diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4cddea4 --- /dev/null +++ b/.gitignore @@ -0,0 +1,74 @@ +extern/SPIRV-Cross/external/ + +build/ +*build/ + +.DS_Store + +CMakeLists.txt.user +CMakeCache.txt +CMakeFiles +CMakeScripts +Testing +Makefile +cmake_install.cmake +install_manifest.txt +compile_commands.json +CTestTestfile.cmake +_deps + +xcuserdata/ + +## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9) +*.xcscmblueprint +*.xccheckout + +## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4) +build/ +DerivedData/ +*.moved-aside +*.pbxuser +!default.pbxuser +*.mode1v3 +!default.mode1v3 +*.mode2v3 +!default.mode2v3 +*.perspectivev3 +!default.perspectivev3 + +## Gcc Patch +/*.gcno + + +# Prerequisites +*.d + +# Compiled Object files +*.slo +*.lo +*.o +*.obj + +# Precompiled Headers +*.gch +*.pch + +# Compiled Dynamic libraries +*.so +*.dylib +*.dll + +# Fortran module files +*.mod +*.smod + +# Compiled Static libraries +*.lai +*.la +*.a +*.lib + +# Executables +*.exe +*.out +*.app diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100755 index 0000000..604d61a --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,137 @@ +cmake_minimum_required(VERSION 3.17) +project(PrismEngine + LANGUAGES CXX) + +list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}/cmake) + +# enable folders in IDEs that support this feature +set_property(GLOBAL PROPERTY USE_FOLDERS ON) + +include(${CMAKE_CURRENT_LIST_DIR}/cmake/Common.cmake) +include(${CMAKE_CURRENT_LIST_DIR}/cmake/AddPlatformExecutable.cmake) +include(FetchContent) + +if(${CMAKE_SYSTEM_NAME} STREQUAL "Windows") + message("Windows build detected!") + + set(ENABLE_WINDOWS ON) + set(ENABLE_VULKAN ON) + set(ENABLE_OPENGL ON) +endif() + +if(${CMAKE_SYSTEM_NAME} STREQUAL "WindowsStore") + message("UWP build detected!") + + set(ENABLE_UWP TRUE) +endif() + +if(${CMAKE_SYSTEM_NAME} STREQUAL "Darwin" AND NOT IOS) + message("macOS build detected!") + + set(ENABLE_METAL TRUE) + set(ENABLE_DARWIN TRUE) + set(ENABLE_MACOS TRUE) + + set(CMAKE_XCODE_GENERATE_SCHEME OFF) +endif() + +if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux") + message("Linux build detected!") + + set(ENABLE_VULKAN TRUE) + set(ENABLE_LINUX TRUE) +endif() + +FetchContent_Declare( + lua + GIT_REPOSITORY https://github.com/NLua/lua.git + GIT_TAG master +) + +FetchContent_Declare( + bullet + GIT_REPOSITORY https://github.com/bulletphysics/bullet3.git + GIT_TAG 2.89 +) + +FetchContent_Declare( + spirv-cross + GIT_REPOSITORY https://github.com/KhronosGroup/SPIRV-Cross.git + GIT_TAG 2020-05-19 +) + +FetchContent_Declare( + glslang + GIT_REPOSITORY https://github.com/KhronosGroup/glslang.git + GIT_TAG master +) + +macro(manual_download) + set(BUILD_BULLET3 OFF CACHE BOOL "" FORCE) + set(BUILD_BULLET3_DEMOS OFF CACHE BOOL "" FORCE) + set(BUILD_BULLET2_DEMOS OFF CACHE BOOL "" FORCE) + set(BUILD_CPU_DEMOS OFF CACHE BOOL "" FORCE) + set(USE_GRAPHICAL_BENCHMARK OFF CACHE BOOL "" FORCE) + set(BUILD_EXTRAS OFF CACHE BOOL "" FORCE) + set(INSTALL_LIBS OFF CACHE BOOL "" FORCE) + set(BUILD_UNIT_TESTS OFF CACHE BOOL "" FORCE) + set(SPIRV_CROSS_SKIP_INSTALL ON CACHE BOOL "" FORCE) + set(BUILD_EXTERNAL OFF CACHE BOOL "" FORCE) + set(ENABLE_GLSLANG_BINARIES OFF CACHE BOOL "" FORCE) + + add_definitions(-DLUA_USE_APPLE) + + set(CMAKE_FOLDER "External") + + FetchContent_MakeAvailable(lua) + FetchContent_MakeAvailable(bullet) + FetchContent_MakeAvailable(spirv-cross) + FetchContent_MakeAvailable(glslang) + + remove_definitions(LUA_USE_MACOSX) + + set(CMAKE_FOLDER "") +endmacro() + +if(${CMAKE_SYSTEM_NAME} STREQUAL "iOS") + message("iOS build detected!") + + set(ENABLE_METAL TRUE) + set(ENABLE_DARWIN TRUE) + set(ENABLE_IOS TRUE) + + manual_download() +endif() + +if(${CMAKE_SYSTEM_NAME} STREQUAL "tvOS") + message("tvOS build detected!") + + set(ENABLE_METAL TRUE) + set(ENABLE_DARWIN TRUE) + set(ENABLE_TVOS TRUE) + + manual_download() +endif() + +add_subdirectory(extern) +add_subdirectory(platforms) + +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) + +add_subdirectory(engine) + +set(CMAKE_FOLDER "Tools" PARENT_SCOPE) + +if(NOT IOS AND NOT ENABLE_TVOS) + add_subdirectory(tools/shadercompiler) +endif() + +if(BUILD_TOOLS) + add_subdirectory(tools/common) + add_subdirectory(tools/fontcompiler) + add_subdirectory(tools/editor) + add_subdirectory(tools/modelcompiler) + add_subdirectory(tools/cutsceneeditor) +endif() + +set(CMAKE_FOLDER "" PARENT_SCOPE) diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..bdecdd0 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 Joshua Goins + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md index b9103ca..8cbb22f 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,54 @@ -# prism -Cross-platform 3D game engine featuring real-time physically based rendering +# Prism +A cross-platform game engine that integrates a real-time physically based workflow and makes it easy to get started writing games or other graphical applications in C++! + +I've been using this to actually develop a game i've been working on, and includes multiple systems to facilitate gameplay (like the UI and audio systems) along with your usual engine systems (like Renderer, and Log). However, the same engine is also proven to be useful for other graphical applications, like the Prism editor. + +Although I developed this on macOS, it has been tested on Windows, Linux, iOS, iPadOS and tvOS machines. Apart from some platform glue, these share a majority of the same code! + +## Features +Here is a list of some of the notable features of Prism: + +* Cross platform graphics API is used for rendering + * Vulkan and Metal backends available + * Shaders are written in GLSL, and compiled to SPIR-V or MSL offline and at runtime using SPIRV-Cross. +* Windowing and System abstraction + * main() and other platform-specific tidbits are abstracted as well, for easy support on non-desktop platforms. + * HiDPI is also supported! + * If available, support for multiple windows as well. +* Dear ImGui used for debug/editor UIs + * Includes the new docking/viewport branch! + * Automatic DPI scaling on fonts for crisp rendering when the window is in a HiDPI environment. + * Custom backend built on top the GFX api and other platform agnostic systems. + * Plenty of custom widgets available for easy debug tooling, see imgui_stdlib.h and imgui_utility.hpp! +* Entity-Component system for scene authoring + * No runtime polymorphism is involved and leverages the native C++ type system. Components are simple structs. +* Asset management + * Custom model pipeline allowing for blazingly fast model loading and authoring. + * Includes a custom blender addon for easy export! + * Assets are referenced from disk, and only loaded once - unloaded once they are no longer referenced. + * Thumbnails are created by the editor and stored on disk until further use. +* Custom UI system for easy authoring + * UIs are declared in JSON, and there is a graphical editor available as well. + * They can even be placed in the world with the UI component! +* Custom math library + * Quaternions, matrices, vectors, rays, and more are available! + * Infinite perspective matrices are created by default. +* Advanced rendering techniques + * Rendering is consistent regardless of platform or API used! + * Where older or underperforming GPUs are supported (for example, an Apple TV 4K, or a Thinkpad X230), the engine supports disabling expensive features like IBL or point light shadows along with other scalability options. + * Real-time physically based rendering including scene probes used for image-based lighting. + * Material node editor for easy and fast material authoring. + * Skinned mesh support with animation. + * PCSS for soft shadows, supported on every type of light. +* Editors supporting scene, cutscene, material authoring + * Multidocument workflow similar to UE4. + * Transform handles for easy object manipulation. + +## Usage +### Requirements +* CMake +* Support for Vulkan or Metal +* C++ compiler that fully supports C++17 + * MSVC, Clang, and GCC have been tested + +There is no example available, but if you clone this repository and include it in your cmake tree, use the function `add_platform_executable` from AddPlatformExecutable.cmake to create a new Prism app. diff --git a/addon/addon.py b/addon/addon.py new file mode 100644 index 0000000..c2ada3c --- /dev/null +++ b/addon/addon.py @@ -0,0 +1,226 @@ +bl_info = { + "name": "Prism Asset Pipeline", + "blender": (2, 80, 0), + "location": "File > Import-Export", + "category": "Import-Export" +} + +import bpy +from bpy.types import Operator, AddonPreferences +from bpy.props import StringProperty, BoolProperty, PointerProperty +from bpy_extras.io_utils import ( + ExportHelper, + ) +import subprocess + +class MarkExportOperator(bpy.types.Operator): + bl_idname = "scene.mark_export_operator" + bl_label = "Mark All Objects for Export" + + def execute(self, context): + for ob in context.scene.objects: + if ob.type == 'MESH': + ob.willExport = True + + return {'FINISHED'} + +class HelloWorldPanel(bpy.types.Panel): + bl_idname = "OBJECT_PT_hello_world" + bl_label = "Prism Asset Pipeline" + bl_space_type = 'PROPERTIES' + bl_region_type = 'WINDOW' + bl_context = "object" + + def draw(self, context): + self.layout.prop(context.object, "modelContainer", text="Model Group") + + self.layout.prop(context.object, "willExport", text="Will Export") + self.layout.prop(context.object, "exportArmature", text="Export Armature") + self.layout.prop(context.object, "exportAnim", text="Export Animations") + +class ExportSettingsPanel(bpy.types.Panel): + bl_idname = "OBJECT_PT_prism_srttings" + bl_label = "Prism Asset Pipeline" + bl_space_type = 'PROPERTIES' + bl_region_type = 'WINDOW' + bl_context = "scene" + + def draw(self, context): + self.layout.operator("scene.mark_export_operator") + self.layout.prop(context.scene, "export_prefix", text="Export Prefix") + self.layout.prop(context.scene, "removeTransforms", text="Remove Transforms") + +def console_get(): + for area in bpy.context.screen.areas: + if area.type == 'CONSOLE': + for space in area.spaces: + if space.type == 'CONSOLE': + return area, space + return None, None + +def console_write(text): + area, space = console_get() + if space is None: + return + + context = bpy.context.copy() + context.update(dict( + space=space, + area=area, + )) + for line in text.split("\n"): + bpy.ops.console.scrollback_append(context, text=line, type='OUTPUT') + +class ExampleAddonPreferences(AddonPreferences): + bl_idname = __name__ + + def update_func(self, context): + if "//" in self.modelCompilerPath: + self.modelCompilerPath = bpy.path.abspath(self.modelCompilerPath) + + if "//" in self.dataExportPath: + self.dataExportPath = bpy.path.abspath(self.dataExportPath) + + modelCompilerPath = StringProperty( + name="Model Compiler Path", + subtype='FILE_PATH', + update=update_func + ) + dataExportPath = StringProperty( + name="Data Export Path", + subtype='DIR_PATH', + update=update_func + ) + + def draw(self, context): + layout = self.layout + layout.prop(self, "modelCompilerPath") + layout.prop(self, "dataExportPath") + + +class ExportAssetPipeline(bpy.types.Operator): + bl_idname = "prism.export_pipeline" + bl_label = "Export Prism Engine" + + action = bpy.props.StringProperty(default="EVERYTHING") + + def execute(self, context): + preferences = context.preferences + addon_prefs = preferences.addons[__name__].preferences + + if len(addon_prefs.modelCompilerPath) == 0 or len(addon_prefs.dataExportPath) == 0: + console_write("No modelS compiler or export path!") + return {'FINISHED'} + + model_compiler = bpy.path.abspath(addon_prefs.modelCompilerPath) + + export_groups = {} + + for object in context.scene.objects: + if object.willExport: + if not object.modelContainer in export_groups: + export_groups[object.modelContainer] = {} + export_groups[object.modelContainer]["objects"] = [] + + console_write("exporting " + object.name + " as " + object.modelContainer) + + export_groups[object.modelContainer]["objects"].append(object.name) + + if object.exportArmature is not None: + export_groups[object.modelContainer]["armature"] = object.exportArmature.name + + console_write(str(export_groups)) + + for group in export_groups.keys(): + bpy.ops.object.select_all(action='DESELECT') + + will_export_anim = False + + if "armature" in export_groups[group]: + object = context.scene.objects[export_groups[group]["armature"]] + + object.select_set(state=True) + + for object_name in export_groups[group]["objects"]: + object = context.scene.objects[object_name] + + if object.exportAnim == True: + will_export_anim = True + + object.select_set(state=True) + + name_part = context.scene.export_prefix + group + + fbx_path = "//" + name_part + ".fbx" + fbx_path = bpy.path.abspath(fbx_path) + + if self.action == 'ONLY_MESH': + will_export_anim = False + + options_dict = {'filepath': fbx_path, + 'check_existing': False, + 'use_selection': True, + 'bake_anim': will_export_anim, + 'apply_unit_scale': True, + 'add_leaf_bones': False, + 'use_armature_deform_only': True, + 'mesh_smooth_type': 'OFF', + 'bake_space_transform': context.scene.removeTransforms, + 'use_tspace': True + } + + if context.scene.removeTransforms: + #options_dict['bake_space_transform'] =True + bpy.ops.export_scene.fbx(**options_dict) + else: + bpy.ops.export_scene.fbx(**options_dict) + + args = [model_compiler, "--no_ui", "--model-path", fbx_path, "--data-path", bpy.path.abspath(addon_prefs.dataExportPath)] + + if context.scene.removeTransforms: + args.append("--compile-static") + + p = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True) + output, errors = p.communicate() + + return {'FINISHED'} + +class PrismExportSubMenu(bpy.types.Menu): + bl_idname = "OBJECT_MT_prism_export_submenu" + bl_label = "Prism Asset Pipeline" + + def draw(self, context): + self.layout.operator(ExportAssetPipeline.bl_idname, text="Everything").action = 'EVERYTHING' + self.layout.operator(ExportAssetPipeline.bl_idname, text="Only Meshes").action = 'ONLY_MESH' + +def menu_func_export(self, context): + self.layout.menu(PrismExportSubMenu.bl_idname) + +def register(): + bpy.utils.register_class(HelloWorldPanel) + bpy.utils.register_class(ExportSettingsPanel) + bpy.utils.register_class(ExportAssetPipeline) + bpy.utils.register_class(MarkExportOperator) + bpy.utils.register_class(PrismExportSubMenu) + + # properties + bpy.types.Object.modelContainer = StringProperty() + bpy.types.Object.willExport = BoolProperty() + bpy.types.Object.exportAnim = BoolProperty() + bpy.types.Scene.export_prefix = StringProperty() + bpy.types.Scene.removeTransforms = BoolProperty() + bpy.types.Object.exportArmature = PointerProperty(type=bpy.types.Object) + + bpy.types.TOPBAR_MT_file_export.append(menu_func_export) + + bpy.utils.register_class(ExampleAddonPreferences) + +def unregister(): + bpy.utils.unregister_class(HelloWorldPanel) + bpy.types.TOPBAR_MT_file_export.remove(menu_func_export) + bpy.utils.unregister_class(ExportAssetPipeline) + bpy.utils.unregister_class(ExampleAddonPreferences) + bpy.utils.unregister_class(MarkExportOperator) + +if __name__ == "__main__": + register() diff --git a/cmake/AddPlatformExecutable.cmake b/cmake/AddPlatformExecutable.cmake new file mode 100755 index 0000000..e0b2747 --- /dev/null +++ b/cmake/AddPlatformExecutable.cmake @@ -0,0 +1,70 @@ +function(set_output_dir target) + set_target_properties(${target} PROPERTIES + RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin + XCODE_GENERATE_SCHEME ON) +endfunction() + +function(add_platform_executable) + cmake_parse_arguments(add_platform_executable + "" + "TARGET;APP_CLASS;APP_INCLUDE;APP_NAME;SKIP_DATA" + "SRC" + ${ARGN}) + + set(APP_CLASS ${add_platform_executable_APP_CLASS} CACHE INTERNAL "") + set(GAME_SRC ${add_platform_executable_SRC} CACHE INTERNAL "") + set(APP_INCLUDE ${add_platform_executable_APP_INCLUDE} CACHE INTERNAL "") + set(APP_NAME ${add_platform_executable_APP_NAME} CACHE INTERNAL "") + + string(REGEX MATCH "^(.*)\\.[^.]*$" dummy ${PLATFORM_MAIN_FILE_NAME}) + set(MYFILE_WITHOUT_EXT ${CMAKE_MATCH_1}) + + configure_file(${PLATFORM_MAIN_FILE_PATH} ${CMAKE_BINARY_DIR}/${add_platform_executable_TARGET}${MYFILE_WITHOUT_EXT}) + + if(COMMAND setup_target) + setup_target(${add_platform_executable_TARGET}) + endif() + + add_executable(${add_platform_executable_TARGET} + ${PLATFORM_SOURCES} + ${add_platform_executable_SRC} + ${CMAKE_BINARY_DIR}/${add_platform_executable_TARGET}${MYFILE_WITHOUT_EXT}) + + if("${PLATFORM_EXECUTABLE_PROPERTIES}" STREQUAL "") + else() + set_target_properties(${add_platform_executable_TARGET} + PROPERTIES + ${PLATFORM_EXECUTABLE_PROPERTIES} + ) + endif() + + target_link_libraries(${add_platform_executable_TARGET} + PRIVATE + ${PLATFORM_LINK_LIBRARIES} + ) + + if("${add_platform_executable_APP_NAME}") + set_target_properties(${add_platform_executable_TARGET} PROPERTIES XCODE_ATTRIBUTE_EXECUTABLE_NAME ${add_platform_executable_APP_NAME}) + set_target_properties(${add_platform_executable_TARGET} PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME ${add_platform_executable_APP_NAME}) + endif() + + if(COMMAND add_platform_commands) + add_platform_commands(${add_platform_executable_TARGET}) + endif() + + set_output_dir(${add_platform_executable_TARGET}) +endfunction() + +function(add_platform) + cmake_parse_arguments(add_platform + "$" + "MAIN_FILE;DISPLAY_NAME" + "EXECUTABLE_PROPERTIES;LINK_LIBRARIES;COMPILE_OPTIONS;SRC" + ${ARGN}) + + set(PLATFORM_MAIN_FILE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/${add_platform_MAIN_FILE} CACHE INTERNAL "") + set(PLATFORM_MAIN_FILE_NAME ${add_platform_MAIN_FILE} CACHE INTERNAL "") + set(PLATFORM_LINK_LIBRARIES ${add_platform_LINK_LIBRARIES} CACHE INTERNAL "") + set(PLATFORM_EXECUTABLE_PROPERTIES ${add_platform_EXECUTABLE_PROPERTIES} CACHE INTERNAL "") + set(PLATFORM_SOURCES ${add_platform_SRC} CACHE INTERNAL "") +endfunction() diff --git a/cmake/BuildShaders.cmake b/cmake/BuildShaders.cmake new file mode 100755 index 0000000..844f2ee --- /dev/null +++ b/cmake/BuildShaders.cmake @@ -0,0 +1,44 @@ +macro(compile_shader src) + string(REGEX REPLACE "\\.[^.]*$" "" MYFILE_WITHOUT_EXT ${src}) + + set(SHADER_COMPILER_COMMAND "${CMAKE_BINARY_DIR}/bin/Debug/ShaderCompiler") + if(ENABLE_IOS) + set(SHADER_COMPILER_COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/../build/bin/Debug/ShaderCompiler") + endif() + + set(EXTRA_PLATFORM_ARG "0") + if(ENABLE_IOS) + set(EXTRA_PLATFORM_ARG "1") + endif() + + add_custom_command( + OUTPUT ${CMAKE_BINARY_DIR}/${MYFILE_WITHOUT_EXT}.glsl + COMMAND ${SHADER_COMPILER_COMMAND} ${CMAKE_CURRENT_SOURCE_DIR}/../../${src} ${CMAKE_BINARY_DIR}/${src} ${EXTRA_PLATFORM_ARG} + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/../../${src} + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../../shaders + ) +endmacro() + +function(add_shader) + if(NOT ENABLE_IOS) + set(options OPTIONAL FAST) + set(oneValueArgs TARGET) + set(multiValueArgs SHADERS) + cmake_parse_arguments(add_shader "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} ) + + foreach(shader ${add_shader_SHADERS}) + string(REGEX REPLACE "\\.[^.]*$" "" MYFILE_WITHOUT_EXT ${shader}) + + compile_shader(${shader}) + + list(APPEND SPV_FILES ${CMAKE_BINARY_DIR}/${MYFILE_WITHOUT_EXT}.glsl) + endforeach() + + file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/shaders) + + add_custom_target(BuildShaders DEPENDS ${SPV_FILES} ShaderCompiler) + add_dependencies(${add_shader_TARGET} BuildShaders) + + set(ALL_SHADER_FILES ${SPV_FILES} CACHE INTERNAL "" FORCE) + endif() +endfunction() diff --git a/cmake/Common.cmake b/cmake/Common.cmake new file mode 100755 index 0000000..7c33e43 --- /dev/null +++ b/cmake/Common.cmake @@ -0,0 +1,35 @@ +macro(set_engine_properties target) + target_compile_features(${target} PUBLIC cxx_std_17) + set_target_properties(${target} PROPERTIES CXX_EXTENSIONS OFF) + target_compile_options(${target} PUBLIC + -Wall + -Wextra + -Wno-c++98-compat + -Wno-c++98-compat-pedantic + -Wno-padded + -Wno-documentation-unknown-command + -Wno-used-but-marked-unused + -Wno-system-headers + -Wconversion + -Wno-sign-conversion) + + if(ENABLE_MACOS) + target_compile_definitions(${target} PUBLIC PLATFORM_MACOS) + endif() + + if(ENABLE_WINDOWS) + target_compile_definitions(${target} PUBLIC PLATFORM_WINDOWS) + endif() + + if(ENABLE_LINUX) + target_compile_definitions(${target} PUBLIC PLATFORM_LINUX) + endif() + + if(ENABLE_IOS) + target_compile_definitions(${target} PUBLIC PLATFORM_IOS) + endif() + + if(ENABLE_TVOS) + target_compile_definitions(${target} PUBLIC PLATFORM_TVOS) + endif() +endmacro() diff --git a/cmake/FindLuaJIT.cmake b/cmake/FindLuaJIT.cmake new file mode 100644 index 0000000..eda7184 --- /dev/null +++ b/cmake/FindLuaJIT.cmake @@ -0,0 +1,50 @@ +# Locate LuaJIT library +# This module defines +# LUAJIT_FOUND, if false, do not try to link to Lua +# LUA_INCLUDE_DIR, where to find lua.h +# LUA_VERSION_STRING, the version of Lua found (since CMake 2.8.8) +# +# This module is similar to FindLua51.cmake except that it finds LuaJit instead. + +FIND_PATH(LUA_INCLUDE_DIR luajit.h + HINTS + $ENV{LUA_DIR} + PATH_SUFFIXES include/luajit-2.1 include/luajit-2.0 include/luajit-5_1-2.1 include/luajit-5_1-2.0 include luajit + PATHS + ~/Library/Frameworks + /Library/Frameworks + /sw # Fink + /opt/local # DarwinPorts + /opt/csw # Blastwave + /opt +) + +FIND_LIBRARY(LUA_LIBRARY + NAMES luajit luajit-5.1 + HINTS + $ENV{LUA_DIR} + PATH_SUFFIXES lib64 lib + PATHS + ~/Library/Frameworks + /Library/Frameworks + /sw + /opt/local + /opt/csw + /opt +) + +IF(LUA_INCLUDE_DIR AND EXISTS "${LUA_INCLUDE_DIR}/luajit.h") + FILE(STRINGS "${LUA_INCLUDE_DIR}/luajit.h" lua_version_str REGEX "^#define[ \t]+LUA_RELEASE[ \t]+\"LuaJIT .+\"") + + STRING(REGEX REPLACE "^#define[ \t]+LUA_RELEASE[ \t]+\"LuaJIT ([^\"]+)\".*" "\\1" LUA_VERSION_STRING "${lua_version_str}") + UNSET(lua_version_str) +ENDIF() + +INCLUDE(FindPackageHandleStandardArgs) +# handle the QUIETLY and REQUIRED arguments and set LUAJIT_FOUND to TRUE if +# all listed variables are TRUE +FIND_PACKAGE_HANDLE_STANDARD_ARGS(LuaJIT + REQUIRED_VARS LUA_LIBRARY LUA_INCLUDE_DIR + VERSION_VAR LUA_VERSION_STRING) + +MARK_AS_ADVANCED(LUA_INCLUDE_DIR LUA_LIBRARY LUA_MATH_LIBRARY) diff --git a/cmake/FindPortAudio.cmake b/cmake/FindPortAudio.cmake new file mode 100644 index 0000000..61d7f99 --- /dev/null +++ b/cmake/FindPortAudio.cmake @@ -0,0 +1,97 @@ +# - Try to find Portaudio +# Once done this will define +# +# PORTAUDIO_FOUND - system has Portaudio +# PORTAUDIO_INCLUDE_DIRS - the Portaudio include directory +# PORTAUDIO_LIBRARIES - Link these to use Portaudio +# PORTAUDIO_DEFINITIONS - Compiler switches required for using Portaudio +# PORTAUDIO_VERSION - Portaudio version +# +# Copyright (c) 2006 Andreas Schneider +# +# Redistribution and use is allowed according to the terms of the New BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. +# + + +if (PORTAUDIO_LIBRARIES AND PORTAUDIO_INCLUDE_DIRS) + # in cache already + set(PORTAUDIO_FOUND TRUE) +else (PORTAUDIO_LIBRARIES AND PORTAUDIO_INCLUDE_DIRS) + if (NOT WIN32) + include(FindPkgConfig) + pkg_check_modules(PORTAUDIO2 portaudio-2.0) + endif (NOT WIN32) + + if (PORTAUDIO2_FOUND) + set(PORTAUDIO_INCLUDE_DIRS + ${PORTAUDIO2_INCLUDE_DIRS} + ) + if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") + set(PORTAUDIO_LIBRARIES "${PORTAUDIO2_LIBRARY_DIRS}/lib${PORTAUDIO2_LIBRARIES}.dylib") + else (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") + set(PORTAUDIO_LIBRARIES + ${PORTAUDIO2_LIBRARIES} + ) + endif (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") + set(PORTAUDIO_VERSION + 19 + ) + set(PORTAUDIO_FOUND TRUE) + else (PORTAUDIO2_FOUND) + find_path(PORTAUDIO_INCLUDE_DIR + NAMES + portaudio.h + PATHS + /usr/include + /usr/local/include + /opt/local/include + /sw/include + ) + + find_library(PORTAUDIO_LIBRARY + NAMES + portaudio + PATHS + /usr/lib + /usr/local/lib + /opt/local/lib + /sw/lib + ${PORTAUDIO_LIBRARY_DIR} + ) + + set(PORTAUDIO_INCLUDE_DIRS + ${PORTAUDIO_INCLUDE_DIR} + ) + set(PORTAUDIO_LIBRARIES + ${PORTAUDIO_LIBRARY} + ) + + set(PORTAUDIO_LIBRARY_DIRS + ${PORTAUDIO_LIBRARY_DIR} + ) + + set(PORTAUDIO_VERSION + 18 + ) + + if (PORTAUDIO_INCLUDE_DIRS AND PORTAUDIO_LIBRARIES) + set(PORTAUDIO_FOUND TRUE) + endif (PORTAUDIO_INCLUDE_DIRS AND PORTAUDIO_LIBRARIES) + + if (PORTAUDIO_FOUND) + if (NOT Portaudio_FIND_QUIETLY) + message(STATUS "Found Portaudio: ${PORTAUDIO_LIBRARIES}") + endif (NOT Portaudio_FIND_QUIETLY) + else (PORTAUDIO_FOUND) + if (Portaudio_FIND_REQUIRED) + message(FATAL_ERROR "Could not find Portaudio") + endif (Portaudio_FIND_REQUIRED) + endif (PORTAUDIO_FOUND) + endif (PORTAUDIO2_FOUND) + + + # show the PORTAUDIO_INCLUDE_DIRS and PORTAUDIO_LIBRARIES variables only in the advanced view + mark_as_advanced(PORTAUDIO_INCLUDE_DIRS PORTAUDIO_LIBRARIES) + +endif (PORTAUDIO_LIBRARIES AND PORTAUDIO_INCLUDE_DIRS) diff --git a/cmake/Findassimp.cmake b/cmake/Findassimp.cmake new file mode 100644 index 0000000..6637f29 --- /dev/null +++ b/cmake/Findassimp.cmake @@ -0,0 +1,77 @@ +include(FindPackageHandleStandardArgs) + +if (WIN32) + # Find include files + find_path( + ASSIMP_INCLUDE_DIR + NAMES assimp/scene.h + PATHS + $ENV{PROGRAMFILES}/include + ${ASSIMP_ROOT_DIR}/include + DOC "The directory where assimp/scene.h resides") + + # Find library files + find_library( + ASSIMP_LIBRARY_RELEASE + NAMES assimp-vc140-mt + PATHS + $ENV{PROGRAMFILES}/lib + ${ASSIMP_ROOT_DIR}/lib + ${LM_EXTERNAL_LIBRARY_PATH}/Release) + + find_library( + ASSIMP_LIBRARY_DEBUG + NAMES assimp-vc140-mtd + PATHS + $ENV{PROGRAMFILES}/lib + ${ASSIMP_ROOT_DIR}/lib + ${LM_EXTERNAL_LIBRARY_PATH}/Debug) +else() + # Find include files + find_path( + ASSIMP_INCLUDE_DIR + NAMES assimp/scene.h + PATHS + /usr/include + /usr/local/include + /sw/include + /opt/local/include + DOC "The directory where assimp/scene.h resides") + + # Find library files + find_library( + ASSIMP_LIBRARY + NAMES assimp + PATHS + /usr/lib64 + /usr/lib + /usr/local/lib64 + /usr/local/lib + /sw/lib + /opt/local/lib + ${ASSIMP_ROOT_DIR}/lib + DOC "The Assimp library") +endif() + +if (WIN32) + # Handle REQUIRD argument, define *_FOUND variable + find_package_handle_standard_args(assimp DEFAULT_MSG ASSIMP_INCLUDE_DIR ASSIMP_LIBRARY_RELEASE ASSIMP_LIBRARY_DEBUG) + + # Define ASSIMP_LIBRARIES and ASSIMP_INCLUDE_DIRS + if (ASSIMP_FOUND) + set(ASSIMP_LIBRARIES_RELEASE ${ASSIMP_LIBRARY_RELEASE}) + set(ASSIMP_LIBRARIES_DEBUG ${ASSIMP_LIBRARY_DEBUG}) + set(ASSIMP_LIBRARIES debug ${ASSIMP_LIBRARIES_DEBUG} optimized ${ASSIMP_LIBRARY_RELEASE}) + set(ASSIMP_INCLUDE_DIRS ${ASSIMP_INCLUDE_DIR}) + endif() + + # Hide some variables + mark_as_advanced(ASSIMP_INCLUDE_DIR ASSIMP_LIBRARY_RELEASE ASSIMP_LIBRARY_DEBUG) +else() + find_package_handle_standard_args(assimp DEFAULT_MSG ASSIMP_INCLUDE_DIR ASSIMP_LIBRARY) + if (ASSIMP_FOUND) + set(ASSIMP_LIBRARIES ${ASSIMP_LIBRARY}) + set(ASSIMP_INCLUDE_DIRS ${ASSIMP_INCLUDE_DIR}) + endif() + mark_as_advanced(ASSIMP_INCLUDE_DIR ASSIMP_LIBRARY) +endif() diff --git a/cmake/Findglslang.cmake b/cmake/Findglslang.cmake new file mode 100644 index 0000000..c03bcb3 --- /dev/null +++ b/cmake/Findglslang.cmake @@ -0,0 +1,202 @@ +#.rst: +# Findglslang +# ---------- +# +# Try to find glslang in the VulkanSDK +# +# IMPORTED Targets +# ^^^^^^^^^^^^^^^^ +# +# This module defines :prop_tgt:`IMPORTED` target ``glslang::glslang``, if +# glslang has been found. +# +# Result Variables +# ^^^^^^^^^^^^^^^^ +# +# This module defines the following variables:: +# +# glslang_FOUND - True if glslang was found +# glslang_INCLUDE_DIRS - include directories for glslang +# glslang_LIBRARIES - link against this library to use glslang +# +# The module will also define two cache variables:: +# +# glslang_INCLUDE_DIR - the glslang include directory +# glslang_LIBRARY - the path to the glslang library +# + +if (DEFINED ENV{VULKAN_SDK}) + if(WIN32) + set(ADDITIONAL_PATHS_INCLUDE "$ENV{VULKAN_SDK}/Include") + if(CMAKE_SIZEOF_VOID_P EQUAL 8) + set(ADDITIONAL_PATHS_LIBS + "$ENV{VULKAN_SDK}/Lib" + "$ENV{VULKAN_SDK}/Bin" + ) + elseif(CMAKE_SIZEOF_VOID_P EQUAL 4) + set(ADDITIONAL_PATHS_LIBS + "$ENV{VULKAN_SDK}/Lib32" + "$ENV{VULKAN_SDK}/Bin32" + ) + endif() + else() + set(ADDITIONAL_PATHS_INCLUDE "$ENV{VULKAN_SDK}/include") + set(ADDITIONAL_PATHS_LIBS "$ENV{VULKAN_SDK}/lib") + endif() +endif() + +find_path(glslang_INCLUDE_DIR + NAMES glslang/Public/ShaderLang.h + PATHS ${ADDITIONAL_PATHS_INCLUDE} +) + +find_path(spirv_INCLUDE_DIR + NAMES SPIRV/GlslangToSpv.h + PATHS ${ADDITIONAL_PATHS_INCLUDE} +) + + +find_library(glslang_LIBRARY + NAMES glslang + PATHS ${ADDITIONAL_PATHS_LIBS} +) + +find_library(OSDependent_LIBRARY + NAMES OSDependent + PATHS ${ADDITIONAL_PATHS_LIBS} +) + +find_library(SPIRV_LIBRARY + NAMES SPIRV + PATHS ${ADDITIONAL_PATHS_LIBS} +) + +find_library(SPIRV-Tools_LIBRARY + NAMES SPIRV-Tools + PATHS ${ADDITIONAL_PATHS_LIBS} +) + +find_library(SPIRV-Tools-opt_LIBRARY + NAMES SPIRV-Tools-opt + PATHS ${ADDITIONAL_PATHS_LIBS} +) + +find_library(OGLCompiler_LIBRARY + NAMES OGLCompiler + PATHS ${ADDITIONAL_PATHS_LIBS} +) + +find_library(HLSL_LIBRARY + NAMES HLSL + PATHS ${ADDITIONAL_PATHS_LIBS} +) + +if(WIN32) + + find_library(glslang_LIBRARY_debug + NAMES glslangd + PATHS ${ADDITIONAL_PATHS_LIBS} + ) + + find_library(OSDependent_LIBRARY_debug + NAMES OSDependentd + PATHS ${ADDITIONAL_PATHS_LIBS} + ) + + find_library(SPIRV_LIBRARY_debug + NAMES SPIRVd + PATHS ${ADDITIONAL_PATHS_LIBS} + ) + + find_library(SPIRV-Tools_LIBRARY_debug + NAMES SPIRV-Toolsd + PATHS ${ADDITIONAL_PATHS_LIBS} + ) + + find_library(SPIRV-Tools-opt_LIBRARY_debug + NAMES SPIRV-Tools-optd + PATHS ${ADDITIONAL_PATHS_LIBS} + ) + + find_library(OGLCompiler_LIBRARY_debug + NAMES OGLCompilerd + PATHS ${ADDITIONAL_PATHS_LIBS} + ) + + find_library(HLSL_LIBRARY_debug + NAMES HLSLd + PATHS ${ADDITIONAL_PATHS_LIBS} + ) +endif() + + +set(glslang_LIBRARIES ${glslang_LIBRARY}) +set(glslang_INCLUDE_DIRS ${glslang_INCLUDE_DIR}) + +mark_as_advanced(glslang_INCLUDE_DIR glslang_LIBRARY) + +if(glslang_LIBRARY AND glslang_INCLUDE_DIR) + set(glslang_FOUND "YES") + message(STATUS "Found glslang: ${glslang_LIBRARY}") +else() + set(glslang_FOUND "NO") + message(STATUS "Failed to find glslang") +endif() + +if(glslang_FOUND AND NOT TARGET glslang::glslang) + add_library(glslang::glslang UNKNOWN IMPORTED) + set_target_properties(glslang::glslang PROPERTIES IMPORTED_LOCATION "${glslang_LIBRARY}" INTERFACE_INCLUDE_DIRECTORIES "${glslang_INCLUDE_DIRS}") + + add_library(glslang::OSDependent UNKNOWN IMPORTED) + set_target_properties(glslang::OSDependent PROPERTIES IMPORTED_LOCATION "${OSDependent_LIBRARY}" INTERFACE_INCLUDE_DIRECTORIES "${OSDependent_INCLUDE_DIRS}") + + add_library(glslang::SPIRV UNKNOWN IMPORTED) + set_target_properties(glslang::SPIRV PROPERTIES IMPORTED_LOCATION "${SPIRV_LIBRARY}" INTERFACE_INCLUDE_DIRECTORIES "${spirv_INCLUDE_DIR}") + + if (SPIRV-Tools_LIBRARY) + add_library(glslang::SPIRV-Tools UNKNOWN IMPORTED) + set_target_properties(glslang::SPIRV-Tools PROPERTIES IMPORTED_LOCATION "${SPIRV-Tools_LIBRARY}" INTERFACE_INCLUDE_DIRECTORIES "${SPIRV-Tools__INCLUDE_DIR}") + endif() + + if (SPIRV-Tools-opt_LIBRARY) + add_library(glslang::SPIRV-Tools-opt UNKNOWN IMPORTED) + set_target_properties(glslang::SPIRV-Tools-opt PROPERTIES IMPORTED_LOCATION "${SPIRV-Tools-opt_LIBRARY}" INTERFACE_INCLUDE_DIRECTORIES "${SPIRV-Tools-opt_INCLUDE_DIR}") + endif() + + add_library(glslang::OGLCompiler UNKNOWN IMPORTED) + set_target_properties(glslang::OGLCompiler PROPERTIES IMPORTED_LOCATION "${OGLCompiler_LIBRARY}" INTERFACE_INCLUDE_DIRECTORIES "${glslang_INCLUDE_DIRS}") + + add_library(glslang::HLSL UNKNOWN IMPORTED) + set_target_properties(glslang::HLSL PROPERTIES IMPORTED_LOCATION "${HLSL_LIBRARY}" INTERFACE_INCLUDE_DIRECTORIES "${glslang_INCLUDE_DIRS}") + + if(WIN32) + set_target_properties(glslang::glslang PROPERTIES IMPORTED_LOCATION_DEBUG "${glslang_LIBRARY_debug}") + set_target_properties(glslang::OSDependent PROPERTIES IMPORTED_LOCATION_DEBUG "${OSDependent_LIBRARY_debug}") + set_target_properties(glslang::SPIRV PROPERTIES IMPORTED_LOCATION_DEBUG "${SPIRV_LIBRARY_debug}") + if (SPIRV-Tools_LIBRARY_debug) + set_target_properties(glslang::SPIRV-Tools PROPERTIES IMPORTED_LOCATION_DEBUG "${SPIRV-Tools_LIBRARY_debug}") + endif() + if (SPIRV-Tools-opt_LIBRARY_debug) + set_target_properties(glslang::SPIRV-Tools-opt PROPERTIES IMPORTED_LOCATION_DEBUG "${SPIRV-Tools-opt_LIBRARY_debug}") + endif() + set_target_properties(glslang::OGLCompiler PROPERTIES IMPORTED_LOCATION_DEBUG "${OGLCompiler_LIBRARY_debug}") + set_target_properties(glslang::HLSL PROPERTIES IMPORTED_LOCATION_DEBUG "${HLSL_LIBRARY_debug}") + endif() + + set(GLSLANG + glslang::glslang + glslang::OSDependent + glslang::SPIRV + glslang::OGLCompiler + glslang::HLSL + ) + + if (SPIRV-Tools-opt_LIBRARY) + list(APPEND GLSLANG glslang::SPIRV-Tools-opt) + endif() + if (SPIRV-Tools_LIBRARY) + list(APPEND GLSLANG glslang::SPIRV-Tools) + endif() + +endif() + diff --git a/engine/CMakeLists.txt b/engine/CMakeLists.txt new file mode 100755 index 0000000..57f5875 --- /dev/null +++ b/engine/CMakeLists.txt @@ -0,0 +1,12 @@ +add_subdirectory(core) +add_subdirectory(renderer) +add_subdirectory(utility) +add_subdirectory(gfx) +add_subdirectory(math) +add_subdirectory(log) +add_subdirectory(asset) + +if(NOT ENABLE_IOS AND NOT ENABLE_TVOS) + add_subdirectory(audio) + add_subdirectory(tests) +endif() \ No newline at end of file diff --git a/engine/asset/CMakeLists.txt b/engine/asset/CMakeLists.txt new file mode 100644 index 0000000..b9b380d --- /dev/null +++ b/engine/asset/CMakeLists.txt @@ -0,0 +1,18 @@ +set(SRC + include/asset_types.hpp + include/asset.hpp + include/assetptr.hpp + include/material_nodes.hpp + + src/asset.cpp) + +add_library(Asset ${SRC}) +target_include_directories(Asset PUBLIC include) +target_link_libraries(Asset + PUBLIC + Math + PRIVATE + stb + Log + Core) +set_engine_properties(Asset) diff --git a/engine/asset/include/asset.hpp b/engine/asset/include/asset.hpp new file mode 100644 index 0000000..86dd681 --- /dev/null +++ b/engine/asset/include/asset.hpp @@ -0,0 +1,155 @@ +#pragma once + +#include +#include +#include + +#include "file.hpp" +#include "assetptr.hpp" +#include "asset_types.hpp" +#include "string_utils.hpp" + +namespace std { + template <> + struct hash { + std::size_t operator()(const file::Path& k) const { + return hash()(k); + } + }; +} + +template +std::unique_ptr load_asset(const file::Path p); + +template +bool can_load_asset(const file::Path p); + +template +using AssetStore = std::unordered_map>; + +template +class AssetPool : public AssetStore... { +public: + template + AssetPtr add() { + const auto p = file::Path(); + auto reference_block = get_reference_block(p); + + AssetStore::try_emplace(p, std::make_unique()); + + return AssetPtr(AssetStore::at(p).get(), reference_block); + } + + template + AssetPtr get(const file::Path path) { + return fetch(path, get_reference_block(path)); + } + + template + std::vector get_all() { + std::vector assets; + for(auto iter = AssetStore::begin(); iter != AssetStore::end(); iter++) { + auto& [p, asset] = *iter; + + assets.push_back(asset.get()); + } + + return assets; + } + + template + AssetPtr fetch(const file::Path path, ReferenceBlock* reference_block) { + if(!AssetStore::count(path)) + AssetStore::try_emplace(path, load_asset(path)); + + return AssetPtr(AssetStore::at(path).get(), reference_block); + } + + std::tuple load_asset_generic(const file::Path path) { + Asset* asset = nullptr; + ReferenceBlock* block = nullptr; + + (load_asset_generic(path, asset, block), ...); + + return {asset, block}; + } + + void perform_cleanup() { + for(auto iter = reference_blocks.begin(); iter != reference_blocks.end();) { + auto& [path, block] = *iter; + + if(block->references == 0) { + ((delete_asset(path)), ...); + + iter = reference_blocks.erase(iter); + } else { + iter = std::next(iter); + } + } + } + + std::unordered_map> reference_blocks; + +private: + ReferenceBlock* get_reference_block(const file::Path path) { + if(!reference_blocks.count(path)) + reference_blocks.try_emplace(path, std::make_unique()); + + return reference_blocks[path].get(); + } + + template + void load_asset_generic(const file::Path path, Asset*& at, ReferenceBlock*& block) { + if(can_load_asset(path)) { + if(!AssetStore::count(path)) + AssetStore::try_emplace(path, load_asset(path)); + + at = AssetStore::at(path).get(); + block = get_reference_block(path); + } + } + + template + void delete_asset(const file::Path path) { + auto iter = AssetStore::find(path); + if(iter != AssetStore::end()) { + auto& [_, asset] = *iter; + + asset.reset(); + + AssetStore::erase(iter); + } + } +}; + +using AssetManager = AssetPool; + +inline std::unique_ptr assetm; + +std::unique_ptr load_mesh(const file::Path path); +std::unique_ptr load_material(const file::Path path); +std::unique_ptr load_texture(const file::Path path); + +void save_material(Material* material, const std::string_view path); + +template +std::unique_ptr load_asset(const file::Path path) { + if constexpr (std::is_same_v) { + return load_mesh(path); + } else if constexpr(std::is_same_v) { + return load_material(path); + } else if constexpr(std::is_same_v) { + return load_texture(path); + } +} + +template +bool can_load_asset(const file::Path path) { + if constexpr(std::is_same_v) { + return path.extension() == ".model"; + } else if constexpr(std::is_same_v) { + return path.extension() == ".material"; + } else if constexpr(std::is_same_v) { + return path.extension() == ".png"; + } +} diff --git a/engine/asset/include/asset_types.hpp b/engine/asset/include/asset_types.hpp new file mode 100644 index 0000000..258b430 --- /dev/null +++ b/engine/asset/include/asset_types.hpp @@ -0,0 +1,84 @@ +#pragma once + +#include + +#include "assetptr.hpp" +#include "math.hpp" +#include "material_nodes.hpp" +#include "aabb.hpp" + +class GFXBuffer; +class GFXTexture; + +class Texture : public Asset { +public: + GFXTexture* handle = nullptr; + int width = 0, height = 0; +}; + +class GFXPipeline; + +class Material : public Asset { +public: + std::vector> nodes; + + GFXPipeline* static_pipeline = nullptr; + GFXPipeline* skinned_pipeline = nullptr; + GFXPipeline* capture_pipeline = nullptr; + + std::map> bound_textures; +}; + +constexpr int max_weights_per_vertex = 4; + +struct BoneVertexData { + std::array ids; + std::array weights; +}; + +struct Bone { + int index = 0; + + std::string name; + Matrix4x4 local_transform, final_transform; + + Bone* parent = nullptr; + + Vector3 position; + Quaternion rotation; + Vector3 scale; +}; + +class Mesh : public Asset { +public: + // meshes are rendered in parts if we cannot batch it in one call, i.e. a mesh + // with multiple materials with different textures, etc + struct Part { + std::string name; + AABB aabb; + + GFXBuffer* bone_batrix_buffer = nullptr; + std::vector offset_matrices; + + uint32_t index_offset = 0, vertex_offset = 0, index_count = 0; + int32_t material_override = -1; + }; + + std::vector parts; + std::vector bones; + Bone* root_bone = nullptr; + + // atributes + GFXBuffer* position_buffer = nullptr; + GFXBuffer* normal_buffer = nullptr; + GFXBuffer* texture_coord_buffer = nullptr; + GFXBuffer* tangent_buffer = nullptr; + GFXBuffer* bitangent_buffer = nullptr; + GFXBuffer* bone_buffer = nullptr; + + GFXBuffer* index_buffer = nullptr; + + Matrix4x4 global_inverse_transformation; + + uint32_t num_indices = 0; +}; diff --git a/engine/asset/include/assetptr.hpp b/engine/asset/include/assetptr.hpp new file mode 100644 index 0000000..8824e6e --- /dev/null +++ b/engine/asset/include/assetptr.hpp @@ -0,0 +1,79 @@ +#pragma once + +#include +#include +#include + +#include "file.hpp" + +struct ReferenceBlock { + uint64_t references = 0; +}; + +class Asset { +public: + std::string path; +}; + +template +struct AssetPtr { + AssetPtr() {} + + AssetPtr(T* ptr, ReferenceBlock* block) : handle(ptr), block(block) { + block->references++; + } + + AssetPtr(const AssetPtr &rhs) { + handle = rhs.handle; + block = rhs.block; + + if(block != nullptr) + block->references++; + } + + AssetPtr& operator=(const AssetPtr& rhs) { + handle = rhs.handle; + block = rhs.block; + + if(block != nullptr) + block->references++; + + return *this; + } + + ~AssetPtr() { + if(block != nullptr) + block->references--; + } + + void clear() { + if(block != nullptr) + block->references--; + + block = nullptr; + handle = nullptr; + } + + T* handle = nullptr; + ReferenceBlock* block = nullptr; + + operator bool() const{ + return handle != nullptr; + } + + T* operator->() { + return handle; + } + + T* operator->() const { + return handle; + } + + T* operator*() { + return handle; + } + + T* operator*() const { + return handle; + } +}; diff --git a/engine/asset/include/material_nodes.hpp b/engine/asset/include/material_nodes.hpp new file mode 100644 index 0000000..444f160 --- /dev/null +++ b/engine/asset/include/material_nodes.hpp @@ -0,0 +1,241 @@ +#pragma once + +#include "renderer.hpp" + +class Texture; +class MaterialNode; + +enum class DataType { + Vector3, + Float, + AssetTexture +}; + +struct MaterialConnector { + MaterialConnector(std::string n, DataType t) : name(n), type(t) {} + MaterialConnector(std::string n, DataType t, bool isn) : name(n), type(t), is_normal_map(isn) {} + + std::string name; + DataType type; + + bool is_normal_map = false; + + MaterialConnector* connected_connector = nullptr; + MaterialNode* connected_node = nullptr; + int connected_index = -1; +}; + +inline bool operator==(const MaterialConnector& a, const MaterialConnector& b) { + return a.name == b.name; +} + +struct MaterialProperty { + std::string name; + DataType type; + + MaterialProperty(std::string n, DataType t) : name(n), type(t) {} + + Vector3 value; + AssetPtr value_tex; + float float_value; +}; + +static int last_id = 0; + +class MaterialNode { +public: + virtual ~MaterialNode() {} + + int id = last_id++; + + std::vector inputs, outputs; + std::vector properties; + + virtual const char* get_prefix() = 0; + virtual const char* get_name() = 0; + + virtual std::string get_glsl() = 0; + + std::string get_connector_variable_name(MaterialConnector& connector) { + return std::string(get_prefix()) + std::to_string(id) + "_" + connector.name; + } + + std::string get_property_variable_name(MaterialProperty& property) { + return std::string(get_prefix()) + std::to_string(id) + "_" + property.name; + } + + std::string get_connector_value(MaterialConnector& connector) { + if(connector.connected_node != nullptr) { + if(connector.type != connector.connected_connector->type) { + return connector.connected_node->get_connector_variable_name(*connector.connected_connector) + ".r"; + } else { + if(connector.is_normal_map) { + if(render_options.enable_normal_mapping) { + return "in_tbn * (2.0 * " + connector.connected_node->get_connector_variable_name(*connector.connected_connector) + " - 1.0)"; + } else { + return "in_normal"; + } + } else { + return connector.connected_node->get_connector_variable_name(*connector.connected_connector); + } + } + } else { + switch(connector.type) { + case DataType::Float: + return "0.0"; + default: + return "vec3(1, 1, 1)"; + } + } + } + + std::string get_property_value(MaterialProperty& property) { + switch(property.type) { + case DataType::Vector3: + { + return "vec3(" + std::to_string(property.value.x) + ", " + std::to_string(property.value.y) + ", " + std::to_string(property.value.z) + ")"; + } + break; + case DataType::Float: + { + return std::to_string(property.float_value); + } + break; + case DataType::AssetTexture: + { + return "texture(" + get_property_variable_name(property) + ", in_uv).rgb"; + } + break; + } + } + + MaterialConnector* find_connector(std::string name) { + for(auto& input : inputs) { + if(input.name == name) + return &input; + } + + for(auto& output : outputs) { + if(output.name == name) + return &output; + } + + return nullptr; + } + + float x = 0.0f, y = 0.0f; + float width = 150.0f, height = 75.0f; +}; + +class MaterialOutput : public MaterialNode { +public: + MaterialOutput() { + inputs = { + MaterialConnector("Color", DataType::Vector3), + MaterialConnector("Roughness", DataType::Float), + MaterialConnector("Metallic", DataType::Float), + MaterialConnector("Normals", DataType::Vector3, true), + }; + } + + const char* get_prefix() override { + return "material_output_"; + } + + const char* get_name() override { + return "Material Output"; + } + + std::string get_glsl() override { + std::string glsl = "vec3 final_diffuse_color = Color;\n \ + float final_roughness = Roughness;\n \ + float final_metallic = Metallic;\n"; + + if(find_connector("Normals")->connected_node != nullptr) { + glsl += "vec3 final_normal = Normals;\n"; + } else { + glsl += "vec3 final_normal = in_normal;\n"; + } + + return glsl; + } +}; + +class Vector3Constant : public MaterialNode { +public: + Vector3Constant() { + outputs = {MaterialConnector("Value", DataType::Vector3)}; + properties = {MaterialProperty("Color", DataType::Vector3)}; + } + + const char* get_prefix() override { + return "vec3const_"; + } + + const char* get_name() override { + return "Vector3 Constant"; + } + + std::string get_glsl() override { + return "vec3 Value = Color;\n"; + } +}; + +class FloatConstant : public MaterialNode { +public: + FloatConstant() { + outputs = {MaterialConnector("Value", DataType::Float)}; + properties = {MaterialProperty("Data", DataType::Float)}; + } + + const char* get_prefix() override { + return "floatconst_"; + } + + const char* get_name() override { + return "Float Constant"; + } + + std::string get_glsl() override { + return "float Value = Data;\n"; + } +}; + +class TextureNode : public MaterialNode { +public: + TextureNode() { + outputs = {MaterialConnector("Value", DataType::Vector3)}; + properties = {MaterialProperty("Texture", DataType::AssetTexture)}; + } + + const char* get_prefix() override { + return "texture_"; + } + + const char* get_name() override { + return "Texture"; + } + + std::string get_glsl() override { + return "vec3 Value = Texture;\n"; + } +}; + +class Geometry : public MaterialNode { +public: + Geometry() { + outputs = {MaterialConnector("Normal", DataType::Vector3)}; + } + + const char* get_prefix() override { + return "geometry_"; + } + + const char* get_name() override { + return "Geometry"; + } + + std::string get_glsl() override { + return "vec3 Normal = normalize(in_normal);\n"; + } +}; diff --git a/engine/asset/src/asset.cpp b/engine/asset/src/asset.cpp new file mode 100644 index 0000000..a3ce23c --- /dev/null +++ b/engine/asset/src/asset.cpp @@ -0,0 +1,387 @@ +#include "asset.hpp" + +#include +#include +#include + +#include "log.hpp" +#include "engine.hpp" +#include "gfx.hpp" +#include "json_conversions.hpp" +#include "gfx_commandbuffer.hpp" +#include "assertions.hpp" + +std::unique_ptr load_mesh(const file::Path path) { + Expects(!path.empty()); + + auto file = file::open(path); + if(!file.has_value()) { + console::error(System::Renderer, "Failed to load mesh from {}!", path); + return nullptr; + } + + int version = 0; + file->read(&version); + + if(version == 5 || version == 6) { + } else { + console::error(System::Renderer, "{} failed the mesh version check! reported version = {}", path, std::to_string(version)); + return nullptr; + } + + auto mesh = std::make_unique(); + mesh->path = path; + + enum MeshType : int { + Static, + Skinned + } mesh_type; + + file->read(&mesh_type); + + // TODO: use unsigned int here + int numVertices = 0; + file->read(&numVertices); + + Expects(numVertices > 0); + + const auto read_buffer = [&f = file.value(), numVertices](unsigned int size) -> GFXBuffer* { + auto buffer = engine->get_gfx()->create_buffer(nullptr, size * static_cast(numVertices), false, GFXBufferUsage::Vertex); + auto buffer_ptr = reinterpret_cast(engine->get_gfx()->get_buffer_contents(buffer)); + + f.read(buffer_ptr, size * static_cast(numVertices)); + + engine->get_gfx()->release_buffer_contents(buffer, buffer_ptr); + + return buffer; + }; + + // read positions + mesh->position_buffer = read_buffer(sizeof(Vector3)); + mesh->normal_buffer = read_buffer(sizeof(Vector3)); + mesh->texture_coord_buffer = read_buffer(sizeof(Vector2)); + mesh->tangent_buffer = read_buffer(sizeof(Vector3)); + mesh->bitangent_buffer = read_buffer(sizeof(Vector3)); + + if(mesh_type == MeshType::Skinned) + mesh->bone_buffer = read_buffer(sizeof(BoneVertexData)); + + int numIndices = 0; + file->read(&numIndices); + + Expects(numIndices > 0); + + mesh->index_buffer = engine->get_gfx()->create_buffer(nullptr, sizeof(uint32_t) * numIndices, false, GFXBufferUsage::Index); + auto index_ptr = reinterpret_cast(engine->get_gfx()->get_buffer_contents(mesh->index_buffer)); + + file->read(index_ptr, sizeof(uint32_t) * numIndices); + + engine->get_gfx()->release_buffer_contents(mesh->index_buffer, index_ptr); + + int bone_len = 0; + file->read(&bone_len); + + mesh->bones.reserve(bone_len); + + if(bone_len > 0) { + file->read(&mesh->global_inverse_transformation); + + std::map boneMapping; + std::map parentQueue; + + for (int v = 0; v < bone_len; v++) { + std::string bone, parent; + + file->read_string(bone); + file->read_string(parent); + + Vector3 pos; + file->read(&pos); + + Quaternion rot; + file->read(&rot); + + Vector3 scl; + file->read(&scl); + + int finalBoneIndex = 0; + + if(boneMapping.count(bone)) { + finalBoneIndex = boneMapping[bone]; + } else { + Bone b; + b.index = mesh->bones.size(); + b.name = bone; + b.name = bone; + b.position = pos; + b.rotation = rot; + b.scale = scl; + + if(parent != "none" && !parent.empty()) + parentQueue[b.index] = parent; + + mesh->bones.push_back(b); + + boneMapping[bone] = b.index; + finalBoneIndex = b.index; + } + } + + for(auto& [index, parentName] : parentQueue) { + for(auto& bone : mesh->bones) { + if(bone.name == parentName) + mesh->bones[index].parent = &bone; + } + } + + for(auto& bone : mesh->bones) { + if(bone.parent == nullptr) + mesh->root_bone = &bone; + } + } + + int numMeshes = 0; + file->read(&numMeshes); + + Expects(numMeshes > 0); + + mesh->parts.resize(numMeshes); + + uint32_t vertexOffset = 0, indexOffset = 0; + for(int i = 0; i < numMeshes; i++) { + auto& p = mesh->parts[i]; + p.vertex_offset = vertexOffset; + p.index_offset = indexOffset; + + file->read_string(p.name); + + if(version == 6) { + file->read(&p.aabb); + } + + int numVerts = 0; + file->read(&numVerts); + + file->read(&p.index_count); + + int numBones = 0; + file->read(&numBones); + + p.bone_batrix_buffer = engine->get_gfx()->create_buffer(nullptr, sizeof(Matrix4x4) * 128, true, GFXBufferUsage::Storage); + + if(numBones > 0) { + p.offset_matrices.resize(numBones); + + file->read(p.offset_matrices.data(), sizeof(Matrix4x4) * numBones); + } + + file->read(&p.material_override); + + vertexOffset += numVerts; + indexOffset += p.index_count; + } + + mesh->num_indices = static_cast(numIndices); + + return mesh; +} + +std::unique_ptr load_texture(const file::Path path) { + Expects(!path.empty()); + + auto file = file::open(path); + if(!file.has_value()) { + console::error(System::Renderer, "Failed to load texture from {}!", path); + return nullptr; + } + + bool should_generate_mipmaps = true; + + auto texture_info_path = path; + texture_info_path.replace_extension(".json"); + + auto json_file = file::open(texture_info_path); + if(json_file != std::nullopt) { + nlohmann::json j; + json_file->read_as_stream() >> j; + + should_generate_mipmaps = j["generate_mipmaps"]; + } + + file->read_all(); + + int width, height, channels; + unsigned char* data = stbi_load_from_memory(file->cast_data(), file->size(), &width, &height, &channels, 4); + if(!data) { + console::error(System::Renderer, "Failed to load texture from {}!", path); + return nullptr; + } + + Expects(width > 0); + Expects(height > 0); + + auto texture = std::make_unique(); + texture->path = path; + texture->width = width; + texture->height = height; + + GFXTextureCreateInfo createInfo = {}; + createInfo.width = width; + createInfo.height = height; + createInfo.format = GFXPixelFormat::R8G8B8A8_UNORM; + createInfo.usage = GFXTextureUsage::Sampled; + + if(should_generate_mipmaps) + createInfo.mip_count = std::floor(std::log2(std::max(width, height))) + 1; + + texture->handle = engine->get_gfx()->create_texture(createInfo); + + engine->get_gfx()->copy_texture(texture->handle, data, width * height * 4); + + if(createInfo.mip_count > 1) { + GFXCommandBuffer* cmd_buf = engine->get_gfx()->acquire_command_buffer(); + + cmd_buf->generate_mipmaps(texture->handle, createInfo.mip_count); + + engine->get_gfx()->submit(cmd_buf); + } + + stbi_image_free(data); + + return texture; +} + +std::unique_ptr load_material(const file::Path path) { + Expects(!path.empty()); + + auto file = file::open(path); + if(!file.has_value()) { + console::error(System::Core, "Failed to load material from {}!", path); + return {}; + } + + nlohmann::json j; + file->read_as_stream() >> j; + + auto mat = std::make_unique(); + mat->path = path; + + if(!j.count("version") || j["version"] != 2) { + console::error(System::Core, "Material {} failed the version check!", path); + return mat; + } + + for(auto node : j["nodes"]) { + std::unique_ptr n; + + auto name = node["name"]; + if(name == "Material Output") { + n = std::make_unique(); + } else if(name == "Texture") { + n = std::make_unique(); + } else if(name == "Float Constant") { + n = std::make_unique(); + } + + n->id = node["id"]; + n->x = node["x"]; + n->y = node["y"]; + n->width = node["width"]; + n->height = node["height"]; + + for(auto& property : node["properties"]) { + for(auto& p : n->properties) { + if(property["name"] == p.name) { + p.value = property["value"]; + p.float_value = property["float_value"]; + + if(!property["asset_value"].get().empty()) { + p.value_tex = assetm->get(file::app_domain / property["asset_value"].get()); + } + } + } + } + + mat->nodes.emplace_back(std::move(n)); + } + + for(auto node : j["nodes"]) { + MaterialNode* n = nullptr; + for(auto& nn : mat->nodes) { + if(nn->id == node["id"]) + n = nn.get(); + } + + if(n == nullptr) + continue; + + for(auto connection : node["connections"]) { + for(auto [i, output] : utility::enumerate(n->outputs)) { + if(connection["name"] == output.name) { + for(auto& nn : mat->nodes) { + if(nn->id == connection["connected_node"]) { + output.connected_node = nn.get(); + + auto connector = nn->find_connector(connection["connected_connector"]); + output.connected_connector = connector; + + connector->connected_index = i; + connector->connected_node = n; + connector->connected_connector = &output; + } + } + + output.connected_index = connection["connected_index"]; + } + } + } + } + + return mat; +} + +void save_material(Material* material, const std::string_view path) { + Expects(material != nullptr); + Expects(!path.empty()); + + nlohmann::json j; + + j["version"] = 2; + + for(auto& node : material->nodes) { + nlohmann::json n; + n["name"] = node->get_name(); + n["id"] = node->id; + n["x"] = node->x; + n["y"] = node->y; + n["width"] = node->width; + n["height"] = node->height; + + for(auto property : node->properties) { + nlohmann::json p; + p["name"] = property.name; + p["value"] = property.value; + p["asset_value"] = property.value_tex ? property.value_tex->path : ""; + p["float_value"] = property.float_value; + + n["properties"].push_back(p); + } + + for(auto output : node->outputs) { + if(output.connected_connector != nullptr) { + nlohmann::json c; + c["name"] = output.name; + c["connected_connector"] = output.connected_connector->name; + c["connected_node"] = output.connected_node->id; + c["connected_index"] = output.connected_index; + + n["connections"].push_back(c); + } + } + + j["nodes"].push_back(n); + } + + std::ofstream out(path.data()); + out << j; +} diff --git a/engine/audio/CMakeLists.txt b/engine/audio/CMakeLists.txt new file mode 100755 index 0000000..15a444c --- /dev/null +++ b/engine/audio/CMakeLists.txt @@ -0,0 +1,14 @@ +set(SRC + include/audio.hpp + src/audio.cpp) + +add_library(Audio STATIC ${SRC}) +target_include_directories(Audio PUBLIC include) +target_link_libraries(Audio PRIVATE + Log + opus + opusfile + portaudio_static + Core) +target_compile_features(Audio PUBLIC cxx_std_17) +set_target_properties(Audio PROPERTIES CXX_EXTENSIONS OFF) diff --git a/engine/audio/include/audio.hpp b/engine/audio/include/audio.hpp new file mode 100755 index 0000000..989015e --- /dev/null +++ b/engine/audio/include/audio.hpp @@ -0,0 +1,17 @@ +#pragma once + +#include +#include +#include +#include + +#include "file.hpp" + +/* +* Audio API +*/ +namespace audio { + void initialize(); + + void play_file(const file::Path path, const float gain = 1.0f); +} diff --git a/engine/audio/src/audio.cpp b/engine/audio/src/audio.cpp new file mode 100755 index 0000000..cd7c5de --- /dev/null +++ b/engine/audio/src/audio.cpp @@ -0,0 +1,92 @@ +#include "audio.hpp" + +#include +#include +#include +#include + +#include "log.hpp" +#include "file.hpp" +#include "platform.hpp" + +constexpr int num_channels = 2; +constexpr int sample_rate = 48000; +constexpr int frame_size = 960; +constexpr int frames_per_buffer = 480; + +struct AudioFile { + float gain = 1.0f; + bool finished = false; + OggOpusFile* handle = nullptr; +}; + +std::vector audio_files; + +static int pa_callback(const void*, void* buffer, + unsigned long, + const PaStreamCallbackTimeInfo*, + PaStreamCallbackFlags, + void*) { + auto out = static_cast(buffer); + + float final_values[frame_size] = {0.0f}; + + for(auto& file : audio_files) { + if(file.finished) + continue; + + float values[frame_size] = {0.0f}; + + int val = op_read_float_stereo(file.handle, values, frame_size); + if(val == 0) + file.finished = true; + + for(int i = 0; i < frame_size; i++) { + final_values[i] += values[i] * file.gain; + } + } + + memcpy(out, final_values, frame_size * sizeof(float)); + + audio_files.erase(std::remove_if(audio_files.begin(), + audio_files.end(), + [](AudioFile& x){return x.finished;}), + audio_files.end()); + + return 0; +} + +void audio::initialize() { + platform::mute_output(); + + Pa_Initialize(); + + platform::unmute_output(); + + PaStream* stream; + + Pa_OpenDefaultStream(&stream, + 0, + num_channels, + paFloat32, + sample_rate, + frames_per_buffer, + pa_callback, + nullptr); + + Pa_StartStream(stream); +} + +void audio::play_file(const file::Path path, const float gain) { + auto audio_file = file::open(path); + if(audio_file == std::nullopt) + return; + + audio_file->read_all(); + + AudioFile file; + file.gain = gain; + file.handle = op_open_memory(audio_file->cast_data(), audio_file->size(), nullptr); + + audio_files.push_back(file); +} diff --git a/engine/core/CMakeLists.txt b/engine/core/CMakeLists.txt new file mode 100755 index 0000000..98e05c3 --- /dev/null +++ b/engine/core/CMakeLists.txt @@ -0,0 +1,55 @@ +if(TARGET BulletDynamics) + set(BULLET_LIBRARIES BulletDynamics BulletCollision LinearMath) + set(BULLET_INCLUDE_DIRS ${CMAKE_BINARY_DIR}/_deps/bullet-src/src) +else() + find_package(Bullet REQUIRED) +endif() + +set(SRC + include/engine.hpp + include/app.hpp + include/input.hpp + include/cutscene.hpp + include/physics.hpp + include/scene.hpp + include/imguilayer.hpp + include/uielement.hpp + include/screen.hpp + include/object.hpp + include/debug.hpp + include/components.hpp + include/platform.hpp + include/file.hpp + include/imgui_utility.hpp + include/frustum.hpp + + src/file.cpp + src/engine.cpp + src/input.cpp + src/physics.cpp + src/imguilayer.cpp + src/screen.cpp + src/scene.cpp + src/debug.cpp) + +if(NOT ENABLE_IOS AND NOT ENABLE_TVOS) + set(EXTRA_LIBRARIES Audio sol) +endif() + +add_library(Core STATIC ${SRC}) +target_include_directories(Core PUBLIC + include) +target_include_directories(Core SYSTEM PUBLIC + ${BULLET_INCLUDE_DIRS}) +target_link_libraries(Core PUBLIC + Utility + GFX + Renderer + nlohmann_json + magic_enum + ${BULLET_LIBRARIES} + imgui + Log + ${EXTRA_LIBRARIES} + Asset) +set_engine_properties(Core) diff --git a/engine/core/include/app.hpp b/engine/core/include/app.hpp new file mode 100755 index 0000000..92c3fde --- /dev/null +++ b/engine/core/include/app.hpp @@ -0,0 +1,29 @@ +#pragma once + +class Engine; + +/// The base class for any Prism application. +class App { +public: + /// Called when a render context is available. + virtual void initialize_render() {} + + /// Called when the engine is about to quit. Should be overriden if an app needs to save data before qutting. + virtual void prepare_quit() {} + + /// Called to check whether or not an app should intervene quitting. + virtual bool should_quit() { + return true; + } + + /// Called when a engine starts a new frame. Typically used for inserting new imgui windows. + virtual void begin_frame() {} + + /** Called during the engine's update cycle. + @param delta_time Delta time in milliseconds. + */ + virtual void update([[maybe_unused]] const float delta_time) {} +}; + +/// This is an app's equivalent main(). You can check command line arguments through Engine::comand_line_arguments. +void app_main(Engine* engine); diff --git a/engine/core/include/components.hpp b/engine/core/include/components.hpp new file mode 100755 index 0000000..f7cd0d2 --- /dev/null +++ b/engine/core/include/components.hpp @@ -0,0 +1,112 @@ +#pragma once + +#include "assetptr.hpp" +#include "screen.hpp" + +class btCollisionShape; +class btRigidBody; +class Scene; +class Mesh; +class Material; + +struct Collision { + enum class Type { + Cube, + Capsule + } type = Type::Cube; + + Vector3 size; + + bool is_trigger = false; + std::string trigger_id; + bool exclude_from_raycast = false; + + bool trigger_entered = false; + btCollisionShape* shape = nullptr; +}; + +struct Rigidbody { + enum class Type { + Dynamic, + Kinematic + } type = Type::Dynamic; + + int mass = 0; + float friction = 0.5f; + + bool enable_deactivation = true; + bool enable_rotation = true; + + void add_force(const Vector3 force) { + stored_force += force; + } + + btRigidBody* body = nullptr; + Vector3 stored_force; +}; + +struct Data { + std::string name, prefab_path; + Object parent = NullObject; + + bool editor_object = false; +}; + +struct Transform { + Vector3 position, scale = Vector3(1); + Quaternion rotation; + + Matrix4x4 model; + + Vector3 get_world_position() const { + return { + model[3][0], + model[3][1], + model[3][2] + }; + } +}; + +struct Renderable { + AssetPtr mesh; + std::vector> materials; +}; + +struct Light { + enum class Type : int{ + Point = 0, + Spot = 1, + Sun = 2 + } type = Type::Point; + + Vector3 color = Vector3(1); + + float power = 10.0f; + float size = 1.0f; + float spot_size = 40.0f; + + bool enable_shadows = true; + bool use_dynamic_shadows = false; +}; + +struct Camera { + float fov = 75.0f; + float near = 0.1f; + float exposure = 1.0; + + Matrix4x4 view, perspective; +}; + +struct UI { + int width = 1920, height = 1080; + + std::string ui_path; + ui::Screen* screen = nullptr; +}; + +struct EnvironmentProbe { + bool is_sized = true; + Vector3 size = Vector3(10); + + float intensity = 1.0; +}; diff --git a/engine/core/include/cutscene.hpp b/engine/core/include/cutscene.hpp new file mode 100755 index 0000000..89516ec --- /dev/null +++ b/engine/core/include/cutscene.hpp @@ -0,0 +1,75 @@ +#pragma once + +#include + +#include "vector.hpp" +#include "quaternion.hpp" + +struct PositionKeyFrame { + float time; + Vector3 value; +}; + +inline bool operator==(const PositionKeyFrame& lhs, const PositionKeyFrame& rhs) { + return nearly_equal(lhs.time, rhs.time) && nearly_equal(lhs.value.x, rhs.value.x); +} + +struct RotationKeyFrame { + float time; + Quaternion value; +}; + +struct ScaleKeyFrame { + float time; + Vector3 value; +}; + +struct AnimationChannel { + std::string id; + + Object target = NullObject; + Bone* bone = nullptr; + + std::vector positions; + std::vector rotations; + std::vector scales; +}; + +inline bool operator==(const AnimationChannel& lhs, const AnimationChannel& rhs) { + return lhs.id == rhs.id && lhs.target == rhs.target && lhs.positions == rhs.positions; +} + +struct Animation { + double ticks_per_second = 0.0; + double duration = 0.0; + + std::vector channels; +}; + +struct Shot { + int begin, length; + + std::vector channels; + + Scene* scene = nullptr; +}; + +inline bool operator==(const Shot& lhs, const Shot& rhs) { + return lhs.begin == rhs.begin && lhs.length == rhs.length; +} + +class Cutscene { +public: + std::vector shots; + + int get_real_end() { + int end = -1; + for(auto& shot : shots) { + if((shot.begin + shot.length) >= end) + end = shot.begin + shot.length; + + } + + return end; + } +}; diff --git a/engine/core/include/debug.hpp b/engine/core/include/debug.hpp new file mode 100644 index 0000000..6434b05 --- /dev/null +++ b/engine/core/include/debug.hpp @@ -0,0 +1,3 @@ +#pragma once + +void draw_debug_ui(); diff --git a/engine/core/include/engine.hpp b/engine/core/include/engine.hpp new file mode 100755 index 0000000..6586d4d --- /dev/null +++ b/engine/core/include/engine.hpp @@ -0,0 +1,399 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +#if !defined(PLATFORM_IOS) && !defined(PLATFORM_TVOS) +#include +#endif + +#include "scene.hpp" +#include "renderer.hpp" +#include "input.hpp" +#include "cutscene.hpp" +#include "physics.hpp" +#include "file.hpp" +#include "object.hpp" +#include "imguilayer.hpp" +#include "shadowpass.hpp" +#include "scenecapture.hpp" +#include "smaapass.hpp" +#include "gaussianhelper.hpp" +#include "common.hpp" + +class GFX; + +namespace ui { + class Screen; +} + +class App; +struct Timer; + +struct AnimationTarget { + float current_time = 0.0f; + float animation_speed_modifier = 1.0f; + bool looping = false; + + Object target; + Animation animation; +}; + +/// An object that contains glue between App and systems such as the Renderer. +class Engine { +public: + /** + Constructs an Engine with command line arguments. Can be accessed later from command_line_arguments. + + @param argc Numer of arguments. Can be null. + @param argv Array of strings containing arguments. Can be null. + */ + Engine(const int argc, char* argv[]); + + /// Command line arguments, can be empty. + std::vector command_line_arguments; + + /** Sets the app object. + @param app The app object to set. Must not be null. + */ + void set_app(App* app); + + /** Gets the current app object + @return The current app object. Can be null. + */ + App* get_app() const; + + /** Call to begin the next frame. + @param delta_time Delta time in seconds. + */ + void begin_frame(const float delta_time); + + /** Call to start updating the current frame. + @param delta_time Delta time in seconds. + */ + void update(const float delta_time); + + /** Call to begin rendering for a window. + @param index The index of the window to begin rendering for. + */ + void render(const int index); + + /// Pause updating. + void pause(); + + /// Resume updating. + void unpause(); + + /** Query the current pause state. + @return Whether or not the engine is currently paused. + */ + bool is_paused() const; + + /// Request to begin quitting immediately. This is not forced, and can be canceled by the user, platform, or app. + void quit(); + + /// Call right before the platform is about to quit the application, and requests the app or other systems to save work. + void prepare_quit(); + + /// Query whether or not the engine is in the process of quitting. + bool is_quitting() const; + + /** Set the GFX api to use. + @param gfx The GFX object to use. Must not be null. + */ + void set_gfx(GFX* gfx); + + /** Get the current GFX api. + @return The current GFX api. Can be null. + */ + GFX* get_gfx(); + + /** Get the input system. + @return Instance of the input system. Will not be null. + */ + Input* get_input(); + + /** Get the renderer for a window. + @param index Index of the window. Default is 0. + @return Instance of the renderer. Will not be null. + */ + Renderer* get_renderer(const int index = 0); + + /** Get the physics system. + @return Instance of the physics system. Will not be null. + */ + Physics* get_physics(); + + /// Creates an empty scene with no path. This will change the current scene. + void create_empty_scene(); + + /** Load a scene from disk. This will change the current scene if successful. + @param path The scene file path. + @return Returns a instance of the scene is successful, and nullptr on failure. + */ + Scene* load_scene(const file::Path path); + + /** Save the current scene to disk. + @param path The absolute file path. + */ + void save_scene(const std::string_view path); + + /** Load a UI screen from disk. This will not change the current screen. + @param path The screen file path. + @return Returns a instance of the screen if successful, and nullptr on failure. + */ + ui::Screen* load_screen(const file::Path path); + + /** Set the current screen. + @param screen The screen object to set as current. Can be null. + */ + void set_screen(ui::Screen* screen); + + /** Gets the current screen. + @return The current screen. Can be null. + */ + ui::Screen* get_screen() const; + + /** Load a prefab from disk. + @param scene The scene to add the prefab to. + @param path The prefab file path. + @param override_name If not empty, the root object's new name. Defaulted to a empty string. + */ + Object add_prefab(Scene& scene, const file::Path path, const std::string_view override_name = ""); + + /** Save a tree of objects as a prefab to disk. + @param root The parent object to save as a prefab. + @param path The absolue file path. + */ + void save_prefab(const Object root, const std::string_view path); + + /** Deserializes a animation channel from JSON. + @param j The animation channel json to deserialize. + @return An animation channel. + */ + AnimationChannel load_animation(nlohmann::json j); + + /** Load an animation from disk. + @param path The animation file path. + @return An animation. + */ + Animation load_animation(const file::Path path); + + /** Load a cutscene from disk. This changes the current cutscene. + @param path The cutscene file path. + */ + void load_cutscene(const file::Path path); + + /** Saves the current cutscene to disk. + @param path The absolute file path. + */ + void save_cutscene(const std::string_view path); + + /** Adds the window for engine management. + @param native_handle The platform's native handle to it's window equivalent. + @param identifier The identifier of the new window. + @param extent The extent of the window. + */ + void add_window(void* native_handle, const int identifier, const Extent extent); + + /** Removes the window from engine management. Should be called before the window is actually closed. + @param identifier The identifier of the window to remove. + */ + void remove_window(const int identifier); + + /** Called when the window has changed size. + @param identifier The window that has been resized. + @param extent The new extent of the window. + */ + void resize(const int identifier, const Extent extent); + + /** Called when a key has been pressed. + @param keyCode A platform-specific key code. + @note Use platform::get_keycode to get a InputButton equivalent if needed. + @note This function is only intended for debug purposes and all production code should be using the Input system instead. + */ + void process_key_down(const unsigned int keyCode); + + /** Called when a key has been released. + @param keyCode A platform-specific key code. + @note Use platform::get_keycode to get a InputButton equivalent if needed. + @note This function is only intended for debug purposes and all production code should be using the Input system instead. + */ + void process_key_up(const unsigned int keyCode); + + /** Called when a mouse button has been clicked.. + @param button The mouse button. + @param offset The mouse position relative to the window where the click occured. + @note This function is only intended for debug purposes and all production code should be using the Input system instead. + */ + void process_mouse_down(const int button, const Offset offset); + + /** Pushes a UI event for the current screen. Does nothing if there is no screen set. + @param name The name of the event. + @param data Data for the event. Defaulted to an empty string. + */ + void push_event(const std::string_view name, const std::string_view data = ""); + + /** Load a localization file from disk. This will change the current localization. + @param path The localization file path. + */ + void load_localization(const std::string_view path); + + /** Queries whether or not the current localization loaded has a key. + @param id The key to query. + @return Whether or not the locale has the key specified. + @note Having no localization loaded will always return false. + */ + bool has_localization(const std::string_view id) const; + + /** Localizes a string. + @param id The locale key to use. + @return A localized string if the key is found, or an empty string if not found. + @note Having no localization loaded will always return a empty string. + */ + std::string localize(const std::string id); + + /** Adds a timer to the list of timers. + @param timer The timer to add. + @note The timer instance is passed by reference. Use this to keep track of your timers without having to query it's state back. + */ + void add_timer(Timer& timer); + + /** Gets the current scene. + @return The current scene if set, or nullptr if there isn't one. + */ + Scene* get_scene(); + + /** Get a scene by path. This does not change the current scene. + @param name The path to the scene file. + @return Returns a scene if it was previously loaded and found, or nullptr on failure. + */ + Scene* get_scene(const std::string_view name); + + /** Set the current scene. + @param scene The scene to set. Can be null. + */ + void set_current_scene(Scene* scene); + + /** Get the current scene's path. + @return If a scene is loaded, the path to the scene. Can be an empty string if there is no scene loaded, or if it's an empty scene. + */ + std::string_view get_scene_path() const; + + /** Updates the Transform hierarchy for a scene. + @param scene The scene to update. + */ + void update_scene(Scene& scene); + + /// The current cutscene. + std::unique_ptr cutscene; + + /// The current time in seconds for cutscene playback. + float current_cutscene_time = 0.0f; + + /// The cutscene playback state. + bool play_cutscene = false; + + /** Start playback of an animation. + @param animation The animation to play. + @param object The animation's target. + @param looping Whether or not the animation should loop or be discarded when finished. Default is false. + */ + void play_animation(const Animation animation, const Object target, const bool looping = false); + + /** Sets the animation speed of an object. + @param target The object you want to change the animation speed of. + @param modifier The speed to play the object's animations at. A modifier of 2.0 would be 2x the speed, and 0.5 would be 1/2x the speed. + */ + void set_animation_speed_modifier(const Object target, const float modifier); + + /** Stops all animation for an object. + @param target The object you want the animations to stop for. + */ + void stop_animation(const Object target); + + /// If there is a render context available. If this is false, avoid doing any GFX or Renderer work as it could crash or cause undefined behavior. + bool render_ready = false; + + /// If physics should upate. This is a control indepentent of the pause state. + bool update_physics = true; + +#if !defined(PLATFORM_IOS) && !defined(PLATFORM_TVOS) + sol::state lua; +#endif + +#if defined(PLATFORM_TVOS) || defined(PLATFORM_IOS) + bool debug_enabled = true; +#else + bool debug_enabled = false; +#endif + +private: + void create_lua_interface(); + void setup_scene(Scene& scene); + + void on_remove(Object object); + + bool _paused = false; + + ui::Screen* _current_screen = nullptr; + + Scene* _current_scene = nullptr; + std::vector> _scenes; + std::map _path_to_scene; + + struct Window { + int identifier = -1; + Extent extent; + bool quitRequested = false; + + std::unique_ptr renderer = nullptr; + }; + + std::vector _windows; + + Window* get_window(const int identifier) { + for(auto& window : _windows) { + if(window.identifier == identifier) + return &window; + } + + return nullptr; + } + + void calculate_bone(Mesh& mesh, const Mesh::Part& part, Bone& bone, const Bone* parent_bone = nullptr); + void calculate_object(Scene& scene, Object object, const Object parent_object = NullObject); + + Shot* get_shot(const float time); + void update_animation(const Animation& anim, const float time); + void update_cutscene(const float time); + + void update_animation_channel(Scene& scene, const AnimationChannel& channel, const float time); + + App* _app = nullptr; + GFX* _gfx = nullptr; + + std::unique_ptr _input = nullptr; + std::unique_ptr _physics = nullptr; + + std::vector _timers, _timersToRemove; + + std::map _strings; + + std::vector _animation_targets; + + std::unique_ptr _imgui = nullptr; + + const InputButton debug_button = InputButton::Q; +}; + +inline bool operator==(const AnimationTarget& a1, const AnimationTarget& a2) { + return a1.current_time == a2.current_time; +} + +inline Engine* engine = nullptr; diff --git a/engine/core/include/file.hpp b/engine/core/include/file.hpp new file mode 100755 index 0000000..75eb545 --- /dev/null +++ b/engine/core/include/file.hpp @@ -0,0 +1,133 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace file { + enum class Domain { + System, + Internal, + App + }; + + /// Represents a file handle. The file may or may not be fully loaded in memory. + class File { + public: + File(FILE* handle) : handle(handle) {} + + File(File&& f) noexcept : + mem(std::move(f.mem)), + handle(std::exchange(f.handle, nullptr)), + data(std::move(f.data)) {} + + ~File() { + fclose(handle); + } + + /** Loads a type. + @param t The pointer to the type. + @param s If not 0, the size to load is derived from sizeof(T). + */ + template + void read(T* t, const size_t s = 0) { + fread(t, s == 0 ? sizeof(T) : s, 1, handle); + } + + /// Reads a string. Assumes the length is an unsigned integer. + void read_string(std::string& str) { + unsigned int length = 0; + read(&length); + + if(length > 0) { + str.resize(length); + + read(str.data(), sizeof(char) * length); + } + } + + /// Loads the entire file into memory, accessible via cast_data() + void read_all() { + fseek(handle, 0L, SEEK_END); + const size_t _size = static_cast(ftell(handle)); + rewind(handle); + + data.resize(_size); + fread(data.data(), _size, 1, handle); + } + + /// If the file is loaded in memory, cast the underlying data. + template + T* cast_data() { + return reinterpret_cast(data.data()); + } + + /// If the file is loaded in memory, return the size of the file. + size_t size() const { + return data.size(); + } + + /// Reads the entire file as a string. + std::string read_as_string() { + auto s = read_as_stream(); + return std::string((std::istreambuf_iterator(s)), + std::istreambuf_iterator()); + } + + /// Reads the entire file as a ifstream, useful for JSON deserialization. + std::istream read_as_stream() { + read_all(); + + auto char_data = cast_data(); + mem = std::make_unique(char_data, char_data + size()); + return std::istream(mem.get()); + } + + private: + struct membuf : std::streambuf { + inline membuf(char* begin, char* end) { + this->setg(begin, begin, end); + } + }; + + std::unique_ptr mem; + + FILE* handle = nullptr; + + std::vector data; + }; + + using Path = std::filesystem::path; + + /** Sets the domain path to a location in the filesystem. + @param domain The domain type. + @param mode The access mode. + @param path The absolute file path. + */ + void set_domain_path(const Domain domain, const Path path); + Path get_domain_path(const Domain domain); + + /// Converts an absolute path to a domain relative path. + Path get_relative_path(const Domain domain, const Path path); + + /// Returns the path to a writeable directory. + Path get_writeable_directory(); + + /** + Opens a file handle. + @param domain The file domain. + @param path The file path. + @param binary_mode Whether or not to open the file as binary or ASCII. Defaults to false. + @return An optional with a value if the file was loaded correctly, otherwise it's empty. + */ + std::optional open(const Path path, const bool binary_mode = false); + + Path root_path(const Path path); + + inline Path internal_domain = "/internal", app_domain = "/app"; +} + +inline std::array domain_data; diff --git a/engine/core/include/frustum.hpp b/engine/core/include/frustum.hpp new file mode 100755 index 0000000..200337f --- /dev/null +++ b/engine/core/include/frustum.hpp @@ -0,0 +1,99 @@ +#pragma once + +struct CameraFrustum { + std::array planes; +}; + +inline CameraFrustum extract_frustum(const Matrix4x4 combined) { + CameraFrustum frustum; + + // left plane + frustum.planes[0].a = combined.data[0][3] + combined.data[0][0]; + frustum.planes[0].b = combined.data[1][3] + combined.data[1][0]; + frustum.planes[0].c = combined.data[2][3] + combined.data[2][0]; + frustum.planes[0].d = combined.data[3][3] + combined.data[3][0]; + + // right plane + frustum.planes[1].a = combined.data[0][3] - combined.data[0][0]; + frustum.planes[1].b = combined.data[1][3] - combined.data[1][0]; + frustum.planes[1].c = combined.data[2][3] - combined.data[2][0]; + frustum.planes[1].d = combined.data[3][3] - combined.data[3][0]; + + // top plane + frustum.planes[2].a = combined.data[0][3] - combined.data[0][1]; + frustum.planes[2].b = combined.data[1][3] - combined.data[1][1]; + frustum.planes[2].c = combined.data[2][3] - combined.data[2][1]; + frustum.planes[2].d = combined.data[3][3] - combined.data[3][1]; + + // bottom plane + frustum.planes[3].a = combined.data[0][3] + combined.data[0][1]; + frustum.planes[3].b = combined.data[1][3] + combined.data[1][1]; + frustum.planes[3].c = combined.data[2][3] + combined.data[2][1]; + frustum.planes[3].d = combined.data[3][3] + combined.data[3][1]; + + // near plane + frustum.planes[4].a = combined.data[0][2]; + frustum.planes[4].b = combined.data[1][2]; + frustum.planes[4].c = combined.data[2][2]; + frustum.planes[4].d = combined.data[3][2]; + + // far plane + frustum.planes[5].a = combined.data[0][3] - combined.data[0][2]; + frustum.planes[5].b = combined.data[1][3] - combined.data[1][2]; + frustum.planes[5].c = combined.data[2][3] - combined.data[2][2]; + frustum.planes[5].d = combined.data[3][3] - combined.data[3][2]; + + return frustum; +} + +inline CameraFrustum camera_extract_frustum(Scene& scene, Object cam) { + const auto camera_component = scene.get(cam); + const Matrix4x4 combined = camera_component.perspective * camera_component.view; + + return extract_frustum(combined); +} + +inline CameraFrustum normalize_frustum(const CameraFrustum& frustum) { + CameraFrustum normalized_frustum; + for(int i = 0; i < 6; i++) + normalized_frustum.planes[i] = normalize(frustum.planes[i]); + + return normalized_frustum; +} + +inline bool test_point_plane(const Plane& plane, const Vector3& point) { + return distance_to_point(plane, point) > 0.0; +} + +inline bool test_point_frustum(const CameraFrustum& frustum, const Vector3& point) { + bool inside_frustum = false; + + for(int i = 0; i < 6; i++) + inside_frustum |= !test_point_plane(frustum.planes[i], point); + + return !inside_frustum; +} + +inline bool test_aabb_frustum(const CameraFrustum& frustum, const AABB& aabb) { + for(int i = 0; i < 6; i++) { + int out = 0; + + for(const auto point : get_points(aabb)) + out += (distance_to_point(frustum.planes[i], point) < 0.0) ? 1 : 0; + + if(out == 8) + return false; + } + + return true; +} + +inline AABB get_aabb_for_part(const Transform& transform, const Mesh::Part& part) { + AABB aabb = {}; + aabb.min = part.aabb.min - transform.get_world_position(); + aabb.max = transform.get_world_position() + part.aabb.max; + aabb.min *= transform.scale; + aabb.max *= transform.scale; + + return aabb; +} diff --git a/engine/core/include/imgui_utility.hpp b/engine/core/include/imgui_utility.hpp new file mode 100755 index 0000000..2a8d20a --- /dev/null +++ b/engine/core/include/imgui_utility.hpp @@ -0,0 +1,64 @@ +#pragma once + +#include + +#include "utility.hpp" +#include "math.hpp" + +namespace ImGui { + template + inline bool ComboEnum(const char* label, T* t) { + bool result = false; + + const auto preview_value = utility::enum_to_string(*t); + + if (ImGui::BeginCombo(label, preview_value.c_str())) { + for(auto& name : magic_enum::enum_values()) { + const auto n = utility::enum_to_string(name); + + if (ImGui::Selectable(n.c_str(), *t == name)) { + *t = name; + result = true; + } + } + + ImGui::EndCombo(); + } + + return result; + } + + template + void ProgressBar(const char* label, const T value, const TMax max) { + const float progress_saturated = value / static_cast(max); + + char buf[32] = {}; + sprintf(buf, "%d/%d", static_cast(value), static_cast(max)); + ImGui::ProgressBar(progress_saturated, ImVec2(0.0f, 0.0f), buf); + + ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x); + ImGui::Text(label); + } + + inline bool DragQuat(const char* label, Quaternion* quat) { + bool result = false; + + Vector3 euler = quat_to_euler(*quat); + + euler.x = degrees(euler.x); + euler.y = degrees(euler.y); + euler.z = degrees(euler.z); + + if(ImGui::DragFloat3(label, euler.ptr(), 1.0f, 0.0f, 0.0f, "%.3f°")) { + euler.x = radians(euler.x); + euler.y = radians(euler.y); + euler.z = radians(euler.z); + + *quat = euler_to_quat(euler); + + result = true; + } + + return result; + } +} diff --git a/engine/core/include/imguilayer.hpp b/engine/core/include/imguilayer.hpp new file mode 100755 index 0000000..fb16ecf --- /dev/null +++ b/engine/core/include/imguilayer.hpp @@ -0,0 +1,12 @@ +#pragma once + +class ImGuiLayer { +public: + ImGuiLayer(); + + void begin_frame(const float delta_time); + void render(int index); + + void process_key_down(unsigned int keyCode); + void process_key_up(unsigned int keyCode); +}; diff --git a/engine/core/include/input.hpp b/engine/core/include/input.hpp new file mode 100755 index 0000000..c3f866d --- /dev/null +++ b/engine/core/include/input.hpp @@ -0,0 +1,86 @@ +#pragma once + +#include +#include + +#include "platform.hpp" + +enum class Axis { + MouseX, + MouseY, + + ScrollX, + ScrollY, + + LeftStickX, + LeftStickY, + + RightStickX, + RightStickY +}; + +struct InputBindingData { + std::string name; + std::map buttons; + + std::vector axises; + + float value = 0.0f; + + bool repeat = false; + InputButton last_button = InputButton::Invalid; +}; + +/** Input system designed for handling events in a cross platform manner and across different input types. + */ +class Input { +public: + /// Updates input bindings and their values. + void update(); + + /** Add a new binding. + @param name The binding name. + */ + void add_binding(const std::string& name); + + /** Ties a button-type input to the binding. + @param name The binding name. + @param button The button to associate with. + @param value The resulting input value when the button is pressed. Default is 1.0. + */ + void add_binding_button(const std::string& name, InputButton button, float value = 1.0f); + + /** Ties an axis-type input to the button. + @param name The binding name. + @param button The axis to associate with. + */ + void add_binding_axis(const std::string& name, Axis axis); + + /** Gets the input value of a binding. + @param name The binding name. + @return The input value associated with that binding, or 0.0 if none is found. + @note If this binding is tied to a button-type input, assume that 0.0 means not pressed. + @note If this binding is tied to an axis-type input, assume that 0.0 means the stick is centered. + */ + float get_value(const std::string& name); + + /** Gets whether or not the binding is pressed. + @param name The binding name. + @param repeating If true, return a correct value regardless if it was identical for multiple frames. If false, any continued input past the first frame of being pressed is ignored and the input is considered released. + @return If the binding is found, return true if the binding value is 1.0. If no binding is found or if the binding has continued pressing and repeating is turned off, returns false. + */ + bool is_pressed(const std::string& name, bool repeating = false); + + /** Queries if the binding is repeating it's input. + @param name The binding name. + @return If the binding is found, returns true if the binding's values have been identical for multiple frames. Returns false if the binding is not found. + */ + bool is_repeating(const std::string& name); + + /// Returns all of the bindings registered with this Input system. + std::vector get_bindings() const; + +private: + std::vector _input_bindings; + std::tuple _last_cursor_position; +}; diff --git a/engine/core/include/object.hpp b/engine/core/include/object.hpp new file mode 100755 index 0000000..1bdf49e --- /dev/null +++ b/engine/core/include/object.hpp @@ -0,0 +1,6 @@ +#pragma once + +#include + +using Object = uint64_t; +constexpr Object NullObject = 0; diff --git a/engine/core/include/physics.hpp b/engine/core/include/physics.hpp new file mode 100755 index 0000000..81bb0c3 --- /dev/null +++ b/engine/core/include/physics.hpp @@ -0,0 +1,39 @@ +#pragma once + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Weverything" + +#if defined(PLATFORM_MACOS) || defined(PLATFORM_IOS) || defined(PLATFORM_TVOS) +#include +#else +#include +#endif +#include +#pragma clang diagnostic pop + +#include "vector.hpp" +#include "object.hpp" + +class Physics { +public: + Physics(); + + void update(float deltaTime); + + void reset(); + void remove_object(Object obj); + + struct RayResult { + bool hasHit; + Vector3 location; + }; + + RayResult raycast(Vector3 from, Vector3 to); + +private: + std::unique_ptr broadphase; + std::unique_ptr collisionConfiguration; + std::unique_ptr dispatcher; + std::unique_ptr solver; + std::unique_ptr world; +}; diff --git a/engine/core/include/platform.hpp b/engine/core/include/platform.hpp new file mode 100755 index 0000000..3fc81e6 --- /dev/null +++ b/engine/core/include/platform.hpp @@ -0,0 +1,173 @@ +#pragma once + +#include +#include +#include + +#include "common.hpp" + +/// Requestable window flags, which may or may not be respected by the platform. +enum class WindowFlags { + None, + Resizable, + Borderless +}; + +/// Represents a button. This includes keyboard, gamepad and mouse buttons. +enum class InputButton { + Invalid, + C, + V, + X, + Y, + Z, + Backspace, + Enter, + W, + A, + S, + D, + Q, + Shift, + Alt, + Super, + Escape, + Tab, + Ctrl, + Space, + LeftArrow, + RightArrow, + + // gamepad inputs + ButtonA, + ButtonB, + ButtonX, + ButtonY, + + DPadUp, + DPadDown, + DPadLeft, + DPadRight, + + // mouse inputs + MouseLeft, + MouseRight +}; + +enum class PlatformFeature { + Windowing +}; + +namespace platform { + /// Returns a human readable platform name, e.g. Linux. + const char* get_name(); + + /// Queries whether or not the platform supports a certain feature. + bool supports_feature(const PlatformFeature feature); + + /** Opens a new window. + @param title The title of the window. + @param rect The requested size and position of the window. + @param flags The requested window flags. + @note Depending on the platform, some of these parameters might be unused. The best practice is to always assume that none of them may be used. + @note On platforms that do not support the Windowing feature, calling open_window more than once is not supported. In this case, the same identifier is returned. + @return A valid window identifier. + */ + int open_window(const std::string_view title, const Rectangle rect, const WindowFlags flags); + + /** Closes a window. + @param index The window to close. + */ + void close_window(const int index); + + /// Forces the platform to quit the application. This is not related to Engine::quit(). + void force_quit(); + + /// Gets the content scale for the window. 1.0 would be 1x scale, 2.0 would be 2x scale, etc. + float get_window_dpi(const int index); + + /// Gets the content scale for the monitor. 1.0 would be 1x scale, 2.0 would be 2x scale, etc. + float get_monitor_dpi(); + + /// Get the monitor resolution. + Rectangle get_monitor_resolution(); + + /// Get the monitor work area. For example on macOS this may exclude the areas of the menu bar and dock. + Rectangle get_monitor_work_area(); + + /// Get the window position. + Offset get_window_position(const int index); + + /// Get the window size, note that in hidpi scenarios this is the non-scaled resolution. + Extent get_window_size(const int index); + + /// Get the window's drawable size. Always use this instead of manually multiplying the window size by the content scale. + Extent get_window_drawable_size(const int index); + + /// Query whether or not the window is focused. + bool is_window_focused(const int index); + + /// If possible, try to manually focus the window. + void set_window_focused(const int index); + + /// Sets the window position to the offset provided. + void set_window_position(const int index, const Offset offset); + + /// Sets the window to the specified size. The platform will handle the subsequent resize events. + void set_window_size(const int index, const Extent extent); + + /// Sets the window title. + void set_window_title(const int index, const std::string_view title); + + /// Queries whether or not the button is currently pressed. + bool get_key_down(const InputButton key); + + /// If available for the InputButton, returns the platform-specific keycode. + int get_keycode(const InputButton key); + + /// Returns the current moue cursor position, relative to the window. + Offset get_cursor_position(); + + /// Returns the current moue cursor position, relative to the monitor. + Offset get_screen_cursor_position(); + + /// Queries whether or not the mouse button requested is pressed or not. + bool get_mouse_button_down(const int button); + + /// Returns the current mouse wheel delta on both axes. + std::tuple get_wheel_delta(); + + /// Returns the current right stick axes values from 0->1 + std::tuple get_right_stick_position(); + + /// Returns the current left stick axes values from 0->1 + std::tuple get_left_stick_position(); + + /// On platforms that support moue capture, this will lock the mouse cursor to the window and hide it. + void capture_mouse(const bool capture); + + /**Opens a file dialog to select a file. This will not block. + @param existing Whether or not to limit to existing files. + @param returnFunction The callback function when a file is selected or the dialog is cancelled. An empy string is returned when cancelled. + @param openDirectory Whether or not to allow selecting directories as well. + */ + void open_dialog(const bool existing, std::function returnFunction, bool openDirectory = false); + + /**Opens a file dialog to select a save location for a file. This will not block. + @param returnFunction The callback function when a file is selected or the dialog is cancelled. An empy string is returned when cancelled. + */ + void save_dialog(std::function returnFunction); + + /**Translates a virtual keycode to it's character equivalent. + @note Example: translateKey(0x01) = 'a'; 0x01 in this example is a platform and language specific keycode for a key named 'a'. + @return A char pointer to the string if translated correctly. + @note Manually freeing the string returned is not needed. + */ + char* translate_keycode(const unsigned int keycode); + + /// Mute standard output + void mute_output(); + + /// Unmute standard output + void unmute_output(); +} diff --git a/engine/core/include/scene.hpp b/engine/core/include/scene.hpp new file mode 100755 index 0000000..f719f18 --- /dev/null +++ b/engine/core/include/scene.hpp @@ -0,0 +1,279 @@ +#pragma once + +#include +#include +#include +#include + +#if !defined(PLATFORM_IOS) && !defined(PLATFORM_TVOS) +#include +#endif + +#include + +#include "vector.hpp" +#include "matrix.hpp" +#include "quaternion.hpp" +#include "utility.hpp" +#include "transform.hpp" +#include "object.hpp" +#include "asset.hpp" +#include "components.hpp" +#include "aabb.hpp" +#include "plane.hpp" + +template +using Pool = std::unordered_map; + +template +class ObjectComponents : Pool... { +public: + /** Adds a new object. + @param parent The object to parent the new object to. Default is null. + @return The newly created object. Will not be null. + */ + Object add_object(const Object parent = NullObject) { + const Object new_index = make_unique_index(); + + add(new_index).parent = parent; + add(new_index); + + _objects.push_back(new_index); + + return new_index; + } + + /// Adds a new object but with a manually specified id. + Object add_object_by_id(const Object id) { + add(id); + add(id); + + _objects.push_back(id); + + return id; + } + + /// Remove an object. + void remove_object(const Object obj) { + recurse_remove(obj); + } + + /// Find an object by name. + Object find_object(const std::string_view name) const { + for(auto& obj : _objects) { + if(get(obj).name == name) + return obj; + } + + return NullObject; + } + + /// Check whether or not an object exists. + bool object_exists(const std::string_view name) const { + return find_object(name) != NullObject; + } + + /// Check if the object originated from a prefab. This works even on children of a root prefab object. + bool is_object_prefab(const Object obj) const { + bool is_prefab = false; + check_prefab_parent(obj, is_prefab); + + return is_prefab; + } + + /// Duplicates an object and all of it's components and data. + Object duplicate_object(const Object original_object) { + const Object duplicate_object = make_unique_index(); + + (add_duplicate_component(original_object, duplicate_object), ...); + + _objects.push_back(duplicate_object); + + return duplicate_object; + } + + /// Returns all of the children of an object, with optional recursion. + std::vector children_of(const Object obj, const bool recursive = false) const { + std::vector vec; + + if(recursive) { + recurse_children(vec, obj); + } else { + for(auto& o : _objects) { + if(get(o).parent == obj) + vec.push_back(o); + } + } + + return vec; + } + + /// Adds a component. + template + Component& add(const Object object) { + return Pool::emplace(object, Component()).first->second; + } + + /// Returns a component. + template + Component& get(const Object object) { + return Pool::at(object); + } + + /// Returns a component. + template + Component get(const Object object) const { + return Pool::at(object); + } + + /// Checks whether or not an object has a certain component. + template + bool has(const Object object) const { + return Pool::count(object); + } + + /// Removes a component from an object. Is a no-op if the component wasn't attached. + template + bool remove(const Object object) { + if(has(object)) { + Pool::erase(object); + return true; + } else { + return false; + } + } + + /// Returns all instances of a component. + template + std::vector> get_all() { + std::vector> comps; + + for(auto it = Pool::begin(); it != Pool::end(); it++) + comps.emplace_back(it->first, it->second); + + return comps; + } + + /// Returns all objects. + std::vector get_objects() const { + return _objects; + } + + /// Callback function when an object is removed. + std::function on_remove; + +private: + Object make_unique_index() { + return _last_index++; + } + + void recurse_remove(Object obj) { + for(auto& o : children_of(obj)) + recurse_remove(o); + + utility::erase(_objects, obj); + + on_remove(obj); + + (remove(obj), ...); + } + + void check_prefab_parent(Object obj, bool& p) const { + if(!get(obj).prefab_path.empty()) + p = true; + + if(get(obj).parent != NullObject) + check_prefab_parent(get(obj).parent, p); + } + + template + void add_duplicate_component(const Object from, const Object to) { + if(Pool::count(from)) + Pool::emplace(to, Pool::at(from)); + } + + void recurse_children(std::vector& vec, Object obj) const { + for(const auto o : _objects) { + if(get(o).parent == obj) { + vec.push_back(o); + + recurse_children(vec, o); + } + } + } + + Object _last_index = 1; + + std::vector _objects; +}; + +const int max_spot_shadows = 4; +const int max_point_shadows = 4; +const int max_environment_probes = 4; + +class GFXFramebuffer; + +/// Represents a scene consisting of Objects with varying Components. +class Scene : public ObjectComponents { +public: + /// If loaded from disk, the path to the scene file this originated from. + std::string path; + + /// Invalidates the current shadow data for all shadowed lights. This may cause stuttering while the data is regenerated. + void reset_shadows() { + sun_light_dirty = true; + + for(auto& point_dirty : point_light_dirty) + point_dirty = true; + + for(auto& spot_dirty : spot_light_dirty) + spot_dirty = true; + } + + /// Invalidates the current environment probe data. This may cause stuttering while the data is regenerated. + void reset_environment() { + for(auto& probe_dirty : environment_dirty) + probe_dirty = true; + } + + // shadow + GFXTexture* depthTexture = nullptr; + GFXFramebuffer* framebuffer = nullptr; + + Matrix4x4 lightSpace; + Matrix4x4 spotLightSpaces[max_spot_shadows]; + + GFXTexture* pointLightArray = nullptr; + GFXTexture* spotLightArray = nullptr; + + bool sun_light_dirty = false; + std::array point_light_dirty; + std::array spot_light_dirty; + + // environment + std::array environment_dirty; + + GFXTexture *irradianceCubeArray = nullptr, *prefilteredCubeArray = nullptr; + + // script + std::string script_path; + +#if !defined(PLATFORM_IOS) && !defined(PLATFORM_TVOS) + sol::environment env; +#endif +}; + +/** Positions and rotates a camera to look at a target from a position. + @param scene The scene that the camera exists in. + @param cam The camera object. + @param pos The position the camera will be viewing the target from. + @param target The position to be centered in the camera's view. + @note Although this is a look at function, it applies no special attribute to the camera and simply changes it's position and rotation. + */ +inline void camera_look_at(Scene& scene, Object cam, Vector3 pos, Vector3 target) { + scene.get(cam).position = pos; + scene.get(cam).rotation = transform::quat_look_at(pos, target, Vector3(0, 1, 0)); +} + +Object load_object(Scene& scene, const nlohmann::json obj); +nlohmann::json save_object(Object obj); diff --git a/engine/core/include/screen.hpp b/engine/core/include/screen.hpp new file mode 100755 index 0000000..14f4261 --- /dev/null +++ b/engine/core/include/screen.hpp @@ -0,0 +1,52 @@ +#pragma once + +#include +#include +#include +#include + +#if !defined(PLATFORM_IOS) && !defined(PLATFORM_TVOS) +#include +#endif + +#include "uielement.hpp" +#include "file.hpp" + +class GFXBuffer; + +namespace ui { + class Screen { + public: + Screen() {} + Screen(const file::Path path); + + void process_event(const std::string& type, std::string data = ""); + + void process_mouse(const int x, const int y); + void calculate_sizes(); + + std::vector elements; + + UIElement* find_element(const std::string& id); + + using CallbackFunction = std::function; + std::map listeners; + + bool blurs_background = false; + + void add_listener(const std::string& id, std::function callback); + + Extent extent; + bool view_changed = false; + + GFXBuffer* glyph_buffer = nullptr; + GFXBuffer* instance_buffer = nullptr; + GFXBuffer* elements_buffer = nullptr; + + std::string script_path; + +#if !defined(PLATFORM_IOS) && !defined(PLATFORM_TVOS) + sol::environment env; +#endif + }; +} diff --git a/engine/core/include/uielement.hpp b/engine/core/include/uielement.hpp new file mode 100755 index 0000000..4bbde25 --- /dev/null +++ b/engine/core/include/uielement.hpp @@ -0,0 +1,67 @@ +#pragma once + +#include + +#include "asset.hpp" + +enum class MetricType { + Absolute, + Relative, + Offset +}; + +struct Color { + Color() : r(1.0f), g(1.0f), b(1.0f), a(1.0f) {} + + Color(const float v) : r(v), g(v), b(v), a(1.0f) {} + + union { + struct { + float r, g, b, a; + }; + + float v[4]; + }; +}; + +class GFXTexture; +class Texture; + +class UIElement { +public: + struct Metrics { + struct Metric { + MetricType type = MetricType::Absolute; + int value = 0; + }; + + Metric x, y, width, height; + } metrics; + + struct Background { + Color color = Color(0.0f); + std::string image; + + AssetPtr texture; + } background; + + enum class TextLocation { + TopLeft, + Center + } text_location = TextLocation::TopLeft; + + std::string id, text, parent; + + bool wrap_text = false; + + float absolute_x = 0.0f, absolute_y = 0.0f, absolute_width = 0.0f, absolute_height = 0.0f; + float text_x = 0.0f, text_y = 0.0f; + + bool visible = true; + + std::string on_click_script; +}; + +inline bool operator==(const UIElement& a, const UIElement& b) { + return a.id == b.id; +} diff --git a/engine/core/src/debug.cpp b/engine/core/src/debug.cpp new file mode 100644 index 0000000..ba940e6 --- /dev/null +++ b/engine/core/src/debug.cpp @@ -0,0 +1,155 @@ +#include "debug.hpp" + +#include +#include + +#include "engine.hpp" +#include "shadowpass.hpp" +#include "scenecapture.hpp" +#include "gfx.hpp" +#include "asset.hpp" +#include "imgui_utility.hpp" + +void draw_general() { + ImGui::Text("Platform: %s", platform::get_name()); + ImGui::Text("GFX: %s", engine->get_gfx()->get_name()); +} + +void draw_asset() { + ImGui::Text("Asset References"); + + ImGui::Separator(); + + ImGui::BeginChild("asset_child", ImVec2(-1, -1), true); + + for(auto& [path, block] : assetm->reference_blocks) { + ImGui::PushID(&block); + + ImGui::Text("- %s has %llu reference(s)", path.c_str(), block->references); + + ImGui::PushStyleColor(ImGuiCol_Button, (ImVec4)ImColor(200, 0, 0)); + + if(ImGui::SmallButton("Force unload")) + block->references = 0; + + ImGui::PopStyleColor(); + + ImGui::PopID(); + } + + ImGui::EndChild(); +} + +void draw_lighting() { + if(engine->get_scene() != nullptr) { + const auto& lights = engine->get_scene()->get_all(); + + ImGui::Text("Lights"); + + ImGui::Separator(); + + for(auto& [obj, light] : lights) { + auto& transform = engine->get_scene()->get(obj); + ImGui::DragFloat3((engine->get_scene()->get(obj).name + "Position").c_str(), transform.position.ptr()); + } + + ImGui::Text("Environment"); + ImGui::Separator(); + + if(ImGui::Button("Reload shadows")) { + engine->get_scene()->reset_shadows(); + } + + if(ImGui::Button("Reload probes")) { + engine->get_scene()->reset_environment(); + } + } else { + ImGui::TextDisabled("No scene loaded."); + } +} + +void draw_renderer() { + if(engine->get_scene() != nullptr) { + ImGui::Text("Budgets"); + ImGui::Separator(); + + const auto& lights = engine->get_scene()->get_all(); + const auto& probes = engine->get_scene()->get_all(); + const auto& renderables = engine->get_scene()->get_all(); + + ImGui::ProgressBar("Light Budget", lights.size(), max_scene_lights); + ImGui::ProgressBar("Probe Budget", probes.size(), max_environment_probes); + + int material_count = 0; + for(const auto& [obj, renderable] : renderables) { + for(auto& material : renderable.materials) { + if(material) + material_count++; + } + } + + ImGui::ProgressBar("Material Budget", material_count, max_scene_materials); + } else { + ImGui::TextDisabled("No scene loaded for budgeting."); + } + + ImGui::Text("Performance"); + ImGui::Separator(); + + ImGui::Text("FPS: %f", ImGui::GetIO().Framerate); + + ImGui::Text("Options"); + ImGui::Separator(); + + bool should_recompile = false; + + float render_scale = render_options.render_scale; + if(ImGui::DragFloat("Render Scale", &render_scale, 0.1f, 1.0f, 0.1f) && render_scale > 0.0f) { + render_options.render_scale = render_scale; + engine->get_renderer()->resize(engine->get_renderer()->get_extent()); + } + + if(ImGui::InputInt("Shadow Resolution", &render_options.shadow_resolution)) { + engine->get_renderer()->shadow_pass->create_scene_resources(*engine->get_scene()); + engine->get_scene()->reset_shadows(); + } + + ImGui::Checkbox("Enable AA", &render_options.enable_aa); + should_recompile |= ImGui::Checkbox("Enable IBL", &render_options.enable_ibl); + should_recompile |= ImGui::Checkbox("Enable Normal Mapping", &render_options.enable_normal_mapping); + should_recompile |= ImGui::Checkbox("Enable Normal Shadowing", &render_options.enable_normal_shadowing); + should_recompile |= ImGui::Checkbox("Enable Point Shadows", &render_options.enable_point_shadows); + should_recompile |= ImGui::ComboEnum("Shadow Filter", &render_options.shadow_filter); + ImGui::Checkbox("Enable Extra Passes", &render_options.enable_extra_passes); + ImGui::Checkbox("Enable Frustum Culling", &render_options.enable_frustum_culling); + + if(ImGui::Button("Force recompile materials (needed for some render option changes!)") || should_recompile) { + for(auto material : assetm->get_all()) { + material->capture_pipeline = nullptr; + material->skinned_pipeline = nullptr; + material->static_pipeline = nullptr; + } + } +} + +void draw_debug_ui() { + if(ImGui::Begin("General")) + draw_general(); + + ImGui::End(); + + if(ImGui::Begin("Lighting")) + draw_lighting(); + + ImGui::End(); + + if(ImGui::Begin("Assets")) + draw_asset(); + + ImGui::End(); + + if(ImGui::Begin("Rendering")) + draw_renderer(); + + ImGui::End(); +} diff --git a/engine/core/src/engine.cpp b/engine/core/src/engine.cpp new file mode 100755 index 0000000..afc3d9c --- /dev/null +++ b/engine/core/src/engine.cpp @@ -0,0 +1,901 @@ +#include "engine.hpp" + +#include + +#include "timer.hpp" +#include "gfx.hpp" +#include "renderer.hpp" +#include "screen.hpp" +#include "file.hpp" +#include "transform.hpp" +#include "math.hpp" +#include "cutscene.hpp" +#include "log.hpp" +#include "imguilayer.hpp" +#include "app.hpp" +#include "json_conversions.hpp" +#include "debug.hpp" +#include "assertions.hpp" + +Engine::Engine(const int argc, char* argv[]) { + console::info(System::Core, "Prism Engine loading..."); + + for(int i = 0; i < argc; i++) + command_line_arguments.push_back(argv[i]); + + _input = std::make_unique(); + _physics = std::make_unique(); + _imgui = std::make_unique(); + assetm = std::make_unique(); + + create_lua_interface(); +} + +void Engine::set_app(App* app) { + Expects(app != nullptr); + + _app = app; +} + +App* Engine::get_app() const { + return _app; +} + +void Engine::load_localization(const std::string_view path) { + Expects(!path.empty()); + + auto file = file::open(file::app_domain / path); + if(file.has_value()) { + nlohmann::json j; + file->read_as_stream() >> j; + + _strings = j["strings"].get>(); + } +} + +void Engine::pause() { + _paused = true; + push_event("engine_pause"); +} + +void Engine::unpause() { + _paused = false; + push_event("engine_unpause"); +} + +bool Engine::is_paused() const { + return _paused; +} + +void Engine::quit() { + _windows[0].quitRequested = true; +} + +bool Engine::is_quitting() const { + return _windows[0].quitRequested; +} + +void Engine::prepare_quit() { + _app->prepare_quit(); +} + +void Engine::set_gfx(GFX* gfx) { + _gfx = gfx; +} + +GFX* Engine::get_gfx() { + return _gfx; +} + +Input* Engine::get_input() { + return _input.get(); +} + +Renderer* Engine::get_renderer(const int index) { + return _windows[index].renderer.get(); +} + +Physics* Engine::get_physics() { + return _physics.get(); +} + +void Engine::create_empty_scene() { + auto scene = std::make_unique(); + + setup_scene(*scene); + + _scenes.push_back(std::move(scene)); + _current_scene = _scenes.back().get(); +} + +Scene* Engine::load_scene(const file::Path path) { + Expects(!path.empty()); + + auto file = file::open(path); + if(!file.has_value()) { + console::error(System::Core, "Failed to load scene from {}!", path); + return nullptr; + } + + nlohmann::json j; + file->read_as_stream() >> j; + + auto scene = std::make_unique(); + + if(j.contains("script")) + scene->script_path = j["script"]; + + std::map parentQueue; + + for(auto& obj : j["objects"]) { + if(obj.contains("prefabPath")) { + Object o = add_prefab(*scene, file::app_domain / obj["prefabPath"].get()); + + scene->get(o).name = obj["name"]; + + auto& transform = scene->get(o); + transform.position = obj["position"]; + transform.rotation = obj["rotation"]; + transform.scale = obj["scale"]; + } else { + auto o = load_object(*scene.get(), obj); + + if(obj.contains("parent")) + parentQueue[o] = obj["parent"]; + } + } + + for(auto& [obj, toParent] : parentQueue) + scene->get(obj).parent = scene->find_object(toParent); + +#if !defined(PLATFORM_IOS) && !defined(PLATFORM_TVOS) + scene->env = sol::environment(lua, sol::create, lua.globals()); + scene->env["scene"] = scene.get(); + + if(!scene->script_path.empty()) { + auto script_file = file::open(file::root_path(path) / scene->script_path); + if(script_file != std::nullopt) + engine->lua.safe_script(script_file->read_as_string(), scene->env); + } +#endif + + setup_scene(*scene); + + _scenes.push_back(std::move(scene)); + _current_scene = _scenes.back().get(); + _path_to_scene[path] = _scenes.back().get(); + + return _scenes.back().get(); +} + +void Engine::save_scene(const std::string_view path) { + Expects(!path.empty()); + + nlohmann::json j; + + for(auto& obj : _current_scene->get_objects()) { + if(!_current_scene->get(obj).editor_object) + j["objects"].push_back(save_object(obj)); + } + + j["script"] = _current_scene->script_path; + + std::ofstream out(path.data()); + out << j; +} + +ui::Screen* Engine::load_screen(const file::Path path) { + Expects(!path.empty()); + + return new ui::Screen(path); +} + +void Engine::set_screen(ui::Screen* screen) { + _current_screen = screen; + + screen->extent = _windows[0].extent; + screen->calculate_sizes(); + + get_renderer()->set_screen(screen); +} + +ui::Screen* Engine::get_screen() const { + return _current_screen; +} + +AnimationChannel Engine::load_animation(nlohmann::json a) { + AnimationChannel animation; + + for(auto& kf : a["frames"]) { + PositionKeyFrame keyframe; + keyframe.time = kf["time"]; + keyframe.value = kf["value"]; + + animation.positions.push_back(keyframe); + } + + return animation; +} + +Animation Engine::load_animation(const file::Path path) { + Expects(!path.empty()); + + auto file = file::open(path, true); + if(!file.has_value()) { + console::error(System::Core, "Failed to load animation from {}!", path); + return {}; + } + + Animation anim; + + file->read(&anim.duration); + file->read(&anim.ticks_per_second); + + unsigned int num_channels; + file->read(&num_channels); + + for(unsigned int i = 0; i < num_channels; i++) { + AnimationChannel channel; + + file->read_string(channel.id); + + unsigned int num_positions; + file->read(&num_positions); + + for(unsigned int j = 0; j < num_positions; j++) { + PositionKeyFrame key; + file->read(&key); + + channel.positions.push_back(key); + } + + unsigned int num_rotations; + file->read(&num_rotations); + + for(unsigned int j = 0; j < num_rotations; j++) { + RotationKeyFrame key; + file->read(&key); + + channel.rotations.push_back(key); + } + + unsigned int num_scales; + file->read(&num_scales); + + for(unsigned int j = 0; j < num_scales; j++) { + ScaleKeyFrame key; + file->read(&key); + + channel.scales.push_back(key); + } + + anim.channels.push_back(channel); + } + + return anim; +} + +void Engine::load_cutscene(const file::Path path) { + Expects(!path.empty()); + + cutscene = std::make_unique(); + + auto file = file::open(path); + if(!file.has_value()) { + console::error(System::Core, "Failed to load cutscene from {}!", path); + return; + } + + nlohmann::json j; + file->read_as_stream() >> j; + + for(auto& s : j["shots"]) { + Shot shot; + shot.begin = s["begin"]; + shot.length = s["end"]; + + for(auto& animation : s["animations"]) { + shot.channels.push_back(load_animation(animation)); + } + + if(_path_to_scene.count(s["scene"])) { + shot.scene = _path_to_scene[s["scene"]]; + + // try to find main camera + auto [obj, cam] = shot.scene->get_all()[0]; + + for(auto& anim : shot.channels) { + if(anim.target == NullObject) + anim.target = obj; + } + } else { + load_scene(file::root_path(path) / s["scene"].get()); + + if(engine->get_scene() == nullptr) + engine->create_empty_scene(); + + auto cameraObj = engine->get_scene()->add_object(); + engine->get_scene()->add(cameraObj); + + for(auto& anim : shot.channels) { + if(anim.target == NullObject) + anim.target = cameraObj; + } + + _path_to_scene[s["scene"]] = _current_scene; + shot.scene = _current_scene; + } + + cutscene->shots.push_back(shot); + } +} + +void Engine::save_cutscene(const std::string_view path) { + Expects(!path.empty()); + + nlohmann::json j; + + for(auto& shot : engine->cutscene->shots) { + nlohmann::json s; + s["begin"] = shot.begin; + s["end"] = shot.length; + + for(auto& [path, scene] : _path_to_scene) { + if(shot.scene == scene) + s["scene"] = path; + } + + j["shots"].push_back(s); + } + + std::ofstream out(path); + out << j; +} + +Object Engine::add_prefab(Scene& scene, const file::Path path, const std::string_view override_name) { + Expects(!path.empty()); + + auto file = file::open(path); + if(!file.has_value()) { + console::error(System::Core, "Failed to load prefab from {}!", path); + return NullObject; + } + + nlohmann::json j; + file->read_as_stream() >> j; + + Object root_node = NullObject; + + std::map parent_queue; + + for(const auto obj : j["objects"]) { + auto o = load_object(scene, obj); + + if(obj.contains("parent")) { + parent_queue[o] = obj["parent"]; + } else { + root_node = o; + } + } + + for(auto& [obj, parent_name] : parent_queue) + scene.get(obj).parent = scene.find_object(parent_name); + + if(!override_name.empty() && root_node != NullObject) + scene.get(root_node).name = override_name; + + return root_node; +} + +void Engine::save_prefab(const Object root, const std::string_view path) { + Expects(root != NullObject); + Expects(!path.empty()); + + nlohmann::json j; + + for(auto& obj : _current_scene->get_objects()) { + if(!_current_scene->get(obj).editor_object) + j["objects"].push_back(save_object(obj)); + } + + std::ofstream out(path.data()); + out << j; +} + +void Engine::add_window(void* native_handle, const int identifier, const Extent extent) { + Expects(native_handle != nullptr); + Expects(identifier >= 0); + + const auto drawable_extent = platform::get_window_drawable_size(identifier); + + _gfx->initialize_view(native_handle, identifier, drawable_extent.width, drawable_extent.height); + + Window window; + window.identifier = identifier; + window.extent = extent; + window.renderer = std::make_unique(_gfx); + + window.renderer->resize(drawable_extent); + + render_ready = true; + _windows.push_back(std::move(window)); +} + +void Engine::remove_window(const int identifier) { + Expects(identifier >= 0); + + utility::erase_if(_windows, [identifier](Window& w) { + return w.identifier == identifier; + }); +} + +void Engine::resize(const int identifier, const Extent extent) { + Expects(identifier >= 0); + + auto window = get_window(identifier); + + Expects(window != nullptr); + + window->extent = extent; + + const auto drawable_extent = platform::get_window_drawable_size(identifier); + + _gfx->recreate_view(identifier, drawable_extent.width, drawable_extent.height); + window->renderer->resize(drawable_extent); + + if(identifier == 0) { + if(_current_screen != nullptr) { + _current_screen->extent = extent; + _current_screen->calculate_sizes(); + } + } +} + +void Engine::process_key_down(const unsigned int keyCode) { + Expects(keyCode >= 0); + + _imgui->process_key_down(keyCode); + + if(keyCode == platform::get_keycode(debug_button)) + debug_enabled = !debug_enabled; +} + +void Engine::process_key_up(const unsigned int keyCode) { + Expects(keyCode >= 0); + + _imgui->process_key_up(keyCode); +} + +void Engine::process_mouse_down(const int button, const Offset offset) { + Expects(offset.x >= 0); + Expects(offset.y >= 0); + + if(_current_screen != nullptr && button == 0) + _current_screen->process_mouse(offset.x, offset.y); +} + +void Engine::push_event(const std::string_view name, const std::string_view data) { + Expects(!name.empty()); + + if(_current_screen != nullptr) + _current_screen->process_event(name.data(), data.data()); +} + +bool Engine::has_localization(const std::string_view id) const { + Expects(!id.empty()); + + return _strings.count(id.data()); +} + +std::string Engine::localize(const std::string id) { + Expects(!id.empty()); + + return _strings[id]; +} + +void Engine::calculate_bone(Mesh& mesh, const Mesh::Part& part, Bone& bone, const Bone* parent_bone) { + if(part.offset_matrices.empty()) + return; + + Matrix4x4 parent_matrix; + if(parent_bone != nullptr) + parent_matrix = parent_bone->local_transform; + + Matrix4x4 local = transform::translate(Matrix4x4(), bone.position); + local *= matrix_from_quat(bone.rotation); + local = transform::scale(local, bone.scale); + + bone.local_transform = parent_matrix * local; + + bone.final_transform = mesh.global_inverse_transformation * bone.local_transform * part.offset_matrices[bone.index]; + + for(auto& b : mesh.bones) { + if(b.parent != nullptr && b.parent->index == bone.index) + calculate_bone(mesh, part, b, &bone); + } +} + +void Engine::calculate_object(Scene& scene, Object object, const Object parent_object) { + Matrix4x4 parent_matrix; + if(parent_object != NullObject) + parent_matrix = scene.get(parent_object).model; + + auto& transform = scene.get(object); + + Matrix4x4 local = transform::translate(Matrix4x4(), transform.position); + local *= matrix_from_quat(transform.rotation); + local = transform::scale(local, transform.scale); + + transform.model = parent_matrix * local; + + if(scene.has(object)) { + auto& mesh = scene.get(object); + + if(mesh.mesh && !mesh.mesh->bones.empty()) { + for(auto& part : mesh.mesh->parts) { + std::vector bones(mesh.mesh->bones.size()); + + if(scene.get(object).parent != NullObject && scene.has(scene.get(object).parent) && !scene.get(scene.get(object).parent).mesh->bones.empty()) { + for(auto [i, ourBone] : utility::enumerate(mesh.mesh->bones)) { + for(auto& theirBone : scene.get(scene.get(object).parent).mesh->bones) { + if(ourBone.name == theirBone.name) + bones[i] = mesh.mesh->global_inverse_transformation * theirBone.local_transform * part.offset_matrices[ourBone.index]; + } + } + } else { + calculate_bone(*mesh.mesh.handle, part, *mesh.mesh->root_bone); + + for(auto [i, bone] : utility::enumerate(bones)) + bones[i] = mesh.mesh->bones[i].final_transform; + } + + engine->get_gfx()->copy_buffer(part.bone_batrix_buffer, bones.data(), 0, bones.size() * sizeof(Matrix4x4)); + } + } + } + + for(auto& child : scene.children_of(object)) + calculate_object(scene, child, object); +} + +Shot* Engine::get_shot(const float time) { + for(auto& shot : engine->cutscene->shots) { + if(time >= shot.begin && time <= (shot.begin + shot.length)) + return &shot; + } + + return nullptr; +} + +void Engine::update_animation_channel(Scene& scene, const AnimationChannel& channel, const float time) { + { + int keyframeIndex = -1; + int i = 0; + for(auto& frame : channel.positions) { + if(time >= frame.time) + keyframeIndex = i; + + i++; + } + + if(keyframeIndex != -1) { + Vector3* targetVec = nullptr; + if(channel.bone != nullptr) + targetVec = &channel.bone->position; + + if(channel.target != NullObject && scene.has(channel.target)) + targetVec = &scene.get(channel.target).position; + + auto& startFrame = channel.positions[keyframeIndex]; + + int endFrameIndex = keyframeIndex + 1; + if(endFrameIndex > channel.positions.size() - 1) { + if(targetVec != nullptr) + *targetVec = startFrame.value; + } else { + auto& endFrame = channel.positions[endFrameIndex]; + + if(targetVec != nullptr) + *targetVec = lerp(startFrame.value, endFrame.value, (float)(time - startFrame.time) / (float)(endFrame.time - startFrame.time)); + } + } + } + + { + int keyframeIndex = -1; + int i = 0; + for(auto& frame : channel.rotations) { + if(time >= frame.time) + keyframeIndex = i; + + i++; + } + + if(keyframeIndex != -1) { + Quaternion* targetVec = nullptr; + if(channel.bone != nullptr) + targetVec = &channel.bone->rotation; + + auto& startFrame = channel.rotations[keyframeIndex]; + + int endFrameIndex = keyframeIndex + 1; + if(endFrameIndex > channel.rotations.size() - 1) { + if(targetVec != nullptr) + *targetVec = startFrame.value; + } else { + auto& endFrame = channel.rotations[endFrameIndex]; + + if(targetVec != nullptr) + *targetVec = lerp(startFrame.value, endFrame.value, (float)(time - startFrame.time) / (float)(endFrame.time - startFrame.time)); + } + } + } +} + +void Engine::update_cutscene(const float time) { + Shot* currentShot = get_shot(time); + if(currentShot != nullptr) { + _current_scene = currentShot->scene; + + for(auto& channel : currentShot->channels) + update_animation_channel(*_current_scene, channel, time); + } else { + _current_scene = nullptr; + } +} + +void Engine::update_animation(const Animation& anim, const float time) { + for(const auto& channel : anim.channels) + update_animation_channel(*_current_scene, channel, time); +} + +void Engine::begin_frame(const float delta_time) { + _imgui->begin_frame(delta_time); + + if(debug_enabled) + draw_debug_ui(); + + if(_app != nullptr) + _app->begin_frame(); +} + +void Engine::update(const float delta_time) { + const float ideal_delta_time = 0.01667f; + + if(render_options.dynamic_resolution) { + if(delta_time < ideal_delta_time) { + render_options.render_scale -= 0.1f; + + render_options.render_scale = std::fmax(render_options.render_scale, 0.1f); + } + } + + for(auto& timer : _timers) { + if(!_paused || (_paused && timer->continue_during_pause)) + timer->current_time += delta_time; + + if(timer->current_time >= timer->duration) { + timer->callback(); + + timer->current_time = 0.0f; + + if(timer->remove_on_trigger) + _timersToRemove.push_back(timer); + } + } + + for(auto& timer : _timersToRemove) + utility::erase(_timers, timer); + + _timersToRemove.clear(); + + _input->update(); + + _app->update(delta_time); + + if(_current_scene != nullptr) { + if(update_physics && !_paused) + _physics->update(delta_time); + + if(cutscene != nullptr && play_cutscene && !_paused) { + update_cutscene(current_cutscene_time); + + current_cutscene_time += delta_time; + } + + for(auto& target : _animation_targets) { + if((target.current_time * target.animation.ticks_per_second) > target.animation.duration) { + if(target.looping) { + target.current_time = 0.0f; + } else { + utility::erase(_animation_targets, target); + } + } else { + update_animation(target.animation, target.current_time * target.animation.ticks_per_second); + + target.current_time += delta_time * target.animation_speed_modifier; + } + } + + update_scene(*_current_scene); + } + + assetm->perform_cleanup(); +} + +void Engine::update_scene(Scene& scene) { + for(auto& obj : scene.get_objects()) { + if(scene.get(obj).parent == NullObject) + calculate_object(scene, obj); + } +} + +void Engine::render(const int index) { + Expects(index >= 0); + + auto window = get_window(index); + if(window == nullptr) + return; + + if(index == 0) { + if(_current_screen != nullptr && _current_screen->view_changed) { + _windows[0].renderer->update_screen(); + _current_screen->view_changed = false; + } + + _imgui->render(0); + } + + if(window->renderer != nullptr) + window->renderer->render(_current_scene, index); +} + +void Engine::add_timer(Timer& timer) { + _timers.push_back(&timer); +} + +Scene* Engine::get_scene() { + return _current_scene; +} + +Scene* Engine::get_scene(const std::string_view name) { + Expects(!name.empty()); + + return _path_to_scene[name.data()]; +} + +void Engine::set_current_scene(Scene* scene) { + _current_scene = scene; +} + +std::string_view Engine::get_scene_path() const { + for(auto& [path, scene] : _path_to_scene) { + if(scene == this->_current_scene) + return path; + } + + return ""; +} + +void Engine::on_remove(Object object) { + Expects(object != NullObject); + + _physics->remove_object(object); +} + +void Engine::play_animation(Animation animation, Object object, bool looping) { + Expects(object != NullObject); + + if(!_current_scene->has(object)) + return; + + AnimationTarget target; + target.animation = animation; + target.target = object; + target.looping = looping; + + for(auto& channel : target.animation.channels) { + for(auto& bone : _current_scene->get(object).mesh->bones) { + if(channel.id == bone.name) + channel.bone = &bone; + } + } + + _animation_targets.push_back(target); +} + +void Engine::set_animation_speed_modifier(Object target, float modifier) { + for(auto& animation : _animation_targets) { + if(animation.target == target) + animation.animation_speed_modifier = modifier; + } +} + +void Engine::stop_animation(Object target) { + for(auto& animation : _animation_targets) { + if(animation.target == target) + utility::erase(_animation_targets, animation); + } +} + +void Engine::create_lua_interface() { +#if !defined(PLATFORM_IOS) && !defined(PLATFORM_TVOS) + lua.open_libraries(sol::lib::base, sol::lib::package, sol::lib::table, sol::lib::string, sol::lib::math); + + lua.new_usertype("Cutscene"); + + lua.new_usertype("InputBindingData", + "name", &InputBindingData::name); + + lua.new_usertype("Input", + "get_bindings", sol::readonly_property(&Input::get_bindings)); + + lua.new_usertype("Engine", + "pause", &Engine::pause, + "unpause", &Engine::unpause, + "clear_cutscene", [this] { + cutscene = nullptr; + }, + "update_screen", [this] { + get_renderer()->update_screen(); + }, + "quit", &Engine::quit, + "get_input", sol::readonly_property(&Engine::get_input), + "push_event", &Engine::push_event); + + lua["engine"] = this; + + lua.new_usertype("UIScreen", + "find_element", &ui::Screen::find_element, + "add_element", [](ui::Screen* screen, UIElement& element) { + screen->elements.push_back(element); + }); + + lua.new_usertype("UIElementBackground", + "image", &UIElement::Background::image); + + lua.new_usertype("UIElementMetric", + "value", &UIElement::Metrics::Metric::value); + + lua.new_usertype("UIElementMetrics", + "x", &UIElement::Metrics::x, + "y", &UIElement::Metrics::y, + "width", &UIElement::Metrics::width, + "height", &UIElement::Metrics::height); + + lua.new_usertype("UIElement", + "id", &UIElement::id, + "text", &UIElement::text, + "=background", &UIElement::background, + "visible", &UIElement::visible, + "metrics", &UIElement::metrics); + + lua.new_usertype("Scene"); + + lua["get_transform"] = [](Object o) -> Transform& { + return engine->get_scene()->get(o); + }; + + lua.new_usertype("Transform", + "position", &Transform::position); + + lua.new_usertype("Vector3", + "x", &Vector3::x, + "y", &Vector3::y, + "z", &Vector3::z); +#endif +} + +void Engine::setup_scene(Scene& scene) { + _physics->reset(); + + scene.on_remove = [this](Object obj) { + on_remove(obj); + }; + + get_renderer()->shadow_pass->create_scene_resources(scene); + get_renderer()->scene_capture->create_scene_resources(scene); + + scene.reset_shadows(); + scene.reset_environment(); +} diff --git a/engine/core/src/file.cpp b/engine/core/src/file.cpp new file mode 100755 index 0000000..5b0d2b3 --- /dev/null +++ b/engine/core/src/file.cpp @@ -0,0 +1,41 @@ +#include "file.hpp" + +#include "string_utils.hpp" +#include "log.hpp" +#include "assertions.hpp" + +file::Path file::root_path(const Path path) { + auto p = path; + while(p.parent_path() != p && p.parent_path() != "/") { + p = p.parent_path(); + } + + return p; +} + +std::optional file::open(const file::Path path, const bool binary_mode) { + Expects(!path.empty()); + + auto fixed_path = path; + if(root_path(path) == app_domain) { + fixed_path = domain_data[static_cast(Domain::App)] / path.lexically_relative(root_path(path)); + } else if(root_path(path) == internal_domain) { + fixed_path = domain_data[static_cast(Domain::Internal)] / path.lexically_relative(root_path(path)); + } + + FILE* file = fopen(fixed_path.c_str(), binary_mode ? "rb" : "r"); + if(file == nullptr) { + console::error(System::File, "Failed to open file handle from {}!", path); + return {}; + } + + return file::File(file); +} + +file::Path file::get_domain_path(const Domain domain) { + return domain_data[static_cast(domain)]; +} + +file::Path parent_domain(const file::Path path) { + return path; +} diff --git a/engine/core/src/imguilayer.cpp b/engine/core/src/imguilayer.cpp new file mode 100755 index 0000000..e648923 --- /dev/null +++ b/engine/core/src/imguilayer.cpp @@ -0,0 +1,211 @@ +#include "imguilayer.hpp" + +#include +#include + +#include "engine.hpp" +#include "platform.hpp" +#include "assertions.hpp" + +const std::map imToPl = { + {ImGuiKey_Tab, InputButton::Tab}, + {ImGuiKey_LeftArrow, InputButton::LeftArrow}, + {ImGuiKey_RightArrow, InputButton::RightArrow}, + {ImGuiKey_UpArrow, InputButton::Escape}, + {ImGuiKey_DownArrow, InputButton::Escape}, + {ImGuiKey_PageUp, InputButton::Escape}, + {ImGuiKey_PageDown, InputButton::Escape}, + {ImGuiKey_Home, InputButton::Escape}, + {ImGuiKey_End, InputButton::Escape}, + {ImGuiKey_Insert, InputButton::Escape}, + {ImGuiKey_Delete, InputButton::Escape}, + {ImGuiKey_Backspace, InputButton::Backspace}, + {ImGuiKey_Space, InputButton::Space}, + {ImGuiKey_Enter, InputButton::Enter}, + {ImGuiKey_Escape, InputButton::Escape}, + {ImGuiKey_A, InputButton::A}, + {ImGuiKey_C, InputButton::C}, + {ImGuiKey_V, InputButton::V}, + {ImGuiKey_X, InputButton::X}, + {ImGuiKey_Y, InputButton::Y}, + {ImGuiKey_Z, InputButton::Z} +}; + +ImGuiLayer::ImGuiLayer() { + ImGui::CreateContext(); + + ImGuiIO& io = ImGui::GetIO(); + io.IniFilename = ""; + io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; + io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; + io.BackendFlags |= ImGuiBackendFlags_PlatformHasViewports; + io.BackendPlatformName = "Prism"; + + //if(platform::supports_feature(PlatformFeature::Windowing)) + // io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; + + for (auto& [im, pl] : imToPl) + io.KeyMap[im] = platform::get_keycode(pl); + + ImGui::StyleColorsDark(); + + auto& style = ImGui::GetStyle(); + style.FrameRounding = 3; + style.FrameBorderSize = 0.0f; + style.WindowBorderSize = 0.0f; + style.WindowPadding = ImVec2(10, 10); + style.FramePadding = ImVec2(4, 4); + style.ItemInnerSpacing = ImVec2(5, 0); + style.ItemSpacing = ImVec2(10, 5); + style.ScrollbarSize = 10; + style.GrabMinSize = 6; + style.WindowRounding = 3.0f; + style.ChildRounding = 3.0f; + style.PopupRounding = 3.0f; + style.ScrollbarRounding = 12.0f; + style.GrabRounding = 3.0f; + style.TabRounding = 3.0f; + style.WindowTitleAlign = ImVec2(0.0, 0.5); + + ImVec4* colors = ImGui::GetStyle().Colors; + colors[ImGuiCol_FrameBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.54f); + colors[ImGuiCol_FrameBgHovered] = ImVec4(0.68f, 0.68f, 0.68f, 0.40f); + colors[ImGuiCol_FrameBgActive] = ImVec4(0.42f, 0.47f, 0.52f, 0.67f); + colors[ImGuiCol_TitleBgActive] = ImVec4(0.23f, 0.43f, 0.73f, 1.00f); + colors[ImGuiCol_CheckMark] = ImVec4(0.74f, 0.80f, 0.87f, 1.00f); + colors[ImGuiCol_SliderGrab] = ImVec4(0.46f, 0.54f, 0.64f, 1.00f); + colors[ImGuiCol_Button] = ImVec4(0.38f, 0.51f, 0.65f, 0.40f); + colors[ImGuiCol_ButtonHovered] = ImVec4(0.57f, 0.61f, 0.67f, 1.00f); + colors[ImGuiCol_ButtonActive] = ImVec4(0.32f, 0.34f, 0.36f, 1.00f); + colors[ImGuiCol_Tab] = ImVec4(0.22f, 0.27f, 0.33f, 0.86f); + colors[ImGuiCol_TabActive] = ImVec4(0.33f, 0.51f, 0.75f, 1.00f); + colors[ImGuiCol_TabUnfocusedActive] = ImVec4(0.30f, 0.33f, 0.38f, 1.00f); + + ImGuiViewport* main_viewport = ImGui::GetMainViewport(); + main_viewport->PlatformHandle = new int(0); + + ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); + + ImGuiPlatformMonitor monitor = {}; + + const auto rect = platform::get_monitor_resolution(); + monitor.MainPos = rect.offset; + monitor.MainSize = rect.extent; + + const auto wrect = platform::get_monitor_work_area(); + monitor.WorkPos = wrect.offset; + monitor.WorkSize = wrect.extent; + + monitor.DpiScale = platform::get_monitor_dpi(); + + platform_io.Monitors.push_back(monitor); + + platform_io.Platform_CreateWindow = [](ImGuiViewport* viewport) { + viewport->PlatformHandle = new int(platform::open_window("", {viewport->Pos, viewport->Size}, WindowFlags::Borderless)); + }; + + platform_io.Platform_DestroyWindow = [](ImGuiViewport* viewport) { + platform::close_window(*(int*)viewport->PlatformHandle); + }; + + platform_io.Platform_ShowWindow = [](ImGuiViewport*) {}; + + platform_io.Platform_SetWindowPos = [](ImGuiViewport* viewport, const ImVec2 pos) { + platform::set_window_position(*(int*)viewport->PlatformHandle, pos); + }; + + platform_io.Platform_GetWindowPos = [](ImGuiViewport* viewport) { + auto [x, y] = platform::get_window_position(*(int*)viewport->PlatformHandle); + return ImVec2(x, y); + }; + + platform_io.Platform_SetWindowSize = [](ImGuiViewport* viewport, const ImVec2 size) { + platform::set_window_size(*(int*)viewport->PlatformHandle, size); + }; + + platform_io.Platform_GetWindowSize = [](ImGuiViewport* viewport) { + auto [x, y] = platform::get_window_size(*(int*)viewport->PlatformHandle); + return ImVec2(x, y); + }; + + platform_io.Platform_SetWindowFocus = [](ImGuiViewport* viewport) { + platform::set_window_focused(*(int*)viewport->PlatformHandle); + }; + + platform_io.Platform_GetWindowFocus = [](ImGuiViewport* viewport) { + return platform::is_window_focused(*(int*)viewport->PlatformHandle); + }; + + platform_io.Platform_GetWindowMinimized = [](ImGuiViewport*) { + return false; + }; + + platform_io.Platform_SetWindowTitle = [](ImGuiViewport* viewport, const char* title) { + platform::set_window_title(*(int*)viewport->PlatformHandle, title); + }; +} + +void ImGuiLayer::begin_frame(const float delta_time) { + ImGuiIO& io = ImGui::GetIO(); + + const auto [width, height] = platform::get_window_size(0); + const auto [dw, dh] = platform::get_window_drawable_size(0); + + io.DisplaySize = ImVec2(width, height); + io.DisplayFramebufferScale = ImVec2((float)dw / width, (float)dh / height); + io.DeltaTime = delta_time; + io.KeyCtrl = platform::get_key_down(InputButton::Ctrl); + io.KeyShift = platform::get_key_down(InputButton::Shift); + io.KeyAlt = platform::get_key_down(InputButton::Alt); + io.KeySuper = platform::get_key_down(InputButton::Super); + io.MouseHoveredViewport = 0; + + const auto [sx, sy] = platform::get_wheel_delta(); + io.MouseWheel = sy; + io.MouseWheelH = sx; + + if(io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) { + const auto [x, y] = platform::get_screen_cursor_position(); + + io.MousePos = ImVec2(static_cast(x), static_cast(y)); + } else { + const auto [x, y] = platform::get_cursor_position(); + + io.MousePos = ImVec2(static_cast(x), static_cast(y)); + } + + io.MouseDown[0] = platform::get_mouse_button_down(0); + io.MouseDown[1] = platform::get_mouse_button_down(1); + + ImGui::NewFrame(); +} + +void ImGuiLayer::render(int index) { + Expects(index >= 0); + + if(index == 0) { + ImGui::EndFrame(); + ImGui::Render(); + + ImGui::UpdatePlatformWindows(); + } +} + +void ImGuiLayer::process_key_down(unsigned int keyCode) { + Expects(keyCode >= 0); + + ImGuiIO& io = ImGui::GetIO(); + + if(keyCode != 52) + io.AddInputCharactersUTF8(platform::translate_keycode(keyCode)); + + io.KeysDown[keyCode] = true; +} + +void ImGuiLayer::process_key_up(unsigned int keyCode) { + Expects(keyCode >= 0); + + ImGuiIO& io = ImGui::GetIO(); + + io.KeysDown[keyCode] = false; +} diff --git a/engine/core/src/input.cpp b/engine/core/src/input.cpp new file mode 100755 index 0000000..0f44e32 --- /dev/null +++ b/engine/core/src/input.cpp @@ -0,0 +1,155 @@ +#include "input.hpp" + +#include + +#include "engine.hpp" +#include "log.hpp" + +bool is_in_range(int value, int cond, int range) { + int low = cond - range; + int high = cond + range; + + return value >= low && value <= high; +} + +void Input::update() { + const auto& [x, y] = platform::get_cursor_position(); + auto& [oldX, oldY] = _last_cursor_position; + + const auto [width, height] = platform::get_window_size(0); + + float xDelta = (x - oldX) / (float)width; + float yDelta = (y - oldY) / (float)height; + + if(is_in_range(x, width / 2, 3) && is_in_range(y, height / 2, 3)) { + xDelta = 0.0f; + yDelta = 0.0f; + } + + _last_cursor_position = { x, y }; + + for (auto& binding : _input_bindings) { + binding.value = 0.0f; + + for (auto& [key, value] : binding.buttons) { + bool is_pressed = false; + switch(key) { + case InputButton::MouseLeft: + is_pressed = platform::get_mouse_button_down(0); + break; + case InputButton::MouseRight: + is_pressed = platform::get_mouse_button_down(1); + break; + default: + is_pressed = platform::get_key_down(key); + break; + } + + if (is_pressed) { + binding.value = value; + + if (binding.last_button == key) { + binding.repeat = true; + } + else { + binding.repeat = false; + } + + binding.last_button = key; + } + } + + if (binding.value == 0.0f) { + binding.last_button = InputButton::Invalid; + binding.repeat = false; + } + + for(auto& axis : binding.axises) { + auto [lx, ly] = platform::get_left_stick_position(); + auto [rx, ry] = platform::get_right_stick_position(); + auto [sx, sy] = platform::get_wheel_delta(); + + float nextValue = 0.0f; + + switch (axis) { + case Axis::MouseX: + nextValue = xDelta; + break; + case Axis::MouseY: + nextValue = yDelta; + break; + case Axis::ScrollX: + nextValue = sx; + break; + case Axis::ScrollY: + nextValue = sy; + break; + case Axis::LeftStickX: + nextValue = lx; + break; + case Axis::LeftStickY: + nextValue = ly; + break; + case Axis::RightStickX: + nextValue = rx; + break; + case Axis::RightStickY: + nextValue = ry; + break; + } + + if(nextValue != 0.0f) + binding.value = nextValue; + } + } +} + +void Input::add_binding(const std::string& name) { + InputBindingData data; + data.name = name; + + _input_bindings.push_back(data); +} + +void Input::add_binding_button(const std::string& name, InputButton key, float value) { + for (auto& binding : _input_bindings) { + if (binding.name == name) + binding.buttons[key] = value; + } +} + +void Input::add_binding_axis(const std::string& name, Axis axis) { + for (auto& binding : _input_bindings) { + if (binding.name == name) { + binding.axises.push_back(axis); + } + } +} + +float Input::get_value(const std::string& name) { + for (auto& binding : _input_bindings) { + if (binding.name == name) { + return binding.value; + } + } + + return 0.0f; +} + +bool Input::is_pressed(const std::string &name, bool repeating) { + return get_value(name) == 1.0 && (repeating ? true : !is_repeating(name)); +} + +bool Input::is_repeating(const std::string& name) { + for (auto& binding : _input_bindings) { + if (binding.name == name) { + return binding.repeat; + } + } + + return false; +} + +std::vector Input::get_bindings() const { + return _input_bindings; +} diff --git a/engine/core/src/physics.cpp b/engine/core/src/physics.cpp new file mode 100755 index 0000000..00bc980 --- /dev/null +++ b/engine/core/src/physics.cpp @@ -0,0 +1,148 @@ +#include "physics.hpp" + +#include "engine.hpp" + +Physics::Physics() { + reset(); +} + +void Physics::update(float deltaTime) { + if(engine->get_scene() == nullptr) + return; + + for(auto [obj, rigidbody] : engine->get_scene()->get_all()) { + if(rigidbody.body != nullptr) { + if(rigidbody.type == Rigidbody::Type::Dynamic) { + if(rigidbody.stored_force != Vector3(0.0f)) { + rigidbody.body->setLinearVelocity(btVector3(rigidbody.stored_force.x, rigidbody.stored_force.y, rigidbody.stored_force.z)); + rigidbody.stored_force = Vector3(0.0f); + } + } + } + } + + world->stepSimulation(deltaTime); + + for(auto [object, collision] : engine->get_scene()->get_all()) { + if(collision.shape == nullptr && !collision.is_trigger) { + switch(collision.type) { + case Collision::Type::Cube: + collision.shape = new btBoxShape(btVector3(collision.size.x / 2.0f, collision.size.y / 2.0f, collision.size.z / 2.0f)); + break; + case Collision::Type::Capsule: + collision.shape = new btCapsuleShape(0.5f, collision.size.y); + break; + } + } + } + + for(auto [obj, rigidbody] : engine->get_scene()->get_all()) { + auto& transform = engine->get_scene()->get(obj); + + if(rigidbody.body == nullptr) { + btTransform t; + t.setIdentity(); + + t.setOrigin(btVector3(transform.position.x, transform.position.y, transform.position.z)); + t.setRotation(btQuaternion(transform.rotation.x, transform.rotation.y, transform.rotation.z, transform.rotation.w)); + + btDefaultMotionState* motionState = new btDefaultMotionState(t); + + btScalar bodyMass = rigidbody.mass; + btVector3 bodyInertia; + + if(rigidbody.mass != 0) + engine->get_scene()->get(obj).shape->calculateLocalInertia(bodyMass, bodyInertia); + + btRigidBody::btRigidBodyConstructionInfo bodyCI = btRigidBody::btRigidBodyConstructionInfo(bodyMass, motionState, engine->get_scene()->get(obj).shape, bodyInertia); + + bodyCI.m_friction = rigidbody.friction; + + rigidbody.body = new btRigidBody(bodyCI); + + if(!rigidbody.enable_deactivation) + rigidbody.body->setActivationState(DISABLE_DEACTIVATION); + + if(!rigidbody.enable_rotation) + rigidbody.body->setAngularFactor(btVector3(0, 0, 0)); + + world->addRigidBody(rigidbody.body); + + rigidbody.body->setUserIndex(obj); + } + + if(rigidbody.type == Rigidbody::Type::Dynamic) { + btTransform trans = rigidbody.body->getWorldTransform(); + transform.position = Vector3(trans.getOrigin().x(), trans.getOrigin().y(), trans.getOrigin().z()); + } else { + btTransform t; + t.setIdentity(); + + t.setOrigin(btVector3(transform.position.x, transform.position.y, transform.position.z)); + t.setRotation(btQuaternion(transform.rotation.x, transform.rotation.y, transform.rotation.z, transform.rotation.w)); + + rigidbody.body->setWorldTransform(t); + } + } +} + +void Physics::remove_object(Object object) { + if(engine->get_scene()->has(object)) { + for(int i = 0 ; i < world->getNumCollisionObjects(); i++) { + auto obj = world->getCollisionObjectArray()[i]; + + if(obj->getUserIndex() == object) { + world->removeCollisionObject(obj); + delete obj; + } + } + } +} + +Physics::RayResult Physics::raycast(Vector3 from, Vector3 to) { + Physics::RayResult result; + + btVector3 btFrom(from.x, from.y, from.z); + btVector3 btTo(to.x, to.y, to.z); + + btCollisionWorld::AllHitsRayResultCallback res(btFrom, btTo); + + world->rayTest(btFrom, btTo, res); + + int closestCollisionObject = NullObject; + float closestHitFraction = 1000.0f; + + for(int i = 0; i < res.m_collisionObjects.size(); i++) { + if(!engine->get_scene()->get(res.m_collisionObjects[i]->getUserIndex()).exclude_from_raycast) { + if(res.m_hitFractions[i] < closestHitFraction) { + closestCollisionObject = i; + closestHitFraction = res.m_hitFractions[i]; + } + } + } + + if(closestCollisionObject != NullObject) { + result.hasHit = true; + + auto vec = res.m_hitPointWorld[closestCollisionObject];; + + result.location = Vector3(vec.x(), vec.y(), vec.z()); + } + + return result; +} + +void Physics::reset() { + if(world != nullptr) + world.reset(); + + broadphase = std::make_unique(); + + collisionConfiguration = std::make_unique(); + dispatcher = std::make_unique(collisionConfiguration.get()); + + solver = std::make_unique(); + + world = std::make_unique(dispatcher.get(), broadphase.get(), solver.get(), collisionConfiguration.get()); + world->setGravity(btVector3(0.0f, -9.8f, 0.0f)); +} diff --git a/engine/core/src/scene.cpp b/engine/core/src/scene.cpp new file mode 100755 index 0000000..4570150 --- /dev/null +++ b/engine/core/src/scene.cpp @@ -0,0 +1,202 @@ +#include "scene.hpp" + +#include "json_conversions.hpp" +#include "file.hpp" +#include "engine.hpp" + +void load_transform_component(nlohmann::json j, Transform& t) { + t.position = j["position"]; + t.scale = j["scale"]; + t.rotation = j["rotation"]; +} + +void load_renderable_component(nlohmann::json j, Renderable& t) { + if(j.contains("path")) + t.mesh = assetm->get(file::app_domain / j["path"].get()); + + for(auto& material : j["materials"]) + t.materials.push_back(assetm->get(file::app_domain / material.get())); +} + +void load_camera_component(nlohmann::json j, Camera& camera) { + if(j.contains("fov")) + camera.fov = j["fov"]; +} + +void load_light_component(nlohmann::json j, Light& light) { + light.color = j["color"]; + light.power = j["power"]; + light.type = j["type"]; + + if(j.count("size") && !j.count("spot_size")) + light.size = j["size"]; + else if(j.count("spot_size")) { + light.size = j["size"]; + light.spot_size = j["spot_size"]; + } + + if(j.count("enable_shadows")) { + light.enable_shadows = j["enable_shadows"]; + light.use_dynamic_shadows = j["use_dynamic_shadows"]; + } +} + +void load_collision_component(nlohmann::json j, Collision& collision) { + collision.type = j["type"]; + collision.size = j["size"]; + + if(j.contains("is_trigger")) { + collision.is_trigger = j["is_trigger"]; + + if(collision.is_trigger) + collision.trigger_id = j["trigger_id"]; + } +} + +void load_rigidbody_component(nlohmann::json j, Rigidbody& rigidbody) { + rigidbody.type = j["type"]; + rigidbody.mass = j["mass"]; +} + +void load_ui_component(nlohmann::json j, UI& ui) { + ui.width = j["width"]; + ui.height = j["height"]; + ui.ui_path = j["path"]; +} + +void load_probe_component(nlohmann::json j, EnvironmentProbe& probe) { + if(j.contains("size")) + probe.size = j["size"]; + + if(j.contains("is_sized")) + probe.is_sized = j["is_sized"]; + + if(j.contains("intensity")) + probe.intensity = j["intensity"]; +} + +Object load_object(Scene& scene, const nlohmann::json obj) { + Object o = scene.add_object(); + + auto& data = scene.get(o); + data.name = obj["name"]; + + load_transform_component(obj["transform"], scene.get(o)); + + if(obj.contains("renderable")) + load_renderable_component(obj["renderable"], scene.add(o)); + + if(obj.contains("light")) + load_light_component(obj["light"], scene.add(o)); + + if(obj.contains("camera")) + load_camera_component(obj["camera"], scene.add(o)); + + if(obj.contains("collision")) + load_collision_component(obj["collision"], scene.add(o)); + + if(obj.contains("rigidbody")) + load_rigidbody_component(obj["rigidbody"], scene.add(o)); + + if(obj.contains("ui")) + load_ui_component(obj["ui"], scene.add(o)); + + if(obj.contains("environment_probe")) + load_probe_component(obj["environment_probe"], scene.add(o)); + + return o; +} + +void save_transform_component(nlohmann::json& j, const Transform& t) { + j["position"] = t.position; + j["scale"] = t.scale; + j["rotation"] = t.rotation; +} + +void save_renderable_component(nlohmann::json& j, const Renderable &mesh) { + if(mesh.mesh) + j["path"] = mesh.mesh->path; + + for(auto& material : mesh.materials) { + if(material) + j["materials"].push_back(material->path); + } +} + +void save_camera_component(nlohmann::json& j, const Camera& camera) { + j["fov"] = camera.fov; +} + +void save_light_component(nlohmann::json& j, const Light& light) { + j["color"] = light.color; + j["power"] = light.power; + j["type"] = light.type; + j["size"] = light.size; + j["spot_size"] = light.spot_size; + j["enable_shadows"] = light.enable_shadows; + j["use_dynamic_shadows"] = light.use_dynamic_shadows; +} + +void save_collision_component(nlohmann::json& j, const Collision& collision) { + j["type"] = collision.type; + j["size"] = collision.size; + + j["is_trigger"] = collision.is_trigger; + if(collision.is_trigger) + j["trigger_id"] = collision.trigger_id; +} + +void save_rigidbody_component(nlohmann::json& j, const Rigidbody& rigidbody) { + j["type"] = rigidbody.type; + j["mass"] = rigidbody.mass; +} + +void save_ui_component(nlohmann::json& j, const UI& ui) { + j["width"] = ui.width; + j["height"] = ui.height; + j["path"] = ui.ui_path; +} + +void save_probe_component(nlohmann::json& j, const EnvironmentProbe& probe) { + j["size"] = probe.size; + j["is_sized"] = probe.is_sized; + j["intensity"] = probe.intensity; +} + +nlohmann::json save_object(Object obj) { + nlohmann::json j; + + auto& data = engine->get_scene()->get(obj); + + j["name"] = data.name; + + if(data.parent != NullObject) + j["parent"] = engine->get_scene()->get(data.parent).name; + + save_transform_component(j["transform"], engine->get_scene()->get(obj)); + + auto scene = engine->get_scene(); + + if(scene->has(obj)) + save_renderable_component(j["renderable"], scene->get(obj)); + + if(scene->has(obj)) + save_light_component(j["light"], scene->get(obj)); + + if(scene->has(obj)) + save_camera_component(j["camera"], scene->get(obj)); + + if(scene->has(obj)) + save_collision_component(j["collision"], scene->get(obj)); + + if(scene->has(obj)) + save_rigidbody_component(j["rigidbody"], scene->get(obj)); + + if(scene->has(obj)) + save_ui_component(j["ui"], scene->get(obj)); + + if(scene->has(obj)) + save_probe_component(j["environment_probe"], scene->get(obj)); + + return j; +} diff --git a/engine/core/src/screen.cpp b/engine/core/src/screen.cpp new file mode 100755 index 0000000..b46afed --- /dev/null +++ b/engine/core/src/screen.cpp @@ -0,0 +1,220 @@ +#include "screen.hpp" + +#include +#include +#include + +#include "file.hpp" +#include "font.hpp" +#include "engine.hpp" +#include "string_utils.hpp" +#include "log.hpp" +#include "assertions.hpp" + +void ui::Screen::calculate_sizes() { + unsigned int numChildren = 0; + + int actualWidth = extent.width, actualHeight = extent.height; + int offsetX = 0, offsetY = 0; + + for(size_t i = 0; i < elements.size(); i++) { + auto& element = elements[i]; + + auto id = "ui_" + element.id; + //if(engine->has_localization(id)) + // element.text = engine->localize(id); + + UIElement* parent = nullptr; + if(!element.parent.empty()) + parent = find_element(element.parent); + + const auto& fillAbsolute = [parent](const auto& metric, auto& absolute, auto base, auto offset) { + switch(metric.type) { + case MetricType::Absolute: + absolute = offset + metric.value; + break; + case MetricType::Relative: + absolute = offset + ((base - offset) * (metric.value / 100.0f)); + break; + case MetricType::Offset: + { + if(parent == nullptr) + absolute = base - metric.value; + else + absolute = parent->absolute_height - metric.value; + } + break; + } + }; + + fillAbsolute(element.metrics.x, element.absolute_x, offsetX + actualWidth, offsetX); + fillAbsolute(element.metrics.y, element.absolute_y, offsetY + actualHeight, offsetY); + + fillAbsolute(element.metrics.width, element.absolute_width, actualWidth, 0); + fillAbsolute(element.metrics.height, element.absolute_height, actualHeight, 0); + + if(parent) { + const float heightPerRow = actualWidth / (float)elements.size(); + + element.absolute_x = (float)numChildren * heightPerRow; + element.absolute_y = actualHeight - 50.0f; + element.absolute_width = (float)heightPerRow; + element.absolute_height = (float)50.0f; + + numChildren++; + } + + if(element.text_location == UIElement::TextLocation::Center) { + if(get_string_width(element.text) < element.absolute_width) + element.text_x = (element.absolute_width / 2.0f) - (get_string_width(element.text) / 2.0f); + + if(get_font_height() < element.absolute_height) + element.text_y = (element.absolute_height / 2.0f) - (get_font_height() / 2.0f); + } + } +} + +void ui::Screen::process_mouse(const int x, const int y) { + Expects(x >= 0); + Expects(y >= 0); + +#if !defined(PLATFORM_IOS) && !defined(PLATFORM_TVOS) + for(auto& element : elements) { + if(x > element.absolute_x && + y > element.absolute_y && + x < (element.absolute_x + element.absolute_width) && + y < (element.absolute_y + element.absolute_height)) { + + if(!element.on_click_script.empty()) + engine->lua.safe_script(element.on_click_script, env); + } + } +#endif +} + +UIElement* ui::Screen::find_element(const std::string& id) { + Expects(!id.empty()); + + UIElement* foundElement = nullptr; + for(auto& element : elements) { + if(element.id == id) + foundElement = &element; + } + + Expects(foundElement != nullptr); + + return foundElement; +} + +ui::Screen::Screen(const file::Path path) { + auto file = file::open(path); + if(!file.has_value()) { + console::error(System::Core, "Failed to load UI from {}!", path); + return; + } + + nlohmann::json j; + file->read_as_stream() >> j; + + if(j.count("script")) + script_path = j["script"]; + + for(auto& element : j["elements"]) { + UIElement ue; + ue.id = element["id"]; + + if(element.contains("on_click")) + ue.on_click_script = element["on_click"]; + + if(element.contains("text")) + ue.text = element["text"]; + + if(element.contains("parent")) + ue.parent = element["parent"]; + + if(element.contains("metrics")) { + const auto& metrics = element["metrics"]; + + const auto parseMetric = [](const std::string& str) { + UIElement::Metrics::Metric m; + + if(string_contains(str, "px")) { + auto v = remove_substring(str, "px"); + + if(string_contains(str, "@")) { + m.type = MetricType::Offset; + m.value = std::stoi(remove_substring(v, "@")); + } else { + m.type = MetricType::Absolute; + m.value = std::stoi(v); + } + } else if(string_contains(str, "%")) { + m.type = MetricType::Relative; + m.value = std::stoi(remove_substring(str, "%")); + } + + return m; + }; + + if(metrics.contains("x")) + ue.metrics.x = parseMetric(metrics["x"]); + + if(metrics.contains("y")) + ue.metrics.y = parseMetric(metrics["y"]); + + if(metrics.contains("width")) + ue.metrics.width = parseMetric(metrics["width"]); + + if(metrics.contains("height")) + ue.metrics.height = parseMetric(metrics["height"]); + } + + if(element.contains("background")) { + if(element["background"].contains("color")) { + auto tokens = tokenize(element["background"]["color"].get(), ","); + ue.background.color.r = std::stof(tokens[0]); + ue.background.color.g = std::stof(tokens[1]); + ue.background.color.b = std::stof(tokens[2]); + ue.background.color.a = std::stof(tokens[3]); + } + + if(element["background"].contains("image")) { + ue.background.image = element["background"]["image"]; + } + } + + if(element.contains("wrap")) + ue.wrap_text = element["wrap"]; + + if(element.contains("textLocation")) { + if(element["textLocation"] == "topLeft") + ue.text_location = UIElement::TextLocation::TopLeft; + else if(element["textLocation"] == "center") + ue.text_location = UIElement::TextLocation::Center; + } + + elements.push_back(ue); + } + +#if !defined(PLATFORM_IOS) && !defined(PLATFORM_TVOS) + env = sol::environment(engine->lua, sol::create, engine->lua.globals()); + env["screen"] = this; + + if(!script_path.empty()) { + auto script_file = file::open(file::app_domain / script_path); + if(script_file != std::nullopt) + engine->lua.safe_script(script_file->read_as_string(), env); + } +#endif +} + +void ui::Screen::add_listener(const std::string& id, std::function callback) { + listeners[id] = callback; +} + +void ui::Screen::process_event(const std::string& type, const std::string data) { +#if !defined(PLATFORM_IOS) && !defined(PLATFORM_TVOS) + auto func = env["process_event"]; + func(type, data); +#endif +} diff --git a/engine/gfx/CMakeLists.txt b/engine/gfx/CMakeLists.txt new file mode 100755 index 0000000..5845c7c --- /dev/null +++ b/engine/gfx/CMakeLists.txt @@ -0,0 +1,24 @@ +set(CMAKE_FOLDER "GFX Backends") + +add_library(GFX INTERFACE) +target_include_directories(GFX INTERFACE public) + +add_custom_target(GFXInterface SOURCES + public/gfx.hpp + public/gfx_buffer.hpp + public/gfx_pipeline.hpp + public/gfx_commandbuffer.hpp + public/gfx_texture.hpp + public/gfx_framebuffer.hpp + public/gfx_renderpass.hpp + public/gfx_object.hpp + public/gfx_sampler.hpp) +set_target_properties(GFXInterface PROPERTIES CMAKE_FOLDER "GFX") + +if(ENABLE_METAL) + add_subdirectory(metal) +endif() + +if(ENABLE_VULKAN) + add_subdirectory(vulkan) +endif() diff --git a/engine/gfx/dummy/CMakeLists.txt b/engine/gfx/dummy/CMakeLists.txt new file mode 100755 index 0000000..2420c49 --- /dev/null +++ b/engine/gfx/dummy/CMakeLists.txt @@ -0,0 +1,3 @@ +add_library(GFXDummy STATIC src/gfx_dummy.cpp) +target_include_directories(GFXDummy PUBLIC include) +target_link_libraries(GFXDummy PUBLIC GFX) \ No newline at end of file diff --git a/engine/gfx/dummy/include/gfx_dummy.hpp b/engine/gfx/dummy/include/gfx_dummy.hpp new file mode 100755 index 0000000..ec46911 --- /dev/null +++ b/engine/gfx/dummy/include/gfx_dummy.hpp @@ -0,0 +1,30 @@ +#pragma once + +#include "gfx.hpp" + +class GFXDummy : public GFX { +public: + bool initialize() override; + void initializeView(void* native_handle, uint32_t width, uint32_t height) override; + + // buffer operations + GFXBuffer* createBuffer(void* data, GFXSize size, GFXBufferUsage usage) override; + void copyBuffer(GFXBuffer* buffer, void* data, GFXSize offset, GFXSize size) override; + + // texture operations + GFXTexture* createTexture(uint32_t width, uint32_t height, GFXPixelFormat format, GFXStorageMode storageMode, GFXTextureUsage usage) override; + void copyTexture(GFXTexture* texture, void* data, GFXSize size) override; + + // framebuffer operations + GFXFramebuffer* createFramebuffer(GFXFramebufferCreateInfo& info) override; + + // render pass operations + GFXRenderPass* createRenderPass(GFXRenderPassCreateInfo& info) override; + + // pipeline operations + GFXPipeline* createPipeline(GFXPipelineCreateInfo& info) override; + + void render(GFXCommandBuffer* command_buffer) override; + + const char* getName() override; +}; diff --git a/engine/gfx/dummy/src/gfx_dummy.cpp b/engine/gfx/dummy/src/gfx_dummy.cpp new file mode 100755 index 0000000..05f3b8b --- /dev/null +++ b/engine/gfx/dummy/src/gfx_dummy.cpp @@ -0,0 +1,46 @@ +#include "gfx_dummy.hpp" + +bool GFXDummy::initialize() { + return true; +} + +void GFXDummy::initializeView(void* native_handle, uint32_t width, uint32_t height) { + +} + +GFXBuffer* GFXDummy::createBuffer(void* data, GFXSize size, GFXBufferUsage usage) { + return nullptr; +} + +void GFXDummy::copyBuffer(GFXBuffer* buffer, void* data, GFXSize offset, GFXSize size) { + +} + +GFXTexture* GFXDummy::createTexture(uint32_t width, uint32_t height, GFXPixelFormat format, GFXStorageMode storageMode, GFXTextureUsage usage) { + return nullptr; +} + +void GFXDummy::copyTexture(GFXTexture* texture, void* data, GFXSize size) { + +} + + +GFXFramebuffer* GFXDummy::createFramebuffer(GFXFramebufferCreateInfo& info) { + return nullptr; +} + +GFXRenderPass* GFXDummy::createRenderPass(GFXRenderPassCreateInfo& info) { + return nullptr; +} + +GFXPipeline* GFXDummy::createPipeline(GFXPipelineCreateInfo& info) { + return nullptr; +} + +void GFXDummy::render(GFXCommandBuffer* command_buffer) { + +} + +const char* GFXDummy::getName() { + return "None"; +} diff --git a/engine/gfx/metal/CMakeLists.txt b/engine/gfx/metal/CMakeLists.txt new file mode 100755 index 0000000..a915562 --- /dev/null +++ b/engine/gfx/metal/CMakeLists.txt @@ -0,0 +1,28 @@ +set(HEADERS + include/gfx_metal.hpp + src/gfx_metal_buffer.hpp + src/gfx_metal_pipeline.hpp + src/gfx_metal_texture.hpp + src/gfx_metal_framebuffer.hpp + src/gfx_metal_renderpass.hpp + src/gfx_metal_sampler.hpp) + +add_library(GFXMetal STATIC + src/gfx_metal.mm + ${HEADERS}) + +set_target_properties(GFXMetal PROPERTIES + FRAMEWORK TRUE + FRAMEWORK_VERSION OBJC + PUBLIC_HEADER "${HEADERS}" +) +target_link_libraries(GFXMetal PUBLIC + GFX + Core + Log + "-framework Metal") +target_include_directories(GFXMetal PUBLIC + include + PRIVATE + src) +set_engine_properties(GFXMetal) diff --git a/engine/gfx/metal/include/gfx_metal.hpp b/engine/gfx/metal/include/gfx_metal.hpp new file mode 100755 index 0000000..0d79221 --- /dev/null +++ b/engine/gfx/metal/include/gfx_metal.hpp @@ -0,0 +1,68 @@ +#pragma once + +#include +#include + +#include "gfx.hpp" + +class GFXMetal : public GFX { +public: + bool is_supported() override; + GFXContext required_context() override { return GFXContext::Metal; } + const char* get_name() override; + + bool supports_feature(const GFXFeature feature) override; + + bool initialize(const GFXCreateInfo& createInfo) override; + + void initialize_view(void* native_handle, const int identifier, const uint32_t width, const uint32_t height) override; + void remove_view(const int identifier) override; + + // buffer operations + GFXBuffer* create_buffer(void* data, const GFXSize size, const bool dynamicData, const GFXBufferUsage usage) override; + void copy_buffer(GFXBuffer* buffer, void* data, const GFXSize offset, const GFXSize size) override; + + void* get_buffer_contents(GFXBuffer* buffer) override; + + // texture operations + GFXTexture* create_texture(const GFXTextureCreateInfo& info) override; + void copy_texture(GFXTexture* texture, void* data, GFXSize size) override; + void copy_texture(GFXTexture* from, GFXTexture* to) override; + void copy_texture(GFXTexture* from, GFXBuffer* to) override; + + // sampler opeations + GFXSampler* create_sampler(const GFXSamplerCreateInfo& info) override; + + // framebuffer operations + GFXFramebuffer* create_framebuffer(const GFXFramebufferCreateInfo& info) override; + + // render pass operations + GFXRenderPass* create_render_pass(const GFXRenderPassCreateInfo& info) override; + + // pipeline operations + GFXPipeline* create_graphics_pipeline(const GFXGraphicsPipelineCreateInfo& info) override; + + GFXCommandBuffer* acquire_command_buffer() override; + + void submit(GFXCommandBuffer* command_buffer, const int window = -1) override; + +private: + struct NativeMTLView { + int identifier = -1; + CAMetalLayer* layer = nullptr; + }; + + std::vector nativeViews; + + NativeMTLView* getNativeView(int identifier) { + for(auto& view : nativeViews) { + if(view->identifier == identifier) + return view; + } + + return nullptr; + } + + id device = nil; + id command_queue = nil; +}; diff --git a/engine/gfx/metal/src/gfx_metal.mm b/engine/gfx/metal/src/gfx_metal.mm new file mode 100755 index 0000000..e61eb58 --- /dev/null +++ b/engine/gfx/metal/src/gfx_metal.mm @@ -0,0 +1,999 @@ +#include "gfx_metal.hpp" + +#include "gfx_metal_buffer.hpp" +#include "gfx_metal_pipeline.hpp" +#include "gfx_commandbuffer.hpp" +#include "gfx_metal_texture.hpp" +#include "gfx_metal_renderpass.hpp" +#include "gfx_metal_framebuffer.hpp" +#include "gfx_metal_sampler.hpp" +#include "file.hpp" +#include "log.hpp" +#include "utility.hpp" +#include "string_utils.hpp" + +static inline bool debug_enabled = false; + +static inline std::array command_buffers; +static inline std::array free_command_buffers; + +MTLPixelFormat toPixelFormat(GFXPixelFormat format) { + switch(format) { + case GFXPixelFormat::R_32F: + return MTLPixelFormatR32Float; + case GFXPixelFormat::RGBA_32F: + return MTLPixelFormatRGBA32Float; + case GFXPixelFormat::RGBA8_UNORM: + return MTLPixelFormatRGBA8Unorm; + case GFXPixelFormat::R8_UNORM: + return MTLPixelFormatR8Unorm; + case GFXPixelFormat::R8G8_UNORM: + return MTLPixelFormatRG8Unorm; + case GFXPixelFormat::R8G8_SFLOAT: + return MTLPixelFormatRG16Float; + case GFXPixelFormat::R8G8B8A8_UNORM: + return MTLPixelFormatRGBA8Unorm; + case GFXPixelFormat::R16G16B16A16_SFLOAT: + return MTLPixelFormatRGBA16Float; + case GFXPixelFormat::DEPTH_32F: + return MTLPixelFormatDepth32Float; + } +} + +MTLBlendFactor toBlendFactor(GFXBlendFactor factor) { + switch(factor) { + case GFXBlendFactor::One: + return MTLBlendFactorOne; + case GFXBlendFactor::Zero: + return MTLBlendFactorZero; + case GFXBlendFactor::SrcColor: + return MTLBlendFactorSourceColor; + case GFXBlendFactor::DstColor: + return MTLBlendFactorDestinationColor; + case GFXBlendFactor::SrcAlpha: + return MTLBlendFactorSourceAlpha; + case GFXBlendFactor::DstAlpha: + return MTLBlendFactorDestinationAlpha; + case GFXBlendFactor::OneMinusSrcAlpha: + return MTLBlendFactorOneMinusSourceAlpha; + case GFXBlendFactor::OneMinusSrcColor: + return MTLBlendFactorOneMinusSourceColor; + } +} + +MTLSamplerAddressMode toSamplingMode(SamplingMode mode) { + switch(mode) { + case SamplingMode::Repeat: + return MTLSamplerAddressModeRepeat; + case SamplingMode::ClampToEdge: + return MTLSamplerAddressModeClampToEdge; + case SamplingMode::ClampToBorder: + { +#if defined(PLATFORM_IOS) || defined(PLATFORM_TVOS) + return MTLSamplerAddressModeRepeat; +#else + return MTLSamplerAddressModeClampToBorderColor; +#endif + } + } +} + +#if !defined(PLATFORM_IOS) && !defined(PLATFORM_TVOS) +MTLSamplerBorderColor toBorderColor(GFXBorderColor color) { + switch(color) { + case GFXBorderColor::OpaqueWhite: + return MTLSamplerBorderColorOpaqueWhite; + case GFXBorderColor::OpaqueBlack: + return MTLSamplerBorderColorOpaqueBlack; + } +} +#endif + +MTLCompareFunction toCompare(GFXCompareFunction function) { + switch(function) { + case GFXCompareFunction::Never: + return MTLCompareFunctionNever; + case GFXCompareFunction::Less: + return MTLCompareFunctionLess; + case GFXCompareFunction::Equal: + return MTLCompareFunctionEqual; + case GFXCompareFunction::LessOrEqual: + return MTLCompareFunctionLessEqual; + case GFXCompareFunction::Greater: + return MTLCompareFunctionGreater; + case GFXCompareFunction::NotEqual: + return MTLCompareFunctionNotEqual; + case GFXCompareFunction::GreaterOrEqual: + return MTLCompareFunctionGreaterEqual; + case GFXCompareFunction::Always: + return MTLCompareFunctionAlways; + } +} + +MTLSamplerMinMagFilter toFilter(GFXFilter filter) { + switch(filter) { + case GFXFilter::Nearest: + return MTLSamplerMinMagFilterNearest; + case GFXFilter::Linear: + return MTLSamplerMinMagFilterLinear; + } +} + +bool GFXMetal::is_supported() { + return true; +} + +bool GFXMetal::initialize(const GFXCreateInfo& createInfo) { + debug_enabled = createInfo.api_validation_enabled; + + device = MTLCreateSystemDefaultDevice(); + if(device) { + command_queue = [device newCommandQueue]; + + for(int i = 0; i < 15; i++) { + command_buffers[i] = new GFXCommandBuffer(); + free_command_buffers[i] = true; + } + + return true; + } else { + return false; + } +} + +const char* GFXMetal::get_name() { + return "Metal"; +} + +bool GFXMetal::supports_feature(const GFXFeature feature) { + if(feature == GFXFeature::CubemapArray) { +#if defined(PLATFORM_TVOS) + return false; +#else + return true; +#endif + } + + return false; +} + +void GFXMetal::initialize_view(void* native_handle, const int identifier, const uint32_t, const uint32_t) { + NativeMTLView* native = new NativeMTLView(); + native->identifier = identifier; + + native->layer = (CAMetalLayer*)native_handle; + native->layer.device = device; + + native->layer.allowsNextDrawableTimeout = true; + + nativeViews.push_back(native); +} + +void GFXMetal::remove_view(const int identifier) { + utility::erase_if(nativeViews, [identifier](NativeMTLView* view) { + return view->identifier == identifier; + }); +} + +GFXBuffer* GFXMetal::create_buffer(void* data, const GFXSize size, const bool dynamicData, const GFXBufferUsage) { + GFXMetalBuffer* buffer = new GFXMetalBuffer(); + buffer->dynamicData = dynamicData; + + if(buffer->dynamicData) { + for(int i = 0; i < 3; i++) { + if(data == nullptr) { + buffer->handles[i] = [device newBufferWithLength:(NSUInteger)size options:MTLResourceStorageModeShared]; + } else { + buffer->handles[i] = [device newBufferWithBytes:data + length:(NSUInteger)size + options:MTLResourceStorageModeShared]; + } + } + } else { + if(data == nullptr) { + buffer->handles[0] = [device newBufferWithLength:(NSUInteger)size options:MTLResourceStorageModeShared]; + } else { + buffer->handles[0] = [device newBufferWithBytes:data + length:(NSUInteger)size + options:MTLResourceStorageModeShared]; + } + } + + return buffer; +} + +int currentFrameIndex = 0; + +void GFXMetal::copy_buffer(GFXBuffer* buffer, void* data, const GFXSize offset, const GFXSize size) { + GFXMetalBuffer* metalBuffer = (GFXMetalBuffer*)buffer; + + const unsigned char * src = reinterpret_cast(data); + unsigned char * dest = reinterpret_cast(metalBuffer->get(currentFrameIndex).contents); + memcpy(dest + offset, src, size); + + //[metalBuffer->handle didModifyRange:NSMakeRange(offset, size)]; +} + +void* GFXMetal::get_buffer_contents(GFXBuffer* buffer) { + GFXMetalBuffer* metalBuffer = (GFXMetalBuffer*)buffer; + + return reinterpret_cast(metalBuffer->get(currentFrameIndex).contents); +} + +GFXTexture* GFXMetal::create_texture(const GFXTextureCreateInfo& info) { + GFXMetalTexture* texture = new GFXMetalTexture(); + + MTLTextureDescriptor* textureDescriptor = [[MTLTextureDescriptor alloc] init]; + + MTLPixelFormat mtlFormat = toPixelFormat(info.format); + + switch(info.type) { + case GFXTextureType::Single2D: + textureDescriptor.textureType = MTLTextureType2D; + break; + case GFXTextureType::Array2D: + textureDescriptor.textureType = MTLTextureType2DArray; + break; + case GFXTextureType::Cubemap: + { + textureDescriptor.textureType = MTLTextureTypeCube; + texture->is_cubemap = true; + } + break; + case GFXTextureType::CubemapArray: + { + textureDescriptor.textureType = MTLTextureTypeCubeArray; + texture->is_cubemap = true; + } + break; + } + + if((info.usage & GFXTextureUsage::Attachment) == GFXTextureUsage::Attachment) { + textureDescriptor.storageMode = MTLStorageModePrivate; + textureDescriptor.usage |= MTLTextureUsageRenderTarget; + } else { +#if defined(PLATFORM_IOS) || defined(PLATFORM_TVOS) + textureDescriptor.storageMode = MTLStorageModeShared; +#else + textureDescriptor.storageMode = MTLStorageModeManaged; +#endif + } + + if((info.usage & GFXTextureUsage::Sampled) == GFXTextureUsage::Sampled) { + textureDescriptor.usage |= MTLTextureUsageShaderRead; + } + + textureDescriptor.pixelFormat = mtlFormat; + textureDescriptor.width = info.width; + textureDescriptor.height = info.height; + textureDescriptor.arrayLength = info.array_length; + + texture->array_length = info.array_length; + + textureDescriptor.mipmapLevelCount = info.mip_count; + + texture->format = mtlFormat; + + texture->handle = [device newTextureWithDescriptor:textureDescriptor]; + + texture->width = info.width; + texture->height = info.height; + + MTLSamplerDescriptor* samplerDescriptor = [MTLSamplerDescriptor new]; + samplerDescriptor.minFilter = MTLSamplerMinMagFilterLinear; + samplerDescriptor.magFilter = MTLSamplerMinMagFilterLinear; + samplerDescriptor.sAddressMode = toSamplingMode(info.samplingMode); + samplerDescriptor.tAddressMode = toSamplingMode(info.samplingMode); + samplerDescriptor.mipFilter = MTLSamplerMipFilterLinear; + samplerDescriptor.maxAnisotropy = 16; + +#if !defined(PLATFORM_IOS) && !defined(PLATFORM_TVOS) + samplerDescriptor.borderColor = toBorderColor(info.border_color); +#endif + + if(info.compare_enabled) + samplerDescriptor.compareFunction = toCompare(info.compare_function); + + texture->sampler = [device newSamplerStateWithDescriptor:samplerDescriptor]; + + return texture; +} + +void GFXMetal::copy_texture(GFXTexture* texture, void* data, const GFXSize) { + GFXMetalTexture* metalTexture = (GFXMetalTexture*)texture; + + MTLRegion region = { + { 0, 0, 0 }, + { + static_cast(texture->width), + static_cast(texture->height), + 1 + } + }; + + NSUInteger byteSize = 1; + if(metalTexture->format == MTLPixelFormatRGBA8Unorm) + byteSize = 4; + else if(metalTexture->format == MTLPixelFormatRG8Unorm) + byteSize = 2; + + [metalTexture->handle replaceRegion:region mipmapLevel:0 withBytes:data bytesPerRow:(NSUInteger)texture->width * byteSize]; +} + +void GFXMetal::copy_texture(GFXTexture* from, GFXTexture* to) { + GFXMetalTexture* metalFromTexture = (GFXMetalTexture*)from; + GFXMetalTexture* metalToTexture = (GFXMetalTexture*)to; + + id commandBuffer = [command_queue commandBuffer]; + id commandEncoder = [commandBuffer blitCommandEncoder]; + [commandEncoder copyFromTexture:metalFromTexture->handle toTexture:metalToTexture->handle]; + [commandEncoder endEncoding]; + [commandBuffer commit]; + [commandBuffer waitUntilCompleted]; +} + +void GFXMetal::copy_texture(GFXTexture* from, GFXBuffer* to) { + GFXMetalTexture* metalFromTexture = (GFXMetalTexture*)from; + GFXMetalBuffer* metalToBuffer = (GFXMetalBuffer*)to; + + MTLOrigin origin; + origin.x = 0; + origin.y = 0; + origin.z = 0; + + MTLSize size; + size.width = from->width; + size.height = from->height; + size.depth = 1; + + NSUInteger byteSize = 1; + if(metalFromTexture->format == MTLPixelFormatRGBA8Unorm) + byteSize = 4; + + id commandBuffer = [command_queue commandBuffer]; + id commandEncoder = [commandBuffer blitCommandEncoder]; + [commandEncoder copyFromTexture:metalFromTexture->handle + sourceSlice:0 + sourceLevel:0 + sourceOrigin:origin + sourceSize:size + toBuffer:metalToBuffer->get(currentFrameIndex) + destinationOffset:0 + destinationBytesPerRow:(NSUInteger)metalFromTexture->width * byteSize + destinationBytesPerImage:0]; + [commandEncoder endEncoding]; + [commandBuffer commit]; + [commandBuffer waitUntilCompleted]; +} + +GFXSampler* GFXMetal::create_sampler(const GFXSamplerCreateInfo& info) { + GFXMetalSampler* sampler = new GFXMetalSampler(); + + MTLSamplerDescriptor* samplerDescriptor = [MTLSamplerDescriptor new]; + samplerDescriptor.minFilter = toFilter(info.min_filter); + samplerDescriptor.magFilter = toFilter(info.mag_filter); + samplerDescriptor.sAddressMode = toSamplingMode(info.samplingMode); + samplerDescriptor.tAddressMode = toSamplingMode(info.samplingMode); + samplerDescriptor.mipFilter = MTLSamplerMipFilterLinear; + samplerDescriptor.maxAnisotropy = 16; + +#if !defined(PLATFORM_IOS) && !defined(PLATFORM_TVOS) + samplerDescriptor.borderColor = toBorderColor(info.border_color); +#endif + + if(info.compare_enabled) + samplerDescriptor.compareFunction = toCompare(info.compare_function); + + sampler->handle = [device newSamplerStateWithDescriptor:samplerDescriptor]; + + return sampler; +} + +GFXFramebuffer* GFXMetal::create_framebuffer(const GFXFramebufferCreateInfo& info) { + GFXMetalFramebuffer* framebuffer = new GFXMetalFramebuffer(); + + for(auto& attachment : info.attachments) + framebuffer->attachments.push_back((GFXMetalTexture*)attachment); + + return framebuffer; +} + +GFXRenderPass* GFXMetal::create_render_pass(const GFXRenderPassCreateInfo& info) { + GFXMetalRenderPass* renderPass = new GFXMetalRenderPass(); + + for(const auto& attachment : info.attachments) + renderPass->attachments.push_back(toPixelFormat(attachment)); + + return renderPass; +} + +MTLFunctionConstantValues* get_constant_values(GFXShaderConstants constants) { + MTLFunctionConstantValues* constantValues = [MTLFunctionConstantValues new]; + + for(auto& constant : constants) { + switch(constant.type) { + case GFXShaderConstant::Type::Integer: + [constantValues setConstantValue:&constant.value type:MTLDataTypeInt atIndex:constant.index]; + break; + } + } + + return constantValues; +} + +GFXPipeline* GFXMetal::create_graphics_pipeline(const GFXGraphicsPipelineCreateInfo& info) { + GFXMetalPipeline* pipeline = new GFXMetalPipeline(); + + NSError* error = nil; + + // vertex + id vertexLibrary; + { + std::string vertex_src; + if(info.shaders.vertex_path.empty()) { + vertex_src = info.shaders.vertex_src; + } else { + const auto vertex_path = utility::format("{}.msl", info.shaders.vertex_path); + + auto file = file::open(file::internal_domain / vertex_path); + if(file != std::nullopt) { + vertex_src = file->read_as_string(); + } else { + console::error(System::GFX, "Failed to load vertex shader from {}!", vertex_path); + } + } + + vertexLibrary = [device newLibraryWithSource:[NSString stringWithFormat:@"%s", vertex_src.c_str()] options:nil error:&error]; + if(!vertexLibrary) + NSLog(@"%@", error.debugDescription); + } + + // fragment + id fragmentLibrary; + { + std::string fragment_src; + if(info.shaders.fragment_path.empty()) { + fragment_src = info.shaders.fragment_src; + } else { + const auto fragment_path = utility::format("{}.msl", info.shaders.fragment_path); + + auto file = file::open(file::internal_domain / fragment_path); + if(file != std::nullopt) { + fragment_src = file->read_as_string(); + } else { + console::error(System::GFX, "Failed to load fragment shader from {}!", fragment_path); + } + } + + fragmentLibrary = [device newLibraryWithSource:[NSString stringWithFormat:@"%s", fragment_src.c_str()] options:nil error:&error]; + if(!fragmentLibrary) + NSLog(@"%@", error.debugDescription); + } + + auto vertex_constants = get_constant_values(info.shaders.vertex_constants); + + id vertexFunc = [vertexLibrary newFunctionWithName:@"main0" constantValues:vertex_constants error:nil]; + + auto fragment_constants = get_constant_values(info.shaders.fragment_constants); + + id fragmentFunc = [fragmentLibrary newFunctionWithName:@"main0" constantValues:fragment_constants error:nil]; + + if(debug_enabled) { + vertexFunc.label = [NSString stringWithFormat:@"%s", info.shaders.vertex_path.data()]; + fragmentFunc.label = [NSString stringWithFormat:@"%s", info.shaders.fragment_path.data()]; + } + + MTLVertexDescriptor* descriptor = [MTLVertexDescriptor new]; + + for(auto input : info.vertex_input.inputs) { + descriptor.layouts[input.location].stride = (NSUInteger)input.stride; + descriptor.layouts[input.location].stepFunction = MTLVertexStepFunctionPerVertex; + + GFXMetalPipeline::VertexStride vs; + vs.location = input.location; + vs.stride = input.stride; + + pipeline->vertexStrides.push_back(vs); + } + + for(auto attribute : info.vertex_input.attributes) { + NSUInteger format = MTLVertexFormatFloat3; + switch(attribute.format) { + case GFXVertexFormat::FLOAT2: + format = MTLVertexFormatFloat2; + break; + case GFXVertexFormat::FLOAT3: + format = MTLVertexFormatFloat3; + break; + case GFXVertexFormat::FLOAT4: + format = MTLVertexFormatFloat4; + break; + case GFXVertexFormat::INT: + format = MTLVertexFormatInt; + break; + case GFXVertexFormat::UNORM4: + format = MTLVertexFormatUChar4Normalized; + break; + case GFXVertexFormat::INT4: + format = MTLVertexFormatInt4; + break; + } + + descriptor.attributes[attribute.location].format = (MTLVertexFormat)format; + descriptor.attributes[attribute.location].bufferIndex = (NSUInteger)attribute.binding; + descriptor.attributes[attribute.location].offset = (NSUInteger)attribute.offset; + } + + MTLRenderPipelineDescriptor *pipelineDescriptor = [MTLRenderPipelineDescriptor new]; + pipelineDescriptor.vertexFunction = vertexFunc; + pipelineDescriptor.fragmentFunction = fragmentFunc; + + if(info.render_pass != nullptr) { + GFXMetalRenderPass* metalRenderPass = (GFXMetalRenderPass*)info.render_pass; + + unsigned int i = 0; + for(const auto& attachment : metalRenderPass->attachments) { + if(attachment != MTLPixelFormatDepth32Float) { + pipelineDescriptor.colorAttachments[i].pixelFormat = attachment; + pipelineDescriptor.colorAttachments[i].blendingEnabled = info.blending.enable_blending; + + pipelineDescriptor.colorAttachments[i].sourceRGBBlendFactor = toBlendFactor(info.blending.src_rgb); + pipelineDescriptor.colorAttachments[i].destinationRGBBlendFactor = toBlendFactor(info.blending.dst_rgb); + + pipelineDescriptor.colorAttachments[i].sourceAlphaBlendFactor = toBlendFactor(info.blending.src_alpha); + pipelineDescriptor.colorAttachments[i].destinationAlphaBlendFactor = toBlendFactor(info.blending.dst_alpha); + + i++; + } else { + pipelineDescriptor.depthAttachmentPixelFormat = MTLPixelFormatDepth32Float; + } + } + } else { + pipelineDescriptor.colorAttachments[0].pixelFormat = [nativeViews[0]->layer pixelFormat]; + pipelineDescriptor.colorAttachments[0].blendingEnabled = info.blending.enable_blending; + + pipelineDescriptor.colorAttachments[0].sourceRGBBlendFactor = toBlendFactor(info.blending.src_rgb); + pipelineDescriptor.colorAttachments[0].destinationRGBBlendFactor = toBlendFactor(info.blending.dst_rgb); + + pipelineDescriptor.colorAttachments[0].sourceAlphaBlendFactor = toBlendFactor(info.blending.src_alpha); + pipelineDescriptor.colorAttachments[0].destinationAlphaBlendFactor = toBlendFactor(info.blending.dst_alpha); + } + + pipelineDescriptor.vertexDescriptor = descriptor; + + if(debug_enabled) { + pipelineDescriptor.label = [NSString stringWithFormat:@"%s", info.label.data()]; + pipeline->label = info.label; + } + + pipeline->handle = [device newRenderPipelineStateWithDescriptor:pipelineDescriptor error:&error]; + if(!pipeline->handle) + NSLog(@"%@", error.debugDescription); + + switch(info.rasterization.primitive_type) { + case GFXPrimitiveType::Triangle: + pipeline->primitiveType = MTLPrimitiveTypeTriangle; + break; + case GFXPrimitiveType::TriangleStrip: + pipeline->primitiveType = MTLPrimitiveTypeTriangleStrip; + break; + } + + for(auto& binding : info.shader_input.bindings) { + if(binding.type == GFXBindingType::PushConstant) + pipeline->pushConstantIndex = binding.binding; + } + + MTLDepthStencilDescriptor* depthStencil = [MTLDepthStencilDescriptor new]; + + if(info.depth.depth_mode != GFXDepthMode::None) { + //depthStencil.depthCompareFunction = info.depth.depth_mode == GFXDepthMode::LessOrEqual ? MTLCompareFunctionGreaterEqual : MTLCompareFunctionGreater; + depthStencil.depthCompareFunction = info.depth.depth_mode == GFXDepthMode::LessOrEqual ? MTLCompareFunctionLessEqual : MTLCompareFunctionLess; + depthStencil.depthWriteEnabled = true; + } + + pipeline->depthStencil = [device newDepthStencilStateWithDescriptor:depthStencil]; + + switch(info.rasterization.culling_mode) { + case GFXCullingMode::Frontface: + pipeline->cullMode = MTLCullModeFront; + break; + case GFXCullingMode::Backface: + pipeline->cullMode = MTLCullModeBack; + break; + case GFXCullingMode::None: + pipeline->cullMode = MTLCullModeNone; + break; + } + + if(info.rasterization.polygon_type == GFXPolygonType::Line) + pipeline->renderWire = true; + + [vertexFunc release]; + [fragmentFunc release]; + + [vertexLibrary release]; + [fragmentLibrary release]; + + [vertex_constants release]; + [fragment_constants release]; + + return pipeline; +} + +GFXCommandBuffer* GFXMetal::acquire_command_buffer() { + for(const auto [i, buffer_status] : utility::enumerate(free_command_buffers)) { + if(buffer_status) { + GFXCommandBuffer* buffer = command_buffers[i]; + + free_command_buffers[i] = false; + + buffer->commands.clear(); + + return buffer; + } + } + + return nullptr; +} + +void GFXMetal::submit(GFXCommandBuffer* command_buffer, const int window) { + @autoreleasepool { + NativeMTLView* native = getNativeView(window); + id drawable = nil; + if(native != nullptr) + drawable = [native->layer nextDrawable]; + + id commandBuffer = [command_queue commandBuffer]; + + id renderEncoder = nil; + id blitEncoder = nil; + + GFXMetalRenderPass* currentRenderPass = nullptr; + GFXMetalFramebuffer* currentFramebuffer = nullptr; + GFXMetalPipeline* currentPipeline = nullptr; + GFXMetalBuffer* currentIndexBuffer = nullptr; + IndexType currentIndextype = IndexType::UINT32; + MTLViewport currentViewport = MTLViewport(); + MTLClearColor currentClearColor; + + enum class CurrentEncoder { + None, + Render, + Blit + } current_encoder = CurrentEncoder::None; + + const auto needEncoder = [&](CurrentEncoder encoder, bool needs_reset = false) { + if(encoder != current_encoder || needs_reset) { + if(renderEncoder != nil) + [renderEncoder endEncoding]; + + if(blitEncoder != nil) + [blitEncoder endEncoding]; + + renderEncoder = nil; + blitEncoder = nil; + } + + if(current_encoder == encoder && !needs_reset) + return; + + switch(encoder) { + case CurrentEncoder::None: + break; + case CurrentEncoder::Render: + { + MTLRenderPassDescriptor* descriptor = [MTLRenderPassDescriptor new]; + + if(currentRenderPass != nullptr && currentFramebuffer != nullptr) { + unsigned int i = 0; + for(const auto& attachment : currentFramebuffer->attachments) { + if(attachment->format == MTLPixelFormatDepth32Float) { + descriptor.depthAttachment.texture = attachment->handle; + descriptor.depthAttachment.loadAction = MTLLoadActionClear; + descriptor.depthAttachment.storeAction = MTLStoreActionStore; + } else { + descriptor.colorAttachments[i].texture = attachment->handle; + descriptor.colorAttachments[i].loadAction = MTLLoadActionClear; + descriptor.colorAttachments[i].storeAction = MTLStoreActionStore; + descriptor.colorAttachments[i].clearColor = currentClearColor; + + i++; + } + } + + renderEncoder = [commandBuffer renderCommandEncoderWithDescriptor:descriptor]; + } else { + descriptor.colorAttachments[0].texture = drawable.texture; + descriptor.colorAttachments[0].loadAction = MTLLoadActionClear; + descriptor.colorAttachments[0].clearColor = MTLClearColorMake(0.0,0.0,0.0,1.0); + + renderEncoder = [commandBuffer renderCommandEncoderWithDescriptor:descriptor]; + } + + if(currentViewport.width != 0.0f && currentViewport.height != 0.0f) + [renderEncoder setViewport:currentViewport]; + + [descriptor release]; + } + break; + case CurrentEncoder::Blit: + { + blitEncoder = [commandBuffer blitCommandEncoder]; + } + break; + } + + current_encoder = encoder; + }; + + for(auto command : command_buffer->commands) { + switch(command.type) { + case GFXCommandType::Invalid: + break; + case GFXCommandType::SetRenderPass: + { + currentClearColor = MTLClearColorMake(command.data.set_render_pass.clear_color.r, + command.data.set_render_pass.clear_color.g, + command.data.set_render_pass.clear_color.b, + command.data.set_render_pass.clear_color.a ); + + currentFramebuffer = (GFXMetalFramebuffer*)command.data.set_render_pass.framebuffer; + currentRenderPass = (GFXMetalRenderPass*)command.data.set_render_pass.render_pass; + + currentViewport = MTLViewport(); + + needEncoder(CurrentEncoder::Render, true); + } + break; + case GFXCommandType::SetPipeline: + { + needEncoder(CurrentEncoder::Render); + + [renderEncoder setRenderPipelineState:((GFXMetalPipeline*)command.data.set_pipeline.pipeline)->handle]; + + currentPipeline = (GFXMetalPipeline*)command.data.set_pipeline.pipeline; + + [renderEncoder setDepthStencilState:currentPipeline->depthStencil]; + + [renderEncoder setCullMode:((GFXMetalPipeline*)command.data.set_pipeline.pipeline)->cullMode]; + + if(currentPipeline->renderWire) + [renderEncoder setTriangleFillMode:MTLTriangleFillModeLines]; + else + [renderEncoder setTriangleFillMode:MTLTriangleFillModeFill]; + } + break; + case GFXCommandType::SetVertexBuffer: + { + needEncoder(CurrentEncoder::Render); + + [renderEncoder setVertexBuffer:((GFXMetalBuffer*)command.data.set_vertex_buffer.buffer)->get(currentFrameIndex) offset:(NSUInteger)command.data.set_vertex_buffer.offset atIndex:(NSUInteger)command.data.set_vertex_buffer.index ]; + } + break; + case GFXCommandType::SetIndexBuffer: + { + currentIndexBuffer = (GFXMetalBuffer*)command.data.set_index_buffer.buffer; + currentIndextype = command.data.set_index_buffer.index_type; + } + break; + case GFXCommandType::SetPushConstant: + { + needEncoder(CurrentEncoder::Render); + + if(currentPipeline == nullptr) + continue; + + [renderEncoder setVertexBytes:command.data.set_push_constant.bytes.data() length:(NSUInteger)command.data.set_push_constant.size atIndex:(NSUInteger)currentPipeline->pushConstantIndex]; + [renderEncoder setFragmentBytes:command.data.set_push_constant.bytes.data() length:(NSUInteger)command.data.set_push_constant.size atIndex:(NSUInteger)currentPipeline->pushConstantIndex]; + } + break; + case GFXCommandType::BindShaderBuffer: + { + needEncoder(CurrentEncoder::Render); + + [renderEncoder setVertexBuffer:((GFXMetalBuffer*)command.data.bind_shader_buffer.buffer)->get(currentFrameIndex) offset:(NSUInteger)command.data.bind_shader_buffer.offset atIndex:(NSUInteger)command.data.bind_shader_buffer.index ]; + + [renderEncoder setFragmentBuffer:((GFXMetalBuffer*)command.data.bind_shader_buffer.buffer)->get(currentFrameIndex) offset:(NSUInteger)command.data.bind_shader_buffer.offset atIndex:(NSUInteger)command.data.bind_shader_buffer.index ]; + } + break; + case GFXCommandType::BindTexture: + { + needEncoder(CurrentEncoder::Render); + + if(command.data.bind_texture.texture != nullptr) { + [renderEncoder setVertexSamplerState:((GFXMetalTexture*)command.data.bind_texture.texture)->sampler atIndex:(NSUInteger)command.data.bind_texture.index]; + + [renderEncoder setVertexTexture:((GFXMetalTexture*)command.data.bind_texture.texture)->handle atIndex:(NSUInteger)command.data.bind_texture.index]; + + [renderEncoder setFragmentSamplerState:((GFXMetalTexture*)command.data.bind_texture.texture)->sampler atIndex:(NSUInteger)command.data.bind_texture.index]; + + [renderEncoder setFragmentTexture:((GFXMetalTexture*)command.data.bind_texture.texture)->handle atIndex:(NSUInteger)command.data.bind_texture.index]; + } else { + [renderEncoder setVertexTexture:nil atIndex:(NSUInteger)command.data.bind_texture.index]; + + [renderEncoder setFragmentTexture:nil atIndex:(NSUInteger)command.data.bind_texture.index]; + } + } + break; + case GFXCommandType::BindSampler: + { + needEncoder(CurrentEncoder::Render); + + if(command.data.bind_sampler.sampler != nullptr) { + [renderEncoder setFragmentSamplerState:((GFXMetalSampler*)command.data.bind_sampler.sampler)->handle atIndex:(NSUInteger)command.data.bind_sampler.index]; + } else { + [renderEncoder setFragmentSamplerState:nil atIndex:(NSUInteger)command.data.bind_sampler.index]; + } + } + break; + case GFXCommandType::Draw: + { + needEncoder(CurrentEncoder::Render); + + if(currentPipeline == nullptr) + continue; + + [renderEncoder drawPrimitives:currentPipeline->primitiveType vertexStart:(NSUInteger)command.data.draw.vertex_offset vertexCount:(NSUInteger)command.data.draw.vertex_count instanceCount:(NSUInteger)command.data.draw.instance_count + baseInstance:(NSUInteger)command.data.draw.base_instance]; + } + break; + case GFXCommandType::DrawIndexed: + { + needEncoder(CurrentEncoder::Render); + + if(currentIndexBuffer == nullptr) + continue; + + if(currentPipeline == nullptr) + continue; + + MTLIndexType indexType; + int indexSize; + switch(currentIndextype) { + case IndexType::UINT16: + { + indexType = MTLIndexTypeUInt16; + indexSize = sizeof(uint16_t); + } + break; + case IndexType::UINT32: + { + indexType = MTLIndexTypeUInt32; + indexSize = sizeof(uint32_t); + } + break; + } + + for(auto& stride : currentPipeline->vertexStrides) + [renderEncoder setVertexBufferOffset:(NSUInteger)command.data.draw_indexed.vertex_offset * stride.stride atIndex:stride.location]; + + [renderEncoder + drawIndexedPrimitives:currentPipeline->primitiveType + indexCount:(NSUInteger)command.data.draw_indexed.index_count + indexType:indexType + indexBuffer:currentIndexBuffer->get(currentFrameIndex) + indexBufferOffset:(NSUInteger)command.data.draw_indexed.first_index * indexSize]; + } + break; + case GFXCommandType::MemoryBarrier: + { + needEncoder(CurrentEncoder::Render); + + #ifdef PLATFORM_MACOS + [renderEncoder memoryBarrierWithScope:MTLBarrierScopeTextures afterStages:MTLRenderStageFragment beforeStages:MTLRenderStageFragment]; + #endif + } + break; + case GFXCommandType::CopyTexture: + { + needEncoder(CurrentEncoder::Blit); + + GFXMetalTexture* metalFromTexture = (GFXMetalTexture*)command.data.copy_texture.src; + GFXMetalTexture* metalToTexture = (GFXMetalTexture*)command.data.copy_texture.dst; + if(metalFromTexture != nullptr && metalToTexture != nullptr) { + const int slice_offset = command.data.copy_texture.to_slice + command.data.copy_texture.to_layer * 6; + + [blitEncoder + copyFromTexture:metalFromTexture->handle + sourceSlice:0 + sourceLevel:0 + sourceOrigin:MTLOriginMake(0, 0, 0) + sourceSize:MTLSizeMake(command.data.copy_texture.width, command.data.copy_texture.height, 1) + toTexture:metalToTexture->handle + destinationSlice: slice_offset + destinationLevel:command.data.copy_texture.to_level + destinationOrigin: MTLOriginMake(0, 0, 0)]; + } + } + break; + case GFXCommandType::SetViewport: + { + MTLViewport viewport; + viewport.originX = command.data.set_viewport.viewport.x; + viewport.originY = command.data.set_viewport.viewport.y; + viewport.width = command.data.set_viewport.viewport.width; + viewport.height = command.data.set_viewport.viewport.height; + viewport.znear = command.data.set_viewport.viewport.min_depth; + viewport.zfar = command.data.set_viewport.viewport.max_depth; + + if(renderEncoder != nil) + [renderEncoder setViewport:viewport]; + + currentViewport = viewport; + } + break; + case GFXCommandType::SetScissor: + { + needEncoder(CurrentEncoder::Render); + + MTLScissorRect rect; + rect.x = (NSUInteger)command.data.set_scissor.rect.offset.x; + rect.y = (NSUInteger)command.data.set_scissor.rect.offset.y; + rect.width = (NSUInteger)command.data.set_scissor.rect.extent.width; + rect.height = (NSUInteger)command.data.set_scissor.rect.extent.height; + + [renderEncoder setScissorRect:rect]; + } + break; + case GFXCommandType::GenerateMipmaps: { + needEncoder(CurrentEncoder::Blit); + + GFXMetalTexture* metalTexture = (GFXMetalTexture*)command.data.generate_mipmaps.texture; + + [blitEncoder generateMipmapsForTexture: metalTexture->handle]; + } + break; + case GFXCommandType::SetDepthBias: { + needEncoder(CurrentEncoder::Render); + + [renderEncoder setDepthBias:command.data.set_depth_bias.constant + slopeScale:command.data.set_depth_bias.slope_factor + clamp:command.data.set_depth_bias.clamp]; + } + break; + case GFXCommandType::PushGroup: { + [commandBuffer pushDebugGroup:[NSString stringWithUTF8String:command.data.push_group.name.data()]]; + } + break; + case GFXCommandType::PopGroup: { + [commandBuffer popDebugGroup]; + } + break; + case GFXCommandType::InsertLabel: { + switch(current_encoder) { + case CurrentEncoder::Render: + [renderEncoder insertDebugSignpost:[NSString stringWithUTF8String:command.data.insert_label.name.data()]]; + break; + case CurrentEncoder::Blit: + [blitEncoder insertDebugSignpost:[NSString stringWithUTF8String:command.data.insert_label.name.data()]]; + break; + default: + break; + } + } + break; + } + } + + if(renderEncoder != nil) + [renderEncoder endEncoding]; + + if(blitEncoder != nil) + [blitEncoder endEncoding]; + + for(auto [i, buffer] : utility::enumerate(command_buffers)) { + if(buffer == command_buffer) + free_command_buffers[i] = true; + } + + if(window != -1) { + [commandBuffer presentDrawable:drawable]; + [commandBuffer commit]; + + currentFrameIndex = (currentFrameIndex + 1) % 3; + } else { + [commandBuffer commit]; + } + } +} diff --git a/engine/gfx/metal/src/gfx_metal_buffer.hpp b/engine/gfx/metal/src/gfx_metal_buffer.hpp new file mode 100755 index 0000000..670b8a9 --- /dev/null +++ b/engine/gfx/metal/src/gfx_metal_buffer.hpp @@ -0,0 +1,19 @@ +#pragma once + +#include + +#include "gfx_buffer.hpp" + +class GFXMetalBuffer : public GFXBuffer { +public: + id handles[3] = {nil, nil, nil}; + bool dynamicData = false; + + id get(int frameIndex) { + if(dynamicData) { + return handles[frameIndex]; + } else { + return handles[0]; + } + } +}; diff --git a/engine/gfx/metal/src/gfx_metal_framebuffer.hpp b/engine/gfx/metal/src/gfx_metal_framebuffer.hpp new file mode 100755 index 0000000..9c0eeb0 --- /dev/null +++ b/engine/gfx/metal/src/gfx_metal_framebuffer.hpp @@ -0,0 +1,13 @@ +#pragma once + +#include +#include + +#include "gfx_framebuffer.hpp" + +class GFXMetalTexture; + +class GFXMetalFramebuffer : public GFXFramebuffer { +public: + std::vector attachments; +}; diff --git a/engine/gfx/metal/src/gfx_metal_pipeline.hpp b/engine/gfx/metal/src/gfx_metal_pipeline.hpp new file mode 100755 index 0000000..38a68f8 --- /dev/null +++ b/engine/gfx/metal/src/gfx_metal_pipeline.hpp @@ -0,0 +1,27 @@ +#pragma once + +#include + +#include "gfx_pipeline.hpp" + +class GFXMetalPipeline : public GFXPipeline { +public: + std::string label; + + id handle = nil; + id depthStencil = nil; + MTLPrimitiveType primitiveType; + + MTLCullMode cullMode; + + struct VertexStride { + int location, stride; + }; + + std::vector vertexStrides; + + int pushConstantSize = 0; + int pushConstantIndex = 0; + + bool renderWire = false; +}; diff --git a/engine/gfx/metal/src/gfx_metal_renderpass.hpp b/engine/gfx/metal/src/gfx_metal_renderpass.hpp new file mode 100755 index 0000000..d793af9 --- /dev/null +++ b/engine/gfx/metal/src/gfx_metal_renderpass.hpp @@ -0,0 +1,10 @@ +#pragma once + +#include + +#include "gfx_renderpass.hpp" + +class GFXMetalRenderPass : public GFXRenderPass { +public: + std::vector attachments; +}; diff --git a/engine/gfx/metal/src/gfx_metal_sampler.hpp b/engine/gfx/metal/src/gfx_metal_sampler.hpp new file mode 100755 index 0000000..aadef10 --- /dev/null +++ b/engine/gfx/metal/src/gfx_metal_sampler.hpp @@ -0,0 +1,10 @@ +#pragma once + +#include + +#include "gfx_sampler.hpp" + +class GFXMetalSampler : public GFXSampler { +public: + id handle = nil; +}; diff --git a/engine/gfx/metal/src/gfx_metal_texture.hpp b/engine/gfx/metal/src/gfx_metal_texture.hpp new file mode 100755 index 0000000..8eecab3 --- /dev/null +++ b/engine/gfx/metal/src/gfx_metal_texture.hpp @@ -0,0 +1,16 @@ +#pragma once + +#include + +#include "gfx_texture.hpp" + +class GFXMetalTexture : public GFXTexture { +public: + id handle = nil; + id sampler = nil; + + int array_length = 1; + bool is_cubemap = false; + + MTLPixelFormat format; +}; diff --git a/engine/gfx/public/gfx.hpp b/engine/gfx/public/gfx.hpp new file mode 100755 index 0000000..c3ffc11 --- /dev/null +++ b/engine/gfx/public/gfx.hpp @@ -0,0 +1,332 @@ +#pragma once + +#include +#include + +class GFXBuffer; +class GFXPipeline; +class GFXCommandBuffer; +class GFXTexture; +class GFXFramebuffer; +class GFXRenderPass; +class GFXObject; +class GFXSampler; + +enum class GFXPixelFormat : int { + R_32F = 0, + RGBA_32F = 1, + RGBA8_UNORM = 2, + R8_UNORM = 3, + R8G8_UNORM = 4, + R8G8_SFLOAT = 5, + R8G8B8A8_UNORM = 6, + R16G16B16A16_SFLOAT = 7, + DEPTH_32F = 8 +}; + +enum class GFXVertexFormat : int { + FLOAT2 = 0, + FLOAT3 = 1, + FLOAT4 = 2, + INT = 3, + UNORM4 = 4, + INT4 = 5 +}; + +enum class GFXTextureUsage : int { + Sampled = 1, + Attachment = 2 +}; + +inline GFXTextureUsage operator|(const GFXTextureUsage a, const GFXTextureUsage b) { + return static_cast(static_cast(a) | static_cast(b)); +} + +inline GFXTextureUsage operator&(const GFXTextureUsage a, const GFXTextureUsage b) { + return static_cast(static_cast(a) & static_cast(b)); +} + +enum class GFXBufferUsage : int { + Storage, + Vertex, + Index +}; + +enum class GFXBlendFactor : int { + One, + Zero, + SrcColor, + DstColor, + SrcAlpha, + DstAlpha, + OneMinusSrcAlpha, + OneMinusSrcColor +}; + +enum class SamplingMode : int { + Repeat, + ClampToEdge, + ClampToBorder +}; + +enum class GFXPrimitiveType { + Triangle, + TriangleStrip +}; + +enum class GFXPolygonType { + Fill, + Line +}; + +enum class GFXCullingMode { + Backface, + Frontface, + None +}; + +struct GFXVertexInput { + int location = 0; + int stride = 0; +}; + +struct GFXVertexAttribute { + int binding = 0, location = 0, offset = 0; + GFXVertexFormat format = GFXVertexFormat::FLOAT4; +}; + +enum class GFXDepthMode { + None, + Less, + LessOrEqual +}; + +struct GFXPushConstant { + int size = 0, offset = 0; +}; + +enum class GFXBindingType { + StorageBuffer, + PushConstant, + Texture +}; + +enum class GFXTextureType { + Single2D, + Array2D, + Cubemap, + CubemapArray +}; + +struct GFXShaderBinding { + int binding = 0; + + GFXBindingType type = GFXBindingType::StorageBuffer; +}; + +struct GFXShaderConstant { + int index = 0; + + enum class Type { + Integer + } type; + + union { + int value; + }; +}; + +using GFXShaderConstants = std::vector; + +struct GFXGraphicsPipelineCreateInfo { + std::string label; // only used for debug + + struct Shaders { + std::string_view vertex_path, fragment_path; + std::string vertex_src, fragment_src; + + GFXShaderConstants vertex_constants, fragment_constants; + } shaders; + + struct Rasterization { + GFXPrimitiveType primitive_type = GFXPrimitiveType::Triangle; + + GFXPolygonType polygon_type = GFXPolygonType::Fill; + + GFXCullingMode culling_mode = GFXCullingMode::None; + } rasterization; + + struct Blending { + GFXBlendFactor src_rgb = GFXBlendFactor::One, dst_rgb = GFXBlendFactor::One; + GFXBlendFactor src_alpha = GFXBlendFactor::One, dst_alpha = GFXBlendFactor::One; + + bool enable_blending = false; + } blending; + + struct VertexInput { + std::vector inputs; + + std::vector attributes; + } vertex_input; + + struct ShaderBindings { + std::vector push_constants; + + std::vector bindings; + } shader_input; + + struct Depth { + GFXDepthMode depth_mode = GFXDepthMode::None; + } depth; + + GFXRenderPass* render_pass = nullptr; +}; + +struct GFXComputePipelineCreateInfo { + std::string label; // only used for debug + + struct Shaders { + std::string_view compute_path; + } shaders; +}; + +struct GFXFramebufferCreateInfo { + GFXRenderPass* render_pass; + std::vector attachments; +}; + +struct GFXRenderPassCreateInfo { + std::vector attachments; +}; + +enum class GFXBorderColor { + OpaqueWhite, + OpaqueBlack +}; + +enum class GFXCompareFunction { + Never, + Less, + Equal, + LessOrEqual, + Greater, + NotEqual, + GreaterOrEqual, + Always +}; + +enum class GFXFilter { + Nearest, + Linear +}; + +struct GFXTextureCreateInfo { + GFXTextureType type = GFXTextureType::Single2D; + uint32_t width = 0; + uint32_t height = 0; + GFXPixelFormat format; + GFXTextureUsage usage; + int array_length = 1; + int mip_count = 1; + + // sampler + SamplingMode samplingMode = SamplingMode::Repeat; + GFXBorderColor border_color = GFXBorderColor::OpaqueWhite; + bool compare_enabled = false; + GFXCompareFunction compare_function = GFXCompareFunction::Never; +}; + +struct GFXSamplerCreateInfo { + GFXFilter min_filter = GFXFilter::Linear, mag_filter = GFXFilter::Linear; + SamplingMode samplingMode = SamplingMode::Repeat; + GFXBorderColor border_color = GFXBorderColor::OpaqueWhite; + bool compare_enabled = false; + GFXCompareFunction compare_function = GFXCompareFunction::Never; +}; + +using GFXSize = uint64_t; + +enum class GFXContext { + None, + Metal, + OpenGL, + DirectX, + Vulkan +}; + +struct GFXCreateInfo { + bool api_validation_enabled = false; +}; + +enum class GFXFeature { + CubemapArray +}; + +class GFX { +public: + // check for runtime support + virtual bool is_supported() { return false; } + virtual GFXContext required_context() { return GFXContext::None; } + virtual const char* get_name() { return nullptr; } + + virtual bool supports_feature([[maybe_unused]] const GFXFeature feature) { return true; } + + // try to initialize + virtual bool initialize([[maybe_unused]] const GFXCreateInfo& createInfo) { return false; } + + virtual void initialize_view([[maybe_unused]] void* native_handle, + [[maybe_unused]] const int identifier, + [[maybe_unused]] const uint32_t width, + [[maybe_unused]] const uint32_t height) {} + + virtual void recreate_view([[maybe_unused]] const int identifier, + [[maybe_unused]] const uint32_t width, + [[maybe_unused]] const uint32_t height) {} + + virtual void remove_view([[maybe_unused]] const int identifier) {} + + // buffer operations + virtual GFXBuffer* create_buffer([[maybe_unused]] void* data, + [[maybe_unused]] const GFXSize size, + [[maybe_unused]] const bool is_dynamic, + [[maybe_unused]] const GFXBufferUsage usage) { return nullptr; } + virtual void copy_buffer([[maybe_unused]] GFXBuffer* buffer, + [[maybe_unused]] void* data, + [[maybe_unused]] const GFXSize offset, + [[maybe_unused]] const GFXSize size) { } + + virtual void* get_buffer_contents([[maybe_unused]] GFXBuffer* buffer) { return nullptr; } + virtual void release_buffer_contents([[maybe_unused]] GFXBuffer* buffer, + [[maybe_unused]] void* handle) {} + + // texture operations + virtual GFXTexture* create_texture([[maybe_unused]] const GFXTextureCreateInfo& info) { return nullptr; } + virtual void copy_texture([[maybe_unused]] GFXTexture* texture, + [[maybe_unused]] void* data, + [[maybe_unused]] const GFXSize size) {} + virtual void copy_texture([[maybe_unused]] GFXTexture* from, + [[maybe_unused]] GFXTexture* to) {} + virtual void copy_texture([[maybe_unused]] GFXTexture* from, + [[maybe_unused]] GFXBuffer* to) {} + + // sampler opeations + virtual GFXSampler* create_sampler([[maybe_unused]] const GFXSamplerCreateInfo& info) { return nullptr; } + + // framebuffer operations + virtual GFXFramebuffer* create_framebuffer([[maybe_unused]] const GFXFramebufferCreateInfo& info) { return nullptr; } + + // render pass operations + virtual GFXRenderPass* create_render_pass([[maybe_unused]] const GFXRenderPassCreateInfo& info) { return nullptr; } + + // pipeline operations + virtual GFXPipeline* create_graphics_pipeline([[maybe_unused]] const GFXGraphicsPipelineCreateInfo& info) { return nullptr; } + virtual GFXPipeline* create_compute_pipeline([[maybe_unused]] const GFXComputePipelineCreateInfo& info) { return nullptr; } + + // misc operations + virtual GFXSize get_alignment(const GFXSize size) { return size; } + + virtual GFXCommandBuffer* acquire_command_buffer() { return nullptr; } + + virtual void submit([[maybe_unused]] GFXCommandBuffer* command_buffer, + [[maybe_unused]] const int window = -1) {} +}; diff --git a/engine/gfx/public/gfx_buffer.hpp b/engine/gfx/public/gfx_buffer.hpp new file mode 100755 index 0000000..6a7ac1e --- /dev/null +++ b/engine/gfx/public/gfx_buffer.hpp @@ -0,0 +1,8 @@ +#pragma once + +#include "gfx_object.hpp" + +class GFXBuffer : public GFXObject { +public: + +}; diff --git a/engine/gfx/public/gfx_commandbuffer.hpp b/engine/gfx/public/gfx_commandbuffer.hpp new file mode 100755 index 0000000..3f2a370 --- /dev/null +++ b/engine/gfx/public/gfx_commandbuffer.hpp @@ -0,0 +1,338 @@ +#pragma once + +#include +#include +#include +#include + +#include "common.hpp" + +class GFXPipeline; +class GFXBuffer; +class GFXFramebuffer; +class GFXRenderPass; +class GFXSampler; + +struct GFXRenderPassBeginInfo { + struct ClearColor { + float r = 0.0f, g = 0.0f, b = 0.0f, a = 0.0f; + } clear_color; + + Rectangle render_area; + + GFXRenderPass* render_pass = nullptr; + GFXFramebuffer* framebuffer = nullptr; +}; + +struct Viewport { + float x = 0.0f; + float y = 0.0f; + float width = 0.0f; + float height = 0.0f; + float min_depth = 0.0f; + float max_depth = 1.0f; +}; + +enum class IndexType : int { + UINT16 = 0, + UINT32 = 1 +}; + +enum class GFXCommandType { + Invalid, + SetRenderPass, + SetPipeline, + SetVertexBuffer, + SetIndexBuffer, + SetPushConstant, + BindShaderBuffer, + BindTexture, + BindSampler, + Draw, + DrawIndexed, + MemoryBarrier, + CopyTexture, + SetViewport, + SetScissor, + GenerateMipmaps, + SetDepthBias, + PushGroup, + PopGroup, + InsertLabel +}; + +struct GFXDrawCommand { + GFXCommandType type = GFXCommandType::Invalid; + + struct CommandData { + GFXRenderPassBeginInfo set_render_pass; + + struct SetPipelineData { + SetPipelineData() {} + + GFXPipeline* pipeline = nullptr; + } set_pipeline; + + struct SetVertexData { + GFXBuffer* buffer = nullptr; + int offset = 0; + int index = 0; + } set_vertex_buffer; + + struct SetIndexData { + GFXBuffer* buffer = nullptr; + IndexType index_type = IndexType::UINT32; + } set_index_buffer; + + struct SetPushData { + std::vector bytes; + size_t size = 0; + } set_push_constant; + + struct BindShaderData { + GFXBuffer* buffer = nullptr; + int offset = 0; + int index = 0; + int size = 0; + } bind_shader_buffer; + + struct BindTextureData { + GFXTexture* texture = nullptr; + int index = 0; + } bind_texture; + + struct BindSamplerData { + GFXSampler* sampler = nullptr; + int index = 0; + } bind_sampler; + + struct DrawData { + int vertex_offset = 0; + int vertex_count = 0; + int base_instance = 0; + int instance_count = 0; + } draw; + + struct DrawIndexedData { + int index_count = 0; + int first_index = 0; + int vertex_offset = 0; + } draw_indexed; + + struct CopyTextureData { + GFXTexture* src = nullptr, *dst = nullptr; + int width = 0, height = 0; + int to_slice = 0; + int to_layer = 0; + int to_level = 0; + } copy_texture; + + struct SetViewportData { + Viewport viewport; + } set_viewport; + + struct SetScissorData { + Rectangle rect; + } set_scissor; + + struct GenerateMipmapData { + GFXTexture* texture = nullptr; + int mip_count = 0; + } generate_mipmaps; + + struct SetDepthBiasData { + float constant = 0.0f; + float clamp = 0.0f; + float slope_factor = 0.0f; + } set_depth_bias; + + struct PushGroupData { + std::string_view name; + } push_group; + + struct InsertLabelData { + std::string_view name; + } insert_label; + } data; +}; + +class GFXCommandBuffer { +public: + void set_render_pass(GFXRenderPassBeginInfo& info) { + GFXDrawCommand command; + command.type = GFXCommandType::SetRenderPass; + command.data.set_render_pass = info; + + commands.push_back(command); + } + + void set_pipeline(GFXPipeline* pipeline) { + GFXDrawCommand command; + command.type = GFXCommandType::SetPipeline; + command.data.set_pipeline.pipeline = pipeline; + + commands.push_back(command); + } + + void set_vertex_buffer(GFXBuffer* buffer, int offset, int index) { + GFXDrawCommand command; + command.type = GFXCommandType::SetVertexBuffer; + command.data.set_vertex_buffer.buffer = buffer; + command.data.set_vertex_buffer.offset = offset; + command.data.set_vertex_buffer.index = index; + + commands.push_back(command); + } + + void set_index_buffer(GFXBuffer* buffer, IndexType indexType) { + GFXDrawCommand command; + command.type = GFXCommandType::SetIndexBuffer; + command.data.set_index_buffer.buffer = buffer; + command.data.set_index_buffer.index_type = indexType; + + commands.push_back(command); + } + + void set_push_constant(const void* data, const size_t size) { + GFXDrawCommand command; + command.type = GFXCommandType::SetPushConstant; + command.data.set_push_constant.size = size; + command.data.set_push_constant.bytes.resize(size); + + memcpy(command.data.set_push_constant.bytes.data(), data, size); + + commands.push_back(command); + } + + void bind_shader_buffer(GFXBuffer* buffer, int offset, int index, int size) { + GFXDrawCommand command; + command.type = GFXCommandType::BindShaderBuffer; + command.data.bind_shader_buffer.buffer = buffer; + command.data.bind_shader_buffer.offset = offset; + command.data.bind_shader_buffer.index = index; + command.data.bind_shader_buffer.size = size; + + + commands.push_back(command); + } + + void bind_texture(GFXTexture* texture, int index) { + GFXDrawCommand command; + command.type = GFXCommandType::BindTexture; + command.data.bind_texture.texture = texture; + command.data.bind_texture.index = index; + + commands.push_back(command); + } + + void bind_sampler(GFXSampler* sampler, const int index) { + GFXDrawCommand command; + command.type = GFXCommandType::BindSampler; + command.data.bind_sampler.sampler = sampler; + command.data.bind_sampler.index = index; + + commands.push_back(command); + } + + void draw(int offset, int count, int instance_base, int instance_count) { + GFXDrawCommand command; + command.type = GFXCommandType::Draw; + command.data.draw.vertex_offset = offset; + command.data.draw.vertex_count = count; + command.data.draw.base_instance = instance_base; + command.data.draw.instance_count = instance_count; + + commands.push_back(command); + } + + void draw_indexed(int indexCount, int firstIndex, int vertexOffset) { + GFXDrawCommand command; + command.type = GFXCommandType::DrawIndexed; + command.data.draw_indexed.vertex_offset = vertexOffset; + command.data.draw_indexed.first_index = firstIndex; + command.data.draw_indexed.index_count = indexCount; + + commands.push_back(command); + } + + void memory_barrier() { + GFXDrawCommand command; + command.type = GFXCommandType::MemoryBarrier; + + commands.push_back(command); + } + + void copy_texture(GFXTexture* src, int width, int height, GFXTexture* dst, int to_slice, int to_layer, int to_level) { + GFXDrawCommand command; + command.type = GFXCommandType::CopyTexture; + command.data.copy_texture.src = src; + command.data.copy_texture.width = width; + command.data.copy_texture.height = height; + command.data.copy_texture.dst = dst; + command.data.copy_texture.to_slice = to_slice; + command.data.copy_texture.to_layer = to_layer; + command.data.copy_texture.to_level = to_level; + + commands.push_back(command); + } + + void set_viewport(Viewport viewport) { + GFXDrawCommand command; + command.type = GFXCommandType::SetViewport; + command.data.set_viewport.viewport = viewport; + + commands.push_back(command); + } + + void set_scissor(const Rectangle rect) { + GFXDrawCommand command; + command.type = GFXCommandType::SetScissor; + command.data.set_scissor.rect = rect; + + commands.push_back(command); + } + + void generate_mipmaps(GFXTexture* texture, int mip_count) { + GFXDrawCommand command; + command.type = GFXCommandType::GenerateMipmaps; + command.data.generate_mipmaps.texture = texture; + command.data.generate_mipmaps.mip_count = mip_count; + + commands.push_back(command); + } + + void set_depth_bias(const float constant, const float clamp, const float slope) { + GFXDrawCommand command; + command.type = GFXCommandType::SetDepthBias; + command.data.set_depth_bias.constant = constant; + command.data.set_depth_bias.clamp = clamp; + command.data.set_depth_bias.slope_factor = slope; + + commands.push_back(command); + } + + void push_group(const std::string_view name) { + GFXDrawCommand command; + command.type = GFXCommandType::PushGroup; + command.data.push_group.name = name; + + commands.push_back(command); + } + + void pop_group() { + GFXDrawCommand command; + command.type = GFXCommandType::PopGroup; + + commands.push_back(command); + } + + void insert_label(const std::string_view name) { + GFXDrawCommand command; + command.type = GFXCommandType::InsertLabel; + command.data.insert_label.name = name; + + commands.push_back(command); + } + + std::vector commands; +}; diff --git a/engine/gfx/public/gfx_framebuffer.hpp b/engine/gfx/public/gfx_framebuffer.hpp new file mode 100755 index 0000000..184a570 --- /dev/null +++ b/engine/gfx/public/gfx_framebuffer.hpp @@ -0,0 +1,8 @@ +#pragma once + +#include "gfx_object.hpp" + +class GFXFramebuffer : public GFXObject { +public: + +}; diff --git a/engine/gfx/public/gfx_object.hpp b/engine/gfx/public/gfx_object.hpp new file mode 100755 index 0000000..927b1b1 --- /dev/null +++ b/engine/gfx/public/gfx_object.hpp @@ -0,0 +1,6 @@ +#pragma once + +class GFXObject { +public: + virtual ~GFXObject() {} +}; diff --git a/engine/gfx/public/gfx_pipeline.hpp b/engine/gfx/public/gfx_pipeline.hpp new file mode 100755 index 0000000..8ca1c8d --- /dev/null +++ b/engine/gfx/public/gfx_pipeline.hpp @@ -0,0 +1,7 @@ +#pragma once + +#include "gfx_object.hpp" + +class GFXPipeline : public GFXObject { +public: +}; diff --git a/engine/gfx/public/gfx_renderpass.hpp b/engine/gfx/public/gfx_renderpass.hpp new file mode 100755 index 0000000..068eda0 --- /dev/null +++ b/engine/gfx/public/gfx_renderpass.hpp @@ -0,0 +1,8 @@ +#pragma once + +#include "gfx_object.hpp" + +class GFXRenderPass : public GFXObject { +public: + +}; diff --git a/engine/gfx/public/gfx_sampler.hpp b/engine/gfx/public/gfx_sampler.hpp new file mode 100755 index 0000000..3cee31a --- /dev/null +++ b/engine/gfx/public/gfx_sampler.hpp @@ -0,0 +1,8 @@ +#pragma once + +#include "gfx_object.hpp" + +class GFXSampler : public GFXObject { +public: + +}; diff --git a/engine/gfx/public/gfx_texture.hpp b/engine/gfx/public/gfx_texture.hpp new file mode 100755 index 0000000..dd8965c --- /dev/null +++ b/engine/gfx/public/gfx_texture.hpp @@ -0,0 +1,8 @@ +#pragma once + +#include "gfx_object.hpp" + +class GFXTexture : public GFXObject { +public: + int width, height; +}; diff --git a/engine/gfx/vulkan/CMakeLists.txt b/engine/gfx/vulkan/CMakeLists.txt new file mode 100755 index 0000000..bc3c276 --- /dev/null +++ b/engine/gfx/vulkan/CMakeLists.txt @@ -0,0 +1,25 @@ +set(HEADERS + include/gfx_vulkan.hpp + src/gfx_vulkan_buffer.hpp + src/gfx_vulkan_pipeline.hpp + src/gfx_vulkan_texture.hpp + src/gfx_vulkan_framebuffer.hpp + src/gfx_vulkan_renderpass.hpp) + +find_package(Vulkan REQUIRED) + +add_library(GFXVulkan STATIC + src/gfx_vulkan.cpp + ${HEADERS}) + +target_link_libraries(GFXVulkan PUBLIC + GFX + Vulkan::Vulkan + Core + Log) +target_include_directories(GFXVulkan PUBLIC + include + PRIVATE + src) +set_target_properties(GFXVulkan PROPERTIES + CXX_STANDARD 17) diff --git a/engine/gfx/vulkan/include/gfx_vulkan.hpp b/engine/gfx/vulkan/include/gfx_vulkan.hpp new file mode 100755 index 0000000..1b8ac44 --- /dev/null +++ b/engine/gfx/vulkan/include/gfx_vulkan.hpp @@ -0,0 +1,114 @@ +#pragma once + +#ifdef PLATFORM_WINDOWS +#define NOMINMAX // donut define max in windows.h +#define VK_USE_PLATFORM_WIN32_KHR +#else +#define VK_USE_PLATFORM_XCB_KHR +#endif + +#include + +#include +#include + +#include "gfx.hpp" +#include "gfx_vulkan_constants.hpp" + +class GFXVulkanPipeline; + +class GFXVulkan : public GFX { +public: + bool is_supported() { return true; } + GFXContext required_context() { return GFXContext::Vulkan; }const char* get_name() override; + + bool initialize(const GFXCreateInfo& info) override; + + void initialize_view(void* native_handle, const int identifier, const uint32_t width, const uint32_t height) override; + void recreate_view(const int identifier, const uint32_t width, const uint32_t height) override; + + // buffer operations + GFXBuffer* create_buffer(void* data, const GFXSize size, const bool dynamic_data, const GFXBufferUsage usage) override; + void copy_buffer(GFXBuffer* buffer, void* data, const GFXSize offset, const GFXSize size) override; + + void* get_buffer_contents(GFXBuffer* buffer) override; + void release_buffer_contents(GFXBuffer* buffer, void* handle) override; + + // texture operations + GFXTexture* create_texture(const GFXTextureCreateInfo& info) override; + void copy_texture(GFXTexture* texture, void* data, const GFXSize size) override; + void copy_texture(GFXTexture* from, GFXTexture* to) override; + void copy_texture(GFXTexture* from, GFXBuffer* to) override; + + // framebuffer operations + GFXFramebuffer* create_framebuffer(const GFXFramebufferCreateInfo& info) override; + + // render pass operations + GFXRenderPass* create_render_pass(const GFXRenderPassCreateInfo& info) override; + + // pipeline operations + GFXPipeline* create_graphics_pipeline(const GFXGraphicsPipelineCreateInfo& info) override; + + // misc operations + GFXSize get_alignment(const GFXSize size) override; + + void render(GFXCommandBuffer* command_buffer, const int identifier) override; + +private: + void createInstance(std::vector layers, std::vector extensions); + void createLogicalDevice(std::vector extensions); + void createSwapchain(VkSwapchainKHR oldSwapchain = VK_NULL_HANDLE); + void createDescriptorPool(); + void createSyncPrimitives(); + + // dynamic descriptor sets + void resetDescriptorState(); + void cacheDescriptorState(GFXVulkanPipeline* pipeline, VkDescriptorSetLayout layout); + uint64_t getDescriptorHash(GFXVulkanPipeline* pipeline); + + uint32_t findMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags properties); + void transitionImageLayout(VkImage image, VkFormat format, VkImageAspectFlags aspect, VkImageLayout oldLayout, VkImageLayout newLayout); + VkShaderModule createShaderModule(const unsigned char* code, const int length); + VkCommandBuffer beginSingleTimeCommands(); + void endSingleTimeCommands(VkCommandBuffer commandBuffer); + + VkInstance instance = VK_NULL_HANDLE; + + VkPhysicalDevice physicalDevice = VK_NULL_HANDLE; + VkDevice device = VK_NULL_HANDLE; + + VkQueue graphicsQueue = VK_NULL_HANDLE; + VkQueue presentQueue = VK_NULL_HANDLE; + + VkCommandPool commandPool = VK_NULL_HANDLE; + + VkDescriptorPool descriptorPool = VK_NULL_HANDLE; + + uint32_t surfaceWidth = -1, surfaceHeight = -1; + + std::vector imageAvailableSemaphores; + std::vector renderFinishedSemaphores; + std::vector inFlightFences; + size_t currentFrame = 0; + + VkSurfaceKHR surface = VK_NULL_HANDLE; + VkSwapchainKHR swapchain = VK_NULL_HANDLE; + VkExtent2D swapchainExtent = {}; + + std::vector swapchainImages; + std::vector swapchainImageViews; + + VkRenderPass swapchainRenderPass = VK_NULL_HANDLE; + + std::vector swapchainFramebuffers; + + std::vector commandBuffers; + + struct BoundShaderBuffer { + GFXBuffer* buffer = nullptr; + VkDeviceSize size = 0, offset = 0; + }; + + std::array boundShaderBuffers; + std::array boundTextures; +}; diff --git a/engine/gfx/vulkan/include/gfx_vulkan_constants.hpp b/engine/gfx/vulkan/include/gfx_vulkan_constants.hpp new file mode 100644 index 0000000..4cf726b --- /dev/null +++ b/engine/gfx/vulkan/include/gfx_vulkan_constants.hpp @@ -0,0 +1,3 @@ +#pragma once + +const int MAX_FRAMES_IN_FLIGHT = 3; diff --git a/engine/gfx/vulkan/src/gfx_vulkan.cpp b/engine/gfx/vulkan/src/gfx_vulkan.cpp new file mode 100755 index 0000000..8e41fed --- /dev/null +++ b/engine/gfx/vulkan/src/gfx_vulkan.cpp @@ -0,0 +1,1522 @@ +#include "gfx_vulkan.hpp" + +#include +#include +#include +#include + +#include "gfx_vulkan_buffer.hpp" +#include "gfx_vulkan_pipeline.hpp" +#include "gfx_commandbuffer.hpp" +#include "gfx_vulkan_texture.hpp" +#include "gfx_vulkan_framebuffer.hpp" +#include "gfx_vulkan_renderpass.hpp" +#include "file.hpp" +#include "log.hpp" + +void* windowNativeHandle; + +VkFormat toVkFormat(GFXPixelFormat format) { + switch (format) { + case GFXPixelFormat::R_32F: + return VK_FORMAT_R32_SFLOAT; + + case GFXPixelFormat::RGBA_32F: + return VK_FORMAT_R32G32B32A32_SFLOAT; + + case GFXPixelFormat::RGBA8_UNORM: + return VK_FORMAT_R8G8B8A8_UNORM; + + case GFXPixelFormat::R8_UNORM: + return VK_FORMAT_R8_UNORM; + + case GFXPixelFormat::R8G8_UNORM: + return VK_FORMAT_R8G8_UNORM; + + case GFXPixelFormat::R8G8B8A8_UNORM: + return VK_FORMAT_R8G8B8A8_UNORM; + + case GFXPixelFormat::R16G16B16A16_SFLOAT: + return VK_FORMAT_R16G16B16A16_SFLOAT; + + case GFXPixelFormat::DEPTH_32F: + return VK_FORMAT_D32_SFLOAT; + } + + return VK_FORMAT_UNDEFINED; +} + +VkFormat toVkFormat(GFXVertexFormat format) { + switch (format) { + case GFXVertexFormat::FLOAT2: + return VK_FORMAT_R32G32_SFLOAT; + case GFXVertexFormat::FLOAT3: + return VK_FORMAT_R32G32B32_SFLOAT; + case GFXVertexFormat::FLOAT4: + return VK_FORMAT_R32G32B32A32_SFLOAT; + case GFXVertexFormat::INT: + return VK_FORMAT_R8_SINT; + case GFXVertexFormat::INT4: + return VK_FORMAT_R32G32B32A32_SINT; + case GFXVertexFormat::UNORM4: + return VK_FORMAT_R8G8B8A8_UNORM; + } + + return VK_FORMAT_UNDEFINED; +} + +VkBlendFactor toVkFactor(GFXBlendFactor factor) { + switch (factor) { + case GFXBlendFactor::One: + return VK_BLEND_FACTOR_ONE; + case GFXBlendFactor::OneMinusSrcAlpha: + return VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; + case GFXBlendFactor::OneMinusSrcColor: + return VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR; + case GFXBlendFactor::SrcAlpha: + return VK_BLEND_FACTOR_SRC_ALPHA; + } + + return VK_BLEND_FACTOR_ONE; +} + + +VKAPI_ATTR VkBool32 VKAPI_CALL DebugCallback( + VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, + VkDebugUtilsMessageTypeFlagsEXT messageType, + const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData, + void *pUserData) { + + console::debug(System::GFX, pCallbackData->pMessage); + + return VK_FALSE; +} + +VkResult name_object(VkDevice device, VkObjectType type, uint64_t object, std::string_view name) { + VkDebugUtilsObjectNameInfoEXT info = {}; + info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT; + info.objectType = type; + info.pObjectName = name.data(); + info.objectHandle = object; + + auto func = (PFN_vkSetDebugUtilsObjectNameEXT)vkGetDeviceProcAddr(device, "vkSetDebugUtilsObjectNameEXT"); + if (func != nullptr) + return func(device, &info); + else + return VK_ERROR_EXTENSION_NOT_PRESENT; +} + +bool GFXVulkan::initialize(const GFXCreateInfo& info) { +#ifdef PLATFORM_WINDOWS + const char* surface_name = "VK_KHR_win32_surface"; +#else + const char* surface_name = VK_KHR_XCB_SURFACE_EXTENSION_NAME; +#endif + + createInstance({ "VK_LAYER_KHRONOS_validation" }, { "VK_EXT_debug_utils", "VK_KHR_surface", surface_name }); + createLogicalDevice({ VK_KHR_SWAPCHAIN_EXTENSION_NAME }); + createDescriptorPool(); + createSyncPrimitives(); + + return true; +} + +void GFXVulkan::initialize_view(void* native_handle, const int identifier, const uint32_t width, const uint32_t height) { + vkDeviceWaitIdle(device); + + surfaceWidth = width; + surfaceHeight = height; + + windowNativeHandle = native_handle; + + createSwapchain(); +} + +void GFXVulkan::recreate_view(const int identifier, const uint32_t width, const uint32_t height) { + vkDeviceWaitIdle(device); + + surfaceWidth = width; + surfaceHeight = height; + + createSwapchain(swapchain); +} + +GFXBuffer* GFXVulkan::create_buffer(void *data, const GFXSize size, const bool dynamic_data, const GFXBufferUsage usage) { + GFXVulkanBuffer* buffer = new GFXVulkanBuffer(); + buffer->is_dynamic_data = dynamic_data; + + vkDeviceWaitIdle(device); + + // choose buffer features + VkBufferUsageFlags bufferUsage = 0; + if (usage == GFXBufferUsage::Storage) + bufferUsage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; + else if (usage == GFXBufferUsage::Vertex) + bufferUsage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; + else + bufferUsage = VK_BUFFER_USAGE_INDEX_BUFFER_BIT; + + // create buffer + VkBufferCreateInfo bufferInfo = {}; + bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + bufferInfo.size = size; + bufferInfo.usage = bufferUsage; + bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + + if(dynamic_data) { + for(int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) + vkCreateBuffer(device, &bufferInfo, nullptr, &buffer->data[i].handle); + } else { + vkCreateBuffer(device, &bufferInfo, nullptr, &buffer->data[0].handle); + } + + buffer->size = size; + + // allocate memory + VkMemoryRequirements memRequirements; + vkGetBufferMemoryRequirements(device, buffer->data[0].handle, &memRequirements); + + VkMemoryAllocateInfo allocInfo = {}; + allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + allocInfo.allocationSize = memRequirements.size; + allocInfo.memoryTypeIndex = findMemoryType(memRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); + + if(dynamic_data) { + for(int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { + vkAllocateMemory(device, &allocInfo, nullptr, &buffer->data[i].memory); + + vkBindBufferMemory(device, buffer->data[i].handle, buffer->data[i].memory, 0); + } + } else { + vkAllocateMemory(device, &allocInfo, nullptr, &buffer->data[0].memory); + + vkBindBufferMemory(device, buffer->data[0].handle, buffer->data[0].memory, 0); + } + + if (data != nullptr) { + if(dynamic_data) { + for(int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { + void* mapped_data; + vkMapMemory(device, buffer->data[i].memory, 0, size, 0, &mapped_data); + memcpy(mapped_data, data, size); + vkUnmapMemory(device, buffer->data[i].memory); + } + } else { + void* mapped_data; + vkMapMemory(device, buffer->data[0].memory, 0, size, 0, &mapped_data); + memcpy(mapped_data, data, size); + vkUnmapMemory(device, buffer->data[0].memory); + } + } + + return buffer; +} + +void GFXVulkan::copy_buffer(GFXBuffer* buffer, void* data, GFXSize offset, GFXSize size) { + GFXVulkanBuffer* vulkanBuffer = (GFXVulkanBuffer*)buffer; + + void* mapped_data; + vkMapMemory(device, vulkanBuffer->get(currentFrame).memory, offset, vulkanBuffer->size - offset, 0, &mapped_data); + memcpy(mapped_data, data, size); + vkUnmapMemory(device, vulkanBuffer->get(currentFrame).memory); +} + +void* GFXVulkan::get_buffer_contents(GFXBuffer* buffer) { + GFXVulkanBuffer* vulkanBuffer = (GFXVulkanBuffer*)buffer; + + void* mapped_data; + vkMapMemory(device, vulkanBuffer->get(currentFrame).memory, 0, vulkanBuffer->size, 0, &mapped_data); + + return mapped_data; +} + +void GFXVulkan::release_buffer_contents(GFXBuffer* buffer, void* handle) { + GFXVulkanBuffer* vulkanBuffer = (GFXVulkanBuffer*)buffer; + vkUnmapMemory(device, vulkanBuffer->get(currentFrame).memory); +} + +GFXTexture* GFXVulkan::create_texture(const GFXTextureCreateInfo& info) { + GFXVulkanTexture* texture = new GFXVulkanTexture(); + + vkDeviceWaitIdle(device); + + // choose image features + VkFormat imageFormat = toVkFormat(info.format); + + VkImageTiling imageTiling; + imageTiling = VK_IMAGE_TILING_OPTIMAL; + + VkImageUsageFlags imageUsage = 0; + if ((info.usage & GFXTextureUsage::Attachment) == GFXTextureUsage::Attachment) { + if (info.format == GFXPixelFormat::DEPTH_32F) { + imageUsage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; + } + else { + imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; + } + } + else { + imageUsage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; + } + + VkImageLayout imageLayout = VK_IMAGE_LAYOUT_UNDEFINED; + if ((info.usage & GFXTextureUsage::Attachment) == GFXTextureUsage::Attachment) { + if (info.format == GFXPixelFormat::DEPTH_32F) { + if((info.usage & GFXTextureUsage::Sampled) == GFXTextureUsage::Sampled) + imageLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL; + else + imageLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + } + else { + if((info.usage & GFXTextureUsage::Sampled) == GFXTextureUsage::Sampled) + imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + else + imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + } + } + else { + imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + } + + VkImageAspectFlags imageAspect; + if (info.format == GFXPixelFormat::DEPTH_32F) + imageAspect = VK_IMAGE_ASPECT_DEPTH_BIT; + else + imageAspect = VK_IMAGE_ASPECT_COLOR_BIT; + + // create image + VkImageCreateInfo imageInfo = {}; + imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; + imageInfo.imageType = VK_IMAGE_TYPE_2D; + imageInfo.extent.width = info.width; + imageInfo.extent.height = info.height; + imageInfo.extent.depth = 1; + imageInfo.mipLevels = 1; + imageInfo.arrayLayers = 1; + imageInfo.format = imageFormat; + imageInfo.tiling = imageTiling; + imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + imageInfo.usage = imageUsage; + imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + imageInfo.samples = VK_SAMPLE_COUNT_1_BIT; + + vkCreateImage(device, &imageInfo, nullptr, &texture->handle); + + texture->layout = imageLayout; + texture->width = info.width; + texture->height = info.height; + texture->format = imageFormat; + + // allocate memory + VkMemoryRequirements memRequirements; + vkGetImageMemoryRequirements(device, texture->handle, &memRequirements); + + VkMemoryAllocateInfo allocInfo = {}; + allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + allocInfo.allocationSize = memRequirements.size; + allocInfo.memoryTypeIndex = findMemoryType(memRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + + vkAllocateMemory(device, &allocInfo, nullptr, &texture->memory); + + vkBindImageMemory(device, texture->handle, texture->memory, 0); + + transitionImageLayout(texture->handle, imageFormat, imageAspect, VK_IMAGE_LAYOUT_UNDEFINED, imageLayout); + + // create image view + VkImageViewCreateInfo viewInfo = {}; + viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + viewInfo.image = texture->handle; + viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; + viewInfo.format = imageFormat; + viewInfo.subresourceRange.aspectMask = imageAspect; + viewInfo.subresourceRange.baseMipLevel = 0; + viewInfo.subresourceRange.levelCount = 1; + viewInfo.subresourceRange.baseArrayLayer = 0; + viewInfo.subresourceRange.layerCount = 1; + + vkCreateImageView(device, &viewInfo, nullptr, &texture->view); + + VkSamplerAddressMode samplerMode = VK_SAMPLER_ADDRESS_MODE_REPEAT; + if(info.samplingMode == SamplingMode::ClampToEdge) + samplerMode = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + + // create sampler + VkSamplerCreateInfo samplerInfo = {}; + samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; + samplerInfo.magFilter = VK_FILTER_LINEAR; + samplerInfo.minFilter = VK_FILTER_LINEAR; + samplerInfo.addressModeU = samplerMode; + samplerInfo.addressModeV = samplerMode; + samplerInfo.addressModeW = samplerMode; + samplerInfo.anisotropyEnable = VK_TRUE; + samplerInfo.maxAnisotropy = 16; + samplerInfo.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK; + samplerInfo.compareOp = VK_COMPARE_OP_ALWAYS; + samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; + + vkCreateSampler(device, &samplerInfo, nullptr, &texture->sampler); + + return texture; +} + +void GFXVulkan::copy_texture(GFXTexture* texture, void* data, GFXSize size) { + GFXVulkanTexture* vulkanTexture = (GFXVulkanTexture*)texture; + + vkDeviceWaitIdle(device); + + // create staging buffer + VkBuffer stagingBuffer; + VkDeviceMemory stagingBufferMemory; + + VkBufferCreateInfo bufferInfo = {}; + bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + bufferInfo.size = size; + bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; + bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + + vkCreateBuffer(device, &bufferInfo, nullptr, &stagingBuffer); + + // allocate staging memory + VkMemoryRequirements memRequirements; + vkGetBufferMemoryRequirements(device, stagingBuffer, &memRequirements); + + VkMemoryAllocateInfo allocInfo = {}; + allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + allocInfo.allocationSize = memRequirements.size; + allocInfo.memoryTypeIndex = findMemoryType(memRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); + + vkAllocateMemory(device, &allocInfo, nullptr, &stagingBufferMemory); + + vkBindBufferMemory(device, stagingBuffer, stagingBufferMemory, 0); + + // copy to staging buffer + void* mapped_data; + vkMapMemory(device, stagingBufferMemory, 0, size, 0, &mapped_data); + memcpy(mapped_data, data, size); + vkUnmapMemory(device, stagingBufferMemory); + + // copy staging buffer to image + transitionImageLayout(vulkanTexture->handle, vulkanTexture->format, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); + + VkCommandBuffer commandBuffer = beginSingleTimeCommands(); + + VkBufferImageCopy region = {}; + region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + region.imageSubresource.mipLevel = 0; + region.imageSubresource.baseArrayLayer = 0; + region.imageSubresource.layerCount = 1; + region.imageExtent = { + (uint32_t)vulkanTexture->width, + (uint32_t)vulkanTexture->height, + 1 + }; + + vkCmdCopyBufferToImage(commandBuffer, stagingBuffer, vulkanTexture->handle, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); + + endSingleTimeCommands(commandBuffer); + + transitionImageLayout(vulkanTexture->handle, vulkanTexture->format, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); +} + +void GFXVulkan::copy_texture(GFXTexture* from, GFXTexture* to) { + console::error(System::GFX, "Copy Texture->Texture unimplemented!"); +} + +void GFXVulkan::copy_texture(GFXTexture* from, GFXBuffer* to) { + console::error(System::GFX, "Copy Texture->Buffer unimplemented!"); +} + + +GFXFramebuffer* GFXVulkan::create_framebuffer(const GFXFramebufferCreateInfo& info) { + GFXVulkanFramebuffer* framebuffer = new GFXVulkanFramebuffer(); + + vkDeviceWaitIdle(device); + + GFXVulkanRenderPass* renderPass = (GFXVulkanRenderPass*)info.render_pass; + + std::vector attachments; + for (auto& attachment : info.attachments) { + GFXVulkanTexture* texture = (GFXVulkanTexture*)attachment; + attachments.push_back(texture->view); + } + + VkFramebufferCreateInfo framebufferInfo = {}; + framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; + framebufferInfo.renderPass = renderPass->handle; + framebufferInfo.attachmentCount = static_cast(attachments.size()); + framebufferInfo.pAttachments = attachments.data(); + framebufferInfo.width = ((GFXVulkanTexture*)info.attachments[0])->width; // FIXME: eww!! + framebufferInfo.height = ((GFXVulkanTexture*)info.attachments[0])->height; + framebufferInfo.layers = 1; + + vkCreateFramebuffer(device, &framebufferInfo, nullptr, &framebuffer->handle); + + framebuffer->width = ((GFXVulkanTexture*)info.attachments[0])->width; + framebuffer->height = ((GFXVulkanTexture*)info.attachments[0])->height; + + return framebuffer; +} + +GFXRenderPass* GFXVulkan::create_render_pass(const GFXRenderPassCreateInfo& info) { + GFXVulkanRenderPass* renderPass = new GFXVulkanRenderPass(); + + vkDeviceWaitIdle(device); + + std::vector descriptions; + std::vector references; + + bool hasDepthAttachment = false; + VkAttachmentDescription depthAttachment; + VkAttachmentReference depthAttachmentRef; + + for (int i = 0; i < info.attachments.size(); i++) { + bool isDepthAttachment = false; + if (info.attachments[i] == GFXPixelFormat::DEPTH_32F) + isDepthAttachment = true; + + VkImageLayout imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + if (isDepthAttachment) + imageLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + + VkAttachmentDescription attachment = {}; + attachment.format = toVkFormat(info.attachments[i]); + attachment.samples = VK_SAMPLE_COUNT_1_BIT; + attachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; + attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + attachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + attachment.finalLayout = imageLayout; + + if (imageLayout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) + attachment.finalLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + + if (imageLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL) + attachment.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL; + + VkAttachmentReference attachmentRef = {}; + attachmentRef.attachment = i; + attachmentRef.layout = imageLayout; + + if (isDepthAttachment) { + hasDepthAttachment = true; + depthAttachment = attachment; + depthAttachmentRef = attachmentRef; + renderPass->depth_attachment = i; + } + else { + descriptions.push_back(attachment); + references.push_back(attachmentRef); + } + } + + VkSubpassDescription subpass = {}; + subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; + subpass.colorAttachmentCount = static_cast(references.size()); + subpass.pColorAttachments = references.data(); + + if(hasDepthAttachment) { + subpass.pDepthStencilAttachment = &depthAttachmentRef; + + descriptions.push_back(depthAttachment); + } + + VkRenderPassCreateInfo renderPassInfo = {}; + renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; + renderPassInfo.attachmentCount = static_cast(descriptions.size()); + renderPassInfo.pAttachments = descriptions.data(); + renderPassInfo.subpassCount = 1; + renderPassInfo.pSubpasses = &subpass; + + vkCreateRenderPass(device, &renderPassInfo, nullptr, &renderPass->handle); + + renderPass->numAttachments = static_cast(descriptions.size()); + renderPass->hasDepthAttachment = hasDepthAttachment; + + return renderPass; +} + +GFXPipeline* GFXVulkan::create_graphics_pipeline(const GFXGraphicsPipelineCreateInfo& info) { + GFXVulkanPipeline* pipeline = new GFXVulkanPipeline(); + + vkDeviceWaitIdle(device); + + // setup shader modules + auto vertex_shader = file::read_file(FileDomain::ShaderData, std::string(info.shaders.vertex_path.data()) + ".spv"); + vertex_shader->read_all(); + + auto fragment_shader = file::read_file(FileDomain::ShaderData, std::string(info.shaders.fragment_path.data()) + ".spv"); + fragment_shader->read_all(); + + auto vertex_module = createShaderModule(vertex_shader->unsigned_data(), vertex_shader->size()); + name_object(device, VK_OBJECT_TYPE_SHADER_MODULE, (uint64_t)vertex_module, info.shaders.vertex_path); + + auto fragment_module = createShaderModule(fragment_shader->unsigned_data(), fragment_shader->size()); + name_object(device, VK_OBJECT_TYPE_SHADER_MODULE, (uint64_t)fragment_module, info.shaders.fragment_path); + + VkPipelineShaderStageCreateInfo vertShaderStageInfo = {}; + vertShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + vertShaderStageInfo.stage = VK_SHADER_STAGE_VERTEX_BIT; + vertShaderStageInfo.module = vertex_module; + vertShaderStageInfo.pName = "main"; + + VkPipelineShaderStageCreateInfo fragShaderStageInfo = {}; + fragShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + fragShaderStageInfo.stage = VK_SHADER_STAGE_FRAGMENT_BIT; + fragShaderStageInfo.module = fragment_module; + fragShaderStageInfo.pName = "main"; + + VkPipelineShaderStageCreateInfo shaderStages[] = { vertShaderStageInfo, fragShaderStageInfo }; + + // setup vertex inputs/bindings + std::vector inputs; + for (auto& binding : info.vertex_input.inputs) { + VkVertexInputBindingDescription b; + b.binding = binding.location; + b.stride = binding.stride; + b.inputRate = VK_VERTEX_INPUT_RATE_VERTEX; + + inputs.push_back(b); + } + + std::vector attributes; + for (auto& attribute : info.vertex_input.attributes) { + VkVertexInputAttributeDescription description; + description.binding = attribute.binding; + description.format = toVkFormat(attribute.format); + description.location = attribute.location; + description.offset = attribute.offset; + + attributes.push_back(description); + } + + // fixed functions + VkPipelineVertexInputStateCreateInfo vertexInputInfo = {}; + vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; + vertexInputInfo.pVertexBindingDescriptions = inputs.data(); + vertexInputInfo.vertexBindingDescriptionCount = static_cast(inputs.size()); + vertexInputInfo.pVertexAttributeDescriptions = attributes.data(); + vertexInputInfo.vertexAttributeDescriptionCount = static_cast(attributes.size()); + + VkPipelineInputAssemblyStateCreateInfo inputAssembly = {}; + inputAssembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; + inputAssembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; + + if (info.rasterization.primitive_type == GFXPrimitiveType::TriangleStrip) + inputAssembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP; + + + VkPipelineViewportStateCreateInfo viewportState = {}; + viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; + viewportState.viewportCount = 1; + viewportState.scissorCount = 1; + + VkPipelineRasterizationStateCreateInfo rasterizer = {}; + rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; + rasterizer.polygonMode = VK_POLYGON_MODE_FILL; + rasterizer.lineWidth = 1.0f; + rasterizer.cullMode = VK_CULL_MODE_NONE; + rasterizer.frontFace = VK_FRONT_FACE_CLOCKWISE; + + if (info.rasterization.polygon_type == GFXPolygonType::Line) + rasterizer.polygonMode = VK_POLYGON_MODE_LINE; + + if (info.rasterization.culling_mode == GFXCullingMode::Backface) { + rasterizer.cullMode = VK_CULL_MODE_BACK_BIT; + } + + VkPipelineMultisampleStateCreateInfo multisampling = {}; + multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; + multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; + + VkPipelineColorBlendAttachmentState colorBlendAttachment = {}; + colorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; + + if (info.blending.enable_blending) { + colorBlendAttachment.blendEnable = VK_TRUE; + colorBlendAttachment.srcColorBlendFactor = toVkFactor(info.blending.src_rgb); + colorBlendAttachment.dstColorBlendFactor = toVkFactor(info.blending.dst_rgb); + colorBlendAttachment.srcAlphaBlendFactor = toVkFactor(info.blending.src_alpha); + colorBlendAttachment.dstAlphaBlendFactor = toVkFactor(info.blending.dst_alpha); + } + + VkPipelineColorBlendStateCreateInfo colorBlending = {}; + colorBlending.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; + colorBlending.attachmentCount = 1; + colorBlending.pAttachments = &colorBlendAttachment; + + VkPipelineDepthStencilStateCreateInfo depthStencil = {}; + depthStencil.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; + + if (info.depth.depth_mode != GFXDepthMode::None) { + depthStencil.depthTestEnable = VK_TRUE; + depthStencil.depthWriteEnable = VK_TRUE; + depthStencil.depthCompareOp = info.depth.depth_mode == GFXDepthMode::Less ? VK_COMPARE_OP_LESS : VK_COMPARE_OP_LESS_OR_EQUAL; + } + + std::vector dynamicStates = {VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR}; + + VkPipelineDynamicStateCreateInfo dynamicState = {}; + dynamicState.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; + dynamicState.dynamicStateCount = static_cast(dynamicStates.size()); + dynamicState.pDynamicStates = dynamicStates.data(); + + // create push constants + std::vector pushConstants; + for (auto& pushConstant : info.shader_input.push_constants) { + VkPushConstantRange range; + range.offset = pushConstant.offset; + range.size = pushConstant.size; + range.stageFlags = VK_SHADER_STAGE_ALL; + + pushConstants.push_back(range); + } + + // create descriptor layout + std::vector layoutBindings; + for (auto& binding : info.shader_input.bindings) { + // ignore push constants + if (binding.type == GFXBindingType::PushConstant) + continue; + + VkDescriptorType descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; + switch (binding.type) { + case GFXBindingType::StorageBuffer: + descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; + break; + case GFXBindingType::Texture: + descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + break; + } + + VkDescriptorSetLayoutBinding layoutBinding = {}; + layoutBinding.binding = binding.binding; + layoutBinding.descriptorType = descriptorType; + layoutBinding.descriptorCount = 1; + layoutBinding.stageFlags = VK_SHADER_STAGE_ALL; + + layoutBindings.push_back(layoutBinding); + } + + VkDescriptorSetLayoutCreateInfo layoutCreateInfo = {}; + layoutCreateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; + layoutCreateInfo.bindingCount = static_cast(layoutBindings.size()); + layoutCreateInfo.pBindings = layoutBindings.data(); + + vkCreateDescriptorSetLayout(device, &layoutCreateInfo, nullptr, &pipeline->descriptorLayout); + + // create layout + VkPipelineLayoutCreateInfo pipelineLayoutInfo = {}; + pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; + pipelineLayoutInfo.pushConstantRangeCount = static_cast(pushConstants.size()); + pipelineLayoutInfo.pPushConstantRanges = pushConstants.data(); + pipelineLayoutInfo.pSetLayouts = &pipeline->descriptorLayout; + pipelineLayoutInfo.setLayoutCount = 1; + + vkCreatePipelineLayout(device, &pipelineLayoutInfo, nullptr, &pipeline->layout); + + // create pipeline + VkGraphicsPipelineCreateInfo pipelineInfo = {}; + pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; + pipelineInfo.stageCount = 2; + pipelineInfo.pStages = shaderStages; + pipelineInfo.pVertexInputState = &vertexInputInfo; + pipelineInfo.pInputAssemblyState = &inputAssembly; + pipelineInfo.pViewportState = &viewportState; + pipelineInfo.pRasterizationState = &rasterizer; + pipelineInfo.pMultisampleState = &multisampling; + pipelineInfo.pColorBlendState = &colorBlending; + pipelineInfo.pDynamicState = &dynamicState; + pipelineInfo.layout = pipeline->layout; + + if (info.render_pass != nullptr) { + pipelineInfo.renderPass = ((GFXVulkanRenderPass*)info.render_pass)->handle; + } + else { + pipelineInfo.renderPass = swapchainRenderPass; + } + + if (info.render_pass != nullptr && ((GFXVulkanRenderPass*)info.render_pass)->hasDepthAttachment) + pipelineInfo.pDepthStencilState = &depthStencil; + + vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &pipeline->handle); + + name_object(device, VK_OBJECT_TYPE_PIPELINE, (uint64_t)pipeline->handle, std::string(info.shaders.vertex_path.data()) + std::string(info.shaders.fragment_path.data())); + + return pipeline; +} + +GFXSize GFXVulkan::get_alignment(GFXSize size) { + VkPhysicalDeviceProperties properties; + vkGetPhysicalDeviceProperties(physicalDevice, &properties); + VkDeviceSize minUboAlignment = properties.limits.minStorageBufferOffsetAlignment; + + return (size + minUboAlignment / 2) & ~int(minUboAlignment - 1); +} + +void GFXVulkan::render(GFXCommandBuffer *command_buffer, const int identifier) { + vkWaitForFences(device, 1, &inFlightFences[currentFrame], VK_TRUE, std::numeric_limits::max()); + + uint32_t imageIndex = 0; + VkResult result = vkAcquireNextImageKHR(device, swapchain, std::numeric_limits::max(), imageAvailableSemaphores[currentFrame], VK_NULL_HANDLE, &imageIndex); + if (result == VK_ERROR_OUT_OF_DATE_KHR) { + //std::cout << "oops??" << std::endl; + return; + } + + VkCommandBufferBeginInfo beginInfo = {}; + beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + beginInfo.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT; + + vkBeginCommandBuffer(commandBuffers[imageIndex], &beginInfo); + + VkRenderPass currentRenderPass = VK_NULL_HANDLE; + GFXVulkanPipeline* currentPipeline = nullptr; + uint64_t lastDescriptorHash = 0; + VkIndexType currentIndexType = VK_INDEX_TYPE_UINT32; + + for (auto command : command_buffer->commands) { + switch (command.type) { + case GFXCommandType::SetRenderPass: + { + // end the previous render pass + if (currentRenderPass != VK_NULL_HANDLE) { + vkCmdEndRenderPass(commandBuffers[imageIndex]); + } + + GFXVulkanRenderPass* renderPass = (GFXVulkanRenderPass*)command.data.set_render_pass.render_pass; + GFXVulkanFramebuffer* framebuffer = (GFXVulkanFramebuffer*)command.data.set_render_pass.framebuffer; + + if (renderPass != nullptr) { + currentRenderPass = renderPass->handle; + } + else { + currentRenderPass = swapchainRenderPass; + } + + VkRenderPassBeginInfo renderPassInfo = {}; + renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; + renderPassInfo.renderPass = currentRenderPass; + + if (framebuffer != nullptr) { + renderPassInfo.framebuffer = framebuffer->handle; + + VkViewport viewport = {}; + viewport.width = static_cast(framebuffer->width); + viewport.height = static_cast(framebuffer->height); + viewport.maxDepth = 1.0f; + + vkCmdSetViewport(commandBuffers[imageIndex], 0, 1, &viewport); + + VkRect2D scissor = {}; + scissor.extent.width = framebuffer->width; + scissor.extent.height = framebuffer->height; + + vkCmdSetScissor(commandBuffers[imageIndex], 0, 1, &scissor); + } + else { + renderPassInfo.framebuffer = swapchainFramebuffers[imageIndex]; + + VkViewport viewport = {}; + viewport.width = static_cast(surfaceWidth); + viewport.height = static_cast(surfaceHeight); + viewport.maxDepth = 1.0f; + + vkCmdSetViewport(commandBuffers[imageIndex], 0, 1, &viewport); + + VkRect2D scissor = {}; + scissor.extent.width = surfaceWidth; + scissor.extent.height = surfaceHeight; + + vkCmdSetScissor(commandBuffers[imageIndex], 0, 1, &scissor); + } + + renderPassInfo.renderArea.offset = { command.data.set_render_pass.viewport.x, command.data.set_render_pass.viewport.y }; + renderPassInfo.renderArea.extent = { command.data.set_render_pass.viewport.width, command.data.set_render_pass.viewport.height }; + + std::vector clearColors; + if (renderPass != nullptr) { + clearColors.resize(renderPass->numAttachments); + } + else { + clearColors.resize(1); + } + + clearColors[0].color.float32[0] = command.data.set_render_pass.clear_color.r; + clearColors[0].color.float32[1] = command.data.set_render_pass.clear_color.g; + clearColors[0].color.float32[2] = command.data.set_render_pass.clear_color.b; + clearColors[0].color.float32[3] = command.data.set_render_pass.clear_color.a; + + if(renderPass != nullptr) { + if(renderPass->depth_attachment != -1) + clearColors[renderPass->depth_attachment].depthStencil.depth = 1.0f; + } + + renderPassInfo.clearValueCount = static_cast(clearColors.size()); + renderPassInfo.pClearValues = clearColors.data(); + + vkCmdBeginRenderPass(commandBuffers[imageIndex], &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE); + } + break; + case GFXCommandType::SetPipeline: + { + currentPipeline = (GFXVulkanPipeline*)command.data.set_pipeline.pipeline; + vkCmdBindPipeline(commandBuffers[imageIndex], VK_PIPELINE_BIND_POINT_GRAPHICS, currentPipeline->handle); + + resetDescriptorState(); + lastDescriptorHash = 0; + } + break; + case GFXCommandType::SetVertexBuffer: + { + VkBuffer buffer = ((GFXVulkanBuffer*)command.data.set_vertex_buffer.buffer)->get(currentFrame).handle; + VkDeviceSize offset = command.data.set_vertex_buffer.offset; + vkCmdBindVertexBuffers(commandBuffers[imageIndex], command.data.set_vertex_buffer.index, 1, &buffer, &offset); + } + break; + case GFXCommandType::SetIndexBuffer: + { + VkIndexType indexType = VK_INDEX_TYPE_UINT32; + if (command.data.set_index_buffer.index_type == IndexType::UINT16) + indexType = VK_INDEX_TYPE_UINT16; + + vkCmdBindIndexBuffer(commandBuffers[imageIndex], ((GFXVulkanBuffer*)command.data.set_index_buffer.buffer)->get(currentFrame).handle, 0, indexType); + + currentIndexType = indexType; + } + break; + case GFXCommandType::SetPushConstant: + { + if(currentPipeline != nullptr) + vkCmdPushConstants(commandBuffers[imageIndex], currentPipeline->layout, VK_SHADER_STAGE_ALL, 0, command.data.set_push_constant.size, command.data.set_push_constant.bytes); + } + break; + case GFXCommandType::BindShaderBuffer: + { + BoundShaderBuffer bsb; + bsb.buffer = command.data.bind_shader_buffer.buffer; + bsb.offset = command.data.bind_shader_buffer.offset; + bsb.size = command.data.bind_shader_buffer.size; + + boundShaderBuffers[command.data.bind_shader_buffer.index] = bsb; + } + break; + case GFXCommandType::BindTexture: + { + boundTextures[command.data.bind_texture.index] = command.data.bind_texture.texture; + } + break; + case GFXCommandType::Draw: + { + if (lastDescriptorHash != getDescriptorHash(currentPipeline)) { + if (!currentPipeline->cachedDescriptorSets.count(getDescriptorHash(currentPipeline))) + cacheDescriptorState(currentPipeline, currentPipeline->descriptorLayout); + + vkCmdBindDescriptorSets(commandBuffers[imageIndex], VK_PIPELINE_BIND_POINT_GRAPHICS, currentPipeline->layout, 0, 1, ¤tPipeline->cachedDescriptorSets[getDescriptorHash(currentPipeline)], 0, nullptr); + + lastDescriptorHash = getDescriptorHash(currentPipeline); + } + + vkCmdDraw(commandBuffers[imageIndex], command.data.draw.vertex_count, command.data.draw.instance_count, command.data.draw.vertex_offset, command.data.draw.base_instance); + } + break; + case GFXCommandType::DrawIndexed: + { + if (lastDescriptorHash != getDescriptorHash(currentPipeline)) { + if (!currentPipeline->cachedDescriptorSets.count(getDescriptorHash(currentPipeline))) + cacheDescriptorState(currentPipeline, currentPipeline->descriptorLayout); + + vkCmdBindDescriptorSets(commandBuffers[imageIndex], VK_PIPELINE_BIND_POINT_GRAPHICS, currentPipeline->layout, 0, 1, ¤tPipeline->cachedDescriptorSets[getDescriptorHash(currentPipeline)], 0, nullptr); + + lastDescriptorHash = getDescriptorHash(currentPipeline); + } + + vkCmdDrawIndexed(commandBuffers[imageIndex], command.data.draw_indexed.index_count, 1, command.data.draw_indexed.first_index, command.data.draw_indexed.vertex_offset, 0); + } + break; + } + } + + // end the last render pass + if (currentRenderPass != VK_NULL_HANDLE) { + vkCmdEndRenderPass(commandBuffers[imageIndex]); + } + + vkEndCommandBuffer(commandBuffers[imageIndex]); + + // submit + VkSubmitInfo submitInfo = {}; + submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + + VkSemaphore waitSemaphores[] = { imageAvailableSemaphores[currentFrame] }; + VkPipelineStageFlags waitStages[] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT }; + submitInfo.waitSemaphoreCount = 1; + submitInfo.pWaitSemaphores = waitSemaphores; + submitInfo.pWaitDstStageMask = waitStages; + submitInfo.commandBufferCount = 1; + submitInfo.pCommandBuffers = &commandBuffers[imageIndex]; + + VkSemaphore signalSemaphores[] = { renderFinishedSemaphores[currentFrame] }; + submitInfo.signalSemaphoreCount = 1; + submitInfo.pSignalSemaphores = signalSemaphores; + + vkResetFences(device, 1, &inFlightFences[currentFrame]); + + if(vkQueueSubmit(graphicsQueue, 1, &submitInfo, inFlightFences[currentFrame]) != VK_SUCCESS) + return; + + // present + VkPresentInfoKHR presentInfo = {}; + presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; + + presentInfo.waitSemaphoreCount = 1; + presentInfo.pWaitSemaphores = signalSemaphores; + VkSwapchainKHR swapChains[] = { swapchain }; + presentInfo.swapchainCount = 1; + presentInfo.pSwapchains = swapChains; + presentInfo.pImageIndices = &imageIndex; + + vkQueuePresentKHR(presentQueue, &presentInfo); + + currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT; +} + +const char* GFXVulkan::get_name() { + return "Vulkan"; +} + +VkResult CreateDebugUtilsMessengerEXT( + VkInstance instance, + const VkDebugUtilsMessengerCreateInfoEXT *pCreateInfo, + const VkAllocationCallbacks *pAllocator, + VkDebugUtilsMessengerEXT *pCallback) { + + // Note: It seems that static_cast<...> doesn't work. Use the C-style forced cast. + auto func = (PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr(instance, "vkCreateDebugUtilsMessengerEXT"); + if (func != nullptr) { + return func(instance, pCreateInfo, pAllocator, pCallback); + } + else { + return VK_ERROR_EXTENSION_NOT_PRESENT; + } +} + +void GFXVulkan::createInstance(std::vector layers, std::vector extensions) { + VkDebugUtilsMessengerCreateInfoEXT debugCreateInfo = {}; + debugCreateInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT; + debugCreateInfo.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT; + debugCreateInfo.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT ; + debugCreateInfo.pfnUserCallback = DebugCallback; // global function + + VkApplicationInfo appInfo = {}; + appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; + appInfo.pApplicationName = "Prism Engine App"; + appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0); + appInfo.pEngineName = "Prism Engine"; + appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0); + appInfo.apiVersion = VK_API_VERSION_1_0; + + VkInstanceCreateInfo createInfo = {}; + createInfo.pNext = &debugCreateInfo; + createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; + createInfo.pApplicationInfo = &appInfo; + createInfo.ppEnabledLayerNames = layers.data(); + createInfo.enabledLayerCount = static_cast(layers.size()); + createInfo.ppEnabledExtensionNames = extensions.data(); + createInfo.enabledExtensionCount = static_cast(extensions.size()); + + vkCreateInstance(&createInfo, nullptr, &instance); + + VkDebugUtilsMessengerEXT callback; + CreateDebugUtilsMessengerEXT(instance, &debugCreateInfo, nullptr, &callback); +} + +void GFXVulkan::createLogicalDevice(std::vector extensions) { + // pick physical device + uint32_t deviceCount = 0; + vkEnumeratePhysicalDevices(instance, &deviceCount, nullptr); + + std::vector devices(deviceCount); + vkEnumeratePhysicalDevices(instance, &deviceCount, devices.data()); + + physicalDevice = devices[0]; + + uint32_t graphicsFamilyIndex = 0, presentFamilyIndex = 0; + + // create logical device + uint32_t queueFamilyCount = 0; + vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueFamilyCount, nullptr); + + std::vector queueFamilies(queueFamilyCount); + vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueFamilyCount, queueFamilies.data()); + + int i = 0; + for (const auto& queueFamily : queueFamilies) { + if (queueFamily.queueCount > 0 && queueFamily.queueFlags & VK_QUEUE_GRAPHICS_BIT) { + graphicsFamilyIndex = i; + } + + i++; + } + + std::vector queueCreateInfos; + + if (graphicsFamilyIndex == presentFamilyIndex) { + VkDeviceQueueCreateInfo queueCreateInfo = {}; + queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; + queueCreateInfo.queueFamilyIndex = graphicsFamilyIndex; + queueCreateInfo.queueCount = 1; + + float queuePriority = 1.0f; + queueCreateInfo.pQueuePriorities = &queuePriority; + + queueCreateInfos.push_back(queueCreateInfo); + } + + VkDeviceCreateInfo createInfo = {}; + createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; + createInfo.pQueueCreateInfos = queueCreateInfos.data(); + createInfo.queueCreateInfoCount = static_cast(queueCreateInfos.size()); + createInfo.ppEnabledExtensionNames = extensions.data(); + createInfo.enabledExtensionCount = static_cast(extensions.size()); + + VkPhysicalDeviceFeatures enabledFeatures = {}; + //enabledFeatures.vertexPipelineStoresAndAtomics = true; + enabledFeatures.fragmentStoresAndAtomics = true; + enabledFeatures.samplerAnisotropy = true; + enabledFeatures.fillModeNonSolid = true; + + createInfo.pEnabledFeatures = &enabledFeatures; + + vkCreateDevice(physicalDevice, &createInfo, nullptr, &device); + + // get queues + vkGetDeviceQueue(device, graphicsFamilyIndex, 0, &graphicsQueue); + vkGetDeviceQueue(device, presentFamilyIndex, 0, &presentQueue); + + // command pool + VkCommandPoolCreateInfo poolInfo = {}; + poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; + poolInfo.queueFamilyIndex = graphicsFamilyIndex; + poolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; + + vkCreateCommandPool(device, &poolInfo, nullptr, &commandPool); +} + +void GFXVulkan::createSwapchain(VkSwapchainKHR oldSwapchain) { + +#ifdef PLATFORM_WINDOWS + // create win32 surface + if(surface == VK_NULL_HANDLE) + { + VkWin32SurfaceCreateInfoKHR createInfo = {}; + createInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR; + createInfo.hwnd = (HWND)windowNativeHandle; + createInfo.hinstance = GetModuleHandle(nullptr); + + vkCreateWin32SurfaceKHR(instance, &createInfo, nullptr, &surface); + } +#else + if(surface == VK_NULL_HANDLE) { + struct WindowConnection { + xcb_connection_t* connection; + xcb_window_t window; + }; + + WindowConnection* wincon = reinterpret_cast(windowNativeHandle); + + VkXcbSurfaceCreateInfoKHR createInfo = {}; + createInfo.sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR; + createInfo.window = wincon->window; + createInfo.connection = wincon->connection; + + vkCreateXcbSurfaceKHR(instance, &createInfo, nullptr, &surface); + } +#endif + + // TODO: fix this pls + VkBool32 supported; + vkGetPhysicalDeviceSurfaceSupportKHR(physicalDevice, 0, surface, &supported); + + // query swapchain support + VkSurfaceCapabilitiesKHR capabilities; + vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, surface, &capabilities); + + std::vector formats; + + uint32_t formatCount; + vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, &formatCount, nullptr); + + formats.resize(formatCount); + vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, &formatCount, formats.data()); + + std::vector presentModes; + uint32_t presentModeCount; + vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, &presentModeCount, nullptr); + + presentModes.resize(presentModeCount); + vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, &presentModeCount, presentModes.data()); + + // choosing swapchain features + VkSurfaceFormatKHR swapchainSurfaceFormat = formats[0]; + for (const auto& availableFormat : formats) { + if (availableFormat.format == VK_FORMAT_B8G8R8A8_UNORM && availableFormat.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) { + swapchainSurfaceFormat = availableFormat; + } + } + + VkPresentModeKHR swapchainPresentMode = VK_PRESENT_MODE_FIFO_KHR; + for (const auto& availablePresentMode : presentModes) { + if (availablePresentMode == VK_PRESENT_MODE_MAILBOX_KHR) { + swapchainPresentMode = availablePresentMode; + } + } + + uint32_t imageCount = capabilities.minImageCount + 1; + if (capabilities.maxImageCount > 0 && imageCount > capabilities.maxImageCount) { + imageCount = capabilities.maxImageCount; + } + + // create swapchain + VkSwapchainCreateInfoKHR createInfo = {}; + createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; + createInfo.surface = surface; + createInfo.minImageCount = imageCount; + createInfo.imageFormat = swapchainSurfaceFormat.format; + createInfo.imageColorSpace = swapchainSurfaceFormat.colorSpace; + createInfo.imageExtent.width = surfaceWidth; + createInfo.imageExtent.height = surfaceHeight; + createInfo.imageArrayLayers = 1; + createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; + createInfo.preTransform = capabilities.currentTransform; + createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; + createInfo.presentMode = swapchainPresentMode; + createInfo.clipped = VK_TRUE; + createInfo.oldSwapchain = oldSwapchain; + + vkCreateSwapchainKHR(device, &createInfo, nullptr, &swapchain); + + if (oldSwapchain != VK_NULL_HANDLE) { + vkDestroySwapchainKHR(device, oldSwapchain, nullptr); + } + + swapchainExtent.width = surfaceWidth; + swapchainExtent.height = surfaceHeight; + + // get swapchain images + vkGetSwapchainImagesKHR(device, swapchain, &imageCount, nullptr); + swapchainImages.resize(imageCount); + vkGetSwapchainImagesKHR(device, swapchain, &imageCount, swapchainImages.data()); + + // create swapchain image views + swapchainImageViews.resize(swapchainImages.size()); + + for (size_t i = 0; i < swapchainImages.size(); i++) { + VkImageViewCreateInfo createInfo = {}; + createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + createInfo.image = swapchainImages[i]; + createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; + createInfo.format = swapchainSurfaceFormat.format; + createInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY; + createInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY; + createInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY; + createInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY; + createInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + createInfo.subresourceRange.baseMipLevel = 0; + createInfo.subresourceRange.levelCount = 1; + createInfo.subresourceRange.baseArrayLayer = 0; + createInfo.subresourceRange.layerCount = 1; + + vkCreateImageView(device, &createInfo, nullptr, &swapchainImageViews[i]); + } + + // create render pass + VkAttachmentDescription colorAttachment = {}; + colorAttachment.format = swapchainSurfaceFormat.format; + colorAttachment.samples = VK_SAMPLE_COUNT_1_BIT; + colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; + colorAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + colorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + colorAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + colorAttachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; + + VkAttachmentReference colorAttachmentRef = {}; + colorAttachmentRef.attachment = 0; + colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + + VkSubpassDescription subpass = {}; + subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; + subpass.colorAttachmentCount = 1; + subpass.pColorAttachments = &colorAttachmentRef; + + VkRenderPassCreateInfo renderPassInfo = {}; + renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; + renderPassInfo.attachmentCount = 1; + renderPassInfo.pAttachments = &colorAttachment; + renderPassInfo.subpassCount = 1; + renderPassInfo.pSubpasses = &subpass; + + vkCreateRenderPass(device, &renderPassInfo, nullptr, &swapchainRenderPass); + + // create swapchain framebuffers + swapchainFramebuffers.resize(swapchainImageViews.size()); + + for (size_t i = 0; i < swapchainImageViews.size(); i++) { + VkImageView attachments[] = { + swapchainImageViews[i] + }; + + VkFramebufferCreateInfo framebufferInfo = {}; + framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; + framebufferInfo.renderPass = swapchainRenderPass; + framebufferInfo.attachmentCount = 1; + framebufferInfo.pAttachments = attachments; + framebufferInfo.width = surfaceWidth; + framebufferInfo.height = surfaceHeight; + framebufferInfo.layers = 1; + + vkCreateFramebuffer(device, &framebufferInfo, nullptr, &swapchainFramebuffers[i]); + } + + // allocate command buffers + commandBuffers.resize(imageCount); + + VkCommandBufferAllocateInfo allocInfo = {}; + allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + allocInfo.commandPool = commandPool; + allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + allocInfo.commandBufferCount = (uint32_t)commandBuffers.size(); + + vkAllocateCommandBuffers(device, &allocInfo, commandBuffers.data()); +} + +void GFXVulkan::createDescriptorPool() { + const std::array poolSizes = { { + {VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 100}, + {VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 100} + }}; + + VkDescriptorPoolCreateInfo poolInfo = {}; + poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; + poolInfo.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT; + poolInfo.poolSizeCount = static_cast(poolSizes.size()); + poolInfo.pPoolSizes = poolSizes.data(); + poolInfo.maxSets = 100; + + vkCreateDescriptorPool(device, &poolInfo, nullptr, &descriptorPool); +} + +void GFXVulkan::createSyncPrimitives() { + imageAvailableSemaphores.resize(MAX_FRAMES_IN_FLIGHT); + renderFinishedSemaphores.resize(MAX_FRAMES_IN_FLIGHT); + inFlightFences.resize(MAX_FRAMES_IN_FLIGHT); + + VkSemaphoreCreateInfo semaphoreInfo = {}; + semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; + + VkFenceCreateInfo fenceCreateInfo = {}; + fenceCreateInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; + fenceCreateInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT; + + for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { + vkCreateSemaphore(device, &semaphoreInfo, nullptr, &imageAvailableSemaphores[i]); + vkCreateSemaphore(device, &semaphoreInfo, nullptr, &renderFinishedSemaphores[i]); + vkCreateFence(device, &fenceCreateInfo, nullptr, &inFlightFences[i]); + } +} + +void GFXVulkan::resetDescriptorState() { + for (auto& buffer : boundShaderBuffers) + buffer.buffer = nullptr; + + for (auto& texture : boundTextures) + texture = nullptr; +} + +void GFXVulkan::cacheDescriptorState(GFXVulkanPipeline* pipeline, VkDescriptorSetLayout layout) { + uint64_t hash = getDescriptorHash(pipeline); + + vkDeviceWaitIdle(device); + + // create set object + VkDescriptorSet descriptorSet; + + VkDescriptorSetAllocateInfo allocInfo = {}; + allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; + allocInfo.descriptorPool = descriptorPool; + allocInfo.descriptorSetCount = 1; + allocInfo.pSetLayouts = &layout; + + vkAllocateDescriptorSets(device, &allocInfo, &descriptorSet); + + // update set + int i = 0; + for (auto& buffer : boundShaderBuffers) { + if (buffer.buffer == nullptr) { + i++; + continue; + } + + GFXVulkanBuffer* vulkanBuffer = (GFXVulkanBuffer*)buffer.buffer; + + VkDescriptorBufferInfo bufferInfo = {}; + bufferInfo.buffer = vulkanBuffer->get(currentFrame).handle; // will this break? + bufferInfo.offset = buffer.offset; + bufferInfo.range = buffer.size; + + VkWriteDescriptorSet descriptorWrite = {}; + descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + descriptorWrite.dstSet = descriptorSet; + descriptorWrite.dstBinding = i; + descriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; + descriptorWrite.descriptorCount = 1; + descriptorWrite.pBufferInfo = &bufferInfo; + + vkUpdateDescriptorSets(device, 1, &descriptorWrite, 0, nullptr); + + i++; + } + + i = 0; + for (auto& texture : boundTextures) { + if (texture == nullptr) { + i++; + continue; + } + + GFXVulkanTexture* vulkanTexture = (GFXVulkanTexture*)texture; + + VkDescriptorImageInfo imageInfo = {}; + imageInfo.imageLayout = vulkanTexture->layout; + + // color attachments are not the right layout + //if (imageInfo.imageLayout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) + // imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + + imageInfo.imageView = vulkanTexture->view; + imageInfo.sampler = vulkanTexture->sampler; + + VkWriteDescriptorSet descriptorWrite = {}; + descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + descriptorWrite.dstSet = descriptorSet; + descriptorWrite.dstBinding = i; + descriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + descriptorWrite.descriptorCount = 1; + descriptorWrite.pImageInfo = &imageInfo; + + vkUpdateDescriptorSets(device, 1, &descriptorWrite, 0, nullptr); + + i++; + } + + pipeline->cachedDescriptorSets[hash] = descriptorSet; +} + +uint64_t GFXVulkan::getDescriptorHash(GFXVulkanPipeline* pipeline) { + uint64_t hash = 0; + hash += (int64_t)pipeline; + + for (auto& buffer : boundShaderBuffers) { + if(buffer.buffer != nullptr) + hash += (uint64_t)buffer.buffer; + } + + int i = 0; + for (auto& texture : boundTextures) { + if (texture != nullptr) { + hash += (uint64_t)texture * (i + 1); + } + } + + return hash; +} + +uint32_t GFXVulkan::findMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags properties) { + VkPhysicalDeviceMemoryProperties memProperties; + vkGetPhysicalDeviceMemoryProperties(physicalDevice, &memProperties); + + for (uint32_t i = 0; i < memProperties.memoryTypeCount; i++) { + if ((typeFilter & (1 << i)) && (memProperties.memoryTypes[i].propertyFlags & properties) == properties) { + return i; + } + } + + return -1; +} + +void GFXVulkan::transitionImageLayout(VkImage image, VkFormat format, VkImageAspectFlags aspect, VkImageLayout oldLayout, VkImageLayout newLayout) { + VkCommandBuffer commandBuffer = beginSingleTimeCommands(); + + VkImageMemoryBarrier barrier = {}; + barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + barrier.oldLayout = oldLayout; + barrier.newLayout = newLayout; + barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barrier.image = image; + barrier.subresourceRange.aspectMask = aspect; + barrier.subresourceRange.baseMipLevel = 0; + barrier.subresourceRange.levelCount = 1; + barrier.subresourceRange.baseArrayLayer = 0; + barrier.subresourceRange.layerCount = 1; + barrier.srcAccessMask = VK_ACCESS_MEMORY_WRITE_BIT; // TODO + barrier.dstAccessMask = VK_ACCESS_MEMORY_WRITE_BIT; // TODO + + vkCmdPipelineBarrier( + commandBuffer, + VK_PIPELINE_STAGE_HOST_BIT /* TODO */, VK_PIPELINE_STAGE_HOST_BIT /* TODO */, + 0, + 0, nullptr, + 0, nullptr, + 1, &barrier + ); + + endSingleTimeCommands(commandBuffer); +} + +VkShaderModule GFXVulkan::createShaderModule(const unsigned char* code, const int length) { + VkShaderModuleCreateInfo createInfo = {}; + createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; + createInfo.codeSize = length; + createInfo.pCode = reinterpret_cast(code); + + VkShaderModule shaderModule; + vkCreateShaderModule(device, &createInfo, nullptr, &shaderModule); + + return shaderModule; +} + +VkCommandBuffer GFXVulkan::beginSingleTimeCommands() { + VkCommandBufferAllocateInfo allocInfo = {}; + allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + allocInfo.commandPool = commandPool; + allocInfo.commandBufferCount = 1; + + VkCommandBuffer commandBuffer; + vkAllocateCommandBuffers(device, &allocInfo, &commandBuffer); + + VkCommandBufferBeginInfo beginInfo = {}; + beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + + vkBeginCommandBuffer(commandBuffer, &beginInfo); + + return commandBuffer; +} + +void GFXVulkan::endSingleTimeCommands(VkCommandBuffer commandBuffer) { + vkEndCommandBuffer(commandBuffer); + + VkSubmitInfo submitInfo = {}; + submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submitInfo.commandBufferCount = 1; + submitInfo.pCommandBuffers = &commandBuffer; + + vkQueueSubmit(graphicsQueue, 1, &submitInfo, VK_NULL_HANDLE); + vkQueueWaitIdle(graphicsQueue); + + vkFreeCommandBuffers(device, commandPool, 1, &commandBuffer); +} diff --git a/engine/gfx/vulkan/src/gfx_vulkan_buffer.hpp b/engine/gfx/vulkan/src/gfx_vulkan_buffer.hpp new file mode 100755 index 0000000..5936a57 --- /dev/null +++ b/engine/gfx/vulkan/src/gfx_vulkan_buffer.hpp @@ -0,0 +1,26 @@ +#pragma once + +#include + +#include "gfx_buffer.hpp" +#include "gfx_vulkan_constants.hpp" + +class GFXVulkanBuffer : public GFXBuffer { +public: + bool is_dynamic_data = false; + + struct Data { + VkBuffer handle; + VkDeviceMemory memory; + } data[MAX_FRAMES_IN_FLIGHT]; + + Data get(int frameIndex) { + if(is_dynamic_data) { + return data[frameIndex]; + } else { + return data[0]; + } + } + + VkDeviceSize size; +}; diff --git a/engine/gfx/vulkan/src/gfx_vulkan_framebuffer.hpp b/engine/gfx/vulkan/src/gfx_vulkan_framebuffer.hpp new file mode 100755 index 0000000..6aa7d4d --- /dev/null +++ b/engine/gfx/vulkan/src/gfx_vulkan_framebuffer.hpp @@ -0,0 +1,12 @@ +#pragma once + +#include + +#include "gfx_framebuffer.hpp" + +class GFXVulkanFramebuffer : public GFXFramebuffer { +public: + VkFramebuffer handle; + + int width = 0, height = 0; +}; diff --git a/engine/gfx/vulkan/src/gfx_vulkan_pipeline.hpp b/engine/gfx/vulkan/src/gfx_vulkan_pipeline.hpp new file mode 100755 index 0000000..9faa339 --- /dev/null +++ b/engine/gfx/vulkan/src/gfx_vulkan_pipeline.hpp @@ -0,0 +1,16 @@ +#pragma once + +#include + +#include "gfx_pipeline.hpp" + +class GFXVulkanPipeline : public GFXPipeline { +public: + VkPipeline handle; + VkPipelineLayout layout; + + VkDescriptorSetLayout descriptorLayout; + + // dynamic descriptor sets + std::map cachedDescriptorSets; +}; diff --git a/engine/gfx/vulkan/src/gfx_vulkan_renderpass.hpp b/engine/gfx/vulkan/src/gfx_vulkan_renderpass.hpp new file mode 100755 index 0000000..361d992 --- /dev/null +++ b/engine/gfx/vulkan/src/gfx_vulkan_renderpass.hpp @@ -0,0 +1,15 @@ +#pragma once + +#include + +#include "gfx_renderpass.hpp" + +class GFXVulkanRenderPass : public GFXRenderPass { +public: + VkRenderPass handle = VK_NULL_HANDLE; + + unsigned int numAttachments = 0; + int depth_attachment = -1; + + bool hasDepthAttachment = false; +}; diff --git a/engine/gfx/vulkan/src/gfx_vulkan_texture.hpp b/engine/gfx/vulkan/src/gfx_vulkan_texture.hpp new file mode 100755 index 0000000..cb193f6 --- /dev/null +++ b/engine/gfx/vulkan/src/gfx_vulkan_texture.hpp @@ -0,0 +1,18 @@ +#pragma once + +#include + +#include "gfx_texture.hpp" + +class GFXVulkanTexture : public GFXTexture { +public: + VkImage handle; + VkDeviceMemory memory; + VkImageView view; + VkSampler sampler; + + int width, height; + + VkFormat format; + VkImageLayout layout; +}; diff --git a/engine/log/CMakeLists.txt b/engine/log/CMakeLists.txt new file mode 100755 index 0000000..3b3722d --- /dev/null +++ b/engine/log/CMakeLists.txt @@ -0,0 +1,9 @@ +set(SRC + include/log.hpp + src/log.cpp) + +add_library(Log STATIC ${SRC}) +target_include_directories(Log PUBLIC include) +target_compile_features(Log PUBLIC cxx_std_17) +set_target_properties(Log PROPERTIES CXX_EXTENSIONS OFF) +target_link_libraries(Log PRIVATE Utility) diff --git a/engine/log/include/log.hpp b/engine/log/include/log.hpp new file mode 100755 index 0000000..ca64ef7 --- /dev/null +++ b/engine/log/include/log.hpp @@ -0,0 +1,62 @@ +#pragma once + +#include +#include +#include + +enum class System { + None, + Core, + Renderer, + Game, + File, + GFX +}; + +enum class Level { + Info, + Warning, + Error, + Debug +}; + +namespace console { + template + void internal_format(std::string& msg, const Arg& arg) { + auto pos = msg.find_first_of("{}"); + msg.replace(pos, 2, arg); + } + + void process_message(const Level level, const System system, const std::string_view message); + + template + void internal_print(const Level level, const System system, const std::string_view format, Args&&... args) { + auto msg = std::string(format); + + ((internal_format(msg, args)), ...); + + process_message(level, system, msg); + } + + template + void info(const System system, const std::string_view format, Args&&... args) { + internal_print(Level::Info, system, format, args...); + } + + template + void warning(const System system, const std::string_view format, Args&&... args) { + internal_print(Level::Warning, system, format, args...); + } + + template + void error(const System system, const std::string_view format, Args&&... args) { + internal_print(Level::Error, system, format, args...); + } + + template + void debug(const System system, const std::string_view format, Args&&... args) { + internal_print(Level::Debug, system, format, args...); + } + + inline std::vector stored_output; +} diff --git a/engine/log/src/log.cpp b/engine/log/src/log.cpp new file mode 100755 index 0000000..c3da45b --- /dev/null +++ b/engine/log/src/log.cpp @@ -0,0 +1,23 @@ +#include "log.hpp" + +#include +#include +#include +#include "string_utils.hpp" +#include "utility.hpp" + +void console::process_message(const Level level, const System system, const std::string_view message) { + auto now = std::chrono::system_clock::now(); + std::time_t t_c = std::chrono::system_clock::to_time_t(now); + + std::string date; + date.resize(30); + + std::strftime(&date[0], date.size(), "%Y-%m-%d %H:%M:%S", std::localtime(&t_c)); + + std::string s = utility::format("{} {} {}: {}", date, utility::enum_to_string(system), utility::enum_to_string(level), message); + + std::cout << s << '\n'; + + stored_output.push_back(s); +} diff --git a/engine/math/CMakeLists.txt b/engine/math/CMakeLists.txt new file mode 100755 index 0000000..9469342 --- /dev/null +++ b/engine/math/CMakeLists.txt @@ -0,0 +1,15 @@ +set(SRC + include/math.hpp + include/matrix.hpp + include/transform.hpp + include/vector.hpp + include/quaternion.hpp + include/plane.hpp + + src/transform.cpp + src/math.cpp) + +add_library(Math STATIC ${SRC}) +target_include_directories(Math PUBLIC include) +target_compile_features(Math PUBLIC cxx_std_17) +set_target_properties(Math PROPERTIES CXX_EXTENSIONS OFF) diff --git a/engine/math/include/math.hpp b/engine/math/include/math.hpp new file mode 100755 index 0000000..3b50805 --- /dev/null +++ b/engine/math/include/math.hpp @@ -0,0 +1,30 @@ +#pragma once + +#include "matrix.hpp" +#include "transform.hpp" +#include "vector.hpp" + +constexpr double PI = 3.141592653589793; + +template +constexpr inline T radians(const T degrees) { + return degrees / static_cast(180) * static_cast(PI); +} + +template +constexpr inline T degrees(const T radians) { + return radians / static_cast(PI) * static_cast(180); +} + +template +constexpr inline bool nearly_equal(const T a, const T b) { + return std::nextafter(a, std::numeric_limits::lowest()) <= b + && std::nextafter(a, std::numeric_limits::max()) >= b; +} + +Matrix4x4 matrix_from_quat(const Quaternion quat); +Quaternion quat_from_matrix(const Matrix3x3 matrix); +Quaternion euler_to_quat(const Vector3 angle); +Vector3 quat_to_euler(const Quaternion quat); +Matrix4x4 inverse(const Matrix4x4 m); +Quaternion angle_axis(const float angle, const Vector3 axis); diff --git a/engine/math/include/matrix.hpp b/engine/math/include/matrix.hpp new file mode 100755 index 0000000..665280f --- /dev/null +++ b/engine/math/include/matrix.hpp @@ -0,0 +1,87 @@ +#pragma once + +#include "vector.hpp" + +// m = rows +// n = columns +// row major storage mode? +template +class Matrix { +public: + constexpr Matrix(const T diagonal = T(1)) { + for(std::size_t i = 0; i < (M * N); i++) + unordered_data[i] = ((i / M) == (i % N) ? diagonal : T(0)); + } + + constexpr Matrix(const Vector4 m1_, const Vector4 m2_, const Vector4 m3_, const Vector4 m4_) { + columns[0] = m1_; + columns[1] = m2_; + columns[2] = m3_; + columns[3] = m4_; + } + + constexpr inline void operator*=(const Matrix rhs); + + using VectorType = Vector; + + constexpr VectorType& operator[](const size_t index) { return columns[index]; } + constexpr VectorType operator[](const size_t index) const { return columns[index]; } + + union { + VectorType columns[M]; + T data[M][N]; + T unordered_data[M * N] = {}; + }; +}; + +using Matrix4x4 = Matrix; +using Matrix3x3 = Matrix; + +constexpr inline Matrix4x4 operator*(const Matrix4x4 lhs, const Matrix4x4 rhs) { + Matrix4x4 tmp(0.0f); + for(int j = 0; j < 4; j++) { + for(int i = 0; i < 4; i++) { + for(int k = 0; k < 4; k++) + tmp.data[j][i] += lhs.data[k][i] * rhs.data[j][k]; + } + } + + return tmp; +} + +constexpr inline Vector4 operator*(const Matrix4x4 lhs, const Vector4 rhs) { + Vector4 tmp; + for(int r = 0; r < 4; r++) { + for(int c = 0; c < 4; c++) + tmp[r] += lhs.data[c][r] * rhs.data[c]; + } + + return tmp; +} + +constexpr inline Matrix4x4 operator/(const Matrix4x4 lhs, const float rhs) { + Matrix4x4 tmp(0.0f); + for(int j = 0; j < 4; j++) { + for(int i = 0; i < 4; i++) { + for(int k = 0; k < 4; k++) + tmp.data[k][i] = lhs.data[k][i] / rhs; + } + } + + return tmp; +} + +constexpr inline Matrix4x4 operator*(const Matrix4x4 lhs, const float rhs) { + Matrix4x4 tmp(0.0f); + for (int j = 0; j < 4; j++) { + for (int i = 0; i < 4; i++) { + for (int k = 0; k < 4; k++) + tmp.data[k][i] = lhs.data[k][i] * rhs; + } + } + + return tmp; +} + +template +constexpr void Matrix::operator*=(const Matrix rhs) { *this = *this * rhs; } diff --git a/engine/math/include/plane.hpp b/engine/math/include/plane.hpp new file mode 100755 index 0000000..beca248 --- /dev/null +++ b/engine/math/include/plane.hpp @@ -0,0 +1,26 @@ +#pragma once + +struct Plane { + float a = 0.0, b = 0.0, c = 0.0, d = 0.0; +}; + +inline Plane normalize(const Plane& plane) { + const float magnitude = std::sqrt(plane.a * plane.a + + plane.b * plane.b + + plane.c * plane.c); + + Plane normalized_plane = plane; + normalized_plane.a = plane.a / magnitude; + normalized_plane.b = plane.b / magnitude; + normalized_plane.c = plane.c / magnitude; + normalized_plane.d = plane.d / magnitude; + + return normalized_plane; +} + +inline float distance_to_point(const Plane& plane, const Vector3& point) { + return plane.a * point.x + + plane.b * point.y + + plane.c * point.z + + plane.d; +} diff --git a/engine/math/include/quaternion.hpp b/engine/math/include/quaternion.hpp new file mode 100755 index 0000000..96f8274 --- /dev/null +++ b/engine/math/include/quaternion.hpp @@ -0,0 +1,87 @@ +#pragma once + +#include "vector.hpp" + +class Quaternion { +public: + constexpr Quaternion(const float v = 0.0f) : w(1.0f), x(v), y(v), z(v) {} + + constexpr Quaternion(const float x, const float y, const float z, const float w) : w(w), x(x), y(y), z(z) {} + + float w, x, y, z; +}; + +constexpr inline Quaternion operator*(const Quaternion lhs, const float rhs) { + Quaternion tmp(lhs); + tmp.x *= rhs; + tmp.y *= rhs; + tmp.z *= rhs; + tmp.w *= rhs; + + return tmp; +} + +constexpr inline Vector3 operator*(const Quaternion& lhs, const Vector3& rhs) { + const Vector3 quatVector = Vector3(lhs.x, lhs.y, lhs.z); + const Vector3 uv = cross(quatVector, rhs); + const Vector3 uuv = cross(quatVector, uv); + + return rhs + ((uv * lhs.w) + uuv) * 2.0f; +} + +constexpr inline Vector3 operator*(const Vector3& rhs, const Quaternion& lhs) { + return lhs * rhs; +} + +constexpr inline float dot(const Quaternion& a, const Quaternion& b) { + return a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w; +} + +inline float length(const Quaternion& quat) { + return sqrtf(dot(quat, quat)); +} + +inline Quaternion normalize(const Quaternion& quat) { + const float l = length(quat); + + return quat * (1.0f / l); +} + +constexpr inline Quaternion lerp(const Quaternion& a, const Quaternion& b, const float time) { + float cosom = dot(a, b); + + Quaternion end = b; + if(cosom < 0.0f) { + cosom = -cosom; + end.x = -end.x; + end.y = -end.y; + end.z = -end.z; + end.w = -end.w; + } + + float sclp = 0.0f, sclq = 0.0f; + if((1.0f - cosom) > 0.0001f) { + const float omega = std::acos(cosom); + const float sinom = std::sin(omega); + sclp = std::sin((1.0f - time) * omega) / sinom; + sclq = std::sin(time* omega) / sinom; + } else { + sclp = 1.0f - time; + sclq = time; + } + + return {sclp * a.x + sclq * end.x, + sclp * a.y + sclq * end.y, + sclp * a.z + sclq * end.z, + sclp * a.w + sclq * end.w}; +} + +constexpr inline Quaternion operator*(const Quaternion lhs, const Quaternion rhs) { + Quaternion tmp; + tmp.w = lhs.w * rhs.w - lhs.x * rhs.x - lhs.y * rhs.y - lhs.z * rhs.z; + tmp.x = lhs.w * rhs.x + lhs.x * rhs.w + lhs.y * rhs.z - lhs.z * rhs.y; + tmp.y = lhs.w * rhs.y + lhs.y * rhs.w + lhs.z * rhs.x - lhs.x * rhs.z; + tmp.z = lhs.w * rhs.z + lhs.z * rhs.w + lhs.x * rhs.y - lhs.y * rhs.x; + + return tmp; +} diff --git a/engine/math/include/transform.hpp b/engine/math/include/transform.hpp new file mode 100755 index 0000000..9945a1f --- /dev/null +++ b/engine/math/include/transform.hpp @@ -0,0 +1,23 @@ +#pragma once + +#include "matrix.hpp" +#include "vector.hpp" +#include "quaternion.hpp" + +namespace transform { + /* + Produces a right-handed perspective matrix. + */ + Matrix4x4 perspective(const float fov, const float aspectRatio, const float zNear); + Matrix4x4 orthographic(float left, float right, float bottom, float top, float zNear, float zFar); + + /* + Produces right-handed outputs. + */ + Matrix4x4 look_at(const Vector3 eye, const Vector3 center, const Vector3 up); + Quaternion quat_look_at(const Vector3 eye, const Vector3 center, const Vector3 up); + + Matrix4x4 translate(const Matrix4x4 matrix, const Vector3 translation); + Matrix4x4 rotate(const Matrix4x4 matrix, const float angle, const Vector3 axis); + Matrix4x4 scale(const Matrix4x4 matrix, const Vector3 scale); +} diff --git a/engine/math/include/vector.hpp b/engine/math/include/vector.hpp new file mode 100755 index 0000000..2c4bcfb --- /dev/null +++ b/engine/math/include/vector.hpp @@ -0,0 +1,251 @@ +#pragma once + +#include +#include +#include +#include + +#define DEFINE_OPERATORS(Size) \ +constexpr Vector(const T scalar = T(0)) { \ + for(std::size_t i = 0; i < Size; i++) \ + data[i] = scalar; \ +} \ +constexpr T& operator[](const size_t index) { \ + return data[index]; \ +} \ +constexpr T operator[](const size_t index) const { \ + return data[index]; \ +} \ +constexpr Vector& operator+=(const Vector rhs) { \ + for(std::size_t i = 0; i < Size; i++)\ + data[i] += rhs[i]; \ + return *this; \ +} \ +constexpr Vector& operator-=(const Vector rhs) { \ + for(std::size_t i = 0; i < Size; i++)\ + data[i] -= rhs[i]; \ + return *this; \ +} \ +constexpr Vector& operator*=(const Vector rhs) { \ + for(std::size_t i = 0; i < Size; i++) \ + data[i] *= rhs[i]; \ + return *this; \ +} \ +constexpr Vector& operator/=(const T scalar) { \ + for(std::size_t i = 0; i < Size; i++) \ + data[i] /= scalar; \ + return *this; \ +} \ +constexpr T* ptr() const { \ + return data.data(); \ +} \ +constexpr T* ptr() { \ + return data.data(); \ +} \ +constexpr Vector operator- () const { \ + Vector vec; \ + for(std::size_t i = 0; i < Size; i++) \ + vec[i] = -data[i]; \ + return vec; \ +} + +template +struct Vector { + std::array data; +}; + +template +struct Vector<2, T> { + constexpr Vector(const T x_, const T y_) { + data[0] = x_; + data[1] = y_; + } + + DEFINE_OPERATORS(2) + + union { + std::array data; + + struct { + T x, y; + }; + }; +}; + +using Vector2 = Vector<2, float>; + +template +struct Vector<3, T> { + constexpr Vector(const T x_, const T y_, const T z_) { + data[0] = x_; + data[1] = y_; + data[2] = z_; + } + + DEFINE_OPERATORS(3) + + union { + std::array data; + + struct { + T x, y, z; + }; + }; +}; + +using Vector3 = Vector<3, float>; + +template +struct alignas(16) Vector<4, T> { + constexpr Vector(const T x_, const T y_, const T z_, const T w_) { + data[0] = x_; + data[1] = y_; + data[2] = z_; + data[3] = w_; + } + + constexpr Vector(const Vector3& v, const float w = 0.0f) : x(v.x), y(v.y), z(v.z), w(w) {} + + DEFINE_OPERATORS(4) + + union { + std::array data; + + struct { + T x, y, z, w; + }; + + struct { + Vector<3, T> xyz; + T padding_xyz; + }; + }; +}; + +using Vector4 = Vector<4, float>; + +template +constexpr inline bool operator==(const Vector lhs, const Vector rhs) { + bool is_equal = true; + for(std::size_t i = 0; i < N; i++) { + if(lhs[i] != rhs[i]) + is_equal = false; + } + + return is_equal; +} + +template +constexpr inline bool operator!=(const Vector lhs, const Vector rhs) { + return !(lhs == rhs); +} + +template +constexpr inline Vector operator-(const Vector lhs, const Vector rhs) { + Vector vec; + for(std::size_t i = 0; i < N; i++) + vec[i] = lhs[i] - rhs[i]; + + return vec; +} + +template +constexpr inline Vector operator+(const Vector lhs, const Vector rhs) { + Vector vec; + for(std::size_t i = 0; i < N; i++) + vec[i] = lhs[i] + rhs[i]; + + return vec; +} + +template +constexpr inline Vector operator*(const Vector lhs, const Vector rhs) { + Vector vec; + for(std::size_t i = 0; i < N; i++) + vec[i] = lhs[i] * rhs[i]; + + return vec; +} + +template +constexpr inline Vector operator*(const Vector lhs, const T scalar) { + Vector vec; + for(std::size_t i = 0; i < N; i++) + vec[i] = lhs[i] * scalar; + + return vec; +} + +template +constexpr inline Vector operator/(const Vector lhs, const Vector rhs) { + Vector vec; + for(std::size_t i = 0; i < N; i++) + vec[i] = lhs[i] / rhs[i]; + + return vec; +} + +template +constexpr inline Vector operator/(const Vector lhs, const T scalar) { + Vector vec; + for(std::size_t i = 0; i < N; i++) + vec[i] = lhs[i] / scalar; + + return vec; +} + +template +constexpr inline T dot(const Vector lhs, const Vector rhs) { + T product = T(0.0); + + for(std::size_t i = 0; i < N; i++) + product += lhs[i] * rhs[i]; + + return product; +} + +template +constexpr inline T length(const Vector vec) { + return sqrtf(dot(vec, vec)); +} + +template +constexpr inline Vector lerp(const Vector a, const Vector b, const T t) { + Vector vec; + for(std::size_t i = 0; i < N; i++) + vec[i] = (T(1) - t) * a[i] + t * b[i]; + + return vec; +} + +template +constexpr inline Vector normalize(const Vector vec) { + Vector result; + + const float len = length(vec); + for(std::size_t i = 0; i < N; i++) + result[i] = vec[i] / len; + + return result; +} + +constexpr inline Vector3 cross(const Vector3 u, const Vector3 v) { + return Vector3(u.y * v.z - u.z * v.y, u.z * v.x - u.x * v.z, u.x * v.y - u.y * v.x); +} + +inline float distance(const Vector3 lhs, const Vector3 rhs) { + const float diffX = lhs.x - rhs.x; + const float diffY = lhs.y - rhs.y; + const float diffZ = lhs.z - rhs.z; + + return std::sqrt((diffX * diffX) + (diffY * diffY) + (diffZ * diffZ)); +} + +template +constexpr inline T norm(const Vector vec) { + T val = T(0); + for(std::size_t i = 0; i < N; i++) + val += abs(vec[i]); + + return sqrtf(dot(vec, vec)); +} diff --git a/engine/math/src/math.cpp b/engine/math/src/math.cpp new file mode 100755 index 0000000..1743d0f --- /dev/null +++ b/engine/math/src/math.cpp @@ -0,0 +1,169 @@ +#include "math.hpp" + +Matrix4x4 matrix_from_quat(const Quaternion quat) { + const float qxx = quat.x * quat.x; + const float qyy = quat.y * quat.y; + const float qzz = quat.z * quat.z; + const float qxz = quat.x * quat.z; + const float qxy = quat.x * quat.y; + const float qyz = quat.y * quat.z; + const float qwx = quat.w * quat.x; + const float qwy = quat.w * quat.y; + const float qwz = quat.w * quat.z; + + Matrix4x4 result(1.0f); + result[0][0] = 1.0f - 2.0f * (qyy + qzz); + result[0][1] = 2.0f * (qxy + qwz); + result[0][2] = 2.0f * (qxz - qwy); + + result[1][0] = 2.0f * (qxy - qwz); + result[1][1] = 1.0f - 2.0f * (qxx + qzz); + result[1][2] = 2.0f * (qyz + qwx); + + result[2][0] = 2.0f * (qxz + qwy); + result[2][1] = 2.0f * (qyz - qwx); + result[2][2] = 1.0f - 2.0f * (qxx + qyy); + + return result; +} + +Quaternion quat_from_matrix(const Matrix3x3 m) { + const float fourXSquaredMinus1 = m[0][0] - m[1][1] - m[2][2]; + const float fourYSquaredMinus1 = m[1][1] - m[0][0] - m[2][2]; + const float fourZSquaredMinus1 = m[2][2] - m[0][0] - m[1][1]; + const float fourWSquaredMinus1 = m[0][0] + m[1][1] + m[2][2]; + + int biggestIndex = 0; + float fourBiggestSquaredMinus1 = fourWSquaredMinus1; + if(fourXSquaredMinus1 > fourBiggestSquaredMinus1) { + fourBiggestSquaredMinus1 = fourXSquaredMinus1; + biggestIndex = 1; + } + + if(fourYSquaredMinus1 > fourBiggestSquaredMinus1) { + fourBiggestSquaredMinus1 = fourYSquaredMinus1; + biggestIndex = 2; + } + + if(fourZSquaredMinus1 > fourBiggestSquaredMinus1) { + fourBiggestSquaredMinus1 = fourZSquaredMinus1; + biggestIndex = 3; + } + + const float biggestVal = sqrt(fourBiggestSquaredMinus1 + 1.0f) * 0.5f; + const float mult = 0.25f / biggestVal; + + switch(biggestIndex) { + case 0: + return Quaternion((m[1][2] - m[2][1]) * mult, (m[2][0] - m[0][2]) * mult, (m[0][1] - m[1][0]) * mult, biggestVal); + case 1: + return Quaternion(biggestVal, (m[0][1] + m[1][0]) * mult, (m[2][0] + m[0][2]) * mult, (m[1][2] - m[2][1]) * mult); + case 2: + return Quaternion((m[0][1] + m[1][0]) * mult, biggestVal, (m[1][2] + m[2][1]) * mult, (m[2][0] - m[0][2]) * mult); + case 3: + return Quaternion((m[2][0] + m[0][2]) * mult, (m[1][2] + m[2][1]) * mult, biggestVal, (m[0][1] - m[1][0]) * mult); + } +} + +Quaternion euler_to_quat(const Vector3 angle) { + const float cy = cosf(angle.z * 0.5f); + const float sy = sinf(angle.z * 0.5f); + const float cr = cosf(angle.x * 0.5f); + const float sr = sinf(angle.x * 0.5f); + const float cp = cosf(angle.y * 0.5f); + const float sp = sinf(angle.y * 0.5f); + + const float cpcy = cp * cy; + const float spcy = sp * cy; + const float cpsy = cp * sy; + const float spsy = sp * sy; + + Quaternion result; + result.w = cr * cpcy + sr * spsy; + result.x = sr * cpcy - cr * spsy; + result.y = cr * spcy + sr * cpsy; + result.z = cr * cpsy - sr * spcy; + + return normalize(result); +} + +Vector3 quat_to_euler(const Quaternion q) { + const float roll = atan2(2.0f * (q.x * q.y + q.w * q.z), q.w * q.w + q.x * q.x - q.y * q.y - q.z * q.z); + + const float y = 2.0f * (q.y * q.z + q.w * q.x); + const float x = q.w * q.w - q.x * q.x - q.y * q.y + q.z * q.z; + + const float pitch = atan2(y, x); + + const float yaw = asinf(-2.0f * (q.x * q.z - q.w * q.y)); + + return Vector3(pitch, yaw, roll); +} + +Matrix4x4 inverse(const Matrix4x4 m) { + const float Coef00 = m[2][2] * m[3][3] - m[3][2] * m[2][3]; + const float Coef02 = m[1][2] * m[3][3] - m[3][2] * m[1][3]; + const float Coef03 = m[1][2] * m[2][3] - m[2][2] * m[1][3]; + + const float Coef04 = m[2][1] * m[3][3] - m[3][1] * m[2][3]; + const float Coef06 = m[1][1] * m[3][3] - m[3][1] * m[1][3]; + const float Coef07 = m[1][1] * m[2][3] - m[2][1] * m[1][3]; + + const float Coef08 = m[2][1] * m[3][2] - m[3][1] * m[2][2]; + const float Coef10 = m[1][1] * m[3][2] - m[3][1] * m[1][2]; + const float Coef11 = m[1][1] * m[2][2] - m[2][1] * m[1][2]; + + const float Coef12 = m[2][0] * m[3][3] - m[3][0] * m[2][3]; + const float Coef14 = m[1][0] * m[3][3] - m[3][0] * m[1][3]; + const float Coef15 = m[1][0] * m[2][3] - m[2][0] * m[1][3]; + + const float Coef16 = m[2][0] * m[3][2] - m[3][0] * m[2][2]; + const float Coef18 = m[1][0] * m[3][2] - m[3][0] * m[1][2]; + const float Coef19 = m[1][0] * m[2][2] - m[2][0] * m[1][2]; + + const float Coef20 = m[2][0] * m[3][1] - m[3][0] * m[2][1]; + const float Coef22 = m[1][0] * m[3][1] - m[3][0] * m[1][1]; + const float Coef23 = m[1][0] * m[2][1] - m[2][0] * m[1][1]; + + const Vector4 Fac0(Coef00, Coef00, Coef02, Coef03); + const Vector4 Fac1(Coef04, Coef04, Coef06, Coef07); + const Vector4 Fac2(Coef08, Coef08, Coef10, Coef11); + const Vector4 Fac3(Coef12, Coef12, Coef14, Coef15); + const Vector4 Fac4(Coef16, Coef16, Coef18, Coef19); + const Vector4 Fac5(Coef20, Coef20, Coef22, Coef23); + + const Vector4 Vec0(m[1][0], m[0][0], m[0][0], m[0][0]); + const Vector4 Vec1(m[1][1], m[0][1], m[0][1], m[0][1]); + const Vector4 Vec2(m[1][2], m[0][2], m[0][2], m[0][2]); + const Vector4 Vec3(m[1][3], m[0][3], m[0][3], m[0][3]); + + const Vector4 Inv0(Vec1 * Fac0 - Vec2 * Fac1 + Vec3 * Fac2); + const Vector4 Inv1(Vec0 * Fac0 - Vec2 * Fac3 + Vec3 * Fac4); + const Vector4 Inv2(Vec0 * Fac1 - Vec1 * Fac3 + Vec3 * Fac5); + const Vector4 Inv3(Vec0 * Fac2 - Vec1 * Fac4 + Vec2 * Fac5); + + const Vector4 SignA(+1, -1, +1, -1); + const Vector4 SignB(-1, +1, -1, +1); + const Matrix4x4 Inverse(Inv0 * SignA, Inv1 * SignB, Inv2 * SignA, Inv3 * SignB); + + const Vector4 Row0(Inverse[0][0], Inverse[1][0], Inverse[2][0], Inverse[3][0]); + + const Vector4 Dot0(m[0] * Row0); + const float Dot1 = (Dot0.x + Dot0.y) + (Dot0.z + Dot0.w); + + const float OneOverDeterminant = 1.0f / Dot1; + + return Inverse * OneOverDeterminant; +} + +Quaternion angle_axis(const float angle, const Vector3 axis) { + const float s = sinf(angle * 0.5f); + + Quaternion result; + result.w = cosf(angle * 0.5f); + result.x = axis.x * s; + result.y = axis.y * s; + result.z = axis.z * s; + + return result; +} diff --git a/engine/math/src/transform.cpp b/engine/math/src/transform.cpp new file mode 100755 index 0000000..ab872cb --- /dev/null +++ b/engine/math/src/transform.cpp @@ -0,0 +1,112 @@ +#include "transform.hpp" + +#include + +#include "math.hpp" + +Matrix4x4 transform::perspective(const float fov, const float aspect, const float zNear) { + const float range = tanf(fov / 2.0f) * zNear; + const float left = -range * aspect; + const float right = range * aspect; + const float bottom = -range; + const float top = range; + + Matrix4x4 result(0.0f); + result[0][0] = (2.0f * zNear) / (right - left); + result[1][1] = (2.0f * zNear) / (top - bottom); + result[2][2] = -1.0f; + result[2][3] = -1.0f; + result[3][2] = -2.0 * zNear; + + return result; +} + +Matrix4x4 transform::orthographic(float left, float right, float bottom, float top, float zNear, float zFar) { + Matrix4x4 result(1.0f); + result[0][0] = 2.0f / (right - left); + result[1][1] = 2.0f / (top - bottom); + result[2][2] = - 1.0f / (zFar - zNear); + result[3][0] = -(right + left) / (right - left); + result[3][1] = -(top + bottom) / (top - bottom); + result[3][2] = - zNear / (zFar - zNear); + + return result; +} + +Matrix4x4 transform::look_at(const Vector3 eye, const Vector3 center, const Vector3 up) { + const Vector3 f = normalize(center - eye); + const Vector3 s = normalize(cross(f, up)); + const Vector3 u = cross(s, f); + + Matrix4x4 result(1.0f); + result[0][0] = s.x; + result[1][0] = s.y; + result[2][0] = s.z; + result[0][1] = u.x; + result[1][1] = u.y; + result[2][1] = u.z; + result[0][2] = -f.x; + result[1][2] = -f.y; + result[2][2] = -f.z; + result[3][0] = -dot(s, eye); + result[3][1] = -dot(u, eye); + result[3][2] = dot(f, eye); + + return result; +} + +Matrix4x4 transform::translate(const Matrix4x4 matrix, const Vector3 translation) { + Matrix4x4 result(1.0f); + result[3] = Vector4(translation, 1.0); + + return matrix * result; +} + +Matrix4x4 transform::rotate(const Matrix4x4 matrix, const float angle, const Vector3 v) { + const float a = angle; + const float c = cosf(a); + const float s = sinf(a); + + const Vector3 axis = normalize(v); + const Vector3 temp = Vector3((1.0f - c) * axis); + + Matrix4x4 Rotate(1.0f); + Rotate[0][0] = c + temp[0] * axis[0]; + Rotate[0][1] = temp[0] * axis[1] + s * axis[2]; + Rotate[0][2] = temp[0] * axis[2] - s * axis[1]; + + Rotate[1][0] = temp[1] * axis[0] - s * axis[2]; + Rotate[1][1] = c + temp[1] * axis[1]; + Rotate[1][2] = temp[1] * axis[2] + s * axis[0]; + + Rotate[2][0] = temp[2] * axis[0] + s * axis[1]; + Rotate[2][1] = temp[2] * axis[1] - s * axis[0]; + Rotate[2][2] = c + temp[2] * axis[2]; + + Matrix4x4 result(1.0f); + result[0] = Rotate[0][0] + Rotate[0][1] + Rotate[0][2]; + result[1] = Rotate[1][0] + Rotate[1][1] + Rotate[1][2]; + result[2] = Rotate[2][0] + Rotate[2][1] + Rotate[2][2]; + + return matrix * result; +} + +Matrix4x4 transform::scale(const Matrix4x4 matrix, const Vector3 scale) { + Matrix4x4 result(1.0f); + result[0][0] = scale.x; + result[1][1] = scale.y; + result[2][2] = scale.z; + + return matrix * result; +} + +Quaternion transform::quat_look_at(const Vector3 eye, const Vector3 center, const Vector3 up) { + const Vector3 direction = normalize(center - eye); + + Matrix3x3 result(1.0f); + result[2] = -direction; + result[0] = cross(up, result[2]); + result[1] = cross(result[2], result[0]); + + return quat_from_matrix(result); +} diff --git a/engine/renderer/CMakeLists.txt b/engine/renderer/CMakeLists.txt new file mode 100755 index 0000000..df1f8c1 --- /dev/null +++ b/engine/renderer/CMakeLists.txt @@ -0,0 +1,110 @@ +set(SRC + include/renderer.hpp + include/font.hpp + include/pass.hpp + include/gaussianhelper.hpp + include/shadowpass.hpp + include/imguipass.hpp + include/smaapass.hpp + include/scenecapture.hpp + include/shadercompiler.hpp + include/DirStackIncluder.h + include/dofpass.hpp + + src/renderer.cpp + src/gaussianhelper.cpp + src/shadowpass.cpp + src/imguipass.cpp + src/smaapass.cpp + src/scenecapture.cpp + src/shadercompiler.cpp + src/dofpass.cpp) + +if(NOT ENABLE_IOS AND NOT ENABLE_TVOS) + find_package(spirv_cross_core REQUIRED) + find_package(spirv_cross_glsl REQUIRED) + find_package(spirv_cross_cpp REQUIRED) + find_package(spirv_cross_msl REQUIRED) + find_package(glslang REQUIRED) + + set(CROSS_LIBS + glslang::glslang + glslang::SPIRV + glslang::OSDependent + glslang::OGLCompiler + glslang::HLSL + spirv-cross-core + spirv-cross-glsl + spirv-cross-cpp + spirv-cross-msl + ) +else() + set(CROSS_LIBS + spirv-cross-core + spirv-cross-glsl + spirv-cross-cpp + spirv-cross-msl + glslang + SPIRV + ) +endif() + +add_library(Renderer STATIC ${SRC}) +target_link_libraries(Renderer + PUBLIC + GFX + Math + PRIVATE + stb + Math + Utility + Core + imgui + SMAA::SMAA + ${CROSS_LIBS}) +target_include_directories(Renderer PUBLIC include) +set_target_properties(Renderer PROPERTIES CXX_STANDARD 17) +target_compile_features(Renderer PUBLIC cxx_std_17) +set_target_properties(Renderer PROPERTIES CXX_EXTENSIONS OFF) + +include(../../cmake/BuildShaders.cmake) + +add_shader(TARGET Renderer + SHADERS + shaders/mesh.vert.nocompile.glsl + shaders/post.vert.glsl + shaders/post.frag.glsl + shaders/text.vert.glsl + shaders/text.frag.glsl + shaders/ui.vert.glsl + shaders/ui.frag.glsl + shaders/imgui.vert.glsl + shaders/imgui.frag.glsl + shaders/debug.vert.glsl + shaders/debug.frag.glsl + shaders/gaussian.vert.glsl + shaders/gaussian.frag.glsl + shaders/shadow.vert.nocompile.glsl + shaders/shadow.frag.glsl + shaders/color.vert.glsl + shaders/color.frag.glsl + shaders/omnishadow.frag.glsl + shaders/edge.vert.glsl + shaders/edge.frag.glsl + shaders/blend.vert.glsl + shaders/blend.frag.glsl + shaders/sky.vert.glsl + shaders/sky.frag.glsl + shaders/billboard.vert.glsl + shaders/billboard.frag.glsl + shaders/scenecapture.vert.nocompile.glsl + shaders/irradiance.vert.glsl + shaders/irradiance.frag.glsl + shaders/filter.vert.glsl + shaders/filter.frag.glsl + shaders/brdf.vert.glsl + shaders/brdf.frag.glsl + shaders/rendering.nocompile.glsl + shaders/common.nocompile.glsl + shaders/dof.vert.glsl + shaders/dof.frag.glsl) diff --git a/engine/renderer/include/DirStackIncluder.h b/engine/renderer/include/DirStackIncluder.h new file mode 100755 index 0000000..6055de1 --- /dev/null +++ b/engine/renderer/include/DirStackIncluder.h @@ -0,0 +1,141 @@ +// +// Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +// Copyright (C) 2017 Google, Inc. +// +// All rights reserved. +// +// 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 3Dlabs Inc. Ltd. nor the names of its +// 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 HOLDERS 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. +// + +#pragma once + +#include +#include +#include +#include + +#include + +#include "file.hpp" + +// Default include class for normal include convention of search backward +// through the stack of active include paths (for nested includes). +// Can be overridden to customize. +class DirStackFileIncluder : public glslang::TShader::Includer { +public: + DirStackFileIncluder() : externalLocalDirectoryCount(0) { } + + virtual IncludeResult* includeLocal(const char* headerName, + const char* includerName, + size_t inclusionDepth) override + { + return readLocalPath(headerName, includerName, (int)inclusionDepth); + } + + virtual IncludeResult* includeSystem(const char* headerName, + const char* /*includerName*/, + size_t /*inclusionDepth*/) override + { + return readSystemPath(headerName); + } + + // Externally set directories. E.g., from a command-line -I. + // - Most-recently pushed are checked first. + // - All these are checked after the parse-time stack of local directories + // is checked. + // - This only applies to the "local" form of #include. + // - Makes its own copy of the path. + virtual void pushExternalLocalDirectory(const std::string& dir) + { + directoryStack.push_back(dir); + externalLocalDirectoryCount = (int)directoryStack.size(); + } + + virtual void releaseInclude(IncludeResult* result) override + { + if (result != nullptr) { + delete [] static_cast(result->userData); + delete result; + } + } + + virtual ~DirStackFileIncluder() override { } + +protected: + typedef char tUserDataElement; + std::vector directoryStack; + int externalLocalDirectoryCount; + + // Search for a valid "local" path based on combining the stack of include + // directories and the nominal name of the header. + virtual IncludeResult* readLocalPath(const char* headerName, const char* includerName, int depth) + { + // Discard popped include directories, and + // initialize when at parse-time first level. + directoryStack.resize(depth + externalLocalDirectoryCount); + if (depth == 1) + directoryStack.back() = getDirectory(includerName); + + // Find a directory that works, using a reverse search of the include stack. + for (auto it = directoryStack.rbegin(); it != directoryStack.rend(); ++it) { + std::string path = *it + '/' + headerName; + std::replace(path.begin(), path.end(), '\\', '/'); + std::ifstream file(path, std::ios_base::binary | std::ios_base::ate); + if (file) { + directoryStack.push_back(getDirectory(path)); + return newIncludeResult(path, file, (int)file.tellg()); + } + } + + return nullptr; + } + + // Search for a valid path. + // Not implemented yet; returning nullptr signals failure to find. + virtual IncludeResult* readSystemPath(const char* /*headerName*/) const + { + return nullptr; + } + + // Do actual reading of the file, filling in a new include result. + virtual IncludeResult* newIncludeResult(const std::string& path, std::ifstream& file, int length) const + { + char* content = new tUserDataElement [length]; + file.seekg(0, file.beg); + file.read(content, length); + return new IncludeResult(path, content, length, content); + } + + // If no path markers, return current working directory. + // Otherwise, strip file name and return path leading up to it. + virtual std::string getDirectory(const std::string) const { + return file::get_domain_path(file::Domain::Internal); + } +}; diff --git a/engine/renderer/include/dofpass.hpp b/engine/renderer/include/dofpass.hpp new file mode 100755 index 0000000..2ec8e78 --- /dev/null +++ b/engine/renderer/include/dofpass.hpp @@ -0,0 +1,22 @@ +#pragma once + +class GFX; +class GFXCommandBuffer; +class GFXFramebuffer; +class GFXPipeline; +class GFXRenderPass; +class GFXTexture; +class Scene; +class Renderer; + +class DoFPass { +public: + DoFPass(GFX* gfx, Renderer* renderer); + + void render(GFXCommandBuffer* command_buffer, Scene& scene); + +private: + Renderer* renderer = nullptr; + + GFXPipeline* pipeline = nullptr; +}; diff --git a/engine/renderer/include/font.hpp b/engine/renderer/include/font.hpp new file mode 100755 index 0000000..b176e07 --- /dev/null +++ b/engine/renderer/include/font.hpp @@ -0,0 +1,34 @@ +#pragma once + +constexpr auto numGlyphs = 95, maxInstances = 11395; +constexpr auto fontSize = 0; + +struct FontChar { + unsigned short x0, y0, x1, y1; + float xoff, yoff, xadvance; + float xoff2, yoff2; +}; + +struct Font { + int width, height; + int ascent, descent, gap; + FontChar sizes[2][numGlyphs]; + float ascentSizes[2]; +}; + +inline Font font; + +inline float get_string_width(std::string s) { + float t = 0.0f; + for(size_t i = 0; i < s.length(); i++) { + auto index = s[i] - 32; + + t += font.sizes[fontSize][index].xadvance; + } + + return t; +} + +inline float get_font_height() { + return font.ascentSizes[fontSize]; +} diff --git a/engine/renderer/include/gaussianhelper.hpp b/engine/renderer/include/gaussianhelper.hpp new file mode 100755 index 0000000..89d1e5b --- /dev/null +++ b/engine/renderer/include/gaussianhelper.hpp @@ -0,0 +1,27 @@ +#pragma once + +#include "common.hpp" + +class GFX; +class GFXCommandBuffer; +class GFXFramebuffer; +class GFXPipeline; +class GFXRenderPass; +class GFXTexture; + +class GaussianHelper { +public: + GaussianHelper(GFX* gfx, const Extent extent); + + GFXTexture* render(GFXCommandBuffer* commandBuffer,GFXTexture* source); + + GFXPipeline* pipeline = nullptr; + + GFXRenderPass* renderPass = nullptr; + + GFXTexture* texA = nullptr, *texB = nullptr; + GFXFramebuffer* fboA = nullptr, *fboB = nullptr; + +private: + Extent extent; +}; diff --git a/engine/renderer/include/imguipass.hpp b/engine/renderer/include/imguipass.hpp new file mode 100755 index 0000000..f3da4b7 --- /dev/null +++ b/engine/renderer/include/imguipass.hpp @@ -0,0 +1,35 @@ +#pragma once + +#include +#include + +#include "pass.hpp" + +class GFXBuffer; +class GFXCommandBuffer; +class GFXPipeline; +class GFXTexture; +struct ImDrawData; + +class ImGuiPass : public Pass { +public: + void initialize() override; + + void resize(const Extent extent) override; + + void render_post(GFXCommandBuffer* command_buffer, const int index) override; + +private: + void load_font(const std::string_view filename); + void create_font_texture(); + void update_buffers(const ImDrawData& draw_data); + + GFXPipeline* pipeline = nullptr; + GFXTexture* font_texture = nullptr; + + GFXBuffer* vertex_buffer = nullptr; + int current_vertex_size = 0; + + GFXBuffer* index_buffer = nullptr; + int current_index_size = 0; +}; diff --git a/engine/renderer/include/pass.hpp b/engine/renderer/include/pass.hpp new file mode 100755 index 0000000..889b50a --- /dev/null +++ b/engine/renderer/include/pass.hpp @@ -0,0 +1,28 @@ +#pragma once + +#include "common.hpp" + +class GFXCommandBuffer; +class Scene; + +enum class PassTextureType { + SelectionSobel +}; + +class GFXTexture; + +class Pass { +public: + virtual ~Pass() {} + + virtual void initialize() {} + + virtual void resize([[maybe_unused]] const Extent extent) {} + + virtual void render_scene([[maybe_unused]] Scene& scene, + [[maybe_unused]] GFXCommandBuffer* commandBuffer) {} + virtual void render_post([[maybe_unused]] GFXCommandBuffer* commandBuffer, + [[maybe_unused]] int index) {} + + virtual GFXTexture* get_requested_texture([[maybe_unused]] PassTextureType type) { return nullptr; } +}; diff --git a/engine/renderer/include/renderer.hpp b/engine/renderer/include/renderer.hpp new file mode 100755 index 0000000..4c27b8f --- /dev/null +++ b/engine/renderer/include/renderer.hpp @@ -0,0 +1,230 @@ +#pragma once + +#include +#include +#include "file.hpp" +#include "pass.hpp" +#include "matrix.hpp" +#include "object.hpp" +#include "dofpass.hpp" +#include "common.hpp" + +namespace ui { + class Screen; +} + +class GFX; +class GFXBuffer; +class GFXCommandBuffer; +class GFXFramebuffer; +class GFXPipeline; +class GFXRenderPass; +class GFXTexture; +class SMAAPass; +class ShadowPass; +class SceneCapture; +class GaussianHelper; +class DoFPass; + +class Scene; +struct MeshData; +struct Camera; + +constexpr int max_scene_materials = 25, max_scene_lights = 25; + +struct RenderScreenOptions { + bool render_world = false; + Matrix4x4 mvp; +}; + +constexpr int brdf_resolution = 512; + +constexpr bool default_enable_aa = true; + +enum class ShadowFilter { + None, + PCF, + PCSS +}; + +#if defined(PLATFORM_TVOS) || defined(PLATFORM_IOS) +constexpr bool default_enable_ibl = false; +constexpr bool default_enable_normal_mapping = false; +constexpr bool default_enable_point_shadows = false; +constexpr ShadowFilter default_shadow_filter = ShadowFilter::PCF; +constexpr int default_shadow_resolution = 1024; +#else +constexpr bool default_enable_ibl = true; +constexpr bool default_enable_normal_mapping = true; +constexpr bool default_enable_point_shadows = true; +constexpr ShadowFilter default_shadow_filter = ShadowFilter::PCSS; +constexpr int default_shadow_resolution = 2048; +#endif + +struct RenderOptions { + bool dynamic_resolution = false; + double render_scale = 1.0f; + + int shadow_resolution = default_shadow_resolution; + + bool enable_aa = default_enable_aa; + bool enable_ibl = default_enable_ibl; + bool enable_normal_mapping = default_enable_normal_mapping; + bool enable_normal_shadowing = default_enable_normal_mapping; + bool enable_point_shadows = default_enable_point_shadows; + ShadowFilter shadow_filter = default_shadow_filter; + bool enable_extra_passes = true; + bool enable_frustum_culling = true; +}; + +inline RenderOptions render_options; + +class Material; + +class Renderer { +public: + Renderer(GFX* gfx, const bool enable_imgui = true); + + void resize(const Extent extent); + void resize_viewport(const Extent extent); + + void set_screen(ui::Screen* screen); + void init_screen(ui::Screen* screen); + void update_screen(); + + void startCrossfade(); + void startSceneBlur(); + void stopSceneBlur(); + + float fade = 0.0f; + bool fading = false; + + bool blurring = false; + bool hasToStore = true; + int blurFrame = 0; + + GFXTexture* blurStore = nullptr; + + struct ControllerContinuity { + int elementOffset = 0; + }; + + void render(Scene* scene, int index); + + void render_screen(GFXCommandBuffer* commandBuffer, ui::Screen* screen, ControllerContinuity& continuity, RenderScreenOptions options = RenderScreenOptions()); + void render_camera(GFXCommandBuffer* command_buffer, Scene& scene, Object camera_object, Camera& camera, ControllerContinuity& continuity); + + void create_mesh_pipeline(Material& material); + + // passes + template + T* addPass(Args&&... args) { + auto t = std::make_unique(args...); + t->initialize(); + + return static_cast(passes.emplace_back(std::move(t)).get()); + } + + GFXTexture* get_requested_texture(PassTextureType type) { + for(auto& pass : passes) { + auto texture = pass->get_requested_texture(type); + if(texture != nullptr) + return texture; + } + + return nullptr; + } + + GFXRenderPass* getOffscreenRenderPass() const { + return offscreenRenderPass; + } + + GFXTexture* offscreenColorTexture = nullptr; + GFXTexture* offscreenDepthTexture = nullptr; + + GFXTexture* viewportColorTexture = nullptr; + + bool viewport_mode = false; + Extent viewport_extent; + + bool gui_only_mode = false; + + Extent get_extent() const { + return viewport_mode ? viewport_extent : extent; + } + + Extent get_render_extent() const { + const auto extent = get_extent(); + + return {static_cast(std::max(int(extent.width * render_options.render_scale), 1)), + static_cast(std::max(int(extent.height * render_options.render_scale), 1))}; + } + + std::unique_ptr shadow_pass; + std::unique_ptr scene_capture; + + /* + This is applied to most framebuffer pass projection-view matrices. + For example, under Metal the y is flipped because the framebuffer sample coordinates are flipped. + */ + Matrix4x4 correction_matrix; + + GFXTexture* dummyTexture = nullptr; + GFXRenderPass* unormRenderPass = nullptr; + GFXPipeline* renderToUnormTexturePipeline = nullptr; + GFXRenderPass* viewportRenderPass = nullptr; + +private: + void createDummyTexture(); + void createOffscreenResources(); + void createMeshPipeline(); + void createPostPipeline(); + void createFontPipeline(); + void createSkyPipeline(); + void createUIPipeline(); + void createGaussianResources(); + void createBRDF(); + + GFX* gfx = nullptr; + Extent extent; + + ui::Screen* current_screen = nullptr; + + // offscreen + GFXTexture* offscreenBackTexture = nullptr; + GFXFramebuffer* offscreenFramebuffer = nullptr; + GFXRenderPass* offscreenRenderPass = nullptr; + + GFXFramebuffer* viewportFramebuffer = nullptr; + + // mesh + GFXBuffer* sceneBuffer = nullptr; + + // sky + GFXPipeline* skyPipeline = nullptr; + + // post + GFXPipeline* postPipeline = nullptr; + GFXPipeline* renderToTexturePipeline = nullptr; + GFXPipeline* renderToViewportPipeline = nullptr; + + // font + GFXTexture* fontTexture = nullptr; + GFXPipeline* textPipeline, *worldTextPipeline = nullptr; + int instanceAlignment = 0; + + // brdf + GFXPipeline* brdfPipeline = nullptr; + GFXTexture* brdfTexture = nullptr; + GFXFramebuffer* brdfFramebuffer = nullptr; + GFXRenderPass* brdfRenderPass = nullptr; + + // general ui + GFXPipeline* generalPipeline, *worldGeneralPipeline = nullptr; + + std::unique_ptr smaaPass; + std::unique_ptr gHelper; + std::unique_ptr dofPass; + + std::vector> passes; +}; diff --git a/engine/renderer/include/scenecapture.hpp b/engine/renderer/include/scenecapture.hpp new file mode 100755 index 0000000..5eebf62 --- /dev/null +++ b/engine/renderer/include/scenecapture.hpp @@ -0,0 +1,39 @@ +#pragma once + +#include "math.hpp" + +class GFX; +class GFXCommandBuffer; +class GFXFramebuffer; +class GFXPipeline; +class GFXRenderPass; +class GFXTexture; +class GFXBuffer; +class Scene; + +const int scene_cubemap_resolution = 1024; +const int irradiance_cubemap_resolution = 32; + +class SceneCapture { +public: + SceneCapture(GFX* gfx); + + void create_scene_resources(Scene& scene); + + void render(GFXCommandBuffer* command_buffer, Scene* scene); + + GFXPipeline* irradiancePipeline, *prefilterPipeline = nullptr, *skyPipeline = nullptr; + GFXRenderPass* renderPass = nullptr, *irradianceRenderPass = nullptr; + + GFXTexture* environmentCube = nullptr; + + GFXTexture* offscreenTexture = nullptr, *irradianceOffscreenTexture = nullptr, *prefilteredOffscreenTexture = nullptr; + GFXTexture* offscreenDepth = nullptr; + GFXFramebuffer* offscreenFramebuffer = nullptr, *irradianceFramebuffer = nullptr, *prefilteredFramebuffer = nullptr; + + GFXBuffer* sceneBuffer = nullptr; + + void createSkyResources(); + void createIrradianceResources(); + void createPrefilterResources(); +}; diff --git a/engine/renderer/include/shadercompiler.hpp b/engine/renderer/include/shadercompiler.hpp new file mode 100755 index 0000000..c7bf18f --- /dev/null +++ b/engine/renderer/include/shadercompiler.hpp @@ -0,0 +1,27 @@ +#pragma once + +#include + +#include "gfx.hpp" + +class Material; + +constexpr int position_buffer_index = 2; +constexpr int normal_buffer_index = 3; +constexpr int texcoord_buffer_index = 4; +constexpr int tangent_buffer_index = 5; +constexpr int bitangent_buffer_index = 6; +constexpr int bone_buffer_index = 7; + +class ShaderCompiler { +public: + GFXPipeline* create_static_pipeline(GFXGraphicsPipelineCreateInfo createInfo, bool positions_only = false, bool cubemap = false); + GFXPipeline* create_skinned_pipeline(GFXGraphicsPipelineCreateInfo createInfo, bool positions_only = false); + + // generates static and skinned versions of the pipeline provided + std::tuple create_pipeline_permutations(GFXGraphicsPipelineCreateInfo& createInfo, bool positions_only = false); + + std::string compile_material_fragment(Material& material, bool use_ibl = true); +}; + +static ShaderCompiler shader_compiler; diff --git a/engine/renderer/include/shadowpass.hpp b/engine/renderer/include/shadowpass.hpp new file mode 100755 index 0000000..f227d4e --- /dev/null +++ b/engine/renderer/include/shadowpass.hpp @@ -0,0 +1,60 @@ +#pragma once + +#include "math.hpp" +#include "object.hpp" +#include "components.hpp" + +class GFX; +class GFXCommandBuffer; +class GFXFramebuffer; +class GFXPipeline; +class GFXRenderPass; +class GFXTexture; +class GFXSampler; +class Scene; +struct CameraFrustum; + +class ShadowPass { +public: + ShadowPass(GFX* gfx); + + void create_scene_resources(Scene& scene); + + void render(GFXCommandBuffer* command_buffer, Scene& scene); + + GFXSampler* shadow_sampler = nullptr; + GFXSampler* pcf_sampler = nullptr; + +private: + void render_meshes(GFXCommandBuffer* command_buffer, Scene& scene, const Matrix4x4 light_matrix, const Matrix4x4 model, const Vector3 light_position, const Light::Type type, const CameraFrustum& frustum); + + void render_sun(GFXCommandBuffer* command_buffer, Scene& scene, Object light_object, Light& light); + void render_spot(GFXCommandBuffer* command_buffer, Scene& scene, Object light_object, Light& light); + void render_point(GFXCommandBuffer* command_buffer, Scene& scene, Object light_object, Light& light); + + int last_point_light = 0; + int last_spot_light = 0; + + void create_render_passes(); + void create_pipelines(); + void create_offscreen_resources(); + + GFXRenderPass* render_pass = nullptr; + GFXRenderPass* cube_render_pass = nullptr; + + GFXTexture* offscreen_color_texture = nullptr; + GFXTexture* offscreen_depth = nullptr; + GFXFramebuffer* offscreen_framebuffer = nullptr; + + // sun + GFXPipeline* static_sun_pipeline = nullptr; + GFXPipeline* skinned_sun_pipeline = nullptr; + + // spot + GFXPipeline* static_spot_pipeline = nullptr; + GFXPipeline* skinned_spot_pipeline = nullptr; + + // point + GFXPipeline* static_point_pipeline = nullptr; + GFXPipeline* skinned_point_pipeline = nullptr; +}; diff --git a/engine/renderer/include/smaapass.hpp b/engine/renderer/include/smaapass.hpp new file mode 100755 index 0000000..1821f58 --- /dev/null +++ b/engine/renderer/include/smaapass.hpp @@ -0,0 +1,43 @@ +#pragma once + +#include "common.hpp" + +class Scene; +class GFX; +class GFXCommandBuffer; +class GFXFramebuffer; +class GFXPipeline; +class GFXRenderPass; +class GFXTexture; +class Renderer; + +class SMAAPass { +public: + SMAAPass(GFX* gfx, Renderer* renderer); + + void render(GFXCommandBuffer* command_buffer); + + GFXTexture* edge_texture = nullptr; + GFXTexture* blend_texture = nullptr; + +private: + void create_textures(); + void create_render_pass(); + void create_pipelines(); + void create_offscreen_resources(); + + Extent extent; + Renderer* renderer = nullptr; + + GFXTexture* area_image = nullptr; + GFXTexture* search_image = nullptr; + + GFXRenderPass* render_pass = nullptr; + + GFXPipeline* edge_pipeline = nullptr; + GFXPipeline* blend_pipeline = nullptr; + + GFXFramebuffer* edge_framebuffer = nullptr; + + GFXFramebuffer* blend_framebuffer = nullptr; +}; diff --git a/engine/renderer/src/dofpass.cpp b/engine/renderer/src/dofpass.cpp new file mode 100755 index 0000000..e6e7052 --- /dev/null +++ b/engine/renderer/src/dofpass.cpp @@ -0,0 +1,46 @@ +#include "dofpass.hpp" + +#include "renderer.hpp" +#include "gfx.hpp" +#include "gfx_commandbuffer.hpp" +#include "engine.hpp" + +AssetPtr aperture_texture; + +DoFPass::DoFPass(GFX* gfx, Renderer* renderer) : renderer(renderer) { + aperture_texture = assetm->get(file::app_domain / "textures/aperture.png"); + + const auto extent = renderer->get_render_extent(); + + GFXShaderConstant width_constant = {}; + width_constant.value = extent.width; + + GFXShaderConstant height_constant = {}; + height_constant.index = 1; + height_constant.value = extent.height; + + GFXGraphicsPipelineCreateInfo create_info = {}; + create_info.shaders.vertex_path = "dof.vert"; + create_info.shaders.vertex_constants = {width_constant, height_constant}; + create_info.shaders.fragment_path = "dof.frag"; + create_info.render_pass = renderer->viewportRenderPass; + create_info.blending.enable_blending = true; + create_info.blending.src_rgb = GFXBlendFactor::SrcAlpha; + create_info.blending.dst_rgb = GFXBlendFactor::OneMinusSrcAlpha; + create_info.blending.src_alpha = GFXBlendFactor::SrcAlpha; + create_info.blending.dst_alpha = GFXBlendFactor::OneMinusSrcAlpha; + + pipeline = gfx->create_graphics_pipeline(create_info); +} + +void DoFPass::render(GFXCommandBuffer* command_buffer, Scene&) { + command_buffer->set_pipeline(pipeline); + + command_buffer->bind_texture(renderer->offscreenColorTexture, 0); + command_buffer->bind_texture(renderer->offscreenDepthTexture, 1); + command_buffer->bind_texture(aperture_texture->handle, 2); + + const auto extent = renderer->get_render_extent(); + + command_buffer->draw(0, 4, 0, extent.width * extent.height); +} diff --git a/engine/renderer/src/gaussianhelper.cpp b/engine/renderer/src/gaussianhelper.cpp new file mode 100755 index 0000000..4158563 --- /dev/null +++ b/engine/renderer/src/gaussianhelper.cpp @@ -0,0 +1,83 @@ +#include "gaussianhelper.hpp" + +#include "gfx_commandbuffer.hpp" +#include "gfx.hpp" + +GaussianHelper::GaussianHelper(GFX* gfx, const Extent extent) : extent(extent) { + // render pass + GFXRenderPassCreateInfo renderPassInfo = {}; + renderPassInfo.attachments.push_back(GFXPixelFormat::RGBA_32F); + + renderPass = gfx->create_render_pass(renderPassInfo); + + // pipeline + GFXGraphicsPipelineCreateInfo pipelineInfo = {}; + pipelineInfo.label = "Gaussian"; + pipelineInfo.shaders.vertex_path = "gaussian.vert"; + pipelineInfo.shaders.fragment_path = "gaussian.frag"; + + pipelineInfo.rasterization.primitive_type = GFXPrimitiveType::TriangleStrip; + + pipelineInfo.shader_input.bindings = { + {0, GFXBindingType::Texture}, + {1, GFXBindingType::PushConstant} + }; + + pipelineInfo.shader_input.push_constants = { + {4, 0} + }; + + pipelineInfo.render_pass = renderPass; + + pipeline = gfx->create_graphics_pipeline(pipelineInfo); + + // resources + GFXTextureCreateInfo textureInfo = {}; + textureInfo.width = extent.width; + textureInfo.height = extent.height; + textureInfo.format = GFXPixelFormat::RGBA_32F; + textureInfo.usage = GFXTextureUsage::Attachment | GFXTextureUsage::Sampled; + textureInfo.samplingMode = SamplingMode::ClampToEdge; + + texA = gfx->create_texture(textureInfo); + texB = gfx->create_texture(textureInfo); + + GFXFramebufferCreateInfo info; + info.attachments = {texA}; + info.render_pass = renderPass; + + fboA = gfx->create_framebuffer(info); + + info.attachments = {texB}; + + fboB = gfx->create_framebuffer(info); +} + +GFXTexture* GaussianHelper::render(GFXCommandBuffer* commandBuffer, GFXTexture* source) { + bool horizontal = true, first_iteration = true; + int amount = 10; + for(int i = 0; i < amount; i++) { + GFXRenderPassBeginInfo info = {}; + info.framebuffer = horizontal ? fboA : fboB; + info.render_pass = renderPass; + info.render_area.extent = extent; + + commandBuffer->set_render_pass(info); + + commandBuffer->set_pipeline(pipeline); + + commandBuffer->memory_barrier(); + + int h = static_cast(horizontal); + commandBuffer->set_push_constant(&h, sizeof(int)); + commandBuffer->bind_texture(first_iteration ? source : (horizontal ? texB : texA), 0); + + commandBuffer->draw(0, 4, 0, 1); + + horizontal = !horizontal; + if (first_iteration) + first_iteration = false; + } + + return (horizontal ? texB : texA); +} diff --git a/engine/renderer/src/imguipass.cpp b/engine/renderer/src/imguipass.cpp new file mode 100755 index 0000000..9cc1bf8 --- /dev/null +++ b/engine/renderer/src/imguipass.cpp @@ -0,0 +1,213 @@ +#include "imguipass.hpp" + +#include + +#include "engine.hpp" +#include "file.hpp" +#include "gfx.hpp" +#include "gfx_commandbuffer.hpp" +#include "log.hpp" +#include "assertions.hpp" + +void ImGuiPass::initialize() { + ImGuiIO& io = ImGui::GetIO(); + io.BackendRendererName = "GFX"; + io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; + io.BackendFlags |= ImGuiBackendFlags_RendererHasViewports; + +#if !defined(PLATFORM_TVOS) && !defined(PLATFORM_IOS) + load_font("OpenSans-Regular.ttf"); +#endif + create_font_texture(); +} + +void ImGuiPass::resize(const Extent extent) { + GFXGraphicsPipelineCreateInfo createInfo; + createInfo.label = "ImGui"; + createInfo.shaders.vertex_path = "imgui.vert"; + createInfo.shaders.fragment_path = "imgui.frag"; + + GFXVertexInput vertexInput = {}; + vertexInput.stride = sizeof(ImDrawVert); + + createInfo.vertex_input.inputs.push_back(vertexInput); + + GFXVertexAttribute positionAttribute = {}; + positionAttribute.format = GFXVertexFormat::FLOAT2; + positionAttribute.offset = offsetof(ImDrawVert, pos); + + createInfo.vertex_input.attributes.push_back(positionAttribute); + + GFXVertexAttribute uvAttribute = {}; + uvAttribute.location = 1; + uvAttribute.format = GFXVertexFormat::FLOAT2; + uvAttribute.offset = offsetof(ImDrawVert, uv); + + createInfo.vertex_input.attributes.push_back(uvAttribute); + + GFXVertexAttribute colAttribute = {}; + colAttribute.location = 2; + colAttribute.format = GFXVertexFormat::UNORM4; + colAttribute.offset = offsetof(ImDrawVert, col); + + createInfo.vertex_input.attributes.push_back(colAttribute); + + createInfo.blending.enable_blending = true; + createInfo.blending.src_rgb = GFXBlendFactor::SrcAlpha; + createInfo.blending.src_alpha= GFXBlendFactor::SrcAlpha; + createInfo.blending.dst_rgb = GFXBlendFactor::OneMinusSrcAlpha; + createInfo.blending.dst_alpha = GFXBlendFactor::OneMinusSrcAlpha; + + createInfo.shader_input.push_constants = { + {sizeof(Matrix4x4), 0} + }; + + createInfo.shader_input.bindings = { + {1, GFXBindingType::PushConstant}, + {2, GFXBindingType::Texture} + }; + + pipeline = engine->get_gfx()->create_graphics_pipeline(createInfo); +} + +void ImGuiPass::render_post(GFXCommandBuffer* command_buffer, const int index) { + ImDrawData* draw_data = nullptr; + if(index == 0) { + draw_data = ImGui::GetDrawData(); + } else { + auto& io = ImGui::GetPlatformIO(); + for(int i = 1; i < io.Viewports.size(); i++) { + if((io.Viewports[i]->Flags & ImGuiViewportFlags_Minimized) == 0) + if(*(int*)io.Viewports[i]->PlatformHandle == index) + draw_data = io.Viewports[i]->DrawData; + } + } + + Expects(draw_data != nullptr); + + const int framebuffer_width = static_cast(draw_data->DisplaySize.x * draw_data->FramebufferScale.x); + const int framebuffer_height = static_cast(draw_data->DisplaySize.y * draw_data->FramebufferScale.y); + + Expects(framebuffer_width > 0); + Expects(framebuffer_height > 0); + + update_buffers(*draw_data); + + command_buffer->set_pipeline(pipeline); + + command_buffer->set_vertex_buffer(vertex_buffer, 0, 0); + command_buffer->set_index_buffer(index_buffer, IndexType::UINT16); + + const Matrix4x4 projection = transform::orthographic(draw_data->DisplayPos.x, + draw_data->DisplayPos.x + draw_data->DisplaySize.x, + draw_data->DisplayPos.y + draw_data->DisplaySize.y, + draw_data->DisplayPos.y, + 0.0f, + 1.0f); + + command_buffer->set_push_constant(&projection, sizeof(Matrix4x4)); + + const ImVec2 clip_offset = draw_data->DisplayPos; + const ImVec2 clip_scale = draw_data->FramebufferScale; + + int vertex_offset = 0; + int index_offset = 0; + for(int n = 0; n < draw_data->CmdListsCount; n++) { + const ImDrawList* cmd_list = draw_data->CmdLists[n]; + for(int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) { + const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i]; + + if(pcmd->TextureId != nullptr) + command_buffer->bind_texture((GFXTexture*)pcmd->TextureId, 2); + + if(pcmd->UserCallback != nullptr) { + pcmd->UserCallback(cmd_list, pcmd); + } else { + ImVec4 clip_rect = {}; + clip_rect.x = (pcmd->ClipRect.x - clip_offset.x) * clip_scale.x; + clip_rect.y = (pcmd->ClipRect.y - clip_offset.y) * clip_scale.y; + clip_rect.z = (pcmd->ClipRect.z - clip_offset.x) * clip_scale.x; + clip_rect.w = (pcmd->ClipRect.w - clip_offset.y) * clip_scale.y; + + if(clip_rect.x < framebuffer_width && clip_rect.y < framebuffer_height && clip_rect.z >= 0.0f && clip_rect.w >= 0.0f) { + command_buffer->draw_indexed(pcmd->ElemCount, + (index_offset + pcmd->IdxOffset), + (vertex_offset + pcmd->VtxOffset)); + } + } + } + + index_offset += cmd_list->IdxBuffer.Size; + vertex_offset += cmd_list->VtxBuffer.Size; + } +} + +void ImGuiPass::load_font(const std::string_view filename) { + Expects(!filename.empty()); + + ImGuiIO& io = ImGui::GetIO(); + +#if !defined(PLATFORM_IOS) || !defined(PLATFORM_TVOS) + if(io.Fonts->Fonts.empty()) { + auto file = file::open(file::app_domain / filename); + if(file != std::nullopt) { + file->read_all(); + + io.Fonts->AddFontFromMemoryTTF(file->cast_data(), file->size(), 15.0 * platform::get_window_dpi(0)); + ImGui::GetIO().FontGlobalScale = 1.0 / platform::get_window_dpi(0); + } else { + console::error(System::Renderer, "Failed to load font file for imgui!"); + return; + } + } +#endif +} + +void ImGuiPass::create_font_texture() { + ImGuiIO& io = ImGui::GetIO(); + + unsigned char* pixels = nullptr; + int width = -1, height = -1; + io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); + + GFXTextureCreateInfo createInfo = {}; + createInfo.width = width; + createInfo.height = height; + createInfo.format = GFXPixelFormat::RGBA8_UNORM; + createInfo.usage = GFXTextureUsage::Sampled; + + font_texture = engine->get_gfx()->create_texture(createInfo); + engine->get_gfx()->copy_texture(font_texture, pixels, width * height * 4); + + io.Fonts->TexID = reinterpret_cast(font_texture); +} + +void ImGuiPass::update_buffers(const ImDrawData& draw_data) { + const int new_vertex_size = draw_data.TotalVtxCount * sizeof(ImDrawVert); + const int new_index_size = draw_data.TotalIdxCount * sizeof(ImDrawIdx); + + Expects(new_vertex_size > 0); + Expects(new_index_size > 0); + + if(vertex_buffer == nullptr || current_vertex_size < new_vertex_size) { + vertex_buffer = engine->get_gfx()->create_buffer(nullptr, new_vertex_size, true, GFXBufferUsage::Vertex); + current_vertex_size = new_vertex_size; + } + + if(index_buffer == nullptr || current_index_size < new_index_size) { + index_buffer = engine->get_gfx()->create_buffer(nullptr, new_index_size, true, GFXBufferUsage::Index); + current_index_size = new_index_size; + } + + int vertex_offset = 0; + int index_offset = 0; + for(int i = 0; i < draw_data.CmdListsCount; i++) { + const ImDrawList* cmd_list = draw_data.CmdLists[i]; + + engine->get_gfx()->copy_buffer(vertex_buffer, cmd_list->VtxBuffer.Data, vertex_offset, cmd_list->VtxBuffer.Size * sizeof(ImDrawVert)); + engine->get_gfx()->copy_buffer(index_buffer, cmd_list->IdxBuffer.Data, index_offset, cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx)); + + vertex_offset += cmd_list->VtxBuffer.Size * sizeof(ImDrawVert); + index_offset += cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx); + } +} diff --git a/engine/renderer/src/renderer.cpp b/engine/renderer/src/renderer.cpp new file mode 100755 index 0000000..8074eb3 --- /dev/null +++ b/engine/renderer/src/renderer.cpp @@ -0,0 +1,997 @@ +#include "renderer.hpp" + +#include + +#include "gfx_commandbuffer.hpp" +#include "math.hpp" +#include "screen.hpp" +#include "file.hpp" +#include "scene.hpp" +#include "font.hpp" +#include "vector.hpp" +#include "engine.hpp" +#include "imguipass.hpp" +#include "gfx.hpp" +#include "log.hpp" +#include "gaussianhelper.hpp" +#include "pass.hpp" +#include "shadowpass.hpp" +#include "smaapass.hpp" +#include "scenecapture.hpp" +#include "shadercompiler.hpp" +#include "assertions.hpp" +#include "dofpass.hpp" +#include "frustum.hpp" + +struct ElementInstance { + Vector4 color; + uint32_t position = 0, size = 0; + uint32_t padding[2]; +}; + +struct GlyphInstance { + uint32_t position = 0, index = 0, instance = 0; +}; + +struct GylphMetric { + uint32_t x0_y0, x1_y1; + float xoff, yoff; + float xoff2, yoff2; +}; + +struct StringInstance { + uint32_t xy; +}; + +struct SceneMaterial { + Vector4 color, info; +}; + +struct SceneLight { + Vector4 positionType; + Vector4 directionPower; + Vector4 colorSize; + Vector4 shadowsEnable; +}; + +struct SceneProbe { + Vector4 position, size; +}; + +struct SceneInformation { + Vector4 options; + Vector4 camPos; + Matrix4x4 vp, lightspace; + Matrix4x4 spotLightSpaces[max_spot_shadows]; + SceneMaterial materials[max_scene_materials]; + SceneLight lights[max_scene_lights]; + SceneProbe probes[max_environment_probes]; + int numLights; + int p[3]; +}; + +struct PostPushConstants { + Vector4 viewport; + Vector4 options; +}; + +struct UIPushConstant { + Vector2 screenSize; + Matrix4x4 mvp; +}; + +Renderer::Renderer(GFX* gfx, const bool enable_imgui) : gfx(gfx) { + Expects(gfx != nullptr); + + createDummyTexture(); + + shadow_pass = std::make_unique(gfx); + scene_capture = std::make_unique(gfx); + + if(enable_imgui) + addPass(); + + if(gfx->required_context() == GFXContext::Metal) + correction_matrix[1][1] *= -1.0f; + + createBRDF(); +} + +void Renderer::resize(const Extent extent) { + this->extent = extent; + + if(!viewport_mode) { + createOffscreenResources(); + createMeshPipeline(); + createPostPipeline(); + createFontPipeline(); + createSkyPipeline(); + createUIPipeline(); + createGaussianResources(); + + smaaPass = std::make_unique(gfx, this); + dofPass = std::make_unique(gfx, this); + } + + for(auto& pass : passes) + pass->resize(extent); +} + +void Renderer::resize_viewport(const Extent extent) { + this->viewport_extent = extent; + + createOffscreenResources(); + createMeshPipeline(); + createPostPipeline(); + createFontPipeline(); + createSkyPipeline(); + createUIPipeline(); + createGaussianResources(); + + smaaPass = std::make_unique(gfx, this); + dofPass = std::make_unique(gfx, this); + + for(auto& pass : passes) + pass->resize(get_render_extent()); +} + +void Renderer::set_screen(ui::Screen* screen) { + Expects(screen != nullptr); + + current_screen = screen; + + init_screen(screen); + + update_screen(); +} + +void Renderer::init_screen(ui::Screen* screen) { + Expects(screen != nullptr); + + std::array metrics; + for(int i = 0; i < numGlyphs; i++) { + GylphMetric& metric = metrics[i]; + metric.x0_y0 = utility::pack_u32(font.sizes[fontSize][i].x0, font.sizes[fontSize][i].y0); + metric.x1_y1 = utility::pack_u32(font.sizes[fontSize][i].x1, font.sizes[fontSize][i].y1); + metric.xoff = font.sizes[fontSize][i].xoff; + metric.yoff = font.sizes[fontSize][i].yoff; + metric.xoff2 = font.sizes[fontSize][i].xoff2; + metric.yoff2 = font.sizes[fontSize][i].yoff2; + } + + screen->glyph_buffer = gfx->create_buffer(nullptr, instanceAlignment + (sizeof(GylphMetric) * numGlyphs), false, GFXBufferUsage::Storage); + + gfx->copy_buffer(screen->glyph_buffer, metrics.data(), instanceAlignment, sizeof(GylphMetric) * numGlyphs); + + screen->elements_buffer = gfx->create_buffer(nullptr, sizeof(ElementInstance) * 50, true, GFXBufferUsage::Storage); + + screen->instance_buffer = gfx->create_buffer(nullptr, sizeof(StringInstance) * 50, true, GFXBufferUsage::Storage); +} + +void Renderer::update_screen() { + if(current_screen != nullptr) { + if(current_screen->blurs_background) { + startSceneBlur(); + } else { + stopSceneBlur(); + } + + for(auto& element : current_screen->elements) { + if(!element.background.image.empty()) + element.background.texture = assetm->get(file::app_domain / element.background.image); + } + } +} + +void Renderer::startCrossfade() { + // copy the current screen + gfx->copy_texture(offscreenColorTexture, offscreenBackTexture); + + fading = true; + fade = 1.0f; +} + +void Renderer::startSceneBlur() { + blurring = true; + hasToStore = true; +} + +void Renderer::stopSceneBlur() { + blurring = false; +} + +void Renderer::render(Scene* scene, int index) { + GFXCommandBuffer* commandbuffer = engine->get_gfx()->acquire_command_buffer(); + + const auto extent = get_extent(); + const auto render_extent = get_render_extent(); + + if(!gui_only_mode) { + commandbuffer->push_group("Scene Rendering"); + + GFXRenderPassBeginInfo beginInfo = {}; + beginInfo.framebuffer = offscreenFramebuffer; + beginInfo.render_pass = offscreenRenderPass; + beginInfo.render_area.extent = render_extent; + + bool hasToRender = true; + if(blurring && !hasToStore) + hasToRender = false; + + ControllerContinuity continuity; + + if(scene != nullptr && hasToRender) { + commandbuffer->push_group("Shadow Rendering"); + + shadow_pass->render(commandbuffer, *scene); + + commandbuffer->pop_group(); + + if(render_options.enable_ibl) { + commandbuffer->push_group("Scene Capture"); + scene_capture->render(commandbuffer, scene); + commandbuffer->pop_group(); + } + + commandbuffer->set_render_pass(beginInfo); + + const auto& cameras = scene->get_all(); + for(auto& [obj, camera] : cameras) { + const int actual_width = render_extent.width / cameras.size(); + + camera.perspective = transform::perspective(radians(camera.fov), static_cast(actual_width) / static_cast(render_extent.height), camera.near); + camera.view = inverse(scene->get(obj).model); + + Viewport viewport = {}; + viewport.x = (actual_width * 0); + viewport.width = actual_width; + viewport.height = render_extent.height; + + commandbuffer->set_viewport(viewport); + + commandbuffer->push_group("render camera"); + + render_camera(commandbuffer, *scene, obj, camera, continuity); + + commandbuffer->pop_group(); + } + } + + commandbuffer->pop_group(); + + commandbuffer->push_group("SMAA"); + + smaaPass->render(commandbuffer); + + commandbuffer->pop_group(); + + if(!viewport_mode) { + beginInfo.framebuffer = nullptr; + beginInfo.render_pass = nullptr; + } else { + beginInfo.framebuffer = viewportFramebuffer; + beginInfo.render_pass = viewportRenderPass; + } + + commandbuffer->set_render_pass(beginInfo); + + Viewport viewport = {}; + viewport.width = render_extent.width; + viewport.height = render_extent.height; + + commandbuffer->set_viewport(viewport); + + commandbuffer->push_group("Post Processing"); + + commandbuffer->set_pipeline(viewport_mode ? renderToViewportPipeline : postPipeline); + commandbuffer->bind_texture(offscreenColorTexture, 1); + commandbuffer->bind_texture(offscreenBackTexture, 2); + commandbuffer->bind_texture(smaaPass->blend_texture, 3); + + if(auto texture = get_requested_texture(PassTextureType::SelectionSobel)) { + commandbuffer->bind_texture(texture, 4); + } else { + commandbuffer->bind_texture(dummyTexture, 4); + } + + PostPushConstants pc; + pc.options.x = render_options.enable_aa; + pc.options.y = fade; + pc.options.z = 1.0; + + const auto [width, height] = render_extent; + pc.viewport = Vector4(1.0f / static_cast(width), 1.0f / static_cast(height), width, height); + + commandbuffer->set_push_constant(&pc, sizeof(PostPushConstants)); + + if(fading) { + if(fade > 0.0f) + fade -= 0.1f; + else if(fade <= 0.0f) { + fading = false; + fade = 0.0f; + } + } + + commandbuffer->draw(0, 4, 0, 1); + + commandbuffer->pop_group(); + + if(current_screen != nullptr) + render_screen(commandbuffer, current_screen, continuity); + } else { + GFXRenderPassBeginInfo beginInfo = {}; + beginInfo.render_area.extent = extent; + + commandbuffer->set_render_pass(beginInfo); + + Viewport viewport = {}; + viewport.width = extent.width; + viewport.height = extent.height; + + commandbuffer->set_viewport(viewport); + } + + commandbuffer->push_group("Extra Passes"); + + for(auto& pass : passes) + pass->render_post(commandbuffer, index); + + commandbuffer->pop_group(); + + gfx->submit(commandbuffer, index); +} + +void Renderer::render_camera(GFXCommandBuffer* command_buffer, Scene& scene, Object camera_object, Camera& camera, ControllerContinuity& continuity) { + // frustum test + const auto frustum = normalize_frustum(camera_extract_frustum(scene, camera_object)); + + const auto extent = get_render_extent(); + + SceneInformation sceneInfo = {}; + sceneInfo.lightspace = scene.lightSpace; + sceneInfo.options = Vector4(1, 0, 0, 0); + sceneInfo.camPos = scene.get(camera_object).get_world_position(); + sceneInfo.camPos.w = 2.0f * camera.near * std::tanf(camera.fov * 0.5f) * (static_cast(extent.width) / static_cast(extent.height)); + sceneInfo.vp = camera.perspective * correction_matrix * camera.view; + + for(const auto [obj, light] : scene.get_all()) { + SceneLight sl; + sl.positionType = Vector4(scene.get(obj).get_world_position(), (int)light.type); + + Vector3 front = Vector3(0.0f, 0.0f, 1.0f) * scene.get(obj).rotation; + + sl.directionPower = Vector4(-front, light.power); + sl.colorSize = Vector4(light.color, radians(light.spot_size)); + sl.shadowsEnable = Vector4(light.enable_shadows, radians(light.size), 0, 0); + + sceneInfo.lights[sceneInfo.numLights++] = sl; + } + + for(int i = 0; i < max_spot_shadows; i++) + sceneInfo.spotLightSpaces[i] = scene.spotLightSpaces[i]; + + int last_probe = 0; + for(const auto [obj, probe] : scene.get_all()) { + SceneProbe p; + p.position = Vector4(scene.get(obj).position, probe.is_sized ? 1.0f : 2.0f); + p.size = Vector4(probe.size, probe.intensity); + + sceneInfo.probes[last_probe++] = p; + } + + int numMaterialsInBuffer = 0; + std::map material_indices; + + const auto& meshes = scene.get_all(); + for(const auto [obj, mesh] : meshes) { + if(!mesh.mesh) + continue; + + if(mesh.materials.empty()) + continue; + + for(auto& material : mesh.materials) { + if(!material) + continue; + + if(material->static_pipeline == nullptr || material->skinned_pipeline == nullptr) + create_mesh_pipeline(*material.handle); + + if(!material_indices.count(material.handle)) { + material_indices[material.handle] = numMaterialsInBuffer++; + } + } + + struct PushConstant { + Matrix4x4 m; + int s; + } pc; + + pc.m = scene.get(obj).model; + + command_buffer->set_vertex_buffer(mesh.mesh->position_buffer, 0, position_buffer_index); + command_buffer->set_vertex_buffer(mesh.mesh->normal_buffer, 0, normal_buffer_index); + command_buffer->set_vertex_buffer(mesh.mesh->texture_coord_buffer, 0, texcoord_buffer_index); + command_buffer->set_vertex_buffer(mesh.mesh->tangent_buffer, 0, tangent_buffer_index); + command_buffer->set_vertex_buffer(mesh.mesh->bitangent_buffer, 0, bitangent_buffer_index); + + if(!mesh.mesh->bones.empty()) + command_buffer->set_vertex_buffer(mesh.mesh->bone_buffer, 0, bone_buffer_index); + + command_buffer->set_index_buffer(mesh.mesh->index_buffer, IndexType::UINT32); + + command_buffer->bind_shader_buffer(sceneBuffer, 0, 1, sizeof(SceneInformation)); + + command_buffer->bind_texture(scene.depthTexture, 2); + command_buffer->bind_texture(scene.pointLightArray, 3); + command_buffer->bind_sampler(shadow_pass->shadow_sampler, 4); + command_buffer->bind_sampler(shadow_pass->pcf_sampler, 5); + command_buffer->bind_texture(scene.spotLightArray, 6); + command_buffer->bind_texture(scene.irradianceCubeArray, 7); + command_buffer->bind_texture(scene.prefilteredCubeArray, 8); + command_buffer->bind_texture(brdfTexture, 9); + + for(const auto& part : mesh.mesh->parts) { + const int material_index = part.material_override == -1 ? 0 : part.material_override; + + if(material_index >= mesh.materials.size()) + continue; + + if(mesh.materials[material_index].handle == nullptr || mesh.materials[material_index]->static_pipeline == nullptr) + continue; + + if(render_options.enable_frustum_culling && !test_aabb_frustum(frustum, get_aabb_for_part(scene.get(obj), part))) { + console::debug(System::Renderer, "Culled {}!", scene.get(obj).name); + continue; + } + + command_buffer->set_pipeline(mesh.mesh->bones.empty() ? mesh.materials[material_index]->static_pipeline : mesh.materials[material_index]->skinned_pipeline); + + if(!mesh.mesh->bones.empty()) + command_buffer->bind_shader_buffer(part.bone_batrix_buffer, 0, 14, sizeof(Matrix4x4) * 128); + + pc.s = material_indices[mesh.materials[material_index].handle]; + command_buffer->set_push_constant(&pc, sizeof(PushConstant)); + + for(const auto& [index, texture] : mesh.materials[material_index]->bound_textures) { + GFXTexture* texture_to_bind = dummyTexture; + if(texture) + texture_to_bind = texture->handle; + + command_buffer->bind_texture(texture_to_bind, index); + } + + command_buffer->draw_indexed(part.index_count, part.index_offset, part.vertex_offset); + } + } + + const auto& screens = scene.get_all(); + for(const auto& [obj, screen] : screens) { + if(!screen.screen) + continue; + + RenderScreenOptions options = {}; + options.render_world = true; + options.mvp = camera.perspective * camera.view * correction_matrix * scene.get(obj).model; + + render_screen(command_buffer, screen.screen, continuity, options); + } + + struct SkyPushConstant { + Matrix4x4 view; + Vector4 aspectFovY; + Vector4 sunPosition; + } pc; + + pc.view = matrix_from_quat(scene.get(camera_object).rotation) * correction_matrix; + pc.aspectFovY = Vector4(static_cast(extent.width) / static_cast(extent.height), radians(camera.fov), 0, 0); + + for(const auto& [obj, light] : scene.get_all()) { + if(light.type == Light::Type::Sun) + pc.sunPosition = Vector4(scene.get(obj).get_world_position()); + } + + command_buffer->set_pipeline(skyPipeline); + + command_buffer->set_push_constant(&pc, sizeof(SkyPushConstant)); + + command_buffer->draw(0, 4, 0, 1); + + if(render_options.enable_extra_passes) { + for(auto& pass : passes) + pass->render_scene(scene, command_buffer); + } + + gfx->copy_buffer(sceneBuffer, &sceneInfo, 0, sizeof(SceneInformation)); +} + +void Renderer::render_screen(GFXCommandBuffer *commandbuffer, ui::Screen* screen, ControllerContinuity& continuity, RenderScreenOptions options) { + std::array instances; + std::vector elementInstances; + std::array stringInstances; + + int stringLen = 0; + int numElements = 0; + + for(auto [i, element] : utility::enumerate(screen->elements)) { + if(!element.visible) + continue; + + ElementInstance instance; + + instance.position = utility::pack_u32(utility::to_fixed(element.absolute_x), utility::to_fixed(element.absolute_y)); + instance.size = utility::pack_u32(utility::to_fixed(element.absolute_width), utility::to_fixed(element.absolute_height)); + instance.color[0] = element.background.color.r; + instance.color[1] = element.background.color.g; + instance.color[2] = element.background.color.b; + instance.color[3] = element.background.color.a; + + elementInstances.push_back(instance); + + stringInstances[i].xy = utility::pack_u32(utility::to_fixed(element.absolute_x + element.text_x), utility::to_fixed(element.absolute_y + element.text_y)); + + float advance = 0.0f; + float yadvance = 0.0f; + + bool do_y_advance = false; // so we can not advance the text by a space if we're wrapping per word + + for(size_t j = 0; j < element.text.length(); j++) { + auto index = element.text[j] - 32; + + if(do_y_advance) { + advance = 0.0f; + yadvance += font.ascentSizes[fontSize]; + do_y_advance = false; + } + + if(element.wrap_text) { + if(element.text[j] == ' ') { + std::string t; + float temp_advance = 0.0f; + for(size_t k = j + 1; k < element.text.length() + j; k++) { + t += element.text[k]; + auto index = element.text[k] - 32; + temp_advance += font.sizes[fontSize][index].xadvance; + + if(element.text[k] == ' ') + break; + } + + if((temp_advance + advance) >= element.absolute_width) + do_y_advance = true; + } + } + + GlyphInstance& instance = instances[stringLen + j]; + instance.position = utility::pack_u32(utility::to_fixed(advance), utility::to_fixed(yadvance)); + instance.index = utility::pack_u32(index, 0); + instance.instance = i; + + advance += font.sizes[fontSize][index].xadvance; + + if(element.text[j] == '\n') { + advance = 0.0f; + yadvance += font.ascentSizes[fontSize]; + } + } + + stringLen += static_cast(element.text.length()); + numElements++; + } + + gfx->copy_buffer(screen->glyph_buffer, instances.data(), 0, instanceAlignment); + gfx->copy_buffer(screen->instance_buffer, stringInstances.data(), 0, sizeof(StringInstance) * 50); + gfx->copy_buffer(screen->elements_buffer, elementInstances.data(), sizeof(ElementInstance) * continuity.elementOffset, sizeof(ElementInstance) * elementInstances.size()); + + const auto extent = get_render_extent(); + const Vector2 windowSize = {static_cast(extent.width), static_cast(extent.height)}; + + for(auto [i, element] : utility::enumerate(screen->elements)) { + if(!element.visible) + continue; + + if(element.background.texture) { + commandbuffer->bind_texture(element.background.texture->handle, 2); + } else { + commandbuffer->bind_texture(dummyTexture, 2); + } + + UIPushConstant pc; + pc.screenSize = windowSize; + + if(options.render_world) { + commandbuffer->set_pipeline(worldGeneralPipeline); + pc.mvp = options.mvp; + } else { + commandbuffer->set_pipeline(generalPipeline); + } + + commandbuffer->set_push_constant(&pc, sizeof(UIPushConstant)); + + commandbuffer->bind_shader_buffer(screen->elements_buffer, 0, 0, sizeof(ElementInstance) * 50); + commandbuffer->draw(0, 4, i + continuity.elementOffset, 1); + } + + UIPushConstant pc; + pc.screenSize = windowSize; + + if(options.render_world) { + commandbuffer->set_pipeline(worldTextPipeline); + pc.mvp = options.mvp; + } else { + commandbuffer->set_pipeline(textPipeline); + } + + commandbuffer->set_push_constant(&pc, sizeof(UIPushConstant)); + + commandbuffer->bind_shader_buffer(screen->glyph_buffer, 0, 0, instanceAlignment); + commandbuffer->bind_shader_buffer(screen->glyph_buffer, instanceAlignment, 1, sizeof(GylphMetric) * numGlyphs); + commandbuffer->bind_shader_buffer(screen->instance_buffer, 0, 2, sizeof(StringInstance) * 50); + commandbuffer->bind_texture(fontTexture, 3); + + if(stringLen > 0) + commandbuffer->draw(0, 4, 0, stringLen); + + continuity.elementOffset += numElements; +} + +void Renderer::create_mesh_pipeline(Material& material) { + GFXShaderConstant materials_constant = {}; + materials_constant.type = GFXShaderConstant::Type::Integer; + materials_constant.value = max_scene_materials; + + GFXShaderConstant lights_constant = {}; + lights_constant.index = 1; + lights_constant.type = GFXShaderConstant::Type::Integer; + lights_constant.value = max_scene_lights; + + GFXShaderConstant spot_lights_constant = {}; + spot_lights_constant.index = 2; + spot_lights_constant.type = GFXShaderConstant::Type::Integer; + spot_lights_constant.value = max_spot_shadows; + + GFXShaderConstant probes_constant = {}; + probes_constant.index = 3; + probes_constant.type = GFXShaderConstant::Type::Integer; + probes_constant.value = max_environment_probes; + + GFXGraphicsPipelineCreateInfo pipelineInfo = {}; + pipelineInfo.label = "Mesh"; + pipelineInfo.shaders.vertex_path = "mesh.vert"; + pipelineInfo.shaders.fragment_path = "mesh.frag"; + + pipelineInfo.shaders.vertex_constants = {materials_constant, lights_constant, spot_lights_constant, probes_constant}; + pipelineInfo.shaders.fragment_constants = {materials_constant, lights_constant, spot_lights_constant, probes_constant}; + + struct PushConstant { + Matrix4x4 m; + int s; + }; + + pipelineInfo.shader_input.push_constants = { + {sizeof(PushConstant), 0} + }; + + pipelineInfo.shader_input.bindings = { + {1, GFXBindingType::StorageBuffer}, + {0, GFXBindingType::PushConstant}, + {2, GFXBindingType::Texture}, + {3, GFXBindingType::Texture}, + {4, GFXBindingType::Texture}, + {5, GFXBindingType::Texture}, + {6, GFXBindingType::Texture}, + {7, GFXBindingType::Texture} + }; + + pipelineInfo.render_pass = offscreenRenderPass; + pipelineInfo.depth.depth_mode = GFXDepthMode::Less; + pipelineInfo.rasterization.culling_mode = GFXCullingMode::Backface; + //pipelineInfo.blending.enable_blending = true; + pipelineInfo.blending.src_rgb = GFXBlendFactor::SrcAlpha; + pipelineInfo.blending.dst_rgb = GFXBlendFactor::OneMinusSrcAlpha; + + pipelineInfo.shaders.fragment_src = shader_compiler.compile_material_fragment(material); + pipelineInfo.shaders.fragment_path = ""; + + auto [static_pipeline, skinned_pipeline] = shader_compiler.create_pipeline_permutations(pipelineInfo); + + material.static_pipeline = static_pipeline; + material.skinned_pipeline = skinned_pipeline; + + pipelineInfo.render_pass = scene_capture->renderPass; + + pipelineInfo.shaders.fragment_src = shader_compiler.compile_material_fragment(material, false); // scene capture does not use IBL + + material.capture_pipeline = shader_compiler.create_static_pipeline(pipelineInfo, false, true); +} + +void Renderer::createDummyTexture() { + GFXTextureCreateInfo createInfo = {}; + createInfo.width = 1; + createInfo.height = 1; + createInfo.format = GFXPixelFormat::R8G8B8A8_UNORM; + createInfo.usage = GFXTextureUsage::Sampled; + + dummyTexture = gfx->create_texture(createInfo); + + uint8_t tex[4] = {0, 0, 0, 0}; + + gfx->copy_texture(dummyTexture, tex, sizeof(tex)); +} + +void Renderer::createOffscreenResources() { + GFXRenderPassCreateInfo renderPassInfo = {}; + renderPassInfo.attachments.push_back(GFXPixelFormat::RGBA_32F); + renderPassInfo.attachments.push_back(GFXPixelFormat::DEPTH_32F); + + offscreenRenderPass = gfx->create_render_pass(renderPassInfo); + + renderPassInfo = {}; + renderPassInfo.attachments = {GFXPixelFormat::RGBA8_UNORM}; + + unormRenderPass = gfx->create_render_pass(renderPassInfo); + + const auto extent = get_render_extent(); + + GFXTextureCreateInfo textureInfo = {}; + textureInfo.width = extent.width; + textureInfo.height = extent.height; + textureInfo.format = GFXPixelFormat::RGBA_32F; + textureInfo.usage = GFXTextureUsage::Attachment | GFXTextureUsage::Sampled; + textureInfo.samplingMode = SamplingMode::ClampToEdge; + + offscreenColorTexture = gfx->create_texture(textureInfo); + offscreenBackTexture = gfx->create_texture(textureInfo); + + textureInfo.format = GFXPixelFormat::DEPTH_32F; + + offscreenDepthTexture = gfx->create_texture(textureInfo); + + GFXFramebufferCreateInfo framebufferInfo = {}; + framebufferInfo.render_pass = offscreenRenderPass; + framebufferInfo.attachments.push_back(offscreenColorTexture); + framebufferInfo.attachments.push_back(offscreenDepthTexture); + + offscreenFramebuffer = gfx->create_framebuffer(framebufferInfo); + + if(viewport_mode) { + GFXRenderPassCreateInfo renderPassInfo = {}; + renderPassInfo.attachments.push_back(GFXPixelFormat::RGBA8_UNORM); + + viewportRenderPass = gfx->create_render_pass(renderPassInfo); + + GFXTextureCreateInfo textureInfo = {}; + textureInfo.width = extent.width; + textureInfo.height = extent.height; + textureInfo.format = GFXPixelFormat::RGBA8_UNORM; + textureInfo.usage = GFXTextureUsage::Attachment | GFXTextureUsage::Sampled; + textureInfo.samplingMode = SamplingMode::ClampToEdge; + + viewportColorTexture = gfx->create_texture(textureInfo); + + framebufferInfo.render_pass = viewportRenderPass; + framebufferInfo.attachments = {viewportColorTexture}; + + viewportFramebuffer = gfx->create_framebuffer(framebufferInfo); + } +} + +void Renderer::createMeshPipeline() { + sceneBuffer = gfx->create_buffer(nullptr, sizeof(SceneInformation), true, GFXBufferUsage::Storage); +} + +void Renderer::createPostPipeline() { + GFXGraphicsPipelineCreateInfo pipelineInfo = {}; + pipelineInfo.label = "Post"; + + pipelineInfo.shaders.vertex_path = "post.vert"; + pipelineInfo.shaders.fragment_path = "post.frag"; + + pipelineInfo.shader_input.bindings = { + {4, GFXBindingType::PushConstant}, + {1, GFXBindingType::Texture}, + {2, GFXBindingType::Texture}, + {3, GFXBindingType::Texture} + }; + + pipelineInfo.shader_input.push_constants = { + {sizeof(PostPushConstants), 0} + }; + + postPipeline = gfx->create_graphics_pipeline(pipelineInfo); + + pipelineInfo.label = "Render to Texture"; + pipelineInfo.render_pass = offscreenRenderPass; + + renderToTexturePipeline = gfx->create_graphics_pipeline(pipelineInfo); + + pipelineInfo.label = "Render to Texture (Unorm)"; + pipelineInfo.render_pass = unormRenderPass; + + renderToUnormTexturePipeline = gfx->create_graphics_pipeline(pipelineInfo); + + pipelineInfo.label = "Render to Viewport"; + pipelineInfo.render_pass = viewportRenderPass; + + renderToViewportPipeline = gfx->create_graphics_pipeline(pipelineInfo); +} + +void Renderer::createFontPipeline() { + auto file = file::open(file::app_domain / "font.fp", true); + if(file == std::nullopt) { + console::error(System::Renderer, "Failed to load font file!"); + return; + } + + file->read(&font); + + std::vector bitmap(font.width * font.height); + file->read(bitmap.data(), font.width * font.height); + + instanceAlignment = (int)gfx->get_alignment(sizeof(GlyphInstance) * maxInstances); + + GFXGraphicsPipelineCreateInfo pipelineInfo = {}; + pipelineInfo.label = "Text"; + + pipelineInfo.shaders.vertex_path = "text.vert"; + pipelineInfo.shaders.fragment_path = "text.frag"; + + pipelineInfo.rasterization.primitive_type = GFXPrimitiveType::TriangleStrip; + + pipelineInfo.blending.enable_blending = true; + pipelineInfo.blending.src_rgb = GFXBlendFactor::SrcAlpha; + pipelineInfo.blending.dst_rgb = GFXBlendFactor::OneMinusSrcColor; + + pipelineInfo.shader_input.bindings = { + {4, GFXBindingType::PushConstant}, + {0, GFXBindingType::StorageBuffer}, + {1, GFXBindingType::StorageBuffer}, + {2, GFXBindingType::StorageBuffer}, + {3, GFXBindingType::Texture} + }; + + pipelineInfo.shader_input.push_constants = { + {sizeof(UIPushConstant), 0} + }; + + textPipeline = gfx->create_graphics_pipeline(pipelineInfo); + + pipelineInfo.render_pass = offscreenRenderPass; + pipelineInfo.label = "Text World"; + pipelineInfo.depth.depth_mode = GFXDepthMode::LessOrEqual; + + worldTextPipeline = gfx->create_graphics_pipeline(pipelineInfo); + + GFXTextureCreateInfo textureInfo = {}; + textureInfo.width = font.width; + textureInfo.height = font.height; + textureInfo.format = GFXPixelFormat::R8_UNORM; + textureInfo.usage = GFXTextureUsage::Sampled; + + fontTexture = gfx->create_texture(textureInfo); + + gfx->copy_texture(fontTexture, bitmap.data(), font.width * font.height); +} + +void Renderer::createSkyPipeline() { + GFXGraphicsPipelineCreateInfo pipelineInfo = {}; + pipelineInfo.label = "Sky"; + pipelineInfo.render_pass = offscreenRenderPass; + + pipelineInfo.shaders.vertex_path = "sky.vert"; + pipelineInfo.shaders.fragment_path = "sky.frag"; + + pipelineInfo.shader_input.bindings = { + {1, GFXBindingType::PushConstant} + }; + + pipelineInfo.shader_input.push_constants = { + {sizeof(Matrix4x4) + sizeof(Vector4) + sizeof(Vector4), 0} + }; + + pipelineInfo.depth.depth_mode = GFXDepthMode::LessOrEqual; + + skyPipeline = gfx->create_graphics_pipeline(pipelineInfo); +} + +void Renderer::createUIPipeline() { + GFXGraphicsPipelineCreateInfo pipelineInfo = {}; + pipelineInfo.label = "UI"; + + pipelineInfo.shaders.vertex_path = "ui.vert"; + pipelineInfo.shaders.fragment_path = "ui.frag"; + + pipelineInfo.rasterization.primitive_type = GFXPrimitiveType::TriangleStrip; + + pipelineInfo.blending.enable_blending = true; + pipelineInfo.blending.src_rgb = GFXBlendFactor::SrcAlpha; + pipelineInfo.blending.dst_rgb = GFXBlendFactor::OneMinusSrcAlpha; + + pipelineInfo.shader_input.bindings = { + {1, GFXBindingType::PushConstant}, + {0, GFXBindingType::StorageBuffer}, + {2, GFXBindingType::Texture} + }; + + pipelineInfo.shader_input.push_constants = { + {sizeof(UIPushConstant), 0} + }; + + generalPipeline = gfx->create_graphics_pipeline(pipelineInfo); + + pipelineInfo.label = "UI World"; + pipelineInfo.render_pass = offscreenRenderPass; + pipelineInfo.depth.depth_mode = GFXDepthMode::LessOrEqual; + + worldGeneralPipeline = gfx->create_graphics_pipeline(pipelineInfo); +} + +void Renderer::createGaussianResources() { + const auto extent = get_render_extent(); + + gHelper = std::make_unique(gfx, extent); + + GFXTextureCreateInfo textureInfo = {}; + textureInfo.width = extent.width; + textureInfo.height = extent.height; + textureInfo.format = GFXPixelFormat::RGBA_32F; + textureInfo.usage = GFXTextureUsage::Sampled; + + blurStore = gfx->create_texture(textureInfo); + + hasToStore = true; +} + +void Renderer::createBRDF() { + GFXRenderPassCreateInfo renderPassInfo = {}; + renderPassInfo.attachments.push_back(GFXPixelFormat::R8G8_SFLOAT); + + brdfRenderPass = gfx->create_render_pass(renderPassInfo); + + GFXGraphicsPipelineCreateInfo pipelineInfo = {}; + pipelineInfo.label = "BRDF"; + + pipelineInfo.shaders.vertex_path = "brdf.vert"; + pipelineInfo.shaders.fragment_path = "brdf.frag"; + + pipelineInfo.render_pass = brdfRenderPass; + + brdfPipeline = gfx->create_graphics_pipeline(pipelineInfo); + + GFXTextureCreateInfo textureInfo = {}; + textureInfo.format = GFXPixelFormat::R8G8_SFLOAT; + textureInfo.width = brdf_resolution; + textureInfo.height = brdf_resolution; + textureInfo.usage = GFXTextureUsage::Sampled | GFXTextureUsage::Attachment; + + brdfTexture = gfx->create_texture(textureInfo); + + GFXFramebufferCreateInfo framebufferInfo = {}; + framebufferInfo.attachments = {brdfTexture}; + framebufferInfo.render_pass = brdfRenderPass; + + brdfFramebuffer = gfx->create_framebuffer(framebufferInfo); + + // render + GFXCommandBuffer* command_buffer = gfx->acquire_command_buffer(); + + GFXRenderPassBeginInfo beginInfo = {}; + beginInfo.render_pass = brdfRenderPass; + beginInfo.framebuffer = brdfFramebuffer; + beginInfo.render_area.extent = {brdf_resolution, brdf_resolution}; + + command_buffer->set_render_pass(beginInfo); + + command_buffer->set_pipeline(brdfPipeline); + + Viewport viewport = {}; + viewport.width = brdf_resolution; + viewport.height = brdf_resolution; + + command_buffer->set_viewport(viewport); + + command_buffer->draw(0, 4, 0, 1); + + gfx->submit(command_buffer); +} diff --git a/engine/renderer/src/scenecapture.cpp b/engine/renderer/src/scenecapture.cpp new file mode 100755 index 0000000..151e2bb --- /dev/null +++ b/engine/renderer/src/scenecapture.cpp @@ -0,0 +1,518 @@ +#include "scenecapture.hpp" + +#include "gfx_commandbuffer.hpp" +#include "scene.hpp" +#include "gfx.hpp" +#include "log.hpp" +#include "engine.hpp" +#include "renderer.hpp" +#include "shadowpass.hpp" +#include "shadercompiler.hpp" +#include "frustum.hpp" + +struct PushConstant { + Matrix4x4 m, v; + int s; +}; + +struct SceneMaterial { + Vector4 color, info; +}; + +struct SceneLight { + Vector4 positionType; + Vector4 directionPower; + Vector4 colorSize; + Vector4 shadowsEnable; +}; + +struct SceneProbe { + Vector4 position, size; +}; + +struct SceneInformation { + Vector4 options; + Vector4 camPos; + Matrix4x4 vp, lightspace; + Matrix4x4 spotLightSpaces[max_spot_shadows]; + SceneMaterial materials[max_scene_materials]; + SceneLight lights[max_scene_lights]; + SceneProbe probes[max_environment_probes]; + int numLights; + int p[3]; +}; + +const int mipLevels = 5; + +const std::array sceneTransforms = { + transform::look_at(Vector3(0), Vector3(1.0, 0.0, 0.0), Vector3(0.0, -1.0, 0.0)), + transform::look_at(Vector3(0), Vector3(-1.0, 0.0, 0.0), Vector3(0.0, -1.0, 0.0)), + transform::look_at(Vector3(0), Vector3( 0.0, -1.0, 0.0), Vector3(0.0, 0.0,1.0)), + transform::look_at(Vector3(0), Vector3( 0.0, 1.0, 0.0), Vector3(0.0, 0.0,-1.0)), + transform::look_at(Vector3(0), Vector3( 0.0, 0.0, 1.0), Vector3(0.0, -1.0, 0.0)), + transform::look_at(Vector3(0), Vector3( 0.0, 0.0, -1.0), Vector3(0.0, -1.0, 0.0)) +}; + +inline AssetPtr cubeMesh; + +SceneCapture::SceneCapture(GFX* gfx) { + cubeMesh = assetm->get(file::app_domain / "models/cube.model"); + + // render pass + GFXRenderPassCreateInfo renderPassInfo = {}; + renderPassInfo.attachments.push_back(GFXPixelFormat::R8G8B8A8_UNORM); + renderPassInfo.attachments.push_back(GFXPixelFormat::DEPTH_32F); + + renderPass = gfx->create_render_pass(renderPassInfo); + + GFXTextureCreateInfo textureInfo = {}; + textureInfo.width = scene_cubemap_resolution; + textureInfo.height = scene_cubemap_resolution; + textureInfo.format = GFXPixelFormat::R8G8B8A8_UNORM; + textureInfo.usage = GFXTextureUsage::Attachment; + textureInfo.samplingMode = SamplingMode::ClampToEdge; + + offscreenTexture = gfx->create_texture(textureInfo); + + GFXTextureCreateInfo depthTextureInfo = {}; + depthTextureInfo.width = scene_cubemap_resolution; + depthTextureInfo.height = scene_cubemap_resolution; + depthTextureInfo.format = GFXPixelFormat::DEPTH_32F; + depthTextureInfo.usage = GFXTextureUsage::Attachment; + depthTextureInfo.samplingMode = SamplingMode::ClampToEdge; + + offscreenDepth = gfx->create_texture(depthTextureInfo); + + GFXFramebufferCreateInfo info; + info.attachments = {offscreenTexture, offscreenDepth}; + info.render_pass = renderPass; + + offscreenFramebuffer = gfx->create_framebuffer(info); + + GFXTextureCreateInfo cubeTextureInfo = {}; + cubeTextureInfo.type = GFXTextureType::Cubemap; + cubeTextureInfo.width = scene_cubemap_resolution; + cubeTextureInfo.height = scene_cubemap_resolution; + cubeTextureInfo.format = GFXPixelFormat::R8G8B8A8_UNORM; + cubeTextureInfo.usage = GFXTextureUsage::Sampled; + cubeTextureInfo.samplingMode = SamplingMode::ClampToEdge; + cubeTextureInfo.mip_count = mipLevels; + + environmentCube = gfx->create_texture(cubeTextureInfo); + + sceneBuffer = gfx->create_buffer(nullptr, sizeof(SceneInformation), true, GFXBufferUsage::Storage); + + createSkyResources(); + createIrradianceResources(); + createPrefilterResources(); +} + +void SceneCapture::create_scene_resources(Scene& scene) { + auto gfx = engine->get_gfx(); + + if(gfx->supports_feature(GFXFeature::CubemapArray)) { + GFXTextureCreateInfo cubeTextureInfo = {}; + cubeTextureInfo.type = GFXTextureType::CubemapArray; + cubeTextureInfo.width = irradiance_cubemap_resolution; + cubeTextureInfo.height = irradiance_cubemap_resolution; + cubeTextureInfo.format = GFXPixelFormat::R8G8B8A8_UNORM; + cubeTextureInfo.usage = GFXTextureUsage::Sampled; + cubeTextureInfo.samplingMode = SamplingMode::ClampToEdge; + cubeTextureInfo.array_length = max_environment_probes; + + scene.irradianceCubeArray = gfx->create_texture(cubeTextureInfo); + + cubeTextureInfo = {}; + cubeTextureInfo.type = GFXTextureType::CubemapArray; + cubeTextureInfo.width = scene_cubemap_resolution; + cubeTextureInfo.height = scene_cubemap_resolution; + cubeTextureInfo.format = GFXPixelFormat::R8G8B8A8_UNORM; + cubeTextureInfo.usage = GFXTextureUsage::Sampled; + cubeTextureInfo.samplingMode = SamplingMode::ClampToEdge; + cubeTextureInfo.array_length = max_environment_probes; + cubeTextureInfo.mip_count = mipLevels; + + scene.prefilteredCubeArray = gfx->create_texture(cubeTextureInfo); + } +} + +void SceneCapture::render(GFXCommandBuffer* command_buffer, Scene* scene) { + int last_probe = 0; + auto probes = scene->get_all(); + for(auto [obj, probe] : probes) { + if(last_probe > max_environment_probes) + return; + + if(scene->environment_dirty[last_probe]) { + std::map material_indices; + int numMaterialsInBuffer = 0; + + const Vector3 lightPos = scene->get(obj).get_world_position(); + + const Matrix4x4 projection = transform::perspective(radians(90.0f), 1.0f, 0.1f); + const Matrix4x4 model = transform::translate(Matrix4x4(), Vector3(-lightPos.x, -lightPos.y, -lightPos.z)); + + SceneInformation sceneInfo = {}; + sceneInfo.lightspace = scene->lightSpace; + sceneInfo.numLights = 0; + sceneInfo.camPos = lightPos; + sceneInfo.vp = projection; + + for(const auto [obj, light] : scene->get_all()) { + SceneLight sl; + sl.positionType = Vector4(scene->get(obj).get_world_position(), (int)light.type); + + Vector3 front = Vector3(0.0f, 0.0f, 1.0f) * scene->get(obj).rotation; + + sl.directionPower = Vector4(-front, light.power); + sl.colorSize = Vector4(light.color, radians(light.size)); + sl.shadowsEnable = Vector4(light.enable_shadows, 0, 0, 0); + + sceneInfo.lights[sceneInfo.numLights++] = sl; + } + + for(int i = 0; i < max_spot_shadows; i++) + sceneInfo.spotLightSpaces[i] = scene->spotLightSpaces[i]; + + const auto& meshes = scene->get_all(); + + for(const auto [obj, mesh] : meshes) { + if(!mesh.mesh) + continue; + + if(mesh.materials.empty()) + continue; + + for(const auto& material : mesh.materials) { + if(!material) + continue; + + if(material->static_pipeline == nullptr || material->skinned_pipeline == nullptr) + engine->get_renderer()->create_mesh_pipeline(*material.handle); + + if(!material_indices.count(material.handle)) { + // unused for now + /*sceneInfo.materials[numMaterialsInBuffer].color = material->base_color; + sceneInfo.materials[numMaterialsInBuffer].info[0] = material->metallic; + sceneInfo.materials[numMaterialsInBuffer].info[1] = material->roughness; + sceneInfo.materials[numMaterialsInBuffer].info[2] = radians(material->hue_shift);*/ + + material_indices[material.handle] = numMaterialsInBuffer++; + } + } + } + + const auto render_face = [this, command_buffer, scene, &meshes, &model, &probe = probe](int face) { + const auto frustum = normalize_frustum(extract_frustum(sceneTransforms[face])); + + GFXRenderPassBeginInfo info = {}; + info.framebuffer = offscreenFramebuffer; + info.render_pass = renderPass; + info.render_area.extent = {scene_cubemap_resolution, scene_cubemap_resolution}; + + command_buffer->set_render_pass(info); + + Viewport viewport = {}; + viewport.width = scene_cubemap_resolution; + viewport.height = scene_cubemap_resolution; + + command_buffer->set_viewport(viewport); + + if(probe.is_sized) { + for(const auto [obj, mesh] : meshes) { + if(!mesh.mesh) + continue; + + if(mesh.materials.empty()) + continue; + + PushConstant pc; + pc.m = scene->get(obj).model; + pc.v = sceneTransforms[face] * model; + + command_buffer->set_vertex_buffer(mesh.mesh->position_buffer, 0, position_buffer_index); + command_buffer->set_vertex_buffer(mesh.mesh->normal_buffer, 0, normal_buffer_index); + command_buffer->set_vertex_buffer(mesh.mesh->texture_coord_buffer, 0, texcoord_buffer_index); + command_buffer->set_vertex_buffer(mesh.mesh->tangent_buffer, 0, tangent_buffer_index); + command_buffer->set_vertex_buffer(mesh.mesh->bitangent_buffer, 0, bitangent_buffer_index); + + command_buffer->set_index_buffer(mesh.mesh->index_buffer, IndexType::UINT32); + + command_buffer->bind_shader_buffer(sceneBuffer, 0, 1, sizeof(SceneInformation)); + command_buffer->bind_texture(scene->depthTexture, 2); + command_buffer->bind_texture(scene->pointLightArray, 3); + command_buffer->bind_sampler(engine->get_renderer()->shadow_pass->shadow_sampler, 4); + command_buffer->bind_sampler(engine->get_renderer()->shadow_pass->pcf_sampler, 5); + command_buffer->bind_texture(scene->spotLightArray, 6); + + if(mesh.mesh->bones.empty()) { + for (auto& part : mesh.mesh->parts) { + const int material_index = part.material_override == -1 ? 0 : part.material_override; + + if(material_index >= mesh.materials.size()) + continue; + + if(mesh.materials[material_index].handle == nullptr || mesh.materials[material_index]->static_pipeline == nullptr) + continue; + + if(render_options.enable_frustum_culling && !test_aabb_frustum(frustum, get_aabb_for_part(scene->get(obj), part))) { + console::debug(System::Renderer, "Scene Culled {}!", scene->get(obj).name); + continue; + } + + command_buffer->set_pipeline( mesh.materials[material_index]->capture_pipeline); + + command_buffer->set_push_constant(&pc, sizeof(PushConstant)); + + for(auto& [index, texture] : mesh.materials[material_index]->bound_textures) { + GFXTexture* texture_to_bind = engine->get_renderer()->dummyTexture; + if(texture) + texture_to_bind = texture->handle; + + command_buffer->bind_texture(texture_to_bind, index); + } + + command_buffer->draw_indexed(part.index_count, part.index_offset, part.vertex_offset); + } + } + } + } + + // render sky + struct SkyPushConstant { + Matrix4x4 view; + Vector4 aspectFovY; + Vector4 sunPosition; + } pc; + + pc.view = sceneTransforms[face]; + pc.view[3] = Vector4(0, 0, 0, 1); // zero out translation + pc.aspectFovY = Vector4(1.0f, radians(90.0f), 0, 0); + + for(auto& [obj, light] : scene->get_all()) { + if(light.type == Light::Type::Sun) + pc.sunPosition = Vector4(scene->get(obj).get_world_position()); + } + + command_buffer->set_pipeline(skyPipeline); + + command_buffer->set_push_constant(&pc, sizeof(SkyPushConstant)); + + command_buffer->draw(0, 4, 0, 1); + + command_buffer->copy_texture(offscreenTexture, scene_cubemap_resolution, scene_cubemap_resolution, environmentCube, face, 0, 0); + }; + + engine->get_gfx()->copy_buffer(sceneBuffer, &sceneInfo, 0, sizeof(SceneInformation)); + + for (int face = 0; face < 6; face++) + render_face(face); + + command_buffer->generate_mipmaps(environmentCube, mipLevels); + + // calculate irradiance + const auto convulute_face = [this, scene, command_buffer, &last_probe, projection](int face) { + GFXRenderPassBeginInfo info = {}; + info.framebuffer = irradianceFramebuffer; + info.render_pass = irradianceRenderPass; + info.render_area.extent = {irradiance_cubemap_resolution, irradiance_cubemap_resolution}; + + command_buffer->set_render_pass(info); + + Viewport viewport = {}; + viewport.width = irradiance_cubemap_resolution; + viewport.height = irradiance_cubemap_resolution; + + command_buffer->set_viewport(viewport); + + Matrix4x4 mvp = projection * sceneTransforms[face]; + + command_buffer->set_vertex_buffer(cubeMesh->position_buffer, 0, 0); + command_buffer->set_index_buffer(cubeMesh->index_buffer, IndexType::UINT32); + + command_buffer->set_pipeline(irradiancePipeline); + command_buffer->bind_texture(environmentCube, 2); + command_buffer->set_push_constant(&mvp, sizeof(Matrix4x4)); + + command_buffer->draw_indexed(cubeMesh->num_indices, 0, 0); + + command_buffer->copy_texture(irradianceOffscreenTexture, irradiance_cubemap_resolution, irradiance_cubemap_resolution, scene->irradianceCubeArray, face, last_probe, 0); + }; + + for (int face = 0; face < 6; face++) + convulute_face(face); + + // prefilter + const auto prefilter_face = [this, scene, command_buffer, &last_probe, projection](int face, int mip) { + GFXRenderPassBeginInfo info = {}; + info.framebuffer = prefilteredFramebuffer; + info.render_pass = irradianceRenderPass; + + const uint32_t resolution = scene_cubemap_resolution * std::pow(0.5, mip); + info.render_area.extent = {resolution, resolution}; + + command_buffer->set_render_pass(info); + + Viewport viewport = {}; + viewport.width = resolution; + viewport.height = resolution; + + command_buffer->set_viewport(viewport); + + command_buffer->set_vertex_buffer(cubeMesh->position_buffer, 0, 0); + command_buffer->set_index_buffer(cubeMesh->index_buffer, IndexType::UINT32); + + struct PushConstant { + Matrix4x4 mvp; + float roughness; + } pc; + + pc.mvp = projection * sceneTransforms[face]; + pc.roughness = ((float)mip) / (float)(mipLevels - 1); + + command_buffer->set_pipeline(prefilterPipeline); + command_buffer->bind_texture(environmentCube, 2); + command_buffer->set_push_constant(&pc, sizeof(PushConstant)); + + command_buffer->draw_indexed(cubeMesh->num_indices, 0, 0); + + command_buffer->copy_texture(prefilteredOffscreenTexture, info.render_area.extent.width, info.render_area.extent.height, scene->prefilteredCubeArray, face, last_probe, mip); + }; + + for(int mip = 0; mip < mipLevels; mip++) { + for(int i = 0; i < 6; i++) + prefilter_face(i, mip); + } + + scene->environment_dirty[last_probe] = false; + } + + last_probe++; + } +} + +void SceneCapture::createSkyResources() { + GFXGraphicsPipelineCreateInfo pipelineInfo = {}; + pipelineInfo.label = "Sky"; + pipelineInfo.render_pass = renderPass; + + pipelineInfo.shaders.vertex_path = "sky.vert"; + pipelineInfo.shaders.fragment_path = "sky.frag"; + + pipelineInfo.shader_input.bindings = { + {1, GFXBindingType::PushConstant} + }; + + pipelineInfo.shader_input.push_constants = { + {sizeof(Matrix4x4) + sizeof(Vector4) + sizeof(Vector4), 0} + }; + + pipelineInfo.depth.depth_mode = GFXDepthMode::LessOrEqual; + + skyPipeline = engine->get_gfx()->create_graphics_pipeline(pipelineInfo); +} + +void SceneCapture::createIrradianceResources() { + GFX* gfx = engine->get_gfx(); + + GFXTextureCreateInfo textureInfo = {}; + textureInfo.width = irradiance_cubemap_resolution; + textureInfo.height = irradiance_cubemap_resolution; + textureInfo.format = GFXPixelFormat::R8G8B8A8_UNORM; + textureInfo.usage = GFXTextureUsage::Attachment; + textureInfo.samplingMode = SamplingMode::ClampToEdge; + + irradianceOffscreenTexture = gfx->create_texture(textureInfo); + + GFXFramebufferCreateInfo info; + info.attachments = {irradianceOffscreenTexture}; + info.render_pass = renderPass; + + irradianceFramebuffer = gfx->create_framebuffer(info); + + GFXRenderPassCreateInfo renderPassInfo = {}; + renderPassInfo.attachments.push_back(GFXPixelFormat::R8G8B8A8_UNORM); + + irradianceRenderPass = gfx->create_render_pass(renderPassInfo); + + GFXGraphicsPipelineCreateInfo pipelineInfo = {}; + pipelineInfo.label = "Irradiance Convolution"; + pipelineInfo.shaders.vertex_path = "irradiance.vert"; + pipelineInfo.shaders.fragment_path = "irradiance.frag"; + + GFXVertexInput input; + input.stride = sizeof(Vector3); + + pipelineInfo.vertex_input.inputs.push_back(input); + + GFXVertexAttribute positionAttribute; + positionAttribute.format = GFXVertexFormat::FLOAT3; + + pipelineInfo.vertex_input.attributes.push_back(positionAttribute); + + pipelineInfo.shader_input.push_constants = { + {sizeof(Matrix4x4), 0} + }; + + pipelineInfo.shader_input.bindings = { + {1, GFXBindingType::PushConstant}, + {2, GFXBindingType::Texture} + }; + + pipelineInfo.render_pass = irradianceRenderPass; + + irradiancePipeline = gfx->create_graphics_pipeline(pipelineInfo); +} + +void SceneCapture::createPrefilterResources() { + GFX* gfx = engine->get_gfx(); + + GFXTextureCreateInfo textureInfo = {}; + textureInfo.width = scene_cubemap_resolution; + textureInfo.height = scene_cubemap_resolution; + textureInfo.format = GFXPixelFormat::R8G8B8A8_UNORM; + textureInfo.usage = GFXTextureUsage::Attachment; + textureInfo.samplingMode = SamplingMode::ClampToEdge; + + prefilteredOffscreenTexture = gfx->create_texture(textureInfo); + + GFXFramebufferCreateInfo info; + info.attachments = {prefilteredOffscreenTexture}; + info.render_pass = irradianceRenderPass; + + prefilteredFramebuffer = gfx->create_framebuffer(info); + + GFXShaderConstant size_constant = {}; + size_constant.type = GFXShaderConstant::Type::Integer; + size_constant.value = scene_cubemap_resolution; + + GFXGraphicsPipelineCreateInfo pipelineInfo = {}; + pipelineInfo.label = "Prefilter"; + pipelineInfo.shaders.vertex_path = "filter.vert"; + pipelineInfo.shaders.fragment_path = "filter.frag"; + + pipelineInfo.shaders.fragment_constants = {size_constant}; + + GFXVertexInput input; + input.stride = sizeof(Vector3); + + pipelineInfo.vertex_input.inputs.push_back(input); + + GFXVertexAttribute positionAttribute; + positionAttribute.format = GFXVertexFormat::FLOAT3; + + pipelineInfo.vertex_input.attributes.push_back(positionAttribute); + + pipelineInfo.shader_input.push_constants = { + {sizeof(Matrix4x4) + sizeof(float), 0} + }; + + pipelineInfo.shader_input.bindings = { + {1, GFXBindingType::PushConstant}, + {2, GFXBindingType::Texture} + }; + + pipelineInfo.render_pass = irradianceRenderPass; + + prefilterPipeline = gfx->create_graphics_pipeline(pipelineInfo); +} diff --git a/engine/renderer/src/shadercompiler.cpp b/engine/renderer/src/shadercompiler.cpp new file mode 100755 index 0000000..66406c7 --- /dev/null +++ b/engine/renderer/src/shadercompiler.cpp @@ -0,0 +1,589 @@ +#include "shadercompiler.hpp" + +#include + +#if defined(PLATFORM_IOS) || defined(PLATFORM_TVOS) +#include +#include +#include +#else +#include +#include +#include +#include +#endif + +#include "file.hpp" +#include "log.hpp" +#include "engine.hpp" +#include "string_utils.hpp" +#include "DirStackIncluder.h" + +const TBuiltInResource DefaultTBuiltInResource = { + /* .MaxLights = */ 32, + /* .MaxClipPlanes = */ 6, + /* .MaxTextureUnits = */ 32, + /* .MaxTextureCoords = */ 32, + /* .MaxVertexAttribs = */ 64, + /* .MaxVertexUniformComponents = */ 4096, + /* .MaxVaryingFloats = */ 64, + /* .MaxVertexTextureImageUnits = */ 32, + /* .MaxCombinedTextureImageUnits = */ 80, + /* .MaxTextureImageUnits = */ 32, + /* .MaxFragmentUniformComponents = */ 4096, + /* .MaxDrawBuffers = */ 32, + /* .MaxVertexUniformVectors = */ 128, + /* .MaxVaryingVectors = */ 8, + /* .MaxFragmentUniformVectors = */ 16, + /* .MaxVertexOutputVectors = */ 16, + /* .MaxFragmentInputVectors = */ 15, + /* .MinProgramTexelOffset = */ -8, + /* .MaxProgramTexelOffset = */ 7, + /* .MaxClipDistances = */ 8, + /* .MaxComputeWorkGroupCountX = */ 65535, + /* .MaxComputeWorkGroupCountY = */ 65535, + /* .MaxComputeWorkGroupCountZ = */ 65535, + /* .MaxComputeWorkGroupSizeX = */ 1024, + /* .MaxComputeWorkGroupSizeY = */ 1024, + /* .MaxComputeWorkGroupSizeZ = */ 64, + /* .MaxComputeUniformComponents = */ 1024, + /* .MaxComputeTextureImageUnits = */ 16, + /* .MaxComputeImageUniforms = */ 8, + /* .MaxComputeAtomicCounters = */ 8, + /* .MaxComputeAtomicCounterBuffers = */ 1, + /* .MaxVaryingComponents = */ 60, + /* .MaxVertexOutputComponents = */ 64, + /* .MaxGeometryInputComponents = */ 64, + /* .MaxGeometryOutputComponents = */ 128, + /* .MaxFragmentInputComponents = */ 128, + /* .MaxImageUnits = */ 8, + /* .MaxCombinedImageUnitsAndFragmentOutputs = */ 8, + /* .MaxCombinedShaderOutputResources = */ 8, + /* .MaxImageSamples = */ 0, + /* .MaxVertexImageUniforms = */ 0, + /* .MaxTessControlImageUniforms = */ 0, + /* .MaxTessEvaluationImageUniforms = */ 0, + /* .MaxGeometryImageUniforms = */ 0, + /* .MaxFragmentImageUniforms = */ 8, + /* .MaxCombinedImageUniforms = */ 8, + /* .MaxGeometryTextureImageUnits = */ 16, + /* .MaxGeometryOutputVertices = */ 256, + /* .MaxGeometryTotalOutputComponents = */ 1024, + /* .MaxGeometryUniformComponents = */ 1024, + /* .MaxGeometryVaryingComponents = */ 64, + /* .MaxTessControlInputComponents = */ 128, + /* .MaxTessControlOutputComponents = */ 128, + /* .MaxTessControlTextureImageUnits = */ 16, + /* .MaxTessControlUniformComponents = */ 1024, + /* .MaxTessControlTotalOutputComponents = */ 4096, + /* .MaxTessEvaluationInputComponents = */ 128, + /* .MaxTessEvaluationOutputComponents = */ 128, + /* .MaxTessEvaluationTextureImageUnits = */ 16, + /* .MaxTessEvaluationUniformComponents = */ 1024, + /* .MaxTessPatchComponents = */ 120, + /* .MaxPatchVertices = */ 32, + /* .MaxTessGenLevel = */ 64, + /* .MaxViewports = */ 16, + /* .MaxVertexAtomicCounters = */ 0, + /* .MaxTessControlAtomicCounters = */ 0, + /* .MaxTessEvaluationAtomicCounters = */ 0, + /* .MaxGeometryAtomicCounters = */ 0, + /* .MaxFragmentAtomicCounters = */ 8, + /* .MaxCombinedAtomicCounters = */ 8, + /* .MaxAtomicCounterBindings = */ 1, + /* .MaxVertexAtomicCounterBuffers = */ 0, + /* .MaxTessControlAtomicCounterBuffers = */ 0, + /* .MaxTessEvaluationAtomicCounterBuffers = */ 0, + /* .MaxGeometryAtomicCounterBuffers = */ 0, + /* .MaxFragmentAtomicCounterBuffers = */ 1, + /* .MaxCombinedAtomicCounterBuffers = */ 1, + /* .MaxAtomicCounterBufferSize = */ 16384, + /* .MaxTransformFeedbackBuffers = */ 4, + /* .MaxTransformFeedbackInterleavedComponents = */ 64, + /* .MaxCullDistances = */ 8, + /* .MaxCombinedClipAndCullDistances = */ 8, + /* .MaxSamples = */ 4, + /* .maxMeshOutputVerticesNV = */ 256, + /* .maxMeshOutputPrimitivesNV = */ 512, + /* .maxMeshWorkGroupSizeX_NV = */ 32, + /* .maxMeshWorkGroupSizeY_NV = */ 1, + /* .maxMeshWorkGroupSizeZ_NV = */ 1, + /* .maxTaskWorkGroupSizeX_NV = */ 32, + /* .maxTaskWorkGroupSizeY_NV = */ 1, + /* .maxTaskWorkGroupSizeZ_NV = */ 1, + /* .maxMeshViewCountNV = */ 4, + +#if defined(PLATFORM_IOS) || defined(PLATFORM_TVOS) + /* .maxDualSourceDrawBuffersEXT = */ 1, +#endif + + /* .limits = */ { + /* .nonInductiveForLoops = */ 1, + /* .whileLoops = */ 1, + /* .doWhileLoops = */ 1, + /* .generalUniformIndexing = */ 1, + /* .generalAttributeMatrixVectorIndexing = */ 1, + /* .generalVaryingIndexing = */ 1, + /* .generalSamplerIndexing = */ 1, + /* .generalVariableIndexing = */ 1, + /* .generalConstantMatrixVectorIndexing = */ 1, +}}; + +const std::vector CompileGLSL(const std::string& filename, EShLanguage ShaderType, bool skinned, bool cubemap) { + std::string newString = "#version 430 core\n"; + + newString += "#extension GL_GOOGLE_include_directive : enable\n"; + newString += "#extension GL_GOOGLE_cpp_style_line_directive : enable\n"; + + if(skinned) + newString += "#define BONE\n"; + + if(cubemap) + newString += "#define CUBEMAP\n"; + + newString += "#line 1\n"; + + newString += filename; + + const char* InputCString = newString.c_str(); + + glslang::TShader Shader(ShaderType); + + Shader.setStrings(&InputCString, 1); + + int ClientInputSemanticsVersion = 100; // maps to, say, #define VULKAN 100 + glslang::EShTargetClientVersion VulkanClientVersion = glslang::EShTargetVulkan_1_1; + glslang::EShTargetLanguageVersion TargetVersion = glslang::EShTargetSpv_1_0; + + Shader.setEnvInput(glslang::EShSourceGlsl, ShaderType, glslang::EShClientVulkan, ClientInputSemanticsVersion); + Shader.setEnvClient(glslang::EShClientVulkan, VulkanClientVersion); + Shader.setEnvTarget(glslang::EShTargetSpv, TargetVersion); + + TBuiltInResource Resources = DefaultTBuiltInResource; + EShMessages messages = (EShMessages) (EShMsgSpvRules); + + DirStackFileIncluder includer; + + if (!Shader.parse(&Resources, 100, false, (EShMessages)0, includer)) { + std::cout << Shader.getInfoLog() << std::endl; + + return {}; + } + + glslang::TProgram Program; + Program.addShader(&Shader); + + if(!Program.link(messages)) { + console::error(System::None, "Failed to link shader: {} {} {}", filename, Shader.getInfoLog(), Shader.getInfoDebugLog()); + + return {}; + } + + std::vector SpirV; + spv::SpvBuildLogger logger; + glslang::SpvOptions spvOptions; + glslang::GlslangToSpv(*Program.getIntermediate(ShaderType), SpirV, &logger, &spvOptions); + + return SpirV; +} + +std::string get_shader(std::string filename, bool skinned, bool cubemap) { + auto shader_file = file::open(file::internal_domain / filename); + if(!shader_file) { + std::cerr << "Failed to open " << filename << "!!" << std::endl; + return ""; + } + + EShLanguage lang; + if(filename.find("vert") != std::string::npos) { + lang = EShLangVertex; + } else { + lang = EShLangFragment; + } + + auto vertexSPIRV = CompileGLSL(shader_file->read_as_string(), lang, skinned, cubemap); + + spirv_cross::CompilerMSL msl(std::move(vertexSPIRV)); + + spirv_cross::CompilerMSL::Options opts; + opts.platform = spirv_cross::CompilerMSL::Options::Platform::macOS; + opts.enable_decoration_binding = true; + + msl.set_msl_options(opts); + + return msl.compile(); +} + +GFXPipeline* ShaderCompiler::create_static_pipeline(GFXGraphicsPipelineCreateInfo createInfo, bool positions_only, bool cubemap) { + // take vertex src + std::string vertex_path = createInfo.shaders.vertex_path.data(); + vertex_path += ".glsl"; + + std::string vertex_src = get_shader(vertex_path, false, cubemap); + createInfo.shaders.vertex_src = vertex_src; + createInfo.shaders.vertex_path = ""; + + if(positions_only) { + createInfo.vertex_input.inputs = { + {position_buffer_index, sizeof(Vector3)} + }; + + createInfo.vertex_input.attributes = { + {position_buffer_index, 0, 0, GFXVertexFormat::FLOAT3} + }; + } else { + createInfo.vertex_input.inputs = { + {position_buffer_index, sizeof(Vector3)}, + {normal_buffer_index, sizeof(Vector3)}, + {texcoord_buffer_index, sizeof(Vector2)}, + {tangent_buffer_index, sizeof(Vector3)}, + {bitangent_buffer_index, sizeof(Vector3)} + }; + + createInfo.vertex_input.attributes = { + {position_buffer_index, 0, 0, GFXVertexFormat::FLOAT3}, + {normal_buffer_index, 1, 0, GFXVertexFormat::FLOAT3}, + {texcoord_buffer_index, 2, 0, GFXVertexFormat::FLOAT2}, + {tangent_buffer_index, 3, 0, GFXVertexFormat::FLOAT3}, + {bitangent_buffer_index, 4, 0, GFXVertexFormat::FLOAT3} + }; + } + + return engine->get_gfx()->create_graphics_pipeline(createInfo); +} + +GFXPipeline* ShaderCompiler::create_skinned_pipeline(GFXGraphicsPipelineCreateInfo createInfo, bool positions_only) { + createInfo.label += " (Skinned)"; + + // take vertex src + std::string vertex_path = createInfo.shaders.vertex_path.data(); + vertex_path += ".glsl"; + + std::string vertex_src = get_shader(vertex_path, true, false); + createInfo.shaders.vertex_src = vertex_src; + createInfo.shaders.vertex_path = ""; + + if(positions_only) { + createInfo.vertex_input.inputs = { + {position_buffer_index, sizeof(Vector3)}, + {bone_buffer_index, sizeof(BoneVertexData)} + }; + + createInfo.vertex_input.attributes = { + {position_buffer_index, 0, 0, GFXVertexFormat::FLOAT3}, + {bone_buffer_index, 4, offsetof(BoneVertexData, ids), GFXVertexFormat::INT4}, + {bone_buffer_index, 5, offsetof(BoneVertexData, weights), GFXVertexFormat::FLOAT4} + }; + } else { + createInfo.vertex_input.inputs = { + {position_buffer_index, sizeof(Vector3)}, + {normal_buffer_index, sizeof(Vector3)}, + {texcoord_buffer_index, sizeof(Vector2)}, + {tangent_buffer_index, sizeof(Vector3)}, + {bitangent_buffer_index, sizeof(Vector3)}, + {bone_buffer_index, sizeof(BoneVertexData)} + }; + + createInfo.vertex_input.attributes = { + {position_buffer_index, 0, 0, GFXVertexFormat::FLOAT3}, + {normal_buffer_index, 1, 0, GFXVertexFormat::FLOAT3}, + {texcoord_buffer_index, 2, 0, GFXVertexFormat::FLOAT2}, + {tangent_buffer_index, 3, 0, GFXVertexFormat::FLOAT3}, + {bitangent_buffer_index, 4, 0, GFXVertexFormat::FLOAT3}, + {bone_buffer_index, 5, offsetof(BoneVertexData, ids), GFXVertexFormat::INT4}, + {bone_buffer_index, 6, offsetof(BoneVertexData, weights), GFXVertexFormat::FLOAT4}, + }; + } + + return engine->get_gfx()->create_graphics_pipeline(createInfo); +} + +std::tuple ShaderCompiler::create_pipeline_permutations(GFXGraphicsPipelineCreateInfo& createInfo, bool positions_only) { + glslang::InitializeProcess(); + + auto st = create_static_pipeline(createInfo, positions_only); + auto ss = create_skinned_pipeline(createInfo, positions_only); + + return {st, ss}; +} + +std::vector walked_nodes; + +void walk_node(std::string& src, MaterialNode* node) { + if(utility::contains(walked_nodes, node)) + return; + + walked_nodes.push_back(node); + + for(auto& input : node->inputs) { + if(input.connected_node != nullptr) + walk_node(src, input.connected_node); + } + + std::string intermediate = node->get_glsl(); + for(auto& property : node->properties) { + intermediate = replace_substring(intermediate, property.name, node->get_property_value(property)); + } + + for(auto& input : node->inputs) { + intermediate = replace_substring(intermediate, input.name, node->get_connector_value(input)); + } + + for(auto& output : node->outputs) { + intermediate = replace_substring(intermediate, output.name, node->get_connector_variable_name(output)); + } + + src += intermediate; +} + +constexpr std::string_view struct_info = +"layout (constant_id = 0) const int max_materials = 25;\n \ +layout (constant_id = 1) const int max_lights = 25;\n \ +layout (constant_id = 2) const int max_spot_lights = 4;\n \ +layout (constant_id = 3) const int max_probes = 4;\n \ +struct Material {\n \ + vec4 color, info;\n \ +};\n \ +struct Light {\n \ + vec4 positionType;\n \ + vec4 directionPower;\n \ + vec4 colorSize;\n \ + vec4 shadowsEnable;\n \ +};\n \ +struct Probe {\n \ + vec4 position, size;\n \ +};\n \ +layout(std430, binding = 1) buffer readonly SceneInformation {\n \ + vec4 options;\n \ + vec4 camPos;\n \ + mat4 vp, lightSpace;\n \ + mat4 spotLightSpaces[max_spot_lights];\n \ + Material materials[max_materials];\n \ + Light lights[max_lights];\n \ + Probe probes[max_probes];\n \ + int numLights;\n \ +} scene;\n \ +layout (binding = 2) uniform texture2D sun_shadow;\n \ +layout (binding = 4) uniform sampler shadow_sampler;\n \ +layout (binding = 5) uniform samplerShadow pcf_sampler;\n \ +layout (binding = 6) uniform texture2DArray spot_shadow;\n \ +layout(push_constant, binding = 0) uniform PushConstant {\n \ + mat4 model;\n \ + int materialOffset;\n \ +};\n"; + +std::string ShaderCompiler::compile_material_fragment(Material& material, bool use_ibl) { + walked_nodes.clear(); + + if(!render_options.enable_ibl) + use_ibl = false; + + std::string src; + + switch(render_options.shadow_filter) { + case ShadowFilter::None: + src += "#define SHADOW_FILTER_NONE\n"; + break; + case ShadowFilter::PCF: + src += "#define SHADOW_FILTER_PCF\n"; + break; + case ShadowFilter::PCSS: + src += "#define SHADOW_FILTER_PCSS\n"; + break; + } + + src += "layout (location = 0) in vec3 in_frag_pos;\n"; + src += "layout(location = 1) in vec3 in_normal;\n"; + src += "layout(location = 2) in vec2 in_uv;\n"; + + src += "layout(location = 0) out vec4 frag_output;\n"; + + if(render_options.enable_point_shadows) { + src += "#define POINT_SHADOWS_SUPPORTED\n"; + src += "layout (binding = 3) uniform textureCubeArray point_shadow;\n"; + } + + src += struct_info; + + if(use_ibl) { + src += "layout (binding = 7) uniform samplerCubeArray irrandianceSampler;\n \ + layout (binding = 8) uniform samplerCubeArray prefilterSampler;\n \ + layout (binding = 9) uniform sampler2D brdfSampler;\n"; + } + + src += "layout(location = 4) in vec4 fragPosLightSpace;\n"; + src += "layout(location = 5) in mat3 in_tbn;\n"; + src += "layout(location = 14) in vec4 fragPostSpotLightSpace[max_spot_lights];\n"; + + src += "#include \"common.glsl\"\n"; + src += "#include \"rendering.glsl\"\n"; + + material.bound_textures.clear(); + + // insert samplers as needed + int sampler_index = 10; + for(auto& node : material.nodes) { + for(auto& property : node->properties) { + if(property.type == DataType::AssetTexture) { + material.bound_textures[sampler_index] = property.value_tex; + + src += "layout(binding = " + std::to_string(sampler_index++) + ") uniform sampler2D " + node->get_property_variable_name(property) + ";\n"; + } + } + } + + if(use_ibl) { + src += "vec3 get_reflect(int i, vec3 final_normal) {\n \ + const vec3 direction = normalize(in_frag_pos - scene.camPos.xyz);\n \ + const vec3 reflection = reflect(direction, normalize(final_normal));\n \ + vec3 box_max = scene.probes[i].position.xyz + (scene.probes[i].size.xyz / 2.0f);\n \ + vec3 box_min = scene.probes[i].position.xyz + -(scene.probes[i].size.xyz / 2.0f);\n \ + vec3 unitary = vec3(1.0);\n \ + vec3 first_plane_intersect = (box_max - in_frag_pos) / reflection;\n \ + vec3 second_plane_intersect = (box_min - in_frag_pos) / reflection;\n \ + vec3 furthest_plane = max(first_plane_intersect, second_plane_intersect);\n \ + float distance = min(furthest_plane.x, min(furthest_plane.y, furthest_plane.z));\n \ + vec3 intersect_position_world = in_frag_pos + reflection * distance; \n \ + return intersect_position_world - scene.probes[i].position.xyz;\n}\n"; + } + + if(render_options.enable_normal_shadowing) { + src += "float calculate_normal_lighting(in sampler2D normal_map, const vec3 normal, const vec3 light_dir) {\n \ + float height_scale = 0.8;\n \ + float sample_count = 100.0;\n \ + float inv_sample_count = 1.0 / sample_count;\n \ + float hardness = 50 * 0.5;\n \ + float lighting = clamp(dot(light_dir, normal), 0.0, 1.0);\n \ + float slope = -lighting;\n \ + vec2 dir = light_dir.xy * vec2(1.0, -1.0) * height_scale;\n \ + float max_slope = 0.0;\n \ + float step = inv_sample_count;\n \ + float pos = step;\n \ + pos = (-lighting >= 0.0) ? 1.001 : pos;\n \ + vec2 noise = fract(in_frag_pos.xy * 0.5);\n \ + noise.x = noise.x + noise.y * 0.5;\n \ + pos = step - step * noise.x;\n \ + float shadow = 0.0;\n \ + while(pos <= 1.0) {\n \ + vec3 tmp_normal = texture(normal_map, in_uv + dir * pos).rgb;\n \ + tmp_normal = in_tbn * (tmp_normal * 2.0 - 1.0);\n \ + float tmp_lighting = dot(light_dir, tmp_normal);\n \ + float shadowed = -tmp_lighting;\n \ + slope += shadowed;\n \ + if(slope > max_slope) {\n \ + shadow += hardness * (1.0 - pos);\n \ + }\n \ + max_slope = max(max_slope, slope);\n \ + pos += step;\n \ + }\n \ + return clamp(1.0 - shadow * inv_sample_count, 0.0, 1.0);\n \ + }\n"; + } + + src += "void main() {\n"; + + bool has_output = false; + bool has_normal_mapping = false; + std::string normal_map_property_name; + for(auto& node : material.nodes) { + if(!strcmp(node->get_name(), "Material Output")) { + for(auto& input : node->inputs) { + if(input.is_normal_map && input.connected_node != nullptr) { + has_normal_mapping = true; + normal_map_property_name = input.connected_node->get_property_variable_name(input.connected_node->properties[0]); // quick and dirty workaround to get the normal map texture name + } + } + + walk_node(src, node.get()); + has_output = true; + } + } + + if(!has_output) { + src += "vec3 final_diffuse_color = vec3(1);\n"; + src += "float final_roughness = 0.5;\n"; + src += "float final_metallic = 0.0;\n"; + src += "vec3 final_normal = in_normal;\n"; + } + + src += + "ComputedSurfaceInfo surface_info = compute_surface(final_diffuse_color.rgb, final_normal, final_metallic, final_roughness);\n \ + vec3 Lo = vec3(0);\n \ + for(int i = 0; i < scene.numLights; i++) {\n \ + const int type = int(scene.lights[i].positionType.w);\n \ + ComputedLightInformation light_info;\n \ + switch(type) {\n \ + case 0:\n \ + light_info = calculate_point(scene.lights[i]);\n \ + break;\n \ + case 1:\n \ + light_info = calculate_spot(scene.lights[i]);\n \ + break;\n \ + case 2:\n \ + light_info = calculate_sun(scene.lights[i]);\n \ + break;\n \ + }\n \ + ComputedLightSurfaceInfo light_surface_info = compute_light_surface(light_info.direction, surface_info);\n"; + + if(render_options.enable_normal_mapping && has_normal_mapping && render_options.enable_normal_shadowing) { + src += std::string("light_info.radiance *= calculate_normal_lighting(") + normal_map_property_name + ", final_normal, light_info.direction);\n"; + } + + src += "Lo += (light_surface_info.kD * final_diffuse_color.rgb / PI + light_surface_info.specular) * light_surface_info.NdotL * scene.lights[i].colorSize.xyz * light_info.radiance;\n \ + }\n"; + + if(use_ibl) { + src += + "const vec3 F = fresnel_schlick_roughness(surface_info.NdotV, surface_info.F0, surface_info.roughness); \n \ + const vec3 kD = (1.0 - F) * (1.0 - surface_info.metallic); \n \ + vec3 ambient = vec3(0.0); \ + float sum = 0.0;\n \ + for(int i = 0; i < max_probes; i++) { \ + if(scene.probes[i].position.w == 1) {\n \ + vec3 position = scene.probes[i].position.xyz; \ + vec3 probe_min = position - (scene.probes[i].size.xyz / 2.0); \ + vec3 probe_max = position + (scene.probes[i].size.xyz / 2.0); \ + if(all(greaterThan(in_frag_pos, probe_min)) && all(lessThan(in_frag_pos, probe_max)) && scene.probes[i].position.w == 1) { \ + float intensity = 1.0 - length(abs(in_frag_pos - position) / (scene.probes[i].size.xyz / 2.0));\n \ + intensity = clamp(intensity, 0.0, 1.0) * scene.probes[i].size.w;\n \ + const vec3 R = get_reflect(i, surface_info.N);\n \ + const vec2 brdf = texture(brdfSampler, vec2(surface_info.NdotV, surface_info.roughness)).rg; \n \ + const vec3 sampledIrradiance = texture(irrandianceSampler, vec4(surface_info.N, i)).xyz;\n \ + const vec3 prefilteredColor = textureLod(prefilterSampler, vec4(R, i), surface_info.roughness * 4).xyz;\n \ + const vec3 diffuse = sampledIrradiance * final_diffuse_color.rgb;\n \ + const vec3 specular = prefilteredColor * (F * brdf.x + brdf.y);\n \ + ambient += (kD * diffuse + specular) * intensity;\n \ + sum += intensity; \n \ + } \ + } else if(scene.probes[i].position.w == 2) {\n \ + const vec3 R = reflect(-surface_info.V, surface_info.N);\n \ + const vec2 brdf = texture(brdfSampler, vec2(surface_info.NdotV, surface_info.roughness)).rg; \n \ + const vec3 sampledIrradiance = texture(irrandianceSampler, vec4(surface_info.N, i)).xyz;\n \ + const vec3 prefilteredColor = textureLod(prefilterSampler, vec4(R, i), surface_info.roughness * 4).xyz;\n \ + const vec3 diffuse = sampledIrradiance * final_diffuse_color.rgb;\n \ + const vec3 specular = prefilteredColor * (F * brdf.x + brdf.y);\n \ + ambient += (kD * diffuse + specular) * scene.probes[i].size.w;\n \ + sum += 1.0; \n \ + }\n \ + }\n \ + ambient /= sum;\n"; + + src += "frag_output = vec4(ambient + Lo, 1.0);\n"; + } else { + src += "frag_output = vec4(Lo, 1.0);\n"; + } + + src += "}\n"; + + auto vertexSPIRV = CompileGLSL(src, EShLangFragment, false, false); + + spirv_cross::CompilerMSL msl(std::move(vertexSPIRV)); + + spirv_cross::CompilerMSL::Options opts; + opts.platform = spirv_cross::CompilerMSL::Options::Platform::macOS; + opts.enable_decoration_binding = true; + + msl.set_msl_options(opts); + + return msl.compile(); +} diff --git a/engine/renderer/src/shadowpass.cpp b/engine/renderer/src/shadowpass.cpp new file mode 100755 index 0000000..749e762 --- /dev/null +++ b/engine/renderer/src/shadowpass.cpp @@ -0,0 +1,385 @@ +#include "shadowpass.hpp" + +#include "gfx_commandbuffer.hpp" +#include "scene.hpp" +#include "gfx.hpp" +#include "log.hpp" +#include "engine.hpp" +#include "shadercompiler.hpp" +#include "assertions.hpp" +#include "frustum.hpp" + +struct PushConstant { + Matrix4x4 mvp, model; + Vector3 lightPos; +}; + +const std::array shadowTransforms = { + transform::look_at(Vector3(0), Vector3(1.0, 0.0, 0.0), Vector3(0.0, -1.0, 0.0)), + transform::look_at(Vector3(0), Vector3(-1.0, 0.0, 0.0), Vector3(0.0, -1.0, 0.0)), + transform::look_at(Vector3(0), Vector3( 0.0, 1.0, 0.0), Vector3(0.0, 0.0,1.0)), + transform::look_at(Vector3(0), Vector3( 0.0, -1.0, 0.0), Vector3(0.0, 0.0,-1.0)), + transform::look_at(Vector3(0), Vector3( 0.0, 0.0, 1.0), Vector3(0.0, -1.0, 0.0)), + transform::look_at(Vector3(0), Vector3( 0.0, 0.0, -1.0), Vector3(0.0, -1.0, 0.0)) +}; + +ShadowPass::ShadowPass(GFX* gfx) { + Expects(gfx != nullptr); + Expects(render_options.shadow_resolution > 0); + + create_render_passes(); + create_pipelines(); + create_offscreen_resources(); + + GFXSamplerCreateInfo sampler_info = {}; + sampler_info.samplingMode = SamplingMode::ClampToBorder; + sampler_info.border_color = GFXBorderColor::OpaqueWhite; + + shadow_sampler = gfx->create_sampler(sampler_info); + pcf_sampler = gfx->create_sampler(sampler_info); // unused atm +} + +void ShadowPass::create_scene_resources(Scene& scene) { + auto gfx = engine->get_gfx(); + + // sun light + { + GFXTextureCreateInfo textureInfo = {}; + textureInfo.width = render_options.shadow_resolution; + textureInfo.height = render_options.shadow_resolution; + textureInfo.format = GFXPixelFormat::DEPTH_32F; + textureInfo.usage = GFXTextureUsage::Sampled | GFXTextureUsage::Attachment; + + scene.depthTexture = gfx->create_texture(textureInfo); + + GFXFramebufferCreateInfo info; + info.attachments = {scene.depthTexture}; + info.render_pass = render_pass; + + scene.framebuffer = gfx->create_framebuffer(info); + } + + // point lights + if(gfx->supports_feature(GFXFeature::CubemapArray)) { + GFXTextureCreateInfo cubeTextureInfo = {}; + cubeTextureInfo.type = GFXTextureType::CubemapArray; + cubeTextureInfo.width = render_options.shadow_resolution; + cubeTextureInfo.height = render_options.shadow_resolution; + cubeTextureInfo.format = GFXPixelFormat::R_32F; + cubeTextureInfo.usage = GFXTextureUsage::Sampled; + cubeTextureInfo.samplingMode = SamplingMode::ClampToEdge; + cubeTextureInfo.array_length = max_point_shadows; + + scene.pointLightArray = gfx->create_texture(cubeTextureInfo); + } + + // spot lights + { + GFXTextureCreateInfo spotTextureInfo = {}; + spotTextureInfo.type = GFXTextureType::Array2D; + spotTextureInfo.width = render_options.shadow_resolution; + spotTextureInfo.height = render_options.shadow_resolution; + spotTextureInfo.format = GFXPixelFormat::DEPTH_32F; + spotTextureInfo.usage = GFXTextureUsage::Sampled | GFXTextureUsage::Attachment; + spotTextureInfo.samplingMode = SamplingMode::ClampToEdge; + spotTextureInfo.array_length = max_spot_shadows; + + scene.spotLightArray = gfx->create_texture(spotTextureInfo); + } +} + +void ShadowPass::render(GFXCommandBuffer* command_buffer, Scene& scene) { + last_spot_light = 0; + last_point_light = 0; + + auto lights = scene.get_all(); + for(auto [obj, light] : lights) { + switch(light.type) { + case Light::Type::Sun: + render_sun(command_buffer, scene, obj, light); + break; + case Light::Type::Spot: + render_spot(command_buffer, scene, obj, light); + break; + case Light::Type::Point: + render_point(command_buffer, scene, obj, light); + break; + } + } +} + +void ShadowPass::render_meshes(GFXCommandBuffer* command_buffer, Scene& scene, const Matrix4x4 light_matrix, const Matrix4x4 model, const Vector3 light_position, const Light::Type type, const CameraFrustum& frustum) { + for(auto [obj, mesh] : scene.get_all()) { + if(!mesh.mesh) + continue; + + command_buffer->set_vertex_buffer(mesh.mesh->position_buffer, 0, position_buffer_index); + + command_buffer->set_index_buffer(mesh.mesh->index_buffer, IndexType::UINT32); + + PushConstant pc; + pc.mvp = light_matrix * model * scene.get(obj).model; + pc.model = scene.get(obj).model; + pc.lightPos = light_position; + + if(mesh.mesh->bones.empty()) { + switch(type) { + case Light::Type::Sun: + command_buffer->set_pipeline(static_sun_pipeline); + break; + case Light::Type::Spot: + command_buffer->set_pipeline(static_spot_pipeline); + break; + case Light::Type::Point: + command_buffer->set_pipeline(static_point_pipeline); + break; + } + + command_buffer->set_push_constant(&pc, sizeof(PushConstant)); + command_buffer->set_depth_bias(1.25f, 0.00f, 1.75f); + + for (auto& part : mesh.mesh->parts) { + if(render_options.enable_frustum_culling && !test_aabb_frustum(frustum, get_aabb_for_part(scene.get(obj), part))) { + console::debug(System::Renderer, "Shadow Culled {}!", scene.get(obj).name); + continue; + } + + command_buffer->draw_indexed(part.index_count, part.index_offset, part.vertex_offset); + } + } else { + switch(type) { + case Light::Type::Sun: + command_buffer->set_pipeline(skinned_sun_pipeline); + break; + case Light::Type::Spot: + command_buffer->set_pipeline(skinned_spot_pipeline); + break; + case Light::Type::Point: + command_buffer->set_pipeline(skinned_point_pipeline); + break; + } + + command_buffer->set_push_constant(&pc, sizeof(PushConstant)); + + command_buffer->set_vertex_buffer(mesh.mesh->bone_buffer, 0, bone_buffer_index); + command_buffer->set_depth_bias(1.25f, 0.00f, 1.75f); + + for (auto& part : mesh.mesh->parts) { + if(render_options.enable_frustum_culling && !test_aabb_frustum(frustum, get_aabb_for_part(scene.get(obj), part))) { + console::debug(System::Renderer, "Shadow Culled {}!", scene.get(obj).name); + continue; + } + + command_buffer->bind_shader_buffer(part.bone_batrix_buffer, 0, 1, sizeof(Matrix4x4) * 128); + command_buffer->draw_indexed(part.index_count, part.index_offset, part.vertex_offset); + } + } + } +} + +void ShadowPass::render_sun(GFXCommandBuffer* command_buffer, Scene& scene, Object light_object, Light& light) { + if(scene.sun_light_dirty || light.use_dynamic_shadows) { + GFXRenderPassBeginInfo info = {}; + info.framebuffer = scene.framebuffer; + info.render_pass = render_pass; + info.render_area.extent = {static_cast(render_options.shadow_resolution), static_cast(render_options.shadow_resolution)}; + + command_buffer->set_render_pass(info); + + Viewport viewport = {}; + viewport.width = render_options.shadow_resolution; + viewport.height = render_options.shadow_resolution; + + command_buffer->set_viewport(viewport); + + const Vector3 lightPos = scene.get(light_object).position; + + const Matrix4x4 projection = transform::orthographic(-25.0f, 25.0f, -25.0f, 25.0f, 0.1f, 100.0f); + const Matrix4x4 view = transform::look_at(lightPos, Vector3(0), Vector3(0, 1, 0)); + + const Matrix4x4 realMVP = projection * engine->get_renderer()->correction_matrix * view; + + scene.lightSpace = projection * view; + + const auto frustum = normalize_frustum(extract_frustum(projection * view)); + + if(light.enable_shadows) + render_meshes(command_buffer, scene, realMVP, Matrix4x4(), lightPos, Light::Type::Sun, frustum); + + scene.sun_light_dirty = false; + } +} + +void ShadowPass::render_spot(GFXCommandBuffer* command_buffer, Scene& scene, Object light_object, Light& light) { + if((last_spot_light + 1) == max_spot_shadows) + return; + + if(scene.spot_light_dirty[last_spot_light] || light.use_dynamic_shadows) { + GFXRenderPassBeginInfo info = {}; + info.framebuffer = offscreen_framebuffer; + info.render_pass = cube_render_pass; + info.render_area.extent = {static_cast(render_options.shadow_resolution), static_cast(render_options.shadow_resolution)}; + + command_buffer->set_render_pass(info); + + Viewport viewport = {}; + viewport.width = render_options.shadow_resolution; + viewport.height = render_options.shadow_resolution; + + command_buffer->set_viewport(viewport); + + const Matrix4x4 perspective = transform::perspective(radians(90.0f), 1.0f, 0.1f); + + const Matrix4x4 realMVP = perspective * engine->get_renderer()->correction_matrix * inverse(scene.get(light_object).model); + + scene.spotLightSpaces[last_spot_light] = perspective * inverse(scene.get(light_object).model); + + const auto frustum = normalize_frustum(extract_frustum(perspective * inverse(scene.get(light_object).model))); + + if(light.enable_shadows) + render_meshes(command_buffer, scene, realMVP, Matrix4x4(), scene.get(light_object).get_world_position(), Light::Type::Spot, frustum); + + command_buffer->copy_texture(offscreen_depth, render_options.shadow_resolution, render_options.shadow_resolution, scene.spotLightArray, 0, last_spot_light, 0); + + scene.spot_light_dirty[last_spot_light] = false; + } + + last_spot_light++; +} + +void ShadowPass::render_point(GFXCommandBuffer* command_buffer, Scene& scene, Object light_object, Light& light) { + if(!render_options.enable_point_shadows) + return; + + if((last_point_light + 1) == max_point_shadows) + return; + + if(scene.point_light_dirty[last_point_light] || light.use_dynamic_shadows) { + for(int face = 0; face < 6; face++) { + GFXRenderPassBeginInfo info = {}; + info.framebuffer = offscreen_framebuffer; + info.render_pass = cube_render_pass; + info.render_area.extent = {static_cast(render_options.shadow_resolution), static_cast(render_options.shadow_resolution)}; + + command_buffer->set_render_pass(info); + + Viewport viewport = {}; + viewport.width = render_options.shadow_resolution; + viewport.height = render_options.shadow_resolution; + + command_buffer->set_viewport(viewport); + + const Vector3 lightPos = scene.get(light_object).get_world_position(); + + const Matrix4x4 projection = transform::perspective(radians(90.0f), 1.0f, 0.1f); + const Matrix4x4 model = transform::translate(Matrix4x4(), Vector3(-lightPos.x, -lightPos.y, -lightPos.z)); + + const auto frustum = normalize_frustum(extract_frustum(projection * shadowTransforms[face] * model)); + + render_meshes(command_buffer, scene, projection * engine->get_renderer()->correction_matrix * shadowTransforms[face], model, lightPos, Light::Type::Point, frustum); + + command_buffer->copy_texture(offscreen_color_texture, render_options.shadow_resolution, render_options.shadow_resolution, scene.pointLightArray, face, last_point_light, 0); + } + + scene.point_light_dirty[last_point_light] = false; + } + + last_point_light++; +} + +void ShadowPass::create_render_passes() { + auto gfx = engine->get_gfx(); + + // render pass + GFXRenderPassCreateInfo renderPassInfo = {}; + renderPassInfo.attachments.push_back(GFXPixelFormat::DEPTH_32F); + + render_pass = gfx->create_render_pass(renderPassInfo); + + renderPassInfo.attachments.clear(); + renderPassInfo.attachments.push_back(GFXPixelFormat::R_32F); + renderPassInfo.attachments.push_back(GFXPixelFormat::DEPTH_32F); + + cube_render_pass = gfx->create_render_pass(renderPassInfo); +} + +void ShadowPass::create_pipelines() { + GFXGraphicsPipelineCreateInfo pipelineInfo = {}; + pipelineInfo.shaders.vertex_path = "shadow.vert"; + pipelineInfo.shaders.fragment_path = "shadow.frag"; + + pipelineInfo.shader_input.bindings = { + {0, GFXBindingType::PushConstant} + }; + + pipelineInfo.shader_input.push_constants = { + {sizeof(PushConstant), 0} + }; + + pipelineInfo.render_pass = render_pass; + + pipelineInfo.depth.depth_mode = GFXDepthMode::LessOrEqual; + pipelineInfo.rasterization.culling_mode = GFXCullingMode::None; + + // sun + { + pipelineInfo.label = "Sun Shadow"; + + auto [static_pipeline, skinned_pipeline] = shader_compiler.create_pipeline_permutations(pipelineInfo, true); + + static_sun_pipeline = static_pipeline; + skinned_sun_pipeline = skinned_pipeline; + } + + // spot + { + pipelineInfo.label = "Spot Shadow"; + + pipelineInfo.render_pass = cube_render_pass; + + auto [static_pipeline, skinned_pipeline] = shader_compiler.create_pipeline_permutations(pipelineInfo, true); + + static_spot_pipeline = static_pipeline; + skinned_spot_pipeline = skinned_pipeline; + } + + // point + { + pipelineInfo.label = "Point Shadow"; + + pipelineInfo.shaders.fragment_path = "omnishadow.frag"; + + auto [static_pipeline, skinned_pipeline] = shader_compiler.create_pipeline_permutations(pipelineInfo, true); + + static_point_pipeline = static_pipeline; + skinned_point_pipeline = skinned_pipeline; + } +} + +void ShadowPass::create_offscreen_resources() { + auto gfx = engine->get_gfx(); + + GFXTextureCreateInfo textureInfo = {}; + textureInfo.width = render_options.shadow_resolution; + textureInfo.height = render_options.shadow_resolution; + textureInfo.format = GFXPixelFormat::R_32F; + textureInfo.usage = GFXTextureUsage::Attachment; + textureInfo.samplingMode = SamplingMode::ClampToEdge; + + offscreen_color_texture = gfx->create_texture(textureInfo); + + GFXTextureCreateInfo depthTextureInfo = {}; + depthTextureInfo.width = render_options.shadow_resolution; + depthTextureInfo.height = render_options.shadow_resolution; + depthTextureInfo.format = GFXPixelFormat::DEPTH_32F; + depthTextureInfo.usage = GFXTextureUsage::Attachment; + depthTextureInfo.samplingMode = SamplingMode::ClampToEdge; + + offscreen_depth = gfx->create_texture(depthTextureInfo); + + GFXFramebufferCreateInfo info; + info.attachments = {offscreen_color_texture, offscreen_depth}; + info.render_pass = render_pass; + + offscreen_framebuffer = gfx->create_framebuffer(info); +} diff --git a/engine/renderer/src/smaapass.cpp b/engine/renderer/src/smaapass.cpp new file mode 100755 index 0000000..b18ac75 --- /dev/null +++ b/engine/renderer/src/smaapass.cpp @@ -0,0 +1,158 @@ +#include "smaapass.hpp" + +#include "gfx_commandbuffer.hpp" +#include "renderer.hpp" +#include "engine.hpp" +#include "gfx.hpp" +#include "assertions.hpp" + +#include +#include + +SMAAPass::SMAAPass(GFX* gfx, Renderer* renderer) : renderer(renderer), extent(renderer->get_render_extent()) { + Expects(gfx != nullptr); + Expects(renderer != nullptr); + + create_textures(); + create_render_pass(); + create_pipelines(); + create_offscreen_resources(); +} + +void SMAAPass::render(GFXCommandBuffer* command_buffer) { + GFXRenderPassBeginInfo beginInfo = {}; + beginInfo.clear_color.a = 0.0f; + beginInfo.render_area.extent = extent; + beginInfo.render_pass = render_pass; + + struct PushConstant { + Vector4 viewport; + Matrix4x4 correction_matrix; + } pc; + + pc.viewport = Vector4(1.0f / static_cast(extent.width), 1.0f / static_cast(extent.height), extent.width, extent.height); + pc.correction_matrix = engine->get_renderer()->correction_matrix; + + // edge + { + beginInfo.framebuffer = edge_framebuffer; + command_buffer->set_render_pass(beginInfo); + + Viewport viewport = {}; + viewport.width = extent.width; + viewport.height = extent.height; + + command_buffer->set_viewport(viewport); + + command_buffer->set_pipeline(edge_pipeline); + command_buffer->set_push_constant(&pc, sizeof(PushConstant)); + + command_buffer->bind_texture(renderer->offscreenColorTexture, 0); // color + command_buffer->bind_texture(renderer->offscreenDepthTexture, 1); // depth + + command_buffer->draw(0, 3, 0, 1); + } + + // blend + { + beginInfo.framebuffer = blend_framebuffer; + command_buffer->set_render_pass(beginInfo); + + command_buffer->set_pipeline(blend_pipeline); + command_buffer->set_push_constant(&pc, sizeof(PushConstant)); + + command_buffer->bind_texture(edge_texture, 0); + command_buffer->bind_texture(area_image, 1); + command_buffer->bind_texture(search_image, 3); + + command_buffer->draw(0, 3, 0, 1); + } +} + +void SMAAPass::create_textures() { + auto gfx = engine->get_gfx(); + + //load area image + GFXTextureCreateInfo areaInfo = {}; + areaInfo.width = AREATEX_WIDTH; + areaInfo.height = AREATEX_HEIGHT; + areaInfo.format = GFXPixelFormat::R8G8_UNORM; + areaInfo.usage = GFXTextureUsage::Sampled; + areaInfo.samplingMode = SamplingMode::ClampToEdge; + + area_image = gfx->create_texture(areaInfo); + + gfx->copy_texture(area_image, (void*)areaTexBytes, AREATEX_SIZE); + + // load search image + GFXTextureCreateInfo searchInfo = {}; + searchInfo.width = SEARCHTEX_WIDTH; + searchInfo.height = SEARCHTEX_HEIGHT; + searchInfo.format = GFXPixelFormat::R8_UNORM; + searchInfo.usage = GFXTextureUsage::Sampled; + searchInfo.samplingMode = SamplingMode::ClampToEdge; + + search_image = gfx->create_texture(searchInfo); + + gfx->copy_texture(search_image, (void*)searchTexBytes, SEARCHTEX_SIZE); +} + +void SMAAPass::create_render_pass() { + GFXRenderPassCreateInfo createInfo = {}; + createInfo.attachments = {GFXPixelFormat::R16G16B16A16_SFLOAT}; + + render_pass = engine->get_gfx()->create_render_pass(createInfo); +} + +void SMAAPass::create_pipelines() { + auto gfx = engine->get_gfx(); + + GFXGraphicsPipelineCreateInfo createInfo = {}; + createInfo.label = "SMAA Edge"; + createInfo.shaders.vertex_path = "edge.vert"; + createInfo.shaders.fragment_path = "edge.frag"; + + createInfo.render_pass = render_pass; + + createInfo.shader_input.push_constants = { + {sizeof(Vector4) + sizeof(Matrix4x4), 0} + }; + + createInfo.shader_input.bindings = { + {0, GFXBindingType::Texture}, + {1, GFXBindingType::Texture}, + {2, GFXBindingType::PushConstant} + }; + + edge_pipeline = gfx->create_graphics_pipeline(createInfo); + + createInfo.label = "SMAA Blend"; + createInfo.shaders.vertex_path = "blend.vert"; + createInfo.shaders.fragment_path = "blend.frag"; + createInfo.shader_input.bindings.push_back({3, GFXBindingType::Texture}); + + blend_pipeline = gfx->create_graphics_pipeline(createInfo); +} + +void SMAAPass::create_offscreen_resources() { + auto gfx = engine->get_gfx(); + + GFXTextureCreateInfo textureInfo = {}; + textureInfo.width = extent.width; + textureInfo.height = extent.height; + textureInfo.format = GFXPixelFormat::R16G16B16A16_SFLOAT; + textureInfo.usage = GFXTextureUsage::Attachment | GFXTextureUsage::Sampled; + + edge_texture = gfx->create_texture(textureInfo); + blend_texture = gfx->create_texture(textureInfo); + + GFXFramebufferCreateInfo framebufferInfo = {}; + framebufferInfo.attachments = {edge_texture}; + framebufferInfo.render_pass = render_pass; + + edge_framebuffer = gfx->create_framebuffer(framebufferInfo); + + framebufferInfo.attachments = {blend_texture}; + + blend_framebuffer = gfx->create_framebuffer(framebufferInfo); +} diff --git a/engine/tests/CMakeLists.txt b/engine/tests/CMakeLists.txt new file mode 100644 index 0000000..2cca27d --- /dev/null +++ b/engine/tests/CMakeLists.txt @@ -0,0 +1,7 @@ +add_executable(Tests + tests.cpp + string_tests.cpp + utility_tests.cpp) +target_link_libraries(Tests PUBLIC doctest Utility) +set_output_dir(Tests) +set_engine_properties(Tests) diff --git a/engine/tests/string_tests.cpp b/engine/tests/string_tests.cpp new file mode 100644 index 0000000..8f29a28 --- /dev/null +++ b/engine/tests/string_tests.cpp @@ -0,0 +1,49 @@ +#include + +#include "string_utils.hpp" + +TEST_SUITE_BEGIN("String Utilities"); + +TEST_CASE("Remove substring") { + std::string str = "foobar"; + + CHECK(remove_substring(str, "foo") == "bar"); + CHECK(remove_substring(str, "bar") == "foo"); +} + +TEST_CASE("Replace substring") { + std::string str = "foobar"; + + CHECK(replace_substring(str, "foo", "bar") == "barbar"); + CHECK(replace_substring(str, "bar", "foo") == "foofoo"); +} + +TEST_CASE("String contains") { + std::string str = "foobar"; + + CHECK(string_contains(str, "foo") == true); + CHECK(string_contains(str, "bar") == true); + CHECK(string_contains(str, "farboo") == false); +} + +TEST_CASE("String starts with") { + std::string str = "(win)and(lose)"; + + CHECK(string_starts_with(str, "(") == true); + CHECK(string_starts_with(str, "(win)") == true); + CHECK(string_starts_with(str, "(lose)") == false); +} + +TEST_CASE("Tokenize") { + std::string first_case = "1,2,3"; + + CHECK(tokenize(first_case) == std::vector({"1", "2", "3"})); + + SUBCASE("Alternative delimiters") { + std::string second_case = "1-2-3"; + + CHECK(tokenize(second_case, "-") == std::vector({"1", "2", "3"})); + } +} + +TEST_SUITE_END(); diff --git a/engine/tests/tests.cpp b/engine/tests/tests.cpp new file mode 100644 index 0000000..6b306db --- /dev/null +++ b/engine/tests/tests.cpp @@ -0,0 +1,3 @@ +#define DOCTEST_CONFIG_COLORS_NONE +#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN +#include diff --git a/engine/tests/utility_tests.cpp b/engine/tests/utility_tests.cpp new file mode 100644 index 0000000..32b0aa3 --- /dev/null +++ b/engine/tests/utility_tests.cpp @@ -0,0 +1,17 @@ +#include + +#include "utility.hpp" + +TEST_SUITE_BEGIN("General Utilities"); + +TEST_CASE("Enum to string") { + enum TestEnum { + A, + B + }; + + CHECK(utility::enum_to_string(TestEnum::A) == "A"); + CHECK(utility::enum_to_string(TestEnum::B) == "B"); +} + +TEST_SUITE_END(); diff --git a/engine/utility/CMakeLists.txt b/engine/utility/CMakeLists.txt new file mode 100755 index 0000000..ec34d3e --- /dev/null +++ b/engine/utility/CMakeLists.txt @@ -0,0 +1,13 @@ +set(SRC + include/utility.hpp + include/json_conversions.hpp + include/string_utils.hpp + include/timer.hpp + include/common.hpp + include/aabb.hpp + + src/string_utils.cpp) + +add_library(Utility ${SRC}) +target_link_libraries(Utility PUBLIC Math magic_enum) +target_include_directories(Utility PUBLIC include) diff --git a/engine/utility/include/aabb.hpp b/engine/utility/include/aabb.hpp new file mode 100755 index 0000000..e1c14a7 --- /dev/null +++ b/engine/utility/include/aabb.hpp @@ -0,0 +1,23 @@ +#pragma once + +#include + +#include "vector.hpp" + +/// A 3D axis aligned bounding box. +struct AABB { + Vector3 min, max; +}; + +/// Creates an array of 8 points, each of these being one extreme of the bounding box.. +inline std::array get_points(const AABB& aabb) { + return { + Vector3(aabb.min.x, aabb.min.y, aabb.min.z), + Vector3(aabb.max.x, aabb.min.y, aabb.min.z), + Vector3(aabb.min.x, aabb.max.y, aabb.min.z), + Vector3(aabb.max.x, aabb.max.y, aabb.min.z), + Vector3(aabb.min.x, aabb.min.y, aabb.max.z), + Vector3(aabb.max.x, aabb.min.y, aabb.max.z), + Vector3(aabb.min.x, aabb.max.y, aabb.max.z), + Vector3(aabb.max.x, aabb.max.y, aabb.max.z)}; +} diff --git a/engine/utility/include/assertions.hpp b/engine/utility/include/assertions.hpp new file mode 100755 index 0000000..51c496c --- /dev/null +++ b/engine/utility/include/assertions.hpp @@ -0,0 +1,5 @@ +#pragma once + +#include + +#define Expects(x) assert(x) diff --git a/engine/utility/include/common.hpp b/engine/utility/include/common.hpp new file mode 100755 index 0000000..24fb256 --- /dev/null +++ b/engine/utility/include/common.hpp @@ -0,0 +1,29 @@ +#pragma once + +#include + +/// A 2D extent. +struct Extent { + Extent() : width(0), height(0) {} + Extent(const uint32_t width, const uint32_t height) : width(width), height(height) {} + + uint32_t width = 0, height = 0; +}; + +/// A 2D offset. +struct Offset { + Offset() : x(0), y(0) {} + Offset(const int32_t x, const int32_t y) : x(x), y(y) {} + + int32_t x = 0, y = 0; +}; + +/// A 2D rectangle defined by a offset and an etent. +struct Rectangle { + Rectangle() {} + Rectangle(const Offset offset, const Extent extent) : offset(offset), extent(extent) {} + Rectangle(const int32_t x, const int32_t y, const uint32_t width, const uint32_t height) : offset(x, y), extent(width, height) {} + + Offset offset; + Extent extent; +}; diff --git a/engine/utility/include/json_conversions.hpp b/engine/utility/include/json_conversions.hpp new file mode 100755 index 0000000..128f3d1 --- /dev/null +++ b/engine/utility/include/json_conversions.hpp @@ -0,0 +1,32 @@ +#pragma once + +#include + +#include "vector.hpp" +#include "quaternion.hpp" + +inline void to_json(nlohmann::json& j, const Vector3& p) { + j["x"] = p.x; + j["y"] = p.y; + j["z"] = p.z; +} + +inline void from_json(const nlohmann::json& j, Vector3& p) { + p.x = j["x"]; + p.y = j["y"]; + p.z = j["z"]; +} + +inline void to_json(nlohmann::json& j, const Quaternion& p) { + j["x"] = p.x; + j["y"] = p.y; + j["z"] = p.z; + j["w"] = p.w; +} + +inline void from_json(const nlohmann::json& j, Quaternion& p) { + p.x = j["x"]; + p.y = j["y"]; + p.z = j["z"]; + p.w = j["w"]; +} diff --git a/engine/utility/include/string_utils.hpp b/engine/utility/include/string_utils.hpp new file mode 100755 index 0000000..2063dd9 --- /dev/null +++ b/engine/utility/include/string_utils.hpp @@ -0,0 +1,30 @@ +#pragma once + +#include +#include +#include + +std::string remove_substring(const std::string_view string, const std::string_view substring); +std::string replace_substring(const std::string_view string, const std::string_view substring, const std::string_view replacement); + +bool string_contains(const std::string_view a, const std::string_view b); +bool string_starts_with(const std::string_view haystack, const std::string_view needle); + +std::vector tokenize(const std::string_view string, const std::string_view& delimiters = ","); + +namespace utility { + template + inline void format_internal_format(std::string& msg, const Arg& arg) { + auto pos = msg.find_first_of("{}"); + msg.replace(pos, 2, arg); + } + + template + std::string format(const std::string_view format, Args&&... args) { + auto msg = std::string(format); + + ((format_internal_format(msg, args)), ...); + + return msg; + } +} diff --git a/engine/utility/include/timer.hpp b/engine/utility/include/timer.hpp new file mode 100755 index 0000000..6f93024 --- /dev/null +++ b/engine/utility/include/timer.hpp @@ -0,0 +1,18 @@ +#pragma once + +#include + +struct Timer { + std::function callback; + + float duration = 0.0f; + + float current_time = 0.0f; + + bool remove_on_trigger = true; + bool continue_during_pause = true; +}; + +inline bool operator==(const Timer& a, const Timer& b) { + return a.duration == b.duration && a.current_time == b.current_time; +} diff --git a/engine/utility/include/utility.hpp b/engine/utility/include/utility.hpp new file mode 100755 index 0000000..b163038 --- /dev/null +++ b/engine/utility/include/utility.hpp @@ -0,0 +1,98 @@ +#pragma once + +#include + +#include +#include +#include +#include + +namespace utility { + template + std::string enum_to_string(const Enum e) { + const std::string_view name = magic_enum::enum_name(e); + + std::string s = name.data(); + return s.substr(0, name.length()); + } + + template + void erase_if(std::vector& vec, const F& f) { + vec.erase(std::remove_if(vec.begin(), vec.end(), f), vec.end()); + } + + template + void erase(std::vector& vec, const V& t) { + vec.erase(std::remove(vec.begin(), vec.end(), t), vec.end()); + } + + template + void erase_at(std::vector& vec, const int index) { + vec.erase(vec.begin() + index); + } + + inline int get_random(const int min, const int max) { + std::random_device rd; + std::mt19937 eng(rd()); + std::uniform_int_distribution<> distr(min, max); + + return distr(eng); + } + + inline int get_random(const int max) { + return get_random(0, max); + } + + template + inline auto get_random(const std::vector& vec) { + return vec[get_random(static_cast(vec.size() - 1))]; + } + + template + inline auto get_random(const std::array& vec) { + return vec[get_random(static_cast(vec.size() - 1))]; + } + + template + inline auto get_random(const std::unordered_map& map) { + const auto item = map.begin(); + std::advance(item, get_random(static_cast(map.size() - 1))); + + return item; + } + + template())), class = decltype(std::end(std::declval()))> + constexpr auto enumerate(T&& iterable) + { + struct iterator { + size_t i; + TIter iter; + bool operator != (const iterator & other) const { return iter != other.iter; } + void operator ++ () { ++i; ++iter; } + auto operator * () const { return std::tie(i, *iter); } + }; + + struct iterable_wrapper { + T iterable; + auto begin() { return iterator{ 0, std::begin(iterable) }; } + auto end() { return iterator{ 0, std::end(iterable) }; } + }; + + return iterable_wrapper{ std::forward(iterable) }; + } + + template + inline bool contains(const std::vector& vec, const V& val) { + return std::count(vec.begin(), vec.end(), val); + } + + /// Packs two 16-bit unsigned ints into one 32 bit unsigned integer. + inline uint32_t pack_u32(const uint16_t a, const uint16_t b) { + return (b << 16) | a; + } + + /// Converts a floating-point to a fixed 16-bit unsigned integer. + inline uint16_t to_fixed(const float f) { + return static_cast(32.0f * f + 0.5f); + } +} diff --git a/engine/utility/src/string_utils.cpp b/engine/utility/src/string_utils.cpp new file mode 100644 index 0000000..391a676 --- /dev/null +++ b/engine/utility/src/string_utils.cpp @@ -0,0 +1,54 @@ +#include "string_utils.hpp" + +std::string remove_substring(const std::string_view string, const std::string_view substring) { + std::string result(string); + + const auto substring_length = substring.length(); + for(auto i = result.find(substring); i != std::string::npos; i = result.find(substring)) + result.erase(i, substring_length); + + return result; +} + +std::string replace_substring(const std::string_view string, const std::string_view substring, const std::string_view replacement) { + std::string result(string); + + const auto substring_length = substring.length(); + size_t i = 0; + while((i = result.find(substring, i)) != std::string::npos) { + result.erase(i, substring_length); + result.insert(i, replacement); + i += replacement.length(); + } + + return result; +} + +bool string_contains(const std::string_view a, const std::string_view b) { + return a.find(b) != std::string::npos; +} + +bool string_starts_with(const std::string_view haystack, const std::string_view needle) { + return needle.length() <= haystack.length() + && std::equal(needle.begin(), needle.end(), haystack.begin()); +} + +std::vector tokenize(const std::string_view string, const std::string_view& delimiters) { + std::vector tokens; + + const size_t length = string.length(); + size_t lastPos = 0; + + while(lastPos < length + 1) { + size_t pos = string.find_first_of(delimiters, lastPos); + if(pos == std::string_view::npos) + pos = length; + + if(pos != lastPos) + tokens.emplace_back(string.data() + lastPos, pos - lastPos); + + lastPos = pos + 1; + } + + return tokens; +} diff --git a/extern/CMakeLists.txt b/extern/CMakeLists.txt new file mode 100755 index 0000000..0295885 --- /dev/null +++ b/extern/CMakeLists.txt @@ -0,0 +1,49 @@ +set(CMAKE_FOLDER "External") + +if(${CMAKE_SYSTEM_NAME} STREQUAL "Windows") + +else() + add_definitions(-Wno-everything) +endif() + +set(OPUS_INSTALL_CMAKE_CONFIG_MODULE OFF CACHE BOOL "" FORCE) +set(BUILD_TESTING OFF CACHE BOOL "" FORCE) + +add_subdirectory(stb) +add_subdirectory(imgui) +add_subdirectory(magic_enum) +add_subdirectory(smaa) +add_subdirectory(sol) +add_subdirectory(doctest) + +include(FetchContent) + +FetchContent_Declare(json + GIT_REPOSITORY https://github.com/ArthurSonzogni/nlohmann_json_cmake_fetchcontent.git + GIT_TAG v3.9.1) + +FetchContent_GetProperties(json) +if(NOT json_POPULATED) + FetchContent_Populate(json) + add_subdirectory(${json_SOURCE_DIR} ${json_BINARY_DIR} EXCLUDE_FROM_ALL) +endif() + +if(NOT ENABLE_IOS AND NOT ENABLE_TVOS) +add_subdirectory(ogg) +add_subdirectory(opus) + +add_library(opusfile + opusfile/src/opusfile.c + opusfile/src/info.c + opusfile/src/internal.c + opusfile/src/stream.c) +target_include_directories(opusfile + PUBLIC + opusfile/include) +target_link_libraries(opusfile + PUBLIC + ogg + opus) + + add_subdirectory(portaudio) +endif() diff --git a/extern/doctest/CMakeLists.txt b/extern/doctest/CMakeLists.txt new file mode 100755 index 0000000..9c7b490 --- /dev/null +++ b/extern/doctest/CMakeLists.txt @@ -0,0 +1,2 @@ +add_library(doctest INTERFACE) +target_include_directories(doctest INTERFACE include) \ No newline at end of file diff --git a/extern/doctest/include/doctest.h b/extern/doctest/include/doctest.h new file mode 100644 index 0000000..86f6f24 --- /dev/null +++ b/extern/doctest/include/doctest.h @@ -0,0 +1,6000 @@ +// ====================================================================== lgtm [cpp/missing-header-guard] +// == DO NOT MODIFY THIS FILE BY HAND - IT IS AUTO GENERATED BY CMAKE! == +// ====================================================================== +// +// doctest.h - the lightest feature-rich C++ single-header testing framework for unit tests and TDD +// +// Copyright (c) 2016-2019 Viktor Kirilov +// +// Distributed under the MIT Software License +// See accompanying file LICENSE.txt or copy at +// https://opensource.org/licenses/MIT +// +// The documentation can be found at the library's page: +// https://github.com/onqtam/doctest/blob/master/doc/markdown/readme.md +// +// ================================================================================================= +// ================================================================================================= +// ================================================================================================= +// +// The library is heavily influenced by Catch - https://github.com/catchorg/Catch2 +// which uses the Boost Software License - Version 1.0 +// see here - https://github.com/catchorg/Catch2/blob/master/LICENSE.txt +// +// The concept of subcases (sections in Catch) and expression decomposition are from there. +// Some parts of the code are taken directly: +// - stringification - the detection of "ostream& operator<<(ostream&, const T&)" and StringMaker<> +// - the Approx() helper class for floating point comparison +// - colors in the console +// - breaking into a debugger +// - signal / SEH handling +// - timer +// - XmlWriter class - thanks to Phil Nash for allowing the direct reuse (AKA copy/paste) +// +// The expression decomposing templates are taken from lest - https://github.com/martinmoene/lest +// which uses the Boost Software License - Version 1.0 +// see here - https://github.com/martinmoene/lest/blob/master/LICENSE.txt +// +// ================================================================================================= +// ================================================================================================= +// ================================================================================================= + +#ifndef DOCTEST_LIBRARY_INCLUDED +#define DOCTEST_LIBRARY_INCLUDED + +// ================================================================================================= +// == VERSION ====================================================================================== +// ================================================================================================= + +#define DOCTEST_VERSION_MAJOR 2 +#define DOCTEST_VERSION_MINOR 3 +#define DOCTEST_VERSION_PATCH 8 +#define DOCTEST_VERSION_STR "2.3.8" + +#define DOCTEST_VERSION \ + (DOCTEST_VERSION_MAJOR * 10000 + DOCTEST_VERSION_MINOR * 100 + DOCTEST_VERSION_PATCH) + +// ================================================================================================= +// == COMPILER VERSION ============================================================================= +// ================================================================================================= + +// ideas for the version stuff are taken from here: https://github.com/cxxstuff/cxx_detect + +#define DOCTEST_COMPILER(MAJOR, MINOR, PATCH) ((MAJOR)*10000000 + (MINOR)*100000 + (PATCH)) + +// GCC/Clang and GCC/MSVC are mutually exclusive, but Clang/MSVC are not because of clang-cl... +#if defined(_MSC_VER) && defined(_MSC_FULL_VER) +#if _MSC_VER == _MSC_FULL_VER / 10000 +#define DOCTEST_MSVC DOCTEST_COMPILER(_MSC_VER / 100, _MSC_VER % 100, _MSC_FULL_VER % 10000) +#else // MSVC +#define DOCTEST_MSVC \ + DOCTEST_COMPILER(_MSC_VER / 100, (_MSC_FULL_VER / 100000) % 100, _MSC_FULL_VER % 100000) +#endif // MSVC +#endif // MSVC +#if defined(__clang__) && defined(__clang_minor__) +#define DOCTEST_CLANG DOCTEST_COMPILER(__clang_major__, __clang_minor__, __clang_patchlevel__) +#elif defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__) && \ + !defined(__INTEL_COMPILER) +#define DOCTEST_GCC DOCTEST_COMPILER(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__) +#endif // GCC + +#ifndef DOCTEST_MSVC +#define DOCTEST_MSVC 0 +#endif // DOCTEST_MSVC +#ifndef DOCTEST_CLANG +#define DOCTEST_CLANG 0 +#endif // DOCTEST_CLANG +#ifndef DOCTEST_GCC +#define DOCTEST_GCC 0 +#endif // DOCTEST_GCC + +// ================================================================================================= +// == COMPILER WARNINGS HELPERS ==================================================================== +// ================================================================================================= + +#if DOCTEST_CLANG +#define DOCTEST_PRAGMA_TO_STR(x) _Pragma(#x) +#define DOCTEST_CLANG_SUPPRESS_WARNING_PUSH _Pragma("clang diagnostic push") +#define DOCTEST_CLANG_SUPPRESS_WARNING(w) DOCTEST_PRAGMA_TO_STR(clang diagnostic ignored w) +#define DOCTEST_CLANG_SUPPRESS_WARNING_POP _Pragma("clang diagnostic pop") +#define DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH(w) \ + DOCTEST_CLANG_SUPPRESS_WARNING_PUSH DOCTEST_CLANG_SUPPRESS_WARNING(w) +#else // DOCTEST_CLANG +#define DOCTEST_CLANG_SUPPRESS_WARNING_PUSH +#define DOCTEST_CLANG_SUPPRESS_WARNING(w) +#define DOCTEST_CLANG_SUPPRESS_WARNING_POP +#define DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH(w) +#endif // DOCTEST_CLANG + +#if DOCTEST_GCC +#define DOCTEST_PRAGMA_TO_STR(x) _Pragma(#x) +#define DOCTEST_GCC_SUPPRESS_WARNING_PUSH _Pragma("GCC diagnostic push") +#define DOCTEST_GCC_SUPPRESS_WARNING(w) DOCTEST_PRAGMA_TO_STR(GCC diagnostic ignored w) +#define DOCTEST_GCC_SUPPRESS_WARNING_POP _Pragma("GCC diagnostic pop") +#define DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH(w) \ + DOCTEST_GCC_SUPPRESS_WARNING_PUSH DOCTEST_GCC_SUPPRESS_WARNING(w) +#else // DOCTEST_GCC +#define DOCTEST_GCC_SUPPRESS_WARNING_PUSH +#define DOCTEST_GCC_SUPPRESS_WARNING(w) +#define DOCTEST_GCC_SUPPRESS_WARNING_POP +#define DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH(w) +#endif // DOCTEST_GCC + +#if DOCTEST_MSVC +#define DOCTEST_MSVC_SUPPRESS_WARNING_PUSH __pragma(warning(push)) +#define DOCTEST_MSVC_SUPPRESS_WARNING(w) __pragma(warning(disable : w)) +#define DOCTEST_MSVC_SUPPRESS_WARNING_POP __pragma(warning(pop)) +#define DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(w) \ + DOCTEST_MSVC_SUPPRESS_WARNING_PUSH DOCTEST_MSVC_SUPPRESS_WARNING(w) +#else // DOCTEST_MSVC +#define DOCTEST_MSVC_SUPPRESS_WARNING_PUSH +#define DOCTEST_MSVC_SUPPRESS_WARNING(w) +#define DOCTEST_MSVC_SUPPRESS_WARNING_POP +#define DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(w) +#endif // DOCTEST_MSVC + +// ================================================================================================= +// == COMPILER WARNINGS ============================================================================ +// ================================================================================================= + +DOCTEST_CLANG_SUPPRESS_WARNING_PUSH +DOCTEST_CLANG_SUPPRESS_WARNING("-Wunknown-pragmas") +DOCTEST_CLANG_SUPPRESS_WARNING("-Wnon-virtual-dtor") +DOCTEST_CLANG_SUPPRESS_WARNING("-Wweak-vtables") +DOCTEST_CLANG_SUPPRESS_WARNING("-Wpadded") +DOCTEST_CLANG_SUPPRESS_WARNING("-Wdeprecated") +DOCTEST_CLANG_SUPPRESS_WARNING("-Wmissing-prototypes") +DOCTEST_CLANG_SUPPRESS_WARNING("-Wunused-local-typedef") +DOCTEST_CLANG_SUPPRESS_WARNING("-Wc++98-compat") +DOCTEST_CLANG_SUPPRESS_WARNING("-Wc++98-compat-pedantic") + +DOCTEST_GCC_SUPPRESS_WARNING_PUSH +DOCTEST_GCC_SUPPRESS_WARNING("-Wunknown-pragmas") +DOCTEST_GCC_SUPPRESS_WARNING("-Wpragmas") +DOCTEST_GCC_SUPPRESS_WARNING("-Weffc++") +DOCTEST_GCC_SUPPRESS_WARNING("-Wstrict-overflow") +DOCTEST_GCC_SUPPRESS_WARNING("-Wstrict-aliasing") +DOCTEST_GCC_SUPPRESS_WARNING("-Wctor-dtor-privacy") +DOCTEST_GCC_SUPPRESS_WARNING("-Wmissing-declarations") +DOCTEST_GCC_SUPPRESS_WARNING("-Wnon-virtual-dtor") +DOCTEST_GCC_SUPPRESS_WARNING("-Wunused-local-typedefs") +DOCTEST_GCC_SUPPRESS_WARNING("-Wuseless-cast") +DOCTEST_GCC_SUPPRESS_WARNING("-Wnoexcept") +DOCTEST_GCC_SUPPRESS_WARNING("-Wsign-promo") + +DOCTEST_MSVC_SUPPRESS_WARNING_PUSH +DOCTEST_MSVC_SUPPRESS_WARNING(4616) // invalid compiler warning +DOCTEST_MSVC_SUPPRESS_WARNING(4619) // invalid compiler warning +DOCTEST_MSVC_SUPPRESS_WARNING(4996) // The compiler encountered a deprecated declaration +DOCTEST_MSVC_SUPPRESS_WARNING(4706) // assignment within conditional expression +DOCTEST_MSVC_SUPPRESS_WARNING(4512) // 'class' : assignment operator could not be generated +DOCTEST_MSVC_SUPPRESS_WARNING(4127) // conditional expression is constant +DOCTEST_MSVC_SUPPRESS_WARNING(4820) // padding +DOCTEST_MSVC_SUPPRESS_WARNING(4625) // copy constructor was implicitly defined as deleted +DOCTEST_MSVC_SUPPRESS_WARNING(4626) // assignment operator was implicitly defined as deleted +DOCTEST_MSVC_SUPPRESS_WARNING(5027) // move assignment operator was implicitly defined as deleted +DOCTEST_MSVC_SUPPRESS_WARNING(5026) // move constructor was implicitly defined as deleted +DOCTEST_MSVC_SUPPRESS_WARNING(4623) // default constructor was implicitly defined as deleted +DOCTEST_MSVC_SUPPRESS_WARNING(4640) // construction of local static object is not thread-safe +// static analysis +DOCTEST_MSVC_SUPPRESS_WARNING(26439) // This kind of function may not throw. Declare it 'noexcept' +DOCTEST_MSVC_SUPPRESS_WARNING(26495) // Always initialize a member variable +DOCTEST_MSVC_SUPPRESS_WARNING(26451) // Arithmetic overflow ... +DOCTEST_MSVC_SUPPRESS_WARNING(26444) // Avoid unnamed objects with custom construction and dtr... +DOCTEST_MSVC_SUPPRESS_WARNING(26812) // Prefer 'enum class' over 'enum' + +// 4548 - expression before comma has no effect; expected expression with side - effect +// 4265 - class has virtual functions, but destructor is not virtual +// 4986 - exception specification does not match previous declaration +// 4350 - behavior change: 'member1' called instead of 'member2' +// 4668 - 'x' is not defined as a preprocessor macro, replacing with '0' for '#if/#elif' +// 4365 - conversion from 'int' to 'unsigned long', signed/unsigned mismatch +// 4774 - format string expected in argument 'x' is not a string literal +// 4820 - padding in structs + +// only 4 should be disabled globally: +// - 4514 # unreferenced inline function has been removed +// - 4571 # SEH related +// - 4710 # function not inlined +// - 4711 # function 'x' selected for automatic inline expansion + +#define DOCTEST_MAKE_STD_HEADERS_CLEAN_FROM_WARNINGS_ON_WALL_BEGIN \ + DOCTEST_MSVC_SUPPRESS_WARNING_PUSH \ + DOCTEST_MSVC_SUPPRESS_WARNING(4548) \ + DOCTEST_MSVC_SUPPRESS_WARNING(4265) \ + DOCTEST_MSVC_SUPPRESS_WARNING(4986) \ + DOCTEST_MSVC_SUPPRESS_WARNING(4350) \ + DOCTEST_MSVC_SUPPRESS_WARNING(4668) \ + DOCTEST_MSVC_SUPPRESS_WARNING(4365) \ + DOCTEST_MSVC_SUPPRESS_WARNING(4774) \ + DOCTEST_MSVC_SUPPRESS_WARNING(4820) \ + DOCTEST_MSVC_SUPPRESS_WARNING(4625) \ + DOCTEST_MSVC_SUPPRESS_WARNING(4626) \ + DOCTEST_MSVC_SUPPRESS_WARNING(5027) \ + DOCTEST_MSVC_SUPPRESS_WARNING(5026) \ + DOCTEST_MSVC_SUPPRESS_WARNING(4623) \ + DOCTEST_MSVC_SUPPRESS_WARNING(5039) \ + DOCTEST_MSVC_SUPPRESS_WARNING(5045) \ + DOCTEST_MSVC_SUPPRESS_WARNING(5105) + +#define DOCTEST_MAKE_STD_HEADERS_CLEAN_FROM_WARNINGS_ON_WALL_END DOCTEST_MSVC_SUPPRESS_WARNING_POP + +// ================================================================================================= +// == FEATURE DETECTION ============================================================================ +// ================================================================================================= + +// general compiler feature support table: https://en.cppreference.com/w/cpp/compiler_support +// MSVC C++11 feature support table: https://msdn.microsoft.com/en-us/library/hh567368.aspx +// GCC C++11 feature support table: https://gcc.gnu.org/projects/cxx-status.html +// MSVC version table: +// https://en.wikipedia.org/wiki/Microsoft_Visual_C%2B%2B#Internal_version_numbering +// MSVC++ 14.2 (16) _MSC_VER == 1920 (Visual Studio 2019) +// MSVC++ 14.1 (15) _MSC_VER == 1910 (Visual Studio 2017) +// MSVC++ 14.0 _MSC_VER == 1900 (Visual Studio 2015) +// MSVC++ 12.0 _MSC_VER == 1800 (Visual Studio 2013) +// MSVC++ 11.0 _MSC_VER == 1700 (Visual Studio 2012) +// MSVC++ 10.0 _MSC_VER == 1600 (Visual Studio 2010) +// MSVC++ 9.0 _MSC_VER == 1500 (Visual Studio 2008) +// MSVC++ 8.0 _MSC_VER == 1400 (Visual Studio 2005) + +#if DOCTEST_MSVC && !defined(DOCTEST_CONFIG_WINDOWS_SEH) +#define DOCTEST_CONFIG_WINDOWS_SEH +#endif // MSVC +#if defined(DOCTEST_CONFIG_NO_WINDOWS_SEH) && defined(DOCTEST_CONFIG_WINDOWS_SEH) +#undef DOCTEST_CONFIG_WINDOWS_SEH +#endif // DOCTEST_CONFIG_NO_WINDOWS_SEH + +#if !defined(_WIN32) && !defined(__QNX__) && !defined(DOCTEST_CONFIG_POSIX_SIGNALS) && \ + !defined(__EMSCRIPTEN__) +#define DOCTEST_CONFIG_POSIX_SIGNALS +#endif // _WIN32 +#if defined(DOCTEST_CONFIG_NO_POSIX_SIGNALS) && defined(DOCTEST_CONFIG_POSIX_SIGNALS) +#undef DOCTEST_CONFIG_POSIX_SIGNALS +#endif // DOCTEST_CONFIG_NO_POSIX_SIGNALS + +#ifndef DOCTEST_CONFIG_NO_EXCEPTIONS +#if !defined(__cpp_exceptions) && !defined(__EXCEPTIONS) && !defined(_CPPUNWIND) +#define DOCTEST_CONFIG_NO_EXCEPTIONS +#endif // no exceptions +#endif // DOCTEST_CONFIG_NO_EXCEPTIONS + +#ifdef DOCTEST_CONFIG_NO_EXCEPTIONS_BUT_WITH_ALL_ASSERTS +#ifndef DOCTEST_CONFIG_NO_EXCEPTIONS +#define DOCTEST_CONFIG_NO_EXCEPTIONS +#endif // DOCTEST_CONFIG_NO_EXCEPTIONS +#endif // DOCTEST_CONFIG_NO_EXCEPTIONS_BUT_WITH_ALL_ASSERTS + +#if defined(DOCTEST_CONFIG_NO_EXCEPTIONS) && !defined(DOCTEST_CONFIG_NO_TRY_CATCH_IN_ASSERTS) +#define DOCTEST_CONFIG_NO_TRY_CATCH_IN_ASSERTS +#endif // DOCTEST_CONFIG_NO_EXCEPTIONS && !DOCTEST_CONFIG_NO_TRY_CATCH_IN_ASSERTS + +#if defined(DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN) && !defined(DOCTEST_CONFIG_IMPLEMENT) +#define DOCTEST_CONFIG_IMPLEMENT +#endif // DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN + +#if defined(_WIN32) || defined(__CYGWIN__) +#if DOCTEST_MSVC +#define DOCTEST_SYMBOL_EXPORT __declspec(dllexport) +#define DOCTEST_SYMBOL_IMPORT __declspec(dllimport) +#else // MSVC +#define DOCTEST_SYMBOL_EXPORT __attribute__((dllexport)) +#define DOCTEST_SYMBOL_IMPORT __attribute__((dllimport)) +#endif // MSVC +#else // _WIN32 +#define DOCTEST_SYMBOL_EXPORT __attribute__((visibility("default"))) +#define DOCTEST_SYMBOL_IMPORT +#endif // _WIN32 + +#ifdef DOCTEST_CONFIG_IMPLEMENTATION_IN_DLL +#ifdef DOCTEST_CONFIG_IMPLEMENT +#define DOCTEST_INTERFACE DOCTEST_SYMBOL_EXPORT +#else // DOCTEST_CONFIG_IMPLEMENT +#define DOCTEST_INTERFACE DOCTEST_SYMBOL_IMPORT +#endif // DOCTEST_CONFIG_IMPLEMENT +#else // DOCTEST_CONFIG_IMPLEMENTATION_IN_DLL +#define DOCTEST_INTERFACE +#endif // DOCTEST_CONFIG_IMPLEMENTATION_IN_DLL + +#define DOCTEST_EMPTY + +#if DOCTEST_MSVC +#define DOCTEST_NOINLINE __declspec(noinline) +#define DOCTEST_UNUSED +#define DOCTEST_ALIGNMENT(x) +#else // MSVC +#define DOCTEST_NOINLINE __attribute__((noinline)) +#define DOCTEST_UNUSED __attribute__((unused)) +#define DOCTEST_ALIGNMENT(x) __attribute__((aligned(x))) +#endif // MSVC + +#ifndef DOCTEST_NORETURN +#define DOCTEST_NORETURN [[noreturn]] +#endif // DOCTEST_NORETURN + +#ifndef DOCTEST_NOEXCEPT +#define DOCTEST_NOEXCEPT noexcept +#endif // DOCTEST_NOEXCEPT + +// ================================================================================================= +// == FEATURE DETECTION END ======================================================================== +// ================================================================================================= + +// internal macros for string concatenation and anonymous variable name generation +#define DOCTEST_CAT_IMPL(s1, s2) s1##s2 +#define DOCTEST_CAT(s1, s2) DOCTEST_CAT_IMPL(s1, s2) +#ifdef __COUNTER__ // not standard and may be missing for some compilers +#define DOCTEST_ANONYMOUS(x) DOCTEST_CAT(x, __COUNTER__) +#else // __COUNTER__ +#define DOCTEST_ANONYMOUS(x) DOCTEST_CAT(x, __LINE__) +#endif // __COUNTER__ + +#define DOCTEST_TOSTR(x) #x + +#ifndef DOCTEST_CONFIG_ASSERTION_PARAMETERS_BY_VALUE +#define DOCTEST_REF_WRAP(x) x& +#else // DOCTEST_CONFIG_ASSERTION_PARAMETERS_BY_VALUE +#define DOCTEST_REF_WRAP(x) x +#endif // DOCTEST_CONFIG_ASSERTION_PARAMETERS_BY_VALUE + +// not using __APPLE__ because... this is how Catch does it +#ifdef __MAC_OS_X_VERSION_MIN_REQUIRED +#define DOCTEST_PLATFORM_MAC +#elif defined(__IPHONE_OS_VERSION_MIN_REQUIRED) +#define DOCTEST_PLATFORM_IPHONE +#elif defined(_WIN32) +#define DOCTEST_PLATFORM_WINDOWS +#else // DOCTEST_PLATFORM +#define DOCTEST_PLATFORM_LINUX +#endif // DOCTEST_PLATFORM + +#define DOCTEST_GLOBAL_NO_WARNINGS(var) \ + DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wglobal-constructors") \ + DOCTEST_CLANG_SUPPRESS_WARNING("-Wunused-variable") \ + static int var DOCTEST_UNUSED // NOLINT(fuchsia-statically-constructed-objects,cert-err58-cpp) +#define DOCTEST_GLOBAL_NO_WARNINGS_END() DOCTEST_CLANG_SUPPRESS_WARNING_POP + +#ifndef DOCTEST_BREAK_INTO_DEBUGGER +// should probably take a look at https://github.com/scottt/debugbreak +#ifdef DOCTEST_PLATFORM_MAC +#define DOCTEST_BREAK_INTO_DEBUGGER() __asm__("int $3\n" : :) +#elif DOCTEST_MSVC +#define DOCTEST_BREAK_INTO_DEBUGGER() __debugbreak() +#elif defined(__MINGW32__) +DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH("-Wredundant-decls") +extern "C" __declspec(dllimport) void __stdcall DebugBreak(); +DOCTEST_GCC_SUPPRESS_WARNING_POP +#define DOCTEST_BREAK_INTO_DEBUGGER() ::DebugBreak() +#else // linux +#define DOCTEST_BREAK_INTO_DEBUGGER() ((void)0) +#endif // linux +#endif // DOCTEST_BREAK_INTO_DEBUGGER + +// this is kept here for backwards compatibility since the config option was changed +#ifdef DOCTEST_CONFIG_USE_IOSFWD +#define DOCTEST_CONFIG_USE_STD_HEADERS +#endif // DOCTEST_CONFIG_USE_IOSFWD + +#ifdef DOCTEST_CONFIG_USE_STD_HEADERS +#include +#include +#include +#else // DOCTEST_CONFIG_USE_STD_HEADERS + +#if DOCTEST_CLANG +// to detect if libc++ is being used with clang (the _LIBCPP_VERSION identifier) +#include +#endif // clang + +#ifdef _LIBCPP_VERSION +#define DOCTEST_STD_NAMESPACE_BEGIN _LIBCPP_BEGIN_NAMESPACE_STD +#define DOCTEST_STD_NAMESPACE_END _LIBCPP_END_NAMESPACE_STD +#else // _LIBCPP_VERSION +#define DOCTEST_STD_NAMESPACE_BEGIN namespace std { +#define DOCTEST_STD_NAMESPACE_END } +#endif // _LIBCPP_VERSION + +// Forward declaring 'X' in namespace std is not permitted by the C++ Standard. +DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4643) + +DOCTEST_STD_NAMESPACE_BEGIN // NOLINT (cert-dcl58-cpp) +typedef decltype(nullptr) nullptr_t; +template +struct char_traits; +template <> +struct char_traits; +template +class basic_ostream; +typedef basic_ostream> ostream; +template +class tuple; +#if DOCTEST_MSVC >= DOCTEST_COMPILER(19, 20, 0) +// see this issue on why this is needed: https://github.com/onqtam/doctest/issues/183 +template +class allocator; +template +class basic_string; +using string = basic_string, allocator>; +#endif // VS 2019 +DOCTEST_STD_NAMESPACE_END + +DOCTEST_MSVC_SUPPRESS_WARNING_POP + +#endif // DOCTEST_CONFIG_USE_STD_HEADERS + +#ifdef DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS +#include +#endif // DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS + +namespace doctest { + +DOCTEST_INTERFACE extern bool is_running_in_test; + +// A 24 byte string class (can be as small as 17 for x64 and 13 for x86) that can hold strings with length +// of up to 23 chars on the stack before going on the heap - the last byte of the buffer is used for: +// - "is small" bit - the highest bit - if "0" then it is small - otherwise its "1" (128) +// - if small - capacity left before going on the heap - using the lowest 5 bits +// - if small - 2 bits are left unused - the second and third highest ones +// - if small - acts as a null terminator if strlen() is 23 (24 including the null terminator) +// and the "is small" bit remains "0" ("as well as the capacity left") so its OK +// Idea taken from this lecture about the string implementation of facebook/folly - fbstring +// https://www.youtube.com/watch?v=kPR8h4-qZdk +// TODO: +// - optimizations - like not deleting memory unnecessarily in operator= and etc. +// - resize/reserve/clear +// - substr +// - replace +// - back/front +// - iterator stuff +// - find & friends +// - push_back/pop_back +// - assign/insert/erase +// - relational operators as free functions - taking const char* as one of the params +class DOCTEST_INTERFACE String +{ + static const unsigned len = 24; //!OCLINT avoid private static members + static const unsigned last = len - 1; //!OCLINT avoid private static members + + struct view // len should be more than sizeof(view) - because of the final byte for flags + { + char* ptr; + unsigned size; + unsigned capacity; + }; + + union + { + char buf[len]; + view data; + }; + + bool isOnStack() const { return (buf[last] & 128) == 0; } + void setOnHeap(); + void setLast(unsigned in = last); + + void copy(const String& other); + +public: + String(); + ~String(); + + // cppcheck-suppress noExplicitConstructor + String(const char* in); + String(const char* in, unsigned in_size); + + String(const String& other); + String& operator=(const String& other); + + String& operator+=(const String& other); + String operator+(const String& other) const; + + String(String&& other); + String& operator=(String&& other); + + char operator[](unsigned i) const; + char& operator[](unsigned i); + + // the only functions I'm willing to leave in the interface - available for inlining + const char* c_str() const { return const_cast(this)->c_str(); } // NOLINT + char* c_str() { + if(isOnStack()) + return reinterpret_cast(buf); + return data.ptr; + } + + unsigned size() const; + unsigned capacity() const; + + int compare(const char* other, bool no_case = false) const; + int compare(const String& other, bool no_case = false) const; +}; + +DOCTEST_INTERFACE bool operator==(const String& lhs, const String& rhs); +DOCTEST_INTERFACE bool operator!=(const String& lhs, const String& rhs); +DOCTEST_INTERFACE bool operator<(const String& lhs, const String& rhs); +DOCTEST_INTERFACE bool operator>(const String& lhs, const String& rhs); +DOCTEST_INTERFACE bool operator<=(const String& lhs, const String& rhs); +DOCTEST_INTERFACE bool operator>=(const String& lhs, const String& rhs); + +DOCTEST_INTERFACE std::ostream& operator<<(std::ostream& s, const String& in); + +namespace Color { + enum Enum + { + None = 0, + White, + Red, + Green, + Blue, + Cyan, + Yellow, + Grey, + + Bright = 0x10, + + BrightRed = Bright | Red, + BrightGreen = Bright | Green, + LightGrey = Bright | Grey, + BrightWhite = Bright | White + }; + + DOCTEST_INTERFACE std::ostream& operator<<(std::ostream& s, Color::Enum code); +} // namespace Color + +namespace assertType { + enum Enum + { + // macro traits + + is_warn = 1, + is_check = 2 * is_warn, + is_require = 2 * is_check, + + is_normal = 2 * is_require, + is_throws = 2 * is_normal, + is_throws_as = 2 * is_throws, + is_throws_with = 2 * is_throws_as, + is_nothrow = 2 * is_throws_with, + + is_false = 2 * is_nothrow, + is_unary = 2 * is_false, // not checked anywhere - used just to distinguish the types + + is_eq = 2 * is_unary, + is_ne = 2 * is_eq, + + is_lt = 2 * is_ne, + is_gt = 2 * is_lt, + + is_ge = 2 * is_gt, + is_le = 2 * is_ge, + + // macro types + + DT_WARN = is_normal | is_warn, + DT_CHECK = is_normal | is_check, + DT_REQUIRE = is_normal | is_require, + + DT_WARN_FALSE = is_normal | is_false | is_warn, + DT_CHECK_FALSE = is_normal | is_false | is_check, + DT_REQUIRE_FALSE = is_normal | is_false | is_require, + + DT_WARN_THROWS = is_throws | is_warn, + DT_CHECK_THROWS = is_throws | is_check, + DT_REQUIRE_THROWS = is_throws | is_require, + + DT_WARN_THROWS_AS = is_throws_as | is_warn, + DT_CHECK_THROWS_AS = is_throws_as | is_check, + DT_REQUIRE_THROWS_AS = is_throws_as | is_require, + + DT_WARN_THROWS_WITH = is_throws_with | is_warn, + DT_CHECK_THROWS_WITH = is_throws_with | is_check, + DT_REQUIRE_THROWS_WITH = is_throws_with | is_require, + + DT_WARN_THROWS_WITH_AS = is_throws_with | is_throws_as | is_warn, + DT_CHECK_THROWS_WITH_AS = is_throws_with | is_throws_as | is_check, + DT_REQUIRE_THROWS_WITH_AS = is_throws_with | is_throws_as | is_require, + + DT_WARN_NOTHROW = is_nothrow | is_warn, + DT_CHECK_NOTHROW = is_nothrow | is_check, + DT_REQUIRE_NOTHROW = is_nothrow | is_require, + + DT_WARN_EQ = is_normal | is_eq | is_warn, + DT_CHECK_EQ = is_normal | is_eq | is_check, + DT_REQUIRE_EQ = is_normal | is_eq | is_require, + + DT_WARN_NE = is_normal | is_ne | is_warn, + DT_CHECK_NE = is_normal | is_ne | is_check, + DT_REQUIRE_NE = is_normal | is_ne | is_require, + + DT_WARN_GT = is_normal | is_gt | is_warn, + DT_CHECK_GT = is_normal | is_gt | is_check, + DT_REQUIRE_GT = is_normal | is_gt | is_require, + + DT_WARN_LT = is_normal | is_lt | is_warn, + DT_CHECK_LT = is_normal | is_lt | is_check, + DT_REQUIRE_LT = is_normal | is_lt | is_require, + + DT_WARN_GE = is_normal | is_ge | is_warn, + DT_CHECK_GE = is_normal | is_ge | is_check, + DT_REQUIRE_GE = is_normal | is_ge | is_require, + + DT_WARN_LE = is_normal | is_le | is_warn, + DT_CHECK_LE = is_normal | is_le | is_check, + DT_REQUIRE_LE = is_normal | is_le | is_require, + + DT_WARN_UNARY = is_normal | is_unary | is_warn, + DT_CHECK_UNARY = is_normal | is_unary | is_check, + DT_REQUIRE_UNARY = is_normal | is_unary | is_require, + + DT_WARN_UNARY_FALSE = is_normal | is_false | is_unary | is_warn, + DT_CHECK_UNARY_FALSE = is_normal | is_false | is_unary | is_check, + DT_REQUIRE_UNARY_FALSE = is_normal | is_false | is_unary | is_require, + }; +} // namespace assertType + +DOCTEST_INTERFACE const char* assertString(assertType::Enum at); +DOCTEST_INTERFACE const char* failureString(assertType::Enum at); +DOCTEST_INTERFACE const char* skipPathFromFilename(const char* file); + +struct DOCTEST_INTERFACE TestCaseData +{ + String m_file; // the file in which the test was registered + unsigned m_line; // the line where the test was registered + const char* m_name; // name of the test case + const char* m_test_suite; // the test suite in which the test was added + const char* m_description; + bool m_skip; + bool m_may_fail; + bool m_should_fail; + int m_expected_failures; + double m_timeout; +}; + +struct DOCTEST_INTERFACE AssertData +{ + // common - for all asserts + const TestCaseData* m_test_case; + assertType::Enum m_at; + const char* m_file; + int m_line; + const char* m_expr; + bool m_failed; + + // exception-related - for all asserts + bool m_threw; + String m_exception; + + // for normal asserts + String m_decomp; + + // for specific exception-related asserts + bool m_threw_as; + const char* m_exception_type; + const char* m_exception_string; +}; + +struct DOCTEST_INTERFACE MessageData +{ + String m_string; + const char* m_file; + int m_line; + assertType::Enum m_severity; +}; + +struct DOCTEST_INTERFACE SubcaseSignature +{ + String m_name; + const char* m_file; + int m_line; + + bool operator<(const SubcaseSignature& other) const; +}; + +struct DOCTEST_INTERFACE IContextScope +{ + IContextScope(); + virtual ~IContextScope(); + virtual void stringify(std::ostream*) const = 0; +}; + +struct ContextOptions //!OCLINT too many fields +{ + std::ostream* cout; // stdout stream - std::cout by default + std::ostream* cerr; // stderr stream - std::cerr by default + String binary_name; // the test binary name + + // == parameters from the command line + String out; // output filename + String order_by; // how tests should be ordered + unsigned rand_seed; // the seed for rand ordering + + unsigned first; // the first (matching) test to be executed + unsigned last; // the last (matching) test to be executed + + int abort_after; // stop tests after this many failed assertions + int subcase_filter_levels; // apply the subcase filters for the first N levels + + bool success; // include successful assertions in output + bool case_sensitive; // if filtering should be case sensitive + bool exit; // if the program should be exited after the tests are ran/whatever + bool duration; // print the time duration of each test case + bool no_throw; // to skip exceptions-related assertion macros + bool no_exitcode; // if the framework should return 0 as the exitcode + bool no_run; // to not run the tests at all (can be done with an "*" exclude) + bool no_version; // to not print the version of the framework + bool no_colors; // if output to the console should be colorized + bool force_colors; // forces the use of colors even when a tty cannot be detected + bool no_breaks; // to not break into the debugger + bool no_skip; // don't skip test cases which are marked to be skipped + bool gnu_file_line; // if line numbers should be surrounded with :x: and not (x): + bool no_path_in_filenames; // if the path to files should be removed from the output + bool no_line_numbers; // if source code line numbers should be omitted from the output + bool no_skipped_summary; // don't print "skipped" in the summary !!! UNDOCUMENTED !!! + + bool help; // to print the help + bool version; // to print the version + bool count; // if only the count of matching tests is to be retrieved + bool list_test_cases; // to list all tests matching the filters + bool list_test_suites; // to list all suites matching the filters + bool list_reporters; // lists all registered reporters +}; + +namespace detail { +#if defined(DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING) || defined(DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS) + template + struct enable_if + {}; + + template + struct enable_if + { typedef TYPE type; }; +#endif // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING) || DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS + + // clang-format off + template struct remove_reference { typedef T type; }; + template struct remove_reference { typedef T type; }; + template struct remove_reference { typedef T type; }; + + template struct remove_const { typedef T type; }; + template struct remove_const { typedef T type; }; + // clang-format on + + template + struct deferred_false + // cppcheck-suppress unusedStructMember + { static const bool value = false; }; + + namespace has_insertion_operator_impl { + typedef char no; + typedef char yes[2]; + + struct any_t + { + template + // cppcheck-suppress noExplicitConstructor + any_t(const DOCTEST_REF_WRAP(T)); + }; + + yes& testStreamable(std::ostream&); + no testStreamable(no); + + no operator<<(const std::ostream&, const any_t&); + + template + struct has_insertion_operator + { + static std::ostream& s; + static const DOCTEST_REF_WRAP(T) t; + static const bool value = sizeof(decltype(testStreamable(s << t))) == sizeof(yes); + }; + } // namespace has_insertion_operator_impl + + template + struct has_insertion_operator : has_insertion_operator_impl::has_insertion_operator + {}; + + DOCTEST_INTERFACE void my_memcpy(void* dest, const void* src, unsigned num); + + DOCTEST_INTERFACE std::ostream* getTlsOss(); // returns a thread-local ostringstream + DOCTEST_INTERFACE String getTlsOssResult(); + + template + struct StringMakerBase + { + template + static String convert(const DOCTEST_REF_WRAP(T)) { + return "{?}"; + } + }; + + template <> + struct StringMakerBase + { + template + static String convert(const DOCTEST_REF_WRAP(T) in) { + *getTlsOss() << in; + return getTlsOssResult(); + } + }; + + DOCTEST_INTERFACE String rawMemoryToString(const void* object, unsigned size); + + template + String rawMemoryToString(const DOCTEST_REF_WRAP(T) object) { + return rawMemoryToString(&object, sizeof(object)); + } + + template + const char* type_to_string() { + return "<>"; + } +} // namespace detail + +template +struct StringMaker : public detail::StringMakerBase::value> +{}; + +template +struct StringMaker +{ + template + static String convert(U* p) { + if(p) + return detail::rawMemoryToString(p); + return "NULL"; + } +}; + +template +struct StringMaker +{ + static String convert(R C::*p) { + if(p) + return detail::rawMemoryToString(p); + return "NULL"; + } +}; + +template +String toString(const DOCTEST_REF_WRAP(T) value) { + return StringMaker::convert(value); +} + +#ifdef DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING +DOCTEST_INTERFACE String toString(char* in); +DOCTEST_INTERFACE String toString(const char* in); +#endif // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING +DOCTEST_INTERFACE String toString(bool in); +DOCTEST_INTERFACE String toString(float in); +DOCTEST_INTERFACE String toString(double in); +DOCTEST_INTERFACE String toString(double long in); + +DOCTEST_INTERFACE String toString(char in); +DOCTEST_INTERFACE String toString(char signed in); +DOCTEST_INTERFACE String toString(char unsigned in); +DOCTEST_INTERFACE String toString(int short in); +DOCTEST_INTERFACE String toString(int short unsigned in); +DOCTEST_INTERFACE String toString(int in); +DOCTEST_INTERFACE String toString(int unsigned in); +DOCTEST_INTERFACE String toString(int long in); +DOCTEST_INTERFACE String toString(int long unsigned in); +DOCTEST_INTERFACE String toString(int long long in); +DOCTEST_INTERFACE String toString(int long long unsigned in); +DOCTEST_INTERFACE String toString(std::nullptr_t in); + +#if DOCTEST_MSVC >= DOCTEST_COMPILER(19, 20, 0) +// see this issue on why this is needed: https://github.com/onqtam/doctest/issues/183 +DOCTEST_INTERFACE String toString(const std::string& in); +#endif // VS 2019 + +class DOCTEST_INTERFACE Approx +{ +public: + explicit Approx(double value); + + Approx operator()(double value) const; + +#ifdef DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS + template + explicit Approx(const T& value, + typename detail::enable_if::value>::type* = + static_cast(nullptr)) { + *this = Approx(static_cast(value)); + } +#endif // DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS + + Approx& epsilon(double newEpsilon); + +#ifdef DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS + template + typename detail::enable_if::value, Approx&>::type epsilon( + const T& newEpsilon) { + m_epsilon = static_cast(newEpsilon); + return *this; + } +#endif // DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS + + Approx& scale(double newScale); + +#ifdef DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS + template + typename detail::enable_if::value, Approx&>::type scale( + const T& newScale) { + m_scale = static_cast(newScale); + return *this; + } +#endif // DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS + + // clang-format off + DOCTEST_INTERFACE friend bool operator==(double lhs, const Approx & rhs); + DOCTEST_INTERFACE friend bool operator==(const Approx & lhs, double rhs); + DOCTEST_INTERFACE friend bool operator!=(double lhs, const Approx & rhs); + DOCTEST_INTERFACE friend bool operator!=(const Approx & lhs, double rhs); + DOCTEST_INTERFACE friend bool operator<=(double lhs, const Approx & rhs); + DOCTEST_INTERFACE friend bool operator<=(const Approx & lhs, double rhs); + DOCTEST_INTERFACE friend bool operator>=(double lhs, const Approx & rhs); + DOCTEST_INTERFACE friend bool operator>=(const Approx & lhs, double rhs); + DOCTEST_INTERFACE friend bool operator< (double lhs, const Approx & rhs); + DOCTEST_INTERFACE friend bool operator< (const Approx & lhs, double rhs); + DOCTEST_INTERFACE friend bool operator> (double lhs, const Approx & rhs); + DOCTEST_INTERFACE friend bool operator> (const Approx & lhs, double rhs); + + DOCTEST_INTERFACE friend String toString(const Approx& in); + +#ifdef DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS +#define DOCTEST_APPROX_PREFIX \ + template friend typename detail::enable_if::value, bool>::type + + DOCTEST_APPROX_PREFIX operator==(const T& lhs, const Approx& rhs) { return operator==(double(lhs), rhs); } + DOCTEST_APPROX_PREFIX operator==(const Approx& lhs, const T& rhs) { return operator==(rhs, lhs); } + DOCTEST_APPROX_PREFIX operator!=(const T& lhs, const Approx& rhs) { return !operator==(lhs, rhs); } + DOCTEST_APPROX_PREFIX operator!=(const Approx& lhs, const T& rhs) { return !operator==(rhs, lhs); } + DOCTEST_APPROX_PREFIX operator<=(const T& lhs, const Approx& rhs) { return double(lhs) < rhs.m_value || lhs == rhs; } + DOCTEST_APPROX_PREFIX operator<=(const Approx& lhs, const T& rhs) { return lhs.m_value < double(rhs) || lhs == rhs; } + DOCTEST_APPROX_PREFIX operator>=(const T& lhs, const Approx& rhs) { return double(lhs) > rhs.m_value || lhs == rhs; } + DOCTEST_APPROX_PREFIX operator>=(const Approx& lhs, const T& rhs) { return lhs.m_value > double(rhs) || lhs == rhs; } + DOCTEST_APPROX_PREFIX operator< (const T& lhs, const Approx& rhs) { return double(lhs) < rhs.m_value && lhs != rhs; } + DOCTEST_APPROX_PREFIX operator< (const Approx& lhs, const T& rhs) { return lhs.m_value < double(rhs) && lhs != rhs; } + DOCTEST_APPROX_PREFIX operator> (const T& lhs, const Approx& rhs) { return double(lhs) > rhs.m_value && lhs != rhs; } + DOCTEST_APPROX_PREFIX operator> (const Approx& lhs, const T& rhs) { return lhs.m_value > double(rhs) && lhs != rhs; } +#undef DOCTEST_APPROX_PREFIX +#endif // DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS + + // clang-format on + +private: + double m_epsilon; + double m_scale; + double m_value; +}; + +DOCTEST_INTERFACE String toString(const Approx& in); + +DOCTEST_INTERFACE const ContextOptions* getContextOptions(); + +#if !defined(DOCTEST_CONFIG_DISABLE) + +namespace detail { + // clang-format off +#ifdef DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING + template struct decay_array { typedef T type; }; + template struct decay_array { typedef T* type; }; + template struct decay_array { typedef T* type; }; + + template struct not_char_pointer { enum { value = 1 }; }; + template<> struct not_char_pointer { enum { value = 0 }; }; + template<> struct not_char_pointer { enum { value = 0 }; }; + + template struct can_use_op : public not_char_pointer::type> {}; +#endif // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING + // clang-format on + + struct DOCTEST_INTERFACE TestFailureException + { + }; + + DOCTEST_INTERFACE bool checkIfShouldThrow(assertType::Enum at); + +#ifndef DOCTEST_CONFIG_NO_EXCEPTIONS + DOCTEST_NORETURN +#endif // DOCTEST_CONFIG_NO_EXCEPTIONS + DOCTEST_INTERFACE void throwException(); + + struct DOCTEST_INTERFACE Subcase + { + SubcaseSignature m_signature; + bool m_entered = false; + + Subcase(const String& name, const char* file, int line); + ~Subcase(); + + operator bool() const; + }; + + template + String stringifyBinaryExpr(const DOCTEST_REF_WRAP(L) lhs, const char* op, + const DOCTEST_REF_WRAP(R) rhs) { + return toString(lhs) + op + toString(rhs); + } + +#define DOCTEST_DO_BINARY_EXPRESSION_COMPARISON(op, op_str, op_macro) \ + template \ + DOCTEST_NOINLINE Result operator op(const DOCTEST_REF_WRAP(R) rhs) { \ + bool res = op_macro(lhs, rhs); \ + if(m_at & assertType::is_false) \ + res = !res; \ + if(!res || doctest::getContextOptions()->success) \ + return Result(res, stringifyBinaryExpr(lhs, op_str, rhs)); \ + return Result(res); \ + } + + // more checks could be added - like in Catch: + // https://github.com/catchorg/Catch2/pull/1480/files + // https://github.com/catchorg/Catch2/pull/1481/files +#define DOCTEST_FORBIT_EXPRESSION(rt, op) \ + template \ + rt& operator op(const R&) { \ + static_assert(deferred_false::value, \ + "Expression Too Complex Please Rewrite As Binary Comparison!"); \ + return *this; \ + } + + struct DOCTEST_INTERFACE Result + { + bool m_passed; + String m_decomp; + + Result(bool passed, const String& decomposition = String()); + + // forbidding some expressions based on this table: https://en.cppreference.com/w/cpp/language/operator_precedence + DOCTEST_FORBIT_EXPRESSION(Result, &) + DOCTEST_FORBIT_EXPRESSION(Result, ^) + DOCTEST_FORBIT_EXPRESSION(Result, |) + DOCTEST_FORBIT_EXPRESSION(Result, &&) + DOCTEST_FORBIT_EXPRESSION(Result, ||) + DOCTEST_FORBIT_EXPRESSION(Result, ==) + DOCTEST_FORBIT_EXPRESSION(Result, !=) + DOCTEST_FORBIT_EXPRESSION(Result, <) + DOCTEST_FORBIT_EXPRESSION(Result, >) + DOCTEST_FORBIT_EXPRESSION(Result, <=) + DOCTEST_FORBIT_EXPRESSION(Result, >=) + DOCTEST_FORBIT_EXPRESSION(Result, =) + DOCTEST_FORBIT_EXPRESSION(Result, +=) + DOCTEST_FORBIT_EXPRESSION(Result, -=) + DOCTEST_FORBIT_EXPRESSION(Result, *=) + DOCTEST_FORBIT_EXPRESSION(Result, /=) + DOCTEST_FORBIT_EXPRESSION(Result, %=) + DOCTEST_FORBIT_EXPRESSION(Result, <<=) + DOCTEST_FORBIT_EXPRESSION(Result, >>=) + DOCTEST_FORBIT_EXPRESSION(Result, &=) + DOCTEST_FORBIT_EXPRESSION(Result, ^=) + DOCTEST_FORBIT_EXPRESSION(Result, |=) + }; + +#ifndef DOCTEST_CONFIG_NO_COMPARISON_WARNING_SUPPRESSION + + DOCTEST_CLANG_SUPPRESS_WARNING_PUSH + DOCTEST_CLANG_SUPPRESS_WARNING("-Wsign-conversion") + DOCTEST_CLANG_SUPPRESS_WARNING("-Wsign-compare") + //DOCTEST_CLANG_SUPPRESS_WARNING("-Wdouble-promotion") + //DOCTEST_CLANG_SUPPRESS_WARNING("-Wconversion") + //DOCTEST_CLANG_SUPPRESS_WARNING("-Wfloat-equal") + + DOCTEST_GCC_SUPPRESS_WARNING_PUSH + DOCTEST_GCC_SUPPRESS_WARNING("-Wsign-conversion") + DOCTEST_GCC_SUPPRESS_WARNING("-Wsign-compare") + //DOCTEST_GCC_SUPPRESS_WARNING("-Wdouble-promotion") + //DOCTEST_GCC_SUPPRESS_WARNING("-Wconversion") + //DOCTEST_GCC_SUPPRESS_WARNING("-Wfloat-equal") + + DOCTEST_MSVC_SUPPRESS_WARNING_PUSH + // https://stackoverflow.com/questions/39479163 what's the difference between 4018 and 4389 + DOCTEST_MSVC_SUPPRESS_WARNING(4388) // signed/unsigned mismatch + DOCTEST_MSVC_SUPPRESS_WARNING(4389) // 'operator' : signed/unsigned mismatch + DOCTEST_MSVC_SUPPRESS_WARNING(4018) // 'expression' : signed/unsigned mismatch + //DOCTEST_MSVC_SUPPRESS_WARNING(4805) // 'operation' : unsafe mix of type 'type' and type 'type' in operation + +#endif // DOCTEST_CONFIG_NO_COMPARISON_WARNING_SUPPRESSION + + // clang-format off +#ifndef DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING +#define DOCTEST_COMPARISON_RETURN_TYPE bool +#else // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING +#define DOCTEST_COMPARISON_RETURN_TYPE typename enable_if::value || can_use_op::value, bool>::type + inline bool eq(const char* lhs, const char* rhs) { return String(lhs) == String(rhs); } + inline bool ne(const char* lhs, const char* rhs) { return String(lhs) != String(rhs); } + inline bool lt(const char* lhs, const char* rhs) { return String(lhs) < String(rhs); } + inline bool gt(const char* lhs, const char* rhs) { return String(lhs) > String(rhs); } + inline bool le(const char* lhs, const char* rhs) { return String(lhs) <= String(rhs); } + inline bool ge(const char* lhs, const char* rhs) { return String(lhs) >= String(rhs); } +#endif // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING + // clang-format on + +#define DOCTEST_RELATIONAL_OP(name, op) \ + template \ + DOCTEST_COMPARISON_RETURN_TYPE name(const DOCTEST_REF_WRAP(L) lhs, \ + const DOCTEST_REF_WRAP(R) rhs) { \ + return lhs op rhs; \ + } + + DOCTEST_RELATIONAL_OP(eq, ==) + DOCTEST_RELATIONAL_OP(ne, !=) + DOCTEST_RELATIONAL_OP(lt, <) + DOCTEST_RELATIONAL_OP(gt, >) + DOCTEST_RELATIONAL_OP(le, <=) + DOCTEST_RELATIONAL_OP(ge, >=) + +#ifndef DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING +#define DOCTEST_CMP_EQ(l, r) l == r +#define DOCTEST_CMP_NE(l, r) l != r +#define DOCTEST_CMP_GT(l, r) l > r +#define DOCTEST_CMP_LT(l, r) l < r +#define DOCTEST_CMP_GE(l, r) l >= r +#define DOCTEST_CMP_LE(l, r) l <= r +#else // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING +#define DOCTEST_CMP_EQ(l, r) eq(l, r) +#define DOCTEST_CMP_NE(l, r) ne(l, r) +#define DOCTEST_CMP_GT(l, r) gt(l, r) +#define DOCTEST_CMP_LT(l, r) lt(l, r) +#define DOCTEST_CMP_GE(l, r) ge(l, r) +#define DOCTEST_CMP_LE(l, r) le(l, r) +#endif // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING + + template + // cppcheck-suppress copyCtorAndEqOperator + struct Expression_lhs + { + L lhs; + assertType::Enum m_at; + + explicit Expression_lhs(L in, assertType::Enum at) + : lhs(in) + , m_at(at) {} + + DOCTEST_NOINLINE operator Result() { + bool res = !!lhs; + if(m_at & assertType::is_false) //!OCLINT bitwise operator in conditional + res = !res; + + if(!res || getContextOptions()->success) + return Result(res, toString(lhs)); + return Result(res); + } + + // clang-format off + DOCTEST_DO_BINARY_EXPRESSION_COMPARISON(==, " == ", DOCTEST_CMP_EQ) //!OCLINT bitwise operator in conditional + DOCTEST_DO_BINARY_EXPRESSION_COMPARISON(!=, " != ", DOCTEST_CMP_NE) //!OCLINT bitwise operator in conditional + DOCTEST_DO_BINARY_EXPRESSION_COMPARISON(>, " > ", DOCTEST_CMP_GT) //!OCLINT bitwise operator in conditional + DOCTEST_DO_BINARY_EXPRESSION_COMPARISON(<, " < ", DOCTEST_CMP_LT) //!OCLINT bitwise operator in conditional + DOCTEST_DO_BINARY_EXPRESSION_COMPARISON(>=, " >= ", DOCTEST_CMP_GE) //!OCLINT bitwise operator in conditional + DOCTEST_DO_BINARY_EXPRESSION_COMPARISON(<=, " <= ", DOCTEST_CMP_LE) //!OCLINT bitwise operator in conditional + // clang-format on + + // forbidding some expressions based on this table: https://en.cppreference.com/w/cpp/language/operator_precedence + DOCTEST_FORBIT_EXPRESSION(Expression_lhs, &) + DOCTEST_FORBIT_EXPRESSION(Expression_lhs, ^) + DOCTEST_FORBIT_EXPRESSION(Expression_lhs, |) + DOCTEST_FORBIT_EXPRESSION(Expression_lhs, &&) + DOCTEST_FORBIT_EXPRESSION(Expression_lhs, ||) + DOCTEST_FORBIT_EXPRESSION(Expression_lhs, =) + DOCTEST_FORBIT_EXPRESSION(Expression_lhs, +=) + DOCTEST_FORBIT_EXPRESSION(Expression_lhs, -=) + DOCTEST_FORBIT_EXPRESSION(Expression_lhs, *=) + DOCTEST_FORBIT_EXPRESSION(Expression_lhs, /=) + DOCTEST_FORBIT_EXPRESSION(Expression_lhs, %=) + DOCTEST_FORBIT_EXPRESSION(Expression_lhs, <<=) + DOCTEST_FORBIT_EXPRESSION(Expression_lhs, >>=) + DOCTEST_FORBIT_EXPRESSION(Expression_lhs, &=) + DOCTEST_FORBIT_EXPRESSION(Expression_lhs, ^=) + DOCTEST_FORBIT_EXPRESSION(Expression_lhs, |=) + // these 2 are unfortunate because they should be allowed - they have higher precedence over the comparisons, but the + // ExpressionDecomposer class uses the left shift operator to capture the left operand of the binary expression... + DOCTEST_FORBIT_EXPRESSION(Expression_lhs, <<) + DOCTEST_FORBIT_EXPRESSION(Expression_lhs, >>) + }; + +#ifndef DOCTEST_CONFIG_NO_COMPARISON_WARNING_SUPPRESSION + + DOCTEST_CLANG_SUPPRESS_WARNING_POP + DOCTEST_MSVC_SUPPRESS_WARNING_POP + DOCTEST_GCC_SUPPRESS_WARNING_POP + +#endif // DOCTEST_CONFIG_NO_COMPARISON_WARNING_SUPPRESSION + + struct DOCTEST_INTERFACE ExpressionDecomposer + { + assertType::Enum m_at; + + ExpressionDecomposer(assertType::Enum at); + + // The right operator for capturing expressions is "<=" instead of "<<" (based on the operator precedence table) + // but then there will be warnings from GCC about "-Wparentheses" and since "_Pragma()" is problematic this will stay for now... + // https://github.com/catchorg/Catch2/issues/870 + // https://github.com/catchorg/Catch2/issues/565 + template + Expression_lhs operator<<(const DOCTEST_REF_WRAP(L) operand) { + return Expression_lhs(operand, m_at); + } + }; + + struct DOCTEST_INTERFACE TestSuite + { + const char* m_test_suite; + const char* m_description; + bool m_skip; + bool m_may_fail; + bool m_should_fail; + int m_expected_failures; + double m_timeout; + + TestSuite& operator*(const char* in); + + template + TestSuite& operator*(const T& in) { + in.fill(*this); + return *this; + } + }; + + typedef void (*funcType)(); + + struct DOCTEST_INTERFACE TestCase : public TestCaseData + { + funcType m_test; // a function pointer to the test case + + const char* m_type; // for templated test cases - gets appended to the real name + int m_template_id; // an ID used to distinguish between the different versions of a templated test case + String m_full_name; // contains the name (only for templated test cases!) + the template type + + TestCase(funcType test, const char* file, unsigned line, const TestSuite& test_suite, + const char* type = "", int template_id = -1); + + TestCase(const TestCase& other); + + DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(26434) // hides a non-virtual function + TestCase& operator=(const TestCase& other); + DOCTEST_MSVC_SUPPRESS_WARNING_POP + + TestCase& operator*(const char* in); + + template + TestCase& operator*(const T& in) { + in.fill(*this); + return *this; + } + + bool operator<(const TestCase& other) const; + }; + + // forward declarations of functions used by the macros + DOCTEST_INTERFACE int regTest(const TestCase& tc); + DOCTEST_INTERFACE int setTestSuite(const TestSuite& ts); + DOCTEST_INTERFACE bool isDebuggerActive(); + + template + int instantiationHelper(const T&) { return 0; } + + namespace binaryAssertComparison { + enum Enum + { + eq = 0, + ne, + gt, + lt, + ge, + le + }; + } // namespace binaryAssertComparison + + // clang-format off + template struct RelationalComparator { bool operator()(const DOCTEST_REF_WRAP(L), const DOCTEST_REF_WRAP(R) ) const { return false; } }; + +#define DOCTEST_BINARY_RELATIONAL_OP(n, op) \ + template struct RelationalComparator { bool operator()(const DOCTEST_REF_WRAP(L) lhs, const DOCTEST_REF_WRAP(R) rhs) const { return op(lhs, rhs); } }; + // clang-format on + + DOCTEST_BINARY_RELATIONAL_OP(0, eq) + DOCTEST_BINARY_RELATIONAL_OP(1, ne) + DOCTEST_BINARY_RELATIONAL_OP(2, gt) + DOCTEST_BINARY_RELATIONAL_OP(3, lt) + DOCTEST_BINARY_RELATIONAL_OP(4, ge) + DOCTEST_BINARY_RELATIONAL_OP(5, le) + + struct DOCTEST_INTERFACE ResultBuilder : public AssertData + { + ResultBuilder(assertType::Enum at, const char* file, int line, const char* expr, + const char* exception_type = "", const char* exception_string = ""); + + void setResult(const Result& res); + + template + DOCTEST_NOINLINE void binary_assert(const DOCTEST_REF_WRAP(L) lhs, + const DOCTEST_REF_WRAP(R) rhs) { + m_failed = !RelationalComparator()(lhs, rhs); + if(m_failed || getContextOptions()->success) + m_decomp = stringifyBinaryExpr(lhs, ", ", rhs); + } + + template + DOCTEST_NOINLINE void unary_assert(const DOCTEST_REF_WRAP(L) val) { + m_failed = !val; + + if(m_at & assertType::is_false) //!OCLINT bitwise operator in conditional + m_failed = !m_failed; + + if(m_failed || getContextOptions()->success) + m_decomp = toString(val); + } + + void translateException(); + + bool log(); + void react() const; + }; + + namespace assertAction { + enum Enum + { + nothing = 0, + dbgbreak = 1, + shouldthrow = 2 + }; + } // namespace assertAction + + DOCTEST_INTERFACE void failed_out_of_a_testing_context(const AssertData& ad); + + DOCTEST_INTERFACE void decomp_assert(assertType::Enum at, const char* file, int line, + const char* expr, Result result); + +#define DOCTEST_ASSERT_OUT_OF_TESTS(decomp) \ + do { \ + if(!is_running_in_test) { \ + if(failed) { \ + ResultBuilder rb(at, file, line, expr); \ + rb.m_failed = failed; \ + rb.m_decomp = decomp; \ + failed_out_of_a_testing_context(rb); \ + if(isDebuggerActive() && !getContextOptions()->no_breaks) \ + DOCTEST_BREAK_INTO_DEBUGGER(); \ + if(checkIfShouldThrow(at)) \ + throwException(); \ + } \ + return; \ + } \ + } while(false) + +#define DOCTEST_ASSERT_IN_TESTS(decomp) \ + ResultBuilder rb(at, file, line, expr); \ + rb.m_failed = failed; \ + if(rb.m_failed || getContextOptions()->success) \ + rb.m_decomp = decomp; \ + if(rb.log()) \ + DOCTEST_BREAK_INTO_DEBUGGER(); \ + if(rb.m_failed && checkIfShouldThrow(at)) \ + throwException() + + template + DOCTEST_NOINLINE void binary_assert(assertType::Enum at, const char* file, int line, + const char* expr, const DOCTEST_REF_WRAP(L) lhs, + const DOCTEST_REF_WRAP(R) rhs) { + bool failed = !RelationalComparator()(lhs, rhs); + + // ################################################################################### + // IF THE DEBUGGER BREAKS HERE - GO 1 LEVEL UP IN THE CALLSTACK FOR THE FAILING ASSERT + // THIS IS THE EFFECT OF HAVING 'DOCTEST_CONFIG_SUPER_FAST_ASSERTS' DEFINED + // ################################################################################### + DOCTEST_ASSERT_OUT_OF_TESTS(stringifyBinaryExpr(lhs, ", ", rhs)); + DOCTEST_ASSERT_IN_TESTS(stringifyBinaryExpr(lhs, ", ", rhs)); + } + + template + DOCTEST_NOINLINE void unary_assert(assertType::Enum at, const char* file, int line, + const char* expr, const DOCTEST_REF_WRAP(L) val) { + bool failed = !val; + + if(at & assertType::is_false) //!OCLINT bitwise operator in conditional + failed = !failed; + + // ################################################################################### + // IF THE DEBUGGER BREAKS HERE - GO 1 LEVEL UP IN THE CALLSTACK FOR THE FAILING ASSERT + // THIS IS THE EFFECT OF HAVING 'DOCTEST_CONFIG_SUPER_FAST_ASSERTS' DEFINED + // ################################################################################### + DOCTEST_ASSERT_OUT_OF_TESTS(toString(val)); + DOCTEST_ASSERT_IN_TESTS(toString(val)); + } + + struct DOCTEST_INTERFACE IExceptionTranslator + { + IExceptionTranslator(); + virtual ~IExceptionTranslator(); + virtual bool translate(String&) const = 0; + }; + + template + class ExceptionTranslator : public IExceptionTranslator //!OCLINT destructor of virtual class + { + public: + explicit ExceptionTranslator(String (*translateFunction)(T)) + : m_translateFunction(translateFunction) {} + + bool translate(String& res) const override { +#ifndef DOCTEST_CONFIG_NO_EXCEPTIONS + try { + throw; // lgtm [cpp/rethrow-no-exception] + // cppcheck-suppress catchExceptionByValue + } catch(T ex) { // NOLINT + res = m_translateFunction(ex); //!OCLINT parameter reassignment + return true; + } catch(...) {} //!OCLINT - empty catch statement +#endif // DOCTEST_CONFIG_NO_EXCEPTIONS + ((void)res); // to silence -Wunused-parameter + return false; + } + + private: + String (*m_translateFunction)(T); + }; + + DOCTEST_INTERFACE void registerExceptionTranslatorImpl(const IExceptionTranslator* et); + + template + struct StringStreamBase + { + template + static void convert(std::ostream* s, const T& in) { + *s << toString(in); + } + + // always treat char* as a string in this context - no matter + // if DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING is defined + static void convert(std::ostream* s, const char* in) { *s << String(in); } + }; + + template <> + struct StringStreamBase + { + template + static void convert(std::ostream* s, const T& in) { + *s << in; + } + }; + + template + struct StringStream : public StringStreamBase::value> + {}; + + template + void toStream(std::ostream* s, const T& value) { + StringStream::convert(s, value); + } + +#ifdef DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING + DOCTEST_INTERFACE void toStream(std::ostream* s, char* in); + DOCTEST_INTERFACE void toStream(std::ostream* s, const char* in); +#endif // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING + DOCTEST_INTERFACE void toStream(std::ostream* s, bool in); + DOCTEST_INTERFACE void toStream(std::ostream* s, float in); + DOCTEST_INTERFACE void toStream(std::ostream* s, double in); + DOCTEST_INTERFACE void toStream(std::ostream* s, double long in); + + DOCTEST_INTERFACE void toStream(std::ostream* s, char in); + DOCTEST_INTERFACE void toStream(std::ostream* s, char signed in); + DOCTEST_INTERFACE void toStream(std::ostream* s, char unsigned in); + DOCTEST_INTERFACE void toStream(std::ostream* s, int short in); + DOCTEST_INTERFACE void toStream(std::ostream* s, int short unsigned in); + DOCTEST_INTERFACE void toStream(std::ostream* s, int in); + DOCTEST_INTERFACE void toStream(std::ostream* s, int unsigned in); + DOCTEST_INTERFACE void toStream(std::ostream* s, int long in); + DOCTEST_INTERFACE void toStream(std::ostream* s, int long unsigned in); + DOCTEST_INTERFACE void toStream(std::ostream* s, int long long in); + DOCTEST_INTERFACE void toStream(std::ostream* s, int long long unsigned in); + + // ContextScope base class used to allow implementing methods of ContextScope + // that don't depend on the template parameter in doctest.cpp. + class DOCTEST_INTERFACE ContextScopeBase : public IContextScope { + protected: + ContextScopeBase(); + + void destroy(); + }; + + template class ContextScope : public ContextScopeBase + { + const L &lambda_; + + public: + explicit ContextScope(const L &lambda) : lambda_(lambda) {} + + ContextScope(ContextScope &&other) : lambda_(other.lambda_) {} + + void stringify(std::ostream* s) const override { lambda_(s); } + + ~ContextScope() override { destroy(); } + }; + + struct DOCTEST_INTERFACE MessageBuilder : public MessageData + { + std::ostream* m_stream; + + MessageBuilder(const char* file, int line, assertType::Enum severity); + MessageBuilder() = delete; + ~MessageBuilder(); + + template + MessageBuilder& operator<<(const T& in) { + toStream(m_stream, in); + return *this; + } + + bool log(); + void react(); + }; + + template + ContextScope MakeContextScope(const L &lambda) { + return ContextScope(lambda); + } +} // namespace detail + +#define DOCTEST_DEFINE_DECORATOR(name, type, def) \ + struct name \ + { \ + type data; \ + name(type in = def) \ + : data(in) {} \ + void fill(detail::TestCase& state) const { state.DOCTEST_CAT(m_, name) = data; } \ + void fill(detail::TestSuite& state) const { state.DOCTEST_CAT(m_, name) = data; } \ + } + +DOCTEST_DEFINE_DECORATOR(test_suite, const char*, ""); +DOCTEST_DEFINE_DECORATOR(description, const char*, ""); +DOCTEST_DEFINE_DECORATOR(skip, bool, true); +DOCTEST_DEFINE_DECORATOR(timeout, double, 0); +DOCTEST_DEFINE_DECORATOR(may_fail, bool, true); +DOCTEST_DEFINE_DECORATOR(should_fail, bool, true); +DOCTEST_DEFINE_DECORATOR(expected_failures, int, 0); + +template +int registerExceptionTranslator(String (*translateFunction)(T)) { + DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wexit-time-destructors") + static detail::ExceptionTranslator exceptionTranslator(translateFunction); + DOCTEST_CLANG_SUPPRESS_WARNING_POP + detail::registerExceptionTranslatorImpl(&exceptionTranslator); + return 0; +} + +} // namespace doctest + +// in a separate namespace outside of doctest because the DOCTEST_TEST_SUITE macro +// introduces an anonymous namespace in which getCurrentTestSuite gets overridden +namespace doctest_detail_test_suite_ns { +DOCTEST_INTERFACE doctest::detail::TestSuite& getCurrentTestSuite(); +} // namespace doctest_detail_test_suite_ns + +namespace doctest { +#else // DOCTEST_CONFIG_DISABLE +template +int registerExceptionTranslator(String (*)(T)) { + return 0; +} +#endif // DOCTEST_CONFIG_DISABLE + +namespace detail { + typedef void (*assert_handler)(const AssertData&); + struct ContextState; +} // namespace detail + +class DOCTEST_INTERFACE Context +{ + detail::ContextState* p; + + void parseArgs(int argc, const char* const* argv, bool withDefaults = false); + +public: + explicit Context(int argc = 0, const char* const* argv = nullptr); + + ~Context(); + + void applyCommandLine(int argc, const char* const* argv); + + void addFilter(const char* filter, const char* value); + void clearFilters(); + void setOption(const char* option, int value); + void setOption(const char* option, const char* value); + + bool shouldExit(); + + void setAsDefaultForAssertsOutOfTestCases(); + + void setAssertHandler(detail::assert_handler ah); + + int run(); +}; + +namespace TestCaseFailureReason { + enum Enum + { + None = 0, + AssertFailure = 1, // an assertion has failed in the test case + Exception = 2, // test case threw an exception + Crash = 4, // a crash... + TooManyFailedAsserts = 8, // the abort-after option + Timeout = 16, // see the timeout decorator + ShouldHaveFailedButDidnt = 32, // see the should_fail decorator + ShouldHaveFailedAndDid = 64, // see the should_fail decorator + DidntFailExactlyNumTimes = 128, // see the expected_failures decorator + FailedExactlyNumTimes = 256, // see the expected_failures decorator + CouldHaveFailedAndDid = 512 // see the may_fail decorator + }; +} // namespace TestCaseFailureReason + +struct DOCTEST_INTERFACE CurrentTestCaseStats +{ + int numAssertsCurrentTest; + int numAssertsFailedCurrentTest; + double seconds; + int failure_flags; // use TestCaseFailureReason::Enum +}; + +struct DOCTEST_INTERFACE TestCaseException +{ + String error_string; + bool is_crash; +}; + +struct DOCTEST_INTERFACE TestRunStats +{ + unsigned numTestCases; + unsigned numTestCasesPassingFilters; + unsigned numTestSuitesPassingFilters; + unsigned numTestCasesFailed; + int numAsserts; + int numAssertsFailed; +}; + +struct QueryData +{ + const TestRunStats* run_stats = nullptr; + const TestCaseData** data = nullptr; + unsigned num_data = 0; +}; + +struct DOCTEST_INTERFACE IReporter +{ + // The constructor has to accept "const ContextOptions&" as a single argument + // which has most of the options for the run + a pointer to the stdout stream + // Reporter(const ContextOptions& in) + + // called when a query should be reported (listing test cases, printing the version, etc.) + virtual void report_query(const QueryData&) = 0; + + // called when the whole test run starts + virtual void test_run_start() = 0; + // called when the whole test run ends (caching a pointer to the input doesn't make sense here) + virtual void test_run_end(const TestRunStats&) = 0; + + // called when a test case is started (safe to cache a pointer to the input) + virtual void test_case_start(const TestCaseData&) = 0; + // called when a test case is reentered because of unfinished subcases (safe to cache a pointer to the input) + virtual void test_case_reenter(const TestCaseData&) = 0; + // called when a test case has ended + virtual void test_case_end(const CurrentTestCaseStats&) = 0; + + // called when an exception is thrown from the test case (or it crashes) + virtual void test_case_exception(const TestCaseException&) = 0; + + // called whenever a subcase is entered (don't cache pointers to the input) + virtual void subcase_start(const SubcaseSignature&) = 0; + // called whenever a subcase is exited (don't cache pointers to the input) + virtual void subcase_end() = 0; + + // called for each assert (don't cache pointers to the input) + virtual void log_assert(const AssertData&) = 0; + // called for each message (don't cache pointers to the input) + virtual void log_message(const MessageData&) = 0; + + // called when a test case is skipped either because it doesn't pass the filters, has a skip decorator + // or isn't in the execution range (between first and last) (safe to cache a pointer to the input) + virtual void test_case_skipped(const TestCaseData&) = 0; + + // doctest will not be managing the lifetimes of reporters given to it but this would still be nice to have + virtual ~IReporter(); + + // can obtain all currently active contexts and stringify them if one wishes to do so + static int get_num_active_contexts(); + static const IContextScope* const* get_active_contexts(); + + // can iterate through contexts which have been stringified automatically in their destructors when an exception has been thrown + static int get_num_stringified_contexts(); + static const String* get_stringified_contexts(); +}; + +namespace detail { + typedef IReporter* (*reporterCreatorFunc)(const ContextOptions&); + + DOCTEST_INTERFACE void registerReporterImpl(const char* name, int prio, reporterCreatorFunc c, bool isReporter); + + template + IReporter* reporterCreator(const ContextOptions& o) { + return new Reporter(o); + } +} // namespace detail + +template +int registerReporter(const char* name, int priority, bool isReporter) { + detail::registerReporterImpl(name, priority, detail::reporterCreator, isReporter); + return 0; +} +} // namespace doctest + +// if registering is not disabled +#if !defined(DOCTEST_CONFIG_DISABLE) + +// common code in asserts - for convenience +#define DOCTEST_ASSERT_LOG_AND_REACT(b) \ + if(b.log()) \ + DOCTEST_BREAK_INTO_DEBUGGER(); \ + b.react() + +#ifdef DOCTEST_CONFIG_NO_TRY_CATCH_IN_ASSERTS +#define DOCTEST_WRAP_IN_TRY(x) x; +#else // DOCTEST_CONFIG_NO_TRY_CATCH_IN_ASSERTS +#define DOCTEST_WRAP_IN_TRY(x) \ + try { \ + x; \ + } catch(...) { _DOCTEST_RB.translateException(); } +#endif // DOCTEST_CONFIG_NO_TRY_CATCH_IN_ASSERTS + +#ifdef DOCTEST_CONFIG_VOID_CAST_EXPRESSIONS +#define DOCTEST_CAST_TO_VOID(...) \ + DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH("-Wuseless-cast") \ + static_cast(__VA_ARGS__); \ + DOCTEST_GCC_SUPPRESS_WARNING_POP +#else // DOCTEST_CONFIG_VOID_CAST_EXPRESSIONS +#define DOCTEST_CAST_TO_VOID(...) __VA_ARGS__; +#endif // DOCTEST_CONFIG_VOID_CAST_EXPRESSIONS + +// registers the test by initializing a dummy var with a function +#define DOCTEST_REGISTER_FUNCTION(global_prefix, f, decorators) \ + global_prefix DOCTEST_GLOBAL_NO_WARNINGS(DOCTEST_ANONYMOUS(_DOCTEST_ANON_VAR_)) = \ + doctest::detail::regTest( \ + doctest::detail::TestCase( \ + f, __FILE__, __LINE__, \ + doctest_detail_test_suite_ns::getCurrentTestSuite()) * \ + decorators); \ + DOCTEST_GLOBAL_NO_WARNINGS_END() + +#define DOCTEST_IMPLEMENT_FIXTURE(der, base, func, decorators) \ + namespace { \ + struct der : public base \ + { \ + void f(); \ + }; \ + static void func() { \ + der v; \ + v.f(); \ + } \ + DOCTEST_REGISTER_FUNCTION(DOCTEST_EMPTY, func, decorators) \ + } \ + inline DOCTEST_NOINLINE void der::f() + +#define DOCTEST_CREATE_AND_REGISTER_FUNCTION(f, decorators) \ + static void f(); \ + DOCTEST_REGISTER_FUNCTION(DOCTEST_EMPTY, f, decorators) \ + static void f() + +#define DOCTEST_CREATE_AND_REGISTER_FUNCTION_IN_CLASS(f, proxy, decorators) \ + static doctest::detail::funcType proxy() { return f; } \ + DOCTEST_REGISTER_FUNCTION(inline const, proxy(), decorators) \ + static void f() + +// for registering tests +#define DOCTEST_TEST_CASE(decorators) \ + DOCTEST_CREATE_AND_REGISTER_FUNCTION(DOCTEST_ANONYMOUS(_DOCTEST_ANON_FUNC_), decorators) + +// for registering tests in classes - requires C++17 for inline variables! +#if __cplusplus >= 201703L || (DOCTEST_MSVC >= DOCTEST_COMPILER(19, 12, 0) && _MSVC_LANG >= 201703L) +#define DOCTEST_TEST_CASE_CLASS(decorators) \ + DOCTEST_CREATE_AND_REGISTER_FUNCTION_IN_CLASS(DOCTEST_ANONYMOUS(_DOCTEST_ANON_FUNC_), \ + DOCTEST_ANONYMOUS(_DOCTEST_ANON_PROXY_), \ + decorators) +#else // DOCTEST_TEST_CASE_CLASS +#define DOCTEST_TEST_CASE_CLASS(...) \ + TEST_CASES_CAN_BE_REGISTERED_IN_CLASSES_ONLY_IN_CPP17_MODE_OR_WITH_VS_2017_OR_NEWER +#endif // DOCTEST_TEST_CASE_CLASS + +// for registering tests with a fixture +#define DOCTEST_TEST_CASE_FIXTURE(c, decorators) \ + DOCTEST_IMPLEMENT_FIXTURE(DOCTEST_ANONYMOUS(_DOCTEST_ANON_CLASS_), c, \ + DOCTEST_ANONYMOUS(_DOCTEST_ANON_FUNC_), decorators) + +// for converting types to strings without the header and demangling +#define DOCTEST_TYPE_TO_STRING_IMPL(...) \ + template <> \ + inline const char* type_to_string<__VA_ARGS__>() { \ + return "<" #__VA_ARGS__ ">"; \ + } +#define DOCTEST_TYPE_TO_STRING(...) \ + namespace doctest { namespace detail { \ + DOCTEST_TYPE_TO_STRING_IMPL(__VA_ARGS__) \ + } \ + } \ + typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_) + +#define DOCTEST_TEST_CASE_TEMPLATE_DEFINE_IMPL(dec, T, iter, func) \ + template \ + static void func(); \ + namespace { \ + template \ + struct iter; \ + template \ + struct iter> \ + { \ + iter(const char* file, unsigned line, int index) { \ + doctest::detail::regTest(doctest::detail::TestCase(func, file, line, \ + doctest_detail_test_suite_ns::getCurrentTestSuite(), \ + doctest::detail::type_to_string(), \ + int(line) * 1000 + index) \ + * dec); \ + iter>(file, line, index + 1); \ + } \ + }; \ + template <> \ + struct iter> \ + { \ + iter(const char*, unsigned, int) {} \ + }; \ + } \ + template \ + static void func() + +#define DOCTEST_TEST_CASE_TEMPLATE_DEFINE(dec, T, id) \ + DOCTEST_TEST_CASE_TEMPLATE_DEFINE_IMPL(dec, T, DOCTEST_CAT(id, ITERATOR), \ + DOCTEST_ANONYMOUS(_DOCTEST_ANON_TMP_)) + +#define DOCTEST_TEST_CASE_TEMPLATE_INSTANTIATE_IMPL(id, anon, ...) \ + DOCTEST_GLOBAL_NO_WARNINGS(DOCTEST_CAT(anon, DUMMY)) = \ + doctest::detail::instantiationHelper(DOCTEST_CAT(id, ITERATOR)<__VA_ARGS__>(__FILE__, __LINE__, 0));\ + DOCTEST_GLOBAL_NO_WARNINGS_END() + +#define DOCTEST_TEST_CASE_TEMPLATE_INVOKE(id, ...) \ + DOCTEST_TEST_CASE_TEMPLATE_INSTANTIATE_IMPL(id, DOCTEST_ANONYMOUS(_DOCTEST_ANON_TMP_), std::tuple<__VA_ARGS__>) \ + typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_) + +#define DOCTEST_TEST_CASE_TEMPLATE_APPLY(id, ...) \ + DOCTEST_TEST_CASE_TEMPLATE_INSTANTIATE_IMPL(id, DOCTEST_ANONYMOUS(_DOCTEST_ANON_TMP_), __VA_ARGS__) \ + typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_) + +#define DOCTEST_TEST_CASE_TEMPLATE_IMPL(dec, T, anon, ...) \ + DOCTEST_TEST_CASE_TEMPLATE_DEFINE_IMPL(dec, T, DOCTEST_CAT(anon, ITERATOR), anon); \ + DOCTEST_TEST_CASE_TEMPLATE_INSTANTIATE_IMPL(anon, anon, std::tuple<__VA_ARGS__>) \ + template \ + static void anon() + +#define DOCTEST_TEST_CASE_TEMPLATE(dec, T, ...) \ + DOCTEST_TEST_CASE_TEMPLATE_IMPL(dec, T, DOCTEST_ANONYMOUS(_DOCTEST_ANON_TMP_), __VA_ARGS__) + +// for subcases +#define DOCTEST_SUBCASE(name) \ + if(const doctest::detail::Subcase & DOCTEST_ANONYMOUS(_DOCTEST_ANON_SUBCASE_) DOCTEST_UNUSED = \ + doctest::detail::Subcase(name, __FILE__, __LINE__)) + +// for grouping tests in test suites by using code blocks +#define DOCTEST_TEST_SUITE_IMPL(decorators, ns_name) \ + namespace ns_name { namespace doctest_detail_test_suite_ns { \ + static DOCTEST_NOINLINE doctest::detail::TestSuite& getCurrentTestSuite() { \ + DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4640) \ + DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wexit-time-destructors") \ + static doctest::detail::TestSuite data; \ + static bool inited = false; \ + DOCTEST_MSVC_SUPPRESS_WARNING_POP \ + DOCTEST_CLANG_SUPPRESS_WARNING_POP \ + if(!inited) { \ + data* decorators; \ + inited = true; \ + } \ + return data; \ + } \ + } \ + } \ + namespace ns_name + +#define DOCTEST_TEST_SUITE(decorators) \ + DOCTEST_TEST_SUITE_IMPL(decorators, DOCTEST_ANONYMOUS(_DOCTEST_ANON_SUITE_)) + +// for starting a testsuite block +#define DOCTEST_TEST_SUITE_BEGIN(decorators) \ + DOCTEST_GLOBAL_NO_WARNINGS(DOCTEST_ANONYMOUS(_DOCTEST_ANON_VAR_)) = \ + doctest::detail::setTestSuite(doctest::detail::TestSuite() * decorators); \ + DOCTEST_GLOBAL_NO_WARNINGS_END() \ + typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_) + +// for ending a testsuite block +#define DOCTEST_TEST_SUITE_END \ + DOCTEST_GLOBAL_NO_WARNINGS(DOCTEST_ANONYMOUS(_DOCTEST_ANON_VAR_)) = \ + doctest::detail::setTestSuite(doctest::detail::TestSuite() * ""); \ + DOCTEST_GLOBAL_NO_WARNINGS_END() \ + typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_) + +// for registering exception translators +#define DOCTEST_REGISTER_EXCEPTION_TRANSLATOR_IMPL(translatorName, signature) \ + inline doctest::String translatorName(signature); \ + DOCTEST_GLOBAL_NO_WARNINGS(DOCTEST_ANONYMOUS(_DOCTEST_ANON_TRANSLATOR_)) = \ + doctest::registerExceptionTranslator(translatorName); \ + DOCTEST_GLOBAL_NO_WARNINGS_END() \ + doctest::String translatorName(signature) + +#define DOCTEST_REGISTER_EXCEPTION_TRANSLATOR(signature) \ + DOCTEST_REGISTER_EXCEPTION_TRANSLATOR_IMPL(DOCTEST_ANONYMOUS(_DOCTEST_ANON_TRANSLATOR_), \ + signature) + +// for registering reporters +#define DOCTEST_REGISTER_REPORTER(name, priority, reporter) \ + DOCTEST_GLOBAL_NO_WARNINGS(DOCTEST_ANONYMOUS(_DOCTEST_ANON_REPORTER_)) = \ + doctest::registerReporter(name, priority, true); \ + DOCTEST_GLOBAL_NO_WARNINGS_END() typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_) + +// for registering listeners +#define DOCTEST_REGISTER_LISTENER(name, priority, reporter) \ + DOCTEST_GLOBAL_NO_WARNINGS(DOCTEST_ANONYMOUS(_DOCTEST_ANON_REPORTER_)) = \ + doctest::registerReporter(name, priority, false); \ + DOCTEST_GLOBAL_NO_WARNINGS_END() typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_) + +// for logging +#define DOCTEST_INFO(expression) \ + DOCTEST_INFO_IMPL(DOCTEST_ANONYMOUS(_DOCTEST_CAPTURE_), DOCTEST_ANONYMOUS(_DOCTEST_CAPTURE_), \ + DOCTEST_ANONYMOUS(_DOCTEST_CAPTURE_), expression) + +#define DOCTEST_INFO_IMPL(lambda_name, mb_name, s_name, expression) \ + DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4626) \ + auto lambda_name = [&](std::ostream* s_name) { \ + doctest::detail::MessageBuilder mb_name(__FILE__, __LINE__, doctest::assertType::is_warn); \ + mb_name.m_stream = s_name; \ + mb_name << expression; \ + }; \ + DOCTEST_MSVC_SUPPRESS_WARNING_POP \ + auto DOCTEST_ANONYMOUS(_DOCTEST_CAPTURE_) = doctest::detail::MakeContextScope(lambda_name) + +#define DOCTEST_CAPTURE(x) DOCTEST_INFO(#x " := " << x) + +#define DOCTEST_ADD_AT_IMPL(type, file, line, mb, x) \ + do { \ + doctest::detail::MessageBuilder mb(file, line, doctest::assertType::type); \ + mb << x; \ + DOCTEST_ASSERT_LOG_AND_REACT(mb); \ + } while(false) + +// clang-format off +#define DOCTEST_ADD_MESSAGE_AT(file, line, x) DOCTEST_ADD_AT_IMPL(is_warn, file, line, DOCTEST_ANONYMOUS(_DOCTEST_MESSAGE_), x) +#define DOCTEST_ADD_FAIL_CHECK_AT(file, line, x) DOCTEST_ADD_AT_IMPL(is_check, file, line, DOCTEST_ANONYMOUS(_DOCTEST_MESSAGE_), x) +#define DOCTEST_ADD_FAIL_AT(file, line, x) DOCTEST_ADD_AT_IMPL(is_require, file, line, DOCTEST_ANONYMOUS(_DOCTEST_MESSAGE_), x) +// clang-format on + +#define DOCTEST_MESSAGE(x) DOCTEST_ADD_MESSAGE_AT(__FILE__, __LINE__, x) +#define DOCTEST_FAIL_CHECK(x) DOCTEST_ADD_FAIL_CHECK_AT(__FILE__, __LINE__, x) +#define DOCTEST_FAIL(x) DOCTEST_ADD_FAIL_AT(__FILE__, __LINE__, x) + +#define DOCTEST_TO_LVALUE(...) __VA_ARGS__ // Not removed to keep backwards compatibility. + +#ifndef DOCTEST_CONFIG_SUPER_FAST_ASSERTS + +#define DOCTEST_ASSERT_IMPLEMENT_2(assert_type, ...) \ + DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Woverloaded-shift-op-parentheses") \ + doctest::detail::ResultBuilder _DOCTEST_RB(doctest::assertType::assert_type, __FILE__, \ + __LINE__, #__VA_ARGS__); \ + DOCTEST_WRAP_IN_TRY(_DOCTEST_RB.setResult( \ + doctest::detail::ExpressionDecomposer(doctest::assertType::assert_type) \ + << __VA_ARGS__)) \ + DOCTEST_ASSERT_LOG_AND_REACT(_DOCTEST_RB) \ + DOCTEST_CLANG_SUPPRESS_WARNING_POP + +#define DOCTEST_ASSERT_IMPLEMENT_1(assert_type, ...) \ + do { \ + DOCTEST_ASSERT_IMPLEMENT_2(assert_type, __VA_ARGS__); \ + } while(false) + +#else // DOCTEST_CONFIG_SUPER_FAST_ASSERTS + +// necessary for _MESSAGE +#define DOCTEST_ASSERT_IMPLEMENT_2 DOCTEST_ASSERT_IMPLEMENT_1 + +#define DOCTEST_ASSERT_IMPLEMENT_1(assert_type, ...) \ + DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Woverloaded-shift-op-parentheses") \ + doctest::detail::decomp_assert( \ + doctest::assertType::assert_type, __FILE__, __LINE__, #__VA_ARGS__, \ + doctest::detail::ExpressionDecomposer(doctest::assertType::assert_type) \ + << __VA_ARGS__) DOCTEST_CLANG_SUPPRESS_WARNING_POP + +#endif // DOCTEST_CONFIG_SUPER_FAST_ASSERTS + +#define DOCTEST_WARN(...) DOCTEST_ASSERT_IMPLEMENT_1(DT_WARN, __VA_ARGS__) +#define DOCTEST_CHECK(...) DOCTEST_ASSERT_IMPLEMENT_1(DT_CHECK, __VA_ARGS__) +#define DOCTEST_REQUIRE(...) DOCTEST_ASSERT_IMPLEMENT_1(DT_REQUIRE, __VA_ARGS__) +#define DOCTEST_WARN_FALSE(...) DOCTEST_ASSERT_IMPLEMENT_1(DT_WARN_FALSE, __VA_ARGS__) +#define DOCTEST_CHECK_FALSE(...) DOCTEST_ASSERT_IMPLEMENT_1(DT_CHECK_FALSE, __VA_ARGS__) +#define DOCTEST_REQUIRE_FALSE(...) DOCTEST_ASSERT_IMPLEMENT_1(DT_REQUIRE_FALSE, __VA_ARGS__) + +// clang-format off +#define DOCTEST_WARN_MESSAGE(cond, msg) do { DOCTEST_INFO(msg); DOCTEST_ASSERT_IMPLEMENT_2(DT_WARN, cond); } while(false) +#define DOCTEST_CHECK_MESSAGE(cond, msg) do { DOCTEST_INFO(msg); DOCTEST_ASSERT_IMPLEMENT_2(DT_CHECK, cond); } while(false) +#define DOCTEST_REQUIRE_MESSAGE(cond, msg) do { DOCTEST_INFO(msg); DOCTEST_ASSERT_IMPLEMENT_2(DT_REQUIRE, cond); } while(false) +#define DOCTEST_WARN_FALSE_MESSAGE(cond, msg) do { DOCTEST_INFO(msg); DOCTEST_ASSERT_IMPLEMENT_2(DT_WARN_FALSE, cond); } while(false) +#define DOCTEST_CHECK_FALSE_MESSAGE(cond, msg) do { DOCTEST_INFO(msg); DOCTEST_ASSERT_IMPLEMENT_2(DT_CHECK_FALSE, cond); } while(false) +#define DOCTEST_REQUIRE_FALSE_MESSAGE(cond, msg) do { DOCTEST_INFO(msg); DOCTEST_ASSERT_IMPLEMENT_2(DT_REQUIRE_FALSE, cond); } while(false) +// clang-format on + +#define DOCTEST_ASSERT_THROWS_AS(expr, assert_type, message, ...) \ + do { \ + if(!doctest::getContextOptions()->no_throw) { \ + doctest::detail::ResultBuilder _DOCTEST_RB(doctest::assertType::assert_type, __FILE__, \ + __LINE__, #expr, #__VA_ARGS__, message); \ + try { \ + DOCTEST_CAST_TO_VOID(expr) \ + } catch(const doctest::detail::remove_const< \ + doctest::detail::remove_reference<__VA_ARGS__>::type>::type&) { \ + _DOCTEST_RB.translateException(); \ + _DOCTEST_RB.m_threw_as = true; \ + } catch(...) { _DOCTEST_RB.translateException(); } \ + DOCTEST_ASSERT_LOG_AND_REACT(_DOCTEST_RB); \ + } \ + } while(false) + +#define DOCTEST_ASSERT_THROWS_WITH(expr, expr_str, assert_type, ...) \ + do { \ + if(!doctest::getContextOptions()->no_throw) { \ + doctest::detail::ResultBuilder _DOCTEST_RB(doctest::assertType::assert_type, __FILE__, \ + __LINE__, expr_str, "", __VA_ARGS__); \ + try { \ + DOCTEST_CAST_TO_VOID(expr) \ + } catch(...) { _DOCTEST_RB.translateException(); } \ + DOCTEST_ASSERT_LOG_AND_REACT(_DOCTEST_RB); \ + } \ + } while(false) + +#define DOCTEST_ASSERT_NOTHROW(assert_type, ...) \ + do { \ + doctest::detail::ResultBuilder _DOCTEST_RB(doctest::assertType::assert_type, __FILE__, \ + __LINE__, #__VA_ARGS__); \ + try { \ + DOCTEST_CAST_TO_VOID(__VA_ARGS__) \ + } catch(...) { _DOCTEST_RB.translateException(); } \ + DOCTEST_ASSERT_LOG_AND_REACT(_DOCTEST_RB); \ + } while(false) + +// clang-format off +#define DOCTEST_WARN_THROWS(...) DOCTEST_ASSERT_THROWS_WITH((__VA_ARGS__), #__VA_ARGS__, DT_WARN_THROWS, "") +#define DOCTEST_CHECK_THROWS(...) DOCTEST_ASSERT_THROWS_WITH((__VA_ARGS__), #__VA_ARGS__, DT_CHECK_THROWS, "") +#define DOCTEST_REQUIRE_THROWS(...) DOCTEST_ASSERT_THROWS_WITH((__VA_ARGS__), #__VA_ARGS__, DT_REQUIRE_THROWS, "") + +#define DOCTEST_WARN_THROWS_AS(expr, ...) DOCTEST_ASSERT_THROWS_AS(expr, DT_WARN_THROWS_AS, "", __VA_ARGS__) +#define DOCTEST_CHECK_THROWS_AS(expr, ...) DOCTEST_ASSERT_THROWS_AS(expr, DT_CHECK_THROWS_AS, "", __VA_ARGS__) +#define DOCTEST_REQUIRE_THROWS_AS(expr, ...) DOCTEST_ASSERT_THROWS_AS(expr, DT_REQUIRE_THROWS_AS, "", __VA_ARGS__) + +#define DOCTEST_WARN_THROWS_WITH(expr, ...) DOCTEST_ASSERT_THROWS_WITH(expr, #expr, DT_WARN_THROWS_WITH, __VA_ARGS__) +#define DOCTEST_CHECK_THROWS_WITH(expr, ...) DOCTEST_ASSERT_THROWS_WITH(expr, #expr, DT_CHECK_THROWS_WITH, __VA_ARGS__) +#define DOCTEST_REQUIRE_THROWS_WITH(expr, ...) DOCTEST_ASSERT_THROWS_WITH(expr, #expr, DT_REQUIRE_THROWS_WITH, __VA_ARGS__) + +#define DOCTEST_WARN_THROWS_WITH_AS(expr, message, ...) DOCTEST_ASSERT_THROWS_AS(expr, DT_WARN_THROWS_WITH_AS, message, __VA_ARGS__) +#define DOCTEST_CHECK_THROWS_WITH_AS(expr, message, ...) DOCTEST_ASSERT_THROWS_AS(expr, DT_CHECK_THROWS_WITH_AS, message, __VA_ARGS__) +#define DOCTEST_REQUIRE_THROWS_WITH_AS(expr, message, ...) DOCTEST_ASSERT_THROWS_AS(expr, DT_REQUIRE_THROWS_WITH_AS, message, __VA_ARGS__) + +#define DOCTEST_WARN_NOTHROW(...) DOCTEST_ASSERT_NOTHROW(DT_WARN_NOTHROW, __VA_ARGS__) +#define DOCTEST_CHECK_NOTHROW(...) DOCTEST_ASSERT_NOTHROW(DT_CHECK_NOTHROW, __VA_ARGS__) +#define DOCTEST_REQUIRE_NOTHROW(...) DOCTEST_ASSERT_NOTHROW(DT_REQUIRE_NOTHROW, __VA_ARGS__) + +#define DOCTEST_WARN_THROWS_MESSAGE(expr, msg) do { DOCTEST_INFO(msg); DOCTEST_WARN_THROWS(expr); } while(false) +#define DOCTEST_CHECK_THROWS_MESSAGE(expr, msg) do { DOCTEST_INFO(msg); DOCTEST_CHECK_THROWS(expr); } while(false) +#define DOCTEST_REQUIRE_THROWS_MESSAGE(expr, msg) do { DOCTEST_INFO(msg); DOCTEST_REQUIRE_THROWS(expr); } while(false) +#define DOCTEST_WARN_THROWS_AS_MESSAGE(expr, ex, msg) do { DOCTEST_INFO(msg); DOCTEST_WARN_THROWS_AS(expr, ex); } while(false) +#define DOCTEST_CHECK_THROWS_AS_MESSAGE(expr, ex, msg) do { DOCTEST_INFO(msg); DOCTEST_CHECK_THROWS_AS(expr, ex); } while(false) +#define DOCTEST_REQUIRE_THROWS_AS_MESSAGE(expr, ex, msg) do { DOCTEST_INFO(msg); DOCTEST_REQUIRE_THROWS_AS(expr, ex); } while(false) +#define DOCTEST_WARN_THROWS_WITH_MESSAGE(expr, with, msg) do { DOCTEST_INFO(msg); DOCTEST_WARN_THROWS_WITH(expr, with); } while(false) +#define DOCTEST_CHECK_THROWS_WITH_MESSAGE(expr, with, msg) do { DOCTEST_INFO(msg); DOCTEST_CHECK_THROWS_WITH(expr, with); } while(false) +#define DOCTEST_REQUIRE_THROWS_WITH_MESSAGE(expr, with, msg) do { DOCTEST_INFO(msg); DOCTEST_REQUIRE_THROWS_WITH(expr, with); } while(false) +#define DOCTEST_WARN_THROWS_WITH_AS_MESSAGE(expr, with, ex, msg) do { DOCTEST_INFO(msg); DOCTEST_WARN_THROWS_WITH_AS(expr, with, ex); } while(false) +#define DOCTEST_CHECK_THROWS_WITH_AS_MESSAGE(expr, with, ex, msg) do { DOCTEST_INFO(msg); DOCTEST_CHECK_THROWS_WITH_AS(expr, with, ex); } while(false) +#define DOCTEST_REQUIRE_THROWS_WITH_AS_MESSAGE(expr, with, ex, msg) do { DOCTEST_INFO(msg); DOCTEST_REQUIRE_THROWS_WITH_AS(expr, with, ex); } while(false) +#define DOCTEST_WARN_NOTHROW_MESSAGE(expr, msg) do { DOCTEST_INFO(msg); DOCTEST_WARN_NOTHROW(expr); } while(false) +#define DOCTEST_CHECK_NOTHROW_MESSAGE(expr, msg) do { DOCTEST_INFO(msg); DOCTEST_CHECK_NOTHROW(expr); } while(false) +#define DOCTEST_REQUIRE_NOTHROW_MESSAGE(expr, msg) do { DOCTEST_INFO(msg); DOCTEST_REQUIRE_NOTHROW(expr); } while(false) +// clang-format on + +#ifndef DOCTEST_CONFIG_SUPER_FAST_ASSERTS + +#define DOCTEST_BINARY_ASSERT(assert_type, comp, ...) \ + do { \ + doctest::detail::ResultBuilder _DOCTEST_RB(doctest::assertType::assert_type, __FILE__, \ + __LINE__, #__VA_ARGS__); \ + DOCTEST_WRAP_IN_TRY( \ + _DOCTEST_RB.binary_assert( \ + __VA_ARGS__)) \ + DOCTEST_ASSERT_LOG_AND_REACT(_DOCTEST_RB); \ + } while(false) + +#define DOCTEST_UNARY_ASSERT(assert_type, ...) \ + do { \ + doctest::detail::ResultBuilder _DOCTEST_RB(doctest::assertType::assert_type, __FILE__, \ + __LINE__, #__VA_ARGS__); \ + DOCTEST_WRAP_IN_TRY(_DOCTEST_RB.unary_assert(__VA_ARGS__)) \ + DOCTEST_ASSERT_LOG_AND_REACT(_DOCTEST_RB); \ + } while(false) + +#else // DOCTEST_CONFIG_SUPER_FAST_ASSERTS + +#define DOCTEST_BINARY_ASSERT(assert_type, comparison, ...) \ + doctest::detail::binary_assert( \ + doctest::assertType::assert_type, __FILE__, __LINE__, #__VA_ARGS__, __VA_ARGS__) + +#define DOCTEST_UNARY_ASSERT(assert_type, ...) \ + doctest::detail::unary_assert(doctest::assertType::assert_type, __FILE__, __LINE__, \ + #__VA_ARGS__, __VA_ARGS__) + +#endif // DOCTEST_CONFIG_SUPER_FAST_ASSERTS + +#define DOCTEST_WARN_EQ(...) DOCTEST_BINARY_ASSERT(DT_WARN_EQ, eq, __VA_ARGS__) +#define DOCTEST_CHECK_EQ(...) DOCTEST_BINARY_ASSERT(DT_CHECK_EQ, eq, __VA_ARGS__) +#define DOCTEST_REQUIRE_EQ(...) DOCTEST_BINARY_ASSERT(DT_REQUIRE_EQ, eq, __VA_ARGS__) +#define DOCTEST_WARN_NE(...) DOCTEST_BINARY_ASSERT(DT_WARN_NE, ne, __VA_ARGS__) +#define DOCTEST_CHECK_NE(...) DOCTEST_BINARY_ASSERT(DT_CHECK_NE, ne, __VA_ARGS__) +#define DOCTEST_REQUIRE_NE(...) DOCTEST_BINARY_ASSERT(DT_REQUIRE_NE, ne, __VA_ARGS__) +#define DOCTEST_WARN_GT(...) DOCTEST_BINARY_ASSERT(DT_WARN_GT, gt, __VA_ARGS__) +#define DOCTEST_CHECK_GT(...) DOCTEST_BINARY_ASSERT(DT_CHECK_GT, gt, __VA_ARGS__) +#define DOCTEST_REQUIRE_GT(...) DOCTEST_BINARY_ASSERT(DT_REQUIRE_GT, gt, __VA_ARGS__) +#define DOCTEST_WARN_LT(...) DOCTEST_BINARY_ASSERT(DT_WARN_LT, lt, __VA_ARGS__) +#define DOCTEST_CHECK_LT(...) DOCTEST_BINARY_ASSERT(DT_CHECK_LT, lt, __VA_ARGS__) +#define DOCTEST_REQUIRE_LT(...) DOCTEST_BINARY_ASSERT(DT_REQUIRE_LT, lt, __VA_ARGS__) +#define DOCTEST_WARN_GE(...) DOCTEST_BINARY_ASSERT(DT_WARN_GE, ge, __VA_ARGS__) +#define DOCTEST_CHECK_GE(...) DOCTEST_BINARY_ASSERT(DT_CHECK_GE, ge, __VA_ARGS__) +#define DOCTEST_REQUIRE_GE(...) DOCTEST_BINARY_ASSERT(DT_REQUIRE_GE, ge, __VA_ARGS__) +#define DOCTEST_WARN_LE(...) DOCTEST_BINARY_ASSERT(DT_WARN_LE, le, __VA_ARGS__) +#define DOCTEST_CHECK_LE(...) DOCTEST_BINARY_ASSERT(DT_CHECK_LE, le, __VA_ARGS__) +#define DOCTEST_REQUIRE_LE(...) DOCTEST_BINARY_ASSERT(DT_REQUIRE_LE, le, __VA_ARGS__) + +#define DOCTEST_WARN_UNARY(...) DOCTEST_UNARY_ASSERT(DT_WARN_UNARY, __VA_ARGS__) +#define DOCTEST_CHECK_UNARY(...) DOCTEST_UNARY_ASSERT(DT_CHECK_UNARY, __VA_ARGS__) +#define DOCTEST_REQUIRE_UNARY(...) DOCTEST_UNARY_ASSERT(DT_REQUIRE_UNARY, __VA_ARGS__) +#define DOCTEST_WARN_UNARY_FALSE(...) DOCTEST_UNARY_ASSERT(DT_WARN_UNARY_FALSE, __VA_ARGS__) +#define DOCTEST_CHECK_UNARY_FALSE(...) DOCTEST_UNARY_ASSERT(DT_CHECK_UNARY_FALSE, __VA_ARGS__) +#define DOCTEST_REQUIRE_UNARY_FALSE(...) DOCTEST_UNARY_ASSERT(DT_REQUIRE_UNARY_FALSE, __VA_ARGS__) + +#ifdef DOCTEST_CONFIG_NO_EXCEPTIONS + +#undef DOCTEST_WARN_THROWS +#undef DOCTEST_CHECK_THROWS +#undef DOCTEST_REQUIRE_THROWS +#undef DOCTEST_WARN_THROWS_AS +#undef DOCTEST_CHECK_THROWS_AS +#undef DOCTEST_REQUIRE_THROWS_AS +#undef DOCTEST_WARN_THROWS_WITH +#undef DOCTEST_CHECK_THROWS_WITH +#undef DOCTEST_REQUIRE_THROWS_WITH +#undef DOCTEST_WARN_THROWS_WITH_AS +#undef DOCTEST_CHECK_THROWS_WITH_AS +#undef DOCTEST_REQUIRE_THROWS_WITH_AS +#undef DOCTEST_WARN_NOTHROW +#undef DOCTEST_CHECK_NOTHROW +#undef DOCTEST_REQUIRE_NOTHROW + +#undef DOCTEST_WARN_THROWS_MESSAGE +#undef DOCTEST_CHECK_THROWS_MESSAGE +#undef DOCTEST_REQUIRE_THROWS_MESSAGE +#undef DOCTEST_WARN_THROWS_AS_MESSAGE +#undef DOCTEST_CHECK_THROWS_AS_MESSAGE +#undef DOCTEST_REQUIRE_THROWS_AS_MESSAGE +#undef DOCTEST_WARN_THROWS_WITH_MESSAGE +#undef DOCTEST_CHECK_THROWS_WITH_MESSAGE +#undef DOCTEST_REQUIRE_THROWS_WITH_MESSAGE +#undef DOCTEST_WARN_THROWS_WITH_AS_MESSAGE +#undef DOCTEST_CHECK_THROWS_WITH_AS_MESSAGE +#undef DOCTEST_REQUIRE_THROWS_WITH_AS_MESSAGE +#undef DOCTEST_WARN_NOTHROW_MESSAGE +#undef DOCTEST_CHECK_NOTHROW_MESSAGE +#undef DOCTEST_REQUIRE_NOTHROW_MESSAGE + +#ifdef DOCTEST_CONFIG_NO_EXCEPTIONS_BUT_WITH_ALL_ASSERTS + +#define DOCTEST_WARN_THROWS(...) ((void)0) +#define DOCTEST_CHECK_THROWS(...) ((void)0) +#define DOCTEST_REQUIRE_THROWS(...) ((void)0) +#define DOCTEST_WARN_THROWS_AS(expr, ...) ((void)0) +#define DOCTEST_CHECK_THROWS_AS(expr, ...) ((void)0) +#define DOCTEST_REQUIRE_THROWS_AS(expr, ...) ((void)0) +#define DOCTEST_WARN_THROWS_WITH(expr, ...) ((void)0) +#define DOCTEST_CHECK_THROWS_WITH(expr, ...) ((void)0) +#define DOCTEST_REQUIRE_THROWS_WITH(expr, ...) ((void)0) +#define DOCTEST_WARN_THROWS_WITH_AS(expr, with, ...) ((void)0) +#define DOCTEST_CHECK_THROWS_WITH_AS(expr, with, ...) ((void)0) +#define DOCTEST_REQUIRE_THROWS_WITH_AS(expr, with, ...) ((void)0) +#define DOCTEST_WARN_NOTHROW(...) ((void)0) +#define DOCTEST_CHECK_NOTHROW(...) ((void)0) +#define DOCTEST_REQUIRE_NOTHROW(...) ((void)0) + +#define DOCTEST_WARN_THROWS_MESSAGE(expr, msg) ((void)0) +#define DOCTEST_CHECK_THROWS_MESSAGE(expr, msg) ((void)0) +#define DOCTEST_REQUIRE_THROWS_MESSAGE(expr, msg) ((void)0) +#define DOCTEST_WARN_THROWS_AS_MESSAGE(expr, ex, msg) ((void)0) +#define DOCTEST_CHECK_THROWS_AS_MESSAGE(expr, ex, msg) ((void)0) +#define DOCTEST_REQUIRE_THROWS_AS_MESSAGE(expr, ex, msg) ((void)0) +#define DOCTEST_WARN_THROWS_WITH_MESSAGE(expr, with, msg) ((void)0) +#define DOCTEST_CHECK_THROWS_WITH_MESSAGE(expr, with, msg) ((void)0) +#define DOCTEST_REQUIRE_THROWS_WITH_MESSAGE(expr, with, msg) ((void)0) +#define DOCTEST_WARN_THROWS_WITH_AS_MESSAGE(expr, with, ex, msg) ((void)0) +#define DOCTEST_CHECK_THROWS_WITH_AS_MESSAGE(expr, with, ex, msg) ((void)0) +#define DOCTEST_REQUIRE_THROWS_WITH_AS_MESSAGE(expr, with, ex, msg) ((void)0) +#define DOCTEST_WARN_NOTHROW_MESSAGE(expr, msg) ((void)0) +#define DOCTEST_CHECK_NOTHROW_MESSAGE(expr, msg) ((void)0) +#define DOCTEST_REQUIRE_NOTHROW_MESSAGE(expr, msg) ((void)0) + +#else // DOCTEST_CONFIG_NO_EXCEPTIONS_BUT_WITH_ALL_ASSERTS + +#undef DOCTEST_REQUIRE +#undef DOCTEST_REQUIRE_FALSE +#undef DOCTEST_REQUIRE_MESSAGE +#undef DOCTEST_REQUIRE_FALSE_MESSAGE +#undef DOCTEST_REQUIRE_EQ +#undef DOCTEST_REQUIRE_NE +#undef DOCTEST_REQUIRE_GT +#undef DOCTEST_REQUIRE_LT +#undef DOCTEST_REQUIRE_GE +#undef DOCTEST_REQUIRE_LE +#undef DOCTEST_REQUIRE_UNARY +#undef DOCTEST_REQUIRE_UNARY_FALSE + +#endif // DOCTEST_CONFIG_NO_EXCEPTIONS_BUT_WITH_ALL_ASSERTS + +#endif // DOCTEST_CONFIG_NO_EXCEPTIONS + +// ================================================================================================= +// == WHAT FOLLOWS IS VERSIONS OF THE MACROS THAT DO NOT DO ANY REGISTERING! == +// == THIS CAN BE ENABLED BY DEFINING DOCTEST_CONFIG_DISABLE GLOBALLY! == +// ================================================================================================= +#else // DOCTEST_CONFIG_DISABLE + +#define DOCTEST_IMPLEMENT_FIXTURE(der, base, func, name) \ + namespace { \ + template \ + struct der : public base \ + { void f(); }; \ + } \ + template \ + inline void der::f() + +#define DOCTEST_CREATE_AND_REGISTER_FUNCTION(f, name) \ + template \ + static inline void f() + +// for registering tests +#define DOCTEST_TEST_CASE(name) \ + DOCTEST_CREATE_AND_REGISTER_FUNCTION(DOCTEST_ANONYMOUS(_DOCTEST_ANON_FUNC_), name) + +// for registering tests in classes +#define DOCTEST_TEST_CASE_CLASS(name) \ + DOCTEST_CREATE_AND_REGISTER_FUNCTION(DOCTEST_ANONYMOUS(_DOCTEST_ANON_FUNC_), name) + +// for registering tests with a fixture +#define DOCTEST_TEST_CASE_FIXTURE(x, name) \ + DOCTEST_IMPLEMENT_FIXTURE(DOCTEST_ANONYMOUS(_DOCTEST_ANON_CLASS_), x, \ + DOCTEST_ANONYMOUS(_DOCTEST_ANON_FUNC_), name) + +// for converting types to strings without the header and demangling +#define DOCTEST_TYPE_TO_STRING(...) typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_) +#define DOCTEST_TYPE_TO_STRING_IMPL(...) + +// for typed tests +#define DOCTEST_TEST_CASE_TEMPLATE(name, type, ...) \ + template \ + inline void DOCTEST_ANONYMOUS(_DOCTEST_ANON_TMP_)() + +#define DOCTEST_TEST_CASE_TEMPLATE_DEFINE(name, type, id) \ + template \ + inline void DOCTEST_ANONYMOUS(_DOCTEST_ANON_TMP_)() + +#define DOCTEST_TEST_CASE_TEMPLATE_INVOKE(id, ...) \ + typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_) + +#define DOCTEST_TEST_CASE_TEMPLATE_APPLY(id, ...) \ + typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_) + +// for subcases +#define DOCTEST_SUBCASE(name) + +// for a testsuite block +#define DOCTEST_TEST_SUITE(name) namespace + +// for starting a testsuite block +#define DOCTEST_TEST_SUITE_BEGIN(name) typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_) + +// for ending a testsuite block +#define DOCTEST_TEST_SUITE_END typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_) + +#define DOCTEST_REGISTER_EXCEPTION_TRANSLATOR(signature) \ + template \ + static inline doctest::String DOCTEST_ANONYMOUS(_DOCTEST_ANON_TRANSLATOR_)(signature) + +#define DOCTEST_REGISTER_REPORTER(name, priority, reporter) +#define DOCTEST_REGISTER_LISTENER(name, priority, reporter) + +#define DOCTEST_INFO(x) ((void)0) +#define DOCTEST_CAPTURE(x) ((void)0) +#define DOCTEST_ADD_MESSAGE_AT(file, line, x) ((void)0) +#define DOCTEST_ADD_FAIL_CHECK_AT(file, line, x) ((void)0) +#define DOCTEST_ADD_FAIL_AT(file, line, x) ((void)0) +#define DOCTEST_MESSAGE(x) ((void)0) +#define DOCTEST_FAIL_CHECK(x) ((void)0) +#define DOCTEST_FAIL(x) ((void)0) + +#define DOCTEST_WARN(...) ((void)0) +#define DOCTEST_CHECK(...) ((void)0) +#define DOCTEST_REQUIRE(...) ((void)0) +#define DOCTEST_WARN_FALSE(...) ((void)0) +#define DOCTEST_CHECK_FALSE(...) ((void)0) +#define DOCTEST_REQUIRE_FALSE(...) ((void)0) + +#define DOCTEST_WARN_MESSAGE(cond, msg) ((void)0) +#define DOCTEST_CHECK_MESSAGE(cond, msg) ((void)0) +#define DOCTEST_REQUIRE_MESSAGE(cond, msg) ((void)0) +#define DOCTEST_WARN_FALSE_MESSAGE(cond, msg) ((void)0) +#define DOCTEST_CHECK_FALSE_MESSAGE(cond, msg) ((void)0) +#define DOCTEST_REQUIRE_FALSE_MESSAGE(cond, msg) ((void)0) + +#define DOCTEST_WARN_THROWS(...) ((void)0) +#define DOCTEST_CHECK_THROWS(...) ((void)0) +#define DOCTEST_REQUIRE_THROWS(...) ((void)0) +#define DOCTEST_WARN_THROWS_AS(expr, ...) ((void)0) +#define DOCTEST_CHECK_THROWS_AS(expr, ...) ((void)0) +#define DOCTEST_REQUIRE_THROWS_AS(expr, ...) ((void)0) +#define DOCTEST_WARN_THROWS_WITH(expr, ...) ((void)0) +#define DOCTEST_CHECK_THROWS_WITH(expr, ...) ((void)0) +#define DOCTEST_REQUIRE_THROWS_WITH(expr, ...) ((void)0) +#define DOCTEST_WARN_THROWS_WITH_AS(expr, with, ...) ((void)0) +#define DOCTEST_CHECK_THROWS_WITH_AS(expr, with, ...) ((void)0) +#define DOCTEST_REQUIRE_THROWS_WITH_AS(expr, with, ...) ((void)0) +#define DOCTEST_WARN_NOTHROW(...) ((void)0) +#define DOCTEST_CHECK_NOTHROW(...) ((void)0) +#define DOCTEST_REQUIRE_NOTHROW(...) ((void)0) + +#define DOCTEST_WARN_THROWS_MESSAGE(expr, msg) ((void)0) +#define DOCTEST_CHECK_THROWS_MESSAGE(expr, msg) ((void)0) +#define DOCTEST_REQUIRE_THROWS_MESSAGE(expr, msg) ((void)0) +#define DOCTEST_WARN_THROWS_AS_MESSAGE(expr, ex, msg) ((void)0) +#define DOCTEST_CHECK_THROWS_AS_MESSAGE(expr, ex, msg) ((void)0) +#define DOCTEST_REQUIRE_THROWS_AS_MESSAGE(expr, ex, msg) ((void)0) +#define DOCTEST_WARN_THROWS_WITH_MESSAGE(expr, with, msg) ((void)0) +#define DOCTEST_CHECK_THROWS_WITH_MESSAGE(expr, with, msg) ((void)0) +#define DOCTEST_REQUIRE_THROWS_WITH_MESSAGE(expr, with, msg) ((void)0) +#define DOCTEST_WARN_THROWS_WITH_AS_MESSAGE(expr, with, ex, msg) ((void)0) +#define DOCTEST_CHECK_THROWS_WITH_AS_MESSAGE(expr, with, ex, msg) ((void)0) +#define DOCTEST_REQUIRE_THROWS_WITH_AS_MESSAGE(expr, with, ex, msg) ((void)0) +#define DOCTEST_WARN_NOTHROW_MESSAGE(expr, msg) ((void)0) +#define DOCTEST_CHECK_NOTHROW_MESSAGE(expr, msg) ((void)0) +#define DOCTEST_REQUIRE_NOTHROW_MESSAGE(expr, msg) ((void)0) + +#define DOCTEST_WARN_EQ(...) ((void)0) +#define DOCTEST_CHECK_EQ(...) ((void)0) +#define DOCTEST_REQUIRE_EQ(...) ((void)0) +#define DOCTEST_WARN_NE(...) ((void)0) +#define DOCTEST_CHECK_NE(...) ((void)0) +#define DOCTEST_REQUIRE_NE(...) ((void)0) +#define DOCTEST_WARN_GT(...) ((void)0) +#define DOCTEST_CHECK_GT(...) ((void)0) +#define DOCTEST_REQUIRE_GT(...) ((void)0) +#define DOCTEST_WARN_LT(...) ((void)0) +#define DOCTEST_CHECK_LT(...) ((void)0) +#define DOCTEST_REQUIRE_LT(...) ((void)0) +#define DOCTEST_WARN_GE(...) ((void)0) +#define DOCTEST_CHECK_GE(...) ((void)0) +#define DOCTEST_REQUIRE_GE(...) ((void)0) +#define DOCTEST_WARN_LE(...) ((void)0) +#define DOCTEST_CHECK_LE(...) ((void)0) +#define DOCTEST_REQUIRE_LE(...) ((void)0) + +#define DOCTEST_WARN_UNARY(...) ((void)0) +#define DOCTEST_CHECK_UNARY(...) ((void)0) +#define DOCTEST_REQUIRE_UNARY(...) ((void)0) +#define DOCTEST_WARN_UNARY_FALSE(...) ((void)0) +#define DOCTEST_CHECK_UNARY_FALSE(...) ((void)0) +#define DOCTEST_REQUIRE_UNARY_FALSE(...) ((void)0) + +#endif // DOCTEST_CONFIG_DISABLE + +// clang-format off +// KEPT FOR BACKWARDS COMPATIBILITY - FORWARDING TO THE RIGHT MACROS +#define DOCTEST_FAST_WARN_EQ DOCTEST_WARN_EQ +#define DOCTEST_FAST_CHECK_EQ DOCTEST_CHECK_EQ +#define DOCTEST_FAST_REQUIRE_EQ DOCTEST_REQUIRE_EQ +#define DOCTEST_FAST_WARN_NE DOCTEST_WARN_NE +#define DOCTEST_FAST_CHECK_NE DOCTEST_CHECK_NE +#define DOCTEST_FAST_REQUIRE_NE DOCTEST_REQUIRE_NE +#define DOCTEST_FAST_WARN_GT DOCTEST_WARN_GT +#define DOCTEST_FAST_CHECK_GT DOCTEST_CHECK_GT +#define DOCTEST_FAST_REQUIRE_GT DOCTEST_REQUIRE_GT +#define DOCTEST_FAST_WARN_LT DOCTEST_WARN_LT +#define DOCTEST_FAST_CHECK_LT DOCTEST_CHECK_LT +#define DOCTEST_FAST_REQUIRE_LT DOCTEST_REQUIRE_LT +#define DOCTEST_FAST_WARN_GE DOCTEST_WARN_GE +#define DOCTEST_FAST_CHECK_GE DOCTEST_CHECK_GE +#define DOCTEST_FAST_REQUIRE_GE DOCTEST_REQUIRE_GE +#define DOCTEST_FAST_WARN_LE DOCTEST_WARN_LE +#define DOCTEST_FAST_CHECK_LE DOCTEST_CHECK_LE +#define DOCTEST_FAST_REQUIRE_LE DOCTEST_REQUIRE_LE + +#define DOCTEST_FAST_WARN_UNARY DOCTEST_WARN_UNARY +#define DOCTEST_FAST_CHECK_UNARY DOCTEST_CHECK_UNARY +#define DOCTEST_FAST_REQUIRE_UNARY DOCTEST_REQUIRE_UNARY +#define DOCTEST_FAST_WARN_UNARY_FALSE DOCTEST_WARN_UNARY_FALSE +#define DOCTEST_FAST_CHECK_UNARY_FALSE DOCTEST_CHECK_UNARY_FALSE +#define DOCTEST_FAST_REQUIRE_UNARY_FALSE DOCTEST_REQUIRE_UNARY_FALSE + +#define DOCTEST_TEST_CASE_TEMPLATE_INSTANTIATE DOCTEST_TEST_CASE_TEMPLATE_INVOKE +// clang-format on + +// BDD style macros +// clang-format off +#define DOCTEST_SCENARIO(name) DOCTEST_TEST_CASE(" Scenario: " name) +#define DOCTEST_SCENARIO_CLASS(name) DOCTEST_TEST_CASE_CLASS(" Scenario: " name) +#define DOCTEST_SCENARIO_TEMPLATE(name, T, ...) DOCTEST_TEST_CASE_TEMPLATE(" Scenario: " name, T, __VA_ARGS__) +#define DOCTEST_SCENARIO_TEMPLATE_DEFINE(name, T, id) DOCTEST_TEST_CASE_TEMPLATE_DEFINE(" Scenario: " name, T, id) + +#define DOCTEST_GIVEN(name) DOCTEST_SUBCASE(" Given: " name) +#define DOCTEST_WHEN(name) DOCTEST_SUBCASE(" When: " name) +#define DOCTEST_AND_WHEN(name) DOCTEST_SUBCASE("And when: " name) +#define DOCTEST_THEN(name) DOCTEST_SUBCASE(" Then: " name) +#define DOCTEST_AND_THEN(name) DOCTEST_SUBCASE(" And: " name) +// clang-format on + +// == SHORT VERSIONS OF THE MACROS +#if !defined(DOCTEST_CONFIG_NO_SHORT_MACRO_NAMES) + +#define TEST_CASE DOCTEST_TEST_CASE +#define TEST_CASE_CLASS DOCTEST_TEST_CASE_CLASS +#define TEST_CASE_FIXTURE DOCTEST_TEST_CASE_FIXTURE +#define TYPE_TO_STRING DOCTEST_TYPE_TO_STRING +#define TEST_CASE_TEMPLATE DOCTEST_TEST_CASE_TEMPLATE +#define TEST_CASE_TEMPLATE_DEFINE DOCTEST_TEST_CASE_TEMPLATE_DEFINE +#define TEST_CASE_TEMPLATE_INVOKE DOCTEST_TEST_CASE_TEMPLATE_INVOKE +#define TEST_CASE_TEMPLATE_APPLY DOCTEST_TEST_CASE_TEMPLATE_APPLY +#define SUBCASE DOCTEST_SUBCASE +#define TEST_SUITE DOCTEST_TEST_SUITE +#define TEST_SUITE_BEGIN DOCTEST_TEST_SUITE_BEGIN +#define TEST_SUITE_END DOCTEST_TEST_SUITE_END +#define REGISTER_EXCEPTION_TRANSLATOR DOCTEST_REGISTER_EXCEPTION_TRANSLATOR +#define REGISTER_REPORTER DOCTEST_REGISTER_REPORTER +#define REGISTER_LISTENER DOCTEST_REGISTER_LISTENER +#define INFO DOCTEST_INFO +#define CAPTURE DOCTEST_CAPTURE +#define ADD_MESSAGE_AT DOCTEST_ADD_MESSAGE_AT +#define ADD_FAIL_CHECK_AT DOCTEST_ADD_FAIL_CHECK_AT +#define ADD_FAIL_AT DOCTEST_ADD_FAIL_AT +#define MESSAGE DOCTEST_MESSAGE +#define FAIL_CHECK DOCTEST_FAIL_CHECK +#define FAIL DOCTEST_FAIL +#define TO_LVALUE DOCTEST_TO_LVALUE + +#define WARN DOCTEST_WARN +#define WARN_FALSE DOCTEST_WARN_FALSE +#define WARN_THROWS DOCTEST_WARN_THROWS +#define WARN_THROWS_AS DOCTEST_WARN_THROWS_AS +#define WARN_THROWS_WITH DOCTEST_WARN_THROWS_WITH +#define WARN_THROWS_WITH_AS DOCTEST_WARN_THROWS_WITH_AS +#define WARN_NOTHROW DOCTEST_WARN_NOTHROW +#define CHECK DOCTEST_CHECK +#define CHECK_FALSE DOCTEST_CHECK_FALSE +#define CHECK_THROWS DOCTEST_CHECK_THROWS +#define CHECK_THROWS_AS DOCTEST_CHECK_THROWS_AS +#define CHECK_THROWS_WITH DOCTEST_CHECK_THROWS_WITH +#define CHECK_THROWS_WITH_AS DOCTEST_CHECK_THROWS_WITH_AS +#define CHECK_NOTHROW DOCTEST_CHECK_NOTHROW +#define REQUIRE DOCTEST_REQUIRE +#define REQUIRE_FALSE DOCTEST_REQUIRE_FALSE +#define REQUIRE_THROWS DOCTEST_REQUIRE_THROWS +#define REQUIRE_THROWS_AS DOCTEST_REQUIRE_THROWS_AS +#define REQUIRE_THROWS_WITH DOCTEST_REQUIRE_THROWS_WITH +#define REQUIRE_THROWS_WITH_AS DOCTEST_REQUIRE_THROWS_WITH_AS +#define REQUIRE_NOTHROW DOCTEST_REQUIRE_NOTHROW + +#define WARN_MESSAGE DOCTEST_WARN_MESSAGE +#define WARN_FALSE_MESSAGE DOCTEST_WARN_FALSE_MESSAGE +#define WARN_THROWS_MESSAGE DOCTEST_WARN_THROWS_MESSAGE +#define WARN_THROWS_AS_MESSAGE DOCTEST_WARN_THROWS_AS_MESSAGE +#define WARN_THROWS_WITH_MESSAGE DOCTEST_WARN_THROWS_WITH_MESSAGE +#define WARN_THROWS_WITH_AS_MESSAGE DOCTEST_WARN_THROWS_WITH_AS_MESSAGE +#define WARN_NOTHROW_MESSAGE DOCTEST_WARN_NOTHROW_MESSAGE +#define CHECK_MESSAGE DOCTEST_CHECK_MESSAGE +#define CHECK_FALSE_MESSAGE DOCTEST_CHECK_FALSE_MESSAGE +#define CHECK_THROWS_MESSAGE DOCTEST_CHECK_THROWS_MESSAGE +#define CHECK_THROWS_AS_MESSAGE DOCTEST_CHECK_THROWS_AS_MESSAGE +#define CHECK_THROWS_WITH_MESSAGE DOCTEST_CHECK_THROWS_WITH_MESSAGE +#define CHECK_THROWS_WITH_AS_MESSAGE DOCTEST_CHECK_THROWS_WITH_AS_MESSAGE +#define CHECK_NOTHROW_MESSAGE DOCTEST_CHECK_NOTHROW_MESSAGE +#define REQUIRE_MESSAGE DOCTEST_REQUIRE_MESSAGE +#define REQUIRE_FALSE_MESSAGE DOCTEST_REQUIRE_FALSE_MESSAGE +#define REQUIRE_THROWS_MESSAGE DOCTEST_REQUIRE_THROWS_MESSAGE +#define REQUIRE_THROWS_AS_MESSAGE DOCTEST_REQUIRE_THROWS_AS_MESSAGE +#define REQUIRE_THROWS_WITH_MESSAGE DOCTEST_REQUIRE_THROWS_WITH_MESSAGE +#define REQUIRE_THROWS_WITH_AS_MESSAGE DOCTEST_REQUIRE_THROWS_WITH_AS_MESSAGE +#define REQUIRE_NOTHROW_MESSAGE DOCTEST_REQUIRE_NOTHROW_MESSAGE + +#define SCENARIO DOCTEST_SCENARIO +#define SCENARIO_CLASS DOCTEST_SCENARIO_CLASS +#define SCENARIO_TEMPLATE DOCTEST_SCENARIO_TEMPLATE +#define SCENARIO_TEMPLATE_DEFINE DOCTEST_SCENARIO_TEMPLATE_DEFINE +#define GIVEN DOCTEST_GIVEN +#define WHEN DOCTEST_WHEN +#define AND_WHEN DOCTEST_AND_WHEN +#define THEN DOCTEST_THEN +#define AND_THEN DOCTEST_AND_THEN + +#define WARN_EQ DOCTEST_WARN_EQ +#define CHECK_EQ DOCTEST_CHECK_EQ +#define REQUIRE_EQ DOCTEST_REQUIRE_EQ +#define WARN_NE DOCTEST_WARN_NE +#define CHECK_NE DOCTEST_CHECK_NE +#define REQUIRE_NE DOCTEST_REQUIRE_NE +#define WARN_GT DOCTEST_WARN_GT +#define CHECK_GT DOCTEST_CHECK_GT +#define REQUIRE_GT DOCTEST_REQUIRE_GT +#define WARN_LT DOCTEST_WARN_LT +#define CHECK_LT DOCTEST_CHECK_LT +#define REQUIRE_LT DOCTEST_REQUIRE_LT +#define WARN_GE DOCTEST_WARN_GE +#define CHECK_GE DOCTEST_CHECK_GE +#define REQUIRE_GE DOCTEST_REQUIRE_GE +#define WARN_LE DOCTEST_WARN_LE +#define CHECK_LE DOCTEST_CHECK_LE +#define REQUIRE_LE DOCTEST_REQUIRE_LE +#define WARN_UNARY DOCTEST_WARN_UNARY +#define CHECK_UNARY DOCTEST_CHECK_UNARY +#define REQUIRE_UNARY DOCTEST_REQUIRE_UNARY +#define WARN_UNARY_FALSE DOCTEST_WARN_UNARY_FALSE +#define CHECK_UNARY_FALSE DOCTEST_CHECK_UNARY_FALSE +#define REQUIRE_UNARY_FALSE DOCTEST_REQUIRE_UNARY_FALSE + +// KEPT FOR BACKWARDS COMPATIBILITY +#define FAST_WARN_EQ DOCTEST_FAST_WARN_EQ +#define FAST_CHECK_EQ DOCTEST_FAST_CHECK_EQ +#define FAST_REQUIRE_EQ DOCTEST_FAST_REQUIRE_EQ +#define FAST_WARN_NE DOCTEST_FAST_WARN_NE +#define FAST_CHECK_NE DOCTEST_FAST_CHECK_NE +#define FAST_REQUIRE_NE DOCTEST_FAST_REQUIRE_NE +#define FAST_WARN_GT DOCTEST_FAST_WARN_GT +#define FAST_CHECK_GT DOCTEST_FAST_CHECK_GT +#define FAST_REQUIRE_GT DOCTEST_FAST_REQUIRE_GT +#define FAST_WARN_LT DOCTEST_FAST_WARN_LT +#define FAST_CHECK_LT DOCTEST_FAST_CHECK_LT +#define FAST_REQUIRE_LT DOCTEST_FAST_REQUIRE_LT +#define FAST_WARN_GE DOCTEST_FAST_WARN_GE +#define FAST_CHECK_GE DOCTEST_FAST_CHECK_GE +#define FAST_REQUIRE_GE DOCTEST_FAST_REQUIRE_GE +#define FAST_WARN_LE DOCTEST_FAST_WARN_LE +#define FAST_CHECK_LE DOCTEST_FAST_CHECK_LE +#define FAST_REQUIRE_LE DOCTEST_FAST_REQUIRE_LE + +#define FAST_WARN_UNARY DOCTEST_FAST_WARN_UNARY +#define FAST_CHECK_UNARY DOCTEST_FAST_CHECK_UNARY +#define FAST_REQUIRE_UNARY DOCTEST_FAST_REQUIRE_UNARY +#define FAST_WARN_UNARY_FALSE DOCTEST_FAST_WARN_UNARY_FALSE +#define FAST_CHECK_UNARY_FALSE DOCTEST_FAST_CHECK_UNARY_FALSE +#define FAST_REQUIRE_UNARY_FALSE DOCTEST_FAST_REQUIRE_UNARY_FALSE + +#define TEST_CASE_TEMPLATE_INSTANTIATE DOCTEST_TEST_CASE_TEMPLATE_INSTANTIATE + +#endif // DOCTEST_CONFIG_NO_SHORT_MACRO_NAMES + +#if !defined(DOCTEST_CONFIG_DISABLE) + +// this is here to clear the 'current test suite' for the current translation unit - at the top +DOCTEST_TEST_SUITE_END(); + +// add stringification for primitive/fundamental types +namespace doctest { namespace detail { + DOCTEST_TYPE_TO_STRING_IMPL(bool) + DOCTEST_TYPE_TO_STRING_IMPL(float) + DOCTEST_TYPE_TO_STRING_IMPL(double) + DOCTEST_TYPE_TO_STRING_IMPL(long double) + DOCTEST_TYPE_TO_STRING_IMPL(char) + DOCTEST_TYPE_TO_STRING_IMPL(signed char) + DOCTEST_TYPE_TO_STRING_IMPL(unsigned char) +#if !DOCTEST_MSVC || defined(_NATIVE_WCHAR_T_DEFINED) + DOCTEST_TYPE_TO_STRING_IMPL(wchar_t) +#endif // not MSVC or wchar_t support enabled + DOCTEST_TYPE_TO_STRING_IMPL(short int) + DOCTEST_TYPE_TO_STRING_IMPL(unsigned short int) + DOCTEST_TYPE_TO_STRING_IMPL(int) + DOCTEST_TYPE_TO_STRING_IMPL(unsigned int) + DOCTEST_TYPE_TO_STRING_IMPL(long int) + DOCTEST_TYPE_TO_STRING_IMPL(unsigned long int) + DOCTEST_TYPE_TO_STRING_IMPL(long long int) + DOCTEST_TYPE_TO_STRING_IMPL(unsigned long long int) +}} // namespace doctest::detail + +#endif // DOCTEST_CONFIG_DISABLE + +DOCTEST_CLANG_SUPPRESS_WARNING_POP +DOCTEST_MSVC_SUPPRESS_WARNING_POP +DOCTEST_GCC_SUPPRESS_WARNING_POP + +#endif // DOCTEST_LIBRARY_INCLUDED + +#ifndef DOCTEST_SINGLE_HEADER +#define DOCTEST_SINGLE_HEADER +#endif // DOCTEST_SINGLE_HEADER + +#if defined(DOCTEST_CONFIG_IMPLEMENT) || !defined(DOCTEST_SINGLE_HEADER) + +#ifndef DOCTEST_SINGLE_HEADER +#include "doctest_fwd.h" +#endif // DOCTEST_SINGLE_HEADER + +DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wunused-macros") + +#ifndef DOCTEST_LIBRARY_IMPLEMENTATION +#define DOCTEST_LIBRARY_IMPLEMENTATION + +DOCTEST_CLANG_SUPPRESS_WARNING_POP + +DOCTEST_CLANG_SUPPRESS_WARNING_PUSH +DOCTEST_CLANG_SUPPRESS_WARNING("-Wunknown-pragmas") +DOCTEST_CLANG_SUPPRESS_WARNING("-Wpadded") +DOCTEST_CLANG_SUPPRESS_WARNING("-Wweak-vtables") +DOCTEST_CLANG_SUPPRESS_WARNING("-Wglobal-constructors") +DOCTEST_CLANG_SUPPRESS_WARNING("-Wexit-time-destructors") +DOCTEST_CLANG_SUPPRESS_WARNING("-Wmissing-prototypes") +DOCTEST_CLANG_SUPPRESS_WARNING("-Wsign-conversion") +DOCTEST_CLANG_SUPPRESS_WARNING("-Wshorten-64-to-32") +DOCTEST_CLANG_SUPPRESS_WARNING("-Wmissing-variable-declarations") +DOCTEST_CLANG_SUPPRESS_WARNING("-Wswitch") +DOCTEST_CLANG_SUPPRESS_WARNING("-Wswitch-enum") +DOCTEST_CLANG_SUPPRESS_WARNING("-Wcovered-switch-default") +DOCTEST_CLANG_SUPPRESS_WARNING("-Wmissing-noreturn") +DOCTEST_CLANG_SUPPRESS_WARNING("-Wunused-local-typedef") +DOCTEST_CLANG_SUPPRESS_WARNING("-Wdisabled-macro-expansion") +DOCTEST_CLANG_SUPPRESS_WARNING("-Wmissing-braces") +DOCTEST_CLANG_SUPPRESS_WARNING("-Wmissing-field-initializers") +DOCTEST_CLANG_SUPPRESS_WARNING("-Wc++98-compat") +DOCTEST_CLANG_SUPPRESS_WARNING("-Wc++98-compat-pedantic") +DOCTEST_CLANG_SUPPRESS_WARNING("-Wunused-member-function") + +DOCTEST_GCC_SUPPRESS_WARNING_PUSH +DOCTEST_GCC_SUPPRESS_WARNING("-Wunknown-pragmas") +DOCTEST_GCC_SUPPRESS_WARNING("-Wpragmas") +DOCTEST_GCC_SUPPRESS_WARNING("-Wconversion") +DOCTEST_GCC_SUPPRESS_WARNING("-Weffc++") +DOCTEST_GCC_SUPPRESS_WARNING("-Wsign-conversion") +DOCTEST_GCC_SUPPRESS_WARNING("-Wstrict-overflow") +DOCTEST_GCC_SUPPRESS_WARNING("-Wstrict-aliasing") +DOCTEST_GCC_SUPPRESS_WARNING("-Wmissing-field-initializers") +DOCTEST_GCC_SUPPRESS_WARNING("-Wmissing-braces") +DOCTEST_GCC_SUPPRESS_WARNING("-Wmissing-declarations") +DOCTEST_GCC_SUPPRESS_WARNING("-Wswitch") +DOCTEST_GCC_SUPPRESS_WARNING("-Wswitch-enum") +DOCTEST_GCC_SUPPRESS_WARNING("-Wswitch-default") +DOCTEST_GCC_SUPPRESS_WARNING("-Wunsafe-loop-optimizations") +DOCTEST_GCC_SUPPRESS_WARNING("-Wold-style-cast") +DOCTEST_GCC_SUPPRESS_WARNING("-Wunused-local-typedefs") +DOCTEST_GCC_SUPPRESS_WARNING("-Wuseless-cast") +DOCTEST_GCC_SUPPRESS_WARNING("-Wunused-function") +DOCTEST_GCC_SUPPRESS_WARNING("-Wmultiple-inheritance") +DOCTEST_GCC_SUPPRESS_WARNING("-Wnoexcept") +DOCTEST_GCC_SUPPRESS_WARNING("-Wsuggest-attribute") + +DOCTEST_MSVC_SUPPRESS_WARNING_PUSH +DOCTEST_MSVC_SUPPRESS_WARNING(4616) // invalid compiler warning +DOCTEST_MSVC_SUPPRESS_WARNING(4619) // invalid compiler warning +DOCTEST_MSVC_SUPPRESS_WARNING(4996) // The compiler encountered a deprecated declaration +DOCTEST_MSVC_SUPPRESS_WARNING(4267) // 'var' : conversion from 'x' to 'y', possible loss of data +DOCTEST_MSVC_SUPPRESS_WARNING(4706) // assignment within conditional expression +DOCTEST_MSVC_SUPPRESS_WARNING(4512) // 'class' : assignment operator could not be generated +DOCTEST_MSVC_SUPPRESS_WARNING(4127) // conditional expression is constant +DOCTEST_MSVC_SUPPRESS_WARNING(4530) // C++ exception handler used, but unwind semantics not enabled +DOCTEST_MSVC_SUPPRESS_WARNING(4577) // 'noexcept' used with no exception handling mode specified +DOCTEST_MSVC_SUPPRESS_WARNING(4774) // format string expected in argument is not a string literal +DOCTEST_MSVC_SUPPRESS_WARNING(4365) // conversion from 'int' to 'unsigned', signed/unsigned mismatch +DOCTEST_MSVC_SUPPRESS_WARNING(4820) // padding in structs +DOCTEST_MSVC_SUPPRESS_WARNING(4640) // construction of local static object is not thread-safe +DOCTEST_MSVC_SUPPRESS_WARNING(5039) // pointer to potentially throwing function passed to extern C +DOCTEST_MSVC_SUPPRESS_WARNING(5045) // Spectre mitigation stuff +DOCTEST_MSVC_SUPPRESS_WARNING(4626) // assignment operator was implicitly defined as deleted +DOCTEST_MSVC_SUPPRESS_WARNING(5027) // move assignment operator was implicitly defined as deleted +DOCTEST_MSVC_SUPPRESS_WARNING(5026) // move constructor was implicitly defined as deleted +DOCTEST_MSVC_SUPPRESS_WARNING(4625) // copy constructor was implicitly defined as deleted +DOCTEST_MSVC_SUPPRESS_WARNING(4800) // forcing value to bool 'true' or 'false' (performance warning) +// static analysis +DOCTEST_MSVC_SUPPRESS_WARNING(26439) // This kind of function may not throw. Declare it 'noexcept' +DOCTEST_MSVC_SUPPRESS_WARNING(26495) // Always initialize a member variable +DOCTEST_MSVC_SUPPRESS_WARNING(26451) // Arithmetic overflow ... +DOCTEST_MSVC_SUPPRESS_WARNING(26444) // Avoid unnamed objects with custom construction and dtor... +DOCTEST_MSVC_SUPPRESS_WARNING(26812) // Prefer 'enum class' over 'enum' + +DOCTEST_MAKE_STD_HEADERS_CLEAN_FROM_WARNINGS_ON_WALL_BEGIN + +// required includes - will go only in one translation unit! +#include +#include +#include +// borland (Embarcadero) compiler requires math.h and not cmath - https://github.com/onqtam/doctest/pull/37 +#ifdef __BORLANDC__ +#include +#endif // __BORLANDC__ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef DOCTEST_CONFIG_POSIX_SIGNALS +#include +#endif // DOCTEST_CONFIG_POSIX_SIGNALS +#include +#include +#include + +#ifdef DOCTEST_PLATFORM_MAC +#include +#include +#include +#endif // DOCTEST_PLATFORM_MAC + +#ifdef DOCTEST_PLATFORM_WINDOWS + +// defines for a leaner windows.h +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif // WIN32_LEAN_AND_MEAN +#ifndef NOMINMAX +#define NOMINMAX +#endif // NOMINMAX + +// not sure what AfxWin.h is for - here I do what Catch does +#ifdef __AFXDLL +#include +#else +#if defined(__MINGW32__) || defined(__MINGW64__) +#include +#else // MINGW +#include +#endif // MINGW +#endif +#include + +#else // DOCTEST_PLATFORM_WINDOWS + +#include +#include + +#endif // DOCTEST_PLATFORM_WINDOWS + +// this is a fix for https://github.com/onqtam/doctest/issues/348 +// https://mail.gnome.org/archives/xml/2012-January/msg00000.html +#if !defined(HAVE_UNISTD_H) && !defined(STDOUT_FILENO) +#define STDOUT_FILENO fileno(stdout) +#endif // HAVE_UNISTD_H + +DOCTEST_MAKE_STD_HEADERS_CLEAN_FROM_WARNINGS_ON_WALL_END + +// counts the number of elements in a C array +#define DOCTEST_COUNTOF(x) (sizeof(x) / sizeof(x[0])) + +#ifdef DOCTEST_CONFIG_DISABLE +#define DOCTEST_BRANCH_ON_DISABLED(if_disabled, if_not_disabled) if_disabled +#else // DOCTEST_CONFIG_DISABLE +#define DOCTEST_BRANCH_ON_DISABLED(if_disabled, if_not_disabled) if_not_disabled +#endif // DOCTEST_CONFIG_DISABLE + +#ifndef DOCTEST_CONFIG_OPTIONS_PREFIX +#define DOCTEST_CONFIG_OPTIONS_PREFIX "dt-" +#endif + +#ifndef DOCTEST_THREAD_LOCAL +#define DOCTEST_THREAD_LOCAL thread_local +#endif + +#ifdef DOCTEST_CONFIG_NO_UNPREFIXED_OPTIONS +#define DOCTEST_OPTIONS_PREFIX_DISPLAY DOCTEST_CONFIG_OPTIONS_PREFIX +#else +#define DOCTEST_OPTIONS_PREFIX_DISPLAY "" +#endif + +namespace doctest { + +bool is_running_in_test = false; + +namespace { + using namespace detail; + // case insensitive strcmp + int stricmp(const char* a, const char* b) { + for(;; a++, b++) { + const int d = tolower(*a) - tolower(*b); + if(d != 0 || !*a) + return d; + } + } + + template + String fpToString(T value, int precision) { + std::ostringstream oss; + oss << std::setprecision(precision) << std::fixed << value; + std::string d = oss.str(); + size_t i = d.find_last_not_of('0'); + if(i != std::string::npos && i != d.size() - 1) { + if(d[i] == '.') + i++; + d = d.substr(0, i + 1); + } + return d.c_str(); + } + + struct Endianness + { + enum Arch + { + Big, + Little + }; + + static Arch which() { + int x = 1; + // casting any data pointer to char* is allowed + auto ptr = reinterpret_cast(&x); + if(*ptr) + return Little; + return Big; + } + }; +} // namespace + +namespace detail { + void my_memcpy(void* dest, const void* src, unsigned num) { memcpy(dest, src, num); } + + String rawMemoryToString(const void* object, unsigned size) { + // Reverse order for little endian architectures + int i = 0, end = static_cast(size), inc = 1; + if(Endianness::which() == Endianness::Little) { + i = end - 1; + end = inc = -1; + } + + unsigned const char* bytes = static_cast(object); + std::ostringstream oss; + oss << "0x" << std::setfill('0') << std::hex; + for(; i != end; i += inc) + oss << std::setw(2) << static_cast(bytes[i]); + return oss.str().c_str(); + } + + DOCTEST_THREAD_LOCAL std::ostringstream g_oss; // NOLINT(cert-err58-cpp) + + std::ostream* getTlsOss() { + g_oss.clear(); // there shouldn't be anything worth clearing in the flags + g_oss.str(""); // the slow way of resetting a string stream + //g_oss.seekp(0); // optimal reset - as seen here: https://stackoverflow.com/a/624291/3162383 + return &g_oss; + } + + String getTlsOssResult() { + //g_oss << std::ends; // needed - as shown here: https://stackoverflow.com/a/624291/3162383 + return g_oss.str().c_str(); + } + +#ifndef DOCTEST_CONFIG_DISABLE + +namespace timer_large_integer +{ + +#if defined(DOCTEST_PLATFORM_WINDOWS) + typedef ULONGLONG type; +#else // DOCTEST_PLATFORM_WINDOWS + using namespace std; + typedef uint64_t type; +#endif // DOCTEST_PLATFORM_WINDOWS +} + +typedef timer_large_integer::type ticks_t; + +#ifdef DOCTEST_CONFIG_GETCURRENTTICKS + ticks_t getCurrentTicks() { return DOCTEST_CONFIG_GETCURRENTTICKS(); } +#elif defined(DOCTEST_PLATFORM_WINDOWS) + ticks_t getCurrentTicks() { + static LARGE_INTEGER hz = {0}, hzo = {0}; + if(!hz.QuadPart) { + QueryPerformanceFrequency(&hz); + QueryPerformanceCounter(&hzo); + } + LARGE_INTEGER t; + QueryPerformanceCounter(&t); + return ((t.QuadPart - hzo.QuadPart) * LONGLONG(1000000)) / hz.QuadPart; + } +#else // DOCTEST_PLATFORM_WINDOWS + ticks_t getCurrentTicks() { + timeval t; + gettimeofday(&t, nullptr); + return static_cast(t.tv_sec) * 1000000 + static_cast(t.tv_usec); + } +#endif // DOCTEST_PLATFORM_WINDOWS + + struct Timer + { + void start() { m_ticks = getCurrentTicks(); } + unsigned int getElapsedMicroseconds() const { + return static_cast(getCurrentTicks() - m_ticks); + } + //unsigned int getElapsedMilliseconds() const { + // return static_cast(getElapsedMicroseconds() / 1000); + //} + double getElapsedSeconds() const { return static_cast(getCurrentTicks() - m_ticks) / 1000000.0; } + + private: + ticks_t m_ticks = 0; + }; + + // this holds both parameters from the command line and runtime data for tests + struct ContextState : ContextOptions, TestRunStats, CurrentTestCaseStats + { + std::atomic numAssertsCurrentTest_atomic; + std::atomic numAssertsFailedCurrentTest_atomic; + + std::vector> filters = decltype(filters)(9); // 9 different filters + + std::vector reporters_currently_used; + + const TestCase* currentTest = nullptr; + + assert_handler ah = nullptr; + + Timer timer; + + std::vector stringifiedContexts; // logging from INFO() due to an exception + + // stuff for subcases + std::vector subcasesStack; + std::set subcasesPassed; + int subcasesCurrentMaxLevel; + bool should_reenter; + std::atomic shouldLogCurrentException; + + void resetRunData() { + numTestCases = 0; + numTestCasesPassingFilters = 0; + numTestSuitesPassingFilters = 0; + numTestCasesFailed = 0; + numAsserts = 0; + numAssertsFailed = 0; + numAssertsCurrentTest = 0; + numAssertsFailedCurrentTest = 0; + } + + void finalizeTestCaseData() { + seconds = timer.getElapsedSeconds(); + + // update the non-atomic counters + numAsserts += numAssertsCurrentTest_atomic; + numAssertsFailed += numAssertsFailedCurrentTest_atomic; + numAssertsCurrentTest = numAssertsCurrentTest_atomic; + numAssertsFailedCurrentTest = numAssertsFailedCurrentTest_atomic; + + if(numAssertsFailedCurrentTest) + failure_flags |= TestCaseFailureReason::AssertFailure; + + if(Approx(currentTest->m_timeout).epsilon(DBL_EPSILON) != 0 && + Approx(seconds).epsilon(DBL_EPSILON) > currentTest->m_timeout) + failure_flags |= TestCaseFailureReason::Timeout; + + if(currentTest->m_should_fail) { + if(failure_flags) { + failure_flags |= TestCaseFailureReason::ShouldHaveFailedAndDid; + } else { + failure_flags |= TestCaseFailureReason::ShouldHaveFailedButDidnt; + } + } else if(failure_flags && currentTest->m_may_fail) { + failure_flags |= TestCaseFailureReason::CouldHaveFailedAndDid; + } else if(currentTest->m_expected_failures > 0) { + if(numAssertsFailedCurrentTest == currentTest->m_expected_failures) { + failure_flags |= TestCaseFailureReason::FailedExactlyNumTimes; + } else { + failure_flags |= TestCaseFailureReason::DidntFailExactlyNumTimes; + } + } + + bool ok_to_fail = (TestCaseFailureReason::ShouldHaveFailedAndDid & failure_flags) || + (TestCaseFailureReason::CouldHaveFailedAndDid & failure_flags) || + (TestCaseFailureReason::FailedExactlyNumTimes & failure_flags); + + // if any subcase has failed - the whole test case has failed + if(failure_flags && !ok_to_fail) + numTestCasesFailed++; + } + }; + + ContextState* g_cs = nullptr; + + // used to avoid locks for the debug output + // TODO: figure out if this is indeed necessary/correct - seems like either there still + // could be a race or that there wouldn't be a race even if using the context directly + DOCTEST_THREAD_LOCAL bool g_no_colors; + +#endif // DOCTEST_CONFIG_DISABLE +} // namespace detail + +void String::setOnHeap() { *reinterpret_cast(&buf[last]) = 128; } +void String::setLast(unsigned in) { buf[last] = char(in); } + +void String::copy(const String& other) { + using namespace std; + if(other.isOnStack()) { + memcpy(buf, other.buf, len); + } else { + setOnHeap(); + data.size = other.data.size; + data.capacity = data.size + 1; + data.ptr = new char[data.capacity]; + memcpy(data.ptr, other.data.ptr, data.size + 1); + } +} + +String::String() { + buf[0] = '\0'; + setLast(); +} + +String::~String() { + if(!isOnStack()) + delete[] data.ptr; +} + +String::String(const char* in) + : String(in, strlen(in)) {} + +String::String(const char* in, unsigned in_size) { + using namespace std; + if(in_size <= last) { + memcpy(buf, in, in_size + 1); + setLast(last - in_size); + } else { + setOnHeap(); + data.size = in_size; + data.capacity = data.size + 1; + data.ptr = new char[data.capacity]; + memcpy(data.ptr, in, in_size + 1); + } +} + +String::String(const String& other) { copy(other); } + +String& String::operator=(const String& other) { + if(this != &other) { + if(!isOnStack()) + delete[] data.ptr; + + copy(other); + } + + return *this; +} + +String& String::operator+=(const String& other) { + const unsigned my_old_size = size(); + const unsigned other_size = other.size(); + const unsigned total_size = my_old_size + other_size; + using namespace std; + if(isOnStack()) { + if(total_size < len) { + // append to the current stack space + memcpy(buf + my_old_size, other.c_str(), other_size + 1); + setLast(last - total_size); + } else { + // alloc new chunk + char* temp = new char[total_size + 1]; + // copy current data to new location before writing in the union + memcpy(temp, buf, my_old_size); // skip the +1 ('\0') for speed + // update data in union + setOnHeap(); + data.size = total_size; + data.capacity = data.size + 1; + data.ptr = temp; + // transfer the rest of the data + memcpy(data.ptr + my_old_size, other.c_str(), other_size + 1); + } + } else { + if(data.capacity > total_size) { + // append to the current heap block + data.size = total_size; + memcpy(data.ptr + my_old_size, other.c_str(), other_size + 1); + } else { + // resize + data.capacity *= 2; + if(data.capacity <= total_size) + data.capacity = total_size + 1; + // alloc new chunk + char* temp = new char[data.capacity]; + // copy current data to new location before releasing it + memcpy(temp, data.ptr, my_old_size); // skip the +1 ('\0') for speed + // release old chunk + delete[] data.ptr; + // update the rest of the union members + data.size = total_size; + data.ptr = temp; + // transfer the rest of the data + memcpy(data.ptr + my_old_size, other.c_str(), other_size + 1); + } + } + + return *this; +} + +String String::operator+(const String& other) const { return String(*this) += other; } + +String::String(String&& other) { + using namespace std; + memcpy(buf, other.buf, len); + other.buf[0] = '\0'; + other.setLast(); +} + +String& String::operator=(String&& other) { + using namespace std; + if(this != &other) { + if(!isOnStack()) + delete[] data.ptr; + memcpy(buf, other.buf, len); + other.buf[0] = '\0'; + other.setLast(); + } + return *this; +} + +char String::operator[](unsigned i) const { + return const_cast(this)->operator[](i); // NOLINT +} + +char& String::operator[](unsigned i) { + if(isOnStack()) + return reinterpret_cast(buf)[i]; + return data.ptr[i]; +} + +DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH("-Wmaybe-uninitialized") +unsigned String::size() const { + if(isOnStack()) + return last - (unsigned(buf[last]) & 31); // using "last" would work only if "len" is 32 + return data.size; +} +DOCTEST_GCC_SUPPRESS_WARNING_POP + +unsigned String::capacity() const { + if(isOnStack()) + return len; + return data.capacity; +} + +int String::compare(const char* other, bool no_case) const { + if(no_case) + return doctest::stricmp(c_str(), other); + return std::strcmp(c_str(), other); +} + +int String::compare(const String& other, bool no_case) const { + return compare(other.c_str(), no_case); +} + +// clang-format off +bool operator==(const String& lhs, const String& rhs) { return lhs.compare(rhs) == 0; } +bool operator!=(const String& lhs, const String& rhs) { return lhs.compare(rhs) != 0; } +bool operator< (const String& lhs, const String& rhs) { return lhs.compare(rhs) < 0; } +bool operator> (const String& lhs, const String& rhs) { return lhs.compare(rhs) > 0; } +bool operator<=(const String& lhs, const String& rhs) { return (lhs != rhs) ? lhs.compare(rhs) < 0 : true; } +bool operator>=(const String& lhs, const String& rhs) { return (lhs != rhs) ? lhs.compare(rhs) > 0 : true; } +// clang-format on + +std::ostream& operator<<(std::ostream& s, const String& in) { return s << in.c_str(); } + +namespace { + void color_to_stream(std::ostream&, Color::Enum) DOCTEST_BRANCH_ON_DISABLED({}, ;) +} // namespace + +namespace Color { + std::ostream& operator<<(std::ostream& s, Color::Enum code) { + color_to_stream(s, code); + return s; + } +} // namespace Color + +// clang-format off +const char* assertString(assertType::Enum at) { + DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4062) // enum 'x' in switch of enum 'y' is not handled + switch(at) { //!OCLINT missing default in switch statements + case assertType::DT_WARN : return "WARN"; + case assertType::DT_CHECK : return "CHECK"; + case assertType::DT_REQUIRE : return "REQUIRE"; + + case assertType::DT_WARN_FALSE : return "WARN_FALSE"; + case assertType::DT_CHECK_FALSE : return "CHECK_FALSE"; + case assertType::DT_REQUIRE_FALSE : return "REQUIRE_FALSE"; + + case assertType::DT_WARN_THROWS : return "WARN_THROWS"; + case assertType::DT_CHECK_THROWS : return "CHECK_THROWS"; + case assertType::DT_REQUIRE_THROWS : return "REQUIRE_THROWS"; + + case assertType::DT_WARN_THROWS_AS : return "WARN_THROWS_AS"; + case assertType::DT_CHECK_THROWS_AS : return "CHECK_THROWS_AS"; + case assertType::DT_REQUIRE_THROWS_AS : return "REQUIRE_THROWS_AS"; + + case assertType::DT_WARN_THROWS_WITH : return "WARN_THROWS_WITH"; + case assertType::DT_CHECK_THROWS_WITH : return "CHECK_THROWS_WITH"; + case assertType::DT_REQUIRE_THROWS_WITH : return "REQUIRE_THROWS_WITH"; + + case assertType::DT_WARN_THROWS_WITH_AS : return "WARN_THROWS_WITH_AS"; + case assertType::DT_CHECK_THROWS_WITH_AS : return "CHECK_THROWS_WITH_AS"; + case assertType::DT_REQUIRE_THROWS_WITH_AS : return "REQUIRE_THROWS_WITH_AS"; + + case assertType::DT_WARN_NOTHROW : return "WARN_NOTHROW"; + case assertType::DT_CHECK_NOTHROW : return "CHECK_NOTHROW"; + case assertType::DT_REQUIRE_NOTHROW : return "REQUIRE_NOTHROW"; + + case assertType::DT_WARN_EQ : return "WARN_EQ"; + case assertType::DT_CHECK_EQ : return "CHECK_EQ"; + case assertType::DT_REQUIRE_EQ : return "REQUIRE_EQ"; + case assertType::DT_WARN_NE : return "WARN_NE"; + case assertType::DT_CHECK_NE : return "CHECK_NE"; + case assertType::DT_REQUIRE_NE : return "REQUIRE_NE"; + case assertType::DT_WARN_GT : return "WARN_GT"; + case assertType::DT_CHECK_GT : return "CHECK_GT"; + case assertType::DT_REQUIRE_GT : return "REQUIRE_GT"; + case assertType::DT_WARN_LT : return "WARN_LT"; + case assertType::DT_CHECK_LT : return "CHECK_LT"; + case assertType::DT_REQUIRE_LT : return "REQUIRE_LT"; + case assertType::DT_WARN_GE : return "WARN_GE"; + case assertType::DT_CHECK_GE : return "CHECK_GE"; + case assertType::DT_REQUIRE_GE : return "REQUIRE_GE"; + case assertType::DT_WARN_LE : return "WARN_LE"; + case assertType::DT_CHECK_LE : return "CHECK_LE"; + case assertType::DT_REQUIRE_LE : return "REQUIRE_LE"; + + case assertType::DT_WARN_UNARY : return "WARN_UNARY"; + case assertType::DT_CHECK_UNARY : return "CHECK_UNARY"; + case assertType::DT_REQUIRE_UNARY : return "REQUIRE_UNARY"; + case assertType::DT_WARN_UNARY_FALSE : return "WARN_UNARY_FALSE"; + case assertType::DT_CHECK_UNARY_FALSE : return "CHECK_UNARY_FALSE"; + case assertType::DT_REQUIRE_UNARY_FALSE : return "REQUIRE_UNARY_FALSE"; + } + DOCTEST_MSVC_SUPPRESS_WARNING_POP + return ""; +} +// clang-format on + +const char* failureString(assertType::Enum at) { + if(at & assertType::is_warn) //!OCLINT bitwise operator in conditional + return "WARNING"; + if(at & assertType::is_check) //!OCLINT bitwise operator in conditional + return "ERROR"; + if(at & assertType::is_require) //!OCLINT bitwise operator in conditional + return "FATAL ERROR"; + return ""; +} + +DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wnull-dereference") +DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH("-Wnull-dereference") +// depending on the current options this will remove the path of filenames +const char* skipPathFromFilename(const char* file) { + if(getContextOptions()->no_path_in_filenames) { + auto back = std::strrchr(file, '\\'); + auto forward = std::strrchr(file, '/'); + if(back || forward) { + if(back > forward) + forward = back; + return forward + 1; + } + } + return file; +} +DOCTEST_CLANG_SUPPRESS_WARNING_POP +DOCTEST_GCC_SUPPRESS_WARNING_POP + +bool SubcaseSignature::operator<(const SubcaseSignature& other) const { + if(m_line != other.m_line) + return m_line < other.m_line; + if(std::strcmp(m_file, other.m_file) != 0) + return std::strcmp(m_file, other.m_file) < 0; + return m_name.compare(other.m_name) < 0; +} + +IContextScope::IContextScope() = default; +IContextScope::~IContextScope() = default; + +#ifdef DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING +String toString(char* in) { return toString(static_cast(in)); } +String toString(const char* in) { return String("\"") + (in ? in : "{null string}") + "\""; } +#endif // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING +String toString(bool in) { return in ? "true" : "false"; } +String toString(float in) { return fpToString(in, 5) + "f"; } +String toString(double in) { return fpToString(in, 10); } +String toString(double long in) { return fpToString(in, 15); } + +#define DOCTEST_TO_STRING_OVERLOAD(type, fmt) \ + String toString(type in) { \ + char buf[64]; \ + std::sprintf(buf, fmt, in); \ + return buf; \ + } + +DOCTEST_TO_STRING_OVERLOAD(char, "%d") +DOCTEST_TO_STRING_OVERLOAD(char signed, "%d") +DOCTEST_TO_STRING_OVERLOAD(char unsigned, "%u") +DOCTEST_TO_STRING_OVERLOAD(int short, "%d") +DOCTEST_TO_STRING_OVERLOAD(int short unsigned, "%u") +DOCTEST_TO_STRING_OVERLOAD(int, "%d") +DOCTEST_TO_STRING_OVERLOAD(unsigned, "%u") +DOCTEST_TO_STRING_OVERLOAD(int long, "%ld") +DOCTEST_TO_STRING_OVERLOAD(int long unsigned, "%lu") +DOCTEST_TO_STRING_OVERLOAD(int long long, "%lld") +DOCTEST_TO_STRING_OVERLOAD(int long long unsigned, "%llu") + +String toString(std::nullptr_t) { return "NULL"; } + +#if DOCTEST_MSVC >= DOCTEST_COMPILER(19, 20, 0) +// see this issue on why this is needed: https://github.com/onqtam/doctest/issues/183 +String toString(const std::string& in) { return in.c_str(); } +#endif // VS 2019 + +Approx::Approx(double value) + : m_epsilon(static_cast(std::numeric_limits::epsilon()) * 100) + , m_scale(1.0) + , m_value(value) {} + +Approx Approx::operator()(double value) const { + Approx approx(value); + approx.epsilon(m_epsilon); + approx.scale(m_scale); + return approx; +} + +Approx& Approx::epsilon(double newEpsilon) { + m_epsilon = newEpsilon; + return *this; +} +Approx& Approx::scale(double newScale) { + m_scale = newScale; + return *this; +} + +bool operator==(double lhs, const Approx& rhs) { + // Thanks to Richard Harris for his help refining this formula + return std::fabs(lhs - rhs.m_value) < + rhs.m_epsilon * (rhs.m_scale + std::max(std::fabs(lhs), std::fabs(rhs.m_value))); +} +bool operator==(const Approx& lhs, double rhs) { return operator==(rhs, lhs); } +bool operator!=(double lhs, const Approx& rhs) { return !operator==(lhs, rhs); } +bool operator!=(const Approx& lhs, double rhs) { return !operator==(rhs, lhs); } +bool operator<=(double lhs, const Approx& rhs) { return lhs < rhs.m_value || lhs == rhs; } +bool operator<=(const Approx& lhs, double rhs) { return lhs.m_value < rhs || lhs == rhs; } +bool operator>=(double lhs, const Approx& rhs) { return lhs > rhs.m_value || lhs == rhs; } +bool operator>=(const Approx& lhs, double rhs) { return lhs.m_value > rhs || lhs == rhs; } +bool operator<(double lhs, const Approx& rhs) { return lhs < rhs.m_value && lhs != rhs; } +bool operator<(const Approx& lhs, double rhs) { return lhs.m_value < rhs && lhs != rhs; } +bool operator>(double lhs, const Approx& rhs) { return lhs > rhs.m_value && lhs != rhs; } +bool operator>(const Approx& lhs, double rhs) { return lhs.m_value > rhs && lhs != rhs; } + +String toString(const Approx& in) { + return String("Approx( ") + doctest::toString(in.m_value) + " )"; +} +const ContextOptions* getContextOptions() { return DOCTEST_BRANCH_ON_DISABLED(nullptr, g_cs); } + +} // namespace doctest + +#ifdef DOCTEST_CONFIG_DISABLE +namespace doctest { +Context::Context(int, const char* const*) {} +Context::~Context() = default; +void Context::applyCommandLine(int, const char* const*) {} +void Context::addFilter(const char*, const char*) {} +void Context::clearFilters() {} +void Context::setOption(const char*, int) {} +void Context::setOption(const char*, const char*) {} +bool Context::shouldExit() { return false; } +void Context::setAsDefaultForAssertsOutOfTestCases() {} +void Context::setAssertHandler(detail::assert_handler) {} +int Context::run() { return 0; } + +IReporter::~IReporter() = default; + +int IReporter::get_num_active_contexts() { return 0; } +const IContextScope* const* IReporter::get_active_contexts() { return nullptr; } +int IReporter::get_num_stringified_contexts() { return 0; } +const String* IReporter::get_stringified_contexts() { return nullptr; } + +int registerReporter(const char*, int, IReporter*) { return 0; } + +} // namespace doctest +#else // DOCTEST_CONFIG_DISABLE + +#if !defined(DOCTEST_CONFIG_COLORS_NONE) +#if !defined(DOCTEST_CONFIG_COLORS_WINDOWS) && !defined(DOCTEST_CONFIG_COLORS_ANSI) +#ifdef DOCTEST_PLATFORM_WINDOWS +#define DOCTEST_CONFIG_COLORS_WINDOWS +#else // linux +#define DOCTEST_CONFIG_COLORS_ANSI +#endif // platform +#endif // DOCTEST_CONFIG_COLORS_WINDOWS && DOCTEST_CONFIG_COLORS_ANSI +#endif // DOCTEST_CONFIG_COLORS_NONE + +namespace doctest_detail_test_suite_ns { +// holds the current test suite +doctest::detail::TestSuite& getCurrentTestSuite() { + static doctest::detail::TestSuite data; + return data; +} +} // namespace doctest_detail_test_suite_ns + +namespace doctest { +namespace { + // the int (priority) is part of the key for automatic sorting - sadly one can register a + // reporter with a duplicate name and a different priority but hopefully that won't happen often :| + typedef std::map, reporterCreatorFunc> reporterMap; + + reporterMap& getReporters() { + static reporterMap data; + return data; + } + reporterMap& getListeners() { + static reporterMap data; + return data; + } +} // namespace +namespace detail { +#define DOCTEST_ITERATE_THROUGH_REPORTERS(function, ...) \ + for(auto& curr_rep : g_cs->reporters_currently_used) \ + curr_rep->function(__VA_ARGS__) + + bool checkIfShouldThrow(assertType::Enum at) { + if(at & assertType::is_require) //!OCLINT bitwise operator in conditional + return true; + + if((at & assertType::is_check) //!OCLINT bitwise operator in conditional + && getContextOptions()->abort_after > 0 && + (g_cs->numAssertsFailed + g_cs->numAssertsFailedCurrentTest_atomic) >= + getContextOptions()->abort_after) + return true; + + return false; + } + +#ifndef DOCTEST_CONFIG_NO_EXCEPTIONS + DOCTEST_NORETURN void throwException() { + g_cs->shouldLogCurrentException = false; + throw TestFailureException(); + } // NOLINT(cert-err60-cpp) +#else // DOCTEST_CONFIG_NO_EXCEPTIONS + void throwException() {} +#endif // DOCTEST_CONFIG_NO_EXCEPTIONS +} // namespace detail + +namespace { + using namespace detail; + // matching of a string against a wildcard mask (case sensitivity configurable) taken from + // https://www.codeproject.com/Articles/1088/Wildcard-string-compare-globbing + int wildcmp(const char* str, const char* wild, bool caseSensitive) { + const char* cp = str; + const char* mp = wild; + + while((*str) && (*wild != '*')) { + if((caseSensitive ? (*wild != *str) : (tolower(*wild) != tolower(*str))) && + (*wild != '?')) { + return 0; + } + wild++; + str++; + } + + while(*str) { + if(*wild == '*') { + if(!*++wild) { + return 1; + } + mp = wild; + cp = str + 1; + } else if((caseSensitive ? (*wild == *str) : (tolower(*wild) == tolower(*str))) || + (*wild == '?')) { + wild++; + str++; + } else { + wild = mp; //!OCLINT parameter reassignment + str = cp++; //!OCLINT parameter reassignment + } + } + + while(*wild == '*') { + wild++; + } + return !*wild; + } + + //// C string hash function (djb2) - taken from http://www.cse.yorku.ca/~oz/hash.html + //unsigned hashStr(unsigned const char* str) { + // unsigned long hash = 5381; + // char c; + // while((c = *str++)) + // hash = ((hash << 5) + hash) + c; // hash * 33 + c + // return hash; + //} + + // checks if the name matches any of the filters (and can be configured what to do when empty) + bool matchesAny(const char* name, const std::vector& filters, bool matchEmpty, + bool caseSensitive) { + if(filters.empty() && matchEmpty) + return true; + for(auto& curr : filters) + if(wildcmp(name, curr.c_str(), caseSensitive)) + return true; + return false; + } +} // namespace +namespace detail { + + Subcase::Subcase(const String& name, const char* file, int line) + : m_signature({name, file, line}) { + ContextState* s = g_cs; + + // check subcase filters + if(s->subcasesStack.size() < size_t(s->subcase_filter_levels)) { + if(!matchesAny(m_signature.m_name.c_str(), s->filters[6], true, s->case_sensitive)) + return; + if(matchesAny(m_signature.m_name.c_str(), s->filters[7], false, s->case_sensitive)) + return; + } + + // if a Subcase on the same level has already been entered + if(s->subcasesStack.size() < size_t(s->subcasesCurrentMaxLevel)) { + s->should_reenter = true; + return; + } + + // push the current signature to the stack so we can check if the + // current stack + the current new subcase have been traversed + s->subcasesStack.push_back(m_signature); + if(s->subcasesPassed.count(s->subcasesStack) != 0) { + // pop - revert to previous stack since we've already passed this + s->subcasesStack.pop_back(); + return; + } + + s->subcasesCurrentMaxLevel = s->subcasesStack.size(); + m_entered = true; + + DOCTEST_ITERATE_THROUGH_REPORTERS(subcase_start, m_signature); + } + + DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4996) // std::uncaught_exception is deprecated in C++17 + DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH("-Wdeprecated-declarations") + DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wdeprecated-declarations") + + Subcase::~Subcase() { + if(m_entered) { + // only mark the subcase stack as passed if no subcases have been skipped + if(g_cs->should_reenter == false) + g_cs->subcasesPassed.insert(g_cs->subcasesStack); + g_cs->subcasesStack.pop_back(); + +#if defined(__cpp_lib_uncaught_exceptions) && __cpp_lib_uncaught_exceptions >= 201411L + if(std::uncaught_exceptions() > 0 +#else + if(std::uncaught_exception() +#endif + && g_cs->shouldLogCurrentException) { + DOCTEST_ITERATE_THROUGH_REPORTERS( + test_case_exception, {"exception thrown in subcase - will translate later " + "when the whole test case has been exited (cannot " + "translate while there is an active exception)", + false}); + g_cs->shouldLogCurrentException = false; + } + DOCTEST_ITERATE_THROUGH_REPORTERS(subcase_end, DOCTEST_EMPTY); + } + } + + DOCTEST_CLANG_SUPPRESS_WARNING_POP + DOCTEST_GCC_SUPPRESS_WARNING_POP + DOCTEST_MSVC_SUPPRESS_WARNING_POP + + Subcase::operator bool() const { return m_entered; } + + Result::Result(bool passed, const String& decomposition) + : m_passed(passed) + , m_decomp(decomposition) {} + + ExpressionDecomposer::ExpressionDecomposer(assertType::Enum at) + : m_at(at) {} + + TestSuite& TestSuite::operator*(const char* in) { + m_test_suite = in; + // clear state + m_description = nullptr; + m_skip = false; + m_may_fail = false; + m_should_fail = false; + m_expected_failures = 0; + m_timeout = 0; + return *this; + } + + TestCase::TestCase(funcType test, const char* file, unsigned line, const TestSuite& test_suite, + const char* type, int template_id) { + m_file = file; + m_line = line; + m_name = nullptr; // will be later overridden in operator* + m_test_suite = test_suite.m_test_suite; + m_description = test_suite.m_description; + m_skip = test_suite.m_skip; + m_may_fail = test_suite.m_may_fail; + m_should_fail = test_suite.m_should_fail; + m_expected_failures = test_suite.m_expected_failures; + m_timeout = test_suite.m_timeout; + + m_test = test; + m_type = type; + m_template_id = template_id; + } + + TestCase::TestCase(const TestCase& other) + : TestCaseData() { + *this = other; + } + + DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(26434) // hides a non-virtual function + DOCTEST_MSVC_SUPPRESS_WARNING(26437) // Do not slice + TestCase& TestCase::operator=(const TestCase& other) { + static_cast(*this) = static_cast(other); + + m_test = other.m_test; + m_type = other.m_type; + m_template_id = other.m_template_id; + m_full_name = other.m_full_name; + + if(m_template_id != -1) + m_name = m_full_name.c_str(); + return *this; + } + DOCTEST_MSVC_SUPPRESS_WARNING_POP + + TestCase& TestCase::operator*(const char* in) { + m_name = in; + // make a new name with an appended type for templated test case + if(m_template_id != -1) { + m_full_name = String(m_name) + m_type; + // redirect the name to point to the newly constructed full name + m_name = m_full_name.c_str(); + } + return *this; + } + + bool TestCase::operator<(const TestCase& other) const { + if(m_line != other.m_line) + return m_line < other.m_line; + const int file_cmp = m_file.compare(other.m_file); + if(file_cmp != 0) + return file_cmp < 0; + return m_template_id < other.m_template_id; + } +} // namespace detail +namespace { + using namespace detail; + // for sorting tests by file/line + bool fileOrderComparator(const TestCase* lhs, const TestCase* rhs) { + // this is needed because MSVC gives different case for drive letters + // for __FILE__ when evaluated in a header and a source file + const int res = lhs->m_file.compare(rhs->m_file, bool(DOCTEST_MSVC)); + if(res != 0) + return res < 0; + if(lhs->m_line != rhs->m_line) + return lhs->m_line < rhs->m_line; + return lhs->m_template_id < rhs->m_template_id; + } + + // for sorting tests by suite/file/line + bool suiteOrderComparator(const TestCase* lhs, const TestCase* rhs) { + const int res = std::strcmp(lhs->m_test_suite, rhs->m_test_suite); + if(res != 0) + return res < 0; + return fileOrderComparator(lhs, rhs); + } + + // for sorting tests by name/suite/file/line + bool nameOrderComparator(const TestCase* lhs, const TestCase* rhs) { + const int res = std::strcmp(lhs->m_name, rhs->m_name); + if(res != 0) + return res < 0; + return suiteOrderComparator(lhs, rhs); + } + + // all the registered tests + std::set& getRegisteredTests() { + static std::set data; + return data; + } + +#ifdef DOCTEST_CONFIG_COLORS_WINDOWS + HANDLE g_stdoutHandle; + WORD g_origFgAttrs; + WORD g_origBgAttrs; + bool g_attrsInitted = false; + + int colors_init() { + if(!g_attrsInitted) { + g_stdoutHandle = GetStdHandle(STD_OUTPUT_HANDLE); + g_attrsInitted = true; + CONSOLE_SCREEN_BUFFER_INFO csbiInfo; + GetConsoleScreenBufferInfo(g_stdoutHandle, &csbiInfo); + g_origFgAttrs = csbiInfo.wAttributes & ~(BACKGROUND_GREEN | BACKGROUND_RED | + BACKGROUND_BLUE | BACKGROUND_INTENSITY); + g_origBgAttrs = csbiInfo.wAttributes & ~(FOREGROUND_GREEN | FOREGROUND_RED | + FOREGROUND_BLUE | FOREGROUND_INTENSITY); + } + return 0; + } + + int dumy_init_console_colors = colors_init(); +#endif // DOCTEST_CONFIG_COLORS_WINDOWS + + DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wdeprecated-declarations") + void color_to_stream(std::ostream& s, Color::Enum code) { + ((void)s); // for DOCTEST_CONFIG_COLORS_NONE or DOCTEST_CONFIG_COLORS_WINDOWS + ((void)code); // for DOCTEST_CONFIG_COLORS_NONE +#ifdef DOCTEST_CONFIG_COLORS_ANSI + if(g_no_colors || + (isatty(STDOUT_FILENO) == false && getContextOptions()->force_colors == false)) + return; + + auto col = ""; + // clang-format off + switch(code) { //!OCLINT missing break in switch statement / unnecessary default statement in covered switch statement + case Color::Red: col = "[0;31m"; break; + case Color::Green: col = "[0;32m"; break; + case Color::Blue: col = "[0;34m"; break; + case Color::Cyan: col = "[0;36m"; break; + case Color::Yellow: col = "[0;33m"; break; + case Color::Grey: col = "[1;30m"; break; + case Color::LightGrey: col = "[0;37m"; break; + case Color::BrightRed: col = "[1;31m"; break; + case Color::BrightGreen: col = "[1;32m"; break; + case Color::BrightWhite: col = "[1;37m"; break; + case Color::Bright: // invalid + case Color::None: + case Color::White: + default: col = "[0m"; + } + // clang-format on + s << "\033" << col; +#endif // DOCTEST_CONFIG_COLORS_ANSI + +#ifdef DOCTEST_CONFIG_COLORS_WINDOWS + if(g_no_colors || + (isatty(fileno(stdout)) == false && getContextOptions()->force_colors == false)) + return; + +#define DOCTEST_SET_ATTR(x) SetConsoleTextAttribute(g_stdoutHandle, x | g_origBgAttrs) + + // clang-format off + switch (code) { + case Color::White: DOCTEST_SET_ATTR(FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE); break; + case Color::Red: DOCTEST_SET_ATTR(FOREGROUND_RED); break; + case Color::Green: DOCTEST_SET_ATTR(FOREGROUND_GREEN); break; + case Color::Blue: DOCTEST_SET_ATTR(FOREGROUND_BLUE); break; + case Color::Cyan: DOCTEST_SET_ATTR(FOREGROUND_BLUE | FOREGROUND_GREEN); break; + case Color::Yellow: DOCTEST_SET_ATTR(FOREGROUND_RED | FOREGROUND_GREEN); break; + case Color::Grey: DOCTEST_SET_ATTR(0); break; + case Color::LightGrey: DOCTEST_SET_ATTR(FOREGROUND_INTENSITY); break; + case Color::BrightRed: DOCTEST_SET_ATTR(FOREGROUND_INTENSITY | FOREGROUND_RED); break; + case Color::BrightGreen: DOCTEST_SET_ATTR(FOREGROUND_INTENSITY | FOREGROUND_GREEN); break; + case Color::BrightWhite: DOCTEST_SET_ATTR(FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE); break; + case Color::None: + case Color::Bright: // invalid + default: DOCTEST_SET_ATTR(g_origFgAttrs); + } + // clang-format on +#endif // DOCTEST_CONFIG_COLORS_WINDOWS + } + DOCTEST_CLANG_SUPPRESS_WARNING_POP + + std::vector& getExceptionTranslators() { + static std::vector data; + return data; + } + + String translateActiveException() { +#ifndef DOCTEST_CONFIG_NO_EXCEPTIONS + String res; + auto& translators = getExceptionTranslators(); + for(auto& curr : translators) + if(curr->translate(res)) + return res; + // clang-format off + DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH("-Wcatch-value") + try { + throw; + } catch(std::exception& ex) { + return ex.what(); + } catch(std::string& msg) { + return msg.c_str(); + } catch(const char* msg) { + return msg; + } catch(...) { + return "unknown exception"; + } + DOCTEST_GCC_SUPPRESS_WARNING_POP +// clang-format on +#else // DOCTEST_CONFIG_NO_EXCEPTIONS + return ""; +#endif // DOCTEST_CONFIG_NO_EXCEPTIONS + } +} // namespace + +namespace detail { + // used by the macros for registering tests + int regTest(const TestCase& tc) { + getRegisteredTests().insert(tc); + return 0; + } + + // sets the current test suite + int setTestSuite(const TestSuite& ts) { + doctest_detail_test_suite_ns::getCurrentTestSuite() = ts; + return 0; + } + +#ifdef DOCTEST_IS_DEBUGGER_ACTIVE + bool isDebuggerActive() { return DOCTEST_IS_DEBUGGER_ACTIVE(); } +#else // DOCTEST_IS_DEBUGGER_ACTIVE +#ifdef DOCTEST_PLATFORM_MAC + // The following function is taken directly from the following technical note: + // https://developer.apple.com/library/archive/qa/qa1361/_index.html + // Returns true if the current process is being debugged (either + // running under the debugger or has a debugger attached post facto). + bool isDebuggerActive() { + int mib[4]; + kinfo_proc info; + size_t size; + // Initialize the flags so that, if sysctl fails for some bizarre + // reason, we get a predictable result. + info.kp_proc.p_flag = 0; + // Initialize mib, which tells sysctl the info we want, in this case + // we're looking for information about a specific process ID. + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_PID; + mib[3] = getpid(); + // Call sysctl. + size = sizeof(info); + if(sysctl(mib, DOCTEST_COUNTOF(mib), &info, &size, 0, 0) != 0) { + std::cerr << "\nCall to sysctl failed - unable to determine if debugger is active **\n"; + return false; + } + // We're being debugged if the P_TRACED flag is set. + return ((info.kp_proc.p_flag & P_TRACED) != 0); + } +#elif DOCTEST_MSVC || defined(__MINGW32__) || defined(__MINGW64__) + bool isDebuggerActive() { return ::IsDebuggerPresent() != 0; } +#else + bool isDebuggerActive() { return false; } +#endif // Platform +#endif // DOCTEST_IS_DEBUGGER_ACTIVE + + void registerExceptionTranslatorImpl(const IExceptionTranslator* et) { + if(std::find(getExceptionTranslators().begin(), getExceptionTranslators().end(), et) == + getExceptionTranslators().end()) + getExceptionTranslators().push_back(et); + } + +#ifdef DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING + void toStream(std::ostream* s, char* in) { *s << in; } + void toStream(std::ostream* s, const char* in) { *s << in; } +#endif // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING + void toStream(std::ostream* s, bool in) { *s << std::boolalpha << in << std::noboolalpha; } + void toStream(std::ostream* s, float in) { *s << in; } + void toStream(std::ostream* s, double in) { *s << in; } + void toStream(std::ostream* s, double long in) { *s << in; } + + void toStream(std::ostream* s, char in) { *s << in; } + void toStream(std::ostream* s, char signed in) { *s << in; } + void toStream(std::ostream* s, char unsigned in) { *s << in; } + void toStream(std::ostream* s, int short in) { *s << in; } + void toStream(std::ostream* s, int short unsigned in) { *s << in; } + void toStream(std::ostream* s, int in) { *s << in; } + void toStream(std::ostream* s, int unsigned in) { *s << in; } + void toStream(std::ostream* s, int long in) { *s << in; } + void toStream(std::ostream* s, int long unsigned in) { *s << in; } + void toStream(std::ostream* s, int long long in) { *s << in; } + void toStream(std::ostream* s, int long long unsigned in) { *s << in; } + + DOCTEST_THREAD_LOCAL std::vector g_infoContexts; // for logging with INFO() + + ContextScopeBase::ContextScopeBase() { + g_infoContexts.push_back(this); + } + + DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4996) // std::uncaught_exception is deprecated in C++17 + DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH("-Wdeprecated-declarations") + DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wdeprecated-declarations") + + // destroy cannot be inlined into the destructor because that would mean calling stringify after + // ContextScope has been destroyed (base class destructors run after derived class destructors). + // Instead, ContextScope calls this method directly from its destructor. + void ContextScopeBase::destroy() { +#if defined(__cpp_lib_uncaught_exceptions) && __cpp_lib_uncaught_exceptions >= 201411L + if(std::uncaught_exceptions() > 0) { +#else + if(std::uncaught_exception()) { +#endif + std::ostringstream s; + this->stringify(&s); + g_cs->stringifiedContexts.push_back(s.str().c_str()); + } + g_infoContexts.pop_back(); + } + + DOCTEST_CLANG_SUPPRESS_WARNING_POP + DOCTEST_GCC_SUPPRESS_WARNING_POP + DOCTEST_MSVC_SUPPRESS_WARNING_POP +} // namespace detail +namespace { + using namespace detail; + +#if !defined(DOCTEST_CONFIG_POSIX_SIGNALS) && !defined(DOCTEST_CONFIG_WINDOWS_SEH) + struct FatalConditionHandler + { + void reset() {} + }; +#else // DOCTEST_CONFIG_POSIX_SIGNALS || DOCTEST_CONFIG_WINDOWS_SEH + + void reportFatal(const std::string&); + +#ifdef DOCTEST_PLATFORM_WINDOWS + + struct SignalDefs + { + DWORD id; + const char* name; + }; + // There is no 1-1 mapping between signals and windows exceptions. + // Windows can easily distinguish between SO and SigSegV, + // but SigInt, SigTerm, etc are handled differently. + SignalDefs signalDefs[] = { + {EXCEPTION_ILLEGAL_INSTRUCTION, "SIGILL - Illegal instruction signal"}, + {EXCEPTION_STACK_OVERFLOW, "SIGSEGV - Stack overflow"}, + {EXCEPTION_ACCESS_VIOLATION, "SIGSEGV - Segmentation violation signal"}, + {EXCEPTION_INT_DIVIDE_BY_ZERO, "Divide by zero error"}, + }; + + struct FatalConditionHandler + { + static LONG CALLBACK handleException(PEXCEPTION_POINTERS ExceptionInfo) { + for(size_t i = 0; i < DOCTEST_COUNTOF(signalDefs); ++i) { + if(ExceptionInfo->ExceptionRecord->ExceptionCode == signalDefs[i].id) { + reportFatal(signalDefs[i].name); + break; + } + } + // If its not an exception we care about, pass it along. + // This stops us from eating debugger breaks etc. + return EXCEPTION_CONTINUE_SEARCH; + } + + FatalConditionHandler() { + isSet = true; + // 32k seems enough for doctest to handle stack overflow, + // but the value was found experimentally, so there is no strong guarantee + guaranteeSize = 32 * 1024; + // Register an unhandled exception filter + previousTop = SetUnhandledExceptionFilter(handleException); + // Pass in guarantee size to be filled + SetThreadStackGuarantee(&guaranteeSize); + } + + static void reset() { + if(isSet) { + // Unregister handler and restore the old guarantee + SetUnhandledExceptionFilter(previousTop); + SetThreadStackGuarantee(&guaranteeSize); + previousTop = nullptr; + isSet = false; + } + } + + ~FatalConditionHandler() { reset(); } + + private: + static bool isSet; + static ULONG guaranteeSize; + static LPTOP_LEVEL_EXCEPTION_FILTER previousTop; + }; + + bool FatalConditionHandler::isSet = false; + ULONG FatalConditionHandler::guaranteeSize = 0; + LPTOP_LEVEL_EXCEPTION_FILTER FatalConditionHandler::previousTop = nullptr; + +#else // DOCTEST_PLATFORM_WINDOWS + + struct SignalDefs + { + int id; + const char* name; + }; + SignalDefs signalDefs[] = {{SIGINT, "SIGINT - Terminal interrupt signal"}, + {SIGILL, "SIGILL - Illegal instruction signal"}, + {SIGFPE, "SIGFPE - Floating point error signal"}, + {SIGSEGV, "SIGSEGV - Segmentation violation signal"}, + {SIGTERM, "SIGTERM - Termination request signal"}, + {SIGABRT, "SIGABRT - Abort (abnormal termination) signal"}}; + + struct FatalConditionHandler + { + static bool isSet; + static struct sigaction oldSigActions[DOCTEST_COUNTOF(signalDefs)]; + static stack_t oldSigStack; + static char altStackMem[4 * SIGSTKSZ]; + + static void handleSignal(int sig) { + const char* name = ""; + for(std::size_t i = 0; i < DOCTEST_COUNTOF(signalDefs); ++i) { + SignalDefs& def = signalDefs[i]; + if(sig == def.id) { + name = def.name; + break; + } + } + reset(); + reportFatal(name); + raise(sig); + } + + FatalConditionHandler() { + isSet = true; + stack_t sigStack; + sigStack.ss_sp = altStackMem; + sigStack.ss_size = sizeof(altStackMem); + sigStack.ss_flags = 0; + sigaltstack(&sigStack, &oldSigStack); + struct sigaction sa = {}; + sa.sa_handler = handleSignal; // NOLINT + sa.sa_flags = SA_ONSTACK; + for(std::size_t i = 0; i < DOCTEST_COUNTOF(signalDefs); ++i) { + sigaction(signalDefs[i].id, &sa, &oldSigActions[i]); + } + } + + ~FatalConditionHandler() { reset(); } + static void reset() { + if(isSet) { + // Set signals back to previous values -- hopefully nobody overwrote them in the meantime + for(std::size_t i = 0; i < DOCTEST_COUNTOF(signalDefs); ++i) { + sigaction(signalDefs[i].id, &oldSigActions[i], nullptr); + } + // Return the old stack + sigaltstack(&oldSigStack, nullptr); + isSet = false; + } + } + }; + + bool FatalConditionHandler::isSet = false; + struct sigaction FatalConditionHandler::oldSigActions[DOCTEST_COUNTOF(signalDefs)] = {}; + stack_t FatalConditionHandler::oldSigStack = {}; + char FatalConditionHandler::altStackMem[] = {}; + +#endif // DOCTEST_PLATFORM_WINDOWS +#endif // DOCTEST_CONFIG_POSIX_SIGNALS || DOCTEST_CONFIG_WINDOWS_SEH + +} // namespace + +namespace { + using namespace detail; + +#ifdef DOCTEST_PLATFORM_WINDOWS +#define DOCTEST_OUTPUT_DEBUG_STRING(text) ::OutputDebugStringA(text) +#else + // TODO: integration with XCode and other IDEs +#define DOCTEST_OUTPUT_DEBUG_STRING(text) // NOLINT(clang-diagnostic-unused-macros) +#endif // Platform + + void addAssert(assertType::Enum at) { + if((at & assertType::is_warn) == 0) //!OCLINT bitwise operator in conditional + g_cs->numAssertsCurrentTest_atomic++; + } + + void addFailedAssert(assertType::Enum at) { + if((at & assertType::is_warn) == 0) //!OCLINT bitwise operator in conditional + g_cs->numAssertsFailedCurrentTest_atomic++; + } + +#if defined(DOCTEST_CONFIG_POSIX_SIGNALS) || defined(DOCTEST_CONFIG_WINDOWS_SEH) + void reportFatal(const std::string& message) { + g_cs->failure_flags |= TestCaseFailureReason::Crash; + + DOCTEST_ITERATE_THROUGH_REPORTERS(test_case_exception, {message.c_str(), true}); + + while(g_cs->subcasesStack.size()) { + g_cs->subcasesStack.pop_back(); + DOCTEST_ITERATE_THROUGH_REPORTERS(subcase_end, DOCTEST_EMPTY); + } + + g_cs->finalizeTestCaseData(); + + DOCTEST_ITERATE_THROUGH_REPORTERS(test_case_end, *g_cs); + + DOCTEST_ITERATE_THROUGH_REPORTERS(test_run_end, *g_cs); + } +#endif // DOCTEST_CONFIG_POSIX_SIGNALS || DOCTEST_CONFIG_WINDOWS_SEH +} // namespace +namespace detail { + + ResultBuilder::ResultBuilder(assertType::Enum at, const char* file, int line, const char* expr, + const char* exception_type, const char* exception_string) { + m_test_case = g_cs->currentTest; + m_at = at; + m_file = file; + m_line = line; + m_expr = expr; + m_failed = true; + m_threw = false; + m_threw_as = false; + m_exception_type = exception_type; + m_exception_string = exception_string; +#if DOCTEST_MSVC + if(m_expr[0] == ' ') // this happens when variadic macros are disabled under MSVC + ++m_expr; +#endif // MSVC + } + + void ResultBuilder::setResult(const Result& res) { + m_decomp = res.m_decomp; + m_failed = !res.m_passed; + } + + void ResultBuilder::translateException() { + m_threw = true; + m_exception = translateActiveException(); + } + + bool ResultBuilder::log() { + if(m_at & assertType::is_throws) { //!OCLINT bitwise operator in conditional + m_failed = !m_threw; + } else if((m_at & assertType::is_throws_as) && (m_at & assertType::is_throws_with)) { //!OCLINT + m_failed = !m_threw_as || (m_exception != m_exception_string); + } else if(m_at & assertType::is_throws_as) { //!OCLINT bitwise operator in conditional + m_failed = !m_threw_as; + } else if(m_at & assertType::is_throws_with) { //!OCLINT bitwise operator in conditional + m_failed = m_exception != m_exception_string; + } else if(m_at & assertType::is_nothrow) { //!OCLINT bitwise operator in conditional + m_failed = m_threw; + } + + if(m_exception.size()) + m_exception = String("\"") + m_exception + "\""; + + if(is_running_in_test) { + addAssert(m_at); + DOCTEST_ITERATE_THROUGH_REPORTERS(log_assert, *this); + + if(m_failed) + addFailedAssert(m_at); + } else if(m_failed) { + failed_out_of_a_testing_context(*this); + } + + return m_failed && isDebuggerActive() && + !getContextOptions()->no_breaks; // break into debugger + } + + void ResultBuilder::react() const { + if(m_failed && checkIfShouldThrow(m_at)) + throwException(); + } + + void failed_out_of_a_testing_context(const AssertData& ad) { + if(g_cs->ah) + g_cs->ah(ad); + else + std::abort(); + } + + void decomp_assert(assertType::Enum at, const char* file, int line, const char* expr, + Result result) { + bool failed = !result.m_passed; + + // ################################################################################### + // IF THE DEBUGGER BREAKS HERE - GO 1 LEVEL UP IN THE CALLSTACK FOR THE FAILING ASSERT + // THIS IS THE EFFECT OF HAVING 'DOCTEST_CONFIG_SUPER_FAST_ASSERTS' DEFINED + // ################################################################################### + DOCTEST_ASSERT_OUT_OF_TESTS(result.m_decomp); + DOCTEST_ASSERT_IN_TESTS(result.m_decomp); + } + + MessageBuilder::MessageBuilder(const char* file, int line, assertType::Enum severity) { + m_stream = getTlsOss(); + m_file = file; + m_line = line; + m_severity = severity; + } + + IExceptionTranslator::IExceptionTranslator() = default; + IExceptionTranslator::~IExceptionTranslator() = default; + + bool MessageBuilder::log() { + m_string = getTlsOssResult(); + DOCTEST_ITERATE_THROUGH_REPORTERS(log_message, *this); + + const bool isWarn = m_severity & assertType::is_warn; + + // warn is just a message in this context so we don't treat it as an assert + if(!isWarn) { + addAssert(m_severity); + addFailedAssert(m_severity); + } + + return isDebuggerActive() && !getContextOptions()->no_breaks && !isWarn; // break + } + + void MessageBuilder::react() { + if(m_severity & assertType::is_require) //!OCLINT bitwise operator in conditional + throwException(); + } + + MessageBuilder::~MessageBuilder() = default; +} // namespace detail +namespace { + using namespace detail; + + template + DOCTEST_NORETURN void throw_exception(Ex const& e) { +#ifndef DOCTEST_CONFIG_NO_EXCEPTIONS + throw e; +#else // DOCTEST_CONFIG_NO_EXCEPTIONS + std::cerr << "doctest will terminate because it needed to throw an exception.\n" + << "The message was: " << e.what() << '\n'; + std::terminate(); +#endif // DOCTEST_CONFIG_NO_EXCEPTIONS + } + +#ifndef DOCTEST_INTERNAL_ERROR +#define DOCTEST_INTERNAL_ERROR(msg) \ + throw_exception(std::logic_error( \ + __FILE__ ":" DOCTEST_TOSTR(__LINE__) ": Internal doctest error: " msg)) +#endif // DOCTEST_INTERNAL_ERROR + + // clang-format off + +// ================================================================================================= +// The following code has been taken verbatim from Catch2/include/internal/catch_xmlwriter.h/cpp +// This is done so cherry-picking bug fixes is trivial - even the style/formatting is untouched. +// ================================================================================================= + + class XmlEncode { + public: + enum ForWhat { ForTextNodes, ForAttributes }; + + XmlEncode( std::string const& str, ForWhat forWhat = ForTextNodes ); + + void encodeTo( std::ostream& os ) const; + + friend std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode ); + + private: + std::string m_str; + ForWhat m_forWhat; + }; + + class XmlWriter { + public: + + class ScopedElement { + public: + ScopedElement( XmlWriter* writer ); + + ScopedElement( ScopedElement&& other ) DOCTEST_NOEXCEPT; + ScopedElement& operator=( ScopedElement&& other ) DOCTEST_NOEXCEPT; + + ~ScopedElement(); + + ScopedElement& writeText( std::string const& text, bool indent = true ); + + template + ScopedElement& writeAttribute( std::string const& name, T const& attribute ) { + m_writer->writeAttribute( name, attribute ); + return *this; + } + + private: + mutable XmlWriter* m_writer = nullptr; + }; + + XmlWriter( std::ostream& os = std::cout ); + ~XmlWriter(); + + XmlWriter( XmlWriter const& ) = delete; + XmlWriter& operator=( XmlWriter const& ) = delete; + + XmlWriter& startElement( std::string const& name ); + + ScopedElement scopedElement( std::string const& name ); + + XmlWriter& endElement(); + + XmlWriter& writeAttribute( std::string const& name, std::string const& attribute ); + + XmlWriter& writeAttribute( std::string const& name, const char* attribute ); + + XmlWriter& writeAttribute( std::string const& name, bool attribute ); + + template + XmlWriter& writeAttribute( std::string const& name, T const& attribute ) { + std::stringstream rss; + rss << attribute; + return writeAttribute( name, rss.str() ); + } + + XmlWriter& writeText( std::string const& text, bool indent = true ); + + //XmlWriter& writeComment( std::string const& text ); + + //void writeStylesheetRef( std::string const& url ); + + //XmlWriter& writeBlankLine(); + + void ensureTagClosed(); + + private: + + void writeDeclaration(); + + void newlineIfNecessary(); + + bool m_tagIsOpen = false; + bool m_needsNewline = false; + std::vector m_tags; + std::string m_indent; + std::ostream& m_os; + }; + +// ================================================================================================= +// The following code has been taken verbatim from Catch2/include/internal/catch_xmlwriter.h/cpp +// This is done so cherry-picking bug fixes is trivial - even the style/formatting is untouched. +// ================================================================================================= + +using uchar = unsigned char; + +namespace { + + size_t trailingBytes(unsigned char c) { + if ((c & 0xE0) == 0xC0) { + return 2; + } + if ((c & 0xF0) == 0xE0) { + return 3; + } + if ((c & 0xF8) == 0xF0) { + return 4; + } + DOCTEST_INTERNAL_ERROR("Invalid multibyte utf-8 start byte encountered"); + } + + uint32_t headerValue(unsigned char c) { + if ((c & 0xE0) == 0xC0) { + return c & 0x1F; + } + if ((c & 0xF0) == 0xE0) { + return c & 0x0F; + } + if ((c & 0xF8) == 0xF0) { + return c & 0x07; + } + DOCTEST_INTERNAL_ERROR("Invalid multibyte utf-8 start byte encountered"); + } + + void hexEscapeChar(std::ostream& os, unsigned char c) { + std::ios_base::fmtflags f(os.flags()); + os << "\\x" + << std::uppercase << std::hex << std::setfill('0') << std::setw(2) + << static_cast(c); + os.flags(f); + } + +} // anonymous namespace + + XmlEncode::XmlEncode( std::string const& str, ForWhat forWhat ) + : m_str( str ), + m_forWhat( forWhat ) + {} + + void XmlEncode::encodeTo( std::ostream& os ) const { + // Apostrophe escaping not necessary if we always use " to write attributes + // (see: https://www.w3.org/TR/xml/#syntax) + + for( std::size_t idx = 0; idx < m_str.size(); ++ idx ) { + uchar c = m_str[idx]; + switch (c) { + case '<': os << "<"; break; + case '&': os << "&"; break; + + case '>': + // See: https://www.w3.org/TR/xml/#syntax + if (idx > 2 && m_str[idx - 1] == ']' && m_str[idx - 2] == ']') + os << ">"; + else + os << c; + break; + + case '\"': + if (m_forWhat == ForAttributes) + os << """; + else + os << c; + break; + + default: + // Check for control characters and invalid utf-8 + + // Escape control characters in standard ascii + // see https://stackoverflow.com/questions/404107/why-are-control-characters-illegal-in-xml-1-0 + if (c < 0x09 || (c > 0x0D && c < 0x20) || c == 0x7F) { + hexEscapeChar(os, c); + break; + } + + // Plain ASCII: Write it to stream + if (c < 0x7F) { + os << c; + break; + } + + // UTF-8 territory + // Check if the encoding is valid and if it is not, hex escape bytes. + // Important: We do not check the exact decoded values for validity, only the encoding format + // First check that this bytes is a valid lead byte: + // This means that it is not encoded as 1111 1XXX + // Or as 10XX XXXX + if (c < 0xC0 || + c >= 0xF8) { + hexEscapeChar(os, c); + break; + } + + auto encBytes = trailingBytes(c); + // Are there enough bytes left to avoid accessing out-of-bounds memory? + if (idx + encBytes - 1 >= m_str.size()) { + hexEscapeChar(os, c); + break; + } + // The header is valid, check data + // The next encBytes bytes must together be a valid utf-8 + // This means: bitpattern 10XX XXXX and the extracted value is sane (ish) + bool valid = true; + uint32_t value = headerValue(c); + for (std::size_t n = 1; n < encBytes; ++n) { + uchar nc = m_str[idx + n]; + valid &= ((nc & 0xC0) == 0x80); + value = (value << 6) | (nc & 0x3F); + } + + if ( + // Wrong bit pattern of following bytes + (!valid) || + // Overlong encodings + (value < 0x80) || + ( value < 0x800 && encBytes > 2) || // removed "0x80 <= value &&" because redundant + (0x800 < value && value < 0x10000 && encBytes > 3) || + // Encoded value out of range + (value >= 0x110000) + ) { + hexEscapeChar(os, c); + break; + } + + // If we got here, this is in fact a valid(ish) utf-8 sequence + for (std::size_t n = 0; n < encBytes; ++n) { + os << m_str[idx + n]; + } + idx += encBytes - 1; + break; + } + } + } + + std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode ) { + xmlEncode.encodeTo( os ); + return os; + } + + XmlWriter::ScopedElement::ScopedElement( XmlWriter* writer ) + : m_writer( writer ) + {} + + XmlWriter::ScopedElement::ScopedElement( ScopedElement&& other ) DOCTEST_NOEXCEPT + : m_writer( other.m_writer ){ + other.m_writer = nullptr; + } + XmlWriter::ScopedElement& XmlWriter::ScopedElement::operator=( ScopedElement&& other ) DOCTEST_NOEXCEPT { + if ( m_writer ) { + m_writer->endElement(); + } + m_writer = other.m_writer; + other.m_writer = nullptr; + return *this; + } + + + XmlWriter::ScopedElement::~ScopedElement() { + if( m_writer ) + m_writer->endElement(); + } + + XmlWriter::ScopedElement& XmlWriter::ScopedElement::writeText( std::string const& text, bool indent ) { + m_writer->writeText( text, indent ); + return *this; + } + + XmlWriter::XmlWriter( std::ostream& os ) : m_os( os ) + { + writeDeclaration(); + } + + XmlWriter::~XmlWriter() { + while( !m_tags.empty() ) + endElement(); + } + + XmlWriter& XmlWriter::startElement( std::string const& name ) { + ensureTagClosed(); + newlineIfNecessary(); + m_os << m_indent << '<' << name; + m_tags.push_back( name ); + m_indent += " "; + m_tagIsOpen = true; + return *this; + } + + XmlWriter::ScopedElement XmlWriter::scopedElement( std::string const& name ) { + ScopedElement scoped( this ); + startElement( name ); + return scoped; + } + + XmlWriter& XmlWriter::endElement() { + newlineIfNecessary(); + m_indent = m_indent.substr( 0, m_indent.size()-2 ); + if( m_tagIsOpen ) { + m_os << "/>"; + m_tagIsOpen = false; + } + else { + m_os << m_indent << ""; + } + m_os << std::endl; + m_tags.pop_back(); + return *this; + } + + XmlWriter& XmlWriter::writeAttribute( std::string const& name, std::string const& attribute ) { + if( !name.empty() && !attribute.empty() ) + m_os << ' ' << name << "=\"" << XmlEncode( attribute, XmlEncode::ForAttributes ) << '"'; + return *this; + } + + XmlWriter& XmlWriter::writeAttribute( std::string const& name, const char* attribute ) { + if( !name.empty() && attribute && attribute[0] != '\0' ) + m_os << ' ' << name << "=\"" << XmlEncode( attribute, XmlEncode::ForAttributes ) << '"'; + return *this; + } + + XmlWriter& XmlWriter::writeAttribute( std::string const& name, bool attribute ) { + m_os << ' ' << name << "=\"" << ( attribute ? "true" : "false" ) << '"'; + return *this; + } + + XmlWriter& XmlWriter::writeText( std::string const& text, bool indent ) { + if( !text.empty() ){ + bool tagWasOpen = m_tagIsOpen; + ensureTagClosed(); + if( tagWasOpen && indent ) + m_os << m_indent; + m_os << XmlEncode( text ); + m_needsNewline = true; + } + return *this; + } + + //XmlWriter& XmlWriter::writeComment( std::string const& text ) { + // ensureTagClosed(); + // m_os << m_indent << ""; + // m_needsNewline = true; + // return *this; + //} + + //void XmlWriter::writeStylesheetRef( std::string const& url ) { + // m_os << "\n"; + //} + + //XmlWriter& XmlWriter::writeBlankLine() { + // ensureTagClosed(); + // m_os << '\n'; + // return *this; + //} + + void XmlWriter::ensureTagClosed() { + if( m_tagIsOpen ) { + m_os << ">" << std::endl; + m_tagIsOpen = false; + } + } + + void XmlWriter::writeDeclaration() { + m_os << "\n"; + } + + void XmlWriter::newlineIfNecessary() { + if( m_needsNewline ) { + m_os << std::endl; + m_needsNewline = false; + } + } + +// ================================================================================================= +// End of copy-pasted code from Catch +// ================================================================================================= + + // clang-format on + + struct XmlReporter : public IReporter + { + XmlWriter xml; + std::mutex mutex; + + // caching pointers/references to objects of these types - safe to do + const ContextOptions& opt; + const TestCaseData* tc = nullptr; + + XmlReporter(const ContextOptions& co) + : xml(*co.cout) + , opt(co) {} + + void log_contexts() { + int num_contexts = get_num_active_contexts(); + if(num_contexts) { + auto contexts = get_active_contexts(); + std::stringstream ss; + for(int i = 0; i < num_contexts; ++i) { + contexts[i]->stringify(&ss); + xml.scopedElement("Info").writeText(ss.str()); + ss.str(""); + } + } + } + + unsigned line(unsigned l) const { return opt.no_line_numbers ? 0 : l; } + + void test_case_start_impl(const TestCaseData& in) { + bool open_ts_tag = false; + if(tc != nullptr) { // we have already opened a test suite + if(std::strcmp(tc->m_test_suite, in.m_test_suite) != 0) { + xml.endElement(); + open_ts_tag = true; + } + } + else { + open_ts_tag = true; // first test case ==> first test suite + } + + if(open_ts_tag) { + xml.startElement("TestSuite"); + xml.writeAttribute("name", in.m_test_suite); + } + + tc = ∈ + xml.startElement("TestCase") + .writeAttribute("name", in.m_name) + .writeAttribute("filename", skipPathFromFilename(in.m_file.c_str())) + .writeAttribute("line", line(in.m_line)) + .writeAttribute("description", in.m_description); + + if(Approx(in.m_timeout) != 0) + xml.writeAttribute("timeout", in.m_timeout); + if(in.m_may_fail) + xml.writeAttribute("may_fail", true); + if(in.m_should_fail) + xml.writeAttribute("should_fail", true); + } + + // ========================================================================================= + // WHAT FOLLOWS ARE OVERRIDES OF THE VIRTUAL METHODS OF THE REPORTER INTERFACE + // ========================================================================================= + + void report_query(const QueryData& in) override { + test_run_start(); + if(opt.list_reporters) { + for(auto& curr : getListeners()) + xml.scopedElement("Listener") + .writeAttribute("priority", curr.first.first) + .writeAttribute("name", curr.first.second); + for(auto& curr : getReporters()) + xml.scopedElement("Reporter") + .writeAttribute("priority", curr.first.first) + .writeAttribute("name", curr.first.second); + } else if(opt.count || opt.list_test_cases) { + for(unsigned i = 0; i < in.num_data; ++i) { + xml.scopedElement("TestCase").writeAttribute("name", in.data[i]->m_name) + .writeAttribute("testsuite", in.data[i]->m_test_suite) + .writeAttribute("filename", skipPathFromFilename(in.data[i]->m_file.c_str())) + .writeAttribute("line", line(in.data[i]->m_line)); + } + xml.scopedElement("OverallResultsTestCases") + .writeAttribute("unskipped", in.run_stats->numTestCasesPassingFilters); + } else if(opt.list_test_suites) { + for(unsigned i = 0; i < in.num_data; ++i) + xml.scopedElement("TestSuite").writeAttribute("name", in.data[i]->m_test_suite); + xml.scopedElement("OverallResultsTestCases") + .writeAttribute("unskipped", in.run_stats->numTestCasesPassingFilters); + xml.scopedElement("OverallResultsTestSuites") + .writeAttribute("unskipped", in.run_stats->numTestSuitesPassingFilters); + } + xml.endElement(); + } + + void test_run_start() override { + // remove .exe extension - mainly to have the same output on UNIX and Windows + std::string binary_name = skipPathFromFilename(opt.binary_name.c_str()); +#ifdef DOCTEST_PLATFORM_WINDOWS + if(binary_name.rfind(".exe") != std::string::npos) + binary_name = binary_name.substr(0, binary_name.length() - 4); +#endif // DOCTEST_PLATFORM_WINDOWS + + xml.startElement("doctest").writeAttribute("binary", binary_name); + if(opt.no_version == false) + xml.writeAttribute("version", DOCTEST_VERSION_STR); + + // only the consequential ones (TODO: filters) + xml.scopedElement("Options") + .writeAttribute("order_by", opt.order_by.c_str()) + .writeAttribute("rand_seed", opt.rand_seed) + .writeAttribute("first", opt.first) + .writeAttribute("last", opt.last) + .writeAttribute("abort_after", opt.abort_after) + .writeAttribute("subcase_filter_levels", opt.subcase_filter_levels) + .writeAttribute("case_sensitive", opt.case_sensitive) + .writeAttribute("no_throw", opt.no_throw) + .writeAttribute("no_skip", opt.no_skip); + } + + void test_run_end(const TestRunStats& p) override { + if(tc) // the TestSuite tag - only if there has been at least 1 test case + xml.endElement(); + + xml.scopedElement("OverallResultsAsserts") + .writeAttribute("successes", p.numAsserts - p.numAssertsFailed) + .writeAttribute("failures", p.numAssertsFailed); + + xml.startElement("OverallResultsTestCases") + .writeAttribute("successes", + p.numTestCasesPassingFilters - p.numTestCasesFailed) + .writeAttribute("failures", p.numTestCasesFailed); + if(opt.no_skipped_summary == false) + xml.writeAttribute("skipped", p.numTestCases - p.numTestCasesPassingFilters); + xml.endElement(); + + xml.endElement(); + } + + void test_case_start(const TestCaseData& in) override { + test_case_start_impl(in); + xml.ensureTagClosed(); + } + + void test_case_reenter(const TestCaseData&) override {} + + void test_case_end(const CurrentTestCaseStats& st) override { + xml.startElement("OverallResultsAsserts") + .writeAttribute("successes", + st.numAssertsCurrentTest - st.numAssertsFailedCurrentTest) + .writeAttribute("failures", st.numAssertsFailedCurrentTest); + if(opt.duration) + xml.writeAttribute("duration", st.seconds); + if(tc->m_expected_failures) + xml.writeAttribute("expected_failures", tc->m_expected_failures); + xml.endElement(); + + xml.endElement(); + } + + void test_case_exception(const TestCaseException& e) override { + std::lock_guard lock(mutex); + + xml.scopedElement("Exception") + .writeAttribute("crash", e.is_crash) + .writeText(e.error_string.c_str()); + } + + void subcase_start(const SubcaseSignature& in) override { + std::lock_guard lock(mutex); + + xml.startElement("SubCase") + .writeAttribute("name", in.m_name) + .writeAttribute("filename", skipPathFromFilename(in.m_file)) + .writeAttribute("line", line(in.m_line)); + xml.ensureTagClosed(); + } + + void subcase_end() override { xml.endElement(); } + + void log_assert(const AssertData& rb) override { + if(!rb.m_failed && !opt.success) + return; + + std::lock_guard lock(mutex); + + xml.startElement("Expression") + .writeAttribute("success", !rb.m_failed) + .writeAttribute("type", assertString(rb.m_at)) + .writeAttribute("filename", skipPathFromFilename(rb.m_file)) + .writeAttribute("line", line(rb.m_line)); + + xml.scopedElement("Original").writeText(rb.m_expr); + + if(rb.m_threw) + xml.scopedElement("Exception").writeText(rb.m_exception.c_str()); + + if(rb.m_at & assertType::is_throws_as) + xml.scopedElement("ExpectedException").writeText(rb.m_exception_type); + if(rb.m_at & assertType::is_throws_with) + xml.scopedElement("ExpectedExceptionString").writeText(rb.m_exception_string); + if((rb.m_at & assertType::is_normal) && !rb.m_threw) + xml.scopedElement("Expanded").writeText(rb.m_decomp.c_str()); + + log_contexts(); + + xml.endElement(); + } + + void log_message(const MessageData& mb) override { + std::lock_guard lock(mutex); + + xml.startElement("Message") + .writeAttribute("type", failureString(mb.m_severity)) + .writeAttribute("filename", skipPathFromFilename(mb.m_file)) + .writeAttribute("line", line(mb.m_line)); + + xml.scopedElement("Text").writeText(mb.m_string.c_str()); + + log_contexts(); + + xml.endElement(); + } + + void test_case_skipped(const TestCaseData& in) override { + if(opt.no_skipped_summary == false) { + test_case_start_impl(in); + xml.writeAttribute("skipped", "true"); + xml.endElement(); + } + } + }; + + DOCTEST_REGISTER_REPORTER("xml", 0, XmlReporter); + + struct Whitespace + { + int nrSpaces; + explicit Whitespace(int nr) + : nrSpaces(nr) {} + }; + + std::ostream& operator<<(std::ostream& out, const Whitespace& ws) { + if(ws.nrSpaces != 0) + out << std::setw(ws.nrSpaces) << ' '; + return out; + } + + struct ConsoleReporter : public IReporter + { + std::ostream& s; + bool hasLoggedCurrentTestStart; + std::vector subcasesStack; + size_t currentSubcaseLevel; + std::mutex mutex; + + // caching pointers/references to objects of these types - safe to do + const ContextOptions& opt; + const TestCaseData* tc; + + ConsoleReporter(const ContextOptions& co) + : s(*co.cout) + , opt(co) {} + + ConsoleReporter(const ContextOptions& co, std::ostream& ostr) + : s(ostr) + , opt(co) {} + + // ========================================================================================= + // WHAT FOLLOWS ARE HELPERS USED BY THE OVERRIDES OF THE VIRTUAL METHODS OF THE INTERFACE + // ========================================================================================= + + void separator_to_stream() { + s << Color::Yellow + << "===============================================================================" + "\n"; + } + + const char* getSuccessOrFailString(bool success, assertType::Enum at, + const char* success_str) { + if(success) + return success_str; + return failureString(at); + } + + Color::Enum getSuccessOrFailColor(bool success, assertType::Enum at) { + return success ? Color::BrightGreen : + (at & assertType::is_warn) ? Color::Yellow : Color::Red; + } + + void successOrFailColoredStringToStream(bool success, assertType::Enum at, + const char* success_str = "SUCCESS") { + s << getSuccessOrFailColor(success, at) + << getSuccessOrFailString(success, at, success_str) << ": "; + } + + void log_contexts() { + int num_contexts = get_num_active_contexts(); + if(num_contexts) { + auto contexts = get_active_contexts(); + + s << Color::None << " logged: "; + for(int i = 0; i < num_contexts; ++i) { + s << (i == 0 ? "" : " "); + contexts[i]->stringify(&s); + s << "\n"; + } + } + + s << "\n"; + } + + virtual void file_line_to_stream(const char* file, int line, + const char* tail = "") { + s << Color::LightGrey << skipPathFromFilename(file) << (opt.gnu_file_line ? ":" : "(") + << (opt.no_line_numbers ? 0 : line) // 0 or the real num depending on the option + << (opt.gnu_file_line ? ":" : "):") << tail; + } + + void logTestStart() { + if(hasLoggedCurrentTestStart) + return; + + separator_to_stream(); + file_line_to_stream(tc->m_file.c_str(), tc->m_line, "\n"); + if(tc->m_description) + s << Color::Yellow << "DESCRIPTION: " << Color::None << tc->m_description << "\n"; + if(tc->m_test_suite && tc->m_test_suite[0] != '\0') + s << Color::Yellow << "TEST SUITE: " << Color::None << tc->m_test_suite << "\n"; + if(strncmp(tc->m_name, " Scenario:", 11) != 0) + s << Color::Yellow << "TEST CASE: "; + s << Color::None << tc->m_name << "\n"; + + for(size_t i = 0; i < currentSubcaseLevel; ++i) { + if(subcasesStack[i].m_name[0] != '\0') + s << " " << subcasesStack[i].m_name << "\n"; + } + + if(currentSubcaseLevel != subcasesStack.size()) { + s << Color::Yellow << "\nDEEPEST SUBCASE STACK REACHED (DIFFERENT FROM THE CURRENT ONE):\n" << Color::None; + for(size_t i = 0; i < subcasesStack.size(); ++i) { + if(subcasesStack[i].m_name[0] != '\0') + s << " " << subcasesStack[i].m_name << "\n"; + } + } + + s << "\n"; + + hasLoggedCurrentTestStart = true; + } + + void printVersion() { + if(opt.no_version == false) + s << Color::Cyan << "[doctest] " << Color::None << "doctest version is \"" + << DOCTEST_VERSION_STR << "\"\n"; + } + + void printIntro() { + printVersion(); + s << Color::Cyan << "[doctest] " << Color::None + << "run with \"--" DOCTEST_OPTIONS_PREFIX_DISPLAY "help\" for options\n"; + } + + void printHelp() { + int sizePrefixDisplay = static_cast(strlen(DOCTEST_OPTIONS_PREFIX_DISPLAY)); + printVersion(); + // clang-format off + s << Color::Cyan << "[doctest]\n" << Color::None; + s << Color::Cyan << "[doctest] " << Color::None; + s << "boolean values: \"1/on/yes/true\" or \"0/off/no/false\"\n"; + s << Color::Cyan << "[doctest] " << Color::None; + s << "filter values: \"str1,str2,str3\" (comma separated strings)\n"; + s << Color::Cyan << "[doctest]\n" << Color::None; + s << Color::Cyan << "[doctest] " << Color::None; + s << "filters use wildcards for matching strings\n"; + s << Color::Cyan << "[doctest] " << Color::None; + s << "something passes a filter if any of the strings in a filter matches\n"; +#ifndef DOCTEST_CONFIG_NO_UNPREFIXED_OPTIONS + s << Color::Cyan << "[doctest]\n" << Color::None; + s << Color::Cyan << "[doctest] " << Color::None; + s << "ALL FLAGS, OPTIONS AND FILTERS ALSO AVAILABLE WITH A \"" DOCTEST_CONFIG_OPTIONS_PREFIX "\" PREFIX!!!\n"; +#endif + s << Color::Cyan << "[doctest]\n" << Color::None; + s << Color::Cyan << "[doctest] " << Color::None; + s << "Query flags - the program quits after them. Available:\n\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "?, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "help, -" DOCTEST_OPTIONS_PREFIX_DISPLAY "h " + << Whitespace(sizePrefixDisplay*0) << "prints this message\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "v, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "version " + << Whitespace(sizePrefixDisplay*1) << "prints the version\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "c, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "count " + << Whitespace(sizePrefixDisplay*1) << "prints the number of matching tests\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "ltc, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "list-test-cases " + << Whitespace(sizePrefixDisplay*1) << "lists all matching tests by name\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "lts, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "list-test-suites " + << Whitespace(sizePrefixDisplay*1) << "lists all matching test suites\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "lr, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "list-reporters " + << Whitespace(sizePrefixDisplay*1) << "lists all registered reporters\n\n"; + // ================================================================================== << 79 + s << Color::Cyan << "[doctest] " << Color::None; + s << "The available / options/filters are:\n\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "tc, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "test-case= " + << Whitespace(sizePrefixDisplay*1) << "filters tests by their name\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "tce, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "test-case-exclude= " + << Whitespace(sizePrefixDisplay*1) << "filters OUT tests by their name\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "sf, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "source-file= " + << Whitespace(sizePrefixDisplay*1) << "filters tests by their file\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "sfe, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "source-file-exclude= " + << Whitespace(sizePrefixDisplay*1) << "filters OUT tests by their file\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "ts, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "test-suite= " + << Whitespace(sizePrefixDisplay*1) << "filters tests by their test suite\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "tse, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "test-suite-exclude= " + << Whitespace(sizePrefixDisplay*1) << "filters OUT tests by their test suite\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "sc, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "subcase= " + << Whitespace(sizePrefixDisplay*1) << "filters subcases by their name\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "sce, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "subcase-exclude= " + << Whitespace(sizePrefixDisplay*1) << "filters OUT subcases by their name\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "r, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "reporters= " + << Whitespace(sizePrefixDisplay*1) << "reporters to use (console is default)\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "o, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "out= " + << Whitespace(sizePrefixDisplay*1) << "output filename\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "ob, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "order-by= " + << Whitespace(sizePrefixDisplay*1) << "how the tests should be ordered\n"; + s << Whitespace(sizePrefixDisplay*3) << " - by [file/suite/name/rand]\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "rs, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "rand-seed= " + << Whitespace(sizePrefixDisplay*1) << "seed for random ordering\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "f, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "first= " + << Whitespace(sizePrefixDisplay*1) << "the first test passing the filters to\n"; + s << Whitespace(sizePrefixDisplay*3) << " execute - for range-based execution\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "l, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "last= " + << Whitespace(sizePrefixDisplay*1) << "the last test passing the filters to\n"; + s << Whitespace(sizePrefixDisplay*3) << " execute - for range-based execution\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "aa, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "abort-after= " + << Whitespace(sizePrefixDisplay*1) << "stop after failed assertions\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "scfl,--" DOCTEST_OPTIONS_PREFIX_DISPLAY "subcase-filter-levels= " + << Whitespace(sizePrefixDisplay*1) << "apply filters for the first levels\n"; + s << Color::Cyan << "\n[doctest] " << Color::None; + s << "Bool options - can be used like flags and true is assumed. Available:\n\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "s, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "success= " + << Whitespace(sizePrefixDisplay*1) << "include successful assertions in output\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "cs, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "case-sensitive= " + << Whitespace(sizePrefixDisplay*1) << "filters being treated as case sensitive\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "e, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "exit= " + << Whitespace(sizePrefixDisplay*1) << "exits after the tests finish\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "d, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "duration= " + << Whitespace(sizePrefixDisplay*1) << "prints the time duration of each test\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "nt, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "no-throw= " + << Whitespace(sizePrefixDisplay*1) << "skips exceptions-related assert checks\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "ne, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "no-exitcode= " + << Whitespace(sizePrefixDisplay*1) << "returns (or exits) always with success\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "nr, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "no-run= " + << Whitespace(sizePrefixDisplay*1) << "skips all runtime doctest operations\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "nv, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "no-version= " + << Whitespace(sizePrefixDisplay*1) << "omit the framework version in the output\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "nc, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "no-colors= " + << Whitespace(sizePrefixDisplay*1) << "disables colors in output\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "fc, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "force-colors= " + << Whitespace(sizePrefixDisplay*1) << "use colors even when not in a tty\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "nb, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "no-breaks= " + << Whitespace(sizePrefixDisplay*1) << "disables breakpoints in debuggers\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "ns, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "no-skip= " + << Whitespace(sizePrefixDisplay*1) << "don't skip test cases marked as skip\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "gfl, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "gnu-file-line= " + << Whitespace(sizePrefixDisplay*1) << ":n: vs (n): for line numbers in output\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "npf, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "no-path-filenames= " + << Whitespace(sizePrefixDisplay*1) << "only filenames and no paths in output\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "nln, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "no-line-numbers= " + << Whitespace(sizePrefixDisplay*1) << "0 instead of real line numbers in output\n"; + // ================================================================================== << 79 + // clang-format on + + s << Color::Cyan << "\n[doctest] " << Color::None; + s << "for more information visit the project documentation\n\n"; + } + + void printRegisteredReporters() { + printVersion(); + auto printReporters = [this] (const reporterMap& reporters, const char* type) { + if(reporters.size()) { + s << Color::Cyan << "[doctest] " << Color::None << "listing all registered " << type << "\n"; + for(auto& curr : reporters) + s << "priority: " << std::setw(5) << curr.first.first + << " name: " << curr.first.second << "\n"; + } + }; + printReporters(getListeners(), "listeners"); + printReporters(getReporters(), "reporters"); + } + + void list_query_results() { + separator_to_stream(); + if(opt.count || opt.list_test_cases) { + s << Color::Cyan << "[doctest] " << Color::None + << "unskipped test cases passing the current filters: " + << g_cs->numTestCasesPassingFilters << "\n"; + } else if(opt.list_test_suites) { + s << Color::Cyan << "[doctest] " << Color::None + << "unskipped test cases passing the current filters: " + << g_cs->numTestCasesPassingFilters << "\n"; + s << Color::Cyan << "[doctest] " << Color::None + << "test suites with unskipped test cases passing the current filters: " + << g_cs->numTestSuitesPassingFilters << "\n"; + } + } + + // ========================================================================================= + // WHAT FOLLOWS ARE OVERRIDES OF THE VIRTUAL METHODS OF THE REPORTER INTERFACE + // ========================================================================================= + + void report_query(const QueryData& in) override { + if(opt.version) { + printVersion(); + } else if(opt.help) { + printHelp(); + } else if(opt.list_reporters) { + printRegisteredReporters(); + } else if(opt.count || opt.list_test_cases) { + if(opt.list_test_cases) { + s << Color::Cyan << "[doctest] " << Color::None + << "listing all test case names\n"; + separator_to_stream(); + } + + for(unsigned i = 0; i < in.num_data; ++i) + s << Color::None << in.data[i]->m_name << "\n"; + + separator_to_stream(); + + s << Color::Cyan << "[doctest] " << Color::None + << "unskipped test cases passing the current filters: " + << g_cs->numTestCasesPassingFilters << "\n"; + + } else if(opt.list_test_suites) { + s << Color::Cyan << "[doctest] " << Color::None << "listing all test suites\n"; + separator_to_stream(); + + for(unsigned i = 0; i < in.num_data; ++i) + s << Color::None << in.data[i]->m_test_suite << "\n"; + + separator_to_stream(); + + s << Color::Cyan << "[doctest] " << Color::None + << "unskipped test cases passing the current filters: " + << g_cs->numTestCasesPassingFilters << "\n"; + s << Color::Cyan << "[doctest] " << Color::None + << "test suites with unskipped test cases passing the current filters: " + << g_cs->numTestSuitesPassingFilters << "\n"; + } + } + + void test_run_start() override { printIntro(); } + + void test_run_end(const TestRunStats& p) override { + separator_to_stream(); + s << std::dec; + + const bool anythingFailed = p.numTestCasesFailed > 0 || p.numAssertsFailed > 0; + s << Color::Cyan << "[doctest] " << Color::None << "test cases: " << std::setw(6) + << p.numTestCasesPassingFilters << " | " + << ((p.numTestCasesPassingFilters == 0 || anythingFailed) ? Color::None : + Color::Green) + << std::setw(6) << p.numTestCasesPassingFilters - p.numTestCasesFailed << " passed" + << Color::None << " | " << (p.numTestCasesFailed > 0 ? Color::Red : Color::None) + << std::setw(6) << p.numTestCasesFailed << " failed" << Color::None << " | "; + if(opt.no_skipped_summary == false) { + const int numSkipped = p.numTestCases - p.numTestCasesPassingFilters; + s << (numSkipped == 0 ? Color::None : Color::Yellow) << std::setw(6) << numSkipped + << " skipped" << Color::None; + } + s << "\n"; + s << Color::Cyan << "[doctest] " << Color::None << "assertions: " << std::setw(6) + << p.numAsserts << " | " + << ((p.numAsserts == 0 || anythingFailed) ? Color::None : Color::Green) + << std::setw(6) << (p.numAsserts - p.numAssertsFailed) << " passed" << Color::None + << " | " << (p.numAssertsFailed > 0 ? Color::Red : Color::None) << std::setw(6) + << p.numAssertsFailed << " failed" << Color::None << " |\n"; + s << Color::Cyan << "[doctest] " << Color::None + << "Status: " << (p.numTestCasesFailed > 0 ? Color::Red : Color::Green) + << ((p.numTestCasesFailed > 0) ? "FAILURE!" : "SUCCESS!") << Color::None << std::endl; + } + + void test_case_start(const TestCaseData& in) override { + hasLoggedCurrentTestStart = false; + tc = ∈ + subcasesStack.clear(); + currentSubcaseLevel = 0; + } + + void test_case_reenter(const TestCaseData&) override { + subcasesStack.clear(); + } + + void test_case_end(const CurrentTestCaseStats& st) override { + // log the preamble of the test case only if there is something + // else to print - something other than that an assert has failed + if(opt.duration || + (st.failure_flags && st.failure_flags != TestCaseFailureReason::AssertFailure)) + logTestStart(); + + if(opt.duration) + s << Color::None << std::setprecision(6) << std::fixed << st.seconds + << " s: " << tc->m_name << "\n"; + + if(st.failure_flags & TestCaseFailureReason::Timeout) + s << Color::Red << "Test case exceeded time limit of " << std::setprecision(6) + << std::fixed << tc->m_timeout << "!\n"; + + if(st.failure_flags & TestCaseFailureReason::ShouldHaveFailedButDidnt) { + s << Color::Red << "Should have failed but didn't! Marking it as failed!\n"; + } else if(st.failure_flags & TestCaseFailureReason::ShouldHaveFailedAndDid) { + s << Color::Yellow << "Failed as expected so marking it as not failed\n"; + } else if(st.failure_flags & TestCaseFailureReason::CouldHaveFailedAndDid) { + s << Color::Yellow << "Allowed to fail so marking it as not failed\n"; + } else if(st.failure_flags & TestCaseFailureReason::DidntFailExactlyNumTimes) { + s << Color::Red << "Didn't fail exactly " << tc->m_expected_failures + << " times so marking it as failed!\n"; + } else if(st.failure_flags & TestCaseFailureReason::FailedExactlyNumTimes) { + s << Color::Yellow << "Failed exactly " << tc->m_expected_failures + << " times as expected so marking it as not failed!\n"; + } + if(st.failure_flags & TestCaseFailureReason::TooManyFailedAsserts) { + s << Color::Red << "Aborting - too many failed asserts!\n"; + } + s << Color::None; // lgtm [cpp/useless-expression] + } + + void test_case_exception(const TestCaseException& e) override { + logTestStart(); + + file_line_to_stream(tc->m_file.c_str(), tc->m_line, " "); + successOrFailColoredStringToStream(false, e.is_crash ? assertType::is_require : + assertType::is_check); + s << Color::Red << (e.is_crash ? "test case CRASHED: " : "test case THREW exception: ") + << Color::Cyan << e.error_string << "\n"; + + int num_stringified_contexts = get_num_stringified_contexts(); + if(num_stringified_contexts) { + auto stringified_contexts = get_stringified_contexts(); + s << Color::None << " logged: "; + for(int i = num_stringified_contexts; i > 0; --i) { + s << (i == num_stringified_contexts ? "" : " ") + << stringified_contexts[i - 1] << "\n"; + } + } + s << "\n" << Color::None; + } + + void subcase_start(const SubcaseSignature& subc) override { + std::lock_guard lock(mutex); + subcasesStack.push_back(subc); + ++currentSubcaseLevel; + hasLoggedCurrentTestStart = false; + } + + void subcase_end() override { + std::lock_guard lock(mutex); + --currentSubcaseLevel; + hasLoggedCurrentTestStart = false; + } + + void log_assert(const AssertData& rb) override { + if(!rb.m_failed && !opt.success) + return; + + std::lock_guard lock(mutex); + + logTestStart(); + + file_line_to_stream(rb.m_file, rb.m_line, " "); + successOrFailColoredStringToStream(!rb.m_failed, rb.m_at); + if((rb.m_at & (assertType::is_throws_as | assertType::is_throws_with)) == + 0) //!OCLINT bitwise operator in conditional + s << Color::Cyan << assertString(rb.m_at) << "( " << rb.m_expr << " ) " + << Color::None; + + if(rb.m_at & assertType::is_throws) { //!OCLINT bitwise operator in conditional + s << (rb.m_threw ? "threw as expected!" : "did NOT throw at all!") << "\n"; + } else if((rb.m_at & assertType::is_throws_as) && + (rb.m_at & assertType::is_throws_with)) { //!OCLINT + s << Color::Cyan << assertString(rb.m_at) << "( " << rb.m_expr << ", \"" + << rb.m_exception_string << "\", " << rb.m_exception_type << " ) " << Color::None; + if(rb.m_threw) { + if(!rb.m_failed) { + s << "threw as expected!\n"; + } else { + s << "threw a DIFFERENT exception! (contents: " << rb.m_exception << ")\n"; + } + } else { + s << "did NOT throw at all!\n"; + } + } else if(rb.m_at & + assertType::is_throws_as) { //!OCLINT bitwise operator in conditional + s << Color::Cyan << assertString(rb.m_at) << "( " << rb.m_expr << ", " + << rb.m_exception_type << " ) " << Color::None + << (rb.m_threw ? (rb.m_threw_as ? "threw as expected!" : + "threw a DIFFERENT exception: ") : + "did NOT throw at all!") + << Color::Cyan << rb.m_exception << "\n"; + } else if(rb.m_at & + assertType::is_throws_with) { //!OCLINT bitwise operator in conditional + s << Color::Cyan << assertString(rb.m_at) << "( " << rb.m_expr << ", \"" + << rb.m_exception_string << "\" ) " << Color::None + << (rb.m_threw ? (!rb.m_failed ? "threw as expected!" : + "threw a DIFFERENT exception: ") : + "did NOT throw at all!") + << Color::Cyan << rb.m_exception << "\n"; + } else if(rb.m_at & assertType::is_nothrow) { //!OCLINT bitwise operator in conditional + s << (rb.m_threw ? "THREW exception: " : "didn't throw!") << Color::Cyan + << rb.m_exception << "\n"; + } else { + s << (rb.m_threw ? "THREW exception: " : + (!rb.m_failed ? "is correct!\n" : "is NOT correct!\n")); + if(rb.m_threw) + s << rb.m_exception << "\n"; + else + s << " values: " << assertString(rb.m_at) << "( " << rb.m_decomp << " )\n"; + } + + log_contexts(); + } + + void log_message(const MessageData& mb) override { + std::lock_guard lock(mutex); + + logTestStart(); + + file_line_to_stream(mb.m_file, mb.m_line, " "); + s << getSuccessOrFailColor(false, mb.m_severity) + << getSuccessOrFailString(mb.m_severity & assertType::is_warn, mb.m_severity, + "MESSAGE") << ": "; + s << Color::None << mb.m_string << "\n"; + log_contexts(); + } + + void test_case_skipped(const TestCaseData&) override {} + }; + + DOCTEST_REGISTER_REPORTER("console", 0, ConsoleReporter); + +#ifdef DOCTEST_PLATFORM_WINDOWS + struct DebugOutputWindowReporter : public ConsoleReporter + { + DOCTEST_THREAD_LOCAL static std::ostringstream oss; + + DebugOutputWindowReporter(const ContextOptions& co) + : ConsoleReporter(co, oss) {} + +#define DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(func, type, arg) \ + void func(type arg) override { \ + bool with_col = g_no_colors; \ + g_no_colors = false; \ + ConsoleReporter::func(arg); \ + DOCTEST_OUTPUT_DEBUG_STRING(oss.str().c_str()); \ + oss.str(""); \ + g_no_colors = with_col; \ + } + + DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(test_run_start, DOCTEST_EMPTY, DOCTEST_EMPTY) + DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(test_run_end, const TestRunStats&, in) + DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(test_case_start, const TestCaseData&, in) + DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(test_case_reenter, const TestCaseData&, in) + DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(test_case_end, const CurrentTestCaseStats&, in) + DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(test_case_exception, const TestCaseException&, in) + DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(subcase_start, const SubcaseSignature&, in) + DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(subcase_end, DOCTEST_EMPTY, DOCTEST_EMPTY) + DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(log_assert, const AssertData&, in) + DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(log_message, const MessageData&, in) + DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(test_case_skipped, const TestCaseData&, in) + }; + + DOCTEST_THREAD_LOCAL std::ostringstream DebugOutputWindowReporter::oss; +#endif // DOCTEST_PLATFORM_WINDOWS + + // the implementation of parseOption() + bool parseOptionImpl(int argc, const char* const* argv, const char* pattern, String* value) { + // going from the end to the beginning and stopping on the first occurrence from the end + for(int i = argc; i > 0; --i) { + auto index = i - 1; + auto temp = std::strstr(argv[index], pattern); + if(temp && (value || strlen(temp) == strlen(pattern))) { //!OCLINT prefer early exits and continue + // eliminate matches in which the chars before the option are not '-' + bool noBadCharsFound = true; + auto curr = argv[index]; + while(curr != temp) { + if(*curr++ != '-') { + noBadCharsFound = false; + break; + } + } + if(noBadCharsFound && argv[index][0] == '-') { + if(value) { + // parsing the value of an option + temp += strlen(pattern); + const unsigned len = strlen(temp); + if(len) { + *value = temp; + return true; + } + } else { + // just a flag - no value + return true; + } + } + } + } + return false; + } + + // parses an option and returns the string after the '=' character + bool parseOption(int argc, const char* const* argv, const char* pattern, String* value = nullptr, + const String& defaultVal = String()) { + if(value) + *value = defaultVal; +#ifndef DOCTEST_CONFIG_NO_UNPREFIXED_OPTIONS + // offset (normally 3 for "dt-") to skip prefix + if(parseOptionImpl(argc, argv, pattern + strlen(DOCTEST_CONFIG_OPTIONS_PREFIX), value)) + return true; +#endif // DOCTEST_CONFIG_NO_UNPREFIXED_OPTIONS + return parseOptionImpl(argc, argv, pattern, value); + } + + // locates a flag on the command line + bool parseFlag(int argc, const char* const* argv, const char* pattern) { + return parseOption(argc, argv, pattern); + } + + // parses a comma separated list of words after a pattern in one of the arguments in argv + bool parseCommaSepArgs(int argc, const char* const* argv, const char* pattern, + std::vector& res) { + String filtersString; + if(parseOption(argc, argv, pattern, &filtersString)) { + // tokenize with "," as a separator + // cppcheck-suppress strtokCalled + DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wdeprecated-declarations") + auto pch = std::strtok(filtersString.c_str(), ","); // modifies the string + while(pch != nullptr) { + if(strlen(pch)) + res.push_back(pch); + // uses the strtok() internal state to go to the next token + // cppcheck-suppress strtokCalled + pch = std::strtok(nullptr, ","); + } + DOCTEST_CLANG_SUPPRESS_WARNING_POP + return true; + } + return false; + } + + enum optionType + { + option_bool, + option_int + }; + + // parses an int/bool option from the command line + bool parseIntOption(int argc, const char* const* argv, const char* pattern, optionType type, + int& res) { + String parsedValue; + if(!parseOption(argc, argv, pattern, &parsedValue)) + return false; + + if(type == 0) { + // boolean + const char positive[][5] = {"1", "true", "on", "yes"}; // 5 - strlen("true") + 1 + const char negative[][6] = {"0", "false", "off", "no"}; // 6 - strlen("false") + 1 + + // if the value matches any of the positive/negative possibilities + for(unsigned i = 0; i < 4; i++) { + if(parsedValue.compare(positive[i], true) == 0) { + res = 1; //!OCLINT parameter reassignment + return true; + } + if(parsedValue.compare(negative[i], true) == 0) { + res = 0; //!OCLINT parameter reassignment + return true; + } + } + } else { + // integer + // TODO: change this to use std::stoi or something else! currently it uses undefined behavior - assumes '0' on failed parse... + int theInt = std::atoi(parsedValue.c_str()); // NOLINT + if(theInt != 0) { + res = theInt; //!OCLINT parameter reassignment + return true; + } + } + return false; + } +} // namespace + +Context::Context(int argc, const char* const* argv) + : p(new detail::ContextState) { + parseArgs(argc, argv, true); + if(argc) + p->binary_name = argv[0]; +} + +Context::~Context() { + if(g_cs == p) + g_cs = nullptr; + delete p; +} + +void Context::applyCommandLine(int argc, const char* const* argv) { + parseArgs(argc, argv); + if(argc) + p->binary_name = argv[0]; +} + +// parses args +void Context::parseArgs(int argc, const char* const* argv, bool withDefaults) { + using namespace detail; + + // clang-format off + parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "source-file=", p->filters[0]); + parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "sf=", p->filters[0]); + parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "source-file-exclude=",p->filters[1]); + parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "sfe=", p->filters[1]); + parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "test-suite=", p->filters[2]); + parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "ts=", p->filters[2]); + parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "test-suite-exclude=", p->filters[3]); + parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "tse=", p->filters[3]); + parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "test-case=", p->filters[4]); + parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "tc=", p->filters[4]); + parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "test-case-exclude=", p->filters[5]); + parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "tce=", p->filters[5]); + parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "subcase=", p->filters[6]); + parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "sc=", p->filters[6]); + parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "subcase-exclude=", p->filters[7]); + parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "sce=", p->filters[7]); + parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "reporters=", p->filters[8]); + parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "r=", p->filters[8]); + // clang-format on + + int intRes = 0; + String strRes; + +#define DOCTEST_PARSE_AS_BOOL_OR_FLAG(name, sname, var, default) \ + if(parseIntOption(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX name "=", option_bool, intRes) || \ + parseIntOption(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX sname "=", option_bool, intRes)) \ + p->var = !!intRes; \ + else if(parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX name) || \ + parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX sname)) \ + p->var = true; \ + else if(withDefaults) \ + p->var = default + +#define DOCTEST_PARSE_INT_OPTION(name, sname, var, default) \ + if(parseIntOption(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX name "=", option_int, intRes) || \ + parseIntOption(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX sname "=", option_int, intRes)) \ + p->var = intRes; \ + else if(withDefaults) \ + p->var = default + +#define DOCTEST_PARSE_STR_OPTION(name, sname, var, default) \ + if(parseOption(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX name "=", &strRes, default) || \ + parseOption(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX sname "=", &strRes, default) || \ + withDefaults) \ + p->var = strRes + + // clang-format off + DOCTEST_PARSE_STR_OPTION("out", "o", out, ""); + DOCTEST_PARSE_STR_OPTION("order-by", "ob", order_by, "file"); + DOCTEST_PARSE_INT_OPTION("rand-seed", "rs", rand_seed, 0); + + DOCTEST_PARSE_INT_OPTION("first", "f", first, 0); + DOCTEST_PARSE_INT_OPTION("last", "l", last, UINT_MAX); + + DOCTEST_PARSE_INT_OPTION("abort-after", "aa", abort_after, 0); + DOCTEST_PARSE_INT_OPTION("subcase-filter-levels", "scfl", subcase_filter_levels, INT_MAX); + + DOCTEST_PARSE_AS_BOOL_OR_FLAG("success", "s", success, false); + DOCTEST_PARSE_AS_BOOL_OR_FLAG("case-sensitive", "cs", case_sensitive, false); + DOCTEST_PARSE_AS_BOOL_OR_FLAG("exit", "e", exit, false); + DOCTEST_PARSE_AS_BOOL_OR_FLAG("duration", "d", duration, false); + DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-throw", "nt", no_throw, false); + DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-exitcode", "ne", no_exitcode, false); + DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-run", "nr", no_run, false); + DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-version", "nv", no_version, false); + DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-colors", "nc", no_colors, false); + DOCTEST_PARSE_AS_BOOL_OR_FLAG("force-colors", "fc", force_colors, false); + DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-breaks", "nb", no_breaks, false); + DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-skip", "ns", no_skip, false); + DOCTEST_PARSE_AS_BOOL_OR_FLAG("gnu-file-line", "gfl", gnu_file_line, !bool(DOCTEST_MSVC)); + DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-path-filenames", "npf", no_path_in_filenames, false); + DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-line-numbers", "nln", no_line_numbers, false); + DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-skipped-summary", "nss", no_skipped_summary, false); + // clang-format on + + if(withDefaults) { + p->help = false; + p->version = false; + p->count = false; + p->list_test_cases = false; + p->list_test_suites = false; + p->list_reporters = false; + } + if(parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "help") || + parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "h") || + parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "?")) { + p->help = true; + p->exit = true; + } + if(parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "version") || + parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "v")) { + p->version = true; + p->exit = true; + } + if(parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "count") || + parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "c")) { + p->count = true; + p->exit = true; + } + if(parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "list-test-cases") || + parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "ltc")) { + p->list_test_cases = true; + p->exit = true; + } + if(parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "list-test-suites") || + parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "lts")) { + p->list_test_suites = true; + p->exit = true; + } + if(parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "list-reporters") || + parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "lr")) { + p->list_reporters = true; + p->exit = true; + } +} + +// allows the user to add procedurally to the filters from the command line +void Context::addFilter(const char* filter, const char* value) { setOption(filter, value); } + +// allows the user to clear all filters from the command line +void Context::clearFilters() { + for(auto& curr : p->filters) + curr.clear(); +} + +// allows the user to override procedurally the int/bool options from the command line +void Context::setOption(const char* option, int value) { + setOption(option, toString(value).c_str()); +} + +// allows the user to override procedurally the string options from the command line +void Context::setOption(const char* option, const char* value) { + auto argv = String("-") + option + "=" + value; + auto lvalue = argv.c_str(); + parseArgs(1, &lvalue); +} + +// users should query this in their main() and exit the program if true +bool Context::shouldExit() { return p->exit; } + +void Context::setAsDefaultForAssertsOutOfTestCases() { g_cs = p; } + +void Context::setAssertHandler(detail::assert_handler ah) { p->ah = ah; } + +// the main function that does all the filtering and test running +int Context::run() { + using namespace detail; + + // save the old context state in case such was setup - for using asserts out of a testing context + auto old_cs = g_cs; + // this is the current contest + g_cs = p; + is_running_in_test = true; + + g_no_colors = p->no_colors; + p->resetRunData(); + + // stdout by default + p->cout = &std::cout; + p->cerr = &std::cerr; + + // or to a file if specified + std::fstream fstr; + if(p->out.size()) { + fstr.open(p->out.c_str(), std::fstream::out); + p->cout = &fstr; + } + + auto cleanup_and_return = [&]() { + if(fstr.is_open()) + fstr.close(); + + // restore context + g_cs = old_cs; + is_running_in_test = false; + + // we have to free the reporters which were allocated when the run started + for(auto& curr : p->reporters_currently_used) + delete curr; + p->reporters_currently_used.clear(); + + if(p->numTestCasesFailed && !p->no_exitcode) + return EXIT_FAILURE; + return EXIT_SUCCESS; + }; + + // setup default reporter if none is given through the command line + if(p->filters[8].empty()) + p->filters[8].push_back("console"); + + // check to see if any of the registered reporters has been selected + for(auto& curr : getReporters()) { + if(matchesAny(curr.first.second.c_str(), p->filters[8], false, p->case_sensitive)) + p->reporters_currently_used.push_back(curr.second(*g_cs)); + } + + // TODO: check if there is nothing in reporters_currently_used + + // prepend all listeners + for(auto& curr : getListeners()) + p->reporters_currently_used.insert(p->reporters_currently_used.begin(), curr.second(*g_cs)); + +#ifdef DOCTEST_PLATFORM_WINDOWS + if(isDebuggerActive()) + p->reporters_currently_used.push_back(new DebugOutputWindowReporter(*g_cs)); +#endif // DOCTEST_PLATFORM_WINDOWS + + // handle version, help and no_run + if(p->no_run || p->version || p->help || p->list_reporters) { + DOCTEST_ITERATE_THROUGH_REPORTERS(report_query, QueryData()); + + return cleanup_and_return(); + } + + std::vector testArray; + for(auto& curr : getRegisteredTests()) + testArray.push_back(&curr); + p->numTestCases = testArray.size(); + + // sort the collected records + if(!testArray.empty()) { + if(p->order_by.compare("file", true) == 0) { + std::sort(testArray.begin(), testArray.end(), fileOrderComparator); + } else if(p->order_by.compare("suite", true) == 0) { + std::sort(testArray.begin(), testArray.end(), suiteOrderComparator); + } else if(p->order_by.compare("name", true) == 0) { + std::sort(testArray.begin(), testArray.end(), nameOrderComparator); + } else if(p->order_by.compare("rand", true) == 0) { + std::srand(p->rand_seed); + + // random_shuffle implementation + const auto first = &testArray[0]; + for(size_t i = testArray.size() - 1; i > 0; --i) { + int idxToSwap = std::rand() % (i + 1); // NOLINT + + const auto temp = first[i]; + + first[i] = first[idxToSwap]; + first[idxToSwap] = temp; + } + } + } + + std::set testSuitesPassingFilt; + + bool query_mode = p->count || p->list_test_cases || p->list_test_suites; + std::vector queryResults; + + if(!query_mode) + DOCTEST_ITERATE_THROUGH_REPORTERS(test_run_start, DOCTEST_EMPTY); + + // invoke the registered functions if they match the filter criteria (or just count them) + for(auto& curr : testArray) { + const auto& tc = *curr; + + bool skip_me = false; + if(tc.m_skip && !p->no_skip) + skip_me = true; + + if(!matchesAny(tc.m_file.c_str(), p->filters[0], true, p->case_sensitive)) + skip_me = true; + if(matchesAny(tc.m_file.c_str(), p->filters[1], false, p->case_sensitive)) + skip_me = true; + if(!matchesAny(tc.m_test_suite, p->filters[2], true, p->case_sensitive)) + skip_me = true; + if(matchesAny(tc.m_test_suite, p->filters[3], false, p->case_sensitive)) + skip_me = true; + if(!matchesAny(tc.m_name, p->filters[4], true, p->case_sensitive)) + skip_me = true; + if(matchesAny(tc.m_name, p->filters[5], false, p->case_sensitive)) + skip_me = true; + + if(!skip_me) + p->numTestCasesPassingFilters++; + + // skip the test if it is not in the execution range + if((p->last < p->numTestCasesPassingFilters && p->first <= p->last) || + (p->first > p->numTestCasesPassingFilters)) + skip_me = true; + + if(skip_me) { + if(!query_mode) + DOCTEST_ITERATE_THROUGH_REPORTERS(test_case_skipped, tc); + continue; + } + + // do not execute the test if we are to only count the number of filter passing tests + if(p->count) + continue; + + // print the name of the test and don't execute it + if(p->list_test_cases) { + queryResults.push_back(&tc); + continue; + } + + // print the name of the test suite if not done already and don't execute it + if(p->list_test_suites) { + if((testSuitesPassingFilt.count(tc.m_test_suite) == 0) && tc.m_test_suite[0] != '\0') { + queryResults.push_back(&tc); + testSuitesPassingFilt.insert(tc.m_test_suite); + p->numTestSuitesPassingFilters++; + } + continue; + } + + // execute the test if it passes all the filtering + { + p->currentTest = &tc; + + p->failure_flags = TestCaseFailureReason::None; + p->seconds = 0; + + // reset atomic counters + p->numAssertsFailedCurrentTest_atomic = 0; + p->numAssertsCurrentTest_atomic = 0; + + p->subcasesPassed.clear(); + + DOCTEST_ITERATE_THROUGH_REPORTERS(test_case_start, tc); + + p->timer.start(); + + bool run_test = true; + + do { + // reset some of the fields for subcases (except for the set of fully passed ones) + p->should_reenter = false; + p->subcasesCurrentMaxLevel = 0; + p->subcasesStack.clear(); + + p->shouldLogCurrentException = true; + + // reset stuff for logging with INFO() + p->stringifiedContexts.clear(); + +#ifndef DOCTEST_CONFIG_NO_EXCEPTIONS + try { +#endif // DOCTEST_CONFIG_NO_EXCEPTIONS + FatalConditionHandler fatalConditionHandler; // Handle signals + // execute the test + tc.m_test(); + fatalConditionHandler.reset(); +#ifndef DOCTEST_CONFIG_NO_EXCEPTIONS + } catch(const TestFailureException&) { + p->failure_flags |= TestCaseFailureReason::AssertFailure; + } catch(...) { + DOCTEST_ITERATE_THROUGH_REPORTERS(test_case_exception, + {translateActiveException(), false}); + p->failure_flags |= TestCaseFailureReason::Exception; + } +#endif // DOCTEST_CONFIG_NO_EXCEPTIONS + + // exit this loop if enough assertions have failed - even if there are more subcases + if(p->abort_after > 0 && + p->numAssertsFailed + p->numAssertsFailedCurrentTest_atomic >= p->abort_after) { + run_test = false; + p->failure_flags |= TestCaseFailureReason::TooManyFailedAsserts; + } + + if(p->should_reenter && run_test) + DOCTEST_ITERATE_THROUGH_REPORTERS(test_case_reenter, tc); + if(!p->should_reenter) + run_test = false; + } while(run_test); + + p->finalizeTestCaseData(); + + DOCTEST_ITERATE_THROUGH_REPORTERS(test_case_end, *g_cs); + + p->currentTest = nullptr; + + // stop executing tests if enough assertions have failed + if(p->abort_after > 0 && p->numAssertsFailed >= p->abort_after) + break; + } + } + + if(!query_mode) { + DOCTEST_ITERATE_THROUGH_REPORTERS(test_run_end, *g_cs); + } else { + QueryData qdata; + qdata.run_stats = g_cs; + qdata.data = queryResults.data(); + qdata.num_data = unsigned(queryResults.size()); + DOCTEST_ITERATE_THROUGH_REPORTERS(report_query, qdata); + } + + // see these issues on the reasoning for this: + // - https://github.com/onqtam/doctest/issues/143#issuecomment-414418903 + // - https://github.com/onqtam/doctest/issues/126 + auto DOCTEST_FIX_FOR_MACOS_LIBCPP_IOSFWD_STRING_LINK_ERRORS = []() DOCTEST_NOINLINE + { std::cout << std::string(); }; + DOCTEST_FIX_FOR_MACOS_LIBCPP_IOSFWD_STRING_LINK_ERRORS(); + + return cleanup_and_return(); +} + +IReporter::~IReporter() = default; + +int IReporter::get_num_active_contexts() { return detail::g_infoContexts.size(); } +const IContextScope* const* IReporter::get_active_contexts() { + return get_num_active_contexts() ? &detail::g_infoContexts[0] : nullptr; +} + +int IReporter::get_num_stringified_contexts() { return detail::g_cs->stringifiedContexts.size(); } +const String* IReporter::get_stringified_contexts() { + return get_num_stringified_contexts() ? &detail::g_cs->stringifiedContexts[0] : nullptr; +} + +namespace detail { + void registerReporterImpl(const char* name, int priority, reporterCreatorFunc c, bool isReporter) { + if(isReporter) + getReporters().insert(reporterMap::value_type(reporterMap::key_type(priority, name), c)); + else + getListeners().insert(reporterMap::value_type(reporterMap::key_type(priority, name), c)); + } +} // namespace detail + +} // namespace doctest + +#endif // DOCTEST_CONFIG_DISABLE + +#ifdef DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN +DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4007) // 'function' : must be 'attribute' - see issue #182 +int main(int argc, char** argv) { return doctest::Context(argc, argv).run(); } +DOCTEST_MSVC_SUPPRESS_WARNING_POP +#endif // DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN + +DOCTEST_CLANG_SUPPRESS_WARNING_POP +DOCTEST_MSVC_SUPPRESS_WARNING_POP +DOCTEST_GCC_SUPPRESS_WARNING_POP + +#endif // DOCTEST_LIBRARY_IMPLEMENTATION +#endif // DOCTEST_CONFIG_IMPLEMENT diff --git a/extern/imgui/CMakeLists.txt b/extern/imgui/CMakeLists.txt new file mode 100755 index 0000000..45fda3b --- /dev/null +++ b/extern/imgui/CMakeLists.txt @@ -0,0 +1,12 @@ +add_library(imgui STATIC + src/imgui_demo.cpp + src/imgui_draw.cpp + src/imgui_widgets.cpp + src/imgui.cpp + src/imgui_stdlib.cpp + include/imconfig.h + include/imgui_stdlib.h + include/imgui.h + src/imgui_internal.h) +target_include_directories(imgui PUBLIC include src) +target_link_libraries(imgui PUBLIC stb Utility) diff --git a/extern/imgui/include/imconfig.h b/extern/imgui/include/imconfig.h new file mode 100644 index 0000000..3fc7f5e --- /dev/null +++ b/extern/imgui/include/imconfig.h @@ -0,0 +1,112 @@ +//----------------------------------------------------------------------------- +// COMPILE-TIME OPTIONS FOR DEAR IMGUI +// Runtime options (clipboard callbacks, enabling various features, etc.) can generally be set via the ImGuiIO structure. +// You can use ImGui::SetAllocatorFunctions() before calling ImGui::CreateContext() to rewire memory allocation functions. +//----------------------------------------------------------------------------- +// A) You may edit imconfig.h (and not overwrite it when updating Dear ImGui, or maintain a patch/branch with your modifications to imconfig.h) +// B) or add configuration directives in your own file and compile with #define IMGUI_USER_CONFIG "myfilename.h" +// If you do so you need to make sure that configuration settings are defined consistently _everywhere_ Dear ImGui is used, which include +// the imgui*.cpp files but also _any_ of your code that uses Dear ImGui. This is because some compile-time options have an affect on data structures. +// Defining those options in imconfig.h will ensure every compilation unit gets to see the same data structure layouts. +// Call IMGUI_CHECKVERSION() from your .cpp files to verify that the data structures your files are using are matching the ones imgui.cpp is using. +//----------------------------------------------------------------------------- + +#pragma once + +#include "common.hpp" + +//---- Define assertion handler. Defaults to calling assert(). +// If your macro uses multiple statements, make sure is enclosed in a 'do { .. } while (0)' block so it can be used as a single statement. +//#define IM_ASSERT(_EXPR) MyAssert(_EXPR) +//#define IM_ASSERT(_EXPR) ((void)(_EXPR)) // Disable asserts + +//---- Define attributes of all API symbols declarations, e.g. for DLL under Windows +// Using dear imgui via a shared library is not recommended, because of function call overhead and because we don't guarantee backward nor forward ABI compatibility. +//#define IMGUI_API __declspec( dllexport ) +//#define IMGUI_API __declspec( dllimport ) + +//---- Don't define obsolete functions/enums/behaviors. Consider enabling from time to time after updating to avoid using soon-to-be obsolete function/names. +#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS + +//---- Disable all of Dear ImGui or don't implement standard windows. +// It is very strongly recommended to NOT disable the demo windows during development. Please read comments in imgui_demo.cpp. +//#define IMGUI_DISABLE // Disable everything: all headers and source files will be empty. +//#define IMGUI_DISABLE_DEMO_WINDOWS // Disable demo windows: ShowDemoWindow()/ShowStyleEditor() will be empty. Not recommended. +//#define IMGUI_DISABLE_METRICS_WINDOW // Disable debug/metrics window: ShowMetricsWindow() will be empty. + +//---- Don't implement some functions to reduce linkage requirements. +//#define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS // [Win32] Don't implement default clipboard handler. Won't use and link with OpenClipboard/GetClipboardData/CloseClipboard etc. +//#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] Don't implement default IME handler. Won't use and link with ImmGetContext/ImmSetCompositionWindow. +//#define IMGUI_DISABLE_WIN32_FUNCTIONS // [Win32] Won't use and link with any Win32 function (clipboard, ime). +//#define IMGUI_ENABLE_OSX_DEFAULT_CLIPBOARD_FUNCTIONS // [OSX] Implement default OSX clipboard handler (need to link with '-framework ApplicationServices', this is why this is not the default). +//#define IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS // Don't implement ImFormatString/ImFormatStringV so you can implement them yourself (e.g. if you don't want to link with vsnprintf) +//#define IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS // Don't implement ImFabs/ImSqrt/ImPow/ImFmod/ImCos/ImSin/ImAcos/ImAtan2 so you can implement them yourself. +//#define IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite so you can implement them yourself if you don't want to link with fopen/fclose/fread/fwrite. This will also disable the LogToTTY() function. +//#define IMGUI_DISABLE_DEFAULT_ALLOCATORS // Don't implement default allocators calling malloc()/free() to avoid linking with them. You will need to call ImGui::SetAllocatorFunctions(). + +//---- Include imgui_user.h at the end of imgui.h as a convenience +//#define IMGUI_INCLUDE_IMGUI_USER_H + +//---- Pack colors to BGRA8 instead of RGBA8 (to avoid converting from one to another) +//#define IMGUI_USE_BGRA_PACKED_COLOR + +//---- Use 32-bit for ImWchar (default is 16-bit) to support full unicode code points. +//#define IMGUI_USE_WCHAR32 + +//---- Avoid multiple STB libraries implementations, or redefine path/filenames to prioritize another version +// By default the embedded implementations are declared static and not available outside of imgui cpp files. +#define IMGUI_STB_TRUETYPE_FILENAME "stb_truetype.h" +#define IMGUI_STB_RECT_PACK_FILENAME "stb_rect_pack.h" +//#define IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION +//#define IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION + +//---- Unless IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS is defined, use the much faster STB sprintf library implementation of vsnprintf instead of the one from the default C library. +// Note that stb_sprintf.h is meant to be provided by the user and available in the include path at compile time. Also, the compatibility checks of the arguments and formats done by clang and GCC will be disabled in order to support the extra formats provided by STB sprintf. +// #define IMGUI_USE_STB_SPRINTF + +//---- Define constructor and implicit cast operators to convert back<>forth between your math types and ImVec2/ImVec4. +// This will be inlined as part of ImVec2 and ImVec4 class declarations. + +#define IM_VEC2_CLASS_EXTRA \ + ImVec2(const Offset& f) { x = static_cast(f.x); y = static_cast(f.y); } \ + operator Offset() const { return Offset(static_cast(x), static_cast(y)); } \ + ImVec2(const Extent& f) { x = static_cast(f.width); y = static_cast(f.height); } \ + operator Extent() const { return Extent(static_cast(x), static_cast(y)); } + +/*#define IM_VEC4_CLASS_EXTRA \ + ImVec4(const MyVec4& f) { x = f.x; y = f.y; z = f.z; w = f.w; } \ + operator MyVec4() const { return MyVec4(x,y,z,w); } +*/ + +//---- Use 32-bit vertex indices (default is 16-bit) is one way to allow large meshes with more than 64K vertices. +// Your renderer back-end will need to support it (most example renderer back-ends support both 16/32-bit indices). +// Another way to allow large meshes while keeping 16-bit indices is to handle ImDrawCmd::VtxOffset in your renderer. +// Read about ImGuiBackendFlags_RendererHasVtxOffset for details. +//#define ImDrawIdx unsigned int + +//---- Override ImDrawCallback signature (will need to modify renderer back-ends accordingly) +//struct ImDrawList; +//struct ImDrawCmd; +//typedef void (*MyImDrawCallback)(const ImDrawList* draw_list, const ImDrawCmd* cmd, void* my_renderer_user_data); +//#define ImDrawCallback MyImDrawCallback + +//---- Debug Tools: Macro to break in Debugger +// (use 'Metrics->Tools->Item Picker' to pick widgets with the mouse and break into them for easy debugging.) +//#define IM_DEBUG_BREAK IM_ASSERT(0) +//#define IM_DEBUG_BREAK __debugbreak() + +//---- Debug Tools: Have the Item Picker break in the ItemAdd() function instead of ItemHoverable(), +// (which comes earlier in the code, will catch a few extra items, allow picking items other than Hovered one.) +// This adds a small runtime cost which is why it is not enabled by default. +//#define IMGUI_DEBUG_TOOL_ITEM_PICKER_EX + +//---- Debug Tools: Enable slower asserts +//#define IMGUI_DEBUG_PARANOID + +//---- Tip: You can add extra functions within the ImGui:: namespace, here or in your own headers files. +/* +namespace ImGui +{ + void MyFunction(const char* name, const MyMatrix44& v); +} +*/ diff --git a/extern/imgui/include/imgui.h b/extern/imgui/include/imgui.h new file mode 100644 index 0000000..eb893df --- /dev/null +++ b/extern/imgui/include/imgui.h @@ -0,0 +1,2622 @@ +// dear imgui, v1.77 WIP +// (headers) + +// Help: +// - Read FAQ at http://dearimgui.org/faq +// - Newcomers, read 'Programmer guide' in imgui.cpp for notes on how to setup Dear ImGui in your codebase. +// - Call and read ImGui::ShowDemoWindow() in imgui_demo.cpp. All applications in examples/ are doing that. +// Read imgui.cpp for details, links and comments. + +// Resources: +// - FAQ http://dearimgui.org/faq +// - Homepage & latest https://github.com/ocornut/imgui +// - Releases & changelog https://github.com/ocornut/imgui/releases +// - Gallery https://github.com/ocornut/imgui/issues/3075 (please post your screenshots/video there!) +// - Glossary https://github.com/ocornut/imgui/wiki/Glossary +// - Wiki https://github.com/ocornut/imgui/wiki +// - Issues & support https://github.com/ocornut/imgui/issues + +/* + +Index of this file: +// Header mess +// Forward declarations and basic types +// ImGui API (Dear ImGui end-user API) +// Flags & Enumerations +// Memory allocations macros +// ImVector<> +// ImGuiStyle +// ImGuiIO +// Misc data structures (ImGuiInputTextCallbackData, ImGuiSizeCallbackData, ImGuiWindowClass, ImGuiPayload) +// Obsolete functions +// Helpers (ImGuiOnceUponAFrame, ImGuiTextFilter, ImGuiTextBuffer, ImGuiStorage, ImGuiListClipper, ImColor) +// Draw List API (ImDrawCallback, ImDrawCmd, ImDrawIdx, ImDrawVert, ImDrawChannel, ImDrawListSplitter, ImDrawListFlags, ImDrawList, ImDrawData) +// Font API (ImFontConfig, ImFontGlyph, ImFontGlyphRangesBuilder, ImFontAtlasFlags, ImFontAtlas, ImFont) +// Platform interface for multi-viewport support (ImGuiPlatformIO, ImGuiPlatformMonitor, ImGuiViewportFlags, ImGuiViewport) + +*/ + +#pragma once + +// Configuration file with compile-time options (edit imconfig.h or #define IMGUI_USER_CONFIG to your own filename) +#ifdef IMGUI_USER_CONFIG +#include IMGUI_USER_CONFIG +#endif +#if !defined(IMGUI_DISABLE_INCLUDE_IMCONFIG_H) || defined(IMGUI_INCLUDE_IMCONFIG_H) +#include "imconfig.h" +#endif + +#ifndef IMGUI_DISABLE + +//----------------------------------------------------------------------------- +// Header mess +//----------------------------------------------------------------------------- + +// Includes +#include // FLT_MIN, FLT_MAX +#include // va_list, va_start, va_end +#include // ptrdiff_t, NULL +#include // memset, memmove, memcpy, strlen, strchr, strcpy, strcmp + +// Version +// (Integer encoded as XYYZZ for use in #if preprocessor conditionals. Work in progress versions typically starts at XYY99 then bounce up to XYY00, XYY01 etc. when release tagging happens) +#define IMGUI_VERSION "1.77 WIP" +#define IMGUI_VERSION_NUM 17601 +#define IMGUI_CHECKVERSION() ImGui::DebugCheckVersionAndDataLayout(IMGUI_VERSION, sizeof(ImGuiIO), sizeof(ImGuiStyle), sizeof(ImVec2), sizeof(ImVec4), sizeof(ImDrawVert), sizeof(ImDrawIdx)) +#define IMGUI_HAS_VIEWPORT 1 // Viewport WIP branch +#define IMGUI_HAS_DOCK 1 // Docking WIP branch + +// Define attributes of all API symbols declarations (e.g. for DLL under Windows) +// IMGUI_API is used for core imgui functions, IMGUI_IMPL_API is used for the default bindings files (imgui_impl_xxx.h) +// Using dear imgui via a shared library is not recommended, because we don't guarantee backward nor forward ABI compatibility (also function call overhead, as dear imgui is a call-heavy API) +#ifndef IMGUI_API +#define IMGUI_API +#endif +#ifndef IMGUI_IMPL_API +#define IMGUI_IMPL_API IMGUI_API +#endif + +// Helper Macros +#ifndef IM_ASSERT +#include +#define IM_ASSERT(_EXPR) assert(_EXPR) // You can override the default assert handler by editing imconfig.h +#endif +#if !defined(IMGUI_USE_STB_SPRINTF) && (defined(__clang__) || defined(__GNUC__)) +#define IM_FMTARGS(FMT) __attribute__((format(printf, FMT, FMT+1))) // To apply printf-style warnings to our functions. +#define IM_FMTLIST(FMT) __attribute__((format(printf, FMT, 0))) +#else +#define IM_FMTARGS(FMT) +#define IM_FMTLIST(FMT) +#endif +#define IM_ARRAYSIZE(_ARR) ((int)(sizeof(_ARR) / sizeof(*_ARR))) // Size of a static C-style array. Don't use on pointers! +#define IM_UNUSED(_VAR) ((void)_VAR) // Used to silence "unused variable warnings". Often useful as asserts may be stripped out from final builds. +#if (__cplusplus >= 201100) +#define IM_OFFSETOF(_TYPE,_MEMBER) offsetof(_TYPE, _MEMBER) // Offset of _MEMBER within _TYPE. Standardized as offsetof() in C++11 +#else +#define IM_OFFSETOF(_TYPE,_MEMBER) ((size_t)&(((_TYPE*)0)->_MEMBER)) // Offset of _MEMBER within _TYPE. Old style macro. +#endif + +// Warnings +#if defined(__clang__) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wold-style-cast" +#if __has_warning("-Wzero-as-null-pointer-constant") +#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" +#endif +#elif defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind +#pragma GCC diagnostic ignored "-Wclass-memaccess" // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead +#endif + +//----------------------------------------------------------------------------- +// Forward declarations and basic types +//----------------------------------------------------------------------------- + +// Forward declarations +struct ImDrawChannel; // Temporary storage to output draw commands out of order, used by ImDrawListSplitter and ImDrawList::ChannelsSplit() +struct ImDrawCmd; // A single draw command within a parent ImDrawList (generally maps to 1 GPU draw call, unless it is a callback) +struct ImDrawData; // All draw command lists required to render the frame + pos/size coordinates to use for the projection matrix. +struct ImDrawList; // A single draw command list (generally one per window, conceptually you may see this as a dynamic "mesh" builder) +struct ImDrawListSharedData; // Data shared among multiple draw lists (typically owned by parent ImGui context, but you may create one yourself) +struct ImDrawListSplitter; // Helper to split a draw list into different layers which can be drawn into out of order, then flattened back. +struct ImDrawVert; // A single vertex (pos + uv + col = 20 bytes by default. Override layout with IMGUI_OVERRIDE_DRAWVERT_STRUCT_LAYOUT) +struct ImFont; // Runtime data for a single font within a parent ImFontAtlas +struct ImFontAtlas; // Runtime data for multiple fonts, bake multiple fonts into a single texture, TTF/OTF font loader +struct ImFontConfig; // Configuration data when adding a font or merging fonts +struct ImFontGlyph; // A single font glyph (code point + coordinates within in ImFontAtlas + offset) +struct ImFontGlyphRangesBuilder; // Helper to build glyph ranges from text/string data +struct ImColor; // Helper functions to create a color that can be converted to either u32 or float4 (*OBSOLETE* please avoid using) +struct ImGuiContext; // Dear ImGui context (opaque structure, unless including imgui_internal.h) +struct ImGuiIO; // Main configuration and I/O between your application and ImGui +struct ImGuiInputTextCallbackData; // Shared state of InputText() when using custom ImGuiInputTextCallback (rare/advanced use) +struct ImGuiListClipper; // Helper to manually clip large list of items +struct ImGuiOnceUponAFrame; // Helper for running a block of code not more than once a frame, used by IMGUI_ONCE_UPON_A_FRAME macro +struct ImGuiPayload; // User data payload for drag and drop operations +struct ImGuiPlatformIO; // Multi-viewport support: interface for Platform/Renderer back-ends + viewports to render +struct ImGuiPlatformMonitor; // Multi-viewport support: user-provided bounds for each connected monitor/display. Used when positioning popups and tooltips to avoid them straddling monitors +struct ImGuiSizeCallbackData; // Callback data when using SetNextWindowSizeConstraints() (rare/advanced use) +struct ImGuiStorage; // Helper for key->value storage +struct ImGuiStyle; // Runtime data for styling/colors +struct ImGuiTextBuffer; // Helper to hold and append into a text buffer (~string builder) +struct ImGuiTextFilter; // Helper to parse and apply text filters (e.g. "aaaaa[,bbbbb][,ccccc]") +struct ImGuiViewport; // Viewport (generally ~1 per window to output to at the OS level. Need per-platform support to use multiple viewports) +struct ImGuiWindowClass; // Window class (rare/advanced uses: provide hints to the platform back-end via altered viewport flags and parent/child info) + +// Enums/Flags (declared as int for compatibility with old C++, to allow using as flags and to not pollute the top of this file) +// - Tip: Use your programming IDE navigation facilities on the names in the _central column_ below to find the actual flags/enum lists! +// In Visual Studio IDE: CTRL+comma ("Edit.NavigateTo") can follow symbols in comments, whereas CTRL+F12 ("Edit.GoToImplementation") cannot. +// With Visual Assist installed: ALT+G ("VAssistX.GoToImplementation") can also follow symbols in comments. +typedef int ImGuiCol; // -> enum ImGuiCol_ // Enum: A color identifier for styling +typedef int ImGuiCond; // -> enum ImGuiCond_ // Enum: A condition for many Set*() functions +typedef int ImGuiDataType; // -> enum ImGuiDataType_ // Enum: A primary data type +typedef int ImGuiDir; // -> enum ImGuiDir_ // Enum: A cardinal direction +typedef int ImGuiKey; // -> enum ImGuiKey_ // Enum: A key identifier (ImGui-side enum) +typedef int ImGuiNavInput; // -> enum ImGuiNavInput_ // Enum: An input identifier for navigation +typedef int ImGuiMouseButton; // -> enum ImGuiMouseButton_ // Enum: A mouse button identifier (0=left, 1=right, 2=middle) +typedef int ImGuiMouseCursor; // -> enum ImGuiMouseCursor_ // Enum: A mouse cursor identifier +typedef int ImGuiStyleVar; // -> enum ImGuiStyleVar_ // Enum: A variable identifier for styling +typedef int ImDrawCornerFlags; // -> enum ImDrawCornerFlags_ // Flags: for ImDrawList::AddRect(), AddRectFilled() etc. +typedef int ImDrawListFlags; // -> enum ImDrawListFlags_ // Flags: for ImDrawList +typedef int ImFontAtlasFlags; // -> enum ImFontAtlasFlags_ // Flags: for ImFontAtlas +typedef int ImGuiBackendFlags; // -> enum ImGuiBackendFlags_ // Flags: for io.BackendFlags +typedef int ImGuiColorEditFlags; // -> enum ImGuiColorEditFlags_ // Flags: for ColorEdit4(), ColorPicker4() etc. +typedef int ImGuiConfigFlags; // -> enum ImGuiConfigFlags_ // Flags: for io.ConfigFlags +typedef int ImGuiComboFlags; // -> enum ImGuiComboFlags_ // Flags: for BeginCombo() +typedef int ImGuiDockNodeFlags; // -> enum ImGuiDockNodeFlags_ // Flags: for DockSpace() +typedef int ImGuiDragDropFlags; // -> enum ImGuiDragDropFlags_ // Flags: for BeginDragDropSource(), AcceptDragDropPayload() +typedef int ImGuiFocusedFlags; // -> enum ImGuiFocusedFlags_ // Flags: for IsWindowFocused() +typedef int ImGuiHoveredFlags; // -> enum ImGuiHoveredFlags_ // Flags: for IsItemHovered(), IsWindowHovered() etc. +typedef int ImGuiInputTextFlags; // -> enum ImGuiInputTextFlags_ // Flags: for InputText(), InputTextMultiline() +typedef int ImGuiKeyModFlags; // -> enum ImGuiKeyModFlags_ // Flags: for io.KeyMods (Ctrl/Shift/Alt/Super) +typedef int ImGuiSelectableFlags; // -> enum ImGuiSelectableFlags_ // Flags: for Selectable() +typedef int ImGuiTabBarFlags; // -> enum ImGuiTabBarFlags_ // Flags: for BeginTabBar() +typedef int ImGuiTabItemFlags; // -> enum ImGuiTabItemFlags_ // Flags: for BeginTabItem() +typedef int ImGuiTreeNodeFlags; // -> enum ImGuiTreeNodeFlags_ // Flags: for TreeNode(), TreeNodeEx(), CollapsingHeader() +typedef int ImGuiViewportFlags; // -> enum ImGuiViewportFlags_ // Flags: for ImGuiViewport +typedef int ImGuiWindowFlags; // -> enum ImGuiWindowFlags_ // Flags: for Begin(), BeginChild() + +// Other types +#ifndef ImTextureID // ImTextureID [configurable type: override in imconfig.h with '#define ImTextureID xxx'] +typedef void* ImTextureID; // User data for rendering back-end to identify a texture. This is whatever to you want it to be! read the FAQ about ImTextureID for details. +#endif +typedef unsigned int ImGuiID; // A unique ID used by widgets, typically hashed from a stack of string. +typedef int (*ImGuiInputTextCallback)(ImGuiInputTextCallbackData *data); +typedef void (*ImGuiSizeCallback)(ImGuiSizeCallbackData* data); + +// Decoded character types +// (we generally use UTF-8 encoded string in the API. This is storage specifically for a decoded character used for keyboard input and display) +typedef unsigned short ImWchar16; // A single decoded U16 character/code point. We encode them as multi bytes UTF-8 when used in strings. +typedef unsigned int ImWchar32; // A single decoded U32 character/code point. We encode them as multi bytes UTF-8 when used in strings. +#ifdef IMGUI_USE_WCHAR32 // ImWchar [configurable type: override in imconfig.h with '#define IMGUI_USE_WCHAR32' to support Unicode planes 1-16] +typedef ImWchar32 ImWchar; +#else +typedef ImWchar16 ImWchar; +#endif + +// Basic scalar data types +typedef signed char ImS8; // 8-bit signed integer +typedef unsigned char ImU8; // 8-bit unsigned integer +typedef signed short ImS16; // 16-bit signed integer +typedef unsigned short ImU16; // 16-bit unsigned integer +typedef signed int ImS32; // 32-bit signed integer == int +typedef unsigned int ImU32; // 32-bit unsigned integer (often used to store packed colors) +#if defined(_MSC_VER) && !defined(__clang__) +typedef signed __int64 ImS64; // 64-bit signed integer (pre and post C++11 with Visual Studio) +typedef unsigned __int64 ImU64; // 64-bit unsigned integer (pre and post C++11 with Visual Studio) +#elif (defined(__clang__) || defined(__GNUC__)) && (__cplusplus < 201100) +#include +typedef int64_t ImS64; // 64-bit signed integer (pre C++11) +typedef uint64_t ImU64; // 64-bit unsigned integer (pre C++11) +#else +typedef signed long long ImS64; // 64-bit signed integer (post C++11) +typedef unsigned long long ImU64; // 64-bit unsigned integer (post C++11) +#endif + +// 2D vector (often used to store positions or sizes) +struct ImVec2 +{ + float x, y; + ImVec2() { x = y = 0.0f; } + ImVec2(float _x, float _y) { x = _x; y = _y; } + float operator[] (size_t idx) const { IM_ASSERT(idx <= 1); return (&x)[idx]; } // We very rarely use this [] operator, the assert overhead is fine. + float& operator[] (size_t idx) { IM_ASSERT(idx <= 1); return (&x)[idx]; } // We very rarely use this [] operator, the assert overhead is fine. +#ifdef IM_VEC2_CLASS_EXTRA + IM_VEC2_CLASS_EXTRA // Define additional constructors and implicit cast operators in imconfig.h to convert back and forth between your math types and ImVec2. +#endif +}; + +// 4D vector (often used to store floating-point colors) +struct ImVec4 +{ + float x, y, z, w; + ImVec4() { x = y = z = w = 0.0f; } + ImVec4(float _x, float _y, float _z, float _w) { x = _x; y = _y; z = _z; w = _w; } +#ifdef IM_VEC4_CLASS_EXTRA + IM_VEC4_CLASS_EXTRA // Define additional constructors and implicit cast operators in imconfig.h to convert back and forth between your math types and ImVec4. +#endif +}; + +//----------------------------------------------------------------------------- +// ImGui: Dear ImGui end-user API +// (This is a namespace. You can add extra ImGui:: functions in your own separate file. Please don't modify imgui source files!) +//----------------------------------------------------------------------------- + +namespace ImGui +{ + // Context creation and access + // Each context create its own ImFontAtlas by default. You may instance one yourself and pass it to CreateContext() to share a font atlas between imgui contexts. + // None of those functions is reliant on the current context. + IMGUI_API ImGuiContext* CreateContext(ImFontAtlas* shared_font_atlas = NULL); + IMGUI_API void DestroyContext(ImGuiContext* ctx = NULL); // NULL = destroy current context + IMGUI_API ImGuiContext* GetCurrentContext(); + IMGUI_API void SetCurrentContext(ImGuiContext* ctx); + + // Main + IMGUI_API ImGuiIO& GetIO(); // access the IO structure (mouse/keyboard/gamepad inputs, time, various configuration options/flags) + IMGUI_API ImGuiStyle& GetStyle(); // access the Style structure (colors, sizes). Always use PushStyleCol(), PushStyleVar() to modify style mid-frame! + IMGUI_API void NewFrame(); // start a new Dear ImGui frame, you can submit any command from this point until Render()/EndFrame(). + IMGUI_API void EndFrame(); // ends the Dear ImGui frame. automatically called by Render(). If you don't need to render data (skipping rendering) you may call EndFrame() without Render()... but you'll have wasted CPU already! If you don't need to render, better to not create any windows and not call NewFrame() at all! + IMGUI_API void Render(); // ends the Dear ImGui frame, finalize the draw data. You can get call GetDrawData() to obtain it and run your rendering function (up to v1.60, this used to call io.RenderDrawListsFn(). Nowadays, we allow and prefer calling your render function yourself.) + IMGUI_API ImDrawData* GetDrawData(); // valid after Render() and until the next call to NewFrame(). this is what you have to render. + + // Demo, Debug, Information + IMGUI_API void ShowDemoWindow(bool* p_open = NULL); // create Demo window (previously called ShowTestWindow). demonstrate most ImGui features. call this to learn about the library! try to make it always available in your application! + IMGUI_API void ShowAboutWindow(bool* p_open = NULL); // create About window. display Dear ImGui version, credits and build/system information. + IMGUI_API void ShowMetricsWindow(bool* p_open = NULL); // create Debug/Metrics window. display Dear ImGui internals: draw commands (with individual draw calls and vertices), window list, basic internal state, etc. + IMGUI_API void ShowStyleEditor(ImGuiStyle* ref = NULL); // add style editor block (not a window). you can pass in a reference ImGuiStyle structure to compare to, revert to and save to (else it uses the default style) + IMGUI_API bool ShowStyleSelector(const char* label); // add style selector block (not a window), essentially a combo listing the default styles. + IMGUI_API void ShowFontSelector(const char* label); // add font selector block (not a window), essentially a combo listing the loaded fonts. + IMGUI_API void ShowUserGuide(); // add basic help/info block (not a window): how to manipulate ImGui as a end-user (mouse/keyboard controls). + IMGUI_API const char* GetVersion(); // get the compiled version string e.g. "1.23" (essentially the compiled value for IMGUI_VERSION) + + // Styles + IMGUI_API void StyleColorsDark(ImGuiStyle* dst = NULL); // new, recommended style (default) + IMGUI_API void StyleColorsClassic(ImGuiStyle* dst = NULL); // classic imgui style + IMGUI_API void StyleColorsLight(ImGuiStyle* dst = NULL); // best used with borders and a custom, thicker font + + // Windows + // - Begin() = push window to the stack and start appending to it. End() = pop window from the stack. + // - You may append multiple times to the same window during the same frame. + // - Passing 'bool* p_open != NULL' shows a window-closing widget in the upper-right corner of the window, + // which clicking will set the boolean to false when clicked. + // - Begin() return false to indicate the window is collapsed or fully clipped, so you may early out and omit submitting + // anything to the window. Always call a matching End() for each Begin() call, regardless of its return value! + // [Important: due to legacy reason, this is inconsistent with most other functions such as BeginMenu/EndMenu, + // BeginPopup/EndPopup, etc. where the EndXXX call should only be called if the corresponding BeginXXX function + // returned true. Begin and BeginChild are the only odd ones out. Will be fixed in a future update.] + // - Note that the bottom of window stack always contains a window called "Debug". + IMGUI_API bool Begin(const char* name, bool* p_open = NULL, ImGuiWindowFlags flags = 0); + IMGUI_API void End(); + + // Child Windows + // - Use child windows to begin into a self-contained independent scrolling/clipping regions within a host window. Child windows can embed their own child. + // - For each independent axis of 'size': ==0.0f: use remaining host window size / >0.0f: fixed size / <0.0f: use remaining window size minus abs(size) / Each axis can use a different mode, e.g. ImVec2(0,400). + // - BeginChild() returns false to indicate the window is collapsed or fully clipped, so you may early out and omit submitting anything to the window. + // Always call a matching EndChild() for each BeginChild() call, regardless of its return value [as with Begin: this is due to legacy reason and inconsistent with most BeginXXX functions apart from the regular Begin() which behaves like BeginChild().] + IMGUI_API bool BeginChild(const char* str_id, const ImVec2& size = ImVec2(0,0), bool border = false, ImGuiWindowFlags flags = 0); + IMGUI_API bool BeginChild(ImGuiID id, const ImVec2& size = ImVec2(0,0), bool border = false, ImGuiWindowFlags flags = 0); + IMGUI_API void EndChild(); + + // Windows Utilities + // - 'current window' = the window we are appending into while inside a Begin()/End() block. 'next window' = next window we will Begin() into. + IMGUI_API bool IsWindowAppearing(); + IMGUI_API bool IsWindowCollapsed(); + IMGUI_API bool IsWindowFocused(ImGuiFocusedFlags flags=0); // is current window focused? or its root/child, depending on flags. see flags for options. + IMGUI_API bool IsWindowHovered(ImGuiHoveredFlags flags=0); // is current window hovered (and typically: not blocked by a popup/modal)? see flags for options. NB: If you are trying to check whether your mouse should be dispatched to imgui or to your app, you should use the 'io.WantCaptureMouse' boolean for that! Please read the FAQ! + IMGUI_API ImDrawList* GetWindowDrawList(); // get draw list associated to the current window, to append your own drawing primitives + IMGUI_API float GetWindowDpiScale(); // get DPI scale currently associated to the current window's viewport. + IMGUI_API ImGuiViewport*GetWindowViewport(); // get viewport currently associated to the current window. + IMGUI_API ImVec2 GetWindowPos(); // get current window position in screen space (useful if you want to do your own drawing via the DrawList API) + IMGUI_API ImVec2 GetWindowSize(); // get current window size + IMGUI_API float GetWindowWidth(); // get current window width (shortcut for GetWindowSize().x) + IMGUI_API float GetWindowHeight(); // get current window height (shortcut for GetWindowSize().y) + + // Prefer using SetNextXXX functions (before Begin) rather that SetXXX functions (after Begin). + IMGUI_API void SetNextWindowPos(const ImVec2& pos, ImGuiCond cond = 0, const ImVec2& pivot = ImVec2(0,0)); // set next window position. call before Begin(). use pivot=(0.5f,0.5f) to center on given point, etc. + IMGUI_API void SetNextWindowSize(const ImVec2& size, ImGuiCond cond = 0); // set next window size. set axis to 0.0f to force an auto-fit on this axis. call before Begin() + IMGUI_API void SetNextWindowSizeConstraints(const ImVec2& size_min, const ImVec2& size_max, ImGuiSizeCallback custom_callback = NULL, void* custom_callback_data = NULL); // set next window size limits. use -1,-1 on either X/Y axis to preserve the current size. Sizes will be rounded down. Use callback to apply non-trivial programmatic constraints. + IMGUI_API void SetNextWindowContentSize(const ImVec2& size); // set next window content size (~ scrollable client area, which enforce the range of scrollbars). Not including window decorations (title bar, menu bar, etc.) nor WindowPadding. set an axis to 0.0f to leave it automatic. call before Begin() + IMGUI_API void SetNextWindowCollapsed(bool collapsed, ImGuiCond cond = 0); // set next window collapsed state. call before Begin() + IMGUI_API void SetNextWindowFocus(); // set next window to be focused / top-most. call before Begin() + IMGUI_API void SetNextWindowBgAlpha(float alpha); // set next window background color alpha. helper to easily override the Alpha component of ImGuiCol_WindowBg/ChildBg/PopupBg. you may also use ImGuiWindowFlags_NoBackground. + IMGUI_API void SetNextWindowViewport(ImGuiID viewport_id); // set next window viewport + IMGUI_API void SetWindowPos(const ImVec2& pos, ImGuiCond cond = 0); // (not recommended) set current window position - call within Begin()/End(). prefer using SetNextWindowPos(), as this may incur tearing and side-effects. + IMGUI_API void SetWindowSize(const ImVec2& size, ImGuiCond cond = 0); // (not recommended) set current window size - call within Begin()/End(). set to ImVec2(0,0) to force an auto-fit. prefer using SetNextWindowSize(), as this may incur tearing and minor side-effects. + IMGUI_API void SetWindowCollapsed(bool collapsed, ImGuiCond cond = 0); // (not recommended) set current window collapsed state. prefer using SetNextWindowCollapsed(). + IMGUI_API void SetWindowFocus(); // (not recommended) set current window to be focused / top-most. prefer using SetNextWindowFocus(). + IMGUI_API void SetWindowFontScale(float scale); // set font scale. Adjust IO.FontGlobalScale if you want to scale all windows. This is an old API! For correct scaling, prefer to reload font + rebuild ImFontAtlas + call style.ScaleAllSizes(). + IMGUI_API void SetWindowPos(const char* name, const ImVec2& pos, ImGuiCond cond = 0); // set named window position. + IMGUI_API void SetWindowSize(const char* name, const ImVec2& size, ImGuiCond cond = 0); // set named window size. set axis to 0.0f to force an auto-fit on this axis. + IMGUI_API void SetWindowCollapsed(const char* name, bool collapsed, ImGuiCond cond = 0); // set named window collapsed state + IMGUI_API void SetWindowFocus(const char* name); // set named window to be focused / top-most. use NULL to remove focus. + + // Content region + // - Those functions are bound to be redesigned soon (they are confusing, incomplete and return values in local window coordinates which increases confusion) + IMGUI_API ImVec2 GetContentRegionMax(); // current content boundaries (typically window boundaries including scrolling, or current column boundaries), in windows coordinates + IMGUI_API ImVec2 GetContentRegionAvail(); // == GetContentRegionMax() - GetCursorPos() + IMGUI_API ImVec2 GetWindowContentRegionMin(); // content boundaries min (roughly (0,0)-Scroll), in window coordinates + IMGUI_API ImVec2 GetWindowContentRegionMax(); // content boundaries max (roughly (0,0)+Size-Scroll) where Size can be override with SetNextWindowContentSize(), in window coordinates + IMGUI_API float GetWindowContentRegionWidth(); // + + // Windows Scrolling + IMGUI_API float GetScrollX(); // get scrolling amount [0..GetScrollMaxX()] + IMGUI_API float GetScrollY(); // get scrolling amount [0..GetScrollMaxY()] + IMGUI_API float GetScrollMaxX(); // get maximum scrolling amount ~~ ContentSize.X - WindowSize.X + IMGUI_API float GetScrollMaxY(); // get maximum scrolling amount ~~ ContentSize.Y - WindowSize.Y + IMGUI_API void SetScrollX(float scroll_x); // set scrolling amount [0..GetScrollMaxX()] + IMGUI_API void SetScrollY(float scroll_y); // set scrolling amount [0..GetScrollMaxY()] + IMGUI_API void SetScrollHereX(float center_x_ratio = 0.5f); // adjust scrolling amount to make current cursor position visible. center_x_ratio=0.0: left, 0.5: center, 1.0: right. When using to make a "default/current item" visible, consider using SetItemDefaultFocus() instead. + IMGUI_API void SetScrollHereY(float center_y_ratio = 0.5f); // adjust scrolling amount to make current cursor position visible. center_y_ratio=0.0: top, 0.5: center, 1.0: bottom. When using to make a "default/current item" visible, consider using SetItemDefaultFocus() instead. + IMGUI_API void SetScrollFromPosX(float local_x, float center_x_ratio = 0.5f); // adjust scrolling amount to make given position visible. Generally GetCursorStartPos() + offset to compute a valid position. + IMGUI_API void SetScrollFromPosY(float local_y, float center_y_ratio = 0.5f); // adjust scrolling amount to make given position visible. Generally GetCursorStartPos() + offset to compute a valid position. + + // Parameters stacks (shared) + IMGUI_API void PushFont(ImFont* font); // use NULL as a shortcut to push default font + IMGUI_API void PopFont(); + IMGUI_API void PushStyleColor(ImGuiCol idx, ImU32 col); + IMGUI_API void PushStyleColor(ImGuiCol idx, const ImVec4& col); + IMGUI_API void PopStyleColor(int count = 1); + IMGUI_API void PushStyleVar(ImGuiStyleVar idx, float val); + IMGUI_API void PushStyleVar(ImGuiStyleVar idx, const ImVec2& val); + IMGUI_API void PopStyleVar(int count = 1); + IMGUI_API const ImVec4& GetStyleColorVec4(ImGuiCol idx); // retrieve style color as stored in ImGuiStyle structure. use to feed back into PushStyleColor(), otherwise use GetColorU32() to get style color with style alpha baked in. + IMGUI_API ImFont* GetFont(); // get current font + IMGUI_API float GetFontSize(); // get current font size (= height in pixels) of current font with current scale applied + IMGUI_API ImVec2 GetFontTexUvWhitePixel(); // get UV coordinate for a while pixel, useful to draw custom shapes via the ImDrawList API + IMGUI_API ImU32 GetColorU32(ImGuiCol idx, float alpha_mul = 1.0f); // retrieve given style color with style alpha applied and optional extra alpha multiplier + IMGUI_API ImU32 GetColorU32(const ImVec4& col); // retrieve given color with style alpha applied + IMGUI_API ImU32 GetColorU32(ImU32 col); // retrieve given color with style alpha applied + + // Parameters stacks (current window) + IMGUI_API void PushItemWidth(float item_width); // push width of items for common large "item+label" widgets. >0.0f: width in pixels, <0.0f align xx pixels to the right of window (so -1.0f always align width to the right side). 0.0f = default to ~2/3 of windows width, + IMGUI_API void PopItemWidth(); + IMGUI_API void SetNextItemWidth(float item_width); // set width of the _next_ common large "item+label" widget. >0.0f: width in pixels, <0.0f align xx pixels to the right of window (so -1.0f always align width to the right side) + IMGUI_API float CalcItemWidth(); // width of item given pushed settings and current cursor position. NOT necessarily the width of last item unlike most 'Item' functions. + IMGUI_API void PushTextWrapPos(float wrap_local_pos_x = 0.0f); // push word-wrapping position for Text*() commands. < 0.0f: no wrapping; 0.0f: wrap to end of window (or column); > 0.0f: wrap at 'wrap_pos_x' position in window local space + IMGUI_API void PopTextWrapPos(); + IMGUI_API void PushAllowKeyboardFocus(bool allow_keyboard_focus); // allow focusing using TAB/Shift-TAB, enabled by default but you can disable it for certain widgets + IMGUI_API void PopAllowKeyboardFocus(); + IMGUI_API void PushButtonRepeat(bool repeat); // in 'repeat' mode, Button*() functions return repeated true in a typematic manner (using io.KeyRepeatDelay/io.KeyRepeatRate setting). Note that you can call IsItemActive() after any Button() to tell if the button is held in the current frame. + IMGUI_API void PopButtonRepeat(); + + // Cursor / Layout + // - By "cursor" we mean the current output position. + // - The typical widget behavior is to output themselves at the current cursor position, then move the cursor one line down. + // - You can call SameLine() between widgets to undo the last carriage return and output at the right of the preceding widget. + // - Attention! We currently have inconsistencies between window-local and absolute positions we will aim to fix with future API: + // Window-local coordinates: SameLine(), GetCursorPos(), SetCursorPos(), GetCursorStartPos(), GetContentRegionMax(), GetWindowContentRegion*(), PushTextWrapPos() + // Absolute coordinate: GetCursorScreenPos(), SetCursorScreenPos(), all ImDrawList:: functions. + IMGUI_API void Separator(); // separator, generally horizontal. inside a menu bar or in horizontal layout mode, this becomes a vertical separator. + IMGUI_API void SameLine(float offset_from_start_x=0.0f, float spacing=-1.0f); // call between widgets or groups to layout them horizontally. X position given in window coordinates. + IMGUI_API void NewLine(); // undo a SameLine() or force a new line when in an horizontal-layout context. + IMGUI_API void Spacing(); // add vertical spacing. + IMGUI_API void Dummy(const ImVec2& size); // add a dummy item of given size. unlike InvisibleButton(), Dummy() won't take the mouse click or be navigable into. + IMGUI_API void Indent(float indent_w = 0.0f); // move content position toward the right, by style.IndentSpacing or indent_w if != 0 + IMGUI_API void Unindent(float indent_w = 0.0f); // move content position back to the left, by style.IndentSpacing or indent_w if != 0 + IMGUI_API void BeginGroup(); // lock horizontal starting position + IMGUI_API void EndGroup(); // unlock horizontal starting position + capture the whole group bounding box into one "item" (so you can use IsItemHovered() or layout primitives such as SameLine() on whole group, etc.) + IMGUI_API ImVec2 GetCursorPos(); // cursor position in window coordinates (relative to window position) + IMGUI_API float GetCursorPosX(); // (some functions are using window-relative coordinates, such as: GetCursorPos, GetCursorStartPos, GetContentRegionMax, GetWindowContentRegion* etc. + IMGUI_API float GetCursorPosY(); // other functions such as GetCursorScreenPos or everything in ImDrawList:: + IMGUI_API void SetCursorPos(const ImVec2& local_pos); // are using the main, absolute coordinate system. + IMGUI_API void SetCursorPosX(float local_x); // GetWindowPos() + GetCursorPos() == GetCursorScreenPos() etc.) + IMGUI_API void SetCursorPosY(float local_y); // + IMGUI_API ImVec2 GetCursorStartPos(); // initial cursor position in window coordinates + IMGUI_API ImVec2 GetCursorScreenPos(); // cursor position in absolute screen coordinates (0..io.DisplaySize) or natural OS coordinates when using multiple viewport. Useful to work with ImDrawList API. + IMGUI_API void SetCursorScreenPos(const ImVec2& pos); // cursor position in absolute screen coordinates (0..io.DisplaySize) or natural OS coordinates when using multiple viewport. + IMGUI_API void AlignTextToFramePadding(); // vertically align upcoming text baseline to FramePadding.y so that it will align properly to regularly framed items (call if you have text on a line before a framed item) + IMGUI_API float GetTextLineHeight(); // ~ FontSize + IMGUI_API float GetTextLineHeightWithSpacing(); // ~ FontSize + style.ItemSpacing.y (distance in pixels between 2 consecutive lines of text) + IMGUI_API float GetFrameHeight(); // ~ FontSize + style.FramePadding.y * 2 + IMGUI_API float GetFrameHeightWithSpacing(); // ~ FontSize + style.FramePadding.y * 2 + style.ItemSpacing.y (distance in pixels between 2 consecutive lines of framed widgets) + + // ID stack/scopes + // - Read the FAQ for more details about how ID are handled in dear imgui. If you are creating widgets in a loop you most + // likely want to push a unique identifier (e.g. object pointer, loop index) to uniquely differentiate them. + // - The resulting ID are hashes of the entire stack. + // - You can also use the "Label##foobar" syntax within widget label to distinguish them from each others. + // - In this header file we use the "label"/"name" terminology to denote a string that will be displayed and used as an ID, + // whereas "str_id" denote a string that is only used as an ID and not normally displayed. + IMGUI_API void PushID(const char* str_id); // push string into the ID stack (will hash string). + IMGUI_API void PushID(const char* str_id_begin, const char* str_id_end); // push string into the ID stack (will hash string). + IMGUI_API void PushID(const void* ptr_id); // push pointer into the ID stack (will hash pointer). + IMGUI_API void PushID(int int_id); // push integer into the ID stack (will hash integer). + IMGUI_API void PopID(); // pop from the ID stack. + IMGUI_API ImGuiID GetID(const char* str_id); // calculate unique ID (hash of whole ID stack + given parameter). e.g. if you want to query into ImGuiStorage yourself + IMGUI_API ImGuiID GetID(const char* str_id_begin, const char* str_id_end); + IMGUI_API ImGuiID GetID(const void* ptr_id); + + // Widgets: Text + IMGUI_API void TextUnformatted(const char* text, const char* text_end = NULL); // raw text without formatting. Roughly equivalent to Text("%s", text) but: A) doesn't require null terminated string if 'text_end' is specified, B) it's faster, no memory copy is done, no buffer size limits, recommended for long chunks of text. + IMGUI_API void Text(const char* fmt, ...) IM_FMTARGS(1); // formatted text + IMGUI_API void TextV(const char* fmt, va_list args) IM_FMTLIST(1); + IMGUI_API void TextColored(const ImVec4& col, const char* fmt, ...) IM_FMTARGS(2); // shortcut for PushStyleColor(ImGuiCol_Text, col); Text(fmt, ...); PopStyleColor(); + IMGUI_API void TextColoredV(const ImVec4& col, const char* fmt, va_list args) IM_FMTLIST(2); + IMGUI_API void TextDisabled(const char* fmt, ...) IM_FMTARGS(1); // shortcut for PushStyleColor(ImGuiCol_Text, style.Colors[ImGuiCol_TextDisabled]); Text(fmt, ...); PopStyleColor(); + IMGUI_API void TextDisabledV(const char* fmt, va_list args) IM_FMTLIST(1); + IMGUI_API void TextWrapped(const char* fmt, ...) IM_FMTARGS(1); // shortcut for PushTextWrapPos(0.0f); Text(fmt, ...); PopTextWrapPos();. Note that this won't work on an auto-resizing window if there's no other widgets to extend the window width, yoy may need to set a size using SetNextWindowSize(). + IMGUI_API void TextWrappedV(const char* fmt, va_list args) IM_FMTLIST(1); + IMGUI_API void LabelText(const char* label, const char* fmt, ...) IM_FMTARGS(2); // display text+label aligned the same way as value+label widgets + IMGUI_API void LabelTextV(const char* label, const char* fmt, va_list args) IM_FMTLIST(2); + IMGUI_API void BulletText(const char* fmt, ...) IM_FMTARGS(1); // shortcut for Bullet()+Text() + IMGUI_API void BulletTextV(const char* fmt, va_list args) IM_FMTLIST(1); + + // Widgets: Main + // - Most widgets return true when the value has been changed or when pressed/selected + // - You may also use one of the many IsItemXXX functions (e.g. IsItemActive, IsItemHovered, etc.) to query widget state. + IMGUI_API bool Button(const char* label, const ImVec2& size = ImVec2(0,0)); // button + IMGUI_API bool SmallButton(const char* label); // button with FramePadding=(0,0) to easily embed within text + IMGUI_API bool InvisibleButton(const char* str_id, const ImVec2& size); // button behavior without the visuals, frequently useful to build custom behaviors using the public api (along with IsItemActive, IsItemHovered, etc.) + IMGUI_API bool ArrowButton(const char* str_id, ImGuiDir dir); // square button with an arrow shape + IMGUI_API void Image(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0 = ImVec2(0,0), const ImVec2& uv1 = ImVec2(1,1), const ImVec4& tint_col = ImVec4(1,1,1,1), const ImVec4& border_col = ImVec4(0,0,0,0)); + IMGUI_API bool ImageButton(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0 = ImVec2(0,0), const ImVec2& uv1 = ImVec2(1,1), int frame_padding = -1, const ImVec4& bg_col = ImVec4(0,0,0,0), const ImVec4& tint_col = ImVec4(1,1,1,1)); // <0 frame_padding uses default frame padding settings. 0 for no padding + IMGUI_API bool Checkbox(const char* label, bool* v); + IMGUI_API bool CheckboxFlags(const char* label, unsigned int* flags, unsigned int flags_value); + IMGUI_API bool RadioButton(const char* label, bool active); // use with e.g. if (RadioButton("one", my_value==1)) { my_value = 1; } + IMGUI_API bool RadioButton(const char* label, int* v, int v_button); // shortcut to handle the above pattern when value is an integer + IMGUI_API void ProgressBar(float fraction, const ImVec2& size_arg = ImVec2(-1,0), const char* overlay = NULL); + IMGUI_API void Bullet(); // draw a small circle and keep the cursor on the same line. advance cursor x position by GetTreeNodeToLabelSpacing(), same distance that TreeNode() uses + + // Widgets: Combo Box + // - The BeginCombo()/EndCombo() api allows you to manage your contents and selection state however you want it, by creating e.g. Selectable() items. + // - The old Combo() api are helpers over BeginCombo()/EndCombo() which are kept available for convenience purpose. + IMGUI_API bool BeginCombo(const char* label, const char* preview_value, ImGuiComboFlags flags = 0); + IMGUI_API void EndCombo(); // only call EndCombo() if BeginCombo() returns true! + IMGUI_API bool Combo(const char* label, int* current_item, const char* const items[], int items_count, int popup_max_height_in_items = -1); + IMGUI_API bool Combo(const char* label, int* current_item, const char* items_separated_by_zeros, int popup_max_height_in_items = -1); // Separate items with \0 within a string, end item-list with \0\0. e.g. "One\0Two\0Three\0" + IMGUI_API bool Combo(const char* label, int* current_item, bool(*items_getter)(void* data, int idx, const char** out_text), void* data, int items_count, int popup_max_height_in_items = -1); + + // Widgets: Drags + // - CTRL+Click on any drag box to turn them into an input box. Manually input values aren't clamped and can go off-bounds. + // - For all the Float2/Float3/Float4/Int2/Int3/Int4 versions of every functions, note that a 'float v[X]' function argument is the same as 'float* v', the array syntax is just a way to document the number of elements that are expected to be accessible. You can pass address of your first element out of a contiguous set, e.g. &myvector.x + // - Adjust format string to decorate the value with a prefix, a suffix, or adapt the editing and display precision e.g. "%.3f" -> 1.234; "%5.2f secs" -> 01.23 secs; "Biscuit: %.0f" -> Biscuit: 1; etc. + // - Speed are per-pixel of mouse movement (v_speed=0.2f: mouse needs to move by 5 pixels to increase value by 1). For gamepad/keyboard navigation, minimum speed is Max(v_speed, minimum_step_at_given_precision). + // - Use v_min < v_max to clamp edits to given limits. Note that CTRL+Click manual input can override those limits. + // - Use v_max = FLT_MAX / INT_MAX etc to avoid clamping to a maximum, same with v_min = -FLT_MAX / INT_MIN to avoid clamping to a minimum. + // - Use v_min > v_max to lock edits. + IMGUI_API bool DragFloat(const char* label, float* v, float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* format = "%.3f", float power = 1.0f); // If v_min >= v_max we have no bound + IMGUI_API bool DragFloat2(const char* label, float v[2], float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* format = "%.3f", float power = 1.0f); + IMGUI_API bool DragFloat3(const char* label, float v[3], float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* format = "%.3f", float power = 1.0f); + IMGUI_API bool DragFloat4(const char* label, float v[4], float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* format = "%.3f", float power = 1.0f); + IMGUI_API bool DragFloatRange2(const char* label, float* v_current_min, float* v_current_max, float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* format = "%.3f", const char* format_max = NULL, float power = 1.0f); + IMGUI_API bool DragInt(const char* label, int* v, float v_speed = 1.0f, int v_min = 0, int v_max = 0, const char* format = "%d"); // If v_min >= v_max we have no bound + IMGUI_API bool DragInt2(const char* label, int v[2], float v_speed = 1.0f, int v_min = 0, int v_max = 0, const char* format = "%d"); + IMGUI_API bool DragInt3(const char* label, int v[3], float v_speed = 1.0f, int v_min = 0, int v_max = 0, const char* format = "%d"); + IMGUI_API bool DragInt4(const char* label, int v[4], float v_speed = 1.0f, int v_min = 0, int v_max = 0, const char* format = "%d"); + IMGUI_API bool DragIntRange2(const char* label, int* v_current_min, int* v_current_max, float v_speed = 1.0f, int v_min = 0, int v_max = 0, const char* format = "%d", const char* format_max = NULL); + IMGUI_API bool DragScalar(const char* label, ImGuiDataType data_type, void* p_data, float v_speed, const void* p_min = NULL, const void* p_max = NULL, const char* format = NULL, float power = 1.0f); + IMGUI_API bool DragScalarN(const char* label, ImGuiDataType data_type, void* p_data, int components, float v_speed, const void* p_min = NULL, const void* p_max = NULL, const char* format = NULL, float power = 1.0f); + + // Widgets: Sliders + // - CTRL+Click on any slider to turn them into an input box. Manually input values aren't clamped and can go off-bounds. + // - Adjust format string to decorate the value with a prefix, a suffix, or adapt the editing and display precision e.g. "%.3f" -> 1.234; "%5.2f secs" -> 01.23 secs; "Biscuit: %.0f" -> Biscuit: 1; etc. + IMGUI_API bool SliderFloat(const char* label, float* v, float v_min, float v_max, const char* format = "%.3f", float power = 1.0f); // adjust format to decorate the value with a prefix or a suffix for in-slider labels or unit display. Use power!=1.0 for power curve sliders + IMGUI_API bool SliderFloat2(const char* label, float v[2], float v_min, float v_max, const char* format = "%.3f", float power = 1.0f); + IMGUI_API bool SliderFloat3(const char* label, float v[3], float v_min, float v_max, const char* format = "%.3f", float power = 1.0f); + IMGUI_API bool SliderFloat4(const char* label, float v[4], float v_min, float v_max, const char* format = "%.3f", float power = 1.0f); + IMGUI_API bool SliderAngle(const char* label, float* v_rad, float v_degrees_min = -360.0f, float v_degrees_max = +360.0f, const char* format = "%.0f deg"); + IMGUI_API bool SliderInt(const char* label, int* v, int v_min, int v_max, const char* format = "%d"); + IMGUI_API bool SliderInt2(const char* label, int v[2], int v_min, int v_max, const char* format = "%d"); + IMGUI_API bool SliderInt3(const char* label, int v[3], int v_min, int v_max, const char* format = "%d"); + IMGUI_API bool SliderInt4(const char* label, int v[4], int v_min, int v_max, const char* format = "%d"); + IMGUI_API bool SliderScalar(const char* label, ImGuiDataType data_type, void* p_data, const void* p_min, const void* p_max, const char* format = NULL, float power = 1.0f); + IMGUI_API bool SliderScalarN(const char* label, ImGuiDataType data_type, void* p_data, int components, const void* p_min, const void* p_max, const char* format = NULL, float power = 1.0f); + IMGUI_API bool VSliderFloat(const char* label, const ImVec2& size, float* v, float v_min, float v_max, const char* format = "%.3f", float power = 1.0f); + IMGUI_API bool VSliderInt(const char* label, const ImVec2& size, int* v, int v_min, int v_max, const char* format = "%d"); + IMGUI_API bool VSliderScalar(const char* label, const ImVec2& size, ImGuiDataType data_type, void* p_data, const void* p_min, const void* p_max, const char* format = NULL, float power = 1.0f); + + // Widgets: Input with Keyboard + // - If you want to use InputText() with std::string or any custom dynamic string type, see misc/cpp/imgui_stdlib.h and comments in imgui_demo.cpp. + // - Most of the ImGuiInputTextFlags flags are only useful for InputText() and not for InputFloatX, InputIntX, InputDouble etc. + IMGUI_API bool InputText(const char* label, char* buf, size_t buf_size, ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = NULL, void* user_data = NULL); + IMGUI_API bool InputTextMultiline(const char* label, char* buf, size_t buf_size, const ImVec2& size = ImVec2(0,0), ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = NULL, void* user_data = NULL); + IMGUI_API bool InputTextWithHint(const char* label, const char* hint, char* buf, size_t buf_size, ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = NULL, void* user_data = NULL); + IMGUI_API bool InputFloat(const char* label, float* v, float step = 0.0f, float step_fast = 0.0f, const char* format = "%.3f", ImGuiInputTextFlags flags = 0); + IMGUI_API bool InputFloat2(const char* label, float v[2], const char* format = "%.3f", ImGuiInputTextFlags flags = 0); + IMGUI_API bool InputFloat3(const char* label, float v[3], const char* format = "%.3f", ImGuiInputTextFlags flags = 0); + IMGUI_API bool InputFloat4(const char* label, float v[4], const char* format = "%.3f", ImGuiInputTextFlags flags = 0); + IMGUI_API bool InputInt(const char* label, int* v, int step = 1, int step_fast = 100, ImGuiInputTextFlags flags = 0); + IMGUI_API bool InputInt2(const char* label, int v[2], ImGuiInputTextFlags flags = 0); + IMGUI_API bool InputInt3(const char* label, int v[3], ImGuiInputTextFlags flags = 0); + IMGUI_API bool InputInt4(const char* label, int v[4], ImGuiInputTextFlags flags = 0); + IMGUI_API bool InputDouble(const char* label, double* v, double step = 0.0, double step_fast = 0.0, const char* format = "%.6f", ImGuiInputTextFlags flags = 0); + IMGUI_API bool InputScalar(const char* label, ImGuiDataType data_type, void* p_data, const void* p_step = NULL, const void* p_step_fast = NULL, const char* format = NULL, ImGuiInputTextFlags flags = 0); + IMGUI_API bool InputScalarN(const char* label, ImGuiDataType data_type, void* p_data, int components, const void* p_step = NULL, const void* p_step_fast = NULL, const char* format = NULL, ImGuiInputTextFlags flags = 0); + + // Widgets: Color Editor/Picker (tip: the ColorEdit* functions have a little colored preview square that can be left-clicked to open a picker, and right-clicked to open an option menu.) + // - Note that in C++ a 'float v[X]' function argument is the _same_ as 'float* v', the array syntax is just a way to document the number of elements that are expected to be accessible. + // - You can pass the address of a first float element out of a contiguous structure, e.g. &myvector.x + IMGUI_API bool ColorEdit3(const char* label, float col[3], ImGuiColorEditFlags flags = 0); + IMGUI_API bool ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flags = 0); + IMGUI_API bool ColorPicker3(const char* label, float col[3], ImGuiColorEditFlags flags = 0); + IMGUI_API bool ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags flags = 0, const float* ref_col = NULL); + IMGUI_API bool ColorButton(const char* desc_id, const ImVec4& col, ImGuiColorEditFlags flags = 0, ImVec2 size = ImVec2(0,0)); // display a colored square/button, hover for details, return true when pressed. + IMGUI_API void SetColorEditOptions(ImGuiColorEditFlags flags); // initialize current options (generally on application startup) if you want to select a default format, picker type, etc. User will be able to change many settings, unless you pass the _NoOptions flag to your calls. + + // Widgets: Trees + // - TreeNode functions return true when the node is open, in which case you need to also call TreePop() when you are finished displaying the tree node contents. + IMGUI_API bool TreeNode(const char* label); + IMGUI_API bool TreeNode(const char* str_id, const char* fmt, ...) IM_FMTARGS(2); // helper variation to easily decorelate the id from the displayed string. Read the FAQ about why and how to use ID. to align arbitrary text at the same level as a TreeNode() you can use Bullet(). + IMGUI_API bool TreeNode(const void* ptr_id, const char* fmt, ...) IM_FMTARGS(2); // " + IMGUI_API bool TreeNodeV(const char* str_id, const char* fmt, va_list args) IM_FMTLIST(2); + IMGUI_API bool TreeNodeV(const void* ptr_id, const char* fmt, va_list args) IM_FMTLIST(2); + IMGUI_API bool TreeNodeEx(const char* label, ImGuiTreeNodeFlags flags = 0); + IMGUI_API bool TreeNodeEx(const char* str_id, ImGuiTreeNodeFlags flags, const char* fmt, ...) IM_FMTARGS(3); + IMGUI_API bool TreeNodeEx(const void* ptr_id, ImGuiTreeNodeFlags flags, const char* fmt, ...) IM_FMTARGS(3); + IMGUI_API bool TreeNodeExV(const char* str_id, ImGuiTreeNodeFlags flags, const char* fmt, va_list args) IM_FMTLIST(3); + IMGUI_API bool TreeNodeExV(const void* ptr_id, ImGuiTreeNodeFlags flags, const char* fmt, va_list args) IM_FMTLIST(3); + IMGUI_API void TreePush(const char* str_id); // ~ Indent()+PushId(). Already called by TreeNode() when returning true, but you can call TreePush/TreePop yourself if desired. + IMGUI_API void TreePush(const void* ptr_id = NULL); // " + IMGUI_API void TreePop(); // ~ Unindent()+PopId() + IMGUI_API float GetTreeNodeToLabelSpacing(); // horizontal distance preceding label when using TreeNode*() or Bullet() == (g.FontSize + style.FramePadding.x*2) for a regular unframed TreeNode + IMGUI_API bool CollapsingHeader(const char* label, ImGuiTreeNodeFlags flags = 0); // if returning 'true' the header is open. doesn't indent nor push on ID stack. user doesn't have to call TreePop(). + IMGUI_API bool CollapsingHeader(const char* label, bool* p_open, ImGuiTreeNodeFlags flags = 0); // when 'p_open' isn't NULL, display an additional small close button on upper right of the header + IMGUI_API void SetNextItemOpen(bool is_open, ImGuiCond cond = 0); // set next TreeNode/CollapsingHeader open state. + + // Widgets: Selectables + // - A selectable highlights when hovered, and can display another color when selected. + // - Neighbors selectable extend their highlight bounds in order to leave no gap between them. This is so a series of selected Selectable appear contiguous. + IMGUI_API bool Selectable(const char* label, bool selected = false, ImGuiSelectableFlags flags = 0, const ImVec2& size = ImVec2(0,0)); // "bool selected" carry the selection state (read-only). Selectable() is clicked is returns true so you can modify your selection state. size.x==0.0: use remaining width, size.x>0.0: specify width. size.y==0.0: use label height, size.y>0.0: specify height + IMGUI_API bool Selectable(const char* label, bool* p_selected, ImGuiSelectableFlags flags = 0, const ImVec2& size = ImVec2(0,0)); // "bool* p_selected" point to the selection state (read-write), as a convenient helper. + + // Widgets: List Boxes + // - FIXME: To be consistent with all the newer API, ListBoxHeader/ListBoxFooter should in reality be called BeginListBox/EndListBox. Will rename them. + IMGUI_API bool ListBox(const char* label, int* current_item, const char* const items[], int items_count, int height_in_items = -1); + IMGUI_API bool ListBox(const char* label, int* current_item, bool (*items_getter)(void* data, int idx, const char** out_text), void* data, int items_count, int height_in_items = -1); + IMGUI_API bool ListBoxHeader(const char* label, const ImVec2& size = ImVec2(0,0)); // use if you want to reimplement ListBox() will custom data or interactions. if the function return true, you can output elements then call ListBoxFooter() afterwards. + IMGUI_API bool ListBoxHeader(const char* label, int items_count, int height_in_items = -1); // " + IMGUI_API void ListBoxFooter(); // terminate the scrolling region. only call ListBoxFooter() if ListBoxHeader() returned true! + + // Widgets: Data Plotting + IMGUI_API void PlotLines(const char* label, const float* values, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0, 0), int stride = sizeof(float)); + IMGUI_API void PlotLines(const char* label, float(*values_getter)(void* data, int idx), void* data, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0, 0)); + IMGUI_API void PlotHistogram(const char* label, const float* values, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0, 0), int stride = sizeof(float)); + IMGUI_API void PlotHistogram(const char* label, float(*values_getter)(void* data, int idx), void* data, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0, 0)); + + // Widgets: Value() Helpers. + // - Those are merely shortcut to calling Text() with a format string. Output single value in "name: value" format (tip: freely declare more in your code to handle your types. you can add functions to the ImGui namespace) + IMGUI_API void Value(const char* prefix, bool b); + IMGUI_API void Value(const char* prefix, int v); + IMGUI_API void Value(const char* prefix, unsigned int v); + IMGUI_API void Value(const char* prefix, float v, const char* float_format = NULL); + + // Widgets: Menus + // - Use BeginMenuBar() on a window ImGuiWindowFlags_MenuBar to append to its menu bar. + // - Use BeginMainMenuBar() to create a menu bar at the top of the screen and append to it. + // - Use BeginMenu() to create a menu. You can call BeginMenu() multiple time with the same identifier to append more items to it. + IMGUI_API bool BeginMenuBar(); // append to menu-bar of current window (requires ImGuiWindowFlags_MenuBar flag set on parent window). + IMGUI_API void EndMenuBar(); // only call EndMenuBar() if BeginMenuBar() returns true! + IMGUI_API bool BeginMainMenuBar(); // create and append to a full screen menu-bar. + IMGUI_API void EndMainMenuBar(); // only call EndMainMenuBar() if BeginMainMenuBar() returns true! + IMGUI_API bool BeginMenu(const char* label, bool enabled = true); // create a sub-menu entry. only call EndMenu() if this returns true! + IMGUI_API void EndMenu(); // only call EndMenu() if BeginMenu() returns true! + IMGUI_API bool MenuItem(const char* label, const char* shortcut = NULL, bool selected = false, bool enabled = true); // return true when activated. shortcuts are displayed for convenience but not processed by ImGui at the moment + IMGUI_API bool MenuItem(const char* label, const char* shortcut, bool* p_selected, bool enabled = true); // return true when activated + toggle (*p_selected) if p_selected != NULL + + // Tooltips + // - Tooltip are windows following the mouse which do not take focus away. + IMGUI_API void BeginTooltip(); // begin/append a tooltip window. to create full-featured tooltip (with any kind of items). + IMGUI_API void EndTooltip(); + IMGUI_API void SetTooltip(const char* fmt, ...) IM_FMTARGS(1); // set a text-only tooltip, typically use with ImGui::IsItemHovered(). override any previous call to SetTooltip(). + IMGUI_API void SetTooltipV(const char* fmt, va_list args) IM_FMTLIST(1); + + // Popups, Modals + // The properties of popups windows are: + // - They block normal mouse hovering detection outside them. (*1) + // - Unless modal, they can be closed by clicking anywhere outside them, or by pressing ESCAPE. + // Because hovering detection is disabled outside the popup, when clicking outside the click will not be seen by underlying widgets! (*1) + // - Their visibility state (~bool) is held internally by Dear ImGui instead of being held by the programmer as we are used to with regular Begin() calls. + // User can manipulate the visibility state by calling OpenPopup(), CloseCurrentPopup() etc. + // - We default to use the right mouse (ImGuiMouseButton_Right=1) for the Popup Context functions. + // Those three properties are connected: we need to retain popup visibility state in the library because popups may be closed as any time. + // (*1) You can bypass that restriction and detect hovering even when normally blocked by a popup. + // To do this use the ImGuiHoveredFlags_AllowWhenBlockedByPopup when calling IsItemHovered() or IsWindowHovered(). + // This is what BeginPopupContextItem() and BeginPopupContextWindow() are doing already, allowing a right-click to reopen another popups without losing the click. + IMGUI_API void OpenPopup(const char* str_id); // call to mark popup as open (don't call every frame!). popups are closed when user click outside, or if CloseCurrentPopup() is called within a BeginPopup()/EndPopup() block. By default, Selectable()/MenuItem() are calling CloseCurrentPopup(). Popup identifiers are relative to the current ID-stack (so OpenPopup and BeginPopup needs to be at the same level). + IMGUI_API bool BeginPopup(const char* str_id, ImGuiWindowFlags flags = 0); // return true if the popup is open, and you can start outputting to it. only call EndPopup() if BeginPopup() returns true! + IMGUI_API bool BeginPopupContextItem(const char* str_id = NULL, ImGuiMouseButton mouse_button = 1); // helper to open and begin popup when clicked on last item. if you can pass a NULL str_id only if the previous item had an id. If you want to use that on a non-interactive item such as Text() you need to pass in an explicit ID here. read comments in .cpp! + IMGUI_API bool BeginPopupContextWindow(const char* str_id = NULL, ImGuiMouseButton mouse_button = 1, bool also_over_items = true); // helper to open and begin popup when clicked on current window. + IMGUI_API bool BeginPopupContextVoid(const char* str_id = NULL, ImGuiMouseButton mouse_button = 1); // helper to open and begin popup when clicked in void (where there are no imgui windows). + IMGUI_API bool BeginPopupModal(const char* name, bool* p_open = NULL, ImGuiWindowFlags flags = 0); // modal dialog (regular window with title bar, block interactions behind the modal window, can't close the modal window by clicking outside) + IMGUI_API void EndPopup(); // only call EndPopup() if BeginPopupXXX() returns true! + IMGUI_API bool OpenPopupOnItemClick(const char* str_id = NULL, ImGuiMouseButton mouse_button = 1); // helper to open popup when clicked on last item (note: actually triggers on the mouse _released_ event to be consistent with popup behaviors). return true when just opened. + IMGUI_API bool IsPopupOpen(const char* str_id); // return true if the popup is open at the current begin-ed level of the popup stack. + IMGUI_API void CloseCurrentPopup(); // close the popup we have begin-ed into. clicking on a MenuItem or Selectable automatically close the current popup. + + // Columns + // - You can also use SameLine(pos_x) to mimic simplified columns. + // - The columns API is work-in-progress and rather lacking (columns are arguably the worst part of dear imgui at the moment!) + // - There is a maximum of 64 columns. + // - Currently working on new 'Tables' api which will replace columns around Q2 2020 (see GitHub #2957). + IMGUI_API void Columns(int count = 1, const char* id = NULL, bool border = true); + IMGUI_API void NextColumn(); // next column, defaults to current row or next row if the current row is finished + IMGUI_API int GetColumnIndex(); // get current column index + IMGUI_API float GetColumnWidth(int column_index = -1); // get column width (in pixels). pass -1 to use current column + IMGUI_API void SetColumnWidth(int column_index, float width); // set column width (in pixels). pass -1 to use current column + IMGUI_API float GetColumnOffset(int column_index = -1); // get position of column line (in pixels, from the left side of the contents region). pass -1 to use current column, otherwise 0..GetColumnsCount() inclusive. column 0 is typically 0.0f + IMGUI_API void SetColumnOffset(int column_index, float offset_x); // set position of column line (in pixels, from the left side of the contents region). pass -1 to use current column + IMGUI_API int GetColumnsCount(); + + // Tab Bars, Tabs + // Note: Tabs are automatically created by the docking system. Use this to create tab bars/tabs yourself without docking being involved. + IMGUI_API bool BeginTabBar(const char* str_id, ImGuiTabBarFlags flags = 0); // create and append into a TabBar + IMGUI_API void EndTabBar(); // only call EndTabBar() if BeginTabBar() returns true! + IMGUI_API bool BeginTabItem(const char* label, bool* p_open = NULL, ImGuiTabItemFlags flags = 0);// create a Tab. Returns true if the Tab is selected. + IMGUI_API void EndTabItem(); // only call EndTabItem() if BeginTabItem() returns true! + IMGUI_API void SetTabItemClosed(const char* tab_or_docked_window_label); // notify TabBar or Docking system of a closed tab/window ahead (useful to reduce visual flicker on reorderable tab bars). For tab-bar: call after BeginTabBar() and before Tab submissions. Otherwise call with a window name. + + // Docking + // [BETA API] Enable with io.ConfigFlags |= ImGuiConfigFlags_DockingEnable. + // Note: You can use most Docking facilities without calling any API. You DO NOT need to call DockSpace() to use Docking! + // - To dock windows: if io.ConfigDockingWithShift == false (default) drag window from their title bar. + // - To dock windows: if io.ConfigDockingWithShift == true: hold SHIFT anywhere while moving windows. + // About DockSpace: + // - Use DockSpace() to create an explicit dock node _within_ an existing window. See Docking demo for details. + // - DockSpace() needs to be submitted _before_ any window they can host. If you use a dockspace, submit it early in your app. + IMGUI_API void DockSpace(ImGuiID id, const ImVec2& size = ImVec2(0, 0), ImGuiDockNodeFlags flags = 0, const ImGuiWindowClass* window_class = NULL); + IMGUI_API ImGuiID DockSpaceOverViewport(ImGuiViewport* viewport = NULL, ImGuiDockNodeFlags flags = 0, const ImGuiWindowClass* window_class = NULL); + IMGUI_API void SetNextWindowDockID(ImGuiID dock_id, ImGuiCond cond = 0); // set next window dock id (FIXME-DOCK) + IMGUI_API void SetNextWindowClass(const ImGuiWindowClass* window_class); // set next window class (rare/advanced uses: provide hints to the platform back-end via altered viewport flags and parent/child info) + IMGUI_API ImGuiID GetWindowDockID(); + IMGUI_API bool IsWindowDocked(); // is current window docked into another window? + + // Logging/Capture + // - All text output from the interface can be captured into tty/file/clipboard. By default, tree nodes are automatically opened during logging. + IMGUI_API void LogToTTY(int auto_open_depth = -1); // start logging to tty (stdout) + IMGUI_API void LogToFile(int auto_open_depth = -1, const char* filename = NULL); // start logging to file + IMGUI_API void LogToClipboard(int auto_open_depth = -1); // start logging to OS clipboard + IMGUI_API void LogFinish(); // stop logging (close file, etc.) + IMGUI_API void LogButtons(); // helper to display buttons for logging to tty/file/clipboard + IMGUI_API void LogText(const char* fmt, ...) IM_FMTARGS(1); // pass text data straight to log (without being displayed) + + // Drag and Drop + // - [BETA API] API may evolve! + // - If you stop calling BeginDragDropSource() the payload is preserved however it won't have a preview tooltip (we currently display a fallback "..." tooltip as replacement) + IMGUI_API bool BeginDragDropSource(ImGuiDragDropFlags flags = 0); // call when the current item is active. If this return true, you can call SetDragDropPayload() + EndDragDropSource() + IMGUI_API bool SetDragDropPayload(const char* type, const void* data, size_t sz, ImGuiCond cond = 0); // type is a user defined string of maximum 32 characters. Strings starting with '_' are reserved for dear imgui internal types. Data is copied and held by imgui. + IMGUI_API void EndDragDropSource(); // only call EndDragDropSource() if BeginDragDropSource() returns true! + IMGUI_API bool BeginDragDropTarget(); // call after submitting an item that may receive a payload. If this returns true, you can call AcceptDragDropPayload() + EndDragDropTarget() + IMGUI_API const ImGuiPayload* AcceptDragDropPayload(const char* type, ImGuiDragDropFlags flags = 0); // accept contents of a given type. If ImGuiDragDropFlags_AcceptBeforeDelivery is set you can peek into the payload before the mouse button is released. + IMGUI_API void EndDragDropTarget(); // only call EndDragDropTarget() if BeginDragDropTarget() returns true! + IMGUI_API const ImGuiPayload* GetDragDropPayload(); // peek directly into the current payload from anywhere. may return NULL. use ImGuiPayload::IsDataType() to test for the payload type. + + // Clipping + IMGUI_API void PushClipRect(const ImVec2& clip_rect_min, const ImVec2& clip_rect_max, bool intersect_with_current_clip_rect); + IMGUI_API void PopClipRect(); + + // Focus, Activation + // - Prefer using "SetItemDefaultFocus()" over "if (IsWindowAppearing()) SetScrollHereY()" when applicable to signify "this is the default item" + IMGUI_API void SetItemDefaultFocus(); // make last item the default focused item of a window. + IMGUI_API void SetKeyboardFocusHere(int offset = 0); // focus keyboard on the next widget. Use positive 'offset' to access sub components of a multiple component widget. Use -1 to access previous widget. + + // Item/Widgets Utilities + // - Most of the functions are referring to the last/previous item we submitted. + // - See Demo Window under "Widgets->Querying Status" for an interactive visualization of most of those functions. + IMGUI_API bool IsItemHovered(ImGuiHoveredFlags flags = 0); // is the last item hovered? (and usable, aka not blocked by a popup, etc.). See ImGuiHoveredFlags for more options. + IMGUI_API bool IsItemActive(); // is the last item active? (e.g. button being held, text field being edited. This will continuously return true while holding mouse button on an item. Items that don't interact will always return false) + IMGUI_API bool IsItemFocused(); // is the last item focused for keyboard/gamepad navigation? + IMGUI_API bool IsItemClicked(ImGuiMouseButton mouse_button = 0); // is the last item clicked? (e.g. button/node just clicked on) == IsMouseClicked(mouse_button) && IsItemHovered() + IMGUI_API bool IsItemVisible(); // is the last item visible? (items may be out of sight because of clipping/scrolling) + IMGUI_API bool IsItemEdited(); // did the last item modify its underlying value this frame? or was pressed? This is generally the same as the "bool" return value of many widgets. + IMGUI_API bool IsItemActivated(); // was the last item just made active (item was previously inactive). + IMGUI_API bool IsItemDeactivated(); // was the last item just made inactive (item was previously active). Useful for Undo/Redo patterns with widgets that requires continuous editing. + IMGUI_API bool IsItemDeactivatedAfterEdit(); // was the last item just made inactive and made a value change when it was active? (e.g. Slider/Drag moved). Useful for Undo/Redo patterns with widgets that requires continuous editing. Note that you may get false positives (some widgets such as Combo()/ListBox()/Selectable() will return true even when clicking an already selected item). + IMGUI_API bool IsItemToggledOpen(); // was the last item open state toggled? set by TreeNode(). + IMGUI_API bool IsAnyItemHovered(); // is any item hovered? + IMGUI_API bool IsAnyItemActive(); // is any item active? + IMGUI_API bool IsAnyItemFocused(); // is any item focused? + IMGUI_API ImVec2 GetItemRectMin(); // get upper-left bounding rectangle of the last item (screen space) + IMGUI_API ImVec2 GetItemRectMax(); // get lower-right bounding rectangle of the last item (screen space) + IMGUI_API ImVec2 GetItemRectSize(); // get size of last item + IMGUI_API void SetItemAllowOverlap(); // allow last item to be overlapped by a subsequent item. sometimes useful with invisible buttons, selectables, etc. to catch unused area. + + // Miscellaneous Utilities + IMGUI_API bool IsRectVisible(const ImVec2& size); // test if rectangle (of given size, starting from cursor position) is visible / not clipped. + IMGUI_API bool IsRectVisible(const ImVec2& rect_min, const ImVec2& rect_max); // test if rectangle (in screen space) is visible / not clipped. to perform coarse clipping on user's side. + IMGUI_API double GetTime(); // get global imgui time. incremented by io.DeltaTime every frame. + IMGUI_API int GetFrameCount(); // get global imgui frame count. incremented by 1 every frame. + IMGUI_API ImDrawList* GetBackgroundDrawList(); // get background draw list for the viewport associated to the current window. this draw list will be the first rendering one. Useful to quickly draw shapes/text behind dear imgui contents. + IMGUI_API ImDrawList* GetForegroundDrawList(); // get foreground draw list for the viewport associated to the current window. this draw list will be the last rendered one. Useful to quickly draw shapes/text over dear imgui contents. + IMGUI_API ImDrawList* GetBackgroundDrawList(ImGuiViewport* viewport); // get background draw list for the given viewport. this draw list will be the first rendering one. Useful to quickly draw shapes/text behind dear imgui contents. + IMGUI_API ImDrawList* GetForegroundDrawList(ImGuiViewport* viewport); // get foreground draw list for the given viewport. this draw list will be the last rendered one. Useful to quickly draw shapes/text over dear imgui contents. + IMGUI_API ImDrawListSharedData* GetDrawListSharedData(); // you may use this when creating your own ImDrawList instances. + IMGUI_API const char* GetStyleColorName(ImGuiCol idx); // get a string corresponding to the enum value (for display, saving, etc.). + IMGUI_API void SetStateStorage(ImGuiStorage* storage); // replace current window storage with our own (if you want to manipulate it yourself, typically clear subsection of it) + IMGUI_API ImGuiStorage* GetStateStorage(); + IMGUI_API void CalcListClipping(int items_count, float items_height, int* out_items_display_start, int* out_items_display_end); // calculate coarse clipping for large list of evenly sized items. Prefer using the ImGuiListClipper higher-level helper if you can. + IMGUI_API bool BeginChildFrame(ImGuiID id, const ImVec2& size, ImGuiWindowFlags flags = 0); // helper to create a child window / scrolling region that looks like a normal widget frame + IMGUI_API void EndChildFrame(); // always call EndChildFrame() regardless of BeginChildFrame() return values (which indicates a collapsed/clipped window) + + // Text Utilities + IMGUI_API ImVec2 CalcTextSize(const char* text, const char* text_end = NULL, bool hide_text_after_double_hash = false, float wrap_width = -1.0f); + + // Color Utilities + IMGUI_API ImVec4 ColorConvertU32ToFloat4(ImU32 in); + IMGUI_API ImU32 ColorConvertFloat4ToU32(const ImVec4& in); + IMGUI_API void ColorConvertRGBtoHSV(float r, float g, float b, float& out_h, float& out_s, float& out_v); + IMGUI_API void ColorConvertHSVtoRGB(float h, float s, float v, float& out_r, float& out_g, float& out_b); + + // Inputs Utilities: Keyboard + // - For 'int user_key_index' you can use your own indices/enums according to how your back-end/engine stored them in io.KeysDown[]. + // - We don't know the meaning of those value. You can use GetKeyIndex() to map a ImGuiKey_ value into the user index. + IMGUI_API int GetKeyIndex(ImGuiKey imgui_key); // map ImGuiKey_* values into user's key index. == io.KeyMap[key] + IMGUI_API bool IsKeyDown(int user_key_index); // is key being held. == io.KeysDown[user_key_index]. + IMGUI_API bool IsKeyPressed(int user_key_index, bool repeat = true); // was key pressed (went from !Down to Down)? if repeat=true, uses io.KeyRepeatDelay / KeyRepeatRate + IMGUI_API bool IsKeyReleased(int user_key_index); // was key released (went from Down to !Down)? + IMGUI_API int GetKeyPressedAmount(int key_index, float repeat_delay, float rate); // uses provided repeat rate/delay. return a count, most often 0 or 1 but might be >1 if RepeatRate is small enough that DeltaTime > RepeatRate + IMGUI_API void CaptureKeyboardFromApp(bool want_capture_keyboard_value = true); // attention: misleading name! manually override io.WantCaptureKeyboard flag next frame (said flag is entirely left for your application to handle). e.g. force capture keyboard when your widget is being hovered. This is equivalent to setting "io.WantCaptureKeyboard = want_capture_keyboard_value"; after the next NewFrame() call. + + // Inputs Utilities: Mouse + // - To refer to a mouse button, you may use named enums in your code e.g. ImGuiMouseButton_Left, ImGuiMouseButton_Right. + // - You can also use regular integer: it is forever guaranteed that 0=Left, 1=Right, 2=Middle. + // - Dragging operations are only reported after mouse has moved a certain distance away from the initial clicking position (see 'lock_threshold' and 'io.MouseDraggingThreshold') + IMGUI_API bool IsMouseDown(ImGuiMouseButton button); // is mouse button held? + IMGUI_API bool IsMouseClicked(ImGuiMouseButton button, bool repeat = false); // did mouse button clicked? (went from !Down to Down) + IMGUI_API bool IsMouseReleased(ImGuiMouseButton button); // did mouse button released? (went from Down to !Down) + IMGUI_API bool IsMouseDoubleClicked(ImGuiMouseButton button); // did mouse button double-clicked? a double-click returns false in IsMouseClicked(). uses io.MouseDoubleClickTime. + IMGUI_API bool IsMouseHoveringRect(const ImVec2& r_min, const ImVec2& r_max, bool clip = true);// is mouse hovering given bounding rect (in screen space). clipped by current clipping settings, but disregarding of other consideration of focus/window ordering/popup-block. + IMGUI_API bool IsMousePosValid(const ImVec2* mouse_pos = NULL); // by convention we use (-FLT_MAX,-FLT_MAX) to denote that there is no mouse available + IMGUI_API bool IsAnyMouseDown(); // is any mouse button held? + IMGUI_API ImVec2 GetMousePos(); // shortcut to ImGui::GetIO().MousePos provided by user, to be consistent with other calls + IMGUI_API ImVec2 GetMousePosOnOpeningCurrentPopup(); // retrieve mouse position at the time of opening popup we have BeginPopup() into (helper to avoid user backing that value themselves) + IMGUI_API bool IsMouseDragging(ImGuiMouseButton button, float lock_threshold = -1.0f); // is mouse dragging? (if lock_threshold < -1.0f, uses io.MouseDraggingThreshold) + IMGUI_API ImVec2 GetMouseDragDelta(ImGuiMouseButton button = 0, float lock_threshold = -1.0f); // return the delta from the initial clicking position while the mouse button is pressed or was just released. This is locked and return 0.0f until the mouse moves past a distance threshold at least once (if lock_threshold < -1.0f, uses io.MouseDraggingThreshold) + IMGUI_API void ResetMouseDragDelta(ImGuiMouseButton button = 0); // + IMGUI_API ImGuiMouseCursor GetMouseCursor(); // get desired cursor type, reset in ImGui::NewFrame(), this is updated during the frame. valid before Render(). If you use software rendering by setting io.MouseDrawCursor ImGui will render those for you + IMGUI_API void SetMouseCursor(ImGuiMouseCursor cursor_type); // set desired cursor type + IMGUI_API void CaptureMouseFromApp(bool want_capture_mouse_value = true); // attention: misleading name! manually override io.WantCaptureMouse flag next frame (said flag is entirely left for your application to handle). This is equivalent to setting "io.WantCaptureMouse = want_capture_mouse_value;" after the next NewFrame() call. + + // Clipboard Utilities + // - Also see the LogToClipboard() function to capture GUI into clipboard, or easily output text data to the clipboard. + IMGUI_API const char* GetClipboardText(); + IMGUI_API void SetClipboardText(const char* text); + + // Settings/.Ini Utilities + // - The disk functions are automatically called if io.IniFilename != NULL (default is "imgui.ini"). + // - Set io.IniFilename to NULL to load/save manually. Read io.WantSaveIniSettings description about handling .ini saving manually. + IMGUI_API void LoadIniSettingsFromDisk(const char* ini_filename); // call after CreateContext() and before the first call to NewFrame(). NewFrame() automatically calls LoadIniSettingsFromDisk(io.IniFilename). + IMGUI_API void LoadIniSettingsFromMemory(const char* ini_data, size_t ini_size=0); // call after CreateContext() and before the first call to NewFrame() to provide .ini data from your own data source. + IMGUI_API void SaveIniSettingsToDisk(const char* ini_filename); // this is automatically called (if io.IniFilename is not empty) a few seconds after any modification that should be reflected in the .ini file (and also by DestroyContext). + IMGUI_API const char* SaveIniSettingsToMemory(size_t* out_ini_size = NULL); // return a zero-terminated string with the .ini data which you can save by your own mean. call when io.WantSaveIniSettings is set, then save data by your own mean and clear io.WantSaveIniSettings. + + // Debug Utilities + IMGUI_API bool DebugCheckVersionAndDataLayout(const char* version_str, size_t sz_io, size_t sz_style, size_t sz_vec2, size_t sz_vec4, size_t sz_drawvert, size_t sz_drawidx); // This is called by IMGUI_CHECKVERSION() macro. + + // Memory Allocators + // - All those functions are not reliant on the current context. + // - If you reload the contents of imgui.cpp at runtime, you may need to call SetCurrentContext() + SetAllocatorFunctions() again because we use global storage for those. + IMGUI_API void SetAllocatorFunctions(void* (*alloc_func)(size_t sz, void* user_data), void (*free_func)(void* ptr, void* user_data), void* user_data = NULL); + IMGUI_API void* MemAlloc(size_t size); + IMGUI_API void MemFree(void* ptr); + + // (Optional) Platform/OS interface for multi-viewport support + // Read comments around the ImGuiPlatformIO structure for more details. + // Note: You may use GetWindowViewport() to get the current viewport of the current window. + IMGUI_API ImGuiPlatformIO& GetPlatformIO(); // platform/renderer functions, for back-end to setup + viewports list. + IMGUI_API ImGuiViewport* GetMainViewport(); // main viewport. same as GetPlatformIO().MainViewport == GetPlatformIO().Viewports[0]. + IMGUI_API void UpdatePlatformWindows(); // call in main loop. will call CreateWindow/ResizeWindow/etc. platform functions for each secondary viewport, and DestroyWindow for each inactive viewport. + IMGUI_API void RenderPlatformWindowsDefault(void* platform_render_arg = NULL, void* renderer_render_arg = NULL); // call in main loop. will call RenderWindow/SwapBuffers platform functions for each secondary viewport which doesn't have the ImGuiViewportFlags_Minimized flag set. May be reimplemented by user for custom rendering needs. + IMGUI_API void DestroyPlatformWindows(); // call DestroyWindow platform functions for all viewports. call from back-end Shutdown() if you need to close platform windows before imgui shutdown. otherwise will be called by DestroyContext(). + IMGUI_API ImGuiViewport* FindViewportByID(ImGuiID id); // this is a helper for back-ends. + IMGUI_API ImGuiViewport* FindViewportByPlatformHandle(void* platform_handle); // this is a helper for back-ends. the type platform_handle is decided by the back-end (e.g. HWND, MyWindow*, GLFWwindow* etc.) + +} // namespace ImGui + +//----------------------------------------------------------------------------- +// Flags & Enumerations +//----------------------------------------------------------------------------- + +// Flags for ImGui::Begin() +enum ImGuiWindowFlags_ +{ + ImGuiWindowFlags_None = 0, + ImGuiWindowFlags_NoTitleBar = 1 << 0, // Disable title-bar + ImGuiWindowFlags_NoResize = 1 << 1, // Disable user resizing with the lower-right grip + ImGuiWindowFlags_NoMove = 1 << 2, // Disable user moving the window + ImGuiWindowFlags_NoScrollbar = 1 << 3, // Disable scrollbars (window can still scroll with mouse or programmatically) + ImGuiWindowFlags_NoScrollWithMouse = 1 << 4, // Disable user vertically scrolling with mouse wheel. On child window, mouse wheel will be forwarded to the parent unless NoScrollbar is also set. + ImGuiWindowFlags_NoCollapse = 1 << 5, // Disable user collapsing window by double-clicking on it. Also referred to as "window menu button" within a docking node. + ImGuiWindowFlags_AlwaysAutoResize = 1 << 6, // Resize every window to its content every frame + ImGuiWindowFlags_NoBackground = 1 << 7, // Disable drawing background color (WindowBg, etc.) and outside border. Similar as using SetNextWindowBgAlpha(0.0f). + ImGuiWindowFlags_NoSavedSettings = 1 << 8, // Never load/save settings in .ini file + ImGuiWindowFlags_NoMouseInputs = 1 << 9, // Disable catching mouse, hovering test with pass through. + ImGuiWindowFlags_MenuBar = 1 << 10, // Has a menu-bar + ImGuiWindowFlags_HorizontalScrollbar = 1 << 11, // Allow horizontal scrollbar to appear (off by default). You may use SetNextWindowContentSize(ImVec2(width,0.0f)); prior to calling Begin() to specify width. Read code in imgui_demo in the "Horizontal Scrolling" section. + ImGuiWindowFlags_NoFocusOnAppearing = 1 << 12, // Disable taking focus when transitioning from hidden to visible state + ImGuiWindowFlags_NoBringToFrontOnFocus = 1 << 13, // Disable bringing window to front when taking focus (e.g. clicking on it or programmatically giving it focus) + ImGuiWindowFlags_AlwaysVerticalScrollbar= 1 << 14, // Always show vertical scrollbar (even if ContentSize.y < Size.y) + ImGuiWindowFlags_AlwaysHorizontalScrollbar=1<< 15, // Always show horizontal scrollbar (even if ContentSize.x < Size.x) + ImGuiWindowFlags_AlwaysUseWindowPadding = 1 << 16, // Ensure child windows without border uses style.WindowPadding (ignored by default for non-bordered child windows, because more convenient) + ImGuiWindowFlags_NoNavInputs = 1 << 18, // No gamepad/keyboard navigation within the window + ImGuiWindowFlags_NoNavFocus = 1 << 19, // No focusing toward this window with gamepad/keyboard navigation (e.g. skipped by CTRL+TAB) + ImGuiWindowFlags_UnsavedDocument = 1 << 20, // Append '*' to title without affecting the ID, as a convenience to avoid using the ### operator. When used in a tab/docking context, tab is selected on closure and closure is deferred by one frame to allow code to cancel the closure (with a confirmation popup, etc.) without flicker. + ImGuiWindowFlags_NoDocking = 1 << 21, // Disable docking of this window + + ImGuiWindowFlags_NoNav = ImGuiWindowFlags_NoNavInputs | ImGuiWindowFlags_NoNavFocus, + ImGuiWindowFlags_NoDecoration = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoCollapse, + ImGuiWindowFlags_NoInputs = ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_NoNavInputs | ImGuiWindowFlags_NoNavFocus, + + // [Internal] + ImGuiWindowFlags_NavFlattened = 1 << 23, // [BETA] Allow gamepad/keyboard navigation to cross over parent border to this child (only use on child that have no scrolling!) + ImGuiWindowFlags_ChildWindow = 1 << 24, // Don't use! For internal use by BeginChild() + ImGuiWindowFlags_Tooltip = 1 << 25, // Don't use! For internal use by BeginTooltip() + ImGuiWindowFlags_Popup = 1 << 26, // Don't use! For internal use by BeginPopup() + ImGuiWindowFlags_Modal = 1 << 27, // Don't use! For internal use by BeginPopupModal() + ImGuiWindowFlags_ChildMenu = 1 << 28, // Don't use! For internal use by BeginMenu() + ImGuiWindowFlags_DockNodeHost = 1 << 29 // Don't use! For internal use by Begin()/NewFrame() + + // [Obsolete] + //ImGuiWindowFlags_ShowBorders = 1 << 7, // --> Set style.FrameBorderSize=1.0f or style.WindowBorderSize=1.0f to enable borders around items or windows. + //ImGuiWindowFlags_ResizeFromAnySide = 1 << 17, // --> Set io.ConfigWindowsResizeFromEdges=true and make sure mouse cursors are supported by back-end (io.BackendFlags & ImGuiBackendFlags_HasMouseCursors) +}; + +// Flags for ImGui::InputText() +enum ImGuiInputTextFlags_ +{ + ImGuiInputTextFlags_None = 0, + ImGuiInputTextFlags_CharsDecimal = 1 << 0, // Allow 0123456789.+-*/ + ImGuiInputTextFlags_CharsHexadecimal = 1 << 1, // Allow 0123456789ABCDEFabcdef + ImGuiInputTextFlags_CharsUppercase = 1 << 2, // Turn a..z into A..Z + ImGuiInputTextFlags_CharsNoBlank = 1 << 3, // Filter out spaces, tabs + ImGuiInputTextFlags_AutoSelectAll = 1 << 4, // Select entire text when first taking mouse focus + ImGuiInputTextFlags_EnterReturnsTrue = 1 << 5, // Return 'true' when Enter is pressed (as opposed to every time the value was modified). Consider looking at the IsItemDeactivatedAfterEdit() function. + ImGuiInputTextFlags_CallbackCompletion = 1 << 6, // Callback on pressing TAB (for completion handling) + ImGuiInputTextFlags_CallbackHistory = 1 << 7, // Callback on pressing Up/Down arrows (for history handling) + ImGuiInputTextFlags_CallbackAlways = 1 << 8, // Callback on each iteration. User code may query cursor position, modify text buffer. + ImGuiInputTextFlags_CallbackCharFilter = 1 << 9, // Callback on character inputs to replace or discard them. Modify 'EventChar' to replace or discard, or return 1 in callback to discard. + ImGuiInputTextFlags_AllowTabInput = 1 << 10, // Pressing TAB input a '\t' character into the text field + ImGuiInputTextFlags_CtrlEnterForNewLine = 1 << 11, // In multi-line mode, unfocus with Enter, add new line with Ctrl+Enter (default is opposite: unfocus with Ctrl+Enter, add line with Enter). + ImGuiInputTextFlags_NoHorizontalScroll = 1 << 12, // Disable following the cursor horizontally + ImGuiInputTextFlags_AlwaysInsertMode = 1 << 13, // Insert mode + ImGuiInputTextFlags_ReadOnly = 1 << 14, // Read-only mode + ImGuiInputTextFlags_Password = 1 << 15, // Password mode, display all characters as '*' + ImGuiInputTextFlags_NoUndoRedo = 1 << 16, // Disable undo/redo. Note that input text owns the text data while active, if you want to provide your own undo/redo stack you need e.g. to call ClearActiveID(). + ImGuiInputTextFlags_CharsScientific = 1 << 17, // Allow 0123456789.+-*/eE (Scientific notation input) + ImGuiInputTextFlags_CallbackResize = 1 << 18, // Callback on buffer capacity changes request (beyond 'buf_size' parameter value), allowing the string to grow. Notify when the string wants to be resized (for string types which hold a cache of their Size). You will be provided a new BufSize in the callback and NEED to honor it. (see misc/cpp/imgui_stdlib.h for an example of using this) + // [Internal] + ImGuiInputTextFlags_Multiline = 1 << 20, // For internal use by InputTextMultiline() + ImGuiInputTextFlags_NoMarkEdited = 1 << 21 // For internal use by functions using InputText() before reformatting data +}; + +// Flags for ImGui::TreeNodeEx(), ImGui::CollapsingHeader*() +enum ImGuiTreeNodeFlags_ +{ + ImGuiTreeNodeFlags_None = 0, + ImGuiTreeNodeFlags_Selected = 1 << 0, // Draw as selected + ImGuiTreeNodeFlags_Framed = 1 << 1, // Full colored frame (e.g. for CollapsingHeader) + ImGuiTreeNodeFlags_AllowItemOverlap = 1 << 2, // Hit testing to allow subsequent widgets to overlap this one + ImGuiTreeNodeFlags_NoTreePushOnOpen = 1 << 3, // Don't do a TreePush() when open (e.g. for CollapsingHeader) = no extra indent nor pushing on ID stack + ImGuiTreeNodeFlags_NoAutoOpenOnLog = 1 << 4, // Don't automatically and temporarily open node when Logging is active (by default logging will automatically open tree nodes) + ImGuiTreeNodeFlags_DefaultOpen = 1 << 5, // Default node to be open + ImGuiTreeNodeFlags_OpenOnDoubleClick = 1 << 6, // Need double-click to open node + ImGuiTreeNodeFlags_OpenOnArrow = 1 << 7, // Only open when clicking on the arrow part. If ImGuiTreeNodeFlags_OpenOnDoubleClick is also set, single-click arrow or double-click all box to open. + ImGuiTreeNodeFlags_Leaf = 1 << 8, // No collapsing, no arrow (use as a convenience for leaf nodes). + ImGuiTreeNodeFlags_Bullet = 1 << 9, // Display a bullet instead of arrow + ImGuiTreeNodeFlags_FramePadding = 1 << 10, // Use FramePadding (even for an unframed text node) to vertically align text baseline to regular widget height. Equivalent to calling AlignTextToFramePadding(). + ImGuiTreeNodeFlags_SpanAvailWidth = 1 << 11, // Extend hit box to the right-most edge, even if not framed. This is not the default in order to allow adding other items on the same line. In the future we may refactor the hit system to be front-to-back, allowing natural overlaps and then this can become the default. + ImGuiTreeNodeFlags_SpanFullWidth = 1 << 12, // Extend hit box to the left-most and right-most edges (bypass the indented area). + ImGuiTreeNodeFlags_NavLeftJumpsBackHere = 1 << 13, // (WIP) Nav: left direction may move to this TreeNode() from any of its child (items submitted between TreeNode and TreePop) + //ImGuiTreeNodeFlags_NoScrollOnOpen = 1 << 14, // FIXME: TODO: Disable automatic scroll on TreePop() if node got just open and contents is not visible + ImGuiTreeNodeFlags_CollapsingHeader = ImGuiTreeNodeFlags_Framed | ImGuiTreeNodeFlags_NoTreePushOnOpen | ImGuiTreeNodeFlags_NoAutoOpenOnLog +}; + +// Flags for ImGui::Selectable() +enum ImGuiSelectableFlags_ +{ + ImGuiSelectableFlags_None = 0, + ImGuiSelectableFlags_DontClosePopups = 1 << 0, // Clicking this don't close parent popup window + ImGuiSelectableFlags_SpanAllColumns = 1 << 1, // Selectable frame can span all columns (text will still fit in current column) + ImGuiSelectableFlags_AllowDoubleClick = 1 << 2, // Generate press events on double clicks too + ImGuiSelectableFlags_Disabled = 1 << 3, // Cannot be selected, display grayed out text + ImGuiSelectableFlags_AllowItemOverlap = 1 << 4 // (WIP) Hit testing to allow subsequent widgets to overlap this one +}; + +// Flags for ImGui::BeginCombo() +enum ImGuiComboFlags_ +{ + ImGuiComboFlags_None = 0, + ImGuiComboFlags_PopupAlignLeft = 1 << 0, // Align the popup toward the left by default + ImGuiComboFlags_HeightSmall = 1 << 1, // Max ~4 items visible. Tip: If you want your combo popup to be a specific size you can use SetNextWindowSizeConstraints() prior to calling BeginCombo() + ImGuiComboFlags_HeightRegular = 1 << 2, // Max ~8 items visible (default) + ImGuiComboFlags_HeightLarge = 1 << 3, // Max ~20 items visible + ImGuiComboFlags_HeightLargest = 1 << 4, // As many fitting items as possible + ImGuiComboFlags_NoArrowButton = 1 << 5, // Display on the preview box without the square arrow button + ImGuiComboFlags_NoPreview = 1 << 6, // Display only a square arrow button + ImGuiComboFlags_HeightMask_ = ImGuiComboFlags_HeightSmall | ImGuiComboFlags_HeightRegular | ImGuiComboFlags_HeightLarge | ImGuiComboFlags_HeightLargest +}; + +// Flags for ImGui::BeginTabBar() +enum ImGuiTabBarFlags_ +{ + ImGuiTabBarFlags_None = 0, + ImGuiTabBarFlags_Reorderable = 1 << 0, // Allow manually dragging tabs to re-order them + New tabs are appended at the end of list + ImGuiTabBarFlags_AutoSelectNewTabs = 1 << 1, // Automatically select new tabs when they appear + ImGuiTabBarFlags_TabListPopupButton = 1 << 2, // Disable buttons to open the tab list popup + ImGuiTabBarFlags_NoCloseWithMiddleMouseButton = 1 << 3, // Disable behavior of closing tabs (that are submitted with p_open != NULL) with middle mouse button. You can still repro this behavior on user's side with if (IsItemHovered() && IsMouseClicked(2)) *p_open = false. + ImGuiTabBarFlags_NoTabListScrollingButtons = 1 << 4, // Disable scrolling buttons (apply when fitting policy is ImGuiTabBarFlags_FittingPolicyScroll) + ImGuiTabBarFlags_NoTooltip = 1 << 5, // Disable tooltips when hovering a tab + ImGuiTabBarFlags_FittingPolicyResizeDown = 1 << 6, // Resize tabs when they don't fit + ImGuiTabBarFlags_FittingPolicyScroll = 1 << 7, // Add scroll buttons when tabs don't fit + ImGuiTabBarFlags_FittingPolicyMask_ = ImGuiTabBarFlags_FittingPolicyResizeDown | ImGuiTabBarFlags_FittingPolicyScroll, + ImGuiTabBarFlags_FittingPolicyDefault_ = ImGuiTabBarFlags_FittingPolicyResizeDown +}; + +// Flags for ImGui::BeginTabItem() +enum ImGuiTabItemFlags_ +{ + ImGuiTabItemFlags_None = 0, + ImGuiTabItemFlags_UnsavedDocument = 1 << 0, // Append '*' to title without affecting the ID, as a convenience to avoid using the ### operator. Also: tab is selected on closure and closure is deferred by one frame to allow code to undo it without flicker. + ImGuiTabItemFlags_SetSelected = 1 << 1, // Trigger flag to programmatically make the tab selected when calling BeginTabItem() + ImGuiTabItemFlags_NoCloseWithMiddleMouseButton = 1 << 2, // Disable behavior of closing tabs (that are submitted with p_open != NULL) with middle mouse button. You can still repro this behavior on user's side with if (IsItemHovered() && IsMouseClicked(2)) *p_open = false. + ImGuiTabItemFlags_NoPushId = 1 << 3 // Don't call PushID(tab->ID)/PopID() on BeginTabItem()/EndTabItem() +}; + +// Flags for ImGui::IsWindowFocused() +enum ImGuiFocusedFlags_ +{ + ImGuiFocusedFlags_None = 0, + ImGuiFocusedFlags_ChildWindows = 1 << 0, // IsWindowFocused(): Return true if any children of the window is focused + ImGuiFocusedFlags_RootWindow = 1 << 1, // IsWindowFocused(): Test from root window (top most parent of the current hierarchy) + ImGuiFocusedFlags_AnyWindow = 1 << 2, // IsWindowFocused(): Return true if any window is focused. Important: If you are trying to tell how to dispatch your low-level inputs, do NOT use this. Use 'io.WantCaptureMouse' instead! Please read the FAQ! + ImGuiFocusedFlags_RootAndChildWindows = ImGuiFocusedFlags_RootWindow | ImGuiFocusedFlags_ChildWindows +}; + +// Flags for ImGui::IsItemHovered(), ImGui::IsWindowHovered() +// Note: if you are trying to check whether your mouse should be dispatched to Dear ImGui or to your app, you should use 'io.WantCaptureMouse' instead! Please read the FAQ! +// Note: windows with the ImGuiWindowFlags_NoInputs flag are ignored by IsWindowHovered() calls. +enum ImGuiHoveredFlags_ +{ + ImGuiHoveredFlags_None = 0, // Return true if directly over the item/window, not obstructed by another window, not obstructed by an active popup or modal blocking inputs under them. + ImGuiHoveredFlags_ChildWindows = 1 << 0, // IsWindowHovered() only: Return true if any children of the window is hovered + ImGuiHoveredFlags_RootWindow = 1 << 1, // IsWindowHovered() only: Test from root window (top most parent of the current hierarchy) + ImGuiHoveredFlags_AnyWindow = 1 << 2, // IsWindowHovered() only: Return true if any window is hovered + ImGuiHoveredFlags_AllowWhenBlockedByPopup = 1 << 3, // Return true even if a popup window is normally blocking access to this item/window + //ImGuiHoveredFlags_AllowWhenBlockedByModal = 1 << 4, // Return true even if a modal popup window is normally blocking access to this item/window. FIXME-TODO: Unavailable yet. + ImGuiHoveredFlags_AllowWhenBlockedByActiveItem = 1 << 5, // Return true even if an active item is blocking access to this item/window. Useful for Drag and Drop patterns. + ImGuiHoveredFlags_AllowWhenOverlapped = 1 << 6, // Return true even if the position is obstructed or overlapped by another window + ImGuiHoveredFlags_AllowWhenDisabled = 1 << 7, // Return true even if the item is disabled + ImGuiHoveredFlags_RectOnly = ImGuiHoveredFlags_AllowWhenBlockedByPopup | ImGuiHoveredFlags_AllowWhenBlockedByActiveItem | ImGuiHoveredFlags_AllowWhenOverlapped, + ImGuiHoveredFlags_RootAndChildWindows = ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_ChildWindows +}; + +// Flags for ImGui::DockSpace(), shared/inherited by child nodes. +// (Some flags can be applied to individual nodes directly) +// FIXME-DOCK: Also see ImGuiDockNodeFlagsPrivate_ which may involve using the WIP and internal DockBuilder api. +enum ImGuiDockNodeFlags_ +{ + ImGuiDockNodeFlags_None = 0, + ImGuiDockNodeFlags_KeepAliveOnly = 1 << 0, // Shared // Don't display the dockspace node but keep it alive. Windows docked into this dockspace node won't be undocked. + //ImGuiDockNodeFlags_NoCentralNode = 1 << 1, // Shared // Disable Central Node (the node which can stay empty) + ImGuiDockNodeFlags_NoDockingInCentralNode = 1 << 2, // Shared // Disable docking inside the Central Node, which will be always kept empty. + ImGuiDockNodeFlags_PassthruCentralNode = 1 << 3, // Shared // Enable passthru dockspace: 1) DockSpace() will render a ImGuiCol_WindowBg background covering everything excepted the Central Node when empty. Meaning the host window should probably use SetNextWindowBgAlpha(0.0f) prior to Begin() when using this. 2) When Central Node is empty: let inputs pass-through + won't display a DockingEmptyBg background. See demo for details. + ImGuiDockNodeFlags_NoSplit = 1 << 4, // Shared/Local // Disable splitting the node into smaller nodes. Useful e.g. when embedding dockspaces into a main root one (the root one may have splitting disabled to reduce confusion). Note: when turned off, existing splits will be preserved. + ImGuiDockNodeFlags_NoResize = 1 << 5, // Shared/Local // Disable resizing node using the splitter/separators. Useful with programatically setup dockspaces. + ImGuiDockNodeFlags_AutoHideTabBar = 1 << 6 // Shared/Local // Tab bar will automatically hide when there is a single window in the dock node. +}; + +// Flags for ImGui::BeginDragDropSource(), ImGui::AcceptDragDropPayload() +enum ImGuiDragDropFlags_ +{ + ImGuiDragDropFlags_None = 0, + // BeginDragDropSource() flags + ImGuiDragDropFlags_SourceNoPreviewTooltip = 1 << 0, // By default, a successful call to BeginDragDropSource opens a tooltip so you can display a preview or description of the source contents. This flag disable this behavior. + ImGuiDragDropFlags_SourceNoDisableHover = 1 << 1, // By default, when dragging we clear data so that IsItemHovered() will return false, to avoid subsequent user code submitting tooltips. This flag disable this behavior so you can still call IsItemHovered() on the source item. + ImGuiDragDropFlags_SourceNoHoldToOpenOthers = 1 << 2, // Disable the behavior that allows to open tree nodes and collapsing header by holding over them while dragging a source item. + ImGuiDragDropFlags_SourceAllowNullID = 1 << 3, // Allow items such as Text(), Image() that have no unique identifier to be used as drag source, by manufacturing a temporary identifier based on their window-relative position. This is extremely unusual within the dear imgui ecosystem and so we made it explicit. + ImGuiDragDropFlags_SourceExtern = 1 << 4, // External source (from outside of dear imgui), won't attempt to read current item/window info. Will always return true. Only one Extern source can be active simultaneously. + ImGuiDragDropFlags_SourceAutoExpirePayload = 1 << 5, // Automatically expire the payload if the source cease to be submitted (otherwise payloads are persisting while being dragged) + // AcceptDragDropPayload() flags + ImGuiDragDropFlags_AcceptBeforeDelivery = 1 << 10, // AcceptDragDropPayload() will returns true even before the mouse button is released. You can then call IsDelivery() to test if the payload needs to be delivered. + ImGuiDragDropFlags_AcceptNoDrawDefaultRect = 1 << 11, // Do not draw the default highlight rectangle when hovering over target. + ImGuiDragDropFlags_AcceptNoPreviewTooltip = 1 << 12, // Request hiding the BeginDragDropSource tooltip from the BeginDragDropTarget site. + ImGuiDragDropFlags_AcceptPeekOnly = ImGuiDragDropFlags_AcceptBeforeDelivery | ImGuiDragDropFlags_AcceptNoDrawDefaultRect // For peeking ahead and inspecting the payload before delivery. +}; + +// Standard Drag and Drop payload types. You can define you own payload types using short strings. Types starting with '_' are defined by Dear ImGui. +#define IMGUI_PAYLOAD_TYPE_COLOR_3F "_COL3F" // float[3]: Standard type for colors, without alpha. User code may use this type. +#define IMGUI_PAYLOAD_TYPE_COLOR_4F "_COL4F" // float[4]: Standard type for colors. User code may use this type. + +// A primary data type +enum ImGuiDataType_ +{ + ImGuiDataType_S8, // signed char / char (with sensible compilers) + ImGuiDataType_U8, // unsigned char + ImGuiDataType_S16, // short + ImGuiDataType_U16, // unsigned short + ImGuiDataType_S32, // int + ImGuiDataType_U32, // unsigned int + ImGuiDataType_S64, // long long / __int64 + ImGuiDataType_U64, // unsigned long long / unsigned __int64 + ImGuiDataType_Float, // float + ImGuiDataType_Double, // double + ImGuiDataType_COUNT +}; + +// A cardinal direction +enum ImGuiDir_ +{ + ImGuiDir_None = -1, + ImGuiDir_Left = 0, + ImGuiDir_Right = 1, + ImGuiDir_Up = 2, + ImGuiDir_Down = 3, + ImGuiDir_COUNT +}; + +// User fill ImGuiIO.KeyMap[] array with indices into the ImGuiIO.KeysDown[512] array +enum ImGuiKey_ +{ + ImGuiKey_Tab, + ImGuiKey_LeftArrow, + ImGuiKey_RightArrow, + ImGuiKey_UpArrow, + ImGuiKey_DownArrow, + ImGuiKey_PageUp, + ImGuiKey_PageDown, + ImGuiKey_Home, + ImGuiKey_End, + ImGuiKey_Insert, + ImGuiKey_Delete, + ImGuiKey_Backspace, + ImGuiKey_Space, + ImGuiKey_Enter, + ImGuiKey_Escape, + ImGuiKey_KeyPadEnter, + ImGuiKey_A, // for text edit CTRL+A: select all + ImGuiKey_C, // for text edit CTRL+C: copy + ImGuiKey_V, // for text edit CTRL+V: paste + ImGuiKey_X, // for text edit CTRL+X: cut + ImGuiKey_Y, // for text edit CTRL+Y: redo + ImGuiKey_Z, // for text edit CTRL+Z: undo + ImGuiKey_COUNT +}; + +// To test io.KeyMods (which is a combination of individual fields io.KeyCtrl, io.KeyShift, io.KeyAlt set by user/back-end) +enum ImGuiKeyModFlags_ +{ + ImGuiKeyModFlags_None = 0, + ImGuiKeyModFlags_Ctrl = 1 << 0, + ImGuiKeyModFlags_Shift = 1 << 1, + ImGuiKeyModFlags_Alt = 1 << 2, + ImGuiKeyModFlags_Super = 1 << 3 +}; + +// Gamepad/Keyboard navigation +// Keyboard: Set io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard to enable. NewFrame() will automatically fill io.NavInputs[] based on your io.KeysDown[] + io.KeyMap[] arrays. +// Gamepad: Set io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad to enable. Back-end: set ImGuiBackendFlags_HasGamepad and fill the io.NavInputs[] fields before calling NewFrame(). Note that io.NavInputs[] is cleared by EndFrame(). +// Read instructions in imgui.cpp for more details. Download PNG/PSD at http://goo.gl/9LgVZW. +enum ImGuiNavInput_ +{ + // Gamepad Mapping + ImGuiNavInput_Activate, // activate / open / toggle / tweak value // e.g. Cross (PS4), A (Xbox), A (Switch), Space (Keyboard) + ImGuiNavInput_Cancel, // cancel / close / exit // e.g. Circle (PS4), B (Xbox), B (Switch), Escape (Keyboard) + ImGuiNavInput_Input, // text input / on-screen keyboard // e.g. Triang.(PS4), Y (Xbox), X (Switch), Return (Keyboard) + ImGuiNavInput_Menu, // tap: toggle menu / hold: focus, move, resize // e.g. Square (PS4), X (Xbox), Y (Switch), Alt (Keyboard) + ImGuiNavInput_DpadLeft, // move / tweak / resize window (w/ PadMenu) // e.g. D-pad Left/Right/Up/Down (Gamepads), Arrow keys (Keyboard) + ImGuiNavInput_DpadRight, // + ImGuiNavInput_DpadUp, // + ImGuiNavInput_DpadDown, // + ImGuiNavInput_LStickLeft, // scroll / move window (w/ PadMenu) // e.g. Left Analog Stick Left/Right/Up/Down + ImGuiNavInput_LStickRight, // + ImGuiNavInput_LStickUp, // + ImGuiNavInput_LStickDown, // + ImGuiNavInput_FocusPrev, // next window (w/ PadMenu) // e.g. L1 or L2 (PS4), LB or LT (Xbox), L or ZL (Switch) + ImGuiNavInput_FocusNext, // prev window (w/ PadMenu) // e.g. R1 or R2 (PS4), RB or RT (Xbox), R or ZL (Switch) + ImGuiNavInput_TweakSlow, // slower tweaks // e.g. L1 or L2 (PS4), LB or LT (Xbox), L or ZL (Switch) + ImGuiNavInput_TweakFast, // faster tweaks // e.g. R1 or R2 (PS4), RB or RT (Xbox), R or ZL (Switch) + + // [Internal] Don't use directly! This is used internally to differentiate keyboard from gamepad inputs for behaviors that require to differentiate them. + // Keyboard behavior that have no corresponding gamepad mapping (e.g. CTRL+TAB) will be directly reading from io.KeysDown[] instead of io.NavInputs[]. + ImGuiNavInput_KeyMenu_, // toggle menu // = io.KeyAlt + ImGuiNavInput_KeyLeft_, // move left // = Arrow keys + ImGuiNavInput_KeyRight_, // move right + ImGuiNavInput_KeyUp_, // move up + ImGuiNavInput_KeyDown_, // move down + ImGuiNavInput_COUNT, + ImGuiNavInput_InternalStart_ = ImGuiNavInput_KeyMenu_ +}; + +// Configuration flags stored in io.ConfigFlags. Set by user/application. +enum ImGuiConfigFlags_ +{ + ImGuiConfigFlags_None = 0, + ImGuiConfigFlags_NavEnableKeyboard = 1 << 0, // Master keyboard navigation enable flag. NewFrame() will automatically fill io.NavInputs[] based on io.KeysDown[]. + ImGuiConfigFlags_NavEnableGamepad = 1 << 1, // Master gamepad navigation enable flag. This is mostly to instruct your imgui back-end to fill io.NavInputs[]. Back-end also needs to set ImGuiBackendFlags_HasGamepad. + ImGuiConfigFlags_NavEnableSetMousePos = 1 << 2, // Instruct navigation to move the mouse cursor. May be useful on TV/console systems where moving a virtual mouse is awkward. Will update io.MousePos and set io.WantSetMousePos=true. If enabled you MUST honor io.WantSetMousePos requests in your binding, otherwise ImGui will react as if the mouse is jumping around back and forth. + ImGuiConfigFlags_NavNoCaptureKeyboard = 1 << 3, // Instruct navigation to not set the io.WantCaptureKeyboard flag when io.NavActive is set. + ImGuiConfigFlags_NoMouse = 1 << 4, // Instruct imgui to clear mouse position/buttons in NewFrame(). This allows ignoring the mouse information set by the back-end. + ImGuiConfigFlags_NoMouseCursorChange = 1 << 5, // Instruct back-end to not alter mouse cursor shape and visibility. Use if the back-end cursor changes are interfering with yours and you don't want to use SetMouseCursor() to change mouse cursor. You may want to honor requests from imgui by reading GetMouseCursor() yourself instead. + + // [BETA] Docking + ImGuiConfigFlags_DockingEnable = 1 << 6, // Docking enable flags. + + // [BETA] Viewports + // When using viewports it is recommended that your default value for ImGuiCol_WindowBg is opaque (Alpha=1.0) so transition to a viewport won't be noticeable. + ImGuiConfigFlags_ViewportsEnable = 1 << 10, // Viewport enable flags (require both ImGuiConfigFlags_PlatformHasViewports + ImGuiConfigFlags_RendererHasViewports set by the respective back-ends) + ImGuiConfigFlags_DpiEnableScaleViewports= 1 << 14, // [BETA: Don't use] FIXME-DPI: Reposition and resize imgui windows when the DpiScale of a viewport changed (mostly useful for the main viewport hosting other window). Note that resizing the main window itself is up to your application. + ImGuiConfigFlags_DpiEnableScaleFonts = 1 << 15, // [BETA: Don't use] FIXME-DPI: Request bitmap-scaled fonts to match DpiScale. This is a very low-quality workaround. The correct way to handle DPI is _currently_ to replace the atlas and/or fonts in the Platform_OnChangedViewport callback, but this is all early work in progress. + + // User storage (to allow your back-end/engine to communicate to code that may be shared between multiple projects. Those flags are not used by core Dear ImGui) + ImGuiConfigFlags_IsSRGB = 1 << 20, // Application is SRGB-aware. + ImGuiConfigFlags_IsTouchScreen = 1 << 21 // Application is using a touch screen instead of a mouse. +}; + +// Back-end capabilities flags stored in io.BackendFlags. Set by imgui_impl_xxx or custom back-end. +enum ImGuiBackendFlags_ +{ + ImGuiBackendFlags_None = 0, + ImGuiBackendFlags_HasGamepad = 1 << 0, // Back-end Platform supports gamepad and currently has one connected. + ImGuiBackendFlags_HasMouseCursors = 1 << 1, // Back-end Platform supports honoring GetMouseCursor() value to change the OS cursor shape. + ImGuiBackendFlags_HasSetMousePos = 1 << 2, // Back-end Platform supports io.WantSetMousePos requests to reposition the OS mouse position (only used if ImGuiConfigFlags_NavEnableSetMousePos is set). + ImGuiBackendFlags_RendererHasVtxOffset = 1 << 3, // Back-end Renderer supports ImDrawCmd::VtxOffset. This enables output of large meshes (64K+ vertices) while still using 16-bit indices. + + // [BETA] Viewports + ImGuiBackendFlags_PlatformHasViewports = 1 << 10, // Back-end Platform supports multiple viewports. + ImGuiBackendFlags_HasMouseHoveredViewport=1 << 11, // Back-end Platform supports setting io.MouseHoveredViewport to the viewport directly under the mouse _IGNORING_ viewports with the ImGuiViewportFlags_NoInputs flag and _REGARDLESS_ of whether another viewport is focused and may be capturing the mouse. This information is _NOT EASY_ to provide correctly with most high-level engines! Don't set this without studying how the examples/ back-end handle it! + ImGuiBackendFlags_RendererHasViewports = 1 << 12 // Back-end Renderer supports multiple viewports. +}; + +// Enumeration for PushStyleColor() / PopStyleColor() +enum ImGuiCol_ +{ + ImGuiCol_Text, + ImGuiCol_TextDisabled, + ImGuiCol_WindowBg, // Background of normal windows + ImGuiCol_ChildBg, // Background of child windows + ImGuiCol_PopupBg, // Background of popups, menus, tooltips windows + ImGuiCol_Border, + ImGuiCol_BorderShadow, + ImGuiCol_FrameBg, // Background of checkbox, radio button, plot, slider, text input + ImGuiCol_FrameBgHovered, + ImGuiCol_FrameBgActive, + ImGuiCol_TitleBg, + ImGuiCol_TitleBgActive, + ImGuiCol_TitleBgCollapsed, + ImGuiCol_MenuBarBg, + ImGuiCol_ScrollbarBg, + ImGuiCol_ScrollbarGrab, + ImGuiCol_ScrollbarGrabHovered, + ImGuiCol_ScrollbarGrabActive, + ImGuiCol_CheckMark, + ImGuiCol_SliderGrab, + ImGuiCol_SliderGrabActive, + ImGuiCol_Button, + ImGuiCol_ButtonHovered, + ImGuiCol_ButtonActive, + ImGuiCol_Header, // Header* colors are used for CollapsingHeader, TreeNode, Selectable, MenuItem + ImGuiCol_HeaderHovered, + ImGuiCol_HeaderActive, + ImGuiCol_Separator, + ImGuiCol_SeparatorHovered, + ImGuiCol_SeparatorActive, + ImGuiCol_ResizeGrip, + ImGuiCol_ResizeGripHovered, + ImGuiCol_ResizeGripActive, + ImGuiCol_Tab, + ImGuiCol_TabHovered, + ImGuiCol_TabActive, + ImGuiCol_TabUnfocused, + ImGuiCol_TabUnfocusedActive, + ImGuiCol_DockingPreview, // Preview overlay color when about to docking something + ImGuiCol_DockingEmptyBg, // Background color for empty node (e.g. CentralNode with no window docked into it) + ImGuiCol_PlotLines, + ImGuiCol_PlotLinesHovered, + ImGuiCol_PlotHistogram, + ImGuiCol_PlotHistogramHovered, + ImGuiCol_TextSelectedBg, + ImGuiCol_DragDropTarget, + ImGuiCol_NavHighlight, // Gamepad/keyboard: current highlighted item + ImGuiCol_NavWindowingHighlight, // Highlight window when using CTRL+TAB + ImGuiCol_NavWindowingDimBg, // Darken/colorize entire screen behind the CTRL+TAB window list, when active + ImGuiCol_ModalWindowDimBg, // Darken/colorize entire screen behind a modal window, when one is active + ImGuiCol_COUNT + + // Obsolete names (will be removed) +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + , ImGuiCol_ModalWindowDarkening = ImGuiCol_ModalWindowDimBg // [renamed in 1.63] + //, ImGuiCol_CloseButton, ImGuiCol_CloseButtonActive, ImGuiCol_CloseButtonHovered// [unused since 1.60+] the close button now uses regular button colors. +#endif +}; + +// Enumeration for PushStyleVar() / PopStyleVar() to temporarily modify the ImGuiStyle structure. +// - The enum only refers to fields of ImGuiStyle which makes sense to be pushed/popped inside UI code. +// During initialization or between frames, feel free to just poke into ImGuiStyle directly. +// - Tip: Use your programming IDE navigation facilities on the names in the _second column_ below to find the actual members and their description. +// In Visual Studio IDE: CTRL+comma ("Edit.NavigateTo") can follow symbols in comments, whereas CTRL+F12 ("Edit.GoToImplementation") cannot. +// With Visual Assist installed: ALT+G ("VAssistX.GoToImplementation") can also follow symbols in comments. +// - When changing this enum, you need to update the associated internal table GStyleVarInfo[] accordingly. This is where we link enum values to members offset/type. +enum ImGuiStyleVar_ +{ + // Enum name --------------------- // Member in ImGuiStyle structure (see ImGuiStyle for descriptions) + ImGuiStyleVar_Alpha, // float Alpha + ImGuiStyleVar_WindowPadding, // ImVec2 WindowPadding + ImGuiStyleVar_WindowRounding, // float WindowRounding + ImGuiStyleVar_WindowBorderSize, // float WindowBorderSize + ImGuiStyleVar_WindowMinSize, // ImVec2 WindowMinSize + ImGuiStyleVar_WindowTitleAlign, // ImVec2 WindowTitleAlign + ImGuiStyleVar_ChildRounding, // float ChildRounding + ImGuiStyleVar_ChildBorderSize, // float ChildBorderSize + ImGuiStyleVar_PopupRounding, // float PopupRounding + ImGuiStyleVar_PopupBorderSize, // float PopupBorderSize + ImGuiStyleVar_FramePadding, // ImVec2 FramePadding + ImGuiStyleVar_FrameRounding, // float FrameRounding + ImGuiStyleVar_FrameBorderSize, // float FrameBorderSize + ImGuiStyleVar_ItemSpacing, // ImVec2 ItemSpacing + ImGuiStyleVar_ItemInnerSpacing, // ImVec2 ItemInnerSpacing + ImGuiStyleVar_IndentSpacing, // float IndentSpacing + ImGuiStyleVar_ScrollbarSize, // float ScrollbarSize + ImGuiStyleVar_ScrollbarRounding, // float ScrollbarRounding + ImGuiStyleVar_GrabMinSize, // float GrabMinSize + ImGuiStyleVar_GrabRounding, // float GrabRounding + ImGuiStyleVar_TabRounding, // float TabRounding + ImGuiStyleVar_ButtonTextAlign, // ImVec2 ButtonTextAlign + ImGuiStyleVar_SelectableTextAlign, // ImVec2 SelectableTextAlign + ImGuiStyleVar_COUNT + + // Obsolete names (will be removed) +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + , ImGuiStyleVar_Count_ = ImGuiStyleVar_COUNT // [renamed in 1.60] +#endif +}; + +// Flags for ColorEdit3() / ColorEdit4() / ColorPicker3() / ColorPicker4() / ColorButton() +enum ImGuiColorEditFlags_ +{ + ImGuiColorEditFlags_None = 0, + ImGuiColorEditFlags_NoAlpha = 1 << 1, // // ColorEdit, ColorPicker, ColorButton: ignore Alpha component (will only read 3 components from the input pointer). + ImGuiColorEditFlags_NoPicker = 1 << 2, // // ColorEdit: disable picker when clicking on colored square. + ImGuiColorEditFlags_NoOptions = 1 << 3, // // ColorEdit: disable toggling options menu when right-clicking on inputs/small preview. + ImGuiColorEditFlags_NoSmallPreview = 1 << 4, // // ColorEdit, ColorPicker: disable colored square preview next to the inputs. (e.g. to show only the inputs) + ImGuiColorEditFlags_NoInputs = 1 << 5, // // ColorEdit, ColorPicker: disable inputs sliders/text widgets (e.g. to show only the small preview colored square). + ImGuiColorEditFlags_NoTooltip = 1 << 6, // // ColorEdit, ColorPicker, ColorButton: disable tooltip when hovering the preview. + ImGuiColorEditFlags_NoLabel = 1 << 7, // // ColorEdit, ColorPicker: disable display of inline text label (the label is still forwarded to the tooltip and picker). + ImGuiColorEditFlags_NoSidePreview = 1 << 8, // // ColorPicker: disable bigger color preview on right side of the picker, use small colored square preview instead. + ImGuiColorEditFlags_NoDragDrop = 1 << 9, // // ColorEdit: disable drag and drop target. ColorButton: disable drag and drop source. + ImGuiColorEditFlags_NoBorder = 1 << 10, // // ColorButton: disable border (which is enforced by default) + + // User Options (right-click on widget to change some of them). + ImGuiColorEditFlags_AlphaBar = 1 << 16, // // ColorEdit, ColorPicker: show vertical alpha bar/gradient in picker. + ImGuiColorEditFlags_AlphaPreview = 1 << 17, // // ColorEdit, ColorPicker, ColorButton: display preview as a transparent color over a checkerboard, instead of opaque. + ImGuiColorEditFlags_AlphaPreviewHalf= 1 << 18, // // ColorEdit, ColorPicker, ColorButton: display half opaque / half checkerboard, instead of opaque. + ImGuiColorEditFlags_HDR = 1 << 19, // // (WIP) ColorEdit: Currently only disable 0.0f..1.0f limits in RGBA edition (note: you probably want to use ImGuiColorEditFlags_Float flag as well). + ImGuiColorEditFlags_DisplayRGB = 1 << 20, // [Display] // ColorEdit: override _display_ type among RGB/HSV/Hex. ColorPicker: select any combination using one or more of RGB/HSV/Hex. + ImGuiColorEditFlags_DisplayHSV = 1 << 21, // [Display] // " + ImGuiColorEditFlags_DisplayHex = 1 << 22, // [Display] // " + ImGuiColorEditFlags_Uint8 = 1 << 23, // [DataType] // ColorEdit, ColorPicker, ColorButton: _display_ values formatted as 0..255. + ImGuiColorEditFlags_Float = 1 << 24, // [DataType] // ColorEdit, ColorPicker, ColorButton: _display_ values formatted as 0.0f..1.0f floats instead of 0..255 integers. No round-trip of value via integers. + ImGuiColorEditFlags_PickerHueBar = 1 << 25, // [Picker] // ColorPicker: bar for Hue, rectangle for Sat/Value. + ImGuiColorEditFlags_PickerHueWheel = 1 << 26, // [Picker] // ColorPicker: wheel for Hue, triangle for Sat/Value. + ImGuiColorEditFlags_InputRGB = 1 << 27, // [Input] // ColorEdit, ColorPicker: input and output data in RGB format. + ImGuiColorEditFlags_InputHSV = 1 << 28, // [Input] // ColorEdit, ColorPicker: input and output data in HSV format. + + // Defaults Options. You can set application defaults using SetColorEditOptions(). The intent is that you probably don't want to + // override them in most of your calls. Let the user choose via the option menu and/or call SetColorEditOptions() once during startup. + ImGuiColorEditFlags__OptionsDefault = ImGuiColorEditFlags_Uint8|ImGuiColorEditFlags_DisplayRGB|ImGuiColorEditFlags_InputRGB|ImGuiColorEditFlags_PickerHueBar, + + // [Internal] Masks + ImGuiColorEditFlags__DisplayMask = ImGuiColorEditFlags_DisplayRGB|ImGuiColorEditFlags_DisplayHSV|ImGuiColorEditFlags_DisplayHex, + ImGuiColorEditFlags__DataTypeMask = ImGuiColorEditFlags_Uint8|ImGuiColorEditFlags_Float, + ImGuiColorEditFlags__PickerMask = ImGuiColorEditFlags_PickerHueWheel|ImGuiColorEditFlags_PickerHueBar, + ImGuiColorEditFlags__InputMask = ImGuiColorEditFlags_InputRGB|ImGuiColorEditFlags_InputHSV + + // Obsolete names (will be removed) +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + , ImGuiColorEditFlags_RGB = ImGuiColorEditFlags_DisplayRGB, ImGuiColorEditFlags_HSV = ImGuiColorEditFlags_DisplayHSV, ImGuiColorEditFlags_HEX = ImGuiColorEditFlags_DisplayHex // [renamed in 1.69] +#endif +}; + +// Identify a mouse button. +// Those values are guaranteed to be stable and we frequently use 0/1 directly. Named enums provided for convenience. +enum ImGuiMouseButton_ +{ + ImGuiMouseButton_Left = 0, + ImGuiMouseButton_Right = 1, + ImGuiMouseButton_Middle = 2, + ImGuiMouseButton_COUNT = 5 +}; + +// Enumeration for GetMouseCursor() +// User code may request binding to display given cursor by calling SetMouseCursor(), which is why we have some cursors that are marked unused here +enum ImGuiMouseCursor_ +{ + ImGuiMouseCursor_None = -1, + ImGuiMouseCursor_Arrow = 0, + ImGuiMouseCursor_TextInput, // When hovering over InputText, etc. + ImGuiMouseCursor_ResizeAll, // (Unused by Dear ImGui functions) + ImGuiMouseCursor_ResizeNS, // When hovering over an horizontal border + ImGuiMouseCursor_ResizeEW, // When hovering over a vertical border or a column + ImGuiMouseCursor_ResizeNESW, // When hovering over the bottom-left corner of a window + ImGuiMouseCursor_ResizeNWSE, // When hovering over the bottom-right corner of a window + ImGuiMouseCursor_Hand, // (Unused by Dear ImGui functions. Use for e.g. hyperlinks) + ImGuiMouseCursor_NotAllowed, // When hovering something with disallowed interaction. Usually a crossed circle. + ImGuiMouseCursor_COUNT + + // Obsolete names (will be removed) +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + , ImGuiMouseCursor_Count_ = ImGuiMouseCursor_COUNT // [renamed in 1.60] +#endif +}; + +// Enumeration for ImGui::SetWindow***(), SetNextWindow***(), SetNextItem***() functions +// Represent a condition. +// Important: Treat as a regular enum! Do NOT combine multiple values using binary operators! All the functions above treat 0 as a shortcut to ImGuiCond_Always. +enum ImGuiCond_ +{ + ImGuiCond_Always = 1 << 0, // Set the variable + ImGuiCond_Once = 1 << 1, // Set the variable once per runtime session (only the first call will succeed) + ImGuiCond_FirstUseEver = 1 << 2, // Set the variable if the object/window has no persistently saved data (no entry in .ini file) + ImGuiCond_Appearing = 1 << 3 // Set the variable if the object/window is appearing after being hidden/inactive (or the first time) +}; + +//----------------------------------------------------------------------------- +// Helpers: Memory allocations macros +// IM_MALLOC(), IM_FREE(), IM_NEW(), IM_PLACEMENT_NEW(), IM_DELETE() +// We call C++ constructor on own allocated memory via the placement "new(ptr) Type()" syntax. +// Defining a custom placement new() with a dummy parameter allows us to bypass including which on some platforms complains when user has disabled exceptions. +//----------------------------------------------------------------------------- + +struct ImNewDummy {}; +inline void* operator new(size_t, ImNewDummy, void* ptr) { return ptr; } +inline void operator delete(void*, ImNewDummy, void*) {} // This is only required so we can use the symmetrical new() +#define IM_ALLOC(_SIZE) ImGui::MemAlloc(_SIZE) +#define IM_FREE(_PTR) ImGui::MemFree(_PTR) +#define IM_PLACEMENT_NEW(_PTR) new(ImNewDummy(), _PTR) +#define IM_NEW(_TYPE) new(ImNewDummy(), ImGui::MemAlloc(sizeof(_TYPE))) _TYPE +template void IM_DELETE(T* p) { if (p) { p->~T(); ImGui::MemFree(p); } } + +//----------------------------------------------------------------------------- +// Helper: ImVector<> +// Lightweight std::vector<>-like class to avoid dragging dependencies (also, some implementations of STL with debug enabled are absurdly slow, we bypass it so our code runs fast in debug). +//----------------------------------------------------------------------------- +// - You generally do NOT need to care or use this ever. But we need to make it available in imgui.h because some of our public structures are relying on it. +// - We use std-like naming convention here, which is a little unusual for this codebase. +// - Important: clear() frees memory, resize(0) keep the allocated buffer. We use resize(0) a lot to intentionally recycle allocated buffers across frames and amortize our costs. +// - Important: our implementation does NOT call C++ constructors/destructors, we treat everything as raw data! This is intentional but be extra mindful of that, +// Do NOT use this class as a std::vector replacement in your own code! Many of the structures used by dear imgui can be safely initialized by a zero-memset. +//----------------------------------------------------------------------------- + +template +struct ImVector +{ + int Size; + int Capacity; + T* Data; + + // Provide standard typedefs but we don't use them ourselves. + typedef T value_type; + typedef value_type* iterator; + typedef const value_type* const_iterator; + + // Constructors, destructor + inline ImVector() { Size = Capacity = 0; Data = NULL; } + inline ImVector(const ImVector& src) { Size = Capacity = 0; Data = NULL; operator=(src); } + inline ImVector& operator=(const ImVector& src) { clear(); resize(src.Size); memcpy(Data, src.Data, (size_t)Size * sizeof(T)); return *this; } + inline ~ImVector() { if (Data) IM_FREE(Data); } + + inline bool empty() const { return Size == 0; } + inline int size() const { return Size; } + inline int size_in_bytes() const { return Size * (int)sizeof(T); } + inline int capacity() const { return Capacity; } + inline T& operator[](int i) { IM_ASSERT(i < Size); return Data[i]; } + inline const T& operator[](int i) const { IM_ASSERT(i < Size); return Data[i]; } + + inline void clear() { if (Data) { Size = Capacity = 0; IM_FREE(Data); Data = NULL; } } + inline T* begin() { return Data; } + inline const T* begin() const { return Data; } + inline T* end() { return Data + Size; } + inline const T* end() const { return Data + Size; } + inline T& front() { IM_ASSERT(Size > 0); return Data[0]; } + inline const T& front() const { IM_ASSERT(Size > 0); return Data[0]; } + inline T& back() { IM_ASSERT(Size > 0); return Data[Size - 1]; } + inline const T& back() const { IM_ASSERT(Size > 0); return Data[Size - 1]; } + inline void swap(ImVector& rhs) { int rhs_size = rhs.Size; rhs.Size = Size; Size = rhs_size; int rhs_cap = rhs.Capacity; rhs.Capacity = Capacity; Capacity = rhs_cap; T* rhs_data = rhs.Data; rhs.Data = Data; Data = rhs_data; } + + inline int _grow_capacity(int sz) const { int new_capacity = Capacity ? (Capacity + Capacity/2) : 8; return new_capacity > sz ? new_capacity : sz; } + inline void resize(int new_size) { if (new_size > Capacity) reserve(_grow_capacity(new_size)); Size = new_size; } + inline void resize(int new_size, const T& v) { if (new_size > Capacity) reserve(_grow_capacity(new_size)); if (new_size > Size) for (int n = Size; n < new_size; n++) memcpy(&Data[n], &v, sizeof(v)); Size = new_size; } + inline void shrink(int new_size) { IM_ASSERT(new_size <= Size); Size = new_size; } // Resize a vector to a smaller size, guaranteed not to cause a reallocation + inline void reserve(int new_capacity) { if (new_capacity <= Capacity) return; T* new_data = (T*)IM_ALLOC((size_t)new_capacity * sizeof(T)); if (Data) { memcpy(new_data, Data, (size_t)Size * sizeof(T)); IM_FREE(Data); } Data = new_data; Capacity = new_capacity; } + + // NB: It is illegal to call push_back/push_front/insert with a reference pointing inside the ImVector data itself! e.g. v.push_back(v[10]) is forbidden. + inline void push_back(const T& v) { if (Size == Capacity) reserve(_grow_capacity(Size + 1)); memcpy(&Data[Size], &v, sizeof(v)); Size++; } + inline void pop_back() { IM_ASSERT(Size > 0); Size--; } + inline void push_front(const T& v) { if (Size == 0) push_back(v); else insert(Data, v); } + inline T* erase(const T* it) { IM_ASSERT(it >= Data && it < Data+Size); const ptrdiff_t off = it - Data; memmove(Data + off, Data + off + 1, ((size_t)Size - (size_t)off - 1) * sizeof(T)); Size--; return Data + off; } + inline T* erase(const T* it, const T* it_last){ IM_ASSERT(it >= Data && it < Data+Size && it_last > it && it_last <= Data+Size); const ptrdiff_t count = it_last - it; const ptrdiff_t off = it - Data; memmove(Data + off, Data + off + count, ((size_t)Size - (size_t)off - count) * sizeof(T)); Size -= (int)count; return Data + off; } + inline T* erase_unsorted(const T* it) { IM_ASSERT(it >= Data && it < Data+Size); const ptrdiff_t off = it - Data; if (it < Data+Size-1) memcpy(Data + off, Data + Size - 1, sizeof(T)); Size--; return Data + off; } + inline T* insert(const T* it, const T& v) { IM_ASSERT(it >= Data && it <= Data+Size); const ptrdiff_t off = it - Data; if (Size == Capacity) reserve(_grow_capacity(Size + 1)); if (off < (int)Size) memmove(Data + off + 1, Data + off, ((size_t)Size - (size_t)off) * sizeof(T)); memcpy(&Data[off], &v, sizeof(v)); Size++; return Data + off; } + inline bool contains(const T& v) const { const T* data = Data; const T* data_end = Data + Size; while (data < data_end) if (*data++ == v) return true; return false; } + inline T* find(const T& v) { T* data = Data; const T* data_end = Data + Size; while (data < data_end) if (*data == v) break; else ++data; return data; } + inline const T* find(const T& v) const { const T* data = Data; const T* data_end = Data + Size; while (data < data_end) if (*data == v) break; else ++data; return data; } + inline bool find_erase(const T& v) { const T* it = find(v); if (it < Data + Size) { erase(it); return true; } return false; } + inline bool find_erase_unsorted(const T& v) { const T* it = find(v); if (it < Data + Size) { erase_unsorted(it); return true; } return false; } + inline int index_from_ptr(const T* it) const { IM_ASSERT(it >= Data && it < Data + Size); const ptrdiff_t off = it - Data; return (int)off; } +}; + +//----------------------------------------------------------------------------- +// ImGuiStyle +// You may modify the ImGui::GetStyle() main instance during initialization and before NewFrame(). +// During the frame, use ImGui::PushStyleVar(ImGuiStyleVar_XXXX)/PopStyleVar() to alter the main style values, +// and ImGui::PushStyleColor(ImGuiCol_XXX)/PopStyleColor() for colors. +//----------------------------------------------------------------------------- + +struct ImGuiStyle +{ + float Alpha; // Global alpha applies to everything in Dear ImGui. + ImVec2 WindowPadding; // Padding within a window. + float WindowRounding; // Radius of window corners rounding. Set to 0.0f to have rectangular windows. + float WindowBorderSize; // Thickness of border around windows. Generally set to 0.0f or 1.0f. (Other values are not well tested and more CPU/GPU costly). + ImVec2 WindowMinSize; // Minimum window size. This is a global setting. If you want to constraint individual windows, use SetNextWindowSizeConstraints(). + ImVec2 WindowTitleAlign; // Alignment for title bar text. Defaults to (0.0f,0.5f) for left-aligned,vertically centered. + ImGuiDir WindowMenuButtonPosition; // Side of the collapsing/docking button in the title bar (None/Left/Right). Defaults to ImGuiDir_Left. + float ChildRounding; // Radius of child window corners rounding. Set to 0.0f to have rectangular windows. + float ChildBorderSize; // Thickness of border around child windows. Generally set to 0.0f or 1.0f. (Other values are not well tested and more CPU/GPU costly). + float PopupRounding; // Radius of popup window corners rounding. (Note that tooltip windows use WindowRounding) + float PopupBorderSize; // Thickness of border around popup/tooltip windows. Generally set to 0.0f or 1.0f. (Other values are not well tested and more CPU/GPU costly). + ImVec2 FramePadding; // Padding within a framed rectangle (used by most widgets). + float FrameRounding; // Radius of frame corners rounding. Set to 0.0f to have rectangular frame (used by most widgets). + float FrameBorderSize; // Thickness of border around frames. Generally set to 0.0f or 1.0f. (Other values are not well tested and more CPU/GPU costly). + ImVec2 ItemSpacing; // Horizontal and vertical spacing between widgets/lines. + ImVec2 ItemInnerSpacing; // Horizontal and vertical spacing between within elements of a composed widget (e.g. a slider and its label). + ImVec2 TouchExtraPadding; // Expand reactive bounding box for touch-based system where touch position is not accurate enough. Unfortunately we don't sort widgets so priority on overlap will always be given to the first widget. So don't grow this too much! + float IndentSpacing; // Horizontal indentation when e.g. entering a tree node. Generally == (FontSize + FramePadding.x*2). + float ColumnsMinSpacing; // Minimum horizontal spacing between two columns. Preferably > (FramePadding.x + 1). + float ScrollbarSize; // Width of the vertical scrollbar, Height of the horizontal scrollbar. + float ScrollbarRounding; // Radius of grab corners for scrollbar. + float GrabMinSize; // Minimum width/height of a grab box for slider/scrollbar. + float GrabRounding; // Radius of grabs corners rounding. Set to 0.0f to have rectangular slider grabs. + float TabRounding; // Radius of upper corners of a tab. Set to 0.0f to have rectangular tabs. + float TabBorderSize; // Thickness of border around tabs. + float TabMinWidthForUnselectedCloseButton; // Minimum width for close button to appears on an unselected tab when hovered. Set to 0.0f to always show when hovering, set to FLT_MAX to never show close button unless selected. + ImGuiDir ColorButtonPosition; // Side of the color button in the ColorEdit4 widget (left/right). Defaults to ImGuiDir_Right. + ImVec2 ButtonTextAlign; // Alignment of button text when button is larger than text. Defaults to (0.5f, 0.5f) (centered). + ImVec2 SelectableTextAlign; // Alignment of selectable text. Defaults to (0.0f, 0.0f) (top-left aligned). It's generally important to keep this left-aligned if you want to lay multiple items on a same line. + ImVec2 DisplayWindowPadding; // Window position are clamped to be visible within the display area or monitors by at least this amount. Only applies to regular windows. + ImVec2 DisplaySafeAreaPadding; // If you cannot see the edges of your screen (e.g. on a TV) increase the safe area padding. Apply to popups/tooltips as well regular windows. NB: Prefer configuring your TV sets correctly! + float MouseCursorScale; // Scale software rendered mouse cursor (when io.MouseDrawCursor is enabled). We apply per-monitor DPI scaling over this scale. May be removed later. + bool AntiAliasedLines; // Enable anti-aliasing on lines/borders. Disable if you are really tight on CPU/GPU. + bool AntiAliasedFill; // Enable anti-aliasing on filled shapes (rounded rectangles, circles, etc.) + float CurveTessellationTol; // Tessellation tolerance when using PathBezierCurveTo() without a specific number of segments. Decrease for highly tessellated curves (higher quality, more polygons), increase to reduce quality. + float CircleSegmentMaxError; // Maximum error (in pixels) allowed when using AddCircle()/AddCircleFilled() or drawing rounded corner rectangles with no explicit segment count specified. Decrease for higher quality but more geometry. + ImVec4 Colors[ImGuiCol_COUNT]; + + IMGUI_API ImGuiStyle(); + IMGUI_API void ScaleAllSizes(float scale_factor); +}; + +//----------------------------------------------------------------------------- +// ImGuiIO +// Communicate most settings and inputs/outputs to Dear ImGui using this structure. +// Access via ImGui::GetIO(). Read 'Programmer guide' section in .cpp file for general usage. +//----------------------------------------------------------------------------- + +struct ImGuiIO +{ + //------------------------------------------------------------------ + // Configuration (fill once) // Default value + //------------------------------------------------------------------ + + ImGuiConfigFlags ConfigFlags; // = 0 // See ImGuiConfigFlags_ enum. Set by user/application. Gamepad/keyboard navigation options, etc. + ImGuiBackendFlags BackendFlags; // = 0 // See ImGuiBackendFlags_ enum. Set by back-end (imgui_impl_xxx files or custom back-end) to communicate features supported by the back-end. + ImVec2 DisplaySize; // // Main display size, in pixels. This is for the default viewport. + float DeltaTime; // = 1.0f/60.0f // Time elapsed since last frame, in seconds. + float IniSavingRate; // = 5.0f // Minimum time between saving positions/sizes to .ini file, in seconds. + const char* IniFilename; // = "imgui.ini" // Path to .ini file. Set NULL to disable automatic .ini loading/saving, if e.g. you want to manually load/save from memory. + const char* LogFilename; // = "imgui_log.txt"// Path to .log file (default parameter to ImGui::LogToFile when no file is specified). + float MouseDoubleClickTime; // = 0.30f // Time for a double-click, in seconds. + float MouseDoubleClickMaxDist; // = 6.0f // Distance threshold to stay in to validate a double-click, in pixels. + float MouseDragThreshold; // = 6.0f // Distance threshold before considering we are dragging. + int KeyMap[ImGuiKey_COUNT]; // // Map of indices into the KeysDown[512] entries array which represent your "native" keyboard state. + float KeyRepeatDelay; // = 0.250f // When holding a key/button, time before it starts repeating, in seconds (for buttons in Repeat mode, etc.). + float KeyRepeatRate; // = 0.050f // When holding a key/button, rate at which it repeats, in seconds. + void* UserData; // = NULL // Store your own data for retrieval by callbacks. + + ImFontAtlas*Fonts; // // Font atlas: load, rasterize and pack one or more fonts into a single texture. + float FontGlobalScale; // = 1.0f // Global scale all fonts + bool FontAllowUserScaling; // = false // Allow user scaling text of individual window with CTRL+Wheel. + ImFont* FontDefault; // = NULL // Font to use on NewFrame(). Use NULL to uses Fonts->Fonts[0]. + ImVec2 DisplayFramebufferScale; // = (1, 1) // For retina display or other situations where window coordinates are different from framebuffer coordinates. This generally ends up in ImDrawData::FramebufferScale. + + // Docking options (when ImGuiConfigFlags_DockingEnable is set) + bool ConfigDockingNoSplit; // = false // Simplified docking mode: disable window splitting, so docking is limited to merging multiple windows together into tab-bars. + bool ConfigDockingWithShift; // = false // Enable docking with holding Shift key (reduce visual noise, allows dropping in wider space) + bool ConfigDockingAlwaysTabBar; // = false // [BETA] [FIXME: This currently creates regression with auto-sizing and general overhead] Make every single floating window display within a docking node. + bool ConfigDockingTransparentPayload;// = false // [BETA] Make window or viewport transparent when docking and only display docking boxes on the target viewport. Useful if rendering of multiple viewport cannot be synced. Best used with ConfigViewportsNoAutoMerge. + + // Viewport options (when ImGuiConfigFlags_ViewportsEnable is set) + bool ConfigViewportsNoAutoMerge; // = false; // Set to make all floating imgui windows always create their own viewport. Otherwise, they are merged into the main host viewports when overlapping it. May also set ImGuiViewportFlags_NoAutoMerge on individual viewport. + bool ConfigViewportsNoTaskBarIcon; // = false // Disable default OS task bar icon flag for secondary viewports. When a viewport doesn't want a task bar icon, ImGuiViewportFlags_NoTaskBarIcon will be set on it. + bool ConfigViewportsNoDecoration; // = true // [BETA] Disable default OS window decoration flag for secondary viewports. When a viewport doesn't want window decorations, ImGuiViewportFlags_NoDecoration will be set on it. Enabling decoration can create subsequent issues at OS levels (e.g. minimum window size). + bool ConfigViewportsNoDefaultParent; // = false // Disable default OS parenting to main viewport for secondary viewports. By default, viewports are marked with ParentViewportId = , expecting the platform back-end to setup a parent/child relationship between the OS windows (some back-end may ignore this). Set to true if you want the default to be 0, then all viewports will be top-level OS windows. + + // Miscellaneous options + bool MouseDrawCursor; // = false // Request ImGui to draw a mouse cursor for you (if you are on a platform without a mouse cursor). Cannot be easily renamed to 'io.ConfigXXX' because this is frequently used by back-end implementations. + bool ConfigMacOSXBehaviors; // = defined(__APPLE__) // OS X style: Text editing cursor movement using Alt instead of Ctrl, Shortcuts using Cmd/Super instead of Ctrl, Line/Text Start and End using Cmd+Arrows instead of Home/End, Double click selects by word instead of selecting whole text, Multi-selection in lists uses Cmd/Super instead of Ctrl (was called io.OptMacOSXBehaviors prior to 1.63) + bool ConfigInputTextCursorBlink; // = true // Set to false to disable blinking cursor, for users who consider it distracting. (was called: io.OptCursorBlink prior to 1.63) + bool ConfigWindowsResizeFromEdges; // = true // Enable resizing of windows from their edges and from the lower-left corner. This requires (io.BackendFlags & ImGuiBackendFlags_HasMouseCursors) because it needs mouse cursor feedback. (This used to be a per-window ImGuiWindowFlags_ResizeFromAnySide flag) + bool ConfigWindowsMoveFromTitleBarOnly; // = false // [BETA] Set to true to only allow moving windows when clicked+dragged from the title bar. Windows without a title bar are not affected. + float ConfigWindowsMemoryCompactTimer;// = 60.0f // [BETA] Compact window memory usage when unused. Set to -1.0f to disable. + + //------------------------------------------------------------------ + // Platform Functions + // (the imgui_impl_xxxx back-end files are setting those up for you) + //------------------------------------------------------------------ + + // Optional: Platform/Renderer back-end name (informational only! will be displayed in About Window) + User data for back-end/wrappers to store their own stuff. + const char* BackendPlatformName; // = NULL + const char* BackendRendererName; // = NULL + void* BackendPlatformUserData; // = NULL // User data for platform back-end + void* BackendRendererUserData; // = NULL // User data for renderer back-end + void* BackendLanguageUserData; // = NULL // User data for non C++ programming language back-end + + // Optional: Access OS clipboard + // (default to use native Win32 clipboard on Windows, otherwise uses a private clipboard. Override to access OS clipboard on other architectures) + const char* (*GetClipboardTextFn)(void* user_data); + void (*SetClipboardTextFn)(void* user_data, const char* text); + void* ClipboardUserData; + +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + // [OBSOLETE since 1.60+] Rendering function, will be automatically called in Render(). Please call your rendering function yourself now! + // You can obtain the ImDrawData* by calling ImGui::GetDrawData() after Render(). See example applications if you are unsure of how to implement this. + void (*RenderDrawListsFn)(ImDrawData* data); +#else + // This is only here to keep ImGuiIO the same size/layout, so that IMGUI_DISABLE_OBSOLETE_FUNCTIONS can exceptionally be used outside of imconfig.h. + void* RenderDrawListsFnUnused; +#endif + + //------------------------------------------------------------------ + // Input - Fill before calling NewFrame() + //------------------------------------------------------------------ + + ImVec2 MousePos; // Mouse position, in pixels. Set to ImVec2(-FLT_MAX,-FLT_MAX) if mouse is unavailable (on another screen, etc.) + bool MouseDown[5]; // Mouse buttons: 0=left, 1=right, 2=middle + extras. ImGui itself mostly only uses left button (BeginPopupContext** are using right button). Others buttons allows us to track if the mouse is being used by your application + available to user as a convenience via IsMouse** API. + float MouseWheel; // Mouse wheel Vertical: 1 unit scrolls about 5 lines text. + float MouseWheelH; // Mouse wheel Horizontal. Most users don't have a mouse with an horizontal wheel, may not be filled by all back-ends. + ImGuiID MouseHoveredViewport; // (Optional) When using multiple viewports: viewport the OS mouse cursor is hovering _IGNORING_ viewports with the ImGuiViewportFlags_NoInputs flag, and _REGARDLESS_ of whether another viewport is focused. Set io.BackendFlags |= ImGuiBackendFlags_HasMouseHoveredViewport if you can provide this info. If you don't imgui will infer the value using the rectangles and last focused time of the viewports it knows about (ignoring other OS windows). + bool KeyCtrl; // Keyboard modifier pressed: Control + bool KeyShift; // Keyboard modifier pressed: Shift + bool KeyAlt; // Keyboard modifier pressed: Alt + bool KeySuper; // Keyboard modifier pressed: Cmd/Super/Windows + bool KeysDown[512]; // Keyboard keys that are pressed (ideally left in the "native" order your engine has access to keyboard keys, so you can use your own defines/enums for keys). + float NavInputs[ImGuiNavInput_COUNT]; // Gamepad inputs. Cleared back to zero by EndFrame(). Keyboard keys will be auto-mapped and be written here by NewFrame(). + + // Functions + IMGUI_API void AddInputCharacter(unsigned int c); // Queue new character input + IMGUI_API void AddInputCharacterUTF16(ImWchar16 c); // Queue new character input from an UTF-16 character, it can be a surrogate + IMGUI_API void AddInputCharactersUTF8(const char* str); // Queue new characters input from an UTF-8 string + IMGUI_API void ClearInputCharacters(); // Clear the text input buffer manually + + //------------------------------------------------------------------ + // Output - Updated by NewFrame() or EndFrame()/Render() + // (when reading from the io.WantCaptureMouse, io.WantCaptureKeyboard flags to dispatch your inputs, it is + // generally easier and more correct to use their state BEFORE calling NewFrame(). See FAQ for details!) + //------------------------------------------------------------------ + + bool WantCaptureMouse; // Set when Dear ImGui will use mouse inputs, in this case do not dispatch them to your main game/application (either way, always pass on mouse inputs to imgui). (e.g. unclicked mouse is hovering over an imgui window, widget is active, mouse was clicked over an imgui window, etc.). + bool WantCaptureKeyboard; // Set when Dear ImGui will use keyboard inputs, in this case do not dispatch them to your main game/application (either way, always pass keyboard inputs to imgui). (e.g. InputText active, or an imgui window is focused and navigation is enabled, etc.). + bool WantTextInput; // Mobile/console: when set, you may display an on-screen keyboard. This is set by Dear ImGui when it wants textual keyboard input to happen (e.g. when a InputText widget is active). + bool WantSetMousePos; // MousePos has been altered, back-end should reposition mouse on next frame. Rarely used! Set only when ImGuiConfigFlags_NavEnableSetMousePos flag is enabled. + bool WantSaveIniSettings; // When manual .ini load/save is active (io.IniFilename == NULL), this will be set to notify your application that you can call SaveIniSettingsToMemory() and save yourself. Important: clear io.WantSaveIniSettings yourself after saving! + bool NavActive; // Keyboard/Gamepad navigation is currently allowed (will handle ImGuiKey_NavXXX events) = a window is focused and it doesn't use the ImGuiWindowFlags_NoNavInputs flag. + bool NavVisible; // Keyboard/Gamepad navigation is visible and allowed (will handle ImGuiKey_NavXXX events). + float Framerate; // Application framerate estimate, in frame per second. Solely for convenience. Rolling average estimation based on io.DeltaTime over 120 frames. + int MetricsRenderVertices; // Vertices output during last call to Render() + int MetricsRenderIndices; // Indices output during last call to Render() = number of triangles * 3 + int MetricsRenderWindows; // Number of visible windows + int MetricsActiveWindows; // Number of active windows + int MetricsActiveAllocations; // Number of active allocations, updated by MemAlloc/MemFree based on current context. May be off if you have multiple imgui contexts. + ImVec2 MouseDelta; // Mouse delta. Note that this is zero if either current or previous position are invalid (-FLT_MAX,-FLT_MAX), so a disappearing/reappearing mouse won't have a huge delta. + + //------------------------------------------------------------------ + // [Internal] Dear ImGui will maintain those fields. Forward compatibility not guaranteed! + //------------------------------------------------------------------ + + ImGuiKeyModFlags KeyMods; // Key mods flags (same as io.KeyCtrl/KeyShift/KeyAlt/KeySuper but merged into flags), updated by NewFrame() + ImVec2 MousePosPrev; // Previous mouse position (note that MouseDelta is not necessary == MousePos-MousePosPrev, in case either position is invalid) + ImVec2 MouseClickedPos[5]; // Position at time of clicking + double MouseClickedTime[5]; // Time of last click (used to figure out double-click) + bool MouseClicked[5]; // Mouse button went from !Down to Down + bool MouseDoubleClicked[5]; // Has mouse button been double-clicked? + bool MouseReleased[5]; // Mouse button went from Down to !Down + bool MouseDownOwned[5]; // Track if button was clicked inside a dear imgui window. We don't request mouse capture from the application if click started outside ImGui bounds. + bool MouseDownWasDoubleClick[5]; // Track if button down was a double-click + float MouseDownDuration[5]; // Duration the mouse button has been down (0.0f == just clicked) + float MouseDownDurationPrev[5]; // Previous time the mouse button has been down + ImVec2 MouseDragMaxDistanceAbs[5]; // Maximum distance, absolute, on each axis, of how much mouse has traveled from the clicking point + float MouseDragMaxDistanceSqr[5]; // Squared maximum distance of how much mouse has traveled from the clicking point + float KeysDownDuration[512]; // Duration the keyboard key has been down (0.0f == just pressed) + float KeysDownDurationPrev[512]; // Previous duration the key has been down + float NavInputsDownDuration[ImGuiNavInput_COUNT]; + float NavInputsDownDurationPrev[ImGuiNavInput_COUNT]; + ImWchar16 InputQueueSurrogate; // For AddInputCharacterUTF16 + ImVector InputQueueCharacters; // Queue of _characters_ input (obtained by platform back-end). Fill using AddInputCharacter() helper. + + IMGUI_API ImGuiIO(); +}; + +//----------------------------------------------------------------------------- +// Misc data structures +//----------------------------------------------------------------------------- + +// Shared state of InputText(), passed as an argument to your callback when a ImGuiInputTextFlags_Callback* flag is used. +// The callback function should return 0 by default. +// Callbacks (follow a flag name and see comments in ImGuiInputTextFlags_ declarations for more details) +// - ImGuiInputTextFlags_CallbackCompletion: Callback on pressing TAB +// - ImGuiInputTextFlags_CallbackHistory: Callback on pressing Up/Down arrows +// - ImGuiInputTextFlags_CallbackAlways: Callback on each iteration +// - ImGuiInputTextFlags_CallbackCharFilter: Callback on character inputs to replace or discard them. Modify 'EventChar' to replace or discard, or return 1 in callback to discard. +// - ImGuiInputTextFlags_CallbackResize: Callback on buffer capacity changes request (beyond 'buf_size' parameter value), allowing the string to grow. +struct ImGuiInputTextCallbackData +{ + ImGuiInputTextFlags EventFlag; // One ImGuiInputTextFlags_Callback* // Read-only + ImGuiInputTextFlags Flags; // What user passed to InputText() // Read-only + void* UserData; // What user passed to InputText() // Read-only + + // Arguments for the different callback events + // - To modify the text buffer in a callback, prefer using the InsertChars() / DeleteChars() function. InsertChars() will take care of calling the resize callback if necessary. + // - If you know your edits are not going to resize the underlying buffer allocation, you may modify the contents of 'Buf[]' directly. You need to update 'BufTextLen' accordingly (0 <= BufTextLen < BufSize) and set 'BufDirty'' to true so InputText can update its internal state. + ImWchar EventChar; // Character input // Read-write // [CharFilter] Replace character with another one, or set to zero to drop. return 1 is equivalent to setting EventChar=0; + ImGuiKey EventKey; // Key pressed (Up/Down/TAB) // Read-only // [Completion,History] + char* Buf; // Text buffer // Read-write // [Resize] Can replace pointer / [Completion,History,Always] Only write to pointed data, don't replace the actual pointer! + int BufTextLen; // Text length (in bytes) // Read-write // [Resize,Completion,History,Always] Exclude zero-terminator storage. In C land: == strlen(some_text), in C++ land: string.length() + int BufSize; // Buffer size (in bytes) = capacity+1 // Read-only // [Resize,Completion,History,Always] Include zero-terminator storage. In C land == ARRAYSIZE(my_char_array), in C++ land: string.capacity()+1 + bool BufDirty; // Set if you modify Buf/BufTextLen! // Write // [Completion,History,Always] + int CursorPos; // // Read-write // [Completion,History,Always] + int SelectionStart; // // Read-write // [Completion,History,Always] == to SelectionEnd when no selection) + int SelectionEnd; // // Read-write // [Completion,History,Always] + + // Helper functions for text manipulation. + // Use those function to benefit from the CallbackResize behaviors. Calling those function reset the selection. + IMGUI_API ImGuiInputTextCallbackData(); + IMGUI_API void DeleteChars(int pos, int bytes_count); + IMGUI_API void InsertChars(int pos, const char* text, const char* text_end = NULL); + bool HasSelection() const { return SelectionStart != SelectionEnd; } +}; + +// Resizing callback data to apply custom constraint. As enabled by SetNextWindowSizeConstraints(). Callback is called during the next Begin(). +// NB: For basic min/max size constraint on each axis you don't need to use the callback! The SetNextWindowSizeConstraints() parameters are enough. +struct ImGuiSizeCallbackData +{ + void* UserData; // Read-only. What user passed to SetNextWindowSizeConstraints() + ImVec2 Pos; // Read-only. Window position, for reference. + ImVec2 CurrentSize; // Read-only. Current window size. + ImVec2 DesiredSize; // Read-write. Desired size, based on user's mouse position. Write to this field to restrain resizing. +}; + +// [ALPHA] Rarely used / very advanced uses only. Use with SetNextWindowClass() and DockSpace() functions. +// Important: the content of this class is still highly WIP and likely to change and be refactored +// before we stabilize Docking features. Please be mindful if using this. +// Provide hints: +// - To the platform back-end via altered viewport flags (enable/disable OS decoration, OS task bar icons, etc.) +// - To the platform back-end for OS level parent/child relationships of viewport. +// - To the docking system for various options and filtering. +struct ImGuiWindowClass +{ + ImGuiID ClassId; // User data. 0 = Default class (unclassed). Windows of different classes cannot be docked with each others. + ImGuiID ParentViewportId; // Hint for the platform back-end. If non-zero, the platform back-end can create a parent<>child relationship between the platform windows. Not conforming back-ends are free to e.g. parent every viewport to the main viewport or not. + ImGuiViewportFlags ViewportFlagsOverrideSet; // Viewport flags to set when a window of this class owns a viewport. This allows you to enforce OS decoration or task bar icon, override the defaults on a per-window basis. + ImGuiViewportFlags ViewportFlagsOverrideClear; // Viewport flags to clear when a window of this class owns a viewport. This allows you to enforce OS decoration or task bar icon, override the defaults on a per-window basis. + ImGuiDockNodeFlags DockNodeFlagsOverrideSet; // [EXPERIMENTAL] Dock node flags to set when a window of this class is hosted by a dock node (it doesn't have to be selected!) + ImGuiDockNodeFlags DockNodeFlagsOverrideClear; // [EXPERIMENTAL] + bool DockingAlwaysTabBar; // Set to true to enforce single floating windows of this class always having their own docking node (equivalent of setting the global io.ConfigDockingAlwaysTabBar) + bool DockingAllowUnclassed; // Set to true to allow windows of this class to be docked/merged with an unclassed window. + + ImGuiWindowClass() { ClassId = 0; ParentViewportId = 0; ViewportFlagsOverrideSet = ViewportFlagsOverrideClear = 0x00; DockNodeFlagsOverrideSet = DockNodeFlagsOverrideClear = 0x00; DockingAlwaysTabBar = false; DockingAllowUnclassed = true; } +}; + +// Data payload for Drag and Drop operations: AcceptDragDropPayload(), GetDragDropPayload() +struct ImGuiPayload +{ + // Members + void* Data; // Data (copied and owned by dear imgui) + int DataSize; // Data size + + // [Internal] + ImGuiID SourceId; // Source item id + ImGuiID SourceParentId; // Source parent id (if available) + int DataFrameCount; // Data timestamp + char DataType[32+1]; // Data type tag (short user-supplied string, 32 characters max) + bool Preview; // Set when AcceptDragDropPayload() was called and mouse has been hovering the target item (nb: handle overlapping drag targets) + bool Delivery; // Set when AcceptDragDropPayload() was called and mouse button is released over the target item. + + ImGuiPayload() { Clear(); } + void Clear() { SourceId = SourceParentId = 0; Data = NULL; DataSize = 0; memset(DataType, 0, sizeof(DataType)); DataFrameCount = -1; Preview = Delivery = false; } + bool IsDataType(const char* type) const { return DataFrameCount != -1 && strcmp(type, DataType) == 0; } + bool IsPreview() const { return Preview; } + bool IsDelivery() const { return Delivery; } +}; + +//----------------------------------------------------------------------------- +// Obsolete functions (Will be removed! Read 'API BREAKING CHANGES' section in imgui.cpp for details) +// Please keep your copy of dear imgui up to date! Occasionally set '#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS' in imconfig.h to stay ahead. +//----------------------------------------------------------------------------- + +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS +namespace ImGui +{ + // OBSOLETED in 1.72 (from July 2019) + static inline void TreeAdvanceToLabelPos() { SetCursorPosX(GetCursorPosX() + GetTreeNodeToLabelSpacing()); } + // OBSOLETED in 1.71 (from June 2019) + static inline void SetNextTreeNodeOpen(bool open, ImGuiCond cond = 0) { SetNextItemOpen(open, cond); } + // OBSOLETED in 1.70 (from May 2019) + static inline float GetContentRegionAvailWidth() { return GetContentRegionAvail().x; } + // OBSOLETED in 1.69 (from Mar 2019) + static inline ImDrawList* GetOverlayDrawList() { return GetForegroundDrawList(); } + // OBSOLETED in 1.66 (from Sep 2018) + static inline void SetScrollHere(float center_ratio=0.5f){ SetScrollHereY(center_ratio); } + // OBSOLETED in 1.63 (between Aug 2018 and Sept 2018) + static inline bool IsItemDeactivatedAfterChange() { return IsItemDeactivatedAfterEdit(); } + // OBSOLETED in 1.61 (between Apr 2018 and Aug 2018) + IMGUI_API bool InputFloat(const char* label, float* v, float step, float step_fast, int decimal_precision, ImGuiInputTextFlags flags = 0); // Use the 'const char* format' version instead of 'decimal_precision'! + IMGUI_API bool InputFloat2(const char* label, float v[2], int decimal_precision, ImGuiInputTextFlags flags = 0); + IMGUI_API bool InputFloat3(const char* label, float v[3], int decimal_precision, ImGuiInputTextFlags flags = 0); + IMGUI_API bool InputFloat4(const char* label, float v[4], int decimal_precision, ImGuiInputTextFlags flags = 0); + // OBSOLETED in 1.60 (between Dec 2017 and Apr 2018) + static inline bool IsAnyWindowFocused() { return IsWindowFocused(ImGuiFocusedFlags_AnyWindow); } + static inline bool IsAnyWindowHovered() { return IsWindowHovered(ImGuiHoveredFlags_AnyWindow); } + static inline ImVec2 CalcItemRectClosestPoint(const ImVec2& pos, bool on_edge = false, float outward = 0.f) { IM_UNUSED(on_edge); IM_UNUSED(outward); IM_ASSERT(0); return pos; } +} +typedef ImGuiInputTextCallback ImGuiTextEditCallback; // OBSOLETED in 1.63 (from Aug 2018): made the names consistent +typedef ImGuiInputTextCallbackData ImGuiTextEditCallbackData; +#endif + +//----------------------------------------------------------------------------- +// Helpers +//----------------------------------------------------------------------------- + +// Helper: Unicode defines +#define IM_UNICODE_CODEPOINT_INVALID 0xFFFD // Invalid Unicode code point (standard value). +#ifdef IMGUI_USE_WCHAR32 +#define IM_UNICODE_CODEPOINT_MAX 0x10FFFF // Maximum Unicode code point supported by this build. +#else +#define IM_UNICODE_CODEPOINT_MAX 0xFFFF // Maximum Unicode code point supported by this build. +#endif + +// Helper: Execute a block of code at maximum once a frame. Convenient if you want to quickly create an UI within deep-nested code that runs multiple times every frame. +// Usage: static ImGuiOnceUponAFrame oaf; if (oaf) ImGui::Text("This will be called only once per frame"); +struct ImGuiOnceUponAFrame +{ + ImGuiOnceUponAFrame() { RefFrame = -1; } + mutable int RefFrame; + operator bool() const { int current_frame = ImGui::GetFrameCount(); if (RefFrame == current_frame) return false; RefFrame = current_frame; return true; } +}; + +// Helper: Parse and apply text filters. In format "aaaaa[,bbbb][,ccccc]" +struct ImGuiTextFilter +{ + IMGUI_API ImGuiTextFilter(const char* default_filter = ""); + IMGUI_API bool Draw(const char* label = "Filter (inc,-exc)", float width = 0.0f); // Helper calling InputText+Build + IMGUI_API bool PassFilter(const char* text, const char* text_end = NULL) const; + IMGUI_API void Build(); + void Clear() { InputBuf[0] = 0; Build(); } + bool IsActive() const { return !Filters.empty(); } + + // [Internal] + struct ImGuiTextRange + { + const char* b; + const char* e; + + ImGuiTextRange() { b = e = NULL; } + ImGuiTextRange(const char* _b, const char* _e) { b = _b; e = _e; } + bool empty() const { return b == e; } + IMGUI_API void split(char separator, ImVector* out) const; + }; + char InputBuf[256]; + ImVectorFilters; + int CountGrep; +}; + +// Helper: Growable text buffer for logging/accumulating text +// (this could be called 'ImGuiTextBuilder' / 'ImGuiStringBuilder') +struct ImGuiTextBuffer +{ + ImVector Buf; + IMGUI_API static char EmptyString[1]; + + ImGuiTextBuffer() { } + inline char operator[](int i) const { IM_ASSERT(Buf.Data != NULL); return Buf.Data[i]; } + const char* begin() const { return Buf.Data ? &Buf.front() : EmptyString; } + const char* end() const { return Buf.Data ? &Buf.back() : EmptyString; } // Buf is zero-terminated, so end() will point on the zero-terminator + int size() const { return Buf.Size ? Buf.Size - 1 : 0; } + bool empty() const { return Buf.Size <= 1; } + void clear() { Buf.clear(); } + void reserve(int capacity) { Buf.reserve(capacity); } + const char* c_str() const { return Buf.Data ? Buf.Data : EmptyString; } + IMGUI_API void append(const char* str, const char* str_end = NULL); + IMGUI_API void appendf(const char* fmt, ...) IM_FMTARGS(2); + IMGUI_API void appendfv(const char* fmt, va_list args) IM_FMTLIST(2); +}; + +// Helper: Key->Value storage +// Typically you don't have to worry about this since a storage is held within each Window. +// We use it to e.g. store collapse state for a tree (Int 0/1) +// This is optimized for efficient lookup (dichotomy into a contiguous buffer) and rare insertion (typically tied to user interactions aka max once a frame) +// You can use it as custom user storage for temporary values. Declare your own storage if, for example: +// - You want to manipulate the open/close state of a particular sub-tree in your interface (tree node uses Int 0/1 to store their state). +// - You want to store custom debug data easily without adding or editing structures in your code (probably not efficient, but convenient) +// Types are NOT stored, so it is up to you to make sure your Key don't collide with different types. +struct ImGuiStorage +{ + // [Internal] + struct ImGuiStoragePair + { + ImGuiID key; + union { int val_i; float val_f; void* val_p; }; + ImGuiStoragePair(ImGuiID _key, int _val_i) { key = _key; val_i = _val_i; } + ImGuiStoragePair(ImGuiID _key, float _val_f) { key = _key; val_f = _val_f; } + ImGuiStoragePair(ImGuiID _key, void* _val_p) { key = _key; val_p = _val_p; } + }; + + ImVector Data; + + // - Get***() functions find pair, never add/allocate. Pairs are sorted so a query is O(log N) + // - Set***() functions find pair, insertion on demand if missing. + // - Sorted insertion is costly, paid once. A typical frame shouldn't need to insert any new pair. + void Clear() { Data.clear(); } + IMGUI_API int GetInt(ImGuiID key, int default_val = 0) const; + IMGUI_API void SetInt(ImGuiID key, int val); + IMGUI_API bool GetBool(ImGuiID key, bool default_val = false) const; + IMGUI_API void SetBool(ImGuiID key, bool val); + IMGUI_API float GetFloat(ImGuiID key, float default_val = 0.0f) const; + IMGUI_API void SetFloat(ImGuiID key, float val); + IMGUI_API void* GetVoidPtr(ImGuiID key) const; // default_val is NULL + IMGUI_API void SetVoidPtr(ImGuiID key, void* val); + + // - Get***Ref() functions finds pair, insert on demand if missing, return pointer. Useful if you intend to do Get+Set. + // - References are only valid until a new value is added to the storage. Calling a Set***() function or a Get***Ref() function invalidates the pointer. + // - A typical use case where this is convenient for quick hacking (e.g. add storage during a live Edit&Continue session if you can't modify existing struct) + // float* pvar = ImGui::GetFloatRef(key); ImGui::SliderFloat("var", pvar, 0, 100.0f); some_var += *pvar; + IMGUI_API int* GetIntRef(ImGuiID key, int default_val = 0); + IMGUI_API bool* GetBoolRef(ImGuiID key, bool default_val = false); + IMGUI_API float* GetFloatRef(ImGuiID key, float default_val = 0.0f); + IMGUI_API void** GetVoidPtrRef(ImGuiID key, void* default_val = NULL); + + // Use on your own storage if you know only integer are being stored (open/close all tree nodes) + IMGUI_API void SetAllInt(int val); + + // For quicker full rebuild of a storage (instead of an incremental one), you may add all your contents and then sort once. + IMGUI_API void BuildSortByKey(); +}; + +// Helper: Manually clip large list of items. +// If you are submitting lots of evenly spaced items and you have a random access to the list, you can perform coarse clipping based on visibility to save yourself from processing those items at all. +// The clipper calculates the range of visible items and advance the cursor to compensate for the non-visible items we have skipped. +// ImGui already clip items based on their bounds but it needs to measure text size to do so. Coarse clipping before submission makes this cost and your own data fetching/submission cost null. +// Usage: +// ImGuiListClipper clipper(1000); // we have 1000 elements, evenly spaced. +// while (clipper.Step()) +// for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) +// ImGui::Text("line number %d", i); +// - Step 0: the clipper let you process the first element, regardless of it being visible or not, so we can measure the element height (step skipped if we passed a known height as second arg to constructor). +// - Step 1: the clipper infer height from first element, calculate the actual range of elements to display, and position the cursor before the first element. +// - (Step 2: dummy step only required if an explicit items_height was passed to constructor or Begin() and user call Step(). Does nothing and switch to Step 3.) +// - Step 3: the clipper validate that we have reached the expected Y position (corresponding to element DisplayEnd), advance the cursor to the end of the list and then returns 'false' to end the loop. +struct ImGuiListClipper +{ + int DisplayStart, DisplayEnd; + int ItemsCount; + + // [Internal] + int StepNo; + float ItemsHeight; + float StartPosY; + + // items_count: Use -1 to ignore (you can call Begin later). Use INT_MAX if you don't know how many items you have (in which case the cursor won't be advanced in the final step). + // items_height: Use -1.0f to be calculated automatically on first step. Otherwise pass in the distance between your items, typically GetTextLineHeightWithSpacing() or GetFrameHeightWithSpacing(). + // If you don't specify an items_height, you NEED to call Step(). If you specify items_height you may call the old Begin()/End() api directly, but prefer calling Step(). + ImGuiListClipper(int items_count = -1, float items_height = -1.0f) { Begin(items_count, items_height); } // NB: Begin() initialize every fields (as we allow user to call Begin/End multiple times on a same instance if they want). + ~ImGuiListClipper() { IM_ASSERT(ItemsCount == -1); } // Assert if user forgot to call End() or Step() until false. + + IMGUI_API bool Step(); // Call until it returns false. The DisplayStart/DisplayEnd fields will be set and you can process/draw those items. + IMGUI_API void Begin(int items_count, float items_height = -1.0f); // Automatically called by constructor if you passed 'items_count' or by Step() in Step 1. + IMGUI_API void End(); // Automatically called on the last call of Step() that returns false. +}; + +// Helpers macros to generate 32-bit encoded colors +#ifdef IMGUI_USE_BGRA_PACKED_COLOR +#define IM_COL32_R_SHIFT 16 +#define IM_COL32_G_SHIFT 8 +#define IM_COL32_B_SHIFT 0 +#define IM_COL32_A_SHIFT 24 +#define IM_COL32_A_MASK 0xFF000000 +#else +#define IM_COL32_R_SHIFT 0 +#define IM_COL32_G_SHIFT 8 +#define IM_COL32_B_SHIFT 16 +#define IM_COL32_A_SHIFT 24 +#define IM_COL32_A_MASK 0xFF000000 +#endif +#define IM_COL32(R,G,B,A) (((ImU32)(A)<>IM_COL32_R_SHIFT)&0xFF) * sc; Value.y = (float)((rgba>>IM_COL32_G_SHIFT)&0xFF) * sc; Value.z = (float)((rgba>>IM_COL32_B_SHIFT)&0xFF) * sc; Value.w = (float)((rgba>>IM_COL32_A_SHIFT)&0xFF) * sc; } + ImColor(float r, float g, float b, float a = 1.0f) { Value.x = r; Value.y = g; Value.z = b; Value.w = a; } + ImColor(const ImVec4& col) { Value = col; } + inline operator ImU32() const { return ImGui::ColorConvertFloat4ToU32(Value); } + inline operator ImVec4() const { return Value; } + + // FIXME-OBSOLETE: May need to obsolete/cleanup those helpers. + inline void SetHSV(float h, float s, float v, float a = 1.0f){ ImGui::ColorConvertHSVtoRGB(h, s, v, Value.x, Value.y, Value.z); Value.w = a; } + static ImColor HSV(float h, float s, float v, float a = 1.0f) { float r,g,b; ImGui::ColorConvertHSVtoRGB(h, s, v, r, g, b); return ImColor(r,g,b,a); } +}; + +//----------------------------------------------------------------------------- +// Draw List API (ImDrawCmd, ImDrawIdx, ImDrawVert, ImDrawChannel, ImDrawListSplitter, ImDrawListFlags, ImDrawList, ImDrawData) +// Hold a series of drawing commands. The user provides a renderer for ImDrawData which essentially contains an array of ImDrawList. +//----------------------------------------------------------------------------- + +// ImDrawCallback: Draw callbacks for advanced uses [configurable type: override in imconfig.h] +// NB: You most likely do NOT need to use draw callbacks just to create your own widget or customized UI rendering, +// you can poke into the draw list for that! Draw callback may be useful for example to: +// A) Change your GPU render state, +// B) render a complex 3D scene inside a UI element without an intermediate texture/render target, etc. +// The expected behavior from your rendering function is 'if (cmd.UserCallback != NULL) { cmd.UserCallback(parent_list, cmd); } else { RenderTriangles() }' +// If you want to override the signature of ImDrawCallback, you can simply use e.g. '#define ImDrawCallback MyDrawCallback' (in imconfig.h) + update rendering back-end accordingly. +#ifndef ImDrawCallback +typedef void (*ImDrawCallback)(const ImDrawList* parent_list, const ImDrawCmd* cmd); +#endif + +// Special Draw callback value to request renderer back-end to reset the graphics/render state. +// The renderer back-end needs to handle this special value, otherwise it will crash trying to call a function at this address. +// This is useful for example if you submitted callbacks which you know have altered the render state and you want it to be restored. +// It is not done by default because they are many perfectly useful way of altering render state for imgui contents (e.g. changing shader/blending settings before an Image call). +#define ImDrawCallback_ResetRenderState (ImDrawCallback)(-1) + +// Typically, 1 command = 1 GPU draw call (unless command is a callback) +// Pre 1.71 back-ends will typically ignore the VtxOffset/IdxOffset fields. When 'io.BackendFlags & ImGuiBackendFlags_RendererHasVtxOffset' +// is enabled, those fields allow us to render meshes larger than 64K vertices while keeping 16-bit indices. +struct ImDrawCmd +{ + unsigned int ElemCount; // Number of indices (multiple of 3) to be rendered as triangles. Vertices are stored in the callee ImDrawList's vtx_buffer[] array, indices in idx_buffer[]. + ImVec4 ClipRect; // Clipping rectangle (x1, y1, x2, y2). Subtract ImDrawData->DisplayPos to get clipping rectangle in "viewport" coordinates + ImTextureID TextureId; // User-provided texture ID. Set by user in ImfontAtlas::SetTexID() for fonts or passed to Image*() functions. Ignore if never using images or multiple fonts atlas. + unsigned int VtxOffset; // Start offset in vertex buffer. Pre-1.71 or without ImGuiBackendFlags_RendererHasVtxOffset: always 0. With ImGuiBackendFlags_RendererHasVtxOffset: may be >0 to support meshes larger than 64K vertices with 16-bit indices. + unsigned int IdxOffset; // Start offset in index buffer. Always equal to sum of ElemCount drawn so far. + ImDrawCallback UserCallback; // If != NULL, call the function instead of rendering the vertices. clip_rect and texture_id will be set normally. + void* UserCallbackData; // The draw callback code can access this. + + ImDrawCmd() { ElemCount = 0; TextureId = (ImTextureID)NULL; VtxOffset = IdxOffset = 0; UserCallback = NULL; UserCallbackData = NULL; } +}; + +// Vertex index, default to 16-bit +// To allow large meshes with 16-bit indices: set 'io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset' and handle ImDrawCmd::VtxOffset in the renderer back-end (recommended). +// To use 32-bit indices: override with '#define ImDrawIdx unsigned int' in imconfig.h. +#ifndef ImDrawIdx +typedef unsigned short ImDrawIdx; +#endif + +// Vertex layout +#ifndef IMGUI_OVERRIDE_DRAWVERT_STRUCT_LAYOUT +struct ImDrawVert +{ + ImVec2 pos; + ImVec2 uv; + ImU32 col; +}; +#else +// You can override the vertex format layout by defining IMGUI_OVERRIDE_DRAWVERT_STRUCT_LAYOUT in imconfig.h +// The code expect ImVec2 pos (8 bytes), ImVec2 uv (8 bytes), ImU32 col (4 bytes), but you can re-order them or add other fields as needed to simplify integration in your engine. +// The type has to be described within the macro (you can either declare the struct or use a typedef). This is because ImVec2/ImU32 are likely not declared a the time you'd want to set your type up. +// NOTE: IMGUI DOESN'T CLEAR THE STRUCTURE AND DOESN'T CALL A CONSTRUCTOR SO ANY CUSTOM FIELD WILL BE UNINITIALIZED. IF YOU ADD EXTRA FIELDS (SUCH AS A 'Z' COORDINATES) YOU WILL NEED TO CLEAR THEM DURING RENDER OR TO IGNORE THEM. +IMGUI_OVERRIDE_DRAWVERT_STRUCT_LAYOUT; +#endif + +// For use by ImDrawListSplitter. +struct ImDrawChannel +{ + ImVector _CmdBuffer; + ImVector _IdxBuffer; +}; + +// Split/Merge functions are used to split the draw list into different layers which can be drawn into out of order. +// This is used by the Columns api, so items of each column can be batched together in a same draw call. +struct ImDrawListSplitter +{ + int _Current; // Current channel number (0) + int _Count; // Number of active channels (1+) + ImVector _Channels; // Draw channels (not resized down so _Count might be < Channels.Size) + + inline ImDrawListSplitter() { Clear(); } + inline ~ImDrawListSplitter() { ClearFreeMemory(); } + inline void Clear() { _Current = 0; _Count = 1; } // Do not clear Channels[] so our allocations are reused next frame + IMGUI_API void ClearFreeMemory(); + IMGUI_API void Split(ImDrawList* draw_list, int count); + IMGUI_API void Merge(ImDrawList* draw_list); + IMGUI_API void SetCurrentChannel(ImDrawList* draw_list, int channel_idx); +}; + +enum ImDrawCornerFlags_ +{ + ImDrawCornerFlags_None = 0, + ImDrawCornerFlags_TopLeft = 1 << 0, // 0x1 + ImDrawCornerFlags_TopRight = 1 << 1, // 0x2 + ImDrawCornerFlags_BotLeft = 1 << 2, // 0x4 + ImDrawCornerFlags_BotRight = 1 << 3, // 0x8 + ImDrawCornerFlags_Top = ImDrawCornerFlags_TopLeft | ImDrawCornerFlags_TopRight, // 0x3 + ImDrawCornerFlags_Bot = ImDrawCornerFlags_BotLeft | ImDrawCornerFlags_BotRight, // 0xC + ImDrawCornerFlags_Left = ImDrawCornerFlags_TopLeft | ImDrawCornerFlags_BotLeft, // 0x5 + ImDrawCornerFlags_Right = ImDrawCornerFlags_TopRight | ImDrawCornerFlags_BotRight, // 0xA + ImDrawCornerFlags_All = 0xF // In your function calls you may use ~0 (= all bits sets) instead of ImDrawCornerFlags_All, as a convenience +}; + +enum ImDrawListFlags_ +{ + ImDrawListFlags_None = 0, + ImDrawListFlags_AntiAliasedLines = 1 << 0, // Lines are anti-aliased (*2 the number of triangles for 1.0f wide line, otherwise *3 the number of triangles) + ImDrawListFlags_AntiAliasedFill = 1 << 1, // Filled shapes have anti-aliased edges (*2 the number of vertices) + ImDrawListFlags_AllowVtxOffset = 1 << 2 // Can emit 'VtxOffset > 0' to allow large meshes. Set when 'ImGuiBackendFlags_RendererHasVtxOffset' is enabled. +}; + +// Draw command list +// This is the low-level list of polygons that ImGui:: functions are filling. At the end of the frame, +// all command lists are passed to your ImGuiIO::RenderDrawListFn function for rendering. +// Each dear imgui window contains its own ImDrawList. You can use ImGui::GetWindowDrawList() to +// access the current window draw list and draw custom primitives. +// You can interleave normal ImGui:: calls and adding primitives to the current draw list. +// All positions are generally in pixel coordinates (generally top-left at 0,0, bottom-right at io.DisplaySize, unless multiple viewports are used), but you are totally free to apply whatever transformation matrix to want to the data (if you apply such transformation you'll want to apply it to ClipRect as well) +// Important: Primitives are always added to the list and not culled (culling is done at higher-level by ImGui:: functions), if you use this API a lot consider coarse culling your drawn objects. +struct ImDrawList +{ + // This is what you have to render + ImVector CmdBuffer; // Draw commands. Typically 1 command = 1 GPU draw call, unless the command is a callback. + ImVector IdxBuffer; // Index buffer. Each command consume ImDrawCmd::ElemCount of those + ImVector VtxBuffer; // Vertex buffer. + ImDrawListFlags Flags; // Flags, you may poke into these to adjust anti-aliasing settings per-primitive. + + // [Internal, used while building lists] + const ImDrawListSharedData* _Data; // Pointer to shared draw data (you can use ImGui::GetDrawListSharedData() to get the one from current ImGui context) + const char* _OwnerName; // Pointer to owner window's name for debugging + unsigned int _VtxCurrentOffset; // [Internal] Always 0 unless 'Flags & ImDrawListFlags_AllowVtxOffset'. + unsigned int _VtxCurrentIdx; // [Internal] Generally == VtxBuffer.Size unless we are past 64K vertices, in which case this gets reset to 0. + ImDrawVert* _VtxWritePtr; // [Internal] point within VtxBuffer.Data after each add command (to avoid using the ImVector<> operators too much) + ImDrawIdx* _IdxWritePtr; // [Internal] point within IdxBuffer.Data after each add command (to avoid using the ImVector<> operators too much) + ImVector _ClipRectStack; // [Internal] + ImVector _TextureIdStack; // [Internal] + ImVector _Path; // [Internal] current path building + ImDrawListSplitter _Splitter; // [Internal] for channels api + + // If you want to create ImDrawList instances, pass them ImGui::GetDrawListSharedData() or create and use your own ImDrawListSharedData (so you can use ImDrawList without ImGui) + ImDrawList(const ImDrawListSharedData* shared_data) { _Data = shared_data; _OwnerName = NULL; Clear(); } + ~ImDrawList() { ClearFreeMemory(); } + IMGUI_API void PushClipRect(ImVec2 clip_rect_min, ImVec2 clip_rect_max, bool intersect_with_current_clip_rect = false); // Render-level scissoring. This is passed down to your render function but not used for CPU-side coarse clipping. Prefer using higher-level ImGui::PushClipRect() to affect logic (hit-testing and widget culling) + IMGUI_API void PushClipRectFullScreen(); + IMGUI_API void PopClipRect(); + IMGUI_API void PushTextureID(ImTextureID texture_id); + IMGUI_API void PopTextureID(); + inline ImVec2 GetClipRectMin() const { const ImVec4& cr = _ClipRectStack.back(); return ImVec2(cr.x, cr.y); } + inline ImVec2 GetClipRectMax() const { const ImVec4& cr = _ClipRectStack.back(); return ImVec2(cr.z, cr.w); } + + // Primitives + // - For rectangular primitives, "p_min" and "p_max" represent the upper-left and lower-right corners. + // - For circle primitives, use "num_segments == 0" to automatically calculate tessellation (preferred). + // In future versions we will use textures to provide cheaper and higher-quality circles. + // Use AddNgon() and AddNgonFilled() functions if you need to guaranteed a specific number of sides. + IMGUI_API void AddLine(const ImVec2& p1, const ImVec2& p2, ImU32 col, float thickness = 1.0f); + IMGUI_API void AddRect(const ImVec2& p_min, const ImVec2& p_max, ImU32 col, float rounding = 0.0f, ImDrawCornerFlags rounding_corners = ImDrawCornerFlags_All, float thickness = 1.0f); // a: upper-left, b: lower-right (== upper-left + size), rounding_corners_flags: 4 bits corresponding to which corner to round + IMGUI_API void AddRectFilled(const ImVec2& p_min, const ImVec2& p_max, ImU32 col, float rounding = 0.0f, ImDrawCornerFlags rounding_corners = ImDrawCornerFlags_All); // a: upper-left, b: lower-right (== upper-left + size) + IMGUI_API void AddRectFilledMultiColor(const ImVec2& p_min, const ImVec2& p_max, ImU32 col_upr_left, ImU32 col_upr_right, ImU32 col_bot_right, ImU32 col_bot_left); + IMGUI_API void AddQuad(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, ImU32 col, float thickness = 1.0f); + IMGUI_API void AddQuadFilled(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, ImU32 col); + IMGUI_API void AddTriangle(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, ImU32 col, float thickness = 1.0f); + IMGUI_API void AddTriangleFilled(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, ImU32 col); + IMGUI_API void AddCircle(const ImVec2& center, float radius, ImU32 col, int num_segments = 12, float thickness = 1.0f); + IMGUI_API void AddCircleFilled(const ImVec2& center, float radius, ImU32 col, int num_segments = 12); + IMGUI_API void AddNgon(const ImVec2& center, float radius, ImU32 col, int num_segments, float thickness = 1.0f); + IMGUI_API void AddNgonFilled(const ImVec2& center, float radius, ImU32 col, int num_segments); + IMGUI_API void AddText(const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end = NULL); + IMGUI_API void AddText(const ImFont* font, float font_size, const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end = NULL, float wrap_width = 0.0f, const ImVec4* cpu_fine_clip_rect = NULL); + IMGUI_API void AddPolyline(const ImVec2* points, int num_points, ImU32 col, bool closed, float thickness); + IMGUI_API void AddConvexPolyFilled(const ImVec2* points, int num_points, ImU32 col); // Note: Anti-aliased filling requires points to be in clockwise order. + IMGUI_API void AddBezierCurve(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, ImU32 col, float thickness, int num_segments = 0); + + // Image primitives + // - Read FAQ to understand what ImTextureID is. + // - "p_min" and "p_max" represent the upper-left and lower-right corners of the rectangle. + // - "uv_min" and "uv_max" represent the normalized texture coordinates to use for those corners. Using (0,0)->(1,1) texture coordinates will generally display the entire texture. + IMGUI_API void AddImage(ImTextureID user_texture_id, const ImVec2& p_min, const ImVec2& p_max, const ImVec2& uv_min = ImVec2(0, 0), const ImVec2& uv_max = ImVec2(1, 1), ImU32 col = IM_COL32_WHITE); + IMGUI_API void AddImageQuad(ImTextureID user_texture_id, const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, const ImVec2& uv1 = ImVec2(0, 0), const ImVec2& uv2 = ImVec2(1, 0), const ImVec2& uv3 = ImVec2(1, 1), const ImVec2& uv4 = ImVec2(0, 1), ImU32 col = IM_COL32_WHITE); + IMGUI_API void AddImageRounded(ImTextureID user_texture_id, const ImVec2& p_min, const ImVec2& p_max, const ImVec2& uv_min, const ImVec2& uv_max, ImU32 col, float rounding, ImDrawCornerFlags rounding_corners = ImDrawCornerFlags_All); + + // Stateful path API, add points then finish with PathFillConvex() or PathStroke() + inline void PathClear() { _Path.Size = 0; } + inline void PathLineTo(const ImVec2& pos) { _Path.push_back(pos); } + inline void PathLineToMergeDuplicate(const ImVec2& pos) { if (_Path.Size == 0 || memcmp(&_Path.Data[_Path.Size-1], &pos, 8) != 0) _Path.push_back(pos); } + inline void PathFillConvex(ImU32 col) { AddConvexPolyFilled(_Path.Data, _Path.Size, col); _Path.Size = 0; } // Note: Anti-aliased filling requires points to be in clockwise order. + inline void PathStroke(ImU32 col, bool closed, float thickness = 1.0f) { AddPolyline(_Path.Data, _Path.Size, col, closed, thickness); _Path.Size = 0; } + IMGUI_API void PathArcTo(const ImVec2& center, float radius, float a_min, float a_max, int num_segments = 10); + IMGUI_API void PathArcToFast(const ImVec2& center, float radius, int a_min_of_12, int a_max_of_12); // Use precomputed angles for a 12 steps circle + IMGUI_API void PathBezierCurveTo(const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, int num_segments = 0); + IMGUI_API void PathRect(const ImVec2& rect_min, const ImVec2& rect_max, float rounding = 0.0f, ImDrawCornerFlags rounding_corners = ImDrawCornerFlags_All); + + // Advanced + IMGUI_API void AddCallback(ImDrawCallback callback, void* callback_data); // Your rendering function must check for 'UserCallback' in ImDrawCmd and call the function instead of rendering triangles. + IMGUI_API void AddDrawCmd(); // This is useful if you need to forcefully create a new draw call (to allow for dependent rendering / blending). Otherwise primitives are merged into the same draw-call as much as possible + IMGUI_API ImDrawList* CloneOutput() const; // Create a clone of the CmdBuffer/IdxBuffer/VtxBuffer. + + // Advanced: Channels + // - Use to split render into layers. By switching channels to can render out-of-order (e.g. submit FG primitives before BG primitives) + // - Use to minimize draw calls (e.g. if going back-and-forth between multiple clipping rectangles, prefer to append into separate channels then merge at the end) + // - FIXME-OBSOLETE: This API shouldn't have been in ImDrawList in the first place! + // Prefer using your own persistent copy of ImDrawListSplitter as you can stack them. + // Using the ImDrawList::ChannelsXXXX you cannot stack a split over another. + inline void ChannelsSplit(int count) { _Splitter.Split(this, count); } + inline void ChannelsMerge() { _Splitter.Merge(this); } + inline void ChannelsSetCurrent(int n) { _Splitter.SetCurrentChannel(this, n); } + + // Internal helpers + // NB: all primitives needs to be reserved via PrimReserve() beforehand! + IMGUI_API void Clear(); + IMGUI_API void ClearFreeMemory(); + IMGUI_API void PrimReserve(int idx_count, int vtx_count); + IMGUI_API void PrimUnreserve(int idx_count, int vtx_count); + IMGUI_API void PrimRect(const ImVec2& a, const ImVec2& b, ImU32 col); // Axis aligned rectangle (composed of two triangles) + IMGUI_API void PrimRectUV(const ImVec2& a, const ImVec2& b, const ImVec2& uv_a, const ImVec2& uv_b, ImU32 col); + IMGUI_API void PrimQuadUV(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& d, const ImVec2& uv_a, const ImVec2& uv_b, const ImVec2& uv_c, const ImVec2& uv_d, ImU32 col); + inline void PrimWriteVtx(const ImVec2& pos, const ImVec2& uv, ImU32 col){ _VtxWritePtr->pos = pos; _VtxWritePtr->uv = uv; _VtxWritePtr->col = col; _VtxWritePtr++; _VtxCurrentIdx++; } + inline void PrimWriteIdx(ImDrawIdx idx) { *_IdxWritePtr = idx; _IdxWritePtr++; } + inline void PrimVtx(const ImVec2& pos, const ImVec2& uv, ImU32 col) { PrimWriteIdx((ImDrawIdx)_VtxCurrentIdx); PrimWriteVtx(pos, uv, col); } + IMGUI_API void UpdateClipRect(); + IMGUI_API void UpdateTextureID(); +}; + +// All draw data to render a Dear ImGui frame +// (NB: the style and the naming convention here is a little inconsistent, we currently preserve them for backward compatibility purpose, +// as this is one of the oldest structure exposed by the library! Basically, ImDrawList == CmdList) +struct ImDrawData +{ + bool Valid; // Only valid after Render() is called and before the next NewFrame() is called. + ImDrawList** CmdLists; // Array of ImDrawList* to render. The ImDrawList are owned by ImGuiContext and only pointed to from here. + int CmdListsCount; // Number of ImDrawList* to render + int TotalIdxCount; // For convenience, sum of all ImDrawList's IdxBuffer.Size + int TotalVtxCount; // For convenience, sum of all ImDrawList's VtxBuffer.Size + ImVec2 DisplayPos; // Upper-left position of the viewport to render (== upper-left of the orthogonal projection matrix to use) + ImVec2 DisplaySize; // Size of the viewport to render (== io.DisplaySize for the main viewport) (DisplayPos + DisplaySize == lower-right of the orthogonal projection matrix to use) + ImVec2 FramebufferScale; // Amount of pixels for each unit of DisplaySize. Based on io.DisplayFramebufferScale. Generally (1,1) on normal display, (2,2) on OSX with Retina display. + ImGuiViewport* OwnerViewport; // Viewport carrying the ImDrawData instance, might be of use to the renderer (generally not). + + // Functions + ImDrawData() { Valid = false; Clear(); } + ~ImDrawData() { Clear(); } + void Clear() { Valid = false; CmdLists = NULL; CmdListsCount = TotalVtxCount = TotalIdxCount = 0; DisplayPos = DisplaySize = FramebufferScale = ImVec2(0.f, 0.f); OwnerViewport = NULL; } // The ImDrawList are owned by ImGuiContext! + IMGUI_API void DeIndexAllBuffers(); // Helper to convert all buffers from indexed to non-indexed, in case you cannot render indexed. Note: this is slow and most likely a waste of resources. Always prefer indexed rendering! + IMGUI_API void ScaleClipRects(const ImVec2& fb_scale); // Helper to scale the ClipRect field of each ImDrawCmd. Use if your final output buffer is at a different scale than Dear ImGui expects, or if there is a difference between your window resolution and framebuffer resolution. +}; + +//----------------------------------------------------------------------------- +// Font API (ImFontConfig, ImFontGlyph, ImFontAtlasFlags, ImFontAtlas, ImFontGlyphRangesBuilder, ImFont) +//----------------------------------------------------------------------------- + +struct ImFontConfig +{ + void* FontData; // // TTF/OTF data + int FontDataSize; // // TTF/OTF data size + bool FontDataOwnedByAtlas; // true // TTF/OTF data ownership taken by the container ImFontAtlas (will delete memory itself). + int FontNo; // 0 // Index of font within TTF/OTF file + float SizePixels; // // Size in pixels for rasterizer (more or less maps to the resulting font height). + int OversampleH; // 3 // Rasterize at higher quality for sub-pixel positioning. Read https://github.com/nothings/stb/blob/master/tests/oversample/README.md for details. + int OversampleV; // 1 // Rasterize at higher quality for sub-pixel positioning. We don't use sub-pixel positions on the Y axis. + bool PixelSnapH; // false // Align every glyph to pixel boundary. Useful e.g. if you are merging a non-pixel aligned font with the default font. If enabled, you can set OversampleH/V to 1. + ImVec2 GlyphExtraSpacing; // 0, 0 // Extra spacing (in pixels) between glyphs. Only X axis is supported for now. + ImVec2 GlyphOffset; // 0, 0 // Offset all glyphs from this font input. + const ImWchar* GlyphRanges; // NULL // Pointer to a user-provided list of Unicode range (2 value per range, values are inclusive, zero-terminated list). THE ARRAY DATA NEEDS TO PERSIST AS LONG AS THE FONT IS ALIVE. + float GlyphMinAdvanceX; // 0 // Minimum AdvanceX for glyphs, set Min to align font icons, set both Min/Max to enforce mono-space font + float GlyphMaxAdvanceX; // FLT_MAX // Maximum AdvanceX for glyphs + bool MergeMode; // false // Merge into previous ImFont, so you can combine multiple inputs font into one ImFont (e.g. ASCII font + icons + Japanese glyphs). You may want to use GlyphOffset.y when merge font of different heights. + unsigned int RasterizerFlags; // 0x00 // Settings for custom font rasterizer (e.g. ImGuiFreeType). Leave as zero if you aren't using one. + float RasterizerMultiply; // 1.0f // Brighten (>1.0f) or darken (<1.0f) font output. Brightening small fonts may be a good workaround to make them more readable. + ImWchar EllipsisChar; // -1 // Explicitly specify unicode codepoint of ellipsis character. When fonts are being merged first specified ellipsis will be used. + + // [Internal] + char Name[40]; // Name (strictly to ease debugging) + ImFont* DstFont; + + IMGUI_API ImFontConfig(); +}; + +// Hold rendering data for one glyph. +// (Note: some language parsers may fail to convert the 31+1 bitfield members, in this case maybe drop store a single u32 or we can rework this) +struct ImFontGlyph +{ + unsigned int Codepoint : 31; // 0x0000..0xFFFF + unsigned int Visible : 1; // Flag to allow early out when rendering + float AdvanceX; // Distance to next character (= data from font + ImFontConfig::GlyphExtraSpacing.x baked in) + float X0, Y0, X1, Y1; // Glyph corners + float U0, V0, U1, V1; // Texture coordinates +}; + +// Helper to build glyph ranges from text/string data. Feed your application strings/characters to it then call BuildRanges(). +// This is essentially a tightly packed of vector of 64k booleans = 8KB storage. +struct ImFontGlyphRangesBuilder +{ + ImVector UsedChars; // Store 1-bit per Unicode code point (0=unused, 1=used) + + ImFontGlyphRangesBuilder() { Clear(); } + inline void Clear() { int size_in_bytes = (IM_UNICODE_CODEPOINT_MAX + 1) / 8; UsedChars.resize(size_in_bytes / (int)sizeof(ImU32)); memset(UsedChars.Data, 0, (size_t)size_in_bytes); } + inline bool GetBit(size_t n) const { int off = (int)(n >> 5); ImU32 mask = 1u << (n & 31); return (UsedChars[off] & mask) != 0; } // Get bit n in the array + inline void SetBit(size_t n) { int off = (int)(n >> 5); ImU32 mask = 1u << (n & 31); UsedChars[off] |= mask; } // Set bit n in the array + inline void AddChar(ImWchar c) { SetBit(c); } // Add character + IMGUI_API void AddText(const char* text, const char* text_end = NULL); // Add string (each character of the UTF-8 string are added) + IMGUI_API void AddRanges(const ImWchar* ranges); // Add ranges, e.g. builder.AddRanges(ImFontAtlas::GetGlyphRangesDefault()) to force add all of ASCII/Latin+Ext + IMGUI_API void BuildRanges(ImVector* out_ranges); // Output new ranges +}; + +// See ImFontAtlas::AddCustomRectXXX functions. +struct ImFontAtlasCustomRect +{ + unsigned short Width, Height; // Input // Desired rectangle dimension + unsigned short X, Y; // Output // Packed position in Atlas + unsigned int GlyphID; // Input // For custom font glyphs only (ID < 0x110000) + float GlyphAdvanceX; // Input // For custom font glyphs only: glyph xadvance + ImVec2 GlyphOffset; // Input // For custom font glyphs only: glyph display offset + ImFont* Font; // Input // For custom font glyphs only: target font + ImFontAtlasCustomRect() { Width = Height = 0; X = Y = 0xFFFF; GlyphID = 0; GlyphAdvanceX = 0.0f; GlyphOffset = ImVec2(0,0); Font = NULL; } + bool IsPacked() const { return X != 0xFFFF; } +}; + +enum ImFontAtlasFlags_ +{ + ImFontAtlasFlags_None = 0, + ImFontAtlasFlags_NoPowerOfTwoHeight = 1 << 0, // Don't round the height to next power of two + ImFontAtlasFlags_NoMouseCursors = 1 << 1 // Don't build software mouse cursors into the atlas +}; + +// Load and rasterize multiple TTF/OTF fonts into a same texture. The font atlas will build a single texture holding: +// - One or more fonts. +// - Custom graphics data needed to render the shapes needed by Dear ImGui. +// - Mouse cursor shapes for software cursor rendering (unless setting 'Flags |= ImFontAtlasFlags_NoMouseCursors' in the font atlas). +// It is the user-code responsibility to setup/build the atlas, then upload the pixel data into a texture accessible by your graphics api. +// - Optionally, call any of the AddFont*** functions. If you don't call any, the default font embedded in the code will be loaded for you. +// - Call GetTexDataAsAlpha8() or GetTexDataAsRGBA32() to build and retrieve pixels data. +// - Upload the pixels data into a texture within your graphics system (see imgui_impl_xxxx.cpp examples) +// - Call SetTexID(my_tex_id); and pass the pointer/identifier to your texture in a format natural to your graphics API. +// This value will be passed back to you during rendering to identify the texture. Read FAQ entry about ImTextureID for more details. +// Common pitfalls: +// - If you pass a 'glyph_ranges' array to AddFont*** functions, you need to make sure that your array persist up until the +// atlas is build (when calling GetTexData*** or Build()). We only copy the pointer, not the data. +// - Important: By default, AddFontFromMemoryTTF() takes ownership of the data. Even though we are not writing to it, we will free the pointer on destruction. +// You can set font_cfg->FontDataOwnedByAtlas=false to keep ownership of your data and it won't be freed, +// - Even though many functions are suffixed with "TTF", OTF data is supported just as well. +// - This is an old API and it is currently awkward for those and and various other reasons! We will address them in the future! +struct ImFontAtlas +{ + IMGUI_API ImFontAtlas(); + IMGUI_API ~ImFontAtlas(); + IMGUI_API ImFont* AddFont(const ImFontConfig* font_cfg); + IMGUI_API ImFont* AddFontDefault(const ImFontConfig* font_cfg = NULL); + IMGUI_API ImFont* AddFontFromFileTTF(const char* filename, float size_pixels, const ImFontConfig* font_cfg = NULL, const ImWchar* glyph_ranges = NULL); + IMGUI_API ImFont* AddFontFromMemoryTTF(void* font_data, int font_size, float size_pixels, const ImFontConfig* font_cfg = NULL, const ImWchar* glyph_ranges = NULL); // Note: Transfer ownership of 'ttf_data' to ImFontAtlas! Will be deleted after destruction of the atlas. Set font_cfg->FontDataOwnedByAtlas=false to keep ownership of your data and it won't be freed. + IMGUI_API ImFont* AddFontFromMemoryCompressedTTF(const void* compressed_font_data, int compressed_font_size, float size_pixels, const ImFontConfig* font_cfg = NULL, const ImWchar* glyph_ranges = NULL); // 'compressed_font_data' still owned by caller. Compress with binary_to_compressed_c.cpp. + IMGUI_API ImFont* AddFontFromMemoryCompressedBase85TTF(const char* compressed_font_data_base85, float size_pixels, const ImFontConfig* font_cfg = NULL, const ImWchar* glyph_ranges = NULL); // 'compressed_font_data_base85' still owned by caller. Compress with binary_to_compressed_c.cpp with -base85 parameter. + IMGUI_API void ClearInputData(); // Clear input data (all ImFontConfig structures including sizes, TTF data, glyph ranges, etc.) = all the data used to build the texture and fonts. + IMGUI_API void ClearTexData(); // Clear output texture data (CPU side). Saves RAM once the texture has been copied to graphics memory. + IMGUI_API void ClearFonts(); // Clear output font data (glyphs storage, UV coordinates). + IMGUI_API void Clear(); // Clear all input and output. + + // Build atlas, retrieve pixel data. + // User is in charge of copying the pixels into graphics memory (e.g. create a texture with your engine). Then store your texture handle with SetTexID(). + // The pitch is always = Width * BytesPerPixels (1 or 4) + // Building in RGBA32 format is provided for convenience and compatibility, but note that unless you manually manipulate or copy color data into + // the texture (e.g. when using the AddCustomRect*** api), then the RGB pixels emitted will always be white (~75% of memory/bandwidth waste. + IMGUI_API bool Build(); // Build pixels data. This is called automatically for you by the GetTexData*** functions. + IMGUI_API void GetTexDataAsAlpha8(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel = NULL); // 1 byte per-pixel + IMGUI_API void GetTexDataAsRGBA32(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel = NULL); // 4 bytes-per-pixel + bool IsBuilt() const { return Fonts.Size > 0 && (TexPixelsAlpha8 != NULL || TexPixelsRGBA32 != NULL); } + void SetTexID(ImTextureID id) { TexID = id; } + + //------------------------------------------- + // Glyph Ranges + //------------------------------------------- + + // Helpers to retrieve list of common Unicode ranges (2 value per range, values are inclusive, zero-terminated list) + // NB: Make sure that your string are UTF-8 and NOT in your local code page. In C++11, you can create UTF-8 string literal using the u8"Hello world" syntax. See FAQ for details. + // NB: Consider using ImFontGlyphRangesBuilder to build glyph ranges from textual data. + IMGUI_API const ImWchar* GetGlyphRangesDefault(); // Basic Latin, Extended Latin + IMGUI_API const ImWchar* GetGlyphRangesKorean(); // Default + Korean characters + IMGUI_API const ImWchar* GetGlyphRangesJapanese(); // Default + Hiragana, Katakana, Half-Width, Selection of 1946 Ideographs + IMGUI_API const ImWchar* GetGlyphRangesChineseFull(); // Default + Half-Width + Japanese Hiragana/Katakana + full set of about 21000 CJK Unified Ideographs + IMGUI_API const ImWchar* GetGlyphRangesChineseSimplifiedCommon();// Default + Half-Width + Japanese Hiragana/Katakana + set of 2500 CJK Unified Ideographs for common simplified Chinese + IMGUI_API const ImWchar* GetGlyphRangesCyrillic(); // Default + about 400 Cyrillic characters + IMGUI_API const ImWchar* GetGlyphRangesThai(); // Default + Thai characters + IMGUI_API const ImWchar* GetGlyphRangesVietnamese(); // Default + Vietnamese characters + + //------------------------------------------- + // [BETA] Custom Rectangles/Glyphs API + //------------------------------------------- + + // You can request arbitrary rectangles to be packed into the atlas, for your own purposes. + // After calling Build(), you can query the rectangle position and render your pixels. + // You can also request your rectangles to be mapped as font glyph (given a font + Unicode point), + // so you can render e.g. custom colorful icons and use them as regular glyphs. + // Read docs/FONTS.txt for more details about using colorful icons. + // Note: this API may be redesigned later in order to support multi-monitor varying DPI settings. + IMGUI_API int AddCustomRectRegular(int width, int height); + IMGUI_API int AddCustomRectFontGlyph(ImFont* font, ImWchar id, int width, int height, float advance_x, const ImVec2& offset = ImVec2(0,0)); + const ImFontAtlasCustomRect*GetCustomRectByIndex(int index) const { if (index < 0) return NULL; return &CustomRects[index]; } + + // [Internal] + IMGUI_API void CalcCustomRectUV(const ImFontAtlasCustomRect* rect, ImVec2* out_uv_min, ImVec2* out_uv_max) const; + IMGUI_API bool GetMouseCursorTexData(ImGuiMouseCursor cursor, ImVec2* out_offset, ImVec2* out_size, ImVec2 out_uv_border[2], ImVec2 out_uv_fill[2]); + + //------------------------------------------- + // Members + //------------------------------------------- + + bool Locked; // Marked as Locked by ImGui::NewFrame() so attempt to modify the atlas will assert. + ImFontAtlasFlags Flags; // Build flags (see ImFontAtlasFlags_) + ImTextureID TexID; // User data to refer to the texture once it has been uploaded to user's graphic systems. It is passed back to you during rendering via the ImDrawCmd structure. + int TexDesiredWidth; // Texture width desired by user before Build(). Must be a power-of-two. If have many glyphs your graphics API have texture size restrictions you may want to increase texture width to decrease height. + int TexGlyphPadding; // Padding between glyphs within texture in pixels. Defaults to 1. If your rendering method doesn't rely on bilinear filtering you may set this to 0. + + // [Internal] + // NB: Access texture data via GetTexData*() calls! Which will setup a default font for you. + unsigned char* TexPixelsAlpha8; // 1 component per pixel, each component is unsigned 8-bit. Total size = TexWidth * TexHeight + unsigned int* TexPixelsRGBA32; // 4 component per pixel, each component is unsigned 8-bit. Total size = TexWidth * TexHeight * 4 + int TexWidth; // Texture width calculated during Build(). + int TexHeight; // Texture height calculated during Build(). + ImVec2 TexUvScale; // = (1.0f/TexWidth, 1.0f/TexHeight) + ImVec2 TexUvWhitePixel; // Texture coordinates to a white pixel + ImVector Fonts; // Hold all the fonts returned by AddFont*. Fonts[0] is the default font upon calling ImGui::NewFrame(), use ImGui::PushFont()/PopFont() to change the current font. + ImVector CustomRects; // Rectangles for packing custom texture data into the atlas. + ImVector ConfigData; // Internal data + int CustomRectIds[1]; // Identifiers of custom texture rectangle used by ImFontAtlas/ImDrawList + +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + typedef ImFontAtlasCustomRect CustomRect; // OBSOLETED in 1.72+ + typedef ImFontGlyphRangesBuilder GlyphRangesBuilder; // OBSOLETED in 1.67+ +#endif +}; + +// Font runtime data and rendering +// ImFontAtlas automatically loads a default embedded font for you when you call GetTexDataAsAlpha8() or GetTexDataAsRGBA32(). +struct ImFont +{ + // Members: Hot ~20/24 bytes (for CalcTextSize) + ImVector IndexAdvanceX; // 12-16 // out // // Sparse. Glyphs->AdvanceX in a directly indexable way (cache-friendly for CalcTextSize functions which only this this info, and are often bottleneck in large UI). + float FallbackAdvanceX; // 4 // out // = FallbackGlyph->AdvanceX + float FontSize; // 4 // in // // Height of characters/line, set during loading (don't change after loading) + + // Members: Hot ~36/48 bytes (for CalcTextSize + render loop) + ImVector IndexLookup; // 12-16 // out // // Sparse. Index glyphs by Unicode code-point. + ImVector Glyphs; // 12-16 // out // // All glyphs. + const ImFontGlyph* FallbackGlyph; // 4-8 // out // = FindGlyph(FontFallbackChar) + ImVec2 DisplayOffset; // 8 // in // = (0,0) // Offset font rendering by xx pixels + + // Members: Cold ~32/40 bytes + ImFontAtlas* ContainerAtlas; // 4-8 // out // // What we has been loaded into + const ImFontConfig* ConfigData; // 4-8 // in // // Pointer within ContainerAtlas->ConfigData + short ConfigDataCount; // 2 // in // ~ 1 // Number of ImFontConfig involved in creating this font. Bigger than 1 when merging multiple font sources into one ImFont. + ImWchar FallbackChar; // 2 // in // = '?' // Replacement character if a glyph isn't found. Only set via SetFallbackChar() + ImWchar EllipsisChar; // 2 // out // = -1 // Character used for ellipsis rendering. + bool DirtyLookupTables; // 1 // out // + float Scale; // 4 // in // = 1.f // Base font scale, multiplied by the per-window font scale which you can adjust with SetWindowFontScale() + float Ascent, Descent; // 4+4 // out // // Ascent: distance from top to bottom of e.g. 'A' [0..FontSize] + int MetricsTotalSurface;// 4 // out // // Total surface in pixels to get an idea of the font rasterization/texture cost (not exact, we approximate the cost of padding between glyphs) + ImU8 Used4kPagesMap[(IM_UNICODE_CODEPOINT_MAX+1)/4096/8]; // 2 bytes if ImWchar=ImWchar16, 34 bytes if ImWchar==ImWchar32. Store 1-bit for each block of 4K codepoints that has one active glyph. This is mainly used to facilitate iterations across all used codepoints. + + // Methods + IMGUI_API ImFont(); + IMGUI_API ~ImFont(); + IMGUI_API const ImFontGlyph*FindGlyph(ImWchar c) const; + IMGUI_API const ImFontGlyph*FindGlyphNoFallback(ImWchar c) const; + float GetCharAdvance(ImWchar c) const { return ((int)c < IndexAdvanceX.Size) ? IndexAdvanceX[(int)c] : FallbackAdvanceX; } + bool IsLoaded() const { return ContainerAtlas != NULL; } + const char* GetDebugName() const { return ConfigData ? ConfigData->Name : ""; } + + // 'max_width' stops rendering after a certain width (could be turned into a 2d size). FLT_MAX to disable. + // 'wrap_width' enable automatic word-wrapping across multiple lines to fit into given width. 0.0f to disable. + IMGUI_API ImVec2 CalcTextSizeA(float size, float max_width, float wrap_width, const char* text_begin, const char* text_end = NULL, const char** remaining = NULL) const; // utf8 + IMGUI_API const char* CalcWordWrapPositionA(float scale, const char* text, const char* text_end, float wrap_width) const; + IMGUI_API void RenderChar(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col, ImWchar c) const; + IMGUI_API void RenderText(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col, const ImVec4& clip_rect, const char* text_begin, const char* text_end, float wrap_width = 0.0f, bool cpu_fine_clip = false) const; + + // [Internal] Don't use! + IMGUI_API void BuildLookupTable(); + IMGUI_API void ClearOutputData(); + IMGUI_API void GrowIndex(int new_size); + IMGUI_API void AddGlyph(ImWchar c, float x0, float y0, float x1, float y1, float u0, float v0, float u1, float v1, float advance_x); + IMGUI_API void AddRemapChar(ImWchar dst, ImWchar src, bool overwrite_dst = true); // Makes 'dst' character/glyph points to 'src' character/glyph. Currently needs to be called AFTER fonts have been built. + IMGUI_API void SetGlyphVisible(ImWchar c, bool visible); + IMGUI_API void SetFallbackChar(ImWchar c); + IMGUI_API bool IsGlyphRangeUnused(unsigned int c_begin, unsigned int c_last); +}; + +//----------------------------------------------------------------------------- +// [BETA] Platform interface for multi-viewport support +//----------------------------------------------------------------------------- +// (Optional) This is completely optional, for advanced users! +// If you are new to Dear ImGui and trying to integrate it into your engine, you can probably ignore this for now. +// +// This feature allows you to seamlessly drag Dear ImGui windows outside of your application viewport. +// This is achieved by creating new Platform/OS windows on the fly, and rendering into them. +// Dear ImGui manages the viewport structures, and the back-end create and maintain one Platform/OS window for each of those viewports. +// +// See Glossary https://github.com/ocornut/imgui/wiki/Glossary for details about some of the terminology. +// See Thread https://github.com/ocornut/imgui/issues/1542 for gifs, news and questions about this evolving feature. +// +// About the coordinates system: +// - When multi-viewports are enabled, all Dear ImGui coordinates become absolute coordinates (same as OS coordinates!) +// - So e.g. ImGui::SetNextWindowPos(ImVec2(0,0)) will position a window relative to your primary monitor! +// - If you want to position windows relative to your main application viewport, use ImGui::GetMainViewport()->Pos as a base position. +// +// Steps to use multi-viewports in your application, when using a default back-end from the examples/ folder: +// - Application: Enable feature with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'. +// - Back-end: The back-end initialization will setup all necessary ImGuiPlatformIO's functions and update monitors info every frame. +// - Application: In your main loop, call ImGui::UpdatePlatformWindows(), ImGui::RenderPlatformWindowsDefault() after EndFrame() or Render(). +// - Application: Fix absolute coordinates used in ImGui::SetWindowPos() or ImGui::SetNextWindowPos() calls. +// +// Steps to use multi-viewports in your application, when using a custom back-end: +// - Important: THIS IS NOT EASY TO DO and comes with many subtleties not described here! +// It's also an experimental feature, so some of the requirements may evolve. +// Consider using default back-ends if you can. Either way, carefully follow and refer to examples/ back-ends for details. +// - Application: Enable feature with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'. +// - Back-end: Hook ImGuiPlatformIO's Platform_* and Renderer_* callbacks (see below). +// Set 'io.BackendFlags |= ImGuiBackendFlags_PlatformHasViewports' and 'io.BackendFlags |= ImGuiBackendFlags_PlatformHasViewports'. +// Update ImGuiPlatformIO's Monitors list every frame. +// Update MousePos every frame, in absolute coordinates. +// - Application: In your main loop, call ImGui::UpdatePlatformWindows(), ImGui::RenderPlatformWindowsDefault() after EndFrame() or Render(). +// You may skip calling RenderPlatformWindowsDefault() if its API is not convenient for your needs. Read comments below. +// - Application: Fix absolute coordinates used in ImGui::SetWindowPos() or ImGui::SetNextWindowPos() calls. +// +// About ImGui::RenderPlatformWindowsDefault(): +// - This function is a mostly a _helper_ for the common-most cases, and to facilitate using default back-ends. +// - You can check its simple source code to understand what it does. +// It basically iterates secondary viewports and call 4 functions that are setup in ImGuiPlatformIO, if available: +// Platform_RenderWindow(), Renderer_RenderWindow(), Platform_SwapBuffers(), Renderer_SwapBuffers() +// Those functions pointers exists only for the benefit of RenderPlatformWindowsDefault(). +// - If you have very specific rendering needs (e.g. flipping multiple swap-chain simultaneously, unusual sync/threading issues, etc.), +// you may be tempted to ignore RenderPlatformWindowsDefault() and write customized code to perform your renderingg. +// You may decide to setup the platform_io's *RenderWindow and *SwapBuffers pointers and call your functions through those pointers, +// or you may decide to never setup those pointers and call your code directly. They are a convenience, not an obligatory interface. +//----------------------------------------------------------------------------- + +// (Optional) Access via ImGui::GetPlatformIO() +struct ImGuiPlatformIO +{ + //------------------------------------------------------------------ + // Input - Back-end interface/functions + Monitor List + //------------------------------------------------------------------ + + // (Optional) Platform functions (e.g. Win32, GLFW, SDL2) + // For reference, the second column shows which function are generally calling the Platform Functions: + // N = ImGui::NewFrame() ~ beginning of the dear imgui frame: read info from platform/OS windows (latest size/position) + // F = ImGui::Begin(), ImGui::EndFrame() ~ during the dear imgui frame + // U = ImGui::UpdatePlatformWindows() ~ after the dear imgui frame: create and update all platform/OS windows + // R = ImGui::RenderPlatformWindowsDefault() ~ render + // D = ImGui::DestroyPlatformWindows() ~ shutdown + // The general idea is that NewFrame() we will read the current Platform/OS state, and UpdatePlatformWindows() will write to it. + // + // The functions are designed so we can mix and match 2 imgui_impl_xxxx files, one for the Platform (~window/input handling), one for Renderer. + // Custom engine back-ends will often provide both Platform and Renderer interfaces and so may not need to use all functions. + // Platform functions are typically called before their Renderer counterpart, apart from Destroy which are called the other way. + + // Platform function --------------------------------------------------- Called by ----- + void (*Platform_CreateWindow)(ImGuiViewport* vp); // . . U . . // Create a new platform window for the given viewport + void (*Platform_DestroyWindow)(ImGuiViewport* vp); // N . U . D // + void (*Platform_ShowWindow)(ImGuiViewport* vp); // . . U . . // Newly created windows are initially hidden so SetWindowPos/Size/Title can be called on them before showing the window + void (*Platform_SetWindowPos)(ImGuiViewport* vp, ImVec2 pos); // . . U . . // Set platform window position (given the upper-left corner of client area) + ImVec2 (*Platform_GetWindowPos)(ImGuiViewport* vp); // N . . . . // + void (*Platform_SetWindowSize)(ImGuiViewport* vp, ImVec2 size); // . . U . . // Set platform window client area size (ignoring OS decorations such as OS title bar etc.) + ImVec2 (*Platform_GetWindowSize)(ImGuiViewport* vp); // N . . . . // Get platform window client area size + void (*Platform_SetWindowFocus)(ImGuiViewport* vp); // N . . . . // Move window to front and set input focus + bool (*Platform_GetWindowFocus)(ImGuiViewport* vp); // . . U . . // + bool (*Platform_GetWindowMinimized)(ImGuiViewport* vp); // N . . . . // Get platform window minimized state. When minimized, we generally won't attempt to get/set size and contents will be culled more easily + void (*Platform_SetWindowTitle)(ImGuiViewport* vp, const char* str); // . . U . . // Set platform window title (given an UTF-8 string) + void (*Platform_SetWindowAlpha)(ImGuiViewport* vp, float alpha); // . . U . . // (Optional) Setup window transparency + void (*Platform_UpdateWindow)(ImGuiViewport* vp); // . . U . . // (Optional) Called by UpdatePlatformWindows(). Optional hook to allow the platform back-end from doing general book-keeping every frame. + void (*Platform_RenderWindow)(ImGuiViewport* vp, void* render_arg); // . . . R . // (Optional) Main rendering (platform side! This is often unused, or just setting a "current" context for OpenGL bindings). 'render_arg' is the value passed to RenderPlatformWindowsDefault(). + void (*Platform_SwapBuffers)(ImGuiViewport* vp, void* render_arg); // . . . R . // (Optional) Call Present/SwapBuffers (platform side! This is often unused!). 'render_arg' is the value passed to RenderPlatformWindowsDefault(). + float (*Platform_GetWindowDpiScale)(ImGuiViewport* vp); // N . . . . // (Optional) [BETA] FIXME-DPI: DPI handling: Return DPI scale for this viewport. 1.0f = 96 DPI. + void (*Platform_OnChangedViewport)(ImGuiViewport* vp); // . F . . . // (Optional) [BETA] FIXME-DPI: DPI handling: Called during Begin() every time the viewport we are outputting into changes, so back-end has a chance to swap fonts to adjust style. + void (*Platform_SetImeInputPos)(ImGuiViewport* vp, ImVec2 pos); // . F . . . // (Optional) Set IME (Input Method Editor, e.g. for Asian languages) input position, so text preview appears over the imgui input box. FIXME: The call timing of this is inconsistent because we want to support without multi-viewports. + int (*Platform_CreateVkSurface)(ImGuiViewport* vp, ImU64 vk_inst, const void* vk_allocators, ImU64* out_vk_surface); // (Optional) For a Vulkan Renderer to call into Platform code (since the surface creation needs to tie them both). + + // (Optional) Renderer functions (e.g. DirectX, OpenGL, Vulkan) + void (*Renderer_CreateWindow)(ImGuiViewport* vp); // . . U . . // Create swap chain, frame buffers etc. (called after Platform_CreateWindow) + void (*Renderer_DestroyWindow)(ImGuiViewport* vp); // N . U . D // Destroy swap chain, frame buffers etc. (called before Platform_DestroyWindow) + void (*Renderer_SetWindowSize)(ImGuiViewport* vp, ImVec2 size); // . . U . . // Resize swap chain, frame buffers etc. (called after Platform_SetWindowSize) + void (*Renderer_RenderWindow)(ImGuiViewport* vp, void* render_arg); // . . . R . // (Optional) Clear framebuffer, setup render target, then render the viewport->DrawData. 'render_arg' is the value passed to RenderPlatformWindowsDefault(). + void (*Renderer_SwapBuffers)(ImGuiViewport* vp, void* render_arg); // . . . R . // (Optional) Call Present/SwapBuffers. 'render_arg' is the value passed to RenderPlatformWindowsDefault(). + + // (Optional) Monitor list + // - Updated by: app/back-end. Update every frame to dynamically support changing monitor or DPI configuration. + // - Used by: dear imgui to query DPI info, clamp popups/tooltips within same monitor and not have them straddle monitors. + ImVector Monitors; + + //------------------------------------------------------------------ + // Output - List of viewports to render into platform windows + //------------------------------------------------------------------ + + // Viewports list (the list is updated by calling ImGui::EndFrame or ImGui::Render) + // (in the future we will attempt to organize this feature to remove the need for a "main viewport") + ImGuiViewport* MainViewport; // Guaranteed to be == Viewports[0] + ImVector Viewports; // Main viewports, followed by all secondary viewports. + ImGuiPlatformIO() { memset(this, 0, sizeof(*this)); } // Zero clear +}; + +// (Optional) This is required when enabling multi-viewport. Represent the bounds of each connected monitor/display and their DPI. +// We use this information for multiple DPI support + clamping the position of popups and tooltips so they don't straddle multiple monitors. +struct ImGuiPlatformMonitor +{ + ImVec2 MainPos, MainSize; // Coordinates of the area displayed on this monitor (Min = upper left, Max = bottom right) + ImVec2 WorkPos, WorkSize; // (Optional) Coordinates without task bars / side bars / menu bars. imgui uses this to avoid positioning popups/tooltips inside this region. + float DpiScale; // 1.0f = 96 DPI + ImGuiPlatformMonitor() { MainPos = MainSize = WorkPos = WorkSize = ImVec2(0, 0); DpiScale = 1.0f; } +}; + +// Flags stored in ImGuiViewport::Flags, giving indications to the platform back-ends. +enum ImGuiViewportFlags_ +{ + ImGuiViewportFlags_None = 0, + ImGuiViewportFlags_NoDecoration = 1 << 0, // Platform Window: Disable platform decorations: title bar, borders, etc. (generally set all windows, but if ImGuiConfigFlags_ViewportsDecoration is set we only set this on popups/tooltips) + ImGuiViewportFlags_NoTaskBarIcon = 1 << 1, // Platform Window: Disable platform task bar icon (generally set on popups/tooltips, or all windows if ImGuiConfigFlags_ViewportsNoTaskBarIcon is set) + ImGuiViewportFlags_NoFocusOnAppearing = 1 << 2, // Platform Window: Don't take focus when created. + ImGuiViewportFlags_NoFocusOnClick = 1 << 3, // Platform Window: Don't take focus when clicked on. + ImGuiViewportFlags_NoInputs = 1 << 4, // Platform Window: Make mouse pass through so we can drag this window while peaking behind it. + ImGuiViewportFlags_NoRendererClear = 1 << 5, // Platform Window: Renderer doesn't need to clear the framebuffer ahead (because we will fill it entirely). + ImGuiViewportFlags_TopMost = 1 << 6, // Platform Window: Display on top (for tooltips only). + ImGuiViewportFlags_Minimized = 1 << 7, // Platform Window: Window is minimized, can skip render. When minimized we tend to avoid using the viewport pos/size for clipping window or testing if they are contained in the viewport. + ImGuiViewportFlags_NoAutoMerge = 1 << 8, // Platform Window: Avoid merging this window into another host window. This can only be set via ImGuiWindowClass viewport flags override (because we need to now ahead if we are going to create a viewport in the first place!). + ImGuiViewportFlags_CanHostOtherWindows = 1 << 9 // Main viewport: can host multiple imgui windows (secondary viewports are associated to a single window). +}; + +// The viewports created and managed by Dear ImGui. The role of the platform back-end is to create the platform/OS windows corresponding to each viewport. +// - Main Area = entire viewport. +// - Work Area = entire viewport minus sections optionally used by menu bars, status bars. Some positioning code will prefer to use this. Window are also trying to stay within this area. +struct ImGuiViewport +{ + ImGuiID ID; // Unique identifier for the viewport + ImGuiViewportFlags Flags; // See ImGuiViewportFlags_ + ImVec2 Pos; // Main Area: Position of the viewport (the imgui coordinates are the same as OS desktop/native coordinates) + ImVec2 Size; // Main Area: Size of the viewport. + ImVec2 WorkOffsetMin; // Work Area: Offset from Pos to top-left corner of Work Area. Generally (0,0) or (0,+main_menu_bar_height). Work Area is Full Area but without menu-bars/status-bars (so WorkArea always fit inside Pos/Size!) + ImVec2 WorkOffsetMax; // Work Area: Offset from Pos+Size to bottom-right corner of Work Area. Generally (0,0) or (0,-status_bar_height). + float DpiScale; // 1.0f = 96 DPI = No extra scale. + ImDrawData* DrawData; // The ImDrawData corresponding to this viewport. Valid after Render() and until the next call to NewFrame(). + ImGuiID ParentViewportId; // (Advanced) 0: no parent. Instruct the platform back-end to setup a parent/child relationship between platform windows. + + // Our design separate the Renderer and Platform back-ends to facilitate combining default back-ends with each others. + // When our create your own back-end for a custom engine, it is possible that both Renderer and Platform will be handled + // by the same system and you may not need to use all the UserData/Handle fields. + // The library never uses those fields, they are merely storage to facilitate back-end implementation. + void* RendererUserData; // void* to hold custom data structure for the renderer (e.g. swap chain, framebuffers etc.). generally set by your Renderer_CreateWindow function. + void* PlatformUserData; // void* to hold custom data structure for the OS / platform (e.g. windowing info, render context). generally set by your Platform_CreateWindow function. + void* PlatformHandle; // void* for FindViewportByPlatformHandle(). (e.g. suggested to use natural platform handle such as HWND, GLFWWindow*, SDL_Window*) + void* PlatformHandleRaw; // void* to hold lower-level, platform-native window handle (e.g. the HWND) when using an abstraction layer like GLFW or SDL (where PlatformHandle would be a SDL_Window*) + bool PlatformRequestMove; // Platform window requested move (e.g. window was moved by the OS / host window manager, authoritative position will be OS window position) + bool PlatformRequestResize; // Platform window requested resize (e.g. window was resized by the OS / host window manager, authoritative size will be OS window size) + bool PlatformRequestClose; // Platform window requested closure (e.g. window was moved by the OS / host window manager, e.g. pressing ALT-F4) + + ImGuiViewport() { ID = 0; Flags = 0; DpiScale = 0.0f; DrawData = NULL; ParentViewportId = 0; RendererUserData = PlatformUserData = PlatformHandle = PlatformHandleRaw = NULL; PlatformRequestMove = PlatformRequestResize = PlatformRequestClose = false; } + ~ImGuiViewport() { IM_ASSERT(PlatformUserData == NULL && RendererUserData == NULL); } + + // Access work-area rectangle + ImVec2 GetWorkPos() { return ImVec2(Pos.x + WorkOffsetMin.x, Pos.y + WorkOffsetMin.y); } + ImVec2 GetWorkSize() { return ImVec2(Size.x - WorkOffsetMin.x + WorkOffsetMax.x, Size.y - WorkOffsetMin.y + WorkOffsetMax.y); } // This not clamped +}; + +#if defined(__clang__) +#pragma clang diagnostic pop +#elif defined(__GNUC__) +#pragma GCC diagnostic pop +#endif + +// Include imgui_user.h at the end of imgui.h (convenient for user to only explicitly include vanilla imgui.h) +#ifdef IMGUI_INCLUDE_IMGUI_USER_H +#include "imgui_user.h" +#endif + +#endif // #ifndef IMGUI_DISABLE diff --git a/extern/imgui/include/imgui_stdlib.h b/extern/imgui/include/imgui_stdlib.h new file mode 100755 index 0000000..06aee95 --- /dev/null +++ b/extern/imgui/include/imgui_stdlib.h @@ -0,0 +1,23 @@ +// imgui_stdlib.h +// Wrappers for C++ standard library (STL) types (std::string, etc.) +// This is also an example of how you may wrap your own similar types. + +// Compatibility: +// - std::string support is only guaranteed to work from C++11. +// If you try to use it pre-C++11, please share your findings (w/ info about compiler/architecture) + +// Changelog: +// - v0.10: Initial version. Added InputText() / InputTextMultiline() calls with std::string + +#pragma once + +#include + +namespace ImGui +{ + // ImGui::InputText() with std::string + // Because text input needs dynamic resizing, we need to setup a callback to grow the capacity + IMGUI_API bool InputText(const char* label, std::string* str, ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = NULL, void* user_data = NULL); + IMGUI_API bool InputTextMultiline(const char* label, std::string* str, const ImVec2& size = ImVec2(0, 0), ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = NULL, void* user_data = NULL); + IMGUI_API bool InputTextWithHint(const char* label, const char* hint, std::string* str, ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = NULL, void* user_data = NULL); +} diff --git a/extern/imgui/src/imgui.cpp b/extern/imgui/src/imgui.cpp new file mode 100644 index 0000000..bec6741 --- /dev/null +++ b/extern/imgui/src/imgui.cpp @@ -0,0 +1,15942 @@ +// dear imgui, v1.77 WIP +// (main code and documentation) + +// Help: +// - Read FAQ at http://dearimgui.org/faq +// - Newcomers, read 'Programmer guide' below for notes on how to setup Dear ImGui in your codebase. +// - Call and read ImGui::ShowDemoWindow() in imgui_demo.cpp. All applications in examples/ are doing that. +// Read imgui.cpp for details, links and comments. + +// Resources: +// - FAQ http://dearimgui.org/faq +// - Homepage & latest https://github.com/ocornut/imgui +// - Releases & changelog https://github.com/ocornut/imgui/releases +// - Gallery https://github.com/ocornut/imgui/issues/3075 (please post your screenshots/video there!) +// - Glossary https://github.com/ocornut/imgui/wiki/Glossary +// - Wiki https://github.com/ocornut/imgui/wiki +// - Issues & support https://github.com/ocornut/imgui/issues + +// Developed by Omar Cornut and every direct or indirect contributors to the GitHub. +// See LICENSE.txt for copyright and licensing details (standard MIT License). +// This library is free but I need your support to sustain development and maintenance. +// Businesses: you can support continued development via invoiced technical support, maintenance and sponsoring contracts. Please reach out to "contact AT dearimgui.org". +// Individuals: you can support continued development via donations. See docs/README or web page. + +// It is recommended that you don't modify imgui.cpp! It will become difficult for you to update the library. +// Note that 'ImGui::' being a namespace, you can add functions into the namespace from your own source files, without +// modifying imgui.h or imgui.cpp. You may include imgui_internal.h to access internal data structures, but it doesn't +// come with any guarantee of forward compatibility. Discussing your changes on the GitHub Issue Tracker may lead you +// to a better solution or official support for them. + +/* + +Index of this file: + +DOCUMENTATION + +- MISSION STATEMENT +- END-USER GUIDE +- PROGRAMMER GUIDE + - READ FIRST + - HOW TO UPDATE TO A NEWER VERSION OF DEAR IMGUI + - GETTING STARTED WITH INTEGRATING DEAR IMGUI IN YOUR CODE/ENGINE + - HOW A SIMPLE APPLICATION MAY LOOK LIKE + - HOW A SIMPLE RENDERING FUNCTION MAY LOOK LIKE + - USING GAMEPAD/KEYBOARD NAVIGATION CONTROLS +- API BREAKING CHANGES (read me when you update!) +- FREQUENTLY ASKED QUESTIONS (FAQ) + - Read all answers online: https://www.dearimgui.org/faq, or in docs/FAQ.md (with a Markdown viewer) + +CODE +(search for "[SECTION]" in the code to find them) + +// [SECTION] INCLUDES +// [SECTION] FORWARD DECLARATIONS +// [SECTION] CONTEXT AND MEMORY ALLOCATORS +// [SECTION] USER FACING STRUCTURES (ImGuiStyle, ImGuiIO) +// [SECTION] MISC HELPERS/UTILITIES (Geometry functions) +// [SECTION] MISC HELPERS/UTILITIES (String, Format, Hash functions) +// [SECTION] MISC HELPERS/UTILITIES (File functions) +// [SECTION] MISC HELPERS/UTILITIES (ImText* functions) +// [SECTION] MISC HELPERS/UTILITIES (Color functions) +// [SECTION] ImGuiStorage +// [SECTION] ImGuiTextFilter +// [SECTION] ImGuiTextBuffer +// [SECTION] ImGuiListClipper +// [SECTION] STYLING +// [SECTION] RENDER HELPERS +// [SECTION] MAIN CODE (most of the code! lots of stuff, needs tidying up!) +// [SECTION] ERROR CHECKING +// [SECTION] LAYOUT +// [SECTION] SCROLLING +// [SECTION] TOOLTIPS +// [SECTION] POPUPS +// [SECTION] KEYBOARD/GAMEPAD NAVIGATION +// [SECTION] DRAG AND DROP +// [SECTION] LOGGING/CAPTURING +// [SECTION] SETTINGS +// [SECTION] VIEWPORTS, PLATFORM WINDOWS +// [SECTION] DOCKING +// [SECTION] PLATFORM DEPENDENT HELPERS +// [SECTION] METRICS/DEBUG WINDOW + +*/ + +//----------------------------------------------------------------------------- +// DOCUMENTATION +//----------------------------------------------------------------------------- + +/* + + MISSION STATEMENT + ================= + + - Easy to use to create code-driven and data-driven tools. + - Easy to use to create ad hoc short-lived tools and long-lived, more elaborate tools. + - Easy to hack and improve. + - Minimize screen real-estate usage. + - Minimize setup and maintenance. + - Minimize state storage on user side. + - Portable, minimize dependencies, run on target (consoles, phones, etc.). + - Efficient runtime and memory consumption (NB- we do allocate when "growing" content e.g. creating a window,. + opening a tree node for the first time, etc. but a typical frame should not allocate anything). + + Designed for developers and content-creators, not the typical end-user! Some of the weaknesses includes: + - Doesn't look fancy, doesn't animate. + - Limited layout features, intricate layouts are typically crafted in code. + + + END-USER GUIDE + ============== + + - Double-click on title bar to collapse window. + - Click upper right corner to close a window, available when 'bool* p_open' is passed to ImGui::Begin(). + - Click and drag on lower right corner to resize window (double-click to auto fit window to its contents). + - Click and drag on any empty space to move window. + - TAB/SHIFT+TAB to cycle through keyboard editable fields. + - CTRL+Click on a slider or drag box to input value as text. + - Use mouse wheel to scroll. + - Text editor: + - Hold SHIFT or use mouse to select text. + - CTRL+Left/Right to word jump. + - CTRL+Shift+Left/Right to select words. + - CTRL+A our Double-Click to select all. + - CTRL+X,CTRL+C,CTRL+V to use OS clipboard/ + - CTRL+Z,CTRL+Y to undo/redo. + - ESCAPE to revert text to its original value. + - You can apply arithmetic operators +,*,/ on numerical values. Use +- to subtract (because - would set a negative value!) + - Controls are automatically adjusted for OSX to match standard OSX text editing operations. + - General Keyboard controls: enable with ImGuiConfigFlags_NavEnableKeyboard. + - General Gamepad controls: enable with ImGuiConfigFlags_NavEnableGamepad. See suggested mappings in imgui.h ImGuiNavInput_ + download PNG/PSD at http://goo.gl/9LgVZW + + + PROGRAMMER GUIDE + ================ + + READ FIRST + ---------- + - Remember to read the FAQ (https://www.dearimgui.org/faq) + - Your code creates the UI, if your code doesn't run the UI is gone! The UI can be highly dynamic, there are no construction + or destruction steps, less superfluous data retention on your side, less state duplication, less state synchronization, less bugs. + - Call and read ImGui::ShowDemoWindow() for demo code demonstrating most features. + - The library is designed to be built from sources. Avoid pre-compiled binaries and packaged versions. See imconfig.h to configure your build. + - Dear ImGui is an implementation of the IMGUI paradigm (immediate-mode graphical user interface, a term coined by Casey Muratori). + You can learn about IMGUI principles at http://www.johno.se/book/imgui.html, http://mollyrocket.com/861 & more links in the FAQ. + - Dear ImGui is a "single pass" rasterizing implementation of the IMGUI paradigm, aimed at ease of use and high-performances. + For every application frame your UI code will be called only once. This is in contrast to e.g. Unity's own implementation of an IMGUI, + where the UI code is called multiple times ("multiple passes") from a single entry point. There are pros and cons to both approaches. + - Our origin are on the top-left. In axis aligned bounding boxes, Min = top-left, Max = bottom-right. + - This codebase is also optimized to yield decent performances with typical "Debug" builds settings. + - Please make sure you have asserts enabled (IM_ASSERT redirects to assert() by default, but can be redirected). + If you get an assert, read the messages and comments around the assert. + - C++: this is a very C-ish codebase: we don't rely on C++11, we don't include any C++ headers, and ImGui:: is a namespace. + - C++: ImVec2/ImVec4 do not expose math operators by default, because it is expected that you use your own math types. + See FAQ "How can I use my own math types instead of ImVec2/ImVec4?" for details about setting up imconfig.h for that. + However, imgui_internal.h can optionally export math operators for ImVec2/ImVec4, which we use in this codebase. + - C++: pay attention that ImVector<> manipulates plain-old-data and does not honor construction/destruction (avoid using it in your code!). + + + HOW TO UPDATE TO A NEWER VERSION OF DEAR IMGUI + ---------------------------------------------- + - Overwrite all the sources files except for imconfig.h (if you have made modification to your copy of imconfig.h) + - Or maintain your own branch where you have imconfig.h modified. + - Read the "API BREAKING CHANGES" section (below). This is where we list occasional API breaking changes. + If a function/type has been renamed / or marked obsolete, try to fix the name in your code before it is permanently removed + from the public API. If you have a problem with a missing function/symbols, search for its name in the code, there will + likely be a comment about it. Please report any issue to the GitHub page! + - Try to keep your copy of dear imgui reasonably up to date. + + + GETTING STARTED WITH INTEGRATING DEAR IMGUI IN YOUR CODE/ENGINE + --------------------------------------------------------------- + - Run and study the examples and demo in imgui_demo.cpp to get acquainted with the library. + - In the majority of cases you should be able to use unmodified back-ends files available in the examples/ folder. + - Add the Dear ImGui source files to your projects or using your preferred build system. + It is recommended you build and statically link the .cpp files as part of your project and NOT as shared library (DLL). + - You can later customize the imconfig.h file to tweak some compile-time behavior, such as integrating Dear ImGui types with your own maths types. + - When using Dear ImGui, your programming IDE is your friend: follow the declaration of variables, functions and types to find comments about them. + - Dear ImGui never touches or knows about your GPU state. The only function that knows about GPU is the draw function that you provide. + Effectively it means you can create widgets at any time in your code, regardless of considerations of being in "update" vs "render" + phases of your own application. All rendering information are stored into command-lists that you will retrieve after calling ImGui::Render(). + - Refer to the bindings and demo applications in the examples/ folder for instruction on how to setup your code. + - If you are running over a standard OS with a common graphics API, you should be able to use unmodified imgui_impl_*** files from the examples/ folder. + + + HOW A SIMPLE APPLICATION MAY LOOK LIKE + -------------------------------------- + EXHIBIT 1: USING THE EXAMPLE BINDINGS (= imgui_impl_XXX.cpp files from the examples/ folder). + The sub-folders in examples/ contains examples applications following this structure. + + // Application init: create a dear imgui context, setup some options, load fonts + ImGui::CreateContext(); + ImGuiIO& io = ImGui::GetIO(); + // TODO: Set optional io.ConfigFlags values, e.g. 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard' to enable keyboard controls. + // TODO: Fill optional fields of the io structure later. + // TODO: Load TTF/OTF fonts if you don't want to use the default font. + + // Initialize helper Platform and Renderer bindings (here we are using imgui_impl_win32.cpp and imgui_impl_dx11.cpp) + ImGui_ImplWin32_Init(hwnd); + ImGui_ImplDX11_Init(g_pd3dDevice, g_pd3dDeviceContext); + + // Application main loop + while (true) + { + // Feed inputs to dear imgui, start new frame + ImGui_ImplDX11_NewFrame(); + ImGui_ImplWin32_NewFrame(); + ImGui::NewFrame(); + + // Any application code here + ImGui::Text("Hello, world!"); + + // Render dear imgui into screen + ImGui::Render(); + ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData()); + g_pSwapChain->Present(1, 0); + } + + // Shutdown + ImGui_ImplDX11_Shutdown(); + ImGui_ImplWin32_Shutdown(); + ImGui::DestroyContext(); + + EXHIBIT 2: IMPLEMENTING CUSTOM BINDING / CUSTOM ENGINE + + // Application init: create a dear imgui context, setup some options, load fonts + ImGui::CreateContext(); + ImGuiIO& io = ImGui::GetIO(); + // TODO: Set optional io.ConfigFlags values, e.g. 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard' to enable keyboard controls. + // TODO: Fill optional fields of the io structure later. + // TODO: Load TTF/OTF fonts if you don't want to use the default font. + + // Build and load the texture atlas into a texture + // (In the examples/ app this is usually done within the ImGui_ImplXXX_Init() function from one of the demo Renderer) + int width, height; + unsigned char* pixels = NULL; + io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); + + // At this point you've got the texture data and you need to upload that your your graphic system: + // After we have created the texture, store its pointer/identifier (_in whichever format your engine uses_) in 'io.Fonts->TexID'. + // This will be passed back to your via the renderer. Basically ImTextureID == void*. Read FAQ for details about ImTextureID. + MyTexture* texture = MyEngine::CreateTextureFromMemoryPixels(pixels, width, height, TEXTURE_TYPE_RGBA32) + io.Fonts->TexID = (void*)texture; + + // Application main loop + while (true) + { + // Setup low-level inputs, e.g. on Win32: calling GetKeyboardState(), or write to those fields from your Windows message handlers, etc. + // (In the examples/ app this is usually done within the ImGui_ImplXXX_NewFrame() function from one of the demo Platform bindings) + io.DeltaTime = 1.0f/60.0f; // set the time elapsed since the previous frame (in seconds) + io.DisplaySize.x = 1920.0f; // set the current display width + io.DisplaySize.y = 1280.0f; // set the current display height here + io.MousePos = my_mouse_pos; // set the mouse position + io.MouseDown[0] = my_mouse_buttons[0]; // set the mouse button states + io.MouseDown[1] = my_mouse_buttons[1]; + + // Call NewFrame(), after this point you can use ImGui::* functions anytime + // (So you want to try calling NewFrame() as early as you can in your mainloop to be able to use Dear ImGui everywhere) + ImGui::NewFrame(); + + // Most of your application code here + ImGui::Text("Hello, world!"); + MyGameUpdate(); // may use any Dear ImGui functions, e.g. ImGui::Begin("My window"); ImGui::Text("Hello, world!"); ImGui::End(); + MyGameRender(); // may use any Dear ImGui functions as well! + + // Render dear imgui, swap buffers + // (You want to try calling EndFrame/Render as late as you can, to be able to use Dear ImGui in your own game rendering code) + ImGui::EndFrame(); + ImGui::Render(); + ImDrawData* draw_data = ImGui::GetDrawData(); + MyImGuiRenderFunction(draw_data); + SwapBuffers(); + } + + // Shutdown + ImGui::DestroyContext(); + + To decide whether to dispatch mouse/keyboard inputs to Dear ImGui to the rest your application, + you should read the 'io.WantCaptureMouse', 'io.WantCaptureKeyboard' and 'io.WantTextInput' flags! + Please read the FAQ and example applications for details about this! + + + HOW A SIMPLE RENDERING FUNCTION MAY LOOK LIKE + --------------------------------------------- + The bindings in impl_impl_XXX.cpp files contains many working implementations of a rendering function. + + void void MyImGuiRenderFunction(ImDrawData* draw_data) + { + // TODO: Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled + // TODO: Setup viewport covering draw_data->DisplayPos to draw_data->DisplayPos + draw_data->DisplaySize + // TODO: Setup orthographic projection matrix cover draw_data->DisplayPos to draw_data->DisplayPos + draw_data->DisplaySize + // TODO: Setup shader: vertex { float2 pos, float2 uv, u32 color }, fragment shader sample color from 1 texture, multiply by vertex color. + for (int n = 0; n < draw_data->CmdListsCount; n++) + { + const ImDrawList* cmd_list = draw_data->CmdLists[n]; + const ImDrawVert* vtx_buffer = cmd_list->VtxBuffer.Data; // vertex buffer generated by Dear ImGui + const ImDrawIdx* idx_buffer = cmd_list->IdxBuffer.Data; // index buffer generated by Dear ImGui + for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) + { + const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i]; + if (pcmd->UserCallback) + { + pcmd->UserCallback(cmd_list, pcmd); + } + else + { + // The texture for the draw call is specified by pcmd->TextureId. + // The vast majority of draw calls will use the Dear ImGui texture atlas, which value you have set yourself during initialization. + MyEngineBindTexture((MyTexture*)pcmd->TextureId); + + // We are using scissoring to clip some objects. All low-level graphics API should supports it. + // - If your engine doesn't support scissoring yet, you may ignore this at first. You will get some small glitches + // (some elements visible outside their bounds) but you can fix that once everything else works! + // - Clipping coordinates are provided in imgui coordinates space (from draw_data->DisplayPos to draw_data->DisplayPos + draw_data->DisplaySize) + // In a single viewport application, draw_data->DisplayPos will always be (0,0) and draw_data->DisplaySize will always be == io.DisplaySize. + // However, in the interest of supporting multi-viewport applications in the future (see 'viewport' branch on github), + // always subtract draw_data->DisplayPos from clipping bounds to convert them to your viewport space. + // - Note that pcmd->ClipRect contains Min+Max bounds. Some graphics API may use Min+Max, other may use Min+Size (size being Max-Min) + ImVec2 pos = draw_data->DisplayPos; + MyEngineScissor((int)(pcmd->ClipRect.x - pos.x), (int)(pcmd->ClipRect.y - pos.y), (int)(pcmd->ClipRect.z - pos.x), (int)(pcmd->ClipRect.w - pos.y)); + + // Render 'pcmd->ElemCount/3' indexed triangles. + // By default the indices ImDrawIdx are 16-bit, you can change them to 32-bit in imconfig.h if your engine doesn't support 16-bit indices. + MyEngineDrawIndexedTriangles(pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer, vtx_buffer); + } + idx_buffer += pcmd->ElemCount; + } + } + } + + + USING GAMEPAD/KEYBOARD NAVIGATION CONTROLS + ------------------------------------------ + - The gamepad/keyboard navigation is fairly functional and keeps being improved. + - Gamepad support is particularly useful to use Dear ImGui on a console system (e.g. PS4, Switch, XB1) without a mouse! + - You can ask questions and report issues at https://github.com/ocornut/imgui/issues/787 + - The initial focus was to support game controllers, but keyboard is becoming increasingly and decently usable. + - Keyboard: + - Set io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard to enable. + NewFrame() will automatically fill io.NavInputs[] based on your io.KeysDown[] + io.KeyMap[] arrays. + - When keyboard navigation is active (io.NavActive + ImGuiConfigFlags_NavEnableKeyboard), the io.WantCaptureKeyboard flag + will be set. For more advanced uses, you may want to read from: + - io.NavActive: true when a window is focused and it doesn't have the ImGuiWindowFlags_NoNavInputs flag set. + - io.NavVisible: true when the navigation cursor is visible (and usually goes false when mouse is used). + - or query focus information with e.g. IsWindowFocused(ImGuiFocusedFlags_AnyWindow), IsItemFocused() etc. functions. + Please reach out if you think the game vs navigation input sharing could be improved. + - Gamepad: + - Set io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad to enable. + - Backend: Set io.BackendFlags |= ImGuiBackendFlags_HasGamepad + fill the io.NavInputs[] fields before calling NewFrame(). + Note that io.NavInputs[] is cleared by EndFrame(). + - See 'enum ImGuiNavInput_' in imgui.h for a description of inputs. For each entry of io.NavInputs[], set the following values: + 0.0f= not held. 1.0f= fully held. Pass intermediate 0.0f..1.0f values for analog triggers/sticks. + - We uses a simple >0.0f test for activation testing, and won't attempt to test for a dead-zone. + Your code will probably need to transform your raw inputs (such as e.g. remapping your 0.2..0.9 raw input range to 0.0..1.0 imgui range, etc.). + - You can download PNG/PSD files depicting the gamepad controls for common controllers at: http://goo.gl/9LgVZW. + - If you need to share inputs between your game and the imgui parts, the easiest approach is to go all-or-nothing, with a buttons combo + to toggle the target. Please reach out if you think the game vs navigation input sharing could be improved. + - Mouse: + - PS4 users: Consider emulating a mouse cursor with DualShock4 touch pad or a spare analog stick as a mouse-emulation fallback. + - Consoles/Tablet/Phone users: Consider using a Synergy 1.x server (on your PC) + uSynergy.c (on your console/tablet/phone app) to share your PC mouse/keyboard. + - On a TV/console system where readability may be lower or mouse inputs may be awkward, you may want to set the ImGuiConfigFlags_NavEnableSetMousePos flag. + Enabling ImGuiConfigFlags_NavEnableSetMousePos + ImGuiBackendFlags_HasSetMousePos instructs dear imgui to move your mouse cursor along with navigation movements. + When enabled, the NewFrame() function may alter 'io.MousePos' and set 'io.WantSetMousePos' to notify you that it wants the mouse cursor to be moved. + When that happens your back-end NEEDS to move the OS or underlying mouse cursor on the next frame. Some of the binding in examples/ do that. + (If you set the NavEnableSetMousePos flag but don't honor 'io.WantSetMousePos' properly, imgui will misbehave as it will see your mouse as moving back and forth!) + (In a setup when you may not have easy control over the mouse cursor, e.g. uSynergy.c doesn't expose moving remote mouse cursor, you may want + to set a boolean to ignore your other external mouse positions until the external source is moved again.) + + + API BREAKING CHANGES + ==================== + + Occasionally introducing changes that are breaking the API. We try to make the breakage minor and easy to fix. + Below is a change-log of API breaking changes only. If you are using one of the functions listed, expect to have to fix some code. + When you are not sure about a old symbol or function name, try using the Search/Find function of your IDE to look for comments or references in all imgui files. + You can read releases logs https://github.com/ocornut/imgui/releases for more details. + + (Docking/Viewport Branch) + - 2019/XX/XX (1.XX) - when multi-viewports are enabled, all positions will be in your natural OS coordinates space. It means that: + - reference to hard-coded positions such as in SetNextWindowPos(ImVec2(0,0)) are probably not what you want anymore. + you may use GetMainViewport()->Pos to offset hard-coded positions, e.g. SetNextWindowPos(GetMainViewport()->Pos) + - likewise io.MousePos and GetMousePos() will use OS coordinates. + If you query mouse positions to interact with non-imgui coordinates you will need to offset them, e.g. subtract GetWindowViewport()->Pos. + - 2019/XX/XX (1.XX) - Moved IME support functions from io.ImeSetInputScreenPosFn, io.ImeWindowHandle to the PlatformIO api. + + + - 2020/04/23 (1.77) - Removed unnecessary ID (first arg) of ImFontAtlas::AddCustomRectRegular(). + - 2020/01/22 (1.75) - ImDrawList::AddCircle()/AddCircleFilled() functions don't accept negative radius any more. + - 2019/12/17 (1.75) - [undid this change in 1.76] made Columns() limited to 64 columns by asserting above that limit. While the current code technically supports it, future code may not so we're putting the restriction ahead. + - 2019/12/13 (1.75) - [imgui_internal.h] changed ImRect() default constructor initializes all fields to 0.0f instead of (FLT_MAX,FLT_MAX,-FLT_MAX,-FLT_MAX). If you used ImRect::Add() to create bounding boxes by adding multiple points into it, you may need to fix your initial value. + - 2019/12/08 (1.75) - removed redirecting functions/enums that were marked obsolete in 1.53 (December 2017): + - ShowTestWindow() -> use ShowDemoWindow() + - IsRootWindowFocused() -> use IsWindowFocused(ImGuiFocusedFlags_RootWindow) + - IsRootWindowOrAnyChildFocused() -> use IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows) + - SetNextWindowContentWidth(w) -> use SetNextWindowContentSize(ImVec2(w, 0.0f) + - GetItemsLineHeightWithSpacing() -> use GetFrameHeightWithSpacing() + - ImGuiCol_ChildWindowBg -> use ImGuiCol_ChildBg + - ImGuiStyleVar_ChildWindowRounding -> use ImGuiStyleVar_ChildRounding + - ImGuiTreeNodeFlags_AllowOverlapMode -> use ImGuiTreeNodeFlags_AllowItemOverlap + - IMGUI_DISABLE_TEST_WINDOWS -> use IMGUI_DISABLE_DEMO_WINDOWS + - 2019/12/08 (1.75) - obsoleted calling ImDrawList::PrimReserve() with a negative count (which was the vaguely documented and rarely if ever used). Instead we added an explicit PrimUnreserve() API. + - 2019/12/06 (1.75) - removed implicit default parameter to IsMouseDragging(int button = 0) to be consistent with other mouse functions (none of the other functions have it). + - 2019/11/21 (1.74) - ImFontAtlas::AddCustomRectRegular() now requires an ID larger than 0x110000 (instead of 0x10000) to conform with supporting Unicode planes 1-16 in a future update. ID below 0x110000 will now assert. + - 2019/11/19 (1.74) - renamed IMGUI_DISABLE_FORMAT_STRING_FUNCTIONS to IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS for consistency. + - 2019/11/19 (1.74) - renamed IMGUI_DISABLE_MATH_FUNCTIONS to IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS for consistency. + - 2019/10/22 (1.74) - removed redirecting functions/enums that were marked obsolete in 1.52 (October 2017): + - Begin() [old 5 args version] -> use Begin() [3 args], use SetNextWindowSize() SetNextWindowBgAlpha() if needed + - IsRootWindowOrAnyChildHovered() -> use IsWindowHovered(ImGuiHoveredFlags_RootAndChildWindows) + - AlignFirstTextHeightToWidgets() -> use AlignTextToFramePadding() + - SetNextWindowPosCenter() -> use SetNextWindowPos() with a pivot of (0.5f, 0.5f) + - ImFont::Glyph -> use ImFontGlyph + - 2019/10/14 (1.74) - inputs: Fixed a miscalculation in the keyboard/mouse "typematic" repeat delay/rate calculation, used by keys and e.g. repeating mouse buttons as well as the GetKeyPressedAmount() function. + if you were using a non-default value for io.KeyRepeatRate (previous default was 0.250), you can add +io.KeyRepeatDelay to it to compensate for the fix. + The function was triggering on: 0.0 and (delay+rate*N) where (N>=1). Fixed formula responds to (N>=0). Effectively it made io.KeyRepeatRate behave like it was set to (io.KeyRepeatRate + io.KeyRepeatDelay). + If you never altered io.KeyRepeatRate nor used GetKeyPressedAmount() this won't affect you. + - 2019/07/15 (1.72) - removed TreeAdvanceToLabelPos() which is rarely used and only does SetCursorPosX(GetCursorPosX() + GetTreeNodeToLabelSpacing()). Kept redirection function (will obsolete). + - 2019/07/12 (1.72) - renamed ImFontAtlas::CustomRect to ImFontAtlasCustomRect. Kept redirection typedef (will obsolete). + - 2019/06/14 (1.72) - removed redirecting functions/enums names that were marked obsolete in 1.51 (June 2017): ImGuiCol_Column*, ImGuiSetCond_*, IsItemHoveredRect(), IsPosHoveringAnyWindow(), IsMouseHoveringAnyWindow(), IsMouseHoveringWindow(), IMGUI_ONCE_UPON_A_FRAME. Grep this log for details and new names, or see how they were implemented until 1.71. + - 2019/06/07 (1.71) - rendering of child window outer decorations (bg color, border, scrollbars) is now performed as part of the parent window. If you have + overlapping child windows in a same parent, and relied on their relative z-order to be mapped to their submission order, this will affect your rendering. + This optimization is disabled if the parent window has no visual output, because it appears to be the most common situation leading to the creation of overlapping child windows. + Please reach out if you are affected. + - 2019/05/13 (1.71) - renamed SetNextTreeNodeOpen() to SetNextItemOpen(). Kept inline redirection function (will obsolete). + - 2019/05/11 (1.71) - changed io.AddInputCharacter(unsigned short c) signature to io.AddInputCharacter(unsigned int c). + - 2019/04/29 (1.70) - improved ImDrawList thick strokes (>1.0f) preserving correct thickness up to 90 degrees angles (e.g. rectangles). If you have custom rendering using thick lines, they will appear thicker now. + - 2019/04/29 (1.70) - removed GetContentRegionAvailWidth(), use GetContentRegionAvail().x instead. Kept inline redirection function (will obsolete). + - 2019/03/04 (1.69) - renamed GetOverlayDrawList() to GetForegroundDrawList(). Kept redirection function (will obsolete). + - 2019/02/26 (1.69) - renamed ImGuiColorEditFlags_RGB/ImGuiColorEditFlags_HSV/ImGuiColorEditFlags_HEX to ImGuiColorEditFlags_DisplayRGB/ImGuiColorEditFlags_DisplayHSV/ImGuiColorEditFlags_DisplayHex. Kept redirection enums (will obsolete). + - 2019/02/14 (1.68) - made it illegal/assert when io.DisplayTime == 0.0f (with an exception for the first frame). If for some reason your time step calculation gives you a zero value, replace it with a dummy small value! + - 2019/02/01 (1.68) - removed io.DisplayVisibleMin/DisplayVisibleMax (which were marked obsolete and removed from viewport/docking branch already). + - 2019/01/06 (1.67) - renamed io.InputCharacters[], marked internal as was always intended. Please don't access directly, and use AddInputCharacter() instead! + - 2019/01/06 (1.67) - renamed ImFontAtlas::GlyphRangesBuilder to ImFontGlyphRangesBuilder. Kept redirection typedef (will obsolete). + - 2018/12/20 (1.67) - made it illegal to call Begin("") with an empty string. This somehow half-worked before but had various undesirable side-effects. + - 2018/12/10 (1.67) - renamed io.ConfigResizeWindowsFromEdges to io.ConfigWindowsResizeFromEdges as we are doing a large pass on configuration flags. + - 2018/10/12 (1.66) - renamed misc/stl/imgui_stl.* to misc/cpp/imgui_stdlib.* in prevision for other C++ helper files. + - 2018/09/28 (1.66) - renamed SetScrollHere() to SetScrollHereY(). Kept redirection function (will obsolete). + - 2018/09/06 (1.65) - renamed stb_truetype.h to imstb_truetype.h, stb_textedit.h to imstb_textedit.h, and stb_rect_pack.h to imstb_rectpack.h. + If you were conveniently using the imgui copy of those STB headers in your project you will have to update your include paths. + - 2018/09/05 (1.65) - renamed io.OptCursorBlink/io.ConfigCursorBlink to io.ConfigInputTextCursorBlink. (#1427) + - 2018/08/31 (1.64) - added imgui_widgets.cpp file, extracted and moved widgets code out of imgui.cpp into imgui_widgets.cpp. Re-ordered some of the code remaining in imgui.cpp. + NONE OF THE FUNCTIONS HAVE CHANGED. THE CODE IS SEMANTICALLY 100% IDENTICAL, BUT _EVERY_ FUNCTION HAS BEEN MOVED. + Because of this, any local modifications to imgui.cpp will likely conflict when you update. Read docs/CHANGELOG.txt for suggestions. + - 2018/08/22 (1.63) - renamed IsItemDeactivatedAfterChange() to IsItemDeactivatedAfterEdit() for consistency with new IsItemEdited() API. Kept redirection function (will obsolete soonish as IsItemDeactivatedAfterChange() is very recent). + - 2018/08/21 (1.63) - renamed ImGuiTextEditCallback to ImGuiInputTextCallback, ImGuiTextEditCallbackData to ImGuiInputTextCallbackData for consistency. Kept redirection types (will obsolete). + - 2018/08/21 (1.63) - removed ImGuiInputTextCallbackData::ReadOnly since it is a duplication of (ImGuiInputTextCallbackData::Flags & ImGuiInputTextFlags_ReadOnly). + - 2018/08/01 (1.63) - removed per-window ImGuiWindowFlags_ResizeFromAnySide beta flag in favor of a global io.ConfigResizeWindowsFromEdges [update 1.67 renamed to ConfigWindowsResizeFromEdges] to enable the feature. + - 2018/08/01 (1.63) - renamed io.OptCursorBlink to io.ConfigCursorBlink [-> io.ConfigInputTextCursorBlink in 1.65], io.OptMacOSXBehaviors to ConfigMacOSXBehaviors for consistency. + - 2018/07/22 (1.63) - changed ImGui::GetTime() return value from float to double to avoid accumulating floating point imprecisions over time. + - 2018/07/08 (1.63) - style: renamed ImGuiCol_ModalWindowDarkening to ImGuiCol_ModalWindowDimBg for consistency with other features. Kept redirection enum (will obsolete). + - 2018/06/08 (1.62) - examples: the imgui_impl_xxx files have been split to separate platform (Win32, Glfw, SDL2, etc.) from renderer (DX11, OpenGL, Vulkan, etc.). + old bindings will still work as is, however prefer using the separated bindings as they will be updated to support multi-viewports. + when adopting new bindings follow the main.cpp code of your preferred examples/ folder to know which functions to call. + in particular, note that old bindings called ImGui::NewFrame() at the end of their ImGui_ImplXXXX_NewFrame() function. + - 2018/06/06 (1.62) - renamed GetGlyphRangesChinese() to GetGlyphRangesChineseFull() to distinguish other variants and discourage using the full set. + - 2018/06/06 (1.62) - TreeNodeEx()/TreeNodeBehavior(): the ImGuiTreeNodeFlags_CollapsingHeader helper now include the ImGuiTreeNodeFlags_NoTreePushOnOpen flag. See Changelog for details. + - 2018/05/03 (1.61) - DragInt(): the default compile-time format string has been changed from "%.0f" to "%d", as we are not using integers internally any more. + If you used DragInt() with custom format strings, make sure you change them to use %d or an integer-compatible format. + To honor backward-compatibility, the DragInt() code will currently parse and modify format strings to replace %*f with %d, giving time to users to upgrade their code. + If you have IMGUI_DISABLE_OBSOLETE_FUNCTIONS enabled, the code will instead assert! You may run a reg-exp search on your codebase for e.g. "DragInt.*%f" to help you find them. + - 2018/04/28 (1.61) - obsoleted InputFloat() functions taking an optional "int decimal_precision" in favor of an equivalent and more flexible "const char* format", + consistent with other functions. Kept redirection functions (will obsolete). + - 2018/04/09 (1.61) - IM_DELETE() helper function added in 1.60 doesn't clear the input _pointer_ reference, more consistent with expectation and allows passing r-value. + - 2018/03/20 (1.60) - renamed io.WantMoveMouse to io.WantSetMousePos for consistency and ease of understanding (was added in 1.52, _not_ used by core and only honored by some binding ahead of merging the Nav branch). + - 2018/03/12 (1.60) - removed ImGuiCol_CloseButton, ImGuiCol_CloseButtonActive, ImGuiCol_CloseButtonHovered as the closing cross uses regular button colors now. + - 2018/03/08 (1.60) - changed ImFont::DisplayOffset.y to default to 0 instead of +1. Fixed rounding of Ascent/Descent to match TrueType renderer. If you were adding or subtracting to ImFont::DisplayOffset check if your fonts are correctly aligned vertically. + - 2018/03/03 (1.60) - renamed ImGuiStyleVar_Count_ to ImGuiStyleVar_COUNT and ImGuiMouseCursor_Count_ to ImGuiMouseCursor_COUNT for consistency with other public enums. + - 2018/02/18 (1.60) - BeginDragDropSource(): temporarily removed the optional mouse_button=0 parameter because it is not really usable in many situations at the moment. + - 2018/02/16 (1.60) - obsoleted the io.RenderDrawListsFn callback, you can call your graphics engine render function after ImGui::Render(). Use ImGui::GetDrawData() to retrieve the ImDrawData* to display. + - 2018/02/07 (1.60) - reorganized context handling to be more explicit, + - YOU NOW NEED TO CALL ImGui::CreateContext() AT THE BEGINNING OF YOUR APP, AND CALL ImGui::DestroyContext() AT THE END. + - removed Shutdown() function, as DestroyContext() serve this purpose. + - you may pass a ImFontAtlas* pointer to CreateContext() to share a font atlas between contexts. Otherwise CreateContext() will create its own font atlas instance. + - removed allocator parameters from CreateContext(), they are now setup with SetAllocatorFunctions(), and shared by all contexts. + - removed the default global context and font atlas instance, which were confusing for users of DLL reloading and users of multiple contexts. + - 2018/01/31 (1.60) - moved sample TTF files from extra_fonts/ to misc/fonts/. If you loaded files directly from the imgui repo you may need to update your paths. + - 2018/01/11 (1.60) - obsoleted IsAnyWindowHovered() in favor of IsWindowHovered(ImGuiHoveredFlags_AnyWindow). Kept redirection function (will obsolete). + - 2018/01/11 (1.60) - obsoleted IsAnyWindowFocused() in favor of IsWindowFocused(ImGuiFocusedFlags_AnyWindow). Kept redirection function (will obsolete). + - 2018/01/03 (1.60) - renamed ImGuiSizeConstraintCallback to ImGuiSizeCallback, ImGuiSizeConstraintCallbackData to ImGuiSizeCallbackData. + - 2017/12/29 (1.60) - removed CalcItemRectClosestPoint() which was weird and not really used by anyone except demo code. If you need it it's easy to replicate on your side. + - 2017/12/24 (1.53) - renamed the emblematic ShowTestWindow() function to ShowDemoWindow(). Kept redirection function (will obsolete). + - 2017/12/21 (1.53) - ImDrawList: renamed style.AntiAliasedShapes to style.AntiAliasedFill for consistency and as a way to explicitly break code that manipulate those flag at runtime. You can now manipulate ImDrawList::Flags + - 2017/12/21 (1.53) - ImDrawList: removed 'bool anti_aliased = true' final parameter of ImDrawList::AddPolyline() and ImDrawList::AddConvexPolyFilled(). Prefer manipulating ImDrawList::Flags if you need to toggle them during the frame. + - 2017/12/14 (1.53) - using the ImGuiWindowFlags_NoScrollWithMouse flag on a child window forwards the mouse wheel event to the parent window, unless either ImGuiWindowFlags_NoInputs or ImGuiWindowFlags_NoScrollbar are also set. + - 2017/12/13 (1.53) - renamed GetItemsLineHeightWithSpacing() to GetFrameHeightWithSpacing(). Kept redirection function (will obsolete). + - 2017/12/13 (1.53) - obsoleted IsRootWindowFocused() in favor of using IsWindowFocused(ImGuiFocusedFlags_RootWindow). Kept redirection function (will obsolete). + - obsoleted IsRootWindowOrAnyChildFocused() in favor of using IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows). Kept redirection function (will obsolete). + - 2017/12/12 (1.53) - renamed ImGuiTreeNodeFlags_AllowOverlapMode to ImGuiTreeNodeFlags_AllowItemOverlap. Kept redirection enum (will obsolete). + - 2017/12/10 (1.53) - removed SetNextWindowContentWidth(), prefer using SetNextWindowContentSize(). Kept redirection function (will obsolete). + - 2017/11/27 (1.53) - renamed ImGuiTextBuffer::append() helper to appendf(), appendv() to appendfv(). If you copied the 'Log' demo in your code, it uses appendv() so that needs to be renamed. + - 2017/11/18 (1.53) - Style, Begin: removed ImGuiWindowFlags_ShowBorders window flag. Borders are now fully set up in the ImGuiStyle structure (see e.g. style.FrameBorderSize, style.WindowBorderSize). Use ImGui::ShowStyleEditor() to look them up. + Please note that the style system will keep evolving (hopefully stabilizing in Q1 2018), and so custom styles will probably subtly break over time. It is recommended you use the StyleColorsClassic(), StyleColorsDark(), StyleColorsLight() functions. + - 2017/11/18 (1.53) - Style: removed ImGuiCol_ComboBg in favor of combo boxes using ImGuiCol_PopupBg for consistency. + - 2017/11/18 (1.53) - Style: renamed ImGuiCol_ChildWindowBg to ImGuiCol_ChildBg. + - 2017/11/18 (1.53) - Style: renamed style.ChildWindowRounding to style.ChildRounding, ImGuiStyleVar_ChildWindowRounding to ImGuiStyleVar_ChildRounding. + - 2017/11/02 (1.53) - obsoleted IsRootWindowOrAnyChildHovered() in favor of using IsWindowHovered(ImGuiHoveredFlags_RootAndChildWindows); + - 2017/10/24 (1.52) - renamed IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCS/IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCS to IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS/IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS for consistency. + - 2017/10/20 (1.52) - changed IsWindowHovered() default parameters behavior to return false if an item is active in another window (e.g. click-dragging item from another window to this window). You can use the newly introduced IsWindowHovered() flags to requests this specific behavior if you need it. + - 2017/10/20 (1.52) - marked IsItemHoveredRect()/IsMouseHoveringWindow() as obsolete, in favor of using the newly introduced flags for IsItemHovered() and IsWindowHovered(). See https://github.com/ocornut/imgui/issues/1382 for details. + removed the IsItemRectHovered()/IsWindowRectHovered() names introduced in 1.51 since they were merely more consistent names for the two functions we are now obsoleting. + IsItemHoveredRect() --> IsItemHovered(ImGuiHoveredFlags_RectOnly) + IsMouseHoveringAnyWindow() --> IsWindowHovered(ImGuiHoveredFlags_AnyWindow) + IsMouseHoveringWindow() --> IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup | ImGuiHoveredFlags_AllowWhenBlockedByActiveItem) [weird, old behavior] + - 2017/10/17 (1.52) - marked the old 5-parameters version of Begin() as obsolete (still available). Use SetNextWindowSize()+Begin() instead! + - 2017/10/11 (1.52) - renamed AlignFirstTextHeightToWidgets() to AlignTextToFramePadding(). Kept inline redirection function (will obsolete). + - 2017/09/26 (1.52) - renamed ImFont::Glyph to ImFontGlyph. Kept redirection typedef (will obsolete). + - 2017/09/25 (1.52) - removed SetNextWindowPosCenter() because SetNextWindowPos() now has the optional pivot information to do the same and more. Kept redirection function (will obsolete). + - 2017/08/25 (1.52) - io.MousePos needs to be set to ImVec2(-FLT_MAX,-FLT_MAX) when mouse is unavailable/missing. Previously ImVec2(-1,-1) was enough but we now accept negative mouse coordinates. In your binding if you need to support unavailable mouse, make sure to replace "io.MousePos = ImVec2(-1,-1)" with "io.MousePos = ImVec2(-FLT_MAX,-FLT_MAX)". + - 2017/08/22 (1.51) - renamed IsItemHoveredRect() to IsItemRectHovered(). Kept inline redirection function (will obsolete). -> (1.52) use IsItemHovered(ImGuiHoveredFlags_RectOnly)! + - renamed IsMouseHoveringAnyWindow() to IsAnyWindowHovered() for consistency. Kept inline redirection function (will obsolete). + - renamed IsMouseHoveringWindow() to IsWindowRectHovered() for consistency. Kept inline redirection function (will obsolete). + - 2017/08/20 (1.51) - renamed GetStyleColName() to GetStyleColorName() for consistency. + - 2017/08/20 (1.51) - added PushStyleColor(ImGuiCol idx, ImU32 col) overload, which _might_ cause an "ambiguous call" compilation error if you are using ImColor() with implicit cast. Cast to ImU32 or ImVec4 explicily to fix. + - 2017/08/15 (1.51) - marked the weird IMGUI_ONCE_UPON_A_FRAME helper macro as obsolete. prefer using the more explicit ImGuiOnceUponAFrame type. + - 2017/08/15 (1.51) - changed parameter order for BeginPopupContextWindow() from (const char*,int buttons,bool also_over_items) to (const char*,int buttons,bool also_over_items). Note that most calls relied on default parameters completely. + - 2017/08/13 (1.51) - renamed ImGuiCol_Column to ImGuiCol_Separator, ImGuiCol_ColumnHovered to ImGuiCol_SeparatorHovered, ImGuiCol_ColumnActive to ImGuiCol_SeparatorActive. Kept redirection enums (will obsolete). + - 2017/08/11 (1.51) - renamed ImGuiSetCond_Always to ImGuiCond_Always, ImGuiSetCond_Once to ImGuiCond_Once, ImGuiSetCond_FirstUseEver to ImGuiCond_FirstUseEver, ImGuiSetCond_Appearing to ImGuiCond_Appearing. Kept redirection enums (will obsolete). + - 2017/08/09 (1.51) - removed ValueColor() helpers, they are equivalent to calling Text(label) + SameLine() + ColorButton(). + - 2017/08/08 (1.51) - removed ColorEditMode() and ImGuiColorEditMode in favor of ImGuiColorEditFlags and parameters to the various Color*() functions. The SetColorEditOptions() allows to initialize default but the user can still change them with right-click context menu. + - changed prototype of 'ColorEdit4(const char* label, float col[4], bool show_alpha = true)' to 'ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flags = 0)', where passing flags = 0x01 is a safe no-op (hello dodgy backward compatibility!). - check and run the demo window, under "Color/Picker Widgets", to understand the various new options. + - changed prototype of rarely used 'ColorButton(ImVec4 col, bool small_height = false, bool outline_border = true)' to 'ColorButton(const char* desc_id, ImVec4 col, ImGuiColorEditFlags flags = 0, ImVec2 size = ImVec2(0,0))' + - 2017/07/20 (1.51) - removed IsPosHoveringAnyWindow(ImVec2), which was partly broken and misleading. ASSERT + redirect user to io.WantCaptureMouse + - 2017/05/26 (1.50) - removed ImFontConfig::MergeGlyphCenterV in favor of a more multipurpose ImFontConfig::GlyphOffset. + - 2017/05/01 (1.50) - renamed ImDrawList::PathFill() (rarely used directly) to ImDrawList::PathFillConvex() for clarity. + - 2016/11/06 (1.50) - BeginChild(const char*) now applies the stack id to the provided label, consistently with other functions as it should always have been. It shouldn't affect you unless (extremely unlikely) you were appending multiple times to a same child from different locations of the stack id. If that's the case, generate an id with GetId() and use it instead of passing string to BeginChild(). + - 2016/10/15 (1.50) - avoid 'void* user_data' parameter to io.SetClipboardTextFn/io.GetClipboardTextFn pointers. We pass io.ClipboardUserData to it. + - 2016/09/25 (1.50) - style.WindowTitleAlign is now a ImVec2 (ImGuiAlign enum was removed). set to (0.5f,0.5f) for horizontal+vertical centering, (0.0f,0.0f) for upper-left, etc. + - 2016/07/30 (1.50) - SameLine(x) with x>0.0f is now relative to left of column/group if any, and not always to left of window. This was sort of always the intent and hopefully breakage should be minimal. + - 2016/05/12 (1.49) - title bar (using ImGuiCol_TitleBg/ImGuiCol_TitleBgActive colors) isn't rendered over a window background (ImGuiCol_WindowBg color) anymore. + If your TitleBg/TitleBgActive alpha was 1.0f or you are using the default theme it will not affect you, otherwise if <1.0f you need tweak your custom theme to readjust for the fact that we don't draw a WindowBg background behind the title bar. + This helper function will convert an old TitleBg/TitleBgActive color into a new one with the same visual output, given the OLD color and the OLD WindowBg color: + ImVec4 ConvertTitleBgCol(const ImVec4& win_bg_col, const ImVec4& title_bg_col) { float new_a = 1.0f - ((1.0f - win_bg_col.w) * (1.0f - title_bg_col.w)), k = title_bg_col.w / new_a; return ImVec4((win_bg_col.x * win_bg_col.w + title_bg_col.x) * k, (win_bg_col.y * win_bg_col.w + title_bg_col.y) * k, (win_bg_col.z * win_bg_col.w + title_bg_col.z) * k, new_a); } + If this is confusing, pick the RGB value from title bar from an old screenshot and apply this as TitleBg/TitleBgActive. Or you may just create TitleBgActive from a tweaked TitleBg color. + - 2016/05/07 (1.49) - removed confusing set of GetInternalState(), GetInternalStateSize(), SetInternalState() functions. Now using CreateContext(), DestroyContext(), GetCurrentContext(), SetCurrentContext(). + - 2016/05/02 (1.49) - renamed SetNextTreeNodeOpened() to SetNextTreeNodeOpen(), no redirection. + - 2016/05/01 (1.49) - obsoleted old signature of CollapsingHeader(const char* label, const char* str_id = NULL, bool display_frame = true, bool default_open = false) as extra parameters were badly designed and rarely used. You can replace the "default_open = true" flag in new API with CollapsingHeader(label, ImGuiTreeNodeFlags_DefaultOpen). + - 2016/04/26 (1.49) - changed ImDrawList::PushClipRect(ImVec4 rect) to ImDrawList::PushClipRect(Imvec2 min,ImVec2 max,bool intersect_with_current_clip_rect=false). Note that higher-level ImGui::PushClipRect() is preferable because it will clip at logic/widget level, whereas ImDrawList::PushClipRect() only affect your renderer. + - 2016/04/03 (1.48) - removed style.WindowFillAlphaDefault setting which was redundant. Bake default BG alpha inside style.Colors[ImGuiCol_WindowBg] and all other Bg color values. (ref github issue #337). + - 2016/04/03 (1.48) - renamed ImGuiCol_TooltipBg to ImGuiCol_PopupBg, used by popups/menus and tooltips. popups/menus were previously using ImGuiCol_WindowBg. (ref github issue #337) + - 2016/03/21 (1.48) - renamed GetWindowFont() to GetFont(), GetWindowFontSize() to GetFontSize(). Kept inline redirection function (will obsolete). + - 2016/03/02 (1.48) - InputText() completion/history/always callbacks: if you modify the text buffer manually (without using DeleteChars()/InsertChars() helper) you need to maintain the BufTextLen field. added an assert. + - 2016/01/23 (1.48) - fixed not honoring exact width passed to PushItemWidth(), previously it would add extra FramePadding.x*2 over that width. if you had manual pixel-perfect alignment in place it might affect you. + - 2015/12/27 (1.48) - fixed ImDrawList::AddRect() which used to render a rectangle 1 px too large on each axis. + - 2015/12/04 (1.47) - renamed Color() helpers to ValueColor() - dangerously named, rarely used and probably to be made obsolete. + - 2015/08/29 (1.45) - with the addition of horizontal scrollbar we made various fixes to inconsistencies with dealing with cursor position. + GetCursorPos()/SetCursorPos() functions now include the scrolled amount. It shouldn't affect the majority of users, but take note that SetCursorPosX(100.0f) puts you at +100 from the starting x position which may include scrolling, not at +100 from the window left side. + GetContentRegionMax()/GetWindowContentRegionMin()/GetWindowContentRegionMax() functions allow include the scrolled amount. Typically those were used in cases where no scrolling would happen so it may not be a problem, but watch out! + - 2015/08/29 (1.45) - renamed style.ScrollbarWidth to style.ScrollbarSize + - 2015/08/05 (1.44) - split imgui.cpp into extra files: imgui_demo.cpp imgui_draw.cpp imgui_internal.h that you need to add to your project. + - 2015/07/18 (1.44) - fixed angles in ImDrawList::PathArcTo(), PathArcToFast() (introduced in 1.43) being off by an extra PI for no justifiable reason + - 2015/07/14 (1.43) - add new ImFontAtlas::AddFont() API. For the old AddFont***, moved the 'font_no' parameter of ImFontAtlas::AddFont** functions to the ImFontConfig structure. + you need to render your textured triangles with bilinear filtering to benefit from sub-pixel positioning of text. + - 2015/07/08 (1.43) - switched rendering data to use indexed rendering. this is saving a fair amount of CPU/GPU and enables us to get anti-aliasing for a marginal cost. + this necessary change will break your rendering function! the fix should be very easy. sorry for that :( + - if you are using a vanilla copy of one of the imgui_impl_XXXX.cpp provided in the example, you just need to update your copy and you can ignore the rest. + - the signature of the io.RenderDrawListsFn handler has changed! + old: ImGui_XXXX_RenderDrawLists(ImDrawList** const cmd_lists, int cmd_lists_count) + new: ImGui_XXXX_RenderDrawLists(ImDrawData* draw_data). + parameters: 'cmd_lists' becomes 'draw_data->CmdLists', 'cmd_lists_count' becomes 'draw_data->CmdListsCount' + ImDrawList: 'commands' becomes 'CmdBuffer', 'vtx_buffer' becomes 'VtxBuffer', 'IdxBuffer' is new. + ImDrawCmd: 'vtx_count' becomes 'ElemCount', 'clip_rect' becomes 'ClipRect', 'user_callback' becomes 'UserCallback', 'texture_id' becomes 'TextureId'. + - each ImDrawList now contains both a vertex buffer and an index buffer. For each command, render ElemCount/3 triangles using indices from the index buffer. + - if you REALLY cannot render indexed primitives, you can call the draw_data->DeIndexAllBuffers() method to de-index the buffers. This is slow and a waste of CPU/GPU. Prefer using indexed rendering! + - refer to code in the examples/ folder or ask on the GitHub if you are unsure of how to upgrade. please upgrade! + - 2015/07/10 (1.43) - changed SameLine() parameters from int to float. + - 2015/07/02 (1.42) - renamed SetScrollPosHere() to SetScrollFromCursorPos(). Kept inline redirection function (will obsolete). + - 2015/07/02 (1.42) - renamed GetScrollPosY() to GetScrollY(). Necessary to reduce confusion along with other scrolling functions, because positions (e.g. cursor position) are not equivalent to scrolling amount. + - 2015/06/14 (1.41) - changed ImageButton() default bg_col parameter from (0,0,0,1) (black) to (0,0,0,0) (transparent) - makes a difference when texture have transparence + - 2015/06/14 (1.41) - changed Selectable() API from (label, selected, size) to (label, selected, flags, size). Size override should have been rarely be used. Sorry! + - 2015/05/31 (1.40) - renamed GetWindowCollapsed() to IsWindowCollapsed() for consistency. Kept inline redirection function (will obsolete). + - 2015/05/31 (1.40) - renamed IsRectClipped() to IsRectVisible() for consistency. Note that return value is opposite! Kept inline redirection function (will obsolete). + - 2015/05/27 (1.40) - removed the third 'repeat_if_held' parameter from Button() - sorry! it was rarely used and inconsistent. Use PushButtonRepeat(true) / PopButtonRepeat() to enable repeat on desired buttons. + - 2015/05/11 (1.40) - changed BeginPopup() API, takes a string identifier instead of a bool. ImGui needs to manage the open/closed state of popups. Call OpenPopup() to actually set the "open" state of a popup. BeginPopup() returns true if the popup is opened. + - 2015/05/03 (1.40) - removed style.AutoFitPadding, using style.WindowPadding makes more sense (the default values were already the same). + - 2015/04/13 (1.38) - renamed IsClipped() to IsRectClipped(). Kept inline redirection function until 1.50. + - 2015/04/09 (1.38) - renamed ImDrawList::AddArc() to ImDrawList::AddArcFast() for compatibility with future API + - 2015/04/03 (1.38) - removed ImGuiCol_CheckHovered, ImGuiCol_CheckActive, replaced with the more general ImGuiCol_FrameBgHovered, ImGuiCol_FrameBgActive. + - 2014/04/03 (1.38) - removed support for passing -FLT_MAX..+FLT_MAX as the range for a SliderFloat(). Use DragFloat() or Inputfloat() instead. + - 2015/03/17 (1.36) - renamed GetItemBoxMin()/GetItemBoxMax()/IsMouseHoveringBox() to GetItemRectMin()/GetItemRectMax()/IsMouseHoveringRect(). Kept inline redirection function until 1.50. + - 2015/03/15 (1.36) - renamed style.TreeNodeSpacing to style.IndentSpacing, ImGuiStyleVar_TreeNodeSpacing to ImGuiStyleVar_IndentSpacing + - 2015/03/13 (1.36) - renamed GetWindowIsFocused() to IsWindowFocused(). Kept inline redirection function until 1.50. + - 2015/03/08 (1.35) - renamed style.ScrollBarWidth to style.ScrollbarWidth (casing) + - 2015/02/27 (1.34) - renamed OpenNextNode(bool) to SetNextTreeNodeOpened(bool, ImGuiSetCond). Kept inline redirection function until 1.50. + - 2015/02/27 (1.34) - renamed ImGuiSetCondition_*** to ImGuiSetCond_***, and _FirstUseThisSession becomes _Once. + - 2015/02/11 (1.32) - changed text input callback ImGuiTextEditCallback return type from void-->int. reserved for future use, return 0 for now. + - 2015/02/10 (1.32) - renamed GetItemWidth() to CalcItemWidth() to clarify its evolving behavior + - 2015/02/08 (1.31) - renamed GetTextLineSpacing() to GetTextLineHeightWithSpacing() + - 2015/02/01 (1.31) - removed IO.MemReallocFn (unused) + - 2015/01/19 (1.30) - renamed ImGuiStorage::GetIntPtr()/GetFloatPtr() to GetIntRef()/GetIntRef() because Ptr was conflicting with actual pointer storage functions. + - 2015/01/11 (1.30) - big font/image API change! now loads TTF file. allow for multiple fonts. no need for a PNG loader. + - 2015/01/11 (1.30) - removed GetDefaultFontData(). uses io.Fonts->GetTextureData*() API to retrieve uncompressed pixels. + - old: const void* png_data; unsigned int png_size; ImGui::GetDefaultFontData(NULL, NULL, &png_data, &png_size); [..Upload texture to GPU..]; + - new: unsigned char* pixels; int width, height; io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); [..Upload texture to GPU..]; io.Fonts->TexId = YourTexIdentifier; + you now have more flexibility to load multiple TTF fonts and manage the texture buffer for internal needs. It is now recommended that you sample the font texture with bilinear interpolation. + - 2015/01/11 (1.30) - added texture identifier in ImDrawCmd passed to your render function (we can now render images). make sure to set io.Fonts->TexID. + - 2015/01/11 (1.30) - removed IO.PixelCenterOffset (unnecessary, can be handled in user projection matrix) + - 2015/01/11 (1.30) - removed ImGui::IsItemFocused() in favor of ImGui::IsItemActive() which handles all widgets + - 2014/12/10 (1.18) - removed SetNewWindowDefaultPos() in favor of new generic API SetNextWindowPos(pos, ImGuiSetCondition_FirstUseEver) + - 2014/11/28 (1.17) - moved IO.Font*** options to inside the IO.Font-> structure (FontYOffset, FontTexUvForWhite, FontBaseScale, FontFallbackGlyph) + - 2014/11/26 (1.17) - reworked syntax of IMGUI_ONCE_UPON_A_FRAME helper macro to increase compiler compatibility + - 2014/11/07 (1.15) - renamed IsHovered() to IsItemHovered() + - 2014/10/02 (1.14) - renamed IMGUI_INCLUDE_IMGUI_USER_CPP to IMGUI_INCLUDE_IMGUI_USER_INL and imgui_user.cpp to imgui_user.inl (more IDE friendly) + - 2014/09/25 (1.13) - removed 'text_end' parameter from IO.SetClipboardTextFn (the string is now always zero-terminated for simplicity) + - 2014/09/24 (1.12) - renamed SetFontScale() to SetWindowFontScale() + - 2014/09/24 (1.12) - moved IM_MALLOC/IM_REALLOC/IM_FREE preprocessor defines to IO.MemAllocFn/IO.MemReallocFn/IO.MemFreeFn + - 2014/08/30 (1.09) - removed IO.FontHeight (now computed automatically) + - 2014/08/30 (1.09) - moved IMGUI_FONT_TEX_UV_FOR_WHITE preprocessor define to IO.FontTexUvForWhite + - 2014/08/28 (1.09) - changed the behavior of IO.PixelCenterOffset following various rendering fixes + + + FREQUENTLY ASKED QUESTIONS (FAQ) + ================================ + + Read all answers online: https://www.dearimgui.org/faq, or in docs/FAQ.md (with a Markdown viewer) + Some answers are copied down here to facilitate searching in code. + + Q&A: Basics + =========== + + Q: Where is the documentation? + A: This library is poorly documented at the moment and expects of the user to be acquainted with C/C++. + - Run the examples/ and explore them. + - See demo code in imgui_demo.cpp and particularly the ImGui::ShowDemoWindow() function. + - The demo covers most features of Dear ImGui, so you can read the code and see its output. + - See documentation and comments at the top of imgui.cpp + effectively imgui.h. + - Dozens of standalone example applications using e.g. OpenGL/DirectX are provided in the + examples/ folder to explain how to integrate Dear ImGui with your own engine/application. + - The Wiki (https://github.com/ocornut/imgui/wiki) has many resources and links. + - The Glossary (https://github.com/ocornut/imgui/wiki/Glossary) page also may be useful. + - Your programming IDE is your friend, find the type or function declaration to find comments + associated to it. + + Q: What is this library called? + Q: Which version should I get? + >> This library is called "Dear ImGui", please don't call it "ImGui" :) + >> See https://www.dearimgui.org/faq + + Q&A: Integration + ================ + + Q: How can I tell whether to dispatch mouse/keyboard to Dear ImGui or to my application? + A: You should read the 'io.WantCaptureMouse', 'io.WantCaptureKeyboard' and 'io.WantTextInput' flags! + >> See https://www.dearimgui.org/faq for fully detailed answer. You really want to read this. + + Q. How can I enable keyboard controls? + Q: How can I use this without a mouse, without a keyboard or without a screen? (gamepad, input share, remote display) + Q: I integrated Dear ImGui in my engine and the text or lines are blurry.. + Q: I integrated Dear ImGui in my engine and some elements are clipping or disappearing when I move windows around.. + >> See https://www.dearimgui.org/faq + + Q&A: Usage + ---------- + + Q: Why are multiple widgets reacting when I interact with a single one? + Q: How can I have multiple widgets with the same label or with an empty label? + A: A primer on labels and the ID Stack... + + Dear ImGui internally need to uniquely identify UI elements. + Elements that are typically not clickable (such as calls to the Text functions) don't need an ID. + Interactive widgets (such as calls to Button buttons) need a unique ID. + Unique ID are used internally to track active widgets and occasionally associate state to widgets. + Unique ID are implicitly built from the hash of multiple elements that identify the "path" to the UI element. + + - Unique ID are often derived from a string label: + + Button("OK"); // Label = "OK", ID = hash of (..., "OK") + Button("Cancel"); // Label = "Cancel", ID = hash of (..., "Cancel") + + - ID are uniquely scoped within windows, tree nodes, etc. which all pushes to the ID stack. Having + two buttons labeled "OK" in different windows or different tree locations is fine. + We used "..." above to signify whatever was already pushed to the ID stack previously: + + Begin("MyWindow"); + Button("OK"); // Label = "OK", ID = hash of ("MyWindow", "OK") + End(); + Begin("MyOtherWindow"); + Button("OK"); // Label = "OK", ID = hash of ("MyOtherWindow", "OK") + End(); + + - If you have a same ID twice in the same location, you'll have a conflict: + + Button("OK"); + Button("OK"); // ID collision! Interacting with either button will trigger the first one. + + Fear not! this is easy to solve and there are many ways to solve it! + + - Solving ID conflict in a simple/local context: + When passing a label you can optionally specify extra ID information within string itself. + Use "##" to pass a complement to the ID that won't be visible to the end-user. + This helps solving the simple collision cases when you know e.g. at compilation time which items + are going to be created: + + Begin("MyWindow"); + Button("Play"); // Label = "Play", ID = hash of ("MyWindow", "Play") + Button("Play##foo1"); // Label = "Play", ID = hash of ("MyWindow", "Play##foo1") // Different from above + Button("Play##foo2"); // Label = "Play", ID = hash of ("MyWindow", "Play##foo2") // Different from above + End(); + + - If you want to completely hide the label, but still need an ID: + + Checkbox("##On", &b); // Label = "", ID = hash of (..., "##On") // No visible label, just a checkbox! + + - Occasionally/rarely you might want change a label while preserving a constant ID. This allows + you to animate labels. For example you may want to include varying information in a window title bar, + but windows are uniquely identified by their ID. Use "###" to pass a label that isn't part of ID: + + Button("Hello###ID"); // Label = "Hello", ID = hash of (..., "###ID") + Button("World###ID"); // Label = "World", ID = hash of (..., "###ID") // Same as above, even though the label looks different + + sprintf(buf, "My game (%f FPS)###MyGame", fps); + Begin(buf); // Variable title, ID = hash of "MyGame" + + - Solving ID conflict in a more general manner: + Use PushID() / PopID() to create scopes and manipulate the ID stack, as to avoid ID conflicts + within the same window. This is the most convenient way of distinguishing ID when iterating and + creating many UI elements programmatically. + You can push a pointer, a string or an integer value into the ID stack. + Remember that ID are formed from the concatenation of _everything_ pushed into the ID stack. + At each level of the stack we store the seed used for items at this level of the ID stack. + + Begin("Window"); + for (int i = 0; i < 100; i++) + { + PushID(i); // Push i to the id tack + Button("Click"); // Label = "Click", ID = hash of ("Window", i, "Click") + PopID(); + } + for (int i = 0; i < 100; i++) + { + MyObject* obj = Objects[i]; + PushID(obj); + Button("Click"); // Label = "Click", ID = hash of ("Window", obj pointer, "Click") + PopID(); + } + for (int i = 0; i < 100; i++) + { + MyObject* obj = Objects[i]; + PushID(obj->Name); + Button("Click"); // Label = "Click", ID = hash of ("Window", obj->Name, "Click") + PopID(); + } + End(); + + - You can stack multiple prefixes into the ID stack: + + Button("Click"); // Label = "Click", ID = hash of (..., "Click") + PushID("node"); + Button("Click"); // Label = "Click", ID = hash of (..., "node", "Click") + PushID(my_ptr); + Button("Click"); // Label = "Click", ID = hash of (..., "node", my_ptr, "Click") + PopID(); + PopID(); + + - Tree nodes implicitly creates a scope for you by calling PushID(). + + Button("Click"); // Label = "Click", ID = hash of (..., "Click") + if (TreeNode("node")) // <-- this function call will do a PushID() for you (unless instructed not to, with a special flag) + { + Button("Click"); // Label = "Click", ID = hash of (..., "node", "Click") + TreePop(); + } + + - When working with trees, ID are used to preserve the open/close state of each tree node. + Depending on your use cases you may want to use strings, indices or pointers as ID. + e.g. when following a single pointer that may change over time, using a static string as ID + will preserve your node open/closed state when the targeted object change. + e.g. when displaying a list of objects, using indices or pointers as ID will preserve the + node open/closed state differently. See what makes more sense in your situation! + + Q: How can I display an image? What is ImTextureID, how does it works? + >> See https://www.dearimgui.org/faq and https://github.com/ocornut/imgui/wiki/Image-Loading-and-Displaying-Examples + + Q: How can I use my own math types instead of ImVec2/ImVec4? + Q: How can I interact with standard C++ types (such as std::string and std::vector)? + Q: How can I display custom shapes? (using low-level ImDrawList API) + >> See https://www.dearimgui.org/faq + + Q&A: Fonts, Text + ================ + + Q: How can I load a different font than the default? + Q: How can I easily use icons in my application? + Q: How can I load multiple fonts? + Q: How can I display and input non-Latin characters such as Chinese, Japanese, Korean, Cyrillic? + >> See https://www.dearimgui.org/faq and docs/FONTS.txt + + Q&A: Concerns + ============= + + Q: Who uses Dear ImGui? + Q: Can you create elaborate/serious tools with Dear ImGui? + Q: Can you reskin the look of Dear ImGui? + Q: Why using C++ (as opposed to C)? + >> See https://www.dearimgui.org/faq + + Q&A: Community + ============== + + Q: How can I help? + A: - Businesses: please reach out to "contact AT dearimgui.org" if you work in a place using Dear ImGui! + We can discuss ways for your company to fund development via invoiced technical support, maintenance or sponsoring contacts. + This is among the most useful thing you can do for Dear ImGui. With increased funding we can hire more people working on this project. + - Individuals: you can support continued development via PayPal donations. See README. + - If you are experienced with Dear ImGui and C++, look at the github issues, look at the Wiki, read docs/TODO.txt + and see how you want to help and can help! + - Disclose your usage of Dear ImGui via a dev blog post, a tweet, a screenshot, a mention somewhere etc. + You may post screenshot or links in the gallery threads (github.com/ocornut/imgui/issues/3075). Visuals are ideal as they inspire other programmers. + But even without visuals, disclosing your use of dear imgui help the library grow credibility, and help other teams and programmers with taking decisions. + - If you have issues or if you need to hack into the library, even if you don't expect any support it is useful that you share your issues (on github or privately). + +*/ + +//------------------------------------------------------------------------- +// [SECTION] INCLUDES +//------------------------------------------------------------------------- + +#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS) +#define _CRT_SECURE_NO_WARNINGS +#endif + +#include "imgui.h" +#ifndef IMGUI_DISABLE + +#ifndef IMGUI_DEFINE_MATH_OPERATORS +#define IMGUI_DEFINE_MATH_OPERATORS +#endif +#include "imgui_internal.h" + +// System includes +#include // toupper +#include // vsnprintf, sscanf, printf +#if defined(_MSC_VER) && _MSC_VER <= 1500 // MSVC 2008 or earlier +#include // intptr_t +#else +#include // intptr_t +#endif + +// [Windows] OS specific includes (optional) +#if defined(_WIN32) && defined(IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS) && defined(IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS) && defined(IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS) +#define IMGUI_DISABLE_WIN32_FUNCTIONS +#endif +#if defined(_WIN32) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS) +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#ifndef NOMINMAX +#define NOMINMAX +#endif +#ifndef __MINGW32__ +#include // _wfopen, OpenClipboard +#else +#include +#endif +#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP) // UWP doesn't have all Win32 functions +#define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS +#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS +#endif +#endif + +// [Apple] OS specific includes +#if defined(__APPLE__) +#include +#endif + +// Visual Studio warnings +#ifdef _MSC_VER +#pragma warning (disable: 4127) // condition expression is constant +#pragma warning (disable: 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen +#if defined(_MSC_VER) && _MSC_VER >= 1922 // MSVC 2019 16.2 or later +#pragma warning (disable: 5054) // operator '|': deprecated between enumerations of different types +#endif +#endif + +// Clang/GCC warnings with -Weverything +#if defined(__clang__) +#pragma clang diagnostic ignored "-Wunknown-pragmas" // warning : unknown warning group '-Wformat-pedantic *' // not all warnings are known by all clang versions.. so ignoring warnings triggers new warnings on some configuration. great! +#pragma clang diagnostic ignored "-Wold-style-cast" // warning : use of old-style cast // yes, they are more terse. +#pragma clang diagnostic ignored "-Wfloat-equal" // warning : comparing floating point with == or != is unsafe // storing and comparing against same constants (typically 0.0f) is ok. +#pragma clang diagnostic ignored "-Wformat-nonliteral" // warning : format string is not a string literal // passing non-literal to vsnformat(). yes, user passing incorrect format strings can crash the code. +#pragma clang diagnostic ignored "-Wexit-time-destructors" // warning : declaration requires an exit-time destructor // exit-time destruction order is undefined. if MemFree() leads to users code that has been disabled before exit it might cause problems. ImGui coding style welcomes static/globals. +#pragma clang diagnostic ignored "-Wglobal-constructors" // warning : declaration requires a global destructor // similar to above, not sure what the exact difference is. +#pragma clang diagnostic ignored "-Wsign-conversion" // warning : implicit conversion changes signedness // +#pragma clang diagnostic ignored "-Wformat-pedantic" // warning : format specifies type 'void *' but the argument has type 'xxxx *' // unreasonable, would lead to casting every %p arg to void*. probably enabled by -pedantic. +#pragma clang diagnostic ignored "-Wint-to-void-pointer-cast" // warning : cast to 'void *' from smaller integer type 'int' +#if __has_warning("-Wzero-as-null-pointer-constant") +#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" // warning : zero as null pointer constant // some standard header variations use #define NULL 0 +#endif +#if __has_warning("-Wdouble-promotion") +#pragma clang diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function // using printf() is a misery with this as C++ va_arg ellipsis changes float to double. +#endif +#elif defined(__GNUC__) +// We disable -Wpragmas because GCC doesn't provide an has_warning equivalent and some forks/patches may not following the warning/version association. +#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind +#pragma GCC diagnostic ignored "-Wunused-function" // warning: 'xxxx' defined but not used +#pragma GCC diagnostic ignored "-Wint-to-pointer-cast" // warning: cast to pointer from integer of different size +#pragma GCC diagnostic ignored "-Wformat" // warning: format '%p' expects argument of type 'void*', but argument 6 has type 'ImGuiWindow*' +#pragma GCC diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function +#pragma GCC diagnostic ignored "-Wconversion" // warning: conversion to 'xxxx' from 'xxxx' may alter its value +#pragma GCC diagnostic ignored "-Wformat-nonliteral" // warning: format not a string literal, format string not checked +#pragma GCC diagnostic ignored "-Wstrict-overflow" // warning: assuming signed overflow does not occur when assuming that (X - c) > X is always false +#pragma GCC diagnostic ignored "-Wclass-memaccess" // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead +#endif + +// Debug options +#define IMGUI_DEBUG_NAV_SCORING 0 // Display navigation scoring preview when hovering items. Display last moving direction matches when holding CTRL +#define IMGUI_DEBUG_NAV_RECTS 0 // Display the reference navigation rectangle for each window +#define IMGUI_DEBUG_INI_SETTINGS 0 // Save additional comments in .ini file (particularly helps for Docking, but makes saving slower) + +// When using CTRL+TAB (or Gamepad Square+L/R) we delay the visual a little in order to reduce visual noise doing a fast switch. +static const float NAV_WINDOWING_HIGHLIGHT_DELAY = 0.20f; // Time before the highlight and screen dimming starts fading in +static const float NAV_WINDOWING_LIST_APPEAR_DELAY = 0.15f; // Time before the window list starts to appear + +// Window resizing from edges (when io.ConfigWindowsResizeFromEdges = true and ImGuiBackendFlags_HasMouseCursors is set in io.BackendFlags by back-end) +static const float WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS = 4.0f; // Extend outside and inside windows. Affect FindHoveredWindow(). +static const float WINDOWS_RESIZE_FROM_EDGES_FEEDBACK_TIMER = 0.04f; // Reduce visual noise by only highlighting the border after a certain time. +static const float WINDOWS_MOUSE_WHEEL_SCROLL_LOCK_TIMER = 2.00f; // Lock scrolled window (so it doesn't pick child windows that are scrolling through) for a certain time, unless mouse moved. + +// Docking +static const float DOCKING_TRANSPARENT_PAYLOAD_ALPHA = 0.50f; // For use with io.ConfigDockingTransparentPayload. Apply to Viewport _or_ WindowBg in host viewport. + +//------------------------------------------------------------------------- +// [SECTION] FORWARD DECLARATIONS +//------------------------------------------------------------------------- + +static void SetCurrentWindow(ImGuiWindow* window); +static void FindHoveredWindow(); +static ImGuiWindow* CreateNewWindow(const char* name, ImGuiWindowFlags flags); +static ImVec2 CalcNextScrollFromScrollTargetAndClamp(ImGuiWindow* window, bool snap_on_edges); + +static void AddDrawListToDrawData(ImVector* out_list, ImDrawList* draw_list); +static void AddWindowToSortBuffer(ImVector* out_sorted_windows, ImGuiWindow* window); + +// Settings +static void WindowSettingsHandler_ClearAll(ImGuiContext*, ImGuiSettingsHandler*); +static void* WindowSettingsHandler_ReadOpen(ImGuiContext*, ImGuiSettingsHandler*, const char* name); +static void WindowSettingsHandler_ReadLine(ImGuiContext*, ImGuiSettingsHandler*, void* entry, const char* line); +static void WindowSettingsHandler_ApplyAll(ImGuiContext*, ImGuiSettingsHandler*); +static void WindowSettingsHandler_WriteAll(ImGuiContext*, ImGuiSettingsHandler*, ImGuiTextBuffer* buf); + +// Platform Dependents default implementation for IO functions +static const char* GetClipboardTextFn_DefaultImpl(void* user_data); +static void SetClipboardTextFn_DefaultImpl(void* user_data, const char* text); + +namespace ImGui +{ +// Navigation +static void NavUpdate(); +static void NavUpdateWindowing(); +static void NavUpdateWindowingOverlay(); +static void NavUpdateMoveResult(); +static float NavUpdatePageUpPageDown(); +static inline void NavUpdateAnyRequestFlag(); +static void NavEndFrame(); +static bool NavScoreItem(ImGuiNavMoveResult* result, ImRect cand); +static void NavProcessItem(ImGuiWindow* window, const ImRect& nav_bb, ImGuiID id); +static ImVec2 NavCalcPreferredRefPos(); +static void NavSaveLastChildNavWindowIntoParent(ImGuiWindow* nav_window); +static ImGuiWindow* NavRestoreLastChildNavWindow(ImGuiWindow* window); +static int FindWindowFocusIndex(ImGuiWindow* window); + +// Error Checking +static void ErrorCheckNewFrameSanityChecks(); +static void ErrorCheckEndFrameSanityChecks(); +static void ErrorCheckBeginEndCompareStacksSize(ImGuiWindow* window, bool write); + +// Misc +static void UpdateSettings(); +static void UpdateMouseInputs(); +static void UpdateMouseWheel(); +static void UpdateTabFocus(); +static void UpdateDebugToolItemPicker(); +static bool UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& size_auto_fit, int* border_held, int resize_grip_count, ImU32 resize_grip_col[4]); +static void RenderWindowOuterBorders(ImGuiWindow* window); +static void RenderWindowDecorations(ImGuiWindow* window, const ImRect& title_bar_rect, bool title_bar_is_highlight, bool handle_borders_and_resize_grips, int resize_grip_count, const ImU32 resize_grip_col[4], float resize_grip_draw_size); +static void RenderWindowTitleBarContents(ImGuiWindow* window, const ImRect& title_bar_rect, const char* name, bool* p_open); +static void EndFrameDrawDimmedBackgrounds(); + +// Viewports +const ImGuiID IMGUI_VIEWPORT_DEFAULT_ID = 0x11111111; // Using an arbitrary constant instead of e.g. ImHashStr("ViewportDefault", 0); so it's easier to spot in the debugger. The exact value doesn't matter. +static ImGuiViewportP* AddUpdateViewport(ImGuiWindow* window, ImGuiID id, const ImVec2& platform_pos, const ImVec2& size, ImGuiViewportFlags flags); +static void UpdateViewportsNewFrame(); +static void UpdateViewportsEndFrame(); +static void UpdateSelectWindowViewport(ImGuiWindow* window); +static bool UpdateTryMergeWindowIntoHostViewport(ImGuiWindow* window, ImGuiViewportP* host_viewport); +static bool UpdateTryMergeWindowIntoHostViewports(ImGuiWindow* window); +static void SetCurrentViewport(ImGuiWindow* window, ImGuiViewportP* viewport); +static bool GetWindowAlwaysWantOwnViewport(ImGuiWindow* window); +static int FindPlatformMonitorForPos(const ImVec2& pos); +static int FindPlatformMonitorForRect(const ImRect& r); +static void UpdateViewportPlatformMonitor(ImGuiViewportP* viewport); + +} + +//----------------------------------------------------------------------------- +// [SECTION] CONTEXT AND MEMORY ALLOCATORS +//----------------------------------------------------------------------------- + +// Current context pointer. Implicitly used by all Dear ImGui functions. Always assumed to be != NULL. +// ImGui::CreateContext() will automatically set this pointer if it is NULL. Change to a different context by calling ImGui::SetCurrentContext(). +// 1) Important: globals are not shared across DLL boundaries! If you use DLLs or any form of hot-reloading: you will need to call +// SetCurrentContext() (with the pointer you got from CreateContext) from each unique static/DLL boundary, and after each hot-reloading. +// In your debugger, add GImGui to your watch window and notice how its value changes depending on which location you are currently stepping into. +// 2) Important: Dear ImGui functions are not thread-safe because of this pointer. +// If you want thread-safety to allow N threads to access N different contexts, you can: +// - Change this variable to use thread local storage so each thread can refer to a different context, in imconfig.h: +// struct ImGuiContext; +// extern thread_local ImGuiContext* MyImGuiTLS; +// #define GImGui MyImGuiTLS +// And then define MyImGuiTLS in one of your cpp file. Note that thread_local is a C++11 keyword, earlier C++ uses compiler-specific keyword. +// - Future development aim to make this context pointer explicit to all calls. Also read https://github.com/ocornut/imgui/issues/586 +// - If you need a finite number of contexts, you may compile and use multiple instances of the ImGui code from different namespace. +#ifndef GImGui +ImGuiContext* GImGui = NULL; +#endif + +// Memory Allocator functions. Use SetAllocatorFunctions() to change them. +// If you use DLL hotreloading you might need to call SetAllocatorFunctions() after reloading code from this file. +// Otherwise, you probably don't want to modify them mid-program, and if you use global/static e.g. ImVector<> instances you may need to keep them accessible during program destruction. +#ifndef IMGUI_DISABLE_DEFAULT_ALLOCATORS +static void* MallocWrapper(size_t size, void* user_data) { IM_UNUSED(user_data); return malloc(size); } +static void FreeWrapper(void* ptr, void* user_data) { IM_UNUSED(user_data); free(ptr); } +#else +static void* MallocWrapper(size_t size, void* user_data) { IM_UNUSED(user_data); IM_UNUSED(size); IM_ASSERT(0); return NULL; } +static void FreeWrapper(void* ptr, void* user_data) { IM_UNUSED(user_data); IM_UNUSED(ptr); IM_ASSERT(0); } +#endif + +static void* (*GImAllocatorAllocFunc)(size_t size, void* user_data) = MallocWrapper; +static void (*GImAllocatorFreeFunc)(void* ptr, void* user_data) = FreeWrapper; +static void* GImAllocatorUserData = NULL; + +//----------------------------------------------------------------------------- +// [SECTION] USER FACING STRUCTURES (ImGuiStyle, ImGuiIO) +//----------------------------------------------------------------------------- + +ImGuiStyle::ImGuiStyle() +{ + Alpha = 1.0f; // Global alpha applies to everything in ImGui + WindowPadding = ImVec2(8,8); // Padding within a window + WindowRounding = 7.0f; // Radius of window corners rounding. Set to 0.0f to have rectangular windows + WindowBorderSize = 1.0f; // Thickness of border around windows. Generally set to 0.0f or 1.0f. Other values not well tested. + WindowMinSize = ImVec2(32,32); // Minimum window size + WindowTitleAlign = ImVec2(0.0f,0.5f);// Alignment for title bar text + WindowMenuButtonPosition= ImGuiDir_Left; // Position of the collapsing/docking button in the title bar (left/right). Defaults to ImGuiDir_Left. + ChildRounding = 0.0f; // Radius of child window corners rounding. Set to 0.0f to have rectangular child windows + ChildBorderSize = 1.0f; // Thickness of border around child windows. Generally set to 0.0f or 1.0f. Other values not well tested. + PopupRounding = 0.0f; // Radius of popup window corners rounding. Set to 0.0f to have rectangular child windows + PopupBorderSize = 1.0f; // Thickness of border around popup or tooltip windows. Generally set to 0.0f or 1.0f. Other values not well tested. + FramePadding = ImVec2(4,3); // Padding within a framed rectangle (used by most widgets) + FrameRounding = 0.0f; // Radius of frame corners rounding. Set to 0.0f to have rectangular frames (used by most widgets). + FrameBorderSize = 0.0f; // Thickness of border around frames. Generally set to 0.0f or 1.0f. Other values not well tested. + ItemSpacing = ImVec2(8,4); // Horizontal and vertical spacing between widgets/lines + ItemInnerSpacing = ImVec2(4,4); // Horizontal and vertical spacing between within elements of a composed widget (e.g. a slider and its label) + TouchExtraPadding = ImVec2(0,0); // Expand reactive bounding box for touch-based system where touch position is not accurate enough. Unfortunately we don't sort widgets so priority on overlap will always be given to the first widget. So don't grow this too much! + IndentSpacing = 21.0f; // Horizontal spacing when e.g. entering a tree node. Generally == (FontSize + FramePadding.x*2). + ColumnsMinSpacing = 6.0f; // Minimum horizontal spacing between two columns. Preferably > (FramePadding.x + 1). + ScrollbarSize = 14.0f; // Width of the vertical scrollbar, Height of the horizontal scrollbar + ScrollbarRounding = 9.0f; // Radius of grab corners rounding for scrollbar + GrabMinSize = 10.0f; // Minimum width/height of a grab box for slider/scrollbar + GrabRounding = 0.0f; // Radius of grabs corners rounding. Set to 0.0f to have rectangular slider grabs. + TabRounding = 4.0f; // Radius of upper corners of a tab. Set to 0.0f to have rectangular tabs. + TabBorderSize = 0.0f; // Thickness of border around tabs. + TabMinWidthForUnselectedCloseButton = 0.0f; // Minimum width for close button to appears on an unselected tab when hovered. Set to 0.0f to always show when hovering, set to FLT_MAX to never show close button unless selected. + ColorButtonPosition = ImGuiDir_Right; // Side of the color button in the ColorEdit4 widget (left/right). Defaults to ImGuiDir_Right. + ButtonTextAlign = ImVec2(0.5f,0.5f);// Alignment of button text when button is larger than text. + SelectableTextAlign = ImVec2(0.0f,0.0f);// Alignment of selectable text. Defaults to (0.0f, 0.0f) (top-left aligned). It's generally important to keep this left-aligned if you want to lay multiple items on a same line. + DisplayWindowPadding = ImVec2(19,19); // Window position are clamped to be visible within the display area or monitors by at least this amount. Only applies to regular windows. + DisplaySafeAreaPadding = ImVec2(3,3); // If you cannot see the edge of your screen (e.g. on a TV) increase the safe area padding. Covers popups/tooltips as well regular windows. + MouseCursorScale = 1.0f; // Scale software rendered mouse cursor (when io.MouseDrawCursor is enabled). May be removed later. + AntiAliasedLines = true; // Enable anti-aliasing on lines/borders. Disable if you are really short on CPU/GPU. + AntiAliasedFill = true; // Enable anti-aliasing on filled shapes (rounded rectangles, circles, etc.) + CurveTessellationTol = 1.25f; // Tessellation tolerance when using PathBezierCurveTo() without a specific number of segments. Decrease for highly tessellated curves (higher quality, more polygons), increase to reduce quality. + CircleSegmentMaxError = 1.60f; // Maximum error (in pixels) allowed when using AddCircle()/AddCircleFilled() or drawing rounded corner rectangles with no explicit segment count specified. Decrease for higher quality but more geometry. + + // Default theme + ImGui::StyleColorsDark(this); +} + +// To scale your entire UI (e.g. if you want your app to use High DPI or generally be DPI aware) you may use this helper function. Scaling the fonts is done separately and is up to you. +// Important: This operation is lossy because we round all sizes to integer. If you need to change your scale multiples, call this over a freshly initialized ImGuiStyle structure rather than scaling multiple times. +void ImGuiStyle::ScaleAllSizes(float scale_factor) +{ + WindowPadding = ImFloor(WindowPadding * scale_factor); + WindowRounding = ImFloor(WindowRounding * scale_factor); + WindowMinSize = ImFloor(WindowMinSize * scale_factor); + ChildRounding = ImFloor(ChildRounding * scale_factor); + PopupRounding = ImFloor(PopupRounding * scale_factor); + FramePadding = ImFloor(FramePadding * scale_factor); + FrameRounding = ImFloor(FrameRounding * scale_factor); + ItemSpacing = ImFloor(ItemSpacing * scale_factor); + ItemInnerSpacing = ImFloor(ItemInnerSpacing * scale_factor); + TouchExtraPadding = ImFloor(TouchExtraPadding * scale_factor); + IndentSpacing = ImFloor(IndentSpacing * scale_factor); + ColumnsMinSpacing = ImFloor(ColumnsMinSpacing * scale_factor); + ScrollbarSize = ImFloor(ScrollbarSize * scale_factor); + ScrollbarRounding = ImFloor(ScrollbarRounding * scale_factor); + GrabMinSize = ImFloor(GrabMinSize * scale_factor); + GrabRounding = ImFloor(GrabRounding * scale_factor); + TabRounding = ImFloor(TabRounding * scale_factor); + if (TabMinWidthForUnselectedCloseButton != FLT_MAX) + TabMinWidthForUnselectedCloseButton = ImFloor(TabMinWidthForUnselectedCloseButton * scale_factor); + DisplayWindowPadding = ImFloor(DisplayWindowPadding * scale_factor); + DisplaySafeAreaPadding = ImFloor(DisplaySafeAreaPadding * scale_factor); + MouseCursorScale = ImFloor(MouseCursorScale * scale_factor); +} + +ImGuiIO::ImGuiIO() +{ + // Most fields are initialized with zero + memset(this, 0, sizeof(*this)); + IM_ASSERT(IM_ARRAYSIZE(ImGuiIO::MouseDown) == ImGuiMouseButton_COUNT && IM_ARRAYSIZE(ImGuiIO::MouseClicked) == ImGuiMouseButton_COUNT); // Our pre-C++11 IM_STATIC_ASSERT() macros triggers warning on modern compilers so we don't use it here. + + // Settings + ConfigFlags = ImGuiConfigFlags_None; + BackendFlags = ImGuiBackendFlags_None; + DisplaySize = ImVec2(-1.0f, -1.0f); + DeltaTime = 1.0f/60.0f; + IniSavingRate = 5.0f; + IniFilename = "imgui.ini"; + LogFilename = "imgui_log.txt"; + MouseDoubleClickTime = 0.30f; + MouseDoubleClickMaxDist = 6.0f; + for (int i = 0; i < ImGuiKey_COUNT; i++) + KeyMap[i] = -1; + KeyRepeatDelay = 0.275f; + KeyRepeatRate = 0.050f; + UserData = NULL; + + Fonts = NULL; + FontGlobalScale = 1.0f; + FontDefault = NULL; + FontAllowUserScaling = false; + DisplayFramebufferScale = ImVec2(1.0f, 1.0f); + + // Docking options (when ImGuiConfigFlags_DockingEnable is set) + ConfigDockingNoSplit = false; + ConfigDockingWithShift = false; + ConfigDockingAlwaysTabBar = false; + ConfigDockingTransparentPayload = false; + + // Viewport options (when ImGuiConfigFlags_ViewportsEnable is set) + ConfigViewportsNoAutoMerge = false; + ConfigViewportsNoTaskBarIcon = false; + ConfigViewportsNoDecoration = true; + ConfigViewportsNoDefaultParent = false; + + // Miscellaneous options + MouseDrawCursor = false; +#ifdef __APPLE__ + ConfigMacOSXBehaviors = true; // Set Mac OS X style defaults based on __APPLE__ compile time flag +#else + ConfigMacOSXBehaviors = false; +#endif + ConfigInputTextCursorBlink = true; + ConfigWindowsResizeFromEdges = true; + ConfigWindowsMoveFromTitleBarOnly = false; + ConfigWindowsMemoryCompactTimer = 60.0f; + + // Platform Functions + BackendPlatformName = BackendRendererName = NULL; + BackendPlatformUserData = BackendRendererUserData = BackendLanguageUserData = NULL; + GetClipboardTextFn = GetClipboardTextFn_DefaultImpl; // Platform dependent default implementations + SetClipboardTextFn = SetClipboardTextFn_DefaultImpl; + ClipboardUserData = NULL; + +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + RenderDrawListsFn = NULL; +#endif + + // Input (NB: we already have memset zero the entire structure!) + MousePos = ImVec2(-FLT_MAX, -FLT_MAX); + MousePosPrev = ImVec2(-FLT_MAX, -FLT_MAX); + MouseDragThreshold = 6.0f; + for (int i = 0; i < IM_ARRAYSIZE(MouseDownDuration); i++) MouseDownDuration[i] = MouseDownDurationPrev[i] = -1.0f; + for (int i = 0; i < IM_ARRAYSIZE(KeysDownDuration); i++) KeysDownDuration[i] = KeysDownDurationPrev[i] = -1.0f; + for (int i = 0; i < IM_ARRAYSIZE(NavInputsDownDuration); i++) NavInputsDownDuration[i] = -1.0f; +} + +// Pass in translated ASCII characters for text input. +// - with glfw you can get those from the callback set in glfwSetCharCallback() +// - on Windows you can get those using ToAscii+keyboard state, or via the WM_CHAR message +void ImGuiIO::AddInputCharacter(unsigned int c) +{ + InputQueueCharacters.push_back(c > 0 && c <= IM_UNICODE_CODEPOINT_MAX ? (ImWchar)c : IM_UNICODE_CODEPOINT_INVALID); +} + +// UTF16 strings use surrogate pairs to encode codepoints >= 0x10000, so +// we should save the high surrogate. +void ImGuiIO::AddInputCharacterUTF16(ImWchar16 c) +{ + if ((c & 0xFC00) == 0xD800) // High surrogate, must save + { + if (InputQueueSurrogate != 0) + InputQueueCharacters.push_back(0xFFFD); + InputQueueSurrogate = c; + return; + } + + ImWchar cp = c; + if (InputQueueSurrogate != 0) + { + if ((c & 0xFC00) != 0xDC00) // Invalid low surrogate + InputQueueCharacters.push_back(IM_UNICODE_CODEPOINT_INVALID); + else if (IM_UNICODE_CODEPOINT_MAX == (0xFFFF)) // Codepoint will not fit in ImWchar (extra parenthesis around 0xFFFF somehow fixes -Wunreachable-code with Clang) + cp = IM_UNICODE_CODEPOINT_INVALID; + else + cp = (ImWchar)(((InputQueueSurrogate - 0xD800) << 10) + (c - 0xDC00) + 0x10000); + InputQueueSurrogate = 0; + } + InputQueueCharacters.push_back(cp); +} + +void ImGuiIO::AddInputCharactersUTF8(const char* utf8_chars) +{ + while (*utf8_chars != 0) + { + unsigned int c = 0; + utf8_chars += ImTextCharFromUtf8(&c, utf8_chars, NULL); + if (c > 0) + InputQueueCharacters.push_back((ImWchar)c); + } +} + +void ImGuiIO::ClearInputCharacters() +{ + InputQueueCharacters.resize(0); +} + +//----------------------------------------------------------------------------- +// [SECTION] MISC HELPERS/UTILITIES (Geometry functions) +//----------------------------------------------------------------------------- + +ImVec2 ImBezierClosestPoint(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, const ImVec2& p, int num_segments) +{ + IM_ASSERT(num_segments > 0); // Use ImBezierClosestPointCasteljau() + ImVec2 p_last = p1; + ImVec2 p_closest; + float p_closest_dist2 = FLT_MAX; + float t_step = 1.0f / (float)num_segments; + for (int i_step = 1; i_step <= num_segments; i_step++) + { + ImVec2 p_current = ImBezierCalc(p1, p2, p3, p4, t_step * i_step); + ImVec2 p_line = ImLineClosestPoint(p_last, p_current, p); + float dist2 = ImLengthSqr(p - p_line); + if (dist2 < p_closest_dist2) + { + p_closest = p_line; + p_closest_dist2 = dist2; + } + p_last = p_current; + } + return p_closest; +} + +// Closely mimics PathBezierToCasteljau() in imgui_draw.cpp +static void BezierClosestPointCasteljauStep(const ImVec2& p, ImVec2& p_closest, ImVec2& p_last, float& p_closest_dist2, float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4, float tess_tol, int level) +{ + float dx = x4 - x1; + float dy = y4 - y1; + float d2 = ((x2 - x4) * dy - (y2 - y4) * dx); + float d3 = ((x3 - x4) * dy - (y3 - y4) * dx); + d2 = (d2 >= 0) ? d2 : -d2; + d3 = (d3 >= 0) ? d3 : -d3; + if ((d2+d3) * (d2+d3) < tess_tol * (dx*dx + dy*dy)) + { + ImVec2 p_current(x4, y4); + ImVec2 p_line = ImLineClosestPoint(p_last, p_current, p); + float dist2 = ImLengthSqr(p - p_line); + if (dist2 < p_closest_dist2) + { + p_closest = p_line; + p_closest_dist2 = dist2; + } + p_last = p_current; + } + else if (level < 10) + { + float x12 = (x1+x2)*0.5f, y12 = (y1+y2)*0.5f; + float x23 = (x2+x3)*0.5f, y23 = (y2+y3)*0.5f; + float x34 = (x3+x4)*0.5f, y34 = (y3+y4)*0.5f; + float x123 = (x12+x23)*0.5f, y123 = (y12+y23)*0.5f; + float x234 = (x23+x34)*0.5f, y234 = (y23+y34)*0.5f; + float x1234 = (x123+x234)*0.5f, y1234 = (y123+y234)*0.5f; + BezierClosestPointCasteljauStep(p, p_closest, p_last, p_closest_dist2, x1, y1, x12, y12, x123, y123, x1234, y1234, tess_tol, level + 1); + BezierClosestPointCasteljauStep(p, p_closest, p_last, p_closest_dist2, x1234, y1234, x234, y234, x34, y34, x4, y4, tess_tol, level + 1); + } +} + +// tess_tol is generally the same value you would find in ImGui::GetStyle().CurveTessellationTol +// Because those ImXXX functions are lower-level than ImGui:: we cannot access this value automatically. +ImVec2 ImBezierClosestPointCasteljau(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, const ImVec2& p, float tess_tol) +{ + IM_ASSERT(tess_tol > 0.0f); + ImVec2 p_last = p1; + ImVec2 p_closest; + float p_closest_dist2 = FLT_MAX; + BezierClosestPointCasteljauStep(p, p_closest, p_last, p_closest_dist2, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, p4.x, p4.y, tess_tol, 0); + return p_closest; +} + +ImVec2 ImLineClosestPoint(const ImVec2& a, const ImVec2& b, const ImVec2& p) +{ + ImVec2 ap = p - a; + ImVec2 ab_dir = b - a; + float dot = ap.x * ab_dir.x + ap.y * ab_dir.y; + if (dot < 0.0f) + return a; + float ab_len_sqr = ab_dir.x * ab_dir.x + ab_dir.y * ab_dir.y; + if (dot > ab_len_sqr) + return b; + return a + ab_dir * dot / ab_len_sqr; +} + +bool ImTriangleContainsPoint(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p) +{ + bool b1 = ((p.x - b.x) * (a.y - b.y) - (p.y - b.y) * (a.x - b.x)) < 0.0f; + bool b2 = ((p.x - c.x) * (b.y - c.y) - (p.y - c.y) * (b.x - c.x)) < 0.0f; + bool b3 = ((p.x - a.x) * (c.y - a.y) - (p.y - a.y) * (c.x - a.x)) < 0.0f; + return ((b1 == b2) && (b2 == b3)); +} + +void ImTriangleBarycentricCoords(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p, float& out_u, float& out_v, float& out_w) +{ + ImVec2 v0 = b - a; + ImVec2 v1 = c - a; + ImVec2 v2 = p - a; + const float denom = v0.x * v1.y - v1.x * v0.y; + out_v = (v2.x * v1.y - v1.x * v2.y) / denom; + out_w = (v0.x * v2.y - v2.x * v0.y) / denom; + out_u = 1.0f - out_v - out_w; +} + +ImVec2 ImTriangleClosestPoint(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p) +{ + ImVec2 proj_ab = ImLineClosestPoint(a, b, p); + ImVec2 proj_bc = ImLineClosestPoint(b, c, p); + ImVec2 proj_ca = ImLineClosestPoint(c, a, p); + float dist2_ab = ImLengthSqr(p - proj_ab); + float dist2_bc = ImLengthSqr(p - proj_bc); + float dist2_ca = ImLengthSqr(p - proj_ca); + float m = ImMin(dist2_ab, ImMin(dist2_bc, dist2_ca)); + if (m == dist2_ab) + return proj_ab; + if (m == dist2_bc) + return proj_bc; + return proj_ca; +} + +//----------------------------------------------------------------------------- +// [SECTION] MISC HELPERS/UTILITIES (String, Format, Hash functions) +//----------------------------------------------------------------------------- + +// Consider using _stricmp/_strnicmp under Windows or strcasecmp/strncasecmp. We don't actually use either ImStricmp/ImStrnicmp in the codebase any more. +int ImStricmp(const char* str1, const char* str2) +{ + int d; + while ((d = toupper(*str2) - toupper(*str1)) == 0 && *str1) { str1++; str2++; } + return d; +} + +int ImStrnicmp(const char* str1, const char* str2, size_t count) +{ + int d = 0; + while (count > 0 && (d = toupper(*str2) - toupper(*str1)) == 0 && *str1) { str1++; str2++; count--; } + return d; +} + +void ImStrncpy(char* dst, const char* src, size_t count) +{ + if (count < 1) + return; + if (count > 1) + strncpy(dst, src, count - 1); + dst[count - 1] = 0; +} + +char* ImStrdup(const char* str) +{ + size_t len = strlen(str); + void* buf = IM_ALLOC(len + 1); + return (char*)memcpy(buf, (const void*)str, len + 1); +} + +char* ImStrdupcpy(char* dst, size_t* p_dst_size, const char* src) +{ + size_t dst_buf_size = p_dst_size ? *p_dst_size : strlen(dst) + 1; + size_t src_size = strlen(src) + 1; + if (dst_buf_size < src_size) + { + IM_FREE(dst); + dst = (char*)IM_ALLOC(src_size); + if (p_dst_size) + *p_dst_size = src_size; + } + return (char*)memcpy(dst, (const void*)src, src_size); +} + +const char* ImStrchrRange(const char* str, const char* str_end, char c) +{ + const char* p = (const char*)memchr(str, (int)c, str_end - str); + return p; +} + +int ImStrlenW(const ImWchar* str) +{ + //return (int)wcslen((const wchar_t*)str); // FIXME-OPT: Could use this when wchar_t are 16-bit + int n = 0; + while (*str++) n++; + return n; +} + +// Find end-of-line. Return pointer will point to either first \n, either str_end. +const char* ImStreolRange(const char* str, const char* str_end) +{ + const char* p = (const char*)memchr(str, '\n', str_end - str); + return p ? p : str_end; +} + +const ImWchar* ImStrbolW(const ImWchar* buf_mid_line, const ImWchar* buf_begin) // find beginning-of-line +{ + while (buf_mid_line > buf_begin && buf_mid_line[-1] != '\n') + buf_mid_line--; + return buf_mid_line; +} + +const char* ImStristr(const char* haystack, const char* haystack_end, const char* needle, const char* needle_end) +{ + if (!needle_end) + needle_end = needle + strlen(needle); + + const char un0 = (char)toupper(*needle); + while ((!haystack_end && *haystack) || (haystack_end && haystack < haystack_end)) + { + if (toupper(*haystack) == un0) + { + const char* b = needle + 1; + for (const char* a = haystack + 1; b < needle_end; a++, b++) + if (toupper(*a) != toupper(*b)) + break; + if (b == needle_end) + return haystack; + } + haystack++; + } + return NULL; +} + +// Trim str by offsetting contents when there's leading data + writing a \0 at the trailing position. We use this in situation where the cost is negligible. +void ImStrTrimBlanks(char* buf) +{ + char* p = buf; + while (p[0] == ' ' || p[0] == '\t') // Leading blanks + p++; + char* p_start = p; + while (*p != 0) // Find end of string + p++; + while (p > p_start && (p[-1] == ' ' || p[-1] == '\t')) // Trailing blanks + p--; + if (p_start != buf) // Copy memory if we had leading blanks + memmove(buf, p_start, p - p_start); + buf[p - p_start] = 0; // Zero terminate +} + +const char* ImStrSkipBlank(const char* str) +{ + while (str[0] == ' ' || str[0] == '\t') + str++; + return str; +} + +// A) MSVC version appears to return -1 on overflow, whereas glibc appears to return total count (which may be >= buf_size). +// Ideally we would test for only one of those limits at runtime depending on the behavior the vsnprintf(), but trying to deduct it at compile time sounds like a pandora can of worm. +// B) When buf==NULL vsnprintf() will return the output size. +#ifndef IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS + +// We support stb_sprintf which is much faster (see: https://github.com/nothings/stb/blob/master/stb_sprintf.h) +// You may set IMGUI_USE_STB_SPRINTF to use our default wrapper, or set IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS +// and setup the wrapper yourself. (FIXME-OPT: Some of our high-level operations such as ImGuiTextBuffer::appendfv() are +// designed using two-passes worst case, which probably could be improved using the stbsp_vsprintfcb() function.) +#ifdef IMGUI_USE_STB_SPRINTF +#define STB_SPRINTF_IMPLEMENTATION +#include "stb_sprintf.h" +#endif + +#if defined(_MSC_VER) && !defined(vsnprintf) +#define vsnprintf _vsnprintf +#endif + +int ImFormatString(char* buf, size_t buf_size, const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); +#ifdef IMGUI_USE_STB_SPRINTF + int w = stbsp_vsnprintf(buf, (int)buf_size, fmt, args); +#else + int w = vsnprintf(buf, buf_size, fmt, args); +#endif + va_end(args); + if (buf == NULL) + return w; + if (w == -1 || w >= (int)buf_size) + w = (int)buf_size - 1; + buf[w] = 0; + return w; +} + +int ImFormatStringV(char* buf, size_t buf_size, const char* fmt, va_list args) +{ +#ifdef IMGUI_USE_STB_SPRINTF + int w = stbsp_vsnprintf(buf, (int)buf_size, fmt, args); +#else + int w = vsnprintf(buf, buf_size, fmt, args); +#endif + if (buf == NULL) + return w; + if (w == -1 || w >= (int)buf_size) + w = (int)buf_size - 1; + buf[w] = 0; + return w; +} +#endif // #ifdef IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS + +// CRC32 needs a 1KB lookup table (not cache friendly) +// Although the code to generate the table is simple and shorter than the table itself, using a const table allows us to easily: +// - avoid an unnecessary branch/memory tap, - keep the ImHashXXX functions usable by static constructors, - make it thread-safe. +static const ImU32 GCrc32LookupTable[256] = +{ + 0x00000000,0x77073096,0xEE0E612C,0x990951BA,0x076DC419,0x706AF48F,0xE963A535,0x9E6495A3,0x0EDB8832,0x79DCB8A4,0xE0D5E91E,0x97D2D988,0x09B64C2B,0x7EB17CBD,0xE7B82D07,0x90BF1D91, + 0x1DB71064,0x6AB020F2,0xF3B97148,0x84BE41DE,0x1ADAD47D,0x6DDDE4EB,0xF4D4B551,0x83D385C7,0x136C9856,0x646BA8C0,0xFD62F97A,0x8A65C9EC,0x14015C4F,0x63066CD9,0xFA0F3D63,0x8D080DF5, + 0x3B6E20C8,0x4C69105E,0xD56041E4,0xA2677172,0x3C03E4D1,0x4B04D447,0xD20D85FD,0xA50AB56B,0x35B5A8FA,0x42B2986C,0xDBBBC9D6,0xACBCF940,0x32D86CE3,0x45DF5C75,0xDCD60DCF,0xABD13D59, + 0x26D930AC,0x51DE003A,0xC8D75180,0xBFD06116,0x21B4F4B5,0x56B3C423,0xCFBA9599,0xB8BDA50F,0x2802B89E,0x5F058808,0xC60CD9B2,0xB10BE924,0x2F6F7C87,0x58684C11,0xC1611DAB,0xB6662D3D, + 0x76DC4190,0x01DB7106,0x98D220BC,0xEFD5102A,0x71B18589,0x06B6B51F,0x9FBFE4A5,0xE8B8D433,0x7807C9A2,0x0F00F934,0x9609A88E,0xE10E9818,0x7F6A0DBB,0x086D3D2D,0x91646C97,0xE6635C01, + 0x6B6B51F4,0x1C6C6162,0x856530D8,0xF262004E,0x6C0695ED,0x1B01A57B,0x8208F4C1,0xF50FC457,0x65B0D9C6,0x12B7E950,0x8BBEB8EA,0xFCB9887C,0x62DD1DDF,0x15DA2D49,0x8CD37CF3,0xFBD44C65, + 0x4DB26158,0x3AB551CE,0xA3BC0074,0xD4BB30E2,0x4ADFA541,0x3DD895D7,0xA4D1C46D,0xD3D6F4FB,0x4369E96A,0x346ED9FC,0xAD678846,0xDA60B8D0,0x44042D73,0x33031DE5,0xAA0A4C5F,0xDD0D7CC9, + 0x5005713C,0x270241AA,0xBE0B1010,0xC90C2086,0x5768B525,0x206F85B3,0xB966D409,0xCE61E49F,0x5EDEF90E,0x29D9C998,0xB0D09822,0xC7D7A8B4,0x59B33D17,0x2EB40D81,0xB7BD5C3B,0xC0BA6CAD, + 0xEDB88320,0x9ABFB3B6,0x03B6E20C,0x74B1D29A,0xEAD54739,0x9DD277AF,0x04DB2615,0x73DC1683,0xE3630B12,0x94643B84,0x0D6D6A3E,0x7A6A5AA8,0xE40ECF0B,0x9309FF9D,0x0A00AE27,0x7D079EB1, + 0xF00F9344,0x8708A3D2,0x1E01F268,0x6906C2FE,0xF762575D,0x806567CB,0x196C3671,0x6E6B06E7,0xFED41B76,0x89D32BE0,0x10DA7A5A,0x67DD4ACC,0xF9B9DF6F,0x8EBEEFF9,0x17B7BE43,0x60B08ED5, + 0xD6D6A3E8,0xA1D1937E,0x38D8C2C4,0x4FDFF252,0xD1BB67F1,0xA6BC5767,0x3FB506DD,0x48B2364B,0xD80D2BDA,0xAF0A1B4C,0x36034AF6,0x41047A60,0xDF60EFC3,0xA867DF55,0x316E8EEF,0x4669BE79, + 0xCB61B38C,0xBC66831A,0x256FD2A0,0x5268E236,0xCC0C7795,0xBB0B4703,0x220216B9,0x5505262F,0xC5BA3BBE,0xB2BD0B28,0x2BB45A92,0x5CB36A04,0xC2D7FFA7,0xB5D0CF31,0x2CD99E8B,0x5BDEAE1D, + 0x9B64C2B0,0xEC63F226,0x756AA39C,0x026D930A,0x9C0906A9,0xEB0E363F,0x72076785,0x05005713,0x95BF4A82,0xE2B87A14,0x7BB12BAE,0x0CB61B38,0x92D28E9B,0xE5D5BE0D,0x7CDCEFB7,0x0BDBDF21, + 0x86D3D2D4,0xF1D4E242,0x68DDB3F8,0x1FDA836E,0x81BE16CD,0xF6B9265B,0x6FB077E1,0x18B74777,0x88085AE6,0xFF0F6A70,0x66063BCA,0x11010B5C,0x8F659EFF,0xF862AE69,0x616BFFD3,0x166CCF45, + 0xA00AE278,0xD70DD2EE,0x4E048354,0x3903B3C2,0xA7672661,0xD06016F7,0x4969474D,0x3E6E77DB,0xAED16A4A,0xD9D65ADC,0x40DF0B66,0x37D83BF0,0xA9BCAE53,0xDEBB9EC5,0x47B2CF7F,0x30B5FFE9, + 0xBDBDF21C,0xCABAC28A,0x53B39330,0x24B4A3A6,0xBAD03605,0xCDD70693,0x54DE5729,0x23D967BF,0xB3667A2E,0xC4614AB8,0x5D681B02,0x2A6F2B94,0xB40BBE37,0xC30C8EA1,0x5A05DF1B,0x2D02EF8D, +}; + +// Known size hash +// It is ok to call ImHashData on a string with known length but the ### operator won't be supported. +// FIXME-OPT: Replace with e.g. FNV1a hash? CRC32 pretty much randomly access 1KB. Need to do proper measurements. +ImU32 ImHashData(const void* data_p, size_t data_size, ImU32 seed) +{ + ImU32 crc = ~seed; + const unsigned char* data = (const unsigned char*)data_p; + const ImU32* crc32_lut = GCrc32LookupTable; + while (data_size-- != 0) + crc = (crc >> 8) ^ crc32_lut[(crc & 0xFF) ^ *data++]; + return ~crc; +} + +// Zero-terminated string hash, with support for ### to reset back to seed value +// We support a syntax of "label###id" where only "###id" is included in the hash, and only "label" gets displayed. +// Because this syntax is rarely used we are optimizing for the common case. +// - If we reach ### in the string we discard the hash so far and reset to the seed. +// - We don't do 'current += 2; continue;' after handling ### to keep the code smaller/faster (measured ~10% diff in Debug build) +// FIXME-OPT: Replace with e.g. FNV1a hash? CRC32 pretty much randomly access 1KB. Need to do proper measurements. +ImU32 ImHashStr(const char* data_p, size_t data_size, ImU32 seed) +{ + seed = ~seed; + ImU32 crc = seed; + const unsigned char* data = (const unsigned char*)data_p; + const ImU32* crc32_lut = GCrc32LookupTable; + if (data_size != 0) + { + while (data_size-- != 0) + { + unsigned char c = *data++; + if (c == '#' && data_size >= 2 && data[0] == '#' && data[1] == '#') + crc = seed; + crc = (crc >> 8) ^ crc32_lut[(crc & 0xFF) ^ c]; + } + } + else + { + while (unsigned char c = *data++) + { + if (c == '#' && data[0] == '#' && data[1] == '#') + crc = seed; + crc = (crc >> 8) ^ crc32_lut[(crc & 0xFF) ^ c]; + } + } + return ~crc; +} + +//----------------------------------------------------------------------------- +// [SECTION] MISC HELPERS/UTILITIES (File functions) +//----------------------------------------------------------------------------- + +// Default file functions +#ifndef IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS + +ImFileHandle ImFileOpen(const char* filename, const char* mode) +{ +#if defined(_WIN32) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS) && !defined(__CYGWIN__) && !defined(__GNUC__) + // We need a fopen() wrapper because MSVC/Windows fopen doesn't handle UTF-8 filenames. + // Previously we used ImTextCountCharsFromUtf8/ImTextStrFromUtf8 here but we now need to support ImWchar16 and ImWchar32! + const int filename_wsize = ::MultiByteToWideChar(CP_UTF8, 0, filename, -1, NULL, 0); + const int mode_wsize = ::MultiByteToWideChar(CP_UTF8, 0, mode, -1, NULL, 0); + ImVector buf; + buf.resize(filename_wsize + mode_wsize); + ::MultiByteToWideChar(CP_UTF8, 0, filename, -1, (wchar_t*)&buf[0], filename_wsize); + ::MultiByteToWideChar(CP_UTF8, 0, mode, -1, (wchar_t*)&buf[filename_wsize], mode_wsize); + return ::_wfopen((const wchar_t*)&buf[0], (const wchar_t*)&buf[filename_wsize]); +#else + return fopen(filename, mode); +#endif +} + +// We should in theory be using fseeko()/ftello() with off_t and _fseeki64()/_ftelli64() with __int64, waiting for the PR that does that in a very portable pre-C++11 zero-warnings way. +bool ImFileClose(ImFileHandle f) { return fclose(f) == 0; } +ImU64 ImFileGetSize(ImFileHandle f) { long off = 0, sz = 0; return ((off = ftell(f)) != -1 && !fseek(f, 0, SEEK_END) && (sz = ftell(f)) != -1 && !fseek(f, off, SEEK_SET)) ? (ImU64)sz : (ImU64)-1; } +ImU64 ImFileRead(void* data, ImU64 sz, ImU64 count, ImFileHandle f) { return fread(data, (size_t)sz, (size_t)count, f); } +ImU64 ImFileWrite(const void* data, ImU64 sz, ImU64 count, ImFileHandle f) { return fwrite(data, (size_t)sz, (size_t)count, f); } +#endif // #ifndef IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS + +// Helper: Load file content into memory +// Memory allocated with IM_ALLOC(), must be freed by user using IM_FREE() == ImGui::MemFree() +// This can't really be used with "rt" because fseek size won't match read size. +void* ImFileLoadToMemory(const char* filename, const char* mode, size_t* out_file_size, int padding_bytes) +{ + IM_ASSERT(filename && mode); + if (out_file_size) + *out_file_size = 0; + + ImFileHandle f; + if ((f = ImFileOpen(filename, mode)) == NULL) + return NULL; + + size_t file_size = (size_t)ImFileGetSize(f); + if (file_size == (size_t)-1) + { + ImFileClose(f); + return NULL; + } + + void* file_data = IM_ALLOC(file_size + padding_bytes); + if (file_data == NULL) + { + ImFileClose(f); + return NULL; + } + if (ImFileRead(file_data, 1, file_size, f) != file_size) + { + ImFileClose(f); + IM_FREE(file_data); + return NULL; + } + if (padding_bytes > 0) + memset((void*)(((char*)file_data) + file_size), 0, (size_t)padding_bytes); + + ImFileClose(f); + if (out_file_size) + *out_file_size = file_size; + + return file_data; +} + +//----------------------------------------------------------------------------- +// [SECTION] MISC HELPERS/UTILITIES (ImText* functions) +//----------------------------------------------------------------------------- + +// Convert UTF-8 to 32-bit character, process single character input. +// Based on stb_from_utf8() from github.com/nothings/stb/ +// We handle UTF-8 decoding error by skipping forward. +int ImTextCharFromUtf8(unsigned int* out_char, const char* in_text, const char* in_text_end) +{ + unsigned int c = (unsigned int)-1; + const unsigned char* str = (const unsigned char*)in_text; + if (!(*str & 0x80)) + { + c = (unsigned int)(*str++); + *out_char = c; + return 1; + } + if ((*str & 0xe0) == 0xc0) + { + *out_char = IM_UNICODE_CODEPOINT_INVALID; // will be invalid but not end of string + if (in_text_end && in_text_end - (const char*)str < 2) return 1; + if (*str < 0xc2) return 2; + c = (unsigned int)((*str++ & 0x1f) << 6); + if ((*str & 0xc0) != 0x80) return 2; + c += (*str++ & 0x3f); + *out_char = c; + return 2; + } + if ((*str & 0xf0) == 0xe0) + { + *out_char = IM_UNICODE_CODEPOINT_INVALID; // will be invalid but not end of string + if (in_text_end && in_text_end - (const char*)str < 3) return 1; + if (*str == 0xe0 && (str[1] < 0xa0 || str[1] > 0xbf)) return 3; + if (*str == 0xed && str[1] > 0x9f) return 3; // str[1] < 0x80 is checked below + c = (unsigned int)((*str++ & 0x0f) << 12); + if ((*str & 0xc0) != 0x80) return 3; + c += (unsigned int)((*str++ & 0x3f) << 6); + if ((*str & 0xc0) != 0x80) return 3; + c += (*str++ & 0x3f); + *out_char = c; + return 3; + } + if ((*str & 0xf8) == 0xf0) + { + *out_char = IM_UNICODE_CODEPOINT_INVALID; // will be invalid but not end of string + if (in_text_end && in_text_end - (const char*)str < 4) return 1; + if (*str > 0xf4) return 4; + if (*str == 0xf0 && (str[1] < 0x90 || str[1] > 0xbf)) return 4; + if (*str == 0xf4 && str[1] > 0x8f) return 4; // str[1] < 0x80 is checked below + c = (unsigned int)((*str++ & 0x07) << 18); + if ((*str & 0xc0) != 0x80) return 4; + c += (unsigned int)((*str++ & 0x3f) << 12); + if ((*str & 0xc0) != 0x80) return 4; + c += (unsigned int)((*str++ & 0x3f) << 6); + if ((*str & 0xc0) != 0x80) return 4; + c += (*str++ & 0x3f); + // utf-8 encodings of values used in surrogate pairs are invalid + if ((c & 0xFFFFF800) == 0xD800) return 4; + // If codepoint does not fit in ImWchar, use replacement character U+FFFD instead + if (c > IM_UNICODE_CODEPOINT_MAX) c = IM_UNICODE_CODEPOINT_INVALID; + *out_char = c; + return 4; + } + *out_char = 0; + return 0; +} + +int ImTextStrFromUtf8(ImWchar* buf, int buf_size, const char* in_text, const char* in_text_end, const char** in_text_remaining) +{ + ImWchar* buf_out = buf; + ImWchar* buf_end = buf + buf_size; + while (buf_out < buf_end-1 && (!in_text_end || in_text < in_text_end) && *in_text) + { + unsigned int c; + in_text += ImTextCharFromUtf8(&c, in_text, in_text_end); + if (c == 0) + break; + *buf_out++ = (ImWchar)c; + } + *buf_out = 0; + if (in_text_remaining) + *in_text_remaining = in_text; + return (int)(buf_out - buf); +} + +int ImTextCountCharsFromUtf8(const char* in_text, const char* in_text_end) +{ + int char_count = 0; + while ((!in_text_end || in_text < in_text_end) && *in_text) + { + unsigned int c; + in_text += ImTextCharFromUtf8(&c, in_text, in_text_end); + if (c == 0) + break; + char_count++; + } + return char_count; +} + +// Based on stb_to_utf8() from github.com/nothings/stb/ +static inline int ImTextCharToUtf8(char* buf, int buf_size, unsigned int c) +{ + if (c < 0x80) + { + buf[0] = (char)c; + return 1; + } + if (c < 0x800) + { + if (buf_size < 2) return 0; + buf[0] = (char)(0xc0 + (c >> 6)); + buf[1] = (char)(0x80 + (c & 0x3f)); + return 2; + } + if (c < 0x10000) + { + if (buf_size < 3) return 0; + buf[0] = (char)(0xe0 + (c >> 12)); + buf[1] = (char)(0x80 + ((c>> 6) & 0x3f)); + buf[2] = (char)(0x80 + ((c ) & 0x3f)); + return 3; + } + if (c <= 0x10FFFF) + { + if (buf_size < 4) return 0; + buf[0] = (char)(0xf0 + (c >> 18)); + buf[1] = (char)(0x80 + ((c >> 12) & 0x3f)); + buf[2] = (char)(0x80 + ((c >> 6) & 0x3f)); + buf[3] = (char)(0x80 + ((c ) & 0x3f)); + return 4; + } + // Invalid code point, the max unicode is 0x10FFFF + return 0; +} + +// Not optimal but we very rarely use this function. +int ImTextCountUtf8BytesFromChar(const char* in_text, const char* in_text_end) +{ + unsigned int dummy = 0; + return ImTextCharFromUtf8(&dummy, in_text, in_text_end); +} + +static inline int ImTextCountUtf8BytesFromChar(unsigned int c) +{ + if (c < 0x80) return 1; + if (c < 0x800) return 2; + if (c < 0x10000) return 3; + if (c <= 0x10FFFF) return 4; + return 3; +} + +int ImTextStrToUtf8(char* buf, int buf_size, const ImWchar* in_text, const ImWchar* in_text_end) +{ + char* buf_out = buf; + const char* buf_end = buf + buf_size; + while (buf_out < buf_end-1 && (!in_text_end || in_text < in_text_end) && *in_text) + { + unsigned int c = (unsigned int)(*in_text++); + if (c < 0x80) + *buf_out++ = (char)c; + else + buf_out += ImTextCharToUtf8(buf_out, (int)(buf_end-buf_out-1), c); + } + *buf_out = 0; + return (int)(buf_out - buf); +} + +int ImTextCountUtf8BytesFromStr(const ImWchar* in_text, const ImWchar* in_text_end) +{ + int bytes_count = 0; + while ((!in_text_end || in_text < in_text_end) && *in_text) + { + unsigned int c = (unsigned int)(*in_text++); + if (c < 0x80) + bytes_count++; + else + bytes_count += ImTextCountUtf8BytesFromChar(c); + } + return bytes_count; +} + +//----------------------------------------------------------------------------- +// [SECTION] MISC HELPERS/UTILITIES (Color functions) +// Note: The Convert functions are early design which are not consistent with other API. +//----------------------------------------------------------------------------- + +IMGUI_API ImU32 ImAlphaBlendColors(ImU32 col_a, ImU32 col_b) +{ + float t = ((col_b >> IM_COL32_A_SHIFT) & 0xFF) / 255.f; + int r = ImLerp((int)(col_a >> IM_COL32_R_SHIFT) & 0xFF, (int)(col_b >> IM_COL32_R_SHIFT) & 0xFF, t); + int g = ImLerp((int)(col_a >> IM_COL32_G_SHIFT) & 0xFF, (int)(col_b >> IM_COL32_G_SHIFT) & 0xFF, t); + int b = ImLerp((int)(col_a >> IM_COL32_B_SHIFT) & 0xFF, (int)(col_b >> IM_COL32_B_SHIFT) & 0xFF, t); + return IM_COL32(r, g, b, 0xFF); +} + +ImVec4 ImGui::ColorConvertU32ToFloat4(ImU32 in) +{ + float s = 1.0f/255.0f; + return ImVec4( + ((in >> IM_COL32_R_SHIFT) & 0xFF) * s, + ((in >> IM_COL32_G_SHIFT) & 0xFF) * s, + ((in >> IM_COL32_B_SHIFT) & 0xFF) * s, + ((in >> IM_COL32_A_SHIFT) & 0xFF) * s); +} + +ImU32 ImGui::ColorConvertFloat4ToU32(const ImVec4& in) +{ + ImU32 out; + out = ((ImU32)IM_F32_TO_INT8_SAT(in.x)) << IM_COL32_R_SHIFT; + out |= ((ImU32)IM_F32_TO_INT8_SAT(in.y)) << IM_COL32_G_SHIFT; + out |= ((ImU32)IM_F32_TO_INT8_SAT(in.z)) << IM_COL32_B_SHIFT; + out |= ((ImU32)IM_F32_TO_INT8_SAT(in.w)) << IM_COL32_A_SHIFT; + return out; +} + +// Convert rgb floats ([0-1],[0-1],[0-1]) to hsv floats ([0-1],[0-1],[0-1]), from Foley & van Dam p592 +// Optimized http://lolengine.net/blog/2013/01/13/fast-rgb-to-hsv +void ImGui::ColorConvertRGBtoHSV(float r, float g, float b, float& out_h, float& out_s, float& out_v) +{ + float K = 0.f; + if (g < b) + { + ImSwap(g, b); + K = -1.f; + } + if (r < g) + { + ImSwap(r, g); + K = -2.f / 6.f - K; + } + + const float chroma = r - (g < b ? g : b); + out_h = ImFabs(K + (g - b) / (6.f * chroma + 1e-20f)); + out_s = chroma / (r + 1e-20f); + out_v = r; +} + +// Convert hsv floats ([0-1],[0-1],[0-1]) to rgb floats ([0-1],[0-1],[0-1]), from Foley & van Dam p593 +// also http://en.wikipedia.org/wiki/HSL_and_HSV +void ImGui::ColorConvertHSVtoRGB(float h, float s, float v, float& out_r, float& out_g, float& out_b) +{ + if (s == 0.0f) + { + // gray + out_r = out_g = out_b = v; + return; + } + + h = ImFmod(h, 1.0f) / (60.0f/360.0f); + int i = (int)h; + float f = h - (float)i; + float p = v * (1.0f - s); + float q = v * (1.0f - s * f); + float t = v * (1.0f - s * (1.0f - f)); + + switch (i) + { + case 0: out_r = v; out_g = t; out_b = p; break; + case 1: out_r = q; out_g = v; out_b = p; break; + case 2: out_r = p; out_g = v; out_b = t; break; + case 3: out_r = p; out_g = q; out_b = v; break; + case 4: out_r = t; out_g = p; out_b = v; break; + case 5: default: out_r = v; out_g = p; out_b = q; break; + } +} + +//----------------------------------------------------------------------------- +// [SECTION] ImGuiStorage +// Helper: Key->value storage +//----------------------------------------------------------------------------- + +// std::lower_bound but without the bullshit +static ImGuiStorage::ImGuiStoragePair* LowerBound(ImVector& data, ImGuiID key) +{ + ImGuiStorage::ImGuiStoragePair* first = data.Data; + ImGuiStorage::ImGuiStoragePair* last = data.Data + data.Size; + size_t count = (size_t)(last - first); + while (count > 0) + { + size_t count2 = count >> 1; + ImGuiStorage::ImGuiStoragePair* mid = first + count2; + if (mid->key < key) + { + first = ++mid; + count -= count2 + 1; + } + else + { + count = count2; + } + } + return first; +} + +// For quicker full rebuild of a storage (instead of an incremental one), you may add all your contents and then sort once. +void ImGuiStorage::BuildSortByKey() +{ + struct StaticFunc + { + static int IMGUI_CDECL PairCompareByID(const void* lhs, const void* rhs) + { + // We can't just do a subtraction because qsort uses signed integers and subtracting our ID doesn't play well with that. + if (((const ImGuiStoragePair*)lhs)->key > ((const ImGuiStoragePair*)rhs)->key) return +1; + if (((const ImGuiStoragePair*)lhs)->key < ((const ImGuiStoragePair*)rhs)->key) return -1; + return 0; + } + }; + if (Data.Size > 1) + ImQsort(Data.Data, (size_t)Data.Size, sizeof(ImGuiStoragePair), StaticFunc::PairCompareByID); +} + +int ImGuiStorage::GetInt(ImGuiID key, int default_val) const +{ + ImGuiStoragePair* it = LowerBound(const_cast&>(Data), key); + if (it == Data.end() || it->key != key) + return default_val; + return it->val_i; +} + +bool ImGuiStorage::GetBool(ImGuiID key, bool default_val) const +{ + return GetInt(key, default_val ? 1 : 0) != 0; +} + +float ImGuiStorage::GetFloat(ImGuiID key, float default_val) const +{ + ImGuiStoragePair* it = LowerBound(const_cast&>(Data), key); + if (it == Data.end() || it->key != key) + return default_val; + return it->val_f; +} + +void* ImGuiStorage::GetVoidPtr(ImGuiID key) const +{ + ImGuiStoragePair* it = LowerBound(const_cast&>(Data), key); + if (it == Data.end() || it->key != key) + return NULL; + return it->val_p; +} + +// References are only valid until a new value is added to the storage. Calling a Set***() function or a Get***Ref() function invalidates the pointer. +int* ImGuiStorage::GetIntRef(ImGuiID key, int default_val) +{ + ImGuiStoragePair* it = LowerBound(Data, key); + if (it == Data.end() || it->key != key) + it = Data.insert(it, ImGuiStoragePair(key, default_val)); + return &it->val_i; +} + +bool* ImGuiStorage::GetBoolRef(ImGuiID key, bool default_val) +{ + return (bool*)GetIntRef(key, default_val ? 1 : 0); +} + +float* ImGuiStorage::GetFloatRef(ImGuiID key, float default_val) +{ + ImGuiStoragePair* it = LowerBound(Data, key); + if (it == Data.end() || it->key != key) + it = Data.insert(it, ImGuiStoragePair(key, default_val)); + return &it->val_f; +} + +void** ImGuiStorage::GetVoidPtrRef(ImGuiID key, void* default_val) +{ + ImGuiStoragePair* it = LowerBound(Data, key); + if (it == Data.end() || it->key != key) + it = Data.insert(it, ImGuiStoragePair(key, default_val)); + return &it->val_p; +} + +// FIXME-OPT: Need a way to reuse the result of lower_bound when doing GetInt()/SetInt() - not too bad because it only happens on explicit interaction (maximum one a frame) +void ImGuiStorage::SetInt(ImGuiID key, int val) +{ + ImGuiStoragePair* it = LowerBound(Data, key); + if (it == Data.end() || it->key != key) + { + Data.insert(it, ImGuiStoragePair(key, val)); + return; + } + it->val_i = val; +} + +void ImGuiStorage::SetBool(ImGuiID key, bool val) +{ + SetInt(key, val ? 1 : 0); +} + +void ImGuiStorage::SetFloat(ImGuiID key, float val) +{ + ImGuiStoragePair* it = LowerBound(Data, key); + if (it == Data.end() || it->key != key) + { + Data.insert(it, ImGuiStoragePair(key, val)); + return; + } + it->val_f = val; +} + +void ImGuiStorage::SetVoidPtr(ImGuiID key, void* val) +{ + ImGuiStoragePair* it = LowerBound(Data, key); + if (it == Data.end() || it->key != key) + { + Data.insert(it, ImGuiStoragePair(key, val)); + return; + } + it->val_p = val; +} + +void ImGuiStorage::SetAllInt(int v) +{ + for (int i = 0; i < Data.Size; i++) + Data[i].val_i = v; +} + +//----------------------------------------------------------------------------- +// [SECTION] ImGuiTextFilter +//----------------------------------------------------------------------------- + +// Helper: Parse and apply text filters. In format "aaaaa[,bbbb][,ccccc]" +ImGuiTextFilter::ImGuiTextFilter(const char* default_filter) +{ + if (default_filter) + { + ImStrncpy(InputBuf, default_filter, IM_ARRAYSIZE(InputBuf)); + Build(); + } + else + { + InputBuf[0] = 0; + CountGrep = 0; + } +} + +bool ImGuiTextFilter::Draw(const char* label, float width) +{ + if (width != 0.0f) + ImGui::SetNextItemWidth(width); + bool value_changed = ImGui::InputText(label, InputBuf, IM_ARRAYSIZE(InputBuf)); + if (value_changed) + Build(); + return value_changed; +} + +void ImGuiTextFilter::ImGuiTextRange::split(char separator, ImVector* out) const +{ + out->resize(0); + const char* wb = b; + const char* we = wb; + while (we < e) + { + if (*we == separator) + { + out->push_back(ImGuiTextRange(wb, we)); + wb = we + 1; + } + we++; + } + if (wb != we) + out->push_back(ImGuiTextRange(wb, we)); +} + +void ImGuiTextFilter::Build() +{ + Filters.resize(0); + ImGuiTextRange input_range(InputBuf, InputBuf+strlen(InputBuf)); + input_range.split(',', &Filters); + + CountGrep = 0; + for (int i = 0; i != Filters.Size; i++) + { + ImGuiTextRange& f = Filters[i]; + while (f.b < f.e && ImCharIsBlankA(f.b[0])) + f.b++; + while (f.e > f.b && ImCharIsBlankA(f.e[-1])) + f.e--; + if (f.empty()) + continue; + if (Filters[i].b[0] != '-') + CountGrep += 1; + } +} + +bool ImGuiTextFilter::PassFilter(const char* text, const char* text_end) const +{ + if (Filters.empty()) + return true; + + if (text == NULL) + text = ""; + + for (int i = 0; i != Filters.Size; i++) + { + const ImGuiTextRange& f = Filters[i]; + if (f.empty()) + continue; + if (f.b[0] == '-') + { + // Subtract + if (ImStristr(text, text_end, f.b + 1, f.e) != NULL) + return false; + } + else + { + // Grep + if (ImStristr(text, text_end, f.b, f.e) != NULL) + return true; + } + } + + // Implicit * grep + if (CountGrep == 0) + return true; + + return false; +} + +//----------------------------------------------------------------------------- +// [SECTION] ImGuiTextBuffer +//----------------------------------------------------------------------------- + +// On some platform vsnprintf() takes va_list by reference and modifies it. +// va_copy is the 'correct' way to copy a va_list but Visual Studio prior to 2013 doesn't have it. +#ifndef va_copy +#if defined(__GNUC__) || defined(__clang__) +#define va_copy(dest, src) __builtin_va_copy(dest, src) +#else +#define va_copy(dest, src) (dest = src) +#endif +#endif + +char ImGuiTextBuffer::EmptyString[1] = { 0 }; + +void ImGuiTextBuffer::append(const char* str, const char* str_end) +{ + int len = str_end ? (int)(str_end - str) : (int)strlen(str); + + // Add zero-terminator the first time + const int write_off = (Buf.Size != 0) ? Buf.Size : 1; + const int needed_sz = write_off + len; + if (write_off + len >= Buf.Capacity) + { + int new_capacity = Buf.Capacity * 2; + Buf.reserve(needed_sz > new_capacity ? needed_sz : new_capacity); + } + + Buf.resize(needed_sz); + memcpy(&Buf[write_off - 1], str, (size_t)len); + Buf[write_off - 1 + len] = 0; +} + +void ImGuiTextBuffer::appendf(const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + appendfv(fmt, args); + va_end(args); +} + +// Helper: Text buffer for logging/accumulating text +void ImGuiTextBuffer::appendfv(const char* fmt, va_list args) +{ + va_list args_copy; + va_copy(args_copy, args); + + int len = ImFormatStringV(NULL, 0, fmt, args); // FIXME-OPT: could do a first pass write attempt, likely successful on first pass. + if (len <= 0) + { + va_end(args_copy); + return; + } + + // Add zero-terminator the first time + const int write_off = (Buf.Size != 0) ? Buf.Size : 1; + const int needed_sz = write_off + len; + if (write_off + len >= Buf.Capacity) + { + int new_capacity = Buf.Capacity * 2; + Buf.reserve(needed_sz > new_capacity ? needed_sz : new_capacity); + } + + Buf.resize(needed_sz); + ImFormatStringV(&Buf[write_off - 1], (size_t)len + 1, fmt, args_copy); + va_end(args_copy); +} + +//----------------------------------------------------------------------------- +// [SECTION] ImGuiListClipper +// This is currently not as flexible/powerful as it should be and really confusing/spaghetti, mostly because we changed +// the API mid-way through development and support two ways to using the clipper, needs some rework (see TODO) +//----------------------------------------------------------------------------- + +// Helper to calculate coarse clipping of large list of evenly sized items. +// NB: Prefer using the ImGuiListClipper higher-level helper if you can! Read comments and instructions there on how those use this sort of pattern. +// NB: 'items_count' is only used to clamp the result, if you don't know your count you can use INT_MAX +void ImGui::CalcListClipping(int items_count, float items_height, int* out_items_display_start, int* out_items_display_end) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if (g.LogEnabled) + { + // If logging is active, do not perform any clipping + *out_items_display_start = 0; + *out_items_display_end = items_count; + return; + } + if (window->SkipItems) + { + *out_items_display_start = *out_items_display_end = 0; + return; + } + + // We create the union of the ClipRect and the NavScoringRect which at worst should be 1 page away from ClipRect + ImRect unclipped_rect = window->ClipRect; + if (g.NavMoveRequest) + unclipped_rect.Add(g.NavScoringRect); + if (g.NavJustMovedToId && window->NavLastIds[0] == g.NavJustMovedToId) + unclipped_rect.Add(ImRect(window->Pos + window->NavRectRel[0].Min, window->Pos + window->NavRectRel[0].Max)); + + const ImVec2 pos = window->DC.CursorPos; + int start = (int)((unclipped_rect.Min.y - pos.y) / items_height); + int end = (int)((unclipped_rect.Max.y - pos.y) / items_height); + + // When performing a navigation request, ensure we have one item extra in the direction we are moving to + if (g.NavMoveRequest && g.NavMoveClipDir == ImGuiDir_Up) + start--; + if (g.NavMoveRequest && g.NavMoveClipDir == ImGuiDir_Down) + end++; + + start = ImClamp(start, 0, items_count); + end = ImClamp(end + 1, start, items_count); + *out_items_display_start = start; + *out_items_display_end = end; +} + +static void SetCursorPosYAndSetupDummyPrevLine(float pos_y, float line_height) +{ + // Set cursor position and a few other things so that SetScrollHereY() and Columns() can work when seeking cursor. + // FIXME: It is problematic that we have to do that here, because custom/equivalent end-user code would stumble on the same issue. + // The clipper should probably have a 4th step to display the last item in a regular manner. + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + window->DC.CursorPos.y = pos_y; + window->DC.CursorMaxPos.y = ImMax(window->DC.CursorMaxPos.y, pos_y); + window->DC.CursorPosPrevLine.y = window->DC.CursorPos.y - line_height; // Setting those fields so that SetScrollHereY() can properly function after the end of our clipper usage. + window->DC.PrevLineSize.y = (line_height - g.Style.ItemSpacing.y); // If we end up needing more accurate data (to e.g. use SameLine) we may as well make the clipper have a fourth step to let user process and display the last item in their list. + if (ImGuiColumns* columns = window->DC.CurrentColumns) + columns->LineMinY = window->DC.CursorPos.y; // Setting this so that cell Y position are set properly +} + +// Use case A: Begin() called from constructor with items_height<0, then called again from Sync() in StepNo 1 +// Use case B: Begin() called from constructor with items_height>0 +// FIXME-LEGACY: Ideally we should remove the Begin/End functions but they are part of the legacy API we still support. This is why some of the code in Step() calling Begin() and reassign some fields, spaghetti style. +void ImGuiListClipper::Begin(int count, float items_height) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + + StartPosY = window->DC.CursorPos.y; + ItemsHeight = items_height; + ItemsCount = count; + StepNo = 0; + DisplayEnd = DisplayStart = -1; + if (ItemsHeight > 0.0f) + { + ImGui::CalcListClipping(ItemsCount, ItemsHeight, &DisplayStart, &DisplayEnd); // calculate how many to clip/display + if (DisplayStart > 0) + SetCursorPosYAndSetupDummyPrevLine(StartPosY + DisplayStart * ItemsHeight, ItemsHeight); // advance cursor + StepNo = 2; + } +} + +void ImGuiListClipper::End() +{ + if (ItemsCount < 0) + return; + // In theory here we should assert that ImGui::GetCursorPosY() == StartPosY + DisplayEnd * ItemsHeight, but it feels saner to just seek at the end and not assert/crash the user. + if (ItemsCount < INT_MAX) + SetCursorPosYAndSetupDummyPrevLine(StartPosY + ItemsCount * ItemsHeight, ItemsHeight); // advance cursor + ItemsCount = -1; + StepNo = 3; +} + +bool ImGuiListClipper::Step() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + + if (ItemsCount == 0 || window->SkipItems) + { + ItemsCount = -1; + return false; + } + if (StepNo == 0) // Step 0: the clipper let you process the first element, regardless of it being visible or not, so we can measure the element height. + { + DisplayStart = 0; + DisplayEnd = 1; + StartPosY = window->DC.CursorPos.y; + StepNo = 1; + return true; + } + if (StepNo == 1) // Step 1: the clipper infer height from first element, calculate the actual range of elements to display, and position the cursor before the first element. + { + if (ItemsCount == 1) { ItemsCount = -1; return false; } + float items_height = window->DC.CursorPos.y - StartPosY; + IM_ASSERT(items_height > 0.0f); // If this triggers, it means Item 0 hasn't moved the cursor vertically + Begin(ItemsCount - 1, items_height); + DisplayStart++; + DisplayEnd++; + StepNo = 3; + return true; + } + if (StepNo == 2) // Step 2: dummy step only required if an explicit items_height was passed to constructor or Begin() and user still call Step(). Does nothing and switch to Step 3. + { + IM_ASSERT(DisplayStart >= 0 && DisplayEnd >= 0); + StepNo = 3; + return true; + } + if (StepNo == 3) // Step 3: the clipper validate that we have reached the expected Y position (corresponding to element DisplayEnd), advance the cursor to the end of the list and then returns 'false' to end the loop. + End(); + return false; +} + +//----------------------------------------------------------------------------- +// [SECTION] STYLING +//----------------------------------------------------------------------------- + +ImGuiStyle& ImGui::GetStyle() +{ + IM_ASSERT(GImGui != NULL && "No current context. Did you call ImGui::CreateContext() and ImGui::SetCurrentContext() ?"); + return GImGui->Style; +} + +ImU32 ImGui::GetColorU32(ImGuiCol idx, float alpha_mul) +{ + ImGuiStyle& style = GImGui->Style; + ImVec4 c = style.Colors[idx]; + c.w *= style.Alpha * alpha_mul; + return ColorConvertFloat4ToU32(c); +} + +ImU32 ImGui::GetColorU32(const ImVec4& col) +{ + ImGuiStyle& style = GImGui->Style; + ImVec4 c = col; + c.w *= style.Alpha; + return ColorConvertFloat4ToU32(c); +} + +const ImVec4& ImGui::GetStyleColorVec4(ImGuiCol idx) +{ + ImGuiStyle& style = GImGui->Style; + return style.Colors[idx]; +} + +ImU32 ImGui::GetColorU32(ImU32 col) +{ + ImGuiStyle& style = GImGui->Style; + if (style.Alpha >= 1.0f) + return col; + ImU32 a = (col & IM_COL32_A_MASK) >> IM_COL32_A_SHIFT; + a = (ImU32)(a * style.Alpha); // We don't need to clamp 0..255 because Style.Alpha is in 0..1 range. + return (col & ~IM_COL32_A_MASK) | (a << IM_COL32_A_SHIFT); +} + +// FIXME: This may incur a round-trip (if the end user got their data from a float4) but eventually we aim to store the in-flight colors as ImU32 +void ImGui::PushStyleColor(ImGuiCol idx, ImU32 col) +{ + ImGuiContext& g = *GImGui; + ImGuiColorMod backup; + backup.Col = idx; + backup.BackupValue = g.Style.Colors[idx]; + g.ColorModifiers.push_back(backup); + g.Style.Colors[idx] = ColorConvertU32ToFloat4(col); +} + +void ImGui::PushStyleColor(ImGuiCol idx, const ImVec4& col) +{ + ImGuiContext& g = *GImGui; + ImGuiColorMod backup; + backup.Col = idx; + backup.BackupValue = g.Style.Colors[idx]; + g.ColorModifiers.push_back(backup); + g.Style.Colors[idx] = col; +} + +void ImGui::PopStyleColor(int count) +{ + ImGuiContext& g = *GImGui; + while (count > 0) + { + ImGuiColorMod& backup = g.ColorModifiers.back(); + g.Style.Colors[backup.Col] = backup.BackupValue; + g.ColorModifiers.pop_back(); + count--; + } +} + +struct ImGuiStyleVarInfo +{ + ImGuiDataType Type; + ImU32 Count; + ImU32 Offset; + void* GetVarPtr(ImGuiStyle* style) const { return (void*)((unsigned char*)style + Offset); } +}; + +static const ImGuiStyleVarInfo GStyleVarInfo[] = +{ + { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, Alpha) }, // ImGuiStyleVar_Alpha + { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowPadding) }, // ImGuiStyleVar_WindowPadding + { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowRounding) }, // ImGuiStyleVar_WindowRounding + { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowBorderSize) }, // ImGuiStyleVar_WindowBorderSize + { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowMinSize) }, // ImGuiStyleVar_WindowMinSize + { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowTitleAlign) }, // ImGuiStyleVar_WindowTitleAlign + { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, ChildRounding) }, // ImGuiStyleVar_ChildRounding + { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, ChildBorderSize) }, // ImGuiStyleVar_ChildBorderSize + { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, PopupRounding) }, // ImGuiStyleVar_PopupRounding + { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, PopupBorderSize) }, // ImGuiStyleVar_PopupBorderSize + { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, FramePadding) }, // ImGuiStyleVar_FramePadding + { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, FrameRounding) }, // ImGuiStyleVar_FrameRounding + { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, FrameBorderSize) }, // ImGuiStyleVar_FrameBorderSize + { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, ItemSpacing) }, // ImGuiStyleVar_ItemSpacing + { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, ItemInnerSpacing) }, // ImGuiStyleVar_ItemInnerSpacing + { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, IndentSpacing) }, // ImGuiStyleVar_IndentSpacing + { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, ScrollbarSize) }, // ImGuiStyleVar_ScrollbarSize + { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, ScrollbarRounding) }, // ImGuiStyleVar_ScrollbarRounding + { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, GrabMinSize) }, // ImGuiStyleVar_GrabMinSize + { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, GrabRounding) }, // ImGuiStyleVar_GrabRounding + { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, TabRounding) }, // ImGuiStyleVar_TabRounding + { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, ButtonTextAlign) }, // ImGuiStyleVar_ButtonTextAlign + { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, SelectableTextAlign) }, // ImGuiStyleVar_SelectableTextAlign +}; + +static const ImGuiStyleVarInfo* GetStyleVarInfo(ImGuiStyleVar idx) +{ + IM_ASSERT(idx >= 0 && idx < ImGuiStyleVar_COUNT); + IM_ASSERT(IM_ARRAYSIZE(GStyleVarInfo) == ImGuiStyleVar_COUNT); + return &GStyleVarInfo[idx]; +} + +void ImGui::PushStyleVar(ImGuiStyleVar idx, float val) +{ + const ImGuiStyleVarInfo* var_info = GetStyleVarInfo(idx); + if (var_info->Type == ImGuiDataType_Float && var_info->Count == 1) + { + ImGuiContext& g = *GImGui; + float* pvar = (float*)var_info->GetVarPtr(&g.Style); + g.StyleModifiers.push_back(ImGuiStyleMod(idx, *pvar)); + *pvar = val; + return; + } + IM_ASSERT(0 && "Called PushStyleVar() float variant but variable is not a float!"); +} + +void ImGui::PushStyleVar(ImGuiStyleVar idx, const ImVec2& val) +{ + const ImGuiStyleVarInfo* var_info = GetStyleVarInfo(idx); + if (var_info->Type == ImGuiDataType_Float && var_info->Count == 2) + { + ImGuiContext& g = *GImGui; + ImVec2* pvar = (ImVec2*)var_info->GetVarPtr(&g.Style); + g.StyleModifiers.push_back(ImGuiStyleMod(idx, *pvar)); + *pvar = val; + return; + } + IM_ASSERT(0 && "Called PushStyleVar() ImVec2 variant but variable is not a ImVec2!"); +} + +void ImGui::PopStyleVar(int count) +{ + ImGuiContext& g = *GImGui; + while (count > 0) + { + // We avoid a generic memcpy(data, &backup.Backup.., GDataTypeSize[info->Type] * info->Count), the overhead in Debug is not worth it. + ImGuiStyleMod& backup = g.StyleModifiers.back(); + const ImGuiStyleVarInfo* info = GetStyleVarInfo(backup.VarIdx); + void* data = info->GetVarPtr(&g.Style); + if (info->Type == ImGuiDataType_Float && info->Count == 1) { ((float*)data)[0] = backup.BackupFloat[0]; } + else if (info->Type == ImGuiDataType_Float && info->Count == 2) { ((float*)data)[0] = backup.BackupFloat[0]; ((float*)data)[1] = backup.BackupFloat[1]; } + g.StyleModifiers.pop_back(); + count--; + } +} + +const char* ImGui::GetStyleColorName(ImGuiCol idx) +{ + // Create switch-case from enum with regexp: ImGuiCol_{.*}, --> case ImGuiCol_\1: return "\1"; + switch (idx) + { + case ImGuiCol_Text: return "Text"; + case ImGuiCol_TextDisabled: return "TextDisabled"; + case ImGuiCol_WindowBg: return "WindowBg"; + case ImGuiCol_ChildBg: return "ChildBg"; + case ImGuiCol_PopupBg: return "PopupBg"; + case ImGuiCol_Border: return "Border"; + case ImGuiCol_BorderShadow: return "BorderShadow"; + case ImGuiCol_FrameBg: return "FrameBg"; + case ImGuiCol_FrameBgHovered: return "FrameBgHovered"; + case ImGuiCol_FrameBgActive: return "FrameBgActive"; + case ImGuiCol_TitleBg: return "TitleBg"; + case ImGuiCol_TitleBgActive: return "TitleBgActive"; + case ImGuiCol_TitleBgCollapsed: return "TitleBgCollapsed"; + case ImGuiCol_MenuBarBg: return "MenuBarBg"; + case ImGuiCol_ScrollbarBg: return "ScrollbarBg"; + case ImGuiCol_ScrollbarGrab: return "ScrollbarGrab"; + case ImGuiCol_ScrollbarGrabHovered: return "ScrollbarGrabHovered"; + case ImGuiCol_ScrollbarGrabActive: return "ScrollbarGrabActive"; + case ImGuiCol_CheckMark: return "CheckMark"; + case ImGuiCol_SliderGrab: return "SliderGrab"; + case ImGuiCol_SliderGrabActive: return "SliderGrabActive"; + case ImGuiCol_Button: return "Button"; + case ImGuiCol_ButtonHovered: return "ButtonHovered"; + case ImGuiCol_ButtonActive: return "ButtonActive"; + case ImGuiCol_Header: return "Header"; + case ImGuiCol_HeaderHovered: return "HeaderHovered"; + case ImGuiCol_HeaderActive: return "HeaderActive"; + case ImGuiCol_Separator: return "Separator"; + case ImGuiCol_SeparatorHovered: return "SeparatorHovered"; + case ImGuiCol_SeparatorActive: return "SeparatorActive"; + case ImGuiCol_ResizeGrip: return "ResizeGrip"; + case ImGuiCol_ResizeGripHovered: return "ResizeGripHovered"; + case ImGuiCol_ResizeGripActive: return "ResizeGripActive"; + case ImGuiCol_Tab: return "Tab"; + case ImGuiCol_TabHovered: return "TabHovered"; + case ImGuiCol_TabActive: return "TabActive"; + case ImGuiCol_TabUnfocused: return "TabUnfocused"; + case ImGuiCol_TabUnfocusedActive: return "TabUnfocusedActive"; + case ImGuiCol_DockingPreview: return "DockingPreview"; + case ImGuiCol_DockingEmptyBg: return "DockingEmptyBg"; + case ImGuiCol_PlotLines: return "PlotLines"; + case ImGuiCol_PlotLinesHovered: return "PlotLinesHovered"; + case ImGuiCol_PlotHistogram: return "PlotHistogram"; + case ImGuiCol_PlotHistogramHovered: return "PlotHistogramHovered"; + case ImGuiCol_TextSelectedBg: return "TextSelectedBg"; + case ImGuiCol_DragDropTarget: return "DragDropTarget"; + case ImGuiCol_NavHighlight: return "NavHighlight"; + case ImGuiCol_NavWindowingHighlight: return "NavWindowingHighlight"; + case ImGuiCol_NavWindowingDimBg: return "NavWindowingDimBg"; + case ImGuiCol_ModalWindowDimBg: return "ModalWindowDimBg"; + } + IM_ASSERT(0); + return "Unknown"; +} + + +//----------------------------------------------------------------------------- +// [SECTION] RENDER HELPERS +// Some of those (internal) functions are currently quite a legacy mess - their signature and behavior will change, +// we need a nicer separation between low-level functions and high-level functions relying on the ImGui context. +// Also see imgui_draw.cpp for some more which have been reworked to not rely on ImGui:: context. +//----------------------------------------------------------------------------- + +const char* ImGui::FindRenderedTextEnd(const char* text, const char* text_end) +{ + const char* text_display_end = text; + if (!text_end) + text_end = (const char*)-1; + + while (text_display_end < text_end && *text_display_end != '\0' && (text_display_end[0] != '#' || text_display_end[1] != '#')) + text_display_end++; + return text_display_end; +} + +// Internal ImGui functions to render text +// RenderText***() functions calls ImDrawList::AddText() calls ImBitmapFont::RenderText() +void ImGui::RenderText(ImVec2 pos, const char* text, const char* text_end, bool hide_text_after_hash) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + + // Hide anything after a '##' string + const char* text_display_end; + if (hide_text_after_hash) + { + text_display_end = FindRenderedTextEnd(text, text_end); + } + else + { + if (!text_end) + text_end = text + strlen(text); // FIXME-OPT + text_display_end = text_end; + } + + if (text != text_display_end) + { + window->DrawList->AddText(g.Font, g.FontSize, pos, GetColorU32(ImGuiCol_Text), text, text_display_end); + if (g.LogEnabled) + LogRenderedText(&pos, text, text_display_end); + } +} + +void ImGui::RenderTextWrapped(ImVec2 pos, const char* text, const char* text_end, float wrap_width) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + + if (!text_end) + text_end = text + strlen(text); // FIXME-OPT + + if (text != text_end) + { + window->DrawList->AddText(g.Font, g.FontSize, pos, GetColorU32(ImGuiCol_Text), text, text_end, wrap_width); + if (g.LogEnabled) + LogRenderedText(&pos, text, text_end); + } +} + +// Default clip_rect uses (pos_min,pos_max) +// Handle clipping on CPU immediately (vs typically let the GPU clip the triangles that are overlapping the clipping rectangle edges) +void ImGui::RenderTextClippedEx(ImDrawList* draw_list, const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_display_end, const ImVec2* text_size_if_known, const ImVec2& align, const ImRect* clip_rect) +{ + // Perform CPU side clipping for single clipped element to avoid using scissor state + ImVec2 pos = pos_min; + const ImVec2 text_size = text_size_if_known ? *text_size_if_known : CalcTextSize(text, text_display_end, false, 0.0f); + + const ImVec2* clip_min = clip_rect ? &clip_rect->Min : &pos_min; + const ImVec2* clip_max = clip_rect ? &clip_rect->Max : &pos_max; + bool need_clipping = (pos.x + text_size.x >= clip_max->x) || (pos.y + text_size.y >= clip_max->y); + if (clip_rect) // If we had no explicit clipping rectangle then pos==clip_min + need_clipping |= (pos.x < clip_min->x) || (pos.y < clip_min->y); + + // Align whole block. We should defer that to the better rendering function when we'll have support for individual line alignment. + if (align.x > 0.0f) pos.x = ImMax(pos.x, pos.x + (pos_max.x - pos.x - text_size.x) * align.x); + if (align.y > 0.0f) pos.y = ImMax(pos.y, pos.y + (pos_max.y - pos.y - text_size.y) * align.y); + + // Render + if (need_clipping) + { + ImVec4 fine_clip_rect(clip_min->x, clip_min->y, clip_max->x, clip_max->y); + draw_list->AddText(NULL, 0.0f, pos, GetColorU32(ImGuiCol_Text), text, text_display_end, 0.0f, &fine_clip_rect); + } + else + { + draw_list->AddText(NULL, 0.0f, pos, GetColorU32(ImGuiCol_Text), text, text_display_end, 0.0f, NULL); + } +} + +void ImGui::RenderTextClipped(const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_end, const ImVec2* text_size_if_known, const ImVec2& align, const ImRect* clip_rect) +{ + // Hide anything after a '##' string + const char* text_display_end = FindRenderedTextEnd(text, text_end); + const int text_len = (int)(text_display_end - text); + if (text_len == 0) + return; + + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + RenderTextClippedEx(window->DrawList, pos_min, pos_max, text, text_display_end, text_size_if_known, align, clip_rect); + if (g.LogEnabled) + LogRenderedText(&pos_min, text, text_display_end); +} + + +// Another overly complex function until we reorganize everything into a nice all-in-one helper. +// This is made more complex because we have dissociated the layout rectangle (pos_min..pos_max) which define _where_ the ellipsis is, from actual clipping of text and limit of the ellipsis display. +// This is because in the context of tabs we selectively hide part of the text when the Close Button appears, but we don't want the ellipsis to move. +void ImGui::RenderTextEllipsis(ImDrawList* draw_list, const ImVec2& pos_min, const ImVec2& pos_max, float clip_max_x, float ellipsis_max_x, const char* text, const char* text_end_full, const ImVec2* text_size_if_known) +{ + ImGuiContext& g = *GImGui; + if (text_end_full == NULL) + text_end_full = FindRenderedTextEnd(text); + const ImVec2 text_size = text_size_if_known ? *text_size_if_known : CalcTextSize(text, text_end_full, false, 0.0f); + + //draw_list->AddLine(ImVec2(pos_max.x, pos_min.y - 4), ImVec2(pos_max.x, pos_max.y + 4), IM_COL32(0, 0, 255, 255)); + //draw_list->AddLine(ImVec2(ellipsis_max_x, pos_min.y-2), ImVec2(ellipsis_max_x, pos_max.y+2), IM_COL32(0, 255, 0, 255)); + //draw_list->AddLine(ImVec2(clip_max_x, pos_min.y), ImVec2(clip_max_x, pos_max.y), IM_COL32(255, 0, 0, 255)); + // FIXME: We could technically remove (last_glyph->AdvanceX - last_glyph->X1) from text_size.x here and save a few pixels. + if (text_size.x > pos_max.x - pos_min.x) + { + // Hello wo... + // | | | + // min max ellipsis_max + // <-> this is generally some padding value + + const ImFont* font = draw_list->_Data->Font; + const float font_size = draw_list->_Data->FontSize; + const char* text_end_ellipsis = NULL; + + ImWchar ellipsis_char = font->EllipsisChar; + int ellipsis_char_count = 1; + if (ellipsis_char == (ImWchar)-1) + { + ellipsis_char = (ImWchar)'.'; + ellipsis_char_count = 3; + } + const ImFontGlyph* glyph = font->FindGlyph(ellipsis_char); + + float ellipsis_glyph_width = glyph->X1; // Width of the glyph with no padding on either side + float ellipsis_total_width = ellipsis_glyph_width; // Full width of entire ellipsis + + if (ellipsis_char_count > 1) + { + // Full ellipsis size without free spacing after it. + const float spacing_between_dots = 1.0f * (draw_list->_Data->FontSize / font->FontSize); + ellipsis_glyph_width = glyph->X1 - glyph->X0 + spacing_between_dots; + ellipsis_total_width = ellipsis_glyph_width * (float)ellipsis_char_count - spacing_between_dots; + } + + // We can now claim the space between pos_max.x and ellipsis_max.x + const float text_avail_width = ImMax((ImMax(pos_max.x, ellipsis_max_x) - ellipsis_total_width) - pos_min.x, 1.0f); + float text_size_clipped_x = font->CalcTextSizeA(font_size, text_avail_width, 0.0f, text, text_end_full, &text_end_ellipsis).x; + if (text == text_end_ellipsis && text_end_ellipsis < text_end_full) + { + // Always display at least 1 character if there's no room for character + ellipsis + text_end_ellipsis = text + ImTextCountUtf8BytesFromChar(text, text_end_full); + text_size_clipped_x = font->CalcTextSizeA(font_size, FLT_MAX, 0.0f, text, text_end_ellipsis).x; + } + while (text_end_ellipsis > text && ImCharIsBlankA(text_end_ellipsis[-1])) + { + // Trim trailing space before ellipsis (FIXME: Supporting non-ascii blanks would be nice, for this we need a function to backtrack in UTF-8 text) + text_end_ellipsis--; + text_size_clipped_x -= font->CalcTextSizeA(font_size, FLT_MAX, 0.0f, text_end_ellipsis, text_end_ellipsis + 1).x; // Ascii blanks are always 1 byte + } + + // Render text, render ellipsis + RenderTextClippedEx(draw_list, pos_min, ImVec2(clip_max_x, pos_max.y), text, text_end_ellipsis, &text_size, ImVec2(0.0f, 0.0f)); + float ellipsis_x = pos_min.x + text_size_clipped_x; + if (ellipsis_x + ellipsis_total_width <= ellipsis_max_x) + for (int i = 0; i < ellipsis_char_count; i++) + { + font->RenderChar(draw_list, font_size, ImVec2(ellipsis_x, pos_min.y), GetColorU32(ImGuiCol_Text), ellipsis_char); + ellipsis_x += ellipsis_glyph_width; + } + } + else + { + RenderTextClippedEx(draw_list, pos_min, ImVec2(clip_max_x, pos_max.y), text, text_end_full, &text_size, ImVec2(0.0f, 0.0f)); + } + + if (g.LogEnabled) + LogRenderedText(&pos_min, text, text_end_full); +} + +// Render a rectangle shaped with optional rounding and borders +void ImGui::RenderFrame(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, bool border, float rounding) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + window->DrawList->AddRectFilled(p_min, p_max, fill_col, rounding); + const float border_size = g.Style.FrameBorderSize; + if (border && border_size > 0.0f) + { + window->DrawList->AddRect(p_min+ImVec2(1,1), p_max+ImVec2(1,1), GetColorU32(ImGuiCol_BorderShadow), rounding, ImDrawCornerFlags_All, border_size); + window->DrawList->AddRect(p_min, p_max, GetColorU32(ImGuiCol_Border), rounding, ImDrawCornerFlags_All, border_size); + } +} + +void ImGui::RenderFrameBorder(ImVec2 p_min, ImVec2 p_max, float rounding) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + const float border_size = g.Style.FrameBorderSize; + if (border_size > 0.0f) + { + window->DrawList->AddRect(p_min+ImVec2(1,1), p_max+ImVec2(1,1), GetColorU32(ImGuiCol_BorderShadow), rounding, ImDrawCornerFlags_All, border_size); + window->DrawList->AddRect(p_min, p_max, GetColorU32(ImGuiCol_Border), rounding, ImDrawCornerFlags_All, border_size); + } +} + +void ImGui::RenderNavHighlight(const ImRect& bb, ImGuiID id, ImGuiNavHighlightFlags flags) +{ + ImGuiContext& g = *GImGui; + if (id != g.NavId) + return; + if (g.NavDisableHighlight && !(flags & ImGuiNavHighlightFlags_AlwaysDraw)) + return; + ImGuiWindow* window = g.CurrentWindow; + if (window->DC.NavHideHighlightOneFrame) + return; + + float rounding = (flags & ImGuiNavHighlightFlags_NoRounding) ? 0.0f : g.Style.FrameRounding; + ImRect display_rect = bb; + display_rect.ClipWith(window->ClipRect); + if (flags & ImGuiNavHighlightFlags_TypeDefault) + { + const float THICKNESS = 2.0f; + const float DISTANCE = 3.0f + THICKNESS * 0.5f; + display_rect.Expand(ImVec2(DISTANCE,DISTANCE)); + bool fully_visible = window->ClipRect.Contains(display_rect); + if (!fully_visible) + window->DrawList->PushClipRect(display_rect.Min, display_rect.Max); + window->DrawList->AddRect(display_rect.Min + ImVec2(THICKNESS*0.5f,THICKNESS*0.5f), display_rect.Max - ImVec2(THICKNESS*0.5f,THICKNESS*0.5f), GetColorU32(ImGuiCol_NavHighlight), rounding, ImDrawCornerFlags_All, THICKNESS); + if (!fully_visible) + window->DrawList->PopClipRect(); + } + if (flags & ImGuiNavHighlightFlags_TypeThin) + { + window->DrawList->AddRect(display_rect.Min, display_rect.Max, GetColorU32(ImGuiCol_NavHighlight), rounding, ~0, 1.0f); + } +} + +//----------------------------------------------------------------------------- +// [SECTION] MAIN CODE (most of the code! lots of stuff, needs tidying up!) +//----------------------------------------------------------------------------- + +// ImGuiWindow is mostly a dumb struct. It merely has a constructor and a few helper methods +ImGuiWindow::ImGuiWindow(ImGuiContext* context, const char* name) + : DrawListInst(&context->DrawListSharedData) +{ + Name = ImStrdup(name); + ID = ImHashStr(name); + IDStack.push_back(ID); + Flags = FlagsPreviousFrame = ImGuiWindowFlags_None; + Viewport = NULL; + ViewportId = 0; + ViewportAllowPlatformMonitorExtend = -1; + ViewportPos = ImVec2(FLT_MAX, FLT_MAX); + Pos = ImVec2(0.0f, 0.0f); + Size = SizeFull = ImVec2(0.0f, 0.0f); + ContentSize = ContentSizeExplicit = ImVec2(0.0f, 0.0f); + WindowPadding = ImVec2(0.0f, 0.0f); + WindowRounding = 0.0f; + WindowBorderSize = 0.0f; + NameBufLen = (int)strlen(name) + 1; + MoveId = GetID("#MOVE"); + ChildId = 0; + Scroll = ImVec2(0.0f, 0.0f); + ScrollTarget = ImVec2(FLT_MAX, FLT_MAX); + ScrollTargetCenterRatio = ImVec2(0.5f, 0.5f); + ScrollbarSizes = ImVec2(0.0f, 0.0f); + ScrollbarX = ScrollbarY = false; + ViewportOwned = false; + Active = WasActive = false; + WriteAccessed = false; + Collapsed = false; + WantCollapseToggle = false; + SkipItems = false; + Appearing = false; + Hidden = false; + IsFallbackWindow = false; + HasCloseButton = false; + ResizeBorderHeld = -1; + BeginCount = 0; + BeginOrderWithinParent = -1; + BeginOrderWithinContext = -1; + PopupId = 0; + AutoFitFramesX = AutoFitFramesY = -1; + AutoFitChildAxises = 0x00; + AutoFitOnlyGrows = false; + AutoPosLastDirection = ImGuiDir_None; + HiddenFramesCanSkipItems = HiddenFramesCannotSkipItems = 0; + SetWindowPosAllowFlags = SetWindowSizeAllowFlags = SetWindowCollapsedAllowFlags = SetWindowDockAllowFlags = ImGuiCond_Always | ImGuiCond_Once | ImGuiCond_FirstUseEver | ImGuiCond_Appearing; + SetWindowPosVal = SetWindowPosPivot = ImVec2(FLT_MAX, FLT_MAX); + + InnerRect = ImRect(0.0f, 0.0f, 0.0f, 0.0f); // Clear so the InnerRect.GetSize() code in Begin() doesn't lead to overflow even if the result isn't used. + + LastFrameActive = -1; + LastFrameJustFocused = -1; + LastTimeActive = -1.0f; + ItemWidthDefault = 0.0f; + FontWindowScale = FontDpiScale = 1.0f; + SettingsOffset = -1; + + DrawList = &DrawListInst; + DrawList->_OwnerName = Name; + ParentWindow = NULL; + RootWindow = NULL; + RootWindowDockStop = NULL; + RootWindowForTitleBarHighlight = NULL; + RootWindowForNav = NULL; + + NavLastIds[0] = NavLastIds[1] = 0; + NavRectRel[0] = NavRectRel[1] = ImRect(); + NavLastChildNavWindow = NULL; + + MemoryCompacted = false; + MemoryDrawListIdxCapacity = MemoryDrawListVtxCapacity = 0; + + DockNode = DockNodeAsHost = NULL; + DockId = 0; + DockTabItemStatusFlags = ImGuiItemStatusFlags_None; + DockOrder = -1; + DockIsActive = DockTabIsVisible = DockTabWantClose = false; +} + +ImGuiWindow::~ImGuiWindow() +{ + IM_ASSERT(DrawList == &DrawListInst); + IM_DELETE(Name); + for (int i = 0; i != ColumnsStorage.Size; i++) + ColumnsStorage[i].~ImGuiColumns(); +} + +ImGuiID ImGuiWindow::GetID(const char* str, const char* str_end) +{ + ImGuiID seed = IDStack.back(); + ImGuiID id = ImHashStr(str, str_end ? (str_end - str) : 0, seed); + ImGui::KeepAliveID(id); +#ifdef IMGUI_ENABLE_TEST_ENGINE + ImGuiContext& g = *GImGui; + IMGUI_TEST_ENGINE_ID_INFO2(id, ImGuiDataType_String, str, str_end); +#endif + return id; +} + +ImGuiID ImGuiWindow::GetID(const void* ptr) +{ + ImGuiID seed = IDStack.back(); + ImGuiID id = ImHashData(&ptr, sizeof(void*), seed); + ImGui::KeepAliveID(id); +#ifdef IMGUI_ENABLE_TEST_ENGINE + ImGuiContext& g = *GImGui; + IMGUI_TEST_ENGINE_ID_INFO(id, ImGuiDataType_Pointer, ptr); +#endif + return id; +} + +ImGuiID ImGuiWindow::GetID(int n) +{ + ImGuiID seed = IDStack.back(); + ImGuiID id = ImHashData(&n, sizeof(n), seed); + ImGui::KeepAliveID(id); +#ifdef IMGUI_ENABLE_TEST_ENGINE + ImGuiContext& g = *GImGui; + IMGUI_TEST_ENGINE_ID_INFO(id, ImGuiDataType_S32, (intptr_t)n); +#endif + return id; +} + +ImGuiID ImGuiWindow::GetIDNoKeepAlive(const char* str, const char* str_end) +{ + ImGuiID seed = IDStack.back(); + ImGuiID id = ImHashStr(str, str_end ? (str_end - str) : 0, seed); +#ifdef IMGUI_ENABLE_TEST_ENGINE + ImGuiContext& g = *GImGui; + IMGUI_TEST_ENGINE_ID_INFO2(id, ImGuiDataType_String, str, str_end); +#endif + return id; +} + +ImGuiID ImGuiWindow::GetIDNoKeepAlive(const void* ptr) +{ + ImGuiID seed = IDStack.back(); + ImGuiID id = ImHashData(&ptr, sizeof(void*), seed); +#ifdef IMGUI_ENABLE_TEST_ENGINE + ImGuiContext& g = *GImGui; + IMGUI_TEST_ENGINE_ID_INFO(id, ImGuiDataType_Pointer, ptr); +#endif + return id; +} + +ImGuiID ImGuiWindow::GetIDNoKeepAlive(int n) +{ + ImGuiID seed = IDStack.back(); + ImGuiID id = ImHashData(&n, sizeof(n), seed); +#ifdef IMGUI_ENABLE_TEST_ENGINE + ImGuiContext& g = *GImGui; + IMGUI_TEST_ENGINE_ID_INFO(id, ImGuiDataType_S32, (intptr_t)n); +#endif + return id; +} + +// This is only used in rare/specific situations to manufacture an ID out of nowhere. +ImGuiID ImGuiWindow::GetIDFromRectangle(const ImRect& r_abs) +{ + ImGuiID seed = IDStack.back(); + const int r_rel[4] = { (int)(r_abs.Min.x - Pos.x), (int)(r_abs.Min.y - Pos.y), (int)(r_abs.Max.x - Pos.x), (int)(r_abs.Max.y - Pos.y) }; + ImGuiID id = ImHashData(&r_rel, sizeof(r_rel), seed); + ImGui::KeepAliveID(id); + return id; +} + +static void SetCurrentWindow(ImGuiWindow* window) +{ + ImGuiContext& g = *GImGui; + g.CurrentWindow = window; + if (window) + g.FontSize = g.DrawListSharedData.FontSize = window->CalcFontSize(); +} + +// Free up/compact internal window buffers, we can use this when a window becomes unused. +// This is currently unused by the library, but you may call this yourself for easy GC. +// Not freed: +// - ImGuiWindow, ImGuiWindowSettings, Name +// - StateStorage, ColumnsStorage (may hold useful data) +// This should have no noticeable visual effect. When the window reappear however, expect new allocation/buffer growth/copy cost. +void ImGui::GcCompactTransientWindowBuffers(ImGuiWindow* window) +{ + window->MemoryCompacted = true; + window->MemoryDrawListIdxCapacity = window->DrawList->IdxBuffer.Capacity; + window->MemoryDrawListVtxCapacity = window->DrawList->VtxBuffer.Capacity; + window->IDStack.clear(); + window->DrawList->ClearFreeMemory(); + window->DC.ChildWindows.clear(); + window->DC.ItemFlagsStack.clear(); + window->DC.ItemWidthStack.clear(); + window->DC.TextWrapPosStack.clear(); + window->DC.GroupStack.clear(); +} + +void ImGui::GcAwakeTransientWindowBuffers(ImGuiWindow* window) +{ + // We stored capacity of the ImDrawList buffer to reduce growth-caused allocation/copy when awakening. + // The other buffers tends to amortize much faster. + window->MemoryCompacted = false; + window->DrawList->IdxBuffer.reserve(window->MemoryDrawListIdxCapacity); + window->DrawList->VtxBuffer.reserve(window->MemoryDrawListVtxCapacity); + window->MemoryDrawListIdxCapacity = window->MemoryDrawListVtxCapacity = 0; +} + +void ImGui::SetActiveID(ImGuiID id, ImGuiWindow* window) +{ + ImGuiContext& g = *GImGui; + g.ActiveIdIsJustActivated = (g.ActiveId != id); + if (g.ActiveIdIsJustActivated) + { + g.ActiveIdTimer = 0.0f; + g.ActiveIdHasBeenPressedBefore = false; + g.ActiveIdHasBeenEditedBefore = false; + if (id != 0) + { + g.LastActiveId = id; + g.LastActiveIdTimer = 0.0f; + } + } + g.ActiveId = id; + g.ActiveIdAllowOverlap = false; + g.ActiveIdWindow = window; + g.ActiveIdHasBeenEditedThisFrame = false; + if (id) + { + g.ActiveIdIsAlive = id; + g.ActiveIdSource = (g.NavActivateId == id || g.NavInputId == id || g.NavJustTabbedId == id || g.NavJustMovedToId == id) ? ImGuiInputSource_Nav : ImGuiInputSource_Mouse; + } + + // Clear declaration of inputs claimed by the widget + // (Please note that this is WIP and not all keys/inputs are thoroughly declared by all widgets yet) + g.ActiveIdUsingNavDirMask = 0x00; + g.ActiveIdUsingNavInputMask = 0x00; + g.ActiveIdUsingKeyInputMask = 0x00; +} + +void ImGui::ClearActiveID() +{ + SetActiveID(0, NULL); +} + +void ImGui::SetHoveredID(ImGuiID id) +{ + ImGuiContext& g = *GImGui; + g.HoveredId = id; + g.HoveredIdAllowOverlap = false; + if (id != 0 && g.HoveredIdPreviousFrame != id) + g.HoveredIdTimer = g.HoveredIdNotActiveTimer = 0.0f; +} + +ImGuiID ImGui::GetHoveredID() +{ + ImGuiContext& g = *GImGui; + return g.HoveredId ? g.HoveredId : g.HoveredIdPreviousFrame; +} + +void ImGui::KeepAliveID(ImGuiID id) +{ + ImGuiContext& g = *GImGui; + if (g.ActiveId == id) + g.ActiveIdIsAlive = id; + if (g.ActiveIdPreviousFrame == id) + g.ActiveIdPreviousFrameIsAlive = true; +} + +void ImGui::MarkItemEdited(ImGuiID id) +{ + // This marking is solely to be able to provide info for IsItemDeactivatedAfterEdit(). + // ActiveId might have been released by the time we call this (as in the typical press/release button behavior) but still need need to fill the data. + ImGuiContext& g = *GImGui; + IM_ASSERT(g.ActiveId == id || g.ActiveId == 0 || g.DragDropActive); + IM_UNUSED(id); // Avoid unused variable warnings when asserts are compiled out. + //IM_ASSERT(g.CurrentWindow->DC.LastItemId == id); + g.ActiveIdHasBeenEditedThisFrame = true; + g.ActiveIdHasBeenEditedBefore = true; + g.CurrentWindow->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_Edited; +} + +static inline bool IsWindowContentHoverable(ImGuiWindow* window, ImGuiHoveredFlags flags) +{ + // An active popup disable hovering on other windows (apart from its own children) + // FIXME-OPT: This could be cached/stored within the window. + ImGuiContext& g = *GImGui; + if (g.NavWindow) + if (ImGuiWindow* focused_root_window = g.NavWindow->RootWindow) + if (focused_root_window->WasActive && focused_root_window != window->RootWindow) + { + // For the purpose of those flags we differentiate "standard popup" from "modal popup" + // NB: The order of those two tests is important because Modal windows are also Popups. + if (focused_root_window->Flags & ImGuiWindowFlags_Modal) + return false; + if ((focused_root_window->Flags & ImGuiWindowFlags_Popup) && !(flags & ImGuiHoveredFlags_AllowWhenBlockedByPopup)) + return false; + } + + // Filter by viewport + if (window->Viewport != g.MouseViewport) + if (g.MovingWindow == NULL || window->RootWindow != g.MovingWindow->RootWindow) + return false; + + return true; +} + +// This is roughly matching the behavior of internal-facing ItemHoverable() +// - we allow hovering to be true when ActiveId==window->MoveID, so that clicking on non-interactive items such as a Text() item still returns true with IsItemHovered() +// - this should work even for non-interactive items that have no ID, so we cannot use LastItemId +bool ImGui::IsItemHovered(ImGuiHoveredFlags flags) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if (g.NavDisableMouseHover && !g.NavDisableHighlight) + return IsItemFocused(); + + // Test for bounding box overlap, as updated as ItemAdd() + if (!(window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_HoveredRect)) + return false; + IM_ASSERT((flags & (ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_ChildWindows)) == 0); // Flags not supported by this function + + // Test if we are hovering the right window (our window could be behind another window) + // [2017/10/16] Reverted commit 344d48be3 and testing RootWindow instead. I believe it is correct to NOT test for RootWindow but this leaves us unable to use IsItemHovered() after EndChild() itself. + // Until a solution is found I believe reverting to the test from 2017/09/27 is safe since this was the test that has been running for a long while. + //if (g.HoveredWindow != window) + // return false; + if (g.HoveredRootWindow != window->RootWindow && !(flags & ImGuiHoveredFlags_AllowWhenOverlapped)) + return false; + + // Test if another item is active (e.g. being dragged) + if (!(flags & ImGuiHoveredFlags_AllowWhenBlockedByActiveItem)) + if (g.ActiveId != 0 && g.ActiveId != window->DC.LastItemId && !g.ActiveIdAllowOverlap && g.ActiveId != window->MoveId) + return false; + + // Test if interactions on this window are blocked by an active popup or modal. + // The ImGuiHoveredFlags_AllowWhenBlockedByPopup flag will be tested here. + if (!IsWindowContentHoverable(window, flags)) + return false; + + // Test if the item is disabled + if ((window->DC.ItemFlags & ImGuiItemFlags_Disabled) && !(flags & ImGuiHoveredFlags_AllowWhenDisabled)) + return false; + + // Special handling for the dummy item after Begin() which represent the title bar or tab. + // When the window is collapsed (SkipItems==true) that last item will never be overwritten so we need to detect the case. + if ((window->DC.LastItemId == window->ID || window->DC.LastItemId == window->MoveId) && window->WriteAccessed) + return false; + return true; +} + +// Internal facing ItemHoverable() used when submitting widgets. Differs slightly from IsItemHovered(). +bool ImGui::ItemHoverable(const ImRect& bb, ImGuiID id) +{ + ImGuiContext& g = *GImGui; + if (g.HoveredId != 0 && g.HoveredId != id && !g.HoveredIdAllowOverlap) + return false; + + ImGuiWindow* window = g.CurrentWindow; + if (g.HoveredWindow != window) + return false; + if (g.ActiveId != 0 && g.ActiveId != id && !g.ActiveIdAllowOverlap) + return false; + if (!IsMouseHoveringRect(bb.Min, bb.Max)) + return false; + if (g.NavDisableMouseHover || !IsWindowContentHoverable(window, ImGuiHoveredFlags_None)) + return false; + if (window->DC.ItemFlags & ImGuiItemFlags_Disabled) + return false; + + SetHoveredID(id); + + // [DEBUG] Item Picker tool! + // We perform the check here because SetHoveredID() is not frequently called (1~ time a frame), making + // the cost of this tool near-zero. We can get slightly better call-stack and support picking non-hovered + // items if we perform the test in ItemAdd(), but that would incur a small runtime cost. + // #define IMGUI_DEBUG_TOOL_ITEM_PICKER_EX in imconfig.h if you want this check to also be performed in ItemAdd(). + if (g.DebugItemPickerActive && g.HoveredIdPreviousFrame == id) + GetForegroundDrawList()->AddRect(bb.Min, bb.Max, IM_COL32(255, 255, 0, 255)); + if (g.DebugItemPickerBreakId == id) + IM_DEBUG_BREAK(); + + return true; +} + +bool ImGui::IsClippedEx(const ImRect& bb, ImGuiID id, bool clip_even_when_logged) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if (!bb.Overlaps(window->ClipRect)) + if (id == 0 || (id != g.ActiveId && id != g.NavId)) + if (clip_even_when_logged || !g.LogEnabled) + return true; + return false; +} + +// Process TAB/Shift+TAB. Be mindful that this function may _clear_ the ActiveID when tabbing out. +bool ImGui::FocusableItemRegister(ImGuiWindow* window, ImGuiID id) +{ + ImGuiContext& g = *GImGui; + + // Increment counters + const bool is_tab_stop = (window->DC.ItemFlags & (ImGuiItemFlags_NoTabStop | ImGuiItemFlags_Disabled)) == 0; + window->DC.FocusCounterRegular++; + if (is_tab_stop) + window->DC.FocusCounterTabStop++; + + // Process TAB/Shift-TAB to tab *OUT* of the currently focused item. + // (Note that we can always TAB out of a widget that doesn't allow tabbing in) + if (g.ActiveId == id && g.FocusTabPressed && !IsActiveIdUsingKey(ImGuiKey_Tab) && g.FocusRequestNextWindow == NULL) + { + g.FocusRequestNextWindow = window; + g.FocusRequestNextCounterTabStop = window->DC.FocusCounterTabStop + (g.IO.KeyShift ? (is_tab_stop ? -1 : 0) : +1); // Modulo on index will be applied at the end of frame once we've got the total counter of items. + } + + // Handle focus requests + if (g.FocusRequestCurrWindow == window) + { + if (window->DC.FocusCounterRegular == g.FocusRequestCurrCounterRegular) + return true; + if (is_tab_stop && window->DC.FocusCounterTabStop == g.FocusRequestCurrCounterTabStop) + { + g.NavJustTabbedId = id; + return true; + } + + // If another item is about to be focused, we clear our own active id + if (g.ActiveId == id) + ClearActiveID(); + } + + return false; +} + +void ImGui::FocusableItemUnregister(ImGuiWindow* window) +{ + window->DC.FocusCounterRegular--; + window->DC.FocusCounterTabStop--; +} + +float ImGui::CalcWrapWidthForPos(const ImVec2& pos, float wrap_pos_x) +{ + if (wrap_pos_x < 0.0f) + return 0.0f; + + ImGuiWindow* window = GImGui->CurrentWindow; + if (wrap_pos_x == 0.0f) + wrap_pos_x = window->WorkRect.Max.x; + else if (wrap_pos_x > 0.0f) + wrap_pos_x += window->Pos.x - window->Scroll.x; // wrap_pos_x is provided is window local space + + return ImMax(wrap_pos_x - pos.x, 1.0f); +} + +// IM_ALLOC() == ImGui::MemAlloc() +void* ImGui::MemAlloc(size_t size) +{ + if (ImGuiContext* ctx = GImGui) + ctx->IO.MetricsActiveAllocations++; + return GImAllocatorAllocFunc(size, GImAllocatorUserData); +} + +// IM_FREE() == ImGui::MemFree() +void ImGui::MemFree(void* ptr) +{ + if (ptr) + if (ImGuiContext* ctx = GImGui) + ctx->IO.MetricsActiveAllocations--; + return GImAllocatorFreeFunc(ptr, GImAllocatorUserData); +} + +const char* ImGui::GetClipboardText() +{ + ImGuiContext& g = *GImGui; + return g.IO.GetClipboardTextFn ? g.IO.GetClipboardTextFn(g.IO.ClipboardUserData) : ""; +} + +void ImGui::SetClipboardText(const char* text) +{ + ImGuiContext& g = *GImGui; + if (g.IO.SetClipboardTextFn) + g.IO.SetClipboardTextFn(g.IO.ClipboardUserData, text); +} + +const char* ImGui::GetVersion() +{ + return IMGUI_VERSION; +} + +// Internal state access - if you want to share Dear ImGui state between modules (e.g. DLL) or allocate it yourself +// Note that we still point to some static data and members (such as GFontAtlas), so the state instance you end up using will point to the static data within its module +ImGuiContext* ImGui::GetCurrentContext() +{ + return GImGui; +} + +void ImGui::SetCurrentContext(ImGuiContext* ctx) +{ +#ifdef IMGUI_SET_CURRENT_CONTEXT_FUNC + IMGUI_SET_CURRENT_CONTEXT_FUNC(ctx); // For custom thread-based hackery you may want to have control over this. +#else + GImGui = ctx; +#endif +} + +void ImGui::SetAllocatorFunctions(void* (*alloc_func)(size_t sz, void* user_data), void (*free_func)(void* ptr, void* user_data), void* user_data) +{ + GImAllocatorAllocFunc = alloc_func; + GImAllocatorFreeFunc = free_func; + GImAllocatorUserData = user_data; +} + +ImGuiContext* ImGui::CreateContext(ImFontAtlas* shared_font_atlas) +{ + ImGuiContext* ctx = IM_NEW(ImGuiContext)(shared_font_atlas); + if (GImGui == NULL) + SetCurrentContext(ctx); + Initialize(ctx); + return ctx; +} + +void ImGui::DestroyContext(ImGuiContext* ctx) +{ + if (ctx == NULL) + ctx = GImGui; + Shutdown(ctx); + if (GImGui == ctx) + SetCurrentContext(NULL); + IM_DELETE(ctx); +} + +ImGuiIO& ImGui::GetIO() +{ + IM_ASSERT(GImGui != NULL && "No current context. Did you call ImGui::CreateContext() and ImGui::SetCurrentContext() ?"); + return GImGui->IO; +} + +ImGuiPlatformIO& ImGui::GetPlatformIO() +{ + IM_ASSERT(GImGui != NULL && "No current context. Did you call ImGui::CreateContext() or ImGui::SetCurrentContext()?"); + return GImGui->PlatformIO; +} + +// Same value as passed to the old io.RenderDrawListsFn function. Valid after Render() and until the next call to NewFrame() +ImDrawData* ImGui::GetDrawData() +{ + ImGuiContext& g = *GImGui; + return g.Viewports[0]->DrawDataP.Valid ? &g.Viewports[0]->DrawDataP : NULL; +} + +double ImGui::GetTime() +{ + return GImGui->Time; +} + +int ImGui::GetFrameCount() +{ + return GImGui->FrameCount; +} + +static ImDrawList* GetViewportDrawList(ImGuiViewportP* viewport, size_t drawlist_no, const char* drawlist_name) +{ + // Create the draw list on demand, because they are not frequently used for all viewports + ImGuiContext& g = *GImGui; + IM_ASSERT(drawlist_no < IM_ARRAYSIZE(viewport->DrawLists)); + ImDrawList* draw_list = viewport->DrawLists[drawlist_no]; + if (draw_list == NULL) + { + draw_list = IM_NEW(ImDrawList)(&g.DrawListSharedData); + draw_list->_OwnerName = drawlist_name; + viewport->DrawLists[drawlist_no] = draw_list; + } + + // Our ImDrawList system requires that there is always a command + if (viewport->LastFrameDrawLists[drawlist_no] != g.FrameCount) + { + draw_list->Clear(); + draw_list->PushTextureID(g.IO.Fonts->TexID); + draw_list->PushClipRect(viewport->Pos, viewport->Pos + viewport->Size, false); + viewport->LastFrameDrawLists[drawlist_no] = g.FrameCount; + } + return draw_list; +} + +ImDrawList* ImGui::GetBackgroundDrawList(ImGuiViewport* viewport) +{ + return GetViewportDrawList((ImGuiViewportP*)viewport, 0, "##Background"); +} + +ImDrawList* ImGui::GetBackgroundDrawList() +{ + ImGuiWindow* window = GImGui->CurrentWindow; + return GetBackgroundDrawList(window->Viewport); +} + +ImDrawList* ImGui::GetForegroundDrawList(ImGuiViewport* viewport) +{ + return GetViewportDrawList((ImGuiViewportP*)viewport, 1, "##Foreground"); +} + +ImDrawList* ImGui::GetForegroundDrawList() +{ + ImGuiWindow* window = GImGui->CurrentWindow; + return GetForegroundDrawList(window->Viewport); +} + +ImDrawListSharedData* ImGui::GetDrawListSharedData() +{ + return &GImGui->DrawListSharedData; +} + +void ImGui::StartMouseMovingWindow(ImGuiWindow* window) +{ + // Set ActiveId even if the _NoMove flag is set. Without it, dragging away from a window with _NoMove would activate hover on other windows. + // We _also_ call this when clicking in a window empty space when io.ConfigWindowsMoveFromTitleBarOnly is set, but clear g.MovingWindow afterward. + // This is because we want ActiveId to be set even when the window is not permitted to move. + ImGuiContext& g = *GImGui; + FocusWindow(window); + SetActiveID(window->MoveId, window); + g.NavDisableHighlight = true; + g.ActiveIdClickOffset = g.IO.MousePos - window->RootWindow->Pos; + + bool can_move_window = true; + if ((window->Flags & ImGuiWindowFlags_NoMove) || (window->RootWindow->Flags & ImGuiWindowFlags_NoMove)) + can_move_window = false; + if (ImGuiDockNode* node = window->DockNodeAsHost) + if (node->VisibleWindow && (node->VisibleWindow->Flags & ImGuiWindowFlags_NoMove)) + can_move_window = false; + if (can_move_window) + g.MovingWindow = window; +} + +// We use 'undock_floating_node == false' when dragging from title bar to allow moving groups of floating nodes without undocking them. +// - undock_floating_node == true: when dragging from a floating node within a hierarchy, always undock the node. +// - undock_floating_node == false: when dragging from a floating node within a hierarchy, move root window. +void ImGui::StartMouseMovingWindowOrNode(ImGuiWindow* window, ImGuiDockNode* node, bool undock_floating_node) +{ + ImGuiContext& g = *GImGui; + bool can_undock_node = false; + if (node != NULL && node->VisibleWindow && (node->VisibleWindow->Flags & ImGuiWindowFlags_NoMove) == 0) + { + // Can undock if: + // - part of a floating node hierarchy with more than one visible node (if only one is visible, we'll just move the whole hierarchy) + // - part of a dockspace node hierarchy (trivia: undocking from a fixed/central node will create a new node and copy windows) + ImGuiDockNode* root_node = DockNodeGetRootNode(node); + if (root_node->OnlyNodeWithWindows != node || root_node->CentralNode != NULL) // -V1051 PVS-Studio thinks node should be root_node and is wrong about that. + if (undock_floating_node || root_node->IsDockSpace()) + can_undock_node = true; + } + + const bool clicked = IsMouseClicked(0); + const bool dragging = IsMouseDragging(0, g.IO.MouseDragThreshold * 1.70f); + if (can_undock_node && dragging) + { + DockContextQueueUndockNode(&g, node); + g.ActiveIdClickOffset = g.IO.MouseClickedPos[0] - node->Pos; + } + else if (!can_undock_node && (clicked || dragging) && g.MovingWindow != window) + { + StartMouseMovingWindow(window); + g.ActiveIdClickOffset = g.IO.MouseClickedPos[0] - window->RootWindow->Pos; + } +} + +// Handle mouse moving window +// Note: moving window with the navigation keys (Square + d-pad / CTRL+TAB + Arrows) are processed in NavUpdateWindowing() +// FIXME: We don't have strong guarantee that g.MovingWindow stay synched with g.ActiveId == g.MovingWindow->MoveId. +// This is currently enforced by the fact that BeginDragDropSource() is setting all g.ActiveIdUsingXXXX flags to inhibit navigation inputs, +// but if we should more thoroughly test cases where g.ActiveId or g.MovingWindow gets changed and not the other. +void ImGui::UpdateMouseMovingWindowNewFrame() +{ + ImGuiContext& g = *GImGui; + if (g.MovingWindow != NULL) + { + // We actually want to move the root window. g.MovingWindow == window we clicked on (could be a child window). + // We track it to preserve Focus and so that generally ActiveIdWindow == MovingWindow and ActiveId == MovingWindow->MoveId for consistency. + KeepAliveID(g.ActiveId); + IM_ASSERT(g.MovingWindow && g.MovingWindow->RootWindow); + ImGuiWindow* moving_window = g.MovingWindow->RootWindow; + if (g.IO.MouseDown[0] && IsMousePosValid(&g.IO.MousePos)) + { + ImVec2 pos = g.IO.MousePos - g.ActiveIdClickOffset; + if (moving_window->Pos.x != pos.x || moving_window->Pos.y != pos.y) + { + MarkIniSettingsDirty(moving_window); + SetWindowPos(moving_window, pos, ImGuiCond_Always); + if (moving_window->ViewportOwned) // Synchronize viewport immediately because some overlays may relies on clipping rectangle before we Begin() into the window. + moving_window->Viewport->Pos = pos; + } + FocusWindow(g.MovingWindow); + } + else + { + // Try to merge the window back into the main viewport. + // This works because MouseViewport should be != MovingWindow->Viewport on release (as per code in UpdateViewports) + if (g.ConfigFlagsCurrFrame & ImGuiConfigFlags_ViewportsEnable) + UpdateTryMergeWindowIntoHostViewport(moving_window, g.MouseViewport); + + // Restore the mouse viewport so that we don't hover the viewport _under_ the moved window during the frame we released the mouse button. + if (!IsDragDropPayloadBeingAccepted()) + g.MouseViewport = moving_window->Viewport; + + // Clear the NoInput window flag set by the Viewport system + moving_window->Viewport->Flags &= ~ImGuiViewportFlags_NoInputs; + + ClearActiveID(); + g.MovingWindow = NULL; + } + } + else + { + // When clicking/dragging from a window that has the _NoMove flag, we still set the ActiveId in order to prevent hovering others. + if (g.ActiveIdWindow && g.ActiveIdWindow->MoveId == g.ActiveId) + { + KeepAliveID(g.ActiveId); + if (!g.IO.MouseDown[0]) + ClearActiveID(); + } + } +} + +// Initiate moving window when clicking on empty space or title bar. +// Handle left-click and right-click focus. +void ImGui::UpdateMouseMovingWindowEndFrame() +{ + ImGuiContext& g = *GImGui; + if (g.ActiveId != 0 || g.HoveredId != 0) + return; + + // Unless we just made a window/popup appear + if (g.NavWindow && g.NavWindow->Appearing) + return; + + // Click on void to focus window and start moving + // (after we're done with all our widgets, so e.g. clicking on docking tab-bar which have set HoveredId already and not get us here!) + if (g.IO.MouseClicked[0]) + { + ImGuiWindow* root_window = g.HoveredWindow ? g.HoveredWindow->RootWindowDockStop : NULL; + if (root_window != NULL) + { + StartMouseMovingWindow(g.HoveredWindow); + if (g.IO.ConfigWindowsMoveFromTitleBarOnly) + if (!(root_window->Flags & ImGuiWindowFlags_NoTitleBar) || root_window->DockIsActive) + if (!root_window->TitleBarRect().Contains(g.IO.MouseClickedPos[0])) + g.MovingWindow = NULL; + } + else if (g.NavWindow != NULL && GetTopMostPopupModal() == NULL) + { + // Clicking on void disable focus + FocusWindow(NULL); + } + } + + // With right mouse button we close popups without changing focus based on where the mouse is aimed + // Instead, focus will be restored to the window under the bottom-most closed popup. + // (The left mouse button path calls FocusWindow on the hovered window, which will lead NewFrame->ClosePopupsOverWindow to trigger) + if (g.IO.MouseClicked[1]) + { + // Find the top-most window between HoveredWindow and the top-most Modal Window. + // This is where we can trim the popup stack. + ImGuiWindow* modal = GetTopMostPopupModal(); + bool hovered_window_above_modal = false; + if (modal == NULL) + hovered_window_above_modal = true; + for (int i = g.Windows.Size - 1; i >= 0 && hovered_window_above_modal == false; i--) + { + ImGuiWindow* window = g.Windows[i]; + if (window == modal) + break; + if (window == g.HoveredWindow) + hovered_window_above_modal = true; + } + ClosePopupsOverWindow(hovered_window_above_modal ? g.HoveredWindow : modal, true); + } +} + +static void TranslateWindow(ImGuiWindow* window, const ImVec2& delta) +{ + window->Pos += delta; + window->ClipRect.Translate(delta); + window->OuterRectClipped.Translate(delta); + window->InnerRect.Translate(delta); + window->DC.CursorPos += delta; + window->DC.CursorStartPos += delta; + window->DC.CursorMaxPos += delta; + window->DC.LastItemRect.Translate(delta); + window->DC.LastItemDisplayRect.Translate(delta); +} + +static void ScaleWindow(ImGuiWindow* window, float scale) +{ + ImVec2 origin = window->Viewport->Pos; + window->Pos = ImFloor((window->Pos - origin) * scale + origin); + window->Size = ImFloor(window->Size * scale); + window->SizeFull = ImFloor(window->SizeFull * scale); + window->ContentSize = ImFloor(window->ContentSize * scale); +} + +static bool IsWindowActiveAndVisible(ImGuiWindow* window) +{ + return (window->Active) && (!window->Hidden); +} + +static void ImGui::UpdateMouseInputs() +{ + ImGuiContext& g = *GImGui; + + // Round mouse position to avoid spreading non-rounded position (e.g. UpdateManualResize doesn't support them well) + if (IsMousePosValid(&g.IO.MousePos)) + g.IO.MousePos = g.LastValidMousePos = ImFloor(g.IO.MousePos); + + // If mouse just appeared or disappeared (usually denoted by -FLT_MAX components) we cancel out movement in MouseDelta + if (IsMousePosValid(&g.IO.MousePos) && IsMousePosValid(&g.IO.MousePosPrev)) + g.IO.MouseDelta = g.IO.MousePos - g.IO.MousePosPrev; + else + g.IO.MouseDelta = ImVec2(0.0f, 0.0f); + if (g.IO.MouseDelta.x != 0.0f || g.IO.MouseDelta.y != 0.0f) + g.NavDisableMouseHover = false; + + g.IO.MousePosPrev = g.IO.MousePos; + for (int i = 0; i < IM_ARRAYSIZE(g.IO.MouseDown); i++) + { + g.IO.MouseClicked[i] = g.IO.MouseDown[i] && g.IO.MouseDownDuration[i] < 0.0f; + g.IO.MouseReleased[i] = !g.IO.MouseDown[i] && g.IO.MouseDownDuration[i] >= 0.0f; + g.IO.MouseDownDurationPrev[i] = g.IO.MouseDownDuration[i]; + g.IO.MouseDownDuration[i] = g.IO.MouseDown[i] ? (g.IO.MouseDownDuration[i] < 0.0f ? 0.0f : g.IO.MouseDownDuration[i] + g.IO.DeltaTime) : -1.0f; + g.IO.MouseDoubleClicked[i] = false; + if (g.IO.MouseClicked[i]) + { + if ((float)(g.Time - g.IO.MouseClickedTime[i]) < g.IO.MouseDoubleClickTime) + { + ImVec2 delta_from_click_pos = IsMousePosValid(&g.IO.MousePos) ? (g.IO.MousePos - g.IO.MouseClickedPos[i]) : ImVec2(0.0f, 0.0f); + if (ImLengthSqr(delta_from_click_pos) < g.IO.MouseDoubleClickMaxDist * g.IO.MouseDoubleClickMaxDist) + g.IO.MouseDoubleClicked[i] = true; + g.IO.MouseClickedTime[i] = -DBL_MAX; // so the third click isn't turned into a double-click + } + else + { + g.IO.MouseClickedTime[i] = g.Time; + } + g.IO.MouseClickedPos[i] = g.IO.MousePos; + g.IO.MouseDownWasDoubleClick[i] = g.IO.MouseDoubleClicked[i]; + g.IO.MouseDragMaxDistanceAbs[i] = ImVec2(0.0f, 0.0f); + g.IO.MouseDragMaxDistanceSqr[i] = 0.0f; + } + else if (g.IO.MouseDown[i]) + { + // Maintain the maximum distance we reaching from the initial click position, which is used with dragging threshold + ImVec2 delta_from_click_pos = IsMousePosValid(&g.IO.MousePos) ? (g.IO.MousePos - g.IO.MouseClickedPos[i]) : ImVec2(0.0f, 0.0f); + g.IO.MouseDragMaxDistanceSqr[i] = ImMax(g.IO.MouseDragMaxDistanceSqr[i], ImLengthSqr(delta_from_click_pos)); + g.IO.MouseDragMaxDistanceAbs[i].x = ImMax(g.IO.MouseDragMaxDistanceAbs[i].x, delta_from_click_pos.x < 0.0f ? -delta_from_click_pos.x : delta_from_click_pos.x); + g.IO.MouseDragMaxDistanceAbs[i].y = ImMax(g.IO.MouseDragMaxDistanceAbs[i].y, delta_from_click_pos.y < 0.0f ? -delta_from_click_pos.y : delta_from_click_pos.y); + } + if (!g.IO.MouseDown[i] && !g.IO.MouseReleased[i]) + g.IO.MouseDownWasDoubleClick[i] = false; + if (g.IO.MouseClicked[i]) // Clicking any mouse button reactivate mouse hovering which may have been deactivated by gamepad/keyboard navigation + g.NavDisableMouseHover = false; + } +} + +static void StartLockWheelingWindow(ImGuiWindow* window) +{ + ImGuiContext& g = *GImGui; + if (g.WheelingWindow == window) + return; + g.WheelingWindow = window; + g.WheelingWindowRefMousePos = g.IO.MousePos; + g.WheelingWindowTimer = WINDOWS_MOUSE_WHEEL_SCROLL_LOCK_TIMER; +} + +void ImGui::UpdateMouseWheel() +{ + ImGuiContext& g = *GImGui; + + // Reset the locked window if we move the mouse or after the timer elapses + if (g.WheelingWindow != NULL) + { + g.WheelingWindowTimer -= g.IO.DeltaTime; + if (IsMousePosValid() && ImLengthSqr(g.IO.MousePos - g.WheelingWindowRefMousePos) > g.IO.MouseDragThreshold * g.IO.MouseDragThreshold) + g.WheelingWindowTimer = 0.0f; + if (g.WheelingWindowTimer <= 0.0f) + { + g.WheelingWindow = NULL; + g.WheelingWindowTimer = 0.0f; + } + } + + if (g.IO.MouseWheel == 0.0f && g.IO.MouseWheelH == 0.0f) + return; + + ImGuiWindow* window = g.WheelingWindow ? g.WheelingWindow : g.HoveredWindow; + if (!window || window->Collapsed) + return; + + // Zoom / Scale window + // FIXME-OBSOLETE: This is an old feature, it still works but pretty much nobody is using it and may be best redesigned. + if (g.IO.MouseWheel != 0.0f && g.IO.KeyCtrl && g.IO.FontAllowUserScaling) + { + StartLockWheelingWindow(window); + const float new_font_scale = ImClamp(window->FontWindowScale + g.IO.MouseWheel * 0.10f, 0.50f, 2.50f); + const float scale = new_font_scale / window->FontWindowScale; + window->FontWindowScale = new_font_scale; + if (!(window->Flags & ImGuiWindowFlags_ChildWindow)) + { + const ImVec2 offset = window->Size * (1.0f - scale) * (g.IO.MousePos - window->Pos) / window->Size; + SetWindowPos(window, window->Pos + offset, 0); + window->Size = ImFloor(window->Size * scale); + window->SizeFull = ImFloor(window->SizeFull * scale); + } + return; + } + + // Mouse wheel scrolling + // If a child window has the ImGuiWindowFlags_NoScrollWithMouse flag, we give a chance to scroll its parent + + // Vertical Mouse Wheel scrolling + const float wheel_y = (g.IO.MouseWheel != 0.0f && !g.IO.KeyShift) ? g.IO.MouseWheel : 0.0f; + if (wheel_y != 0.0f && !g.IO.KeyCtrl) + { + StartLockWheelingWindow(window); + while ((window->Flags & ImGuiWindowFlags_ChildWindow) && ((window->ScrollMax.y == 0.0f) || ((window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(window->Flags & ImGuiWindowFlags_NoMouseInputs)))) + window = window->ParentWindow; + if (!(window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(window->Flags & ImGuiWindowFlags_NoMouseInputs)) + { + float max_step = window->InnerRect.GetHeight() * 0.67f; + float scroll_step = ImFloor(ImMin(5 * window->CalcFontSize(), max_step)); + SetScrollY(window, window->Scroll.y - wheel_y * scroll_step); + } + } + + // Horizontal Mouse Wheel scrolling, or Vertical Mouse Wheel w/ Shift held + const float wheel_x = (g.IO.MouseWheelH != 0.0f && !g.IO.KeyShift) ? g.IO.MouseWheelH : (g.IO.MouseWheel != 0.0f && g.IO.KeyShift) ? g.IO.MouseWheel : 0.0f; + if (wheel_x != 0.0f && !g.IO.KeyCtrl) + { + StartLockWheelingWindow(window); + while ((window->Flags & ImGuiWindowFlags_ChildWindow) && ((window->ScrollMax.x == 0.0f) || ((window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(window->Flags & ImGuiWindowFlags_NoMouseInputs)))) + window = window->ParentWindow; + if (!(window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(window->Flags & ImGuiWindowFlags_NoMouseInputs)) + { + float max_step = window->InnerRect.GetWidth() * 0.67f; + float scroll_step = ImFloor(ImMin(2 * window->CalcFontSize(), max_step)); + SetScrollX(window, window->Scroll.x - wheel_x * scroll_step); + } + } +} + +void ImGui::UpdateTabFocus() +{ + ImGuiContext& g = *GImGui; + + // Pressing TAB activate widget focus + g.FocusTabPressed = (g.NavWindow && g.NavWindow->Active && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs) && !g.IO.KeyCtrl && IsKeyPressedMap(ImGuiKey_Tab)); + if (g.ActiveId == 0 && g.FocusTabPressed) + { + // Note that SetKeyboardFocusHere() sets the Next fields mid-frame. To be consistent we also + // manipulate the Next fields even, even though they will be turned into Curr fields by the code below. + g.FocusRequestNextWindow = g.NavWindow; + g.FocusRequestNextCounterRegular = INT_MAX; + if (g.NavId != 0 && g.NavIdTabCounter != INT_MAX) + g.FocusRequestNextCounterTabStop = g.NavIdTabCounter + 1 + (g.IO.KeyShift ? -1 : 1); + else + g.FocusRequestNextCounterTabStop = g.IO.KeyShift ? -1 : 0; + } + + // Turn queued focus request into current one + g.FocusRequestCurrWindow = NULL; + g.FocusRequestCurrCounterRegular = g.FocusRequestCurrCounterTabStop = INT_MAX; + if (g.FocusRequestNextWindow != NULL) + { + ImGuiWindow* window = g.FocusRequestNextWindow; + g.FocusRequestCurrWindow = window; + if (g.FocusRequestNextCounterRegular != INT_MAX && window->DC.FocusCounterRegular != -1) + g.FocusRequestCurrCounterRegular = ImModPositive(g.FocusRequestNextCounterRegular, window->DC.FocusCounterRegular + 1); + if (g.FocusRequestNextCounterTabStop != INT_MAX && window->DC.FocusCounterTabStop != -1) + g.FocusRequestCurrCounterTabStop = ImModPositive(g.FocusRequestNextCounterTabStop, window->DC.FocusCounterTabStop + 1); + g.FocusRequestNextWindow = NULL; + g.FocusRequestNextCounterRegular = g.FocusRequestNextCounterTabStop = INT_MAX; + } + + g.NavIdTabCounter = INT_MAX; +} + +// The reason this is exposed in imgui_internal.h is: on touch-based system that don't have hovering, we want to dispatch inputs to the right target (imgui vs imgui+app) +void ImGui::UpdateHoveredWindowAndCaptureFlags() +{ + ImGuiContext& g = *GImGui; + + // Find the window hovered by mouse: + // - Child windows can extend beyond the limit of their parent so we need to derive HoveredRootWindow from HoveredWindow. + // - When moving a window we can skip the search, which also conveniently bypasses the fact that window->WindowRectClipped is lagging as this point of the frame. + // - We also support the moved window toggling the NoInputs flag after moving has started in order to be able to detect windows below it, which is useful for e.g. docking mechanisms. + FindHoveredWindow(); + IM_ASSERT(g.HoveredWindow == NULL || g.HoveredWindow == g.MovingWindow || g.HoveredWindow->Viewport == g.MouseViewport); + + // Modal windows prevents cursor from hovering behind them. + ImGuiWindow* modal_window = GetTopMostPopupModal(); + if (modal_window) + if (g.HoveredRootWindow && !IsWindowChildOf(g.HoveredRootWindow, modal_window)) + g.HoveredWindow = g.HoveredRootWindow = g.HoveredWindowUnderMovingWindow = NULL; + + // Disabled mouse? + if (g.IO.ConfigFlags & ImGuiConfigFlags_NoMouse) + g.HoveredWindow = g.HoveredRootWindow = g.HoveredWindowUnderMovingWindow = NULL; + + // We track click ownership. When clicked outside of a window the click is owned by the application and won't report hovering nor request capture even while dragging over our windows afterward. + int mouse_earliest_button_down = -1; + bool mouse_any_down = false; + for (int i = 0; i < IM_ARRAYSIZE(g.IO.MouseDown); i++) + { + if (g.IO.MouseClicked[i]) + g.IO.MouseDownOwned[i] = (g.HoveredWindow != NULL) || (!g.OpenPopupStack.empty()); + mouse_any_down |= g.IO.MouseDown[i]; + if (g.IO.MouseDown[i]) + if (mouse_earliest_button_down == -1 || g.IO.MouseClickedTime[i] < g.IO.MouseClickedTime[mouse_earliest_button_down]) + mouse_earliest_button_down = i; + } + const bool mouse_avail_to_imgui = (mouse_earliest_button_down == -1) || g.IO.MouseDownOwned[mouse_earliest_button_down]; + + // If mouse was first clicked outside of ImGui bounds we also cancel out hovering. + // FIXME: For patterns of drag and drop across OS windows, we may need to rework/remove this test (first committed 311c0ca9 on 2015/02) + const bool mouse_dragging_extern_payload = g.DragDropActive && (g.DragDropSourceFlags & ImGuiDragDropFlags_SourceExtern) != 0; + if (!mouse_avail_to_imgui && !mouse_dragging_extern_payload) + g.HoveredWindow = g.HoveredRootWindow = g.HoveredWindowUnderMovingWindow = NULL; + + // Update io.WantCaptureMouse for the user application (true = dispatch mouse info to imgui, false = dispatch mouse info to Dear ImGui + app) + if (g.WantCaptureMouseNextFrame != -1) + g.IO.WantCaptureMouse = (g.WantCaptureMouseNextFrame != 0); + else + g.IO.WantCaptureMouse = (mouse_avail_to_imgui && (g.HoveredWindow != NULL || mouse_any_down)) || (!g.OpenPopupStack.empty()); + + // Update io.WantCaptureKeyboard for the user application (true = dispatch keyboard info to imgui, false = dispatch keyboard info to Dear ImGui + app) + if (g.WantCaptureKeyboardNextFrame != -1) + g.IO.WantCaptureKeyboard = (g.WantCaptureKeyboardNextFrame != 0); + else + g.IO.WantCaptureKeyboard = (g.ActiveId != 0) || (modal_window != NULL); + if (g.IO.NavActive && (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) && !(g.IO.ConfigFlags & ImGuiConfigFlags_NavNoCaptureKeyboard)) + g.IO.WantCaptureKeyboard = true; + + // Update io.WantTextInput flag, this is to allow systems without a keyboard (e.g. mobile, hand-held) to show a software keyboard if possible + g.IO.WantTextInput = (g.WantTextInputNextFrame != -1) ? (g.WantTextInputNextFrame != 0) : false; +} + +ImGuiKeyModFlags ImGui::GetMergedKeyModFlags() +{ + ImGuiContext& g = *GImGui; + ImGuiKeyModFlags key_mod_flags = ImGuiKeyModFlags_None; + if (g.IO.KeyCtrl) { key_mod_flags |= ImGuiKeyModFlags_Ctrl; } + if (g.IO.KeyShift) { key_mod_flags |= ImGuiKeyModFlags_Shift; } + if (g.IO.KeyAlt) { key_mod_flags |= ImGuiKeyModFlags_Alt; } + if (g.IO.KeySuper) { key_mod_flags |= ImGuiKeyModFlags_Super; } + return key_mod_flags; +} + +void ImGui::NewFrame() +{ + IM_ASSERT(GImGui != NULL && "No current context. Did you call ImGui::CreateContext() and ImGui::SetCurrentContext() ?"); + ImGuiContext& g = *GImGui; + +#ifdef IMGUI_ENABLE_TEST_ENGINE + ImGuiTestEngineHook_PreNewFrame(&g); +#endif + + // Check and assert for various common IO and Configuration mistakes + g.ConfigFlagsLastFrame = g.ConfigFlagsCurrFrame; + ErrorCheckNewFrameSanityChecks(); + g.ConfigFlagsCurrFrame = g.IO.ConfigFlags; + + // Load settings on first frame, save settings when modified (after a delay) + UpdateSettings(); + + g.Time += g.IO.DeltaTime; + g.WithinFrameScope = true; + g.FrameCount += 1; + g.TooltipOverrideCount = 0; + g.WindowsActiveCount = 0; + g.MenusIdSubmittedThisFrame.resize(0); + + // Calculate frame-rate for the user, as a purely luxurious feature + g.FramerateSecPerFrameAccum += g.IO.DeltaTime - g.FramerateSecPerFrame[g.FramerateSecPerFrameIdx]; + g.FramerateSecPerFrame[g.FramerateSecPerFrameIdx] = g.IO.DeltaTime; + g.FramerateSecPerFrameIdx = (g.FramerateSecPerFrameIdx + 1) % IM_ARRAYSIZE(g.FramerateSecPerFrame); + g.IO.Framerate = (g.FramerateSecPerFrameAccum > 0.0f) ? (1.0f / (g.FramerateSecPerFrameAccum / (float)IM_ARRAYSIZE(g.FramerateSecPerFrame))) : FLT_MAX; + + UpdateViewportsNewFrame(); + + // Setup current font and draw list shared data + // FIXME-VIEWPORT: the concept of a single ClipRectFullscreen is not ideal! + g.IO.Fonts->Locked = true; + SetCurrentFont(GetDefaultFont()); + IM_ASSERT(g.Font->IsLoaded()); + ImRect virtual_space(FLT_MAX, FLT_MAX, -FLT_MAX, -FLT_MAX); + for (int n = 0; n < g.Viewports.Size; n++) + virtual_space.Add(g.Viewports[n]->GetMainRect()); + g.DrawListSharedData.ClipRectFullscreen = ImVec4(virtual_space.Min.x, virtual_space.Min.y, virtual_space.Max.x, virtual_space.Max.y); + g.DrawListSharedData.CurveTessellationTol = g.Style.CurveTessellationTol; + g.DrawListSharedData.SetCircleSegmentMaxError(g.Style.CircleSegmentMaxError); + g.DrawListSharedData.InitialFlags = ImDrawListFlags_None; + if (g.Style.AntiAliasedLines) + g.DrawListSharedData.InitialFlags |= ImDrawListFlags_AntiAliasedLines; + if (g.Style.AntiAliasedFill) + g.DrawListSharedData.InitialFlags |= ImDrawListFlags_AntiAliasedFill; + if (g.IO.BackendFlags & ImGuiBackendFlags_RendererHasVtxOffset) + g.DrawListSharedData.InitialFlags |= ImDrawListFlags_AllowVtxOffset; + + // Mark rendering data as invalid to prevent user who may have a handle on it to use it. + for (int n = 0; n < g.Viewports.Size; n++) + { + ImGuiViewportP* viewport = g.Viewports[n]; + viewport->DrawData = NULL; + viewport->DrawDataP.Clear(); + } + + // Drag and drop keep the source ID alive so even if the source disappear our state is consistent + if (g.DragDropActive && g.DragDropPayload.SourceId == g.ActiveId) + KeepAliveID(g.DragDropPayload.SourceId); + + // Update HoveredId data + if (!g.HoveredIdPreviousFrame) + g.HoveredIdTimer = 0.0f; + if (!g.HoveredIdPreviousFrame || (g.HoveredId && g.ActiveId == g.HoveredId)) + g.HoveredIdNotActiveTimer = 0.0f; + if (g.HoveredId) + g.HoveredIdTimer += g.IO.DeltaTime; + if (g.HoveredId && g.ActiveId != g.HoveredId) + g.HoveredIdNotActiveTimer += g.IO.DeltaTime; + g.HoveredIdPreviousFrame = g.HoveredId; + g.HoveredId = 0; + g.HoveredIdAllowOverlap = false; + + // Update ActiveId data (clear reference to active widget if the widget isn't alive anymore) + if (g.ActiveIdIsAlive != g.ActiveId && g.ActiveIdPreviousFrame == g.ActiveId && g.ActiveId != 0) + ClearActiveID(); + if (g.ActiveId) + g.ActiveIdTimer += g.IO.DeltaTime; + g.LastActiveIdTimer += g.IO.DeltaTime; + g.ActiveIdPreviousFrame = g.ActiveId; + g.ActiveIdPreviousFrameWindow = g.ActiveIdWindow; + g.ActiveIdPreviousFrameHasBeenEditedBefore = g.ActiveIdHasBeenEditedBefore; + g.ActiveIdIsAlive = 0; + g.ActiveIdHasBeenEditedThisFrame = false; + g.ActiveIdPreviousFrameIsAlive = false; + g.ActiveIdIsJustActivated = false; + if (g.TempInputId != 0 && g.ActiveId != g.TempInputId) + g.TempInputId = 0; + if (g.ActiveId == 0) + { + g.ActiveIdUsingNavDirMask = 0x00; + g.ActiveIdUsingNavInputMask = 0x00; + g.ActiveIdUsingKeyInputMask = 0x00; + } + + // Drag and drop + g.DragDropAcceptIdPrev = g.DragDropAcceptIdCurr; + g.DragDropAcceptIdCurr = 0; + g.DragDropAcceptIdCurrRectSurface = FLT_MAX; + g.DragDropWithinSource = false; + g.DragDropWithinTarget = false; + g.DragDropHoldJustPressedId = 0; + + // Update keyboard input state + // Synchronize io.KeyMods with individual modifiers io.KeyXXX bools + g.IO.KeyMods = GetMergedKeyModFlags(); + memcpy(g.IO.KeysDownDurationPrev, g.IO.KeysDownDuration, sizeof(g.IO.KeysDownDuration)); + for (int i = 0; i < IM_ARRAYSIZE(g.IO.KeysDown); i++) + g.IO.KeysDownDuration[i] = g.IO.KeysDown[i] ? (g.IO.KeysDownDuration[i] < 0.0f ? 0.0f : g.IO.KeysDownDuration[i] + g.IO.DeltaTime) : -1.0f; + + // Update gamepad/keyboard navigation + NavUpdate(); + + // Update mouse input state + UpdateMouseInputs(); + + // Undocking + // (needs to be before UpdateMouseMovingWindowNewFrame so the window is already offset and following the mouse on the detaching frame) + DockContextUpdateUndocking(&g); + + // Find hovered window + // (needs to be before UpdateMouseMovingWindowNewFrame so we fill g.HoveredWindowUnderMovingWindow on the mouse release frame) + UpdateHoveredWindowAndCaptureFlags(); + + // Handle user moving window with mouse (at the beginning of the frame to avoid input lag or sheering) + UpdateMouseMovingWindowNewFrame(); + + // Background darkening/whitening + if (GetTopMostPopupModal() != NULL || (g.NavWindowingTarget != NULL && g.NavWindowingHighlightAlpha > 0.0f)) + g.DimBgRatio = ImMin(g.DimBgRatio + g.IO.DeltaTime * 6.0f, 1.0f); + else + g.DimBgRatio = ImMax(g.DimBgRatio - g.IO.DeltaTime * 10.0f, 0.0f); + + g.MouseCursor = ImGuiMouseCursor_Arrow; + g.WantCaptureMouseNextFrame = g.WantCaptureKeyboardNextFrame = g.WantTextInputNextFrame = -1; + g.PlatformImePos = ImVec2(1.0f, 1.0f); // OS Input Method Editor showing on top-left of our window by default + g.PlatformImePosViewport = NULL; + + // Mouse wheel scrolling, scale + UpdateMouseWheel(); + + // Update legacy TAB focus + UpdateTabFocus(); + + // Mark all windows as not visible and compact unused memory. + IM_ASSERT(g.WindowsFocusOrder.Size == g.Windows.Size); + const float memory_compact_start_time = (g.IO.ConfigWindowsMemoryCompactTimer >= 0.0f) ? (float)g.Time - g.IO.ConfigWindowsMemoryCompactTimer : FLT_MAX; + for (int i = 0; i != g.Windows.Size; i++) + { + ImGuiWindow* window = g.Windows[i]; + window->WasActive = window->Active; + window->BeginCount = 0; + window->Active = false; + window->WriteAccessed = false; + + // Garbage collect transient buffers of recently unused windows + if (!window->WasActive && !window->MemoryCompacted && window->LastTimeActive < memory_compact_start_time) + GcCompactTransientWindowBuffers(window); + } + + // Closing the focused window restore focus to the first active root window in descending z-order + if (g.NavWindow && !g.NavWindow->WasActive) + FocusTopMostWindowUnderOne(NULL, NULL); + + // No window should be open at the beginning of the frame. + // But in order to allow the user to call NewFrame() multiple times without calling Render(), we are doing an explicit clear. + g.CurrentWindowStack.resize(0); + g.BeginPopupStack.resize(0); + ClosePopupsOverWindow(g.NavWindow, false); + + // Docking + DockContextUpdateDocking(&g); + + // [DEBUG] Item picker tool - start with DebugStartItemPicker() - useful to visually select an item and break into its call-stack. + UpdateDebugToolItemPicker(); + + // Create implicit/fallback window - which we will only render it if the user has added something to it. + // We don't use "Debug" to avoid colliding with user trying to create a "Debug" window with custom flags. + // This fallback is particularly important as it avoid ImGui:: calls from crashing. + g.WithinFrameScopeWithImplicitWindow = true; + SetNextWindowSize(ImVec2(400,400), ImGuiCond_FirstUseEver); + Begin("Debug##Default"); + IM_ASSERT(g.CurrentWindow->IsFallbackWindow == true); + +#ifdef IMGUI_ENABLE_TEST_ENGINE + ImGuiTestEngineHook_PostNewFrame(&g); +#endif +} + +// [DEBUG] Item picker tool - start with DebugStartItemPicker() - useful to visually select an item and break into its call-stack. +void ImGui::UpdateDebugToolItemPicker() +{ + ImGuiContext& g = *GImGui; + g.DebugItemPickerBreakId = 0; + if (g.DebugItemPickerActive) + { + const ImGuiID hovered_id = g.HoveredIdPreviousFrame; + ImGui::SetMouseCursor(ImGuiMouseCursor_Hand); + if (ImGui::IsKeyPressedMap(ImGuiKey_Escape)) + g.DebugItemPickerActive = false; + if (ImGui::IsMouseClicked(0) && hovered_id) + { + g.DebugItemPickerBreakId = hovered_id; + g.DebugItemPickerActive = false; + } + ImGui::SetNextWindowBgAlpha(0.60f); + ImGui::BeginTooltip(); + ImGui::Text("HoveredId: 0x%08X", hovered_id); + ImGui::Text("Press ESC to abort picking."); + ImGui::TextColored(GetStyleColorVec4(hovered_id ? ImGuiCol_Text : ImGuiCol_TextDisabled), "Click to break in debugger!"); + ImGui::EndTooltip(); + } +} + +void ImGui::Initialize(ImGuiContext* context) +{ + ImGuiContext& g = *context; + IM_ASSERT(!g.Initialized && !g.SettingsLoaded); + + // Add .ini handle for ImGuiWindow type + { + ImGuiSettingsHandler ini_handler; + ini_handler.TypeName = "Window"; + ini_handler.TypeHash = ImHashStr("Window"); + ini_handler.ClearAllFn = WindowSettingsHandler_ClearAll; + ini_handler.ReadOpenFn = WindowSettingsHandler_ReadOpen; + ini_handler.ReadLineFn = WindowSettingsHandler_ReadLine; + ini_handler.ApplyAllFn = WindowSettingsHandler_ApplyAll; + ini_handler.WriteAllFn = WindowSettingsHandler_WriteAll; + g.SettingsHandlers.push_back(ini_handler); + } + +#ifdef IMGUI_HAS_TABLE + // Add .ini handle for ImGuiTable type + { + ImGuiSettingsHandler ini_handler; + ini_handler.TypeName = "Table"; + ini_handler.TypeHash = ImHashStr("Table"); + ini_handler.ReadOpenFn = TableSettingsHandler_ReadOpen; + ini_handler.ReadLineFn = TableSettingsHandler_ReadLine; + ini_handler.WriteAllFn = TableSettingsHandler_WriteAll; + g.SettingsHandlers.push_back(ini_handler); + } +#endif // #ifdef IMGUI_HAS_TABLE + +#ifdef IMGUI_HAS_DOCK + // Create default viewport + ImGuiViewportP* viewport = IM_NEW(ImGuiViewportP)(); + viewport->ID = IMGUI_VIEWPORT_DEFAULT_ID; + viewport->Idx = 0; + viewport->PlatformWindowCreated = true; + g.Viewports.push_back(viewport); + g.PlatformIO.MainViewport = g.Viewports[0]; // Make it accessible in public-facing GetPlatformIO() immediately (before the first call to EndFrame) + g.PlatformIO.Viewports.push_back(g.Viewports[0]); + + // Extensions + DockContextInitialize(&g); +#endif // #ifdef IMGUI_HAS_DOCK + + g.Initialized = true; +} + +// This function is merely here to free heap allocations. +void ImGui::Shutdown(ImGuiContext* context) +{ + // The fonts atlas can be used prior to calling NewFrame(), so we clear it even if g.Initialized is FALSE (which would happen if we never called NewFrame) + ImGuiContext& g = *context; + if (g.IO.Fonts && g.FontAtlasOwnedByContext) + { + g.IO.Fonts->Locked = false; + IM_DELETE(g.IO.Fonts); + } + g.IO.Fonts = NULL; + + // Cleanup of other data are conditional on actually having initialized Dear ImGui. + if (!g.Initialized) + return; + + // Save settings (unless we haven't attempted to load them: CreateContext/DestroyContext without a call to NewFrame shouldn't save an empty file) + if (g.SettingsLoaded && g.IO.IniFilename != NULL) + { + ImGuiContext* backup_context = GImGui; + SetCurrentContext(context); + SaveIniSettingsToDisk(g.IO.IniFilename); + SetCurrentContext(backup_context); + } + + // Destroy platform windows + ImGuiContext* backup_context = ImGui::GetCurrentContext(); + SetCurrentContext(context); + DestroyPlatformWindows(); + SetCurrentContext(backup_context); + + // Shutdown extensions + DockContextShutdown(&g); + + // Clear everything else + for (int i = 0; i < g.Windows.Size; i++) + IM_DELETE(g.Windows[i]); + g.Windows.clear(); + g.WindowsFocusOrder.clear(); + g.WindowsTempSortBuffer.clear(); + g.CurrentWindow = NULL; + g.CurrentWindowStack.clear(); + g.WindowsById.Clear(); + g.NavWindow = NULL; + g.HoveredWindow = g.HoveredRootWindow = g.HoveredWindowUnderMovingWindow = NULL; + g.ActiveIdWindow = g.ActiveIdPreviousFrameWindow = NULL; + g.MovingWindow = NULL; + g.ColorModifiers.clear(); + g.StyleModifiers.clear(); + g.FontStack.clear(); + g.OpenPopupStack.clear(); + g.BeginPopupStack.clear(); + + g.CurrentViewport = g.MouseViewport = g.MouseLastHoveredViewport = NULL; + for (int i = 0; i < g.Viewports.Size; i++) + IM_DELETE(g.Viewports[i]); + g.Viewports.clear(); + + g.TabBars.Clear(); + g.CurrentTabBarStack.clear(); + g.ShrinkWidthBuffer.clear(); + + g.ClipboardHandlerData.clear(); + g.MenusIdSubmittedThisFrame.clear(); + g.InputTextState.ClearFreeMemory(); + + g.SettingsWindows.clear(); + g.SettingsHandlers.clear(); + + if (g.LogFile) + { +#ifndef IMGUI_DISABLE_TTY_FUNCTIONS + if (g.LogFile != stdout) +#endif + ImFileClose(g.LogFile); + g.LogFile = NULL; + } + g.LogBuffer.clear(); + + g.Initialized = false; +} + +// FIXME: Add a more explicit sort order in the window structure. +static int IMGUI_CDECL ChildWindowComparer(const void* lhs, const void* rhs) +{ + const ImGuiWindow* const a = *(const ImGuiWindow* const *)lhs; + const ImGuiWindow* const b = *(const ImGuiWindow* const *)rhs; + if (int d = (a->Flags & ImGuiWindowFlags_Popup) - (b->Flags & ImGuiWindowFlags_Popup)) + return d; + if (int d = (a->Flags & ImGuiWindowFlags_Tooltip) - (b->Flags & ImGuiWindowFlags_Tooltip)) + return d; + return (a->BeginOrderWithinParent - b->BeginOrderWithinParent); +} + +static void AddWindowToSortBuffer(ImVector* out_sorted_windows, ImGuiWindow* window) +{ + out_sorted_windows->push_back(window); + if (window->Active) + { + int count = window->DC.ChildWindows.Size; + if (count > 1) + ImQsort(window->DC.ChildWindows.Data, (size_t)count, sizeof(ImGuiWindow*), ChildWindowComparer); + for (int i = 0; i < count; i++) + { + ImGuiWindow* child = window->DC.ChildWindows[i]; + if (child->Active) + AddWindowToSortBuffer(out_sorted_windows, child); + } + } +} + +static void AddDrawListToDrawData(ImVector* out_list, ImDrawList* draw_list) +{ + if (draw_list->CmdBuffer.empty()) + return; + + // Remove trailing command if unused + ImDrawCmd& last_cmd = draw_list->CmdBuffer.back(); + if (last_cmd.ElemCount == 0 && last_cmd.UserCallback == NULL) + { + draw_list->CmdBuffer.pop_back(); + if (draw_list->CmdBuffer.empty()) + return; + } + + // Draw list sanity check. Detect mismatch between PrimReserve() calls and incrementing _VtxCurrentIdx, _VtxWritePtr etc. + // May trigger for you if you are using PrimXXX functions incorrectly. + IM_ASSERT(draw_list->VtxBuffer.Size == 0 || draw_list->_VtxWritePtr == draw_list->VtxBuffer.Data + draw_list->VtxBuffer.Size); + IM_ASSERT(draw_list->IdxBuffer.Size == 0 || draw_list->_IdxWritePtr == draw_list->IdxBuffer.Data + draw_list->IdxBuffer.Size); + if (!(draw_list->Flags & ImDrawListFlags_AllowVtxOffset)) + IM_ASSERT((int)draw_list->_VtxCurrentIdx == draw_list->VtxBuffer.Size); + + // Check that draw_list doesn't use more vertices than indexable (default ImDrawIdx = unsigned short = 2 bytes = 64K vertices per ImDrawList = per window) + // If this assert triggers because you are drawing lots of stuff manually: + // - First, make sure you are coarse clipping yourself and not trying to draw many things outside visible bounds. + // Be mindful that the ImDrawList API doesn't filter vertices. Use the Metrics window to inspect draw list contents. + // - If you want large meshes with more than 64K vertices, you can either: + // (A) Handle the ImDrawCmd::VtxOffset value in your renderer back-end, and set 'io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset'. + // Most example back-ends already support this from 1.71. Pre-1.71 back-ends won't. + // Some graphics API such as GL ES 1/2 don't have a way to offset the starting vertex so it is not supported for them. + // (B) Or handle 32-bit indices in your renderer back-end, and uncomment '#define ImDrawIdx unsigned int' line in imconfig.h. + // Most example back-ends already support this. For example, the OpenGL example code detect index size at compile-time: + // glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer_offset); + // Your own engine or render API may use different parameters or function calls to specify index sizes. + // 2 and 4 bytes indices are generally supported by most graphics API. + // - If for some reason neither of those solutions works for you, a workaround is to call BeginChild()/EndChild() before reaching + // the 64K limit to split your draw commands in multiple draw lists. + if (sizeof(ImDrawIdx) == 2) + IM_ASSERT(draw_list->_VtxCurrentIdx < (1 << 16) && "Too many vertices in ImDrawList using 16-bit indices. Read comment above"); + + out_list->push_back(draw_list); +} + +static void AddWindowToDrawData(ImGuiWindow* window, int layer) +{ + ImGuiContext& g = *GImGui; + g.IO.MetricsRenderWindows++; + AddDrawListToDrawData(&window->Viewport->DrawDataBuilder.Layers[layer], window->DrawList); + for (int i = 0; i < window->DC.ChildWindows.Size; i++) + { + ImGuiWindow* child = window->DC.ChildWindows[i]; + if (IsWindowActiveAndVisible(child)) // Clipped children may have been marked not active + AddWindowToDrawData(child, layer); + } +} + +// Layer is locked for the root window, however child windows may use a different viewport (e.g. extruding menu) +static void AddRootWindowToDrawData(ImGuiWindow* window) +{ + int layer = (window->Flags & ImGuiWindowFlags_Tooltip) ? 1 : 0; + AddWindowToDrawData(window, layer); +} + +void ImDrawDataBuilder::FlattenIntoSingleLayer() +{ + int n = Layers[0].Size; + int size = n; + for (int i = 1; i < IM_ARRAYSIZE(Layers); i++) + size += Layers[i].Size; + Layers[0].resize(size); + for (int layer_n = 1; layer_n < IM_ARRAYSIZE(Layers); layer_n++) + { + ImVector& layer = Layers[layer_n]; + if (layer.empty()) + continue; + memcpy(&Layers[0][n], &layer[0], layer.Size * sizeof(ImDrawList*)); + n += layer.Size; + layer.resize(0); + } +} + +static void SetupViewportDrawData(ImGuiViewportP* viewport, ImVector* draw_lists) +{ + ImDrawData* draw_data = &viewport->DrawDataP; + viewport->DrawData = draw_data; // Make publicly accessible + draw_data->Valid = true; + draw_data->CmdLists = (draw_lists->Size > 0) ? draw_lists->Data : NULL; + draw_data->CmdListsCount = draw_lists->Size; + draw_data->TotalVtxCount = draw_data->TotalIdxCount = 0; + draw_data->DisplayPos = viewport->Pos; + draw_data->DisplaySize = viewport->Size; + draw_data->FramebufferScale = ImGui::GetIO().DisplayFramebufferScale; // FIXME-VIEWPORT: This may vary on a per-monitor/viewport basis? + draw_data->OwnerViewport = viewport; + for (int n = 0; n < draw_lists->Size; n++) + { + draw_data->TotalVtxCount += draw_lists->Data[n]->VtxBuffer.Size; + draw_data->TotalIdxCount += draw_lists->Data[n]->IdxBuffer.Size; + } +} + +// When using this function it is sane to ensure that float are perfectly rounded to integer values, to that e.g. (int)(max.x-min.x) in user's render produce correct result. +void ImGui::PushClipRect(const ImVec2& clip_rect_min, const ImVec2& clip_rect_max, bool intersect_with_current_clip_rect) +{ + ImGuiWindow* window = GetCurrentWindow(); + window->DrawList->PushClipRect(clip_rect_min, clip_rect_max, intersect_with_current_clip_rect); + window->ClipRect = window->DrawList->_ClipRectStack.back(); +} + +void ImGui::PopClipRect() +{ + ImGuiWindow* window = GetCurrentWindow(); + window->DrawList->PopClipRect(); + window->ClipRect = window->DrawList->_ClipRectStack.back(); +} + +static ImGuiWindow* FindFrontMostVisibleChildWindow(ImGuiWindow* window) +{ + for (int n = window->DC.ChildWindows.Size - 1; n >= 0; n--) + if (IsWindowActiveAndVisible(window->DC.ChildWindows[n])) + return FindFrontMostVisibleChildWindow(window->DC.ChildWindows[n]); + return window; +} + +static void ImGui::EndFrameDrawDimmedBackgrounds() +{ + ImGuiContext& g = *GImGui; + + // Draw modal whitening background on _other_ viewports than the one the modal is one + ImGuiWindow* modal_window = GetTopMostPopupModal(); + const bool dim_bg_for_modal = (modal_window != NULL); + const bool dim_bg_for_window_list = (g.NavWindowingTargetAnim != NULL); + if (dim_bg_for_modal || dim_bg_for_window_list) + for (int viewport_n = 0; viewport_n < g.Viewports.Size; viewport_n++) + { + ImGuiViewportP* viewport = g.Viewports[viewport_n]; + if (modal_window && viewport == modal_window->Viewport) + continue; + if (g.NavWindowingListWindow && viewport == g.NavWindowingListWindow->Viewport) + continue; + if (g.NavWindowingTargetAnim && viewport == g.NavWindowingTargetAnim->Viewport) + continue; + ImDrawList* draw_list = GetForegroundDrawList(viewport); + const ImU32 dim_bg_col = GetColorU32(dim_bg_for_modal ? ImGuiCol_ModalWindowDimBg : ImGuiCol_NavWindowingDimBg, g.DimBgRatio); + draw_list->AddRectFilled(viewport->Pos, viewport->Pos + viewport->Size, dim_bg_col); + } + + // Draw modal whitening background between CTRL-TAB list + if (dim_bg_for_window_list) + { + // Choose a draw list that will be front-most across all our children + ImGuiWindow* window = g.NavWindowingTargetAnim; + ImDrawList* draw_list = FindFrontMostVisibleChildWindow(window->RootWindow)->DrawList; + draw_list->PushClipRectFullScreen(); + + // Docking: draw modal whitening background on other nodes of a same dock tree + if (window->RootWindowDockStop->DockIsActive) + if (window->RootWindow != window->RootWindowDockStop) + RenderRectFilledWithHole(draw_list, window->RootWindow->Rect(), window->RootWindowDockStop->Rect(), GetColorU32(ImGuiCol_NavWindowingDimBg, g.DimBgRatio), g.Style.WindowRounding); + + // Draw navigation selection/windowing rectangle border + float rounding = ImMax(window->WindowRounding, g.Style.WindowRounding); + ImRect bb = window->Rect(); + bb.Expand(g.FontSize); + if (bb.Contains(window->Viewport->GetMainRect())) // If a window fits the entire viewport, adjust its highlight inward + { + bb.Expand(-g.FontSize - 1.0f); + rounding = window->WindowRounding; + } + draw_list->AddRect(bb.Min, bb.Max, GetColorU32(ImGuiCol_NavWindowingHighlight, g.NavWindowingHighlightAlpha), rounding, ~0, 3.0f); + draw_list->PopClipRect(); + } +} + +// This is normally called by Render(). You may want to call it directly if you want to avoid calling Render() but the gain will be very minimal. +void ImGui::EndFrame() +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(g.Initialized); + + // Don't process EndFrame() multiple times. + if (g.FrameCountEnded == g.FrameCount) + return; + IM_ASSERT(g.WithinFrameScope && "Forgot to call ImGui::NewFrame()?"); + + ErrorCheckEndFrameSanityChecks(); + + // Notify OS when our Input Method Editor cursor has moved (e.g. CJK inputs using Microsoft IME) + if (g.PlatformIO.Platform_SetImeInputPos && (g.PlatformImeLastPos.x == FLT_MAX || ImLengthSqr(g.PlatformImePos - g.PlatformImeLastPos) > 0.0001f)) + if (g.PlatformImePosViewport && g.PlatformImePosViewport->PlatformWindowCreated) + { + g.PlatformIO.Platform_SetImeInputPos(g.PlatformImePosViewport, g.PlatformImePos); + g.PlatformImeLastPos = g.PlatformImePos; + g.PlatformImePosViewport = NULL; + } + + // Hide implicit/fallback "Debug" window if it hasn't been used + g.WithinFrameScopeWithImplicitWindow = false; + if (g.CurrentWindow && !g.CurrentWindow->WriteAccessed) + g.CurrentWindow->Active = false; + End(); + + // Draw modal whitening background on _other_ viewports than the one the modal is one + EndFrameDrawDimmedBackgrounds(); + + // Update navigation: CTRL+Tab, wrap-around requests + NavEndFrame(); + + SetCurrentViewport(NULL, NULL); + + // Drag and Drop: Elapse payload (if delivered, or if source stops being submitted) + if (g.DragDropActive) + { + bool is_delivered = g.DragDropPayload.Delivery; + bool is_elapsed = (g.DragDropPayload.DataFrameCount + 1 < g.FrameCount) && ((g.DragDropSourceFlags & ImGuiDragDropFlags_SourceAutoExpirePayload) || !IsMouseDown(g.DragDropMouseButton)); + if (is_delivered || is_elapsed) + ClearDragDrop(); + } + + // Drag and Drop: Fallback for source tooltip. This is not ideal but better than nothing. + if (g.DragDropActive && g.DragDropSourceFrameCount < g.FrameCount && !(g.DragDropSourceFlags & ImGuiDragDropFlags_SourceNoPreviewTooltip)) + { + g.DragDropWithinSource = true; + SetTooltip("..."); + g.DragDropWithinSource = false; + } + + // End frame + g.WithinFrameScope = false; + g.FrameCountEnded = g.FrameCount; + + // Initiate moving window + handle left-click and right-click focus + UpdateMouseMovingWindowEndFrame(); + + // Update user-facing viewport list (g.Viewports -> g.PlatformIO.Viewports after filtering out some) + UpdateViewportsEndFrame(); + + // Sort the window list so that all child windows are after their parent + // We cannot do that on FocusWindow() because children may not exist yet + g.WindowsTempSortBuffer.resize(0); + g.WindowsTempSortBuffer.reserve(g.Windows.Size); + for (int i = 0; i != g.Windows.Size; i++) + { + ImGuiWindow* window = g.Windows[i]; + if (window->Active && (window->Flags & ImGuiWindowFlags_ChildWindow)) // if a child is active its parent will add it + continue; + AddWindowToSortBuffer(&g.WindowsTempSortBuffer, window); + } + + // This usually assert if there is a mismatch between the ImGuiWindowFlags_ChildWindow / ParentWindow values and DC.ChildWindows[] in parents, aka we've done something wrong. + IM_ASSERT(g.Windows.Size == g.WindowsTempSortBuffer.Size); + g.Windows.swap(g.WindowsTempSortBuffer); + g.IO.MetricsActiveWindows = g.WindowsActiveCount; + + // Unlock font atlas + g.IO.Fonts->Locked = false; + + // Clear Input data for next frame + g.IO.MouseWheel = g.IO.MouseWheelH = 0.0f; + g.IO.InputQueueCharacters.resize(0); + memset(g.IO.NavInputs, 0, sizeof(g.IO.NavInputs)); +} + +void ImGui::Render() +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(g.Initialized); + + if (g.FrameCountEnded != g.FrameCount) + EndFrame(); + g.FrameCountRendered = g.FrameCount; + g.IO.MetricsRenderWindows = 0; + + // Add background ImDrawList (for each active viewport) + for (int n = 0; n != g.Viewports.Size; n++) + { + ImGuiViewportP* viewport = g.Viewports[n]; + viewport->DrawDataBuilder.Clear(); + if (viewport->DrawLists[0] != NULL) + AddDrawListToDrawData(&viewport->DrawDataBuilder.Layers[0], GetBackgroundDrawList(viewport)); + } + + // Add ImDrawList to render + ImGuiWindow* windows_to_render_top_most[2]; + windows_to_render_top_most[0] = (g.NavWindowingTarget && !(g.NavWindowingTarget->Flags & ImGuiWindowFlags_NoBringToFrontOnFocus)) ? g.NavWindowingTarget->RootWindow : NULL; + windows_to_render_top_most[1] = (g.NavWindowingTarget ? g.NavWindowingListWindow : NULL); + for (int n = 0; n != g.Windows.Size; n++) + { + ImGuiWindow* window = g.Windows[n]; + if (IsWindowActiveAndVisible(window) && (window->Flags & ImGuiWindowFlags_ChildWindow) == 0 && window != windows_to_render_top_most[0] && window != windows_to_render_top_most[1]) + AddRootWindowToDrawData(window); + } + for (int n = 0; n < IM_ARRAYSIZE(windows_to_render_top_most); n++) + if (windows_to_render_top_most[n] && IsWindowActiveAndVisible(windows_to_render_top_most[n])) // NavWindowingTarget is always temporarily displayed as the top-most window + AddRootWindowToDrawData(windows_to_render_top_most[n]); + + ImVec2 mouse_cursor_offset, mouse_cursor_size, mouse_cursor_uv[4]; + if (g.IO.MouseDrawCursor && g.MouseCursor != ImGuiMouseCursor_None) + g.IO.Fonts->GetMouseCursorTexData(g.MouseCursor, &mouse_cursor_offset, &mouse_cursor_size, &mouse_cursor_uv[0], &mouse_cursor_uv[2]); + + // Setup ImDrawData structures for end-user + g.IO.MetricsRenderVertices = g.IO.MetricsRenderIndices = 0; + for (int n = 0; n < g.Viewports.Size; n++) + { + ImGuiViewportP* viewport = g.Viewports[n]; + viewport->DrawDataBuilder.FlattenIntoSingleLayer(); + + // Draw software mouse cursor if requested by io.MouseDrawCursor flag + // (note we scale cursor by current viewport/monitor, however Windows 10 for its own hardware cursor seems to be using a different scale factor) + if (mouse_cursor_size.x > 0.0f && mouse_cursor_size.y > 0.0f) + { + float scale = g.Style.MouseCursorScale * viewport->DpiScale; + if (viewport->GetMainRect().Overlaps(ImRect(g.IO.MousePos, g.IO.MousePos + ImVec2(mouse_cursor_size.x + 2, mouse_cursor_size.y + 2) * scale))) + RenderMouseCursor(GetForegroundDrawList(viewport), g.IO.MousePos, scale, g.MouseCursor, IM_COL32_WHITE, IM_COL32_BLACK, IM_COL32(0, 0, 0, 48)); + } + + // Add foreground ImDrawList (for each active viewport) + if (viewport->DrawLists[1] != NULL) + AddDrawListToDrawData(&viewport->DrawDataBuilder.Layers[0], GetForegroundDrawList(viewport)); + + SetupViewportDrawData(viewport, &viewport->DrawDataBuilder.Layers[0]); + g.IO.MetricsRenderVertices += viewport->DrawData->TotalVtxCount; + g.IO.MetricsRenderIndices += viewport->DrawData->TotalIdxCount; + } + + // (Legacy) Call the Render callback function. The current prefer way is to let the user retrieve GetDrawData() and call the render function themselves. +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + if (g.Viewports[0]->DrawData->CmdListsCount > 0 && g.IO.RenderDrawListsFn != NULL) + g.IO.RenderDrawListsFn(g.Viewports[0]->DrawData); +#endif +} + +// Calculate text size. Text can be multi-line. Optionally ignore text after a ## marker. +// CalcTextSize("") should return ImVec2(0.0f, g.FontSize) +ImVec2 ImGui::CalcTextSize(const char* text, const char* text_end, bool hide_text_after_double_hash, float wrap_width) +{ + ImGuiContext& g = *GImGui; + + const char* text_display_end; + if (hide_text_after_double_hash) + text_display_end = FindRenderedTextEnd(text, text_end); // Hide anything after a '##' string + else + text_display_end = text_end; + + ImFont* font = g.Font; + const float font_size = g.FontSize; + if (text == text_display_end) + return ImVec2(0.0f, font_size); + ImVec2 text_size = font->CalcTextSizeA(font_size, FLT_MAX, wrap_width, text, text_display_end, NULL); + + // Round + text_size.x = IM_FLOOR(text_size.x + 0.95f); + + return text_size; +} + +// Find window given position, search front-to-back +// FIXME: Note that we have an inconsequential lag here: OuterRectClipped is updated in Begin(), so windows moved programmatically +// with SetWindowPos() and not SetNextWindowPos() will have that rectangle lagging by a frame at the time FindHoveredWindow() is +// called, aka before the next Begin(). Moving window isn't affected. +static void FindHoveredWindow() +{ + ImGuiContext& g = *GImGui; + + // Special handling for the window being moved: Ignore the mouse viewport check (because it may reset/lose its viewport during the undocking frame) + ImGuiViewportP* moving_window_viewport = g.MovingWindow ? g.MovingWindow->Viewport : NULL; + if (g.MovingWindow) + g.MovingWindow->Viewport = g.MouseViewport; + + ImGuiWindow* hovered_window = NULL; + ImGuiWindow* hovered_window_ignoring_moving_window = NULL; + if (g.MovingWindow && !(g.MovingWindow->Flags & ImGuiWindowFlags_NoMouseInputs)) + hovered_window = g.MovingWindow; + + ImVec2 padding_regular = g.Style.TouchExtraPadding; + ImVec2 padding_for_resize_from_edges = g.IO.ConfigWindowsResizeFromEdges ? ImMax(g.Style.TouchExtraPadding, ImVec2(WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS, WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS)) : padding_regular; + for (int i = g.Windows.Size - 1; i >= 0; i--) + { + ImGuiWindow* window = g.Windows[i]; + if (!window->Active || window->Hidden) + continue; + if (window->Flags & ImGuiWindowFlags_NoMouseInputs) + continue; + IM_ASSERT(window->Viewport); + if (window->Viewport != g.MouseViewport) + continue; + + // Using the clipped AABB, a child window will typically be clipped by its parent (not always) + ImRect bb(window->OuterRectClipped); + if (window->Flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize)) + bb.Expand(padding_regular); + else + bb.Expand(padding_for_resize_from_edges); + if (!bb.Contains(g.IO.MousePos)) + continue; + + if (window->HitTestHoleSize.x != 0) + { + // FIXME: Consider generalizing hit-testing override (with more generic data, callback, etc.) (#1512) + ImRect hole_bb((float)(window->HitTestHoleOffset.x), (float)(window->HitTestHoleOffset.y), + (float)(window->HitTestHoleOffset.x + window->HitTestHoleSize.x), (float)(window->HitTestHoleOffset.y + window->HitTestHoleSize.y)); + if (hole_bb.Contains(g.IO.MousePos - window->Pos)) + continue; + } + + if (hovered_window == NULL) + hovered_window = window; + if (hovered_window_ignoring_moving_window == NULL && (!g.MovingWindow || window->RootWindow != g.MovingWindow->RootWindow)) + hovered_window_ignoring_moving_window = window; + if (hovered_window && hovered_window_ignoring_moving_window) + break; + } + + g.HoveredWindow = hovered_window; + g.HoveredRootWindow = g.HoveredWindow ? g.HoveredWindow->RootWindow : NULL; + g.HoveredWindowUnderMovingWindow = hovered_window_ignoring_moving_window; + + if (g.MovingWindow) + g.MovingWindow->Viewport = moving_window_viewport; +} + +// Test if mouse cursor is hovering given rectangle +// NB- Rectangle is clipped by our current clip setting +// NB- Expand the rectangle to be generous on imprecise inputs systems (g.Style.TouchExtraPadding) +bool ImGui::IsMouseHoveringRect(const ImVec2& r_min, const ImVec2& r_max, bool clip) +{ + ImGuiContext& g = *GImGui; + + // Clip + ImRect rect_clipped(r_min, r_max); + if (clip) + rect_clipped.ClipWith(g.CurrentWindow->ClipRect); + + // Expand for touch input + const ImRect rect_for_touch(rect_clipped.Min - g.Style.TouchExtraPadding, rect_clipped.Max + g.Style.TouchExtraPadding); + if (!rect_for_touch.Contains(g.IO.MousePos)) + return false; + if (!g.MouseViewport->GetMainRect().Overlaps(rect_clipped)) + return false; + return true; +} + +int ImGui::GetKeyIndex(ImGuiKey imgui_key) +{ + IM_ASSERT(imgui_key >= 0 && imgui_key < ImGuiKey_COUNT); + ImGuiContext& g = *GImGui; + return g.IO.KeyMap[imgui_key]; +} + +// Note that dear imgui doesn't know the semantic of each entry of io.KeysDown[]! +// Use your own indices/enums according to how your back-end/engine stored them into io.KeysDown[]! +bool ImGui::IsKeyDown(int user_key_index) +{ + if (user_key_index < 0) + return false; + ImGuiContext& g = *GImGui; + IM_ASSERT(user_key_index >= 0 && user_key_index < IM_ARRAYSIZE(g.IO.KeysDown)); + return g.IO.KeysDown[user_key_index]; +} + +// t0 = previous time (e.g.: g.Time - g.IO.DeltaTime) +// t1 = current time (e.g.: g.Time) +// An event is triggered at: +// t = 0.0f t = repeat_delay, t = repeat_delay + repeat_rate*N +int ImGui::CalcTypematicRepeatAmount(float t0, float t1, float repeat_delay, float repeat_rate) +{ + if (t1 == 0.0f) + return 1; + if (t0 >= t1) + return 0; + if (repeat_rate <= 0.0f) + return (t0 < repeat_delay) && (t1 >= repeat_delay); + const int count_t0 = (t0 < repeat_delay) ? -1 : (int)((t0 - repeat_delay) / repeat_rate); + const int count_t1 = (t1 < repeat_delay) ? -1 : (int)((t1 - repeat_delay) / repeat_rate); + const int count = count_t1 - count_t0; + return count; +} + +int ImGui::GetKeyPressedAmount(int key_index, float repeat_delay, float repeat_rate) +{ + ImGuiContext& g = *GImGui; + if (key_index < 0) + return 0; + IM_ASSERT(key_index >= 0 && key_index < IM_ARRAYSIZE(g.IO.KeysDown)); + const float t = g.IO.KeysDownDuration[key_index]; + return CalcTypematicRepeatAmount(t - g.IO.DeltaTime, t, repeat_delay, repeat_rate); +} + +bool ImGui::IsKeyPressed(int user_key_index, bool repeat) +{ + ImGuiContext& g = *GImGui; + if (user_key_index < 0) + return false; + IM_ASSERT(user_key_index >= 0 && user_key_index < IM_ARRAYSIZE(g.IO.KeysDown)); + const float t = g.IO.KeysDownDuration[user_key_index]; + if (t == 0.0f) + return true; + if (repeat && t > g.IO.KeyRepeatDelay) + return GetKeyPressedAmount(user_key_index, g.IO.KeyRepeatDelay, g.IO.KeyRepeatRate) > 0; + return false; +} + +bool ImGui::IsKeyReleased(int user_key_index) +{ + ImGuiContext& g = *GImGui; + if (user_key_index < 0) return false; + IM_ASSERT(user_key_index >= 0 && user_key_index < IM_ARRAYSIZE(g.IO.KeysDown)); + return g.IO.KeysDownDurationPrev[user_key_index] >= 0.0f && !g.IO.KeysDown[user_key_index]; +} + +bool ImGui::IsMouseDown(ImGuiMouseButton button) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); + return g.IO.MouseDown[button]; +} + +bool ImGui::IsMouseClicked(ImGuiMouseButton button, bool repeat) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); + const float t = g.IO.MouseDownDuration[button]; + if (t == 0.0f) + return true; + + if (repeat && t > g.IO.KeyRepeatDelay) + { + // FIXME: 2019/05/03: Our old repeat code was wrong here and led to doubling the repeat rate, which made it an ok rate for repeat on mouse hold. + int amount = CalcTypematicRepeatAmount(t - g.IO.DeltaTime, t, g.IO.KeyRepeatDelay, g.IO.KeyRepeatRate * 0.50f); + if (amount > 0) + return true; + } + return false; +} + +bool ImGui::IsMouseReleased(ImGuiMouseButton button) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); + return g.IO.MouseReleased[button]; +} + +bool ImGui::IsMouseDoubleClicked(ImGuiMouseButton button) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); + return g.IO.MouseDoubleClicked[button]; +} + +// [Internal] This doesn't test if the button is pressed +bool ImGui::IsMouseDragPastThreshold(ImGuiMouseButton button, float lock_threshold) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); + if (lock_threshold < 0.0f) + lock_threshold = g.IO.MouseDragThreshold; + return g.IO.MouseDragMaxDistanceSqr[button] >= lock_threshold * lock_threshold; +} + +bool ImGui::IsMouseDragging(ImGuiMouseButton button, float lock_threshold) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); + if (!g.IO.MouseDown[button]) + return false; + return IsMouseDragPastThreshold(button, lock_threshold); +} + +ImVec2 ImGui::GetMousePos() +{ + ImGuiContext& g = *GImGui; + return g.IO.MousePos; +} + +// NB: prefer to call right after BeginPopup(). At the time Selectable/MenuItem is activated, the popup is already closed! +ImVec2 ImGui::GetMousePosOnOpeningCurrentPopup() +{ + ImGuiContext& g = *GImGui; + if (g.BeginPopupStack.Size > 0) + return g.OpenPopupStack[g.BeginPopupStack.Size-1].OpenMousePos; + return g.IO.MousePos; +} + +// We typically use ImVec2(-FLT_MAX,-FLT_MAX) to denote an invalid mouse position. +bool ImGui::IsMousePosValid(const ImVec2* mouse_pos) +{ + // The assert is only to silence a false-positive in XCode Static Analysis. + // Because GImGui is not dereferenced in every code path, the static analyzer assume that it may be NULL (which it doesn't for other functions). + IM_ASSERT(GImGui != NULL); + const float MOUSE_INVALID = -256000.0f; + ImVec2 p = mouse_pos ? *mouse_pos : GImGui->IO.MousePos; + return p.x >= MOUSE_INVALID && p.y >= MOUSE_INVALID; +} + +bool ImGui::IsAnyMouseDown() +{ + ImGuiContext& g = *GImGui; + for (int n = 0; n < IM_ARRAYSIZE(g.IO.MouseDown); n++) + if (g.IO.MouseDown[n]) + return true; + return false; +} + +// Return the delta from the initial clicking position while the mouse button is clicked or was just released. +// This is locked and return 0.0f until the mouse moves past a distance threshold at least once. +// NB: This is only valid if IsMousePosValid(). Back-ends in theory should always keep mouse position valid when dragging even outside the client window. +ImVec2 ImGui::GetMouseDragDelta(ImGuiMouseButton button, float lock_threshold) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); + if (lock_threshold < 0.0f) + lock_threshold = g.IO.MouseDragThreshold; + if (g.IO.MouseDown[button] || g.IO.MouseReleased[button]) + if (g.IO.MouseDragMaxDistanceSqr[button] >= lock_threshold * lock_threshold) + if (IsMousePosValid(&g.IO.MousePos) && IsMousePosValid(&g.IO.MouseClickedPos[button])) + return g.IO.MousePos - g.IO.MouseClickedPos[button]; + return ImVec2(0.0f, 0.0f); +} + +void ImGui::ResetMouseDragDelta(ImGuiMouseButton button) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); + // NB: We don't need to reset g.IO.MouseDragMaxDistanceSqr + g.IO.MouseClickedPos[button] = g.IO.MousePos; +} + +ImGuiMouseCursor ImGui::GetMouseCursor() +{ + return GImGui->MouseCursor; +} + +void ImGui::SetMouseCursor(ImGuiMouseCursor cursor_type) +{ + GImGui->MouseCursor = cursor_type; +} + +void ImGui::CaptureKeyboardFromApp(bool capture) +{ + GImGui->WantCaptureKeyboardNextFrame = capture ? 1 : 0; +} + +void ImGui::CaptureMouseFromApp(bool capture) +{ + GImGui->WantCaptureMouseNextFrame = capture ? 1 : 0; +} + +bool ImGui::IsItemActive() +{ + ImGuiContext& g = *GImGui; + if (g.ActiveId) + { + ImGuiWindow* window = g.CurrentWindow; + return g.ActiveId == window->DC.LastItemId; + } + return false; +} + +bool ImGui::IsItemActivated() +{ + ImGuiContext& g = *GImGui; + if (g.ActiveId) + { + ImGuiWindow* window = g.CurrentWindow; + if (g.ActiveId == window->DC.LastItemId && g.ActiveIdPreviousFrame != window->DC.LastItemId) + return true; + } + return false; +} + +bool ImGui::IsItemDeactivated() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if (window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_HasDeactivated) + return (window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_Deactivated) != 0; + return (g.ActiveIdPreviousFrame == window->DC.LastItemId && g.ActiveIdPreviousFrame != 0 && g.ActiveId != window->DC.LastItemId); +} + +bool ImGui::IsItemDeactivatedAfterEdit() +{ + ImGuiContext& g = *GImGui; + return IsItemDeactivated() && (g.ActiveIdPreviousFrameHasBeenEditedBefore || (g.ActiveId == 0 && g.ActiveIdHasBeenEditedBefore)); +} + +bool ImGui::IsItemFocused() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + + if (g.NavId == 0 || g.NavDisableHighlight || g.NavId != window->DC.LastItemId) + return false; + + // Special handling for the dummy item after Begin() which represent the title bar or tab. + // When the window is collapsed (SkipItems==true) that last item will never be overwritten so we need to detect the case. + if (window->DC.LastItemId == window->ID && window->WriteAccessed) + return false; + + return true; +} + +bool ImGui::IsItemClicked(ImGuiMouseButton mouse_button) +{ + return IsMouseClicked(mouse_button) && IsItemHovered(ImGuiHoveredFlags_None); +} + +bool ImGui::IsItemToggledOpen() +{ + ImGuiContext& g = *GImGui; + return (g.CurrentWindow->DC.LastItemStatusFlags & ImGuiItemStatusFlags_ToggledOpen) ? true : false; +} + +bool ImGui::IsItemToggledSelection() +{ + ImGuiContext& g = *GImGui; + return (g.CurrentWindow->DC.LastItemStatusFlags & ImGuiItemStatusFlags_ToggledSelection) ? true : false; +} + +bool ImGui::IsAnyItemHovered() +{ + ImGuiContext& g = *GImGui; + return g.HoveredId != 0 || g.HoveredIdPreviousFrame != 0; +} + +bool ImGui::IsAnyItemActive() +{ + ImGuiContext& g = *GImGui; + return g.ActiveId != 0; +} + +bool ImGui::IsAnyItemFocused() +{ + ImGuiContext& g = *GImGui; + return g.NavId != 0 && !g.NavDisableHighlight; +} + +bool ImGui::IsItemVisible() +{ + ImGuiWindow* window = GetCurrentWindowRead(); + return window->ClipRect.Overlaps(window->DC.LastItemRect); +} + +bool ImGui::IsItemEdited() +{ + ImGuiWindow* window = GetCurrentWindowRead(); + return (window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_Edited) != 0; +} + +// Allow last item to be overlapped by a subsequent item. Both may be activated during the same frame before the later one takes priority. +void ImGui::SetItemAllowOverlap() +{ + ImGuiContext& g = *GImGui; + if (g.HoveredId == g.CurrentWindow->DC.LastItemId) + g.HoveredIdAllowOverlap = true; + if (g.ActiveId == g.CurrentWindow->DC.LastItemId) + g.ActiveIdAllowOverlap = true; +} + +ImVec2 ImGui::GetItemRectMin() +{ + ImGuiWindow* window = GetCurrentWindowRead(); + return window->DC.LastItemRect.Min; +} + +ImVec2 ImGui::GetItemRectMax() +{ + ImGuiWindow* window = GetCurrentWindowRead(); + return window->DC.LastItemRect.Max; +} + +ImVec2 ImGui::GetItemRectSize() +{ + ImGuiWindow* window = GetCurrentWindowRead(); + return window->DC.LastItemRect.GetSize(); +} + +bool ImGui::BeginChildEx(const char* name, ImGuiID id, const ImVec2& size_arg, bool border, ImGuiWindowFlags flags) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* parent_window = g.CurrentWindow; + + flags |= ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoResize|ImGuiWindowFlags_NoSavedSettings|ImGuiWindowFlags_ChildWindow|ImGuiWindowFlags_NoDocking; + flags |= (parent_window->Flags & ImGuiWindowFlags_NoMove); // Inherit the NoMove flag + + // Size + const ImVec2 content_avail = GetContentRegionAvail(); + ImVec2 size = ImFloor(size_arg); + const int auto_fit_axises = ((size.x == 0.0f) ? (1 << ImGuiAxis_X) : 0x00) | ((size.y == 0.0f) ? (1 << ImGuiAxis_Y) : 0x00); + if (size.x <= 0.0f) + size.x = ImMax(content_avail.x + size.x, 4.0f); // Arbitrary minimum child size (0.0f causing too much issues) + if (size.y <= 0.0f) + size.y = ImMax(content_avail.y + size.y, 4.0f); + SetNextWindowSize(size); + + // Build up name. If you need to append to a same child from multiple location in the ID stack, use BeginChild(ImGuiID id) with a stable value. + char title[256]; + if (name) + ImFormatString(title, IM_ARRAYSIZE(title), "%s/%s_%08X", parent_window->Name, name, id); + else + ImFormatString(title, IM_ARRAYSIZE(title), "%s/%08X", parent_window->Name, id); + + const float backup_border_size = g.Style.ChildBorderSize; + if (!border) + g.Style.ChildBorderSize = 0.0f; + bool ret = Begin(title, NULL, flags); + g.Style.ChildBorderSize = backup_border_size; + + ImGuiWindow* child_window = g.CurrentWindow; + child_window->ChildId = id; + child_window->AutoFitChildAxises = (ImS8)auto_fit_axises; + + // Set the cursor to handle case where the user called SetNextWindowPos()+BeginChild() manually. + // While this is not really documented/defined, it seems that the expected thing to do. + if (child_window->BeginCount == 1) + parent_window->DC.CursorPos = child_window->Pos; + + // Process navigation-in immediately so NavInit can run on first frame + if (g.NavActivateId == id && !(flags & ImGuiWindowFlags_NavFlattened) && (child_window->DC.NavLayerActiveMask != 0 || child_window->DC.NavHasScroll)) + { + FocusWindow(child_window); + NavInitWindow(child_window, false); + SetActiveID(id+1, child_window); // Steal ActiveId with a dummy id so that key-press won't activate child item + g.ActiveIdSource = ImGuiInputSource_Nav; + } + return ret; +} + +bool ImGui::BeginChild(const char* str_id, const ImVec2& size_arg, bool border, ImGuiWindowFlags extra_flags) +{ + ImGuiWindow* window = GetCurrentWindow(); + return BeginChildEx(str_id, window->GetID(str_id), size_arg, border, extra_flags); +} + +bool ImGui::BeginChild(ImGuiID id, const ImVec2& size_arg, bool border, ImGuiWindowFlags extra_flags) +{ + IM_ASSERT(id != 0); + return BeginChildEx(NULL, id, size_arg, border, extra_flags); +} + +void ImGui::EndChild() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + + IM_ASSERT(g.WithinEndChild == false); + IM_ASSERT(window->Flags & ImGuiWindowFlags_ChildWindow); // Mismatched BeginChild()/EndChild() calls + + g.WithinEndChild = true; + if (window->BeginCount > 1) + { + End(); + } + else + { + ImVec2 sz = window->Size; + if (window->AutoFitChildAxises & (1 << ImGuiAxis_X)) // Arbitrary minimum zero-ish child size of 4.0f causes less trouble than a 0.0f + sz.x = ImMax(4.0f, sz.x); + if (window->AutoFitChildAxises & (1 << ImGuiAxis_Y)) + sz.y = ImMax(4.0f, sz.y); + End(); + + ImGuiWindow* parent_window = g.CurrentWindow; + ImRect bb(parent_window->DC.CursorPos, parent_window->DC.CursorPos + sz); + ItemSize(sz); + if ((window->DC.NavLayerActiveMask != 0 || window->DC.NavHasScroll) && !(window->Flags & ImGuiWindowFlags_NavFlattened)) + { + ItemAdd(bb, window->ChildId); + RenderNavHighlight(bb, window->ChildId); + + // When browsing a window that has no activable items (scroll only) we keep a highlight on the child + if (window->DC.NavLayerActiveMask == 0 && window == g.NavWindow) + RenderNavHighlight(ImRect(bb.Min - ImVec2(2,2), bb.Max + ImVec2(2,2)), g.NavId, ImGuiNavHighlightFlags_TypeThin); + } + else + { + // Not navigable into + ItemAdd(bb, 0); + } + } + g.WithinEndChild = false; +} + +// Helper to create a child window / scrolling region that looks like a normal widget frame. +bool ImGui::BeginChildFrame(ImGuiID id, const ImVec2& size, ImGuiWindowFlags extra_flags) +{ + ImGuiContext& g = *GImGui; + const ImGuiStyle& style = g.Style; + PushStyleColor(ImGuiCol_ChildBg, style.Colors[ImGuiCol_FrameBg]); + PushStyleVar(ImGuiStyleVar_ChildRounding, style.FrameRounding); + PushStyleVar(ImGuiStyleVar_ChildBorderSize, style.FrameBorderSize); + PushStyleVar(ImGuiStyleVar_WindowPadding, style.FramePadding); + bool ret = BeginChild(id, size, true, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysUseWindowPadding | extra_flags); + PopStyleVar(3); + PopStyleColor(); + return ret; +} + +void ImGui::EndChildFrame() +{ + EndChild(); +} + +static void SetWindowConditionAllowFlags(ImGuiWindow* window, ImGuiCond flags, bool enabled) +{ + window->SetWindowPosAllowFlags = enabled ? (window->SetWindowPosAllowFlags | flags) : (window->SetWindowPosAllowFlags & ~flags); + window->SetWindowSizeAllowFlags = enabled ? (window->SetWindowSizeAllowFlags | flags) : (window->SetWindowSizeAllowFlags & ~flags); + window->SetWindowCollapsedAllowFlags = enabled ? (window->SetWindowCollapsedAllowFlags | flags) : (window->SetWindowCollapsedAllowFlags & ~flags); + window->SetWindowDockAllowFlags = enabled ? (window->SetWindowDockAllowFlags | flags) : (window->SetWindowDockAllowFlags & ~flags); +} + +ImGuiWindow* ImGui::FindWindowByID(ImGuiID id) +{ + ImGuiContext& g = *GImGui; + return (ImGuiWindow*)g.WindowsById.GetVoidPtr(id); +} + +ImGuiWindow* ImGui::FindWindowByName(const char* name) +{ + ImGuiID id = ImHashStr(name); + return FindWindowByID(id); +} + +static void ApplyWindowSettings(ImGuiWindow* window, ImGuiWindowSettings* settings) +{ + ImGuiViewport* main_viewport = ImGui::GetMainViewport(); + window->ViewportPos = main_viewport->Pos; + if (settings->ViewportId) + { + window->ViewportId = settings->ViewportId; + window->ViewportPos = ImVec2(settings->ViewportPos.x, settings->ViewportPos.y); + } + window->Pos = ImFloor(ImVec2(settings->Pos.x + window->ViewportPos.x, settings->Pos.y + window->ViewportPos.y)); + if (settings->Size.x > 0 && settings->Size.y > 0) + window->Size = window->SizeFull = ImFloor(ImVec2(settings->Size.x, settings->Size.y)); + window->Collapsed = settings->Collapsed; + window->DockId = settings->DockId; + window->DockOrder = settings->DockOrder; +} + +static ImGuiWindow* CreateNewWindow(const char* name, ImGuiWindowFlags flags) +{ + ImGuiContext& g = *GImGui; + //IMGUI_DEBUG_LOG("CreateNewWindow '%s', flags = 0x%08X\n", name, flags); + + // Create window the first time + ImGuiWindow* window = IM_NEW(ImGuiWindow)(&g, name); + window->Flags = flags; + g.WindowsById.SetVoidPtr(window->ID, window); + + // Default/arbitrary window position. Use SetNextWindowPos() with the appropriate condition flag to change the initial position of a window. + ImGuiViewport* main_viewport = ImGui::GetMainViewport(); + window->Pos = main_viewport->Pos + ImVec2(60, 60); + window->ViewportPos = main_viewport->Pos; + + // User can disable loading and saving of settings. Tooltip and child windows also don't store settings. + if (!(flags & ImGuiWindowFlags_NoSavedSettings)) + if (ImGuiWindowSettings* settings = ImGui::FindWindowSettings(window->ID)) + { + // Retrieve settings from .ini file + window->SettingsOffset = g.SettingsWindows.offset_from_ptr(settings); + SetWindowConditionAllowFlags(window, ImGuiCond_FirstUseEver, false); + ApplyWindowSettings(window, settings); + } + window->DC.CursorStartPos = window->DC.CursorMaxPos = window->Pos; // So first call to CalcContentSize() doesn't return crazy values + + if ((flags & ImGuiWindowFlags_AlwaysAutoResize) != 0) + { + window->AutoFitFramesX = window->AutoFitFramesY = 2; + window->AutoFitOnlyGrows = false; + } + else + { + if (window->Size.x <= 0.0f) + window->AutoFitFramesX = 2; + if (window->Size.y <= 0.0f) + window->AutoFitFramesY = 2; + window->AutoFitOnlyGrows = (window->AutoFitFramesX > 0) || (window->AutoFitFramesY > 0); + } + + g.WindowsFocusOrder.push_back(window); + if (flags & ImGuiWindowFlags_NoBringToFrontOnFocus) + g.Windows.push_front(window); // Quite slow but rare and only once + else + g.Windows.push_back(window); + return window; +} + +static ImGuiWindow* GetWindowForTitleDisplay(ImGuiWindow* window) +{ + return window->DockNodeAsHost ? window->DockNodeAsHost->VisibleWindow : window; +} + +static ImGuiWindow* GetWindowForTitleAndMenuHeight(ImGuiWindow* window) +{ + return (window->DockNodeAsHost && window->DockNodeAsHost->VisibleWindow) ? window->DockNodeAsHost->VisibleWindow : window; +} + +static ImVec2 CalcWindowSizeAfterConstraint(ImGuiWindow* window, ImVec2 new_size) +{ + ImGuiContext& g = *GImGui; + if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSizeConstraint) + { + // Using -1,-1 on either X/Y axis to preserve the current size. + ImRect cr = g.NextWindowData.SizeConstraintRect; + new_size.x = (cr.Min.x >= 0 && cr.Max.x >= 0) ? ImClamp(new_size.x, cr.Min.x, cr.Max.x) : window->SizeFull.x; + new_size.y = (cr.Min.y >= 0 && cr.Max.y >= 0) ? ImClamp(new_size.y, cr.Min.y, cr.Max.y) : window->SizeFull.y; + if (g.NextWindowData.SizeCallback) + { + ImGuiSizeCallbackData data; + data.UserData = g.NextWindowData.SizeCallbackUserData; + data.Pos = window->Pos; + data.CurrentSize = window->SizeFull; + data.DesiredSize = new_size; + g.NextWindowData.SizeCallback(&data); + new_size = data.DesiredSize; + } + new_size.x = IM_FLOOR(new_size.x); + new_size.y = IM_FLOOR(new_size.y); + } + + // Minimum size + if (!(window->Flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_AlwaysAutoResize))) + { + ImGuiWindow* window_for_height = GetWindowForTitleAndMenuHeight(window); + new_size = ImMax(new_size, g.Style.WindowMinSize); + new_size.y = ImMax(new_size.y, window_for_height->TitleBarHeight() + window_for_height->MenuBarHeight() + ImMax(0.0f, g.Style.WindowRounding - 1.0f)); // Reduce artifacts with very small windows + } + return new_size; +} + +static ImVec2 CalcWindowContentSize(ImGuiWindow* window) +{ + if (window->Collapsed) + if (window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0) + return window->ContentSize; + if (window->Hidden && window->HiddenFramesCannotSkipItems == 0 && window->HiddenFramesCanSkipItems > 0) + return window->ContentSize; + + ImVec2 sz; + sz.x = IM_FLOOR((window->ContentSizeExplicit.x != 0.0f) ? window->ContentSizeExplicit.x : window->DC.CursorMaxPos.x - window->DC.CursorStartPos.x); + sz.y = IM_FLOOR((window->ContentSizeExplicit.y != 0.0f) ? window->ContentSizeExplicit.y : window->DC.CursorMaxPos.y - window->DC.CursorStartPos.y); + return sz; +} + +static ImVec2 CalcWindowAutoFitSize(ImGuiWindow* window, const ImVec2& size_contents) +{ + ImGuiContext& g = *GImGui; + ImGuiStyle& style = g.Style; + ImVec2 size_decorations = ImVec2(0.0f, window->TitleBarHeight() + window->MenuBarHeight()); + ImVec2 size_pad = window->WindowPadding * 2.0f; + ImVec2 size_desired = size_contents + size_pad + size_decorations; + if (window->Flags & ImGuiWindowFlags_Tooltip) + { + // Tooltip always resize + return size_desired; + } + else + { + // Maximum window size is determined by the viewport size or monitor size + const bool is_popup = (window->Flags & ImGuiWindowFlags_Popup) != 0; + const bool is_menu = (window->Flags & ImGuiWindowFlags_ChildMenu) != 0; + ImVec2 size_min = style.WindowMinSize; + if (is_popup || is_menu) // Popups and menus bypass style.WindowMinSize by default, but we give then a non-zero minimum size to facilitate understanding problematic cases (e.g. empty popups) + size_min = ImMin(size_min, ImVec2(4.0f, 4.0f)); + + // FIXME-VIEWPORT-WORKAREA: May want to use GetWorkSize() instead of Size depending on the type of windows? + ImVec2 avail_size = window->Viewport->Size; + if (window->ViewportOwned) + avail_size = ImVec2(FLT_MAX, FLT_MAX); + const int monitor_idx = window->ViewportAllowPlatformMonitorExtend; + if (monitor_idx >= 0 && monitor_idx < g.PlatformIO.Monitors.Size) + avail_size = g.PlatformIO.Monitors[monitor_idx].WorkSize; + ImVec2 size_auto_fit = ImClamp(size_desired, size_min, ImMax(size_min, avail_size - g.Style.DisplaySafeAreaPadding * 2.0f)); + + // When the window cannot fit all contents (either because of constraints, either because screen is too small), + // we are growing the size on the other axis to compensate for expected scrollbar. FIXME: Might turn bigger than ViewportSize-WindowPadding. + ImVec2 size_auto_fit_after_constraint = CalcWindowSizeAfterConstraint(window, size_auto_fit); + bool will_have_scrollbar_x = (size_auto_fit_after_constraint.x - size_pad.x - size_decorations.x < size_contents.x && !(window->Flags & ImGuiWindowFlags_NoScrollbar) && (window->Flags & ImGuiWindowFlags_HorizontalScrollbar)) || (window->Flags & ImGuiWindowFlags_AlwaysHorizontalScrollbar); + bool will_have_scrollbar_y = (size_auto_fit_after_constraint.y - size_pad.y - size_decorations.y < size_contents.y && !(window->Flags & ImGuiWindowFlags_NoScrollbar)) || (window->Flags & ImGuiWindowFlags_AlwaysVerticalScrollbar); + if (will_have_scrollbar_x) + size_auto_fit.y += style.ScrollbarSize; + if (will_have_scrollbar_y) + size_auto_fit.x += style.ScrollbarSize; + return size_auto_fit; + } +} + +ImVec2 ImGui::CalcWindowExpectedSize(ImGuiWindow* window) +{ + ImVec2 size_contents = CalcWindowContentSize(window); + ImVec2 size_auto_fit = CalcWindowAutoFitSize(window, size_contents); + ImVec2 size_final = CalcWindowSizeAfterConstraint(window, size_auto_fit); + return size_final; +} + +static ImGuiCol GetWindowBgColorIdxFromFlags(ImGuiWindowFlags flags) +{ + if (flags & (ImGuiWindowFlags_Tooltip | ImGuiWindowFlags_Popup)) + return ImGuiCol_PopupBg; + if (flags & ImGuiWindowFlags_ChildWindow) + return ImGuiCol_ChildBg; + return ImGuiCol_WindowBg; +} + +static void CalcResizePosSizeFromAnyCorner(ImGuiWindow* window, const ImVec2& corner_target, const ImVec2& corner_norm, ImVec2* out_pos, ImVec2* out_size) +{ + ImVec2 pos_min = ImLerp(corner_target, window->Pos, corner_norm); // Expected window upper-left + ImVec2 pos_max = ImLerp(window->Pos + window->Size, corner_target, corner_norm); // Expected window lower-right + ImVec2 size_expected = pos_max - pos_min; + ImVec2 size_constrained = CalcWindowSizeAfterConstraint(window, size_expected); + *out_pos = pos_min; + if (corner_norm.x == 0.0f) + out_pos->x -= (size_constrained.x - size_expected.x); + if (corner_norm.y == 0.0f) + out_pos->y -= (size_constrained.y - size_expected.y); + *out_size = size_constrained; +} + +struct ImGuiResizeGripDef +{ + ImVec2 CornerPosN; + ImVec2 InnerDir; + int AngleMin12, AngleMax12; +}; + +static const ImGuiResizeGripDef resize_grip_def[4] = +{ + { ImVec2(1,1), ImVec2(-1,-1), 0, 3 }, // Lower-right + { ImVec2(0,1), ImVec2(+1,-1), 3, 6 }, // Lower-left + { ImVec2(0,0), ImVec2(+1,+1), 6, 9 }, // Upper-left (Unused) + { ImVec2(1,0), ImVec2(-1,+1), 9,12 }, // Upper-right (Unused) +}; + +static ImRect GetResizeBorderRect(ImGuiWindow* window, int border_n, float perp_padding, float thickness) +{ + ImRect rect = window->Rect(); + if (thickness == 0.0f) rect.Max -= ImVec2(1,1); + if (border_n == 0) return ImRect(rect.Min.x + perp_padding, rect.Min.y - thickness, rect.Max.x - perp_padding, rect.Min.y + thickness); // Top + if (border_n == 1) return ImRect(rect.Max.x - thickness, rect.Min.y + perp_padding, rect.Max.x + thickness, rect.Max.y - perp_padding); // Right + if (border_n == 2) return ImRect(rect.Min.x + perp_padding, rect.Max.y - thickness, rect.Max.x - perp_padding, rect.Max.y + thickness); // Bottom + if (border_n == 3) return ImRect(rect.Min.x - thickness, rect.Min.y + perp_padding, rect.Min.x + thickness, rect.Max.y - perp_padding); // Left + IM_ASSERT(0); + return ImRect(); +} + +// 0..3: corners (Lower-right, Lower-left, Unused, Unused) +// 4..7: borders (Top, Right, Bottom, Left) +ImGuiID ImGui::GetWindowResizeID(ImGuiWindow* window, int n) +{ + IM_ASSERT(n >= 0 && n <= 7); + ImGuiID id = window->DockIsActive ? window->DockNode->HostWindow->ID : window->ID; + id = ImHashStr("#RESIZE", 0, id); + id = ImHashData(&n, sizeof(int), id); + return id; +} + +// Handle resize for: Resize Grips, Borders, Gamepad +// Return true when using auto-fit (double click on resize grip) +static bool ImGui::UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& size_auto_fit, int* border_held, int resize_grip_count, ImU32 resize_grip_col[4]) +{ + ImGuiContext& g = *GImGui; + ImGuiWindowFlags flags = window->Flags; + + if ((flags & ImGuiWindowFlags_NoResize) || (flags & ImGuiWindowFlags_AlwaysAutoResize) || window->AutoFitFramesX > 0 || window->AutoFitFramesY > 0) + return false; + if (window->WasActive == false) // Early out to avoid running this code for e.g. an hidden implicit/fallback Debug window. + return false; + + bool ret_auto_fit = false; + const int resize_border_count = g.IO.ConfigWindowsResizeFromEdges ? 4 : 0; + const float grip_draw_size = IM_FLOOR(ImMax(g.FontSize * 1.35f, window->WindowRounding + 1.0f + g.FontSize * 0.2f)); + const float grip_hover_inner_size = IM_FLOOR(grip_draw_size * 0.75f); + const float grip_hover_outer_size = g.IO.ConfigWindowsResizeFromEdges ? WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS : 0.0f; + + ImVec2 pos_target(FLT_MAX, FLT_MAX); + ImVec2 size_target(FLT_MAX, FLT_MAX); + + // Clip mouse interaction rectangles within the viewport rectangle (in practice the narrowing is going to happen most of the time). + // - Not narrowing would mostly benefit the situation where OS windows _without_ decoration have a threshold for hovering when outside their limits. + // This is however not the case with current back-ends under Win32, but a custom borderless window implementation would benefit from it. + // - When decoration are enabled we typically benefit from that distance, but then our resize elements would be conflicting with OS resize elements, so we also narrow. + // - Note that we are unable to tell if the platform setup allows hovering with a distance threshold (on Win32, decorated window have such threshold). + const bool clip_with_viewport_rect = !(g.IO.BackendFlags & ImGuiBackendFlags_HasMouseHoveredViewport) || (g.IO.MouseHoveredViewport != window->ViewportId) || !(window->Viewport->Flags & ImGuiViewportFlags_NoDecoration); + if (clip_with_viewport_rect) + PushClipRect(window->Viewport->Pos, window->Viewport->Pos + window->Viewport->Size, true); // Won't incur a draw command as we are not drawing here. + + // Resize grips and borders are on layer 1 + window->DC.NavLayerCurrent = ImGuiNavLayer_Menu; + window->DC.NavLayerCurrentMask = (1 << ImGuiNavLayer_Menu); + + // Manual resize grips + PushID("#RESIZE"); + for (int resize_grip_n = 0; resize_grip_n < resize_grip_count; resize_grip_n++) + { + const ImGuiResizeGripDef& grip = resize_grip_def[resize_grip_n]; + const ImVec2 corner = ImLerp(window->Pos, window->Pos + window->Size, grip.CornerPosN); + + // Using the FlattenChilds button flag we make the resize button accessible even if we are hovering over a child window + ImRect resize_rect(corner - grip.InnerDir * grip_hover_outer_size, corner + grip.InnerDir * grip_hover_inner_size); + if (resize_rect.Min.x > resize_rect.Max.x) ImSwap(resize_rect.Min.x, resize_rect.Max.x); + if (resize_rect.Min.y > resize_rect.Max.y) ImSwap(resize_rect.Min.y, resize_rect.Max.y); + bool hovered, held; + ButtonBehavior(resize_rect, window->GetID(resize_grip_n), &hovered, &held, ImGuiButtonFlags_FlattenChildren | ImGuiButtonFlags_NoNavFocus); + //GetForegroundDrawList(window)->AddRect(resize_rect.Min, resize_rect.Max, IM_COL32(255, 255, 0, 255)); + if (hovered || held) + g.MouseCursor = (resize_grip_n & 1) ? ImGuiMouseCursor_ResizeNESW : ImGuiMouseCursor_ResizeNWSE; + + if (held && g.IO.MouseDoubleClicked[0] && resize_grip_n == 0) + { + // Manual auto-fit when double-clicking + size_target = CalcWindowSizeAfterConstraint(window, size_auto_fit); + ret_auto_fit = true; + ClearActiveID(); + } + else if (held) + { + // Resize from any of the four corners + // We don't use an incremental MouseDelta but rather compute an absolute target size based on mouse position + ImVec2 corner_target = g.IO.MousePos - g.ActiveIdClickOffset + ImLerp(grip.InnerDir * grip_hover_outer_size, grip.InnerDir * -grip_hover_inner_size, grip.CornerPosN); // Corner of the window corresponding to our corner grip + CalcResizePosSizeFromAnyCorner(window, corner_target, grip.CornerPosN, &pos_target, &size_target); + } + if (resize_grip_n == 0 || held || hovered) + resize_grip_col[resize_grip_n] = GetColorU32(held ? ImGuiCol_ResizeGripActive : hovered ? ImGuiCol_ResizeGripHovered : ImGuiCol_ResizeGrip); + } + for (int border_n = 0; border_n < resize_border_count; border_n++) + { + bool hovered, held; + ImRect border_rect = GetResizeBorderRect(window, border_n, grip_hover_inner_size, WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS); + ButtonBehavior(border_rect, window->GetID(border_n + 4), &hovered, &held, ImGuiButtonFlags_FlattenChildren); + //GetForegroundDrawLists(window)->AddRect(border_rect.Min, border_rect.Max, IM_COL32(255, 255, 0, 255)); + if ((hovered && g.HoveredIdTimer > WINDOWS_RESIZE_FROM_EDGES_FEEDBACK_TIMER) || held) + { + g.MouseCursor = (border_n & 1) ? ImGuiMouseCursor_ResizeEW : ImGuiMouseCursor_ResizeNS; + if (held) + *border_held = border_n; + } + if (held) + { + ImVec2 border_target = window->Pos; + ImVec2 border_posn; + if (border_n == 0) { border_posn = ImVec2(0, 0); border_target.y = (g.IO.MousePos.y - g.ActiveIdClickOffset.y + WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS); } // Top + if (border_n == 1) { border_posn = ImVec2(1, 0); border_target.x = (g.IO.MousePos.x - g.ActiveIdClickOffset.x + WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS); } // Right + if (border_n == 2) { border_posn = ImVec2(0, 1); border_target.y = (g.IO.MousePos.y - g.ActiveIdClickOffset.y + WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS); } // Bottom + if (border_n == 3) { border_posn = ImVec2(0, 0); border_target.x = (g.IO.MousePos.x - g.ActiveIdClickOffset.x + WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS); } // Left + CalcResizePosSizeFromAnyCorner(window, border_target, border_posn, &pos_target, &size_target); + } + } + PopID(); + if (clip_with_viewport_rect) + PopClipRect(); + + // Restore nav layer + window->DC.NavLayerCurrent = ImGuiNavLayer_Main; + window->DC.NavLayerCurrentMask = (1 << ImGuiNavLayer_Main); + + // Navigation resize (keyboard/gamepad) + if (g.NavWindowingTarget && g.NavWindowingTarget->RootWindow == window) + { + ImVec2 nav_resize_delta; + if (g.NavInputSource == ImGuiInputSource_NavKeyboard && g.IO.KeyShift) + nav_resize_delta = GetNavInputAmount2d(ImGuiNavDirSourceFlags_Keyboard, ImGuiInputReadMode_Down); + if (g.NavInputSource == ImGuiInputSource_NavGamepad) + nav_resize_delta = GetNavInputAmount2d(ImGuiNavDirSourceFlags_PadDPad, ImGuiInputReadMode_Down); + if (nav_resize_delta.x != 0.0f || nav_resize_delta.y != 0.0f) + { + const float NAV_RESIZE_SPEED = 600.0f; + nav_resize_delta *= ImFloor(NAV_RESIZE_SPEED * g.IO.DeltaTime * ImMin(g.IO.DisplayFramebufferScale.x, g.IO.DisplayFramebufferScale.y)); + g.NavWindowingToggleLayer = false; + g.NavDisableMouseHover = true; + resize_grip_col[0] = GetColorU32(ImGuiCol_ResizeGripActive); + // FIXME-NAV: Should store and accumulate into a separate size buffer to handle sizing constraints properly, right now a constraint will make us stuck. + size_target = CalcWindowSizeAfterConstraint(window, window->SizeFull + nav_resize_delta); + } + } + + // Apply back modified position/size to window + if (size_target.x != FLT_MAX) + { + window->SizeFull = size_target; + MarkIniSettingsDirty(window); + } + if (pos_target.x != FLT_MAX) + { + window->Pos = ImFloor(pos_target); + MarkIniSettingsDirty(window); + } + + window->Size = window->SizeFull; + return ret_auto_fit; +} + +static inline void ClampWindowRect(ImGuiWindow* window, const ImRect& rect, const ImVec2& padding) +{ + ImGuiContext& g = *GImGui; + ImVec2 size_for_clamping = (g.IO.ConfigWindowsMoveFromTitleBarOnly && !(window->Flags & ImGuiWindowFlags_NoTitleBar)) ? ImVec2(window->Size.x, window->TitleBarHeight()) : window->Size; + window->Pos = ImMin(rect.Max - padding, ImMax(window->Pos + size_for_clamping, rect.Min + padding) - size_for_clamping); +} + +static void ImGui::RenderWindowOuterBorders(ImGuiWindow* window) +{ + ImGuiContext& g = *GImGui; + float rounding = window->WindowRounding; + float border_size = window->WindowBorderSize; + if (border_size > 0.0f && !(window->Flags & ImGuiWindowFlags_NoBackground)) + window->DrawList->AddRect(window->Pos, window->Pos + window->Size, GetColorU32(ImGuiCol_Border), rounding, ImDrawCornerFlags_All, border_size); + + int border_held = window->ResizeBorderHeld; + if (border_held != -1) + { + struct ImGuiResizeBorderDef + { + ImVec2 InnerDir; + ImVec2 CornerPosN1, CornerPosN2; + float OuterAngle; + }; + static const ImGuiResizeBorderDef resize_border_def[4] = + { + { ImVec2(0,+1), ImVec2(0,0), ImVec2(1,0), IM_PI*1.50f }, // Top + { ImVec2(-1,0), ImVec2(1,0), ImVec2(1,1), IM_PI*0.00f }, // Right + { ImVec2(0,-1), ImVec2(1,1), ImVec2(0,1), IM_PI*0.50f }, // Bottom + { ImVec2(+1,0), ImVec2(0,1), ImVec2(0,0), IM_PI*1.00f } // Left + }; + const ImGuiResizeBorderDef& def = resize_border_def[border_held]; + ImRect border_r = GetResizeBorderRect(window, border_held, rounding, 0.0f); + window->DrawList->PathArcTo(ImLerp(border_r.Min, border_r.Max, def.CornerPosN1) + ImVec2(0.5f, 0.5f) + def.InnerDir * rounding, rounding, def.OuterAngle - IM_PI*0.25f, def.OuterAngle); + window->DrawList->PathArcTo(ImLerp(border_r.Min, border_r.Max, def.CornerPosN2) + ImVec2(0.5f, 0.5f) + def.InnerDir * rounding, rounding, def.OuterAngle, def.OuterAngle + IM_PI*0.25f); + window->DrawList->PathStroke(GetColorU32(ImGuiCol_SeparatorActive), false, ImMax(2.0f, border_size)); // Thicker than usual + } + if (g.Style.FrameBorderSize > 0 && !(window->Flags & ImGuiWindowFlags_NoTitleBar) && !window->DockIsActive) + { + float y = window->Pos.y + window->TitleBarHeight() - 1; + window->DrawList->AddLine(ImVec2(window->Pos.x + border_size, y), ImVec2(window->Pos.x + window->Size.x - border_size, y), GetColorU32(ImGuiCol_Border), g.Style.FrameBorderSize); + } +} + +// Draw background and borders +// Draw and handle scrollbars +void ImGui::RenderWindowDecorations(ImGuiWindow* window, const ImRect& title_bar_rect, bool title_bar_is_highlight, bool handle_borders_and_resize_grips, int resize_grip_count, const ImU32 resize_grip_col[4], float resize_grip_draw_size) +{ + ImGuiContext& g = *GImGui; + ImGuiStyle& style = g.Style; + ImGuiWindowFlags flags = window->Flags; + + // Ensure that ScrollBar doesn't read last frame's SkipItems + window->SkipItems = false; + + // Draw window + handle manual resize + // As we highlight the title bar when want_focus is set, multiple reappearing windows will have have their title bar highlighted on their reappearing frame. + const float window_rounding = window->WindowRounding; + const float window_border_size = window->WindowBorderSize; + if (window->Collapsed) + { + // Title bar only + float backup_border_size = style.FrameBorderSize; + g.Style.FrameBorderSize = window->WindowBorderSize; + ImU32 title_bar_col = GetColorU32((title_bar_is_highlight && !g.NavDisableHighlight) ? ImGuiCol_TitleBgActive : ImGuiCol_TitleBgCollapsed); + RenderFrame(title_bar_rect.Min, title_bar_rect.Max, title_bar_col, true, window_rounding); + g.Style.FrameBorderSize = backup_border_size; + } + else + { + // Window background + if (!(flags & ImGuiWindowFlags_NoBackground)) + { + bool is_docking_transparent_payload = false; + if (g.DragDropActive && (g.FrameCount - g.DragDropAcceptFrameCount) <= 1 && g.IO.ConfigDockingTransparentPayload) + if (g.DragDropPayload.IsDataType(IMGUI_PAYLOAD_TYPE_WINDOW) && *(ImGuiWindow**)g.DragDropPayload.Data == window) + is_docking_transparent_payload = true; + + ImU32 bg_col = GetColorU32(GetWindowBgColorIdxFromFlags(flags)); + if (window->ViewportOwned) + { + // No alpha + bg_col = (bg_col | IM_COL32_A_MASK); + if (is_docking_transparent_payload) + window->Viewport->Alpha *= DOCKING_TRANSPARENT_PAYLOAD_ALPHA; + } + else + { + // Adjust alpha. For docking + bool override_alpha = false; + float alpha = 1.0f; + if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasBgAlpha) + { + alpha = g.NextWindowData.BgAlphaVal; + override_alpha = true; + } + if (is_docking_transparent_payload) + { + alpha *= DOCKING_TRANSPARENT_PAYLOAD_ALPHA; // FIXME-DOCK: Should that be an override? + override_alpha = true; + } + if (override_alpha) + bg_col = (bg_col & ~IM_COL32_A_MASK) | (IM_F32_TO_INT8_SAT(alpha) << IM_COL32_A_SHIFT); + } + window->DrawList->AddRectFilled(window->Pos + ImVec2(0, window->TitleBarHeight()), window->Pos + window->Size, bg_col, window_rounding, (flags & ImGuiWindowFlags_NoTitleBar) ? ImDrawCornerFlags_All : ImDrawCornerFlags_Bot); + } + + // Title bar + // (when docked, DockNode are drawing their own title bar. Individual windows however do NOT set the _NoTitleBar flag, + // in order for their pos/size to be matching their undocking state.) + if (!(flags & ImGuiWindowFlags_NoTitleBar) && !window->DockIsActive) + { + ImU32 title_bar_col = GetColorU32(title_bar_is_highlight ? ImGuiCol_TitleBgActive : ImGuiCol_TitleBg); + window->DrawList->AddRectFilled(title_bar_rect.Min, title_bar_rect.Max, title_bar_col, window_rounding, ImDrawCornerFlags_Top); + } + + // Menu bar + if (flags & ImGuiWindowFlags_MenuBar) + { + ImRect menu_bar_rect = window->MenuBarRect(); + menu_bar_rect.ClipWith(window->Rect()); // Soft clipping, in particular child window don't have minimum size covering the menu bar so this is useful for them. + window->DrawList->AddRectFilled(menu_bar_rect.Min + ImVec2(window_border_size, 0), menu_bar_rect.Max - ImVec2(window_border_size, 0), GetColorU32(ImGuiCol_MenuBarBg), (flags & ImGuiWindowFlags_NoTitleBar) ? window_rounding : 0.0f, ImDrawCornerFlags_Top); + if (style.FrameBorderSize > 0.0f && menu_bar_rect.Max.y < window->Pos.y + window->Size.y) + window->DrawList->AddLine(menu_bar_rect.GetBL(), menu_bar_rect.GetBR(), GetColorU32(ImGuiCol_Border), style.FrameBorderSize); + } + + // Docking: Unhide tab bar (small triangle in the corner), drag from small triangle to quickly undock + ImGuiDockNode* node = window->DockNode; + if (window->DockIsActive && node->IsHiddenTabBar() && !node->IsNoTabBar()) + { + float unhide_sz_draw = ImFloor(g.FontSize * 0.70f); + float unhide_sz_hit = ImFloor(g.FontSize * 0.55f); + ImVec2 p = node->Pos; + ImRect r(p, p + ImVec2(unhide_sz_hit, unhide_sz_hit)); + bool hovered, held; + if (ButtonBehavior(r, window->GetID("#UNHIDE"), &hovered, &held, ImGuiButtonFlags_FlattenChildren)) + node->WantHiddenTabBarToggle = true; + else if (held && IsMouseDragging(0)) + StartMouseMovingWindowOrNode(window, node, true); + + // FIXME-DOCK: Ideally we'd use ImGuiCol_TitleBgActive/ImGuiCol_TitleBg here, but neither is guaranteed to be visible enough at this sort of size.. + ImU32 col = GetColorU32(((held && hovered) || (node->IsFocused && !hovered)) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button); + window->DrawList->AddTriangleFilled(p, p + ImVec2(unhide_sz_draw, 0.0f), p + ImVec2(0.0f, unhide_sz_draw), col); + } + + // Scrollbars + if (window->ScrollbarX) + Scrollbar(ImGuiAxis_X); + if (window->ScrollbarY) + Scrollbar(ImGuiAxis_Y); + + // Render resize grips (after their input handling so we don't have a frame of latency) + if (handle_borders_and_resize_grips && !(flags & ImGuiWindowFlags_NoResize)) + { + for (int resize_grip_n = 0; resize_grip_n < resize_grip_count; resize_grip_n++) + { + const ImGuiResizeGripDef& grip = resize_grip_def[resize_grip_n]; + const ImVec2 corner = ImLerp(window->Pos, window->Pos + window->Size, grip.CornerPosN); + window->DrawList->PathLineTo(corner + grip.InnerDir * ((resize_grip_n & 1) ? ImVec2(window_border_size, resize_grip_draw_size) : ImVec2(resize_grip_draw_size, window_border_size))); + window->DrawList->PathLineTo(corner + grip.InnerDir * ((resize_grip_n & 1) ? ImVec2(resize_grip_draw_size, window_border_size) : ImVec2(window_border_size, resize_grip_draw_size))); + window->DrawList->PathArcToFast(ImVec2(corner.x + grip.InnerDir.x * (window_rounding + window_border_size), corner.y + grip.InnerDir.y * (window_rounding + window_border_size)), window_rounding, grip.AngleMin12, grip.AngleMax12); + window->DrawList->PathFillConvex(resize_grip_col[resize_grip_n]); + } + } + + // Borders (for dock node host they will be rendered over after the tab bar) + if (handle_borders_and_resize_grips && !window->DockNodeAsHost) + RenderWindowOuterBorders(window); + } +} + +// Render title text, collapse button, close button +// When inside a dock node, this is handled in DockNodeUpdateTabBar() instead. +void ImGui::RenderWindowTitleBarContents(ImGuiWindow* window, const ImRect& title_bar_rect, const char* name, bool* p_open) +{ + ImGuiContext& g = *GImGui; + ImGuiStyle& style = g.Style; + ImGuiWindowFlags flags = window->Flags; + + const bool has_close_button = (p_open != NULL); + const bool has_collapse_button = !(flags & ImGuiWindowFlags_NoCollapse) && (style.WindowMenuButtonPosition != ImGuiDir_None); + + // Close & Collapse button are on the Menu NavLayer and don't default focus (unless there's nothing else on that layer) + const ImGuiItemFlags item_flags_backup = window->DC.ItemFlags; + window->DC.ItemFlags |= ImGuiItemFlags_NoNavDefaultFocus; + window->DC.NavLayerCurrent = ImGuiNavLayer_Menu; + window->DC.NavLayerCurrentMask = (1 << ImGuiNavLayer_Menu); + + // Layout buttons + // FIXME: Would be nice to generalize the subtleties expressed here into reusable code. + float pad_l = style.FramePadding.x; + float pad_r = style.FramePadding.x; + float button_sz = g.FontSize; + ImVec2 close_button_pos; + ImVec2 collapse_button_pos; + if (has_close_button) + { + pad_r += button_sz; + close_button_pos = ImVec2(title_bar_rect.Max.x - pad_r - style.FramePadding.x, title_bar_rect.Min.y); + } + if (has_collapse_button && style.WindowMenuButtonPosition == ImGuiDir_Right) + { + pad_r += button_sz; + collapse_button_pos = ImVec2(title_bar_rect.Max.x - pad_r - style.FramePadding.x, title_bar_rect.Min.y); + } + if (has_collapse_button && style.WindowMenuButtonPosition == ImGuiDir_Left) + { + collapse_button_pos = ImVec2(title_bar_rect.Min.x + pad_l - style.FramePadding.x, title_bar_rect.Min.y); + pad_l += button_sz; + } + + // Collapse button (submitting first so it gets priority when choosing a navigation init fallback) + if (has_collapse_button) + if (CollapseButton(window->GetID("#COLLAPSE"), collapse_button_pos, NULL)) + window->WantCollapseToggle = true; // Defer actual collapsing to next frame as we are too far in the Begin() function + + // Close button + if (has_close_button) + if (CloseButton(window->GetID("#CLOSE"), close_button_pos)) + *p_open = false; + + window->DC.NavLayerCurrent = ImGuiNavLayer_Main; + window->DC.NavLayerCurrentMask = (1 << ImGuiNavLayer_Main); + window->DC.ItemFlags = item_flags_backup; + + // Title bar text (with: horizontal alignment, avoiding collapse/close button, optional "unsaved document" marker) + // FIXME: Refactor text alignment facilities along with RenderText helpers, this is WAY too much messy code.. + const char* UNSAVED_DOCUMENT_MARKER = "*"; + const float marker_size_x = (flags & ImGuiWindowFlags_UnsavedDocument) ? CalcTextSize(UNSAVED_DOCUMENT_MARKER, NULL, false).x : 0.0f; + const ImVec2 text_size = CalcTextSize(name, NULL, true) + ImVec2(marker_size_x, 0.0f); + + // As a nice touch we try to ensure that centered title text doesn't get affected by visibility of Close/Collapse button, + // while uncentered title text will still reach edges correct. + if (pad_l > style.FramePadding.x) + pad_l += g.Style.ItemInnerSpacing.x; + if (pad_r > style.FramePadding.x) + pad_r += g.Style.ItemInnerSpacing.x; + if (style.WindowTitleAlign.x > 0.0f && style.WindowTitleAlign.x < 1.0f) + { + float centerness = ImSaturate(1.0f - ImFabs(style.WindowTitleAlign.x - 0.5f) * 2.0f); // 0.0f on either edges, 1.0f on center + float pad_extend = ImMin(ImMax(pad_l, pad_r), title_bar_rect.GetWidth() - pad_l - pad_r - text_size.x); + pad_l = ImMax(pad_l, pad_extend * centerness); + pad_r = ImMax(pad_r, pad_extend * centerness); + } + + ImRect layout_r(title_bar_rect.Min.x + pad_l, title_bar_rect.Min.y, title_bar_rect.Max.x - pad_r, title_bar_rect.Max.y); + ImRect clip_r(layout_r.Min.x, layout_r.Min.y, layout_r.Max.x + g.Style.ItemInnerSpacing.x, layout_r.Max.y); + //if (g.IO.KeyCtrl) window->DrawList->AddRect(layout_r.Min, layout_r.Max, IM_COL32(255, 128, 0, 255)); // [DEBUG] + RenderTextClipped(layout_r.Min, layout_r.Max, name, NULL, &text_size, style.WindowTitleAlign, &clip_r); + if (flags & ImGuiWindowFlags_UnsavedDocument) + { + ImVec2 marker_pos = ImVec2(ImMax(layout_r.Min.x, layout_r.Min.x + (layout_r.GetWidth() - text_size.x) * style.WindowTitleAlign.x) + text_size.x, layout_r.Min.y) + ImVec2(2 - marker_size_x, 0.0f); + ImVec2 off = ImVec2(0.0f, IM_FLOOR(-g.FontSize * 0.25f)); + RenderTextClipped(marker_pos + off, layout_r.Max + off, UNSAVED_DOCUMENT_MARKER, NULL, NULL, ImVec2(0, style.WindowTitleAlign.y), &clip_r); + } +} + +void ImGui::UpdateWindowParentAndRootLinks(ImGuiWindow* window, ImGuiWindowFlags flags, ImGuiWindow* parent_window) +{ + window->ParentWindow = parent_window; + window->RootWindow = window->RootWindowDockStop = window->RootWindowForTitleBarHighlight = window->RootWindowForNav = window; + if (parent_window && (flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Tooltip)) + { + window->RootWindow = parent_window->RootWindow; + if (!window->DockIsActive && !(parent_window->Flags & ImGuiWindowFlags_DockNodeHost)) + window->RootWindowDockStop = parent_window->RootWindowDockStop; + } + if (parent_window && !(flags & ImGuiWindowFlags_Modal) && (flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_Popup))) + window->RootWindowForTitleBarHighlight = parent_window->RootWindowForTitleBarHighlight; + while (window->RootWindowForNav->Flags & ImGuiWindowFlags_NavFlattened) + { + IM_ASSERT(window->RootWindowForNav->ParentWindow != NULL); + window->RootWindowForNav = window->RootWindowForNav->ParentWindow; + } +} + +// Push a new Dear ImGui window to add widgets to. +// - A default window called "Debug" is automatically stacked at the beginning of every frame so you can use widgets without explicitly calling a Begin/End pair. +// - Begin/End can be called multiple times during the frame with the same window name to append content. +// - The window name is used as a unique identifier to preserve window information across frames (and save rudimentary information to the .ini file). +// You can use the "##" or "###" markers to use the same label with different id, or same id with different label. See documentation at the top of this file. +// - Return false when window is collapsed, so you can early out in your code. You always need to call ImGui::End() even if false is returned. +// - Passing 'bool* p_open' displays a Close button on the upper-right corner of the window, the pointed value will be set to false when the button is pressed. +bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) +{ + ImGuiContext& g = *GImGui; + const ImGuiStyle& style = g.Style; + IM_ASSERT(name != NULL && name[0] != '\0'); // Window name required + IM_ASSERT(g.WithinFrameScope); // Forgot to call ImGui::NewFrame() + IM_ASSERT(g.FrameCountEnded != g.FrameCount); // Called ImGui::Render() or ImGui::EndFrame() and haven't called ImGui::NewFrame() again yet + + // Find or create + ImGuiWindow* window = FindWindowByName(name); + const bool window_just_created = (window == NULL); + if (window_just_created) + window = CreateNewWindow(name, flags); + + // Automatically disable manual moving/resizing when NoInputs is set + if ((flags & ImGuiWindowFlags_NoInputs) == ImGuiWindowFlags_NoInputs) + flags |= ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize; + + if (flags & ImGuiWindowFlags_NavFlattened) + IM_ASSERT(flags & ImGuiWindowFlags_ChildWindow); + + const int current_frame = g.FrameCount; + const bool first_begin_of_the_frame = (window->LastFrameActive != current_frame); + window->IsFallbackWindow = (g.CurrentWindowStack.Size == 0 && g.WithinFrameScopeWithImplicitWindow); + + // Update the Appearing flag + bool window_just_activated_by_user = (window->LastFrameActive < current_frame - 1); // Not using !WasActive because the implicit "Debug" window would always toggle off->on + const bool window_just_appearing_after_hidden_for_resize = (window->HiddenFramesCannotSkipItems > 0); + if (flags & ImGuiWindowFlags_Popup) + { + ImGuiPopupData& popup_ref = g.OpenPopupStack[g.BeginPopupStack.Size]; + window_just_activated_by_user |= (window->PopupId != popup_ref.PopupId); // We recycle popups so treat window as activated if popup id changed + window_just_activated_by_user |= (window != popup_ref.Window); + } + window->Appearing = (window_just_activated_by_user || window_just_appearing_after_hidden_for_resize); + if (window->Appearing) + SetWindowConditionAllowFlags(window, ImGuiCond_Appearing, true); + + // Update Flags, LastFrameActive, BeginOrderXXX fields + if (first_begin_of_the_frame) + { + window->FlagsPreviousFrame = window->Flags; + window->Flags = (ImGuiWindowFlags)flags; + window->LastFrameActive = current_frame; + window->LastTimeActive = (float)g.Time; + window->BeginOrderWithinParent = 0; + window->BeginOrderWithinContext = (short)(g.WindowsActiveCount++); + } + else + { + flags = window->Flags; + } + + // Docking + // (NB: during the frame dock nodes are created, it is possible that (window->DockIsActive == false) even though (window->DockNode->Windows.Size > 1) + IM_ASSERT(window->DockNode == NULL || window->DockNodeAsHost == NULL); // Cannot be both + if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasDock) + SetWindowDock(window, g.NextWindowData.DockId, g.NextWindowData.DockCond); + if (first_begin_of_the_frame) + { + bool has_dock_node = (window->DockId != 0 || window->DockNode != NULL); + bool new_auto_dock_node = !has_dock_node && GetWindowAlwaysWantOwnTabBar(window); + if (has_dock_node || new_auto_dock_node) + { + BeginDocked(window, p_open); + flags = window->Flags; + if (window->DockIsActive) + IM_ASSERT(window->DockNode != NULL); + + // Docking currently override constraints + g.NextWindowData.Flags &= ~ImGuiNextWindowDataFlags_HasSizeConstraint; + } + } + + // Parent window is latched only on the first call to Begin() of the frame, so further append-calls can be done from a different window stack + ImGuiWindow* parent_window_in_stack = window->DockIsActive ? window->DockNode->HostWindow : g.CurrentWindowStack.empty() ? NULL : g.CurrentWindowStack.back(); + ImGuiWindow* parent_window = first_begin_of_the_frame ? ((flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_Popup)) ? parent_window_in_stack : NULL) : window->ParentWindow; + IM_ASSERT(parent_window != NULL || !(flags & ImGuiWindowFlags_ChildWindow)); + + // We allow window memory to be compacted so recreate the base stack when needed. + if (window->IDStack.Size == 0) + window->IDStack.push_back(window->ID); + + // Add to stack + // We intentionally set g.CurrentWindow to NULL to prevent usage until when the viewport is set, then will call SetCurrentWindow() + g.CurrentWindowStack.push_back(window); + g.CurrentWindow = NULL; + ErrorCheckBeginEndCompareStacksSize(window, true); + if (flags & ImGuiWindowFlags_Popup) + { + ImGuiPopupData& popup_ref = g.OpenPopupStack[g.BeginPopupStack.Size]; + popup_ref.Window = window; + g.BeginPopupStack.push_back(popup_ref); + window->PopupId = popup_ref.PopupId; + } + + if (window_just_appearing_after_hidden_for_resize && !(flags & ImGuiWindowFlags_ChildWindow)) + window->NavLastIds[0] = 0; + + // Update ->RootWindow and others pointers (before any possible call to FocusWindow) + if (first_begin_of_the_frame) + UpdateWindowParentAndRootLinks(window, flags, parent_window); + + // Process SetNextWindow***() calls + // (FIXME: Consider splitting the HasXXX flags into X/Y components + bool window_pos_set_by_api = false; + bool window_size_x_set_by_api = false, window_size_y_set_by_api = false; + if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasPos) + { + window_pos_set_by_api = (window->SetWindowPosAllowFlags & g.NextWindowData.PosCond) != 0; + if (window_pos_set_by_api && ImLengthSqr(g.NextWindowData.PosPivotVal) > 0.00001f) + { + // May be processed on the next frame if this is our first frame and we are measuring size + // FIXME: Look into removing the branch so everything can go through this same code path for consistency. + window->SetWindowPosVal = g.NextWindowData.PosVal; + window->SetWindowPosPivot = g.NextWindowData.PosPivotVal; + window->SetWindowPosAllowFlags &= ~(ImGuiCond_Once | ImGuiCond_FirstUseEver | ImGuiCond_Appearing); + } + else + { + SetWindowPos(window, g.NextWindowData.PosVal, g.NextWindowData.PosCond); + } + } + if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSize) + { + window_size_x_set_by_api = (window->SetWindowSizeAllowFlags & g.NextWindowData.SizeCond) != 0 && (g.NextWindowData.SizeVal.x > 0.0f); + window_size_y_set_by_api = (window->SetWindowSizeAllowFlags & g.NextWindowData.SizeCond) != 0 && (g.NextWindowData.SizeVal.y > 0.0f); + SetWindowSize(window, g.NextWindowData.SizeVal, g.NextWindowData.SizeCond); + } + if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasScroll) + { + if (g.NextWindowData.ScrollVal.x >= 0.0f) + { + window->ScrollTarget.x = g.NextWindowData.ScrollVal.x; + window->ScrollTargetCenterRatio.x = 0.0f; + } + if (g.NextWindowData.ScrollVal.y >= 0.0f) + { + window->ScrollTarget.y = g.NextWindowData.ScrollVal.y; + window->ScrollTargetCenterRatio.y = 0.0f; + } + } + if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasContentSize) + window->ContentSizeExplicit = g.NextWindowData.ContentSizeVal; + else if (first_begin_of_the_frame) + window->ContentSizeExplicit = ImVec2(0.0f, 0.0f); + if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasWindowClass) + window->WindowClass = g.NextWindowData.WindowClass; + if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasCollapsed) + SetWindowCollapsed(window, g.NextWindowData.CollapsedVal, g.NextWindowData.CollapsedCond); + if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasFocus) + FocusWindow(window); + if (window->Appearing) + SetWindowConditionAllowFlags(window, ImGuiCond_Appearing, false); + + // When reusing window again multiple times a frame, just append content (don't need to setup again) + if (first_begin_of_the_frame) + { + // Initialize + const bool window_is_child_tooltip = (flags & ImGuiWindowFlags_ChildWindow) && (flags & ImGuiWindowFlags_Tooltip); // FIXME-WIP: Undocumented behavior of Child+Tooltip for pinned tooltip (#1345) + window->Active = true; + window->HasCloseButton = (p_open != NULL); + window->ClipRect = ImVec4(-FLT_MAX,-FLT_MAX,+FLT_MAX,+FLT_MAX); + window->IDStack.resize(1); + + // Restore buffer capacity when woken from a compacted state, to avoid + if (window->MemoryCompacted) + GcAwakeTransientWindowBuffers(window); + + // Update stored window name when it changes (which can _only_ happen with the "###" operator, so the ID would stay unchanged). + // The title bar always display the 'name' parameter, so we only update the string storage if it needs to be visible to the end-user elsewhere. + bool window_title_visible_elsewhere = false; + if ((window->Viewport && window->Viewport->Window == window) || (window->DockIsActive)) + window_title_visible_elsewhere = true; + else if (g.NavWindowingListWindow != NULL && (window->Flags & ImGuiWindowFlags_NoNavFocus) == 0) // Window titles visible when using CTRL+TAB + window_title_visible_elsewhere = true; + if (window_title_visible_elsewhere && !window_just_created && strcmp(name, window->Name) != 0) + { + size_t buf_len = (size_t)window->NameBufLen; + window->Name = ImStrdupcpy(window->Name, &buf_len, name); + window->NameBufLen = (int)buf_len; + } + + // UPDATE CONTENTS SIZE, UPDATE HIDDEN STATUS + + // Update contents size from last frame for auto-fitting (or use explicit size) + window->ContentSize = CalcWindowContentSize(window); + if (window->HiddenFramesCanSkipItems > 0) + window->HiddenFramesCanSkipItems--; + if (window->HiddenFramesCannotSkipItems > 0) + window->HiddenFramesCannotSkipItems--; + + // Hide new windows for one frame until they calculate their size + if (window_just_created && (!window_size_x_set_by_api || !window_size_y_set_by_api)) + window->HiddenFramesCannotSkipItems = 1; + + // Hide popup/tooltip window when re-opening while we measure size (because we recycle the windows) + // We reset Size/ContentSize for reappearing popups/tooltips early in this function, so further code won't be tempted to use the old size. + if (window_just_activated_by_user && (flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_Tooltip)) != 0) + { + window->HiddenFramesCannotSkipItems = 1; + if (flags & ImGuiWindowFlags_AlwaysAutoResize) + { + if (!window_size_x_set_by_api) + window->Size.x = window->SizeFull.x = 0.f; + if (!window_size_y_set_by_api) + window->Size.y = window->SizeFull.y = 0.f; + window->ContentSize = ImVec2(0.f, 0.f); + } + } + + // SELECT VIEWPORT + // We need to do this before using any style/font sizes, as viewport with a different DPI may affect font sizes. + + UpdateSelectWindowViewport(window); + SetCurrentViewport(window, window->Viewport); + window->FontDpiScale = (g.IO.ConfigFlags & ImGuiConfigFlags_DpiEnableScaleFonts) ? window->Viewport->DpiScale : 1.0f; + SetCurrentWindow(window); + flags = window->Flags; + + // LOCK BORDER SIZE AND PADDING FOR THE FRAME (so that altering them doesn't cause inconsistencies) + // We read Style data after the call to UpdateSelectWindowViewport() which might be swapping the style. + + if (flags & ImGuiWindowFlags_ChildWindow) + window->WindowBorderSize = style.ChildBorderSize; + else + window->WindowBorderSize = ((flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_Tooltip)) && !(flags & ImGuiWindowFlags_Modal)) ? style.PopupBorderSize : style.WindowBorderSize; + if (!window->DockIsActive && (flags & ImGuiWindowFlags_ChildWindow) && !(flags & (ImGuiWindowFlags_AlwaysUseWindowPadding | ImGuiWindowFlags_Popup)) && window->WindowBorderSize == 0.0f) + window->WindowPadding = ImVec2(0.0f, (flags & ImGuiWindowFlags_MenuBar) ? style.WindowPadding.y : 0.0f); + else + window->WindowPadding = style.WindowPadding; + + // Lock menu offset so size calculation can use it as menu-bar windows need a minimum size. + window->DC.MenuBarOffset.x = ImMax(ImMax(window->WindowPadding.x, style.ItemSpacing.x), g.NextWindowData.MenuBarOffsetMinVal.x); + window->DC.MenuBarOffset.y = g.NextWindowData.MenuBarOffsetMinVal.y; + + // Collapse window by double-clicking on title bar + // At this point we don't have a clipping rectangle setup yet, so we can use the title bar area for hit detection and drawing + if (!(flags & ImGuiWindowFlags_NoTitleBar) && !(flags & ImGuiWindowFlags_NoCollapse) && !window->DockIsActive) + { + // We don't use a regular button+id to test for double-click on title bar (mostly due to legacy reason, could be fixed), so verify that we don't have items over the title bar. + ImRect title_bar_rect = window->TitleBarRect(); + if (g.HoveredWindow == window && g.HoveredId == 0 && g.HoveredIdPreviousFrame == 0 && IsMouseHoveringRect(title_bar_rect.Min, title_bar_rect.Max) && g.IO.MouseDoubleClicked[0]) + window->WantCollapseToggle = true; + if (window->WantCollapseToggle) + { + window->Collapsed = !window->Collapsed; + MarkIniSettingsDirty(window); + FocusWindow(window); + } + } + else + { + window->Collapsed = false; + } + window->WantCollapseToggle = false; + + // SIZE + + // Calculate auto-fit size, handle automatic resize + const ImVec2 size_auto_fit = CalcWindowAutoFitSize(window, window->ContentSize); + bool use_current_size_for_scrollbar_x = window_just_created; + bool use_current_size_for_scrollbar_y = window_just_created; + if ((flags & ImGuiWindowFlags_AlwaysAutoResize) && !window->Collapsed) + { + // Using SetNextWindowSize() overrides ImGuiWindowFlags_AlwaysAutoResize, so it can be used on tooltips/popups, etc. + if (!window_size_x_set_by_api) + { + window->SizeFull.x = size_auto_fit.x; + use_current_size_for_scrollbar_x = true; + } + if (!window_size_y_set_by_api) + { + window->SizeFull.y = size_auto_fit.y; + use_current_size_for_scrollbar_y = true; + } + } + else if (window->AutoFitFramesX > 0 || window->AutoFitFramesY > 0) + { + // Auto-fit may only grow window during the first few frames + // We still process initial auto-fit on collapsed windows to get a window width, but otherwise don't honor ImGuiWindowFlags_AlwaysAutoResize when collapsed. + if (!window_size_x_set_by_api && window->AutoFitFramesX > 0) + { + window->SizeFull.x = window->AutoFitOnlyGrows ? ImMax(window->SizeFull.x, size_auto_fit.x) : size_auto_fit.x; + use_current_size_for_scrollbar_x = true; + } + if (!window_size_y_set_by_api && window->AutoFitFramesY > 0) + { + window->SizeFull.y = window->AutoFitOnlyGrows ? ImMax(window->SizeFull.y, size_auto_fit.y) : size_auto_fit.y; + use_current_size_for_scrollbar_y = true; + } + if (!window->Collapsed) + MarkIniSettingsDirty(window); + } + + // Apply minimum/maximum window size constraints and final size + window->SizeFull = CalcWindowSizeAfterConstraint(window, window->SizeFull); + window->Size = window->Collapsed && !(flags & ImGuiWindowFlags_ChildWindow) ? window->TitleBarRect().GetSize() : window->SizeFull; + + // Decoration size + const float decoration_up_height = window->TitleBarHeight() + window->MenuBarHeight(); + + // POSITION + + // Popup latch its initial position, will position itself when it appears next frame + if (window_just_activated_by_user) + { + window->AutoPosLastDirection = ImGuiDir_None; + if ((flags & ImGuiWindowFlags_Popup) != 0 && !window_pos_set_by_api) + window->Pos = g.BeginPopupStack.back().OpenPopupPos; + } + + // Position child window + if (flags & ImGuiWindowFlags_ChildWindow) + { + IM_ASSERT(parent_window && parent_window->Active); + window->BeginOrderWithinParent = (short)parent_window->DC.ChildWindows.Size; + parent_window->DC.ChildWindows.push_back(window); + if (!(flags & ImGuiWindowFlags_Popup) && !window_pos_set_by_api && !window_is_child_tooltip) + window->Pos = parent_window->DC.CursorPos; + } + + const bool window_pos_with_pivot = (window->SetWindowPosVal.x != FLT_MAX && window->HiddenFramesCannotSkipItems == 0); + if (window_pos_with_pivot) + SetWindowPos(window, window->SetWindowPosVal - window->SizeFull * window->SetWindowPosPivot, 0); // Position given a pivot (e.g. for centering) + else if ((flags & ImGuiWindowFlags_ChildMenu) != 0) + window->Pos = FindBestWindowPosForPopup(window); + else if ((flags & ImGuiWindowFlags_Popup) != 0 && !window_pos_set_by_api && window_just_appearing_after_hidden_for_resize) + window->Pos = FindBestWindowPosForPopup(window); + else if ((flags & ImGuiWindowFlags_Tooltip) != 0 && !window_pos_set_by_api && !window_is_child_tooltip) + window->Pos = FindBestWindowPosForPopup(window); + + // Late create viewport if we don't fit within our current host viewport. + if (window->ViewportAllowPlatformMonitorExtend >= 0 && !window->ViewportOwned && !(window->Viewport->Flags & ImGuiViewportFlags_Minimized)) + if (!window->Viewport->GetMainRect().Contains(window->Rect())) + { + // This is based on the assumption that the DPI will be known ahead (same as the DPI of the selection done in UpdateSelectWindowViewport) + //ImGuiViewport* old_viewport = window->Viewport; + window->Viewport = AddUpdateViewport(window, window->ID, window->Pos, window->Size, ImGuiViewportFlags_NoFocusOnAppearing); + + // FIXME-DPI + //IM_ASSERT(old_viewport->DpiScale == window->Viewport->DpiScale); // FIXME-DPI: Something went wrong + SetCurrentViewport(window, window->Viewport); + window->FontDpiScale = (g.IO.ConfigFlags & ImGuiConfigFlags_DpiEnableScaleFonts) ? window->Viewport->DpiScale : 1.0f; + SetCurrentWindow(window); + } + + bool viewport_rect_changed = false; + if (window->ViewportOwned) + { + // Synchronize window --> viewport in most situations + // Synchronize viewport -> window in case the platform window has been moved or resized from the OS/WM + if (window->Viewport->PlatformRequestMove) + { + window->Pos = window->Viewport->Pos; + MarkIniSettingsDirty(window); + } + else if (memcmp(&window->Viewport->Pos, &window->Pos, sizeof(window->Pos)) != 0) + { + viewport_rect_changed = true; + window->Viewport->Pos = window->Pos; + } + + if (window->Viewport->PlatformRequestResize) + { + window->Size = window->SizeFull = window->Viewport->Size; + MarkIniSettingsDirty(window); + } + else if (memcmp(&window->Viewport->Size, &window->Size, sizeof(window->Size)) != 0) + { + viewport_rect_changed = true; + window->Viewport->Size = window->Size; + } + + // The viewport may have changed monitor since the global update in UpdateViewportsNewFrame() + // Either a SetNextWindowPos() call in the current frame or a SetWindowPos() call in the previous frame may have this effect. + if (viewport_rect_changed) + UpdateViewportPlatformMonitor(window->Viewport); + + // Update common viewport flags + const ImGuiViewportFlags viewport_flags_to_clear = ImGuiViewportFlags_TopMost | ImGuiViewportFlags_NoTaskBarIcon | ImGuiViewportFlags_NoDecoration | ImGuiViewportFlags_NoRendererClear; + ImGuiViewportFlags viewport_flags = window->Viewport->Flags & ~viewport_flags_to_clear; + const bool is_short_lived_floating_window = (flags & (ImGuiWindowFlags_ChildMenu | ImGuiWindowFlags_Tooltip | ImGuiWindowFlags_Popup)) != 0; + if (flags & ImGuiWindowFlags_Tooltip) + viewport_flags |= ImGuiViewportFlags_TopMost; + if (g.IO.ConfigViewportsNoTaskBarIcon || is_short_lived_floating_window) + viewport_flags |= ImGuiViewportFlags_NoTaskBarIcon; + if (g.IO.ConfigViewportsNoDecoration || is_short_lived_floating_window) + viewport_flags |= ImGuiViewportFlags_NoDecoration; + + // For popups and menus that may be protruding out of their parent viewport, we enable _NoFocusOnClick so that clicking on them + // won't steal the OS focus away from their parent window (which may be reflected in OS the title bar decoration). + // Setting _NoFocusOnClick would technically prevent us from bringing back to front in case they are being covered by an OS window from a different app, + // but it shouldn't be much of a problem considering those are already popups that are closed when clicking elsewhere. + if (is_short_lived_floating_window && (flags & ImGuiWindowFlags_Modal) == 0) + viewport_flags |= ImGuiViewportFlags_NoFocusOnAppearing | ImGuiViewportFlags_NoFocusOnClick; + + // We can overwrite viewport flags using ImGuiWindowClass (advanced users) + // We don't default to the main viewport because. + if (window->WindowClass.ParentViewportId) + window->Viewport->ParentViewportId = window->WindowClass.ParentViewportId; + else if ((flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_Tooltip)) && parent_window_in_stack) + window->Viewport->ParentViewportId = parent_window_in_stack->Viewport->ID; + else + window->Viewport->ParentViewportId = g.IO.ConfigViewportsNoDefaultParent ? 0 : IMGUI_VIEWPORT_DEFAULT_ID; + if (window->WindowClass.ViewportFlagsOverrideSet) + viewport_flags |= window->WindowClass.ViewportFlagsOverrideSet; + if (window->WindowClass.ViewportFlagsOverrideClear) + viewport_flags &= ~window->WindowClass.ViewportFlagsOverrideClear; + + // We also tell the back-end that clearing the platform window won't be necessary, as our window is filling the viewport and we have disabled BgAlpha + if (!(flags & ImGuiWindowFlags_NoBackground)) + viewport_flags &= ~ImGuiViewportFlags_NoRendererClear; + + window->Viewport->Flags = viewport_flags; + } + + // Clamp position/size so window stays visible within its viewport or monitor + // Ignore zero-sized display explicitly to avoid losing positions if a window manager reports zero-sized window when initializing or minimizing. + // FIXME: Similar to code in GetWindowAllowedExtentRect() + ImRect viewport_rect = window->Viewport->GetMainRect(); + if (!window_pos_set_by_api && !(flags & ImGuiWindowFlags_ChildWindow) && window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0) + { + ImVec2 clamp_padding = ImMax(style.DisplayWindowPadding, style.DisplaySafeAreaPadding); + if (!window->ViewportOwned && viewport_rect.GetWidth() > 0 && viewport_rect.GetHeight() > 0.0f) + { + ClampWindowRect(window, window->Viewport->GetWorkRect(), clamp_padding); + } + else if (window->ViewportOwned && g.PlatformIO.Monitors.Size > 0) + { + if (window->Viewport->PlatformMonitor == -1) + { + // Fallback for "lost" window (e.g. a monitor disconnected): we move the window back over the main viewport + SetWindowPos(window, g.Viewports[0]->Pos + style.DisplayWindowPadding, ImGuiCond_Always); + } + else + { + ImGuiPlatformMonitor& monitor = g.PlatformIO.Monitors[window->Viewport->PlatformMonitor]; + ClampWindowRect(window, ImRect(monitor.WorkPos, monitor.WorkPos + monitor.WorkSize), clamp_padding); + } + } + } + window->Pos = ImFloor(window->Pos); + + // Lock window rounding for the frame (so that altering them doesn't cause inconsistencies) + if (window->ViewportOwned || window->DockIsActive) + window->WindowRounding = 0.0f; + else + window->WindowRounding = (flags & ImGuiWindowFlags_ChildWindow) ? style.ChildRounding : ((flags & ImGuiWindowFlags_Popup) && !(flags & ImGuiWindowFlags_Modal)) ? style.PopupRounding : style.WindowRounding; + + // Apply window focus (new and reactivated windows are moved to front) + bool want_focus = false; + if (window_just_activated_by_user && !(flags & ImGuiWindowFlags_NoFocusOnAppearing)) + { + if (flags & ImGuiWindowFlags_Popup) + want_focus = true; + else if ((window->DockIsActive || (flags & ImGuiWindowFlags_ChildWindow) == 0) && !(flags & ImGuiWindowFlags_Tooltip)) + want_focus = true; + } + + // Decide if we are going to handle borders and resize grips + const bool handle_borders_and_resize_grips = (window->DockNodeAsHost || !window->DockIsActive); + + // Handle manual resize: Resize Grips, Borders, Gamepad + int border_held = -1; + ImU32 resize_grip_col[4] = {}; + const int resize_grip_count = g.IO.ConfigWindowsResizeFromEdges ? 2 : 1; // Allow resize from lower-left if we have the mouse cursor feedback for it. + const float resize_grip_draw_size = IM_FLOOR(ImMax(g.FontSize * 1.35f, window->WindowRounding + 1.0f + g.FontSize * 0.2f)); + if (handle_borders_and_resize_grips && !window->Collapsed) + if (UpdateWindowManualResize(window, size_auto_fit, &border_held, resize_grip_count, &resize_grip_col[0])) + use_current_size_for_scrollbar_x = use_current_size_for_scrollbar_y = true; + window->ResizeBorderHeld = (signed char)border_held; + + // Synchronize window --> viewport again and one last time (clamping and manual resize may have affected either) + if (window->ViewportOwned) + { + if (!window->Viewport->PlatformRequestMove) + window->Viewport->Pos = window->Pos; + if (!window->Viewport->PlatformRequestResize) + window->Viewport->Size = window->Size; + viewport_rect = window->Viewport->GetMainRect(); + } + + // Save last known viewport position within the window itself (so it can be saved in .ini file and restored) + window->ViewportPos = window->Viewport->Pos; + + // SCROLLBAR VISIBILITY + + // Update scrollbar visibility (based on the Size that was effective during last frame or the auto-resized Size). + if (!window->Collapsed) + { + // When reading the current size we need to read it after size constraints have been applied. + // When we use InnerRect here we are intentionally reading last frame size, same for ScrollbarSizes values before we set them again. + ImVec2 avail_size_from_current_frame = ImVec2(window->SizeFull.x, window->SizeFull.y - decoration_up_height); + ImVec2 avail_size_from_last_frame = window->InnerRect.GetSize() + window->ScrollbarSizes; + ImVec2 needed_size_from_last_frame = window_just_created ? ImVec2(0, 0) : window->ContentSize + window->WindowPadding * 2.0f; + float size_x_for_scrollbars = use_current_size_for_scrollbar_x ? avail_size_from_current_frame.x : avail_size_from_last_frame.x; + float size_y_for_scrollbars = use_current_size_for_scrollbar_y ? avail_size_from_current_frame.y : avail_size_from_last_frame.y; + //bool scrollbar_y_from_last_frame = window->ScrollbarY; // FIXME: May want to use that in the ScrollbarX expression? How many pros vs cons? + window->ScrollbarY = (flags & ImGuiWindowFlags_AlwaysVerticalScrollbar) || ((needed_size_from_last_frame.y > size_y_for_scrollbars) && !(flags & ImGuiWindowFlags_NoScrollbar)); + window->ScrollbarX = (flags & ImGuiWindowFlags_AlwaysHorizontalScrollbar) || ((needed_size_from_last_frame.x > size_x_for_scrollbars - (window->ScrollbarY ? style.ScrollbarSize : 0.0f)) && !(flags & ImGuiWindowFlags_NoScrollbar) && (flags & ImGuiWindowFlags_HorizontalScrollbar)); + if (window->ScrollbarX && !window->ScrollbarY) + window->ScrollbarY = (needed_size_from_last_frame.y > size_y_for_scrollbars) && !(flags & ImGuiWindowFlags_NoScrollbar); + window->ScrollbarSizes = ImVec2(window->ScrollbarY ? style.ScrollbarSize : 0.0f, window->ScrollbarX ? style.ScrollbarSize : 0.0f); + } + + // UPDATE RECTANGLES (1- THOSE NOT AFFECTED BY SCROLLING) + // Update various regions. Variables they depends on should be set above in this function. + // We set this up after processing the resize grip so that our rectangles doesn't lag by a frame. + + // Outer rectangle + // Not affected by window border size. Used by: + // - FindHoveredWindow() (w/ extra padding when border resize is enabled) + // - Begin() initial clipping rect for drawing window background and borders. + // - Begin() clipping whole child + const ImRect host_rect = ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Popup) && !window_is_child_tooltip) ? parent_window->ClipRect : viewport_rect; + const ImRect outer_rect = window->Rect(); + const ImRect title_bar_rect = window->TitleBarRect(); + window->OuterRectClipped = outer_rect; + if (window->DockIsActive) + window->OuterRectClipped.Min.y += window->TitleBarHeight(); + window->OuterRectClipped.ClipWith(host_rect); + + // Inner rectangle + // Not affected by window border size. Used by: + // - InnerClipRect + // - ScrollToBringRectIntoView() + // - NavUpdatePageUpPageDown() + // - Scrollbar() + window->InnerRect.Min.x = window->Pos.x; + window->InnerRect.Min.y = window->Pos.y + decoration_up_height; + window->InnerRect.Max.x = window->Pos.x + window->Size.x - window->ScrollbarSizes.x; + window->InnerRect.Max.y = window->Pos.y + window->Size.y - window->ScrollbarSizes.y; + + // Inner clipping rectangle. + // Will extend a little bit outside the normal work region. + // This is to allow e.g. Selectable or CollapsingHeader or some separators to cover that space. + // Force round operator last to ensure that e.g. (int)(max.x-min.x) in user's render code produce correct result. + // Note that if our window is collapsed we will end up with an inverted (~null) clipping rectangle which is the correct behavior. + // Affected by window/frame border size. Used by: + // - Begin() initial clip rect + float top_border_size = (((flags & ImGuiWindowFlags_MenuBar) || !(flags & ImGuiWindowFlags_NoTitleBar)) ? style.FrameBorderSize : window->WindowBorderSize); + window->InnerClipRect.Min.x = ImFloor(0.5f + window->InnerRect.Min.x + ImMax(ImFloor(window->WindowPadding.x * 0.5f), window->WindowBorderSize)); + window->InnerClipRect.Min.y = ImFloor(0.5f + window->InnerRect.Min.y + top_border_size); + window->InnerClipRect.Max.x = ImFloor(0.5f + window->InnerRect.Max.x - ImMax(ImFloor(window->WindowPadding.x * 0.5f), window->WindowBorderSize)); + window->InnerClipRect.Max.y = ImFloor(0.5f + window->InnerRect.Max.y - window->WindowBorderSize); + window->InnerClipRect.ClipWithFull(host_rect); + + // Default item width. Make it proportional to window size if window manually resizes + if (window->Size.x > 0.0f && !(flags & ImGuiWindowFlags_Tooltip) && !(flags & ImGuiWindowFlags_AlwaysAutoResize)) + window->ItemWidthDefault = ImFloor(window->Size.x * 0.65f); + else + window->ItemWidthDefault = ImFloor(g.FontSize * 16.0f); + + // SCROLLING + + // Lock down maximum scrolling + // The value of ScrollMax are ahead from ScrollbarX/ScrollbarY which is intentionally using InnerRect from previous rect in order to accommodate + // for right/bottom aligned items without creating a scrollbar. + window->ScrollMax.x = ImMax(0.0f, window->ContentSize.x + window->WindowPadding.x * 2.0f - window->InnerRect.GetWidth()); + window->ScrollMax.y = ImMax(0.0f, window->ContentSize.y + window->WindowPadding.y * 2.0f - window->InnerRect.GetHeight()); + + // Apply scrolling + window->Scroll = CalcNextScrollFromScrollTargetAndClamp(window, true); + window->ScrollTarget = ImVec2(FLT_MAX, FLT_MAX); + + // DRAWING + + // Setup draw list and outer clipping rectangle + window->DrawList->Clear(); + window->DrawList->PushTextureID(g.Font->ContainerAtlas->TexID); + PushClipRect(host_rect.Min, host_rect.Max, false); + + // Draw modal or window list full viewport dimming background (for other viewports we'll render them in EndFrame) + ImGuiWindow* window_window_list = g.NavWindowingListWindow; + const bool dim_bg_for_modal = (flags & ImGuiWindowFlags_Modal) && window == GetTopMostPopupModal() && window->HiddenFramesCannotSkipItems <= 0; + const bool dim_bg_for_window_list = g.NavWindowingTargetAnim && ((window == g.NavWindowingTargetAnim->RootWindow) || (window == window_window_list && window_window_list->Viewport != g.NavWindowingTargetAnim->Viewport)); + if (dim_bg_for_modal || dim_bg_for_window_list) + { + const ImU32 dim_bg_col = GetColorU32(dim_bg_for_modal ? ImGuiCol_ModalWindowDimBg : ImGuiCol_NavWindowingDimBg, g.DimBgRatio); + window->DrawList->AddRectFilled(viewport_rect.Min, viewport_rect.Max, dim_bg_col); + } + + // Draw navigation selection/windowing rectangle background + if (dim_bg_for_window_list && window == g.NavWindowingTargetAnim) + { + ImRect bb = window->Rect(); + bb.Expand(g.FontSize); + if (!bb.Contains(viewport_rect)) // Avoid drawing if the window covers all the viewport anyway + window->DrawList->AddRectFilled(bb.Min, bb.Max, GetColorU32(ImGuiCol_NavWindowingHighlight, g.NavWindowingHighlightAlpha * 0.25f), g.Style.WindowRounding); + } + + // Since 1.71, child window can render their decoration (bg color, border, scrollbars, etc.) within their parent to save a draw call. + // When using overlapping child windows, this will break the assumption that child z-order is mapped to submission order. + // We disable this when the parent window has zero vertices, which is a common pattern leading to laying out multiple overlapping child. + // We also disabled this when we have dimming overlay behind this specific one child. + // FIXME: More code may rely on explicit sorting of overlapping child window and would need to disable this somehow. Please get in contact if you are affected. + const bool is_undocked_or_docked_visible = !window->DockIsActive || window->DockTabIsVisible; + if (is_undocked_or_docked_visible) + { + bool render_decorations_in_parent = false; + if ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Popup) && !window_is_child_tooltip) + if (window->DrawList->CmdBuffer.back().ElemCount == 0 && parent_window->DrawList->VtxBuffer.Size > 0) + render_decorations_in_parent = true; + if (render_decorations_in_parent) + window->DrawList = parent_window->DrawList; + + // Handle title bar, scrollbar, resize grips and resize borders + const ImGuiWindow* window_to_highlight = g.NavWindowingTarget ? g.NavWindowingTarget : g.NavWindow; + const bool title_bar_is_highlight = want_focus || (window_to_highlight && (window->RootWindowForTitleBarHighlight == window_to_highlight->RootWindowForTitleBarHighlight || (window->DockNode && window->DockNode == window_to_highlight->DockNode))); + RenderWindowDecorations(window, title_bar_rect, title_bar_is_highlight, handle_borders_and_resize_grips, resize_grip_count, resize_grip_col, resize_grip_draw_size); + + if (render_decorations_in_parent) + window->DrawList = &window->DrawListInst; + } + + // Draw navigation selection/windowing rectangle border + if (g.NavWindowingTargetAnim == window) + { + float rounding = ImMax(window->WindowRounding, g.Style.WindowRounding); + ImRect bb = window->Rect(); + bb.Expand(g.FontSize); + if (bb.Contains(viewport_rect)) // If a window fits the entire viewport, adjust its highlight inward + { + bb.Expand(-g.FontSize - 1.0f); + rounding = window->WindowRounding; + } + window->DrawList->AddRect(bb.Min, bb.Max, GetColorU32(ImGuiCol_NavWindowingHighlight, g.NavWindowingHighlightAlpha), rounding, ~0, 3.0f); + } + + // UPDATE RECTANGLES (2- THOSE AFFECTED BY SCROLLING) + + // Work rectangle. + // Affected by window padding and border size. Used by: + // - Columns() for right-most edge + // - TreeNode(), CollapsingHeader() for right-most edge + // - BeginTabBar() for right-most edge + const bool allow_scrollbar_x = !(flags & ImGuiWindowFlags_NoScrollbar) && (flags & ImGuiWindowFlags_HorizontalScrollbar); + const bool allow_scrollbar_y = !(flags & ImGuiWindowFlags_NoScrollbar); + const float work_rect_size_x = (window->ContentSizeExplicit.x != 0.0f ? window->ContentSizeExplicit.x : ImMax(allow_scrollbar_x ? window->ContentSize.x : 0.0f, window->Size.x - window->WindowPadding.x * 2.0f - window->ScrollbarSizes.x)); + const float work_rect_size_y = (window->ContentSizeExplicit.y != 0.0f ? window->ContentSizeExplicit.y : ImMax(allow_scrollbar_y ? window->ContentSize.y : 0.0f, window->Size.y - window->WindowPadding.y * 2.0f - decoration_up_height - window->ScrollbarSizes.y)); + window->WorkRect.Min.x = ImFloor(window->InnerRect.Min.x - window->Scroll.x + ImMax(window->WindowPadding.x, window->WindowBorderSize)); + window->WorkRect.Min.y = ImFloor(window->InnerRect.Min.y - window->Scroll.y + ImMax(window->WindowPadding.y, window->WindowBorderSize)); + window->WorkRect.Max.x = window->WorkRect.Min.x + work_rect_size_x; + window->WorkRect.Max.y = window->WorkRect.Min.y + work_rect_size_y; + + // [LEGACY] Content Region + // FIXME-OBSOLETE: window->ContentRegionRect.Max is currently very misleading / partly faulty, but some BeginChild() patterns relies on it. + // Used by: + // - Mouse wheel scrolling + many other things + window->ContentRegionRect.Min.x = window->Pos.x - window->Scroll.x + window->WindowPadding.x; + window->ContentRegionRect.Min.y = window->Pos.y - window->Scroll.y + window->WindowPadding.y + decoration_up_height; + window->ContentRegionRect.Max.x = window->ContentRegionRect.Min.x + (window->ContentSizeExplicit.x != 0.0f ? window->ContentSizeExplicit.x : (window->Size.x - window->WindowPadding.x * 2.0f - window->ScrollbarSizes.x)); + window->ContentRegionRect.Max.y = window->ContentRegionRect.Min.y + (window->ContentSizeExplicit.y != 0.0f ? window->ContentSizeExplicit.y : (window->Size.y - window->WindowPadding.y * 2.0f - decoration_up_height - window->ScrollbarSizes.y)); + + // Setup drawing context + // (NB: That term "drawing context / DC" lost its meaning a long time ago. Initially was meant to hold transient data only. Nowadays difference between window-> and window->DC-> is dubious.) + window->DC.Indent.x = 0.0f + window->WindowPadding.x - window->Scroll.x; + window->DC.GroupOffset.x = 0.0f; + window->DC.ColumnsOffset.x = 0.0f; + window->DC.CursorStartPos = window->Pos + ImVec2(window->DC.Indent.x + window->DC.ColumnsOffset.x, decoration_up_height + window->WindowPadding.y - window->Scroll.y); + window->DC.CursorPos = window->DC.CursorStartPos; + window->DC.CursorPosPrevLine = window->DC.CursorPos; + window->DC.CursorMaxPos = window->DC.CursorStartPos; + window->DC.CurrLineSize = window->DC.PrevLineSize = ImVec2(0.0f, 0.0f); + window->DC.CurrLineTextBaseOffset = window->DC.PrevLineTextBaseOffset = 0.0f; + + window->DC.NavLayerCurrent = ImGuiNavLayer_Main; + window->DC.NavLayerCurrentMask = (1 << ImGuiNavLayer_Main); + window->DC.NavLayerActiveMask = window->DC.NavLayerActiveMaskNext; + window->DC.NavLayerActiveMaskNext = 0x00; + window->DC.NavFocusScopeIdCurrent = (flags & ImGuiWindowFlags_ChildWindow) ? parent_window->DC.NavFocusScopeIdCurrent : 0; // -V595 + window->DC.NavHideHighlightOneFrame = false; + window->DC.NavHasScroll = (window->ScrollMax.y > 0.0f); + + window->DC.MenuBarAppending = false; + window->DC.MenuColumns.Update(3, style.ItemSpacing.x, window_just_activated_by_user); + window->DC.TreeDepth = 0; + window->DC.TreeJumpToParentOnPopMask = 0x00; + window->DC.ChildWindows.resize(0); + window->DC.StateStorage = &window->StateStorage; + window->DC.CurrentColumns = NULL; + window->DC.LayoutType = ImGuiLayoutType_Vertical; + window->DC.ParentLayoutType = parent_window ? parent_window->DC.LayoutType : ImGuiLayoutType_Vertical; + window->DC.FocusCounterRegular = window->DC.FocusCounterTabStop = -1; + + window->DC.ItemWidth = window->ItemWidthDefault; + window->DC.TextWrapPos = -1.0f; // disabled + window->DC.ItemFlagsStack.resize(0); + window->DC.ItemWidthStack.resize(0); + window->DC.TextWrapPosStack.resize(0); + window->DC.GroupStack.resize(0); + window->DC.ItemFlags = parent_window ? parent_window->DC.ItemFlags : ImGuiItemFlags_Default_; + if (parent_window) + window->DC.ItemFlagsStack.push_back(window->DC.ItemFlags); + + if (window->AutoFitFramesX > 0) + window->AutoFitFramesX--; + if (window->AutoFitFramesY > 0) + window->AutoFitFramesY--; + + // Apply focus (we need to call FocusWindow() AFTER setting DC.CursorStartPos so our initial navigation reference rectangle can start around there) + if (want_focus) + { + FocusWindow(window); + NavInitWindow(window, false); + } + + // Close requested by platform window + if (p_open != NULL && window->Viewport->PlatformRequestClose && window->Viewport != GetMainViewport()) + { + if (!window->DockIsActive || window->DockTabIsVisible) + { + window->Viewport->PlatformRequestClose = false; + g.NavWindowingToggleLayer = false; // Assume user mapped PlatformRequestClose on ALT-F4 so we disable ALT for menu toggle. False positive not an issue. + IMGUI_DEBUG_LOG_VIEWPORT("Window '%s' PlatformRequestClose\n", window->Name); + *p_open = false; + } + } + + // Title bar + if (!(flags & ImGuiWindowFlags_NoTitleBar) && !window->DockIsActive) + RenderWindowTitleBarContents(window, title_bar_rect, name, p_open); + + // Clear hit test shape every frame + window->HitTestHoleSize.x = window->HitTestHoleSize.y = 0; + + // Pressing CTRL+C while holding on a window copy its content to the clipboard + // This works but 1. doesn't handle multiple Begin/End pairs, 2. recursing into another Begin/End pair - so we need to work that out and add better logging scope. + // Maybe we can support CTRL+C on every element? + /* + if (g.ActiveId == move_id) + if (g.IO.KeyCtrl && IsKeyPressedMap(ImGuiKey_C)) + LogToClipboard(); + */ + + if (g.IO.ConfigFlags & ImGuiConfigFlags_DockingEnable) + { + // Docking: Dragging a dockable window (or any of its child) turns it into a drag and drop source. + // We need to do this _before_ we overwrite window->DC.LastItemId below because BeginDockableDragDropSource() also overwrites it. + if ((g.MovingWindow == window) && (g.IO.ConfigDockingWithShift == g.IO.KeyShift)) + if ((window->RootWindow->Flags & ImGuiWindowFlags_NoDocking) == 0) + BeginDockableDragDropSource(window); + + // Docking: Any dockable window can act as a target. For dock node hosts we call BeginDockableDragDropTarget() in DockNodeUpdate() instead. + if (g.DragDropActive && !(flags & ImGuiWindowFlags_NoDocking)) + if (g.MovingWindow == NULL || g.MovingWindow->RootWindow != window) + if ((window == window->RootWindow) && !(window->Flags & ImGuiWindowFlags_DockNodeHost)) + BeginDockableDragDropTarget(window); + } + + // We fill last item data based on Title Bar/Tab, in order for IsItemHovered() and IsItemActive() to be usable after Begin(). + // This is useful to allow creating context menus on title bar only, etc. + if (window->DockIsActive) + { + window->DC.LastItemId = window->ID; + window->DC.LastItemStatusFlags = window->DockTabItemStatusFlags; + window->DC.LastItemRect = window->DockTabItemRect; + } + else + { + window->DC.LastItemId = window->MoveId; + window->DC.LastItemStatusFlags = IsMouseHoveringRect(title_bar_rect.Min, title_bar_rect.Max, false) ? ImGuiItemStatusFlags_HoveredRect : 0; + window->DC.LastItemRect = title_bar_rect; + } + +#ifdef IMGUI_ENABLE_TEST_ENGINE + if (!(window->Flags & ImGuiWindowFlags_NoTitleBar)) + IMGUI_TEST_ENGINE_ITEM_ADD(window->DC.LastItemRect, window->DC.LastItemId); +#endif + } + else + { + // Append + SetCurrentViewport(window, window->Viewport); + SetCurrentWindow(window); + } + + if (!(flags & ImGuiWindowFlags_DockNodeHost)) + PushClipRect(window->InnerClipRect.Min, window->InnerClipRect.Max, true); + + // Clear 'accessed' flag last thing (After PushClipRect which will set the flag. We want the flag to stay false when the default "Debug" window is unused) + if (first_begin_of_the_frame) + window->WriteAccessed = false; + + window->BeginCount++; + g.NextWindowData.ClearFlags(); + + // When we are about to select this tab (which will only be visible on the _next frame_), flag it with a non-zero HiddenFramesCannotSkipItems. + // This will have the important effect of actually returning true in Begin() and not setting SkipItems, allowing an earlier submission of the window contents. + // This is analogous to regular windows being hidden from one frame. + // It is especially important as e.g. nested TabBars would otherwise generate flicker in the form of one empty frame, or focus requests won't be processed. + if (window->DockIsActive && !window->DockTabIsVisible) + { + if (window->LastFrameJustFocused == g.FrameCount) + window->HiddenFramesCannotSkipItems = 1; + else + window->HiddenFramesCanSkipItems = 1; + } + + if (flags & ImGuiWindowFlags_ChildWindow) + { + // Child window can be out of sight and have "negative" clip windows. + // Mark them as collapsed so commands are skipped earlier (we can't manually collapse them because they have no title bar). + IM_ASSERT((flags & ImGuiWindowFlags_NoTitleBar) != 0 || (window->DockIsActive)); + if (!(flags & ImGuiWindowFlags_AlwaysAutoResize) && window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0) + if (window->OuterRectClipped.Min.x >= window->OuterRectClipped.Max.x || window->OuterRectClipped.Min.y >= window->OuterRectClipped.Max.y) + window->HiddenFramesCanSkipItems = 1; + + // Hide along with parent or if parent is collapsed + if (parent_window && (parent_window->Collapsed || parent_window->HiddenFramesCanSkipItems > 0)) + window->HiddenFramesCanSkipItems = 1; + if (parent_window && (parent_window->Collapsed || parent_window->HiddenFramesCannotSkipItems > 0)) + window->HiddenFramesCannotSkipItems = 1; + } + + // Don't render if style alpha is 0.0 at the time of Begin(). This is arbitrary and inconsistent but has been there for a long while (may remove at some point) + if (style.Alpha <= 0.0f) + window->HiddenFramesCanSkipItems = 1; + + // Update the Hidden flag + window->Hidden = (window->HiddenFramesCanSkipItems > 0) || (window->HiddenFramesCannotSkipItems > 0); + + // Update the SkipItems flag, used to early out of all items functions (no layout required) + bool skip_items = false; + if (window->Collapsed || !window->Active || window->Hidden) + if (window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0 && window->HiddenFramesCannotSkipItems <= 0) + skip_items = true; + window->SkipItems = skip_items; + + return !skip_items; +} + +void ImGui::End() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + + // Error checking: verify that user hasn't called End() too many times! + if (g.CurrentWindowStack.Size <= 1 && g.WithinFrameScopeWithImplicitWindow) + { + IM_ASSERT_USER_ERROR(g.CurrentWindowStack.Size > 1, "Calling End() too many times!"); + return; + } + IM_ASSERT(g.CurrentWindowStack.Size > 0); + + // Error checking: verify that user doesn't directly call End() on a child window. + if ((window->Flags & ImGuiWindowFlags_ChildWindow) && !window->DockIsActive) + IM_ASSERT_USER_ERROR(g.WithinEndChild, "Must call EndChild() and not End()!"); + + // Close anything that is open + if (window->DC.CurrentColumns) + EndColumns(); + if (!(window->Flags & ImGuiWindowFlags_DockNodeHost)) // Pop inner window clip rectangle + PopClipRect(); + + // Stop logging + if (!(window->Flags & ImGuiWindowFlags_ChildWindow)) // FIXME: add more options for scope of logging + LogFinish(); + + // Docking: report contents sizes to parent to allow for auto-resize + if (window->DockNode && window->DockTabIsVisible) + if (ImGuiWindow* host_window = window->DockNode->HostWindow) // FIXME-DOCK + host_window->DC.CursorMaxPos = window->DC.CursorMaxPos + window->WindowPadding - host_window->WindowPadding; + + // Pop from window stack + g.CurrentWindowStack.pop_back(); + if (window->Flags & ImGuiWindowFlags_Popup) + g.BeginPopupStack.pop_back(); + ErrorCheckBeginEndCompareStacksSize(window, false); + SetCurrentWindow(g.CurrentWindowStack.empty() ? NULL : g.CurrentWindowStack.back()); + if (g.CurrentWindow) + SetCurrentViewport(g.CurrentWindow, g.CurrentWindow->Viewport); +} + +void ImGui::BringWindowToFocusFront(ImGuiWindow* window) +{ + ImGuiContext& g = *GImGui; + if (g.WindowsFocusOrder.back() == window) + return; + for (int i = g.WindowsFocusOrder.Size - 2; i >= 0; i--) // We can ignore the top-most window + if (g.WindowsFocusOrder[i] == window) + { + memmove(&g.WindowsFocusOrder[i], &g.WindowsFocusOrder[i + 1], (size_t)(g.WindowsFocusOrder.Size - i - 1) * sizeof(ImGuiWindow*)); + g.WindowsFocusOrder[g.WindowsFocusOrder.Size - 1] = window; + break; + } +} + +void ImGui::BringWindowToDisplayFront(ImGuiWindow* window) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* current_front_window = g.Windows.back(); + if (current_front_window == window || current_front_window->RootWindow == window) + return; + for (int i = g.Windows.Size - 2; i >= 0; i--) // We can ignore the top-most window + if (g.Windows[i] == window) + { + memmove(&g.Windows[i], &g.Windows[i + 1], (size_t)(g.Windows.Size - i - 1) * sizeof(ImGuiWindow*)); + g.Windows[g.Windows.Size - 1] = window; + break; + } +} + +void ImGui::BringWindowToDisplayBack(ImGuiWindow* window) +{ + ImGuiContext& g = *GImGui; + if (g.Windows[0] == window) + return; + for (int i = 0; i < g.Windows.Size; i++) + if (g.Windows[i] == window) + { + memmove(&g.Windows[1], &g.Windows[0], (size_t)i * sizeof(ImGuiWindow*)); + g.Windows[0] = window; + break; + } +} + +// Moving window to front of display and set focus (which happens to be back of our sorted list) +void ImGui::FocusWindow(ImGuiWindow* window) +{ + ImGuiContext& g = *GImGui; + + if (g.NavWindow != window) + { + g.NavWindow = window; + if (window && g.NavDisableMouseHover) + g.NavMousePosDirty = true; + g.NavInitRequest = false; + g.NavId = window ? window->NavLastIds[0] : 0; // Restore NavId + g.NavFocusScopeId = 0; + g.NavIdIsAlive = false; + g.NavLayer = ImGuiNavLayer_Main; + //IMGUI_DEBUG_LOG("FocusWindow(\"%s\")\n", window ? window->Name : NULL); + } + + // Close popups if any + ClosePopupsOverWindow(window, false); + + // Move the root window to the top of the pile + IM_ASSERT(window == NULL || window->RootWindow != NULL); + ImGuiWindow* focus_front_window = window ? window->RootWindowDockStop : NULL; + ImGuiWindow* display_front_window = window ? window->RootWindow : NULL; + ImGuiDockNode* dock_node = window ? window->DockNode : NULL; + bool active_id_window_is_dock_node_host = (g.ActiveIdWindow && dock_node && dock_node->HostWindow == g.ActiveIdWindow); + + // Steal active widgets. Some of the cases it triggers includes: + // - Focus a window while an InputText in another window is active, if focus happens before the old InputText can run. + // - When using Nav to activate menu items (due to timing of activating on press->new window appears->losing ActiveId) + // - Using dock host items (tab, collapse button) can trigger this before we redirect the ActiveIdWindow toward the child window. + if (g.ActiveId != 0 && g.ActiveIdWindow && g.ActiveIdWindow->RootWindowDockStop != focus_front_window && !active_id_window_is_dock_node_host) + ClearActiveID(); + + // Passing NULL allow to disable keyboard focus + if (!window) + return; + window->LastFrameJustFocused = g.FrameCount; + + // Select in dock node + if (dock_node && dock_node->TabBar) + dock_node->TabBar->SelectedTabId = dock_node->TabBar->NextSelectedTabId = window->ID; + + // Bring to front + BringWindowToFocusFront(focus_front_window); + if (((window->Flags | focus_front_window->Flags | display_front_window->Flags) & ImGuiWindowFlags_NoBringToFrontOnFocus) == 0) + BringWindowToDisplayFront(display_front_window); +} + +void ImGui::FocusTopMostWindowUnderOne(ImGuiWindow* under_this_window, ImGuiWindow* ignore_window) +{ + ImGuiContext& g = *GImGui; + + int start_idx = g.WindowsFocusOrder.Size - 1; + if (under_this_window != NULL) + { + int under_this_window_idx = FindWindowFocusIndex(under_this_window); + if (under_this_window_idx != -1) + start_idx = under_this_window_idx - 1; + } + for (int i = start_idx; i >= 0; i--) + { + // We may later decide to test for different NoXXXInputs based on the active navigation input (mouse vs nav) but that may feel more confusing to the user. + ImGuiWindow* window = g.WindowsFocusOrder[i]; + if (window != ignore_window && window->WasActive && window->RootWindowDockStop == window) + if ((window->Flags & (ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_NoNavInputs)) != (ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_NoNavInputs)) + { + // FIXME-DOCK: This is failing (lagging by one frame) for docked windows. + // If A and B are docked into window and B disappear, at the NewFrame() call site window->NavLastChildNavWindow will still point to B. + // We might leverage the tab order implicitly stored in window->DockNodeAsHost->TabBar (essentially the 'most_recently_selected_tab' code in tab bar will do that but on next update) + // to tell which is the "previous" window. Or we may leverage 'LastFrameFocused/LastFrameJustFocused' and have this function handle child window itself? + ImGuiWindow* focus_window = NavRestoreLastChildNavWindow(window); + FocusWindow(focus_window); + return; + } + } + FocusWindow(NULL); +} + +void ImGui::SetCurrentFont(ImFont* font) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(font && font->IsLoaded()); // Font Atlas not created. Did you call io.Fonts->GetTexDataAsRGBA32 / GetTexDataAsAlpha8 ? + IM_ASSERT(font->Scale > 0.0f); + g.Font = font; + g.FontBaseSize = ImMax(1.0f, g.IO.FontGlobalScale * g.Font->FontSize * g.Font->Scale); + g.FontSize = g.CurrentWindow ? g.CurrentWindow->CalcFontSize() : 0.0f; + + ImFontAtlas* atlas = g.Font->ContainerAtlas; + g.DrawListSharedData.TexUvWhitePixel = atlas->TexUvWhitePixel; + g.DrawListSharedData.Font = g.Font; + g.DrawListSharedData.FontSize = g.FontSize; +} + +void ImGui::PushFont(ImFont* font) +{ + ImGuiContext& g = *GImGui; + if (!font) + font = GetDefaultFont(); + SetCurrentFont(font); + g.FontStack.push_back(font); + g.CurrentWindow->DrawList->PushTextureID(font->ContainerAtlas->TexID); +} + +void ImGui::PopFont() +{ + ImGuiContext& g = *GImGui; + g.CurrentWindow->DrawList->PopTextureID(); + g.FontStack.pop_back(); + SetCurrentFont(g.FontStack.empty() ? GetDefaultFont() : g.FontStack.back()); +} + +void ImGui::PushItemFlag(ImGuiItemFlags option, bool enabled) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (enabled) + window->DC.ItemFlags |= option; + else + window->DC.ItemFlags &= ~option; + window->DC.ItemFlagsStack.push_back(window->DC.ItemFlags); +} + +void ImGui::PopItemFlag() +{ + ImGuiWindow* window = GetCurrentWindow(); + window->DC.ItemFlagsStack.pop_back(); + window->DC.ItemFlags = window->DC.ItemFlagsStack.empty() ? ImGuiItemFlags_Default_ : window->DC.ItemFlagsStack.back(); +} + +// FIXME: Look into renaming this once we have settled the new Focus/Activation/TabStop system. +void ImGui::PushAllowKeyboardFocus(bool allow_keyboard_focus) +{ + PushItemFlag(ImGuiItemFlags_NoTabStop, !allow_keyboard_focus); +} + +void ImGui::PopAllowKeyboardFocus() +{ + PopItemFlag(); +} + +void ImGui::PushButtonRepeat(bool repeat) +{ + PushItemFlag(ImGuiItemFlags_ButtonRepeat, repeat); +} + +void ImGui::PopButtonRepeat() +{ + PopItemFlag(); +} + +void ImGui::PushTextWrapPos(float wrap_pos_x) +{ + ImGuiWindow* window = GetCurrentWindow(); + window->DC.TextWrapPos = wrap_pos_x; + window->DC.TextWrapPosStack.push_back(wrap_pos_x); +} + +void ImGui::PopTextWrapPos() +{ + ImGuiWindow* window = GetCurrentWindow(); + window->DC.TextWrapPosStack.pop_back(); + window->DC.TextWrapPos = window->DC.TextWrapPosStack.empty() ? -1.0f : window->DC.TextWrapPosStack.back(); +} + +bool ImGui::IsWindowChildOf(ImGuiWindow* window, ImGuiWindow* potential_parent) +{ + if (window->RootWindow == potential_parent) + return true; + while (window != NULL) + { + if (window == potential_parent) + return true; + window = window->ParentWindow; + } + return false; +} + +bool ImGui::IsWindowHovered(ImGuiHoveredFlags flags) +{ + IM_ASSERT((flags & ImGuiHoveredFlags_AllowWhenOverlapped) == 0); // Flags not supported by this function + ImGuiContext& g = *GImGui; + + if (flags & ImGuiHoveredFlags_AnyWindow) + { + if (g.HoveredWindow == NULL) + return false; + } + else + { + switch (flags & (ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_ChildWindows)) + { + case ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_ChildWindows: + if (g.HoveredWindow == NULL || g.HoveredWindow->RootWindowDockStop != g.CurrentWindow->RootWindowDockStop) + return false; + break; + case ImGuiHoveredFlags_RootWindow: + if (g.HoveredWindow != g.CurrentWindow->RootWindowDockStop) + return false; + break; + case ImGuiHoveredFlags_ChildWindows: + if (g.HoveredWindow == NULL || !IsWindowChildOf(g.HoveredWindow, g.CurrentWindow)) + return false; + break; + default: + if (g.HoveredWindow != g.CurrentWindow) + return false; + break; + } + } + + if (!IsWindowContentHoverable(g.HoveredWindow, flags)) + return false; + if (!(flags & ImGuiHoveredFlags_AllowWhenBlockedByActiveItem)) + if (g.ActiveId != 0 && !g.ActiveIdAllowOverlap && g.ActiveId != g.HoveredWindow->MoveId) + return false; + return true; +} + +bool ImGui::IsWindowFocused(ImGuiFocusedFlags flags) +{ + ImGuiContext& g = *GImGui; + + if (flags & ImGuiFocusedFlags_AnyWindow) + return g.NavWindow != NULL; + + IM_ASSERT(g.CurrentWindow); // Not inside a Begin()/End() + switch (flags & (ImGuiFocusedFlags_RootWindow | ImGuiFocusedFlags_ChildWindows)) + { + case ImGuiFocusedFlags_RootWindow | ImGuiFocusedFlags_ChildWindows: + return g.NavWindow && g.NavWindow->RootWindowDockStop == g.CurrentWindow->RootWindowDockStop; + case ImGuiFocusedFlags_RootWindow: + return g.NavWindow == g.CurrentWindow->RootWindowDockStop; + case ImGuiFocusedFlags_ChildWindows: + return g.NavWindow && IsWindowChildOf(g.NavWindow, g.CurrentWindow); + default: + return g.NavWindow == g.CurrentWindow; + } +} + +ImGuiID ImGui::GetWindowDockID() +{ + ImGuiContext& g = *GImGui; + return g.CurrentWindow->DockId; +} + +bool ImGui::IsWindowDocked() +{ + ImGuiContext& g = *GImGui; + return g.CurrentWindow->DockIsActive; +} + +// Can we focus this window with CTRL+TAB (or PadMenu + PadFocusPrev/PadFocusNext) +// Note that NoNavFocus makes the window not reachable with CTRL+TAB but it can still be focused with mouse or programmatically. +// If you want a window to never be focused, you may use the e.g. NoInputs flag. +bool ImGui::IsWindowNavFocusable(ImGuiWindow* window) +{ + return window->Active && window == window->RootWindowDockStop && !(window->Flags & ImGuiWindowFlags_NoNavFocus); +} + +float ImGui::GetWindowWidth() +{ + ImGuiWindow* window = GImGui->CurrentWindow; + return window->Size.x; +} + +float ImGui::GetWindowHeight() +{ + ImGuiWindow* window = GImGui->CurrentWindow; + return window->Size.y; +} + +ImVec2 ImGui::GetWindowPos() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + return window->Pos; +} + +void ImGui::SetWindowPos(ImGuiWindow* window, const ImVec2& pos, ImGuiCond cond) +{ + // Test condition (NB: bit 0 is always true) and clear flags for next time + if (cond && (window->SetWindowPosAllowFlags & cond) == 0) + return; + + IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags. + window->SetWindowPosAllowFlags &= ~(ImGuiCond_Once | ImGuiCond_FirstUseEver | ImGuiCond_Appearing); + window->SetWindowPosVal = ImVec2(FLT_MAX, FLT_MAX); + + // Set + const ImVec2 old_pos = window->Pos; + window->Pos = ImFloor(pos); + ImVec2 offset = window->Pos - old_pos; + window->DC.CursorPos += offset; // As we happen to move the window while it is being appended to (which is a bad idea - will smear) let's at least offset the cursor + window->DC.CursorMaxPos += offset; // And more importantly we need to offset CursorMaxPos/CursorStartPos this so ContentSize calculation doesn't get affected. + window->DC.CursorStartPos += offset; +} + +void ImGui::SetWindowPos(const ImVec2& pos, ImGuiCond cond) +{ + ImGuiWindow* window = GetCurrentWindowRead(); + SetWindowPos(window, pos, cond); +} + +void ImGui::SetWindowPos(const char* name, const ImVec2& pos, ImGuiCond cond) +{ + if (ImGuiWindow* window = FindWindowByName(name)) + SetWindowPos(window, pos, cond); +} + +ImVec2 ImGui::GetWindowSize() +{ + ImGuiWindow* window = GetCurrentWindowRead(); + return window->Size; +} + +void ImGui::SetWindowSize(ImGuiWindow* window, const ImVec2& size, ImGuiCond cond) +{ + // Test condition (NB: bit 0 is always true) and clear flags for next time + if (cond && (window->SetWindowSizeAllowFlags & cond) == 0) + return; + + IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags. + window->SetWindowSizeAllowFlags &= ~(ImGuiCond_Once | ImGuiCond_FirstUseEver | ImGuiCond_Appearing); + + // Set + if (size.x > 0.0f) + { + window->AutoFitFramesX = 0; + window->SizeFull.x = IM_FLOOR(size.x); + } + else + { + window->AutoFitFramesX = 2; + window->AutoFitOnlyGrows = false; + } + if (size.y > 0.0f) + { + window->AutoFitFramesY = 0; + window->SizeFull.y = IM_FLOOR(size.y); + } + else + { + window->AutoFitFramesY = 2; + window->AutoFitOnlyGrows = false; + } +} + +void ImGui::SetWindowSize(const ImVec2& size, ImGuiCond cond) +{ + SetWindowSize(GImGui->CurrentWindow, size, cond); +} + +void ImGui::SetWindowSize(const char* name, const ImVec2& size, ImGuiCond cond) +{ + if (ImGuiWindow* window = FindWindowByName(name)) + SetWindowSize(window, size, cond); +} + +void ImGui::SetWindowCollapsed(ImGuiWindow* window, bool collapsed, ImGuiCond cond) +{ + // Test condition (NB: bit 0 is always true) and clear flags for next time + if (cond && (window->SetWindowCollapsedAllowFlags & cond) == 0) + return; + window->SetWindowCollapsedAllowFlags &= ~(ImGuiCond_Once | ImGuiCond_FirstUseEver | ImGuiCond_Appearing); + + // Set + window->Collapsed = collapsed; +} + +void ImGui::SetWindowHitTestHole(ImGuiWindow* window, const ImVec2& pos, const ImVec2& size) +{ + IM_ASSERT(window->HitTestHoleSize.x == 0); // We don't support multiple holes/hit test filters + window->HitTestHoleSize = ImVec2ih(size); + window->HitTestHoleOffset = ImVec2ih(pos - window->Pos); +} + +void ImGui::SetWindowCollapsed(bool collapsed, ImGuiCond cond) +{ + SetWindowCollapsed(GImGui->CurrentWindow, collapsed, cond); +} + +bool ImGui::IsWindowCollapsed() +{ + ImGuiWindow* window = GetCurrentWindowRead(); + return window->Collapsed; +} + +bool ImGui::IsWindowAppearing() +{ + ImGuiWindow* window = GetCurrentWindowRead(); + return window->Appearing; +} + +void ImGui::SetWindowCollapsed(const char* name, bool collapsed, ImGuiCond cond) +{ + if (ImGuiWindow* window = FindWindowByName(name)) + SetWindowCollapsed(window, collapsed, cond); +} + +void ImGui::SetWindowFocus() +{ + FocusWindow(GImGui->CurrentWindow); +} + +void ImGui::SetWindowFocus(const char* name) +{ + if (name) + { + if (ImGuiWindow* window = FindWindowByName(name)) + FocusWindow(window); + } + else + { + FocusWindow(NULL); + } +} + +void ImGui::SetNextWindowPos(const ImVec2& pos, ImGuiCond cond, const ImVec2& pivot) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags. + g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasPos; + g.NextWindowData.PosVal = pos; + g.NextWindowData.PosPivotVal = pivot; + g.NextWindowData.PosCond = cond ? cond : ImGuiCond_Always; + g.NextWindowData.PosUndock = true; +} + +void ImGui::SetNextWindowSize(const ImVec2& size, ImGuiCond cond) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags. + g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasSize; + g.NextWindowData.SizeVal = size; + g.NextWindowData.SizeCond = cond ? cond : ImGuiCond_Always; +} + +void ImGui::SetNextWindowSizeConstraints(const ImVec2& size_min, const ImVec2& size_max, ImGuiSizeCallback custom_callback, void* custom_callback_user_data) +{ + ImGuiContext& g = *GImGui; + g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasSizeConstraint; + g.NextWindowData.SizeConstraintRect = ImRect(size_min, size_max); + g.NextWindowData.SizeCallback = custom_callback; + g.NextWindowData.SizeCallbackUserData = custom_callback_user_data; +} + +// Content size = inner scrollable rectangle, padded with WindowPadding. +// SetNextWindowContentSize(ImVec2(100,100) + ImGuiWindowFlags_AlwaysAutoResize will always allow submitting a 100x100 item. +void ImGui::SetNextWindowContentSize(const ImVec2& size) +{ + ImGuiContext& g = *GImGui; + g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasContentSize; + g.NextWindowData.ContentSizeVal = size; +} + +void ImGui::SetNextWindowScroll(const ImVec2& scroll) +{ + ImGuiContext& g = *GImGui; + g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasScroll; + g.NextWindowData.ScrollVal = scroll; +} + +void ImGui::SetNextWindowCollapsed(bool collapsed, ImGuiCond cond) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags. + g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasCollapsed; + g.NextWindowData.CollapsedVal = collapsed; + g.NextWindowData.CollapsedCond = cond ? cond : ImGuiCond_Always; +} + +void ImGui::SetNextWindowFocus() +{ + ImGuiContext& g = *GImGui; + g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasFocus; +} + +void ImGui::SetNextWindowBgAlpha(float alpha) +{ + ImGuiContext& g = *GImGui; + g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasBgAlpha; + g.NextWindowData.BgAlphaVal = alpha; +} + +void ImGui::SetNextWindowViewport(ImGuiID id) +{ + ImGuiContext& g = *GImGui; + g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasViewport; + g.NextWindowData.ViewportId = id; +} + +void ImGui::SetNextWindowDockID(ImGuiID id, ImGuiCond cond) +{ + ImGuiContext& g = *GImGui; + g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasDock; + g.NextWindowData.DockCond = cond ? cond : ImGuiCond_Always; + g.NextWindowData.DockId = id; +} + +void ImGui::SetNextWindowClass(const ImGuiWindowClass* window_class) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT((window_class->ViewportFlagsOverrideSet & window_class->ViewportFlagsOverrideClear) == 0); // Cannot set both set and clear for the same bit + g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasWindowClass; + g.NextWindowData.WindowClass = *window_class; +} + +ImDrawList* ImGui::GetWindowDrawList() +{ + ImGuiWindow* window = GetCurrentWindow(); + return window->DrawList; +} + +float ImGui::GetWindowDpiScale() +{ + ImGuiContext& g = *GImGui; + return g.CurrentDpiScale; +} + +ImGuiViewport* ImGui::GetWindowViewport() +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(g.CurrentViewport != NULL && g.CurrentViewport == g.CurrentWindow->Viewport); + return g.CurrentViewport; +} + +ImFont* ImGui::GetFont() +{ + return GImGui->Font; +} + +float ImGui::GetFontSize() +{ + return GImGui->FontSize; +} + +ImVec2 ImGui::GetFontTexUvWhitePixel() +{ + return GImGui->DrawListSharedData.TexUvWhitePixel; +} + +void ImGui::SetWindowFontScale(float scale) +{ + IM_ASSERT(scale > 0.0f); + ImGuiContext& g = *GImGui; + ImGuiWindow* window = GetCurrentWindow(); + window->FontWindowScale = scale; + g.FontSize = g.DrawListSharedData.FontSize = window->CalcFontSize(); +} + +void ImGui::ActivateItem(ImGuiID id) +{ + ImGuiContext& g = *GImGui; + g.NavNextActivateId = id; +} + +// Note: this is storing in same stack as IDStack, so Push/Pop mismatch will be reported there. +void ImGui::PushFocusScope(ImGuiID id) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + window->IDStack.push_back(window->DC.NavFocusScopeIdCurrent); + window->DC.NavFocusScopeIdCurrent = id; +} + +void ImGui::PopFocusScope() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + window->DC.NavFocusScopeIdCurrent = window->IDStack.back(); + window->IDStack.pop_back(); +} + +void ImGui::SetKeyboardFocusHere(int offset) +{ + IM_ASSERT(offset >= -1); // -1 is allowed but not below + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + g.FocusRequestNextWindow = window; + g.FocusRequestNextCounterRegular = window->DC.FocusCounterRegular + 1 + offset; + g.FocusRequestNextCounterTabStop = INT_MAX; +} + +void ImGui::SetItemDefaultFocus() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if (!window->Appearing) + return; + if (g.NavWindow == window->RootWindowForNav && (g.NavInitRequest || g.NavInitResultId != 0) && g.NavLayer == g.NavWindow->DC.NavLayerCurrent) + { + g.NavInitRequest = false; + g.NavInitResultId = g.NavWindow->DC.LastItemId; + g.NavInitResultRectRel = ImRect(g.NavWindow->DC.LastItemRect.Min - g.NavWindow->Pos, g.NavWindow->DC.LastItemRect.Max - g.NavWindow->Pos); + NavUpdateAnyRequestFlag(); + if (!IsItemVisible()) + SetScrollHereY(); + } +} + +void ImGui::SetStateStorage(ImGuiStorage* tree) +{ + ImGuiWindow* window = GImGui->CurrentWindow; + window->DC.StateStorage = tree ? tree : &window->StateStorage; +} + +ImGuiStorage* ImGui::GetStateStorage() +{ + ImGuiWindow* window = GImGui->CurrentWindow; + return window->DC.StateStorage; +} + +void ImGui::PushID(const char* str_id) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + ImGuiID id = window->GetIDNoKeepAlive(str_id); + window->IDStack.push_back(id); +} + +void ImGui::PushID(const char* str_id_begin, const char* str_id_end) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + ImGuiID id = window->GetIDNoKeepAlive(str_id_begin, str_id_end); + window->IDStack.push_back(id); +} + +void ImGui::PushID(const void* ptr_id) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + ImGuiID id = window->GetIDNoKeepAlive(ptr_id); + window->IDStack.push_back(id); +} + +void ImGui::PushID(int int_id) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + ImGuiID id = window->GetIDNoKeepAlive(int_id); + window->IDStack.push_back(id); +} + +// Push a given id value ignoring the ID stack as a seed. +void ImGui::PushOverrideID(ImGuiID id) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + window->IDStack.push_back(id); +} + +void ImGui::PopID() +{ + ImGuiWindow* window = GImGui->CurrentWindow; + window->IDStack.pop_back(); +} + +ImGuiID ImGui::GetID(const char* str_id) +{ + ImGuiWindow* window = GImGui->CurrentWindow; + return window->GetID(str_id); +} + +ImGuiID ImGui::GetID(const char* str_id_begin, const char* str_id_end) +{ + ImGuiWindow* window = GImGui->CurrentWindow; + return window->GetID(str_id_begin, str_id_end); +} + +ImGuiID ImGui::GetID(const void* ptr_id) +{ + ImGuiWindow* window = GImGui->CurrentWindow; + return window->GetID(ptr_id); +} + +bool ImGui::IsRectVisible(const ImVec2& size) +{ + ImGuiWindow* window = GImGui->CurrentWindow; + return window->ClipRect.Overlaps(ImRect(window->DC.CursorPos, window->DC.CursorPos + size)); +} + +bool ImGui::IsRectVisible(const ImVec2& rect_min, const ImVec2& rect_max) +{ + ImGuiWindow* window = GImGui->CurrentWindow; + return window->ClipRect.Overlaps(ImRect(rect_min, rect_max)); +} + + +//----------------------------------------------------------------------------- +// [SECTION] ERROR CHECKING +//----------------------------------------------------------------------------- + +// Helper function to verify ABI compatibility between caller code and compiled version of Dear ImGui. +// Verify that the type sizes are matching between the calling file's compilation unit and imgui.cpp's compilation unit +// If the user has inconsistent compilation settings, imgui configuration #define, packing pragma, etc. your user code +// may see different structures than what imgui.cpp sees, which is problematic. +// We usually require settings to be in imconfig.h to make sure that they are accessible to all compilation units involved with Dear ImGui. +bool ImGui::DebugCheckVersionAndDataLayout(const char* version, size_t sz_io, size_t sz_style, size_t sz_vec2, size_t sz_vec4, size_t sz_vert, size_t sz_idx) +{ + bool error = false; + if (strcmp(version, IMGUI_VERSION) != 0) { error = true; IM_ASSERT(strcmp(version, IMGUI_VERSION) == 0 && "Mismatched version string!"); } + if (sz_io != sizeof(ImGuiIO)) { error = true; IM_ASSERT(sz_io == sizeof(ImGuiIO) && "Mismatched struct layout!"); } + if (sz_style != sizeof(ImGuiStyle)) { error = true; IM_ASSERT(sz_style == sizeof(ImGuiStyle) && "Mismatched struct layout!"); } + if (sz_vec2 != sizeof(ImVec2)) { error = true; IM_ASSERT(sz_vec2 == sizeof(ImVec2) && "Mismatched struct layout!"); } + if (sz_vec4 != sizeof(ImVec4)) { error = true; IM_ASSERT(sz_vec4 == sizeof(ImVec4) && "Mismatched struct layout!"); } + if (sz_vert != sizeof(ImDrawVert)) { error = true; IM_ASSERT(sz_vert == sizeof(ImDrawVert) && "Mismatched struct layout!"); } + if (sz_idx != sizeof(ImDrawIdx)) { error = true; IM_ASSERT(sz_idx == sizeof(ImDrawIdx) && "Mismatched struct layout!"); } + return !error; +} + +static void ImGui::ErrorCheckNewFrameSanityChecks() +{ + ImGuiContext& g = *GImGui; + + // Check user IM_ASSERT macro + // (IF YOU GET A WARNING OR COMPILE ERROR HERE: it means you assert macro is incorrectly defined! + // If your macro uses multiple statements, it NEEDS to be surrounded by a 'do { ... } while (0)' block. + // This is a common C/C++ idiom to allow multiple statements macros to be used in control flow blocks.) + // #define IM_ASSERT(EXPR) SomeCode(EXPR); SomeMoreCode(); // Wrong! + // #define IM_ASSERT(EXPR) do { SomeCode(EXPR); SomeMoreCode(); } while (0) // Correct! + if (true) IM_ASSERT(1); else IM_ASSERT(0); + + // Check user data + // (We pass an error message in the assert expression to make it visible to programmers who are not using a debugger, as most assert handlers display their argument) + IM_ASSERT(g.Initialized); + IM_ASSERT((g.IO.DeltaTime > 0.0f || g.FrameCount == 0) && "Need a positive DeltaTime!"); + IM_ASSERT((g.FrameCount == 0 || g.FrameCountEnded == g.FrameCount) && "Forgot to call Render() or EndFrame() at the end of the previous frame?"); + IM_ASSERT(g.IO.DisplaySize.x >= 0.0f && g.IO.DisplaySize.y >= 0.0f && "Invalid DisplaySize value!"); + IM_ASSERT(g.IO.Fonts->Fonts.Size > 0 && "Font Atlas not built. Did you call io.Fonts->GetTexDataAsRGBA32() / GetTexDataAsAlpha8() ?"); + IM_ASSERT(g.IO.Fonts->Fonts[0]->IsLoaded() && "Font Atlas not built. Did you call io.Fonts->GetTexDataAsRGBA32() / GetTexDataAsAlpha8() ?"); + IM_ASSERT(g.Style.CurveTessellationTol > 0.0f && "Invalid style setting!"); + IM_ASSERT(g.Style.CircleSegmentMaxError > 0.0f && "Invalid style setting!"); + IM_ASSERT(g.Style.Alpha >= 0.0f && g.Style.Alpha <= 1.0f && "Invalid style setting. Alpha cannot be negative (allows us to avoid a few clamps in color computations)!"); + IM_ASSERT(g.Style.WindowMinSize.x >= 1.0f && g.Style.WindowMinSize.y >= 1.0f && "Invalid style setting."); + IM_ASSERT(g.Style.WindowMenuButtonPosition == ImGuiDir_None || g.Style.WindowMenuButtonPosition == ImGuiDir_Left || g.Style.WindowMenuButtonPosition == ImGuiDir_Right); + for (int n = 0; n < ImGuiKey_COUNT; n++) + IM_ASSERT(g.IO.KeyMap[n] >= -1 && g.IO.KeyMap[n] < IM_ARRAYSIZE(g.IO.KeysDown) && "io.KeyMap[] contains an out of bound value (need to be 0..512, or -1 for unmapped key)"); + + // Perform simple check: required key mapping (we intentionally do NOT check all keys to not pressure user into setting up everything, but Space is required and was only recently added in 1.60 WIP) + if (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) + IM_ASSERT(g.IO.KeyMap[ImGuiKey_Space] != -1 && "ImGuiKey_Space is not mapped, required for keyboard navigation."); + + // Perform simple check: the beta io.ConfigWindowsResizeFromEdges option requires back-end to honor mouse cursor changes and set the ImGuiBackendFlags_HasMouseCursors flag accordingly. + if (g.IO.ConfigWindowsResizeFromEdges && !(g.IO.BackendFlags & ImGuiBackendFlags_HasMouseCursors)) + g.IO.ConfigWindowsResizeFromEdges = false; + + // Perform simple check: error if Docking or Viewport are enabled _exactly_ on frame 1 (instead of frame 0 or later), which is a common error leading to loss of .ini data. + if (g.FrameCount == 1 && (g.IO.ConfigFlags & ImGuiConfigFlags_DockingEnable) && (g.ConfigFlagsLastFrame & ImGuiConfigFlags_DockingEnable) == 0) + IM_ASSERT(0 && "Please set DockingEnable before the first call to NewFrame()! Otherwise you will lose your .ini settings!"); + if (g.FrameCount == 1 && (g.IO.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) && (g.ConfigFlagsLastFrame & ImGuiConfigFlags_ViewportsEnable) == 0) + IM_ASSERT(0 && "Please set ViewportsEnable before the first call to NewFrame()! Otherwise you will lose your .ini settings!"); + + // Perform simple checks: multi-viewport and platform windows support + if (g.IO.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) + { + if ((g.IO.BackendFlags & ImGuiBackendFlags_PlatformHasViewports) && (g.IO.BackendFlags & ImGuiBackendFlags_RendererHasViewports)) + { + IM_ASSERT((g.FrameCount == 0 || g.FrameCount == g.FrameCountPlatformEnded) && "Forgot to call UpdatePlatformWindows() in main loop after EndFrame()? Check examples/ applications for reference."); + IM_ASSERT(g.PlatformIO.Platform_CreateWindow != NULL && "Platform init didn't install handlers?"); + IM_ASSERT(g.PlatformIO.Platform_DestroyWindow != NULL && "Platform init didn't install handlers?"); + IM_ASSERT(g.PlatformIO.Platform_GetWindowPos != NULL && "Platform init didn't install handlers?"); + IM_ASSERT(g.PlatformIO.Platform_SetWindowPos != NULL && "Platform init didn't install handlers?"); + IM_ASSERT(g.PlatformIO.Platform_GetWindowSize != NULL && "Platform init didn't install handlers?"); + IM_ASSERT(g.PlatformIO.Platform_SetWindowSize != NULL && "Platform init didn't install handlers?"); + IM_ASSERT(g.PlatformIO.Monitors.Size > 0 && "Platform init didn't setup Monitors list?"); + IM_ASSERT((g.Viewports[0]->PlatformUserData != NULL || g.Viewports[0]->PlatformHandle != NULL) && "Platform init didn't setup main viewport."); + if (g.IO.ConfigDockingTransparentPayload && (g.IO.ConfigFlags & ImGuiConfigFlags_DockingEnable)) + IM_ASSERT(g.PlatformIO.Platform_SetWindowAlpha != NULL && "Platform_SetWindowAlpha handler is required to use io.ConfigDockingTransparent!"); +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + IM_ASSERT(g.IO.RenderDrawListsFn == NULL); // Call ImGui::Render() then pass ImGui::GetDrawData() yourself to your render function! +#endif + } + else + { + // Disable feature, our back-ends do not support it + g.IO.ConfigFlags &= ~ImGuiConfigFlags_ViewportsEnable; + } + + // Perform simple checks on platform monitor data + compute a total bounding box for quick early outs + for (int monitor_n = 0; monitor_n < g.PlatformIO.Monitors.Size; monitor_n++) + { + ImGuiPlatformMonitor& mon = g.PlatformIO.Monitors[monitor_n]; + IM_UNUSED(mon); + IM_ASSERT(mon.MainSize.x > 0.0f && mon.MainSize.y > 0.0f && "Monitor bounds not setup properly."); + IM_ASSERT(mon.WorkSize.x > 0.0f && mon.WorkSize.y > 0.0f && "Monitor bounds not setup properly. If you don't have work area information, just copy Min/Max into them."); + IM_ASSERT(mon.DpiScale != 0.0f); + } + } +} + +static void ImGui::ErrorCheckEndFrameSanityChecks() +{ + ImGuiContext& g = *GImGui; + + // Verify that io.KeyXXX fields haven't been tampered with. Key mods should not be modified between NewFrame() and EndFrame() + // One possible reason leading to this assert is that your back-ends update inputs _AFTER_ NewFrame(). + const ImGuiKeyModFlags expected_key_mod_flags = GetMergedKeyModFlags(); + IM_ASSERT(g.IO.KeyMods == expected_key_mod_flags && "Mismatching io.KeyCtrl/io.KeyShift/io.KeyAlt/io.KeySuper vs io.KeyMods"); + IM_UNUSED(expected_key_mod_flags); + + // Report when there is a mismatch of Begin/BeginChild vs End/EndChild calls. Important: Remember that the Begin/BeginChild API requires you + // to always call End/EndChild even if Begin/BeginChild returns false! (this is unfortunately inconsistent with most other Begin* API). + if (g.CurrentWindowStack.Size != 1) + { + if (g.CurrentWindowStack.Size > 1) + { + IM_ASSERT_USER_ERROR(g.CurrentWindowStack.Size == 1, "Mismatched Begin/BeginChild vs End/EndChild calls: did you forget to call End/EndChild?"); + while (g.CurrentWindowStack.Size > 1) + End(); + } + else + { + IM_ASSERT_USER_ERROR(g.CurrentWindowStack.Size == 1, "Mismatched Begin/BeginChild vs End/EndChild calls: did you call End/EndChild too much?"); + } + } +} + +// Save and compare stack sizes on Begin()/End() to detect usage errors +// Begin() calls this with write=true +// End() calls this with write=false +static void ImGui::ErrorCheckBeginEndCompareStacksSize(ImGuiWindow* window, bool write) +{ + ImGuiContext& g = *GImGui; + short* p = &window->DC.StackSizesBackup[0]; + + // Window stacks + // NOT checking: DC.ItemWidth, DC.AllowKeyboardFocus, DC.ButtonRepeat, DC.TextWrapPos (per window) to allow user to conveniently push once and not pop (they are cleared on Begin) + { int n = window->IDStack.Size; if (write) *p = (short)n; else IM_ASSERT(*p == n && "PushID/PopID or TreeNode/TreePop Mismatch!"); p++; } // Too few or too many PopID()/TreePop() + { int n = window->DC.GroupStack.Size; if (write) *p = (short)n; else IM_ASSERT(*p == n && "BeginGroup/EndGroup Mismatch!"); p++; } // Too few or too many EndGroup() + + // Global stacks + // For color, style and font stacks there is an incentive to use Push/Begin/Pop/.../End patterns, so we relax our checks a little to allow them. + { int n = g.BeginPopupStack.Size; if (write) *p = (short)n; else IM_ASSERT(*p == n && "BeginMenu/EndMenu or BeginPopup/EndPopup Mismatch!"); p++; }// Too few or too many EndMenu()/EndPopup() + { int n = g.ColorModifiers.Size; if (write) *p = (short)n; else IM_ASSERT(*p >= n && "PushStyleColor/PopStyleColor Mismatch!"); p++; } // Too few or too many PopStyleColor() + { int n = g.StyleModifiers.Size; if (write) *p = (short)n; else IM_ASSERT(*p >= n && "PushStyleVar/PopStyleVar Mismatch!"); p++; } // Too few or too many PopStyleVar() + { int n = g.FontStack.Size; if (write) *p = (short)n; else IM_ASSERT(*p >= n && "PushFont/PopFont Mismatch!"); p++; } // Too few or too many PopFont() + IM_ASSERT(p == window->DC.StackSizesBackup + IM_ARRAYSIZE(window->DC.StackSizesBackup)); +} + + +//----------------------------------------------------------------------------- +// [SECTION] LAYOUT +//----------------------------------------------------------------------------- +// - ItemSize() +// - ItemAdd() +// - SameLine() +// - GetCursorScreenPos() +// - SetCursorScreenPos() +// - GetCursorPos(), GetCursorPosX(), GetCursorPosY() +// - SetCursorPos(), SetCursorPosX(), SetCursorPosY() +// - GetCursorStartPos() +// - Indent() +// - Unindent() +// - SetNextItemWidth() +// - PushItemWidth() +// - PushMultiItemsWidths() +// - PopItemWidth() +// - CalcItemWidth() +// - CalcItemSize() +// - GetTextLineHeight() +// - GetTextLineHeightWithSpacing() +// - GetFrameHeight() +// - GetFrameHeightWithSpacing() +// - GetContentRegionMax() +// - GetContentRegionMaxAbs() [Internal] +// - GetContentRegionAvail(), +// - GetWindowContentRegionMin(), GetWindowContentRegionMax() +// - GetWindowContentRegionWidth() +// - BeginGroup() +// - EndGroup() +// Also see in imgui_widgets: tab bars, columns. +//----------------------------------------------------------------------------- + +// Advance cursor given item size for layout. +// Register minimum needed size so it can extend the bounding box used for auto-fit calculation. +// See comments in ItemAdd() about how/why the size provided to ItemSize() vs ItemAdd() may often different. +void ImGui::ItemSize(const ImVec2& size, float text_baseline_y) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if (window->SkipItems) + return; + + // We increase the height in this function to accommodate for baseline offset. + // In theory we should be offsetting the starting position (window->DC.CursorPos), that will be the topic of a larger refactor, + // but since ItemSize() is not yet an API that moves the cursor (to handle e.g. wrapping) enlarging the height has the same effect. + const float offset_to_match_baseline_y = (text_baseline_y >= 0) ? ImMax(0.0f, window->DC.CurrLineTextBaseOffset - text_baseline_y) : 0.0f; + const float line_height = ImMax(window->DC.CurrLineSize.y, size.y + offset_to_match_baseline_y); + + // Always align ourselves on pixel boundaries + //if (g.IO.KeyAlt) window->DrawList->AddRect(window->DC.CursorPos, window->DC.CursorPos + ImVec2(size.x, line_height), IM_COL32(255,0,0,200)); // [DEBUG] + window->DC.CursorPosPrevLine.x = window->DC.CursorPos.x + size.x; + window->DC.CursorPosPrevLine.y = window->DC.CursorPos.y; + window->DC.CursorPos.x = IM_FLOOR(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x); // Next line + window->DC.CursorPos.y = IM_FLOOR(window->DC.CursorPos.y + line_height + g.Style.ItemSpacing.y); // Next line + window->DC.CursorMaxPos.x = ImMax(window->DC.CursorMaxPos.x, window->DC.CursorPosPrevLine.x); + window->DC.CursorMaxPos.y = ImMax(window->DC.CursorMaxPos.y, window->DC.CursorPos.y - g.Style.ItemSpacing.y); + //if (g.IO.KeyAlt) window->DrawList->AddCircle(window->DC.CursorMaxPos, 3.0f, IM_COL32(255,0,0,255), 4); // [DEBUG] + + window->DC.PrevLineSize.y = line_height; + window->DC.CurrLineSize.y = 0.0f; + window->DC.PrevLineTextBaseOffset = ImMax(window->DC.CurrLineTextBaseOffset, text_baseline_y); + window->DC.CurrLineTextBaseOffset = 0.0f; + + // Horizontal layout mode + if (window->DC.LayoutType == ImGuiLayoutType_Horizontal) + SameLine(); +} + +void ImGui::ItemSize(const ImRect& bb, float text_baseline_y) +{ + ItemSize(bb.GetSize(), text_baseline_y); +} + +// Declare item bounding box for clipping and interaction. +// Note that the size can be different than the one provided to ItemSize(). Typically, widgets that spread over available surface +// declare their minimum size requirement to ItemSize() and provide a larger region to ItemAdd() which is used drawing/interaction. +bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + + if (id != 0) + { + // Navigation processing runs prior to clipping early-out + // (a) So that NavInitRequest can be honored, for newly opened windows to select a default widget + // (b) So that we can scroll up/down past clipped items. This adds a small O(N) cost to regular navigation requests + // unfortunately, but it is still limited to one window. It may not scale very well for windows with ten of + // thousands of item, but at least NavMoveRequest is only set on user interaction, aka maximum once a frame. + // We could early out with "if (is_clipped && !g.NavInitRequest) return false;" but when we wouldn't be able + // to reach unclipped widgets. This would work if user had explicit scrolling control (e.g. mapped on a stick). + // We intentionally don't check if g.NavWindow != NULL because g.NavAnyRequest should only be set when it is non null. + // If we crash on a NULL g.NavWindow we need to fix the bug elsewhere. + window->DC.NavLayerActiveMaskNext |= window->DC.NavLayerCurrentMask; + if (g.NavId == id || g.NavAnyRequest) + if (g.NavWindow->RootWindowForNav == window->RootWindowForNav) + if (window == g.NavWindow || ((window->Flags | g.NavWindow->Flags) & ImGuiWindowFlags_NavFlattened)) + NavProcessItem(window, nav_bb_arg ? *nav_bb_arg : bb, id); + + // [DEBUG] Item Picker tool, when enabling the "extended" version we perform the check in ItemAdd() +#ifdef IMGUI_DEBUG_TOOL_ITEM_PICKER_EX + if (id == g.DebugItemPickerBreakId) + { + IM_DEBUG_BREAK(); + g.DebugItemPickerBreakId = 0; + } +#endif + } + + window->DC.LastItemId = id; + window->DC.LastItemRect = bb; + window->DC.LastItemStatusFlags = ImGuiItemStatusFlags_None; + g.NextItemData.Flags = ImGuiNextItemDataFlags_None; + +#ifdef IMGUI_ENABLE_TEST_ENGINE + if (id != 0) + IMGUI_TEST_ENGINE_ITEM_ADD(nav_bb_arg ? *nav_bb_arg : bb, id); +#endif + + // Clipping test + const bool is_clipped = IsClippedEx(bb, id, false); + if (is_clipped) + return false; + //if (g.IO.KeyAlt) window->DrawList->AddRect(bb.Min, bb.Max, IM_COL32(255,255,0,120)); // [DEBUG] + + // We need to calculate this now to take account of the current clipping rectangle (as items like Selectable may change them) + if (IsMouseHoveringRect(bb.Min, bb.Max)) + window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_HoveredRect; + return true; +} + +// Gets back to previous line and continue with horizontal layout +// offset_from_start_x == 0 : follow right after previous item +// offset_from_start_x != 0 : align to specified x position (relative to window/group left) +// spacing_w < 0 : use default spacing if pos_x == 0, no spacing if pos_x != 0 +// spacing_w >= 0 : enforce spacing amount +void ImGui::SameLine(float offset_from_start_x, float spacing_w) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return; + + ImGuiContext& g = *GImGui; + if (offset_from_start_x != 0.0f) + { + if (spacing_w < 0.0f) spacing_w = 0.0f; + window->DC.CursorPos.x = window->Pos.x - window->Scroll.x + offset_from_start_x + spacing_w + window->DC.GroupOffset.x + window->DC.ColumnsOffset.x; + window->DC.CursorPos.y = window->DC.CursorPosPrevLine.y; + } + else + { + if (spacing_w < 0.0f) spacing_w = g.Style.ItemSpacing.x; + window->DC.CursorPos.x = window->DC.CursorPosPrevLine.x + spacing_w; + window->DC.CursorPos.y = window->DC.CursorPosPrevLine.y; + } + window->DC.CurrLineSize = window->DC.PrevLineSize; + window->DC.CurrLineTextBaseOffset = window->DC.PrevLineTextBaseOffset; +} + +ImVec2 ImGui::GetCursorScreenPos() +{ + ImGuiWindow* window = GetCurrentWindowRead(); + return window->DC.CursorPos; +} + +void ImGui::SetCursorScreenPos(const ImVec2& pos) +{ + ImGuiWindow* window = GetCurrentWindow(); + window->DC.CursorPos = pos; + window->DC.CursorMaxPos = ImMax(window->DC.CursorMaxPos, window->DC.CursorPos); +} + +// User generally sees positions in window coordinates. Internally we store CursorPos in absolute screen coordinates because it is more convenient. +// Conversion happens as we pass the value to user, but it makes our naming convention confusing because GetCursorPos() == (DC.CursorPos - window.Pos). May want to rename 'DC.CursorPos'. +ImVec2 ImGui::GetCursorPos() +{ + ImGuiWindow* window = GetCurrentWindowRead(); + return window->DC.CursorPos - window->Pos + window->Scroll; +} + +float ImGui::GetCursorPosX() +{ + ImGuiWindow* window = GetCurrentWindowRead(); + return window->DC.CursorPos.x - window->Pos.x + window->Scroll.x; +} + +float ImGui::GetCursorPosY() +{ + ImGuiWindow* window = GetCurrentWindowRead(); + return window->DC.CursorPos.y - window->Pos.y + window->Scroll.y; +} + +void ImGui::SetCursorPos(const ImVec2& local_pos) +{ + ImGuiWindow* window = GetCurrentWindow(); + window->DC.CursorPos = window->Pos - window->Scroll + local_pos; + window->DC.CursorMaxPos = ImMax(window->DC.CursorMaxPos, window->DC.CursorPos); +} + +void ImGui::SetCursorPosX(float x) +{ + ImGuiWindow* window = GetCurrentWindow(); + window->DC.CursorPos.x = window->Pos.x - window->Scroll.x + x; + window->DC.CursorMaxPos.x = ImMax(window->DC.CursorMaxPos.x, window->DC.CursorPos.x); +} + +void ImGui::SetCursorPosY(float y) +{ + ImGuiWindow* window = GetCurrentWindow(); + window->DC.CursorPos.y = window->Pos.y - window->Scroll.y + y; + window->DC.CursorMaxPos.y = ImMax(window->DC.CursorMaxPos.y, window->DC.CursorPos.y); +} + +ImVec2 ImGui::GetCursorStartPos() +{ + ImGuiWindow* window = GetCurrentWindowRead(); + return window->DC.CursorStartPos - window->Pos; +} + +void ImGui::Indent(float indent_w) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = GetCurrentWindow(); + window->DC.Indent.x += (indent_w != 0.0f) ? indent_w : g.Style.IndentSpacing; + window->DC.CursorPos.x = window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x; +} + +void ImGui::Unindent(float indent_w) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = GetCurrentWindow(); + window->DC.Indent.x -= (indent_w != 0.0f) ? indent_w : g.Style.IndentSpacing; + window->DC.CursorPos.x = window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x; +} + +// Affect large frame+labels widgets only. +void ImGui::SetNextItemWidth(float item_width) +{ + ImGuiContext& g = *GImGui; + g.NextItemData.Flags |= ImGuiNextItemDataFlags_HasWidth; + g.NextItemData.Width = item_width; +} + +void ImGui::PushItemWidth(float item_width) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + window->DC.ItemWidth = (item_width == 0.0f ? window->ItemWidthDefault : item_width); + window->DC.ItemWidthStack.push_back(window->DC.ItemWidth); + g.NextItemData.Flags &= ~ImGuiNextItemDataFlags_HasWidth; +} + +void ImGui::PushMultiItemsWidths(int components, float w_full) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + const ImGuiStyle& style = g.Style; + const float w_item_one = ImMax(1.0f, IM_FLOOR((w_full - (style.ItemInnerSpacing.x) * (components-1)) / (float)components)); + const float w_item_last = ImMax(1.0f, IM_FLOOR(w_full - (w_item_one + style.ItemInnerSpacing.x) * (components-1))); + window->DC.ItemWidthStack.push_back(w_item_last); + for (int i = 0; i < components-1; i++) + window->DC.ItemWidthStack.push_back(w_item_one); + window->DC.ItemWidth = window->DC.ItemWidthStack.back(); + g.NextItemData.Flags &= ~ImGuiNextItemDataFlags_HasWidth; +} + +void ImGui::PopItemWidth() +{ + ImGuiWindow* window = GetCurrentWindow(); + window->DC.ItemWidthStack.pop_back(); + window->DC.ItemWidth = window->DC.ItemWidthStack.empty() ? window->ItemWidthDefault : window->DC.ItemWidthStack.back(); +} + +// Calculate default item width given value passed to PushItemWidth() or SetNextItemWidth(). +// The SetNextItemWidth() data is generally cleared/consumed by ItemAdd() or NextItemData.ClearFlags() +float ImGui::CalcItemWidth() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + float w; + if (g.NextItemData.Flags & ImGuiNextItemDataFlags_HasWidth) + w = g.NextItemData.Width; + else + w = window->DC.ItemWidth; + if (w < 0.0f) + { + float region_max_x = GetContentRegionMaxAbs().x; + w = ImMax(1.0f, region_max_x - window->DC.CursorPos.x + w); + } + w = IM_FLOOR(w); + return w; +} + +// [Internal] Calculate full item size given user provided 'size' parameter and default width/height. Default width is often == CalcItemWidth(). +// Those two functions CalcItemWidth vs CalcItemSize are awkwardly named because they are not fully symmetrical. +// Note that only CalcItemWidth() is publicly exposed. +// The 4.0f here may be changed to match CalcItemWidth() and/or BeginChild() (right now we have a mismatch which is harmless but undesirable) +ImVec2 ImGui::CalcItemSize(ImVec2 size, float default_w, float default_h) +{ + ImGuiWindow* window = GImGui->CurrentWindow; + + ImVec2 region_max; + if (size.x < 0.0f || size.y < 0.0f) + region_max = GetContentRegionMaxAbs(); + + if (size.x == 0.0f) + size.x = default_w; + else if (size.x < 0.0f) + size.x = ImMax(4.0f, region_max.x - window->DC.CursorPos.x + size.x); + + if (size.y == 0.0f) + size.y = default_h; + else if (size.y < 0.0f) + size.y = ImMax(4.0f, region_max.y - window->DC.CursorPos.y + size.y); + + return size; +} + +float ImGui::GetTextLineHeight() +{ + ImGuiContext& g = *GImGui; + return g.FontSize; +} + +float ImGui::GetTextLineHeightWithSpacing() +{ + ImGuiContext& g = *GImGui; + return g.FontSize + g.Style.ItemSpacing.y; +} + +float ImGui::GetFrameHeight() +{ + ImGuiContext& g = *GImGui; + return g.FontSize + g.Style.FramePadding.y * 2.0f; +} + +float ImGui::GetFrameHeightWithSpacing() +{ + ImGuiContext& g = *GImGui; + return g.FontSize + g.Style.FramePadding.y * 2.0f + g.Style.ItemSpacing.y; +} + +// FIXME: All the Contents Region function are messy or misleading. WE WILL AIM TO OBSOLETE ALL OF THEM WITH A NEW "WORK RECT" API. Thanks for your patience! + +// FIXME: This is in window space (not screen space!). +ImVec2 ImGui::GetContentRegionMax() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + ImVec2 mx = window->ContentRegionRect.Max - window->Pos; + if (window->DC.CurrentColumns) + mx.x = window->WorkRect.Max.x - window->Pos.x; + return mx; +} + +// [Internal] Absolute coordinate. Saner. This is not exposed until we finishing refactoring work rect features. +ImVec2 ImGui::GetContentRegionMaxAbs() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + ImVec2 mx = window->ContentRegionRect.Max; + if (window->DC.CurrentColumns) + mx.x = window->WorkRect.Max.x; + return mx; +} + +ImVec2 ImGui::GetContentRegionAvail() +{ + ImGuiWindow* window = GImGui->CurrentWindow; + return GetContentRegionMaxAbs() - window->DC.CursorPos; +} + +// In window space (not screen space!) +ImVec2 ImGui::GetWindowContentRegionMin() +{ + ImGuiWindow* window = GImGui->CurrentWindow; + return window->ContentRegionRect.Min - window->Pos; +} + +ImVec2 ImGui::GetWindowContentRegionMax() +{ + ImGuiWindow* window = GImGui->CurrentWindow; + return window->ContentRegionRect.Max - window->Pos; +} + +float ImGui::GetWindowContentRegionWidth() +{ + ImGuiWindow* window = GImGui->CurrentWindow; + return window->ContentRegionRect.GetWidth(); +} + +// Lock horizontal starting position + capture group bounding box into one "item" (so you can use IsItemHovered() or layout primitives such as SameLine() on whole group, etc.) +void ImGui::BeginGroup() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = GetCurrentWindow(); + + window->DC.GroupStack.resize(window->DC.GroupStack.Size + 1); + ImGuiGroupData& group_data = window->DC.GroupStack.back(); + group_data.BackupCursorPos = window->DC.CursorPos; + group_data.BackupCursorMaxPos = window->DC.CursorMaxPos; + group_data.BackupIndent = window->DC.Indent; + group_data.BackupGroupOffset = window->DC.GroupOffset; + group_data.BackupCurrLineSize = window->DC.CurrLineSize; + group_data.BackupCurrLineTextBaseOffset = window->DC.CurrLineTextBaseOffset; + group_data.BackupActiveIdIsAlive = g.ActiveIdIsAlive; + group_data.BackupActiveIdPreviousFrameIsAlive = g.ActiveIdPreviousFrameIsAlive; + group_data.EmitItem = true; + + window->DC.GroupOffset.x = window->DC.CursorPos.x - window->Pos.x - window->DC.ColumnsOffset.x; + window->DC.Indent = window->DC.GroupOffset; + window->DC.CursorMaxPos = window->DC.CursorPos; + window->DC.CurrLineSize = ImVec2(0.0f, 0.0f); + if (g.LogEnabled) + g.LogLinePosY = -FLT_MAX; // To enforce Log carriage return +} + +void ImGui::EndGroup() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = GetCurrentWindow(); + IM_ASSERT(!window->DC.GroupStack.empty()); // Mismatched BeginGroup()/EndGroup() calls + + ImGuiGroupData& group_data = window->DC.GroupStack.back(); + + ImRect group_bb(group_data.BackupCursorPos, ImMax(window->DC.CursorMaxPos, group_data.BackupCursorPos)); + + window->DC.CursorPos = group_data.BackupCursorPos; + window->DC.CursorMaxPos = ImMax(group_data.BackupCursorMaxPos, window->DC.CursorMaxPos); + window->DC.Indent = group_data.BackupIndent; + window->DC.GroupOffset = group_data.BackupGroupOffset; + window->DC.CurrLineSize = group_data.BackupCurrLineSize; + window->DC.CurrLineTextBaseOffset = group_data.BackupCurrLineTextBaseOffset; + if (g.LogEnabled) + g.LogLinePosY = -FLT_MAX; // To enforce Log carriage return + + if (!group_data.EmitItem) + { + window->DC.GroupStack.pop_back(); + return; + } + + window->DC.CurrLineTextBaseOffset = ImMax(window->DC.PrevLineTextBaseOffset, group_data.BackupCurrLineTextBaseOffset); // FIXME: Incorrect, we should grab the base offset from the *first line* of the group but it is hard to obtain now. + ItemSize(group_bb.GetSize()); + ItemAdd(group_bb, 0); + + // If the current ActiveId was declared within the boundary of our group, we copy it to LastItemId so IsItemActive(), IsItemDeactivated() etc. will be functional on the entire group. + // It would be be neater if we replaced window.DC.LastItemId by e.g. 'bool LastItemIsActive', but would put a little more burden on individual widgets. + // Also if you grep for LastItemId you'll notice it is only used in that context. + // (The tests not symmetrical because ActiveIdIsAlive is an ID itself, in order to be able to handle ActiveId being overwritten during the frame.) + const bool group_contains_curr_active_id = (group_data.BackupActiveIdIsAlive != g.ActiveId) && (g.ActiveIdIsAlive == g.ActiveId) && g.ActiveId; + const bool group_contains_prev_active_id = !group_data.BackupActiveIdPreviousFrameIsAlive && g.ActiveIdPreviousFrameIsAlive; + if (group_contains_curr_active_id) + window->DC.LastItemId = g.ActiveId; + else if (group_contains_prev_active_id) + window->DC.LastItemId = g.ActiveIdPreviousFrame; + window->DC.LastItemRect = group_bb; + + // Forward Edited flag + if (group_contains_curr_active_id && g.ActiveIdHasBeenEditedThisFrame) + window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_Edited; + + // Forward Deactivated flag + window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_HasDeactivated; + if (group_contains_prev_active_id && g.ActiveId != g.ActiveIdPreviousFrame) + window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_Deactivated; + + window->DC.GroupStack.pop_back(); + //window->DrawList->AddRect(group_bb.Min, group_bb.Max, IM_COL32(255,0,255,255)); // [Debug] +} + + +//----------------------------------------------------------------------------- +// [SECTION] SCROLLING +//----------------------------------------------------------------------------- + +static ImVec2 CalcNextScrollFromScrollTargetAndClamp(ImGuiWindow* window, bool snap_on_edges) +{ + ImGuiContext& g = *GImGui; + ImVec2 scroll = window->Scroll; + if (window->ScrollTarget.x < FLT_MAX) + { + float cr_x = window->ScrollTargetCenterRatio.x; + float target_x = window->ScrollTarget.x; + if (snap_on_edges && cr_x <= 0.0f && target_x <= window->WindowPadding.x) + target_x = 0.0f; + else if (snap_on_edges && cr_x >= 1.0f && target_x >= window->ContentSize.x + window->WindowPadding.x + g.Style.ItemSpacing.x) + target_x = window->ContentSize.x + window->WindowPadding.x * 2.0f; + scroll.x = target_x - cr_x * (window->SizeFull.x - window->ScrollbarSizes.x); + } + if (window->ScrollTarget.y < FLT_MAX) + { + // 'snap_on_edges' allows for a discontinuity at the edge of scrolling limits to take account of WindowPadding so that scrolling to make the last item visible scroll far enough to see the padding. + float decoration_up_height = window->TitleBarHeight() + window->MenuBarHeight(); + float cr_y = window->ScrollTargetCenterRatio.y; + float target_y = window->ScrollTarget.y; + if (snap_on_edges && cr_y <= 0.0f && target_y <= window->WindowPadding.y) + target_y = 0.0f; + if (snap_on_edges && cr_y >= 1.0f && target_y >= window->ContentSize.y + window->WindowPadding.y + g.Style.ItemSpacing.y) + target_y = window->ContentSize.y + window->WindowPadding.y * 2.0f; + scroll.y = target_y - cr_y * (window->SizeFull.y - window->ScrollbarSizes.y - decoration_up_height); + } + scroll.x = IM_FLOOR(ImMax(scroll.x, 0.0f)); + scroll.y = IM_FLOOR(ImMax(scroll.y, 0.0f)); + if (!window->Collapsed && !window->SkipItems) + { + scroll.x = ImMin(scroll.x, window->ScrollMax.x); + scroll.y = ImMin(scroll.y, window->ScrollMax.y); + } + return scroll; +} + +// Scroll to keep newly navigated item fully into view +ImVec2 ImGui::ScrollToBringRectIntoView(ImGuiWindow* window, const ImRect& item_rect) +{ + ImGuiContext& g = *GImGui; + ImRect window_rect(window->InnerRect.Min - ImVec2(1, 1), window->InnerRect.Max + ImVec2(1, 1)); + //GetForegroundDrawList(window)->AddRect(window_rect.Min, window_rect.Max, IM_COL32_WHITE); // [DEBUG] + + ImVec2 delta_scroll; + if (!window_rect.Contains(item_rect)) + { + if (window->ScrollbarX && item_rect.Min.x < window_rect.Min.x) + SetScrollFromPosX(window, item_rect.Min.x - window->Pos.x + g.Style.ItemSpacing.x, 0.0f); + else if (window->ScrollbarX && item_rect.Max.x >= window_rect.Max.x) + SetScrollFromPosX(window, item_rect.Max.x - window->Pos.x + g.Style.ItemSpacing.x, 1.0f); + if (item_rect.Min.y < window_rect.Min.y) + SetScrollFromPosY(window, item_rect.Min.y - window->Pos.y - g.Style.ItemSpacing.y, 0.0f); + else if (item_rect.Max.y >= window_rect.Max.y) + SetScrollFromPosY(window, item_rect.Max.y - window->Pos.y + g.Style.ItemSpacing.y, 1.0f); + + ImVec2 next_scroll = CalcNextScrollFromScrollTargetAndClamp(window, false); + delta_scroll = next_scroll - window->Scroll; + } + + // Also scroll parent window to keep us into view if necessary + if (window->Flags & ImGuiWindowFlags_ChildWindow) + delta_scroll += ScrollToBringRectIntoView(window->ParentWindow, ImRect(item_rect.Min - delta_scroll, item_rect.Max - delta_scroll)); + + return delta_scroll; +} + +float ImGui::GetScrollX() +{ + ImGuiWindow* window = GImGui->CurrentWindow; + return window->Scroll.x; +} + +float ImGui::GetScrollY() +{ + ImGuiWindow* window = GImGui->CurrentWindow; + return window->Scroll.y; +} + +float ImGui::GetScrollMaxX() +{ + ImGuiWindow* window = GImGui->CurrentWindow; + return window->ScrollMax.x; +} + +float ImGui::GetScrollMaxY() +{ + ImGuiWindow* window = GImGui->CurrentWindow; + return window->ScrollMax.y; +} + +void ImGui::SetScrollX(float scroll_x) +{ + ImGuiWindow* window = GetCurrentWindow(); + window->ScrollTarget.x = scroll_x; + window->ScrollTargetCenterRatio.x = 0.0f; +} + +void ImGui::SetScrollY(float scroll_y) +{ + ImGuiWindow* window = GetCurrentWindow(); + window->ScrollTarget.y = scroll_y; + window->ScrollTargetCenterRatio.y = 0.0f; +} + +void ImGui::SetScrollX(ImGuiWindow* window, float new_scroll_x) +{ + window->ScrollTarget.x = new_scroll_x; + window->ScrollTargetCenterRatio.x = 0.0f; +} + +void ImGui::SetScrollY(ImGuiWindow* window, float new_scroll_y) +{ + window->ScrollTarget.y = new_scroll_y; + window->ScrollTargetCenterRatio.y = 0.0f; +} + + +void ImGui::SetScrollFromPosX(ImGuiWindow* window, float local_x, float center_x_ratio) +{ + // We store a target position so centering can occur on the next frame when we are guaranteed to have a known window size + IM_ASSERT(center_x_ratio >= 0.0f && center_x_ratio <= 1.0f); + window->ScrollTarget.x = IM_FLOOR(local_x + window->Scroll.x); + window->ScrollTargetCenterRatio.x = center_x_ratio; +} + +void ImGui::SetScrollFromPosY(ImGuiWindow* window, float local_y, float center_y_ratio) +{ + // We store a target position so centering can occur on the next frame when we are guaranteed to have a known window size + IM_ASSERT(center_y_ratio >= 0.0f && center_y_ratio <= 1.0f); + const float decoration_up_height = window->TitleBarHeight() + window->MenuBarHeight(); + local_y -= decoration_up_height; + window->ScrollTarget.y = IM_FLOOR(local_y + window->Scroll.y); + window->ScrollTargetCenterRatio.y = center_y_ratio; +} + +void ImGui::SetScrollFromPosX(float local_x, float center_x_ratio) +{ + ImGuiContext& g = *GImGui; + SetScrollFromPosX(g.CurrentWindow, local_x, center_x_ratio); +} + +void ImGui::SetScrollFromPosY(float local_y, float center_y_ratio) +{ + ImGuiContext& g = *GImGui; + SetScrollFromPosY(g.CurrentWindow, local_y, center_y_ratio); +} + +// center_x_ratio: 0.0f left of last item, 0.5f horizontal center of last item, 1.0f right of last item. +void ImGui::SetScrollHereX(float center_x_ratio) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + float target_x = window->DC.LastItemRect.Min.x - window->Pos.x; // Left of last item, in window space + float last_item_width = window->DC.LastItemRect.GetWidth(); + target_x += (last_item_width * center_x_ratio) + (g.Style.ItemSpacing.x * (center_x_ratio - 0.5f) * 2.0f); // Precisely aim before, in the middle or after the last item. + SetScrollFromPosX(target_x, center_x_ratio); +} + +// center_y_ratio: 0.0f top of last item, 0.5f vertical center of last item, 1.0f bottom of last item. +void ImGui::SetScrollHereY(float center_y_ratio) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + float target_y = window->DC.CursorPosPrevLine.y - window->Pos.y; // Top of last item, in window space + target_y += (window->DC.PrevLineSize.y * center_y_ratio) + (g.Style.ItemSpacing.y * (center_y_ratio - 0.5f) * 2.0f); // Precisely aim above, in the middle or below the last line. + SetScrollFromPosY(target_y, center_y_ratio); +} + +//----------------------------------------------------------------------------- +// [SECTION] TOOLTIPS +//----------------------------------------------------------------------------- + +void ImGui::BeginTooltip() +{ + BeginTooltipEx(ImGuiWindowFlags_None, ImGuiTooltipFlags_None); +} + +void ImGui::BeginTooltipEx(ImGuiWindowFlags extra_flags, ImGuiTooltipFlags tooltip_flags) +{ + ImGuiContext& g = *GImGui; + + if (g.DragDropWithinSource || g.DragDropWithinTarget) + { + // The default tooltip position is a little offset to give space to see the context menu (it's also clamped within the current viewport/monitor) + // In the context of a dragging tooltip we try to reduce that offset and we enforce following the cursor. + // Whatever we do we want to call SetNextWindowPos() to enforce a tooltip position and disable clipping the tooltip without our display area, like regular tooltip do. + //ImVec2 tooltip_pos = g.IO.MousePos - g.ActiveIdClickOffset - g.Style.WindowPadding; + ImVec2 tooltip_pos = g.IO.MousePos + ImVec2(16 * g.Style.MouseCursorScale, 8 * g.Style.MouseCursorScale); + SetNextWindowPos(tooltip_pos); + SetNextWindowBgAlpha(g.Style.Colors[ImGuiCol_PopupBg].w * 0.60f); + //PushStyleVar(ImGuiStyleVar_Alpha, g.Style.Alpha * 0.60f); // This would be nice but e.g ColorButton with checkboard has issue with transparent colors :( + tooltip_flags |= ImGuiTooltipFlags_OverridePreviousTooltip; + } + + char window_name[16]; + ImFormatString(window_name, IM_ARRAYSIZE(window_name), "##Tooltip_%02d", g.TooltipOverrideCount); + if (tooltip_flags & ImGuiTooltipFlags_OverridePreviousTooltip) + if (ImGuiWindow* window = FindWindowByName(window_name)) + if (window->Active) + { + // Hide previous tooltip from being displayed. We can't easily "reset" the content of a window so we create a new one. + window->Hidden = true; + window->HiddenFramesCanSkipItems = 1; + ImFormatString(window_name, IM_ARRAYSIZE(window_name), "##Tooltip_%02d", ++g.TooltipOverrideCount); + } + ImGuiWindowFlags flags = ImGuiWindowFlags_Tooltip|ImGuiWindowFlags_NoInputs|ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_NoResize|ImGuiWindowFlags_NoSavedSettings|ImGuiWindowFlags_AlwaysAutoResize|ImGuiWindowFlags_NoDocking; + Begin(window_name, NULL, flags | extra_flags); +} + +void ImGui::EndTooltip() +{ + IM_ASSERT(GetCurrentWindowRead()->Flags & ImGuiWindowFlags_Tooltip); // Mismatched BeginTooltip()/EndTooltip() calls + End(); +} + +void ImGui::SetTooltipV(const char* fmt, va_list args) +{ + BeginTooltipEx(0, ImGuiTooltipFlags_OverridePreviousTooltip); + TextV(fmt, args); + EndTooltip(); +} + +void ImGui::SetTooltip(const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + SetTooltipV(fmt, args); + va_end(args); +} + +//----------------------------------------------------------------------------- +// [SECTION] POPUPS +//----------------------------------------------------------------------------- + +bool ImGui::IsPopupOpen(ImGuiID id) +{ + ImGuiContext& g = *GImGui; + return g.OpenPopupStack.Size > g.BeginPopupStack.Size && g.OpenPopupStack[g.BeginPopupStack.Size].PopupId == id; +} + +bool ImGui::IsPopupOpen(const char* str_id) +{ + ImGuiContext& g = *GImGui; + return g.OpenPopupStack.Size > g.BeginPopupStack.Size && g.OpenPopupStack[g.BeginPopupStack.Size].PopupId == g.CurrentWindow->GetID(str_id); +} + +ImGuiWindow* ImGui::GetTopMostPopupModal() +{ + ImGuiContext& g = *GImGui; + for (int n = g.OpenPopupStack.Size-1; n >= 0; n--) + if (ImGuiWindow* popup = g.OpenPopupStack.Data[n].Window) + if (popup->Flags & ImGuiWindowFlags_Modal) + return popup; + return NULL; +} + +void ImGui::OpenPopup(const char* str_id) +{ + ImGuiContext& g = *GImGui; + OpenPopupEx(g.CurrentWindow->GetID(str_id)); +} + +// Mark popup as open (toggle toward open state). +// Popups are closed when user click outside, or activate a pressable item, or CloseCurrentPopup() is called within a BeginPopup()/EndPopup() block. +// Popup identifiers are relative to the current ID-stack (so OpenPopup and BeginPopup needs to be at the same level). +// One open popup per level of the popup hierarchy (NB: when assigning we reset the Window member of ImGuiPopupRef to NULL) +void ImGui::OpenPopupEx(ImGuiID id) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* parent_window = g.CurrentWindow; + int current_stack_size = g.BeginPopupStack.Size; + ImGuiPopupData popup_ref; // Tagged as new ref as Window will be set back to NULL if we write this into OpenPopupStack. + popup_ref.PopupId = id; + popup_ref.Window = NULL; + popup_ref.SourceWindow = g.NavWindow; + popup_ref.OpenFrameCount = g.FrameCount; + popup_ref.OpenParentId = parent_window->IDStack.back(); + popup_ref.OpenPopupPos = NavCalcPreferredRefPos(); + popup_ref.OpenMousePos = IsMousePosValid(&g.IO.MousePos) ? g.IO.MousePos : popup_ref.OpenPopupPos; + + IMGUI_DEBUG_LOG_POPUP("OpenPopupEx(0x%08X)\n", id); + if (g.OpenPopupStack.Size < current_stack_size + 1) + { + g.OpenPopupStack.push_back(popup_ref); + } + else + { + // Gently handle the user mistakenly calling OpenPopup() every frame. It is a programming mistake! However, if we were to run the regular code path, the ui + // would become completely unusable because the popup will always be in hidden-while-calculating-size state _while_ claiming focus. Which would be a very confusing + // situation for the programmer. Instead, we silently allow the popup to proceed, it will keep reappearing and the programming error will be more obvious to understand. + if (g.OpenPopupStack[current_stack_size].PopupId == id && g.OpenPopupStack[current_stack_size].OpenFrameCount == g.FrameCount - 1) + { + g.OpenPopupStack[current_stack_size].OpenFrameCount = popup_ref.OpenFrameCount; + } + else + { + // Close child popups if any, then flag popup for open/reopen + g.OpenPopupStack.resize(current_stack_size + 1); + g.OpenPopupStack[current_stack_size] = popup_ref; + } + + // When reopening a popup we first refocus its parent, otherwise if its parent is itself a popup it would get closed by ClosePopupsOverWindow(). + // This is equivalent to what ClosePopupToLevel() does. + //if (g.OpenPopupStack[current_stack_size].PopupId == id) + // FocusWindow(parent_window); + } +} + +void ImGui::ClosePopupsOverWindow(ImGuiWindow* ref_window, bool restore_focus_to_window_under_popup) +{ + ImGuiContext& g = *GImGui; + if (g.OpenPopupStack.empty()) + return; + + // When popups are stacked, clicking on a lower level popups puts focus back to it and close popups above it. + // Don't close our own child popup windows. + int popup_count_to_keep = 0; + if (ref_window) + { + // Find the highest popup which is a descendant of the reference window (generally reference window = NavWindow) + for (; popup_count_to_keep < g.OpenPopupStack.Size; popup_count_to_keep++) + { + ImGuiPopupData& popup = g.OpenPopupStack[popup_count_to_keep]; + if (!popup.Window) + continue; + IM_ASSERT((popup.Window->Flags & ImGuiWindowFlags_Popup) != 0); + if (popup.Window->Flags & ImGuiWindowFlags_ChildWindow) + continue; + + // Trim the stack when popups are not direct descendant of the reference window (the reference window is often the NavWindow) + bool popup_or_descendent_is_ref_window = false; + for (int m = popup_count_to_keep; m < g.OpenPopupStack.Size && !popup_or_descendent_is_ref_window; m++) + if (ImGuiWindow* popup_window = g.OpenPopupStack[m].Window) + if (popup_window->RootWindow == ref_window->RootWindow) + popup_or_descendent_is_ref_window = true; + if (!popup_or_descendent_is_ref_window) + break; + } + } + if (popup_count_to_keep < g.OpenPopupStack.Size) // This test is not required but it allows to set a convenient breakpoint on the statement below + { + IMGUI_DEBUG_LOG_POPUP("ClosePopupsOverWindow(\"%s\") -> ClosePopupToLevel(%d)\n", ref_window->Name, popup_count_to_keep); + ClosePopupToLevel(popup_count_to_keep, restore_focus_to_window_under_popup); + } +} + +void ImGui::ClosePopupToLevel(int remaining, bool restore_focus_to_window_under_popup) +{ + ImGuiContext& g = *GImGui; + IMGUI_DEBUG_LOG_POPUP("ClosePopupToLevel(%d), restore_focus_to_window_under_popup=%d\n", remaining, restore_focus_to_window_under_popup); + IM_ASSERT(remaining >= 0 && remaining < g.OpenPopupStack.Size); + ImGuiWindow* focus_window = g.OpenPopupStack[remaining].SourceWindow; + ImGuiWindow* popup_window = g.OpenPopupStack[remaining].Window; + g.OpenPopupStack.resize(remaining); + + if (restore_focus_to_window_under_popup) + { + if (focus_window && !focus_window->WasActive && popup_window) + { + // Fallback + FocusTopMostWindowUnderOne(popup_window, NULL); + } + else + { + if (g.NavLayer == ImGuiNavLayer_Main && focus_window) + focus_window = NavRestoreLastChildNavWindow(focus_window); + FocusWindow(focus_window); + } + } +} + +// Close the popup we have begin-ed into. +void ImGui::CloseCurrentPopup() +{ + ImGuiContext& g = *GImGui; + int popup_idx = g.BeginPopupStack.Size - 1; + if (popup_idx < 0 || popup_idx >= g.OpenPopupStack.Size || g.BeginPopupStack[popup_idx].PopupId != g.OpenPopupStack[popup_idx].PopupId) + return; + + // Closing a menu closes its top-most parent popup (unless a modal) + while (popup_idx > 0) + { + ImGuiWindow* popup_window = g.OpenPopupStack[popup_idx].Window; + ImGuiWindow* parent_popup_window = g.OpenPopupStack[popup_idx - 1].Window; + bool close_parent = false; + if (popup_window && (popup_window->Flags & ImGuiWindowFlags_ChildMenu)) + if (parent_popup_window == NULL || !(parent_popup_window->Flags & ImGuiWindowFlags_Modal)) + close_parent = true; + if (!close_parent) + break; + popup_idx--; + } + IMGUI_DEBUG_LOG_POPUP("CloseCurrentPopup %d -> %d\n", g.BeginPopupStack.Size - 1, popup_idx); + ClosePopupToLevel(popup_idx, true); + + // A common pattern is to close a popup when selecting a menu item/selectable that will open another window. + // To improve this usage pattern, we avoid nav highlight for a single frame in the parent window. + // Similarly, we could avoid mouse hover highlight in this window but it is less visually problematic. + if (ImGuiWindow* window = g.NavWindow) + window->DC.NavHideHighlightOneFrame = true; +} + +bool ImGui::BeginPopupEx(ImGuiID id, ImGuiWindowFlags flags) +{ + ImGuiContext& g = *GImGui; + if (!IsPopupOpen(id)) + { + g.NextWindowData.ClearFlags(); // We behave like Begin() and need to consume those values + return false; + } + + char name[20]; + if (flags & ImGuiWindowFlags_ChildMenu) + ImFormatString(name, IM_ARRAYSIZE(name), "##Menu_%02d", g.BeginPopupStack.Size); // Recycle windows based on depth + else + ImFormatString(name, IM_ARRAYSIZE(name), "##Popup_%08x", id); // Not recycling, so we can close/open during the same frame + + flags |= ImGuiWindowFlags_Popup | ImGuiWindowFlags_NoDocking; + bool is_open = Begin(name, NULL, flags); + if (!is_open) // NB: Begin can return false when the popup is completely clipped (e.g. zero size display) + EndPopup(); + + return is_open; +} + +bool ImGui::BeginPopup(const char* str_id, ImGuiWindowFlags flags) +{ + ImGuiContext& g = *GImGui; + if (g.OpenPopupStack.Size <= g.BeginPopupStack.Size) // Early out for performance + { + g.NextWindowData.ClearFlags(); // We behave like Begin() and need to consume those values + return false; + } + flags |= ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoSavedSettings; + return BeginPopupEx(g.CurrentWindow->GetID(str_id), flags); +} + +// If 'p_open' is specified for a modal popup window, the popup will have a regular close button which will close the popup. +// Note that popup visibility status is owned by Dear ImGui (and manipulated with e.g. OpenPopup) so the actual value of *p_open is meaningless here. +bool ImGui::BeginPopupModal(const char* name, bool* p_open, ImGuiWindowFlags flags) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + const ImGuiID id = window->GetID(name); + if (!IsPopupOpen(id)) + { + g.NextWindowData.ClearFlags(); // We behave like Begin() and need to consume those values + return false; + } + + // Center modal windows by default + // FIXME: Should test for (PosCond & window->SetWindowPosAllowFlags) with the upcoming window. + if ((g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasPos) == 0) + { + ImGuiViewportP* viewport = window->WasActive ? window->Viewport : (ImGuiViewportP*)GetMainViewport(); // FIXME-VIEWPORT: What may be our reference viewport? + SetNextWindowPos(viewport->GetMainRect().GetCenter(), ImGuiCond_Appearing, ImVec2(0.5f, 0.5f)); + } + + flags |= ImGuiWindowFlags_Popup | ImGuiWindowFlags_Modal | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoDocking; + const bool is_open = Begin(name, p_open, flags); + if (!is_open || (p_open && !*p_open)) // NB: is_open can be 'false' when the popup is completely clipped (e.g. zero size display) + { + EndPopup(); + if (is_open) + ClosePopupToLevel(g.BeginPopupStack.Size, true); + return false; + } + return is_open; +} + +void ImGui::EndPopup() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + IM_ASSERT(window->Flags & ImGuiWindowFlags_Popup); // Mismatched BeginPopup()/EndPopup() calls + IM_ASSERT(g.BeginPopupStack.Size > 0); + + // Make all menus and popups wrap around for now, may need to expose that policy. + if (g.NavWindow == window) + NavMoveRequestTryWrapping(window, ImGuiNavMoveFlags_LoopY); + + // Child-popups don't need to be laid out + IM_ASSERT(g.WithinEndChild == false); + if (window->Flags & ImGuiWindowFlags_ChildWindow) + g.WithinEndChild = true; + End(); + g.WithinEndChild = false; +} + +bool ImGui::OpenPopupOnItemClick(const char* str_id, ImGuiMouseButton mouse_button) +{ + ImGuiWindow* window = GImGui->CurrentWindow; + if (IsMouseReleased(mouse_button) && IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup)) + { + ImGuiID id = str_id ? window->GetID(str_id) : window->DC.LastItemId; // If user hasn't passed an ID, we can use the LastItemID. Using LastItemID as a Popup ID won't conflict! + IM_ASSERT(id != 0); // You cannot pass a NULL str_id if the last item has no identifier (e.g. a Text() item) + OpenPopupEx(id); + return true; + } + return false; +} + +// This is a helper to handle the simplest case of associating one named popup to one given widget. +// You may want to handle this on user side if you have specific needs (e.g. tweaking IsItemHovered() parameters). +// You can pass a NULL str_id to use the identifier of the last item. +bool ImGui::BeginPopupContextItem(const char* str_id, ImGuiMouseButton mouse_button) +{ + ImGuiWindow* window = GImGui->CurrentWindow; + if (window->SkipItems) + return false; + ImGuiID id = str_id ? window->GetID(str_id) : window->DC.LastItemId; // If user hasn't passed an ID, we can use the LastItemID. Using LastItemID as a Popup ID won't conflict! + IM_ASSERT(id != 0); // You cannot pass a NULL str_id if the last item has no identifier (e.g. a Text() item) + if (IsMouseReleased(mouse_button) && IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup)) + OpenPopupEx(id); + return BeginPopupEx(id, ImGuiWindowFlags_AlwaysAutoResize|ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoSavedSettings); +} + +bool ImGui::BeginPopupContextWindow(const char* str_id, ImGuiMouseButton mouse_button, bool also_over_items) +{ + if (!str_id) + str_id = "window_context"; + ImGuiID id = GImGui->CurrentWindow->GetID(str_id); + if (IsMouseReleased(mouse_button) && IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup)) + if (also_over_items || !IsAnyItemHovered()) + OpenPopupEx(id); + return BeginPopupEx(id, ImGuiWindowFlags_AlwaysAutoResize|ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoSavedSettings); +} + +bool ImGui::BeginPopupContextVoid(const char* str_id, ImGuiMouseButton mouse_button) +{ + if (!str_id) + str_id = "void_context"; + ImGuiID id = GImGui->CurrentWindow->GetID(str_id); + if (IsMouseReleased(mouse_button) && !IsWindowHovered(ImGuiHoveredFlags_AnyWindow)) + OpenPopupEx(id); + return BeginPopupEx(id, ImGuiWindowFlags_AlwaysAutoResize|ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoSavedSettings); +} + +// r_avoid = the rectangle to avoid (e.g. for tooltip it is a rectangle around the mouse cursor which we want to avoid. for popups it's a small point around the cursor.) +// r_outer = the visible area rectangle, minus safe area padding. If our popup size won't fit because of safe area padding we ignore it. +// (r_outer is usually equivalent to the viewport rectangle minus padding, but when multi-viewports are enabled and monitor +// information are available, it may represent the entire platform monitor from the frame of reference of the current viewport. +// this allows us to have tooltips/popups displayed out of the parent viewport.) +ImVec2 ImGui::FindBestWindowPosForPopupEx(const ImVec2& ref_pos, const ImVec2& size, ImGuiDir* last_dir, const ImRect& r_outer, const ImRect& r_avoid, ImGuiPopupPositionPolicy policy) +{ + ImVec2 base_pos_clamped = ImClamp(ref_pos, r_outer.Min, r_outer.Max - size); + //GetForegroundDrawList()->AddRect(r_avoid.Min, r_avoid.Max, IM_COL32(255,0,0,255)); + //GetForegroundDrawList()->AddRect(r_outer.Min, r_outer.Max, IM_COL32(0,255,0,255)); + + // Combo Box policy (we want a connecting edge) + if (policy == ImGuiPopupPositionPolicy_ComboBox) + { + const ImGuiDir dir_prefered_order[ImGuiDir_COUNT] = { ImGuiDir_Down, ImGuiDir_Right, ImGuiDir_Left, ImGuiDir_Up }; + for (int n = (*last_dir != ImGuiDir_None) ? -1 : 0; n < ImGuiDir_COUNT; n++) + { + const ImGuiDir dir = (n == -1) ? *last_dir : dir_prefered_order[n]; + if (n != -1 && dir == *last_dir) // Already tried this direction? + continue; + ImVec2 pos; + if (dir == ImGuiDir_Down) pos = ImVec2(r_avoid.Min.x, r_avoid.Max.y); // Below, Toward Right (default) + if (dir == ImGuiDir_Right) pos = ImVec2(r_avoid.Min.x, r_avoid.Min.y - size.y); // Above, Toward Right + if (dir == ImGuiDir_Left) pos = ImVec2(r_avoid.Max.x - size.x, r_avoid.Max.y); // Below, Toward Left + if (dir == ImGuiDir_Up) pos = ImVec2(r_avoid.Max.x - size.x, r_avoid.Min.y - size.y); // Above, Toward Left + if (!r_outer.Contains(ImRect(pos, pos + size))) + continue; + *last_dir = dir; + return pos; + } + } + + // Default popup policy + const ImGuiDir dir_prefered_order[ImGuiDir_COUNT] = { ImGuiDir_Right, ImGuiDir_Down, ImGuiDir_Up, ImGuiDir_Left }; + for (int n = (*last_dir != ImGuiDir_None) ? -1 : 0; n < ImGuiDir_COUNT; n++) + { + const ImGuiDir dir = (n == -1) ? *last_dir : dir_prefered_order[n]; + if (n != -1 && dir == *last_dir) // Already tried this direction? + continue; + float avail_w = (dir == ImGuiDir_Left ? r_avoid.Min.x : r_outer.Max.x) - (dir == ImGuiDir_Right ? r_avoid.Max.x : r_outer.Min.x); + float avail_h = (dir == ImGuiDir_Up ? r_avoid.Min.y : r_outer.Max.y) - (dir == ImGuiDir_Down ? r_avoid.Max.y : r_outer.Min.y); + if (avail_w < size.x || avail_h < size.y) + continue; + ImVec2 pos; + pos.x = (dir == ImGuiDir_Left) ? r_avoid.Min.x - size.x : (dir == ImGuiDir_Right) ? r_avoid.Max.x : base_pos_clamped.x; + pos.y = (dir == ImGuiDir_Up) ? r_avoid.Min.y - size.y : (dir == ImGuiDir_Down) ? r_avoid.Max.y : base_pos_clamped.y; + *last_dir = dir; + return pos; + } + + // Fallback, try to keep within display + *last_dir = ImGuiDir_None; + ImVec2 pos = ref_pos; + pos.x = ImMax(ImMin(pos.x + size.x, r_outer.Max.x) - size.x, r_outer.Min.x); + pos.y = ImMax(ImMin(pos.y + size.y, r_outer.Max.y) - size.y, r_outer.Min.y); + return pos; +} + +// Note that this is used for popups, which can overlap the non work-area of individual viewports. +ImRect ImGui::GetWindowAllowedExtentRect(ImGuiWindow* window) +{ + ImGuiContext& g = *GImGui; + ImRect r_screen; + if (window->ViewportAllowPlatformMonitorExtend >= 0) + { + // Extent with be in the frame of reference of the given viewport (so Min is likely to be negative here) + const ImGuiPlatformMonitor& monitor = g.PlatformIO.Monitors[window->ViewportAllowPlatformMonitorExtend]; + r_screen.Min = monitor.WorkPos; + r_screen.Max = monitor.WorkPos + monitor.WorkSize; + } + else + { + // Use the full viewport area (not work area) for popups + r_screen.Min = window->Viewport->Pos; + r_screen.Max = window->Viewport->Pos + window->Viewport->Size; + } + ImVec2 padding = g.Style.DisplaySafeAreaPadding; + r_screen.Expand(ImVec2((r_screen.GetWidth() > padding.x * 2) ? -padding.x : 0.0f, (r_screen.GetHeight() > padding.y * 2) ? -padding.y : 0.0f)); + return r_screen; +} + +ImVec2 ImGui::FindBestWindowPosForPopup(ImGuiWindow* window) +{ + ImGuiContext& g = *GImGui; + if (window->Flags & ImGuiWindowFlags_ChildMenu) + { + // Child menus typically request _any_ position within the parent menu item, and then we move the new menu outside the parent bounds. + // This is how we end up with child menus appearing (most-commonly) on the right of the parent menu. + ImGuiWindow* parent_window = window->ParentWindow; + float horizontal_overlap = g.Style.ItemInnerSpacing.x; // We want some overlap to convey the relative depth of each menu (currently the amount of overlap is hard-coded to style.ItemSpacing.x). + ImRect r_outer = GetWindowAllowedExtentRect(window); + ImRect r_avoid; + if (parent_window->DC.MenuBarAppending) + r_avoid = ImRect(-FLT_MAX, parent_window->ClipRect.Min.y, FLT_MAX, parent_window->ClipRect.Max.y); // Avoid parent menu-bar. If we wanted multi-line menu-bar, we may instead want to have the calling window setup e.g. a NextWindowData.PosConstraintAvoidRect field + else + r_avoid = ImRect(parent_window->Pos.x + horizontal_overlap, -FLT_MAX, parent_window->Pos.x + parent_window->Size.x - horizontal_overlap - parent_window->ScrollbarSizes.x, FLT_MAX); + return FindBestWindowPosForPopupEx(window->Pos, window->Size, &window->AutoPosLastDirection, r_outer, r_avoid); + } + if (window->Flags & ImGuiWindowFlags_Popup) + { + ImRect r_outer = GetWindowAllowedExtentRect(window); + ImRect r_avoid = ImRect(window->Pos.x - 1, window->Pos.y - 1, window->Pos.x + 1, window->Pos.y + 1); + return FindBestWindowPosForPopupEx(window->Pos, window->Size, &window->AutoPosLastDirection, r_outer, r_avoid); + } + if (window->Flags & ImGuiWindowFlags_Tooltip) + { + // Position tooltip (always follows mouse) + float sc = g.Style.MouseCursorScale; + ImVec2 ref_pos = NavCalcPreferredRefPos(); + ImRect r_outer = GetWindowAllowedExtentRect(window); + ImRect r_avoid; + if (!g.NavDisableHighlight && g.NavDisableMouseHover && !(g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableSetMousePos)) + r_avoid = ImRect(ref_pos.x - 16, ref_pos.y - 8, ref_pos.x + 16, ref_pos.y + 8); + else + r_avoid = ImRect(ref_pos.x - 16, ref_pos.y - 8, ref_pos.x + 24 * sc, ref_pos.y + 24 * sc); // FIXME: Hard-coded based on mouse cursor shape expectation. Exact dimension not very important. + ImVec2 pos = FindBestWindowPosForPopupEx(ref_pos, window->Size, &window->AutoPosLastDirection, r_outer, r_avoid); + if (window->AutoPosLastDirection == ImGuiDir_None) + pos = ref_pos + ImVec2(2, 2); // If there's not enough room, for tooltip we prefer avoiding the cursor at all cost even if it means that part of the tooltip won't be visible. + return pos; + } + IM_ASSERT(0); + return window->Pos; +} + +//----------------------------------------------------------------------------- +// [SECTION] KEYBOARD/GAMEPAD NAVIGATION +//----------------------------------------------------------------------------- + +// FIXME-NAV: The existence of SetNavID vs SetNavIDWithRectRel vs SetFocusID is incredibly messy and confusing, +// and needs some explanation or serious refactoring. +void ImGui::SetNavID(ImGuiID id, int nav_layer, ImGuiID focus_scope_id) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(g.NavWindow); + IM_ASSERT(nav_layer == 0 || nav_layer == 1); + g.NavId = id; + g.NavFocusScopeId = focus_scope_id; + g.NavWindow->NavLastIds[nav_layer] = id; +} + +void ImGui::SetNavIDWithRectRel(ImGuiID id, int nav_layer, ImGuiID focus_scope_id, const ImRect& rect_rel) +{ + ImGuiContext& g = *GImGui; + SetNavID(id, nav_layer, focus_scope_id); + g.NavWindow->NavRectRel[nav_layer] = rect_rel; + g.NavMousePosDirty = true; + g.NavDisableHighlight = false; + g.NavDisableMouseHover = true; +} + +void ImGui::SetFocusID(ImGuiID id, ImGuiWindow* window) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(id != 0); + + // Assume that SetFocusID() is called in the context where its window->DC.NavLayerCurrent and window->DC.NavFocusScopeIdCurrent are valid. + // Note that window may be != g.CurrentWindow (e.g. SetFocusID call in InputTextEx for multi-line text) + const ImGuiNavLayer nav_layer = window->DC.NavLayerCurrent; + if (g.NavWindow != window) + g.NavInitRequest = false; + g.NavWindow = window; + g.NavId = id; + g.NavLayer = nav_layer; + g.NavFocusScopeId = window->DC.NavFocusScopeIdCurrent; + window->NavLastIds[nav_layer] = id; + if (window->DC.LastItemId == id) + window->NavRectRel[nav_layer] = ImRect(window->DC.LastItemRect.Min - window->Pos, window->DC.LastItemRect.Max - window->Pos); + + if (g.ActiveIdSource == ImGuiInputSource_Nav) + g.NavDisableMouseHover = true; + else + g.NavDisableHighlight = true; +} + +ImGuiDir ImGetDirQuadrantFromDelta(float dx, float dy) +{ + if (ImFabs(dx) > ImFabs(dy)) + return (dx > 0.0f) ? ImGuiDir_Right : ImGuiDir_Left; + return (dy > 0.0f) ? ImGuiDir_Down : ImGuiDir_Up; +} + +static float inline NavScoreItemDistInterval(float a0, float a1, float b0, float b1) +{ + if (a1 < b0) + return a1 - b0; + if (b1 < a0) + return a0 - b1; + return 0.0f; +} + +static void inline NavClampRectToVisibleAreaForMoveDir(ImGuiDir move_dir, ImRect& r, const ImRect& clip_rect) +{ + if (move_dir == ImGuiDir_Left || move_dir == ImGuiDir_Right) + { + r.Min.y = ImClamp(r.Min.y, clip_rect.Min.y, clip_rect.Max.y); + r.Max.y = ImClamp(r.Max.y, clip_rect.Min.y, clip_rect.Max.y); + } + else + { + r.Min.x = ImClamp(r.Min.x, clip_rect.Min.x, clip_rect.Max.x); + r.Max.x = ImClamp(r.Max.x, clip_rect.Min.x, clip_rect.Max.x); + } +} + +// Scoring function for gamepad/keyboard directional navigation. Based on https://gist.github.com/rygorous/6981057 +static bool ImGui::NavScoreItem(ImGuiNavMoveResult* result, ImRect cand) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if (g.NavLayer != window->DC.NavLayerCurrent) + return false; + + const ImRect& curr = g.NavScoringRect; // Current modified source rect (NB: we've applied Max.x = Min.x in NavUpdate() to inhibit the effect of having varied item width) + g.NavScoringCount++; + + // When entering through a NavFlattened border, we consider child window items as fully clipped for scoring + if (window->ParentWindow == g.NavWindow) + { + IM_ASSERT((window->Flags | g.NavWindow->Flags) & ImGuiWindowFlags_NavFlattened); + if (!window->ClipRect.Overlaps(cand)) + return false; + cand.ClipWithFull(window->ClipRect); // This allows the scored item to not overlap other candidates in the parent window + } + + // We perform scoring on items bounding box clipped by the current clipping rectangle on the other axis (clipping on our movement axis would give us equal scores for all clipped items) + // For example, this ensure that items in one column are not reached when moving vertically from items in another column. + NavClampRectToVisibleAreaForMoveDir(g.NavMoveClipDir, cand, window->ClipRect); + + // Compute distance between boxes + // FIXME-NAV: Introducing biases for vertical navigation, needs to be removed. + float dbx = NavScoreItemDistInterval(cand.Min.x, cand.Max.x, curr.Min.x, curr.Max.x); + float dby = NavScoreItemDistInterval(ImLerp(cand.Min.y, cand.Max.y, 0.2f), ImLerp(cand.Min.y, cand.Max.y, 0.8f), ImLerp(curr.Min.y, curr.Max.y, 0.2f), ImLerp(curr.Min.y, curr.Max.y, 0.8f)); // Scale down on Y to keep using box-distance for vertically touching items + if (dby != 0.0f && dbx != 0.0f) + dbx = (dbx/1000.0f) + ((dbx > 0.0f) ? +1.0f : -1.0f); + float dist_box = ImFabs(dbx) + ImFabs(dby); + + // Compute distance between centers (this is off by a factor of 2, but we only compare center distances with each other so it doesn't matter) + float dcx = (cand.Min.x + cand.Max.x) - (curr.Min.x + curr.Max.x); + float dcy = (cand.Min.y + cand.Max.y) - (curr.Min.y + curr.Max.y); + float dist_center = ImFabs(dcx) + ImFabs(dcy); // L1 metric (need this for our connectedness guarantee) + + // Determine which quadrant of 'curr' our candidate item 'cand' lies in based on distance + ImGuiDir quadrant; + float dax = 0.0f, day = 0.0f, dist_axial = 0.0f; + if (dbx != 0.0f || dby != 0.0f) + { + // For non-overlapping boxes, use distance between boxes + dax = dbx; + day = dby; + dist_axial = dist_box; + quadrant = ImGetDirQuadrantFromDelta(dbx, dby); + } + else if (dcx != 0.0f || dcy != 0.0f) + { + // For overlapping boxes with different centers, use distance between centers + dax = dcx; + day = dcy; + dist_axial = dist_center; + quadrant = ImGetDirQuadrantFromDelta(dcx, dcy); + } + else + { + // Degenerate case: two overlapping buttons with same center, break ties arbitrarily (note that LastItemId here is really the _previous_ item order, but it doesn't matter) + quadrant = (window->DC.LastItemId < g.NavId) ? ImGuiDir_Left : ImGuiDir_Right; + } + +#if IMGUI_DEBUG_NAV_SCORING + char buf[128]; + if (IsMouseHoveringRect(cand.Min, cand.Max)) + { + ImFormatString(buf, IM_ARRAYSIZE(buf), "dbox (%.2f,%.2f->%.4f)\ndcen (%.2f,%.2f->%.4f)\nd (%.2f,%.2f->%.4f)\nnav %c, quadrant %c", dbx, dby, dist_box, dcx, dcy, dist_center, dax, day, dist_axial, "WENS"[g.NavMoveDir], "WENS"[quadrant]); + ImDrawList* draw_list = GetForegroundDrawList(window); + draw_list->AddRect(curr.Min, curr.Max, IM_COL32(255,200,0,100)); + draw_list->AddRect(cand.Min, cand.Max, IM_COL32(255,255,0,200)); + draw_list->AddRectFilled(cand.Max - ImVec2(4,4), cand.Max + CalcTextSize(buf) + ImVec2(4,4), IM_COL32(40,0,0,150)); + draw_list->AddText(g.IO.FontDefault, 13.0f, cand.Max, ~0U, buf); + } + else if (g.IO.KeyCtrl) // Hold to preview score in matching quadrant. Press C to rotate. + { + if (IsKeyPressedMap(ImGuiKey_C)) { g.NavMoveDirLast = (ImGuiDir)((g.NavMoveDirLast + 1) & 3); g.IO.KeysDownDuration[g.IO.KeyMap[ImGuiKey_C]] = 0.01f; } + if (quadrant == g.NavMoveDir) + { + ImFormatString(buf, IM_ARRAYSIZE(buf), "%.0f/%.0f", dist_box, dist_center); + ImDrawList* draw_list = GetForegroundDrawList(window); + draw_list->AddRectFilled(cand.Min, cand.Max, IM_COL32(255, 0, 0, 200)); + draw_list->AddText(g.IO.FontDefault, 13.0f, cand.Min, IM_COL32(255, 255, 255, 255), buf); + } + } + #endif + + // Is it in the quadrant we're interesting in moving to? + bool new_best = false; + if (quadrant == g.NavMoveDir) + { + // Does it beat the current best candidate? + if (dist_box < result->DistBox) + { + result->DistBox = dist_box; + result->DistCenter = dist_center; + return true; + } + if (dist_box == result->DistBox) + { + // Try using distance between center points to break ties + if (dist_center < result->DistCenter) + { + result->DistCenter = dist_center; + new_best = true; + } + else if (dist_center == result->DistCenter) + { + // Still tied! we need to be extra-careful to make sure everything gets linked properly. We consistently break ties by symbolically moving "later" items + // (with higher index) to the right/downwards by an infinitesimal amount since we the current "best" button already (so it must have a lower index), + // this is fairly easy. This rule ensures that all buttons with dx==dy==0 will end up being linked in order of appearance along the x axis. + if (((g.NavMoveDir == ImGuiDir_Up || g.NavMoveDir == ImGuiDir_Down) ? dby : dbx) < 0.0f) // moving bj to the right/down decreases distance + new_best = true; + } + } + } + + // Axial check: if 'curr' has no link at all in some direction and 'cand' lies roughly in that direction, add a tentative link. This will only be kept if no "real" matches + // are found, so it only augments the graph produced by the above method using extra links. (important, since it doesn't guarantee strong connectedness) + // This is just to avoid buttons having no links in a particular direction when there's a suitable neighbor. you get good graphs without this too. + // 2017/09/29: FIXME: This now currently only enabled inside menu bars, ideally we'd disable it everywhere. Menus in particular need to catch failure. For general navigation it feels awkward. + // Disabling it may lead to disconnected graphs when nodes are very spaced out on different axis. Perhaps consider offering this as an option? + if (result->DistBox == FLT_MAX && dist_axial < result->DistAxial) // Check axial match + if (g.NavLayer == ImGuiNavLayer_Menu && !(g.NavWindow->Flags & ImGuiWindowFlags_ChildMenu)) + if ((g.NavMoveDir == ImGuiDir_Left && dax < 0.0f) || (g.NavMoveDir == ImGuiDir_Right && dax > 0.0f) || (g.NavMoveDir == ImGuiDir_Up && day < 0.0f) || (g.NavMoveDir == ImGuiDir_Down && day > 0.0f)) + { + result->DistAxial = dist_axial; + new_best = true; + } + + return new_best; +} + +// We get there when either NavId == id, or when g.NavAnyRequest is set (which is updated by NavUpdateAnyRequestFlag above) +static void ImGui::NavProcessItem(ImGuiWindow* window, const ImRect& nav_bb, const ImGuiID id) +{ + ImGuiContext& g = *GImGui; + //if (!g.IO.NavActive) // [2017/10/06] Removed this possibly redundant test but I am not sure of all the side-effects yet. Some of the feature here will need to work regardless of using a _NoNavInputs flag. + // return; + + const ImGuiItemFlags item_flags = window->DC.ItemFlags; + const ImRect nav_bb_rel(nav_bb.Min - window->Pos, nav_bb.Max - window->Pos); + + // Process Init Request + if (g.NavInitRequest && g.NavLayer == window->DC.NavLayerCurrent) + { + // Even if 'ImGuiItemFlags_NoNavDefaultFocus' is on (typically collapse/close button) we record the first ResultId so they can be used as a fallback + if (!(item_flags & ImGuiItemFlags_NoNavDefaultFocus) || g.NavInitResultId == 0) + { + g.NavInitResultId = id; + g.NavInitResultRectRel = nav_bb_rel; + } + if (!(item_flags & ImGuiItemFlags_NoNavDefaultFocus)) + { + g.NavInitRequest = false; // Found a match, clear request + NavUpdateAnyRequestFlag(); + } + } + + // Process Move Request (scoring for navigation) + // FIXME-NAV: Consider policy for double scoring (scoring from NavScoringRectScreen + scoring from a rect wrapped according to current wrapping policy) + if ((g.NavId != id || (g.NavMoveRequestFlags & ImGuiNavMoveFlags_AllowCurrentNavId)) && !(item_flags & (ImGuiItemFlags_Disabled|ImGuiItemFlags_NoNav))) + { + ImGuiNavMoveResult* result = (window == g.NavWindow) ? &g.NavMoveResultLocal : &g.NavMoveResultOther; +#if IMGUI_DEBUG_NAV_SCORING + // [DEBUG] Score all items in NavWindow at all times + if (!g.NavMoveRequest) + g.NavMoveDir = g.NavMoveDirLast; + bool new_best = NavScoreItem(result, nav_bb) && g.NavMoveRequest; +#else + bool new_best = g.NavMoveRequest && NavScoreItem(result, nav_bb); +#endif + if (new_best) + { + result->Window = window; + result->ID = id; + result->FocusScopeId = window->DC.NavFocusScopeIdCurrent; + result->RectRel = nav_bb_rel; + } + + // Features like PageUp/PageDown need to maintain a separate score for the visible set of items. + const float VISIBLE_RATIO = 0.70f; + if ((g.NavMoveRequestFlags & ImGuiNavMoveFlags_AlsoScoreVisibleSet) && window->ClipRect.Overlaps(nav_bb)) + if (ImClamp(nav_bb.Max.y, window->ClipRect.Min.y, window->ClipRect.Max.y) - ImClamp(nav_bb.Min.y, window->ClipRect.Min.y, window->ClipRect.Max.y) >= (nav_bb.Max.y - nav_bb.Min.y) * VISIBLE_RATIO) + if (NavScoreItem(&g.NavMoveResultLocalVisibleSet, nav_bb)) + { + result = &g.NavMoveResultLocalVisibleSet; + result->Window = window; + result->ID = id; + result->FocusScopeId = window->DC.NavFocusScopeIdCurrent; + result->RectRel = nav_bb_rel; + } + } + + // Update window-relative bounding box of navigated item + if (g.NavId == id) + { + g.NavWindow = window; // Always refresh g.NavWindow, because some operations such as FocusItem() don't have a window. + g.NavLayer = window->DC.NavLayerCurrent; + g.NavFocusScopeId = window->DC.NavFocusScopeIdCurrent; + g.NavIdIsAlive = true; + g.NavIdTabCounter = window->DC.FocusCounterTabStop; + window->NavRectRel[window->DC.NavLayerCurrent] = nav_bb_rel; // Store item bounding box (relative to window position) + } +} + +bool ImGui::NavMoveRequestButNoResultYet() +{ + ImGuiContext& g = *GImGui; + return g.NavMoveRequest && g.NavMoveResultLocal.ID == 0 && g.NavMoveResultOther.ID == 0; +} + +void ImGui::NavMoveRequestCancel() +{ + ImGuiContext& g = *GImGui; + g.NavMoveRequest = false; + NavUpdateAnyRequestFlag(); +} + +void ImGui::NavMoveRequestForward(ImGuiDir move_dir, ImGuiDir clip_dir, const ImRect& bb_rel, ImGuiNavMoveFlags move_flags) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(g.NavMoveRequestForward == ImGuiNavForward_None); + NavMoveRequestCancel(); + g.NavMoveDir = move_dir; + g.NavMoveClipDir = clip_dir; + g.NavMoveRequestForward = ImGuiNavForward_ForwardQueued; + g.NavMoveRequestFlags = move_flags; + g.NavWindow->NavRectRel[g.NavLayer] = bb_rel; +} + +void ImGui::NavMoveRequestTryWrapping(ImGuiWindow* window, ImGuiNavMoveFlags move_flags) +{ + ImGuiContext& g = *GImGui; + + // Navigation wrap-around logic is delayed to the end of the frame because this operation is only valid after entire + // popup is assembled and in case of appended popups it is not clear which EndPopup() call is final. + g.NavWrapRequestWindow = window; + g.NavWrapRequestFlags = move_flags; +} + +// FIXME: This could be replaced by updating a frame number in each window when (window == NavWindow) and (NavLayer == 0). +// This way we could find the last focused window among our children. It would be much less confusing this way? +static void ImGui::NavSaveLastChildNavWindowIntoParent(ImGuiWindow* nav_window) +{ + ImGuiWindow* parent = nav_window; + while (parent && parent->RootWindowDockStop != parent && (parent->Flags & ImGuiWindowFlags_ChildWindow) != 0 && (parent->Flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_ChildMenu)) == 0) + parent = parent->ParentWindow; + if (parent && parent != nav_window) + parent->NavLastChildNavWindow = nav_window; +} + +// Restore the last focused child. +// Call when we are expected to land on the Main Layer (0) after FocusWindow() +static ImGuiWindow* ImGui::NavRestoreLastChildNavWindow(ImGuiWindow* window) +{ + if (window->NavLastChildNavWindow && window->NavLastChildNavWindow->WasActive) + return window->NavLastChildNavWindow; + if (window->DockNodeAsHost && window->DockNodeAsHost->TabBar) + if (ImGuiTabItem* tab = TabBarFindMostRecentlySelectedTabForActiveWindow(window->DockNodeAsHost->TabBar)) + return tab->Window; + return window; +} + +static void NavRestoreLayer(ImGuiNavLayer layer) +{ + ImGuiContext& g = *GImGui; + g.NavLayer = layer; + if (layer == 0) + g.NavWindow = ImGui::NavRestoreLastChildNavWindow(g.NavWindow); + ImGuiWindow* window = g.NavWindow; + if (window->NavLastIds[layer] != 0) + ImGui::SetNavIDWithRectRel(window->NavLastIds[layer], layer, 0, g.NavWindow->NavRectRel[layer]); + else + ImGui::NavInitWindow(window, true); +} + +static inline void ImGui::NavUpdateAnyRequestFlag() +{ + ImGuiContext& g = *GImGui; + g.NavAnyRequest = g.NavMoveRequest || g.NavInitRequest || (IMGUI_DEBUG_NAV_SCORING && g.NavWindow != NULL); + if (g.NavAnyRequest) + IM_ASSERT(g.NavWindow != NULL); +} + +// This needs to be called before we submit any widget (aka in or before Begin) +void ImGui::NavInitWindow(ImGuiWindow* window, bool force_reinit) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(window == g.NavWindow); + bool init_for_nav = false; + if (!(window->Flags & ImGuiWindowFlags_NoNavInputs)) + if (!(window->Flags & ImGuiWindowFlags_ChildWindow) || (window->Flags & ImGuiWindowFlags_Popup) || (window->NavLastIds[0] == 0) || force_reinit) + init_for_nav = true; + //IMGUI_DEBUG_LOG("[Nav] NavInitWindow() init_for_nav=%d, window=\"%s\", layer=%d\n", init_for_nav, window->Name, g.NavLayer); + if (init_for_nav) + { + SetNavID(0, g.NavLayer, 0); + g.NavInitRequest = true; + g.NavInitRequestFromMove = false; + g.NavInitResultId = 0; + g.NavInitResultRectRel = ImRect(); + NavUpdateAnyRequestFlag(); + } + else + { + g.NavId = window->NavLastIds[0]; + g.NavFocusScopeId = 0; + } +} + +static ImVec2 ImGui::NavCalcPreferredRefPos() +{ + ImGuiContext& g = *GImGui; + if (g.NavDisableHighlight || !g.NavDisableMouseHover || !g.NavWindow) + { + // Mouse (we need a fallback in case the mouse becomes invalid after being used) + if (IsMousePosValid(&g.IO.MousePos)) + return g.IO.MousePos; + return g.LastValidMousePos; + } + else + { + // When navigation is active and mouse is disabled, decide on an arbitrary position around the bottom left of the currently navigated item. + const ImRect& rect_rel = g.NavWindow->NavRectRel[g.NavLayer]; + ImVec2 pos = g.NavWindow->Pos + ImVec2(rect_rel.Min.x + ImMin(g.Style.FramePadding.x * 4, rect_rel.GetWidth()), rect_rel.Max.y - ImMin(g.Style.FramePadding.y, rect_rel.GetHeight())); + ImRect visible_rect = g.NavWindow->Viewport->GetMainRect(); + return ImFloor(ImClamp(pos, visible_rect.Min, visible_rect.Max)); // ImFloor() is important because non-integer mouse position application in back-end might be lossy and result in undesirable non-zero delta. + } +} + +float ImGui::GetNavInputAmount(ImGuiNavInput n, ImGuiInputReadMode mode) +{ + ImGuiContext& g = *GImGui; + if (mode == ImGuiInputReadMode_Down) + return g.IO.NavInputs[n]; // Instant, read analog input (0.0f..1.0f, as provided by user) + + const float t = g.IO.NavInputsDownDuration[n]; + if (t < 0.0f && mode == ImGuiInputReadMode_Released) // Return 1.0f when just released, no repeat, ignore analog input. + return (g.IO.NavInputsDownDurationPrev[n] >= 0.0f ? 1.0f : 0.0f); + if (t < 0.0f) + return 0.0f; + if (mode == ImGuiInputReadMode_Pressed) // Return 1.0f when just pressed, no repeat, ignore analog input. + return (t == 0.0f) ? 1.0f : 0.0f; + if (mode == ImGuiInputReadMode_Repeat) + return (float)CalcTypematicRepeatAmount(t - g.IO.DeltaTime, t, g.IO.KeyRepeatDelay * 0.72f, g.IO.KeyRepeatRate * 0.80f); + if (mode == ImGuiInputReadMode_RepeatSlow) + return (float)CalcTypematicRepeatAmount(t - g.IO.DeltaTime, t, g.IO.KeyRepeatDelay * 1.25f, g.IO.KeyRepeatRate * 2.00f); + if (mode == ImGuiInputReadMode_RepeatFast) + return (float)CalcTypematicRepeatAmount(t - g.IO.DeltaTime, t, g.IO.KeyRepeatDelay * 0.72f, g.IO.KeyRepeatRate * 0.30f); + return 0.0f; +} + +ImVec2 ImGui::GetNavInputAmount2d(ImGuiNavDirSourceFlags dir_sources, ImGuiInputReadMode mode, float slow_factor, float fast_factor) +{ + ImVec2 delta(0.0f, 0.0f); + if (dir_sources & ImGuiNavDirSourceFlags_Keyboard) + delta += ImVec2(GetNavInputAmount(ImGuiNavInput_KeyRight_, mode) - GetNavInputAmount(ImGuiNavInput_KeyLeft_, mode), GetNavInputAmount(ImGuiNavInput_KeyDown_, mode) - GetNavInputAmount(ImGuiNavInput_KeyUp_, mode)); + if (dir_sources & ImGuiNavDirSourceFlags_PadDPad) + delta += ImVec2(GetNavInputAmount(ImGuiNavInput_DpadRight, mode) - GetNavInputAmount(ImGuiNavInput_DpadLeft, mode), GetNavInputAmount(ImGuiNavInput_DpadDown, mode) - GetNavInputAmount(ImGuiNavInput_DpadUp, mode)); + if (dir_sources & ImGuiNavDirSourceFlags_PadLStick) + delta += ImVec2(GetNavInputAmount(ImGuiNavInput_LStickRight, mode) - GetNavInputAmount(ImGuiNavInput_LStickLeft, mode), GetNavInputAmount(ImGuiNavInput_LStickDown, mode) - GetNavInputAmount(ImGuiNavInput_LStickUp, mode)); + if (slow_factor != 0.0f && IsNavInputDown(ImGuiNavInput_TweakSlow)) + delta *= slow_factor; + if (fast_factor != 0.0f && IsNavInputDown(ImGuiNavInput_TweakFast)) + delta *= fast_factor; + return delta; +} + +static void ImGui::NavUpdate() +{ + ImGuiContext& g = *GImGui; + g.IO.WantSetMousePos = false; + g.NavWrapRequestWindow = NULL; + g.NavWrapRequestFlags = ImGuiNavMoveFlags_None; +#if 0 + if (g.NavScoringCount > 0) IMGUI_DEBUG_LOG("NavScoringCount %d for '%s' layer %d (Init:%d, Move:%d)\n", g.FrameCount, g.NavScoringCount, g.NavWindow ? g.NavWindow->Name : "NULL", g.NavLayer, g.NavInitRequest || g.NavInitResultId != 0, g.NavMoveRequest); +#endif + + // Set input source as Gamepad when buttons are pressed (as some features differs when used with Gamepad vs Keyboard) + // (do it before we map Keyboard input!) + bool nav_keyboard_active = (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) != 0; + bool nav_gamepad_active = (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) != 0 && (g.IO.BackendFlags & ImGuiBackendFlags_HasGamepad) != 0; + if (nav_gamepad_active) + if (g.IO.NavInputs[ImGuiNavInput_Activate] > 0.0f || g.IO.NavInputs[ImGuiNavInput_Input] > 0.0f || g.IO.NavInputs[ImGuiNavInput_Cancel] > 0.0f || g.IO.NavInputs[ImGuiNavInput_Menu] > 0.0f) + g.NavInputSource = ImGuiInputSource_NavGamepad; + + // Update Keyboard->Nav inputs mapping + if (nav_keyboard_active) + { + #define NAV_MAP_KEY(_KEY, _NAV_INPUT) do { if (IsKeyDown(g.IO.KeyMap[_KEY])) { g.IO.NavInputs[_NAV_INPUT] = 1.0f; g.NavInputSource = ImGuiInputSource_NavKeyboard; } } while (0) + NAV_MAP_KEY(ImGuiKey_Space, ImGuiNavInput_Activate ); + NAV_MAP_KEY(ImGuiKey_Enter, ImGuiNavInput_Input ); + NAV_MAP_KEY(ImGuiKey_Escape, ImGuiNavInput_Cancel ); + NAV_MAP_KEY(ImGuiKey_LeftArrow, ImGuiNavInput_KeyLeft_ ); + NAV_MAP_KEY(ImGuiKey_RightArrow,ImGuiNavInput_KeyRight_); + NAV_MAP_KEY(ImGuiKey_UpArrow, ImGuiNavInput_KeyUp_ ); + NAV_MAP_KEY(ImGuiKey_DownArrow, ImGuiNavInput_KeyDown_ ); + if (g.IO.KeyCtrl) + g.IO.NavInputs[ImGuiNavInput_TweakSlow] = 1.0f; + if (g.IO.KeyShift) + g.IO.NavInputs[ImGuiNavInput_TweakFast] = 1.0f; + if (g.IO.KeyAlt && !g.IO.KeyCtrl) // AltGR is Alt+Ctrl, also even on keyboards without AltGR we don't want Alt+Ctrl to open menu. + g.IO.NavInputs[ImGuiNavInput_KeyMenu_] = 1.0f; + #undef NAV_MAP_KEY + } + memcpy(g.IO.NavInputsDownDurationPrev, g.IO.NavInputsDownDuration, sizeof(g.IO.NavInputsDownDuration)); + for (int i = 0; i < IM_ARRAYSIZE(g.IO.NavInputs); i++) + g.IO.NavInputsDownDuration[i] = (g.IO.NavInputs[i] > 0.0f) ? (g.IO.NavInputsDownDuration[i] < 0.0f ? 0.0f : g.IO.NavInputsDownDuration[i] + g.IO.DeltaTime) : -1.0f; + + // Process navigation init request (select first/default focus) + // In very rare cases g.NavWindow may be null (e.g. clearing focus after requesting an init request, which does happen when releasing Alt while clicking on void) + if (g.NavInitResultId != 0 && (!g.NavDisableHighlight || g.NavInitRequestFromMove) && g.NavWindow) + { + // Apply result from previous navigation init request (will typically select the first item, unless SetItemDefaultFocus() has been called) + //IMGUI_DEBUG_LOG("[Nav] Apply NavInitRequest result: 0x%08X Layer %d in \"%s\"\n", g.NavInitResultId, g.NavLayer, g.NavWindow->Name); + if (g.NavInitRequestFromMove) + SetNavIDWithRectRel(g.NavInitResultId, g.NavLayer, 0, g.NavInitResultRectRel); + else + SetNavID(g.NavInitResultId, g.NavLayer, 0); + g.NavWindow->NavRectRel[g.NavLayer] = g.NavInitResultRectRel; + } + g.NavInitRequest = false; + g.NavInitRequestFromMove = false; + g.NavInitResultId = 0; + g.NavJustMovedToId = 0; + + // Process navigation move request + if (g.NavMoveRequest) + NavUpdateMoveResult(); + + // When a forwarded move request failed, we restore the highlight that we disabled during the forward frame + if (g.NavMoveRequestForward == ImGuiNavForward_ForwardActive) + { + IM_ASSERT(g.NavMoveRequest); + if (g.NavMoveResultLocal.ID == 0 && g.NavMoveResultOther.ID == 0) + g.NavDisableHighlight = false; + g.NavMoveRequestForward = ImGuiNavForward_None; + } + + // Apply application mouse position movement, after we had a chance to process move request result. + if (g.NavMousePosDirty && g.NavIdIsAlive) + { + // Set mouse position given our knowledge of the navigated item position from last frame + if ((g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableSetMousePos) && (g.IO.BackendFlags & ImGuiBackendFlags_HasSetMousePos)) + { + if (!g.NavDisableHighlight && g.NavDisableMouseHover && g.NavWindow) + { + g.IO.MousePos = g.IO.MousePosPrev = NavCalcPreferredRefPos(); + g.IO.WantSetMousePos = true; + } + } + g.NavMousePosDirty = false; + } + g.NavIdIsAlive = false; + g.NavJustTabbedId = 0; + IM_ASSERT(g.NavLayer == 0 || g.NavLayer == 1); + + // Store our return window (for returning from Layer 1 to Layer 0) and clear it as soon as we step back in our own Layer 0 + if (g.NavWindow) + NavSaveLastChildNavWindowIntoParent(g.NavWindow); + if (g.NavWindow && g.NavWindow->NavLastChildNavWindow != NULL && g.NavLayer == ImGuiNavLayer_Main) + g.NavWindow->NavLastChildNavWindow = NULL; + + // Update CTRL+TAB and Windowing features (hold Square to move/resize/etc.) + NavUpdateWindowing(); + + // Set output flags for user application + g.IO.NavActive = (nav_keyboard_active || nav_gamepad_active) && g.NavWindow && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs); + g.IO.NavVisible = (g.IO.NavActive && g.NavId != 0 && !g.NavDisableHighlight) || (g.NavWindowingTarget != NULL); + + // Process NavCancel input (to close a popup, get back to parent, clear focus) + if (IsNavInputTest(ImGuiNavInput_Cancel, ImGuiInputReadMode_Pressed)) + { + if (g.ActiveId != 0) + { + if (!IsActiveIdUsingNavInput(ImGuiNavInput_Cancel)) + ClearActiveID(); + } + else if (g.NavWindow && (g.NavWindow->Flags & ImGuiWindowFlags_ChildWindow) && !(g.NavWindow->Flags & ImGuiWindowFlags_Popup) && g.NavWindow->ParentWindow && g.NavWindow != g.NavWindow->RootWindowDockStop) + { + // Exit child window + ImGuiWindow* child_window = g.NavWindow; + ImGuiWindow* parent_window = g.NavWindow->ParentWindow; + IM_ASSERT(child_window->ChildId != 0); + FocusWindow(parent_window); + SetNavID(child_window->ChildId, 0, 0); + // Reassigning with same value, we're being explicit here. + g.NavIdIsAlive = false; // -V1048 + if (g.NavDisableMouseHover) + g.NavMousePosDirty = true; + } + else if (g.OpenPopupStack.Size > 0) + { + // Close open popup/menu + if (!(g.OpenPopupStack.back().Window->Flags & ImGuiWindowFlags_Modal)) + ClosePopupToLevel(g.OpenPopupStack.Size - 1, true); + } + else if (g.NavLayer != ImGuiNavLayer_Main) + { + // Leave the "menu" layer + NavRestoreLayer(ImGuiNavLayer_Main); + } + else + { + // Clear NavLastId for popups but keep it for regular child window so we can leave one and come back where we were + if (g.NavWindow && ((g.NavWindow->Flags & ImGuiWindowFlags_Popup) || !(g.NavWindow->Flags & ImGuiWindowFlags_ChildWindow))) + g.NavWindow->NavLastIds[0] = 0; + g.NavId = g.NavFocusScopeId = 0; + } + } + + // Process manual activation request + g.NavActivateId = g.NavActivateDownId = g.NavActivatePressedId = g.NavInputId = 0; + if (g.NavId != 0 && !g.NavDisableHighlight && !g.NavWindowingTarget && g.NavWindow && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs)) + { + bool activate_down = IsNavInputDown(ImGuiNavInput_Activate); + bool activate_pressed = activate_down && IsNavInputTest(ImGuiNavInput_Activate, ImGuiInputReadMode_Pressed); + if (g.ActiveId == 0 && activate_pressed) + g.NavActivateId = g.NavId; + if ((g.ActiveId == 0 || g.ActiveId == g.NavId) && activate_down) + g.NavActivateDownId = g.NavId; + if ((g.ActiveId == 0 || g.ActiveId == g.NavId) && activate_pressed) + g.NavActivatePressedId = g.NavId; + if ((g.ActiveId == 0 || g.ActiveId == g.NavId) && IsNavInputTest(ImGuiNavInput_Input, ImGuiInputReadMode_Pressed)) + g.NavInputId = g.NavId; + } + if (g.NavWindow && (g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs)) + g.NavDisableHighlight = true; + if (g.NavActivateId != 0) + IM_ASSERT(g.NavActivateDownId == g.NavActivateId); + g.NavMoveRequest = false; + + // Process programmatic activation request + if (g.NavNextActivateId != 0) + g.NavActivateId = g.NavActivateDownId = g.NavActivatePressedId = g.NavInputId = g.NavNextActivateId; + g.NavNextActivateId = 0; + + // Initiate directional inputs request + if (g.NavMoveRequestForward == ImGuiNavForward_None) + { + g.NavMoveDir = ImGuiDir_None; + g.NavMoveRequestFlags = ImGuiNavMoveFlags_None; + if (g.NavWindow && !g.NavWindowingTarget && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs)) + { + const ImGuiInputReadMode read_mode = ImGuiInputReadMode_Repeat; + if (!IsActiveIdUsingNavDir(ImGuiDir_Left) && (IsNavInputTest(ImGuiNavInput_DpadLeft, read_mode) || IsNavInputTest(ImGuiNavInput_KeyLeft_, read_mode))) { g.NavMoveDir = ImGuiDir_Left; } + if (!IsActiveIdUsingNavDir(ImGuiDir_Right) && (IsNavInputTest(ImGuiNavInput_DpadRight, read_mode) || IsNavInputTest(ImGuiNavInput_KeyRight_, read_mode))) { g.NavMoveDir = ImGuiDir_Right; } + if (!IsActiveIdUsingNavDir(ImGuiDir_Up) && (IsNavInputTest(ImGuiNavInput_DpadUp, read_mode) || IsNavInputTest(ImGuiNavInput_KeyUp_, read_mode))) { g.NavMoveDir = ImGuiDir_Up; } + if (!IsActiveIdUsingNavDir(ImGuiDir_Down) && (IsNavInputTest(ImGuiNavInput_DpadDown, read_mode) || IsNavInputTest(ImGuiNavInput_KeyDown_, read_mode))) { g.NavMoveDir = ImGuiDir_Down; } + } + g.NavMoveClipDir = g.NavMoveDir; + } + else + { + // Forwarding previous request (which has been modified, e.g. wrap around menus rewrite the requests with a starting rectangle at the other side of the window) + // (Preserve g.NavMoveRequestFlags, g.NavMoveClipDir which were set by the NavMoveRequestForward() function) + IM_ASSERT(g.NavMoveDir != ImGuiDir_None && g.NavMoveClipDir != ImGuiDir_None); + IM_ASSERT(g.NavMoveRequestForward == ImGuiNavForward_ForwardQueued); + g.NavMoveRequestForward = ImGuiNavForward_ForwardActive; + } + + // Update PageUp/PageDown/Home/End scroll + // FIXME-NAV: Consider enabling those keys even without the master ImGuiConfigFlags_NavEnableKeyboard flag? + float nav_scoring_rect_offset_y = 0.0f; + if (nav_keyboard_active) + nav_scoring_rect_offset_y = NavUpdatePageUpPageDown(); + + // If we initiate a movement request and have no current NavId, we initiate a InitDefautRequest that will be used as a fallback if the direction fails to find a match + if (g.NavMoveDir != ImGuiDir_None) + { + g.NavMoveRequest = true; + g.NavMoveRequestKeyMods = g.IO.KeyMods; + g.NavMoveDirLast = g.NavMoveDir; + } + if (g.NavMoveRequest && g.NavId == 0) + { + //IMGUI_DEBUG_LOG("[Nav] NavInitRequest from move, window \"%s\", layer=%d\n", g.NavWindow->Name, g.NavLayer); + g.NavInitRequest = g.NavInitRequestFromMove = true; + // Reassigning with same value, we're being explicit here. + g.NavInitResultId = 0; // -V1048 + g.NavDisableHighlight = false; + } + NavUpdateAnyRequestFlag(); + + // Scrolling + if (g.NavWindow && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs) && !g.NavWindowingTarget) + { + // *Fallback* manual-scroll with Nav directional keys when window has no navigable item + ImGuiWindow* window = g.NavWindow; + const float scroll_speed = IM_ROUND(window->CalcFontSize() * 100 * g.IO.DeltaTime); // We need round the scrolling speed because sub-pixel scroll isn't reliably supported. + if (window->DC.NavLayerActiveMask == 0x00 && window->DC.NavHasScroll && g.NavMoveRequest) + { + if (g.NavMoveDir == ImGuiDir_Left || g.NavMoveDir == ImGuiDir_Right) + SetScrollX(window, ImFloor(window->Scroll.x + ((g.NavMoveDir == ImGuiDir_Left) ? -1.0f : +1.0f) * scroll_speed)); + if (g.NavMoveDir == ImGuiDir_Up || g.NavMoveDir == ImGuiDir_Down) + SetScrollY(window, ImFloor(window->Scroll.y + ((g.NavMoveDir == ImGuiDir_Up) ? -1.0f : +1.0f) * scroll_speed)); + } + + // *Normal* Manual scroll with NavScrollXXX keys + // Next movement request will clamp the NavId reference rectangle to the visible area, so navigation will resume within those bounds. + ImVec2 scroll_dir = GetNavInputAmount2d(ImGuiNavDirSourceFlags_PadLStick, ImGuiInputReadMode_Down, 1.0f/10.0f, 10.0f); + if (scroll_dir.x != 0.0f && window->ScrollbarX) + { + SetScrollX(window, ImFloor(window->Scroll.x + scroll_dir.x * scroll_speed)); + g.NavMoveFromClampedRefRect = true; + } + if (scroll_dir.y != 0.0f) + { + SetScrollY(window, ImFloor(window->Scroll.y + scroll_dir.y * scroll_speed)); + g.NavMoveFromClampedRefRect = true; + } + } + + // Reset search results + g.NavMoveResultLocal.Clear(); + g.NavMoveResultLocalVisibleSet.Clear(); + g.NavMoveResultOther.Clear(); + + // When we have manually scrolled (without using navigation) and NavId becomes out of bounds, we project its bounding box to the visible area to restart navigation within visible items + if (g.NavMoveRequest && g.NavMoveFromClampedRefRect && g.NavLayer == ImGuiNavLayer_Main) + { + ImGuiWindow* window = g.NavWindow; + ImRect window_rect_rel(window->InnerRect.Min - window->Pos - ImVec2(1,1), window->InnerRect.Max - window->Pos + ImVec2(1,1)); + if (!window_rect_rel.Contains(window->NavRectRel[g.NavLayer])) + { + float pad = window->CalcFontSize() * 0.5f; + window_rect_rel.Expand(ImVec2(-ImMin(window_rect_rel.GetWidth(), pad), -ImMin(window_rect_rel.GetHeight(), pad))); // Terrible approximation for the intent of starting navigation from first fully visible item + window->NavRectRel[g.NavLayer].ClipWith(window_rect_rel); + g.NavId = g.NavFocusScopeId = 0; + } + g.NavMoveFromClampedRefRect = false; + } + + // For scoring we use a single segment on the left side our current item bounding box (not touching the edge to avoid box overlap with zero-spaced items) + ImRect nav_rect_rel = (g.NavWindow && !g.NavWindow->NavRectRel[g.NavLayer].IsInverted()) ? g.NavWindow->NavRectRel[g.NavLayer] : ImRect(0,0,0,0); + g.NavScoringRect = g.NavWindow ? ImRect(g.NavWindow->Pos + nav_rect_rel.Min, g.NavWindow->Pos + nav_rect_rel.Max) : ImRect(0,0,0,0); + g.NavScoringRect.TranslateY(nav_scoring_rect_offset_y); + g.NavScoringRect.Min.x = ImMin(g.NavScoringRect.Min.x + 1.0f, g.NavScoringRect.Max.x); + g.NavScoringRect.Max.x = g.NavScoringRect.Min.x; + IM_ASSERT(!g.NavScoringRect.IsInverted()); // Ensure if we have a finite, non-inverted bounding box here will allows us to remove extraneous ImFabs() calls in NavScoreItem(). + //GetForegroundDrawList()->AddRect(g.NavScoringRectScreen.Min, g.NavScoringRectScreen.Max, IM_COL32(255,200,0,255)); // [DEBUG] + g.NavScoringCount = 0; +#if IMGUI_DEBUG_NAV_RECTS + if (g.NavWindow) + { + ImDrawList* draw_list = GetForegroundDrawList(g.NavWindow); + if (1) { for (int layer = 0; layer < 2; layer++) draw_list->AddRect(g.NavWindow->Pos + g.NavWindow->NavRectRel[layer].Min, g.NavWindow->Pos + g.NavWindow->NavRectRel[layer].Max, IM_COL32(255,200,0,255)); } // [DEBUG] + if (1) { ImU32 col = (!g.NavWindow->Hidden) ? IM_COL32(255,0,255,255) : IM_COL32(255,0,0,255); ImVec2 p = NavCalcPreferredRefPos(); char buf[32]; ImFormatString(buf, 32, "%d", g.NavLayer); draw_list->AddCircleFilled(p, 3.0f, col); draw_list->AddText(NULL, 13.0f, p + ImVec2(8,-4), col, buf); } + } +#endif +} + +// Apply result from previous frame navigation directional move request +static void ImGui::NavUpdateMoveResult() +{ + ImGuiContext& g = *GImGui; + if (g.NavMoveResultLocal.ID == 0 && g.NavMoveResultOther.ID == 0) + { + // In a situation when there is no results but NavId != 0, re-enable the Navigation highlight (because g.NavId is not considered as a possible result) + if (g.NavId != 0) + { + g.NavDisableHighlight = false; + g.NavDisableMouseHover = true; + } + return; + } + + // Select which result to use + ImGuiNavMoveResult* result = (g.NavMoveResultLocal.ID != 0) ? &g.NavMoveResultLocal : &g.NavMoveResultOther; + + // PageUp/PageDown behavior first jumps to the bottom/top mostly visible item, _otherwise_ use the result from the previous/next page. + if (g.NavMoveRequestFlags & ImGuiNavMoveFlags_AlsoScoreVisibleSet) + if (g.NavMoveResultLocalVisibleSet.ID != 0 && g.NavMoveResultLocalVisibleSet.ID != g.NavId) + result = &g.NavMoveResultLocalVisibleSet; + + // Maybe entering a flattened child from the outside? In this case solve the tie using the regular scoring rules. + if (result != &g.NavMoveResultOther && g.NavMoveResultOther.ID != 0 && g.NavMoveResultOther.Window->ParentWindow == g.NavWindow) + if ((g.NavMoveResultOther.DistBox < result->DistBox) || (g.NavMoveResultOther.DistBox == result->DistBox && g.NavMoveResultOther.DistCenter < result->DistCenter)) + result = &g.NavMoveResultOther; + IM_ASSERT(g.NavWindow && result->Window); + + // Scroll to keep newly navigated item fully into view. + if (g.NavLayer == ImGuiNavLayer_Main) + { + ImVec2 delta_scroll; + if (g.NavMoveRequestFlags & ImGuiNavMoveFlags_ScrollToEdge) + { + float scroll_target = (g.NavMoveDir == ImGuiDir_Up) ? result->Window->ScrollMax.y : 0.0f; + delta_scroll.y = result->Window->Scroll.y - scroll_target; + SetScrollY(result->Window, scroll_target); + } + else + { + ImRect rect_abs = ImRect(result->RectRel.Min + result->Window->Pos, result->RectRel.Max + result->Window->Pos); + delta_scroll = ScrollToBringRectIntoView(result->Window, rect_abs); + } + + // Offset our result position so mouse position can be applied immediately after in NavUpdate() + result->RectRel.TranslateX(-delta_scroll.x); + result->RectRel.TranslateY(-delta_scroll.y); + } + + ClearActiveID(); + g.NavWindow = result->Window; + if (g.NavId != result->ID) + { + // Don't set NavJustMovedToId if just landed on the same spot (which may happen with ImGuiNavMoveFlags_AllowCurrentNavId) + g.NavJustMovedToId = result->ID; + g.NavJustMovedToFocusScopeId = result->FocusScopeId; + g.NavJustMovedToKeyMods = g.NavMoveRequestKeyMods; + } + SetNavIDWithRectRel(result->ID, g.NavLayer, result->FocusScopeId, result->RectRel); + g.NavMoveFromClampedRefRect = false; +} + +// Handle PageUp/PageDown/Home/End keys +static float ImGui::NavUpdatePageUpPageDown() +{ + ImGuiContext& g = *GImGui; + if (g.NavMoveDir != ImGuiDir_None || g.NavWindow == NULL) + return 0.0f; + if ((g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs) || g.NavWindowingTarget != NULL || g.NavLayer != ImGuiNavLayer_Main) + return 0.0f; + + ImGuiWindow* window = g.NavWindow; + const bool page_up_held = IsKeyDown(g.IO.KeyMap[ImGuiKey_PageUp]) && !IsActiveIdUsingKey(ImGuiKey_PageUp); + const bool page_down_held = IsKeyDown(g.IO.KeyMap[ImGuiKey_PageDown]) && !IsActiveIdUsingKey(ImGuiKey_PageDown); + const bool home_pressed = IsKeyPressed(g.IO.KeyMap[ImGuiKey_Home]) && !IsActiveIdUsingKey(ImGuiKey_Home); + const bool end_pressed = IsKeyPressed(g.IO.KeyMap[ImGuiKey_End]) && !IsActiveIdUsingKey(ImGuiKey_End); + if (page_up_held != page_down_held || home_pressed != end_pressed) // If either (not both) are pressed + { + if (window->DC.NavLayerActiveMask == 0x00 && window->DC.NavHasScroll) + { + // Fallback manual-scroll when window has no navigable item + if (IsKeyPressed(g.IO.KeyMap[ImGuiKey_PageUp], true)) + SetScrollY(window, window->Scroll.y - window->InnerRect.GetHeight()); + else if (IsKeyPressed(g.IO.KeyMap[ImGuiKey_PageDown], true)) + SetScrollY(window, window->Scroll.y + window->InnerRect.GetHeight()); + else if (home_pressed) + SetScrollY(window, 0.0f); + else if (end_pressed) + SetScrollY(window, window->ScrollMax.y); + } + else + { + ImRect& nav_rect_rel = window->NavRectRel[g.NavLayer]; + const float page_offset_y = ImMax(0.0f, window->InnerRect.GetHeight() - window->CalcFontSize() * 1.0f + nav_rect_rel.GetHeight()); + float nav_scoring_rect_offset_y = 0.0f; + if (IsKeyPressed(g.IO.KeyMap[ImGuiKey_PageUp], true)) + { + nav_scoring_rect_offset_y = -page_offset_y; + g.NavMoveDir = ImGuiDir_Down; // Because our scoring rect is offset up, we request the down direction (so we can always land on the last item) + g.NavMoveClipDir = ImGuiDir_Up; + g.NavMoveRequestFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_AlsoScoreVisibleSet; + } + else if (IsKeyPressed(g.IO.KeyMap[ImGuiKey_PageDown], true)) + { + nav_scoring_rect_offset_y = +page_offset_y; + g.NavMoveDir = ImGuiDir_Up; // Because our scoring rect is offset down, we request the up direction (so we can always land on the last item) + g.NavMoveClipDir = ImGuiDir_Down; + g.NavMoveRequestFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_AlsoScoreVisibleSet; + } + else if (home_pressed) + { + // FIXME-NAV: handling of Home/End is assuming that the top/bottom most item will be visible with Scroll.y == 0/ScrollMax.y + // Scrolling will be handled via the ImGuiNavMoveFlags_ScrollToEdge flag, we don't scroll immediately to avoid scrolling happening before nav result. + // Preserve current horizontal position if we have any. + nav_rect_rel.Min.y = nav_rect_rel.Max.y = -window->Scroll.y; + if (nav_rect_rel.IsInverted()) + nav_rect_rel.Min.x = nav_rect_rel.Max.x = 0.0f; + g.NavMoveDir = ImGuiDir_Down; + g.NavMoveRequestFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_ScrollToEdge; + } + else if (end_pressed) + { + nav_rect_rel.Min.y = nav_rect_rel.Max.y = window->ScrollMax.y + window->SizeFull.y - window->Scroll.y; + if (nav_rect_rel.IsInverted()) + nav_rect_rel.Min.x = nav_rect_rel.Max.x = 0.0f; + g.NavMoveDir = ImGuiDir_Up; + g.NavMoveRequestFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_ScrollToEdge; + } + return nav_scoring_rect_offset_y; + } + } + return 0.0f; +} + +static void ImGui::NavEndFrame() +{ + ImGuiContext& g = *GImGui; + + // Show CTRL+TAB list window + if (g.NavWindowingTarget != NULL) + NavUpdateWindowingOverlay(); + + // Perform wrap-around in menus + ImGuiWindow* window = g.NavWrapRequestWindow; + ImGuiNavMoveFlags move_flags = g.NavWrapRequestFlags; + if (window != NULL && g.NavWindow == window && NavMoveRequestButNoResultYet() && g.NavMoveRequestForward == ImGuiNavForward_None && g.NavLayer == ImGuiNavLayer_Main) + { + IM_ASSERT(move_flags != 0); // No points calling this with no wrapping + ImRect bb_rel = window->NavRectRel[0]; + + ImGuiDir clip_dir = g.NavMoveDir; + if (g.NavMoveDir == ImGuiDir_Left && (move_flags & (ImGuiNavMoveFlags_WrapX | ImGuiNavMoveFlags_LoopX))) + { + bb_rel.Min.x = bb_rel.Max.x = + ImMax(window->SizeFull.x, window->ContentSize.x + window->WindowPadding.x * 2.0f) - window->Scroll.x; + if (move_flags & ImGuiNavMoveFlags_WrapX) + { + bb_rel.TranslateY(-bb_rel.GetHeight()); + clip_dir = ImGuiDir_Up; + } + NavMoveRequestForward(g.NavMoveDir, clip_dir, bb_rel, move_flags); + } + if (g.NavMoveDir == ImGuiDir_Right && (move_flags & (ImGuiNavMoveFlags_WrapX | ImGuiNavMoveFlags_LoopX))) + { + bb_rel.Min.x = bb_rel.Max.x = -window->Scroll.x; + if (move_flags & ImGuiNavMoveFlags_WrapX) + { + bb_rel.TranslateY(+bb_rel.GetHeight()); + clip_dir = ImGuiDir_Down; + } + NavMoveRequestForward(g.NavMoveDir, clip_dir, bb_rel, move_flags); + } + if (g.NavMoveDir == ImGuiDir_Up && (move_flags & (ImGuiNavMoveFlags_WrapY | ImGuiNavMoveFlags_LoopY))) + { + bb_rel.Min.y = bb_rel.Max.y = + ImMax(window->SizeFull.y, window->ContentSize.y + window->WindowPadding.y * 2.0f) - window->Scroll.y; + if (move_flags & ImGuiNavMoveFlags_WrapY) + { + bb_rel.TranslateX(-bb_rel.GetWidth()); + clip_dir = ImGuiDir_Left; + } + NavMoveRequestForward(g.NavMoveDir, clip_dir, bb_rel, move_flags); + } + if (g.NavMoveDir == ImGuiDir_Down && (move_flags & (ImGuiNavMoveFlags_WrapY | ImGuiNavMoveFlags_LoopY))) + { + bb_rel.Min.y = bb_rel.Max.y = -window->Scroll.y; + if (move_flags & ImGuiNavMoveFlags_WrapY) + { + bb_rel.TranslateX(+bb_rel.GetWidth()); + clip_dir = ImGuiDir_Right; + } + NavMoveRequestForward(g.NavMoveDir, clip_dir, bb_rel, move_flags); + } + } +} + +static int ImGui::FindWindowFocusIndex(ImGuiWindow* window) // FIXME-OPT O(N) +{ + ImGuiContext& g = *GImGui; + for (int i = g.WindowsFocusOrder.Size-1; i >= 0; i--) + if (g.WindowsFocusOrder[i] == window) + return i; + return -1; +} + +static ImGuiWindow* FindWindowNavFocusable(int i_start, int i_stop, int dir) // FIXME-OPT O(N) +{ + ImGuiContext& g = *GImGui; + for (int i = i_start; i >= 0 && i < g.WindowsFocusOrder.Size && i != i_stop; i += dir) + if (ImGui::IsWindowNavFocusable(g.WindowsFocusOrder[i])) + return g.WindowsFocusOrder[i]; + return NULL; +} + +static void NavUpdateWindowingHighlightWindow(int focus_change_dir) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(g.NavWindowingTarget); + if (g.NavWindowingTarget->Flags & ImGuiWindowFlags_Modal) + return; + + const int i_current = ImGui::FindWindowFocusIndex(g.NavWindowingTarget); + ImGuiWindow* window_target = FindWindowNavFocusable(i_current + focus_change_dir, -INT_MAX, focus_change_dir); + if (!window_target) + window_target = FindWindowNavFocusable((focus_change_dir < 0) ? (g.WindowsFocusOrder.Size - 1) : 0, i_current, focus_change_dir); + if (window_target) // Don't reset windowing target if there's a single window in the list + g.NavWindowingTarget = g.NavWindowingTargetAnim = window_target; + g.NavWindowingToggleLayer = false; +} + +// Windowing management mode +// Keyboard: CTRL+Tab (change focus/move/resize), Alt (toggle menu layer) +// Gamepad: Hold Menu/Square (change focus/move/resize), Tap Menu/Square (toggle menu layer) +static void ImGui::NavUpdateWindowing() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* apply_focus_window = NULL; + bool apply_toggle_layer = false; + + ImGuiWindow* modal_window = GetTopMostPopupModal(); + if (modal_window != NULL) + { + g.NavWindowingTarget = NULL; + return; + } + + // Fade out + if (g.NavWindowingTargetAnim && g.NavWindowingTarget == NULL) + { + g.NavWindowingHighlightAlpha = ImMax(g.NavWindowingHighlightAlpha - g.IO.DeltaTime * 10.0f, 0.0f); + if (g.DimBgRatio <= 0.0f && g.NavWindowingHighlightAlpha <= 0.0f) + g.NavWindowingTargetAnim = NULL; + } + + // Start CTRL-TAB or Square+L/R window selection + bool start_windowing_with_gamepad = !g.NavWindowingTarget && IsNavInputTest(ImGuiNavInput_Menu, ImGuiInputReadMode_Pressed); + bool start_windowing_with_keyboard = !g.NavWindowingTarget && g.IO.KeyCtrl && IsKeyPressedMap(ImGuiKey_Tab) && (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard); + if (start_windowing_with_gamepad || start_windowing_with_keyboard) + if (ImGuiWindow* window = g.NavWindow ? g.NavWindow : FindWindowNavFocusable(g.WindowsFocusOrder.Size - 1, -INT_MAX, -1)) + { + g.NavWindowingTarget = g.NavWindowingTargetAnim = window->RootWindowDockStop; + g.NavWindowingTimer = g.NavWindowingHighlightAlpha = 0.0f; + g.NavWindowingToggleLayer = start_windowing_with_keyboard ? false : true; + g.NavInputSource = start_windowing_with_keyboard ? ImGuiInputSource_NavKeyboard : ImGuiInputSource_NavGamepad; + } + + // Gamepad update + g.NavWindowingTimer += g.IO.DeltaTime; + if (g.NavWindowingTarget && g.NavInputSource == ImGuiInputSource_NavGamepad) + { + // Highlight only appears after a brief time holding the button, so that a fast tap on PadMenu (to toggle NavLayer) doesn't add visual noise + g.NavWindowingHighlightAlpha = ImMax(g.NavWindowingHighlightAlpha, ImSaturate((g.NavWindowingTimer - NAV_WINDOWING_HIGHLIGHT_DELAY) / 0.05f)); + + // Select window to focus + const int focus_change_dir = (int)IsNavInputTest(ImGuiNavInput_FocusPrev, ImGuiInputReadMode_RepeatSlow) - (int)IsNavInputTest(ImGuiNavInput_FocusNext, ImGuiInputReadMode_RepeatSlow); + if (focus_change_dir != 0) + { + NavUpdateWindowingHighlightWindow(focus_change_dir); + g.NavWindowingHighlightAlpha = 1.0f; + } + + // Single press toggles NavLayer, long press with L/R apply actual focus on release (until then the window was merely rendered top-most) + if (!IsNavInputDown(ImGuiNavInput_Menu)) + { + g.NavWindowingToggleLayer &= (g.NavWindowingHighlightAlpha < 1.0f); // Once button was held long enough we don't consider it a tap-to-toggle-layer press anymore. + if (g.NavWindowingToggleLayer && g.NavWindow) + apply_toggle_layer = true; + else if (!g.NavWindowingToggleLayer) + apply_focus_window = g.NavWindowingTarget; + g.NavWindowingTarget = NULL; + } + } + + // Keyboard: Focus + if (g.NavWindowingTarget && g.NavInputSource == ImGuiInputSource_NavKeyboard) + { + // Visuals only appears after a brief time after pressing TAB the first time, so that a fast CTRL+TAB doesn't add visual noise + g.NavWindowingHighlightAlpha = ImMax(g.NavWindowingHighlightAlpha, ImSaturate((g.NavWindowingTimer - NAV_WINDOWING_HIGHLIGHT_DELAY) / 0.05f)); // 1.0f + if (IsKeyPressedMap(ImGuiKey_Tab, true)) + NavUpdateWindowingHighlightWindow(g.IO.KeyShift ? +1 : -1); + if (!g.IO.KeyCtrl) + apply_focus_window = g.NavWindowingTarget; + } + + // Keyboard: Press and Release ALT to toggle menu layer + // FIXME: We lack an explicit IO variable for "is the imgui window focused", so compare mouse validity to detect the common case of back-end clearing releases all keys on ALT-TAB + if (IsNavInputTest(ImGuiNavInput_KeyMenu_, ImGuiInputReadMode_Pressed)) + g.NavWindowingToggleLayer = true; + if ((g.ActiveId == 0 || g.ActiveIdAllowOverlap) && g.NavWindowingToggleLayer && IsNavInputTest(ImGuiNavInput_KeyMenu_, ImGuiInputReadMode_Released)) + if (IsMousePosValid(&g.IO.MousePos) == IsMousePosValid(&g.IO.MousePosPrev)) + apply_toggle_layer = true; + + // Move window + if (g.NavWindowingTarget && !(g.NavWindowingTarget->Flags & ImGuiWindowFlags_NoMove)) + { + ImVec2 move_delta; + if (g.NavInputSource == ImGuiInputSource_NavKeyboard && !g.IO.KeyShift) + move_delta = GetNavInputAmount2d(ImGuiNavDirSourceFlags_Keyboard, ImGuiInputReadMode_Down); + if (g.NavInputSource == ImGuiInputSource_NavGamepad) + move_delta = GetNavInputAmount2d(ImGuiNavDirSourceFlags_PadLStick, ImGuiInputReadMode_Down); + if (move_delta.x != 0.0f || move_delta.y != 0.0f) + { + const float NAV_MOVE_SPEED = 800.0f; + const float move_speed = ImFloor(NAV_MOVE_SPEED * g.IO.DeltaTime * ImMin(g.IO.DisplayFramebufferScale.x, g.IO.DisplayFramebufferScale.y)); // FIXME: Doesn't code variable framerate very well + SetWindowPos(g.NavWindowingTarget->RootWindow, g.NavWindowingTarget->RootWindow->Pos + move_delta * move_speed, ImGuiCond_Always); + g.NavDisableMouseHover = true; + MarkIniSettingsDirty(g.NavWindowingTarget); + } + } + + // Apply final focus + if (apply_focus_window && (g.NavWindow == NULL || apply_focus_window != g.NavWindow->RootWindowDockStop)) + { + ImGuiViewport* previous_viewport = g.NavWindow ? g.NavWindow->Viewport : NULL; + ClearActiveID(); + g.NavDisableHighlight = false; + g.NavDisableMouseHover = true; + apply_focus_window = NavRestoreLastChildNavWindow(apply_focus_window); + ClosePopupsOverWindow(apply_focus_window, false); + FocusWindow(apply_focus_window); + if (apply_focus_window->NavLastIds[0] == 0) + NavInitWindow(apply_focus_window, false); + + // If the window only has a menu layer, select it directly + if (apply_focus_window->DC.NavLayerActiveMask == (1 << ImGuiNavLayer_Menu)) + g.NavLayer = ImGuiNavLayer_Menu; + + // Request OS level focus + if (apply_focus_window->Viewport != previous_viewport && g.PlatformIO.Platform_SetWindowFocus) + g.PlatformIO.Platform_SetWindowFocus(apply_focus_window->Viewport); + } + if (apply_focus_window) + g.NavWindowingTarget = NULL; + + // Apply menu/layer toggle + if (apply_toggle_layer && g.NavWindow) + { + // Move to parent menu if necessary + ImGuiWindow* new_nav_window = g.NavWindow; + while (new_nav_window->ParentWindow + && (new_nav_window->DC.NavLayerActiveMask & (1 << ImGuiNavLayer_Menu)) == 0 + && (new_nav_window->Flags & ImGuiWindowFlags_ChildWindow) != 0 + && (new_nav_window->Flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_ChildMenu)) == 0) + new_nav_window = new_nav_window->ParentWindow; + if (new_nav_window != g.NavWindow) + { + ImGuiWindow* old_nav_window = g.NavWindow; + FocusWindow(new_nav_window); + new_nav_window->NavLastChildNavWindow = old_nav_window; + } + g.NavDisableHighlight = false; + g.NavDisableMouseHover = true; + + // When entering a regular menu bar with the Alt key, we always reinitialize the navigation ID. It however persist on docking tab tabs. + const ImGuiNavLayer new_nav_layer = (g.NavWindow->DC.NavLayerActiveMask & (1 << ImGuiNavLayer_Menu)) ? (ImGuiNavLayer)((int)g.NavLayer ^ 1) : ImGuiNavLayer_Main; + const bool preserve_layer_1_nav_id = (new_nav_window->DockNodeAsHost != NULL); + if (new_nav_layer == ImGuiNavLayer_Menu && !preserve_layer_1_nav_id) + g.NavWindow->NavLastIds[ImGuiNavLayer_Menu] = 0; + NavRestoreLayer(new_nav_layer); + } +} + +// Window has already passed the IsWindowNavFocusable() +static const char* GetFallbackWindowNameForWindowingList(ImGuiWindow* window) +{ + if (window->Flags & ImGuiWindowFlags_Popup) + return "(Popup)"; + if ((window->Flags & ImGuiWindowFlags_MenuBar) && strcmp(window->Name, "##MainMenuBar") == 0) + return "(Main menu bar)"; + if (window->DockNodeAsHost) + return "(Dock node)"; + return "(Untitled)"; +} + +// Overlay displayed when using CTRL+TAB. Called by EndFrame(). +void ImGui::NavUpdateWindowingOverlay() +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(g.NavWindowingTarget != NULL); + + if (g.NavWindowingTimer < NAV_WINDOWING_LIST_APPEAR_DELAY) + return; + + if (g.NavWindowingListWindow == NULL) + g.NavWindowingListWindow = FindWindowByName("###NavWindowingList"); + ImGuiViewportP* viewport = /*g.NavWindow ? g.NavWindow->Viewport :*/ (ImGuiViewportP*)GetMainViewport(); + SetNextWindowSizeConstraints(ImVec2(viewport->Size.x * 0.20f, viewport->Size.y * 0.20f), ImVec2(FLT_MAX, FLT_MAX)); + SetNextWindowPos(viewport->Pos + viewport->Size * 0.5f, ImGuiCond_Always, ImVec2(0.5f, 0.5f)); + PushStyleVar(ImGuiStyleVar_WindowPadding, g.Style.WindowPadding * 2.0f); + Begin("###NavWindowingList", NULL, ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings); + for (int n = g.WindowsFocusOrder.Size - 1; n >= 0; n--) + { + ImGuiWindow* window = g.WindowsFocusOrder[n]; + if (!IsWindowNavFocusable(window)) + continue; + const char* label = window->Name; + if (label == FindRenderedTextEnd(label)) + label = GetFallbackWindowNameForWindowingList(window); + Selectable(label, g.NavWindowingTarget == window); + } + End(); + PopStyleVar(); +} + +//----------------------------------------------------------------------------- +// [SECTION] DRAG AND DROP +//----------------------------------------------------------------------------- + +void ImGui::ClearDragDrop() +{ + ImGuiContext& g = *GImGui; + g.DragDropActive = false; + g.DragDropPayload.Clear(); + g.DragDropAcceptFlags = ImGuiDragDropFlags_None; + g.DragDropAcceptIdCurr = g.DragDropAcceptIdPrev = 0; + g.DragDropAcceptIdCurrRectSurface = FLT_MAX; + g.DragDropAcceptFrameCount = -1; + + g.DragDropPayloadBufHeap.clear(); + memset(&g.DragDropPayloadBufLocal, 0, sizeof(g.DragDropPayloadBufLocal)); +} + +// Call when current ID is active. +// When this returns true you need to: a) call SetDragDropPayload() exactly once, b) you may render the payload visual/description, c) call EndDragDropSource() +bool ImGui::BeginDragDropSource(ImGuiDragDropFlags flags) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + + bool source_drag_active = false; + ImGuiID source_id = 0; + ImGuiID source_parent_id = 0; + ImGuiMouseButton mouse_button = ImGuiMouseButton_Left; + if (!(flags & ImGuiDragDropFlags_SourceExtern)) + { + source_id = window->DC.LastItemId; + if (source_id != 0 && g.ActiveId != source_id) // Early out for most common case + return false; + if (g.IO.MouseDown[mouse_button] == false) + return false; + + if (source_id == 0) + { + // If you want to use BeginDragDropSource() on an item with no unique identifier for interaction, such as Text() or Image(), you need to: + // A) Read the explanation below, B) Use the ImGuiDragDropFlags_SourceAllowNullID flag, C) Swallow your programmer pride. + if (!(flags & ImGuiDragDropFlags_SourceAllowNullID)) + { + IM_ASSERT(0); + return false; + } + + // Early out + if ((window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_HoveredRect) == 0 && (g.ActiveId == 0 || g.ActiveIdWindow != window)) + return false; + + // Magic fallback (=somehow reprehensible) to handle items with no assigned ID, e.g. Text(), Image() + // We build a throwaway ID based on current ID stack + relative AABB of items in window. + // THE IDENTIFIER WON'T SURVIVE ANY REPOSITIONING OF THE WIDGET, so if your widget moves your dragging operation will be canceled. + // We don't need to maintain/call ClearActiveID() as releasing the button will early out this function and trigger !ActiveIdIsAlive. + source_id = window->DC.LastItemId = window->GetIDFromRectangle(window->DC.LastItemRect); + bool is_hovered = ItemHoverable(window->DC.LastItemRect, source_id); + if (is_hovered && g.IO.MouseClicked[mouse_button]) + { + SetActiveID(source_id, window); + FocusWindow(window); + } + if (g.ActiveId == source_id) // Allow the underlying widget to display/return hovered during the mouse release frame, else we would get a flicker. + g.ActiveIdAllowOverlap = is_hovered; + } + else + { + g.ActiveIdAllowOverlap = false; + } + if (g.ActiveId != source_id) + return false; + source_parent_id = window->IDStack.back(); + source_drag_active = IsMouseDragging(mouse_button); + + // Disable navigation and key inputs while dragging + g.ActiveIdUsingNavDirMask = ~(ImU32)0; + g.ActiveIdUsingNavInputMask = ~(ImU32)0; + g.ActiveIdUsingKeyInputMask = ~(ImU64)0; + } + else + { + window = NULL; + source_id = ImHashStr("#SourceExtern"); + source_drag_active = true; + } + + if (source_drag_active) + { + if (!g.DragDropActive) + { + IM_ASSERT(source_id != 0); + ClearDragDrop(); + ImGuiPayload& payload = g.DragDropPayload; + payload.SourceId = source_id; + payload.SourceParentId = source_parent_id; + g.DragDropActive = true; + g.DragDropSourceFlags = flags; + g.DragDropMouseButton = mouse_button; + } + g.DragDropSourceFrameCount = g.FrameCount; + g.DragDropWithinSource = true; + + if (!(flags & ImGuiDragDropFlags_SourceNoPreviewTooltip)) + { + // Target can request the Source to not display its tooltip (we use a dedicated flag to make this request explicit) + // We unfortunately can't just modify the source flags and skip the call to BeginTooltip, as caller may be emitting contents. + BeginTooltip(); + if (g.DragDropAcceptIdPrev && (g.DragDropAcceptFlags & ImGuiDragDropFlags_AcceptNoPreviewTooltip)) + { + ImGuiWindow* tooltip_window = g.CurrentWindow; + tooltip_window->SkipItems = true; + tooltip_window->HiddenFramesCanSkipItems = 1; + } + } + + if (!(flags & ImGuiDragDropFlags_SourceNoDisableHover) && !(flags & ImGuiDragDropFlags_SourceExtern)) + window->DC.LastItemStatusFlags &= ~ImGuiItemStatusFlags_HoveredRect; + + return true; + } + return false; +} + +void ImGui::EndDragDropSource() +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(g.DragDropActive); + IM_ASSERT(g.DragDropWithinSource && "Not after a BeginDragDropSource()?"); + + if (!(g.DragDropSourceFlags & ImGuiDragDropFlags_SourceNoPreviewTooltip)) + EndTooltip(); + + // Discard the drag if have not called SetDragDropPayload() + if (g.DragDropPayload.DataFrameCount == -1) + ClearDragDrop(); + g.DragDropWithinSource = false; +} + +// Use 'cond' to choose to submit payload on drag start or every frame +bool ImGui::SetDragDropPayload(const char* type, const void* data, size_t data_size, ImGuiCond cond) +{ + ImGuiContext& g = *GImGui; + ImGuiPayload& payload = g.DragDropPayload; + if (cond == 0) + cond = ImGuiCond_Always; + + IM_ASSERT(type != NULL); + IM_ASSERT(strlen(type) < IM_ARRAYSIZE(payload.DataType) && "Payload type can be at most 32 characters long"); + IM_ASSERT((data != NULL && data_size > 0) || (data == NULL && data_size == 0)); + IM_ASSERT(cond == ImGuiCond_Always || cond == ImGuiCond_Once); + IM_ASSERT(payload.SourceId != 0); // Not called between BeginDragDropSource() and EndDragDropSource() + + if (cond == ImGuiCond_Always || payload.DataFrameCount == -1) + { + // Copy payload + ImStrncpy(payload.DataType, type, IM_ARRAYSIZE(payload.DataType)); + g.DragDropPayloadBufHeap.resize(0); + if (data_size > sizeof(g.DragDropPayloadBufLocal)) + { + // Store in heap + g.DragDropPayloadBufHeap.resize((int)data_size); + payload.Data = g.DragDropPayloadBufHeap.Data; + memcpy(payload.Data, data, data_size); + } + else if (data_size > 0) + { + // Store locally + memset(&g.DragDropPayloadBufLocal, 0, sizeof(g.DragDropPayloadBufLocal)); + payload.Data = g.DragDropPayloadBufLocal; + memcpy(payload.Data, data, data_size); + } + else + { + payload.Data = NULL; + } + payload.DataSize = (int)data_size; + } + payload.DataFrameCount = g.FrameCount; + + return (g.DragDropAcceptFrameCount == g.FrameCount) || (g.DragDropAcceptFrameCount == g.FrameCount - 1); +} + +bool ImGui::BeginDragDropTargetCustom(const ImRect& bb, ImGuiID id) +{ + ImGuiContext& g = *GImGui; + if (!g.DragDropActive) + return false; + + ImGuiWindow* window = g.CurrentWindow; + if (g.HoveredWindowUnderMovingWindow == NULL || window->RootWindow != g.HoveredWindowUnderMovingWindow->RootWindow) + return false; + IM_ASSERT(id != 0); + if (!IsMouseHoveringRect(bb.Min, bb.Max) || (id == g.DragDropPayload.SourceId)) + return false; + if (window->SkipItems) + return false; + + IM_ASSERT(g.DragDropWithinTarget == false); + g.DragDropTargetRect = bb; + g.DragDropTargetId = id; + g.DragDropWithinTarget = true; + return true; +} + +// We don't use BeginDragDropTargetCustom() and duplicate its code because: +// 1) we use LastItemRectHoveredRect which handles items that pushes a temporarily clip rectangle in their code. Calling BeginDragDropTargetCustom(LastItemRect) would not handle them. +// 2) and it's faster. as this code may be very frequently called, we want to early out as fast as we can. +// Also note how the HoveredWindow test is positioned differently in both functions (in both functions we optimize for the cheapest early out case) +bool ImGui::BeginDragDropTarget() +{ + ImGuiContext& g = *GImGui; + if (!g.DragDropActive) + return false; + + ImGuiWindow* window = g.CurrentWindow; + if (!(window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_HoveredRect)) + return false; + if (g.HoveredWindowUnderMovingWindow == NULL || window->RootWindow != g.HoveredWindowUnderMovingWindow->RootWindow) + return false; + + const ImRect& display_rect = (window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_HasDisplayRect) ? window->DC.LastItemDisplayRect : window->DC.LastItemRect; + ImGuiID id = window->DC.LastItemId; + if (id == 0) + id = window->GetIDFromRectangle(display_rect); + if (g.DragDropPayload.SourceId == id) + return false; + + IM_ASSERT(g.DragDropWithinTarget == false); + g.DragDropTargetRect = display_rect; + g.DragDropTargetId = id; + g.DragDropWithinTarget = true; + return true; +} + +bool ImGui::IsDragDropPayloadBeingAccepted() +{ + ImGuiContext& g = *GImGui; + return g.DragDropActive && g.DragDropAcceptIdPrev != 0; +} + +const ImGuiPayload* ImGui::AcceptDragDropPayload(const char* type, ImGuiDragDropFlags flags) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + ImGuiPayload& payload = g.DragDropPayload; + IM_ASSERT(g.DragDropActive); // Not called between BeginDragDropTarget() and EndDragDropTarget() ? + IM_ASSERT(payload.DataFrameCount != -1); // Forgot to call EndDragDropTarget() ? + if (type != NULL && !payload.IsDataType(type)) + return NULL; + + // Accept smallest drag target bounding box, this allows us to nest drag targets conveniently without ordering constraints. + // NB: We currently accept NULL id as target. However, overlapping targets requires a unique ID to function! + const bool was_accepted_previously = (g.DragDropAcceptIdPrev == g.DragDropTargetId); + ImRect r = g.DragDropTargetRect; + float r_surface = r.GetWidth() * r.GetHeight(); + if (r_surface < g.DragDropAcceptIdCurrRectSurface) + { + g.DragDropAcceptFlags = flags; + g.DragDropAcceptIdCurr = g.DragDropTargetId; + g.DragDropAcceptIdCurrRectSurface = r_surface; + } + + // Render default drop visuals + payload.Preview = was_accepted_previously; + flags |= (g.DragDropSourceFlags & ImGuiDragDropFlags_AcceptNoDrawDefaultRect); // Source can also inhibit the preview (useful for external sources that lives for 1 frame) + if (!(flags & ImGuiDragDropFlags_AcceptNoDrawDefaultRect) && payload.Preview) + { + // FIXME-DRAG: Settle on a proper default visuals for drop target. + r.Expand(3.5f); + bool push_clip_rect = !window->ClipRect.Contains(r); + if (push_clip_rect) window->DrawList->PushClipRect(r.Min-ImVec2(1,1), r.Max+ImVec2(1,1)); + window->DrawList->AddRect(r.Min, r.Max, GetColorU32(ImGuiCol_DragDropTarget), 0.0f, ~0, 2.0f); + if (push_clip_rect) window->DrawList->PopClipRect(); + } + + g.DragDropAcceptFrameCount = g.FrameCount; + payload.Delivery = was_accepted_previously && !IsMouseDown(g.DragDropMouseButton); // For extern drag sources affecting os window focus, it's easier to just test !IsMouseDown() instead of IsMouseReleased() + if (!payload.Delivery && !(flags & ImGuiDragDropFlags_AcceptBeforeDelivery)) + return NULL; + + return &payload; +} + +const ImGuiPayload* ImGui::GetDragDropPayload() +{ + ImGuiContext& g = *GImGui; + return g.DragDropActive ? &g.DragDropPayload : NULL; +} + +// We don't really use/need this now, but added it for the sake of consistency and because we might need it later. +void ImGui::EndDragDropTarget() +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(g.DragDropActive); + IM_ASSERT(g.DragDropWithinTarget); + g.DragDropWithinTarget = false; +} + +//----------------------------------------------------------------------------- +// [SECTION] LOGGING/CAPTURING +//----------------------------------------------------------------------------- +// All text output from the interface can be captured into tty/file/clipboard. +// By default, tree nodes are automatically opened during logging. +//----------------------------------------------------------------------------- + +// Pass text data straight to log (without being displayed) +void ImGui::LogText(const char* fmt, ...) +{ + ImGuiContext& g = *GImGui; + if (!g.LogEnabled) + return; + + va_list args; + va_start(args, fmt); + if (g.LogFile) + { + g.LogBuffer.Buf.resize(0); + g.LogBuffer.appendfv(fmt, args); + ImFileWrite(g.LogBuffer.c_str(), sizeof(char), (ImU64)g.LogBuffer.size(), g.LogFile); + } + else + { + g.LogBuffer.appendfv(fmt, args); + } + va_end(args); +} + +// Internal version that takes a position to decide on newline placement and pad items according to their depth. +// We split text into individual lines to add current tree level padding +void ImGui::LogRenderedText(const ImVec2* ref_pos, const char* text, const char* text_end) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + + if (!text_end) + text_end = FindRenderedTextEnd(text, text_end); + + const bool log_new_line = ref_pos && (ref_pos->y > g.LogLinePosY + 1); + if (ref_pos) + g.LogLinePosY = ref_pos->y; + if (log_new_line) + g.LogLineFirstItem = true; + + const char* text_remaining = text; + if (g.LogDepthRef > window->DC.TreeDepth) // Re-adjust padding if we have popped out of our starting depth + g.LogDepthRef = window->DC.TreeDepth; + const int tree_depth = (window->DC.TreeDepth - g.LogDepthRef); + for (;;) + { + // Split the string. Each new line (after a '\n') is followed by spacing corresponding to the current depth of our log entry. + // We don't add a trailing \n to allow a subsequent item on the same line to be captured. + const char* line_start = text_remaining; + const char* line_end = ImStreolRange(line_start, text_end); + const bool is_first_line = (line_start == text); + const bool is_last_line = (line_end == text_end); + if (!is_last_line || (line_start != line_end)) + { + const int char_count = (int)(line_end - line_start); + if (log_new_line || !is_first_line) + LogText(IM_NEWLINE "%*s%.*s", tree_depth * 4, "", char_count, line_start); + else if (g.LogLineFirstItem) + LogText("%*s%.*s", tree_depth * 4, "", char_count, line_start); + else + LogText(" %.*s", char_count, line_start); + g.LogLineFirstItem = false; + } + else if (log_new_line) + { + // An empty "" string at a different Y position should output a carriage return. + LogText(IM_NEWLINE); + break; + } + + if (is_last_line) + break; + text_remaining = line_end + 1; + } +} + +// Start logging/capturing text output +void ImGui::LogBegin(ImGuiLogType type, int auto_open_depth) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + IM_ASSERT(g.LogEnabled == false); + IM_ASSERT(g.LogFile == NULL); + IM_ASSERT(g.LogBuffer.empty()); + g.LogEnabled = true; + g.LogType = type; + g.LogDepthRef = window->DC.TreeDepth; + g.LogDepthToExpand = ((auto_open_depth >= 0) ? auto_open_depth : g.LogDepthToExpandDefault); + g.LogLinePosY = FLT_MAX; + g.LogLineFirstItem = true; +} + +void ImGui::LogToTTY(int auto_open_depth) +{ + ImGuiContext& g = *GImGui; + if (g.LogEnabled) + return; + IM_UNUSED(auto_open_depth); +#ifndef IMGUI_DISABLE_TTY_FUNCTIONS + LogBegin(ImGuiLogType_TTY, auto_open_depth); + g.LogFile = stdout; +#endif +} + +// Start logging/capturing text output to given file +void ImGui::LogToFile(int auto_open_depth, const char* filename) +{ + ImGuiContext& g = *GImGui; + if (g.LogEnabled) + return; + + // FIXME: We could probably open the file in text mode "at", however note that clipboard/buffer logging will still + // be subject to outputting OS-incompatible carriage return if within strings the user doesn't use IM_NEWLINE. + // By opening the file in binary mode "ab" we have consistent output everywhere. + if (!filename) + filename = g.IO.LogFilename; + if (!filename || !filename[0]) + return; + ImFileHandle f = ImFileOpen(filename, "ab"); + if (!f) + { + IM_ASSERT(0); + return; + } + + LogBegin(ImGuiLogType_File, auto_open_depth); + g.LogFile = f; +} + +// Start logging/capturing text output to clipboard +void ImGui::LogToClipboard(int auto_open_depth) +{ + ImGuiContext& g = *GImGui; + if (g.LogEnabled) + return; + LogBegin(ImGuiLogType_Clipboard, auto_open_depth); +} + +void ImGui::LogToBuffer(int auto_open_depth) +{ + ImGuiContext& g = *GImGui; + if (g.LogEnabled) + return; + LogBegin(ImGuiLogType_Buffer, auto_open_depth); +} + +void ImGui::LogFinish() +{ + ImGuiContext& g = *GImGui; + if (!g.LogEnabled) + return; + + LogText(IM_NEWLINE); + switch (g.LogType) + { + case ImGuiLogType_TTY: +#ifndef IMGUI_DISABLE_TTY_FUNCTIONS + fflush(g.LogFile); +#endif + break; + case ImGuiLogType_File: + ImFileClose(g.LogFile); + break; + case ImGuiLogType_Buffer: + break; + case ImGuiLogType_Clipboard: + if (!g.LogBuffer.empty()) + SetClipboardText(g.LogBuffer.begin()); + break; + case ImGuiLogType_None: + IM_ASSERT(0); + break; + } + + g.LogEnabled = false; + g.LogType = ImGuiLogType_None; + g.LogFile = NULL; + g.LogBuffer.clear(); +} + +// Helper to display logging buttons +// FIXME-OBSOLETE: We should probably obsolete this and let the user have their own helper (this is one of the oldest function alive!) +void ImGui::LogButtons() +{ + ImGuiContext& g = *GImGui; + + PushID("LogButtons"); +#ifndef IMGUI_DISABLE_TTY_FUNCTIONS + const bool log_to_tty = Button("Log To TTY"); SameLine(); +#else + const bool log_to_tty = false; +#endif + const bool log_to_file = Button("Log To File"); SameLine(); + const bool log_to_clipboard = Button("Log To Clipboard"); SameLine(); + PushAllowKeyboardFocus(false); + SetNextItemWidth(80.0f); + SliderInt("Default Depth", &g.LogDepthToExpandDefault, 0, 9, NULL); + PopAllowKeyboardFocus(); + PopID(); + + // Start logging at the end of the function so that the buttons don't appear in the log + if (log_to_tty) + LogToTTY(); + if (log_to_file) + LogToFile(); + if (log_to_clipboard) + LogToClipboard(); +} + + +//----------------------------------------------------------------------------- +// [SECTION] SETTINGS +//----------------------------------------------------------------------------- +// - UpdateSettings() [Internal] +// - MarkIniSettingsDirty() [Internal] +// - CreateNewWindowSettings() [Internal] +// - FindWindowSettings() [Internal] +// - FindOrCreateWindowSettings() [Internal] +// - FindSettingsHandler() [Internal] +// - ClearIniSettings() [Internal] +// - LoadIniSettingsFromDisk() +// - LoadIniSettingsFromMemory() +// - SaveIniSettingsToDisk() +// - SaveIniSettingsToMemory() +// - WindowSettingsHandler_***() [Internal] +//----------------------------------------------------------------------------- + +// Called by NewFrame() +void ImGui::UpdateSettings() +{ + // Load settings on first frame (if not explicitly loaded manually before) + ImGuiContext& g = *GImGui; + if (!g.SettingsLoaded) + { + IM_ASSERT(g.SettingsWindows.empty()); + if (g.IO.IniFilename) + LoadIniSettingsFromDisk(g.IO.IniFilename); + g.SettingsLoaded = true; + } + + // Save settings (with a delay after the last modification, so we don't spam disk too much) + if (g.SettingsDirtyTimer > 0.0f) + { + g.SettingsDirtyTimer -= g.IO.DeltaTime; + if (g.SettingsDirtyTimer <= 0.0f) + { + if (g.IO.IniFilename != NULL) + SaveIniSettingsToDisk(g.IO.IniFilename); + else + g.IO.WantSaveIniSettings = true; // Let user know they can call SaveIniSettingsToMemory(). user will need to clear io.WantSaveIniSettings themselves. + g.SettingsDirtyTimer = 0.0f; + } + } +} + +void ImGui::MarkIniSettingsDirty() +{ + ImGuiContext& g = *GImGui; + if (g.SettingsDirtyTimer <= 0.0f) + g.SettingsDirtyTimer = g.IO.IniSavingRate; +} + +void ImGui::MarkIniSettingsDirty(ImGuiWindow* window) +{ + ImGuiContext& g = *GImGui; + if (!(window->Flags & ImGuiWindowFlags_NoSavedSettings)) + if (g.SettingsDirtyTimer <= 0.0f) + g.SettingsDirtyTimer = g.IO.IniSavingRate; +} + +ImGuiWindowSettings* ImGui::CreateNewWindowSettings(const char* name) +{ + ImGuiContext& g = *GImGui; + +#if !IMGUI_DEBUG_INI_SETTINGS + // Skip to the "###" marker if any. We don't skip past to match the behavior of GetID() + // Preserve the full string when IMGUI_DEBUG_INI_SETTINGS is set to make .ini inspection easier. + if (const char* p = strstr(name, "###")) + name = p; +#endif + const size_t name_len = strlen(name); + + // Allocate chunk + const size_t chunk_size = sizeof(ImGuiWindowSettings) + name_len + 1; + ImGuiWindowSettings* settings = g.SettingsWindows.alloc_chunk(chunk_size); + IM_PLACEMENT_NEW(settings) ImGuiWindowSettings(); + settings->ID = ImHashStr(name, name_len); + memcpy(settings->GetName(), name, name_len + 1); // Store with zero terminator + + return settings; +} + +ImGuiWindowSettings* ImGui::FindWindowSettings(ImGuiID id) +{ + ImGuiContext& g = *GImGui; + for (ImGuiWindowSettings* settings = g.SettingsWindows.begin(); settings != NULL; settings = g.SettingsWindows.next_chunk(settings)) + if (settings->ID == id) + return settings; + return NULL; +} + +ImGuiWindowSettings* ImGui::FindOrCreateWindowSettings(const char* name) +{ + if (ImGuiWindowSettings* settings = FindWindowSettings(ImHashStr(name))) + return settings; + return CreateNewWindowSettings(name); +} + +ImGuiSettingsHandler* ImGui::FindSettingsHandler(const char* type_name) +{ + ImGuiContext& g = *GImGui; + const ImGuiID type_hash = ImHashStr(type_name); + for (int handler_n = 0; handler_n < g.SettingsHandlers.Size; handler_n++) + if (g.SettingsHandlers[handler_n].TypeHash == type_hash) + return &g.SettingsHandlers[handler_n]; + return NULL; +} + +void ImGui::ClearIniSettings() +{ + ImGuiContext& g = *GImGui; + g.SettingsIniData.clear(); + for (int handler_n = 0; handler_n < g.SettingsHandlers.Size; handler_n++) + if (g.SettingsHandlers[handler_n].ClearAllFn) + g.SettingsHandlers[handler_n].ClearAllFn(&g, &g.SettingsHandlers[handler_n]); +} + +void ImGui::LoadIniSettingsFromDisk(const char* ini_filename) +{ + size_t file_data_size = 0; + char* file_data = (char*)ImFileLoadToMemory(ini_filename, "rb", &file_data_size); + if (!file_data) + return; + LoadIniSettingsFromMemory(file_data, (size_t)file_data_size); + IM_FREE(file_data); +} + +// Zero-tolerance, no error reporting, cheap .ini parsing +void ImGui::LoadIniSettingsFromMemory(const char* ini_data, size_t ini_size) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(g.Initialized); + //IM_ASSERT(!g.WithinFrameScope && "Cannot be called between NewFrame() and EndFrame()"); + //IM_ASSERT(g.SettingsLoaded == false && g.FrameCount == 0); + + // For user convenience, we allow passing a non zero-terminated string (hence the ini_size parameter). + // For our convenience and to make the code simpler, we'll also write zero-terminators within the buffer. So let's create a writable copy.. + if (ini_size == 0) + ini_size = strlen(ini_data); + g.SettingsIniData.Buf.resize((int)ini_size + 1); + char* const buf = g.SettingsIniData.Buf.Data; + char* const buf_end = buf + ini_size; + memcpy(buf, ini_data, ini_size); + buf_end[0] = 0; + + // Call pre-read handlers + // Some types will clear their data (e.g. dock information) some types will allow merge/override (window) + for (int handler_n = 0; handler_n < g.SettingsHandlers.Size; handler_n++) + if (g.SettingsHandlers[handler_n].ReadInitFn) + g.SettingsHandlers[handler_n].ReadInitFn(&g, &g.SettingsHandlers[handler_n]); + + void* entry_data = NULL; + ImGuiSettingsHandler* entry_handler = NULL; + + char* line_end = NULL; + for (char* line = buf; line < buf_end; line = line_end + 1) + { + // Skip new lines markers, then find end of the line + while (*line == '\n' || *line == '\r') + line++; + line_end = line; + while (line_end < buf_end && *line_end != '\n' && *line_end != '\r') + line_end++; + line_end[0] = 0; + if (line[0] == ';') + continue; + if (line[0] == '[' && line_end > line && line_end[-1] == ']') + { + // Parse "[Type][Name]". Note that 'Name' can itself contains [] characters, which is acceptable with the current format and parsing code. + line_end[-1] = 0; + const char* name_end = line_end - 1; + const char* type_start = line + 1; + char* type_end = (char*)(void*)ImStrchrRange(type_start, name_end, ']'); + const char* name_start = type_end ? ImStrchrRange(type_end + 1, name_end, '[') : NULL; + if (!type_end || !name_start) + continue; + *type_end = 0; // Overwrite first ']' + name_start++; // Skip second '[' + entry_handler = FindSettingsHandler(type_start); + entry_data = entry_handler ? entry_handler->ReadOpenFn(&g, entry_handler, name_start) : NULL; + } + else if (entry_handler != NULL && entry_data != NULL) + { + // Let type handler parse the line + entry_handler->ReadLineFn(&g, entry_handler, entry_data, line); + } + } + g.SettingsLoaded = true; + + // [DEBUG] Restore untouched copy so it can be browsed in Metrics (not strictly necessary) + memcpy(buf, ini_data, ini_size); + + // Call post-read handlers + for (int handler_n = 0; handler_n < g.SettingsHandlers.Size; handler_n++) + if (g.SettingsHandlers[handler_n].ApplyAllFn) + g.SettingsHandlers[handler_n].ApplyAllFn(&g, &g.SettingsHandlers[handler_n]); +} + +void ImGui::SaveIniSettingsToDisk(const char* ini_filename) +{ + ImGuiContext& g = *GImGui; + g.SettingsDirtyTimer = 0.0f; + if (!ini_filename) + return; + + size_t ini_data_size = 0; + const char* ini_data = SaveIniSettingsToMemory(&ini_data_size); + ImFileHandle f = ImFileOpen(ini_filename, "wt"); + if (!f) + return; + ImFileWrite(ini_data, sizeof(char), ini_data_size, f); + ImFileClose(f); +} + +// Call registered handlers (e.g. SettingsHandlerWindow_WriteAll() + custom handlers) to write their stuff into a text buffer +const char* ImGui::SaveIniSettingsToMemory(size_t* out_size) +{ + ImGuiContext& g = *GImGui; + g.SettingsDirtyTimer = 0.0f; + g.SettingsIniData.Buf.resize(0); + g.SettingsIniData.Buf.push_back(0); + for (int handler_n = 0; handler_n < g.SettingsHandlers.Size; handler_n++) + { + ImGuiSettingsHandler* handler = &g.SettingsHandlers[handler_n]; + handler->WriteAllFn(&g, handler, &g.SettingsIniData); + } + if (out_size) + *out_size = (size_t)g.SettingsIniData.size(); + return g.SettingsIniData.c_str(); +} + +static void WindowSettingsHandler_ClearAll(ImGuiContext* ctx, ImGuiSettingsHandler*) +{ + ImGuiContext& g = *ctx; + for (int i = 0; i != g.Windows.Size; i++) + g.Windows[i]->SettingsOffset = -1; + g.SettingsWindows.clear(); +} + +static void* WindowSettingsHandler_ReadOpen(ImGuiContext*, ImGuiSettingsHandler*, const char* name) +{ + ImGuiWindowSettings* settings = ImGui::FindOrCreateWindowSettings(name); + ImGuiID id = settings->ID; + *settings = ImGuiWindowSettings(); // Clear existing if recycling previous entry + settings->ID = id; + settings->WantApply = true; + return (void*)settings; +} + +static void WindowSettingsHandler_ReadLine(ImGuiContext*, ImGuiSettingsHandler*, void* entry, const char* line) +{ + ImGuiWindowSettings* settings = (ImGuiWindowSettings*)entry; + int x, y; + int i; + ImU32 u1; + if (sscanf(line, "Pos=%i,%i", &x, &y) == 2) { settings->Pos = ImVec2ih((short)x, (short)y); } + else if (sscanf(line, "Size=%i,%i", &x, &y) == 2) { settings->Size = ImVec2ih((short)x, (short)y); } + else if (sscanf(line, "ViewportId=0x%08X", &u1) == 1) { settings->ViewportId = u1; } + else if (sscanf(line, "ViewportPos=%i,%i", &x, &y) == 2) { settings->ViewportPos = ImVec2ih((short)x, (short)y); } + else if (sscanf(line, "Collapsed=%d", &i) == 1) { settings->Collapsed = (i != 0); } + else if (sscanf(line, "DockId=0x%X,%d", &u1, &i) == 2) { settings->DockId = u1; settings->DockOrder = (short)i; } + else if (sscanf(line, "DockId=0x%X", &u1) == 1) { settings->DockId = u1; settings->DockOrder = -1; } + else if (sscanf(line, "ClassId=0x%X", &u1) == 1) { settings->ClassId = u1; } +} + +// Apply to existing windows (if any) +static void WindowSettingsHandler_ApplyAll(ImGuiContext* ctx, ImGuiSettingsHandler*) +{ + ImGuiContext& g = *ctx; + for (ImGuiWindowSettings* settings = g.SettingsWindows.begin(); settings != NULL; settings = g.SettingsWindows.next_chunk(settings)) + if (settings->WantApply) + { + if (ImGuiWindow* window = ImGui::FindWindowByID(settings->ID)) + ApplyWindowSettings(window, settings); + settings->WantApply = false; + } +} + +static void WindowSettingsHandler_WriteAll(ImGuiContext* ctx, ImGuiSettingsHandler* handler, ImGuiTextBuffer* buf) +{ + // Gather data from windows that were active during this session + // (if a window wasn't opened in this session we preserve its settings) + ImGuiContext& g = *ctx; + for (int i = 0; i != g.Windows.Size; i++) + { + ImGuiWindow* window = g.Windows[i]; + if (window->Flags & ImGuiWindowFlags_NoSavedSettings) + continue; + + ImGuiWindowSettings* settings = (window->SettingsOffset != -1) ? g.SettingsWindows.ptr_from_offset(window->SettingsOffset) : ImGui::FindWindowSettings(window->ID); + if (!settings) + { + settings = ImGui::CreateNewWindowSettings(window->Name); + window->SettingsOffset = g.SettingsWindows.offset_from_ptr(settings); + } + IM_ASSERT(settings->ID == window->ID); + settings->Pos = ImVec2ih(window->Pos - window->ViewportPos); + settings->Size = ImVec2ih(window->SizeFull); + settings->ViewportId = window->ViewportId; + settings->ViewportPos = ImVec2ih(window->ViewportPos); + IM_ASSERT(window->DockNode == NULL || window->DockNode->ID == window->DockId); + settings->DockId = window->DockId; + settings->ClassId = window->WindowClass.ClassId; + settings->DockOrder = window->DockOrder; + settings->Collapsed = window->Collapsed; + } + + // Write to text buffer + buf->reserve(buf->size() + g.SettingsWindows.size() * 6); // ballpark reserve + for (ImGuiWindowSettings* settings = g.SettingsWindows.begin(); settings != NULL; settings = g.SettingsWindows.next_chunk(settings)) + { + const char* settings_name = settings->GetName(); + buf->appendf("[%s][%s]\n", handler->TypeName, settings_name); + if (settings->ViewportId != 0 && settings->ViewportId != ImGui::IMGUI_VIEWPORT_DEFAULT_ID) + { + buf->appendf("ViewportPos=%d,%d\n", settings->ViewportPos.x, settings->ViewportPos.y); + buf->appendf("ViewportId=0x%08X\n", settings->ViewportId); + } + if (settings->Pos.x != 0 || settings->Pos.y != 0 || settings->ViewportId == ImGui::IMGUI_VIEWPORT_DEFAULT_ID) + buf->appendf("Pos=%d,%d\n", settings->Pos.x, settings->Pos.y); + if (settings->Size.x != 0 || settings->Size.y != 0) + buf->appendf("Size=%d,%d\n", settings->Size.x, settings->Size.y); + buf->appendf("Collapsed=%d\n", settings->Collapsed); + if (settings->DockId != 0) + { + // Write DockId as 4 digits if possible. Automatic DockId are small numbers, but full explicit DockSpace() are full ImGuiID range. + if (settings->DockOrder == -1) + buf->appendf("DockId=0x%08X\n", settings->DockId); + else + buf->appendf("DockId=0x%08X,%d\n", settings->DockId, settings->DockOrder); + if (settings->ClassId != 0) + buf->appendf("ClassId=0x%08X\n", settings->ClassId); + } + buf->append("\n"); + } +} + + +//----------------------------------------------------------------------------- +// [SECTION] VIEWPORTS, PLATFORM WINDOWS +//----------------------------------------------------------------------------- +// - GetMainViewport() +// - FindViewportByID() +// - FindViewportByPlatformHandle() +// - SetCurrentViewport() [Internal] +// - SetWindowViewport() [Internal] +// - GetWindowAlwaysWantOwnViewport() [Internal] +// - UpdateTryMergeWindowIntoHostViewport() [Internal] +// - UpdateTryMergeWindowIntoHostViewports() [Internal] +// - TranslateWindowsInViewport() [Internal] +// - ScaleWindowsInViewport() [Internal] +// - FindHoveredViewportFromPlatformWindowStack() [Internal] +// - UpdateViewportsNewFrame() [Internal] +// - UpdateViewportsEndFrame() [Internal] +// - AddUpdateViewport() [Internal] +// - UpdateSelectWindowViewport() [Internal] +// - UpdatePlatformWindows() +// - RenderPlatformWindowsDefault() +// - FindPlatformMonitorForPos() [Internal] +// - FindPlatformMonitorForRect() [Internal] +// - UpdateViewportPlatformMonitor() [Internal] +// - DestroyPlatformWindow() [Internal] +// - DestroyPlatformWindows() +//----------------------------------------------------------------------------- + +ImGuiViewport* ImGui::GetMainViewport() +{ + ImGuiContext& g = *GImGui; + return g.Viewports[0]; +} + +ImGuiViewport* ImGui::FindViewportByID(ImGuiID id) +{ + ImGuiContext& g = *GImGui; + for (int n = 0; n < g.Viewports.Size; n++) + if (g.Viewports[n]->ID == id) + return g.Viewports[n]; + return NULL; +} + +ImGuiViewport* ImGui::FindViewportByPlatformHandle(void* platform_handle) +{ + ImGuiContext& g = *GImGui; + for (int i = 0; i != g.Viewports.Size; i++) + if (g.Viewports[i]->PlatformHandle == platform_handle) + return g.Viewports[i]; + return NULL; +} + +void ImGui::SetCurrentViewport(ImGuiWindow* current_window, ImGuiViewportP* viewport) +{ + ImGuiContext& g = *GImGui; + (void)current_window; + + if (viewport) + viewport->LastFrameActive = g.FrameCount; + if (g.CurrentViewport == viewport) + return; + g.CurrentDpiScale = viewport ? viewport->DpiScale : 1.0f; + g.CurrentViewport = viewport; + //IMGUI_DEBUG_LOG_VIEWPORT("SetCurrentViewport changed '%s' 0x%08X\n", current_window ? current_window->Name : NULL, viewport ? viewport->ID : 0); + + // Notify platform layer of viewport changes + // FIXME-DPI: This is only currently used for experimenting with handling of multiple DPI + if (g.CurrentViewport && g.PlatformIO.Platform_OnChangedViewport) + g.PlatformIO.Platform_OnChangedViewport(g.CurrentViewport); +} + +static void SetWindowViewport(ImGuiWindow* window, ImGuiViewportP* viewport) +{ + window->Viewport = viewport; + window->ViewportId = viewport->ID; + window->ViewportOwned = (viewport->Window == window); +} + +static bool ImGui::GetWindowAlwaysWantOwnViewport(ImGuiWindow* window) +{ + // Tooltips and menus are not automatically forced into their own viewport when the NoMerge flag is set, however the multiplication of viewports makes them more likely to protrude and create their own. + ImGuiContext& g = *GImGui; + if (g.IO.ConfigViewportsNoAutoMerge || (window->WindowClass.ViewportFlagsOverrideSet & ImGuiViewportFlags_NoAutoMerge)) + if (g.ConfigFlagsCurrFrame & ImGuiConfigFlags_ViewportsEnable) + if (!window->DockIsActive) + if ((window->Flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_ChildMenu | ImGuiWindowFlags_Tooltip)) == 0) + if ((window->Flags & ImGuiWindowFlags_Popup) == 0 || (window->Flags & ImGuiWindowFlags_Modal) != 0) + return true; + return false; +} + +static bool ImGui::UpdateTryMergeWindowIntoHostViewport(ImGuiWindow* window, ImGuiViewportP* viewport) +{ + ImGuiContext& g = *GImGui; + if (window->Viewport == viewport) + return false; + if ((viewport->Flags & ImGuiViewportFlags_CanHostOtherWindows) == 0) + return false; + if ((viewport->Flags & ImGuiViewportFlags_Minimized) != 0) + return false; + if (!viewport->GetMainRect().Contains(window->Rect())) + return false; + if (GetWindowAlwaysWantOwnViewport(window)) + return false; + + for (int n = 0; n < g.Windows.Size; n++) + { + ImGuiWindow* window_behind = g.Windows[n]; + if (window_behind == window) + break; + if (window_behind->WasActive && window_behind->ViewportOwned && !(window_behind->Flags & ImGuiWindowFlags_ChildWindow)) + if (window_behind->Viewport->GetMainRect().Overlaps(window->Rect())) + return false; + } + + // Move to the existing viewport, Move child/hosted windows as well (FIXME-OPT: iterate child) + ImGuiViewportP* old_viewport = window->Viewport; + if (window->ViewportOwned) + for (int n = 0; n < g.Windows.Size; n++) + if (g.Windows[n]->Viewport == old_viewport) + SetWindowViewport(g.Windows[n], viewport); + SetWindowViewport(window, viewport); + BringWindowToDisplayFront(window); + + return true; +} + +static bool ImGui::UpdateTryMergeWindowIntoHostViewports(ImGuiWindow* window) +{ + ImGuiContext& g = *GImGui; + return UpdateTryMergeWindowIntoHostViewport(window, g.Viewports[0]); +} + +// Translate imgui windows when a Host Viewport has been moved +// (This additionally keeps windows at the same place when ImGuiConfigFlags_ViewportsEnable is toggled!) +void ImGui::TranslateWindowsInViewport(ImGuiViewportP* viewport, const ImVec2& old_pos, const ImVec2& new_pos) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(viewport->Window == NULL && (viewport->Flags & ImGuiViewportFlags_CanHostOtherWindows)); + + // 1) We test if ImGuiConfigFlags_ViewportsEnable was just toggled, which allows us to conveniently + // translate imgui windows from OS-window-local to absolute coordinates or vice-versa. + // 2) If it's not going to fit into the new size, keep it at same absolute position. + // One problem with this is that most Win32 applications doesn't update their render while dragging, + // and so the window will appear to teleport when releasing the mouse. + const bool translate_all_windows = (g.ConfigFlagsCurrFrame & ImGuiConfigFlags_ViewportsEnable) != (g.ConfigFlagsLastFrame & ImGuiConfigFlags_ViewportsEnable); + ImRect test_still_fit_rect(old_pos, old_pos + viewport->Size); + ImVec2 delta_pos = new_pos - old_pos; + for (int window_n = 0; window_n < g.Windows.Size; window_n++) // FIXME-OPT + if (translate_all_windows || (g.Windows[window_n]->Viewport == viewport && test_still_fit_rect.Contains(g.Windows[window_n]->Rect()))) + TranslateWindow(g.Windows[window_n], delta_pos); +} + +// Scale all windows (position, size). Use when e.g. changing DPI. (This is a lossy operation!) +void ImGui::ScaleWindowsInViewport(ImGuiViewportP* viewport, float scale) +{ + ImGuiContext& g = *GImGui; + if (viewport->Window) + { + ScaleWindow(viewport->Window, scale); + } + else + { + for (int i = 0; i != g.Windows.Size; i++) + if (g.Windows[i]->Viewport == viewport) + ScaleWindow(g.Windows[i], scale); + } +} + +// If the back-end doesn't set MouseLastHoveredViewport or doesn't honor ImGuiViewportFlags_NoInputs, we do a search ourselves. +// A) It won't take account of the possibility that non-imgui windows may be in-between our dragged window and our target window. +// B) It requires Platform_GetWindowFocus to be implemented by back-end. +static ImGuiViewportP* FindHoveredViewportFromPlatformWindowStack(const ImVec2 mouse_platform_pos) +{ + ImGuiContext& g = *GImGui; + ImGuiViewportP* best_candidate = NULL; + for (int n = 0; n < g.Viewports.Size; n++) + { + ImGuiViewportP* viewport = g.Viewports[n]; + if (!(viewport->Flags & (ImGuiViewportFlags_NoInputs | ImGuiViewportFlags_Minimized)) && viewport->GetMainRect().Contains(mouse_platform_pos)) + if (best_candidate == NULL || best_candidate->LastFrontMostStampCount < viewport->LastFrontMostStampCount) + best_candidate = viewport; + } + return best_candidate; +} + +// Update viewports and monitor infos +// Note that this is running even if 'ImGuiConfigFlags_ViewportsEnable' is not set, in order to clear unused viewports (if any) and update monitor info. +static void ImGui::UpdateViewportsNewFrame() +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(g.PlatformIO.Viewports.Size <= g.Viewports.Size); + + // Update Minimized status (we need it first in order to decide if we'll apply Pos/Size of the main viewport) + const bool viewports_enabled = (g.ConfigFlagsCurrFrame & ImGuiConfigFlags_ViewportsEnable) != 0; + if (viewports_enabled) + { + for (int n = 0; n < g.Viewports.Size; n++) + { + ImGuiViewportP* viewport = g.Viewports[n]; + const bool platform_funcs_available = viewport->PlatformWindowCreated; + if (g.PlatformIO.Platform_GetWindowMinimized && platform_funcs_available) + { + bool minimized = g.PlatformIO.Platform_GetWindowMinimized(viewport); + if (minimized) + viewport->Flags |= ImGuiViewportFlags_Minimized; + else + viewport->Flags &= ~ImGuiViewportFlags_Minimized; + } + } + } + + // Create/update main viewport with current platform position. + // FIXME-VIEWPORT: Size is driven by back-end/user code for backward-compatibility but we should aim to make this more consistent. + ImGuiViewportP* main_viewport = g.Viewports[0]; + IM_ASSERT(main_viewport->ID == IMGUI_VIEWPORT_DEFAULT_ID); + IM_ASSERT(main_viewport->Window == NULL); + ImVec2 main_viewport_pos = viewports_enabled ? g.PlatformIO.Platform_GetWindowPos(main_viewport) : ImVec2(0.0f, 0.0f); + ImVec2 main_viewport_size = g.IO.DisplaySize; + if (viewports_enabled && (main_viewport->Flags & ImGuiViewportFlags_Minimized)) + { + main_viewport_pos = main_viewport->Pos; // Preserve last pos/size when minimized (FIXME: We don't do the same for Size outside of the viewport path) + main_viewport_size = main_viewport->Size; + } + AddUpdateViewport(NULL, IMGUI_VIEWPORT_DEFAULT_ID, main_viewport_pos, main_viewport_size, ImGuiViewportFlags_CanHostOtherWindows); + + g.CurrentDpiScale = 0.0f; + g.CurrentViewport = NULL; + g.MouseViewport = NULL; + for (int n = 0; n < g.Viewports.Size; n++) + { + ImGuiViewportP* viewport = g.Viewports[n]; + viewport->Idx = n; + + // Erase unused viewports + if (n > 0 && viewport->LastFrameActive < g.FrameCount - 2) + { + // Clear references to this viewport in windows (window->ViewportId becomes the master data) + for (int window_n = 0; window_n < g.Windows.Size; window_n++) + if (g.Windows[window_n]->Viewport == viewport) + { + g.Windows[window_n]->Viewport = NULL; + g.Windows[window_n]->ViewportOwned = false; + } + if (viewport == g.MouseLastHoveredViewport) + g.MouseLastHoveredViewport = NULL; + g.Viewports.erase(g.Viewports.Data + n); + + // Destroy + IMGUI_DEBUG_LOG_VIEWPORT("Delete Viewport %08X (%s)\n", viewport->ID, viewport->Window ? viewport->Window->Name : "n/a"); + DestroyPlatformWindow(viewport); // In most circumstances the platform window will already be destroyed here. + IM_ASSERT(g.PlatformIO.Viewports.contains(viewport) == false); + IM_DELETE(viewport); + n--; + continue; + } + + const bool platform_funcs_available = viewport->PlatformWindowCreated; + if (viewports_enabled) + { + // Update Position and Size (from Platform Window to ImGui) if requested. + // We do it early in the frame instead of waiting for UpdatePlatformWindows() to avoid a frame of lag when moving/resizing using OS facilities. + if (!(viewport->Flags & ImGuiViewportFlags_Minimized) && platform_funcs_available) + { + if (viewport->PlatformRequestMove) + viewport->Pos = viewport->LastPlatformPos = g.PlatformIO.Platform_GetWindowPos(viewport); + if (viewport->PlatformRequestResize) + viewport->Size = viewport->LastPlatformSize = g.PlatformIO.Platform_GetWindowSize(viewport); + } + } + + // Update/copy monitor info + UpdateViewportPlatformMonitor(viewport); + + // Lock down space taken by menu bars and status bars, reset the offset for fucntions like BeginMainMenuBar() to alter them again. + viewport->WorkOffsetMin = viewport->CurrWorkOffsetMin; + viewport->WorkOffsetMax = viewport->CurrWorkOffsetMax; + viewport->CurrWorkOffsetMin = viewport->CurrWorkOffsetMax = ImVec2(0.0f, 0.0f); + + // Reset alpha every frame. Users of transparency (docking) needs to request a lower alpha back. + viewport->Alpha = 1.0f; + + // Translate imgui windows when a Host Viewport has been moved + // (This additionally keeps windows at the same place when ImGuiConfigFlags_ViewportsEnable is toggled!) + const ImVec2 viewport_delta_pos = viewport->Pos - viewport->LastPos; + if ((viewport->Flags & ImGuiViewportFlags_CanHostOtherWindows) && (viewport_delta_pos.x != 0.0f || viewport_delta_pos.y != 0.0f)) + TranslateWindowsInViewport(viewport, viewport->LastPos, viewport->Pos); + + // Update DPI scale + float new_dpi_scale; + if (g.PlatformIO.Platform_GetWindowDpiScale && platform_funcs_available) + new_dpi_scale = g.PlatformIO.Platform_GetWindowDpiScale(viewport); + else if (viewport->PlatformMonitor != -1) + new_dpi_scale = g.PlatformIO.Monitors[viewport->PlatformMonitor].DpiScale; + else + new_dpi_scale = (viewport->DpiScale != 0.0f) ? viewport->DpiScale : 1.0f; + if (viewport->DpiScale != 0.0f && new_dpi_scale != viewport->DpiScale) + { + float scale_factor = new_dpi_scale / viewport->DpiScale; + if (g.IO.ConfigFlags & ImGuiConfigFlags_DpiEnableScaleViewports) + ScaleWindowsInViewport(viewport, scale_factor); + //if (viewport == GetMainViewport()) + // g.PlatformInterface.SetWindowSize(viewport, viewport->Size * scale_factor); + + // Scale our window moving pivot so that the window will rescale roughly around the mouse position. + // FIXME-VIEWPORT: This currently creates a resizing feedback loop when a window is straddling a DPI transition border. + // (Minor: since our sizes do not perfectly linearly scale, deferring the click offset scale until we know the actual window scale ratio may get us slightly more precise mouse positioning.) + //if (g.MovingWindow != NULL && g.MovingWindow->Viewport == viewport) + // g.ActiveIdClickOffset = ImFloor(g.ActiveIdClickOffset * scale_factor); + } + viewport->DpiScale = new_dpi_scale; + } + + if (!viewports_enabled) + { + g.MouseViewport = main_viewport; + return; + } + + // Mouse handling: decide on the actual mouse viewport for this frame between the active/focused viewport and the hovered viewport. + // Note that 'viewport_hovered' should skip over any viewport that has the ImGuiViewportFlags_NoInputs flags set. + ImGuiViewportP* viewport_hovered = NULL; + if (g.IO.BackendFlags & ImGuiBackendFlags_HasMouseHoveredViewport) + { + viewport_hovered = g.IO.MouseHoveredViewport ? (ImGuiViewportP*)FindViewportByID(g.IO.MouseHoveredViewport) : NULL; + if (viewport_hovered && (viewport_hovered->Flags & ImGuiViewportFlags_NoInputs)) + { + // Back-end failed at honoring its contract if it returned a viewport with the _NoInputs flag. + IM_ASSERT(0); + viewport_hovered = FindHoveredViewportFromPlatformWindowStack(g.IO.MousePos); + } + } + else + { + // If the back-end doesn't know how to honor ImGuiViewportFlags_NoInputs, we do a search ourselves. Note that this search: + // A) won't take account of the possibility that non-imgui windows may be in-between our dragged window and our target window. + // B) uses LastFrameAsRefViewport as a flawed replacement for the last time a window was focused (we could/should fix that by introducing Focus functions in PlatformIO) + viewport_hovered = FindHoveredViewportFromPlatformWindowStack(g.IO.MousePos); + } + if (viewport_hovered != NULL) + g.MouseLastHoveredViewport = viewport_hovered; + else if (g.MouseLastHoveredViewport == NULL) + g.MouseLastHoveredViewport = g.Viewports[0]; + + // Update mouse reference viewport + // (when moving a window we aim at its viewport, but this will be overwritten below if we go in drag and drop mode) + if (g.MovingWindow) + g.MouseViewport = g.MovingWindow->Viewport; + else + g.MouseViewport = g.MouseLastHoveredViewport; + + // When dragging something, always refer to the last hovered viewport. + // - when releasing a moving window we will revert to aiming behind (at viewport_hovered) + // - when we are between viewports, our dragged preview will tend to show in the last viewport _even_ if we don't have tooltips in their viewports (when lacking monitor info) + // - consider the case of holding on a menu item to browse child menus: even thou a mouse button is held, there's no active id because menu items only react on mouse release. + const bool is_mouse_dragging_with_an_expected_destination = g.DragDropActive; + if (is_mouse_dragging_with_an_expected_destination && viewport_hovered == NULL) + viewport_hovered = g.MouseLastHoveredViewport; + if (is_mouse_dragging_with_an_expected_destination || g.ActiveId == 0 || !IsAnyMouseDown()) + if (viewport_hovered != NULL && viewport_hovered != g.MouseViewport && !(viewport_hovered->Flags & ImGuiViewportFlags_NoInputs)) + g.MouseViewport = viewport_hovered; + + IM_ASSERT(g.MouseViewport != NULL); +} + +// Update user-facing viewport list (g.Viewports -> g.PlatformIO.Viewports after filtering out some) +static void ImGui::UpdateViewportsEndFrame() +{ + ImGuiContext& g = *GImGui; + g.PlatformIO.MainViewport = g.Viewports[0]; + g.PlatformIO.Viewports.resize(0); + for (int i = 0; i < g.Viewports.Size; i++) + { + ImGuiViewportP* viewport = g.Viewports[i]; + viewport->LastPos = viewport->Pos; + if (viewport->LastFrameActive < g.FrameCount || viewport->Size.x <= 0.0f || viewport->Size.y <= 0.0f) + if (i > 0) // Always include main viewport in the list + continue; + if (viewport->Window && !IsWindowActiveAndVisible(viewport->Window)) + continue; + if (i > 0) + IM_ASSERT(viewport->Window != NULL); + g.PlatformIO.Viewports.push_back(viewport); + } + g.Viewports[0]->ClearRequestFlags(); // Clear main viewport flags because UpdatePlatformWindows() won't do it and may not even be called +} + +// FIXME: We should ideally refactor the system to call this every frame (we currently don't) +ImGuiViewportP* ImGui::AddUpdateViewport(ImGuiWindow* window, ImGuiID id, const ImVec2& pos, const ImVec2& size, ImGuiViewportFlags flags) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(id != 0); + + if (window != NULL) + { + if (g.MovingWindow && g.MovingWindow->RootWindow == window) + flags |= ImGuiViewportFlags_NoInputs | ImGuiViewportFlags_NoFocusOnAppearing; + if ((window->Flags & ImGuiWindowFlags_NoMouseInputs) && (window->Flags & ImGuiWindowFlags_NoNavInputs)) + flags |= ImGuiViewportFlags_NoInputs; + if (window->Flags & ImGuiWindowFlags_NoFocusOnAppearing) + flags |= ImGuiViewportFlags_NoFocusOnAppearing; + } + + ImGuiViewportP* viewport = (ImGuiViewportP*)FindViewportByID(id); + if (viewport) + { + if (!viewport->PlatformRequestMove) + viewport->Pos = pos; + if (!viewport->PlatformRequestResize) + viewport->Size = size; + viewport->Flags = flags | (viewport->Flags & ImGuiViewportFlags_Minimized); // Preserve existing flags + } + else + { + // New viewport + viewport = IM_NEW(ImGuiViewportP)(); + viewport->ID = id; + viewport->Idx = g.Viewports.Size; + viewport->Pos = viewport->LastPos = pos; + viewport->Size = size; + viewport->Flags = flags; + UpdateViewportPlatformMonitor(viewport); + g.Viewports.push_back(viewport); + IMGUI_DEBUG_LOG_VIEWPORT("Add Viewport %08X (%s)\n", id, window->Name); + + // We normally setup for all viewports in NewFrame() but here need to handle the mid-frame creation of a new viewport. + // We need to extend the fullscreen clip rect so the OverlayDrawList clip is correct for that the first frame + g.DrawListSharedData.ClipRectFullscreen.x = ImMin(g.DrawListSharedData.ClipRectFullscreen.x, viewport->Pos.x); + g.DrawListSharedData.ClipRectFullscreen.y = ImMin(g.DrawListSharedData.ClipRectFullscreen.y, viewport->Pos.y); + g.DrawListSharedData.ClipRectFullscreen.z = ImMax(g.DrawListSharedData.ClipRectFullscreen.z, viewport->Pos.x + viewport->Size.x); + g.DrawListSharedData.ClipRectFullscreen.w = ImMax(g.DrawListSharedData.ClipRectFullscreen.w, viewport->Pos.y + viewport->Size.y); + + // Store initial DpiScale before the OS platform window creation, based on expected monitor data. + // This is so we can select an appropriate font size on the first frame of our window lifetime + if (viewport->PlatformMonitor != -1) + viewport->DpiScale = g.PlatformIO.Monitors[viewport->PlatformMonitor].DpiScale; + } + + viewport->Window = window; + viewport->LastFrameActive = g.FrameCount; + IM_ASSERT(window == NULL || viewport->ID == window->ID); + + if (window != NULL) + window->ViewportOwned = true; + + return viewport; +} + +// FIXME-VIEWPORT: This is all super messy and ought to be clarified or rewritten. +static void ImGui::UpdateSelectWindowViewport(ImGuiWindow* window) +{ + ImGuiContext& g = *GImGui; + ImGuiWindowFlags flags = window->Flags; + window->ViewportAllowPlatformMonitorExtend = -1; + + // Restore main viewport if multi-viewport is not supported by the back-end + ImGuiViewportP* main_viewport = g.Viewports[0]; + if (!(g.ConfigFlagsCurrFrame & ImGuiConfigFlags_ViewportsEnable)) + { + SetWindowViewport(window, main_viewport); + return; + } + window->ViewportOwned = false; + + // Appearing popups reset their viewport so they can inherit again + if ((flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_Tooltip)) && window->Appearing) + { + window->Viewport = NULL; + window->ViewportId = 0; + } + + if ((g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasViewport) == 0) + { + // By default inherit from parent window + if (window->Viewport == NULL && window->ParentWindow && !window->ParentWindow->IsFallbackWindow) + window->Viewport = window->ParentWindow->Viewport; + + // Attempt to restore saved viewport id (= window that hasn't been activated yet), try to restore the viewport based on saved 'window->ViewportPos' restored from .ini file + if (window->Viewport == NULL && window->ViewportId != 0) + { + window->Viewport = (ImGuiViewportP*)FindViewportByID(window->ViewportId); + if (window->Viewport == NULL && window->ViewportPos.x != FLT_MAX && window->ViewportPos.y != FLT_MAX) + window->Viewport = AddUpdateViewport(window, window->ID, window->ViewportPos, window->Size, ImGuiViewportFlags_None); + } + } + + bool lock_viewport = false; + if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasViewport) + { + // Code explicitly request a viewport + window->Viewport = (ImGuiViewportP*)FindViewportByID(g.NextWindowData.ViewportId); + window->ViewportId = g.NextWindowData.ViewportId; // Store ID even if Viewport isn't resolved yet. + lock_viewport = true; + } + else if ((flags & ImGuiWindowFlags_ChildWindow) || (flags & ImGuiWindowFlags_ChildMenu)) + { + // Always inherit viewport from parent window + window->Viewport = window->ParentWindow->Viewport; + } + else if (flags & ImGuiWindowFlags_Tooltip) + { + window->Viewport = g.MouseViewport; + } + else if (GetWindowAlwaysWantOwnViewport(window)) + { + window->Viewport = AddUpdateViewport(window, window->ID, window->Pos, window->Size, ImGuiViewportFlags_None); + } + else if (g.MovingWindow && g.MovingWindow->RootWindow == window && IsMousePosValid()) + { + if (window->Viewport != NULL && window->Viewport->Window == window) + window->Viewport = AddUpdateViewport(window, window->ID, window->Pos, window->Size, ImGuiViewportFlags_None); + } + else + { + // Merge into host viewport? + // We cannot test window->ViewportOwned as it set lower in the function. + bool try_to_merge_into_host_viewport = (window->Viewport && window == window->Viewport->Window && g.ActiveId == 0); + if (try_to_merge_into_host_viewport) + UpdateTryMergeWindowIntoHostViewports(window); + } + + // Fallback to default viewport + if (window->Viewport == NULL) + window->Viewport = main_viewport; + + // Mark window as allowed to protrude outside of its viewport and into the current monitor + if (!lock_viewport) + { + if (flags & (ImGuiWindowFlags_Tooltip | ImGuiWindowFlags_Popup)) + { + // We need to take account of the possibility that mouse may become invalid. + // Popups/Tooltip always set ViewportAllowPlatformMonitorExtend so GetWindowAllowedExtentRect() will return full monitor bounds. + ImVec2 mouse_ref = (flags & ImGuiWindowFlags_Tooltip) ? g.IO.MousePos : g.BeginPopupStack.back().OpenMousePos; + bool use_mouse_ref = (g.NavDisableHighlight || !g.NavDisableMouseHover || !g.NavWindow); + bool mouse_valid = IsMousePosValid(&mouse_ref); + if ((window->Appearing || (flags & (ImGuiWindowFlags_Tooltip | ImGuiWindowFlags_ChildMenu))) && (!use_mouse_ref || mouse_valid)) + window->ViewportAllowPlatformMonitorExtend = FindPlatformMonitorForPos((use_mouse_ref && mouse_valid) ? mouse_ref : NavCalcPreferredRefPos()); + else + window->ViewportAllowPlatformMonitorExtend = window->Viewport->PlatformMonitor; + } + else if (window->Viewport && window != window->Viewport->Window && window->Viewport->Window && !(flags & ImGuiWindowFlags_ChildWindow)) + { + // When called from Begin() we don't have access to a proper version of the Hidden flag yet, so we replicate this code. + const bool will_be_visible = (window->DockIsActive && !window->DockTabIsVisible) ? false : true; + if ((window->Flags & ImGuiWindowFlags_DockNodeHost) && window->Viewport->LastFrameActive < g.FrameCount && will_be_visible) + { + // Steal/transfer ownership + IMGUI_DEBUG_LOG_VIEWPORT("Window '%s' steal Viewport %08X from Window '%s'\n", window->Name, window->Viewport->ID, window->Viewport->Window->Name); + window->Viewport->Window = window; + window->Viewport->ID = window->ID; + window->Viewport->LastNameHash = 0; + } + else if (!UpdateTryMergeWindowIntoHostViewports(window)) // Merge? + { + // New viewport + window->Viewport = AddUpdateViewport(window, window->ID, window->Pos, window->Size, ImGuiViewportFlags_NoFocusOnAppearing); + } + } + else if (window->ViewportAllowPlatformMonitorExtend < 0 && (flags & ImGuiWindowFlags_ChildWindow) == 0) + { + // Regular (non-child, non-popup) windows by default are also allowed to protrude + // Child windows are kept contained within their parent. + window->ViewportAllowPlatformMonitorExtend = window->Viewport->PlatformMonitor; + } + } + + // Update flags + window->ViewportOwned = (window == window->Viewport->Window); + window->ViewportId = window->Viewport->ID; + + // If the OS window has a title bar, hide our imgui title bar + //if (window->ViewportOwned && !(window->Viewport->Flags & ImGuiViewportFlags_NoDecoration)) + // window->Flags |= ImGuiWindowFlags_NoTitleBar; +} + +// Called by user at the end of the main loop, after EndFrame() +// This will handle the creation/update of all OS windows via function defined in the ImGuiPlatformIO api. +void ImGui::UpdatePlatformWindows() +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(g.FrameCountEnded == g.FrameCount && "Forgot to call Render() or EndFrame() before UpdatePlatformWindows()?"); + IM_ASSERT(g.FrameCountPlatformEnded < g.FrameCount); + g.FrameCountPlatformEnded = g.FrameCount; + if (!(g.ConfigFlagsCurrFrame & ImGuiConfigFlags_ViewportsEnable)) + return; + + // Create/resize/destroy platform windows to match each active viewport. + // Skip the main viewport (index 0), which is always fully handled by the application! + for (int i = 1; i < g.Viewports.Size; i++) + { + ImGuiViewportP* viewport = g.Viewports[i]; + + // Destroy platform window if the viewport hasn't been submitted or if it is hosting a hidden window + // (the implicit/fallback Debug##Default window will be registering its viewport then be disabled, causing a dummy DestroyPlatformWindow to be made each frame) + bool destroy_platform_window = false; + destroy_platform_window |= (viewport->LastFrameActive < g.FrameCount - 1); + destroy_platform_window |= (viewport->Window && !IsWindowActiveAndVisible(viewport->Window)); + if (destroy_platform_window) + { + DestroyPlatformWindow(viewport); + continue; + } + + // New windows that appears directly in a new viewport won't always have a size on their first frame + if (viewport->LastFrameActive < g.FrameCount || viewport->Size.x <= 0 || viewport->Size.y <= 0) + continue; + + // Create window + bool is_new_platform_window = (viewport->PlatformWindowCreated == false); + if (is_new_platform_window) + { + IMGUI_DEBUG_LOG_VIEWPORT("Create Platform Window %08X (%s)\n", viewport->ID, viewport->Window ? viewport->Window->Name : "n/a"); + g.PlatformIO.Platform_CreateWindow(viewport); + if (g.PlatformIO.Renderer_CreateWindow != NULL) + g.PlatformIO.Renderer_CreateWindow(viewport); + viewport->LastNameHash = 0; + viewport->LastPlatformPos = viewport->LastPlatformSize = ImVec2(FLT_MAX, FLT_MAX); // By clearing those we'll enforce a call to Platform_SetWindowPos/Size below, before Platform_ShowWindow (FIXME: Is that necessary?) + viewport->LastRendererSize = viewport->Size; // We don't need to call Renderer_SetWindowSize() as it is expected Renderer_CreateWindow() already did it. + viewport->PlatformWindowCreated = true; + } + + // Apply Position and Size (from ImGui to Platform/Renderer back-ends) + if ((viewport->LastPlatformPos.x != viewport->Pos.x || viewport->LastPlatformPos.y != viewport->Pos.y) && !viewport->PlatformRequestMove) + g.PlatformIO.Platform_SetWindowPos(viewport, viewport->Pos); + if ((viewport->LastPlatformSize.x != viewport->Size.x || viewport->LastPlatformSize.y != viewport->Size.y) && !viewport->PlatformRequestResize) + g.PlatformIO.Platform_SetWindowSize(viewport, viewport->Size); + if ((viewport->LastRendererSize.x != viewport->Size.x || viewport->LastRendererSize.y != viewport->Size.y) && g.PlatformIO.Renderer_SetWindowSize) + g.PlatformIO.Renderer_SetWindowSize(viewport, viewport->Size); + viewport->LastPlatformPos = viewport->Pos; + viewport->LastPlatformSize = viewport->LastRendererSize = viewport->Size; + + // Update title bar (if it changed) + if (ImGuiWindow* window_for_title = GetWindowForTitleDisplay(viewport->Window)) + { + const char* title_begin = window_for_title->Name; + char* title_end = (char*)(intptr_t)FindRenderedTextEnd(title_begin); + const ImGuiID title_hash = ImHashStr(title_begin, title_end - title_begin); + if (viewport->LastNameHash != title_hash) + { + char title_end_backup_c = *title_end; + *title_end = 0; // Cut existing buffer short instead of doing an alloc/free, no small gain. + g.PlatformIO.Platform_SetWindowTitle(viewport, title_begin); + *title_end = title_end_backup_c; + viewport->LastNameHash = title_hash; + } + } + + // Update alpha (if it changed) + if (viewport->LastAlpha != viewport->Alpha && g.PlatformIO.Platform_SetWindowAlpha) + g.PlatformIO.Platform_SetWindowAlpha(viewport, viewport->Alpha); + viewport->LastAlpha = viewport->Alpha; + + // Optional, general purpose call to allow the back-end to perform general book-keeping even if things haven't changed. + if (g.PlatformIO.Platform_UpdateWindow) + g.PlatformIO.Platform_UpdateWindow(viewport); + + if (is_new_platform_window) + { + // On startup ensure new platform window don't steal focus (give it a few frames, as nested contents may lead to viewport being created a few frames late) + if (g.FrameCount < 3) + viewport->Flags |= ImGuiViewportFlags_NoFocusOnAppearing; + + // Show window + g.PlatformIO.Platform_ShowWindow(viewport); + + // Even without focus, we assume the window becomes front-most. + // This is useful for our platform z-order heuristic when io.MouseHoveredViewport is not available. + if (viewport->LastFrontMostStampCount != g.ViewportFrontMostStampCount) + viewport->LastFrontMostStampCount = ++g.ViewportFrontMostStampCount; + } + + // Clear request flags + viewport->ClearRequestFlags(); + } + + // Update our implicit z-order knowledge of platform windows, which is used when the back-end cannot provide io.MouseHoveredViewport. + // When setting Platform_GetWindowFocus, it is expected that the platform back-end can handle calls without crashing if it doesn't have data stored. + if (g.PlatformIO.Platform_GetWindowFocus != NULL) + { + ImGuiViewportP* focused_viewport = NULL; + for (int n = 0; n < g.Viewports.Size && focused_viewport == NULL; n++) + { + ImGuiViewportP* viewport = g.Viewports[n]; + if (viewport->PlatformWindowCreated) + if (g.PlatformIO.Platform_GetWindowFocus(viewport)) + focused_viewport = viewport; + } + if (focused_viewport && g.PlatformLastFocusedViewport != focused_viewport->ID) + { + if (focused_viewport->LastFrontMostStampCount != g.ViewportFrontMostStampCount) + focused_viewport->LastFrontMostStampCount = ++g.ViewportFrontMostStampCount; + g.PlatformLastFocusedViewport = focused_viewport->ID; + } + } +} + +// This is a default/basic function for performing the rendering/swap of multiple Platform Windows. +// Custom renderers may prefer to not call this function at all, and instead iterate the publicly exposed platform data and handle rendering/sync themselves. +// The Render/Swap functions stored in ImGuiPlatformIO are merely here to allow for this helper to exist, but you can do it yourself: +// +// ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); +// for (int i = 1; i < platform_io.Viewports.Size; i++) +// if ((platform_io.Viewports[i]->Flags & ImGuiViewportFlags_Minimized) == 0) +// MyRenderFunction(platform_io.Viewports[i], my_args); +// for (int i = 1; i < platform_io.Viewports.Size; i++) +// if ((platform_io.Viewports[i]->Flags & ImGuiViewportFlags_Minimized) == 0) +// MySwapBufferFunction(platform_io.Viewports[i], my_args); +// +void ImGui::RenderPlatformWindowsDefault(void* platform_render_arg, void* renderer_render_arg) +{ + // Skip the main viewport (index 0), which is always fully handled by the application! + ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); + for (int i = 1; i < platform_io.Viewports.Size; i++) + { + ImGuiViewport* viewport = platform_io.Viewports[i]; + if (viewport->Flags & ImGuiViewportFlags_Minimized) + continue; + if (platform_io.Platform_RenderWindow) platform_io.Platform_RenderWindow(viewport, platform_render_arg); + if (platform_io.Renderer_RenderWindow) platform_io.Renderer_RenderWindow(viewport, renderer_render_arg); + } + for (int i = 1; i < platform_io.Viewports.Size; i++) + { + ImGuiViewport* viewport = platform_io.Viewports[i]; + if (viewport->Flags & ImGuiViewportFlags_Minimized) + continue; + if (platform_io.Platform_SwapBuffers) platform_io.Platform_SwapBuffers(viewport, platform_render_arg); + if (platform_io.Renderer_SwapBuffers) platform_io.Renderer_SwapBuffers(viewport, renderer_render_arg); + } +} + +static int ImGui::FindPlatformMonitorForPos(const ImVec2& pos) +{ + ImGuiContext& g = *GImGui; + for (int monitor_n = 0; monitor_n < g.PlatformIO.Monitors.Size; monitor_n++) + { + const ImGuiPlatformMonitor& monitor = g.PlatformIO.Monitors[monitor_n]; + if (ImRect(monitor.MainPos, monitor.MainPos + monitor.MainSize).Contains(pos)) + return monitor_n; + } + return -1; +} + +// Search for the monitor with the largest intersection area with the given rectangle +// We generally try to avoid searching loops but the monitor count should be very small here +// FIXME-OPT: We could test the last monitor used for that viewport first, and early +static int ImGui::FindPlatformMonitorForRect(const ImRect& rect) +{ + ImGuiContext& g = *GImGui; + + const int monitor_count = g.PlatformIO.Monitors.Size; + if (monitor_count <= 1) + return monitor_count - 1; + + // Use a minimum threshold of 1.0f so a zero-sized rect won't false positive, and will still find the correct monitor given its position. + // This is necessary for tooltips which always resize down to zero at first. + const float surface_threshold = ImMax(rect.GetWidth() * rect.GetHeight() * 0.5f, 1.0f); + int best_monitor_n = -1; + float best_monitor_surface = 0.001f; + + for (int monitor_n = 0; monitor_n < g.PlatformIO.Monitors.Size && best_monitor_surface < surface_threshold; monitor_n++) + { + const ImGuiPlatformMonitor& monitor = g.PlatformIO.Monitors[monitor_n]; + const ImRect monitor_rect = ImRect(monitor.MainPos, monitor.MainPos + monitor.MainSize); + if (monitor_rect.Contains(rect)) + return monitor_n; + ImRect overlapping_rect = rect; + overlapping_rect.ClipWithFull(monitor_rect); + float overlapping_surface = overlapping_rect.GetWidth() * overlapping_rect.GetHeight(); + if (overlapping_surface < best_monitor_surface) + continue; + best_monitor_surface = overlapping_surface; + best_monitor_n = monitor_n; + } + return best_monitor_n; +} + +// Update monitor from viewport rectangle (we'll use this info to clamp windows and save windows lost in a removed monitor) +static void ImGui::UpdateViewportPlatformMonitor(ImGuiViewportP* viewport) +{ + viewport->PlatformMonitor = (short)FindPlatformMonitorForRect(viewport->GetMainRect()); +} + +void ImGui::DestroyPlatformWindow(ImGuiViewportP* viewport) +{ + ImGuiContext& g = *GImGui; + if (viewport->PlatformWindowCreated) + { + if (g.PlatformIO.Renderer_DestroyWindow) + g.PlatformIO.Renderer_DestroyWindow(viewport); + if (g.PlatformIO.Platform_DestroyWindow) + g.PlatformIO.Platform_DestroyWindow(viewport); + IM_ASSERT(viewport->RendererUserData == NULL && viewport->PlatformUserData == NULL); + + // Don't clear PlatformWindowCreated for the main viewport, as we initially set that up to true in Initialize() + // The right-er way may be to leave it to the back-end to set this flag all-together, and made the flag public. + if (viewport->ID != IMGUI_VIEWPORT_DEFAULT_ID) + viewport->PlatformWindowCreated = false; + } + else + { + IM_ASSERT(viewport->RendererUserData == NULL && viewport->PlatformUserData == NULL && viewport->PlatformHandle == NULL); + } + viewport->RendererUserData = viewport->PlatformUserData = viewport->PlatformHandle = NULL; + viewport->ClearRequestFlags(); +} + +void ImGui::DestroyPlatformWindows() +{ + // We call the destroy window on every viewport (including the main viewport, index 0) to give a chance to the back-end + // to clear any data they may have stored in e.g. PlatformUserData, RendererUserData. + // It is convenient for the platform back-end code to store something in the main viewport, in order for e.g. the mouse handling + // code to operator a consistent manner. + // It is expected that the back-end can handle calls to Renderer_DestroyWindow/Platform_DestroyWindow without + // crashing if it doesn't have data stored. + ImGuiContext& g = *GImGui; + for (int i = 0; i < g.Viewports.Size; i++) + DestroyPlatformWindow(g.Viewports[i]); +} + + +//----------------------------------------------------------------------------- +// [SECTION] DOCKING +//----------------------------------------------------------------------------- +// Docking: Internal Types +// Docking: Forward Declarations +// Docking: ImGuiDockContext +// Docking: ImGuiDockContext Docking/Undocking functions +// Docking: ImGuiDockNode +// Docking: ImGuiDockNode Tree manipulation functions +// Docking: Public Functions (SetWindowDock, DockSpace, DockSpaceOverViewport) +// Docking: Builder Functions +// Docking: Begin/End Support Functions (called from Begin/End) +// Docking: Settings +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// Docking: Internal Types +//----------------------------------------------------------------------------- +// - ImGuiDockRequestType +// - ImGuiDockRequest +// - ImGuiDockPreviewData +// - ImGuiDockNodeSettings +// - ImGuiDockContext +//----------------------------------------------------------------------------- + +static float IMGUI_DOCK_SPLITTER_SIZE = 2.0f; + +enum ImGuiDockRequestType +{ + ImGuiDockRequestType_None = 0, + ImGuiDockRequestType_Dock, + ImGuiDockRequestType_Undock, + ImGuiDockRequestType_Split // Split is the same as Dock but without a DockPayload +}; + +struct ImGuiDockRequest +{ + ImGuiDockRequestType Type; + ImGuiWindow* DockTargetWindow; // Destination/Target Window to dock into (may be a loose window or a DockNode, might be NULL in which case DockTargetNode cannot be NULL) + ImGuiDockNode* DockTargetNode; // Destination/Target Node to dock into + ImGuiWindow* DockPayload; // Source/Payload window to dock (may be a loose window or a DockNode), [Optional] + ImGuiDir DockSplitDir; + float DockSplitRatio; + bool DockSplitOuter; + ImGuiWindow* UndockTargetWindow; + ImGuiDockNode* UndockTargetNode; + + ImGuiDockRequest() + { + Type = ImGuiDockRequestType_None; + DockTargetWindow = DockPayload = UndockTargetWindow = NULL; + DockTargetNode = UndockTargetNode = NULL; + DockSplitDir = ImGuiDir_None; + DockSplitRatio = 0.5f; + DockSplitOuter = false; + } +}; + +struct ImGuiDockPreviewData +{ + ImGuiDockNode FutureNode; + bool IsDropAllowed; + bool IsCenterAvailable; + bool IsSidesAvailable; // Hold your breath, grammar freaks.. + bool IsSplitDirExplicit; // Set when hovered the drop rect (vs. implicit SplitDir==None when hovered the window) + ImGuiDockNode* SplitNode; + ImGuiDir SplitDir; + float SplitRatio; + ImRect DropRectsDraw[ImGuiDir_COUNT + 1]; // May be slightly different from hit-testing drop rects used in DockNodeCalcDropRects() + + ImGuiDockPreviewData() : FutureNode(0) { IsDropAllowed = IsCenterAvailable = IsSidesAvailable = IsSplitDirExplicit = false; SplitNode = NULL; SplitDir = ImGuiDir_None; SplitRatio = 0.f; } +}; + +// Persistent Settings data, stored contiguously in SettingsNodes (sizeof() ~32 bytes) +struct ImGuiDockNodeSettings +{ + ImGuiID ID; + ImGuiID ParentNodeId; + ImGuiID ParentWindowId; + ImGuiID SelectedWindowId; + signed char SplitAxis; + char Depth; + ImGuiDockNodeFlags Flags; // NB: We save individual flags one by one in ascii format (ImGuiDockNodeFlags_SavedFlagsMask_) + ImVec2ih Pos; + ImVec2ih Size; + ImVec2ih SizeRef; + ImGuiDockNodeSettings() { ID = ParentNodeId = ParentWindowId = SelectedWindowId = 0; SplitAxis = ImGuiAxis_None; Depth = 0; Flags = ImGuiDockNodeFlags_None; } +}; + +//----------------------------------------------------------------------------- +// Docking: Forward Declarations +//----------------------------------------------------------------------------- + +namespace ImGui +{ + // ImGuiDockContext + static ImGuiDockNode* DockContextAddNode(ImGuiContext* ctx, ImGuiID id); + static void DockContextRemoveNode(ImGuiContext* ctx, ImGuiDockNode* node, bool merge_sibling_into_parent_node); + static void DockContextQueueNotifyRemovedNode(ImGuiContext* ctx, ImGuiDockNode* node); + static void DockContextProcessDock(ImGuiContext* ctx, ImGuiDockRequest* req); + static void DockContextProcessUndockWindow(ImGuiContext* ctx, ImGuiWindow* window, bool clear_persistent_docking_ref = true); + static void DockContextProcessUndockNode(ImGuiContext* ctx, ImGuiDockNode* node); + static void DockContextPruneUnusedSettingsNodes(ImGuiContext* ctx); + static ImGuiDockNode* DockContextFindNodeByID(ImGuiContext* ctx, ImGuiID id); + static ImGuiDockNode* DockContextBindNodeToWindow(ImGuiContext* ctx, ImGuiWindow* window); + static void DockContextBuildNodesFromSettings(ImGuiContext* ctx, ImGuiDockNodeSettings* node_settings_array, int node_settings_count); + static void DockContextBuildAddWindowsToNodes(ImGuiContext* ctx, ImGuiID root_id); // Use root_id==0 to add all + + // ImGuiDockNode + static void DockNodeAddWindow(ImGuiDockNode* node, ImGuiWindow* window, bool add_to_tab_bar); + static void DockNodeMoveWindows(ImGuiDockNode* dst_node, ImGuiDockNode* src_node); + static void DockNodeMoveChildNodes(ImGuiDockNode* dst_node, ImGuiDockNode* src_node); + static ImGuiWindow* DockNodeFindWindowByID(ImGuiDockNode* node, ImGuiID id); + static void DockNodeApplyPosSizeToWindows(ImGuiDockNode* node); + static void DockNodeRemoveWindow(ImGuiDockNode* node, ImGuiWindow* window, ImGuiID save_dock_id); + static void DockNodeHideHostWindow(ImGuiDockNode* node); + static void DockNodeUpdate(ImGuiDockNode* node); + static void DockNodeUpdateForRootNode(ImGuiDockNode* node); + static void DockNodeUpdateVisibleFlagAndInactiveChilds(ImGuiDockNode* node); + static void DockNodeUpdateTabBar(ImGuiDockNode* node, ImGuiWindow* host_window); + static void DockNodeAddTabBar(ImGuiDockNode* node); + static void DockNodeRemoveTabBar(ImGuiDockNode* node); + static ImGuiID DockNodeUpdateWindowMenu(ImGuiDockNode* node, ImGuiTabBar* tab_bar); + static void DockNodeUpdateVisibleFlag(ImGuiDockNode* node); + static void DockNodeStartMouseMovingWindow(ImGuiDockNode* node, ImGuiWindow* window); + static bool DockNodeIsDropAllowed(ImGuiWindow* host_window, ImGuiWindow* payload_window); + static void DockNodePreviewDockSetup(ImGuiWindow* host_window, ImGuiDockNode* host_node, ImGuiWindow* payload_window, ImGuiDockPreviewData* preview_data, bool is_explicit_target, bool is_outer_docking); + static void DockNodePreviewDockRender(ImGuiWindow* host_window, ImGuiDockNode* host_node, ImGuiWindow* payload_window, const ImGuiDockPreviewData* preview_data); + static void DockNodeCalcTabBarLayout(const ImGuiDockNode* node, ImRect* out_title_rect, ImRect* out_tab_bar_rect, ImVec2* out_window_menu_button_pos); + static void DockNodeCalcSplitRects(ImVec2& pos_old, ImVec2& size_old, ImVec2& pos_new, ImVec2& size_new, ImGuiDir dir, ImVec2 size_new_desired); + static bool DockNodeCalcDropRectsAndTestMousePos(const ImRect& parent, ImGuiDir dir, ImRect& out_draw, bool outer_docking, ImVec2* test_mouse_pos); + static const char* DockNodeGetHostWindowTitle(ImGuiDockNode* node, char* buf, int buf_size) { ImFormatString(buf, buf_size, "##DockNode_%02X", node->ID); return buf; } + static int DockNodeGetTabOrder(ImGuiWindow* window); + + // ImGuiDockNode tree manipulations + static void DockNodeTreeSplit(ImGuiContext* ctx, ImGuiDockNode* parent_node, ImGuiAxis split_axis, int split_first_child, float split_ratio, ImGuiDockNode* new_node); + static void DockNodeTreeMerge(ImGuiContext* ctx, ImGuiDockNode* parent_node, ImGuiDockNode* merge_lead_child); + static void DockNodeTreeUpdatePosSize(ImGuiDockNode* node, ImVec2 pos, ImVec2 size, bool only_write_to_marked_nodes = false); + static void DockNodeTreeUpdateSplitter(ImGuiDockNode* node); + static ImGuiDockNode* DockNodeTreeFindNodeByPos(ImGuiDockNode* node, ImVec2 pos); + static ImGuiDockNode* DockNodeTreeFindFallbackLeafNode(ImGuiDockNode* node); + + // Settings + static void DockSettingsRenameNodeReferences(ImGuiID old_node_id, ImGuiID new_node_id); + static void DockSettingsRemoveNodeReferences(ImGuiID* node_ids, int node_ids_count); + static ImGuiDockNodeSettings* DockSettingsFindNodeSettings(ImGuiContext* ctx, ImGuiID node_id); + static void DockSettingsHandler_ClearAll(ImGuiContext*, ImGuiSettingsHandler*); + static void DockSettingsHandler_ApplyAll(ImGuiContext*, ImGuiSettingsHandler*); + static void* DockSettingsHandler_ReadOpen(ImGuiContext*, ImGuiSettingsHandler*, const char* name); + static void DockSettingsHandler_ReadLine(ImGuiContext*, ImGuiSettingsHandler*, void* entry, const char* line); + static void DockSettingsHandler_WriteAll(ImGuiContext* imgui_ctx, ImGuiSettingsHandler* handler, ImGuiTextBuffer* buf); +} + +//----------------------------------------------------------------------------- +// Docking: ImGuiDockContext +//----------------------------------------------------------------------------- +// The lifetime model is different from the one of regular windows: we always create a ImGuiDockNode for each ImGuiDockNodeSettings, +// or we always hold the entire docking node tree. Nodes are frequently hidden, e.g. if the window(s) or child nodes they host are not active. +// At boot time only, we run a simple GC to remove nodes that have no references. +// Because dock node settings (which are small, contiguous structures) are always mirrored by their corresponding dock nodes (more complete structures), +// we can also very easily recreate the nodes from scratch given the settings data (this is what DockContextRebuild() does). +// This is convenient as docking reconfiguration can be implemented by mostly poking at the simpler settings data. +//----------------------------------------------------------------------------- +// - DockContextInitialize() +// - DockContextShutdown() +// - DockContextClearNodes() +// - DockContextRebuildNodes() +// - DockContextUpdateUndocking() +// - DockContextUpdateDocking() +// - DockContextFindNodeByID() +// - DockContextBindNodeToWindow() +// - DockContextGenNodeID() +// - DockContextAddNode() +// - DockContextRemoveNode() +// - ImGuiDockContextPruneNodeData +// - DockContextPruneUnusedSettingsNodes() +// - DockContextBuildNodesFromSettings() +// - DockContextBuildAddWindowsToNodes() +//----------------------------------------------------------------------------- + +void ImGui::DockContextInitialize(ImGuiContext* ctx) +{ + ImGuiContext& g = *ctx; + + // Add .ini handle for persistent docking data + ImGuiSettingsHandler ini_handler; + ini_handler.TypeName = "Docking"; + ini_handler.TypeHash = ImHashStr("Docking"); + ini_handler.ClearAllFn = DockSettingsHandler_ClearAll; + ini_handler.ReadInitFn = DockSettingsHandler_ClearAll; // Also clear on read + ini_handler.ReadOpenFn = DockSettingsHandler_ReadOpen; + ini_handler.ReadLineFn = DockSettingsHandler_ReadLine; + ini_handler.ApplyAllFn = DockSettingsHandler_ApplyAll; + ini_handler.WriteAllFn = DockSettingsHandler_WriteAll; + g.SettingsHandlers.push_back(ini_handler); +} + +void ImGui::DockContextShutdown(ImGuiContext* ctx) +{ + ImGuiDockContext* dc = &ctx->DockContext; + for (int n = 0; n < dc->Nodes.Data.Size; n++) + if (ImGuiDockNode* node = (ImGuiDockNode*)dc->Nodes.Data[n].val_p) + IM_DELETE(node); +} + +void ImGui::DockContextClearNodes(ImGuiContext* ctx, ImGuiID root_id, bool clear_settings_refs) +{ + IM_UNUSED(ctx); + IM_ASSERT(ctx == GImGui); + DockBuilderRemoveNodeDockedWindows(root_id, clear_settings_refs); + DockBuilderRemoveNodeChildNodes(root_id); +} + +// [DEBUG] This function also acts as a defacto test to make sure we can rebuild from scratch without a glitch +// (Different from DockSettingsHandler_ClearAll() + DockSettingsHandler_ApplyAll() because this reuses current settings!) +void ImGui::DockContextRebuildNodes(ImGuiContext* ctx) +{ + IMGUI_DEBUG_LOG_DOCKING("DockContextRebuild()\n"); + ImGuiDockContext* dc = &ctx->DockContext; + SaveIniSettingsToMemory(); + ImGuiID root_id = 0; // Rebuild all + DockContextClearNodes(ctx, root_id, false); + DockContextBuildNodesFromSettings(ctx, dc->NodesSettings.Data, dc->NodesSettings.Size); + DockContextBuildAddWindowsToNodes(ctx, root_id); +} + +// Docking context update function, called by NewFrame() +void ImGui::DockContextUpdateUndocking(ImGuiContext* ctx) +{ + ImGuiContext& g = *ctx; + ImGuiDockContext* dc = &ctx->DockContext; + if (!(g.IO.ConfigFlags & ImGuiConfigFlags_DockingEnable)) + { + if (dc->Nodes.Data.Size > 0 || dc->Requests.Size > 0) + DockContextClearNodes(ctx, 0, true); + return; + } + + // Setting NoSplit at runtime merges all nodes + if (g.IO.ConfigDockingNoSplit) + for (int n = 0; n < dc->Nodes.Data.Size; n++) + if (ImGuiDockNode* node = (ImGuiDockNode*)dc->Nodes.Data[n].val_p) + if (node->IsRootNode() && node->IsSplitNode()) + { + DockBuilderRemoveNodeChildNodes(node->ID); + //dc->WantFullRebuild = true; + } + + // Process full rebuild +#if 0 + if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_C))) + dc->WantFullRebuild = true; +#endif + if (dc->WantFullRebuild) + { + DockContextRebuildNodes(ctx); + dc->WantFullRebuild = false; + } + + // Process Undocking requests (we need to process them _before_ the UpdateMouseMovingWindowNewFrame call in NewFrame) + for (int n = 0; n < dc->Requests.Size; n++) + { + ImGuiDockRequest* req = &dc->Requests[n]; + if (req->Type == ImGuiDockRequestType_Undock && req->UndockTargetWindow) + DockContextProcessUndockWindow(ctx, req->UndockTargetWindow); + else if (req->Type == ImGuiDockRequestType_Undock && req->UndockTargetNode) + DockContextProcessUndockNode(ctx, req->UndockTargetNode); + } +} + +// Docking context update function, called by NewFrame() +void ImGui::DockContextUpdateDocking(ImGuiContext* ctx) +{ + ImGuiContext& g = *ctx; + ImGuiDockContext* dc = &ctx->DockContext; + if (!(g.IO.ConfigFlags & ImGuiConfigFlags_DockingEnable)) + return; + + // Process Docking requests + for (int n = 0; n < dc->Requests.Size; n++) + if (dc->Requests[n].Type == ImGuiDockRequestType_Dock) + DockContextProcessDock(ctx, &dc->Requests[n]); + dc->Requests.resize(0); + + // Create windows for each automatic docking nodes + // We can have NULL pointers when we delete nodes, but because ID are recycled this should amortize nicely (and our node count will never be very high) + for (int n = 0; n < dc->Nodes.Data.Size; n++) + if (ImGuiDockNode* node = (ImGuiDockNode*)dc->Nodes.Data[n].val_p) + if (node->IsFloatingNode()) + DockNodeUpdate(node); +} + +static ImGuiDockNode* ImGui::DockContextFindNodeByID(ImGuiContext* ctx, ImGuiID id) +{ + return (ImGuiDockNode*)ctx->DockContext.Nodes.GetVoidPtr(id); +} + +ImGuiID ImGui::DockContextGenNodeID(ImGuiContext* ctx) +{ + // Generate an ID for new node (the exact ID value doesn't matter as long as it is not already used) + // FIXME-OPT FIXME-DOCK: This is suboptimal, even if the node count is small enough not to be a worry. We should poke in ctx->Nodes to find a suitable ID faster. + ImGuiID id = 0x0001; + while (DockContextFindNodeByID(ctx, id) != NULL) + id++; + return id; +} + +static ImGuiDockNode* ImGui::DockContextAddNode(ImGuiContext* ctx, ImGuiID id) +{ + // Generate an ID for the new node (the exact ID value doesn't matter as long as it is not already used) and add the first window. + if (id == 0) + id = DockContextGenNodeID(ctx); + else + IM_ASSERT(DockContextFindNodeByID(ctx, id) == NULL); + + // We don't set node->LastFrameAlive on construction. Nodes are always created at all time to reflect .ini settings! + IMGUI_DEBUG_LOG_DOCKING("DockContextAddNode 0x%08X\n", id); + ImGuiDockNode* node = IM_NEW(ImGuiDockNode)(id); + ctx->DockContext.Nodes.SetVoidPtr(node->ID, node); + return node; +} + +static void ImGui::DockContextRemoveNode(ImGuiContext* ctx, ImGuiDockNode* node, bool merge_sibling_into_parent_node) +{ + ImGuiContext& g = *ctx; + ImGuiDockContext* dc = &ctx->DockContext; + + IMGUI_DEBUG_LOG_DOCKING("DockContextRemoveNode 0x%08X\n", node->ID); + IM_ASSERT(DockContextFindNodeByID(ctx, node->ID) == node); + IM_ASSERT(node->ChildNodes[0] == NULL && node->ChildNodes[1] == NULL); + IM_ASSERT(node->Windows.Size == 0); + + if (node->HostWindow) + node->HostWindow->DockNodeAsHost = NULL; + + ImGuiDockNode* parent_node = node->ParentNode; + const bool merge = (merge_sibling_into_parent_node && parent_node != NULL); + if (merge) + { + IM_ASSERT(parent_node->ChildNodes[0] == node || parent_node->ChildNodes[1] == node); + ImGuiDockNode* sibling_node = (parent_node->ChildNodes[0] == node ? parent_node->ChildNodes[1] : parent_node->ChildNodes[0]); + DockNodeTreeMerge(&g, parent_node, sibling_node); + } + else + { + for (int n = 0; parent_node && n < IM_ARRAYSIZE(parent_node->ChildNodes); n++) + if (parent_node->ChildNodes[n] == node) + node->ParentNode->ChildNodes[n] = NULL; + dc->Nodes.SetVoidPtr(node->ID, NULL); + IM_DELETE(node); + } +} + +static int IMGUI_CDECL DockNodeComparerDepthMostFirst(const void* lhs, const void* rhs) +{ + const ImGuiDockNode* a = *(const ImGuiDockNode* const*)lhs; + const ImGuiDockNode* b = *(const ImGuiDockNode* const*)rhs; + return ImGui::DockNodeGetDepth(b) - ImGui::DockNodeGetDepth(a); +} + +// Pre C++0x doesn't allow us to use a function-local type (without linkage) as template parameter, so we moved this here. +struct ImGuiDockContextPruneNodeData +{ + int CountWindows, CountChildWindows, CountChildNodes; + ImGuiID RootId; + ImGuiDockContextPruneNodeData() { CountWindows = CountChildWindows = CountChildNodes = 0; RootId = 0; } +}; + +// Garbage collect unused nodes (run once at init time) +static void ImGui::DockContextPruneUnusedSettingsNodes(ImGuiContext* ctx) +{ + ImGuiContext& g = *ctx; + ImGuiDockContext* dc = &ctx->DockContext; + IM_ASSERT(g.Windows.Size == 0); + + ImPool pool; + pool.Reserve(dc->NodesSettings.Size); + + // Count child nodes and compute RootID + for (int settings_n = 0; settings_n < dc->NodesSettings.Size; settings_n++) + { + ImGuiDockNodeSettings* settings = &dc->NodesSettings[settings_n]; + ImGuiDockContextPruneNodeData* parent_data = settings->ParentNodeId ? pool.GetByKey(settings->ParentNodeId) : 0; + pool.GetOrAddByKey(settings->ID)->RootId = parent_data ? parent_data->RootId : settings->ID; + if (settings->ParentNodeId) + pool.GetOrAddByKey(settings->ParentNodeId)->CountChildNodes++; + } + + // Count reference to dock ids from dockspaces + // We track the 'auto-DockNode <- manual-Window <- manual-DockSpace' in order to avoid 'auto-DockNode' being ditched by DockContextPruneUnusedSettingsNodes() + for (int settings_n = 0; settings_n < dc->NodesSettings.Size; settings_n++) + { + ImGuiDockNodeSettings* settings = &dc->NodesSettings[settings_n]; + if (settings->ParentWindowId != 0) + if (ImGuiWindowSettings* window_settings = FindWindowSettings(settings->ParentWindowId)) + if (window_settings->DockId) + if (ImGuiDockContextPruneNodeData* data = pool.GetByKey(window_settings->DockId)) + data->CountChildNodes++; + } + + // Count reference to dock ids from window settings + // We guard against the possibility of an invalid .ini file (RootID may point to a missing node) + for (ImGuiWindowSettings* settings = g.SettingsWindows.begin(); settings != NULL; settings = g.SettingsWindows.next_chunk(settings)) + if (ImGuiID dock_id = settings->DockId) + if (ImGuiDockContextPruneNodeData* data = pool.GetByKey(dock_id)) + { + data->CountWindows++; + if (ImGuiDockContextPruneNodeData* data_root = (data->RootId == dock_id) ? data : pool.GetByKey(data->RootId)) + data_root->CountChildWindows++; + } + + // Prune + for (int settings_n = 0; settings_n < dc->NodesSettings.Size; settings_n++) + { + ImGuiDockNodeSettings* settings = &dc->NodesSettings[settings_n]; + ImGuiDockContextPruneNodeData* data = pool.GetByKey(settings->ID); + if (data->CountWindows > 1) + continue; + ImGuiDockContextPruneNodeData* data_root = (data->RootId == settings->ID) ? data : pool.GetByKey(data->RootId); + + bool remove = false; + remove |= (data->CountWindows == 1 && settings->ParentNodeId == 0 && data->CountChildNodes == 0 && !(settings->Flags & ImGuiDockNodeFlags_CentralNode)); // Floating root node with only 1 window + remove |= (data->CountWindows == 0 && settings->ParentNodeId == 0 && data->CountChildNodes == 0); // Leaf nodes with 0 window + remove |= (data_root->CountChildWindows == 0); + if (remove) + { + IMGUI_DEBUG_LOG_DOCKING("DockContextPruneUnusedSettingsNodes: Prune 0x%08X\n", settings->ID); + DockSettingsRemoveNodeReferences(&settings->ID, 1); + settings->ID = 0; + } + } +} + +static void ImGui::DockContextBuildNodesFromSettings(ImGuiContext* ctx, ImGuiDockNodeSettings* node_settings_array, int node_settings_count) +{ + // Build nodes + for (int node_n = 0; node_n < node_settings_count; node_n++) + { + ImGuiDockNodeSettings* settings = &node_settings_array[node_n]; + if (settings->ID == 0) + continue; + ImGuiDockNode* node = DockContextAddNode(ctx, settings->ID); + node->ParentNode = settings->ParentNodeId ? DockContextFindNodeByID(ctx, settings->ParentNodeId) : NULL; + node->Pos = ImVec2(settings->Pos.x, settings->Pos.y); + node->Size = ImVec2(settings->Size.x, settings->Size.y); + node->SizeRef = ImVec2(settings->SizeRef.x, settings->SizeRef.y); + node->AuthorityForPos = node->AuthorityForSize = node->AuthorityForViewport = ImGuiDataAuthority_DockNode; + if (node->ParentNode && node->ParentNode->ChildNodes[0] == NULL) + node->ParentNode->ChildNodes[0] = node; + else if (node->ParentNode && node->ParentNode->ChildNodes[1] == NULL) + node->ParentNode->ChildNodes[1] = node; + node->SelectedTabId = settings->SelectedWindowId; + node->SplitAxis = (ImGuiAxis)settings->SplitAxis; + node->LocalFlags |= (settings->Flags & ImGuiDockNodeFlags_SavedFlagsMask_); + + // Bind host window immediately if it already exist (in case of a rebuild) + // This is useful as the RootWindowForTitleBarHighlight links necessary to highlight the currently focused node requires node->HostWindow to be set. + char host_window_title[20]; + ImGuiDockNode* root_node = DockNodeGetRootNode(node); + node->HostWindow = FindWindowByName(DockNodeGetHostWindowTitle(root_node, host_window_title, IM_ARRAYSIZE(host_window_title))); + } +} + +void ImGui::DockContextBuildAddWindowsToNodes(ImGuiContext* ctx, ImGuiID root_id) +{ + // Rebind all windows to nodes (they can also lazily rebind but we'll have a visible glitch during the first frame) + ImGuiContext& g = *ctx; + for (int n = 0; n < g.Windows.Size; n++) + { + ImGuiWindow* window = g.Windows[n]; + if (window->DockId == 0 || window->LastFrameActive < g.FrameCount - 1) + continue; + if (window->DockNode != NULL) + continue; + + ImGuiDockNode* node = DockContextFindNodeByID(ctx, window->DockId); + IM_ASSERT(node != NULL); // This should have been called after DockContextBuildNodesFromSettings() + if (root_id == 0 || DockNodeGetRootNode(node)->ID == root_id) + DockNodeAddWindow(node, window, true); + } +} + +//----------------------------------------------------------------------------- +// Docking: ImGuiDockContext Docking/Undocking functions +//----------------------------------------------------------------------------- +// - DockContextQueueDock() +// - DockContextQueueUndockWindow() +// - DockContextQueueUndockNode() +// - DockContextQueueNotifyRemovedNode() +// - DockContextProcessDock() +// - DockContextProcessUndockWindow() +// - DockContextProcessUndockNode() +// - DockContextCalcDropPosForDocking() +//----------------------------------------------------------------------------- + +void ImGui::DockContextQueueDock(ImGuiContext* ctx, ImGuiWindow* target, ImGuiDockNode* target_node, ImGuiWindow* payload, ImGuiDir split_dir, float split_ratio, bool split_outer) +{ + IM_ASSERT(target != payload); + ImGuiDockRequest req; + req.Type = ImGuiDockRequestType_Dock; + req.DockTargetWindow = target; + req.DockTargetNode = target_node; + req.DockPayload = payload; + req.DockSplitDir = split_dir; + req.DockSplitRatio = split_ratio; + req.DockSplitOuter = split_outer; + ctx->DockContext.Requests.push_back(req); +} + +void ImGui::DockContextQueueUndockWindow(ImGuiContext* ctx, ImGuiWindow* window) +{ + ImGuiDockRequest req; + req.Type = ImGuiDockRequestType_Undock; + req.UndockTargetWindow = window; + ctx->DockContext.Requests.push_back(req); +} + +void ImGui::DockContextQueueUndockNode(ImGuiContext* ctx, ImGuiDockNode* node) +{ + ImGuiDockRequest req; + req.Type = ImGuiDockRequestType_Undock; + req.UndockTargetNode = node; + ctx->DockContext.Requests.push_back(req); +} + +void ImGui::DockContextQueueNotifyRemovedNode(ImGuiContext* ctx, ImGuiDockNode* node) +{ + ImGuiDockContext* dc = &ctx->DockContext; + for (int n = 0; n < dc->Requests.Size; n++) + if (dc->Requests[n].DockTargetNode == node) + dc->Requests[n].Type = ImGuiDockRequestType_None; +} + +void ImGui::DockContextProcessDock(ImGuiContext* ctx, ImGuiDockRequest* req) +{ + IM_ASSERT((req->Type == ImGuiDockRequestType_Dock && req->DockPayload != NULL) || (req->Type == ImGuiDockRequestType_Split && req->DockPayload == NULL)); + IM_ASSERT(req->DockTargetWindow != NULL || req->DockTargetNode != NULL); + + ImGuiContext& g = *ctx; + IM_UNUSED(g); + + ImGuiWindow* payload_window = req->DockPayload; // Optional + ImGuiWindow* target_window = req->DockTargetWindow; + ImGuiDockNode* node = req->DockTargetNode; + if (payload_window) + IMGUI_DEBUG_LOG_DOCKING("DockContextProcessDock node 0x%08X target '%s' dock window '%s', split_dir %d\n", node ? node->ID : 0, target_window ? target_window->Name : "NULL", payload_window ? payload_window->Name : "NULL", req->DockSplitDir); + else + IMGUI_DEBUG_LOG_DOCKING("DockContextProcessDock node 0x%08X, split_dir %d\n", node ? node->ID : 0, req->DockSplitDir); + + // Decide which Tab will be selected at the end of the operation + ImGuiID next_selected_id = 0; + ImGuiDockNode* payload_node = NULL; + if (payload_window) + { + payload_node = payload_window->DockNodeAsHost; + payload_window->DockNodeAsHost = NULL; // Important to clear this as the node will have its life as a child which might be merged/deleted later. + if (payload_node && payload_node->IsLeafNode()) + next_selected_id = payload_node->TabBar->NextSelectedTabId ? payload_node->TabBar->NextSelectedTabId : payload_node->TabBar->SelectedTabId; + if (payload_node == NULL) + next_selected_id = payload_window->ID; + } + + // FIXME-DOCK: When we are trying to dock an existing single-window node into a loose window, transfer Node ID as well + // When processing an interactive split, usually LastFrameAlive will be < g.FrameCount. But DockBuilder operations can make it ==. + if (node) + IM_ASSERT(node->LastFrameAlive <= g.FrameCount); + if (node && target_window && node == target_window->DockNodeAsHost) + IM_ASSERT(node->Windows.Size > 0 || node->IsSplitNode() || node->IsCentralNode()); + + // Create new node and add existing window to it + if (node == NULL) + { + node = DockContextAddNode(ctx, 0); + node->Pos = target_window->Pos; + node->Size = target_window->Size; + if (target_window->DockNodeAsHost == NULL) + { + DockNodeAddWindow(node, target_window, true); + node->TabBar->Tabs[0].Flags &= ~ImGuiTabItemFlags_Unsorted; + target_window->DockIsActive = true; + } + } + + ImGuiDir split_dir = req->DockSplitDir; + if (split_dir != ImGuiDir_None) + { + // Split into one, one side will be our payload node unless we are dropping a loose window + const ImGuiAxis split_axis = (split_dir == ImGuiDir_Left || split_dir == ImGuiDir_Right) ? ImGuiAxis_X : ImGuiAxis_Y; + const int split_inheritor_child_idx = (split_dir == ImGuiDir_Left || split_dir == ImGuiDir_Up) ? 1 : 0; // Current contents will be moved to the opposite side + const float split_ratio = req->DockSplitRatio; + DockNodeTreeSplit(ctx, node, split_axis, split_inheritor_child_idx, split_ratio, payload_node); // payload_node may be NULL here! + ImGuiDockNode* new_node = node->ChildNodes[split_inheritor_child_idx ^ 1]; + new_node->HostWindow = node->HostWindow; + node = new_node; + } + node->LocalFlags &= ~ImGuiDockNodeFlags_HiddenTabBar; + + if (node != payload_node) + { + // Create tab bar before we call DockNodeMoveWindows (which would attempt to move the old tab-bar, which would lead us to payload tabs wrongly appearing before target tabs!) + if (node->Windows.Size > 0 && node->TabBar == NULL) + { + DockNodeAddTabBar(node); + for (int n = 0; n < node->Windows.Size; n++) + TabBarAddTab(node->TabBar, ImGuiTabItemFlags_None, node->Windows[n]); + } + + if (payload_node != NULL) + { + // Transfer full payload node (with 1+ child windows or child nodes) + if (payload_node->IsSplitNode()) + { + if (node->Windows.Size > 0) + { + // We can dock a split payload into a node that already has windows _only_ if our payload is a node tree with a single visible node. + // In this situation, we move the windows of the target node into the currently visible node of the payload. + // This allows us to preserve some of the underlying dock tree settings nicely. + IM_ASSERT(payload_node->OnlyNodeWithWindows != NULL); // The docking should have been blocked by DockNodePreviewDockSetup() early on and never submitted. + ImGuiDockNode* visible_node = payload_node->OnlyNodeWithWindows; + if (visible_node->TabBar) + IM_ASSERT(visible_node->TabBar->Tabs.Size > 0); + DockNodeMoveWindows(node, visible_node); + DockNodeMoveWindows(visible_node, node); + DockSettingsRenameNodeReferences(node->ID, visible_node->ID); + } + if (node->IsCentralNode()) + { + // Central node property needs to be moved to a leaf node, pick the last focused one. + // FIXME-DOCK: If we had to transfer other flags here, what would the policy be? + ImGuiDockNode* last_focused_node = DockContextFindNodeByID(ctx, payload_node->LastFocusedNodeId); + IM_ASSERT(last_focused_node != NULL); + ImGuiDockNode* last_focused_root_node = DockNodeGetRootNode(last_focused_node); + IM_ASSERT(last_focused_root_node == DockNodeGetRootNode(payload_node)); + last_focused_node->LocalFlags |= ImGuiDockNodeFlags_CentralNode; + node->LocalFlags &= ~ImGuiDockNodeFlags_CentralNode; + last_focused_root_node->CentralNode = last_focused_node; + } + + IM_ASSERT(node->Windows.Size == 0); + DockNodeMoveChildNodes(node, payload_node); + } + else + { + const ImGuiID payload_dock_id = payload_node->ID; + DockNodeMoveWindows(node, payload_node); + DockSettingsRenameNodeReferences(payload_dock_id, node->ID); + } + DockContextRemoveNode(ctx, payload_node, true); + } + else if (payload_window) + { + // Transfer single window + const ImGuiID payload_dock_id = payload_window->DockId; + node->VisibleWindow = payload_window; + DockNodeAddWindow(node, payload_window, true); + if (payload_dock_id != 0) + DockSettingsRenameNodeReferences(payload_dock_id, node->ID); + } + } + else + { + // When docking a floating single window node we want to reevaluate auto-hiding of the tab bar + node->WantHiddenTabBarUpdate = true; + } + + // Update selection immediately + if (ImGuiTabBar* tab_bar = node->TabBar) + tab_bar->NextSelectedTabId = next_selected_id; + MarkIniSettingsDirty(); +} + +void ImGui::DockContextProcessUndockWindow(ImGuiContext* ctx, ImGuiWindow* window, bool clear_persistent_docking_ref) +{ + IMGUI_DEBUG_LOG_DOCKING("DockContextProcessUndockWindow window '%s', clear_persistent_docking_ref = %d\n", window->Name, clear_persistent_docking_ref); + IM_UNUSED(ctx); + if (window->DockNode) + DockNodeRemoveWindow(window->DockNode, window, clear_persistent_docking_ref ? 0 : window->DockId); + else + window->DockId = 0; + window->Collapsed = false; + window->DockIsActive = false; + window->DockTabIsVisible = false; + MarkIniSettingsDirty(); +} + +void ImGui::DockContextProcessUndockNode(ImGuiContext* ctx, ImGuiDockNode* node) +{ + IMGUI_DEBUG_LOG_DOCKING("DockContextProcessUndockNode node %08X\n", node->ID); + IM_ASSERT(node->IsLeafNode()); + IM_ASSERT(node->Windows.Size >= 1); + + if (node->IsRootNode() || node->IsCentralNode()) + { + // In the case of a root node or central node, the node will have to stay in place. Create a new node to receive the payload. + ImGuiDockNode* new_node = DockContextAddNode(ctx, 0); + DockNodeMoveWindows(new_node, node); + DockSettingsRenameNodeReferences(node->ID, new_node->ID); + for (int n = 0; n < new_node->Windows.Size; n++) + UpdateWindowParentAndRootLinks(new_node->Windows[n], new_node->Windows[n]->Flags, NULL); + node = new_node; + } + else + { + // Otherwise extract our node and merging our sibling back into the parent node. + IM_ASSERT(node->ParentNode->ChildNodes[0] == node || node->ParentNode->ChildNodes[1] == node); + int index_in_parent = (node->ParentNode->ChildNodes[0] == node) ? 0 : 1; + node->ParentNode->ChildNodes[index_in_parent] = NULL; + DockNodeTreeMerge(ctx, node->ParentNode, node->ParentNode->ChildNodes[index_in_parent ^ 1]); + node->ParentNode->AuthorityForViewport = ImGuiDataAuthority_Window; // The node that stays in place keeps the viewport, so our newly dragged out node will create a new viewport + node->ParentNode = NULL; + } + node->AuthorityForPos = node->AuthorityForSize = ImGuiDataAuthority_Window; + node->WantMouseMove = true; + MarkIniSettingsDirty(); +} + +// This is mostly used for automation. +bool ImGui::DockContextCalcDropPosForDocking(ImGuiWindow* target, ImGuiDockNode* target_node, ImGuiWindow* payload, ImGuiDir split_dir, bool split_outer, ImVec2* out_pos) +{ + if (split_outer) + { + IM_ASSERT(0); + } + else + { + ImGuiDockPreviewData split_data; + DockNodePreviewDockSetup(target, target_node, payload, &split_data, false, split_outer); + if (split_data.DropRectsDraw[split_dir+1].IsInverted()) + return false; + *out_pos = split_data.DropRectsDraw[split_dir+1].GetCenter(); + return true; + } + return false; +} + +//----------------------------------------------------------------------------- +// Docking: ImGuiDockNode +//----------------------------------------------------------------------------- +// - DockNodeGetTabOrder() +// - DockNodeAddWindow() +// - DockNodeRemoveWindow() +// - DockNodeMoveChildNodes() +// - DockNodeMoveWindows() +// - DockNodeApplyPosSizeToWindows() +// - DockNodeHideHostWindow() +// - ImGuiDockNodeFindInfoResults +// - DockNodeFindInfo() +// - DockNodeFindWindowByID() +// - DockNodeUpdateVisibleFlagAndInactiveChilds() +// - DockNodeUpdateVisibleFlag() +// - DockNodeStartMouseMovingWindow() +// - DockNodeUpdate() +// - DockNodeUpdateWindowMenu() +// - DockNodeUpdateTabBar() +// - DockNodeAddTabBar() +// - DockNodeRemoveTabBar() +// - DockNodeIsDropAllowedOne() +// - DockNodeIsDropAllowed() +// - DockNodeCalcTabBarLayout() +// - DockNodeCalcSplitRects() +// - DockNodeCalcDropRectsAndTestMousePos() +// - DockNodePreviewDockSetup() +// - DockNodePreviewDockRender() +//----------------------------------------------------------------------------- + +ImGuiDockNode::ImGuiDockNode(ImGuiID id) +{ + ID = id; + SharedFlags = LocalFlags = ImGuiDockNodeFlags_None; + ParentNode = ChildNodes[0] = ChildNodes[1] = NULL; + TabBar = NULL; + SplitAxis = ImGuiAxis_None; + + State = ImGuiDockNodeState_Unknown; + HostWindow = VisibleWindow = NULL; + CentralNode = OnlyNodeWithWindows = NULL; + LastFrameAlive = LastFrameActive = LastFrameFocused = -1; + LastFocusedNodeId = 0; + SelectedTabId = 0; + WantCloseTabId = 0; + AuthorityForPos = AuthorityForSize = ImGuiDataAuthority_DockNode; + AuthorityForViewport = ImGuiDataAuthority_Auto; + IsVisible = true; + IsFocused = HasCloseButton = HasWindowMenuButton = EnableCloseButton = false; + WantCloseAll = WantLockSizeOnce = WantMouseMove = WantHiddenTabBarUpdate = WantHiddenTabBarToggle = false; + MarkedForPosSizeWrite = false; +} + +ImGuiDockNode::~ImGuiDockNode() +{ + IM_DELETE(TabBar); + TabBar = NULL; + ChildNodes[0] = ChildNodes[1] = NULL; +} + +int ImGui::DockNodeGetTabOrder(ImGuiWindow* window) +{ + ImGuiTabBar* tab_bar = window->DockNode->TabBar; + if (tab_bar == NULL) + return -1; + ImGuiTabItem* tab = TabBarFindTabByID(tab_bar, window->ID); + return tab ? tab_bar->GetTabOrder(tab) : -1; +} + +static void ImGui::DockNodeAddWindow(ImGuiDockNode* node, ImGuiWindow* window, bool add_to_tab_bar) +{ + ImGuiContext& g = *GImGui; (void)g; + if (window->DockNode) + { + // Can overwrite an existing window->DockNode (e.g. pointing to a disabled DockSpace node) + IM_ASSERT(window->DockNode->ID != node->ID); + DockNodeRemoveWindow(window->DockNode, window, 0); + } + IM_ASSERT(window->DockNode == NULL || window->DockNodeAsHost == NULL); + IMGUI_DEBUG_LOG_DOCKING("DockNodeAddWindow node 0x%08X window '%s'\n", node->ID, window->Name); + + node->Windows.push_back(window); + node->WantHiddenTabBarUpdate = true; + window->DockNode = node; + window->DockId = node->ID; + window->DockIsActive = (node->Windows.Size > 1); + window->DockTabWantClose = false; + + // If more than 2 windows appeared on the same frame, we'll create a new hosting DockNode from the point of the second window submission. + // Then we need to hide the first window (after its been output) otherwise it would be visible as a standalone window for one frame. + if (node->HostWindow == NULL && node->Windows.Size == 2 && node->Windows[0]->WasActive == false) + { + node->Windows[0]->Hidden = true; + node->Windows[0]->HiddenFramesCanSkipItems = 1; + } + + // When reactivating a node with one or two loose window, the window pos/size/viewport are authoritative over the node storage. + // In particular it is important we init the viewport from the first window so we don't create two viewports and drop one. + if (node->HostWindow == NULL && node->IsFloatingNode()) + { + if (node->AuthorityForPos == ImGuiDataAuthority_Auto) + node->AuthorityForPos = ImGuiDataAuthority_Window; + if (node->AuthorityForSize == ImGuiDataAuthority_Auto) + node->AuthorityForSize = ImGuiDataAuthority_Window; + if (node->AuthorityForViewport == ImGuiDataAuthority_Auto) + node->AuthorityForViewport = ImGuiDataAuthority_Window; + } + + // Add to tab bar if requested + if (add_to_tab_bar) + { + if (node->TabBar == NULL) + { + DockNodeAddTabBar(node); + node->TabBar->SelectedTabId = node->TabBar->NextSelectedTabId = node->SelectedTabId; + + // Add existing windows + for (int n = 0; n < node->Windows.Size - 1; n++) + TabBarAddTab(node->TabBar, ImGuiTabItemFlags_None, node->Windows[n]); + } + TabBarAddTab(node->TabBar, ImGuiTabItemFlags_Unsorted, window); + } + + DockNodeUpdateVisibleFlag(node); + + // Update this without waiting for the next time we Begin() in the window, so our host window will have the proper title bar color on its first frame. + if (node->HostWindow) + UpdateWindowParentAndRootLinks(window, window->Flags | ImGuiWindowFlags_ChildWindow, node->HostWindow); +} + +static void ImGui::DockNodeRemoveWindow(ImGuiDockNode* node, ImGuiWindow* window, ImGuiID save_dock_id) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(window->DockNode == node); + //IM_ASSERT(window->RootWindow == node->HostWindow); + //IM_ASSERT(window->LastFrameActive < g.FrameCount); // We may call this from Begin() + IM_ASSERT(save_dock_id == 0 || save_dock_id == node->ID); + IMGUI_DEBUG_LOG_DOCKING("DockNodeRemoveWindow node 0x%08X window '%s'\n", node->ID, window->Name); + + window->DockNode = NULL; + window->DockIsActive = window->DockTabWantClose = false; + window->DockId = save_dock_id; + UpdateWindowParentAndRootLinks(window, window->Flags & ~ImGuiWindowFlags_ChildWindow, NULL); // Update immediately + + // Remove window + bool erased = false; + for (int n = 0; n < node->Windows.Size; n++) + if (node->Windows[n] == window) + { + node->Windows.erase(node->Windows.Data + n); + erased = true; + break; + } + IM_ASSERT(erased); + if (node->VisibleWindow == window) + node->VisibleWindow = NULL; + + // Remove tab and possibly tab bar + node->WantHiddenTabBarUpdate = true; + if (node->TabBar) + { + TabBarRemoveTab(node->TabBar, window->ID); + const int tab_count_threshold_for_tab_bar = node->IsCentralNode() ? 1 : 2; + if (node->Windows.Size < tab_count_threshold_for_tab_bar) + DockNodeRemoveTabBar(node); + } + + if (node->Windows.Size == 0 && !node->IsCentralNode() && !node->IsDockSpace() && window->DockId != node->ID) + { + // Automatic dock node delete themselves if they are not holding at least one tab + DockContextRemoveNode(&g, node, true); + return; + } + + if (node->Windows.Size == 1 && !node->IsCentralNode() && node->HostWindow) + { + ImGuiWindow* remaining_window = node->Windows[0]; + if (node->HostWindow->ViewportOwned && node->IsRootNode()) + { + // Transfer viewport back to the remaining loose window + IM_ASSERT(node->HostWindow->Viewport->Window == node->HostWindow); + node->HostWindow->Viewport->Window = remaining_window; + node->HostWindow->Viewport->ID = remaining_window->ID; + } + remaining_window->Collapsed = node->HostWindow->Collapsed; + } + + // Update visibility immediately is required so the DockNodeUpdateRemoveInactiveChilds() processing can reflect changes up the tree + DockNodeUpdateVisibleFlag(node); +} + +static void ImGui::DockNodeMoveChildNodes(ImGuiDockNode* dst_node, ImGuiDockNode* src_node) +{ + IM_ASSERT(dst_node->Windows.Size == 0); + dst_node->ChildNodes[0] = src_node->ChildNodes[0]; + dst_node->ChildNodes[1] = src_node->ChildNodes[1]; + if (dst_node->ChildNodes[0]) + dst_node->ChildNodes[0]->ParentNode = dst_node; + if (dst_node->ChildNodes[1]) + dst_node->ChildNodes[1]->ParentNode = dst_node; + dst_node->SplitAxis = src_node->SplitAxis; + dst_node->SizeRef = src_node->SizeRef; + src_node->ChildNodes[0] = src_node->ChildNodes[1] = NULL; +} + +static void ImGui::DockNodeMoveWindows(ImGuiDockNode* dst_node, ImGuiDockNode* src_node) +{ + // Insert tabs in the same orders as currently ordered (node->Windows isn't ordered) + IM_ASSERT(src_node && dst_node && dst_node != src_node); + ImGuiTabBar* src_tab_bar = src_node->TabBar; + if (src_tab_bar != NULL) + IM_ASSERT(src_node->Windows.Size == src_node->TabBar->Tabs.Size); + + // If the dst_node is empty we can just move the entire tab bar (to preserve selection, scrolling, etc.) + bool move_tab_bar = (src_tab_bar != NULL) && (dst_node->TabBar == NULL); + if (move_tab_bar) + { + dst_node->TabBar = src_node->TabBar; + src_node->TabBar = NULL; + } + + for (int n = 0; n < src_node->Windows.Size; n++) + { + ImGuiWindow* window = src_tab_bar ? src_tab_bar->Tabs[n].Window : src_node->Windows[n]; + window->DockNode = NULL; + window->DockIsActive = false; + DockNodeAddWindow(dst_node, window, move_tab_bar ? false : true); + } + src_node->Windows.clear(); + + if (!move_tab_bar && src_node->TabBar) + { + if (dst_node->TabBar) + dst_node->TabBar->SelectedTabId = src_node->TabBar->SelectedTabId; + DockNodeRemoveTabBar(src_node); + } +} + +static void ImGui::DockNodeApplyPosSizeToWindows(ImGuiDockNode* node) +{ + for (int n = 0; n < node->Windows.Size; n++) + { + SetWindowPos(node->Windows[n], node->Pos, ImGuiCond_Always); // We don't assign directly to Pos because it can break the calculation of SizeContents on next frame + SetWindowSize(node->Windows[n], node->Size, ImGuiCond_Always); + } +} + +static void ImGui::DockNodeHideHostWindow(ImGuiDockNode* node) +{ + if (node->HostWindow) + { + if (node->HostWindow->DockNodeAsHost == node) + node->HostWindow->DockNodeAsHost = NULL; + node->HostWindow = NULL; + } + + if (node->Windows.Size == 1) + { + node->VisibleWindow = node->Windows[0]; + node->Windows[0]->DockIsActive = false; + } + + if (node->TabBar) + DockNodeRemoveTabBar(node); +} + +// Search function called once by root node in DockNodeUpdate() +struct ImGuiDockNodeFindInfoResults +{ + ImGuiDockNode* CentralNode; + ImGuiDockNode* FirstNodeWithWindows; + int CountNodesWithWindows; + //ImGuiWindowClass WindowClassForMerges; + + ImGuiDockNodeFindInfoResults() { CentralNode = FirstNodeWithWindows = NULL; CountNodesWithWindows = 0; } +}; + +static void DockNodeFindInfo(ImGuiDockNode* node, ImGuiDockNodeFindInfoResults* results) +{ + if (node->Windows.Size > 0) + { + if (results->FirstNodeWithWindows == NULL) + results->FirstNodeWithWindows = node; + results->CountNodesWithWindows++; + } + if (node->IsCentralNode()) + { + IM_ASSERT(results->CentralNode == NULL); // Should be only one + IM_ASSERT(node->IsLeafNode() && "If you get this assert: please submit .ini file + repro of actions leading to this."); + results->CentralNode = node; + } + if (results->CountNodesWithWindows > 1 && results->CentralNode != NULL) + return; + if (node->ChildNodes[0]) + DockNodeFindInfo(node->ChildNodes[0], results); + if (node->ChildNodes[1]) + DockNodeFindInfo(node->ChildNodes[1], results); +} + +static ImGuiWindow* ImGui::DockNodeFindWindowByID(ImGuiDockNode* node, ImGuiID id) +{ + IM_ASSERT(id != 0); + for (int n = 0; n < node->Windows.Size; n++) + if (node->Windows[n]->ID == id) + return node->Windows[n]; + return NULL; +} + +// - Remove inactive windows/nodes. +// - Update visibility flag. +static void ImGui::DockNodeUpdateVisibleFlagAndInactiveChilds(ImGuiDockNode* node) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(node->ParentNode == NULL || node->ParentNode->ChildNodes[0] == node || node->ParentNode->ChildNodes[1] == node); + + // Inherit most flags + if (node->ParentNode) + node->SharedFlags = node->ParentNode->SharedFlags & ImGuiDockNodeFlags_SharedFlagsInheritMask_; + + // Recurse into children + // There is the possibility that one of our child becoming empty will delete itself and moving its sibling contents into 'node'. + // If 'node->ChildNode[0]' delete itself, then 'node->ChildNode[1]->Windows' will be moved into 'node' + // If 'node->ChildNode[1]' delete itself, then 'node->ChildNode[0]->Windows' will be moved into 'node' and the "remove inactive windows" loop will have run twice on those windows (harmless) + if (node->ChildNodes[0]) + DockNodeUpdateVisibleFlagAndInactiveChilds(node->ChildNodes[0]); + if (node->ChildNodes[1]) + DockNodeUpdateVisibleFlagAndInactiveChilds(node->ChildNodes[1]); + + // Remove inactive windows + // Merge node flags overrides stored in windows + for (int window_n = 0; window_n < node->Windows.Size; window_n++) + { + ImGuiWindow* window = node->Windows[window_n]; + IM_ASSERT(window->DockNode == node); + + bool node_was_active = (node->LastFrameActive + 1 == g.FrameCount); + bool remove = false; + remove |= node_was_active && (window->LastFrameActive + 1 < g.FrameCount); + remove |= node_was_active && (node->WantCloseAll || node->WantCloseTabId == window->ID) && window->HasCloseButton && !(window->Flags & ImGuiWindowFlags_UnsavedDocument); // Submit all _expected_ closure from last frame + remove |= (window->DockTabWantClose); + if (remove) + { + window->DockTabWantClose = false; + if (node->Windows.Size == 1 && !node->IsCentralNode()) + { + DockNodeHideHostWindow(node); + node->State = ImGuiDockNodeState_HostWindowHiddenBecauseSingleWindow; + DockNodeRemoveWindow(node, window, node->ID); // Will delete the node so it'll be invalid on return + return; + } + DockNodeRemoveWindow(node, window, node->ID); + window_n--; + } + else + { + node->LocalFlags &= ~window->WindowClass.DockNodeFlagsOverrideClear; + node->LocalFlags |= window->WindowClass.DockNodeFlagsOverrideSet; + } + } + + // Auto-hide tab bar option + ImGuiDockNodeFlags node_flags = node->GetMergedFlags(); + if (node->WantHiddenTabBarUpdate && node->Windows.Size == 1 && (node_flags & ImGuiDockNodeFlags_AutoHideTabBar) && !node->IsHiddenTabBar()) + node->WantHiddenTabBarToggle = true; + node->WantHiddenTabBarUpdate = false; + + // Cancel toggling if we know our tab bar is enforced to be hidden at all times + if (node->WantHiddenTabBarToggle && node->VisibleWindow && (node->VisibleWindow->WindowClass.DockNodeFlagsOverrideSet & ImGuiDockNodeFlags_HiddenTabBar)) + node->WantHiddenTabBarToggle = false; + + // Apply toggles at a single point of the frame (here!) + if (node->Windows.Size > 1) + node->LocalFlags &= ~ImGuiDockNodeFlags_HiddenTabBar; + else if (node->WantHiddenTabBarToggle) + node->LocalFlags ^= ImGuiDockNodeFlags_HiddenTabBar; + node->WantHiddenTabBarToggle = false; + + DockNodeUpdateVisibleFlag(node); +} + +static void ImGui::DockNodeUpdateVisibleFlag(ImGuiDockNode* node) +{ + // Update visibility flag + bool is_visible = (node->ParentNode == NULL) ? node->IsDockSpace() : node->IsCentralNode(); + is_visible |= (node->Windows.Size > 0); + is_visible |= (node->ChildNodes[0] && node->ChildNodes[0]->IsVisible); + is_visible |= (node->ChildNodes[1] && node->ChildNodes[1]->IsVisible); + node->IsVisible = is_visible; +} + +static void ImGui::DockNodeStartMouseMovingWindow(ImGuiDockNode* node, ImGuiWindow* window) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(node->WantMouseMove == true); + ImVec2 backup_active_click_offset = g.ActiveIdClickOffset; + StartMouseMovingWindow(window); + g.MovingWindow = window; // If we are docked into a non moveable root window, StartMouseMovingWindow() won't set g.MovingWindow. Override that decision. + node->WantMouseMove = false; + g.ActiveIdClickOffset = backup_active_click_offset; +} + +// Update CentralNode, OnlyNodeWithWindows, LastFocusedNodeID. Copy window class. +static void ImGui::DockNodeUpdateForRootNode(ImGuiDockNode* node) +{ + DockNodeUpdateVisibleFlagAndInactiveChilds(node); + + // FIXME-DOCK: Merge this scan into the one above. + // - Setup central node pointers + // - Find if there's only a single visible window in the hierarchy (in which case we need to display a regular title bar -> FIXME-DOCK: that last part is not done yet!) + ImGuiDockNodeFindInfoResults results; + DockNodeFindInfo(node, &results); + node->CentralNode = results.CentralNode; + node->OnlyNodeWithWindows = (results.CountNodesWithWindows == 1) ? results.FirstNodeWithWindows : NULL; + if (node->LastFocusedNodeId == 0 && results.FirstNodeWithWindows != NULL) + node->LastFocusedNodeId = results.FirstNodeWithWindows->ID; + + // Copy the window class from of our first window so it can be used for proper dock filtering. + // When node has mixed windows, prioritize the class with the most constraint (DockingAllowUnclassed = false) as the reference to copy. + // FIXME-DOCK: We don't recurse properly, this code could be reworked to work from DockNodeUpdateScanRec. + if (ImGuiDockNode* first_node_with_windows = results.FirstNodeWithWindows) + { + node->WindowClass = first_node_with_windows->Windows[0]->WindowClass; + for (int n = 1; n < first_node_with_windows->Windows.Size; n++) + if (first_node_with_windows->Windows[n]->WindowClass.DockingAllowUnclassed == false) + { + node->WindowClass = first_node_with_windows->Windows[n]->WindowClass; + break; + } + } +} + +static void ImGui::DockNodeUpdate(ImGuiDockNode* node) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(node->LastFrameActive != g.FrameCount); + node->LastFrameAlive = g.FrameCount; + node->MarkedForPosSizeWrite = false; + + node->CentralNode = node->OnlyNodeWithWindows = NULL; + if (node->IsRootNode()) + DockNodeUpdateForRootNode(node); + + // Remove tab bar if not needed + if (node->TabBar && node->IsNoTabBar()) + DockNodeRemoveTabBar(node); + + // Early out for hidden root dock nodes (when all DockId references are in inactive windows, or there is only 1 floating window holding on the DockId) + bool want_to_hide_host_window = false; + if (node->Windows.Size <= 1 && node->IsFloatingNode() && node->IsLeafNode()) + if (!g.IO.ConfigDockingAlwaysTabBar && (node->Windows.Size == 0 || !node->Windows[0]->WindowClass.DockingAlwaysTabBar)) + want_to_hide_host_window = true; + if (want_to_hide_host_window) + { + if (node->Windows.Size == 1) + { + // Floating window pos/size is authoritative + ImGuiWindow* single_window = node->Windows[0]; + node->Pos = single_window->Pos; + node->Size = single_window->SizeFull; + node->AuthorityForPos = node->AuthorityForSize = node->AuthorityForViewport = ImGuiDataAuthority_Window; + + // Transfer focus immediately so when we revert to a regular window it is immediately selected + if (node->HostWindow && g.NavWindow == node->HostWindow) + FocusWindow(single_window); + if (node->HostWindow) + { + single_window->Viewport = node->HostWindow->Viewport; + single_window->ViewportId = node->HostWindow->ViewportId; + if (node->HostWindow->ViewportOwned) + { + single_window->Viewport->Window = single_window; + single_window->ViewportOwned = true; + } + } + } + + DockNodeHideHostWindow(node); + node->State = ImGuiDockNodeState_HostWindowHiddenBecauseSingleWindow; + node->WantCloseAll = false; + node->WantCloseTabId = 0; + node->HasCloseButton = node->HasWindowMenuButton = node->EnableCloseButton = false; + node->LastFrameActive = g.FrameCount; + + if (node->WantMouseMove && node->Windows.Size == 1) + DockNodeStartMouseMovingWindow(node, node->Windows[0]); + return; + } + + // In some circumstance we will defer creating the host window (so everything will be kept hidden), + // while the expected visible window is resizing itself. + // This is important for first-time (no ini settings restored) single window when io.ConfigDockingAlwaysTabBar is enabled, + // otherwise the node ends up using the minimum window size. Effectively those windows will take an extra frame to show up: + // N+0: Begin(): window created (with no known size), node is created + // N+1: DockNodeUpdate(): node skip creating host window / Begin(): window size applied, not visible + // N+2: DockNodeUpdate(): node can create host window / Begin(): window becomes visible + // We could remove this frame if we could reliably calculate the expected window size during node update, before the Begin() code. + // It would require a generalization of CalcWindowExpectedSize(), probably extracting code away from Begin(). + // In reality it isn't very important as user quickly ends up with size data in .ini file. + if (node->IsVisible && node->HostWindow == NULL && node->IsFloatingNode() && node->IsLeafNode()) + { + IM_ASSERT(node->Windows.Size > 0); + ImGuiWindow* ref_window = NULL; + if (node->SelectedTabId != 0) // Note that we prune single-window-node settings on .ini loading, so this is generally 0 for them! + ref_window = DockNodeFindWindowByID(node, node->SelectedTabId); + if (ref_window == NULL) + ref_window = node->Windows[0]; + if (ref_window->AutoFitFramesX > 0 || ref_window->AutoFitFramesY > 0) + { + node->State = ImGuiDockNodeState_HostWindowHiddenBecauseWindowsAreResizing; + return; + } + } + + const ImGuiDockNodeFlags node_flags = node->GetMergedFlags(); + + // Bind or create host window + ImGuiWindow* host_window = NULL; + bool beginned_into_host_window = false; + if (node->IsDockSpace()) + { + // [Explicit root dockspace node] + IM_ASSERT(node->HostWindow); + node->EnableCloseButton = false; + node->HasCloseButton = (node_flags & ImGuiDockNodeFlags_NoCloseButton) == 0; + node->HasWindowMenuButton = (node_flags & ImGuiDockNodeFlags_NoWindowMenuButton) == 0; + host_window = node->HostWindow; + } + else + { + // [Automatic root or child nodes] + node->EnableCloseButton = false; + node->HasCloseButton = (node->Windows.Size > 0) && (node_flags & ImGuiDockNodeFlags_NoCloseButton) == 0; + node->HasWindowMenuButton = (node->Windows.Size > 0) && (node_flags & ImGuiDockNodeFlags_NoWindowMenuButton) == 0; + for (int window_n = 0; window_n < node->Windows.Size; window_n++) + { + // FIXME-DOCK: Setting DockIsActive here means that for single active window in a leaf node, DockIsActive will be cleared until the next Begin() call. + ImGuiWindow* window = node->Windows[window_n]; + window->DockIsActive = (node->Windows.Size > 1); + node->EnableCloseButton |= window->HasCloseButton; + } + + if (node->IsRootNode() && node->IsVisible) + { + ImGuiWindow* ref_window = (node->Windows.Size > 0) ? node->Windows[0] : NULL; + + // Sync Pos + if (node->AuthorityForPos == ImGuiDataAuthority_Window && ref_window) + SetNextWindowPos(ref_window->Pos); + else if (node->AuthorityForPos == ImGuiDataAuthority_DockNode) + SetNextWindowPos(node->Pos); + + // Sync Size + if (node->AuthorityForSize == ImGuiDataAuthority_Window && ref_window) + SetNextWindowSize(ref_window->SizeFull); + else if (node->AuthorityForSize == ImGuiDataAuthority_DockNode) + SetNextWindowSize(node->Size); + + // Sync Collapsed + if (node->AuthorityForSize == ImGuiDataAuthority_Window && ref_window) + SetNextWindowCollapsed(ref_window->Collapsed); + + // Sync Viewport + if (node->AuthorityForViewport == ImGuiDataAuthority_Window && ref_window) + SetNextWindowViewport(ref_window->ViewportId); + + SetNextWindowClass(&node->WindowClass); + + // Begin into the host window + char window_label[20]; + DockNodeGetHostWindowTitle(node, window_label, IM_ARRAYSIZE(window_label)); + ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse | ImGuiWindowFlags_DockNodeHost; + window_flags |= ImGuiWindowFlags_NoFocusOnAppearing; + window_flags |= ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoNavFocus | ImGuiWindowFlags_NoCollapse; + window_flags |= ImGuiWindowFlags_NoTitleBar; + + PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0)); + Begin(window_label, NULL, window_flags); + PopStyleVar(); + beginned_into_host_window = true; + + node->HostWindow = host_window = g.CurrentWindow; + host_window->DockNodeAsHost = node; + host_window->DC.CursorPos = host_window->Pos; + node->Pos = host_window->Pos; + node->Size = host_window->Size; + + // We set ImGuiWindowFlags_NoFocusOnAppearing because we don't want the host window to take full focus (e.g. steal NavWindow) + // But we still it bring it to the front of display. There's no way to choose this precise behavior via window flags. + // One simple case to ponder if: window A has a toggle to create windows B/C/D. Dock B/C/D together, clear the toggle and enable it again. + // When reappearing B/C/D will request focus and be moved to the top of the display pile, but they are not linked to the dock host window + // during the frame they appear. The dock host window would keep its old display order, and the sorting in EndFrame would move B/C/D back + // after the dock host window, losing their top-most status. + if (node->HostWindow->Appearing) + BringWindowToDisplayFront(node->HostWindow); + + node->AuthorityForPos = node->AuthorityForSize = node->AuthorityForViewport = ImGuiDataAuthority_Auto; + } + else if (node->ParentNode) + { + node->HostWindow = host_window = node->ParentNode->HostWindow; + node->AuthorityForPos = node->AuthorityForSize = node->AuthorityForViewport = ImGuiDataAuthority_Auto; + } + if (node->WantMouseMove && node->HostWindow) + DockNodeStartMouseMovingWindow(node, node->HostWindow); + } + + // Update focused node (the one whose title bar is highlight) within a node tree + if (node->IsSplitNode()) + IM_ASSERT(node->TabBar == NULL); + if (node->IsRootNode()) + if (g.NavWindow && g.NavWindow->RootWindowDockStop->DockNode && g.NavWindow->RootWindowDockStop->ParentWindow == host_window) + node->LastFocusedNodeId = g.NavWindow->RootWindowDockStop->DockNode->ID; + + // We need to draw a background at the root level if requested by ImGuiDockNodeFlags_PassthruCentralNode, but we will only know the correct pos/size after + // processing the resizing splitters. So we are using the DrawList channel splitting facility to submit drawing primitives out of order! + const bool render_dockspace_bg = node->IsRootNode() && host_window && (node_flags & ImGuiDockNodeFlags_PassthruCentralNode) != 0; + if (render_dockspace_bg) + { + host_window->DrawList->ChannelsSplit(2); + host_window->DrawList->ChannelsSetCurrent(1); + } + + // Register a hit-test hole in the window unless we are currently dragging a window that is compatible with our dockspace + const ImGuiDockNode* central_node = node->CentralNode; + const bool central_node_hole = node->IsRootNode() && host_window && (node_flags & ImGuiDockNodeFlags_PassthruCentralNode) != 0 && central_node != NULL && central_node->IsEmpty(); + bool central_node_hole_register_hit_test_hole = central_node_hole; + if (central_node_hole) + if (const ImGuiPayload* payload = ImGui::GetDragDropPayload()) + if (payload->IsDataType(IMGUI_PAYLOAD_TYPE_WINDOW) && DockNodeIsDropAllowed(host_window, *(ImGuiWindow**)payload->Data)) + central_node_hole_register_hit_test_hole = false; + if (central_node_hole_register_hit_test_hole) + { + // Add a little padding to match the "resize from edges" behavior and allow grabbing the splitter easily. + IM_ASSERT(node->IsDockSpace()); // We cannot pass this flag without the DockSpace() api. Testing this because we also setup the hole in host_window->ParentNode + ImRect central_hole(central_node->Pos, central_node->Pos + central_node->Size); + central_hole.Expand(ImVec2(-WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS, -WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS)); + if (central_node_hole && !central_hole.IsInverted()) + { + SetWindowHitTestHole(host_window, central_hole.Min, central_hole.Max - central_hole.Min); + SetWindowHitTestHole(host_window->ParentWindow, central_hole.Min, central_hole.Max - central_hole.Min); + } + } + + // Update position/size, process and draw resizing splitters + if (node->IsRootNode() && host_window) + { + DockNodeTreeUpdatePosSize(node, host_window->Pos, host_window->Size); + DockNodeTreeUpdateSplitter(node); + } + + // Draw empty node background (currently can only be the Central Node) + if (host_window && node->IsEmpty() && node->IsVisible && !(node_flags & ImGuiDockNodeFlags_PassthruCentralNode)) + host_window->DrawList->AddRectFilled(node->Pos, node->Pos + node->Size, GetColorU32(ImGuiCol_DockingEmptyBg)); + + // Draw whole dockspace background if ImGuiDockNodeFlags_PassthruCentralNode if set. + if (render_dockspace_bg && node->IsVisible) + { + host_window->DrawList->ChannelsSetCurrent(0); + if (central_node_hole) + RenderRectFilledWithHole(host_window->DrawList, node->Rect(), central_node->Rect(), GetColorU32(ImGuiCol_WindowBg), 0.0f); + else + host_window->DrawList->AddRectFilled(node->Pos, node->Pos + node->Size, GetColorU32(ImGuiCol_WindowBg), 0.0f); + host_window->DrawList->ChannelsMerge(); + } + + // Draw and populate Tab Bar + if (host_window && node->Windows.Size > 0) + { + DockNodeUpdateTabBar(node, host_window); + } + else + { + node->WantCloseAll = false; + node->WantCloseTabId = 0; + node->IsFocused = false; + } + if (node->TabBar && node->TabBar->SelectedTabId) + node->SelectedTabId = node->TabBar->SelectedTabId; + else if (node->Windows.Size > 0) + node->SelectedTabId = node->Windows[0]->ID; + + // Draw payload drop target + if (host_window && node->IsVisible) + if (node->IsRootNode() && (g.MovingWindow == NULL || g.MovingWindow->RootWindow != host_window)) + BeginDockableDragDropTarget(host_window); + + // We update this after DockNodeUpdateTabBar() + node->LastFrameActive = g.FrameCount; + + // Recurse into children + // FIXME-DOCK FIXME-OPT: Should not need to recurse into children + if (host_window) + { + if (node->ChildNodes[0]) + DockNodeUpdate(node->ChildNodes[0]); + if (node->ChildNodes[1]) + DockNodeUpdate(node->ChildNodes[1]); + + // Render outer borders last (after the tab bar) + if (node->IsRootNode()) + RenderWindowOuterBorders(host_window); + } + + // End host window + if (beginned_into_host_window) //-V1020 + End(); +} + +// Compare TabItem nodes given the last known DockOrder (will persist in .ini file as hint), used to sort tabs when multiple tabs are added on the same frame. +static int IMGUI_CDECL TabItemComparerByDockOrder(const void* lhs, const void* rhs) +{ + ImGuiWindow* a = ((const ImGuiTabItem*)lhs)->Window; + ImGuiWindow* b = ((const ImGuiTabItem*)rhs)->Window; + if (int d = ((a->DockOrder == -1) ? INT_MAX : a->DockOrder) - ((b->DockOrder == -1) ? INT_MAX : b->DockOrder)) + return d; + return (a->BeginOrderWithinContext - b->BeginOrderWithinContext); +} + +static ImGuiID ImGui::DockNodeUpdateWindowMenu(ImGuiDockNode* node, ImGuiTabBar* tab_bar) +{ + // Try to position the menu so it is more likely to stays within the same viewport + ImGuiContext& g = *GImGui; + ImGuiID ret_tab_id = 0; + if (g.Style.WindowMenuButtonPosition == ImGuiDir_Left) + SetNextWindowPos(ImVec2(node->Pos.x, node->Pos.y + GetFrameHeight()), ImGuiCond_Always, ImVec2(0.0f, 0.0f)); + else + SetNextWindowPos(ImVec2(node->Pos.x + node->Size.x, node->Pos.y + GetFrameHeight()), ImGuiCond_Always, ImVec2(1.0f, 0.0f)); + if (BeginPopup("#WindowMenu")) + { + node->IsFocused = true; + if (tab_bar->Tabs.Size == 1) + { + if (MenuItem("Hide tab bar", NULL, node->IsHiddenTabBar())) + node->WantHiddenTabBarToggle = true; + } + else + { + for (int tab_n = 0; tab_n < tab_bar->Tabs.Size; tab_n++) + { + ImGuiTabItem* tab = &tab_bar->Tabs[tab_n]; + IM_ASSERT(tab->Window != NULL); + if (Selectable(tab->Window->Name, tab->ID == tab_bar->SelectedTabId)) + ret_tab_id = tab->ID; + SameLine(); + Text(" "); + } + } + EndPopup(); + } + return ret_tab_id; +} + +static void ImGui::DockNodeUpdateTabBar(ImGuiDockNode* node, ImGuiWindow* host_window) +{ + ImGuiContext& g = *GImGui; + ImGuiStyle& style = g.Style; + + const bool node_was_active = (node->LastFrameActive + 1 == g.FrameCount); + const bool closed_all = node->WantCloseAll && node_was_active; + const ImGuiID closed_one = node->WantCloseTabId && node_was_active; + node->WantCloseAll = false; + node->WantCloseTabId = 0; + + // Decide if we should use a focused title bar color + bool is_focused = false; + ImGuiDockNode* root_node = DockNodeGetRootNode(node); + if (g.NavWindowingTarget) + is_focused = (g.NavWindowingTarget->DockNode == node); + else if (g.NavWindow && g.NavWindow->RootWindowForTitleBarHighlight == host_window->RootWindow && root_node->LastFocusedNodeId == node->ID) + is_focused = true; + + // Hidden tab bar will show a triangle on the upper-left (in Begin) + if (node->IsHiddenTabBar() || node->IsNoTabBar()) + { + node->VisibleWindow = (node->Windows.Size > 0) ? node->Windows[0] : NULL; + node->IsFocused = is_focused; + if (is_focused) + node->LastFrameFocused = g.FrameCount; + if (node->VisibleWindow) + { + // Notify root of visible window (used to display title in OS task bar) + if (is_focused || root_node->VisibleWindow == NULL) + root_node->VisibleWindow = node->VisibleWindow; + if (node->TabBar) + node->TabBar->VisibleTabId = node->VisibleWindow->ID; + } + return; + } + + // Move ourselves to the Menu layer (so we can be accessed by tapping Alt) + undo SkipItems flag in order to draw over the title bar even if the window is collapsed + bool backup_skip_item = host_window->SkipItems; + if (!node->IsDockSpace()) + { + host_window->SkipItems = false; + host_window->DC.NavLayerCurrent = ImGuiNavLayer_Menu; + host_window->DC.NavLayerCurrentMask = (1 << ImGuiNavLayer_Menu); + } + + // Use PushOverrideID() instead of PushID() to use the node id _without_ the host window ID. + // This is to facilitate computing those ID from the outside, and will affect more or less only the ID of the collapse button, popup and tabs, + // as docked windows themselves will override the stack with their own root ID. + PushOverrideID(node->ID); + ImGuiTabBar* tab_bar = node->TabBar; + bool tab_bar_is_recreated = (tab_bar == NULL); // Tab bar are automatically destroyed when a node gets hidden + if (tab_bar == NULL) + { + DockNodeAddTabBar(node); + tab_bar = node->TabBar; + } + + ImGuiID focus_tab_id = 0; + node->IsFocused = is_focused; + + const ImGuiDockNodeFlags node_flags = node->GetMergedFlags(); + const bool has_window_menu_button = (node_flags & ImGuiDockNodeFlags_NoWindowMenuButton) == 0; + const bool has_close_button = (node_flags & ImGuiDockNodeFlags_NoCloseButton) == 0; + + // In a dock node, the Collapse Button turns into the Window Menu button. + // FIXME-DOCK FIXME-OPT: Could we recycle popups id across multiple dock nodes? + if (has_window_menu_button && IsPopupOpen("#WindowMenu")) + { + if (ImGuiID tab_id = DockNodeUpdateWindowMenu(node, tab_bar)) + focus_tab_id = tab_bar->NextSelectedTabId = tab_id; + is_focused |= node->IsFocused; + } + + // Layout + ImRect title_bar_rect, tab_bar_rect; + ImVec2 window_menu_button_pos; + DockNodeCalcTabBarLayout(node, &title_bar_rect, &tab_bar_rect, &window_menu_button_pos); + + // Title bar + if (is_focused) + node->LastFrameFocused = g.FrameCount; + ImU32 title_bar_col = GetColorU32(host_window->Collapsed ? ImGuiCol_TitleBgCollapsed : is_focused ? ImGuiCol_TitleBgActive : ImGuiCol_TitleBg); + host_window->DrawList->AddRectFilled(title_bar_rect.Min, title_bar_rect.Max, title_bar_col, host_window->WindowRounding, ImDrawCornerFlags_Top); + + // Docking/Collapse button + if (has_window_menu_button) + { + if (CollapseButton(host_window->GetID("#COLLAPSE"), window_menu_button_pos, node)) + OpenPopup("#WindowMenu"); + if (IsItemActive()) + focus_tab_id = tab_bar->SelectedTabId; + } + + // Submit new tabs and apply NavWindow focus back to the tab bar. They will be added as Unsorted and sorted below based on relative DockOrder value. + const int tabs_count_old = tab_bar->Tabs.Size; + for (int window_n = 0; window_n < node->Windows.Size; window_n++) + { + ImGuiWindow* window = node->Windows[window_n]; + if (g.NavWindow && g.NavWindow->RootWindowDockStop == window) + tab_bar->SelectedTabId = window->ID; + if (TabBarFindTabByID(tab_bar, window->ID) == NULL) + TabBarAddTab(tab_bar, ImGuiTabItemFlags_Unsorted, window); + } + + // If multiple tabs are appearing on the same frame, sort them based on their persistent DockOrder value + int tabs_unsorted_start = tab_bar->Tabs.Size; + for (int tab_n = tab_bar->Tabs.Size - 1; tab_n >= 0 && (tab_bar->Tabs[tab_n].Flags & ImGuiTabItemFlags_Unsorted); tab_n--) + { + // FIXME-DOCK: Consider only clearing the flag after the tab has been alive for a few consecutive frames, allowing late comers to not break sorting? + tab_bar->Tabs[tab_n].Flags &= ~ImGuiTabItemFlags_Unsorted; + tabs_unsorted_start = tab_n; + } + if (tab_bar->Tabs.Size > tabs_unsorted_start) + { + IMGUI_DEBUG_LOG_DOCKING("In node 0x%08X: %d new appearing tabs:%s\n", node->ID, tab_bar->Tabs.Size - tabs_unsorted_start, (tab_bar->Tabs.Size > tabs_unsorted_start + 1) ? " (will sort)" : ""); + for (int tab_n = tabs_unsorted_start; tab_n < tab_bar->Tabs.Size; tab_n++) + IMGUI_DEBUG_LOG_DOCKING(" - Tab '%s' Order %d\n", tab_bar->Tabs[tab_n].Window->Name, tab_bar->Tabs[tab_n].Window->DockOrder); + if (tab_bar->Tabs.Size > tabs_unsorted_start + 1) + ImQsort(tab_bar->Tabs.Data + tabs_unsorted_start, tab_bar->Tabs.Size - tabs_unsorted_start, sizeof(ImGuiTabItem), TabItemComparerByDockOrder); + } + + // Selected newly added tabs, or persistent tab ID if the tab bar was just recreated + if (tab_bar_is_recreated && TabBarFindTabByID(tab_bar, node->SelectedTabId) != NULL) + tab_bar->SelectedTabId = tab_bar->NextSelectedTabId = node->SelectedTabId; + else if (tab_bar->Tabs.Size > tabs_count_old) + tab_bar->SelectedTabId = tab_bar->NextSelectedTabId = tab_bar->Tabs.back().Window->ID; + + // Begin tab bar + ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_Reorderable | ImGuiTabBarFlags_AutoSelectNewTabs; // | ImGuiTabBarFlags_NoTabListScrollingButtons); + tab_bar_flags |= ImGuiTabBarFlags_SaveSettings | ImGuiTabBarFlags_DockNode; + if (!host_window->Collapsed && is_focused) + tab_bar_flags |= ImGuiTabBarFlags_IsFocused; + BeginTabBarEx(tab_bar, tab_bar_rect, tab_bar_flags, node); + //host_window->DrawList->AddRect(tab_bar_rect.Min, tab_bar_rect.Max, IM_COL32(255,0,255,255)); + + // Submit actual tabs + node->VisibleWindow = NULL; + for (int window_n = 0; window_n < node->Windows.Size; window_n++) + { + ImGuiWindow* window = node->Windows[window_n]; + if ((closed_all || closed_one == window->ID) && window->HasCloseButton && !(window->Flags & ImGuiWindowFlags_UnsavedDocument)) + continue; + if (window->LastFrameActive + 1 >= g.FrameCount || !node_was_active) + { + ImGuiTabItemFlags tab_item_flags = 0; + if (window->Flags & ImGuiWindowFlags_UnsavedDocument) + tab_item_flags |= ImGuiTabItemFlags_UnsavedDocument; + if (tab_bar->Flags & ImGuiTabBarFlags_NoCloseWithMiddleMouseButton) + tab_item_flags |= ImGuiTabItemFlags_NoCloseWithMiddleMouseButton; + + bool tab_open = true; + TabItemEx(tab_bar, window->Name, window->HasCloseButton ? &tab_open : NULL, tab_item_flags, window); + if (!tab_open) + node->WantCloseTabId = window->ID; + if (tab_bar->VisibleTabId == window->ID) + node->VisibleWindow = window; + + // Store last item data so it can be queried with IsItemXXX functions after the user Begin() call + window->DockTabItemStatusFlags = host_window->DC.LastItemStatusFlags; + window->DockTabItemRect = host_window->DC.LastItemRect; + + // Update navigation ID on menu layer + if (g.NavWindow && g.NavWindow->RootWindowDockStop == window && (window->DC.NavLayerActiveMask & (1 << 1)) == 0) + host_window->NavLastIds[1] = window->ID; + } + } + + // Notify root of visible window (used to display title in OS task bar) + if (node->VisibleWindow) + if (is_focused || root_node->VisibleWindow == NULL) + root_node->VisibleWindow = node->VisibleWindow; + + // Close button (after VisibleWindow was updated) + // Note that VisibleWindow may have been overrided by CTRL+Tabbing, so VisibleWindow->ID may be != from tab_bar->SelectedTabId + if (has_close_button && node->VisibleWindow) + { + if (!node->VisibleWindow->HasCloseButton) + { + PushItemFlag(ImGuiItemFlags_Disabled, true); + PushStyleColor(ImGuiCol_Text, style.Colors[ImGuiCol_Text] * ImVec4(1.0f,1.0f,1.0f,0.5f)); + } + const float button_sz = g.FontSize; + if (CloseButton(host_window->GetID("#CLOSE"), title_bar_rect.GetTR() + ImVec2(-style.FramePadding.x * 2.0f - button_sz, 0.0f))) + if (ImGuiTabItem* tab = TabBarFindTabByID(tab_bar, tab_bar->VisibleTabId)) + { + node->WantCloseTabId = tab->ID; + TabBarCloseTab(tab_bar, tab); + } + //if (IsItemActive()) + // focus_tab_id = tab_bar->SelectedTabId; + if (!node->VisibleWindow->HasCloseButton) + { + PopStyleColor(); + PopItemFlag(); + } + } + + // When clicking on the title bar outside of tabs, we still focus the selected tab for that node + // FIXME: TabItem use AllowItemOverlap so we manually perform a more specific test for now (hovered || held) + ImGuiID title_bar_id = host_window->GetID("#TITLEBAR"); + if (g.HoveredId == 0 || g.HoveredId == title_bar_id || g.ActiveId == title_bar_id) + { + bool held; + ButtonBehavior(title_bar_rect, title_bar_id, NULL, &held); + if (held) + { + if (IsMouseClicked(0)) + focus_tab_id = tab_bar->SelectedTabId; + + // Forward moving request to selected window + if (ImGuiTabItem* tab = TabBarFindTabByID(tab_bar, tab_bar->SelectedTabId)) + StartMouseMovingWindowOrNode(tab->Window, node, false); + } + } + + // Forward focus from host node to selected window + //if (is_focused && g.NavWindow == host_window && !g.NavWindowingTarget) + // focus_tab_id = tab_bar->SelectedTabId; + + // When clicked on a tab we requested focus to the docked child + // This overrides the value set by "forward focus from host node to selected window". + if (tab_bar->NextSelectedTabId) + focus_tab_id = tab_bar->NextSelectedTabId; + + // Apply navigation focus + if (focus_tab_id != 0) + if (ImGuiTabItem* tab = TabBarFindTabByID(tab_bar, focus_tab_id)) + { + FocusWindow(tab->Window); + NavInitWindow(tab->Window, false); + } + + EndTabBar(); + PopID(); + + // Restore SkipItems flag + if (!node->IsDockSpace()) + { + host_window->DC.NavLayerCurrent = ImGuiNavLayer_Main; + host_window->DC.NavLayerCurrentMask = (1 << ImGuiNavLayer_Main); + host_window->SkipItems = backup_skip_item; + } +} + +static void ImGui::DockNodeAddTabBar(ImGuiDockNode* node) +{ + IM_ASSERT(node->TabBar == NULL); + node->TabBar = IM_NEW(ImGuiTabBar); +} + +static void ImGui::DockNodeRemoveTabBar(ImGuiDockNode* node) +{ + if (node->TabBar == NULL) + return; + IM_DELETE(node->TabBar); + node->TabBar = NULL; +} + +static bool DockNodeIsDropAllowedOne(ImGuiWindow* payload, ImGuiWindow* host_window) +{ + if (host_window->DockNodeAsHost && host_window->DockNodeAsHost->IsDockSpace() && payload->BeginOrderWithinContext < host_window->BeginOrderWithinContext) + return false; + + ImGuiWindowClass* host_class = host_window->DockNodeAsHost ? &host_window->DockNodeAsHost->WindowClass : &host_window->WindowClass; + ImGuiWindowClass* payload_class = &payload->WindowClass; + if (host_class->ClassId != payload_class->ClassId) + { + if (host_class->ClassId != 0 && host_class->DockingAllowUnclassed && payload_class->ClassId == 0) + return true; + if (payload_class->ClassId != 0 && payload_class->DockingAllowUnclassed && host_class->ClassId == 0) + return true; + return false; + } + + return true; +} + +static bool ImGui::DockNodeIsDropAllowed(ImGuiWindow* host_window, ImGuiWindow* root_payload) +{ + if (root_payload->DockNodeAsHost && root_payload->DockNodeAsHost->IsSplitNode()) + return true; + + const int payload_count = root_payload->DockNodeAsHost ? root_payload->DockNodeAsHost->Windows.Size : 1; + for (int payload_n = 0; payload_n < payload_count; payload_n++) + { + ImGuiWindow* payload = root_payload->DockNodeAsHost ? root_payload->DockNodeAsHost->Windows[payload_n] : root_payload; + if (DockNodeIsDropAllowedOne(payload, host_window)) + return true; + } + return false; +} + +// window menu button == collapse button when not in a dock node. +// FIXME: This is similar to RenderWindowTitleBarContents, may want to share code. +static void ImGui::DockNodeCalcTabBarLayout(const ImGuiDockNode* node, ImRect* out_title_rect, ImRect* out_tab_bar_rect, ImVec2* out_window_menu_button_pos) +{ + ImGuiContext& g = *GImGui; + ImRect r = ImRect(node->Pos.x, node->Pos.y, node->Pos.x + node->Size.x, node->Pos.y + g.FontSize + g.Style.FramePadding.y * 2.0f); + if (out_title_rect) { *out_title_rect = r; } + + ImVec2 window_menu_button_pos = r.Min; + r.Min.x += g.Style.FramePadding.x; + r.Max.x -= g.Style.FramePadding.x; + if (node->HasCloseButton) + { + r.Max.x -= g.FontSize;// +1.0f; // In DockNodeUpdateTabBar() we currently display a disabled close button even if there is none. + } + if (node->HasWindowMenuButton && g.Style.WindowMenuButtonPosition == ImGuiDir_Left) + { + r.Min.x += g.FontSize; // + g.Style.ItemInnerSpacing.x; // <-- Adding ItemInnerSpacing makes the title text moves slightly when in a docking tab bar. Instead we adjusted RenderArrowDockMenu() + } + else if (node->HasWindowMenuButton && g.Style.WindowMenuButtonPosition == ImGuiDir_Right) + { + r.Max.x -= g.FontSize + g.Style.FramePadding.x; + window_menu_button_pos = ImVec2(r.Max.x, r.Min.y); + } + if (out_tab_bar_rect) { *out_tab_bar_rect = r; } + if (out_window_menu_button_pos) { *out_window_menu_button_pos = window_menu_button_pos; } +} + +void ImGui::DockNodeCalcSplitRects(ImVec2& pos_old, ImVec2& size_old, ImVec2& pos_new, ImVec2& size_new, ImGuiDir dir, ImVec2 size_new_desired) +{ + ImGuiContext& g = *GImGui; + const float dock_spacing = g.Style.ItemInnerSpacing.x; + const ImGuiAxis axis = (dir == ImGuiDir_Left || dir == ImGuiDir_Right) ? ImGuiAxis_X : ImGuiAxis_Y; + pos_new[axis ^ 1] = pos_old[axis ^ 1]; + size_new[axis ^ 1] = size_old[axis ^ 1]; + + // Distribute size on given axis (with a desired size or equally) + const float w_avail = size_old[axis] - dock_spacing; + if (size_new_desired[axis] > 0.0f && size_new_desired[axis] <= w_avail * 0.5f) + { + size_new[axis] = size_new_desired[axis]; + size_old[axis] = IM_FLOOR(w_avail - size_new[axis]); + } + else + { + size_new[axis] = IM_FLOOR(w_avail * 0.5f); + size_old[axis] = IM_FLOOR(w_avail - size_new[axis]); + } + + // Position each node + if (dir == ImGuiDir_Right || dir == ImGuiDir_Down) + { + pos_new[axis] = pos_old[axis] + size_old[axis] + dock_spacing; + } + else if (dir == ImGuiDir_Left || dir == ImGuiDir_Up) + { + pos_new[axis] = pos_old[axis]; + pos_old[axis] = pos_new[axis] + size_new[axis] + dock_spacing; + } +} + +// Retrieve the drop rectangles for a given direction or for the center + perform hit testing. +bool ImGui::DockNodeCalcDropRectsAndTestMousePos(const ImRect& parent, ImGuiDir dir, ImRect& out_r, bool outer_docking, ImVec2* test_mouse_pos) +{ + ImGuiContext& g = *GImGui; + + const float parent_smaller_axis = ImMin(parent.GetWidth(), parent.GetHeight()); + const float hs_for_central_nodes = ImMin(g.FontSize * 1.5f, ImMax(g.FontSize * 0.5f, parent_smaller_axis / 8.0f)); + float hs_w; // Half-size, longer axis + float hs_h; // Half-size, smaller axis + ImVec2 off; // Distance from edge or center + if (outer_docking) + { + //hs_w = ImFloor(ImClamp(parent_smaller_axis - hs_for_central_nodes * 4.0f, g.FontSize * 0.5f, g.FontSize * 8.0f)); + //hs_h = ImFloor(hs_w * 0.15f); + //off = ImVec2(ImFloor(parent.GetWidth() * 0.5f - GetFrameHeightWithSpacing() * 1.4f - hs_h), ImFloor(parent.GetHeight() * 0.5f - GetFrameHeightWithSpacing() * 1.4f - hs_h)); + hs_w = ImFloor(hs_for_central_nodes * 1.50f); + hs_h = ImFloor(hs_for_central_nodes * 0.80f); + off = ImVec2(ImFloor(parent.GetWidth() * 0.5f - hs_h), ImFloor(parent.GetHeight() * 0.5f - hs_h)); + } + else + { + hs_w = ImFloor(hs_for_central_nodes); + hs_h = ImFloor(hs_for_central_nodes * 0.90f); + off = ImVec2(ImFloor(hs_w * 2.40f), ImFloor(hs_w * 2.40f)); + } + + ImVec2 c = ImFloor(parent.GetCenter()); + if (dir == ImGuiDir_None) { out_r = ImRect(c.x - hs_w, c.y - hs_w, c.x + hs_w, c.y + hs_w); } + else if (dir == ImGuiDir_Up) { out_r = ImRect(c.x - hs_w, c.y - off.y - hs_h, c.x + hs_w, c.y - off.y + hs_h); } + else if (dir == ImGuiDir_Down) { out_r = ImRect(c.x - hs_w, c.y + off.y - hs_h, c.x + hs_w, c.y + off.y + hs_h); } + else if (dir == ImGuiDir_Left) { out_r = ImRect(c.x - off.x - hs_h, c.y - hs_w, c.x - off.x + hs_h, c.y + hs_w); } + else if (dir == ImGuiDir_Right) { out_r = ImRect(c.x + off.x - hs_h, c.y - hs_w, c.x + off.x + hs_h, c.y + hs_w); } + + if (test_mouse_pos == NULL) + return false; + + ImRect hit_r = out_r; + if (!outer_docking) + { + // Custom hit testing for the 5-way selection, designed to reduce flickering when moving diagonally between sides + hit_r.Expand(ImFloor(hs_w * 0.30f)); + ImVec2 mouse_delta = (*test_mouse_pos - c); + float mouse_delta_len2 = ImLengthSqr(mouse_delta); + float r_threshold_center = hs_w * 1.4f; + float r_threshold_sides = hs_w * (1.4f + 1.2f); + if (mouse_delta_len2 < r_threshold_center * r_threshold_center) + return (dir == ImGuiDir_None); + if (mouse_delta_len2 < r_threshold_sides * r_threshold_sides) + return (dir == ImGetDirQuadrantFromDelta(mouse_delta.x, mouse_delta.y)); + } + return hit_r.Contains(*test_mouse_pos); +} + +// host_node may be NULL if the window doesn't have a DockNode already. +// FIXME-DOCK: This is misnamed since it's also doing the filtering. +static void ImGui::DockNodePreviewDockSetup(ImGuiWindow* host_window, ImGuiDockNode* host_node, ImGuiWindow* root_payload, ImGuiDockPreviewData* data, bool is_explicit_target, bool is_outer_docking) +{ + ImGuiContext& g = *GImGui; + + // There is an edge case when docking into a dockspace which only has inactive nodes. + // In this case DockNodeTreeFindNodeByPos() will have selected a leaf node which is inactive. + // Because the inactive leaf node doesn't have proper pos/size yet, we'll use the root node as reference. + ImGuiDockNode* root_payload_as_host = root_payload->DockNodeAsHost; + ImGuiDockNode* ref_node_for_rect = (host_node && !host_node->IsVisible) ? DockNodeGetRootNode(host_node) : host_node; + if (ref_node_for_rect) + IM_ASSERT(ref_node_for_rect->IsVisible); + + // Filter, figure out where we are allowed to dock + ImGuiDockNodeFlags host_node_flags = host_node ? host_node->GetMergedFlags() : 0; + data->IsCenterAvailable = true; + if (is_outer_docking) + data->IsCenterAvailable = false; + else if (host_node && (host_node_flags & ImGuiDockNodeFlags_NoDocking)) + data->IsCenterAvailable = false; + else if (host_node && (host_node_flags & ImGuiDockNodeFlags_NoDockingInCentralNode) && host_node->IsCentralNode()) + data->IsCenterAvailable = false; + else if ((!host_node || !host_node->IsEmpty()) && root_payload_as_host && root_payload_as_host->IsSplitNode() && (root_payload_as_host->OnlyNodeWithWindows == NULL)) // Is _visibly_ split? + data->IsCenterAvailable = false; + + data->IsSidesAvailable = true; + if ((host_node && (host_node_flags & ImGuiDockNodeFlags_NoSplit)) || g.IO.ConfigDockingNoSplit) + data->IsSidesAvailable = false; + else if (!is_outer_docking && host_node && host_node->ParentNode == NULL && host_node->IsCentralNode()) + data->IsSidesAvailable = false; + + // Build a tentative future node (reuse same structure because it is practical. Shape will be readjusted when previewing a split) + data->FutureNode.HasCloseButton = (host_node ? host_node->HasCloseButton : host_window->HasCloseButton) || (root_payload->HasCloseButton); + data->FutureNode.HasWindowMenuButton = host_node ? true : ((host_window->Flags & ImGuiWindowFlags_NoCollapse) == 0); + data->FutureNode.Pos = ref_node_for_rect ? ref_node_for_rect->Pos : host_window->Pos; + data->FutureNode.Size = ref_node_for_rect ? ref_node_for_rect->Size : host_window->Size; + + // Calculate drop shapes geometry for allowed splitting directions + IM_ASSERT(ImGuiDir_None == -1); + data->SplitNode = host_node; + data->SplitDir = ImGuiDir_None; + data->IsSplitDirExplicit = false; + if (!host_window->Collapsed) + for (int dir = ImGuiDir_None; dir < ImGuiDir_COUNT; dir++) + { + if (dir == ImGuiDir_None && !data->IsCenterAvailable) + continue; + if (dir != ImGuiDir_None && !data->IsSidesAvailable) + continue; + if (DockNodeCalcDropRectsAndTestMousePos(data->FutureNode.Rect(), (ImGuiDir)dir, data->DropRectsDraw[dir+1], is_outer_docking, &g.IO.MousePos)) + { + data->SplitDir = (ImGuiDir)dir; + data->IsSplitDirExplicit = true; + } + } + + // When docking without holding Shift, we only allow and preview docking when hovering over a drop rect or over the title bar + data->IsDropAllowed = (data->SplitDir != ImGuiDir_None) || (data->IsCenterAvailable); + if (!is_explicit_target && !data->IsSplitDirExplicit && !g.IO.ConfigDockingWithShift) + data->IsDropAllowed = false; + + // Calculate split area + data->SplitRatio = 0.0f; + if (data->SplitDir != ImGuiDir_None) + { + ImGuiDir split_dir = data->SplitDir; + ImGuiAxis split_axis = (split_dir == ImGuiDir_Left || split_dir == ImGuiDir_Right) ? ImGuiAxis_X : ImGuiAxis_Y; + ImVec2 pos_new, pos_old = data->FutureNode.Pos; + ImVec2 size_new, size_old = data->FutureNode.Size; + DockNodeCalcSplitRects(pos_old, size_old, pos_new, size_new, split_dir, root_payload->Size); + + // Calculate split ratio so we can pass it down the docking request + float split_ratio = ImSaturate(size_new[split_axis] / data->FutureNode.Size[split_axis]); + data->FutureNode.Pos = pos_new; + data->FutureNode.Size = size_new; + data->SplitRatio = (split_dir == ImGuiDir_Right || split_dir == ImGuiDir_Down) ? (1.0f - split_ratio) : (split_ratio); + } +} + +static void ImGui::DockNodePreviewDockRender(ImGuiWindow* host_window, ImGuiDockNode* host_node, ImGuiWindow* root_payload, const ImGuiDockPreviewData* data) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(g.CurrentWindow == host_window); // Because we rely on font size to calculate tab sizes + + // With this option, we only display the preview on the target viewport, and the payload viewport is made transparent. + // To compensate for the single layer obstructed by the payload, we'll increase the alpha of the preview nodes. + const bool is_transparent_payload = g.IO.ConfigDockingTransparentPayload; + + // In case the two windows involved are on different viewports, we will draw the overlay on each of them. + int overlay_draw_lists_count = 0; + ImDrawList* overlay_draw_lists[2]; + overlay_draw_lists[overlay_draw_lists_count++] = GetForegroundDrawList(host_window->Viewport); + if (host_window->Viewport != root_payload->Viewport && !is_transparent_payload) + overlay_draw_lists[overlay_draw_lists_count++] = GetForegroundDrawList(root_payload->Viewport); + + // Draw main preview rectangle + const ImU32 overlay_col_tabs = GetColorU32(ImGuiCol_TabActive); + const ImU32 overlay_col_main = GetColorU32(ImGuiCol_DockingPreview, is_transparent_payload ? 0.60f : 0.40f); + const ImU32 overlay_col_drop = GetColorU32(ImGuiCol_DockingPreview, is_transparent_payload ? 0.90f : 0.70f); + const ImU32 overlay_col_drop_hovered = GetColorU32(ImGuiCol_DockingPreview, is_transparent_payload ? 1.20f : 1.00f); + const ImU32 overlay_col_lines = GetColorU32(ImGuiCol_NavWindowingHighlight, is_transparent_payload ? 0.80f : 0.60f); + + // Display area preview + const bool can_preview_tabs = (root_payload->DockNodeAsHost == NULL || root_payload->DockNodeAsHost->Windows.Size > 0); + if (data->IsDropAllowed) + { + ImRect overlay_rect = data->FutureNode.Rect(); + if (data->SplitDir == ImGuiDir_None && can_preview_tabs) + overlay_rect.Min.y += GetFrameHeight(); + if (data->SplitDir != ImGuiDir_None || data->IsCenterAvailable) + for (int overlay_n = 0; overlay_n < overlay_draw_lists_count; overlay_n++) + overlay_draw_lists[overlay_n]->AddRectFilled(overlay_rect.Min, overlay_rect.Max, overlay_col_main, host_window->WindowRounding); + } + + // Display tab shape/label preview unless we are splitting node (it generally makes the situation harder to read) + if (data->IsDropAllowed && can_preview_tabs && data->SplitDir == ImGuiDir_None && data->IsCenterAvailable) + { + // Compute target tab bar geometry so we can locate our preview tabs + ImRect tab_bar_rect; + DockNodeCalcTabBarLayout(&data->FutureNode, NULL, &tab_bar_rect, NULL); + ImVec2 tab_pos = tab_bar_rect.Min; + if (host_node && host_node->TabBar) + { + if (!host_node->IsHiddenTabBar() && !host_node->IsNoTabBar()) + tab_pos.x += host_node->TabBar->OffsetMax + g.Style.ItemInnerSpacing.x; // We don't use OffsetNewTab because when using non-persistent-order tab bar it is incremented with each Tab submission. + else + tab_pos.x += g.Style.ItemInnerSpacing.x + TabItemCalcSize(host_node->Windows[0]->Name, host_node->Windows[0]->HasCloseButton).x; + } + else if (!(host_window->Flags & ImGuiWindowFlags_DockNodeHost)) + { + tab_pos.x += g.Style.ItemInnerSpacing.x + TabItemCalcSize(host_window->Name, host_window->HasCloseButton).x; // Account for slight offset which will be added when changing from title bar to tab bar + } + + // Draw tab shape/label preview (payload may be a loose window or a host window carrying multiple tabbed windows) + if (root_payload->DockNodeAsHost) + IM_ASSERT(root_payload->DockNodeAsHost->Windows.Size == root_payload->DockNodeAsHost->TabBar->Tabs.Size); + const int payload_count = root_payload->DockNodeAsHost ? root_payload->DockNodeAsHost->TabBar->Tabs.Size : 1; + for (int payload_n = 0; payload_n < payload_count; payload_n++) + { + // Calculate the tab bounding box for each payload window + ImGuiWindow* payload = root_payload->DockNodeAsHost ? root_payload->DockNodeAsHost->TabBar->Tabs[payload_n].Window : root_payload; + if (!DockNodeIsDropAllowedOne(payload, host_window)) + continue; + + ImVec2 tab_size = TabItemCalcSize(payload->Name, payload->HasCloseButton); + ImRect tab_bb(tab_pos.x, tab_pos.y, tab_pos.x + tab_size.x, tab_pos.y + tab_size.y); + tab_pos.x += tab_size.x + g.Style.ItemInnerSpacing.x; + for (int overlay_n = 0; overlay_n < overlay_draw_lists_count; overlay_n++) + { + ImGuiTabItemFlags tab_flags = ImGuiTabItemFlags_Preview | ((payload->Flags & ImGuiWindowFlags_UnsavedDocument) ? ImGuiTabItemFlags_UnsavedDocument : 0); + if (!tab_bar_rect.Contains(tab_bb)) + overlay_draw_lists[overlay_n]->PushClipRect(tab_bar_rect.Min, tab_bar_rect.Max); + TabItemBackground(overlay_draw_lists[overlay_n], tab_bb, tab_flags, overlay_col_tabs); + TabItemLabelAndCloseButton(overlay_draw_lists[overlay_n], tab_bb, tab_flags, g.Style.FramePadding, payload->Name, 0, 0, false); + if (!tab_bar_rect.Contains(tab_bb)) + overlay_draw_lists[overlay_n]->PopClipRect(); + } + } + } + + // Display drop boxes + const float overlay_rounding = ImMax(3.0f, g.Style.FrameRounding); + for (int dir = ImGuiDir_None; dir < ImGuiDir_COUNT; dir++) + { + if (!data->DropRectsDraw[dir + 1].IsInverted()) + { + ImRect draw_r = data->DropRectsDraw[dir + 1]; + ImRect draw_r_in = draw_r; + draw_r_in.Expand(-2.0f); + ImU32 overlay_col = (data->SplitDir == (ImGuiDir)dir && data->IsSplitDirExplicit) ? overlay_col_drop_hovered : overlay_col_drop; + for (int overlay_n = 0; overlay_n < overlay_draw_lists_count; overlay_n++) + { + ImVec2 center = ImFloor(draw_r_in.GetCenter()); + overlay_draw_lists[overlay_n]->AddRectFilled(draw_r.Min, draw_r.Max, overlay_col, overlay_rounding); + overlay_draw_lists[overlay_n]->AddRect(draw_r_in.Min, draw_r_in.Max, overlay_col_lines, overlay_rounding); + if (dir == ImGuiDir_Left || dir == ImGuiDir_Right) + overlay_draw_lists[overlay_n]->AddLine(ImVec2(center.x, draw_r_in.Min.y), ImVec2(center.x, draw_r_in.Max.y), overlay_col_lines); + if (dir == ImGuiDir_Up || dir == ImGuiDir_Down) + overlay_draw_lists[overlay_n]->AddLine(ImVec2(draw_r_in.Min.x, center.y), ImVec2(draw_r_in.Max.x, center.y), overlay_col_lines); + } + } + + // Stop after ImGuiDir_None + if ((host_node && (host_node->GetMergedFlags() & ImGuiDockNodeFlags_NoSplit)) || g.IO.ConfigDockingNoSplit) + return; + } +} + +//----------------------------------------------------------------------------- +// Docking: ImGuiDockNode Tree manipulation functions +//----------------------------------------------------------------------------- +// - DockNodeTreeSplit() +// - DockNodeTreeMerge() +// - DockNodeTreeUpdatePosSize() +// - DockNodeTreeUpdateSplitterFindTouchingNode() +// - DockNodeTreeUpdateSplitter() +// - DockNodeTreeFindFallbackLeafNode() +// - DockNodeTreeFindNodeByPos() +//----------------------------------------------------------------------------- + +void ImGui::DockNodeTreeSplit(ImGuiContext* ctx, ImGuiDockNode* parent_node, ImGuiAxis split_axis, int split_inheritor_child_idx, float split_ratio, ImGuiDockNode* new_node) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(split_axis != ImGuiAxis_None); + + ImGuiDockNode* child_0 = (new_node && split_inheritor_child_idx != 0) ? new_node : DockContextAddNode(ctx, 0); + child_0->ParentNode = parent_node; + + ImGuiDockNode* child_1 = (new_node && split_inheritor_child_idx != 1) ? new_node : DockContextAddNode(ctx, 0); + child_1->ParentNode = parent_node; + + ImGuiDockNode* child_inheritor = (split_inheritor_child_idx == 0) ? child_0 : child_1; + DockNodeMoveChildNodes(child_inheritor, parent_node); + parent_node->ChildNodes[0] = child_0; + parent_node->ChildNodes[1] = child_1; + parent_node->ChildNodes[split_inheritor_child_idx]->VisibleWindow = parent_node->VisibleWindow; + parent_node->SplitAxis = split_axis; + parent_node->VisibleWindow = NULL; + parent_node->AuthorityForPos = parent_node->AuthorityForSize = ImGuiDataAuthority_DockNode; + + float size_avail = (parent_node->Size[split_axis] - IMGUI_DOCK_SPLITTER_SIZE); + size_avail = ImMax(size_avail, g.Style.WindowMinSize[split_axis] * 2.0f); + IM_ASSERT(size_avail > 0.0f); // If you created a node manually with DockBuilderAddNode(), you need to also call DockBuilderSetNodeSize() before splitting. + child_0->SizeRef = child_1->SizeRef = parent_node->Size; + child_0->SizeRef[split_axis] = ImFloor(size_avail * split_ratio); + child_1->SizeRef[split_axis] = ImFloor(size_avail - child_0->SizeRef[split_axis]); + + DockNodeMoveWindows(parent_node->ChildNodes[split_inheritor_child_idx], parent_node); + DockNodeTreeUpdatePosSize(parent_node, parent_node->Pos, parent_node->Size); + + // Flags transfer (e.g. this is where we transfer the ImGuiDockNodeFlags_CentralNode property) + child_0->SharedFlags = parent_node->SharedFlags & ImGuiDockNodeFlags_SharedFlagsInheritMask_; + child_1->SharedFlags = parent_node->SharedFlags & ImGuiDockNodeFlags_SharedFlagsInheritMask_; + child_inheritor->LocalFlags = parent_node->LocalFlags & ImGuiDockNodeFlags_LocalFlagsTransferMask_; + parent_node->LocalFlags &= ~ImGuiDockNodeFlags_LocalFlagsTransferMask_; + if (child_inheritor->IsCentralNode()) + DockNodeGetRootNode(parent_node)->CentralNode = child_inheritor; +} + +void ImGui::DockNodeTreeMerge(ImGuiContext* ctx, ImGuiDockNode* parent_node, ImGuiDockNode* merge_lead_child) +{ + // When called from DockContextProcessUndockNode() it is possible that one of the child is NULL. + ImGuiDockNode* child_0 = parent_node->ChildNodes[0]; + ImGuiDockNode* child_1 = parent_node->ChildNodes[1]; + IM_ASSERT(child_0 || child_1); + IM_ASSERT(merge_lead_child == child_0 || merge_lead_child == child_1); + if ((child_0 && child_0->Windows.Size > 0) || (child_1 && child_1->Windows.Size > 0)) + { + IM_ASSERT(parent_node->TabBar == NULL); + IM_ASSERT(parent_node->Windows.Size == 0); + } + IMGUI_DEBUG_LOG_DOCKING("DockNodeTreeMerge 0x%08X & 0x%08X back into parent 0x%08X\n", child_0 ? child_0->ID : 0, child_1 ? child_1->ID : 0, parent_node->ID); + + ImVec2 backup_last_explicit_size = parent_node->SizeRef; + DockNodeMoveChildNodes(parent_node, merge_lead_child); + if (child_0) + { + DockNodeMoveWindows(parent_node, child_0); // Generally only 1 of the 2 child node will have windows + DockSettingsRenameNodeReferences(child_0->ID, parent_node->ID); + } + if (child_1) + { + DockNodeMoveWindows(parent_node, child_1); + DockSettingsRenameNodeReferences(child_1->ID, parent_node->ID); + } + DockNodeApplyPosSizeToWindows(parent_node); + parent_node->AuthorityForPos = parent_node->AuthorityForSize = parent_node->AuthorityForViewport = ImGuiDataAuthority_Auto; + parent_node->VisibleWindow = merge_lead_child->VisibleWindow; + parent_node->SizeRef = backup_last_explicit_size; + + // Flags transfer + parent_node->LocalFlags &= ~ImGuiDockNodeFlags_LocalFlagsTransferMask_; // Preserve Dockspace flag + parent_node->LocalFlags |= (child_0 ? child_0->LocalFlags : 0) & ImGuiDockNodeFlags_LocalFlagsTransferMask_; + parent_node->LocalFlags |= (child_1 ? child_1->LocalFlags : 0) & ImGuiDockNodeFlags_LocalFlagsTransferMask_; + + if (child_0) + { + ctx->DockContext.Nodes.SetVoidPtr(child_0->ID, NULL); + IM_DELETE(child_0); + } + if (child_1) + { + ctx->DockContext.Nodes.SetVoidPtr(child_1->ID, NULL); + IM_DELETE(child_1); + } +} + +// Update Pos/Size for a node hierarchy (don't affect child Windows yet) +void ImGui::DockNodeTreeUpdatePosSize(ImGuiDockNode* node, ImVec2 pos, ImVec2 size, bool only_write_to_marked_nodes) +{ + // During the regular dock node update we write to all nodes. + // 'only_write_to_marked_nodes' is only set when turning a node visible mid-frame and we need its size right-away. + const bool write_to_node = (only_write_to_marked_nodes == false) || (node->MarkedForPosSizeWrite); + if (write_to_node) + { + node->Pos = pos; + node->Size = size; + } + + if (node->IsLeafNode()) + return; + + ImGuiDockNode* child_0 = node->ChildNodes[0]; + ImGuiDockNode* child_1 = node->ChildNodes[1]; + ImVec2 child_0_pos = pos, child_1_pos = pos; + ImVec2 child_0_size = size, child_1_size = size; + if (child_0->IsVisible && child_1->IsVisible) + { + const float spacing = IMGUI_DOCK_SPLITTER_SIZE; + const ImGuiAxis axis = (ImGuiAxis)node->SplitAxis; + const float size_avail = ImMax(size[axis] - spacing, 0.0f); + + // Size allocation policy + // 1) The first 0..WindowMinSize[axis]*2 are allocated evenly to both windows. + ImGuiContext& g = *GImGui; + const float size_min_each = ImFloor(ImMin(size_avail, g.Style.WindowMinSize[axis] * 2.0f) * 0.5f); + + // 2) Process locked absolute size (during a splitter resize we preserve the child of nodes not touching the splitter edge) + IM_ASSERT(!(child_0->WantLockSizeOnce && child_1->WantLockSizeOnce)); + if (child_0->WantLockSizeOnce) + { + child_0->WantLockSizeOnce = false; + child_0_size[axis] = child_0->SizeRef[axis] = child_0->Size[axis]; + child_1_size[axis] = child_1->SizeRef[axis] = (size_avail - child_0_size[axis]); + IM_ASSERT(child_0->SizeRef[axis] > 0.0f && child_1->SizeRef[axis] > 0.0f); + + } + else if (child_1->WantLockSizeOnce) + { + child_1->WantLockSizeOnce = false; + child_1_size[axis] = child_1->SizeRef[axis] = child_1->Size[axis]; + child_0_size[axis] = child_0->SizeRef[axis] = (size_avail - child_1_size[axis]); + IM_ASSERT(child_0->SizeRef[axis] > 0.0f && child_1->SizeRef[axis] > 0.0f); + } + + // 3) If one window is the central node (~ use remaining space, should be made explicit!), use explicit size from the other, and remainder for the central node + else if (child_1->IsCentralNode() && child_0->SizeRef[axis] != 0.0f) + { + child_0_size[axis] = ImMin(size_avail - size_min_each, child_0->SizeRef[axis]); + child_1_size[axis] = (size_avail - child_0_size[axis]); + } + else if (child_0->IsCentralNode() && child_1->SizeRef[axis] != 0.0f) + { + child_1_size[axis] = ImMin(size_avail - size_min_each, child_1->SizeRef[axis]); + child_0_size[axis] = (size_avail - child_1_size[axis]); + } + else + { + // 4) Otherwise distribute according to the relative ratio of each SizeRef value + float split_ratio = child_0->SizeRef[axis] / (child_0->SizeRef[axis] + child_1->SizeRef[axis]); + child_0_size[axis] = ImMax(size_min_each, ImFloor(size_avail * split_ratio + 0.5F)); + child_1_size[axis] = (size_avail - child_0_size[axis]); + } + child_1_pos[axis] += spacing + child_0_size[axis]; + } + if (child_0->IsVisible) + DockNodeTreeUpdatePosSize(child_0, child_0_pos, child_0_size); + if (child_1->IsVisible) + DockNodeTreeUpdatePosSize(child_1, child_1_pos, child_1_size); +} + +static void DockNodeTreeUpdateSplitterFindTouchingNode(ImGuiDockNode* node, ImGuiAxis axis, int side, ImVector* touching_nodes) +{ + if (node->IsLeafNode()) + { + touching_nodes->push_back(node); + return; + } + if (node->ChildNodes[0]->IsVisible) + if (node->SplitAxis != axis || side == 0 || !node->ChildNodes[1]->IsVisible) + DockNodeTreeUpdateSplitterFindTouchingNode(node->ChildNodes[0], axis, side, touching_nodes); + if (node->ChildNodes[1]->IsVisible) + if (node->SplitAxis != axis || side == 1 || !node->ChildNodes[0]->IsVisible) + DockNodeTreeUpdateSplitterFindTouchingNode(node->ChildNodes[1], axis, side, touching_nodes); +} + +void ImGui::DockNodeTreeUpdateSplitter(ImGuiDockNode* node) +{ + if (node->IsLeafNode()) + return; + + ImGuiContext& g = *GImGui; + + ImGuiDockNode* child_0 = node->ChildNodes[0]; + ImGuiDockNode* child_1 = node->ChildNodes[1]; + if (child_0->IsVisible && child_1->IsVisible) + { + // Bounding box of the splitter cover the space between both nodes (w = Spacing, h = Size[xy^1] for when splitting horizontally) + const ImGuiAxis axis = (ImGuiAxis)node->SplitAxis; + IM_ASSERT(axis != ImGuiAxis_None); + ImRect bb; + bb.Min = child_0->Pos; + bb.Max = child_1->Pos; + bb.Min[axis] += child_0->Size[axis]; + bb.Max[axis ^ 1] += child_1->Size[axis ^ 1]; + //if (g.IO.KeyCtrl) GetForegroundDrawList(g.CurrentWindow->Viewport)->AddRect(bb.Min, bb.Max, IM_COL32(255,0,255,255)); + + if ((child_0->GetMergedFlags() | child_1->GetMergedFlags()) & ImGuiDockNodeFlags_NoResize) + { + ImGuiWindow* window = g.CurrentWindow; + window->DrawList->AddRectFilled(bb.Min, bb.Max, GetColorU32(ImGuiCol_Separator), g.Style.FrameRounding); + } + else + { + //bb.Min[axis] += 1; // Display a little inward so highlight doesn't connect with nearby tabs on the neighbor node. + //bb.Max[axis] -= 1; + PushID(node->ID); + + // Gather list of nodes that are touching the splitter line. Find resizing limits based on those nodes. + ImVector touching_nodes[2]; + float min_size = g.Style.WindowMinSize[axis]; + float resize_limits[2]; + resize_limits[0] = node->ChildNodes[0]->Pos[axis] + min_size; + resize_limits[1] = node->ChildNodes[1]->Pos[axis] + node->ChildNodes[1]->Size[axis] - min_size; + + ImGuiID splitter_id = GetID("##Splitter"); + if (g.ActiveId == splitter_id) + { + // Only process when splitter is active + DockNodeTreeUpdateSplitterFindTouchingNode(child_0, axis, 1, &touching_nodes[0]); + DockNodeTreeUpdateSplitterFindTouchingNode(child_1, axis, 0, &touching_nodes[1]); + for (int touching_node_n = 0; touching_node_n < touching_nodes[0].Size; touching_node_n++) + resize_limits[0] = ImMax(resize_limits[0], touching_nodes[0][touching_node_n]->Rect().Min[axis] + min_size); + for (int touching_node_n = 0; touching_node_n < touching_nodes[1].Size; touching_node_n++) + resize_limits[1] = ImMin(resize_limits[1], touching_nodes[1][touching_node_n]->Rect().Max[axis] - min_size); + + /* + // [DEBUG] Render limits + ImDrawList* draw_list = node->HostWindow ? GetForegroundDrawList(node->HostWindow) : GetForegroundDrawList((ImGuiViewportP*)GetMainViewport()); + for (int n = 0; n < 2; n++) + if (axis == ImGuiAxis_X) + draw_list->AddLine(ImVec2(resize_limits[n], node->ChildNodes[n]->Pos.y), ImVec2(resize_limits[n], node->ChildNodes[n]->Pos.y + node->ChildNodes[n]->Size.y), IM_COL32(255, 0, 255, 255), 3.0f); + else + draw_list->AddLine(ImVec2(node->ChildNodes[n]->Pos.x, resize_limits[n]), ImVec2(node->ChildNodes[n]->Pos.x + node->ChildNodes[n]->Size.x, resize_limits[n]), IM_COL32(255, 0, 255, 255), 3.0f); + */ + } + + // Use a short delay before highlighting the splitter (and changing the mouse cursor) in order for regular mouse movement to not highlight many splitters + float cur_size_0 = child_0->Size[axis]; + float cur_size_1 = child_1->Size[axis]; + float min_size_0 = resize_limits[0] - child_0->Pos[axis]; + float min_size_1 = child_1->Pos[axis] + child_1->Size[axis] - resize_limits[1]; + if (SplitterBehavior(bb, GetID("##Splitter"), axis, &cur_size_0, &cur_size_1, min_size_0, min_size_1, WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS, WINDOWS_RESIZE_FROM_EDGES_FEEDBACK_TIMER)) + { + if (touching_nodes[0].Size > 0 && touching_nodes[1].Size > 0) + { + child_0->Size[axis] = child_0->SizeRef[axis] = cur_size_0; + child_1->Pos[axis] -= cur_size_1 - child_1->Size[axis]; + child_1->Size[axis] = child_1->SizeRef[axis] = cur_size_1; + + // Lock the size of every node that is a sibling of the node we are touching + // This might be less desirable if we can merge sibling of a same axis into the same parental level. + for (int side_n = 0; side_n < 2; side_n++) + for (int touching_node_n = 0; touching_node_n < touching_nodes[side_n].Size; touching_node_n++) + { + ImGuiDockNode* touching_node = touching_nodes[side_n][touching_node_n]; + //ImDrawList* draw_list = node->HostWindow ? GetForegroundDrawList(node->HostWindow) : GetForegroundDrawList((ImGuiViewportP*)GetMainViewport()); + //draw_list->AddRect(touching_node->Pos, touching_node->Pos + touching_node->Size, IM_COL32(255, 128, 0, 255)); + while (touching_node->ParentNode != node) + { + if (touching_node->ParentNode->SplitAxis == axis) + { + // Mark other node so its size will be preserved during the upcoming call to DockNodeTreeUpdatePosSize(). + ImGuiDockNode* node_to_preserve = touching_node->ParentNode->ChildNodes[side_n]; + node_to_preserve->WantLockSizeOnce = true; + //draw_list->AddRect(touching_node->Pos, touching_node->Rect().Max, IM_COL32(255, 0, 0, 255)); + //draw_list->AddRectFilled(node_to_preserve->Pos, node_to_preserve->Rect().Max, IM_COL32(0, 255, 0, 100)); + } + touching_node = touching_node->ParentNode; + } + } + + DockNodeTreeUpdatePosSize(child_0, child_0->Pos, child_0->Size); + DockNodeTreeUpdatePosSize(child_1, child_1->Pos, child_1->Size); + MarkIniSettingsDirty(); + } + } + PopID(); + } + } + + if (child_0->IsVisible) + DockNodeTreeUpdateSplitter(child_0); + if (child_1->IsVisible) + DockNodeTreeUpdateSplitter(child_1); +} + +ImGuiDockNode* ImGui::DockNodeTreeFindFallbackLeafNode(ImGuiDockNode* node) +{ + if (node->IsLeafNode()) + return node; + if (ImGuiDockNode* leaf_node = DockNodeTreeFindFallbackLeafNode(node->ChildNodes[0])) + return leaf_node; + if (ImGuiDockNode* leaf_node = DockNodeTreeFindFallbackLeafNode(node->ChildNodes[1])) + return leaf_node; + return NULL; +} + +ImGuiDockNode* ImGui::DockNodeTreeFindNodeByPos(ImGuiDockNode* node, ImVec2 pos) +{ + if (!node->IsVisible) + return NULL; + + ImGuiContext& g = *GImGui; + const float dock_spacing = g.Style.ItemInnerSpacing.x; + ImRect r(node->Pos, node->Pos + node->Size); + r.Expand(dock_spacing * 0.5f); + bool inside = r.Contains(pos); + if (!inside) + return NULL; + + if (node->IsLeafNode()) + return node; + if (ImGuiDockNode* hovered_node = DockNodeTreeFindNodeByPos(node->ChildNodes[0], pos)) + return hovered_node; + if (ImGuiDockNode* hovered_node = DockNodeTreeFindNodeByPos(node->ChildNodes[1], pos)) + return hovered_node; + + // There is an edge case when docking into a dockspace which only has inactive nodes (because none of the windows are active) + // In this case we need to fallback into any leaf mode, possibly the central node. + if (node->IsDockSpace() && node->IsRootNode()) + { + if (node->CentralNode && node->IsLeafNode()) // FIXME-20181220: We should not have to test for IsLeafNode() here but we have another bug to fix first. + return node->CentralNode; + return DockNodeTreeFindFallbackLeafNode(node); + } + + return NULL; +} + +//----------------------------------------------------------------------------- +// Docking: Public Functions (SetWindowDock, DockSpace, DockSpaceOverViewport) +//----------------------------------------------------------------------------- +// - SetWindowDock() [Internal] +// - DockSpace() +// - DockSpaceOverViewport() +//----------------------------------------------------------------------------- + +// [Internal] Called via SetNextWindowDockID() +void ImGui::SetWindowDock(ImGuiWindow* window, ImGuiID dock_id, ImGuiCond cond) +{ + // Test condition (NB: bit 0 is always true) and clear flags for next time + if (cond && (window->SetWindowDockAllowFlags & cond) == 0) + return; + window->SetWindowDockAllowFlags &= ~(ImGuiCond_Once | ImGuiCond_FirstUseEver | ImGuiCond_Appearing); + + if (window->DockId == dock_id) + return; + + // If the user attempt to set a dock id that is a split node, we'll dig within to find a suitable docking spot + ImGuiContext* ctx = GImGui; + if (ImGuiDockNode* new_node = DockContextFindNodeByID(ctx, dock_id)) + if (new_node->IsSplitNode()) + { + // Policy: Find central node or latest focused node. We first move back to our root node. + new_node = DockNodeGetRootNode(new_node); + if (new_node->CentralNode) + { + IM_ASSERT(new_node->CentralNode->IsCentralNode()); + dock_id = new_node->CentralNode->ID; + } + else + { + dock_id = new_node->LastFocusedNodeId; + } + } + + if (window->DockId == dock_id) + return; + + if (window->DockNode) + DockNodeRemoveWindow(window->DockNode, window, 0); + window->DockId = dock_id; +} + +// Create an explicit dockspace node within an existing window. Also expose dock node flags and creates a CentralNode by default. +// The Central Node is always displayed even when empty and shrink/extend according to the requested size of its neighbors. +// DockSpace() needs to be submitted _before_ any window they can host. If you use a dockspace, submit it early in your app. +void ImGui::DockSpace(ImGuiID id, const ImVec2& size_arg, ImGuiDockNodeFlags flags, const ImGuiWindowClass* window_class) +{ + ImGuiContext* ctx = GImGui; + ImGuiContext& g = *ctx; + ImGuiWindow* window = GetCurrentWindow(); + if (!(g.IO.ConfigFlags & ImGuiConfigFlags_DockingEnable)) + return; + + // Early out if parent window is hidden/collapsed + // This is faster but also DockNodeUpdateTabBar() relies on TabBarLayout() running (which won't if SkipItems=true) to set NextSelectedTabId = 0). See #2960. + // If for whichever reason this is causing problem we would need to ensure that DockNodeUpdateTabBar() ends up clearing NextSelectedTabId even if SkipItems=true. + if (window->SkipItems) + flags |= ImGuiDockNodeFlags_KeepAliveOnly; + + IM_ASSERT((flags & ImGuiDockNodeFlags_DockSpace) == 0); + ImGuiDockNode* node = DockContextFindNodeByID(ctx, id); + if (!node) + { + IMGUI_DEBUG_LOG_DOCKING("DockSpace: dockspace node 0x%08X created\n", id); + node = DockContextAddNode(ctx, id); + node->LocalFlags |= ImGuiDockNodeFlags_CentralNode; + } + if (window_class && window_class->ClassId != node->WindowClass.ClassId) + IMGUI_DEBUG_LOG_DOCKING("DockSpace: dockspace node 0x%08X: setup WindowClass 0x%08X -> 0x%08X\n", id, node->WindowClass.ClassId, window_class->ClassId); + node->SharedFlags = flags; + node->WindowClass = window_class ? *window_class : ImGuiWindowClass(); + + // When a DockSpace transitioned form implicit to explicit this may be called a second time + // It is possible that the node has already been claimed by a docked window which appeared before the DockSpace() node, so we overwrite IsDockSpace again. + if (node->LastFrameActive == g.FrameCount && !(flags & ImGuiDockNodeFlags_KeepAliveOnly)) + { + IM_ASSERT(node->IsDockSpace() == false && "Cannot call DockSpace() twice a frame with the same ID"); + node->LocalFlags |= ImGuiDockNodeFlags_DockSpace; + return; + } + node->LocalFlags |= ImGuiDockNodeFlags_DockSpace; + + // Keep alive mode, this is allow windows docked into this node so stay docked even if they are not visible + if (flags & ImGuiDockNodeFlags_KeepAliveOnly) + { + node->LastFrameAlive = g.FrameCount; + return; + } + + const ImVec2 content_avail = GetContentRegionAvail(); + ImVec2 size = ImFloor(size_arg); + if (size.x <= 0.0f) + size.x = ImMax(content_avail.x + size.x, 4.0f); // Arbitrary minimum child size (0.0f causing too much issues) + if (size.y <= 0.0f) + size.y = ImMax(content_avail.y + size.y, 4.0f); + IM_ASSERT(size.x > 0.0f && size.y > 0.0f); + + node->Pos = window->DC.CursorPos; + node->Size = node->SizeRef = size; + SetNextWindowPos(node->Pos); + SetNextWindowSize(node->Size); + g.NextWindowData.PosUndock = false; + + // FIXME-DOCK Why do we need a child window to host a dockspace, could we host it in the existing window? + ImGuiWindowFlags window_flags = ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_DockNodeHost; + window_flags |= ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoTitleBar; + window_flags |= ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse; + + char title[256]; + ImFormatString(title, IM_ARRAYSIZE(title), "%s/DockSpace_%08X", window->Name, id); + + if (node->Windows.Size > 0 || node->IsSplitNode()) + PushStyleColor(ImGuiCol_ChildBg, IM_COL32(0, 0, 0, 0)); + PushStyleVar(ImGuiStyleVar_ChildBorderSize, 0.0f); + Begin(title, NULL, window_flags); + PopStyleVar(); + if (node->Windows.Size > 0 || node->IsSplitNode()) + PopStyleColor(); + + ImGuiWindow* host_window = g.CurrentWindow; + host_window->DockNodeAsHost = node; + host_window->ChildId = window->GetID(title); + node->HostWindow = host_window; + node->OnlyNodeWithWindows = NULL; + + IM_ASSERT(node->IsRootNode()); + DockNodeUpdate(node); + + g.WithinEndChild = true; + End(); + g.WithinEndChild = false; +} + +// Tips: Use with ImGuiDockNodeFlags_PassthruCentralNode! +// The limitation with this call is that your window won't have a menu bar. +// Even though we could pass window flags, it would also require the user to be able to call BeginMenuBar() somehow meaning we can't Begin/End in a single function. +// But you can also use BeginMainMenuBar(). If you really want a menu bar inside the same window as the one hosting the dockspace, you will need to copy this code somewhere and tweak it. +ImGuiID ImGui::DockSpaceOverViewport(ImGuiViewport* viewport, ImGuiDockNodeFlags dockspace_flags, const ImGuiWindowClass* window_class) +{ + if (viewport == NULL) + viewport = GetMainViewport(); + + SetNextWindowPos(viewport->GetWorkPos()); + SetNextWindowSize(viewport->GetWorkSize()); + SetNextWindowViewport(viewport->ID); + + ImGuiWindowFlags host_window_flags = 0; + host_window_flags |= ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoDocking; + host_window_flags |= ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoNavFocus; + if (dockspace_flags & ImGuiDockNodeFlags_PassthruCentralNode) + host_window_flags |= ImGuiWindowFlags_NoBackground; + + char label[32]; + ImFormatString(label, IM_ARRAYSIZE(label), "DockSpaceViewport_%08X", viewport->ID); + + PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f); + PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f); + PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f)); + Begin(label, NULL, host_window_flags); + PopStyleVar(3); + + ImGuiID dockspace_id = GetID("DockSpace"); + DockSpace(dockspace_id, ImVec2(0.0f, 0.0f), dockspace_flags, window_class); + End(); + + return dockspace_id; +} + +//----------------------------------------------------------------------------- +// Docking: Builder Functions +//----------------------------------------------------------------------------- +// Very early end-user API to manipulate dock nodes. +// Only available in imgui_internal.h. Expect this API to change/break! +// It is expected that those functions are all called _before_ the dockspace node submission. +//----------------------------------------------------------------------------- +// - DockBuilderDockWindow() +// - DockBuilderGetNode() +// - DockBuilderSetNodePos() +// - DockBuilderSetNodeSize() +// - DockBuilderAddNode() +// - DockBuilderRemoveNode() +// - DockBuilderRemoveNodeChildNodes() +// - DockBuilderRemoveNodeDockedWindows() +// - DockBuilderSplitNode() +// - DockBuilderCopyNodeRec() +// - DockBuilderCopyNode() +// - DockBuilderCopyWindowSettings() +// - DockBuilderCopyDockSpace() +// - DockBuilderFinish() +//----------------------------------------------------------------------------- + +void ImGui::DockBuilderDockWindow(const char* window_name, ImGuiID node_id) +{ + // We don't preserve relative order of multiple docked windows (by clearing DockOrder back to -1) + ImGuiID window_id = ImHashStr(window_name); + if (ImGuiWindow* window = FindWindowByID(window_id)) + { + // Apply to created window + SetWindowDock(window, node_id, ImGuiCond_Always); + window->DockOrder = -1; + } + else + { + // Apply to settings + ImGuiWindowSettings* settings = FindWindowSettings(window_id); + if (settings == NULL) + settings = CreateNewWindowSettings(window_name); + settings->DockId = node_id; + settings->DockOrder = -1; + } +} + +ImGuiDockNode* ImGui::DockBuilderGetNode(ImGuiID node_id) +{ + ImGuiContext* ctx = GImGui; + return DockContextFindNodeByID(ctx, node_id); +} + +void ImGui::DockBuilderSetNodePos(ImGuiID node_id, ImVec2 pos) +{ + ImGuiContext* ctx = GImGui; + ImGuiDockNode* node = DockContextFindNodeByID(ctx, node_id); + if (node == NULL) + return; + node->Pos = pos; + node->AuthorityForPos = ImGuiDataAuthority_DockNode; +} + +void ImGui::DockBuilderSetNodeSize(ImGuiID node_id, ImVec2 size) +{ + ImGuiContext* ctx = GImGui; + ImGuiDockNode* node = DockContextFindNodeByID(ctx, node_id); + if (node == NULL) + return; + IM_ASSERT(size.x > 0.0f && size.y > 0.0f); + node->Size = node->SizeRef = size; + node->AuthorityForSize = ImGuiDataAuthority_DockNode; +} + +// Make sure to use the ImGuiDockNodeFlags_DockSpace flag to create a dockspace node! Otherwise this will create a floating node! +// - Floating node: you can then call DockBuilderSetNodePos()/DockBuilderSetNodeSize() to position and size the floating node. +// - Dockspace node: calling DockBuilderSetNodePos() is unnecessary. +// - If you intend to split a node immediately after creation using DockBuilderSplitNode(), make sure to call DockBuilderSetNodeSize() beforehand! +// For various reason, the splitting code currently needs a base size otherwise space may not be allocated as precisely as you would expect. +// - Use (id == 0) to let the system allocate a node identifier. +ImGuiID ImGui::DockBuilderAddNode(ImGuiID id, ImGuiDockNodeFlags flags) +{ + ImGuiContext* ctx = GImGui; + ImGuiDockNode* node = NULL; + if (flags & ImGuiDockNodeFlags_DockSpace) + { + DockSpace(id, ImVec2(0, 0), (flags & ~ImGuiDockNodeFlags_DockSpace) | ImGuiDockNodeFlags_KeepAliveOnly); + node = DockContextFindNodeByID(ctx, id); + } + else + { + if (id != 0) + node = DockContextFindNodeByID(ctx, id); + if (!node) + node = DockContextAddNode(ctx, id); + node->LocalFlags = flags; + } + node->LastFrameAlive = ctx->FrameCount; // Set this otherwise BeginDocked will undock during the same frame. + return node->ID; +} + +void ImGui::DockBuilderRemoveNode(ImGuiID node_id) +{ + ImGuiContext* ctx = GImGui; + ImGuiDockNode* node = DockContextFindNodeByID(ctx, node_id); + if (node == NULL) + return; + DockBuilderRemoveNodeDockedWindows(node_id, true); + DockBuilderRemoveNodeChildNodes(node_id); + if (node->IsCentralNode() && node->ParentNode) + node->ParentNode->LocalFlags |= ImGuiDockNodeFlags_CentralNode; + DockContextRemoveNode(ctx, node, true); +} + +// root_id = 0 to remove all, root_id != 0 to remove child of given node. +void ImGui::DockBuilderRemoveNodeChildNodes(ImGuiID root_id) +{ + ImGuiContext* ctx = GImGui; + ImGuiDockContext* dc = &ctx->DockContext; + + ImGuiDockNode* root_node = root_id ? DockContextFindNodeByID(ctx, root_id) : NULL; + if (root_id && root_node == NULL) + return; + bool has_central_node = false; + + ImGuiDataAuthority backup_root_node_authority_for_pos = root_node ? root_node->AuthorityForPos : ImGuiDataAuthority_Auto; + ImGuiDataAuthority backup_root_node_authority_for_size = root_node ? root_node->AuthorityForSize : ImGuiDataAuthority_Auto; + + // Process active windows + ImVector nodes_to_remove; + for (int n = 0; n < dc->Nodes.Data.Size; n++) + if (ImGuiDockNode* node = (ImGuiDockNode*)dc->Nodes.Data[n].val_p) + { + bool want_removal = (root_id == 0) || (node->ID != root_id && DockNodeGetRootNode(node)->ID == root_id); + if (want_removal) + { + if (node->IsCentralNode()) + has_central_node = true; + if (root_id != 0) + DockContextQueueNotifyRemovedNode(ctx, node); + if (root_node) + DockNodeMoveWindows(root_node, node); + nodes_to_remove.push_back(node); + } + } + + // DockNodeMoveWindows->DockNodeAddWindow will normally set those when reaching two windows (which is only adequate during interactive merge) + // Make sure we don't lose our current pos/size. (FIXME-DOCK: Consider tidying up that code in DockNodeAddWindow instead) + if (root_node) + { + root_node->AuthorityForPos = backup_root_node_authority_for_pos; + root_node->AuthorityForSize = backup_root_node_authority_for_size; + } + + // Apply to settings + for (ImGuiWindowSettings* settings = ctx->SettingsWindows.begin(); settings != NULL; settings = ctx->SettingsWindows.next_chunk(settings)) + if (ImGuiID window_settings_dock_id = settings->DockId) + for (int n = 0; n < nodes_to_remove.Size; n++) + if (nodes_to_remove[n]->ID == window_settings_dock_id) + { + settings->DockId = root_id; + break; + } + + // Not really efficient, but easier to destroy a whole hierarchy considering DockContextRemoveNode is attempting to merge nodes + if (nodes_to_remove.Size > 1) + ImQsort(nodes_to_remove.Data, nodes_to_remove.Size, sizeof(ImGuiDockNode*), DockNodeComparerDepthMostFirst); + for (int n = 0; n < nodes_to_remove.Size; n++) + DockContextRemoveNode(ctx, nodes_to_remove[n], false); + + if (root_id == 0) + { + dc->Nodes.Clear(); + dc->Requests.clear(); + } + else if (has_central_node) + { + root_node->LocalFlags |= ImGuiDockNodeFlags_CentralNode; + root_node->CentralNode = root_node; + } +} + +void ImGui::DockBuilderRemoveNodeDockedWindows(ImGuiID root_id, bool clear_settings_refs) +{ + // Clear references in settings + ImGuiContext* ctx = GImGui; + ImGuiContext& g = *ctx; + if (clear_settings_refs) + { + for (ImGuiWindowSettings* settings = g.SettingsWindows.begin(); settings != NULL; settings = g.SettingsWindows.next_chunk(settings)) + { + bool want_removal = (root_id == 0) || (settings->DockId == root_id); + if (!want_removal && settings->DockId != 0) + if (ImGuiDockNode* node = DockContextFindNodeByID(ctx, settings->DockId)) + if (DockNodeGetRootNode(node)->ID == root_id) + want_removal = true; + if (want_removal) + settings->DockId = 0; + } + } + + // Clear references in windows + for (int n = 0; n < g.Windows.Size; n++) + { + ImGuiWindow* window = g.Windows[n]; + bool want_removal = (root_id == 0) || (window->DockNode && DockNodeGetRootNode(window->DockNode)->ID == root_id) || (window->DockNodeAsHost && window->DockNodeAsHost->ID == root_id); + if (want_removal) + { + const ImGuiID backup_dock_id = window->DockId; + IM_UNUSED(backup_dock_id); + DockContextProcessUndockWindow(ctx, window, clear_settings_refs); + if (!clear_settings_refs) + IM_ASSERT(window->DockId == backup_dock_id); + } + } +} + +// If 'out_id_at_dir' or 'out_id_at_opposite_dir' are non NULL, the function will write out the ID of the two new nodes created. +// Return value is ID of the node at the specified direction, so same as (*out_id_at_dir) if that pointer is set. +// FIXME-DOCK: We are not exposing nor using split_outer. +ImGuiID ImGui::DockBuilderSplitNode(ImGuiID id, ImGuiDir split_dir, float size_ratio_for_node_at_dir, ImGuiID* out_id_at_dir, ImGuiID* out_id_at_opposite_dir) +{ + ImGuiContext* ctx = GImGui; + IM_ASSERT(split_dir != ImGuiDir_None); + IMGUI_DEBUG_LOG_DOCKING("DockBuilderSplitNode node 0x%08X, split_dir %d\n", id, split_dir); + + ImGuiDockNode* node = DockContextFindNodeByID(ctx, id); + if (node == NULL) + { + IM_ASSERT(node != NULL); + return 0; + } + + IM_ASSERT(!node->IsSplitNode()); // Assert if already Split + + ImGuiDockRequest req; + req.Type = ImGuiDockRequestType_Split; + req.DockTargetWindow = NULL; + req.DockTargetNode = node; + req.DockPayload = NULL; + req.DockSplitDir = split_dir; + req.DockSplitRatio = ImSaturate((split_dir == ImGuiDir_Left || split_dir == ImGuiDir_Up) ? size_ratio_for_node_at_dir : 1.0f - size_ratio_for_node_at_dir); + req.DockSplitOuter = false; + DockContextProcessDock(ctx, &req); + + ImGuiID id_at_dir = node->ChildNodes[(split_dir == ImGuiDir_Left || split_dir == ImGuiDir_Up) ? 0 : 1]->ID; + ImGuiID id_at_opposite_dir = node->ChildNodes[(split_dir == ImGuiDir_Left || split_dir == ImGuiDir_Up) ? 1 : 0]->ID; + if (out_id_at_dir) + *out_id_at_dir = id_at_dir; + if (out_id_at_opposite_dir) + *out_id_at_opposite_dir = id_at_opposite_dir; + return id_at_dir; +} + +static ImGuiDockNode* DockBuilderCopyNodeRec(ImGuiDockNode* src_node, ImGuiID dst_node_id_if_known, ImVector* out_node_remap_pairs) +{ + ImGuiContext* ctx = GImGui; + ImGuiDockNode* dst_node = ImGui::DockContextAddNode(ctx, dst_node_id_if_known); + dst_node->SharedFlags = src_node->SharedFlags; + dst_node->LocalFlags = src_node->LocalFlags; + dst_node->Pos = src_node->Pos; + dst_node->Size = src_node->Size; + dst_node->SizeRef = src_node->SizeRef; + dst_node->SplitAxis = src_node->SplitAxis; + + out_node_remap_pairs->push_back(src_node->ID); + out_node_remap_pairs->push_back(dst_node->ID); + + for (int child_n = 0; child_n < IM_ARRAYSIZE(src_node->ChildNodes); child_n++) + if (src_node->ChildNodes[child_n]) + { + dst_node->ChildNodes[child_n] = DockBuilderCopyNodeRec(src_node->ChildNodes[child_n], 0, out_node_remap_pairs); + dst_node->ChildNodes[child_n]->ParentNode = dst_node; + } + + IMGUI_DEBUG_LOG_DOCKING("Fork node %08X -> %08X (%d childs)\n", src_node->ID, dst_node->ID, dst_node->IsSplitNode() ? 2 : 0); + return dst_node; +} + +void ImGui::DockBuilderCopyNode(ImGuiID src_node_id, ImGuiID dst_node_id, ImVector* out_node_remap_pairs) +{ + ImGuiContext* ctx = GImGui; + IM_ASSERT(src_node_id != 0); + IM_ASSERT(dst_node_id != 0); + IM_ASSERT(out_node_remap_pairs != NULL); + + ImGuiDockNode* src_node = DockContextFindNodeByID(ctx, src_node_id); + IM_ASSERT(src_node != NULL); + + out_node_remap_pairs->clear(); + DockBuilderRemoveNode(dst_node_id); + DockBuilderCopyNodeRec(src_node, dst_node_id, out_node_remap_pairs); + + IM_ASSERT((out_node_remap_pairs->Size % 2) == 0); +} + +void ImGui::DockBuilderCopyWindowSettings(const char* src_name, const char* dst_name) +{ + ImGuiWindow* src_window = FindWindowByName(src_name); + if (src_window == NULL) + return; + if (ImGuiWindow* dst_window = FindWindowByName(dst_name)) + { + dst_window->Pos = src_window->Pos; + dst_window->Size = src_window->Size; + dst_window->SizeFull = src_window->SizeFull; + dst_window->Collapsed = src_window->Collapsed; + } + else if (ImGuiWindowSettings* dst_settings = FindOrCreateWindowSettings(dst_name)) + { + ImVec2ih window_pos_2ih = ImVec2ih(src_window->Pos); + if (src_window->ViewportId != 0 && src_window->ViewportId != IMGUI_VIEWPORT_DEFAULT_ID) + { + dst_settings->ViewportPos = window_pos_2ih; + dst_settings->ViewportId = src_window->ViewportId; + dst_settings->Pos = ImVec2ih(0, 0); + } + else + { + dst_settings->Pos = window_pos_2ih; + } + dst_settings->Size = ImVec2ih(src_window->SizeFull); + dst_settings->Collapsed = src_window->Collapsed; + } +} + +// FIXME: Will probably want to change this signature, in particular how the window remapping pairs are passed. +void ImGui::DockBuilderCopyDockSpace(ImGuiID src_dockspace_id, ImGuiID dst_dockspace_id, ImVector* in_window_remap_pairs) +{ + IM_ASSERT(src_dockspace_id != 0); + IM_ASSERT(dst_dockspace_id != 0); + IM_ASSERT(in_window_remap_pairs != NULL); + IM_ASSERT((in_window_remap_pairs->Size % 2) == 0); + + // Duplicate entire dock + // FIXME: When overwriting dst_dockspace_id, windows that aren't part of our dockspace window class but that are docked in a same node will be split apart, + // whereas we could attempt to at least keep them together in a new, same floating node. + ImVector node_remap_pairs; + DockBuilderCopyNode(src_dockspace_id, dst_dockspace_id, &node_remap_pairs); + + // Attempt to transition all the upcoming windows associated to dst_dockspace_id into the newly created hierarchy of dock nodes + // (The windows associated to src_dockspace_id are staying in place) + ImVector src_windows; + for (int remap_window_n = 0; remap_window_n < in_window_remap_pairs->Size; remap_window_n += 2) + { + const char* src_window_name = (*in_window_remap_pairs)[remap_window_n]; + const char* dst_window_name = (*in_window_remap_pairs)[remap_window_n + 1]; + ImGuiID src_window_id = ImHashStr(src_window_name); + src_windows.push_back(src_window_id); + + // Search in the remapping tables + ImGuiID src_dock_id = 0; + if (ImGuiWindow* src_window = FindWindowByID(src_window_id)) + src_dock_id = src_window->DockId; + else if (ImGuiWindowSettings* src_window_settings = FindWindowSettings(src_window_id)) + src_dock_id = src_window_settings->DockId; + ImGuiID dst_dock_id = 0; + for (int dock_remap_n = 0; dock_remap_n < node_remap_pairs.Size; dock_remap_n += 2) + if (node_remap_pairs[dock_remap_n] == src_dock_id) + { + dst_dock_id = node_remap_pairs[dock_remap_n + 1]; + //node_remap_pairs[dock_remap_n] = node_remap_pairs[dock_remap_n + 1] = 0; // Clear + break; + } + + if (dst_dock_id != 0) + { + // Docked windows gets redocked into the new node hierarchy. + IMGUI_DEBUG_LOG_DOCKING("Remap live window '%s' 0x%08X -> '%s' 0x%08X\n", src_window_name, src_dock_id, dst_window_name, dst_dock_id); + DockBuilderDockWindow(dst_window_name, dst_dock_id); + } + else + { + // Floating windows gets their settings transferred (regardless of whether the new window already exist or not) + // When this is leading to a Copy and not a Move, we would get two overlapping floating windows. Could we possibly dock them together? + IMGUI_DEBUG_LOG_DOCKING("Remap window settings '%s' -> '%s'\n", src_window_name, dst_window_name); + DockBuilderCopyWindowSettings(src_window_name, dst_window_name); + } + } + + // Anything else in the source nodes of 'node_remap_pairs' are windows that were docked in src_dockspace_id but are not owned by it (unaffiliated windows, e.g. "ImGui Demo") + // Find those windows and move to them to the cloned dock node. This may be optional? + for (int dock_remap_n = 0; dock_remap_n < node_remap_pairs.Size; dock_remap_n += 2) + if (ImGuiID src_dock_id = node_remap_pairs[dock_remap_n]) + { + ImGuiID dst_dock_id = node_remap_pairs[dock_remap_n + 1]; + ImGuiDockNode* node = DockBuilderGetNode(src_dock_id); + for (int window_n = 0; window_n < node->Windows.Size; window_n++) + { + ImGuiWindow* window = node->Windows[window_n]; + if (src_windows.contains(window->ID)) + continue; + + // Docked windows gets redocked into the new node hierarchy. + IMGUI_DEBUG_LOG_DOCKING("Remap window '%s' %08X -> %08X\n", window->Name, src_dock_id, dst_dock_id); + DockBuilderDockWindow(window->Name, dst_dock_id); + } + } +} + +void ImGui::DockBuilderFinish(ImGuiID root_id) +{ + ImGuiContext* ctx = GImGui; + //DockContextRebuild(ctx); + DockContextBuildAddWindowsToNodes(ctx, root_id); +} + +//----------------------------------------------------------------------------- +// Docking: Begin/End Support Functions (called from Begin/End) +//----------------------------------------------------------------------------- +// - GetWindowAlwaysWantOwnTabBar() +// - DockContextBindNodeToWindow() +// - BeginDocked() +// - BeginDockableDragDropSource() +// - BeginDockableDragDropTarget() +//----------------------------------------------------------------------------- + +bool ImGui::GetWindowAlwaysWantOwnTabBar(ImGuiWindow* window) +{ + ImGuiContext& g = *GImGui; + if (g.IO.ConfigDockingAlwaysTabBar || window->WindowClass.DockingAlwaysTabBar) + if ((window->Flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoDocking)) == 0) + if (!window->IsFallbackWindow) // We don't support AlwaysTabBar on the fallback/implicit window to avoid unused dock-node overhead/noise + return true; + return false; +} + +static ImGuiDockNode* ImGui::DockContextBindNodeToWindow(ImGuiContext* ctx, ImGuiWindow* window) +{ + ImGuiContext& g = *ctx; + ImGuiDockNode* node = DockContextFindNodeByID(ctx, window->DockId); + IM_ASSERT(window->DockNode == NULL); + + // We should not be docking into a split node (SetWindowDock should avoid this) + if (node && node->IsSplitNode()) + { + DockContextProcessUndockWindow(ctx, window); + return NULL; + } + + // Create node + if (node == NULL) + { + node = DockContextAddNode(ctx, window->DockId); + node->AuthorityForPos = node->AuthorityForSize = node->AuthorityForViewport = ImGuiDataAuthority_Window; + node->LastFrameAlive = g.FrameCount; + } + + // If the node just turned visible and is part of a hierarchy, it doesn't have a Size assigned by DockNodeTreeUpdatePosSize() yet, + // so we're forcing a Pos/Size update from the first ancestor that is already visible (often it will be the root node). + // If we don't do this, the window will be assigned a zero-size on its first frame, which won't ideally warm up the layout. + // This is a little wonky because we don't normally update the Pos/Size of visible node mid-frame. + if (!node->IsVisible) + { + ImGuiDockNode* ancestor_node = node; + while (!ancestor_node->IsVisible) + { + ancestor_node->IsVisible = true; + ancestor_node->MarkedForPosSizeWrite = true; + if (ancestor_node->ParentNode) + ancestor_node = ancestor_node->ParentNode; + } + IM_ASSERT(ancestor_node->Size.x > 0.0f && ancestor_node->Size.y > 0.0f); + DockNodeTreeUpdatePosSize(ancestor_node, ancestor_node->Pos, ancestor_node->Size, true); + } + + // Add window to node + DockNodeAddWindow(node, window, true); + IM_ASSERT(node == window->DockNode); + return node; +} + +void ImGui::BeginDocked(ImGuiWindow* window, bool* p_open) +{ + ImGuiContext* ctx = GImGui; + ImGuiContext& g = *ctx; + + const bool auto_dock_node = GetWindowAlwaysWantOwnTabBar(window); + if (auto_dock_node) + { + if (window->DockId == 0) + { + IM_ASSERT(window->DockNode == NULL); + window->DockId = DockContextGenNodeID(ctx); + } + } + else + { + // Calling SetNextWindowPos() undock windows by default (by setting PosUndock) + bool want_undock = false; + want_undock |= (window->Flags & ImGuiWindowFlags_NoDocking) != 0; + want_undock |= (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasPos) && (window->SetWindowPosAllowFlags & g.NextWindowData.PosCond) && g.NextWindowData.PosUndock; + if (want_undock) + { + DockContextProcessUndockWindow(ctx, window); + return; + } + } + + // Bind to our dock node + ImGuiDockNode* node = window->DockNode; + if (node != NULL) + IM_ASSERT(window->DockId == node->ID); + if (window->DockId != 0 && node == NULL) + { + node = DockContextBindNodeToWindow(ctx, window); + if (node == NULL) + return; + } + +#if 0 + // Undock if the ImGuiDockNodeFlags_NoDockingInCentralNode got set + if (node->IsCentralNode && (node->Flags & ImGuiDockNodeFlags_NoDockingInCentralNode)) + { + DockContextProcessUndockWindow(ctx, window); + return; + } +#endif + + // Undock if our dockspace node disappeared + // Note how we are testing for LastFrameAlive and NOT LastFrameActive. A DockSpace node can be maintained alive while being inactive with ImGuiDockNodeFlags_KeepAliveOnly. + if (node->LastFrameAlive < g.FrameCount) + { + // If the window has been orphaned, transition the docknode to an implicit node processed in DockContextUpdateDocking() + ImGuiDockNode* root_node = DockNodeGetRootNode(node); + if (root_node->LastFrameAlive < g.FrameCount) + { + DockContextProcessUndockWindow(ctx, window); + } + else + { + window->DockIsActive = true; + window->DockTabIsVisible = false; + } + return; + } + + // Fast path return. It is common for windows to hold on a persistent DockId but be the only visible window, + // and never create neither a host window neither a tab bar. + // FIXME-DOCK: replace ->HostWindow NULL compare with something more explicit (~was initially intended as a first frame test) + if (node->HostWindow == NULL) + { + window->DockIsActive = (node->State == ImGuiDockNodeState_HostWindowHiddenBecauseWindowsAreResizing); + window->DockTabIsVisible = false; + return; + } + + // We can have zero-sized nodes (e.g. children of a small-size dockspace) + IM_ASSERT(node->HostWindow); + IM_ASSERT(node->IsLeafNode()); + IM_ASSERT(node->Size.x >= 0.0f && node->Size.y >= 0.0f); + node->State = ImGuiDockNodeState_HostWindowVisible; + + // Undock if we are submitted earlier than the host window + if (window->BeginOrderWithinContext < node->HostWindow->BeginOrderWithinContext) + { + DockContextProcessUndockWindow(ctx, window); + return; + } + + // Position/Size window + SetNextWindowPos(node->Pos); + SetNextWindowSize(node->Size); + g.NextWindowData.PosUndock = false; // Cancel implicit undocking of SetNextWindowPos() + window->DockIsActive = true; + window->DockTabIsVisible = false; + if (node->SharedFlags & ImGuiDockNodeFlags_KeepAliveOnly) + return; + + // When the window is selected we mark it as visible. + if (node->VisibleWindow == window) + window->DockTabIsVisible = true; + + // Update window flag + IM_ASSERT((window->Flags & ImGuiWindowFlags_ChildWindow) == 0); + window->Flags |= ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_AlwaysUseWindowPadding | ImGuiWindowFlags_NoResize; + if (node->IsHiddenTabBar() || node->IsNoTabBar()) + window->Flags |= ImGuiWindowFlags_NoTitleBar; + else + window->Flags &= ~ImGuiWindowFlags_NoTitleBar; // Clear the NoTitleBar flag in case the user set it: confusingly enough we need a title bar height so we are correctly offset, but it won't be displayed! + + // Save new dock order only if the tab bar has been visible once. + // This allows multiple windows to be created in the same frame and have their respective dock orders preserved. + if (node->TabBar && node->TabBar->CurrFrameVisible != -1) + window->DockOrder = (short)DockNodeGetTabOrder(window); + + if ((node->WantCloseAll || node->WantCloseTabId == window->ID) && p_open != NULL) + *p_open = false; + + // Update ChildId to allow returning from Child to Parent with Escape + ImGuiWindow* parent_window = window->DockNode->HostWindow; + window->ChildId = parent_window->GetID(window->Name); +} + +void ImGui::BeginDockableDragDropSource(ImGuiWindow* window) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(g.ActiveId == window->MoveId); + IM_ASSERT(g.MovingWindow == window); + + window->DC.LastItemId = window->MoveId; + window = window->RootWindow; + IM_ASSERT((window->Flags & ImGuiWindowFlags_NoDocking) == 0); + bool is_drag_docking = (g.IO.ConfigDockingWithShift) || ImRect(0, 0, window->SizeFull.x, GetFrameHeight()).Contains(g.ActiveIdClickOffset); + if (is_drag_docking && BeginDragDropSource(ImGuiDragDropFlags_SourceNoPreviewTooltip | ImGuiDragDropFlags_SourceNoHoldToOpenOthers | ImGuiDragDropFlags_SourceAutoExpirePayload)) + { + SetDragDropPayload(IMGUI_PAYLOAD_TYPE_WINDOW, &window, sizeof(window)); + EndDragDropSource(); + } +} + +void ImGui::BeginDockableDragDropTarget(ImGuiWindow* window) +{ + ImGuiContext* ctx = GImGui; + ImGuiContext& g = *ctx; + + //IM_ASSERT(window->RootWindow == window); // May also be a DockSpace + IM_ASSERT((window->Flags & ImGuiWindowFlags_NoDocking) == 0); + if (!g.DragDropActive) + return; + if (!BeginDragDropTargetCustom(window->Rect(), window->ID)) + return; + + // Peek into the payload before calling AcceptDragDropPayload() so we can handle overlapping dock nodes with filtering + // (this is a little unusual pattern, normally most code would call AcceptDragDropPayload directly) + const ImGuiPayload* payload = &g.DragDropPayload; + if (!payload->IsDataType(IMGUI_PAYLOAD_TYPE_WINDOW) || !DockNodeIsDropAllowed(window, *(ImGuiWindow**)payload->Data)) + { + EndDragDropTarget(); + return; + } + + ImGuiWindow* payload_window = *(ImGuiWindow**)payload->Data; + if (AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_WINDOW, ImGuiDragDropFlags_AcceptBeforeDelivery | ImGuiDragDropFlags_AcceptNoDrawDefaultRect)) + { + // Select target node + ImGuiDockNode* node = NULL; + bool allow_null_target_node = false; + if (window->DockNodeAsHost) + node = DockNodeTreeFindNodeByPos(window->DockNodeAsHost, g.IO.MousePos); + else if (window->DockNode) // && window->DockIsActive) + node = window->DockNode; + else + allow_null_target_node = true; // Dock into a regular window + + const ImRect explicit_target_rect = (node && node->TabBar && !node->IsHiddenTabBar() && !node->IsNoTabBar()) ? node->TabBar->BarRect : ImRect(window->Pos, window->Pos + ImVec2(window->Size.x, GetFrameHeight())); + const bool is_explicit_target = g.IO.ConfigDockingWithShift || IsMouseHoveringRect(explicit_target_rect.Min, explicit_target_rect.Max); + + // Preview docking request and find out split direction/ratio + //const bool do_preview = true; // Ignore testing for payload->IsPreview() which removes one frame of delay, but breaks overlapping drop targets within the same window. + const bool do_preview = payload->IsPreview() || payload->IsDelivery(); + if (do_preview && (node != NULL || allow_null_target_node)) + { + ImGuiDockPreviewData split_inner; + ImGuiDockPreviewData split_outer; + ImGuiDockPreviewData* split_data = &split_inner; + if (node && (node->ParentNode || node->IsCentralNode())) + if (ImGuiDockNode* root_node = DockNodeGetRootNode(node)) + { + DockNodePreviewDockSetup(window, root_node, payload_window, &split_outer, is_explicit_target, true); + if (split_outer.IsSplitDirExplicit) + split_data = &split_outer; + } + DockNodePreviewDockSetup(window, node, payload_window, &split_inner, is_explicit_target, false); + if (split_data == &split_outer) + split_inner.IsDropAllowed = false; + + // Draw inner then outer, so that previewed tab (in inner data) will be behind the outer drop boxes + DockNodePreviewDockRender(window, node, payload_window, &split_inner); + DockNodePreviewDockRender(window, node, payload_window, &split_outer); + + // Queue docking request + if (split_data->IsDropAllowed && payload->IsDelivery()) + DockContextQueueDock(ctx, window, split_data->SplitNode, payload_window, split_data->SplitDir, split_data->SplitRatio, split_data == &split_outer); + } + } + EndDragDropTarget(); +} + +//----------------------------------------------------------------------------- +// Docking: Settings +//----------------------------------------------------------------------------- +// - DockSettingsRenameNodeReferences() +// - DockSettingsRemoveNodeReferences() +// - DockSettingsFindNodeSettings() +// - DockSettingsHandler_ApplyAll() +// - DockSettingsHandler_ReadOpen() +// - DockSettingsHandler_ReadLine() +// - DockSettingsHandler_DockNodeToSettings() +// - DockSettingsHandler_WriteAll() +//----------------------------------------------------------------------------- + +static void ImGui::DockSettingsRenameNodeReferences(ImGuiID old_node_id, ImGuiID new_node_id) +{ + ImGuiContext& g = *GImGui; + IMGUI_DEBUG_LOG_DOCKING("DockSettingsRenameNodeReferences: from 0x%08X -> to 0x%08X\n", old_node_id, new_node_id); + for (int window_n = 0; window_n < g.Windows.Size; window_n++) + { + ImGuiWindow* window = g.Windows[window_n]; + if (window->DockId == old_node_id && window->DockNode == NULL) + window->DockId = new_node_id; + } + //// FIXME-OPT: We could remove this loop by storing the index in the map + for (ImGuiWindowSettings* settings = g.SettingsWindows.begin(); settings != NULL; settings = g.SettingsWindows.next_chunk(settings)) + if (settings->DockId == old_node_id) + settings->DockId = new_node_id; +} + +// Remove references stored in ImGuiWindowSettings to the given ImGuiDockNodeSettings +static void ImGui::DockSettingsRemoveNodeReferences(ImGuiID* node_ids, int node_ids_count) +{ + ImGuiContext& g = *GImGui; + int found = 0; + //// FIXME-OPT: We could remove this loop by storing the index in the map + for (ImGuiWindowSettings* settings = g.SettingsWindows.begin(); settings != NULL; settings = g.SettingsWindows.next_chunk(settings)) + for (int node_n = 0; node_n < node_ids_count; node_n++) + if (settings->DockId == node_ids[node_n]) + { + settings->DockId = 0; + settings->DockOrder = -1; + if (++found < node_ids_count) + break; + return; + } +} + +static ImGuiDockNodeSettings* ImGui::DockSettingsFindNodeSettings(ImGuiContext* ctx, ImGuiID id) +{ + // FIXME-OPT + ImGuiDockContext* dc = &ctx->DockContext; + for (int n = 0; n < dc->NodesSettings.Size; n++) + if (dc->NodesSettings[n].ID == id) + return &dc->NodesSettings[n]; + return NULL; +} + +// Clear settings data +static void ImGui::DockSettingsHandler_ClearAll(ImGuiContext* ctx, ImGuiSettingsHandler*) +{ + ImGuiDockContext* dc = &ctx->DockContext; + dc->NodesSettings.clear(); + DockContextClearNodes(ctx, 0, true); +} + +// Recreate nodes based on settings data +static void ImGui::DockSettingsHandler_ApplyAll(ImGuiContext* ctx, ImGuiSettingsHandler*) +{ + // Prune settings at boot time only + ImGuiDockContext* dc = &ctx->DockContext; + if (ctx->Windows.Size == 0) + DockContextPruneUnusedSettingsNodes(ctx); + DockContextBuildNodesFromSettings(ctx, dc->NodesSettings.Data, dc->NodesSettings.Size); + DockContextBuildAddWindowsToNodes(ctx, 0); +} + +static void* ImGui::DockSettingsHandler_ReadOpen(ImGuiContext*, ImGuiSettingsHandler*, const char* name) +{ + if (strcmp(name, "Data") != 0) + return NULL; + return (void*)1; +} + +static void ImGui::DockSettingsHandler_ReadLine(ImGuiContext* ctx, ImGuiSettingsHandler*, void*, const char* line) +{ + char c = 0; + int x = 0, y = 0; + int r = 0; + + // Parsing, e.g. + // " DockNode ID=0x00000001 Pos=383,193 Size=201,322 Split=Y,0.506 " + // " DockNode ID=0x00000002 Parent=0x00000001 " + // Important: this code expect currently fields in a fixed order. + ImGuiDockNodeSettings node; + line = ImStrSkipBlank(line); + if (strncmp(line, "DockNode", 8) == 0) { line = ImStrSkipBlank(line + strlen("DockNode")); } + else if (strncmp(line, "DockSpace", 9) == 0) { line = ImStrSkipBlank(line + strlen("DockSpace")); node.Flags |= ImGuiDockNodeFlags_DockSpace; } + else return; + if (sscanf(line, "ID=0x%08X%n", &node.ID, &r) == 1) { line += r; } else return; + if (sscanf(line, " Parent=0x%08X%n", &node.ParentNodeId, &r) == 1) { line += r; if (node.ParentNodeId == 0) return; } + if (sscanf(line, " Window=0x%08X%n", &node.ParentWindowId, &r) ==1) { line += r; if (node.ParentWindowId == 0) return; } + if (node.ParentNodeId == 0) + { + if (sscanf(line, " Pos=%i,%i%n", &x, &y, &r) == 2) { line += r; node.Pos = ImVec2ih((short)x, (short)y); } else return; + if (sscanf(line, " Size=%i,%i%n", &x, &y, &r) == 2) { line += r; node.Size = ImVec2ih((short)x, (short)y); } else return; + } + else + { + if (sscanf(line, " SizeRef=%i,%i%n", &x, &y, &r) == 2) { line += r; node.SizeRef = ImVec2ih((short)x, (short)y); } + } + if (sscanf(line, " Split=%c%n", &c, &r) == 1) { line += r; if (c == 'X') node.SplitAxis = ImGuiAxis_X; else if (c == 'Y') node.SplitAxis = ImGuiAxis_Y; } + if (sscanf(line, " NoResize=%d%n", &x, &r) == 1) { line += r; if (x != 0) node.Flags |= ImGuiDockNodeFlags_NoResize; } + if (sscanf(line, " CentralNode=%d%n", &x, &r) == 1) { line += r; if (x != 0) node.Flags |= ImGuiDockNodeFlags_CentralNode; } + if (sscanf(line, " NoTabBar=%d%n", &x, &r) == 1) { line += r; if (x != 0) node.Flags |= ImGuiDockNodeFlags_NoTabBar; } + if (sscanf(line, " HiddenTabBar=%d%n", &x, &r) == 1) { line += r; if (x != 0) node.Flags |= ImGuiDockNodeFlags_HiddenTabBar; } + if (sscanf(line, " NoWindowMenuButton=%d%n", &x, &r) == 1) { line += r; if (x != 0) node.Flags |= ImGuiDockNodeFlags_NoWindowMenuButton; } + if (sscanf(line, " NoCloseButton=%d%n", &x, &r) == 1) { line += r; if (x != 0) node.Flags |= ImGuiDockNodeFlags_NoCloseButton; } + if (sscanf(line, " Selected=0x%08X%n", &node.SelectedWindowId,&r) == 1) { line += r; } + if (node.ParentNodeId != 0) + if (ImGuiDockNodeSettings* parent_settings = DockSettingsFindNodeSettings(ctx, node.ParentNodeId)) + node.Depth = parent_settings->Depth + 1; + ctx->DockContext.NodesSettings.push_back(node); +} + +static void DockSettingsHandler_DockNodeToSettings(ImGuiDockContext* dc, ImGuiDockNode* node, int depth) +{ + ImGuiDockNodeSettings node_settings; + IM_ASSERT(depth < (1 << (sizeof(node_settings.Depth) << 3))); + node_settings.ID = node->ID; + node_settings.ParentNodeId = node->ParentNode ? node->ParentNode->ID : 0; + node_settings.ParentWindowId = (node->IsDockSpace() && node->HostWindow && node->HostWindow->ParentWindow) ? node->HostWindow->ParentWindow->ID : 0; + node_settings.SelectedWindowId = node->SelectedTabId; + node_settings.SplitAxis = (signed char)(node->IsSplitNode() ? node->SplitAxis : ImGuiAxis_None); + node_settings.Depth = (char)depth; + node_settings.Flags = (node->LocalFlags & ImGuiDockNodeFlags_SavedFlagsMask_); + node_settings.Pos = ImVec2ih(node->Pos); + node_settings.Size = ImVec2ih(node->Size); + node_settings.SizeRef = ImVec2ih(node->SizeRef); + dc->NodesSettings.push_back(node_settings); + if (node->ChildNodes[0]) + DockSettingsHandler_DockNodeToSettings(dc, node->ChildNodes[0], depth + 1); + if (node->ChildNodes[1]) + DockSettingsHandler_DockNodeToSettings(dc, node->ChildNodes[1], depth + 1); +} + +static void ImGui::DockSettingsHandler_WriteAll(ImGuiContext* ctx, ImGuiSettingsHandler* handler, ImGuiTextBuffer* buf) +{ + ImGuiContext& g = *ctx; + ImGuiDockContext* dc = &ctx->DockContext; + if (!(g.IO.ConfigFlags & ImGuiConfigFlags_DockingEnable)) + return; + + // Gather settings data + // (unlike our windows settings, because nodes are always built we can do a full rewrite of the SettingsNode buffer) + dc->NodesSettings.resize(0); + dc->NodesSettings.reserve(dc->Nodes.Data.Size); + for (int n = 0; n < dc->Nodes.Data.Size; n++) + if (ImGuiDockNode* node = (ImGuiDockNode*)dc->Nodes.Data[n].val_p) + if (node->IsRootNode()) + DockSettingsHandler_DockNodeToSettings(dc, node, 0); + + int max_depth = 0; + for (int node_n = 0; node_n < dc->NodesSettings.Size; node_n++) + max_depth = ImMax((int)dc->NodesSettings[node_n].Depth, max_depth); + + // Write to text buffer + buf->appendf("[%s][Data]\n", handler->TypeName); + for (int node_n = 0; node_n < dc->NodesSettings.Size; node_n++) + { + const int line_start_pos = buf->size(); (void)line_start_pos; + const ImGuiDockNodeSettings* node_settings = &dc->NodesSettings[node_n]; + buf->appendf("%*s%s%*s", node_settings->Depth * 2, "", (node_settings->Flags & ImGuiDockNodeFlags_DockSpace) ? "DockSpace" : "DockNode ", (max_depth - node_settings->Depth) * 2, ""); // Text align nodes to facilitate looking at .ini file + buf->appendf(" ID=0x%08X", node_settings->ID); + if (node_settings->ParentNodeId) + { + buf->appendf(" Parent=0x%08X SizeRef=%d,%d", node_settings->ParentNodeId, node_settings->SizeRef.x, node_settings->SizeRef.y); + } + else + { + if (node_settings->ParentWindowId) + buf->appendf(" Window=0x%08X", node_settings->ParentWindowId); + buf->appendf(" Pos=%d,%d Size=%d,%d", node_settings->Pos.x, node_settings->Pos.y, node_settings->Size.x, node_settings->Size.y); + } + if (node_settings->SplitAxis != ImGuiAxis_None) + buf->appendf(" Split=%c", (node_settings->SplitAxis == ImGuiAxis_X) ? 'X' : 'Y'); + if (node_settings->Flags & ImGuiDockNodeFlags_NoResize) + buf->appendf(" NoResize=1"); + if (node_settings->Flags & ImGuiDockNodeFlags_CentralNode) + buf->appendf(" CentralNode=1"); + if (node_settings->Flags & ImGuiDockNodeFlags_NoTabBar) + buf->appendf(" NoTabBar=1"); + if (node_settings->Flags & ImGuiDockNodeFlags_HiddenTabBar) + buf->appendf(" HiddenTabBar=1"); + if (node_settings->Flags & ImGuiDockNodeFlags_NoWindowMenuButton) + buf->appendf(" NoWindowMenuButton=1"); + if (node_settings->Flags & ImGuiDockNodeFlags_NoCloseButton) + buf->appendf(" NoCloseButton=1"); + if (node_settings->SelectedWindowId) + buf->appendf(" Selected=0x%08X", node_settings->SelectedWindowId); + +#if IMGUI_DEBUG_INI_SETTINGS + // [DEBUG] Include comments in the .ini file to ease debugging + if (ImGuiDockNode* node = DockContextFindNodeByID(ctx, node_settings->ID)) + { + buf->appendf("%*s", ImMax(2, (line_start_pos + 92) - buf->size()), ""); // Align everything + if (node->IsDockSpace() && node->HostWindow && node->HostWindow->ParentWindow) + buf->appendf(" ; in '%s'", node->HostWindow->ParentWindow->Name); + // Iterate settings so we can give info about windows that didn't exist during the session. + int contains_window = 0; + for (ImGuiWindowSettings* settings = g.SettingsWindows.begin(); settings != NULL; settings = g.SettingsWindows.next_chunk(settings)) + if (settings->DockId == node_settings->ID) + { + if (contains_window++ == 0) + buf->appendf(" ; contains "); + buf->appendf("'%s' ", settings->GetName()); + } + } +#endif + buf->appendf("\n"); + } + buf->appendf("\n"); +} + + +//----------------------------------------------------------------------------- +// [SECTION] PLATFORM DEPENDENT HELPERS +//----------------------------------------------------------------------------- + +#if defined(_WIN32) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS) && !defined(IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS) + +#ifdef _MSC_VER +#pragma comment(lib, "user32") +#pragma comment(lib, "kernel32") +#endif + +// Win32 clipboard implementation +// We use g.ClipboardHandlerData for temporary storage to ensure it is freed on Shutdown() +static const char* GetClipboardTextFn_DefaultImpl(void*) +{ + ImGuiContext& g = *GImGui; + g.ClipboardHandlerData.clear(); + if (!::OpenClipboard(NULL)) + return NULL; + HANDLE wbuf_handle = ::GetClipboardData(CF_UNICODETEXT); + if (wbuf_handle == NULL) + { + ::CloseClipboard(); + return NULL; + } + if (const WCHAR* wbuf_global = (const WCHAR*)::GlobalLock(wbuf_handle)) + { + int buf_len = ::WideCharToMultiByte(CP_UTF8, 0, wbuf_global, -1, NULL, 0, NULL, NULL); + g.ClipboardHandlerData.resize(buf_len); + ::WideCharToMultiByte(CP_UTF8, 0, wbuf_global, -1, g.ClipboardHandlerData.Data, buf_len, NULL, NULL); + } + ::GlobalUnlock(wbuf_handle); + ::CloseClipboard(); + return g.ClipboardHandlerData.Data; +} + +static void SetClipboardTextFn_DefaultImpl(void*, const char* text) +{ + if (!::OpenClipboard(NULL)) + return; + const int wbuf_length = ::MultiByteToWideChar(CP_UTF8, 0, text, -1, NULL, 0); + HGLOBAL wbuf_handle = ::GlobalAlloc(GMEM_MOVEABLE, (SIZE_T)wbuf_length * sizeof(WCHAR)); + if (wbuf_handle == NULL) + { + ::CloseClipboard(); + return; + } + WCHAR* wbuf_global = (WCHAR*)::GlobalLock(wbuf_handle); + ::MultiByteToWideChar(CP_UTF8, 0, text, -1, wbuf_global, wbuf_length); + ::GlobalUnlock(wbuf_handle); + ::EmptyClipboard(); + if (::SetClipboardData(CF_UNICODETEXT, wbuf_handle) == NULL) + ::GlobalFree(wbuf_handle); + ::CloseClipboard(); +} + +#elif defined(__APPLE__) && TARGET_OS_OSX && defined(IMGUI_ENABLE_OSX_DEFAULT_CLIPBOARD_FUNCTIONS) + +#include // Use old API to avoid need for separate .mm file +static PasteboardRef main_clipboard = 0; + +// OSX clipboard implementation +// If you enable this you will need to add '-framework ApplicationServices' to your linker command-line! +static void SetClipboardTextFn_DefaultImpl(void*, const char* text) +{ + if (!main_clipboard) + PasteboardCreate(kPasteboardClipboard, &main_clipboard); + PasteboardClear(main_clipboard); + CFDataRef cf_data = CFDataCreate(kCFAllocatorDefault, (const UInt8*)text, strlen(text)); + if (cf_data) + { + PasteboardPutItemFlavor(main_clipboard, (PasteboardItemID)1, CFSTR("public.utf8-plain-text"), cf_data, 0); + CFRelease(cf_data); + } +} + +static const char* GetClipboardTextFn_DefaultImpl(void*) +{ + if (!main_clipboard) + PasteboardCreate(kPasteboardClipboard, &main_clipboard); + PasteboardSynchronize(main_clipboard); + + ItemCount item_count = 0; + PasteboardGetItemCount(main_clipboard, &item_count); + for (ItemCount i = 0; i < item_count; i++) + { + PasteboardItemID item_id = 0; + PasteboardGetItemIdentifier(main_clipboard, i + 1, &item_id); + CFArrayRef flavor_type_array = 0; + PasteboardCopyItemFlavors(main_clipboard, item_id, &flavor_type_array); + for (CFIndex j = 0, nj = CFArrayGetCount(flavor_type_array); j < nj; j++) + { + CFDataRef cf_data; + if (PasteboardCopyItemFlavorData(main_clipboard, item_id, CFSTR("public.utf8-plain-text"), &cf_data) == noErr) + { + ImGuiContext& g = *GImGui; + g.ClipboardHandlerData.clear(); + int length = (int)CFDataGetLength(cf_data); + g.ClipboardHandlerData.resize(length + 1); + CFDataGetBytes(cf_data, CFRangeMake(0, length), (UInt8*)g.ClipboardHandlerData.Data); + g.ClipboardHandlerData[length] = 0; + CFRelease(cf_data); + return g.ClipboardHandlerData.Data; + } + } + } + return NULL; +} + +#else + +// Local Dear ImGui-only clipboard implementation, if user hasn't defined better clipboard handlers. +static const char* GetClipboardTextFn_DefaultImpl(void*) +{ + ImGuiContext& g = *GImGui; + return g.ClipboardHandlerData.empty() ? NULL : g.ClipboardHandlerData.begin(); +} + +static void SetClipboardTextFn_DefaultImpl(void*, const char* text) +{ + ImGuiContext& g = *GImGui; + g.ClipboardHandlerData.clear(); + const char* text_end = text + strlen(text); + g.ClipboardHandlerData.resize((int)(text_end - text) + 1); + memcpy(&g.ClipboardHandlerData[0], text, (size_t)(text_end - text)); + g.ClipboardHandlerData[(int)(text_end - text)] = 0; +} + +#endif + +//----------------------------------------------------------------------------- +// [SECTION] METRICS/DEBUG WINDOW +//----------------------------------------------------------------------------- + +static void RenderViewportThumbnail(ImDrawList* draw_list, ImGuiViewportP* viewport, const ImRect& bb) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + + ImVec2 scale = bb.GetSize() / viewport->Size; + ImVec2 off = bb.Min - viewport->Pos * scale; + float alpha_mul = (viewport->Flags & ImGuiViewportFlags_Minimized) ? 0.30f : 1.00f; + window->DrawList->AddRectFilled(bb.Min, bb.Max, ImGui::GetColorU32(ImGuiCol_Border, alpha_mul * 0.40f)); + for (int i = 0; i != g.Windows.Size; i++) + { + ImGuiWindow* thumb_window = g.Windows[i]; + if (!thumb_window->WasActive || ((thumb_window->Flags & ImGuiWindowFlags_ChildWindow))) + continue; + if (thumb_window->SkipItems && (thumb_window->Flags & ImGuiWindowFlags_ChildWindow)) // FIXME-DOCK: Skip hidden docked windows. Identify those betters. + continue; + if (thumb_window->Viewport != viewport) + continue; + + ImRect thumb_r = thumb_window->Rect(); + ImRect title_r = thumb_window->TitleBarRect(); + ImRect thumb_r_scaled = ImRect(ImFloor(off + thumb_r.Min * scale), ImFloor(off + thumb_r.Max * scale)); + ImRect title_r_scaled = ImRect(ImFloor(off + title_r.Min * scale), ImFloor(off + ImVec2(title_r.Max.x, title_r.Min.y) * scale) + ImVec2(0,5)); // Exaggerate title bar height + thumb_r_scaled.ClipWithFull(bb); + title_r_scaled.ClipWithFull(bb); + const bool window_is_focused = (g.NavWindow && thumb_window->RootWindowForTitleBarHighlight == g.NavWindow->RootWindowForTitleBarHighlight); + window->DrawList->AddRectFilled(thumb_r_scaled.Min, thumb_r_scaled.Max, ImGui::GetColorU32(ImGuiCol_WindowBg, alpha_mul)); + window->DrawList->AddRectFilled(title_r_scaled.Min, title_r_scaled.Max, ImGui::GetColorU32(window_is_focused ? ImGuiCol_TitleBgActive : ImGuiCol_TitleBg, alpha_mul)); + window->DrawList->AddRect(thumb_r_scaled.Min, thumb_r_scaled.Max, ImGui::GetColorU32(ImGuiCol_Border, alpha_mul)); + if (ImGuiWindow* window_for_title = GetWindowForTitleDisplay(thumb_window)) + window->DrawList->AddText(g.Font, g.FontSize * 1.0f, title_r_scaled.Min, ImGui::GetColorU32(ImGuiCol_Text, alpha_mul), window_for_title->Name, ImGui::FindRenderedTextEnd(window_for_title->Name)); + } + draw_list->AddRect(bb.Min, bb.Max, ImGui::GetColorU32(ImGuiCol_Border, alpha_mul)); +} + +void ImGui::ShowViewportThumbnails() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + + // We don't display full monitor bounds (we could, but it often looks awkward), instead we display just enough to cover all of our viewports. + float SCALE = 1.0f / 8.0f; + ImRect bb_full; + //for (int n = 0; n < g.PlatformIO.Monitors.Size; n++) + // bb_full.Add(GetPlatformMonitorMainRect(g.PlatformIO.Monitors[n])); + for (int n = 0; n < g.Viewports.Size; n++) + bb_full.Add(g.Viewports[n]->GetMainRect()); + ImVec2 p = window->DC.CursorPos; + ImVec2 off = p - bb_full.Min * SCALE; + //for (int n = 0; n < g.PlatformIO.Monitors.Size; n++) + // window->DrawList->AddRect(off + g.PlatformIO.Monitors[n].MainPos * SCALE, off + (g.PlatformIO.Monitors[n].MainPos + g.PlatformIO.Monitors[n].MainSize) * SCALE, ImGui::GetColorU32(ImGuiCol_Border)); + for (int n = 0; n < g.Viewports.Size; n++) + { + ImGuiViewportP* viewport = g.Viewports[n]; + ImRect viewport_draw_bb(off + (viewport->Pos) * SCALE, off + (viewport->Pos + viewport->Size) * SCALE); + RenderViewportThumbnail(window->DrawList, viewport, viewport_draw_bb); + } + ImGui::Dummy(bb_full.GetSize() * SCALE); +} + +#ifndef IMGUI_DISABLE_METRICS_WINDOW + +// Avoid naming collision with imgui_demo.cpp's HelpMarker() for unity builds. +static void MetricsHelpMarker(const char* desc) +{ + ImGui::TextDisabled("(?)"); + if (ImGui::IsItemHovered()) + { + ImGui::BeginTooltip(); + ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f); + ImGui::TextUnformatted(desc); + ImGui::PopTextWrapPos(); + ImGui::EndTooltip(); + } +} + +void ImGui::ShowMetricsWindow(bool* p_open) +{ + if (!ImGui::Begin("Dear ImGui Metrics", p_open)) + { + ImGui::End(); + return; + } + + // Debugging enums + enum { WRT_OuterRect, WRT_OuterRectClipped, WRT_InnerRect, WRT_InnerClipRect, WRT_WorkRect, WRT_Content, WRT_ContentRegionRect, WRT_Count }; // Windows Rect Type + const char* wrt_rects_names[WRT_Count] = { "OuterRect", "OuterRectClipped", "InnerRect", "InnerClipRect", "WorkRect", "Content", "ContentRegionRect" }; + enum { TRT_OuterRect, TRT_WorkRect, TRT_HostClipRect, TRT_InnerClipRect, TRT_BackgroundClipRect, TRT_ColumnsRect, TRT_ColumnsClipRect, TRT_ColumnsContentHeadersUsed, TRT_ColumnsContentHeadersDesired, TRT_ColumnsContentRowsFrozen, TRT_ColumnsContentRowsUnfrozen, TRT_Count }; // Tables Rect Type + const char* trt_rects_names[TRT_Count] = { "OuterRect", "WorkRect", "HostClipRect", "InnerClipRect", "BackgroundClipRect", "ColumnsRect", "ColumnsClipRect", "ColumnsContentHeadersUsed", "ColumnsContentHeadersDesired", "ColumnsContentRowsFrozen", "ColumnsContentRowsUnfrozen" }; + + // State + static bool show_windows_rects = false; + static int show_windows_rect_type = WRT_WorkRect; + static bool show_windows_begin_order = false; + static bool show_tables_rects = false; + static int show_tables_rect_type = TRT_WorkRect; + static bool show_drawcmd_mesh = true; + static bool show_drawcmd_aabb = true; + static bool show_docking_nodes = false; + + // Basic info + ImGuiContext& g = *GImGui; + ImGuiIO& io = ImGui::GetIO(); + ImGui::Text("Dear ImGui %s", ImGui::GetVersion()); + ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate); + ImGui::Text("%d vertices, %d indices (%d triangles)", io.MetricsRenderVertices, io.MetricsRenderIndices, io.MetricsRenderIndices / 3); + ImGui::Text("%d active windows (%d visible)", io.MetricsActiveWindows, io.MetricsRenderWindows); + ImGui::Text("%d active allocations", io.MetricsActiveAllocations); + ImGui::Separator(); + + // Helper functions to display common structures: + // - NodeDrawList() + // - NodeColumns() + // - NodeWindow() + // - NodeWindows() + // - NodeViewport() + // - NodeDockNode() + // - NodeTabBar() + // - NodeStorage() + struct Funcs + { + static ImRect GetWindowRect(ImGuiWindow* window, int rect_type) + { + if (rect_type == WRT_OuterRect) { return window->Rect(); } + else if (rect_type == WRT_OuterRectClipped) { return window->OuterRectClipped; } + else if (rect_type == WRT_InnerRect) { return window->InnerRect; } + else if (rect_type == WRT_InnerClipRect) { return window->InnerClipRect; } + else if (rect_type == WRT_WorkRect) { return window->WorkRect; } + else if (rect_type == WRT_Content) { ImVec2 min = window->InnerRect.Min - window->Scroll + window->WindowPadding; return ImRect(min, min + window->ContentSize); } + else if (rect_type == WRT_ContentRegionRect) { return window->ContentRegionRect; } + IM_ASSERT(0); + return ImRect(); + } + + static void NodeDrawCmdShowMeshAndBoundingBox(ImDrawList* fg_draw_list, const ImDrawList* draw_list, const ImDrawCmd* draw_cmd, int elem_offset, bool show_mesh, bool show_aabb) + { + IM_ASSERT(show_mesh || show_aabb); + ImDrawIdx* idx_buffer = (draw_list->IdxBuffer.Size > 0) ? draw_list->IdxBuffer.Data : NULL; + + // Draw wire-frame version of all triangles + ImRect clip_rect = draw_cmd->ClipRect; + ImRect vtxs_rect(FLT_MAX, FLT_MAX, -FLT_MAX, -FLT_MAX); + ImDrawListFlags backup_flags = fg_draw_list->Flags; + fg_draw_list->Flags &= ~ImDrawListFlags_AntiAliasedLines; // Disable AA on triangle outlines is more readable for very large and thin triangles. + for (unsigned int base_idx = elem_offset; base_idx < (elem_offset + draw_cmd->ElemCount); base_idx += 3) + { + ImVec2 triangle[3]; + for (int n = 0; n < 3; n++) + { + ImVec2 p = draw_list->VtxBuffer[idx_buffer ? idx_buffer[base_idx + n] : (base_idx + n)].pos; + triangle[n] = p; + vtxs_rect.Add(p); + } + if (show_mesh) + fg_draw_list->AddPolyline(triangle, 3, IM_COL32(255, 255, 0, 255), true, 1.0f); // In yellow: mesh triangles + } + // Draw bounding boxes + if (show_aabb) + { + fg_draw_list->AddRect(ImFloor(clip_rect.Min), ImFloor(clip_rect.Max), IM_COL32(255, 0, 255, 255)); // In pink: clipping rectangle submitted to GPU + fg_draw_list->AddRect(ImFloor(vtxs_rect.Min), ImFloor(vtxs_rect.Max), IM_COL32(0, 255, 255, 255)); // In cyan: bounding box of triangles + } + fg_draw_list->Flags = backup_flags; + } + + // Note that both 'window' and 'viewport' may be NULL here. Viewport is generally null of destroyed popups which previously owned a viewport. + static void NodeDrawList(ImGuiWindow* window, ImGuiViewportP* viewport, ImDrawList* draw_list, const char* label) + { + bool node_open = ImGui::TreeNode(draw_list, "%s: '%s' %d vtx, %d indices, %d cmds", label, draw_list->_OwnerName ? draw_list->_OwnerName : "", draw_list->VtxBuffer.Size, draw_list->IdxBuffer.Size, draw_list->CmdBuffer.Size); + if (draw_list == ImGui::GetWindowDrawList()) + { + ImGui::SameLine(); + ImGui::TextColored(ImVec4(1.0f,0.4f,0.4f,1.0f), "CURRENTLY APPENDING"); // Can't display stats for active draw list! (we don't have the data double-buffered) + if (node_open) ImGui::TreePop(); + return; + } + + ImDrawList* fg_draw_list = viewport ? GetForegroundDrawList(viewport) : NULL; // Render additional visuals into the top-most draw list + if (window && fg_draw_list && ImGui::IsItemHovered()) + fg_draw_list->AddRect(window->Pos, window->Pos + window->Size, IM_COL32(255, 255, 0, 255)); + if (!node_open) + return; + + if (window && !window->WasActive) + ImGui::TextDisabled("Warning: owning Window is inactive. This DrawList is not being rendered!"); + + unsigned int elem_offset = 0; + for (const ImDrawCmd* pcmd = draw_list->CmdBuffer.begin(); pcmd < draw_list->CmdBuffer.end(); elem_offset += pcmd->ElemCount, pcmd++) + { + if (pcmd->UserCallback == NULL && pcmd->ElemCount == 0) + continue; + if (pcmd->UserCallback) + { + ImGui::BulletText("Callback %p, user_data %p", pcmd->UserCallback, pcmd->UserCallbackData); + continue; + } + + ImDrawIdx* idx_buffer = (draw_list->IdxBuffer.Size > 0) ? draw_list->IdxBuffer.Data : NULL; + char buf[300]; + ImFormatString(buf, IM_ARRAYSIZE(buf), "DrawCmd: %4d triangles, Tex 0x%p, ClipRect (%4.0f,%4.0f)-(%4.0f,%4.0f)", + pcmd->ElemCount/3, (void*)(intptr_t)pcmd->TextureId, + pcmd->ClipRect.x, pcmd->ClipRect.y, pcmd->ClipRect.z, pcmd->ClipRect.w); + bool pcmd_node_open = ImGui::TreeNode((void*)(pcmd - draw_list->CmdBuffer.begin()), "%s", buf); + if (ImGui::IsItemHovered() && (show_drawcmd_mesh || show_drawcmd_aabb) && fg_draw_list) + NodeDrawCmdShowMeshAndBoundingBox(fg_draw_list, draw_list, pcmd, elem_offset, show_drawcmd_mesh, show_drawcmd_aabb); + if (!pcmd_node_open) + continue; + + // Calculate approximate coverage area (touched pixel count) + // This will be in pixels squared as long there's no post-scaling happening to the renderer output. + float total_area = 0.0f; + for (unsigned int base_idx = elem_offset; base_idx < (elem_offset + pcmd->ElemCount); base_idx += 3) + { + ImVec2 triangle[3]; + for (int n = 0; n < 3; n++) + triangle[n] = draw_list->VtxBuffer[idx_buffer ? idx_buffer[base_idx + n] : (base_idx + n)].pos; + total_area += ImTriangleArea(triangle[0], triangle[1], triangle[2]); + } + + // Display vertex information summary. Hover to get all triangles drawn in wire-frame + ImFormatString(buf, IM_ARRAYSIZE(buf), "Mesh: ElemCount: %d, VtxOffset: +%d, IdxOffset: +%d, Area: ~%0.f px", pcmd->ElemCount, pcmd->VtxOffset, pcmd->IdxOffset, total_area); + ImGui::Selectable(buf); + if (ImGui::IsItemHovered() && fg_draw_list) + NodeDrawCmdShowMeshAndBoundingBox(fg_draw_list, draw_list, pcmd, elem_offset, true, false); + + // Display individual triangles/vertices. Hover on to get the corresponding triangle highlighted. + ImGuiListClipper clipper(pcmd->ElemCount/3); // Manually coarse clip our print out of individual vertices to save CPU, only items that may be visible. + while (clipper.Step()) + for (int prim = clipper.DisplayStart, idx_i = elem_offset + clipper.DisplayStart*3; prim < clipper.DisplayEnd; prim++) + { + char *buf_p = buf, *buf_end = buf + IM_ARRAYSIZE(buf); + ImVec2 triangle[3]; + for (int n = 0; n < 3; n++, idx_i++) + { + ImDrawVert& v = draw_list->VtxBuffer[idx_buffer ? idx_buffer[idx_i] : idx_i]; + triangle[n] = v.pos; + buf_p += ImFormatString(buf_p, buf_end - buf_p, "%s %04d: pos (%8.2f,%8.2f), uv (%.6f,%.6f), col %08X\n", + (n == 0) ? "Vert:" : " ", idx_i, v.pos.x, v.pos.y, v.uv.x, v.uv.y, v.col); + } + + ImGui::Selectable(buf, false); + if (fg_draw_list && ImGui::IsItemHovered()) + { + ImDrawListFlags backup_flags = fg_draw_list->Flags; + fg_draw_list->Flags &= ~ImDrawListFlags_AntiAliasedLines; // Disable AA on triangle outlines is more readable for very large and thin triangles. + fg_draw_list->AddPolyline(triangle, 3, IM_COL32(255,255,0,255), true, 1.0f); + fg_draw_list->Flags = backup_flags; + } + } + ImGui::TreePop(); + } + ImGui::TreePop(); + } + + static void NodeColumns(const ImGuiColumns* columns) + { + if (!ImGui::TreeNode((void*)(uintptr_t)columns->ID, "Columns Id: 0x%08X, Count: %d, Flags: 0x%04X", columns->ID, columns->Count, columns->Flags)) + return; + ImGui::BulletText("Width: %.1f (MinX: %.1f, MaxX: %.1f)", columns->OffMaxX - columns->OffMinX, columns->OffMinX, columns->OffMaxX); + for (int column_n = 0; column_n < columns->Columns.Size; column_n++) + ImGui::BulletText("Column %02d: OffsetNorm %.3f (= %.1f px)", column_n, columns->Columns[column_n].OffsetNorm, GetColumnOffsetFromNorm(columns, columns->Columns[column_n].OffsetNorm)); + ImGui::TreePop(); + } + + static void NodeWindows(ImVector& windows, const char* label) + { + if (!ImGui::TreeNode(label, "%s (%d)", label, windows.Size)) + return; + for (int i = 0; i < windows.Size; i++) + { + ImGui::PushID(windows[i]); + Funcs::NodeWindow(windows[i], "Window"); + ImGui::PopID(); + } + ImGui::TreePop(); + } + + static void NodeWindow(ImGuiWindow* window, const char* label) + { + if (window == NULL) + { + ImGui::BulletText("%s: NULL", label); + return; + } + bool open = ImGui::TreeNode(label, "%s '%s', %d @ 0x%p", label, window->Name, (window->Active || window->WasActive), window); + if (ImGui::IsItemHovered() && window->WasActive) + ImGui::GetForegroundDrawList()->AddRect(window->Pos, window->Pos + window->Size, IM_COL32(255, 255, 0, 255)); + if (!open) + return; + + if (!window->WasActive) + ImGui::TextDisabled("Note: window is not currently visible."); + if (window->MemoryCompacted) + ImGui::TextDisabled("Note: some memory buffers have been compacted/freed."); + + ImGuiWindowFlags flags = window->Flags; + NodeDrawList(window, window->Viewport, window->DrawList, "DrawList"); + ImGui::BulletText("Pos: (%.1f,%.1f), Size: (%.1f,%.1f), ContentSize (%.1f,%.1f)", window->Pos.x, window->Pos.y, window->Size.x, window->Size.y, window->ContentSize.x, window->ContentSize.y); + ImGui::BulletText("Flags: 0x%08X (%s%s%s%s%s%s%s%s%s..)", flags, + (flags & ImGuiWindowFlags_ChildWindow) ? "Child " : "", (flags & ImGuiWindowFlags_Tooltip) ? "Tooltip " : "", (flags & ImGuiWindowFlags_Popup) ? "Popup " : "", + (flags & ImGuiWindowFlags_Modal) ? "Modal " : "", (flags & ImGuiWindowFlags_ChildMenu) ? "ChildMenu " : "", (flags & ImGuiWindowFlags_NoSavedSettings) ? "NoSavedSettings " : "", + (flags & ImGuiWindowFlags_NoMouseInputs)? "NoMouseInputs":"", (flags & ImGuiWindowFlags_NoNavInputs) ? "NoNavInputs" : "", (flags & ImGuiWindowFlags_AlwaysAutoResize) ? "AlwaysAutoResize" : ""); + ImGui::BulletText("WindowClassId: 0x%08X", window->WindowClass.ClassId); + ImGui::BulletText("Scroll: (%.2f/%.2f,%.2f/%.2f) Scrollbar:%s%s", window->Scroll.x, window->ScrollMax.x, window->Scroll.y, window->ScrollMax.y, window->ScrollbarX ? "X" : "", window->ScrollbarY ? "Y" : ""); + ImGui::BulletText("Active: %d/%d, WriteAccessed: %d, BeginOrderWithinContext: %d", window->Active, window->WasActive, window->WriteAccessed, (window->Active || window->WasActive) ? window->BeginOrderWithinContext : -1); + ImGui::BulletText("Appearing: %d, Hidden: %d (CanSkip %d Cannot %d), SkipItems: %d", window->Appearing, window->Hidden, window->HiddenFramesCanSkipItems, window->HiddenFramesCannotSkipItems, window->SkipItems); + ImGui::BulletText("NavLastIds: 0x%08X,0x%08X, NavLayerActiveMask: %X", window->NavLastIds[0], window->NavLastIds[1], window->DC.NavLayerActiveMask); + ImGui::BulletText("NavLastChildNavWindow: %s", window->NavLastChildNavWindow ? window->NavLastChildNavWindow->Name : "NULL"); + if (!window->NavRectRel[0].IsInverted()) + ImGui::BulletText("NavRectRel[0]: (%.1f,%.1f)(%.1f,%.1f)", window->NavRectRel[0].Min.x, window->NavRectRel[0].Min.y, window->NavRectRel[0].Max.x, window->NavRectRel[0].Max.y); + else + ImGui::BulletText("NavRectRel[0]: "); + ImGui::BulletText("Viewport: %d%s, ViewportId: 0x%08X, ViewportPos: (%.1f,%.1f)", window->Viewport ? window->Viewport->Idx : -1, window->ViewportOwned ? " (Owned)" : "", window->ViewportId, window->ViewportPos.x, window->ViewportPos.y); + ImGui::BulletText("ViewportMonitor: %d", window->Viewport ? window->Viewport->PlatformMonitor : -1); + ImGui::BulletText("DockId: 0x%04X, DockOrder: %d, Act: %d, Vis: %d", window->DockId, window->DockOrder, window->DockIsActive, window->DockTabIsVisible); + if (window->DockNode || window->DockNodeAsHost) + NodeDockNode(window->DockNodeAsHost ? window->DockNodeAsHost : window->DockNode, window->DockNodeAsHost ? "DockNodeAsHost" : "DockNode"); + if (window->RootWindow != window) NodeWindow(window->RootWindow, "RootWindow"); + if (window->RootWindowDockStop != window->RootWindow) NodeWindow(window->RootWindowDockStop, "RootWindowDockStop"); + if (window->ParentWindow != NULL) NodeWindow(window->ParentWindow, "ParentWindow"); + if (window->DC.ChildWindows.Size > 0) NodeWindows(window->DC.ChildWindows, "ChildWindows"); + if (window->ColumnsStorage.Size > 0 && ImGui::TreeNode("Columns", "Columns sets (%d)", window->ColumnsStorage.Size)) + { + for (int n = 0; n < window->ColumnsStorage.Size; n++) + NodeColumns(&window->ColumnsStorage[n]); + ImGui::TreePop(); + } + NodeStorage(&window->StateStorage, "Storage"); + ImGui::TreePop(); + } + + static void NodeWindowSettings(ImGuiWindowSettings* settings) + { + ImGui::Text("0x%08X \"%s\" Pos (%d,%d) Size (%d,%d) Collapsed=%d", + settings->ID, settings->GetName(), settings->Pos.x, settings->Pos.y, settings->Size.x, settings->Size.y, settings->Collapsed); + } + + static void NodeViewport(ImGuiViewportP* viewport) + { + ImGui::SetNextItemOpen(true, ImGuiCond_Once); + if (ImGui::TreeNode((void*)(intptr_t)viewport->ID, "Viewport #%d, ID: 0x%08X, Parent: 0x%08X, Window: \"%s\"", viewport->Idx, viewport->ID, viewport->ParentViewportId, viewport->Window ? viewport->Window->Name : "N/A")) + { + ImGuiWindowFlags flags = viewport->Flags; + ImGui::BulletText("Main Pos: (%.0f,%.0f), Size: (%.0f,%.0f)\nWorkArea Offset Left: %.0f Top: %.0f, Right: %.0f, Bottom: %.0f\nMonitor: %d, DpiScale: %.0f%%", + viewport->Pos.x, viewport->Pos.y, viewport->Size.x, viewport->Size.y, + viewport->WorkOffsetMin.x, viewport->WorkOffsetMin.y, viewport->WorkOffsetMax.x, viewport->WorkOffsetMax.y, + viewport->PlatformMonitor, viewport->DpiScale * 100.0f); + if (viewport->Idx > 0) { ImGui::SameLine(); if (ImGui::SmallButton("Reset Pos")) { viewport->Pos = ImVec2(200,200); if (viewport->Window) viewport->Window->Pos = ImVec2(200,200); } } + ImGui::BulletText("Flags: 0x%04X =%s%s%s%s%s%s%s", viewport->Flags, + (flags & ImGuiViewportFlags_CanHostOtherWindows) ? " CanHostOtherWindows" : "", (flags & ImGuiViewportFlags_NoDecoration) ? " NoDecoration" : "", + (flags & ImGuiViewportFlags_NoFocusOnAppearing) ? " NoFocusOnAppearing" : "", (flags & ImGuiViewportFlags_NoInputs) ? " NoInputs" : "", + (flags & ImGuiViewportFlags_NoRendererClear) ? " NoRendererClear" : "", (flags & ImGuiViewportFlags_Minimized) ? " Minimized" : "", + (flags & ImGuiViewportFlags_NoAutoMerge) ? " NoAutoMerge" : ""); + for (int layer_i = 0; layer_i < IM_ARRAYSIZE(viewport->DrawDataBuilder.Layers); layer_i++) + for (int draw_list_i = 0; draw_list_i < viewport->DrawDataBuilder.Layers[layer_i].Size; draw_list_i++) + Funcs::NodeDrawList(NULL, viewport, viewport->DrawDataBuilder.Layers[layer_i][draw_list_i], "DrawList"); + ImGui::TreePop(); + } + } + + static void NodeDockNode(ImGuiDockNode* node, const char* label) + { + ImGuiContext& g = *GImGui; + bool open; + if (node->Windows.Size > 0) + open = ImGui::TreeNode((void*)(intptr_t)node->ID, "%s 0x%04X%s: %d windows (vis: '%s')", label, node->ID, node->IsVisible ? "" : " (hidden)", node->Windows.Size, node->VisibleWindow ? node->VisibleWindow->Name : "NULL"); + else + open = ImGui::TreeNode((void*)(intptr_t)node->ID, "%s 0x%04X%s: %s split (vis: '%s')", label, node->ID, node->IsVisible ? "" : " (hidden)", (node->SplitAxis == ImGuiAxis_X) ? "horizontal" : (node->SplitAxis == ImGuiAxis_Y) ? "vertical" : "n/a", node->VisibleWindow ? node->VisibleWindow->Name : "NULL"); + if (open) + { + IM_ASSERT(node->ChildNodes[0] == NULL || node->ChildNodes[0]->ParentNode == node); + IM_ASSERT(node->ChildNodes[1] == NULL || node->ChildNodes[1]->ParentNode == node); + ImGui::BulletText("Pos (%.0f,%.0f), Size (%.0f, %.0f) Ref (%.0f, %.0f)", + node->Pos.x, node->Pos.y, node->Size.x, node->Size.y, node->SizeRef.x, node->SizeRef.y); + NodeWindow(node->HostWindow, "HostWindow"); + NodeWindow(node->VisibleWindow, "VisibleWindow"); + ImGui::BulletText("SelectedTabID: 0x%08X, LastFocusedNodeID: 0x%08X", node->SelectedTabId, node->LastFocusedNodeId); + ImGui::BulletText("Misc:%s%s%s%s", node->IsDockSpace() ? " IsDockSpace" : "", node->IsCentralNode() ? " IsCentralNode" : "", (g.FrameCount - node->LastFrameAlive < 2) ? " IsAlive" : "", (g.FrameCount - node->LastFrameActive < 2) ? " IsActive" : ""); + if (ImGui::TreeNode("flags", "LocalFlags: 0x%04X SharedFlags: 0x%04X", node->LocalFlags, node->SharedFlags)) + { + ImGui::CheckboxFlags("LocalFlags: NoDocking", (ImU32*)&node->LocalFlags, ImGuiDockNodeFlags_NoDocking); + ImGui::CheckboxFlags("LocalFlags: NoSplit", (ImU32*)&node->LocalFlags, ImGuiDockNodeFlags_NoSplit); + ImGui::CheckboxFlags("LocalFlags: NoResize", (ImU32*)&node->LocalFlags, ImGuiDockNodeFlags_NoResize); + ImGui::CheckboxFlags("LocalFlags: NoTabBar", (ImU32*)&node->LocalFlags, ImGuiDockNodeFlags_NoTabBar); + ImGui::CheckboxFlags("LocalFlags: HiddenTabBar", (ImU32*)&node->LocalFlags, ImGuiDockNodeFlags_HiddenTabBar); + ImGui::CheckboxFlags("LocalFlags: NoWindowMenuButton", (ImU32*)&node->LocalFlags, ImGuiDockNodeFlags_NoWindowMenuButton); + ImGui::CheckboxFlags("LocalFlags: NoCloseButton", (ImU32*)&node->LocalFlags, ImGuiDockNodeFlags_NoCloseButton); + ImGui::TreePop(); + } + if (node->ParentNode) + NodeDockNode(node->ParentNode, "ParentNode"); + if (node->ChildNodes[0]) + NodeDockNode(node->ChildNodes[0], "Child[0]"); + if (node->ChildNodes[1]) + NodeDockNode(node->ChildNodes[1], "Child[1]"); + if (node->TabBar) + NodeTabBar(node->TabBar); + ImGui::TreePop(); + } + } + + static void NodeTabBar(ImGuiTabBar* tab_bar) + { + // Standalone tab bars (not associated to docking/windows functionality) currently hold no discernible strings. + char buf[256]; + char* p = buf; + const char* buf_end = buf + IM_ARRAYSIZE(buf); + p += ImFormatString(p, buf_end - p, "TabBar (%d tabs)%s", tab_bar->Tabs.Size, (tab_bar->PrevFrameVisible < ImGui::GetFrameCount() - 2) ? " *Inactive*" : ""); + if (tab_bar->Flags & ImGuiTabBarFlags_DockNode) + { + p += ImFormatString(p, buf_end - p, " { "); + for (int tab_n = 0; tab_n < ImMin(tab_bar->Tabs.Size, 3); tab_n++) + p += ImFormatString(p, buf_end - p, "%s'%s'", tab_n > 0 ? ", " : "", tab_bar->Tabs[tab_n].Window->Name); + p += ImFormatString(p, buf_end - p, (tab_bar->Tabs.Size > 3) ? " ... }" : " } "); + } + if (ImGui::TreeNode(tab_bar, "%s", buf)) + { + for (int tab_n = 0; tab_n < tab_bar->Tabs.Size; tab_n++) + { + const ImGuiTabItem* tab = &tab_bar->Tabs[tab_n]; + ImGui::PushID(tab); + if (ImGui::SmallButton("<")) { TabBarQueueChangeTabOrder(tab_bar, tab, -1); } ImGui::SameLine(0, 2); + if (ImGui::SmallButton(">")) { TabBarQueueChangeTabOrder(tab_bar, tab, +1); } ImGui::SameLine(); + ImGui::Text("%02d%c Tab 0x%08X '%s'", tab_n, (tab->ID == tab_bar->SelectedTabId) ? '*' : ' ', tab->ID, (tab->Window || tab->NameOffset != -1) ? tab_bar->GetTabName(tab) : ""); + ImGui::PopID(); + } + ImGui::TreePop(); + } + } + + static void NodeStorage(ImGuiStorage* storage, const char* label) + { + if (!ImGui::TreeNode(label, "%s: %d entries, %d bytes", label, storage->Data.Size, storage->Data.size_in_bytes())) + return; + for (int n = 0; n < storage->Data.Size; n++) + { + const ImGuiStorage::ImGuiStoragePair& p = storage->Data[n]; + ImGui::BulletText("Key 0x%08X Value { i: %d }", p.key, p.val_i); // Important: we currently don't store a type, real value may not be integer. + } + ImGui::TreePop(); + } + }; + + + // Tools + if (ImGui::TreeNode("Tools")) + { + // The Item Picker tool is super useful to visually select an item and break into the call-stack of where it was submitted. + if (ImGui::Button("Item Picker..")) + ImGui::DebugStartItemPicker(); + ImGui::SameLine(); + MetricsHelpMarker("Will call the IM_DEBUG_BREAK() macro to break in debugger.\nWarning: If you don't have a debugger attached, this will probably crash."); + + ImGui::Checkbox("Show windows begin order", &show_windows_begin_order); + ImGui::Checkbox("Show windows rectangles", &show_windows_rects); + ImGui::SameLine(); + ImGui::SetNextItemWidth(ImGui::GetFontSize() * 12); + show_windows_rects |= ImGui::Combo("##show_windows_rect_type", &show_windows_rect_type, wrt_rects_names, WRT_Count, WRT_Count); + if (show_windows_rects && g.NavWindow) + { + ImGui::BulletText("'%s':", g.NavWindow->Name); + ImGui::Indent(); + for (int rect_n = 0; rect_n < WRT_Count; rect_n++) + { + ImRect r = Funcs::GetWindowRect(g.NavWindow, rect_n); + ImGui::Text("(%6.1f,%6.1f) (%6.1f,%6.1f) Size (%6.1f,%6.1f) %s", r.Min.x, r.Min.y, r.Max.x, r.Max.y, r.GetWidth(), r.GetHeight(), wrt_rects_names[rect_n]); + } + ImGui::Unindent(); + } + ImGui::Checkbox("Show mesh when hovering ImDrawCmd", &show_drawcmd_mesh); + ImGui::Checkbox("Show bounding boxes when hovering ImDrawCmd", &show_drawcmd_aabb); + ImGui::TreePop(); + } + + // Contents + Funcs::NodeWindows(g.Windows, "Windows"); + //Funcs::NodeWindows(g.WindowsFocusOrder, "WindowsFocusOrder"); + if (ImGui::TreeNode("Viewport", "Viewports (%d)", g.Viewports.Size)) + { + ImGui::Indent(ImGui::GetTreeNodeToLabelSpacing()); + ImGui::ShowViewportThumbnails(); + ImGui::Unindent(ImGui::GetTreeNodeToLabelSpacing()); + bool open = ImGui::TreeNode("Monitors", "Monitors (%d)", g.PlatformIO.Monitors.Size); + ImGui::SameLine(); + MetricsHelpMarker("Dear ImGui uses monitor data:\n- to query DPI settings on a per monitor basis\n- to position popup/tooltips so they don't straddle monitors."); + if (open) + { + for (int i = 0; i < g.PlatformIO.Monitors.Size; i++) + { + const ImGuiPlatformMonitor& mon = g.PlatformIO.Monitors[i]; + ImGui::BulletText("Monitor #%d: DPI %.0f%%\n MainMin (%.0f,%.0f), MainMax (%.0f,%.0f), MainSize (%.0f,%.0f)\n WorkMin (%.0f,%.0f), WorkMax (%.0f,%.0f), WorkSize (%.0f,%.0f)", + i, mon.DpiScale * 100.0f, + mon.MainPos.x, mon.MainPos.y, mon.MainPos.x + mon.MainSize.x, mon.MainPos.y + mon.MainSize.y, mon.MainSize.x, mon.MainSize.y, + mon.WorkPos.x, mon.WorkPos.y, mon.WorkPos.x + mon.WorkSize.x, mon.WorkPos.y + mon.WorkSize.y, mon.WorkSize.x, mon.WorkSize.y); + } + ImGui::TreePop(); + } + for (int i = 0; i < g.Viewports.Size; i++) + Funcs::NodeViewport(g.Viewports[i]); + ImGui::TreePop(); + } + + // Details for Popups + if (ImGui::TreeNode("Popups", "Popups (%d)", g.OpenPopupStack.Size)) + { + for (int i = 0; i < g.OpenPopupStack.Size; i++) + { + ImGuiWindow* window = g.OpenPopupStack[i].Window; + ImGui::BulletText("PopupID: %08x, Window: '%s'%s%s", g.OpenPopupStack[i].PopupId, window ? window->Name : "NULL", window && (window->Flags & ImGuiWindowFlags_ChildWindow) ? " ChildWindow" : "", window && (window->Flags & ImGuiWindowFlags_ChildMenu) ? " ChildMenu" : ""); + } + ImGui::TreePop(); + } + + // Details for TabBars + if (ImGui::TreeNode("TabBars", "Tab Bars (%d)", g.TabBars.GetSize())) + { + for (int n = 0; n < g.TabBars.GetSize(); n++) + Funcs::NodeTabBar(g.TabBars.GetByIndex(n)); + ImGui::TreePop(); + } + + // Details for Tables + IM_UNUSED(trt_rects_names); + IM_UNUSED(show_tables_rects); + IM_UNUSED(show_tables_rect_type); +#ifdef IMGUI_HAS_TABLE + if (ImGui::TreeNode("Tables", "Tables (%d)", g.Tables.GetSize())) + { + for (int n = 0; n < g.Tables.GetSize(); n++) + Funcs::NodeTable(g.Tables.GetByIndex(n)); + ImGui::TreePop(); + } +#endif // #define IMGUI_HAS_TABLE + + // Details for Docking +#ifdef IMGUI_HAS_DOCK + if (ImGui::TreeNode("Dock nodes")) + { + ImGuiDockContext* dc = &g.DockContext; + ImGui::Checkbox("Ctrl shows window dock info", &show_docking_nodes); + if (ImGui::SmallButton("Clear nodes")) { DockContextClearNodes(&g, 0, true); } + ImGui::SameLine(); + if (ImGui::SmallButton("Rebuild all")) { dc->WantFullRebuild = true; } + for (int n = 0; n < dc->Nodes.Data.Size; n++) + if (ImGuiDockNode* node = (ImGuiDockNode*)dc->Nodes.Data[n].val_p) + if (node->IsRootNode()) + Funcs::NodeDockNode(node, "Node"); + ImGui::TreePop(); + } +#endif // #define IMGUI_HAS_DOCK + + // Settings + if (ImGui::TreeNode("Settings")) + { + if (ImGui::SmallButton("Clear")) + ImGui::ClearIniSettings(); + ImGui::SameLine(); + if (ImGui::SmallButton("Save to memory")) + ImGui::SaveIniSettingsToMemory(); + ImGui::SameLine(); + if (ImGui::SmallButton("Save to disk")) + ImGui::SaveIniSettingsToDisk(g.IO.IniFilename); + ImGui::SameLine(); + if (g.IO.IniFilename) + ImGui::Text("\"%s\"", g.IO.IniFilename); + else + ImGui::TextUnformatted(""); + ImGui::Text("SettingsDirtyTimer %.2f", g.SettingsDirtyTimer); + if (ImGui::TreeNode("SettingsHandlers", "Settings handlers: (%d)", g.SettingsHandlers.Size)) + { + for (int n = 0; n < g.SettingsHandlers.Size; n++) + ImGui::BulletText("%s", g.SettingsHandlers[n].TypeName); + ImGui::TreePop(); + } + if (ImGui::TreeNode("SettingsWindows", "Settings packed data: Windows: %d bytes", g.SettingsWindows.size())) + { + for (ImGuiWindowSettings* settings = g.SettingsWindows.begin(); settings != NULL; settings = g.SettingsWindows.next_chunk(settings)) + Funcs::NodeWindowSettings(settings); + ImGui::TreePop(); + } + +#ifdef IMGUI_HAS_TABLE + if (ImGui::TreeNode("SettingsTables", "Settings packed data: Tables: %d bytes", g.SettingsTables.size())) + { + for (ImGuiTableSettings* settings = g.SettingsTables.begin(); settings != NULL; settings = g.SettingsTables.next_chunk(settings)) + Funcs::NodeTableSettings(settings); + ImGui::TreePop(); + } +#endif + +#ifdef IMGUI_HAS_DOCK + if (ImGui::TreeNode("SettingsDocking", "Settings packed data: Docking")) + { + ImGuiDockContext* dc = &g.DockContext; + ImGui::Text("In SettingsWindows:"); + for (ImGuiWindowSettings* settings = g.SettingsWindows.begin(); settings != NULL; settings = g.SettingsWindows.next_chunk(settings)) + if (settings->DockId != 0) + ImGui::BulletText("Window '%s' -> DockId %08X", settings->GetName(), settings->DockId); + ImGui::Text("In SettingsNodes:"); + for (int n = 0; n < dc->NodesSettings.Size; n++) + { + ImGuiDockNodeSettings* settings = &dc->NodesSettings[n]; + const char* selected_tab_name = NULL; + if (settings->SelectedWindowId) + { + if (ImGuiWindow* window = FindWindowByID(settings->SelectedWindowId)) + selected_tab_name = window->Name; + else if (ImGuiWindowSettings* window_settings = FindWindowSettings(settings->SelectedWindowId)) + selected_tab_name = window_settings->GetName(); + } + ImGui::BulletText("Node %08X, Parent %08X, SelectedTab %08X ('%s')", settings->ID, settings->ParentNodeId, settings->SelectedWindowId, selected_tab_name ? selected_tab_name : settings->SelectedWindowId ? "N/A" : ""); + } + ImGui::TreePop(); + } +#endif + + if (ImGui::TreeNode("SettingsIniData", "Settings unpacked data (.ini): %d bytes", g.SettingsIniData.size())) + { + char* buf = (char*)(void*)(g.SettingsIniData.Buf.Data ? g.SettingsIniData.Buf.Data : ""); + ImGui::InputTextMultiline("##Ini", buf, g.SettingsIniData.Buf.Size, ImVec2(-FLT_MIN, 0.0f), ImGuiInputTextFlags_ReadOnly); + ImGui::TreePop(); + } + ImGui::TreePop(); + } + + // Misc Details + if (ImGui::TreeNode("Internal state")) + { + const char* input_source_names[] = { "None", "Mouse", "Nav", "NavKeyboard", "NavGamepad" }; IM_ASSERT(IM_ARRAYSIZE(input_source_names) == ImGuiInputSource_COUNT); + ImGui::Text("HoveredWindow: '%s'", g.HoveredWindow ? g.HoveredWindow->Name : "NULL"); + ImGui::Text("HoveredRootWindow: '%s'", g.HoveredRootWindow ? g.HoveredRootWindow->Name : "NULL"); + ImGui::Text("HoveredWindowUnderMovingWindow: '%s'", g.HoveredWindowUnderMovingWindow ? g.HoveredWindowUnderMovingWindow->Name : "NULL"); + ImGui::Text("HoveredId: 0x%08X/0x%08X (%.2f sec), AllowOverlap: %d", g.HoveredId, g.HoveredIdPreviousFrame, g.HoveredIdTimer, g.HoveredIdAllowOverlap); // Data is "in-flight" so depending on when the Metrics window is called we may see current frame information or not + ImGui::Text("ActiveId: 0x%08X/0x%08X (%.2f sec), AllowOverlap: %d, Source: %s", g.ActiveId, g.ActiveIdPreviousFrame, g.ActiveIdTimer, g.ActiveIdAllowOverlap, input_source_names[g.ActiveIdSource]); + ImGui::Text("ActiveIdWindow: '%s'", g.ActiveIdWindow ? g.ActiveIdWindow->Name : "NULL"); + ImGui::Text("MovingWindow: '%s'", g.MovingWindow ? g.MovingWindow->Name : "NULL"); + ImGui::Text("NavWindow: '%s'", g.NavWindow ? g.NavWindow->Name : "NULL"); + ImGui::Text("NavId: 0x%08X, NavLayer: %d", g.NavId, g.NavLayer); + ImGui::Text("NavInputSource: %s", input_source_names[g.NavInputSource]); + ImGui::Text("NavActive: %d, NavVisible: %d", g.IO.NavActive, g.IO.NavVisible); + ImGui::Text("NavActivateId: 0x%08X, NavInputId: 0x%08X", g.NavActivateId, g.NavInputId); + ImGui::Text("NavDisableHighlight: %d, NavDisableMouseHover: %d", g.NavDisableHighlight, g.NavDisableMouseHover); + ImGui::Text("NavWindowingTarget: '%s'", g.NavWindowingTarget ? g.NavWindowingTarget->Name : "NULL"); + ImGui::Text("DragDrop: %d, SourceId = 0x%08X, Payload \"%s\" (%d bytes)", g.DragDropActive, g.DragDropPayload.SourceId, g.DragDropPayload.DataType, g.DragDropPayload.DataSize); + ImGui::Text("MouseViewport: 0x%08X (UserHovered 0x%08X, LastHovered 0x%08X)", g.MouseViewport->ID, g.IO.MouseHoveredViewport, g.MouseLastHoveredViewport ? g.MouseLastHoveredViewport->ID : 0); + ImGui::TreePop(); + } + + // Overlay: Display windows Rectangles and Begin Order + if (show_windows_rects || show_windows_begin_order) + { + for (int n = 0; n < g.Windows.Size; n++) + { + ImGuiWindow* window = g.Windows[n]; + if (!window->WasActive) + continue; + ImDrawList* draw_list = GetForegroundDrawList(window); + if (show_windows_rects) + { + ImRect r = Funcs::GetWindowRect(window, show_windows_rect_type); + draw_list->AddRect(r.Min, r.Max, IM_COL32(255, 0, 128, 255)); + } + if (show_windows_begin_order && !(window->Flags & ImGuiWindowFlags_ChildWindow)) + { + char buf[32]; + ImFormatString(buf, IM_ARRAYSIZE(buf), "%d", window->BeginOrderWithinContext); + float font_size = ImGui::GetFontSize(); + draw_list->AddRectFilled(window->Pos, window->Pos + ImVec2(font_size, font_size), IM_COL32(200, 100, 100, 255)); + draw_list->AddText(window->Pos, IM_COL32(255, 255, 255, 255), buf); + } + } + } + +#ifdef IMGUI_HAS_TABLE + // Overlay: Display Tables Rectangles + if (show_tables_rects) + { + for (int table_n = 0; table_n < g.Tables.GetSize(); table_n++) + { + ImGuiTable* table = g.Tables.GetByIndex(table_n); + } + } +#endif // #define IMGUI_HAS_TABLE + +#ifdef IMGUI_HAS_DOCK + // Overlay: Display Docking info + if (show_docking_nodes && g.IO.KeyCtrl) + { + ImGuiDockContext* dc = &g.DockContext; + for (int n = 0; n < dc->Nodes.Data.Size; n++) + if (ImGuiDockNode* node = (ImGuiDockNode*)dc->Nodes.Data[n].val_p) + { + ImGuiDockNode* root_node = DockNodeGetRootNode(node); + if (ImGuiDockNode* hovered_node = DockNodeTreeFindNodeByPos(root_node, g.IO.MousePos)) + if (hovered_node != node) + continue; + char buf[64] = ""; + char* p = buf; + ImDrawList* overlay_draw_list = node->HostWindow ? GetForegroundDrawList(node->HostWindow) : GetForegroundDrawList((ImGuiViewportP*)GetMainViewport()); + p += ImFormatString(p, buf + IM_ARRAYSIZE(buf) - p, "DockId: %X%s\n", node->ID, node->IsCentralNode() ? " *CentralNode*" : ""); + p += ImFormatString(p, buf + IM_ARRAYSIZE(buf) - p, "WindowClass: %08X\n", node->WindowClass.ClassId); + p += ImFormatString(p, buf + IM_ARRAYSIZE(buf) - p, "Size: (%.0f, %.0f)\n", node->Size.x, node->Size.y); + p += ImFormatString(p, buf + IM_ARRAYSIZE(buf) - p, "SizeRef: (%.0f, %.0f)\n", node->SizeRef.x, node->SizeRef.y); + int depth = DockNodeGetDepth(node); + overlay_draw_list->AddRect(node->Pos + ImVec2(3, 3) * (float)depth, node->Pos + node->Size - ImVec2(3, 3) * (float)depth, IM_COL32(200, 100, 100, 255)); + ImVec2 pos = node->Pos + ImVec2(3, 3) * (float)depth; + overlay_draw_list->AddRectFilled(pos - ImVec2(1, 1), pos + CalcTextSize(buf) + ImVec2(1, 1), IM_COL32(200, 100, 100, 255)); + overlay_draw_list->AddText(NULL, 0.0f, pos, IM_COL32(255, 255, 255, 255), buf); + } + } +#endif // #define IMGUI_HAS_DOCK + + ImGui::End(); +} + +#else + +void ImGui::ShowMetricsWindow(bool*) { } + +#endif + +//----------------------------------------------------------------------------- + +// Include imgui_user.inl at the end of imgui.cpp to access private data/functions that aren't exposed. +// Prefer just including imgui_internal.h from your code rather than using this define. If a declaration is missing from imgui_internal.h add it or request it on the github. +#ifdef IMGUI_INCLUDE_IMGUI_USER_INL +#include "imgui_user.inl" +#endif + +//----------------------------------------------------------------------------- + +#endif // #ifndef IMGUI_DISABLE diff --git a/extern/imgui/src/imgui_demo.cpp b/extern/imgui/src/imgui_demo.cpp new file mode 100644 index 0000000..2700269 --- /dev/null +++ b/extern/imgui/src/imgui_demo.cpp @@ -0,0 +1,5536 @@ +// dear imgui, v1.77 WIP +// (demo code) + +// Help: +// - Read FAQ at http://dearimgui.org/faq +// - Newcomers, read 'Programmer guide' in imgui.cpp for notes on how to setup Dear ImGui in your codebase. +// - Call and read ImGui::ShowDemoWindow() in imgui_demo.cpp. All applications in examples/ are doing that. +// Read imgui.cpp for more details, documentation and comments. +// Get latest version at https://github.com/ocornut/imgui + +// Message to the person tempted to delete this file when integrating Dear ImGui into their code base: +// Do NOT remove this file from your project! Think again! It is the most useful reference code that you and other +// coders will want to refer to and call. Have the ImGui::ShowDemoWindow() function wired in an always-available +// debug menu of your game/app! Removing this file from your project is hindering access to documentation for everyone +// in your team, likely leading you to poorer usage of the library. +// Everything in this file will be stripped out by the linker if you don't call ImGui::ShowDemoWindow(). +// If you want to link core Dear ImGui in your shipped builds but want a thorough guarantee that the demo will not be +// linked, you can setup your imconfig.h with #define IMGUI_DISABLE_DEMO_WINDOWS and those functions will be empty. +// In other situation, whenever you have Dear ImGui available you probably want this to be available for reference. +// Thank you, +// -Your beloved friend, imgui_demo.cpp (which you won't delete) + +// Message to beginner C/C++ programmers about the meaning of the 'static' keyword: +// In this demo code, we frequently we use 'static' variables inside functions. A static variable persist across calls, +// so it is essentially like a global variable but declared inside the scope of the function. We do this as a way to +// gather code and data in the same place, to make the demo source code faster to read, faster to write, and smaller +// in size. It also happens to be a convenient way of storing simple UI related information as long as your function +// doesn't need to be reentrant or used in multiple threads. This might be a pattern you will want to use in your code, +// but most of the real data you would be editing is likely going to be stored outside your functions. + +// The Demo code in this file is designed to be easy to copy-and-paste in into your application! +// Because of this: +// - We never omit the ImGui:: prefix when calling functions, even though most code here is in the same namespace. +// - We try to declare static variables in the local scope, as close as possible to the code using them. +// - We never use any of the helpers/facilities used internally by Dear ImGui, unless available in the public API. +// - We never use maths operators on ImVec2/ImVec4. For our other sources files we use them, and they are provided +// by imgui_internal.h using the IMGUI_DEFINE_MATH_OPERATORS define. For your own sources file they are optional +// and require you either enable those, either provide your own via IM_VEC2_CLASS_EXTRA in imconfig.h. +// Because we can't assume anything about your support of maths operators, we cannot use them in imgui_demo.cpp. + +/* + +Index of this file: + +// [SECTION] Forward Declarations, Helpers +// [SECTION] Demo Window / ShowDemoWindow() +// [SECTION] About Window / ShowAboutWindow() +// [SECTION] Style Editor / ShowStyleEditor() +// [SECTION] Example App: Main Menu Bar / ShowExampleAppMainMenuBar() +// [SECTION] Example App: Debug Console / ShowExampleAppConsole() +// [SECTION] Example App: Debug Log / ShowExampleAppLog() +// [SECTION] Example App: Simple Layout / ShowExampleAppLayout() +// [SECTION] Example App: Property Editor / ShowExampleAppPropertyEditor() +// [SECTION] Example App: Long Text / ShowExampleAppLongText() +// [SECTION] Example App: Auto Resize / ShowExampleAppAutoResize() +// [SECTION] Example App: Constrained Resize / ShowExampleAppConstrainedResize() +// [SECTION] Example App: Simple Overlay / ShowExampleAppSimpleOverlay() +// [SECTION] Example App: Manipulating Window Titles / ShowExampleAppWindowTitles() +// [SECTION] Example App: Custom Rendering using ImDrawList API / ShowExampleAppCustomRendering() +// [SECTION] Example App: Docking, DockSpace / ShowExampleAppDockSpace() +// [SECTION] Example App: Documents Handling / ShowExampleAppDocuments() + +*/ + +#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS) +#define _CRT_SECURE_NO_WARNINGS +#endif + +#include "imgui.h" +#ifndef IMGUI_DISABLE + +#include // toupper +#include // INT_MIN, INT_MAX +#include // sqrtf, powf, cosf, sinf, floorf, ceilf +#include // vsnprintf, sscanf, printf +#include // NULL, malloc, free, atoi +#if defined(_MSC_VER) && _MSC_VER <= 1500 // MSVC 2008 or earlier +#include // intptr_t +#else +#include // intptr_t +#endif + +#ifdef _MSC_VER +#pragma warning (disable: 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen +#endif +#if defined(__clang__) +#pragma clang diagnostic ignored "-Wold-style-cast" // warning: use of old-style cast // yes, they are more terse. +#pragma clang diagnostic ignored "-Wdeprecated-declarations" // warning: 'xx' is deprecated: The POSIX name for this.. // for strdup used in demo code (so user can copy & paste the code) +#pragma clang diagnostic ignored "-Wint-to-void-pointer-cast" // warning: cast to 'void *' from smaller integer type +#pragma clang diagnostic ignored "-Wformat-security" // warning: format string is not a string literal +#pragma clang diagnostic ignored "-Wexit-time-destructors" // warning: declaration requires an exit-time destructor // exit-time destruction order is undefined. if MemFree() leads to users code that has been disabled before exit it might cause problems. ImGui coding style welcomes static/globals. +#pragma clang diagnostic ignored "-Wunused-macros" // warning: macro is not used // we define snprintf/vsnprintf on Windows so they are available, but not always used. +#if __has_warning("-Wzero-as-null-pointer-constant") +#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" // warning: zero as null pointer constant // some standard header variations use #define NULL 0 +#endif +#if __has_warning("-Wdouble-promotion") +#pragma clang diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function // using printf() is a misery with this as C++ va_arg ellipsis changes float to double. +#endif +#if __has_warning("-Wreserved-id-macro") +#pragma clang diagnostic ignored "-Wreserved-id-macro" // warning: macro name is a reserved identifier +#endif +#elif defined(__GNUC__) +#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind +#pragma GCC diagnostic ignored "-Wint-to-pointer-cast" // warning: cast to pointer from integer of different size +#pragma GCC diagnostic ignored "-Wformat-security" // warning: format string is not a string literal (potentially insecure) +#pragma GCC diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function +#pragma GCC diagnostic ignored "-Wconversion" // warning: conversion to 'xxxx' from 'xxxx' may alter its value +#pragma GCC diagnostic ignored "-Wmisleading-indentation" // [__GNUC__ >= 6] warning: this 'if' clause does not guard this statement // GCC 6.0+ only. See #883 on GitHub. +#endif + +// Play it nice with Windows users (Update: May 2018, Notepad now supports Unix-style carriage returns!) +#ifdef _WIN32 +#define IM_NEWLINE "\r\n" +#else +#define IM_NEWLINE "\n" +#endif + +// Helpers +#if defined(_MSC_VER) && !defined(snprintf) +#define snprintf _snprintf +#endif +#if defined(_MSC_VER) && !defined(vsnprintf) +#define vsnprintf _vsnprintf +#endif + +// Helpers macros +// We normally try to not use many helpers in imgui_demo.cpp in order to make code easier to copy and paste, +// but making an exception here as those are largely simplifying code... +// In other imgui sources we can use nicer internal functions from imgui_internal.h (ImMin/ImMax) but not in the demo. +#define IM_MIN(A, B) (((A) < (B)) ? (A) : (B)) +#define IM_MAX(A, B) (((A) >= (B)) ? (A) : (B)) +#define IM_CLAMP(V, MN, MX) ((V) < (MN) ? (MN) : (V) > (MX) ? (MX) : (V)) + +//----------------------------------------------------------------------------- +// [SECTION] Forward Declarations, Helpers +//----------------------------------------------------------------------------- + +#if !defined(IMGUI_DISABLE_DEMO_WINDOWS) + +// Forward Declarations +static void ShowExampleAppDockSpace(bool* p_open); +static void ShowExampleAppDocuments(bool* p_open); +static void ShowExampleAppMainMenuBar(); +static void ShowExampleAppConsole(bool* p_open); +static void ShowExampleAppLog(bool* p_open); +static void ShowExampleAppLayout(bool* p_open); +static void ShowExampleAppPropertyEditor(bool* p_open); +static void ShowExampleAppLongText(bool* p_open); +static void ShowExampleAppAutoResize(bool* p_open); +static void ShowExampleAppConstrainedResize(bool* p_open); +static void ShowExampleAppSimpleOverlay(bool* p_open); +static void ShowExampleAppWindowTitles(bool* p_open); +static void ShowExampleAppCustomRendering(bool* p_open); +static void ShowExampleMenuFile(); + +// Helper to display a little (?) mark which shows a tooltip when hovered. +// In your own code you may want to display an actual icon if you are using a merged icon fonts (see docs/FONTS.txt) +static void HelpMarker(const char* desc) +{ + ImGui::TextDisabled("(?)"); + if (ImGui::IsItemHovered()) + { + ImGui::BeginTooltip(); + ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f); + ImGui::TextUnformatted(desc); + ImGui::PopTextWrapPos(); + ImGui::EndTooltip(); + } +} + +static void ShowDockingDisabledMessage() +{ + ImGuiIO& io = ImGui::GetIO(); + ImGui::Text("ERROR: Docking is not enabled! See Demo > Configuration."); + ImGui::Text("Set io.ConfigFlags |= ImGuiConfigFlags_DockingEnable in your code, or "); + ImGui::SameLine(0.0f, 0.0f); + if (ImGui::SmallButton("click here")) + io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; +} + +// Helper to display basic user controls. +void ImGui::ShowUserGuide() +{ + ImGuiIO& io = ImGui::GetIO(); + ImGui::BulletText("Double-click on title bar to collapse window."); + ImGui::BulletText( + "Click and drag on lower corner to resize window\n" + "(double-click to auto fit window to its contents)."); + ImGui::BulletText("CTRL+Click on a slider or drag box to input value as text."); + ImGui::BulletText("TAB/SHIFT+TAB to cycle through keyboard editable fields."); + if (io.FontAllowUserScaling) + ImGui::BulletText("CTRL+Mouse Wheel to zoom window contents."); + ImGui::BulletText("While inputing text:\n"); + ImGui::Indent(); + ImGui::BulletText("CTRL+Left/Right to word jump."); + ImGui::BulletText("CTRL+A or double-click to select all."); + ImGui::BulletText("CTRL+X/C/V to use clipboard cut/copy/paste."); + ImGui::BulletText("CTRL+Z,CTRL+Y to undo/redo."); + ImGui::BulletText("ESCAPE to revert."); + ImGui::BulletText("You can apply arithmetic operators +,*,/ on numerical values.\nUse +- to subtract."); + ImGui::Unindent(); + ImGui::BulletText("With keyboard navigation enabled:"); + ImGui::Indent(); + ImGui::BulletText("Arrow keys to navigate."); + ImGui::BulletText("Space to activate a widget."); + ImGui::BulletText("Return to input text into a widget."); + ImGui::BulletText("Escape to deactivate a widget, close popup, exit child window."); + ImGui::BulletText("Alt to jump to the menu layer of a window."); + ImGui::BulletText("CTRL+Tab to select a window."); + ImGui::Unindent(); +} + +//----------------------------------------------------------------------------- +// [SECTION] Demo Window / ShowDemoWindow() +//----------------------------------------------------------------------------- +// - ShowDemoWindowWidgets() +// - ShowDemoWindowLayout() +// - ShowDemoWindowPopups() +// - ShowDemoWindowColumns() +// - ShowDemoWindowMisc() +//----------------------------------------------------------------------------- + +// We split the contents of the big ShowDemoWindow() function into smaller functions +// (because the link time of very large functions grow non-linearly) +static void ShowDemoWindowWidgets(); +static void ShowDemoWindowLayout(); +static void ShowDemoWindowPopups(); +static void ShowDemoWindowColumns(); +static void ShowDemoWindowMisc(); + +// Demonstrate most Dear ImGui features (this is big function!) +// You may execute this function to experiment with the UI and understand what it does. +// You may then search for keywords in the code when you are interested by a specific feature. +void ImGui::ShowDemoWindow(bool* p_open) +{ + // Exceptionally add an extra assert here for people confused about initial Dear ImGui setup + // Most ImGui functions would normally just crash if the context is missing. + IM_ASSERT(ImGui::GetCurrentContext() != NULL && "Missing dear imgui context. Refer to examples app!"); + + // Examples Apps (accessible from the "Examples" menu) + static bool show_app_main_menu_bar = false; + static bool show_app_dockspace = false; + static bool show_app_documents = false; + static bool show_app_console = false; + static bool show_app_log = false; + static bool show_app_layout = false; + static bool show_app_property_editor = false; + static bool show_app_long_text = false; + static bool show_app_auto_resize = false; + static bool show_app_constrained_resize = false; + static bool show_app_simple_overlay = false; + static bool show_app_window_titles = false; + static bool show_app_custom_rendering = false; + + if (show_app_main_menu_bar) ShowExampleAppMainMenuBar(); + if (show_app_dockspace) ShowExampleAppDockSpace(&show_app_dockspace); // Process the Docking app first, as explicit DockSpace() nodes needs to be submitted early (read comments near the DockSpace function) + if (show_app_documents) ShowExampleAppDocuments(&show_app_documents); // Process the Document app next, as it may also use a DockSpace() + if (show_app_console) ShowExampleAppConsole(&show_app_console); + if (show_app_log) ShowExampleAppLog(&show_app_log); + if (show_app_layout) ShowExampleAppLayout(&show_app_layout); + if (show_app_property_editor) ShowExampleAppPropertyEditor(&show_app_property_editor); + if (show_app_long_text) ShowExampleAppLongText(&show_app_long_text); + if (show_app_auto_resize) ShowExampleAppAutoResize(&show_app_auto_resize); + if (show_app_constrained_resize) ShowExampleAppConstrainedResize(&show_app_constrained_resize); + if (show_app_simple_overlay) ShowExampleAppSimpleOverlay(&show_app_simple_overlay); + if (show_app_window_titles) ShowExampleAppWindowTitles(&show_app_window_titles); + if (show_app_custom_rendering) ShowExampleAppCustomRendering(&show_app_custom_rendering); + + // Dear ImGui Apps (accessible from the "Tools" menu) + static bool show_app_metrics = false; + static bool show_app_style_editor = false; + static bool show_app_about = false; + + if (show_app_metrics) { ImGui::ShowMetricsWindow(&show_app_metrics); } + if (show_app_about) { ImGui::ShowAboutWindow(&show_app_about); } + if (show_app_style_editor) + { + ImGui::Begin("Dear ImGui Style Editor", &show_app_style_editor); + ImGui::ShowStyleEditor(); + ImGui::End(); + } + + // Demonstrate the various window flags. Typically you would just use the default! + static bool no_titlebar = false; + static bool no_scrollbar = false; + static bool no_menu = false; + static bool no_move = false; + static bool no_resize = false; + static bool no_collapse = false; + static bool no_close = false; + static bool no_nav = false; + static bool no_background = false; + static bool no_bring_to_front = false; + static bool no_docking = false; + + ImGuiWindowFlags window_flags = 0; + if (no_titlebar) window_flags |= ImGuiWindowFlags_NoTitleBar; + if (no_scrollbar) window_flags |= ImGuiWindowFlags_NoScrollbar; + if (!no_menu) window_flags |= ImGuiWindowFlags_MenuBar; + if (no_move) window_flags |= ImGuiWindowFlags_NoMove; + if (no_resize) window_flags |= ImGuiWindowFlags_NoResize; + if (no_collapse) window_flags |= ImGuiWindowFlags_NoCollapse; + if (no_nav) window_flags |= ImGuiWindowFlags_NoNav; + if (no_background) window_flags |= ImGuiWindowFlags_NoBackground; + if (no_bring_to_front) window_flags |= ImGuiWindowFlags_NoBringToFrontOnFocus; + if (no_docking) window_flags |= ImGuiWindowFlags_NoDocking; + if (no_close) p_open = NULL; // Don't pass our bool* to Begin + + // We specify a default position/size in case there's no data in the .ini file. + // We only do it to make the demo applications a little more welcoming, but typically this isn't required. + ImGuiViewport* main_viewport = ImGui::GetMainViewport(); + ImGui::SetNextWindowPos(ImVec2(main_viewport->GetWorkPos().x + 650, main_viewport->GetWorkPos().y + 20), ImGuiCond_FirstUseEver); + ImGui::SetNextWindowSize(ImVec2(550, 680), ImGuiCond_FirstUseEver); + + // Main body of the Demo window starts here. + if (!ImGui::Begin("Dear ImGui Demo", p_open, window_flags)) + { + // Early out if the window is collapsed, as an optimization. + ImGui::End(); + return; + } + + // Most "big" widgets share a common width settings by default. See 'Demo->Layout->Widgets Width' for details. + + // e.g. Use 2/3 of the space for widgets and 1/3 for labels (default) + //ImGui::PushItemWidth(ImGui::GetWindowWidth() * 0.65f); + + // e.g. Leave a fixed amount of width for labels (by passing a negative value), the rest goes to widgets. + ImGui::PushItemWidth(ImGui::GetFontSize() * -12); + + // Menu Bar + if (ImGui::BeginMenuBar()) + { + if (ImGui::BeginMenu("Menu")) + { + ShowExampleMenuFile(); + ImGui::EndMenu(); + } + if (ImGui::BeginMenu("Examples")) + { + ImGui::MenuItem("Main menu bar", NULL, &show_app_main_menu_bar); + ImGui::MenuItem("Console", NULL, &show_app_console); + ImGui::MenuItem("Log", NULL, &show_app_log); + ImGui::MenuItem("Simple layout", NULL, &show_app_layout); + ImGui::MenuItem("Property editor", NULL, &show_app_property_editor); + ImGui::MenuItem("Long text display", NULL, &show_app_long_text); + ImGui::MenuItem("Auto-resizing window", NULL, &show_app_auto_resize); + ImGui::MenuItem("Constrained-resizing window", NULL, &show_app_constrained_resize); + ImGui::MenuItem("Simple overlay", NULL, &show_app_simple_overlay); + ImGui::MenuItem("Manipulating window titles", NULL, &show_app_window_titles); + ImGui::MenuItem("Custom rendering", NULL, &show_app_custom_rendering); + ImGui::MenuItem("Dockspace", NULL, &show_app_dockspace); + ImGui::MenuItem("Documents", NULL, &show_app_documents); + ImGui::EndMenu(); + } + if (ImGui::BeginMenu("Tools")) + { + ImGui::MenuItem("Metrics", NULL, &show_app_metrics); + ImGui::MenuItem("Style Editor", NULL, &show_app_style_editor); + ImGui::MenuItem("About Dear ImGui", NULL, &show_app_about); + ImGui::EndMenu(); + } + ImGui::EndMenuBar(); + } + + ImGui::Text("dear imgui says hello. (%s)", IMGUI_VERSION); + ImGui::Spacing(); + + if (ImGui::CollapsingHeader("Help")) + { + ImGui::Text("ABOUT THIS DEMO:"); + ImGui::BulletText("Sections below are demonstrating many aspects of the library."); + ImGui::BulletText("The \"Examples\" menu above leads to more demo contents."); + ImGui::BulletText("The \"Tools\" menu above gives access to: About Box, Style Editor,\n" + "and Metrics (general purpose Dear ImGui debugging tool)."); + ImGui::Separator(); + + ImGui::Text("PROGRAMMER GUIDE:"); + ImGui::BulletText("See the ShowDemoWindow() code in imgui_demo.cpp. <- you are here!"); + ImGui::BulletText("See comments in imgui.cpp."); + ImGui::BulletText("See example applications in the examples/ folder."); + ImGui::BulletText("Read the FAQ at http://www.dearimgui.org/faq/"); + ImGui::BulletText("Set 'io.ConfigFlags |= NavEnableKeyboard' for keyboard controls."); + ImGui::BulletText("Set 'io.ConfigFlags |= NavEnableGamepad' for gamepad controls."); + ImGui::Separator(); + + ImGui::Text("USER GUIDE:"); + ImGui::ShowUserGuide(); + } + + if (ImGui::CollapsingHeader("Configuration")) + { + ImGuiIO& io = ImGui::GetIO(); + + if (ImGui::TreeNode("Configuration##2")) + { + ImGui::CheckboxFlags("io.ConfigFlags: NavEnableKeyboard", (unsigned int *)&io.ConfigFlags, ImGuiConfigFlags_NavEnableKeyboard); + ImGui::CheckboxFlags("io.ConfigFlags: NavEnableGamepad", (unsigned int *)&io.ConfigFlags, ImGuiConfigFlags_NavEnableGamepad); + ImGui::SameLine(); HelpMarker("Required back-end to feed in gamepad inputs in io.NavInputs[] and set io.BackendFlags |= ImGuiBackendFlags_HasGamepad.\n\nRead instructions in imgui.cpp for details."); + ImGui::CheckboxFlags("io.ConfigFlags: NavEnableSetMousePos", (unsigned int *)&io.ConfigFlags, ImGuiConfigFlags_NavEnableSetMousePos); + ImGui::SameLine(); HelpMarker("Instruct navigation to move the mouse cursor. See comment for ImGuiConfigFlags_NavEnableSetMousePos."); + ImGui::CheckboxFlags("io.ConfigFlags: NoMouse", (unsigned int *)&io.ConfigFlags, ImGuiConfigFlags_NoMouse); + + // The "NoMouse" option above can get us stuck with a disable mouse! Provide an alternative way to fix it: + if (io.ConfigFlags & ImGuiConfigFlags_NoMouse) + { + if (fmodf((float)ImGui::GetTime(), 0.40f) < 0.20f) + { + ImGui::SameLine(); + ImGui::Text("<>"); + } + if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Space))) + io.ConfigFlags &= ~ImGuiConfigFlags_NoMouse; + } + ImGui::CheckboxFlags("io.ConfigFlags: NoMouseCursorChange", (unsigned int *)&io.ConfigFlags, ImGuiConfigFlags_NoMouseCursorChange); + ImGui::SameLine(); HelpMarker("Instruct back-end to not alter mouse cursor shape and visibility."); + + ImGui::CheckboxFlags("io.ConfigFlags: DockingEnable", (unsigned int *)&io.ConfigFlags, ImGuiConfigFlags_DockingEnable); + ImGui::SameLine(); HelpMarker(io.ConfigDockingWithShift ? "[beta] Use SHIFT to dock window into each others." : "[beta] Drag from title bar to dock windows into each others."); + if (io.ConfigFlags & ImGuiConfigFlags_DockingEnable) + { + ImGui::Indent(); + ImGui::Checkbox("io.ConfigDockingNoSplit", &io.ConfigDockingNoSplit); + ImGui::SameLine(); HelpMarker("Simplified docking mode: disable window splitting, so docking is limited to merging multiple windows together into tab-bars."); + ImGui::Checkbox("io.ConfigDockingWithShift", &io.ConfigDockingWithShift); + ImGui::SameLine(); HelpMarker("Enable docking when holding Shift only (allows to drop in wider space, reduce visual noise)"); + ImGui::Checkbox("io.ConfigDockingAlwaysTabBar", &io.ConfigDockingAlwaysTabBar); + ImGui::SameLine(); HelpMarker("Create a docking node and tab-bar on single floating windows."); + ImGui::Checkbox("io.ConfigDockingTransparentPayload", &io.ConfigDockingTransparentPayload); + ImGui::SameLine(); HelpMarker("Make window or viewport transparent when docking and only display docking boxes on the target viewport. Useful if rendering of multiple viewport cannot be synced. Best used with ConfigViewportsNoAutoMerge."); + ImGui::Unindent(); + } + + ImGui::CheckboxFlags("io.ConfigFlags: ViewportsEnable", (unsigned int *)&io.ConfigFlags, ImGuiConfigFlags_ViewportsEnable); + ImGui::SameLine(); HelpMarker("[beta] Enable beta multi-viewports support. See ImGuiPlatformIO for details."); + if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) + { + ImGui::Indent(); + ImGui::Checkbox("io.ConfigViewportsNoAutoMerge", &io.ConfigViewportsNoAutoMerge); + ImGui::SameLine(); HelpMarker("Set to make all floating imgui windows always create their own viewport. Otherwise, they are merged into the main host viewports when overlapping it."); + ImGui::Checkbox("io.ConfigViewportsNoTaskBarIcon", &io.ConfigViewportsNoTaskBarIcon); + ImGui::SameLine(); HelpMarker("Toggling this at runtime is normally unsupported (most platform back-ends won't refresh the task bar icon state right away)."); + ImGui::Checkbox("io.ConfigViewportsNoDecoration", &io.ConfigViewportsNoDecoration); + ImGui::SameLine(); HelpMarker("Toggling this at runtime is normally unsupported (most platform back-ends won't refresh the decoration right away)."); + ImGui::Checkbox("io.ConfigViewportsNoDefaultParent", &io.ConfigViewportsNoDefaultParent); + ImGui::SameLine(); HelpMarker("Toggling this at runtime is normally unsupported (most platform back-ends won't refresh the parenting right away)."); + ImGui::Unindent(); + } + + ImGui::Checkbox("io.ConfigInputTextCursorBlink", &io.ConfigInputTextCursorBlink); + ImGui::SameLine(); HelpMarker("Set to false to disable blinking cursor, for users who consider it distracting"); + ImGui::Checkbox("io.ConfigWindowsResizeFromEdges", &io.ConfigWindowsResizeFromEdges); + ImGui::SameLine(); HelpMarker("Enable resizing of windows from their edges and from the lower-left corner.\nThis requires (io.BackendFlags & ImGuiBackendFlags_HasMouseCursors) because it needs mouse cursor feedback."); + ImGui::Checkbox("io.ConfigWindowsMoveFromTitleBarOnly", &io.ConfigWindowsMoveFromTitleBarOnly); + ImGui::Checkbox("io.MouseDrawCursor", &io.MouseDrawCursor); + ImGui::SameLine(); HelpMarker("Instruct Dear ImGui to render a mouse cursor itself. Note that a mouse cursor rendered via your application GPU rendering path will feel more laggy than hardware cursor, but will be more in sync with your other visuals.\n\nSome desktop applications may use both kinds of cursors (e.g. enable software cursor only when resizing/dragging something)."); + ImGui::TreePop(); + ImGui::Separator(); + } + + if (ImGui::TreeNode("Backend Flags")) + { + HelpMarker( + "Those flags are set by the back-ends (imgui_impl_xxx files) to specify their capabilities.\n" + "Here we expose then as read-only fields to avoid breaking interactions with your back-end."); + // Make a local copy to avoid modifying actual back-end flags. + ImGuiBackendFlags backend_flags = io.BackendFlags; + ImGui::CheckboxFlags("io.BackendFlags: HasGamepad", (unsigned int *)&backend_flags, ImGuiBackendFlags_HasGamepad); + ImGui::CheckboxFlags("io.BackendFlags: HasMouseCursors", (unsigned int *)&backend_flags, ImGuiBackendFlags_HasMouseCursors); + ImGui::CheckboxFlags("io.BackendFlags: HasSetMousePos", (unsigned int *)&backend_flags, ImGuiBackendFlags_HasSetMousePos); + ImGui::CheckboxFlags("io.BackendFlags: PlatformHasViewports", (unsigned int *)&backend_flags, ImGuiBackendFlags_PlatformHasViewports); + ImGui::CheckboxFlags("io.BackendFlags: HasMouseHoveredViewport", (unsigned int *)&backend_flags, ImGuiBackendFlags_HasMouseHoveredViewport); + ImGui::CheckboxFlags("io.BackendFlags: RendererHasVtxOffset", (unsigned int *)&backend_flags, ImGuiBackendFlags_RendererHasVtxOffset); + ImGui::CheckboxFlags("io.BackendFlags: RendererHasViewports", (unsigned int *)&backend_flags, ImGuiBackendFlags_RendererHasViewports); + ImGui::TreePop(); + ImGui::Separator(); + } + + if (ImGui::TreeNode("Style")) + { + HelpMarker("The same contents can be accessed in 'Tools->Style Editor' or by calling the ShowStyleEditor() function."); + ImGui::ShowStyleEditor(); + ImGui::TreePop(); + ImGui::Separator(); + } + + if (ImGui::TreeNode("Capture/Logging")) + { + HelpMarker( + "The logging API redirects all text output so you can easily capture the content of " + "a window or a block. Tree nodes can be automatically expanded.\n" + "Try opening any of the contents below in this window and then click one of the \"Log To\" button."); + ImGui::LogButtons(); + + HelpMarker("You can also call ImGui::LogText() to output directly to the log without a visual output."); + if (ImGui::Button("Copy \"Hello, world!\" to clipboard")) + { + ImGui::LogToClipboard(); + ImGui::LogText("Hello, world!"); + ImGui::LogFinish(); + } + ImGui::TreePop(); + } + } + + if (ImGui::CollapsingHeader("Window options")) + { + ImGui::Checkbox("No titlebar", &no_titlebar); ImGui::SameLine(150); + ImGui::Checkbox("No scrollbar", &no_scrollbar); ImGui::SameLine(300); + ImGui::Checkbox("No menu", &no_menu); + ImGui::Checkbox("No move", &no_move); ImGui::SameLine(150); + ImGui::Checkbox("No resize", &no_resize); ImGui::SameLine(300); + ImGui::Checkbox("No collapse", &no_collapse); + ImGui::Checkbox("No close", &no_close); ImGui::SameLine(150); + ImGui::Checkbox("No nav", &no_nav); ImGui::SameLine(300); + ImGui::Checkbox("No background", &no_background); + ImGui::Checkbox("No bring to front", &no_bring_to_front); + ImGui::Checkbox("No docking", &no_docking); + } + + // All demo contents + ShowDemoWindowWidgets(); + ShowDemoWindowLayout(); + ShowDemoWindowPopups(); + ShowDemoWindowColumns(); + ShowDemoWindowMisc(); + + // End of ShowDemoWindow() + ImGui::End(); +} + +static void ShowDemoWindowWidgets() +{ + if (!ImGui::CollapsingHeader("Widgets")) + return; + + if (ImGui::TreeNode("Basic")) + { + static int clicked = 0; + if (ImGui::Button("Button")) + clicked++; + if (clicked & 1) + { + ImGui::SameLine(); + ImGui::Text("Thanks for clicking me!"); + } + + static bool check = true; + ImGui::Checkbox("checkbox", &check); + + static int e = 0; + ImGui::RadioButton("radio a", &e, 0); ImGui::SameLine(); + ImGui::RadioButton("radio b", &e, 1); ImGui::SameLine(); + ImGui::RadioButton("radio c", &e, 2); + + // Color buttons, demonstrate using PushID() to add unique identifier in the ID stack, and changing style. + for (int i = 0; i < 7; i++) + { + if (i > 0) + ImGui::SameLine(); + ImGui::PushID(i); + ImGui::PushStyleColor(ImGuiCol_Button, (ImVec4)ImColor::HSV(i/7.0f, 0.6f, 0.6f)); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, (ImVec4)ImColor::HSV(i/7.0f, 0.7f, 0.7f)); + ImGui::PushStyleColor(ImGuiCol_ButtonActive, (ImVec4)ImColor::HSV(i/7.0f, 0.8f, 0.8f)); + ImGui::Button("Click"); + ImGui::PopStyleColor(3); + ImGui::PopID(); + } + + // Use AlignTextToFramePadding() to align text baseline to the baseline of framed widgets elements + // (otherwise a Text+SameLine+Button sequence will have the text a little too high by default!) + // See 'Demo->Layout->Text Baseline Alignment' for details. + ImGui::AlignTextToFramePadding(); + ImGui::Text("Hold to repeat:"); + ImGui::SameLine(); + + // Arrow buttons with Repeater + static int counter = 0; + float spacing = ImGui::GetStyle().ItemInnerSpacing.x; + ImGui::PushButtonRepeat(true); + if (ImGui::ArrowButton("##left", ImGuiDir_Left)) { counter--; } + ImGui::SameLine(0.0f, spacing); + if (ImGui::ArrowButton("##right", ImGuiDir_Right)) { counter++; } + ImGui::PopButtonRepeat(); + ImGui::SameLine(); + ImGui::Text("%d", counter); + + ImGui::Text("Hover over me"); + if (ImGui::IsItemHovered()) + ImGui::SetTooltip("I am a tooltip"); + + ImGui::SameLine(); + ImGui::Text("- or me"); + if (ImGui::IsItemHovered()) + { + ImGui::BeginTooltip(); + ImGui::Text("I am a fancy tooltip"); + static float arr[] = { 0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f }; + ImGui::PlotLines("Curve", arr, IM_ARRAYSIZE(arr)); + ImGui::EndTooltip(); + } + + ImGui::Separator(); + + ImGui::LabelText("label", "Value"); + + { + // Using the _simplified_ one-liner Combo() api here + // See "Combo" section for examples of how to use the more complete BeginCombo()/EndCombo() api. + const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIIIIII", "JJJJ", "KKKKKKK" }; + static int item_current = 0; + ImGui::Combo("combo", &item_current, items, IM_ARRAYSIZE(items)); + ImGui::SameLine(); HelpMarker("Refer to the \"Combo\" section below for an explanation of the full BeginCombo/EndCombo API, and demonstration of various flags.\n"); + } + + { + // To wire InputText() with std::string or any other custom string type, + // see the "Text Input > Resize Callback" section of this demo, and the misc/cpp/imgui_stdlib.h file. + static char str0[128] = "Hello, world!"; + ImGui::InputText("input text", str0, IM_ARRAYSIZE(str0)); + ImGui::SameLine(); HelpMarker( + "USER:\n" + "Hold SHIFT or use mouse to select text.\n" + "CTRL+Left/Right to word jump.\n" + "CTRL+A or double-click to select all.\n" + "CTRL+X,CTRL+C,CTRL+V clipboard.\n" + "CTRL+Z,CTRL+Y undo/redo.\n" + "ESCAPE to revert.\n\n" + "PROGRAMMER:\n" + "You can use the ImGuiInputTextFlags_CallbackResize facility if you need to wire InputText() " + "to a dynamic string type. See misc/cpp/imgui_stdlib.h for an example (this is not demonstrated " + "in imgui_demo.cpp)."); + + static char str1[128] = ""; + ImGui::InputTextWithHint("input text (w/ hint)", "enter text here", str1, IM_ARRAYSIZE(str1)); + + static int i0 = 123; + ImGui::InputInt("input int", &i0); + ImGui::SameLine(); HelpMarker( + "You can apply arithmetic operators +,*,/ on numerical values.\n" + " e.g. [ 100 ], input \'*2\', result becomes [ 200 ]\n" + "Use +- to subtract."); + + static float f0 = 0.001f; + ImGui::InputFloat("input float", &f0, 0.01f, 1.0f, "%.3f"); + + static double d0 = 999999.00000001; + ImGui::InputDouble("input double", &d0, 0.01f, 1.0f, "%.8f"); + + static float f1 = 1.e10f; + ImGui::InputFloat("input scientific", &f1, 0.0f, 0.0f, "%e"); + ImGui::SameLine(); HelpMarker( + "You can input value using the scientific notation,\n" + " e.g. \"1e+8\" becomes \"100000000\"."); + + static float vec4a[4] = { 0.10f, 0.20f, 0.30f, 0.44f }; + ImGui::InputFloat3("input float3", vec4a); + } + + { + static int i1 = 50, i2 = 42; + ImGui::DragInt("drag int", &i1, 1); + ImGui::SameLine(); HelpMarker( + "Click and drag to edit value.\n" + "Hold SHIFT/ALT for faster/slower edit.\n" + "Double-click or CTRL+click to input value."); + + ImGui::DragInt("drag int 0..100", &i2, 1, 0, 100, "%d%%"); + + static float f1=1.00f, f2=0.0067f; + ImGui::DragFloat("drag float", &f1, 0.005f); + ImGui::DragFloat("drag small float", &f2, 0.0001f, 0.0f, 0.0f, "%.06f ns"); + } + + { + static int i1=0; + ImGui::SliderInt("slider int", &i1, -1, 3); + ImGui::SameLine(); HelpMarker("CTRL+click to input value."); + + static float f1=0.123f, f2=0.0f; + ImGui::SliderFloat("slider float", &f1, 0.0f, 1.0f, "ratio = %.3f"); + ImGui::SliderFloat("slider float (curve)", &f2, -10.0f, 10.0f, "%.4f", 2.0f); + + static float angle = 0.0f; + ImGui::SliderAngle("slider angle", &angle); + + // Using the format string to display a name instead of an integer. + // Here we completely omit '%d' from the format string, so it'll only display a name. + // This technique can also be used with DragInt(). + enum Element { Element_Fire, Element_Earth, Element_Air, Element_Water, Element_COUNT }; + static int elem = Element_Fire; + const char* elems_names[Element_COUNT] = { "Fire", "Earth", "Air", "Water" }; + const char* elem_name = (elem >= 0 && elem < Element_COUNT) ? elems_names[elem] : "Unknown"; + ImGui::SliderInt("slider enum", &elem, 0, Element_COUNT - 1, elem_name); + ImGui::SameLine(); HelpMarker("Using the format string parameter to display a name instead of the underlying integer."); + } + + { + static float col1[3] = { 1.0f,0.0f,0.2f }; + static float col2[4] = { 0.4f,0.7f,0.0f,0.5f }; + ImGui::ColorEdit3("color 1", col1); + ImGui::SameLine(); HelpMarker( + "Click on the colored square to open a color picker.\n" + "Click and hold to use drag and drop.\n" + "Right-click on the colored square to show options.\n" + "CTRL+click on individual component to input value.\n"); + + ImGui::ColorEdit4("color 2", col2); + } + + { + // List box + const char* items[] = { "Apple", "Banana", "Cherry", "Kiwi", "Mango", "Orange", "Pineapple", "Strawberry", "Watermelon" }; + static int item_current = 1; + ImGui::ListBox("listbox\n(single select)", &item_current, items, IM_ARRAYSIZE(items), 4); + + //static int listbox_item_current2 = 2; + //ImGui::SetNextItemWidth(-1); + //ImGui::ListBox("##listbox2", &listbox_item_current2, listbox_items, IM_ARRAYSIZE(listbox_items), 4); + } + + ImGui::TreePop(); + } + + // Testing ImGuiOnceUponAFrame helper. + //static ImGuiOnceUponAFrame once; + //for (int i = 0; i < 5; i++) + // if (once) + // ImGui::Text("This will be displayed only once."); + + if (ImGui::TreeNode("Trees")) + { + if (ImGui::TreeNode("Basic trees")) + { + for (int i = 0; i < 5; i++) + { + // Use SetNextItemOpen() so set the default state of a node to be open. We could + // also use TreeNodeEx() with the ImGuiTreeNodeFlags_DefaultOpen flag to achieve the same thing! + if (i == 0) + ImGui::SetNextItemOpen(true, ImGuiCond_Once); + + if (ImGui::TreeNode((void*)(intptr_t)i, "Child %d", i)) + { + ImGui::Text("blah blah"); + ImGui::SameLine(); + if (ImGui::SmallButton("button")) {} + ImGui::TreePop(); + } + } + ImGui::TreePop(); + } + + if (ImGui::TreeNode("Advanced, with Selectable nodes")) + { + HelpMarker( + "This is a more typical looking tree with selectable nodes.\n" + "Click to select, CTRL+Click to toggle, click on arrows or double-click to open."); + static ImGuiTreeNodeFlags base_flags = ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_SpanAvailWidth; + static bool align_label_with_current_x_position = false; + static bool test_drag_and_drop = false; + ImGui::CheckboxFlags("ImGuiTreeNodeFlags_OpenOnArrow", (unsigned int*)&base_flags, ImGuiTreeNodeFlags_OpenOnArrow); + ImGui::CheckboxFlags("ImGuiTreeNodeFlags_OpenOnDoubleClick", (unsigned int*)&base_flags, ImGuiTreeNodeFlags_OpenOnDoubleClick); + ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanAvailWidth", (unsigned int*)&base_flags, ImGuiTreeNodeFlags_SpanAvailWidth); ImGui::SameLine(); HelpMarker("Extend hit area to all available width instead of allowing more items to be laid out after the node."); + ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanFullWidth", (unsigned int*)&base_flags, ImGuiTreeNodeFlags_SpanFullWidth); + ImGui::Checkbox("Align label with current X position", &align_label_with_current_x_position); + ImGui::Checkbox("Test tree node as drag source", &test_drag_and_drop); + ImGui::Text("Hello!"); + if (align_label_with_current_x_position) + ImGui::Unindent(ImGui::GetTreeNodeToLabelSpacing()); + + // 'selection_mask' is dumb representation of what may be user-side selection state. + // You may retain selection state inside or outside your objects in whatever format you see fit. + // 'node_clicked' is temporary storage of what node we have clicked to process selection at the end + /// of the loop. May be a pointer to your own node type, etc. + static int selection_mask = (1 << 2); + int node_clicked = -1; + for (int i = 0; i < 6; i++) + { + // Disable the default "open on single-click behavior" + set Selected flag according to our selection. + ImGuiTreeNodeFlags node_flags = base_flags; + const bool is_selected = (selection_mask & (1 << i)) != 0; + if (is_selected) + node_flags |= ImGuiTreeNodeFlags_Selected; + if (i < 3) + { + // Items 0..2 are Tree Node + bool node_open = ImGui::TreeNodeEx((void*)(intptr_t)i, node_flags, "Selectable Node %d", i); + if (ImGui::IsItemClicked()) + node_clicked = i; + if (test_drag_and_drop && ImGui::BeginDragDropSource()) + { + ImGui::SetDragDropPayload("_TREENODE", NULL, 0); + ImGui::Text("This is a drag and drop source"); + ImGui::EndDragDropSource(); + } + if (node_open) + { + ImGui::BulletText("Blah blah\nBlah Blah"); + ImGui::TreePop(); + } + } + else + { + // Items 3..5 are Tree Leaves + // The only reason we use TreeNode at all is to allow selection of the leaf. Otherwise we can + // use BulletText() or advance the cursor by GetTreeNodeToLabelSpacing() and call Text(). + node_flags |= ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen; // ImGuiTreeNodeFlags_Bullet + ImGui::TreeNodeEx((void*)(intptr_t)i, node_flags, "Selectable Leaf %d", i); + if (ImGui::IsItemClicked()) + node_clicked = i; + if (test_drag_and_drop && ImGui::BeginDragDropSource()) + { + ImGui::SetDragDropPayload("_TREENODE", NULL, 0); + ImGui::Text("This is a drag and drop source"); + ImGui::EndDragDropSource(); + } + } + } + if (node_clicked != -1) + { + // Update selection state + // (process outside of tree loop to avoid visual inconsistencies during the clicking frame) + if (ImGui::GetIO().KeyCtrl) + selection_mask ^= (1 << node_clicked); // CTRL+click to toggle + else //if (!(selection_mask & (1 << node_clicked))) // Depending on selection behavior you want, may want to preserve selection when clicking on item that is part of the selection + selection_mask = (1 << node_clicked); // Click to single-select + } + if (align_label_with_current_x_position) + ImGui::Indent(ImGui::GetTreeNodeToLabelSpacing()); + ImGui::TreePop(); + } + ImGui::TreePop(); + } + + if (ImGui::TreeNode("Collapsing Headers")) + { + static bool closable_group = true; + ImGui::Checkbox("Show 2nd header", &closable_group); + if (ImGui::CollapsingHeader("Header", ImGuiTreeNodeFlags_None)) + { + ImGui::Text("IsItemHovered: %d", ImGui::IsItemHovered()); + for (int i = 0; i < 5; i++) + ImGui::Text("Some content %d", i); + } + if (ImGui::CollapsingHeader("Header with a close button", &closable_group)) + { + ImGui::Text("IsItemHovered: %d", ImGui::IsItemHovered()); + for (int i = 0; i < 5; i++) + ImGui::Text("More content %d", i); + } + /* + if (ImGui::CollapsingHeader("Header with a bullet", ImGuiTreeNodeFlags_Bullet)) + ImGui::Text("IsItemHovered: %d", ImGui::IsItemHovered()); + */ + ImGui::TreePop(); + } + + if (ImGui::TreeNode("Bullets")) + { + ImGui::BulletText("Bullet point 1"); + ImGui::BulletText("Bullet point 2\nOn multiple lines"); + if (ImGui::TreeNode("Tree node")) + { + ImGui::BulletText("Another bullet point"); + ImGui::TreePop(); + } + ImGui::Bullet(); ImGui::Text("Bullet point 3 (two calls)"); + ImGui::Bullet(); ImGui::SmallButton("Button"); + ImGui::TreePop(); + } + + if (ImGui::TreeNode("Text")) + { + if (ImGui::TreeNode("Colored Text")) + { + // Using shortcut. You can use PushStyleColor()/PopStyleColor() for more flexibility. + ImGui::TextColored(ImVec4(1.0f,0.0f,1.0f,1.0f), "Pink"); + ImGui::TextColored(ImVec4(1.0f,1.0f,0.0f,1.0f), "Yellow"); + ImGui::TextDisabled("Disabled"); + ImGui::SameLine(); HelpMarker("The TextDisabled color is stored in ImGuiStyle."); + ImGui::TreePop(); + } + + if (ImGui::TreeNode("Word Wrapping")) + { + // Using shortcut. You can use PushTextWrapPos()/PopTextWrapPos() for more flexibility. + ImGui::TextWrapped("This text should automatically wrap on the edge of the window. The current implementation for text wrapping follows simple rules suitable for English and possibly other languages."); + ImGui::Spacing(); + + static float wrap_width = 200.0f; + ImGui::SliderFloat("Wrap width", &wrap_width, -20, 600, "%.0f"); + + ImDrawList* draw_list = ImGui::GetWindowDrawList(); + for (int n = 0; n < 2; n++) + { + ImGui::Text("Test paragraph %d:", n); + ImVec2 pos = ImGui::GetCursorScreenPos(); + ImVec2 marker_min = ImVec2(pos.x + wrap_width, pos.y); + ImVec2 marker_max = ImVec2(pos.x + wrap_width + 10, pos.y + ImGui::GetTextLineHeight()); + ImGui::PushTextWrapPos(ImGui::GetCursorPos().x + wrap_width); + if (n == 0) + ImGui::Text("The lazy dog is a good dog. This paragraph should fit within %.0f pixels. Testing a 1 character word. The quick brown fox jumps over the lazy dog.", wrap_width); + if (n == 1) + ImGui::Text("aaaaaaaa bbbbbbbb, c cccccccc,dddddddd. d eeeeeeee ffffffff. gggggggg!hhhhhhhh"); + + // Draw actual text bounding box, following by marker of our expected limit (should not overlap!) + draw_list->AddRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax(), IM_COL32(255, 255, 0, 255)); + draw_list->AddRectFilled(marker_min, marker_max, IM_COL32(255, 0, 255, 255)); + ImGui::PopTextWrapPos(); + } + + ImGui::TreePop(); + } + + if (ImGui::TreeNode("UTF-8 Text")) + { + // UTF-8 test with Japanese characters + // (Needs a suitable font? Try "Google Noto" or "Arial Unicode". See docs/FONTS.txt for details.) + // - From C++11 you can use the u8"my text" syntax to encode literal strings as UTF-8 + // - For earlier compiler, you may be able to encode your sources as UTF-8 (e.g. in Visual Studio, you + // can save your source files as 'UTF-8 without signature'). + // - FOR THIS DEMO FILE ONLY, BECAUSE WE WANT TO SUPPORT OLD COMPILERS, WE ARE *NOT* INCLUDING RAW UTF-8 + // CHARACTERS IN THIS SOURCE FILE. Instead we are encoding a few strings with hexadecimal constants. + // Don't do this in your application! Please use u8"text in any language" in your application! + // Note that characters values are preserved even by InputText() if the font cannot be displayed, + // so you can safely copy & paste garbled characters into another application. + ImGui::TextWrapped( + "CJK text will only appears if the font was loaded with the appropriate CJK character ranges. " + "Call io.Font->AddFontFromFileTTF() manually to load extra character ranges. " + "Read docs/FONTS.txt for details."); + ImGui::Text("Hiragana: \xe3\x81\x8b\xe3\x81\x8d\xe3\x81\x8f\xe3\x81\x91\xe3\x81\x93 (kakikukeko)"); // Normally we would use u8"blah blah" with the proper characters directly in the string. + ImGui::Text("Kanjis: \xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e (nihongo)"); + static char buf[32] = "\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e"; + //static char buf[32] = u8"NIHONGO"; // <- this is how you would write it with C++11, using real kanjis + ImGui::InputText("UTF-8 input", buf, IM_ARRAYSIZE(buf)); + ImGui::TreePop(); + } + ImGui::TreePop(); + } + + if (ImGui::TreeNode("Images")) + { + ImGuiIO& io = ImGui::GetIO(); + ImGui::TextWrapped("Below we are displaying the font texture (which is the only texture we have access to in this demo). Use the 'ImTextureID' type as storage to pass pointers or identifier to your own texture data. Hover the texture for a zoomed view!"); + + // Below we are displaying the font texture because it is the only texture we have access to inside the demo! + // Remember that ImTextureID is just storage for whatever you want it to be. It is essentially a value that + // will be passed to the rendering back-end via the ImDrawCmd structure. + // If you use one of the default imgui_impl_XXXX.cpp rendering back-end, they all have comments at the top + // of their respective source file to specify what they expect to be stored in ImTextureID, for example: + // - The imgui_impl_dx11.cpp renderer expect a 'ID3D11ShaderResourceView*' pointer + // - The imgui_impl_opengl3.cpp renderer expect a GLuint OpenGL texture identifier, etc. + // More: + // - If you decided that ImTextureID = MyEngineTexture*, then you can pass your MyEngineTexture* pointers + // to ImGui::Image(), and gather width/height through your own functions, etc. + // - You can use ShowMetricsWindow() to inspect the draw data that are being passed to your renderer, + // it will help you debug issues if you are confused about it. + // - Consider using the lower-level ImDrawList::AddImage() API, via ImGui::GetWindowDrawList()->AddImage(). + // - Read https://github.com/ocornut/imgui/blob/master/docs/FAQ.md + // - Read https://github.com/ocornut/imgui/wiki/Image-Loading-and-Displaying-Examples + ImTextureID my_tex_id = io.Fonts->TexID; + float my_tex_w = (float)io.Fonts->TexWidth; + float my_tex_h = (float)io.Fonts->TexHeight; + { + ImGui::Text("%.0fx%.0f", my_tex_w, my_tex_h); + ImVec2 pos = ImGui::GetCursorScreenPos(); + ImVec2 uv_min = ImVec2(0.0f, 0.0f); // Top-left + ImVec2 uv_max = ImVec2(1.0f, 1.0f); // Lower-right + ImVec4 tint_col = ImVec4(1.0f, 1.0f, 1.0f, 1.0f); // No tint + ImVec4 border_col = ImVec4(1.0f, 1.0f, 1.0f, 0.5f); // 50% opaque white + ImGui::Image(my_tex_id, ImVec2(my_tex_w, my_tex_h), uv_min, uv_max, tint_col, border_col); + if (ImGui::IsItemHovered()) + { + ImGui::BeginTooltip(); + float region_sz = 32.0f; + float region_x = io.MousePos.x - pos.x - region_sz * 0.5f; + float region_y = io.MousePos.y - pos.y - region_sz * 0.5f; + float zoom = 4.0f; + if (region_x < 0.0f) { region_x = 0.0f; } + else if (region_x > my_tex_w - region_sz) { region_x = my_tex_w - region_sz; } + if (region_y < 0.0f) { region_y = 0.0f; } + else if (region_y > my_tex_h - region_sz) { region_y = my_tex_h - region_sz; } + ImGui::Text("Min: (%.2f, %.2f)", region_x, region_y); + ImGui::Text("Max: (%.2f, %.2f)", region_x + region_sz, region_y + region_sz); + ImVec2 uv0 = ImVec2((region_x) / my_tex_w, (region_y) / my_tex_h); + ImVec2 uv1 = ImVec2((region_x + region_sz) / my_tex_w, (region_y + region_sz) / my_tex_h); + ImGui::Image(my_tex_id, ImVec2(region_sz * zoom, region_sz * zoom), uv0, uv1, tint_col, border_col); + ImGui::EndTooltip(); + } + } + ImGui::TextWrapped("And now some textured buttons.."); + static int pressed_count = 0; + for (int i = 0; i < 8; i++) + { + ImGui::PushID(i); + int frame_padding = -1 + i; // -1 == uses default padding (style.FramePadding) + ImVec2 size = ImVec2(32.0f, 32.0f); // Size of the image we want to make visible + ImVec2 uv0 = ImVec2(0.0f, 0.0f); // UV coordinates for lower-left + ImVec2 uv1 = ImVec2(32.0f / my_tex_w, 32 / my_tex_h); // UV coordinates for (32,32) in our texture + ImVec4 bg_col = ImVec4(0.0f, 0.0f, 0.0f, 1.0f); // Black background + ImVec4 tint_col = ImVec4(1.0f, 1.0f, 1.0f, 1.0f); // No tint + if (ImGui::ImageButton(my_tex_id, size, uv0, uv1, frame_padding, bg_col, tint_col)) + pressed_count += 1; + ImGui::PopID(); + ImGui::SameLine(); + } + ImGui::NewLine(); + ImGui::Text("Pressed %d times.", pressed_count); + ImGui::TreePop(); + } + + if (ImGui::TreeNode("Combo")) + { + // Expose flags as checkbox for the demo + static ImGuiComboFlags flags = 0; + ImGui::CheckboxFlags("ImGuiComboFlags_PopupAlignLeft", (unsigned int*)&flags, ImGuiComboFlags_PopupAlignLeft); + ImGui::SameLine(); HelpMarker("Only makes a difference if the popup is larger than the combo"); + if (ImGui::CheckboxFlags("ImGuiComboFlags_NoArrowButton", (unsigned int*)&flags, ImGuiComboFlags_NoArrowButton)) + flags &= ~ImGuiComboFlags_NoPreview; // Clear the other flag, as we cannot combine both + if (ImGui::CheckboxFlags("ImGuiComboFlags_NoPreview", (unsigned int*)&flags, ImGuiComboFlags_NoPreview)) + flags &= ~ImGuiComboFlags_NoArrowButton; // Clear the other flag, as we cannot combine both + + // Using the generic BeginCombo() API, you have full control over how to display the combo contents. + // (your selection data could be an index, a pointer to the object, an id for the object, a flag intrusively + // stored in the object itself, etc.) + const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIII", "JJJJ", "KKKK", "LLLLLLL", "MMMM", "OOOOOOO" }; + static int item_current_idx = 0; // Here our selection data is an index. + const char* combo_label = items[item_current_idx]; // Label to preview before opening the combo (technically could be anything)( + if (ImGui::BeginCombo("combo 1", combo_label, flags)) + { + for (int n = 0; n < IM_ARRAYSIZE(items); n++) + { + const bool is_selected = (item_current_idx == n); + if (ImGui::Selectable(items[n], is_selected)) + item_current_idx = n; + + // Set the initial focus when opening the combo (scrolling + keyboard navigation focus) + if (is_selected) + ImGui::SetItemDefaultFocus(); + } + ImGui::EndCombo(); + } + + // Simplified one-liner Combo() API, using values packed in a single constant string + static int item_current_2 = 0; + ImGui::Combo("combo 2 (one-liner)", &item_current_2, "aaaa\0bbbb\0cccc\0dddd\0eeee\0\0"); + + // Simplified one-liner Combo() using an array of const char* + static int item_current_3 = -1; // If the selection isn't within 0..count, Combo won't display a preview + ImGui::Combo("combo 3 (array)", &item_current_3, items, IM_ARRAYSIZE(items)); + + // Simplified one-liner Combo() using an accessor function + struct FuncHolder { static bool ItemGetter(void* data, int idx, const char** out_str) { *out_str = ((const char**)data)[idx]; return true; } }; + static int item_current_4 = 0; + ImGui::Combo("combo 4 (function)", &item_current_4, &FuncHolder::ItemGetter, items, IM_ARRAYSIZE(items)); + + ImGui::TreePop(); + } + + if (ImGui::TreeNode("Selectables")) + { + // Selectable() has 2 overloads: + // - The one taking "bool selected" as a read-only selection information. + // When Selectable() has been clicked it returns true and you can alter selection state accordingly. + // - The one taking "bool* p_selected" as a read-write selection information (convenient in some cases) + // The earlier is more flexible, as in real application your selection may be stored in many different ways + // and not necessarily inside a bool value (e.g. in flags within objects, as an external list, etc). + if (ImGui::TreeNode("Basic")) + { + static bool selection[5] = { false, true, false, false, false }; + ImGui::Selectable("1. I am selectable", &selection[0]); + ImGui::Selectable("2. I am selectable", &selection[1]); + ImGui::Text("3. I am not selectable"); + ImGui::Selectable("4. I am selectable", &selection[3]); + if (ImGui::Selectable("5. I am double clickable", selection[4], ImGuiSelectableFlags_AllowDoubleClick)) + if (ImGui::IsMouseDoubleClicked(0)) + selection[4] = !selection[4]; + ImGui::TreePop(); + } + if (ImGui::TreeNode("Selection State: Single Selection")) + { + static int selected = -1; + for (int n = 0; n < 5; n++) + { + char buf[32]; + sprintf(buf, "Object %d", n); + if (ImGui::Selectable(buf, selected == n)) + selected = n; + } + ImGui::TreePop(); + } + if (ImGui::TreeNode("Selection State: Multiple Selection")) + { + HelpMarker("Hold CTRL and click to select multiple items."); + static bool selection[5] = { false, false, false, false, false }; + for (int n = 0; n < 5; n++) + { + char buf[32]; + sprintf(buf, "Object %d", n); + if (ImGui::Selectable(buf, selection[n])) + { + if (!ImGui::GetIO().KeyCtrl) // Clear selection when CTRL is not held + memset(selection, 0, sizeof(selection)); + selection[n] ^= 1; + } + } + ImGui::TreePop(); + } + if (ImGui::TreeNode("Rendering more text into the same line")) + { + // Using the Selectable() override that takes "bool* p_selected" parameter, + // this function toggle your bool value automatically. + static bool selected[3] = { false, false, false }; + ImGui::Selectable("main.c", &selected[0]); ImGui::SameLine(300); ImGui::Text(" 2,345 bytes"); + ImGui::Selectable("Hello.cpp", &selected[1]); ImGui::SameLine(300); ImGui::Text("12,345 bytes"); + ImGui::Selectable("Hello.h", &selected[2]); ImGui::SameLine(300); ImGui::Text(" 2,345 bytes"); + ImGui::TreePop(); + } + if (ImGui::TreeNode("In columns")) + { + ImGui::Columns(3, NULL, false); + static bool selected[16] = {}; + for (int i = 0; i < 16; i++) + { + char label[32]; sprintf(label, "Item %d", i); + if (ImGui::Selectable(label, &selected[i])) {} + ImGui::NextColumn(); + } + ImGui::Columns(1); + ImGui::TreePop(); + } + if (ImGui::TreeNode("Grid")) + { + static int selected[4*4] = { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 }; + for (int i = 0; i < 4*4; i++) + { + ImGui::PushID(i); + if (ImGui::Selectable("Sailor", selected[i] != 0, 0, ImVec2(50,50))) + { + // Toggle + selected[i] = !selected[i]; + + // Note: We _unnecessarily_ test for both x/y and i here only to silence some static analyzer. + // The second part of each test is unnecessary. + int x = i % 4; + int y = i / 4; + if (x > 0) { selected[i - 1] ^= 1; } + if (x < 3 && i < 15) { selected[i + 1] ^= 1; } + if (y > 0 && i > 3) { selected[i - 4] ^= 1; } + if (y < 3 && i < 12) { selected[i + 4] ^= 1; } + } + if ((i % 4) < 3) ImGui::SameLine(); + ImGui::PopID(); + } + ImGui::TreePop(); + } + if (ImGui::TreeNode("Alignment")) + { + HelpMarker( + "By default, Selectables uses style.SelectableTextAlign but it can be overridden on a per-item " + "basis using PushStyleVar(). You'll probably want to always keep your default situation to " + "left-align otherwise it becomes difficult to layout multiple items on a same line"); + static bool selected[3 * 3] = { true, false, true, false, true, false, true, false, true }; + for (int y = 0; y < 3; y++) + { + for (int x = 0; x < 3; x++) + { + ImVec2 alignment = ImVec2((float)x / 2.0f, (float)y / 2.0f); + char name[32]; + sprintf(name, "(%.1f,%.1f)", alignment.x, alignment.y); + if (x > 0) ImGui::SameLine(); + ImGui::PushStyleVar(ImGuiStyleVar_SelectableTextAlign, alignment); + ImGui::Selectable(name, &selected[3*y+x], ImGuiSelectableFlags_None, ImVec2(80,80)); + ImGui::PopStyleVar(); + } + } + ImGui::TreePop(); + } + ImGui::TreePop(); + } + + // To wire InputText() with std::string or any other custom string type, + // see the "Text Input > Resize Callback" section of this demo, and the misc/cpp/imgui_stdlib.h file. + if (ImGui::TreeNode("Text Input")) + { + if (ImGui::TreeNode("Multi-line Text Input")) + { + // Note: we are using a fixed-sized buffer for simplicity here. See ImGuiInputTextFlags_CallbackResize + // and the code in misc/cpp/imgui_stdlib.h for how to setup InputText() for dynamically resizing strings. + static char text[1024 * 16] = + "/*\n" + " The Pentium F00F bug, shorthand for F0 0F C7 C8,\n" + " the hexadecimal encoding of one offending instruction,\n" + " more formally, the invalid operand with locked CMPXCHG8B\n" + " instruction bug, is a design flaw in the majority of\n" + " Intel Pentium, Pentium MMX, and Pentium OverDrive\n" + " processors (all in the P5 microarchitecture).\n" + "*/\n\n" + "label:\n" + "\tlock cmpxchg8b eax\n"; + + static ImGuiInputTextFlags flags = ImGuiInputTextFlags_AllowTabInput; + HelpMarker("You can use the ImGuiInputTextFlags_CallbackResize facility if you need to wire InputTextMultiline() to a dynamic string type. See misc/cpp/imgui_stdlib.h for an example. (This is not demonstrated in imgui_demo.cpp because we don't want to include in here)"); + ImGui::CheckboxFlags("ImGuiInputTextFlags_ReadOnly", (unsigned int*)&flags, ImGuiInputTextFlags_ReadOnly); + ImGui::CheckboxFlags("ImGuiInputTextFlags_AllowTabInput", (unsigned int*)&flags, ImGuiInputTextFlags_AllowTabInput); + ImGui::CheckboxFlags("ImGuiInputTextFlags_CtrlEnterForNewLine", (unsigned int*)&flags, ImGuiInputTextFlags_CtrlEnterForNewLine); + ImGui::InputTextMultiline("##source", text, IM_ARRAYSIZE(text), ImVec2(-FLT_MIN, ImGui::GetTextLineHeight() * 16), flags); + ImGui::TreePop(); + } + + if (ImGui::TreeNode("Filtered Text Input")) + { + struct TextFilters + { + // Return 0 (pass) if the character is 'i' or 'm' or 'g' or 'u' or 'i' + static int FilterImGuiLetters(ImGuiInputTextCallbackData* data) + { + if (data->EventChar < 256 && strchr("imgui", (char)data->EventChar)) + return 0; + return 1; + } + }; + + static char buf1[64] = ""; ImGui::InputText("default", buf1, 64); + static char buf2[64] = ""; ImGui::InputText("decimal", buf2, 64, ImGuiInputTextFlags_CharsDecimal); + static char buf3[64] = ""; ImGui::InputText("hexadecimal", buf3, 64, ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsUppercase); + static char buf4[64] = ""; ImGui::InputText("uppercase", buf4, 64, ImGuiInputTextFlags_CharsUppercase); + static char buf5[64] = ""; ImGui::InputText("no blank", buf5, 64, ImGuiInputTextFlags_CharsNoBlank); + static char buf6[64] = ""; ImGui::InputText("\"imgui\" letters", buf6, 64, ImGuiInputTextFlags_CallbackCharFilter, TextFilters::FilterImGuiLetters); + + ImGui::Text("Password input"); + static char password[64] = "password123"; + ImGui::InputText("password", password, IM_ARRAYSIZE(password), ImGuiInputTextFlags_Password); + ImGui::SameLine(); HelpMarker("Display all characters as '*'.\nDisable clipboard cut and copy.\nDisable logging.\n"); + ImGui::InputTextWithHint("password (w/ hint)", "", password, IM_ARRAYSIZE(password), ImGuiInputTextFlags_Password); + ImGui::InputText("password (clear)", password, IM_ARRAYSIZE(password)); + ImGui::TreePop(); + } + + if (ImGui::TreeNode("Resize Callback")) + { + // To wire InputText() with std::string or any other custom string type, + // you can use the ImGuiInputTextFlags_CallbackResize flag + create a custom ImGui::InputText() wrapper + // using your preferred type. See misc/cpp/imgui_stdlib.h for an implementation of this using std::string. + HelpMarker( + "Using ImGuiInputTextFlags_CallbackResize to wire your custom string type to InputText().\n\n" + "See misc/cpp/imgui_stdlib.h for an implementation of this for std::string."); + struct Funcs + { + static int MyResizeCallback(ImGuiInputTextCallbackData* data) + { + if (data->EventFlag == ImGuiInputTextFlags_CallbackResize) + { + ImVector* my_str = (ImVector*)data->UserData; + IM_ASSERT(my_str->begin() == data->Buf); + my_str->resize(data->BufSize); // NB: On resizing calls, generally data->BufSize == data->BufTextLen + 1 + data->Buf = my_str->begin(); + } + return 0; + } + + // Note: Because ImGui:: is a namespace you would typically add your own function into the namespace. + // For example, you code may declare a function 'ImGui::InputText(const char* label, MyString* my_str)' + static bool MyInputTextMultiline(const char* label, ImVector* my_str, const ImVec2& size = ImVec2(0, 0), ImGuiInputTextFlags flags = 0) + { + IM_ASSERT((flags & ImGuiInputTextFlags_CallbackResize) == 0); + return ImGui::InputTextMultiline(label, my_str->begin(), (size_t)my_str->size(), size, flags | ImGuiInputTextFlags_CallbackResize, Funcs::MyResizeCallback, (void*)my_str); + } + }; + + // For this demo we are using ImVector as a string container. + // Note that because we need to store a terminating zero character, our size/capacity are 1 more + // than usually reported by a typical string class. + static ImVector my_str; + if (my_str.empty()) + my_str.push_back(0); + Funcs::MyInputTextMultiline("##MyStr", &my_str, ImVec2(-FLT_MIN, ImGui::GetTextLineHeight() * 16)); + ImGui::Text("Data: %p\nSize: %d\nCapacity: %d", (void*)my_str.begin(), my_str.size(), my_str.capacity()); + ImGui::TreePop(); + } + + ImGui::TreePop(); + } + + // Plot/Graph widgets are currently fairly limited. + // Consider writing your own plotting widget, or using a third-party one + // (for third-party Plot widgets, see 'Wiki->Useful Widgets' or https://github.com/ocornut/imgui/labels/plot%2Fgraph) + if (ImGui::TreeNode("Plots Widgets")) + { + static bool animate = true; + ImGui::Checkbox("Animate", &animate); + + static float arr[] = { 0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f }; + ImGui::PlotLines("Frame Times", arr, IM_ARRAYSIZE(arr)); + + // Create a dummy array of contiguous float values to plot + // Tip: If your float aren't contiguous but part of a structure, you can pass a pointer to your first float + // and the sizeof() of your structure in the "stride" parameter. + static float values[90] = {}; + static int values_offset = 0; + static double refresh_time = 0.0; + if (!animate || refresh_time == 0.0) + refresh_time = ImGui::GetTime(); + while (refresh_time < ImGui::GetTime()) // Create dummy data at fixed 60 Hz rate for the demo + { + static float phase = 0.0f; + values[values_offset] = cosf(phase); + values_offset = (values_offset+1) % IM_ARRAYSIZE(values); + phase += 0.10f*values_offset; + refresh_time += 1.0f/60.0f; + } + + // Plots can display overlay texts + // (in this example, we will display an average value) + { + float average = 0.0f; + for (int n = 0; n < IM_ARRAYSIZE(values); n++) + average += values[n]; + average /= (float)IM_ARRAYSIZE(values); + char overlay[32]; + sprintf(overlay, "avg %f", average); + ImGui::PlotLines("Lines", values, IM_ARRAYSIZE(values), values_offset, overlay, -1.0f, 1.0f, ImVec2(0, 80.0f)); + } + ImGui::PlotHistogram("Histogram", arr, IM_ARRAYSIZE(arr), 0, NULL, 0.0f, 1.0f, ImVec2(0, 80.0f)); + + // Use functions to generate output + // FIXME: This is rather awkward because current plot API only pass in indices. + // We probably want an API passing floats and user provide sample rate/count. + struct Funcs + { + static float Sin(void*, int i) { return sinf(i * 0.1f); } + static float Saw(void*, int i) { return (i & 1) ? 1.0f : -1.0f; } + }; + static int func_type = 0, display_count = 70; + ImGui::Separator(); + ImGui::SetNextItemWidth(100); + ImGui::Combo("func", &func_type, "Sin\0Saw\0"); + ImGui::SameLine(); + ImGui::SliderInt("Sample count", &display_count, 1, 400); + float (*func)(void*, int) = (func_type == 0) ? Funcs::Sin : Funcs::Saw; + ImGui::PlotLines("Lines", func, NULL, display_count, 0, NULL, -1.0f, 1.0f, ImVec2(0,80)); + ImGui::PlotHistogram("Histogram", func, NULL, display_count, 0, NULL, -1.0f, 1.0f, ImVec2(0,80)); + ImGui::Separator(); + + // Animate a simple progress bar + static float progress = 0.0f, progress_dir = 1.0f; + if (animate) + { + progress += progress_dir * 0.4f * ImGui::GetIO().DeltaTime; + if (progress >= +1.1f) { progress = +1.1f; progress_dir *= -1.0f; } + if (progress <= -0.1f) { progress = -0.1f; progress_dir *= -1.0f; } + } + + // Typically we would use ImVec2(-1.0f,0.0f) or ImVec2(-FLT_MIN,0.0f) to use all available width, + // or ImVec2(width,0.0f) for a specified width. ImVec2(0.0f,0.0f) uses ItemWidth. + ImGui::ProgressBar(progress, ImVec2(0.0f,0.0f)); + ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x); + ImGui::Text("Progress Bar"); + + float progress_saturated = IM_CLAMP(progress, 0.0f, 1.0f); + char buf[32]; + sprintf(buf, "%d/%d", (int)(progress_saturated*1753), 1753); + ImGui::ProgressBar(progress, ImVec2(0.f,0.f), buf); + ImGui::TreePop(); + } + + if (ImGui::TreeNode("Color/Picker Widgets")) + { + static ImVec4 color = ImVec4(114.0f/255.0f, 144.0f/255.0f, 154.0f/255.0f, 200.0f/255.0f); + + static bool alpha_preview = true; + static bool alpha_half_preview = false; + static bool drag_and_drop = true; + static bool options_menu = true; + static bool hdr = false; + ImGui::Checkbox("With Alpha Preview", &alpha_preview); + ImGui::Checkbox("With Half Alpha Preview", &alpha_half_preview); + ImGui::Checkbox("With Drag and Drop", &drag_and_drop); + ImGui::Checkbox("With Options Menu", &options_menu); ImGui::SameLine(); HelpMarker("Right-click on the individual color widget to show options."); + ImGui::Checkbox("With HDR", &hdr); ImGui::SameLine(); HelpMarker("Currently all this does is to lift the 0..1 limits on dragging widgets."); + ImGuiColorEditFlags misc_flags = (hdr ? ImGuiColorEditFlags_HDR : 0) | (drag_and_drop ? 0 : ImGuiColorEditFlags_NoDragDrop) | (alpha_half_preview ? ImGuiColorEditFlags_AlphaPreviewHalf : (alpha_preview ? ImGuiColorEditFlags_AlphaPreview : 0)) | (options_menu ? 0 : ImGuiColorEditFlags_NoOptions); + + ImGui::Text("Color widget:"); + ImGui::SameLine(); HelpMarker( + "Click on the colored square to open a color picker.\n" + "CTRL+click on individual component to input value.\n"); + ImGui::ColorEdit3("MyColor##1", (float*)&color, misc_flags); + + ImGui::Text("Color widget HSV with Alpha:"); + ImGui::ColorEdit4("MyColor##2", (float*)&color, ImGuiColorEditFlags_DisplayHSV | misc_flags); + + ImGui::Text("Color widget with Float Display:"); + ImGui::ColorEdit4("MyColor##2f", (float*)&color, ImGuiColorEditFlags_Float | misc_flags); + + ImGui::Text("Color button with Picker:"); + ImGui::SameLine(); HelpMarker( + "With the ImGuiColorEditFlags_NoInputs flag you can hide all the slider/text inputs.\n" + "With the ImGuiColorEditFlags_NoLabel flag you can pass a non-empty label which will only " + "be used for the tooltip and picker popup."); + ImGui::ColorEdit4("MyColor##3", (float*)&color, ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel | misc_flags); + + ImGui::Text("Color button with Custom Picker Popup:"); + + // Generate a dummy default palette. The palette will persist and can be edited. + static bool saved_palette_init = true; + static ImVec4 saved_palette[32] = {}; + if (saved_palette_init) + { + for (int n = 0; n < IM_ARRAYSIZE(saved_palette); n++) + { + ImGui::ColorConvertHSVtoRGB(n / 31.0f, 0.8f, 0.8f, + saved_palette[n].x, saved_palette[n].y, saved_palette[n].z); + saved_palette[n].w = 1.0f; // Alpha + } + saved_palette_init = false; + } + + static ImVec4 backup_color; + bool open_popup = ImGui::ColorButton("MyColor##3b", color, misc_flags); + ImGui::SameLine(0, ImGui::GetStyle().ItemInnerSpacing.x); + open_popup |= ImGui::Button("Palette"); + if (open_popup) + { + ImGui::OpenPopup("mypicker"); + backup_color = color; + } + if (ImGui::BeginPopup("mypicker")) + { + ImGui::Text("MY CUSTOM COLOR PICKER WITH AN AMAZING PALETTE!"); + ImGui::Separator(); + ImGui::ColorPicker4("##picker", (float*)&color, misc_flags | ImGuiColorEditFlags_NoSidePreview | ImGuiColorEditFlags_NoSmallPreview); + ImGui::SameLine(); + + ImGui::BeginGroup(); // Lock X position + ImGui::Text("Current"); + ImGui::ColorButton("##current", color, ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_AlphaPreviewHalf, ImVec2(60,40)); + ImGui::Text("Previous"); + if (ImGui::ColorButton("##previous", backup_color, ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_AlphaPreviewHalf, ImVec2(60,40))) + color = backup_color; + ImGui::Separator(); + ImGui::Text("Palette"); + for (int n = 0; n < IM_ARRAYSIZE(saved_palette); n++) + { + ImGui::PushID(n); + if ((n % 8) != 0) + ImGui::SameLine(0.0f, ImGui::GetStyle().ItemSpacing.y); + + ImGuiColorEditFlags palette_button_flags = ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_NoTooltip; + if (ImGui::ColorButton("##palette", saved_palette[n], palette_button_flags, ImVec2(20,20))) + color = ImVec4(saved_palette[n].x, saved_palette[n].y, saved_palette[n].z, color.w); // Preserve alpha! + + // Allow user to drop colors into each palette entry. Note that ColorButton() is already a + // drag source by default, unless specifying the ImGuiColorEditFlags_NoDragDrop flag. + if (ImGui::BeginDragDropTarget()) + { + if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_3F)) + memcpy((float*)&saved_palette[n], payload->Data, sizeof(float) * 3); + if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F)) + memcpy((float*)&saved_palette[n], payload->Data, sizeof(float) * 4); + ImGui::EndDragDropTarget(); + } + + ImGui::PopID(); + } + ImGui::EndGroup(); + ImGui::EndPopup(); + } + + ImGui::Text("Color button only:"); + static bool no_border = false; + ImGui::Checkbox("ImGuiColorEditFlags_NoBorder", &no_border); + ImGui::ColorButton("MyColor##3c", *(ImVec4*)&color, misc_flags | (no_border ? ImGuiColorEditFlags_NoBorder : 0), ImVec2(80,80)); + + ImGui::Text("Color picker:"); + static bool alpha = true; + static bool alpha_bar = true; + static bool side_preview = true; + static bool ref_color = false; + static ImVec4 ref_color_v(1.0f,0.0f,1.0f,0.5f); + static int display_mode = 0; + static int picker_mode = 0; + ImGui::Checkbox("With Alpha", &alpha); + ImGui::Checkbox("With Alpha Bar", &alpha_bar); + ImGui::Checkbox("With Side Preview", &side_preview); + if (side_preview) + { + ImGui::SameLine(); + ImGui::Checkbox("With Ref Color", &ref_color); + if (ref_color) + { + ImGui::SameLine(); + ImGui::ColorEdit4("##RefColor", &ref_color_v.x, ImGuiColorEditFlags_NoInputs | misc_flags); + } + } + ImGui::Combo("Display Mode", &display_mode, "Auto/Current\0None\0RGB Only\0HSV Only\0Hex Only\0"); + ImGui::SameLine(); HelpMarker( + "ColorEdit defaults to displaying RGB inputs if you don't specify a display mode, " + "but the user can change it with a right-click.\n\nColorPicker defaults to displaying RGB+HSV+Hex " + "if you don't specify a display mode.\n\nYou can change the defaults using SetColorEditOptions()."); + ImGui::Combo("Picker Mode", &picker_mode, "Auto/Current\0Hue bar + SV rect\0Hue wheel + SV triangle\0"); + ImGui::SameLine(); HelpMarker("User can right-click the picker to change mode."); + ImGuiColorEditFlags flags = misc_flags; + if (!alpha) flags |= ImGuiColorEditFlags_NoAlpha; // This is by default if you call ColorPicker3() instead of ColorPicker4() + if (alpha_bar) flags |= ImGuiColorEditFlags_AlphaBar; + if (!side_preview) flags |= ImGuiColorEditFlags_NoSidePreview; + if (picker_mode == 1) flags |= ImGuiColorEditFlags_PickerHueBar; + if (picker_mode == 2) flags |= ImGuiColorEditFlags_PickerHueWheel; + if (display_mode == 1) flags |= ImGuiColorEditFlags_NoInputs; // Disable all RGB/HSV/Hex displays + if (display_mode == 2) flags |= ImGuiColorEditFlags_DisplayRGB; // Override display mode + if (display_mode == 3) flags |= ImGuiColorEditFlags_DisplayHSV; + if (display_mode == 4) flags |= ImGuiColorEditFlags_DisplayHex; + ImGui::ColorPicker4("MyColor##4", (float*)&color, flags, ref_color ? &ref_color_v.x : NULL); + + ImGui::Text("Set defaults in code:"); + ImGui::SameLine(); HelpMarker( + "SetColorEditOptions() is designed to allow you to set boot-time default.\n" + "We don't have Push/Pop functions because you can force options on a per-widget basis if needed," + "and the user can change non-forced ones with the options menu.\nWe don't have a getter to avoid" + "encouraging you to persistently save values that aren't forward-compatible."); + if (ImGui::Button("Default: Uint8 + HSV + Hue Bar")) + ImGui::SetColorEditOptions(ImGuiColorEditFlags_Uint8 | ImGuiColorEditFlags_DisplayHSV | ImGuiColorEditFlags_PickerHueBar); + if (ImGui::Button("Default: Float + HDR + Hue Wheel")) + ImGui::SetColorEditOptions(ImGuiColorEditFlags_Float | ImGuiColorEditFlags_HDR | ImGuiColorEditFlags_PickerHueWheel); + + // HSV encoded support (to avoid RGB<>HSV round trips and singularities when S==0 or V==0) + static ImVec4 color_hsv(0.23f, 1.0f, 1.0f, 1.0f); // Stored as HSV! + ImGui::Spacing(); + ImGui::Text("HSV encoded colors"); + ImGui::SameLine(); HelpMarker( + "By default, colors are given to ColorEdit and ColorPicker in RGB, but ImGuiColorEditFlags_InputHSV" + "allows you to store colors as HSV and pass them to ColorEdit and ColorPicker as HSV. This comes with the" + "added benefit that you can manipulate hue values with the picker even when saturation or value are zero."); + ImGui::Text("Color widget with InputHSV:"); + ImGui::ColorEdit4("HSV shown as RGB##1", (float*)&color_hsv, ImGuiColorEditFlags_DisplayRGB | ImGuiColorEditFlags_InputHSV | ImGuiColorEditFlags_Float); + ImGui::ColorEdit4("HSV shown as HSV##1", (float*)&color_hsv, ImGuiColorEditFlags_DisplayHSV | ImGuiColorEditFlags_InputHSV | ImGuiColorEditFlags_Float); + ImGui::DragFloat4("Raw HSV values", (float*)&color_hsv, 0.01f, 0.0f, 1.0f); + + ImGui::TreePop(); + } + + if (ImGui::TreeNode("Range Widgets")) + { + static float begin = 10, end = 90; + static int begin_i = 100, end_i = 1000; + ImGui::DragFloatRange2("range", &begin, &end, 0.25f, 0.0f, 100.0f, "Min: %.1f %%", "Max: %.1f %%"); + ImGui::DragIntRange2("range int (no bounds)", &begin_i, &end_i, 5, 0, 0, "Min: %d units", "Max: %d units"); + ImGui::TreePop(); + } + + if (ImGui::TreeNode("Data Types")) + { + // DragScalar/InputScalar/SliderScalar functions allow various data types + // - signed/unsigned + // - 8/16/32/64-bits + // - integer/float/double + // To avoid polluting the public API with all possible combinations, we use the ImGuiDataType enum + // to pass the type, and passing all arguments by pointer. + // This is the reason the test code below creates local variables to hold "zero" "one" etc. for each types. + // In practice, if you frequently use a given type that is not covered by the normal API entry points, + // you can wrap it yourself inside a 1 line function which can take typed argument as value instead of void*, + // and then pass their address to the generic function. For example: + // bool MySliderU64(const char *label, u64* value, u64 min = 0, u64 max = 0, const char* format = "%lld") + // { + // return SliderScalar(label, ImGuiDataType_U64, value, &min, &max, format); + // } + + // Setup limits (as helper variables so we can take their address, as explained above) + // Note: SliderScalar() functions have a maximum usable range of half the natural type maximum, hence the /2. + #ifndef LLONG_MIN + ImS64 LLONG_MIN = -9223372036854775807LL - 1; + ImS64 LLONG_MAX = 9223372036854775807LL; + ImU64 ULLONG_MAX = (2ULL * 9223372036854775807LL + 1); + #endif + const char s8_zero = 0, s8_one = 1, s8_fifty = 50, s8_min = -128, s8_max = 127; + const ImU8 u8_zero = 0, u8_one = 1, u8_fifty = 50, u8_min = 0, u8_max = 255; + const short s16_zero = 0, s16_one = 1, s16_fifty = 50, s16_min = -32768, s16_max = 32767; + const ImU16 u16_zero = 0, u16_one = 1, u16_fifty = 50, u16_min = 0, u16_max = 65535; + const ImS32 s32_zero = 0, s32_one = 1, s32_fifty = 50, s32_min = INT_MIN/2, s32_max = INT_MAX/2, s32_hi_a = INT_MAX/2 - 100, s32_hi_b = INT_MAX/2; + const ImU32 u32_zero = 0, u32_one = 1, u32_fifty = 50, u32_min = 0, u32_max = UINT_MAX/2, u32_hi_a = UINT_MAX/2 - 100, u32_hi_b = UINT_MAX/2; + const ImS64 s64_zero = 0, s64_one = 1, s64_fifty = 50, s64_min = LLONG_MIN/2, s64_max = LLONG_MAX/2, s64_hi_a = LLONG_MAX/2 - 100, s64_hi_b = LLONG_MAX/2; + const ImU64 u64_zero = 0, u64_one = 1, u64_fifty = 50, u64_min = 0, u64_max = ULLONG_MAX/2, u64_hi_a = ULLONG_MAX/2 - 100, u64_hi_b = ULLONG_MAX/2; + const float f32_zero = 0.f, f32_one = 1.f, f32_lo_a = -10000000000.0f, f32_hi_a = +10000000000.0f; + const double f64_zero = 0., f64_one = 1., f64_lo_a = -1000000000000000.0, f64_hi_a = +1000000000000000.0; + + // State + static char s8_v = 127; + static ImU8 u8_v = 255; + static short s16_v = 32767; + static ImU16 u16_v = 65535; + static ImS32 s32_v = -1; + static ImU32 u32_v = (ImU32)-1; + static ImS64 s64_v = -1; + static ImU64 u64_v = (ImU64)-1; + static float f32_v = 0.123f; + static double f64_v = 90000.01234567890123456789; + + const float drag_speed = 0.2f; + static bool drag_clamp = false; + ImGui::Text("Drags:"); + ImGui::Checkbox("Clamp integers to 0..50", &drag_clamp); ImGui::SameLine(); HelpMarker("As with every widgets in dear imgui, we never modify values unless there is a user interaction.\nYou can override the clamping limits by using CTRL+Click to input a value."); + ImGui::DragScalar("drag s8", ImGuiDataType_S8, &s8_v, drag_speed, drag_clamp ? &s8_zero : NULL, drag_clamp ? &s8_fifty : NULL); + ImGui::DragScalar("drag u8", ImGuiDataType_U8, &u8_v, drag_speed, drag_clamp ? &u8_zero : NULL, drag_clamp ? &u8_fifty : NULL, "%u ms"); + ImGui::DragScalar("drag s16", ImGuiDataType_S16, &s16_v, drag_speed, drag_clamp ? &s16_zero : NULL, drag_clamp ? &s16_fifty : NULL); + ImGui::DragScalar("drag u16", ImGuiDataType_U16, &u16_v, drag_speed, drag_clamp ? &u16_zero : NULL, drag_clamp ? &u16_fifty : NULL, "%u ms"); + ImGui::DragScalar("drag s32", ImGuiDataType_S32, &s32_v, drag_speed, drag_clamp ? &s32_zero : NULL, drag_clamp ? &s32_fifty : NULL); + ImGui::DragScalar("drag u32", ImGuiDataType_U32, &u32_v, drag_speed, drag_clamp ? &u32_zero : NULL, drag_clamp ? &u32_fifty : NULL, "%u ms"); + ImGui::DragScalar("drag s64", ImGuiDataType_S64, &s64_v, drag_speed, drag_clamp ? &s64_zero : NULL, drag_clamp ? &s64_fifty : NULL); + ImGui::DragScalar("drag u64", ImGuiDataType_U64, &u64_v, drag_speed, drag_clamp ? &u64_zero : NULL, drag_clamp ? &u64_fifty : NULL); + ImGui::DragScalar("drag float", ImGuiDataType_Float, &f32_v, 0.005f, &f32_zero, &f32_one, "%f", 1.0f); + ImGui::DragScalar("drag float ^2", ImGuiDataType_Float, &f32_v, 0.005f, &f32_zero, &f32_one, "%f", 2.0f); ImGui::SameLine(); HelpMarker("You can use the 'power' parameter to increase tweaking precision on one side of the range."); + ImGui::DragScalar("drag double", ImGuiDataType_Double, &f64_v, 0.0005f, &f64_zero, NULL, "%.10f grams", 1.0f); + ImGui::DragScalar("drag double ^2", ImGuiDataType_Double, &f64_v, 0.0005f, &f64_zero, &f64_one, "0 < %.10f < 1", 2.0f); + + ImGui::Text("Sliders"); + ImGui::SliderScalar("slider s8 full", ImGuiDataType_S8, &s8_v, &s8_min, &s8_max, "%d"); + ImGui::SliderScalar("slider u8 full", ImGuiDataType_U8, &u8_v, &u8_min, &u8_max, "%u"); + ImGui::SliderScalar("slider s16 full", ImGuiDataType_S16, &s16_v, &s16_min, &s16_max, "%d"); + ImGui::SliderScalar("slider u16 full", ImGuiDataType_U16, &u16_v, &u16_min, &u16_max, "%u"); + ImGui::SliderScalar("slider s32 low", ImGuiDataType_S32, &s32_v, &s32_zero, &s32_fifty,"%d"); + ImGui::SliderScalar("slider s32 high", ImGuiDataType_S32, &s32_v, &s32_hi_a, &s32_hi_b, "%d"); + ImGui::SliderScalar("slider s32 full", ImGuiDataType_S32, &s32_v, &s32_min, &s32_max, "%d"); + ImGui::SliderScalar("slider u32 low", ImGuiDataType_U32, &u32_v, &u32_zero, &u32_fifty,"%u"); + ImGui::SliderScalar("slider u32 high", ImGuiDataType_U32, &u32_v, &u32_hi_a, &u32_hi_b, "%u"); + ImGui::SliderScalar("slider u32 full", ImGuiDataType_U32, &u32_v, &u32_min, &u32_max, "%u"); + ImGui::SliderScalar("slider s64 low", ImGuiDataType_S64, &s64_v, &s64_zero, &s64_fifty,"%I64d"); + ImGui::SliderScalar("slider s64 high", ImGuiDataType_S64, &s64_v, &s64_hi_a, &s64_hi_b, "%I64d"); + ImGui::SliderScalar("slider s64 full", ImGuiDataType_S64, &s64_v, &s64_min, &s64_max, "%I64d"); + ImGui::SliderScalar("slider u64 low", ImGuiDataType_U64, &u64_v, &u64_zero, &u64_fifty,"%I64u ms"); + ImGui::SliderScalar("slider u64 high", ImGuiDataType_U64, &u64_v, &u64_hi_a, &u64_hi_b, "%I64u ms"); + ImGui::SliderScalar("slider u64 full", ImGuiDataType_U64, &u64_v, &u64_min, &u64_max, "%I64u ms"); + ImGui::SliderScalar("slider float low", ImGuiDataType_Float, &f32_v, &f32_zero, &f32_one); + ImGui::SliderScalar("slider float low^2", ImGuiDataType_Float, &f32_v, &f32_zero, &f32_one, "%.10f", 2.0f); + ImGui::SliderScalar("slider float high", ImGuiDataType_Float, &f32_v, &f32_lo_a, &f32_hi_a, "%e"); + ImGui::SliderScalar("slider double low", ImGuiDataType_Double, &f64_v, &f64_zero, &f64_one, "%.10f grams", 1.0f); + ImGui::SliderScalar("slider double low^2",ImGuiDataType_Double, &f64_v, &f64_zero, &f64_one, "%.10f", 2.0f); + ImGui::SliderScalar("slider double high", ImGuiDataType_Double, &f64_v, &f64_lo_a, &f64_hi_a, "%e grams", 1.0f); + + static bool inputs_step = true; + ImGui::Text("Inputs"); + ImGui::Checkbox("Show step buttons", &inputs_step); + ImGui::InputScalar("input s8", ImGuiDataType_S8, &s8_v, inputs_step ? &s8_one : NULL, NULL, "%d"); + ImGui::InputScalar("input u8", ImGuiDataType_U8, &u8_v, inputs_step ? &u8_one : NULL, NULL, "%u"); + ImGui::InputScalar("input s16", ImGuiDataType_S16, &s16_v, inputs_step ? &s16_one : NULL, NULL, "%d"); + ImGui::InputScalar("input u16", ImGuiDataType_U16, &u16_v, inputs_step ? &u16_one : NULL, NULL, "%u"); + ImGui::InputScalar("input s32", ImGuiDataType_S32, &s32_v, inputs_step ? &s32_one : NULL, NULL, "%d"); + ImGui::InputScalar("input s32 hex", ImGuiDataType_S32, &s32_v, inputs_step ? &s32_one : NULL, NULL, "%08X", ImGuiInputTextFlags_CharsHexadecimal); + ImGui::InputScalar("input u32", ImGuiDataType_U32, &u32_v, inputs_step ? &u32_one : NULL, NULL, "%u"); + ImGui::InputScalar("input u32 hex", ImGuiDataType_U32, &u32_v, inputs_step ? &u32_one : NULL, NULL, "%08X", ImGuiInputTextFlags_CharsHexadecimal); + ImGui::InputScalar("input s64", ImGuiDataType_S64, &s64_v, inputs_step ? &s64_one : NULL); + ImGui::InputScalar("input u64", ImGuiDataType_U64, &u64_v, inputs_step ? &u64_one : NULL); + ImGui::InputScalar("input float", ImGuiDataType_Float, &f32_v, inputs_step ? &f32_one : NULL); + ImGui::InputScalar("input double", ImGuiDataType_Double, &f64_v, inputs_step ? &f64_one : NULL); + + ImGui::TreePop(); + } + + if (ImGui::TreeNode("Multi-component Widgets")) + { + static float vec4f[4] = { 0.10f, 0.20f, 0.30f, 0.44f }; + static int vec4i[4] = { 1, 5, 100, 255 }; + + ImGui::InputFloat2("input float2", vec4f); + ImGui::DragFloat2("drag float2", vec4f, 0.01f, 0.0f, 1.0f); + ImGui::SliderFloat2("slider float2", vec4f, 0.0f, 1.0f); + ImGui::InputInt2("input int2", vec4i); + ImGui::DragInt2("drag int2", vec4i, 1, 0, 255); + ImGui::SliderInt2("slider int2", vec4i, 0, 255); + ImGui::Spacing(); + + ImGui::InputFloat3("input float3", vec4f); + ImGui::DragFloat3("drag float3", vec4f, 0.01f, 0.0f, 1.0f); + ImGui::SliderFloat3("slider float3", vec4f, 0.0f, 1.0f); + ImGui::InputInt3("input int3", vec4i); + ImGui::DragInt3("drag int3", vec4i, 1, 0, 255); + ImGui::SliderInt3("slider int3", vec4i, 0, 255); + ImGui::Spacing(); + + ImGui::InputFloat4("input float4", vec4f); + ImGui::DragFloat4("drag float4", vec4f, 0.01f, 0.0f, 1.0f); + ImGui::SliderFloat4("slider float4", vec4f, 0.0f, 1.0f); + ImGui::InputInt4("input int4", vec4i); + ImGui::DragInt4("drag int4", vec4i, 1, 0, 255); + ImGui::SliderInt4("slider int4", vec4i, 0, 255); + + ImGui::TreePop(); + } + + if (ImGui::TreeNode("Vertical Sliders")) + { + const float spacing = 4; + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(spacing, spacing)); + + static int int_value = 0; + ImGui::VSliderInt("##int", ImVec2(18,160), &int_value, 0, 5); + ImGui::SameLine(); + + static float values[7] = { 0.0f, 0.60f, 0.35f, 0.9f, 0.70f, 0.20f, 0.0f }; + ImGui::PushID("set1"); + for (int i = 0; i < 7; i++) + { + if (i > 0) ImGui::SameLine(); + ImGui::PushID(i); + ImGui::PushStyleColor(ImGuiCol_FrameBg, (ImVec4)ImColor::HSV(i/7.0f, 0.5f, 0.5f)); + ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, (ImVec4)ImColor::HSV(i/7.0f, 0.6f, 0.5f)); + ImGui::PushStyleColor(ImGuiCol_FrameBgActive, (ImVec4)ImColor::HSV(i/7.0f, 0.7f, 0.5f)); + ImGui::PushStyleColor(ImGuiCol_SliderGrab, (ImVec4)ImColor::HSV(i/7.0f, 0.9f, 0.9f)); + ImGui::VSliderFloat("##v", ImVec2(18,160), &values[i], 0.0f, 1.0f, ""); + if (ImGui::IsItemActive() || ImGui::IsItemHovered()) + ImGui::SetTooltip("%.3f", values[i]); + ImGui::PopStyleColor(4); + ImGui::PopID(); + } + ImGui::PopID(); + + ImGui::SameLine(); + ImGui::PushID("set2"); + static float values2[4] = { 0.20f, 0.80f, 0.40f, 0.25f }; + const int rows = 3; + const ImVec2 small_slider_size(18, (float)(int)((160.0f - (rows - 1) * spacing) / rows)); + for (int nx = 0; nx < 4; nx++) + { + if (nx > 0) ImGui::SameLine(); + ImGui::BeginGroup(); + for (int ny = 0; ny < rows; ny++) + { + ImGui::PushID(nx*rows+ny); + ImGui::VSliderFloat("##v", small_slider_size, &values2[nx], 0.0f, 1.0f, ""); + if (ImGui::IsItemActive() || ImGui::IsItemHovered()) + ImGui::SetTooltip("%.3f", values2[nx]); + ImGui::PopID(); + } + ImGui::EndGroup(); + } + ImGui::PopID(); + + ImGui::SameLine(); + ImGui::PushID("set3"); + for (int i = 0; i < 4; i++) + { + if (i > 0) ImGui::SameLine(); + ImGui::PushID(i); + ImGui::PushStyleVar(ImGuiStyleVar_GrabMinSize, 40); + ImGui::VSliderFloat("##v", ImVec2(40,160), &values[i], 0.0f, 1.0f, "%.2f\nsec"); + ImGui::PopStyleVar(); + ImGui::PopID(); + } + ImGui::PopID(); + ImGui::PopStyleVar(); + ImGui::TreePop(); + } + + if (ImGui::TreeNode("Drag and Drop")) + { + if (ImGui::TreeNode("Drag and drop in standard widgets")) + { + // ColorEdit widgets automatically act as drag source and drag target. + // They are using standardized payload strings IMGUI_PAYLOAD_TYPE_COLOR_3F and IMGUI_PAYLOAD_TYPE_COLOR_4F + // to allow your own widgets to use colors in their drag and drop interaction. + // Also see 'Demo->Widgets->Color/Picker Widgets->Palette' demo. + HelpMarker("You can drag from the colored squares."); + static float col1[3] = { 1.0f, 0.0f, 0.2f }; + static float col2[4] = { 0.4f, 0.7f, 0.0f, 0.5f }; + ImGui::ColorEdit3("color 1", col1); + ImGui::ColorEdit4("color 2", col2); + ImGui::TreePop(); + } + + if (ImGui::TreeNode("Drag and drop to copy/swap items")) + { + enum Mode + { + Mode_Copy, + Mode_Move, + Mode_Swap + }; + static int mode = 0; + if (ImGui::RadioButton("Copy", mode == Mode_Copy)) { mode = Mode_Copy; } ImGui::SameLine(); + if (ImGui::RadioButton("Move", mode == Mode_Move)) { mode = Mode_Move; } ImGui::SameLine(); + if (ImGui::RadioButton("Swap", mode == Mode_Swap)) { mode = Mode_Swap; } + const char* names[9] = + { + "Bobby", "Beatrice", "Betty", + "Brianna", "Barry", "Bernard", + "Bibi", "Blaine", "Bryn" + }; + for (int n = 0; n < IM_ARRAYSIZE(names); n++) + { + ImGui::PushID(n); + if ((n % 3) != 0) + ImGui::SameLine(); + ImGui::Button(names[n], ImVec2(60,60)); + + // Our buttons are both drag sources and drag targets here! + if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_None)) + { + // Set payload to carry the index of our item (could be anything) + ImGui::SetDragDropPayload("DND_DEMO_CELL", &n, sizeof(int)); + + // Display preview (could be anything, e.g. when dragging an image we could decide to display + // the filename and a small preview of the image, etc.) + if (mode == Mode_Copy) { ImGui::Text("Copy %s", names[n]); } + if (mode == Mode_Move) { ImGui::Text("Move %s", names[n]); } + if (mode == Mode_Swap) { ImGui::Text("Swap %s", names[n]); } + ImGui::EndDragDropSource(); + } + if (ImGui::BeginDragDropTarget()) + { + if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("DND_DEMO_CELL")) + { + IM_ASSERT(payload->DataSize == sizeof(int)); + int payload_n = *(const int*)payload->Data; + if (mode == Mode_Copy) + { + names[n] = names[payload_n]; + } + if (mode == Mode_Move) + { + names[n] = names[payload_n]; + names[payload_n] = ""; + } + if (mode == Mode_Swap) + { + const char* tmp = names[n]; + names[n] = names[payload_n]; + names[payload_n] = tmp; + } + } + ImGui::EndDragDropTarget(); + } + ImGui::PopID(); + } + ImGui::TreePop(); + } + + if (ImGui::TreeNode("Drag to reorder items (simple)")) + { + // Simple reordering + HelpMarker( + "We don't use the drag and drop api at all here! " + "Instead we query when the item is held but not hovered, and order items accordingly."); + static const char* item_names[] = { "Item One", "Item Two", "Item Three", "Item Four", "Item Five" }; + for (int n = 0; n < IM_ARRAYSIZE(item_names); n++) + { + const char* item = item_names[n]; + ImGui::Selectable(item); + + if (ImGui::IsItemActive() && !ImGui::IsItemHovered()) + { + int n_next = n + (ImGui::GetMouseDragDelta(0).y < 0.f ? -1 : 1); + if (n_next >= 0 && n_next < IM_ARRAYSIZE(item_names)) + { + item_names[n] = item_names[n_next]; + item_names[n_next] = item; + ImGui::ResetMouseDragDelta(); + } + } + } + ImGui::TreePop(); + } + + ImGui::TreePop(); + } + + if (ImGui::TreeNode("Querying Status (Active/Focused/Hovered etc.)")) + { + // Select an item type + const char* item_names[] = + { + "Text", "Button", "Button (w/ repeat)", "Checkbox", "SliderFloat", "InputText", "InputFloat", + "InputFloat3", "ColorEdit4", "MenuItem", "TreeNode", "TreeNode (w/ double-click)", "ListBox" + }; + static int item_type = 1; + ImGui::Combo("Item Type", &item_type, item_names, IM_ARRAYSIZE(item_names), IM_ARRAYSIZE(item_names)); + ImGui::SameLine(); + HelpMarker("Testing how various types of items are interacting with the IsItemXXX functions."); + + // Submit selected item item so we can query their status in the code following it. + bool ret = false; + static bool b = false; + static float col4f[4] = { 1.0f, 0.5, 0.0f, 1.0f }; + static char str[16] = {}; + if (item_type == 0) { ImGui::Text("ITEM: Text"); } // Testing text items with no identifier/interaction + if (item_type == 1) { ret = ImGui::Button("ITEM: Button"); } // Testing button + if (item_type == 2) { ImGui::PushButtonRepeat(true); ret = ImGui::Button("ITEM: Button"); ImGui::PopButtonRepeat(); } // Testing button (with repeater) + if (item_type == 3) { ret = ImGui::Checkbox("ITEM: Checkbox", &b); } // Testing checkbox + if (item_type == 4) { ret = ImGui::SliderFloat("ITEM: SliderFloat", &col4f[0], 0.0f, 1.0f); } // Testing basic item + if (item_type == 5) { ret = ImGui::InputText("ITEM: InputText", &str[0], IM_ARRAYSIZE(str)); } // Testing input text (which handles tabbing) + if (item_type == 6) { ret = ImGui::InputFloat("ITEM: InputFloat", col4f, 1.0f); } // Testing +/- buttons on scalar input + if (item_type == 7) { ret = ImGui::InputFloat3("ITEM: InputFloat3", col4f); } // Testing multi-component items (IsItemXXX flags are reported merged) + if (item_type == 8) { ret = ImGui::ColorEdit4("ITEM: ColorEdit4", col4f); } // Testing multi-component items (IsItemXXX flags are reported merged) + if (item_type == 9) { ret = ImGui::MenuItem("ITEM: MenuItem"); } // Testing menu item (they use ImGuiButtonFlags_PressedOnRelease button policy) + if (item_type == 10){ ret = ImGui::TreeNode("ITEM: TreeNode"); if (ret) ImGui::TreePop(); } // Testing tree node + if (item_type == 11){ ret = ImGui::TreeNodeEx("ITEM: TreeNode w/ ImGuiTreeNodeFlags_OpenOnDoubleClick", ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_NoTreePushOnOpen); } // Testing tree node with ImGuiButtonFlags_PressedOnDoubleClick button policy. + if (item_type == 12){ const char* items[] = { "Apple", "Banana", "Cherry", "Kiwi" }; static int current = 1; ret = ImGui::ListBox("ITEM: ListBox", ¤t, items, IM_ARRAYSIZE(items), IM_ARRAYSIZE(items)); } + + // Display the values of IsItemHovered() and other common item state functions. + // Note that the ImGuiHoveredFlags_XXX flags can be combined. + // Because BulletText is an item itself and that would affect the output of IsItemXXX functions, + // we query every state in a single call to avoid storing them and to simplify the code. + ImGui::BulletText( + "Return value = %d\n" + "IsItemFocused() = %d\n" + "IsItemHovered() = %d\n" + "IsItemHovered(_AllowWhenBlockedByPopup) = %d\n" + "IsItemHovered(_AllowWhenBlockedByActiveItem) = %d\n" + "IsItemHovered(_AllowWhenOverlapped) = %d\n" + "IsItemHovered(_RectOnly) = %d\n" + "IsItemActive() = %d\n" + "IsItemEdited() = %d\n" + "IsItemActivated() = %d\n" + "IsItemDeactivated() = %d\n" + "IsItemDeactivatedAfterEdit() = %d\n" + "IsItemVisible() = %d\n" + "IsItemClicked() = %d\n" + "IsItemToggledOpen() = %d\n" + "GetItemRectMin() = (%.1f, %.1f)\n" + "GetItemRectMax() = (%.1f, %.1f)\n" + "GetItemRectSize() = (%.1f, %.1f)", + ret, + ImGui::IsItemFocused(), + ImGui::IsItemHovered(), + ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup), + ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem), + ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenOverlapped), + ImGui::IsItemHovered(ImGuiHoveredFlags_RectOnly), + ImGui::IsItemActive(), + ImGui::IsItemEdited(), + ImGui::IsItemActivated(), + ImGui::IsItemDeactivated(), + ImGui::IsItemDeactivatedAfterEdit(), + ImGui::IsItemVisible(), + ImGui::IsItemClicked(), + ImGui::IsItemToggledOpen(), + ImGui::GetItemRectMin().x, ImGui::GetItemRectMin().y, + ImGui::GetItemRectMax().x, ImGui::GetItemRectMax().y, + ImGui::GetItemRectSize().x, ImGui::GetItemRectSize().y + ); + + static bool embed_all_inside_a_child_window = false; + ImGui::Checkbox("Embed everything inside a child window (for additional testing)", &embed_all_inside_a_child_window); + if (embed_all_inside_a_child_window) + ImGui::BeginChild("outer_child", ImVec2(0, ImGui::GetFontSize() * 20.0f), true); + + // Testing IsWindowFocused() function with its various flags. + // Note that the ImGuiFocusedFlags_XXX flags can be combined. + ImGui::BulletText( + "IsWindowFocused() = %d\n" + "IsWindowFocused(_ChildWindows) = %d\n" + "IsWindowFocused(_ChildWindows|_RootWindow) = %d\n" + "IsWindowFocused(_RootWindow) = %d\n" + "IsWindowFocused(_AnyWindow) = %d\n", + ImGui::IsWindowFocused(), + ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows), + ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows | ImGuiFocusedFlags_RootWindow), + ImGui::IsWindowFocused(ImGuiFocusedFlags_RootWindow), + ImGui::IsWindowFocused(ImGuiFocusedFlags_AnyWindow)); + + // Testing IsWindowHovered() function with its various flags. + // Note that the ImGuiHoveredFlags_XXX flags can be combined. + ImGui::BulletText( + "IsWindowHovered() = %d\n" + "IsWindowHovered(_AllowWhenBlockedByPopup) = %d\n" + "IsWindowHovered(_AllowWhenBlockedByActiveItem) = %d\n" + "IsWindowHovered(_ChildWindows) = %d\n" + "IsWindowHovered(_ChildWindows|_RootWindow) = %d\n" + "IsWindowHovered(_ChildWindows|_AllowWhenBlockedByPopup) = %d\n" + "IsWindowHovered(_RootWindow) = %d\n" + "IsWindowHovered(_AnyWindow) = %d\n", + ImGui::IsWindowHovered(), + ImGui::IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup), + ImGui::IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem), + ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows), + ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_RootWindow), + ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_AllowWhenBlockedByPopup), + ImGui::IsWindowHovered(ImGuiHoveredFlags_RootWindow), + ImGui::IsWindowHovered(ImGuiHoveredFlags_AnyWindow)); + + ImGui::BeginChild("child", ImVec2(0, 50), true); + ImGui::Text("This is another child window for testing the _ChildWindows flag."); + ImGui::EndChild(); + if (embed_all_inside_a_child_window) + ImGui::EndChild(); + + static char dummy_str[] = "This is a dummy field to be able to tab-out of the widgets above."; + ImGui::InputText("dummy", dummy_str, IM_ARRAYSIZE(dummy_str), ImGuiInputTextFlags_ReadOnly); + + // Calling IsItemHovered() after begin returns the hovered status of the title bar. + // This is useful in particular if you want to create a context menu associated to the title bar of a window. + // This will also work when docked into a Tab (the Tab replace the Title Bar and guarantee the same properties). + static bool test_window = false; + ImGui::Checkbox("Hovered/Active tests after Begin() for title bar testing", &test_window); + if (test_window) + { + // FIXME-DOCK: This window cannot be docked within the ImGui Demo window, this will cause a feedback loop and get them stuck. + // Could we fix this through an ImGuiWindowClass feature? Or an API call to tag our parent as "don't skip items"? + ImGui::Begin("Title bar Hovered/Active tests", &test_window); + if (ImGui::BeginPopupContextItem()) // <-- This is using IsItemHovered() + { + if (ImGui::MenuItem("Close")) { test_window = false; } + ImGui::EndPopup(); + } + ImGui::Text( + "IsItemHovered() after begin = %d (== is title bar hovered)\n" + "IsItemActive() after begin = %d (== is window being clicked/moved)\n", + ImGui::IsItemHovered(), ImGui::IsItemActive()); + ImGui::End(); + } + + ImGui::TreePop(); + } +} + +static void ShowDemoWindowLayout() +{ + if (!ImGui::CollapsingHeader("Layout")) + return; + + if (ImGui::TreeNode("Child windows")) + { + HelpMarker("Use child windows to begin into a self-contained independent scrolling/clipping regions within a host window."); + static bool disable_mouse_wheel = false; + static bool disable_menu = false; + ImGui::Checkbox("Disable Mouse Wheel", &disable_mouse_wheel); + ImGui::Checkbox("Disable Menu", &disable_menu); + + static int line = 50; + bool goto_line = ImGui::Button("Goto"); + ImGui::SameLine(); + ImGui::SetNextItemWidth(100); + goto_line |= ImGui::InputInt("##Line", &line, 0, 0, ImGuiInputTextFlags_EnterReturnsTrue); + + // Child 1: no border, enable horizontal scrollbar + { + ImGuiWindowFlags window_flags = ImGuiWindowFlags_HorizontalScrollbar; + if (disable_mouse_wheel) + window_flags |= ImGuiWindowFlags_NoScrollWithMouse; + ImGui::BeginChild("ChildL", ImVec2(ImGui::GetWindowContentRegionWidth() * 0.5f, 260), false, window_flags); + for (int i = 0; i < 100; i++) + { + ImGui::Text("%04d: scrollable region", i); + if (goto_line && line == i) + ImGui::SetScrollHereY(); + } + if (goto_line && line >= 100) + ImGui::SetScrollHereY(); + ImGui::EndChild(); + } + + ImGui::SameLine(); + + // Child 2: rounded border + { + ImGuiWindowFlags window_flags = ImGuiWindowFlags_None; + if (disable_mouse_wheel) + window_flags |= ImGuiWindowFlags_NoScrollWithMouse; + if (!disable_menu) + window_flags |= ImGuiWindowFlags_MenuBar; + ImGui::PushStyleVar(ImGuiStyleVar_ChildRounding, 5.0f); + ImGui::BeginChild("ChildR", ImVec2(0, 260), true, window_flags); + if (!disable_menu && ImGui::BeginMenuBar()) + { + if (ImGui::BeginMenu("Menu")) + { + ShowExampleMenuFile(); + ImGui::EndMenu(); + } + ImGui::EndMenuBar(); + } + ImGui::Columns(2); + for (int i = 0; i < 100; i++) + { + char buf[32]; + sprintf(buf, "%03d", i); + ImGui::Button(buf, ImVec2(-FLT_MIN, 0.0f)); + ImGui::NextColumn(); + } + ImGui::EndChild(); + ImGui::PopStyleVar(); + } + + ImGui::Separator(); + + // Demonstrate a few extra things + // - Changing ImGuiCol_ChildBg (which is transparent black in default styles) + // - Using SetCursorPos() to position child window (the child window is an item from the POV of parent window) + // You can also call SetNextWindowPos() to position the child window. The parent window will effectively + // layout from this position. + // - Using ImGui::GetItemRectMin/Max() to query the "item" state (because the child window is an item from + // the POV of the parent window). See 'Demo->Querying Status (Active/Focused/Hovered etc.)' for details. + { + ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 10); + ImGui::PushStyleColor(ImGuiCol_ChildBg, IM_COL32(255, 0, 0, 100)); + ImGui::BeginChild("Red", ImVec2(200, 100), true, ImGuiWindowFlags_None); + for (int n = 0; n < 50; n++) + ImGui::Text("Some test %d", n); + ImGui::EndChild(); + ImVec2 child_rect_min = ImGui::GetItemRectMin(); + ImVec2 child_rect_max = ImGui::GetItemRectMax(); + ImGui::PopStyleColor(); + ImGui::Text("Rect of child window is: (%.0f,%.0f) (%.0f,%.0f)", child_rect_min.x, child_rect_min.y, child_rect_max.x, child_rect_max.y); + } + + ImGui::TreePop(); + } + + if (ImGui::TreeNode("Widgets Width")) + { + // Use SetNextItemWidth() to set the width of a single upcoming item. + // Use PushItemWidth()/PopItemWidth() to set the width of a group of items. + // In real code use you'll probably want to choose width values that are proportional to your font size + // e.g. Using '20.0f * GetFontSize()' as width instead of '200.0f', etc. + + static float f = 0.0f; + ImGui::Text("SetNextItemWidth/PushItemWidth(100)"); + ImGui::SameLine(); HelpMarker("Fixed width."); + ImGui::SetNextItemWidth(100); + ImGui::DragFloat("float##1", &f); + + ImGui::Text("SetNextItemWidth/PushItemWidth(GetWindowWidth() * 0.5f)"); + ImGui::SameLine(); HelpMarker("Half of window width."); + ImGui::SetNextItemWidth(ImGui::GetWindowWidth() * 0.5f); + ImGui::DragFloat("float##2", &f); + + ImGui::Text("SetNextItemWidth/PushItemWidth(GetContentRegionAvail().x * 0.5f)"); + ImGui::SameLine(); HelpMarker("Half of available width.\n(~ right-cursor_pos)\n(works within a column set)"); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x * 0.5f); + ImGui::DragFloat("float##3", &f); + + ImGui::Text("SetNextItemWidth/PushItemWidth(-100)"); + ImGui::SameLine(); HelpMarker("Align to right edge minus 100"); + ImGui::SetNextItemWidth(-100); + ImGui::DragFloat("float##4", &f); + + // Demonstrate using PushItemWidth to surround three items. + // Calling SetNextItemWidth() before each of them would have the same effect. + ImGui::Text("SetNextItemWidth/PushItemWidth(-1)"); + ImGui::SameLine(); HelpMarker("Align to right edge"); + ImGui::PushItemWidth(-1); + ImGui::DragFloat("##float5a", &f); + ImGui::DragFloat("##float5b", &f); + ImGui::DragFloat("##float5c", &f); + ImGui::PopItemWidth(); + + ImGui::TreePop(); + } + + if (ImGui::TreeNode("Basic Horizontal Layout")) + { + ImGui::TextWrapped("(Use ImGui::SameLine() to keep adding items to the right of the preceding item)"); + + // Text + ImGui::Text("Two items: Hello"); ImGui::SameLine(); + ImGui::TextColored(ImVec4(1,1,0,1), "Sailor"); + + // Adjust spacing + ImGui::Text("More spacing: Hello"); ImGui::SameLine(0, 20); + ImGui::TextColored(ImVec4(1,1,0,1), "Sailor"); + + // Button + ImGui::AlignTextToFramePadding(); + ImGui::Text("Normal buttons"); ImGui::SameLine(); + ImGui::Button("Banana"); ImGui::SameLine(); + ImGui::Button("Apple"); ImGui::SameLine(); + ImGui::Button("Corniflower"); + + // Button + ImGui::Text("Small buttons"); ImGui::SameLine(); + ImGui::SmallButton("Like this one"); ImGui::SameLine(); + ImGui::Text("can fit within a text block."); + + // Aligned to arbitrary position. Easy/cheap column. + ImGui::Text("Aligned"); + ImGui::SameLine(150); ImGui::Text("x=150"); + ImGui::SameLine(300); ImGui::Text("x=300"); + ImGui::Text("Aligned"); + ImGui::SameLine(150); ImGui::SmallButton("x=150"); + ImGui::SameLine(300); ImGui::SmallButton("x=300"); + + // Checkbox + static bool c1 = false, c2 = false, c3 = false, c4 = false; + ImGui::Checkbox("My", &c1); ImGui::SameLine(); + ImGui::Checkbox("Tailor", &c2); ImGui::SameLine(); + ImGui::Checkbox("Is", &c3); ImGui::SameLine(); + ImGui::Checkbox("Rich", &c4); + + // Various + static float f0 = 1.0f, f1 = 2.0f, f2 = 3.0f; + ImGui::PushItemWidth(80); + const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD" }; + static int item = -1; + ImGui::Combo("Combo", &item, items, IM_ARRAYSIZE(items)); ImGui::SameLine(); + ImGui::SliderFloat("X", &f0, 0.0f, 5.0f); ImGui::SameLine(); + ImGui::SliderFloat("Y", &f1, 0.0f, 5.0f); ImGui::SameLine(); + ImGui::SliderFloat("Z", &f2, 0.0f, 5.0f); + ImGui::PopItemWidth(); + + ImGui::PushItemWidth(80); + ImGui::Text("Lists:"); + static int selection[4] = { 0, 1, 2, 3 }; + for (int i = 0; i < 4; i++) + { + if (i > 0) ImGui::SameLine(); + ImGui::PushID(i); + ImGui::ListBox("", &selection[i], items, IM_ARRAYSIZE(items)); + ImGui::PopID(); + //if (ImGui::IsItemHovered()) ImGui::SetTooltip("ListBox %d hovered", i); + } + ImGui::PopItemWidth(); + + // Dummy + ImVec2 button_sz(40, 40); + ImGui::Button("A", button_sz); ImGui::SameLine(); + ImGui::Dummy(button_sz); ImGui::SameLine(); + ImGui::Button("B", button_sz); + + // Manually wrapping + // (we should eventually provide this as an automatic layout feature, but for now you can do it manually) + ImGui::Text("Manually wrapping:"); + ImGuiStyle& style = ImGui::GetStyle(); + int buttons_count = 20; + float window_visible_x2 = ImGui::GetWindowPos().x + ImGui::GetWindowContentRegionMax().x; + for (int n = 0; n < buttons_count; n++) + { + ImGui::PushID(n); + ImGui::Button("Box", button_sz); + float last_button_x2 = ImGui::GetItemRectMax().x; + float next_button_x2 = last_button_x2 + style.ItemSpacing.x + button_sz.x; // Expected position if next button was on same line + if (n + 1 < buttons_count && next_button_x2 < window_visible_x2) + ImGui::SameLine(); + ImGui::PopID(); + } + + ImGui::TreePop(); + } + + if (ImGui::TreeNode("Tabs")) + { + if (ImGui::TreeNode("Basic")) + { + ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_None; + if (ImGui::BeginTabBar("MyTabBar", tab_bar_flags)) + { + if (ImGui::BeginTabItem("Avocado")) + { + ImGui::Text("This is the Avocado tab!\nblah blah blah blah blah"); + ImGui::EndTabItem(); + } + if (ImGui::BeginTabItem("Broccoli")) + { + ImGui::Text("This is the Broccoli tab!\nblah blah blah blah blah"); + ImGui::EndTabItem(); + } + if (ImGui::BeginTabItem("Cucumber")) + { + ImGui::Text("This is the Cucumber tab!\nblah blah blah blah blah"); + ImGui::EndTabItem(); + } + ImGui::EndTabBar(); + } + ImGui::Separator(); + ImGui::TreePop(); + } + + if (ImGui::TreeNode("Advanced & Close Button")) + { + // Expose a couple of the available flags. In most cases you may just call BeginTabBar() with no flags (0). + static ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_Reorderable; + ImGui::CheckboxFlags("ImGuiTabBarFlags_Reorderable", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_Reorderable); + ImGui::CheckboxFlags("ImGuiTabBarFlags_AutoSelectNewTabs", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_AutoSelectNewTabs); + ImGui::CheckboxFlags("ImGuiTabBarFlags_TabListPopupButton", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_TabListPopupButton); + ImGui::CheckboxFlags("ImGuiTabBarFlags_NoCloseWithMiddleMouseButton", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_NoCloseWithMiddleMouseButton); + if ((tab_bar_flags & ImGuiTabBarFlags_FittingPolicyMask_) == 0) + tab_bar_flags |= ImGuiTabBarFlags_FittingPolicyDefault_; + if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyResizeDown", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_FittingPolicyResizeDown)) + tab_bar_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyResizeDown); + if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyScroll", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_FittingPolicyScroll)) + tab_bar_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyScroll); + + // Tab Bar + const char* names[4] = { "Artichoke", "Beetroot", "Celery", "Daikon" }; + static bool opened[4] = { true, true, true, true }; // Persistent user state + for (int n = 0; n < IM_ARRAYSIZE(opened); n++) + { + if (n > 0) { ImGui::SameLine(); } + ImGui::Checkbox(names[n], &opened[n]); + } + + // Passing a bool* to BeginTabItem() is similar to passing one to Begin(): + // the underlying bool will be set to false when the tab is closed. + if (ImGui::BeginTabBar("MyTabBar", tab_bar_flags)) + { + for (int n = 0; n < IM_ARRAYSIZE(opened); n++) + if (opened[n] && ImGui::BeginTabItem(names[n], &opened[n], ImGuiTabItemFlags_None)) + { + ImGui::Text("This is the %s tab!", names[n]); + if (n & 1) + ImGui::Text("I am an odd tab."); + ImGui::EndTabItem(); + } + ImGui::EndTabBar(); + } + ImGui::Separator(); + ImGui::TreePop(); + } + ImGui::TreePop(); + } + + if (ImGui::TreeNode("Groups")) + { + HelpMarker( + "BeginGroup() basically locks the horizontal position for new line. " + "EndGroup() bundles the whole group so that you can use \"item\" functions such as " + "IsItemHovered()/IsItemActive() or SameLine() etc. on the whole group."); + ImGui::BeginGroup(); + { + ImGui::BeginGroup(); + ImGui::Button("AAA"); + ImGui::SameLine(); + ImGui::Button("BBB"); + ImGui::SameLine(); + ImGui::BeginGroup(); + ImGui::Button("CCC"); + ImGui::Button("DDD"); + ImGui::EndGroup(); + ImGui::SameLine(); + ImGui::Button("EEE"); + ImGui::EndGroup(); + if (ImGui::IsItemHovered()) + ImGui::SetTooltip("First group hovered"); + } + // Capture the group size and create widgets using the same size + ImVec2 size = ImGui::GetItemRectSize(); + const float values[5] = { 0.5f, 0.20f, 0.80f, 0.60f, 0.25f }; + ImGui::PlotHistogram("##values", values, IM_ARRAYSIZE(values), 0, NULL, 0.0f, 1.0f, size); + + ImGui::Button("ACTION", ImVec2((size.x - ImGui::GetStyle().ItemSpacing.x) * 0.5f, size.y)); + ImGui::SameLine(); + ImGui::Button("REACTION", ImVec2((size.x - ImGui::GetStyle().ItemSpacing.x) * 0.5f, size.y)); + ImGui::EndGroup(); + ImGui::SameLine(); + + ImGui::Button("LEVERAGE\nBUZZWORD", size); + ImGui::SameLine(); + + if (ImGui::ListBoxHeader("List", size)) + { + ImGui::Selectable("Selected", true); + ImGui::Selectable("Not Selected", false); + ImGui::ListBoxFooter(); + } + + ImGui::TreePop(); + } + + if (ImGui::TreeNode("Text Baseline Alignment")) + { + { + ImGui::BulletText("Text baseline:"); + ImGui::SameLine(); HelpMarker( + "This is testing the vertical alignment that gets applied on text to keep it aligned with widgets. " + "Lines only composed of text or \"small\" widgets use less vertical space than lines with framed widgets."); + ImGui::Indent(); + + ImGui::Text("KO Blahblah"); ImGui::SameLine(); + ImGui::Button("Some framed item"); ImGui::SameLine(); + HelpMarker("Baseline of button will look misaligned with text.."); + + // If your line starts with text, call AlignTextToFramePadding() to align text to upcoming widgets. + // (because we don't know what's coming after the Text() statement, we need to move the text baseline + // down by FramePadding.y ahead of time) + ImGui::AlignTextToFramePadding(); + ImGui::Text("OK Blahblah"); ImGui::SameLine(); + ImGui::Button("Some framed item"); ImGui::SameLine(); + HelpMarker("We call AlignTextToFramePadding() to vertically align the text baseline by +FramePadding.y"); + + // SmallButton() uses the same vertical padding as Text + ImGui::Button("TEST##1"); ImGui::SameLine(); + ImGui::Text("TEST"); ImGui::SameLine(); + ImGui::SmallButton("TEST##2"); + + // If your line starts with text, call AlignTextToFramePadding() to align text to upcoming widgets. + ImGui::AlignTextToFramePadding(); + ImGui::Text("Text aligned to framed item"); ImGui::SameLine(); + ImGui::Button("Item##1"); ImGui::SameLine(); + ImGui::Text("Item"); ImGui::SameLine(); + ImGui::SmallButton("Item##2"); ImGui::SameLine(); + ImGui::Button("Item##3"); + + ImGui::Unindent(); + } + + ImGui::Spacing(); + + { + ImGui::BulletText("Multi-line text:"); + ImGui::Indent(); + ImGui::Text("One\nTwo\nThree"); ImGui::SameLine(); + ImGui::Text("Hello\nWorld"); ImGui::SameLine(); + ImGui::Text("Banana"); + + ImGui::Text("Banana"); ImGui::SameLine(); + ImGui::Text("Hello\nWorld"); ImGui::SameLine(); + ImGui::Text("One\nTwo\nThree"); + + ImGui::Button("HOP##1"); ImGui::SameLine(); + ImGui::Text("Banana"); ImGui::SameLine(); + ImGui::Text("Hello\nWorld"); ImGui::SameLine(); + ImGui::Text("Banana"); + + ImGui::Button("HOP##2"); ImGui::SameLine(); + ImGui::Text("Hello\nWorld"); ImGui::SameLine(); + ImGui::Text("Banana"); + ImGui::Unindent(); + } + + ImGui::Spacing(); + + { + ImGui::BulletText("Misc items:"); + ImGui::Indent(); + + // SmallButton() sets FramePadding to zero. Text baseline is aligned to match baseline of previous Button. + ImGui::Button("80x80", ImVec2(80, 80)); + ImGui::SameLine(); + ImGui::Button("50x50", ImVec2(50, 50)); + ImGui::SameLine(); + ImGui::Button("Button()"); + ImGui::SameLine(); + ImGui::SmallButton("SmallButton()"); + + // Tree + const float spacing = ImGui::GetStyle().ItemInnerSpacing.x; + ImGui::Button("Button##1"); + ImGui::SameLine(0.0f, spacing); + if (ImGui::TreeNode("Node##1")) + { + // Dummy tree data + for (int i = 0; i < 6; i++) + ImGui::BulletText("Item %d..", i); + ImGui::TreePop(); + } + + // Vertically align text node a bit lower so it'll be vertically centered with upcoming widget. + // Otherwise you can use SmallButton() (smaller fit). + ImGui::AlignTextToFramePadding(); + + // Common mistake to avoid: if we want to SameLine after TreeNode we need to do it before we add + // other contents below the node. + bool node_open = ImGui::TreeNode("Node##2"); + ImGui::SameLine(0.0f, spacing); ImGui::Button("Button##2"); + if (node_open) + { + // Dummy tree data + for (int i = 0; i < 6; i++) + ImGui::BulletText("Item %d..", i); + ImGui::TreePop(); + } + + // Bullet + ImGui::Button("Button##3"); + ImGui::SameLine(0.0f, spacing); + ImGui::BulletText("Bullet text"); + + ImGui::AlignTextToFramePadding(); + ImGui::BulletText("Node"); + ImGui::SameLine(0.0f, spacing); ImGui::Button("Button##4"); + ImGui::Unindent(); + } + + ImGui::TreePop(); + } + + if (ImGui::TreeNode("Scrolling")) + { + // Vertical scroll functions + HelpMarker("Use SetScrollHereY() or SetScrollFromPosY() to scroll to a given vertical position."); + + static int track_item = 50; + static bool enable_track = true; + static bool enable_extra_decorations = false; + static float scroll_to_off_px = 0.0f; + static float scroll_to_pos_px = 200.0f; + + ImGui::Checkbox("Decoration", &enable_extra_decorations); + ImGui::SameLine(); + HelpMarker("We expose this for testing because scrolling sometimes had issues with window decoration such as menu-bars."); + + ImGui::Checkbox("Track", &enable_track); + ImGui::PushItemWidth(100); + ImGui::SameLine(140); enable_track |= ImGui::DragInt("##item", &track_item, 0.25f, 0, 99, "Item = %d"); + + bool scroll_to_off = ImGui::Button("Scroll Offset"); + ImGui::SameLine(140); scroll_to_off |= ImGui::DragFloat("##off", &scroll_to_off_px, 1.00f, 0, FLT_MAX, "+%.0f px"); + + bool scroll_to_pos = ImGui::Button("Scroll To Pos"); + ImGui::SameLine(140); scroll_to_pos |= ImGui::DragFloat("##pos", &scroll_to_pos_px, 1.00f, -10, FLT_MAX, "X/Y = %.0f px"); + ImGui::PopItemWidth(); + + if (scroll_to_off || scroll_to_pos) + enable_track = false; + + ImGuiStyle& style = ImGui::GetStyle(); + float child_w = (ImGui::GetContentRegionAvail().x - 4 * style.ItemSpacing.x) / 5; + if (child_w < 1.0f) + child_w = 1.0f; + ImGui::PushID("##VerticalScrolling"); + for (int i = 0; i < 5; i++) + { + if (i > 0) ImGui::SameLine(); + ImGui::BeginGroup(); + const char* names[] = { "Top", "25%", "Center", "75%", "Bottom" }; + ImGui::TextUnformatted(names[i]); + + const ImGuiWindowFlags child_flags = enable_extra_decorations ? ImGuiWindowFlags_MenuBar : 0; + const ImGuiID child_id = ImGui::GetID((void*)(intptr_t)i); + const bool child_is_visible = ImGui::BeginChild(child_id, ImVec2(child_w, 200.0f), true, child_flags); + if (ImGui::BeginMenuBar()) + { + ImGui::TextUnformatted("abc"); + ImGui::EndMenuBar(); + } + if (scroll_to_off) + ImGui::SetScrollY(scroll_to_off_px); + if (scroll_to_pos) + ImGui::SetScrollFromPosY(ImGui::GetCursorStartPos().y + scroll_to_pos_px, i * 0.25f); + if (child_is_visible) // Avoid calling SetScrollHereY when running with culled items + { + for (int item = 0; item < 100; item++) + { + if (enable_track && item == track_item) + { + ImGui::TextColored(ImVec4(1, 1, 0, 1), "Item %d", item); + ImGui::SetScrollHereY(i * 0.25f); // 0.0f:top, 0.5f:center, 1.0f:bottom + } + else + { + ImGui::Text("Item %d", item); + } + } + } + float scroll_y = ImGui::GetScrollY(); + float scroll_max_y = ImGui::GetScrollMaxY(); + ImGui::EndChild(); + ImGui::Text("%.0f/%.0f", scroll_y, scroll_max_y); + ImGui::EndGroup(); + } + ImGui::PopID(); + + // Horizontal scroll functions + ImGui::Spacing(); + HelpMarker( + "Use SetScrollHereX() or SetScrollFromPosX() to scroll to a given horizontal position.\n\n" + "Using the \"Scroll To Pos\" button above will make the discontinuity at edges visible: " + "scrolling to the top/bottom/left/right-most item will add an additional WindowPadding to reflect " + "on reaching the edge of the list.\n\nBecause the clipping rectangle of most window hides half " + "worth of WindowPadding on the left/right, using SetScrollFromPosX(+1) will usually result in " + "clipped text whereas the equivalent SetScrollFromPosY(+1) wouldn't."); + ImGui::PushID("##HorizontalScrolling"); + for (int i = 0; i < 5; i++) + { + float child_height = ImGui::GetTextLineHeight() + style.ScrollbarSize + style.WindowPadding.y * 2.0f; + ImGuiWindowFlags child_flags = ImGuiWindowFlags_HorizontalScrollbar | (enable_extra_decorations ? ImGuiWindowFlags_AlwaysVerticalScrollbar : 0); + ImGuiID child_id = ImGui::GetID((void*)(intptr_t)i); + bool child_is_visible = ImGui::BeginChild(child_id, ImVec2(-100, child_height), true, child_flags); + if (scroll_to_off) + ImGui::SetScrollX(scroll_to_off_px); + if (scroll_to_pos) + ImGui::SetScrollFromPosX(ImGui::GetCursorStartPos().x + scroll_to_pos_px, i * 0.25f); + if (child_is_visible) // Avoid calling SetScrollHereY when running with culled items + { + for (int item = 0; item < 100; item++) + { + if (enable_track && item == track_item) + { + ImGui::TextColored(ImVec4(1, 1, 0, 1), "Item %d", item); + ImGui::SetScrollHereX(i * 0.25f); // 0.0f:left, 0.5f:center, 1.0f:right + } + else + { + ImGui::Text("Item %d", item); + } + ImGui::SameLine(); + } + } + float scroll_x = ImGui::GetScrollX(); + float scroll_max_x = ImGui::GetScrollMaxX(); + ImGui::EndChild(); + ImGui::SameLine(); + const char* names[] = { "Left", "25%", "Center", "75%", "Right" }; + ImGui::Text("%s\n%.0f/%.0f", names[i], scroll_x, scroll_max_x); + ImGui::Spacing(); + } + ImGui::PopID(); + + // Miscellaneous Horizontal Scrolling Demo + HelpMarker( + "Horizontal scrolling for a window is enabled via the ImGuiWindowFlags_HorizontalScrollbar flag.\n\n" + "You may want to also explicitly specify content width by using SetNextWindowContentWidth() before Begin()."); + static int lines = 7; + ImGui::SliderInt("Lines", &lines, 1, 15); + ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 3.0f); + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(2.0f, 1.0f)); + ImVec2 scrolling_child_size = ImVec2(0, ImGui::GetFrameHeightWithSpacing() * 7 + 30); + ImGui::BeginChild("scrolling", scrolling_child_size, true, ImGuiWindowFlags_HorizontalScrollbar); + for (int line = 0; line < lines; line++) + { + // Display random stuff. For the sake of this trivial demo we are using basic Button() + SameLine() + // If you want to create your own time line for a real application you may be better off manipulating + // the cursor position yourself, aka using SetCursorPos/SetCursorScreenPos to position the widgets + // yourself. You may also want to use the lower-level ImDrawList API. + int num_buttons = 10 + ((line & 1) ? line * 9 : line * 3); + for (int n = 0; n < num_buttons; n++) + { + if (n > 0) ImGui::SameLine(); + ImGui::PushID(n + line * 1000); + char num_buf[16]; + sprintf(num_buf, "%d", n); + const char* label = (!(n%15)) ? "FizzBuzz" : (!(n%3)) ? "Fizz" : (!(n%5)) ? "Buzz" : num_buf; + float hue = n*0.05f; + ImGui::PushStyleColor(ImGuiCol_Button, (ImVec4)ImColor::HSV(hue, 0.6f, 0.6f)); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, (ImVec4)ImColor::HSV(hue, 0.7f, 0.7f)); + ImGui::PushStyleColor(ImGuiCol_ButtonActive, (ImVec4)ImColor::HSV(hue, 0.8f, 0.8f)); + ImGui::Button(label, ImVec2(40.0f + sinf((float)(line + n)) * 20.0f, 0.0f)); + ImGui::PopStyleColor(3); + ImGui::PopID(); + } + } + float scroll_x = ImGui::GetScrollX(); + float scroll_max_x = ImGui::GetScrollMaxX(); + ImGui::EndChild(); + ImGui::PopStyleVar(2); + float scroll_x_delta = 0.0f; + ImGui::SmallButton("<<"); + if (ImGui::IsItemActive()) + scroll_x_delta = -ImGui::GetIO().DeltaTime * 1000.0f; + ImGui::SameLine(); + ImGui::Text("Scroll from code"); ImGui::SameLine(); + ImGui::SmallButton(">>"); + if (ImGui::IsItemActive()) + scroll_x_delta = +ImGui::GetIO().DeltaTime * 1000.0f; + ImGui::SameLine(); + ImGui::Text("%.0f/%.0f", scroll_x, scroll_max_x); + if (scroll_x_delta != 0.0f) + { + // Demonstrate a trick: you can use Begin to set yourself in the context of another window + // (here we are already out of your child window) + ImGui::BeginChild("scrolling"); + ImGui::SetScrollX(ImGui::GetScrollX() + scroll_x_delta); + ImGui::EndChild(); + } + ImGui::Spacing(); + + static bool show_horizontal_contents_size_demo_window = false; + ImGui::Checkbox("Show Horizontal contents size demo window", &show_horizontal_contents_size_demo_window); + + if (show_horizontal_contents_size_demo_window) + { + static bool show_h_scrollbar = true; + static bool show_button = true; + static bool show_tree_nodes = true; + static bool show_text_wrapped = false; + static bool show_columns = true; + static bool show_tab_bar = true; + static bool show_child = false; + static bool explicit_content_size = false; + static float contents_size_x = 300.0f; + if (explicit_content_size) + ImGui::SetNextWindowContentSize(ImVec2(contents_size_x, 0.0f)); + ImGui::Begin("Horizontal contents size demo window", &show_horizontal_contents_size_demo_window, show_h_scrollbar ? ImGuiWindowFlags_HorizontalScrollbar : 0); + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(2, 0)); + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(2, 0)); + HelpMarker("Test of different widgets react and impact the work rectangle growing when horizontal scrolling is enabled.\n\nUse 'Metrics->Tools->Show windows rectangles' to visualize rectangles."); + ImGui::Checkbox("H-scrollbar", &show_h_scrollbar); + ImGui::Checkbox("Button", &show_button); // Will grow contents size (unless explicitly overwritten) + ImGui::Checkbox("Tree nodes", &show_tree_nodes); // Will grow contents size and display highlight over full width + ImGui::Checkbox("Text wrapped", &show_text_wrapped);// Will grow and use contents size + ImGui::Checkbox("Columns", &show_columns); // Will use contents size + ImGui::Checkbox("Tab bar", &show_tab_bar); // Will use contents size + ImGui::Checkbox("Child", &show_child); // Will grow and use contents size + ImGui::Checkbox("Explicit content size", &explicit_content_size); + ImGui::Text("Scroll %.1f/%.1f %.1f/%.1f", ImGui::GetScrollX(), ImGui::GetScrollMaxX(), ImGui::GetScrollY(), ImGui::GetScrollMaxY()); + if (explicit_content_size) + { + ImGui::SameLine(); + ImGui::SetNextItemWidth(100); + ImGui::DragFloat("##csx", &contents_size_x); + ImVec2 p = ImGui::GetCursorScreenPos(); + ImGui::GetWindowDrawList()->AddRectFilled(p, ImVec2(p.x + 10, p.y + 10), IM_COL32_WHITE); + ImGui::GetWindowDrawList()->AddRectFilled(ImVec2(p.x + contents_size_x - 10, p.y), ImVec2(p.x + contents_size_x, p.y + 10), IM_COL32_WHITE); + ImGui::Dummy(ImVec2(0, 10)); + } + ImGui::PopStyleVar(2); + ImGui::Separator(); + if (show_button) + { + ImGui::Button("this is a 300-wide button", ImVec2(300, 0)); + } + if (show_tree_nodes) + { + bool open = true; + if (ImGui::TreeNode("this is a tree node")) + { + if (ImGui::TreeNode("another one of those tree node...")) + { + ImGui::Text("Some tree contents"); + ImGui::TreePop(); + } + ImGui::TreePop(); + } + ImGui::CollapsingHeader("CollapsingHeader", &open); + } + if (show_text_wrapped) + { + ImGui::TextWrapped("This text should automatically wrap on the edge of the work rectangle."); + } + if (show_columns) + { + ImGui::Columns(4); + for (int n = 0; n < 4; n++) + { + ImGui::Text("Width %.2f", ImGui::GetColumnWidth()); + ImGui::NextColumn(); + } + ImGui::Columns(1); + } + if (show_tab_bar && ImGui::BeginTabBar("Hello")) + { + if (ImGui::BeginTabItem("OneOneOne")) { ImGui::EndTabItem(); } + if (ImGui::BeginTabItem("TwoTwoTwo")) { ImGui::EndTabItem(); } + if (ImGui::BeginTabItem("ThreeThreeThree")) { ImGui::EndTabItem(); } + if (ImGui::BeginTabItem("FourFourFour")) { ImGui::EndTabItem(); } + ImGui::EndTabBar(); + } + if (show_child) + { + ImGui::BeginChild("child", ImVec2(0,0), true); + ImGui::EndChild(); + } + ImGui::End(); + } + + ImGui::TreePop(); + } + + if (ImGui::TreeNode("Clipping")) + { + static ImVec2 size(100, 100), offset(50, 20); + ImGui::TextWrapped( + "On a per-widget basis we are occasionally clipping text CPU-side if it won't fit in its frame. " + "Otherwise we are doing coarser clipping + passing a scissor rectangle to the renderer. " + "The system is designed to try minimizing both execution and CPU/GPU rendering cost."); + ImGui::DragFloat2("size", (float*)&size, 0.5f, 1.0f, 200.0f, "%.0f"); + ImGui::TextWrapped("(Click and drag)"); + ImVec2 pos = ImGui::GetCursorScreenPos(); + ImVec4 clip_rect(pos.x, pos.y, pos.x + size.x, pos.y + size.y); + ImGui::InvisibleButton("##dummy", size); + if (ImGui::IsItemActive() && ImGui::IsMouseDragging(0)) + { + offset.x += ImGui::GetIO().MouseDelta.x; + offset.y += ImGui::GetIO().MouseDelta.y; + } + ImGui::GetWindowDrawList()->AddRectFilled(pos, ImVec2(pos.x + size.x, pos.y + size.y), IM_COL32(90, 90, 120, 255)); + ImGui::GetWindowDrawList()->AddText(ImGui::GetFont(), ImGui::GetFontSize()*2.0f, ImVec2(pos.x + offset.x, pos.y + offset.y), IM_COL32_WHITE, "Line 1 hello\nLine 2 clip me!", NULL, 0.0f, &clip_rect); + ImGui::TreePop(); + } +} + +static void ShowDemoWindowPopups() +{ + if (!ImGui::CollapsingHeader("Popups & Modal windows")) + return; + + // The properties of popups windows are: + // - They block normal mouse hovering detection outside them. (*) + // - Unless modal, they can be closed by clicking anywhere outside them, or by pressing ESCAPE. + // - Their visibility state (~bool) is held internally by Dear ImGui instead of being held by the programmer as + // we are used to with regular Begin() calls. User can manipulate the visibility state by calling OpenPopup(). + // (*) One can use IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup) to bypass it and detect hovering even + // when normally blocked by a popup. + // Those three properties are connected. The library needs to hold their visibility state BECAUSE it can close + // popups at any time. + + // Typical use for regular windows: + // bool my_tool_is_active = false; if (ImGui::Button("Open")) my_tool_is_active = true; [...] if (my_tool_is_active) Begin("My Tool", &my_tool_is_active) { [...] } End(); + // Typical use for popups: + // if (ImGui::Button("Open")) ImGui::OpenPopup("MyPopup"); if (ImGui::BeginPopup("MyPopup") { [...] EndPopup(); } + + // With popups we have to go through a library call (here OpenPopup) to manipulate the visibility state. + // This may be a bit confusing at first but it should quickly make sense. Follow on the examples below. + + if (ImGui::TreeNode("Popups")) + { + ImGui::TextWrapped( + "When a popup is active, it inhibits interacting with windows that are behind the popup. " + "Clicking outside the popup closes it."); + + static int selected_fish = -1; + const char* names[] = { "Bream", "Haddock", "Mackerel", "Pollock", "Tilefish" }; + static bool toggles[] = { true, false, false, false, false }; + + // Simple selection popup (if you want to show the current selection inside the Button itself, + // you may want to build a string using the "###" operator to preserve a constant ID with a variable label) + if (ImGui::Button("Select..")) + ImGui::OpenPopup("my_select_popup"); + ImGui::SameLine(); + ImGui::TextUnformatted(selected_fish == -1 ? "" : names[selected_fish]); + if (ImGui::BeginPopup("my_select_popup")) + { + ImGui::Text("Aquarium"); + ImGui::Separator(); + for (int i = 0; i < IM_ARRAYSIZE(names); i++) + if (ImGui::Selectable(names[i])) + selected_fish = i; + ImGui::EndPopup(); + } + + // Showing a menu with toggles + if (ImGui::Button("Toggle..")) + ImGui::OpenPopup("my_toggle_popup"); + if (ImGui::BeginPopup("my_toggle_popup")) + { + for (int i = 0; i < IM_ARRAYSIZE(names); i++) + ImGui::MenuItem(names[i], "", &toggles[i]); + if (ImGui::BeginMenu("Sub-menu")) + { + ImGui::MenuItem("Click me"); + ImGui::EndMenu(); + } + + ImGui::Separator(); + ImGui::Text("Tooltip here"); + if (ImGui::IsItemHovered()) + ImGui::SetTooltip("I am a tooltip over a popup"); + + if (ImGui::Button("Stacked Popup")) + ImGui::OpenPopup("another popup"); + if (ImGui::BeginPopup("another popup")) + { + for (int i = 0; i < IM_ARRAYSIZE(names); i++) + ImGui::MenuItem(names[i], "", &toggles[i]); + if (ImGui::BeginMenu("Sub-menu")) + { + ImGui::MenuItem("Click me"); + if (ImGui::Button("Stacked Popup")) + ImGui::OpenPopup("another popup"); + if (ImGui::BeginPopup("another popup")) + { + ImGui::Text("I am the last one here."); + ImGui::EndPopup(); + } + ImGui::EndMenu(); + } + ImGui::EndPopup(); + } + ImGui::EndPopup(); + } + + // Call the more complete ShowExampleMenuFile which we use in various places of this demo + if (ImGui::Button("File Menu..")) + ImGui::OpenPopup("my_file_popup"); + if (ImGui::BeginPopup("my_file_popup")) + { + ShowExampleMenuFile(); + ImGui::EndPopup(); + } + + ImGui::TreePop(); + } + + if (ImGui::TreeNode("Context menus")) + { + // BeginPopupContextItem() is a helper to provide common/simple popup behavior of essentially doing: + // if (IsItemHovered() && IsMouseReleased(0)) + // OpenPopup(id); + // return BeginPopup(id); + // For more advanced uses you may want to replicate and customize this code. + // See details in BeginPopupContextItem(). + static float value = 0.5f; + ImGui::Text("Value = %.3f (<-- right-click here)", value); + if (ImGui::BeginPopupContextItem("item context menu")) + { + if (ImGui::Selectable("Set to zero")) value = 0.0f; + if (ImGui::Selectable("Set to PI")) value = 3.1415f; + ImGui::SetNextItemWidth(-1); + ImGui::DragFloat("##Value", &value, 0.1f, 0.0f, 0.0f); + ImGui::EndPopup(); + } + + // We can also use OpenPopupOnItemClick() which is the same as BeginPopupContextItem() but without the + // Begin() call. So here we will make it that clicking on the text field with the right mouse button (1) + // will toggle the visibility of the popup above. + ImGui::Text("(You can also right-click me to open the same popup as above.)"); + ImGui::OpenPopupOnItemClick("item context menu", 1); + + // When used after an item that has an ID (e.g.Button), we can skip providing an ID to BeginPopupContextItem(). + // BeginPopupContextItem() will use the last item ID as the popup ID. + // In addition here, we want to include your editable label inside the button label. + // We use the ### operator to override the ID (read FAQ about ID for details) + static char name[32] = "Label1"; + char buf[64]; + sprintf(buf, "Button: %s###Button", name); // ### operator override ID ignoring the preceding label + ImGui::Button(buf); + if (ImGui::BeginPopupContextItem()) + { + ImGui::Text("Edit name:"); + ImGui::InputText("##edit", name, IM_ARRAYSIZE(name)); + if (ImGui::Button("Close")) + ImGui::CloseCurrentPopup(); + ImGui::EndPopup(); + } + ImGui::SameLine(); ImGui::Text("(<-- right-click here)"); + + ImGui::TreePop(); + } + + if (ImGui::TreeNode("Modals")) + { + ImGui::TextWrapped("Modal windows are like popups but the user cannot close them by clicking outside."); + + if (ImGui::Button("Delete..")) + ImGui::OpenPopup("Delete?"); + + if (ImGui::BeginPopupModal("Delete?", NULL, ImGuiWindowFlags_AlwaysAutoResize)) + { + ImGui::Text("All those beautiful files will be deleted.\nThis operation cannot be undone!\n\n"); + ImGui::Separator(); + + //static int dummy_i = 0; + //ImGui::Combo("Combo", &dummy_i, "Delete\0Delete harder\0"); + + static bool dont_ask_me_next_time = false; + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0)); + ImGui::Checkbox("Don't ask me next time", &dont_ask_me_next_time); + ImGui::PopStyleVar(); + + if (ImGui::Button("OK", ImVec2(120, 0))) { ImGui::CloseCurrentPopup(); } + ImGui::SetItemDefaultFocus(); + ImGui::SameLine(); + if (ImGui::Button("Cancel", ImVec2(120, 0))) { ImGui::CloseCurrentPopup(); } + ImGui::EndPopup(); + } + + if (ImGui::Button("Stacked modals..")) + ImGui::OpenPopup("Stacked 1"); + if (ImGui::BeginPopupModal("Stacked 1", NULL, ImGuiWindowFlags_MenuBar)) + { + if (ImGui::BeginMenuBar()) + { + if (ImGui::BeginMenu("File")) + { + if (ImGui::MenuItem("Dummy menu item")) {} + ImGui::EndMenu(); + } + ImGui::EndMenuBar(); + } + ImGui::Text("Hello from Stacked The First\nUsing style.Colors[ImGuiCol_ModalWindowDimBg] behind it."); + + // Testing behavior of widgets stacking their own regular popups over the modal. + static int item = 1; + static float color[4] = { 0.4f,0.7f,0.0f,0.5f }; + ImGui::Combo("Combo", &item, "aaaa\0bbbb\0cccc\0dddd\0eeee\0\0"); + ImGui::ColorEdit4("color", color); + + if (ImGui::Button("Add another modal..")) + ImGui::OpenPopup("Stacked 2"); + + // Also demonstrate passing a bool* to BeginPopupModal(), this will create a regular close button which + // will close the popup. Note that the visibility state of popups is owned by imgui, so the input value + // of the bool actually doesn't matter here. + bool dummy_open = true; + if (ImGui::BeginPopupModal("Stacked 2", &dummy_open)) + { + ImGui::Text("Hello from Stacked The Second!"); + if (ImGui::Button("Close")) + ImGui::CloseCurrentPopup(); + ImGui::EndPopup(); + } + + if (ImGui::Button("Close")) + ImGui::CloseCurrentPopup(); + ImGui::EndPopup(); + } + + ImGui::TreePop(); + } + + if (ImGui::TreeNode("Menus inside a regular window")) + { + ImGui::TextWrapped("Below we are testing adding menu items to a regular window. It's rather unusual but should work!"); + ImGui::Separator(); + + // Note: As a quirk in this very specific example, we want to differentiate the parent of this menu from the + // parent of the various popup menus above. To do so we are encloding the items in a PushID()/PopID() block + // to make them two different menusets. If we don't, opening any popup above and hovering our menu here would + // open it. This is because once a menu is active, we allow to switch to a sibling menu by just hovering on it, + // which is the desired behavior for regular menus. + ImGui::PushID("foo"); + ImGui::MenuItem("Menu item", "CTRL+M"); + if (ImGui::BeginMenu("Menu inside a regular window")) + { + ShowExampleMenuFile(); + ImGui::EndMenu(); + } + ImGui::PopID(); + ImGui::Separator(); + ImGui::TreePop(); + } +} + +static void ShowDemoWindowColumns() +{ + if (!ImGui::CollapsingHeader("Columns")) + return; + + ImGui::PushID("Columns"); + + static bool disable_indent = false; + ImGui::Checkbox("Disable tree indentation", &disable_indent); + ImGui::SameLine(); + HelpMarker("Disable the indenting of tree nodes so demo columns can use the full window width."); + if (disable_indent) + ImGui::PushStyleVar(ImGuiStyleVar_IndentSpacing, 0.0f); + + // Basic columns + if (ImGui::TreeNode("Basic")) + { + ImGui::Text("Without border:"); + ImGui::Columns(3, "mycolumns3", false); // 3-ways, no border + ImGui::Separator(); + for (int n = 0; n < 14; n++) + { + char label[32]; + sprintf(label, "Item %d", n); + if (ImGui::Selectable(label)) {} + //if (ImGui::Button(label, ImVec2(-FLT_MIN,0.0f))) {} + ImGui::NextColumn(); + } + ImGui::Columns(1); + ImGui::Separator(); + + ImGui::Text("With border:"); + ImGui::Columns(4, "mycolumns"); // 4-ways, with border + ImGui::Separator(); + ImGui::Text("ID"); ImGui::NextColumn(); + ImGui::Text("Name"); ImGui::NextColumn(); + ImGui::Text("Path"); ImGui::NextColumn(); + ImGui::Text("Hovered"); ImGui::NextColumn(); + ImGui::Separator(); + const char* names[3] = { "One", "Two", "Three" }; + const char* paths[3] = { "/path/one", "/path/two", "/path/three" }; + static int selected = -1; + for (int i = 0; i < 3; i++) + { + char label[32]; + sprintf(label, "%04d", i); + if (ImGui::Selectable(label, selected == i, ImGuiSelectableFlags_SpanAllColumns)) + selected = i; + bool hovered = ImGui::IsItemHovered(); + ImGui::NextColumn(); + ImGui::Text(names[i]); ImGui::NextColumn(); + ImGui::Text(paths[i]); ImGui::NextColumn(); + ImGui::Text("%d", hovered); ImGui::NextColumn(); + } + ImGui::Columns(1); + ImGui::Separator(); + ImGui::TreePop(); + } + + if (ImGui::TreeNode("Borders")) + { + // NB: Future columns API should allow automatic horizontal borders. + static bool h_borders = true; + static bool v_borders = true; + static int columns_count = 4; + const int lines_count = 3; + ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8); + ImGui::DragInt("##columns_count", &columns_count, 0.1f, 2, 10, "%d columns"); + if (columns_count < 2) + columns_count = 2; + ImGui::SameLine(); + ImGui::Checkbox("horizontal", &h_borders); + ImGui::SameLine(); + ImGui::Checkbox("vertical", &v_borders); + ImGui::Columns(columns_count, NULL, v_borders); + for (int i = 0; i < columns_count * lines_count; i++) + { + if (h_borders && ImGui::GetColumnIndex() == 0) + ImGui::Separator(); + ImGui::Text("%c%c%c", 'a' + i, 'a' + i, 'a' + i); + ImGui::Text("Width %.2f", ImGui::GetColumnWidth()); + ImGui::Text("Avail %.2f", ImGui::GetContentRegionAvail().x); + ImGui::Text("Offset %.2f", ImGui::GetColumnOffset()); + ImGui::Text("Long text that is likely to clip"); + ImGui::Button("Button", ImVec2(-FLT_MIN, 0.0f)); + ImGui::NextColumn(); + } + ImGui::Columns(1); + if (h_borders) + ImGui::Separator(); + ImGui::TreePop(); + } + + // Create multiple items in a same cell before switching to next column + if (ImGui::TreeNode("Mixed items")) + { + ImGui::Columns(3, "mixed"); + ImGui::Separator(); + + ImGui::Text("Hello"); + ImGui::Button("Banana"); + ImGui::NextColumn(); + + ImGui::Text("ImGui"); + ImGui::Button("Apple"); + static float foo = 1.0f; + ImGui::InputFloat("red", &foo, 0.05f, 0, "%.3f"); + ImGui::Text("An extra line here."); + ImGui::NextColumn(); + + ImGui::Text("Sailor"); + ImGui::Button("Corniflower"); + static float bar = 1.0f; + ImGui::InputFloat("blue", &bar, 0.05f, 0, "%.3f"); + ImGui::NextColumn(); + + if (ImGui::CollapsingHeader("Category A")) { ImGui::Text("Blah blah blah"); } ImGui::NextColumn(); + if (ImGui::CollapsingHeader("Category B")) { ImGui::Text("Blah blah blah"); } ImGui::NextColumn(); + if (ImGui::CollapsingHeader("Category C")) { ImGui::Text("Blah blah blah"); } ImGui::NextColumn(); + ImGui::Columns(1); + ImGui::Separator(); + ImGui::TreePop(); + } + + // Word wrapping + if (ImGui::TreeNode("Word-wrapping")) + { + ImGui::Columns(2, "word-wrapping"); + ImGui::Separator(); + ImGui::TextWrapped("The quick brown fox jumps over the lazy dog."); + ImGui::TextWrapped("Hello Left"); + ImGui::NextColumn(); + ImGui::TextWrapped("The quick brown fox jumps over the lazy dog."); + ImGui::TextWrapped("Hello Right"); + ImGui::Columns(1); + ImGui::Separator(); + ImGui::TreePop(); + } + + // Scrolling columns + /* + if (ImGui::TreeNode("Vertical Scrolling")) + { + ImGui::BeginChild("##header", ImVec2(0, ImGui::GetTextLineHeightWithSpacing()+ImGui::GetStyle().ItemSpacing.y)); + ImGui::Columns(3); + ImGui::Text("ID"); ImGui::NextColumn(); + ImGui::Text("Name"); ImGui::NextColumn(); + ImGui::Text("Path"); ImGui::NextColumn(); + ImGui::Columns(1); + ImGui::Separator(); + ImGui::EndChild(); + ImGui::BeginChild("##scrollingregion", ImVec2(0, 60)); + ImGui::Columns(3); + for (int i = 0; i < 10; i++) + { + ImGui::Text("%04d", i); ImGui::NextColumn(); + ImGui::Text("Foobar"); ImGui::NextColumn(); + ImGui::Text("/path/foobar/%04d/", i); ImGui::NextColumn(); + } + ImGui::Columns(1); + ImGui::EndChild(); + ImGui::TreePop(); + } + */ + + if (ImGui::TreeNode("Horizontal Scrolling")) + { + ImGui::SetNextWindowContentSize(ImVec2(1500.0f, 0.0f)); + ImVec2 child_size = ImVec2(0, ImGui::GetFontSize() * 20.0f); + ImGui::BeginChild("##ScrollingRegion", child_size, false, ImGuiWindowFlags_HorizontalScrollbar); + ImGui::Columns(10); + int ITEMS_COUNT = 2000; + ImGuiListClipper clipper(ITEMS_COUNT); // Also demonstrate using the clipper for large list + while (clipper.Step()) + { + for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) + for (int j = 0; j < 10; j++) + { + ImGui::Text("Line %d Column %d...", i, j); + ImGui::NextColumn(); + } + } + ImGui::Columns(1); + ImGui::EndChild(); + ImGui::TreePop(); + } + + if (ImGui::TreeNode("Tree")) + { + ImGui::Columns(2, "tree", true); + for (int x = 0; x < 3; x++) + { + bool open1 = ImGui::TreeNode((void*)(intptr_t)x, "Node%d", x); + ImGui::NextColumn(); + ImGui::Text("Node contents"); + ImGui::NextColumn(); + if (open1) + { + for (int y = 0; y < 3; y++) + { + bool open2 = ImGui::TreeNode((void*)(intptr_t)y, "Node%d.%d", x, y); + ImGui::NextColumn(); + ImGui::Text("Node contents"); + if (open2) + { + ImGui::Text("Even more contents"); + if (ImGui::TreeNode("Tree in column")) + { + ImGui::Text("The quick brown fox jumps over the lazy dog"); + ImGui::TreePop(); + } + } + ImGui::NextColumn(); + if (open2) + ImGui::TreePop(); + } + ImGui::TreePop(); + } + } + ImGui::Columns(1); + ImGui::TreePop(); + } + + if (disable_indent) + ImGui::PopStyleVar(); + ImGui::PopID(); +} + +static void ShowDemoWindowMisc() +{ + if (ImGui::CollapsingHeader("Filtering")) + { + // Helper class to easy setup a text filter. + // You may want to implement a more feature-full filtering scheme in your own application. + static ImGuiTextFilter filter; + ImGui::Text("Filter usage:\n" + " \"\" display all lines\n" + " \"xxx\" display lines containing \"xxx\"\n" + " \"xxx,yyy\" display lines containing \"xxx\" or \"yyy\"\n" + " \"-xxx\" hide lines containing \"xxx\""); + filter.Draw(); + const char* lines[] = { "aaa1.c", "bbb1.c", "ccc1.c", "aaa2.cpp", "bbb2.cpp", "ccc2.cpp", "abc.h", "hello, world" }; + for (int i = 0; i < IM_ARRAYSIZE(lines); i++) + if (filter.PassFilter(lines[i])) + ImGui::BulletText("%s", lines[i]); + } + + if (ImGui::CollapsingHeader("Inputs, Navigation & Focus")) + { + ImGuiIO& io = ImGui::GetIO(); + + // Display ImGuiIO output flags + ImGui::Text("WantCaptureMouse: %d", io.WantCaptureMouse); + ImGui::Text("WantCaptureKeyboard: %d", io.WantCaptureKeyboard); + ImGui::Text("WantTextInput: %d", io.WantTextInput); + ImGui::Text("WantSetMousePos: %d", io.WantSetMousePos); + ImGui::Text("NavActive: %d, NavVisible: %d", io.NavActive, io.NavVisible); + + // Display Keyboard/Mouse state + if (ImGui::TreeNode("Keyboard, Mouse & Navigation State")) + { + if (ImGui::IsMousePosValid()) + ImGui::Text("Mouse pos: (%g, %g)", io.MousePos.x, io.MousePos.y); + else + ImGui::Text("Mouse pos: "); + ImGui::Text("Mouse delta: (%g, %g)", io.MouseDelta.x, io.MouseDelta.y); + ImGui::Text("Mouse down:"); for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) if (io.MouseDownDuration[i] >= 0.0f) { ImGui::SameLine(); ImGui::Text("b%d (%.02f secs)", i, io.MouseDownDuration[i]); } + ImGui::Text("Mouse clicked:"); for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) if (ImGui::IsMouseClicked(i)) { ImGui::SameLine(); ImGui::Text("b%d", i); } + ImGui::Text("Mouse dblclick:"); for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) if (ImGui::IsMouseDoubleClicked(i)) { ImGui::SameLine(); ImGui::Text("b%d", i); } + ImGui::Text("Mouse released:"); for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) if (ImGui::IsMouseReleased(i)) { ImGui::SameLine(); ImGui::Text("b%d", i); } + ImGui::Text("Mouse wheel: %.1f", io.MouseWheel); + + ImGui::Text("Keys down:"); for (int i = 0; i < IM_ARRAYSIZE(io.KeysDown); i++) if (io.KeysDownDuration[i] >= 0.0f) { ImGui::SameLine(); ImGui::Text("%d (0x%X) (%.02f secs)", i, i, io.KeysDownDuration[i]); } + ImGui::Text("Keys pressed:"); for (int i = 0; i < IM_ARRAYSIZE(io.KeysDown); i++) if (ImGui::IsKeyPressed(i)) { ImGui::SameLine(); ImGui::Text("%d (0x%X)", i, i); } + ImGui::Text("Keys release:"); for (int i = 0; i < IM_ARRAYSIZE(io.KeysDown); i++) if (ImGui::IsKeyReleased(i)) { ImGui::SameLine(); ImGui::Text("%d (0x%X)", i, i); } + ImGui::Text("Keys mods: %s%s%s%s", io.KeyCtrl ? "CTRL " : "", io.KeyShift ? "SHIFT " : "", io.KeyAlt ? "ALT " : "", io.KeySuper ? "SUPER " : ""); + ImGui::Text("Chars queue:"); for (int i = 0; i < io.InputQueueCharacters.Size; i++) { ImWchar c = io.InputQueueCharacters[i]; ImGui::SameLine(); ImGui::Text("\'%c\' (0x%04X)", (c > ' ' && c <= 255) ? (char)c : '?', c); } // FIXME: We should convert 'c' to UTF-8 here but the functions are not public. + + ImGui::Text("NavInputs down:"); for (int i = 0; i < IM_ARRAYSIZE(io.NavInputs); i++) if (io.NavInputs[i] > 0.0f) { ImGui::SameLine(); ImGui::Text("[%d] %.2f", i, io.NavInputs[i]); } + ImGui::Text("NavInputs pressed:"); for (int i = 0; i < IM_ARRAYSIZE(io.NavInputs); i++) if (io.NavInputsDownDuration[i] == 0.0f) { ImGui::SameLine(); ImGui::Text("[%d]", i); } + ImGui::Text("NavInputs duration:"); for (int i = 0; i < IM_ARRAYSIZE(io.NavInputs); i++) if (io.NavInputsDownDuration[i] >= 0.0f) { ImGui::SameLine(); ImGui::Text("[%d] %.2f", i, io.NavInputsDownDuration[i]); } + + ImGui::Button("Hovering me sets the\nkeyboard capture flag"); + if (ImGui::IsItemHovered()) + ImGui::CaptureKeyboardFromApp(true); + ImGui::SameLine(); + ImGui::Button("Holding me clears the\nthe keyboard capture flag"); + if (ImGui::IsItemActive()) + ImGui::CaptureKeyboardFromApp(false); + + ImGui::TreePop(); + } + + if (ImGui::TreeNode("Tabbing")) + { + ImGui::Text("Use TAB/SHIFT+TAB to cycle through keyboard editable fields."); + static char buf[32] = "dummy"; + ImGui::InputText("1", buf, IM_ARRAYSIZE(buf)); + ImGui::InputText("2", buf, IM_ARRAYSIZE(buf)); + ImGui::InputText("3", buf, IM_ARRAYSIZE(buf)); + ImGui::PushAllowKeyboardFocus(false); + ImGui::InputText("4 (tab skip)", buf, IM_ARRAYSIZE(buf)); + //ImGui::SameLine(); HelpMarker("Use ImGui::PushAllowKeyboardFocus(bool) to disable tabbing through certain widgets."); + ImGui::PopAllowKeyboardFocus(); + ImGui::InputText("5", buf, IM_ARRAYSIZE(buf)); + ImGui::TreePop(); + } + + if (ImGui::TreeNode("Focus from code")) + { + bool focus_1 = ImGui::Button("Focus on 1"); ImGui::SameLine(); + bool focus_2 = ImGui::Button("Focus on 2"); ImGui::SameLine(); + bool focus_3 = ImGui::Button("Focus on 3"); + int has_focus = 0; + static char buf[128] = "click on a button to set focus"; + + if (focus_1) ImGui::SetKeyboardFocusHere(); + ImGui::InputText("1", buf, IM_ARRAYSIZE(buf)); + if (ImGui::IsItemActive()) has_focus = 1; + + if (focus_2) ImGui::SetKeyboardFocusHere(); + ImGui::InputText("2", buf, IM_ARRAYSIZE(buf)); + if (ImGui::IsItemActive()) has_focus = 2; + + ImGui::PushAllowKeyboardFocus(false); + if (focus_3) ImGui::SetKeyboardFocusHere(); + ImGui::InputText("3 (tab skip)", buf, IM_ARRAYSIZE(buf)); + if (ImGui::IsItemActive()) has_focus = 3; + ImGui::PopAllowKeyboardFocus(); + + if (has_focus) + ImGui::Text("Item with focus: %d", has_focus); + else + ImGui::Text("Item with focus: "); + + // Use >= 0 parameter to SetKeyboardFocusHere() to focus an upcoming item + static float f3[3] = { 0.0f, 0.0f, 0.0f }; + int focus_ahead = -1; + if (ImGui::Button("Focus on X")) { focus_ahead = 0; } ImGui::SameLine(); + if (ImGui::Button("Focus on Y")) { focus_ahead = 1; } ImGui::SameLine(); + if (ImGui::Button("Focus on Z")) { focus_ahead = 2; } + if (focus_ahead != -1) ImGui::SetKeyboardFocusHere(focus_ahead); + ImGui::SliderFloat3("Float3", &f3[0], 0.0f, 1.0f); + + ImGui::TextWrapped("NB: Cursor & selection are preserved when refocusing last used item in code."); + ImGui::TreePop(); + } + + if (ImGui::TreeNode("Dragging")) + { + ImGui::TextWrapped("You can use ImGui::GetMouseDragDelta(0) to query for the dragged amount on any widget."); + for (int button = 0; button < 3; button++) + { + ImGui::Text("IsMouseDragging(%d):", button); + ImGui::Text(" w/ default threshold: %d,", ImGui::IsMouseDragging(button)); + ImGui::Text(" w/ zero threshold: %d,", ImGui::IsMouseDragging(button, 0.0f)); + ImGui::Text(" w/ large threshold: %d,", ImGui::IsMouseDragging(button, 20.0f)); + } + + ImGui::Button("Drag Me"); + if (ImGui::IsItemActive()) + ImGui::GetForegroundDrawList()->AddLine(io.MouseClickedPos[0], io.MousePos, ImGui::GetColorU32(ImGuiCol_Button), 4.0f); // Draw a line between the button and the mouse cursor + + // Drag operations gets "unlocked" when the mouse has moved past a certain threshold + // (the default threshold is stored in io.MouseDragThreshold). You can request a lower or higher + // threshold using the second parameter of IsMouseDragging() and GetMouseDragDelta(). + ImVec2 value_raw = ImGui::GetMouseDragDelta(0, 0.0f); + ImVec2 value_with_lock_threshold = ImGui::GetMouseDragDelta(0); + ImVec2 mouse_delta = io.MouseDelta; + ImGui::Text("GetMouseDragDelta(0):"); + ImGui::Text(" w/ default threshold: (%.1f, %.1f)", value_with_lock_threshold.x, value_with_lock_threshold.y); + ImGui::Text(" w/ zero threshold: (%.1f, %.1f)", value_raw.x, value_raw.y); + ImGui::Text("io.MouseDelta: (%.1f, %.1f)", mouse_delta.x, mouse_delta.y); + ImGui::TreePop(); + } + + if (ImGui::TreeNode("Mouse cursors")) + { + const char* mouse_cursors_names[] = { "Arrow", "TextInput", "ResizeAll", "ResizeNS", "ResizeEW", "ResizeNESW", "ResizeNWSE", "Hand", "NotAllowed" }; + IM_ASSERT(IM_ARRAYSIZE(mouse_cursors_names) == ImGuiMouseCursor_COUNT); + + ImGuiMouseCursor current = ImGui::GetMouseCursor(); + ImGui::Text("Current mouse cursor = %d: %s", current, mouse_cursors_names[current]); + ImGui::Text("Hover to see mouse cursors:"); + ImGui::SameLine(); HelpMarker( + "Your application can render a different mouse cursor based on what ImGui::GetMouseCursor() returns. " + "If software cursor rendering (io.MouseDrawCursor) is set ImGui will draw the right cursor for you, " + "otherwise your backend needs to handle it."); + for (int i = 0; i < ImGuiMouseCursor_COUNT; i++) + { + char label[32]; + sprintf(label, "Mouse cursor %d: %s", i, mouse_cursors_names[i]); + ImGui::Bullet(); ImGui::Selectable(label, false); + if (ImGui::IsItemHovered() || ImGui::IsItemFocused()) + ImGui::SetMouseCursor(i); + } + ImGui::TreePop(); + } + } +} + +//----------------------------------------------------------------------------- +// [SECTION] About Window / ShowAboutWindow() +// Access from Dear ImGui Demo -> Tools -> About +//----------------------------------------------------------------------------- + +void ImGui::ShowAboutWindow(bool* p_open) +{ + if (!ImGui::Begin("About Dear ImGui", p_open, ImGuiWindowFlags_AlwaysAutoResize)) + { + ImGui::End(); + return; + } + ImGui::Text("Dear ImGui %s", ImGui::GetVersion()); + ImGui::Separator(); + ImGui::Text("By Omar Cornut and all Dear ImGui contributors."); + ImGui::Text("Dear ImGui is licensed under the MIT License, see LICENSE for more information."); + + static bool show_config_info = false; + ImGui::Checkbox("Config/Build Information", &show_config_info); + if (show_config_info) + { + ImGuiIO& io = ImGui::GetIO(); + ImGuiStyle& style = ImGui::GetStyle(); + + bool copy_to_clipboard = ImGui::Button("Copy to clipboard"); + ImVec2 child_size = ImVec2(0, ImGui::GetTextLineHeightWithSpacing() * 18); + ImGui::BeginChildFrame(ImGui::GetID("cfg_infos"), child_size, ImGuiWindowFlags_NoMove); + if (copy_to_clipboard) + { + ImGui::LogToClipboard(); + ImGui::LogText("```\n"); // Back quotes will make text appears without formatting when pasting on GitHub + } + + ImGui::Text("Dear ImGui %s (%d)", IMGUI_VERSION, IMGUI_VERSION_NUM); + ImGui::Separator(); + ImGui::Text("sizeof(size_t): %d, sizeof(ImDrawIdx): %d, sizeof(ImDrawVert): %d", (int)sizeof(size_t), (int)sizeof(ImDrawIdx), (int)sizeof(ImDrawVert)); + ImGui::Text("define: __cplusplus=%d", (int)__cplusplus); +#ifdef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + ImGui::Text("define: IMGUI_DISABLE_OBSOLETE_FUNCTIONS"); +#endif +#ifdef IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS + ImGui::Text("define: IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS"); +#endif +#ifdef IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS + ImGui::Text("define: IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS"); +#endif +#ifdef IMGUI_DISABLE_WIN32_FUNCTIONS + ImGui::Text("define: IMGUI_DISABLE_WIN32_FUNCTIONS"); +#endif +#ifdef IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS + ImGui::Text("define: IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS"); +#endif +#ifdef IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS + ImGui::Text("define: IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS"); +#endif +#ifdef IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS + ImGui::Text("define: IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS"); +#endif +#ifdef IMGUI_DISABLE_FILE_FUNCTIONS + ImGui::Text("define: IMGUI_DISABLE_FILE_FUNCTIONS"); +#endif +#ifdef IMGUI_DISABLE_DEFAULT_ALLOCATORS + ImGui::Text("define: IMGUI_DISABLE_DEFAULT_ALLOCATORS"); +#endif +#ifdef IMGUI_USE_BGRA_PACKED_COLOR + ImGui::Text("define: IMGUI_USE_BGRA_PACKED_COLOR"); +#endif +#ifdef _WIN32 + ImGui::Text("define: _WIN32"); +#endif +#ifdef _WIN64 + ImGui::Text("define: _WIN64"); +#endif +#ifdef __linux__ + ImGui::Text("define: __linux__"); +#endif +#ifdef __APPLE__ + ImGui::Text("define: __APPLE__"); +#endif +#ifdef _MSC_VER + ImGui::Text("define: _MSC_VER=%d", _MSC_VER); +#endif +#ifdef __MINGW32__ + ImGui::Text("define: __MINGW32__"); +#endif +#ifdef __MINGW64__ + ImGui::Text("define: __MINGW64__"); +#endif +#ifdef __GNUC__ + ImGui::Text("define: __GNUC__=%d", (int)__GNUC__); +#endif +#ifdef __clang_version__ + ImGui::Text("define: __clang_version__=%s", __clang_version__); +#endif +#ifdef IMGUI_HAS_VIEWPORT + ImGui::Text("define: IMGUI_HAS_VIEWPORT"); +#endif +#ifdef IMGUI_HAS_DOCK + ImGui::Text("define: IMGUI_HAS_DOCK"); +#endif + ImGui::Separator(); + ImGui::Text("io.BackendPlatformName: %s", io.BackendPlatformName ? io.BackendPlatformName : "NULL"); + ImGui::Text("io.BackendRendererName: %s", io.BackendRendererName ? io.BackendRendererName : "NULL"); + ImGui::Text("io.ConfigFlags: 0x%08X", io.ConfigFlags); + if (io.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) ImGui::Text(" NavEnableKeyboard"); + if (io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) ImGui::Text(" NavEnableGamepad"); + if (io.ConfigFlags & ImGuiConfigFlags_NavEnableSetMousePos) ImGui::Text(" NavEnableSetMousePos"); + if (io.ConfigFlags & ImGuiConfigFlags_NavNoCaptureKeyboard) ImGui::Text(" NavNoCaptureKeyboard"); + if (io.ConfigFlags & ImGuiConfigFlags_NoMouse) ImGui::Text(" NoMouse"); + if (io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange) ImGui::Text(" NoMouseCursorChange"); + if (io.ConfigFlags & ImGuiConfigFlags_DockingEnable) ImGui::Text(" DockingEnable"); + if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) ImGui::Text(" ViewportsEnable"); + if (io.ConfigFlags & ImGuiConfigFlags_DpiEnableScaleViewports) ImGui::Text(" DpiEnableScaleViewports"); + if (io.ConfigFlags & ImGuiConfigFlags_DpiEnableScaleFonts) ImGui::Text(" DpiEnableScaleFonts"); + if (io.MouseDrawCursor) ImGui::Text("io.MouseDrawCursor"); + if (io.ConfigViewportsNoAutoMerge) ImGui::Text("io.ConfigViewportsNoAutoMerge"); + if (io.ConfigViewportsNoTaskBarIcon) ImGui::Text("io.ConfigViewportsNoTaskBarIcon"); + if (io.ConfigViewportsNoDecoration) ImGui::Text("io.ConfigViewportsNoDecoration"); + if (io.ConfigViewportsNoDefaultParent) ImGui::Text("io.ConfigViewportsNoDefaultParent"); + if (io.ConfigDockingNoSplit) ImGui::Text("io.ConfigDockingNoSplit"); + if (io.ConfigDockingWithShift) ImGui::Text("io.ConfigDockingWithShift"); + if (io.ConfigDockingAlwaysTabBar) ImGui::Text("io.ConfigDockingAlwaysTabBar"); + if (io.ConfigDockingTransparentPayload) ImGui::Text("io.ConfigDockingTransparentPayload"); + if (io.ConfigMacOSXBehaviors) ImGui::Text("io.ConfigMacOSXBehaviors"); + if (io.ConfigInputTextCursorBlink) ImGui::Text("io.ConfigInputTextCursorBlink"); + if (io.ConfigWindowsResizeFromEdges) ImGui::Text("io.ConfigWindowsResizeFromEdges"); + if (io.ConfigWindowsMoveFromTitleBarOnly) ImGui::Text("io.ConfigWindowsMoveFromTitleBarOnly"); + if (io.ConfigWindowsMemoryCompactTimer >= 0.0f) ImGui::Text("io.ConfigWindowsMemoryCompactTimer = %.1ff", io.ConfigWindowsMemoryCompactTimer); + ImGui::Text("io.BackendFlags: 0x%08X", io.BackendFlags); + if (io.BackendFlags & ImGuiBackendFlags_HasGamepad) ImGui::Text(" HasGamepad"); + if (io.BackendFlags & ImGuiBackendFlags_HasMouseCursors) ImGui::Text(" HasMouseCursors"); + if (io.BackendFlags & ImGuiBackendFlags_HasSetMousePos) ImGui::Text(" HasSetMousePos"); + if (io.BackendFlags & ImGuiBackendFlags_PlatformHasViewports) ImGui::Text(" PlatformHasViewports"); + if (io.BackendFlags & ImGuiBackendFlags_HasMouseHoveredViewport)ImGui::Text(" HasMouseHoveredViewport"); + if (io.BackendFlags & ImGuiBackendFlags_RendererHasVtxOffset) ImGui::Text(" RendererHasVtxOffset"); + if (io.BackendFlags & ImGuiBackendFlags_RendererHasViewports) ImGui::Text(" RendererHasViewports"); + ImGui::Separator(); + ImGui::Text("io.Fonts: %d fonts, Flags: 0x%08X, TexSize: %d,%d", io.Fonts->Fonts.Size, io.Fonts->Flags, io.Fonts->TexWidth, io.Fonts->TexHeight); + ImGui::Text("io.DisplaySize: %.2f,%.2f", io.DisplaySize.x, io.DisplaySize.y); + ImGui::Text("io.DisplayFramebufferScale: %.2f,%.2f", io.DisplayFramebufferScale.x, io.DisplayFramebufferScale.y); + ImGui::Separator(); + ImGui::Text("style.WindowPadding: %.2f,%.2f", style.WindowPadding.x, style.WindowPadding.y); + ImGui::Text("style.WindowBorderSize: %.2f", style.WindowBorderSize); + ImGui::Text("style.FramePadding: %.2f,%.2f", style.FramePadding.x, style.FramePadding.y); + ImGui::Text("style.FrameRounding: %.2f", style.FrameRounding); + ImGui::Text("style.FrameBorderSize: %.2f", style.FrameBorderSize); + ImGui::Text("style.ItemSpacing: %.2f,%.2f", style.ItemSpacing.x, style.ItemSpacing.y); + ImGui::Text("style.ItemInnerSpacing: %.2f,%.2f", style.ItemInnerSpacing.x, style.ItemInnerSpacing.y); + + if (copy_to_clipboard) + { + ImGui::LogText("\n```\n"); + ImGui::LogFinish(); + } + ImGui::EndChildFrame(); + } + ImGui::End(); +} + +//----------------------------------------------------------------------------- +// [SECTION] Style Editor / ShowStyleEditor() +//----------------------------------------------------------------------------- +// - ShowStyleSelector() +// - ShowFontSelector() +// - ShowStyleEditor() +//----------------------------------------------------------------------------- + +// Demo helper function to select among default colors. See ShowStyleEditor() for more advanced options. +// Here we use the simplified Combo() api that packs items into a single literal string. +// Useful for quick combo boxes where the choices are known locally. +bool ImGui::ShowStyleSelector(const char* label) +{ + static int style_idx = -1; + if (ImGui::Combo(label, &style_idx, "Classic\0Dark\0Light\0")) + { + switch (style_idx) + { + case 0: ImGui::StyleColorsClassic(); break; + case 1: ImGui::StyleColorsDark(); break; + case 2: ImGui::StyleColorsLight(); break; + } + return true; + } + return false; +} + +// Demo helper function to select among loaded fonts. +// Here we use the regular BeginCombo()/EndCombo() api which is more the more flexible one. +void ImGui::ShowFontSelector(const char* label) +{ + ImGuiIO& io = ImGui::GetIO(); + ImFont* font_current = ImGui::GetFont(); + if (ImGui::BeginCombo(label, font_current->GetDebugName())) + { + for (int n = 0; n < io.Fonts->Fonts.Size; n++) + { + ImFont* font = io.Fonts->Fonts[n]; + ImGui::PushID((void*)font); + if (ImGui::Selectable(font->GetDebugName(), font == font_current)) + io.FontDefault = font; + ImGui::PopID(); + } + ImGui::EndCombo(); + } + ImGui::SameLine(); + HelpMarker( + "- Load additional fonts with io.Fonts->AddFontFromFileTTF().\n" + "- The font atlas is built when calling io.Fonts->GetTexDataAsXXXX() or io.Fonts->Build().\n" + "- Read FAQ and docs/FONTS.txt for more details.\n" + "- If you need to add/remove fonts at runtime (e.g. for DPI change), do it before calling NewFrame()."); +} + +// [Internal] Display details for a single font, called by ShowStyleEditor(). +static void NodeFont(ImFont* font) +{ + ImGuiIO& io = ImGui::GetIO(); + ImGuiStyle& style = ImGui::GetStyle(); + bool font_details_opened = ImGui::TreeNode(font, "Font: \"%s\"\n%.2f px, %d glyphs, %d file(s)", + font->ConfigData ? font->ConfigData[0].Name : "", font->FontSize, font->Glyphs.Size, font->ConfigDataCount); + ImGui::SameLine(); if (ImGui::SmallButton("Set as default")) { io.FontDefault = font; } + if (!font_details_opened) + return; + + ImGui::PushFont(font); + ImGui::Text("The quick brown fox jumps over the lazy dog"); + ImGui::PopFont(); + ImGui::DragFloat("Font scale", &font->Scale, 0.005f, 0.3f, 2.0f, "%.1f"); // Scale only this font + ImGui::SameLine(); HelpMarker( + "Note than the default embedded font is NOT meant to be scaled.\n\n" + "Font are currently rendered into bitmaps at a given size at the time of building the atlas. " + "You may oversample them to get some flexibility with scaling. " + "You can also render at multiple sizes and select which one to use at runtime.\n\n" + "(Glimmer of hope: the atlas system will be rewritten in the future to make scaling more flexible.)"); + ImGui::InputFloat("Font offset", &font->DisplayOffset.y, 1, 1, "%.0f"); + ImGui::Text("Ascent: %f, Descent: %f, Height: %f", font->Ascent, font->Descent, font->Ascent - font->Descent); + ImGui::Text("Fallback character: '%c' (U+%04X)", font->FallbackChar, font->FallbackChar); + ImGui::Text("Ellipsis character: '%c' (U+%04X)", font->EllipsisChar, font->EllipsisChar); + const int surface_sqrt = (int)sqrtf((float)font->MetricsTotalSurface); + ImGui::Text("Texture Area: about %d px ~%dx%d px", font->MetricsTotalSurface, surface_sqrt, surface_sqrt); + for (int config_i = 0; config_i < font->ConfigDataCount; config_i++) + if (font->ConfigData) + if (const ImFontConfig* cfg = &font->ConfigData[config_i]) + ImGui::BulletText("Input %d: \'%s\', Oversample: (%d,%d), PixelSnapH: %d", + config_i, cfg->Name, cfg->OversampleH, cfg->OversampleV, cfg->PixelSnapH); + if (ImGui::TreeNode("Glyphs", "Glyphs (%d)", font->Glyphs.Size)) + { + // Display all glyphs of the fonts in separate pages of 256 characters + const ImU32 glyph_col = ImGui::GetColorU32(ImGuiCol_Text); + for (unsigned int base = 0; base <= IM_UNICODE_CODEPOINT_MAX; base += 256) + { + // Skip ahead if a large bunch of glyphs are not present in the font (test in chunks of 4k) + // This is only a small optimization to reduce the number of iterations when IM_UNICODE_MAX_CODEPOINT + // is large // (if ImWchar==ImWchar32 we will do at least about 272 queries here) + if (!(base & 4095) && font->IsGlyphRangeUnused(base, base + 4095)) + { + base += 4096 - 256; + continue; + } + + int count = 0; + for (unsigned int n = 0; n < 256; n++) + if (font->FindGlyphNoFallback((ImWchar)(base + n))) + count++; + if (count <= 0) + continue; + if (!ImGui::TreeNode((void*)(intptr_t)base, "U+%04X..U+%04X (%d %s)", base, base + 255, count, count > 1 ? "glyphs" : "glyph")) + continue; + float cell_size = font->FontSize * 1; + float cell_spacing = style.ItemSpacing.y; + ImVec2 base_pos = ImGui::GetCursorScreenPos(); + ImDrawList* draw_list = ImGui::GetWindowDrawList(); + for (unsigned int n = 0; n < 256; n++) + { + // We use ImFont::RenderChar as a shortcut because we don't have UTF-8 conversion functions + // available here and thus cannot easily generate a zero-terminated UTF-8 encoded string. + ImVec2 cell_p1(base_pos.x + (n % 16) * (cell_size + cell_spacing), base_pos.y + (n / 16) * (cell_size + cell_spacing)); + ImVec2 cell_p2(cell_p1.x + cell_size, cell_p1.y + cell_size); + const ImFontGlyph* glyph = font->FindGlyphNoFallback((ImWchar)(base + n)); + draw_list->AddRect(cell_p1, cell_p2, glyph ? IM_COL32(255, 255, 255, 100) : IM_COL32(255, 255, 255, 50)); + if (glyph) + font->RenderChar(draw_list, cell_size, cell_p1, glyph_col, (ImWchar)(base + n)); + if (glyph && ImGui::IsMouseHoveringRect(cell_p1, cell_p2)) + { + ImGui::BeginTooltip(); + ImGui::Text("Codepoint: U+%04X", base + n); + ImGui::Separator(); + ImGui::Text("Visible: %d", glyph->Visible); + ImGui::Text("AdvanceX: %.1f", glyph->AdvanceX); + ImGui::Text("Pos: (%.2f,%.2f)->(%.2f,%.2f)", glyph->X0, glyph->Y0, glyph->X1, glyph->Y1); + ImGui::Text("UV: (%.3f,%.3f)->(%.3f,%.3f)", glyph->U0, glyph->V0, glyph->U1, glyph->V1); + ImGui::EndTooltip(); + } + } + ImGui::Dummy(ImVec2((cell_size + cell_spacing) * 16, (cell_size + cell_spacing) * 16)); + ImGui::TreePop(); + } + ImGui::TreePop(); + } + ImGui::TreePop(); +} + +void ImGui::ShowStyleEditor(ImGuiStyle* ref) +{ + // You can pass in a reference ImGuiStyle structure to compare to, revert to and save to + // (without a reference style pointer, we will use one compared locally as a reference) + ImGuiStyle& style = ImGui::GetStyle(); + static ImGuiStyle ref_saved_style; + + // Default to using internal storage as reference + static bool init = true; + if (init && ref == NULL) + ref_saved_style = style; + init = false; + if (ref == NULL) + ref = &ref_saved_style; + + ImGui::PushItemWidth(ImGui::GetWindowWidth() * 0.50f); + + if (ImGui::ShowStyleSelector("Colors##Selector")) + ref_saved_style = style; + ImGui::ShowFontSelector("Fonts##Selector"); + + // Simplified Settings (expose floating-pointer border sizes as boolean representing 0.0f or 1.0f) + if (ImGui::SliderFloat("FrameRounding", &style.FrameRounding, 0.0f, 12.0f, "%.0f")) + style.GrabRounding = style.FrameRounding; // Make GrabRounding always the same value as FrameRounding + { bool border = (style.WindowBorderSize > 0.0f); if (ImGui::Checkbox("WindowBorder", &border)) { style.WindowBorderSize = border ? 1.0f : 0.0f; } } + ImGui::SameLine(); + { bool border = (style.FrameBorderSize > 0.0f); if (ImGui::Checkbox("FrameBorder", &border)) { style.FrameBorderSize = border ? 1.0f : 0.0f; } } + ImGui::SameLine(); + { bool border = (style.PopupBorderSize > 0.0f); if (ImGui::Checkbox("PopupBorder", &border)) { style.PopupBorderSize = border ? 1.0f : 0.0f; } } + + // Save/Revert button + if (ImGui::Button("Save Ref")) + *ref = ref_saved_style = style; + ImGui::SameLine(); + if (ImGui::Button("Revert Ref")) + style = *ref; + ImGui::SameLine(); + HelpMarker( + "Save/Revert in local non-persistent storage. Default Colors definition are not affected. " + "Use \"Export\" below to save them somewhere."); + + ImGui::Separator(); + + if (ImGui::BeginTabBar("##tabs", ImGuiTabBarFlags_None)) + { + if (ImGui::BeginTabItem("Sizes")) + { + ImGui::Text("Main"); + ImGui::SliderFloat2("WindowPadding", (float*)&style.WindowPadding, 0.0f, 20.0f, "%.0f"); + ImGui::SliderFloat2("FramePadding", (float*)&style.FramePadding, 0.0f, 20.0f, "%.0f"); + ImGui::SliderFloat2("ItemSpacing", (float*)&style.ItemSpacing, 0.0f, 20.0f, "%.0f"); + ImGui::SliderFloat2("ItemInnerSpacing", (float*)&style.ItemInnerSpacing, 0.0f, 20.0f, "%.0f"); + ImGui::SliderFloat2("TouchExtraPadding", (float*)&style.TouchExtraPadding, 0.0f, 10.0f, "%.0f"); + ImGui::SliderFloat("IndentSpacing", &style.IndentSpacing, 0.0f, 30.0f, "%.0f"); + ImGui::SliderFloat("ScrollbarSize", &style.ScrollbarSize, 1.0f, 20.0f, "%.0f"); + ImGui::SliderFloat("GrabMinSize", &style.GrabMinSize, 1.0f, 20.0f, "%.0f"); + ImGui::Text("Borders"); + ImGui::SliderFloat("WindowBorderSize", &style.WindowBorderSize, 0.0f, 1.0f, "%.0f"); + ImGui::SliderFloat("ChildBorderSize", &style.ChildBorderSize, 0.0f, 1.0f, "%.0f"); + ImGui::SliderFloat("PopupBorderSize", &style.PopupBorderSize, 0.0f, 1.0f, "%.0f"); + ImGui::SliderFloat("FrameBorderSize", &style.FrameBorderSize, 0.0f, 1.0f, "%.0f"); + ImGui::SliderFloat("TabBorderSize", &style.TabBorderSize, 0.0f, 1.0f, "%.0f"); + ImGui::Text("Rounding"); + ImGui::SliderFloat("WindowRounding", &style.WindowRounding, 0.0f, 12.0f, "%.0f"); + ImGui::SliderFloat("ChildRounding", &style.ChildRounding, 0.0f, 12.0f, "%.0f"); + ImGui::SliderFloat("FrameRounding", &style.FrameRounding, 0.0f, 12.0f, "%.0f"); + ImGui::SliderFloat("PopupRounding", &style.PopupRounding, 0.0f, 12.0f, "%.0f"); + ImGui::SliderFloat("ScrollbarRounding", &style.ScrollbarRounding, 0.0f, 12.0f, "%.0f"); + ImGui::SliderFloat("GrabRounding", &style.GrabRounding, 0.0f, 12.0f, "%.0f"); + ImGui::SliderFloat("TabRounding", &style.TabRounding, 0.0f, 12.0f, "%.0f"); + ImGui::Text("Alignment"); + ImGui::SliderFloat2("WindowTitleAlign", (float*)&style.WindowTitleAlign, 0.0f, 1.0f, "%.2f"); + int window_menu_button_position = style.WindowMenuButtonPosition + 1; + if (ImGui::Combo("WindowMenuButtonPosition", (int*)&window_menu_button_position, "None\0Left\0Right\0")) + style.WindowMenuButtonPosition = window_menu_button_position - 1; + ImGui::Combo("ColorButtonPosition", (int*)&style.ColorButtonPosition, "Left\0Right\0"); + ImGui::SliderFloat2("ButtonTextAlign", (float*)&style.ButtonTextAlign, 0.0f, 1.0f, "%.2f"); + ImGui::SameLine(); HelpMarker("Alignment applies when a button is larger than its text content."); + ImGui::SliderFloat2("SelectableTextAlign", (float*)&style.SelectableTextAlign, 0.0f, 1.0f, "%.2f"); + ImGui::SameLine(); HelpMarker("Alignment applies when a selectable is larger than its text content."); + ImGui::Text("Safe Area Padding"); + ImGui::SameLine(); HelpMarker("Adjust if you cannot see the edges of your screen (e.g. on a TV where scaling has not been configured)."); + ImGui::SliderFloat2("DisplaySafeAreaPadding", (float*)&style.DisplaySafeAreaPadding, 0.0f, 30.0f, "%.0f"); + ImGui::EndTabItem(); + } + + if (ImGui::BeginTabItem("Colors")) + { + static int output_dest = 0; + static bool output_only_modified = true; + if (ImGui::Button("Export")) + { + if (output_dest == 0) + ImGui::LogToClipboard(); + else + ImGui::LogToTTY(); + ImGui::LogText("ImVec4* colors = ImGui::GetStyle().Colors;" IM_NEWLINE); + for (int i = 0; i < ImGuiCol_COUNT; i++) + { + const ImVec4& col = style.Colors[i]; + const char* name = ImGui::GetStyleColorName(i); + if (!output_only_modified || memcmp(&col, &ref->Colors[i], sizeof(ImVec4)) != 0) + ImGui::LogText("colors[ImGuiCol_%s]%*s= ImVec4(%.2ff, %.2ff, %.2ff, %.2ff);" IM_NEWLINE, + name, 23 - (int)strlen(name), "", col.x, col.y, col.z, col.w); + } + ImGui::LogFinish(); + } + ImGui::SameLine(); ImGui::SetNextItemWidth(120); ImGui::Combo("##output_type", &output_dest, "To Clipboard\0To TTY\0"); + ImGui::SameLine(); ImGui::Checkbox("Only Modified Colors", &output_only_modified); + + static ImGuiTextFilter filter; + filter.Draw("Filter colors", ImGui::GetFontSize() * 16); + + static ImGuiColorEditFlags alpha_flags = 0; + if (ImGui::RadioButton("Opaque", alpha_flags == ImGuiColorEditFlags_None)) { alpha_flags = ImGuiColorEditFlags_None; } ImGui::SameLine(); + if (ImGui::RadioButton("Alpha", alpha_flags == ImGuiColorEditFlags_AlphaPreview)) { alpha_flags = ImGuiColorEditFlags_AlphaPreview; } ImGui::SameLine(); + if (ImGui::RadioButton("Both", alpha_flags == ImGuiColorEditFlags_AlphaPreviewHalf)) { alpha_flags = ImGuiColorEditFlags_AlphaPreviewHalf; } ImGui::SameLine(); + HelpMarker( + "In the color list:\n" + "Left-click on colored square to open color picker,\n" + "Right-click to open edit options menu."); + + ImGui::BeginChild("##colors", ImVec2(0, 0), true, ImGuiWindowFlags_AlwaysVerticalScrollbar | ImGuiWindowFlags_AlwaysHorizontalScrollbar | ImGuiWindowFlags_NavFlattened); + ImGui::PushItemWidth(-160); + for (int i = 0; i < ImGuiCol_COUNT; i++) + { + const char* name = ImGui::GetStyleColorName(i); + if (!filter.PassFilter(name)) + continue; + ImGui::PushID(i); + ImGui::ColorEdit4("##color", (float*)&style.Colors[i], ImGuiColorEditFlags_AlphaBar | alpha_flags); + if (memcmp(&style.Colors[i], &ref->Colors[i], sizeof(ImVec4)) != 0) + { + // Tips: in a real user application, you may want to merge and use an icon font into the main font, + // so instead of "Save"/"Revert" you'd use icons! + // Read the FAQ and docs/FONTS.txt about using icon fonts. It's really easy and super convenient! + ImGui::SameLine(0.0f, style.ItemInnerSpacing.x); if (ImGui::Button("Save")) { ref->Colors[i] = style.Colors[i]; } + ImGui::SameLine(0.0f, style.ItemInnerSpacing.x); if (ImGui::Button("Revert")) { style.Colors[i] = ref->Colors[i]; } + } + ImGui::SameLine(0.0f, style.ItemInnerSpacing.x); + ImGui::TextUnformatted(name); + ImGui::PopID(); + } + ImGui::PopItemWidth(); + ImGui::EndChild(); + + ImGui::EndTabItem(); + } + + if (ImGui::BeginTabItem("Fonts")) + { + ImGuiIO& io = ImGui::GetIO(); + ImFontAtlas* atlas = io.Fonts; + HelpMarker("Read FAQ and docs/FONTS.txt for details on font loading."); + ImGui::PushItemWidth(120); + for (int i = 0; i < atlas->Fonts.Size; i++) + { + ImFont* font = atlas->Fonts[i]; + ImGui::PushID(font); + NodeFont(font); + ImGui::PopID(); + } + if (ImGui::TreeNode("Atlas texture", "Atlas texture (%dx%d pixels)", atlas->TexWidth, atlas->TexHeight)) + { + ImVec4 tint_col = ImVec4(1.0f, 1.0f, 1.0f, 1.0f); + ImVec4 border_col = ImVec4(1.0f, 1.0f, 1.0f, 0.5f); + ImGui::Image(atlas->TexID, ImVec2((float)atlas->TexWidth, (float)atlas->TexHeight), ImVec2(0, 0), ImVec2(1, 1), tint_col, border_col); + ImGui::TreePop(); + } + + // Post-baking font scaling. Note that this is NOT the nice way of scaling fonts, read below. + // (we enforce hard clamping manually as by default DragFloat/SliderFloat allows CTRL+Click text to get out of bounds). + const float MIN_SCALE = 0.3f; + const float MAX_SCALE = 2.0f; + HelpMarker( + "Those are old settings provided for convenience.\n" + "However, the _correct_ way of scaling your UI is currently to reload your font at the designed size, " + "rebuild the font atlas, and call style.ScaleAllSizes() on a reference ImGuiStyle structure.\n" + "Using those settings here will give you poor quality results."); + static float window_scale = 1.0f; + if (ImGui::DragFloat("window scale", &window_scale, 0.005f, MIN_SCALE, MAX_SCALE, "%.2f")) // Scale only this window + ImGui::SetWindowFontScale(IM_MAX(window_scale, MIN_SCALE)); + if (ImGui::DragFloat("global scale", &io.FontGlobalScale, 0.005f, MIN_SCALE, MAX_SCALE, "%.2f")) // Scale everything + io.FontGlobalScale = IM_MAX(io.FontGlobalScale, MIN_SCALE); + ImGui::PopItemWidth(); + + ImGui::EndTabItem(); + } + + if (ImGui::BeginTabItem("Rendering")) + { + ImGui::Checkbox("Anti-aliased lines", &style.AntiAliasedLines); + ImGui::SameLine(); HelpMarker("When disabling anti-aliasing lines, you'll probably want to disable borders in your style as well."); + ImGui::Checkbox("Anti-aliased fill", &style.AntiAliasedFill); + ImGui::PushItemWidth(100); + ImGui::DragFloat("Curve Tessellation Tolerance", &style.CurveTessellationTol, 0.02f, 0.10f, 10.0f, "%.2f"); + if (style.CurveTessellationTol < 0.10f) style.CurveTessellationTol = 0.10f; + ImGui::DragFloat("Circle segment Max Error", &style.CircleSegmentMaxError, 0.01f, 0.10f, 10.0f, "%.2f"); + ImGui::DragFloat("Global Alpha", &style.Alpha, 0.005f, 0.20f, 1.0f, "%.2f"); // Not exposing zero here so user doesn't "lose" the UI (zero alpha clips all widgets). But application code could have a toggle to switch between zero and non-zero. + ImGui::PopItemWidth(); + + ImGui::EndTabItem(); + } + + ImGui::EndTabBar(); + } + + ImGui::PopItemWidth(); +} + +//----------------------------------------------------------------------------- +// [SECTION] Example App: Main Menu Bar / ShowExampleAppMainMenuBar() +//----------------------------------------------------------------------------- +// - ShowExampleAppMainMenuBar() +// - ShowExampleMenuFile() +//----------------------------------------------------------------------------- + +// Demonstrate creating a "main" fullscreen menu bar and populating it. +// Note the difference between BeginMainMenuBar() and BeginMenuBar(): +// - BeginMenuBar() = menu-bar inside current window (which needs the ImGuiWindowFlags_MenuBar flag!) +// - BeginMainMenuBar() = helper to create menu-bar-sized window at the top of the main viewport + call BeginMenuBar() into it. +static void ShowExampleAppMainMenuBar() +{ + if (ImGui::BeginMainMenuBar()) + { + if (ImGui::BeginMenu("File")) + { + ShowExampleMenuFile(); + ImGui::EndMenu(); + } + if (ImGui::BeginMenu("Edit")) + { + if (ImGui::MenuItem("Undo", "CTRL+Z")) {} + if (ImGui::MenuItem("Redo", "CTRL+Y", false, false)) {} // Disabled item + ImGui::Separator(); + if (ImGui::MenuItem("Cut", "CTRL+X")) {} + if (ImGui::MenuItem("Copy", "CTRL+C")) {} + if (ImGui::MenuItem("Paste", "CTRL+V")) {} + ImGui::EndMenu(); + } + ImGui::EndMainMenuBar(); + } +} + +// Note that shortcuts are currently provided for display only +// (future version will add explicit flags to BeginMenu() to request processing shortcuts) +static void ShowExampleMenuFile() +{ + ImGui::MenuItem("(dummy menu)", NULL, false, false); + if (ImGui::MenuItem("New")) {} + if (ImGui::MenuItem("Open", "Ctrl+O")) {} + if (ImGui::BeginMenu("Open Recent")) + { + ImGui::MenuItem("fish_hat.c"); + ImGui::MenuItem("fish_hat.inl"); + ImGui::MenuItem("fish_hat.h"); + if (ImGui::BeginMenu("More..")) + { + ImGui::MenuItem("Hello"); + ImGui::MenuItem("Sailor"); + if (ImGui::BeginMenu("Recurse..")) + { + ShowExampleMenuFile(); + ImGui::EndMenu(); + } + ImGui::EndMenu(); + } + ImGui::EndMenu(); + } + if (ImGui::MenuItem("Save", "Ctrl+S")) {} + if (ImGui::MenuItem("Save As..")) {} + + ImGui::Separator(); + if (ImGui::BeginMenu("Options")) + { + static bool enabled = true; + ImGui::MenuItem("Enabled", "", &enabled); + ImGui::BeginChild("child", ImVec2(0, 60), true); + for (int i = 0; i < 10; i++) + ImGui::Text("Scrolling Text %d", i); + ImGui::EndChild(); + static float f = 0.5f; + static int n = 0; + ImGui::SliderFloat("Value", &f, 0.0f, 1.0f); + ImGui::InputFloat("Input", &f, 0.1f); + ImGui::Combo("Combo", &n, "Yes\0No\0Maybe\0\0"); + ImGui::EndMenu(); + } + + if (ImGui::BeginMenu("Colors")) + { + float sz = ImGui::GetTextLineHeight(); + for (int i = 0; i < ImGuiCol_COUNT; i++) + { + const char* name = ImGui::GetStyleColorName((ImGuiCol)i); + ImVec2 p = ImGui::GetCursorScreenPos(); + ImGui::GetWindowDrawList()->AddRectFilled(p, ImVec2(p.x+sz, p.y+sz), ImGui::GetColorU32((ImGuiCol)i)); + ImGui::Dummy(ImVec2(sz, sz)); + ImGui::SameLine(); + ImGui::MenuItem(name); + } + ImGui::EndMenu(); + } + + // Here we demonstrate appending again to the "Options" menu (which we already created above) + // Of course in this demo it is a little bit silly that this function calls BeginMenu("Options") twice. + // In a real code-base using it would make senses to use this feature from very different code locations. + if (ImGui::BeginMenu("Options")) // <-- Append! + { + static bool b = true; + ImGui::Checkbox("SomeOption", &b); + ImGui::EndMenu(); + } + + if (ImGui::BeginMenu("Disabled", false)) // Disabled + { + IM_ASSERT(0); + } + if (ImGui::MenuItem("Checked", NULL, true)) {} + if (ImGui::MenuItem("Quit", "Alt+F4")) {} +} + +//----------------------------------------------------------------------------- +// [SECTION] Example App: Debug Console / ShowExampleAppConsole() +//----------------------------------------------------------------------------- + +// Demonstrate creating a simple console window, with scrolling, filtering, completion and history. +// For the console example, we are using a more C++ like approach of declaring a class to hold both data and functions. +struct ExampleAppConsole +{ + char InputBuf[256]; + ImVector Items; + ImVector Commands; + ImVector History; + int HistoryPos; // -1: new line, 0..History.Size-1 browsing history. + ImGuiTextFilter Filter; + bool AutoScroll; + bool ScrollToBottom; + + ExampleAppConsole() + { + ClearLog(); + memset(InputBuf, 0, sizeof(InputBuf)); + HistoryPos = -1; + + // "CLASSIFY" is here to provide the test case where "C"+[tab] completes to "CL" and display multiple matches. + Commands.push_back("HELP"); + Commands.push_back("HISTORY"); + Commands.push_back("CLEAR"); + Commands.push_back("CLASSIFY"); + AutoScroll = true; + ScrollToBottom = false; + AddLog("Welcome to Dear ImGui!"); + } + ~ExampleAppConsole() + { + ClearLog(); + for (int i = 0; i < History.Size; i++) + free(History[i]); + } + + // Portable helpers + static int Stricmp(const char* s1, const char* s2) { int d; while ((d = toupper(*s2) - toupper(*s1)) == 0 && *s1) { s1++; s2++; } return d; } + static int Strnicmp(const char* s1, const char* s2, int n) { int d = 0; while (n > 0 && (d = toupper(*s2) - toupper(*s1)) == 0 && *s1) { s1++; s2++; n--; } return d; } + static char* Strdup(const char* s) { size_t len = strlen(s) + 1; void* buf = malloc(len); IM_ASSERT(buf); return (char*)memcpy(buf, (const void*)s, len); } + static void Strtrim(char* s) { char* str_end = s + strlen(s); while (str_end > s && str_end[-1] == ' ') str_end--; *str_end = 0; } + + void ClearLog() + { + for (int i = 0; i < Items.Size; i++) + free(Items[i]); + Items.clear(); + } + + void AddLog(const char* fmt, ...) IM_FMTARGS(2) + { + // FIXME-OPT + char buf[1024]; + va_list args; + va_start(args, fmt); + vsnprintf(buf, IM_ARRAYSIZE(buf), fmt, args); + buf[IM_ARRAYSIZE(buf)-1] = 0; + va_end(args); + Items.push_back(Strdup(buf)); + } + + void Draw(const char* title, bool* p_open) + { + ImGui::SetNextWindowSize(ImVec2(520,600), ImGuiCond_FirstUseEver); + if (!ImGui::Begin(title, p_open)) + { + ImGui::End(); + return; + } + + // As a specific feature guaranteed by the library, after calling Begin() the last Item represent the title bar. + // So e.g. IsItemHovered() will return true when hovering the title bar. + // Here we create a context menu only available from the title bar. + if (ImGui::BeginPopupContextItem()) + { + if (ImGui::MenuItem("Close Console")) + *p_open = false; + ImGui::EndPopup(); + } + + ImGui::TextWrapped( + "This example implements a console with basic coloring, completion and history. A more elaborate " + "implementation may want to store entries along with extra data such as timestamp, emitter, etc."); + ImGui::TextWrapped("Enter 'HELP' for help, press TAB to use text completion."); + + // TODO: display items starting from the bottom + + if (ImGui::SmallButton("Add Dummy Text")) { AddLog("%d some text", Items.Size); AddLog("some more text"); AddLog("display very important message here!"); } ImGui::SameLine(); + if (ImGui::SmallButton("Add Dummy Error")) { AddLog("[error] something went wrong"); } ImGui::SameLine(); + if (ImGui::SmallButton("Clear")) { ClearLog(); } ImGui::SameLine(); + bool copy_to_clipboard = ImGui::SmallButton("Copy"); + //static float t = 0.0f; if (ImGui::GetTime() - t > 0.02f) { t = ImGui::GetTime(); AddLog("Spam %f", t); } + + ImGui::Separator(); + + // Options menu + if (ImGui::BeginPopup("Options")) + { + ImGui::Checkbox("Auto-scroll", &AutoScroll); + ImGui::EndPopup(); + } + + // Options, Filter + if (ImGui::Button("Options")) + ImGui::OpenPopup("Options"); + ImGui::SameLine(); + Filter.Draw("Filter (\"incl,-excl\") (\"error\")", 180); + ImGui::Separator(); + + // Reserve enough left-over height for 1 separator + 1 input text + const float footer_height_to_reserve = ImGui::GetStyle().ItemSpacing.y + ImGui::GetFrameHeightWithSpacing(); + ImGui::BeginChild("ScrollingRegion", ImVec2(0, -footer_height_to_reserve), false, ImGuiWindowFlags_HorizontalScrollbar); + if (ImGui::BeginPopupContextWindow()) + { + if (ImGui::Selectable("Clear")) ClearLog(); + ImGui::EndPopup(); + } + + // Display every line as a separate entry so we can change their color or add custom widgets. + // If you only want raw text you can use ImGui::TextUnformatted(log.begin(), log.end()); + // NB- if you have thousands of entries this approach may be too inefficient and may require user-side clipping + // to only process visible items. The clipper will automatically measure the height of your first item and then + // "seek" to display only items in the visible area. + // To use the clipper we can replace your standard loop: + // for (int i = 0; i < Items.Size; i++) + // With: + // ImGuiListClipper clipper(Items.Size); + // while (clipper.Step()) + // for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) + // - That your items are evenly spaced (same height) + // - That you have cheap random access to your elements (you can access them given their index, + // without processing all the ones before) + // You cannot this code as-is if a filter is active because it breaks the 'cheap random-access' property. + // We would need random-access on the post-filtered list. + // A typical application wanting coarse clipping and filtering may want to pre-compute an array of indices + // or offsets of items that passed the filtering test, recomputing this array when user changes the filter, + // and appending newly elements as they are inserted. This is left as a task to the user until we can manage + // to improve this example code! + // If your items are of variable height: + // - Split them into same height items would be simpler and facilitate random-seeking into your list. + // - Consider using manual call to IsRectVisible() and skipping extraneous decoration from your items. + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(4,1)); // Tighten spacing + if (copy_to_clipboard) + ImGui::LogToClipboard(); + for (int i = 0; i < Items.Size; i++) + { + const char* item = Items[i]; + if (!Filter.PassFilter(item)) + continue; + + // Normally you would store more information in your item than just a string. + // (e.g. make Items[] an array of structure, store color/type etc.) + ImVec4 color; + bool has_color = false; + if (strstr(item, "[error]")) { color = ImVec4(1.0f, 0.4f, 0.4f, 1.0f); has_color = true; } + else if (strncmp(item, "# ", 2) == 0) { color = ImVec4(1.0f, 0.8f, 0.6f, 1.0f); has_color = true; } + if (has_color) + ImGui::PushStyleColor(ImGuiCol_Text, color); + ImGui::TextUnformatted(item); + if (has_color) + ImGui::PopStyleColor(); + } + if (copy_to_clipboard) + ImGui::LogFinish(); + + if (ScrollToBottom || (AutoScroll && ImGui::GetScrollY() >= ImGui::GetScrollMaxY())) + ImGui::SetScrollHereY(1.0f); + ScrollToBottom = false; + + ImGui::PopStyleVar(); + ImGui::EndChild(); + ImGui::Separator(); + + // Command-line + bool reclaim_focus = false; + ImGuiInputTextFlags input_text_flags = ImGuiInputTextFlags_EnterReturnsTrue | ImGuiInputTextFlags_CallbackCompletion | ImGuiInputTextFlags_CallbackHistory; + if (ImGui::InputText("Input", InputBuf, IM_ARRAYSIZE(InputBuf), input_text_flags, &TextEditCallbackStub, (void*)this)) + { + char* s = InputBuf; + Strtrim(s); + if (s[0]) + ExecCommand(s); + strcpy(s, ""); + reclaim_focus = true; + } + + // Auto-focus on window apparition + ImGui::SetItemDefaultFocus(); + if (reclaim_focus) + ImGui::SetKeyboardFocusHere(-1); // Auto focus previous widget + + ImGui::End(); + } + + void ExecCommand(const char* command_line) + { + AddLog("# %s\n", command_line); + + // Insert into history. First find match and delete it so it can be pushed to the back. + // This isn't trying to be smart or optimal. + HistoryPos = -1; + for (int i = History.Size-1; i >= 0; i--) + if (Stricmp(History[i], command_line) == 0) + { + free(History[i]); + History.erase(History.begin() + i); + break; + } + History.push_back(Strdup(command_line)); + + // Process command + if (Stricmp(command_line, "CLEAR") == 0) + { + ClearLog(); + } + else if (Stricmp(command_line, "HELP") == 0) + { + AddLog("Commands:"); + for (int i = 0; i < Commands.Size; i++) + AddLog("- %s", Commands[i]); + } + else if (Stricmp(command_line, "HISTORY") == 0) + { + int first = History.Size - 10; + for (int i = first > 0 ? first : 0; i < History.Size; i++) + AddLog("%3d: %s\n", i, History[i]); + } + else + { + AddLog("Unknown command: '%s'\n", command_line); + } + + // On command input, we scroll to bottom even if AutoScroll==false + ScrollToBottom = true; + } + + // In C++11 you'd be better off using lambdas for this sort of forwarding callbacks + static int TextEditCallbackStub(ImGuiInputTextCallbackData* data) + { + ExampleAppConsole* console = (ExampleAppConsole*)data->UserData; + return console->TextEditCallback(data); + } + + int TextEditCallback(ImGuiInputTextCallbackData* data) + { + //AddLog("cursor: %d, selection: %d-%d", data->CursorPos, data->SelectionStart, data->SelectionEnd); + switch (data->EventFlag) + { + case ImGuiInputTextFlags_CallbackCompletion: + { + // Example of TEXT COMPLETION + + // Locate beginning of current word + const char* word_end = data->Buf + data->CursorPos; + const char* word_start = word_end; + while (word_start > data->Buf) + { + const char c = word_start[-1]; + if (c == ' ' || c == '\t' || c == ',' || c == ';') + break; + word_start--; + } + + // Build a list of candidates + ImVector candidates; + for (int i = 0; i < Commands.Size; i++) + if (Strnicmp(Commands[i], word_start, (int)(word_end-word_start)) == 0) + candidates.push_back(Commands[i]); + + if (candidates.Size == 0) + { + // No match + AddLog("No match for \"%.*s\"!\n", (int)(word_end-word_start), word_start); + } + else if (candidates.Size == 1) + { + // Single match. Delete the beginning of the word and replace it entirely so we've got nice casing. + data->DeleteChars((int)(word_start-data->Buf), (int)(word_end-word_start)); + data->InsertChars(data->CursorPos, candidates[0]); + data->InsertChars(data->CursorPos, " "); + } + else + { + // Multiple matches. Complete as much as we can.. + // So inputing "C"+Tab will complete to "CL" then display "CLEAR" and "CLASSIFY" as matches. + int match_len = (int)(word_end - word_start); + for (;;) + { + int c = 0; + bool all_candidates_matches = true; + for (int i = 0; i < candidates.Size && all_candidates_matches; i++) + if (i == 0) + c = toupper(candidates[i][match_len]); + else if (c == 0 || c != toupper(candidates[i][match_len])) + all_candidates_matches = false; + if (!all_candidates_matches) + break; + match_len++; + } + + if (match_len > 0) + { + data->DeleteChars((int)(word_start - data->Buf), (int)(word_end-word_start)); + data->InsertChars(data->CursorPos, candidates[0], candidates[0] + match_len); + } + + // List matches + AddLog("Possible matches:\n"); + for (int i = 0; i < candidates.Size; i++) + AddLog("- %s\n", candidates[i]); + } + + break; + } + case ImGuiInputTextFlags_CallbackHistory: + { + // Example of HISTORY + const int prev_history_pos = HistoryPos; + if (data->EventKey == ImGuiKey_UpArrow) + { + if (HistoryPos == -1) + HistoryPos = History.Size - 1; + else if (HistoryPos > 0) + HistoryPos--; + } + else if (data->EventKey == ImGuiKey_DownArrow) + { + if (HistoryPos != -1) + if (++HistoryPos >= History.Size) + HistoryPos = -1; + } + + // A better implementation would preserve the data on the current input line along with cursor position. + if (prev_history_pos != HistoryPos) + { + const char* history_str = (HistoryPos >= 0) ? History[HistoryPos] : ""; + data->DeleteChars(0, data->BufTextLen); + data->InsertChars(0, history_str); + } + } + } + return 0; + } +}; + +static void ShowExampleAppConsole(bool* p_open) +{ + static ExampleAppConsole console; + console.Draw("Example: Console", p_open); +} + +//----------------------------------------------------------------------------- +// [SECTION] Example App: Debug Log / ShowExampleAppLog() +//----------------------------------------------------------------------------- + +// Usage: +// static ExampleAppLog my_log; +// my_log.AddLog("Hello %d world\n", 123); +// my_log.Draw("title"); +struct ExampleAppLog +{ + ImGuiTextBuffer Buf; + ImGuiTextFilter Filter; + ImVector LineOffsets; // Index to lines offset. We maintain this with AddLog() calls. + bool AutoScroll; // Keep scrolling if already at the bottom. + + ExampleAppLog() + { + AutoScroll = true; + Clear(); + } + + void Clear() + { + Buf.clear(); + LineOffsets.clear(); + LineOffsets.push_back(0); + } + + void AddLog(const char* fmt, ...) IM_FMTARGS(2) + { + int old_size = Buf.size(); + va_list args; + va_start(args, fmt); + Buf.appendfv(fmt, args); + va_end(args); + for (int new_size = Buf.size(); old_size < new_size; old_size++) + if (Buf[old_size] == '\n') + LineOffsets.push_back(old_size + 1); + } + + void Draw(const char* title, bool* p_open = NULL) + { + if (!ImGui::Begin(title, p_open)) + { + ImGui::End(); + return; + } + + // Options menu + if (ImGui::BeginPopup("Options")) + { + ImGui::Checkbox("Auto-scroll", &AutoScroll); + ImGui::EndPopup(); + } + + // Main window + if (ImGui::Button("Options")) + ImGui::OpenPopup("Options"); + ImGui::SameLine(); + bool clear = ImGui::Button("Clear"); + ImGui::SameLine(); + bool copy = ImGui::Button("Copy"); + ImGui::SameLine(); + Filter.Draw("Filter", -100.0f); + + ImGui::Separator(); + ImGui::BeginChild("scrolling", ImVec2(0,0), false, ImGuiWindowFlags_HorizontalScrollbar); + + if (clear) + Clear(); + if (copy) + ImGui::LogToClipboard(); + + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0)); + const char* buf = Buf.begin(); + const char* buf_end = Buf.end(); + if (Filter.IsActive()) + { + // In this example we don't use the clipper when Filter is enabled. + // This is because we don't have a random access on the result on our filter. + // A real application processing logs with ten of thousands of entries may want to store the result of + // search/filter.. especially if the filtering function is not trivial (e.g. reg-exp). + for (int line_no = 0; line_no < LineOffsets.Size; line_no++) + { + const char* line_start = buf + LineOffsets[line_no]; + const char* line_end = (line_no + 1 < LineOffsets.Size) ? (buf + LineOffsets[line_no + 1] - 1) : buf_end; + if (Filter.PassFilter(line_start, line_end)) + ImGui::TextUnformatted(line_start, line_end); + } + } + else + { + // The simplest and easy way to display the entire buffer: + // ImGui::TextUnformatted(buf_begin, buf_end); + // And it'll just work. TextUnformatted() has specialization for large blob of text and will fast-forward + // to skip non-visible lines. Here we instead demonstrate using the clipper to only process lines that are + // within the visible area. + // If you have tens of thousands of items and their processing cost is non-negligible, coarse clipping them + // on your side is recommended. Using ImGuiListClipper requires + // - A) random access into your data + // - B) items all being the same height, + // both of which we can handle since we an array pointing to the beginning of each line of text. + // When using the filter (in the block of code above) we don't have random access into the data to display + // anymore, which is why we don't use the clipper. Storing or skimming through the search result would make + // it possible (and would be recommended if you want to search through tens of thousands of entries). + ImGuiListClipper clipper; + clipper.Begin(LineOffsets.Size); + while (clipper.Step()) + { + for (int line_no = clipper.DisplayStart; line_no < clipper.DisplayEnd; line_no++) + { + const char* line_start = buf + LineOffsets[line_no]; + const char* line_end = (line_no + 1 < LineOffsets.Size) ? (buf + LineOffsets[line_no + 1] - 1) : buf_end; + ImGui::TextUnformatted(line_start, line_end); + } + } + clipper.End(); + } + ImGui::PopStyleVar(); + + if (AutoScroll && ImGui::GetScrollY() >= ImGui::GetScrollMaxY()) + ImGui::SetScrollHereY(1.0f); + + ImGui::EndChild(); + ImGui::End(); + } +}; + +// Demonstrate creating a simple log window with basic filtering. +static void ShowExampleAppLog(bool* p_open) +{ + static ExampleAppLog log; + + // For the demo: add a debug button _BEFORE_ the normal log window contents + // We take advantage of a rarely used feature: multiple calls to Begin()/End() are appending to the _same_ window. + // Most of the contents of the window will be added by the log.Draw() call. + ImGui::SetNextWindowSize(ImVec2(500, 400), ImGuiCond_FirstUseEver); + ImGui::Begin("Example: Log", p_open); + if (ImGui::SmallButton("[Debug] Add 5 entries")) + { + static int counter = 0; + const char* categories[3] = { "info", "warn", "error" }; + const char* words[] = { "Bumfuzzled", "Cattywampus", "Snickersnee", "Abibliophobia", "Absquatulate", "Nincompoop", "Pauciloquent" }; + for (int n = 0; n < 5; n++) + { + const char* category = categories[counter % IM_ARRAYSIZE(categories)]; + const char* word = words[counter % IM_ARRAYSIZE(words)]; + log.AddLog("[%05d] [%s] Hello, current time is %.1f, here's a word: '%s'\n", + ImGui::GetFrameCount(), category, ImGui::GetTime(), word); + counter++; + } + } + ImGui::End(); + + // Actually call in the regular Log helper (which will Begin() into the same window as we just did) + log.Draw("Example: Log", p_open); +} + +//----------------------------------------------------------------------------- +// [SECTION] Example App: Simple Layout / ShowExampleAppLayout() +//----------------------------------------------------------------------------- + +// Demonstrate create a window with multiple child windows. +static void ShowExampleAppLayout(bool* p_open) +{ + ImGui::SetNextWindowSize(ImVec2(500, 440), ImGuiCond_FirstUseEver); + if (ImGui::Begin("Example: Simple layout", p_open, ImGuiWindowFlags_MenuBar)) + { + if (ImGui::BeginMenuBar()) + { + if (ImGui::BeginMenu("File")) + { + if (ImGui::MenuItem("Close")) *p_open = false; + ImGui::EndMenu(); + } + ImGui::EndMenuBar(); + } + + // Left + static int selected = 0; + { + ImGui::BeginChild("left pane", ImVec2(150, 0), true); + for (int i = 0; i < 100; i++) + { + char label[128]; + sprintf(label, "MyObject %d", i); + if (ImGui::Selectable(label, selected == i)) + selected = i; + } + ImGui::EndChild(); + } + ImGui::SameLine(); + + // Right + { + ImGui::BeginGroup(); + ImGui::BeginChild("item view", ImVec2(0, -ImGui::GetFrameHeightWithSpacing())); // Leave room for 1 line below us + ImGui::Text("MyObject: %d", selected); + ImGui::Separator(); + if (ImGui::BeginTabBar("##Tabs", ImGuiTabBarFlags_None)) + { + if (ImGui::BeginTabItem("Description")) + { + ImGui::TextWrapped("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. "); + ImGui::EndTabItem(); + } + if (ImGui::BeginTabItem("Details")) + { + ImGui::Text("ID: 0123456789"); + ImGui::EndTabItem(); + } + ImGui::EndTabBar(); + } + ImGui::EndChild(); + if (ImGui::Button("Revert")) {} + ImGui::SameLine(); + if (ImGui::Button("Save")) {} + ImGui::EndGroup(); + } + } + ImGui::End(); +} + +//----------------------------------------------------------------------------- +// [SECTION] Example App: Property Editor / ShowExampleAppPropertyEditor() +//----------------------------------------------------------------------------- + +static void ShowDummyObject(const char* prefix, int uid) +{ + // Use object uid as identifier. Most commonly you could also use the object pointer as a base ID. + ImGui::PushID(uid); + ImGui::AlignTextToFramePadding(); // Text and Tree nodes are less high than framed widgets, here we add vertical spacing to make the tree lines equal high. + bool node_open = ImGui::TreeNode("Object", "%s_%u", prefix, uid); + ImGui::NextColumn(); + ImGui::AlignTextToFramePadding(); + ImGui::Text("my sailor is rich"); + ImGui::NextColumn(); + if (node_open) + { + static float dummy_members[8] = { 0.0f,0.0f,1.0f,3.1416f,100.0f,999.0f }; + for (int i = 0; i < 8; i++) + { + ImGui::PushID(i); // Use field index as identifier. + if (i < 2) + { + ShowDummyObject("Child", 424242); + } + else + { + // Here we use a TreeNode to highlight on hover (we could use e.g. Selectable as well) + ImGui::AlignTextToFramePadding(); + ImGuiTreeNodeFlags flags = ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen | ImGuiTreeNodeFlags_Bullet; + ImGui::TreeNodeEx("Field", flags, "Field_%d", i); + ImGui::NextColumn(); + ImGui::SetNextItemWidth(-1); + if (i >= 5) + ImGui::InputFloat("##value", &dummy_members[i], 1.0f); + else + ImGui::DragFloat("##value", &dummy_members[i], 0.01f); + ImGui::NextColumn(); + } + ImGui::PopID(); + } + ImGui::TreePop(); + } + ImGui::PopID(); +} + +// Demonstrate create a simple property editor. +static void ShowExampleAppPropertyEditor(bool* p_open) +{ + ImGui::SetNextWindowSize(ImVec2(430,450), ImGuiCond_FirstUseEver); + if (!ImGui::Begin("Example: Property editor", p_open)) + { + ImGui::End(); + return; + } + + HelpMarker( + "This example shows how you may implement a property editor using two columns.\n" + "All objects/fields data are dummies here.\n" + "Remember that in many simple cases, you can use ImGui::SameLine(xxx) to position\n" + "your cursor horizontally instead of using the Columns() API."); + + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(2,2)); + ImGui::Columns(2); + ImGui::Separator(); + + // Iterate dummy objects with dummy members (all the same data) + for (int obj_i = 0; obj_i < 3; obj_i++) + ShowDummyObject("Object", obj_i); + + ImGui::Columns(1); + ImGui::Separator(); + ImGui::PopStyleVar(); + ImGui::End(); +} + +//----------------------------------------------------------------------------- +// [SECTION] Example App: Long Text / ShowExampleAppLongText() +//----------------------------------------------------------------------------- + +// Demonstrate/test rendering huge amount of text, and the incidence of clipping. +static void ShowExampleAppLongText(bool* p_open) +{ + ImGui::SetNextWindowSize(ImVec2(520,600), ImGuiCond_FirstUseEver); + if (!ImGui::Begin("Example: Long text display", p_open)) + { + ImGui::End(); + return; + } + + static int test_type = 0; + static ImGuiTextBuffer log; + static int lines = 0; + ImGui::Text("Printing unusually long amount of text."); + ImGui::Combo("Test type", &test_type, + "Single call to TextUnformatted()\0" + "Multiple calls to Text(), clipped\0" + "Multiple calls to Text(), not clipped (slow)\0"); + ImGui::Text("Buffer contents: %d lines, %d bytes", lines, log.size()); + if (ImGui::Button("Clear")) { log.clear(); lines = 0; } + ImGui::SameLine(); + if (ImGui::Button("Add 1000 lines")) + { + for (int i = 0; i < 1000; i++) + log.appendf("%i The quick brown fox jumps over the lazy dog\n", lines+i); + lines += 1000; + } + ImGui::BeginChild("Log"); + switch (test_type) + { + case 0: + // Single call to TextUnformatted() with a big buffer + ImGui::TextUnformatted(log.begin(), log.end()); + break; + case 1: + { + // Multiple calls to Text(), manually coarsely clipped - demonstrate how to use the ImGuiListClipper helper. + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0,0)); + ImGuiListClipper clipper(lines); + while (clipper.Step()) + for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) + ImGui::Text("%i The quick brown fox jumps over the lazy dog", i); + ImGui::PopStyleVar(); + break; + } + case 2: + // Multiple calls to Text(), not clipped (slow) + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0,0)); + for (int i = 0; i < lines; i++) + ImGui::Text("%i The quick brown fox jumps over the lazy dog", i); + ImGui::PopStyleVar(); + break; + } + ImGui::EndChild(); + ImGui::End(); +} + +//----------------------------------------------------------------------------- +// [SECTION] Example App: Auto Resize / ShowExampleAppAutoResize() +//----------------------------------------------------------------------------- + +// Demonstrate creating a window which gets auto-resized according to its content. +static void ShowExampleAppAutoResize(bool* p_open) +{ + if (!ImGui::Begin("Example: Auto-resizing window", p_open, ImGuiWindowFlags_AlwaysAutoResize)) + { + ImGui::End(); + return; + } + + static int lines = 10; + ImGui::TextUnformatted( + "Window will resize every-frame to the size of its content.\n" + "Note that you probably don't want to query the window size to\n" + "output your content because that would create a feedback loop."); + ImGui::SliderInt("Number of lines", &lines, 1, 20); + for (int i = 0; i < lines; i++) + ImGui::Text("%*sThis is line %d", i * 4, "", i); // Pad with space to extend size horizontally + ImGui::End(); +} + +//----------------------------------------------------------------------------- +// [SECTION] Example App: Constrained Resize / ShowExampleAppConstrainedResize() +//----------------------------------------------------------------------------- + +// Demonstrate creating a window with custom resize constraints. +static void ShowExampleAppConstrainedResize(bool* p_open) +{ + struct CustomConstraints + { + // Helper functions to demonstrate programmatic constraints + static void Square(ImGuiSizeCallbackData* data) { data->DesiredSize.x = data->DesiredSize.y = IM_MAX(data->DesiredSize.x, data->DesiredSize.y); } + static void Step(ImGuiSizeCallbackData* data) { float step = (float)(int)(intptr_t)data->UserData; data->DesiredSize = ImVec2((int)(data->DesiredSize.x / step + 0.5f) * step, (int)(data->DesiredSize.y / step + 0.5f) * step); } + }; + + const char* test_desc[] = + { + "Resize vertical only", + "Resize horizontal only", + "Width > 100, Height > 100", + "Width 400-500", + "Height 400-500", + "Custom: Always Square", + "Custom: Fixed Steps (100)", + }; + + static bool auto_resize = false; + static int type = 0; + static int display_lines = 10; + if (type == 0) ImGui::SetNextWindowSizeConstraints(ImVec2(-1, 0), ImVec2(-1, FLT_MAX)); // Vertical only + if (type == 1) ImGui::SetNextWindowSizeConstraints(ImVec2(0, -1), ImVec2(FLT_MAX, -1)); // Horizontal only + if (type == 2) ImGui::SetNextWindowSizeConstraints(ImVec2(100, 100), ImVec2(FLT_MAX, FLT_MAX)); // Width > 100, Height > 100 + if (type == 3) ImGui::SetNextWindowSizeConstraints(ImVec2(400, -1), ImVec2(500, -1)); // Width 400-500 + if (type == 4) ImGui::SetNextWindowSizeConstraints(ImVec2(-1, 400), ImVec2(-1, 500)); // Height 400-500 + if (type == 5) ImGui::SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(FLT_MAX, FLT_MAX), CustomConstraints::Square); // Always Square + if (type == 6) ImGui::SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(FLT_MAX, FLT_MAX), CustomConstraints::Step, (void*)(intptr_t)100); // Fixed Step + + ImGuiWindowFlags flags = auto_resize ? ImGuiWindowFlags_AlwaysAutoResize : 0; + if (ImGui::Begin("Example: Constrained Resize", p_open, flags)) + { + if (ImGui::IsWindowDocked()) + ImGui::Text("Warning: Sizing Constraints won't work if the window is docked!"); + if (ImGui::Button("200x200")) { ImGui::SetWindowSize(ImVec2(200, 200)); } ImGui::SameLine(); + if (ImGui::Button("500x500")) { ImGui::SetWindowSize(ImVec2(500, 500)); } ImGui::SameLine(); + if (ImGui::Button("800x200")) { ImGui::SetWindowSize(ImVec2(800, 200)); } + ImGui::SetNextItemWidth(200); + ImGui::Combo("Constraint", &type, test_desc, IM_ARRAYSIZE(test_desc)); + ImGui::SetNextItemWidth(200); + ImGui::DragInt("Lines", &display_lines, 0.2f, 1, 100); + ImGui::Checkbox("Auto-resize", &auto_resize); + for (int i = 0; i < display_lines; i++) + ImGui::Text("%*sHello, sailor! Making this line long enough for the example.", i * 4, ""); + } + ImGui::End(); +} + +//----------------------------------------------------------------------------- +// [SECTION] Example App: Simple Overlay / ShowExampleAppSimpleOverlay() +//----------------------------------------------------------------------------- + +// Demonstrate creating a simple static window with no decoration +// + a context-menu to choose which corner of the screen to use. +static void ShowExampleAppSimpleOverlay(bool* p_open) +{ + // FIXME-VIEWPORT: Select a default viewport + const float DISTANCE = 10.0f; + static int corner = 0; + ImGuiIO& io = ImGui::GetIO(); + if (corner != -1) + { + ImGuiViewport* viewport = ImGui::GetMainViewport(); + ImVec2 work_area_pos = viewport->GetWorkPos(); // Instead of using viewport->Pos we use GetWorkPos() to avoid menu bars, if any! + ImVec2 work_area_size = viewport->GetWorkSize(); + ImVec2 window_pos = ImVec2((corner & 1) ? (work_area_pos.x + work_area_size.x - DISTANCE) : (work_area_pos.x + DISTANCE), (corner & 2) ? (work_area_pos.y + work_area_size.y - DISTANCE) : (work_area_pos.y + DISTANCE)); + ImVec2 window_pos_pivot = ImVec2((corner & 1) ? 1.0f : 0.0f, (corner & 2) ? 1.0f : 0.0f); + ImGui::SetNextWindowPos(window_pos, ImGuiCond_Always, window_pos_pivot); + ImGui::SetNextWindowViewport(viewport->ID); + } + ImGui::SetNextWindowBgAlpha(0.35f); // Transparent background + ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoDocking | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoNav; + if (corner != -1) + window_flags |= ImGuiWindowFlags_NoMove; + if (ImGui::Begin("Example: Simple overlay", p_open, window_flags)) + { + ImGui::Text("Simple overlay\n" "in the corner of the screen.\n" "(right-click to change position)"); + ImGui::Separator(); + if (ImGui::IsMousePosValid()) + ImGui::Text("Mouse Position: (%.1f,%.1f)", io.MousePos.x, io.MousePos.y); + else + ImGui::Text("Mouse Position: "); + if (ImGui::BeginPopupContextWindow()) + { + if (ImGui::MenuItem("Custom", NULL, corner == -1)) corner = -1; + if (ImGui::MenuItem("Top-left", NULL, corner == 0)) corner = 0; + if (ImGui::MenuItem("Top-right", NULL, corner == 1)) corner = 1; + if (ImGui::MenuItem("Bottom-left", NULL, corner == 2)) corner = 2; + if (ImGui::MenuItem("Bottom-right", NULL, corner == 3)) corner = 3; + if (p_open && ImGui::MenuItem("Close")) *p_open = false; + ImGui::EndPopup(); + } + } + ImGui::End(); +} + +//----------------------------------------------------------------------------- +// [SECTION] Example App: Manipulating Window Titles / ShowExampleAppWindowTitles() +//----------------------------------------------------------------------------- + +// Demonstrate using "##" and "###" in identifiers to manipulate ID generation. +// This apply to all regular items as well. +// Read FAQ section "How can I have multiple widgets with the same label?" for details. +static void ShowExampleAppWindowTitles(bool*) +{ + // By default, Windows are uniquely identified by their title. + // You can use the "##" and "###" markers to manipulate the display/ID. + + // Using "##" to display same title but have unique identifier. + ImGui::SetNextWindowPos(ImVec2(100, 100), ImGuiCond_FirstUseEver); + ImGui::Begin("Same title as another window##1"); + ImGui::Text("This is window 1.\nMy title is the same as window 2, but my identifier is unique."); + ImGui::End(); + + ImGui::SetNextWindowPos(ImVec2(100, 200), ImGuiCond_FirstUseEver); + ImGui::Begin("Same title as another window##2"); + ImGui::Text("This is window 2.\nMy title is the same as window 1, but my identifier is unique."); + ImGui::End(); + + // Using "###" to display a changing title but keep a static identifier "AnimatedTitle" + char buf[128]; + sprintf(buf, "Animated title %c %d###AnimatedTitle", "|/-\\"[(int)(ImGui::GetTime() / 0.25f) & 3], ImGui::GetFrameCount()); + ImGui::SetNextWindowPos(ImVec2(100, 300), ImGuiCond_FirstUseEver); + ImGui::Begin(buf); + ImGui::Text("This window has a changing title."); + ImGui::End(); +} + +//----------------------------------------------------------------------------- +// [SECTION] Example App: Custom Rendering using ImDrawList API / ShowExampleAppCustomRendering() +//----------------------------------------------------------------------------- + +// Demonstrate using the low-level ImDrawList to draw custom shapes. +static void ShowExampleAppCustomRendering(bool* p_open) +{ + if (!ImGui::Begin("Example: Custom rendering", p_open)) + { + ImGui::End(); + return; + } + + // Tip: If you do a lot of custom rendering, you probably want to use your own geometrical types and benefit of + // overloaded operators, etc. Define IM_VEC2_CLASS_EXTRA in imconfig.h to create implicit conversions between your + // types and ImVec2/ImVec4. Dear ImGui defines overloaded operators but they are internal to imgui.cpp and not + // exposed outside (to avoid messing with your types) In this example we are not using the maths operators! + ImDrawList* draw_list = ImGui::GetWindowDrawList(); + + if (ImGui::BeginTabBar("##TabBar")) + { + if (ImGui::BeginTabItem("Primitives")) + { + ImGui::PushItemWidth(-ImGui::GetFontSize() * 10); + + // Draw gradients + // (note that those are currently exacerbating our sRGB/Linear issues) + ImGui::Text("Gradients"); + ImVec2 gradient_size = ImVec2(ImGui::CalcItemWidth(), ImGui::GetFrameHeight()); + { + ImVec2 p0 = ImGui::GetCursorScreenPos(); + ImVec2 p1 = ImVec2(p0.x + gradient_size.x, p0.y + gradient_size.y); + ImU32 col_a = ImGui::GetColorU32(ImVec4(0.0f, 0.0f, 0.0f, 1.0f)); + ImU32 col_b = ImGui::GetColorU32(ImVec4(1.0f, 1.0f, 1.0f, 1.0f)); + draw_list->AddRectFilledMultiColor(p0, p1, col_a, col_b, col_b, col_a); + ImGui::InvisibleButton("##gradient1", gradient_size); + } + { + ImVec2 p0 = ImGui::GetCursorScreenPos(); + ImVec2 p1 = ImVec2(p0.x + gradient_size.x, p0.y + gradient_size.y); + ImU32 col_a = ImGui::GetColorU32(ImVec4(0.0f, 1.0f, 0.0f, 1.0f)); + ImU32 col_b = ImGui::GetColorU32(ImVec4(1.0f, 0.0f, 0.0f, 1.0f)); + draw_list->AddRectFilledMultiColor(p0, p1, col_a, col_b, col_b, col_a); + ImGui::InvisibleButton("##gradient2", gradient_size); + } + + // Draw a bunch of primitives + ImGui::Text("All primitives"); + static float sz = 36.0f; + static float thickness = 3.0f; + static int ngon_sides = 6; + static bool circle_segments_override = false; + static int circle_segments_override_v = 12; + static ImVec4 colf = ImVec4(1.0f, 1.0f, 0.4f, 1.0f); + ImGui::DragFloat("Size", &sz, 0.2f, 2.0f, 72.0f, "%.0f"); + ImGui::DragFloat("Thickness", &thickness, 0.05f, 1.0f, 8.0f, "%.02f"); + ImGui::SliderInt("N-gon sides", &ngon_sides, 3, 12); + ImGui::Checkbox("##circlesegmentoverride", &circle_segments_override); + ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x); + if (ImGui::SliderInt("Circle segments", &circle_segments_override_v, 3, 40)) + circle_segments_override = true; + ImGui::ColorEdit4("Color", &colf.x); + const ImVec2 p = ImGui::GetCursorScreenPos(); + const ImU32 col = ImColor(colf); + const float spacing = 10.0f; + const ImDrawCornerFlags corners_none = 0; + const ImDrawCornerFlags corners_all = ImDrawCornerFlags_All; + const ImDrawCornerFlags corners_tl_br = ImDrawCornerFlags_TopLeft | ImDrawCornerFlags_BotRight; + const int circle_segments = circle_segments_override ? circle_segments_override_v : 0; + float x = p.x + 4.0f, y = p.y + 4.0f; + for (int n = 0; n < 2; n++) + { + // First line uses a thickness of 1.0f, second line uses the configurable thickness + float th = (n == 0) ? 1.0f : thickness; + draw_list->AddNgon(ImVec2(x + sz*0.5f, y + sz*0.5f), sz*0.5f, col, ngon_sides, th); x += sz + spacing; // N-gon + draw_list->AddCircle(ImVec2(x + sz*0.5f, y + sz*0.5f), sz*0.5f, col, circle_segments, th); x += sz + spacing; // Circle + draw_list->AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, 0.0f, corners_none, th); x += sz + spacing; // Square + draw_list->AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, 10.0f, corners_all, th); x += sz + spacing; // Square with all rounded corners + draw_list->AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, 10.0f, corners_tl_br, th); x += sz + spacing; // Square with two rounded corners + draw_list->AddTriangle(ImVec2(x+sz*0.5f,y), ImVec2(x+sz, y+sz-0.5f), ImVec2(x, y+sz-0.5f), col, th); x += sz + spacing; // Triangle + draw_list->AddTriangle(ImVec2(x+sz*0.2f,y), ImVec2(x, y+sz-0.5f), ImVec2(x+sz*0.4f, y+sz-0.5f), col, th); x += sz*0.4f + spacing; // Thin triangle + draw_list->AddLine(ImVec2(x, y), ImVec2(x + sz, y), col, th); x += sz + spacing; // Horizontal line (note: drawing a filled rectangle will be faster!) + draw_list->AddLine(ImVec2(x, y), ImVec2(x, y + sz), col, th); x += spacing; // Vertical line (note: drawing a filled rectangle will be faster!) + draw_list->AddLine(ImVec2(x, y), ImVec2(x + sz, y + sz), col, th); x += sz + spacing; // Diagonal line + draw_list->AddBezierCurve(ImVec2(x, y), ImVec2(x + sz*1.3f, y + sz*0.3f), ImVec2(x + sz - sz*1.3f, y + sz - sz*0.3f), ImVec2(x + sz, y + sz), col, th); + x = p.x + 4; + y += sz + spacing; + } + draw_list->AddNgonFilled(ImVec2(x + sz * 0.5f, y + sz * 0.5f), sz*0.5f, col, ngon_sides); x += sz + spacing; // N-gon + draw_list->AddCircleFilled(ImVec2(x + sz*0.5f, y + sz*0.5f), sz*0.5f, col, circle_segments);x += sz + spacing; // Circle + draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + sz), col); x += sz + spacing; // Square + draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + sz), col, 10.0f); x += sz + spacing; // Square with all rounded corners + draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + sz), col, 10.0f, corners_tl_br); x += sz + spacing; // Square with two rounded corners + draw_list->AddTriangleFilled(ImVec2(x+sz*0.5f,y), ImVec2(x+sz, y+sz-0.5f), ImVec2(x, y+sz-0.5f), col); x += sz + spacing; // Triangle + draw_list->AddTriangleFilled(ImVec2(x+sz*0.2f,y), ImVec2(x, y+sz-0.5f), ImVec2(x+sz*0.4f, y+sz-0.5f), col); x += sz*0.4f + spacing; // Thin triangle + draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + thickness), col); x += sz + spacing; // Horizontal line (faster than AddLine, but only handle integer thickness) + draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + thickness, y + sz), col); x += spacing*2.0f; // Vertical line (faster than AddLine, but only handle integer thickness) + draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + 1, y + 1), col); x += sz; // Pixel (faster than AddLine) + draw_list->AddRectFilledMultiColor(ImVec2(x, y), ImVec2(x + sz, y + sz), IM_COL32(0, 0, 0, 255), IM_COL32(255, 0, 0, 255), IM_COL32(255, 255, 0, 255), IM_COL32(0, 255, 0, 255)); + ImGui::Dummy(ImVec2((sz + spacing) * 9.8f, (sz + spacing) * 3)); + + ImGui::PopItemWidth(); + ImGui::EndTabItem(); + } + + if (ImGui::BeginTabItem("Canvas")) + { + static ImVector points; + static bool adding_line = false; + if (ImGui::Button("Clear")) points.clear(); + if (points.Size >= 2) { ImGui::SameLine(); if (ImGui::Button("Undo")) { points.pop_back(); points.pop_back(); } } + ImGui::Text("Left-click and drag to add lines,\nRight-click to undo"); + + // Here we are using InvisibleButton() as a convenience to 1) advance the cursor and 2) allows us to use + // IsItemHovered(). But you can also draw directly and poll mouse/keyboard by yourself. + // You can manipulate the cursor using GetCursorPos() and SetCursorPos(). + // If you only use the ImDrawList API, you can notify the owner window of its extends with SetCursorPos(max). + ImVec2 canvas_p = ImGui::GetCursorScreenPos(); // ImDrawList API uses screen coordinates! + ImVec2 canvas_sz = ImGui::GetContentRegionAvail(); // Resize canvas to what's available + if (canvas_sz.x < 50.0f) canvas_sz.x = 50.0f; + if (canvas_sz.y < 50.0f) canvas_sz.y = 50.0f; + draw_list->AddRectFilledMultiColor(canvas_p, ImVec2(canvas_p.x + canvas_sz.x, canvas_p.y + canvas_sz.y), IM_COL32(50, 50, 50, 255), IM_COL32(50, 50, 60, 255), IM_COL32(60, 60, 70, 255), IM_COL32(50, 50, 60, 255)); + draw_list->AddRect(canvas_p, ImVec2(canvas_p.x + canvas_sz.x, canvas_p.y + canvas_sz.y), IM_COL32(255, 255, 255, 255)); + + bool adding_preview = false; + ImGui::InvisibleButton("canvas", canvas_sz); + ImVec2 mouse_pos_global = ImGui::GetIO().MousePos; + ImVec2 mouse_pos_canvas = ImVec2(mouse_pos_global.x - canvas_p.x, mouse_pos_global.y - canvas_p.y); + if (adding_line) + { + adding_preview = true; + points.push_back(mouse_pos_canvas); + if (!ImGui::IsMouseDown(0)) + adding_line = adding_preview = false; + } + if (ImGui::IsItemHovered()) + { + if (!adding_line && ImGui::IsMouseClicked(0)) + { + points.push_back(mouse_pos_canvas); + adding_line = true; + } + if (ImGui::IsMouseClicked(1) && !points.empty()) + { + adding_line = adding_preview = false; + points.pop_back(); + points.pop_back(); + } + } + + // Draw all lines in the canvas (with a clipping rectangle so they don't stray out of it). + draw_list->PushClipRect(canvas_p, ImVec2(canvas_p.x + canvas_sz.x, canvas_p.y + canvas_sz.y), true); + for (int i = 0; i < points.Size - 1; i += 2) + draw_list->AddLine(ImVec2(canvas_p.x + points[i].x, canvas_p.y + points[i].y), ImVec2(canvas_p.x + points[i + 1].x, canvas_p.y + points[i + 1].y), IM_COL32(255, 255, 0, 255), 2.0f); + draw_list->PopClipRect(); + if (adding_preview) + points.pop_back(); + ImGui::EndTabItem(); + } + + if (ImGui::BeginTabItem("BG/FG draw lists")) + { + static bool draw_bg = true; + static bool draw_fg = true; + ImGui::Checkbox("Draw in Background draw list", &draw_bg); + ImGui::SameLine(); HelpMarker("The Background draw list will be rendered below every Dear ImGui windows."); + ImGui::Checkbox("Draw in Foreground draw list", &draw_fg); + ImGui::SameLine(); HelpMarker("The Foreground draw list will be rendered over every Dear ImGui windows."); + ImVec2 window_pos = ImGui::GetWindowPos(); + ImVec2 window_size = ImGui::GetWindowSize(); + ImVec2 window_center = ImVec2(window_pos.x + window_size.x * 0.5f, window_pos.y + window_size.y * 0.5f); + if (draw_bg) + ImGui::GetBackgroundDrawList()->AddCircle(window_center, window_size.x * 0.6f, IM_COL32(255, 0, 0, 200), 0, 10+4); + if (draw_fg) + ImGui::GetForegroundDrawList()->AddCircle(window_center, window_size.y * 0.6f, IM_COL32(0, 255, 0, 200), 0, 10); + ImGui::EndTabItem(); + } + + ImGui::EndTabBar(); + } + + ImGui::End(); +} + +//----------------------------------------------------------------------------- +// [SECTION] Example App: Docking, DockSpace / ShowExampleAppDockSpace() +//----------------------------------------------------------------------------- + +// Demonstrate using DockSpace() to create an explicit docking node within an existing window. +// Note that you already dock windows into each others _without_ a DockSpace() by just moving windows +// from their title bar (or by holding SHIFT if io.ConfigDockingWithShift is set). +// DockSpace() is only useful to construct to a central location for your application. +void ShowExampleAppDockSpace(bool* p_open) +{ + static bool opt_fullscreen_persistant = true; + bool opt_fullscreen = opt_fullscreen_persistant; + static ImGuiDockNodeFlags dockspace_flags = ImGuiDockNodeFlags_None; + + // We are using the ImGuiWindowFlags_NoDocking flag to make the parent window not dockable into, + // because it would be confusing to have two docking targets within each others. + ImGuiWindowFlags window_flags = ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoDocking; + if (opt_fullscreen) + { + ImGuiViewport* viewport = ImGui::GetMainViewport(); + ImGui::SetNextWindowPos(viewport->GetWorkPos()); + ImGui::SetNextWindowSize(viewport->GetWorkSize()); + ImGui::SetNextWindowViewport(viewport->ID); + ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f); + ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f); + window_flags |= ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove; + window_flags |= ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoNavFocus; + } + + // When using ImGuiDockNodeFlags_PassthruCentralNode, DockSpace() will render our background + // and handle the pass-thru hole, so we ask Begin() to not render a background. + if (dockspace_flags & ImGuiDockNodeFlags_PassthruCentralNode) + window_flags |= ImGuiWindowFlags_NoBackground; + + // Important: note that we proceed even if Begin() returns false (aka window is collapsed). + // This is because we want to keep our DockSpace() active. If a DockSpace() is inactive, + // all active windows docked into it will lose their parent and become undocked. + // We cannot preserve the docking relationship between an active window and an inactive docking, otherwise + // any change of dockspace/settings would lead to windows being stuck in limbo and never being visible. + ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f)); + ImGui::Begin("DockSpace Demo", p_open, window_flags); + ImGui::PopStyleVar(); + + if (opt_fullscreen) + ImGui::PopStyleVar(2); + + // DockSpace + ImGuiIO& io = ImGui::GetIO(); + if (io.ConfigFlags & ImGuiConfigFlags_DockingEnable) + { + ImGuiID dockspace_id = ImGui::GetID("MyDockSpace"); + ImGui::DockSpace(dockspace_id, ImVec2(0.0f, 0.0f), dockspace_flags); + } + else + { + ShowDockingDisabledMessage(); + } + + if (ImGui::BeginMenuBar()) + { + if (ImGui::BeginMenu("Docking")) + { + // Disabling fullscreen would allow the window to be moved to the front of other windows, + // which we can't undo at the moment without finer window depth/z control. + //ImGui::MenuItem("Fullscreen", NULL, &opt_fullscreen_persistant); + + if (ImGui::MenuItem("Flag: NoSplit", "", (dockspace_flags & ImGuiDockNodeFlags_NoSplit) != 0)) dockspace_flags ^= ImGuiDockNodeFlags_NoSplit; + if (ImGui::MenuItem("Flag: NoResize", "", (dockspace_flags & ImGuiDockNodeFlags_NoResize) != 0)) dockspace_flags ^= ImGuiDockNodeFlags_NoResize; + if (ImGui::MenuItem("Flag: NoDockingInCentralNode", "", (dockspace_flags & ImGuiDockNodeFlags_NoDockingInCentralNode) != 0)) dockspace_flags ^= ImGuiDockNodeFlags_NoDockingInCentralNode; + if (ImGui::MenuItem("Flag: PassthruCentralNode", "", (dockspace_flags & ImGuiDockNodeFlags_PassthruCentralNode) != 0)) dockspace_flags ^= ImGuiDockNodeFlags_PassthruCentralNode; + if (ImGui::MenuItem("Flag: AutoHideTabBar", "", (dockspace_flags & ImGuiDockNodeFlags_AutoHideTabBar) != 0)) dockspace_flags ^= ImGuiDockNodeFlags_AutoHideTabBar; + ImGui::Separator(); + if (ImGui::MenuItem("Close DockSpace", NULL, false, p_open != NULL)) + *p_open = false; + ImGui::EndMenu(); + } + HelpMarker( + "When docking is enabled, you can ALWAYS dock MOST window into another! Try it now!" "\n\n" + " > if io.ConfigDockingWithShift==false (default):" "\n" + " drag windows from title bar to dock" "\n" + " > if io.ConfigDockingWithShift==true:" "\n" + " drag windows from anywhere and hold Shift to dock" "\n\n" + "This demo app has nothing to do with it!" "\n\n" + "This demo app only demonstrate the use of ImGui::DockSpace() which allows you to manually create a docking node _within_ another window. This is useful so you can decorate your main application window (e.g. with a menu bar)." "\n\n" + "ImGui::DockSpace() comes with one hard constraint: it needs to be submitted _before_ any window which may be docked into it. Therefore, if you use a dock spot as the central point of your application, you'll probably want it to be part of the very first window you are submitting to imgui every frame." "\n\n" + "(NB: because of this constraint, the implicit \"Debug\" window can not be docked into an explicit DockSpace() node, because that window is submitted as part of the NewFrame() call. An easy workaround is that you can create your own implicit \"Debug##2\" window after calling DockSpace() and leave it in the window stack for anyone to use.)" + ); + + ImGui::EndMenuBar(); + } + + ImGui::End(); +} + +//----------------------------------------------------------------------------- +// [SECTION] Example App: Documents Handling / ShowExampleAppDocuments() +//----------------------------------------------------------------------------- + +// Simplified structure to mimic a Document model +struct MyDocument +{ + const char* Name; // Document title + bool Open; // Set when open (we keep an array of all available documents to simplify demo code!) + bool OpenPrev; // Copy of Open from last update. + bool Dirty; // Set when the document has been modified + bool WantClose; // Set when the document + ImVec4 Color; // An arbitrary variable associated to the document + + MyDocument(const char* name, bool open = true, const ImVec4& color = ImVec4(1.0f,1.0f,1.0f,1.0f)) + { + Name = name; + Open = OpenPrev = open; + Dirty = false; + WantClose = false; + Color = color; + } + void DoOpen() { Open = true; } + void DoQueueClose() { WantClose = true; } + void DoForceClose() { Open = false; Dirty = false; } + void DoSave() { Dirty = false; } + + // Display dummy contents for the Document + static void DisplayContents(MyDocument* doc) + { + ImGui::PushID(doc); + ImGui::Text("Document \"%s\"", doc->Name); + ImGui::PushStyleColor(ImGuiCol_Text, doc->Color); + ImGui::TextWrapped("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."); + ImGui::PopStyleColor(); + if (ImGui::Button("Modify", ImVec2(100, 0))) + doc->Dirty = true; + ImGui::SameLine(); + if (ImGui::Button("Save", ImVec2(100, 0))) + doc->DoSave(); + ImGui::ColorEdit3("color", &doc->Color.x); // Useful to test drag and drop and hold-dragged-to-open-tab behavior. + ImGui::PopID(); + } + + // Display context menu for the Document + static void DisplayContextMenu(MyDocument* doc) + { + if (!ImGui::BeginPopupContextItem()) + return; + + char buf[256]; + sprintf(buf, "Save %s", doc->Name); + if (ImGui::MenuItem(buf, "CTRL+S", false, doc->Open)) + doc->DoSave(); + if (ImGui::MenuItem("Close", "CTRL+W", false, doc->Open)) + doc->DoQueueClose(); + ImGui::EndPopup(); + } +}; + +struct ExampleAppDocuments +{ + ImVector Documents; + + ExampleAppDocuments() + { + Documents.push_back(MyDocument("Lettuce", true, ImVec4(0.4f, 0.8f, 0.4f, 1.0f))); + Documents.push_back(MyDocument("Eggplant", true, ImVec4(0.8f, 0.5f, 1.0f, 1.0f))); + Documents.push_back(MyDocument("Carrot", true, ImVec4(1.0f, 0.8f, 0.5f, 1.0f))); + Documents.push_back(MyDocument("Tomato", false, ImVec4(1.0f, 0.3f, 0.4f, 1.0f))); + Documents.push_back(MyDocument("A Rather Long Title", false)); + Documents.push_back(MyDocument("Some Document", false)); + } +}; + +// [Optional] Notify the system of Tabs/Windows closure that happened outside the regular tab interface. +// If a tab has been closed programmatically (aka closed from another source such as the Checkbox() in the demo, +// as opposed to clicking on the regular tab closing button) and stops being submitted, it will take a frame for +// the tab bar to notice its absence. During this frame there will be a gap in the tab bar, and if the tab that has +// disappeared was the selected one, the tab bar will report no selected tab during the frame. This will effectively +// give the impression of a flicker for one frame. +// We call SetTabItemClosed() to manually notify the Tab Bar or Docking system of removed tabs to avoid this glitch. +// Note that this completely optional, and only affect tab bars with the ImGuiTabBarFlags_Reorderable flag. +static void NotifyOfDocumentsClosedElsewhere(ExampleAppDocuments& app) +{ + for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++) + { + MyDocument* doc = &app.Documents[doc_n]; + if (!doc->Open && doc->OpenPrev) + ImGui::SetTabItemClosed(doc->Name); + doc->OpenPrev = doc->Open; + } +} + +void ShowExampleAppDocuments(bool* p_open) +{ + static ExampleAppDocuments app; + + // Options + enum Target + { + Target_None, + Target_Tab, // Create documents as local tab into a local tab bar + Target_DockSpaceAndWindow // Create documents as regular windows, and create an embedded dockspace + }; + static Target opt_target = Target_Tab; + static bool opt_reorderable = true; + static ImGuiTabBarFlags opt_fitting_flags = ImGuiTabBarFlags_FittingPolicyDefault_; + + // When (opt_target == Target_DockSpaceAndWindow) there is the possibily that one of our child Document window (e.g. "Eggplant") + // that we emit gets docked into the same spot as the parent window ("Example: Documents"). + // This would create a problematic feedback loop because selecting the "Eggplant" tab would make the "Example: Documents" tab + // not visible, which in turn would stop submitting the "Eggplant" window. + // We avoid this problem by submitting our documents window even if our parent window is not currently visible. + // Another solution may be to make the "Example: Documents" window use the ImGuiWindowFlags_NoDocking. + + bool window_contents_visible = ImGui::Begin("Example: Documents", p_open, ImGuiWindowFlags_MenuBar); + if (!window_contents_visible && opt_target != Target_DockSpaceAndWindow) + { + ImGui::End(); + return; + } + + // Menu + if (ImGui::BeginMenuBar()) + { + if (ImGui::BeginMenu("File")) + { + int open_count = 0; + for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++) + open_count += app.Documents[doc_n].Open ? 1 : 0; + + if (ImGui::BeginMenu("Open", open_count < app.Documents.Size)) + { + for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++) + { + MyDocument* doc = &app.Documents[doc_n]; + if (!doc->Open) + if (ImGui::MenuItem(doc->Name)) + doc->DoOpen(); + } + ImGui::EndMenu(); + } + if (ImGui::MenuItem("Close All Documents", NULL, false, open_count > 0)) + for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++) + app.Documents[doc_n].DoQueueClose(); + if (ImGui::MenuItem("Exit", "Alt+F4")) {} + ImGui::EndMenu(); + } + ImGui::EndMenuBar(); + } + + // [Debug] List documents with one checkbox for each + for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++) + { + MyDocument* doc = &app.Documents[doc_n]; + if (doc_n > 0) + ImGui::SameLine(); + ImGui::PushID(doc); + if (ImGui::Checkbox(doc->Name, &doc->Open)) + if (!doc->Open) + doc->DoForceClose(); + ImGui::PopID(); + } + ImGui::PushItemWidth(ImGui::GetFontSize() * 12); + ImGui::Combo("Output", (int*)&opt_target, "None\0TabBar+Tabs\0DockSpace+Window\0"); + ImGui::PopItemWidth(); + bool redock_all = false; + if (opt_target == Target_Tab) { ImGui::SameLine(); ImGui::Checkbox("Reorderable Tabs", &opt_reorderable); } + if (opt_target == Target_DockSpaceAndWindow) { ImGui::SameLine(); redock_all = ImGui::Button("Redock all"); } + + ImGui::Separator(); + + // Tabs + if (opt_target == Target_Tab) + { + ImGuiTabBarFlags tab_bar_flags = (opt_fitting_flags) | (opt_reorderable ? ImGuiTabBarFlags_Reorderable : 0); + if (ImGui::BeginTabBar("##tabs", tab_bar_flags)) + { + if (opt_reorderable) + NotifyOfDocumentsClosedElsewhere(app); + + // [DEBUG] Stress tests + //if ((ImGui::GetFrameCount() % 30) == 0) docs[1].Open ^= 1; // [DEBUG] Automatically show/hide a tab. Test various interactions e.g. dragging with this on. + //if (ImGui::GetIO().KeyCtrl) ImGui::SetTabItemSelected(docs[1].Name); // [DEBUG] Test SetTabItemSelected(), probably not very useful as-is anyway.. + + // Submit Tabs + for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++) + { + MyDocument* doc = &app.Documents[doc_n]; + if (!doc->Open) + continue; + + ImGuiTabItemFlags tab_flags = (doc->Dirty ? ImGuiTabItemFlags_UnsavedDocument : 0); + bool visible = ImGui::BeginTabItem(doc->Name, &doc->Open, tab_flags); + + // Cancel attempt to close when unsaved add to save queue so we can display a popup. + if (!doc->Open && doc->Dirty) + { + doc->Open = true; + doc->DoQueueClose(); + } + + MyDocument::DisplayContextMenu(doc); + if (visible) + { + MyDocument::DisplayContents(doc); + ImGui::EndTabItem(); + } + } + + ImGui::EndTabBar(); + } + } + else if (opt_target == Target_DockSpaceAndWindow) + { + if (ImGui::GetIO().ConfigFlags & ImGuiConfigFlags_DockingEnable) + { + NotifyOfDocumentsClosedElsewhere(app); + + // Create a DockSpace node where any window can be docked + ImGuiID dockspace_id = ImGui::GetID("MyDockSpace"); + ImGui::DockSpace(dockspace_id); + + // Create Windows + for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++) + { + MyDocument* doc = &app.Documents[doc_n]; + if (!doc->Open) + continue; + + ImGui::SetNextWindowDockID(dockspace_id, redock_all ? ImGuiCond_Always : ImGuiCond_FirstUseEver); + ImGuiWindowFlags window_flags = (doc->Dirty ? ImGuiWindowFlags_UnsavedDocument : 0); + bool visible = ImGui::Begin(doc->Name, &doc->Open, window_flags); + + // Cancel attempt to close when unsaved add to save queue so we can display a popup. + if (!doc->Open && doc->Dirty) + { + doc->Open = true; + doc->DoQueueClose(); + } + + MyDocument::DisplayContextMenu(doc); + if (visible) + MyDocument::DisplayContents(doc); + + ImGui::End(); + } + } + else + { + ShowDockingDisabledMessage(); + } + } + + // Early out other contents + if (!window_contents_visible) + { + ImGui::End(); + return; + } + + // Update closing queue + static ImVector close_queue; + if (close_queue.empty()) + { + // Close queue is locked once we started a popup + for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++) + { + MyDocument* doc = &app.Documents[doc_n]; + if (doc->WantClose) + { + doc->WantClose = false; + close_queue.push_back(doc); + } + } + } + + // Display closing confirmation UI + if (!close_queue.empty()) + { + int close_queue_unsaved_documents = 0; + for (int n = 0; n < close_queue.Size; n++) + if (close_queue[n]->Dirty) + close_queue_unsaved_documents++; + + if (close_queue_unsaved_documents == 0) + { + // Close documents when all are unsaved + for (int n = 0; n < close_queue.Size; n++) + close_queue[n]->DoForceClose(); + close_queue.clear(); + } + else + { + if (!ImGui::IsPopupOpen("Save?")) + ImGui::OpenPopup("Save?"); + if (ImGui::BeginPopupModal("Save?")) + { + ImGui::Text("Save change to the following items?"); + ImGui::SetNextItemWidth(-1.0f); + if (ImGui::ListBoxHeader("##", close_queue_unsaved_documents, 6)) + { + for (int n = 0; n < close_queue.Size; n++) + if (close_queue[n]->Dirty) + ImGui::Text("%s", close_queue[n]->Name); + ImGui::ListBoxFooter(); + } + + if (ImGui::Button("Yes", ImVec2(80, 0))) + { + for (int n = 0; n < close_queue.Size; n++) + { + if (close_queue[n]->Dirty) + close_queue[n]->DoSave(); + close_queue[n]->DoForceClose(); + } + close_queue.clear(); + ImGui::CloseCurrentPopup(); + } + ImGui::SameLine(); + if (ImGui::Button("No", ImVec2(80, 0))) + { + for (int n = 0; n < close_queue.Size; n++) + close_queue[n]->DoForceClose(); + close_queue.clear(); + ImGui::CloseCurrentPopup(); + } + ImGui::SameLine(); + if (ImGui::Button("Cancel", ImVec2(80, 0))) + { + close_queue.clear(); + ImGui::CloseCurrentPopup(); + } + ImGui::EndPopup(); + } + } + } + + ImGui::End(); +} + +// End of Demo code +#else + +void ImGui::ShowAboutWindow(bool*) {} +void ImGui::ShowDemoWindow(bool*) {} +void ImGui::ShowUserGuide() {} +void ImGui::ShowStyleEditor(ImGuiStyle*) {} + +#endif + +#endif // #ifndef IMGUI_DISABLE diff --git a/extern/imgui/src/imgui_draw.cpp b/extern/imgui/src/imgui_draw.cpp new file mode 100644 index 0000000..e7263e7 --- /dev/null +++ b/extern/imgui/src/imgui_draw.cpp @@ -0,0 +1,3625 @@ +// dear imgui, v1.77 WIP +// (drawing and font code) + +/* + +Index of this file: + +// [SECTION] STB libraries implementation +// [SECTION] Style functions +// [SECTION] ImDrawList +// [SECTION] ImDrawListSplitter +// [SECTION] ImDrawData +// [SECTION] Helpers ShadeVertsXXX functions +// [SECTION] ImFontConfig +// [SECTION] ImFontAtlas +// [SECTION] ImFontAtlas glyph ranges helpers +// [SECTION] ImFontGlyphRangesBuilder +// [SECTION] ImFont +// [SECTION] ImGui Internal Render Helpers +// [SECTION] Decompression code +// [SECTION] Default font data (ProggyClean.ttf) + +*/ + +#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS) +#define _CRT_SECURE_NO_WARNINGS +#endif + +#include "imgui.h" +#ifndef IMGUI_DISABLE + +#ifndef IMGUI_DEFINE_MATH_OPERATORS +#define IMGUI_DEFINE_MATH_OPERATORS +#endif +#include "imgui_internal.h" + +#include // vsnprintf, sscanf, printf +#if !defined(alloca) +#if defined(__GLIBC__) || defined(__sun) || defined(__APPLE__) || defined(__NEWLIB__) +#include // alloca (glibc uses . Note that Cygwin may have _WIN32 defined, so the order matters here) +#elif defined(_WIN32) +#include // alloca +#if !defined(alloca) +#define alloca _alloca // for clang with MS Codegen +#endif +#else +#include // alloca +#endif +#endif + +// Visual Studio warnings +#ifdef _MSC_VER +#pragma warning (disable: 4127) // condition expression is constant +#pragma warning (disable: 4505) // unreferenced local function has been removed (stb stuff) +#pragma warning (disable: 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen +#endif + +// Clang/GCC warnings with -Weverything +#if defined(__clang__) +#pragma clang diagnostic ignored "-Wold-style-cast" // warning : use of old-style cast // yes, they are more terse. +#pragma clang diagnostic ignored "-Wfloat-equal" // warning : comparing floating point with == or != is unsafe // storing and comparing against same constants ok. +#pragma clang diagnostic ignored "-Wglobal-constructors" // warning : declaration requires a global destructor // similar to above, not sure what the exact difference is. +#pragma clang diagnostic ignored "-Wsign-conversion" // warning : implicit conversion changes signedness // +#if __has_warning("-Wzero-as-null-pointer-constant") +#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" // warning : zero as null pointer constant // some standard header variations use #define NULL 0 +#endif +#if __has_warning("-Wcomma") +#pragma clang diagnostic ignored "-Wcomma" // warning : possible misuse of comma operator here // +#endif +#if __has_warning("-Wreserved-id-macro") +#pragma clang diagnostic ignored "-Wreserved-id-macro" // warning : macro name is a reserved identifier // +#endif +#if __has_warning("-Wdouble-promotion") +#pragma clang diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function // using printf() is a misery with this as C++ va_arg ellipsis changes float to double. +#endif +#elif defined(__GNUC__) +#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind +#pragma GCC diagnostic ignored "-Wunused-function" // warning: 'xxxx' defined but not used +#pragma GCC diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function +#pragma GCC diagnostic ignored "-Wconversion" // warning: conversion to 'xxxx' from 'xxxx' may alter its value +#pragma GCC diagnostic ignored "-Wstack-protector" // warning: stack protector not protecting local variables: variable length buffer +#pragma GCC diagnostic ignored "-Wclass-memaccess" // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead +#endif + +//------------------------------------------------------------------------- +// [SECTION] STB libraries implementation +//------------------------------------------------------------------------- + +// Compile time options: +//#define IMGUI_STB_NAMESPACE ImStb +//#define IMGUI_STB_TRUETYPE_FILENAME "my_folder/stb_truetype.h" +//#define IMGUI_STB_RECT_PACK_FILENAME "my_folder/stb_rect_pack.h" +//#define IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION +//#define IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION + +#ifdef IMGUI_STB_NAMESPACE +namespace IMGUI_STB_NAMESPACE +{ +#endif + +#ifdef _MSC_VER +#pragma warning (push) +#pragma warning (disable: 4456) // declaration of 'xx' hides previous local declaration +#endif + +#if defined(__clang__) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-function" +#pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wimplicit-fallthrough" +#pragma clang diagnostic ignored "-Wcast-qual" // warning : cast from 'const xxxx *' to 'xxx *' drops const qualifier // +#endif + +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wtype-limits" // warning: comparison is always true due to limited range of data type [-Wtype-limits] +#pragma GCC diagnostic ignored "-Wcast-qual" // warning: cast from type 'const xxxx *' to type 'xxxx *' casts away qualifiers +#endif + +#ifndef STB_RECT_PACK_IMPLEMENTATION // in case the user already have an implementation in the _same_ compilation unit (e.g. unity builds) +#ifndef IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION +#define STBRP_STATIC +#define STBRP_ASSERT(x) do { IM_ASSERT(x); } while (0) +#define STBRP_SORT ImQsort +#define STB_RECT_PACK_IMPLEMENTATION +#endif +#ifdef IMGUI_STB_RECT_PACK_FILENAME +#include IMGUI_STB_RECT_PACK_FILENAME +#else +#include "imstb_rectpack.h" +#endif +#endif + +#ifndef STB_TRUETYPE_IMPLEMENTATION // in case the user already have an implementation in the _same_ compilation unit (e.g. unity builds) +#ifndef IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION +#define STBTT_malloc(x,u) ((void)(u), IM_ALLOC(x)) +#define STBTT_free(x,u) ((void)(u), IM_FREE(x)) +#define STBTT_assert(x) do { IM_ASSERT(x); } while(0) +#define STBTT_fmod(x,y) ImFmod(x,y) +#define STBTT_sqrt(x) ImSqrt(x) +#define STBTT_pow(x,y) ImPow(x,y) +#define STBTT_fabs(x) ImFabs(x) +#define STBTT_ifloor(x) ((int)ImFloorStd(x)) +#define STBTT_iceil(x) ((int)ImCeil(x)) +#define STBTT_STATIC +#define STB_TRUETYPE_IMPLEMENTATION +#else +#define STBTT_DEF extern +#endif +#ifdef IMGUI_STB_TRUETYPE_FILENAME +#include IMGUI_STB_TRUETYPE_FILENAME +#else +#include "imstb_truetype.h" +#endif +#endif + +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif + +#if defined(__clang__) +#pragma clang diagnostic pop +#endif + +#if defined(_MSC_VER) +#pragma warning (pop) +#endif + +#ifdef IMGUI_STB_NAMESPACE +} // namespace ImStb +using namespace IMGUI_STB_NAMESPACE; +#endif + +//----------------------------------------------------------------------------- +// [SECTION] Style functions +//----------------------------------------------------------------------------- + +void ImGui::StyleColorsDark(ImGuiStyle* dst) +{ + ImGuiStyle* style = dst ? dst : &ImGui::GetStyle(); + ImVec4* colors = style->Colors; + + colors[ImGuiCol_Text] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f); + colors[ImGuiCol_TextDisabled] = ImVec4(0.50f, 0.50f, 0.50f, 1.00f); + colors[ImGuiCol_WindowBg] = ImVec4(0.06f, 0.06f, 0.06f, 0.94f); + colors[ImGuiCol_ChildBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); + colors[ImGuiCol_PopupBg] = ImVec4(0.08f, 0.08f, 0.08f, 0.94f); + colors[ImGuiCol_Border] = ImVec4(0.43f, 0.43f, 0.50f, 0.50f); + colors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); + colors[ImGuiCol_FrameBg] = ImVec4(0.16f, 0.29f, 0.48f, 0.54f); + colors[ImGuiCol_FrameBgHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.40f); + colors[ImGuiCol_FrameBgActive] = ImVec4(0.26f, 0.59f, 0.98f, 0.67f); + colors[ImGuiCol_TitleBg] = ImVec4(0.04f, 0.04f, 0.04f, 1.00f); + colors[ImGuiCol_TitleBgActive] = ImVec4(0.16f, 0.29f, 0.48f, 1.00f); + colors[ImGuiCol_TitleBgCollapsed] = ImVec4(0.00f, 0.00f, 0.00f, 0.51f); + colors[ImGuiCol_MenuBarBg] = ImVec4(0.14f, 0.14f, 0.14f, 1.00f); + colors[ImGuiCol_ScrollbarBg] = ImVec4(0.02f, 0.02f, 0.02f, 0.53f); + colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.31f, 0.31f, 0.31f, 1.00f); + colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.41f, 0.41f, 0.41f, 1.00f); + colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.51f, 0.51f, 0.51f, 1.00f); + colors[ImGuiCol_CheckMark] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f); + colors[ImGuiCol_SliderGrab] = ImVec4(0.24f, 0.52f, 0.88f, 1.00f); + colors[ImGuiCol_SliderGrabActive] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f); + colors[ImGuiCol_Button] = ImVec4(0.26f, 0.59f, 0.98f, 0.40f); + colors[ImGuiCol_ButtonHovered] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f); + colors[ImGuiCol_ButtonActive] = ImVec4(0.06f, 0.53f, 0.98f, 1.00f); + colors[ImGuiCol_Header] = ImVec4(0.26f, 0.59f, 0.98f, 0.31f); + colors[ImGuiCol_HeaderHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.80f); + colors[ImGuiCol_HeaderActive] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f); + colors[ImGuiCol_Separator] = colors[ImGuiCol_Border]; + colors[ImGuiCol_SeparatorHovered] = ImVec4(0.10f, 0.40f, 0.75f, 0.78f); + colors[ImGuiCol_SeparatorActive] = ImVec4(0.10f, 0.40f, 0.75f, 1.00f); + colors[ImGuiCol_ResizeGrip] = ImVec4(0.26f, 0.59f, 0.98f, 0.25f); + colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.67f); + colors[ImGuiCol_ResizeGripActive] = ImVec4(0.26f, 0.59f, 0.98f, 0.95f); + colors[ImGuiCol_Tab] = ImLerp(colors[ImGuiCol_Header], colors[ImGuiCol_TitleBgActive], 0.80f); + colors[ImGuiCol_TabHovered] = colors[ImGuiCol_HeaderHovered]; + colors[ImGuiCol_TabActive] = ImLerp(colors[ImGuiCol_HeaderActive], colors[ImGuiCol_TitleBgActive], 0.60f); + colors[ImGuiCol_TabUnfocused] = ImLerp(colors[ImGuiCol_Tab], colors[ImGuiCol_TitleBg], 0.80f); + colors[ImGuiCol_TabUnfocusedActive] = ImLerp(colors[ImGuiCol_TabActive], colors[ImGuiCol_TitleBg], 0.40f); + colors[ImGuiCol_DockingPreview] = colors[ImGuiCol_HeaderActive] * ImVec4(1.0f, 1.0f, 1.0f, 0.7f); + colors[ImGuiCol_DockingEmptyBg] = ImVec4(0.20f, 0.20f, 0.20f, 1.00f); + colors[ImGuiCol_PlotLines] = ImVec4(0.61f, 0.61f, 0.61f, 1.00f); + colors[ImGuiCol_PlotLinesHovered] = ImVec4(1.00f, 0.43f, 0.35f, 1.00f); + colors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f); + colors[ImGuiCol_PlotHistogramHovered] = ImVec4(1.00f, 0.60f, 0.00f, 1.00f); + colors[ImGuiCol_TextSelectedBg] = ImVec4(0.26f, 0.59f, 0.98f, 0.35f); + colors[ImGuiCol_DragDropTarget] = ImVec4(1.00f, 1.00f, 0.00f, 0.90f); + colors[ImGuiCol_NavHighlight] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f); + colors[ImGuiCol_NavWindowingHighlight] = ImVec4(1.00f, 1.00f, 1.00f, 0.70f); + colors[ImGuiCol_NavWindowingDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.20f); + colors[ImGuiCol_ModalWindowDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.35f); +} + +void ImGui::StyleColorsClassic(ImGuiStyle* dst) +{ + ImGuiStyle* style = dst ? dst : &ImGui::GetStyle(); + ImVec4* colors = style->Colors; + + colors[ImGuiCol_Text] = ImVec4(0.90f, 0.90f, 0.90f, 1.00f); + colors[ImGuiCol_TextDisabled] = ImVec4(0.60f, 0.60f, 0.60f, 1.00f); + colors[ImGuiCol_WindowBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.70f); + colors[ImGuiCol_ChildBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); + colors[ImGuiCol_PopupBg] = ImVec4(0.11f, 0.11f, 0.14f, 0.92f); + colors[ImGuiCol_Border] = ImVec4(0.50f, 0.50f, 0.50f, 0.50f); + colors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); + colors[ImGuiCol_FrameBg] = ImVec4(0.43f, 0.43f, 0.43f, 0.39f); + colors[ImGuiCol_FrameBgHovered] = ImVec4(0.47f, 0.47f, 0.69f, 0.40f); + colors[ImGuiCol_FrameBgActive] = ImVec4(0.42f, 0.41f, 0.64f, 0.69f); + colors[ImGuiCol_TitleBg] = ImVec4(0.27f, 0.27f, 0.54f, 0.83f); + colors[ImGuiCol_TitleBgActive] = ImVec4(0.32f, 0.32f, 0.63f, 0.87f); + colors[ImGuiCol_TitleBgCollapsed] = ImVec4(0.40f, 0.40f, 0.80f, 0.20f); + colors[ImGuiCol_MenuBarBg] = ImVec4(0.40f, 0.40f, 0.55f, 0.80f); + colors[ImGuiCol_ScrollbarBg] = ImVec4(0.20f, 0.25f, 0.30f, 0.60f); + colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.40f, 0.40f, 0.80f, 0.30f); + colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.40f, 0.40f, 0.80f, 0.40f); + colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.41f, 0.39f, 0.80f, 0.60f); + colors[ImGuiCol_CheckMark] = ImVec4(0.90f, 0.90f, 0.90f, 0.50f); + colors[ImGuiCol_SliderGrab] = ImVec4(1.00f, 1.00f, 1.00f, 0.30f); + colors[ImGuiCol_SliderGrabActive] = ImVec4(0.41f, 0.39f, 0.80f, 0.60f); + colors[ImGuiCol_Button] = ImVec4(0.35f, 0.40f, 0.61f, 0.62f); + colors[ImGuiCol_ButtonHovered] = ImVec4(0.40f, 0.48f, 0.71f, 0.79f); + colors[ImGuiCol_ButtonActive] = ImVec4(0.46f, 0.54f, 0.80f, 1.00f); + colors[ImGuiCol_Header] = ImVec4(0.40f, 0.40f, 0.90f, 0.45f); + colors[ImGuiCol_HeaderHovered] = ImVec4(0.45f, 0.45f, 0.90f, 0.80f); + colors[ImGuiCol_HeaderActive] = ImVec4(0.53f, 0.53f, 0.87f, 0.80f); + colors[ImGuiCol_Separator] = ImVec4(0.50f, 0.50f, 0.50f, 0.60f); + colors[ImGuiCol_SeparatorHovered] = ImVec4(0.60f, 0.60f, 0.70f, 1.00f); + colors[ImGuiCol_SeparatorActive] = ImVec4(0.70f, 0.70f, 0.90f, 1.00f); + colors[ImGuiCol_ResizeGrip] = ImVec4(1.00f, 1.00f, 1.00f, 0.16f); + colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.78f, 0.82f, 1.00f, 0.60f); + colors[ImGuiCol_ResizeGripActive] = ImVec4(0.78f, 0.82f, 1.00f, 0.90f); + colors[ImGuiCol_Tab] = ImLerp(colors[ImGuiCol_Header], colors[ImGuiCol_TitleBgActive], 0.80f); + colors[ImGuiCol_TabHovered] = colors[ImGuiCol_HeaderHovered]; + colors[ImGuiCol_TabActive] = ImLerp(colors[ImGuiCol_HeaderActive], colors[ImGuiCol_TitleBgActive], 0.60f); + colors[ImGuiCol_TabUnfocused] = ImLerp(colors[ImGuiCol_Tab], colors[ImGuiCol_TitleBg], 0.80f); + colors[ImGuiCol_TabUnfocusedActive] = ImLerp(colors[ImGuiCol_TabActive], colors[ImGuiCol_TitleBg], 0.40f); + colors[ImGuiCol_DockingPreview] = colors[ImGuiCol_Header] * ImVec4(1.0f, 1.0f, 1.0f, 0.7f); + colors[ImGuiCol_DockingEmptyBg] = ImVec4(0.20f, 0.20f, 0.20f, 1.00f); + colors[ImGuiCol_PlotLines] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f); + colors[ImGuiCol_PlotLinesHovered] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f); + colors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f); + colors[ImGuiCol_PlotHistogramHovered] = ImVec4(1.00f, 0.60f, 0.00f, 1.00f); + colors[ImGuiCol_TextSelectedBg] = ImVec4(0.00f, 0.00f, 1.00f, 0.35f); + colors[ImGuiCol_DragDropTarget] = ImVec4(1.00f, 1.00f, 0.00f, 0.90f); + colors[ImGuiCol_NavHighlight] = colors[ImGuiCol_HeaderHovered]; + colors[ImGuiCol_NavWindowingHighlight] = ImVec4(1.00f, 1.00f, 1.00f, 0.70f); + colors[ImGuiCol_NavWindowingDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.20f); + colors[ImGuiCol_ModalWindowDimBg] = ImVec4(0.20f, 0.20f, 0.20f, 0.35f); +} + +// Those light colors are better suited with a thicker font than the default one + FrameBorder +void ImGui::StyleColorsLight(ImGuiStyle* dst) +{ + ImGuiStyle* style = dst ? dst : &ImGui::GetStyle(); + ImVec4* colors = style->Colors; + + colors[ImGuiCol_Text] = ImVec4(0.00f, 0.00f, 0.00f, 1.00f); + colors[ImGuiCol_TextDisabled] = ImVec4(0.60f, 0.60f, 0.60f, 1.00f); + colors[ImGuiCol_WindowBg] = ImVec4(0.94f, 0.94f, 0.94f, 1.00f); + colors[ImGuiCol_ChildBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); + colors[ImGuiCol_PopupBg] = ImVec4(1.00f, 1.00f, 1.00f, 0.98f); + colors[ImGuiCol_Border] = ImVec4(0.00f, 0.00f, 0.00f, 0.30f); + colors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); + colors[ImGuiCol_FrameBg] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f); + colors[ImGuiCol_FrameBgHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.40f); + colors[ImGuiCol_FrameBgActive] = ImVec4(0.26f, 0.59f, 0.98f, 0.67f); + colors[ImGuiCol_TitleBg] = ImVec4(0.96f, 0.96f, 0.96f, 1.00f); + colors[ImGuiCol_TitleBgActive] = ImVec4(0.82f, 0.82f, 0.82f, 1.00f); + colors[ImGuiCol_TitleBgCollapsed] = ImVec4(1.00f, 1.00f, 1.00f, 0.51f); + colors[ImGuiCol_MenuBarBg] = ImVec4(0.86f, 0.86f, 0.86f, 1.00f); + colors[ImGuiCol_ScrollbarBg] = ImVec4(0.98f, 0.98f, 0.98f, 0.53f); + colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.69f, 0.69f, 0.69f, 0.80f); + colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.49f, 0.49f, 0.49f, 0.80f); + colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.49f, 0.49f, 0.49f, 1.00f); + colors[ImGuiCol_CheckMark] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f); + colors[ImGuiCol_SliderGrab] = ImVec4(0.26f, 0.59f, 0.98f, 0.78f); + colors[ImGuiCol_SliderGrabActive] = ImVec4(0.46f, 0.54f, 0.80f, 0.60f); + colors[ImGuiCol_Button] = ImVec4(0.26f, 0.59f, 0.98f, 0.40f); + colors[ImGuiCol_ButtonHovered] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f); + colors[ImGuiCol_ButtonActive] = ImVec4(0.06f, 0.53f, 0.98f, 1.00f); + colors[ImGuiCol_Header] = ImVec4(0.26f, 0.59f, 0.98f, 0.31f); + colors[ImGuiCol_HeaderHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.80f); + colors[ImGuiCol_HeaderActive] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f); + colors[ImGuiCol_Separator] = ImVec4(0.39f, 0.39f, 0.39f, 0.62f); + colors[ImGuiCol_SeparatorHovered] = ImVec4(0.14f, 0.44f, 0.80f, 0.78f); + colors[ImGuiCol_SeparatorActive] = ImVec4(0.14f, 0.44f, 0.80f, 1.00f); + colors[ImGuiCol_ResizeGrip] = ImVec4(0.80f, 0.80f, 0.80f, 0.56f); + colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.67f); + colors[ImGuiCol_ResizeGripActive] = ImVec4(0.26f, 0.59f, 0.98f, 0.95f); + colors[ImGuiCol_Tab] = ImLerp(colors[ImGuiCol_Header], colors[ImGuiCol_TitleBgActive], 0.90f); + colors[ImGuiCol_TabHovered] = colors[ImGuiCol_HeaderHovered]; + colors[ImGuiCol_TabActive] = ImLerp(colors[ImGuiCol_HeaderActive], colors[ImGuiCol_TitleBgActive], 0.60f); + colors[ImGuiCol_TabUnfocused] = ImLerp(colors[ImGuiCol_Tab], colors[ImGuiCol_TitleBg], 0.80f); + colors[ImGuiCol_TabUnfocusedActive] = ImLerp(colors[ImGuiCol_TabActive], colors[ImGuiCol_TitleBg], 0.40f); + colors[ImGuiCol_DockingPreview] = colors[ImGuiCol_Header] * ImVec4(1.0f, 1.0f, 1.0f, 0.7f); + colors[ImGuiCol_DockingEmptyBg] = ImVec4(0.20f, 0.20f, 0.20f, 1.00f); + colors[ImGuiCol_PlotLines] = ImVec4(0.39f, 0.39f, 0.39f, 1.00f); + colors[ImGuiCol_PlotLinesHovered] = ImVec4(1.00f, 0.43f, 0.35f, 1.00f); + colors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f); + colors[ImGuiCol_PlotHistogramHovered] = ImVec4(1.00f, 0.45f, 0.00f, 1.00f); + colors[ImGuiCol_TextSelectedBg] = ImVec4(0.26f, 0.59f, 0.98f, 0.35f); + colors[ImGuiCol_DragDropTarget] = ImVec4(0.26f, 0.59f, 0.98f, 0.95f); + colors[ImGuiCol_NavHighlight] = colors[ImGuiCol_HeaderHovered]; + colors[ImGuiCol_NavWindowingHighlight] = ImVec4(0.70f, 0.70f, 0.70f, 0.70f); + colors[ImGuiCol_NavWindowingDimBg] = ImVec4(0.20f, 0.20f, 0.20f, 0.20f); + colors[ImGuiCol_ModalWindowDimBg] = ImVec4(0.20f, 0.20f, 0.20f, 0.35f); +} + +//----------------------------------------------------------------------------- +// ImDrawList +//----------------------------------------------------------------------------- + +ImDrawListSharedData::ImDrawListSharedData() +{ + Font = NULL; + FontSize = 0.0f; + CurveTessellationTol = 0.0f; + CircleSegmentMaxError = 0.0f; + ClipRectFullscreen = ImVec4(-8192.0f, -8192.0f, +8192.0f, +8192.0f); + InitialFlags = ImDrawListFlags_None; + + // Lookup tables + for (int i = 0; i < IM_ARRAYSIZE(ArcFastVtx); i++) + { + const float a = ((float)i * 2 * IM_PI) / (float)IM_ARRAYSIZE(ArcFastVtx); + ArcFastVtx[i] = ImVec2(ImCos(a), ImSin(a)); + } + memset(CircleSegmentCounts, 0, sizeof(CircleSegmentCounts)); // This will be set by SetCircleSegmentMaxError() +} + +void ImDrawListSharedData::SetCircleSegmentMaxError(float max_error) +{ + if (CircleSegmentMaxError == max_error) + return; + CircleSegmentMaxError = max_error; + for (int i = 0; i < IM_ARRAYSIZE(CircleSegmentCounts); i++) + { + const float radius = i + 1.0f; + const int segment_count = IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC(radius, CircleSegmentMaxError); + CircleSegmentCounts[i] = (ImU8)ImMin(segment_count, 255); + } +} + +void ImDrawList::Clear() +{ + CmdBuffer.resize(0); + IdxBuffer.resize(0); + VtxBuffer.resize(0); + Flags = _Data ? _Data->InitialFlags : ImDrawListFlags_None; + _VtxCurrentOffset = 0; + _VtxCurrentIdx = 0; + _VtxWritePtr = NULL; + _IdxWritePtr = NULL; + _ClipRectStack.resize(0); + _TextureIdStack.resize(0); + _Path.resize(0); + _Splitter.Clear(); +} + +void ImDrawList::ClearFreeMemory() +{ + CmdBuffer.clear(); + IdxBuffer.clear(); + VtxBuffer.clear(); + _VtxCurrentIdx = 0; + _VtxWritePtr = NULL; + _IdxWritePtr = NULL; + _ClipRectStack.clear(); + _TextureIdStack.clear(); + _Path.clear(); + _Splitter.ClearFreeMemory(); +} + +ImDrawList* ImDrawList::CloneOutput() const +{ + ImDrawList* dst = IM_NEW(ImDrawList(_Data)); + dst->CmdBuffer = CmdBuffer; + dst->IdxBuffer = IdxBuffer; + dst->VtxBuffer = VtxBuffer; + dst->Flags = Flags; + return dst; +} + +// Using macros because C++ is a terrible language, we want guaranteed inline, no code in header, and no overhead in Debug builds +#define GetCurrentClipRect() (_ClipRectStack.Size ? _ClipRectStack.Data[_ClipRectStack.Size-1] : _Data->ClipRectFullscreen) +#define GetCurrentTextureId() (_TextureIdStack.Size ? _TextureIdStack.Data[_TextureIdStack.Size-1] : (ImTextureID)NULL) + +void ImDrawList::AddDrawCmd() +{ + ImDrawCmd draw_cmd; + draw_cmd.ClipRect = GetCurrentClipRect(); + draw_cmd.TextureId = GetCurrentTextureId(); + draw_cmd.VtxOffset = _VtxCurrentOffset; + draw_cmd.IdxOffset = IdxBuffer.Size; + + IM_ASSERT(draw_cmd.ClipRect.x <= draw_cmd.ClipRect.z && draw_cmd.ClipRect.y <= draw_cmd.ClipRect.w); + CmdBuffer.push_back(draw_cmd); +} + +void ImDrawList::AddCallback(ImDrawCallback callback, void* callback_data) +{ + ImDrawCmd* current_cmd = CmdBuffer.Size ? &CmdBuffer.back() : NULL; + if (!current_cmd || current_cmd->ElemCount != 0 || current_cmd->UserCallback != NULL) + { + AddDrawCmd(); + current_cmd = &CmdBuffer.back(); + } + current_cmd->UserCallback = callback; + current_cmd->UserCallbackData = callback_data; + + AddDrawCmd(); // Force a new command after us (see comment below) +} + +// Our scheme may appears a bit unusual, basically we want the most-common calls AddLine AddRect etc. to not have to perform any check so we always have a command ready in the stack. +// The cost of figuring out if a new command has to be added or if we can merge is paid in those Update** functions only. +void ImDrawList::UpdateClipRect() +{ + // If current command is used with different settings we need to add a new command + const ImVec4 curr_clip_rect = GetCurrentClipRect(); + ImDrawCmd* curr_cmd = CmdBuffer.Size > 0 ? &CmdBuffer.Data[CmdBuffer.Size-1] : NULL; + if (!curr_cmd || (curr_cmd->ElemCount != 0 && memcmp(&curr_cmd->ClipRect, &curr_clip_rect, sizeof(ImVec4)) != 0) || curr_cmd->UserCallback != NULL) + { + AddDrawCmd(); + return; + } + + // Try to merge with previous command if it matches, else use current command + ImDrawCmd* prev_cmd = CmdBuffer.Size > 1 ? curr_cmd - 1 : NULL; + if (curr_cmd->ElemCount == 0 && prev_cmd && memcmp(&prev_cmd->ClipRect, &curr_clip_rect, sizeof(ImVec4)) == 0 && prev_cmd->TextureId == GetCurrentTextureId() && prev_cmd->UserCallback == NULL) + CmdBuffer.pop_back(); + else + curr_cmd->ClipRect = curr_clip_rect; +} + +void ImDrawList::UpdateTextureID() +{ + // If current command is used with different settings we need to add a new command + const ImTextureID curr_texture_id = GetCurrentTextureId(); + ImDrawCmd* curr_cmd = CmdBuffer.Size ? &CmdBuffer.back() : NULL; + if (!curr_cmd || (curr_cmd->ElemCount != 0 && curr_cmd->TextureId != curr_texture_id) || curr_cmd->UserCallback != NULL) + { + AddDrawCmd(); + return; + } + + // Try to merge with previous command if it matches, else use current command + ImDrawCmd* prev_cmd = CmdBuffer.Size > 1 ? curr_cmd - 1 : NULL; + if (curr_cmd->ElemCount == 0 && prev_cmd && prev_cmd->TextureId == curr_texture_id && memcmp(&prev_cmd->ClipRect, &GetCurrentClipRect(), sizeof(ImVec4)) == 0 && prev_cmd->UserCallback == NULL) + CmdBuffer.pop_back(); + else + curr_cmd->TextureId = curr_texture_id; +} + +#undef GetCurrentClipRect +#undef GetCurrentTextureId + +// Render-level scissoring. This is passed down to your render function but not used for CPU-side coarse clipping. Prefer using higher-level ImGui::PushClipRect() to affect logic (hit-testing and widget culling) +void ImDrawList::PushClipRect(ImVec2 cr_min, ImVec2 cr_max, bool intersect_with_current_clip_rect) +{ + ImVec4 cr(cr_min.x, cr_min.y, cr_max.x, cr_max.y); + if (intersect_with_current_clip_rect && _ClipRectStack.Size) + { + ImVec4 current = _ClipRectStack.Data[_ClipRectStack.Size-1]; + if (cr.x < current.x) cr.x = current.x; + if (cr.y < current.y) cr.y = current.y; + if (cr.z > current.z) cr.z = current.z; + if (cr.w > current.w) cr.w = current.w; + } + cr.z = ImMax(cr.x, cr.z); + cr.w = ImMax(cr.y, cr.w); + + _ClipRectStack.push_back(cr); + UpdateClipRect(); +} + +void ImDrawList::PushClipRectFullScreen() +{ + PushClipRect(ImVec2(_Data->ClipRectFullscreen.x, _Data->ClipRectFullscreen.y), ImVec2(_Data->ClipRectFullscreen.z, _Data->ClipRectFullscreen.w)); +} + +void ImDrawList::PopClipRect() +{ + IM_ASSERT(_ClipRectStack.Size > 0); + _ClipRectStack.pop_back(); + UpdateClipRect(); +} + +void ImDrawList::PushTextureID(ImTextureID texture_id) +{ + _TextureIdStack.push_back(texture_id); + UpdateTextureID(); +} + +void ImDrawList::PopTextureID() +{ + IM_ASSERT(_TextureIdStack.Size > 0); + _TextureIdStack.pop_back(); + UpdateTextureID(); +} + +// Reserve space for a number of vertices and indices. +// You must finish filling your reserved data before calling PrimReserve() again, as it may reallocate or +// submit the intermediate results. PrimUnreserve() can be used to release unused allocations. +void ImDrawList::PrimReserve(int idx_count, int vtx_count) +{ + // Large mesh support (when enabled) + IM_ASSERT_PARANOID(idx_count >= 0 && vtx_count >= 0); + if (sizeof(ImDrawIdx) == 2 && (_VtxCurrentIdx + vtx_count >= (1 << 16)) && (Flags & ImDrawListFlags_AllowVtxOffset)) + { + _VtxCurrentOffset = VtxBuffer.Size; + _VtxCurrentIdx = 0; + AddDrawCmd(); + } + + ImDrawCmd& draw_cmd = CmdBuffer.Data[CmdBuffer.Size - 1]; + draw_cmd.ElemCount += idx_count; + + int vtx_buffer_old_size = VtxBuffer.Size; + VtxBuffer.resize(vtx_buffer_old_size + vtx_count); + _VtxWritePtr = VtxBuffer.Data + vtx_buffer_old_size; + + int idx_buffer_old_size = IdxBuffer.Size; + IdxBuffer.resize(idx_buffer_old_size + idx_count); + _IdxWritePtr = IdxBuffer.Data + idx_buffer_old_size; +} + +// Release the a number of reserved vertices/indices from the end of the last reservation made with PrimReserve(). +void ImDrawList::PrimUnreserve(int idx_count, int vtx_count) +{ + IM_ASSERT_PARANOID(idx_count >= 0 && vtx_count >= 0); + + ImDrawCmd& draw_cmd = CmdBuffer.Data[CmdBuffer.Size - 1]; + draw_cmd.ElemCount -= idx_count; + VtxBuffer.shrink(VtxBuffer.Size - vtx_count); + IdxBuffer.shrink(IdxBuffer.Size - idx_count); +} + +// Fully unrolled with inline call to keep our debug builds decently fast. +void ImDrawList::PrimRect(const ImVec2& a, const ImVec2& c, ImU32 col) +{ + ImVec2 b(c.x, a.y), d(a.x, c.y), uv(_Data->TexUvWhitePixel); + ImDrawIdx idx = (ImDrawIdx)_VtxCurrentIdx; + _IdxWritePtr[0] = idx; _IdxWritePtr[1] = (ImDrawIdx)(idx+1); _IdxWritePtr[2] = (ImDrawIdx)(idx+2); + _IdxWritePtr[3] = idx; _IdxWritePtr[4] = (ImDrawIdx)(idx+2); _IdxWritePtr[5] = (ImDrawIdx)(idx+3); + _VtxWritePtr[0].pos = a; _VtxWritePtr[0].uv = uv; _VtxWritePtr[0].col = col; + _VtxWritePtr[1].pos = b; _VtxWritePtr[1].uv = uv; _VtxWritePtr[1].col = col; + _VtxWritePtr[2].pos = c; _VtxWritePtr[2].uv = uv; _VtxWritePtr[2].col = col; + _VtxWritePtr[3].pos = d; _VtxWritePtr[3].uv = uv; _VtxWritePtr[3].col = col; + _VtxWritePtr += 4; + _VtxCurrentIdx += 4; + _IdxWritePtr += 6; +} + +void ImDrawList::PrimRectUV(const ImVec2& a, const ImVec2& c, const ImVec2& uv_a, const ImVec2& uv_c, ImU32 col) +{ + ImVec2 b(c.x, a.y), d(a.x, c.y), uv_b(uv_c.x, uv_a.y), uv_d(uv_a.x, uv_c.y); + ImDrawIdx idx = (ImDrawIdx)_VtxCurrentIdx; + _IdxWritePtr[0] = idx; _IdxWritePtr[1] = (ImDrawIdx)(idx+1); _IdxWritePtr[2] = (ImDrawIdx)(idx+2); + _IdxWritePtr[3] = idx; _IdxWritePtr[4] = (ImDrawIdx)(idx+2); _IdxWritePtr[5] = (ImDrawIdx)(idx+3); + _VtxWritePtr[0].pos = a; _VtxWritePtr[0].uv = uv_a; _VtxWritePtr[0].col = col; + _VtxWritePtr[1].pos = b; _VtxWritePtr[1].uv = uv_b; _VtxWritePtr[1].col = col; + _VtxWritePtr[2].pos = c; _VtxWritePtr[2].uv = uv_c; _VtxWritePtr[2].col = col; + _VtxWritePtr[3].pos = d; _VtxWritePtr[3].uv = uv_d; _VtxWritePtr[3].col = col; + _VtxWritePtr += 4; + _VtxCurrentIdx += 4; + _IdxWritePtr += 6; +} + +void ImDrawList::PrimQuadUV(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& d, const ImVec2& uv_a, const ImVec2& uv_b, const ImVec2& uv_c, const ImVec2& uv_d, ImU32 col) +{ + ImDrawIdx idx = (ImDrawIdx)_VtxCurrentIdx; + _IdxWritePtr[0] = idx; _IdxWritePtr[1] = (ImDrawIdx)(idx+1); _IdxWritePtr[2] = (ImDrawIdx)(idx+2); + _IdxWritePtr[3] = idx; _IdxWritePtr[4] = (ImDrawIdx)(idx+2); _IdxWritePtr[5] = (ImDrawIdx)(idx+3); + _VtxWritePtr[0].pos = a; _VtxWritePtr[0].uv = uv_a; _VtxWritePtr[0].col = col; + _VtxWritePtr[1].pos = b; _VtxWritePtr[1].uv = uv_b; _VtxWritePtr[1].col = col; + _VtxWritePtr[2].pos = c; _VtxWritePtr[2].uv = uv_c; _VtxWritePtr[2].col = col; + _VtxWritePtr[3].pos = d; _VtxWritePtr[3].uv = uv_d; _VtxWritePtr[3].col = col; + _VtxWritePtr += 4; + _VtxCurrentIdx += 4; + _IdxWritePtr += 6; +} + +// On AddPolyline() and AddConvexPolyFilled() we intentionally avoid using ImVec2 and superfluous function calls to optimize debug/non-inlined builds. +// Those macros expects l-values. +#define IM_NORMALIZE2F_OVER_ZERO(VX,VY) do { float d2 = VX*VX + VY*VY; if (d2 > 0.0f) { float inv_len = 1.0f / ImSqrt(d2); VX *= inv_len; VY *= inv_len; } } while (0) +#define IM_FIXNORMAL2F(VX,VY) do { float d2 = VX*VX + VY*VY; if (d2 < 0.5f) d2 = 0.5f; float inv_lensq = 1.0f / d2; VX *= inv_lensq; VY *= inv_lensq; } while (0) + +// TODO: Thickness anti-aliased lines cap are missing their AA fringe. +// We avoid using the ImVec2 math operators here to reduce cost to a minimum for debug/non-inlined builds. +void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32 col, bool closed, float thickness) +{ + if (points_count < 2) + return; + + const ImVec2 uv = _Data->TexUvWhitePixel; + + int count = points_count; + if (!closed) + count = points_count-1; + + const bool thick_line = thickness > 1.0f; + if (Flags & ImDrawListFlags_AntiAliasedLines) + { + // Anti-aliased stroke + const float AA_SIZE = 1.0f; + const ImU32 col_trans = col & ~IM_COL32_A_MASK; + + const int idx_count = thick_line ? count*18 : count*12; + const int vtx_count = thick_line ? points_count*4 : points_count*3; + PrimReserve(idx_count, vtx_count); + + // Temporary buffer + ImVec2* temp_normals = (ImVec2*)alloca(points_count * (thick_line ? 5 : 3) * sizeof(ImVec2)); //-V630 + ImVec2* temp_points = temp_normals + points_count; + + for (int i1 = 0; i1 < count; i1++) + { + const int i2 = (i1+1) == points_count ? 0 : i1+1; + float dx = points[i2].x - points[i1].x; + float dy = points[i2].y - points[i1].y; + IM_NORMALIZE2F_OVER_ZERO(dx, dy); + temp_normals[i1].x = dy; + temp_normals[i1].y = -dx; + } + if (!closed) + temp_normals[points_count-1] = temp_normals[points_count-2]; + + if (!thick_line) + { + if (!closed) + { + temp_points[0] = points[0] + temp_normals[0] * AA_SIZE; + temp_points[1] = points[0] - temp_normals[0] * AA_SIZE; + temp_points[(points_count-1)*2+0] = points[points_count-1] + temp_normals[points_count-1] * AA_SIZE; + temp_points[(points_count-1)*2+1] = points[points_count-1] - temp_normals[points_count-1] * AA_SIZE; + } + + // FIXME-OPT: Merge the different loops, possibly remove the temporary buffer. + unsigned int idx1 = _VtxCurrentIdx; + for (int i1 = 0; i1 < count; i1++) + { + const int i2 = (i1+1) == points_count ? 0 : i1+1; + unsigned int idx2 = (i1+1) == points_count ? _VtxCurrentIdx : idx1+3; + + // Average normals + float dm_x = (temp_normals[i1].x + temp_normals[i2].x) * 0.5f; + float dm_y = (temp_normals[i1].y + temp_normals[i2].y) * 0.5f; + IM_FIXNORMAL2F(dm_x, dm_y); + dm_x *= AA_SIZE; + dm_y *= AA_SIZE; + + // Add temporary vertices + ImVec2* out_vtx = &temp_points[i2*2]; + out_vtx[0].x = points[i2].x + dm_x; + out_vtx[0].y = points[i2].y + dm_y; + out_vtx[1].x = points[i2].x - dm_x; + out_vtx[1].y = points[i2].y - dm_y; + + // Add indexes + _IdxWritePtr[0] = (ImDrawIdx)(idx2+0); _IdxWritePtr[1] = (ImDrawIdx)(idx1+0); _IdxWritePtr[2] = (ImDrawIdx)(idx1+2); + _IdxWritePtr[3] = (ImDrawIdx)(idx1+2); _IdxWritePtr[4] = (ImDrawIdx)(idx2+2); _IdxWritePtr[5] = (ImDrawIdx)(idx2+0); + _IdxWritePtr[6] = (ImDrawIdx)(idx2+1); _IdxWritePtr[7] = (ImDrawIdx)(idx1+1); _IdxWritePtr[8] = (ImDrawIdx)(idx1+0); + _IdxWritePtr[9] = (ImDrawIdx)(idx1+0); _IdxWritePtr[10]= (ImDrawIdx)(idx2+0); _IdxWritePtr[11]= (ImDrawIdx)(idx2+1); + _IdxWritePtr += 12; + + idx1 = idx2; + } + + // Add vertices + for (int i = 0; i < points_count; i++) + { + _VtxWritePtr[0].pos = points[i]; _VtxWritePtr[0].uv = uv; _VtxWritePtr[0].col = col; + _VtxWritePtr[1].pos = temp_points[i*2+0]; _VtxWritePtr[1].uv = uv; _VtxWritePtr[1].col = col_trans; + _VtxWritePtr[2].pos = temp_points[i*2+1]; _VtxWritePtr[2].uv = uv; _VtxWritePtr[2].col = col_trans; + _VtxWritePtr += 3; + } + } + else + { + const float half_inner_thickness = (thickness - AA_SIZE) * 0.5f; + if (!closed) + { + temp_points[0] = points[0] + temp_normals[0] * (half_inner_thickness + AA_SIZE); + temp_points[1] = points[0] + temp_normals[0] * (half_inner_thickness); + temp_points[2] = points[0] - temp_normals[0] * (half_inner_thickness); + temp_points[3] = points[0] - temp_normals[0] * (half_inner_thickness + AA_SIZE); + temp_points[(points_count-1)*4+0] = points[points_count-1] + temp_normals[points_count-1] * (half_inner_thickness + AA_SIZE); + temp_points[(points_count-1)*4+1] = points[points_count-1] + temp_normals[points_count-1] * (half_inner_thickness); + temp_points[(points_count-1)*4+2] = points[points_count-1] - temp_normals[points_count-1] * (half_inner_thickness); + temp_points[(points_count-1)*4+3] = points[points_count-1] - temp_normals[points_count-1] * (half_inner_thickness + AA_SIZE); + } + + // FIXME-OPT: Merge the different loops, possibly remove the temporary buffer. + unsigned int idx1 = _VtxCurrentIdx; + for (int i1 = 0; i1 < count; i1++) + { + const int i2 = (i1+1) == points_count ? 0 : i1+1; + unsigned int idx2 = (i1+1) == points_count ? _VtxCurrentIdx : idx1+4; + + // Average normals + float dm_x = (temp_normals[i1].x + temp_normals[i2].x) * 0.5f; + float dm_y = (temp_normals[i1].y + temp_normals[i2].y) * 0.5f; + IM_FIXNORMAL2F(dm_x, dm_y); + float dm_out_x = dm_x * (half_inner_thickness + AA_SIZE); + float dm_out_y = dm_y * (half_inner_thickness + AA_SIZE); + float dm_in_x = dm_x * half_inner_thickness; + float dm_in_y = dm_y * half_inner_thickness; + + // Add temporary vertices + ImVec2* out_vtx = &temp_points[i2*4]; + out_vtx[0].x = points[i2].x + dm_out_x; + out_vtx[0].y = points[i2].y + dm_out_y; + out_vtx[1].x = points[i2].x + dm_in_x; + out_vtx[1].y = points[i2].y + dm_in_y; + out_vtx[2].x = points[i2].x - dm_in_x; + out_vtx[2].y = points[i2].y - dm_in_y; + out_vtx[3].x = points[i2].x - dm_out_x; + out_vtx[3].y = points[i2].y - dm_out_y; + + // Add indexes + _IdxWritePtr[0] = (ImDrawIdx)(idx2+1); _IdxWritePtr[1] = (ImDrawIdx)(idx1+1); _IdxWritePtr[2] = (ImDrawIdx)(idx1+2); + _IdxWritePtr[3] = (ImDrawIdx)(idx1+2); _IdxWritePtr[4] = (ImDrawIdx)(idx2+2); _IdxWritePtr[5] = (ImDrawIdx)(idx2+1); + _IdxWritePtr[6] = (ImDrawIdx)(idx2+1); _IdxWritePtr[7] = (ImDrawIdx)(idx1+1); _IdxWritePtr[8] = (ImDrawIdx)(idx1+0); + _IdxWritePtr[9] = (ImDrawIdx)(idx1+0); _IdxWritePtr[10] = (ImDrawIdx)(idx2+0); _IdxWritePtr[11] = (ImDrawIdx)(idx2+1); + _IdxWritePtr[12] = (ImDrawIdx)(idx2+2); _IdxWritePtr[13] = (ImDrawIdx)(idx1+2); _IdxWritePtr[14] = (ImDrawIdx)(idx1+3); + _IdxWritePtr[15] = (ImDrawIdx)(idx1+3); _IdxWritePtr[16] = (ImDrawIdx)(idx2+3); _IdxWritePtr[17] = (ImDrawIdx)(idx2+2); + _IdxWritePtr += 18; + + idx1 = idx2; + } + + // Add vertices + for (int i = 0; i < points_count; i++) + { + _VtxWritePtr[0].pos = temp_points[i*4+0]; _VtxWritePtr[0].uv = uv; _VtxWritePtr[0].col = col_trans; + _VtxWritePtr[1].pos = temp_points[i*4+1]; _VtxWritePtr[1].uv = uv; _VtxWritePtr[1].col = col; + _VtxWritePtr[2].pos = temp_points[i*4+2]; _VtxWritePtr[2].uv = uv; _VtxWritePtr[2].col = col; + _VtxWritePtr[3].pos = temp_points[i*4+3]; _VtxWritePtr[3].uv = uv; _VtxWritePtr[3].col = col_trans; + _VtxWritePtr += 4; + } + } + _VtxCurrentIdx += (ImDrawIdx)vtx_count; + } + else + { + // Non Anti-aliased Stroke + const int idx_count = count*6; + const int vtx_count = count*4; // FIXME-OPT: Not sharing edges + PrimReserve(idx_count, vtx_count); + + for (int i1 = 0; i1 < count; i1++) + { + const int i2 = (i1+1) == points_count ? 0 : i1+1; + const ImVec2& p1 = points[i1]; + const ImVec2& p2 = points[i2]; + + float dx = p2.x - p1.x; + float dy = p2.y - p1.y; + IM_NORMALIZE2F_OVER_ZERO(dx, dy); + dx *= (thickness * 0.5f); + dy *= (thickness * 0.5f); + + _VtxWritePtr[0].pos.x = p1.x + dy; _VtxWritePtr[0].pos.y = p1.y - dx; _VtxWritePtr[0].uv = uv; _VtxWritePtr[0].col = col; + _VtxWritePtr[1].pos.x = p2.x + dy; _VtxWritePtr[1].pos.y = p2.y - dx; _VtxWritePtr[1].uv = uv; _VtxWritePtr[1].col = col; + _VtxWritePtr[2].pos.x = p2.x - dy; _VtxWritePtr[2].pos.y = p2.y + dx; _VtxWritePtr[2].uv = uv; _VtxWritePtr[2].col = col; + _VtxWritePtr[3].pos.x = p1.x - dy; _VtxWritePtr[3].pos.y = p1.y + dx; _VtxWritePtr[3].uv = uv; _VtxWritePtr[3].col = col; + _VtxWritePtr += 4; + + _IdxWritePtr[0] = (ImDrawIdx)(_VtxCurrentIdx); _IdxWritePtr[1] = (ImDrawIdx)(_VtxCurrentIdx+1); _IdxWritePtr[2] = (ImDrawIdx)(_VtxCurrentIdx+2); + _IdxWritePtr[3] = (ImDrawIdx)(_VtxCurrentIdx); _IdxWritePtr[4] = (ImDrawIdx)(_VtxCurrentIdx+2); _IdxWritePtr[5] = (ImDrawIdx)(_VtxCurrentIdx+3); + _IdxWritePtr += 6; + _VtxCurrentIdx += 4; + } + } +} + +// We intentionally avoid using ImVec2 and its math operators here to reduce cost to a minimum for debug/non-inlined builds. +void ImDrawList::AddConvexPolyFilled(const ImVec2* points, const int points_count, ImU32 col) +{ + if (points_count < 3) + return; + + const ImVec2 uv = _Data->TexUvWhitePixel; + + if (Flags & ImDrawListFlags_AntiAliasedFill) + { + // Anti-aliased Fill + const float AA_SIZE = 1.0f; + const ImU32 col_trans = col & ~IM_COL32_A_MASK; + const int idx_count = (points_count-2)*3 + points_count*6; + const int vtx_count = (points_count*2); + PrimReserve(idx_count, vtx_count); + + // Add indexes for fill + unsigned int vtx_inner_idx = _VtxCurrentIdx; + unsigned int vtx_outer_idx = _VtxCurrentIdx+1; + for (int i = 2; i < points_count; i++) + { + _IdxWritePtr[0] = (ImDrawIdx)(vtx_inner_idx); _IdxWritePtr[1] = (ImDrawIdx)(vtx_inner_idx+((i-1)<<1)); _IdxWritePtr[2] = (ImDrawIdx)(vtx_inner_idx+(i<<1)); + _IdxWritePtr += 3; + } + + // Compute normals + ImVec2* temp_normals = (ImVec2*)alloca(points_count * sizeof(ImVec2)); //-V630 + for (int i0 = points_count-1, i1 = 0; i1 < points_count; i0 = i1++) + { + const ImVec2& p0 = points[i0]; + const ImVec2& p1 = points[i1]; + float dx = p1.x - p0.x; + float dy = p1.y - p0.y; + IM_NORMALIZE2F_OVER_ZERO(dx, dy); + temp_normals[i0].x = dy; + temp_normals[i0].y = -dx; + } + + for (int i0 = points_count-1, i1 = 0; i1 < points_count; i0 = i1++) + { + // Average normals + const ImVec2& n0 = temp_normals[i0]; + const ImVec2& n1 = temp_normals[i1]; + float dm_x = (n0.x + n1.x) * 0.5f; + float dm_y = (n0.y + n1.y) * 0.5f; + IM_FIXNORMAL2F(dm_x, dm_y); + dm_x *= AA_SIZE * 0.5f; + dm_y *= AA_SIZE * 0.5f; + + // Add vertices + _VtxWritePtr[0].pos.x = (points[i1].x - dm_x); _VtxWritePtr[0].pos.y = (points[i1].y - dm_y); _VtxWritePtr[0].uv = uv; _VtxWritePtr[0].col = col; // Inner + _VtxWritePtr[1].pos.x = (points[i1].x + dm_x); _VtxWritePtr[1].pos.y = (points[i1].y + dm_y); _VtxWritePtr[1].uv = uv; _VtxWritePtr[1].col = col_trans; // Outer + _VtxWritePtr += 2; + + // Add indexes for fringes + _IdxWritePtr[0] = (ImDrawIdx)(vtx_inner_idx+(i1<<1)); _IdxWritePtr[1] = (ImDrawIdx)(vtx_inner_idx+(i0<<1)); _IdxWritePtr[2] = (ImDrawIdx)(vtx_outer_idx+(i0<<1)); + _IdxWritePtr[3] = (ImDrawIdx)(vtx_outer_idx+(i0<<1)); _IdxWritePtr[4] = (ImDrawIdx)(vtx_outer_idx+(i1<<1)); _IdxWritePtr[5] = (ImDrawIdx)(vtx_inner_idx+(i1<<1)); + _IdxWritePtr += 6; + } + _VtxCurrentIdx += (ImDrawIdx)vtx_count; + } + else + { + // Non Anti-aliased Fill + const int idx_count = (points_count-2)*3; + const int vtx_count = points_count; + PrimReserve(idx_count, vtx_count); + for (int i = 0; i < vtx_count; i++) + { + _VtxWritePtr[0].pos = points[i]; _VtxWritePtr[0].uv = uv; _VtxWritePtr[0].col = col; + _VtxWritePtr++; + } + for (int i = 2; i < points_count; i++) + { + _IdxWritePtr[0] = (ImDrawIdx)(_VtxCurrentIdx); _IdxWritePtr[1] = (ImDrawIdx)(_VtxCurrentIdx+i-1); _IdxWritePtr[2] = (ImDrawIdx)(_VtxCurrentIdx+i); + _IdxWritePtr += 3; + } + _VtxCurrentIdx += (ImDrawIdx)vtx_count; + } +} + +void ImDrawList::PathArcToFast(const ImVec2& center, float radius, int a_min_of_12, int a_max_of_12) +{ + if (radius == 0.0f || a_min_of_12 > a_max_of_12) + { + _Path.push_back(center); + return; + } + + // For legacy reason the PathArcToFast() always takes angles where 2*PI is represented by 12, + // but it is possible to set IM_DRAWLIST_ARCFAST_TESSELATION_MULTIPLIER to a higher value. This should compile to a no-op otherwise. +#if IM_DRAWLIST_ARCFAST_TESSELLATION_MULTIPLIER != 1 + a_min_of_12 *= IM_DRAWLIST_ARCFAST_TESSELLATION_MULTIPLIER; + a_max_of_12 *= IM_DRAWLIST_ARCFAST_TESSELLATION_MULTIPLIER; +#endif + + _Path.reserve(_Path.Size + (a_max_of_12 - a_min_of_12 + 1)); + for (int a = a_min_of_12; a <= a_max_of_12; a++) + { + const ImVec2& c = _Data->ArcFastVtx[a % IM_ARRAYSIZE(_Data->ArcFastVtx)]; + _Path.push_back(ImVec2(center.x + c.x * radius, center.y + c.y * radius)); + } +} + +void ImDrawList::PathArcTo(const ImVec2& center, float radius, float a_min, float a_max, int num_segments) +{ + if (radius == 0.0f) + { + _Path.push_back(center); + return; + } + + // Note that we are adding a point at both a_min and a_max. + // If you are trying to draw a full closed circle you don't want the overlapping points! + _Path.reserve(_Path.Size + (num_segments + 1)); + for (int i = 0; i <= num_segments; i++) + { + const float a = a_min + ((float)i / (float)num_segments) * (a_max - a_min); + _Path.push_back(ImVec2(center.x + ImCos(a) * radius, center.y + ImSin(a) * radius)); + } +} + +ImVec2 ImBezierCalc(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, float t) +{ + float u = 1.0f - t; + float w1 = u*u*u; + float w2 = 3*u*u*t; + float w3 = 3*u*t*t; + float w4 = t*t*t; + return ImVec2(w1*p1.x + w2*p2.x + w3*p3.x + w4*p4.x, w1*p1.y + w2*p2.y + w3*p3.y + w4*p4.y); +} + +// Closely mimics BezierClosestPointCasteljauStep() in imgui.cpp +static void PathBezierToCasteljau(ImVector* path, float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4, float tess_tol, int level) +{ + float dx = x4 - x1; + float dy = y4 - y1; + float d2 = ((x2 - x4) * dy - (y2 - y4) * dx); + float d3 = ((x3 - x4) * dy - (y3 - y4) * dx); + d2 = (d2 >= 0) ? d2 : -d2; + d3 = (d3 >= 0) ? d3 : -d3; + if ((d2+d3) * (d2+d3) < tess_tol * (dx*dx + dy*dy)) + { + path->push_back(ImVec2(x4, y4)); + } + else if (level < 10) + { + float x12 = (x1+x2)*0.5f, y12 = (y1+y2)*0.5f; + float x23 = (x2+x3)*0.5f, y23 = (y2+y3)*0.5f; + float x34 = (x3+x4)*0.5f, y34 = (y3+y4)*0.5f; + float x123 = (x12+x23)*0.5f, y123 = (y12+y23)*0.5f; + float x234 = (x23+x34)*0.5f, y234 = (y23+y34)*0.5f; + float x1234 = (x123+x234)*0.5f, y1234 = (y123+y234)*0.5f; + PathBezierToCasteljau(path, x1,y1, x12,y12, x123,y123, x1234,y1234, tess_tol, level+1); + PathBezierToCasteljau(path, x1234,y1234, x234,y234, x34,y34, x4,y4, tess_tol, level+1); + } +} + +void ImDrawList::PathBezierCurveTo(const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, int num_segments) +{ + ImVec2 p1 = _Path.back(); + if (num_segments == 0) + { + PathBezierToCasteljau(&_Path, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, p4.x, p4.y, _Data->CurveTessellationTol, 0); // Auto-tessellated + } + else + { + float t_step = 1.0f / (float)num_segments; + for (int i_step = 1; i_step <= num_segments; i_step++) + _Path.push_back(ImBezierCalc(p1, p2, p3, p4, t_step * i_step)); + } +} + +void ImDrawList::PathRect(const ImVec2& a, const ImVec2& b, float rounding, ImDrawCornerFlags rounding_corners) +{ + rounding = ImMin(rounding, ImFabs(b.x - a.x) * ( ((rounding_corners & ImDrawCornerFlags_Top) == ImDrawCornerFlags_Top) || ((rounding_corners & ImDrawCornerFlags_Bot) == ImDrawCornerFlags_Bot) ? 0.5f : 1.0f ) - 1.0f); + rounding = ImMin(rounding, ImFabs(b.y - a.y) * ( ((rounding_corners & ImDrawCornerFlags_Left) == ImDrawCornerFlags_Left) || ((rounding_corners & ImDrawCornerFlags_Right) == ImDrawCornerFlags_Right) ? 0.5f : 1.0f ) - 1.0f); + + if (rounding <= 0.0f || rounding_corners == 0) + { + PathLineTo(a); + PathLineTo(ImVec2(b.x, a.y)); + PathLineTo(b); + PathLineTo(ImVec2(a.x, b.y)); + } + else + { + const float rounding_tl = (rounding_corners & ImDrawCornerFlags_TopLeft) ? rounding : 0.0f; + const float rounding_tr = (rounding_corners & ImDrawCornerFlags_TopRight) ? rounding : 0.0f; + const float rounding_br = (rounding_corners & ImDrawCornerFlags_BotRight) ? rounding : 0.0f; + const float rounding_bl = (rounding_corners & ImDrawCornerFlags_BotLeft) ? rounding : 0.0f; + PathArcToFast(ImVec2(a.x + rounding_tl, a.y + rounding_tl), rounding_tl, 6, 9); + PathArcToFast(ImVec2(b.x - rounding_tr, a.y + rounding_tr), rounding_tr, 9, 12); + PathArcToFast(ImVec2(b.x - rounding_br, b.y - rounding_br), rounding_br, 0, 3); + PathArcToFast(ImVec2(a.x + rounding_bl, b.y - rounding_bl), rounding_bl, 3, 6); + } +} + +void ImDrawList::AddLine(const ImVec2& p1, const ImVec2& p2, ImU32 col, float thickness) +{ + if ((col & IM_COL32_A_MASK) == 0) + return; + PathLineTo(p1 + ImVec2(0.5f, 0.5f)); + PathLineTo(p2 + ImVec2(0.5f, 0.5f)); + PathStroke(col, false, thickness); +} + +// p_min = upper-left, p_max = lower-right +// Note we don't render 1 pixels sized rectangles properly. +void ImDrawList::AddRect(const ImVec2& p_min, const ImVec2& p_max, ImU32 col, float rounding, ImDrawCornerFlags rounding_corners, float thickness) +{ + if ((col & IM_COL32_A_MASK) == 0) + return; + if (Flags & ImDrawListFlags_AntiAliasedLines) + PathRect(p_min + ImVec2(0.50f,0.50f), p_max - ImVec2(0.50f,0.50f), rounding, rounding_corners); + else + PathRect(p_min + ImVec2(0.50f,0.50f), p_max - ImVec2(0.49f,0.49f), rounding, rounding_corners); // Better looking lower-right corner and rounded non-AA shapes. + PathStroke(col, true, thickness); +} + +void ImDrawList::AddRectFilled(const ImVec2& p_min, const ImVec2& p_max, ImU32 col, float rounding, ImDrawCornerFlags rounding_corners) +{ + if ((col & IM_COL32_A_MASK) == 0) + return; + if (rounding > 0.0f) + { + PathRect(p_min, p_max, rounding, rounding_corners); + PathFillConvex(col); + } + else + { + PrimReserve(6, 4); + PrimRect(p_min, p_max, col); + } +} + +// p_min = upper-left, p_max = lower-right +void ImDrawList::AddRectFilledMultiColor(const ImVec2& p_min, const ImVec2& p_max, ImU32 col_upr_left, ImU32 col_upr_right, ImU32 col_bot_right, ImU32 col_bot_left) +{ + if (((col_upr_left | col_upr_right | col_bot_right | col_bot_left) & IM_COL32_A_MASK) == 0) + return; + + const ImVec2 uv = _Data->TexUvWhitePixel; + PrimReserve(6, 4); + PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx)); PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx+1)); PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx+2)); + PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx)); PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx+2)); PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx+3)); + PrimWriteVtx(p_min, uv, col_upr_left); + PrimWriteVtx(ImVec2(p_max.x, p_min.y), uv, col_upr_right); + PrimWriteVtx(p_max, uv, col_bot_right); + PrimWriteVtx(ImVec2(p_min.x, p_max.y), uv, col_bot_left); +} + +void ImDrawList::AddQuad(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, ImU32 col, float thickness) +{ + if ((col & IM_COL32_A_MASK) == 0) + return; + + PathLineTo(p1); + PathLineTo(p2); + PathLineTo(p3); + PathLineTo(p4); + PathStroke(col, true, thickness); +} + +void ImDrawList::AddQuadFilled(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, ImU32 col) +{ + if ((col & IM_COL32_A_MASK) == 0) + return; + + PathLineTo(p1); + PathLineTo(p2); + PathLineTo(p3); + PathLineTo(p4); + PathFillConvex(col); +} + +void ImDrawList::AddTriangle(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, ImU32 col, float thickness) +{ + if ((col & IM_COL32_A_MASK) == 0) + return; + + PathLineTo(p1); + PathLineTo(p2); + PathLineTo(p3); + PathStroke(col, true, thickness); +} + +void ImDrawList::AddTriangleFilled(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, ImU32 col) +{ + if ((col & IM_COL32_A_MASK) == 0) + return; + + PathLineTo(p1); + PathLineTo(p2); + PathLineTo(p3); + PathFillConvex(col); +} + +void ImDrawList::AddCircle(const ImVec2& center, float radius, ImU32 col, int num_segments, float thickness) +{ + if ((col & IM_COL32_A_MASK) == 0 || radius <= 0.0f) + return; + + // Obtain segment count + if (num_segments <= 0) + { + // Automatic segment count + const int radius_idx = (int)radius - 1; + if (radius_idx < IM_ARRAYSIZE(_Data->CircleSegmentCounts)) + num_segments = _Data->CircleSegmentCounts[radius_idx]; // Use cached value + else + num_segments = IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC(radius, _Data->CircleSegmentMaxError); + } + else + { + // Explicit segment count (still clamp to avoid drawing insanely tessellated shapes) + num_segments = ImClamp(num_segments, 3, IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_MAX); + } + + // Because we are filling a closed shape we remove 1 from the count of segments/points + const float a_max = (IM_PI * 2.0f) * ((float)num_segments - 1.0f) / (float)num_segments; + if (num_segments == 12) + PathArcToFast(center, radius - 0.5f, 0, 12); + else + PathArcTo(center, radius - 0.5f, 0.0f, a_max, num_segments - 1); + PathStroke(col, true, thickness); +} + +void ImDrawList::AddCircleFilled(const ImVec2& center, float radius, ImU32 col, int num_segments) +{ + if ((col & IM_COL32_A_MASK) == 0 || radius <= 0.0f) + return; + + // Obtain segment count + if (num_segments <= 0) + { + // Automatic segment count + const int radius_idx = (int)radius - 1; + if (radius_idx < IM_ARRAYSIZE(_Data->CircleSegmentCounts)) + num_segments = _Data->CircleSegmentCounts[radius_idx]; // Use cached value + else + num_segments = IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC(radius, _Data->CircleSegmentMaxError); + } + else + { + // Explicit segment count (still clamp to avoid drawing insanely tessellated shapes) + num_segments = ImClamp(num_segments, 3, IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_MAX); + } + + // Because we are filling a closed shape we remove 1 from the count of segments/points + const float a_max = (IM_PI * 2.0f) * ((float)num_segments - 1.0f) / (float)num_segments; + if (num_segments == 12) + PathArcToFast(center, radius, 0, 12); + else + PathArcTo(center, radius, 0.0f, a_max, num_segments - 1); + PathFillConvex(col); +} + +// Guaranteed to honor 'num_segments' +void ImDrawList::AddNgon(const ImVec2& center, float radius, ImU32 col, int num_segments, float thickness) +{ + if ((col & IM_COL32_A_MASK) == 0 || num_segments <= 2) + return; + + // Because we are filling a closed shape we remove 1 from the count of segments/points + const float a_max = (IM_PI * 2.0f) * ((float)num_segments - 1.0f) / (float)num_segments; + PathArcTo(center, radius - 0.5f, 0.0f, a_max, num_segments - 1); + PathStroke(col, true, thickness); +} + +// Guaranteed to honor 'num_segments' +void ImDrawList::AddNgonFilled(const ImVec2& center, float radius, ImU32 col, int num_segments) +{ + if ((col & IM_COL32_A_MASK) == 0 || num_segments <= 2) + return; + + // Because we are filling a closed shape we remove 1 from the count of segments/points + const float a_max = (IM_PI * 2.0f) * ((float)num_segments - 1.0f) / (float)num_segments; + PathArcTo(center, radius, 0.0f, a_max, num_segments - 1); + PathFillConvex(col); +} + +// Cubic Bezier takes 4 controls points +void ImDrawList::AddBezierCurve(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, ImU32 col, float thickness, int num_segments) +{ + if ((col & IM_COL32_A_MASK) == 0) + return; + + PathLineTo(p1); + PathBezierCurveTo(p2, p3, p4, num_segments); + PathStroke(col, false, thickness); +} + +void ImDrawList::AddText(const ImFont* font, float font_size, const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end, float wrap_width, const ImVec4* cpu_fine_clip_rect) +{ + if ((col & IM_COL32_A_MASK) == 0) + return; + + if (text_end == NULL) + text_end = text_begin + strlen(text_begin); + if (text_begin == text_end) + return; + + // Pull default font/size from the shared ImDrawListSharedData instance + if (font == NULL) + font = _Data->Font; + if (font_size == 0.0f) + font_size = _Data->FontSize; + + IM_ASSERT(font->ContainerAtlas->TexID == _TextureIdStack.back()); // Use high-level ImGui::PushFont() or low-level ImDrawList::PushTextureId() to change font. + + ImVec4 clip_rect = _ClipRectStack.back(); + if (cpu_fine_clip_rect) + { + clip_rect.x = ImMax(clip_rect.x, cpu_fine_clip_rect->x); + clip_rect.y = ImMax(clip_rect.y, cpu_fine_clip_rect->y); + clip_rect.z = ImMin(clip_rect.z, cpu_fine_clip_rect->z); + clip_rect.w = ImMin(clip_rect.w, cpu_fine_clip_rect->w); + } + font->RenderText(this, font_size, pos, col, clip_rect, text_begin, text_end, wrap_width, cpu_fine_clip_rect != NULL); +} + +void ImDrawList::AddText(const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end) +{ + AddText(NULL, 0.0f, pos, col, text_begin, text_end); +} + +void ImDrawList::AddImage(ImTextureID user_texture_id, const ImVec2& p_min, const ImVec2& p_max, const ImVec2& uv_min, const ImVec2& uv_max, ImU32 col) +{ + if ((col & IM_COL32_A_MASK) == 0) + return; + + const bool push_texture_id = _TextureIdStack.empty() || user_texture_id != _TextureIdStack.back(); + if (push_texture_id) + PushTextureID(user_texture_id); + + PrimReserve(6, 4); + PrimRectUV(p_min, p_max, uv_min, uv_max, col); + + if (push_texture_id) + PopTextureID(); +} + +void ImDrawList::AddImageQuad(ImTextureID user_texture_id, const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, const ImVec2& uv1, const ImVec2& uv2, const ImVec2& uv3, const ImVec2& uv4, ImU32 col) +{ + if ((col & IM_COL32_A_MASK) == 0) + return; + + const bool push_texture_id = _TextureIdStack.empty() || user_texture_id != _TextureIdStack.back(); + if (push_texture_id) + PushTextureID(user_texture_id); + + PrimReserve(6, 4); + PrimQuadUV(p1, p2, p3, p4, uv1, uv2, uv3, uv4, col); + + if (push_texture_id) + PopTextureID(); +} + +void ImDrawList::AddImageRounded(ImTextureID user_texture_id, const ImVec2& p_min, const ImVec2& p_max, const ImVec2& uv_min, const ImVec2& uv_max, ImU32 col, float rounding, ImDrawCornerFlags rounding_corners) +{ + if ((col & IM_COL32_A_MASK) == 0) + return; + + if (rounding <= 0.0f || (rounding_corners & ImDrawCornerFlags_All) == 0) + { + AddImage(user_texture_id, p_min, p_max, uv_min, uv_max, col); + return; + } + + const bool push_texture_id = _TextureIdStack.empty() || user_texture_id != _TextureIdStack.back(); + if (push_texture_id) + PushTextureID(user_texture_id); + + int vert_start_idx = VtxBuffer.Size; + PathRect(p_min, p_max, rounding, rounding_corners); + PathFillConvex(col); + int vert_end_idx = VtxBuffer.Size; + ImGui::ShadeVertsLinearUV(this, vert_start_idx, vert_end_idx, p_min, p_max, uv_min, uv_max, true); + + if (push_texture_id) + PopTextureID(); +} + + +//----------------------------------------------------------------------------- +// ImDrawListSplitter +//----------------------------------------------------------------------------- +// FIXME: This may be a little confusing, trying to be a little too low-level/optimal instead of just doing vector swap.. +//----------------------------------------------------------------------------- + +void ImDrawListSplitter::ClearFreeMemory() +{ + for (int i = 0; i < _Channels.Size; i++) + { + if (i == _Current) + memset(&_Channels[i], 0, sizeof(_Channels[i])); // Current channel is a copy of CmdBuffer/IdxBuffer, don't destruct again + _Channels[i]._CmdBuffer.clear(); + _Channels[i]._IdxBuffer.clear(); + } + _Current = 0; + _Count = 1; + _Channels.clear(); +} + +void ImDrawListSplitter::Split(ImDrawList* draw_list, int channels_count) +{ + IM_ASSERT(_Current == 0 && _Count <= 1 && "Nested channel splitting is not supported. Please use separate instances of ImDrawListSplitter."); + int old_channels_count = _Channels.Size; + if (old_channels_count < channels_count) + _Channels.resize(channels_count); + _Count = channels_count; + + // Channels[] (24/32 bytes each) hold storage that we'll swap with draw_list->_CmdBuffer/_IdxBuffer + // The content of Channels[0] at this point doesn't matter. We clear it to make state tidy in a debugger but we don't strictly need to. + // When we switch to the next channel, we'll copy draw_list->_CmdBuffer/_IdxBuffer into Channels[0] and then Channels[1] into draw_list->CmdBuffer/_IdxBuffer + memset(&_Channels[0], 0, sizeof(ImDrawChannel)); + for (int i = 1; i < channels_count; i++) + { + if (i >= old_channels_count) + { + IM_PLACEMENT_NEW(&_Channels[i]) ImDrawChannel(); + } + else + { + _Channels[i]._CmdBuffer.resize(0); + _Channels[i]._IdxBuffer.resize(0); + } + if (_Channels[i]._CmdBuffer.Size == 0) + { + ImDrawCmd draw_cmd; + draw_cmd.ClipRect = draw_list->_ClipRectStack.back(); + draw_cmd.TextureId = draw_list->_TextureIdStack.back(); + _Channels[i]._CmdBuffer.push_back(draw_cmd); + } + } +} + +static inline bool CanMergeDrawCommands(ImDrawCmd* a, ImDrawCmd* b) +{ + return memcmp(&a->ClipRect, &b->ClipRect, sizeof(a->ClipRect)) == 0 && a->TextureId == b->TextureId && a->VtxOffset == b->VtxOffset && !a->UserCallback && !b->UserCallback; +} + +void ImDrawListSplitter::Merge(ImDrawList* draw_list) +{ + // Note that we never use or rely on channels.Size because it is merely a buffer that we never shrink back to 0 to keep all sub-buffers ready for use. + if (_Count <= 1) + return; + + SetCurrentChannel(draw_list, 0); + if (draw_list->CmdBuffer.Size != 0 && draw_list->CmdBuffer.back().ElemCount == 0) + draw_list->CmdBuffer.pop_back(); + + // Calculate our final buffer sizes. Also fix the incorrect IdxOffset values in each command. + int new_cmd_buffer_count = 0; + int new_idx_buffer_count = 0; + ImDrawCmd* last_cmd = (_Count > 0 && draw_list->CmdBuffer.Size > 0) ? &draw_list->CmdBuffer.back() : NULL; + int idx_offset = last_cmd ? last_cmd->IdxOffset + last_cmd->ElemCount : 0; + for (int i = 1; i < _Count; i++) + { + ImDrawChannel& ch = _Channels[i]; + if (ch._CmdBuffer.Size > 0 && ch._CmdBuffer.back().ElemCount == 0) + ch._CmdBuffer.pop_back(); + if (ch._CmdBuffer.Size > 0 && last_cmd != NULL && CanMergeDrawCommands(last_cmd, &ch._CmdBuffer[0])) + { + // Merge previous channel last draw command with current channel first draw command if matching. + last_cmd->ElemCount += ch._CmdBuffer[0].ElemCount; + idx_offset += ch._CmdBuffer[0].ElemCount; + ch._CmdBuffer.erase(ch._CmdBuffer.Data); // FIXME-OPT: Improve for multiple merges. + } + if (ch._CmdBuffer.Size > 0) + last_cmd = &ch._CmdBuffer.back(); + new_cmd_buffer_count += ch._CmdBuffer.Size; + new_idx_buffer_count += ch._IdxBuffer.Size; + for (int cmd_n = 0; cmd_n < ch._CmdBuffer.Size; cmd_n++) + { + ch._CmdBuffer.Data[cmd_n].IdxOffset = idx_offset; + idx_offset += ch._CmdBuffer.Data[cmd_n].ElemCount; + } + } + draw_list->CmdBuffer.resize(draw_list->CmdBuffer.Size + new_cmd_buffer_count); + draw_list->IdxBuffer.resize(draw_list->IdxBuffer.Size + new_idx_buffer_count); + + // Write commands and indices in order (they are fairly small structures, we don't copy vertices only indices) + ImDrawCmd* cmd_write = draw_list->CmdBuffer.Data + draw_list->CmdBuffer.Size - new_cmd_buffer_count; + ImDrawIdx* idx_write = draw_list->IdxBuffer.Data + draw_list->IdxBuffer.Size - new_idx_buffer_count; + for (int i = 1; i < _Count; i++) + { + ImDrawChannel& ch = _Channels[i]; + if (int sz = ch._CmdBuffer.Size) { memcpy(cmd_write, ch._CmdBuffer.Data, sz * sizeof(ImDrawCmd)); cmd_write += sz; } + if (int sz = ch._IdxBuffer.Size) { memcpy(idx_write, ch._IdxBuffer.Data, sz * sizeof(ImDrawIdx)); idx_write += sz; } + } + draw_list->_IdxWritePtr = idx_write; + draw_list->UpdateClipRect(); // We call this instead of AddDrawCmd(), so that empty channels won't produce an extra draw call. + draw_list->UpdateTextureID(); + _Count = 1; +} + +void ImDrawListSplitter::SetCurrentChannel(ImDrawList* draw_list, int idx) +{ + IM_ASSERT(idx >= 0 && idx < _Count); + if (_Current == idx) + return; + // Overwrite ImVector (12/16 bytes), four times. This is merely a silly optimization instead of doing .swap() + memcpy(&_Channels.Data[_Current]._CmdBuffer, &draw_list->CmdBuffer, sizeof(draw_list->CmdBuffer)); + memcpy(&_Channels.Data[_Current]._IdxBuffer, &draw_list->IdxBuffer, sizeof(draw_list->IdxBuffer)); + _Current = idx; + memcpy(&draw_list->CmdBuffer, &_Channels.Data[idx]._CmdBuffer, sizeof(draw_list->CmdBuffer)); + memcpy(&draw_list->IdxBuffer, &_Channels.Data[idx]._IdxBuffer, sizeof(draw_list->IdxBuffer)); + draw_list->_IdxWritePtr = draw_list->IdxBuffer.Data + draw_list->IdxBuffer.Size; +} + +//----------------------------------------------------------------------------- +// [SECTION] ImDrawData +//----------------------------------------------------------------------------- + +// For backward compatibility: convert all buffers from indexed to de-indexed, in case you cannot render indexed. Note: this is slow and most likely a waste of resources. Always prefer indexed rendering! +void ImDrawData::DeIndexAllBuffers() +{ + ImVector new_vtx_buffer; + TotalVtxCount = TotalIdxCount = 0; + for (int i = 0; i < CmdListsCount; i++) + { + ImDrawList* cmd_list = CmdLists[i]; + if (cmd_list->IdxBuffer.empty()) + continue; + new_vtx_buffer.resize(cmd_list->IdxBuffer.Size); + for (int j = 0; j < cmd_list->IdxBuffer.Size; j++) + new_vtx_buffer[j] = cmd_list->VtxBuffer[cmd_list->IdxBuffer[j]]; + cmd_list->VtxBuffer.swap(new_vtx_buffer); + cmd_list->IdxBuffer.resize(0); + TotalVtxCount += cmd_list->VtxBuffer.Size; + } +} + +// Helper to scale the ClipRect field of each ImDrawCmd. +// Use if your final output buffer is at a different scale than draw_data->DisplaySize, +// or if there is a difference between your window resolution and framebuffer resolution. +void ImDrawData::ScaleClipRects(const ImVec2& fb_scale) +{ + for (int i = 0; i < CmdListsCount; i++) + { + ImDrawList* cmd_list = CmdLists[i]; + for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) + { + ImDrawCmd* cmd = &cmd_list->CmdBuffer[cmd_i]; + cmd->ClipRect = ImVec4(cmd->ClipRect.x * fb_scale.x, cmd->ClipRect.y * fb_scale.y, cmd->ClipRect.z * fb_scale.x, cmd->ClipRect.w * fb_scale.y); + } + } +} + +//----------------------------------------------------------------------------- +// [SECTION] Helpers ShadeVertsXXX functions +//----------------------------------------------------------------------------- + +// Generic linear color gradient, write to RGB fields, leave A untouched. +void ImGui::ShadeVertsLinearColorGradientKeepAlpha(ImDrawList* draw_list, int vert_start_idx, int vert_end_idx, ImVec2 gradient_p0, ImVec2 gradient_p1, ImU32 col0, ImU32 col1) +{ + ImVec2 gradient_extent = gradient_p1 - gradient_p0; + float gradient_inv_length2 = 1.0f / ImLengthSqr(gradient_extent); + ImDrawVert* vert_start = draw_list->VtxBuffer.Data + vert_start_idx; + ImDrawVert* vert_end = draw_list->VtxBuffer.Data + vert_end_idx; + for (ImDrawVert* vert = vert_start; vert < vert_end; vert++) + { + float d = ImDot(vert->pos - gradient_p0, gradient_extent); + float t = ImClamp(d * gradient_inv_length2, 0.0f, 1.0f); + int r = ImLerp((int)(col0 >> IM_COL32_R_SHIFT) & 0xFF, (int)(col1 >> IM_COL32_R_SHIFT) & 0xFF, t); + int g = ImLerp((int)(col0 >> IM_COL32_G_SHIFT) & 0xFF, (int)(col1 >> IM_COL32_G_SHIFT) & 0xFF, t); + int b = ImLerp((int)(col0 >> IM_COL32_B_SHIFT) & 0xFF, (int)(col1 >> IM_COL32_B_SHIFT) & 0xFF, t); + vert->col = (r << IM_COL32_R_SHIFT) | (g << IM_COL32_G_SHIFT) | (b << IM_COL32_B_SHIFT) | (vert->col & IM_COL32_A_MASK); + } +} + +// Distribute UV over (a, b) rectangle +void ImGui::ShadeVertsLinearUV(ImDrawList* draw_list, int vert_start_idx, int vert_end_idx, const ImVec2& a, const ImVec2& b, const ImVec2& uv_a, const ImVec2& uv_b, bool clamp) +{ + const ImVec2 size = b - a; + const ImVec2 uv_size = uv_b - uv_a; + const ImVec2 scale = ImVec2( + size.x != 0.0f ? (uv_size.x / size.x) : 0.0f, + size.y != 0.0f ? (uv_size.y / size.y) : 0.0f); + + ImDrawVert* vert_start = draw_list->VtxBuffer.Data + vert_start_idx; + ImDrawVert* vert_end = draw_list->VtxBuffer.Data + vert_end_idx; + if (clamp) + { + const ImVec2 min = ImMin(uv_a, uv_b); + const ImVec2 max = ImMax(uv_a, uv_b); + for (ImDrawVert* vertex = vert_start; vertex < vert_end; ++vertex) + vertex->uv = ImClamp(uv_a + ImMul(ImVec2(vertex->pos.x, vertex->pos.y) - a, scale), min, max); + } + else + { + for (ImDrawVert* vertex = vert_start; vertex < vert_end; ++vertex) + vertex->uv = uv_a + ImMul(ImVec2(vertex->pos.x, vertex->pos.y) - a, scale); + } +} + +//----------------------------------------------------------------------------- +// [SECTION] ImFontConfig +//----------------------------------------------------------------------------- + +ImFontConfig::ImFontConfig() +{ + FontData = NULL; + FontDataSize = 0; + FontDataOwnedByAtlas = true; + FontNo = 0; + SizePixels = 0.0f; + OversampleH = 3; // FIXME: 2 may be a better default? + OversampleV = 1; + PixelSnapH = false; + GlyphExtraSpacing = ImVec2(0.0f, 0.0f); + GlyphOffset = ImVec2(0.0f, 0.0f); + GlyphRanges = NULL; + GlyphMinAdvanceX = 0.0f; + GlyphMaxAdvanceX = FLT_MAX; + MergeMode = false; + RasterizerFlags = 0x00; + RasterizerMultiply = 1.0f; + EllipsisChar = (ImWchar)-1; + memset(Name, 0, sizeof(Name)); + DstFont = NULL; +} + +//----------------------------------------------------------------------------- +// [SECTION] ImFontAtlas +//----------------------------------------------------------------------------- + +// A work of art lies ahead! (. = white layer, X = black layer, others are blank) +// The white texels on the top left are the ones we'll use everywhere in Dear ImGui to render filled shapes. +const int FONT_ATLAS_DEFAULT_TEX_DATA_W_HALF = 108; +const int FONT_ATLAS_DEFAULT_TEX_DATA_H = 27; +static const char FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS[FONT_ATLAS_DEFAULT_TEX_DATA_W_HALF * FONT_ATLAS_DEFAULT_TEX_DATA_H + 1] = +{ + "..- -XXXXXXX- X - X -XXXXXXX - XXXXXXX- XX " + "..- -X.....X- X.X - X.X -X.....X - X.....X- X..X " + "--- -XXX.XXX- X...X - X...X -X....X - X....X- X..X " + "X - X.X - X.....X - X.....X -X...X - X...X- X..X " + "XX - X.X -X.......X- X.......X -X..X.X - X.X..X- X..X " + "X.X - X.X -XXXX.XXXX- XXXX.XXXX -X.X X.X - X.X X.X- X..XXX " + "X..X - X.X - X.X - X.X -XX X.X - X.X XX- X..X..XXX " + "X...X - X.X - X.X - XX X.X XX - X.X - X.X - X..X..X..XX " + "X....X - X.X - X.X - X.X X.X X.X - X.X - X.X - X..X..X..X.X " + "X.....X - X.X - X.X - X..X X.X X..X - X.X - X.X -XXX X..X..X..X..X" + "X......X - X.X - X.X - X...XXXXXX.XXXXXX...X - X.X XX-XX X.X -X..XX........X..X" + "X.......X - X.X - X.X -X.....................X- X.X X.X-X.X X.X -X...X...........X" + "X........X - X.X - X.X - X...XXXXXX.XXXXXX...X - X.X..X-X..X.X - X..............X" + "X.........X -XXX.XXX- X.X - X..X X.X X..X - X...X-X...X - X.............X" + "X..........X-X.....X- X.X - X.X X.X X.X - X....X-X....X - X.............X" + "X......XXXXX-XXXXXXX- X.X - XX X.X XX - X.....X-X.....X - X............X" + "X...X..X --------- X.X - X.X - XXXXXXX-XXXXXXX - X...........X " + "X..X X..X - -XXXX.XXXX- XXXX.XXXX ------------------------------------- X..........X " + "X.X X..X - -X.......X- X.......X - XX XX - - X..........X " + "XX X..X - - X.....X - X.....X - X.X X.X - - X........X " + " X..X - X...X - X...X - X..X X..X - - X........X " + " XX - X.X - X.X - X...XXXXXXXXXXXXX...X - - XXXXXXXXXX " + "------------ - X - X -X.....................X- ------------------" + " ----------------------------------- X...XXXXXXXXXXXXX...X - " + " - X..X X..X - " + " - X.X X.X - " + " - XX XX - " +}; + +static const ImVec2 FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[ImGuiMouseCursor_COUNT][3] = +{ + // Pos ........ Size ......... Offset ...... + { ImVec2( 0,3), ImVec2(12,19), ImVec2( 0, 0) }, // ImGuiMouseCursor_Arrow + { ImVec2(13,0), ImVec2( 7,16), ImVec2( 1, 8) }, // ImGuiMouseCursor_TextInput + { ImVec2(31,0), ImVec2(23,23), ImVec2(11,11) }, // ImGuiMouseCursor_ResizeAll + { ImVec2(21,0), ImVec2( 9,23), ImVec2( 4,11) }, // ImGuiMouseCursor_ResizeNS + { ImVec2(55,18),ImVec2(23, 9), ImVec2(11, 4) }, // ImGuiMouseCursor_ResizeEW + { ImVec2(73,0), ImVec2(17,17), ImVec2( 8, 8) }, // ImGuiMouseCursor_ResizeNESW + { ImVec2(55,0), ImVec2(17,17), ImVec2( 8, 8) }, // ImGuiMouseCursor_ResizeNWSE + { ImVec2(91,0), ImVec2(17,22), ImVec2( 5, 0) }, // ImGuiMouseCursor_Hand +}; + +ImFontAtlas::ImFontAtlas() +{ + Locked = false; + Flags = ImFontAtlasFlags_None; + TexID = (ImTextureID)NULL; + TexDesiredWidth = 0; + TexGlyphPadding = 1; + + TexPixelsAlpha8 = NULL; + TexPixelsRGBA32 = NULL; + TexWidth = TexHeight = 0; + TexUvScale = ImVec2(0.0f, 0.0f); + TexUvWhitePixel = ImVec2(0.0f, 0.0f); + for (int n = 0; n < IM_ARRAYSIZE(CustomRectIds); n++) + CustomRectIds[n] = -1; +} + +ImFontAtlas::~ImFontAtlas() +{ + IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!"); + Clear(); +} + +void ImFontAtlas::ClearInputData() +{ + IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!"); + for (int i = 0; i < ConfigData.Size; i++) + if (ConfigData[i].FontData && ConfigData[i].FontDataOwnedByAtlas) + { + IM_FREE(ConfigData[i].FontData); + ConfigData[i].FontData = NULL; + } + + // When clearing this we lose access to the font name and other information used to build the font. + for (int i = 0; i < Fonts.Size; i++) + if (Fonts[i]->ConfigData >= ConfigData.Data && Fonts[i]->ConfigData < ConfigData.Data + ConfigData.Size) + { + Fonts[i]->ConfigData = NULL; + Fonts[i]->ConfigDataCount = 0; + } + ConfigData.clear(); + CustomRects.clear(); + for (int n = 0; n < IM_ARRAYSIZE(CustomRectIds); n++) + CustomRectIds[n] = -1; +} + +void ImFontAtlas::ClearTexData() +{ + IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!"); + if (TexPixelsAlpha8) + IM_FREE(TexPixelsAlpha8); + if (TexPixelsRGBA32) + IM_FREE(TexPixelsRGBA32); + TexPixelsAlpha8 = NULL; + TexPixelsRGBA32 = NULL; +} + +void ImFontAtlas::ClearFonts() +{ + IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!"); + for (int i = 0; i < Fonts.Size; i++) + IM_DELETE(Fonts[i]); + Fonts.clear(); +} + +void ImFontAtlas::Clear() +{ + ClearInputData(); + ClearTexData(); + ClearFonts(); +} + +void ImFontAtlas::GetTexDataAsAlpha8(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel) +{ + // Build atlas on demand + if (TexPixelsAlpha8 == NULL) + { + if (ConfigData.empty()) + AddFontDefault(); + Build(); + } + + *out_pixels = TexPixelsAlpha8; + if (out_width) *out_width = TexWidth; + if (out_height) *out_height = TexHeight; + if (out_bytes_per_pixel) *out_bytes_per_pixel = 1; +} + +void ImFontAtlas::GetTexDataAsRGBA32(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel) +{ + // Convert to RGBA32 format on demand + // Although it is likely to be the most commonly used format, our font rendering is 1 channel / 8 bpp + if (!TexPixelsRGBA32) + { + unsigned char* pixels = NULL; + GetTexDataAsAlpha8(&pixels, NULL, NULL); + if (pixels) + { + TexPixelsRGBA32 = (unsigned int*)IM_ALLOC((size_t)TexWidth * (size_t)TexHeight * 4); + const unsigned char* src = pixels; + unsigned int* dst = TexPixelsRGBA32; + for (int n = TexWidth * TexHeight; n > 0; n--) + *dst++ = IM_COL32(255, 255, 255, (unsigned int)(*src++)); + } + } + + *out_pixels = (unsigned char*)TexPixelsRGBA32; + if (out_width) *out_width = TexWidth; + if (out_height) *out_height = TexHeight; + if (out_bytes_per_pixel) *out_bytes_per_pixel = 4; +} + +ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg) +{ + IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!"); + IM_ASSERT(font_cfg->FontData != NULL && font_cfg->FontDataSize > 0); + IM_ASSERT(font_cfg->SizePixels > 0.0f); + + // Create new font + if (!font_cfg->MergeMode) + Fonts.push_back(IM_NEW(ImFont)); + else + IM_ASSERT(!Fonts.empty() && "Cannot use MergeMode for the first font"); // When using MergeMode make sure that a font has already been added before. You can use ImGui::GetIO().Fonts->AddFontDefault() to add the default imgui font. + + ConfigData.push_back(*font_cfg); + ImFontConfig& new_font_cfg = ConfigData.back(); + if (new_font_cfg.DstFont == NULL) + new_font_cfg.DstFont = Fonts.back(); + if (!new_font_cfg.FontDataOwnedByAtlas) + { + new_font_cfg.FontData = IM_ALLOC(new_font_cfg.FontDataSize); + new_font_cfg.FontDataOwnedByAtlas = true; + memcpy(new_font_cfg.FontData, font_cfg->FontData, (size_t)new_font_cfg.FontDataSize); + } + + if (new_font_cfg.DstFont->EllipsisChar == (ImWchar)-1) + new_font_cfg.DstFont->EllipsisChar = font_cfg->EllipsisChar; + + // Invalidate texture + ClearTexData(); + return new_font_cfg.DstFont; +} + +// Default font TTF is compressed with stb_compress then base85 encoded (see misc/fonts/binary_to_compressed_c.cpp for encoder) +static unsigned int stb_decompress_length(const unsigned char *input); +static unsigned int stb_decompress(unsigned char *output, const unsigned char *input, unsigned int length); +static const char* GetDefaultCompressedFontDataTTFBase85(); +static unsigned int Decode85Byte(char c) { return c >= '\\' ? c-36 : c-35; } +static void Decode85(const unsigned char* src, unsigned char* dst) +{ + while (*src) + { + unsigned int tmp = Decode85Byte(src[0]) + 85*(Decode85Byte(src[1]) + 85*(Decode85Byte(src[2]) + 85*(Decode85Byte(src[3]) + 85*Decode85Byte(src[4])))); + dst[0] = ((tmp >> 0) & 0xFF); dst[1] = ((tmp >> 8) & 0xFF); dst[2] = ((tmp >> 16) & 0xFF); dst[3] = ((tmp >> 24) & 0xFF); // We can't assume little-endianness. + src += 5; + dst += 4; + } +} + +// Load embedded ProggyClean.ttf at size 13, disable oversampling +ImFont* ImFontAtlas::AddFontDefault(const ImFontConfig* font_cfg_template) +{ + ImFontConfig font_cfg = font_cfg_template ? *font_cfg_template : ImFontConfig(); + if (!font_cfg_template) + { + font_cfg.OversampleH = font_cfg.OversampleV = 1; + font_cfg.PixelSnapH = true; + } + if (font_cfg.SizePixels <= 0.0f) + font_cfg.SizePixels = 13.0f * 1.0f; + if (font_cfg.Name[0] == '\0') + ImFormatString(font_cfg.Name, IM_ARRAYSIZE(font_cfg.Name), "ProggyClean.ttf, %dpx", (int)font_cfg.SizePixels); + font_cfg.EllipsisChar = (ImWchar)0x0085; + + const char* ttf_compressed_base85 = GetDefaultCompressedFontDataTTFBase85(); + const ImWchar* glyph_ranges = font_cfg.GlyphRanges != NULL ? font_cfg.GlyphRanges : GetGlyphRangesDefault(); + ImFont* font = AddFontFromMemoryCompressedBase85TTF(ttf_compressed_base85, font_cfg.SizePixels, &font_cfg, glyph_ranges); + font->DisplayOffset.y = 1.0f; + return font; +} + +ImFont* ImFontAtlas::AddFontFromFileTTF(const char* filename, float size_pixels, const ImFontConfig* font_cfg_template, const ImWchar* glyph_ranges) +{ + IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!"); + size_t data_size = 0; + void* data = ImFileLoadToMemory(filename, "rb", &data_size, 0); + if (!data) + { + IM_ASSERT_USER_ERROR(0, "Could not load font file!"); + return NULL; + } + ImFontConfig font_cfg = font_cfg_template ? *font_cfg_template : ImFontConfig(); + if (font_cfg.Name[0] == '\0') + { + // Store a short copy of filename into into the font name for convenience + const char* p; + for (p = filename + strlen(filename); p > filename && p[-1] != '/' && p[-1] != '\\'; p--) {} + ImFormatString(font_cfg.Name, IM_ARRAYSIZE(font_cfg.Name), "%s, %.0fpx", p, size_pixels); + } + return AddFontFromMemoryTTF(data, (int)data_size, size_pixels, &font_cfg, glyph_ranges); +} + +// NB: Transfer ownership of 'ttf_data' to ImFontAtlas, unless font_cfg_template->FontDataOwnedByAtlas == false. Owned TTF buffer will be deleted after Build(). +ImFont* ImFontAtlas::AddFontFromMemoryTTF(void* ttf_data, int ttf_size, float size_pixels, const ImFontConfig* font_cfg_template, const ImWchar* glyph_ranges) +{ + IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!"); + ImFontConfig font_cfg = font_cfg_template ? *font_cfg_template : ImFontConfig(); + IM_ASSERT(font_cfg.FontData == NULL); + font_cfg.FontData = ttf_data; + font_cfg.FontDataSize = ttf_size; + font_cfg.SizePixels = size_pixels; + if (glyph_ranges) + font_cfg.GlyphRanges = glyph_ranges; + return AddFont(&font_cfg); +} + +ImFont* ImFontAtlas::AddFontFromMemoryCompressedTTF(const void* compressed_ttf_data, int compressed_ttf_size, float size_pixels, const ImFontConfig* font_cfg_template, const ImWchar* glyph_ranges) +{ + const unsigned int buf_decompressed_size = stb_decompress_length((const unsigned char*)compressed_ttf_data); + unsigned char* buf_decompressed_data = (unsigned char *)IM_ALLOC(buf_decompressed_size); + stb_decompress(buf_decompressed_data, (const unsigned char*)compressed_ttf_data, (unsigned int)compressed_ttf_size); + + ImFontConfig font_cfg = font_cfg_template ? *font_cfg_template : ImFontConfig(); + IM_ASSERT(font_cfg.FontData == NULL); + font_cfg.FontDataOwnedByAtlas = true; + return AddFontFromMemoryTTF(buf_decompressed_data, (int)buf_decompressed_size, size_pixels, &font_cfg, glyph_ranges); +} + +ImFont* ImFontAtlas::AddFontFromMemoryCompressedBase85TTF(const char* compressed_ttf_data_base85, float size_pixels, const ImFontConfig* font_cfg, const ImWchar* glyph_ranges) +{ + int compressed_ttf_size = (((int)strlen(compressed_ttf_data_base85) + 4) / 5) * 4; + void* compressed_ttf = IM_ALLOC((size_t)compressed_ttf_size); + Decode85((const unsigned char*)compressed_ttf_data_base85, (unsigned char*)compressed_ttf); + ImFont* font = AddFontFromMemoryCompressedTTF(compressed_ttf, compressed_ttf_size, size_pixels, font_cfg, glyph_ranges); + IM_FREE(compressed_ttf); + return font; +} + +int ImFontAtlas::AddCustomRectRegular(int width, int height) +{ + IM_ASSERT(width > 0 && width <= 0xFFFF); + IM_ASSERT(height > 0 && height <= 0xFFFF); + ImFontAtlasCustomRect r; + r.Width = (unsigned short)width; + r.Height = (unsigned short)height; + CustomRects.push_back(r); + return CustomRects.Size - 1; // Return index +} + +int ImFontAtlas::AddCustomRectFontGlyph(ImFont* font, ImWchar id, int width, int height, float advance_x, const ImVec2& offset) +{ +#ifdef IMGUI_USE_WCHAR32 + IM_ASSERT(id <= IM_UNICODE_CODEPOINT_MAX); +#endif + IM_ASSERT(font != NULL); + IM_ASSERT(width > 0 && width <= 0xFFFF); + IM_ASSERT(height > 0 && height <= 0xFFFF); + ImFontAtlasCustomRect r; + r.Width = (unsigned short)width; + r.Height = (unsigned short)height; + r.GlyphID = id; + r.GlyphAdvanceX = advance_x; + r.GlyphOffset = offset; + r.Font = font; + CustomRects.push_back(r); + return CustomRects.Size - 1; // Return index +} + +void ImFontAtlas::CalcCustomRectUV(const ImFontAtlasCustomRect* rect, ImVec2* out_uv_min, ImVec2* out_uv_max) const +{ + IM_ASSERT(TexWidth > 0 && TexHeight > 0); // Font atlas needs to be built before we can calculate UV coordinates + IM_ASSERT(rect->IsPacked()); // Make sure the rectangle has been packed + *out_uv_min = ImVec2((float)rect->X * TexUvScale.x, (float)rect->Y * TexUvScale.y); + *out_uv_max = ImVec2((float)(rect->X + rect->Width) * TexUvScale.x, (float)(rect->Y + rect->Height) * TexUvScale.y); +} + +bool ImFontAtlas::GetMouseCursorTexData(ImGuiMouseCursor cursor_type, ImVec2* out_offset, ImVec2* out_size, ImVec2 out_uv_border[2], ImVec2 out_uv_fill[2]) +{ + if (cursor_type <= ImGuiMouseCursor_None || cursor_type >= ImGuiMouseCursor_COUNT) + return false; + if (Flags & ImFontAtlasFlags_NoMouseCursors) + return false; + + IM_ASSERT(CustomRectIds[0] != -1); + ImFontAtlasCustomRect& r = CustomRects[CustomRectIds[0]]; + ImVec2 pos = FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[cursor_type][0] + ImVec2((float)r.X, (float)r.Y); + ImVec2 size = FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[cursor_type][1]; + *out_size = size; + *out_offset = FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[cursor_type][2]; + out_uv_border[0] = (pos) * TexUvScale; + out_uv_border[1] = (pos + size) * TexUvScale; + pos.x += FONT_ATLAS_DEFAULT_TEX_DATA_W_HALF + 1; + out_uv_fill[0] = (pos) * TexUvScale; + out_uv_fill[1] = (pos + size) * TexUvScale; + return true; +} + +bool ImFontAtlas::Build() +{ + IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!"); + return ImFontAtlasBuildWithStbTruetype(this); +} + +void ImFontAtlasBuildMultiplyCalcLookupTable(unsigned char out_table[256], float in_brighten_factor) +{ + for (unsigned int i = 0; i < 256; i++) + { + unsigned int value = (unsigned int)(i * in_brighten_factor); + out_table[i] = value > 255 ? 255 : (value & 0xFF); + } +} + +void ImFontAtlasBuildMultiplyRectAlpha8(const unsigned char table[256], unsigned char* pixels, int x, int y, int w, int h, int stride) +{ + unsigned char* data = pixels + x + y * stride; + for (int j = h; j > 0; j--, data += stride) + for (int i = 0; i < w; i++) + data[i] = table[data[i]]; +} + +// Temporary data for one source font (multiple source fonts can be merged into one destination ImFont) +// (C++03 doesn't allow instancing ImVector<> with function-local types so we declare the type here.) +struct ImFontBuildSrcData +{ + stbtt_fontinfo FontInfo; + stbtt_pack_range PackRange; // Hold the list of codepoints to pack (essentially points to Codepoints.Data) + stbrp_rect* Rects; // Rectangle to pack. We first fill in their size and the packer will give us their position. + stbtt_packedchar* PackedChars; // Output glyphs + const ImWchar* SrcRanges; // Ranges as requested by user (user is allowed to request too much, e.g. 0x0020..0xFFFF) + int DstIndex; // Index into atlas->Fonts[] and dst_tmp_array[] + int GlyphsHighest; // Highest requested codepoint + int GlyphsCount; // Glyph count (excluding missing glyphs and glyphs already set by an earlier source font) + ImBitVector GlyphsSet; // Glyph bit map (random access, 1-bit per codepoint. This will be a maximum of 8KB) + ImVector GlyphsList; // Glyph codepoints list (flattened version of GlyphsMap) +}; + +// Temporary data for one destination ImFont* (multiple source fonts can be merged into one destination ImFont) +struct ImFontBuildDstData +{ + int SrcCount; // Number of source fonts targeting this destination font. + int GlyphsHighest; + int GlyphsCount; + ImBitVector GlyphsSet; // This is used to resolve collision when multiple sources are merged into a same destination font. +}; + +static void UnpackBitVectorToFlatIndexList(const ImBitVector* in, ImVector* out) +{ + IM_ASSERT(sizeof(in->Storage.Data[0]) == sizeof(int)); + const ImU32* it_begin = in->Storage.begin(); + const ImU32* it_end = in->Storage.end(); + for (const ImU32* it = it_begin; it < it_end; it++) + if (ImU32 entries_32 = *it) + for (ImU32 bit_n = 0; bit_n < 32; bit_n++) + if (entries_32 & ((ImU32)1 << bit_n)) + out->push_back((int)(((it - it_begin) << 5) + bit_n)); +} + +bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas) +{ + IM_ASSERT(atlas->ConfigData.Size > 0); + + ImFontAtlasBuildInit(atlas); + + // Clear atlas + atlas->TexID = (ImTextureID)NULL; + atlas->TexWidth = atlas->TexHeight = 0; + atlas->TexUvScale = ImVec2(0.0f, 0.0f); + atlas->TexUvWhitePixel = ImVec2(0.0f, 0.0f); + atlas->ClearTexData(); + + // Temporary storage for building + ImVector src_tmp_array; + ImVector dst_tmp_array; + src_tmp_array.resize(atlas->ConfigData.Size); + dst_tmp_array.resize(atlas->Fonts.Size); + memset(src_tmp_array.Data, 0, (size_t)src_tmp_array.size_in_bytes()); + memset(dst_tmp_array.Data, 0, (size_t)dst_tmp_array.size_in_bytes()); + + // 1. Initialize font loading structure, check font data validity + for (int src_i = 0; src_i < atlas->ConfigData.Size; src_i++) + { + ImFontBuildSrcData& src_tmp = src_tmp_array[src_i]; + ImFontConfig& cfg = atlas->ConfigData[src_i]; + IM_ASSERT(cfg.DstFont && (!cfg.DstFont->IsLoaded() || cfg.DstFont->ContainerAtlas == atlas)); + + // Find index from cfg.DstFont (we allow the user to set cfg.DstFont. Also it makes casual debugging nicer than when storing indices) + src_tmp.DstIndex = -1; + for (int output_i = 0; output_i < atlas->Fonts.Size && src_tmp.DstIndex == -1; output_i++) + if (cfg.DstFont == atlas->Fonts[output_i]) + src_tmp.DstIndex = output_i; + IM_ASSERT(src_tmp.DstIndex != -1); // cfg.DstFont not pointing within atlas->Fonts[] array? + if (src_tmp.DstIndex == -1) + return false; + + // Initialize helper structure for font loading and verify that the TTF/OTF data is correct + const int font_offset = stbtt_GetFontOffsetForIndex((unsigned char*)cfg.FontData, cfg.FontNo); + IM_ASSERT(font_offset >= 0 && "FontData is incorrect, or FontNo cannot be found."); + if (!stbtt_InitFont(&src_tmp.FontInfo, (unsigned char*)cfg.FontData, font_offset)) + return false; + + // Measure highest codepoints + ImFontBuildDstData& dst_tmp = dst_tmp_array[src_tmp.DstIndex]; + src_tmp.SrcRanges = cfg.GlyphRanges ? cfg.GlyphRanges : atlas->GetGlyphRangesDefault(); + for (const ImWchar* src_range = src_tmp.SrcRanges; src_range[0] && src_range[1]; src_range += 2) + src_tmp.GlyphsHighest = ImMax(src_tmp.GlyphsHighest, (int)src_range[1]); + dst_tmp.SrcCount++; + dst_tmp.GlyphsHighest = ImMax(dst_tmp.GlyphsHighest, src_tmp.GlyphsHighest); + } + + // 2. For every requested codepoint, check for their presence in the font data, and handle redundancy or overlaps between source fonts to avoid unused glyphs. + int total_glyphs_count = 0; + for (int src_i = 0; src_i < src_tmp_array.Size; src_i++) + { + ImFontBuildSrcData& src_tmp = src_tmp_array[src_i]; + ImFontBuildDstData& dst_tmp = dst_tmp_array[src_tmp.DstIndex]; + src_tmp.GlyphsSet.Create(src_tmp.GlyphsHighest + 1); + if (dst_tmp.GlyphsSet.Storage.empty()) + dst_tmp.GlyphsSet.Create(dst_tmp.GlyphsHighest + 1); + + for (const ImWchar* src_range = src_tmp.SrcRanges; src_range[0] && src_range[1]; src_range += 2) + for (unsigned int codepoint = src_range[0]; codepoint <= src_range[1]; codepoint++) + { + if (dst_tmp.GlyphsSet.TestBit(codepoint)) // Don't overwrite existing glyphs. We could make this an option for MergeMode (e.g. MergeOverwrite==true) + continue; + if (!stbtt_FindGlyphIndex(&src_tmp.FontInfo, codepoint)) // It is actually in the font? + continue; + + // Add to avail set/counters + src_tmp.GlyphsCount++; + dst_tmp.GlyphsCount++; + src_tmp.GlyphsSet.SetBit(codepoint); + dst_tmp.GlyphsSet.SetBit(codepoint); + total_glyphs_count++; + } + } + + // 3. Unpack our bit map into a flat list (we now have all the Unicode points that we know are requested _and_ available _and_ not overlapping another) + for (int src_i = 0; src_i < src_tmp_array.Size; src_i++) + { + ImFontBuildSrcData& src_tmp = src_tmp_array[src_i]; + src_tmp.GlyphsList.reserve(src_tmp.GlyphsCount); + UnpackBitVectorToFlatIndexList(&src_tmp.GlyphsSet, &src_tmp.GlyphsList); + src_tmp.GlyphsSet.Clear(); + IM_ASSERT(src_tmp.GlyphsList.Size == src_tmp.GlyphsCount); + } + for (int dst_i = 0; dst_i < dst_tmp_array.Size; dst_i++) + dst_tmp_array[dst_i].GlyphsSet.Clear(); + dst_tmp_array.clear(); + + // Allocate packing character data and flag packed characters buffer as non-packed (x0=y0=x1=y1=0) + // (We technically don't need to zero-clear buf_rects, but let's do it for the sake of sanity) + ImVector buf_rects; + ImVector buf_packedchars; + buf_rects.resize(total_glyphs_count); + buf_packedchars.resize(total_glyphs_count); + memset(buf_rects.Data, 0, (size_t)buf_rects.size_in_bytes()); + memset(buf_packedchars.Data, 0, (size_t)buf_packedchars.size_in_bytes()); + + // 4. Gather glyphs sizes so we can pack them in our virtual canvas. + int total_surface = 0; + int buf_rects_out_n = 0; + int buf_packedchars_out_n = 0; + for (int src_i = 0; src_i < src_tmp_array.Size; src_i++) + { + ImFontBuildSrcData& src_tmp = src_tmp_array[src_i]; + if (src_tmp.GlyphsCount == 0) + continue; + + src_tmp.Rects = &buf_rects[buf_rects_out_n]; + src_tmp.PackedChars = &buf_packedchars[buf_packedchars_out_n]; + buf_rects_out_n += src_tmp.GlyphsCount; + buf_packedchars_out_n += src_tmp.GlyphsCount; + + // Convert our ranges in the format stb_truetype wants + ImFontConfig& cfg = atlas->ConfigData[src_i]; + src_tmp.PackRange.font_size = cfg.SizePixels; + src_tmp.PackRange.first_unicode_codepoint_in_range = 0; + src_tmp.PackRange.array_of_unicode_codepoints = src_tmp.GlyphsList.Data; + src_tmp.PackRange.num_chars = src_tmp.GlyphsList.Size; + src_tmp.PackRange.chardata_for_range = src_tmp.PackedChars; + src_tmp.PackRange.h_oversample = (unsigned char)cfg.OversampleH; + src_tmp.PackRange.v_oversample = (unsigned char)cfg.OversampleV; + + // Gather the sizes of all rectangles we will need to pack (this loop is based on stbtt_PackFontRangesGatherRects) + const float scale = (cfg.SizePixels > 0) ? stbtt_ScaleForPixelHeight(&src_tmp.FontInfo, cfg.SizePixels) : stbtt_ScaleForMappingEmToPixels(&src_tmp.FontInfo, -cfg.SizePixels); + const int padding = atlas->TexGlyphPadding; + for (int glyph_i = 0; glyph_i < src_tmp.GlyphsList.Size; glyph_i++) + { + int x0, y0, x1, y1; + const int glyph_index_in_font = stbtt_FindGlyphIndex(&src_tmp.FontInfo, src_tmp.GlyphsList[glyph_i]); + IM_ASSERT(glyph_index_in_font != 0); + stbtt_GetGlyphBitmapBoxSubpixel(&src_tmp.FontInfo, glyph_index_in_font, scale * cfg.OversampleH, scale * cfg.OversampleV, 0, 0, &x0, &y0, &x1, &y1); + src_tmp.Rects[glyph_i].w = (stbrp_coord)(x1 - x0 + padding + cfg.OversampleH - 1); + src_tmp.Rects[glyph_i].h = (stbrp_coord)(y1 - y0 + padding + cfg.OversampleV - 1); + total_surface += src_tmp.Rects[glyph_i].w * src_tmp.Rects[glyph_i].h; + } + } + + // We need a width for the skyline algorithm, any width! + // The exact width doesn't really matter much, but some API/GPU have texture size limitations and increasing width can decrease height. + // User can override TexDesiredWidth and TexGlyphPadding if they wish, otherwise we use a simple heuristic to select the width based on expected surface. + const int surface_sqrt = (int)ImSqrt((float)total_surface) + 1; + atlas->TexHeight = 0; + if (atlas->TexDesiredWidth > 0) + atlas->TexWidth = atlas->TexDesiredWidth; + else + atlas->TexWidth = (surface_sqrt >= 4096*0.7f) ? 4096 : (surface_sqrt >= 2048*0.7f) ? 2048 : (surface_sqrt >= 1024*0.7f) ? 1024 : 512; + + // 5. Start packing + // Pack our extra data rectangles first, so it will be on the upper-left corner of our texture (UV will have small values). + const int TEX_HEIGHT_MAX = 1024 * 32; + stbtt_pack_context spc = {}; + stbtt_PackBegin(&spc, NULL, atlas->TexWidth, TEX_HEIGHT_MAX, 0, atlas->TexGlyphPadding, NULL); + ImFontAtlasBuildPackCustomRects(atlas, spc.pack_info); + + // 6. Pack each source font. No rendering yet, we are working with rectangles in an infinitely tall texture at this point. + for (int src_i = 0; src_i < src_tmp_array.Size; src_i++) + { + ImFontBuildSrcData& src_tmp = src_tmp_array[src_i]; + if (src_tmp.GlyphsCount == 0) + continue; + + stbrp_pack_rects((stbrp_context*)spc.pack_info, src_tmp.Rects, src_tmp.GlyphsCount); + + // Extend texture height and mark missing glyphs as non-packed so we won't render them. + // FIXME: We are not handling packing failure here (would happen if we got off TEX_HEIGHT_MAX or if a single if larger than TexWidth?) + for (int glyph_i = 0; glyph_i < src_tmp.GlyphsCount; glyph_i++) + if (src_tmp.Rects[glyph_i].was_packed) + atlas->TexHeight = ImMax(atlas->TexHeight, src_tmp.Rects[glyph_i].y + src_tmp.Rects[glyph_i].h); + } + + // 7. Allocate texture + atlas->TexHeight = (atlas->Flags & ImFontAtlasFlags_NoPowerOfTwoHeight) ? (atlas->TexHeight + 1) : ImUpperPowerOfTwo(atlas->TexHeight); + atlas->TexUvScale = ImVec2(1.0f / atlas->TexWidth, 1.0f / atlas->TexHeight); + atlas->TexPixelsAlpha8 = (unsigned char*)IM_ALLOC(atlas->TexWidth * atlas->TexHeight); + memset(atlas->TexPixelsAlpha8, 0, atlas->TexWidth * atlas->TexHeight); + spc.pixels = atlas->TexPixelsAlpha8; + spc.height = atlas->TexHeight; + + // 8. Render/rasterize font characters into the texture + for (int src_i = 0; src_i < src_tmp_array.Size; src_i++) + { + ImFontConfig& cfg = atlas->ConfigData[src_i]; + ImFontBuildSrcData& src_tmp = src_tmp_array[src_i]; + if (src_tmp.GlyphsCount == 0) + continue; + + stbtt_PackFontRangesRenderIntoRects(&spc, &src_tmp.FontInfo, &src_tmp.PackRange, 1, src_tmp.Rects); + + // Apply multiply operator + if (cfg.RasterizerMultiply != 1.0f) + { + unsigned char multiply_table[256]; + ImFontAtlasBuildMultiplyCalcLookupTable(multiply_table, cfg.RasterizerMultiply); + stbrp_rect* r = &src_tmp.Rects[0]; + for (int glyph_i = 0; glyph_i < src_tmp.GlyphsCount; glyph_i++, r++) + if (r->was_packed) + ImFontAtlasBuildMultiplyRectAlpha8(multiply_table, atlas->TexPixelsAlpha8, r->x, r->y, r->w, r->h, atlas->TexWidth * 1); + } + src_tmp.Rects = NULL; + } + + // End packing + stbtt_PackEnd(&spc); + buf_rects.clear(); + + // 9. Setup ImFont and glyphs for runtime + for (int src_i = 0; src_i < src_tmp_array.Size; src_i++) + { + ImFontBuildSrcData& src_tmp = src_tmp_array[src_i]; + if (src_tmp.GlyphsCount == 0) + continue; + + ImFontConfig& cfg = atlas->ConfigData[src_i]; + ImFont* dst_font = cfg.DstFont; // We can have multiple input fonts writing into a same destination font (when using MergeMode=true) + + const float font_scale = stbtt_ScaleForPixelHeight(&src_tmp.FontInfo, cfg.SizePixels); + int unscaled_ascent, unscaled_descent, unscaled_line_gap; + stbtt_GetFontVMetrics(&src_tmp.FontInfo, &unscaled_ascent, &unscaled_descent, &unscaled_line_gap); + + const float ascent = ImFloor(unscaled_ascent * font_scale + ((unscaled_ascent > 0.0f) ? +1 : -1)); + const float descent = ImFloor(unscaled_descent * font_scale + ((unscaled_descent > 0.0f) ? +1 : -1)); + ImFontAtlasBuildSetupFont(atlas, dst_font, &cfg, ascent, descent); + const float font_off_x = cfg.GlyphOffset.x; + const float font_off_y = cfg.GlyphOffset.y + IM_ROUND(dst_font->Ascent); + + for (int glyph_i = 0; glyph_i < src_tmp.GlyphsCount; glyph_i++) + { + const int codepoint = src_tmp.GlyphsList[glyph_i]; + const stbtt_packedchar& pc = src_tmp.PackedChars[glyph_i]; + + const float char_advance_x_org = pc.xadvance; + const float char_advance_x_mod = ImClamp(char_advance_x_org, cfg.GlyphMinAdvanceX, cfg.GlyphMaxAdvanceX); + float char_off_x = font_off_x; + if (char_advance_x_org != char_advance_x_mod) + char_off_x += cfg.PixelSnapH ? ImFloor((char_advance_x_mod - char_advance_x_org) * 0.5f) : (char_advance_x_mod - char_advance_x_org) * 0.5f; + + // Register glyph + stbtt_aligned_quad q; + float dummy_x = 0.0f, dummy_y = 0.0f; + stbtt_GetPackedQuad(src_tmp.PackedChars, atlas->TexWidth, atlas->TexHeight, glyph_i, &dummy_x, &dummy_y, &q, 0); + dst_font->AddGlyph((ImWchar)codepoint, q.x0 + char_off_x, q.y0 + font_off_y, q.x1 + char_off_x, q.y1 + font_off_y, q.s0, q.t0, q.s1, q.t1, char_advance_x_mod); + } + } + + // Cleanup temporary (ImVector doesn't honor destructor) + for (int src_i = 0; src_i < src_tmp_array.Size; src_i++) + src_tmp_array[src_i].~ImFontBuildSrcData(); + + ImFontAtlasBuildFinish(atlas); + return true; +} + +// Register default custom rectangles (this is called/shared by both the stb_truetype and the FreeType builder) +void ImFontAtlasBuildInit(ImFontAtlas* atlas) +{ + if (atlas->CustomRectIds[0] >= 0) + return; + if (!(atlas->Flags & ImFontAtlasFlags_NoMouseCursors)) + atlas->CustomRectIds[0] = atlas->AddCustomRectRegular(FONT_ATLAS_DEFAULT_TEX_DATA_W_HALF*2+1, FONT_ATLAS_DEFAULT_TEX_DATA_H); + else + atlas->CustomRectIds[0] = atlas->AddCustomRectRegular(2, 2); +} + +void ImFontAtlasBuildSetupFont(ImFontAtlas* atlas, ImFont* font, ImFontConfig* font_config, float ascent, float descent) +{ + if (!font_config->MergeMode) + { + font->ClearOutputData(); + font->FontSize = font_config->SizePixels; + font->ConfigData = font_config; + font->ContainerAtlas = atlas; + font->Ascent = ascent; + font->Descent = descent; + } + font->ConfigDataCount++; +} + +void ImFontAtlasBuildPackCustomRects(ImFontAtlas* atlas, void* stbrp_context_opaque) +{ + stbrp_context* pack_context = (stbrp_context*)stbrp_context_opaque; + IM_ASSERT(pack_context != NULL); + + ImVector& user_rects = atlas->CustomRects; + IM_ASSERT(user_rects.Size >= 1); // We expect at least the default custom rects to be registered, else something went wrong. + + ImVector pack_rects; + pack_rects.resize(user_rects.Size); + memset(pack_rects.Data, 0, (size_t)pack_rects.size_in_bytes()); + for (int i = 0; i < user_rects.Size; i++) + { + pack_rects[i].w = user_rects[i].Width; + pack_rects[i].h = user_rects[i].Height; + } + stbrp_pack_rects(pack_context, &pack_rects[0], pack_rects.Size); + for (int i = 0; i < pack_rects.Size; i++) + if (pack_rects[i].was_packed) + { + user_rects[i].X = pack_rects[i].x; + user_rects[i].Y = pack_rects[i].y; + IM_ASSERT(pack_rects[i].w == user_rects[i].Width && pack_rects[i].h == user_rects[i].Height); + atlas->TexHeight = ImMax(atlas->TexHeight, pack_rects[i].y + pack_rects[i].h); + } +} + +static void ImFontAtlasBuildRenderDefaultTexData(ImFontAtlas* atlas) +{ + IM_ASSERT(atlas->CustomRectIds[0] >= 0); + IM_ASSERT(atlas->TexPixelsAlpha8 != NULL); + ImFontAtlasCustomRect& r = atlas->CustomRects[atlas->CustomRectIds[0]]; + IM_ASSERT(r.IsPacked()); + + const int w = atlas->TexWidth; + if (!(atlas->Flags & ImFontAtlasFlags_NoMouseCursors)) + { + // Render/copy pixels + IM_ASSERT(r.Width == FONT_ATLAS_DEFAULT_TEX_DATA_W_HALF * 2 + 1 && r.Height == FONT_ATLAS_DEFAULT_TEX_DATA_H); + for (int y = 0, n = 0; y < FONT_ATLAS_DEFAULT_TEX_DATA_H; y++) + for (int x = 0; x < FONT_ATLAS_DEFAULT_TEX_DATA_W_HALF; x++, n++) + { + const int offset0 = (int)(r.X + x) + (int)(r.Y + y) * w; + const int offset1 = offset0 + FONT_ATLAS_DEFAULT_TEX_DATA_W_HALF + 1; + atlas->TexPixelsAlpha8[offset0] = FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS[n] == '.' ? 0xFF : 0x00; + atlas->TexPixelsAlpha8[offset1] = FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS[n] == 'X' ? 0xFF : 0x00; + } + } + else + { + IM_ASSERT(r.Width == 2 && r.Height == 2); + const int offset = (int)(r.X) + (int)(r.Y) * w; + atlas->TexPixelsAlpha8[offset] = atlas->TexPixelsAlpha8[offset + 1] = atlas->TexPixelsAlpha8[offset + w] = atlas->TexPixelsAlpha8[offset + w + 1] = 0xFF; + } + atlas->TexUvWhitePixel = ImVec2((r.X + 0.5f) * atlas->TexUvScale.x, (r.Y + 0.5f) * atlas->TexUvScale.y); +} + +void ImFontAtlasBuildFinish(ImFontAtlas* atlas) +{ + // Render into our custom data block + ImFontAtlasBuildRenderDefaultTexData(atlas); + + // Register custom rectangle glyphs + for (int i = 0; i < atlas->CustomRects.Size; i++) + { + const ImFontAtlasCustomRect& r = atlas->CustomRects[i]; + if (r.Font == NULL || r.GlyphID == 0) + continue; + + IM_ASSERT(r.Font->ContainerAtlas == atlas); + ImVec2 uv0, uv1; + atlas->CalcCustomRectUV(&r, &uv0, &uv1); + r.Font->AddGlyph((ImWchar)r.GlyphID, r.GlyphOffset.x, r.GlyphOffset.y, r.GlyphOffset.x + r.Width, r.GlyphOffset.y + r.Height, uv0.x, uv0.y, uv1.x, uv1.y, r.GlyphAdvanceX); + } + + // Build all fonts lookup tables + for (int i = 0; i < atlas->Fonts.Size; i++) + if (atlas->Fonts[i]->DirtyLookupTables) + atlas->Fonts[i]->BuildLookupTable(); + + // Ellipsis character is required for rendering elided text. We prefer using U+2026 (horizontal ellipsis). + // However some old fonts may contain ellipsis at U+0085. Here we auto-detect most suitable ellipsis character. + // FIXME: Also note that 0x2026 is currently seldom included in our font ranges. Because of this we are more likely to use three individual dots. + for (int i = 0; i < atlas->Fonts.size(); i++) + { + ImFont* font = atlas->Fonts[i]; + if (font->EllipsisChar != (ImWchar)-1) + continue; + const ImWchar ellipsis_variants[] = { (ImWchar)0x2026, (ImWchar)0x0085 }; + for (int j = 0; j < IM_ARRAYSIZE(ellipsis_variants); j++) + if (font->FindGlyphNoFallback(ellipsis_variants[j]) != NULL) // Verify glyph exists + { + font->EllipsisChar = ellipsis_variants[j]; + break; + } + } +} + +// Retrieve list of range (2 int per range, values are inclusive) +const ImWchar* ImFontAtlas::GetGlyphRangesDefault() +{ + static const ImWchar ranges[] = + { + 0x0020, 0x00FF, // Basic Latin + Latin Supplement + 0, + }; + return &ranges[0]; +} + +const ImWchar* ImFontAtlas::GetGlyphRangesKorean() +{ + static const ImWchar ranges[] = + { + 0x0020, 0x00FF, // Basic Latin + Latin Supplement + 0x3131, 0x3163, // Korean alphabets + 0xAC00, 0xD7A3, // Korean characters + 0, + }; + return &ranges[0]; +} + +const ImWchar* ImFontAtlas::GetGlyphRangesChineseFull() +{ + static const ImWchar ranges[] = + { + 0x0020, 0x00FF, // Basic Latin + Latin Supplement + 0x2000, 0x206F, // General Punctuation + 0x3000, 0x30FF, // CJK Symbols and Punctuations, Hiragana, Katakana + 0x31F0, 0x31FF, // Katakana Phonetic Extensions + 0xFF00, 0xFFEF, // Half-width characters + 0x4e00, 0x9FAF, // CJK Ideograms + 0, + }; + return &ranges[0]; +} + +static void UnpackAccumulativeOffsetsIntoRanges(int base_codepoint, const short* accumulative_offsets, int accumulative_offsets_count, ImWchar* out_ranges) +{ + for (int n = 0; n < accumulative_offsets_count; n++, out_ranges += 2) + { + out_ranges[0] = out_ranges[1] = (ImWchar)(base_codepoint + accumulative_offsets[n]); + base_codepoint += accumulative_offsets[n]; + } + out_ranges[0] = 0; +} + +//------------------------------------------------------------------------- +// [SECTION] ImFontAtlas glyph ranges helpers +//------------------------------------------------------------------------- + +const ImWchar* ImFontAtlas::GetGlyphRangesChineseSimplifiedCommon() +{ + // Store 2500 regularly used characters for Simplified Chinese. + // Sourced from https://zh.wiktionary.org/wiki/%E9%99%84%E5%BD%95:%E7%8E%B0%E4%BB%A3%E6%B1%89%E8%AF%AD%E5%B8%B8%E7%94%A8%E5%AD%97%E8%A1%A8 + // This table covers 97.97% of all characters used during the month in July, 1987. + // You can use ImFontGlyphRangesBuilder to create your own ranges derived from this, by merging existing ranges or adding new characters. + // (Stored as accumulative offsets from the initial unicode codepoint 0x4E00. This encoding is designed to helps us compact the source code size.) + static const short accumulative_offsets_from_0x4E00[] = + { + 0,1,2,4,1,1,1,1,2,1,3,2,1,2,2,1,1,1,1,1,5,2,1,2,3,3,3,2,2,4,1,1,1,2,1,5,2,3,1,2,1,2,1,1,2,1,1,2,2,1,4,1,1,1,1,5,10,1,2,19,2,1,2,1,2,1,2,1,2, + 1,5,1,6,3,2,1,2,2,1,1,1,4,8,5,1,1,4,1,1,3,1,2,1,5,1,2,1,1,1,10,1,1,5,2,4,6,1,4,2,2,2,12,2,1,1,6,1,1,1,4,1,1,4,6,5,1,4,2,2,4,10,7,1,1,4,2,4, + 2,1,4,3,6,10,12,5,7,2,14,2,9,1,1,6,7,10,4,7,13,1,5,4,8,4,1,1,2,28,5,6,1,1,5,2,5,20,2,2,9,8,11,2,9,17,1,8,6,8,27,4,6,9,20,11,27,6,68,2,2,1,1, + 1,2,1,2,2,7,6,11,3,3,1,1,3,1,2,1,1,1,1,1,3,1,1,8,3,4,1,5,7,2,1,4,4,8,4,2,1,2,1,1,4,5,6,3,6,2,12,3,1,3,9,2,4,3,4,1,5,3,3,1,3,7,1,5,1,1,1,1,2, + 3,4,5,2,3,2,6,1,1,2,1,7,1,7,3,4,5,15,2,2,1,5,3,22,19,2,1,1,1,1,2,5,1,1,1,6,1,1,12,8,2,9,18,22,4,1,1,5,1,16,1,2,7,10,15,1,1,6,2,4,1,2,4,1,6, + 1,1,3,2,4,1,6,4,5,1,2,1,1,2,1,10,3,1,3,2,1,9,3,2,5,7,2,19,4,3,6,1,1,1,1,1,4,3,2,1,1,1,2,5,3,1,1,1,2,2,1,1,2,1,1,2,1,3,1,1,1,3,7,1,4,1,1,2,1, + 1,2,1,2,4,4,3,8,1,1,1,2,1,3,5,1,3,1,3,4,6,2,2,14,4,6,6,11,9,1,15,3,1,28,5,2,5,5,3,1,3,4,5,4,6,14,3,2,3,5,21,2,7,20,10,1,2,19,2,4,28,28,2,3, + 2,1,14,4,1,26,28,42,12,40,3,52,79,5,14,17,3,2,2,11,3,4,6,3,1,8,2,23,4,5,8,10,4,2,7,3,5,1,1,6,3,1,2,2,2,5,28,1,1,7,7,20,5,3,29,3,17,26,1,8,4, + 27,3,6,11,23,5,3,4,6,13,24,16,6,5,10,25,35,7,3,2,3,3,14,3,6,2,6,1,4,2,3,8,2,1,1,3,3,3,4,1,1,13,2,2,4,5,2,1,14,14,1,2,2,1,4,5,2,3,1,14,3,12, + 3,17,2,16,5,1,2,1,8,9,3,19,4,2,2,4,17,25,21,20,28,75,1,10,29,103,4,1,2,1,1,4,2,4,1,2,3,24,2,2,2,1,1,2,1,3,8,1,1,1,2,1,1,3,1,1,1,6,1,5,3,1,1, + 1,3,4,1,1,5,2,1,5,6,13,9,16,1,1,1,1,3,2,3,2,4,5,2,5,2,2,3,7,13,7,2,2,1,1,1,1,2,3,3,2,1,6,4,9,2,1,14,2,14,2,1,18,3,4,14,4,11,41,15,23,15,23, + 176,1,3,4,1,1,1,1,5,3,1,2,3,7,3,1,1,2,1,2,4,4,6,2,4,1,9,7,1,10,5,8,16,29,1,1,2,2,3,1,3,5,2,4,5,4,1,1,2,2,3,3,7,1,6,10,1,17,1,44,4,6,2,1,1,6, + 5,4,2,10,1,6,9,2,8,1,24,1,2,13,7,8,8,2,1,4,1,3,1,3,3,5,2,5,10,9,4,9,12,2,1,6,1,10,1,1,7,7,4,10,8,3,1,13,4,3,1,6,1,3,5,2,1,2,17,16,5,2,16,6, + 1,4,2,1,3,3,6,8,5,11,11,1,3,3,2,4,6,10,9,5,7,4,7,4,7,1,1,4,2,1,3,6,8,7,1,6,11,5,5,3,24,9,4,2,7,13,5,1,8,82,16,61,1,1,1,4,2,2,16,10,3,8,1,1, + 6,4,2,1,3,1,1,1,4,3,8,4,2,2,1,1,1,1,1,6,3,5,1,1,4,6,9,2,1,1,1,2,1,7,2,1,6,1,5,4,4,3,1,8,1,3,3,1,3,2,2,2,2,3,1,6,1,2,1,2,1,3,7,1,8,2,1,2,1,5, + 2,5,3,5,10,1,2,1,1,3,2,5,11,3,9,3,5,1,1,5,9,1,2,1,5,7,9,9,8,1,3,3,3,6,8,2,3,2,1,1,32,6,1,2,15,9,3,7,13,1,3,10,13,2,14,1,13,10,2,1,3,10,4,15, + 2,15,15,10,1,3,9,6,9,32,25,26,47,7,3,2,3,1,6,3,4,3,2,8,5,4,1,9,4,2,2,19,10,6,2,3,8,1,2,2,4,2,1,9,4,4,4,6,4,8,9,2,3,1,1,1,1,3,5,5,1,3,8,4,6, + 2,1,4,12,1,5,3,7,13,2,5,8,1,6,1,2,5,14,6,1,5,2,4,8,15,5,1,23,6,62,2,10,1,1,8,1,2,2,10,4,2,2,9,2,1,1,3,2,3,1,5,3,3,2,1,3,8,1,1,1,11,3,1,1,4, + 3,7,1,14,1,2,3,12,5,2,5,1,6,7,5,7,14,11,1,3,1,8,9,12,2,1,11,8,4,4,2,6,10,9,13,1,1,3,1,5,1,3,2,4,4,1,18,2,3,14,11,4,29,4,2,7,1,3,13,9,2,2,5, + 3,5,20,7,16,8,5,72,34,6,4,22,12,12,28,45,36,9,7,39,9,191,1,1,1,4,11,8,4,9,2,3,22,1,1,1,1,4,17,1,7,7,1,11,31,10,2,4,8,2,3,2,1,4,2,16,4,32,2, + 3,19,13,4,9,1,5,2,14,8,1,1,3,6,19,6,5,1,16,6,2,10,8,5,1,2,3,1,5,5,1,11,6,6,1,3,3,2,6,3,8,1,1,4,10,7,5,7,7,5,8,9,2,1,3,4,1,1,3,1,3,3,2,6,16, + 1,4,6,3,1,10,6,1,3,15,2,9,2,10,25,13,9,16,6,2,2,10,11,4,3,9,1,2,6,6,5,4,30,40,1,10,7,12,14,33,6,3,6,7,3,1,3,1,11,14,4,9,5,12,11,49,18,51,31, + 140,31,2,2,1,5,1,8,1,10,1,4,4,3,24,1,10,1,3,6,6,16,3,4,5,2,1,4,2,57,10,6,22,2,22,3,7,22,6,10,11,36,18,16,33,36,2,5,5,1,1,1,4,10,1,4,13,2,7, + 5,2,9,3,4,1,7,43,3,7,3,9,14,7,9,1,11,1,1,3,7,4,18,13,1,14,1,3,6,10,73,2,2,30,6,1,11,18,19,13,22,3,46,42,37,89,7,3,16,34,2,2,3,9,1,7,1,1,1,2, + 2,4,10,7,3,10,3,9,5,28,9,2,6,13,7,3,1,3,10,2,7,2,11,3,6,21,54,85,2,1,4,2,2,1,39,3,21,2,2,5,1,1,1,4,1,1,3,4,15,1,3,2,4,4,2,3,8,2,20,1,8,7,13, + 4,1,26,6,2,9,34,4,21,52,10,4,4,1,5,12,2,11,1,7,2,30,12,44,2,30,1,1,3,6,16,9,17,39,82,2,2,24,7,1,7,3,16,9,14,44,2,1,2,1,2,3,5,2,4,1,6,7,5,3, + 2,6,1,11,5,11,2,1,18,19,8,1,3,24,29,2,1,3,5,2,2,1,13,6,5,1,46,11,3,5,1,1,5,8,2,10,6,12,6,3,7,11,2,4,16,13,2,5,1,1,2,2,5,2,28,5,2,23,10,8,4, + 4,22,39,95,38,8,14,9,5,1,13,5,4,3,13,12,11,1,9,1,27,37,2,5,4,4,63,211,95,2,2,2,1,3,5,2,1,1,2,2,1,1,1,3,2,4,1,2,1,1,5,2,2,1,1,2,3,1,3,1,1,1, + 3,1,4,2,1,3,6,1,1,3,7,15,5,3,2,5,3,9,11,4,2,22,1,6,3,8,7,1,4,28,4,16,3,3,25,4,4,27,27,1,4,1,2,2,7,1,3,5,2,28,8,2,14,1,8,6,16,25,3,3,3,14,3, + 3,1,1,2,1,4,6,3,8,4,1,1,1,2,3,6,10,6,2,3,18,3,2,5,5,4,3,1,5,2,5,4,23,7,6,12,6,4,17,11,9,5,1,1,10,5,12,1,1,11,26,33,7,3,6,1,17,7,1,5,12,1,11, + 2,4,1,8,14,17,23,1,2,1,7,8,16,11,9,6,5,2,6,4,16,2,8,14,1,11,8,9,1,1,1,9,25,4,11,19,7,2,15,2,12,8,52,7,5,19,2,16,4,36,8,1,16,8,24,26,4,6,2,9, + 5,4,36,3,28,12,25,15,37,27,17,12,59,38,5,32,127,1,2,9,17,14,4,1,2,1,1,8,11,50,4,14,2,19,16,4,17,5,4,5,26,12,45,2,23,45,104,30,12,8,3,10,2,2, + 3,3,1,4,20,7,2,9,6,15,2,20,1,3,16,4,11,15,6,134,2,5,59,1,2,2,2,1,9,17,3,26,137,10,211,59,1,2,4,1,4,1,1,1,2,6,2,3,1,1,2,3,2,3,1,3,4,4,2,3,3, + 1,4,3,1,7,2,2,3,1,2,1,3,3,3,2,2,3,2,1,3,14,6,1,3,2,9,6,15,27,9,34,145,1,1,2,1,1,1,1,2,1,1,1,1,2,2,2,3,1,2,1,1,1,2,3,5,8,3,5,2,4,1,3,2,2,2,12, + 4,1,1,1,10,4,5,1,20,4,16,1,15,9,5,12,2,9,2,5,4,2,26,19,7,1,26,4,30,12,15,42,1,6,8,172,1,1,4,2,1,1,11,2,2,4,2,1,2,1,10,8,1,2,1,4,5,1,2,5,1,8, + 4,1,3,4,2,1,6,2,1,3,4,1,2,1,1,1,1,12,5,7,2,4,3,1,1,1,3,3,6,1,2,2,3,3,3,2,1,2,12,14,11,6,6,4,12,2,8,1,7,10,1,35,7,4,13,15,4,3,23,21,28,52,5, + 26,5,6,1,7,10,2,7,53,3,2,1,1,1,2,163,532,1,10,11,1,3,3,4,8,2,8,6,2,2,23,22,4,2,2,4,2,1,3,1,3,3,5,9,8,2,1,2,8,1,10,2,12,21,20,15,105,2,3,1,1, + 3,2,3,1,1,2,5,1,4,15,11,19,1,1,1,1,5,4,5,1,1,2,5,3,5,12,1,2,5,1,11,1,1,15,9,1,4,5,3,26,8,2,1,3,1,1,15,19,2,12,1,2,5,2,7,2,19,2,20,6,26,7,5, + 2,2,7,34,21,13,70,2,128,1,1,2,1,1,2,1,1,3,2,2,2,15,1,4,1,3,4,42,10,6,1,49,85,8,1,2,1,1,4,4,2,3,6,1,5,7,4,3,211,4,1,2,1,2,5,1,2,4,2,2,6,5,6, + 10,3,4,48,100,6,2,16,296,5,27,387,2,2,3,7,16,8,5,38,15,39,21,9,10,3,7,59,13,27,21,47,5,21,6 + }; + static ImWchar base_ranges[] = // not zero-terminated + { + 0x0020, 0x00FF, // Basic Latin + Latin Supplement + 0x2000, 0x206F, // General Punctuation + 0x3000, 0x30FF, // CJK Symbols and Punctuations, Hiragana, Katakana + 0x31F0, 0x31FF, // Katakana Phonetic Extensions + 0xFF00, 0xFFEF // Half-width characters + }; + static ImWchar full_ranges[IM_ARRAYSIZE(base_ranges) + IM_ARRAYSIZE(accumulative_offsets_from_0x4E00) * 2 + 1] = { 0 }; + if (!full_ranges[0]) + { + memcpy(full_ranges, base_ranges, sizeof(base_ranges)); + UnpackAccumulativeOffsetsIntoRanges(0x4E00, accumulative_offsets_from_0x4E00, IM_ARRAYSIZE(accumulative_offsets_from_0x4E00), full_ranges + IM_ARRAYSIZE(base_ranges)); + } + return &full_ranges[0]; +} + +const ImWchar* ImFontAtlas::GetGlyphRangesJapanese() +{ + // 1946 common ideograms code points for Japanese + // Sourced from http://theinstructionlimit.com/common-kanji-character-ranges-for-xna-spritefont-rendering + // FIXME: Source a list of the revised 2136 Joyo Kanji list from 2010 and rebuild this. + // You can use ImFontGlyphRangesBuilder to create your own ranges derived from this, by merging existing ranges or adding new characters. + // (Stored as accumulative offsets from the initial unicode codepoint 0x4E00. This encoding is designed to helps us compact the source code size.) + static const short accumulative_offsets_from_0x4E00[] = + { + 0,1,2,4,1,1,1,1,2,1,6,2,2,1,8,5,7,11,1,2,10,10,8,2,4,20,2,11,8,2,1,2,1,6,2,1,7,5,3,7,1,1,13,7,9,1,4,6,1,2,1,10,1,1,9,2,2,4,5,6,14,1,1,9,3,18, + 5,4,2,2,10,7,1,1,1,3,2,4,3,23,2,10,12,2,14,2,4,13,1,6,10,3,1,7,13,6,4,13,5,2,3,17,2,2,5,7,6,4,1,7,14,16,6,13,9,15,1,1,7,16,4,7,1,19,9,2,7,15, + 2,6,5,13,25,4,14,13,11,25,1,1,1,2,1,2,2,3,10,11,3,3,1,1,4,4,2,1,4,9,1,4,3,5,5,2,7,12,11,15,7,16,4,5,16,2,1,1,6,3,3,1,1,2,7,6,6,7,1,4,7,6,1,1, + 2,1,12,3,3,9,5,8,1,11,1,2,3,18,20,4,1,3,6,1,7,3,5,5,7,2,2,12,3,1,4,2,3,2,3,11,8,7,4,17,1,9,25,1,1,4,2,2,4,1,2,7,1,1,1,3,1,2,6,16,1,2,1,1,3,12, + 20,2,5,20,8,7,6,2,1,1,1,1,6,2,1,2,10,1,1,6,1,3,1,2,1,4,1,12,4,1,3,1,1,1,1,1,10,4,7,5,13,1,15,1,1,30,11,9,1,15,38,14,1,32,17,20,1,9,31,2,21,9, + 4,49,22,2,1,13,1,11,45,35,43,55,12,19,83,1,3,2,3,13,2,1,7,3,18,3,13,8,1,8,18,5,3,7,25,24,9,24,40,3,17,24,2,1,6,2,3,16,15,6,7,3,12,1,9,7,3,3, + 3,15,21,5,16,4,5,12,11,11,3,6,3,2,31,3,2,1,1,23,6,6,1,4,2,6,5,2,1,1,3,3,22,2,6,2,3,17,3,2,4,5,1,9,5,1,1,6,15,12,3,17,2,14,2,8,1,23,16,4,2,23, + 8,15,23,20,12,25,19,47,11,21,65,46,4,3,1,5,6,1,2,5,26,2,1,1,3,11,1,1,1,2,1,2,3,1,1,10,2,3,1,1,1,3,6,3,2,2,6,6,9,2,2,2,6,2,5,10,2,4,1,2,1,2,2, + 3,1,1,3,1,2,9,23,9,2,1,1,1,1,5,3,2,1,10,9,6,1,10,2,31,25,3,7,5,40,1,15,6,17,7,27,180,1,3,2,2,1,1,1,6,3,10,7,1,3,6,17,8,6,2,2,1,3,5,5,8,16,14, + 15,1,1,4,1,2,1,1,1,3,2,7,5,6,2,5,10,1,4,2,9,1,1,11,6,1,44,1,3,7,9,5,1,3,1,1,10,7,1,10,4,2,7,21,15,7,2,5,1,8,3,4,1,3,1,6,1,4,2,1,4,10,8,1,4,5, + 1,5,10,2,7,1,10,1,1,3,4,11,10,29,4,7,3,5,2,3,33,5,2,19,3,1,4,2,6,31,11,1,3,3,3,1,8,10,9,12,11,12,8,3,14,8,6,11,1,4,41,3,1,2,7,13,1,5,6,2,6,12, + 12,22,5,9,4,8,9,9,34,6,24,1,1,20,9,9,3,4,1,7,2,2,2,6,2,28,5,3,6,1,4,6,7,4,2,1,4,2,13,6,4,4,3,1,8,8,3,2,1,5,1,2,2,3,1,11,11,7,3,6,10,8,6,16,16, + 22,7,12,6,21,5,4,6,6,3,6,1,3,2,1,2,8,29,1,10,1,6,13,6,6,19,31,1,13,4,4,22,17,26,33,10,4,15,12,25,6,67,10,2,3,1,6,10,2,6,2,9,1,9,4,4,1,2,16,2, + 5,9,2,3,8,1,8,3,9,4,8,6,4,8,11,3,2,1,1,3,26,1,7,5,1,11,1,5,3,5,2,13,6,39,5,1,5,2,11,6,10,5,1,15,5,3,6,19,21,22,2,4,1,6,1,8,1,4,8,2,4,2,2,9,2, + 1,1,1,4,3,6,3,12,7,1,14,2,4,10,2,13,1,17,7,3,2,1,3,2,13,7,14,12,3,1,29,2,8,9,15,14,9,14,1,3,1,6,5,9,11,3,38,43,20,7,7,8,5,15,12,19,15,81,8,7, + 1,5,73,13,37,28,8,8,1,15,18,20,165,28,1,6,11,8,4,14,7,15,1,3,3,6,4,1,7,14,1,1,11,30,1,5,1,4,14,1,4,2,7,52,2,6,29,3,1,9,1,21,3,5,1,26,3,11,14, + 11,1,17,5,1,2,1,3,2,8,1,2,9,12,1,1,2,3,8,3,24,12,7,7,5,17,3,3,3,1,23,10,4,4,6,3,1,16,17,22,3,10,21,16,16,6,4,10,2,1,1,2,8,8,6,5,3,3,3,39,25, + 15,1,1,16,6,7,25,15,6,6,12,1,22,13,1,4,9,5,12,2,9,1,12,28,8,3,5,10,22,60,1,2,40,4,61,63,4,1,13,12,1,4,31,12,1,14,89,5,16,6,29,14,2,5,49,18,18, + 5,29,33,47,1,17,1,19,12,2,9,7,39,12,3,7,12,39,3,1,46,4,12,3,8,9,5,31,15,18,3,2,2,66,19,13,17,5,3,46,124,13,57,34,2,5,4,5,8,1,1,1,4,3,1,17,5, + 3,5,3,1,8,5,6,3,27,3,26,7,12,7,2,17,3,7,18,78,16,4,36,1,2,1,6,2,1,39,17,7,4,13,4,4,4,1,10,4,2,4,6,3,10,1,19,1,26,2,4,33,2,73,47,7,3,8,2,4,15, + 18,1,29,2,41,14,1,21,16,41,7,39,25,13,44,2,2,10,1,13,7,1,7,3,5,20,4,8,2,49,1,10,6,1,6,7,10,7,11,16,3,12,20,4,10,3,1,2,11,2,28,9,2,4,7,2,15,1, + 27,1,28,17,4,5,10,7,3,24,10,11,6,26,3,2,7,2,2,49,16,10,16,15,4,5,27,61,30,14,38,22,2,7,5,1,3,12,23,24,17,17,3,3,2,4,1,6,2,7,5,1,1,5,1,1,9,4, + 1,3,6,1,8,2,8,4,14,3,5,11,4,1,3,32,1,19,4,1,13,11,5,2,1,8,6,8,1,6,5,13,3,23,11,5,3,16,3,9,10,1,24,3,198,52,4,2,2,5,14,5,4,22,5,20,4,11,6,41, + 1,5,2,2,11,5,2,28,35,8,22,3,18,3,10,7,5,3,4,1,5,3,8,9,3,6,2,16,22,4,5,5,3,3,18,23,2,6,23,5,27,8,1,33,2,12,43,16,5,2,3,6,1,20,4,2,9,7,1,11,2, + 10,3,14,31,9,3,25,18,20,2,5,5,26,14,1,11,17,12,40,19,9,6,31,83,2,7,9,19,78,12,14,21,76,12,113,79,34,4,1,1,61,18,85,10,2,2,13,31,11,50,6,33,159, + 179,6,6,7,4,4,2,4,2,5,8,7,20,32,22,1,3,10,6,7,28,5,10,9,2,77,19,13,2,5,1,4,4,7,4,13,3,9,31,17,3,26,2,6,6,5,4,1,7,11,3,4,2,1,6,2,20,4,1,9,2,6, + 3,7,1,1,1,20,2,3,1,6,2,3,6,2,4,8,1,5,13,8,4,11,23,1,10,6,2,1,3,21,2,2,4,24,31,4,10,10,2,5,192,15,4,16,7,9,51,1,2,1,1,5,1,1,2,1,3,5,3,1,3,4,1, + 3,1,3,3,9,8,1,2,2,2,4,4,18,12,92,2,10,4,3,14,5,25,16,42,4,14,4,2,21,5,126,30,31,2,1,5,13,3,22,5,6,6,20,12,1,14,12,87,3,19,1,8,2,9,9,3,3,23,2, + 3,7,6,3,1,2,3,9,1,3,1,6,3,2,1,3,11,3,1,6,10,3,2,3,1,2,1,5,1,1,11,3,6,4,1,7,2,1,2,5,5,34,4,14,18,4,19,7,5,8,2,6,79,1,5,2,14,8,2,9,2,1,36,28,16, + 4,1,1,1,2,12,6,42,39,16,23,7,15,15,3,2,12,7,21,64,6,9,28,8,12,3,3,41,59,24,51,55,57,294,9,9,2,6,2,15,1,2,13,38,90,9,9,9,3,11,7,1,1,1,5,6,3,2, + 1,2,2,3,8,1,4,4,1,5,7,1,4,3,20,4,9,1,1,1,5,5,17,1,5,2,6,2,4,1,4,5,7,3,18,11,11,32,7,5,4,7,11,127,8,4,3,3,1,10,1,1,6,21,14,1,16,1,7,1,3,6,9,65, + 51,4,3,13,3,10,1,1,12,9,21,110,3,19,24,1,1,10,62,4,1,29,42,78,28,20,18,82,6,3,15,6,84,58,253,15,155,264,15,21,9,14,7,58,40,39, + }; + static ImWchar base_ranges[] = // not zero-terminated + { + 0x0020, 0x00FF, // Basic Latin + Latin Supplement + 0x3000, 0x30FF, // CJK Symbols and Punctuations, Hiragana, Katakana + 0x31F0, 0x31FF, // Katakana Phonetic Extensions + 0xFF00, 0xFFEF // Half-width characters + }; + static ImWchar full_ranges[IM_ARRAYSIZE(base_ranges) + IM_ARRAYSIZE(accumulative_offsets_from_0x4E00)*2 + 1] = { 0 }; + if (!full_ranges[0]) + { + memcpy(full_ranges, base_ranges, sizeof(base_ranges)); + UnpackAccumulativeOffsetsIntoRanges(0x4E00, accumulative_offsets_from_0x4E00, IM_ARRAYSIZE(accumulative_offsets_from_0x4E00), full_ranges + IM_ARRAYSIZE(base_ranges)); + } + return &full_ranges[0]; +} + +const ImWchar* ImFontAtlas::GetGlyphRangesCyrillic() +{ + static const ImWchar ranges[] = + { + 0x0020, 0x00FF, // Basic Latin + Latin Supplement + 0x0400, 0x052F, // Cyrillic + Cyrillic Supplement + 0x2DE0, 0x2DFF, // Cyrillic Extended-A + 0xA640, 0xA69F, // Cyrillic Extended-B + 0, + }; + return &ranges[0]; +} + +const ImWchar* ImFontAtlas::GetGlyphRangesThai() +{ + static const ImWchar ranges[] = + { + 0x0020, 0x00FF, // Basic Latin + 0x2010, 0x205E, // Punctuations + 0x0E00, 0x0E7F, // Thai + 0, + }; + return &ranges[0]; +} + +const ImWchar* ImFontAtlas::GetGlyphRangesVietnamese() +{ + static const ImWchar ranges[] = + { + 0x0020, 0x00FF, // Basic Latin + 0x0102, 0x0103, + 0x0110, 0x0111, + 0x0128, 0x0129, + 0x0168, 0x0169, + 0x01A0, 0x01A1, + 0x01AF, 0x01B0, + 0x1EA0, 0x1EF9, + 0, + }; + return &ranges[0]; +} + +//----------------------------------------------------------------------------- +// [SECTION] ImFontGlyphRangesBuilder +//----------------------------------------------------------------------------- + +void ImFontGlyphRangesBuilder::AddText(const char* text, const char* text_end) +{ + while (text_end ? (text < text_end) : *text) + { + unsigned int c = 0; + int c_len = ImTextCharFromUtf8(&c, text, text_end); + text += c_len; + if (c_len == 0) + break; + AddChar((ImWchar)c); + } +} + +void ImFontGlyphRangesBuilder::AddRanges(const ImWchar* ranges) +{ + for (; ranges[0]; ranges += 2) + for (ImWchar c = ranges[0]; c <= ranges[1]; c++) + AddChar(c); +} + +void ImFontGlyphRangesBuilder::BuildRanges(ImVector* out_ranges) +{ + const int max_codepoint = IM_UNICODE_CODEPOINT_MAX; + for (int n = 0; n <= max_codepoint; n++) + if (GetBit(n)) + { + out_ranges->push_back((ImWchar)n); + while (n < max_codepoint && GetBit(n + 1)) + n++; + out_ranges->push_back((ImWchar)n); + } + out_ranges->push_back(0); +} + +//----------------------------------------------------------------------------- +// [SECTION] ImFont +//----------------------------------------------------------------------------- + +ImFont::ImFont() +{ + FontSize = 0.0f; + FallbackAdvanceX = 0.0f; + FallbackChar = (ImWchar)'?'; + EllipsisChar = (ImWchar)-1; + DisplayOffset = ImVec2(0.0f, 0.0f); + FallbackGlyph = NULL; + ContainerAtlas = NULL; + ConfigData = NULL; + ConfigDataCount = 0; + DirtyLookupTables = false; + Scale = 1.0f; + Ascent = Descent = 0.0f; + MetricsTotalSurface = 0; + memset(Used4kPagesMap, 0, sizeof(Used4kPagesMap)); +} + +ImFont::~ImFont() +{ + ClearOutputData(); +} + +void ImFont::ClearOutputData() +{ + FontSize = 0.0f; + FallbackAdvanceX = 0.0f; + Glyphs.clear(); + IndexAdvanceX.clear(); + IndexLookup.clear(); + FallbackGlyph = NULL; + ContainerAtlas = NULL; + DirtyLookupTables = true; + Ascent = Descent = 0.0f; + MetricsTotalSurface = 0; +} + +void ImFont::BuildLookupTable() +{ + int max_codepoint = 0; + for (int i = 0; i != Glyphs.Size; i++) + max_codepoint = ImMax(max_codepoint, (int)Glyphs[i].Codepoint); + + // Build lookup table + IM_ASSERT(Glyphs.Size < 0xFFFF); // -1 is reserved + IndexAdvanceX.clear(); + IndexLookup.clear(); + DirtyLookupTables = false; + memset(Used4kPagesMap, 0, sizeof(Used4kPagesMap)); + GrowIndex(max_codepoint + 1); + for (int i = 0; i < Glyphs.Size; i++) + { + int codepoint = (int)Glyphs[i].Codepoint; + IndexAdvanceX[codepoint] = Glyphs[i].AdvanceX; + IndexLookup[codepoint] = (ImWchar)i; + + // Mark 4K page as used + const int page_n = codepoint / 4096; + Used4kPagesMap[page_n >> 3] |= 1 << (page_n & 7); + } + + // Create a glyph to handle TAB + // FIXME: Needs proper TAB handling but it needs to be contextualized (or we could arbitrary say that each string starts at "column 0" ?) + if (FindGlyph((ImWchar)' ')) + { + if (Glyphs.back().Codepoint != '\t') // So we can call this function multiple times (FIXME: Flaky) + Glyphs.resize(Glyphs.Size + 1); + ImFontGlyph& tab_glyph = Glyphs.back(); + tab_glyph = *FindGlyph((ImWchar)' '); + tab_glyph.Codepoint = '\t'; + tab_glyph.AdvanceX *= IM_TABSIZE; + IndexAdvanceX[(int)tab_glyph.Codepoint] = (float)tab_glyph.AdvanceX; + IndexLookup[(int)tab_glyph.Codepoint] = (ImWchar)(Glyphs.Size-1); + } + + // Mark special glyphs as not visible (note that AddGlyph already mark as non-visible glyphs with zero-size polygons) + SetGlyphVisible((ImWchar)' ', false); + SetGlyphVisible((ImWchar)'\t', false); + + // Setup fall-backs + FallbackGlyph = FindGlyphNoFallback(FallbackChar); + FallbackAdvanceX = FallbackGlyph ? FallbackGlyph->AdvanceX : 0.0f; + for (int i = 0; i < max_codepoint + 1; i++) + if (IndexAdvanceX[i] < 0.0f) + IndexAdvanceX[i] = FallbackAdvanceX; +} + +// API is designed this way to avoid exposing the 4K page size +// e.g. use with IsGlyphRangeUnused(0, 255) +bool ImFont::IsGlyphRangeUnused(unsigned int c_begin, unsigned int c_last) +{ + unsigned int page_begin = (c_begin / 4096); + unsigned int page_last = (c_last / 4096); + for (unsigned int page_n = page_begin; page_n <= page_last; page_n++) + if ((page_n >> 3) < sizeof(Used4kPagesMap)) + if (Used4kPagesMap[page_n >> 3] & (1 << (page_n & 7))) + return false; + return true; +} + +void ImFont::SetGlyphVisible(ImWchar c, bool visible) +{ + if (ImFontGlyph* glyph = (ImFontGlyph*)(void*)FindGlyph((ImWchar)c)) + glyph->Visible = visible ? 1 : 0; +} + +void ImFont::SetFallbackChar(ImWchar c) +{ + FallbackChar = c; + BuildLookupTable(); +} + +void ImFont::GrowIndex(int new_size) +{ + IM_ASSERT(IndexAdvanceX.Size == IndexLookup.Size); + if (new_size <= IndexLookup.Size) + return; + IndexAdvanceX.resize(new_size, -1.0f); + IndexLookup.resize(new_size, (ImWchar)-1); +} + +// x0/y0/x1/y1 are offset from the character upper-left layout position, in pixels. Therefore x0/y0 are often fairly close to zero. +// Not to be mistaken with texture coordinates, which are held by u0/v0/u1/v1 in normalized format (0.0..1.0 on each texture axis). +void ImFont::AddGlyph(ImWchar codepoint, float x0, float y0, float x1, float y1, float u0, float v0, float u1, float v1, float advance_x) +{ + Glyphs.resize(Glyphs.Size + 1); + ImFontGlyph& glyph = Glyphs.back(); + glyph.Codepoint = (unsigned int)codepoint; + glyph.Visible = (x0 != x1) && (y0 != y1); + glyph.X0 = x0; + glyph.Y0 = y0; + glyph.X1 = x1; + glyph.Y1 = y1; + glyph.U0 = u0; + glyph.V0 = v0; + glyph.U1 = u1; + glyph.V1 = v1; + glyph.AdvanceX = advance_x + ConfigData->GlyphExtraSpacing.x; // Bake spacing into AdvanceX + + if (ConfigData->PixelSnapH) + glyph.AdvanceX = IM_ROUND(glyph.AdvanceX); + + // Compute rough surface usage metrics (+1 to account for average padding, +0.99 to round) + DirtyLookupTables = true; + MetricsTotalSurface += (int)((glyph.U1 - glyph.U0) * ContainerAtlas->TexWidth + 1.99f) * (int)((glyph.V1 - glyph.V0) * ContainerAtlas->TexHeight + 1.99f); +} + +void ImFont::AddRemapChar(ImWchar dst, ImWchar src, bool overwrite_dst) +{ + IM_ASSERT(IndexLookup.Size > 0); // Currently this can only be called AFTER the font has been built, aka after calling ImFontAtlas::GetTexDataAs*() function. + unsigned int index_size = (unsigned int)IndexLookup.Size; + + if (dst < index_size && IndexLookup.Data[dst] == (ImWchar)-1 && !overwrite_dst) // 'dst' already exists + return; + if (src >= index_size && dst >= index_size) // both 'dst' and 'src' don't exist -> no-op + return; + + GrowIndex(dst + 1); + IndexLookup[dst] = (src < index_size) ? IndexLookup.Data[src] : (ImWchar)-1; + IndexAdvanceX[dst] = (src < index_size) ? IndexAdvanceX.Data[src] : 1.0f; +} + +const ImFontGlyph* ImFont::FindGlyph(ImWchar c) const +{ + if (c >= (size_t)IndexLookup.Size) + return FallbackGlyph; + const ImWchar i = IndexLookup.Data[c]; + if (i == (ImWchar)-1) + return FallbackGlyph; + return &Glyphs.Data[i]; +} + +const ImFontGlyph* ImFont::FindGlyphNoFallback(ImWchar c) const +{ + if (c >= (size_t)IndexLookup.Size) + return NULL; + const ImWchar i = IndexLookup.Data[c]; + if (i == (ImWchar)-1) + return NULL; + return &Glyphs.Data[i]; +} + +const char* ImFont::CalcWordWrapPositionA(float scale, const char* text, const char* text_end, float wrap_width) const +{ + // Simple word-wrapping for English, not full-featured. Please submit failing cases! + // FIXME: Much possible improvements (don't cut things like "word !", "word!!!" but cut within "word,,,,", more sensible support for punctuations, support for Unicode punctuations, etc.) + + // For references, possible wrap point marked with ^ + // "aaa bbb, ccc,ddd. eee fff. ggg!" + // ^ ^ ^ ^ ^__ ^ ^ + + // List of hardcoded separators: .,;!?'" + + // Skip extra blanks after a line returns (that includes not counting them in width computation) + // e.g. "Hello world" --> "Hello" "World" + + // Cut words that cannot possibly fit within one line. + // e.g.: "The tropical fish" with ~5 characters worth of width --> "The tr" "opical" "fish" + + float line_width = 0.0f; + float word_width = 0.0f; + float blank_width = 0.0f; + wrap_width /= scale; // We work with unscaled widths to avoid scaling every characters + + const char* word_end = text; + const char* prev_word_end = NULL; + bool inside_word = true; + + const char* s = text; + while (s < text_end) + { + unsigned int c = (unsigned int)*s; + const char* next_s; + if (c < 0x80) + next_s = s + 1; + else + next_s = s + ImTextCharFromUtf8(&c, s, text_end); + if (c == 0) + break; + + if (c < 32) + { + if (c == '\n') + { + line_width = word_width = blank_width = 0.0f; + inside_word = true; + s = next_s; + continue; + } + if (c == '\r') + { + s = next_s; + continue; + } + } + + const float char_width = ((int)c < IndexAdvanceX.Size ? IndexAdvanceX.Data[c] : FallbackAdvanceX); + if (ImCharIsBlankW(c)) + { + if (inside_word) + { + line_width += blank_width; + blank_width = 0.0f; + word_end = s; + } + blank_width += char_width; + inside_word = false; + } + else + { + word_width += char_width; + if (inside_word) + { + word_end = next_s; + } + else + { + prev_word_end = word_end; + line_width += word_width + blank_width; + word_width = blank_width = 0.0f; + } + + // Allow wrapping after punctuation. + inside_word = !(c == '.' || c == ',' || c == ';' || c == '!' || c == '?' || c == '\"'); + } + + // We ignore blank width at the end of the line (they can be skipped) + if (line_width + word_width > wrap_width) + { + // Words that cannot possibly fit within an entire line will be cut anywhere. + if (word_width < wrap_width) + s = prev_word_end ? prev_word_end : word_end; + break; + } + + s = next_s; + } + + return s; +} + +ImVec2 ImFont::CalcTextSizeA(float size, float max_width, float wrap_width, const char* text_begin, const char* text_end, const char** remaining) const +{ + if (!text_end) + text_end = text_begin + strlen(text_begin); // FIXME-OPT: Need to avoid this. + + const float line_height = size; + const float scale = size / FontSize; + + ImVec2 text_size = ImVec2(0,0); + float line_width = 0.0f; + + const bool word_wrap_enabled = (wrap_width > 0.0f); + const char* word_wrap_eol = NULL; + + const char* s = text_begin; + while (s < text_end) + { + if (word_wrap_enabled) + { + // Calculate how far we can render. Requires two passes on the string data but keeps the code simple and not intrusive for what's essentially an uncommon feature. + if (!word_wrap_eol) + { + word_wrap_eol = CalcWordWrapPositionA(scale, s, text_end, wrap_width - line_width); + if (word_wrap_eol == s) // Wrap_width is too small to fit anything. Force displaying 1 character to minimize the height discontinuity. + word_wrap_eol++; // +1 may not be a character start point in UTF-8 but it's ok because we use s >= word_wrap_eol below + } + + if (s >= word_wrap_eol) + { + if (text_size.x < line_width) + text_size.x = line_width; + text_size.y += line_height; + line_width = 0.0f; + word_wrap_eol = NULL; + + // Wrapping skips upcoming blanks + while (s < text_end) + { + const char c = *s; + if (ImCharIsBlankA(c)) { s++; } else if (c == '\n') { s++; break; } else { break; } + } + continue; + } + } + + // Decode and advance source + const char* prev_s = s; + unsigned int c = (unsigned int)*s; + if (c < 0x80) + { + s += 1; + } + else + { + s += ImTextCharFromUtf8(&c, s, text_end); + if (c == 0) // Malformed UTF-8? + break; + } + + if (c < 32) + { + if (c == '\n') + { + text_size.x = ImMax(text_size.x, line_width); + text_size.y += line_height; + line_width = 0.0f; + continue; + } + if (c == '\r') + continue; + } + + const float char_width = ((int)c < IndexAdvanceX.Size ? IndexAdvanceX.Data[c] : FallbackAdvanceX) * scale; + if (line_width + char_width >= max_width) + { + s = prev_s; + break; + } + + line_width += char_width; + } + + if (text_size.x < line_width) + text_size.x = line_width; + + if (line_width > 0 || text_size.y == 0.0f) + text_size.y += line_height; + + if (remaining) + *remaining = s; + + return text_size; +} + +void ImFont::RenderChar(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col, ImWchar c) const +{ + const ImFontGlyph* glyph = FindGlyph(c); + if (!glyph || !glyph->Visible) + return; + float scale = (size >= 0.0f) ? (size / FontSize) : 1.0f; + pos.x = IM_FLOOR(pos.x + DisplayOffset.x); + pos.y = IM_FLOOR(pos.y + DisplayOffset.y); + draw_list->PrimReserve(6, 4); + draw_list->PrimRectUV(ImVec2(pos.x + glyph->X0 * scale, pos.y + glyph->Y0 * scale), ImVec2(pos.x + glyph->X1 * scale, pos.y + glyph->Y1 * scale), ImVec2(glyph->U0, glyph->V0), ImVec2(glyph->U1, glyph->V1), col); +} + +void ImFont::RenderText(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col, const ImVec4& clip_rect, const char* text_begin, const char* text_end, float wrap_width, bool cpu_fine_clip) const +{ + if (!text_end) + text_end = text_begin + strlen(text_begin); // ImGui:: functions generally already provides a valid text_end, so this is merely to handle direct calls. + + // Align to be pixel perfect + pos.x = IM_FLOOR(pos.x + DisplayOffset.x); + pos.y = IM_FLOOR(pos.y + DisplayOffset.y); + float x = pos.x; + float y = pos.y; + if (y > clip_rect.w) + return; + + const float scale = size / FontSize; + const float line_height = FontSize * scale; + const bool word_wrap_enabled = (wrap_width > 0.0f); + const char* word_wrap_eol = NULL; + + // Fast-forward to first visible line + const char* s = text_begin; + if (y + line_height < clip_rect.y && !word_wrap_enabled) + while (y + line_height < clip_rect.y && s < text_end) + { + s = (const char*)memchr(s, '\n', text_end - s); + s = s ? s + 1 : text_end; + y += line_height; + } + + // For large text, scan for the last visible line in order to avoid over-reserving in the call to PrimReserve() + // Note that very large horizontal line will still be affected by the issue (e.g. a one megabyte string buffer without a newline will likely crash atm) + if (text_end - s > 10000 && !word_wrap_enabled) + { + const char* s_end = s; + float y_end = y; + while (y_end < clip_rect.w && s_end < text_end) + { + s_end = (const char*)memchr(s_end, '\n', text_end - s_end); + s_end = s_end ? s_end + 1 : text_end; + y_end += line_height; + } + text_end = s_end; + } + if (s == text_end) + return; + + // Reserve vertices for remaining worse case (over-reserving is useful and easily amortized) + const int vtx_count_max = (int)(text_end - s) * 4; + const int idx_count_max = (int)(text_end - s) * 6; + const int idx_expected_size = draw_list->IdxBuffer.Size + idx_count_max; + draw_list->PrimReserve(idx_count_max, vtx_count_max); + + ImDrawVert* vtx_write = draw_list->_VtxWritePtr; + ImDrawIdx* idx_write = draw_list->_IdxWritePtr; + unsigned int vtx_current_idx = draw_list->_VtxCurrentIdx; + + while (s < text_end) + { + if (word_wrap_enabled) + { + // Calculate how far we can render. Requires two passes on the string data but keeps the code simple and not intrusive for what's essentially an uncommon feature. + if (!word_wrap_eol) + { + word_wrap_eol = CalcWordWrapPositionA(scale, s, text_end, wrap_width - (x - pos.x)); + if (word_wrap_eol == s) // Wrap_width is too small to fit anything. Force displaying 1 character to minimize the height discontinuity. + word_wrap_eol++; // +1 may not be a character start point in UTF-8 but it's ok because we use s >= word_wrap_eol below + } + + if (s >= word_wrap_eol) + { + x = pos.x; + y += line_height; + word_wrap_eol = NULL; + + // Wrapping skips upcoming blanks + while (s < text_end) + { + const char c = *s; + if (ImCharIsBlankA(c)) { s++; } else if (c == '\n') { s++; break; } else { break; } + } + continue; + } + } + + // Decode and advance source + unsigned int c = (unsigned int)*s; + if (c < 0x80) + { + s += 1; + } + else + { + s += ImTextCharFromUtf8(&c, s, text_end); + if (c == 0) // Malformed UTF-8? + break; + } + + if (c < 32) + { + if (c == '\n') + { + x = pos.x; + y += line_height; + if (y > clip_rect.w) + break; // break out of main loop + continue; + } + if (c == '\r') + continue; + } + + const ImFontGlyph* glyph = FindGlyph((ImWchar)c); + if (glyph == NULL) + continue; + + float char_width = glyph->AdvanceX * scale; + if (glyph->Visible) + { + // We don't do a second finer clipping test on the Y axis as we've already skipped anything before clip_rect.y and exit once we pass clip_rect.w + float x1 = x + glyph->X0 * scale; + float x2 = x + glyph->X1 * scale; + float y1 = y + glyph->Y0 * scale; + float y2 = y + glyph->Y1 * scale; + if (x1 <= clip_rect.z && x2 >= clip_rect.x) + { + // Render a character + float u1 = glyph->U0; + float v1 = glyph->V0; + float u2 = glyph->U1; + float v2 = glyph->V1; + + // CPU side clipping used to fit text in their frame when the frame is too small. Only does clipping for axis aligned quads. + if (cpu_fine_clip) + { + if (x1 < clip_rect.x) + { + u1 = u1 + (1.0f - (x2 - clip_rect.x) / (x2 - x1)) * (u2 - u1); + x1 = clip_rect.x; + } + if (y1 < clip_rect.y) + { + v1 = v1 + (1.0f - (y2 - clip_rect.y) / (y2 - y1)) * (v2 - v1); + y1 = clip_rect.y; + } + if (x2 > clip_rect.z) + { + u2 = u1 + ((clip_rect.z - x1) / (x2 - x1)) * (u2 - u1); + x2 = clip_rect.z; + } + if (y2 > clip_rect.w) + { + v2 = v1 + ((clip_rect.w - y1) / (y2 - y1)) * (v2 - v1); + y2 = clip_rect.w; + } + if (y1 >= y2) + { + x += char_width; + continue; + } + } + + // We are NOT calling PrimRectUV() here because non-inlined causes too much overhead in a debug builds. Inlined here: + { + idx_write[0] = (ImDrawIdx)(vtx_current_idx); idx_write[1] = (ImDrawIdx)(vtx_current_idx+1); idx_write[2] = (ImDrawIdx)(vtx_current_idx+2); + idx_write[3] = (ImDrawIdx)(vtx_current_idx); idx_write[4] = (ImDrawIdx)(vtx_current_idx+2); idx_write[5] = (ImDrawIdx)(vtx_current_idx+3); + vtx_write[0].pos.x = x1; vtx_write[0].pos.y = y1; vtx_write[0].col = col; vtx_write[0].uv.x = u1; vtx_write[0].uv.y = v1; + vtx_write[1].pos.x = x2; vtx_write[1].pos.y = y1; vtx_write[1].col = col; vtx_write[1].uv.x = u2; vtx_write[1].uv.y = v1; + vtx_write[2].pos.x = x2; vtx_write[2].pos.y = y2; vtx_write[2].col = col; vtx_write[2].uv.x = u2; vtx_write[2].uv.y = v2; + vtx_write[3].pos.x = x1; vtx_write[3].pos.y = y2; vtx_write[3].col = col; vtx_write[3].uv.x = u1; vtx_write[3].uv.y = v2; + vtx_write += 4; + vtx_current_idx += 4; + idx_write += 6; + } + } + } + x += char_width; + } + + // Give back unused vertices (clipped ones, blanks) ~ this is essentially a PrimUnreserve() action. + draw_list->VtxBuffer.Size = (int)(vtx_write - draw_list->VtxBuffer.Data); // Same as calling shrink() + draw_list->IdxBuffer.Size = (int)(idx_write - draw_list->IdxBuffer.Data); + draw_list->CmdBuffer[draw_list->CmdBuffer.Size-1].ElemCount -= (idx_expected_size - draw_list->IdxBuffer.Size); + draw_list->_VtxWritePtr = vtx_write; + draw_list->_IdxWritePtr = idx_write; + draw_list->_VtxCurrentIdx = vtx_current_idx; +} + +//----------------------------------------------------------------------------- +// [SECTION] ImGui Internal Render Helpers +//----------------------------------------------------------------------------- +// Vaguely redesigned to stop accessing ImGui global state: +// - RenderArrow() +// - RenderBullet() +// - RenderCheckMark() +// - RenderMouseCursor() +// - RenderArrowDockMenu() +// - RenderArrowPointingAt() +// - RenderRectFilledRangeH() +// - RenderRectFilledWithHole() +//----------------------------------------------------------------------------- +// Function in need of a redesign (legacy mess) +// - RenderColorRectWithAlphaCheckerboard() +//----------------------------------------------------------------------------- + +// Render an arrow aimed to be aligned with text (p_min is a position in the same space text would be positioned). To e.g. denote expanded/collapsed state +void ImGui::RenderArrow(ImDrawList* draw_list, ImVec2 pos, ImU32 col, ImGuiDir dir, float scale) +{ + const float h = draw_list->_Data->FontSize * 1.00f; + float r = h * 0.40f * scale; + ImVec2 center = pos + ImVec2(h * 0.50f, h * 0.50f * scale); + + ImVec2 a, b, c; + switch (dir) + { + case ImGuiDir_Up: + case ImGuiDir_Down: + if (dir == ImGuiDir_Up) r = -r; + a = ImVec2(+0.000f, +0.750f) * r; + b = ImVec2(-0.866f, -0.750f) * r; + c = ImVec2(+0.866f, -0.750f) * r; + break; + case ImGuiDir_Left: + case ImGuiDir_Right: + if (dir == ImGuiDir_Left) r = -r; + a = ImVec2(+0.750f, +0.000f) * r; + b = ImVec2(-0.750f, +0.866f) * r; + c = ImVec2(-0.750f, -0.866f) * r; + break; + case ImGuiDir_None: + case ImGuiDir_COUNT: + IM_ASSERT(0); + break; + } + draw_list->AddTriangleFilled(center + a, center + b, center + c, col); +} + +void ImGui::RenderBullet(ImDrawList* draw_list, ImVec2 pos, ImU32 col) +{ + draw_list->AddCircleFilled(pos, draw_list->_Data->FontSize * 0.20f, col, 8); +} + +void ImGui::RenderCheckMark(ImDrawList* draw_list, ImVec2 pos, ImU32 col, float sz) +{ + float thickness = ImMax(sz / 5.0f, 1.0f); + sz -= thickness * 0.5f; + pos += ImVec2(thickness * 0.25f, thickness * 0.25f); + + float third = sz / 3.0f; + float bx = pos.x + third; + float by = pos.y + sz - third * 0.5f; + draw_list->PathLineTo(ImVec2(bx - third, by - third)); + draw_list->PathLineTo(ImVec2(bx, by)); + draw_list->PathLineTo(ImVec2(bx + third * 2.0f, by - third * 2.0f)); + draw_list->PathStroke(col, false, thickness); +} + +void ImGui::RenderMouseCursor(ImDrawList* draw_list, ImVec2 pos, float scale, ImGuiMouseCursor mouse_cursor, ImU32 col_fill, ImU32 col_border, ImU32 col_shadow) +{ + if (mouse_cursor == ImGuiMouseCursor_None) + return; + IM_ASSERT(mouse_cursor > ImGuiMouseCursor_None && mouse_cursor < ImGuiMouseCursor_COUNT); + + ImFontAtlas* font_atlas = draw_list->_Data->Font->ContainerAtlas; + ImVec2 offset, size, uv[4]; + if (font_atlas->GetMouseCursorTexData(mouse_cursor, &offset, &size, &uv[0], &uv[2])) + { + pos -= offset; + const ImTextureID tex_id = font_atlas->TexID; + draw_list->PushTextureID(tex_id); + draw_list->AddImage(tex_id, pos + ImVec2(1,0)*scale, pos + ImVec2(1,0)*scale + size*scale, uv[2], uv[3], col_shadow); + draw_list->AddImage(tex_id, pos + ImVec2(2,0)*scale, pos + ImVec2(2,0)*scale + size*scale, uv[2], uv[3], col_shadow); + draw_list->AddImage(tex_id, pos, pos + size*scale, uv[2], uv[3], col_border); + draw_list->AddImage(tex_id, pos, pos + size*scale, uv[0], uv[1], col_fill); + draw_list->PopTextureID(); + } +} + +// Render an arrow. 'pos' is position of the arrow tip. half_sz.x is length from base to tip. half_sz.y is length on each side. +void ImGui::RenderArrowPointingAt(ImDrawList* draw_list, ImVec2 pos, ImVec2 half_sz, ImGuiDir direction, ImU32 col) +{ + switch (direction) + { + case ImGuiDir_Left: draw_list->AddTriangleFilled(ImVec2(pos.x + half_sz.x, pos.y - half_sz.y), ImVec2(pos.x + half_sz.x, pos.y + half_sz.y), pos, col); return; + case ImGuiDir_Right: draw_list->AddTriangleFilled(ImVec2(pos.x - half_sz.x, pos.y + half_sz.y), ImVec2(pos.x - half_sz.x, pos.y - half_sz.y), pos, col); return; + case ImGuiDir_Up: draw_list->AddTriangleFilled(ImVec2(pos.x + half_sz.x, pos.y + half_sz.y), ImVec2(pos.x - half_sz.x, pos.y + half_sz.y), pos, col); return; + case ImGuiDir_Down: draw_list->AddTriangleFilled(ImVec2(pos.x - half_sz.x, pos.y - half_sz.y), ImVec2(pos.x + half_sz.x, pos.y - half_sz.y), pos, col); return; + case ImGuiDir_None: case ImGuiDir_COUNT: break; // Fix warnings + } +} + +// This is less wide than RenderArrow() and we use in dock nodes instead of the regular RenderArrow() to denote a change of functionality, +// and because the saved space means that the left-most tab label can stay at exactly the same position as the label of a loose window. +void ImGui::RenderArrowDockMenu(ImDrawList* draw_list, ImVec2 p_min, float sz, ImU32 col) +{ + draw_list->AddRectFilled(p_min + ImVec2(sz * 0.10f, sz * 0.15f), p_min + ImVec2(sz * 0.70f, sz * 0.30f), col); + RenderArrowPointingAt(draw_list, p_min + ImVec2(sz * 0.40f, sz * 0.85f), ImVec2(sz * 0.30f, sz * 0.40f), ImGuiDir_Down, col); +} + +static inline float ImAcos01(float x) +{ + if (x <= 0.0f) return IM_PI * 0.5f; + if (x >= 1.0f) return 0.0f; + return ImAcos(x); + //return (-0.69813170079773212f * x * x - 0.87266462599716477f) * x + 1.5707963267948966f; // Cheap approximation, may be enough for what we do. +} + +// FIXME: Cleanup and move code to ImDrawList. +void ImGui::RenderRectFilledRangeH(ImDrawList* draw_list, const ImRect& rect, ImU32 col, float x_start_norm, float x_end_norm, float rounding) +{ + if (x_end_norm == x_start_norm) + return; + if (x_start_norm > x_end_norm) + ImSwap(x_start_norm, x_end_norm); + + ImVec2 p0 = ImVec2(ImLerp(rect.Min.x, rect.Max.x, x_start_norm), rect.Min.y); + ImVec2 p1 = ImVec2(ImLerp(rect.Min.x, rect.Max.x, x_end_norm), rect.Max.y); + if (rounding == 0.0f) + { + draw_list->AddRectFilled(p0, p1, col, 0.0f); + return; + } + + rounding = ImClamp(ImMin((rect.Max.x - rect.Min.x) * 0.5f, (rect.Max.y - rect.Min.y) * 0.5f) - 1.0f, 0.0f, rounding); + const float inv_rounding = 1.0f / rounding; + const float arc0_b = ImAcos01(1.0f - (p0.x - rect.Min.x) * inv_rounding); + const float arc0_e = ImAcos01(1.0f - (p1.x - rect.Min.x) * inv_rounding); + const float half_pi = IM_PI * 0.5f; // We will == compare to this because we know this is the exact value ImAcos01 can return. + const float x0 = ImMax(p0.x, rect.Min.x + rounding); + if (arc0_b == arc0_e) + { + draw_list->PathLineTo(ImVec2(x0, p1.y)); + draw_list->PathLineTo(ImVec2(x0, p0.y)); + } + else if (arc0_b == 0.0f && arc0_e == half_pi) + { + draw_list->PathArcToFast(ImVec2(x0, p1.y - rounding), rounding, 3, 6); // BL + draw_list->PathArcToFast(ImVec2(x0, p0.y + rounding), rounding, 6, 9); // TR + } + else + { + draw_list->PathArcTo(ImVec2(x0, p1.y - rounding), rounding, IM_PI - arc0_e, IM_PI - arc0_b, 3); // BL + draw_list->PathArcTo(ImVec2(x0, p0.y + rounding), rounding, IM_PI + arc0_b, IM_PI + arc0_e, 3); // TR + } + if (p1.x > rect.Min.x + rounding) + { + const float arc1_b = ImAcos01(1.0f - (rect.Max.x - p1.x) * inv_rounding); + const float arc1_e = ImAcos01(1.0f - (rect.Max.x - p0.x) * inv_rounding); + const float x1 = ImMin(p1.x, rect.Max.x - rounding); + if (arc1_b == arc1_e) + { + draw_list->PathLineTo(ImVec2(x1, p0.y)); + draw_list->PathLineTo(ImVec2(x1, p1.y)); + } + else if (arc1_b == 0.0f && arc1_e == half_pi) + { + draw_list->PathArcToFast(ImVec2(x1, p0.y + rounding), rounding, 9, 12); // TR + draw_list->PathArcToFast(ImVec2(x1, p1.y - rounding), rounding, 0, 3); // BR + } + else + { + draw_list->PathArcTo(ImVec2(x1, p0.y + rounding), rounding, -arc1_e, -arc1_b, 3); // TR + draw_list->PathArcTo(ImVec2(x1, p1.y - rounding), rounding, +arc1_b, +arc1_e, 3); // BR + } + } + draw_list->PathFillConvex(col); +} + +// For CTRL+TAB within a docking node we need to render the dimming background in 8 steps +// (Because the root node renders the background in one shot, in order to avoid flickering when a child dock node is not submitted) +void ImGui::RenderRectFilledWithHole(ImDrawList* draw_list, ImRect outer, ImRect inner, ImU32 col, float rounding) +{ + const bool fill_L = (inner.Min.x > outer.Min.x); + const bool fill_R = (inner.Max.x < outer.Max.x); + const bool fill_U = (inner.Min.y > outer.Min.y); + const bool fill_D = (inner.Max.y < outer.Max.y); + if (fill_L) draw_list->AddRectFilled(ImVec2(outer.Min.x, inner.Min.y), ImVec2(inner.Min.x, inner.Max.y), col, rounding, (fill_U ? 0 : ImDrawCornerFlags_TopLeft) | (fill_D ? 0 : ImDrawCornerFlags_BotLeft)); + if (fill_R) draw_list->AddRectFilled(ImVec2(inner.Max.x, inner.Min.y), ImVec2(outer.Max.x, inner.Max.y), col, rounding, (fill_U ? 0 : ImDrawCornerFlags_TopRight) | (fill_D ? 0 : ImDrawCornerFlags_BotRight)); + if (fill_U) draw_list->AddRectFilled(ImVec2(inner.Min.x, outer.Min.y), ImVec2(inner.Max.x, inner.Min.y), col, rounding, (fill_L ? 0 : ImDrawCornerFlags_TopLeft) | (fill_R ? 0 : ImDrawCornerFlags_TopRight)); + if (fill_D) draw_list->AddRectFilled(ImVec2(inner.Min.x, inner.Max.y), ImVec2(inner.Max.x, outer.Max.y), col, rounding, (fill_L ? 0 : ImDrawCornerFlags_BotLeft) | (fill_R ? 0 : ImDrawCornerFlags_BotRight)); + if (fill_L && fill_U) draw_list->AddRectFilled(ImVec2(outer.Min.x, outer.Min.y), ImVec2(inner.Min.x, inner.Min.y), col, rounding, ImDrawCornerFlags_TopLeft); + if (fill_R && fill_U) draw_list->AddRectFilled(ImVec2(inner.Max.x, outer.Min.y), ImVec2(outer.Max.x, inner.Min.y), col, rounding, ImDrawCornerFlags_TopRight); + if (fill_L && fill_D) draw_list->AddRectFilled(ImVec2(outer.Min.x, inner.Max.y), ImVec2(inner.Min.x, outer.Max.y), col, rounding, ImDrawCornerFlags_BotLeft); + if (fill_R && fill_D) draw_list->AddRectFilled(ImVec2(inner.Max.x, inner.Max.y), ImVec2(outer.Max.x, outer.Max.y), col, rounding, ImDrawCornerFlags_BotRight); +} + +// Helper for ColorPicker4() +// NB: This is rather brittle and will show artifact when rounding this enabled if rounded corners overlap multiple cells. Caller currently responsible for avoiding that. +// Spent a non reasonable amount of time trying to getting this right for ColorButton with rounding+anti-aliasing+ImGuiColorEditFlags_HalfAlphaPreview flag + various grid sizes and offsets, and eventually gave up... probably more reasonable to disable rounding altogether. +// FIXME: uses ImGui::GetColorU32 +void ImGui::RenderColorRectWithAlphaCheckerboard(ImDrawList* draw_list, ImVec2 p_min, ImVec2 p_max, ImU32 col, float grid_step, ImVec2 grid_off, float rounding, int rounding_corners_flags) +{ + if (((col & IM_COL32_A_MASK) >> IM_COL32_A_SHIFT) < 0xFF) + { + ImU32 col_bg1 = ImGui::GetColorU32(ImAlphaBlendColors(IM_COL32(204, 204, 204, 255), col)); + ImU32 col_bg2 = ImGui::GetColorU32(ImAlphaBlendColors(IM_COL32(128, 128, 128, 255), col)); + draw_list->AddRectFilled(p_min, p_max, col_bg1, rounding, rounding_corners_flags); + + int yi = 0; + for (float y = p_min.y + grid_off.y; y < p_max.y; y += grid_step, yi++) + { + float y1 = ImClamp(y, p_min.y, p_max.y), y2 = ImMin(y + grid_step, p_max.y); + if (y2 <= y1) + continue; + for (float x = p_min.x + grid_off.x + (yi & 1) * grid_step; x < p_max.x; x += grid_step * 2.0f) + { + float x1 = ImClamp(x, p_min.x, p_max.x), x2 = ImMin(x + grid_step, p_max.x); + if (x2 <= x1) + continue; + int rounding_corners_flags_cell = 0; + if (y1 <= p_min.y) { if (x1 <= p_min.x) rounding_corners_flags_cell |= ImDrawCornerFlags_TopLeft; if (x2 >= p_max.x) rounding_corners_flags_cell |= ImDrawCornerFlags_TopRight; } + if (y2 >= p_max.y) { if (x1 <= p_min.x) rounding_corners_flags_cell |= ImDrawCornerFlags_BotLeft; if (x2 >= p_max.x) rounding_corners_flags_cell |= ImDrawCornerFlags_BotRight; } + rounding_corners_flags_cell &= rounding_corners_flags; + draw_list->AddRectFilled(ImVec2(x1, y1), ImVec2(x2, y2), col_bg2, rounding_corners_flags_cell ? rounding : 0.0f, rounding_corners_flags_cell); + } + } + } + else + { + draw_list->AddRectFilled(p_min, p_max, col, rounding, rounding_corners_flags); + } +} + +//----------------------------------------------------------------------------- +// [SECTION] Decompression code +//----------------------------------------------------------------------------- +// Compressed with stb_compress() then converted to a C array and encoded as base85. +// Use the program in misc/fonts/binary_to_compressed_c.cpp to create the array from a TTF file. +// The purpose of encoding as base85 instead of "0x00,0x01,..." style is only save on _source code_ size. +// Decompression from stb.h (public domain) by Sean Barrett https://github.com/nothings/stb/blob/master/stb.h +//----------------------------------------------------------------------------- + +static unsigned int stb_decompress_length(const unsigned char *input) +{ + return (input[8] << 24) + (input[9] << 16) + (input[10] << 8) + input[11]; +} + +static unsigned char *stb__barrier_out_e, *stb__barrier_out_b; +static const unsigned char *stb__barrier_in_b; +static unsigned char *stb__dout; +static void stb__match(const unsigned char *data, unsigned int length) +{ + // INVERSE of memmove... write each byte before copying the next... + IM_ASSERT(stb__dout + length <= stb__barrier_out_e); + if (stb__dout + length > stb__barrier_out_e) { stb__dout += length; return; } + if (data < stb__barrier_out_b) { stb__dout = stb__barrier_out_e+1; return; } + while (length--) *stb__dout++ = *data++; +} + +static void stb__lit(const unsigned char *data, unsigned int length) +{ + IM_ASSERT(stb__dout + length <= stb__barrier_out_e); + if (stb__dout + length > stb__barrier_out_e) { stb__dout += length; return; } + if (data < stb__barrier_in_b) { stb__dout = stb__barrier_out_e+1; return; } + memcpy(stb__dout, data, length); + stb__dout += length; +} + +#define stb__in2(x) ((i[x] << 8) + i[(x)+1]) +#define stb__in3(x) ((i[x] << 16) + stb__in2((x)+1)) +#define stb__in4(x) ((i[x] << 24) + stb__in3((x)+1)) + +static const unsigned char *stb_decompress_token(const unsigned char *i) +{ + if (*i >= 0x20) { // use fewer if's for cases that expand small + if (*i >= 0x80) stb__match(stb__dout-i[1]-1, i[0] - 0x80 + 1), i += 2; + else if (*i >= 0x40) stb__match(stb__dout-(stb__in2(0) - 0x4000 + 1), i[2]+1), i += 3; + else /* *i >= 0x20 */ stb__lit(i+1, i[0] - 0x20 + 1), i += 1 + (i[0] - 0x20 + 1); + } else { // more ifs for cases that expand large, since overhead is amortized + if (*i >= 0x18) stb__match(stb__dout-(stb__in3(0) - 0x180000 + 1), i[3]+1), i += 4; + else if (*i >= 0x10) stb__match(stb__dout-(stb__in3(0) - 0x100000 + 1), stb__in2(3)+1), i += 5; + else if (*i >= 0x08) stb__lit(i+2, stb__in2(0) - 0x0800 + 1), i += 2 + (stb__in2(0) - 0x0800 + 1); + else if (*i == 0x07) stb__lit(i+3, stb__in2(1) + 1), i += 3 + (stb__in2(1) + 1); + else if (*i == 0x06) stb__match(stb__dout-(stb__in3(1)+1), i[4]+1), i += 5; + else if (*i == 0x04) stb__match(stb__dout-(stb__in3(1)+1), stb__in2(4)+1), i += 6; + } + return i; +} + +static unsigned int stb_adler32(unsigned int adler32, unsigned char *buffer, unsigned int buflen) +{ + const unsigned long ADLER_MOD = 65521; + unsigned long s1 = adler32 & 0xffff, s2 = adler32 >> 16; + unsigned long blocklen = buflen % 5552; + + unsigned long i; + while (buflen) { + for (i=0; i + 7 < blocklen; i += 8) { + s1 += buffer[0], s2 += s1; + s1 += buffer[1], s2 += s1; + s1 += buffer[2], s2 += s1; + s1 += buffer[3], s2 += s1; + s1 += buffer[4], s2 += s1; + s1 += buffer[5], s2 += s1; + s1 += buffer[6], s2 += s1; + s1 += buffer[7], s2 += s1; + + buffer += 8; + } + + for (; i < blocklen; ++i) + s1 += *buffer++, s2 += s1; + + s1 %= ADLER_MOD, s2 %= ADLER_MOD; + buflen -= blocklen; + blocklen = 5552; + } + return (unsigned int)(s2 << 16) + (unsigned int)s1; +} + +static unsigned int stb_decompress(unsigned char *output, const unsigned char *i, unsigned int /*length*/) +{ + if (stb__in4(0) != 0x57bC0000) return 0; + if (stb__in4(4) != 0) return 0; // error! stream is > 4GB + const unsigned int olen = stb_decompress_length(i); + stb__barrier_in_b = i; + stb__barrier_out_e = output + olen; + stb__barrier_out_b = output; + i += 16; + + stb__dout = output; + for (;;) { + const unsigned char *old_i = i; + i = stb_decompress_token(i); + if (i == old_i) { + if (*i == 0x05 && i[1] == 0xfa) { + IM_ASSERT(stb__dout == output + olen); + if (stb__dout != output + olen) return 0; + if (stb_adler32(1, output, olen) != (unsigned int) stb__in4(2)) + return 0; + return olen; + } else { + IM_ASSERT(0); /* NOTREACHED */ + return 0; + } + } + IM_ASSERT(stb__dout <= output + olen); + if (stb__dout > output + olen) + return 0; + } +} + +//----------------------------------------------------------------------------- +// [SECTION] Default font data (ProggyClean.ttf) +//----------------------------------------------------------------------------- +// ProggyClean.ttf +// Copyright (c) 2004, 2005 Tristan Grimmer +// MIT license (see License.txt in http://www.upperbounds.net/download/ProggyClean.ttf.zip) +// Download and more information at http://upperbounds.net +//----------------------------------------------------------------------------- +// File: 'ProggyClean.ttf' (41208 bytes) +// Exported using misc/fonts/binary_to_compressed_c.cpp (with compression + base85 string encoding). +// The purpose of encoding as base85 instead of "0x00,0x01,..." style is only save on _source code_ size. +//----------------------------------------------------------------------------- +static const char proggy_clean_ttf_compressed_data_base85[11980+1] = + "7])#######hV0qs'/###[),##/l:$#Q6>##5[n42>c-TH`->>#/e>11NNV=Bv(*:.F?uu#(gRU.o0XGH`$vhLG1hxt9?W`#,5LsCp#-i>.r$<$6pD>Lb';9Crc6tgXmKVeU2cD4Eo3R/" + "2*>]b(MC;$jPfY.;h^`IWM9Qo#t'X#(v#Y9w0#1D$CIf;W'#pWUPXOuxXuU(H9M(1=Ke$$'5F%)]0^#0X@U.a$FBjVQTSDgEKnIS7EM9>ZY9w0#L;>>#Mx&4Mvt//L[MkA#W@lK.N'[0#7RL_&#w+F%HtG9M#XL`N&.,GM4Pg;--VsM.M0rJfLH2eTM`*oJMHRC`N" + "kfimM2J,W-jXS:)r0wK#@Fge$U>`w'N7G#$#fB#$E^$#:9:hk+eOe--6x)F7*E%?76%^GMHePW-Z5l'&GiF#$956:rS?dA#fiK:)Yr+`�j@'DbG&#^$PG.Ll+DNa&VZ>1i%h1S9u5o@YaaW$e+bROPOpxTO7Stwi1::iB1q)C_=dV26J;2,]7op$]uQr@_V7$q^%lQwtuHY]=DX,n3L#0PHDO4f9>dC@O>HBuKPpP*E,N+b3L#lpR/MrTEH.IAQk.a>D[.e;mc." + "x]Ip.PH^'/aqUO/$1WxLoW0[iLAw=4h(9.`G" + "CRUxHPeR`5Mjol(dUWxZa(>STrPkrJiWx`5U7F#.g*jrohGg`cg:lSTvEY/EV_7H4Q9[Z%cnv;JQYZ5q.l7Zeas:HOIZOB?Ggv:[7MI2k).'2($5FNP&EQ(,)" + "U]W]+fh18.vsai00);D3@4ku5P?DP8aJt+;qUM]=+b'8@;mViBKx0DE[-auGl8:PJ&Dj+M6OC]O^((##]`0i)drT;-7X`=-H3[igUnPG-NZlo.#k@h#=Ork$m>a>$-?Tm$UV(?#P6YY#" + "'/###xe7q.73rI3*pP/$1>s9)W,JrM7SN]'/4C#v$U`0#V.[0>xQsH$fEmPMgY2u7Kh(G%siIfLSoS+MK2eTM$=5,M8p`A.;_R%#u[K#$x4AG8.kK/HSB==-'Ie/QTtG?-.*^N-4B/ZM" + "_3YlQC7(p7q)&](`6_c)$/*JL(L-^(]$wIM`dPtOdGA,U3:w2M-0+WomX2u7lqM2iEumMTcsF?-aT=Z-97UEnXglEn1K-bnEO`gu" + "Ft(c%=;Am_Qs@jLooI&NX;]0#j4#F14;gl8-GQpgwhrq8'=l_f-b49'UOqkLu7-##oDY2L(te+Mch&gLYtJ,MEtJfLh'x'M=$CS-ZZ%P]8bZ>#S?YY#%Q&q'3^Fw&?D)UDNrocM3A76/" + "/oL?#h7gl85[qW/NDOk%16ij;+:1a'iNIdb-ou8.P*w,v5#EI$TWS>Pot-R*H'-SEpA:g)f+O$%%`kA#G=8RMmG1&O`>to8bC]T&$,n.LoO>29sp3dt-52U%VM#q7'DHpg+#Z9%H[Ket`e;)f#Km8&+DC$I46>#Kr]]u-[=99tts1.qb#q72g1WJO81q+eN'03'eM>&1XxY-caEnO" + "j%2n8)),?ILR5^.Ibn<-X-Mq7[a82Lq:F&#ce+S9wsCK*x`569E8ew'He]h:sI[2LM$[guka3ZRd6:t%IG:;$%YiJ:Nq=?eAw;/:nnDq0(CYcMpG)qLN4$##&J-XTt,%OVU4)S1+R-#dg0/Nn?Ku1^0f$B*P:Rowwm-`0PKjYDDM'3]d39VZHEl4,.j']Pk-M.h^&:0FACm$maq-&sgw0t7/6(^xtk%" + "LuH88Fj-ekm>GA#_>568x6(OFRl-IZp`&b,_P'$MhLbxfc$mj`,O;&%W2m`Zh:/)Uetw:aJ%]K9h:TcF]u_-Sj9,VK3M.*'&0D[Ca]J9gp8,kAW]" + "%(?A%R$f<->Zts'^kn=-^@c4%-pY6qI%J%1IGxfLU9CP8cbPlXv);C=b),<2mOvP8up,UVf3839acAWAW-W?#ao/^#%KYo8fRULNd2.>%m]UK:n%r$'sw]J;5pAoO_#2mO3n,'=H5(et" + "Hg*`+RLgv>=4U8guD$I%D:W>-r5V*%j*W:Kvej.Lp$'?;++O'>()jLR-^u68PHm8ZFWe+ej8h:9r6L*0//c&iH&R8pRbA#Kjm%upV1g:" + "a_#Ur7FuA#(tRh#.Y5K+@?3<-8m0$PEn;J:rh6?I6uG<-`wMU'ircp0LaE_OtlMb&1#6T.#FDKu#1Lw%u%+GM+X'e?YLfjM[VO0MbuFp7;>Q&#WIo)0@F%q7c#4XAXN-U&VBpqB>0ie&jhZ[?iLR@@_AvA-iQC(=ksRZRVp7`.=+NpBC%rh&3]R:8XDmE5^V8O(x<-+k?'(^](H.aREZSi,#1:[IXaZFOm<-ui#qUq2$##Ri;u75OK#(RtaW-K-F`S+cF]uN`-KMQ%rP/Xri.LRcB##=YL3BgM/3M" + "D?@f&1'BW-)Ju#bmmWCMkk&#TR`C,5d>g)F;t,4:@_l8G/5h4vUd%&%950:VXD'QdWoY-F$BtUwmfe$YqL'8(PWX(" + "P?^@Po3$##`MSs?DWBZ/S>+4%>fX,VWv/w'KD`LP5IbH;rTV>n3cEK8U#bX]l-/V+^lj3;vlMb&[5YQ8#pekX9JP3XUC72L,,?+Ni&co7ApnO*5NK,((W-i:$,kp'UDAO(G0Sq7MVjJs" + "bIu)'Z,*[>br5fX^:FPAWr-m2KgLQ_nN6'8uTGT5g)uLv:873UpTLgH+#FgpH'_o1780Ph8KmxQJ8#H72L4@768@Tm&Q" + "h4CB/5OvmA&,Q&QbUoi$a_%3M01H)4x7I^&KQVgtFnV+;[Pc>[m4k//,]1?#`VY[Jr*3&&slRfLiVZJ:]?=K3Sw=[$=uRB?3xk48@aege0jT6'N#(q%.O=?2S]u*(m<-" + "V8J'(1)G][68hW$5'q[GC&5j`TE?m'esFGNRM)j,ffZ?-qx8;->g4t*:CIP/[Qap7/9'#(1sao7w-.qNUdkJ)tCF&#B^;xGvn2r9FEPFFFcL@.iFNkTve$m%#QvQS8U@)2Z+3K:AKM5i" + "sZ88+dKQ)W6>J%CL`.d*(B`-n8D9oK-XV1q['-5k'cAZ69e;D_?$ZPP&s^+7])$*$#@QYi9,5P r+$%CE=68>K8r0=dSC%%(@p7" + ".m7jilQ02'0-VWAgTlGW'b)Tq7VT9q^*^$$.:&N@@" + "$&)WHtPm*5_rO0&e%K&#-30j(E4#'Zb.o/(Tpm$>K'f@[PvFl,hfINTNU6u'0pao7%XUp9]5.>%h`8_=VYbxuel.NTSsJfLacFu3B'lQSu/m6-Oqem8T+oE--$0a/k]uj9EwsG>%veR*" + "hv^BFpQj:K'#SJ,sB-'#](j.Lg92rTw-*n%@/;39rrJF,l#qV%OrtBeC6/,;qB3ebNW[?,Hqj2L.1NP&GjUR=1D8QaS3Up&@*9wP?+lo7b?@%'k4`p0Z$22%K3+iCZj?XJN4Nm&+YF]u" + "@-W$U%VEQ/,,>>#)D#%8cY#YZ?=,`Wdxu/ae&#" + "w6)R89tI#6@s'(6Bf7a&?S=^ZI_kS&ai`&=tE72L_D,;^R)7[$so8lKN%5/$(vdfq7+ebA#" + "u1p]ovUKW&Y%q]'>$1@-[xfn$7ZTp7mM,G,Ko7a&Gu%G[RMxJs[0MM%wci.LFDK)(%:_i2B5CsR8&9Z&#=mPEnm0f`<&c)QL5uJ#%u%lJj+D-r;BoFDoS97h5g)E#o:&S4weDF,9^Hoe`h*L+_a*NrLW-1pG_&2UdB8" + "6e%B/:=>)N4xeW.*wft-;$'58-ESqr#U`'6AQ]m&6/`Z>#S?YY#Vc;r7U2&326d=w&H####?TZ`*4?&.MK?LP8Vxg>$[QXc%QJv92.(Db*B)gb*BM9dM*hJMAo*c&#" + "b0v=Pjer]$gG&JXDf->'StvU7505l9$AFvgYRI^&<^b68?j#q9QX4SM'RO#&sL1IM.rJfLUAj221]d##DW=m83u5;'bYx,*Sl0hL(W;;$doB&O/TQ:(Z^xBdLjLV#*8U_72Lh+2Q8Cj0i:6hp&$C/:p(HK>T8Y[gHQ4`4)'$Ab(Nof%V'8hL&#SfD07&6D@M.*J:;$-rv29'M]8qMv-tLp,'886iaC=Hb*YJoKJ,(j%K=H`K.v9HggqBIiZu'QvBT.#=)0ukruV&.)3=(^1`o*Pj4<-#MJ+gLq9-##@HuZPN0]u:h7.T..G:;$/Usj(T7`Q8tT72LnYl<-qx8;-HV7Q-&Xdx%1a,hC=0u+HlsV>nuIQL-5" + "_>@kXQtMacfD.m-VAb8;IReM3$wf0''hra*so568'Ip&vRs849'MRYSp%:t:h5qSgwpEr$B>Q,;s(C#$)`svQuF$##-D,##,g68@2[T;.XSdN9Qe)rpt._K-#5wF)sP'##p#C0c%-Gb%" + "hd+<-j'Ai*x&&HMkT]C'OSl##5RG[JXaHN;d'uA#x._U;.`PU@(Z3dt4r152@:v,'R.Sj'w#0<-;kPI)FfJ&#AYJ&#//)>-k=m=*XnK$>=)72L]0I%>.G690a:$##<,);?;72#?x9+d;" + "^V'9;jY@;)br#q^YQpx:X#Te$Z^'=-=bGhLf:D6&bNwZ9-ZD#n^9HhLMr5G;']d&6'wYmTFmLq9wI>P(9mI[>kC-ekLC/R&CH+s'B;K-M6$EB%is00:" + "+A4[7xks.LrNk0&E)wILYF@2L'0Nb$+pv<(2.768/FrY&h$^3i&@+G%JT'<-,v`3;_)I9M^AE]CN?Cl2AZg+%4iTpT3$U4O]GKx'm9)b@p7YsvK3w^YR-" + "CdQ*:Ir<($u&)#(&?L9Rg3H)4fiEp^iI9O8KnTj,]H?D*r7'M;PwZ9K0E^k&-cpI;.p/6_vwoFMV<->#%Xi.LxVnrU(4&8/P+:hLSKj$#U%]49t'I:rgMi'FL@a:0Y-uA[39',(vbma*" + "hU%<-SRF`Tt:542R_VV$p@[p8DV[A,?1839FWdFTi1O*H&#(AL8[_P%.M>v^-))qOT*F5Cq0`Ye%+$B6i:7@0IXSsDiWP,##P`%/L-" + "S(qw%sf/@%#B6;/U7K]uZbi^Oc^2n%t<)'mEVE''n`WnJra$^TKvX5B>;_aSEK',(hwa0:i4G?.Bci.(X[?b*($,=-n<.Q%`(X=?+@Am*Js0&=3bh8K]mL69=Lb,OcZV/);TTm8VI;?%OtJ<(b4mq7M6:u?KRdFl*:xP?Yb.5)%w_I?7uk5JC+FS(m#i'k.'a0i)9<7b'fs'59hq$*5Uhv##pi^8+hIEBF`nvo`;'l0.^S1<-wUK2/Coh58KKhLj" + "M=SO*rfO`+qC`W-On.=AJ56>>i2@2LH6A:&5q`?9I3@@'04&p2/LVa*T-4<-i3;M9UvZd+N7>b*eIwg:CC)c<>nO&#$(>.Z-I&J(Q0Hd5Q%7Co-b`-cP)hI;*_F]u`Rb[.j8_Q/<&>uu+VsH$sM9TA%?)(vmJ80),P7E>)tjD%2L=-t#fK[%`v=Q8WlA2);Sa" + ">gXm8YB`1d@K#n]76-a$U,mF%Ul:#/'xoFM9QX-$.QN'>" + "[%$Z$uF6pA6Ki2O5:8w*vP1<-1`[G,)-m#>0`P&#eb#.3i)rtB61(o'$?X3B2Qft^ae_5tKL9MUe9b*sLEQ95C&`=G?@Mj=wh*'3E>=-<)Gt*Iw)'QG:`@I" + "wOf7&]1i'S01B+Ev/Nac#9S;=;YQpg_6U`*kVY39xK,[/6Aj7:'1Bm-_1EYfa1+o&o4hp7KN_Q(OlIo@S%;jVdn0'1h19w,WQhLI)3S#f$2(eb,jr*b;3Vw]*7NH%$c4Vs,eD9>XW8?N]o+(*pgC%/72LV-uW%iewS8W6m2rtCpo'RS1R84=@paTKt)>=%&1[)*vp'u+x,VrwN;&]kuO9JDbg=pO$J*.jVe;u'm0dr9l,<*wMK*Oe=g8lV_KEBFkO'oU]^=[-792#ok,)" + "i]lR8qQ2oA8wcRCZ^7w/Njh;?.stX?Q1>S1q4Bn$)K1<-rGdO'$Wr.Lc.CG)$/*JL4tNR/,SVO3,aUw'DJN:)Ss;wGn9A32ijw%FL+Z0Fn.U9;reSq)bmI32U==5ALuG&#Vf1398/pVo" + "1*c-(aY168o<`JsSbk-,1N;$>0:OUas(3:8Z972LSfF8eb=c-;>SPw7.6hn3m`9^Xkn(r.qS[0;T%&Qc=+STRxX'q1BNk3&*eu2;&8q$&x>Q#Q7^Tf+6<(d%ZVmj2bDi%.3L2n+4W'$P" + "iDDG)g,r%+?,$@?uou5tSe2aN_AQU*'IAO" + "URQ##V^Fv-XFbGM7Fl(N<3DhLGF%q.1rC$#:T__&Pi68%0xi_&[qFJ(77j_&JWoF.V735&T,[R*:xFR*K5>>#`bW-?4Ne_&6Ne_&6Ne_&n`kr-#GJcM6X;uM6X;uM(.a..^2TkL%oR(#" + ";u.T%fAr%4tJ8&><1=GHZ_+m9/#H1F^R#SC#*N=BA9(D?v[UiFY>>^8p,KKF.W]L29uLkLlu/+4T" + "w$)F./^n3+rlo+DB;5sIYGNk+i1t-69Jg--0pao7Sm#K)pdHW&;LuDNH@H>#/X-TI(;P>#,Gc>#0Su>#4`1?#8lC?#xL$#B.`$#F:r$#JF.%#NR@%#R_R%#Vke%#Zww%#_-4^Rh%Sflr-k'MS.o?.5/sWel/wpEM0%3'/1)K^f1-d>G21&v(35>V`39V7A4=onx4" + "A1OY5EI0;6Ibgr6M$HS7Q<)58C5w,;WoA*#[%T*#`1g*#d=#+#hI5+#lUG+#pbY+#tnl+#x$),#&1;,#*=M,#.I`,#2Ur,#6b.-#;w[H#iQtA#m^0B#qjBB#uvTB##-hB#'9$C#+E6C#" + "/QHC#3^ZC#7jmC#;v)D#?,)4kMYD4lVu`4m`:&5niUA5@(A5BA1]PBB:xlBCC=2CDLXMCEUtiCf&0g2'tN?PGT4CPGT4CPGT4CPGT4CPGT4CPGT4CPGT4CP" + "GT4CPGT4CPGT4CPGT4CPGT4CPGT4CP-qekC`.9kEg^+F$kwViFJTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5o,^<-28ZI'O?;xp" + "O?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xp;7q-#lLYI:xvD=#"; + +static const char* GetDefaultCompressedFontDataTTFBase85() +{ + return proggy_clean_ttf_compressed_data_base85; +} + +#endif // #ifndef IMGUI_DISABLE diff --git a/extern/imgui/src/imgui_internal.h b/extern/imgui/src/imgui_internal.h new file mode 100644 index 0000000..dfa1fbf --- /dev/null +++ b/extern/imgui/src/imgui_internal.h @@ -0,0 +1,2324 @@ +// dear imgui, v1.77 WIP +// (internal structures/api) + +// You may use this file to debug, understand or extend ImGui features but we don't provide any guarantee of forward compatibility! +// Set: +// #define IMGUI_DEFINE_MATH_OPERATORS +// To implement maths operators for ImVec2 (disabled by default to not collide with using IM_VEC2_CLASS_EXTRA along with your own math types+operators) + +/* + +Index of this file: + +// [SECTION] Header mess +// [SECTION] Forward declarations +// [SECTION] Context pointer +// [SECTION] STB libraries includes +// [SECTION] Macros +// [SECTION] Generic helpers +// [SECTION] ImDrawList support +// [SECTION] Widgets support: flags, enums, data structures +// [SECTION] Columns support +// [SECTION] Settings support +// [SECTION] Multi-select support +// [SECTION] Docking support +// [SECTION] Viewport support +// [SECTION] ImGuiContext (main imgui context) +// [SECTION] ImGuiWindowTempData, ImGuiWindow +// [SECTION] Tab bar, Tab item support +// [SECTION] Table support +// [SECTION] Internal API +// [SECTION] Test Engine Hooks (imgui_test_engine) + +*/ + +#pragma once +#ifndef IMGUI_DISABLE + +//----------------------------------------------------------------------------- +// [SECTION] Header mess +//----------------------------------------------------------------------------- + +#ifndef IMGUI_VERSION +#error Must include imgui.h before imgui_internal.h +#endif + +#include // FILE*, sscanf +#include // NULL, malloc, free, qsort, atoi, atof +#include // sqrtf, fabsf, fmodf, powf, floorf, ceilf, cosf, sinf +#include // INT_MIN, INT_MAX + +// Visual Studio warnings +#ifdef _MSC_VER +#pragma warning (push) +#pragma warning (disable: 4251) // class 'xxx' needs to have dll-interface to be used by clients of struct 'xxx' // when IMGUI_API is set to__declspec(dllexport) +#endif + +// Clang/GCC warnings with -Weverything +#if defined(__clang__) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-function" // for stb_textedit.h +#pragma clang diagnostic ignored "-Wmissing-prototypes" // for stb_textedit.h +#pragma clang diagnostic ignored "-Wold-style-cast" +#if __has_warning("-Wzero-as-null-pointer-constant") +#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" +#endif +#if __has_warning("-Wdouble-promotion") +#pragma clang diagnostic ignored "-Wdouble-promotion" +#endif +#elif defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind +#pragma GCC diagnostic ignored "-Wclass-memaccess" // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead +#endif + +// Legacy defines +#ifdef IMGUI_DISABLE_FORMAT_STRING_FUNCTIONS // Renamed in 1.74 +#error Use IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS +#endif +#ifdef IMGUI_DISABLE_MATH_FUNCTIONS // Renamed in 1.74 +#error Use IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS +#endif + +//----------------------------------------------------------------------------- +// [SECTION] Forward declarations +//----------------------------------------------------------------------------- + +struct ImBitVector; // Store 1-bit per value +struct ImRect; // An axis-aligned rectangle (2 points) +struct ImDrawDataBuilder; // Helper to build a ImDrawData instance +struct ImDrawListSharedData; // Data shared between all ImDrawList instances +struct ImGuiColorMod; // Stacked color modifier, backup of modified data so we can restore it +struct ImGuiColumnData; // Storage data for a single column +struct ImGuiColumns; // Storage data for a columns set +struct ImGuiContext; // Main Dear ImGui context +struct ImGuiDataTypeInfo; // Type information associated to a ImGuiDataType enum +struct ImGuiDockContext; // Docking system context +struct ImGuiDockRequest; // Docking system dock/undock queued request +struct ImGuiDockNode; // Docking system node (hold a list of Windows OR two child dock nodes) +struct ImGuiDockNodeSettings; // Storage for a dock node in .ini file (we preserve those even if the associated dock node isn't active during the session) +struct ImGuiGroupData; // Stacked storage data for BeginGroup()/EndGroup() +struct ImGuiInputTextState; // Internal state of the currently focused/edited text input box +struct ImGuiItemHoveredDataBackup; // Backup and restore IsItemHovered() internal data +struct ImGuiMenuColumns; // Simple column measurement, currently used for MenuItem() only +struct ImGuiNavMoveResult; // Result of a gamepad/keyboard directional navigation move query result +struct ImGuiNextWindowData; // Storage for SetNextWindow** functions +struct ImGuiNextItemData; // Storage for SetNextItem** functions +struct ImGuiPopupData; // Storage for current popup stack +struct ImGuiSettingsHandler; // Storage for one type registered in the .ini file +struct ImGuiStyleMod; // Stacked style modifier, backup of modified data so we can restore it +struct ImGuiTabBar; // Storage for a tab bar +struct ImGuiTabItem; // Storage for a tab item (within a tab bar) +struct ImGuiWindow; // Storage for one window +struct ImGuiWindowTempData; // Temporary storage for one window (that's the data which in theory we could ditch at the end of the frame) +struct ImGuiWindowSettings; // Storage for a window .ini settings (we keep one of those even if the actual window wasn't instanced during this session) + +// Use your programming IDE "Go to definition" facility on the names of the center columns to find the actual flags/enum lists. +typedef int ImGuiDataAuthority; // -> enum ImGuiDataAuthority_ // Enum: for storing the source authority (dock node vs window) of a field +typedef int ImGuiLayoutType; // -> enum ImGuiLayoutType_ // Enum: Horizontal or vertical +typedef int ImGuiButtonFlags; // -> enum ImGuiButtonFlags_ // Flags: for ButtonEx(), ButtonBehavior() +typedef int ImGuiColumnsFlags; // -> enum ImGuiColumnsFlags_ // Flags: BeginColumns() +typedef int ImGuiDragFlags; // -> enum ImGuiDragFlags_ // Flags: for DragBehavior() +typedef int ImGuiItemFlags; // -> enum ImGuiItemFlags_ // Flags: for PushItemFlag() +typedef int ImGuiItemStatusFlags; // -> enum ImGuiItemStatusFlags_ // Flags: for DC.LastItemStatusFlags +typedef int ImGuiNavHighlightFlags; // -> enum ImGuiNavHighlightFlags_ // Flags: for RenderNavHighlight() +typedef int ImGuiNavDirSourceFlags; // -> enum ImGuiNavDirSourceFlags_ // Flags: for GetNavInputAmount2d() +typedef int ImGuiNavMoveFlags; // -> enum ImGuiNavMoveFlags_ // Flags: for navigation requests +typedef int ImGuiNextItemDataFlags; // -> enum ImGuiNextItemDataFlags_ // Flags: for SetNextItemXXX() functions +typedef int ImGuiNextWindowDataFlags; // -> enum ImGuiNextWindowDataFlags_// Flags: for SetNextWindowXXX() functions +typedef int ImGuiSeparatorFlags; // -> enum ImGuiSeparatorFlags_ // Flags: for SeparatorEx() +typedef int ImGuiSliderFlags; // -> enum ImGuiSliderFlags_ // Flags: for SliderBehavior() +typedef int ImGuiTextFlags; // -> enum ImGuiTextFlags_ // Flags: for TextEx() +typedef int ImGuiTooltipFlags; // -> enum ImGuiTooltipFlags_ // Flags: for BeginTooltipEx() + +//----------------------------------------------------------------------------- +// [SECTION] Context pointer +// See implementation of this variable in imgui.cpp for comments and details. +//----------------------------------------------------------------------------- + +#ifndef GImGui +extern IMGUI_API ImGuiContext* GImGui; // Current implicit context pointer +#endif + +//------------------------------------------------------------------------- +// [SECTION] STB libraries includes +//------------------------------------------------------------------------- + +namespace ImStb +{ + +#undef STB_TEXTEDIT_STRING +#undef STB_TEXTEDIT_CHARTYPE +#define STB_TEXTEDIT_STRING ImGuiInputTextState +#define STB_TEXTEDIT_CHARTYPE ImWchar +#define STB_TEXTEDIT_GETWIDTH_NEWLINE -1.0f +#define STB_TEXTEDIT_UNDOSTATECOUNT 99 +#define STB_TEXTEDIT_UNDOCHARCOUNT 999 +#include "stb_textedit.h" + +} // namespace ImStb + +//----------------------------------------------------------------------------- +// [SECTION] Macros +//----------------------------------------------------------------------------- + +// Internal Drag and Drop payload types. String starting with '_' are reserved for Dear ImGui. +#define IMGUI_PAYLOAD_TYPE_WINDOW "_IMWINDOW" // Payload == ImGuiWindow* + +// Debug Logging +#ifndef IMGUI_DEBUG_LOG +#define IMGUI_DEBUG_LOG(_FMT,...) printf("[%05d] " _FMT, GImGui->FrameCount, __VA_ARGS__) +#endif + +// Debug Logging for selected systems. Remove the '((void)0) //' to enable. +//#define IMGUI_DEBUG_LOG_POPUP IMGUI_DEBUG_LOG // Enable log +//#define IMGUI_DEBUG_LOG_VIEWPORT IMGUI_DEBUG_LOG // Enable log +//#define IMGUI_DEBUG_LOG_DOCKING IMGUI_DEBUG_LOG // Enable log +#define IMGUI_DEBUG_LOG_POPUP(...) ((void)0) // Disable log +#define IMGUI_DEBUG_LOG_VIEWPORT(...) ((void)0) // Disable log +#define IMGUI_DEBUG_LOG_DOCKING(...) ((void)0) // Disable log + +// Static Asserts +#if (__cplusplus >= 201100) +#define IM_STATIC_ASSERT(_COND) static_assert(_COND, "") +#else +#define IM_STATIC_ASSERT(_COND) typedef char static_assertion_##__line__[(_COND)?1:-1] +#endif + +// "Paranoid" Debug Asserts are meant to only be enabled during specific debugging/work, otherwise would slow down the code too much. +// We currently don't have many of those so the effect is currently negligible, but onward intent to add more aggressive ones in the code. +//#define IMGUI_DEBUG_PARANOID +#ifdef IMGUI_DEBUG_PARANOID +#define IM_ASSERT_PARANOID(_EXPR) IM_ASSERT(_EXPR) +#else +#define IM_ASSERT_PARANOID(_EXPR) +#endif + +// Error handling +// Down the line in some frameworks/languages we would like to have a way to redirect those to the programmer and recover from more faults. +#ifndef IM_ASSERT_USER_ERROR +#define IM_ASSERT_USER_ERROR(_EXP,_MSG) IM_ASSERT((_EXP) && _MSG) // Recoverable User Error +#endif + +// Misc Macros +#define IM_PI 3.14159265358979323846f +#ifdef _WIN32 +#define IM_NEWLINE "\r\n" // Play it nice with Windows users (Update: since 2018-05, Notepad finally appears to support Unix-style carriage returns!) +#else +#define IM_NEWLINE "\n" +#endif +#define IM_TABSIZE (4) +#define IM_F32_TO_INT8_UNBOUND(_VAL) ((int)((_VAL) * 255.0f + ((_VAL)>=0 ? 0.5f : -0.5f))) // Unsaturated, for display purpose +#define IM_F32_TO_INT8_SAT(_VAL) ((int)(ImSaturate(_VAL) * 255.0f + 0.5f)) // Saturated, always output 0..255 +#define IM_FLOOR(_VAL) ((float)(int)(_VAL)) // ImFloor() is not inlined in MSVC debug builds +#define IM_ROUND(_VAL) ((float)(int)((_VAL) + 0.5f)) // + +// Enforce cdecl calling convention for functions called by the standard library, in case compilation settings changed the default to e.g. __vectorcall +#ifdef _MSC_VER +#define IMGUI_CDECL __cdecl +#else +#define IMGUI_CDECL +#endif + +// Debug Tools +// Use 'Metrics->Tools->Item Picker' to break into the call-stack of a specific item. +#ifndef IM_DEBUG_BREAK +#if defined(__clang__) +#define IM_DEBUG_BREAK() __builtin_debugtrap() +#elif defined (_MSC_VER) +#define IM_DEBUG_BREAK() __debugbreak() +#else +#define IM_DEBUG_BREAK() IM_ASSERT(0) // It is expected that you define IM_DEBUG_BREAK() into something that will break nicely in a debugger! +#endif +#endif // #ifndef IM_DEBUG_BREAK + +//----------------------------------------------------------------------------- +// [SECTION] Generic helpers +// Note that the ImXXX helpers functions are lower-level than ImGui functions. +// ImGui functions or the ImGui context are never called/used from other ImXXX functions. +//----------------------------------------------------------------------------- +// - Helpers: Hashing +// - Helpers: Sorting +// - Helpers: Bit manipulation +// - Helpers: String, Formatting +// - Helpers: UTF-8 <> wchar conversions +// - Helpers: ImVec2/ImVec4 operators +// - Helpers: Maths +// - Helpers: Geometry +// - Helper: ImVec1 +// - Helper: ImVec2ih +// - Helper: ImRect +// - Helper: ImBitArray +// - Helper: ImBitVector +// - Helper: ImPool<> +// - Helper: ImChunkStream<> +//----------------------------------------------------------------------------- + +// Helpers: Hashing +IMGUI_API ImU32 ImHashData(const void* data, size_t data_size, ImU32 seed = 0); +IMGUI_API ImU32 ImHashStr(const char* data, size_t data_size = 0, ImU32 seed = 0); +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS +static inline ImU32 ImHash(const void* data, int size, ImU32 seed = 0) { return size ? ImHashData(data, (size_t)size, seed) : ImHashStr((const char*)data, 0, seed); } // [moved to ImHashStr/ImHashData in 1.68] +#endif + +// Helpers: Sorting +#define ImQsort qsort + +// Helpers: Color Blending +IMGUI_API ImU32 ImAlphaBlendColors(ImU32 col_a, ImU32 col_b); + +// Helpers: Bit manipulation +static inline bool ImIsPowerOfTwo(int v) { return v != 0 && (v & (v - 1)) == 0; } +static inline int ImUpperPowerOfTwo(int v) { v--; v |= v >> 1; v |= v >> 2; v |= v >> 4; v |= v >> 8; v |= v >> 16; v++; return v; } + +// Helpers: String, Formatting +IMGUI_API int ImStricmp(const char* str1, const char* str2); +IMGUI_API int ImStrnicmp(const char* str1, const char* str2, size_t count); +IMGUI_API void ImStrncpy(char* dst, const char* src, size_t count); +IMGUI_API char* ImStrdup(const char* str); +IMGUI_API char* ImStrdupcpy(char* dst, size_t* p_dst_size, const char* str); +IMGUI_API const char* ImStrchrRange(const char* str_begin, const char* str_end, char c); +IMGUI_API int ImStrlenW(const ImWchar* str); +IMGUI_API const char* ImStreolRange(const char* str, const char* str_end); // End end-of-line +IMGUI_API const ImWchar*ImStrbolW(const ImWchar* buf_mid_line, const ImWchar* buf_begin); // Find beginning-of-line +IMGUI_API const char* ImStristr(const char* haystack, const char* haystack_end, const char* needle, const char* needle_end); +IMGUI_API void ImStrTrimBlanks(char* str); +IMGUI_API const char* ImStrSkipBlank(const char* str); +IMGUI_API int ImFormatString(char* buf, size_t buf_size, const char* fmt, ...) IM_FMTARGS(3); +IMGUI_API int ImFormatStringV(char* buf, size_t buf_size, const char* fmt, va_list args) IM_FMTLIST(3); +IMGUI_API const char* ImParseFormatFindStart(const char* format); +IMGUI_API const char* ImParseFormatFindEnd(const char* format); +IMGUI_API const char* ImParseFormatTrimDecorations(const char* format, char* buf, size_t buf_size); +IMGUI_API int ImParseFormatPrecision(const char* format, int default_value); +static inline bool ImCharIsBlankA(char c) { return c == ' ' || c == '\t'; } +static inline bool ImCharIsBlankW(unsigned int c) { return c == ' ' || c == '\t' || c == 0x3000; } + +// Helpers: UTF-8 <> wchar conversions +IMGUI_API int ImTextStrToUtf8(char* buf, int buf_size, const ImWchar* in_text, const ImWchar* in_text_end); // return output UTF-8 bytes count +IMGUI_API int ImTextCharFromUtf8(unsigned int* out_char, const char* in_text, const char* in_text_end); // read one character. return input UTF-8 bytes count +IMGUI_API int ImTextStrFromUtf8(ImWchar* buf, int buf_size, const char* in_text, const char* in_text_end, const char** in_remaining = NULL); // return input UTF-8 bytes count +IMGUI_API int ImTextCountCharsFromUtf8(const char* in_text, const char* in_text_end); // return number of UTF-8 code-points (NOT bytes count) +IMGUI_API int ImTextCountUtf8BytesFromChar(const char* in_text, const char* in_text_end); // return number of bytes to express one char in UTF-8 +IMGUI_API int ImTextCountUtf8BytesFromStr(const ImWchar* in_text, const ImWchar* in_text_end); // return number of bytes to express string in UTF-8 + +// Helpers: ImVec2/ImVec4 operators +// We are keeping those disabled by default so they don't leak in user space, to allow user enabling implicit cast operators between ImVec2 and their own types (using IM_VEC2_CLASS_EXTRA etc.) +// We unfortunately don't have a unary- operator for ImVec2 because this would needs to be defined inside the class itself. +#ifdef IMGUI_DEFINE_MATH_OPERATORS +static inline ImVec2 operator*(const ImVec2& lhs, const float rhs) { return ImVec2(lhs.x*rhs, lhs.y*rhs); } +static inline ImVec2 operator/(const ImVec2& lhs, const float rhs) { return ImVec2(lhs.x/rhs, lhs.y/rhs); } +static inline ImVec2 operator+(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x+rhs.x, lhs.y+rhs.y); } +static inline ImVec2 operator-(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x-rhs.x, lhs.y-rhs.y); } +static inline ImVec2 operator*(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x*rhs.x, lhs.y*rhs.y); } +static inline ImVec2 operator/(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x/rhs.x, lhs.y/rhs.y); } +static inline ImVec2& operator*=(ImVec2& lhs, const float rhs) { lhs.x *= rhs; lhs.y *= rhs; return lhs; } +static inline ImVec2& operator/=(ImVec2& lhs, const float rhs) { lhs.x /= rhs; lhs.y /= rhs; return lhs; } +static inline ImVec2& operator+=(ImVec2& lhs, const ImVec2& rhs) { lhs.x += rhs.x; lhs.y += rhs.y; return lhs; } +static inline ImVec2& operator-=(ImVec2& lhs, const ImVec2& rhs) { lhs.x -= rhs.x; lhs.y -= rhs.y; return lhs; } +static inline ImVec2& operator*=(ImVec2& lhs, const ImVec2& rhs) { lhs.x *= rhs.x; lhs.y *= rhs.y; return lhs; } +static inline ImVec2& operator/=(ImVec2& lhs, const ImVec2& rhs) { lhs.x /= rhs.x; lhs.y /= rhs.y; return lhs; } +static inline ImVec4 operator+(const ImVec4& lhs, const ImVec4& rhs) { return ImVec4(lhs.x+rhs.x, lhs.y+rhs.y, lhs.z+rhs.z, lhs.w+rhs.w); } +static inline ImVec4 operator-(const ImVec4& lhs, const ImVec4& rhs) { return ImVec4(lhs.x-rhs.x, lhs.y-rhs.y, lhs.z-rhs.z, lhs.w-rhs.w); } +static inline ImVec4 operator*(const ImVec4& lhs, const ImVec4& rhs) { return ImVec4(lhs.x*rhs.x, lhs.y*rhs.y, lhs.z*rhs.z, lhs.w*rhs.w); } +#endif + +// Helpers: File System +#ifdef IMGUI_DISABLE_FILE_FUNCTIONS +#define IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS +typedef void* ImFileHandle; +static inline ImFileHandle ImFileOpen(const char*, const char*) { return NULL; } +static inline bool ImFileClose(ImFileHandle) { return false; } +static inline ImU64 ImFileGetSize(ImFileHandle) { return (ImU64)-1; } +static inline ImU64 ImFileRead(void*, ImU64, ImU64, ImFileHandle) { return 0; } +static inline ImU64 ImFileWrite(const void*, ImU64, ImU64, ImFileHandle) { return 0; } +#endif +#ifndef IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS +typedef FILE* ImFileHandle; +IMGUI_API ImFileHandle ImFileOpen(const char* filename, const char* mode); +IMGUI_API bool ImFileClose(ImFileHandle file); +IMGUI_API ImU64 ImFileGetSize(ImFileHandle file); +IMGUI_API ImU64 ImFileRead(void* data, ImU64 size, ImU64 count, ImFileHandle file); +IMGUI_API ImU64 ImFileWrite(const void* data, ImU64 size, ImU64 count, ImFileHandle file); +#else +#define IMGUI_DISABLE_TTY_FUNCTIONS // Can't use stdout, fflush if we are not using default file functions +#endif +IMGUI_API void* ImFileLoadToMemory(const char* filename, const char* mode, size_t* out_file_size = NULL, int padding_bytes = 0); + +// Helpers: Maths +// - Wrapper for standard libs functions. (Note that imgui_demo.cpp does _not_ use them to keep the code easy to copy) +#ifndef IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS +#define ImFabs(X) fabsf(X) +#define ImSqrt(X) sqrtf(X) +#define ImFmod(X, Y) fmodf((X), (Y)) +#define ImCos(X) cosf(X) +#define ImSin(X) sinf(X) +#define ImAcos(X) acosf(X) +#define ImAtan2(Y, X) atan2f((Y), (X)) +#define ImAtof(STR) atof(STR) +#define ImFloorStd(X) floorf(X) // We already uses our own ImFloor() { return (float)(int)v } internally so the standard one wrapper is named differently (it's used by e.g. stb_truetype) +#define ImCeil(X) ceilf(X) +static inline float ImPow(float x, float y) { return powf(x, y); } // DragBehaviorT/SliderBehaviorT uses ImPow with either float/double and need the precision +static inline double ImPow(double x, double y) { return pow(x, y); } +#endif +// - ImMin/ImMax/ImClamp/ImLerp/ImSwap are used by widgets which support variety of types: signed/unsigned int/long long float/double +// (Exceptionally using templates here but we could also redefine them for those types) +template static inline T ImMin(T lhs, T rhs) { return lhs < rhs ? lhs : rhs; } +template static inline T ImMax(T lhs, T rhs) { return lhs >= rhs ? lhs : rhs; } +template static inline T ImClamp(T v, T mn, T mx) { return (v < mn) ? mn : (v > mx) ? mx : v; } +template static inline T ImLerp(T a, T b, float t) { return (T)(a + (b - a) * t); } +template static inline void ImSwap(T& a, T& b) { T tmp = a; a = b; b = tmp; } +template static inline T ImAddClampOverflow(T a, T b, T mn, T mx) { if (b < 0 && (a < mn - b)) return mn; if (b > 0 && (a > mx - b)) return mx; return a + b; } +template static inline T ImSubClampOverflow(T a, T b, T mn, T mx) { if (b > 0 && (a < mn + b)) return mn; if (b < 0 && (a > mx + b)) return mx; return a - b; } +// - Misc maths helpers +static inline ImVec2 ImMin(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x < rhs.x ? lhs.x : rhs.x, lhs.y < rhs.y ? lhs.y : rhs.y); } +static inline ImVec2 ImMax(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x >= rhs.x ? lhs.x : rhs.x, lhs.y >= rhs.y ? lhs.y : rhs.y); } +static inline ImVec2 ImClamp(const ImVec2& v, const ImVec2& mn, ImVec2 mx) { return ImVec2((v.x < mn.x) ? mn.x : (v.x > mx.x) ? mx.x : v.x, (v.y < mn.y) ? mn.y : (v.y > mx.y) ? mx.y : v.y); } +static inline ImVec2 ImLerp(const ImVec2& a, const ImVec2& b, float t) { return ImVec2(a.x + (b.x - a.x) * t, a.y + (b.y - a.y) * t); } +static inline ImVec2 ImLerp(const ImVec2& a, const ImVec2& b, const ImVec2& t) { return ImVec2(a.x + (b.x - a.x) * t.x, a.y + (b.y - a.y) * t.y); } +static inline ImVec4 ImLerp(const ImVec4& a, const ImVec4& b, float t) { return ImVec4(a.x + (b.x - a.x) * t, a.y + (b.y - a.y) * t, a.z + (b.z - a.z) * t, a.w + (b.w - a.w) * t); } +static inline float ImSaturate(float f) { return (f < 0.0f) ? 0.0f : (f > 1.0f) ? 1.0f : f; } +static inline float ImLengthSqr(const ImVec2& lhs) { return lhs.x*lhs.x + lhs.y*lhs.y; } +static inline float ImLengthSqr(const ImVec4& lhs) { return lhs.x*lhs.x + lhs.y*lhs.y + lhs.z*lhs.z + lhs.w*lhs.w; } +static inline float ImInvLength(const ImVec2& lhs, float fail_value) { float d = lhs.x*lhs.x + lhs.y*lhs.y; if (d > 0.0f) return 1.0f / ImSqrt(d); return fail_value; } +static inline float ImFloor(float f) { return (float)(int)(f); } +static inline ImVec2 ImFloor(const ImVec2& v) { return ImVec2((float)(int)(v.x), (float)(int)(v.y)); } +static inline int ImModPositive(int a, int b) { return (a + b) % b; } +static inline float ImDot(const ImVec2& a, const ImVec2& b) { return a.x * b.x + a.y * b.y; } +static inline ImVec2 ImRotate(const ImVec2& v, float cos_a, float sin_a) { return ImVec2(v.x * cos_a - v.y * sin_a, v.x * sin_a + v.y * cos_a); } +static inline float ImLinearSweep(float current, float target, float speed) { if (current < target) return ImMin(current + speed, target); if (current > target) return ImMax(current - speed, target); return current; } +static inline ImVec2 ImMul(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x * rhs.x, lhs.y * rhs.y); } + +// Helpers: Geometry +IMGUI_API ImVec2 ImBezierCalc(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, float t); // Cubic Bezier +IMGUI_API ImVec2 ImBezierClosestPoint(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, const ImVec2& p, int num_segments); // For curves with explicit number of segments +IMGUI_API ImVec2 ImBezierClosestPointCasteljau(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, const ImVec2& p, float tess_tol);// For auto-tessellated curves you can use tess_tol = style.CurveTessellationTol +IMGUI_API ImVec2 ImLineClosestPoint(const ImVec2& a, const ImVec2& b, const ImVec2& p); +IMGUI_API bool ImTriangleContainsPoint(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p); +IMGUI_API ImVec2 ImTriangleClosestPoint(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p); +IMGUI_API void ImTriangleBarycentricCoords(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p, float& out_u, float& out_v, float& out_w); +inline float ImTriangleArea(const ImVec2& a, const ImVec2& b, const ImVec2& c) { return ImFabs((a.x * (b.y - c.y)) + (b.x * (c.y - a.y)) + (c.x * (a.y - b.y))) * 0.5f; } +IMGUI_API ImGuiDir ImGetDirQuadrantFromDelta(float dx, float dy); + +// Helper: ImVec1 (1D vector) +// (this odd construct is used to facilitate the transition between 1D and 2D, and the maintenance of some branches/patches) +struct ImVec1 +{ + float x; + ImVec1() { x = 0.0f; } + ImVec1(float _x) { x = _x; } +}; + +// Helper: ImVec2ih (2D vector, half-size integer, for long-term packed storage) +struct ImVec2ih +{ + short x, y; + ImVec2ih() { x = y = 0; } + ImVec2ih(short _x, short _y) { x = _x; y = _y; } + explicit ImVec2ih(const ImVec2& rhs) { x = (short)rhs.x; y = (short)rhs.y; } +}; + +// Helper: ImRect (2D axis aligned bounding-box) +// NB: we can't rely on ImVec2 math operators being available here! +struct IMGUI_API ImRect +{ + ImVec2 Min; // Upper-left + ImVec2 Max; // Lower-right + + ImRect() : Min(0.0f, 0.0f), Max(0.0f, 0.0f) {} + ImRect(const ImVec2& min, const ImVec2& max) : Min(min), Max(max) {} + ImRect(const ImVec4& v) : Min(v.x, v.y), Max(v.z, v.w) {} + ImRect(float x1, float y1, float x2, float y2) : Min(x1, y1), Max(x2, y2) {} + + ImVec2 GetCenter() const { return ImVec2((Min.x + Max.x) * 0.5f, (Min.y + Max.y) * 0.5f); } + ImVec2 GetSize() const { return ImVec2(Max.x - Min.x, Max.y - Min.y); } + float GetWidth() const { return Max.x - Min.x; } + float GetHeight() const { return Max.y - Min.y; } + ImVec2 GetTL() const { return Min; } // Top-left + ImVec2 GetTR() const { return ImVec2(Max.x, Min.y); } // Top-right + ImVec2 GetBL() const { return ImVec2(Min.x, Max.y); } // Bottom-left + ImVec2 GetBR() const { return Max; } // Bottom-right + bool Contains(const ImVec2& p) const { return p.x >= Min.x && p.y >= Min.y && p.x < Max.x && p.y < Max.y; } + bool Contains(const ImRect& r) const { return r.Min.x >= Min.x && r.Min.y >= Min.y && r.Max.x <= Max.x && r.Max.y <= Max.y; } + bool Overlaps(const ImRect& r) const { return r.Min.y < Max.y && r.Max.y > Min.y && r.Min.x < Max.x && r.Max.x > Min.x; } + void Add(const ImVec2& p) { if (Min.x > p.x) Min.x = p.x; if (Min.y > p.y) Min.y = p.y; if (Max.x < p.x) Max.x = p.x; if (Max.y < p.y) Max.y = p.y; } + void Add(const ImRect& r) { if (Min.x > r.Min.x) Min.x = r.Min.x; if (Min.y > r.Min.y) Min.y = r.Min.y; if (Max.x < r.Max.x) Max.x = r.Max.x; if (Max.y < r.Max.y) Max.y = r.Max.y; } + void Expand(const float amount) { Min.x -= amount; Min.y -= amount; Max.x += amount; Max.y += amount; } + void Expand(const ImVec2& amount) { Min.x -= amount.x; Min.y -= amount.y; Max.x += amount.x; Max.y += amount.y; } + void Translate(const ImVec2& d) { Min.x += d.x; Min.y += d.y; Max.x += d.x; Max.y += d.y; } + void TranslateX(float dx) { Min.x += dx; Max.x += dx; } + void TranslateY(float dy) { Min.y += dy; Max.y += dy; } + void ClipWith(const ImRect& r) { Min = ImMax(Min, r.Min); Max = ImMin(Max, r.Max); } // Simple version, may lead to an inverted rectangle, which is fine for Contains/Overlaps test but not for display. + void ClipWithFull(const ImRect& r) { Min = ImClamp(Min, r.Min, r.Max); Max = ImClamp(Max, r.Min, r.Max); } // Full version, ensure both points are fully clipped. + void Floor() { Min.x = IM_FLOOR(Min.x); Min.y = IM_FLOOR(Min.y); Max.x = IM_FLOOR(Max.x); Max.y = IM_FLOOR(Max.y); } + bool IsInverted() const { return Min.x > Max.x || Min.y > Max.y; } +}; + +// Helper: ImBitArray +inline bool ImBitArrayTestBit(const ImU32* arr, int n) { ImU32 mask = (ImU32)1 << (n & 31); return (arr[n >> 5] & mask) != 0; } +inline void ImBitArrayClearBit(ImU32* arr, int n) { ImU32 mask = (ImU32)1 << (n & 31); arr[n >> 5] &= ~mask; } +inline void ImBitArraySetBit(ImU32* arr, int n) { ImU32 mask = (ImU32)1 << (n & 31); arr[n >> 5] |= mask; } +inline void ImBitArraySetBitRange(ImU32* arr, int n, int n2) +{ + while (n <= n2) + { + int a_mod = (n & 31); + int b_mod = ((n2 >= n + 31) ? 31 : (n2 & 31)) + 1; + ImU32 mask = (ImU32)(((ImU64)1 << b_mod) - 1) & ~(ImU32)(((ImU64)1 << a_mod) - 1); + arr[n >> 5] |= mask; + n = (n + 32) & ~31; + } +} + +// Helper: ImBitVector +// Store 1-bit per value. +struct IMGUI_API ImBitVector +{ + ImVector Storage; + void Create(int sz) { Storage.resize((sz + 31) >> 5); memset(Storage.Data, 0, (size_t)Storage.Size * sizeof(Storage.Data[0])); } + void Clear() { Storage.clear(); } + bool TestBit(int n) const { IM_ASSERT(n < (Storage.Size << 5)); return ImBitArrayTestBit(Storage.Data, n); } + void SetBit(int n) { IM_ASSERT(n < (Storage.Size << 5)); ImBitArraySetBit(Storage.Data, n); } + void ClearBit(int n) { IM_ASSERT(n < (Storage.Size << 5)); ImBitArrayClearBit(Storage.Data, n); } +}; + +// Helper: ImPool<> +// Basic keyed storage for contiguous instances, slow/amortized insertion, O(1) indexable, O(Log N) queries by ID over a dense/hot buffer, +// Honor constructor/destructor. Add/remove invalidate all pointers. Indexes have the same lifetime as the associated object. +typedef int ImPoolIdx; +template +struct IMGUI_API ImPool +{ + ImVector Buf; // Contiguous data + ImGuiStorage Map; // ID->Index + ImPoolIdx FreeIdx; // Next free idx to use + + ImPool() { FreeIdx = 0; } + ~ImPool() { Clear(); } + T* GetByKey(ImGuiID key) { int idx = Map.GetInt(key, -1); return (idx != -1) ? &Buf[idx] : NULL; } + T* GetByIndex(ImPoolIdx n) { return &Buf[n]; } + ImPoolIdx GetIndex(const T* p) const { IM_ASSERT(p >= Buf.Data && p < Buf.Data + Buf.Size); return (ImPoolIdx)(p - Buf.Data); } + T* GetOrAddByKey(ImGuiID key) { int* p_idx = Map.GetIntRef(key, -1); if (*p_idx != -1) return &Buf[*p_idx]; *p_idx = FreeIdx; return Add(); } + bool Contains(const T* p) const { return (p >= Buf.Data && p < Buf.Data + Buf.Size); } + void Clear() { for (int n = 0; n < Map.Data.Size; n++) { int idx = Map.Data[n].val_i; if (idx != -1) Buf[idx].~T(); } Map.Clear(); Buf.clear(); FreeIdx = 0; } + T* Add() { int idx = FreeIdx; if (idx == Buf.Size) { Buf.resize(Buf.Size + 1); FreeIdx++; } else { FreeIdx = *(int*)&Buf[idx]; } IM_PLACEMENT_NEW(&Buf[idx]) T(); return &Buf[idx]; } + void Remove(ImGuiID key, const T* p) { Remove(key, GetIndex(p)); } + void Remove(ImGuiID key, ImPoolIdx idx) { Buf[idx].~T(); *(int*)&Buf[idx] = FreeIdx; FreeIdx = idx; Map.SetInt(key, -1); } + void Reserve(int capacity) { Buf.reserve(capacity); Map.Data.reserve(capacity); } + int GetSize() const { return Buf.Size; } +}; + +// Helper: ImChunkStream<> +// Build and iterate a contiguous stream of variable-sized structures. +// This is used by Settings to store persistent data while reducing allocation count. +// We store the chunk size first, and align the final size on 4 bytes boundaries (this what the '(X + 3) & ~3' statement is for) +// The tedious/zealous amount of casting is to avoid -Wcast-align warnings. +template +struct IMGUI_API ImChunkStream +{ + ImVector Buf; + + void clear() { Buf.clear(); } + bool empty() const { return Buf.Size == 0; } + int size() const { return Buf.Size; } + T* alloc_chunk(size_t sz) { size_t HDR_SZ = 4; sz = ((HDR_SZ + sz) + 3u) & ~3u; int off = Buf.Size; Buf.resize(off + (int)sz); ((int*)(void*)(Buf.Data + off))[0] = (int)sz; return (T*)(void*)(Buf.Data + off + (int)HDR_SZ); } + T* begin() { size_t HDR_SZ = 4; if (!Buf.Data) return NULL; return (T*)(void*)(Buf.Data + HDR_SZ); } + T* next_chunk(T* p) { size_t HDR_SZ = 4; IM_ASSERT(p >= begin() && p < end()); p = (T*)(void*)((char*)(void*)p + chunk_size(p)); if (p == (T*)(void*)((char*)end() + HDR_SZ)) return (T*)0; IM_ASSERT(p < end()); return p; } + int chunk_size(const T* p) { return ((const int*)p)[-1]; } + T* end() { return (T*)(void*)(Buf.Data + Buf.Size); } + int offset_from_ptr(const T* p) { IM_ASSERT(p >= begin() && p < end()); const ptrdiff_t off = (const char*)p - Buf.Data; return (int)off; } + T* ptr_from_offset(int off) { IM_ASSERT(off >= 4 && off < Buf.Size); return (T*)(void*)(Buf.Data + off); } +}; + +//----------------------------------------------------------------------------- +// [SECTION] ImDrawList support +//----------------------------------------------------------------------------- + +// ImDrawList: Helper function to calculate a circle's segment count given its radius and a "maximum error" value. +#define IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_MIN 12 +#define IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_MAX 512 +#define IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC(_RAD,_MAXERROR) ImClamp((int)((IM_PI * 2.0f) / ImAcos(((_RAD) - (_MAXERROR)) / (_RAD))), IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_MIN, IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_MAX) + +// ImDrawList: You may set this to higher values (e.g. 2 or 3) to increase tessellation of fast rounded corners path. +#ifndef IM_DRAWLIST_ARCFAST_TESSELLATION_MULTIPLIER +#define IM_DRAWLIST_ARCFAST_TESSELLATION_MULTIPLIER 1 +#endif + +// Data shared between all ImDrawList instances +// You may want to create your own instance of this if you want to use ImDrawList completely without ImGui. In that case, watch out for future changes to this structure. +struct IMGUI_API ImDrawListSharedData +{ + ImVec2 TexUvWhitePixel; // UV of white pixel in the atlas + ImFont* Font; // Current/default font (optional, for simplified AddText overload) + float FontSize; // Current/default font size (optional, for simplified AddText overload) + float CurveTessellationTol; // Tessellation tolerance when using PathBezierCurveTo() + float CircleSegmentMaxError; // Number of circle segments to use per pixel of radius for AddCircle() etc + ImVec4 ClipRectFullscreen; // Value for PushClipRectFullscreen() + ImDrawListFlags InitialFlags; // Initial flags at the beginning of the frame (it is possible to alter flags on a per-drawlist basis afterwards) + + // [Internal] Lookup tables + ImVec2 ArcFastVtx[12 * IM_DRAWLIST_ARCFAST_TESSELLATION_MULTIPLIER]; // FIXME: Bake rounded corners fill/borders in atlas + ImU8 CircleSegmentCounts[64]; // Precomputed segment count for given radius (array index + 1) before we calculate it dynamically (to avoid calculation overhead) + + ImDrawListSharedData(); + void SetCircleSegmentMaxError(float max_error); +}; + +struct ImDrawDataBuilder +{ + ImVector Layers[2]; // Global layers for: regular, tooltip + + void Clear() { for (int n = 0; n < IM_ARRAYSIZE(Layers); n++) Layers[n].resize(0); } + void ClearFreeMemory() { for (int n = 0; n < IM_ARRAYSIZE(Layers); n++) Layers[n].clear(); } + IMGUI_API void FlattenIntoSingleLayer(); +}; + +//----------------------------------------------------------------------------- +// [SECTION] Widgets support: flags, enums, data structures +//----------------------------------------------------------------------------- + +// Transient per-window flags, reset at the beginning of the frame. For child window, inherited from parent on first Begin(). +// This is going to be exposed in imgui.h when stabilized enough. +enum ImGuiItemFlags_ +{ + ImGuiItemFlags_None = 0, + ImGuiItemFlags_NoTabStop = 1 << 0, // false + ImGuiItemFlags_ButtonRepeat = 1 << 1, // false // Button() will return true multiple times based on io.KeyRepeatDelay and io.KeyRepeatRate settings. + ImGuiItemFlags_Disabled = 1 << 2, // false // [BETA] Disable interactions but doesn't affect visuals yet. See github.com/ocornut/imgui/issues/211 + ImGuiItemFlags_NoNav = 1 << 3, // false + ImGuiItemFlags_NoNavDefaultFocus = 1 << 4, // false + ImGuiItemFlags_SelectableDontClosePopup = 1 << 5, // false // MenuItem/Selectable() automatically closes current Popup window + ImGuiItemFlags_MixedValue = 1 << 6, // false // [BETA] Represent a mixed/indeterminate value, generally multi-selection where values differ. Currently only supported by Checkbox() (later should support all sorts of widgets) + ImGuiItemFlags_Default_ = 0 +}; + +// Storage for LastItem data +enum ImGuiItemStatusFlags_ +{ + ImGuiItemStatusFlags_None = 0, + ImGuiItemStatusFlags_HoveredRect = 1 << 0, + ImGuiItemStatusFlags_HasDisplayRect = 1 << 1, + ImGuiItemStatusFlags_Edited = 1 << 2, // Value exposed by item was edited in the current frame (should match the bool return value of most widgets) + ImGuiItemStatusFlags_ToggledSelection = 1 << 3, // Set when Selectable(), TreeNode() reports toggling a selection. We can't report "Selected" because reporting the change allows us to handle clipping with less issues. + ImGuiItemStatusFlags_ToggledOpen = 1 << 4, // Set when TreeNode() reports toggling their open state. + ImGuiItemStatusFlags_HasDeactivated = 1 << 5, // Set if the widget/group is able to provide data for the ImGuiItemStatusFlags_Deactivated flag. + ImGuiItemStatusFlags_Deactivated = 1 << 6 // Only valid if ImGuiItemStatusFlags_HasDeactivated is set. + +#ifdef IMGUI_ENABLE_TEST_ENGINE + , // [imgui_tests only] + ImGuiItemStatusFlags_Openable = 1 << 10, // + ImGuiItemStatusFlags_Opened = 1 << 11, // + ImGuiItemStatusFlags_Checkable = 1 << 12, // + ImGuiItemStatusFlags_Checked = 1 << 13 // +#endif +}; + +enum ImGuiButtonFlags_ +{ + ImGuiButtonFlags_None = 0, + ImGuiButtonFlags_Repeat = 1 << 0, // hold to repeat + ImGuiButtonFlags_PressedOnClick = 1 << 1, // return true on click (mouse down event) + ImGuiButtonFlags_PressedOnClickRelease = 1 << 2, // [Default] return true on click + release on same item <-- this is what the majority of Button are using + ImGuiButtonFlags_PressedOnClickReleaseAnywhere = 1 << 3, // return true on click + release even if the release event is not done while hovering the item + ImGuiButtonFlags_PressedOnRelease = 1 << 4, // return true on release (default requires click+release) + ImGuiButtonFlags_PressedOnDoubleClick = 1 << 5, // return true on double-click (default requires click+release) + ImGuiButtonFlags_PressedOnDragDropHold = 1 << 6, // return true when held into while we are drag and dropping another item (used by e.g. tree nodes, collapsing headers) + ImGuiButtonFlags_FlattenChildren = 1 << 7, // allow interactions even if a child window is overlapping + ImGuiButtonFlags_AllowItemOverlap = 1 << 8, // require previous frame HoveredId to either match id or be null before being usable, use along with SetItemAllowOverlap() + ImGuiButtonFlags_DontClosePopups = 1 << 9, // disable automatically closing parent popup on press // [UNUSED] + ImGuiButtonFlags_Disabled = 1 << 10, // disable interactions + ImGuiButtonFlags_AlignTextBaseLine = 1 << 11, // vertically align button to match text baseline - ButtonEx() only // FIXME: Should be removed and handled by SmallButton(), not possible currently because of DC.CursorPosPrevLine + ImGuiButtonFlags_NoKeyModifiers = 1 << 12, // disable mouse interaction if a key modifier is held + ImGuiButtonFlags_NoHoldingActiveId = 1 << 13, // don't set ActiveId while holding the mouse (ImGuiButtonFlags_PressedOnClick only) + ImGuiButtonFlags_NoNavFocus = 1 << 14, // don't override navigation focus when activated + ImGuiButtonFlags_NoHoveredOnFocus = 1 << 15, // don't report as hovered when nav focus is on this item + ImGuiButtonFlags_MouseButtonLeft = 1 << 16, // [Default] react on left mouse button + ImGuiButtonFlags_MouseButtonRight = 1 << 17, // react on right mouse button + ImGuiButtonFlags_MouseButtonMiddle = 1 << 18, // react on center mouse button + + ImGuiButtonFlags_MouseButtonMask_ = ImGuiButtonFlags_MouseButtonLeft | ImGuiButtonFlags_MouseButtonRight | ImGuiButtonFlags_MouseButtonMiddle, + ImGuiButtonFlags_MouseButtonShift_ = 16, + ImGuiButtonFlags_MouseButtonDefault_ = ImGuiButtonFlags_MouseButtonLeft, + ImGuiButtonFlags_PressedOnMask_ = ImGuiButtonFlags_PressedOnClick | ImGuiButtonFlags_PressedOnClickRelease | ImGuiButtonFlags_PressedOnClickReleaseAnywhere | ImGuiButtonFlags_PressedOnRelease | ImGuiButtonFlags_PressedOnDoubleClick | ImGuiButtonFlags_PressedOnDragDropHold, + ImGuiButtonFlags_PressedOnDefault_ = ImGuiButtonFlags_PressedOnClickRelease +}; + +enum ImGuiSliderFlags_ +{ + ImGuiSliderFlags_None = 0, + ImGuiSliderFlags_Vertical = 1 << 0 +}; + +enum ImGuiDragFlags_ +{ + ImGuiDragFlags_None = 0, + ImGuiDragFlags_Vertical = 1 << 0 +}; + +// Extend ImGuiSelectableFlags_ +enum ImGuiSelectableFlagsPrivate_ +{ + // NB: need to be in sync with last value of ImGuiSelectableFlags_ + ImGuiSelectableFlags_NoHoldingActiveID = 1 << 20, + ImGuiSelectableFlags_SelectOnClick = 1 << 21, // Override button behavior to react on Click (default is Click+Release) + ImGuiSelectableFlags_SelectOnRelease = 1 << 22, // Override button behavior to react on Release (default is Click+Release) + ImGuiSelectableFlags_SpanAvailWidth = 1 << 23, // Span all avail width even if we declared less for layout purpose. FIXME: We may be able to remove this (added in 6251d379, 2bcafc86 for menus) + ImGuiSelectableFlags_DrawHoveredWhenHeld= 1 << 24, // Always show active when held, even is not hovered. This concept could probably be renamed/formalized somehow. + ImGuiSelectableFlags_SetNavIdOnHover = 1 << 25 +}; + +// Extend ImGuiTreeNodeFlags_ +enum ImGuiTreeNodeFlagsPrivate_ +{ + ImGuiTreeNodeFlags_ClipLabelForTrailingButton = 1 << 20 +}; + +enum ImGuiSeparatorFlags_ +{ + ImGuiSeparatorFlags_None = 0, + ImGuiSeparatorFlags_Horizontal = 1 << 0, // Axis default to current layout type, so generally Horizontal unless e.g. in a menu bar + ImGuiSeparatorFlags_Vertical = 1 << 1, + ImGuiSeparatorFlags_SpanAllColumns = 1 << 2 +}; + +enum ImGuiTextFlags_ +{ + ImGuiTextFlags_None = 0, + ImGuiTextFlags_NoWidthForLargeClippedText = 1 << 0 +}; + +enum ImGuiTooltipFlags_ +{ + ImGuiTooltipFlags_None = 0, + ImGuiTooltipFlags_OverridePreviousTooltip = 1 << 0 // Override will clear/ignore previously submitted tooltip (defaults to append) +}; + +// FIXME: this is in development, not exposed/functional as a generic feature yet. +// Horizontal/Vertical enums are fixed to 0/1 so they may be used to index ImVec2 +enum ImGuiLayoutType_ +{ + ImGuiLayoutType_Horizontal = 0, + ImGuiLayoutType_Vertical = 1 +}; + +enum ImGuiLogType +{ + ImGuiLogType_None = 0, + ImGuiLogType_TTY, + ImGuiLogType_File, + ImGuiLogType_Buffer, + ImGuiLogType_Clipboard +}; + +// X/Y enums are fixed to 0/1 so they may be used to index ImVec2 +enum ImGuiAxis +{ + ImGuiAxis_None = -1, + ImGuiAxis_X = 0, + ImGuiAxis_Y = 1 +}; + +enum ImGuiPlotType +{ + ImGuiPlotType_Lines, + ImGuiPlotType_Histogram +}; + +enum ImGuiInputSource +{ + ImGuiInputSource_None = 0, + ImGuiInputSource_Mouse, + ImGuiInputSource_Nav, + ImGuiInputSource_NavKeyboard, // Only used occasionally for storage, not tested/handled by most code + ImGuiInputSource_NavGamepad, // " + ImGuiInputSource_COUNT +}; + +// FIXME-NAV: Clarify/expose various repeat delay/rate +enum ImGuiInputReadMode +{ + ImGuiInputReadMode_Down, + ImGuiInputReadMode_Pressed, + ImGuiInputReadMode_Released, + ImGuiInputReadMode_Repeat, + ImGuiInputReadMode_RepeatSlow, + ImGuiInputReadMode_RepeatFast +}; + +enum ImGuiNavHighlightFlags_ +{ + ImGuiNavHighlightFlags_None = 0, + ImGuiNavHighlightFlags_TypeDefault = 1 << 0, + ImGuiNavHighlightFlags_TypeThin = 1 << 1, + ImGuiNavHighlightFlags_AlwaysDraw = 1 << 2, // Draw rectangular highlight if (g.NavId == id) _even_ when using the mouse. + ImGuiNavHighlightFlags_NoRounding = 1 << 3 +}; + +enum ImGuiNavDirSourceFlags_ +{ + ImGuiNavDirSourceFlags_None = 0, + ImGuiNavDirSourceFlags_Keyboard = 1 << 0, + ImGuiNavDirSourceFlags_PadDPad = 1 << 1, + ImGuiNavDirSourceFlags_PadLStick = 1 << 2 +}; + +enum ImGuiNavMoveFlags_ +{ + ImGuiNavMoveFlags_None = 0, + ImGuiNavMoveFlags_LoopX = 1 << 0, // On failed request, restart from opposite side + ImGuiNavMoveFlags_LoopY = 1 << 1, + ImGuiNavMoveFlags_WrapX = 1 << 2, // On failed request, request from opposite side one line down (when NavDir==right) or one line up (when NavDir==left) + ImGuiNavMoveFlags_WrapY = 1 << 3, // This is not super useful for provided for completeness + ImGuiNavMoveFlags_AllowCurrentNavId = 1 << 4, // Allow scoring and considering the current NavId as a move target candidate. This is used when the move source is offset (e.g. pressing PageDown actually needs to send a Up move request, if we are pressing PageDown from the bottom-most item we need to stay in place) + ImGuiNavMoveFlags_AlsoScoreVisibleSet = 1 << 5, // Store alternate result in NavMoveResultLocalVisibleSet that only comprise elements that are already fully visible. + ImGuiNavMoveFlags_ScrollToEdge = 1 << 6 +}; + +enum ImGuiNavForward +{ + ImGuiNavForward_None, + ImGuiNavForward_ForwardQueued, + ImGuiNavForward_ForwardActive +}; + +enum ImGuiNavLayer +{ + ImGuiNavLayer_Main = 0, // Main scrolling layer + ImGuiNavLayer_Menu = 1, // Menu layer (access with Alt/ImGuiNavInput_Menu) + ImGuiNavLayer_COUNT +}; + +enum ImGuiPopupPositionPolicy +{ + ImGuiPopupPositionPolicy_Default, + ImGuiPopupPositionPolicy_ComboBox +}; + +struct ImGuiDataTypeTempStorage +{ + ImU8 Data[8]; // Can fit any data up to ImGuiDataType_COUNT +}; + +// Type information associated to one ImGuiDataType. Retrieve with DataTypeGetInfo(). +struct ImGuiDataTypeInfo +{ + size_t Size; // Size in byte + const char* PrintFmt; // Default printf format for the type + const char* ScanFmt; // Default scanf format for the type +}; + +// Extend ImGuiDataType_ +enum ImGuiDataTypePrivate_ +{ + ImGuiDataType_String = ImGuiDataType_COUNT + 1, + ImGuiDataType_Pointer, + ImGuiDataType_ID +}; + +// Stacked color modifier, backup of modified data so we can restore it +struct ImGuiColorMod +{ + ImGuiCol Col; + ImVec4 BackupValue; +}; + +// Stacked style modifier, backup of modified data so we can restore it. Data type inferred from the variable. +struct ImGuiStyleMod +{ + ImGuiStyleVar VarIdx; + union { int BackupInt[2]; float BackupFloat[2]; }; + ImGuiStyleMod(ImGuiStyleVar idx, int v) { VarIdx = idx; BackupInt[0] = v; } + ImGuiStyleMod(ImGuiStyleVar idx, float v) { VarIdx = idx; BackupFloat[0] = v; } + ImGuiStyleMod(ImGuiStyleVar idx, ImVec2 v) { VarIdx = idx; BackupFloat[0] = v.x; BackupFloat[1] = v.y; } +}; + +// Stacked storage data for BeginGroup()/EndGroup() +struct ImGuiGroupData +{ + ImVec2 BackupCursorPos; + ImVec2 BackupCursorMaxPos; + ImVec1 BackupIndent; + ImVec1 BackupGroupOffset; + ImVec2 BackupCurrLineSize; + float BackupCurrLineTextBaseOffset; + ImGuiID BackupActiveIdIsAlive; + bool BackupActiveIdPreviousFrameIsAlive; + bool EmitItem; +}; + +// Simple column measurement, currently used for MenuItem() only.. This is very short-sighted/throw-away code and NOT a generic helper. +struct IMGUI_API ImGuiMenuColumns +{ + float Spacing; + float Width, NextWidth; + float Pos[3], NextWidths[3]; + + ImGuiMenuColumns(); + void Update(int count, float spacing, bool clear); + float DeclColumns(float w0, float w1, float w2); + float CalcExtraSpace(float avail_w) const; +}; + +// Internal state of the currently focused/edited text input box +// For a given item ID, access with ImGui::GetInputTextState() +struct IMGUI_API ImGuiInputTextState +{ + ImGuiID ID; // widget id owning the text state + int CurLenW, CurLenA; // we need to maintain our buffer length in both UTF-8 and wchar format. UTF-8 length is valid even if TextA is not. + ImVector TextW; // edit buffer, we need to persist but can't guarantee the persistence of the user-provided buffer. so we copy into own buffer. + ImVector TextA; // temporary UTF8 buffer for callbacks and other operations. this is not updated in every code-path! size=capacity. + ImVector InitialTextA; // backup of end-user buffer at the time of focus (in UTF-8, unaltered) + bool TextAIsValid; // temporary UTF8 buffer is not initially valid before we make the widget active (until then we pull the data from user argument) + int BufCapacityA; // end-user buffer capacity + float ScrollX; // horizontal scrolling/offset + ImStb::STB_TexteditState Stb; // state for stb_textedit.h + float CursorAnim; // timer for cursor blink, reset on every user action so the cursor reappears immediately + bool CursorFollow; // set when we want scrolling to follow the current cursor position (not always!) + bool SelectedAllMouseLock; // after a double-click to select all, we ignore further mouse drags to update selection + ImGuiInputTextFlags UserFlags; // Temporarily set while we call user's callback + ImGuiInputTextCallback UserCallback; // " + void* UserCallbackData; // " + + ImGuiInputTextState() { memset(this, 0, sizeof(*this)); } + void ClearText() { CurLenW = CurLenA = 0; TextW[0] = 0; TextA[0] = 0; CursorClamp(); } + void ClearFreeMemory() { TextW.clear(); TextA.clear(); InitialTextA.clear(); } + int GetUndoAvailCount() const { return Stb.undostate.undo_point; } + int GetRedoAvailCount() const { return STB_TEXTEDIT_UNDOSTATECOUNT - Stb.undostate.redo_point; } + void OnKeyPressed(int key); // Cannot be inline because we call in code in stb_textedit.h implementation + + // Cursor & Selection + void CursorAnimReset() { CursorAnim = -0.30f; } // After a user-input the cursor stays on for a while without blinking + void CursorClamp() { Stb.cursor = ImMin(Stb.cursor, CurLenW); Stb.select_start = ImMin(Stb.select_start, CurLenW); Stb.select_end = ImMin(Stb.select_end, CurLenW); } + bool HasSelection() const { return Stb.select_start != Stb.select_end; } + void ClearSelection() { Stb.select_start = Stb.select_end = Stb.cursor; } + void SelectAll() { Stb.select_start = 0; Stb.cursor = Stb.select_end = CurLenW; Stb.has_preferred_x = 0; } +}; + +// Storage for current popup stack +struct ImGuiPopupData +{ + ImGuiID PopupId; // Set on OpenPopup() + ImGuiWindow* Window; // Resolved on BeginPopup() - may stay unresolved if user never calls OpenPopup() + ImGuiWindow* SourceWindow; // Set on OpenPopup() copy of NavWindow at the time of opening the popup + int OpenFrameCount; // Set on OpenPopup() + ImGuiID OpenParentId; // Set on OpenPopup(), we need this to differentiate multiple menu sets from each others (e.g. inside menu bar vs loose menu items) + ImVec2 OpenPopupPos; // Set on OpenPopup(), preferred popup position (typically == OpenMousePos when using mouse) + ImVec2 OpenMousePos; // Set on OpenPopup(), copy of mouse position at the time of opening popup + + ImGuiPopupData() { PopupId = 0; Window = SourceWindow = NULL; OpenFrameCount = -1; OpenParentId = 0; } +}; + +struct ImGuiNavMoveResult +{ + ImGuiWindow* Window; // Best candidate window + ImGuiID ID; // Best candidate ID + ImGuiID FocusScopeId; // Best candidate focus scope ID + float DistBox; // Best candidate box distance to current NavId + float DistCenter; // Best candidate center distance to current NavId + float DistAxial; + ImRect RectRel; // Best candidate bounding box in window relative space + + ImGuiNavMoveResult() { Clear(); } + void Clear() { Window = NULL; ID = FocusScopeId = 0; DistBox = DistCenter = DistAxial = FLT_MAX; RectRel = ImRect(); } +}; + +enum ImGuiNextWindowDataFlags_ +{ + ImGuiNextWindowDataFlags_None = 0, + ImGuiNextWindowDataFlags_HasPos = 1 << 0, + ImGuiNextWindowDataFlags_HasSize = 1 << 1, + ImGuiNextWindowDataFlags_HasContentSize = 1 << 2, + ImGuiNextWindowDataFlags_HasCollapsed = 1 << 3, + ImGuiNextWindowDataFlags_HasSizeConstraint = 1 << 4, + ImGuiNextWindowDataFlags_HasFocus = 1 << 5, + ImGuiNextWindowDataFlags_HasBgAlpha = 1 << 6, + ImGuiNextWindowDataFlags_HasScroll = 1 << 7, + ImGuiNextWindowDataFlags_HasViewport = 1 << 8, + ImGuiNextWindowDataFlags_HasDock = 1 << 9, + ImGuiNextWindowDataFlags_HasWindowClass = 1 << 10 +}; + +// Storage for SetNexWindow** functions +struct ImGuiNextWindowData +{ + ImGuiNextWindowDataFlags Flags; + ImGuiCond PosCond; + ImGuiCond SizeCond; + ImGuiCond CollapsedCond; + ImGuiCond DockCond; + ImVec2 PosVal; + ImVec2 PosPivotVal; + ImVec2 SizeVal; + ImVec2 ContentSizeVal; + ImVec2 ScrollVal; + bool PosUndock; + bool CollapsedVal; + ImRect SizeConstraintRect; + ImGuiSizeCallback SizeCallback; + void* SizeCallbackUserData; + float BgAlphaVal; // Override background alpha + ImGuiID ViewportId; + ImGuiID DockId; + ImGuiWindowClass WindowClass; + ImVec2 MenuBarOffsetMinVal; // (Always on) This is not exposed publicly, so we don't clear it and it doesn't have a corresponding flag (could we? for consistency?) + + ImGuiNextWindowData() { memset(this, 0, sizeof(*this)); } + inline void ClearFlags() { Flags = ImGuiNextWindowDataFlags_None; } +}; + +enum ImGuiNextItemDataFlags_ +{ + ImGuiNextItemDataFlags_None = 0, + ImGuiNextItemDataFlags_HasWidth = 1 << 0, + ImGuiNextItemDataFlags_HasOpen = 1 << 1 +}; + +struct ImGuiNextItemData +{ + ImGuiNextItemDataFlags Flags; + float Width; // Set by SetNextItemWidth() + ImGuiID FocusScopeId; // Set by SetNextItemMultiSelectData() (!= 0 signify value has been set, so it's an alternate version of HasSelectionData, we don't use Flags for this because they are cleared too early. This is mostly used for debugging) + ImGuiCond OpenCond; + bool OpenVal; // Set by SetNextItemOpen() + + ImGuiNextItemData() { memset(this, 0, sizeof(*this)); } + inline void ClearFlags() { Flags = ImGuiNextItemDataFlags_None; } // Also cleared manually by ItemAdd()! +}; + +struct ImGuiShrinkWidthItem +{ + int Index; + float Width; +}; + +struct ImGuiPtrOrIndex +{ + void* Ptr; // Either field can be set, not both. e.g. Dock node tab bars are loose while BeginTabBar() ones are in a pool. + int Index; // Usually index in a main pool. + + ImGuiPtrOrIndex(void* ptr) { Ptr = ptr; Index = -1; } + ImGuiPtrOrIndex(int index) { Ptr = NULL; Index = index; } +}; + +//----------------------------------------------------------------------------- +// [SECTION] Columns support +//----------------------------------------------------------------------------- + +enum ImGuiColumnsFlags_ +{ + // Default: 0 + ImGuiColumnsFlags_None = 0, + ImGuiColumnsFlags_NoBorder = 1 << 0, // Disable column dividers + ImGuiColumnsFlags_NoResize = 1 << 1, // Disable resizing columns when clicking on the dividers + ImGuiColumnsFlags_NoPreserveWidths = 1 << 2, // Disable column width preservation when adjusting columns + ImGuiColumnsFlags_NoForceWithinWindow = 1 << 3, // Disable forcing columns to fit within window + ImGuiColumnsFlags_GrowParentContentsSize= 1 << 4 // (WIP) Restore pre-1.51 behavior of extending the parent window contents size but _without affecting the columns width at all_. Will eventually remove. +}; + +struct ImGuiColumnData +{ + float OffsetNorm; // Column start offset, normalized 0.0 (far left) -> 1.0 (far right) + float OffsetNormBeforeResize; + ImGuiColumnsFlags Flags; // Not exposed + ImRect ClipRect; + + ImGuiColumnData() { OffsetNorm = OffsetNormBeforeResize = 0.0f; Flags = ImGuiColumnsFlags_None; } +}; + +struct ImGuiColumns +{ + ImGuiID ID; + ImGuiColumnsFlags Flags; + bool IsFirstFrame; + bool IsBeingResized; + int Current; + int Count; + float OffMinX, OffMaxX; // Offsets from HostWorkRect.Min.x + float LineMinY, LineMaxY; + float HostCursorPosY; // Backup of CursorPos at the time of BeginColumns() + float HostCursorMaxPosX; // Backup of CursorMaxPos at the time of BeginColumns() + ImRect HostClipRect; // Backup of ClipRect at the time of BeginColumns() + ImRect HostWorkRect; // Backup of WorkRect at the time of BeginColumns() + ImVector Columns; + ImDrawListSplitter Splitter; + + ImGuiColumns() { Clear(); } + void Clear() + { + ID = 0; + Flags = ImGuiColumnsFlags_None; + IsFirstFrame = false; + IsBeingResized = false; + Current = 0; + Count = 1; + OffMinX = OffMaxX = 0.0f; + LineMinY = LineMaxY = 0.0f; + HostCursorPosY = 0.0f; + HostCursorMaxPosX = 0.0f; + Columns.clear(); + } +}; + +//----------------------------------------------------------------------------- +// [SECTION] Multi-select support +//----------------------------------------------------------------------------- + +#ifdef IMGUI_HAS_MULTI_SELECT +// +#endif // #ifdef IMGUI_HAS_MULTI_SELECT + +//----------------------------------------------------------------------------- +// [SECTION] Docking support +//----------------------------------------------------------------------------- + +#ifdef IMGUI_HAS_DOCK + +// Extend ImGuiDockNodeFlags_ +enum ImGuiDockNodeFlagsPrivate_ +{ + // [Internal] + ImGuiDockNodeFlags_DockSpace = 1 << 10, // Local, Saved // A dockspace is a node that occupy space within an existing user window. Otherwise the node is floating and create its own window. + ImGuiDockNodeFlags_CentralNode = 1 << 11, // Local, Saved // The central node has 2 main properties: stay visible when empty, only use "remaining" spaces from its neighbor. + ImGuiDockNodeFlags_NoTabBar = 1 << 12, // Local, Saved // Tab bar is completely unavailable. No triangle in the corner to enable it back. + ImGuiDockNodeFlags_HiddenTabBar = 1 << 13, // Local, Saved // Tab bar is hidden, with a triangle in the corner to show it again (NB: actual tab-bar instance may be destroyed as this is only used for single-window tab bar) + ImGuiDockNodeFlags_NoWindowMenuButton = 1 << 14, // Local, Saved // Disable window/docking menu (that one that appears instead of the collapse button) + ImGuiDockNodeFlags_NoCloseButton = 1 << 15, // Local, Saved // + ImGuiDockNodeFlags_NoDocking = 1 << 16, // Local, Saved // Disable any form of docking in this dockspace or individual node. (On a whole dockspace, this pretty much defeat the purpose of using a dockspace at all). Note: when turned on, existing docked nodes will be preserved. + ImGuiDockNodeFlags_SharedFlagsInheritMask_ = ~0, + ImGuiDockNodeFlags_LocalFlagsMask_ = ImGuiDockNodeFlags_NoSplit | ImGuiDockNodeFlags_NoResize | ImGuiDockNodeFlags_AutoHideTabBar | ImGuiDockNodeFlags_DockSpace | ImGuiDockNodeFlags_CentralNode | ImGuiDockNodeFlags_NoTabBar | ImGuiDockNodeFlags_HiddenTabBar | ImGuiDockNodeFlags_NoWindowMenuButton | ImGuiDockNodeFlags_NoCloseButton | ImGuiDockNodeFlags_NoDocking, + ImGuiDockNodeFlags_LocalFlagsTransferMask_ = ImGuiDockNodeFlags_LocalFlagsMask_ & ~ImGuiDockNodeFlags_DockSpace, // When splitting those flags are moved to the inheriting child, never duplicated + ImGuiDockNodeFlags_SavedFlagsMask_ = ImGuiDockNodeFlags_NoResize | ImGuiDockNodeFlags_DockSpace | ImGuiDockNodeFlags_CentralNode | ImGuiDockNodeFlags_NoTabBar | ImGuiDockNodeFlags_HiddenTabBar | ImGuiDockNodeFlags_NoWindowMenuButton | ImGuiDockNodeFlags_NoCloseButton | ImGuiDockNodeFlags_NoDocking +}; + +// Store the source authority (dock node vs window) of a field +enum ImGuiDataAuthority_ +{ + ImGuiDataAuthority_Auto, + ImGuiDataAuthority_DockNode, + ImGuiDataAuthority_Window +}; + +enum ImGuiDockNodeState +{ + ImGuiDockNodeState_Unknown, + ImGuiDockNodeState_HostWindowHiddenBecauseSingleWindow, + ImGuiDockNodeState_HostWindowHiddenBecauseWindowsAreResizing, + ImGuiDockNodeState_HostWindowVisible +}; + +// sizeof() 116~160 +struct ImGuiDockNode +{ + ImGuiID ID; + ImGuiDockNodeFlags SharedFlags; // Flags shared by all nodes of a same dockspace hierarchy (inherited from the root node) + ImGuiDockNodeFlags LocalFlags; // Flags specific to this node + ImGuiDockNode* ParentNode; + ImGuiDockNode* ChildNodes[2]; // [Split node only] Child nodes (left/right or top/bottom). Consider switching to an array. + ImVector Windows; // Note: unordered list! Iterate TabBar->Tabs for user-order. + ImGuiTabBar* TabBar; + ImVec2 Pos; // Current position + ImVec2 Size; // Current size + ImVec2 SizeRef; // [Split node only] Last explicitly written-to size (overridden when using a splitter affecting the node), used to calculate Size. + ImGuiAxis SplitAxis; // [Split node only] Split axis (X or Y) + ImGuiWindowClass WindowClass; // [Root node only] + + ImGuiDockNodeState State; + ImGuiWindow* HostWindow; + ImGuiWindow* VisibleWindow; // Generally point to window which is ID is == SelectedTabID, but when CTRL+Tabbing this can be a different window. + ImGuiDockNode* CentralNode; // [Root node only] Pointer to central node. + ImGuiDockNode* OnlyNodeWithWindows; // [Root node only] Set when there is a single visible node within the hierarchy. + int LastFrameAlive; // Last frame number the node was updated or kept alive explicitly with DockSpace() + ImGuiDockNodeFlags_KeepAliveOnly + int LastFrameActive; // Last frame number the node was updated. + int LastFrameFocused; // Last frame number the node was focused. + ImGuiID LastFocusedNodeId; // [Root node only] Which of our child docking node (any ancestor in the hierarchy) was last focused. + ImGuiID SelectedTabId; // [Leaf node only] Which of our tab/window is selected. + ImGuiID WantCloseTabId; // [Leaf node only] Set when closing a specific tab/window. + ImGuiDataAuthority AuthorityForPos :3; + ImGuiDataAuthority AuthorityForSize :3; + ImGuiDataAuthority AuthorityForViewport :3; + bool IsVisible :1; // Set to false when the node is hidden (usually disabled as it has no active window) + bool IsFocused :1; + bool HasCloseButton :1; + bool HasWindowMenuButton :1; + bool EnableCloseButton :1; + bool WantCloseAll :1; // Set when closing all tabs at once. + bool WantLockSizeOnce :1; + bool WantMouseMove :1; // After a node extraction we need to transition toward moving the newly created host window + bool WantHiddenTabBarUpdate :1; + bool WantHiddenTabBarToggle :1; + bool MarkedForPosSizeWrite :1; // Update by DockNodeTreeUpdatePosSize() write-filtering + + ImGuiDockNode(ImGuiID id); + ~ImGuiDockNode(); + bool IsRootNode() const { return ParentNode == NULL; } + bool IsDockSpace() const { return (LocalFlags & ImGuiDockNodeFlags_DockSpace) != 0; } + bool IsFloatingNode() const { return ParentNode == NULL && (LocalFlags & ImGuiDockNodeFlags_DockSpace) == 0; } + bool IsCentralNode() const { return (LocalFlags & ImGuiDockNodeFlags_CentralNode) != 0; } + bool IsHiddenTabBar() const { return (LocalFlags & ImGuiDockNodeFlags_HiddenTabBar) != 0; } // Hidden tab bar can be shown back by clicking the small triangle + bool IsNoTabBar() const { return (LocalFlags & ImGuiDockNodeFlags_NoTabBar) != 0; } // Never show a tab bar + bool IsSplitNode() const { return ChildNodes[0] != NULL; } + bool IsLeafNode() const { return ChildNodes[0] == NULL; } + bool IsEmpty() const { return ChildNodes[0] == NULL && Windows.Size == 0; } + ImGuiDockNodeFlags GetMergedFlags() const { return SharedFlags | LocalFlags; } + ImRect Rect() const { return ImRect(Pos.x, Pos.y, Pos.x + Size.x, Pos.y + Size.y); } +}; + +struct ImGuiDockContext +{ + ImGuiStorage Nodes; // Map ID -> ImGuiDockNode*: Active nodes + ImVector Requests; + ImVector NodesSettings; + bool WantFullRebuild; + ImGuiDockContext() { WantFullRebuild = false; } +}; + +#endif // #ifdef IMGUI_HAS_DOCK + +//----------------------------------------------------------------------------- +// [SECTION] Viewport support +//----------------------------------------------------------------------------- + +#ifdef IMGUI_HAS_VIEWPORT + +// ImGuiViewport Private/Internals fields (cardinal sin: we are using inheritance!) +// Note that every instance of ImGuiViewport is in fact a ImGuiViewportP. +struct ImGuiViewportP : public ImGuiViewport +{ + int Idx; + int LastFrameActive; // Last frame number this viewport was activated by a window + int LastFrameDrawLists[2]; // Last frame number the background (0) and foreground (1) draw lists were used + int LastFrontMostStampCount; // Last stamp number from when a window hosted by this viewport was made front-most (by comparing this value between two viewport we have an implicit viewport z-order + ImGuiID LastNameHash; + ImVec2 LastPos; + float Alpha; // Window opacity (when dragging dockable windows/viewports we make them transparent) + float LastAlpha; + short PlatformMonitor; + bool PlatformWindowCreated; + ImGuiWindow* Window; // Set when the viewport is owned by a window (and ImGuiViewportFlags_CanHostOtherWindows is NOT set) + ImDrawList* DrawLists[2]; // Convenience background (0) and foreground (1) draw lists. We use them to draw software mouser cursor when io.MouseDrawCursor is set and to draw most debug overlays. + ImDrawData DrawDataP; + ImDrawDataBuilder DrawDataBuilder; + ImVec2 LastPlatformPos; + ImVec2 LastPlatformSize; + ImVec2 LastRendererSize; + ImVec2 CurrWorkOffsetMin; // Work area top-left offset being increased during the frame + ImVec2 CurrWorkOffsetMax; // Work area bottom-right offset being decreased during the frame + + ImGuiViewportP() { Idx = -1; LastFrameActive = LastFrameDrawLists[0] = LastFrameDrawLists[1] = LastFrontMostStampCount = -1; LastNameHash = 0; Alpha = LastAlpha = 1.0f; PlatformMonitor = -1; PlatformWindowCreated = false; Window = NULL; DrawLists[0] = DrawLists[1] = NULL; LastPlatformPos = LastPlatformSize = LastRendererSize = ImVec2(FLT_MAX, FLT_MAX); } + ~ImGuiViewportP() { if (DrawLists[0]) IM_DELETE(DrawLists[0]); if (DrawLists[1]) IM_DELETE(DrawLists[1]); } + ImRect GetMainRect() const { return ImRect(Pos.x, Pos.y, Pos.x + Size.x, Pos.y + Size.y); } + ImRect GetWorkRect() const { return ImRect(Pos.x + WorkOffsetMin.x, Pos.y + WorkOffsetMin.y, Pos.x + Size.x + WorkOffsetMax.x, Pos.y + Size.y + WorkOffsetMax.y); } + void ClearRequestFlags() { PlatformRequestClose = PlatformRequestMove = PlatformRequestResize = false; } +}; + +#endif // #ifdef IMGUI_HAS_VIEWPORT + +//----------------------------------------------------------------------------- +// [SECTION] Settings support +//----------------------------------------------------------------------------- + +// Windows data saved in imgui.ini file +// Because we never destroy or rename ImGuiWindowSettings, we can store the names in a separate buffer easily. +// (this is designed to be stored in a ImChunkStream buffer, with the variable-length Name following our structure) +struct ImGuiWindowSettings +{ + ImGuiID ID; + ImVec2ih Pos; // NB: Settings position are stored RELATIVE to the viewport! Whereas runtime ones are absolute positions. + ImVec2ih Size; + ImVec2ih ViewportPos; + ImGuiID ViewportId; + ImGuiID DockId; // ID of last known DockNode (even if the DockNode is invisible because it has only 1 active window), or 0 if none. + ImGuiID ClassId; // ID of window class if specified + short DockOrder; // Order of the last time the window was visible within its DockNode. This is used to reorder windows that are reappearing on the same frame. Same value between windows that were active and windows that were none are possible. + bool Collapsed; + bool WantApply; // Set when loaded from .ini data (to enable merging/loading .ini data into an already running context) + + ImGuiWindowSettings() { ID = 0; Pos = Size = ViewportPos = ImVec2ih(0, 0); ViewportId = DockId = ClassId = 0; DockOrder = -1; Collapsed = WantApply = false; } + char* GetName() { return (char*)(this + 1); } +}; + +struct ImGuiSettingsHandler +{ + const char* TypeName; // Short description stored in .ini file. Disallowed characters: '[' ']' + ImGuiID TypeHash; // == ImHashStr(TypeName) + void (*ClearAllFn)(ImGuiContext* ctx, ImGuiSettingsHandler* handler); // Clear all settings data + void (*ReadInitFn)(ImGuiContext* ctx, ImGuiSettingsHandler* handler); // Read: Called before reading (in registration order) + void* (*ReadOpenFn)(ImGuiContext* ctx, ImGuiSettingsHandler* handler, const char* name); // Read: Called when entering into a new ini entry e.g. "[Window][Name]" + void (*ReadLineFn)(ImGuiContext* ctx, ImGuiSettingsHandler* handler, void* entry, const char* line); // Read: Called for every line of text within an ini entry + void (*ApplyAllFn)(ImGuiContext* ctx, ImGuiSettingsHandler* handler); // Read: Called after reading (in registration order) + void (*WriteAllFn)(ImGuiContext* ctx, ImGuiSettingsHandler* handler, ImGuiTextBuffer* out_buf); // Write: Output every entries into 'out_buf' + void* UserData; + + ImGuiSettingsHandler() { memset(this, 0, sizeof(*this)); } +}; + +//----------------------------------------------------------------------------- +// [SECTION] ImGuiContext (main imgui context) +//----------------------------------------------------------------------------- + +struct ImGuiContext +{ + bool Initialized; + bool FontAtlasOwnedByContext; // IO.Fonts-> is owned by the ImGuiContext and will be destructed along with it. + ImGuiIO IO; + ImGuiPlatformIO PlatformIO; + ImGuiStyle Style; + ImGuiConfigFlags ConfigFlagsCurrFrame; // = g.IO.ConfigFlags at the time of NewFrame() + ImGuiConfigFlags ConfigFlagsLastFrame; + ImFont* Font; // (Shortcut) == FontStack.empty() ? IO.Font : FontStack.back() + float FontSize; // (Shortcut) == FontBaseSize * g.CurrentWindow->FontWindowScale == window->FontSize(). Text height for current window. + float FontBaseSize; // (Shortcut) == IO.FontGlobalScale * Font->Scale * Font->FontSize. Base text height. + ImDrawListSharedData DrawListSharedData; + double Time; + int FrameCount; + int FrameCountEnded; + int FrameCountPlatformEnded; + int FrameCountRendered; + bool WithinFrameScope; // Set by NewFrame(), cleared by EndFrame() + bool WithinFrameScopeWithImplicitWindow; // Set by NewFrame(), cleared by EndFrame() when the implicit debug window has been pushed + bool WithinEndChild; // Set within EndChild() + bool TestEngineHookItems; // Will call test engine hooks: ImGuiTestEngineHook_ItemAdd(), ImGuiTestEngineHook_ItemInfo(), ImGuiTestEngineHook_Log() + ImGuiID TestEngineHookIdInfo; // Will call test engine hooks: ImGuiTestEngineHook_IdInfo() from GetID() + void* TestEngine; // Test engine user data + + // Windows state + ImVector Windows; // Windows, sorted in display order, back to front + ImVector WindowsFocusOrder; // Windows, sorted in focus order, back to front. (FIXME: We could only store root windows here! Need to sort out the Docking equivalent which is RootWindowDockStop and is unfortunately a little more dynamic) + ImVector WindowsTempSortBuffer; // Temporary buffer used in EndFrame() to reorder windows so parents are kept before their child + ImVector CurrentWindowStack; + ImGuiStorage WindowsById; // Map window's ImGuiID to ImGuiWindow* + int WindowsActiveCount; // Number of unique windows submitted by frame + ImGuiWindow* CurrentWindow; // Window being drawn into + ImGuiWindow* HoveredWindow; // Will catch mouse inputs + ImGuiWindow* HoveredRootWindow; // Will catch mouse inputs (for focus/move only) + ImGuiWindow* HoveredWindowUnderMovingWindow; // Hovered window ignoring MovingWindow. Only set if MovingWindow is set. + ImGuiWindow* MovingWindow; // Track the window we clicked on (in order to preserve focus). The actually window that is moved is generally MovingWindow->RootWindow. + ImGuiWindow* WheelingWindow; // Track the window we started mouse-wheeling on. Until a timer elapse or mouse has moved, generally keep scrolling the same window even if during the course of scrolling the mouse ends up hovering a child window. + ImVec2 WheelingWindowRefMousePos; + float WheelingWindowTimer; + + // Item/widgets state and tracking information + ImGuiID HoveredId; // Hovered widget + bool HoveredIdAllowOverlap; + ImGuiID HoveredIdPreviousFrame; + float HoveredIdTimer; // Measure contiguous hovering time + float HoveredIdNotActiveTimer; // Measure contiguous hovering time where the item has not been active + ImGuiID ActiveId; // Active widget + ImGuiID ActiveIdIsAlive; // Active widget has been seen this frame (we can't use a bool as the ActiveId may change within the frame) + float ActiveIdTimer; + bool ActiveIdIsJustActivated; // Set at the time of activation for one frame + bool ActiveIdAllowOverlap; // Active widget allows another widget to steal active id (generally for overlapping widgets, but not always) + bool ActiveIdHasBeenPressedBefore; // Track whether the active id led to a press (this is to allow changing between PressOnClick and PressOnRelease without pressing twice). Used by range_select branch. + bool ActiveIdHasBeenEditedBefore; // Was the value associated to the widget Edited over the course of the Active state. + bool ActiveIdHasBeenEditedThisFrame; + ImU32 ActiveIdUsingNavDirMask; // Active widget will want to read those nav move requests (e.g. can activate a button and move away from it) + ImU32 ActiveIdUsingNavInputMask; // Active widget will want to read those nav inputs. + ImU64 ActiveIdUsingKeyInputMask; // Active widget will want to read those key inputs. When we grow the ImGuiKey enum we'll need to either to order the enum to make useful keys come first, either redesign this into e.g. a small array. + ImVec2 ActiveIdClickOffset; // Clicked offset from upper-left corner, if applicable (currently only set by ButtonBehavior) + ImGuiWindow* ActiveIdWindow; + ImGuiInputSource ActiveIdSource; // Activating with mouse or nav (gamepad/keyboard) + int ActiveIdMouseButton; + ImGuiID ActiveIdPreviousFrame; + bool ActiveIdPreviousFrameIsAlive; + bool ActiveIdPreviousFrameHasBeenEditedBefore; + ImGuiWindow* ActiveIdPreviousFrameWindow; + ImGuiID LastActiveId; // Store the last non-zero ActiveId, useful for animation. + float LastActiveIdTimer; // Store the last non-zero ActiveId timer since the beginning of activation, useful for animation. + + // Next window/item data + ImGuiNextWindowData NextWindowData; // Storage for SetNextWindow** functions + ImGuiNextItemData NextItemData; // Storage for SetNextItem** functions + + // Shared stacks + ImVector ColorModifiers; // Stack for PushStyleColor()/PopStyleColor() + ImVector StyleModifiers; // Stack for PushStyleVar()/PopStyleVar() + ImVector FontStack; // Stack for PushFont()/PopFont() + ImVectorOpenPopupStack; // Which popups are open (persistent) + ImVectorBeginPopupStack; // Which level of BeginPopup() we are in (reset every frame) + + // Viewports + ImVector Viewports; // Active viewports (always 1+, and generally 1 unless multi-viewports are enabled). Each viewports hold their copy of ImDrawData. + float CurrentDpiScale; // == CurrentViewport->DpiScale + ImGuiViewportP* CurrentViewport; // We track changes of viewport (happening in Begin) so we can call Platform_OnChangedViewport() + ImGuiViewportP* MouseViewport; + ImGuiViewportP* MouseLastHoveredViewport; // Last known viewport that was hovered by mouse (even if we are not hovering any viewport any more) + honoring the _NoInputs flag. + ImGuiID PlatformLastFocusedViewport; // Record of last focused platform window/viewport, when this changes we stamp the viewport as front-most + int ViewportFrontMostStampCount; // Every time the front-most window changes, we stamp its viewport with an incrementing counter + + // Gamepad/keyboard Navigation + ImGuiWindow* NavWindow; // Focused window for navigation. Could be called 'FocusWindow' + ImGuiID NavId; // Focused item for navigation + ImGuiID NavFocusScopeId; // Identify a selection scope (selection code often wants to "clear other items" when landing on an item of the selection set) + ImGuiID NavActivateId; // ~~ (g.ActiveId == 0) && IsNavInputPressed(ImGuiNavInput_Activate) ? NavId : 0, also set when calling ActivateItem() + ImGuiID NavActivateDownId; // ~~ IsNavInputDown(ImGuiNavInput_Activate) ? NavId : 0 + ImGuiID NavActivatePressedId; // ~~ IsNavInputPressed(ImGuiNavInput_Activate) ? NavId : 0 + ImGuiID NavInputId; // ~~ IsNavInputPressed(ImGuiNavInput_Input) ? NavId : 0 + ImGuiID NavJustTabbedId; // Just tabbed to this id. + ImGuiID NavJustMovedToId; // Just navigated to this id (result of a successfully MoveRequest). + ImGuiID NavJustMovedToFocusScopeId; // Just navigated to this focus scope id (result of a successfully MoveRequest). + ImGuiKeyModFlags NavJustMovedToKeyMods; + ImGuiID NavNextActivateId; // Set by ActivateItem(), queued until next frame. + ImGuiInputSource NavInputSource; // Keyboard or Gamepad mode? THIS WILL ONLY BE None or NavGamepad or NavKeyboard. + ImRect NavScoringRect; // Rectangle used for scoring, in screen space. Based of window->DC.NavRefRectRel[], modified for directional navigation scoring. + int NavScoringCount; // Metrics for debugging + ImGuiNavLayer NavLayer; // Layer we are navigating on. For now the system is hard-coded for 0=main contents and 1=menu/title bar, may expose layers later. + int NavIdTabCounter; // == NavWindow->DC.FocusIdxTabCounter at time of NavId processing + bool NavIdIsAlive; // Nav widget has been seen this frame ~~ NavRefRectRel is valid + bool NavMousePosDirty; // When set we will update mouse position if (io.ConfigFlags & ImGuiConfigFlags_NavEnableSetMousePos) if set (NB: this not enabled by default) + bool NavDisableHighlight; // When user starts using mouse, we hide gamepad/keyboard highlight (NB: but they are still available, which is why NavDisableHighlight isn't always != NavDisableMouseHover) + bool NavDisableMouseHover; // When user starts using gamepad/keyboard, we hide mouse hovering highlight until mouse is touched again. + bool NavAnyRequest; // ~~ NavMoveRequest || NavInitRequest + bool NavInitRequest; // Init request for appearing window to select first item + bool NavInitRequestFromMove; + ImGuiID NavInitResultId; // Init request result (first item of the window, or one for which SetItemDefaultFocus() was called) + ImRect NavInitResultRectRel; // Init request result rectangle (relative to parent window) + bool NavMoveFromClampedRefRect; // Set by manual scrolling, if we scroll to a point where NavId isn't visible we reset navigation from visible items + bool NavMoveRequest; // Move request for this frame + ImGuiNavMoveFlags NavMoveRequestFlags; + ImGuiNavForward NavMoveRequestForward; // None / ForwardQueued / ForwardActive (this is used to navigate sibling parent menus from a child menu) + ImGuiKeyModFlags NavMoveRequestKeyMods; + ImGuiDir NavMoveDir, NavMoveDirLast; // Direction of the move request (left/right/up/down), direction of the previous move request + ImGuiDir NavMoveClipDir; // FIXME-NAV: Describe the purpose of this better. Might want to rename? + ImGuiNavMoveResult NavMoveResultLocal; // Best move request candidate within NavWindow + ImGuiNavMoveResult NavMoveResultLocalVisibleSet; // Best move request candidate within NavWindow that are mostly visible (when using ImGuiNavMoveFlags_AlsoScoreVisibleSet flag) + ImGuiNavMoveResult NavMoveResultOther; // Best move request candidate within NavWindow's flattened hierarchy (when using ImGuiWindowFlags_NavFlattened flag) + ImGuiWindow* NavWrapRequestWindow; // Window which requested trying nav wrap-around. + ImGuiNavMoveFlags NavWrapRequestFlags; // Wrap-around operation flags. + + // Navigation: Windowing (CTRL+TAB for list, or Menu button + keys or directional pads to move/resize) + ImGuiWindow* NavWindowingTarget; // Target window when doing CTRL+Tab (or Pad Menu + FocusPrev/Next), this window is temporarily displayed top-most! + ImGuiWindow* NavWindowingTargetAnim; // Record of last valid NavWindowingTarget until DimBgRatio and NavWindowingHighlightAlpha becomes 0.0f, so the fade-out can stay on it. + ImGuiWindow* NavWindowingListWindow; // Internal window actually listing the CTRL+Tab contents + float NavWindowingTimer; + float NavWindowingHighlightAlpha; + bool NavWindowingToggleLayer; + + // Legacy Focus/Tabbing system (older than Nav, active even if Nav is disabled, misnamed. FIXME-NAV: This needs a redesign!) + ImGuiWindow* FocusRequestCurrWindow; // + ImGuiWindow* FocusRequestNextWindow; // + int FocusRequestCurrCounterRegular; // Any item being requested for focus, stored as an index (we on layout to be stable between the frame pressing TAB and the next frame, semi-ouch) + int FocusRequestCurrCounterTabStop; // Tab item being requested for focus, stored as an index + int FocusRequestNextCounterRegular; // Stored for next frame + int FocusRequestNextCounterTabStop; // " + bool FocusTabPressed; // + + // Render + float DimBgRatio; // 0.0..1.0 animation when fading in a dimming background (for modal window and CTRL+TAB list) + ImGuiMouseCursor MouseCursor; + + // Drag and Drop + bool DragDropActive; + bool DragDropWithinSource; // Set when within a BeginDragDropXXX/EndDragDropXXX block for a drag source. + bool DragDropWithinTarget; // Set when within a BeginDragDropXXX/EndDragDropXXX block for a drag target. + ImGuiDragDropFlags DragDropSourceFlags; + int DragDropSourceFrameCount; + int DragDropMouseButton; + ImGuiPayload DragDropPayload; + ImRect DragDropTargetRect; // Store rectangle of current target candidate (we favor small targets when overlapping) + ImGuiID DragDropTargetId; + ImGuiDragDropFlags DragDropAcceptFlags; + float DragDropAcceptIdCurrRectSurface; // Target item surface (we resolve overlapping targets by prioritizing the smaller surface) + ImGuiID DragDropAcceptIdCurr; // Target item id (set at the time of accepting the payload) + ImGuiID DragDropAcceptIdPrev; // Target item id from previous frame (we need to store this to allow for overlapping drag and drop targets) + int DragDropAcceptFrameCount; // Last time a target expressed a desire to accept the source + ImGuiID DragDropHoldJustPressedId; // Set when holding a payload just made ButtonBehavior() return a press. + ImVector DragDropPayloadBufHeap; // We don't expose the ImVector<> directly, ImGuiPayload only holds pointer+size + unsigned char DragDropPayloadBufLocal[16]; // Local buffer for small payloads + + // Tab bars + ImGuiTabBar* CurrentTabBar; + ImPool TabBars; + ImVector CurrentTabBarStack; + ImVector ShrinkWidthBuffer; + + // Widget state + ImVec2 LastValidMousePos; + ImGuiInputTextState InputTextState; + ImFont InputTextPasswordFont; + ImGuiID TempInputId; // Temporary text input when CTRL+clicking on a slider, etc. + ImGuiColorEditFlags ColorEditOptions; // Store user options for color edit widgets + float ColorEditLastHue; // Backup of last Hue associated to LastColor[3], so we can restore Hue in lossy RGB<>HSV round trips + float ColorEditLastSat; // Backup of last Saturation associated to LastColor[3], so we can restore Saturation in lossy RGB<>HSV round trips + float ColorEditLastColor[3]; + ImVec4 ColorPickerRef; // Initial/reference color at the time of opening the color picker. + bool DragCurrentAccumDirty; + float DragCurrentAccum; // Accumulator for dragging modification. Always high-precision, not rounded by end-user precision settings + float DragSpeedDefaultRatio; // If speed == 0.0f, uses (max-min) * DragSpeedDefaultRatio + float ScrollbarClickDeltaToGrabCenter; // Distance between mouse and center of grab box, normalized in parent space. Use storage? + int TooltipOverrideCount; + ImVector ClipboardHandlerData; // If no custom clipboard handler is defined + ImVector MenusIdSubmittedThisFrame; // A list of menu IDs that were rendered at least once + + // Platform support + ImVec2 PlatformImePos; // Cursor position request & last passed to the OS Input Method Editor + ImVec2 PlatformImeLastPos; + ImGuiViewportP* PlatformImePosViewport; + + // Extensions + // FIXME: We could provide an API to register one slot in an array held in ImGuiContext? + ImGuiDockContext DockContext; + + // Settings + bool SettingsLoaded; + float SettingsDirtyTimer; // Save .ini Settings to memory when time reaches zero + ImGuiTextBuffer SettingsIniData; // In memory .ini settings + ImVector SettingsHandlers; // List of .ini settings handlers + ImChunkStream SettingsWindows; // ImGuiWindow .ini settings entries + + // Capture/Logging + bool LogEnabled; // Currently capturing + ImGuiLogType LogType; // Capture target + ImFileHandle LogFile; // If != NULL log to stdout/ file + ImGuiTextBuffer LogBuffer; // Accumulation buffer when log to clipboard. This is pointer so our GImGui static constructor doesn't call heap allocators. + float LogLinePosY; + bool LogLineFirstItem; + int LogDepthRef; + int LogDepthToExpand; + int LogDepthToExpandDefault; // Default/stored value for LogDepthMaxExpand if not specified in the LogXXX function call. + + // Debug Tools + bool DebugItemPickerActive; // Item picker is active (started with DebugStartItemPicker()) + ImGuiID DebugItemPickerBreakId; // Will call IM_DEBUG_BREAK() when encountering this id + + // Misc + float FramerateSecPerFrame[120]; // Calculate estimate of framerate for user over the last 2 seconds. + int FramerateSecPerFrameIdx; + float FramerateSecPerFrameAccum; + int WantCaptureMouseNextFrame; // Explicit capture via CaptureKeyboardFromApp()/CaptureMouseFromApp() sets those flags + int WantCaptureKeyboardNextFrame; + int WantTextInputNextFrame; + char TempBuffer[1024*3+1]; // Temporary text buffer + + ImGuiContext(ImFontAtlas* shared_font_atlas) + { + Initialized = false; + ConfigFlagsCurrFrame = ConfigFlagsLastFrame = ImGuiConfigFlags_None; + FontAtlasOwnedByContext = shared_font_atlas ? false : true; + Font = NULL; + FontSize = FontBaseSize = 0.0f; + IO.Fonts = shared_font_atlas ? shared_font_atlas : IM_NEW(ImFontAtlas)(); + Time = 0.0f; + FrameCount = 0; + FrameCountEnded = FrameCountPlatformEnded = FrameCountRendered = -1; + WithinFrameScope = WithinFrameScopeWithImplicitWindow = WithinEndChild = false; + TestEngineHookItems = false; + TestEngineHookIdInfo = 0; + TestEngine = NULL; + + WindowsActiveCount = 0; + CurrentWindow = NULL; + HoveredWindow = NULL; + HoveredRootWindow = NULL; + HoveredWindowUnderMovingWindow = NULL; + MovingWindow = NULL; + WheelingWindow = NULL; + WheelingWindowTimer = 0.0f; + + HoveredId = 0; + HoveredIdAllowOverlap = false; + HoveredIdPreviousFrame = 0; + HoveredIdTimer = HoveredIdNotActiveTimer = 0.0f; + ActiveId = 0; + ActiveIdIsAlive = 0; + ActiveIdTimer = 0.0f; + ActiveIdIsJustActivated = false; + ActiveIdAllowOverlap = false; + ActiveIdHasBeenPressedBefore = false; + ActiveIdHasBeenEditedBefore = false; + ActiveIdHasBeenEditedThisFrame = false; + ActiveIdUsingNavDirMask = 0x00; + ActiveIdUsingNavInputMask = 0x00; + ActiveIdUsingKeyInputMask = 0x00; + ActiveIdClickOffset = ImVec2(-1,-1); + ActiveIdWindow = NULL; + ActiveIdSource = ImGuiInputSource_None; + ActiveIdMouseButton = 0; + ActiveIdPreviousFrame = 0; + ActiveIdPreviousFrameIsAlive = false; + ActiveIdPreviousFrameHasBeenEditedBefore = false; + ActiveIdPreviousFrameWindow = NULL; + LastActiveId = 0; + LastActiveIdTimer = 0.0f; + + CurrentDpiScale = 0.0f; + CurrentViewport = NULL; + MouseViewport = MouseLastHoveredViewport = NULL; + PlatformLastFocusedViewport = 0; + ViewportFrontMostStampCount = 0; + + NavWindow = NULL; + NavId = NavFocusScopeId = NavActivateId = NavActivateDownId = NavActivatePressedId = NavInputId = 0; + NavJustTabbedId = NavJustMovedToId = NavJustMovedToFocusScopeId = NavNextActivateId = 0; + NavJustMovedToKeyMods = ImGuiKeyModFlags_None; + NavInputSource = ImGuiInputSource_None; + NavScoringRect = ImRect(); + NavScoringCount = 0; + NavLayer = ImGuiNavLayer_Main; + NavIdTabCounter = INT_MAX; + NavIdIsAlive = false; + NavMousePosDirty = false; + NavDisableHighlight = true; + NavDisableMouseHover = false; + NavAnyRequest = false; + NavInitRequest = false; + NavInitRequestFromMove = false; + NavInitResultId = 0; + NavMoveFromClampedRefRect = false; + NavMoveRequest = false; + NavMoveRequestFlags = ImGuiNavMoveFlags_None; + NavMoveRequestForward = ImGuiNavForward_None; + NavMoveRequestKeyMods = ImGuiKeyModFlags_None; + NavMoveDir = NavMoveDirLast = NavMoveClipDir = ImGuiDir_None; + NavWrapRequestWindow = NULL; + NavWrapRequestFlags = ImGuiNavMoveFlags_None; + + NavWindowingTarget = NavWindowingTargetAnim = NavWindowingListWindow = NULL; + NavWindowingTimer = NavWindowingHighlightAlpha = 0.0f; + NavWindowingToggleLayer = false; + + FocusRequestCurrWindow = FocusRequestNextWindow = NULL; + FocusRequestCurrCounterRegular = FocusRequestCurrCounterTabStop = INT_MAX; + FocusRequestNextCounterRegular = FocusRequestNextCounterTabStop = INT_MAX; + FocusTabPressed = false; + + DimBgRatio = 0.0f; + MouseCursor = ImGuiMouseCursor_Arrow; + + DragDropActive = DragDropWithinSource = DragDropWithinTarget = false; + DragDropSourceFlags = ImGuiDragDropFlags_None; + DragDropSourceFrameCount = -1; + DragDropMouseButton = -1; + DragDropTargetId = 0; + DragDropAcceptFlags = ImGuiDragDropFlags_None; + DragDropAcceptIdCurrRectSurface = 0.0f; + DragDropAcceptIdPrev = DragDropAcceptIdCurr = 0; + DragDropAcceptFrameCount = -1; + DragDropHoldJustPressedId = 0; + memset(DragDropPayloadBufLocal, 0, sizeof(DragDropPayloadBufLocal)); + + CurrentTabBar = NULL; + + LastValidMousePos = ImVec2(0.0f, 0.0f); + TempInputId = 0; + ColorEditOptions = ImGuiColorEditFlags__OptionsDefault; + ColorEditLastHue = ColorEditLastSat = 0.0f; + ColorEditLastColor[0] = ColorEditLastColor[1] = ColorEditLastColor[2] = FLT_MAX; + DragCurrentAccumDirty = false; + DragCurrentAccum = 0.0f; + DragSpeedDefaultRatio = 1.0f / 100.0f; + ScrollbarClickDeltaToGrabCenter = 0.0f; + TooltipOverrideCount = 0; + + PlatformImePos = PlatformImeLastPos = ImVec2(FLT_MAX, FLT_MAX); + PlatformImePosViewport = 0; + + SettingsLoaded = false; + SettingsDirtyTimer = 0.0f; + + LogEnabled = false; + LogType = ImGuiLogType_None; + LogFile = NULL; + LogLinePosY = FLT_MAX; + LogLineFirstItem = false; + LogDepthRef = 0; + LogDepthToExpand = LogDepthToExpandDefault = 2; + + DebugItemPickerActive = false; + DebugItemPickerBreakId = 0; + + memset(FramerateSecPerFrame, 0, sizeof(FramerateSecPerFrame)); + FramerateSecPerFrameIdx = 0; + FramerateSecPerFrameAccum = 0.0f; + WantCaptureMouseNextFrame = WantCaptureKeyboardNextFrame = WantTextInputNextFrame = -1; + memset(TempBuffer, 0, sizeof(TempBuffer)); + } +}; + +//----------------------------------------------------------------------------- +// [SECTION] ImGuiWindowTempData, ImGuiWindow +//----------------------------------------------------------------------------- + +// Transient per-window data, reset at the beginning of the frame. This used to be called ImGuiDrawContext, hence the DC variable name in ImGuiWindow. +// FIXME: That's theory, in practice the delimitation between ImGuiWindow and ImGuiWindowTempData is quite tenuous and could be reconsidered. +struct IMGUI_API ImGuiWindowTempData +{ + // Layout + ImVec2 CursorPos; // Current emitting position, in absolute coordinates. + ImVec2 CursorPosPrevLine; + ImVec2 CursorStartPos; // Initial position after Begin(), generally ~ window position + WindowPadding. + ImVec2 CursorMaxPos; // Used to implicitly calculate the size of our contents, always growing during the frame. Used to calculate window->ContentSize at the beginning of next frame + ImVec2 CurrLineSize; + ImVec2 PrevLineSize; + float CurrLineTextBaseOffset; // Baseline offset (0.0f by default on a new line, generally == style.FramePadding.y when a framed item has been added). + float PrevLineTextBaseOffset; + ImVec1 Indent; // Indentation / start position from left of window (increased by TreePush/TreePop, etc.) + ImVec1 ColumnsOffset; // Offset to the current column (if ColumnsCurrent > 0). FIXME: This and the above should be a stack to allow use cases like Tree->Column->Tree. Need revamp columns API. + ImVec1 GroupOffset; + + // Last item status + ImGuiID LastItemId; // ID for last item + ImGuiItemStatusFlags LastItemStatusFlags; // Status flags for last item (see ImGuiItemStatusFlags_) + ImRect LastItemRect; // Interaction rect for last item + ImRect LastItemDisplayRect; // End-user display rect for last item (only valid if LastItemStatusFlags & ImGuiItemStatusFlags_HasDisplayRect) + + // Keyboard/Gamepad navigation + ImGuiNavLayer NavLayerCurrent; // Current layer, 0..31 (we currently only use 0..1) + int NavLayerCurrentMask; // = (1 << NavLayerCurrent) used by ItemAdd prior to clipping. + int NavLayerActiveMask; // Which layer have been written to (result from previous frame) + int NavLayerActiveMaskNext; // Which layer have been written to (buffer for current frame) + ImGuiID NavFocusScopeIdCurrent; // Current focus scope ID while appending + bool NavHideHighlightOneFrame; + bool NavHasScroll; // Set when scrolling can be used (ScrollMax > 0.0f) + + // Miscellaneous + bool MenuBarAppending; // FIXME: Remove this + ImVec2 MenuBarOffset; // MenuBarOffset.x is sort of equivalent of a per-layer CursorPos.x, saved/restored as we switch to the menu bar. The only situation when MenuBarOffset.y is > 0 if when (SafeAreaPadding.y > FramePadding.y), often used on TVs. + ImGuiMenuColumns MenuColumns; // Simplified columns storage for menu items measurement + int TreeDepth; // Current tree depth. + ImU32 TreeJumpToParentOnPopMask; // Store a copy of !g.NavIdIsAlive for TreeDepth 0..31.. Could be turned into a ImU64 if necessary. + ImVector ChildWindows; + ImGuiStorage* StateStorage; // Current persistent per-window storage (store e.g. tree node open/close state) + ImGuiColumns* CurrentColumns; // Current columns set + ImGuiLayoutType LayoutType; + ImGuiLayoutType ParentLayoutType; // Layout type of parent window at the time of Begin() + int FocusCounterRegular; // (Legacy Focus/Tabbing system) Sequential counter, start at -1 and increase as assigned via FocusableItemRegister() (FIXME-NAV: Needs redesign) + int FocusCounterTabStop; // (Legacy Focus/Tabbing system) Same, but only count widgets which you can Tab through. + + // Local parameters stacks + // We store the current settings outside of the vectors to increase memory locality (reduce cache misses). The vectors are rarely modified. Also it allows us to not heap allocate for short-lived windows which are not using those settings. + ImGuiItemFlags ItemFlags; // == ItemFlagsStack.back() [empty == ImGuiItemFlags_Default] + float ItemWidth; // == ItemWidthStack.back(). 0.0: default, >0.0: width in pixels, <0.0: align xx pixels to the right of window + float TextWrapPos; // == TextWrapPosStack.back() [empty == -1.0f] + ImVectorItemFlagsStack; + ImVector ItemWidthStack; + ImVector TextWrapPosStack; + ImVectorGroupStack; + short StackSizesBackup[6]; // Store size of various stacks for asserting + + ImGuiWindowTempData() + { + CursorPos = CursorPosPrevLine = CursorStartPos = CursorMaxPos = ImVec2(0.0f, 0.0f); + CurrLineSize = PrevLineSize = ImVec2(0.0f, 0.0f); + CurrLineTextBaseOffset = PrevLineTextBaseOffset = 0.0f; + Indent = ImVec1(0.0f); + ColumnsOffset = ImVec1(0.0f); + GroupOffset = ImVec1(0.0f); + + LastItemId = 0; + LastItemStatusFlags = ImGuiItemStatusFlags_None; + LastItemRect = LastItemDisplayRect = ImRect(); + + NavLayerActiveMask = NavLayerActiveMaskNext = 0x00; + NavLayerCurrent = ImGuiNavLayer_Main; + NavLayerCurrentMask = (1 << ImGuiNavLayer_Main); + NavFocusScopeIdCurrent = 0; + NavHideHighlightOneFrame = false; + NavHasScroll = false; + + MenuBarAppending = false; + MenuBarOffset = ImVec2(0.0f, 0.0f); + TreeDepth = 0; + TreeJumpToParentOnPopMask = 0x00; + StateStorage = NULL; + CurrentColumns = NULL; + LayoutType = ParentLayoutType = ImGuiLayoutType_Vertical; + FocusCounterRegular = FocusCounterTabStop = -1; + + ItemFlags = ImGuiItemFlags_Default_; + ItemWidth = 0.0f; + TextWrapPos = -1.0f; + memset(StackSizesBackup, 0, sizeof(StackSizesBackup)); + } +}; + +// Storage for one window +struct IMGUI_API ImGuiWindow +{ + char* Name; // Window name, owned by the window. + ImGuiID ID; // == ImHashStr(Name) + ImGuiWindowFlags Flags, FlagsPreviousFrame; // See enum ImGuiWindowFlags_ + ImGuiWindowClass WindowClass; // Advanced users only. Set with SetNextWindowClass() + ImGuiViewportP* Viewport; // Always set in Begin(), only inactive windows may have a NULL value here + ImGuiID ViewportId; // We backup the viewport id (since the viewport may disappear or never be created if the window is inactive) + ImVec2 ViewportPos; // We backup the viewport position (since the viewport may disappear or never be created if the window is inactive) + int ViewportAllowPlatformMonitorExtend; // Reset to -1 every frame (index is guaranteed to be valid between NewFrame..EndFrame), only used in the Appearing frame of a tooltip/popup to enforce clamping to a given monitor + ImVec2 Pos; // Position (always rounded-up to nearest pixel) + ImVec2 Size; // Current size (==SizeFull or collapsed title bar size) + ImVec2 SizeFull; // Size when non collapsed + ImVec2 ContentSize; // Size of contents/scrollable client area (calculated from the extents reach of the cursor) from previous frame. Does not include window decoration or window padding. + ImVec2 ContentSizeExplicit; // Size of contents/scrollable client area explicitly request by the user via SetNextWindowContentSize(). + ImVec2 WindowPadding; // Window padding at the time of Begin(). + float WindowRounding; // Window rounding at the time of Begin(). + float WindowBorderSize; // Window border size at the time of Begin(). + int NameBufLen; // Size of buffer storing Name. May be larger than strlen(Name)! + ImGuiID MoveId; // == window->GetID("#MOVE") + ImGuiID ChildId; // ID of corresponding item in parent window (for navigation to return from child window to parent window) + ImVec2 Scroll; + ImVec2 ScrollMax; + ImVec2 ScrollTarget; // target scroll position. stored as cursor position with scrolling canceled out, so the highest point is always 0.0f. (FLT_MAX for no change) + ImVec2 ScrollTargetCenterRatio; // 0.0f = scroll so that target position is at top, 0.5f = scroll so that target position is centered + ImVec2 ScrollbarSizes; // Size taken by each scrollbars on their smaller axis. Pay attention! ScrollbarSizes.x == width of the vertical scrollbar, ScrollbarSizes.y = height of the horizontal scrollbar. + bool ScrollbarX, ScrollbarY; // Are scrollbars visible? + bool ViewportOwned; + bool Active; // Set to true on Begin(), unless Collapsed + bool WasActive; + bool WriteAccessed; // Set to true when any widget access the current window + bool Collapsed; // Set when collapsing window to become only title-bar + bool WantCollapseToggle; + bool SkipItems; // Set when items can safely be all clipped (e.g. window not visible or collapsed) + bool Appearing; // Set during the frame where the window is appearing (or re-appearing) + bool Hidden; // Do not display (== (HiddenFrames*** > 0)) + bool IsFallbackWindow; // Set on the "Debug##Default" window. + bool HasCloseButton; // Set when the window has a close button (p_open != NULL) + signed char ResizeBorderHeld; // Current border being held for resize (-1: none, otherwise 0-3) + short BeginCount; // Number of Begin() during the current frame (generally 0 or 1, 1+ if appending via multiple Begin/End pairs) + short BeginOrderWithinParent; // Order within immediate parent window, if we are a child window. Otherwise 0. + short BeginOrderWithinContext; // Order within entire imgui context. This is mostly used for debugging submission order related issues. + ImGuiID PopupId; // ID in the popup stack when this window is used as a popup/menu (because we use generic Name/ID for recycling) + ImS8 AutoFitFramesX, AutoFitFramesY; + ImS8 AutoFitChildAxises; + bool AutoFitOnlyGrows; + ImGuiDir AutoPosLastDirection; + int HiddenFramesCanSkipItems; // Hide the window for N frames + int HiddenFramesCannotSkipItems; // Hide the window for N frames while allowing items to be submitted so we can measure their size + ImGuiCond SetWindowPosAllowFlags; // store acceptable condition flags for SetNextWindowPos() use. + ImGuiCond SetWindowSizeAllowFlags; // store acceptable condition flags for SetNextWindowSize() use. + ImGuiCond SetWindowCollapsedAllowFlags; // store acceptable condition flags for SetNextWindowCollapsed() use. + ImGuiCond SetWindowDockAllowFlags; // store acceptable condition flags for SetNextWindowDock() use. + ImVec2 SetWindowPosVal; // store window position when using a non-zero Pivot (position set needs to be processed when we know the window size) + ImVec2 SetWindowPosPivot; // store window pivot for positioning. ImVec2(0,0) when positioning from top-left corner; ImVec2(0.5f,0.5f) for centering; ImVec2(1,1) for bottom right. + + ImVector IDStack; // ID stack. ID are hashes seeded with the value at the top of the stack. (In theory this should be in the TempData structure) + ImGuiWindowTempData DC; // Temporary per-window data, reset at the beginning of the frame. This used to be called ImGuiDrawContext, hence the "DC" variable name. + + // The best way to understand what those rectangles are is to use the 'Metrics -> Tools -> Show windows rectangles' viewer. + // The main 'OuterRect', omitted as a field, is window->Rect(). + ImRect OuterRectClipped; // == Window->Rect() just after setup in Begin(). == window->Rect() for root window. + ImRect InnerRect; // Inner rectangle (omit title bar, menu bar, scroll bar) + ImRect InnerClipRect; // == InnerRect shrunk by WindowPadding*0.5f on each side, clipped within viewport or parent clip rect. + ImRect WorkRect; // Cover the whole scrolling region, shrunk by WindowPadding*1.0f on each side. This is meant to replace ContentRegionRect over time (from 1.71+ onward). + ImRect ClipRect; // Current clipping/scissoring rectangle, evolve as we are using PushClipRect(), etc. == DrawList->clip_rect_stack.back(). + ImRect ContentRegionRect; // FIXME: This is currently confusing/misleading. It is essentially WorkRect but not handling of scrolling. We currently rely on it as right/bottom aligned sizing operation need some size to rely on. + ImVec2ih HitTestHoleSize, HitTestHoleOffset; + + int LastFrameActive; // Last frame number the window was Active. + int LastFrameJustFocused; // Last frame number the window was made Focused. + float LastTimeActive; // Last timestamp the window was Active (using float as we don't need high precision there) + float ItemWidthDefault; + ImGuiStorage StateStorage; + ImVector ColumnsStorage; + float FontWindowScale; // User scale multiplier per-window, via SetWindowFontScale() + float FontDpiScale; + int SettingsOffset; // Offset into SettingsWindows[] (offsets are always valid as we only grow the array from the back) + + ImDrawList* DrawList; // == &DrawListInst (for backward compatibility reason with code using imgui_internal.h we keep this a pointer) + ImDrawList DrawListInst; + ImGuiWindow* ParentWindow; // If we are a child _or_ popup window, this is pointing to our parent. Otherwise NULL. + ImGuiWindow* RootWindow; // Point to ourself or first ancestor that is not a child window. + ImGuiWindow* RootWindowDockStop; // Point to ourself or first ancestor that is not a child window. Doesn't cross through dock nodes. We use this so IsWindowFocused() can behave consistently regardless of docking state. + ImGuiWindow* RootWindowForTitleBarHighlight; // Point to ourself or first ancestor which will display TitleBgActive color when this window is active. + ImGuiWindow* RootWindowForNav; // Point to ourself or first ancestor which doesn't have the NavFlattened flag. + + ImGuiWindow* NavLastChildNavWindow; // When going to the menu bar, we remember the child window we came from. (This could probably be made implicit if we kept g.Windows sorted by last focused including child window.) + ImGuiID NavLastIds[ImGuiNavLayer_COUNT]; // Last known NavId for this window, per layer (0/1) + ImRect NavRectRel[ImGuiNavLayer_COUNT]; // Reference rectangle, in window relative space + + bool MemoryCompacted; // Set when window extraneous data have been garbage collected + int MemoryDrawListIdxCapacity; // Backup of last idx/vtx count, so when waking up the window we can preallocate and avoid iterative alloc/copy + int MemoryDrawListVtxCapacity; + + // Docking + ImGuiDockNode* DockNode; // Which node are we docked into. Important: Prefer testing DockIsActive in many cases as this will still be set when the dock node is hidden. + ImGuiDockNode* DockNodeAsHost; // Which node are we owning (for parent windows) + ImGuiID DockId; // Backup of last valid DockNode->ID, so single window remember their dock node id even when they are not bound any more + ImGuiItemStatusFlags DockTabItemStatusFlags; + ImRect DockTabItemRect; + short DockOrder; // Order of the last time the window was visible within its DockNode. This is used to reorder windows that are reappearing on the same frame. Same value between windows that were active and windows that were none are possible. + bool DockIsActive :1; // When docking artifacts are actually visible. When this is set, DockNode is guaranteed to be != NULL. ~~ (DockNode != NULL) && (DockNode->Windows.Size > 1). + bool DockTabIsVisible :1; // Is our window visible this frame? ~~ is the corresponding tab selected? + bool DockTabWantClose :1; + +public: + ImGuiWindow(ImGuiContext* context, const char* name); + ~ImGuiWindow(); + + ImGuiID GetID(const char* str, const char* str_end = NULL); + ImGuiID GetID(const void* ptr); + ImGuiID GetID(int n); + ImGuiID GetIDNoKeepAlive(const char* str, const char* str_end = NULL); + ImGuiID GetIDNoKeepAlive(const void* ptr); + ImGuiID GetIDNoKeepAlive(int n); + ImGuiID GetIDFromRectangle(const ImRect& r_abs); + + // We don't use g.FontSize because the window may be != g.CurrentWidow. + ImRect Rect() const { return ImRect(Pos.x, Pos.y, Pos.x+Size.x, Pos.y+Size.y); } + float CalcFontSize() const { ImGuiContext& g = *GImGui; float scale = g.FontBaseSize * FontWindowScale * FontDpiScale; if (ParentWindow) scale *= ParentWindow->FontWindowScale; return scale; } + float TitleBarHeight() const { ImGuiContext& g = *GImGui; return (Flags & ImGuiWindowFlags_NoTitleBar) ? 0.0f : CalcFontSize() + g.Style.FramePadding.y * 2.0f; } + ImRect TitleBarRect() const { return ImRect(Pos, ImVec2(Pos.x + SizeFull.x, Pos.y + TitleBarHeight())); } + float MenuBarHeight() const { ImGuiContext& g = *GImGui; return (Flags & ImGuiWindowFlags_MenuBar) ? DC.MenuBarOffset.y + CalcFontSize() + g.Style.FramePadding.y * 2.0f : 0.0f; } + ImRect MenuBarRect() const { float y1 = Pos.y + TitleBarHeight(); return ImRect(Pos.x, y1, Pos.x + SizeFull.x, y1 + MenuBarHeight()); } +}; + +// Backup and restore just enough data to be able to use IsItemHovered() on item A after another B in the same window has overwritten the data. +struct ImGuiItemHoveredDataBackup +{ + ImGuiID LastItemId; + ImGuiItemStatusFlags LastItemStatusFlags; + ImRect LastItemRect; + ImRect LastItemDisplayRect; + + ImGuiItemHoveredDataBackup() { Backup(); } + void Backup() { ImGuiWindow* window = GImGui->CurrentWindow; LastItemId = window->DC.LastItemId; LastItemStatusFlags = window->DC.LastItemStatusFlags; LastItemRect = window->DC.LastItemRect; LastItemDisplayRect = window->DC.LastItemDisplayRect; } + void Restore() const { ImGuiWindow* window = GImGui->CurrentWindow; window->DC.LastItemId = LastItemId; window->DC.LastItemStatusFlags = LastItemStatusFlags; window->DC.LastItemRect = LastItemRect; window->DC.LastItemDisplayRect = LastItemDisplayRect; } +}; + +//----------------------------------------------------------------------------- +// [SECTION] Tab bar, Tab item support +//----------------------------------------------------------------------------- + +// Extend ImGuiTabBarFlags_ +enum ImGuiTabBarFlagsPrivate_ +{ + ImGuiTabBarFlags_DockNode = 1 << 20, // Part of a dock node [we don't use this in the master branch but it facilitate branch syncing to keep this around] + ImGuiTabBarFlags_IsFocused = 1 << 21, + ImGuiTabBarFlags_SaveSettings = 1 << 22 // FIXME: Settings are handled by the docking system, this only request the tab bar to mark settings dirty when reordering tabs +}; + +// Extend ImGuiTabItemFlags_ +enum ImGuiTabItemFlagsPrivate_ +{ + ImGuiTabItemFlags_NoCloseButton = 1 << 20, // Track whether p_open was set or not (we'll need this info on the next frame to recompute ContentWidth during layout) + ImGuiTabItemFlags_Unsorted = 1 << 21, // [Docking] Trailing tabs with the _Unsorted flag will be sorted based on the DockOrder of their Window. + ImGuiTabItemFlags_Preview = 1 << 22 // [Docking] Display tab shape for docking preview (height is adjusted slightly to compensate for the yet missing tab bar) +}; + +// Storage for one active tab item (sizeof() 32~40 bytes) +struct ImGuiTabItem +{ + ImGuiID ID; + ImGuiTabItemFlags Flags; + ImGuiWindow* Window; // When TabItem is part of a DockNode's TabBar, we hold on to a window. + int LastFrameVisible; + int LastFrameSelected; // This allows us to infer an ordered list of the last activated tabs with little maintenance + int NameOffset; // When Window==NULL, offset to name within parent ImGuiTabBar::TabsNames + float Offset; // Position relative to beginning of tab + float Width; // Width currently displayed + float ContentWidth; // Width of actual contents, stored during BeginTabItem() call + + ImGuiTabItem() { ID = 0; Flags = ImGuiTabItemFlags_None; Window = NULL; LastFrameVisible = LastFrameSelected = -1; NameOffset = -1; Offset = Width = ContentWidth = 0.0f; } +}; + +// Storage for a tab bar (sizeof() 92~96 bytes) +struct ImGuiTabBar +{ + ImVector Tabs; + ImGuiID ID; // Zero for tab-bars used by docking + ImGuiID SelectedTabId; // Selected tab/window + ImGuiID NextSelectedTabId; + ImGuiID VisibleTabId; // Can occasionally be != SelectedTabId (e.g. when previewing contents for CTRL+TAB preview) + int CurrFrameVisible; + int PrevFrameVisible; + ImRect BarRect; + float LastTabContentHeight; // Record the height of contents submitted below the tab bar + float OffsetMax; // Distance from BarRect.Min.x, locked during layout + float OffsetMaxIdeal; // Ideal offset if all tabs were visible and not clipped + float OffsetNextTab; // Distance from BarRect.Min.x, incremented with each BeginTabItem() call, not used if ImGuiTabBarFlags_Reorderable if set. + float ScrollingAnim; + float ScrollingTarget; + float ScrollingTargetDistToVisibility; + float ScrollingSpeed; + ImGuiTabBarFlags Flags; + ImGuiID ReorderRequestTabId; + ImS8 ReorderRequestDir; + bool WantLayout; + bool VisibleTabWasSubmitted; + short LastTabItemIdx; // For BeginTabItem()/EndTabItem() + ImVec2 FramePadding; // style.FramePadding locked at the time of BeginTabBar() + ImGuiTextBuffer TabsNames; // For non-docking tab bar we re-append names in a contiguous buffer. + + ImGuiTabBar(); + int GetTabOrder(const ImGuiTabItem* tab) const { return Tabs.index_from_ptr(tab); } + const char* GetTabName(const ImGuiTabItem* tab) const + { + if (tab->Window) + return tab->Window->Name; + IM_ASSERT(tab->NameOffset != -1 && tab->NameOffset < TabsNames.Buf.Size); + return TabsNames.Buf.Data + tab->NameOffset; + } +}; + +//----------------------------------------------------------------------------- +// [SECTION] Table support +//----------------------------------------------------------------------------- + +#ifdef IMGUI_HAS_TABLE +// +#endif // #ifdef IMGUI_HAS_TABLE + +//----------------------------------------------------------------------------- +// [SECTION] Internal API +// No guarantee of forward compatibility here! +//----------------------------------------------------------------------------- + +namespace ImGui +{ + // Windows + // We should always have a CurrentWindow in the stack (there is an implicit "Debug" window) + // If this ever crash because g.CurrentWindow is NULL it means that either + // - ImGui::NewFrame() has never been called, which is illegal. + // - You are calling ImGui functions after ImGui::EndFrame()/ImGui::Render() and before the next ImGui::NewFrame(), which is also illegal. + inline ImGuiWindow* GetCurrentWindowRead() { ImGuiContext& g = *GImGui; return g.CurrentWindow; } + inline ImGuiWindow* GetCurrentWindow() { ImGuiContext& g = *GImGui; g.CurrentWindow->WriteAccessed = true; return g.CurrentWindow; } + IMGUI_API ImGuiWindow* FindWindowByID(ImGuiID id); + IMGUI_API ImGuiWindow* FindWindowByName(const char* name); + IMGUI_API void UpdateWindowParentAndRootLinks(ImGuiWindow* window, ImGuiWindowFlags flags, ImGuiWindow* parent_window); + IMGUI_API ImVec2 CalcWindowExpectedSize(ImGuiWindow* window); + IMGUI_API bool IsWindowChildOf(ImGuiWindow* window, ImGuiWindow* potential_parent); + IMGUI_API bool IsWindowNavFocusable(ImGuiWindow* window); + IMGUI_API ImRect GetWindowAllowedExtentRect(ImGuiWindow* window); + IMGUI_API void SetWindowPos(ImGuiWindow* window, const ImVec2& pos, ImGuiCond cond = 0); + IMGUI_API void SetWindowSize(ImGuiWindow* window, const ImVec2& size, ImGuiCond cond = 0); + IMGUI_API void SetWindowCollapsed(ImGuiWindow* window, bool collapsed, ImGuiCond cond = 0); + IMGUI_API void SetWindowHitTestHole(ImGuiWindow* window, const ImVec2& pos, const ImVec2& size); + + // Windows: Display Order and Focus Order + IMGUI_API void FocusWindow(ImGuiWindow* window); + IMGUI_API void FocusTopMostWindowUnderOne(ImGuiWindow* under_this_window, ImGuiWindow* ignore_window); + IMGUI_API void BringWindowToFocusFront(ImGuiWindow* window); + IMGUI_API void BringWindowToDisplayFront(ImGuiWindow* window); + IMGUI_API void BringWindowToDisplayBack(ImGuiWindow* window); + + // Fonts, drawing + IMGUI_API void SetCurrentFont(ImFont* font); + inline ImFont* GetDefaultFont() { ImGuiContext& g = *GImGui; return g.IO.FontDefault ? g.IO.FontDefault : g.IO.Fonts->Fonts[0]; } + inline ImDrawList* GetForegroundDrawList(ImGuiWindow* window) { return GetForegroundDrawList(window->Viewport); } + + // Init + IMGUI_API void Initialize(ImGuiContext* context); + IMGUI_API void Shutdown(ImGuiContext* context); // Since 1.60 this is a _private_ function. You can call DestroyContext() to destroy the context created by CreateContext(). + + // NewFrame + IMGUI_API void UpdateHoveredWindowAndCaptureFlags(); + IMGUI_API void StartMouseMovingWindow(ImGuiWindow* window); + IMGUI_API void StartMouseMovingWindowOrNode(ImGuiWindow* window, ImGuiDockNode* node, bool undock_floating_node); + IMGUI_API void UpdateMouseMovingWindowNewFrame(); + IMGUI_API void UpdateMouseMovingWindowEndFrame(); + + // Viewports + IMGUI_API void TranslateWindowsInViewport(ImGuiViewportP* viewport, const ImVec2& old_pos, const ImVec2& new_pos); + IMGUI_API void ScaleWindowsInViewport(ImGuiViewportP* viewport, float scale); + IMGUI_API void DestroyPlatformWindow(ImGuiViewportP* viewport); + IMGUI_API void ShowViewportThumbnails(); + + // Settings + IMGUI_API void MarkIniSettingsDirty(); + IMGUI_API void MarkIniSettingsDirty(ImGuiWindow* window); + IMGUI_API void ClearIniSettings(); + IMGUI_API ImGuiWindowSettings* CreateNewWindowSettings(const char* name); + IMGUI_API ImGuiWindowSettings* FindWindowSettings(ImGuiID id); + IMGUI_API ImGuiWindowSettings* FindOrCreateWindowSettings(const char* name); + IMGUI_API ImGuiSettingsHandler* FindSettingsHandler(const char* type_name); + + // Scrolling + IMGUI_API void SetNextWindowScroll(const ImVec2& scroll); // Use -1.0f on one axis to leave as-is + IMGUI_API void SetScrollX(ImGuiWindow* window, float new_scroll_x); + IMGUI_API void SetScrollY(ImGuiWindow* window, float new_scroll_y); + IMGUI_API void SetScrollFromPosX(ImGuiWindow* window, float local_x, float center_x_ratio = 0.5f); + IMGUI_API void SetScrollFromPosY(ImGuiWindow* window, float local_y, float center_y_ratio = 0.5f); + IMGUI_API ImVec2 ScrollToBringRectIntoView(ImGuiWindow* window, const ImRect& item_rect); + + // Basic Accessors + inline ImGuiID GetItemID() { ImGuiContext& g = *GImGui; return g.CurrentWindow->DC.LastItemId; } // Get ID of last item (~~ often same ImGui::GetID(label) beforehand) + inline ImGuiItemStatusFlags GetItemStatusFlags() { ImGuiContext& g = *GImGui; return g.CurrentWindow->DC.LastItemStatusFlags; } + inline ImGuiID GetActiveID() { ImGuiContext& g = *GImGui; return g.ActiveId; } + inline ImGuiID GetFocusID() { ImGuiContext& g = *GImGui; return g.NavId; } + IMGUI_API void SetActiveID(ImGuiID id, ImGuiWindow* window); + IMGUI_API void SetFocusID(ImGuiID id, ImGuiWindow* window); + IMGUI_API void ClearActiveID(); + IMGUI_API ImGuiID GetHoveredID(); + IMGUI_API void SetHoveredID(ImGuiID id); + IMGUI_API void KeepAliveID(ImGuiID id); + IMGUI_API void MarkItemEdited(ImGuiID id); // Mark data associated to given item as "edited", used by IsItemDeactivatedAfterEdit() function. + IMGUI_API void PushOverrideID(ImGuiID id); // Push given value as-is at the top of the ID stack (whereas PushID combines old and new hashes) + + // Basic Helpers for widget code + IMGUI_API void ItemSize(const ImVec2& size, float text_baseline_y = -1.0f); + IMGUI_API void ItemSize(const ImRect& bb, float text_baseline_y = -1.0f); + IMGUI_API bool ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb = NULL); + IMGUI_API bool ItemHoverable(const ImRect& bb, ImGuiID id); + IMGUI_API bool IsClippedEx(const ImRect& bb, ImGuiID id, bool clip_even_when_logged); + IMGUI_API bool FocusableItemRegister(ImGuiWindow* window, ImGuiID id); // Return true if focus is requested + IMGUI_API void FocusableItemUnregister(ImGuiWindow* window); + IMGUI_API ImVec2 CalcItemSize(ImVec2 size, float default_w, float default_h); + IMGUI_API float CalcWrapWidthForPos(const ImVec2& pos, float wrap_pos_x); + IMGUI_API void PushMultiItemsWidths(int components, float width_full); + IMGUI_API void PushItemFlag(ImGuiItemFlags option, bool enabled); + IMGUI_API void PopItemFlag(); + IMGUI_API bool IsItemToggledSelection(); // Was the last item selection toggled? (after Selectable(), TreeNode() etc. We only returns toggle _event_ in order to handle clipping correctly) + IMGUI_API ImVec2 GetContentRegionMaxAbs(); + IMGUI_API void ShrinkWidths(ImGuiShrinkWidthItem* items, int count, float width_excess); + + // Logging/Capture + IMGUI_API void LogBegin(ImGuiLogType type, int auto_open_depth); // -> BeginCapture() when we design v2 api, for now stay under the radar by using the old name. + IMGUI_API void LogToBuffer(int auto_open_depth = -1); // Start logging/capturing to internal buffer + + // Popups, Modals, Tooltips + IMGUI_API bool BeginChildEx(const char* name, ImGuiID id, const ImVec2& size_arg, bool border, ImGuiWindowFlags flags); + IMGUI_API void OpenPopupEx(ImGuiID id); + IMGUI_API void ClosePopupToLevel(int remaining, bool restore_focus_to_window_under_popup); + IMGUI_API void ClosePopupsOverWindow(ImGuiWindow* ref_window, bool restore_focus_to_window_under_popup); + IMGUI_API bool IsPopupOpen(ImGuiID id); // Test for id at current popup stack level (currently begin-ed into); this doesn't scan the whole popup stack! + IMGUI_API bool BeginPopupEx(ImGuiID id, ImGuiWindowFlags extra_flags); + IMGUI_API void BeginTooltipEx(ImGuiWindowFlags extra_flags, ImGuiTooltipFlags tooltip_flags); + IMGUI_API ImGuiWindow* GetTopMostPopupModal(); + IMGUI_API ImVec2 FindBestWindowPosForPopup(ImGuiWindow* window); + IMGUI_API ImVec2 FindBestWindowPosForPopupEx(const ImVec2& ref_pos, const ImVec2& size, ImGuiDir* last_dir, const ImRect& r_outer, const ImRect& r_avoid, ImGuiPopupPositionPolicy policy = ImGuiPopupPositionPolicy_Default); + + // Gamepad/Keyboard Navigation + IMGUI_API void NavInitWindow(ImGuiWindow* window, bool force_reinit); + IMGUI_API bool NavMoveRequestButNoResultYet(); + IMGUI_API void NavMoveRequestCancel(); + IMGUI_API void NavMoveRequestForward(ImGuiDir move_dir, ImGuiDir clip_dir, const ImRect& bb_rel, ImGuiNavMoveFlags move_flags); + IMGUI_API void NavMoveRequestTryWrapping(ImGuiWindow* window, ImGuiNavMoveFlags move_flags); + IMGUI_API float GetNavInputAmount(ImGuiNavInput n, ImGuiInputReadMode mode); + IMGUI_API ImVec2 GetNavInputAmount2d(ImGuiNavDirSourceFlags dir_sources, ImGuiInputReadMode mode, float slow_factor = 0.0f, float fast_factor = 0.0f); + IMGUI_API int CalcTypematicRepeatAmount(float t0, float t1, float repeat_delay, float repeat_rate); + IMGUI_API void ActivateItem(ImGuiID id); // Remotely activate a button, checkbox, tree node etc. given its unique ID. activation is queued and processed on the next frame when the item is encountered again. + IMGUI_API void SetNavID(ImGuiID id, int nav_layer, ImGuiID focus_scope_id); + IMGUI_API void SetNavIDWithRectRel(ImGuiID id, int nav_layer, ImGuiID focus_scope_id, const ImRect& rect_rel); + + // Focus Scope (WIP) + // This is generally used to identify a selection set (multiple of which may be in the same window), as selection + // patterns generally need to react (e.g. clear selection) when landing on an item of the set. + IMGUI_API void PushFocusScope(ImGuiID id); + IMGUI_API void PopFocusScope(); + inline ImGuiID GetFocusScopeID() { ImGuiContext& g = *GImGui; return g.NavFocusScopeId; } + + // Inputs + // FIXME: Eventually we should aim to move e.g. IsActiveIdUsingKey() into IsKeyXXX functions. + inline bool IsActiveIdUsingNavDir(ImGuiDir dir) { ImGuiContext& g = *GImGui; return (g.ActiveIdUsingNavDirMask & (1 << dir)) != 0; } + inline bool IsActiveIdUsingNavInput(ImGuiNavInput input) { ImGuiContext& g = *GImGui; return (g.ActiveIdUsingNavInputMask & (1 << input)) != 0; } + inline bool IsActiveIdUsingKey(ImGuiKey key) { ImGuiContext& g = *GImGui; IM_ASSERT(key < 64); return (g.ActiveIdUsingKeyInputMask & ((ImU64)1 << key)) != 0; } + IMGUI_API bool IsMouseDragPastThreshold(ImGuiMouseButton button, float lock_threshold = -1.0f); + inline bool IsKeyPressedMap(ImGuiKey key, bool repeat = true) { ImGuiContext& g = *GImGui; const int key_index = g.IO.KeyMap[key]; return (key_index >= 0) ? IsKeyPressed(key_index, repeat) : false; } + inline bool IsNavInputDown(ImGuiNavInput n) { ImGuiContext& g = *GImGui; return g.IO.NavInputs[n] > 0.0f; } + inline bool IsNavInputTest(ImGuiNavInput n, ImGuiInputReadMode rm) { return (GetNavInputAmount(n, rm) > 0.0f); } + IMGUI_API ImGuiKeyModFlags GetMergedKeyModFlags(); + + // Docking + // (some functions are only declared in imgui.cpp, see Docking section) + IMGUI_API void DockContextInitialize(ImGuiContext* ctx); + IMGUI_API void DockContextShutdown(ImGuiContext* ctx); + IMGUI_API void DockContextClearNodes(ImGuiContext* ctx, ImGuiID root_id, bool clear_settings_refs); // Use root_id==0 to clear all + IMGUI_API void DockContextRebuildNodes(ImGuiContext* ctx); + IMGUI_API void DockContextUpdateUndocking(ImGuiContext* ctx); + IMGUI_API void DockContextUpdateDocking(ImGuiContext* ctx); + IMGUI_API ImGuiID DockContextGenNodeID(ImGuiContext* ctx); + IMGUI_API void DockContextQueueDock(ImGuiContext* ctx, ImGuiWindow* target, ImGuiDockNode* target_node, ImGuiWindow* payload, ImGuiDir split_dir, float split_ratio, bool split_outer); + IMGUI_API void DockContextQueueUndockWindow(ImGuiContext* ctx, ImGuiWindow* window); + IMGUI_API void DockContextQueueUndockNode(ImGuiContext* ctx, ImGuiDockNode* node); + IMGUI_API bool DockContextCalcDropPosForDocking(ImGuiWindow* target, ImGuiDockNode* target_node, ImGuiWindow* payload, ImGuiDir split_dir, bool split_outer, ImVec2* out_pos); + inline ImGuiDockNode* DockNodeGetRootNode(ImGuiDockNode* node) { while (node->ParentNode) node = node->ParentNode; return node; } + inline int DockNodeGetDepth(const ImGuiDockNode* node) { int depth = 0; while (node->ParentNode) { node = node->ParentNode; depth++; } return depth; } + inline ImGuiDockNode* GetWindowDockNode() { ImGuiContext& g = *GImGui; return g.CurrentWindow->DockNode; } + IMGUI_API bool GetWindowAlwaysWantOwnTabBar(ImGuiWindow* window); + IMGUI_API void BeginDocked(ImGuiWindow* window, bool* p_open); + IMGUI_API void BeginDockableDragDropSource(ImGuiWindow* window); + IMGUI_API void BeginDockableDragDropTarget(ImGuiWindow* window); + IMGUI_API void SetWindowDock(ImGuiWindow* window, ImGuiID dock_id, ImGuiCond cond); + + // Docking - Builder function needs to be generally called before the node is used/submitted. + // - The DockBuilderXXX functions are designed to _eventually_ become a public API, but it is too early to expose it and guarantee stability. + // - Do not hold on ImGuiDockNode* pointers! They may be invalidated by any split/merge/remove operation and every frame. + // - To create a DockSpace() node, make sure to set the ImGuiDockNodeFlags_DockSpace flag when calling DockBuilderAddNode(). + // You can create dockspace nodes (attached to a window) _or_ floating nodes (carry its own window) with this API. + // - DockBuilderSplitNode() create 2 child nodes within 1 node. The initial node becomes a parent node. + // - If you intend to split the node immediately after creation using DockBuilderSplitNode(), make sure + // to call DockBuilderSetNodeSize() beforehand. If you don't, the resulting split sizes may not be reliable. + // - Call DockBuilderFinish() after you are done. + IMGUI_API void DockBuilderDockWindow(const char* window_name, ImGuiID node_id); + IMGUI_API ImGuiDockNode*DockBuilderGetNode(ImGuiID node_id); + inline ImGuiDockNode* DockBuilderGetCentralNode(ImGuiID node_id) { ImGuiDockNode* node = DockBuilderGetNode(node_id); if (!node) return NULL; return DockNodeGetRootNode(node)->CentralNode; } + IMGUI_API ImGuiID DockBuilderAddNode(ImGuiID node_id = 0, ImGuiDockNodeFlags flags = 0); + IMGUI_API void DockBuilderRemoveNode(ImGuiID node_id); // Remove node and all its child, undock all windows + IMGUI_API void DockBuilderRemoveNodeDockedWindows(ImGuiID node_id, bool clear_settings_refs = true); + IMGUI_API void DockBuilderRemoveNodeChildNodes(ImGuiID node_id); // Remove all split/hierarchy. All remaining docked windows will be re-docked to the remaining root node (node_id). + IMGUI_API void DockBuilderSetNodePos(ImGuiID node_id, ImVec2 pos); + IMGUI_API void DockBuilderSetNodeSize(ImGuiID node_id, ImVec2 size); + IMGUI_API ImGuiID DockBuilderSplitNode(ImGuiID node_id, ImGuiDir split_dir, float size_ratio_for_node_at_dir, ImGuiID* out_id_at_dir, ImGuiID* out_id_at_opposite_dir); // Create 2 child nodes in this parent node. + IMGUI_API void DockBuilderCopyDockSpace(ImGuiID src_dockspace_id, ImGuiID dst_dockspace_id, ImVector* in_window_remap_pairs); + IMGUI_API void DockBuilderCopyNode(ImGuiID src_node_id, ImGuiID dst_node_id, ImVector* out_node_remap_pairs); + IMGUI_API void DockBuilderCopyWindowSettings(const char* src_name, const char* dst_name); + IMGUI_API void DockBuilderFinish(ImGuiID node_id); + + // Drag and Drop + IMGUI_API bool BeginDragDropTargetCustom(const ImRect& bb, ImGuiID id); + IMGUI_API void ClearDragDrop(); + IMGUI_API bool IsDragDropPayloadBeingAccepted(); + + // Internal Columns API (this is not exposed because we will encourage transitioning to the Tables API) + IMGUI_API void BeginColumns(const char* str_id, int count, ImGuiColumnsFlags flags = 0); // setup number of columns. use an identifier to distinguish multiple column sets. close with EndColumns(). + IMGUI_API void EndColumns(); // close columns + IMGUI_API void PushColumnClipRect(int column_index); + IMGUI_API void PushColumnsBackground(); + IMGUI_API void PopColumnsBackground(); + IMGUI_API ImGuiID GetColumnsID(const char* str_id, int count); + IMGUI_API ImGuiColumns* FindOrCreateColumns(ImGuiWindow* window, ImGuiID id); + IMGUI_API float GetColumnOffsetFromNorm(const ImGuiColumns* columns, float offset_norm); + IMGUI_API float GetColumnNormFromOffset(const ImGuiColumns* columns, float offset); + + // Tab Bars + IMGUI_API bool BeginTabBarEx(ImGuiTabBar* tab_bar, const ImRect& bb, ImGuiTabBarFlags flags, ImGuiDockNode* dock_node); + IMGUI_API ImGuiTabItem* TabBarFindTabByID(ImGuiTabBar* tab_bar, ImGuiID tab_id); + IMGUI_API ImGuiTabItem* TabBarFindMostRecentlySelectedTabForActiveWindow(ImGuiTabBar* tab_bar); + IMGUI_API void TabBarAddTab(ImGuiTabBar* tab_bar, ImGuiTabItemFlags tab_flags, ImGuiWindow* window); + IMGUI_API void TabBarRemoveTab(ImGuiTabBar* tab_bar, ImGuiID tab_id); + IMGUI_API void TabBarCloseTab(ImGuiTabBar* tab_bar, ImGuiTabItem* tab); + IMGUI_API void TabBarQueueChangeTabOrder(ImGuiTabBar* tab_bar, const ImGuiTabItem* tab, int dir); + IMGUI_API bool TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, ImGuiTabItemFlags flags, ImGuiWindow* docked_window); + IMGUI_API ImVec2 TabItemCalcSize(const char* label, bool has_close_button); + IMGUI_API void TabItemBackground(ImDrawList* draw_list, const ImRect& bb, ImGuiTabItemFlags flags, ImU32 col); + IMGUI_API bool TabItemLabelAndCloseButton(ImDrawList* draw_list, const ImRect& bb, ImGuiTabItemFlags flags, ImVec2 frame_padding, const char* label, ImGuiID tab_id, ImGuiID close_button_id, bool is_contents_visible); + + // Render helpers + // AVOID USING OUTSIDE OF IMGUI.CPP! NOT FOR PUBLIC CONSUMPTION. THOSE FUNCTIONS ARE A MESS. THEIR SIGNATURE AND BEHAVIOR WILL CHANGE, THEY NEED TO BE REFACTORED INTO SOMETHING DECENT. + // NB: All position are in absolute pixels coordinates (we are never using window coordinates internally) + IMGUI_API void RenderText(ImVec2 pos, const char* text, const char* text_end = NULL, bool hide_text_after_hash = true); + IMGUI_API void RenderTextWrapped(ImVec2 pos, const char* text, const char* text_end, float wrap_width); + IMGUI_API void RenderTextClipped(const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_end, const ImVec2* text_size_if_known, const ImVec2& align = ImVec2(0,0), const ImRect* clip_rect = NULL); + IMGUI_API void RenderTextClippedEx(ImDrawList* draw_list, const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_end, const ImVec2* text_size_if_known, const ImVec2& align = ImVec2(0, 0), const ImRect* clip_rect = NULL); + IMGUI_API void RenderTextEllipsis(ImDrawList* draw_list, const ImVec2& pos_min, const ImVec2& pos_max, float clip_max_x, float ellipsis_max_x, const char* text, const char* text_end, const ImVec2* text_size_if_known); + IMGUI_API void RenderFrame(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, bool border = true, float rounding = 0.0f); + IMGUI_API void RenderFrameBorder(ImVec2 p_min, ImVec2 p_max, float rounding = 0.0f); + IMGUI_API void RenderColorRectWithAlphaCheckerboard(ImDrawList* draw_list, ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, float grid_step, ImVec2 grid_off, float rounding = 0.0f, int rounding_corners_flags = ~0); + IMGUI_API void RenderNavHighlight(const ImRect& bb, ImGuiID id, ImGuiNavHighlightFlags flags = ImGuiNavHighlightFlags_TypeDefault); // Navigation highlight + IMGUI_API const char* FindRenderedTextEnd(const char* text, const char* text_end = NULL); // Find the optional ## from which we stop displaying text. + IMGUI_API void LogRenderedText(const ImVec2* ref_pos, const char* text, const char* text_end = NULL); + + // Render helpers (those functions don't access any ImGui state!) + IMGUI_API void RenderArrow(ImDrawList* draw_list, ImVec2 pos, ImU32 col, ImGuiDir dir, float scale = 1.0f); + IMGUI_API void RenderBullet(ImDrawList* draw_list, ImVec2 pos, ImU32 col); + IMGUI_API void RenderCheckMark(ImDrawList* draw_list, ImVec2 pos, ImU32 col, float sz); + IMGUI_API void RenderMouseCursor(ImDrawList* draw_list, ImVec2 pos, float scale, ImGuiMouseCursor mouse_cursor, ImU32 col_fill, ImU32 col_border, ImU32 col_shadow); + IMGUI_API void RenderArrowPointingAt(ImDrawList* draw_list, ImVec2 pos, ImVec2 half_sz, ImGuiDir direction, ImU32 col); + IMGUI_API void RenderArrowDockMenu(ImDrawList* draw_list, ImVec2 p_min, float sz, ImU32 col); + IMGUI_API void RenderRectFilledRangeH(ImDrawList* draw_list, const ImRect& rect, ImU32 col, float x_start_norm, float x_end_norm, float rounding); + IMGUI_API void RenderRectFilledWithHole(ImDrawList* draw_list, ImRect outer, ImRect inner, ImU32 col, float rounding); + +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + // [1.71: 2019/06/07: Updating prototypes of some of the internal functions. Leaving those for reference for a short while] + inline void RenderArrow(ImVec2 pos, ImGuiDir dir, float scale=1.0f) { ImGuiWindow* window = GetCurrentWindow(); RenderArrow(window->DrawList, pos, GetColorU32(ImGuiCol_Text), dir, scale); } + inline void RenderBullet(ImVec2 pos) { ImGuiWindow* window = GetCurrentWindow(); RenderBullet(window->DrawList, pos, GetColorU32(ImGuiCol_Text)); } +#endif + + // Widgets + IMGUI_API void TextEx(const char* text, const char* text_end = NULL, ImGuiTextFlags flags = 0); + IMGUI_API bool ButtonEx(const char* label, const ImVec2& size_arg = ImVec2(0,0), ImGuiButtonFlags flags = 0); + IMGUI_API bool CloseButton(ImGuiID id, const ImVec2& pos); + IMGUI_API bool CollapseButton(ImGuiID id, const ImVec2& pos, ImGuiDockNode* dock_node); + IMGUI_API bool ArrowButtonEx(const char* str_id, ImGuiDir dir, ImVec2 size_arg, ImGuiButtonFlags flags = 0); + IMGUI_API void Scrollbar(ImGuiAxis axis); + IMGUI_API bool ScrollbarEx(const ImRect& bb, ImGuiID id, ImGuiAxis axis, float* p_scroll_v, float avail_v, float contents_v, ImDrawCornerFlags rounding_corners); + IMGUI_API ImRect GetWindowScrollbarRect(ImGuiWindow* window, ImGuiAxis axis); + IMGUI_API ImGuiID GetWindowScrollbarID(ImGuiWindow* window, ImGuiAxis axis); + IMGUI_API ImGuiID GetWindowResizeID(ImGuiWindow* window, int n); // 0..3: corners, 4..7: borders + IMGUI_API void SeparatorEx(ImGuiSeparatorFlags flags); + + // Widgets low-level behaviors + IMGUI_API bool ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool* out_held, ImGuiButtonFlags flags = 0); + IMGUI_API bool DragBehavior(ImGuiID id, ImGuiDataType data_type, void* p_v, float v_speed, const void* p_min, const void* p_max, const char* format, float power, ImGuiDragFlags flags); + IMGUI_API bool SliderBehavior(const ImRect& bb, ImGuiID id, ImGuiDataType data_type, void* p_v, const void* p_min, const void* p_max, const char* format, float power, ImGuiSliderFlags flags, ImRect* out_grab_bb); + IMGUI_API bool SplitterBehavior(const ImRect& bb, ImGuiID id, ImGuiAxis axis, float* size1, float* size2, float min_size1, float min_size2, float hover_extend = 0.0f, float hover_visibility_delay = 0.0f); + IMGUI_API bool TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* label, const char* label_end = NULL); + IMGUI_API bool TreeNodeBehaviorIsOpen(ImGuiID id, ImGuiTreeNodeFlags flags = 0); // Consume previous SetNextItemOpen() data, if any. May return true when logging + IMGUI_API void TreePushOverrideID(ImGuiID id); + + // Template functions are instantiated in imgui_widgets.cpp for a finite number of types. + // To use them externally (for custom widget) you may need an "extern template" statement in your code in order to link to existing instances and silence Clang warnings (see #2036). + // e.g. " extern template IMGUI_API float RoundScalarWithFormatT(const char* format, ImGuiDataType data_type, float v); " + template IMGUI_API bool DragBehaviorT(ImGuiDataType data_type, T* v, float v_speed, T v_min, T v_max, const char* format, float power, ImGuiDragFlags flags); + template IMGUI_API bool SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_type, T* v, T v_min, T v_max, const char* format, float power, ImGuiSliderFlags flags, ImRect* out_grab_bb); + template IMGUI_API float SliderCalcRatioFromValueT(ImGuiDataType data_type, T v, T v_min, T v_max, float power, float linear_zero_pos); + template IMGUI_API T RoundScalarWithFormatT(const char* format, ImGuiDataType data_type, T v); + + // Data type helpers + IMGUI_API const ImGuiDataTypeInfo* DataTypeGetInfo(ImGuiDataType data_type); + IMGUI_API int DataTypeFormatString(char* buf, int buf_size, ImGuiDataType data_type, const void* p_data, const char* format); + IMGUI_API void DataTypeApplyOp(ImGuiDataType data_type, int op, void* output, void* arg_1, const void* arg_2); + IMGUI_API bool DataTypeApplyOpFromText(const char* buf, const char* initial_value_buf, ImGuiDataType data_type, void* p_data, const char* format); + IMGUI_API bool DataTypeClamp(ImGuiDataType data_type, void* p_data, const void* p_min, const void* p_max); + + // InputText + IMGUI_API bool InputTextEx(const char* label, const char* hint, char* buf, int buf_size, const ImVec2& size_arg, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback = NULL, void* user_data = NULL); + IMGUI_API bool TempInputText(const ImRect& bb, ImGuiID id, const char* label, char* buf, int buf_size, ImGuiInputTextFlags flags); + IMGUI_API bool TempInputScalar(const ImRect& bb, ImGuiID id, const char* label, ImGuiDataType data_type, void* p_data, const char* format, const void* p_clamp_min = NULL, const void* p_clamp_max = NULL); + inline bool TempInputIsActive(ImGuiID id) { ImGuiContext& g = *GImGui; return (g.ActiveId == id && g.TempInputId == id); } + inline ImGuiInputTextState* GetInputTextState(ImGuiID id) { ImGuiContext& g = *GImGui; return (g.InputTextState.ID == id) ? &g.InputTextState : NULL; } // Get input text state if active + + // Color + IMGUI_API void ColorTooltip(const char* text, const float* col, ImGuiColorEditFlags flags); + IMGUI_API void ColorEditOptionsPopup(const float* col, ImGuiColorEditFlags flags); + IMGUI_API void ColorPickerOptionsPopup(const float* ref_col, ImGuiColorEditFlags flags); + + // Plot + IMGUI_API int PlotEx(ImGuiPlotType plot_type, const char* label, float (*values_getter)(void* data, int idx), void* data, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, ImVec2 frame_size); + + // Shade functions (write over already created vertices) + IMGUI_API void ShadeVertsLinearColorGradientKeepAlpha(ImDrawList* draw_list, int vert_start_idx, int vert_end_idx, ImVec2 gradient_p0, ImVec2 gradient_p1, ImU32 col0, ImU32 col1); + IMGUI_API void ShadeVertsLinearUV(ImDrawList* draw_list, int vert_start_idx, int vert_end_idx, const ImVec2& a, const ImVec2& b, const ImVec2& uv_a, const ImVec2& uv_b, bool clamp); + + // Garbage collection + IMGUI_API void GcCompactTransientWindowBuffers(ImGuiWindow* window); + IMGUI_API void GcAwakeTransientWindowBuffers(ImGuiWindow* window); + + // Debug Tools + inline void DebugDrawItemRect(ImU32 col = IM_COL32(255,0,0,255)) { ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; GetForegroundDrawList(window)->AddRect(window->DC.LastItemRect.Min, window->DC.LastItemRect.Max, col); } + inline void DebugStartItemPicker() { ImGuiContext& g = *GImGui; g.DebugItemPickerActive = true; } + +} // namespace ImGui + +// ImFontAtlas internals +IMGUI_API bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas); +IMGUI_API void ImFontAtlasBuildInit(ImFontAtlas* atlas); +IMGUI_API void ImFontAtlasBuildSetupFont(ImFontAtlas* atlas, ImFont* font, ImFontConfig* font_config, float ascent, float descent); +IMGUI_API void ImFontAtlasBuildPackCustomRects(ImFontAtlas* atlas, void* stbrp_context_opaque); +IMGUI_API void ImFontAtlasBuildFinish(ImFontAtlas* atlas); +IMGUI_API void ImFontAtlasBuildMultiplyCalcLookupTable(unsigned char out_table[256], float in_multiply_factor); +IMGUI_API void ImFontAtlasBuildMultiplyRectAlpha8(const unsigned char table[256], unsigned char* pixels, int x, int y, int w, int h, int stride); + +//----------------------------------------------------------------------------- +// [SECTION] Test Engine Hooks (imgui_test_engine) +//----------------------------------------------------------------------------- + +//#define IMGUI_ENABLE_TEST_ENGINE +#ifdef IMGUI_ENABLE_TEST_ENGINE +extern void ImGuiTestEngineHook_PreNewFrame(ImGuiContext* ctx); +extern void ImGuiTestEngineHook_PostNewFrame(ImGuiContext* ctx); +extern void ImGuiTestEngineHook_ItemAdd(ImGuiContext* ctx, const ImRect& bb, ImGuiID id); +extern void ImGuiTestEngineHook_ItemInfo(ImGuiContext* ctx, ImGuiID id, const char* label, ImGuiItemStatusFlags flags); +extern void ImGuiTestEngineHook_IdInfo(ImGuiContext* ctx, ImGuiDataType data_type, ImGuiID id, const void* data_id); +extern void ImGuiTestEngineHook_IdInfo(ImGuiContext* ctx, ImGuiDataType data_type, ImGuiID id, const void* data_id, const void* data_id_end); +extern void ImGuiTestEngineHook_Log(ImGuiContext* ctx, const char* fmt, ...); +#define IMGUI_TEST_ENGINE_ITEM_ADD(_BB,_ID) if (g.TestEngineHookItems) ImGuiTestEngineHook_ItemAdd(&g, _BB, _ID) // Register item bounding box +#define IMGUI_TEST_ENGINE_ITEM_INFO(_ID,_LABEL,_FLAGS) if (g.TestEngineHookItems) ImGuiTestEngineHook_ItemInfo(&g, _ID, _LABEL, _FLAGS) // Register item label and status flags (optional) +#define IMGUI_TEST_ENGINE_LOG(_FMT,...) if (g.TestEngineHookItems) ImGuiTestEngineHook_Log(&g, _FMT, __VA_ARGS__) // Custom log entry from user land into test log +#define IMGUI_TEST_ENGINE_ID_INFO(_ID,_TYPE,_DATA) if (g.TestEngineHookIdInfo == id) ImGuiTestEngineHook_IdInfo(&g, _TYPE, _ID, (const void*)(_DATA)); +#define IMGUI_TEST_ENGINE_ID_INFO2(_ID,_TYPE,_DATA,_DATA2) if (g.TestEngineHookIdInfo == id) ImGuiTestEngineHook_IdInfo(&g, _TYPE, _ID, (const void*)(_DATA), (const void*)(_DATA2)); +#else +#define IMGUI_TEST_ENGINE_ITEM_ADD(_BB,_ID) do { } while (0) +#define IMGUI_TEST_ENGINE_ITEM_INFO(_ID,_LABEL,_FLAGS) do { } while (0) +#define IMGUI_TEST_ENGINE_LOG(_FMT,...) do { } while (0) +#define IMGUI_TEST_ENGINE_ID_INFO(_ID,_TYPE,_DATA) do { } while (0) +#define IMGUI_TEST_ENGINE_ID_INFO2(_ID,_TYPE,_DATA,_DATA2) do { } while (0) +#endif + +#if defined(__clang__) +#pragma clang diagnostic pop +#elif defined(__GNUC__) +#pragma GCC diagnostic pop +#endif + +#ifdef _MSC_VER +#pragma warning (pop) +#endif + +#endif // #ifndef IMGUI_DISABLE diff --git a/extern/imgui/src/imgui_stdlib.cpp b/extern/imgui/src/imgui_stdlib.cpp new file mode 100755 index 0000000..4f1ab09 --- /dev/null +++ b/extern/imgui/src/imgui_stdlib.cpp @@ -0,0 +1,77 @@ +// imgui_stdlib.cpp +// Wrappers for C++ standard library (STL) types (std::string, etc.) +// This is also an example of how you may wrap your own similar types. + +// Compatibility: +// - std::string support is only guaranteed to work from C++11. +// If you try to use it pre-C++11, please share your findings (w/ info about compiler/architecture) + +// Changelog: +// - v0.10: Initial version. Added InputText() / InputTextMultiline() calls with std::string + +#include "imgui.h" +#include "imgui_stdlib.h" + +struct InputTextCallback_UserData +{ + std::string* Str; + ImGuiInputTextCallback ChainCallback; + void* ChainCallbackUserData; +}; + +static int InputTextCallback(ImGuiInputTextCallbackData* data) +{ + InputTextCallback_UserData* user_data = (InputTextCallback_UserData*)data->UserData; + if (data->EventFlag == ImGuiInputTextFlags_CallbackResize) + { + // Resize string callback + // If for some reason we refuse the new length (BufTextLen) and/or capacity (BufSize) we need to set them back to what we want. + std::string* str = user_data->Str; + IM_ASSERT(data->Buf == str->c_str()); + str->resize(data->BufTextLen); + data->Buf = (char*)str->c_str(); + } + else if (user_data->ChainCallback) + { + // Forward to user callback, if any + data->UserData = user_data->ChainCallbackUserData; + return user_data->ChainCallback(data); + } + return 0; +} + +bool ImGui::InputText(const char* label, std::string* str, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data) +{ + IM_ASSERT((flags & ImGuiInputTextFlags_CallbackResize) == 0); + flags |= ImGuiInputTextFlags_CallbackResize; + + InputTextCallback_UserData cb_user_data; + cb_user_data.Str = str; + cb_user_data.ChainCallback = callback; + cb_user_data.ChainCallbackUserData = user_data; + return InputText(label, (char*)str->c_str(), str->capacity() + 1, flags, InputTextCallback, &cb_user_data); +} + +bool ImGui::InputTextMultiline(const char* label, std::string* str, const ImVec2& size, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data) +{ + IM_ASSERT((flags & ImGuiInputTextFlags_CallbackResize) == 0); + flags |= ImGuiInputTextFlags_CallbackResize; + + InputTextCallback_UserData cb_user_data; + cb_user_data.Str = str; + cb_user_data.ChainCallback = callback; + cb_user_data.ChainCallbackUserData = user_data; + return InputTextMultiline(label, (char*)str->c_str(), str->capacity() + 1, size, flags, InputTextCallback, &cb_user_data); +} + +bool ImGui::InputTextWithHint(const char* label, const char* hint, std::string* str, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data) +{ + IM_ASSERT((flags & ImGuiInputTextFlags_CallbackResize) == 0); + flags |= ImGuiInputTextFlags_CallbackResize; + + InputTextCallback_UserData cb_user_data; + cb_user_data.Str = str; + cb_user_data.ChainCallback = callback; + cb_user_data.ChainCallbackUserData = user_data; + return InputTextWithHint(label, hint, (char*)str->c_str(), str->capacity() + 1, flags, InputTextCallback, &cb_user_data); +} diff --git a/extern/imgui/src/imgui_widgets.cpp b/extern/imgui/src/imgui_widgets.cpp new file mode 100644 index 0000000..1debb5d --- /dev/null +++ b/extern/imgui/src/imgui_widgets.cpp @@ -0,0 +1,7961 @@ +// dear imgui, v1.77 WIP +// (widgets code) + +/* + +Index of this file: + +// [SECTION] Forward Declarations +// [SECTION] Widgets: Text, etc. +// [SECTION] Widgets: Main (Button, Image, Checkbox, RadioButton, ProgressBar, Bullet, etc.) +// [SECTION] Widgets: Low-level Layout helpers (Spacing, Dummy, NewLine, Separator, etc.) +// [SECTION] Widgets: ComboBox +// [SECTION] Data Type and Data Formatting Helpers +// [SECTION] Widgets: DragScalar, DragFloat, DragInt, etc. +// [SECTION] Widgets: SliderScalar, SliderFloat, SliderInt, etc. +// [SECTION] Widgets: InputScalar, InputFloat, InputInt, etc. +// [SECTION] Widgets: InputText, InputTextMultiline +// [SECTION] Widgets: ColorEdit, ColorPicker, ColorButton, etc. +// [SECTION] Widgets: TreeNode, CollapsingHeader, etc. +// [SECTION] Widgets: Selectable +// [SECTION] Widgets: ListBox +// [SECTION] Widgets: PlotLines, PlotHistogram +// [SECTION] Widgets: Value helpers +// [SECTION] Widgets: MenuItem, BeginMenu, EndMenu, etc. +// [SECTION] Widgets: BeginTabBar, EndTabBar, etc. +// [SECTION] Widgets: BeginTabItem, EndTabItem, etc. +// [SECTION] Widgets: Columns, BeginColumns, EndColumns, etc. + +*/ + +#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS) +#define _CRT_SECURE_NO_WARNINGS +#endif + +#include "imgui.h" +#ifndef IMGUI_DISABLE + +#ifndef IMGUI_DEFINE_MATH_OPERATORS +#define IMGUI_DEFINE_MATH_OPERATORS +#endif +#include "imgui_internal.h" + +#include // toupper +#if defined(_MSC_VER) && _MSC_VER <= 1500 // MSVC 2008 or earlier +#include // intptr_t +#else +#include // intptr_t +#endif + +// Visual Studio warnings +#ifdef _MSC_VER +#pragma warning (disable: 4127) // condition expression is constant +#pragma warning (disable: 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen +#if defined(_MSC_VER) && _MSC_VER >= 1922 // MSVC 2019 16.2 or later +#pragma warning (disable: 5054) // operator '|': deprecated between enumerations of different types +#endif +#endif + +// Clang/GCC warnings with -Weverything +#if defined(__clang__) +#pragma clang diagnostic ignored "-Wold-style-cast" // warning : use of old-style cast // yes, they are more terse. +#pragma clang diagnostic ignored "-Wfloat-equal" // warning : comparing floating point with == or != is unsafe // storing and comparing against same constants (typically 0.0f) is ok. +#pragma clang diagnostic ignored "-Wformat-nonliteral" // warning : format string is not a string literal // passing non-literal to vsnformat(). yes, user passing incorrect format strings can crash the code. +#pragma clang diagnostic ignored "-Wsign-conversion" // warning : implicit conversion changes signedness // +#if __has_warning("-Wzero-as-null-pointer-constant") +#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" // warning : zero as null pointer constant // some standard header variations use #define NULL 0 +#endif +#if __has_warning("-Wdouble-promotion") +#pragma clang diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function // using printf() is a misery with this as C++ va_arg ellipsis changes float to double. +#endif +#if __has_warning("-Wdeprecated-enum-enum-conversion") +#pragma clang diagnostic ignored "-Wdeprecated-enum-enum-conversion" // warning: bitwise operation between different enumeration types ('XXXFlags_' and 'XXXFlagsPrivate_') is deprecated +#endif +#elif defined(__GNUC__) +#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind +#pragma GCC diagnostic ignored "-Wformat-nonliteral" // warning: format not a string literal, format string not checked +#pragma GCC diagnostic ignored "-Wclass-memaccess" // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead +#endif + +//------------------------------------------------------------------------- +// Data +//------------------------------------------------------------------------- + +// Those MIN/MAX values are not define because we need to point to them +static const signed char IM_S8_MIN = -128; +static const signed char IM_S8_MAX = 127; +static const unsigned char IM_U8_MIN = 0; +static const unsigned char IM_U8_MAX = 0xFF; +static const signed short IM_S16_MIN = -32768; +static const signed short IM_S16_MAX = 32767; +static const unsigned short IM_U16_MIN = 0; +static const unsigned short IM_U16_MAX = 0xFFFF; +static const ImS32 IM_S32_MIN = INT_MIN; // (-2147483647 - 1), (0x80000000); +static const ImS32 IM_S32_MAX = INT_MAX; // (2147483647), (0x7FFFFFFF) +static const ImU32 IM_U32_MIN = 0; +static const ImU32 IM_U32_MAX = UINT_MAX; // (0xFFFFFFFF) +#ifdef LLONG_MIN +static const ImS64 IM_S64_MIN = LLONG_MIN; // (-9223372036854775807ll - 1ll); +static const ImS64 IM_S64_MAX = LLONG_MAX; // (9223372036854775807ll); +#else +static const ImS64 IM_S64_MIN = -9223372036854775807LL - 1; +static const ImS64 IM_S64_MAX = 9223372036854775807LL; +#endif +static const ImU64 IM_U64_MIN = 0; +#ifdef ULLONG_MAX +static const ImU64 IM_U64_MAX = ULLONG_MAX; // (0xFFFFFFFFFFFFFFFFull); +#else +static const ImU64 IM_U64_MAX = (2ULL * 9223372036854775807LL + 1); +#endif + +//------------------------------------------------------------------------- +// [SECTION] Forward Declarations +//------------------------------------------------------------------------- + +// For InputTextEx() +static bool InputTextFilterCharacter(unsigned int* p_char, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data); +static int InputTextCalcTextLenAndLineCount(const char* text_begin, const char** out_text_end); +static ImVec2 InputTextCalcTextSizeW(const ImWchar* text_begin, const ImWchar* text_end, const ImWchar** remaining = NULL, ImVec2* out_offset = NULL, bool stop_on_new_line = false); + +//------------------------------------------------------------------------- +// [SECTION] Widgets: Text, etc. +//------------------------------------------------------------------------- +// - TextEx() [Internal] +// - TextUnformatted() +// - Text() +// - TextV() +// - TextColored() +// - TextColoredV() +// - TextDisabled() +// - TextDisabledV() +// - TextWrapped() +// - TextWrappedV() +// - LabelText() +// - LabelTextV() +// - BulletText() +// - BulletTextV() +//------------------------------------------------------------------------- + +void ImGui::TextEx(const char* text, const char* text_end, ImGuiTextFlags flags) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return; + + ImGuiContext& g = *GImGui; + IM_ASSERT(text != NULL); + const char* text_begin = text; + if (text_end == NULL) + text_end = text + strlen(text); // FIXME-OPT + + const ImVec2 text_pos(window->DC.CursorPos.x, window->DC.CursorPos.y + window->DC.CurrLineTextBaseOffset); + const float wrap_pos_x = window->DC.TextWrapPos; + const bool wrap_enabled = (wrap_pos_x >= 0.0f); + if (text_end - text > 2000 && !wrap_enabled) + { + // Long text! + // Perform manual coarse clipping to optimize for long multi-line text + // - From this point we will only compute the width of lines that are visible. Optimization only available when word-wrapping is disabled. + // - We also don't vertically center the text within the line full height, which is unlikely to matter because we are likely the biggest and only item on the line. + // - We use memchr(), pay attention that well optimized versions of those str/mem functions are much faster than a casually written loop. + const char* line = text; + const float line_height = GetTextLineHeight(); + ImVec2 text_size(0,0); + + // Lines to skip (can't skip when logging text) + ImVec2 pos = text_pos; + if (!g.LogEnabled) + { + int lines_skippable = (int)((window->ClipRect.Min.y - text_pos.y) / line_height); + if (lines_skippable > 0) + { + int lines_skipped = 0; + while (line < text_end && lines_skipped < lines_skippable) + { + const char* line_end = (const char*)memchr(line, '\n', text_end - line); + if (!line_end) + line_end = text_end; + if ((flags & ImGuiTextFlags_NoWidthForLargeClippedText) == 0) + text_size.x = ImMax(text_size.x, CalcTextSize(line, line_end).x); + line = line_end + 1; + lines_skipped++; + } + pos.y += lines_skipped * line_height; + } + } + + // Lines to render + if (line < text_end) + { + ImRect line_rect(pos, pos + ImVec2(FLT_MAX, line_height)); + while (line < text_end) + { + if (IsClippedEx(line_rect, 0, false)) + break; + + const char* line_end = (const char*)memchr(line, '\n', text_end - line); + if (!line_end) + line_end = text_end; + text_size.x = ImMax(text_size.x, CalcTextSize(line, line_end).x); + RenderText(pos, line, line_end, false); + line = line_end + 1; + line_rect.Min.y += line_height; + line_rect.Max.y += line_height; + pos.y += line_height; + } + + // Count remaining lines + int lines_skipped = 0; + while (line < text_end) + { + const char* line_end = (const char*)memchr(line, '\n', text_end - line); + if (!line_end) + line_end = text_end; + if ((flags & ImGuiTextFlags_NoWidthForLargeClippedText) == 0) + text_size.x = ImMax(text_size.x, CalcTextSize(line, line_end).x); + line = line_end + 1; + lines_skipped++; + } + pos.y += lines_skipped * line_height; + } + text_size.y = (pos - text_pos).y; + + ImRect bb(text_pos, text_pos + text_size); + ItemSize(text_size, 0.0f); + ItemAdd(bb, 0); + } + else + { + const float wrap_width = wrap_enabled ? CalcWrapWidthForPos(window->DC.CursorPos, wrap_pos_x) : 0.0f; + const ImVec2 text_size = CalcTextSize(text_begin, text_end, false, wrap_width); + + ImRect bb(text_pos, text_pos + text_size); + ItemSize(text_size, 0.0f); + if (!ItemAdd(bb, 0)) + return; + + // Render (we don't hide text after ## in this end-user function) + RenderTextWrapped(bb.Min, text_begin, text_end, wrap_width); + } +} + +void ImGui::TextUnformatted(const char* text, const char* text_end) +{ + TextEx(text, text_end, ImGuiTextFlags_NoWidthForLargeClippedText); +} + +void ImGui::Text(const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + TextV(fmt, args); + va_end(args); +} + +void ImGui::TextV(const char* fmt, va_list args) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return; + + ImGuiContext& g = *GImGui; + const char* text_end = g.TempBuffer + ImFormatStringV(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), fmt, args); + TextEx(g.TempBuffer, text_end, ImGuiTextFlags_NoWidthForLargeClippedText); +} + +void ImGui::TextColored(const ImVec4& col, const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + TextColoredV(col, fmt, args); + va_end(args); +} + +void ImGui::TextColoredV(const ImVec4& col, const char* fmt, va_list args) +{ + PushStyleColor(ImGuiCol_Text, col); + TextV(fmt, args); + PopStyleColor(); +} + +void ImGui::TextDisabled(const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + TextDisabledV(fmt, args); + va_end(args); +} + +void ImGui::TextDisabledV(const char* fmt, va_list args) +{ + PushStyleColor(ImGuiCol_Text, GImGui->Style.Colors[ImGuiCol_TextDisabled]); + TextV(fmt, args); + PopStyleColor(); +} + +void ImGui::TextWrapped(const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + TextWrappedV(fmt, args); + va_end(args); +} + +void ImGui::TextWrappedV(const char* fmt, va_list args) +{ + ImGuiWindow* window = GetCurrentWindow(); + bool need_backup = (window->DC.TextWrapPos < 0.0f); // Keep existing wrap position if one is already set + if (need_backup) + PushTextWrapPos(0.0f); + TextV(fmt, args); + if (need_backup) + PopTextWrapPos(); +} + +void ImGui::LabelText(const char* label, const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + LabelTextV(label, fmt, args); + va_end(args); +} + +// Add a label+text combo aligned to other label+value widgets +void ImGui::LabelTextV(const char* label, const char* fmt, va_list args) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return; + + ImGuiContext& g = *GImGui; + const ImGuiStyle& style = g.Style; + const float w = CalcItemWidth(); + + const ImVec2 label_size = CalcTextSize(label, NULL, true); + const ImRect value_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y + style.FramePadding.y*2)); + const ImRect total_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w + (label_size.x > 0.0f ? style.ItemInnerSpacing.x : 0.0f), style.FramePadding.y*2) + label_size); + ItemSize(total_bb, style.FramePadding.y); + if (!ItemAdd(total_bb, 0)) + return; + + // Render + const char* value_text_begin = &g.TempBuffer[0]; + const char* value_text_end = value_text_begin + ImFormatStringV(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), fmt, args); + RenderTextClipped(value_bb.Min, value_bb.Max, value_text_begin, value_text_end, NULL, ImVec2(0.0f,0.5f)); + if (label_size.x > 0.0f) + RenderText(ImVec2(value_bb.Max.x + style.ItemInnerSpacing.x, value_bb.Min.y + style.FramePadding.y), label); +} + +void ImGui::BulletText(const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + BulletTextV(fmt, args); + va_end(args); +} + +// Text with a little bullet aligned to the typical tree node. +void ImGui::BulletTextV(const char* fmt, va_list args) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return; + + ImGuiContext& g = *GImGui; + const ImGuiStyle& style = g.Style; + + const char* text_begin = g.TempBuffer; + const char* text_end = text_begin + ImFormatStringV(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), fmt, args); + const ImVec2 label_size = CalcTextSize(text_begin, text_end, false); + const ImVec2 total_size = ImVec2(g.FontSize + (label_size.x > 0.0f ? (label_size.x + style.FramePadding.x * 2) : 0.0f), label_size.y); // Empty text doesn't add padding + ImVec2 pos = window->DC.CursorPos; + pos.y += window->DC.CurrLineTextBaseOffset; + ItemSize(total_size, 0.0f); + const ImRect bb(pos, pos + total_size); + if (!ItemAdd(bb, 0)) + return; + + // Render + ImU32 text_col = GetColorU32(ImGuiCol_Text); + RenderBullet(window->DrawList, bb.Min + ImVec2(style.FramePadding.x + g.FontSize*0.5f, g.FontSize*0.5f), text_col); + RenderText(bb.Min + ImVec2(g.FontSize + style.FramePadding.x * 2, 0.0f), text_begin, text_end, false); +} + +//------------------------------------------------------------------------- +// [SECTION] Widgets: Main +//------------------------------------------------------------------------- +// - ButtonBehavior() [Internal] +// - Button() +// - SmallButton() +// - InvisibleButton() +// - ArrowButton() +// - CloseButton() [Internal] +// - CollapseButton() [Internal] +// - GetWindowScrollbarID() [Internal] +// - GetWindowScrollbarRect() [Internal] +// - Scrollbar() [Internal] +// - ScrollbarEx() [Internal] +// - Image() +// - ImageButton() +// - Checkbox() +// - CheckboxFlags() +// - RadioButton() +// - ProgressBar() +// - Bullet() +//------------------------------------------------------------------------- + +// The ButtonBehavior() function is key to many interactions and used by many/most widgets. +// Because we handle so many cases (keyboard/gamepad navigation, drag and drop) and many specific behavior (via ImGuiButtonFlags_), +// this code is a little complex. +// By far the most common path is interacting with the Mouse using the default ImGuiButtonFlags_PressedOnClickRelease button behavior. +// See the series of events below and the corresponding state reported by dear imgui: +//------------------------------------------------------------------------------------------------------------------------------------------------ +// with PressedOnClickRelease: return-value IsItemHovered() IsItemActive() IsItemActivated() IsItemDeactivated() IsItemClicked() +// Frame N+0 (mouse is outside bb) - - - - - - +// Frame N+1 (mouse moves inside bb) - true - - - - +// Frame N+2 (mouse button is down) - true true true - true +// Frame N+3 (mouse button is down) - true true - - - +// Frame N+4 (mouse moves outside bb) - - true - - - +// Frame N+5 (mouse moves inside bb) - true true - - - +// Frame N+6 (mouse button is released) true true - - true - +// Frame N+7 (mouse button is released) - true - - - - +// Frame N+8 (mouse moves outside bb) - - - - - - +//------------------------------------------------------------------------------------------------------------------------------------------------ +// with PressedOnClick: return-value IsItemHovered() IsItemActive() IsItemActivated() IsItemDeactivated() IsItemClicked() +// Frame N+2 (mouse button is down) true true true true - true +// Frame N+3 (mouse button is down) - true true - - - +// Frame N+6 (mouse button is released) - true - - true - +// Frame N+7 (mouse button is released) - true - - - - +//------------------------------------------------------------------------------------------------------------------------------------------------ +// with PressedOnRelease: return-value IsItemHovered() IsItemActive() IsItemActivated() IsItemDeactivated() IsItemClicked() +// Frame N+2 (mouse button is down) - true - - - true +// Frame N+3 (mouse button is down) - true - - - - +// Frame N+6 (mouse button is released) true true - - - - +// Frame N+7 (mouse button is released) - true - - - - +//------------------------------------------------------------------------------------------------------------------------------------------------ +// with PressedOnDoubleClick: return-value IsItemHovered() IsItemActive() IsItemActivated() IsItemDeactivated() IsItemClicked() +// Frame N+0 (mouse button is down) - true - - - true +// Frame N+1 (mouse button is down) - true - - - - +// Frame N+2 (mouse button is released) - true - - - - +// Frame N+3 (mouse button is released) - true - - - - +// Frame N+4 (mouse button is down) true true true true - true +// Frame N+5 (mouse button is down) - true true - - - +// Frame N+6 (mouse button is released) - true - - true - +// Frame N+7 (mouse button is released) - true - - - - +//------------------------------------------------------------------------------------------------------------------------------------------------ +// Note that some combinations are supported, +// - PressedOnDragDropHold can generally be associated with any flag. +// - PressedOnDoubleClick can be associated by PressedOnClickRelease/PressedOnRelease, in which case the second release event won't be reported. +//------------------------------------------------------------------------------------------------------------------------------------------------ +// The behavior of the return-value changes when ImGuiButtonFlags_Repeat is set: +// Repeat+ Repeat+ Repeat+ Repeat+ +// PressedOnClickRelease PressedOnClick PressedOnRelease PressedOnDoubleClick +//------------------------------------------------------------------------------------------------------------------------------------------------- +// Frame N+0 (mouse button is down) - true - true +// ... - - - - +// Frame N + RepeatDelay true true - true +// ... - - - - +// Frame N + RepeatDelay + RepeatRate*N true true - true +//------------------------------------------------------------------------------------------------------------------------------------------------- + +bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool* out_held, ImGuiButtonFlags flags) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = GetCurrentWindow(); + + if (flags & ImGuiButtonFlags_Disabled) + { + if (out_hovered) *out_hovered = false; + if (out_held) *out_held = false; + if (g.ActiveId == id) ClearActiveID(); + return false; + } + + // Default only reacts to left mouse button + if ((flags & ImGuiButtonFlags_MouseButtonMask_) == 0) + flags |= ImGuiButtonFlags_MouseButtonDefault_; + + // Default behavior requires click + release inside bounding box + if ((flags & ImGuiButtonFlags_PressedOnMask_) == 0) + flags |= ImGuiButtonFlags_PressedOnDefault_; + + ImGuiWindow* backup_hovered_window = g.HoveredWindow; + const bool flatten_hovered_children = (flags & ImGuiButtonFlags_FlattenChildren) && g.HoveredRootWindow == window->RootWindow; + if (flatten_hovered_children) + g.HoveredWindow = window; + +#ifdef IMGUI_ENABLE_TEST_ENGINE + if (id != 0 && window->DC.LastItemId != id) + IMGUI_TEST_ENGINE_ITEM_ADD(bb, id); +#endif + + bool pressed = false; + bool hovered = ItemHoverable(bb, id); + + // Drag source doesn't report as hovered + if (hovered && g.DragDropActive && g.DragDropPayload.SourceId == id && !(g.DragDropSourceFlags & ImGuiDragDropFlags_SourceNoDisableHover)) + hovered = false; + + // Special mode for Drag and Drop where holding button pressed for a long time while dragging another item triggers the button + if (g.DragDropActive && (flags & ImGuiButtonFlags_PressedOnDragDropHold) && !(g.DragDropSourceFlags & ImGuiDragDropFlags_SourceNoHoldToOpenOthers)) + if (IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem)) + { + const float DRAG_DROP_HOLD_TIMER = 0.70f; + hovered = true; + SetHoveredID(id); + if (CalcTypematicRepeatAmount(g.HoveredIdTimer + 0.0001f - g.IO.DeltaTime, g.HoveredIdTimer + 0.0001f, DRAG_DROP_HOLD_TIMER, 0.00f)) + { + pressed = true; + g.DragDropHoldJustPressedId = id; + FocusWindow(window); + } + } + + if (flatten_hovered_children) + g.HoveredWindow = backup_hovered_window; + + // AllowOverlap mode (rarely used) requires previous frame HoveredId to be null or to match. This allows using patterns where a later submitted widget overlaps a previous one. + if (hovered && (flags & ImGuiButtonFlags_AllowItemOverlap) && (g.HoveredIdPreviousFrame != id && g.HoveredIdPreviousFrame != 0)) + hovered = false; + + // Mouse handling + if (hovered) + { + if (!(flags & ImGuiButtonFlags_NoKeyModifiers) || (!g.IO.KeyCtrl && !g.IO.KeyShift && !g.IO.KeyAlt)) + { + // Poll buttons + int mouse_button_clicked = -1; + int mouse_button_released = -1; + if ((flags & ImGuiButtonFlags_MouseButtonLeft) && g.IO.MouseClicked[0]) { mouse_button_clicked = 0; } + else if ((flags & ImGuiButtonFlags_MouseButtonRight) && g.IO.MouseClicked[1]) { mouse_button_clicked = 1; } + else if ((flags & ImGuiButtonFlags_MouseButtonMiddle) && g.IO.MouseClicked[2]) { mouse_button_clicked = 2; } + if ((flags & ImGuiButtonFlags_MouseButtonLeft) && g.IO.MouseReleased[0]) { mouse_button_released = 0; } + else if ((flags & ImGuiButtonFlags_MouseButtonRight) && g.IO.MouseReleased[1]) { mouse_button_released = 1; } + else if ((flags & ImGuiButtonFlags_MouseButtonMiddle) && g.IO.MouseReleased[2]) { mouse_button_released = 2; } + + if (mouse_button_clicked != -1 && g.ActiveId != id) + { + if (flags & (ImGuiButtonFlags_PressedOnClickRelease | ImGuiButtonFlags_PressedOnClickReleaseAnywhere)) + { + SetActiveID(id, window); + g.ActiveIdMouseButton = mouse_button_clicked; + if (!(flags & ImGuiButtonFlags_NoNavFocus)) + SetFocusID(id, window); + FocusWindow(window); + } + if ((flags & ImGuiButtonFlags_PressedOnClick) || ((flags & ImGuiButtonFlags_PressedOnDoubleClick) && g.IO.MouseDoubleClicked[mouse_button_clicked])) + { + pressed = true; + if (flags & ImGuiButtonFlags_NoHoldingActiveId) + ClearActiveID(); + else + SetActiveID(id, window); // Hold on ID + g.ActiveIdMouseButton = mouse_button_clicked; + FocusWindow(window); + } + } + if ((flags & ImGuiButtonFlags_PressedOnRelease) && mouse_button_released != -1) + { + // Repeat mode trumps on release behavior + if (!((flags & ImGuiButtonFlags_Repeat) && g.IO.MouseDownDurationPrev[mouse_button_released] >= g.IO.KeyRepeatDelay)) + pressed = true; + ClearActiveID(); + } + + // 'Repeat' mode acts when held regardless of _PressedOn flags (see table above). + // Relies on repeat logic of IsMouseClicked() but we may as well do it ourselves if we end up exposing finer RepeatDelay/RepeatRate settings. + if (g.ActiveId == id && (flags & ImGuiButtonFlags_Repeat)) + if (g.IO.MouseDownDuration[g.ActiveIdMouseButton] > 0.0f && IsMouseClicked(g.ActiveIdMouseButton, true)) + pressed = true; + } + + if (pressed) + g.NavDisableHighlight = true; + } + + // Gamepad/Keyboard navigation + // We report navigated item as hovered but we don't set g.HoveredId to not interfere with mouse. + if (g.NavId == id && !g.NavDisableHighlight && g.NavDisableMouseHover && (g.ActiveId == 0 || g.ActiveId == id || g.ActiveId == window->MoveId)) + if (!(flags & ImGuiButtonFlags_NoHoveredOnFocus)) + hovered = true; + if (g.NavActivateDownId == id) + { + bool nav_activated_by_code = (g.NavActivateId == id); + bool nav_activated_by_inputs = IsNavInputTest(ImGuiNavInput_Activate, (flags & ImGuiButtonFlags_Repeat) ? ImGuiInputReadMode_Repeat : ImGuiInputReadMode_Pressed); + if (nav_activated_by_code || nav_activated_by_inputs) + pressed = true; + if (nav_activated_by_code || nav_activated_by_inputs || g.ActiveId == id) + { + // Set active id so it can be queried by user via IsItemActive(), equivalent of holding the mouse button. + g.NavActivateId = id; // This is so SetActiveId assign a Nav source + SetActiveID(id, window); + if ((nav_activated_by_code || nav_activated_by_inputs) && !(flags & ImGuiButtonFlags_NoNavFocus)) + SetFocusID(id, window); + } + } + + bool held = false; + if (g.ActiveId == id) + { + if (g.ActiveIdSource == ImGuiInputSource_Mouse) + { + if (g.ActiveIdIsJustActivated) + g.ActiveIdClickOffset = g.IO.MousePos - bb.Min; + + const int mouse_button = g.ActiveIdMouseButton; + IM_ASSERT(mouse_button >= 0 && mouse_button < ImGuiMouseButton_COUNT); + if (g.IO.MouseDown[mouse_button]) + { + held = true; + } + else + { + bool release_in = hovered && (flags & ImGuiButtonFlags_PressedOnClickRelease) != 0; + bool release_anywhere = (flags & ImGuiButtonFlags_PressedOnClickReleaseAnywhere) != 0; + if ((release_in || release_anywhere) && !g.DragDropActive) + { + bool is_double_click_release = (flags & ImGuiButtonFlags_PressedOnDoubleClick) && g.IO.MouseDownWasDoubleClick[mouse_button]; + bool is_repeating_already = (flags & ImGuiButtonFlags_Repeat) && g.IO.MouseDownDurationPrev[mouse_button] >= g.IO.KeyRepeatDelay; // Repeat mode trumps + if (!is_double_click_release && !is_repeating_already) + pressed = true; + } + ClearActiveID(); + } + if (!(flags & ImGuiButtonFlags_NoNavFocus)) + g.NavDisableHighlight = true; + } + else if (g.ActiveIdSource == ImGuiInputSource_Nav) + { + if (g.NavActivateDownId != id) + ClearActiveID(); + } + if (pressed) + g.ActiveIdHasBeenPressedBefore = true; + } + + if (out_hovered) *out_hovered = hovered; + if (out_held) *out_held = held; + + return pressed; +} + +bool ImGui::ButtonEx(const char* label, const ImVec2& size_arg, ImGuiButtonFlags flags) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + ImGuiContext& g = *GImGui; + const ImGuiStyle& style = g.Style; + const ImGuiID id = window->GetID(label); + const ImVec2 label_size = CalcTextSize(label, NULL, true); + + ImVec2 pos = window->DC.CursorPos; + if ((flags & ImGuiButtonFlags_AlignTextBaseLine) && style.FramePadding.y < window->DC.CurrLineTextBaseOffset) // Try to vertically align buttons that are smaller/have no padding so that text baseline matches (bit hacky, since it shouldn't be a flag) + pos.y += window->DC.CurrLineTextBaseOffset - style.FramePadding.y; + ImVec2 size = CalcItemSize(size_arg, label_size.x + style.FramePadding.x * 2.0f, label_size.y + style.FramePadding.y * 2.0f); + + const ImRect bb(pos, pos + size); + ItemSize(size, style.FramePadding.y); + if (!ItemAdd(bb, id)) + return false; + + if (window->DC.ItemFlags & ImGuiItemFlags_ButtonRepeat) + flags |= ImGuiButtonFlags_Repeat; + bool hovered, held; + bool pressed = ButtonBehavior(bb, id, &hovered, &held, flags); + + // Render + const ImU32 col = GetColorU32((held && hovered) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button); + RenderNavHighlight(bb, id); + RenderFrame(bb.Min, bb.Max, col, true, style.FrameRounding); + RenderTextClipped(bb.Min + style.FramePadding, bb.Max - style.FramePadding, label, NULL, &label_size, style.ButtonTextAlign, &bb); + + // Automatically close popups + //if (pressed && !(flags & ImGuiButtonFlags_DontClosePopups) && (window->Flags & ImGuiWindowFlags_Popup)) + // CloseCurrentPopup(); + + IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.LastItemStatusFlags); + return pressed; +} + +bool ImGui::Button(const char* label, const ImVec2& size_arg) +{ + return ButtonEx(label, size_arg, 0); +} + +// Small buttons fits within text without additional vertical spacing. +bool ImGui::SmallButton(const char* label) +{ + ImGuiContext& g = *GImGui; + float backup_padding_y = g.Style.FramePadding.y; + g.Style.FramePadding.y = 0.0f; + bool pressed = ButtonEx(label, ImVec2(0, 0), ImGuiButtonFlags_AlignTextBaseLine); + g.Style.FramePadding.y = backup_padding_y; + return pressed; +} + +// Tip: use ImGui::PushID()/PopID() to push indices or pointers in the ID stack. +// Then you can keep 'str_id' empty or the same for all your buttons (instead of creating a string based on a non-string id) +bool ImGui::InvisibleButton(const char* str_id, const ImVec2& size_arg) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + // Cannot use zero-size for InvisibleButton(). Unlike Button() there is not way to fallback using the label size. + IM_ASSERT(size_arg.x != 0.0f && size_arg.y != 0.0f); + + const ImGuiID id = window->GetID(str_id); + ImVec2 size = CalcItemSize(size_arg, 0.0f, 0.0f); + const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size); + ItemSize(size); + if (!ItemAdd(bb, id)) + return false; + + bool hovered, held; + bool pressed = ButtonBehavior(bb, id, &hovered, &held); + + return pressed; +} + +bool ImGui::ArrowButtonEx(const char* str_id, ImGuiDir dir, ImVec2 size, ImGuiButtonFlags flags) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + ImGuiContext& g = *GImGui; + const ImGuiID id = window->GetID(str_id); + const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size); + const float default_size = GetFrameHeight(); + ItemSize(size, (size.y >= default_size) ? g.Style.FramePadding.y : -1.0f); + if (!ItemAdd(bb, id)) + return false; + + if (window->DC.ItemFlags & ImGuiItemFlags_ButtonRepeat) + flags |= ImGuiButtonFlags_Repeat; + + bool hovered, held; + bool pressed = ButtonBehavior(bb, id, &hovered, &held, flags); + + // Render + const ImU32 bg_col = GetColorU32((held && hovered) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button); + const ImU32 text_col = GetColorU32(ImGuiCol_Text); + RenderNavHighlight(bb, id); + RenderFrame(bb.Min, bb.Max, bg_col, true, g.Style.FrameRounding); + RenderArrow(window->DrawList, bb.Min + ImVec2(ImMax(0.0f, (size.x - g.FontSize) * 0.5f), ImMax(0.0f, (size.y - g.FontSize) * 0.5f)), text_col, dir); + + return pressed; +} + +bool ImGui::ArrowButton(const char* str_id, ImGuiDir dir) +{ + float sz = GetFrameHeight(); + return ArrowButtonEx(str_id, dir, ImVec2(sz, sz), ImGuiButtonFlags_None); +} + +// Button to close a window +bool ImGui::CloseButton(ImGuiID id, const ImVec2& pos)//, float size) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + + // We intentionally allow interaction when clipped so that a mechanical Alt,Right,Validate sequence close a window. + // (this isn't the regular behavior of buttons, but it doesn't affect the user much because navigation tends to keep items visible). + const ImRect bb(pos, pos + ImVec2(g.FontSize, g.FontSize) + g.Style.FramePadding * 2.0f); + bool is_clipped = !ItemAdd(bb, id); + + bool hovered, held; + bool pressed = ButtonBehavior(bb, id, &hovered, &held); + if (is_clipped) + return pressed; + + // Render + ImU32 col = GetColorU32(held ? ImGuiCol_ButtonActive : ImGuiCol_ButtonHovered); + ImVec2 center = bb.GetCenter(); + if (hovered) + window->DrawList->AddCircleFilled(center, ImMax(2.0f, g.FontSize * 0.5f + 1.0f), col, 12); + + float cross_extent = g.FontSize * 0.5f * 0.7071f - 1.0f; + ImU32 cross_col = GetColorU32(ImGuiCol_Text); + center -= ImVec2(0.5f, 0.5f); + window->DrawList->AddLine(center + ImVec2(+cross_extent,+cross_extent), center + ImVec2(-cross_extent,-cross_extent), cross_col, 1.0f); + window->DrawList->AddLine(center + ImVec2(+cross_extent,-cross_extent), center + ImVec2(-cross_extent,+cross_extent), cross_col, 1.0f); + + return pressed; +} + +// The Collapse button also functions as a Dock Menu button. +bool ImGui::CollapseButton(ImGuiID id, const ImVec2& pos, ImGuiDockNode* dock_node) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + + ImRect bb(pos, pos + ImVec2(g.FontSize, g.FontSize) + g.Style.FramePadding * 2.0f); + ItemAdd(bb, id); + bool hovered, held; + bool pressed = ButtonBehavior(bb, id, &hovered, &held, ImGuiButtonFlags_None); + + // Render + //bool is_dock_menu = (window->DockNodeAsHost && !window->Collapsed); + ImVec2 off = dock_node ? ImVec2(IM_FLOOR(-g.Style.ItemInnerSpacing.x * 0.5f) + 0.5f, 0.0f) : ImVec2(0.0f, 0.0f); + ImU32 bg_col = GetColorU32((held && hovered) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button); + ImU32 text_col = GetColorU32(ImGuiCol_Text); + ImVec2 center = bb.GetCenter(); + if (hovered || held) + window->DrawList->AddCircleFilled(center + off + ImVec2(0,-0.5f), g.FontSize * 0.5f + 1.0f, bg_col, 12); + + if (dock_node) + RenderArrowDockMenu(window->DrawList, bb.Min + g.Style.FramePadding, g.FontSize, text_col); + else + RenderArrow(window->DrawList, bb.Min + g.Style.FramePadding, text_col, window->Collapsed ? ImGuiDir_Right : ImGuiDir_Down, 1.0f); + + // Switch to moving the window after mouse is moved beyond the initial drag threshold + if (IsItemActive() && IsMouseDragging(0)) + StartMouseMovingWindowOrNode(window, dock_node, true); + + return pressed; +} + +ImGuiID ImGui::GetWindowScrollbarID(ImGuiWindow* window, ImGuiAxis axis) +{ + return window->GetIDNoKeepAlive(axis == ImGuiAxis_X ? "#SCROLLX" : "#SCROLLY"); +} + +// Return scrollbar rectangle, must only be called for corresponding axis if window->ScrollbarX/Y is set. +ImRect ImGui::GetWindowScrollbarRect(ImGuiWindow* window, ImGuiAxis axis) +{ + const ImRect outer_rect = window->Rect(); + const ImRect inner_rect = window->InnerRect; + const float border_size = window->WindowBorderSize; + const float scrollbar_size = window->ScrollbarSizes[axis ^ 1]; // (ScrollbarSizes.x = width of Y scrollbar; ScrollbarSizes.y = height of X scrollbar) + IM_ASSERT(scrollbar_size > 0.0f); + if (axis == ImGuiAxis_X) + return ImRect(inner_rect.Min.x, ImMax(outer_rect.Min.y, outer_rect.Max.y - border_size - scrollbar_size), inner_rect.Max.x, outer_rect.Max.y); + else + return ImRect(ImMax(outer_rect.Min.x, outer_rect.Max.x - border_size - scrollbar_size), inner_rect.Min.y, outer_rect.Max.x, inner_rect.Max.y); +} + +void ImGui::Scrollbar(ImGuiAxis axis) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + + const ImGuiID id = GetWindowScrollbarID(window, axis); + KeepAliveID(id); + + // Calculate scrollbar bounding box + ImRect bb = GetWindowScrollbarRect(window, axis); + ImDrawCornerFlags rounding_corners = 0; + if (axis == ImGuiAxis_X) + { + rounding_corners |= ImDrawCornerFlags_BotLeft; + if (!window->ScrollbarY) + rounding_corners |= ImDrawCornerFlags_BotRight; + } + else + { + if ((window->Flags & ImGuiWindowFlags_NoTitleBar) && !(window->Flags & ImGuiWindowFlags_MenuBar)) + rounding_corners |= ImDrawCornerFlags_TopRight; + if (!window->ScrollbarX) + rounding_corners |= ImDrawCornerFlags_BotRight; + } + float size_avail = window->InnerRect.Max[axis] - window->InnerRect.Min[axis]; + float size_contents = window->ContentSize[axis] + window->WindowPadding[axis] * 2.0f; + ScrollbarEx(bb, id, axis, &window->Scroll[axis], size_avail, size_contents, rounding_corners); +} + +// Vertical/Horizontal scrollbar +// The entire piece of code below is rather confusing because: +// - We handle absolute seeking (when first clicking outside the grab) and relative manipulation (afterward or when clicking inside the grab) +// - We store values as normalized ratio and in a form that allows the window content to change while we are holding on a scrollbar +// - We handle both horizontal and vertical scrollbars, which makes the terminology not ideal. +// Still, the code should probably be made simpler.. +bool ImGui::ScrollbarEx(const ImRect& bb_frame, ImGuiID id, ImGuiAxis axis, float* p_scroll_v, float size_avail_v, float size_contents_v, ImDrawCornerFlags rounding_corners) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if (window->SkipItems) + return false; + + const float bb_frame_width = bb_frame.GetWidth(); + const float bb_frame_height = bb_frame.GetHeight(); + if (bb_frame_width <= 0.0f || bb_frame_height <= 0.0f) + return false; + + // When we are too small, start hiding and disabling the grab (this reduce visual noise on very small window and facilitate using the window resize grab) + float alpha = 1.0f; + if ((axis == ImGuiAxis_Y) && bb_frame_height < g.FontSize + g.Style.FramePadding.y * 2.0f) + alpha = ImSaturate((bb_frame_height - g.FontSize) / (g.Style.FramePadding.y * 2.0f)); + if (alpha <= 0.0f) + return false; + + const ImGuiStyle& style = g.Style; + const bool allow_interaction = (alpha >= 1.0f); + + ImRect bb = bb_frame; + bb.Expand(ImVec2(-ImClamp(IM_FLOOR((bb_frame_width - 2.0f) * 0.5f), 0.0f, 3.0f), -ImClamp(IM_FLOOR((bb_frame_height - 2.0f) * 0.5f), 0.0f, 3.0f))); + + // V denote the main, longer axis of the scrollbar (= height for a vertical scrollbar) + const float scrollbar_size_v = (axis == ImGuiAxis_X) ? bb.GetWidth() : bb.GetHeight(); + + // Calculate the height of our grabbable box. It generally represent the amount visible (vs the total scrollable amount) + // But we maintain a minimum size in pixel to allow for the user to still aim inside. + IM_ASSERT(ImMax(size_contents_v, size_avail_v) > 0.0f); // Adding this assert to check if the ImMax(XXX,1.0f) is still needed. PLEASE CONTACT ME if this triggers. + const float win_size_v = ImMax(ImMax(size_contents_v, size_avail_v), 1.0f); + const float grab_h_pixels = ImClamp(scrollbar_size_v * (size_avail_v / win_size_v), style.GrabMinSize, scrollbar_size_v); + const float grab_h_norm = grab_h_pixels / scrollbar_size_v; + + // Handle input right away. None of the code of Begin() is relying on scrolling position before calling Scrollbar(). + bool held = false; + bool hovered = false; + ButtonBehavior(bb, id, &hovered, &held, ImGuiButtonFlags_NoNavFocus); + + float scroll_max = ImMax(1.0f, size_contents_v - size_avail_v); + float scroll_ratio = ImSaturate(*p_scroll_v / scroll_max); + float grab_v_norm = scroll_ratio * (scrollbar_size_v - grab_h_pixels) / scrollbar_size_v; // Grab position in normalized space + if (held && allow_interaction && grab_h_norm < 1.0f) + { + float scrollbar_pos_v = bb.Min[axis]; + float mouse_pos_v = g.IO.MousePos[axis]; + + // Click position in scrollbar normalized space (0.0f->1.0f) + const float clicked_v_norm = ImSaturate((mouse_pos_v - scrollbar_pos_v) / scrollbar_size_v); + SetHoveredID(id); + + bool seek_absolute = false; + if (g.ActiveIdIsJustActivated) + { + // On initial click calculate the distance between mouse and the center of the grab + seek_absolute = (clicked_v_norm < grab_v_norm || clicked_v_norm > grab_v_norm + grab_h_norm); + if (seek_absolute) + g.ScrollbarClickDeltaToGrabCenter = 0.0f; + else + g.ScrollbarClickDeltaToGrabCenter = clicked_v_norm - grab_v_norm - grab_h_norm * 0.5f; + } + + // Apply scroll (p_scroll_v will generally point on one member of window->Scroll) + // It is ok to modify Scroll here because we are being called in Begin() after the calculation of ContentSize and before setting up our starting position + const float scroll_v_norm = ImSaturate((clicked_v_norm - g.ScrollbarClickDeltaToGrabCenter - grab_h_norm * 0.5f) / (1.0f - grab_h_norm)); + *p_scroll_v = IM_ROUND(scroll_v_norm * scroll_max);//(win_size_contents_v - win_size_v)); + + // Update values for rendering + scroll_ratio = ImSaturate(*p_scroll_v / scroll_max); + grab_v_norm = scroll_ratio * (scrollbar_size_v - grab_h_pixels) / scrollbar_size_v; + + // Update distance to grab now that we have seeked and saturated + if (seek_absolute) + g.ScrollbarClickDeltaToGrabCenter = clicked_v_norm - grab_v_norm - grab_h_norm * 0.5f; + } + + // Render + const ImU32 bg_col = GetColorU32(ImGuiCol_ScrollbarBg); + const ImU32 grab_col = GetColorU32(held ? ImGuiCol_ScrollbarGrabActive : hovered ? ImGuiCol_ScrollbarGrabHovered : ImGuiCol_ScrollbarGrab, alpha); + window->DrawList->AddRectFilled(bb_frame.Min, bb_frame.Max, bg_col, window->WindowRounding, rounding_corners); + ImRect grab_rect; + if (axis == ImGuiAxis_X) + grab_rect = ImRect(ImLerp(bb.Min.x, bb.Max.x, grab_v_norm), bb.Min.y, ImLerp(bb.Min.x, bb.Max.x, grab_v_norm) + grab_h_pixels, bb.Max.y); + else + grab_rect = ImRect(bb.Min.x, ImLerp(bb.Min.y, bb.Max.y, grab_v_norm), bb.Max.x, ImLerp(bb.Min.y, bb.Max.y, grab_v_norm) + grab_h_pixels); + window->DrawList->AddRectFilled(grab_rect.Min, grab_rect.Max, grab_col, style.ScrollbarRounding); + + return held; +} + +void ImGui::Image(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& tint_col, const ImVec4& border_col) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return; + + ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size); + if (border_col.w > 0.0f) + bb.Max += ImVec2(2, 2); + ItemSize(bb); + if (!ItemAdd(bb, 0)) + return; + + if (border_col.w > 0.0f) + { + window->DrawList->AddRect(bb.Min, bb.Max, GetColorU32(border_col), 0.0f); + window->DrawList->AddImage(user_texture_id, bb.Min + ImVec2(1, 1), bb.Max - ImVec2(1, 1), uv0, uv1, GetColorU32(tint_col)); + } + else + { + window->DrawList->AddImage(user_texture_id, bb.Min, bb.Max, uv0, uv1, GetColorU32(tint_col)); + } +} + +// frame_padding < 0: uses FramePadding from style (default) +// frame_padding = 0: no framing +// frame_padding > 0: set framing size +// The color used are the button colors. +bool ImGui::ImageButton(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0, const ImVec2& uv1, int frame_padding, const ImVec4& bg_col, const ImVec4& tint_col) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + ImGuiContext& g = *GImGui; + const ImGuiStyle& style = g.Style; + + // Default to using texture ID as ID. User can still push string/integer prefixes. + // We could hash the size/uv to create a unique ID but that would prevent the user from animating UV. + PushID((void*)(intptr_t)user_texture_id); + const ImGuiID id = window->GetID("#image"); + PopID(); + + const ImVec2 padding = (frame_padding >= 0) ? ImVec2((float)frame_padding, (float)frame_padding) : style.FramePadding; + const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size + padding * 2); + const ImRect image_bb(window->DC.CursorPos + padding, window->DC.CursorPos + padding + size); + ItemSize(bb); + if (!ItemAdd(bb, id)) + return false; + + bool hovered, held; + bool pressed = ButtonBehavior(bb, id, &hovered, &held); + + // Render + const ImU32 col = GetColorU32((held && hovered) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button); + RenderNavHighlight(bb, id); + RenderFrame(bb.Min, bb.Max, col, true, ImClamp((float)ImMin(padding.x, padding.y), 0.0f, style.FrameRounding)); + if (bg_col.w > 0.0f) + window->DrawList->AddRectFilled(image_bb.Min, image_bb.Max, GetColorU32(bg_col)); + window->DrawList->AddImage(user_texture_id, image_bb.Min, image_bb.Max, uv0, uv1, GetColorU32(tint_col)); + + return pressed; +} + +bool ImGui::Checkbox(const char* label, bool* v) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + ImGuiContext& g = *GImGui; + const ImGuiStyle& style = g.Style; + const ImGuiID id = window->GetID(label); + const ImVec2 label_size = CalcTextSize(label, NULL, true); + + const float square_sz = GetFrameHeight(); + const ImVec2 pos = window->DC.CursorPos; + const ImRect total_bb(pos, pos + ImVec2(square_sz + (label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f), label_size.y + style.FramePadding.y * 2.0f)); + ItemSize(total_bb, style.FramePadding.y); + if (!ItemAdd(total_bb, id)) + return false; + + bool hovered, held; + bool pressed = ButtonBehavior(total_bb, id, &hovered, &held); + if (pressed) + { + *v = !(*v); + MarkItemEdited(id); + } + + const ImRect check_bb(pos, pos + ImVec2(square_sz, square_sz)); + RenderNavHighlight(total_bb, id); + RenderFrame(check_bb.Min, check_bb.Max, GetColorU32((held && hovered) ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg), true, style.FrameRounding); + ImU32 check_col = GetColorU32(ImGuiCol_CheckMark); + if (window->DC.ItemFlags & ImGuiItemFlags_MixedValue) + { + // Undocumented tristate/mixed/indeterminate checkbox (#2644) + ImVec2 pad(ImMax(1.0f, IM_FLOOR(square_sz / 3.6f)), ImMax(1.0f, IM_FLOOR(square_sz / 3.6f))); + window->DrawList->AddRectFilled(check_bb.Min + pad, check_bb.Max - pad, check_col, style.FrameRounding); + } + else if (*v) + { + const float pad = ImMax(1.0f, IM_FLOOR(square_sz / 6.0f)); + RenderCheckMark(window->DrawList, check_bb.Min + ImVec2(pad, pad), check_col, square_sz - pad*2.0f); + } + + if (g.LogEnabled) + LogRenderedText(&total_bb.Min, *v ? "[x]" : "[ ]"); + if (label_size.x > 0.0f) + RenderText(ImVec2(check_bb.Max.x + style.ItemInnerSpacing.x, check_bb.Min.y + style.FramePadding.y), label); + + IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.ItemFlags | ImGuiItemStatusFlags_Checkable | (*v ? ImGuiItemStatusFlags_Checked : 0)); + return pressed; +} + +bool ImGui::CheckboxFlags(const char* label, unsigned int* flags, unsigned int flags_value) +{ + bool v = ((*flags & flags_value) == flags_value); + bool pressed = Checkbox(label, &v); + if (pressed) + { + if (v) + *flags |= flags_value; + else + *flags &= ~flags_value; + } + + return pressed; +} + +bool ImGui::RadioButton(const char* label, bool active) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + ImGuiContext& g = *GImGui; + const ImGuiStyle& style = g.Style; + const ImGuiID id = window->GetID(label); + const ImVec2 label_size = CalcTextSize(label, NULL, true); + + const float square_sz = GetFrameHeight(); + const ImVec2 pos = window->DC.CursorPos; + const ImRect check_bb(pos, pos + ImVec2(square_sz, square_sz)); + const ImRect total_bb(pos, pos + ImVec2(square_sz + (label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f), label_size.y + style.FramePadding.y * 2.0f)); + ItemSize(total_bb, style.FramePadding.y); + if (!ItemAdd(total_bb, id)) + return false; + + ImVec2 center = check_bb.GetCenter(); + center.x = IM_ROUND(center.x); + center.y = IM_ROUND(center.y); + const float radius = (square_sz - 1.0f) * 0.5f; + + bool hovered, held; + bool pressed = ButtonBehavior(total_bb, id, &hovered, &held); + if (pressed) + MarkItemEdited(id); + + RenderNavHighlight(total_bb, id); + window->DrawList->AddCircleFilled(center, radius, GetColorU32((held && hovered) ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg), 16); + if (active) + { + const float pad = ImMax(1.0f, IM_FLOOR(square_sz / 6.0f)); + window->DrawList->AddCircleFilled(center, radius - pad, GetColorU32(ImGuiCol_CheckMark), 16); + } + + if (style.FrameBorderSize > 0.0f) + { + window->DrawList->AddCircle(center + ImVec2(1,1), radius, GetColorU32(ImGuiCol_BorderShadow), 16, style.FrameBorderSize); + window->DrawList->AddCircle(center, radius, GetColorU32(ImGuiCol_Border), 16, style.FrameBorderSize); + } + + if (g.LogEnabled) + LogRenderedText(&total_bb.Min, active ? "(x)" : "( )"); + if (label_size.x > 0.0f) + RenderText(ImVec2(check_bb.Max.x + style.ItemInnerSpacing.x, check_bb.Min.y + style.FramePadding.y), label); + + IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.ItemFlags); + return pressed; +} + +// FIXME: This would work nicely if it was a public template, e.g. 'template RadioButton(const char* label, T* v, T v_button)', but I'm not sure how we would expose it.. +bool ImGui::RadioButton(const char* label, int* v, int v_button) +{ + const bool pressed = RadioButton(label, *v == v_button); + if (pressed) + *v = v_button; + return pressed; +} + +// size_arg (for each axis) < 0.0f: align to end, 0.0f: auto, > 0.0f: specified size +void ImGui::ProgressBar(float fraction, const ImVec2& size_arg, const char* overlay) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return; + + ImGuiContext& g = *GImGui; + const ImGuiStyle& style = g.Style; + + ImVec2 pos = window->DC.CursorPos; + ImVec2 size = CalcItemSize(size_arg, CalcItemWidth(), g.FontSize + style.FramePadding.y*2.0f); + ImRect bb(pos, pos + size); + ItemSize(size, style.FramePadding.y); + if (!ItemAdd(bb, 0)) + return; + + // Render + fraction = ImSaturate(fraction); + RenderFrame(bb.Min, bb.Max, GetColorU32(ImGuiCol_FrameBg), true, style.FrameRounding); + bb.Expand(ImVec2(-style.FrameBorderSize, -style.FrameBorderSize)); + const ImVec2 fill_br = ImVec2(ImLerp(bb.Min.x, bb.Max.x, fraction), bb.Max.y); + RenderRectFilledRangeH(window->DrawList, bb, GetColorU32(ImGuiCol_PlotHistogram), 0.0f, fraction, style.FrameRounding); + + // Default displaying the fraction as percentage string, but user can override it + char overlay_buf[32]; + if (!overlay) + { + ImFormatString(overlay_buf, IM_ARRAYSIZE(overlay_buf), "%.0f%%", fraction*100+0.01f); + overlay = overlay_buf; + } + + ImVec2 overlay_size = CalcTextSize(overlay, NULL); + if (overlay_size.x > 0.0f) + RenderTextClipped(ImVec2(ImClamp(fill_br.x + style.ItemSpacing.x, bb.Min.x, bb.Max.x - overlay_size.x - style.ItemInnerSpacing.x), bb.Min.y), bb.Max, overlay, NULL, &overlay_size, ImVec2(0.0f,0.5f), &bb); +} + +void ImGui::Bullet() +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return; + + ImGuiContext& g = *GImGui; + const ImGuiStyle& style = g.Style; + const float line_height = ImMax(ImMin(window->DC.CurrLineSize.y, g.FontSize + g.Style.FramePadding.y*2), g.FontSize); + const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(g.FontSize, line_height)); + ItemSize(bb); + if (!ItemAdd(bb, 0)) + { + SameLine(0, style.FramePadding.x*2); + return; + } + + // Render and stay on same line + ImU32 text_col = GetColorU32(ImGuiCol_Text); + RenderBullet(window->DrawList, bb.Min + ImVec2(style.FramePadding.x + g.FontSize*0.5f, line_height*0.5f), text_col); + SameLine(0, style.FramePadding.x * 2.0f); +} + +//------------------------------------------------------------------------- +// [SECTION] Widgets: Low-level Layout helpers +//------------------------------------------------------------------------- +// - Spacing() +// - Dummy() +// - NewLine() +// - AlignTextToFramePadding() +// - SeparatorEx() [Internal] +// - Separator() +// - SplitterBehavior() [Internal] +// - ShrinkWidths() [Internal] +//------------------------------------------------------------------------- + +void ImGui::Spacing() +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return; + ItemSize(ImVec2(0,0)); +} + +void ImGui::Dummy(const ImVec2& size) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return; + + const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size); + ItemSize(size); + ItemAdd(bb, 0); +} + +void ImGui::NewLine() +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return; + + ImGuiContext& g = *GImGui; + const ImGuiLayoutType backup_layout_type = window->DC.LayoutType; + window->DC.LayoutType = ImGuiLayoutType_Vertical; + if (window->DC.CurrLineSize.y > 0.0f) // In the event that we are on a line with items that is smaller that FontSize high, we will preserve its height. + ItemSize(ImVec2(0,0)); + else + ItemSize(ImVec2(0.0f, g.FontSize)); + window->DC.LayoutType = backup_layout_type; +} + +void ImGui::AlignTextToFramePadding() +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return; + + ImGuiContext& g = *GImGui; + window->DC.CurrLineSize.y = ImMax(window->DC.CurrLineSize.y, g.FontSize + g.Style.FramePadding.y * 2); + window->DC.CurrLineTextBaseOffset = ImMax(window->DC.CurrLineTextBaseOffset, g.Style.FramePadding.y); +} + +// Horizontal/vertical separating line +void ImGui::SeparatorEx(ImGuiSeparatorFlags flags) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return; + + ImGuiContext& g = *GImGui; + IM_ASSERT(ImIsPowerOfTwo(flags & (ImGuiSeparatorFlags_Horizontal | ImGuiSeparatorFlags_Vertical))); // Check that only 1 option is selected + + float thickness_draw = 1.0f; + float thickness_layout = 0.0f; + if (flags & ImGuiSeparatorFlags_Vertical) + { + // Vertical separator, for menu bars (use current line height). Not exposed because it is misleading and it doesn't have an effect on regular layout. + float y1 = window->DC.CursorPos.y; + float y2 = window->DC.CursorPos.y + window->DC.CurrLineSize.y; + const ImRect bb(ImVec2(window->DC.CursorPos.x, y1), ImVec2(window->DC.CursorPos.x + thickness_draw, y2)); + ItemSize(ImVec2(thickness_layout, 0.0f)); + if (!ItemAdd(bb, 0)) + return; + + // Draw + window->DrawList->AddLine(ImVec2(bb.Min.x, bb.Min.y), ImVec2(bb.Min.x, bb.Max.y), GetColorU32(ImGuiCol_Separator)); + if (g.LogEnabled) + LogText(" |"); + } + else if (flags & ImGuiSeparatorFlags_Horizontal) + { + // Horizontal Separator + float x1 = window->Pos.x; + float x2 = window->Pos.x + window->Size.x; + if (!window->DC.GroupStack.empty()) + x1 += window->DC.Indent.x; + + ImGuiColumns* columns = (flags & ImGuiSeparatorFlags_SpanAllColumns) ? window->DC.CurrentColumns : NULL; + if (columns) + PushColumnsBackground(); + + // We don't provide our width to the layout so that it doesn't get feed back into AutoFit + const ImRect bb(ImVec2(x1, window->DC.CursorPos.y), ImVec2(x2, window->DC.CursorPos.y + thickness_draw)); + ItemSize(ImVec2(0.0f, thickness_layout)); + const bool item_visible = ItemAdd(bb, 0); + if (item_visible) + { + // Draw + window->DrawList->AddLine(bb.Min, ImVec2(bb.Max.x, bb.Min.y), GetColorU32(ImGuiCol_Separator)); + if (g.LogEnabled) + LogRenderedText(&bb.Min, "--------------------------------"); + } + if (columns) + { + PopColumnsBackground(); + columns->LineMinY = window->DC.CursorPos.y; + } + } +} + +void ImGui::Separator() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if (window->SkipItems) + return; + + // Those flags should eventually be overridable by the user + ImGuiSeparatorFlags flags = (window->DC.LayoutType == ImGuiLayoutType_Horizontal) ? ImGuiSeparatorFlags_Vertical : ImGuiSeparatorFlags_Horizontal; + flags |= ImGuiSeparatorFlags_SpanAllColumns; + SeparatorEx(flags); +} + +// Using 'hover_visibility_delay' allows us to hide the highlight and mouse cursor for a short time, which can be convenient to reduce visual noise. +bool ImGui::SplitterBehavior(const ImRect& bb, ImGuiID id, ImGuiAxis axis, float* size1, float* size2, float min_size1, float min_size2, float hover_extend, float hover_visibility_delay) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + + const ImGuiItemFlags item_flags_backup = window->DC.ItemFlags; + window->DC.ItemFlags |= ImGuiItemFlags_NoNav | ImGuiItemFlags_NoNavDefaultFocus; + bool item_add = ItemAdd(bb, id); + window->DC.ItemFlags = item_flags_backup; + if (!item_add) + return false; + + bool hovered, held; + ImRect bb_interact = bb; + bb_interact.Expand(axis == ImGuiAxis_Y ? ImVec2(0.0f, hover_extend) : ImVec2(hover_extend, 0.0f)); + ButtonBehavior(bb_interact, id, &hovered, &held, ImGuiButtonFlags_FlattenChildren | ImGuiButtonFlags_AllowItemOverlap); + if (g.ActiveId != id) + SetItemAllowOverlap(); + + if (held || (g.HoveredId == id && g.HoveredIdPreviousFrame == id && g.HoveredIdTimer >= hover_visibility_delay)) + SetMouseCursor(axis == ImGuiAxis_Y ? ImGuiMouseCursor_ResizeNS : ImGuiMouseCursor_ResizeEW); + + ImRect bb_render = bb; + if (held) + { + ImVec2 mouse_delta_2d = g.IO.MousePos - g.ActiveIdClickOffset - bb_interact.Min; + float mouse_delta = (axis == ImGuiAxis_Y) ? mouse_delta_2d.y : mouse_delta_2d.x; + + // Minimum pane size + float size_1_maximum_delta = ImMax(0.0f, *size1 - min_size1); + float size_2_maximum_delta = ImMax(0.0f, *size2 - min_size2); + if (mouse_delta < -size_1_maximum_delta) + mouse_delta = -size_1_maximum_delta; + if (mouse_delta > size_2_maximum_delta) + mouse_delta = size_2_maximum_delta; + + // Apply resize + if (mouse_delta != 0.0f) + { + if (mouse_delta < 0.0f) + IM_ASSERT(*size1 + mouse_delta >= min_size1); + if (mouse_delta > 0.0f) + IM_ASSERT(*size2 - mouse_delta >= min_size2); + *size1 += mouse_delta; + *size2 -= mouse_delta; + bb_render.Translate((axis == ImGuiAxis_X) ? ImVec2(mouse_delta, 0.0f) : ImVec2(0.0f, mouse_delta)); + MarkItemEdited(id); + } + } + + // Render + const ImU32 col = GetColorU32(held ? ImGuiCol_SeparatorActive : (hovered && g.HoveredIdTimer >= hover_visibility_delay) ? ImGuiCol_SeparatorHovered : ImGuiCol_Separator); + window->DrawList->AddRectFilled(bb_render.Min, bb_render.Max, col, 0.0f); + + return held; +} + +static int IMGUI_CDECL ShrinkWidthItemComparer(const void* lhs, const void* rhs) +{ + const ImGuiShrinkWidthItem* a = (const ImGuiShrinkWidthItem*)lhs; + const ImGuiShrinkWidthItem* b = (const ImGuiShrinkWidthItem*)rhs; + if (int d = (int)(b->Width - a->Width)) + return d; + return (b->Index - a->Index); +} + +// Shrink excess width from a set of item, by removing width from the larger items first. +void ImGui::ShrinkWidths(ImGuiShrinkWidthItem* items, int count, float width_excess) +{ + if (count == 1) + { + items[0].Width = ImMax(items[0].Width - width_excess, 1.0f); + return; + } + ImQsort(items, (size_t)count, sizeof(ImGuiShrinkWidthItem), ShrinkWidthItemComparer); + int count_same_width = 1; + while (width_excess > 0.0f && count_same_width < count) + { + while (count_same_width < count && items[0].Width <= items[count_same_width].Width) + count_same_width++; + float max_width_to_remove_per_item = (count_same_width < count) ? (items[0].Width - items[count_same_width].Width) : (items[0].Width - 1.0f); + float width_to_remove_per_item = ImMin(width_excess / count_same_width, max_width_to_remove_per_item); + for (int item_n = 0; item_n < count_same_width; item_n++) + items[item_n].Width -= width_to_remove_per_item; + width_excess -= width_to_remove_per_item * count_same_width; + } + + // Round width and redistribute remainder left-to-right (could make it an option of the function?) + // Ensure that e.g. the right-most tab of a shrunk tab-bar always reaches exactly at the same distance from the right-most edge of the tab bar separator. + width_excess = 0.0f; + for (int n = 0; n < count; n++) + { + float width_rounded = ImFloor(items[n].Width); + width_excess += items[n].Width - width_rounded; + items[n].Width = width_rounded; + } + if (width_excess > 0.0f) + for (int n = 0; n < count; n++) + if (items[n].Index < (int)(width_excess + 0.01f)) + items[n].Width += 1.0f; +} + +//------------------------------------------------------------------------- +// [SECTION] Widgets: ComboBox +//------------------------------------------------------------------------- +// - BeginCombo() +// - EndCombo() +// - Combo() +//------------------------------------------------------------------------- + +static float CalcMaxPopupHeightFromItemCount(int items_count) +{ + ImGuiContext& g = *GImGui; + if (items_count <= 0) + return FLT_MAX; + return (g.FontSize + g.Style.ItemSpacing.y) * items_count - g.Style.ItemSpacing.y + (g.Style.WindowPadding.y * 2); +} + +bool ImGui::BeginCombo(const char* label, const char* preview_value, ImGuiComboFlags flags) +{ + // Always consume the SetNextWindowSizeConstraint() call in our early return paths + ImGuiContext& g = *GImGui; + bool has_window_size_constraint = (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSizeConstraint) != 0; + g.NextWindowData.Flags &= ~ImGuiNextWindowDataFlags_HasSizeConstraint; + + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + IM_ASSERT((flags & (ImGuiComboFlags_NoArrowButton | ImGuiComboFlags_NoPreview)) != (ImGuiComboFlags_NoArrowButton | ImGuiComboFlags_NoPreview)); // Can't use both flags together + + const ImGuiStyle& style = g.Style; + const ImGuiID id = window->GetID(label); + + const float arrow_size = (flags & ImGuiComboFlags_NoArrowButton) ? 0.0f : GetFrameHeight(); + const ImVec2 label_size = CalcTextSize(label, NULL, true); + const float expected_w = CalcItemWidth(); + const float w = (flags & ImGuiComboFlags_NoPreview) ? arrow_size : expected_w; + const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y + style.FramePadding.y*2.0f)); + const ImRect total_bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f)); + ItemSize(total_bb, style.FramePadding.y); + if (!ItemAdd(total_bb, id, &frame_bb)) + return false; + + bool hovered, held; + bool pressed = ButtonBehavior(frame_bb, id, &hovered, &held); + bool popup_open = IsPopupOpen(id); + + const ImU32 frame_col = GetColorU32(hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg); + const float value_x2 = ImMax(frame_bb.Min.x, frame_bb.Max.x - arrow_size); + RenderNavHighlight(frame_bb, id); + if (!(flags & ImGuiComboFlags_NoPreview)) + window->DrawList->AddRectFilled(frame_bb.Min, ImVec2(value_x2, frame_bb.Max.y), frame_col, style.FrameRounding, (flags & ImGuiComboFlags_NoArrowButton) ? ImDrawCornerFlags_All : ImDrawCornerFlags_Left); + if (!(flags & ImGuiComboFlags_NoArrowButton)) + { + ImU32 bg_col = GetColorU32((popup_open || hovered) ? ImGuiCol_ButtonHovered : ImGuiCol_Button); + ImU32 text_col = GetColorU32(ImGuiCol_Text); + window->DrawList->AddRectFilled(ImVec2(value_x2, frame_bb.Min.y), frame_bb.Max, bg_col, style.FrameRounding, (w <= arrow_size) ? ImDrawCornerFlags_All : ImDrawCornerFlags_Right); + if (value_x2 + arrow_size - style.FramePadding.x <= frame_bb.Max.x) + RenderArrow(window->DrawList, ImVec2(value_x2 + style.FramePadding.y, frame_bb.Min.y + style.FramePadding.y), text_col, ImGuiDir_Down, 1.0f); + } + RenderFrameBorder(frame_bb.Min, frame_bb.Max, style.FrameRounding); + if (preview_value != NULL && !(flags & ImGuiComboFlags_NoPreview)) + RenderTextClipped(frame_bb.Min + style.FramePadding, ImVec2(value_x2, frame_bb.Max.y), preview_value, NULL, NULL, ImVec2(0.0f,0.0f)); + if (label_size.x > 0) + RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label); + + if ((pressed || g.NavActivateId == id) && !popup_open) + { + if (window->DC.NavLayerCurrent == 0) + window->NavLastIds[0] = id; + OpenPopupEx(id); + popup_open = true; + } + + if (!popup_open) + return false; + + if (has_window_size_constraint) + { + g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasSizeConstraint; + g.NextWindowData.SizeConstraintRect.Min.x = ImMax(g.NextWindowData.SizeConstraintRect.Min.x, w); + } + else + { + if ((flags & ImGuiComboFlags_HeightMask_) == 0) + flags |= ImGuiComboFlags_HeightRegular; + IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiComboFlags_HeightMask_)); // Only one + int popup_max_height_in_items = -1; + if (flags & ImGuiComboFlags_HeightRegular) popup_max_height_in_items = 8; + else if (flags & ImGuiComboFlags_HeightSmall) popup_max_height_in_items = 4; + else if (flags & ImGuiComboFlags_HeightLarge) popup_max_height_in_items = 20; + SetNextWindowSizeConstraints(ImVec2(w, 0.0f), ImVec2(FLT_MAX, CalcMaxPopupHeightFromItemCount(popup_max_height_in_items))); + } + + char name[16]; + ImFormatString(name, IM_ARRAYSIZE(name), "##Combo_%02d", g.BeginPopupStack.Size); // Recycle windows based on depth + + // Peak into expected window size so we can position it + if (ImGuiWindow* popup_window = FindWindowByName(name)) + if (popup_window->WasActive) + { + ImVec2 size_expected = CalcWindowExpectedSize(popup_window); + if (flags & ImGuiComboFlags_PopupAlignLeft) + popup_window->AutoPosLastDirection = ImGuiDir_Left; + ImRect r_outer = GetWindowAllowedExtentRect(popup_window); + ImVec2 pos = FindBestWindowPosForPopupEx(frame_bb.GetBL(), size_expected, &popup_window->AutoPosLastDirection, r_outer, frame_bb, ImGuiPopupPositionPolicy_ComboBox); + SetNextWindowPos(pos); + } + + // We don't use BeginPopupEx() solely because we have a custom name string, which we could make an argument to BeginPopupEx() + ImGuiWindowFlags window_flags = ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_Popup | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoMove; + + // Horizontally align ourselves with the framed text + PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(style.FramePadding.x, style.WindowPadding.y)); + bool ret = Begin(name, NULL, window_flags); + PopStyleVar(); + if (!ret) + { + EndPopup(); + IM_ASSERT(0); // This should never happen as we tested for IsPopupOpen() above + return false; + } + return true; +} + +void ImGui::EndCombo() +{ + EndPopup(); +} + +// Getter for the old Combo() API: const char*[] +static bool Items_ArrayGetter(void* data, int idx, const char** out_text) +{ + const char* const* items = (const char* const*)data; + if (out_text) + *out_text = items[idx]; + return true; +} + +// Getter for the old Combo() API: "item1\0item2\0item3\0" +static bool Items_SingleStringGetter(void* data, int idx, const char** out_text) +{ + // FIXME-OPT: we could pre-compute the indices to fasten this. But only 1 active combo means the waste is limited. + const char* items_separated_by_zeros = (const char*)data; + int items_count = 0; + const char* p = items_separated_by_zeros; + while (*p) + { + if (idx == items_count) + break; + p += strlen(p) + 1; + items_count++; + } + if (!*p) + return false; + if (out_text) + *out_text = p; + return true; +} + +// Old API, prefer using BeginCombo() nowadays if you can. +bool ImGui::Combo(const char* label, int* current_item, bool (*items_getter)(void*, int, const char**), void* data, int items_count, int popup_max_height_in_items) +{ + ImGuiContext& g = *GImGui; + + // Call the getter to obtain the preview string which is a parameter to BeginCombo() + const char* preview_value = NULL; + if (*current_item >= 0 && *current_item < items_count) + items_getter(data, *current_item, &preview_value); + + // The old Combo() API exposed "popup_max_height_in_items". The new more general BeginCombo() API doesn't have/need it, but we emulate it here. + if (popup_max_height_in_items != -1 && !(g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSizeConstraint)) + SetNextWindowSizeConstraints(ImVec2(0,0), ImVec2(FLT_MAX, CalcMaxPopupHeightFromItemCount(popup_max_height_in_items))); + + if (!BeginCombo(label, preview_value, ImGuiComboFlags_None)) + return false; + + // Display items + // FIXME-OPT: Use clipper (but we need to disable it on the appearing frame to make sure our call to SetItemDefaultFocus() is processed) + bool value_changed = false; + for (int i = 0; i < items_count; i++) + { + PushID((void*)(intptr_t)i); + const bool item_selected = (i == *current_item); + const char* item_text; + if (!items_getter(data, i, &item_text)) + item_text = "*Unknown item*"; + if (Selectable(item_text, item_selected)) + { + value_changed = true; + *current_item = i; + } + if (item_selected) + SetItemDefaultFocus(); + PopID(); + } + + EndCombo(); + return value_changed; +} + +// Combo box helper allowing to pass an array of strings. +bool ImGui::Combo(const char* label, int* current_item, const char* const items[], int items_count, int height_in_items) +{ + const bool value_changed = Combo(label, current_item, Items_ArrayGetter, (void*)items, items_count, height_in_items); + return value_changed; +} + +// Combo box helper allowing to pass all items in a single string literal holding multiple zero-terminated items "item1\0item2\0" +bool ImGui::Combo(const char* label, int* current_item, const char* items_separated_by_zeros, int height_in_items) +{ + int items_count = 0; + const char* p = items_separated_by_zeros; // FIXME-OPT: Avoid computing this, or at least only when combo is open + while (*p) + { + p += strlen(p) + 1; + items_count++; + } + bool value_changed = Combo(label, current_item, Items_SingleStringGetter, (void*)items_separated_by_zeros, items_count, height_in_items); + return value_changed; +} + +//------------------------------------------------------------------------- +// [SECTION] Data Type and Data Formatting Helpers [Internal] +//------------------------------------------------------------------------- +// - PatchFormatStringFloatToInt() +// - DataTypeGetInfo() +// - DataTypeFormatString() +// - DataTypeApplyOp() +// - DataTypeApplyOpFromText() +// - DataTypeClamp() +// - GetMinimumStepAtDecimalPrecision +// - RoundScalarWithFormat<>() +//------------------------------------------------------------------------- + +static const ImGuiDataTypeInfo GDataTypeInfo[] = +{ + { sizeof(char), "%d", "%d" }, // ImGuiDataType_S8 + { sizeof(unsigned char), "%u", "%u" }, + { sizeof(short), "%d", "%d" }, // ImGuiDataType_S16 + { sizeof(unsigned short), "%u", "%u" }, + { sizeof(int), "%d", "%d" }, // ImGuiDataType_S32 + { sizeof(unsigned int), "%u", "%u" }, +#ifdef _MSC_VER + { sizeof(ImS64), "%I64d","%I64d" }, // ImGuiDataType_S64 + { sizeof(ImU64), "%I64u","%I64u" }, +#else + { sizeof(ImS64), "%lld", "%lld" }, // ImGuiDataType_S64 + { sizeof(ImU64), "%llu", "%llu" }, +#endif + { sizeof(float), "%f", "%f" }, // ImGuiDataType_Float (float are promoted to double in va_arg) + { sizeof(double), "%f", "%lf" }, // ImGuiDataType_Double +}; +IM_STATIC_ASSERT(IM_ARRAYSIZE(GDataTypeInfo) == ImGuiDataType_COUNT); + +// FIXME-LEGACY: Prior to 1.61 our DragInt() function internally used floats and because of this the compile-time default value for format was "%.0f". +// Even though we changed the compile-time default, we expect users to have carried %f around, which would break the display of DragInt() calls. +// To honor backward compatibility we are rewriting the format string, unless IMGUI_DISABLE_OBSOLETE_FUNCTIONS is enabled. What could possibly go wrong?! +static const char* PatchFormatStringFloatToInt(const char* fmt) +{ + if (fmt[0] == '%' && fmt[1] == '.' && fmt[2] == '0' && fmt[3] == 'f' && fmt[4] == 0) // Fast legacy path for "%.0f" which is expected to be the most common case. + return "%d"; + const char* fmt_start = ImParseFormatFindStart(fmt); // Find % (if any, and ignore %%) + const char* fmt_end = ImParseFormatFindEnd(fmt_start); // Find end of format specifier, which itself is an exercise of confidence/recklessness (because snprintf is dependent on libc or user). + if (fmt_end > fmt_start && fmt_end[-1] == 'f') + { +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + if (fmt_start == fmt && fmt_end[0] == 0) + return "%d"; + ImGuiContext& g = *GImGui; + ImFormatString(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), "%.*s%%d%s", (int)(fmt_start - fmt), fmt, fmt_end); // Honor leading and trailing decorations, but lose alignment/precision. + return g.TempBuffer; +#else + IM_ASSERT(0 && "DragInt(): Invalid format string!"); // Old versions used a default parameter of "%.0f", please replace with e.g. "%d" +#endif + } + return fmt; +} + +const ImGuiDataTypeInfo* ImGui::DataTypeGetInfo(ImGuiDataType data_type) +{ + IM_ASSERT(data_type >= 0 && data_type < ImGuiDataType_COUNT); + return &GDataTypeInfo[data_type]; +} + +int ImGui::DataTypeFormatString(char* buf, int buf_size, ImGuiDataType data_type, const void* p_data, const char* format) +{ + // Signedness doesn't matter when pushing integer arguments + if (data_type == ImGuiDataType_S32 || data_type == ImGuiDataType_U32) + return ImFormatString(buf, buf_size, format, *(const ImU32*)p_data); + if (data_type == ImGuiDataType_S64 || data_type == ImGuiDataType_U64) + return ImFormatString(buf, buf_size, format, *(const ImU64*)p_data); + if (data_type == ImGuiDataType_Float) + return ImFormatString(buf, buf_size, format, *(const float*)p_data); + if (data_type == ImGuiDataType_Double) + return ImFormatString(buf, buf_size, format, *(const double*)p_data); + if (data_type == ImGuiDataType_S8) + return ImFormatString(buf, buf_size, format, *(const ImS8*)p_data); + if (data_type == ImGuiDataType_U8) + return ImFormatString(buf, buf_size, format, *(const ImU8*)p_data); + if (data_type == ImGuiDataType_S16) + return ImFormatString(buf, buf_size, format, *(const ImS16*)p_data); + if (data_type == ImGuiDataType_U16) + return ImFormatString(buf, buf_size, format, *(const ImU16*)p_data); + IM_ASSERT(0); + return 0; +} + +void ImGui::DataTypeApplyOp(ImGuiDataType data_type, int op, void* output, void* arg1, const void* arg2) +{ + IM_ASSERT(op == '+' || op == '-'); + switch (data_type) + { + case ImGuiDataType_S8: + if (op == '+') { *(ImS8*)output = ImAddClampOverflow(*(const ImS8*)arg1, *(const ImS8*)arg2, IM_S8_MIN, IM_S8_MAX); } + if (op == '-') { *(ImS8*)output = ImSubClampOverflow(*(const ImS8*)arg1, *(const ImS8*)arg2, IM_S8_MIN, IM_S8_MAX); } + return; + case ImGuiDataType_U8: + if (op == '+') { *(ImU8*)output = ImAddClampOverflow(*(const ImU8*)arg1, *(const ImU8*)arg2, IM_U8_MIN, IM_U8_MAX); } + if (op == '-') { *(ImU8*)output = ImSubClampOverflow(*(const ImU8*)arg1, *(const ImU8*)arg2, IM_U8_MIN, IM_U8_MAX); } + return; + case ImGuiDataType_S16: + if (op == '+') { *(ImS16*)output = ImAddClampOverflow(*(const ImS16*)arg1, *(const ImS16*)arg2, IM_S16_MIN, IM_S16_MAX); } + if (op == '-') { *(ImS16*)output = ImSubClampOverflow(*(const ImS16*)arg1, *(const ImS16*)arg2, IM_S16_MIN, IM_S16_MAX); } + return; + case ImGuiDataType_U16: + if (op == '+') { *(ImU16*)output = ImAddClampOverflow(*(const ImU16*)arg1, *(const ImU16*)arg2, IM_U16_MIN, IM_U16_MAX); } + if (op == '-') { *(ImU16*)output = ImSubClampOverflow(*(const ImU16*)arg1, *(const ImU16*)arg2, IM_U16_MIN, IM_U16_MAX); } + return; + case ImGuiDataType_S32: + if (op == '+') { *(ImS32*)output = ImAddClampOverflow(*(const ImS32*)arg1, *(const ImS32*)arg2, IM_S32_MIN, IM_S32_MAX); } + if (op == '-') { *(ImS32*)output = ImSubClampOverflow(*(const ImS32*)arg1, *(const ImS32*)arg2, IM_S32_MIN, IM_S32_MAX); } + return; + case ImGuiDataType_U32: + if (op == '+') { *(ImU32*)output = ImAddClampOverflow(*(const ImU32*)arg1, *(const ImU32*)arg2, IM_U32_MIN, IM_U32_MAX); } + if (op == '-') { *(ImU32*)output = ImSubClampOverflow(*(const ImU32*)arg1, *(const ImU32*)arg2, IM_U32_MIN, IM_U32_MAX); } + return; + case ImGuiDataType_S64: + if (op == '+') { *(ImS64*)output = ImAddClampOverflow(*(const ImS64*)arg1, *(const ImS64*)arg2, IM_S64_MIN, IM_S64_MAX); } + if (op == '-') { *(ImS64*)output = ImSubClampOverflow(*(const ImS64*)arg1, *(const ImS64*)arg2, IM_S64_MIN, IM_S64_MAX); } + return; + case ImGuiDataType_U64: + if (op == '+') { *(ImU64*)output = ImAddClampOverflow(*(const ImU64*)arg1, *(const ImU64*)arg2, IM_U64_MIN, IM_U64_MAX); } + if (op == '-') { *(ImU64*)output = ImSubClampOverflow(*(const ImU64*)arg1, *(const ImU64*)arg2, IM_U64_MIN, IM_U64_MAX); } + return; + case ImGuiDataType_Float: + if (op == '+') { *(float*)output = *(const float*)arg1 + *(const float*)arg2; } + if (op == '-') { *(float*)output = *(const float*)arg1 - *(const float*)arg2; } + return; + case ImGuiDataType_Double: + if (op == '+') { *(double*)output = *(const double*)arg1 + *(const double*)arg2; } + if (op == '-') { *(double*)output = *(const double*)arg1 - *(const double*)arg2; } + return; + case ImGuiDataType_COUNT: break; + } + IM_ASSERT(0); +} + +// User can input math operators (e.g. +100) to edit a numerical values. +// NB: This is _not_ a full expression evaluator. We should probably add one and replace this dumb mess.. +bool ImGui::DataTypeApplyOpFromText(const char* buf, const char* initial_value_buf, ImGuiDataType data_type, void* p_data, const char* format) +{ + while (ImCharIsBlankA(*buf)) + buf++; + + // We don't support '-' op because it would conflict with inputing negative value. + // Instead you can use +-100 to subtract from an existing value + char op = buf[0]; + if (op == '+' || op == '*' || op == '/') + { + buf++; + while (ImCharIsBlankA(*buf)) + buf++; + } + else + { + op = 0; + } + if (!buf[0]) + return false; + + // Copy the value in an opaque buffer so we can compare at the end of the function if it changed at all. + const ImGuiDataTypeInfo* type_info = DataTypeGetInfo(data_type); + ImGuiDataTypeTempStorage data_backup; + memcpy(&data_backup, p_data, type_info->Size); + + if (format == NULL) + format = type_info->ScanFmt; + + // FIXME-LEGACY: The aim is to remove those operators and write a proper expression evaluator at some point.. + int arg1i = 0; + if (data_type == ImGuiDataType_S32) + { + int* v = (int*)p_data; + int arg0i = *v; + float arg1f = 0.0f; + if (op && sscanf(initial_value_buf, format, &arg0i) < 1) + return false; + // Store operand in a float so we can use fractional value for multipliers (*1.1), but constant always parsed as integer so we can fit big integers (e.g. 2000000003) past float precision + if (op == '+') { if (sscanf(buf, "%d", &arg1i)) *v = (int)(arg0i + arg1i); } // Add (use "+-" to subtract) + else if (op == '*') { if (sscanf(buf, "%f", &arg1f)) *v = (int)(arg0i * arg1f); } // Multiply + else if (op == '/') { if (sscanf(buf, "%f", &arg1f) && arg1f != 0.0f) *v = (int)(arg0i / arg1f); } // Divide + else { if (sscanf(buf, format, &arg1i) == 1) *v = arg1i; } // Assign constant + } + else if (data_type == ImGuiDataType_Float) + { + // For floats we have to ignore format with precision (e.g. "%.2f") because sscanf doesn't take them in + format = "%f"; + float* v = (float*)p_data; + float arg0f = *v, arg1f = 0.0f; + if (op && sscanf(initial_value_buf, format, &arg0f) < 1) + return false; + if (sscanf(buf, format, &arg1f) < 1) + return false; + if (op == '+') { *v = arg0f + arg1f; } // Add (use "+-" to subtract) + else if (op == '*') { *v = arg0f * arg1f; } // Multiply + else if (op == '/') { if (arg1f != 0.0f) *v = arg0f / arg1f; } // Divide + else { *v = arg1f; } // Assign constant + } + else if (data_type == ImGuiDataType_Double) + { + format = "%lf"; // scanf differentiate float/double unlike printf which forces everything to double because of ellipsis + double* v = (double*)p_data; + double arg0f = *v, arg1f = 0.0; + if (op && sscanf(initial_value_buf, format, &arg0f) < 1) + return false; + if (sscanf(buf, format, &arg1f) < 1) + return false; + if (op == '+') { *v = arg0f + arg1f; } // Add (use "+-" to subtract) + else if (op == '*') { *v = arg0f * arg1f; } // Multiply + else if (op == '/') { if (arg1f != 0.0f) *v = arg0f / arg1f; } // Divide + else { *v = arg1f; } // Assign constant + } + else if (data_type == ImGuiDataType_U32 || data_type == ImGuiDataType_S64 || data_type == ImGuiDataType_U64) + { + // All other types assign constant + // We don't bother handling support for legacy operators since they are a little too crappy. Instead we will later implement a proper expression evaluator in the future. + sscanf(buf, format, p_data); + } + else + { + // Small types need a 32-bit buffer to receive the result from scanf() + int v32; + sscanf(buf, format, &v32); + if (data_type == ImGuiDataType_S8) + *(ImS8*)p_data = (ImS8)ImClamp(v32, (int)IM_S8_MIN, (int)IM_S8_MAX); + else if (data_type == ImGuiDataType_U8) + *(ImU8*)p_data = (ImU8)ImClamp(v32, (int)IM_U8_MIN, (int)IM_U8_MAX); + else if (data_type == ImGuiDataType_S16) + *(ImS16*)p_data = (ImS16)ImClamp(v32, (int)IM_S16_MIN, (int)IM_S16_MAX); + else if (data_type == ImGuiDataType_U16) + *(ImU16*)p_data = (ImU16)ImClamp(v32, (int)IM_U16_MIN, (int)IM_U16_MAX); + else + IM_ASSERT(0); + } + + return memcmp(&data_backup, p_data, type_info->Size) != 0; +} + +template +static bool ClampBehaviorT(T* v, T v_min, T v_max) +{ + if (*v < v_min) { *v = v_min; return true; } + if (*v > v_max) { *v = v_max; return true; } + return false; +} + +bool ImGui::DataTypeClamp(ImGuiDataType data_type, void* p_data, const void* p_min, const void* p_max) +{ + switch (data_type) + { + case ImGuiDataType_S8: return ClampBehaviorT((ImS8* )p_data, *(const ImS8* )p_min, *(const ImS8* )p_max); + case ImGuiDataType_U8: return ClampBehaviorT((ImU8* )p_data, *(const ImU8* )p_min, *(const ImU8* )p_max); + case ImGuiDataType_S16: return ClampBehaviorT((ImS16* )p_data, *(const ImS16* )p_min, *(const ImS16* )p_max); + case ImGuiDataType_U16: return ClampBehaviorT((ImU16* )p_data, *(const ImU16* )p_min, *(const ImU16* )p_max); + case ImGuiDataType_S32: return ClampBehaviorT((ImS32* )p_data, *(const ImS32* )p_min, *(const ImS32* )p_max); + case ImGuiDataType_U32: return ClampBehaviorT((ImU32* )p_data, *(const ImU32* )p_min, *(const ImU32* )p_max); + case ImGuiDataType_S64: return ClampBehaviorT((ImS64* )p_data, *(const ImS64* )p_min, *(const ImS64* )p_max); + case ImGuiDataType_U64: return ClampBehaviorT((ImU64* )p_data, *(const ImU64* )p_min, *(const ImU64* )p_max); + case ImGuiDataType_Float: return ClampBehaviorT((float* )p_data, *(const float* )p_min, *(const float* )p_max); + case ImGuiDataType_Double: return ClampBehaviorT((double*)p_data, *(const double*)p_min, *(const double*)p_max); + case ImGuiDataType_COUNT: break; + } + IM_ASSERT(0); + return false; +} + +static float GetMinimumStepAtDecimalPrecision(int decimal_precision) +{ + static const float min_steps[10] = { 1.0f, 0.1f, 0.01f, 0.001f, 0.0001f, 0.00001f, 0.000001f, 0.0000001f, 0.00000001f, 0.000000001f }; + if (decimal_precision < 0) + return FLT_MIN; + return (decimal_precision < IM_ARRAYSIZE(min_steps)) ? min_steps[decimal_precision] : ImPow(10.0f, (float)-decimal_precision); +} + +template +static const char* ImAtoi(const char* src, TYPE* output) +{ + int negative = 0; + if (*src == '-') { negative = 1; src++; } + if (*src == '+') { src++; } + TYPE v = 0; + while (*src >= '0' && *src <= '9') + v = (v * 10) + (*src++ - '0'); + *output = negative ? -v : v; + return src; +} + +template +TYPE ImGui::RoundScalarWithFormatT(const char* format, ImGuiDataType data_type, TYPE v) +{ + const char* fmt_start = ImParseFormatFindStart(format); + if (fmt_start[0] != '%' || fmt_start[1] == '%') // Don't apply if the value is not visible in the format string + return v; + char v_str[64]; + ImFormatString(v_str, IM_ARRAYSIZE(v_str), fmt_start, v); + const char* p = v_str; + while (*p == ' ') + p++; + if (data_type == ImGuiDataType_Float || data_type == ImGuiDataType_Double) + v = (TYPE)ImAtof(p); + else + ImAtoi(p, (SIGNEDTYPE*)&v); + return v; +} + +//------------------------------------------------------------------------- +// [SECTION] Widgets: DragScalar, DragFloat, DragInt, etc. +//------------------------------------------------------------------------- +// - DragBehaviorT<>() [Internal] +// - DragBehavior() [Internal] +// - DragScalar() +// - DragScalarN() +// - DragFloat() +// - DragFloat2() +// - DragFloat3() +// - DragFloat4() +// - DragFloatRange2() +// - DragInt() +// - DragInt2() +// - DragInt3() +// - DragInt4() +// - DragIntRange2() +//------------------------------------------------------------------------- + +// This is called by DragBehavior() when the widget is active (held by mouse or being manipulated with Nav controls) +template +bool ImGui::DragBehaviorT(ImGuiDataType data_type, TYPE* v, float v_speed, const TYPE v_min, const TYPE v_max, const char* format, float power, ImGuiDragFlags flags) +{ + ImGuiContext& g = *GImGui; + const ImGuiAxis axis = (flags & ImGuiDragFlags_Vertical) ? ImGuiAxis_Y : ImGuiAxis_X; + const bool is_decimal = (data_type == ImGuiDataType_Float) || (data_type == ImGuiDataType_Double); + const bool is_clamped = (v_min < v_max); + const bool is_power = (power != 1.0f && is_decimal && is_clamped && (v_max - v_min < FLT_MAX)); + const bool is_locked = (v_min > v_max); + if (is_locked) + return false; + + // Default tweak speed + if (v_speed == 0.0f && is_clamped && (v_max - v_min < FLT_MAX)) + v_speed = (float)((v_max - v_min) * g.DragSpeedDefaultRatio); + + // Inputs accumulates into g.DragCurrentAccum, which is flushed into the current value as soon as it makes a difference with our precision settings + float adjust_delta = 0.0f; + if (g.ActiveIdSource == ImGuiInputSource_Mouse && IsMousePosValid() && g.IO.MouseDragMaxDistanceSqr[0] > 1.0f*1.0f) + { + adjust_delta = g.IO.MouseDelta[axis]; + if (g.IO.KeyAlt) + adjust_delta *= 1.0f / 100.0f; + if (g.IO.KeyShift) + adjust_delta *= 10.0f; + } + else if (g.ActiveIdSource == ImGuiInputSource_Nav) + { + int decimal_precision = is_decimal ? ImParseFormatPrecision(format, 3) : 0; + adjust_delta = GetNavInputAmount2d(ImGuiNavDirSourceFlags_Keyboard | ImGuiNavDirSourceFlags_PadDPad, ImGuiInputReadMode_RepeatFast, 1.0f / 10.0f, 10.0f)[axis]; + v_speed = ImMax(v_speed, GetMinimumStepAtDecimalPrecision(decimal_precision)); + } + adjust_delta *= v_speed; + + // For vertical drag we currently assume that Up=higher value (like we do with vertical sliders). This may become a parameter. + if (axis == ImGuiAxis_Y) + adjust_delta = -adjust_delta; + + // Clear current value on activation + // Avoid altering values and clamping when we are _already_ past the limits and heading in the same direction, so e.g. if range is 0..255, current value is 300 and we are pushing to the right side, keep the 300. + bool is_just_activated = g.ActiveIdIsJustActivated; + bool is_already_past_limits_and_pushing_outward = is_clamped && ((*v >= v_max && adjust_delta > 0.0f) || (*v <= v_min && adjust_delta < 0.0f)); + bool is_drag_direction_change_with_power = is_power && ((adjust_delta < 0 && g.DragCurrentAccum > 0) || (adjust_delta > 0 && g.DragCurrentAccum < 0)); + if (is_just_activated || is_already_past_limits_and_pushing_outward || is_drag_direction_change_with_power) + { + g.DragCurrentAccum = 0.0f; + g.DragCurrentAccumDirty = false; + } + else if (adjust_delta != 0.0f) + { + g.DragCurrentAccum += adjust_delta; + g.DragCurrentAccumDirty = true; + } + + if (!g.DragCurrentAccumDirty) + return false; + + TYPE v_cur = *v; + FLOATTYPE v_old_ref_for_accum_remainder = (FLOATTYPE)0.0f; + + if (is_power) + { + // Offset + round to user desired precision, with a curve on the v_min..v_max range to get more precision on one side of the range + FLOATTYPE v_old_norm_curved = ImPow((FLOATTYPE)(v_cur - v_min) / (FLOATTYPE)(v_max - v_min), (FLOATTYPE)1.0f / power); + FLOATTYPE v_new_norm_curved = v_old_norm_curved + (g.DragCurrentAccum / (v_max - v_min)); + v_cur = v_min + (SIGNEDTYPE)ImPow(ImSaturate((float)v_new_norm_curved), power) * (v_max - v_min); + v_old_ref_for_accum_remainder = v_old_norm_curved; + } + else + { + v_cur += (SIGNEDTYPE)g.DragCurrentAccum; + } + + // Round to user desired precision based on format string + v_cur = RoundScalarWithFormatT(format, data_type, v_cur); + + // Preserve remainder after rounding has been applied. This also allow slow tweaking of values. + g.DragCurrentAccumDirty = false; + if (is_power) + { + FLOATTYPE v_cur_norm_curved = ImPow((FLOATTYPE)(v_cur - v_min) / (FLOATTYPE)(v_max - v_min), (FLOATTYPE)1.0f / power); + g.DragCurrentAccum -= (float)(v_cur_norm_curved - v_old_ref_for_accum_remainder); + } + else + { + g.DragCurrentAccum -= (float)((SIGNEDTYPE)v_cur - (SIGNEDTYPE)*v); + } + + // Lose zero sign for float/double + if (v_cur == (TYPE)-0) + v_cur = (TYPE)0; + + // Clamp values (+ handle overflow/wrap-around for integer types) + if (*v != v_cur && is_clamped) + { + if (v_cur < v_min || (v_cur > *v && adjust_delta < 0.0f && !is_decimal)) + v_cur = v_min; + if (v_cur > v_max || (v_cur < *v && adjust_delta > 0.0f && !is_decimal)) + v_cur = v_max; + } + + // Apply result + if (*v == v_cur) + return false; + *v = v_cur; + return true; +} + +bool ImGui::DragBehavior(ImGuiID id, ImGuiDataType data_type, void* p_v, float v_speed, const void* p_min, const void* p_max, const char* format, float power, ImGuiDragFlags flags) +{ + ImGuiContext& g = *GImGui; + if (g.ActiveId == id) + { + if (g.ActiveIdSource == ImGuiInputSource_Mouse && !g.IO.MouseDown[0]) + ClearActiveID(); + else if (g.ActiveIdSource == ImGuiInputSource_Nav && g.NavActivatePressedId == id && !g.ActiveIdIsJustActivated) + ClearActiveID(); + } + if (g.ActiveId != id) + return false; + + switch (data_type) + { + case ImGuiDataType_S8: { ImS32 v32 = (ImS32)*(ImS8*)p_v; bool r = DragBehaviorT(ImGuiDataType_S32, &v32, v_speed, p_min ? *(const ImS8*) p_min : IM_S8_MIN, p_max ? *(const ImS8*)p_max : IM_S8_MAX, format, power, flags); if (r) *(ImS8*)p_v = (ImS8)v32; return r; } + case ImGuiDataType_U8: { ImU32 v32 = (ImU32)*(ImU8*)p_v; bool r = DragBehaviorT(ImGuiDataType_U32, &v32, v_speed, p_min ? *(const ImU8*) p_min : IM_U8_MIN, p_max ? *(const ImU8*)p_max : IM_U8_MAX, format, power, flags); if (r) *(ImU8*)p_v = (ImU8)v32; return r; } + case ImGuiDataType_S16: { ImS32 v32 = (ImS32)*(ImS16*)p_v; bool r = DragBehaviorT(ImGuiDataType_S32, &v32, v_speed, p_min ? *(const ImS16*)p_min : IM_S16_MIN, p_max ? *(const ImS16*)p_max : IM_S16_MAX, format, power, flags); if (r) *(ImS16*)p_v = (ImS16)v32; return r; } + case ImGuiDataType_U16: { ImU32 v32 = (ImU32)*(ImU16*)p_v; bool r = DragBehaviorT(ImGuiDataType_U32, &v32, v_speed, p_min ? *(const ImU16*)p_min : IM_U16_MIN, p_max ? *(const ImU16*)p_max : IM_U16_MAX, format, power, flags); if (r) *(ImU16*)p_v = (ImU16)v32; return r; } + case ImGuiDataType_S32: return DragBehaviorT(data_type, (ImS32*)p_v, v_speed, p_min ? *(const ImS32* )p_min : IM_S32_MIN, p_max ? *(const ImS32* )p_max : IM_S32_MAX, format, power, flags); + case ImGuiDataType_U32: return DragBehaviorT(data_type, (ImU32*)p_v, v_speed, p_min ? *(const ImU32* )p_min : IM_U32_MIN, p_max ? *(const ImU32* )p_max : IM_U32_MAX, format, power, flags); + case ImGuiDataType_S64: return DragBehaviorT(data_type, (ImS64*)p_v, v_speed, p_min ? *(const ImS64* )p_min : IM_S64_MIN, p_max ? *(const ImS64* )p_max : IM_S64_MAX, format, power, flags); + case ImGuiDataType_U64: return DragBehaviorT(data_type, (ImU64*)p_v, v_speed, p_min ? *(const ImU64* )p_min : IM_U64_MIN, p_max ? *(const ImU64* )p_max : IM_U64_MAX, format, power, flags); + case ImGuiDataType_Float: return DragBehaviorT(data_type, (float*)p_v, v_speed, p_min ? *(const float* )p_min : -FLT_MAX, p_max ? *(const float* )p_max : FLT_MAX, format, power, flags); + case ImGuiDataType_Double: return DragBehaviorT(data_type, (double*)p_v, v_speed, p_min ? *(const double*)p_min : -DBL_MAX, p_max ? *(const double*)p_max : DBL_MAX, format, power, flags); + case ImGuiDataType_COUNT: break; + } + IM_ASSERT(0); + return false; +} + +// Note: p_data, p_min and p_max are _pointers_ to a memory address holding the data. For a Drag widget, p_min and p_max are optional. +// Read code of e.g. SliderFloat(), SliderInt() etc. or examples in 'Demo->Widgets->Data Types' to understand how to use this function directly. +bool ImGui::DragScalar(const char* label, ImGuiDataType data_type, void* p_data, float v_speed, const void* p_min, const void* p_max, const char* format, float power) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + if (power != 1.0f) + IM_ASSERT(p_min != NULL && p_max != NULL); // When using a power curve the drag needs to have known bounds + + ImGuiContext& g = *GImGui; + const ImGuiStyle& style = g.Style; + const ImGuiID id = window->GetID(label); + const float w = CalcItemWidth(); + const ImVec2 label_size = CalcTextSize(label, NULL, true); + const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y + style.FramePadding.y*2.0f)); + const ImRect total_bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f)); + + ItemSize(total_bb, style.FramePadding.y); + if (!ItemAdd(total_bb, id, &frame_bb)) + return false; + + // Default format string when passing NULL + if (format == NULL) + format = DataTypeGetInfo(data_type)->PrintFmt; + else if (data_type == ImGuiDataType_S32 && strcmp(format, "%d") != 0) // (FIXME-LEGACY: Patch old "%.0f" format string to use "%d", read function more details.) + format = PatchFormatStringFloatToInt(format); + + // Tabbing or CTRL-clicking on Drag turns it into an input box + const bool hovered = ItemHoverable(frame_bb, id); + bool temp_input_is_active = TempInputIsActive(id); + bool temp_input_start = false; + if (!temp_input_is_active) + { + const bool focus_requested = FocusableItemRegister(window, id); + const bool clicked = (hovered && g.IO.MouseClicked[0]); + const bool double_clicked = (hovered && g.IO.MouseDoubleClicked[0]); + if (focus_requested || clicked || double_clicked || g.NavActivateId == id || g.NavInputId == id) + { + SetActiveID(id, window); + SetFocusID(id, window); + FocusWindow(window); + g.ActiveIdUsingNavDirMask = (1 << ImGuiDir_Left) | (1 << ImGuiDir_Right); + if (focus_requested || (clicked && g.IO.KeyCtrl) || double_clicked || g.NavInputId == id) + { + temp_input_start = true; + FocusableItemUnregister(window); + } + } + } + + // Our current specs do NOT clamp when using CTRL+Click manual input, but we should eventually add a flag for that.. + if (temp_input_is_active || temp_input_start) + return TempInputScalar(frame_bb, id, label, data_type, p_data, format);// , p_min, p_max); + + // Draw frame + const ImU32 frame_col = GetColorU32(g.ActiveId == id ? ImGuiCol_FrameBgActive : g.HoveredId == id ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg); + RenderNavHighlight(frame_bb, id); + RenderFrame(frame_bb.Min, frame_bb.Max, frame_col, true, style.FrameRounding); + + // Drag behavior + const bool value_changed = DragBehavior(id, data_type, p_data, v_speed, p_min, p_max, format, power, ImGuiDragFlags_None); + if (value_changed) + MarkItemEdited(id); + + // Display value using user-provided display format so user can add prefix/suffix/decorations to the value. + char value_buf[64]; + const char* value_buf_end = value_buf + DataTypeFormatString(value_buf, IM_ARRAYSIZE(value_buf), data_type, p_data, format); + RenderTextClipped(frame_bb.Min, frame_bb.Max, value_buf, value_buf_end, NULL, ImVec2(0.5f, 0.5f)); + + if (label_size.x > 0.0f) + RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label); + + IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.ItemFlags); + return value_changed; +} + +bool ImGui::DragScalarN(const char* label, ImGuiDataType data_type, void* p_data, int components, float v_speed, const void* p_min, const void* p_max, const char* format, float power) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + ImGuiContext& g = *GImGui; + bool value_changed = false; + BeginGroup(); + PushID(label); + PushMultiItemsWidths(components, CalcItemWidth()); + size_t type_size = GDataTypeInfo[data_type].Size; + for (int i = 0; i < components; i++) + { + PushID(i); + if (i > 0) + SameLine(0, g.Style.ItemInnerSpacing.x); + value_changed |= DragScalar("", data_type, p_data, v_speed, p_min, p_max, format, power); + PopID(); + PopItemWidth(); + p_data = (void*)((char*)p_data + type_size); + } + PopID(); + + const char* label_end = FindRenderedTextEnd(label); + if (label != label_end) + { + SameLine(0, g.Style.ItemInnerSpacing.x); + TextEx(label, label_end); + } + + EndGroup(); + return value_changed; +} + +bool ImGui::DragFloat(const char* label, float* v, float v_speed, float v_min, float v_max, const char* format, float power) +{ + return DragScalar(label, ImGuiDataType_Float, v, v_speed, &v_min, &v_max, format, power); +} + +bool ImGui::DragFloat2(const char* label, float v[2], float v_speed, float v_min, float v_max, const char* format, float power) +{ + return DragScalarN(label, ImGuiDataType_Float, v, 2, v_speed, &v_min, &v_max, format, power); +} + +bool ImGui::DragFloat3(const char* label, float v[3], float v_speed, float v_min, float v_max, const char* format, float power) +{ + return DragScalarN(label, ImGuiDataType_Float, v, 3, v_speed, &v_min, &v_max, format, power); +} + +bool ImGui::DragFloat4(const char* label, float v[4], float v_speed, float v_min, float v_max, const char* format, float power) +{ + return DragScalarN(label, ImGuiDataType_Float, v, 4, v_speed, &v_min, &v_max, format, power); +} + +bool ImGui::DragFloatRange2(const char* label, float* v_current_min, float* v_current_max, float v_speed, float v_min, float v_max, const char* format, const char* format_max, float power) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + ImGuiContext& g = *GImGui; + PushID(label); + BeginGroup(); + PushMultiItemsWidths(2, CalcItemWidth()); + + bool value_changed = DragFloat("##min", v_current_min, v_speed, (v_min >= v_max) ? -FLT_MAX : v_min, (v_min >= v_max) ? *v_current_max : ImMin(v_max, *v_current_max), format, power); + PopItemWidth(); + SameLine(0, g.Style.ItemInnerSpacing.x); + value_changed |= DragFloat("##max", v_current_max, v_speed, (v_min >= v_max) ? *v_current_min : ImMax(v_min, *v_current_min), (v_min >= v_max) ? FLT_MAX : v_max, format_max ? format_max : format, power); + PopItemWidth(); + SameLine(0, g.Style.ItemInnerSpacing.x); + + TextEx(label, FindRenderedTextEnd(label)); + EndGroup(); + PopID(); + return value_changed; +} + +// NB: v_speed is float to allow adjusting the drag speed with more precision +bool ImGui::DragInt(const char* label, int* v, float v_speed, int v_min, int v_max, const char* format) +{ + return DragScalar(label, ImGuiDataType_S32, v, v_speed, &v_min, &v_max, format); +} + +bool ImGui::DragInt2(const char* label, int v[2], float v_speed, int v_min, int v_max, const char* format) +{ + return DragScalarN(label, ImGuiDataType_S32, v, 2, v_speed, &v_min, &v_max, format); +} + +bool ImGui::DragInt3(const char* label, int v[3], float v_speed, int v_min, int v_max, const char* format) +{ + return DragScalarN(label, ImGuiDataType_S32, v, 3, v_speed, &v_min, &v_max, format); +} + +bool ImGui::DragInt4(const char* label, int v[4], float v_speed, int v_min, int v_max, const char* format) +{ + return DragScalarN(label, ImGuiDataType_S32, v, 4, v_speed, &v_min, &v_max, format); +} + +bool ImGui::DragIntRange2(const char* label, int* v_current_min, int* v_current_max, float v_speed, int v_min, int v_max, const char* format, const char* format_max) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + ImGuiContext& g = *GImGui; + PushID(label); + BeginGroup(); + PushMultiItemsWidths(2, CalcItemWidth()); + + bool value_changed = DragInt("##min", v_current_min, v_speed, (v_min >= v_max) ? INT_MIN : v_min, (v_min >= v_max) ? *v_current_max : ImMin(v_max, *v_current_max), format); + PopItemWidth(); + SameLine(0, g.Style.ItemInnerSpacing.x); + value_changed |= DragInt("##max", v_current_max, v_speed, (v_min >= v_max) ? *v_current_min : ImMax(v_min, *v_current_min), (v_min >= v_max) ? INT_MAX : v_max, format_max ? format_max : format); + PopItemWidth(); + SameLine(0, g.Style.ItemInnerSpacing.x); + + TextEx(label, FindRenderedTextEnd(label)); + EndGroup(); + PopID(); + + return value_changed; +} + +//------------------------------------------------------------------------- +// [SECTION] Widgets: SliderScalar, SliderFloat, SliderInt, etc. +//------------------------------------------------------------------------- +// - SliderBehaviorT<>() [Internal] +// - SliderBehavior() [Internal] +// - SliderScalar() +// - SliderScalarN() +// - SliderFloat() +// - SliderFloat2() +// - SliderFloat3() +// - SliderFloat4() +// - SliderAngle() +// - SliderInt() +// - SliderInt2() +// - SliderInt3() +// - SliderInt4() +// - VSliderScalar() +// - VSliderFloat() +// - VSliderInt() +//------------------------------------------------------------------------- + +template +float ImGui::SliderCalcRatioFromValueT(ImGuiDataType data_type, TYPE v, TYPE v_min, TYPE v_max, float power, float linear_zero_pos) +{ + if (v_min == v_max) + return 0.0f; + + const bool is_power = (power != 1.0f) && (data_type == ImGuiDataType_Float || data_type == ImGuiDataType_Double); + const TYPE v_clamped = (v_min < v_max) ? ImClamp(v, v_min, v_max) : ImClamp(v, v_max, v_min); + if (is_power) + { + if (v_clamped < 0.0f) + { + const float f = 1.0f - (float)((v_clamped - v_min) / (ImMin((TYPE)0, v_max) - v_min)); + return (1.0f - ImPow(f, 1.0f/power)) * linear_zero_pos; + } + else + { + const float f = (float)((v_clamped - ImMax((TYPE)0, v_min)) / (v_max - ImMax((TYPE)0, v_min))); + return linear_zero_pos + ImPow(f, 1.0f/power) * (1.0f - linear_zero_pos); + } + } + + // Linear slider + return (float)((FLOATTYPE)(v_clamped - v_min) / (FLOATTYPE)(v_max - v_min)); +} + +// FIXME: Move some of the code into SliderBehavior(). Current responsibility is larger than what the equivalent DragBehaviorT<> does, we also do some rendering, etc. +template +bool ImGui::SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_type, TYPE* v, const TYPE v_min, const TYPE v_max, const char* format, float power, ImGuiSliderFlags flags, ImRect* out_grab_bb) +{ + ImGuiContext& g = *GImGui; + const ImGuiStyle& style = g.Style; + + const ImGuiAxis axis = (flags & ImGuiSliderFlags_Vertical) ? ImGuiAxis_Y : ImGuiAxis_X; + const bool is_decimal = (data_type == ImGuiDataType_Float) || (data_type == ImGuiDataType_Double); + const bool is_power = (power != 1.0f) && is_decimal; + + const float grab_padding = 2.0f; + const float slider_sz = (bb.Max[axis] - bb.Min[axis]) - grab_padding * 2.0f; + float grab_sz = style.GrabMinSize; + SIGNEDTYPE v_range = (v_min < v_max ? v_max - v_min : v_min - v_max); + if (!is_decimal && v_range >= 0) // v_range < 0 may happen on integer overflows + grab_sz = ImMax((float)(slider_sz / (v_range + 1)), style.GrabMinSize); // For integer sliders: if possible have the grab size represent 1 unit + grab_sz = ImMin(grab_sz, slider_sz); + const float slider_usable_sz = slider_sz - grab_sz; + const float slider_usable_pos_min = bb.Min[axis] + grab_padding + grab_sz * 0.5f; + const float slider_usable_pos_max = bb.Max[axis] - grab_padding - grab_sz * 0.5f; + + // For power curve sliders that cross over sign boundary we want the curve to be symmetric around 0.0f + float linear_zero_pos; // 0.0->1.0f + if (is_power && v_min * v_max < 0.0f) + { + // Different sign + const FLOATTYPE linear_dist_min_to_0 = ImPow(v_min >= 0 ? (FLOATTYPE)v_min : -(FLOATTYPE)v_min, (FLOATTYPE)1.0f / power); + const FLOATTYPE linear_dist_max_to_0 = ImPow(v_max >= 0 ? (FLOATTYPE)v_max : -(FLOATTYPE)v_max, (FLOATTYPE)1.0f / power); + linear_zero_pos = (float)(linear_dist_min_to_0 / (linear_dist_min_to_0 + linear_dist_max_to_0)); + } + else + { + // Same sign + linear_zero_pos = v_min < 0.0f ? 1.0f : 0.0f; + } + + // Process interacting with the slider + bool value_changed = false; + if (g.ActiveId == id) + { + bool set_new_value = false; + float clicked_t = 0.0f; + if (g.ActiveIdSource == ImGuiInputSource_Mouse) + { + if (!g.IO.MouseDown[0]) + { + ClearActiveID(); + } + else + { + const float mouse_abs_pos = g.IO.MousePos[axis]; + clicked_t = (slider_usable_sz > 0.0f) ? ImClamp((mouse_abs_pos - slider_usable_pos_min) / slider_usable_sz, 0.0f, 1.0f) : 0.0f; + if (axis == ImGuiAxis_Y) + clicked_t = 1.0f - clicked_t; + set_new_value = true; + } + } + else if (g.ActiveIdSource == ImGuiInputSource_Nav) + { + const ImVec2 delta2 = GetNavInputAmount2d(ImGuiNavDirSourceFlags_Keyboard | ImGuiNavDirSourceFlags_PadDPad, ImGuiInputReadMode_RepeatFast, 0.0f, 0.0f); + float delta = (axis == ImGuiAxis_X) ? delta2.x : -delta2.y; + if (g.NavActivatePressedId == id && !g.ActiveIdIsJustActivated) + { + ClearActiveID(); + } + else if (delta != 0.0f) + { + clicked_t = SliderCalcRatioFromValueT(data_type, *v, v_min, v_max, power, linear_zero_pos); + const int decimal_precision = is_decimal ? ImParseFormatPrecision(format, 3) : 0; + if ((decimal_precision > 0) || is_power) + { + delta /= 100.0f; // Gamepad/keyboard tweak speeds in % of slider bounds + if (IsNavInputDown(ImGuiNavInput_TweakSlow)) + delta /= 10.0f; + } + else + { + if ((v_range >= -100.0f && v_range <= 100.0f) || IsNavInputDown(ImGuiNavInput_TweakSlow)) + delta = ((delta < 0.0f) ? -1.0f : +1.0f) / (float)v_range; // Gamepad/keyboard tweak speeds in integer steps + else + delta /= 100.0f; + } + if (IsNavInputDown(ImGuiNavInput_TweakFast)) + delta *= 10.0f; + set_new_value = true; + if ((clicked_t >= 1.0f && delta > 0.0f) || (clicked_t <= 0.0f && delta < 0.0f)) // This is to avoid applying the saturation when already past the limits + set_new_value = false; + else + clicked_t = ImSaturate(clicked_t + delta); + } + } + + if (set_new_value) + { + TYPE v_new; + if (is_power) + { + // Account for power curve scale on both sides of the zero + if (clicked_t < linear_zero_pos) + { + // Negative: rescale to the negative range before powering + float a = 1.0f - (clicked_t / linear_zero_pos); + a = ImPow(a, power); + v_new = ImLerp(ImMin(v_max, (TYPE)0), v_min, a); + } + else + { + // Positive: rescale to the positive range before powering + float a; + if (ImFabs(linear_zero_pos - 1.0f) > 1.e-6f) + a = (clicked_t - linear_zero_pos) / (1.0f - linear_zero_pos); + else + a = clicked_t; + a = ImPow(a, power); + v_new = ImLerp(ImMax(v_min, (TYPE)0), v_max, a); + } + } + else + { + // Linear slider + if (is_decimal) + { + v_new = ImLerp(v_min, v_max, clicked_t); + } + else + { + // For integer values we want the clicking position to match the grab box so we round above + // This code is carefully tuned to work with large values (e.g. high ranges of U64) while preserving this property.. + FLOATTYPE v_new_off_f = (v_max - v_min) * clicked_t; + TYPE v_new_off_floor = (TYPE)(v_new_off_f); + TYPE v_new_off_round = (TYPE)(v_new_off_f + (FLOATTYPE)0.5); + if (v_new_off_floor < v_new_off_round) + v_new = v_min + v_new_off_round; + else + v_new = v_min + v_new_off_floor; + } + } + + // Round to user desired precision based on format string + v_new = RoundScalarWithFormatT(format, data_type, v_new); + + // Apply result + if (*v != v_new) + { + *v = v_new; + value_changed = true; + } + } + } + + if (slider_sz < 1.0f) + { + *out_grab_bb = ImRect(bb.Min, bb.Min); + } + else + { + // Output grab position so it can be displayed by the caller + float grab_t = SliderCalcRatioFromValueT(data_type, *v, v_min, v_max, power, linear_zero_pos); + if (axis == ImGuiAxis_Y) + grab_t = 1.0f - grab_t; + const float grab_pos = ImLerp(slider_usable_pos_min, slider_usable_pos_max, grab_t); + if (axis == ImGuiAxis_X) + *out_grab_bb = ImRect(grab_pos - grab_sz * 0.5f, bb.Min.y + grab_padding, grab_pos + grab_sz * 0.5f, bb.Max.y - grab_padding); + else + *out_grab_bb = ImRect(bb.Min.x + grab_padding, grab_pos - grab_sz * 0.5f, bb.Max.x - grab_padding, grab_pos + grab_sz * 0.5f); + } + + return value_changed; +} + +// For 32-bit and larger types, slider bounds are limited to half the natural type range. +// So e.g. an integer Slider between INT_MAX-10 and INT_MAX will fail, but an integer Slider between INT_MAX/2-10 and INT_MAX/2 will be ok. +// It would be possible to lift that limitation with some work but it doesn't seem to be worth it for sliders. +bool ImGui::SliderBehavior(const ImRect& bb, ImGuiID id, ImGuiDataType data_type, void* p_v, const void* p_min, const void* p_max, const char* format, float power, ImGuiSliderFlags flags, ImRect* out_grab_bb) +{ + switch (data_type) + { + case ImGuiDataType_S8: { ImS32 v32 = (ImS32)*(ImS8*)p_v; bool r = SliderBehaviorT(bb, id, ImGuiDataType_S32, &v32, *(const ImS8*)p_min, *(const ImS8*)p_max, format, power, flags, out_grab_bb); if (r) *(ImS8*)p_v = (ImS8)v32; return r; } + case ImGuiDataType_U8: { ImU32 v32 = (ImU32)*(ImU8*)p_v; bool r = SliderBehaviorT(bb, id, ImGuiDataType_U32, &v32, *(const ImU8*)p_min, *(const ImU8*)p_max, format, power, flags, out_grab_bb); if (r) *(ImU8*)p_v = (ImU8)v32; return r; } + case ImGuiDataType_S16: { ImS32 v32 = (ImS32)*(ImS16*)p_v; bool r = SliderBehaviorT(bb, id, ImGuiDataType_S32, &v32, *(const ImS16*)p_min, *(const ImS16*)p_max, format, power, flags, out_grab_bb); if (r) *(ImS16*)p_v = (ImS16)v32; return r; } + case ImGuiDataType_U16: { ImU32 v32 = (ImU32)*(ImU16*)p_v; bool r = SliderBehaviorT(bb, id, ImGuiDataType_U32, &v32, *(const ImU16*)p_min, *(const ImU16*)p_max, format, power, flags, out_grab_bb); if (r) *(ImU16*)p_v = (ImU16)v32; return r; } + case ImGuiDataType_S32: + IM_ASSERT(*(const ImS32*)p_min >= IM_S32_MIN/2 && *(const ImS32*)p_max <= IM_S32_MAX/2); + return SliderBehaviorT(bb, id, data_type, (ImS32*)p_v, *(const ImS32*)p_min, *(const ImS32*)p_max, format, power, flags, out_grab_bb); + case ImGuiDataType_U32: + IM_ASSERT(*(const ImU32*)p_max <= IM_U32_MAX/2); + return SliderBehaviorT(bb, id, data_type, (ImU32*)p_v, *(const ImU32*)p_min, *(const ImU32*)p_max, format, power, flags, out_grab_bb); + case ImGuiDataType_S64: + IM_ASSERT(*(const ImS64*)p_min >= IM_S64_MIN/2 && *(const ImS64*)p_max <= IM_S64_MAX/2); + return SliderBehaviorT(bb, id, data_type, (ImS64*)p_v, *(const ImS64*)p_min, *(const ImS64*)p_max, format, power, flags, out_grab_bb); + case ImGuiDataType_U64: + IM_ASSERT(*(const ImU64*)p_max <= IM_U64_MAX/2); + return SliderBehaviorT(bb, id, data_type, (ImU64*)p_v, *(const ImU64*)p_min, *(const ImU64*)p_max, format, power, flags, out_grab_bb); + case ImGuiDataType_Float: + IM_ASSERT(*(const float*)p_min >= -FLT_MAX/2.0f && *(const float*)p_max <= FLT_MAX/2.0f); + return SliderBehaviorT(bb, id, data_type, (float*)p_v, *(const float*)p_min, *(const float*)p_max, format, power, flags, out_grab_bb); + case ImGuiDataType_Double: + IM_ASSERT(*(const double*)p_min >= -DBL_MAX/2.0f && *(const double*)p_max <= DBL_MAX/2.0f); + return SliderBehaviorT(bb, id, data_type, (double*)p_v, *(const double*)p_min, *(const double*)p_max, format, power, flags, out_grab_bb); + case ImGuiDataType_COUNT: break; + } + IM_ASSERT(0); + return false; +} + +// Note: p_data, p_min and p_max are _pointers_ to a memory address holding the data. For a slider, they are all required. +// Read code of e.g. SliderFloat(), SliderInt() etc. or examples in 'Demo->Widgets->Data Types' to understand how to use this function directly. +bool ImGui::SliderScalar(const char* label, ImGuiDataType data_type, void* p_data, const void* p_min, const void* p_max, const char* format, float power) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + ImGuiContext& g = *GImGui; + const ImGuiStyle& style = g.Style; + const ImGuiID id = window->GetID(label); + const float w = CalcItemWidth(); + + const ImVec2 label_size = CalcTextSize(label, NULL, true); + const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y + style.FramePadding.y*2.0f)); + const ImRect total_bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f)); + + ItemSize(total_bb, style.FramePadding.y); + if (!ItemAdd(total_bb, id, &frame_bb)) + return false; + + // Default format string when passing NULL + if (format == NULL) + format = DataTypeGetInfo(data_type)->PrintFmt; + else if (data_type == ImGuiDataType_S32 && strcmp(format, "%d") != 0) // (FIXME-LEGACY: Patch old "%.0f" format string to use "%d", read function more details.) + format = PatchFormatStringFloatToInt(format); + + // Tabbing or CTRL-clicking on Slider turns it into an input box + const bool hovered = ItemHoverable(frame_bb, id); + bool temp_input_is_active = TempInputIsActive(id); + bool temp_input_start = false; + if (!temp_input_is_active) + { + const bool focus_requested = FocusableItemRegister(window, id); + const bool clicked = (hovered && g.IO.MouseClicked[0]); + if (focus_requested || clicked || g.NavActivateId == id || g.NavInputId == id) + { + SetActiveID(id, window); + SetFocusID(id, window); + FocusWindow(window); + g.ActiveIdUsingNavDirMask |= (1 << ImGuiDir_Left) | (1 << ImGuiDir_Right); + if (focus_requested || (clicked && g.IO.KeyCtrl) || g.NavInputId == id) + { + temp_input_start = true; + FocusableItemUnregister(window); + } + } + } + + // Our current specs do NOT clamp when using CTRL+Click manual input, but we should eventually add a flag for that.. + if (temp_input_is_active || temp_input_start) + return TempInputScalar(frame_bb, id, label, data_type, p_data, format);// , p_min, p_max); + + // Draw frame + const ImU32 frame_col = GetColorU32(g.ActiveId == id ? ImGuiCol_FrameBgActive : g.HoveredId == id ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg); + RenderNavHighlight(frame_bb, id); + RenderFrame(frame_bb.Min, frame_bb.Max, frame_col, true, g.Style.FrameRounding); + + // Slider behavior + ImRect grab_bb; + const bool value_changed = SliderBehavior(frame_bb, id, data_type, p_data, p_min, p_max, format, power, ImGuiSliderFlags_None, &grab_bb); + if (value_changed) + MarkItemEdited(id); + + // Render grab + if (grab_bb.Max.x > grab_bb.Min.x) + window->DrawList->AddRectFilled(grab_bb.Min, grab_bb.Max, GetColorU32(g.ActiveId == id ? ImGuiCol_SliderGrabActive : ImGuiCol_SliderGrab), style.GrabRounding); + + // Display value using user-provided display format so user can add prefix/suffix/decorations to the value. + char value_buf[64]; + const char* value_buf_end = value_buf + DataTypeFormatString(value_buf, IM_ARRAYSIZE(value_buf), data_type, p_data, format); + RenderTextClipped(frame_bb.Min, frame_bb.Max, value_buf, value_buf_end, NULL, ImVec2(0.5f,0.5f)); + + if (label_size.x > 0.0f) + RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label); + + IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.ItemFlags); + return value_changed; +} + +// Add multiple sliders on 1 line for compact edition of multiple components +bool ImGui::SliderScalarN(const char* label, ImGuiDataType data_type, void* v, int components, const void* v_min, const void* v_max, const char* format, float power) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + ImGuiContext& g = *GImGui; + bool value_changed = false; + BeginGroup(); + PushID(label); + PushMultiItemsWidths(components, CalcItemWidth()); + size_t type_size = GDataTypeInfo[data_type].Size; + for (int i = 0; i < components; i++) + { + PushID(i); + if (i > 0) + SameLine(0, g.Style.ItemInnerSpacing.x); + value_changed |= SliderScalar("", data_type, v, v_min, v_max, format, power); + PopID(); + PopItemWidth(); + v = (void*)((char*)v + type_size); + } + PopID(); + + const char* label_end = FindRenderedTextEnd(label); + if (label != label_end) + { + SameLine(0, g.Style.ItemInnerSpacing.x); + TextEx(label, label_end); + } + + EndGroup(); + return value_changed; +} + +bool ImGui::SliderFloat(const char* label, float* v, float v_min, float v_max, const char* format, float power) +{ + return SliderScalar(label, ImGuiDataType_Float, v, &v_min, &v_max, format, power); +} + +bool ImGui::SliderFloat2(const char* label, float v[2], float v_min, float v_max, const char* format, float power) +{ + return SliderScalarN(label, ImGuiDataType_Float, v, 2, &v_min, &v_max, format, power); +} + +bool ImGui::SliderFloat3(const char* label, float v[3], float v_min, float v_max, const char* format, float power) +{ + return SliderScalarN(label, ImGuiDataType_Float, v, 3, &v_min, &v_max, format, power); +} + +bool ImGui::SliderFloat4(const char* label, float v[4], float v_min, float v_max, const char* format, float power) +{ + return SliderScalarN(label, ImGuiDataType_Float, v, 4, &v_min, &v_max, format, power); +} + +bool ImGui::SliderAngle(const char* label, float* v_rad, float v_degrees_min, float v_degrees_max, const char* format) +{ + if (format == NULL) + format = "%.0f deg"; + float v_deg = (*v_rad) * 360.0f / (2*IM_PI); + bool value_changed = SliderFloat(label, &v_deg, v_degrees_min, v_degrees_max, format, 1.0f); + *v_rad = v_deg * (2*IM_PI) / 360.0f; + return value_changed; +} + +bool ImGui::SliderInt(const char* label, int* v, int v_min, int v_max, const char* format) +{ + return SliderScalar(label, ImGuiDataType_S32, v, &v_min, &v_max, format); +} + +bool ImGui::SliderInt2(const char* label, int v[2], int v_min, int v_max, const char* format) +{ + return SliderScalarN(label, ImGuiDataType_S32, v, 2, &v_min, &v_max, format); +} + +bool ImGui::SliderInt3(const char* label, int v[3], int v_min, int v_max, const char* format) +{ + return SliderScalarN(label, ImGuiDataType_S32, v, 3, &v_min, &v_max, format); +} + +bool ImGui::SliderInt4(const char* label, int v[4], int v_min, int v_max, const char* format) +{ + return SliderScalarN(label, ImGuiDataType_S32, v, 4, &v_min, &v_max, format); +} + +bool ImGui::VSliderScalar(const char* label, const ImVec2& size, ImGuiDataType data_type, void* p_data, const void* p_min, const void* p_max, const char* format, float power) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + ImGuiContext& g = *GImGui; + const ImGuiStyle& style = g.Style; + const ImGuiID id = window->GetID(label); + + const ImVec2 label_size = CalcTextSize(label, NULL, true); + const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + size); + const ImRect bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f)); + + ItemSize(bb, style.FramePadding.y); + if (!ItemAdd(frame_bb, id)) + return false; + + // Default format string when passing NULL + if (format == NULL) + format = DataTypeGetInfo(data_type)->PrintFmt; + else if (data_type == ImGuiDataType_S32 && strcmp(format, "%d") != 0) // (FIXME-LEGACY: Patch old "%.0f" format string to use "%d", read function more details.) + format = PatchFormatStringFloatToInt(format); + + const bool hovered = ItemHoverable(frame_bb, id); + if ((hovered && g.IO.MouseClicked[0]) || g.NavActivateId == id || g.NavInputId == id) + { + SetActiveID(id, window); + SetFocusID(id, window); + FocusWindow(window); + g.ActiveIdUsingNavDirMask |= (1 << ImGuiDir_Up) | (1 << ImGuiDir_Down); + } + + // Draw frame + const ImU32 frame_col = GetColorU32(g.ActiveId == id ? ImGuiCol_FrameBgActive : g.HoveredId == id ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg); + RenderNavHighlight(frame_bb, id); + RenderFrame(frame_bb.Min, frame_bb.Max, frame_col, true, g.Style.FrameRounding); + + // Slider behavior + ImRect grab_bb; + const bool value_changed = SliderBehavior(frame_bb, id, data_type, p_data, p_min, p_max, format, power, ImGuiSliderFlags_Vertical, &grab_bb); + if (value_changed) + MarkItemEdited(id); + + // Render grab + if (grab_bb.Max.y > grab_bb.Min.y) + window->DrawList->AddRectFilled(grab_bb.Min, grab_bb.Max, GetColorU32(g.ActiveId == id ? ImGuiCol_SliderGrabActive : ImGuiCol_SliderGrab), style.GrabRounding); + + // Display value using user-provided display format so user can add prefix/suffix/decorations to the value. + // For the vertical slider we allow centered text to overlap the frame padding + char value_buf[64]; + const char* value_buf_end = value_buf + DataTypeFormatString(value_buf, IM_ARRAYSIZE(value_buf), data_type, p_data, format); + RenderTextClipped(ImVec2(frame_bb.Min.x, frame_bb.Min.y + style.FramePadding.y), frame_bb.Max, value_buf, value_buf_end, NULL, ImVec2(0.5f,0.0f)); + if (label_size.x > 0.0f) + RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label); + + return value_changed; +} + +bool ImGui::VSliderFloat(const char* label, const ImVec2& size, float* v, float v_min, float v_max, const char* format, float power) +{ + return VSliderScalar(label, size, ImGuiDataType_Float, v, &v_min, &v_max, format, power); +} + +bool ImGui::VSliderInt(const char* label, const ImVec2& size, int* v, int v_min, int v_max, const char* format) +{ + return VSliderScalar(label, size, ImGuiDataType_S32, v, &v_min, &v_max, format); +} + +//------------------------------------------------------------------------- +// [SECTION] Widgets: InputScalar, InputFloat, InputInt, etc. +//------------------------------------------------------------------------- +// - ImParseFormatFindStart() [Internal] +// - ImParseFormatFindEnd() [Internal] +// - ImParseFormatTrimDecorations() [Internal] +// - ImParseFormatPrecision() [Internal] +// - TempInputTextScalar() [Internal] +// - InputScalar() +// - InputScalarN() +// - InputFloat() +// - InputFloat2() +// - InputFloat3() +// - InputFloat4() +// - InputInt() +// - InputInt2() +// - InputInt3() +// - InputInt4() +// - InputDouble() +//------------------------------------------------------------------------- + +// We don't use strchr() because our strings are usually very short and often start with '%' +const char* ImParseFormatFindStart(const char* fmt) +{ + while (char c = fmt[0]) + { + if (c == '%' && fmt[1] != '%') + return fmt; + else if (c == '%') + fmt++; + fmt++; + } + return fmt; +} + +const char* ImParseFormatFindEnd(const char* fmt) +{ + // Printf/scanf types modifiers: I/L/h/j/l/t/w/z. Other uppercase letters qualify as types aka end of the format. + if (fmt[0] != '%') + return fmt; + const unsigned int ignored_uppercase_mask = (1 << ('I'-'A')) | (1 << ('L'-'A')); + const unsigned int ignored_lowercase_mask = (1 << ('h'-'a')) | (1 << ('j'-'a')) | (1 << ('l'-'a')) | (1 << ('t'-'a')) | (1 << ('w'-'a')) | (1 << ('z'-'a')); + for (char c; (c = *fmt) != 0; fmt++) + { + if (c >= 'A' && c <= 'Z' && ((1 << (c - 'A')) & ignored_uppercase_mask) == 0) + return fmt + 1; + if (c >= 'a' && c <= 'z' && ((1 << (c - 'a')) & ignored_lowercase_mask) == 0) + return fmt + 1; + } + return fmt; +} + +// Extract the format out of a format string with leading or trailing decorations +// fmt = "blah blah" -> return fmt +// fmt = "%.3f" -> return fmt +// fmt = "hello %.3f" -> return fmt + 6 +// fmt = "%.3f hello" -> return buf written with "%.3f" +const char* ImParseFormatTrimDecorations(const char* fmt, char* buf, size_t buf_size) +{ + const char* fmt_start = ImParseFormatFindStart(fmt); + if (fmt_start[0] != '%') + return fmt; + const char* fmt_end = ImParseFormatFindEnd(fmt_start); + if (fmt_end[0] == 0) // If we only have leading decoration, we don't need to copy the data. + return fmt_start; + ImStrncpy(buf, fmt_start, ImMin((size_t)(fmt_end - fmt_start) + 1, buf_size)); + return buf; +} + +// Parse display precision back from the display format string +// FIXME: This is still used by some navigation code path to infer a minimum tweak step, but we should aim to rework widgets so it isn't needed. +int ImParseFormatPrecision(const char* fmt, int default_precision) +{ + fmt = ImParseFormatFindStart(fmt); + if (fmt[0] != '%') + return default_precision; + fmt++; + while (*fmt >= '0' && *fmt <= '9') + fmt++; + int precision = INT_MAX; + if (*fmt == '.') + { + fmt = ImAtoi(fmt + 1, &precision); + if (precision < 0 || precision > 99) + precision = default_precision; + } + if (*fmt == 'e' || *fmt == 'E') // Maximum precision with scientific notation + precision = -1; + if ((*fmt == 'g' || *fmt == 'G') && precision == INT_MAX) + precision = -1; + return (precision == INT_MAX) ? default_precision : precision; +} + +// Create text input in place of another active widget (e.g. used when doing a CTRL+Click on drag/slider widgets) +// FIXME: Facilitate using this in variety of other situations. +bool ImGui::TempInputText(const ImRect& bb, ImGuiID id, const char* label, char* buf, int buf_size, ImGuiInputTextFlags flags) +{ + // On the first frame, g.TempInputTextId == 0, then on subsequent frames it becomes == id. + // We clear ActiveID on the first frame to allow the InputText() taking it back. + ImGuiContext& g = *GImGui; + const bool init = (g.TempInputId != id); + if (init) + ClearActiveID(); + + g.CurrentWindow->DC.CursorPos = bb.Min; + bool value_changed = InputTextEx(label, NULL, buf, buf_size, bb.GetSize(), flags); + if (init) + { + // First frame we started displaying the InputText widget, we expect it to take the active id. + IM_ASSERT(g.ActiveId == id); + g.TempInputId = g.ActiveId; + } + return value_changed; +} + +// Note that Drag/Slider functions are currently NOT forwarding the min/max values clamping values! +// This is intended: this way we allow CTRL+Click manual input to set a value out of bounds, for maximum flexibility. +// However this may not be ideal for all uses, as some user code may break on out of bound values. +// In the future we should add flags to Slider/Drag to specify how to enforce min/max values with CTRL+Click. +// See GitHub issues #1829 and #3209 +// In the meanwhile, you can easily "wrap" those functions to enforce clamping, using wrapper functions, e.g. +// bool SliderFloatClamp(const char* label, float* v, float v_min, float v_max) +// { +// float v_backup = *v; +// if (!SliderFloat(label, v, v_min, v_max)) +// return false; +// *v = ImClamp(*v, v_min, v_max); +// return v_backup != *v; +// } +bool ImGui::TempInputScalar(const ImRect& bb, ImGuiID id, const char* label, ImGuiDataType data_type, void* p_data, const char* format, const void* p_clamp_min, const void* p_clamp_max) +{ + ImGuiContext& g = *GImGui; + + char fmt_buf[32]; + char data_buf[32]; + format = ImParseFormatTrimDecorations(format, fmt_buf, IM_ARRAYSIZE(fmt_buf)); + DataTypeFormatString(data_buf, IM_ARRAYSIZE(data_buf), data_type, p_data, format); + ImStrTrimBlanks(data_buf); + + ImGuiInputTextFlags flags = ImGuiInputTextFlags_AutoSelectAll | ImGuiInputTextFlags_NoMarkEdited; + flags |= ((data_type == ImGuiDataType_Float || data_type == ImGuiDataType_Double) ? ImGuiInputTextFlags_CharsScientific : ImGuiInputTextFlags_CharsDecimal); + bool value_changed = false; + if (TempInputText(bb, id, label, data_buf, IM_ARRAYSIZE(data_buf), flags)) + { + // Backup old value + size_t data_type_size = DataTypeGetInfo(data_type)->Size; + ImGuiDataTypeTempStorage data_backup; + memcpy(&data_backup, p_data, data_type_size); + + // Apply new value (or operations) then clamp + DataTypeApplyOpFromText(data_buf, g.InputTextState.InitialTextA.Data, data_type, p_data, NULL); + if (p_clamp_min && p_clamp_max) + DataTypeClamp(data_type, p_data, p_clamp_min, p_clamp_max); + + // Only mark as edited if new value is different + value_changed = memcmp(&data_backup, p_data, data_type_size) != 0; + if (value_changed) + MarkItemEdited(id); + } + return value_changed; +} + +// Note: p_data, p_step, p_step_fast are _pointers_ to a memory address holding the data. For an Input widget, p_step and p_step_fast are optional. +// Read code of e.g. InputFloat(), InputInt() etc. or examples in 'Demo->Widgets->Data Types' to understand how to use this function directly. +bool ImGui::InputScalar(const char* label, ImGuiDataType data_type, void* p_data, const void* p_step, const void* p_step_fast, const char* format, ImGuiInputTextFlags flags) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + ImGuiContext& g = *GImGui; + ImGuiStyle& style = g.Style; + + if (format == NULL) + format = DataTypeGetInfo(data_type)->PrintFmt; + + char buf[64]; + DataTypeFormatString(buf, IM_ARRAYSIZE(buf), data_type, p_data, format); + + bool value_changed = false; + if ((flags & (ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsScientific)) == 0) + flags |= ImGuiInputTextFlags_CharsDecimal; + flags |= ImGuiInputTextFlags_AutoSelectAll; + flags |= ImGuiInputTextFlags_NoMarkEdited; // We call MarkItemEdited() ourselves by comparing the actual data rather than the string. + + if (p_step != NULL) + { + const float button_size = GetFrameHeight(); + + BeginGroup(); // The only purpose of the group here is to allow the caller to query item data e.g. IsItemActive() + PushID(label); + SetNextItemWidth(ImMax(1.0f, CalcItemWidth() - (button_size + style.ItemInnerSpacing.x) * 2)); + if (InputText("", buf, IM_ARRAYSIZE(buf), flags)) // PushId(label) + "" gives us the expected ID from outside point of view + value_changed = DataTypeApplyOpFromText(buf, g.InputTextState.InitialTextA.Data, data_type, p_data, format); + + // Step buttons + const ImVec2 backup_frame_padding = style.FramePadding; + style.FramePadding.x = style.FramePadding.y; + ImGuiButtonFlags button_flags = ImGuiButtonFlags_Repeat | ImGuiButtonFlags_DontClosePopups; + if (flags & ImGuiInputTextFlags_ReadOnly) + button_flags |= ImGuiButtonFlags_Disabled; + SameLine(0, style.ItemInnerSpacing.x); + if (ButtonEx("-", ImVec2(button_size, button_size), button_flags)) + { + DataTypeApplyOp(data_type, '-', p_data, p_data, g.IO.KeyCtrl && p_step_fast ? p_step_fast : p_step); + value_changed = true; + } + SameLine(0, style.ItemInnerSpacing.x); + if (ButtonEx("+", ImVec2(button_size, button_size), button_flags)) + { + DataTypeApplyOp(data_type, '+', p_data, p_data, g.IO.KeyCtrl && p_step_fast ? p_step_fast : p_step); + value_changed = true; + } + + const char* label_end = FindRenderedTextEnd(label); + if (label != label_end) + { + SameLine(0, style.ItemInnerSpacing.x); + TextEx(label, label_end); + } + style.FramePadding = backup_frame_padding; + + PopID(); + EndGroup(); + } + else + { + if (InputText(label, buf, IM_ARRAYSIZE(buf), flags)) + value_changed = DataTypeApplyOpFromText(buf, g.InputTextState.InitialTextA.Data, data_type, p_data, format); + } + if (value_changed) + MarkItemEdited(window->DC.LastItemId); + + return value_changed; +} + +bool ImGui::InputScalarN(const char* label, ImGuiDataType data_type, void* p_data, int components, const void* p_step, const void* p_step_fast, const char* format, ImGuiInputTextFlags flags) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + ImGuiContext& g = *GImGui; + bool value_changed = false; + BeginGroup(); + PushID(label); + PushMultiItemsWidths(components, CalcItemWidth()); + size_t type_size = GDataTypeInfo[data_type].Size; + for (int i = 0; i < components; i++) + { + PushID(i); + if (i > 0) + SameLine(0, g.Style.ItemInnerSpacing.x); + value_changed |= InputScalar("", data_type, p_data, p_step, p_step_fast, format, flags); + PopID(); + PopItemWidth(); + p_data = (void*)((char*)p_data + type_size); + } + PopID(); + + const char* label_end = FindRenderedTextEnd(label); + if (label != label_end) + { + SameLine(0.0f, g.Style.ItemInnerSpacing.x); + TextEx(label, label_end); + } + + EndGroup(); + return value_changed; +} + +bool ImGui::InputFloat(const char* label, float* v, float step, float step_fast, const char* format, ImGuiInputTextFlags flags) +{ + flags |= ImGuiInputTextFlags_CharsScientific; + return InputScalar(label, ImGuiDataType_Float, (void*)v, (void*)(step>0.0f ? &step : NULL), (void*)(step_fast>0.0f ? &step_fast : NULL), format, flags); +} + +bool ImGui::InputFloat2(const char* label, float v[2], const char* format, ImGuiInputTextFlags flags) +{ + return InputScalarN(label, ImGuiDataType_Float, v, 2, NULL, NULL, format, flags); +} + +bool ImGui::InputFloat3(const char* label, float v[3], const char* format, ImGuiInputTextFlags flags) +{ + return InputScalarN(label, ImGuiDataType_Float, v, 3, NULL, NULL, format, flags); +} + +bool ImGui::InputFloat4(const char* label, float v[4], const char* format, ImGuiInputTextFlags flags) +{ + return InputScalarN(label, ImGuiDataType_Float, v, 4, NULL, NULL, format, flags); +} + +// Prefer using "const char* format" directly, which is more flexible and consistent with other API. +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS +bool ImGui::InputFloat(const char* label, float* v, float step, float step_fast, int decimal_precision, ImGuiInputTextFlags flags) +{ + char format[16] = "%f"; + if (decimal_precision >= 0) + ImFormatString(format, IM_ARRAYSIZE(format), "%%.%df", decimal_precision); + return InputFloat(label, v, step, step_fast, format, flags); +} + +bool ImGui::InputFloat2(const char* label, float v[2], int decimal_precision, ImGuiInputTextFlags flags) +{ + char format[16] = "%f"; + if (decimal_precision >= 0) + ImFormatString(format, IM_ARRAYSIZE(format), "%%.%df", decimal_precision); + return InputScalarN(label, ImGuiDataType_Float, v, 2, NULL, NULL, format, flags); +} + +bool ImGui::InputFloat3(const char* label, float v[3], int decimal_precision, ImGuiInputTextFlags flags) +{ + char format[16] = "%f"; + if (decimal_precision >= 0) + ImFormatString(format, IM_ARRAYSIZE(format), "%%.%df", decimal_precision); + return InputScalarN(label, ImGuiDataType_Float, v, 3, NULL, NULL, format, flags); +} + +bool ImGui::InputFloat4(const char* label, float v[4], int decimal_precision, ImGuiInputTextFlags flags) +{ + char format[16] = "%f"; + if (decimal_precision >= 0) + ImFormatString(format, IM_ARRAYSIZE(format), "%%.%df", decimal_precision); + return InputScalarN(label, ImGuiDataType_Float, v, 4, NULL, NULL, format, flags); +} +#endif // IMGUI_DISABLE_OBSOLETE_FUNCTIONS + +bool ImGui::InputInt(const char* label, int* v, int step, int step_fast, ImGuiInputTextFlags flags) +{ + // Hexadecimal input provided as a convenience but the flag name is awkward. Typically you'd use InputText() to parse your own data, if you want to handle prefixes. + const char* format = (flags & ImGuiInputTextFlags_CharsHexadecimal) ? "%08X" : "%d"; + return InputScalar(label, ImGuiDataType_S32, (void*)v, (void*)(step>0 ? &step : NULL), (void*)(step_fast>0 ? &step_fast : NULL), format, flags); +} + +bool ImGui::InputInt2(const char* label, int v[2], ImGuiInputTextFlags flags) +{ + return InputScalarN(label, ImGuiDataType_S32, v, 2, NULL, NULL, "%d", flags); +} + +bool ImGui::InputInt3(const char* label, int v[3], ImGuiInputTextFlags flags) +{ + return InputScalarN(label, ImGuiDataType_S32, v, 3, NULL, NULL, "%d", flags); +} + +bool ImGui::InputInt4(const char* label, int v[4], ImGuiInputTextFlags flags) +{ + return InputScalarN(label, ImGuiDataType_S32, v, 4, NULL, NULL, "%d", flags); +} + +bool ImGui::InputDouble(const char* label, double* v, double step, double step_fast, const char* format, ImGuiInputTextFlags flags) +{ + flags |= ImGuiInputTextFlags_CharsScientific; + return InputScalar(label, ImGuiDataType_Double, (void*)v, (void*)(step>0.0 ? &step : NULL), (void*)(step_fast>0.0 ? &step_fast : NULL), format, flags); +} + +//------------------------------------------------------------------------- +// [SECTION] Widgets: InputText, InputTextMultiline, InputTextWithHint +//------------------------------------------------------------------------- +// - InputText() +// - InputTextWithHint() +// - InputTextMultiline() +// - InputTextEx() [Internal] +//------------------------------------------------------------------------- + +bool ImGui::InputText(const char* label, char* buf, size_t buf_size, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data) +{ + IM_ASSERT(!(flags & ImGuiInputTextFlags_Multiline)); // call InputTextMultiline() + return InputTextEx(label, NULL, buf, (int)buf_size, ImVec2(0,0), flags, callback, user_data); +} + +bool ImGui::InputTextMultiline(const char* label, char* buf, size_t buf_size, const ImVec2& size, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data) +{ + return InputTextEx(label, NULL, buf, (int)buf_size, size, flags | ImGuiInputTextFlags_Multiline, callback, user_data); +} + +bool ImGui::InputTextWithHint(const char* label, const char* hint, char* buf, size_t buf_size, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data) +{ + IM_ASSERT(!(flags & ImGuiInputTextFlags_Multiline)); // call InputTextMultiline() + return InputTextEx(label, hint, buf, (int)buf_size, ImVec2(0, 0), flags, callback, user_data); +} + +static int InputTextCalcTextLenAndLineCount(const char* text_begin, const char** out_text_end) +{ + int line_count = 0; + const char* s = text_begin; + while (char c = *s++) // We are only matching for \n so we can ignore UTF-8 decoding + if (c == '\n') + line_count++; + s--; + if (s[0] != '\n' && s[0] != '\r') + line_count++; + *out_text_end = s; + return line_count; +} + +static ImVec2 InputTextCalcTextSizeW(const ImWchar* text_begin, const ImWchar* text_end, const ImWchar** remaining, ImVec2* out_offset, bool stop_on_new_line) +{ + ImGuiContext& g = *GImGui; + ImFont* font = g.Font; + const float line_height = g.FontSize; + const float scale = line_height / font->FontSize; + + ImVec2 text_size = ImVec2(0,0); + float line_width = 0.0f; + + const ImWchar* s = text_begin; + while (s < text_end) + { + unsigned int c = (unsigned int)(*s++); + if (c == '\n') + { + text_size.x = ImMax(text_size.x, line_width); + text_size.y += line_height; + line_width = 0.0f; + if (stop_on_new_line) + break; + continue; + } + if (c == '\r') + continue; + + const float char_width = font->GetCharAdvance((ImWchar)c) * scale; + line_width += char_width; + } + + if (text_size.x < line_width) + text_size.x = line_width; + + if (out_offset) + *out_offset = ImVec2(line_width, text_size.y + line_height); // offset allow for the possibility of sitting after a trailing \n + + if (line_width > 0 || text_size.y == 0.0f) // whereas size.y will ignore the trailing \n + text_size.y += line_height; + + if (remaining) + *remaining = s; + + return text_size; +} + +// Wrapper for stb_textedit.h to edit text (our wrapper is for: statically sized buffer, single-line, wchar characters. InputText converts between UTF-8 and wchar) +namespace ImStb +{ + +static int STB_TEXTEDIT_STRINGLEN(const STB_TEXTEDIT_STRING* obj) { return obj->CurLenW; } +static ImWchar STB_TEXTEDIT_GETCHAR(const STB_TEXTEDIT_STRING* obj, int idx) { return obj->TextW[idx]; } +static float STB_TEXTEDIT_GETWIDTH(STB_TEXTEDIT_STRING* obj, int line_start_idx, int char_idx) { ImWchar c = obj->TextW[line_start_idx + char_idx]; if (c == '\n') return STB_TEXTEDIT_GETWIDTH_NEWLINE; ImGuiContext& g = *GImGui; return g.Font->GetCharAdvance(c) * (g.FontSize / g.Font->FontSize); } +static int STB_TEXTEDIT_KEYTOTEXT(int key) { return key >= 0x200000 ? 0 : key; } +static ImWchar STB_TEXTEDIT_NEWLINE = '\n'; +static void STB_TEXTEDIT_LAYOUTROW(StbTexteditRow* r, STB_TEXTEDIT_STRING* obj, int line_start_idx) +{ + const ImWchar* text = obj->TextW.Data; + const ImWchar* text_remaining = NULL; + const ImVec2 size = InputTextCalcTextSizeW(text + line_start_idx, text + obj->CurLenW, &text_remaining, NULL, true); + r->x0 = 0.0f; + r->x1 = size.x; + r->baseline_y_delta = size.y; + r->ymin = 0.0f; + r->ymax = size.y; + r->num_chars = (int)(text_remaining - (text + line_start_idx)); +} + +static bool is_separator(unsigned int c) { return ImCharIsBlankW(c) || c==',' || c==';' || c=='(' || c==')' || c=='{' || c=='}' || c=='[' || c==']' || c=='|'; } +static int is_word_boundary_from_right(STB_TEXTEDIT_STRING* obj, int idx) { return idx > 0 ? (is_separator( obj->TextW[idx-1] ) && !is_separator( obj->TextW[idx] ) ) : 1; } +static int STB_TEXTEDIT_MOVEWORDLEFT_IMPL(STB_TEXTEDIT_STRING* obj, int idx) { idx--; while (idx >= 0 && !is_word_boundary_from_right(obj, idx)) idx--; return idx < 0 ? 0 : idx; } +#ifdef __APPLE__ // FIXME: Move setting to IO structure +static int is_word_boundary_from_left(STB_TEXTEDIT_STRING* obj, int idx) { return idx > 0 ? (!is_separator( obj->TextW[idx-1] ) && is_separator( obj->TextW[idx] ) ) : 1; } +static int STB_TEXTEDIT_MOVEWORDRIGHT_IMPL(STB_TEXTEDIT_STRING* obj, int idx) { idx++; int len = obj->CurLenW; while (idx < len && !is_word_boundary_from_left(obj, idx)) idx++; return idx > len ? len : idx; } +#else +static int STB_TEXTEDIT_MOVEWORDRIGHT_IMPL(STB_TEXTEDIT_STRING* obj, int idx) { idx++; int len = obj->CurLenW; while (idx < len && !is_word_boundary_from_right(obj, idx)) idx++; return idx > len ? len : idx; } +#endif +#define STB_TEXTEDIT_MOVEWORDLEFT STB_TEXTEDIT_MOVEWORDLEFT_IMPL // They need to be #define for stb_textedit.h +#define STB_TEXTEDIT_MOVEWORDRIGHT STB_TEXTEDIT_MOVEWORDRIGHT_IMPL + +static void STB_TEXTEDIT_DELETECHARS(STB_TEXTEDIT_STRING* obj, int pos, int n) +{ + ImWchar* dst = obj->TextW.Data + pos; + + // We maintain our buffer length in both UTF-8 and wchar formats + obj->CurLenA -= ImTextCountUtf8BytesFromStr(dst, dst + n); + obj->CurLenW -= n; + + // Offset remaining text (FIXME-OPT: Use memmove) + const ImWchar* src = obj->TextW.Data + pos + n; + while (ImWchar c = *src++) + *dst++ = c; + *dst = '\0'; +} + +static bool STB_TEXTEDIT_INSERTCHARS(STB_TEXTEDIT_STRING* obj, int pos, const ImWchar* new_text, int new_text_len) +{ + const bool is_resizable = (obj->UserFlags & ImGuiInputTextFlags_CallbackResize) != 0; + const int text_len = obj->CurLenW; + IM_ASSERT(pos <= text_len); + + const int new_text_len_utf8 = ImTextCountUtf8BytesFromStr(new_text, new_text + new_text_len); + if (!is_resizable && (new_text_len_utf8 + obj->CurLenA + 1 > obj->BufCapacityA)) + return false; + + // Grow internal buffer if needed + if (new_text_len + text_len + 1 > obj->TextW.Size) + { + if (!is_resizable) + return false; + IM_ASSERT(text_len < obj->TextW.Size); + obj->TextW.resize(text_len + ImClamp(new_text_len * 4, 32, ImMax(256, new_text_len)) + 1); + } + + ImWchar* text = obj->TextW.Data; + if (pos != text_len) + memmove(text + pos + new_text_len, text + pos, (size_t)(text_len - pos) * sizeof(ImWchar)); + memcpy(text + pos, new_text, (size_t)new_text_len * sizeof(ImWchar)); + + obj->CurLenW += new_text_len; + obj->CurLenA += new_text_len_utf8; + obj->TextW[obj->CurLenW] = '\0'; + + return true; +} + +// We don't use an enum so we can build even with conflicting symbols (if another user of stb_textedit.h leak their STB_TEXTEDIT_K_* symbols) +#define STB_TEXTEDIT_K_LEFT 0x200000 // keyboard input to move cursor left +#define STB_TEXTEDIT_K_RIGHT 0x200001 // keyboard input to move cursor right +#define STB_TEXTEDIT_K_UP 0x200002 // keyboard input to move cursor up +#define STB_TEXTEDIT_K_DOWN 0x200003 // keyboard input to move cursor down +#define STB_TEXTEDIT_K_LINESTART 0x200004 // keyboard input to move cursor to start of line +#define STB_TEXTEDIT_K_LINEEND 0x200005 // keyboard input to move cursor to end of line +#define STB_TEXTEDIT_K_TEXTSTART 0x200006 // keyboard input to move cursor to start of text +#define STB_TEXTEDIT_K_TEXTEND 0x200007 // keyboard input to move cursor to end of text +#define STB_TEXTEDIT_K_DELETE 0x200008 // keyboard input to delete selection or character under cursor +#define STB_TEXTEDIT_K_BACKSPACE 0x200009 // keyboard input to delete selection or character left of cursor +#define STB_TEXTEDIT_K_UNDO 0x20000A // keyboard input to perform undo +#define STB_TEXTEDIT_K_REDO 0x20000B // keyboard input to perform redo +#define STB_TEXTEDIT_K_WORDLEFT 0x20000C // keyboard input to move cursor left one word +#define STB_TEXTEDIT_K_WORDRIGHT 0x20000D // keyboard input to move cursor right one word +#define STB_TEXTEDIT_K_SHIFT 0x400000 + +#define STB_TEXTEDIT_IMPLEMENTATION +#include "stb_textedit.h" + +// stb_textedit internally allows for a single undo record to do addition and deletion, but somehow, calling +// the stb_textedit_paste() function creates two separate records, so we perform it manually. (FIXME: Report to nothings/stb?) +static void stb_textedit_replace(STB_TEXTEDIT_STRING* str, STB_TexteditState* state, const STB_TEXTEDIT_CHARTYPE* text, int text_len) +{ + stb_text_makeundo_replace(str, state, 0, str->CurLenW, text_len); + ImStb::STB_TEXTEDIT_DELETECHARS(str, 0, str->CurLenW); + if (text_len <= 0) + return; + if (ImStb::STB_TEXTEDIT_INSERTCHARS(str, 0, text, text_len)) + { + state->cursor = text_len; + state->has_preferred_x = 0; + return; + } + IM_ASSERT(0); // Failed to insert character, normally shouldn't happen because of how we currently use stb_textedit_replace() +} + +} // namespace ImStb + +void ImGuiInputTextState::OnKeyPressed(int key) +{ + stb_textedit_key(this, &Stb, key); + CursorFollow = true; + CursorAnimReset(); +} + +ImGuiInputTextCallbackData::ImGuiInputTextCallbackData() +{ + memset(this, 0, sizeof(*this)); +} + +// Public API to manipulate UTF-8 text +// We expose UTF-8 to the user (unlike the STB_TEXTEDIT_* functions which are manipulating wchar) +// FIXME: The existence of this rarely exercised code path is a bit of a nuisance. +void ImGuiInputTextCallbackData::DeleteChars(int pos, int bytes_count) +{ + IM_ASSERT(pos + bytes_count <= BufTextLen); + char* dst = Buf + pos; + const char* src = Buf + pos + bytes_count; + while (char c = *src++) + *dst++ = c; + *dst = '\0'; + + if (CursorPos + bytes_count >= pos) + CursorPos -= bytes_count; + else if (CursorPos >= pos) + CursorPos = pos; + SelectionStart = SelectionEnd = CursorPos; + BufDirty = true; + BufTextLen -= bytes_count; +} + +void ImGuiInputTextCallbackData::InsertChars(int pos, const char* new_text, const char* new_text_end) +{ + const bool is_resizable = (Flags & ImGuiInputTextFlags_CallbackResize) != 0; + const int new_text_len = new_text_end ? (int)(new_text_end - new_text) : (int)strlen(new_text); + if (new_text_len + BufTextLen >= BufSize) + { + if (!is_resizable) + return; + + // Contrary to STB_TEXTEDIT_INSERTCHARS() this is working in the UTF8 buffer, hence the mildly similar code (until we remove the U16 buffer altogether!) + ImGuiContext& g = *GImGui; + ImGuiInputTextState* edit_state = &g.InputTextState; + IM_ASSERT(edit_state->ID != 0 && g.ActiveId == edit_state->ID); + IM_ASSERT(Buf == edit_state->TextA.Data); + int new_buf_size = BufTextLen + ImClamp(new_text_len * 4, 32, ImMax(256, new_text_len)) + 1; + edit_state->TextA.reserve(new_buf_size + 1); + Buf = edit_state->TextA.Data; + BufSize = edit_state->BufCapacityA = new_buf_size; + } + + if (BufTextLen != pos) + memmove(Buf + pos + new_text_len, Buf + pos, (size_t)(BufTextLen - pos)); + memcpy(Buf + pos, new_text, (size_t)new_text_len * sizeof(char)); + Buf[BufTextLen + new_text_len] = '\0'; + + if (CursorPos >= pos) + CursorPos += new_text_len; + SelectionStart = SelectionEnd = CursorPos; + BufDirty = true; + BufTextLen += new_text_len; +} + +// Return false to discard a character. +static bool InputTextFilterCharacter(unsigned int* p_char, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data) +{ + unsigned int c = *p_char; + + // Filter non-printable (NB: isprint is unreliable! see #2467) + if (c < 0x20) + { + bool pass = false; + pass |= (c == '\n' && (flags & ImGuiInputTextFlags_Multiline)); + pass |= (c == '\t' && (flags & ImGuiInputTextFlags_AllowTabInput)); + if (!pass) + return false; + } + + // We ignore Ascii representation of delete (emitted from Backspace on OSX, see #2578, #2817) + if (c == 127) + return false; + + // Filter private Unicode range. GLFW on OSX seems to send private characters for special keys like arrow keys (FIXME) + if (c >= 0xE000 && c <= 0xF8FF) + return false; + + // Filter Unicode ranges we are not handling in this build. + if (c > IM_UNICODE_CODEPOINT_MAX) + return false; + + // Generic named filters + if (flags & (ImGuiInputTextFlags_CharsDecimal | ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsUppercase | ImGuiInputTextFlags_CharsNoBlank | ImGuiInputTextFlags_CharsScientific)) + { + if (flags & ImGuiInputTextFlags_CharsDecimal) + if (!(c >= '0' && c <= '9') && (c != '.') && (c != '-') && (c != '+') && (c != '*') && (c != '/')) + return false; + + if (flags & ImGuiInputTextFlags_CharsScientific) + if (!(c >= '0' && c <= '9') && (c != '.') && (c != '-') && (c != '+') && (c != '*') && (c != '/') && (c != 'e') && (c != 'E')) + return false; + + if (flags & ImGuiInputTextFlags_CharsHexadecimal) + if (!(c >= '0' && c <= '9') && !(c >= 'a' && c <= 'f') && !(c >= 'A' && c <= 'F')) + return false; + + if (flags & ImGuiInputTextFlags_CharsUppercase) + if (c >= 'a' && c <= 'z') + *p_char = (c += (unsigned int)('A'-'a')); + + if (flags & ImGuiInputTextFlags_CharsNoBlank) + if (ImCharIsBlankW(c)) + return false; + } + + // Custom callback filter + if (flags & ImGuiInputTextFlags_CallbackCharFilter) + { + ImGuiInputTextCallbackData callback_data; + memset(&callback_data, 0, sizeof(ImGuiInputTextCallbackData)); + callback_data.EventFlag = ImGuiInputTextFlags_CallbackCharFilter; + callback_data.EventChar = (ImWchar)c; + callback_data.Flags = flags; + callback_data.UserData = user_data; + if (callback(&callback_data) != 0) + return false; + *p_char = callback_data.EventChar; + if (!callback_data.EventChar) + return false; + } + + return true; +} + +// Edit a string of text +// - buf_size account for the zero-terminator, so a buf_size of 6 can hold "Hello" but not "Hello!". +// This is so we can easily call InputText() on static arrays using ARRAYSIZE() and to match +// Note that in std::string world, capacity() would omit 1 byte used by the zero-terminator. +// - When active, hold on a privately held copy of the text (and apply back to 'buf'). So changing 'buf' while the InputText is active has no effect. +// - If you want to use ImGui::InputText() with std::string, see misc/cpp/imgui_stdlib.h +// (FIXME: Rather confusing and messy function, among the worse part of our codebase, expecting to rewrite a V2 at some point.. Partly because we are +// doing UTF8 > U16 > UTF8 conversions on the go to easily interface with stb_textedit. Ideally should stay in UTF-8 all the time. See https://github.com/nothings/stb/issues/188) +bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_size, const ImVec2& size_arg, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* callback_user_data) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + IM_ASSERT(buf != NULL && buf_size >= 0); + IM_ASSERT(!((flags & ImGuiInputTextFlags_CallbackHistory) && (flags & ImGuiInputTextFlags_Multiline))); // Can't use both together (they both use up/down keys) + IM_ASSERT(!((flags & ImGuiInputTextFlags_CallbackCompletion) && (flags & ImGuiInputTextFlags_AllowTabInput))); // Can't use both together (they both use tab key) + + ImGuiContext& g = *GImGui; + ImGuiIO& io = g.IO; + const ImGuiStyle& style = g.Style; + + const bool RENDER_SELECTION_WHEN_INACTIVE = false; + const bool is_multiline = (flags & ImGuiInputTextFlags_Multiline) != 0; + const bool is_readonly = (flags & ImGuiInputTextFlags_ReadOnly) != 0; + const bool is_password = (flags & ImGuiInputTextFlags_Password) != 0; + const bool is_undoable = (flags & ImGuiInputTextFlags_NoUndoRedo) == 0; + const bool is_resizable = (flags & ImGuiInputTextFlags_CallbackResize) != 0; + if (is_resizable) + IM_ASSERT(callback != NULL); // Must provide a callback if you set the ImGuiInputTextFlags_CallbackResize flag! + + if (is_multiline) // Open group before calling GetID() because groups tracks id created within their scope, + BeginGroup(); + const ImGuiID id = window->GetID(label); + const ImVec2 label_size = CalcTextSize(label, NULL, true); + const ImVec2 frame_size = CalcItemSize(size_arg, CalcItemWidth(), (is_multiline ? g.FontSize * 8.0f : label_size.y) + style.FramePadding.y*2.0f); // Arbitrary default of 8 lines high for multi-line + const ImVec2 total_size = ImVec2(frame_size.x + (label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f), frame_size.y); + + const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + frame_size); + const ImRect total_bb(frame_bb.Min, frame_bb.Min + total_size); + + ImGuiWindow* draw_window = window; + ImVec2 inner_size = frame_size; + if (is_multiline) + { + if (!ItemAdd(total_bb, id, &frame_bb)) + { + ItemSize(total_bb, style.FramePadding.y); + EndGroup(); + return false; + } + + // We reproduce the contents of BeginChildFrame() in order to provide 'label' so our window internal data are easier to read/debug. + PushStyleColor(ImGuiCol_ChildBg, style.Colors[ImGuiCol_FrameBg]); + PushStyleVar(ImGuiStyleVar_ChildRounding, style.FrameRounding); + PushStyleVar(ImGuiStyleVar_ChildBorderSize, style.FrameBorderSize); + PushStyleVar(ImGuiStyleVar_WindowPadding, style.FramePadding); + bool child_visible = BeginChildEx(label, id, frame_bb.GetSize(), true, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysUseWindowPadding); + PopStyleVar(3); + PopStyleColor(); + if (!child_visible) + { + EndChild(); + EndGroup(); + return false; + } + draw_window = g.CurrentWindow; // Child window + draw_window->DC.NavLayerActiveMaskNext |= draw_window->DC.NavLayerCurrentMask; // This is to ensure that EndChild() will display a navigation highlight so we can "enter" into it. + inner_size.x -= draw_window->ScrollbarSizes.x; + } + else + { + ItemSize(total_bb, style.FramePadding.y); + if (!ItemAdd(total_bb, id, &frame_bb)) + return false; + } + const bool hovered = ItemHoverable(frame_bb, id); + if (hovered) + g.MouseCursor = ImGuiMouseCursor_TextInput; + + // We are only allowed to access the state if we are already the active widget. + ImGuiInputTextState* state = GetInputTextState(id); + + const bool focus_requested = FocusableItemRegister(window, id); + const bool focus_requested_by_code = focus_requested && (g.FocusRequestCurrWindow == window && g.FocusRequestCurrCounterRegular == window->DC.FocusCounterRegular); + const bool focus_requested_by_tab = focus_requested && !focus_requested_by_code; + + const bool user_clicked = hovered && io.MouseClicked[0]; + const bool user_nav_input_start = (g.ActiveId != id) && ((g.NavInputId == id) || (g.NavActivateId == id && g.NavInputSource == ImGuiInputSource_NavKeyboard)); + const bool user_scroll_finish = is_multiline && state != NULL && g.ActiveId == 0 && g.ActiveIdPreviousFrame == GetWindowScrollbarID(draw_window, ImGuiAxis_Y); + const bool user_scroll_active = is_multiline && state != NULL && g.ActiveId == GetWindowScrollbarID(draw_window, ImGuiAxis_Y); + + bool clear_active_id = false; + bool select_all = (g.ActiveId != id) && ((flags & ImGuiInputTextFlags_AutoSelectAll) != 0 || user_nav_input_start) && (!is_multiline); + + const bool init_make_active = (focus_requested || user_clicked || user_scroll_finish || user_nav_input_start); + const bool init_state = (init_make_active || user_scroll_active); + if (init_state && g.ActiveId != id) + { + // Access state even if we don't own it yet. + state = &g.InputTextState; + state->CursorAnimReset(); + + // Take a copy of the initial buffer value (both in original UTF-8 format and converted to wchar) + // From the moment we focused we are ignoring the content of 'buf' (unless we are in read-only mode) + const int buf_len = (int)strlen(buf); + state->InitialTextA.resize(buf_len + 1); // UTF-8. we use +1 to make sure that .Data is always pointing to at least an empty string. + memcpy(state->InitialTextA.Data, buf, buf_len + 1); + + // Start edition + const char* buf_end = NULL; + state->TextW.resize(buf_size + 1); // wchar count <= UTF-8 count. we use +1 to make sure that .Data is always pointing to at least an empty string. + state->TextA.resize(0); + state->TextAIsValid = false; // TextA is not valid yet (we will display buf until then) + state->CurLenW = ImTextStrFromUtf8(state->TextW.Data, buf_size, buf, NULL, &buf_end); + state->CurLenA = (int)(buf_end - buf); // We can't get the result from ImStrncpy() above because it is not UTF-8 aware. Here we'll cut off malformed UTF-8. + + // Preserve cursor position and undo/redo stack if we come back to same widget + // FIXME: For non-readonly widgets we might be able to require that TextAIsValid && TextA == buf ? (untested) and discard undo stack if user buffer has changed. + const bool recycle_state = (state->ID == id); + if (recycle_state) + { + // Recycle existing cursor/selection/undo stack but clamp position + // Note a single mouse click will override the cursor/position immediately by calling stb_textedit_click handler. + state->CursorClamp(); + } + else + { + state->ID = id; + state->ScrollX = 0.0f; + stb_textedit_initialize_state(&state->Stb, !is_multiline); + if (!is_multiline && focus_requested_by_code) + select_all = true; + } + if (flags & ImGuiInputTextFlags_AlwaysInsertMode) + state->Stb.insert_mode = 1; + if (!is_multiline && (focus_requested_by_tab || (user_clicked && io.KeyCtrl))) + select_all = true; + } + + if (g.ActiveId != id && init_make_active) + { + IM_ASSERT(state && state->ID == id); + SetActiveID(id, window); + SetFocusID(id, window); + FocusWindow(window); + + // Declare our inputs + IM_ASSERT(ImGuiNavInput_COUNT < 32); + g.ActiveIdUsingNavDirMask |= (1 << ImGuiDir_Left) | (1 << ImGuiDir_Right); + if (is_multiline || (flags & ImGuiInputTextFlags_CallbackHistory)) + g.ActiveIdUsingNavDirMask |= (1 << ImGuiDir_Up) | (1 << ImGuiDir_Down); + g.ActiveIdUsingNavInputMask |= (1 << ImGuiNavInput_Cancel); + g.ActiveIdUsingKeyInputMask |= ((ImU64)1 << ImGuiKey_Home) | ((ImU64)1 << ImGuiKey_End); + if (is_multiline) + g.ActiveIdUsingKeyInputMask |= ((ImU64)1 << ImGuiKey_PageUp) | ((ImU64)1 << ImGuiKey_PageDown); // FIXME-NAV: Page up/down actually not supported yet by widget, but claim them ahead. + if (flags & (ImGuiInputTextFlags_CallbackCompletion | ImGuiInputTextFlags_AllowTabInput)) // Disable keyboard tabbing out as we will use the \t character. + g.ActiveIdUsingKeyInputMask |= ((ImU64)1 << ImGuiKey_Tab); + } + + // We have an edge case if ActiveId was set through another widget (e.g. widget being swapped), clear id immediately (don't wait until the end of the function) + if (g.ActiveId == id && state == NULL) + ClearActiveID(); + + // Release focus when we click outside + if (g.ActiveId == id && io.MouseClicked[0] && !init_state && !init_make_active) //-V560 + clear_active_id = true; + + // Lock the decision of whether we are going to take the path displaying the cursor or selection + const bool render_cursor = (g.ActiveId == id) || (state && user_scroll_active); + bool render_selection = state && state->HasSelection() && (RENDER_SELECTION_WHEN_INACTIVE || render_cursor); + bool value_changed = false; + bool enter_pressed = false; + + // When read-only we always use the live data passed to the function + // FIXME-OPT: Because our selection/cursor code currently needs the wide text we need to convert it when active, which is not ideal :( + if (is_readonly && state != NULL && (render_cursor || render_selection)) + { + const char* buf_end = NULL; + state->TextW.resize(buf_size + 1); + state->CurLenW = ImTextStrFromUtf8(state->TextW.Data, state->TextW.Size, buf, NULL, &buf_end); + state->CurLenA = (int)(buf_end - buf); + state->CursorClamp(); + render_selection &= state->HasSelection(); + } + + // Select the buffer to render. + const bool buf_display_from_state = (render_cursor || render_selection || g.ActiveId == id) && !is_readonly && state && state->TextAIsValid; + const bool is_displaying_hint = (hint != NULL && (buf_display_from_state ? state->TextA.Data : buf)[0] == 0); + + // Password pushes a temporary font with only a fallback glyph + if (is_password && !is_displaying_hint) + { + const ImFontGlyph* glyph = g.Font->FindGlyph('*'); + ImFont* password_font = &g.InputTextPasswordFont; + password_font->FontSize = g.Font->FontSize; + password_font->Scale = g.Font->Scale; + password_font->DisplayOffset = g.Font->DisplayOffset; + password_font->Ascent = g.Font->Ascent; + password_font->Descent = g.Font->Descent; + password_font->ContainerAtlas = g.Font->ContainerAtlas; + password_font->FallbackGlyph = glyph; + password_font->FallbackAdvanceX = glyph->AdvanceX; + IM_ASSERT(password_font->Glyphs.empty() && password_font->IndexAdvanceX.empty() && password_font->IndexLookup.empty()); + PushFont(password_font); + } + + // Process mouse inputs and character inputs + int backup_current_text_length = 0; + if (g.ActiveId == id) + { + IM_ASSERT(state != NULL); + backup_current_text_length = state->CurLenA; + state->BufCapacityA = buf_size; + state->UserFlags = flags; + state->UserCallback = callback; + state->UserCallbackData = callback_user_data; + + // Although we are active we don't prevent mouse from hovering other elements unless we are interacting right now with the widget. + // Down the line we should have a cleaner library-wide concept of Selected vs Active. + g.ActiveIdAllowOverlap = !io.MouseDown[0]; + g.WantTextInputNextFrame = 1; + + // Edit in progress + const float mouse_x = (io.MousePos.x - frame_bb.Min.x - style.FramePadding.x) + state->ScrollX; + const float mouse_y = (is_multiline ? (io.MousePos.y - draw_window->DC.CursorPos.y - style.FramePadding.y) : (g.FontSize*0.5f)); + + const bool is_osx = io.ConfigMacOSXBehaviors; + if (select_all || (hovered && !is_osx && io.MouseDoubleClicked[0])) + { + state->SelectAll(); + state->SelectedAllMouseLock = true; + } + else if (hovered && is_osx && io.MouseDoubleClicked[0]) + { + // Double-click select a word only, OS X style (by simulating keystrokes) + state->OnKeyPressed(STB_TEXTEDIT_K_WORDLEFT); + state->OnKeyPressed(STB_TEXTEDIT_K_WORDRIGHT | STB_TEXTEDIT_K_SHIFT); + } + else if (io.MouseClicked[0] && !state->SelectedAllMouseLock) + { + if (hovered) + { + stb_textedit_click(state, &state->Stb, mouse_x, mouse_y); + state->CursorAnimReset(); + } + } + else if (io.MouseDown[0] && !state->SelectedAllMouseLock && (io.MouseDelta.x != 0.0f || io.MouseDelta.y != 0.0f)) + { + stb_textedit_drag(state, &state->Stb, mouse_x, mouse_y); + state->CursorAnimReset(); + state->CursorFollow = true; + } + if (state->SelectedAllMouseLock && !io.MouseDown[0]) + state->SelectedAllMouseLock = false; + + // It is ill-defined whether the back-end needs to send a \t character when pressing the TAB keys. + // Win32 and GLFW naturally do it but not SDL. + const bool ignore_char_inputs = (io.KeyCtrl && !io.KeyAlt) || (is_osx && io.KeySuper); + if ((flags & ImGuiInputTextFlags_AllowTabInput) && IsKeyPressedMap(ImGuiKey_Tab) && !ignore_char_inputs && !io.KeyShift && !is_readonly) + if (!io.InputQueueCharacters.contains('\t')) + { + unsigned int c = '\t'; // Insert TAB + if (InputTextFilterCharacter(&c, flags, callback, callback_user_data)) + state->OnKeyPressed((int)c); + } + + // Process regular text input (before we check for Return because using some IME will effectively send a Return?) + // We ignore CTRL inputs, but need to allow ALT+CTRL as some keyboards (e.g. German) use AltGR (which _is_ Alt+Ctrl) to input certain characters. + if (io.InputQueueCharacters.Size > 0) + { + if (!ignore_char_inputs && !is_readonly && !user_nav_input_start) + for (int n = 0; n < io.InputQueueCharacters.Size; n++) + { + // Insert character if they pass filtering + unsigned int c = (unsigned int)io.InputQueueCharacters[n]; + if (c == '\t' && io.KeyShift) + continue; + if (InputTextFilterCharacter(&c, flags, callback, callback_user_data)) + state->OnKeyPressed((int)c); + } + + // Consume characters + io.InputQueueCharacters.resize(0); + } + } + + // Process other shortcuts/key-presses + bool cancel_edit = false; + if (g.ActiveId == id && !g.ActiveIdIsJustActivated && !clear_active_id) + { + IM_ASSERT(state != NULL); + IM_ASSERT(io.KeyMods == GetMergedKeyModFlags() && "Mismatching io.KeyCtrl/io.KeyShift/io.KeyAlt/io.KeySuper vs io.KeyMods"); // We rarely do this check, but if anything let's do it here. + + const int k_mask = (io.KeyShift ? STB_TEXTEDIT_K_SHIFT : 0); + const bool is_osx = io.ConfigMacOSXBehaviors; + const bool is_osx_shift_shortcut = is_osx && (io.KeyMods == (ImGuiKeyModFlags_Super | ImGuiKeyModFlags_Shift)); + const bool is_wordmove_key_down = is_osx ? io.KeyAlt : io.KeyCtrl; // OS X style: Text editing cursor movement using Alt instead of Ctrl + const bool is_startend_key_down = is_osx && io.KeySuper && !io.KeyCtrl && !io.KeyAlt; // OS X style: Line/Text Start and End using Cmd+Arrows instead of Home/End + const bool is_ctrl_key_only = (io.KeyMods == ImGuiKeyModFlags_Ctrl); + const bool is_shift_key_only = (io.KeyMods == ImGuiKeyModFlags_Shift); + const bool is_shortcut_key = g.IO.ConfigMacOSXBehaviors ? (io.KeyMods == ImGuiKeyModFlags_Super) : (io.KeyMods == ImGuiKeyModFlags_Ctrl); + + const bool is_cut = ((is_shortcut_key && IsKeyPressedMap(ImGuiKey_X)) || (is_shift_key_only && IsKeyPressedMap(ImGuiKey_Delete))) && !is_readonly && !is_password && (!is_multiline || state->HasSelection()); + const bool is_copy = ((is_shortcut_key && IsKeyPressedMap(ImGuiKey_C)) || (is_ctrl_key_only && IsKeyPressedMap(ImGuiKey_Insert))) && !is_password && (!is_multiline || state->HasSelection()); + const bool is_paste = ((is_shortcut_key && IsKeyPressedMap(ImGuiKey_V)) || (is_shift_key_only && IsKeyPressedMap(ImGuiKey_Insert))) && !is_readonly; + const bool is_undo = ((is_shortcut_key && IsKeyPressedMap(ImGuiKey_Z)) && !is_readonly && is_undoable); + const bool is_redo = ((is_shortcut_key && IsKeyPressedMap(ImGuiKey_Y)) || (is_osx_shift_shortcut && IsKeyPressedMap(ImGuiKey_Z))) && !is_readonly && is_undoable; + + if (IsKeyPressedMap(ImGuiKey_LeftArrow)) { state->OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_LINESTART : is_wordmove_key_down ? STB_TEXTEDIT_K_WORDLEFT : STB_TEXTEDIT_K_LEFT) | k_mask); } + else if (IsKeyPressedMap(ImGuiKey_RightArrow)) { state->OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_LINEEND : is_wordmove_key_down ? STB_TEXTEDIT_K_WORDRIGHT : STB_TEXTEDIT_K_RIGHT) | k_mask); } + else if (IsKeyPressedMap(ImGuiKey_UpArrow) && is_multiline) { if (io.KeyCtrl) SetScrollY(draw_window, ImMax(draw_window->Scroll.y - g.FontSize, 0.0f)); else state->OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_TEXTSTART : STB_TEXTEDIT_K_UP) | k_mask); } + else if (IsKeyPressedMap(ImGuiKey_DownArrow) && is_multiline) { if (io.KeyCtrl) SetScrollY(draw_window, ImMin(draw_window->Scroll.y + g.FontSize, GetScrollMaxY())); else state->OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_TEXTEND : STB_TEXTEDIT_K_DOWN) | k_mask); } + else if (IsKeyPressedMap(ImGuiKey_Home)) { state->OnKeyPressed(io.KeyCtrl ? STB_TEXTEDIT_K_TEXTSTART | k_mask : STB_TEXTEDIT_K_LINESTART | k_mask); } + else if (IsKeyPressedMap(ImGuiKey_End)) { state->OnKeyPressed(io.KeyCtrl ? STB_TEXTEDIT_K_TEXTEND | k_mask : STB_TEXTEDIT_K_LINEEND | k_mask); } + else if (IsKeyPressedMap(ImGuiKey_Delete) && !is_readonly) { state->OnKeyPressed(STB_TEXTEDIT_K_DELETE | k_mask); } + else if (IsKeyPressedMap(ImGuiKey_Backspace) && !is_readonly) + { + if (!state->HasSelection()) + { + if (is_wordmove_key_down) + state->OnKeyPressed(STB_TEXTEDIT_K_WORDLEFT|STB_TEXTEDIT_K_SHIFT); + else if (is_osx && io.KeySuper && !io.KeyAlt && !io.KeyCtrl) + state->OnKeyPressed(STB_TEXTEDIT_K_LINESTART|STB_TEXTEDIT_K_SHIFT); + } + state->OnKeyPressed(STB_TEXTEDIT_K_BACKSPACE | k_mask); + } + else if (IsKeyPressedMap(ImGuiKey_Enter) || IsKeyPressedMap(ImGuiKey_KeyPadEnter)) + { + bool ctrl_enter_for_new_line = (flags & ImGuiInputTextFlags_CtrlEnterForNewLine) != 0; + if (!is_multiline || (ctrl_enter_for_new_line && !io.KeyCtrl) || (!ctrl_enter_for_new_line && io.KeyCtrl)) + { + enter_pressed = clear_active_id = true; + } + else if (!is_readonly) + { + unsigned int c = '\n'; // Insert new line + if (InputTextFilterCharacter(&c, flags, callback, callback_user_data)) + state->OnKeyPressed((int)c); + } + } + else if (IsKeyPressedMap(ImGuiKey_Escape)) + { + clear_active_id = cancel_edit = true; + } + else if (is_undo || is_redo) + { + state->OnKeyPressed(is_undo ? STB_TEXTEDIT_K_UNDO : STB_TEXTEDIT_K_REDO); + state->ClearSelection(); + } + else if (is_shortcut_key && IsKeyPressedMap(ImGuiKey_A)) + { + state->SelectAll(); + state->CursorFollow = true; + } + else if (is_cut || is_copy) + { + // Cut, Copy + if (io.SetClipboardTextFn) + { + const int ib = state->HasSelection() ? ImMin(state->Stb.select_start, state->Stb.select_end) : 0; + const int ie = state->HasSelection() ? ImMax(state->Stb.select_start, state->Stb.select_end) : state->CurLenW; + const int clipboard_data_len = ImTextCountUtf8BytesFromStr(state->TextW.Data + ib, state->TextW.Data + ie) + 1; + char* clipboard_data = (char*)IM_ALLOC(clipboard_data_len * sizeof(char)); + ImTextStrToUtf8(clipboard_data, clipboard_data_len, state->TextW.Data + ib, state->TextW.Data + ie); + SetClipboardText(clipboard_data); + MemFree(clipboard_data); + } + if (is_cut) + { + if (!state->HasSelection()) + state->SelectAll(); + state->CursorFollow = true; + stb_textedit_cut(state, &state->Stb); + } + } + else if (is_paste) + { + if (const char* clipboard = GetClipboardText()) + { + // Filter pasted buffer + const int clipboard_len = (int)strlen(clipboard); + ImWchar* clipboard_filtered = (ImWchar*)IM_ALLOC((clipboard_len+1) * sizeof(ImWchar)); + int clipboard_filtered_len = 0; + for (const char* s = clipboard; *s; ) + { + unsigned int c; + s += ImTextCharFromUtf8(&c, s, NULL); + if (c == 0) + break; + if (!InputTextFilterCharacter(&c, flags, callback, callback_user_data)) + continue; + clipboard_filtered[clipboard_filtered_len++] = (ImWchar)c; + } + clipboard_filtered[clipboard_filtered_len] = 0; + if (clipboard_filtered_len > 0) // If everything was filtered, ignore the pasting operation + { + stb_textedit_paste(state, &state->Stb, clipboard_filtered, clipboard_filtered_len); + state->CursorFollow = true; + } + MemFree(clipboard_filtered); + } + } + + // Update render selection flag after events have been handled, so selection highlight can be displayed during the same frame. + render_selection |= state->HasSelection() && (RENDER_SELECTION_WHEN_INACTIVE || render_cursor); + } + + // Process callbacks and apply result back to user's buffer. + if (g.ActiveId == id) + { + IM_ASSERT(state != NULL); + const char* apply_new_text = NULL; + int apply_new_text_length = 0; + if (cancel_edit) + { + // Restore initial value. Only return true if restoring to the initial value changes the current buffer contents. + if (!is_readonly && strcmp(buf, state->InitialTextA.Data) != 0) + { + // Push records into the undo stack so we can CTRL+Z the revert operation itself + apply_new_text = state->InitialTextA.Data; + apply_new_text_length = state->InitialTextA.Size - 1; + ImVector w_text; + if (apply_new_text_length > 0) + { + w_text.resize(ImTextCountCharsFromUtf8(apply_new_text, apply_new_text + apply_new_text_length) + 1); + ImTextStrFromUtf8(w_text.Data, w_text.Size, apply_new_text, apply_new_text + apply_new_text_length); + } + stb_textedit_replace(state, &state->Stb, w_text.Data, (apply_new_text_length > 0) ? (w_text.Size - 1) : 0); + } + } + + // When using 'ImGuiInputTextFlags_EnterReturnsTrue' as a special case we reapply the live buffer back to the input buffer before clearing ActiveId, even though strictly speaking it wasn't modified on this frame. + // If we didn't do that, code like InputInt() with ImGuiInputTextFlags_EnterReturnsTrue would fail. + // This also allows the user to use InputText() with ImGuiInputTextFlags_EnterReturnsTrue without maintaining any user-side storage (please note that if you use this property along ImGuiInputTextFlags_CallbackResize you can end up with your temporary string object unnecessarily allocating once a frame, either store your string data, either if you don't then don't use ImGuiInputTextFlags_CallbackResize). + bool apply_edit_back_to_user_buffer = !cancel_edit || (enter_pressed && (flags & ImGuiInputTextFlags_EnterReturnsTrue) != 0); + if (apply_edit_back_to_user_buffer) + { + // Apply new value immediately - copy modified buffer back + // Note that as soon as the input box is active, the in-widget value gets priority over any underlying modification of the input buffer + // FIXME: We actually always render 'buf' when calling DrawList->AddText, making the comment above incorrect. + // FIXME-OPT: CPU waste to do this every time the widget is active, should mark dirty state from the stb_textedit callbacks. + if (!is_readonly) + { + state->TextAIsValid = true; + state->TextA.resize(state->TextW.Size * 4 + 1); + ImTextStrToUtf8(state->TextA.Data, state->TextA.Size, state->TextW.Data, NULL); + } + + // User callback + if ((flags & (ImGuiInputTextFlags_CallbackCompletion | ImGuiInputTextFlags_CallbackHistory | ImGuiInputTextFlags_CallbackAlways)) != 0) + { + IM_ASSERT(callback != NULL); + + // The reason we specify the usage semantic (Completion/History) is that Completion needs to disable keyboard TABBING at the moment. + ImGuiInputTextFlags event_flag = 0; + ImGuiKey event_key = ImGuiKey_COUNT; + if ((flags & ImGuiInputTextFlags_CallbackCompletion) != 0 && IsKeyPressedMap(ImGuiKey_Tab)) + { + event_flag = ImGuiInputTextFlags_CallbackCompletion; + event_key = ImGuiKey_Tab; + } + else if ((flags & ImGuiInputTextFlags_CallbackHistory) != 0 && IsKeyPressedMap(ImGuiKey_UpArrow)) + { + event_flag = ImGuiInputTextFlags_CallbackHistory; + event_key = ImGuiKey_UpArrow; + } + else if ((flags & ImGuiInputTextFlags_CallbackHistory) != 0 && IsKeyPressedMap(ImGuiKey_DownArrow)) + { + event_flag = ImGuiInputTextFlags_CallbackHistory; + event_key = ImGuiKey_DownArrow; + } + else if (flags & ImGuiInputTextFlags_CallbackAlways) + event_flag = ImGuiInputTextFlags_CallbackAlways; + + if (event_flag) + { + ImGuiInputTextCallbackData callback_data; + memset(&callback_data, 0, sizeof(ImGuiInputTextCallbackData)); + callback_data.EventFlag = event_flag; + callback_data.Flags = flags; + callback_data.UserData = callback_user_data; + + callback_data.EventKey = event_key; + callback_data.Buf = state->TextA.Data; + callback_data.BufTextLen = state->CurLenA; + callback_data.BufSize = state->BufCapacityA; + callback_data.BufDirty = false; + + // We have to convert from wchar-positions to UTF-8-positions, which can be pretty slow (an incentive to ditch the ImWchar buffer, see https://github.com/nothings/stb/issues/188) + ImWchar* text = state->TextW.Data; + const int utf8_cursor_pos = callback_data.CursorPos = ImTextCountUtf8BytesFromStr(text, text + state->Stb.cursor); + const int utf8_selection_start = callback_data.SelectionStart = ImTextCountUtf8BytesFromStr(text, text + state->Stb.select_start); + const int utf8_selection_end = callback_data.SelectionEnd = ImTextCountUtf8BytesFromStr(text, text + state->Stb.select_end); + + // Call user code + callback(&callback_data); + + // Read back what user may have modified + IM_ASSERT(callback_data.Buf == state->TextA.Data); // Invalid to modify those fields + IM_ASSERT(callback_data.BufSize == state->BufCapacityA); + IM_ASSERT(callback_data.Flags == flags); + if (callback_data.CursorPos != utf8_cursor_pos) { state->Stb.cursor = ImTextCountCharsFromUtf8(callback_data.Buf, callback_data.Buf + callback_data.CursorPos); state->CursorFollow = true; } + if (callback_data.SelectionStart != utf8_selection_start) { state->Stb.select_start = ImTextCountCharsFromUtf8(callback_data.Buf, callback_data.Buf + callback_data.SelectionStart); } + if (callback_data.SelectionEnd != utf8_selection_end) { state->Stb.select_end = ImTextCountCharsFromUtf8(callback_data.Buf, callback_data.Buf + callback_data.SelectionEnd); } + if (callback_data.BufDirty) + { + IM_ASSERT(callback_data.BufTextLen == (int)strlen(callback_data.Buf)); // You need to maintain BufTextLen if you change the text! + if (callback_data.BufTextLen > backup_current_text_length && is_resizable) + state->TextW.resize(state->TextW.Size + (callback_data.BufTextLen - backup_current_text_length)); + state->CurLenW = ImTextStrFromUtf8(state->TextW.Data, state->TextW.Size, callback_data.Buf, NULL); + state->CurLenA = callback_data.BufTextLen; // Assume correct length and valid UTF-8 from user, saves us an extra strlen() + state->CursorAnimReset(); + } + } + } + + // Will copy result string if modified + if (!is_readonly && strcmp(state->TextA.Data, buf) != 0) + { + apply_new_text = state->TextA.Data; + apply_new_text_length = state->CurLenA; + } + } + + // Copy result to user buffer + if (apply_new_text) + { + // We cannot test for 'backup_current_text_length != apply_new_text_length' here because we have no guarantee that the size + // of our owned buffer matches the size of the string object held by the user, and by design we allow InputText() to be used + // without any storage on user's side. + IM_ASSERT(apply_new_text_length >= 0); + if (is_resizable) + { + ImGuiInputTextCallbackData callback_data; + callback_data.EventFlag = ImGuiInputTextFlags_CallbackResize; + callback_data.Flags = flags; + callback_data.Buf = buf; + callback_data.BufTextLen = apply_new_text_length; + callback_data.BufSize = ImMax(buf_size, apply_new_text_length + 1); + callback_data.UserData = callback_user_data; + callback(&callback_data); + buf = callback_data.Buf; + buf_size = callback_data.BufSize; + apply_new_text_length = ImMin(callback_data.BufTextLen, buf_size - 1); + IM_ASSERT(apply_new_text_length <= buf_size); + } + //IMGUI_DEBUG_LOG("InputText(\"%s\"): apply_new_text length %d\n", label, apply_new_text_length); + + // If the underlying buffer resize was denied or not carried to the next frame, apply_new_text_length+1 may be >= buf_size. + ImStrncpy(buf, apply_new_text, ImMin(apply_new_text_length + 1, buf_size)); + value_changed = true; + } + + // Clear temporary user storage + state->UserFlags = 0; + state->UserCallback = NULL; + state->UserCallbackData = NULL; + } + + // Release active ID at the end of the function (so e.g. pressing Return still does a final application of the value) + if (clear_active_id && g.ActiveId == id) + ClearActiveID(); + + // Render frame + if (!is_multiline) + { + RenderNavHighlight(frame_bb, id); + RenderFrame(frame_bb.Min, frame_bb.Max, GetColorU32(ImGuiCol_FrameBg), true, style.FrameRounding); + } + + const ImVec4 clip_rect(frame_bb.Min.x, frame_bb.Min.y, frame_bb.Min.x + inner_size.x, frame_bb.Min.y + inner_size.y); // Not using frame_bb.Max because we have adjusted size + ImVec2 draw_pos = is_multiline ? draw_window->DC.CursorPos : frame_bb.Min + style.FramePadding; + ImVec2 text_size(0.0f, 0.0f); + + // Set upper limit of single-line InputTextEx() at 2 million characters strings. The current pathological worst case is a long line + // without any carriage return, which would makes ImFont::RenderText() reserve too many vertices and probably crash. Avoid it altogether. + // Note that we only use this limit on single-line InputText(), so a pathologically large line on a InputTextMultiline() would still crash. + const int buf_display_max_length = 2 * 1024 * 1024; + const char* buf_display = buf_display_from_state ? state->TextA.Data : buf; //-V595 + const char* buf_display_end = NULL; // We have specialized paths below for setting the length + if (is_displaying_hint) + { + buf_display = hint; + buf_display_end = hint + strlen(hint); + } + + // Render text. We currently only render selection when the widget is active or while scrolling. + // FIXME: We could remove the '&& render_cursor' to keep rendering selection when inactive. + if (render_cursor || render_selection) + { + IM_ASSERT(state != NULL); + if (!is_displaying_hint) + buf_display_end = buf_display + state->CurLenA; + + // Render text (with cursor and selection) + // This is going to be messy. We need to: + // - Display the text (this alone can be more easily clipped) + // - Handle scrolling, highlight selection, display cursor (those all requires some form of 1d->2d cursor position calculation) + // - Measure text height (for scrollbar) + // We are attempting to do most of that in **one main pass** to minimize the computation cost (non-negligible for large amount of text) + 2nd pass for selection rendering (we could merge them by an extra refactoring effort) + // FIXME: This should occur on buf_display but we'd need to maintain cursor/select_start/select_end for UTF-8. + const ImWchar* text_begin = state->TextW.Data; + ImVec2 cursor_offset, select_start_offset; + + { + // Find lines numbers straddling 'cursor' (slot 0) and 'select_start' (slot 1) positions. + const ImWchar* searches_input_ptr[2] = { NULL, NULL }; + int searches_result_line_no[2] = { -1000, -1000 }; + int searches_remaining = 0; + if (render_cursor) + { + searches_input_ptr[0] = text_begin + state->Stb.cursor; + searches_result_line_no[0] = -1; + searches_remaining++; + } + if (render_selection) + { + searches_input_ptr[1] = text_begin + ImMin(state->Stb.select_start, state->Stb.select_end); + searches_result_line_no[1] = -1; + searches_remaining++; + } + + // Iterate all lines to find our line numbers + // In multi-line mode, we never exit the loop until all lines are counted, so add one extra to the searches_remaining counter. + searches_remaining += is_multiline ? 1 : 0; + int line_count = 0; + //for (const ImWchar* s = text_begin; (s = (const ImWchar*)wcschr((const wchar_t*)s, (wchar_t)'\n')) != NULL; s++) // FIXME-OPT: Could use this when wchar_t are 16-bit + for (const ImWchar* s = text_begin; *s != 0; s++) + if (*s == '\n') + { + line_count++; + if (searches_result_line_no[0] == -1 && s >= searches_input_ptr[0]) { searches_result_line_no[0] = line_count; if (--searches_remaining <= 0) break; } + if (searches_result_line_no[1] == -1 && s >= searches_input_ptr[1]) { searches_result_line_no[1] = line_count; if (--searches_remaining <= 0) break; } + } + line_count++; + if (searches_result_line_no[0] == -1) + searches_result_line_no[0] = line_count; + if (searches_result_line_no[1] == -1) + searches_result_line_no[1] = line_count; + + // Calculate 2d position by finding the beginning of the line and measuring distance + cursor_offset.x = InputTextCalcTextSizeW(ImStrbolW(searches_input_ptr[0], text_begin), searches_input_ptr[0]).x; + cursor_offset.y = searches_result_line_no[0] * g.FontSize; + if (searches_result_line_no[1] >= 0) + { + select_start_offset.x = InputTextCalcTextSizeW(ImStrbolW(searches_input_ptr[1], text_begin), searches_input_ptr[1]).x; + select_start_offset.y = searches_result_line_no[1] * g.FontSize; + } + + // Store text height (note that we haven't calculated text width at all, see GitHub issues #383, #1224) + if (is_multiline) + text_size = ImVec2(inner_size.x, line_count * g.FontSize); + } + + // Scroll + if (render_cursor && state->CursorFollow) + { + // Horizontal scroll in chunks of quarter width + if (!(flags & ImGuiInputTextFlags_NoHorizontalScroll)) + { + const float scroll_increment_x = inner_size.x * 0.25f; + if (cursor_offset.x < state->ScrollX) + state->ScrollX = IM_FLOOR(ImMax(0.0f, cursor_offset.x - scroll_increment_x)); + else if (cursor_offset.x - inner_size.x >= state->ScrollX) + state->ScrollX = IM_FLOOR(cursor_offset.x - inner_size.x + scroll_increment_x); + } + else + { + state->ScrollX = 0.0f; + } + + // Vertical scroll + if (is_multiline) + { + float scroll_y = draw_window->Scroll.y; + if (cursor_offset.y - g.FontSize < scroll_y) + scroll_y = ImMax(0.0f, cursor_offset.y - g.FontSize); + else if (cursor_offset.y - inner_size.y >= scroll_y) + scroll_y = cursor_offset.y - inner_size.y; + draw_pos.y += (draw_window->Scroll.y - scroll_y); // Manipulate cursor pos immediately avoid a frame of lag + draw_window->Scroll.y = scroll_y; + } + + state->CursorFollow = false; + } + + // Draw selection + const ImVec2 draw_scroll = ImVec2(state->ScrollX, 0.0f); + if (render_selection) + { + const ImWchar* text_selected_begin = text_begin + ImMin(state->Stb.select_start, state->Stb.select_end); + const ImWchar* text_selected_end = text_begin + ImMax(state->Stb.select_start, state->Stb.select_end); + + ImU32 bg_color = GetColorU32(ImGuiCol_TextSelectedBg, render_cursor ? 1.0f : 0.6f); // FIXME: current code flow mandate that render_cursor is always true here, we are leaving the transparent one for tests. + float bg_offy_up = is_multiline ? 0.0f : -1.0f; // FIXME: those offsets should be part of the style? they don't play so well with multi-line selection. + float bg_offy_dn = is_multiline ? 0.0f : 2.0f; + ImVec2 rect_pos = draw_pos + select_start_offset - draw_scroll; + for (const ImWchar* p = text_selected_begin; p < text_selected_end; ) + { + if (rect_pos.y > clip_rect.w + g.FontSize) + break; + if (rect_pos.y < clip_rect.y) + { + //p = (const ImWchar*)wmemchr((const wchar_t*)p, '\n', text_selected_end - p); // FIXME-OPT: Could use this when wchar_t are 16-bit + //p = p ? p + 1 : text_selected_end; + while (p < text_selected_end) + if (*p++ == '\n') + break; + } + else + { + ImVec2 rect_size = InputTextCalcTextSizeW(p, text_selected_end, &p, NULL, true); + if (rect_size.x <= 0.0f) rect_size.x = IM_FLOOR(g.Font->GetCharAdvance((ImWchar)' ') * 0.50f); // So we can see selected empty lines + ImRect rect(rect_pos + ImVec2(0.0f, bg_offy_up - g.FontSize), rect_pos +ImVec2(rect_size.x, bg_offy_dn)); + rect.ClipWith(clip_rect); + if (rect.Overlaps(clip_rect)) + draw_window->DrawList->AddRectFilled(rect.Min, rect.Max, bg_color); + } + rect_pos.x = draw_pos.x - draw_scroll.x; + rect_pos.y += g.FontSize; + } + } + + // We test for 'buf_display_max_length' as a way to avoid some pathological cases (e.g. single-line 1 MB string) which would make ImDrawList crash. + if (is_multiline || (buf_display_end - buf_display) < buf_display_max_length) + { + ImU32 col = GetColorU32(is_displaying_hint ? ImGuiCol_TextDisabled : ImGuiCol_Text); + draw_window->DrawList->AddText(g.Font, g.FontSize, draw_pos - draw_scroll, col, buf_display, buf_display_end, 0.0f, is_multiline ? NULL : &clip_rect); + } + + // Draw blinking cursor + if (render_cursor) + { + state->CursorAnim += io.DeltaTime; + bool cursor_is_visible = (!g.IO.ConfigInputTextCursorBlink) || (state->CursorAnim <= 0.0f) || ImFmod(state->CursorAnim, 1.20f) <= 0.80f; + ImVec2 cursor_screen_pos = draw_pos + cursor_offset - draw_scroll; + ImRect cursor_screen_rect(cursor_screen_pos.x, cursor_screen_pos.y - g.FontSize + 0.5f, cursor_screen_pos.x + 1.0f, cursor_screen_pos.y - 1.5f); + if (cursor_is_visible && cursor_screen_rect.Overlaps(clip_rect)) + draw_window->DrawList->AddLine(cursor_screen_rect.Min, cursor_screen_rect.GetBL(), GetColorU32(ImGuiCol_Text)); + + // Notify OS of text input position for advanced IME (-1 x offset so that Windows IME can cover our cursor. Bit of an extra nicety.) + if (!is_readonly) + { + g.PlatformImePos = ImVec2(cursor_screen_pos.x - 1, cursor_screen_pos.y - g.FontSize); + g.PlatformImePosViewport = window->Viewport; + } + } + } + else + { + // Render text only (no selection, no cursor) + if (is_multiline) + text_size = ImVec2(inner_size.x, InputTextCalcTextLenAndLineCount(buf_display, &buf_display_end) * g.FontSize); // We don't need width + else if (!is_displaying_hint && g.ActiveId == id) + buf_display_end = buf_display + state->CurLenA; + else if (!is_displaying_hint) + buf_display_end = buf_display + strlen(buf_display); + + if (is_multiline || (buf_display_end - buf_display) < buf_display_max_length) + { + ImU32 col = GetColorU32(is_displaying_hint ? ImGuiCol_TextDisabled : ImGuiCol_Text); + draw_window->DrawList->AddText(g.Font, g.FontSize, draw_pos, col, buf_display, buf_display_end, 0.0f, is_multiline ? NULL : &clip_rect); + } + } + + if (is_multiline) + { + Dummy(text_size + ImVec2(0.0f, g.FontSize)); // Always add room to scroll an extra line + EndChild(); + EndGroup(); + } + + if (is_password && !is_displaying_hint) + PopFont(); + + // Log as text + if (g.LogEnabled && !(is_password && !is_displaying_hint)) + LogRenderedText(&draw_pos, buf_display, buf_display_end); + + if (label_size.x > 0) + RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label); + + if (value_changed && !(flags & ImGuiInputTextFlags_NoMarkEdited)) + MarkItemEdited(id); + + IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.ItemFlags); + if ((flags & ImGuiInputTextFlags_EnterReturnsTrue) != 0) + return enter_pressed; + else + return value_changed; +} + +//------------------------------------------------------------------------- +// [SECTION] Widgets: ColorEdit, ColorPicker, ColorButton, etc. +//------------------------------------------------------------------------- +// - ColorEdit3() +// - ColorEdit4() +// - ColorPicker3() +// - RenderColorRectWithAlphaCheckerboard() [Internal] +// - ColorPicker4() +// - ColorButton() +// - SetColorEditOptions() +// - ColorTooltip() [Internal] +// - ColorEditOptionsPopup() [Internal] +// - ColorPickerOptionsPopup() [Internal] +//------------------------------------------------------------------------- + +bool ImGui::ColorEdit3(const char* label, float col[3], ImGuiColorEditFlags flags) +{ + return ColorEdit4(label, col, flags | ImGuiColorEditFlags_NoAlpha); +} + +// Edit colors components (each component in 0.0f..1.0f range). +// See enum ImGuiColorEditFlags_ for available options. e.g. Only access 3 floats if ImGuiColorEditFlags_NoAlpha flag is set. +// With typical options: Left-click on colored square to open color picker. Right-click to open option menu. CTRL-Click over input fields to edit them and TAB to go to next item. +bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flags) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + ImGuiContext& g = *GImGui; + const ImGuiStyle& style = g.Style; + const float square_sz = GetFrameHeight(); + const float w_full = CalcItemWidth(); + const float w_button = (flags & ImGuiColorEditFlags_NoSmallPreview) ? 0.0f : (square_sz + style.ItemInnerSpacing.x); + const float w_inputs = w_full - w_button; + const char* label_display_end = FindRenderedTextEnd(label); + g.NextItemData.ClearFlags(); + + BeginGroup(); + PushID(label); + + // If we're not showing any slider there's no point in doing any HSV conversions + const ImGuiColorEditFlags flags_untouched = flags; + if (flags & ImGuiColorEditFlags_NoInputs) + flags = (flags & (~ImGuiColorEditFlags__DisplayMask)) | ImGuiColorEditFlags_DisplayRGB | ImGuiColorEditFlags_NoOptions; + + // Context menu: display and modify options (before defaults are applied) + if (!(flags & ImGuiColorEditFlags_NoOptions)) + ColorEditOptionsPopup(col, flags); + + // Read stored options + if (!(flags & ImGuiColorEditFlags__DisplayMask)) + flags |= (g.ColorEditOptions & ImGuiColorEditFlags__DisplayMask); + if (!(flags & ImGuiColorEditFlags__DataTypeMask)) + flags |= (g.ColorEditOptions & ImGuiColorEditFlags__DataTypeMask); + if (!(flags & ImGuiColorEditFlags__PickerMask)) + flags |= (g.ColorEditOptions & ImGuiColorEditFlags__PickerMask); + if (!(flags & ImGuiColorEditFlags__InputMask)) + flags |= (g.ColorEditOptions & ImGuiColorEditFlags__InputMask); + flags |= (g.ColorEditOptions & ~(ImGuiColorEditFlags__DisplayMask | ImGuiColorEditFlags__DataTypeMask | ImGuiColorEditFlags__PickerMask | ImGuiColorEditFlags__InputMask)); + IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiColorEditFlags__DisplayMask)); // Check that only 1 is selected + IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiColorEditFlags__InputMask)); // Check that only 1 is selected + + const bool alpha = (flags & ImGuiColorEditFlags_NoAlpha) == 0; + const bool hdr = (flags & ImGuiColorEditFlags_HDR) != 0; + const int components = alpha ? 4 : 3; + + // Convert to the formats we need + float f[4] = { col[0], col[1], col[2], alpha ? col[3] : 1.0f }; + if ((flags & ImGuiColorEditFlags_InputHSV) && (flags & ImGuiColorEditFlags_DisplayRGB)) + ColorConvertHSVtoRGB(f[0], f[1], f[2], f[0], f[1], f[2]); + else if ((flags & ImGuiColorEditFlags_InputRGB) && (flags & ImGuiColorEditFlags_DisplayHSV)) + { + // Hue is lost when converting from greyscale rgb (saturation=0). Restore it. + ColorConvertRGBtoHSV(f[0], f[1], f[2], f[0], f[1], f[2]); + if (memcmp(g.ColorEditLastColor, col, sizeof(float) * 3) == 0) + { + if (f[1] == 0) + f[0] = g.ColorEditLastHue; + if (f[2] == 0) + f[1] = g.ColorEditLastSat; + } + } + int i[4] = { IM_F32_TO_INT8_UNBOUND(f[0]), IM_F32_TO_INT8_UNBOUND(f[1]), IM_F32_TO_INT8_UNBOUND(f[2]), IM_F32_TO_INT8_UNBOUND(f[3]) }; + + bool value_changed = false; + bool value_changed_as_float = false; + + const ImVec2 pos = window->DC.CursorPos; + const float inputs_offset_x = (style.ColorButtonPosition == ImGuiDir_Left) ? w_button : 0.0f; + window->DC.CursorPos.x = pos.x + inputs_offset_x; + + if ((flags & (ImGuiColorEditFlags_DisplayRGB | ImGuiColorEditFlags_DisplayHSV)) != 0 && (flags & ImGuiColorEditFlags_NoInputs) == 0) + { + // RGB/HSV 0..255 Sliders + const float w_item_one = ImMax(1.0f, IM_FLOOR((w_inputs - (style.ItemInnerSpacing.x) * (components-1)) / (float)components)); + const float w_item_last = ImMax(1.0f, IM_FLOOR(w_inputs - (w_item_one + style.ItemInnerSpacing.x) * (components-1))); + + const bool hide_prefix = (w_item_one <= CalcTextSize((flags & ImGuiColorEditFlags_Float) ? "M:0.000" : "M:000").x); + static const char* ids[4] = { "##X", "##Y", "##Z", "##W" }; + static const char* fmt_table_int[3][4] = + { + { "%3d", "%3d", "%3d", "%3d" }, // Short display + { "R:%3d", "G:%3d", "B:%3d", "A:%3d" }, // Long display for RGBA + { "H:%3d", "S:%3d", "V:%3d", "A:%3d" } // Long display for HSVA + }; + static const char* fmt_table_float[3][4] = + { + { "%0.3f", "%0.3f", "%0.3f", "%0.3f" }, // Short display + { "R:%0.3f", "G:%0.3f", "B:%0.3f", "A:%0.3f" }, // Long display for RGBA + { "H:%0.3f", "S:%0.3f", "V:%0.3f", "A:%0.3f" } // Long display for HSVA + }; + const int fmt_idx = hide_prefix ? 0 : (flags & ImGuiColorEditFlags_DisplayHSV) ? 2 : 1; + + for (int n = 0; n < components; n++) + { + if (n > 0) + SameLine(0, style.ItemInnerSpacing.x); + SetNextItemWidth((n + 1 < components) ? w_item_one : w_item_last); + + // FIXME: When ImGuiColorEditFlags_HDR flag is passed HS values snap in weird ways when SV values go below 0. + if (flags & ImGuiColorEditFlags_Float) + { + value_changed |= DragFloat(ids[n], &f[n], 1.0f/255.0f, 0.0f, hdr ? 0.0f : 1.0f, fmt_table_float[fmt_idx][n]); + value_changed_as_float |= value_changed; + } + else + { + value_changed |= DragInt(ids[n], &i[n], 1.0f, 0, hdr ? 0 : 255, fmt_table_int[fmt_idx][n]); + } + if (!(flags & ImGuiColorEditFlags_NoOptions)) + OpenPopupOnItemClick("context"); + } + } + else if ((flags & ImGuiColorEditFlags_DisplayHex) != 0 && (flags & ImGuiColorEditFlags_NoInputs) == 0) + { + // RGB Hexadecimal Input + char buf[64]; + if (alpha) + ImFormatString(buf, IM_ARRAYSIZE(buf), "#%02X%02X%02X%02X", ImClamp(i[0],0,255), ImClamp(i[1],0,255), ImClamp(i[2],0,255), ImClamp(i[3],0,255)); + else + ImFormatString(buf, IM_ARRAYSIZE(buf), "#%02X%02X%02X", ImClamp(i[0],0,255), ImClamp(i[1],0,255), ImClamp(i[2],0,255)); + SetNextItemWidth(w_inputs); + if (InputText("##Text", buf, IM_ARRAYSIZE(buf), ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsUppercase)) + { + value_changed = true; + char* p = buf; + while (*p == '#' || ImCharIsBlankA(*p)) + p++; + i[0] = i[1] = i[2] = i[3] = 0; + if (alpha) + sscanf(p, "%02X%02X%02X%02X", (unsigned int*)&i[0], (unsigned int*)&i[1], (unsigned int*)&i[2], (unsigned int*)&i[3]); // Treat at unsigned (%X is unsigned) + else + sscanf(p, "%02X%02X%02X", (unsigned int*)&i[0], (unsigned int*)&i[1], (unsigned int*)&i[2]); + } + if (!(flags & ImGuiColorEditFlags_NoOptions)) + OpenPopupOnItemClick("context"); + } + + ImGuiWindow* picker_active_window = NULL; + if (!(flags & ImGuiColorEditFlags_NoSmallPreview)) + { + const float button_offset_x = ((flags & ImGuiColorEditFlags_NoInputs) || (style.ColorButtonPosition == ImGuiDir_Left)) ? 0.0f : w_inputs + style.ItemInnerSpacing.x; + window->DC.CursorPos = ImVec2(pos.x + button_offset_x, pos.y); + + const ImVec4 col_v4(col[0], col[1], col[2], alpha ? col[3] : 1.0f); + if (ColorButton("##ColorButton", col_v4, flags)) + { + if (!(flags & ImGuiColorEditFlags_NoPicker)) + { + // Store current color and open a picker + g.ColorPickerRef = col_v4; + OpenPopup("picker"); + SetNextWindowPos(window->DC.LastItemRect.GetBL() + ImVec2(-1,style.ItemSpacing.y)); + } + } + if (!(flags & ImGuiColorEditFlags_NoOptions)) + OpenPopupOnItemClick("context"); + + if (BeginPopup("picker")) + { + picker_active_window = g.CurrentWindow; + if (label != label_display_end) + { + TextEx(label, label_display_end); + Spacing(); + } + ImGuiColorEditFlags picker_flags_to_forward = ImGuiColorEditFlags__DataTypeMask | ImGuiColorEditFlags__PickerMask | ImGuiColorEditFlags__InputMask | ImGuiColorEditFlags_HDR | ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_AlphaBar; + ImGuiColorEditFlags picker_flags = (flags_untouched & picker_flags_to_forward) | ImGuiColorEditFlags__DisplayMask | ImGuiColorEditFlags_NoLabel | ImGuiColorEditFlags_AlphaPreviewHalf; + SetNextItemWidth(square_sz * 12.0f); // Use 256 + bar sizes? + value_changed |= ColorPicker4("##picker", col, picker_flags, &g.ColorPickerRef.x); + EndPopup(); + } + } + + if (label != label_display_end && !(flags & ImGuiColorEditFlags_NoLabel)) + { + const float text_offset_x = (flags & ImGuiColorEditFlags_NoInputs) ? w_button : w_full + style.ItemInnerSpacing.x; + window->DC.CursorPos = ImVec2(pos.x + text_offset_x, pos.y + style.FramePadding.y); + TextEx(label, label_display_end); + } + + // Convert back + if (value_changed && picker_active_window == NULL) + { + if (!value_changed_as_float) + for (int n = 0; n < 4; n++) + f[n] = i[n] / 255.0f; + if ((flags & ImGuiColorEditFlags_DisplayHSV) && (flags & ImGuiColorEditFlags_InputRGB)) + { + g.ColorEditLastHue = f[0]; + g.ColorEditLastSat = f[1]; + ColorConvertHSVtoRGB(f[0], f[1], f[2], f[0], f[1], f[2]); + memcpy(g.ColorEditLastColor, f, sizeof(float) * 3); + } + if ((flags & ImGuiColorEditFlags_DisplayRGB) && (flags & ImGuiColorEditFlags_InputHSV)) + ColorConvertRGBtoHSV(f[0], f[1], f[2], f[0], f[1], f[2]); + + col[0] = f[0]; + col[1] = f[1]; + col[2] = f[2]; + if (alpha) + col[3] = f[3]; + } + + PopID(); + EndGroup(); + + // Drag and Drop Target + // NB: The flag test is merely an optional micro-optimization, BeginDragDropTarget() does the same test. + if ((window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_HoveredRect) && !(flags & ImGuiColorEditFlags_NoDragDrop) && BeginDragDropTarget()) + { + bool accepted_drag_drop = false; + if (const ImGuiPayload* payload = AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_3F)) + { + memcpy((float*)col, payload->Data, sizeof(float) * 3); // Preserve alpha if any //-V512 + value_changed = accepted_drag_drop = true; + } + if (const ImGuiPayload* payload = AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F)) + { + memcpy((float*)col, payload->Data, sizeof(float) * components); + value_changed = accepted_drag_drop = true; + } + + // Drag-drop payloads are always RGB + if (accepted_drag_drop && (flags & ImGuiColorEditFlags_InputHSV)) + ColorConvertRGBtoHSV(col[0], col[1], col[2], col[0], col[1], col[2]); + EndDragDropTarget(); + } + + // When picker is being actively used, use its active id so IsItemActive() will function on ColorEdit4(). + if (picker_active_window && g.ActiveId != 0 && g.ActiveIdWindow == picker_active_window) + window->DC.LastItemId = g.ActiveId; + + if (value_changed) + MarkItemEdited(window->DC.LastItemId); + + return value_changed; +} + +bool ImGui::ColorPicker3(const char* label, float col[3], ImGuiColorEditFlags flags) +{ + float col4[4] = { col[0], col[1], col[2], 1.0f }; + if (!ColorPicker4(label, col4, flags | ImGuiColorEditFlags_NoAlpha)) + return false; + col[0] = col4[0]; col[1] = col4[1]; col[2] = col4[2]; + return true; +} + +// Helper for ColorPicker4() +static void RenderArrowsForVerticalBar(ImDrawList* draw_list, ImVec2 pos, ImVec2 half_sz, float bar_w, float alpha) +{ + ImU32 alpha8 = IM_F32_TO_INT8_SAT(alpha); + ImGui::RenderArrowPointingAt(draw_list, ImVec2(pos.x + half_sz.x + 1, pos.y), ImVec2(half_sz.x + 2, half_sz.y + 1), ImGuiDir_Right, IM_COL32(0,0,0,alpha8)); + ImGui::RenderArrowPointingAt(draw_list, ImVec2(pos.x + half_sz.x, pos.y), half_sz, ImGuiDir_Right, IM_COL32(255,255,255,alpha8)); + ImGui::RenderArrowPointingAt(draw_list, ImVec2(pos.x + bar_w - half_sz.x - 1, pos.y), ImVec2(half_sz.x + 2, half_sz.y + 1), ImGuiDir_Left, IM_COL32(0,0,0,alpha8)); + ImGui::RenderArrowPointingAt(draw_list, ImVec2(pos.x + bar_w - half_sz.x, pos.y), half_sz, ImGuiDir_Left, IM_COL32(255,255,255,alpha8)); +} + +// Note: ColorPicker4() only accesses 3 floats if ImGuiColorEditFlags_NoAlpha flag is set. +// (In C++ the 'float col[4]' notation for a function argument is equivalent to 'float* col', we only specify a size to facilitate understanding of the code.) +// FIXME: we adjust the big color square height based on item width, which may cause a flickering feedback loop (if automatic height makes a vertical scrollbar appears, affecting automatic width..) +// FIXME: this is trying to be aware of style.Alpha but not fully correct. Also, the color wheel will have overlapping glitches with (style.Alpha < 1.0) +bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags flags, const float* ref_col) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + ImDrawList* draw_list = window->DrawList; + ImGuiStyle& style = g.Style; + ImGuiIO& io = g.IO; + + const float width = CalcItemWidth(); + g.NextItemData.ClearFlags(); + + PushID(label); + BeginGroup(); + + if (!(flags & ImGuiColorEditFlags_NoSidePreview)) + flags |= ImGuiColorEditFlags_NoSmallPreview; + + // Context menu: display and store options. + if (!(flags & ImGuiColorEditFlags_NoOptions)) + ColorPickerOptionsPopup(col, flags); + + // Read stored options + if (!(flags & ImGuiColorEditFlags__PickerMask)) + flags |= ((g.ColorEditOptions & ImGuiColorEditFlags__PickerMask) ? g.ColorEditOptions : ImGuiColorEditFlags__OptionsDefault) & ImGuiColorEditFlags__PickerMask; + if (!(flags & ImGuiColorEditFlags__InputMask)) + flags |= ((g.ColorEditOptions & ImGuiColorEditFlags__InputMask) ? g.ColorEditOptions : ImGuiColorEditFlags__OptionsDefault) & ImGuiColorEditFlags__InputMask; + IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiColorEditFlags__PickerMask)); // Check that only 1 is selected + IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiColorEditFlags__InputMask)); // Check that only 1 is selected + if (!(flags & ImGuiColorEditFlags_NoOptions)) + flags |= (g.ColorEditOptions & ImGuiColorEditFlags_AlphaBar); + + // Setup + int components = (flags & ImGuiColorEditFlags_NoAlpha) ? 3 : 4; + bool alpha_bar = (flags & ImGuiColorEditFlags_AlphaBar) && !(flags & ImGuiColorEditFlags_NoAlpha); + ImVec2 picker_pos = window->DC.CursorPos; + float square_sz = GetFrameHeight(); + float bars_width = square_sz; // Arbitrary smallish width of Hue/Alpha picking bars + float sv_picker_size = ImMax(bars_width * 1, width - (alpha_bar ? 2 : 1) * (bars_width + style.ItemInnerSpacing.x)); // Saturation/Value picking box + float bar0_pos_x = picker_pos.x + sv_picker_size + style.ItemInnerSpacing.x; + float bar1_pos_x = bar0_pos_x + bars_width + style.ItemInnerSpacing.x; + float bars_triangles_half_sz = IM_FLOOR(bars_width * 0.20f); + + float backup_initial_col[4]; + memcpy(backup_initial_col, col, components * sizeof(float)); + + float wheel_thickness = sv_picker_size * 0.08f; + float wheel_r_outer = sv_picker_size * 0.50f; + float wheel_r_inner = wheel_r_outer - wheel_thickness; + ImVec2 wheel_center(picker_pos.x + (sv_picker_size + bars_width)*0.5f, picker_pos.y + sv_picker_size*0.5f); + + // Note: the triangle is displayed rotated with triangle_pa pointing to Hue, but most coordinates stays unrotated for logic. + float triangle_r = wheel_r_inner - (int)(sv_picker_size * 0.027f); + ImVec2 triangle_pa = ImVec2(triangle_r, 0.0f); // Hue point. + ImVec2 triangle_pb = ImVec2(triangle_r * -0.5f, triangle_r * -0.866025f); // Black point. + ImVec2 triangle_pc = ImVec2(triangle_r * -0.5f, triangle_r * +0.866025f); // White point. + + float H = col[0], S = col[1], V = col[2]; + float R = col[0], G = col[1], B = col[2]; + if (flags & ImGuiColorEditFlags_InputRGB) + { + // Hue is lost when converting from greyscale rgb (saturation=0). Restore it. + ColorConvertRGBtoHSV(R, G, B, H, S, V); + if (memcmp(g.ColorEditLastColor, col, sizeof(float) * 3) == 0) + { + if (S == 0) + H = g.ColorEditLastHue; + if (V == 0) + S = g.ColorEditLastSat; + } + } + else if (flags & ImGuiColorEditFlags_InputHSV) + { + ColorConvertHSVtoRGB(H, S, V, R, G, B); + } + + bool value_changed = false, value_changed_h = false, value_changed_sv = false; + + PushItemFlag(ImGuiItemFlags_NoNav, true); + if (flags & ImGuiColorEditFlags_PickerHueWheel) + { + // Hue wheel + SV triangle logic + InvisibleButton("hsv", ImVec2(sv_picker_size + style.ItemInnerSpacing.x + bars_width, sv_picker_size)); + if (IsItemActive()) + { + ImVec2 initial_off = g.IO.MouseClickedPos[0] - wheel_center; + ImVec2 current_off = g.IO.MousePos - wheel_center; + float initial_dist2 = ImLengthSqr(initial_off); + if (initial_dist2 >= (wheel_r_inner-1)*(wheel_r_inner-1) && initial_dist2 <= (wheel_r_outer+1)*(wheel_r_outer+1)) + { + // Interactive with Hue wheel + H = ImAtan2(current_off.y, current_off.x) / IM_PI*0.5f; + if (H < 0.0f) + H += 1.0f; + value_changed = value_changed_h = true; + } + float cos_hue_angle = ImCos(-H * 2.0f * IM_PI); + float sin_hue_angle = ImSin(-H * 2.0f * IM_PI); + if (ImTriangleContainsPoint(triangle_pa, triangle_pb, triangle_pc, ImRotate(initial_off, cos_hue_angle, sin_hue_angle))) + { + // Interacting with SV triangle + ImVec2 current_off_unrotated = ImRotate(current_off, cos_hue_angle, sin_hue_angle); + if (!ImTriangleContainsPoint(triangle_pa, triangle_pb, triangle_pc, current_off_unrotated)) + current_off_unrotated = ImTriangleClosestPoint(triangle_pa, triangle_pb, triangle_pc, current_off_unrotated); + float uu, vv, ww; + ImTriangleBarycentricCoords(triangle_pa, triangle_pb, triangle_pc, current_off_unrotated, uu, vv, ww); + V = ImClamp(1.0f - vv, 0.0001f, 1.0f); + S = ImClamp(uu / V, 0.0001f, 1.0f); + value_changed = value_changed_sv = true; + } + } + if (!(flags & ImGuiColorEditFlags_NoOptions)) + OpenPopupOnItemClick("context"); + } + else if (flags & ImGuiColorEditFlags_PickerHueBar) + { + // SV rectangle logic + InvisibleButton("sv", ImVec2(sv_picker_size, sv_picker_size)); + if (IsItemActive()) + { + S = ImSaturate((io.MousePos.x - picker_pos.x) / (sv_picker_size-1)); + V = 1.0f - ImSaturate((io.MousePos.y - picker_pos.y) / (sv_picker_size-1)); + value_changed = value_changed_sv = true; + } + if (!(flags & ImGuiColorEditFlags_NoOptions)) + OpenPopupOnItemClick("context"); + + // Hue bar logic + SetCursorScreenPos(ImVec2(bar0_pos_x, picker_pos.y)); + InvisibleButton("hue", ImVec2(bars_width, sv_picker_size)); + if (IsItemActive()) + { + H = ImSaturate((io.MousePos.y - picker_pos.y) / (sv_picker_size-1)); + value_changed = value_changed_h = true; + } + } + + // Alpha bar logic + if (alpha_bar) + { + SetCursorScreenPos(ImVec2(bar1_pos_x, picker_pos.y)); + InvisibleButton("alpha", ImVec2(bars_width, sv_picker_size)); + if (IsItemActive()) + { + col[3] = 1.0f - ImSaturate((io.MousePos.y - picker_pos.y) / (sv_picker_size-1)); + value_changed = true; + } + } + PopItemFlag(); // ImGuiItemFlags_NoNav + + if (!(flags & ImGuiColorEditFlags_NoSidePreview)) + { + SameLine(0, style.ItemInnerSpacing.x); + BeginGroup(); + } + + if (!(flags & ImGuiColorEditFlags_NoLabel)) + { + const char* label_display_end = FindRenderedTextEnd(label); + if (label != label_display_end) + { + if ((flags & ImGuiColorEditFlags_NoSidePreview)) + SameLine(0, style.ItemInnerSpacing.x); + TextEx(label, label_display_end); + } + } + + if (!(flags & ImGuiColorEditFlags_NoSidePreview)) + { + PushItemFlag(ImGuiItemFlags_NoNavDefaultFocus, true); + ImVec4 col_v4(col[0], col[1], col[2], (flags & ImGuiColorEditFlags_NoAlpha) ? 1.0f : col[3]); + if ((flags & ImGuiColorEditFlags_NoLabel)) + Text("Current"); + + ImGuiColorEditFlags sub_flags_to_forward = ImGuiColorEditFlags__InputMask | ImGuiColorEditFlags_HDR | ImGuiColorEditFlags_AlphaPreview | ImGuiColorEditFlags_AlphaPreviewHalf | ImGuiColorEditFlags_NoTooltip; + ColorButton("##current", col_v4, (flags & sub_flags_to_forward), ImVec2(square_sz * 3, square_sz * 2)); + if (ref_col != NULL) + { + Text("Original"); + ImVec4 ref_col_v4(ref_col[0], ref_col[1], ref_col[2], (flags & ImGuiColorEditFlags_NoAlpha) ? 1.0f : ref_col[3]); + if (ColorButton("##original", ref_col_v4, (flags & sub_flags_to_forward), ImVec2(square_sz * 3, square_sz * 2))) + { + memcpy(col, ref_col, components * sizeof(float)); + value_changed = true; + } + } + PopItemFlag(); + EndGroup(); + } + + // Convert back color to RGB + if (value_changed_h || value_changed_sv) + { + if (flags & ImGuiColorEditFlags_InputRGB) + { + ColorConvertHSVtoRGB(H >= 1.0f ? H - 10 * 1e-6f : H, S > 0.0f ? S : 10*1e-6f, V > 0.0f ? V : 1e-6f, col[0], col[1], col[2]); + g.ColorEditLastHue = H; + g.ColorEditLastSat = S; + memcpy(g.ColorEditLastColor, col, sizeof(float) * 3); + } + else if (flags & ImGuiColorEditFlags_InputHSV) + { + col[0] = H; + col[1] = S; + col[2] = V; + } + } + + // R,G,B and H,S,V slider color editor + bool value_changed_fix_hue_wrap = false; + if ((flags & ImGuiColorEditFlags_NoInputs) == 0) + { + PushItemWidth((alpha_bar ? bar1_pos_x : bar0_pos_x) + bars_width - picker_pos.x); + ImGuiColorEditFlags sub_flags_to_forward = ImGuiColorEditFlags__DataTypeMask | ImGuiColorEditFlags__InputMask | ImGuiColorEditFlags_HDR | ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_NoOptions | ImGuiColorEditFlags_NoSmallPreview | ImGuiColorEditFlags_AlphaPreview | ImGuiColorEditFlags_AlphaPreviewHalf; + ImGuiColorEditFlags sub_flags = (flags & sub_flags_to_forward) | ImGuiColorEditFlags_NoPicker; + if (flags & ImGuiColorEditFlags_DisplayRGB || (flags & ImGuiColorEditFlags__DisplayMask) == 0) + if (ColorEdit4("##rgb", col, sub_flags | ImGuiColorEditFlags_DisplayRGB)) + { + // FIXME: Hackily differentiating using the DragInt (ActiveId != 0 && !ActiveIdAllowOverlap) vs. using the InputText or DropTarget. + // For the later we don't want to run the hue-wrap canceling code. If you are well versed in HSV picker please provide your input! (See #2050) + value_changed_fix_hue_wrap = (g.ActiveId != 0 && !g.ActiveIdAllowOverlap); + value_changed = true; + } + if (flags & ImGuiColorEditFlags_DisplayHSV || (flags & ImGuiColorEditFlags__DisplayMask) == 0) + value_changed |= ColorEdit4("##hsv", col, sub_flags | ImGuiColorEditFlags_DisplayHSV); + if (flags & ImGuiColorEditFlags_DisplayHex || (flags & ImGuiColorEditFlags__DisplayMask) == 0) + value_changed |= ColorEdit4("##hex", col, sub_flags | ImGuiColorEditFlags_DisplayHex); + PopItemWidth(); + } + + // Try to cancel hue wrap (after ColorEdit4 call), if any + if (value_changed_fix_hue_wrap && (flags & ImGuiColorEditFlags_InputRGB)) + { + float new_H, new_S, new_V; + ColorConvertRGBtoHSV(col[0], col[1], col[2], new_H, new_S, new_V); + if (new_H <= 0 && H > 0) + { + if (new_V <= 0 && V != new_V) + ColorConvertHSVtoRGB(H, S, new_V <= 0 ? V * 0.5f : new_V, col[0], col[1], col[2]); + else if (new_S <= 0) + ColorConvertHSVtoRGB(H, new_S <= 0 ? S * 0.5f : new_S, new_V, col[0], col[1], col[2]); + } + } + + if (value_changed) + { + if (flags & ImGuiColorEditFlags_InputRGB) + { + R = col[0]; + G = col[1]; + B = col[2]; + ColorConvertRGBtoHSV(R, G, B, H, S, V); + if (memcmp(g.ColorEditLastColor, col, sizeof(float) * 3) == 0) // Fix local Hue as display below will use it immediately. + { + if (S == 0) + H = g.ColorEditLastHue; + if (V == 0) + S = g.ColorEditLastSat; + } + } + else if (flags & ImGuiColorEditFlags_InputHSV) + { + H = col[0]; + S = col[1]; + V = col[2]; + ColorConvertHSVtoRGB(H, S, V, R, G, B); + } + } + + const int style_alpha8 = IM_F32_TO_INT8_SAT(style.Alpha); + const ImU32 col_black = IM_COL32(0,0,0,style_alpha8); + const ImU32 col_white = IM_COL32(255,255,255,style_alpha8); + const ImU32 col_midgrey = IM_COL32(128,128,128,style_alpha8); + const ImU32 col_hues[6 + 1] = { IM_COL32(255,0,0,style_alpha8), IM_COL32(255,255,0,style_alpha8), IM_COL32(0,255,0,style_alpha8), IM_COL32(0,255,255,style_alpha8), IM_COL32(0,0,255,style_alpha8), IM_COL32(255,0,255,style_alpha8), IM_COL32(255,0,0,style_alpha8) }; + + ImVec4 hue_color_f(1, 1, 1, style.Alpha); ColorConvertHSVtoRGB(H, 1, 1, hue_color_f.x, hue_color_f.y, hue_color_f.z); + ImU32 hue_color32 = ColorConvertFloat4ToU32(hue_color_f); + ImU32 user_col32_striped_of_alpha = ColorConvertFloat4ToU32(ImVec4(R, G, B, style.Alpha)); // Important: this is still including the main rendering/style alpha!! + + ImVec2 sv_cursor_pos; + + if (flags & ImGuiColorEditFlags_PickerHueWheel) + { + // Render Hue Wheel + const float aeps = 0.5f / wheel_r_outer; // Half a pixel arc length in radians (2pi cancels out). + const int segment_per_arc = ImMax(4, (int)wheel_r_outer / 12); + for (int n = 0; n < 6; n++) + { + const float a0 = (n) /6.0f * 2.0f * IM_PI - aeps; + const float a1 = (n+1.0f)/6.0f * 2.0f * IM_PI + aeps; + const int vert_start_idx = draw_list->VtxBuffer.Size; + draw_list->PathArcTo(wheel_center, (wheel_r_inner + wheel_r_outer)*0.5f, a0, a1, segment_per_arc); + draw_list->PathStroke(col_white, false, wheel_thickness); + const int vert_end_idx = draw_list->VtxBuffer.Size; + + // Paint colors over existing vertices + ImVec2 gradient_p0(wheel_center.x + ImCos(a0) * wheel_r_inner, wheel_center.y + ImSin(a0) * wheel_r_inner); + ImVec2 gradient_p1(wheel_center.x + ImCos(a1) * wheel_r_inner, wheel_center.y + ImSin(a1) * wheel_r_inner); + ShadeVertsLinearColorGradientKeepAlpha(draw_list, vert_start_idx, vert_end_idx, gradient_p0, gradient_p1, col_hues[n], col_hues[n+1]); + } + + // Render Cursor + preview on Hue Wheel + float cos_hue_angle = ImCos(H * 2.0f * IM_PI); + float sin_hue_angle = ImSin(H * 2.0f * IM_PI); + ImVec2 hue_cursor_pos(wheel_center.x + cos_hue_angle * (wheel_r_inner+wheel_r_outer)*0.5f, wheel_center.y + sin_hue_angle * (wheel_r_inner+wheel_r_outer)*0.5f); + float hue_cursor_rad = value_changed_h ? wheel_thickness * 0.65f : wheel_thickness * 0.55f; + int hue_cursor_segments = ImClamp((int)(hue_cursor_rad / 1.4f), 9, 32); + draw_list->AddCircleFilled(hue_cursor_pos, hue_cursor_rad, hue_color32, hue_cursor_segments); + draw_list->AddCircle(hue_cursor_pos, hue_cursor_rad+1, col_midgrey, hue_cursor_segments); + draw_list->AddCircle(hue_cursor_pos, hue_cursor_rad, col_white, hue_cursor_segments); + + // Render SV triangle (rotated according to hue) + ImVec2 tra = wheel_center + ImRotate(triangle_pa, cos_hue_angle, sin_hue_angle); + ImVec2 trb = wheel_center + ImRotate(triangle_pb, cos_hue_angle, sin_hue_angle); + ImVec2 trc = wheel_center + ImRotate(triangle_pc, cos_hue_angle, sin_hue_angle); + ImVec2 uv_white = GetFontTexUvWhitePixel(); + draw_list->PrimReserve(6, 6); + draw_list->PrimVtx(tra, uv_white, hue_color32); + draw_list->PrimVtx(trb, uv_white, hue_color32); + draw_list->PrimVtx(trc, uv_white, col_white); + draw_list->PrimVtx(tra, uv_white, 0); + draw_list->PrimVtx(trb, uv_white, col_black); + draw_list->PrimVtx(trc, uv_white, 0); + draw_list->AddTriangle(tra, trb, trc, col_midgrey, 1.5f); + sv_cursor_pos = ImLerp(ImLerp(trc, tra, ImSaturate(S)), trb, ImSaturate(1 - V)); + } + else if (flags & ImGuiColorEditFlags_PickerHueBar) + { + // Render SV Square + draw_list->AddRectFilledMultiColor(picker_pos, picker_pos + ImVec2(sv_picker_size, sv_picker_size), col_white, hue_color32, hue_color32, col_white); + draw_list->AddRectFilledMultiColor(picker_pos, picker_pos + ImVec2(sv_picker_size, sv_picker_size), 0, 0, col_black, col_black); + RenderFrameBorder(picker_pos, picker_pos + ImVec2(sv_picker_size, sv_picker_size), 0.0f); + sv_cursor_pos.x = ImClamp(IM_ROUND(picker_pos.x + ImSaturate(S) * sv_picker_size), picker_pos.x + 2, picker_pos.x + sv_picker_size - 2); // Sneakily prevent the circle to stick out too much + sv_cursor_pos.y = ImClamp(IM_ROUND(picker_pos.y + ImSaturate(1 - V) * sv_picker_size), picker_pos.y + 2, picker_pos.y + sv_picker_size - 2); + + // Render Hue Bar + for (int i = 0; i < 6; ++i) + draw_list->AddRectFilledMultiColor(ImVec2(bar0_pos_x, picker_pos.y + i * (sv_picker_size / 6)), ImVec2(bar0_pos_x + bars_width, picker_pos.y + (i + 1) * (sv_picker_size / 6)), col_hues[i], col_hues[i], col_hues[i + 1], col_hues[i + 1]); + float bar0_line_y = IM_ROUND(picker_pos.y + H * sv_picker_size); + RenderFrameBorder(ImVec2(bar0_pos_x, picker_pos.y), ImVec2(bar0_pos_x + bars_width, picker_pos.y + sv_picker_size), 0.0f); + RenderArrowsForVerticalBar(draw_list, ImVec2(bar0_pos_x - 1, bar0_line_y), ImVec2(bars_triangles_half_sz + 1, bars_triangles_half_sz), bars_width + 2.0f, style.Alpha); + } + + // Render cursor/preview circle (clamp S/V within 0..1 range because floating points colors may lead HSV values to be out of range) + float sv_cursor_rad = value_changed_sv ? 10.0f : 6.0f; + draw_list->AddCircleFilled(sv_cursor_pos, sv_cursor_rad, user_col32_striped_of_alpha, 12); + draw_list->AddCircle(sv_cursor_pos, sv_cursor_rad+1, col_midgrey, 12); + draw_list->AddCircle(sv_cursor_pos, sv_cursor_rad, col_white, 12); + + // Render alpha bar + if (alpha_bar) + { + float alpha = ImSaturate(col[3]); + ImRect bar1_bb(bar1_pos_x, picker_pos.y, bar1_pos_x + bars_width, picker_pos.y + sv_picker_size); + RenderColorRectWithAlphaCheckerboard(draw_list, bar1_bb.Min, bar1_bb.Max, 0, bar1_bb.GetWidth() / 2.0f, ImVec2(0.0f, 0.0f)); + draw_list->AddRectFilledMultiColor(bar1_bb.Min, bar1_bb.Max, user_col32_striped_of_alpha, user_col32_striped_of_alpha, user_col32_striped_of_alpha & ~IM_COL32_A_MASK, user_col32_striped_of_alpha & ~IM_COL32_A_MASK); + float bar1_line_y = IM_ROUND(picker_pos.y + (1.0f - alpha) * sv_picker_size); + RenderFrameBorder(bar1_bb.Min, bar1_bb.Max, 0.0f); + RenderArrowsForVerticalBar(draw_list, ImVec2(bar1_pos_x - 1, bar1_line_y), ImVec2(bars_triangles_half_sz + 1, bars_triangles_half_sz), bars_width + 2.0f, style.Alpha); + } + + EndGroup(); + + if (value_changed && memcmp(backup_initial_col, col, components * sizeof(float)) == 0) + value_changed = false; + if (value_changed) + MarkItemEdited(window->DC.LastItemId); + + PopID(); + + return value_changed; +} + +// A little colored square. Return true when clicked. +// FIXME: May want to display/ignore the alpha component in the color display? Yet show it in the tooltip. +// 'desc_id' is not called 'label' because we don't display it next to the button, but only in the tooltip. +// Note that 'col' may be encoded in HSV if ImGuiColorEditFlags_InputHSV is set. +bool ImGui::ColorButton(const char* desc_id, const ImVec4& col, ImGuiColorEditFlags flags, ImVec2 size) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + ImGuiContext& g = *GImGui; + const ImGuiID id = window->GetID(desc_id); + float default_size = GetFrameHeight(); + if (size.x == 0.0f) + size.x = default_size; + if (size.y == 0.0f) + size.y = default_size; + const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size); + ItemSize(bb, (size.y >= default_size) ? g.Style.FramePadding.y : 0.0f); + if (!ItemAdd(bb, id)) + return false; + + bool hovered, held; + bool pressed = ButtonBehavior(bb, id, &hovered, &held); + + if (flags & ImGuiColorEditFlags_NoAlpha) + flags &= ~(ImGuiColorEditFlags_AlphaPreview | ImGuiColorEditFlags_AlphaPreviewHalf); + + ImVec4 col_rgb = col; + if (flags & ImGuiColorEditFlags_InputHSV) + ColorConvertHSVtoRGB(col_rgb.x, col_rgb.y, col_rgb.z, col_rgb.x, col_rgb.y, col_rgb.z); + + ImVec4 col_rgb_without_alpha(col_rgb.x, col_rgb.y, col_rgb.z, 1.0f); + float grid_step = ImMin(size.x, size.y) / 2.99f; + float rounding = ImMin(g.Style.FrameRounding, grid_step * 0.5f); + ImRect bb_inner = bb; + float off = 0.0f; + if ((flags & ImGuiColorEditFlags_NoBorder) == 0) + { + off = -0.75f; // The border (using Col_FrameBg) tends to look off when color is near-opaque and rounding is enabled. This offset seemed like a good middle ground to reduce those artifacts. + bb_inner.Expand(off); + } + if ((flags & ImGuiColorEditFlags_AlphaPreviewHalf) && col_rgb.w < 1.0f) + { + float mid_x = IM_ROUND((bb_inner.Min.x + bb_inner.Max.x) * 0.5f); + RenderColorRectWithAlphaCheckerboard(window->DrawList, ImVec2(bb_inner.Min.x + grid_step, bb_inner.Min.y), bb_inner.Max, GetColorU32(col_rgb), grid_step, ImVec2(-grid_step + off, off), rounding, ImDrawCornerFlags_TopRight| ImDrawCornerFlags_BotRight); + window->DrawList->AddRectFilled(bb_inner.Min, ImVec2(mid_x, bb_inner.Max.y), GetColorU32(col_rgb_without_alpha), rounding, ImDrawCornerFlags_TopLeft|ImDrawCornerFlags_BotLeft); + } + else + { + // Because GetColorU32() multiplies by the global style Alpha and we don't want to display a checkerboard if the source code had no alpha + ImVec4 col_source = (flags & ImGuiColorEditFlags_AlphaPreview) ? col_rgb : col_rgb_without_alpha; + if (col_source.w < 1.0f) + RenderColorRectWithAlphaCheckerboard(window->DrawList, bb_inner.Min, bb_inner.Max, GetColorU32(col_source), grid_step, ImVec2(off, off), rounding); + else + window->DrawList->AddRectFilled(bb_inner.Min, bb_inner.Max, GetColorU32(col_source), rounding, ImDrawCornerFlags_All); + } + RenderNavHighlight(bb, id); + if ((flags & ImGuiColorEditFlags_NoBorder) == 0) + { + if (g.Style.FrameBorderSize > 0.0f) + RenderFrameBorder(bb.Min, bb.Max, rounding); + else + window->DrawList->AddRect(bb.Min, bb.Max, GetColorU32(ImGuiCol_FrameBg), rounding); // Color button are often in need of some sort of border + } + + // Drag and Drop Source + // NB: The ActiveId test is merely an optional micro-optimization, BeginDragDropSource() does the same test. + if (g.ActiveId == id && !(flags & ImGuiColorEditFlags_NoDragDrop) && BeginDragDropSource()) + { + if (flags & ImGuiColorEditFlags_NoAlpha) + SetDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_3F, &col_rgb, sizeof(float) * 3, ImGuiCond_Once); + else + SetDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F, &col_rgb, sizeof(float) * 4, ImGuiCond_Once); + ColorButton(desc_id, col, flags); + SameLine(); + TextEx("Color"); + EndDragDropSource(); + } + + // Tooltip + if (!(flags & ImGuiColorEditFlags_NoTooltip) && hovered) + ColorTooltip(desc_id, &col.x, flags & (ImGuiColorEditFlags__InputMask | ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_AlphaPreview | ImGuiColorEditFlags_AlphaPreviewHalf)); + + return pressed; +} + +// Initialize/override default color options +void ImGui::SetColorEditOptions(ImGuiColorEditFlags flags) +{ + ImGuiContext& g = *GImGui; + if ((flags & ImGuiColorEditFlags__DisplayMask) == 0) + flags |= ImGuiColorEditFlags__OptionsDefault & ImGuiColorEditFlags__DisplayMask; + if ((flags & ImGuiColorEditFlags__DataTypeMask) == 0) + flags |= ImGuiColorEditFlags__OptionsDefault & ImGuiColorEditFlags__DataTypeMask; + if ((flags & ImGuiColorEditFlags__PickerMask) == 0) + flags |= ImGuiColorEditFlags__OptionsDefault & ImGuiColorEditFlags__PickerMask; + if ((flags & ImGuiColorEditFlags__InputMask) == 0) + flags |= ImGuiColorEditFlags__OptionsDefault & ImGuiColorEditFlags__InputMask; + IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiColorEditFlags__DisplayMask)); // Check only 1 option is selected + IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiColorEditFlags__DataTypeMask)); // Check only 1 option is selected + IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiColorEditFlags__PickerMask)); // Check only 1 option is selected + IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiColorEditFlags__InputMask)); // Check only 1 option is selected + g.ColorEditOptions = flags; +} + +// Note: only access 3 floats if ImGuiColorEditFlags_NoAlpha flag is set. +void ImGui::ColorTooltip(const char* text, const float* col, ImGuiColorEditFlags flags) +{ + ImGuiContext& g = *GImGui; + + BeginTooltipEx(0, ImGuiTooltipFlags_OverridePreviousTooltip); + const char* text_end = text ? FindRenderedTextEnd(text, NULL) : text; + if (text_end > text) + { + TextEx(text, text_end); + Separator(); + } + + ImVec2 sz(g.FontSize * 3 + g.Style.FramePadding.y * 2, g.FontSize * 3 + g.Style.FramePadding.y * 2); + ImVec4 cf(col[0], col[1], col[2], (flags & ImGuiColorEditFlags_NoAlpha) ? 1.0f : col[3]); + int cr = IM_F32_TO_INT8_SAT(col[0]), cg = IM_F32_TO_INT8_SAT(col[1]), cb = IM_F32_TO_INT8_SAT(col[2]), ca = (flags & ImGuiColorEditFlags_NoAlpha) ? 255 : IM_F32_TO_INT8_SAT(col[3]); + ColorButton("##preview", cf, (flags & (ImGuiColorEditFlags__InputMask | ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_AlphaPreview | ImGuiColorEditFlags_AlphaPreviewHalf)) | ImGuiColorEditFlags_NoTooltip, sz); + SameLine(); + if ((flags & ImGuiColorEditFlags_InputRGB) || !(flags & ImGuiColorEditFlags__InputMask)) + { + if (flags & ImGuiColorEditFlags_NoAlpha) + Text("#%02X%02X%02X\nR: %d, G: %d, B: %d\n(%.3f, %.3f, %.3f)", cr, cg, cb, cr, cg, cb, col[0], col[1], col[2]); + else + Text("#%02X%02X%02X%02X\nR:%d, G:%d, B:%d, A:%d\n(%.3f, %.3f, %.3f, %.3f)", cr, cg, cb, ca, cr, cg, cb, ca, col[0], col[1], col[2], col[3]); + } + else if (flags & ImGuiColorEditFlags_InputHSV) + { + if (flags & ImGuiColorEditFlags_NoAlpha) + Text("H: %.3f, S: %.3f, V: %.3f", col[0], col[1], col[2]); + else + Text("H: %.3f, S: %.3f, V: %.3f, A: %.3f", col[0], col[1], col[2], col[3]); + } + EndTooltip(); +} + +void ImGui::ColorEditOptionsPopup(const float* col, ImGuiColorEditFlags flags) +{ + bool allow_opt_inputs = !(flags & ImGuiColorEditFlags__DisplayMask); + bool allow_opt_datatype = !(flags & ImGuiColorEditFlags__DataTypeMask); + if ((!allow_opt_inputs && !allow_opt_datatype) || !BeginPopup("context")) + return; + ImGuiContext& g = *GImGui; + ImGuiColorEditFlags opts = g.ColorEditOptions; + if (allow_opt_inputs) + { + if (RadioButton("RGB", (opts & ImGuiColorEditFlags_DisplayRGB) != 0)) opts = (opts & ~ImGuiColorEditFlags__DisplayMask) | ImGuiColorEditFlags_DisplayRGB; + if (RadioButton("HSV", (opts & ImGuiColorEditFlags_DisplayHSV) != 0)) opts = (opts & ~ImGuiColorEditFlags__DisplayMask) | ImGuiColorEditFlags_DisplayHSV; + if (RadioButton("Hex", (opts & ImGuiColorEditFlags_DisplayHex) != 0)) opts = (opts & ~ImGuiColorEditFlags__DisplayMask) | ImGuiColorEditFlags_DisplayHex; + } + if (allow_opt_datatype) + { + if (allow_opt_inputs) Separator(); + if (RadioButton("0..255", (opts & ImGuiColorEditFlags_Uint8) != 0)) opts = (opts & ~ImGuiColorEditFlags__DataTypeMask) | ImGuiColorEditFlags_Uint8; + if (RadioButton("0.00..1.00", (opts & ImGuiColorEditFlags_Float) != 0)) opts = (opts & ~ImGuiColorEditFlags__DataTypeMask) | ImGuiColorEditFlags_Float; + } + + if (allow_opt_inputs || allow_opt_datatype) + Separator(); + if (Button("Copy as..", ImVec2(-1,0))) + OpenPopup("Copy"); + if (BeginPopup("Copy")) + { + int cr = IM_F32_TO_INT8_SAT(col[0]), cg = IM_F32_TO_INT8_SAT(col[1]), cb = IM_F32_TO_INT8_SAT(col[2]), ca = (flags & ImGuiColorEditFlags_NoAlpha) ? 255 : IM_F32_TO_INT8_SAT(col[3]); + char buf[64]; + ImFormatString(buf, IM_ARRAYSIZE(buf), "(%.3ff, %.3ff, %.3ff, %.3ff)", col[0], col[1], col[2], (flags & ImGuiColorEditFlags_NoAlpha) ? 1.0f : col[3]); + if (Selectable(buf)) + SetClipboardText(buf); + ImFormatString(buf, IM_ARRAYSIZE(buf), "(%d,%d,%d,%d)", cr, cg, cb, ca); + if (Selectable(buf)) + SetClipboardText(buf); + ImFormatString(buf, IM_ARRAYSIZE(buf), "#%02X%02X%02X", cr, cg, cb); + if (Selectable(buf)) + SetClipboardText(buf); + if (!(flags & ImGuiColorEditFlags_NoAlpha)) + { + ImFormatString(buf, IM_ARRAYSIZE(buf), "#%02X%02X%02X%02X", cr, cg, cb, ca); + if (Selectable(buf)) + SetClipboardText(buf); + } + EndPopup(); + } + + g.ColorEditOptions = opts; + EndPopup(); +} + +void ImGui::ColorPickerOptionsPopup(const float* ref_col, ImGuiColorEditFlags flags) +{ + bool allow_opt_picker = !(flags & ImGuiColorEditFlags__PickerMask); + bool allow_opt_alpha_bar = !(flags & ImGuiColorEditFlags_NoAlpha) && !(flags & ImGuiColorEditFlags_AlphaBar); + if ((!allow_opt_picker && !allow_opt_alpha_bar) || !BeginPopup("context")) + return; + ImGuiContext& g = *GImGui; + if (allow_opt_picker) + { + ImVec2 picker_size(g.FontSize * 8, ImMax(g.FontSize * 8 - (GetFrameHeight() + g.Style.ItemInnerSpacing.x), 1.0f)); // FIXME: Picker size copied from main picker function + PushItemWidth(picker_size.x); + for (int picker_type = 0; picker_type < 2; picker_type++) + { + // Draw small/thumbnail version of each picker type (over an invisible button for selection) + if (picker_type > 0) Separator(); + PushID(picker_type); + ImGuiColorEditFlags picker_flags = ImGuiColorEditFlags_NoInputs|ImGuiColorEditFlags_NoOptions|ImGuiColorEditFlags_NoLabel|ImGuiColorEditFlags_NoSidePreview|(flags & ImGuiColorEditFlags_NoAlpha); + if (picker_type == 0) picker_flags |= ImGuiColorEditFlags_PickerHueBar; + if (picker_type == 1) picker_flags |= ImGuiColorEditFlags_PickerHueWheel; + ImVec2 backup_pos = GetCursorScreenPos(); + if (Selectable("##selectable", false, 0, picker_size)) // By default, Selectable() is closing popup + g.ColorEditOptions = (g.ColorEditOptions & ~ImGuiColorEditFlags__PickerMask) | (picker_flags & ImGuiColorEditFlags__PickerMask); + SetCursorScreenPos(backup_pos); + ImVec4 dummy_ref_col; + memcpy(&dummy_ref_col, ref_col, sizeof(float) * ((picker_flags & ImGuiColorEditFlags_NoAlpha) ? 3 : 4)); + ColorPicker4("##dummypicker", &dummy_ref_col.x, picker_flags); + PopID(); + } + PopItemWidth(); + } + if (allow_opt_alpha_bar) + { + if (allow_opt_picker) Separator(); + CheckboxFlags("Alpha Bar", (unsigned int*)&g.ColorEditOptions, ImGuiColorEditFlags_AlphaBar); + } + EndPopup(); +} + +//------------------------------------------------------------------------- +// [SECTION] Widgets: TreeNode, CollapsingHeader, etc. +//------------------------------------------------------------------------- +// - TreeNode() +// - TreeNodeV() +// - TreeNodeEx() +// - TreeNodeExV() +// - TreeNodeBehavior() [Internal] +// - TreePush() +// - TreePop() +// - GetTreeNodeToLabelSpacing() +// - SetNextItemOpen() +// - CollapsingHeader() +//------------------------------------------------------------------------- + +bool ImGui::TreeNode(const char* str_id, const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + bool is_open = TreeNodeExV(str_id, 0, fmt, args); + va_end(args); + return is_open; +} + +bool ImGui::TreeNode(const void* ptr_id, const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + bool is_open = TreeNodeExV(ptr_id, 0, fmt, args); + va_end(args); + return is_open; +} + +bool ImGui::TreeNode(const char* label) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + return TreeNodeBehavior(window->GetID(label), 0, label, NULL); +} + +bool ImGui::TreeNodeV(const char* str_id, const char* fmt, va_list args) +{ + return TreeNodeExV(str_id, 0, fmt, args); +} + +bool ImGui::TreeNodeV(const void* ptr_id, const char* fmt, va_list args) +{ + return TreeNodeExV(ptr_id, 0, fmt, args); +} + +bool ImGui::TreeNodeEx(const char* label, ImGuiTreeNodeFlags flags) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + return TreeNodeBehavior(window->GetID(label), flags, label, NULL); +} + +bool ImGui::TreeNodeEx(const char* str_id, ImGuiTreeNodeFlags flags, const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + bool is_open = TreeNodeExV(str_id, flags, fmt, args); + va_end(args); + return is_open; +} + +bool ImGui::TreeNodeEx(const void* ptr_id, ImGuiTreeNodeFlags flags, const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + bool is_open = TreeNodeExV(ptr_id, flags, fmt, args); + va_end(args); + return is_open; +} + +bool ImGui::TreeNodeExV(const char* str_id, ImGuiTreeNodeFlags flags, const char* fmt, va_list args) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + ImGuiContext& g = *GImGui; + const char* label_end = g.TempBuffer + ImFormatStringV(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), fmt, args); + return TreeNodeBehavior(window->GetID(str_id), flags, g.TempBuffer, label_end); +} + +bool ImGui::TreeNodeExV(const void* ptr_id, ImGuiTreeNodeFlags flags, const char* fmt, va_list args) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + ImGuiContext& g = *GImGui; + const char* label_end = g.TempBuffer + ImFormatStringV(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), fmt, args); + return TreeNodeBehavior(window->GetID(ptr_id), flags, g.TempBuffer, label_end); +} + +bool ImGui::TreeNodeBehaviorIsOpen(ImGuiID id, ImGuiTreeNodeFlags flags) +{ + if (flags & ImGuiTreeNodeFlags_Leaf) + return true; + + // We only write to the tree storage if the user clicks (or explicitly use the SetNextItemOpen function) + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + ImGuiStorage* storage = window->DC.StateStorage; + + bool is_open; + if (g.NextItemData.Flags & ImGuiNextItemDataFlags_HasOpen) + { + if (g.NextItemData.OpenCond & ImGuiCond_Always) + { + is_open = g.NextItemData.OpenVal; + storage->SetInt(id, is_open); + } + else + { + // We treat ImGuiCond_Once and ImGuiCond_FirstUseEver the same because tree node state are not saved persistently. + const int stored_value = storage->GetInt(id, -1); + if (stored_value == -1) + { + is_open = g.NextItemData.OpenVal; + storage->SetInt(id, is_open); + } + else + { + is_open = stored_value != 0; + } + } + } + else + { + is_open = storage->GetInt(id, (flags & ImGuiTreeNodeFlags_DefaultOpen) ? 1 : 0) != 0; + } + + // When logging is enabled, we automatically expand tree nodes (but *NOT* collapsing headers.. seems like sensible behavior). + // NB- If we are above max depth we still allow manually opened nodes to be logged. + if (g.LogEnabled && !(flags & ImGuiTreeNodeFlags_NoAutoOpenOnLog) && (window->DC.TreeDepth - g.LogDepthRef) < g.LogDepthToExpand) + is_open = true; + + return is_open; +} + +bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* label, const char* label_end) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + ImGuiContext& g = *GImGui; + const ImGuiStyle& style = g.Style; + const bool display_frame = (flags & ImGuiTreeNodeFlags_Framed) != 0; + const ImVec2 padding = (display_frame || (flags & ImGuiTreeNodeFlags_FramePadding)) ? style.FramePadding : ImVec2(style.FramePadding.x, ImMin(window->DC.CurrLineTextBaseOffset, style.FramePadding.y)); + + if (!label_end) + label_end = FindRenderedTextEnd(label); + const ImVec2 label_size = CalcTextSize(label, label_end, false); + + // We vertically grow up to current line height up the typical widget height. + const float frame_height = ImMax(ImMin(window->DC.CurrLineSize.y, g.FontSize + style.FramePadding.y*2), label_size.y + padding.y*2); + ImRect frame_bb; + frame_bb.Min.x = (flags & ImGuiTreeNodeFlags_SpanFullWidth) ? window->WorkRect.Min.x : window->DC.CursorPos.x; + frame_bb.Min.y = window->DC.CursorPos.y; + frame_bb.Max.x = window->WorkRect.Max.x; + frame_bb.Max.y = window->DC.CursorPos.y + frame_height; + if (display_frame) + { + // Framed header expand a little outside the default padding, to the edge of InnerClipRect + // (FIXME: May remove this at some point and make InnerClipRect align with WindowPadding.x instead of WindowPadding.x*0.5f) + frame_bb.Min.x -= IM_FLOOR(window->WindowPadding.x * 0.5f - 1.0f); + frame_bb.Max.x += IM_FLOOR(window->WindowPadding.x * 0.5f); + } + + const float text_offset_x = g.FontSize + (display_frame ? padding.x*3 : padding.x*2); // Collapser arrow width + Spacing + const float text_offset_y = ImMax(padding.y, window->DC.CurrLineTextBaseOffset); // Latch before ItemSize changes it + const float text_width = g.FontSize + (label_size.x > 0.0f ? label_size.x + padding.x*2 : 0.0f); // Include collapser + ImVec2 text_pos(window->DC.CursorPos.x + text_offset_x, window->DC.CursorPos.y + text_offset_y); + ItemSize(ImVec2(text_width, frame_height), padding.y); + + // For regular tree nodes, we arbitrary allow to click past 2 worth of ItemSpacing + ImRect interact_bb = frame_bb; + if (!display_frame && (flags & (ImGuiTreeNodeFlags_SpanAvailWidth | ImGuiTreeNodeFlags_SpanFullWidth)) == 0) + interact_bb.Max.x = frame_bb.Min.x + text_width + style.ItemSpacing.x * 2.0f; + + // Store a flag for the current depth to tell if we will allow closing this node when navigating one of its child. + // For this purpose we essentially compare if g.NavIdIsAlive went from 0 to 1 between TreeNode() and TreePop(). + // This is currently only support 32 level deep and we are fine with (1 << Depth) overflowing into a zero. + const bool is_leaf = (flags & ImGuiTreeNodeFlags_Leaf) != 0; + bool is_open = TreeNodeBehaviorIsOpen(id, flags); + if (is_open && !g.NavIdIsAlive && (flags & ImGuiTreeNodeFlags_NavLeftJumpsBackHere) && !(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen)) + window->DC.TreeJumpToParentOnPopMask |= (1 << window->DC.TreeDepth); + + bool item_add = ItemAdd(interact_bb, id); + window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_HasDisplayRect; + window->DC.LastItemDisplayRect = frame_bb; + + if (!item_add) + { + if (is_open && !(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen)) + TreePushOverrideID(id); + IMGUI_TEST_ENGINE_ITEM_INFO(window->DC.LastItemId, label, window->DC.ItemFlags | (is_leaf ? 0 : ImGuiItemStatusFlags_Openable) | (is_open ? ImGuiItemStatusFlags_Opened : 0)); + return is_open; + } + + ImGuiButtonFlags button_flags = ImGuiTreeNodeFlags_None; + if (flags & ImGuiTreeNodeFlags_AllowItemOverlap) + button_flags |= ImGuiButtonFlags_AllowItemOverlap; + if (!is_leaf) + button_flags |= ImGuiButtonFlags_PressedOnDragDropHold; + + // We allow clicking on the arrow section with keyboard modifiers held, in order to easily + // allow browsing a tree while preserving selection with code implementing multi-selection patterns. + // When clicking on the rest of the tree node we always disallow keyboard modifiers. + const float arrow_hit_x1 = (text_pos.x - text_offset_x) - style.TouchExtraPadding.x; + const float arrow_hit_x2 = (text_pos.x - text_offset_x) + (g.FontSize + padding.x * 2.0f) + style.TouchExtraPadding.x; + const bool is_mouse_x_over_arrow = (g.IO.MousePos.x >= arrow_hit_x1 && g.IO.MousePos.x < arrow_hit_x2); + if (window != g.HoveredWindow || !is_mouse_x_over_arrow) + button_flags |= ImGuiButtonFlags_NoKeyModifiers; + + // Open behaviors can be altered with the _OpenOnArrow and _OnOnDoubleClick flags. + // Some alteration have subtle effects (e.g. toggle on MouseUp vs MouseDown events) due to requirements for multi-selection and drag and drop support. + // - Single-click on label = Toggle on MouseUp (default) + // - Single-click on arrow = Toggle on MouseUp (when _OpenOnArrow=0) + // - Single-click on arrow = Toggle on MouseDown (when _OpenOnArrow=1) + // - Double-click on label = Toggle on MouseDoubleClick (when _OpenOnDoubleClick=1) + // - Double-click on arrow = Toggle on MouseDoubleClick (when _OpenOnDoubleClick=1 and _OpenOnArrow=0) + // This makes _OpenOnArrow have a subtle effect on _OpenOnDoubleClick: arrow click reacts on Down rather than Up. + // It is rather standard that arrow click react on Down rather than Up and we'd be tempted to make it the default + // (by removing the _OpenOnArrow test below), however this would have a perhaps surprising effect on CollapsingHeader()? + // So right now we are making this optional. May evolve later. + // We set ImGuiButtonFlags_PressedOnClickRelease on OpenOnDoubleClick because we want the item to be active on the initial MouseDown in order for drag and drop to work. + if (is_mouse_x_over_arrow && (flags & ImGuiTreeNodeFlags_OpenOnArrow)) + button_flags |= ImGuiButtonFlags_PressedOnClick; + else if (flags & ImGuiTreeNodeFlags_OpenOnDoubleClick) + button_flags |= ImGuiButtonFlags_PressedOnClickRelease | ImGuiButtonFlags_PressedOnDoubleClick; + else + button_flags |= ImGuiButtonFlags_PressedOnClickRelease; + + bool selected = (flags & ImGuiTreeNodeFlags_Selected) != 0; + const bool was_selected = selected; + + bool hovered, held; + bool pressed = ButtonBehavior(interact_bb, id, &hovered, &held, button_flags); + bool toggled = false; + if (!is_leaf) + { + if (pressed && g.DragDropHoldJustPressedId != id) + { + if ((flags & (ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick)) == 0 || (g.NavActivateId == id)) + toggled = true; + if (flags & ImGuiTreeNodeFlags_OpenOnArrow) + toggled |= is_mouse_x_over_arrow && !g.NavDisableMouseHover; // Lightweight equivalent of IsMouseHoveringRect() since ButtonBehavior() already did the job + if ((flags & ImGuiTreeNodeFlags_OpenOnDoubleClick) && g.IO.MouseDoubleClicked[0]) + toggled = true; + } + else if (pressed && g.DragDropHoldJustPressedId == id) + { + IM_ASSERT(button_flags & ImGuiButtonFlags_PressedOnDragDropHold); + if (!is_open) // When using Drag and Drop "hold to open" we keep the node highlighted after opening, but never close it again. + toggled = true; + } + + if (g.NavId == id && g.NavMoveRequest && g.NavMoveDir == ImGuiDir_Left && is_open) + { + toggled = true; + NavMoveRequestCancel(); + } + if (g.NavId == id && g.NavMoveRequest && g.NavMoveDir == ImGuiDir_Right && !is_open) // If there's something upcoming on the line we may want to give it the priority? + { + toggled = true; + NavMoveRequestCancel(); + } + + if (toggled) + { + is_open = !is_open; + window->DC.StateStorage->SetInt(id, is_open); + window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_ToggledOpen; + } + } + if (flags & ImGuiTreeNodeFlags_AllowItemOverlap) + SetItemAllowOverlap(); + + // In this branch, TreeNodeBehavior() cannot toggle the selection so this will never trigger. + if (selected != was_selected) //-V547 + window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_ToggledSelection; + + // Render + const ImU32 text_col = GetColorU32(ImGuiCol_Text); + ImGuiNavHighlightFlags nav_highlight_flags = ImGuiNavHighlightFlags_TypeThin; + if (display_frame) + { + // Framed type + const ImU32 bg_col = GetColorU32((held && hovered) ? ImGuiCol_HeaderActive : hovered ? ImGuiCol_HeaderHovered : ImGuiCol_Header); + RenderFrame(frame_bb.Min, frame_bb.Max, bg_col, true, style.FrameRounding); + RenderNavHighlight(frame_bb, id, nav_highlight_flags); + if (flags & ImGuiTreeNodeFlags_Bullet) + RenderBullet(window->DrawList, ImVec2(text_pos.x - text_offset_x * 0.60f, text_pos.y + g.FontSize * 0.5f), text_col); + else if (!is_leaf) + RenderArrow(window->DrawList, ImVec2(text_pos.x - text_offset_x + padding.x, text_pos.y), text_col, is_open ? ImGuiDir_Down : ImGuiDir_Right, 1.0f); + else // Leaf without bullet, left-adjusted text + text_pos.x -= text_offset_x; + if (flags & ImGuiTreeNodeFlags_ClipLabelForTrailingButton) + frame_bb.Max.x -= g.FontSize + style.FramePadding.x; + if (g.LogEnabled) + { + // NB: '##' is normally used to hide text (as a library-wide feature), so we need to specify the text range to make sure the ## aren't stripped out here. + const char log_prefix[] = "\n##"; + const char log_suffix[] = "##"; + LogRenderedText(&text_pos, log_prefix, log_prefix+3); + RenderTextClipped(text_pos, frame_bb.Max, label, label_end, &label_size); + LogRenderedText(&text_pos, log_suffix, log_suffix+2); + } + else + { + RenderTextClipped(text_pos, frame_bb.Max, label, label_end, &label_size); + } + } + else + { + // Unframed typed for tree nodes + if (hovered || selected) + { + const ImU32 bg_col = GetColorU32((held && hovered) ? ImGuiCol_HeaderActive : hovered ? ImGuiCol_HeaderHovered : ImGuiCol_Header); + RenderFrame(frame_bb.Min, frame_bb.Max, bg_col, false); + RenderNavHighlight(frame_bb, id, nav_highlight_flags); + } + if (flags & ImGuiTreeNodeFlags_Bullet) + RenderBullet(window->DrawList, ImVec2(text_pos.x - text_offset_x * 0.5f, text_pos.y + g.FontSize * 0.5f), text_col); + else if (!is_leaf) + RenderArrow(window->DrawList, ImVec2(text_pos.x - text_offset_x + padding.x, text_pos.y + g.FontSize * 0.15f), text_col, is_open ? ImGuiDir_Down : ImGuiDir_Right, 0.70f); + if (g.LogEnabled) + LogRenderedText(&text_pos, ">"); + RenderText(text_pos, label, label_end, false); + } + + if (is_open && !(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen)) + TreePushOverrideID(id); + IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.ItemFlags | (is_leaf ? 0 : ImGuiItemStatusFlags_Openable) | (is_open ? ImGuiItemStatusFlags_Opened : 0)); + return is_open; +} + +void ImGui::TreePush(const char* str_id) +{ + ImGuiWindow* window = GetCurrentWindow(); + Indent(); + window->DC.TreeDepth++; + PushID(str_id ? str_id : "#TreePush"); +} + +void ImGui::TreePush(const void* ptr_id) +{ + ImGuiWindow* window = GetCurrentWindow(); + Indent(); + window->DC.TreeDepth++; + PushID(ptr_id ? ptr_id : (const void*)"#TreePush"); +} + +void ImGui::TreePushOverrideID(ImGuiID id) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + Indent(); + window->DC.TreeDepth++; + window->IDStack.push_back(id); +} + +void ImGui::TreePop() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + Unindent(); + + window->DC.TreeDepth--; + ImU32 tree_depth_mask = (1 << window->DC.TreeDepth); + + // Handle Left arrow to move to parent tree node (when ImGuiTreeNodeFlags_NavLeftJumpsBackHere is enabled) + if (g.NavMoveDir == ImGuiDir_Left && g.NavWindow == window && NavMoveRequestButNoResultYet()) + if (g.NavIdIsAlive && (window->DC.TreeJumpToParentOnPopMask & tree_depth_mask)) + { + SetNavID(window->IDStack.back(), g.NavLayer, 0); + NavMoveRequestCancel(); + } + window->DC.TreeJumpToParentOnPopMask &= tree_depth_mask - 1; + + IM_ASSERT(window->IDStack.Size > 1); // There should always be 1 element in the IDStack (pushed during window creation). If this triggers you called TreePop/PopID too much. + PopID(); +} + +// Horizontal distance preceding label when using TreeNode() or Bullet() +float ImGui::GetTreeNodeToLabelSpacing() +{ + ImGuiContext& g = *GImGui; + return g.FontSize + (g.Style.FramePadding.x * 2.0f); +} + +// Set next TreeNode/CollapsingHeader open state. +void ImGui::SetNextItemOpen(bool is_open, ImGuiCond cond) +{ + ImGuiContext& g = *GImGui; + if (g.CurrentWindow->SkipItems) + return; + g.NextItemData.Flags |= ImGuiNextItemDataFlags_HasOpen; + g.NextItemData.OpenVal = is_open; + g.NextItemData.OpenCond = cond ? cond : ImGuiCond_Always; +} + +// CollapsingHeader returns true when opened but do not indent nor push into the ID stack (because of the ImGuiTreeNodeFlags_NoTreePushOnOpen flag). +// This is basically the same as calling TreeNodeEx(label, ImGuiTreeNodeFlags_CollapsingHeader). You can remove the _NoTreePushOnOpen flag if you want behavior closer to normal TreeNode(). +bool ImGui::CollapsingHeader(const char* label, ImGuiTreeNodeFlags flags) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + return TreeNodeBehavior(window->GetID(label), flags | ImGuiTreeNodeFlags_CollapsingHeader, label); +} + +bool ImGui::CollapsingHeader(const char* label, bool* p_open, ImGuiTreeNodeFlags flags) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + if (p_open && !*p_open) + return false; + + ImGuiID id = window->GetID(label); + flags |= ImGuiTreeNodeFlags_CollapsingHeader; + if (p_open) + flags |= ImGuiTreeNodeFlags_AllowItemOverlap | ImGuiTreeNodeFlags_ClipLabelForTrailingButton; + bool is_open = TreeNodeBehavior(id, flags, label); + if (p_open) + { + // Create a small overlapping close button + // FIXME: We can evolve this into user accessible helpers to add extra buttons on title bars, headers, etc. + // FIXME: CloseButton can overlap into text, need find a way to clip the text somehow. + ImGuiContext& g = *GImGui; + ImGuiItemHoveredDataBackup last_item_backup; + float button_size = g.FontSize; + float button_x = ImMax(window->DC.LastItemRect.Min.x, window->DC.LastItemRect.Max.x - g.Style.FramePadding.x * 2.0f - button_size); + float button_y = window->DC.LastItemRect.Min.y; + if (CloseButton(window->GetID((void*)((intptr_t)id + 1)), ImVec2(button_x, button_y))) + *p_open = false; + last_item_backup.Restore(); + } + + return is_open; +} + +//------------------------------------------------------------------------- +// [SECTION] Widgets: Selectable +//------------------------------------------------------------------------- +// - Selectable() +//------------------------------------------------------------------------- + +// Tip: pass a non-visible label (e.g. "##dummy") then you can use the space to draw other text or image. +// But you need to make sure the ID is unique, e.g. enclose calls in PushID/PopID or use ##unique_id. +// With this scheme, ImGuiSelectableFlags_SpanAllColumns and ImGuiSelectableFlags_AllowItemOverlap are also frequently used flags. +// FIXME: Selectable() with (size.x == 0.0f) and (SelectableTextAlign.x > 0.0f) followed by SameLine() is currently not supported. +bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags flags, const ImVec2& size_arg) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + ImGuiContext& g = *GImGui; + const ImGuiStyle& style = g.Style; + + if ((flags & ImGuiSelectableFlags_SpanAllColumns) && window->DC.CurrentColumns) // FIXME-OPT: Avoid if vertically clipped. + PushColumnsBackground(); + + // Submit label or explicit size to ItemSize(), whereas ItemAdd() will submit a larger/spanning rectangle. + ImGuiID id = window->GetID(label); + ImVec2 label_size = CalcTextSize(label, NULL, true); + ImVec2 size(size_arg.x != 0.0f ? size_arg.x : label_size.x, size_arg.y != 0.0f ? size_arg.y : label_size.y); + ImVec2 pos = window->DC.CursorPos; + pos.y += window->DC.CurrLineTextBaseOffset; + ItemSize(size, 0.0f); + + // Fill horizontal space + const float min_x = (flags & ImGuiSelectableFlags_SpanAllColumns) ? window->ContentRegionRect.Min.x : pos.x; + const float max_x = (flags & ImGuiSelectableFlags_SpanAllColumns) ? window->ContentRegionRect.Max.x : GetContentRegionMaxAbs().x; + if (size_arg.x == 0.0f || (flags & ImGuiSelectableFlags_SpanAvailWidth)) + size.x = ImMax(label_size.x, max_x - min_x); + + // Text stays at the submission position, but bounding box may be extended on both sides + const ImVec2 text_min = pos; + const ImVec2 text_max(min_x + size.x, pos.y + size.y); + + // Selectables are meant to be tightly packed together with no click-gap, so we extend their box to cover spacing between selectable. + ImRect bb_enlarged(min_x, pos.y, text_max.x, text_max.y); + const float spacing_x = style.ItemSpacing.x; + const float spacing_y = style.ItemSpacing.y; + const float spacing_L = IM_FLOOR(spacing_x * 0.50f); + const float spacing_U = IM_FLOOR(spacing_y * 0.50f); + bb_enlarged.Min.x -= spacing_L; + bb_enlarged.Min.y -= spacing_U; + bb_enlarged.Max.x += (spacing_x - spacing_L); + bb_enlarged.Max.y += (spacing_y - spacing_U); + //if (g.IO.KeyCtrl) { GetForegroundDrawList()->AddRect(bb_align.Min, bb_align.Max, IM_COL32(255, 0, 0, 255)); } + //if (g.IO.KeyCtrl) { GetForegroundDrawList()->AddRect(bb_enlarged.Min, bb_enlarged.Max, IM_COL32(0, 255, 0, 255)); } + + bool item_add; + if (flags & ImGuiSelectableFlags_Disabled) + { + ImGuiItemFlags backup_item_flags = window->DC.ItemFlags; + window->DC.ItemFlags |= ImGuiItemFlags_Disabled | ImGuiItemFlags_NoNavDefaultFocus; + item_add = ItemAdd(bb_enlarged, id); + window->DC.ItemFlags = backup_item_flags; + } + else + { + item_add = ItemAdd(bb_enlarged, id); + } + if (!item_add) + { + if ((flags & ImGuiSelectableFlags_SpanAllColumns) && window->DC.CurrentColumns) + PopColumnsBackground(); + return false; + } + + // We use NoHoldingActiveID on menus so user can click and _hold_ on a menu then drag to browse child entries + ImGuiButtonFlags button_flags = 0; + if (flags & ImGuiSelectableFlags_NoHoldingActiveID) { button_flags |= ImGuiButtonFlags_NoHoldingActiveId; } + if (flags & ImGuiSelectableFlags_SelectOnClick) { button_flags |= ImGuiButtonFlags_PressedOnClick; } + if (flags & ImGuiSelectableFlags_SelectOnRelease) { button_flags |= ImGuiButtonFlags_PressedOnRelease; } + if (flags & ImGuiSelectableFlags_Disabled) { button_flags |= ImGuiButtonFlags_Disabled; } + if (flags & ImGuiSelectableFlags_AllowDoubleClick) { button_flags |= ImGuiButtonFlags_PressedOnClickRelease | ImGuiButtonFlags_PressedOnDoubleClick; } + if (flags & ImGuiSelectableFlags_AllowItemOverlap) { button_flags |= ImGuiButtonFlags_AllowItemOverlap; } + + if (flags & ImGuiSelectableFlags_Disabled) + selected = false; + + const bool was_selected = selected; + bool hovered, held; + bool pressed = ButtonBehavior(bb_enlarged, id, &hovered, &held, button_flags); + + // Update NavId when clicking or when Hovering (this doesn't happen on most widgets), so navigation can be resumed with gamepad/keyboard + if (pressed || (hovered && (flags & ImGuiSelectableFlags_SetNavIdOnHover))) + { + if (!g.NavDisableMouseHover && g.NavWindow == window && g.NavLayer == window->DC.NavLayerCurrent) + { + g.NavDisableHighlight = true; + SetNavID(id, window->DC.NavLayerCurrent, window->DC.NavFocusScopeIdCurrent); + } + } + if (pressed) + MarkItemEdited(id); + + if (flags & ImGuiSelectableFlags_AllowItemOverlap) + SetItemAllowOverlap(); + + // In this branch, Selectable() cannot toggle the selection so this will never trigger. + if (selected != was_selected) //-V547 + window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_ToggledSelection; + + // Render + if (held && (flags & ImGuiSelectableFlags_DrawHoveredWhenHeld)) + hovered = true; + if (hovered || selected) + { + const ImU32 col = GetColorU32((held && hovered) ? ImGuiCol_HeaderActive : hovered ? ImGuiCol_HeaderHovered : ImGuiCol_Header); + RenderFrame(bb_enlarged.Min, bb_enlarged.Max, col, false, 0.0f); + RenderNavHighlight(bb_enlarged, id, ImGuiNavHighlightFlags_TypeThin | ImGuiNavHighlightFlags_NoRounding); + } + + if ((flags & ImGuiSelectableFlags_SpanAllColumns) && window->DC.CurrentColumns) + PopColumnsBackground(); + + if (flags & ImGuiSelectableFlags_Disabled) PushStyleColor(ImGuiCol_Text, style.Colors[ImGuiCol_TextDisabled]); + RenderTextClipped(text_min, text_max, label, NULL, &label_size, style.SelectableTextAlign, &bb_enlarged); + if (flags & ImGuiSelectableFlags_Disabled) PopStyleColor(); + + // Automatically close popups + if (pressed && (window->Flags & ImGuiWindowFlags_Popup) && !(flags & ImGuiSelectableFlags_DontClosePopups) && !(window->DC.ItemFlags & ImGuiItemFlags_SelectableDontClosePopup)) + CloseCurrentPopup(); + + IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.ItemFlags); + return pressed; +} + +bool ImGui::Selectable(const char* label, bool* p_selected, ImGuiSelectableFlags flags, const ImVec2& size_arg) +{ + if (Selectable(label, *p_selected, flags, size_arg)) + { + *p_selected = !*p_selected; + return true; + } + return false; +} + +//------------------------------------------------------------------------- +// [SECTION] Widgets: ListBox +//------------------------------------------------------------------------- +// - ListBox() +// - ListBoxHeader() +// - ListBoxFooter() +//------------------------------------------------------------------------- +// FIXME: This is an old API. We should redesign some of it, rename ListBoxHeader->BeginListBox, ListBoxFooter->EndListBox +// and promote using them over existing ListBox() functions, similarly to change with combo boxes. +//------------------------------------------------------------------------- + +// FIXME: In principle this function should be called BeginListBox(). We should rename it after re-evaluating if we want to keep the same signature. +// Helper to calculate the size of a listbox and display a label on the right. +// Tip: To have a list filling the entire window width, PushItemWidth(-1) and pass an non-visible label e.g. "##empty" +bool ImGui::ListBoxHeader(const char* label, const ImVec2& size_arg) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + const ImGuiStyle& style = g.Style; + const ImGuiID id = GetID(label); + const ImVec2 label_size = CalcTextSize(label, NULL, true); + + // Size default to hold ~7 items. Fractional number of items helps seeing that we can scroll down/up without looking at scrollbar. + ImVec2 size = CalcItemSize(size_arg, CalcItemWidth(), GetTextLineHeightWithSpacing() * 7.4f + style.ItemSpacing.y); + ImVec2 frame_size = ImVec2(size.x, ImMax(size.y, label_size.y)); + ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + frame_size); + ImRect bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f)); + window->DC.LastItemRect = bb; // Forward storage for ListBoxFooter.. dodgy. + g.NextItemData.ClearFlags(); + + if (!IsRectVisible(bb.Min, bb.Max)) + { + ItemSize(bb.GetSize(), style.FramePadding.y); + ItemAdd(bb, 0, &frame_bb); + return false; + } + + BeginGroup(); + if (label_size.x > 0) + RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label); + + BeginChildFrame(id, frame_bb.GetSize()); + return true; +} + +// FIXME: In principle this function should be called EndListBox(). We should rename it after re-evaluating if we want to keep the same signature. +bool ImGui::ListBoxHeader(const char* label, int items_count, int height_in_items) +{ + // Size default to hold ~7.25 items. + // We add +25% worth of item height to allow the user to see at a glance if there are more items up/down, without looking at the scrollbar. + // We don't add this extra bit if items_count <= height_in_items. It is slightly dodgy, because it means a dynamic list of items will make the widget resize occasionally when it crosses that size. + // I am expecting that someone will come and complain about this behavior in a remote future, then we can advise on a better solution. + if (height_in_items < 0) + height_in_items = ImMin(items_count, 7); + const ImGuiStyle& style = GetStyle(); + float height_in_items_f = (height_in_items < items_count) ? (height_in_items + 0.25f) : (height_in_items + 0.00f); + + // We include ItemSpacing.y so that a list sized for the exact number of items doesn't make a scrollbar appears. We could also enforce that by passing a flag to BeginChild(). + ImVec2 size; + size.x = 0.0f; + size.y = ImFloor(GetTextLineHeightWithSpacing() * height_in_items_f + style.FramePadding.y * 2.0f); + return ListBoxHeader(label, size); +} + +// FIXME: In principle this function should be called EndListBox(). We should rename it after re-evaluating if we want to keep the same signature. +void ImGui::ListBoxFooter() +{ + ImGuiWindow* parent_window = GetCurrentWindow()->ParentWindow; + const ImRect bb = parent_window->DC.LastItemRect; + const ImGuiStyle& style = GetStyle(); + + EndChildFrame(); + + // Redeclare item size so that it includes the label (we have stored the full size in LastItemRect) + // We call SameLine() to restore DC.CurrentLine* data + SameLine(); + parent_window->DC.CursorPos = bb.Min; + ItemSize(bb, style.FramePadding.y); + EndGroup(); +} + +bool ImGui::ListBox(const char* label, int* current_item, const char* const items[], int items_count, int height_items) +{ + const bool value_changed = ListBox(label, current_item, Items_ArrayGetter, (void*)items, items_count, height_items); + return value_changed; +} + +bool ImGui::ListBox(const char* label, int* current_item, bool (*items_getter)(void*, int, const char**), void* data, int items_count, int height_in_items) +{ + if (!ListBoxHeader(label, items_count, height_in_items)) + return false; + + // Assume all items have even height (= 1 line of text). If you need items of different or variable sizes you can create a custom version of ListBox() in your code without using the clipper. + ImGuiContext& g = *GImGui; + bool value_changed = false; + ImGuiListClipper clipper(items_count, GetTextLineHeightWithSpacing()); // We know exactly our line height here so we pass it as a minor optimization, but generally you don't need to. + while (clipper.Step()) + for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) + { + const bool item_selected = (i == *current_item); + const char* item_text; + if (!items_getter(data, i, &item_text)) + item_text = "*Unknown item*"; + + PushID(i); + if (Selectable(item_text, item_selected)) + { + *current_item = i; + value_changed = true; + } + if (item_selected) + SetItemDefaultFocus(); + PopID(); + } + ListBoxFooter(); + if (value_changed) + MarkItemEdited(g.CurrentWindow->DC.LastItemId); + + return value_changed; +} + +//------------------------------------------------------------------------- +// [SECTION] Widgets: PlotLines, PlotHistogram +//------------------------------------------------------------------------- +// - PlotEx() [Internal] +// - PlotLines() +// - PlotHistogram() +//------------------------------------------------------------------------- + +int ImGui::PlotEx(ImGuiPlotType plot_type, const char* label, float (*values_getter)(void* data, int idx), void* data, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, ImVec2 frame_size) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return -1; + + const ImGuiStyle& style = g.Style; + const ImGuiID id = window->GetID(label); + + const ImVec2 label_size = CalcTextSize(label, NULL, true); + if (frame_size.x == 0.0f) + frame_size.x = CalcItemWidth(); + if (frame_size.y == 0.0f) + frame_size.y = label_size.y + (style.FramePadding.y * 2); + + const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + frame_size); + const ImRect inner_bb(frame_bb.Min + style.FramePadding, frame_bb.Max - style.FramePadding); + const ImRect total_bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0)); + ItemSize(total_bb, style.FramePadding.y); + if (!ItemAdd(total_bb, 0, &frame_bb)) + return -1; + const bool hovered = ItemHoverable(frame_bb, id); + + // Determine scale from values if not specified + if (scale_min == FLT_MAX || scale_max == FLT_MAX) + { + float v_min = FLT_MAX; + float v_max = -FLT_MAX; + for (int i = 0; i < values_count; i++) + { + const float v = values_getter(data, i); + if (v != v) // Ignore NaN values + continue; + v_min = ImMin(v_min, v); + v_max = ImMax(v_max, v); + } + if (scale_min == FLT_MAX) + scale_min = v_min; + if (scale_max == FLT_MAX) + scale_max = v_max; + } + + RenderFrame(frame_bb.Min, frame_bb.Max, GetColorU32(ImGuiCol_FrameBg), true, style.FrameRounding); + + const int values_count_min = (plot_type == ImGuiPlotType_Lines) ? 2 : 1; + int idx_hovered = -1; + if (values_count >= values_count_min) + { + int res_w = ImMin((int)frame_size.x, values_count) + ((plot_type == ImGuiPlotType_Lines) ? -1 : 0); + int item_count = values_count + ((plot_type == ImGuiPlotType_Lines) ? -1 : 0); + + // Tooltip on hover + if (hovered && inner_bb.Contains(g.IO.MousePos)) + { + const float t = ImClamp((g.IO.MousePos.x - inner_bb.Min.x) / (inner_bb.Max.x - inner_bb.Min.x), 0.0f, 0.9999f); + const int v_idx = (int)(t * item_count); + IM_ASSERT(v_idx >= 0 && v_idx < values_count); + + const float v0 = values_getter(data, (v_idx + values_offset) % values_count); + const float v1 = values_getter(data, (v_idx + 1 + values_offset) % values_count); + if (plot_type == ImGuiPlotType_Lines) + SetTooltip("%d: %8.4g\n%d: %8.4g", v_idx, v0, v_idx+1, v1); + else if (plot_type == ImGuiPlotType_Histogram) + SetTooltip("%d: %8.4g", v_idx, v0); + idx_hovered = v_idx; + } + + const float t_step = 1.0f / (float)res_w; + const float inv_scale = (scale_min == scale_max) ? 0.0f : (1.0f / (scale_max - scale_min)); + + float v0 = values_getter(data, (0 + values_offset) % values_count); + float t0 = 0.0f; + ImVec2 tp0 = ImVec2( t0, 1.0f - ImSaturate((v0 - scale_min) * inv_scale) ); // Point in the normalized space of our target rectangle + float histogram_zero_line_t = (scale_min * scale_max < 0.0f) ? (-scale_min * inv_scale) : (scale_min < 0.0f ? 0.0f : 1.0f); // Where does the zero line stands + + const ImU32 col_base = GetColorU32((plot_type == ImGuiPlotType_Lines) ? ImGuiCol_PlotLines : ImGuiCol_PlotHistogram); + const ImU32 col_hovered = GetColorU32((plot_type == ImGuiPlotType_Lines) ? ImGuiCol_PlotLinesHovered : ImGuiCol_PlotHistogramHovered); + + for (int n = 0; n < res_w; n++) + { + const float t1 = t0 + t_step; + const int v1_idx = (int)(t0 * item_count + 0.5f); + IM_ASSERT(v1_idx >= 0 && v1_idx < values_count); + const float v1 = values_getter(data, (v1_idx + values_offset + 1) % values_count); + const ImVec2 tp1 = ImVec2( t1, 1.0f - ImSaturate((v1 - scale_min) * inv_scale) ); + + // NB: Draw calls are merged together by the DrawList system. Still, we should render our batch are lower level to save a bit of CPU. + ImVec2 pos0 = ImLerp(inner_bb.Min, inner_bb.Max, tp0); + ImVec2 pos1 = ImLerp(inner_bb.Min, inner_bb.Max, (plot_type == ImGuiPlotType_Lines) ? tp1 : ImVec2(tp1.x, histogram_zero_line_t)); + if (plot_type == ImGuiPlotType_Lines) + { + window->DrawList->AddLine(pos0, pos1, idx_hovered == v1_idx ? col_hovered : col_base); + } + else if (plot_type == ImGuiPlotType_Histogram) + { + if (pos1.x >= pos0.x + 2.0f) + pos1.x -= 1.0f; + window->DrawList->AddRectFilled(pos0, pos1, idx_hovered == v1_idx ? col_hovered : col_base); + } + + t0 = t1; + tp0 = tp1; + } + } + + // Text overlay + if (overlay_text) + RenderTextClipped(ImVec2(frame_bb.Min.x, frame_bb.Min.y + style.FramePadding.y), frame_bb.Max, overlay_text, NULL, NULL, ImVec2(0.5f,0.0f)); + + if (label_size.x > 0.0f) + RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, inner_bb.Min.y), label); + + // Return hovered index or -1 if none are hovered. + // This is currently not exposed in the public API because we need a larger redesign of the whole thing, but in the short-term we are making it available in PlotEx(). + return idx_hovered; +} + +struct ImGuiPlotArrayGetterData +{ + const float* Values; + int Stride; + + ImGuiPlotArrayGetterData(const float* values, int stride) { Values = values; Stride = stride; } +}; + +static float Plot_ArrayGetter(void* data, int idx) +{ + ImGuiPlotArrayGetterData* plot_data = (ImGuiPlotArrayGetterData*)data; + const float v = *(const float*)(const void*)((const unsigned char*)plot_data->Values + (size_t)idx * plot_data->Stride); + return v; +} + +void ImGui::PlotLines(const char* label, const float* values, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, ImVec2 graph_size, int stride) +{ + ImGuiPlotArrayGetterData data(values, stride); + PlotEx(ImGuiPlotType_Lines, label, &Plot_ArrayGetter, (void*)&data, values_count, values_offset, overlay_text, scale_min, scale_max, graph_size); +} + +void ImGui::PlotLines(const char* label, float (*values_getter)(void* data, int idx), void* data, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, ImVec2 graph_size) +{ + PlotEx(ImGuiPlotType_Lines, label, values_getter, data, values_count, values_offset, overlay_text, scale_min, scale_max, graph_size); +} + +void ImGui::PlotHistogram(const char* label, const float* values, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, ImVec2 graph_size, int stride) +{ + ImGuiPlotArrayGetterData data(values, stride); + PlotEx(ImGuiPlotType_Histogram, label, &Plot_ArrayGetter, (void*)&data, values_count, values_offset, overlay_text, scale_min, scale_max, graph_size); +} + +void ImGui::PlotHistogram(const char* label, float (*values_getter)(void* data, int idx), void* data, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, ImVec2 graph_size) +{ + PlotEx(ImGuiPlotType_Histogram, label, values_getter, data, values_count, values_offset, overlay_text, scale_min, scale_max, graph_size); +} + +//------------------------------------------------------------------------- +// [SECTION] Widgets: Value helpers +// Those is not very useful, legacy API. +//------------------------------------------------------------------------- +// - Value() +//------------------------------------------------------------------------- + +void ImGui::Value(const char* prefix, bool b) +{ + Text("%s: %s", prefix, (b ? "true" : "false")); +} + +void ImGui::Value(const char* prefix, int v) +{ + Text("%s: %d", prefix, v); +} + +void ImGui::Value(const char* prefix, unsigned int v) +{ + Text("%s: %d", prefix, v); +} + +void ImGui::Value(const char* prefix, float v, const char* float_format) +{ + if (float_format) + { + char fmt[64]; + ImFormatString(fmt, IM_ARRAYSIZE(fmt), "%%s: %s", float_format); + Text(fmt, prefix, v); + } + else + { + Text("%s: %.3f", prefix, v); + } +} + +//------------------------------------------------------------------------- +// [SECTION] MenuItem, BeginMenu, EndMenu, etc. +//------------------------------------------------------------------------- +// - ImGuiMenuColumns [Internal] +// - BeginMenuBar() +// - EndMenuBar() +// - BeginMainMenuBar() +// - EndMainMenuBar() +// - BeginMenu() +// - EndMenu() +// - MenuItem() +//------------------------------------------------------------------------- + +// Helpers for internal use +ImGuiMenuColumns::ImGuiMenuColumns() +{ + Spacing = Width = NextWidth = 0.0f; + memset(Pos, 0, sizeof(Pos)); + memset(NextWidths, 0, sizeof(NextWidths)); +} + +void ImGuiMenuColumns::Update(int count, float spacing, bool clear) +{ + IM_ASSERT(count == IM_ARRAYSIZE(Pos)); + IM_UNUSED(count); + Width = NextWidth = 0.0f; + Spacing = spacing; + if (clear) + memset(NextWidths, 0, sizeof(NextWidths)); + for (int i = 0; i < IM_ARRAYSIZE(Pos); i++) + { + if (i > 0 && NextWidths[i] > 0.0f) + Width += Spacing; + Pos[i] = IM_FLOOR(Width); + Width += NextWidths[i]; + NextWidths[i] = 0.0f; + } +} + +float ImGuiMenuColumns::DeclColumns(float w0, float w1, float w2) // not using va_arg because they promote float to double +{ + NextWidth = 0.0f; + NextWidths[0] = ImMax(NextWidths[0], w0); + NextWidths[1] = ImMax(NextWidths[1], w1); + NextWidths[2] = ImMax(NextWidths[2], w2); + for (int i = 0; i < IM_ARRAYSIZE(Pos); i++) + NextWidth += NextWidths[i] + ((i > 0 && NextWidths[i] > 0.0f) ? Spacing : 0.0f); + return ImMax(Width, NextWidth); +} + +float ImGuiMenuColumns::CalcExtraSpace(float avail_w) const +{ + return ImMax(0.0f, avail_w - Width); +} + +// FIXME: Provided a rectangle perhaps e.g. a BeginMenuBarEx() could be used anywhere.. +// Currently the main responsibility of this function being to setup clip-rect + horizontal layout + menu navigation layer. +// Ideally we also want this to be responsible for claiming space out of the main window scrolling rectangle, in which case ImGuiWindowFlags_MenuBar will become unnecessary. +// Then later the same system could be used for multiple menu-bars, scrollbars, side-bars. +bool ImGui::BeginMenuBar() +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + if (!(window->Flags & ImGuiWindowFlags_MenuBar)) + return false; + + IM_ASSERT(!window->DC.MenuBarAppending); + BeginGroup(); // Backup position on layer 0 // FIXME: Misleading to use a group for that backup/restore + PushID("##menubar"); + + // We don't clip with current window clipping rectangle as it is already set to the area below. However we clip with window full rect. + // We remove 1 worth of rounding to Max.x to that text in long menus and small windows don't tend to display over the lower-right rounded area, which looks particularly glitchy. + ImRect bar_rect = window->MenuBarRect(); + ImRect clip_rect(IM_ROUND(bar_rect.Min.x + window->WindowBorderSize), IM_ROUND(bar_rect.Min.y + window->WindowBorderSize), IM_ROUND(ImMax(bar_rect.Min.x, bar_rect.Max.x - ImMax(window->WindowRounding, window->WindowBorderSize))), IM_ROUND(bar_rect.Max.y)); + clip_rect.ClipWith(window->OuterRectClipped); + PushClipRect(clip_rect.Min, clip_rect.Max, false); + + window->DC.CursorPos = ImVec2(bar_rect.Min.x + window->DC.MenuBarOffset.x, bar_rect.Min.y + window->DC.MenuBarOffset.y); + window->DC.LayoutType = ImGuiLayoutType_Horizontal; + window->DC.NavLayerCurrent = ImGuiNavLayer_Menu; + window->DC.NavLayerCurrentMask = (1 << ImGuiNavLayer_Menu); + window->DC.MenuBarAppending = true; + AlignTextToFramePadding(); + return true; +} + +void ImGui::EndMenuBar() +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return; + ImGuiContext& g = *GImGui; + + // Nav: When a move request within one of our child menu failed, capture the request to navigate among our siblings. + if (NavMoveRequestButNoResultYet() && (g.NavMoveDir == ImGuiDir_Left || g.NavMoveDir == ImGuiDir_Right) && (g.NavWindow->Flags & ImGuiWindowFlags_ChildMenu)) + { + ImGuiWindow* nav_earliest_child = g.NavWindow; + while (nav_earliest_child->ParentWindow && (nav_earliest_child->ParentWindow->Flags & ImGuiWindowFlags_ChildMenu)) + nav_earliest_child = nav_earliest_child->ParentWindow; + if (nav_earliest_child->ParentWindow == window && nav_earliest_child->DC.ParentLayoutType == ImGuiLayoutType_Horizontal && g.NavMoveRequestForward == ImGuiNavForward_None) + { + // To do so we claim focus back, restore NavId and then process the movement request for yet another frame. + // This involve a one-frame delay which isn't very problematic in this situation. We could remove it by scoring in advance for multiple window (probably not worth the hassle/cost) + const ImGuiNavLayer layer = ImGuiNavLayer_Menu; + IM_ASSERT(window->DC.NavLayerActiveMaskNext & (1 << layer)); // Sanity check + FocusWindow(window); + SetNavIDWithRectRel(window->NavLastIds[layer], layer, 0, window->NavRectRel[layer]); + g.NavLayer = layer; + g.NavDisableHighlight = true; // Hide highlight for the current frame so we don't see the intermediary selection. + g.NavMoveRequestForward = ImGuiNavForward_ForwardQueued; + NavMoveRequestCancel(); + } + } + + IM_ASSERT(window->Flags & ImGuiWindowFlags_MenuBar); + IM_ASSERT(window->DC.MenuBarAppending); + PopClipRect(); + PopID(); + window->DC.MenuBarOffset.x = window->DC.CursorPos.x - window->MenuBarRect().Min.x; // Save horizontal position so next append can reuse it. This is kinda equivalent to a per-layer CursorPos. + window->DC.GroupStack.back().EmitItem = false; + EndGroup(); // Restore position on layer 0 + window->DC.LayoutType = ImGuiLayoutType_Vertical; + window->DC.NavLayerCurrent = ImGuiNavLayer_Main; + window->DC.NavLayerCurrentMask = (1 << ImGuiNavLayer_Main); + window->DC.MenuBarAppending = false; +} + +bool ImGui::BeginMainMenuBar() +{ + ImGuiContext& g = *GImGui; + ImGuiViewportP* viewport = g.Viewports[0]; + ImGuiWindow* menu_bar_window = FindWindowByName("##MainMenuBar"); + + // For the main menu bar, which cannot be moved, we honor g.Style.DisplaySafeAreaPadding to ensure text can be visible on a TV set. + g.NextWindowData.MenuBarOffsetMinVal = ImVec2(g.Style.DisplaySafeAreaPadding.x, ImMax(g.Style.DisplaySafeAreaPadding.y - g.Style.FramePadding.y, 0.0f)); + + // Get our rectangle at the top of the work area + if (menu_bar_window == NULL || menu_bar_window->BeginCount == 0) + { + // Set window position + // We don't attempt to calculate our height ahead, as it depends on the per-viewport font size. However menu-bar will affect the minimum window size so we'll get the right height. + ImVec2 menu_bar_pos = viewport->Pos + viewport->CurrWorkOffsetMin; + ImVec2 menu_bar_size = ImVec2(viewport->Size.x - viewport->CurrWorkOffsetMin.x + viewport->CurrWorkOffsetMax.x, 1.0f); + SetNextWindowPos(menu_bar_pos); + SetNextWindowSize(menu_bar_size); + } + + // Create window + SetNextWindowViewport(viewport->ID); // Enforce viewport so we don't create our own viewport when ImGuiConfigFlags_ViewportsNoMerge is set. + PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f); + PushStyleVar(ImGuiStyleVar_WindowMinSize, ImVec2(0, 0)); // Lift normal size constraint, however the presence of a menu-bar will give us the minimum height we want. + ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoDocking | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_MenuBar; + bool is_open = Begin("##MainMenuBar", NULL, window_flags) && BeginMenuBar(); + PopStyleVar(2); + + // Report our size into work area (for next frame) using actual window size + menu_bar_window = GetCurrentWindow(); + if (menu_bar_window->BeginCount == 1) + viewport->CurrWorkOffsetMin.y += menu_bar_window->Size.y; + + g.NextWindowData.MenuBarOffsetMinVal = ImVec2(0.0f, 0.0f); + if (!is_open) + { + End(); + return false; + } + return true; //-V1020 +} + +void ImGui::EndMainMenuBar() +{ + EndMenuBar(); + + // When the user has left the menu layer (typically: closed menus through activation of an item), we restore focus to the previous window + // FIXME: With this strategy we won't be able to restore a NULL focus. + ImGuiContext& g = *GImGui; + if (g.CurrentWindow == g.NavWindow && g.NavLayer == ImGuiNavLayer_Main && !g.NavAnyRequest) + FocusTopMostWindowUnderOne(g.NavWindow, NULL); + + End(); +} + +bool ImGui::BeginMenu(const char* label, bool enabled) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + ImGuiContext& g = *GImGui; + const ImGuiStyle& style = g.Style; + const ImGuiID id = window->GetID(label); + bool menu_is_open = IsPopupOpen(id); + + // Sub-menus are ChildWindow so that mouse can be hovering across them (otherwise top-most popup menu would steal focus and not allow hovering on parent menu) + ImGuiWindowFlags flags = ImGuiWindowFlags_ChildMenu | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoNavFocus; + if (window->Flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_ChildMenu)) + flags |= ImGuiWindowFlags_ChildWindow; + + // If a menu with same the ID was already submitted, we will append to it, matching the behavior of Begin(). + // We are relying on a O(N) search - so O(N log N) over the frame - which seems like the most efficient for the expected small amount of BeginMenu() calls per frame. + // If somehow this is ever becoming a problem we can switch to use e.g. a ImGuiStorager mapping key to last frame used. + if (g.MenusIdSubmittedThisFrame.contains(id)) + { + if (menu_is_open) + menu_is_open = BeginPopupEx(id, flags); // menu_is_open can be 'false' when the popup is completely clipped (e.g. zero size display) + else + g.NextWindowData.ClearFlags(); // we behave like Begin() and need to consume those values + return menu_is_open; + } + + // Tag menu as used. Next time BeginMenu() with same ID is called it will append to existing menu + g.MenusIdSubmittedThisFrame.push_back(id); + + ImVec2 label_size = CalcTextSize(label, NULL, true); + bool pressed; + bool menuset_is_open = !(window->Flags & ImGuiWindowFlags_Popup) && (g.OpenPopupStack.Size > g.BeginPopupStack.Size && g.OpenPopupStack[g.BeginPopupStack.Size].OpenParentId == window->IDStack.back()); + ImGuiWindow* backed_nav_window = g.NavWindow; + if (menuset_is_open) + g.NavWindow = window; // Odd hack to allow hovering across menus of a same menu-set (otherwise we wouldn't be able to hover parent) + + // The reference position stored in popup_pos will be used by Begin() to find a suitable position for the child menu, + // However the final position is going to be different! It is chosen by FindBestWindowPosForPopup(). + // e.g. Menus tend to overlap each other horizontally to amplify relative Z-ordering. + ImVec2 popup_pos, pos = window->DC.CursorPos; + if (window->DC.LayoutType == ImGuiLayoutType_Horizontal) + { + // Menu inside an horizontal menu bar + // Selectable extend their highlight by half ItemSpacing in each direction. + // For ChildMenu, the popup position will be overwritten by the call to FindBestWindowPosForPopup() in Begin() + popup_pos = ImVec2(pos.x - 1.0f - IM_FLOOR(style.ItemSpacing.x * 0.5f), pos.y - style.FramePadding.y + window->MenuBarHeight()); + window->DC.CursorPos.x += IM_FLOOR(style.ItemSpacing.x * 0.5f); + PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(style.ItemSpacing.x * 2.0f, style.ItemSpacing.y)); + float w = label_size.x; + pressed = Selectable(label, menu_is_open, ImGuiSelectableFlags_NoHoldingActiveID | ImGuiSelectableFlags_SelectOnClick | ImGuiSelectableFlags_DontClosePopups | (!enabled ? ImGuiSelectableFlags_Disabled : 0), ImVec2(w, 0.0f)); + PopStyleVar(); + window->DC.CursorPos.x += IM_FLOOR(style.ItemSpacing.x * (-1.0f + 0.5f)); // -1 spacing to compensate the spacing added when Selectable() did a SameLine(). It would also work to call SameLine() ourselves after the PopStyleVar(). + } + else + { + // Menu inside a menu + // (In a typical menu window where all items are BeginMenu() or MenuItem() calls, extra_w will always be 0.0f. + // Only when they are other items sticking out we're going to add spacing, yet only register minimum width into the layout system. + popup_pos = ImVec2(pos.x, pos.y - style.WindowPadding.y); + float min_w = window->DC.MenuColumns.DeclColumns(label_size.x, 0.0f, IM_FLOOR(g.FontSize * 1.20f)); // Feedback to next frame + float extra_w = ImMax(0.0f, GetContentRegionAvail().x - min_w); + pressed = Selectable(label, menu_is_open, ImGuiSelectableFlags_NoHoldingActiveID | ImGuiSelectableFlags_SelectOnClick | ImGuiSelectableFlags_DontClosePopups | ImGuiSelectableFlags_SpanAvailWidth | (!enabled ? ImGuiSelectableFlags_Disabled : 0), ImVec2(min_w, 0.0f)); + ImU32 text_col = GetColorU32(enabled ? ImGuiCol_Text : ImGuiCol_TextDisabled); + RenderArrow(window->DrawList, pos + ImVec2(window->DC.MenuColumns.Pos[2] + extra_w + g.FontSize * 0.30f, 0.0f), text_col, ImGuiDir_Right); + } + + const bool hovered = enabled && ItemHoverable(window->DC.LastItemRect, id); + if (menuset_is_open) + g.NavWindow = backed_nav_window; + + bool want_open = false; + bool want_close = false; + if (window->DC.LayoutType == ImGuiLayoutType_Vertical) // (window->Flags & (ImGuiWindowFlags_Popup|ImGuiWindowFlags_ChildMenu)) + { + // Close menu when not hovering it anymore unless we are moving roughly in the direction of the menu + // Implement http://bjk5.com/post/44698559168/breaking-down-amazons-mega-dropdown to avoid using timers, so menus feels more reactive. + bool moving_toward_other_child_menu = false; + + ImGuiWindow* child_menu_window = (g.BeginPopupStack.Size < g.OpenPopupStack.Size && g.OpenPopupStack[g.BeginPopupStack.Size].SourceWindow == window) ? g.OpenPopupStack[g.BeginPopupStack.Size].Window : NULL; + if (g.HoveredWindow == window && child_menu_window != NULL && !(window->Flags & ImGuiWindowFlags_MenuBar)) + { + // FIXME-DPI: Values should be derived from a master "scale" factor. + ImRect next_window_rect = child_menu_window->Rect(); + ImVec2 ta = g.IO.MousePos - g.IO.MouseDelta; + ImVec2 tb = (window->Pos.x < child_menu_window->Pos.x) ? next_window_rect.GetTL() : next_window_rect.GetTR(); + ImVec2 tc = (window->Pos.x < child_menu_window->Pos.x) ? next_window_rect.GetBL() : next_window_rect.GetBR(); + float extra = ImClamp(ImFabs(ta.x - tb.x) * 0.30f, 5.0f, 30.0f); // add a bit of extra slack. + ta.x += (window->Pos.x < child_menu_window->Pos.x) ? -0.5f : +0.5f; // to avoid numerical issues + tb.y = ta.y + ImMax((tb.y - extra) - ta.y, -100.0f); // triangle is maximum 200 high to limit the slope and the bias toward large sub-menus // FIXME: Multiply by fb_scale? + tc.y = ta.y + ImMin((tc.y + extra) - ta.y, +100.0f); + moving_toward_other_child_menu = ImTriangleContainsPoint(ta, tb, tc, g.IO.MousePos); + //GetForegroundDrawList()->AddTriangleFilled(ta, tb, tc, moving_within_opened_triangle ? IM_COL32(0,128,0,128) : IM_COL32(128,0,0,128)); // [DEBUG] + } + if (menu_is_open && !hovered && g.HoveredWindow == window && g.HoveredIdPreviousFrame != 0 && g.HoveredIdPreviousFrame != id && !moving_toward_other_child_menu) + want_close = true; + + if (!menu_is_open && hovered && pressed) // Click to open + want_open = true; + else if (!menu_is_open && hovered && !moving_toward_other_child_menu) // Hover to open + want_open = true; + + if (g.NavActivateId == id) + { + want_close = menu_is_open; + want_open = !menu_is_open; + } + if (g.NavId == id && g.NavMoveRequest && g.NavMoveDir == ImGuiDir_Right) // Nav-Right to open + { + want_open = true; + NavMoveRequestCancel(); + } + } + else + { + // Menu bar + if (menu_is_open && pressed && menuset_is_open) // Click an open menu again to close it + { + want_close = true; + want_open = menu_is_open = false; + } + else if (pressed || (hovered && menuset_is_open && !menu_is_open)) // First click to open, then hover to open others + { + want_open = true; + } + else if (g.NavId == id && g.NavMoveRequest && g.NavMoveDir == ImGuiDir_Down) // Nav-Down to open + { + want_open = true; + NavMoveRequestCancel(); + } + } + + if (!enabled) // explicitly close if an open menu becomes disabled, facilitate users code a lot in pattern such as 'if (BeginMenu("options", has_object)) { ..use object.. }' + want_close = true; + if (want_close && IsPopupOpen(id)) + ClosePopupToLevel(g.BeginPopupStack.Size, true); + + IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.ItemFlags | ImGuiItemStatusFlags_Openable | (menu_is_open ? ImGuiItemStatusFlags_Opened : 0)); + + if (!menu_is_open && want_open && g.OpenPopupStack.Size > g.BeginPopupStack.Size) + { + // Don't recycle same menu level in the same frame, first close the other menu and yield for a frame. + OpenPopup(label); + return false; + } + + menu_is_open |= want_open; + if (want_open) + OpenPopup(label); + + if (menu_is_open) + { + SetNextWindowPos(popup_pos, ImGuiCond_Always); + menu_is_open = BeginPopupEx(id, flags); // menu_is_open can be 'false' when the popup is completely clipped (e.g. zero size display) + } + else + { + g.NextWindowData.ClearFlags(); // We behave like Begin() and need to consume those values + } + + return menu_is_open; +} + +void ImGui::EndMenu() +{ + // Nav: When a left move request _within our child menu_ failed, close ourselves (the _parent_ menu). + // A menu doesn't close itself because EndMenuBar() wants the catch the last Left<>Right inputs. + // However, it means that with the current code, a BeginMenu() from outside another menu or a menu-bar won't be closable with the Left direction. + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if (g.NavWindow && g.NavWindow->ParentWindow == window && g.NavMoveDir == ImGuiDir_Left && NavMoveRequestButNoResultYet() && window->DC.LayoutType == ImGuiLayoutType_Vertical) + { + ClosePopupToLevel(g.BeginPopupStack.Size, true); + NavMoveRequestCancel(); + } + + EndPopup(); +} + +bool ImGui::MenuItem(const char* label, const char* shortcut, bool selected, bool enabled) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + ImGuiContext& g = *GImGui; + ImGuiStyle& style = g.Style; + ImVec2 pos = window->DC.CursorPos; + ImVec2 label_size = CalcTextSize(label, NULL, true); + + // We've been using the equivalent of ImGuiSelectableFlags_SetNavIdOnHover on all Selectable() since early Nav system days (commit 43ee5d73), + // but I am unsure whether this should be kept at all. For now moved it to be an opt-in feature used by menus only. + ImGuiSelectableFlags flags = ImGuiSelectableFlags_SelectOnRelease | ImGuiSelectableFlags_SetNavIdOnHover | (enabled ? 0 : ImGuiSelectableFlags_Disabled); + bool pressed; + if (window->DC.LayoutType == ImGuiLayoutType_Horizontal) + { + // Mimic the exact layout spacing of BeginMenu() to allow MenuItem() inside a menu bar, which is a little misleading but may be useful + // Note that in this situation we render neither the shortcut neither the selected tick mark + float w = label_size.x; + window->DC.CursorPos.x += IM_FLOOR(style.ItemSpacing.x * 0.5f); + PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(style.ItemSpacing.x * 2.0f, style.ItemSpacing.y)); + pressed = Selectable(label, false, flags, ImVec2(w, 0.0f)); + PopStyleVar(); + window->DC.CursorPos.x += IM_FLOOR(style.ItemSpacing.x * (-1.0f + 0.5f)); // -1 spacing to compensate the spacing added when Selectable() did a SameLine(). It would also work to call SameLine() ourselves after the PopStyleVar(). + } + else + { + // Menu item inside a vertical menu + // (In a typical menu window where all items are BeginMenu() or MenuItem() calls, extra_w will always be 0.0f. + // Only when they are other items sticking out we're going to add spacing, yet only register minimum width into the layout system. + float shortcut_w = shortcut ? CalcTextSize(shortcut, NULL).x : 0.0f; + float min_w = window->DC.MenuColumns.DeclColumns(label_size.x, shortcut_w, IM_FLOOR(g.FontSize * 1.20f)); // Feedback for next frame + float extra_w = ImMax(0.0f, GetContentRegionAvail().x - min_w); + pressed = Selectable(label, false, flags | ImGuiSelectableFlags_SpanAvailWidth, ImVec2(min_w, 0.0f)); + if (shortcut_w > 0.0f) + { + PushStyleColor(ImGuiCol_Text, g.Style.Colors[ImGuiCol_TextDisabled]); + RenderText(pos + ImVec2(window->DC.MenuColumns.Pos[1] + extra_w, 0.0f), shortcut, NULL, false); + PopStyleColor(); + } + if (selected) + RenderCheckMark(window->DrawList, pos + ImVec2(window->DC.MenuColumns.Pos[2] + extra_w + g.FontSize * 0.40f, g.FontSize * 0.134f * 0.5f), GetColorU32(enabled ? ImGuiCol_Text : ImGuiCol_TextDisabled), g.FontSize * 0.866f); + } + + IMGUI_TEST_ENGINE_ITEM_INFO(window->DC.LastItemId, label, window->DC.ItemFlags | ImGuiItemStatusFlags_Checkable | (selected ? ImGuiItemStatusFlags_Checked : 0)); + return pressed; +} + +bool ImGui::MenuItem(const char* label, const char* shortcut, bool* p_selected, bool enabled) +{ + if (MenuItem(label, shortcut, p_selected ? *p_selected : false, enabled)) + { + if (p_selected) + *p_selected = !*p_selected; + return true; + } + return false; +} + +//------------------------------------------------------------------------- +// [SECTION] Widgets: BeginTabBar, EndTabBar, etc. +//------------------------------------------------------------------------- +// - BeginTabBar() +// - BeginTabBarEx() [Internal] +// - EndTabBar() +// - TabBarLayout() [Internal] +// - TabBarCalcTabID() [Internal] +// - TabBarCalcMaxTabWidth() [Internal] +// - TabBarFindTabById() [Internal] +// - TabBarAddTab() [Internal] +// - TabBarRemoveTab() [Internal] +// - TabBarCloseTab() [Internal] +// - TabBarScrollClamp()v +// - TabBarScrollToTab() [Internal] +// - TabBarQueueChangeTabOrder() [Internal] +// - TabBarScrollingButtons() [Internal] +// - TabBarTabListPopupButton() [Internal] +//------------------------------------------------------------------------- + +namespace ImGui +{ + static void TabBarLayout(ImGuiTabBar* tab_bar); + static ImU32 TabBarCalcTabID(ImGuiTabBar* tab_bar, const char* label); + static float TabBarCalcMaxTabWidth(); + static float TabBarScrollClamp(ImGuiTabBar* tab_bar, float scrolling); + static void TabBarScrollToTab(ImGuiTabBar* tab_bar, ImGuiTabItem* tab); + static ImGuiTabItem* TabBarScrollingButtons(ImGuiTabBar* tab_bar); + static ImGuiTabItem* TabBarTabListPopupButton(ImGuiTabBar* tab_bar); +} + +ImGuiTabBar::ImGuiTabBar() +{ + ID = 0; + SelectedTabId = NextSelectedTabId = VisibleTabId = 0; + CurrFrameVisible = PrevFrameVisible = -1; + LastTabContentHeight = 0.0f; + OffsetMax = OffsetMaxIdeal = OffsetNextTab = 0.0f; + ScrollingAnim = ScrollingTarget = ScrollingTargetDistToVisibility = ScrollingSpeed = 0.0f; + Flags = ImGuiTabBarFlags_None; + ReorderRequestTabId = 0; + ReorderRequestDir = 0; + WantLayout = VisibleTabWasSubmitted = false; + LastTabItemIdx = -1; +} + +static int IMGUI_CDECL TabItemComparerByVisibleOffset(const void* lhs, const void* rhs) +{ + const ImGuiTabItem* a = (const ImGuiTabItem*)lhs; + const ImGuiTabItem* b = (const ImGuiTabItem*)rhs; + return (int)(a->Offset - b->Offset); +} + +static ImGuiTabBar* GetTabBarFromTabBarRef(const ImGuiPtrOrIndex& ref) +{ + ImGuiContext& g = *GImGui; + return ref.Ptr ? (ImGuiTabBar*)ref.Ptr : g.TabBars.GetByIndex(ref.Index); +} + +static ImGuiPtrOrIndex GetTabBarRefFromTabBar(ImGuiTabBar* tab_bar) +{ + ImGuiContext& g = *GImGui; + if (g.TabBars.Contains(tab_bar)) + return ImGuiPtrOrIndex(g.TabBars.GetIndex(tab_bar)); + return ImGuiPtrOrIndex(tab_bar); +} + +bool ImGui::BeginTabBar(const char* str_id, ImGuiTabBarFlags flags) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if (window->SkipItems) + return false; + + ImGuiID id = window->GetID(str_id); + ImGuiTabBar* tab_bar = g.TabBars.GetOrAddByKey(id); + ImRect tab_bar_bb = ImRect(window->DC.CursorPos.x, window->DC.CursorPos.y, window->WorkRect.Max.x, window->DC.CursorPos.y + g.FontSize + g.Style.FramePadding.y * 2); + tab_bar->ID = id; + return BeginTabBarEx(tab_bar, tab_bar_bb, flags | ImGuiTabBarFlags_IsFocused, NULL); +} + +bool ImGui::BeginTabBarEx(ImGuiTabBar* tab_bar, const ImRect& tab_bar_bb, ImGuiTabBarFlags flags, ImGuiDockNode* dock_node) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if (window->SkipItems) + return false; + + if ((flags & ImGuiTabBarFlags_DockNode) == 0) + PushOverrideID(tab_bar->ID); + + // Add to stack + g.CurrentTabBarStack.push_back(GetTabBarRefFromTabBar(tab_bar)); + g.CurrentTabBar = tab_bar; + + if (tab_bar->CurrFrameVisible == g.FrameCount) + { + //IMGUI_DEBUG_LOG("BeginTabBarEx already called this frame\n", g.FrameCount); + //IM_ASSERT(0); + return true; + } + + // When toggling back from ordered to manually-reorderable, shuffle tabs to enforce the last visible order. + // Otherwise, the most recently inserted tabs would move at the end of visible list which can be a little too confusing or magic for the user. + if ((flags & ImGuiTabBarFlags_Reorderable) && !(tab_bar->Flags & ImGuiTabBarFlags_Reorderable) && tab_bar->Tabs.Size > 1 && tab_bar->PrevFrameVisible != -1) + ImQsort(tab_bar->Tabs.Data, tab_bar->Tabs.Size, sizeof(ImGuiTabItem), TabItemComparerByVisibleOffset); + + // Flags + if ((flags & ImGuiTabBarFlags_FittingPolicyMask_) == 0) + flags |= ImGuiTabBarFlags_FittingPolicyDefault_; + + tab_bar->Flags = flags; + tab_bar->BarRect = tab_bar_bb; + tab_bar->WantLayout = true; // Layout will be done on the first call to ItemTab() + tab_bar->PrevFrameVisible = tab_bar->CurrFrameVisible; + tab_bar->CurrFrameVisible = g.FrameCount; + tab_bar->FramePadding = g.Style.FramePadding; + + // Layout + ItemSize(ImVec2(tab_bar->OffsetMaxIdeal, tab_bar->BarRect.GetHeight()), tab_bar->FramePadding.y); + window->DC.CursorPos.x = tab_bar->BarRect.Min.x; + + // Draw separator + const ImU32 col = GetColorU32((flags & ImGuiTabBarFlags_IsFocused) ? ImGuiCol_TabActive : ImGuiCol_TabUnfocusedActive); + const float y = tab_bar->BarRect.Max.y - 1.0f; + if (dock_node != NULL) + { + const float separator_min_x = dock_node->Pos.x + window->WindowBorderSize; + const float separator_max_x = dock_node->Pos.x + dock_node->Size.x - window->WindowBorderSize; + window->DrawList->AddLine(ImVec2(separator_min_x, y), ImVec2(separator_max_x, y), col, 1.0f); + } + else + { + const float separator_min_x = tab_bar->BarRect.Min.x - IM_FLOOR(window->WindowPadding.x * 0.5f); + const float separator_max_x = tab_bar->BarRect.Max.x + IM_FLOOR(window->WindowPadding.x * 0.5f); + window->DrawList->AddLine(ImVec2(separator_min_x, y), ImVec2(separator_max_x, y), col, 1.0f); + } + return true; +} + +void ImGui::EndTabBar() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if (window->SkipItems) + return; + + ImGuiTabBar* tab_bar = g.CurrentTabBar; + if (tab_bar == NULL) + { + IM_ASSERT_USER_ERROR(tab_bar != NULL, "Mismatched BeginTabBar()/EndTabBar()!"); + return; + } + if (tab_bar->WantLayout) + TabBarLayout(tab_bar); + + // Restore the last visible height if no tab is visible, this reduce vertical flicker/movement when a tabs gets removed without calling SetTabItemClosed(). + const bool tab_bar_appearing = (tab_bar->PrevFrameVisible + 1 < g.FrameCount); + if (tab_bar->VisibleTabWasSubmitted || tab_bar->VisibleTabId == 0 || tab_bar_appearing) + tab_bar->LastTabContentHeight = ImMax(window->DC.CursorPos.y - tab_bar->BarRect.Max.y, 0.0f); + else + window->DC.CursorPos.y = tab_bar->BarRect.Max.y + tab_bar->LastTabContentHeight; + + if ((tab_bar->Flags & ImGuiTabBarFlags_DockNode) == 0) + PopID(); + + g.CurrentTabBarStack.pop_back(); + g.CurrentTabBar = g.CurrentTabBarStack.empty() ? NULL : GetTabBarFromTabBarRef(g.CurrentTabBarStack.back()); +} + +// This is called only once a frame before by the first call to ItemTab() +// The reason we're not calling it in BeginTabBar() is to leave a chance to the user to call the SetTabItemClosed() functions. +static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar) +{ + ImGuiContext& g = *GImGui; + tab_bar->WantLayout = false; + + // Garbage collect + int tab_dst_n = 0; + for (int tab_src_n = 0; tab_src_n < tab_bar->Tabs.Size; tab_src_n++) + { + ImGuiTabItem* tab = &tab_bar->Tabs[tab_src_n]; + if (tab->LastFrameVisible < tab_bar->PrevFrameVisible) + { + if (tab->ID == tab_bar->SelectedTabId) + tab_bar->SelectedTabId = 0; + continue; + } + if (tab_dst_n != tab_src_n) + tab_bar->Tabs[tab_dst_n] = tab_bar->Tabs[tab_src_n]; + tab_dst_n++; + } + if (tab_bar->Tabs.Size != tab_dst_n) + tab_bar->Tabs.resize(tab_dst_n); + + // Setup next selected tab + ImGuiID scroll_track_selected_tab_id = 0; + if (tab_bar->NextSelectedTabId) + { + tab_bar->SelectedTabId = tab_bar->NextSelectedTabId; + tab_bar->NextSelectedTabId = 0; + scroll_track_selected_tab_id = tab_bar->SelectedTabId; + } + + // Process order change request (we could probably process it when requested but it's just saner to do it in a single spot). + if (tab_bar->ReorderRequestTabId != 0) + { + if (ImGuiTabItem* tab1 = TabBarFindTabByID(tab_bar, tab_bar->ReorderRequestTabId)) + { + //IM_ASSERT(tab_bar->Flags & ImGuiTabBarFlags_Reorderable); // <- this may happen when using debug tools + int tab2_order = tab_bar->GetTabOrder(tab1) + tab_bar->ReorderRequestDir; + if (tab2_order >= 0 && tab2_order < tab_bar->Tabs.Size) + { + ImGuiTabItem* tab2 = &tab_bar->Tabs[tab2_order]; + ImGuiTabItem item_tmp = *tab1; + *tab1 = *tab2; + *tab2 = item_tmp; + if (tab2->ID == tab_bar->SelectedTabId) + scroll_track_selected_tab_id = tab2->ID; + tab1 = tab2 = NULL; + } + if (tab_bar->Flags & ImGuiTabBarFlags_SaveSettings) + MarkIniSettingsDirty(); + } + tab_bar->ReorderRequestTabId = 0; + } + + // Tab List Popup (will alter tab_bar->BarRect and therefore the available width!) + const bool tab_list_popup_button = (tab_bar->Flags & ImGuiTabBarFlags_TabListPopupButton) != 0; + if (tab_list_popup_button) + if (ImGuiTabItem* tab_to_select = TabBarTabListPopupButton(tab_bar)) // NB: Will alter BarRect.Max.x! + scroll_track_selected_tab_id = tab_bar->SelectedTabId = tab_to_select->ID; + + // Compute ideal widths + g.ShrinkWidthBuffer.resize(tab_bar->Tabs.Size); + float width_total_contents = 0.0f; + ImGuiTabItem* most_recently_selected_tab = NULL; + bool found_selected_tab_id = false; + for (int tab_n = 0; tab_n < tab_bar->Tabs.Size; tab_n++) + { + ImGuiTabItem* tab = &tab_bar->Tabs[tab_n]; + IM_ASSERT(tab->LastFrameVisible >= tab_bar->PrevFrameVisible); + + if (most_recently_selected_tab == NULL || most_recently_selected_tab->LastFrameSelected < tab->LastFrameSelected) + most_recently_selected_tab = tab; + if (tab->ID == tab_bar->SelectedTabId) + found_selected_tab_id = true; + + // Refresh tab width immediately, otherwise changes of style e.g. style.FramePadding.x would noticeably lag in the tab bar. + // Additionally, when using TabBarAddTab() to manipulate tab bar order we occasionally insert new tabs that don't have a width yet, + // and we cannot wait for the next BeginTabItem() call. We cannot compute this width within TabBarAddTab() because font size depends on the active window. + const char* tab_name = tab_bar->GetTabName(tab); + const bool has_close_button = tab->Window ? tab->Window->HasCloseButton : ((tab->Flags & ImGuiTabItemFlags_NoCloseButton) == 0); + tab->ContentWidth = TabItemCalcSize(tab_name, has_close_button).x; + + width_total_contents += (tab_n > 0 ? g.Style.ItemInnerSpacing.x : 0.0f) + tab->ContentWidth; + + // Store data so we can build an array sorted by width if we need to shrink tabs down + g.ShrinkWidthBuffer[tab_n].Index = tab_n; + g.ShrinkWidthBuffer[tab_n].Width = tab->ContentWidth; + } + + // Compute width + const float initial_offset_x = 0.0f; // g.Style.ItemInnerSpacing.x; + const float width_avail = ImMax(tab_bar->BarRect.GetWidth() - initial_offset_x, 0.0f); + float width_excess = (width_avail < width_total_contents) ? (width_total_contents - width_avail) : 0.0f; + if (width_excess > 0.0f && (tab_bar->Flags & ImGuiTabBarFlags_FittingPolicyResizeDown)) + { + // If we don't have enough room, resize down the largest tabs first + ShrinkWidths(g.ShrinkWidthBuffer.Data, g.ShrinkWidthBuffer.Size, width_excess); + for (int tab_n = 0; tab_n < tab_bar->Tabs.Size; tab_n++) + tab_bar->Tabs[g.ShrinkWidthBuffer[tab_n].Index].Width = IM_FLOOR(g.ShrinkWidthBuffer[tab_n].Width); + } + else + { + const float tab_max_width = TabBarCalcMaxTabWidth(); + for (int tab_n = 0; tab_n < tab_bar->Tabs.Size; tab_n++) + { + ImGuiTabItem* tab = &tab_bar->Tabs[tab_n]; + tab->Width = ImMin(tab->ContentWidth, tab_max_width); + IM_ASSERT(tab->Width > 0.0f); + } + } + + // Layout all active tabs + float offset_x = initial_offset_x; + float offset_x_ideal = offset_x; + tab_bar->OffsetNextTab = offset_x; // This is used by non-reorderable tab bar where the submission order is always honored. + for (int tab_n = 0; tab_n < tab_bar->Tabs.Size; tab_n++) + { + ImGuiTabItem* tab = &tab_bar->Tabs[tab_n]; + tab->Offset = offset_x; + if (scroll_track_selected_tab_id == 0 && g.NavJustMovedToId == tab->ID) + scroll_track_selected_tab_id = tab->ID; + offset_x += tab->Width + g.Style.ItemInnerSpacing.x; + offset_x_ideal += tab->ContentWidth + g.Style.ItemInnerSpacing.x; + } + tab_bar->OffsetMax = ImMax(offset_x - g.Style.ItemInnerSpacing.x, 0.0f); + tab_bar->OffsetMaxIdeal = ImMax(offset_x_ideal - g.Style.ItemInnerSpacing.x, 0.0f); + + // Horizontal scrolling buttons + const bool scrolling_buttons = (tab_bar->OffsetMax > tab_bar->BarRect.GetWidth() && tab_bar->Tabs.Size > 1) && !(tab_bar->Flags & ImGuiTabBarFlags_NoTabListScrollingButtons) && (tab_bar->Flags & ImGuiTabBarFlags_FittingPolicyScroll); + if (scrolling_buttons) + if (ImGuiTabItem* tab_to_select = TabBarScrollingButtons(tab_bar)) // NB: Will alter BarRect.Max.x! + scroll_track_selected_tab_id = tab_bar->SelectedTabId = tab_to_select->ID; + + // If we have lost the selected tab, select the next most recently active one + if (found_selected_tab_id == false) + tab_bar->SelectedTabId = 0; + if (tab_bar->SelectedTabId == 0 && tab_bar->NextSelectedTabId == 0 && most_recently_selected_tab != NULL) + scroll_track_selected_tab_id = tab_bar->SelectedTabId = most_recently_selected_tab->ID; + + // Lock in visible tab + tab_bar->VisibleTabId = tab_bar->SelectedTabId; + tab_bar->VisibleTabWasSubmitted = false; + + // CTRL+TAB can override visible tab temporarily + if (g.NavWindowingTarget != NULL && g.NavWindowingTarget->DockNode && g.NavWindowingTarget->DockNode->TabBar == tab_bar) + tab_bar->VisibleTabId = scroll_track_selected_tab_id = g.NavWindowingTarget->ID; + + // Update scrolling + if (scroll_track_selected_tab_id) + if (ImGuiTabItem* scroll_track_selected_tab = TabBarFindTabByID(tab_bar, scroll_track_selected_tab_id)) + TabBarScrollToTab(tab_bar, scroll_track_selected_tab); + tab_bar->ScrollingAnim = TabBarScrollClamp(tab_bar, tab_bar->ScrollingAnim); + tab_bar->ScrollingTarget = TabBarScrollClamp(tab_bar, tab_bar->ScrollingTarget); + if (tab_bar->ScrollingAnim != tab_bar->ScrollingTarget) + { + // Scrolling speed adjust itself so we can always reach our target in 1/3 seconds. + // Teleport if we are aiming far off the visible line + tab_bar->ScrollingSpeed = ImMax(tab_bar->ScrollingSpeed, 70.0f * g.FontSize); + tab_bar->ScrollingSpeed = ImMax(tab_bar->ScrollingSpeed, ImFabs(tab_bar->ScrollingTarget - tab_bar->ScrollingAnim) / 0.3f); + const bool teleport = (tab_bar->PrevFrameVisible + 1 < g.FrameCount) || (tab_bar->ScrollingTargetDistToVisibility > 10.0f * g.FontSize); + tab_bar->ScrollingAnim = teleport ? tab_bar->ScrollingTarget : ImLinearSweep(tab_bar->ScrollingAnim, tab_bar->ScrollingTarget, g.IO.DeltaTime * tab_bar->ScrollingSpeed); + } + else + { + tab_bar->ScrollingSpeed = 0.0f; + } + + // Clear name buffers + if ((tab_bar->Flags & ImGuiTabBarFlags_DockNode) == 0) + tab_bar->TabsNames.Buf.resize(0); +} + +// Dockables uses Name/ID in the global namespace. Non-dockable items use the ID stack. +static ImU32 ImGui::TabBarCalcTabID(ImGuiTabBar* tab_bar, const char* label) +{ + if (tab_bar->Flags & ImGuiTabBarFlags_DockNode) + { + ImGuiID id = ImHashStr(label); + KeepAliveID(id); + return id; + } + else + { + ImGuiWindow* window = GImGui->CurrentWindow; + return window->GetID(label); + } +} + +static float ImGui::TabBarCalcMaxTabWidth() +{ + ImGuiContext& g = *GImGui; + return g.FontSize * 20.0f; +} + +ImGuiTabItem* ImGui::TabBarFindTabByID(ImGuiTabBar* tab_bar, ImGuiID tab_id) +{ + if (tab_id != 0) + for (int n = 0; n < tab_bar->Tabs.Size; n++) + if (tab_bar->Tabs[n].ID == tab_id) + return &tab_bar->Tabs[n]; + return NULL; +} + +// FIXME: See references to #2304 in TODO.txt +ImGuiTabItem* ImGui::TabBarFindMostRecentlySelectedTabForActiveWindow(ImGuiTabBar* tab_bar) +{ + ImGuiTabItem* most_recently_selected_tab = NULL; + for (int tab_n = 0; tab_n < tab_bar->Tabs.Size; tab_n++) + { + ImGuiTabItem* tab = &tab_bar->Tabs[tab_n]; + if (most_recently_selected_tab == NULL || most_recently_selected_tab->LastFrameSelected < tab->LastFrameSelected) + if (tab->Window && tab->Window->WasActive) + most_recently_selected_tab = tab; + } + return most_recently_selected_tab; +} + +// The purpose of this call is to register tab in advance so we can control their order at the time they appear. +// Otherwise calling this is unnecessary as tabs are appending as needed by the BeginTabItem() function. +void ImGui::TabBarAddTab(ImGuiTabBar* tab_bar, ImGuiTabItemFlags tab_flags, ImGuiWindow* window) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(TabBarFindTabByID(tab_bar, window->ID) == NULL); + IM_ASSERT(g.CurrentTabBar != tab_bar); // Can't work while the tab bar is active as our tab doesn't have an X offset yet, in theory we could/should test something like (tab_bar->CurrFrameVisible < g.FrameCount) but we'd need to solve why triggers the commented early-out assert in BeginTabBarEx() (probably dock node going from implicit to explicit in same frame) + + ImGuiTabItem new_tab; + new_tab.ID = window->ID; + new_tab.Flags = tab_flags; + new_tab.LastFrameVisible = tab_bar->CurrFrameVisible; // Required so BeginTabBar() doesn't ditch the tab + if (new_tab.LastFrameVisible == -1) + new_tab.LastFrameVisible = g.FrameCount - 1; + new_tab.Window = window; // Required so tab bar layout can compute the tab width before tab submission + tab_bar->Tabs.push_back(new_tab); +} + +// The *TabId fields be already set by the docking system _before_ the actual TabItem was created, so we clear them regardless. +void ImGui::TabBarRemoveTab(ImGuiTabBar* tab_bar, ImGuiID tab_id) +{ + if (ImGuiTabItem* tab = TabBarFindTabByID(tab_bar, tab_id)) + tab_bar->Tabs.erase(tab); + if (tab_bar->VisibleTabId == tab_id) { tab_bar->VisibleTabId = 0; } + if (tab_bar->SelectedTabId == tab_id) { tab_bar->SelectedTabId = 0; } + if (tab_bar->NextSelectedTabId == tab_id) { tab_bar->NextSelectedTabId = 0; } +} + +// Called on manual closure attempt +void ImGui::TabBarCloseTab(ImGuiTabBar* tab_bar, ImGuiTabItem* tab) +{ + if ((tab_bar->VisibleTabId == tab->ID) && !(tab->Flags & ImGuiTabItemFlags_UnsavedDocument)) + { + // This will remove a frame of lag for selecting another tab on closure. + // However we don't run it in the case where the 'Unsaved' flag is set, so user gets a chance to fully undo the closure + tab->LastFrameVisible = -1; + tab_bar->SelectedTabId = tab_bar->NextSelectedTabId = 0; + } + else if ((tab_bar->VisibleTabId != tab->ID) && (tab->Flags & ImGuiTabItemFlags_UnsavedDocument)) + { + // Actually select before expecting closure + tab_bar->NextSelectedTabId = tab->ID; + } +} + +static float ImGui::TabBarScrollClamp(ImGuiTabBar* tab_bar, float scrolling) +{ + scrolling = ImMin(scrolling, tab_bar->OffsetMax - tab_bar->BarRect.GetWidth()); + return ImMax(scrolling, 0.0f); +} + +static void ImGui::TabBarScrollToTab(ImGuiTabBar* tab_bar, ImGuiTabItem* tab) +{ + ImGuiContext& g = *GImGui; + float margin = g.FontSize * 1.0f; // When to scroll to make Tab N+1 visible always make a bit of N visible to suggest more scrolling area (since we don't have a scrollbar) + int order = tab_bar->GetTabOrder(tab); + float tab_x1 = tab->Offset + (order > 0 ? -margin : 0.0f); + float tab_x2 = tab->Offset + tab->Width + (order + 1 < tab_bar->Tabs.Size ? margin : 1.0f); + tab_bar->ScrollingTargetDistToVisibility = 0.0f; + if (tab_bar->ScrollingTarget > tab_x1 || (tab_x2 - tab_x1 >= tab_bar->BarRect.GetWidth())) + { + tab_bar->ScrollingTargetDistToVisibility = ImMax(tab_bar->ScrollingAnim - tab_x2, 0.0f); + tab_bar->ScrollingTarget = tab_x1; + } + else if (tab_bar->ScrollingTarget < tab_x2 - tab_bar->BarRect.GetWidth()) + { + tab_bar->ScrollingTargetDistToVisibility = ImMax((tab_x1 - tab_bar->BarRect.GetWidth()) - tab_bar->ScrollingAnim, 0.0f); + tab_bar->ScrollingTarget = tab_x2 - tab_bar->BarRect.GetWidth(); + } +} + +void ImGui::TabBarQueueChangeTabOrder(ImGuiTabBar* tab_bar, const ImGuiTabItem* tab, int dir) +{ + IM_ASSERT(dir == -1 || dir == +1); + IM_ASSERT(tab_bar->ReorderRequestTabId == 0); + tab_bar->ReorderRequestTabId = tab->ID; + tab_bar->ReorderRequestDir = (ImS8)dir; +} + +static ImGuiTabItem* ImGui::TabBarScrollingButtons(ImGuiTabBar* tab_bar) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + + const ImVec2 arrow_button_size(g.FontSize - 2.0f, g.FontSize + g.Style.FramePadding.y * 2.0f); + const float scrolling_buttons_width = arrow_button_size.x * 2.0f; + + const ImVec2 backup_cursor_pos = window->DC.CursorPos; + //window->DrawList->AddRect(ImVec2(tab_bar->BarRect.Max.x - scrolling_buttons_width, tab_bar->BarRect.Min.y), ImVec2(tab_bar->BarRect.Max.x, tab_bar->BarRect.Max.y), IM_COL32(255,0,0,255)); + + const ImRect avail_bar_rect = tab_bar->BarRect; + bool want_clip_rect = !avail_bar_rect.Contains(ImRect(window->DC.CursorPos, window->DC.CursorPos + ImVec2(scrolling_buttons_width, 0.0f))); + if (want_clip_rect) + PushClipRect(tab_bar->BarRect.Min, tab_bar->BarRect.Max + ImVec2(g.Style.ItemInnerSpacing.x, 0.0f), true); + + ImGuiTabItem* tab_to_select = NULL; + + int select_dir = 0; + ImVec4 arrow_col = g.Style.Colors[ImGuiCol_Text]; + arrow_col.w *= 0.5f; + + PushStyleColor(ImGuiCol_Text, arrow_col); + PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0)); + const float backup_repeat_delay = g.IO.KeyRepeatDelay; + const float backup_repeat_rate = g.IO.KeyRepeatRate; + g.IO.KeyRepeatDelay = 0.250f; + g.IO.KeyRepeatRate = 0.200f; + window->DC.CursorPos = ImVec2(tab_bar->BarRect.Max.x - scrolling_buttons_width, tab_bar->BarRect.Min.y); + if (ArrowButtonEx("##<", ImGuiDir_Left, arrow_button_size, ImGuiButtonFlags_PressedOnClick | ImGuiButtonFlags_Repeat)) + select_dir = -1; + window->DC.CursorPos = ImVec2(tab_bar->BarRect.Max.x - scrolling_buttons_width + arrow_button_size.x, tab_bar->BarRect.Min.y); + if (ArrowButtonEx("##>", ImGuiDir_Right, arrow_button_size, ImGuiButtonFlags_PressedOnClick | ImGuiButtonFlags_Repeat)) + select_dir = +1; + PopStyleColor(2); + g.IO.KeyRepeatRate = backup_repeat_rate; + g.IO.KeyRepeatDelay = backup_repeat_delay; + + if (want_clip_rect) + PopClipRect(); + + if (select_dir != 0) + if (ImGuiTabItem* tab_item = TabBarFindTabByID(tab_bar, tab_bar->SelectedTabId)) + { + int selected_order = tab_bar->GetTabOrder(tab_item); + int target_order = selected_order + select_dir; + tab_to_select = &tab_bar->Tabs[(target_order >= 0 && target_order < tab_bar->Tabs.Size) ? target_order : selected_order]; // If we are at the end of the list, still scroll to make our tab visible + } + window->DC.CursorPos = backup_cursor_pos; + tab_bar->BarRect.Max.x -= scrolling_buttons_width + 1.0f; + + return tab_to_select; +} + +static ImGuiTabItem* ImGui::TabBarTabListPopupButton(ImGuiTabBar* tab_bar) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + + // We use g.Style.FramePadding.y to match the square ArrowButton size + const float tab_list_popup_button_width = g.FontSize + g.Style.FramePadding.y; + const ImVec2 backup_cursor_pos = window->DC.CursorPos; + window->DC.CursorPos = ImVec2(tab_bar->BarRect.Min.x - g.Style.FramePadding.y, tab_bar->BarRect.Min.y); + tab_bar->BarRect.Min.x += tab_list_popup_button_width; + + ImVec4 arrow_col = g.Style.Colors[ImGuiCol_Text]; + arrow_col.w *= 0.5f; + PushStyleColor(ImGuiCol_Text, arrow_col); + PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0)); + bool open = BeginCombo("##v", NULL, ImGuiComboFlags_NoPreview); + PopStyleColor(2); + + ImGuiTabItem* tab_to_select = NULL; + if (open) + { + for (int tab_n = 0; tab_n < tab_bar->Tabs.Size; tab_n++) + { + ImGuiTabItem* tab = &tab_bar->Tabs[tab_n]; + const char* tab_name = tab_bar->GetTabName(tab); + if (Selectable(tab_name, tab_bar->SelectedTabId == tab->ID)) + tab_to_select = tab; + } + EndCombo(); + } + + window->DC.CursorPos = backup_cursor_pos; + return tab_to_select; +} + +//------------------------------------------------------------------------- +// [SECTION] Widgets: BeginTabItem, EndTabItem, etc. +//------------------------------------------------------------------------- +// - BeginTabItem() +// - EndTabItem() +// - TabItemEx() [Internal] +// - SetTabItemClosed() +// - TabItemCalcSize() [Internal] +// - TabItemBackground() [Internal] +// - TabItemLabelAndCloseButton() [Internal] +//------------------------------------------------------------------------- + +bool ImGui::BeginTabItem(const char* label, bool* p_open, ImGuiTabItemFlags flags) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if (window->SkipItems) + return false; + + ImGuiTabBar* tab_bar = g.CurrentTabBar; + if (tab_bar == NULL) + { + IM_ASSERT_USER_ERROR(tab_bar, "BeginTabItem() Needs to be called between BeginTabBar() and EndTabBar()!"); + return false; + } + bool ret = TabItemEx(tab_bar, label, p_open, flags, NULL); + if (ret && !(flags & ImGuiTabItemFlags_NoPushId)) + { + ImGuiTabItem* tab = &tab_bar->Tabs[tab_bar->LastTabItemIdx]; + PushOverrideID(tab->ID); // We already hashed 'label' so push into the ID stack directly instead of doing another hash through PushID(label) + } + return ret; +} + +void ImGui::EndTabItem() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if (window->SkipItems) + return; + + ImGuiTabBar* tab_bar = g.CurrentTabBar; + if (tab_bar == NULL) + { + IM_ASSERT(tab_bar != NULL && "Needs to be called between BeginTabBar() and EndTabBar()!"); + return; + } + IM_ASSERT(tab_bar->LastTabItemIdx >= 0); + ImGuiTabItem* tab = &tab_bar->Tabs[tab_bar->LastTabItemIdx]; + if (!(tab->Flags & ImGuiTabItemFlags_NoPushId)) + window->IDStack.pop_back(); +} + +bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, ImGuiTabItemFlags flags, ImGuiWindow* docked_window) +{ + // Layout whole tab bar if not already done + if (tab_bar->WantLayout) + TabBarLayout(tab_bar); + + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if (window->SkipItems) + return false; + + const ImGuiStyle& style = g.Style; + const ImGuiID id = TabBarCalcTabID(tab_bar, label); + + // If the user called us with *p_open == false, we early out and don't render. We make a dummy call to ItemAdd() so that attempts to use a contextual popup menu with an implicit ID won't use an older ID. + IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.LastItemStatusFlags); + if (p_open && !*p_open) + { + PushItemFlag(ImGuiItemFlags_NoNav | ImGuiItemFlags_NoNavDefaultFocus, true); + ItemAdd(ImRect(), id); + PopItemFlag(); + return false; + } + + // Store into ImGuiTabItemFlags_NoCloseButton, also honor ImGuiTabItemFlags_NoCloseButton passed by user (although not documented) + if (flags & ImGuiTabItemFlags_NoCloseButton) + p_open = NULL; + else if (p_open == NULL) + flags |= ImGuiTabItemFlags_NoCloseButton; + + // Calculate tab contents size + ImVec2 size = TabItemCalcSize(label, p_open != NULL); + + // Acquire tab data + ImGuiTabItem* tab = TabBarFindTabByID(tab_bar, id); + bool tab_is_new = false; + if (tab == NULL) + { + tab_bar->Tabs.push_back(ImGuiTabItem()); + tab = &tab_bar->Tabs.back(); + tab->ID = id; + tab->Width = size.x; + tab_is_new = true; + } + tab_bar->LastTabItemIdx = (short)tab_bar->Tabs.index_from_ptr(tab); + tab->ContentWidth = size.x; + + const bool tab_bar_appearing = (tab_bar->PrevFrameVisible + 1 < g.FrameCount); + const bool tab_bar_focused = (tab_bar->Flags & ImGuiTabBarFlags_IsFocused) != 0; + const bool tab_appearing = (tab->LastFrameVisible + 1 < g.FrameCount); + tab->LastFrameVisible = g.FrameCount; + tab->Flags = flags; + tab->Window = docked_window; + + // Append name with zero-terminator + if (tab_bar->Flags & ImGuiTabBarFlags_DockNode) + { + IM_ASSERT(tab->Window != NULL); + tab->NameOffset = -1; + } + else + { + IM_ASSERT(tab->Window == NULL); + tab->NameOffset = tab_bar->TabsNames.size(); + tab_bar->TabsNames.append(label, label + strlen(label) + 1); // Append name _with_ the zero-terminator. + } + + // If we are not reorderable, always reset offset based on submission order. + // (We already handled layout and sizing using the previous known order, but sizing is not affected by order!) + if (!tab_appearing && !(tab_bar->Flags & ImGuiTabBarFlags_Reorderable)) + { + tab->Offset = tab_bar->OffsetNextTab; + tab_bar->OffsetNextTab += tab->Width + g.Style.ItemInnerSpacing.x; + } + + // Update selected tab + if (tab_appearing && (tab_bar->Flags & ImGuiTabBarFlags_AutoSelectNewTabs) && tab_bar->NextSelectedTabId == 0) + if (!tab_bar_appearing || tab_bar->SelectedTabId == 0) + tab_bar->NextSelectedTabId = id; // New tabs gets activated + if ((flags & ImGuiTabItemFlags_SetSelected) && (tab_bar->SelectedTabId != id)) // SetSelected can only be passed on explicit tab bar + tab_bar->NextSelectedTabId = id; + + // Lock visibility + // (Note: tab_contents_visible != tab_selected... because CTRL+TAB operations may preview some tabs without selecting them!) + bool tab_contents_visible = (tab_bar->VisibleTabId == id); + if (tab_contents_visible) + tab_bar->VisibleTabWasSubmitted = true; + + // On the very first frame of a tab bar we let first tab contents be visible to minimize appearing glitches + if (!tab_contents_visible && tab_bar->SelectedTabId == 0 && tab_bar_appearing && docked_window == NULL) + if (tab_bar->Tabs.Size == 1 && !(tab_bar->Flags & ImGuiTabBarFlags_AutoSelectNewTabs)) + tab_contents_visible = true; + + if (tab_appearing && !(tab_bar_appearing && !tab_is_new)) + { + PushItemFlag(ImGuiItemFlags_NoNav | ImGuiItemFlags_NoNavDefaultFocus, true); + ItemAdd(ImRect(), id); + PopItemFlag(); + return tab_contents_visible; + } + + if (tab_bar->SelectedTabId == id) + tab->LastFrameSelected = g.FrameCount; + + // Backup current layout position + const ImVec2 backup_main_cursor_pos = window->DC.CursorPos; + + // Layout + size.x = tab->Width; + window->DC.CursorPos = tab_bar->BarRect.Min + ImVec2(IM_FLOOR(tab->Offset - tab_bar->ScrollingAnim), 0.0f); + ImVec2 pos = window->DC.CursorPos; + ImRect bb(pos, pos + size); + + // We don't have CPU clipping primitives to clip the CloseButton (until it becomes a texture), so need to add an extra draw call (temporary in the case of vertical animation) + bool want_clip_rect = (bb.Min.x < tab_bar->BarRect.Min.x) || (bb.Max.x > tab_bar->BarRect.Max.x); + if (want_clip_rect) + PushClipRect(ImVec2(ImMax(bb.Min.x, tab_bar->BarRect.Min.x), bb.Min.y - 1), ImVec2(tab_bar->BarRect.Max.x, bb.Max.y), true); + + ImVec2 backup_cursor_max_pos = window->DC.CursorMaxPos; + ItemSize(bb.GetSize(), style.FramePadding.y); + window->DC.CursorMaxPos = backup_cursor_max_pos; + + if (!ItemAdd(bb, id)) + { + if (want_clip_rect) + PopClipRect(); + window->DC.CursorPos = backup_main_cursor_pos; + return tab_contents_visible; + } + + // Click to Select a tab + ImGuiButtonFlags button_flags = (ImGuiButtonFlags_PressedOnClick | ImGuiButtonFlags_AllowItemOverlap); + if (g.DragDropActive && !g.DragDropPayload.IsDataType(IMGUI_PAYLOAD_TYPE_WINDOW)) + button_flags |= ImGuiButtonFlags_PressedOnDragDropHold; + bool hovered, held; + bool pressed = ButtonBehavior(bb, id, &hovered, &held, button_flags); + if (pressed) + tab_bar->NextSelectedTabId = id; + hovered |= (g.HoveredId == id); + + // Transfer active id window so the active id is not owned by the dock host (as StartMouseMovingWindow() + // will only do it on the drag). This allows FocusWindow() to be more conservative in how it clears active id. + if (held && docked_window && g.ActiveId == id && g.ActiveIdIsJustActivated) + g.ActiveIdWindow = docked_window; + + // Allow the close button to overlap unless we are dragging (in which case we don't want any overlapping tabs to be hovered) + if (!held) + SetItemAllowOverlap(); + + // Drag and drop a single floating window node moves it + ImGuiDockNode* node = docked_window ? docked_window->DockNode : NULL; + const bool single_floating_window_node = node && node->IsFloatingNode() && (node->Windows.Size == 1); + if (held && single_floating_window_node && IsMouseDragging(0, 0.0f)) + { + // Move + StartMouseMovingWindow(docked_window); + } + else if (held && !tab_appearing && IsMouseDragging(0)) + { + // Drag and drop: re-order tabs + float drag_distance_from_edge_x = 0.0f; + if (!g.DragDropActive && ((tab_bar->Flags & ImGuiTabBarFlags_Reorderable) || (docked_window != NULL))) + { + // While moving a tab it will jump on the other side of the mouse, so we also test for MouseDelta.x + if (g.IO.MouseDelta.x < 0.0f && g.IO.MousePos.x < bb.Min.x) + { + drag_distance_from_edge_x = bb.Min.x - g.IO.MousePos.x; + if (tab_bar->Flags & ImGuiTabBarFlags_Reorderable) + TabBarQueueChangeTabOrder(tab_bar, tab, -1); + } + else if (g.IO.MouseDelta.x > 0.0f && g.IO.MousePos.x > bb.Max.x) + { + drag_distance_from_edge_x = g.IO.MousePos.x - bb.Max.x; + if (tab_bar->Flags & ImGuiTabBarFlags_Reorderable) + TabBarQueueChangeTabOrder(tab_bar, tab, +1); + } + } + + // Extract a Dockable window out of it's tab bar + if (docked_window != NULL && !(docked_window->Flags & ImGuiWindowFlags_NoMove)) + { + // We use a variable threshold to distinguish dragging tabs within a tab bar and extracting them out of the tab bar + bool undocking_tab = (g.DragDropActive && g.DragDropPayload.SourceId == id); + + if (!undocking_tab) //&& (!g.IO.ConfigDockingWithShift || g.IO.KeyShift) + { + float threshold_base = g.FontSize; + //float threshold_base = g.IO.ConfigDockingWithShift ? g.FontSize * 0.5f : g.FontSize; + float threshold_x = (threshold_base * 2.2f); + float threshold_y = (threshold_base * 1.5f) + ImClamp((ImFabs(g.IO.MouseDragMaxDistanceAbs[0].x) - threshold_base * 2.0f) * 0.20f, 0.0f, threshold_base * 4.0f); + //GetForegroundDrawList()->AddRect(ImVec2(bb.Min.x - threshold_x, bb.Min.y - threshold_y), ImVec2(bb.Max.x + threshold_x, bb.Max.y + threshold_y), IM_COL32_WHITE); // [DEBUG] + + float distance_from_edge_y = ImMax(bb.Min.y - g.IO.MousePos.y, g.IO.MousePos.y - bb.Max.y); + if (distance_from_edge_y >= threshold_y) + undocking_tab = true; + else if (drag_distance_from_edge_x > threshold_x) + if ((tab_bar->ReorderRequestDir < 0 && tab_bar->GetTabOrder(tab) == 0) || (tab_bar->ReorderRequestDir > 0 && tab_bar->GetTabOrder(tab) == tab_bar->Tabs.Size - 1)) + undocking_tab = true; + } + + if (undocking_tab) + { + // Undock + DockContextQueueUndockWindow(&g, docked_window); + g.MovingWindow = docked_window; + g.ActiveId = g.MovingWindow->MoveId; + g.ActiveIdClickOffset -= g.MovingWindow->Pos - bb.Min; + } + } + } + +#if 0 + if (hovered && g.HoveredIdNotActiveTimer > 0.50f && bb.GetWidth() < tab->ContentWidth) + { + // Enlarge tab display when hovering + bb.Max.x = bb.Min.x + IM_FLOOR(ImLerp(bb.GetWidth(), tab->ContentWidth, ImSaturate((g.HoveredIdNotActiveTimer - 0.40f) * 6.0f))); + display_draw_list = GetForegroundDrawList(window); + TabItemBackground(display_draw_list, bb, flags, GetColorU32(ImGuiCol_TitleBgActive)); + } +#endif + + // Render tab shape + ImDrawList* display_draw_list = window->DrawList; + const ImU32 tab_col = GetColorU32((held || hovered) ? ImGuiCol_TabHovered : tab_contents_visible ? (tab_bar_focused ? ImGuiCol_TabActive : ImGuiCol_TabUnfocusedActive) : (tab_bar_focused ? ImGuiCol_Tab : ImGuiCol_TabUnfocused)); + TabItemBackground(display_draw_list, bb, flags, tab_col); + RenderNavHighlight(bb, id); + + // Select with right mouse button. This is so the common idiom for context menu automatically highlight the current widget. + const bool hovered_unblocked = IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup); + if (hovered_unblocked && (IsMouseClicked(1) || IsMouseReleased(1))) + tab_bar->NextSelectedTabId = id; + + if (tab_bar->Flags & ImGuiTabBarFlags_NoCloseWithMiddleMouseButton) + flags |= ImGuiTabItemFlags_NoCloseWithMiddleMouseButton; + + // Render tab label, process close button + const ImGuiID close_button_id = p_open ? window->GetID((void*)((intptr_t)id + 1)) : 0; + bool just_closed = TabItemLabelAndCloseButton(display_draw_list, bb, flags, tab_bar->FramePadding, label, id, close_button_id, tab_contents_visible); + if (just_closed && p_open != NULL) + { + *p_open = false; + TabBarCloseTab(tab_bar, tab); + } + + // Restore main window position so user can draw there + if (want_clip_rect) + PopClipRect(); + window->DC.CursorPos = backup_main_cursor_pos; + + // Tooltip (FIXME: Won't work over the close button because ItemOverlap systems messes up with HoveredIdTimer) + // We test IsItemHovered() to discard e.g. when another item is active or drag and drop over the tab bar (which g.HoveredId ignores) + if (g.HoveredId == id && !held && g.HoveredIdNotActiveTimer > 0.50f && IsItemHovered()) + if (!(tab_bar->Flags & ImGuiTabBarFlags_NoTooltip)) + SetTooltip("%.*s", (int)(FindRenderedTextEnd(label) - label), label); + + return tab_contents_visible; +} + +// [Public] This is call is 100% optional but it allows to remove some one-frame glitches when a tab has been unexpectedly removed. +// To use it to need to call the function SetTabItemClosed() after BeginTabBar() and before any call to BeginTabItem() +void ImGui::SetTabItemClosed(const char* label) +{ + ImGuiContext& g = *GImGui; + bool is_within_manual_tab_bar = g.CurrentTabBar && !(g.CurrentTabBar->Flags & ImGuiTabBarFlags_DockNode); + if (is_within_manual_tab_bar) + { + ImGuiTabBar* tab_bar = g.CurrentTabBar; + IM_ASSERT(tab_bar->WantLayout); // Needs to be called AFTER BeginTabBar() and BEFORE the first call to BeginTabItem() + ImGuiID tab_id = TabBarCalcTabID(tab_bar, label); + TabBarRemoveTab(tab_bar, tab_id); + } + else if (ImGuiWindow* window = FindWindowByName(label)) + { + if (window->DockIsActive) + if (ImGuiDockNode* node = window->DockNode) + { + ImGuiID tab_id = TabBarCalcTabID(node->TabBar, label); + TabBarRemoveTab(node->TabBar, tab_id); + window->DockTabWantClose = true; + } + } +} + +ImVec2 ImGui::TabItemCalcSize(const char* label, bool has_close_button) +{ + ImGuiContext& g = *GImGui; + ImVec2 label_size = CalcTextSize(label, NULL, true); + ImVec2 size = ImVec2(label_size.x + g.Style.FramePadding.x, label_size.y + g.Style.FramePadding.y * 2.0f); + if (has_close_button) + size.x += g.Style.FramePadding.x + (g.Style.ItemInnerSpacing.x + g.FontSize); // We use Y intentionally to fit the close button circle. + else + size.x += g.Style.FramePadding.x + 1.0f; + return ImVec2(ImMin(size.x, TabBarCalcMaxTabWidth()), size.y); +} + +void ImGui::TabItemBackground(ImDrawList* draw_list, const ImRect& bb, ImGuiTabItemFlags flags, ImU32 col) +{ + // While rendering tabs, we trim 1 pixel off the top of our bounding box so they can fit within a regular frame height while looking "detached" from it. + ImGuiContext& g = *GImGui; + const float width = bb.GetWidth(); + IM_UNUSED(flags); + IM_ASSERT(width > 0.0f); + const float rounding = ImMax(0.0f, ImMin(g.Style.TabRounding, width * 0.5f - 1.0f)); + const float y1 = bb.Min.y + 1.0f; + const float y2 = bb.Max.y + ((flags & ImGuiTabItemFlags_Preview) ? 0.0f : -1.0f); + draw_list->PathLineTo(ImVec2(bb.Min.x, y2)); + draw_list->PathArcToFast(ImVec2(bb.Min.x + rounding, y1 + rounding), rounding, 6, 9); + draw_list->PathArcToFast(ImVec2(bb.Max.x - rounding, y1 + rounding), rounding, 9, 12); + draw_list->PathLineTo(ImVec2(bb.Max.x, y2)); + draw_list->PathFillConvex(col); + if (g.Style.TabBorderSize > 0.0f) + { + draw_list->PathLineTo(ImVec2(bb.Min.x + 0.5f, y2)); + draw_list->PathArcToFast(ImVec2(bb.Min.x + rounding + 0.5f, y1 + rounding + 0.5f), rounding, 6, 9); + draw_list->PathArcToFast(ImVec2(bb.Max.x - rounding - 0.5f, y1 + rounding + 0.5f), rounding, 9, 12); + draw_list->PathLineTo(ImVec2(bb.Max.x - 0.5f, y2)); + draw_list->PathStroke(GetColorU32(ImGuiCol_Border), false, g.Style.TabBorderSize); + } +} + +// Render text label (with custom clipping) + Unsaved Document marker + Close Button logic +// We tend to lock style.FramePadding for a given tab-bar, hence the 'frame_padding' parameter. +bool ImGui::TabItemLabelAndCloseButton(ImDrawList* draw_list, const ImRect& bb, ImGuiTabItemFlags flags, ImVec2 frame_padding, const char* label, ImGuiID tab_id, ImGuiID close_button_id, bool is_contents_visible) +{ + ImGuiContext& g = *GImGui; + ImVec2 label_size = CalcTextSize(label, NULL, true); + if (bb.GetWidth() <= 1.0f) + return false; + + // In Style V2 we'll have full override of all colors per state (e.g. focused, selected) + // But right now if you want to alter text color of tabs this is what you need to do. +#if 0 + const float backup_alpha = g.Style.Alpha; + if (!is_contents_visible) + g.Style.Alpha *= 0.7f; +#endif + + // Render text label (with clipping + alpha gradient) + unsaved marker + const char* TAB_UNSAVED_MARKER = "*"; + ImRect text_pixel_clip_bb(bb.Min.x + frame_padding.x, bb.Min.y + frame_padding.y, bb.Max.x - frame_padding.x, bb.Max.y); + if (flags & ImGuiTabItemFlags_UnsavedDocument) + { + text_pixel_clip_bb.Max.x -= CalcTextSize(TAB_UNSAVED_MARKER, NULL, false).x; + ImVec2 unsaved_marker_pos(ImMin(bb.Min.x + frame_padding.x + label_size.x + 2, text_pixel_clip_bb.Max.x), bb.Min.y + frame_padding.y + IM_FLOOR(-g.FontSize * 0.25f)); + RenderTextClippedEx(draw_list, unsaved_marker_pos, bb.Max - frame_padding, TAB_UNSAVED_MARKER, NULL, NULL); + } + ImRect text_ellipsis_clip_bb = text_pixel_clip_bb; + + // Close Button + // We are relying on a subtle and confusing distinction between 'hovered' and 'g.HoveredId' which happens because we are using ImGuiButtonFlags_AllowOverlapMode + SetItemAllowOverlap() + // 'hovered' will be true when hovering the Tab but NOT when hovering the close button + // 'g.HoveredId==id' will be true when hovering the Tab including when hovering the close button + // 'g.ActiveId==close_button_id' will be true when we are holding on the close button, in which case both hovered booleans are false + bool close_button_pressed = false; + bool close_button_visible = false; + if (close_button_id != 0) + if (is_contents_visible || bb.GetWidth() >= g.Style.TabMinWidthForUnselectedCloseButton) + if (g.HoveredId == tab_id || g.HoveredId == close_button_id || g.ActiveId == close_button_id) + close_button_visible = true; + if (close_button_visible) + { + ImGuiItemHoveredDataBackup last_item_backup; + const float close_button_sz = g.FontSize; + PushStyleVar(ImGuiStyleVar_FramePadding, frame_padding); + if (CloseButton(close_button_id, ImVec2(bb.Max.x - frame_padding.x * 2.0f - close_button_sz, bb.Min.y))) + close_button_pressed = true; + PopStyleVar(); + last_item_backup.Restore(); + + // Close with middle mouse button + if (!(flags & ImGuiTabItemFlags_NoCloseWithMiddleMouseButton) && IsMouseClicked(2)) + close_button_pressed = true; + + text_pixel_clip_bb.Max.x -= close_button_sz; + } + + float ellipsis_max_x = close_button_visible ? text_pixel_clip_bb.Max.x : bb.Max.x - 1.0f; + RenderTextEllipsis(draw_list, text_ellipsis_clip_bb.Min, text_ellipsis_clip_bb.Max, text_pixel_clip_bb.Max.x, ellipsis_max_x, label, NULL, &label_size); + +#if 0 + if (!is_contents_visible) + g.Style.Alpha = backup_alpha; +#endif + + return close_button_pressed; +} + + +//------------------------------------------------------------------------- +// [SECTION] Widgets: Columns, BeginColumns, EndColumns, etc. +// In the current version, Columns are very weak. Needs to be replaced with a more full-featured system. +//------------------------------------------------------------------------- +// - GetColumnIndex() +// - GetColumnCount() +// - GetColumnOffset() +// - GetColumnWidth() +// - SetColumnOffset() +// - SetColumnWidth() +// - PushColumnClipRect() [Internal] +// - PushColumnsBackground() [Internal] +// - PopColumnsBackground() [Internal] +// - FindOrCreateColumns() [Internal] +// - GetColumnsID() [Internal] +// - BeginColumns() +// - NextColumn() +// - EndColumns() +// - Columns() +//------------------------------------------------------------------------- + +int ImGui::GetColumnIndex() +{ + ImGuiWindow* window = GetCurrentWindowRead(); + return window->DC.CurrentColumns ? window->DC.CurrentColumns->Current : 0; +} + +int ImGui::GetColumnsCount() +{ + ImGuiWindow* window = GetCurrentWindowRead(); + return window->DC.CurrentColumns ? window->DC.CurrentColumns->Count : 1; +} + +float ImGui::GetColumnOffsetFromNorm(const ImGuiColumns* columns, float offset_norm) +{ + return offset_norm * (columns->OffMaxX - columns->OffMinX); +} + +float ImGui::GetColumnNormFromOffset(const ImGuiColumns* columns, float offset) +{ + return offset / (columns->OffMaxX - columns->OffMinX); +} + +static const float COLUMNS_HIT_RECT_HALF_WIDTH = 4.0f; + +static float GetDraggedColumnOffset(ImGuiColumns* columns, int column_index) +{ + // Active (dragged) column always follow mouse. The reason we need this is that dragging a column to the right edge of an auto-resizing + // window creates a feedback loop because we store normalized positions. So while dragging we enforce absolute positioning. + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + IM_ASSERT(column_index > 0); // We are not supposed to drag column 0. + IM_ASSERT(g.ActiveId == columns->ID + ImGuiID(column_index)); + + float x = g.IO.MousePos.x - g.ActiveIdClickOffset.x + COLUMNS_HIT_RECT_HALF_WIDTH - window->Pos.x; + x = ImMax(x, ImGui::GetColumnOffset(column_index - 1) + g.Style.ColumnsMinSpacing); + if ((columns->Flags & ImGuiColumnsFlags_NoPreserveWidths)) + x = ImMin(x, ImGui::GetColumnOffset(column_index + 1) - g.Style.ColumnsMinSpacing); + + return x; +} + +float ImGui::GetColumnOffset(int column_index) +{ + ImGuiWindow* window = GetCurrentWindowRead(); + ImGuiColumns* columns = window->DC.CurrentColumns; + if (columns == NULL) + return 0.0f; + + if (column_index < 0) + column_index = columns->Current; + IM_ASSERT(column_index < columns->Columns.Size); + + const float t = columns->Columns[column_index].OffsetNorm; + const float x_offset = ImLerp(columns->OffMinX, columns->OffMaxX, t); + return x_offset; +} + +static float GetColumnWidthEx(ImGuiColumns* columns, int column_index, bool before_resize = false) +{ + if (column_index < 0) + column_index = columns->Current; + + float offset_norm; + if (before_resize) + offset_norm = columns->Columns[column_index + 1].OffsetNormBeforeResize - columns->Columns[column_index].OffsetNormBeforeResize; + else + offset_norm = columns->Columns[column_index + 1].OffsetNorm - columns->Columns[column_index].OffsetNorm; + return ImGui::GetColumnOffsetFromNorm(columns, offset_norm); +} + +float ImGui::GetColumnWidth(int column_index) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + ImGuiColumns* columns = window->DC.CurrentColumns; + if (columns == NULL) + return GetContentRegionAvail().x; + + if (column_index < 0) + column_index = columns->Current; + return GetColumnOffsetFromNorm(columns, columns->Columns[column_index + 1].OffsetNorm - columns->Columns[column_index].OffsetNorm); +} + +void ImGui::SetColumnOffset(int column_index, float offset) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + ImGuiColumns* columns = window->DC.CurrentColumns; + IM_ASSERT(columns != NULL); + + if (column_index < 0) + column_index = columns->Current; + IM_ASSERT(column_index < columns->Columns.Size); + + const bool preserve_width = !(columns->Flags & ImGuiColumnsFlags_NoPreserveWidths) && (column_index < columns->Count-1); + const float width = preserve_width ? GetColumnWidthEx(columns, column_index, columns->IsBeingResized) : 0.0f; + + if (!(columns->Flags & ImGuiColumnsFlags_NoForceWithinWindow)) + offset = ImMin(offset, columns->OffMaxX - g.Style.ColumnsMinSpacing * (columns->Count - column_index)); + columns->Columns[column_index].OffsetNorm = GetColumnNormFromOffset(columns, offset - columns->OffMinX); + + if (preserve_width) + SetColumnOffset(column_index + 1, offset + ImMax(g.Style.ColumnsMinSpacing, width)); +} + +void ImGui::SetColumnWidth(int column_index, float width) +{ + ImGuiWindow* window = GetCurrentWindowRead(); + ImGuiColumns* columns = window->DC.CurrentColumns; + IM_ASSERT(columns != NULL); + + if (column_index < 0) + column_index = columns->Current; + SetColumnOffset(column_index + 1, GetColumnOffset(column_index) + width); +} + +void ImGui::PushColumnClipRect(int column_index) +{ + ImGuiWindow* window = GetCurrentWindowRead(); + ImGuiColumns* columns = window->DC.CurrentColumns; + if (column_index < 0) + column_index = columns->Current; + + ImGuiColumnData* column = &columns->Columns[column_index]; + PushClipRect(column->ClipRect.Min, column->ClipRect.Max, false); +} + +// Get into the columns background draw command (which is generally the same draw command as before we called BeginColumns) +void ImGui::PushColumnsBackground() +{ + ImGuiWindow* window = GetCurrentWindowRead(); + ImGuiColumns* columns = window->DC.CurrentColumns; + if (columns->Count == 1) + return; + columns->Splitter.SetCurrentChannel(window->DrawList, 0); + int cmd_size = window->DrawList->CmdBuffer.Size; + PushClipRect(columns->HostClipRect.Min, columns->HostClipRect.Max, false); + IM_UNUSED(cmd_size); + IM_ASSERT(cmd_size == window->DrawList->CmdBuffer.Size); // Being in channel 0 this should not have created an ImDrawCmd +} + +void ImGui::PopColumnsBackground() +{ + ImGuiWindow* window = GetCurrentWindowRead(); + ImGuiColumns* columns = window->DC.CurrentColumns; + if (columns->Count == 1) + return; + columns->Splitter.SetCurrentChannel(window->DrawList, columns->Current + 1); + PopClipRect(); +} + +ImGuiColumns* ImGui::FindOrCreateColumns(ImGuiWindow* window, ImGuiID id) +{ + // We have few columns per window so for now we don't need bother much with turning this into a faster lookup. + for (int n = 0; n < window->ColumnsStorage.Size; n++) + if (window->ColumnsStorage[n].ID == id) + return &window->ColumnsStorage[n]; + + window->ColumnsStorage.push_back(ImGuiColumns()); + ImGuiColumns* columns = &window->ColumnsStorage.back(); + columns->ID = id; + return columns; +} + +ImGuiID ImGui::GetColumnsID(const char* str_id, int columns_count) +{ + ImGuiWindow* window = GetCurrentWindow(); + + // Differentiate column ID with an arbitrary prefix for cases where users name their columns set the same as another widget. + // In addition, when an identifier isn't explicitly provided we include the number of columns in the hash to make it uniquer. + PushID(0x11223347 + (str_id ? 0 : columns_count)); + ImGuiID id = window->GetID(str_id ? str_id : "columns"); + PopID(); + + return id; +} + +void ImGui::BeginColumns(const char* str_id, int columns_count, ImGuiColumnsFlags flags) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = GetCurrentWindow(); + + IM_ASSERT(columns_count >= 1); + IM_ASSERT(window->DC.CurrentColumns == NULL); // Nested columns are currently not supported + + // Acquire storage for the columns set + ImGuiID id = GetColumnsID(str_id, columns_count); + ImGuiColumns* columns = FindOrCreateColumns(window, id); + IM_ASSERT(columns->ID == id); + columns->Current = 0; + columns->Count = columns_count; + columns->Flags = flags; + window->DC.CurrentColumns = columns; + + columns->HostCursorPosY = window->DC.CursorPos.y; + columns->HostCursorMaxPosX = window->DC.CursorMaxPos.x; + columns->HostClipRect = window->ClipRect; + columns->HostWorkRect = window->WorkRect; + + // Set state for first column + // We aim so that the right-most column will have the same clipping width as other after being clipped by parent ClipRect + const float column_padding = g.Style.ItemSpacing.x; + const float half_clip_extend_x = ImFloor(ImMax(window->WindowPadding.x * 0.5f, window->WindowBorderSize)); + const float max_1 = window->WorkRect.Max.x + column_padding - ImMax(column_padding - window->WindowPadding.x, 0.0f); + const float max_2 = window->WorkRect.Max.x + half_clip_extend_x; + columns->OffMinX = window->DC.Indent.x - column_padding + ImMax(column_padding - window->WindowPadding.x, 0.0f); + columns->OffMaxX = ImMax(ImMin(max_1, max_2) - window->Pos.x, columns->OffMinX + 1.0f); + columns->LineMinY = columns->LineMaxY = window->DC.CursorPos.y; + + // Clear data if columns count changed + if (columns->Columns.Size != 0 && columns->Columns.Size != columns_count + 1) + columns->Columns.resize(0); + + // Initialize default widths + columns->IsFirstFrame = (columns->Columns.Size == 0); + if (columns->Columns.Size == 0) + { + columns->Columns.reserve(columns_count + 1); + for (int n = 0; n < columns_count + 1; n++) + { + ImGuiColumnData column; + column.OffsetNorm = n / (float)columns_count; + columns->Columns.push_back(column); + } + } + + for (int n = 0; n < columns_count; n++) + { + // Compute clipping rectangle + ImGuiColumnData* column = &columns->Columns[n]; + float clip_x1 = IM_ROUND(window->Pos.x + GetColumnOffset(n)); + float clip_x2 = IM_ROUND(window->Pos.x + GetColumnOffset(n + 1) - 1.0f); + column->ClipRect = ImRect(clip_x1, -FLT_MAX, clip_x2, +FLT_MAX); + column->ClipRect.ClipWith(window->ClipRect); + } + + if (columns->Count > 1) + { + columns->Splitter.Split(window->DrawList, 1 + columns->Count); + columns->Splitter.SetCurrentChannel(window->DrawList, 1); + PushColumnClipRect(0); + } + + // We don't generally store Indent.x inside ColumnsOffset because it may be manipulated by the user. + float offset_0 = GetColumnOffset(columns->Current); + float offset_1 = GetColumnOffset(columns->Current + 1); + float width = offset_1 - offset_0; + PushItemWidth(width * 0.65f); + window->DC.ColumnsOffset.x = ImMax(column_padding - window->WindowPadding.x, 0.0f); + window->DC.CursorPos.x = IM_FLOOR(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x); + window->WorkRect.Max.x = window->Pos.x + offset_1 - column_padding; +} + +void ImGui::NextColumn() +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems || window->DC.CurrentColumns == NULL) + return; + + ImGuiContext& g = *GImGui; + ImGuiColumns* columns = window->DC.CurrentColumns; + + if (columns->Count == 1) + { + window->DC.CursorPos.x = IM_FLOOR(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x); + IM_ASSERT(columns->Current == 0); + return; + } + PopItemWidth(); + PopClipRect(); + + const float column_padding = g.Style.ItemSpacing.x; + columns->LineMaxY = ImMax(columns->LineMaxY, window->DC.CursorPos.y); + if (++columns->Current < columns->Count) + { + // Columns 1+ ignore IndentX (by canceling it out) + // FIXME-COLUMNS: Unnecessary, could be locked? + window->DC.ColumnsOffset.x = GetColumnOffset(columns->Current) - window->DC.Indent.x + column_padding; + columns->Splitter.SetCurrentChannel(window->DrawList, columns->Current + 1); + } + else + { + // New row/line + // Column 0 honor IndentX + window->DC.ColumnsOffset.x = ImMax(column_padding - window->WindowPadding.x, 0.0f); + columns->Splitter.SetCurrentChannel(window->DrawList, 1); + columns->Current = 0; + columns->LineMinY = columns->LineMaxY; + } + window->DC.CursorPos.x = IM_FLOOR(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x); + window->DC.CursorPos.y = columns->LineMinY; + window->DC.CurrLineSize = ImVec2(0.0f, 0.0f); + window->DC.CurrLineTextBaseOffset = 0.0f; + + PushColumnClipRect(columns->Current); // FIXME-COLUMNS: Could it be an overwrite? + + // FIXME-COLUMNS: Share code with BeginColumns() - move code on columns setup. + float offset_0 = GetColumnOffset(columns->Current); + float offset_1 = GetColumnOffset(columns->Current + 1); + float width = offset_1 - offset_0; + PushItemWidth(width * 0.65f); + window->WorkRect.Max.x = window->Pos.x + offset_1 - column_padding; +} + +void ImGui::EndColumns() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = GetCurrentWindow(); + ImGuiColumns* columns = window->DC.CurrentColumns; + IM_ASSERT(columns != NULL); + + PopItemWidth(); + if (columns->Count > 1) + { + PopClipRect(); + columns->Splitter.Merge(window->DrawList); + } + + const ImGuiColumnsFlags flags = columns->Flags; + columns->LineMaxY = ImMax(columns->LineMaxY, window->DC.CursorPos.y); + window->DC.CursorPos.y = columns->LineMaxY; + if (!(flags & ImGuiColumnsFlags_GrowParentContentsSize)) + window->DC.CursorMaxPos.x = columns->HostCursorMaxPosX; // Restore cursor max pos, as columns don't grow parent + + // Draw columns borders and handle resize + // The IsBeingResized flag ensure we preserve pre-resize columns width so back-and-forth are not lossy + bool is_being_resized = false; + if (!(flags & ImGuiColumnsFlags_NoBorder) && !window->SkipItems) + { + // We clip Y boundaries CPU side because very long triangles are mishandled by some GPU drivers. + const float y1 = ImMax(columns->HostCursorPosY, window->ClipRect.Min.y); + const float y2 = ImMin(window->DC.CursorPos.y, window->ClipRect.Max.y); + int dragging_column = -1; + for (int n = 1; n < columns->Count; n++) + { + ImGuiColumnData* column = &columns->Columns[n]; + float x = window->Pos.x + GetColumnOffset(n); + const ImGuiID column_id = columns->ID + ImGuiID(n); + const float column_hit_hw = COLUMNS_HIT_RECT_HALF_WIDTH; + const ImRect column_hit_rect(ImVec2(x - column_hit_hw, y1), ImVec2(x + column_hit_hw, y2)); + KeepAliveID(column_id); + if (IsClippedEx(column_hit_rect, column_id, false)) + continue; + + bool hovered = false, held = false; + if (!(flags & ImGuiColumnsFlags_NoResize)) + { + ButtonBehavior(column_hit_rect, column_id, &hovered, &held); + if (hovered || held) + g.MouseCursor = ImGuiMouseCursor_ResizeEW; + if (held && !(column->Flags & ImGuiColumnsFlags_NoResize)) + dragging_column = n; + } + + // Draw column + const ImU32 col = GetColorU32(held ? ImGuiCol_SeparatorActive : hovered ? ImGuiCol_SeparatorHovered : ImGuiCol_Separator); + const float xi = IM_FLOOR(x); + window->DrawList->AddLine(ImVec2(xi, y1 + 1.0f), ImVec2(xi, y2), col); + } + + // Apply dragging after drawing the column lines, so our rendered lines are in sync with how items were displayed during the frame. + if (dragging_column != -1) + { + if (!columns->IsBeingResized) + for (int n = 0; n < columns->Count + 1; n++) + columns->Columns[n].OffsetNormBeforeResize = columns->Columns[n].OffsetNorm; + columns->IsBeingResized = is_being_resized = true; + float x = GetDraggedColumnOffset(columns, dragging_column); + SetColumnOffset(dragging_column, x); + } + } + columns->IsBeingResized = is_being_resized; + + window->WorkRect = columns->HostWorkRect; + window->DC.CurrentColumns = NULL; + window->DC.ColumnsOffset.x = 0.0f; + window->DC.CursorPos.x = IM_FLOOR(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x); +} + +// [2018-03: This is currently the only public API, while we are working on making BeginColumns/EndColumns user-facing] +void ImGui::Columns(int columns_count, const char* id, bool border) +{ + ImGuiWindow* window = GetCurrentWindow(); + IM_ASSERT(columns_count >= 1); + + ImGuiColumnsFlags flags = (border ? 0 : ImGuiColumnsFlags_NoBorder); + //flags |= ImGuiColumnsFlags_NoPreserveWidths; // NB: Legacy behavior + ImGuiColumns* columns = window->DC.CurrentColumns; + if (columns != NULL && columns->Count == columns_count && columns->Flags == flags) + return; + + if (columns != NULL) + EndColumns(); + + if (columns_count != 1) + BeginColumns(id, columns_count, flags); +} + +//------------------------------------------------------------------------- + +#endif // #ifndef IMGUI_DISABLE diff --git a/extern/magic_enum/CMakeLists.txt b/extern/magic_enum/CMakeLists.txt new file mode 100755 index 0000000..3cf3032 --- /dev/null +++ b/extern/magic_enum/CMakeLists.txt @@ -0,0 +1,2 @@ +add_library(magic_enum INTERFACE) +target_include_directories(magic_enum INTERFACE include) \ No newline at end of file diff --git a/extern/magic_enum/include/magic_enum.hpp b/extern/magic_enum/include/magic_enum.hpp new file mode 100755 index 0000000..ae49308 --- /dev/null +++ b/extern/magic_enum/include/magic_enum.hpp @@ -0,0 +1,612 @@ +// __ __ _ ______ _____ +// | \/ | (_) | ____| / ____|_ _ +// | \ / | __ _ __ _ _ ___ | |__ _ __ _ _ _ __ ___ | | _| |_ _| |_ +// | |\/| |/ _` |/ _` | |/ __| | __| | '_ \| | | | '_ ` _ \ | | |_ _|_ _| +// | | | | (_| | (_| | | (__ | |____| | | | |_| | | | | | | | |____|_| |_| +// |_| |_|\__,_|\__, |_|\___| |______|_| |_|\__,_|_| |_| |_| \_____| +// __/ | https://github.com/Neargye/magic_enum +// |___/ version 0.6.5 +// +// Licensed under the MIT License . +// SPDX-License-Identifier: MIT +// Copyright (c) 2019 Daniil Goncharov . +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#ifndef NEARGYE_MAGIC_ENUM_HPP +#define NEARGYE_MAGIC_ENUM_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(_MSC_VER) +# pragma warning(push) +# pragma warning(disable : 26495) // Variable 'magic_enum::detail::static_string::chars' is uninitialized. +# pragma warning(disable : 26451) // Arithmetic overflow: 'indexes[static_cast(value) - min_v]' using operator '-' on a 4 byte value and then casting the result to a 8 byte value. +#endif + +// Checks magic_enum compiler compatibility. +#if defined(__clang__) || defined(__GNUC__) && __GNUC__ >= 9 || defined(_MSC_VER) +# undef MAGIC_ENUM_SUPPORTED +# define MAGIC_ENUM_SUPPORTED 1 +#endif + +// Enum value must be greater or equals than MAGIC_ENUM_RANGE_MIN. By default MAGIC_ENUM_RANGE_MIN = -128. +// If need another min range for all enum types by default, redefine the macro MAGIC_ENUM_RANGE_MIN. +#if !defined(MAGIC_ENUM_RANGE_MIN) +# define MAGIC_ENUM_RANGE_MIN -128 +#endif + +// Enum value must be less or equals than MAGIC_ENUM_RANGE_MAX. By default MAGIC_ENUM_RANGE_MAX = 128. +// If need another max range for all enum types by default, redefine the macro MAGIC_ENUM_RANGE_MAX. +#if !defined(MAGIC_ENUM_RANGE_MAX) +# define MAGIC_ENUM_RANGE_MAX 128 +#endif + +namespace magic_enum { + + // Enum value must be in range [MAGIC_ENUM_RANGE_MIN, MAGIC_ENUM_RANGE_MAX]. By default MAGIC_ENUM_RANGE_MIN = -128, MAGIC_ENUM_RANGE_MAX = 128. + // If need another range for all enum types by default, redefine the macro MAGIC_ENUM_RANGE_MIN and MAGIC_ENUM_RANGE_MAX. + // If need another range for specific enum type, add specialization enum_range for necessary enum type. + template + struct enum_range { + static_assert(std::is_enum_v, "magic_enum::enum_range requires enum type."); + inline static constexpr int min = MAGIC_ENUM_RANGE_MIN; + inline static constexpr int max = MAGIC_ENUM_RANGE_MAX; + static_assert(max > min, "magic_enum::enum_range requires max > min."); + }; + + static_assert(MAGIC_ENUM_RANGE_MIN <= 0, "MAGIC_ENUM_RANGE_MIN must be less or equals than 0."); + static_assert(MAGIC_ENUM_RANGE_MIN > (std::numeric_limits::min)(), "MAGIC_ENUM_RANGE_MIN must be greater than INT16_MIN."); + + static_assert(MAGIC_ENUM_RANGE_MAX > 0, "MAGIC_ENUM_RANGE_MAX must be greater than 0."); + static_assert(MAGIC_ENUM_RANGE_MAX < (std::numeric_limits::max)(), "MAGIC_ENUM_RANGE_MAX must be less than INT16_MAX."); + + static_assert(MAGIC_ENUM_RANGE_MAX > MAGIC_ENUM_RANGE_MIN, "MAGIC_ENUM_RANGE_MAX must be greater than MAGIC_ENUM_RANGE_MIN."); + + namespace detail { + + template + struct supported +#if defined(MAGIC_ENUM_SUPPORTED) && MAGIC_ENUM_SUPPORTED || defined(MAGIC_ENUM_NO_CHECK_SUPPORT) + : std::true_type {}; +#else + : std::false_type {}; +#endif + + template + inline constexpr bool is_enum_v = std::is_enum_v && std::is_same_v>; + + template + struct static_string { + constexpr explicit static_string(std::string_view str) noexcept : static_string{str, std::make_index_sequence{}} { + assert(str.size() == N); + } + + constexpr const char* data() const noexcept { return chars.data(); } + + constexpr std::size_t size() const noexcept { return chars.size(); } + + constexpr operator std::string_view() const noexcept { return {data(), size()}; } + + private: + template + constexpr static_string(std::string_view str, std::index_sequence) noexcept : chars{{str[I]...}} {} + + const std::array chars; + }; + + template <> + struct static_string<0> { + constexpr explicit static_string(std::string_view) noexcept {} + + constexpr const char* data() const noexcept { return nullptr; } + + constexpr std::size_t size() const noexcept { return 0; } + + constexpr operator std::string_view() const noexcept { return {}; } + }; + + constexpr std::string_view pretty_name(std::string_view name) noexcept { + for (std::size_t i = name.size(); i > 0; --i) { + if (!((name[i - 1] >= '0' && name[i - 1] <= '9') || + (name[i - 1] >= 'a' && name[i - 1] <= 'z') || + (name[i - 1] >= 'A' && name[i - 1] <= 'Z') || + (name[i - 1] == '_'))) { + name.remove_prefix(i); + break; + } + } + + if (name.size() > 0 && ((name.front() >= 'a' && name.front() <= 'z') || + (name.front() >= 'A' && name.front() <= 'Z') || + (name.front() == '_'))) { + return name; + } + + return {}; // Invalid name. + } + + template + constexpr bool mixed_sign_less(L lhs, R rhs) noexcept { + static_assert(std::is_integral_v && std::is_integral_v, "magic_enum::detail::mixed_sign_less requires integral type."); + + if constexpr (std::is_signed_v && std::is_unsigned_v) { + // If 'left' is negative, then result is 'true', otherwise cast & compare. + return lhs < 0 || static_cast>(lhs) < rhs; + } else if constexpr (std::is_unsigned_v && std::is_signed_v) { + // If 'right' is negative, then result is 'false', otherwise cast & compare. + return rhs >= 0 && lhs < static_cast>(rhs); + } else { + // If same signedness (both signed or both unsigned). + return lhs < rhs; + } + } + + template + constexpr auto n() noexcept { + static_assert(is_enum_v, "magic_enum::detail::n requires enum type."); +#if defined(MAGIC_ENUM_SUPPORTED) && MAGIC_ENUM_SUPPORTED +# if defined(__clang__) + constexpr std::string_view name{__PRETTY_FUNCTION__ + 34, sizeof(__PRETTY_FUNCTION__) - 36}; +# elif defined(__GNUC__) + constexpr std::string_view name{__PRETTY_FUNCTION__ + 49, sizeof(__PRETTY_FUNCTION__) - 51}; +# elif defined(_MSC_VER) + constexpr std::string_view name{__FUNCSIG__ + 40, sizeof(__FUNCSIG__) - 57}; +# endif + return static_string{name}; +#else + static_assert(supported::value, "magic_enum: Unsupported compiler (https://github.com/Neargye/magic_enum#compiler-compatibility)."); + return std::string_view{}; // Unsupported compiler. +#endif + } + + template + inline constexpr auto type_name_v = n(); + + template + constexpr auto n() noexcept { + static_assert(is_enum_v, "magic_enum::detail::n requires enum type."); +#if defined(MAGIC_ENUM_SUPPORTED) && MAGIC_ENUM_SUPPORTED +# if defined(__clang__) || defined(__GNUC__) + constexpr auto name = pretty_name({__PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 2}); +# elif defined(_MSC_VER) + constexpr auto name = pretty_name({__FUNCSIG__, sizeof(__FUNCSIG__) - 17}); +# endif + return static_string{name}; +#else + static_assert(supported::value, "magic_enum: Unsupported compiler (https://github.com/Neargye/magic_enum#compiler-compatibility)."); + return std::string_view{}; // Unsupported compiler. +#endif + } + + template + inline constexpr auto name_v = n(); + + template + constexpr int reflected_min() noexcept { + static_assert(is_enum_v, "magic_enum::detail::reflected_min requires enum type."); + constexpr auto lhs = enum_range::min; + static_assert(lhs > (std::numeric_limits::min)(), "magic_enum::enum_range requires min must be greater than INT16_MIN."); + constexpr auto rhs = (std::numeric_limits>::min)(); + + return mixed_sign_less(lhs, rhs) ? rhs : lhs; + } + + template + constexpr int reflected_max() noexcept { + static_assert(is_enum_v, "magic_enum::detail::reflected_max requires enum type."); + constexpr auto lhs = enum_range::max; + static_assert(lhs < (std::numeric_limits::max)(), "magic_enum::enum_range requires max must be less than INT16_MAX."); + constexpr auto rhs = (std::numeric_limits>::max)(); + + return mixed_sign_less(lhs, rhs) ? lhs : rhs; + } + + template + inline constexpr int reflected_min_v = reflected_min(); + + template + inline constexpr int reflected_max_v = reflected_max(); + + template + constexpr std::size_t reflected_size() noexcept { + static_assert(is_enum_v, "magic_enum::detail::reflected_size requires enum type."); + static_assert(reflected_max_v > reflected_min_v, "magic_enum::enum_range requires max > min."); + constexpr auto size = reflected_max_v - reflected_min_v + 1; + static_assert(size > 0, "magic_enum::enum_range requires valid size."); + static_assert(size < (std::numeric_limits::max)(), "magic_enum::enum_range requires valid size."); + + return static_cast(size); + } + + template + constexpr auto values(std::integer_sequence) noexcept { + static_assert(is_enum_v, "magic_enum::detail::values requires enum type."); + constexpr std::array valid{{(n(I + reflected_min_v)>().size() != 0)...}}; + constexpr int count = ((valid[I] ? 1 : 0) + ...); + + std::array values{}; + for (int i = 0, v = 0; v < count; ++i) { + if (valid[i]) { + values[v++] = static_cast(i + reflected_min_v); + } + } + + return values; + } + + template + inline constexpr auto values_v = values(std::make_integer_sequence()>{}); + + template + inline constexpr std::size_t count_v = values_v.size(); + + template + inline constexpr int min_v = values_v.empty() ? 0 : static_cast(values_v.front()); + + template + inline constexpr int max_v = values_v.empty() ? 0 : static_cast(values_v.back()); + + template + constexpr std::size_t range_size() noexcept { + static_assert(is_enum_v, "magic_enum::detail::range_size requires enum type."); + constexpr auto size = max_v - min_v + 1; + static_assert(size > 0, "magic_enum::enum_range requires valid size."); + static_assert(size < (std::numeric_limits::max)(), "magic_enum::enum_range requires valid size."); + + return static_cast(size); + } + + template + inline constexpr std::size_t range_size_v = range_size(); + + template + using index_t = std::conditional_t < (std::numeric_limits::max)(), std::uint8_t, std::uint16_t>; + + template + inline constexpr auto invalid_index_v = (std::numeric_limits>::max)(); + + template + constexpr auto indexes(std::integer_sequence) noexcept { + static_assert(is_enum_v, "magic_enum::detail::indexes requires enum type."); + index_t i = 0; + + return std::array, sizeof...(I)>{{((n(I + min_v)>().size() != 0) ? i++ : invalid_index_v)...}}; + } + + template + constexpr auto names(std::index_sequence) noexcept { + static_assert(is_enum_v, "magic_enum::detail::names requires enum type."); + + return std::array{{name_v[I]>...}}; + } + + template + constexpr auto entries(std::index_sequence) noexcept { + static_assert(is_enum_v, "magic_enum::detail::entries requires enum type."); + + return std::array, sizeof...(I)>{{{values_v[I], name_v[I]>}...}}; + } + + template + using enable_if_enum_t = std::enable_if_t>, R>; + + template >>> + using enum_concept = T; + + template > + struct is_scoped_enum : std::false_type {}; + + template + struct is_scoped_enum : std::bool_constant>> {}; + + template > + struct is_unscoped_enum : std::false_type {}; + + template + struct is_unscoped_enum : std::bool_constant>> {}; + + template >> + struct underlying_type {}; + + template + struct underlying_type : std::underlying_type> {}; + + template + struct enum_traits {}; + + template + struct enum_traits>> { + using type = E; + using underlying_type = typename detail::underlying_type::type; + + inline static constexpr std::string_view type_name = detail::type_name_v; + + inline static constexpr bool is_unscoped = detail::is_unscoped_enum::value; + inline static constexpr bool is_scoped = detail::is_scoped_enum::value; + inline static constexpr bool is_dense = detail::range_size_v == detail::count_v; + inline static constexpr bool is_sparse = detail::range_size_v != detail::count_v; + + inline static constexpr std::size_t count = detail::count_v; + inline static constexpr std::array values = detail::values_v; + inline static constexpr std::array names = detail::names(std::make_index_sequence>{}); + inline static constexpr std::array, count> entries = detail::entries(std::make_index_sequence>{}); + + [[nodiscard]] static constexpr bool reflected(E value) noexcept { + return static_cast(value) >= static_cast(reflected_min_v) && static_cast(value) <= static_cast(reflected_max_v); + } + + [[nodiscard]] static constexpr int index(E value) noexcept { + if (static_cast(value) >= static_cast(min_v) && static_cast(value) <= static_cast(max_v)) { + if constexpr (is_sparse) { + if (const auto i = indexes[static_cast(value) - min_v]; i != invalid_index_v) { + return i; + } + } else { + return static_cast(value) - min_v; + } + } + + return -1; // Value out of range. + } + + [[nodiscard]] static constexpr E value(std::size_t index) noexcept { + if constexpr (is_sparse) { + return assert(index < count), values[index]; + } else { + return assert(index < count), static_cast(index + min_v); + } + } + + [[nodiscard]] static constexpr std::string_view name(E value) noexcept { + if (const auto i = index(value); i != -1) { + return names[i]; + } + + return {}; // Value out of range. + } + + private: + static_assert(is_enum_v, "magic_enum::enum_traits requires enum type."); + static_assert(count > 0, "magic_enum::enum_range requires enum implementation or valid max and min."); + using U = underlying_type; + inline static constexpr auto indexes = detail::indexes(std::make_integer_sequence>{}); + }; + + } // namespace magic_enum::detail + + // Checks is magic_enum supported compiler. + inline constexpr bool is_magic_enum_supported = detail::supported::value; + + template + using Enum = detail::enum_concept; + + // Checks whether T is an Unscoped enumeration type. + // Provides the member constant value which is equal to true, if T is an [Unscoped enumeration](https://en.cppreference.com/w/cpp/language/enum#Unscoped_enumeration) type. Otherwise, value is equal to false. + template + struct is_unscoped_enum : detail::is_unscoped_enum {}; + + template + inline constexpr bool is_unscoped_enum_v = is_unscoped_enum::value; + + // Checks whether T is an Scoped enumeration type. + // Provides the member constant value which is equal to true, if T is an [Scoped enumeration](https://en.cppreference.com/w/cpp/language/enum#Scoped_enumerations) type. Otherwise, value is equal to false. + template + struct is_scoped_enum : detail::is_scoped_enum {}; + + template + inline constexpr bool is_scoped_enum_v = is_scoped_enum::value; + + // If T is a complete enumeration type, provides a member typedef type that names the underlying type of T. + // Otherwise, if T is not an enumeration type, there is no member type. Otherwise (T is an incomplete enumeration type), the program is ill-formed. + template + struct underlying_type : detail::underlying_type {}; + + template + using underlying_type_t = typename underlying_type::type; + + // Enum traits defines a compile-time template-based interface to query the properties of enum. + template + using enum_traits = detail::enum_traits>; + + // Obtains enum value from enum string name. + // Returns std::optional with enum value. + template + [[nodiscard]] constexpr auto enum_cast(std::string_view value) noexcept -> detail::enable_if_enum_t>> { + using D = std::decay_t; + + if constexpr (detail::range_size_v > detail::count_v * 2) { + for (std::size_t i = 0; i < enum_traits::count; ++i) { + if (value == enum_traits::names[i]) { + return enum_traits::values[i]; + } + } + } else { + for (auto i = detail::min_v; i <= detail::max_v; ++i) { + if (value == enum_traits::name(static_cast(i))) { + return static_cast(i); + } + } + } + + return std::nullopt; // Invalid value or out of range. + } + + // Obtains enum value from integer value. + // Returns std::optional with enum value. + template + [[nodiscard]] constexpr auto enum_cast(underlying_type_t value) noexcept -> detail::enable_if_enum_t>> { + using D = std::decay_t; + + if (enum_traits::index(static_cast(value)) != -1) { + return static_cast(value); + } + + return std::nullopt; // Invalid value or out of range. + } + + // Returns integer value from enum value. + template + [[nodiscard]] constexpr auto enum_integer(E value) noexcept -> detail::enable_if_enum_t> { + return static_cast>(value); + } + + // Obtains index in enum value sequence from enum value. + // Returns std::optional with index. + template + [[nodiscard]] constexpr auto enum_index(E value) noexcept -> detail::enable_if_enum_t> { + if (const auto i = enum_traits::index(value); i != -1) { + return i; + } + + return std::nullopt; // Value out of range. + } + + // Returns enum value at specified index. + // No bounds checking is performed: the behavior is undefined if index >= number of enum values. + template + [[nodiscard]] constexpr auto enum_value(std::size_t index) noexcept -> detail::enable_if_enum_t> { + return enum_traits::value(index); + } + + // Obtains value enum sequence. + // Returns std::array with enum values, sorted by enum value. + template + [[nodiscard]] constexpr auto enum_values() noexcept -> detail::enable_if_enum_t::values)&> { + return enum_traits::values; + } + + // Returns number of enum values. + template + [[nodiscard]] constexpr auto enum_count() noexcept -> detail::enable_if_enum_t { + return enum_traits::count; + } + + // Returns string enum name from static storage enum variable. + // This version is much lighter on the compile times and is not restricted to the enum_range limitation. + template + [[nodiscard]] constexpr auto enum_name() noexcept -> detail::enable_if_enum_t { + constexpr std::string_view name = detail::name_v, V>; + static_assert(name.size() > 0, "Enum value does not have a name."); + + return name; + } + + // Returns string enum name from enum value. + // If enum value does not have name or value out of range, returns empty string. + template + [[nodiscard]] constexpr auto enum_name(E value) noexcept -> detail::enable_if_enum_t { + return enum_traits::name(value); + } + + // Obtains string enum name sequence. + // Returns std::array with string enum names, sorted by enum value. + template + [[nodiscard]] constexpr auto enum_names() noexcept -> detail::enable_if_enum_t::names)&> { + return enum_traits::names; + } + + // Obtains pair (value enum, string enum name) sequence. + // Returns std::array with std::pair (value enum, string enum name), sorted by enum value. + template + [[nodiscard]] constexpr auto enum_entries() noexcept -> detail::enable_if_enum_t::entries)&> { + return enum_traits::entries; + } + + namespace ostream_operators { + + template + auto operator<<(std::basic_ostream& os, E value) -> detail::enable_if_enum_t&> { + if (const auto name = enum_name(value); !name.empty()) { + for (const auto c : name) { + os.put(c); + } + } else { + os << enum_integer(value); + } + + return os; + } + + template + auto operator<<(std::basic_ostream& os, std::optional value) -> detail::enable_if_enum_t&> { + if (value.has_value()) { + os << value.value(); + } + + return os; + } + + } // namespace magic_enum::ostream_operators + + namespace bitwise_operators { + + template + constexpr auto operator~(E rhs) noexcept -> detail::enable_if_enum_t { + return static_cast(~static_cast>(rhs)); + } + + template + constexpr auto operator|(E lhs, E rhs) noexcept -> detail::enable_if_enum_t { + return static_cast(static_cast>(lhs) | static_cast>(rhs)); + } + + template + constexpr auto operator&(E lhs, E rhs) noexcept -> detail::enable_if_enum_t { + return static_cast(static_cast>(lhs) & static_cast>(rhs)); + } + + template + constexpr auto operator^(E lhs, E rhs) noexcept -> detail::enable_if_enum_t { + return static_cast(static_cast>(lhs) ^ static_cast>(rhs)); + } + + template + constexpr auto operator|=(E& lhs, E rhs) noexcept -> detail::enable_if_enum_t { + return lhs = lhs | rhs; + } + + template + constexpr auto operator&=(E& lhs, E rhs) noexcept -> detail::enable_if_enum_t { + return lhs = lhs & rhs; + } + + template + constexpr auto operator^=(E& lhs, E rhs) noexcept -> detail::enable_if_enum_t { + return lhs = lhs ^ rhs; + } + + } // namespace magic_enum::bitwise_operators + +} // namespace magic_enum + +#if defined(_MSC_VER) +# pragma warning(pop) +#endif + +#endif // NEARGYE_MAGIC_ENUM_HPP diff --git a/extern/ogg/.gitignore b/extern/ogg/.gitignore new file mode 100644 index 0000000..1f25663 --- /dev/null +++ b/extern/ogg/.gitignore @@ -0,0 +1,50 @@ +aclocal.m4 +autom4te.cache +ChangeLog +compile +config.guess +config.h +config.h.in +config.h.in~ +config.log +config.status +config.sub +configure +depcomp +install-sh +libogg.spec +libtool +ltmain.sh +Makefile +Makefile.in +missing +mkinstalldirs +ogg.pc +ogg-uninstalled.pc +stamp-h1 +.project +include/ogg/config_types.h +src/*.o +src/*.lo +src/lib*.la +src/.libs +src/.deps +src/test_* +macosx/build/ +/m4 + +CMakeCache.txt +CMakeFiles +CMakeScripts +Testing +Makefile +cmake_install.cmake +install_manifest.txt +compile_commands.json +CTestTestfile.cmake +CMakeSettings.json + +*[Bb]uild*/ + +.vs/ +.vscode/ diff --git a/extern/ogg/.travis.yml b/extern/ogg/.travis.yml new file mode 100644 index 0000000..f7187cb --- /dev/null +++ b/extern/ogg/.travis.yml @@ -0,0 +1,25 @@ +language: c + +os: + - linux + - osx + +compiler: + - gcc + - clang + +env: + - BUILD=AUTOTOOLS + - BUILD=CMAKE + +script: + - if [[ "$BUILD" == "AUTOTOOLS" ]] ; then ./autogen.sh ; fi + - if [[ "$BUILD" == "AUTOTOOLS" ]] ; then ./configure ; fi + - if [[ "$BUILD" == "AUTOTOOLS" ]] ; then make distcheck ; fi + - if [[ "$BUILD" == "CMAKE" ]] ; then mkdir build ; fi + - if [[ "$BUILD" == "CMAKE" ]] ; then pushd build ; fi + - if [[ "$BUILD" == "CMAKE" ]] ; then cmake -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTING=ON -DCPACK_PACKAGE_CONTACT="Xiph.Org Foundation" .. ; fi + - if [[ "$BUILD" == "CMAKE" ]] ; then cmake --build . ; fi + - if [[ "$BUILD" == "CMAKE" ]] ; then ctest ; fi + - if [[ "$BUILD" == "CMAKE" && "$TRAVIS_OS_NAME" == "linux" ]] ; then cpack -G DEB ; fi + - if [[ "$BUILD" == "CMAKE" ]] ; then popd ; fi diff --git a/extern/ogg/AUTHORS b/extern/ogg/AUTHORS new file mode 100644 index 0000000..a0023f2 --- /dev/null +++ b/extern/ogg/AUTHORS @@ -0,0 +1,7 @@ +Monty +Greg Maxwell +Ralph Giles +Cristian Adam +Tim Terriberry + +and the rest of the Xiph.Org Foundation. diff --git a/extern/ogg/CHANGES b/extern/ogg/CHANGES new file mode 100644 index 0000000..855b0b1 --- /dev/null +++ b/extern/ogg/CHANGES @@ -0,0 +1,104 @@ +Version 1.3.4 (2019 August 30) + +* Faster slice-by-8 CRC32 implementation. + see https://lwn.net/Articles/453931/ for motivation. +* Add CMake build. +* Deprecate Visual Studio project files in favor of CMake. +* configure --disable-crc option for fuzzing. +* Various build fixes. +* Documentation and example code fixes. + +Version 1.3.3 (2017 November 7) + + * Fix an issue with corrupt continued packet handling. + * Update Windows projects and build settings. + * Remove Mac OS 9 build support. + +Version 1.3.2 (2014 May 27) + + * Fix an bug in oggpack_writecopy(). + +Version 1.3.1 (2013 May 12) + +* Guard against very large packets. +* Respect the configure --docdir override. +* Documentation fixes. +* More Windows build fixes. + +Version 1.3.0 (2011 August 4) + +* Add ogg_stream_flush_fill() call + This produces longer packets on flush, similar to + what ogg_stream_pageout_fill() does for single pages. +* Windows build fixes + +Version 1.2.2 (2010 December 07) + +* Build fix (types correction) for Mac OS X +* Update win32 project files to Visual Studio 2008 +* ogg_stream_pageout_fill documentation fix + +Version 1.2.1 (2010 November 01) + +* Various build updates (see SVN) +* Add ogg_stream_pageout_fill() to API to allow applications + greater explicit flexibility in page sizing. +* Documentation updates including multiplexing description, + terminology and API (incl. ogg_packet_clear(), + ogg_stream_pageout_fill()) +* Correct possible buffer overwrite in stream encoding on 32 bit + when a single packet exceed 250MB. +* Correct read-buffer overrun [without side effects] under + similar circumstances. +* Update unit testing to work properly with new page spill + heuristic. + +Version 1.2.0 (2010 March 25) + +* Alter default flushing behavior to span less often and use larger page + sizes when packet sizes are large. +* Build fixes for additional compilers +* Documentation updates + +Version 1.1.4 (2009 June 24) + +* New async error reporting mechanism. Calls made after a fatal error are + now safely handled in the event an error code is ignored +* Added allocation checks useful to some embedded applications +* fix possible read past end of buffer when reading 0 bits +* Updates to API documentation +* Build fixes + +Version 1.1.3 (2005 November 27) + + * Correct a bug in the granulepos field of pages where no packet ends + * New VS2003 and XCode builds, minor fixes to other builds + * documentation fixes and cleanup + +Version 1.1.2 (2004 September 23) + + * fix a bug with multipage packet assembly after seek + +Version 1.1.1 (2004 September 12) + + * various bugfixes + * important bugfix for 64-bit platforms + * various portability fixes + * autotools cleanup from Thomas Vander Stichele + * Symbian OS build support from Colin Ward at CSIRO + * new multiplexed Ogg stream documentation + +Version 1.1 (2003 November 17) + + * big-endian bitpacker routines for Theora + * various portability fixes + * improved API documentation + * RFC 3533 documentation of the format by Silvia Pfeiffer at CSIRO + * RFC 3534 documentation of the application/ogg mime-type by Linus Walleij + +Version 1.0 (2002 July 19) + + * First stable release + * little-endian bitpacker routines for Vorbis + * basic Ogg bitstream sync and coding support + diff --git a/extern/ogg/CMakeLists.txt b/extern/ogg/CMakeLists.txt new file mode 100644 index 0000000..62f7576 --- /dev/null +++ b/extern/ogg/CMakeLists.txt @@ -0,0 +1,203 @@ +cmake_minimum_required(VERSION 2.8.12) +project(libogg) + +# Required modules +include(GNUInstallDirs) +include(CheckIncludeFiles) +include(CMakePackageConfigHelpers) +include(CTest) + +# Build options +option(BUILD_SHARED_LIBS "Build shared library" OFF) +if(APPLE) + option(BUILD_FRAMEWORK "Build Framework bundle for OSX" OFF) +endif() + +# Install options +option(INSTALL_DOCS "Install documentation" ON) +option(INSTALL_PKG_CONFIG_MODULE "Install ogg.pc file" ON) +option(INSTALL_CMAKE_PACKAGE_MODULE "Install CMake package configiguration module" ON) + +# Extract project version from configure.ac +file(READ configure.ac CONFIGURE_AC_CONTENTS) +string(REGEX MATCH "AC_INIT\\(\\[libogg\\],\\[([0-9]*).([0-9]*).([0-9]*)" DUMMY ${CONFIGURE_AC_CONTENTS}) +set(PROJECT_VERSION_MAJOR ${CMAKE_MATCH_1}) +set(PROJECT_VERSION_MINOR ${CMAKE_MATCH_2}) +set(PROJECT_VERSION_PATCH ${CMAKE_MATCH_3}) +set(PROJECT_VERSION ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}) + +# Extract library version from configure.ac +string(REGEX MATCH "LIB_CURRENT=([0-9]*)" DUMMY ${CONFIGURE_AC_CONTENTS}) +set(LIB_CURRENT ${CMAKE_MATCH_1}) + +string(REGEX MATCH "LIB_AGE=([0-9]*)" DUMMY ${CONFIGURE_AC_CONTENTS}) +set(LIB_AGE ${CMAKE_MATCH_1}) + +string(REGEX MATCH "LIB_REVISION=([0-9]*)" DUMMY ${CONFIGURE_AC_CONTENTS}) +set(LIB_REVISION ${CMAKE_MATCH_1}) + +math(EXPR LIB_SOVERSION "${LIB_CURRENT} - ${LIB_AGE}") +set(LIB_VERSION "${LIB_SOVERSION}.${LIB_AGE}.${LIB_REVISION}") + + +# Helper function to configure pkg-config files +function(configure_pkg_config_file pkg_config_file_in) + set(prefix ${CMAKE_INSTALL_PREFIX}) + set(exec_prefix ${CMAKE_INSTALL_FULL_BINDIR}) + set(libdir ${CMAKE_INSTALL_FULL_LIBDIR}) + set(includedir ${CMAKE_INSTALL_FULL_INCLUDEDIR}) + set(VERSION ${PROJECT_VERSION}) + string(REPLACE ".in" "" pkg_config_file ${pkg_config_file_in}) + configure_file(${pkg_config_file_in} ${pkg_config_file} @ONLY) +endfunction() + +message(STATUS "Configuring ${PROJECT_NAME} ${PROJECT_VERSION}") + +# Configure config_type.h +check_include_files(inttypes.h INCLUDE_INTTYPES_H) +check_include_files(stdint.h INCLUDE_STDINT_H) +check_include_files(sys/types.h INCLUDE_SYS_TYPES_H) + +list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") +set(SIZE16 int16_t) +set(USIZE16 uint16_t) +set(SIZE32 int32_t) +set(USIZE32 uint32_t) +set(SIZE64 int64_t) +set(USIZE64 uint64_t) + +if(NOT ENABLE_IOS) +include(CheckSizes) +endif() + +configure_file(include/ogg/config_types.h.in include/ogg/config_types.h @ONLY) + +set(OGG_HEADERS + ${CMAKE_CURRENT_BINARY_DIR}/include/ogg/config_types.h + include/ogg/ogg.h + include/ogg/os_types.h +) + +set(OGG_SOURCES + src/bitwise.c + src/framing.c + src/crctable.h +) + +if(WIN32 AND BUILD_SHARED_LIBS) + list(APPEND OGG_SOURCES win32/ogg.def) +endif() + +if(BUILD_FRAMEWORK) + set(BUILD_SHARED_LIBS TRUE) +endif() + +add_library(ogg ${OGG_HEADERS} ${OGG_SOURCES}) +target_include_directories(ogg PUBLIC + $ + $ + $ +) + +set_target_properties( + ogg PROPERTIES + SOVERSION ${LIB_SOVERSION} + VERSION ${LIB_VERSION} + PUBLIC_HEADER "${OGG_HEADERS}" +) + +if(BUILD_FRAMEWORK) + set_target_properties(ogg PROPERTIES + FRAMEWORK TRUE + FRAMEWORK_VERSION ${PROJECT_VERSION} + MACOSX_FRAMEWORK_IDENTIFIER org.xiph.ogg + MACOSX_FRAMEWORK_SHORT_VERSION_STRING ${PROJECT_VERSION} + MACOSX_FRAMEWORK_BUNDLE_VERSION ${PROJECT_VERSION} + XCODE_ATTRIBUTE_INSTALL_PATH "@rpath" + OUTPUT_NAME Ogg + ) +endif() + +configure_pkg_config_file(ogg.pc.in) + +install(TARGETS ogg + EXPORT OggTargets + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + FRAMEWORK DESTINATION ${CMAKE_INSTALL_PREFIX} + PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/ogg +) + +if(INSTALL_CMAKE_PACKAGE_MODULE) + set(CMAKE_INSTALL_CONFIGDIR ${CMAKE_INSTALL_LIBDIR}/cmake/Ogg) + install(EXPORT OggTargets + DESTINATION ${CMAKE_INSTALL_CONFIGDIR} + NAMESPACE Ogg:: + ) + + include(CMakePackageConfigHelpers) + + configure_package_config_file(${PROJECT_SOURCE_DIR}/cmake/OggConfig.cmake.in ${PROJECT_BINARY_DIR}/OggConfig.cmake + INSTALL_DESTINATION ${CMAKE_INSTALL_CONFIGDIR} + PATH_VARS CMAKE_INSTALL_FULL_INCLUDEDIR + ) + + write_basic_package_version_file(${PROJECT_BINARY_DIR}/OggConfigVersion.cmake + VERSION ${PROJECT_VERSION} + COMPATIBILITY SameMajorVersion + ) + + install(FILES ${PROJECT_BINARY_DIR}/OggConfig.cmake ${PROJECT_BINARY_DIR}/OggConfigVersion.cmake + DESTINATION ${CMAKE_INSTALL_CONFIGDIR} + ) +endif() + +if(INSTALL_PKG_CONFIG_MODULE) + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/ogg.pc + DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig + ) +endif() + +if(INSTALL_DOCS) + set(OGG_DOCS + doc/framing.html + doc/index.html + doc/oggstream.html + doc/ogg-multiplex.html + doc/fish_xiph_org.png + doc/multiplex1.png + doc/packets.png + doc/pages.png + doc/stream.png + doc/vorbisword2.png + doc/white-ogg.png + doc/white-xifish.png + doc/rfc3533.txt + doc/rfc5334.txt + doc/skeleton.html + ) + install(FILES ${OGG_DOCS} DESTINATION ${CMAKE_INSTALL_DOCDIR}/html) + install(DIRECTORY doc/libogg DESTINATION ${CMAKE_INSTALL_DOCDIR}/html) +endif() + +if(BUILD_TESTING) + add_executable(test_bitwise src/bitwise.c ${OGG_HEADERS}) + target_compile_definitions(test_bitwise PRIVATE _V_SELFTEST) + target_include_directories(test_bitwise PRIVATE + include + ${CMAKE_CURRENT_BINARY_DIR}/include + ) + add_test(NAME test_bitwise COMMAND $) + + add_executable(test_framing src/framing.c ${OGG_HEADERS}) + target_compile_definitions(test_framing PRIVATE _V_SELFTEST) + target_include_directories(test_framing PRIVATE + include + ${CMAKE_CURRENT_BINARY_DIR}/include + ) + add_test(NAME test_framing COMMAND $) +endif() + +set(CPACK_PACKAGE_VERSION ${PROJECT_VERSION}) +include(CPack) diff --git a/extern/ogg/COPYING b/extern/ogg/COPYING new file mode 100644 index 0000000..6111c6c --- /dev/null +++ b/extern/ogg/COPYING @@ -0,0 +1,28 @@ +Copyright (c) 2002, Xiph.org Foundation + +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 the Xiph.org Foundation nor the names of its +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 FOUNDATION +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. diff --git a/extern/ogg/Makefile.am b/extern/ogg/Makefile.am new file mode 100644 index 0000000..dd75bc1 --- /dev/null +++ b/extern/ogg/Makefile.am @@ -0,0 +1,44 @@ +## Process this file with automake to produce Makefile.in + + +#AUTOMAKE_OPTIONS = foreign 1.6 dist-zip +AUTOMAKE_OPTIONS = foreign 1.11 dist-zip dist-xz +ACLOCAL_AMFLAGS = -I m4 + +SUBDIRS = src include doc + +m4datadir = $(datadir)/aclocal +m4data_DATA = ogg.m4 + +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = ogg.pc + +EXTRA_DIST = README.md AUTHORS CHANGES COPYING \ + libogg.spec libogg.spec.in \ + ogg.m4 ogg.pc.in ogg-uninstalled.pc.in \ + macosx win32 CMakeLists.txt cmake + +dist-hook: + for item in $(EXTRA_DIST); do \ + if test -d $$item; then \ + echo -n "cleaning dir $$item for distribution..."; \ + rm -rf `find $(distdir)/$$item -name .svn`; \ + echo "OK"; \ + fi; \ + done + +# Verify cmake works with the dist tarball. +cmake_builddir = _build.cmake +distcheck-hook: + $(RM) -rf $(cmake_builddir) + mkdir $(cmake_builddir) + cd $(cmake_builddir) && cmake ../$(top_distdir) + cd $(cmake_builddir) && cmake --build . + cd $(cmake_builddir) && ctest + $(RM) -rf $(cmake_builddir) + +debug: + $(MAKE) all CFLAGS="@DEBUG@" + +profile: + $(MAKE) all CFLAGS="@PROFILE@" diff --git a/extern/ogg/README.md b/extern/ogg/README.md new file mode 100644 index 0000000..63545e2 --- /dev/null +++ b/extern/ogg/README.md @@ -0,0 +1,133 @@ +# Ogg + +[![Travis Build Status](https://travis-ci.org/xiph/ogg.svg?branch=master)](https://travis-ci.org/xiph/ogg) +[![Jenkins Build Status](https://mf4.xiph.org/jenkins/job/libogg/badge/icon)](https://mf4.xiph.org/jenkins/job/libogg/) +[![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/github/xiph/ogg?branch=master&svg=true)](https://ci.appveyor.com/project/rillian/ogg) + +Ogg project codecs use the Ogg bitstream format to arrange the raw, +compressed bitstream into a more robust, useful form. For example, +the Ogg bitstream makes seeking, time stamping and error recovery +possible, as well as mixing several sepearate, concurrent media +streams into a single physical bitstream. + +## What's here ## +This source distribution includes libogg and nothing else. Other modules +(eg, the modules libvorbis, vorbis-tools for the Vorbis music codec, +libtheora for the Theora video codec) contain the codec libraries for +use with Ogg bitstreams. + +Directory: + +- `src` The source for libogg, a BSD-license inplementation of the public domain Ogg bitstream format + +- `include` Library API headers + +- `doc` Ogg specification and libogg API documents + +- `win32` Win32 projects and build automation + +- `macosx` Mac OS X project and build files + +## Contact ## + +The Ogg homepage is located at https://www.xiph.org/ogg/ . +Up to date technical documents, contact information, source code and +pre-built utilities may be found there. + +## Building ## + +#### Building from tarball distributions #### + + ./configure + make + +and optionally (as root): + + make install + +This will install the Ogg libraries (static and shared) into +/usr/local/lib, includes into /usr/local/include and API +documentation into /usr/local/share/doc. + +#### Building from repository source #### + +A standard svn build should consist of nothing more than: + + ./autogen.sh + ./configure + make + +and as root if desired : + + make install + +#### Building on Windows #### + +Use the project file in the win32 directory. It should compile out of the box. + +#### Cross-compiling from Linux to Windows #### + +It is also possible to cross compile from Linux to windows using the MinGW +cross tools and even to run the test suite under Wine, the Linux/*nix +windows emulator. + +On Debian and Ubuntu systems, these cross compiler tools can be installed +by doing: + + sudo apt-get mingw32 mingw32-binutils mingw32-runtime wine + +Once these tools are installed its possible to compile and test by +executing the following commands, or something similar depending on +your system: + + ./configure --host=i586-mingw32msvc --target=i586-mingw32msvc --build=i586-linux + make + make check + +(Build instructions for Ogg codecs such as vorbis are similar and may +be found in those source modules' README files) + +## Building with CMake ## + +Ogg supports building using [CMake](http://www.cmake.org/). CMake is a meta build system that generates native projects for each platform. +To generate projects just run cmake replacing `YOUR-PROJECT-GENERATOR` with a proper generator from a list [here](http://www.cmake.org/cmake/help/v3.2/manual/cmake-generators.7.html): + + mkdir build + cd build + cmake -G YOUR-PROJECT-GENERATOR .. + +Note that by default cmake generates projects that will build static libraries. +To generate projects that will build dynamic library use `BUILD_SHARED_LIBS` option like this: + + cmake -G YOUR-PROJECT-GENERATOR -DBUILD_SHARED_LIBS=1 .. + +After projects are generated use them as usual + +#### Building on Windows #### + +Use proper generator for your Visual Studio version like: + + cmake -G "Visual Studio 12 2013" .. + +#### Building on Mac OS X #### + +Use Xcode generator. To build framework run: + + cmake -G Xcode -DBUILD_FRAMEWORK=1 .. + +#### Building on Linux #### + +Use Makefile generator which is default one. + + cmake .. + make + +## License ## + +THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. +USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS +GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE +IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. + +THE OggVorbis SOURCE CODE IS COPYRIGHT (C) 1994-2019 +by the Xiph.Org Foundation https://www.xiph.org/ diff --git a/extern/ogg/appveyor.yml b/extern/ogg/appveyor.yml new file mode 100644 index 0000000..653d8ac --- /dev/null +++ b/extern/ogg/appveyor.yml @@ -0,0 +1,33 @@ +image: Visual Studio 2015 +configuration: +- Debug +- Release + +platform: +- Win32 +- x64 + +environment: + matrix: + - BUILD_SYSTEM: MSVC + - BUILD_SYSTEM: CMAKE + +build_script: + - if "%BUILD_SYSTEM%" == "MSVC" ( + msbuild "%APPVEYOR_BUILD_FOLDER%\win32\VS2015\libogg.sln" /m /v:minimal /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" /property:Configuration=%CONFIGURATION%;Platform=%PLATFORM% + ) + - if "%BUILD_SYSTEM%" == "CMAKE" ( + mkdir "%APPVEYOR_BUILD_FOLDER%\build" && + pushd "%APPVEYOR_BUILD_FOLDER%\build" && + cmake -A "%PLATFORM%" -G "Visual Studio 14 2015" .. && + cmake --build . --config "%CONFIGURATION%" -- /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" && + popd + ) + +after_build: + - if "%BUILD_SYSTEM%" == "MSVC" ( + 7z a ogg.zip win32\VS2015\%PLATFORM%\%CONFIGURATION%\libogg.lib include\ogg\*.h + ) + +artifacts: +- path: ogg.zip diff --git a/extern/ogg/autogen.sh b/extern/ogg/autogen.sh new file mode 100755 index 0000000..f6490cc --- /dev/null +++ b/extern/ogg/autogen.sh @@ -0,0 +1,13 @@ +#!/bin/sh +# Run this to set up the build system: configure, makefiles, etc. +set -e + +package="libogg" + +srcdir=`dirname $0` +test -n "$srcdir" && cd "$srcdir" + +echo "Updating build configuration files for $package, please wait...." + +mkdir -p m4 +autoreconf -if diff --git a/extern/ogg/cmake/CheckSizes.cmake b/extern/ogg/cmake/CheckSizes.cmake new file mode 100644 index 0000000..4d6c8a0 --- /dev/null +++ b/extern/ogg/cmake/CheckSizes.cmake @@ -0,0 +1,73 @@ +include(CheckTypeSize) + +check_type_size("int16_t" INT16_SIZE LANGUAGE C) +check_type_size("uint16_t" UINT16_SIZE LANGUAGE C) +check_type_size("u_int16_t" U_INT16_SIZE LANGUAGE C) +check_type_size("int32_t" INT32_SIZE LANGUAGE C) +check_type_size("uint32_t" UINT32_SIZE LANGUAGE C) +check_type_size("u_int32_t" U_INT32_SIZE LANGUAGE C) +check_type_size("int64_t" INT64_SIZE LANGUAGE C) +check_type_size("short" SHORT_SIZE LANGUAGE C) +check_type_size("int" INT_SIZE LANGUAGE C) +check_type_size("long" LONG_SIZE LANGUAGE C) +check_type_size("long long" LONG_LONG_SIZE LANGUAGE C) + +if(INT16_SIZE EQUAL 2) + set(SIZE16 "int16_t") +elseif(SHORT_SIZE EQUAL 2) + set(SIZE16 "short") +elseif(INT_SIZE EQUAL 2) + set(SIZE16 "int") +else() + message(FATAL_ERROR "No 16 bit type found on this platform!") +endif() + +if(UINT16_SIZE EQUAL 2) + set(USIZE16 "uint16_t") +elseif(SHORT_SIZE EQUAL 2) + set(USIZE16 "unsigned short") +elseif(INT_SIZE EQUAL 2) + set(USIZE16 "unsigned int") +elseif(U_INT_SIZE EQUAL 2) + set(USIZE16 "u_int16_t") +else() + message(FATAL_ERROR "No unsigned 16 bit type found on this platform!") +endif() + +if(INT32_SIZE EQUAL 4) + set(SIZE32 "int32_t") +elseif(SHORT_SIZE EQUAL 4) + set(SIZE32 "short") +elseif(INT_SIZE EQUAL 4) + set(SIZE32 "int") +elseif(LONG_SIZE EQUAL 4) + set(SIZE16 "long") +else() + message(FATAL_ERROR "No 32 bit type found on this platform!") +endif() + +if(UINT32_SIZE EQUAL 4) + set(USIZE32 "uint32_t") +elseif(SHORT_SIZE EQUAL 4) + set(USIZE32 "unsigned short") +elseif(INT_SIZE EQUAL 4) + set(USIZE32 "unsigned int") +elseif(LONG_SIZE EQUAL 4) + set(USIZE32 "unsigned long") +elseif(U_INT_SIZE EQUAL 4) + set(USIZE32 "u_int32_t") +else() + message(FATAL_ERROR "No unsigned 32 bit type found on this platform!") +endif() + +if(INT64_SIZE EQUAL 8) + set(SIZE64 "int64_t") +elseif(INT_SIZE EQUAL 8) + set(SIZE64 "int") +elseif(LONG_SIZE EQUAL 8) + set(SIZE64 "long") +elseif(LONG_LONG_SIZE EQUAL 8) + set(SIZE64 "long long") +else() + message(FATAL_ERROR "No 64 bit type found on this platform!") +endif() diff --git a/extern/ogg/cmake/OggConfig.cmake.in b/extern/ogg/cmake/OggConfig.cmake.in new file mode 100644 index 0000000..43de6a9 --- /dev/null +++ b/extern/ogg/cmake/OggConfig.cmake.in @@ -0,0 +1,16 @@ +@PACKAGE_INIT@ + +set(Ogg_INCLUDE_DIR "@PACKAGE_CMAKE_INSTALL_FULL_INCLUDEDIR@") +set(OGG_INCLUDE_DIR "@PACKAGE_CMAKE_INSTALL_FULL_INCLUDEDIR@") +set(Ogg_INCLUDE_DIRS "@PACKAGE_CMAKE_INSTALL_FULL_INCLUDEDIR@") +set(OGG_INCLUDE_DIRS "@PACKAGE_CMAKE_INSTALL_FULL_INCLUDEDIR@") + +include(${CMAKE_CURRENT_LIST_DIR}/OggTargets.cmake) + +set(Ogg_LIBRARY Ogg::ogg) +set(OGG_LIBRARY Ogg::ogg) +set(Ogg_LIBRARIES Ogg::ogg) +set(OGG_LIBRARIES Ogg::ogg) + +check_required_components(Ogg) +set(OGG_FOUND 1) diff --git a/extern/ogg/configure.ac b/extern/ogg/configure.ac new file mode 100644 index 0000000..a2429e7 --- /dev/null +++ b/extern/ogg/configure.ac @@ -0,0 +1,209 @@ +dnl Process this file with autoconf to produce a configure script. + +AC_INIT([libogg],[1.3.4],[ogg-dev@xiph.org]) + +LT_INIT +AC_CONFIG_MACRO_DIR([m4]) +AC_CONFIG_SRCDIR(src/framing.c) + +AM_INIT_AUTOMAKE +AM_MAINTAINER_MODE([enable]) + +dnl Library versioning + +LIB_CURRENT=8 +LIB_REVISION=4 +LIB_AGE=8 +AC_SUBST(LIB_CURRENT) +AC_SUBST(LIB_REVISION) +AC_SUBST(LIB_AGE) + +AC_PROG_CC +AM_PROG_CC_C_O + +dnl Set some options based on environment + +cflags_save="$CFLAGS" +if test -z "$GCC"; then + case $host in + *-*-irix*) + DEBUG="-g -signed" + CFLAGS="-O2 -w -signed" + PROFILE="-p -g3 -O2 -signed" + ;; + sparc-sun-solaris*) + DEBUG="-v -g" + CFLAGS="-xO4 -fast -w -fsimple -native -xcg92" + PROFILE="-v -xpg -g -xO4 -fast -native -fsimple -xcg92 -Dsuncc" + ;; + *) + DEBUG="-g" + CFLAGS="-O" + PROFILE="-g -p" + ;; + esac +else + case $host in + *-*-linux*) + DEBUG="-g -Wall -fsigned-char" + CFLAGS="-O20 -Wall -ffast-math -fsigned-char" + PROFILE="-Wall -W -pg -g -O20 -ffast-math -fsigned-char" + ;; + sparc-sun-*) + DEBUG="-g -Wall -fsigned-char" + CFLAGS="-O20 -ffast-math -fsigned-char" + PROFILE="-pg -g -O20 -fsigned-char" + ;; + *-*-darwin*) + DEBUG="-fno-common -g -Wall -fsigned-char" + CFLAGS="-fno-common -O4 -Wall -fsigned-char -ffast-math" + PROFILE="-fno-common -O4 -Wall -pg -g -fsigned-char -ffast-math" + ;; + *) + DEBUG="-g -Wall -fsigned-char" + CFLAGS="-O20 -fsigned-char" + PROFILE="-O20 -g -pg -fsigned-char" + ;; + esac +fi +CFLAGS="$CFLAGS $cflags_save" +DEBUG="$DEBUG $cflags_save" +PROFILE="$PROFILE $cflags_save" + +dnl Checks for programs. + +dnl Checks for libraries. + +dnl Checks for header files. +AC_HEADER_STDC +INCLUDE_INTTYPES_H=0 +INCLUDE_STDINT_H=0 +INCLUDE_SYS_TYPES_H=0 +AC_CHECK_HEADER(inttypes.h,INCLUDE_INTTYPES_H=1) +AC_CHECK_HEADER(stdint.h,INCLUDE_STDINT_H=1) +AC_CHECK_HEADER(sys/types.h,INCLUDE_SYS_TYPES_H=1) + +dnl Checks for typedefs, structures, and compiler characteristics. +AC_C_CONST + +dnl Check for types + +AC_CHECK_SIZEOF(int16_t) +AC_CHECK_SIZEOF(uint16_t) +AC_CHECK_SIZEOF(u_int16_t) +AC_CHECK_SIZEOF(int32_t) +AC_CHECK_SIZEOF(uint32_t) +AC_CHECK_SIZEOF(u_int32_t) +AC_CHECK_SIZEOF(int64_t) +AC_CHECK_SIZEOF(uint64_t) +AC_CHECK_SIZEOF(short) +AC_CHECK_SIZEOF(int) +AC_CHECK_SIZEOF(long) +AC_CHECK_SIZEOF(long long) + +case 2 in + $ac_cv_sizeof_int16_t) SIZE16="int16_t";; + $ac_cv_sizeof_short) SIZE16="short";; + $ac_cv_sizeof_int) SIZE16="int";; +esac + +case 2 in + $ac_cv_sizeof_uint16_t) USIZE16="uint16_t";; + $ac_cv_sizeof_short) USIZE16="unsigned short";; + $ac_cv_sizeof_int) USIZE16="unsigned int";; + $ac_cv_sizeof_u_int16_t) USIZE16="u_int16_t";; +esac + +case 4 in + $ac_cv_sizeof_int32_t) SIZE32="int32_t";; + $ac_cv_sizeof_short) SIZE32="short";; + $ac_cv_sizeof_int) SIZE32="int";; + $ac_cv_sizeof_long) SIZE32="long";; +esac + +case 4 in + $ac_cv_sizeof_uint32_t) USIZE32="uint32_t";; + $ac_cv_sizeof_short) USIZE32="unsigned short";; + $ac_cv_sizeof_int) USIZE32="unsigned int";; + $ac_cv_sizeof_long) USIZE32="unsigned long";; + $ac_cv_sizeof_u_int32_t) USIZE32="u_int32_t";; +esac + +case 8 in + $ac_cv_sizeof_int64_t) SIZE64="int64_t";; + $ac_cv_sizeof_int) SIZE64="int";; + $ac_cv_sizeof_long) SIZE64="long";; + $ac_cv_sizeof_long_long) SIZE64="long long";; +esac + +case 8 in + $ac_cv_sizeof_uint64_t) USIZE64="uint64_t";; + $ac_cv_sizeof_unsigned_int) USIZE64="unsigned int";; + $ac_cv_sizeof_unsigned_long) USIZE64="unsigned long";; + $ac_cv_sizeof_unsigned_long_long) USIZE64="unsigned long long";; +esac + +if test -z "$SIZE16"; then + AC_MSG_ERROR(No 16 bit type found on this platform!) +fi +if test -z "$USIZE16"; then + AC_MSG_ERROR(No unsigned 16 bit type found on this platform!) +fi +if test -z "$SIZE32"; then + AC_MSG_ERROR(No 32 bit type found on this platform!) +fi +if test -z "$USIZE32"; then + AC_MSG_ERROR(No unsigned 32 bit type found on this platform!) +fi +if test -z "$SIZE64"; then + AC_MSG_WARN(No 64 bit type found on this platform!) +fi +if test -z "$USIZE64"; then + AC_MSG_WARN(No unsigned 64 bit type found on this platform!) +fi + +AC_ARG_ENABLE([crc], + [AS_HELP_STRING([--disable-crc], + [Disable CRC in the demuxer])],, + [enable_crc=yes]) + +AM_CONDITIONAL([DISABLE_CRC], [test "$enable_crc" = "no"]) + +AS_IF([test "$enable_crc" = "no"],[ + AC_DEFINE([DISABLE_CRC], [1], [Do not build with CRC]) +]) + +dnl Checks for library functions. +AC_FUNC_MEMCMP + +dnl Make substitutions + +AC_SUBST(LIBTOOL_DEPS) +AC_SUBST(INCLUDE_INTTYPES_H) +AC_SUBST(INCLUDE_STDINT_H) +AC_SUBST(INCLUDE_SYS_TYPES_H) +AC_SUBST(SIZE16) +AC_SUBST(USIZE16) +AC_SUBST(SIZE32) +AC_SUBST(USIZE32) +AC_SUBST(SIZE64) +AC_SUBST(USIZE64) +AC_SUBST(OPT) +AC_SUBST(LIBS) +AC_SUBST(DEBUG) +AC_SUBST(CFLAGS) +AC_SUBST(PROFILE) + + +AC_CONFIG_FILES([ +Makefile +src/Makefile +doc/Makefile doc/libogg/Makefile +include/Makefile include/ogg/Makefile include/ogg/config_types.h +libogg.spec +ogg.pc +ogg-uninstalled.pc +]) +AC_CONFIG_HEADERS([config.h]) + +AC_OUTPUT diff --git a/extern/ogg/doc/Makefile.am b/extern/ogg/doc/Makefile.am new file mode 100644 index 0000000..3dd47b9 --- /dev/null +++ b/extern/ogg/doc/Makefile.am @@ -0,0 +1,9 @@ +## Process this with automake to create Makefile.in + +SUBDIRS = libogg + +dist_html_DATA = framing.html index.html oggstream.html ogg-multiplex.html \ + fish_xiph_org.png multiplex1.png packets.png pages.png stream.png \ + vorbisword2.png white-ogg.png white-xifish.png \ + rfc3533.txt rfc5334.txt skeleton.html + diff --git a/extern/ogg/doc/fish_xiph_org.png b/extern/ogg/doc/fish_xiph_org.png new file mode 100644 index 0000000..b398c06 Binary files /dev/null and b/extern/ogg/doc/fish_xiph_org.png differ diff --git a/extern/ogg/doc/framing.html b/extern/ogg/doc/framing.html new file mode 100644 index 0000000..b5ac6ac --- /dev/null +++ b/extern/ogg/doc/framing.html @@ -0,0 +1,429 @@ + + + + + +Ogg Documentation + + + + + + + + + +

Ogg logical bitstream framing

+ +

Ogg bitstreams

+ +

The Ogg transport bitstream is designed to provide framing, error +protection and seeking structure for higher-level codec streams that +consist of raw, unencapsulated data packets, such as the Vorbis audio +codec or Theora video codec.

+ +

Application example: Vorbis

+ +

Vorbis encodes short-time blocks of PCM data into raw packets of +bit-packed data. These raw packets may be used directly by transport +mechanisms that provide their own framing and packet-separation +mechanisms (such as UDP datagrams). For stream based storage (such as +files) and transport (such as TCP streams or pipes), Vorbis uses the +Ogg bitstream format to provide framing/sync, sync recapture +after error, landmarks during seeking, and enough information to +properly separate data back into packets at the original packet +boundaries without relying on decoding to find packet boundaries.

+ +

Design constraints for Ogg bitstreams

+ +
    +
  1. True streaming; we must not need to seek to build a 100% + complete bitstream.
  2. +
  3. Use no more than approximately 1-2% of bitstream bandwidth for + packet boundary marking, high-level framing, sync and seeking.
  4. +
  5. Specification of absolute position within the original sample + stream.
  6. +
  7. Simple mechanism to ease limited editing, such as a simplified + concatenation mechanism.
  8. +
  9. Detection of corruption, recapture after error and direct, random + access to data at arbitrary positions in the bitstream.
  10. +
+ +

Logical and Physical Bitstreams

+ +

A logical Ogg bitstream is a contiguous stream of +sequential pages belonging only to the logical bitstream. A +physical Ogg bitstream is constructed from one or more +than one logical Ogg bitstream (the simplest physical bitstream +is simply a single logical bitstream). We describe below the exact +formatting of an Ogg logical bitstream. Combining logical +bitstreams into more complex physical bitstreams is described in the +Ogg bitstream overview. The exact +mapping of raw Vorbis packets into a valid Ogg Vorbis physical +bitstream is described in the Vorbis I Specification.

+ +

Bitstream structure

+ +

An Ogg stream is structured by dividing incoming packets into +segments of up to 255 bytes and then wrapping a group of contiguous +packet segments into a variable length page preceded by a page +header. Both the header size and page size are variable; the page +header contains sizing information and checksum data to determine +header/page size and data integrity.

+ +

The bitstream is captured (or recaptured) by looking for the beginning +of a page, specifically the capture pattern. Once the capture pattern +is found, the decoder verifies page sync and integrity by computing +and comparing the checksum. At that point, the decoder can extract the +packets themselves.

+ +

Packet segmentation

+ +

Packets are logically divided into multiple segments before encoding +into a page. Note that the segmentation and fragmentation process is a +logical one; it's used to compute page header values and the original +page data need not be disturbed, even when a packet spans page +boundaries.

+ +

The raw packet is logically divided into [n] 255 byte segments and a +last fractional segment of < 255 bytes. A packet size may well +consist only of the trailing fractional segment, and a fractional +segment may be zero length. These values, called "lacing values" are +then saved and placed into the header segment table.

+ +

An example should make the basic concept clear:

+ +
+
+raw packet:
+  ___________________________________________
+ |______________packet data__________________| 753 bytes
+
+lacing values for page header segment table: 255,255,243
+
+
+ +

We simply add the lacing values for the total size; the last lacing +value for a packet is always the value that is less than 255. Note +that this encoding both avoids imposing a maximum packet size as well +as imposing minimum overhead on small packets (as opposed to, eg, +simply using two bytes at the head of every packet and having a max +packet size of 32k. Small packets (<255, the typical case) are +penalized with twice the segmentation overhead). Using the lacing +values as suggested, small packets see the minimum possible +byte-aligned overhead (1 byte) and large packets, over 512 bytes or +so, see a fairly constant ~.5% overhead on encoding space.

+ +

Note that a lacing value of 255 implies that a second lacing value +follows in the packet, and a value of < 255 marks the end of the +packet after that many additional bytes. A packet of 255 bytes (or a +multiple of 255 bytes) is terminated by a lacing value of 0:

+ +

+raw packet:
+  _______________________________
+ |________packet data____________|          255 bytes
+
+lacing values: 255, 0
+
+ +

Note also that a 'nil' (zero length) packet is not an error; it +consists of nothing more than a lacing value of zero in the header.

+ +

Packets spanning pages

+ +

Packets are not restricted to beginning and ending within a page, +although individual segments are, by definition, required to do so. +Packets are not restricted to a maximum size, although excessively +large packets in the data stream are discouraged.

+ +

After segmenting a packet, the encoder may decide not to place all the +resulting segments into the current page; to do so, the encoder places +the lacing values of the segments it wishes to belong to the current +page into the current segment table, then finishes the page. The next +page is begun with the first value in the segment table belonging to +the next packet segment, thus continuing the packet (data in the +packet body must also correspond properly to the lacing values in the +spanned pages. The segment data in the first packet corresponding to +the lacing values of the first page belong in that page; packet +segments listed in the segment table of the following page must begin +the page body of the subsequent page).

+ +

The last mechanic to spanning a page boundary is to set the header +flag in the new page to indicate that the first lacing value in the +segment table continues rather than begins a packet; a header flag of +0x01 is set to indicate a continued packet. Although mandatory, it +is not actually algorithmically necessary; one could inspect the +preceding segment table to determine if the packet is new or +continued. Adding the information to the packet_header flag allows a +simpler design (with no overhead) that needs only inspect the current +page header after frame capture. This also allows faster error +recovery in the event that the packet originates in a corrupt +preceding page, implying that the previous page's segment table +cannot be trusted.

+ +

Note that a packet can span an arbitrary number of pages; the above +spanning process is repeated for each spanned page boundary. Also a +'zero termination' on a packet size that is an even multiple of 255 +must appear even if the lacing value appears in the next page as a +zero-length continuation of the current packet. The header flag +should be set to 0x01 to indicate that the packet spanned, even though +the span is a nil case as far as data is concerned.

+ +

The encoding looks odd, but is properly optimized for speed and the +expected case of the majority of packets being between 50 and 200 +bytes (note that it is designed such that packets of wildly different +sizes can be handled within the model; placing packet size +restrictions on the encoder would have only slightly simplified design +in page generation and increased overall encoder complexity).

+ +

The main point behind tracking individual packets (and packet +segments) is to allow more flexible encoding tricks that requiring +explicit knowledge of packet size. An example is simple bandwidth +limiting, implemented by simply truncating packets in the nominal case +if the packet is arranged so that the least sensitive portion of the +data comes last.

+ + +

Page header

+ +

The headering mechanism is designed to avoid copying and re-assembly +of the packet data (ie, making the packet segmentation process a +logical one); the header can be generated directly from incoming +packet data. The encoder buffers packet data until it finishes a +complete page at which point it writes the header followed by the +buffered packet segments.

+ +

capture_pattern

+ +

A header begins with a capture pattern that simplifies identifying +pages; once the decoder has found the capture pattern it can do a more +intensive job of verifying that it has in fact found a page boundary +(as opposed to an inadvertent coincidence in the byte stream).

+ +

+ byte value
+
+  0  0x4f 'O'
+  1  0x67 'g'
+  2  0x67 'g'
+  3  0x53 'S'  
+
+ +

stream_structure_version

+ +

The capture pattern is followed by the stream structure revision:

+ +

+ byte value
+
+  4  0x00
+
+ +

header_type_flag

+ +

The header type flag identifies this page's context in the bitstream:

+ +

+ byte value
+
+  5  bitflags: 0x01: unset = fresh packet
+	               set = continued packet
+	       0x02: unset = not first page of logical bitstream
+                       set = first page of logical bitstream (bos)
+	       0x04: unset = not last page of logical bitstream
+                       set = last page of logical bitstream (eos)
+
+ +

absolute granule position

+ +

(This is packed in the same way the rest of Ogg data is packed; LSb +of LSB first. Note that the 'position' data specifies a 'sample' +number (eg, in a CD quality sample is four octets, 16 bits for left +and 16 bits for right; in video it would likely be the frame number. +It is up to the specific codec in use to define the semantic meaning +of the granule position value). The position specified is the total +samples encoded after including all packets finished on this page +(packets begun on this page but continuing on to the next page do not +count). The rationale here is that the position specified in the +frame header of the last page tells how long the data coded by the +bitstream is. A truncated stream will still return the proper number +of samples that can be decoded fully.

+ +

A special value of '-1' (in two's complement) indicates that no packets +finish on this page.

+ +

+ byte value
+
+  6  0xXX LSB
+  7  0xXX
+  8  0xXX
+  9  0xXX
+ 10  0xXX
+ 11  0xXX
+ 12  0xXX
+ 13  0xXX MSB
+
+ +

stream serial number

+ +

Ogg allows for separate logical bitstreams to be mixed at page +granularity in a physical bitstream. The most common case would be +sequential arrangement, but it is possible to interleave pages for +two separate bitstreams to be decoded concurrently. The serial +number is the means by which pages physical pages are associated with +a particular logical stream. Each logical stream must have a unique +serial number within a physical stream:

+ +

+ byte value
+
+ 14  0xXX LSB
+ 15  0xXX
+ 16  0xXX
+ 17  0xXX MSB
+
+ +

page sequence no

+ +

Page counter; lets us know if a page is lost (useful where packets +span page boundaries).

+ +

+ byte value
+
+ 18  0xXX LSB
+ 19  0xXX
+ 20  0xXX
+ 21  0xXX MSB
+
+ +

page checksum

+ +

32 bit CRC value (direct algorithm, initial val and final XOR = 0, +generator polynomial=0x04c11db7). The value is computed over the +entire header (with the CRC field in the header set to zero) and then +continued over the page. The CRC field is then filled with the +computed value.

+ +

(A thorough discussion of CRC algorithms can be found in "A +Painless Guide to CRC Error Detection Algorithms" by Ross +Williams ross@ross.net.)

+ +

+ byte value
+
+ 22  0xXX LSB
+ 23  0xXX
+ 24  0xXX
+ 25  0xXX MSB
+
+ +

page_segments

+ +

The number of segment entries to appear in the segment table. The +maximum number of 255 segments (255 bytes each) sets the maximum +possible physical page size at 65307 bytes or just under 64kB (thus +we know that a header corrupted so as destroy sizing/alignment +information will not cause a runaway bitstream. We'll read in the +page according to the corrupted size information that's guaranteed to +be a reasonable size regardless, notice the checksum mismatch, drop +sync and then look for recapture).

+ +

+ byte value
+
+ 26 0x00-0xff (0-255)
+
+ +

segment_table (containing packet lacing values)

+ +

The lacing values for each packet segment physically appearing in +this page are listed in contiguous order.

+ +

+ byte value
+
+ 27 0x00-0xff (0-255)
+ [...]
+ n  0x00-0xff (0-255, n=page_segments+26)
+
+ +

Total page size is calculated directly from the known header size and +lacing values in the segment table. Packet data segments follow +immediately after the header.

+ +

Page headers typically impose a flat .25-.5% space overhead assuming +nominal ~8k page sizes. The segmentation table needed for exact +packet recovery in the streaming layer adds approximately .5-1% +nominal assuming expected encoder behavior in the 44.1kHz, 128kbps +stereo encodings.

+ + + + + diff --git a/extern/ogg/doc/index.html b/extern/ogg/doc/index.html new file mode 100644 index 0000000..6e02f79 --- /dev/null +++ b/extern/ogg/doc/index.html @@ -0,0 +1,105 @@ + + + + + +Ogg Documentation + + + + + + + + + +

Ogg Documentation

+ +

Ogg programming documentation

+ + + +

Ogg bitstream documentation

+ + + +

RFC documentation

+ + + + + + + diff --git a/extern/ogg/doc/libogg/Makefile.am b/extern/ogg/doc/libogg/Makefile.am new file mode 100644 index 0000000..4007907 --- /dev/null +++ b/extern/ogg/doc/libogg/Makefile.am @@ -0,0 +1,39 @@ +## Process this file with automake to produce Makefile.in + +apidocdir = $(htmldir)/libogg + +dist_apidoc_DATA = bitpacking.html datastructures.html decoding.html encoding.html\ + general.html index.html ogg_iovec_t.html ogg_packet.html ogg_packet_clear.html\ + ogg_page.html ogg_page_bos.html ogg_page_checksum_set.html\ + ogg_page_continued.html ogg_page_eos.html ogg_page_granulepos.html\ + ogg_page_packets.html ogg_page_pageno.html ogg_page_serialno.html\ + ogg_page_version.html ogg_stream_check.html ogg_stream_clear.html ogg_stream_destroy.html\ + ogg_stream_eos.html ogg_stream_flush.html ogg_stream_flush_fill.html ogg_stream_init.html\ + ogg_stream_iovecin.html ogg_stream_packetin.html ogg_stream_packetout.html\ + ogg_stream_packetpeek.html ogg_stream_pagein.html\ + ogg_stream_pageout.html ogg_stream_pageout_fill.html ogg_stream_reset.html\ + ogg_stream_reset_serialno.html ogg_stream_state.html\ + ogg_sync_buffer.html ogg_sync_check.html ogg_sync_clear.html ogg_sync_destroy.html\ + ogg_sync_init.html ogg_sync_pageout.html ogg_sync_pageseek.html\ + ogg_sync_reset.html ogg_sync_state.html ogg_sync_wrote.html\ + oggpack_adv.html oggpack_adv1.html oggpack_bits.html\ + oggpack_buffer.html oggpack_bytes.html oggpack_get_buffer.html\ + oggpack_look.html oggpack_look1.html oggpack_read.html\ + oggpack_read1.html oggpack_readinit.html oggpack_reset.html\ + oggpack_write.html oggpack_writealign.html oggpack_writecheck.html oggpack_writeclear.html\ + oggpack_writecopy.html oggpack_writeinit.html oggpack_writetrunc.html\ + overview.html reference.html style.css + +update-doc-version: + @YEAR=$$(date +%Y); DAY=$$(date +%Y%m%d); \ + for f in $(srcdir)/*.html; do \ + sed -e "s/2000-[0-9]\{4\} Xiph.Org/2000-$$YEAR Xiph.Org/g" \ + -e "s/libogg release [0-9. -]\+/libogg release $(VERSION) - $$DAY/g"\ + < $$f > $$f.tmp; \ + if diff -q $$f $$f.tmp > /dev/null; then \ + rm $$f.tmp; \ + else \ + mv $$f.tmp $$f; \ + fi; \ + done; + diff --git a/extern/ogg/doc/libogg/bitpacking.html b/extern/ogg/doc/libogg/bitpacking.html new file mode 100644 index 0000000..6f5b04a --- /dev/null +++ b/extern/ogg/doc/libogg/bitpacking.html @@ -0,0 +1,103 @@ + + + +libogg - Bitpacking Functions + + + + + + + + + +

libogg documentation

libogg release 1.3.4 - 20190830

+ +

Bitpacking Functions

+

Libogg contains a basic bitpacking library that is useful for manipulating data within a buffer. +

+All the libogg specific functions are declared in "ogg/ogg.h". +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
functionpurpose
oggpack_writeinitInitializes a buffer for writing using this bitpacking library.
oggpack_writecheckAsynchronously checks error status of bitpacker write buffer.
oggpack_resetClears and resets the buffer to the initial position.
oggpack_writeclearFrees the memory used by the buffer.
oggpack_readinitInitializes a buffer for reading using this bitpacking library.
oggpack_writeWrites bytes to the specified location within the buffer.
oggpack_lookLook at a specified number of bits, <=32, without advancing the location pointer.
oggpack_look1Looks at one bit without advancing the location pointer.
oggpack_advAdvances the location pointer by a specified number of bits.
oggpack_adv1Advances the location pointer by one bit.
oggpack_readReads a specified number of bits from the buffer.
oggpack_read1Reads one bit from the buffer.
oggpack_bytesReturns the total number of bytes contained within the buffer.
oggpack_bitsReturns the total number of bits contained within the buffer.
oggpack_get_bufferReturns a pointer to the buffer encapsulated within the oggpack_buffer struct.
+ +

+


+ + + + + + + + +

copyright © 2000-2019 Xiph.Org Foundation

Ogg Container Format

libogg documentation

libogg release 1.3.4 - 20190830

+ + + + diff --git a/extern/ogg/doc/libogg/datastructures.html b/extern/ogg/doc/libogg/datastructures.html new file mode 100644 index 0000000..b6596f2 --- /dev/null +++ b/extern/ogg/doc/libogg/datastructures.html @@ -0,0 +1,59 @@ + + + +libogg - Base Data Structures + + + + + + + + + +

libogg documentation

libogg release 1.3.4 - 20190830

+ +

Base Data Structures

+

Libogg uses several data structures to hold data and state information. +

+All the libogg specific data structures are declared in "ogg/ogg.h". +

+ + + + + + + + + + + + + + + + + + + + + + +
datatypepurpose
ogg_pageThis structure encapsulates data into one ogg bitstream page.
ogg_stream_stateThis structure contains current encode/decode data for a logical bitstream.
ogg_packetThis structure encapsulates the data and metadata for a single Ogg packet.
ogg_sync_stateContains bitstream synchronization information.
+ +

+


+ + + + + + + + +

copyright © 2000-2019 Xiph.Org Foundation

Ogg Container Format

libogg documentation

libogg release 1.3.4 - 20190830

+ + + + diff --git a/extern/ogg/doc/libogg/decoding.html b/extern/ogg/doc/libogg/decoding.html new file mode 100644 index 0000000..ec90c7d --- /dev/null +++ b/extern/ogg/doc/libogg/decoding.html @@ -0,0 +1,104 @@ + + + +libogg - Decoding + + + + + + + + + +

libogg documentation

libogg release 1.3.4 - 20190830

+ +

Decoding

+

Libogg contains a set of functions used in the decoding process. +

+All the libogg specific functions are declared in "ogg/ogg.h". +

+

Decoding is based around the ogg synchronization layer. The ogg_sync_state struct coordinates between incoming data and the decoder. We read data into the synchronization layer, submit the data to the stream, and output raw packets to the decoder. +

Decoding through the Ogg layer follows a specific logical sequence. A read loop follows these logical steps: +

+

In practice, streams are more complex, and Ogg also must handle headers, incomplete or dropped pages, and other errors in input. +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
functionpurpose
ogg_sync_initInitializes an Ogg bitstream.
ogg_sync_clearClears the status information from the synchronization struct. +
ogg_sync_resetResets the synchronization status to initial values.
ogg_sync_destroyFrees the synchronization struct.
ogg_sync_checkCheck for asynchronous errors.
ogg_sync_bufferExposes a buffer from the synchronization layer in order to read data.
ogg_sync_wroteTells the synchronization layer how many bytes were written into the buffer.
ogg_sync_pageseekFinds the borders of pages and resynchronizes the stream.
ogg_sync_pageoutOutputs a page from the synchronization layer.
ogg_stream_pageinSubmits a complete page to the stream layer.
ogg_stream_packetoutOutputs a packet to the codec-specific decoding engine.
ogg_stream_packetpeekProvides access to the next packet in the bitstream without +advancing decoding.
+ +

+


+ + + + + + + + +

copyright © 2000-2019 Xiph.Org Foundation

Ogg Container Format

libogg documentation

libogg release 1.3.4 - 20190830

+ + + + diff --git a/extern/ogg/doc/libogg/encoding.html b/extern/ogg/doc/libogg/encoding.html new file mode 100644 index 0000000..cda5d24 --- /dev/null +++ b/extern/ogg/doc/libogg/encoding.html @@ -0,0 +1,76 @@ + + + +libogg - Encoding + + + + + + + + + +

libogg documentation

libogg release 1.3.4 - 20190830

+ +

Encoding

+

Libogg contains a set of functions used in the encoding process. +

+All the libogg specific functions are declared in "ogg/ogg.h". +

+

When encoding, the encoding engine will output raw packets which must be placed into an Ogg bitstream. +

Raw packets are inserted into the stream, and an ogg_page is output when enough packets have been written to create a full page. The pages output are pointers to buffered packet segments, and can then be written out and saved as an ogg stream. +

There are a couple of basic steps: +

    +
  • Use the encoding engine to produce a raw packet of data. +
  • Call ogg_stream_packetin to submit a raw packet to the stream. +
  • Use ogg_stream_pageout to output a page, if enough data has been submitted. Otherwise, continue submitting data. +
+

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
functionpurpose
ogg_stream_packetinSubmits a raw packet to the streaming layer, so that it can be formed into a page.
ogg_stream_ioveciniovec version of ogg_stream_packetin() above.
ogg_stream_pageoutOutputs a completed page if the stream contains enough packets to form a full page. +
ogg_stream_pageout_fillSimilar to ogg_stream_pageout(), but specifies a page spill threshold in bytes. +
ogg_stream_flushForces any remaining packets in the stream to be returned as a page of any size. +
ogg_stream_flush_fillSimilar to ogg_stream_flush(), but specifies a page spill threshold in bytes. +
+ +

+
+ + + + + + + + +

copyright © 2000-2019 Xiph.Org Foundation

Ogg Container Format

libogg documentation

libogg release 1.3.4 - 20190830

+ + + + diff --git a/extern/ogg/doc/libogg/general.html b/extern/ogg/doc/libogg/general.html new file mode 100644 index 0000000..7e7ca45 --- /dev/null +++ b/extern/ogg/doc/libogg/general.html @@ -0,0 +1,109 @@ + + + +libogg - General Functions + + + + + + + + + +

libogg documentation

libogg release 1.3.4 - 20190830

+ +

General Functions

+

Libogg contains several functions which are generally useful when using Ogg streaming, whether encoding or decoding. +

+All the libogg specific functions are declared in "ogg/ogg.h". +

+

These functions can be used to manipulate some of the basic elements of Ogg - streams and pages. Streams and pages are important during both the encode and decode process. +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
functionpurpose
ogg_stream_initInitializes an Ogg bitstream.
ogg_stream_clearClears the storage within the Ogg stream, but does not free the stream itself. +
ogg_stream_resetResets the stream status to its initial position.
ogg_stream_destroyFrees the entire Ogg stream.
ogg_stream_checkCheck for asynchronous errors.
ogg_stream_eosIndicates whether we are at the end of the stream.
ogg_page_versionReturns the version of ogg_page that this stream/page uses
ogg_page_continuedIndicates if the current page contains a continued packet from the last page.
ogg_page_packetsIndicates the number of packets contained in a page.
ogg_page_bosIndicates if the current page is the beginning of the stream.
ogg_page_eosIndicates if the current page is the end of the stream.
ogg_page_granuleposReturns the precise playback location of this page.
ogg_page_serialnoReturns the unique serial number of the logical bitstream associated with this page.
ogg_page_pagenoReturns the sequential page number for this page.
ogg_packet_clearClears the ogg_packet structure.
ogg_page_checksum_setChecksums an ogg_page.
+ +

+


+ + + + + + + + +

copyright © 2000-2019 Xiph.Org Foundation

Ogg Container Format

libogg documentation

libogg release 1.3.4 - 20190830

+ + + + diff --git a/extern/ogg/doc/libogg/index.html b/extern/ogg/doc/libogg/index.html new file mode 100644 index 0000000..fb410cb --- /dev/null +++ b/extern/ogg/doc/libogg/index.html @@ -0,0 +1,39 @@ + + + +libogg - Documentation + + + + + + + + + +

libogg documentation

libogg release 1.3.4 - 20190830

+ +

Libogg Documentation

+ +

+Libogg contains necessary functionality to create, decode, and work with Ogg bitstreams. +

This document explains how to use the libogg API in detail. +

+libogg api overview
+libogg api reference
+ +

+


+ + + + + + + + +

copyright © 2000-2019 Xiph.Org Foundation

Ogg Container Format

libogg documentation

libogg release 1.3.4 - 20190830

+ + + + diff --git a/extern/ogg/doc/libogg/ogg_iovec_t.html b/extern/ogg/doc/libogg/ogg_iovec_t.html new file mode 100644 index 0000000..589c4ba --- /dev/null +++ b/extern/ogg/doc/libogg/ogg_iovec_t.html @@ -0,0 +1,62 @@ + + + +libogg - datatype - ogg_iovec_t + + + + + + + + + +

libogg documentation

libogg release 1.3.4 - 20190830

+ +

ogg_iovec_t

+ +

declared in "ogg/ogg.h"

+ +

+The ogg_iovec_t struct encapsulates a length-encoded buffer. An array +of ogg_iovec_t is used to pass a list of buffers to functions that +accept data in ogg_iovec_t* form. +

+ + + + + +
+

+typedef struct {
+  void *iov_base;
+  size_t iov_len;
+} ogg_iovec_t;
+
+
+ +

Relevant Struct Members

+
+
iov_base
+
Pointer to the buffer data.
+
iov_len
+
Length of buffer data in bytes.
+
+ + +

+
+ + + + + + + + +

copyright © 2000-2019 Xiph.Org Foundation

Ogg Container Format

libogg documentation

libogg release 1.3.4 - 20190830

+ + + + diff --git a/extern/ogg/doc/libogg/ogg_packet.html b/extern/ogg/doc/libogg/ogg_packet.html new file mode 100644 index 0000000..1ef7613 --- /dev/null +++ b/extern/ogg/doc/libogg/ogg_packet.html @@ -0,0 +1,75 @@ + + + +libogg - datatype - ogg_packet + + + + + + + + + +

libogg documentation

libogg release 1.3.4 - 20190830

+ +

ogg_packet

+ +

declared in "ogg/ogg.h"

+ +

+The ogg_packet struct encapsulates the data for a single raw packet of data +and is used to transfer data between the ogg framing layer and the handling codec. +

+ + + + + +
+

+typedef struct {
+  unsigned char *packet;
+  long  bytes;
+  long  b_o_s;
+  long  e_o_s;
+
+  ogg_int64_t  granulepos;
+  ogg_int64_t  packetno;
+
+} ogg_packet;
+
+
+ +

Relevant Struct Members

+
+
packet
+
Pointer to the packet's data. This is treated as an opaque type by the ogg layer.
+
bytes
+
Indicates the size of the packet data in bytes. Packets can be of arbitrary size.
+
b_o_s
+
Flag indicating whether this packet begins a logical bitstream. 1 indicates this is the first packet, 0 indicates any other position in the stream.
+
e_o_s
+
Flag indicating whether this packet ends a bitstream. 1 indicates the last packet, 0 indicates any other position in the stream.
+
granulepos
+
A number indicating the position of this packet in the decoded data. This is the last sample, frame or other unit of information ('granule') that can be completely decoded from this packet.
+
packetno
+
Sequential number of this packet in the ogg bitstream.
+
+ + +

+
+ + + + + + + + +

copyright © 2000-2019 Xiph.Org Foundation

Ogg Container Format

libogg documentation

libogg release 1.3.4 - 20190830

+ + + + diff --git a/extern/ogg/doc/libogg/ogg_packet_clear.html b/extern/ogg/doc/libogg/ogg_packet_clear.html new file mode 100644 index 0000000..0f291cd --- /dev/null +++ b/extern/ogg/doc/libogg/ogg_packet_clear.html @@ -0,0 +1,64 @@ + + + +libogg - function - ogg_packet_clear + + + + + + + + + +

libogg documentation

libogg release 1.3.4 - 20190830

+ +

ogg_packet_clear

+ +

declared in "ogg/ogg.h";

+ +

This function clears the memory used by the ogg_packet struct, +but does not free the structure itself. +It unconditionally frees the packet data buffer, +then it zeros all structure members. +

+ + + + +
+

+void ogg_packet_clear(ogg_packet *op);
+
+
+ +

Parameters

+
+
op
+
Pointer to the ogg_packet struct to be cleared.
+
+ + +

Return Values

+
+
  • +None.
  • +
    +

    + +

    +


    + + + + + + + + +

    copyright © 2000-2019 Xiph.Org Foundation

    Ogg Container Format

    libogg documentation

    libogg release 1.3.4 - 20190830

    + + + + + diff --git a/extern/ogg/doc/libogg/ogg_page.html b/extern/ogg/doc/libogg/ogg_page.html new file mode 100644 index 0000000..1a47bd3 --- /dev/null +++ b/extern/ogg/doc/libogg/ogg_page.html @@ -0,0 +1,75 @@ + + + +libogg - datatype - ogg_page + + + + + + + + + +

    libogg documentation

    libogg release 1.3.4 - 20190830

    + +

    ogg_page

    + +

    declared in "ogg/ogg.h"

    + +

    +The ogg_page struct encapsulates the data for an Ogg page. +

    +Ogg pages are the fundamental unit of framing and interleave in an ogg bitstream. +They are made up of packet segments of 255 bytes each. There can be as many as +255 packet segments per page, for a maximum page size of a little under 64 kB. +This is not a practical limitation as the segments can be joined across +page boundaries allowing packets of arbitrary size. In practice many +applications will not completely fill all pages because they flush the +accumulated packets periodically order to bound latency more tightly. +

    +

    For a complete description of ogg pages and headers, please refer to the framing document. + + + + + +
    +
    
    +typedef struct {
    +  unsigned char *header;
    +  long           header_len;
    +  unsigned char *body;
    +  long           body_len;
    +} ogg_page;
    +
    +
    + +

    Relevant Struct Members

    +
    +
    header
    +
    Pointer to the page header for this page. The exact contents of this header are defined in the framing spec document.
    +
    header_len
    +
    Length of the page header in bytes. +
    body
    +
    Pointer to the data for this page.
    +
    body_len
    +
    Length of the body data in bytes.
    +
    + + +

    +
    + + + + + + + + +

    copyright © 2000-2019 Xiph.Org Foundation

    Ogg Container Format

    libogg documentation

    libogg release 1.3.4 - 20190830

    + + + + diff --git a/extern/ogg/doc/libogg/ogg_page_bos.html b/extern/ogg/doc/libogg/ogg_page_bos.html new file mode 100644 index 0000000..a30d96c --- /dev/null +++ b/extern/ogg/doc/libogg/ogg_page_bos.html @@ -0,0 +1,65 @@ + + + +libogg - function - ogg_page_bos + + + + + + + + + +

    libogg documentation

    libogg release 1.3.4 - 20190830

    + +

    ogg_page_bos

    + +

    declared in "ogg/ogg.h";

    + +

    Indicates whether this page is at the beginning of the logical bitstream. +

    +

    + + + + +
    +
    
    +int ogg_page_bos(ogg_page *og);
    +
    +
    +
    + +

    Parameters

    +
    +
    og
    +
    Pointer to the current ogg_page struct.
    +
    + + +

    Return Values

    +
    +
  • +greater than 0 if this page is the beginning of a bitstream.
  • +
  • +0 if this page is from any other location in the stream.
  • +
    +

    + +

    +


    + + + + + + + + +

    copyright © 2000-2019 Xiph.Org Foundation

    Ogg Container Format

    libogg documentation

    libogg release 1.3.4 - 20190830

    + + + + + diff --git a/extern/ogg/doc/libogg/ogg_page_checksum_set.html b/extern/ogg/doc/libogg/ogg_page_checksum_set.html new file mode 100644 index 0000000..a4bd08e --- /dev/null +++ b/extern/ogg/doc/libogg/ogg_page_checksum_set.html @@ -0,0 +1,62 @@ + + + +libogg - function - ogg_page_checksum_set + + + + + + + + + +

    libogg documentation

    libogg release 1.3.4 - 20190830

    + +

    ogg_page_checksum_set

    + +

    declared in "ogg/ogg.h";

    + +

    Checksums an ogg_page. +

    +

    + + + + +
    +
    
    +int ogg_page_checksum_set(ogg_page *og);
    +
    +
    +
    + +

    Parameters

    +
    +
    og
    +
    Pointer to an ogg_page struct.
    +
    + + +

    Return Values

    +
    +None. +
    +

    + +

    +


    + + + + + + + + +

    copyright © 2000-2019 Xiph.Org Foundation

    Ogg Container Format

    libogg documentation

    libogg release 1.3.4 - 20190830

    + + + + + diff --git a/extern/ogg/doc/libogg/ogg_page_continued.html b/extern/ogg/doc/libogg/ogg_page_continued.html new file mode 100644 index 0000000..a2bbab0 --- /dev/null +++ b/extern/ogg/doc/libogg/ogg_page_continued.html @@ -0,0 +1,64 @@ + + + +libogg - function - ogg_page_version + + + + + + + + + +

    libogg documentation

    libogg release 1.3.4 - 20190830

    + +

    ogg_page_continued

    + +

    declared in "ogg/ogg.h";

    + +

    Indicates whether this page contains packet data which has been continued from the previous page. +

    + + + + +
    +
    
    +int ogg_page_continued(ogg_page *og);
    +
    +
    +
    + +

    Parameters

    +
    +
    og
    +
    Pointer to the current ogg_page struct.
    +
    + + +

    Return Values

    +
    +
  • +1 if this page contains packet data continued from the last page.
  • +
  • +0 if this page does not contain continued data.
  • +
    +

    + +

    +


    + + + + + + + + +

    copyright © 2000-2019 Xiph.Org Foundation

    Ogg Container Format

    libogg documentation

    libogg release 1.3.4 - 20190830

    + + + + + diff --git a/extern/ogg/doc/libogg/ogg_page_eos.html b/extern/ogg/doc/libogg/ogg_page_eos.html new file mode 100644 index 0000000..1fd62a3 --- /dev/null +++ b/extern/ogg/doc/libogg/ogg_page_eos.html @@ -0,0 +1,65 @@ + + + +libogg - function - ogg_page_eos + + + + + + + + + +

    libogg documentation

    libogg release 1.3.4 - 20190830

    + +

    ogg_page_eos

    + +

    declared in "ogg/ogg.h";

    + +

    Indicates whether this page is at the end of the logical bitstream. +

    +

    + + + + +
    +
    
    +int ogg_page_eos(ogg_page *og);
    +
    +
    +
    + +

    Parameters

    +
    +
    og
    +
    Pointer to the current ogg_page struct.
    +
    + + +

    Return Values

    +
    +
  • +greater than zero if this page contains the end of a bitstream.
  • +
  • +0 if this page is from any other location in the stream.
  • +
    +

    + +

    +


    + + + + + + + + +

    copyright © 2000-2019 Xiph.Org Foundation

    Ogg Container Format

    libogg documentation

    libogg release 1.3.4 - 20190830

    + + + + + diff --git a/extern/ogg/doc/libogg/ogg_page_granulepos.html b/extern/ogg/doc/libogg/ogg_page_granulepos.html new file mode 100644 index 0000000..f82fb5f --- /dev/null +++ b/extern/ogg/doc/libogg/ogg_page_granulepos.html @@ -0,0 +1,65 @@ + + + +libogg - function - ogg_page_granulepos + + + + + + + + + +

    libogg documentation

    libogg release 1.3.4 - 20190830

    + +

    ogg_page_granulepos

    + +

    declared in "ogg/ogg.h";

    + +

    Returns the exact granular position of the packet data contained at the end of this page. +

    This is useful for tracking location when seeking or decoding. +

    For example, in audio codecs this position is the pcm sample number and in video this is the frame number. +

    +

    + + + + +
    +
    
    +ogg_in64_t ogg_page_granulepos(ogg_page *og);
    +
    +
    +
    + +

    Parameters

    +
    +
    og
    +
    Pointer to the current ogg_page struct.
    +
    + + +

    Return Values

    +
    +
  • +n is the specific last granular position of the decoded data contained in the page.
  • +
    +

    + +

    +


    + + + + + + + + +

    copyright © 2000-2019 Xiph.Org Foundation

    Ogg Container Format

    libogg documentation

    libogg release 1.3.4 - 20190830

    + + + + + diff --git a/extern/ogg/doc/libogg/ogg_page_packets.html b/extern/ogg/doc/libogg/ogg_page_packets.html new file mode 100644 index 0000000..01c7785 --- /dev/null +++ b/extern/ogg/doc/libogg/ogg_page_packets.html @@ -0,0 +1,75 @@ + + + +libogg - function - ogg_page_packets + + + + + + + + + +

    libogg documentation

    libogg release 1.3.4 - 20190830

    + +

    ogg_page_packets

    + +

    declared in "ogg/ogg.h";

    + +

    Returns the number of packets that are completed on this page. If the +leading packet is begun on a previous page, but ends on this page, it's +counted. +

    +

    + + + + +
    +
    
    +int ogg_page_packets(ogg_page *og);
    +
    +
    +
    + +

    Parameters

    +
    +
    og
    +
    Pointer to the current ogg_page struct.
    +
    + + +

    Return Values

    +
    +If a page consists of a packet begun on a previous page, and a new packet +begun (but not completed) on this page, the return will be:
    +
    +ogg_page_packets(page) will return 1,
    +ogg_page_continued(paged) will return non-zero.
    +

    +If a page happens to be a single packet that was begun on a previous page, and +spans to the next page (in the case of a three or more page packet), the +return will be:
    +
    +ogg_page_packets(page) will return 0,
    +ogg_page_continued(page) will return non-zero.
    +
    +

    + +

    +


    + + + + + + + + +

    copyright © 2000-2019 Xiph.Org Foundation

    Ogg Container Format

    libogg documentation

    libogg release 1.3.4 - 20190830

    + + + + + diff --git a/extern/ogg/doc/libogg/ogg_page_pageno.html b/extern/ogg/doc/libogg/ogg_page_pageno.html new file mode 100644 index 0000000..d975aa0 --- /dev/null +++ b/extern/ogg/doc/libogg/ogg_page_pageno.html @@ -0,0 +1,63 @@ + + + +libogg - function - ogg_page_pageno + + + + + + + + + +

    libogg documentation

    libogg release 1.3.4 - 20190830

    + +

    ogg_page_pageno

    + +

    declared in "ogg/ogg.h";

    + +

    Returns the sequential page number. +

    This is useful for ordering pages or determining when pages have been lost. +

    + + + + +
    +
    
    +long ogg_page_pageno(ogg_page *og);
    +
    +
    +
    + +

    Parameters

    +
    +
    og
    +
    Pointer to the current ogg_page struct.
    +
    + + +

    Return Values

    +
    +
  • +n is the page number for this page.
  • +
    +

    + +

    +


    + + + + + + + + +

    copyright © 2000-2019 Xiph.Org Foundation

    Ogg Container Format

    libogg documentation

    libogg release 1.3.4 - 20190830

    + + + + + diff --git a/extern/ogg/doc/libogg/ogg_page_serialno.html b/extern/ogg/doc/libogg/ogg_page_serialno.html new file mode 100644 index 0000000..a5df3e9 --- /dev/null +++ b/extern/ogg/doc/libogg/ogg_page_serialno.html @@ -0,0 +1,63 @@ + + + +libogg - function - ogg_page_serialno + + + + + + + + + +

    libogg documentation

    libogg release 1.3.4 - 20190830

    + +

    ogg_page_serialno

    + +

    declared in "ogg/ogg.h";

    + +

    Returns the unique serial number for the logical bitstream of this page. Each page contains the serial number for the logical bitstream that it belongs to. +

    +

    + + + + +
    +
    
    +int ogg_page_serialno(ogg_page *og);
    +
    +
    +
    + +

    Parameters

    +
    +
    og
    +
    Pointer to the current ogg_page struct.
    +
    + + +

    Return Values

    +
    +
  • +n is the serial number for this page.
  • +
    +

    + +

    +


    + + + + + + + + +

    copyright © 2000-2019 Xiph.Org Foundation

    Ogg Container Format

    libogg documentation

    libogg release 1.3.4 - 20190830

    + + + + + diff --git a/extern/ogg/doc/libogg/ogg_page_version.html b/extern/ogg/doc/libogg/ogg_page_version.html new file mode 100644 index 0000000..5727104 --- /dev/null +++ b/extern/ogg/doc/libogg/ogg_page_version.html @@ -0,0 +1,63 @@ + + + +libogg - function - ogg_page_version + + + + + + + + + +

    libogg documentation

    libogg release 1.3.4 - 20190830

    + +

    ogg_page_version

    + +

    declared in "ogg/ogg.h";

    + +

    This function returns the version of ogg_page used in this page. +

    In current versions of libogg, all ogg_page structs have the same version, so 0 should always be returned. +

    + + + + +
    +
    
    +int ogg_page_version(ogg_page *og);
    +
    +
    +
    + +

    Parameters

    +
    +
    og
    +
    Pointer to the current ogg_page struct.
    +
    + + +

    Return Values

    +
    +
  • +n is the version number. In the current version of Ogg, the version number is always 0. Nonzero return values indicate an error in page encoding.
  • +
    +

    + +

    +


    + + + + + + + + +

    copyright © 2000-2019 Xiph.Org Foundation

    Ogg Container Format

    libogg documentation

    libogg release 1.3.4 - 20190830

    + + + + + diff --git a/extern/ogg/doc/libogg/ogg_stream_check.html b/extern/ogg/doc/libogg/ogg_stream_check.html new file mode 100644 index 0000000..016fa27 --- /dev/null +++ b/extern/ogg/doc/libogg/ogg_stream_check.html @@ -0,0 +1,71 @@ + + + +libogg - function - ogg_stream_check + + + + + + + + + +

    libogg documentation

    libogg release 1.3.4 - 20190830

    + +

    ogg_stream_check

    + +

    declared in "ogg/ogg.h";

    + +

    This function is used to check the error or readiness condition of an ogg_stream_state structure. +

    It is safe practice to ignore unrecoverable errors (such as an internal error caused by a malloc() failure) returned by ogg stream synchronization calls. Should an +internal error occur, the ogg_stream_state structure will be cleared (equivalent to a +call to +ogg_stream_clear) and subsequent calls +using this ogg_stream_state will be +noops. Error detection is then handled via a single call to +ogg_stream_check at the end of the operational block.

    + +

    + + + + +
    +
    
    +int ogg_stream_check(ogg_stream_state *os);
    +
    +
    + +

    Parameters

    +
    +
    os
    +
    Pointer to a previously declared ogg_stream_state struct.
    +
    + + +

    Return Values

    +
    +
  • +0 is returned if the ogg_stream_state structure is initialized and ready.
  • +
  • +nonzero is returned if the structure was never initialized, or if an unrecoverable internal error occurred in a previous call using the passed in ogg_stream_state struct.
  • +
    +

    + +

    +


    + + + + + + + + +

    copyright © 2000-2019 Xiph.Org Foundation

    Ogg Container Format

    libogg documentation

    libogg release 1.3.4 - 20190830

    + + + + + diff --git a/extern/ogg/doc/libogg/ogg_stream_clear.html b/extern/ogg/doc/libogg/ogg_stream_clear.html new file mode 100644 index 0000000..8d771f8 --- /dev/null +++ b/extern/ogg/doc/libogg/ogg_stream_clear.html @@ -0,0 +1,61 @@ + + + +libogg - function - ogg_stream_clear + + + + + + + + + +

    libogg documentation

    libogg release 1.3.4 - 20190830

    + +

    ogg_stream_clear

    + +

    declared in "ogg/ogg.h";

    + +

    This function clears and frees the internal memory used by the ogg_stream_state struct, but does not free the structure itself. It is safe to call ogg_stream_clear on the same structure more than once. +

    + + + + +
    +
    
    +int ogg_stream_clear(ogg_stream_state *os);
    +
    +
    + +

    Parameters

    +
    +
    os
    +
    Pointer to the ogg_stream_state struct to be cleared.
    +
    + + +

    Return Values

    +
    +
  • +0 is always returned.
  • +
    +

    + +

    +


    + + + + + + + + +

    copyright © 2000-2019 Xiph.Org Foundation

    Ogg Container Format

    libogg documentation

    libogg release 1.3.4 - 20190830

    + + + + + diff --git a/extern/ogg/doc/libogg/ogg_stream_destroy.html b/extern/ogg/doc/libogg/ogg_stream_destroy.html new file mode 100644 index 0000000..c24f320 --- /dev/null +++ b/extern/ogg/doc/libogg/ogg_stream_destroy.html @@ -0,0 +1,71 @@ + + + +libogg - function - ogg_stream_destroy + + + + + + + + + +

    libogg documentation

    libogg release 1.3.4 - 20190830

    + +

    ogg_stream_destroy

    + +

    declared in "ogg/ogg.h";

    + +

    This function frees the internal memory used by +the ogg_stream_state struct as +well as the structure itself. + +

    This should be called when you are done working with an ogg stream. +It can also be called to make sure that the struct does not exist.

    + +

    It calls free() on its argument, so if the ogg_stream_state +is not malloc()'d or will otherwise be freed by your own code, use +ogg_stream_clear instead.

    + +

    + + + + +
    +
    
    +int ogg_stream_destroy(ogg_stream_state *os);
    +
    +
    + +

    Parameters

    +
    +
    os
    +
    Pointer to the ogg_stream_state struct to be destroyed.
    +
    + + +

    Return Values

    +
    +
  • +0 is always returned.
  • +
    +

    + +

    +


    + + + + + + + + +

    copyright © 2000-2019 Xiph.Org Foundation

    Ogg Container Format

    libogg documentation

    libogg release 1.3.4 - 20190830

    + + + + + diff --git a/extern/ogg/doc/libogg/ogg_stream_eos.html b/extern/ogg/doc/libogg/ogg_stream_eos.html new file mode 100644 index 0000000..49ce6b5 --- /dev/null +++ b/extern/ogg/doc/libogg/ogg_stream_eos.html @@ -0,0 +1,62 @@ + + + +libogg - function - ogg_stream_eos + + + + + + + + + +

    libogg documentation

    libogg release 1.3.4 - 20190830

    + +

    ogg_stream_eos

    + +

    declared in "ogg/ogg.h";

    + +

    This function indicates whether we have reached the end of the stream or not. +

    + + + + +
    +
    
    +int ogg_stream_eos(ogg_stream_state *os);
    +
    +
    + +

    Parameters

    +
    +
    os
    +
    Pointer to the current ogg_stream_state struct.
    +
    + + +

    Return Values

    +
    +
  • 1 if we are at the end of the stream or an internal error occurred.
  • +
  • +0 if we have not yet reached the end of the stream.
  • +
    +

    + +

    +


    + + + + + + + + +

    copyright © 2000-2019 Xiph.Org Foundation

    Ogg Container Format

    libogg documentation

    libogg release 1.3.4 - 20190830

    + + + + + diff --git a/extern/ogg/doc/libogg/ogg_stream_flush.html b/extern/ogg/doc/libogg/ogg_stream_flush.html new file mode 100644 index 0000000..e155e11 --- /dev/null +++ b/extern/ogg/doc/libogg/ogg_stream_flush.html @@ -0,0 +1,67 @@ + + + +libogg - function - ogg_stream_flush + + + + + + + + + +

    libogg documentation

    libogg release 1.3.4 - 20190830

    + +

    ogg_stream_flush

    + +

    declared in "ogg/ogg.h";

    + +

    This function checks for remaining packets inside the stream and forces remaining packets into a page, regardless of the size of the page. +

    This should only be used when you want to flush an undersized page from the middle of the stream. Otherwise, ogg_stream_pageout or ogg_stream_pageout_fill should always be used. +

    This function can also be used to verify that all packets have been flushed. If the return value is 0, all packets have been placed into a page. Like ogg_stream_pageout, it should generally be called in a loop until available packet data has been flushes, since even a single packet may span multiple pages. + +

    + + + + +
    +
    
    +int ogg_stream_flush(ogg_stream_state *os, ogg_page *og);
    +
    +
    + +

    Parameters

    +
    +
    os
    +
    Pointer to a previously declared ogg_stream_state struct, which represents the current logical bitstream.
    +
    og
    +
    Pointer to a page of data. The remaining packets in the stream will be placed into this page, if any remain. +
    + + +

    Return Values

    +
    +
  • 0 means that all packet data has already been flushed into pages, and there are no packets to put into the page. 0 is also returned in the case of an ogg_stream_state that has been cleared explicitly or implicitly due to an internal error.
  • +
  • +Nonzero means that remaining packets have successfully been flushed into the page.
  • +
    +

    + +

    +


    + + + + + + + + +

    copyright © 2000-2019 Xiph.Org Foundation

    Ogg Container Format

    libogg documentation

    libogg release 1.3.4 - 20190830

    + + + + + diff --git a/extern/ogg/doc/libogg/ogg_stream_flush_fill.html b/extern/ogg/doc/libogg/ogg_stream_flush_fill.html new file mode 100644 index 0000000..84305a5 --- /dev/null +++ b/extern/ogg/doc/libogg/ogg_stream_flush_fill.html @@ -0,0 +1,74 @@ + + + +libogg - function - ogg_stream_flush_fill + + + + + + + + + +

    libogg documentation

    libogg release 1.3.4 - 20190830

    + +

    ogg_stream_flush_fill

    + +

    declared in "ogg/ogg.h";

    + +

    This function flushes available packets into pages, similar to +ogg_stream_flush(), but +allows applications to explicitly request a specific page spill +size.

    + +

    This function checks for remaining packets inside the stream and forces remaining packets into pages of approximately the requested size. +This should be used when you want to flush all remaining data from a stream. ogg_stream_flush may be used instead if a particular page size isn't important. +

    This function can be used to verify that all packets have been flushed. If the return value is 0, all packets have been placed into a page. Generally speaking, it should be called in a loop until all packets are flushed, since even a single packet may span multiple pages. + +

    + + + + +
    +
    
    +int ogg_stream_flush_fill(ogg_stream_state *os, ogg_page *og, int fillbytes);
    +
    +
    + +

    Parameters

    +
    +
    os
    +
    Pointer to a previously declared ogg_stream_state struct, which represents the current logical bitstream.
    +
    og
    +
    Pointer to a page of data. The remaining packets in the stream will be placed into this page, if any remain. +
    fillbytes
    +
    Packet data watermark in bytes.
    +
    + + +

    Return Values

    +
    +
  • 0 means that all packet data has already been flushed into pages, and there are no packets to put into the page. 0 is also returned in the case of an ogg_stream_state that has been cleared explicitly or implicitly due to an internal error.
  • +
  • +Nonzero means that remaining packets have successfully been flushed into the page.
  • +
    +

    + +

    +


    + + + + + + + + +

    copyright © 2000-2019 Xiph.Org Foundation

    Ogg Container Format

    libogg documentation

    libogg release 1.3.4 - 20190830

    + + + + + diff --git a/extern/ogg/doc/libogg/ogg_stream_init.html b/extern/ogg/doc/libogg/ogg_stream_init.html new file mode 100644 index 0000000..25e3ed3 --- /dev/null +++ b/extern/ogg/doc/libogg/ogg_stream_init.html @@ -0,0 +1,66 @@ + + + +libogg - function - ogg_stream_init + + + + + + + + + +

    libogg documentation

    libogg release 1.3.4 - 20190830

    + +

    ogg_stream_init

    + +

    declared in "ogg/ogg.h";

    + +

    This function is used to initialize an ogg_stream_state struct and allocates appropriate memory in preparation for encoding or decoding. +

    It also assigns the stream a given serial number. +

    + + + + +
    +
    
    +int ogg_stream_init(ogg_stream_state *os,int serialno);
    +
    +
    + +

    Parameters

    +
    +
    os
    +
    Pointer to the ogg_stream_state struct that we will be initializing.
    +
    serialno
    +
    Serial number that we will attach to this stream.
    +
    + + +

    Return Values

    +
    +
  • +0 if successful
  • +
  • +-1 if unsuccessful.
  • +
    +

    + +

    +


    + + + + + + + + +

    copyright © 2000-2019 Xiph.Org Foundation

    Ogg Container Format

    libogg documentation

    libogg release 1.3.4 - 20190830

    + + + + + diff --git a/extern/ogg/doc/libogg/ogg_stream_iovecin.html b/extern/ogg/doc/libogg/ogg_stream_iovecin.html new file mode 100644 index 0000000..773e926 --- /dev/null +++ b/extern/ogg/doc/libogg/ogg_stream_iovecin.html @@ -0,0 +1,80 @@ + + + +libogg - function - ogg_stream_iovecin + + + + + + + + + +

    libogg documentation

    libogg release 1.3.4 - 20190830

    + +

    ogg_stream_iovecin

    + +

    declared in "ogg/ogg.h";

    + +

    This function submits packet data (in the form of +an array of ogg_iovec_t, rather than using +an ogg_packet structure) to the +bitstream for page encapsulation. After this is called, more packets +can be submitted, or pages can be written out.

    + +

    In a typical encoding situation, this should be used after filling a +packet with data. +The data in the packet is copied into the internal storage managed by +the ogg_stream_state, so the caller +is free to alter the contents of os after this call has returned. + +

    + + + + +
    +
    
    +int ogg_stream_iovecin(ogg_stream_state *os, ogg_iovec_t *iov, int count, long e_o_s, ogg_int64_t granulepos);
    +
    +
    + +

    Parameters

    +
    +
    os
    +
    Pointer to a previously declared ogg_stream_state struct.
    +
    iov
    +
    Length-encoded buffers held in an array of ogg_iovec_t. +
    count
    +
    Length of the iov array. +
    e_o_s
    +
    End of stream flag, analogous to the e_o_s field in an ogg_packet. +
    granulepos
    +
    Granule position value, analogous to the granpos field in an ogg_packet. +
    + + +

    Return Values

    +
    +
  • +0 returned on success. -1 returned in the event of internal error.
  • +
    +

    + +

    +


    + + + + + + + + +

    copyright © 2000-2019 Xiph.Org Foundation

    Ogg Container Format

    libogg documentation

    libogg release 1.3.4 - 20190830

    + + + + + diff --git a/extern/ogg/doc/libogg/ogg_stream_packetin.html b/extern/ogg/doc/libogg/ogg_stream_packetin.html new file mode 100644 index 0000000..dfc0ab8 --- /dev/null +++ b/extern/ogg/doc/libogg/ogg_stream_packetin.html @@ -0,0 +1,72 @@ + + + +libogg - function - ogg_stream_packetin + + + + + + + + + +

    libogg documentation

    libogg release 1.3.4 - 20190830

    + +

    ogg_stream_packetin

    + +

    declared in "ogg/ogg.h";

    + +

    This function submits a packet to the bitstream for page +encapsulation. After this is called, more packets can be submitted, +or pages can be written out.

    + +

    In a typical encoding situation, this should be used after filling a +packet with data. +The data in the packet is copied into the internal storage managed by +the ogg_stream_state, so the caller +is free to alter the contents of op after this call has returned. + +

    + + + + +
    +
    
    +int ogg_stream_packetin(ogg_stream_state *os,ogg_packet *op);
    +
    +
    + +

    Parameters

    +
    +
    os
    +
    Pointer to a previously declared ogg_stream_state struct.
    +
    op
    +
    Pointer to the packet we are putting into the bitstream. +
    + + +

    Return Values

    +
    +
  • +0 returned on success. -1 returned in the event of internal error.
  • +
    +

    + +

    +


    + + + + + + + + +

    copyright © 2000-2019 Xiph.Org Foundation

    Ogg Container Format

    libogg documentation

    libogg release 1.3.4 - 20190830

    + + + + + diff --git a/extern/ogg/doc/libogg/ogg_stream_packetout.html b/extern/ogg/doc/libogg/ogg_stream_packetout.html new file mode 100644 index 0000000..bf5a7ba --- /dev/null +++ b/extern/ogg/doc/libogg/ogg_stream_packetout.html @@ -0,0 +1,85 @@ + + + +libogg - function - ogg_stream_packetout + + + + + + + + + +

    libogg documentation

    libogg release 1.3.4 - 20190830

    + +

    ogg_stream_packetout

    + +

    declared in "ogg/ogg.h";

    + +

    This function assembles a data packet for output to the codec +decoding engine. The data has already been submitted to the +ogg_stream_state and broken +into segments. Each successive call returns the next complete packet +built from those segments.

    + +

    In a typical decoding situation, this should be used after calling +ogg_stream_pagein() to submit a +page of data to the bitstream. If the function returns 0, more data is +needed and another page should be submitted. A non-zero return value +indicates successful return of a packet.

    + +

    The op is filled in with pointers to memory managed by +the stream state and is only valid until the next call. The client +must copy the packet data if a longer lifetime is required.

    + +

    + + + + +
    +
    
    +int ogg_stream_packetout(ogg_stream_state *os,ogg_packet *op);
    +
    +
    + +

    Parameters

    +
    +
    os
    +
    Pointer to a previously declared ogg_stream_state struct. Before this function is called, an ogg_page should be submitted to the stream using ogg_stream_pagein().
    +
    op
    +
    Pointer to the packet to be filled in with pointers to the new data. +This will typically be submitted to a codec for decode after this +function is called. The pointers are only valid until the next call +on this stream state.
    +
    + + +

    Return Values

    +
    +
      +
    • -1 if we are out of sync and there is a gap in the data. This is usually a recoverable error and subsequent calls to ogg_stream_packetout are likely to succeed. op has not been updated.
    • +
    • 0 if there is insufficient data available to complete a packet, or on unrecoverable internal error occurred. op has not been updated. +
    • 1 if a packet was assembled normally. op contains the next packet from the stream.
    • +
    +
    + +

    + +
    + + + + + + + + + +

    copyright © 2000-2019 Xiph.Org Foundation

    Ogg Container Format

    libogg documentation

    libogg release 1.3.4 - 20190830

    + + + + diff --git a/extern/ogg/doc/libogg/ogg_stream_packetpeek.html b/extern/ogg/doc/libogg/ogg_stream_packetpeek.html new file mode 100644 index 0000000..e62394e --- /dev/null +++ b/extern/ogg/doc/libogg/ogg_stream_packetpeek.html @@ -0,0 +1,85 @@ + + + +libogg - function - ogg_stream_packetpeek + + + + + + + + + +

    libogg documentation

    libogg release 1.3.4 - 20190830

    + +

    ogg_stream_packetpeek

    + +

    declared in "ogg/ogg.h";

    + +

    This function attempts to assemble a raw data packet and returns +it without advancing decoding.

    + +

    In a typical situation, this would be called +speculatively after ogg_stream_pagein() to check +the packet contents before handing it off to a codec for +decompression. To advance page decoding and remove +the packet from the sync structure, call +ogg_stream_packetout().

    + +

    + + + + + +
    +
    
    +int ogg_stream_packetpeek(ogg_stream_state *os,ogg_packet *op);
    +
    +
    + +

    Parameters

    +
    +
    os
    +
    Pointer to a previously declared +ogg_stream_state struct. Before this +function is called, an ogg_page should be +submitted to the stream using +ogg_stream_pagein().
    +
    op
    +
    Pointer to the next packet available in the bitstream, if +any. A NULL value may be passed in the case of a simple "is there a +packet?" check.
    +
    + + +

    Return Values

    +
    +
      +
    • -1 if there's no packet available due to lost sync or a hole in the data.
    • +
    • 0 if there is insufficient data available to complete a packet, or on unrecoverable internal error occurred.
    • +
    • 1 if a packet is available.
    • +
    +
    + + +

    + +
    + + + + + + + + + +

    copyright © 2000-2019 Xiph.Org Foundation

    Ogg Container Format

    libogg documentation

    libogg release 1.3.4 - 20190830

    + + + + + diff --git a/extern/ogg/doc/libogg/ogg_stream_pagein.html b/extern/ogg/doc/libogg/ogg_stream_pagein.html new file mode 100644 index 0000000..b2b5d73 --- /dev/null +++ b/extern/ogg/doc/libogg/ogg_stream_pagein.html @@ -0,0 +1,67 @@ + + + +libogg - function - ogg_stream_pagein + + + + + + + + + +

    libogg documentation

    libogg release 1.3.4 - 20190830

    + +

    ogg_stream_pagein

    + +

    declared in "ogg/ogg.h";

    + +

    This function adds a complete page to the bitstream. +

    In a typical decoding situation, this function would be called after using ogg_sync_pageout to create a valid ogg_page struct. +

    Internally, this function breaks the page into packet segments in preparation for outputting a valid packet to the codec decoding layer. + +

    + + + + +
    +
    
    +int ogg_stream_pagein(ogg_stream_state *os, ogg_page *og);
    +
    +
    + +

    Parameters

    +
    +
    os
    +
    Pointer to a previously declared ogg_stream_state struct, which represents the current logical bitstream.
    +
    og
    +
    Pointer to a page of data. The data inside this page is being submitted to the streaming layer in order to be allocated into packets. +
    + + +

    Return Values

    +
    +
  • -1 indicates failure. This means that the serial number of the page did not match the serial number of the bitstream, the page version was incorrect, or an internal error occurred.
  • +
  • +0 means that the page was successfully submitted to the bitstream.
  • +
    +

    + +

    +


    + + + + + + + + +

    copyright © 2000-2019 Xiph.Org Foundation

    Ogg Container Format

    libogg documentation

    libogg release 1.3.4 - 20190830

    + + + + + diff --git a/extern/ogg/doc/libogg/ogg_stream_pageout.html b/extern/ogg/doc/libogg/ogg_stream_pageout.html new file mode 100644 index 0000000..4e192ed --- /dev/null +++ b/extern/ogg/doc/libogg/ogg_stream_pageout.html @@ -0,0 +1,84 @@ + + + +libogg - function - ogg_stream_pageout + + + + + + + + + +

    libogg documentation

    libogg release 1.3.4 - 20190830

    + +

    ogg_stream_pageout

    + +

    declared in "ogg/ogg.h";

    + +

    This function forms packets into pages.

    + +

    In a typical encoding situation, this would be called after using ogg_stream_packetin() to submit +data packets to the bitstream. Internally, this function assembles +the accumulated packet bodies into an Ogg page suitable for writing +to a stream. The function is typically called in a loop until there +are no more pages ready for output.

    + +

    This function will only return a page when a "reasonable" amount of +packet data is available. Normally this is appropriate since it +limits the overhead of the Ogg page headers in the bitstream, and so +calling ogg_stream_pageout() after ogg_stream_packetin() should be the +common case. Call ogg_stream_flush() +if immediate page generation is desired. This may be occasionally +necessary, for example, to limit the temporal latency of a variable +bitrate stream.

    + +

    + + + + +
    +
    
    +int ogg_stream_pageout(ogg_stream_state *os, ogg_page *og);
    +
    +
    + +

    Parameters

    +
    +
    os
    +
    Pointer to a previously declared ogg_stream struct, which represents the current logical bitstream.
    +
    og
    +
    Pointer to an ogg_page structure to fill +in. Data pointed to is owned by libogg. The structure is valid until the +next call to ogg_stream_pageout(), ogg_stream_packetin(), or +ogg_stream_flush().
    +
    + + +

    Return Values

    +
    +
  • Zero means that insufficient data has accumulated to fill a page, or an internal error occurred. In +this case og is not modified.
  • +
  • Non-zero means that a page has been completed and returned.
  • +
    +

    + +

    +


    + + + + + + + + +

    copyright © 2000-2019 Xiph.Org Foundation

    Ogg Container Format

    libogg documentation

    libogg release 1.3.4 - 20190830

    + + + + + diff --git a/extern/ogg/doc/libogg/ogg_stream_pageout_fill.html b/extern/ogg/doc/libogg/ogg_stream_pageout_fill.html new file mode 100644 index 0000000..a1d1e89 --- /dev/null +++ b/extern/ogg/doc/libogg/ogg_stream_pageout_fill.html @@ -0,0 +1,89 @@ + + + +libogg - function - ogg_stream_pageout_fill + + + + + + + + + +

    libogg documentation

    libogg release 1.3.4 - 20190830

    + +

    ogg_stream_pageout_fill

    + +

    declared in "ogg/ogg.h";

    + +

    This function forms packets into pages, similar +to ogg_stream_pageout(), but +allows applications to explicitly request a specific page spill +size.

    + +

    In a typical encoding situation, this would be called after using ogg_stream_packetin() to submit +data packets to the bitstream. Internally, this function assembles +the accumulated packet bodies into an Ogg page suitable for writing +to a stream. The function is typically called in a loop until there +are no more pages ready for output.

    + +

    This function will return a page when at least four packets have +been accumulated and accumulated packet data meets or exceeds the +specified number of bytes, and/or when the accumulated packet +data meets/exceeds the maximum page size regardless of accumulated +packet count. +Call ogg_stream_flush() or +ogg_stream_flush_fill() if +immediate page generation is desired regardless of accumulated data.

    + +

    + + + + +
    +
    
    +int ogg_stream_pageout_fill(ogg_stream_state *os, ogg_page *og, int fillbytes);
    +
    +
    + +

    Parameters

    +
    +
    os
    +
    Pointer to a previously declared ogg_stream struct, which represents the current logical bitstream.
    +
    og
    +
    Pointer to an ogg_page structure to fill +in. Data pointed to is owned by libogg. The structure is valid until the +next call to ogg_stream_pageout(), ogg_stream_packetin(), or +ogg_stream_flush().
    +
    fillbytes
    +
    Packet data watermark in bytes.
    +
    + + +

    Return Values

    +
    +
  • Zero means that insufficient data has accumulated to fill a page, or an internal error occurred. In +this case og is not modified.
  • +
  • Non-zero means that a page has been completed and returned.
  • +
    +

    + +

    +


    + + + + + + + + +

    copyright © 2000-2019 Xiph.Org Foundation

    Ogg Container Format

    libogg documentation

    libogg release 1.3.4 - 20190830

    + + + + + diff --git a/extern/ogg/doc/libogg/ogg_stream_reset.html b/extern/ogg/doc/libogg/ogg_stream_reset.html new file mode 100644 index 0000000..c3114f0 --- /dev/null +++ b/extern/ogg/doc/libogg/ogg_stream_reset.html @@ -0,0 +1,61 @@ + + + +libogg - function - ogg_stream_reset + + + + + + + + + +

    libogg documentation

    libogg release 1.3.4 - 20190830

    + +

    ogg_stream_reset

    + +

    declared in "ogg/ogg.h";

    + +

    This function sets values in the ogg_stream_state struct back to initial values. +

    + + + + +
    +
    
    +int ogg_stream_reset(ogg_stream_state *os);
    +
    +
    + +

    Parameters

    +
    +
    os
    +
    Pointer to the ogg_stream_state struct to be reset.
    +
    + + +

    Return Values

    +
    +
  • +0 indicates success. nonzero is returned on internal error.
  • +
    +

    + +

    +


    + + + + + + + + +

    copyright © 2000-2019 Xiph.Org Foundation

    Ogg Container Format

    libogg documentation

    libogg release 1.3.4 - 20190830

    + + + + + diff --git a/extern/ogg/doc/libogg/ogg_stream_reset_serialno.html b/extern/ogg/doc/libogg/ogg_stream_reset_serialno.html new file mode 100644 index 0000000..e35c7c3 --- /dev/null +++ b/extern/ogg/doc/libogg/ogg_stream_reset_serialno.html @@ -0,0 +1,67 @@ + + + +libogg - function - ogg_stream_reset_serialno + + + + + + + + + +

    libogg documentation

    libogg release 1.3.4 - 20190830

    + +

    ogg_stream_reset

    + +

    declared in "ogg/ogg.h";

    + +

    This function reinitializes the values in the +ogg_stream_state, +just like ogg_stream_reset(). +Additionally, it sets the stream serial number to the given value.

    + +

    + + + + +
    +
    
    +int ogg_stream_reset_serialno(ogg_stream_state *os, int serialno);
    +
    +
    + +

    Parameters

    +
    +
    os
    +
    Pointer to the ogg_stream_state struct to be reset.
    +
    serialno
    +
    New stream serial number to use
    +
    + + +

    Return Values

    +
    +
  • +0 indicates success. nonzero is returned on internal error.
  • +
    +

    + +

    +


    + + + + + + + + +

    copyright © 2000-2019 Xiph.Org Foundation

    Ogg Container Format

    libogg documentation

    libogg release 1.3.4 - 20190830

    + + + + + diff --git a/extern/ogg/doc/libogg/ogg_stream_state.html b/extern/ogg/doc/libogg/ogg_stream_state.html new file mode 100644 index 0000000..652b652 --- /dev/null +++ b/extern/ogg/doc/libogg/ogg_stream_state.html @@ -0,0 +1,122 @@ + + + +libogg - datatype - ogg_stream_state + + + + + + + + + +

    libogg documentation

    libogg release 1.3.4 - 20190830

    + +

    ogg_stream_state

    + +

    declared in "ogg/ogg.h"

    + +

    +The ogg_stream_state struct tracks the current encode/decode state +of the current logical bitstream. +

    + + + + + +
    +
    
    +typedef struct {
    +  unsigned char   *body_data;    /* bytes from packet bodies */
    +  long    body_storage;          /* storage elements allocated */
    +  long    body_fill;             /* elements stored; fill mark */
    +  long    body_returned;         /* elements of fill returned */
    +
    +
    +  int     *lacing_vals;      /* The values that will go to the segment table */
    +  ogg_int64_t *granule_vals; /* granulepos values for headers. Not compact
    +                                this way, but it is simple coupled to the
    +                                lacing fifo */
    +  long    lacing_storage;
    +  long    lacing_fill;
    +  long    lacing_packet;
    +  long    lacing_returned;
    +
    +  unsigned char    header[282];      /* working space for header encode */
    +  int              header_fill;
    +
    +  int     e_o_s;          /* set when we have buffered the last packet in the
    +                             logical bitstream */
    +  int     b_o_s;          /* set after we've written the initial page
    +                             of a logical bitstream */
    +  long    serialno;
    +  long    pageno;
    +  ogg_int64_t  packetno;  /* sequence number for decode; the framing
    +                             knows where there's a hole in the data,
    +                             but we need coupling so that the codec
    +                             (which is in a separate abstraction
    +                             layer) also knows about the gap */
    +  ogg_int64_t   granulepos;
    +
    +} ogg_stream_state;
    +
    +
    + +

    Relevant Struct Members

    +
    +
    body_data
    +
    Pointer to data from packet bodies.
    +
    body_storage
    +
    Storage allocated for bodies in bytes (filled or unfilled).
    +
    body_fill
    +
    Amount of storage filled with stored packet bodies.
    +
    body_returned
    +
    Number of elements returned from storage.
    +
    lacing_vals
    +
    String of lacing values for the packet segments within the current page. Each value is a byte, indicating packet segment length.
    +
    granule_vals
    +
    Pointer to the lacing values for the packet segments within the current page.
    +
    lacing_storage
    +
    Total amount of storage (in bytes) allocated for storing lacing values.
    +
    lacing_fill
    +
    Fill marker for the current vs. total allocated storage of lacing values for the page.
    +
    lacing_packet
    +
    Lacing value for current packet segment.
    +
    lacing_returned
    +
    Number of lacing values returned from lacing_storage.
    +
    header
    +
    Temporary storage for page header during encode process, while the header is being created.
    +
    header_fill
    +
    Fill marker for header storage allocation. Used during the header creation process.
    +
    e_o_s
    +
    Marker set when the last packet of the logical bitstream has been buffered.
    +
    b_o_s
    +
    Marker set after we have written the first page in the logical bitstream.
    +
    serialno
    +
    Serial number of this logical bitstream.
    +
    pageno
    +
    Number of the current page within the stream.
    +
    packetno
    +
    Number of the current packet.
    +
    granulepos
    +
    Exact position of decoding/encoding process.
    +
    + + +

    +
    + + + + + + + + +

    copyright © 2000-2019 Xiph.Org Foundation

    Ogg Container Format

    libogg documentation

    libogg release 1.3.4 - 20190830

    + + + + diff --git a/extern/ogg/doc/libogg/ogg_sync_buffer.html b/extern/ogg/doc/libogg/ogg_sync_buffer.html new file mode 100644 index 0000000..34b3fd8 --- /dev/null +++ b/extern/ogg/doc/libogg/ogg_sync_buffer.html @@ -0,0 +1,67 @@ + + + +libogg - function - ogg_sync_buffer + + + + + + + + + +

    libogg documentation

    libogg release 1.3.4 - 20190830

    + +

    ogg_sync_buffer

    + +

    declared in "ogg/ogg.h";

    + +

    This function is used to provide a properly-sized buffer for writing. +

    Buffer space which has already been returned is cleared, and the buffer is extended as necessary by the size plus some additional bytes. Within the current implementation, an extra 4096 bytes are allocated, but applications should not rely on this additional buffer space. +

    The buffer exposed by this function is empty internal storage from the ogg_sync_state struct, beginning at the fill mark within the struct. +

    A pointer to this buffer is returned to be used by the calling application. + +

    + + + + +
    +
    
    +char *ogg_sync_buffer(ogg_sync_state *oy, long size);
    +
    +
    + +

    Parameters

    +
    +
    oy
    +
    Pointer to a previously declared ogg_sync_state struct.
    +
    size
    +
    Size of the desired buffer. The actual size of the buffer returned will be this size plus some extra bytes (currently 4096). +
    + + +

    Return Values

    +
    +
  • +Returns a pointer to the newly allocated buffer or NULL on error
  • +
    +

    + +

    +


    + + + + + + + + +

    copyright © 2000-2019 Xiph.Org Foundation

    Ogg Container Format

    libogg documentation

    libogg release 1.3.4 - 20190830

    + + + + + diff --git a/extern/ogg/doc/libogg/ogg_sync_check.html b/extern/ogg/doc/libogg/ogg_sync_check.html new file mode 100644 index 0000000..1478a12 --- /dev/null +++ b/extern/ogg/doc/libogg/ogg_sync_check.html @@ -0,0 +1,71 @@ + + + +libogg - function - ogg_sync_check + + + + + + + + + +

    libogg documentation

    libogg release 1.3.4 - 20190830

    + +

    ogg_sync_check

    + +

    declared in "ogg/ogg.h";

    + +

    This function is used to check the error or readiness condition of an ogg_sync_state structure. +

    It is safe practice to ignore unrecoverable errors (such as an internal error caused by a malloc() failure) returned by ogg stream synchronization calls. Should an +internal error occur, the ogg_sync_state structure will be cleared (equivalent to a +call to +ogg_sync_clear) and subsequent calls +using this ogg_sync_state will be +noops. Error detection is then handled via a single call to +ogg_sync_check at the end of the operational block.

    + +

    + + + + +
    +
    
    +int ogg_sync_check(ogg_sync_state *oy);
    +
    +
    + +

    Parameters

    +
    +
    oy
    +
    Pointer to a previously declared ogg_sync_state struct.
    +
    + + +

    Return Values

    +
    +
  • +0 is returned if the ogg_sync_state structure is initialized and ready.
  • +
  • +nonzero is returned if the structure was never initialized, or if an unrecoverable internal error occurred in a previous call using the passed in ogg_sync_state struct.
  • +
    +

    + +

    +


    + + + + + + + + +

    copyright © 2000-2019 Xiph.Org Foundation

    Ogg Container Format

    libogg documentation

    libogg release 1.3.4 - 20190830

    + + + + + diff --git a/extern/ogg/doc/libogg/ogg_sync_clear.html b/extern/ogg/doc/libogg/ogg_sync_clear.html new file mode 100644 index 0000000..82cfce8 --- /dev/null +++ b/extern/ogg/doc/libogg/ogg_sync_clear.html @@ -0,0 +1,62 @@ + + + +libogg - function - ogg_sync_clear + + + + + + + + + +

    libogg documentation

    libogg release 1.3.4 - 20190830

    + +

    ogg_sync_clear

    + +

    declared in "ogg/ogg.h";

    + +

    This function is used to free the internal storage of an ogg_sync_state struct and resets the struct to the initial state. To free the entire struct, ogg_sync_destroy should be used instead. In situations where the struct needs to be reset but the internal storage does not need to be freed, ogg_sync_reset should be used. + +

    + + + + +
    +
    
    +int ogg_sync_clear(ogg_sync_state *oy);
    +
    +
    + +

    Parameters

    +
    +
    oy
    +
    Pointer to a previously declared ogg_sync_state struct.
    +
    + + +

    Return Values

    +
    +
  • +0 is always returned.
  • +
    +

    + +

    +


    + + + + + + + + +

    copyright © 2000-2019 Xiph.Org Foundation

    Ogg Container Format

    libogg documentation

    libogg release 1.3.4 - 20190830

    + + + + + diff --git a/extern/ogg/doc/libogg/ogg_sync_destroy.html b/extern/ogg/doc/libogg/ogg_sync_destroy.html new file mode 100644 index 0000000..2ca5499 --- /dev/null +++ b/extern/ogg/doc/libogg/ogg_sync_destroy.html @@ -0,0 +1,68 @@ + + + +libogg - function - ogg_sync_destroy + + + + + + + + + +

    libogg documentation

    libogg release 1.3.4 - 20190830

    + +

    ogg_sync_destroy

    + +

    declared in "ogg/ogg.h";

    + +

    This function is used to destroy an ogg_sync_state struct and free all memory used.

    + +

    Note this calls free() on its argument so you should only use this +function if you've allocated the ogg_sync_state on the heap. If it is +allocated on the stack, or it will otherwise be freed by your +own code, use ogg_sync_clear instead +to release just the internal memory.

    + +

    + + + + +
    +
    
    +int ogg_sync_destroy(ogg_sync_state *oy);
    +
    +
    + +

    Parameters

    +
    +
    oy
    +
    Pointer to a previously declared ogg_sync_state struct.
    +
    + + +

    Return Values

    +
    +
  • +0 is always returned.
  • +
    +

    + +

    +


    + + + + + + + + +

    copyright © 2000-2019 Xiph.Org Foundation

    Ogg Container Format

    libogg documentation

    libogg release 1.3.4 - 20190830

    + + + + + diff --git a/extern/ogg/doc/libogg/ogg_sync_init.html b/extern/ogg/doc/libogg/ogg_sync_init.html new file mode 100644 index 0000000..fac6667 --- /dev/null +++ b/extern/ogg/doc/libogg/ogg_sync_init.html @@ -0,0 +1,63 @@ + + + +libogg - function - ogg_sync_init + + + + + + + + + +

    libogg documentation

    libogg release 1.3.4 - 20190830

    + +

    ogg_sync_init

    + +

    declared in "ogg/ogg.h";

    + +

    This function is used to initialize an ogg_sync_state struct to a known initial value in preparation for manipulation of an Ogg bitstream. +

    The ogg_sync struct is important when decoding, as it synchronizes retrieval and return of data. + +

    + + + + +
    +
    
    +int ogg_sync_init(ogg_sync_state *oy);
    +
    +
    + +

    Parameters

    +
    +
    oy
    +
    Pointer to a previously declared ogg_sync_state struct. After this function call, this struct has been initialized.
    +
    + + +

    Return Values

    +
    +
  • +0 is always returned.
  • +
    +

    + +

    +


    + + + + + + + + +

    copyright © 2000-2019 Xiph.Org Foundation

    Ogg Container Format

    libogg documentation

    libogg release 1.3.4 - 20190830

    + + + + + diff --git a/extern/ogg/doc/libogg/ogg_sync_pageout.html b/extern/ogg/doc/libogg/ogg_sync_pageout.html new file mode 100644 index 0000000..0e37f39 --- /dev/null +++ b/extern/ogg/doc/libogg/ogg_sync_pageout.html @@ -0,0 +1,77 @@ + + + +libogg - function - ogg_sync_pageout + + + + + + + + + +

    libogg documentation

    libogg release 1.3.4 - 20190830

    + +

    ogg_sync_pageout

    + +

    declared in "ogg/ogg.h";

    + +

    This function takes the data stored in the buffer of the ogg_sync_state struct and inserts them into an ogg_page. + +

    In an actual decoding loop, this function should be called first to ensure that the buffer is cleared. The example code below illustrates a clean reading loop which will fill and output pages. +

    Caution:This function should be called before reading into the buffer to ensure that data does not remain in the ogg_sync_state struct. Failing to do so may result in a memory leak. See the example code below for details. + +

    + + + + +
    +
    
    +int ogg_sync_pageout(ogg_sync_state *oy, ogg_page *og);
    +
    +
    + +

    Parameters

    +
    +
    oy
    +
    Pointer to a previously declared ogg_sync_state struct. Normally, the internal storage of this struct should be filled with newly read data and verified using ogg_sync_wrote.
    +
    og
    +
    Pointer to page struct filled by this function. +
    + + +

    Return Values

    +
    +
  • -1 returned if stream has not yet captured sync (bytes were skipped).
  • +
  • 0 returned if more data needed or an internal error occurred.
  • +
  • 1 indicated a page was synced and returned.
  • +
    +

    + +

    Example Usage

    +
    +if (ogg_sync_pageout(&oy, &og) != 1) {
    +	buffer = ogg_sync_buffer(&oy, 8192);
    +	bytes = fread(buffer, 1, 8192, stdin);
    +	ogg_sync_wrote(&oy, bytes);
    +}
    +
    + +

    +
    + + + + + + + + +

    copyright © 2000-2019 Xiph.Org Foundation

    Ogg Container Format

    libogg documentation

    libogg release 1.3.4 - 20190830

    + + + + + diff --git a/extern/ogg/doc/libogg/ogg_sync_pageseek.html b/extern/ogg/doc/libogg/ogg_sync_pageseek.html new file mode 100644 index 0000000..3433e91 --- /dev/null +++ b/extern/ogg/doc/libogg/ogg_sync_pageseek.html @@ -0,0 +1,68 @@ + + + +libogg - function - ogg_sync_pageseek + + + + + + + + + +

    libogg documentation

    libogg release 1.3.4 - 20190830

    + +

    ogg_sync_pageseek

    + +

    declared in "ogg/ogg.h";

    + +

    This function synchronizes the ogg_sync_state struct to the next ogg_page. +

    This is useful when seeking within a bitstream. ogg_sync_pageseek will synchronize to the next page in the bitstream and return information about how many bytes we advanced or skipped in order to do so. + +

    + + + + +
    +
    
    +int ogg_sync_pageseek(ogg_sync_state *oy, ogg_page *og);
    +
    +
    + +

    Parameters

    +
    +
    oy
    +
    Pointer to a previously declared ogg_sync_state struct.
    +
    og
    +
    Pointer to a page (or an incomplete page) of data. This is the page we are attempting to sync. +
    + + +

    Return Values

    +
    +
  • -n means that we skipped n bytes within the bitstream.
  • +
  • +0 means that the page isn't ready and we need more data, or than an internal error occurred. No bytes have been skipped.
  • +
  • +n means that the page was synced at the current location, with a page length of n bytes. +
  • +

    + +

    +


    + + + + + + + + +

    copyright © 2000-2019 Xiph.Org Foundation

    Ogg Container Format

    libogg documentation

    libogg release 1.3.4 - 20190830

    + + + + + diff --git a/extern/ogg/doc/libogg/ogg_sync_reset.html b/extern/ogg/doc/libogg/ogg_sync_reset.html new file mode 100644 index 0000000..bf65345 --- /dev/null +++ b/extern/ogg/doc/libogg/ogg_sync_reset.html @@ -0,0 +1,63 @@ + + + +libogg - function - ogg_sync_reset + + + + + + + + + +

    libogg documentation

    libogg release 1.3.4 - 20190830

    + +

    ogg_sync_reset

    + +

    declared in "ogg/ogg.h";

    + +

    This function is used to reset the internal counters of the ogg_sync_state struct to initial values. +

    It is a good idea to call this before seeking within a bitstream. + +

    + + + + +
    +
    
    +int ogg_sync_reset(ogg_sync_state *oy);
    +
    +
    + +

    Parameters

    +
    +
    oy
    +
    Pointer to a previously declared ogg_sync_state struct.
    +
    + + +

    Return Values

    +
    +
  • +0 is always returned.
  • +
    +

    + +

    +


    + + + + + + + + +

    copyright © 2000-2019 Xiph.Org Foundation

    Ogg Container Format

    libogg documentation

    libogg release 1.3.4 - 20190830

    + + + + + diff --git a/extern/ogg/doc/libogg/ogg_sync_state.html b/extern/ogg/doc/libogg/ogg_sync_state.html new file mode 100644 index 0000000..a274a31 --- /dev/null +++ b/extern/ogg/doc/libogg/ogg_sync_state.html @@ -0,0 +1,77 @@ + + + +libogg - datatype - ogg_sync_state + + + + + + + + + +

    libogg documentation

    libogg release 1.3.4 - 20190830

    + +

    ogg_sync_state

    + +

    declared in "ogg/ogg.h"

    + +

    +The ogg_sync_state struct tracks the synchronization of the current page. +

    It is used during decoding to track the status of data as it is read in, synchronized, verified, and parsed into pages belonging to the various logical bistreams in the current physical bitstream link. +

    + + + + + +
    +
    
    +typedef struct {
    +  unsigned char *data;
    +  int storage;
    +  int fill;
    +  int returned;
    +
    +  int unsynced;
    +  int headerbytes;
    +  int bodybytes;
    +} ogg_sync_state;
    +
    +
    + +

    Relevant Struct Members

    +
    +
    data
    +
    Pointer to buffered stream data.
    +
    storage
    +
    Current allocated size of the stream buffer held in *data.
    +
    fill
    +
    The number of valid bytes currently held in *data; functions as the buffer head pointer.
    +
    returned
    +
    The number of bytes at the head of *data that have already been returned as pages; functions as the buffer tail pointer.
    +
    unsynced
    +
    Synchronization state flag; nonzero if sync has not yet been attained or has been lost.
    +
    headerbytes
    +
    If synced, the number of bytes used by the synced page's header.
    +
    bodybytes
    +
    If synced, the number of bytes used by the synced page's body.
    +
    + + +

    +
    + + + + + + + + +

    copyright © 2000-2019 Xiph.Org Foundation

    Ogg Container Format

    libogg documentation

    libogg release 1.3.4 - 20190830

    + + + + diff --git a/extern/ogg/doc/libogg/ogg_sync_wrote.html b/extern/ogg/doc/libogg/ogg_sync_wrote.html new file mode 100644 index 0000000..e2f4ee5 --- /dev/null +++ b/extern/ogg/doc/libogg/ogg_sync_wrote.html @@ -0,0 +1,73 @@ + + + +libogg - function - ogg_sync_wrote + + + + + + + + + +

    libogg documentation

    libogg release 1.3.4 - 20190830

    + +

    ogg_sync_wrote

    + +

    declared in "ogg/ogg.h";

    + +

    This function is used to tell the ogg_sync_state struct how many bytes we wrote into the buffer. + +

    +The general procedure is to request a pointer into an internal +ogg_sync_state buffer by calling +ogg_sync_buffer(). The buffer +is then filled up to the requested size with new input, and +ogg_sync_wrote() is called to advance the fill pointer by however +much data was actually available.

    + +
    + + + + +
    +
    
    +int ogg_sync_wrote(ogg_sync_state *oy, long bytes);
    +
    +
    + +

    Parameters

    +
    +
    oy
    +
    Pointer to a previously declared ogg_sync_state struct.
    +
    bytes
    +
    Number of bytes of new data written.
    +
    + + +

    Return Values

    +
    +
  • -1 if the number of bytes written overflows the internal storage of the ogg_sync_state struct or an internal error occurred. +
  • +0 in all other cases.
  • +
    + + +

    +
    + + + + + + + + +

    copyright © 2000-2019 Xiph.Org Foundation

    Ogg Container Format

    libogg documentation

    libogg release 1.3.4 - 20190830

    + + + + + diff --git a/extern/ogg/doc/libogg/oggpack_adv.html b/extern/ogg/doc/libogg/oggpack_adv.html new file mode 100644 index 0000000..eb33d1f --- /dev/null +++ b/extern/ogg/doc/libogg/oggpack_adv.html @@ -0,0 +1,64 @@ + + + +libogg - function - oggpack_adv + + + + + + + + + +

    libogg documentation

    libogg release 1.3.4 - 20190830

    + +

    oggpack_adv

    + +

    declared in "ogg/ogg.h";

    + +

    This function advances the location pointer by the specified number of bits without reading any data. + +

    + + + + +
    +
    
    +void  oggpack_adv(oggpack_buffer *b,int bits);
    +
    +
    + +

    Parameters

    +
    +
    b
    +
    Pointer to the current oggpack_buffer.
    +
    bits
    +
    Number of bits to advance.
    +
    + + +

    Return Values

    +
    +
  • +No values are returned.
  • +
    +

    + +

    +


    + + + + + + + + +

    copyright © 2000-2019 Xiph.Org Foundation

    Ogg Container Format

    libogg documentation

    libogg release 1.3.4 - 20190830

    + + + + + diff --git a/extern/ogg/doc/libogg/oggpack_adv1.html b/extern/ogg/doc/libogg/oggpack_adv1.html new file mode 100644 index 0000000..6503edb --- /dev/null +++ b/extern/ogg/doc/libogg/oggpack_adv1.html @@ -0,0 +1,62 @@ + + + +libogg - function - oggpack_adv1 + + + + + + + + + +

    libogg documentation

    libogg release 1.3.4 - 20190830

    + +

    oggpack_adv1

    + +

    declared in "ogg/ogg.h";

    + +

    This function advances the location pointer by one bit without reading any data. + +

    + + + + +
    +
    
    +void  oggpack_adv1(oggpack_buffer *b);
    +
    +
    + +

    Parameters

    +
    +
    b
    +
    Pointer to the current oggpack_buffer.
    +
    + + +

    Return Values

    +
    +
  • No values are returned. +
  • +
    +

    + +

    +


    + + + + + + + + +

    copyright © 2000-2019 Xiph.Org Foundation

    Ogg Container Format

    libogg documentation

    libogg release 1.3.4 - 20190830

    + + + + + diff --git a/extern/ogg/doc/libogg/oggpack_bits.html b/extern/ogg/doc/libogg/oggpack_bits.html new file mode 100644 index 0000000..cfd6897 --- /dev/null +++ b/extern/ogg/doc/libogg/oggpack_bits.html @@ -0,0 +1,62 @@ + + + +libogg - function - oggpack_bits + + + + + + + + + +

    libogg documentation

    libogg release 1.3.4 - 20190830

    + +

    oggpack_bits

    + +

    declared in "ogg/ogg.h";

    + +

    This function returns the total number of bits currently in the oggpack_buffer's internal buffer. + +

    + + + + +
    +
    
    +long oggpack_bits(oggpack_buffer *b);
    +
    +
    + +

    Parameters

    +
    +
    b
    +
    oggpack_buffer struct to be .
    +
    + + +

    Return Values

    +
    +
  • +n is the total number of bits within the current buffer.
  • +
    +

    + +

    +


    + + + + + + + + +

    copyright © 2000-2019 Xiph.Org Foundation

    Ogg Container Format

    libogg documentation

    libogg release 1.3.4 - 20190830

    + + + + + diff --git a/extern/ogg/doc/libogg/oggpack_buffer.html b/extern/ogg/doc/libogg/oggpack_buffer.html new file mode 100644 index 0000000..3783839 --- /dev/null +++ b/extern/ogg/doc/libogg/oggpack_buffer.html @@ -0,0 +1,66 @@ + + + +libogg - datatype - oggpack_buffer + + + + + + + + + +

    libogg documentation

    libogg release 1.3.4 - 20190830

    + +

    oggpack_buffer

    + +

    declared in "ogg/ogg.h"

    + +

    +The oggpack_buffer struct is used with libogg's bitpacking functions. You should never need to directly access anything in this structure. +

    + + + + + +
    +
    
    +typedef struct {
    +  long endbyte;
    +  int  endbit;
    +
    +  unsigned char *buffer;
    +  unsigned char *ptr;
    +  long storage;
    +} oggpack_buffer;
    +
    +
    + +

    Relevant Struct Members

    +
    +
    buffer
    +
    Pointer to data being manipulated.
    +
    ptr
    +
    Location pointer to mark which data has been read.
    +
    storage
    +
    Size of buffer. +
    + + +

    +
    + + + + + + + + +

    copyright © 2000-2019 Xiph.Org Foundation

    Ogg Container Format

    libogg documentation

    libogg release 1.3.4 - 20190830

    + + + + diff --git a/extern/ogg/doc/libogg/oggpack_bytes.html b/extern/ogg/doc/libogg/oggpack_bytes.html new file mode 100644 index 0000000..08fc187 --- /dev/null +++ b/extern/ogg/doc/libogg/oggpack_bytes.html @@ -0,0 +1,67 @@ + + + +libogg - function - oggpack_bytes + + + + + + + + + +

    libogg documentation

    libogg release 1.3.4 - 20190830

    + +

    oggpack_bytes

    + +

    declared in "ogg/ogg.h";

    + +

    This function returns the total number of bytes behind the current +access point in the oggpack_buffer. +For write-initialized buffers, this is the number of complete bytes +written so far. For read-initialized buffers, it is the number of +complete bytes that have been read so far. +

    The return value is the number of complete bytes in the buffer. +There may be extra (<8) bits. +

    + + + + +
    +
    
    +long oggpack_bytes(oggpack_buffer *b);
    +
    +
    + +

    Parameters

    +
    +
    b
    +
    oggpack_buffer struct to be checked.
    +
    + + +

    Return Values

    +
    +
  • +n is the total number of bytes within the current buffer.
  • +
    +

    + +

    +


    + + + + + + + + +

    copyright © 2000-2019 Xiph.Org Foundation

    Ogg Container Format

    libogg documentation

    libogg release 1.3.4 - 20190830

    + + + + + diff --git a/extern/ogg/doc/libogg/oggpack_get_buffer.html b/extern/ogg/doc/libogg/oggpack_get_buffer.html new file mode 100644 index 0000000..5cbab82 --- /dev/null +++ b/extern/ogg/doc/libogg/oggpack_get_buffer.html @@ -0,0 +1,62 @@ + + + +libogg - function - oggpack_get_buffer + + + + + + + + + +

    libogg documentation

    libogg release 1.3.4 - 20190830

    + +

    oggpack_get_buffer

    + +

    declared in "ogg/ogg.h";

    + +

    This function returns a pointer to the data buffer within the given oggpack_buffer struct. + +

    + + + + +
    +
    
    +unsigned char *oggpack_get_buffer(oggpack_buffer *b);
    +
    +
    + +

    Parameters

    +
    +
    b
    +
    Pointer to the current oggpack_buffer.
    +
    + + +

    Return Values

    +
    +
  • +No values are returned.
  • +
    +

    + +

    +


    + + + + + + + + +

    copyright © 2000-2019 Xiph.Org Foundation

    Ogg Container Format

    libogg documentation

    libogg release 1.3.4 - 20190830

    + + + + + diff --git a/extern/ogg/doc/libogg/oggpack_look.html b/extern/ogg/doc/libogg/oggpack_look.html new file mode 100644 index 0000000..27e9b37 --- /dev/null +++ b/extern/ogg/doc/libogg/oggpack_look.html @@ -0,0 +1,66 @@ + + + +libogg - function - oggpack_look + + + + + + + + + +

    libogg documentation

    libogg release 1.3.4 - 20190830

    + +

    oggpack_look

    + +

    declared in "ogg/ogg.h";

    + +

    This function looks at a specified number of bits inside the buffer without advancing the location pointer. +

    The specified number of bits are read, starting from the location pointer. +

    This function can be used to read 32 or fewer bits. + +

    + + + + +
    +
    
    +long  oggpack_look(oggpack_buffer *b,int bits);
    +
    +
    + +

    Parameters

    +
    +
    b
    +
    Pointer to oggpack_buffer to be read.
    +
    bits
    +
    Number of bits to look at. For this function, must be 32 or fewer.
    +
    + + +

    Return Values

    +
    +
  • +n represents the requested bits.
  • +
    +

    + +

    +


    + + + + + + + + +

    copyright © 2000-2019 Xiph.Org Foundation

    Ogg Container Format

    libogg documentation

    libogg release 1.3.4 - 20190830

    + + + + + diff --git a/extern/ogg/doc/libogg/oggpack_look1.html b/extern/ogg/doc/libogg/oggpack_look1.html new file mode 100644 index 0000000..5c84372 --- /dev/null +++ b/extern/ogg/doc/libogg/oggpack_look1.html @@ -0,0 +1,63 @@ + + + +libogg - function - oggpack_look1 + + + + + + + + + +

    libogg documentation

    libogg release 1.3.4 - 20190830

    + +

    oggpack_look1

    + +

    declared in "ogg/ogg.h";

    + +

    This function looks at the next bit without advancing the location pointer. +

    The next bit is read starting from the location pointer. + +

    + + + + +
    +
    
    +long  oggpack_look1(oggpack_buffer *b);
    +
    +
    + +

    Parameters

    +
    +
    b
    +
    Pointer to an oggpack_buffer struct containing our buffer.
    +
    + + +

    Return Values

    +
    +
  • +n represents the value of the next bit after the location pointer.
  • +
    +

    + +

    +


    + + + + + + + + +

    copyright © 2000-2019 Xiph.Org Foundation

    Ogg Container Format

    libogg documentation

    libogg release 1.3.4 - 20190830

    + + + + + diff --git a/extern/ogg/doc/libogg/oggpack_read.html b/extern/ogg/doc/libogg/oggpack_read.html new file mode 100644 index 0000000..127cc2a --- /dev/null +++ b/extern/ogg/doc/libogg/oggpack_read.html @@ -0,0 +1,65 @@ + + + +libogg - function - oggpack_read + + + + + + + + + +

    libogg documentation

    libogg release 1.3.4 - 20190830

    + +

    oggpack_read

    + +

    declared in "ogg/ogg.h";

    + +

    This function reads the requested number of bits from the buffer and advances the location pointer. +

    Before reading, the buffer should be initialized using oggpack_readinit. + +

    + + + + +
    +
    
    +long oggpack_read(oggpack_buffer *b,int bits);
    +
    +
    + +

    Parameters

    +
    +
    b
    +
    Pointer to an oggpack_buffer struct containing buffered data to be read.
    +
    bits
    +
    Number of bits to read.
    +
    + + +

    Return Values

    +
    +
  • +n represents the requested bits.
  • +
    +

    + +

    +


    + + + + + + + + +

    copyright © 2000-2019 Xiph.Org Foundation

    Ogg Container Format

    libogg documentation

    libogg release 1.3.4 - 20190830

    + + + + + diff --git a/extern/ogg/doc/libogg/oggpack_read1.html b/extern/ogg/doc/libogg/oggpack_read1.html new file mode 100644 index 0000000..d3a104c --- /dev/null +++ b/extern/ogg/doc/libogg/oggpack_read1.html @@ -0,0 +1,63 @@ + + + +libogg - function - oggpack_read1 + + + + + + + + + +

    libogg documentation

    libogg release 1.3.4 - 20190830

    + +

    oggpack_read1

    + +

    declared in "ogg/ogg.h";

    + +

    This function reads one bit from the oggpack_buffer data buffer and advances the location pointer. +

    Before reading, the buffer should be initialized using oggpack_readinit. + +

    + + + + +
    +
    
    +long  oggpack_read1(oggpack_buffer *b);
    +
    +
    + +

    Parameters

    +
    +
    b
    +
    Pointer to an oggpack_buffer struct containing buffered data to be read.
    +
    + + +

    Return Values

    +
    +
  • +n is the bit read by this function.
  • +
    +

    + +

    +


    + + + + + + + + +

    copyright © 2000-2019 Xiph.Org Foundation

    Ogg Container Format

    libogg documentation

    libogg release 1.3.4 - 20190830

    + + + + + diff --git a/extern/ogg/doc/libogg/oggpack_readinit.html b/extern/ogg/doc/libogg/oggpack_readinit.html new file mode 100644 index 0000000..3bc4da2 --- /dev/null +++ b/extern/ogg/doc/libogg/oggpack_readinit.html @@ -0,0 +1,64 @@ + + + +libogg - function - oggpack_readinit + + + + + + + + + +

    libogg documentation

    libogg release 1.3.4 - 20190830

    + +

    oggpack_readinit

    + +

    declared in "ogg/ogg.h";

    + +

    This function takes an ordinary buffer and prepares an oggpack_buffer for reading using the Ogg bitpacking functions. + +

    + + + + +
    +
    
    +void oggpack_readinit(oggpack_buffer *b,unsigned char *buf,int bytes);
    +
    +
    + +

    Parameters

    +
    +
    b
    +
    Pointer to oggpack_buffer to be initialized with some extra markers to ease bit navigation and manipulation.
    +
    buf
    +
    Original data buffer, to be inserted into the oggpack_buffer so that it can be read using bitpacking functions. +
    + + +

    Return Values

    +
    +
  • +No values are returned.
  • +
    +

    + +

    +


    + + + + + + + + +

    copyright © 2000-2019 Xiph.Org Foundation

    Ogg Container Format

    libogg documentation

    libogg release 1.3.4 - 20190830

    + + + + + diff --git a/extern/ogg/doc/libogg/oggpack_reset.html b/extern/ogg/doc/libogg/oggpack_reset.html new file mode 100644 index 0000000..0d8b15d --- /dev/null +++ b/extern/ogg/doc/libogg/oggpack_reset.html @@ -0,0 +1,62 @@ + + + +libogg - function - oggpack_reset + + + + + + + + + +

    libogg documentation

    libogg release 1.3.4 - 20190830

    + +

    oggpack_reset

    + +

    declared in "ogg/ogg.h";

    + +

    This function resets the contents of an oggpack_buffer to their original state but does not free the memory used. + +

    + + + + +
    +
    
    +void  oggpack_reset(oggpack_buffer *b);
    +
    +
    + +

    Parameters

    +
    +
    b
    +
    oggpack_buffer to be reset.
    +
    + + +

    Return Values

    +
    +
  • +No values are returned.
  • +
    +

    + +

    +


    + + + + + + + + +

    copyright © 2000-2019 Xiph.Org Foundation

    Ogg Container Format

    libogg documentation

    libogg release 1.3.4 - 20190830

    + + + + + diff --git a/extern/ogg/doc/libogg/oggpack_write.html b/extern/ogg/doc/libogg/oggpack_write.html new file mode 100644 index 0000000..79884a4 --- /dev/null +++ b/extern/ogg/doc/libogg/oggpack_write.html @@ -0,0 +1,68 @@ + + + +libogg - function - oggpack_write + + + + + + + + + +

    libogg documentation

    libogg release 1.3.4 - 20190830

    + +

    oggpack_write

    + +

    declared in "ogg/ogg.h";

    + +

    This function writes bits into an oggpack_buffer. +

    The oggpack_buffer must already be initialized for writing using oggpack_writeinit. +

    Only 32 bits can be written at a time. + +

    + + + + +
    +
    
    +void  oggpack_write(oggpack_buffer *b,unsigned long value,int bits);
    +
    +
    + +

    Parameters

    +
    +
    b
    +
    Buffer to be used for writing.
    +
    value
    +
    The data to be written into the buffer. This must be 32 bits or fewer.
    +
    bits
    +
    The number of bits being written into the buffer.
    +
    + + +

    Return Values

    +
    +
  • +No values are returned.
  • +
    +

    + +

    +


    + + + + + + + + +

    copyright © 2000-2019 Xiph.Org Foundation

    Ogg Container Format

    libogg documentation

    libogg release 1.3.4 - 20190830

    + + + + + diff --git a/extern/ogg/doc/libogg/oggpack_writealign.html b/extern/ogg/doc/libogg/oggpack_writealign.html new file mode 100644 index 0000000..c2769a7 --- /dev/null +++ b/extern/ogg/doc/libogg/oggpack_writealign.html @@ -0,0 +1,65 @@ + + + +libogg - function - oggpack_writealign + + + + + + + + + +

    libogg documentation

    libogg release 1.3.4 - 20190830

    + +

    oggpack_writealign

    + +

    declared in "ogg/ogg.h";

    + +

    This function pads the oggpack_buffer with zeros out to the +next byte boundary.

    +

    The oggpack_buffer must already be initialized for writing using oggpack_writeinit. +

    Only 32 bits can be written at a time.

    + +

    + + + + +
    +
    
    +void  oggpack_writetrunc(oggpack_buffer *b);
    +
    +
    + +

    Parameters

    +
    +
    b
    +
    Buffer to be used for writing.
    +
    + + +

    Return Values

    +
    +
  • +No values are returned.
  • +
    +

    + +

    +


    + + + + + + + + +

    copyright © 2000-2019 Xiph.Org Foundation

    Ogg Container Format

    libogg documentation

    libogg release 1.3.4 - 20190830

    + + + + + diff --git a/extern/ogg/doc/libogg/oggpack_writecheck.html b/extern/ogg/doc/libogg/oggpack_writecheck.html new file mode 100644 index 0000000..15eb554 --- /dev/null +++ b/extern/ogg/doc/libogg/oggpack_writecheck.html @@ -0,0 +1,81 @@ + + + +libogg - function - oggpack_writecheck + + + + + + + + + +

    libogg documentation

    libogg release 1.3.4 - 20190830

    + +

    oggpack_writecheck

    + +

    declared in "ogg/ogg.h";

    + +

    This function checks the readiness status of +an oggpack_buffer previously +initialized for writing using the +Ogg bitpacking functions. A write +buffer that encounters an error (such as a failed malloc) will clear +its internal state and release any in-use memory, flagging itself as +'not ready'. Subsequent attempts to write using the buffer will +silently fail. This error state may be detected at any later time by +using oggpack_writecheck(). It is safe but not necessary to +call oggpack_writeclear() on a buffer that +has flagged an error and released its resources. + +

    Important note to developers: Although libogg checks the +results of memory allocations, these checks are only useful on a +narrow range of embedded platforms. Allocation checks perform no +useful service on a general purpose desktop OS where pages are +routinely overallocated and all allocations succeed whether memory is +available or not. The only way to detect an out of memory condition +on the vast majority of OSes is to watch for and capture segmentation +faults. This function is useful only to embedded developers. + +

    + + + + +
    +
    
    +int  oggpack_writecheck(oggpack_buffer *b);
    +
    +
    + +

    Parameters

    +
    +
    b
    +
    An oggpack_buffer previously initialized for writing.
    +
    + + +

    Return Values

    +
    +
  • zero: buffer is ready for writing
  • +
  • nonzero: buffer is not ready or encountered an error
  • +
    +

    + +

    +


    + + + + + + + + +

    copyright © 2000-2019 Xiph.Org Foundation

    Ogg Container Format

    libogg documentation

    libogg release 1.3.4 - 20190830

    + + + + + diff --git a/extern/ogg/doc/libogg/oggpack_writeclear.html b/extern/ogg/doc/libogg/oggpack_writeclear.html new file mode 100644 index 0000000..a5a40b1 --- /dev/null +++ b/extern/ogg/doc/libogg/oggpack_writeclear.html @@ -0,0 +1,62 @@ + + + +libogg - function - oggpack_reset + + + + + + + + + +

    libogg documentation

    libogg release 1.3.4 - 20190830

    + +

    oggpack_writeclear

    + +

    declared in "ogg/ogg.h";

    + +

    This function clears the buffer after writing and frees the memory used by the oggpack_buffer. + +

    + + + + +
    +
    
    +void oggpack_writeclear(oggpack_buffer *b);
    +
    +
    + +

    Parameters

    +
    +
    b
    +
    Our oggpack_buffer. This is an ordinary data buffer with some extra markers to ease bit navigation and manipulation.
    +
    + + +

    Return Values

    +
    +
  • +No values are returned.
  • +
    +

    + +

    +


    + + + + + + + + +

    copyright © 2000-2019 Xiph.Org Foundation

    Ogg Container Format

    libogg documentation

    libogg release 1.3.4 - 20190830

    + + + + + diff --git a/extern/ogg/doc/libogg/oggpack_writecopy.html b/extern/ogg/doc/libogg/oggpack_writecopy.html new file mode 100644 index 0000000..f274186 --- /dev/null +++ b/extern/ogg/doc/libogg/oggpack_writecopy.html @@ -0,0 +1,69 @@ + + + +libogg - function - oggpack_writecopy + + + + + + + + + +

    libogg documentation

    libogg release 1.3.4 - 20190830

    + +

    oggpack_writecopy

    + +

    declared in "ogg/ogg.h";

    + +

    This function copies a sequence of bits from a source buffer into an +oggpack_buffer.

    +

    The oggpack_buffer must already be initialized for writing using oggpack_writeinit.

    +

    Only 32 bits can be written at a time.

    + +

    + + + + +
    +
    
    +void  oggpack_writecopy(oggpack_buffer *b, void *source, long bits);
    +
    +
    + +

    Parameters

    +
    +
    b
    +
    Buffer to be used for writing.
    +
    source
    +
    A pointer to the data to be written into the buffer.
    +
    bits
    +
    The number of bits to be copied into the buffer.
    +
    + + +

    Return Values

    +
    +
  • +No values are returned.
  • +
    +

    + +

    +


    + + + + + + + + +

    copyright © 2000-2019 Xiph.Org Foundation

    Ogg Container Format

    libogg documentation

    libogg release 1.3.4 - 20190830

    + + + + + diff --git a/extern/ogg/doc/libogg/oggpack_writeinit.html b/extern/ogg/doc/libogg/oggpack_writeinit.html new file mode 100644 index 0000000..752a9e0 --- /dev/null +++ b/extern/ogg/doc/libogg/oggpack_writeinit.html @@ -0,0 +1,62 @@ + + + +libogg - function - oggpack_writeinit + + + + + + + + + +

    libogg documentation

    libogg release 1.3.4 - 20190830

    + +

    oggpack_writeinit

    + +

    declared in "ogg/ogg.h";

    + +

    This function initializes an oggpack_buffer for writing using the Ogg bitpacking functions. + +

    + + + + +
    +
    
    +void  oggpack_writeinit(oggpack_buffer *b);
    +
    +
    + +

    Parameters

    +
    +
    b
    +
    Buffer to be used for writing. This is an ordinary data buffer with some extra markers to ease bit navigation and manipulation.
    +
    + + +

    Return Values

    +
    +
  • +No values are returned.
  • +
    +

    + +

    +


    + + + + + + + + +

    copyright © 2000-2019 Xiph.Org Foundation

    Ogg Container Format

    libogg documentation

    libogg release 1.3.4 - 20190830

    + + + + + diff --git a/extern/ogg/doc/libogg/oggpack_writetrunc.html b/extern/ogg/doc/libogg/oggpack_writetrunc.html new file mode 100644 index 0000000..3b543b6 --- /dev/null +++ b/extern/ogg/doc/libogg/oggpack_writetrunc.html @@ -0,0 +1,65 @@ + + + +libogg - function - oggpack_writetrunc + + + + + + + + + +

    libogg documentation

    libogg release 1.3.4 - 20190830

    + +

    oggpack_writetrunc

    + +

    declared in "ogg/ogg.h";

    + +

    This function truncates an already written-to oggpack_buffer.

    +

    The oggpack_buffer must already be initialized for writing using oggpack_writeinit.

    + +

    + + + + +
    +
    
    +void  oggpack_writetrunc(oggpack_buffer *b, long bits);
    +
    +
    + +

    Parameters

    +
    +
    b
    +
    Buffer to be truncated.
    +
    bits
    +
    Number of bits to keep in the buffer (size after truncation)
    +
    + + +

    Return Values

    +
    +
  • +No values are returned.
  • +
    +

    + +

    +


    + + + + + + + + +

    copyright © 2000-2019 Xiph.Org Foundation

    Ogg Container Format

    libogg documentation

    libogg release 1.3.4 - 20190830

    + + + + + diff --git a/extern/ogg/doc/libogg/overview.html b/extern/ogg/doc/libogg/overview.html new file mode 100644 index 0000000..620688f --- /dev/null +++ b/extern/ogg/doc/libogg/overview.html @@ -0,0 +1,44 @@ + + + +libogg - API Overview + + + + + + + + + +

    libogg documentation

    libogg release 1.3.4 - 20190830

    + +

    Libogg API Overview

    + +

    +The libogg API consists of the following functional categories: +

    +

    + +

    +
    + + + + + + + + +

    copyright © 2000-2019 Xiph.Org Foundation

    Ogg Container Format

    libogg documentation

    libogg release 1.3.4 - 20190830

    + + + + diff --git a/extern/ogg/doc/libogg/reference.html b/extern/ogg/doc/libogg/reference.html new file mode 100644 index 0000000..3fbb95c --- /dev/null +++ b/extern/ogg/doc/libogg/reference.html @@ -0,0 +1,98 @@ + + + +Libogg API Reference + + + + + + + + + +

    libogg documentation

    libogg release 1.3.4 - 20190830

    + +

    Libogg API Reference

    + +

    +Data Structures
    +oggpack_buffer
    +ogg_page
    +ogg_stream_state
    +ogg_packet
    +ogg_sync_state
    +
    +Bitpacking
    +oggpack_writeinit()
    +oggpack_writecheck()
    +oggpack_reset()
    +oggpack_writetrunc()
    +oggpack_writealign()
    +oggpack_writecopy()
    +oggpack_writeclear()
    +oggpack_readinit()
    +oggpack_write()
    +oggpack_look()
    +oggpack_look1()
    +oggpack_adv()
    +oggpack_adv1()
    +oggpack_read()
    +oggpack_read1()
    +oggpack_bytes()
    +oggpack_bits()
    +oggpack_get_buffer()
    +
    +Decoding-Related
    +ogg_sync_init()
    +ogg_sync_check()
    +ogg_sync_clear()
    +ogg_sync_destroy()
    +ogg_sync_reset()
    +ogg_sync_buffer()
    +ogg_sync_wrote()
    +ogg_sync_pageseek()
    +ogg_sync_pageout()
    +ogg_stream_pagein()
    +ogg_stream_packetout()
    +ogg_stream_packetpeek()
    +
    +Encoding-Related
    +ogg_stream_packetin()
    +ogg_stream_pageout()
    +ogg_stream_pageout_fill()
    +ogg_stream_flush()
    +ogg_stream_flush_fill()
    +
    +General
    +ogg_stream_init()
    +ogg_stream_check()
    +ogg_stream_clear()
    +ogg_stream_reset()
    +ogg_stream_reset_serialno()
    +ogg_stream_destroy()
    +ogg_page_version()
    +ogg_page_continued()
    +ogg_page_packets()
    +ogg_page_bos()
    +ogg_page_eos()
    +ogg_page_granulepos()
    +ogg_page_serialno()
    +ogg_page_pageno()
    +ogg_packet_clear()
    +ogg_page_checksum_set()
    +

    +


    + + + + + + + + +

    copyright © 2000-2019 Xiph.Org Foundation

    Ogg Container Format

    libogg documentation

    libogg release 1.3.4 - 20190830

    + + + + diff --git a/extern/ogg/doc/libogg/style.css b/extern/ogg/doc/libogg/style.css new file mode 100644 index 0000000..81cf417 --- /dev/null +++ b/extern/ogg/doc/libogg/style.css @@ -0,0 +1,7 @@ +BODY { font-family: Helvetica, sans-serif } +TD { font-family: Helvetica, sans-serif } +P { font-family: Helvetica, sans-serif } +H1 { font-family: Helvetica, sans-serif } +H2 { font-family: Helvetica, sans-serif } +H4 { font-family: Helvetica, sans-serif } +P.tiny { font-size: 8pt } diff --git a/extern/ogg/doc/multiplex1.png b/extern/ogg/doc/multiplex1.png new file mode 100644 index 0000000..e48d1dd Binary files /dev/null and b/extern/ogg/doc/multiplex1.png differ diff --git a/extern/ogg/doc/multiplex1.svg b/extern/ogg/doc/multiplex1.svg new file mode 100644 index 0000000..46e6d52 --- /dev/null +++ b/extern/ogg/doc/multiplex1.svg @@ -0,0 +1,632 @@ + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + elementary physical bitstream A + logical bitstream A + OggS + OggS + OggS + OggS + OggS + OggS + + + + + + + + + + + + + elementary physical bitstream B + logical bitstream B + OggS + OggS + OggS + OggS + OggS + OggS + + + + + + + + + + + + + + + multiplexed physical bitstream + + + + + + + + + + OggS + OggS + OggS + OggS + OggS + OggS + + diff --git a/extern/ogg/doc/ogg-multiplex.html b/extern/ogg/doc/ogg-multiplex.html new file mode 100644 index 0000000..0674400 --- /dev/null +++ b/extern/ogg/doc/ogg-multiplex.html @@ -0,0 +1,446 @@ + + + + + +Ogg Documentation + + + + + + + + + +

    Page Multiplexing and Ordering in a Physical Ogg Stream

    + +

    The low-level mechanisms of an Ogg stream (as described in the Ogg +Bitstream Overview) provide means for mixing multiple logical streams +and media types into a single linear-chronological stream. This +document specifies the high-level arrangement and use of page +structure to multiplex multiple streams of mixed media type within a +physical Ogg stream.

    + +

    Design Elements

    + +

    The design and arrangement of the Ogg container format is governed by +several high-level design decisions that form the reasoning behind +specific low-level design decisions.

    + +

    Linear media

    + +

    The Ogg bitstream is intended to encapsulate chronological, +time-linear mixed media into a single delivery stream or file. The +design is such that an application can always encode and/or decode a +full-featured bitstream in one pass with no seeking and minimal +buffering. Seeking to provide optimized encoding (such as two-pass +encoding) or interactive decoding (such as scrubbing or instant +replay) is not disallowed or discouraged, however no bitstream feature +must require nonlinear operation on the bitstream.

    + +

    Multiplexing

    + +

    Ogg bitstreams multiplex multiple logical streams into a single +physical stream at the page level. Each page contains an abstract +time stamp (the Granule Position) that represents an absolute time +landmark within the stream. After the pages representing stream +headers (all logical stream headers occur at the beginning of a +physical bitstream section before any logical stream data), logical +stream data pages are arranged in a physical bitstream in strict +non-decreasing order by chronological absolute time as +specified by the granule position.

    + +

    The only exception to arranging pages in strictly ascending time order +by granule position is those pages that do not set the granule +position value. This is a special case when exceptionally large +packets span multiple pages; the specifics of handling this special +case are described later under 'Continuous and Discontinuous +Streams'.

    + +

    Seeking

    + +

    Ogg is designed to use an interpolated bisection search to +implement exact positional seeking. Interpolated bisection search is +a spec-mandated mechanism.

    + +

    An index may improve objective performance, but it seldom +improves subjective performance outside of a few high-latency use +cases and adds no additional functionality as bisection search +delivers the same functionality for both one- and two-pass stream +types. For these reasons, use of indexes is discouraged, except in +cases where an index provides demonstrable and noticeable performance +improvement.

    + +

    Seek operations are by absolute time; a direct bisection search must +find the exact time position requested. Information in the Ogg +bitstream is arranged such that all information to be presented for +playback from the desired seek point will occur at or after the +desired seek point. Seek operations are neither 'fuzzy' nor +heuristic.

    + +

    Although key frame handling in video appears to be an exception to +"all needed playback information lies ahead of a given seek", +key frames can still be handled directly within this indexless +framework. Seeking to a key frame in video (as well as seeking in other +media types with analogous restraints) is handled as two seeks; first +a seek to the desired time which extracts state information that +decodes to the time of the last key frame, followed by a second seek +directly to the key frame. The location of the previous key frame is +embedded as state information in the granulepos; this mechanism is +described in more detail later.

    + +

    Continuous and Discontinuous Streams

    + +

    Logical streams within a physical Ogg stream belong to one of two +categories, "Continuous" streams and "Discontinuous" streams. +Although these are discussed in more detail later, the distinction is +important to a high-level understanding of how to buffer an Ogg +stream.

    + +

    A stream that provides a gapless, time-continuous media type with a +fine-grained timebase is considered to be 'Continuous'. A continuous +stream should never be starved of data. Clear examples of continuous +data types include broadcast audio and video.

    + +

    A stream that delivers data in a potentially irregular pattern or with +widely spaced timing gaps is considered to be 'Discontinuous'. A +discontinuous stream may be best thought of as data representing +scattered events; although they happen in order, they are typically +unconnected data often located far apart. One possible example of a +discontinuous stream types would be captioning. Although it's +possible to design captions as a continuous stream type, it's most +natural to think of captions as widely spaced pieces of text with +little happening between.

    + +

    The fundamental design distinction between continuous and +discontinuous streams concerns buffering.

    + +

    Buffering

    + +

    Because a continuous stream is, by definition, gapless, Ogg buffering +is based on the simple premise of never allowing any active continuous +stream to starve for data during decode; buffering proceeds ahead +until all continuous streams in a physical stream have data ready to +decode on demand.

    + +

    Discontinuous stream data may occur on a fairly regular basis, but the +timing of, for example, a specific caption is impossible to predict +with certainty in most captioning systems. Thus the buffering system +should take discontinuous data 'as it comes' rather than working ahead +(for a potentially unbounded period) to look for future discontinuous +data. As such, discontinuous streams are ignored when managing +buffering; their pages simply 'fall out' of the stream when continuous +streams are handled properly.

    + +

    Buffering requirements need not be explicitly declared or managed for +the encoded stream; the decoder simply reads as much data as is +necessary to keep all continuous stream types gapless (also ensuring +discontinuous data arrives in time) and no more, resulting in optimum +implicit buffer usage for a given stream. Because all pages of all +data types are stamped with absolute timing information within the +stream, inter-stream synchronization timing is always explicitly +maintained without the need for explicitly declared buffer-ahead +hinting.

    + +

    Further details, mechanisms and reasons for the differing arrangement +and behavior of continuous and discontinuous streams is discussed +later.

    + +

    Whole-stream navigation

    + +

    Ogg is designed so that the simplest navigation operations treat the +physical Ogg stream as a whole summary of its streams, rather than +navigating each interleaved stream as a separate entity.

    + +

    First Example: seeking to a desired time position in a multiplexed (or +unmultiplexed) Ogg stream can be accomplished through a bisection +search on time position of all pages in the stream (as encoded in the +granule position). More powerful searches (such as a key frame-aware +seek within video) are also possible with additional search +complexity, but similar computational complexity.

    + +

    Second Example: A bitstream section may consist of three multiplexed +streams of differing lengths. The result of multiplexing these +streams should be thought of as a single mixed stream with a length +equal to the longest of the three component streams. Although it is +also possible to think of the multiplexed results as three concurrent +streams of different lengths and it is possible to recover the three +original streams, it will also become obvious that once multiplexed, +it isn't possible to find the internal lengths of the component +streams without a linear search of the whole bitstream section. +However, it is possible to find the length of the whole bitstream +section easily (in near-constant time per section) just as it is for a +single-media unmultiplexed stream.

    + +

    Granule Position

    + +

    Description

    + +

    The Granule Position is a signed 64 bit field appearing in the header +of every Ogg page. Although the granule position represents absolute +time within a logical stream, its value does not necessarily directly +encode a simple timestamp. It may represent frames elapsed (as in +Vorbis), a simple timestamp, or a more complex bit-division encoding +(such as in Theora). The exact encoding of the granule position is up +to a specific codec.

    + +

    The granule position is governed by the following rules:

    + +
      + +
    • Granule Position must always increase forward or remain equal from +page to page, be unset, or be zero for a header page. The absolute +time to which any correct sequence of granule position maps must +similarly always increase forward or remain equal. (A codec may +make use of data, such as a control sequence, that only affects codec +working state without producing data and thus advancing granule +position and time. Although the packet sequence number increases in +this case, the granule position, and thus the time position, do +not.)
    • + +
    • Granule position may only be unset if there no packet defining a +time boundary on the page (that is, if no packet in a continuous +stream ends on the page, or no packet in a discontinuous stream begins +on the page. This will be discussed in more detail under Continuous +and Discontinuous streams).
    • + +
    • A codec must be able to translate a given granule position value +to a unique, deterministic absolute time value through direct +calculation. A codec is not required to be able to translate an +absolute time value into a unique granule position value.
    • + +
    • Codecs shall choose a granule position definition that allows that +codec means to seek as directly as possible to an immediately +decodable point, such as the bit-divided granule position encoding of +Theora allows the codec to seek efficiently to key frame without using +an index. That is, additional information other than absolute time +may be encoded into a granule position value so long as the granule +position obeys the above points.
    • + +
    + +

    Example: timestamp

    + +

    In general, a codec/stream type should choose the simplest granule +position encoding that addresses its requirements. The examples here +are by no means exhaustive of the possibilities within Ogg.

    + +

    A simple granule position could encode a timestamp directly. For +example, a granule position that encoded milliseconds from beginning +of stream would allow a logical stream length of over 100,000,000,000 +days before beginning a new logical stream (to avoid the granule +position wrapping).

    + +

    Example: framestamp

    + +

    A simple millisecond timestamp granule encoding might suit many stream +types, but a millisecond resolution is inappropriate to, eg, most +audio encodings where exact single-sample resolution is generally a +requirement. A millisecond is both too large a granule and often does +not represent an integer number of samples.

    + +

    In the event that audio frames are always encoded as the same number of +samples, the granule position could simply be a linear count of frames +since beginning of stream. This has the advantages of being exact and +efficient. Position in time would simply be [granule_position] * +[samples_per_frame] / [samples_per_second].

    + +

    Example: samplestamp (Vorbis)

    + +

    Frame counting is insufficient in codecs such as Vorbis where an audio +frame [packet] encodes a variable number of samples. In Vorbis's +case, the granule position is a count of the number of raw samples +from the beginning of stream; the absolute time of +a granule position is [granule_position] / +[samples_per_second].

    + +

    Example: bit-divided framestamp (Theora)

    + +

    Some video codecs may be able to use the simple framestamp scheme for +granule position. However, most modern video codecs introduce at +least the following complications:

    + +
      + +
    • video frames are relatively far apart compared to audio samples; +for this reason, the point at which a video frame changes to the next +frame is usually a strictly defined offset within the frame 'period'. +That is, video at 50fps could just as easily define frame transitions +<.015, .035, .055...> as at <.00, .02, .04...>.
    • + +
    • frame rates often include drop-frames, leap-frames or other +rational-but-non-integer timings.
    • + +
    • Decode must begin at a 'key frame' or 'I frame'. Keyframes usually +occur relatively seldom.
    • + +
    + +

    The first two points can be handled straightforwardly via the fact +that the codec has complete control mapping granule position to +absolute time; non-integer frame rates and offsets can be set in the +codec's initial header, and the rest is just arithmetic.

    + +

    The third point appears trickier at first glance, but it too can be +handled through the granule position mapping mechanism. Here we +arrange the granule position in such a way that granule positions of +key frames are easy to find. Divide the granule position into two +fields; the most-significant bits are an absolute frame counter, but +it's only updated at each key frame. The least significant bits encode +the number of frames since the last key frame. In this way, each +granule position both encodes the absolute time of the current frame +as well as the absolute time of the last key frame.

    + +

    Seeking to a most recent preceding key frame is then accomplished by +first seeking to the original desired point, inspecting the granulepos +of the resulting video page, extracting from that granulepos the +absolute time of the desired key frame, and then seeking directly to +that key frame's page. Of course, it's still possible for an +application to ignore key frames and use a simpler seeking algorithm +(decode would be unable to present decoded video until the next +key frame). Surprisingly many player applications do choose the +simpler approach.

    + +

    granule position, packets and pages

    + +

    Although each packet of data in a logical stream theoretically has a +specific granule position, only one granule position is encoded +per page. It is possible to encode a logical stream such that each +page contains only a single packet (so that granule positions are +preserved for each packet), however a one-to-one packet/page mapping +is not intended to be the general case.

    + +

    Because Ogg functions at the page, not packet, level, this +once-per-page time information provides Ogg with the finest-grained +time information is can use. Ogg passes this granule positioning data +to the codec (along with the packets extracted from a page); it is the +responsibility of codecs to track timing information at granularities +finer than a single page.

    + +

    start-time and end-time positioning

    + +

    A granule position represents the instantaneous time location +between two pages. However, continuous streams and discontinuous +streams differ on whether the granulepos represents the end-time of +the data on a page or the start-time. Continuous streams are +'end-time' encoded; the granulepos represents the point in time +immediately after the last data decoded from a page. Discontinuous +streams are 'start-time' encoded; the granulepos represents the point +in time of the first data decoded from the page.

    + +

    An Ogg stream type is declared continuous or discontinuous by its +codec. A given codec may support both continuous and discontinuous +operation so long as any given logical stream is continuous or +discontinuous for its entirety and the codec is able to ascertain (and +inform the Ogg layer) as to which after decoding the initial stream +header. The majority of codecs will always be continuous (such as +Vorbis) or discontinuous (such as Writ).

    + +

    Start- and end-time encoding do not affect multiplexing sort-order; +pages are still sorted by the absolute time a given granulepos maps to +regardless of whether that granulepos represents start- or +end-time.

    + +

    Multiplex/Demultiplex Division of Labor

    + +

    The Ogg multiplex/demultiplex layer provides mechanisms for encoding +raw packets into Ogg pages, decoding Ogg pages back into the original +codec packets, determining the logical structure of an Ogg stream, and +navigating through and synchronizing with an Ogg stream at a desired +stream location. Strict multiplex/demultiplex operations are entirely +in the Ogg domain and require no intervention from codecs.

    + +

    Implementation of more complex operations does require codec +knowledge, however. Unlike other framing systems, Ogg maintains +strict separation between framing and the framed bitstream data; Ogg +does not replicate codec-specific information in the page/framing +data, nor does Ogg blur the line between framing and stream +data/metadata. Because Ogg is fully data-agnostic toward the data it +frames, operations which require specifics of bitstream data (such as +'seek to key frame') also require interaction with the codec layer +(because, in this example, the Ogg layer is not aware of the concept +of key frames). This is different from systems that blur the +separation between framing and stream data in order to simplify the +separation of code. The Ogg system purposely keeps the distinction in +data simple so that later codec innovations are not constrained by +framing design.

    + +

    For this reason, however, complex seeking operations require +interaction with the codecs in order to decode the granule position of +a given stream type back to absolute time or in order to find +'decodable points' such as key frames in video.

    + +

    Unsorted Discussion Points

    + +

    flushes around key frames? RFC suggestion: repaginating or building a +stream this way is nice but not required

    + +

    Appendix A: multiplexing examples

    + + + + + diff --git a/extern/ogg/doc/oggstream.html b/extern/ogg/doc/oggstream.html new file mode 100644 index 0000000..9769d5a --- /dev/null +++ b/extern/ogg/doc/oggstream.html @@ -0,0 +1,594 @@ + + + + + +Ogg Documentation + + + + + + +
    + + + +

    Ogg bitstream overview

    + +

    This document serves as starting point for understanding the design +and implementation of the Ogg container format. If you're new to Ogg +or merely want a high-level technical overview, start reading here. +Other documents linked from the index page +give distilled technical descriptions and references of the container +mechanisms. This document is intended to aid understanding. + +

    Container format design points

    + +

    Ogg is intended to be a simplest-possible container, concerned only +with framing, ordering, and interleave. It can be used as a stream delivery +mechanism, for media file storage, or as a building block toward +implementing a more complex, non-linear container (for example, see +the Skeleton or Annodex/CMML). + +

    The Ogg container is not intended to be a monolithic +'kitchen-sink'. It exists only to frame and deliver in-order stream +data and as such is vastly simpler than most other containers. +Elementary and multiplexed streams are both constructed entirely from a +single building block (an Ogg page) comprised of eight fields +totalling twenty-eight bytes (the page header) a list of packet lengths +(up to 255 bytes) and payload data (up to 65025 bytes). The structure +of every page is the same. There are no optional fields or alternate +encodings. + +

    Stream and media metadata is contained in Ogg and not built into +the Ogg container itself. Metadata is thus compartmentalized and +layered rather than part of a monolithic design, an especially good +idea as no two groups seem able to agree on what a complete or +complete-enough metadata set should be. In this way, the container and +container implementation are isolated from unnecessary metadata design +flux. + +

    Streaming

    + +

    The Ogg container is primarily a streaming format, +encapsulating chronological, time-linear mixed media into a single +delivery stream or file. The design is such that an application can +always encode and/or decode all features of a bitstream in one pass +with no seeking and minimal buffering. Seeking to provide optimized +encoding (such as two-pass encoding) or interactive decoding (such as +scrubbing or instant replay) is not disallowed or discouraged, however +no container feature requires nonlinear access of the bitstream. + +

    Variable Bit Rate, Variable Payload Size

    + +

    Ogg is designed to contain any size data payload with bounded, +predictable efficiency. Ogg packets have no maximum size and a +zero-byte minimum size. There is no restriction on size changes from +packet to packet. Variable size packets do not require the use of any +optional or additional container features. There is no optimal +suggested packet size, though special consideration was paid to make +sure 50-200 byte packets were no less efficient than larger packet +sizes. The original design criteria was a 2% overhead at 50 byte +packets, dropping to a maximum working overhead of 1% with larger +packets, and a typical working overhead of .5-.7% for most practical +uses. + +

    Simple pagination

    + +

    Ogg is a byte-aligned container with no context-dependent, optional +or variable-length fields. Ogg requires no repacking of codec data. +The page structure is written out in-line as packet data is submitted +to the streaming abstraction. In addition, it is possible to +implement both Ogg mux and demux as MT-hot zero-copy abstractions (as +is done in the Tremor sourcebase). + +

    Capture

    + +

    Ogg is designed for efficient and immediate stream capture with +high confidence. Although packets have no size limit in Ogg, pages +are a maximum of just under 64kB meaning that any Ogg stream can be +captured with confidence after seeing 128kB of data or less [worst +case; typical figure is 6kB] from any random starting point in the +stream. + +

    Seeking

    + +

    Ogg implements simple coarse- and fine-grained seeking by design. + +

    Coarse seeking may be performed by simply 'moving the tone arm' to a +new position and 'dropping the needle'. Rapid capture with +accompanying timecode from any location in an Ogg file is guaranteed +by the stream design. From the acquisition of the first timecode, +all data needed to play back from that time code forward is ahead of +the stream cursor. + +

    Ogg implements full sample-granularity seeking using an +interpolated bisection search built on the capture and timecode +mechanisms used by coarse seeking. As above, once a search finds +the desired timecode, all data needed to play back from that time code +forward is ahead of the stream cursor. + +

    Both coarse and fine seeking use the page structure and sequencing +inherent to the Ogg format. All Ogg streams are fully seekable from +creation; seekability is unaffected by truncation or missing data, and +is tolerant of gross corruption. Seek operations are neither 'fuzzy' nor +heuristic. + +

    Seeking without use of an index is a major point of the Ogg +design. There two primary reasons why Ogg transport forgoes an index: + +

      + +
    1. An index is only marginally useful in Ogg for the complexity +added; it adds no new functionality and seldom improves performance +noticeably. Empirical testing shows that indexless interpolation +search does not require many more seeks in practice than using an +index would. + +
    2. 'Optional' indexes encourage lazy implementations that can seek +only when indexes are present, or that implement indexless seeking +only by building an internal index after reading the entire file +beginning to end. This has been the fate of other containers that +specify optional indexing. + +
    + +

    In addition, it must be possible to create an Ogg stream in a +single pass. Although an optional index can simply be tacked on the +end of the created stream, some software groups object to +end-positioned indexes and claim to be unwilling to support indexes +not located at the stream beginning. + +

    All this said, it's become clear that an optional index is a +demanded feature. For this reason, the OggSkeleton now defines a +proposed index. + +

    Simple multiplexing

    + +

    Ogg multiplexes streams by interleaving pages from multiple elementary streams into a +multiplexed stream in time order. The multiplexed pages are not +altered. Muxing an Ogg AV stream out of separate audio, +video and data streams is akin to shuffling several decks of cards +together into a single deck; the cards themselves remain unchanged. +Demultiplexing is similarly simple (as the cards are marked). + +

    The goal of this design is to make the mux/demux operation as +trivial as possible to allow live streaming systems to build and +rebuild streams on the fly with minimal CPU usage and no additional +storage or latency requirements. + +

    Continuous and Discontinuous Media

    + +

    Ogg streams belong to one of two categories, "Continuous" streams and +"Discontinuous" streams. + +

    A stream that provides a gapless, time-continuous media type with a +fine-grained timebase is considered to be 'Continuous'. A continuous +stream should never be starved of data. Examples of continuous data +types include broadcast audio and video. + +

    A stream that delivers data in a potentially irregular pattern or +with widely spaced timing gaps is considered to be 'Discontinuous'. A +discontinuous stream may be best thought of as data representing +scattered events; although they happen in order, they are typically +unconnected data often located far apart. One example of a +discontinuous stream types would be captioning such as Ogg Kate. Although it's +possible to design captions as a continuous stream type, it's most +natural to think of captions as widely spaced pieces of text with +little happening between. + +

    The fundamental reason for distinction between continuous and +discontinuous streams concerns buffering. + +

    Buffering

    + +

    A continuous stream is, by definition, gapless. Ogg buffering is based +on the simple premise of never allowing an active continuous stream +to starve for data during decode; buffering works ahead until all +continuous streams in a physical stream have data ready and no further. + +

    Discontinuous stream data is not assumed to be predictable. The +buffering design takes discontinuous data 'as it comes' rather than +working ahead to look for future discontinuous data for a potentially +unbounded period. Thus, the buffering process makes no attempt to fill +discontinuous stream buffers; their pages simply 'fall out' of the +stream when continuous streams are handled properly. + +

    Buffering requirements in this design need not be explicitly +declared or managed in the encoded stream. The decoder simply reads as +much data as is necessary to keep all continuous stream types gapless +and no more, with discontinuous data processed as it arrives in the +continuous data. Buffering is implicitly optimal for the given +stream. Because all pages of all data types are stamped with absolute +timing information within the stream, inter-stream synchronization +timing is always maintained without the need for explicitly declared +buffer-ahead hinting. + +

    Codec metadata

    + +

    Ogg does not replicate codec-specific metadata into the mux layer +in an attempt to make the mux and codec layer implementations 'fully +separable'. Things like specific timebase, keyframing strategy, frame +duration, etc, do not appear in the Ogg container. The mux layer is, +instead, expected to query a codec through a centralized interface, +left to the implementation, for this data when it is needed. + +

    Though modern design wisdom usually prefers to predict all possible +needs of current and future codecs then embed these dependencies and +the required metadata into the container itself, this strategy +increases container specification complexity, fragility, and rigidity. +The mux and codec code becomes more independent, but the +specifications become logically less independent. A codec can't do +what a container hasn't already provided for. Novel codecs are harder +to support, and you can do fewer useful things with the ones you've +already got (eg, try to make a good splitter without using any codecs. +Such a splitter is limited to splitting at keyframes only, or building +yet another new mechanism into the container layer to mark what frames +to skip displaying). + +

    Ogg's design goes the opposite direction, where the specification +is to be as simple, easy to understand, and 'proofed' against novel +codecs as possible. When an Ogg mux layer requires codec-specific +information, it queries the codec (or a codec stub). This trades a +more complex implementation for a simpler, more flexible +specification. + +

    Stream structure metadata

    + +

    The Ogg container itself does not define a metadata system for +declaring the structure and interrelations between multiple media +types in a muxed stream. That is, the Ogg container itself does not +specify data like 'which steam is the subtitle stream?' or 'which +video stream is the primary angle?'. This metadata still exists, but +is stored by the Ogg container rather than being built into the Ogg +container itself. Xiph specifies the 'Skeleton' metadata format for Ogg +streams, but this decoupling of container and stream structure +metadata means it is possible to use Ogg with any metadata +specification without altering the container itself, or without stream +structure metadata at all. + +

    Frame accurate absolute position

    + +

    Every Ogg page is stamped with a 64 bit 'granule position' that +serves as an absolute timestamp for mux and seeking. A few nifty +little tricks are usually also embedded in the granpos state, but +we'll leave those aside for the moment (strictly speaking, they're +part of each codec's mapping, not Ogg). + +

    As previously mentioned above, granule positions are mapped into +absolute timestamps by the codec, rather than being a hard timestamp. +This allows maximally efficient use of the available 64 bits to +address every sample/frame position without approximation while +supporting new and previously unknown timebase encodings without +needing to extend or update the mux layer. When a codec needs a novel +timebase, it simply brings the code for that mapping along with it. +This is not a theoretical curiosity; new, wholly novel timebases were +deployed with the adoption of both Theora and Dirac. "Rolling INTRA" +(keyframeless video) also benefits from novel use of the granule +position. + +

    Ogg stream arrangement

    + +

    Packets, pages, and bitstreams

    + +

    Ogg codecs place raw compressed data into packets. +Packets are octet payloads containing the data needed for a single +decompressed unit, eg, one video frame. Packets have no maximum size +and may be zero length. They do not generally have any framing +information; strung together, the unframed packets form a logical +bitstream of codec data with no internal landmarks. + +

    + + +

    Packets of raw codec data are not typically internally framed. + When they are strung together into a stream without any container to + provide framing, they lose their individual boundaries. Seek and + capture are not possible within an unframed stream, and for many + codecs with variable length payloads and/or early-packet termination + (such as Vorbis), it may become impossible to recover the original + frame boundaries even if the stream is scanned linearly from + beginning to end. + +

    + +

    Logical bitstream packets are grouped and framed into Ogg pages +along with a unique stream serial number to produce a +physical bitstream. An elementary stream is a +physical bitstream containing only a single logical bitstream. Each +page is a self contained entity, although a packet may be split and +encoded across one or more pages. The page decode mechanism is +designed to recognize, verify and handle single pages at a time from +the overall bitstream. + +

    + + +

    The primary purpose of a container is to provide framing for raw + packets, marking the packet boundaries so the exact packets can be + retrieved for decode later. The container also provides secondary + functions such as capture, timestamping, sequencing, stream + identification and so on. Not all of these functions are represented in the diagram. + +

    In the Ogg container, pages do not necessarily contain + integer numbers of packets. Packets may span across page boundaries + or even multiple pages. This is necessary as pages have a maximum + possible size in order to provide capture guarantees, but packet + size is unbounded. +

    + + +

    Ogg Bitstream Framing specifies +the page format of an Ogg bitstream, the packet coding process +and elementary bitstreams in detail. + +

    Multiplexed bitstreams

    + +

    Multiple logical/elementary bitstreams can be combined into a single +multiplexed bitstream by interleaving whole pages from each +contributing elementary stream in time order. The result is a single +physical stream that multiplexes and frames multiple logical streams. +Each logical stream is identified by the unique stream serial number +stamped in its pages. A physical stream may include a 'meta-header' +(such as the Ogg Skeleton) comprising its +own Ogg page at the beginning of the physical stream. A decoder +recovers the original logical/elementary bitstreams out of the +physical bitstream by taking the pages in order from the physical +bitstream and redirecting them into the appropriate logical decoding +entity. + +

    + + +

    Multiple media types are mutliplexed into a single Ogg stream by +interleaving the pages from each elementary physical stream. + +

    + +

    Ogg Bitstream Multiplexing specifies +proper multiplexing of an Ogg bitstream in detail. + +

    Chaining

    + +

    Multiple Ogg physical bitstreams may be concatenated into a single new +stream; this is chaining. The bitstreams do not overlap; the +final page of a given logical bitstream is immediately followed by the +initial page of the next.

    + +

    Each logical bitstream in a chain must have a unique serial number +within the scope of the full physical bitstream, not only within a +particular link or segment of the chain.

    + +

    Continuous and discontinuous streams

    + +

    Within Ogg, each stream must be declared (by the codec) to be +continuous- or discontinuous-time. Most codecs treat all streams they +use as either inherently continuous- or discontinuous-time, although +this is not a requirement. A codec may, as part of its mapping, choose +according to data in the initial header. + +

    Continuous-time pages are stamped by end-time, discontinuous pages +are stamped by begin-time. Pages in a multiplexed stream are +interleaved in order of the time stamp regardless of stream type. +Both continuous and discontinuous logical streams are used to seek +within a physical stream, however only continuous streams are used to +determine buffering depth; because discontinuous streams are stamped +by start time, they will always 'fall out' at the proper time when +buffering the continuous streams. See 'Examples' for an illustration +of the buffering mechanism. + +

    Multiplexing Requirements

    + +

    Multiplexing requirements within Ogg are straightforward. When +constructing a single-link (unchained) physical bitstream consisting +of multiple elementary streams: + +

      + +
    1. The initial header for each stream appears in sequence, each +header on a single page. All initial headers must appear with no +intervening data (no auxiliary header pages or packets, no data pages +or packets). Order of the initial headers is unspecified. The +'beginning of stream' flag is set on each initial header. + +

    2. All auxiliary headers for all streams must follow. Order +is unspecified. The final auxiliary header of each stream must flush +its page. + +

    3. Data pages for each stream follow, interleaved in time order. + +

    4. The final page of each stream sets the 'end of stream' flag. +Unlike initial pages, terminal pages for the logical bitstreams need +not occur contiguously; indeed it may not be possible for them to do so. +

    + +

    Each grouped bitstream must have a unique serial number within the +scope of the physical bitstream.

    + +

    chaining and multiplexing

    + +

    Multiplexed and/or unmultiplexed bitstreams may be chained +consecutively. Such a physical bitstream obeys all the rules of both +chained and multiplexed streams. Each link, when unchained, must +stand on its own as a valid physical bitstream. Chained streams do +not mix or interleave; a new segment may not begin until all streams +in the preceding segment have terminated.

    + +

    Codec Mapping Requirements

    + +

    Each codec is allowed some freedom in deciding how its logical +bitstream is encapsulated into an Ogg bitstream (even if it is a +trivial mapping, eg, 'plop the packets in and go'). This is the +codec's mapping. Ogg imposes a few mapping requirements +on any codec. + +

      + +
    1. The framing specification defines +'beginning of stream' and 'end of stream' page markers via a header +flag (it is possible for a stream to consist of a single page). A +correct stream always consists of an integer number of pages, an easy +requirement given the variable size nature of pages.

      + +
    2. The first page of an elementary Ogg bitstream consists of a single, +small 'initial header' packet that must include sufficient information +to identify the exact CODEC type. From this initial header, the codec +must also be able to determine its timebase and whether or not it is a +continuous- or discontinuous-time stream. The initial header must fit +on a single page. If a codec makes use of auxiliary headers (for +example, Vorbis uses two auxiliary headers), these headers must follow +the initial header immediately. The last header finishes its page; +data begins on a fresh page. + +

      As an example, Ogg Vorbis places the name and revision of the +Vorbis CODEC, the audio rate and the audio quality into this initial +header. Vorbis comments and detailed codec setup appears in the larger +auxiliary headers.

      + +
    3. Granule positions must be translatable to an exact absolute +time value. As described above, the mux layer is permitted to query a +codec or codec stub plugin to perform this mapping. It is not +necessary for an absolute time to be mappable into a single unique +granule position value. + +

    4. Codecs are not required to use a fixed duration-per-packet (for +example, Vorbis does not). the mux layer is permitted to query a +codec or codec stub plugin for the time duration of a packet. + +

    5. Although an absolute time need not be translatable to a unique +granule position, a codec must be able to determine the unique granule +position of the current packet using the granule position of a +preceding packet. + +

    6. Packets and pages must be arranged in ascending +granule-position and time order. + +

    + +

    Examples

    + +[More to come shortly; this section is currently being revised and expanded] + +

    Below, we present an example of a multiplexed and chained bitstream:

    + +

    stream

    + +

    In this example, we see pages from five total logical bitstreams +multiplexed into a physical bitstream. Note the following +characteristics:

    + +
      +
    1. Multiplexed bitstreams in a given link begin together; all of the +initial pages must appear before any data pages. When concurrently +multiplexed groups are chained, the new group does not begin until all +the bitstreams in the previous group have terminated.
    2. + +
    3. The ordering of pages of concurrently multiplexed bitstreams is +goverened by timestamp (not shown here); there is no regular +interleaving order. Pages within a logical bitstream appear in +sequence order.
    4. +
    + + + +
    + + diff --git a/extern/ogg/doc/packets.png b/extern/ogg/doc/packets.png new file mode 100644 index 0000000..917b6c1 Binary files /dev/null and b/extern/ogg/doc/packets.png differ diff --git a/extern/ogg/doc/packets.svg b/extern/ogg/doc/packets.svg new file mode 100644 index 0000000..6b426c7 --- /dev/null +++ b/extern/ogg/doc/packets.svg @@ -0,0 +1,876 @@ + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + packet + packet + packet + packet + packet + packet + packet + packet + packet + packet + packet + packet + packet + packet + packet + packet + packet + packet + packet + + + + + + + + + + + + + + + + + + + + + + + packet + packet + packet + packet + packet + packet + packet + packet + packet + packet + packet + packet + packet + packet + packet + packet + packet + packet + packet + + packet stream + unframed logical bitstream + + diff --git a/extern/ogg/doc/pages.png b/extern/ogg/doc/pages.png new file mode 100644 index 0000000..b4b431e Binary files /dev/null and b/extern/ogg/doc/pages.png differ diff --git a/extern/ogg/doc/pages.svg b/extern/ogg/doc/pages.svg new file mode 100644 index 0000000..436849c --- /dev/null +++ b/extern/ogg/doc/pages.svg @@ -0,0 +1,1219 @@ + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + OggS + OggS + OggS + + + + + + + + + + + + + + + 23 + 24 + 25 + + ... + ... + physical bitstream + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + framed logical bitstream + + + + + + + + + + + + + + + + + + + + + + + packet + packet + packet + packet + packet + packet + packet + packet + packet + packet + packet + packet + packet + packet + packet + packet + packet + packet + packet + + + diff --git a/extern/ogg/doc/release.txt b/extern/ogg/doc/release.txt new file mode 100644 index 0000000..f72985f --- /dev/null +++ b/extern/ogg/doc/release.txt @@ -0,0 +1,29 @@ += Release checklist = + +Source release: + +- Update CHANGES with notable specifics. +- Update version and LIB_* API soname suffix in configure.ac. + - If the source code changed, incremement REVISION. + - If interfaces changed, increment CURRENT and zero REVISION. + - If interfaces were added, increment AGE. + - If interfaces were removed, set AGE to zero. +- Update the version and release date in doc/libogg/*.html. + - `make -C doc/libogg update-doc-version` +- Check for uncommitted changes to master. +- Tag the release commit with 'git tag -s vN.M'. + - Include release notes in the tag annotation. +- Verify 'make distcheck' produces a tarball with the desired name. +- Push tag to public repo. +- Upload source package 'libogg-${version}.tar.gz' et al. + to the website and verify file permissions. +- Update checksum files on website. +- Update links on . +- Add a copy of the documentation to + and update the links. + +Releases are committed to https://svn.xiph.org/releases/ogg/ +which propagates to downloads.xiph.org. + +Release packages should also be manually attached to the corresponding +tag on the github mirror https://github.com/xiph/ogg/releases diff --git a/extern/ogg/doc/rfc3533.txt b/extern/ogg/doc/rfc3533.txt new file mode 100644 index 0000000..f2fcd1a --- /dev/null +++ b/extern/ogg/doc/rfc3533.txt @@ -0,0 +1,843 @@ + + + + + + +Network Working Group S. Pfeiffer +Request for Comments: 3533 CSIRO +Category: Informational May 2003 + + + The Ogg Encapsulation Format Version 0 + +Status of this Memo + + This memo provides information for the Internet community. It does + not specify an Internet standard of any kind. Distribution of this + memo is unlimited. + +Copyright Notice + + Copyright (C) The Internet Society (2003). All Rights Reserved. + +Abstract + + This document describes the Ogg bitstream format version 0, which is + a general, freely-available encapsulation format for media streams. + It is able to encapsulate any kind and number of video and audio + encoding formats as well as other data streams in a single bitstream. + +Terminology + + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this + document are to be interpreted as described in BCP 14, RFC 2119 [2]. + +Table of Contents + + 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . . 2 + 2. Definitions . . . . . . . . . . . . . . . . . . . . . . . . . 2 + 3. Requirements for a generic encapsulation format . . . . . . . 3 + 4. The Ogg bitstream format . . . . . . . . . . . . . . . . . . . 3 + 5. The encapsulation process . . . . . . . . . . . . . . . . . . 6 + 6. The Ogg page format . . . . . . . . . . . . . . . . . . . . . 9 + 7. Security Considerations . . . . . . . . . . . . . . . . . . . 11 + 8. References . . . . . . . . . . . . . . . . . . . . . . . . . . 12 + A. Glossary of terms and abbreviations . . . . . . . . . . . . . 13 + B. Acknowledgements . . . . . . . . . . . . . . . . . . . . . . . 14 + Author's Address . . . . . . . . . . . . . . . . . . . . . . . 14 + Full Copyright Statement . . . . . . . . . . . . . . . . . . . 15 + + + + + + + +Pfeiffer Informational [Page 1] + +RFC 3533 OGG May 2003 + + +1. Introduction + + The Ogg bitstream format has been developed as a part of a larger + project aimed at creating a set of components for the coding and + decoding of multimedia content (codecs) which are to be freely + available and freely re-implementable, both in software and in + hardware for the computing community at large, including the Internet + community. It is the intention of the Ogg developers represented by + Xiph.Org that it be usable without intellectual property concerns. + + This document describes the Ogg bitstream format and how to use it to + encapsulate one or several media bitstreams created by one or several + encoders. The Ogg transport bitstream is designed to provide + framing, error protection and seeking structure for higher-level + codec streams that consist of raw, unencapsulated data packets, such + as the Vorbis audio codec or the upcoming Tarkin and Theora video + codecs. It is capable of interleaving different binary media and + other time-continuous data streams that are prepared by an encoder as + a sequence of data packets. Ogg provides enough information to + properly separate data back into such encoder created data packets at + the original packet boundaries without relying on decoding to find + packet boundaries. + + Please note that the MIME type application/ogg has been registered + with the IANA [1]. + +2. Definitions + + For describing the Ogg encapsulation process, a set of terms will be + used whose meaning needs to be well understood. Therefore, some of + the most fundamental terms are defined now before we start with the + description of the requirements for a generic media stream + encapsulation format, the process of encapsulation, and the concrete + format of the Ogg bitstream. See the Appendix for a more complete + glossary. + + The result of an Ogg encapsulation is called the "Physical (Ogg) + Bitstream". It encapsulates one or several encoder-created + bitstreams, which are called "Logical Bitstreams". A logical + bitstream, provided to the Ogg encapsulation process, has a + structure, i.e., it is split up into a sequence of so-called + "Packets". The packets are created by the encoder of that logical + bitstream and represent meaningful entities for that encoder only + (e.g., an uncompressed stream may use video frames as packets). They + do not contain boundary information - strung together they appear to + be streams of random bytes with no landmarks. + + + + + +Pfeiffer Informational [Page 2] + +RFC 3533 OGG May 2003 + + + Please note that the term "packet" is not used in this document to + signify entities for transport over a network. + +3. Requirements for a generic encapsulation format + + The design idea behind Ogg was to provide a generic, linear media + transport format to enable both file-based storage and stream-based + transmission of one or several interleaved media streams independent + of the encoding format of the media data. Such an encapsulation + format needs to provide: + + o framing for logical bitstreams. + + o interleaving of different logical bitstreams. + + o detection of corruption. + + o recapture after a parsing error. + + o position landmarks for direct random access of arbitrary positions + in the bitstream. + + o streaming capability (i.e., no seeking is needed to build a 100% + complete bitstream). + + o small overhead (i.e., use no more than approximately 1-2% of + bitstream bandwidth for packet boundary marking, high-level + framing, sync and seeking). + + o simplicity to enable fast parsing. + + o simple concatenation mechanism of several physical bitstreams. + + All of these design considerations have been taken into consideration + for Ogg. Ogg supports framing and interleaving of logical + bitstreams, seeking landmarks, detection of corruption, and stream + resynchronisation after a parsing error with no more than + approximately 1-2% overhead. It is a generic framework to perform + encapsulation of time-continuous bitstreams. It does not know any + specifics about the codec data that it encapsulates and is thus + independent of any media codec. + +4. The Ogg bitstream format + + A physical Ogg bitstream consists of multiple logical bitstreams + interleaved in so-called "Pages". Whole pages are taken in order + from multiple logical bitstreams multiplexed at the page level. The + logical bitstreams are identified by a unique serial number in the + + + +Pfeiffer Informational [Page 3] + +RFC 3533 OGG May 2003 + + + header of each page of the physical bitstream. This unique serial + number is created randomly and does not have any connection to the + content or encoder of the logical bitstream it represents. Pages of + all logical bitstreams are concurrently interleaved, but they need + not be in a regular order - they are only required to be consecutive + within the logical bitstream. Ogg demultiplexing reconstructs the + original logical bitstreams from the physical bitstream by taking the + pages in order from the physical bitstream and redirecting them into + the appropriate logical decoding entity. + + Each Ogg page contains only one type of data as it belongs to one + logical bitstream only. Pages are of variable size and have a page + header containing encapsulation and error recovery information. Each + logical bitstream in a physical Ogg bitstream starts with a special + start page (bos=beginning of stream) and ends with a special page + (eos=end of stream). + + The bos page contains information to uniquely identify the codec type + and MAY contain information to set up the decoding process. The bos + page SHOULD also contain information about the encoded media - for + example, for audio, it should contain the sample rate and number of + channels. By convention, the first bytes of the bos page contain + magic data that uniquely identifies the required codec. It is the + responsibility of anyone fielding a new codec to make sure it is + possible to reliably distinguish his/her codec from all other codecs + in use. There is no fixed way to detect the end of the codec- + identifying marker. The format of the bos page is dependent on the + codec and therefore MUST be given in the encapsulation specification + of that logical bitstream type. Ogg also allows but does not require + secondary header packets after the bos page for logical bitstreams + and these must also precede any data packets in any logical + bitstream. These subsequent header packets are framed into an + integral number of pages, which will not contain any data packets. + So, a physical bitstream begins with the bos pages of all logical + bitstreams containing one initial header packet per page, followed by + the subsidiary header packets of all streams, followed by pages + containing data packets. + + The encapsulation specification for one or more logical bitstreams is + called a "media mapping". An example for a media mapping is "Ogg + Vorbis", which uses the Ogg framework to encapsulate Vorbis-encoded + audio data for stream-based storage (such as files) and transport + (such as TCP streams or pipes). Ogg Vorbis provides the name and + revision of the Vorbis codec, the audio rate and the audio quality on + the Ogg Vorbis bos page. It also uses two additional header pages + per logical bitstream. The Ogg Vorbis bos page starts with the byte + 0x01, followed by "vorbis" (a total of 7 bytes of identifier). + + + + +Pfeiffer Informational [Page 4] + +RFC 3533 OGG May 2003 + + + Ogg knows two types of multiplexing: concurrent multiplexing (so- + called "Grouping") and sequential multiplexing (so-called + "Chaining"). Grouping defines how to interleave several logical + bitstreams page-wise in the same physical bitstream. Grouping is for + example needed for interleaving a video stream with several + synchronised audio tracks using different codecs in different logical + bitstreams. Chaining on the other hand, is defined to provide a + simple mechanism to concatenate physical Ogg bitstreams, as is often + needed for streaming applications. + + In grouping, all bos pages of all logical bitstreams MUST appear + together at the beginning of the Ogg bitstream. The media mapping + specifies the order of the initial pages. For example, the grouping + of a specific Ogg video and Ogg audio bitstream may specify that the + physical bitstream MUST begin with the bos page of the logical video + bitstream, followed by the bos page of the audio bitstream. Unlike + bos pages, eos pages for the logical bitstreams need not all occur + contiguously. Eos pages may be 'nil' pages, that is, pages + containing no content but simply a page header with position + information and the eos flag set in the page header. Each grouped + logical bitstream MUST have a unique serial number within the scope + of the physical bitstream. + + In chaining, complete logical bitstreams are concatenated. The + bitstreams do not overlap, i.e., the eos page of a given logical + bitstream is immediately followed by the bos page of the next. Each + chained logical bitstream MUST have a unique serial number within the + scope of the physical bitstream. + + It is possible to consecutively chain groups of concurrently + multiplexed bitstreams. The groups, when unchained, MUST stand on + their own as a valid concurrently multiplexed bitstream. The + following diagram shows a schematic example of such a physical + bitstream that obeys all the rules of both grouped and chained + multiplexed bitstreams. + + physical bitstream with pages of + different logical bitstreams grouped and chained + ------------------------------------------------------------- + |*A*|*B*|*C*|A|A|C|B|A|B|#A#|C|...|B|C|#B#|#C#|*D*|D|...|#D#| + ------------------------------------------------------------- + bos bos bos eos eos eos bos eos + + In this example, there are two chained physical bitstreams, the first + of which is a grouped stream of three logical bitstreams A, B, and C. + The second physical bitstream is chained after the end of the grouped + bitstream, which ends after the last eos page of all its grouped + logical bitstreams. As can be seen, grouped bitstreams begin + + + +Pfeiffer Informational [Page 5] + +RFC 3533 OGG May 2003 + + + together - all of the bos pages MUST appear before any data pages. + It can also be seen that pages of concurrently multiplexed bitstreams + need not conform to a regular order. And it can be seen that a + grouped bitstream can end long before the other bitstreams in the + group end. + + Ogg does not know any specifics about the codec data except that each + logical bitstream belongs to a different codec, the data from the + codec comes in order and has position markers (so-called "Granule + positions"). Ogg does not have a concept of 'time': it only knows + about sequentially increasing, unitless position markers. An + application can only get temporal information through higher layers + which have access to the codec APIs to assign and convert granule + positions or time. + + A specific definition of a media mapping using Ogg may put further + constraints on its specific use of the Ogg bitstream format. For + example, a specific media mapping may require that all the eos pages + for all grouped bitstreams need to appear in direct sequence. An + example for a media mapping is the specification of "Ogg Vorbis". + Another example is the upcoming "Ogg Theora" specification which + encapsulates Theora-encoded video data and usually comes multiplexed + with a Vorbis stream for an Ogg containing synchronised audio and + video. As Ogg does not specify temporal relationships between the + encapsulated concurrently multiplexed bitstreams, the temporal + synchronisation between the audio and video stream will be specified + in this media mapping. To enable streaming, pages from various + logical bitstreams will typically be interleaved in chronological + order. + +5. The encapsulation process + + The process of multiplexing different logical bitstreams happens at + the level of pages as described above. The bitstreams provided by + encoders are however handed over to Ogg as so-called "Packets" with + packet boundaries dependent on the encoding format. The process of + encapsulating packets into pages will be described now. + + From Ogg's perspective, packets can be of any arbitrary size. A + specific media mapping will define how to group or break up packets + from a specific media encoder. As Ogg pages have a maximum size of + about 64 kBytes, sometimes a packet has to be distributed over + several pages. To simplify that process, Ogg divides each packet + into 255 byte long chunks plus a final shorter chunk. These chunks + are called "Ogg Segments". They are only a logical construct and do + not have a header for themselves. + + + + + +Pfeiffer Informational [Page 6] + +RFC 3533 OGG May 2003 + + + A group of contiguous segments is wrapped into a variable length page + preceded by a header. A segment table in the page header tells about + the "Lacing values" (sizes) of the segments included in the page. A + flag in the page header tells whether a page contains a packet + continued from a previous page. Note that a lacing value of 255 + implies that a second lacing value follows in the packet, and a value + of less than 255 marks the end of the packet after that many + additional bytes. A packet of 255 bytes (or a multiple of 255 bytes) + is terminated by a lacing value of 0. Note also that a 'nil' (zero + length) packet is not an error; it consists of nothing more than a + lacing value of zero in the header. + + The encoding is optimized for speed and the expected case of the + majority of packets being between 50 and 200 bytes large. This is a + design justification rather than a recommendation. This encoding + both avoids imposing a maximum packet size as well as imposing + minimum overhead on small packets. In contrast, e.g., simply using + two bytes at the head of every packet and having a max packet size of + 32 kBytes would always penalize small packets (< 255 bytes, the + typical case) with twice the segmentation overhead. Using the lacing + values as suggested, small packets see the minimum possible byte- + aligned overhead (1 byte) and large packets (>512 bytes) see a fairly + constant ~0.5% overhead on encoding space. + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Pfeiffer Informational [Page 7] + +RFC 3533 OGG May 2003 + + + The following diagram shows a schematic example of a media mapping + using Ogg and grouped logical bitstreams: + + logical bitstream with packet boundaries + ----------------------------------------------------------------- + > | packet_1 | packet_2 | packet_3 | < + ----------------------------------------------------------------- + + |segmentation (logically only) + v + + packet_1 (5 segments) packet_2 (4 segs) p_3 (2 segs) + ------------------------------ -------------------- ------------ + .. |seg_1|seg_2|seg_3|seg_4|s_5 | |seg_1|seg_2|seg_3|| |seg_1|s_2 | .. + ------------------------------ -------------------- ------------ + + | page encapsulation + v + + page_1 (packet_1 data) page_2 (pket_1 data) page_3 (packet_2 data) +------------------------ ---------------- ------------------------ +|H|------------------- | |H|----------- | |H|------------------- | +|D||seg_1|seg_2|seg_3| | |D|seg_4|s_5 | | |D||seg_1|seg_2|seg_3| | ... +|R|------------------- | |R|----------- | |R|------------------- | +------------------------ ---------------- ------------------------ + + | +pages of | +other --------| | +logical ------- +bitstreams | MUX | + ------- + | + v + + page_1 page_2 page_3 + ------ ------ ------- ----- ------- + ... || | || | || | || | || | ... + ------ ------ ------- ----- ------- + physical Ogg bitstream + + In this example we take a snapshot of the encapsulation process of + one logical bitstream. We can see part of that bitstream's + subdivision into packets as provided by the codec. The Ogg + encapsulation process chops up the packets into segments. The + packets in this example are rather large such that packet_1 is split + into 5 segments - 4 segments with 255 bytes and a final smaller one. + Packet_2 is split into 4 segments - 3 segments with 255 bytes and a + + + +Pfeiffer Informational [Page 8] + +RFC 3533 OGG May 2003 + + + final very small one - and packet_3 is split into two segments. The + encapsulation process then creates pages, which are quite small in + this example. Page_1 consists of the first three segments of + packet_1, page_2 contains the remaining 2 segments from packet_1, and + page_3 contains the first three pages of packet_2. Finally, this + logical bitstream is multiplexed into a physical Ogg bitstream with + pages of other logical bitstreams. + +6. The Ogg page format + + A physical Ogg bitstream consists of a sequence of concatenated + pages. Pages are of variable size, usually 4-8 kB, maximum 65307 + bytes. A page header contains all the information needed to + demultiplex the logical bitstreams out of the physical bitstream and + to perform basic error recovery and landmarks for seeking. Each page + is a self-contained entity such that the page decode mechanism can + recognize, verify, and handle single pages at a time without + requiring the overall bitstream. + + The Ogg page header has the following format: + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1| Byte ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| capture_pattern: Magic number for page start "OggS" | 0-3 ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| version | header_type | granule_position | 4-7 ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| | 8-11 ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| | bitstream_serial_number | 12-15 ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| | page_sequence_number | 16-19 ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| | CRC_checksum | 20-23 ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| |page_segments | segment_table | 24-27 ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| ... | 28- ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + The LSb (least significant bit) comes first in the Bytes. Fields + with more than one byte length are encoded LSB (least significant + byte) first. + + + + + + + +Pfeiffer Informational [Page 9] + +RFC 3533 OGG May 2003 + + + The fields in the page header have the following meaning: + + 1. capture_pattern: a 4 Byte field that signifies the beginning of a + page. It contains the magic numbers: + + 0x4f 'O' + + 0x67 'g' + + 0x67 'g' + + 0x53 'S' + + It helps a decoder to find the page boundaries and regain + synchronisation after parsing a corrupted stream. Once the + capture pattern is found, the decoder verifies page sync and + integrity by computing and comparing the checksum. + + 2. stream_structure_version: 1 Byte signifying the version number of + the Ogg file format used in this stream (this document specifies + version 0). + + 3. header_type_flag: the bits in this 1 Byte field identify the + specific type of this page. + + * bit 0x01 + + set: page contains data of a packet continued from the previous + page + + unset: page contains a fresh packet + + * bit 0x02 + + set: this is the first page of a logical bitstream (bos) + + unset: this page is not a first page + + * bit 0x04 + + set: this is the last page of a logical bitstream (eos) + + unset: this page is not a last page + + 4. granule_position: an 8 Byte field containing position information. + For example, for an audio stream, it MAY contain the total number + of PCM samples encoded after including all frames finished on this + page. For a video stream it MAY contain the total number of video + + + +Pfeiffer Informational [Page 10] + +RFC 3533 OGG May 2003 + + + frames encoded after this page. This is a hint for the decoder + and gives it some timing and position information. Its meaning is + dependent on the codec for that logical bitstream and specified in + a specific media mapping. A special value of -1 (in two's + complement) indicates that no packets finish on this page. + + 5. bitstream_serial_number: a 4 Byte field containing the unique + serial number by which the logical bitstream is identified. + + 6. page_sequence_number: a 4 Byte field containing the sequence + number of the page so the decoder can identify page loss. This + sequence number is increasing on each logical bitstream + separately. + + 7. CRC_checksum: a 4 Byte field containing a 32 bit CRC checksum of + the page (including header with zero CRC field and page content). + The generator polynomial is 0x04c11db7. + + 8. number_page_segments: 1 Byte giving the number of segment entries + encoded in the segment table. + + 9. segment_table: number_page_segments Bytes containing the lacing + values of all segments in this page. Each Byte contains one + lacing value. + + The total header size in bytes is given by: + header_size = number_page_segments + 27 [Byte] + + The total page size in Bytes is given by: + page_size = header_size + sum(lacing_values: 1..number_page_segments) + [Byte] + +7. Security Considerations + + The Ogg encapsulation format is a container format and only + encapsulates content (such as Vorbis-encoded audio). It does not + provide for any generic encryption or signing of itself or its + contained content bitstreams. However, it encapsulates any kind of + content bitstream as long as there is a codec for it, and is thus + able to contain encrypted and signed content data. It is also + possible to add an external security mechanism that encrypts or signs + an Ogg physical bitstream and thus provides content confidentiality + and authenticity. + + As Ogg encapsulates binary data, it is possible to include executable + content in an Ogg bitstream. This can be an issue with applications + that are implemented using the Ogg format, especially when Ogg is + used for streaming or file transfer in a networking scenario. As + + + +Pfeiffer Informational [Page 11] + +RFC 3533 OGG May 2003 + + + such, Ogg does not pose a threat there. However, an application + decoding Ogg and its encapsulated content bitstreams has to ensure + correct handling of manipulated bitstreams, of buffer overflows and + the like. + +8. References + + [1] Walleij, L., "The application/ogg Media Type", RFC 3534, May + 2003. + + [2] Bradner, S., "Key words for use in RFCs to Indicate Requirement + Levels", BCP 14, RFC 2119, March 1997. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Pfeiffer Informational [Page 12] + +RFC 3533 OGG May 2003 + + +Appendix A. Glossary of terms and abbreviations + + bos page: The initial page (beginning of stream) of a logical + bitstream which contains information to identify the codec type + and other decoding-relevant information. + + chaining (or sequential multiplexing): Concatenation of two or more + complete physical Ogg bitstreams. + + eos page: The final page (end of stream) of a logical bitstream. + + granule position: An increasing position number for a specific + logical bitstream stored in the page header. Its meaning is + dependent on the codec for that logical bitstream and specified in + a specific media mapping. + + grouping (or concurrent multiplexing): Interleaving of pages of + several logical bitstreams into one complete physical Ogg + bitstream under the restriction that all bos pages of all grouped + logical bitstreams MUST appear before any data pages. + + lacing value: An entry in the segment table of a page header + representing the size of the related segment. + + logical bitstream: A sequence of bits being the result of an encoded + media stream. + + media mapping: A specific use of the Ogg encapsulation format + together with a specific (set of) codec(s). + + (Ogg) packet: A subpart of a logical bitstream that is created by the + encoder for that bitstream and represents a meaningful entity for + the encoder, but only a sequence of bits to the Ogg encapsulation. + + (Ogg) page: A physical bitstream consists of a sequence of Ogg pages + containing data of one logical bitstream only. It usually + contains a group of contiguous segments of one packet only, but + sometimes packets are too large and need to be split over several + pages. + + physical (Ogg) bitstream: The sequence of bits resulting from an Ogg + encapsulation of one or several logical bitstreams. It consists + of a sequence of pages from the logical bitstreams with the + restriction that the pages of one logical bitstream MUST come in + their correct temporal order. + + + + + + +Pfeiffer Informational [Page 13] + +RFC 3533 OGG May 2003 + + + (Ogg) segment: The Ogg encapsulation process splits each packet into + chunks of 255 bytes plus a last fractional chunk of less than 255 + bytes. These chunks are called segments. + +Appendix B. Acknowledgements + + The author gratefully acknowledges the work that Christopher + Montgomery and the Xiph.Org foundation have done in defining the Ogg + multimedia project and as part of it the open file format described + in this document. The author hopes that providing this document to + the Internet community will help in promoting the Ogg multimedia + project at http://www.xiph.org/. Many thanks also for the many + technical and typo corrections that C. Montgomery and the Ogg + community provided as feedback to this RFC. + +Author's Address + + Silvia Pfeiffer + CSIRO, Australia + Locked Bag 17 + North Ryde, NSW 2113 + Australia + + Phone: +61 2 9325 3141 + EMail: Silvia.Pfeiffer@csiro.au + URI: http://www.cmis.csiro.au/Silvia.Pfeiffer/ + + + + + + + + + + + + + + + + + + + + + + + + + +Pfeiffer Informational [Page 14] + +RFC 3533 OGG May 2003 + + +Full Copyright Statement + + Copyright (C) The Internet Society (2003). All Rights Reserved. + + This document and translations of it may be copied and furnished to + others, and derivative works that comment on or otherwise explain it + or assist in its implementation may be prepared, copied, published + and distributed, in whole or in part, without restriction of any + kind, provided that the above copyright notice and this paragraph are + included on all such copies and derivative works. However, this + document itself may not be modified in any way, such as by removing + the copyright notice or references to the Internet Society or other + Internet organizations, except as needed for the purpose of + developing Internet standards in which case the procedures for + copyrights defined in the Internet Standards process must be + followed, or as required to translate it into languages other than + English. + + The limited permissions granted above are perpetual and will not be + revoked by the Internet Society or its successors or assigns. + + This document and the information contained herein is provided on an + "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING + TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING + BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION + HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF + MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + +Acknowledgement + + Funding for the RFC Editor function is currently provided by the + Internet Society. + + + + + + + + + + + + + + + + + + + +Pfeiffer Informational [Page 15] + diff --git a/extern/ogg/doc/rfc3534.txt b/extern/ogg/doc/rfc3534.txt new file mode 100644 index 0000000..840f1ec --- /dev/null +++ b/extern/ogg/doc/rfc3534.txt @@ -0,0 +1,339 @@ + + + + + + +Network Working Group L. Walleij +Request for Comments: 3534 The Ogg Vorbis Community +Category: Standards Track May 2003 + + + The application/ogg Media Type + +Status of this Memo + + This document specifies an Internet standards track protocol for the + Internet community, and requests discussion and suggestions for + improvements. Please refer to the current edition of the "Internet + Official Protocol Standards" (STD 1) for the standardization state + and status of this protocol. Distribution of this memo is unlimited. + +Copyright Notice + + Copyright (C) The Internet Society (2003). All Rights Reserved. + +Abstract + + The Ogg Bitstream Format aims at becoming a general, freely-available + standard for transporting multimedia content across computing + platforms and networks. The intention of this document is to define + the MIME media type application/ogg to refer to this kind of content + when transported across the Internet. It is the intention of the Ogg + Bitstream Format developers that it be usable without intellectual + property concerns. + +Conventions used in this Document + + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this + document are to be interpreted as described in RFC 2119 [2]. + +1. The Ogg Bitstream Format + + The Ogg Bitstream format has been developed as a part of a larger + project aimed at creating a set of components for the coding and + decoding of multimedia content (codecs) which are to be freely + available and freely re-implementable both in software and in + hardware for the computing community at large, including the Internet + community. + + Raw packets from these codecs may be used directly by transport + mechanisms that provide their own framing and packet-separation + mechanisms (such as UDP datagrams). + + + + +Walleij Standards Track [Page 1] + +RFC 3534 The application/ogg Media Type May 2003 + + + One such framing and content-separation mechanism is the real-time + transport protocol (RTP). RTP allows the streaming of synchronous + lossy data for broadcasting and similar purposes. If this function + is desired then a separate RTP wrapping mechanism should be used. A + wrapping mechanism is currently under development. + + For stream based storage (such as files) and transport (such as TCP + streams or pipes), Ogg codecs use the Ogg Bitstream Format to provide + framing/sync, sync recapture after error, landmarks during seeking, + and enough information to properly separate data back into packets at + the original packet boundaries without relying on decoding to find + packet boundaries. The application/ogg MIME type refers to this kind + of bitstreams, when no further knowledge of the bitstream content + exists. + + The bitstream format in itself is documented in [1]. + +2. Registration Information + + To: ietf-types@iana.org + + Subject: Registration of MIME media type application/ogg + + MIME media type name: application + + MIME subtype name: ogg + + Required parameters: none + + Optional parameters: none + + Encoding Considerations: + + The Ogg bitstream format is binary data, and must be encoded for + non-binary transport; the Base64 encoding is suitable for Email. + Binary encoding could also be used. + + Security Considerations: + + As the Ogg bitstream file is a container format and only a carrier of + content (such as Vorbis audio) with a very rigid definition (see + [1]), this format in itself is not more vulnerable than any other + content framing mechanism. The main security consideration for the + receiving application is to ensure that manipulated packages can not + cause buffer overflows and the like. It is possible to encapsulate + even executable content in the bitstream, so for such uses additional + security considerations must be taken. + + + + +Walleij Standards Track [Page 2] + +RFC 3534 The application/ogg Media Type May 2003 + + + Ogg bitstream files are not signed or encrypted using any applicable + encryption schemes. External security mechanisms must be added if + content confidentiality and authenticity is to be achieved. + + Interoperability considerations: + + The Ogg bitstream format has proved to be widely implementable across + different computing platforms. A broadly portable reference + implementation is available under a BSD license. + + The Ogg bitstream format is not patented and can be implemented by + third parties without patent considerations. + + Published specification: + + See [1]. + + Applications which use this media type: + + Any application that implements the specification will be able to + encode or decode Ogg bitstream files. Specifically, the format is + supposed to be used by subcodecs that implement, for example, Vorbis + audio. + + Additional information: + + Magic number(s): + + In Ogg bitstream files, the first four bytes are 0x4f 0x67 0x67 0x53 + corresponding to the string "OggS". + + File extension: .ogg + + Macintosh File Type Code(s): OggS + + Object Identifier(s) or OID(s): none + + Person & email address to contact for further information: + + Questions about this proposal should be directed to Linus Walleij + . Technical questions about the Ogg bitstream + standard may be asked on the mailing lists for the developer + community. + + Intended usage: COMMON + + + + + + +Walleij Standards Track [Page 3] + +RFC 3534 The application/ogg Media Type May 2003 + + + Author/Change controller: + + This document was written by Linus Walleij . + Changes to this document will either be handled by him, a + representative of the Xiph.org, or the associated development + communities. + + The Ogg bitstream format is controlled by the Xiph.org and the + respective development communities. + +3. Security Considerations + + Security considerations are discussed in the security considerations + clause of the MIME registration in section 2. + +4. Normative References + + [1] Pfeiffer, S., "The Ogg encapsulation format version 0", RFC + 3533, May 2003. + + [2] Bradner, S., "Key words for use in RFCs to Indicate Requirement + Levels", BCP 14, RFC 2119, March 1997. + +5. Intellectual Property Statement + + The IETF takes no position regarding the validity or scope of any + intellectual property or other rights that might be claimed to + pertain to the implementation or use of the technology described in + this document or the extent to which any license under such rights + might or might not be available; neither does it represent that it + has made any effort to identify any such rights. Information on the + IETF's procedures with respect to rights in standards-track and + standards-related documentation can be found in BCP-11. Copies of + claims of rights made available for publication and any assurances of + licenses to be made available, or the result of an attempt made to + obtain a general license or permission for the use of such + proprietary rights by implementors or users of this specification can + be obtained from the IETF Secretariat. + + The IETF invites any interested party to bring to its attention any + copyrights, patents or patent applications, or other proprietary + rights which may cover technology that may be required to practice + this standard. Please address the information to the IETF Executive + Director. + + + + + + + +Walleij Standards Track [Page 4] + +RFC 3534 The application/ogg Media Type May 2003 + + +6. Author's Address + + Linus Walleij + The Ogg Vorbis Community + Master Olofs Vag 24 + Lund 224 66 + SE + + Phone: +46 703 193678 + EMail: triad@df.lth.se + URI: http://www.xiph.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Walleij Standards Track [Page 5] + +RFC 3534 The application/ogg Media Type May 2003 + + +7. Full Copyright Statement + + Copyright (C) The Internet Society (2003). All Rights Reserved. + + This document and translations of it may be copied and furnished to + others, and derivative works that comment on or otherwise explain it + or assist in its implementation may be prepared, copied, published + and distributed, in whole or in part, without restriction of any + kind, provided that the above copyright notice and this paragraph are + included on all such copies and derivative works. However, this + document itself may not be modified in any way, such as by removing + the copyright notice or references to the Internet Society or other + Internet organizations, except as needed for the purpose of + developing Internet standards in which case the procedures for + copyrights defined in the Internet Standards process must be + followed, or as required to translate it into languages other than + English. + + The limited permissions granted above are perpetual and will not be + revoked by the Internet Society or its successors or assigns. + + This document and the information contained herein is provided on an + "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING + TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING + BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION + HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF + MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + +Acknowledgement + + Funding for the RFC Editor function is currently provided by the + Internet Society. + + + + + + + + + + + + + + + + + + + +Walleij Standards Track [Page 6] + diff --git a/extern/ogg/doc/rfc5334.txt b/extern/ogg/doc/rfc5334.txt new file mode 100644 index 0000000..fea91fb --- /dev/null +++ b/extern/ogg/doc/rfc5334.txt @@ -0,0 +1,787 @@ + + + + + + +Network Working Group I. Goncalves +Request for Comments: 5334 S. Pfeiffer +Obsoletes: 3534 C. Montgomery +Category: Standards Track Xiph + September 2008 + + + Ogg Media Types + +Status of This Memo + + This document specifies an Internet standards track protocol for the + Internet community, and requests discussion and suggestions for + improvements. Please refer to the current edition of the "Internet + Official Protocol Standards" (STD 1) for the standardization state + and status of this protocol. Distribution of this memo is unlimited. + +Abstract + + This document describes the registration of media types for the Ogg + container format and conformance requirements for implementations of + these types. This document obsoletes RFC 3534. + +Table of Contents + + 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . 2 + 2. Changes Since RFC 3534 . . . . . . . . . . . . . . . . . . 2 + 3. Conformance and Document Conventions . . . . . . . . . . . 3 + 4. Deployed Media Types and Compatibility . . . . . . . . . . 3 + 5. Relation between the Media Types . . . . . . . . . . . . . 5 + 6. Encoding Considerations . . . . . . . . . . . . . . . . . . 5 + 7. Security Considerations . . . . . . . . . . . . . . . . . . 6 + 8. Interoperability Considerations . . . . . . . . . . . . . . 7 + 9. IANA Considerations . . . . . . . . . . . . . . . . . . . . 7 + 10. Ogg Media Types . . . . . . . . . . . . . . . . . . . . . . 7 + 10.1. application/ogg . . . . . . . . . . . . . . . . . . . . . . 7 + 10.2. video/ogg . . . . . . . . . . . . . . . . . . . . . . . . . 8 + 10.3. audio/ogg . . . . . . . . . . . . . . . . . . . . . . . . . 9 + 11. Acknowledgements . . . . . . . . . . . . . . . . . . . . . 10 + 12. Copying Conditions . . . . . . . . . . . . . . . . . . . . 10 + 13. References . . . . . . . . . . . . . . . . . . . . . . . . 11 + 13.1. Normative References . . . . . . . . . . . . . . . . . . . 11 + 13.2. Informative References . . . . . . . . . . . . . . . . . . 11 + + + + + + + + +Goncalves, et al. Standards Track [Page 1] + +RFC 5334 Ogg Media Types September 2008 + + +1. Introduction + + This document describes media types for Ogg, a data encapsulation + format defined by the Xiph.Org Foundation for public use. Refer to + "Introduction" in [RFC3533] and "Overview" in [Ogg] for background + information on this container format. + + Binary data contained in Ogg, such as Vorbis and Theora, has + historically been interchanged using the application/ogg media type + as defined by [RFC3534]. This document obsoletes [RFC3534] and + defines three media types for different types of content in Ogg to + reflect this usage in the IANA media type registry, to foster + interoperability by defining underspecified aspects, and to provide + general security considerations. + + The Ogg container format is known to contain [Theora] or [Dirac] + video, [Speex] (narrow-band and wide-band) speech, [Vorbis] or [FLAC] + audio, and [CMML] timed text/metadata. As Ogg encapsulates binary + data, it is possible to include any other type of video, audio, + image, text, or, generally speaking, any time-continuously sampled + data. + + While raw packets from these data sources may be used directly by + transport mechanisms that provide their own framing and packet- + separation mechanisms (such as UDP datagrams or RTP), Ogg is a + solution for stream based storage (such as files) and transport (such + as TCP streams or pipes). The media types defined in this document + are needed to correctly identify such content when it is served over + HTTP, included in multi-part documents, or used in other places where + media types [RFC2045] are used. + +2. Changes Since RFC 3534 + + o The type "application/ogg" is redefined. + + o The types "video/ogg" and "audio/ogg" are defined. + + o New file extensions are defined. + + o New Macintosh file type codes are defined. + + o The codecs parameter is defined for optional use. + + o The Ogg Skeleton extension becomes a recommended addition for + content served under the new types. + + + + + + +Goncalves, et al. Standards Track [Page 2] + +RFC 5334 Ogg Media Types September 2008 + + +3. Conformance and Document Conventions + + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this + document are to be interpreted as described in BCP 14, [RFC2119] and + indicate requirement levels for compliant implementations. + Requirements apply to all implementations unless otherwise stated. + + An implementation is a software module that supports one of the media + types defined in this document. Software modules may support + multiple media types, but conformance is considered individually for + each type. + + Implementations that fail to satisfy one or more "MUST" requirements + are considered non-compliant. Implementations that satisfy all + "MUST" requirements, but fail to satisfy one or more "SHOULD" + requirements, are said to be "conditionally compliant". All other + implementations are "unconditionally compliant". + +4. Deployed Media Types and Compatibility + + The application/ogg media type has been used in an ad hoc fashion to + label and exchange multimedia content in Ogg containers. + + Use of the "application" top-level type for this kind of content is + known to be problematic, in particular since it obfuscates video and + audio content. This document thus defines the media types, + + o video/ogg + + o audio/ogg + + which are intended for common use and SHOULD be used when dealing + with video or audio content, respectively. This document also + obsoletes the [RFC3534] definition of application/ogg and marks it + for complex data (e.g., multitrack visual, audio, textual, and other + time-continuously sampled data), which is not clearly video or audio + data and thus not suited for either the video/ogg or audio/ogg types. + Refer to the following section for more details. + + An Ogg bitstream generally consists of one or more logical bitstreams + that each consist of a series of header and data pages packetising + time-continuous binary data [RFC3533]. The content types of the + logical bitstreams may be identified without decoding the header + pages of the logical bitstreams through use of a [Skeleton] + bitstream. Using Ogg Skeleton is REQUIRED for content served under + + + + + +Goncalves, et al. Standards Track [Page 3] + +RFC 5334 Ogg Media Types September 2008 + + + the application/ogg type and RECOMMENDED for video/ogg and audio/ogg, + as Skeleton contains identifiers to describe the different + encapsulated data. + + Furthermore, it is RECOMMENDED that implementations that identify a + logical bitstream that they cannot decode SHOULD ignore it, while + continuing to decode the ones they can. Such precaution ensures + backward and forward compatibility with existing and future data. + + These media types can optionally use the "codecs" parameter described + in [RFC4281]. Codecs encapsulated in Ogg require a text identifier + at the beginning of the first header page, hence a machine-readable + method to identify the encapsulated codecs would be through this + header. The following table illustrates how those header values map + into strings that are used in the "codecs" parameter when dealing + with Ogg media types. + + Codec Identifier | Codecs Parameter + ----------------------------------------------------------- + char[5]: 'BBCD\0' | dirac + char[5]: '\177FLAC' | flac + char[7]: '\x80theora' | theora + char[7]: '\x01vorbis' | vorbis + char[8]: 'CELT ' | celt + char[8]: 'CMML\0\0\0\0' | cmml + char[8]: '\213JNG\r\n\032\n' | jng + char[8]: '\x80kate\0\0\0' | kate + char[8]: 'OggMIDI\0' | midi + char[8]: '\212MNG\r\n\032\n' | mng + char[8]: 'PCM ' | pcm + char[8]: '\211PNG\r\n\032\n' | png + char[8]: 'Speex ' | speex + char[8]: 'YUV4MPEG' | yuv4mpeg + + An up-to-date version of this table is kept at Xiph.org (see + [Codecs]). + + Possible examples include: + + o application/ogg; codecs="theora, cmml, ecmascript" + + o video/ogg; codecs="theora, vorbis" + + o audio/ogg; codecs=speex + + + + + + + +Goncalves, et al. Standards Track [Page 4] + +RFC 5334 Ogg Media Types September 2008 + + +5. Relation between the Media Types + + As stated in the previous section, this document describes three + media types that are targeted at different data encapsulated in Ogg. + Since Ogg is capable of encapsulating any kind of data, the multiple + usage scenarios have revealed interoperability issues between + implementations when dealing with content served solely under the + application/ogg type. + + While this document does redefine the earlier definition of + application/ogg, this media type will continue to embrace the widest + net possible of content with the video/ogg and audio/ogg types being + smaller subsets of it. However, the video/ogg and audio/ogg types + take precedence in a subset of the usages, specifically when serving + multimedia content that is not complex enough to warrant the use of + application/ogg. Following this line of thought, the audio/ogg type + is an even smaller subset within video/ogg, as it is not intended to + refer to visual content. + + As such, the application/ogg type is the recommended choice to serve + content aimed at scientific and other applications that require + various multiplexed signals or streams of continuous data, with or + without scriptable control of content. For bitstreams containing + visual, timed text, and any other type of material that requires a + visual interface, but that is not complex enough to warrant serving + under application/ogg, the video/ogg type is recommended. In + situations where the Ogg bitstream predominantly contains audio data + (lyrics, metadata, or cover art notwithstanding), it is recommended + to use the audio/ogg type. + +6. Encoding Considerations + + Binary: The content consists of an unrestricted sequence of octets. + + Note: + + o Ogg encapsulated content is binary data and should be transmitted + in a suitable encoding without CR/LF conversion, 7-bit stripping, + etc.; base64 [RFC4648] is generally preferred for binary-to-text + encoding. + + o Media types described in this document are used for stream based + storage (such as files) and transport (such as TCP streams or + pipes); separate types are used to identify codecs such as in + real-time applications for the RTP payload formats of Theora + [ThRTP] video, Vorbis [RFC5215], or Speex [SpRTP] audio, as well + as for identification of encapsulated data within Ogg through + Skeleton. + + + +Goncalves, et al. Standards Track [Page 5] + +RFC 5334 Ogg Media Types September 2008 + + +7. Security Considerations + + Refer to [RFC3552] for a discussion of terminology used in this + section. + + The Ogg encapsulation format is a container and only a carrier of + content (such as audio, video, and displayable text data) with a very + rigid definition. This format in itself is not more vulnerable than + any other content framing mechanism. + + Ogg does not provide for any generic encryption or signing of itself + or its contained bitstreams. However, it encapsulates any kind of + binary content and is thus able to contain encrypted and signed + content data. It is also possible to add an external security + mechanism that encrypts or signs an Ogg bitstream and thus provides + content confidentiality and authenticity. + + As Ogg encapsulates binary data, it is possible to include executable + content in an Ogg bitstream. Implementations SHOULD NOT execute such + content without prior validation of its origin by the end-user. + + Issues may arise on applications that use Ogg for streaming or file + transfer in a networking scenario. In such cases, implementations + decoding Ogg and its encapsulated bitstreams have to ensure correct + handling of manipulated bitstreams, of buffer overflows, and similar + issues. + + It is also possible to author malicious Ogg bitstreams, which attempt + to call for an excessively large picture size, high sampling-rate + audio, etc. Implementations SHOULD protect themselves against this + kind of attack. + + Ogg has an extensible structure, so that it is theoretically possible + that metadata fields or media formats might be defined in the future + which might be used to induce particular actions on the part of the + recipient, thus presenting additional security risks. However, this + type of capability is currently not supported in the referenced + specification. + + Implementations may fail to implement a specific security model or + other means to prevent possibly dangerous operations. Such failure + might possibly be exploited to gain unauthorized access to a system + or sensitive information; such failure constitutes an unknown factor + and is thus considered out of the scope of this document. + + + + + + + +Goncalves, et al. Standards Track [Page 6] + +RFC 5334 Ogg Media Types September 2008 + + +8. Interoperability Considerations + + The Ogg container format is device-, platform-, and vendor-neutral + and has proved to be widely implementable across different computing + platforms through a wide range of encoders and decoders. A broadly + portable reference implementation [libogg] is available under the + revised (3-clause) BSD license, which is a Free Software license. + + The Xiph.Org Foundation has defined the specification, + interoperability, and conformance and conducts regular + interoperability testing. + + The use of the Ogg Skeleton extension has been confirmed to not cause + interoperability issues with existing implementations. Third parties + are, however, welcome to conduct their own testing. + +9. IANA Considerations + + In accordance with the procedures set forth in [RFC4288], this + document registers two new media types and redefines the existing + application/ogg as defined in the following section. + +10. Ogg Media Types + +10.1. application/ogg + + Type name: application + + Subtype name: ogg + + Required parameters: none + + Optional parameters: codecs, whose syntax is defined in RFC 4281. + See section 4 of RFC 5334 for a list of allowed values. + + Encoding considerations: See section 6 of RFC 5334. + + Security considerations: See section 7 of RFC 5334. + + Interoperability considerations: None, as noted in section 8 of RFC + 5334. + + Published specification: RFC 3533 + + Applications which use this media type: Scientific and otherwise that + require various multiplexed signals or streams of data, with or + without scriptable control of content. + + + + +Goncalves, et al. Standards Track [Page 7] + +RFC 5334 Ogg Media Types September 2008 + + + Additional information: + + Magic number(s): The first four bytes, 0x4f 0x67 0x67 0x53, + correspond to the string "OggS". + + File extension(s): .ogx + + RFC 3534 defined the file extension .ogg for application/ogg, + which RFC 5334 obsoletes in favor of .ogx due to concerns where, + historically, some implementations expect .ogg files to be solely + Vorbis-encoded audio. + + Macintosh File Type Code(s): OggX + + Person & Email address to contact for further information: See + "Authors' Addresses" section. + + Intended usage: COMMON + + Restrictions on usage: The type application/ogg SHOULD only be used + in situations where it is not appropriate to serve data under the + video/ogg or audio/ogg types. Data served under the application/ogg + type SHOULD use the .ogx file extension and MUST contain an Ogg + Skeleton logical bitstream to identify all other contained logical + bitstreams. + + Author: See "Authors' Addresses" section. + + Change controller: The Xiph.Org Foundation. + +10.2. video/ogg + + Type name: video + + Subtype name: ogg + + Required parameters: none + + Optional parameters: codecs, whose syntax is defined in RFC 4281. + See section 4 of RFC 5334 for a list of allowed values. + + Encoding considerations: See section 6 of RFC 5334. + + Security considerations: See section 7 of RFC 5334. + + Interoperability considerations: None, as noted in section 8 of RFC + 5334. + + + + +Goncalves, et al. Standards Track [Page 8] + +RFC 5334 Ogg Media Types September 2008 + + + Published specification: RFC 3533 + + Applications which use this media type: Multimedia applications, + including embedded, streaming, and conferencing tools. + + Additional information: + + Magic number(s): The first four bytes, 0x4f 0x67 0x67 0x53, + correspond to the string "OggS". + + File extension(s): .ogv + + Macintosh File Type Code(s): OggV + + Person & Email address to contact for further information: See + "Authors' Addresses" section. + + Intended usage: COMMON + + Restrictions on usage: The type "video/ogg" SHOULD be used for Ogg + bitstreams containing visual, audio, timed text, or any other type of + material that requires a visual interface. It is intended for + content not complex enough to warrant serving under "application/ + ogg"; for example, a combination of Theora video, Vorbis audio, + Skeleton metadata, and CMML captioning. Data served under the type + "video/ogg" SHOULD contain an Ogg Skeleton logical bitstream. + Implementations interacting with the type "video/ogg" SHOULD support + multiplexed bitstreams. + + Author: See "Authors' Addresses" section. + + Change controller: The Xiph.Org Foundation. + +10.3. audio/ogg + + Type name: audio + + Subtype name: ogg + + Required parameters: none + + Optional parameters: codecs, whose syntax is defined in RFC 4281. + See section 4 of RFC 5334 for a list of allowed values. + + Encoding considerations: See section 6 of RFC 5334. + + Security considerations: See section 7 of RFC 5334. + + + + +Goncalves, et al. Standards Track [Page 9] + +RFC 5334 Ogg Media Types September 2008 + + + Interoperability considerations: None, as noted in section 8 of RFC + 5334. + + Published specification: RFC 3533 + + Applications which use this media type: Multimedia applications, + including embedded, streaming, and conferencing tools. + + Additional information: + + Magic number(s): The first four bytes, 0x4f 0x67 0x67 0x53, + correspond to the string "OggS". + + File extension(s): .oga, .ogg, .spx + + Macintosh File Type Code(s): OggA + + Person & Email address to contact for further information: See + "Authors' Addresses" section. + + Intended usage: COMMON + + Restrictions on usage: The type "audio/ogg" SHOULD be used when the + Ogg bitstream predominantly contains audio data. Content served + under the "audio/ogg" type SHOULD have an Ogg Skeleton logical + bitstream when using the default .oga file extension. The .ogg and + .spx file extensions indicate a specialization that requires no + Skeleton due to backward compatibility concerns with existing + implementations. In particular, .ogg is used for Ogg files that + contain only a Vorbis bitstream, while .spx is used for Ogg files + that contain only a Speex bitstream. + + Author: See "Authors' Addresses" section. + + Change controller: The Xiph.Org Foundation. + +11. Acknowledgements + + The authors gratefully acknowledge the contributions of Magnus + Westerlund, Alfred Hoenes, and Peter Saint-Andre. + +12. Copying Conditions + + The authors agree to grant third parties the irrevocable right to + copy, use and distribute the work, with or without modification, in + any medium, without royalty, provided that, unless separate + permission is granted, redistributed modified works do not contain + misleading author, version, name of work, or endorsement information. + + + +Goncalves, et al. Standards Track [Page 10] + +RFC 5334 Ogg Media Types September 2008 + + +13. References + +13.1. Normative References + + [RFC2045] Freed, N. and N. Borenstein, "Multipurpose Internet Mail + Extensions (MIME) Part One: Format of Internet Message + Bodies", RFC 2045, November 1996. + + [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate + Requirement Levels", BCP 14, RFC 2119, March 1997. + + [RFC3533] Pfeiffer, S., "The Ogg Encapsulation Format Version 0", + RFC 3533, May 2003. + + [RFC4281] Gellens, R., Singer, D., and P. Frojdh, "The Codecs + Parameter for "Bucket" Media Types", RFC 4281, + November 2005. + + [RFC4288] Freed, N. and J. Klensin, "Media Type Specifications and + Registration Procedures", BCP 13, RFC 4288, + December 2005. + +13.2. Informative References + + [CMML] Pfeiffer, S., Parker, C., and A. Pang, "The Continuous + Media Markup Language (CMML)", Work in Progress, + March 2006. + + [Codecs] Pfeiffer, S. and I. Goncalves, "Specification of MIME + types and respective codecs parameter", July 2008, + . + + [Dirac] Dirac Group, "Dirac Specification", + . + + [FLAC] Coalson, J., "The FLAC Format", + . + + [libogg] Xiph.Org Foundation, "The libogg API", June 2000, + . + + [Ogg] Xiph.Org Foundation, "Ogg bitstream documentation: Ogg + logical and physical bitstream overview, Ogg logical + bitstream framing, Ogg multi-stream multiplexing", + . + + [RFC3534] Walleij, L., "The application/ogg Media Type", RFC 3534, + May 2003. + + + +Goncalves, et al. Standards Track [Page 11] + +RFC 5334 Ogg Media Types September 2008 + + + [RFC3552] Rescorla, E. and B. Korver, "Guidelines for Writing RFC + Text on Security Considerations", BCP 72, RFC 3552, + July 2003. + + [RFC4648] Josefsson, S., "The Base16, Base32, and Base64 Data + Encodings", RFC 4648, October 2006. + + [RFC5215] Barbato, L., "RTP Payload Format for Vorbis Encoded + Audio", RFC 5215, August 2008. + + [Skeleton] Pfeiffer, S. and C. Parker, "The Ogg Skeleton Metadata + Bitstream", November 2007, + . + + [Speex] Valin, J., "The Speex Codec Manual", February 2002, + . + + [SpRTP] Herlein, G., Valin, J., Heggestad, A., and A. Moizard, + "RTP Payload Format for the Speex Codec", Work + in Progress, February 2008. + + [Theora] Xiph.Org Foundation, "Theora Specification", + October 2007, . + + [ThRTP] Barbato, L., "RTP Payload Format for Theora Encoded + Video", Work in Progress, June 2006. + + [Vorbis] Xiph.Org Foundation, "Vorbis I Specification", July 2004, + . + + + + + + + + + + + + + + + + + + + + + + +Goncalves, et al. Standards Track [Page 12] + +RFC 5334 Ogg Media Types September 2008 + + +Authors' Addresses + + Ivo Emanuel Goncalves + Xiph.Org Foundation + 21 College Hill Road + Somerville, MA 02144 + US + + EMail: justivo@gmail.com + URI: xmpp:justivo@gmail.com + + + Silvia Pfeiffer + Xiph.Org Foundation + + EMail: silvia@annodex.net + URI: http://annodex.net/ + + + Christopher Montgomery + Xiph.Org Foundation + + EMail: monty@xiph.org + URI: http://xiph.org + + + + + + + + + + + + + + + + + + + + + + + + + + + +Goncalves, et al. Standards Track [Page 13] + +RFC 5334 Ogg Media Types September 2008 + + +Full Copyright Statement + + Copyright (C) The IETF Trust (2008). + + This document is subject to the rights, licenses and restrictions + contained in BCP 78, and except as set forth therein, the authors + retain all their rights. + + This document and the information contained herein are provided on an + "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS + OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY, THE IETF TRUST AND + THE INTERNET ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF + THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED + WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + +Intellectual Property + + The IETF takes no position regarding the validity or scope of any + Intellectual Property Rights or other rights that might be claimed to + pertain to the implementation or use of the technology described in + this document or the extent to which any license under such rights + might or might not be available; nor does it represent that it has + made any independent effort to identify any such rights. Information + on the procedures with respect to rights in RFC documents can be + found in BCP 78 and BCP 79. + + Copies of IPR disclosures made to the IETF Secretariat and any + assurances of licenses to be made available, or the result of an + attempt made to obtain a general license or permission for the use of + such proprietary rights by implementers or users of this + specification can be obtained from the IETF on-line IPR repository at + http://www.ietf.org/ipr. + + The IETF invites any interested party to bring to its attention any + copyrights, patents or patent applications, or other proprietary + rights that may cover technology that may be required to implement + this standard. Please address the information to the IETF at + ietf-ipr@ietf.org. + + + + + + + + + + + + +Goncalves, et al. Standards Track [Page 14] + diff --git a/extern/ogg/doc/skeleton.html b/extern/ogg/doc/skeleton.html new file mode 100755 index 0000000..8b29c18 --- /dev/null +++ b/extern/ogg/doc/skeleton.html @@ -0,0 +1,222 @@ + + + + + +The Ogg Skeleton Metadata Bitstream + + + + + + + + + +

    The Ogg Skeleton Metadata Bitstream

    + +

    Overview

    + +

    Ogg Skeleton provides structuring information for multitrack Ogg files. It is compatible with Ogg Theora and provides extra clues for synchronization and content negotiation such as language selection.

    + +

    Ogg is a generic container format for time-continuous data streams, enabling interleaving of several tracks of frame-wise encoded content in a time-multiplexed manner. As an example, an Ogg physical bitstream could encapsulate several tracks of video encoded in Theora and multiple tracks of audio encoded in Speex or Vorbis or FLAC at the same time. A player that decodes such a bitstream could then, for example, play one video channel as the main video playback, alpha-blend another one on top of it (e.g. a caption track), play a main Vorbis audio together with several FLAC audio tracks simultaneously (e.g. as sound effects), and provide a choice of Speex channels (e.g. providing commentary in different languages). Such a file is generally possible to create with Ogg, it is however not possible to generically parse such a file, seek on it, understand what codecs are contained in such a file, and dynamically handle and play back such content.

    + +

    Ogg does not know anything about the content it carries and leaves it to the media mapping of each codec to declare and describe itself. There is no meta information available at the Ogg level about the content tracks encapsulated within an Ogg physical bitstream. This is particularly a problem if you don't have all the decoder libraries available and just want to parse an Ogg file to find out what type of data it encapsulates (such as the "file" command under *nix to determine what file it is through magic numbers), or want to seek to a temporal offset without having to decode the data (such as on a Web server that just serves out Ogg files and parts thereof).

    + +

    Ogg Skeleton is being designed to overcome these problems. Ogg Skeleton is a logical bitstream within an Ogg stream that contains information about the other encapsulated logical bitstreams. For each logical bitstream it provides information such as its media type, and explains the way the granulepos field in Ogg pages is mapped to time.

    + +

    Ogg Skeleton is also designed to allow the creation of substreams from Ogg physical bitstreams that retain the original timing information. For example, when cutting out the segment between the 7th and the 59th second of an Ogg file, it would be nice to continue to start this cut out file with a playback time of 7 seconds and not of 0. This is of particular interest if you're streaming this file from a Web server after a query for a temporal subpart such as in http://example.com/video.ogv?t=7-59

    + +

    Specification

    + +

    How to describe the logical bitstreams within an Ogg container?

    + +

    The following information about a logical bitstream is of interest to contain as meta information in the Skeleton:

    +
      +
    • the serial number: it identifies a content track
    • +
    • the mime type: it identifies the content type
    • +
    • other generic name-value fields that can provide meta information such as the language of a track or the video height and width
    • +
    • the number of header packets: this informs a parser about the number of actual header packets in an Ogg logical bitstream
    • +
    • the granule rate: the granule rate represents the data rate in Hz at which content is sampled for the particular logical bitstream, allowing to map a granule position to time by calculating "granulepos / granulerate"
    • +
    • the preroll: the number of past content packets to take into account when decoding the current Ogg page, which is necessary for seeking (vorbis has generally 2, speex 3)
    • +
    • the granuleshift: the number of lower bits from the granulepos field that are used to provide position information for sub-seekable units (like the keyframe shift in theora)
    • +
    • a basetime: it provides a mapping for granule position 0 (for all logical bitstreams) to a playback time; an example use: most content in professional analog video creation actually starts at a time of 1 hour and thus adding this additional field allows them retain this mapping on digitizing their content
    • +
    • a UTC time: it provides a mapping for granule position 0 (for all logical bitstreams) to a real-world clock time allowing to remember e.g. the recording or broadcast time of some content
    • +
    + +

    How to allow the creation of substreams from an Ogg physical bitstream?

    + +

    When cutting out a subpart of an Ogg physical bitstream, the aim is to keep all the content pages intact (including the framing and granule positions) and just change some information in the Skeleton that allows reconstruction of the accurate time mapping. When remultiplexing such a bitstream, it is necessary to take into account all the different contained logical bitstreams. A given cut-in time maps to several different byte positions in the Ogg physical bitstream because each logical bitstream has its relevant information for that time at a different location. In addition, the resolution of each logical bitstream may not be high enough to accommodate for the given cut-in time and thus there may be some surplus information necessary to be remuxed into the new bitstream.

    + +

    The following information is necessary to be added to the Skeleton to allow a correct presentation of a subpart of an Ogg bitstream:

    +
      +
    • the presentation time: this is the actual cut-in time and all logical bitstreams are meant to start presenting from this time onwards, not from the time their data starts, which may be some time before that (because this time may have mapped right into the middle of a packet, or because the logical bitstream has a preroll or a keyframe shift)
    • +
    • the basegranule: this represents the granule number with which this logical bitstream starts in the remuxed stream and provides for each logical bitstream the accurate start time of its data stream; this information is necessary to allow correct decoding and timing of the first data packets contained in a logcial bitstream of a remuxed Ogg stream
    • +
    + +

    Ogg Skeleton version 3.0 Format Specification

    + +

    Adding the above information into an Ogg bitstream without breaking existing Ogg functionality and code requires the use of a logical bitstream for Ogg Skeleton. This logical bitstream may be ignored on decoding such that existing players can still continue to play back Ogg files that have a Skeleton bitstream. Skeleton enriches the Ogg bitstream to provide meta information about structure and content of the Ogg bitstream.

    + +

    The Skeleton logical bitstream starts with an ident header that contains information about all of the logical bitstreams and is mapped into the Skeleton bos page. The first 8 bytes provide the magic identifier "fishead\0". +After the fishead follows a set of secondary header packets, each of which contains information about one logical bitstream. These secondary header packets are identified by an 8 byte code of "fisbone\0". The Skeleton logical bitstream has no actual content packets. Its eos page is included into the stream before any data pages of the other logical bitstreams appear and contains a packet of length 0.

    + +

    The fishead ident header looks as follows:

    +
    +
    +  0                   1                   2                   3
    +  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1| Byte
    + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    + | Identifier 'fishead\0'                                        | 0-3
    + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    + |                                                               | 4-7
    + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    + | Version major                 | Version minor                 | 8-11
    + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    + | Presentationtime numerator                                    | 12-15
    + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    + |                                                               | 16-19
    + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    + | Presentationtime denominator                                  | 20-23
    + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    + |                                                               | 24-27
    + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    + | Basetime numerator                                            | 28-31
    + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    + |                                                               | 32-35
    + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    + | Basetime denominator                                          | 36-39
    + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    + |                                                               | 40-43
    + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    + | UTC                                                           | 44-47
    + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    + |                                                               | 48-51
    + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    + |                                                               | 52-55
    + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    + |                                                               | 56-59
    + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    + |                                                               | 60-63
    + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    +
    +
    +

    The version fields provide version information for the Skeleton track, currently being 3.0 (the number having evolved within the Annodex project).

    + +

    Presentation time and basetime are specified as a rational number, the denominator providing the temporal resolution at which the time is given (e.g. to specify time in milliseconds, provide a denominator of 1000).

    + +

    The fisbone secondary header packet looks as follows:

    +
    +
    +  0                   1                   2                   3
    +  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1| Byte
    + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    + | Identifier 'fisbone\0'                                        | 0-3
    + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    + |                                                               | 4-7
    + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    + | Offset to message header fields                               | 8-11
    + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    + | Serial number                                                 | 12-15
    + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    + | Number of header packets                                      | 16-19
    + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    + | Granulerate numerator                                         | 20-23
    + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    + |                                                               | 24-27
    + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    + | Granulerate denominator                                       | 28-31
    + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    + |                                                               | 32-35
    + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    + | Basegranule                                                   | 36-39
    + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    + |                                                               | 40-43
    + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    + | Preroll                                                       | 44-47
    + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    + | Granuleshift  | Padding/future use                            | 48-51
    + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    + | Message header fields ...                                     | 52-
    + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    +
    +
    +

    The mime type is provided as a message header field specified in the same way that HTTP header fields are given (e.g. "Content-Type: audio/vorbis"). Further meta information (such as language and screen size) are also included as message header fields. The offset to the message header fields at the beginning of a fisbone packet is included for forward compatibility - to allow further fields to be included into the packet without disrupting the message header field parsing.

    + +

    The granule rate is again given as a rational number in the same way that presentation time and basetime were provided above.

    + +

    A further restriction on how to encapsulate Skeleton into Ogg is proposed to allow for easier parsing:

    +
      +
    • there can only be one Skeleton logical bitstream in a Ogg bitstream
    • +
    • the Skeleton bos page is the very first bos page in the Ogg stream such that it can be identified straight away and decoders don't get confused about it being e.g. Ogg Vorbis without this meta information
    • +
    • the bos pages of all the other logical bistreams come next (a requirement of Ogg)
    • +
    • the secondary header pages of all logical bitstreams come next, including Skeleton's secondary header packets
    • +
    • the Skeleton eos page end the control section of the Ogg stream before any content pages of any of the other logical bitstreams appear
    • +
    + + + + + \ No newline at end of file diff --git a/extern/ogg/doc/stream.png b/extern/ogg/doc/stream.png new file mode 100644 index 0000000..ce2d2da Binary files /dev/null and b/extern/ogg/doc/stream.png differ diff --git a/extern/ogg/doc/vorbisword2.png b/extern/ogg/doc/vorbisword2.png new file mode 100644 index 0000000..12e3d31 Binary files /dev/null and b/extern/ogg/doc/vorbisword2.png differ diff --git a/extern/ogg/doc/white-ogg.png b/extern/ogg/doc/white-ogg.png new file mode 100644 index 0000000..2694296 Binary files /dev/null and b/extern/ogg/doc/white-ogg.png differ diff --git a/extern/ogg/doc/white-xifish.png b/extern/ogg/doc/white-xifish.png new file mode 100644 index 0000000..ab25cc8 Binary files /dev/null and b/extern/ogg/doc/white-xifish.png differ diff --git a/extern/ogg/include/Makefile.am b/extern/ogg/include/Makefile.am new file mode 100644 index 0000000..0084e4d --- /dev/null +++ b/extern/ogg/include/Makefile.am @@ -0,0 +1,3 @@ +## Process this file with automake to produce Makefile.in + +SUBDIRS = ogg diff --git a/extern/ogg/include/ogg/Makefile.am b/extern/ogg/include/ogg/Makefile.am new file mode 100644 index 0000000..142699d --- /dev/null +++ b/extern/ogg/include/ogg/Makefile.am @@ -0,0 +1,6 @@ +## Process this file with automake to produce Makefile.in + +oggincludedir = $(includedir)/ogg + +ogginclude_HEADERS = ogg.h os_types.h +nodist_ogginclude_HEADERS = config_types.h diff --git a/extern/ogg/include/ogg/config_types.h.in b/extern/ogg/include/ogg/config_types.h.in new file mode 100644 index 0000000..898c3f1 --- /dev/null +++ b/extern/ogg/include/ogg/config_types.h.in @@ -0,0 +1,26 @@ +#ifndef __CONFIG_TYPES_H__ +#define __CONFIG_TYPES_H__ + +/* these are filled in by configure or cmake*/ +#define INCLUDE_INTTYPES_H @INCLUDE_INTTYPES_H@ +#define INCLUDE_STDINT_H @INCLUDE_STDINT_H@ +#define INCLUDE_SYS_TYPES_H @INCLUDE_SYS_TYPES_H@ + +#if INCLUDE_INTTYPES_H +# include +#endif +#if INCLUDE_STDINT_H +# include +#endif +#if INCLUDE_SYS_TYPES_H +# include +#endif + +typedef @SIZE16@ ogg_int16_t; +typedef @USIZE16@ ogg_uint16_t; +typedef @SIZE32@ ogg_int32_t; +typedef @USIZE32@ ogg_uint32_t; +typedef @SIZE64@ ogg_int64_t; +typedef @USIZE64@ ogg_uint64_t; + +#endif diff --git a/extern/ogg/include/ogg/ogg.h b/extern/ogg/include/ogg/ogg.h new file mode 100644 index 0000000..c4325aa --- /dev/null +++ b/extern/ogg/include/ogg/ogg.h @@ -0,0 +1,209 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2007 * + * by the Xiph.Org Foundation http://www.xiph.org/ * + * * + ******************************************************************** + + function: toplevel libogg include + + ********************************************************************/ +#ifndef _OGG_H +#define _OGG_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +typedef struct { + void *iov_base; + size_t iov_len; +} ogg_iovec_t; + +typedef struct { + long endbyte; + int endbit; + + unsigned char *buffer; + unsigned char *ptr; + long storage; +} oggpack_buffer; + +/* ogg_page is used to encapsulate the data in one Ogg bitstream page *****/ + +typedef struct { + unsigned char *header; + long header_len; + unsigned char *body; + long body_len; +} ogg_page; + +/* ogg_stream_state contains the current encode/decode state of a logical + Ogg bitstream **********************************************************/ + +typedef struct { + unsigned char *body_data; /* bytes from packet bodies */ + long body_storage; /* storage elements allocated */ + long body_fill; /* elements stored; fill mark */ + long body_returned; /* elements of fill returned */ + + + int *lacing_vals; /* The values that will go to the segment table */ + ogg_int64_t *granule_vals; /* granulepos values for headers. Not compact + this way, but it is simple coupled to the + lacing fifo */ + long lacing_storage; + long lacing_fill; + long lacing_packet; + long lacing_returned; + + unsigned char header[282]; /* working space for header encode */ + int header_fill; + + int e_o_s; /* set when we have buffered the last packet in the + logical bitstream */ + int b_o_s; /* set after we've written the initial page + of a logical bitstream */ + long serialno; + long pageno; + ogg_int64_t packetno; /* sequence number for decode; the framing + knows where there's a hole in the data, + but we need coupling so that the codec + (which is in a separate abstraction + layer) also knows about the gap */ + ogg_int64_t granulepos; + +} ogg_stream_state; + +/* ogg_packet is used to encapsulate the data and metadata belonging + to a single raw Ogg/Vorbis packet *************************************/ + +typedef struct { + unsigned char *packet; + long bytes; + long b_o_s; + long e_o_s; + + ogg_int64_t granulepos; + + ogg_int64_t packetno; /* sequence number for decode; the framing + knows where there's a hole in the data, + but we need coupling so that the codec + (which is in a separate abstraction + layer) also knows about the gap */ +} ogg_packet; + +typedef struct { + unsigned char *data; + int storage; + int fill; + int returned; + + int unsynced; + int headerbytes; + int bodybytes; +} ogg_sync_state; + +/* Ogg BITSTREAM PRIMITIVES: bitstream ************************/ + +extern void oggpack_writeinit(oggpack_buffer *b); +extern int oggpack_writecheck(oggpack_buffer *b); +extern void oggpack_writetrunc(oggpack_buffer *b,long bits); +extern void oggpack_writealign(oggpack_buffer *b); +extern void oggpack_writecopy(oggpack_buffer *b,void *source,long bits); +extern void oggpack_reset(oggpack_buffer *b); +extern void oggpack_writeclear(oggpack_buffer *b); +extern void oggpack_readinit(oggpack_buffer *b,unsigned char *buf,int bytes); +extern void oggpack_write(oggpack_buffer *b,unsigned long value,int bits); +extern long oggpack_look(oggpack_buffer *b,int bits); +extern long oggpack_look1(oggpack_buffer *b); +extern void oggpack_adv(oggpack_buffer *b,int bits); +extern void oggpack_adv1(oggpack_buffer *b); +extern long oggpack_read(oggpack_buffer *b,int bits); +extern long oggpack_read1(oggpack_buffer *b); +extern long oggpack_bytes(oggpack_buffer *b); +extern long oggpack_bits(oggpack_buffer *b); +extern unsigned char *oggpack_get_buffer(oggpack_buffer *b); + +extern void oggpackB_writeinit(oggpack_buffer *b); +extern int oggpackB_writecheck(oggpack_buffer *b); +extern void oggpackB_writetrunc(oggpack_buffer *b,long bits); +extern void oggpackB_writealign(oggpack_buffer *b); +extern void oggpackB_writecopy(oggpack_buffer *b,void *source,long bits); +extern void oggpackB_reset(oggpack_buffer *b); +extern void oggpackB_writeclear(oggpack_buffer *b); +extern void oggpackB_readinit(oggpack_buffer *b,unsigned char *buf,int bytes); +extern void oggpackB_write(oggpack_buffer *b,unsigned long value,int bits); +extern long oggpackB_look(oggpack_buffer *b,int bits); +extern long oggpackB_look1(oggpack_buffer *b); +extern void oggpackB_adv(oggpack_buffer *b,int bits); +extern void oggpackB_adv1(oggpack_buffer *b); +extern long oggpackB_read(oggpack_buffer *b,int bits); +extern long oggpackB_read1(oggpack_buffer *b); +extern long oggpackB_bytes(oggpack_buffer *b); +extern long oggpackB_bits(oggpack_buffer *b); +extern unsigned char *oggpackB_get_buffer(oggpack_buffer *b); + +/* Ogg BITSTREAM PRIMITIVES: encoding **************************/ + +extern int ogg_stream_packetin(ogg_stream_state *os, ogg_packet *op); +extern int ogg_stream_iovecin(ogg_stream_state *os, ogg_iovec_t *iov, + int count, long e_o_s, ogg_int64_t granulepos); +extern int ogg_stream_pageout(ogg_stream_state *os, ogg_page *og); +extern int ogg_stream_pageout_fill(ogg_stream_state *os, ogg_page *og, int nfill); +extern int ogg_stream_flush(ogg_stream_state *os, ogg_page *og); +extern int ogg_stream_flush_fill(ogg_stream_state *os, ogg_page *og, int nfill); + +/* Ogg BITSTREAM PRIMITIVES: decoding **************************/ + +extern int ogg_sync_init(ogg_sync_state *oy); +extern int ogg_sync_clear(ogg_sync_state *oy); +extern int ogg_sync_reset(ogg_sync_state *oy); +extern int ogg_sync_destroy(ogg_sync_state *oy); +extern int ogg_sync_check(ogg_sync_state *oy); + +extern char *ogg_sync_buffer(ogg_sync_state *oy, long size); +extern int ogg_sync_wrote(ogg_sync_state *oy, long bytes); +extern long ogg_sync_pageseek(ogg_sync_state *oy,ogg_page *og); +extern int ogg_sync_pageout(ogg_sync_state *oy, ogg_page *og); +extern int ogg_stream_pagein(ogg_stream_state *os, ogg_page *og); +extern int ogg_stream_packetout(ogg_stream_state *os,ogg_packet *op); +extern int ogg_stream_packetpeek(ogg_stream_state *os,ogg_packet *op); + +/* Ogg BITSTREAM PRIMITIVES: general ***************************/ + +extern int ogg_stream_init(ogg_stream_state *os,int serialno); +extern int ogg_stream_clear(ogg_stream_state *os); +extern int ogg_stream_reset(ogg_stream_state *os); +extern int ogg_stream_reset_serialno(ogg_stream_state *os,int serialno); +extern int ogg_stream_destroy(ogg_stream_state *os); +extern int ogg_stream_check(ogg_stream_state *os); +extern int ogg_stream_eos(ogg_stream_state *os); + +extern void ogg_page_checksum_set(ogg_page *og); + +extern int ogg_page_version(const ogg_page *og); +extern int ogg_page_continued(const ogg_page *og); +extern int ogg_page_bos(const ogg_page *og); +extern int ogg_page_eos(const ogg_page *og); +extern ogg_int64_t ogg_page_granulepos(const ogg_page *og); +extern int ogg_page_serialno(const ogg_page *og); +extern long ogg_page_pageno(const ogg_page *og); +extern int ogg_page_packets(const ogg_page *og); + +extern void ogg_packet_clear(ogg_packet *op); + + +#ifdef __cplusplus +} +#endif + +#endif /* _OGG_H */ diff --git a/extern/ogg/include/ogg/os_types.h b/extern/ogg/include/ogg/os_types.h new file mode 100644 index 0000000..eb8a322 --- /dev/null +++ b/extern/ogg/include/ogg/os_types.h @@ -0,0 +1,158 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2002 * + * by the Xiph.Org Foundation http://www.xiph.org/ * + * * + ******************************************************************** + + function: Define a consistent set of types on each platform. + + ********************************************************************/ +#ifndef _OS_TYPES_H +#define _OS_TYPES_H + +/* make it easy on the folks that want to compile the libs with a + different malloc than stdlib */ +#define _ogg_malloc malloc +#define _ogg_calloc calloc +#define _ogg_realloc realloc +#define _ogg_free free + +#if defined(_WIN32) + +# if defined(__CYGWIN__) +# include + typedef int16_t ogg_int16_t; + typedef uint16_t ogg_uint16_t; + typedef int32_t ogg_int32_t; + typedef uint32_t ogg_uint32_t; + typedef int64_t ogg_int64_t; + typedef uint64_t ogg_uint64_t; +# elif defined(__MINGW32__) +# include + typedef short ogg_int16_t; + typedef unsigned short ogg_uint16_t; + typedef int ogg_int32_t; + typedef unsigned int ogg_uint32_t; + typedef long long ogg_int64_t; + typedef unsigned long long ogg_uint64_t; +# elif defined(__MWERKS__) + typedef long long ogg_int64_t; + typedef unsigned long long ogg_uint64_t; + typedef int ogg_int32_t; + typedef unsigned int ogg_uint32_t; + typedef short ogg_int16_t; + typedef unsigned short ogg_uint16_t; +# else +# if defined(_MSC_VER) && (_MSC_VER >= 1800) /* MSVC 2013 and newer */ +# include + typedef int16_t ogg_int16_t; + typedef uint16_t ogg_uint16_t; + typedef int32_t ogg_int32_t; + typedef uint32_t ogg_uint32_t; + typedef int64_t ogg_int64_t; + typedef uint64_t ogg_uint64_t; +# else + /* MSVC/Borland */ + typedef __int64 ogg_int64_t; + typedef __int32 ogg_int32_t; + typedef unsigned __int32 ogg_uint32_t; + typedef unsigned __int64 ogg_uint64_t; + typedef __int16 ogg_int16_t; + typedef unsigned __int16 ogg_uint16_t; +# endif +# endif + +#elif (defined(__APPLE__) && defined(__MACH__)) /* MacOS X Framework build */ + +# include + typedef int16_t ogg_int16_t; + typedef uint16_t ogg_uint16_t; + typedef int32_t ogg_int32_t; + typedef uint32_t ogg_uint32_t; + typedef int64_t ogg_int64_t; + typedef uint64_t ogg_uint64_t; + +#elif defined(__HAIKU__) + + /* Haiku */ +# include + typedef short ogg_int16_t; + typedef unsigned short ogg_uint16_t; + typedef int ogg_int32_t; + typedef unsigned int ogg_uint32_t; + typedef long long ogg_int64_t; + typedef unsigned long long ogg_uint64_t; + +#elif defined(__BEOS__) + + /* Be */ +# include + typedef int16_t ogg_int16_t; + typedef uint16_t ogg_uint16_t; + typedef int32_t ogg_int32_t; + typedef uint32_t ogg_uint32_t; + typedef int64_t ogg_int64_t; + typedef uint64_t ogg_uint64_t; + +#elif defined (__EMX__) + + /* OS/2 GCC */ + typedef short ogg_int16_t; + typedef unsigned short ogg_uint16_t; + typedef int ogg_int32_t; + typedef unsigned int ogg_uint32_t; + typedef long long ogg_int64_t; + typedef unsigned long long ogg_uint64_t; + + +#elif defined (DJGPP) + + /* DJGPP */ + typedef short ogg_int16_t; + typedef int ogg_int32_t; + typedef unsigned int ogg_uint32_t; + typedef long long ogg_int64_t; + typedef unsigned long long ogg_uint64_t; + +#elif defined(R5900) + + /* PS2 EE */ + typedef long ogg_int64_t; + typedef unsigned long ogg_uint64_t; + typedef int ogg_int32_t; + typedef unsigned ogg_uint32_t; + typedef short ogg_int16_t; + +#elif defined(__SYMBIAN32__) + + /* Symbian GCC */ + typedef signed short ogg_int16_t; + typedef unsigned short ogg_uint16_t; + typedef signed int ogg_int32_t; + typedef unsigned int ogg_uint32_t; + typedef long long int ogg_int64_t; + typedef unsigned long long int ogg_uint64_t; + +#elif defined(__TMS320C6X__) + + /* TI C64x compiler */ + typedef signed short ogg_int16_t; + typedef unsigned short ogg_uint16_t; + typedef signed int ogg_int32_t; + typedef unsigned int ogg_uint32_t; + typedef long long int ogg_int64_t; + typedef unsigned long long int ogg_uint64_t; + +#else + +# include + +#endif + +#endif /* _OS_TYPES_H */ diff --git a/extern/ogg/libogg.spec.in b/extern/ogg/libogg.spec.in new file mode 100644 index 0000000..41e9307 --- /dev/null +++ b/extern/ogg/libogg.spec.in @@ -0,0 +1,109 @@ +Name: libogg +Version: @VERSION@ +Release: 0.xiph.1 +Summary: Ogg Bitstream Library. + +Group: System Environment/Libraries +License: BSD +URL: http://www.xiph.org/ +Vendor: Xiph.org Foundation +Source: http://www.vorbis.com/files/1.0.1/unix/%{name}-%{version}.tar.gz +BuildRoot: %{_tmppath}/%{name}-%{version}-root + +# We're forced to use an epoch since both Red Hat and Ximian use it in their +# rc packages +Epoch: 2 +# Dirty trick to tell rpm that this package actually provides what the +# last rc and beta was offering +Provides: %{name} = %{epoch}:1.0rc3-%{release} +Provides: %{name} = %{epoch}:1.0beta4-%{release} + +%description +Libogg is a library for manipulating ogg bitstreams. It handles +both making ogg bitstreams and getting packets from ogg bitstreams. + +%package devel +Summary: Ogg Bitstream Library Development +Group: Development/Libraries +Requires: libogg = %{version} +# Dirty trick to tell rpm that this package actually provides what the +# last rc and beta was offering +Provides: %{name}-devel = %{epoch}:1.0rc3-%{release} +Provides: %{name}-devel = %{epoch}:1.0beta4-%{release} + +%description devel +The libogg-devel package contains the header files, static libraries +and documentation needed to develop applications with libogg. + +%prep +%setup -q -n %{name}-%{version} + +%build +CFLAGS="$RPM_OPT_FLAGS" ./configure --prefix=%{_prefix} --enable-static +make + +%install +rm -rf $RPM_BUILD_ROOT + +make DESTDIR=$RPM_BUILD_ROOT install + +%clean +rm -rf $RPM_BUILD_ROOT + +%post -p /sbin/ldconfig + +%postun -p /sbin/ldconfig + +%files +%defattr(-,root,root) +%doc AUTHORS CHANGES COPYING README +%{_libdir}/libogg.so.* + +%files devel +%defattr(-,root,root) +%doc doc/index.html +%doc doc/framing.html +%doc doc/oggstream.html +%doc doc/white-ogg.png +%doc doc/white-xifish.png +%doc doc/stream.png +%doc doc/libogg/*.html +%doc doc/libogg/style.css +%dir %{_includedir}/ogg +%{_includedir}/ogg/ogg.h +%{_includedir}/ogg/os_types.h +%{_includedir}/ogg/config_types.h +%{_libdir}/libogg.a +%{_libdir}/libogg.la +%{_libdir}/libogg.so +%{_libdir}/pkgconfig/ogg.pc +%{_datadir}/aclocal/ogg.m4 + +%changelog +* Thu Nov 08 2007 Conrad Parker +- update doc dir (reported by thosmos on #vorbis) + +* Thu Jun 10 2004 Thomas Vander Stichele +- autogenerate from configure +- fix download location +- remove Prefix +- own include dir +- move ldconfig runs to -p scripts +- change Release tag to include xiph + +* Tue Oct 07 2003 Warren Dukes +- update for 1.1 release + +* Sun Jul 14 2002 Thomas Vander Stichele +- update for 1.0 release +- conform Group to Red Hat's idea of it +- take out case where configure doesn't exist; a tarball should have it + +* Tue Dec 18 2001 Jack Moffitt +- Update for RC3 release + +* Sun Oct 07 2001 Jack Moffitt +- add support for configurable prefixes + +* Sat Sep 02 2000 Jack Moffitt +- initial spec file created diff --git a/extern/ogg/macosx/English.lproj/InfoPlist.strings b/extern/ogg/macosx/English.lproj/InfoPlist.strings new file mode 100644 index 0000000..b230fea Binary files /dev/null and b/extern/ogg/macosx/English.lproj/InfoPlist.strings differ diff --git a/extern/ogg/macosx/Info.plist b/extern/ogg/macosx/Info.plist new file mode 100644 index 0000000..d075456 --- /dev/null +++ b/extern/ogg/macosx/Info.plist @@ -0,0 +1,30 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + Ogg + CFBundleGetInfoString + Ogg framework 1.1.4, Copyright © 1994-2009 Xiph.Org Foundation + CFBundleIconFile + + CFBundleIdentifier + org.xiph.ogg + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.1.4 + CFBundleSignature + ???? + CFBundleVersion + 1.1.4 + NSHumanReadableCopyright + Ogg framework 1.1.4, Copyright © 1994-2009 Xiph.Org Foundation + CSResourcesFileMapped + + + diff --git a/extern/ogg/macosx/Ogg.xcodeproj/project.pbxproj b/extern/ogg/macosx/Ogg.xcodeproj/project.pbxproj new file mode 100644 index 0000000..596ccda --- /dev/null +++ b/extern/ogg/macosx/Ogg.xcodeproj/project.pbxproj @@ -0,0 +1,363 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 42; + objects = { + +/* Begin PBXBuildFile section */ + 730F236309181A8D00AB638C /* bitwise.c in Sources */ = {isa = PBXBuildFile; fileRef = 730F236109181A8D00AB638C /* bitwise.c */; }; + 730F236409181A8D00AB638C /* framing.c in Sources */ = {isa = PBXBuildFile; fileRef = 730F236209181A8D00AB638C /* framing.c */; }; + 730F236709181ABE00AB638C /* ogg.h in Headers */ = {isa = PBXBuildFile; fileRef = 730F236509181ABE00AB638C /* ogg.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 730F236809181ABE00AB638C /* os_types.h in Headers */ = {isa = PBXBuildFile; fileRef = 730F236609181ABE00AB638C /* os_types.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 734FB2E70B18B36F00D561D7 /* bitwise.c in Sources */ = {isa = PBXBuildFile; fileRef = 730F236109181A8D00AB638C /* bitwise.c */; }; + 734FB2E80B18B36F00D561D7 /* framing.c in Sources */ = {isa = PBXBuildFile; fileRef = 730F236209181A8D00AB638C /* framing.c */; }; + 8D07F2BE0486CC7A007CD1D0 /* Ogg_Prefix.pch in Headers */ = {isa = PBXBuildFile; fileRef = 32BAE0B70371A74B00C91783 /* Ogg_Prefix.pch */; }; + 8D07F2C00486CC7A007CD1D0 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 089C1666FE841158C02AAC07 /* InfoPlist.strings */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 089C1667FE841158C02AAC07 /* English */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/InfoPlist.strings; sourceTree = ""; }; + 32BAE0B70371A74B00C91783 /* Ogg_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Ogg_Prefix.pch; sourceTree = ""; }; + 730F236109181A8D00AB638C /* bitwise.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = bitwise.c; path = ../src/bitwise.c; sourceTree = SOURCE_ROOT; }; + 730F236209181A8D00AB638C /* framing.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = framing.c; path = ../src/framing.c; sourceTree = SOURCE_ROOT; }; + 730F236509181ABE00AB638C /* ogg.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = ogg.h; path = ../include/ogg/ogg.h; sourceTree = SOURCE_ROOT; }; + 730F236609181ABE00AB638C /* os_types.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = os_types.h; path = ../include/ogg/os_types.h; sourceTree = SOURCE_ROOT; }; + 734FB2E50B18B33E00D561D7 /* libogg.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libogg.a; sourceTree = BUILT_PRODUCTS_DIR; }; + 8D07F2C70486CC7A007CD1D0 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; + 8D07F2C80486CC7A007CD1D0 /* Ogg.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Ogg.framework; sourceTree = BUILT_PRODUCTS_DIR; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 734FB2E30B18B33E00D561D7 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 8D07F2C30486CC7A007CD1D0 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 034768DDFF38A45A11DB9C8B /* Products */ = { + isa = PBXGroup; + children = ( + 8D07F2C80486CC7A007CD1D0 /* Ogg.framework */, + 734FB2E50B18B33E00D561D7 /* libogg.a */, + ); + name = Products; + sourceTree = ""; + }; + 0867D691FE84028FC02AAC07 /* Ogg */ = { + isa = PBXGroup; + children = ( + 730F235F09181A3E00AB638C /* Headers */, + 08FB77ACFE841707C02AAC07 /* Source */, + 089C1665FE841158C02AAC07 /* Resources */, + 0867D69AFE84028FC02AAC07 /* External Frameworks and Libraries */, + 034768DDFF38A45A11DB9C8B /* Products */, + ); + name = Ogg; + sourceTree = ""; + }; + 0867D69AFE84028FC02AAC07 /* External Frameworks and Libraries */ = { + isa = PBXGroup; + children = ( + ); + name = "External Frameworks and Libraries"; + sourceTree = ""; + }; + 089C1665FE841158C02AAC07 /* Resources */ = { + isa = PBXGroup; + children = ( + 8D07F2C70486CC7A007CD1D0 /* Info.plist */, + 089C1666FE841158C02AAC07 /* InfoPlist.strings */, + ); + name = Resources; + sourceTree = ""; + }; + 08FB77ACFE841707C02AAC07 /* Source */ = { + isa = PBXGroup; + children = ( + 730F236109181A8D00AB638C /* bitwise.c */, + 730F236209181A8D00AB638C /* framing.c */, + 32BAE0B70371A74B00C91783 /* Ogg_Prefix.pch */, + ); + name = Source; + sourceTree = ""; + }; + 730F235F09181A3E00AB638C /* Headers */ = { + isa = PBXGroup; + children = ( + 730F236509181ABE00AB638C /* ogg.h */, + 730F236609181ABE00AB638C /* os_types.h */, + ); + name = Headers; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + 734FB2E10B18B33E00D561D7 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 8D07F2BD0486CC7A007CD1D0 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 8D07F2BE0486CC7A007CD1D0 /* Ogg_Prefix.pch in Headers */, + 730F236709181ABE00AB638C /* ogg.h in Headers */, + 730F236809181ABE00AB638C /* os_types.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + 734FB2E40B18B33E00D561D7 /* libogg (static) */ = { + isa = PBXNativeTarget; + buildConfigurationList = 734FB2ED0B18B3B900D561D7 /* Build configuration list for PBXNativeTarget "libogg (static)" */; + buildPhases = ( + 734FB2E10B18B33E00D561D7 /* Headers */, + 734FB2E20B18B33E00D561D7 /* Sources */, + 734FB2E30B18B33E00D561D7 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "libogg (static)"; + productName = ogg; + productReference = 734FB2E50B18B33E00D561D7 /* libogg.a */; + productType = "com.apple.product-type.library.static"; + }; + 8D07F2BC0486CC7A007CD1D0 /* Ogg */ = { + isa = PBXNativeTarget; + buildConfigurationList = 730F235409181A3A00AB638C /* Build configuration list for PBXNativeTarget "Ogg" */; + buildPhases = ( + 8D07F2BD0486CC7A007CD1D0 /* Headers */, + 8D07F2BF0486CC7A007CD1D0 /* Resources */, + 8D07F2C10486CC7A007CD1D0 /* Sources */, + 8D07F2C30486CC7A007CD1D0 /* Frameworks */, + 8D07F2C50486CC7A007CD1D0 /* Rez */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Ogg; + productInstallPath = "$(HOME)/Library/Frameworks"; + productName = Ogg; + productReference = 8D07F2C80486CC7A007CD1D0 /* Ogg.framework */; + productType = "com.apple.product-type.framework"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 0867D690FE84028FC02AAC07 /* Project object */ = { + isa = PBXProject; + buildConfigurationList = 730F235809181A3A00AB638C /* Build configuration list for PBXProject "Ogg" */; + hasScannedForEncodings = 1; + mainGroup = 0867D691FE84028FC02AAC07 /* Ogg */; + productRefGroup = 034768DDFF38A45A11DB9C8B /* Products */; + projectDirPath = ""; + targets = ( + 8D07F2BC0486CC7A007CD1D0 /* Ogg */, + 734FB2E40B18B33E00D561D7 /* libogg (static) */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 8D07F2BF0486CC7A007CD1D0 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 8D07F2C00486CC7A007CD1D0 /* InfoPlist.strings in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXRezBuildPhase section */ + 8D07F2C50486CC7A007CD1D0 /* Rez */ = { + isa = PBXRezBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXRezBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 734FB2E20B18B33E00D561D7 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 734FB2E70B18B36F00D561D7 /* bitwise.c in Sources */, + 734FB2E80B18B36F00D561D7 /* framing.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 8D07F2C10486CC7A007CD1D0 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 730F236309181A8D00AB638C /* bitwise.c in Sources */, + 730F236409181A8D00AB638C /* framing.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 089C1666FE841158C02AAC07 /* InfoPlist.strings */ = { + isa = PBXVariantGroup; + children = ( + 089C1667FE841158C02AAC07 /* English */, + ); + name = InfoPlist.strings; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 730F235509181A3A00AB638C /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + COPY_PHASE_STRIP = NO; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + FRAMEWORK_VERSION = A; + GCC_DYNAMIC_NO_PIC = NO; + GCC_ENABLE_FIX_AND_CONTINUE = YES; + GCC_GENERATE_DEBUGGING_SYMBOLS = YES; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = Ogg_Prefix.pch; + INFOPLIST_FILE = Info.plist; + INSTALL_PATH = /Library/Frameworks; + PRODUCT_NAME = Ogg; + WRAPPER_EXTENSION = framework; + ZERO_LINK = YES; + }; + name = Debug; + }; + 730F235609181A3A00AB638C /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + COPY_PHASE_STRIP = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + FRAMEWORK_VERSION = A; + GCC_ENABLE_FIX_AND_CONTINUE = NO; + GCC_GENERATE_DEBUGGING_SYMBOLS = NO; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = Ogg_Prefix.pch; + INFOPLIST_FILE = Info.plist; + INSTALL_PATH = /Library/Frameworks; + PRODUCT_NAME = Ogg; + WRAPPER_EXTENSION = framework; + ZERO_LINK = NO; + }; + name = Release; + }; + 730F235909181A3A00AB638C /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = __MACOSX__; + SDKROOT = /Developer/SDKs/MacOSX10.4u.sdk; + }; + name = Debug; + }; + 730F235A09181A3A00AB638C /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = ( + ppc, + i386, + ); + GCC_OPTIMIZATION_LEVEL = 3; + GCC_PREPROCESSOR_DEFINITIONS = __MACOSX__; + OTHER_CFLAGS = ( + "$(OTHER_CFLAGS)", + "-ffast-math", + "-falign-loops=16", + ); + SDKROOT = /Developer/SDKs/MacOSX10.4u.sdk; + }; + name = Release; + }; + 734FB2EE0B18B3B900D561D7 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + COPY_PHASE_STRIP = NO; + GCC_DYNAMIC_NO_PIC = NO; + GCC_ENABLE_FIX_AND_CONTINUE = YES; + GCC_GENERATE_DEBUGGING_SYMBOLS = YES; + INSTALL_PATH = /usr/local/lib; + PREBINDING = NO; + PRODUCT_NAME = ogg; + ZERO_LINK = YES; + }; + name = Debug; + }; + 734FB2EF0B18B3B900D561D7 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + COPY_PHASE_STRIP = YES; + GCC_ENABLE_FIX_AND_CONTINUE = NO; + GCC_GENERATE_DEBUGGING_SYMBOLS = NO; + INSTALL_PATH = /usr/local/lib; + PREBINDING = NO; + PRODUCT_NAME = ogg; + ZERO_LINK = NO; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 730F235409181A3A00AB638C /* Build configuration list for PBXNativeTarget "Ogg" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 730F235509181A3A00AB638C /* Debug */, + 730F235609181A3A00AB638C /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 730F235809181A3A00AB638C /* Build configuration list for PBXProject "Ogg" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 730F235909181A3A00AB638C /* Debug */, + 730F235A09181A3A00AB638C /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 734FB2ED0B18B3B900D561D7 /* Build configuration list for PBXNativeTarget "libogg (static)" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 734FB2EE0B18B3B900D561D7 /* Debug */, + 734FB2EF0B18B3B900D561D7 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 0867D690FE84028FC02AAC07 /* Project object */; +} diff --git a/extern/ogg/ogg-uninstalled.pc.in b/extern/ogg/ogg-uninstalled.pc.in new file mode 100644 index 0000000..7acad78 --- /dev/null +++ b/extern/ogg/ogg-uninstalled.pc.in @@ -0,0 +1,14 @@ +# ogg uninstalled pkg-config file + +prefix= +exec_prefix= +libdir=${pcfiledir}/src +includedir=${pcfiledir}/@top_srcdir@/include + +Name: ogg +Description: ogg is a library for manipulating ogg bitstreams (not installed) +Version: @VERSION@ +Requires: +Conflicts: +Libs: ${libdir}/.libs/libogg.la +Cflags: -I${includedir} diff --git a/extern/ogg/ogg.m4 b/extern/ogg/ogg.m4 new file mode 100644 index 0000000..17235da --- /dev/null +++ b/extern/ogg/ogg.m4 @@ -0,0 +1,116 @@ +# Configure paths for libogg +# Jack Moffitt 10-21-2000 +# Shamelessly stolen from Owen Taylor and Manish Singh + +dnl XIPH_PATH_OGG([ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]) +dnl Test for libogg, and define OGG_CFLAGS and OGG_LIBS +dnl +AC_DEFUN([XIPH_PATH_OGG], +[dnl +dnl Get the cflags and libraries +dnl +AC_ARG_WITH(ogg,AC_HELP_STRING([--with-ogg=PFX],[Prefix where libogg is installed (optional)]), ogg_prefix="$withval", ogg_prefix="") +AC_ARG_WITH(ogg-libraries,AC_HELP_STRING([--with-ogg-libraries=DIR],[Directory where libogg library is installed (optional)]), ogg_libraries="$withval", ogg_libraries="") +AC_ARG_WITH(ogg-includes,AC_HELP_STRING([--with-ogg-includes=DIR],[Directory where libogg header files are installed (optional)]), ogg_includes="$withval", ogg_includes="") +AC_ARG_ENABLE(oggtest,AC_HELP_STRING([--disable-oggtest],[Do not try to compile and run a test Ogg program]),, enable_oggtest=yes) + + if test "x$ogg_libraries" != "x" ; then + OGG_LIBS="-L$ogg_libraries" + elif test "x$ogg_prefix" = "xno" || test "x$ogg_prefix" = "xyes" ; then + OGG_LIBS="" + elif test "x$ogg_prefix" != "x" ; then + OGG_LIBS="-L$ogg_prefix/lib" + elif test "x$prefix" != "xNONE" ; then + OGG_LIBS="-L$prefix/lib" + fi + + if test "x$ogg_prefix" != "xno" ; then + OGG_LIBS="$OGG_LIBS -logg" + fi + + if test "x$ogg_includes" != "x" ; then + OGG_CFLAGS="-I$ogg_includes" + elif test "x$ogg_prefix" = "xno" || test "x$ogg_prefix" = "xyes" ; then + OGG_CFLAGS="" + elif test "x$ogg_prefix" != "x" ; then + OGG_CFLAGS="-I$ogg_prefix/include" + elif test "x$prefix" != "xNONE"; then + OGG_CFLAGS="-I$prefix/include" + fi + + AC_MSG_CHECKING(for Ogg) + if test "x$ogg_prefix" = "xno" ; then + no_ogg="disabled" + enable_oggtest="no" + else + no_ogg="" + fi + + + if test "x$enable_oggtest" = "xyes" ; then + ac_save_CFLAGS="$CFLAGS" + ac_save_LIBS="$LIBS" + CFLAGS="$CFLAGS $OGG_CFLAGS" + LIBS="$LIBS $OGG_LIBS" +dnl +dnl Now check if the installed Ogg is sufficiently new. +dnl + rm -f conf.oggtest + AC_TRY_RUN([ +#include +#include +#include +#include + +int main () +{ + system("touch conf.oggtest"); + return 0; +} + +],, no_ogg=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"]) + CFLAGS="$ac_save_CFLAGS" + LIBS="$ac_save_LIBS" + fi + + if test "x$no_ogg" = "xdisabled" ; then + AC_MSG_RESULT(no) + ifelse([$2], , :, [$2]) + elif test "x$no_ogg" = "x" ; then + AC_MSG_RESULT(yes) + ifelse([$1], , :, [$1]) + else + AC_MSG_RESULT(no) + if test -f conf.oggtest ; then + : + else + echo "*** Could not run Ogg test program, checking why..." + CFLAGS="$CFLAGS $OGG_CFLAGS" + LIBS="$LIBS $OGG_LIBS" + AC_TRY_LINK([ +#include +#include +], [ return 0; ], + [ echo "*** The test program compiled, but did not run. This usually means" + echo "*** that the run-time linker is not finding Ogg or finding the wrong" + echo "*** version of Ogg. If it is not finding Ogg, you'll need to set your" + echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point" + echo "*** to the installed location Also, make sure you have run ldconfig if that" + echo "*** is required on your system" + echo "***" + echo "*** If you have an old version installed, it is best to remove it, although" + echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH"], + [ echo "*** The test program failed to compile or link. See the file config.log for the" + echo "*** exact error that occurred. This usually means Ogg was incorrectly installed" + echo "*** or that you have moved Ogg since it was installed." ]) + CFLAGS="$ac_save_CFLAGS" + LIBS="$ac_save_LIBS" + fi + OGG_CFLAGS="" + OGG_LIBS="" + ifelse([$2], , :, [$2]) + fi + AC_SUBST(OGG_CFLAGS) + AC_SUBST(OGG_LIBS) + rm -f conf.oggtest +]) diff --git a/extern/ogg/ogg.pc.in b/extern/ogg/ogg.pc.in new file mode 100644 index 0000000..9e84375 --- /dev/null +++ b/extern/ogg/ogg.pc.in @@ -0,0 +1,14 @@ +# ogg pkg-config file + +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: ogg +Description: ogg is a library for manipulating ogg bitstreams +Version: @VERSION@ +Requires: +Conflicts: +Libs: -L${libdir} -logg +Cflags: -I${includedir} diff --git a/extern/ogg/releases.sha2 b/extern/ogg/releases.sha2 new file mode 100644 index 0000000..a37cd57 --- /dev/null +++ b/extern/ogg/releases.sha2 @@ -0,0 +1,37 @@ +c8a4157b0194962aa885e2088cf8561c65ce2eee36a77ca6325c6c36c842b2a9 libogg-1.0beta4.tar.gz +37bec40bf26ba6af8e98f2996051079cd2fbc4c401960fadb15c9e75383f3361 libogg-1.0rc1.tar.gz +c5f5924f25402a59a2586c3d037d3e79dae97de30531b8dd8b8b4abc20d5f036 libogg-1.0rc2.tar.gz +e907b7bc56de5a9dd0c5f062c7b0340a6295671cf2c6ad994d5f62919c9e1b0b libogg-1.0rc3.tar.gz +920fa2a0924d66884825d36a2e843de069cfdf1af01945d05da25999bbd6396c libogg-1.0.tar.gz +269f8f6b11b8ac737cbd8ed8cfa244cc51ca42b6da6683336ba1413d2a00ceb3 libogg-1.1.1.tar.gz +b72f4d716d8e1339469a874962aae5f055ba618772f00f43d3c6d0b543cdfadd libogg-1.1.1.zip +7934f3bf689c6ea0870bc73fcf40b00d5050044b03e558819a1ed333dc3cfadf libogg-1.1.2.tar.gz +01e97dd79336db38b31003ff956c7e29ebcfd8ceef8175cf17cf4f339a8c1a54 libogg-1.1.2.zip +bae29e79fbc50bbedf1235852094b71c8c910a1ef0cd42fe4163b7b545630b65 libogg-1.1.3.tar.gz +11c0202bc8f8e6fa361051a7d2dbc7ec95195b126c0407c5fc851d01c2a2ad6b libogg-1.1.3.zip +253d138b8c062db4d8446be1522162940dd89cad35c8332c3127d2e842850f31 libogg-1.1.4rc1.tar.gz +6bb65e5eafc75cc2ef7ccc37aea81749f1e72e503f7614e6748c06f532c42707 libogg-1.1.4rc1.zip +9354c183fd88417c2860778b60b7896c9487d8f6e58b9fec3fdbf971142ce103 libogg-1.1.4.tar.gz +0e9eb2370ba8d28ee6f6ccf27779c154fbfbd9c5e9d3a09e4419a85112a900ce libogg-1.1.4.zip +01453d561255b5fcb361997904752860e4f8c6b9742f290578a44615fcc94356 libogg-1.1.tar.gz +f30d983e238acd94e80ae551327ea2f83cdc330470b4188564bef28fec59eb69 libogg-1.2.0.tar.gz +6bf8650f0f3651fa4714ab9d03a5f781879e697d85d776f4dabc31877f42a0b2 libogg-1.2.0.zip +da222202be8be48149f0a0668f3d2445a166b1f9f40a25e27cd222bfa9c1d4d4 libogg-1.2.1.tar.bz2 +6858848617bca6eab01e7d8526bc0d2a417e95070a255cbf9c881881365e36c0 libogg-1.2.1.tar.gz +21e0a61e15e9dd294587bcd39d81fbe1998b27b1c525e15ecfaba94344f921b4 libogg-1.2.1.tar.xz +2d799a043865edc030ae56186a44624deb6365d59bcd8b3ae96384ccf613189d libogg-1.2.1.zip +ab000574bc26d5f01284f5b0f50e12dc761d035c429f2e9c70cb2a9487d8cfba libogg-1.2.2.tar.gz +559f1ea72a559520298e518865e488eb9a7185c6b9279f70602b01a87f7defed libogg-1.2.2.tar.xz +3f3bec05106d852da5ae3899ac2047dd14e2009bba872524eeade2d0bda42da0 libogg-1.2.2.zip +a8de807631014615549d2356fd36641833b8288221cea214f8a72750efe93780 libogg-1.3.0.tar.gz +231725029c843492914f24e74085e734bca6f1d6446ac72df39b0c3a9d4bc74b libogg-1.3.0.tar.xz +56db84601e7e855d1b9095ccba73d8ef98f063a2384f2239a7042070a3f1cde3 libogg-1.3.0.zip +4e343f07aa5a1de8e0fa1107042d472186b3470d846b20b115b964eba5bae554 libogg-1.3.1.tar.gz +3a5bad78d81afb78908326d11761c0fb1a0662ee7150b6ad587cc586838cdcfa libogg-1.3.1.tar.xz +131ae1f65f65e0ed70db03fbe3a9d9f2e8c24ac43754ae5e055fc55e6f750bc7 libogg-1.3.1.zip +e19ee34711d7af328cb26287f4137e70630e7261b17cbe3cd41011d73a654692 libogg-1.3.2.tar.gz +3f687ccdd5ac8b52d76328fbbfebc70c459a40ea891dbf3dccb74a210826e79b libogg-1.3.2.tar.xz +957b4168a03932e02853db340cfddd0fa89b6ca80073a54f7c827372c3606350 libogg-1.3.2.zip +c2e8a485110b97550f453226ec644ebac6cb29d1caef2902c007edab4308d985 libogg-1.3.3.tar.gz +4f3fc6178a533d392064f14776b23c397ed4b9f48f5de297aba73b643f955c08 libogg-1.3.3.tar.xz +ddbb0884406ea2b30d831dc7304fd4a958a05d62f24429d8fa83e1c9d620e7f8 libogg-1.3.3.zip diff --git a/extern/ogg/src/Makefile.am b/extern/ogg/src/Makefile.am new file mode 100644 index 0000000..d171fe7 --- /dev/null +++ b/extern/ogg/src/Makefile.am @@ -0,0 +1,28 @@ +## Process this file with automake to produce Makefile.in + +AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_builddir)/include + +lib_LTLIBRARIES = libogg.la + +libogg_la_SOURCES = framing.c bitwise.c crctable.h +libogg_la_LDFLAGS = -no-undefined -version-info @LIB_CURRENT@:@LIB_REVISION@:@LIB_AGE@ + +# build and run the self tests on 'make check' + +noinst_PROGRAMS = test_bitwise test_framing + +test_bitwise_SOURCES = bitwise.c +test_bitwise_CFLAGS = -D_V_SELFTEST + +test_framing_SOURCES = framing.c crctable.h +test_framing_CFLAGS = -D_V_SELFTEST + +check: $(noinst_PROGRAMS) + ./test_bitwise$(EXEEXT) + ./test_framing$(EXEEXT) + +debug: + $(MAKE) all CFLAGS="@DEBUG@" + +profile: + $(MAKE) all CFLAGS="@PROFILE@" diff --git a/extern/ogg/src/bitwise.c b/extern/ogg/src/bitwise.c new file mode 100644 index 0000000..f5ef791 --- /dev/null +++ b/extern/ogg/src/bitwise.c @@ -0,0 +1,1087 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE Ogg CONTAINER SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2014 * + * by the Xiph.Org Foundation http://www.xiph.org/ * + * * + ******************************************************************** + + function: packing variable sized words into an octet stream + + ********************************************************************/ + +/* We're 'LSb' endian; if we write a word but read individual bits, + then we'll read the lsb first */ + +#include +#include +#include +#include + +#define BUFFER_INCREMENT 256 + +static const unsigned long mask[]= +{0x00000000,0x00000001,0x00000003,0x00000007,0x0000000f, + 0x0000001f,0x0000003f,0x0000007f,0x000000ff,0x000001ff, + 0x000003ff,0x000007ff,0x00000fff,0x00001fff,0x00003fff, + 0x00007fff,0x0000ffff,0x0001ffff,0x0003ffff,0x0007ffff, + 0x000fffff,0x001fffff,0x003fffff,0x007fffff,0x00ffffff, + 0x01ffffff,0x03ffffff,0x07ffffff,0x0fffffff,0x1fffffff, + 0x3fffffff,0x7fffffff,0xffffffff }; + +static const unsigned int mask8B[]= +{0x00,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff}; + +void oggpack_writeinit(oggpack_buffer *b){ + memset(b,0,sizeof(*b)); + b->ptr=b->buffer=_ogg_malloc(BUFFER_INCREMENT); + b->buffer[0]='\0'; + b->storage=BUFFER_INCREMENT; +} + +void oggpackB_writeinit(oggpack_buffer *b){ + oggpack_writeinit(b); +} + +int oggpack_writecheck(oggpack_buffer *b){ + if(!b->ptr || !b->storage)return -1; + return 0; +} + +int oggpackB_writecheck(oggpack_buffer *b){ + return oggpack_writecheck(b); +} + +void oggpack_writetrunc(oggpack_buffer *b,long bits){ + long bytes=bits>>3; + if(b->ptr){ + bits-=bytes*8; + b->ptr=b->buffer+bytes; + b->endbit=bits; + b->endbyte=bytes; + *b->ptr&=mask[bits]; + } +} + +void oggpackB_writetrunc(oggpack_buffer *b,long bits){ + long bytes=bits>>3; + if(b->ptr){ + bits-=bytes*8; + b->ptr=b->buffer+bytes; + b->endbit=bits; + b->endbyte=bytes; + *b->ptr&=mask8B[bits]; + } +} + +/* Takes only up to 32 bits. */ +void oggpack_write(oggpack_buffer *b,unsigned long value,int bits){ + if(bits<0 || bits>32) goto err; + if(b->endbyte>=b->storage-4){ + void *ret; + if(!b->ptr)return; + if(b->storage>LONG_MAX-BUFFER_INCREMENT) goto err; + ret=_ogg_realloc(b->buffer,b->storage+BUFFER_INCREMENT); + if(!ret) goto err; + b->buffer=ret; + b->storage+=BUFFER_INCREMENT; + b->ptr=b->buffer+b->endbyte; + } + + value&=mask[bits]; + bits+=b->endbit; + + b->ptr[0]|=value<endbit; + + if(bits>=8){ + b->ptr[1]=(unsigned char)(value>>(8-b->endbit)); + if(bits>=16){ + b->ptr[2]=(unsigned char)(value>>(16-b->endbit)); + if(bits>=24){ + b->ptr[3]=(unsigned char)(value>>(24-b->endbit)); + if(bits>=32){ + if(b->endbit) + b->ptr[4]=(unsigned char)(value>>(32-b->endbit)); + else + b->ptr[4]=0; + } + } + } + } + + b->endbyte+=bits/8; + b->ptr+=bits/8; + b->endbit=bits&7; + return; + err: + oggpack_writeclear(b); +} + +/* Takes only up to 32 bits. */ +void oggpackB_write(oggpack_buffer *b,unsigned long value,int bits){ + if(bits<0 || bits>32) goto err; + if(b->endbyte>=b->storage-4){ + void *ret; + if(!b->ptr)return; + if(b->storage>LONG_MAX-BUFFER_INCREMENT) goto err; + ret=_ogg_realloc(b->buffer,b->storage+BUFFER_INCREMENT); + if(!ret) goto err; + b->buffer=ret; + b->storage+=BUFFER_INCREMENT; + b->ptr=b->buffer+b->endbyte; + } + + value=(value&mask[bits])<<(32-bits); + bits+=b->endbit; + + b->ptr[0]|=value>>(24+b->endbit); + + if(bits>=8){ + b->ptr[1]=(unsigned char)(value>>(16+b->endbit)); + if(bits>=16){ + b->ptr[2]=(unsigned char)(value>>(8+b->endbit)); + if(bits>=24){ + b->ptr[3]=(unsigned char)(value>>(b->endbit)); + if(bits>=32){ + if(b->endbit) + b->ptr[4]=(unsigned char)(value<<(8-b->endbit)); + else + b->ptr[4]=0; + } + } + } + } + + b->endbyte+=bits/8; + b->ptr+=bits/8; + b->endbit=bits&7; + return; + err: + oggpack_writeclear(b); +} + +void oggpack_writealign(oggpack_buffer *b){ + int bits=8-b->endbit; + if(bits<8) + oggpack_write(b,0,bits); +} + +void oggpackB_writealign(oggpack_buffer *b){ + int bits=8-b->endbit; + if(bits<8) + oggpackB_write(b,0,bits); +} + +static void oggpack_writecopy_helper(oggpack_buffer *b, + void *source, + long bits, + void (*w)(oggpack_buffer *, + unsigned long, + int), + int msb){ + unsigned char *ptr=(unsigned char *)source; + + long bytes=bits/8; + long pbytes=(b->endbit+bits)/8; + bits-=bytes*8; + + /* expand storage up-front */ + if(b->endbyte+pbytes>=b->storage){ + void *ret; + if(!b->ptr) goto err; + if(b->storage>b->endbyte+pbytes+BUFFER_INCREMENT) goto err; + b->storage=b->endbyte+pbytes+BUFFER_INCREMENT; + ret=_ogg_realloc(b->buffer,b->storage); + if(!ret) goto err; + b->buffer=ret; + b->ptr=b->buffer+b->endbyte; + } + + /* copy whole octets */ + if(b->endbit){ + int i; + /* unaligned copy. Do it the hard way. */ + for(i=0;iptr,source,bytes); + b->ptr+=bytes; + b->endbyte+=bytes; + *b->ptr=0; + } + + /* copy trailing bits */ + if(bits){ + if(msb) + w(b,(unsigned long)(ptr[bytes]>>(8-bits)),bits); + else + w(b,(unsigned long)(ptr[bytes]),bits); + } + return; + err: + oggpack_writeclear(b); +} + +void oggpack_writecopy(oggpack_buffer *b,void *source,long bits){ + oggpack_writecopy_helper(b,source,bits,oggpack_write,0); +} + +void oggpackB_writecopy(oggpack_buffer *b,void *source,long bits){ + oggpack_writecopy_helper(b,source,bits,oggpackB_write,1); +} + +void oggpack_reset(oggpack_buffer *b){ + if(!b->ptr)return; + b->ptr=b->buffer; + b->buffer[0]=0; + b->endbit=b->endbyte=0; +} + +void oggpackB_reset(oggpack_buffer *b){ + oggpack_reset(b); +} + +void oggpack_writeclear(oggpack_buffer *b){ + if(b->buffer)_ogg_free(b->buffer); + memset(b,0,sizeof(*b)); +} + +void oggpackB_writeclear(oggpack_buffer *b){ + oggpack_writeclear(b); +} + +void oggpack_readinit(oggpack_buffer *b,unsigned char *buf,int bytes){ + memset(b,0,sizeof(*b)); + b->buffer=b->ptr=buf; + b->storage=bytes; +} + +void oggpackB_readinit(oggpack_buffer *b,unsigned char *buf,int bytes){ + oggpack_readinit(b,buf,bytes); +} + +/* Read in bits without advancing the bitptr; bits <= 32 */ +long oggpack_look(oggpack_buffer *b,int bits){ + unsigned long ret; + unsigned long m; + + if(bits<0 || bits>32) return -1; + m=mask[bits]; + bits+=b->endbit; + + if(b->endbyte >= b->storage-4){ + /* not the main path */ + if(b->endbyte > b->storage-((bits+7)>>3)) return -1; + /* special case to avoid reading b->ptr[0], which might be past the end of + the buffer; also skips some useless accounting */ + else if(!bits)return(0L); + } + + ret=b->ptr[0]>>b->endbit; + if(bits>8){ + ret|=b->ptr[1]<<(8-b->endbit); + if(bits>16){ + ret|=b->ptr[2]<<(16-b->endbit); + if(bits>24){ + ret|=b->ptr[3]<<(24-b->endbit); + if(bits>32 && b->endbit) + ret|=b->ptr[4]<<(32-b->endbit); + } + } + } + return(m&ret); +} + +/* Read in bits without advancing the bitptr; bits <= 32 */ +long oggpackB_look(oggpack_buffer *b,int bits){ + unsigned long ret; + int m=32-bits; + + if(m<0 || m>32) return -1; + bits+=b->endbit; + + if(b->endbyte >= b->storage-4){ + /* not the main path */ + if(b->endbyte > b->storage-((bits+7)>>3)) return -1; + /* special case to avoid reading b->ptr[0], which might be past the end of + the buffer; also skips some useless accounting */ + else if(!bits)return(0L); + } + + ret=b->ptr[0]<<(24+b->endbit); + if(bits>8){ + ret|=b->ptr[1]<<(16+b->endbit); + if(bits>16){ + ret|=b->ptr[2]<<(8+b->endbit); + if(bits>24){ + ret|=b->ptr[3]<<(b->endbit); + if(bits>32 && b->endbit) + ret|=b->ptr[4]>>(8-b->endbit); + } + } + } + return ((ret&0xffffffff)>>(m>>1))>>((m+1)>>1); +} + +long oggpack_look1(oggpack_buffer *b){ + if(b->endbyte>=b->storage)return(-1); + return((b->ptr[0]>>b->endbit)&1); +} + +long oggpackB_look1(oggpack_buffer *b){ + if(b->endbyte>=b->storage)return(-1); + return((b->ptr[0]>>(7-b->endbit))&1); +} + +void oggpack_adv(oggpack_buffer *b,int bits){ + bits+=b->endbit; + + if(b->endbyte > b->storage-((bits+7)>>3)) goto overflow; + + b->ptr+=bits/8; + b->endbyte+=bits/8; + b->endbit=bits&7; + return; + + overflow: + b->ptr=NULL; + b->endbyte=b->storage; + b->endbit=1; +} + +void oggpackB_adv(oggpack_buffer *b,int bits){ + oggpack_adv(b,bits); +} + +void oggpack_adv1(oggpack_buffer *b){ + if(++(b->endbit)>7){ + b->endbit=0; + b->ptr++; + b->endbyte++; + } +} + +void oggpackB_adv1(oggpack_buffer *b){ + oggpack_adv1(b); +} + +/* bits <= 32 */ +long oggpack_read(oggpack_buffer *b,int bits){ + long ret; + unsigned long m; + + if(bits<0 || bits>32) goto err; + m=mask[bits]; + bits+=b->endbit; + + if(b->endbyte >= b->storage-4){ + /* not the main path */ + if(b->endbyte > b->storage-((bits+7)>>3)) goto overflow; + /* special case to avoid reading b->ptr[0], which might be past the end of + the buffer; also skips some useless accounting */ + else if(!bits)return(0L); + } + + ret=b->ptr[0]>>b->endbit; + if(bits>8){ + ret|=b->ptr[1]<<(8-b->endbit); + if(bits>16){ + ret|=b->ptr[2]<<(16-b->endbit); + if(bits>24){ + ret|=b->ptr[3]<<(24-b->endbit); + if(bits>32 && b->endbit){ + ret|=b->ptr[4]<<(32-b->endbit); + } + } + } + } + ret&=m; + b->ptr+=bits/8; + b->endbyte+=bits/8; + b->endbit=bits&7; + return ret; + + overflow: + err: + b->ptr=NULL; + b->endbyte=b->storage; + b->endbit=1; + return -1L; +} + +/* bits <= 32 */ +long oggpackB_read(oggpack_buffer *b,int bits){ + long ret; + long m=32-bits; + + if(m<0 || m>32) goto err; + bits+=b->endbit; + + if(b->endbyte+4>=b->storage){ + /* not the main path */ + if(b->endbyte > b->storage-((bits+7)>>3)) goto overflow; + /* special case to avoid reading b->ptr[0], which might be past the end of + the buffer; also skips some useless accounting */ + else if(!bits)return(0L); + } + + ret=b->ptr[0]<<(24+b->endbit); + if(bits>8){ + ret|=b->ptr[1]<<(16+b->endbit); + if(bits>16){ + ret|=b->ptr[2]<<(8+b->endbit); + if(bits>24){ + ret|=b->ptr[3]<<(b->endbit); + if(bits>32 && b->endbit) + ret|=b->ptr[4]>>(8-b->endbit); + } + } + } + ret=((ret&0xffffffffUL)>>(m>>1))>>((m+1)>>1); + + b->ptr+=bits/8; + b->endbyte+=bits/8; + b->endbit=bits&7; + return ret; + + overflow: + err: + b->ptr=NULL; + b->endbyte=b->storage; + b->endbit=1; + return -1L; +} + +long oggpack_read1(oggpack_buffer *b){ + long ret; + + if(b->endbyte >= b->storage) goto overflow; + ret=(b->ptr[0]>>b->endbit)&1; + + b->endbit++; + if(b->endbit>7){ + b->endbit=0; + b->ptr++; + b->endbyte++; + } + return ret; + + overflow: + b->ptr=NULL; + b->endbyte=b->storage; + b->endbit=1; + return -1L; +} + +long oggpackB_read1(oggpack_buffer *b){ + long ret; + + if(b->endbyte >= b->storage) goto overflow; + ret=(b->ptr[0]>>(7-b->endbit))&1; + + b->endbit++; + if(b->endbit>7){ + b->endbit=0; + b->ptr++; + b->endbyte++; + } + return ret; + + overflow: + b->ptr=NULL; + b->endbyte=b->storage; + b->endbit=1; + return -1L; +} + +long oggpack_bytes(oggpack_buffer *b){ + return(b->endbyte+(b->endbit+7)/8); +} + +long oggpack_bits(oggpack_buffer *b){ + return(b->endbyte*8+b->endbit); +} + +long oggpackB_bytes(oggpack_buffer *b){ + return oggpack_bytes(b); +} + +long oggpackB_bits(oggpack_buffer *b){ + return oggpack_bits(b); +} + +unsigned char *oggpack_get_buffer(oggpack_buffer *b){ + return(b->buffer); +} + +unsigned char *oggpackB_get_buffer(oggpack_buffer *b){ + return oggpack_get_buffer(b); +} + +/* Self test of the bitwise routines; everything else is based on + them, so they damned well better be solid. */ + +#ifdef _V_SELFTEST +#include + +static int ilog(unsigned int v){ + int ret=0; + while(v){ + ret++; + v>>=1; + } + return(ret); +} + +oggpack_buffer o; +oggpack_buffer r; + +void report(char *in){ + fprintf(stderr,"%s",in); + exit(1); +} + +void cliptest(unsigned long *b,int vals,int bits,int *comp,int compsize){ + long bytes,i; + unsigned char *buffer; + + oggpack_reset(&o); + for(i=0;i + +static const ogg_uint32_t crc_lookup[8][256]={ +{0x00000000,0x04c11db7,0x09823b6e,0x0d4326d9,0x130476dc,0x17c56b6b,0x1a864db2,0x1e475005, + 0x2608edb8,0x22c9f00f,0x2f8ad6d6,0x2b4bcb61,0x350c9b64,0x31cd86d3,0x3c8ea00a,0x384fbdbd, + 0x4c11db70,0x48d0c6c7,0x4593e01e,0x4152fda9,0x5f15adac,0x5bd4b01b,0x569796c2,0x52568b75, + 0x6a1936c8,0x6ed82b7f,0x639b0da6,0x675a1011,0x791d4014,0x7ddc5da3,0x709f7b7a,0x745e66cd, + 0x9823b6e0,0x9ce2ab57,0x91a18d8e,0x95609039,0x8b27c03c,0x8fe6dd8b,0x82a5fb52,0x8664e6e5, + 0xbe2b5b58,0xbaea46ef,0xb7a96036,0xb3687d81,0xad2f2d84,0xa9ee3033,0xa4ad16ea,0xa06c0b5d, + 0xd4326d90,0xd0f37027,0xddb056fe,0xd9714b49,0xc7361b4c,0xc3f706fb,0xceb42022,0xca753d95, + 0xf23a8028,0xf6fb9d9f,0xfbb8bb46,0xff79a6f1,0xe13ef6f4,0xe5ffeb43,0xe8bccd9a,0xec7dd02d, + 0x34867077,0x30476dc0,0x3d044b19,0x39c556ae,0x278206ab,0x23431b1c,0x2e003dc5,0x2ac12072, + 0x128e9dcf,0x164f8078,0x1b0ca6a1,0x1fcdbb16,0x018aeb13,0x054bf6a4,0x0808d07d,0x0cc9cdca, + 0x7897ab07,0x7c56b6b0,0x71159069,0x75d48dde,0x6b93dddb,0x6f52c06c,0x6211e6b5,0x66d0fb02, + 0x5e9f46bf,0x5a5e5b08,0x571d7dd1,0x53dc6066,0x4d9b3063,0x495a2dd4,0x44190b0d,0x40d816ba, + 0xaca5c697,0xa864db20,0xa527fdf9,0xa1e6e04e,0xbfa1b04b,0xbb60adfc,0xb6238b25,0xb2e29692, + 0x8aad2b2f,0x8e6c3698,0x832f1041,0x87ee0df6,0x99a95df3,0x9d684044,0x902b669d,0x94ea7b2a, + 0xe0b41de7,0xe4750050,0xe9362689,0xedf73b3e,0xf3b06b3b,0xf771768c,0xfa325055,0xfef34de2, + 0xc6bcf05f,0xc27dede8,0xcf3ecb31,0xcbffd686,0xd5b88683,0xd1799b34,0xdc3abded,0xd8fba05a, + 0x690ce0ee,0x6dcdfd59,0x608edb80,0x644fc637,0x7a089632,0x7ec98b85,0x738aad5c,0x774bb0eb, + 0x4f040d56,0x4bc510e1,0x46863638,0x42472b8f,0x5c007b8a,0x58c1663d,0x558240e4,0x51435d53, + 0x251d3b9e,0x21dc2629,0x2c9f00f0,0x285e1d47,0x36194d42,0x32d850f5,0x3f9b762c,0x3b5a6b9b, + 0x0315d626,0x07d4cb91,0x0a97ed48,0x0e56f0ff,0x1011a0fa,0x14d0bd4d,0x19939b94,0x1d528623, + 0xf12f560e,0xf5ee4bb9,0xf8ad6d60,0xfc6c70d7,0xe22b20d2,0xe6ea3d65,0xeba91bbc,0xef68060b, + 0xd727bbb6,0xd3e6a601,0xdea580d8,0xda649d6f,0xc423cd6a,0xc0e2d0dd,0xcda1f604,0xc960ebb3, + 0xbd3e8d7e,0xb9ff90c9,0xb4bcb610,0xb07daba7,0xae3afba2,0xaafbe615,0xa7b8c0cc,0xa379dd7b, + 0x9b3660c6,0x9ff77d71,0x92b45ba8,0x9675461f,0x8832161a,0x8cf30bad,0x81b02d74,0x857130c3, + 0x5d8a9099,0x594b8d2e,0x5408abf7,0x50c9b640,0x4e8ee645,0x4a4ffbf2,0x470cdd2b,0x43cdc09c, + 0x7b827d21,0x7f436096,0x7200464f,0x76c15bf8,0x68860bfd,0x6c47164a,0x61043093,0x65c52d24, + 0x119b4be9,0x155a565e,0x18197087,0x1cd86d30,0x029f3d35,0x065e2082,0x0b1d065b,0x0fdc1bec, + 0x3793a651,0x3352bbe6,0x3e119d3f,0x3ad08088,0x2497d08d,0x2056cd3a,0x2d15ebe3,0x29d4f654, + 0xc5a92679,0xc1683bce,0xcc2b1d17,0xc8ea00a0,0xd6ad50a5,0xd26c4d12,0xdf2f6bcb,0xdbee767c, + 0xe3a1cbc1,0xe760d676,0xea23f0af,0xeee2ed18,0xf0a5bd1d,0xf464a0aa,0xf9278673,0xfde69bc4, + 0x89b8fd09,0x8d79e0be,0x803ac667,0x84fbdbd0,0x9abc8bd5,0x9e7d9662,0x933eb0bb,0x97ffad0c, + 0xafb010b1,0xab710d06,0xa6322bdf,0xa2f33668,0xbcb4666d,0xb8757bda,0xb5365d03,0xb1f740b4}, + +{0x00000000,0xd219c1dc,0xa0f29e0f,0x72eb5fd3,0x452421a9,0x973de075,0xe5d6bfa6,0x37cf7e7a, + 0x8a484352,0x5851828e,0x2abadd5d,0xf8a31c81,0xcf6c62fb,0x1d75a327,0x6f9efcf4,0xbd873d28, + 0x10519b13,0xc2485acf,0xb0a3051c,0x62bac4c0,0x5575baba,0x876c7b66,0xf58724b5,0x279ee569, + 0x9a19d841,0x4800199d,0x3aeb464e,0xe8f28792,0xdf3df9e8,0x0d243834,0x7fcf67e7,0xadd6a63b, + 0x20a33626,0xf2baf7fa,0x8051a829,0x524869f5,0x6587178f,0xb79ed653,0xc5758980,0x176c485c, + 0xaaeb7574,0x78f2b4a8,0x0a19eb7b,0xd8002aa7,0xefcf54dd,0x3dd69501,0x4f3dcad2,0x9d240b0e, + 0x30f2ad35,0xe2eb6ce9,0x9000333a,0x4219f2e6,0x75d68c9c,0xa7cf4d40,0xd5241293,0x073dd34f, + 0xbabaee67,0x68a32fbb,0x1a487068,0xc851b1b4,0xff9ecfce,0x2d870e12,0x5f6c51c1,0x8d75901d, + 0x41466c4c,0x935fad90,0xe1b4f243,0x33ad339f,0x04624de5,0xd67b8c39,0xa490d3ea,0x76891236, + 0xcb0e2f1e,0x1917eec2,0x6bfcb111,0xb9e570cd,0x8e2a0eb7,0x5c33cf6b,0x2ed890b8,0xfcc15164, + 0x5117f75f,0x830e3683,0xf1e56950,0x23fca88c,0x1433d6f6,0xc62a172a,0xb4c148f9,0x66d88925, + 0xdb5fb40d,0x094675d1,0x7bad2a02,0xa9b4ebde,0x9e7b95a4,0x4c625478,0x3e890bab,0xec90ca77, + 0x61e55a6a,0xb3fc9bb6,0xc117c465,0x130e05b9,0x24c17bc3,0xf6d8ba1f,0x8433e5cc,0x562a2410, + 0xebad1938,0x39b4d8e4,0x4b5f8737,0x994646eb,0xae893891,0x7c90f94d,0x0e7ba69e,0xdc626742, + 0x71b4c179,0xa3ad00a5,0xd1465f76,0x035f9eaa,0x3490e0d0,0xe689210c,0x94627edf,0x467bbf03, + 0xfbfc822b,0x29e543f7,0x5b0e1c24,0x8917ddf8,0xbed8a382,0x6cc1625e,0x1e2a3d8d,0xcc33fc51, + 0x828cd898,0x50951944,0x227e4697,0xf067874b,0xc7a8f931,0x15b138ed,0x675a673e,0xb543a6e2, + 0x08c49bca,0xdadd5a16,0xa83605c5,0x7a2fc419,0x4de0ba63,0x9ff97bbf,0xed12246c,0x3f0be5b0, + 0x92dd438b,0x40c48257,0x322fdd84,0xe0361c58,0xd7f96222,0x05e0a3fe,0x770bfc2d,0xa5123df1, + 0x189500d9,0xca8cc105,0xb8679ed6,0x6a7e5f0a,0x5db12170,0x8fa8e0ac,0xfd43bf7f,0x2f5a7ea3, + 0xa22feebe,0x70362f62,0x02dd70b1,0xd0c4b16d,0xe70bcf17,0x35120ecb,0x47f95118,0x95e090c4, + 0x2867adec,0xfa7e6c30,0x889533e3,0x5a8cf23f,0x6d438c45,0xbf5a4d99,0xcdb1124a,0x1fa8d396, + 0xb27e75ad,0x6067b471,0x128ceba2,0xc0952a7e,0xf75a5404,0x254395d8,0x57a8ca0b,0x85b10bd7, + 0x383636ff,0xea2ff723,0x98c4a8f0,0x4add692c,0x7d121756,0xaf0bd68a,0xdde08959,0x0ff94885, + 0xc3cab4d4,0x11d37508,0x63382adb,0xb121eb07,0x86ee957d,0x54f754a1,0x261c0b72,0xf405caae, + 0x4982f786,0x9b9b365a,0xe9706989,0x3b69a855,0x0ca6d62f,0xdebf17f3,0xac544820,0x7e4d89fc, + 0xd39b2fc7,0x0182ee1b,0x7369b1c8,0xa1707014,0x96bf0e6e,0x44a6cfb2,0x364d9061,0xe45451bd, + 0x59d36c95,0x8bcaad49,0xf921f29a,0x2b383346,0x1cf74d3c,0xceee8ce0,0xbc05d333,0x6e1c12ef, + 0xe36982f2,0x3170432e,0x439b1cfd,0x9182dd21,0xa64da35b,0x74546287,0x06bf3d54,0xd4a6fc88, + 0x6921c1a0,0xbb38007c,0xc9d35faf,0x1bca9e73,0x2c05e009,0xfe1c21d5,0x8cf77e06,0x5eeebfda, + 0xf33819e1,0x2121d83d,0x53ca87ee,0x81d34632,0xb61c3848,0x6405f994,0x16eea647,0xc4f7679b, + 0x79705ab3,0xab699b6f,0xd982c4bc,0x0b9b0560,0x3c547b1a,0xee4dbac6,0x9ca6e515,0x4ebf24c9}, + +{0x00000000,0x01d8ac87,0x03b1590e,0x0269f589,0x0762b21c,0x06ba1e9b,0x04d3eb12,0x050b4795, + 0x0ec56438,0x0f1dc8bf,0x0d743d36,0x0cac91b1,0x09a7d624,0x087f7aa3,0x0a168f2a,0x0bce23ad, + 0x1d8ac870,0x1c5264f7,0x1e3b917e,0x1fe33df9,0x1ae87a6c,0x1b30d6eb,0x19592362,0x18818fe5, + 0x134fac48,0x129700cf,0x10fef546,0x112659c1,0x142d1e54,0x15f5b2d3,0x179c475a,0x1644ebdd, + 0x3b1590e0,0x3acd3c67,0x38a4c9ee,0x397c6569,0x3c7722fc,0x3daf8e7b,0x3fc67bf2,0x3e1ed775, + 0x35d0f4d8,0x3408585f,0x3661add6,0x37b90151,0x32b246c4,0x336aea43,0x31031fca,0x30dbb34d, + 0x269f5890,0x2747f417,0x252e019e,0x24f6ad19,0x21fdea8c,0x2025460b,0x224cb382,0x23941f05, + 0x285a3ca8,0x2982902f,0x2beb65a6,0x2a33c921,0x2f388eb4,0x2ee02233,0x2c89d7ba,0x2d517b3d, + 0x762b21c0,0x77f38d47,0x759a78ce,0x7442d449,0x714993dc,0x70913f5b,0x72f8cad2,0x73206655, + 0x78ee45f8,0x7936e97f,0x7b5f1cf6,0x7a87b071,0x7f8cf7e4,0x7e545b63,0x7c3daeea,0x7de5026d, + 0x6ba1e9b0,0x6a794537,0x6810b0be,0x69c81c39,0x6cc35bac,0x6d1bf72b,0x6f7202a2,0x6eaaae25, + 0x65648d88,0x64bc210f,0x66d5d486,0x670d7801,0x62063f94,0x63de9313,0x61b7669a,0x606fca1d, + 0x4d3eb120,0x4ce61da7,0x4e8fe82e,0x4f5744a9,0x4a5c033c,0x4b84afbb,0x49ed5a32,0x4835f6b5, + 0x43fbd518,0x4223799f,0x404a8c16,0x41922091,0x44996704,0x4541cb83,0x47283e0a,0x46f0928d, + 0x50b47950,0x516cd5d7,0x5305205e,0x52dd8cd9,0x57d6cb4c,0x560e67cb,0x54679242,0x55bf3ec5, + 0x5e711d68,0x5fa9b1ef,0x5dc04466,0x5c18e8e1,0x5913af74,0x58cb03f3,0x5aa2f67a,0x5b7a5afd, + 0xec564380,0xed8eef07,0xefe71a8e,0xee3fb609,0xeb34f19c,0xeaec5d1b,0xe885a892,0xe95d0415, + 0xe29327b8,0xe34b8b3f,0xe1227eb6,0xe0fad231,0xe5f195a4,0xe4293923,0xe640ccaa,0xe798602d, + 0xf1dc8bf0,0xf0042777,0xf26dd2fe,0xf3b57e79,0xf6be39ec,0xf766956b,0xf50f60e2,0xf4d7cc65, + 0xff19efc8,0xfec1434f,0xfca8b6c6,0xfd701a41,0xf87b5dd4,0xf9a3f153,0xfbca04da,0xfa12a85d, + 0xd743d360,0xd69b7fe7,0xd4f28a6e,0xd52a26e9,0xd021617c,0xd1f9cdfb,0xd3903872,0xd24894f5, + 0xd986b758,0xd85e1bdf,0xda37ee56,0xdbef42d1,0xdee40544,0xdf3ca9c3,0xdd555c4a,0xdc8df0cd, + 0xcac91b10,0xcb11b797,0xc978421e,0xc8a0ee99,0xcdaba90c,0xcc73058b,0xce1af002,0xcfc25c85, + 0xc40c7f28,0xc5d4d3af,0xc7bd2626,0xc6658aa1,0xc36ecd34,0xc2b661b3,0xc0df943a,0xc10738bd, + 0x9a7d6240,0x9ba5cec7,0x99cc3b4e,0x981497c9,0x9d1fd05c,0x9cc77cdb,0x9eae8952,0x9f7625d5, + 0x94b80678,0x9560aaff,0x97095f76,0x96d1f3f1,0x93dab464,0x920218e3,0x906bed6a,0x91b341ed, + 0x87f7aa30,0x862f06b7,0x8446f33e,0x859e5fb9,0x8095182c,0x814db4ab,0x83244122,0x82fceda5, + 0x8932ce08,0x88ea628f,0x8a839706,0x8b5b3b81,0x8e507c14,0x8f88d093,0x8de1251a,0x8c39899d, + 0xa168f2a0,0xa0b05e27,0xa2d9abae,0xa3010729,0xa60a40bc,0xa7d2ec3b,0xa5bb19b2,0xa463b535, + 0xafad9698,0xae753a1f,0xac1ccf96,0xadc46311,0xa8cf2484,0xa9178803,0xab7e7d8a,0xaaa6d10d, + 0xbce23ad0,0xbd3a9657,0xbf5363de,0xbe8bcf59,0xbb8088cc,0xba58244b,0xb831d1c2,0xb9e97d45, + 0xb2275ee8,0xb3fff26f,0xb19607e6,0xb04eab61,0xb545ecf4,0xb49d4073,0xb6f4b5fa,0xb72c197d}, + +{0x00000000,0xdc6d9ab7,0xbc1a28d9,0x6077b26e,0x7cf54c05,0xa098d6b2,0xc0ef64dc,0x1c82fe6b, + 0xf9ea980a,0x258702bd,0x45f0b0d3,0x999d2a64,0x851fd40f,0x59724eb8,0x3905fcd6,0xe5686661, + 0xf7142da3,0x2b79b714,0x4b0e057a,0x97639fcd,0x8be161a6,0x578cfb11,0x37fb497f,0xeb96d3c8, + 0x0efeb5a9,0xd2932f1e,0xb2e49d70,0x6e8907c7,0x720bf9ac,0xae66631b,0xce11d175,0x127c4bc2, + 0xeae946f1,0x3684dc46,0x56f36e28,0x8a9ef49f,0x961c0af4,0x4a719043,0x2a06222d,0xf66bb89a, + 0x1303defb,0xcf6e444c,0xaf19f622,0x73746c95,0x6ff692fe,0xb39b0849,0xd3ecba27,0x0f812090, + 0x1dfd6b52,0xc190f1e5,0xa1e7438b,0x7d8ad93c,0x61082757,0xbd65bde0,0xdd120f8e,0x017f9539, + 0xe417f358,0x387a69ef,0x580ddb81,0x84604136,0x98e2bf5d,0x448f25ea,0x24f89784,0xf8950d33, + 0xd1139055,0x0d7e0ae2,0x6d09b88c,0xb164223b,0xade6dc50,0x718b46e7,0x11fcf489,0xcd916e3e, + 0x28f9085f,0xf49492e8,0x94e32086,0x488eba31,0x540c445a,0x8861deed,0xe8166c83,0x347bf634, + 0x2607bdf6,0xfa6a2741,0x9a1d952f,0x46700f98,0x5af2f1f3,0x869f6b44,0xe6e8d92a,0x3a85439d, + 0xdfed25fc,0x0380bf4b,0x63f70d25,0xbf9a9792,0xa31869f9,0x7f75f34e,0x1f024120,0xc36fdb97, + 0x3bfad6a4,0xe7974c13,0x87e0fe7d,0x5b8d64ca,0x470f9aa1,0x9b620016,0xfb15b278,0x277828cf, + 0xc2104eae,0x1e7dd419,0x7e0a6677,0xa267fcc0,0xbee502ab,0x6288981c,0x02ff2a72,0xde92b0c5, + 0xcceefb07,0x108361b0,0x70f4d3de,0xac994969,0xb01bb702,0x6c762db5,0x0c019fdb,0xd06c056c, + 0x3504630d,0xe969f9ba,0x891e4bd4,0x5573d163,0x49f12f08,0x959cb5bf,0xf5eb07d1,0x29869d66, + 0xa6e63d1d,0x7a8ba7aa,0x1afc15c4,0xc6918f73,0xda137118,0x067eebaf,0x660959c1,0xba64c376, + 0x5f0ca517,0x83613fa0,0xe3168dce,0x3f7b1779,0x23f9e912,0xff9473a5,0x9fe3c1cb,0x438e5b7c, + 0x51f210be,0x8d9f8a09,0xede83867,0x3185a2d0,0x2d075cbb,0xf16ac60c,0x911d7462,0x4d70eed5, + 0xa81888b4,0x74751203,0x1402a06d,0xc86f3ada,0xd4edc4b1,0x08805e06,0x68f7ec68,0xb49a76df, + 0x4c0f7bec,0x9062e15b,0xf0155335,0x2c78c982,0x30fa37e9,0xec97ad5e,0x8ce01f30,0x508d8587, + 0xb5e5e3e6,0x69887951,0x09ffcb3f,0xd5925188,0xc910afe3,0x157d3554,0x750a873a,0xa9671d8d, + 0xbb1b564f,0x6776ccf8,0x07017e96,0xdb6ce421,0xc7ee1a4a,0x1b8380fd,0x7bf43293,0xa799a824, + 0x42f1ce45,0x9e9c54f2,0xfeebe69c,0x22867c2b,0x3e048240,0xe26918f7,0x821eaa99,0x5e73302e, + 0x77f5ad48,0xab9837ff,0xcbef8591,0x17821f26,0x0b00e14d,0xd76d7bfa,0xb71ac994,0x6b775323, + 0x8e1f3542,0x5272aff5,0x32051d9b,0xee68872c,0xf2ea7947,0x2e87e3f0,0x4ef0519e,0x929dcb29, + 0x80e180eb,0x5c8c1a5c,0x3cfba832,0xe0963285,0xfc14ccee,0x20795659,0x400ee437,0x9c637e80, + 0x790b18e1,0xa5668256,0xc5113038,0x197caa8f,0x05fe54e4,0xd993ce53,0xb9e47c3d,0x6589e68a, + 0x9d1cebb9,0x4171710e,0x2106c360,0xfd6b59d7,0xe1e9a7bc,0x3d843d0b,0x5df38f65,0x819e15d2, + 0x64f673b3,0xb89be904,0xd8ec5b6a,0x0481c1dd,0x18033fb6,0xc46ea501,0xa419176f,0x78748dd8, + 0x6a08c61a,0xb6655cad,0xd612eec3,0x0a7f7474,0x16fd8a1f,0xca9010a8,0xaae7a2c6,0x768a3871, + 0x93e25e10,0x4f8fc4a7,0x2ff876c9,0xf395ec7e,0xef171215,0x337a88a2,0x530d3acc,0x8f60a07b}, + +{0x00000000,0x490d678d,0x921acf1a,0xdb17a897,0x20f48383,0x69f9e40e,0xb2ee4c99,0xfbe32b14, + 0x41e90706,0x08e4608b,0xd3f3c81c,0x9afeaf91,0x611d8485,0x2810e308,0xf3074b9f,0xba0a2c12, + 0x83d20e0c,0xcadf6981,0x11c8c116,0x58c5a69b,0xa3268d8f,0xea2bea02,0x313c4295,0x78312518, + 0xc23b090a,0x8b366e87,0x5021c610,0x192ca19d,0xe2cf8a89,0xabc2ed04,0x70d54593,0x39d8221e, + 0x036501af,0x4a686622,0x917fceb5,0xd872a938,0x2391822c,0x6a9ce5a1,0xb18b4d36,0xf8862abb, + 0x428c06a9,0x0b816124,0xd096c9b3,0x999bae3e,0x6278852a,0x2b75e2a7,0xf0624a30,0xb96f2dbd, + 0x80b70fa3,0xc9ba682e,0x12adc0b9,0x5ba0a734,0xa0438c20,0xe94eebad,0x3259433a,0x7b5424b7, + 0xc15e08a5,0x88536f28,0x5344c7bf,0x1a49a032,0xe1aa8b26,0xa8a7ecab,0x73b0443c,0x3abd23b1, + 0x06ca035e,0x4fc764d3,0x94d0cc44,0xddddabc9,0x263e80dd,0x6f33e750,0xb4244fc7,0xfd29284a, + 0x47230458,0x0e2e63d5,0xd539cb42,0x9c34accf,0x67d787db,0x2edae056,0xf5cd48c1,0xbcc02f4c, + 0x85180d52,0xcc156adf,0x1702c248,0x5e0fa5c5,0xa5ec8ed1,0xece1e95c,0x37f641cb,0x7efb2646, + 0xc4f10a54,0x8dfc6dd9,0x56ebc54e,0x1fe6a2c3,0xe40589d7,0xad08ee5a,0x761f46cd,0x3f122140, + 0x05af02f1,0x4ca2657c,0x97b5cdeb,0xdeb8aa66,0x255b8172,0x6c56e6ff,0xb7414e68,0xfe4c29e5, + 0x444605f7,0x0d4b627a,0xd65ccaed,0x9f51ad60,0x64b28674,0x2dbfe1f9,0xf6a8496e,0xbfa52ee3, + 0x867d0cfd,0xcf706b70,0x1467c3e7,0x5d6aa46a,0xa6898f7e,0xef84e8f3,0x34934064,0x7d9e27e9, + 0xc7940bfb,0x8e996c76,0x558ec4e1,0x1c83a36c,0xe7608878,0xae6deff5,0x757a4762,0x3c7720ef, + 0x0d9406bc,0x44996131,0x9f8ec9a6,0xd683ae2b,0x2d60853f,0x646de2b2,0xbf7a4a25,0xf6772da8, + 0x4c7d01ba,0x05706637,0xde67cea0,0x976aa92d,0x6c898239,0x2584e5b4,0xfe934d23,0xb79e2aae, + 0x8e4608b0,0xc74b6f3d,0x1c5cc7aa,0x5551a027,0xaeb28b33,0xe7bfecbe,0x3ca84429,0x75a523a4, + 0xcfaf0fb6,0x86a2683b,0x5db5c0ac,0x14b8a721,0xef5b8c35,0xa656ebb8,0x7d41432f,0x344c24a2, + 0x0ef10713,0x47fc609e,0x9cebc809,0xd5e6af84,0x2e058490,0x6708e31d,0xbc1f4b8a,0xf5122c07, + 0x4f180015,0x06156798,0xdd02cf0f,0x940fa882,0x6fec8396,0x26e1e41b,0xfdf64c8c,0xb4fb2b01, + 0x8d23091f,0xc42e6e92,0x1f39c605,0x5634a188,0xadd78a9c,0xe4daed11,0x3fcd4586,0x76c0220b, + 0xccca0e19,0x85c76994,0x5ed0c103,0x17dda68e,0xec3e8d9a,0xa533ea17,0x7e244280,0x3729250d, + 0x0b5e05e2,0x4253626f,0x9944caf8,0xd049ad75,0x2baa8661,0x62a7e1ec,0xb9b0497b,0xf0bd2ef6, + 0x4ab702e4,0x03ba6569,0xd8adcdfe,0x91a0aa73,0x6a438167,0x234ee6ea,0xf8594e7d,0xb15429f0, + 0x888c0bee,0xc1816c63,0x1a96c4f4,0x539ba379,0xa878886d,0xe175efe0,0x3a624777,0x736f20fa, + 0xc9650ce8,0x80686b65,0x5b7fc3f2,0x1272a47f,0xe9918f6b,0xa09ce8e6,0x7b8b4071,0x328627fc, + 0x083b044d,0x413663c0,0x9a21cb57,0xd32cacda,0x28cf87ce,0x61c2e043,0xbad548d4,0xf3d82f59, + 0x49d2034b,0x00df64c6,0xdbc8cc51,0x92c5abdc,0x692680c8,0x202be745,0xfb3c4fd2,0xb231285f, + 0x8be90a41,0xc2e46dcc,0x19f3c55b,0x50fea2d6,0xab1d89c2,0xe210ee4f,0x390746d8,0x700a2155, + 0xca000d47,0x830d6aca,0x581ac25d,0x1117a5d0,0xeaf48ec4,0xa3f9e949,0x78ee41de,0x31e32653}, + +{0x00000000,0x1b280d78,0x36501af0,0x2d781788,0x6ca035e0,0x77883898,0x5af02f10,0x41d82268, + 0xd9406bc0,0xc26866b8,0xef107130,0xf4387c48,0xb5e05e20,0xaec85358,0x83b044d0,0x989849a8, + 0xb641ca37,0xad69c74f,0x8011d0c7,0x9b39ddbf,0xdae1ffd7,0xc1c9f2af,0xecb1e527,0xf799e85f, + 0x6f01a1f7,0x7429ac8f,0x5951bb07,0x4279b67f,0x03a19417,0x1889996f,0x35f18ee7,0x2ed9839f, + 0x684289d9,0x736a84a1,0x5e129329,0x453a9e51,0x04e2bc39,0x1fcab141,0x32b2a6c9,0x299aabb1, + 0xb102e219,0xaa2aef61,0x8752f8e9,0x9c7af591,0xdda2d7f9,0xc68ada81,0xebf2cd09,0xf0dac071, + 0xde0343ee,0xc52b4e96,0xe853591e,0xf37b5466,0xb2a3760e,0xa98b7b76,0x84f36cfe,0x9fdb6186, + 0x0743282e,0x1c6b2556,0x311332de,0x2a3b3fa6,0x6be31dce,0x70cb10b6,0x5db3073e,0x469b0a46, + 0xd08513b2,0xcbad1eca,0xe6d50942,0xfdfd043a,0xbc252652,0xa70d2b2a,0x8a753ca2,0x915d31da, + 0x09c57872,0x12ed750a,0x3f956282,0x24bd6ffa,0x65654d92,0x7e4d40ea,0x53355762,0x481d5a1a, + 0x66c4d985,0x7decd4fd,0x5094c375,0x4bbcce0d,0x0a64ec65,0x114ce11d,0x3c34f695,0x271cfbed, + 0xbf84b245,0xa4acbf3d,0x89d4a8b5,0x92fca5cd,0xd32487a5,0xc80c8add,0xe5749d55,0xfe5c902d, + 0xb8c79a6b,0xa3ef9713,0x8e97809b,0x95bf8de3,0xd467af8b,0xcf4fa2f3,0xe237b57b,0xf91fb803, + 0x6187f1ab,0x7aaffcd3,0x57d7eb5b,0x4cffe623,0x0d27c44b,0x160fc933,0x3b77debb,0x205fd3c3, + 0x0e86505c,0x15ae5d24,0x38d64aac,0x23fe47d4,0x622665bc,0x790e68c4,0x54767f4c,0x4f5e7234, + 0xd7c63b9c,0xccee36e4,0xe196216c,0xfabe2c14,0xbb660e7c,0xa04e0304,0x8d36148c,0x961e19f4, + 0xa5cb3ad3,0xbee337ab,0x939b2023,0x88b32d5b,0xc96b0f33,0xd243024b,0xff3b15c3,0xe41318bb, + 0x7c8b5113,0x67a35c6b,0x4adb4be3,0x51f3469b,0x102b64f3,0x0b03698b,0x267b7e03,0x3d53737b, + 0x138af0e4,0x08a2fd9c,0x25daea14,0x3ef2e76c,0x7f2ac504,0x6402c87c,0x497adff4,0x5252d28c, + 0xcaca9b24,0xd1e2965c,0xfc9a81d4,0xe7b28cac,0xa66aaec4,0xbd42a3bc,0x903ab434,0x8b12b94c, + 0xcd89b30a,0xd6a1be72,0xfbd9a9fa,0xe0f1a482,0xa12986ea,0xba018b92,0x97799c1a,0x8c519162, + 0x14c9d8ca,0x0fe1d5b2,0x2299c23a,0x39b1cf42,0x7869ed2a,0x6341e052,0x4e39f7da,0x5511faa2, + 0x7bc8793d,0x60e07445,0x4d9863cd,0x56b06eb5,0x17684cdd,0x0c4041a5,0x2138562d,0x3a105b55, + 0xa28812fd,0xb9a01f85,0x94d8080d,0x8ff00575,0xce28271d,0xd5002a65,0xf8783ded,0xe3503095, + 0x754e2961,0x6e662419,0x431e3391,0x58363ee9,0x19ee1c81,0x02c611f9,0x2fbe0671,0x34960b09, + 0xac0e42a1,0xb7264fd9,0x9a5e5851,0x81765529,0xc0ae7741,0xdb867a39,0xf6fe6db1,0xedd660c9, + 0xc30fe356,0xd827ee2e,0xf55ff9a6,0xee77f4de,0xafafd6b6,0xb487dbce,0x99ffcc46,0x82d7c13e, + 0x1a4f8896,0x016785ee,0x2c1f9266,0x37379f1e,0x76efbd76,0x6dc7b00e,0x40bfa786,0x5b97aafe, + 0x1d0ca0b8,0x0624adc0,0x2b5cba48,0x3074b730,0x71ac9558,0x6a849820,0x47fc8fa8,0x5cd482d0, + 0xc44ccb78,0xdf64c600,0xf21cd188,0xe934dcf0,0xa8ecfe98,0xb3c4f3e0,0x9ebce468,0x8594e910, + 0xab4d6a8f,0xb06567f7,0x9d1d707f,0x86357d07,0xc7ed5f6f,0xdcc55217,0xf1bd459f,0xea9548e7, + 0x720d014f,0x69250c37,0x445d1bbf,0x5f7516c7,0x1ead34af,0x058539d7,0x28fd2e5f,0x33d52327}, + +{0x00000000,0x4f576811,0x9eaed022,0xd1f9b833,0x399cbdf3,0x76cbd5e2,0xa7326dd1,0xe86505c0, + 0x73397be6,0x3c6e13f7,0xed97abc4,0xa2c0c3d5,0x4aa5c615,0x05f2ae04,0xd40b1637,0x9b5c7e26, + 0xe672f7cc,0xa9259fdd,0x78dc27ee,0x378b4fff,0xdfee4a3f,0x90b9222e,0x41409a1d,0x0e17f20c, + 0x954b8c2a,0xda1ce43b,0x0be55c08,0x44b23419,0xacd731d9,0xe38059c8,0x3279e1fb,0x7d2e89ea, + 0xc824f22f,0x87739a3e,0x568a220d,0x19dd4a1c,0xf1b84fdc,0xbeef27cd,0x6f169ffe,0x2041f7ef, + 0xbb1d89c9,0xf44ae1d8,0x25b359eb,0x6ae431fa,0x8281343a,0xcdd65c2b,0x1c2fe418,0x53788c09, + 0x2e5605e3,0x61016df2,0xb0f8d5c1,0xffafbdd0,0x17cab810,0x589dd001,0x89646832,0xc6330023, + 0x5d6f7e05,0x12381614,0xc3c1ae27,0x8c96c636,0x64f3c3f6,0x2ba4abe7,0xfa5d13d4,0xb50a7bc5, + 0x9488f9e9,0xdbdf91f8,0x0a2629cb,0x457141da,0xad14441a,0xe2432c0b,0x33ba9438,0x7cedfc29, + 0xe7b1820f,0xa8e6ea1e,0x791f522d,0x36483a3c,0xde2d3ffc,0x917a57ed,0x4083efde,0x0fd487cf, + 0x72fa0e25,0x3dad6634,0xec54de07,0xa303b616,0x4b66b3d6,0x0431dbc7,0xd5c863f4,0x9a9f0be5, + 0x01c375c3,0x4e941dd2,0x9f6da5e1,0xd03acdf0,0x385fc830,0x7708a021,0xa6f11812,0xe9a67003, + 0x5cac0bc6,0x13fb63d7,0xc202dbe4,0x8d55b3f5,0x6530b635,0x2a67de24,0xfb9e6617,0xb4c90e06, + 0x2f957020,0x60c21831,0xb13ba002,0xfe6cc813,0x1609cdd3,0x595ea5c2,0x88a71df1,0xc7f075e0, + 0xbadefc0a,0xf589941b,0x24702c28,0x6b274439,0x834241f9,0xcc1529e8,0x1dec91db,0x52bbf9ca, + 0xc9e787ec,0x86b0effd,0x574957ce,0x181e3fdf,0xf07b3a1f,0xbf2c520e,0x6ed5ea3d,0x2182822c, + 0x2dd0ee65,0x62878674,0xb37e3e47,0xfc295656,0x144c5396,0x5b1b3b87,0x8ae283b4,0xc5b5eba5, + 0x5ee99583,0x11befd92,0xc04745a1,0x8f102db0,0x67752870,0x28224061,0xf9dbf852,0xb68c9043, + 0xcba219a9,0x84f571b8,0x550cc98b,0x1a5ba19a,0xf23ea45a,0xbd69cc4b,0x6c907478,0x23c71c69, + 0xb89b624f,0xf7cc0a5e,0x2635b26d,0x6962da7c,0x8107dfbc,0xce50b7ad,0x1fa90f9e,0x50fe678f, + 0xe5f41c4a,0xaaa3745b,0x7b5acc68,0x340da479,0xdc68a1b9,0x933fc9a8,0x42c6719b,0x0d91198a, + 0x96cd67ac,0xd99a0fbd,0x0863b78e,0x4734df9f,0xaf51da5f,0xe006b24e,0x31ff0a7d,0x7ea8626c, + 0x0386eb86,0x4cd18397,0x9d283ba4,0xd27f53b5,0x3a1a5675,0x754d3e64,0xa4b48657,0xebe3ee46, + 0x70bf9060,0x3fe8f871,0xee114042,0xa1462853,0x49232d93,0x06744582,0xd78dfdb1,0x98da95a0, + 0xb958178c,0xf60f7f9d,0x27f6c7ae,0x68a1afbf,0x80c4aa7f,0xcf93c26e,0x1e6a7a5d,0x513d124c, + 0xca616c6a,0x8536047b,0x54cfbc48,0x1b98d459,0xf3fdd199,0xbcaab988,0x6d5301bb,0x220469aa, + 0x5f2ae040,0x107d8851,0xc1843062,0x8ed35873,0x66b65db3,0x29e135a2,0xf8188d91,0xb74fe580, + 0x2c139ba6,0x6344f3b7,0xb2bd4b84,0xfdea2395,0x158f2655,0x5ad84e44,0x8b21f677,0xc4769e66, + 0x717ce5a3,0x3e2b8db2,0xefd23581,0xa0855d90,0x48e05850,0x07b73041,0xd64e8872,0x9919e063, + 0x02459e45,0x4d12f654,0x9ceb4e67,0xd3bc2676,0x3bd923b6,0x748e4ba7,0xa577f394,0xea209b85, + 0x970e126f,0xd8597a7e,0x09a0c24d,0x46f7aa5c,0xae92af9c,0xe1c5c78d,0x303c7fbe,0x7f6b17af, + 0xe4376989,0xab600198,0x7a99b9ab,0x35ced1ba,0xddabd47a,0x92fcbc6b,0x43050458,0x0c526c49}, + +{0x00000000,0x5ba1dcca,0xb743b994,0xece2655e,0x6a466e9f,0x31e7b255,0xdd05d70b,0x86a40bc1, + 0xd48cdd3e,0x8f2d01f4,0x63cf64aa,0x386eb860,0xbecab3a1,0xe56b6f6b,0x09890a35,0x5228d6ff, + 0xadd8a7cb,0xf6797b01,0x1a9b1e5f,0x413ac295,0xc79ec954,0x9c3f159e,0x70dd70c0,0x2b7cac0a, + 0x79547af5,0x22f5a63f,0xce17c361,0x95b61fab,0x1312146a,0x48b3c8a0,0xa451adfe,0xfff07134, + 0x5f705221,0x04d18eeb,0xe833ebb5,0xb392377f,0x35363cbe,0x6e97e074,0x8275852a,0xd9d459e0, + 0x8bfc8f1f,0xd05d53d5,0x3cbf368b,0x671eea41,0xe1bae180,0xba1b3d4a,0x56f95814,0x0d5884de, + 0xf2a8f5ea,0xa9092920,0x45eb4c7e,0x1e4a90b4,0x98ee9b75,0xc34f47bf,0x2fad22e1,0x740cfe2b, + 0x262428d4,0x7d85f41e,0x91679140,0xcac64d8a,0x4c62464b,0x17c39a81,0xfb21ffdf,0xa0802315, + 0xbee0a442,0xe5417888,0x09a31dd6,0x5202c11c,0xd4a6cadd,0x8f071617,0x63e57349,0x3844af83, + 0x6a6c797c,0x31cda5b6,0xdd2fc0e8,0x868e1c22,0x002a17e3,0x5b8bcb29,0xb769ae77,0xecc872bd, + 0x13380389,0x4899df43,0xa47bba1d,0xffda66d7,0x797e6d16,0x22dfb1dc,0xce3dd482,0x959c0848, + 0xc7b4deb7,0x9c15027d,0x70f76723,0x2b56bbe9,0xadf2b028,0xf6536ce2,0x1ab109bc,0x4110d576, + 0xe190f663,0xba312aa9,0x56d34ff7,0x0d72933d,0x8bd698fc,0xd0774436,0x3c952168,0x6734fda2, + 0x351c2b5d,0x6ebdf797,0x825f92c9,0xd9fe4e03,0x5f5a45c2,0x04fb9908,0xe819fc56,0xb3b8209c, + 0x4c4851a8,0x17e98d62,0xfb0be83c,0xa0aa34f6,0x260e3f37,0x7dafe3fd,0x914d86a3,0xcaec5a69, + 0x98c48c96,0xc365505c,0x2f873502,0x7426e9c8,0xf282e209,0xa9233ec3,0x45c15b9d,0x1e608757, + 0x79005533,0x22a189f9,0xce43eca7,0x95e2306d,0x13463bac,0x48e7e766,0xa4058238,0xffa45ef2, + 0xad8c880d,0xf62d54c7,0x1acf3199,0x416eed53,0xc7cae692,0x9c6b3a58,0x70895f06,0x2b2883cc, + 0xd4d8f2f8,0x8f792e32,0x639b4b6c,0x383a97a6,0xbe9e9c67,0xe53f40ad,0x09dd25f3,0x527cf939, + 0x00542fc6,0x5bf5f30c,0xb7179652,0xecb64a98,0x6a124159,0x31b39d93,0xdd51f8cd,0x86f02407, + 0x26700712,0x7dd1dbd8,0x9133be86,0xca92624c,0x4c36698d,0x1797b547,0xfb75d019,0xa0d40cd3, + 0xf2fcda2c,0xa95d06e6,0x45bf63b8,0x1e1ebf72,0x98bab4b3,0xc31b6879,0x2ff90d27,0x7458d1ed, + 0x8ba8a0d9,0xd0097c13,0x3ceb194d,0x674ac587,0xe1eece46,0xba4f128c,0x56ad77d2,0x0d0cab18, + 0x5f247de7,0x0485a12d,0xe867c473,0xb3c618b9,0x35621378,0x6ec3cfb2,0x8221aaec,0xd9807626, + 0xc7e0f171,0x9c412dbb,0x70a348e5,0x2b02942f,0xada69fee,0xf6074324,0x1ae5267a,0x4144fab0, + 0x136c2c4f,0x48cdf085,0xa42f95db,0xff8e4911,0x792a42d0,0x228b9e1a,0xce69fb44,0x95c8278e, + 0x6a3856ba,0x31998a70,0xdd7bef2e,0x86da33e4,0x007e3825,0x5bdfe4ef,0xb73d81b1,0xec9c5d7b, + 0xbeb48b84,0xe515574e,0x09f73210,0x5256eeda,0xd4f2e51b,0x8f5339d1,0x63b15c8f,0x38108045, + 0x9890a350,0xc3317f9a,0x2fd31ac4,0x7472c60e,0xf2d6cdcf,0xa9771105,0x4595745b,0x1e34a891, + 0x4c1c7e6e,0x17bda2a4,0xfb5fc7fa,0xa0fe1b30,0x265a10f1,0x7dfbcc3b,0x9119a965,0xcab875af, + 0x3548049b,0x6ee9d851,0x820bbd0f,0xd9aa61c5,0x5f0e6a04,0x04afb6ce,0xe84dd390,0xb3ec0f5a, + 0xe1c4d9a5,0xba65056f,0x56876031,0x0d26bcfb,0x8b82b73a,0xd0236bf0,0x3cc10eae,0x6760d264}}; diff --git a/extern/ogg/src/framing.c b/extern/ogg/src/framing.c new file mode 100644 index 0000000..8360119 --- /dev/null +++ b/extern/ogg/src/framing.c @@ -0,0 +1,2109 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE Ogg CONTAINER SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2018 * + * by the Xiph.Org Foundation http://www.xiph.org/ * + * * + ******************************************************************** + + function: code raw packets into framed OggSquish stream and + decode Ogg streams back into raw packets + + note: The CRC code is directly derived from public domain code by + Ross Williams (ross@guest.adelaide.edu.au). See docs/framing.html + for details. + + ********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include + +/* A complete description of Ogg framing exists in docs/framing.html */ + +int ogg_page_version(const ogg_page *og){ + return((int)(og->header[4])); +} + +int ogg_page_continued(const ogg_page *og){ + return((int)(og->header[5]&0x01)); +} + +int ogg_page_bos(const ogg_page *og){ + return((int)(og->header[5]&0x02)); +} + +int ogg_page_eos(const ogg_page *og){ + return((int)(og->header[5]&0x04)); +} + +ogg_int64_t ogg_page_granulepos(const ogg_page *og){ + unsigned char *page=og->header; + ogg_uint64_t granulepos=page[13]&(0xff); + granulepos= (granulepos<<8)|(page[12]&0xff); + granulepos= (granulepos<<8)|(page[11]&0xff); + granulepos= (granulepos<<8)|(page[10]&0xff); + granulepos= (granulepos<<8)|(page[9]&0xff); + granulepos= (granulepos<<8)|(page[8]&0xff); + granulepos= (granulepos<<8)|(page[7]&0xff); + granulepos= (granulepos<<8)|(page[6]&0xff); + return((ogg_int64_t)granulepos); +} + +int ogg_page_serialno(const ogg_page *og){ + return((int)((ogg_uint32_t)og->header[14]) | + ((ogg_uint32_t)og->header[15]<<8) | + ((ogg_uint32_t)og->header[16]<<16) | + ((ogg_uint32_t)og->header[17]<<24)); +} + +long ogg_page_pageno(const ogg_page *og){ + return((long)((ogg_uint32_t)og->header[18]) | + ((ogg_uint32_t)og->header[19]<<8) | + ((ogg_uint32_t)og->header[20]<<16) | + ((ogg_uint32_t)og->header[21]<<24)); +} + + + +/* returns the number of packets that are completed on this page (if + the leading packet is begun on a previous page, but ends on this + page, it's counted */ + +/* NOTE: + If a page consists of a packet begun on a previous page, and a new + packet begun (but not completed) on this page, the return will be: + ogg_page_packets(page) ==1, + ogg_page_continued(page) !=0 + + If a page happens to be a single packet that was begun on a + previous page, and spans to the next page (in the case of a three or + more page packet), the return will be: + ogg_page_packets(page) ==0, + ogg_page_continued(page) !=0 +*/ + +int ogg_page_packets(const ogg_page *og){ + int i,n=og->header[26],count=0; + for(i=0;iheader[27+i]<255)count++; + return(count); +} + + +#if 0 +/* helper to initialize lookup for direct-table CRC (illustrative; we + use the static init in crctable.h) */ + +static void _ogg_crc_init(){ + int i, j; + ogg_uint32_t polynomial, crc; + polynomial = 0x04c11db7; /* The same as the ethernet generator + polynomial, although we use an + unreflected alg and an init/final + of 0, not 0xffffffff */ + for (i = 0; i <= 0xFF; i++){ + crc = i << 24; + + for (j = 0; j < 8; j++) + crc = (crc << 1) ^ (crc & (1 << 31) ? polynomial : 0); + + crc_lookup[0][i] = crc; + } + + for (i = 0; i <= 0xFF; i++) + for (j = 1; j < 8; j++) + crc_lookup[j][i] = crc_lookup[0][(crc_lookup[j - 1][i] >> 24) & 0xFF] ^ (crc_lookup[j - 1][i] << 8); +} +#endif + +#include "crctable.h" + +/* init the encode/decode logical stream state */ + +int ogg_stream_init(ogg_stream_state *os,int serialno){ + if(os){ + memset(os,0,sizeof(*os)); + os->body_storage=16*1024; + os->lacing_storage=1024; + + os->body_data=_ogg_malloc(os->body_storage*sizeof(*os->body_data)); + os->lacing_vals=_ogg_malloc(os->lacing_storage*sizeof(*os->lacing_vals)); + os->granule_vals=_ogg_malloc(os->lacing_storage*sizeof(*os->granule_vals)); + + if(!os->body_data || !os->lacing_vals || !os->granule_vals){ + ogg_stream_clear(os); + return -1; + } + + os->serialno=serialno; + + return(0); + } + return(-1); +} + +/* async/delayed error detection for the ogg_stream_state */ +int ogg_stream_check(ogg_stream_state *os){ + if(!os || !os->body_data) return -1; + return 0; +} + +/* _clear does not free os, only the non-flat storage within */ +int ogg_stream_clear(ogg_stream_state *os){ + if(os){ + if(os->body_data)_ogg_free(os->body_data); + if(os->lacing_vals)_ogg_free(os->lacing_vals); + if(os->granule_vals)_ogg_free(os->granule_vals); + + memset(os,0,sizeof(*os)); + } + return(0); +} + +int ogg_stream_destroy(ogg_stream_state *os){ + if(os){ + ogg_stream_clear(os); + _ogg_free(os); + } + return(0); +} + +/* Helpers for ogg_stream_encode; this keeps the structure and + what's happening fairly clear */ + +static int _os_body_expand(ogg_stream_state *os,long needed){ + if(os->body_storage-needed<=os->body_fill){ + long body_storage; + void *ret; + if(os->body_storage>LONG_MAX-needed){ + ogg_stream_clear(os); + return -1; + } + body_storage=os->body_storage+needed; + if(body_storagebody_data,body_storage*sizeof(*os->body_data)); + if(!ret){ + ogg_stream_clear(os); + return -1; + } + os->body_storage=body_storage; + os->body_data=ret; + } + return 0; +} + +static int _os_lacing_expand(ogg_stream_state *os,long needed){ + if(os->lacing_storage-needed<=os->lacing_fill){ + long lacing_storage; + void *ret; + if(os->lacing_storage>LONG_MAX-needed){ + ogg_stream_clear(os); + return -1; + } + lacing_storage=os->lacing_storage+needed; + if(lacing_storagelacing_vals,lacing_storage*sizeof(*os->lacing_vals)); + if(!ret){ + ogg_stream_clear(os); + return -1; + } + os->lacing_vals=ret; + ret=_ogg_realloc(os->granule_vals,lacing_storage* + sizeof(*os->granule_vals)); + if(!ret){ + ogg_stream_clear(os); + return -1; + } + os->granule_vals=ret; + os->lacing_storage=lacing_storage; + } + return 0; +} + +/* checksum the page */ +/* Direct table CRC; note that this will be faster in the future if we + perform the checksum simultaneously with other copies */ + +static ogg_uint32_t _os_update_crc(ogg_uint32_t crc, unsigned char *buffer, int size){ + while (size>=8){ + crc^=((ogg_uint32_t)buffer[0]<<24)|((ogg_uint32_t)buffer[1]<<16)|((ogg_uint32_t)buffer[2]<<8)|((ogg_uint32_t)buffer[3]); + + crc=crc_lookup[7][ crc>>24 ]^crc_lookup[6][(crc>>16)&0xFF]^ + crc_lookup[5][(crc>> 8)&0xFF]^crc_lookup[4][ crc &0xFF]^ + crc_lookup[3][buffer[4] ]^crc_lookup[2][buffer[5] ]^ + crc_lookup[1][buffer[6] ]^crc_lookup[0][buffer[7] ]; + + buffer+=8; + size-=8; + } + + while (size--) + crc=(crc<<8)^crc_lookup[0][((crc >> 24)&0xff)^*buffer++]; + return crc; +} + +void ogg_page_checksum_set(ogg_page *og){ + if(og){ + ogg_uint32_t crc_reg=0; + + /* safety; needed for API behavior, but not framing code */ + og->header[22]=0; + og->header[23]=0; + og->header[24]=0; + og->header[25]=0; + + crc_reg=_os_update_crc(crc_reg,og->header,og->header_len); + crc_reg=_os_update_crc(crc_reg,og->body,og->body_len); + + og->header[22]=(unsigned char)(crc_reg&0xff); + og->header[23]=(unsigned char)((crc_reg>>8)&0xff); + og->header[24]=(unsigned char)((crc_reg>>16)&0xff); + og->header[25]=(unsigned char)((crc_reg>>24)&0xff); + } +} + +/* submit data to the internal buffer of the framing engine */ +int ogg_stream_iovecin(ogg_stream_state *os, ogg_iovec_t *iov, int count, + long e_o_s, ogg_int64_t granulepos){ + + long bytes = 0, lacing_vals; + int i; + + if(ogg_stream_check(os)) return -1; + if(!iov) return 0; + + for (i = 0; i < count; ++i){ + if(iov[i].iov_len>LONG_MAX) return -1; + if(bytes>LONG_MAX-(long)iov[i].iov_len) return -1; + bytes += (long)iov[i].iov_len; + } + lacing_vals=bytes/255+1; + + if(os->body_returned){ + /* advance packet data according to the body_returned pointer. We + had to keep it around to return a pointer into the buffer last + call */ + + os->body_fill-=os->body_returned; + if(os->body_fill) + memmove(os->body_data,os->body_data+os->body_returned, + os->body_fill); + os->body_returned=0; + } + + /* make sure we have the buffer storage */ + if(_os_body_expand(os,bytes) || _os_lacing_expand(os,lacing_vals)) + return -1; + + /* Copy in the submitted packet. Yes, the copy is a waste; this is + the liability of overly clean abstraction for the time being. It + will actually be fairly easy to eliminate the extra copy in the + future */ + + for (i = 0; i < count; ++i) { + memcpy(os->body_data+os->body_fill, iov[i].iov_base, iov[i].iov_len); + os->body_fill += (int)iov[i].iov_len; + } + + /* Store lacing vals for this packet */ + for(i=0;ilacing_vals[os->lacing_fill+i]=255; + os->granule_vals[os->lacing_fill+i]=os->granulepos; + } + os->lacing_vals[os->lacing_fill+i]=bytes%255; + os->granulepos=os->granule_vals[os->lacing_fill+i]=granulepos; + + /* flag the first segment as the beginning of the packet */ + os->lacing_vals[os->lacing_fill]|= 0x100; + + os->lacing_fill+=lacing_vals; + + /* for the sake of completeness */ + os->packetno++; + + if(e_o_s)os->e_o_s=1; + + return(0); +} + +int ogg_stream_packetin(ogg_stream_state *os,ogg_packet *op){ + ogg_iovec_t iov; + iov.iov_base = op->packet; + iov.iov_len = op->bytes; + return ogg_stream_iovecin(os, &iov, 1, op->e_o_s, op->granulepos); +} + +/* Conditionally flush a page; force==0 will only flush nominal-size + pages, force==1 forces us to flush a page regardless of page size + so long as there's any data available at all. */ +static int ogg_stream_flush_i(ogg_stream_state *os,ogg_page *og, int force, int nfill){ + int i; + int vals=0; + int maxvals=(os->lacing_fill>255?255:os->lacing_fill); + int bytes=0; + long acc=0; + ogg_int64_t granule_pos=-1; + + if(ogg_stream_check(os)) return(0); + if(maxvals==0) return(0); + + /* construct a page */ + /* decide how many segments to include */ + + /* If this is the initial header case, the first page must only include + the initial header packet */ + if(os->b_o_s==0){ /* 'initial header page' case */ + granule_pos=0; + for(vals=0;valslacing_vals[vals]&0x0ff)<255){ + vals++; + break; + } + } + }else{ + + /* The extra packets_done, packet_just_done logic here attempts to do two things: + 1) Don't unnecessarily span pages. + 2) Unless necessary, don't flush pages if there are less than four packets on + them; this expands page size to reduce unnecessary overhead if incoming packets + are large. + These are not necessary behaviors, just 'always better than naive flushing' + without requiring an application to explicitly request a specific optimized + behavior. We'll want an explicit behavior setup pathway eventually as well. */ + + int packets_done=0; + int packet_just_done=0; + for(vals=0;valsnfill && packet_just_done>=4){ + force=1; + break; + } + acc+=os->lacing_vals[vals]&0x0ff; + if((os->lacing_vals[vals]&0xff)<255){ + granule_pos=os->granule_vals[vals]; + packet_just_done=++packets_done; + }else + packet_just_done=0; + } + if(vals==255)force=1; + } + + if(!force) return(0); + + /* construct the header in temp storage */ + memcpy(os->header,"OggS",4); + + /* stream structure version */ + os->header[4]=0x00; + + /* continued packet flag? */ + os->header[5]=0x00; + if((os->lacing_vals[0]&0x100)==0)os->header[5]|=0x01; + /* first page flag? */ + if(os->b_o_s==0)os->header[5]|=0x02; + /* last page flag? */ + if(os->e_o_s && os->lacing_fill==vals)os->header[5]|=0x04; + os->b_o_s=1; + + /* 64 bits of PCM position */ + for(i=6;i<14;i++){ + os->header[i]=(unsigned char)(granule_pos&0xff); + granule_pos>>=8; + } + + /* 32 bits of stream serial number */ + { + long serialno=os->serialno; + for(i=14;i<18;i++){ + os->header[i]=(unsigned char)(serialno&0xff); + serialno>>=8; + } + } + + /* 32 bits of page counter (we have both counter and page header + because this val can roll over) */ + if(os->pageno==-1)os->pageno=0; /* because someone called + stream_reset; this would be a + strange thing to do in an + encode stream, but it has + plausible uses */ + { + long pageno=os->pageno++; + for(i=18;i<22;i++){ + os->header[i]=(unsigned char)(pageno&0xff); + pageno>>=8; + } + } + + /* zero for computation; filled in later */ + os->header[22]=0; + os->header[23]=0; + os->header[24]=0; + os->header[25]=0; + + /* segment table */ + os->header[26]=(unsigned char)(vals&0xff); + for(i=0;iheader[i+27]=(unsigned char)(os->lacing_vals[i]&0xff); + + /* set pointers in the ogg_page struct */ + og->header=os->header; + og->header_len=os->header_fill=vals+27; + og->body=os->body_data+os->body_returned; + og->body_len=bytes; + + /* advance the lacing data and set the body_returned pointer */ + + os->lacing_fill-=vals; + memmove(os->lacing_vals,os->lacing_vals+vals,os->lacing_fill*sizeof(*os->lacing_vals)); + memmove(os->granule_vals,os->granule_vals+vals,os->lacing_fill*sizeof(*os->granule_vals)); + os->body_returned+=bytes; + + /* calculate the checksum */ + + ogg_page_checksum_set(og); + + /* done */ + return(1); +} + +/* This will flush remaining packets into a page (returning nonzero), + even if there is not enough data to trigger a flush normally + (undersized page). If there are no packets or partial packets to + flush, ogg_stream_flush returns 0. Note that ogg_stream_flush will + try to flush a normal sized page like ogg_stream_pageout; a call to + ogg_stream_flush does not guarantee that all packets have flushed. + Only a return value of 0 from ogg_stream_flush indicates all packet + data is flushed into pages. + + since ogg_stream_flush will flush the last page in a stream even if + it's undersized, you almost certainly want to use ogg_stream_pageout + (and *not* ogg_stream_flush) unless you specifically need to flush + a page regardless of size in the middle of a stream. */ + +int ogg_stream_flush(ogg_stream_state *os,ogg_page *og){ + return ogg_stream_flush_i(os,og,1,4096); +} + +/* Like the above, but an argument is provided to adjust the nominal + page size for applications which are smart enough to provide their + own delay based flushing */ + +int ogg_stream_flush_fill(ogg_stream_state *os,ogg_page *og, int nfill){ + return ogg_stream_flush_i(os,og,1,nfill); +} + +/* This constructs pages from buffered packet segments. The pointers +returned are to static buffers; do not free. The returned buffers are +good only until the next call (using the same ogg_stream_state) */ + +int ogg_stream_pageout(ogg_stream_state *os, ogg_page *og){ + int force=0; + if(ogg_stream_check(os)) return 0; + + if((os->e_o_s&&os->lacing_fill) || /* 'were done, now flush' case */ + (os->lacing_fill&&!os->b_o_s)) /* 'initial header page' case */ + force=1; + + return(ogg_stream_flush_i(os,og,force,4096)); +} + +/* Like the above, but an argument is provided to adjust the nominal +page size for applications which are smart enough to provide their +own delay based flushing */ + +int ogg_stream_pageout_fill(ogg_stream_state *os, ogg_page *og, int nfill){ + int force=0; + if(ogg_stream_check(os)) return 0; + + if((os->e_o_s&&os->lacing_fill) || /* 'were done, now flush' case */ + (os->lacing_fill&&!os->b_o_s)) /* 'initial header page' case */ + force=1; + + return(ogg_stream_flush_i(os,og,force,nfill)); +} + +int ogg_stream_eos(ogg_stream_state *os){ + if(ogg_stream_check(os)) return 1; + return os->e_o_s; +} + +/* DECODING PRIMITIVES: packet streaming layer **********************/ + +/* This has two layers to place more of the multi-serialno and paging + control in the application's hands. First, we expose a data buffer + using ogg_sync_buffer(). The app either copies into the + buffer, or passes it directly to read(), etc. We then call + ogg_sync_wrote() to tell how many bytes we just added. + + Pages are returned (pointers into the buffer in ogg_sync_state) + by ogg_sync_pageout(). The page is then submitted to + ogg_stream_pagein() along with the appropriate + ogg_stream_state* (ie, matching serialno). We then get raw + packets out calling ogg_stream_packetout() with a + ogg_stream_state. */ + +/* initialize the struct to a known state */ +int ogg_sync_init(ogg_sync_state *oy){ + if(oy){ + oy->storage = -1; /* used as a readiness flag */ + memset(oy,0,sizeof(*oy)); + } + return(0); +} + +/* clear non-flat storage within */ +int ogg_sync_clear(ogg_sync_state *oy){ + if(oy){ + if(oy->data)_ogg_free(oy->data); + memset(oy,0,sizeof(*oy)); + } + return(0); +} + +int ogg_sync_destroy(ogg_sync_state *oy){ + if(oy){ + ogg_sync_clear(oy); + _ogg_free(oy); + } + return(0); +} + +int ogg_sync_check(ogg_sync_state *oy){ + if(oy->storage<0) return -1; + return 0; +} + +char *ogg_sync_buffer(ogg_sync_state *oy, long size){ + if(ogg_sync_check(oy)) return NULL; + + /* first, clear out any space that has been previously returned */ + if(oy->returned){ + oy->fill-=oy->returned; + if(oy->fill>0) + memmove(oy->data,oy->data+oy->returned,oy->fill); + oy->returned=0; + } + + if(size>oy->storage-oy->fill){ + /* We need to extend the internal buffer */ + long newsize=size+oy->fill+4096; /* an extra page to be nice */ + void *ret; + + if(oy->data) + ret=_ogg_realloc(oy->data,newsize); + else + ret=_ogg_malloc(newsize); + if(!ret){ + ogg_sync_clear(oy); + return NULL; + } + oy->data=ret; + oy->storage=newsize; + } + + /* expose a segment at least as large as requested at the fill mark */ + return((char *)oy->data+oy->fill); +} + +int ogg_sync_wrote(ogg_sync_state *oy, long bytes){ + if(ogg_sync_check(oy))return -1; + if(oy->fill+bytes>oy->storage)return -1; + oy->fill+=bytes; + return(0); +} + +/* sync the stream. This is meant to be useful for finding page + boundaries. + + return values for this: + -n) skipped n bytes + 0) page not ready; more data (no bytes skipped) + n) page synced at current location; page length n bytes + +*/ + +long ogg_sync_pageseek(ogg_sync_state *oy,ogg_page *og){ + unsigned char *page=oy->data+oy->returned; + unsigned char *next; + long bytes=oy->fill-oy->returned; + + if(ogg_sync_check(oy))return 0; + + if(oy->headerbytes==0){ + int headerbytes,i; + if(bytes<27)return(0); /* not enough for a header */ + + /* verify capture pattern */ + if(memcmp(page,"OggS",4))goto sync_fail; + + headerbytes=page[26]+27; + if(bytesbodybytes+=page[27+i]; + oy->headerbytes=headerbytes; + } + + if(oy->bodybytes+oy->headerbytes>bytes)return(0); + + /* The whole test page is buffered. Verify the checksum */ + { + /* Grab the checksum bytes, set the header field to zero */ + char chksum[4]; + ogg_page log; + + memcpy(chksum,page+22,4); + memset(page+22,0,4); + + /* set up a temp page struct and recompute the checksum */ + log.header=page; + log.header_len=oy->headerbytes; + log.body=page+oy->headerbytes; + log.body_len=oy->bodybytes; + ogg_page_checksum_set(&log); + + /* Compare */ + if(memcmp(chksum,page+22,4)){ + /* D'oh. Mismatch! Corrupt page (or miscapture and not a page + at all) */ + /* replace the computed checksum with the one actually read in */ + memcpy(page+22,chksum,4); + +#ifndef DISABLE_CRC + /* Bad checksum. Lose sync */ + goto sync_fail; +#endif + } + } + + /* yes, have a whole page all ready to go */ + { + if(og){ + og->header=page; + og->header_len=oy->headerbytes; + og->body=page+oy->headerbytes; + og->body_len=oy->bodybytes; + } + + oy->unsynced=0; + oy->returned+=(bytes=oy->headerbytes+oy->bodybytes); + oy->headerbytes=0; + oy->bodybytes=0; + return(bytes); + } + + sync_fail: + + oy->headerbytes=0; + oy->bodybytes=0; + + /* search for possible capture */ + next=memchr(page+1,'O',bytes-1); + if(!next) + next=oy->data+oy->fill; + + oy->returned=(int)(next-oy->data); + return((long)-(next-page)); +} + +/* sync the stream and get a page. Keep trying until we find a page. + Suppress 'sync errors' after reporting the first. + + return values: + -1) recapture (hole in data) + 0) need more data + 1) page returned + + Returns pointers into buffered data; invalidated by next call to + _stream, _clear, _init, or _buffer */ + +int ogg_sync_pageout(ogg_sync_state *oy, ogg_page *og){ + + if(ogg_sync_check(oy))return 0; + + /* all we need to do is verify a page at the head of the stream + buffer. If it doesn't verify, we look for the next potential + frame */ + + for(;;){ + long ret=ogg_sync_pageseek(oy,og); + if(ret>0){ + /* have a page */ + return(1); + } + if(ret==0){ + /* need more data */ + return(0); + } + + /* head did not start a synced page... skipped some bytes */ + if(!oy->unsynced){ + oy->unsynced=1; + return(-1); + } + + /* loop. keep looking */ + + } +} + +/* add the incoming page to the stream state; we decompose the page + into packet segments here as well. */ + +int ogg_stream_pagein(ogg_stream_state *os, ogg_page *og){ + unsigned char *header=og->header; + unsigned char *body=og->body; + long bodysize=og->body_len; + int segptr=0; + + int version=ogg_page_version(og); + int continued=ogg_page_continued(og); + int bos=ogg_page_bos(og); + int eos=ogg_page_eos(og); + ogg_int64_t granulepos=ogg_page_granulepos(og); + int serialno=ogg_page_serialno(og); + long pageno=ogg_page_pageno(og); + int segments=header[26]; + + if(ogg_stream_check(os)) return -1; + + /* clean up 'returned data' */ + { + long lr=os->lacing_returned; + long br=os->body_returned; + + /* body data */ + if(br){ + os->body_fill-=br; + if(os->body_fill) + memmove(os->body_data,os->body_data+br,os->body_fill); + os->body_returned=0; + } + + if(lr){ + /* segment table */ + if(os->lacing_fill-lr){ + memmove(os->lacing_vals,os->lacing_vals+lr, + (os->lacing_fill-lr)*sizeof(*os->lacing_vals)); + memmove(os->granule_vals,os->granule_vals+lr, + (os->lacing_fill-lr)*sizeof(*os->granule_vals)); + } + os->lacing_fill-=lr; + os->lacing_packet-=lr; + os->lacing_returned=0; + } + } + + /* check the serial number */ + if(serialno!=os->serialno)return(-1); + if(version>0)return(-1); + + if(_os_lacing_expand(os,segments+1)) return -1; + + /* are we in sequence? */ + if(pageno!=os->pageno){ + int i; + + /* unroll previous partial packet (if any) */ + for(i=os->lacing_packet;ilacing_fill;i++) + os->body_fill-=os->lacing_vals[i]&0xff; + os->lacing_fill=os->lacing_packet; + + /* make a note of dropped data in segment table */ + if(os->pageno!=-1){ + os->lacing_vals[os->lacing_fill++]=0x400; + os->lacing_packet++; + } + } + + /* are we a 'continued packet' page? If so, we may need to skip + some segments */ + if(continued){ + if(os->lacing_fill<1 || + (os->lacing_vals[os->lacing_fill-1]&0xff)<255 || + os->lacing_vals[os->lacing_fill-1]==0x400){ + bos=0; + for(;segptrbody_data+os->body_fill,body,bodysize); + os->body_fill+=bodysize; + } + + { + int saved=-1; + while(segptrlacing_vals[os->lacing_fill]=val; + os->granule_vals[os->lacing_fill]=-1; + + if(bos){ + os->lacing_vals[os->lacing_fill]|=0x100; + bos=0; + } + + if(val<255)saved=os->lacing_fill; + + os->lacing_fill++; + segptr++; + + if(val<255)os->lacing_packet=os->lacing_fill; + } + + /* set the granulepos on the last granuleval of the last full packet */ + if(saved!=-1){ + os->granule_vals[saved]=granulepos; + } + + } + + if(eos){ + os->e_o_s=1; + if(os->lacing_fill>0) + os->lacing_vals[os->lacing_fill-1]|=0x200; + } + + os->pageno=pageno+1; + + return(0); +} + +/* clear things to an initial state. Good to call, eg, before seeking */ +int ogg_sync_reset(ogg_sync_state *oy){ + if(ogg_sync_check(oy))return -1; + + oy->fill=0; + oy->returned=0; + oy->unsynced=0; + oy->headerbytes=0; + oy->bodybytes=0; + return(0); +} + +int ogg_stream_reset(ogg_stream_state *os){ + if(ogg_stream_check(os)) return -1; + + os->body_fill=0; + os->body_returned=0; + + os->lacing_fill=0; + os->lacing_packet=0; + os->lacing_returned=0; + + os->header_fill=0; + + os->e_o_s=0; + os->b_o_s=0; + os->pageno=-1; + os->packetno=0; + os->granulepos=0; + + return(0); +} + +int ogg_stream_reset_serialno(ogg_stream_state *os,int serialno){ + if(ogg_stream_check(os)) return -1; + ogg_stream_reset(os); + os->serialno=serialno; + return(0); +} + +static int _packetout(ogg_stream_state *os,ogg_packet *op,int adv){ + + /* The last part of decode. We have the stream broken into packet + segments. Now we need to group them into packets (or return the + out of sync markers) */ + + int ptr=os->lacing_returned; + + if(os->lacing_packet<=ptr)return(0); + + if(os->lacing_vals[ptr]&0x400){ + /* we need to tell the codec there's a gap; it might need to + handle previous packet dependencies. */ + os->lacing_returned++; + os->packetno++; + return(-1); + } + + if(!op && !adv)return(1); /* just using peek as an inexpensive way + to ask if there's a whole packet + waiting */ + + /* Gather the whole packet. We'll have no holes or a partial packet */ + { + int size=os->lacing_vals[ptr]&0xff; + long bytes=size; + int eos=os->lacing_vals[ptr]&0x200; /* last packet of the stream? */ + int bos=os->lacing_vals[ptr]&0x100; /* first packet of the stream? */ + + while(size==255){ + int val=os->lacing_vals[++ptr]; + size=val&0xff; + if(val&0x200)eos=0x200; + bytes+=size; + } + + if(op){ + op->e_o_s=eos; + op->b_o_s=bos; + op->packet=os->body_data+os->body_returned; + op->packetno=os->packetno; + op->granulepos=os->granule_vals[ptr]; + op->bytes=bytes; + } + + if(adv){ + os->body_returned+=bytes; + os->lacing_returned=ptr+1; + os->packetno++; + } + } + return(1); +} + +int ogg_stream_packetout(ogg_stream_state *os,ogg_packet *op){ + if(ogg_stream_check(os)) return 0; + return _packetout(os,op,1); +} + +int ogg_stream_packetpeek(ogg_stream_state *os,ogg_packet *op){ + if(ogg_stream_check(os)) return 0; + return _packetout(os,op,0); +} + +void ogg_packet_clear(ogg_packet *op) { + _ogg_free(op->packet); + memset(op, 0, sizeof(*op)); +} + +#ifdef _V_SELFTEST +#include + +ogg_stream_state os_en, os_de; +ogg_sync_state oy; + +void checkpacket(ogg_packet *op,long len, int no, long pos){ + long j; + static int sequence=0; + static int lastno=0; + + if(op->bytes!=len){ + fprintf(stderr,"incorrect packet length (%ld != %ld)!\n",op->bytes,len); + exit(1); + } + if(op->granulepos!=pos){ + fprintf(stderr,"incorrect packet granpos (%ld != %ld)!\n",(long)op->granulepos,pos); + exit(1); + } + + /* packet number just follows sequence/gap; adjust the input number + for that */ + if(no==0){ + sequence=0; + }else{ + sequence++; + if(no>lastno+1) + sequence++; + } + lastno=no; + if(op->packetno!=sequence){ + fprintf(stderr,"incorrect packet sequence %ld != %d\n", + (long)(op->packetno),sequence); + exit(1); + } + + /* Test data */ + for(j=0;jbytes;j++) + if(op->packet[j]!=((j+no)&0xff)){ + fprintf(stderr,"body data mismatch (1) at pos %ld: %x!=%lx!\n\n", + j,op->packet[j],(j+no)&0xff); + exit(1); + } +} + +void check_page(unsigned char *data,const int *header,ogg_page *og){ + long j; + /* Test data */ + for(j=0;jbody_len;j++) + if(og->body[j]!=data[j]){ + fprintf(stderr,"body data mismatch (2) at pos %ld: %x!=%x!\n\n", + j,data[j],og->body[j]); + exit(1); + } + + /* Test header */ + for(j=0;jheader_len;j++){ + if(og->header[j]!=header[j]){ + fprintf(stderr,"header content mismatch at pos %ld:\n",j); + for(j=0;jheader[j]); + fprintf(stderr,"\n"); + exit(1); + } + } + if(og->header_len!=header[26]+27){ + fprintf(stderr,"header length incorrect! (%ld!=%d)\n", + og->header_len,header[26]+27); + exit(1); + } +} + +void print_header(ogg_page *og){ + int j; + fprintf(stderr,"\nHEADER:\n"); + fprintf(stderr," capture: %c %c %c %c version: %d flags: %x\n", + og->header[0],og->header[1],og->header[2],og->header[3], + (int)og->header[4],(int)og->header[5]); + + fprintf(stderr," granulepos: %d serialno: %d pageno: %ld\n", + (og->header[9]<<24)|(og->header[8]<<16)| + (og->header[7]<<8)|og->header[6], + (og->header[17]<<24)|(og->header[16]<<16)| + (og->header[15]<<8)|og->header[14], + ((long)(og->header[21])<<24)|(og->header[20]<<16)| + (og->header[19]<<8)|og->header[18]); + + fprintf(stderr," checksum: %02x:%02x:%02x:%02x\n segments: %d (", + (int)og->header[22],(int)og->header[23], + (int)og->header[24],(int)og->header[25], + (int)og->header[26]); + + for(j=27;jheader_len;j++) + fprintf(stderr,"%d ",(int)og->header[j]); + fprintf(stderr,")\n\n"); +} + +void copy_page(ogg_page *og){ + unsigned char *temp=_ogg_malloc(og->header_len); + memcpy(temp,og->header,og->header_len); + og->header=temp; + + temp=_ogg_malloc(og->body_len); + memcpy(temp,og->body,og->body_len); + og->body=temp; +} + +void free_page(ogg_page *og){ + _ogg_free (og->header); + _ogg_free (og->body); +} + +void error(void){ + fprintf(stderr,"error!\n"); + exit(1); +} + +/* 17 only */ +const int head1_0[] = {0x4f,0x67,0x67,0x53,0,0x06, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,0,0,0,0, + 0x15,0xed,0xec,0x91, + 1, + 17}; + +/* 17, 254, 255, 256, 500, 510, 600 byte, pad */ +const int head1_1[] = {0x4f,0x67,0x67,0x53,0,0x02, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,0,0,0,0, + 0x59,0x10,0x6c,0x2c, + 1, + 17}; +const int head2_1[] = {0x4f,0x67,0x67,0x53,0,0x04, + 0x07,0x18,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,1,0,0,0, + 0x89,0x33,0x85,0xce, + 13, + 254,255,0,255,1,255,245,255,255,0, + 255,255,90}; + +/* nil packets; beginning,middle,end */ +const int head1_2[] = {0x4f,0x67,0x67,0x53,0,0x02, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,0,0,0,0, + 0xff,0x7b,0x23,0x17, + 1, + 0}; +const int head2_2[] = {0x4f,0x67,0x67,0x53,0,0x04, + 0x07,0x28,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,1,0,0,0, + 0x5c,0x3f,0x66,0xcb, + 17, + 17,254,255,0,0,255,1,0,255,245,255,255,0, + 255,255,90,0}; + +/* large initial packet */ +const int head1_3[] = {0x4f,0x67,0x67,0x53,0,0x02, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,0,0,0,0, + 0x01,0x27,0x31,0xaa, + 18, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255,255,10}; + +const int head2_3[] = {0x4f,0x67,0x67,0x53,0,0x04, + 0x07,0x08,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,1,0,0,0, + 0x7f,0x4e,0x8a,0xd2, + 4, + 255,4,255,0}; + + +/* continuing packet test */ +const int head1_4[] = {0x4f,0x67,0x67,0x53,0,0x02, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,0,0,0,0, + 0xff,0x7b,0x23,0x17, + 1, + 0}; + +const int head2_4[] = {0x4f,0x67,0x67,0x53,0,0x00, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0x01,0x02,0x03,0x04,1,0,0,0, + 0xf8,0x3c,0x19,0x79, + 255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255}; + +const int head3_4[] = {0x4f,0x67,0x67,0x53,0,0x05, + 0x07,0x0c,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,2,0,0,0, + 0x38,0xe6,0xb6,0x28, + 6, + 255,220,255,4,255,0}; + + +/* spill expansion test */ +const int head1_4b[] = {0x4f,0x67,0x67,0x53,0,0x02, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,0,0,0,0, + 0xff,0x7b,0x23,0x17, + 1, + 0}; + +const int head2_4b[] = {0x4f,0x67,0x67,0x53,0,0x00, + 0x07,0x10,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,1,0,0,0, + 0xce,0x8f,0x17,0x1a, + 23, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255,255,10,255,4,255,0,0}; + + +const int head3_4b[] = {0x4f,0x67,0x67,0x53,0,0x04, + 0x07,0x14,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,2,0,0,0, + 0x9b,0xb2,0x50,0xa1, + 1, + 0}; + +/* page with the 255 segment limit */ +const int head1_5[] = {0x4f,0x67,0x67,0x53,0,0x02, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,0,0,0,0, + 0xff,0x7b,0x23,0x17, + 1, + 0}; + +const int head2_5[] = {0x4f,0x67,0x67,0x53,0,0x00, + 0x07,0xfc,0x03,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,1,0,0,0, + 0xed,0x2a,0x2e,0xa7, + 255, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10}; + +const int head3_5[] = {0x4f,0x67,0x67,0x53,0,0x04, + 0x07,0x00,0x04,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,2,0,0,0, + 0x6c,0x3b,0x82,0x3d, + 1, + 50}; + + +/* packet that overspans over an entire page */ +const int head1_6[] = {0x4f,0x67,0x67,0x53,0,0x02, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,0,0,0,0, + 0xff,0x7b,0x23,0x17, + 1, + 0}; + +const int head2_6[] = {0x4f,0x67,0x67,0x53,0,0x00, + 0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,1,0,0,0, + 0x68,0x22,0x7c,0x3d, + 255, + 100, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255}; + +const int head3_6[] = {0x4f,0x67,0x67,0x53,0,0x01, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0x01,0x02,0x03,0x04,2,0,0,0, + 0xf4,0x87,0xba,0xf3, + 255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255}; + +const int head4_6[] = {0x4f,0x67,0x67,0x53,0,0x05, + 0x07,0x10,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,3,0,0,0, + 0xf7,0x2f,0x6c,0x60, + 5, + 254,255,4,255,0}; + +/* packet that overspans over an entire page */ +const int head1_7[] = {0x4f,0x67,0x67,0x53,0,0x02, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,0,0,0,0, + 0xff,0x7b,0x23,0x17, + 1, + 0}; + +const int head2_7[] = {0x4f,0x67,0x67,0x53,0,0x00, + 0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,1,0,0,0, + 0x68,0x22,0x7c,0x3d, + 255, + 100, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255}; + +const int head3_7[] = {0x4f,0x67,0x67,0x53,0,0x05, + 0x07,0x08,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,2,0,0,0, + 0xd4,0xe0,0x60,0xe5, + 1, + 0}; + +int compare_packet(const ogg_packet *op1, const ogg_packet *op2){ + if(op1->packet!=op2->packet){ + fprintf(stderr,"op1->packet != op2->packet\n"); + return(1); + } + if(op1->bytes!=op2->bytes){ + fprintf(stderr,"op1->bytes != op2->bytes\n"); + return(1); + } + if(op1->b_o_s!=op2->b_o_s){ + fprintf(stderr,"op1->b_o_s != op2->b_o_s\n"); + return(1); + } + if(op1->e_o_s!=op2->e_o_s){ + fprintf(stderr,"op1->e_o_s != op2->e_o_s\n"); + return(1); + } + if(op1->granulepos!=op2->granulepos){ + fprintf(stderr,"op1->granulepos != op2->granulepos\n"); + return(1); + } + if(op1->packetno!=op2->packetno){ + fprintf(stderr,"op1->packetno != op2->packetno\n"); + return(1); + } + return(0); +} + +void test_pack(const int *pl, const int **headers, int byteskip, + int pageskip, int packetskip){ + unsigned char *data=_ogg_malloc(1024*1024); /* for scripted test cases only */ + long inptr=0; + long outptr=0; + long deptr=0; + long depacket=0; + long granule_pos=7,pageno=0; + int i,j,packets,pageout=pageskip; + int eosflag=0; + int bosflag=0; + + int byteskipcount=0; + + ogg_stream_reset(&os_en); + ogg_stream_reset(&os_de); + ogg_sync_reset(&oy); + + for(packets=0;packetsbyteskip){ + memcpy(next,og.header,byteskipcount-byteskip); + next+=byteskipcount-byteskip; + byteskipcount=byteskip; + } + + byteskipcount+=og.body_len; + if(byteskipcount>byteskip){ + memcpy(next,og.body,byteskipcount-byteskip); + next+=byteskipcount-byteskip; + byteskipcount=byteskip; + } + + ogg_sync_wrote(&oy,next-buf); + + while(1){ + int ret=ogg_sync_pageout(&oy,&og_de); + if(ret==0)break; + if(ret<0)continue; + /* got a page. Happy happy. Verify that it's good. */ + + fprintf(stderr,"(%d), ",pageout); + + check_page(data+deptr,headers[pageout],&og_de); + deptr+=og_de.body_len; + pageout++; + + /* submit it to deconstitution */ + ogg_stream_pagein(&os_de,&og_de); + + /* packets out? */ + while(ogg_stream_packetpeek(&os_de,&op_de2)>0){ + ogg_stream_packetpeek(&os_de,NULL); + ogg_stream_packetout(&os_de,&op_de); /* just catching them all */ + + /* verify peek and out match */ + if(compare_packet(&op_de,&op_de2)){ + fprintf(stderr,"packetout != packetpeek! pos=%ld\n", + depacket); + exit(1); + } + + /* verify the packet! */ + /* check data */ + if(memcmp(data+depacket,op_de.packet,op_de.bytes)){ + fprintf(stderr,"packet data mismatch in decode! pos=%ld\n", + depacket); + exit(1); + } + /* check bos flag */ + if(bosflag==0 && op_de.b_o_s==0){ + fprintf(stderr,"b_o_s flag not set on packet!\n"); + exit(1); + } + if(bosflag && op_de.b_o_s){ + fprintf(stderr,"b_o_s flag incorrectly set on packet!\n"); + exit(1); + } + bosflag=1; + depacket+=op_de.bytes; + + /* check eos flag */ + if(eosflag){ + fprintf(stderr,"Multiple decoded packets with eos flag!\n"); + exit(1); + } + + if(op_de.e_o_s)eosflag=1; + + /* check granulepos flag */ + if(op_de.granulepos!=-1){ + fprintf(stderr," granule:%ld ",(long)op_de.granulepos); + } + } + } + } + } + } + } + _ogg_free(data); + if(headers[pageno]!=NULL){ + fprintf(stderr,"did not write last page!\n"); + exit(1); + } + if(headers[pageout]!=NULL){ + fprintf(stderr,"did not decode last page!\n"); + exit(1); + } + if(inptr!=outptr){ + fprintf(stderr,"encoded page data incomplete!\n"); + exit(1); + } + if(inptr!=deptr){ + fprintf(stderr,"decoded page data incomplete!\n"); + exit(1); + } + if(inptr!=depacket){ + fprintf(stderr,"decoded packet data incomplete!\n"); + exit(1); + } + if(!eosflag){ + fprintf(stderr,"Never got a packet with EOS set!\n"); + exit(1); + } + fprintf(stderr,"ok.\n"); +} + +int main(void){ + + ogg_stream_init(&os_en,0x04030201); + ogg_stream_init(&os_de,0x04030201); + ogg_sync_init(&oy); + + /* Exercise each code path in the framing code. Also verify that + the checksums are working. */ + + { + /* 17 only */ + const int packets[]={17, -1}; + const int *headret[]={head1_0,NULL}; + + fprintf(stderr,"testing single page encoding... "); + test_pack(packets,headret,0,0,0); + } + + { + /* 17, 254, 255, 256, 500, 510, 600 byte, pad */ + const int packets[]={17, 254, 255, 256, 500, 510, 600, -1}; + const int *headret[]={head1_1,head2_1,NULL}; + + fprintf(stderr,"testing basic page encoding... "); + test_pack(packets,headret,0,0,0); + } + + { + /* nil packets; beginning,middle,end */ + const int packets[]={0,17, 254, 255, 0, 256, 0, 500, 510, 600, 0, -1}; + const int *headret[]={head1_2,head2_2,NULL}; + + fprintf(stderr,"testing basic nil packets... "); + test_pack(packets,headret,0,0,0); + } + + { + /* large initial packet */ + const int packets[]={4345,259,255,-1}; + const int *headret[]={head1_3,head2_3,NULL}; + + fprintf(stderr,"testing initial-packet lacing > 4k... "); + test_pack(packets,headret,0,0,0); + } + + { + /* continuing packet test; with page spill expansion, we have to + overflow the lacing table. */ + const int packets[]={0,65500,259,255,-1}; + const int *headret[]={head1_4,head2_4,head3_4,NULL}; + + fprintf(stderr,"testing single packet page span... "); + test_pack(packets,headret,0,0,0); + } + + { + /* spill expand packet test */ + const int packets[]={0,4345,259,255,0,0,-1}; + const int *headret[]={head1_4b,head2_4b,head3_4b,NULL}; + + fprintf(stderr,"testing page spill expansion... "); + test_pack(packets,headret,0,0,0); + } + + /* page with the 255 segment limit */ + { + + const int packets[]={0,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,50,-1}; + const int *headret[]={head1_5,head2_5,head3_5,NULL}; + + fprintf(stderr,"testing max packet segments... "); + test_pack(packets,headret,0,0,0); + } + + { + /* packet that overspans over an entire page */ + const int packets[]={0,100,130049,259,255,-1}; + const int *headret[]={head1_6,head2_6,head3_6,head4_6,NULL}; + + fprintf(stderr,"testing very large packets... "); + test_pack(packets,headret,0,0,0); + } + +#ifndef DISABLE_CRC + { + /* test for the libogg 1.1.1 resync in large continuation bug + found by Josh Coalson) */ + const int packets[]={0,100,130049,259,255,-1}; + const int *headret[]={head1_6,head2_6,head3_6,head4_6,NULL}; + + fprintf(stderr,"testing continuation resync in very large packets... "); + test_pack(packets,headret,100,2,3); + } +#else + fprintf(stderr,"Skipping continuation resync test due to --disable-crc\n"); +#endif + + { + /* term only page. why not? */ + const int packets[]={0,100,64770,-1}; + const int *headret[]={head1_7,head2_7,head3_7,NULL}; + + fprintf(stderr,"testing zero data page (1 nil packet)... "); + test_pack(packets,headret,0,0,0); + } + + + + { + /* build a bunch of pages for testing */ + unsigned char *data=_ogg_malloc(1024*1024); + int pl[]={0, 1,1,98,4079, 1,1,2954,2057, 76,34,912,0,234,1000,1000, 1000,300,-1}; + int inptr=0,i,j; + ogg_page og[5]; + + ogg_stream_reset(&os_en); + + for(i=0;pl[i]!=-1;i++){ + ogg_packet op; + int len=pl[i]; + + op.packet=data+inptr; + op.bytes=len; + op.e_o_s=(pl[i+1]<0?1:0); + op.granulepos=(i+1)*1000; + + for(j=0;j0)error(); + + /* Test fractional page inputs: incomplete fixed header */ + memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+3, + 20); + ogg_sync_wrote(&oy,20); + if(ogg_sync_pageout(&oy,&og_de)>0)error(); + + /* Test fractional page inputs: incomplete header */ + memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+23, + 5); + ogg_sync_wrote(&oy,5); + if(ogg_sync_pageout(&oy,&og_de)>0)error(); + + /* Test fractional page inputs: incomplete body */ + + memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+28, + og[1].header_len-28); + ogg_sync_wrote(&oy,og[1].header_len-28); + if(ogg_sync_pageout(&oy,&og_de)>0)error(); + + memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,1000); + ogg_sync_wrote(&oy,1000); + if(ogg_sync_pageout(&oy,&og_de)>0)error(); + + memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body+1000, + og[1].body_len-1000); + ogg_sync_wrote(&oy,og[1].body_len-1000); + if(ogg_sync_pageout(&oy,&og_de)<=0)error(); + + fprintf(stderr,"ok.\n"); + } + + /* Test fractional page inputs: page + incomplete capture */ + { + ogg_page og_de; + fprintf(stderr,"Testing sync on 1+partial inputs... "); + ogg_sync_reset(&oy); + + memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header, + og[1].header_len); + ogg_sync_wrote(&oy,og[1].header_len); + + memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body, + og[1].body_len); + ogg_sync_wrote(&oy,og[1].body_len); + + memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header, + 20); + ogg_sync_wrote(&oy,20); + if(ogg_sync_pageout(&oy,&og_de)<=0)error(); + if(ogg_sync_pageout(&oy,&og_de)>0)error(); + + memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+20, + og[1].header_len-20); + ogg_sync_wrote(&oy,og[1].header_len-20); + memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body, + og[1].body_len); + ogg_sync_wrote(&oy,og[1].body_len); + if(ogg_sync_pageout(&oy,&og_de)<=0)error(); + + fprintf(stderr,"ok.\n"); + } + + /* Test recapture: garbage + page */ + { + ogg_page og_de; + fprintf(stderr,"Testing search for capture... "); + ogg_sync_reset(&oy); + + /* 'garbage' */ + memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body, + og[1].body_len); + ogg_sync_wrote(&oy,og[1].body_len); + + memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header, + og[1].header_len); + ogg_sync_wrote(&oy,og[1].header_len); + + memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body, + og[1].body_len); + ogg_sync_wrote(&oy,og[1].body_len); + + memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header, + 20); + ogg_sync_wrote(&oy,20); + if(ogg_sync_pageout(&oy,&og_de)>0)error(); + if(ogg_sync_pageout(&oy,&og_de)<=0)error(); + if(ogg_sync_pageout(&oy,&og_de)>0)error(); + + memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header+20, + og[2].header_len-20); + ogg_sync_wrote(&oy,og[2].header_len-20); + memcpy(ogg_sync_buffer(&oy,og[2].body_len),og[2].body, + og[2].body_len); + ogg_sync_wrote(&oy,og[2].body_len); + if(ogg_sync_pageout(&oy,&og_de)<=0)error(); + + fprintf(stderr,"ok.\n"); + } + +#ifndef DISABLE_CRC + /* Test recapture: page + garbage + page */ + { + ogg_page og_de; + fprintf(stderr,"Testing recapture... "); + ogg_sync_reset(&oy); + + memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header, + og[1].header_len); + ogg_sync_wrote(&oy,og[1].header_len); + + memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body, + og[1].body_len); + ogg_sync_wrote(&oy,og[1].body_len); + + memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header, + og[2].header_len); + ogg_sync_wrote(&oy,og[2].header_len); + + memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header, + og[2].header_len); + ogg_sync_wrote(&oy,og[2].header_len); + + if(ogg_sync_pageout(&oy,&og_de)<=0)error(); + + memcpy(ogg_sync_buffer(&oy,og[2].body_len),og[2].body, + og[2].body_len-5); + ogg_sync_wrote(&oy,og[2].body_len-5); + + memcpy(ogg_sync_buffer(&oy,og[3].header_len),og[3].header, + og[3].header_len); + ogg_sync_wrote(&oy,og[3].header_len); + + memcpy(ogg_sync_buffer(&oy,og[3].body_len),og[3].body, + og[3].body_len); + ogg_sync_wrote(&oy,og[3].body_len); + + if(ogg_sync_pageout(&oy,&og_de)>0)error(); + if(ogg_sync_pageout(&oy,&og_de)<=0)error(); + + fprintf(stderr,"ok.\n"); + } +#else + fprintf(stderr,"Skipping recapture test due to --disable-crc\n"); +#endif + + /* Free page data that was previously copied */ + { + for(i=0;i<5;i++){ + free_page(&og[i]); + } + } + } + ogg_sync_clear(&oy); + ogg_stream_clear(&os_en); + ogg_stream_clear(&os_de); + + return(0); +} + +#endif diff --git a/extern/ogg/symbian/bld.inf b/extern/ogg/symbian/bld.inf new file mode 100644 index 0000000..47132c3 --- /dev/null +++ b/extern/ogg/symbian/bld.inf @@ -0,0 +1,35 @@ +/* + Copyright (C) 2003 Commonwealth Scientific and Industrial Research + Organisation (CSIRO) Australia + + 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 CSIRO Australia nor the names of its + 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 ORGANISATION 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. +*/ + +PRJ_MMPFILES + +ogg.mmp diff --git a/extern/ogg/symbian/ogg.mmp b/extern/ogg/symbian/ogg.mmp new file mode 100644 index 0000000..13b553d --- /dev/null +++ b/extern/ogg/symbian/ogg.mmp @@ -0,0 +1,39 @@ +/* + Copyright (C) 2003 Commonwealth Scientific and Industrial Research + Organisation (CSIRO) Australia + + 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 CSIRO Australia nor the names of its + 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 ORGANISATION 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. +*/ + +TARGET ogg.lib +TARGETTYPE lib +UID 0 +SOURCEPATH ..\src +SOURCE bitwise.c framing.c +USERINCLUDE . +SYSTEMINCLUDE \epoc32\include \epoc32\include\libc ..\include . diff --git a/extern/ogg/win32/.gitignore b/extern/ogg/win32/.gitignore new file mode 100644 index 0000000..eb2b1ee --- /dev/null +++ b/extern/ogg/win32/.gitignore @@ -0,0 +1,105 @@ +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# Build results +[Dd]ebug/ +[Dd]ebugDLL/ +[Rr]elease/ +[Rr]eleaseDLL/ +x64/ +x86/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Local History for Visual Studio +.localhistory/ diff --git a/extern/ogg/win32/VS2015/libogg.sln b/extern/ogg/win32/VS2015/libogg.sln new file mode 100644 index 0000000..e19789a --- /dev/null +++ b/extern/ogg/win32/VS2015/libogg.sln @@ -0,0 +1,38 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libogg", "libogg.vcxproj", "{AFF27A26-C088-444B-BC2A-0BA94A02AFA7}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|Win32 = Debug|Win32 + DebugDLL|x64 = DebugDLL|x64 + DebugDLL|Win32 = DebugDLL|Win32 + Release|x64 = Release|x64 + Release|Win32 = Release|Win32 + ReleaseDLL|x64 = ReleaseDLL|x64 + ReleaseDLL|Win32 = ReleaseDLL|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {AFF27A26-C088-444B-BC2A-0BA94A02AFA7}.Debug|x64.ActiveCfg = Debug|x64 + {AFF27A26-C088-444B-BC2A-0BA94A02AFA7}.Debug|x64.Build.0 = Debug|x64 + {AFF27A26-C088-444B-BC2A-0BA94A02AFA7}.Debug|Win32.ActiveCfg = Debug|Win32 + {AFF27A26-C088-444B-BC2A-0BA94A02AFA7}.Debug|Win32.Build.0 = Debug|Win32 + {AFF27A26-C088-444B-BC2A-0BA94A02AFA7}.DebugDLL|x64.ActiveCfg = DebugDLL|x64 + {AFF27A26-C088-444B-BC2A-0BA94A02AFA7}.DebugDLL|x64.Build.0 = DebugDLL|x64 + {AFF27A26-C088-444B-BC2A-0BA94A02AFA7}.DebugDLL|Win32.ActiveCfg = DebugDLL|Win32 + {AFF27A26-C088-444B-BC2A-0BA94A02AFA7}.DebugDLL|Win32.Build.0 = DebugDLL|Win32 + {AFF27A26-C088-444B-BC2A-0BA94A02AFA7}.Release|x64.ActiveCfg = Release|x64 + {AFF27A26-C088-444B-BC2A-0BA94A02AFA7}.Release|x64.Build.0 = Release|x64 + {AFF27A26-C088-444B-BC2A-0BA94A02AFA7}.Release|Win32.ActiveCfg = Release|Win32 + {AFF27A26-C088-444B-BC2A-0BA94A02AFA7}.Release|Win32.Build.0 = Release|Win32 + {AFF27A26-C088-444B-BC2A-0BA94A02AFA7}.ReleaseDLL|x64.ActiveCfg = ReleaseDLL|x64 + {AFF27A26-C088-444B-BC2A-0BA94A02AFA7}.ReleaseDLL|x64.Build.0 = ReleaseDLL|x64 + {AFF27A26-C088-444B-BC2A-0BA94A02AFA7}.ReleaseDLL|Win32.ActiveCfg = ReleaseDLL|Win32 + {AFF27A26-C088-444B-BC2A-0BA94A02AFA7}.ReleaseDLL|Win32.Build.0 = ReleaseDLL|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/extern/ogg/win32/VS2015/libogg.vcxproj b/extern/ogg/win32/VS2015/libogg.vcxproj new file mode 100644 index 0000000..9dec07a --- /dev/null +++ b/extern/ogg/win32/VS2015/libogg.vcxproj @@ -0,0 +1,296 @@ + + + + + DebugDLL + Win32 + + + DebugDLL + x64 + + + Debug + Win32 + + + ReleaseDLL + Win32 + + + ReleaseDLL + x64 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + {AFF27A26-C088-444B-BC2A-0BA94A02AFA7} + libogg + 8.1 + + + + StaticLibrary + true + v140 + MultiByte + $(SolutionDir)$(PlatformName)\$(Configuration)\ + $(PlatformName)\$(Configuration)\ + + + DynamicLibrary + true + v140 + MultiByte + $(SolutionDir)$(PlatformName)\$(Configuration)\ + $(PlatformName)\$(Configuration)\ + + + StaticLibrary + false + v140 + true + MultiByte + $(SolutionDir)$(PlatformName)\$(Configuration)\ + $(PlatformName)\$(Configuration)\ + + + DynamicLibrary + false + v140 + true + MultiByte + $(SolutionDir)$(PlatformName)\$(Configuration)\ + $(PlatformName)\$(Configuration)\ + + + StaticLibrary + true + v140 + MultiByte + $(SolutionDir)$(PlatformName)\$(Configuration)\ + $(PlatformName)\$(Configuration)\ + + + DynamicLibrary + true + v140 + MultiByte + $(SolutionDir)$(PlatformName)\$(Configuration)\ + $(PlatformName)\$(Configuration)\ + + + StaticLibrary + false + v140 + true + MultiByte + $(SolutionDir)$(PlatformName)\$(Configuration)\ + $(PlatformName)\$(Configuration)\ + + + DynamicLibrary + false + v140 + true + MultiByte + $(SolutionDir)$(PlatformName)\$(Configuration)\ + $(PlatformName)\$(Configuration)\ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + $(SolutionDir)..\..\include;%(AdditionalIncludeDirectories) + false + true + 4244;%(DisableSpecificWarnings) + false + true + true + Disabled + MultiThreadedDebug + Level4 + + + + + $(SolutionDir)..\..\include;%(AdditionalIncludeDirectories) + false + true + 4244;%(DisableSpecificWarnings) + false + true + Disabled + Level4 + + + $(SolutionDir)..\ogg.def + + + + + $(SolutionDir)..\..\include;%(AdditionalIncludeDirectories) + false + true + 4244;%(DisableSpecificWarnings) + false + true + true + Disabled + MultiThreadedDebug + Level4 + + + + + $(SolutionDir)..\..\include;%(AdditionalIncludeDirectories) + false + true + 4244;%(DisableSpecificWarnings) + false + true + Disabled + Level4 + + + $(SolutionDir)..\ogg.def + + + + + $(SolutionDir)..\..\include;%(AdditionalIncludeDirectories) + false + true + 4244;%(DisableSpecificWarnings) + true + true + false + true + true + MaxSpeed + NDEBUG;%(PreprocessorDefinitions) + MultiThreaded + Level4 + + + true + true + + + + + $(SolutionDir)..\..\include;%(AdditionalIncludeDirectories) + false + true + 4244;%(DisableSpecificWarnings) + true + true + false + true + MaxSpeed + NDEBUG;%(PreprocessorDefinitions) + Level4 + + + true + $(SolutionDir)..\ogg.def + true + + + + + $(SolutionDir)..\..\include;%(AdditionalIncludeDirectories) + false + true + 4244;%(DisableSpecificWarnings) + true + true + false + true + true + MaxSpeed + NDEBUG;%(PreprocessorDefinitions) + MultiThreaded + Level4 + + + true + true + + + + + $(SolutionDir)..\..\include;%(AdditionalIncludeDirectories) + false + true + 4244;%(DisableSpecificWarnings) + true + true + false + true + MaxSpeed + NDEBUG;%(PreprocessorDefinitions) + Level4 + + + true + $(SolutionDir)..\ogg.def + true + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/extern/ogg/win32/VS2015/libogg.vcxproj.filters b/extern/ogg/win32/VS2015/libogg.vcxproj.filters new file mode 100644 index 0000000..76b1f4e --- /dev/null +++ b/extern/ogg/win32/VS2015/libogg.vcxproj.filters @@ -0,0 +1,41 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + + + Source Files + + + \ No newline at end of file diff --git a/extern/ogg/win32/ogg.def b/extern/ogg/win32/ogg.def new file mode 100644 index 0000000..030b644 --- /dev/null +++ b/extern/ogg/win32/ogg.def @@ -0,0 +1,80 @@ +; +; ogg.def +; List of exported functions for Windows builds. +; +LIBRARY ogg +EXPORTS +; +oggpack_writeinit +oggpack_writetrunc +oggpack_writealign +oggpack_writecopy +oggpack_reset +oggpack_writeclear +oggpack_readinit +oggpack_write +oggpack_look +oggpack_look1 +oggpack_adv +oggpack_adv1 +oggpack_read +oggpack_read1 +oggpack_bytes +oggpack_bits +oggpack_get_buffer +; +oggpackB_writeinit +oggpackB_writetrunc +oggpackB_writealign +oggpackB_writecopy +oggpackB_reset +oggpackB_writeclear +oggpackB_readinit +oggpackB_write +oggpackB_look +oggpackB_look1 +oggpackB_adv +oggpackB_adv1 +oggpackB_read +oggpackB_read1 +oggpackB_bytes +oggpackB_bits +oggpackB_get_buffer +; +ogg_stream_packetin +ogg_stream_pageout +ogg_stream_flush +; +ogg_sync_init +ogg_sync_clear +ogg_sync_reset +ogg_sync_destroy +ogg_sync_buffer +ogg_sync_wrote +ogg_sync_pageseek +ogg_sync_pageout +ogg_stream_pagein +ogg_stream_packetout +ogg_stream_packetpeek +; +ogg_stream_init +ogg_stream_clear +ogg_stream_reset +ogg_stream_reset_serialno +ogg_stream_destroy +ogg_stream_eos +ogg_stream_pageout_fill +ogg_stream_flush_fill +; +ogg_page_checksum_set +ogg_page_version +ogg_page_continued +ogg_page_bos +ogg_page_eos +ogg_page_granulepos +ogg_page_serialno +ogg_page_pageno +ogg_page_packets +ogg_packet_clear + + diff --git a/extern/opus/.appveyor.yml b/extern/opus/.appveyor.yml new file mode 100644 index 0000000..a0f4a77 --- /dev/null +++ b/extern/opus/.appveyor.yml @@ -0,0 +1,37 @@ +image: Visual Studio 2015 +configuration: +- Debug +- DebugDLL +- DebugDLL_fixed +- Release +- ReleaseDLL +- ReleaseDLL_fixed + +platform: +- Win32 +- x64 + +environment: + api_key: + secure: kR3Ac0NjGwFnTmXdFrR8d6VXjdk5F7L4F/BilC4nvaM= + +build: + project: win32\VS2015\opus.sln + parallel: true + verbosity: minimal + +after_build: +- cd %APPVEYOR_BUILD_FOLDER% +- 7z a opus.zip win32\VS2015\%PLATFORM%\%CONFIGURATION%\opus.??? include\*.h + +test_script: +- cd %APPVEYOR_BUILD_FOLDER%\win32\VS2015\%PLATFORM%\%CONFIGURATION% +- test_opus_api.exe +- test_opus_decode.exe +- test_opus_encode.exe + +artifacts: +- path: opus.zip + +on_success: +- ps: if ($env:api_key -and "$env:configuration/$env:platform" -eq "ReleaseDLL_fixed/x64") { Start-AppveyorBuild -ApiKey $env:api_key -ProjectSlug 'opus-tools' } diff --git a/extern/opus/.gitattributes b/extern/opus/.gitattributes new file mode 100644 index 0000000..649c810 --- /dev/null +++ b/extern/opus/.gitattributes @@ -0,0 +1,10 @@ +.gitignore export-ignore +.gitattributes export-ignore + +update_version export-ignore + +*.bat eol=crlf +*.sln eol=crlf +*.vcxproj eol=crlf +*.vcxproj.filters eol=crlf +common.props eol=crlf diff --git a/extern/opus/.gitignore b/extern/opus/.gitignore new file mode 100644 index 0000000..31e2901 --- /dev/null +++ b/extern/opus/.gitignore @@ -0,0 +1,89 @@ +Doxyfile +Makefile +Makefile.in +TAGS +aclocal.m4 +autom4te.cache +*.kdevelop.pcs +*.kdevses +compile +config.guess +config.h +config.h.in +config.log +config.status +config.sub +configure +depcomp +INSTALL +install-sh +.deps +.libs +.dirstamp +*.a +*.exe +*.la +*-gnu.S +testcelt +libtool +ltmain.sh +missing +m4/libtool.m4 +m4/ltoptions.m4 +m4/ltsugar.m4 +m4/ltversion.m4 +m4/lt~obsolete.m4 +opus_compare +opus_demo +repacketizer_demo +stamp-h1 +test-driver +*.sw* +*.o +*.lo +*.pc +*.tar.gz +*~ +tests/*test +tests/test_opus_api +tests/test_opus_decode +tests/test_opus_encode +tests/test_opus_padding +tests/test_opus_projection +celt/arm/armopts.s +celt/dump_modes/dump_modes +celt/tests/test_unit_cwrs32 +celt/tests/test_unit_dft +celt/tests/test_unit_entropy +celt/tests/test_unit_laplace +celt/tests/test_unit_mathops +celt/tests/test_unit_mdct +celt/tests/test_unit_rotation +celt/tests/test_unit_types +doc/doxygen_sqlite3.db +doc/doxygen-build.stamp +doc/html +doc/latex +doc/man +package_version +version.h +celt/Debug +celt/Release +celt/x64 +silk/Debug +silk/Release +silk/x64 +silk/fixed/Debug +silk/fixed/Release +silk/fixed/x64 +silk/float/Debug +silk/float/Release +silk/float/x64 +silk/tests/test_unit_LPC_inv_pred_gain +src/Debug +src/Release +src/x64 +/*[Bb]uild*/ +.vs/ +.vscode/ +CMakeSettings.json diff --git a/extern/opus/.travis.yml b/extern/opus/.travis.yml new file mode 100644 index 0000000..821c813 --- /dev/null +++ b/extern/opus/.travis.yml @@ -0,0 +1,21 @@ +language: c + +compiler: + - gcc + - clang + +os: + - linux + - osx + +env: + - CONFIG="" + - CONFIG="--enable-assertions" + - CONFIG="--enable-fixed-point" + - CONFIG="--enable-fixed-point --disable-float-api" + - CONFIG="--enable-fixed-point --enable-assertions" + +script: + - ./autogen.sh + - ./configure $CONFIG + - make distcheck diff --git a/extern/opus/AUTHORS b/extern/opus/AUTHORS new file mode 100644 index 0000000..b3d22a2 --- /dev/null +++ b/extern/opus/AUTHORS @@ -0,0 +1,6 @@ +Jean-Marc Valin (jmvalin@jmvalin.ca) +Koen Vos (koenvos74@gmail.com) +Timothy Terriberry (tterribe@xiph.org) +Karsten Vandborg Sorensen (karsten.vandborg.sorensen@skype.net) +Soren Skak Jensen (ssjensen@gn.com) +Gregory Maxwell (greg@xiph.org) diff --git a/extern/opus/CMakeLists.txt b/extern/opus/CMakeLists.txt new file mode 100644 index 0000000..17ee3fc --- /dev/null +++ b/extern/opus/CMakeLists.txt @@ -0,0 +1,411 @@ +cmake_minimum_required(VERSION 3.1) + +include(opus_functions.cmake) + +get_library_version(OPUS_LIBRARY_VERSION OPUS_LIBRARY_VERSION_MAJOR) +message(STATUS "Opus library version: ${OPUS_LIBRARY_VERSION}") + +get_package_version(PACKAGE_VERSION) +message(STATUS "Opus package version: ${PACKAGE_VERSION}") + +string(REGEX + REPLACE "^([0-9]+.[0-9]+\\.?([0-9]+)?).*" + "\\1" + PROJECT_VERSION + ${PACKAGE_VERSION}) +message(STATUS "Opus project version: ${PROJECT_VERSION}") + +project(Opus LANGUAGES C VERSION ${PROJECT_VERSION}) +include(opus_buildtype.cmake) + +option(OPUS_STACK_PROTECTOR "Use stack protection" ON) +option(OPUS_USE_ALLOCA "Use alloca for stack arrays (on non-C99 compilers)" OFF) +option(OPUS_CUSTOM_MODES "Enable non-Opus modes, e.g. 44.1 kHz & 2^n frames" + OFF) +option(OPUS_BUILD_PROGRAMS "Build programs" OFF) +option(OPUS_FIXED_POINT + "Compile as fixed-point (for machines without a fast enough FPU)" OFF) +option(OPUS_ENABLE_FLOAT_API + "Compile with the floating point API (for machines with float library" + ON) +option(OPUS_INSTALL_PKG_CONFIG_MODULE "Install PkgConfig module" ON) +option(OPUS_INSTALL_CMAKE_CONFIG_MODULE "Install CMake package config module" + ON) + +include(opus_config.cmake) +include(opus_sources.cmake) +include(GNUInstallDirs) +include(CMakeDependentOption) +include(FeatureSummary) + +if(OPUS_STACK_PROTECTOR) + if(NOT MSVC) # GC on by default on MSVC + check_and_set_flag(STACK_PROTECTION_STRONG -fstack-protector-strong) + endif() +else() + if(MSVC) + check_and_set_flag(BUFFER_SECURITY_CHECK /GS-) + endif() +endif() + +if(OPUS_CPU_X86 OR OPUS_CPU_X64) + cmake_dependent_option(OPUS_X86_MAY_HAVE_SSE + "Does runtime check for SSE1 support" + ON + "SSE1_SUPPORTED" + OFF) + cmake_dependent_option(OPUS_X86_MAY_HAVE_SSE2 + "Does runtime check for SSE2 support" + ON + "SSE2_SUPPORTED" + OFF) + cmake_dependent_option(OPUS_X86_MAY_HAVE_SSE4_1 + "Does runtime check for SSE4.1 support" + ON + "SSE4_1_SUPPORTED" + OFF) + cmake_dependent_option(OPUS_X86_MAY_HAVE_AVX + "Does runtime check for AVX support" + ON + "AVX_SUPPORTED" + OFF) + + if(OPUS_CPU_X64) # Assume 64 bit has SSE2 support + cmake_dependent_option(OPUS_X86_PRESUME_SSE + "Assume target CPU has SSE1 support" + ON + "OPUS_X86_MAY_HAVE_SSE" + OFF) + cmake_dependent_option(OPUS_X86_PRESUME_SSE2 + "Assume target CPU has SSE2 support" + ON + "OPUS_X86_MAY_HAVE_SSE2" + OFF) + else() + cmake_dependent_option(OPUS_X86_PRESUME_SSE + "Assume target CPU has SSE1 support" + OFF + "OPUS_X86_MAY_HAVE_SSE" + OFF) + cmake_dependent_option(OPUS_X86_PRESUME_SSE2 + "Assume target CPU has SSE2 support" + OFF + "OPUS_X86_MAY_HAVE_SSE2" + OFF) + endif() + cmake_dependent_option(OPUS_X86_PRESUME_SSE4_1 + "Assume target CPU has SSE4.1 support" + OFF + "OPUS_X86_MAY_HAVE_SSE4_1" + OFF) + cmake_dependent_option(OPUS_X86_PRESUME_AVX + "Assume target CPU has AVX support" + OFF + "OPUS_X86_MAY_HAVE_AVX" + OFF) +endif() + +set_package_properties(Git + PROPERTIES + TYPE + REQUIRED + DESCRIPTION + "fast, scalable, distributed revision control system" + URL + "https://git-scm.com/" + PURPOSE + "required to set up package version") + +add_feature_info(STACK_PROTECTOR OPUS_STACK_PROTECTOR "Use stack protection") +add_feature_info(USE_ALLOCA OPUS_USE_ALLOCA + "Use alloca for stack arrays (on non-C99 compilers)") +add_feature_info(CUSTOM_MODES OPUS_CUSTOM_MODES + "Enable non-Opus modes, e.g. 44.1 kHz & 2^n frames") +add_feature_info(BUILD_PROGRAMS OPUS_BUILD_PROGRAMS "Build programs") +add_feature_info( + FIXED_POINT OPUS_FIXED_POINT + "compile as fixed-point (for machines without a fast enough FPU)") +add_feature_info( + FLOAT_API OPUS_ENABLE_FLOAT_API + "compile with the floating point API (for machines with float library)") + +add_feature_info(INSTALL_PKG_CONFIG_MODULE OPUS_INSTALL_PKG_CONFIG_MODULE + "install PkgConfig module") +add_feature_info(INSTALL_CMAKE_CONFIG_MODULE OPUS_INSTALL_CMAKE_CONFIG_MODULE + "install CMake package config module") + +if(OPUS_CPU_X86 OR OPUS_CPU_X64) + add_feature_info(X86_MAY_HAVE_SSE OPUS_X86_MAY_HAVE_SSE + "does runtime check for SSE1 support") + add_feature_info(X86_MAY_HAVE_SSE2 OPUS_X86_MAY_HAVE_SSE2 + "does runtime check for SSE2 support") + add_feature_info(X86_MAY_HAVE_SSE4_1 OPUS_X86_MAY_HAVE_SSE4_1 + "does runtime check for SSE4_1 support") + add_feature_info(X86_MAY_HAVE_AVX OPUS_X86_MAY_HAVE_AVX + "does runtime check for AVX support") + add_feature_info(X86_PRESUME_SSE OPUS_X86_PRESUME_SSE + "assume target CPU has SSE1 support") + add_feature_info(X86_PRESUME_SSE2 OPUS_X86_PRESUME_SSE2 + "assume target CPU has SSE2 support") + add_feature_info(X86_PRESUME_SSE4_1 OPUS_X86_PRESUME_SSE4_1 + "assume target CPU has SSE4_1 support") + add_feature_info(X86_PRESUME_AVX OPUS_X86_PRESUME_AVX + "assume target CPU has AVX support") +endif() + +feature_summary(WHAT ALL) + +add_library(opus ${opus_sources} ${opus_sources_float}) + +set(Opus_PUBLIC_HEADER + ${CMAKE_CURRENT_SOURCE_DIR}/include/opus.h + ${CMAKE_CURRENT_SOURCE_DIR}/include/opus_custom.h + ${CMAKE_CURRENT_SOURCE_DIR}/include/opus_defines.h + ${CMAKE_CURRENT_SOURCE_DIR}/include/opus_multistream.h + ${CMAKE_CURRENT_SOURCE_DIR}/include/opus_projection.h + ${CMAKE_CURRENT_SOURCE_DIR}/include/opus_types.h) + +set_target_properties(opus + PROPERTIES SOVERSION + ${OPUS_LIBRARY_VERSION_MAJOR} + VERSION + ${OPUS_LIBRARY_VERSION} + PUBLIC_HEADER + "${Opus_PUBLIC_HEADER}") + +target_include_directories( + opus + PUBLIC $ + $ + PRIVATE ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_CURRENT_SOURCE_DIR} + celt + silk) + +target_link_libraries(opus PRIVATE ${OPUS_REQUIRED_LIBRARIES}) +target_compile_definitions(opus PRIVATE OPUS_BUILD ENABLE_HARDENING) + +if(NOT MSVC) + target_compile_definitions(opus PRIVATE FORTIFY_SOURCE=2) +endif() + +# It is strongly recommended to uncomment one of these VAR_ARRAYS: Use C99 +# variable-length arrays for stack allocation USE_ALLOCA: Use alloca() for stack +# allocation If none is defined, then the fallback is a non-threadsafe global +# array +if(OPUS_USE_ALLOCA OR MSVC) + target_compile_definitions(opus PRIVATE USE_ALLOCA) +else() + target_compile_definitions(opus PRIVATE VAR_ARRAYS) +endif() + +if(OPUS_CUSTOM_MODES) + target_compile_definitions(opus PRIVATE CUSTOM_MODES) +endif() + +if(BUILD_SHARED_LIBS) + if(WIN32) + target_compile_definitions(opus PRIVATE DLL_EXPORT) + else() + include(CheckCCompilerFlag) + check_c_compiler_flag(-fvisibility=hidden COMPILER_HAS_HIDDEN_VISIBILITY) + if(COMPILER_HAS_HIDDEN_VISIBILITY) + set_target_properties(opus PROPERTIES C_VISIBILITY_PRESET hidden) + endif() + endif() +endif() + +add_sources_group(opus silk ${silk_sources}) +add_sources_group(opus celt ${celt_sources}) + +if(OPUS_FIXED_POINT) + add_sources_group(opus silk ${silk_sources_fixed}) + target_include_directories(opus PRIVATE silk/fixed) + target_compile_definitions(opus PRIVATE FIXED_POINT=1) +else() + add_sources_group(opus silk ${silk_sources_float}) + target_include_directories(opus PRIVATE silk/float) +endif() + +if(NOT OPUS_ENABLE_FLOAT_API) + target_compile_definitions(opus PRIVATE DISABLE_FLOAT_API) +endif() + +if(OPUS_X86_MAY_HAVE_SSE + OR OPUS_X86_MAY_HAVE_SSE2 + OR OPUS_X86_MAY_HAVE_SSE4_1 + OR OPUS_X86_MAY_HAVE_AVX) + target_compile_definitions(opus PRIVATE OPUS_HAVE_RTCD) +endif() + +if(OPUS_X86_MAY_HAVE_SSE) + add_sources_group(opus celt ${celt_sources_sse}) + target_compile_definitions(opus PRIVATE OPUS_X86_MAY_HAVE_SSE) +endif() +if(OPUS_X86_PRESUME_SSE) + target_compile_definitions(opus PRIVATE OPUS_X86_PRESUME_SSE) +endif() + +if(OPUS_X86_MAY_HAVE_SSE2) + add_sources_group(opus celt ${celt_sources_sse2}) + target_compile_definitions(opus PRIVATE OPUS_X86_MAY_HAVE_SSE2) +endif() +if(OPUS_X86_PRESUME_SSE2) + target_compile_definitions(opus PRIVATE OPUS_X86_PRESUME_SSE2) +endif() + +if(OPUS_X86_MAY_HAVE_SSE) + add_sources_group(opus celt ${celt_sources_sse4_1}) + add_sources_group(opus silk ${silk_sources_sse4_1}) + if(OPUS_FIXED_POINT) + add_sources_group(opus silk ${silk_sources_fixed_sse4_1}) + endif() + target_compile_definitions(opus PRIVATE OPUS_X86_MAY_HAVE_SSE4_1) +endif() +if(OPUS_X86_PRESUME_SSE4_1) + target_compile_definitions(opus PRIVATE OPUS_X86_PRESUME_SSE4_1) +endif() + +if(CMAKE_SYSTEM_PROCESSOR MATCHES "(armv7-a)") + add_sources_group(opus celt ${celt_sources_arm}) +endif() + +if(COMPILER_SUPPORT_NEON AND OPUS_USE_NEON) + + if(OPUS_MAY_HAVE_NEON) + if(RUNTIME_CPU_CAPABILITY_DETECTION) + message(STATUS "OPUS_MAY_HAVE_NEON enabling runtime detection") + target_compile_definitions(opus PRIVATE OPUS_HAVE_RTCD) + else() + message(ERROR "Runtime cpu capability detection needed for MAY_HAVE_NEON") + endif() + # Do runtime check for NEON + target_compile_definitions(opus + PRIVATE + OPUS_ARM_MAY_HAVE_NEON + OPUS_ARM_MAY_HAVE_NEON_INTR) + endif() + + add_sources_group(opus celt ${celt_sources_arm_neon_intr}) + add_sources_group(opus silk ${silk_sources_arm_neon_intr}) + + # silk arm neon depends on main_Fix.h + target_include_directories(opus PRIVATE silk/fixed) + + if(OPUS_FIXED_POINT) + add_sources_group(opus silk ${silk_sources_fixed_arm_neon_intr}) + endif() + + if(OPUS_PRESUME_NEON) + target_compile_definitions(opus + PRIVATE + OPUS_ARM_PRESUME_NEON + OPUS_ARM_PRESUME_NEON_INTR) + endif() +endif() + +install(TARGETS opus + EXPORT OpusTargets + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/opus) + +if(OPUS_INSTALL_PKG_CONFIG_MODULE) + set(prefix ${CMAKE_INSTALL_PREFIX}) + set(exec_prefix ${CMAKE_INSTALL_PREFIX}) + set(libdir ${CMAKE_INSTALL_FULL_LIBDIR}) + set(includedir ${CMAKE_INSTALL_FULL_INCLUDEDIR}) + set(VERSION ${OPUS_LIBRARY_VERSION}) + set(VERSION ${OPUS_LIBRARY_VERSION}) + if(HAVE_LIBM) + set(LIBM "-lm") + endif() + configure_file(opus.pc.in opus.pc) + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/opus.pc + DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) +endif() + +if(OPUS_INSTALL_CMAKE_CONFIG_MODULE) + set(CMAKE_INSTALL_PACKAGEDIR ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}) + install(EXPORT OpusTargets + NAMESPACE Opus:: + DESTINATION ${CMAKE_INSTALL_PACKAGEDIR}) + + include(CMakePackageConfigHelpers) + + set(INCLUDE_INSTALL_DIR ${CMAKE_INSTALL_INCLUDEDIR}) + configure_package_config_file(OpusConfig.cmake.in + OpusConfig.cmake + INSTALL_DESTINATION + ${CMAKE_INSTALL_PACKAGEDIR} + PATH_VARS + INCLUDE_INSTALL_DIR + INSTALL_PREFIX + ${CMAKE_INSTALL_PREFIX}) + write_basic_package_version_file(OpusConfigVersion.cmake + VERSION ${PROJECT_VERSION} + COMPATIBILITY SameMajorVersion) + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/OpusConfig.cmake + ${CMAKE_CURRENT_BINARY_DIR}/OpusConfigVersion.cmake + DESTINATION ${CMAKE_INSTALL_PACKAGEDIR}) +endif() + +if(OPUS_BUILD_PROGRAMS) + # demo + if(OPUS_CUSTOM_MODES) + add_executable(opus_custom_demo ${opus_custom_demo_sources}) + target_include_directories(opus_custom_demo + PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) + target_link_libraries(opus_custom_demo PRIVATE opus) + endif() + + add_executable(opus_demo ${opus_demo_sources}) + target_include_directories(opus_demo PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) + target_include_directories(opus_demo PRIVATE silk) # debug.h + target_include_directories(opus_demo PRIVATE celt) # arch.h + target_link_libraries(opus_demo PRIVATE opus) + + # compare + add_executable(opus_compare ${opus_compare_sources}) + target_include_directories(opus_compare PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) + target_link_libraries(opus_compare PRIVATE opus) +endif() + +if(BUILD_TESTING) + enable_testing() + + # tests + add_executable(test_opus_decode ${test_opus_decode_sources}) + target_include_directories(test_opus_decode + PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) + target_link_libraries(test_opus_decode PRIVATE opus) + if(OPUS_FIXED_POINT) + target_compile_definitions(test_opus_decode PRIVATE DISABLE_FLOAT_API) + endif() + add_test(test_opus_decode test_opus_decode) + + add_executable(test_opus_padding ${test_opus_padding_sources}) + target_include_directories(test_opus_padding + PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) + target_link_libraries(test_opus_padding PRIVATE opus) + add_test(test_opus_padding test_opus_padding) + + if(NOT BUILD_SHARED_LIBS) + # disable tests that depends on private API when building shared lib + add_executable(test_opus_api ${test_opus_api_sources}) + target_include_directories(test_opus_api + PRIVATE ${CMAKE_CURRENT_BINARY_DIR} celt) + target_link_libraries(test_opus_api PRIVATE opus) + if(OPUS_FIXED_POINT) + target_compile_definitions(test_opus_api PRIVATE DISABLE_FLOAT_API) + endif() + add_test(test_opus_api test_opus_api) + + add_executable(test_opus_encode ${test_opus_encode_sources}) + target_include_directories(test_opus_encode + PRIVATE ${CMAKE_CURRENT_BINARY_DIR} celt) + target_link_libraries(test_opus_encode PRIVATE opus) + add_test(test_opus_encode test_opus_encode) + endif() +endif() diff --git a/extern/opus/COPYING b/extern/opus/COPYING new file mode 100644 index 0000000..9c739c3 --- /dev/null +++ b/extern/opus/COPYING @@ -0,0 +1,44 @@ +Copyright 2001-2011 Xiph.Org, Skype Limited, Octasic, + Jean-Marc Valin, Timothy B. Terriberry, + CSIRO, Gregory Maxwell, Mark Borgerding, + Erik de Castro Lopo + +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 OWNER +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. + +Opus is subject to the royalty-free patent licenses which are +specified at: + +Xiph.Org Foundation: +https://datatracker.ietf.org/ipr/1524/ + +Microsoft Corporation: +https://datatracker.ietf.org/ipr/1914/ + +Broadcom Corporation: +https://datatracker.ietf.org/ipr/1526/ diff --git a/extern/opus/ChangeLog b/extern/opus/ChangeLog new file mode 100644 index 0000000..e69de29 diff --git a/extern/opus/LICENSE_PLEASE_READ.txt b/extern/opus/LICENSE_PLEASE_READ.txt new file mode 100644 index 0000000..bc88efa --- /dev/null +++ b/extern/opus/LICENSE_PLEASE_READ.txt @@ -0,0 +1,22 @@ +Contributions to the collaboration shall not be considered confidential. + +Each contributor represents and warrants that it has the right and +authority to license copyright in its contributions to the collaboration. + +Each contributor agrees to license the copyright in the contributions +under the Modified (2-clause or 3-clause) BSD License or the Clear BSD License. + +Please see the IPR statements submitted to the IETF for the complete +patent licensing details: + +Xiph.Org Foundation: +https://datatracker.ietf.org/ipr/1524/ + +Microsoft Corporation: +https://datatracker.ietf.org/ipr/1914/ + +Skype Limited: +https://datatracker.ietf.org/ipr/1602/ + +Broadcom Corporation: +https://datatracker.ietf.org/ipr/1526/ diff --git a/extern/opus/Makefile.am b/extern/opus/Makefile.am new file mode 100644 index 0000000..4e3f183 --- /dev/null +++ b/extern/opus/Makefile.am @@ -0,0 +1,351 @@ +# Provide the full test output for failed tests when using the parallel +# test suite (which is enabled by default with automake 1.13+). +export VERBOSE = yes + +AUTOMAKE_OPTIONS = subdir-objects +ACLOCAL_AMFLAGS = -I m4 + +lib_LTLIBRARIES = libopus.la + +DIST_SUBDIRS = doc + +AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/celt -I$(top_srcdir)/silk \ + -I$(top_srcdir)/silk/float -I$(top_srcdir)/silk/fixed $(NE10_CFLAGS) + +include celt_sources.mk +include silk_sources.mk +include opus_sources.mk + +if FIXED_POINT +SILK_SOURCES += $(SILK_SOURCES_FIXED) +if HAVE_SSE4_1 +SILK_SOURCES += $(SILK_SOURCES_SSE4_1) $(SILK_SOURCES_FIXED_SSE4_1) +endif +if HAVE_ARM_NEON_INTR +SILK_SOURCES += $(SILK_SOURCES_FIXED_ARM_NEON_INTR) +endif +else +SILK_SOURCES += $(SILK_SOURCES_FLOAT) +if HAVE_SSE4_1 +SILK_SOURCES += $(SILK_SOURCES_SSE4_1) +endif +endif + +if DISABLE_FLOAT_API +else +OPUS_SOURCES += $(OPUS_SOURCES_FLOAT) +endif + +if HAVE_SSE +CELT_SOURCES += $(CELT_SOURCES_SSE) +endif +if HAVE_SSE2 +CELT_SOURCES += $(CELT_SOURCES_SSE2) +endif +if HAVE_SSE4_1 +CELT_SOURCES += $(CELT_SOURCES_SSE4_1) +endif + +if CPU_ARM +CELT_SOURCES += $(CELT_SOURCES_ARM) +SILK_SOURCES += $(SILK_SOURCES_ARM) + +if HAVE_ARM_NEON_INTR +CELT_SOURCES += $(CELT_SOURCES_ARM_NEON_INTR) +SILK_SOURCES += $(SILK_SOURCES_ARM_NEON_INTR) +endif + +if HAVE_ARM_NE10 +CELT_SOURCES += $(CELT_SOURCES_ARM_NE10) +endif + +if OPUS_ARM_EXTERNAL_ASM +noinst_LTLIBRARIES = libarmasm.la +libarmasm_la_SOURCES = $(CELT_SOURCES_ARM_ASM:.s=-gnu.S) +BUILT_SOURCES = $(CELT_SOURCES_ARM_ASM:.s=-gnu.S) \ + $(CELT_AM_SOURCES_ARM_ASM:.s.in=.s) \ + $(CELT_AM_SOURCES_ARM_ASM:.s.in=-gnu.S) +endif +endif + +CLEANFILES = $(CELT_SOURCES_ARM_ASM:.s=-gnu.S) \ + $(CELT_AM_SOURCES_ARM_ASM:.s.in=-gnu.S) + +include celt_headers.mk +include silk_headers.mk +include opus_headers.mk + +libopus_la_SOURCES = $(CELT_SOURCES) $(SILK_SOURCES) $(OPUS_SOURCES) +libopus_la_LDFLAGS = -no-undefined -version-info @OPUS_LT_CURRENT@:@OPUS_LT_REVISION@:@OPUS_LT_AGE@ +libopus_la_LIBADD = $(NE10_LIBS) $(LIBM) +if OPUS_ARM_EXTERNAL_ASM +libopus_la_LIBADD += libarmasm.la +endif + +pkginclude_HEADERS = include/opus.h include/opus_multistream.h include/opus_types.h include/opus_defines.h include/opus_projection.h + +noinst_HEADERS = $(OPUS_HEAD) $(SILK_HEAD) $(CELT_HEAD) + +if EXTRA_PROGRAMS +noinst_PROGRAMS = celt/tests/test_unit_cwrs32 \ + celt/tests/test_unit_dft \ + celt/tests/test_unit_entropy \ + celt/tests/test_unit_laplace \ + celt/tests/test_unit_mathops \ + celt/tests/test_unit_mdct \ + celt/tests/test_unit_rotation \ + celt/tests/test_unit_types \ + opus_compare \ + opus_demo \ + repacketizer_demo \ + silk/tests/test_unit_LPC_inv_pred_gain \ + tests/test_opus_api \ + tests/test_opus_decode \ + tests/test_opus_encode \ + tests/test_opus_padding \ + tests/test_opus_projection + +TESTS = celt/tests/test_unit_cwrs32 \ + celt/tests/test_unit_dft \ + celt/tests/test_unit_entropy \ + celt/tests/test_unit_laplace \ + celt/tests/test_unit_mathops \ + celt/tests/test_unit_mdct \ + celt/tests/test_unit_rotation \ + celt/tests/test_unit_types \ + silk/tests/test_unit_LPC_inv_pred_gain \ + tests/test_opus_api \ + tests/test_opus_decode \ + tests/test_opus_encode \ + tests/test_opus_padding \ + tests/test_opus_projection + +opus_demo_SOURCES = src/opus_demo.c + +opus_demo_LDADD = libopus.la $(NE10_LIBS) $(LIBM) + +repacketizer_demo_SOURCES = src/repacketizer_demo.c + +repacketizer_demo_LDADD = libopus.la $(NE10_LIBS) $(LIBM) + +opus_compare_SOURCES = src/opus_compare.c +opus_compare_LDADD = $(LIBM) + +tests_test_opus_api_SOURCES = tests/test_opus_api.c tests/test_opus_common.h +tests_test_opus_api_LDADD = libopus.la $(NE10_LIBS) $(LIBM) + +tests_test_opus_encode_SOURCES = tests/test_opus_encode.c tests/opus_encode_regressions.c tests/test_opus_common.h +tests_test_opus_encode_LDADD = libopus.la $(NE10_LIBS) $(LIBM) + +tests_test_opus_decode_SOURCES = tests/test_opus_decode.c tests/test_opus_common.h +tests_test_opus_decode_LDADD = libopus.la $(NE10_LIBS) $(LIBM) + +tests_test_opus_padding_SOURCES = tests/test_opus_padding.c tests/test_opus_common.h +tests_test_opus_padding_LDADD = libopus.la $(NE10_LIBS) $(LIBM) + +CELT_OBJ = $(CELT_SOURCES:.c=.lo) +SILK_OBJ = $(SILK_SOURCES:.c=.lo) +OPUS_OBJ = $(OPUS_SOURCES:.c=.lo) + +tests_test_opus_projection_SOURCES = tests/test_opus_projection.c tests/test_opus_common.h +tests_test_opus_projection_LDADD = $(OPUS_OBJ) $(SILK_OBJ) $(CELT_OBJ) $(NE10_LIBS) $(LIBM) +if OPUS_ARM_EXTERNAL_ASM +tests_test_opus_projection_LDADD += libarmasm.la +endif + +silk_tests_test_unit_LPC_inv_pred_gain_SOURCES = silk/tests/test_unit_LPC_inv_pred_gain.c +silk_tests_test_unit_LPC_inv_pred_gain_LDADD = $(SILK_OBJ) $(CELT_OBJ) $(NE10_LIBS) $(LIBM) +if OPUS_ARM_EXTERNAL_ASM +silk_tests_test_unit_LPC_inv_pred_gain_LDADD += libarmasm.la +endif + +celt_tests_test_unit_cwrs32_SOURCES = celt/tests/test_unit_cwrs32.c +celt_tests_test_unit_cwrs32_LDADD = $(LIBM) + +celt_tests_test_unit_dft_SOURCES = celt/tests/test_unit_dft.c +celt_tests_test_unit_dft_LDADD = $(CELT_OBJ) $(NE10_LIBS) $(LIBM) +if OPUS_ARM_EXTERNAL_ASM +celt_tests_test_unit_dft_LDADD += libarmasm.la +endif + +celt_tests_test_unit_entropy_SOURCES = celt/tests/test_unit_entropy.c +celt_tests_test_unit_entropy_LDADD = $(LIBM) + +celt_tests_test_unit_laplace_SOURCES = celt/tests/test_unit_laplace.c +celt_tests_test_unit_laplace_LDADD = $(LIBM) + +celt_tests_test_unit_mathops_SOURCES = celt/tests/test_unit_mathops.c +celt_tests_test_unit_mathops_LDADD = $(CELT_OBJ) $(NE10_LIBS) $(LIBM) +if OPUS_ARM_EXTERNAL_ASM +celt_tests_test_unit_mathops_LDADD += libarmasm.la +endif + +celt_tests_test_unit_mdct_SOURCES = celt/tests/test_unit_mdct.c +celt_tests_test_unit_mdct_LDADD = $(CELT_OBJ) $(NE10_LIBS) $(LIBM) +if OPUS_ARM_EXTERNAL_ASM +celt_tests_test_unit_mdct_LDADD += libarmasm.la +endif + +celt_tests_test_unit_rotation_SOURCES = celt/tests/test_unit_rotation.c +celt_tests_test_unit_rotation_LDADD = $(CELT_OBJ) $(NE10_LIBS) $(LIBM) +if OPUS_ARM_EXTERNAL_ASM +celt_tests_test_unit_rotation_LDADD += libarmasm.la +endif + +celt_tests_test_unit_types_SOURCES = celt/tests/test_unit_types.c +celt_tests_test_unit_types_LDADD = $(LIBM) +endif + +if CUSTOM_MODES +pkginclude_HEADERS += include/opus_custom.h +if EXTRA_PROGRAMS +noinst_PROGRAMS += opus_custom_demo +opus_custom_demo_SOURCES = celt/opus_custom_demo.c +opus_custom_demo_LDADD = libopus.la $(LIBM) +endif +endif + +EXTRA_DIST = opus.pc.in \ + opus-uninstalled.pc.in \ + opus.m4 \ + Makefile.mips \ + Makefile.unix \ + CMakeLists.txt \ + config.h.cmake.in \ + opus_config.cmake \ + opus_functions.cmake \ + opus_sources.cmake \ + OpusConfig.cmake.in \ + tests/run_vectors.sh \ + celt/arm/arm2gnu.pl \ + celt/arm/celt_pitch_xcorr_arm.s \ + win32/VS2015/opus.vcxproj \ + win32/VS2015/test_opus_encode.vcxproj.filters \ + win32/VS2015/test_opus_encode.vcxproj \ + win32/VS2015/opus_demo.vcxproj \ + win32/VS2015/test_opus_api.vcxproj.filters \ + win32/VS2015/test_opus_api.vcxproj \ + win32/VS2015/test_opus_decode.vcxproj.filters \ + win32/VS2015/opus_demo.vcxproj.filters \ + win32/VS2015/opus.vcxproj.filters \ + win32/VS2015/test_opus_decode.vcxproj \ + win32/VS2015/opus.sln \ + win32/VS2015/common.props \ + win32/genversion.bat \ + win32/config.h + +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = opus.pc + +m4datadir = $(datadir)/aclocal +m4data_DATA = opus.m4 + +# Targets to build and install just the library without the docs +opus check-opus install-opus: export NO_DOXYGEN = 1 + +opus: all +check-opus: check +install-opus: install + + +# Or just the docs +docs: + ( cd doc && $(MAKE) $(AM_MAKEFLAGS) ) + +install-docs: + ( cd doc && $(MAKE) $(AM_MAKEFLAGS) install ) + + +# Or everything (by default) +all-local: + @[ -n "$(NO_DOXYGEN)" ] || ( cd doc && $(MAKE) $(AM_MAKEFLAGS) ) + +install-data-local: + @[ -n "$(NO_DOXYGEN)" ] || ( cd doc && $(MAKE) $(AM_MAKEFLAGS) install ) + +clean-local: + -( cd doc && $(MAKE) $(AM_MAKEFLAGS) clean ) + +uninstall-local: + ( cd doc && $(MAKE) $(AM_MAKEFLAGS) uninstall ) + + +# We check this every time make is run, with configure.ac being touched to +# trigger an update of the build system files if update_version changes the +# current PACKAGE_VERSION (or if package_version was modified manually by a +# user with either AUTO_UPDATE=no or no update_version script present - the +# latter being the normal case for tarball releases). +# +# We can't just add the package_version file to CONFIGURE_DEPENDENCIES since +# simply running autoconf will not actually regenerate configure for us when +# the content of that file changes (due to autoconf dependency checking not +# knowing about that without us creating yet another file for it to include). +# +# The MAKECMDGOALS check is a gnu-make'ism, but will degrade 'gracefully' for +# makes that don't support it. The only loss of functionality is not forcing +# an update of package_version for `make dist` if AUTO_UPDATE=no, but that is +# unlikely to be a real problem for any real user. +$(top_srcdir)/configure.ac: force + @case "$(MAKECMDGOALS)" in \ + dist-hook) exit 0 ;; \ + dist-* | dist | distcheck | distclean) _arg=release ;; \ + esac; \ + if ! $(top_srcdir)/update_version $$_arg 2> /dev/null; then \ + if [ ! -e $(top_srcdir)/package_version ]; then \ + echo 'PACKAGE_VERSION="unknown"' > $(top_srcdir)/package_version; \ + fi; \ + . $(top_srcdir)/package_version || exit 1; \ + [ "$(PACKAGE_VERSION)" != "$$PACKAGE_VERSION" ] || exit 0; \ + fi; \ + touch $@ + +force: + +# Create a minimal package_version file when make dist is run. +dist-hook: + echo 'PACKAGE_VERSION="$(PACKAGE_VERSION)"' > $(top_distdir)/package_version + + +.PHONY: opus check-opus install-opus docs install-docs + +# automake doesn't do dependency tracking for asm files, that I can tell +$(CELT_SOURCES_ARM_ASM:%.s=%-gnu.S): celt/arm/armopts-gnu.S +$(CELT_SOURCES_ARM_ASM:%.s=%-gnu.S): $(top_srcdir)/celt/arm/arm2gnu.pl + +# convert ARM asm to GNU as format +%-gnu.S: $(top_srcdir)/%.s + $(top_srcdir)/celt/arm/arm2gnu.pl @ARM2GNU_PARAMS@ < $< > $@ +# For autoconf-modified sources (e.g., armopts.s) +%-gnu.S: %.s + $(top_srcdir)/celt/arm/arm2gnu.pl @ARM2GNU_PARAMS@ < $< > $@ + +OPT_UNIT_TEST_OBJ = $(celt_tests_test_unit_mathops_SOURCES:.c=.o) \ + $(celt_tests_test_unit_rotation_SOURCES:.c=.o) \ + $(celt_tests_test_unit_mdct_SOURCES:.c=.o) \ + $(celt_tests_test_unit_dft_SOURCES:.c=.o) \ + $(silk_tests_test_unit_LPC_inv_pred_gain_SOURCES:.c=.o) + +if HAVE_SSE +SSE_OBJ = $(CELT_SOURCES_SSE:.c=.lo) +$(SSE_OBJ): CFLAGS += $(OPUS_X86_SSE_CFLAGS) +endif + +if HAVE_SSE2 +SSE2_OBJ = $(CELT_SOURCES_SSE2:.c=.lo) +$(SSE2_OBJ): CFLAGS += $(OPUS_X86_SSE2_CFLAGS) +endif + +if HAVE_SSE4_1 +SSE4_1_OBJ = $(CELT_SOURCES_SSE4_1:.c=.lo) \ + $(SILK_SOURCES_SSE4_1:.c=.lo) \ + $(SILK_SOURCES_FIXED_SSE4_1:.c=.lo) +$(SSE4_1_OBJ): CFLAGS += $(OPUS_X86_SSE4_1_CFLAGS) +endif + +if HAVE_ARM_NEON_INTR +ARM_NEON_INTR_OBJ = $(CELT_SOURCES_ARM_NEON_INTR:.c=.lo) \ + $(SILK_SOURCES_ARM_NEON_INTR:.c=.lo) \ + $(SILK_SOURCES_FIXED_ARM_NEON_INTR:.c=.lo) +$(ARM_NEON_INTR_OBJ): CFLAGS += \ + $(OPUS_ARM_NEON_INTR_CFLAGS) $(NE10_CFLAGS) +endif diff --git a/extern/opus/Makefile.mips b/extern/opus/Makefile.mips new file mode 100644 index 0000000..e9bfc22 --- /dev/null +++ b/extern/opus/Makefile.mips @@ -0,0 +1,161 @@ +#################### COMPILE OPTIONS ####################### + +# Uncomment this for fixed-point build +FIXED_POINT=1 + +# It is strongly recommended to uncomment one of these +# VAR_ARRAYS: Use C99 variable-length arrays for stack allocation +# USE_ALLOCA: Use alloca() for stack allocation +# If none is defined, then the fallback is a non-threadsafe global array +CFLAGS := -DUSE_ALLOCA $(CFLAGS) +#CFLAGS := -DVAR_ARRAYS $(CFLAGS) + +# These options affect performance +# HAVE_LRINTF: Use C99 intrinsics to speed up float-to-int conversion +CFLAGS := -DHAVE_LRINTF $(CFLAGS) + +###################### END OF OPTIONS ###################### + +-include package_version + +include silk_sources.mk +include celt_sources.mk +include opus_sources.mk + +ifdef FIXED_POINT +SILK_SOURCES += $(SILK_SOURCES_FIXED) +else +SILK_SOURCES += $(SILK_SOURCES_FLOAT) +OPUS_SOURCES += $(OPUS_SOURCES_FLOAT) +endif + +EXESUFFIX = +LIBPREFIX = lib +LIBSUFFIX = .a +OBJSUFFIX = .o + +CC = $(TOOLCHAIN_PREFIX)cc$(TOOLCHAIN_SUFFIX) +AR = $(TOOLCHAIN_PREFIX)ar +RANLIB = $(TOOLCHAIN_PREFIX)ranlib +CP = $(TOOLCHAIN_PREFIX)cp + +cppflags-from-defines = $(addprefix -D,$(1)) +cppflags-from-includes = $(addprefix -I,$(1)) +ldflags-from-ldlibdirs = $(addprefix -L,$(1)) +ldlibs-from-libs = $(addprefix -l,$(1)) + +WARNINGS = -Wall -W -Wstrict-prototypes -Wextra -Wcast-align -Wnested-externs -Wshadow + +CFLAGS += -mips32r2 -mno-mips16 -std=gnu99 -O2 -g $(WARNINGS) -DENABLE_ASSERTIONS -DMIPSr1_ASM -DOPUS_BUILD -mdspr2 -march=74kc -mtune=74kc -mmt -mgp32 + +CINCLUDES = include silk celt + +ifdef FIXED_POINT +CFLAGS += -DFIXED_POINT=1 -DDISABLE_FLOAT_API +CINCLUDES += silk/fixed +else +CINCLUDES += silk/float +endif + + +LIBS = m + +LDLIBDIRS = ./ + +CFLAGS += $(call cppflags-from-defines,$(CDEFINES)) +CFLAGS += $(call cppflags-from-includes,$(CINCLUDES)) +LDFLAGS += $(call ldflags-from-ldlibdirs,$(LDLIBDIRS)) +LDLIBS += $(call ldlibs-from-libs,$(LIBS)) + +COMPILE.c.cmdline = $(CC) -c $(CFLAGS) -o $@ $< +LINK.o = $(CC) $(LDPREFLAGS) $(LDFLAGS) +LINK.o.cmdline = $(LINK.o) $^ $(LDLIBS) -o $@$(EXESUFFIX) + +ARCHIVE.cmdline = $(AR) $(ARFLAGS) $@ $^ && $(RANLIB) $@ + +%$(OBJSUFFIX):%.c + $(COMPILE.c.cmdline) + +%$(OBJSUFFIX):%.cpp + $(COMPILE.cpp.cmdline) + +# Directives + + +# Variable definitions +LIB_NAME = opus +TARGET = $(LIBPREFIX)$(LIB_NAME)$(LIBSUFFIX) + +SRCS_C = $(SILK_SOURCES) $(CELT_SOURCES) $(OPUS_SOURCES) + +OBJS := $(patsubst %.c,%$(OBJSUFFIX),$(SRCS_C)) + +OPUSDEMO_SRCS_C = src/opus_demo.c +OPUSDEMO_OBJS := $(patsubst %.c,%$(OBJSUFFIX),$(OPUSDEMO_SRCS_C)) + +TESTOPUSAPI_SRCS_C = tests/test_opus_api.c +TESTOPUSAPI_OBJS := $(patsubst %.c,%$(OBJSUFFIX),$(TESTOPUSAPI_SRCS_C)) + +TESTOPUSDECODE_SRCS_C = tests/test_opus_decode.c +TESTOPUSDECODE_OBJS := $(patsubst %.c,%$(OBJSUFFIX),$(TESTOPUSDECODE_SRCS_C)) + +TESTOPUSENCODE_SRCS_C = tests/test_opus_encode.c tests/opus_encode_regressions.c +TESTOPUSENCODE_OBJS := $(patsubst %.c,%$(OBJSUFFIX),$(TESTOPUSENCODE_SRCS_C)) + +TESTOPUSPADDING_SRCS_C = tests/test_opus_padding.c +TESTOPUSPADDING_OBJS := $(patsubst %.c,%$(OBJSUFFIX),$(TESTOPUSPADDING_SRCS_C)) + +OPUSCOMPARE_SRCS_C = src/opus_compare.c +OPUSCOMPARE_OBJS := $(patsubst %.c,%$(OBJSUFFIX),$(OPUSCOMPARE_SRCS_C)) + +TESTS := test_opus_api test_opus_decode test_opus_encode test_opus_padding + +# Rules +all: lib opus_demo opus_compare $(TESTS) + +lib: $(TARGET) + +check: all + for test in $(TESTS); do ./$$test; done + +$(TARGET): $(OBJS) + $(ARCHIVE.cmdline) + +opus_demo$(EXESUFFIX): $(OPUSDEMO_OBJS) $(TARGET) + $(LINK.o.cmdline) + +test_opus_api$(EXESUFFIX): $(TESTOPUSAPI_OBJS) $(TARGET) + $(LINK.o.cmdline) + +test_opus_decode$(EXESUFFIX): $(TESTOPUSDECODE_OBJS) $(TARGET) + $(LINK.o.cmdline) + +test_opus_encode$(EXESUFFIX): $(TESTOPUSENCODE_OBJS) $(TARGET) + $(LINK.o.cmdline) + +test_opus_padding$(EXESUFFIX): $(TESTOPUSPADDING_OBJS) $(TARGET) + $(LINK.o.cmdline) + +opus_compare$(EXESUFFIX): $(OPUSCOMPARE_OBJS) + $(LINK.o.cmdline) + +celt/celt.o: CFLAGS += -DPACKAGE_VERSION='$(PACKAGE_VERSION)' +celt/celt.o: package_version + +package_version: force + @if [ -x ./update_version ]; then \ + ./update_version || true; \ + elif [ ! -e ./package_version ]; then \ + echo 'PACKAGE_VERSION="unknown"' > ./package_version; \ + fi + +force: + +clean: + rm -f opus_demo$(EXESUFFIX) opus_compare$(EXESUFFIX) $(TARGET) \ + test_opus_api$(EXESUFFIX) test_opus_decode$(EXESUFFIX) \ + test_opus_encode$(EXESUFFIX) test_opus_padding$(EXESUFFIX) \ + $(OBJS) $(OPUSDEMO_OBJS) $(OPUSCOMPARE_OBJS) $(TESTOPUSAPI_OBJS) \ + $(TESTOPUSDECODE_OBJS) $(TESTOPUSENCODE_OBJS) $(TESTOPUSPADDING_OBJS) + +.PHONY: all lib clean force check diff --git a/extern/opus/Makefile.unix b/extern/opus/Makefile.unix new file mode 100644 index 0000000..90a48f0 --- /dev/null +++ b/extern/opus/Makefile.unix @@ -0,0 +1,159 @@ +#################### COMPILE OPTIONS ####################### + +# Uncomment this for fixed-point build +#FIXED_POINT=1 + +# It is strongly recommended to uncomment one of these +# VAR_ARRAYS: Use C99 variable-length arrays for stack allocation +# USE_ALLOCA: Use alloca() for stack allocation +# If none is defined, then the fallback is a non-threadsafe global array +CFLAGS := -DUSE_ALLOCA $(CFLAGS) +#CFLAGS := -DVAR_ARRAYS $(CFLAGS) + +# These options affect performance +# HAVE_LRINTF: Use C99 intrinsics to speed up float-to-int conversion +#CFLAGS := -DHAVE_LRINTF $(CFLAGS) + +###################### END OF OPTIONS ###################### + +-include package_version + +include silk_sources.mk +include celt_sources.mk +include opus_sources.mk + +ifdef FIXED_POINT +SILK_SOURCES += $(SILK_SOURCES_FIXED) +else +SILK_SOURCES += $(SILK_SOURCES_FLOAT) +OPUS_SOURCES += $(OPUS_SOURCES_FLOAT) +endif + +EXESUFFIX = +LIBPREFIX = lib +LIBSUFFIX = .a +OBJSUFFIX = .o + +CC = $(TOOLCHAIN_PREFIX)cc$(TOOLCHAIN_SUFFIX) +AR = $(TOOLCHAIN_PREFIX)ar +RANLIB = $(TOOLCHAIN_PREFIX)ranlib +CP = $(TOOLCHAIN_PREFIX)cp + +cppflags-from-defines = $(addprefix -D,$(1)) +cppflags-from-includes = $(addprefix -I,$(1)) +ldflags-from-ldlibdirs = $(addprefix -L,$(1)) +ldlibs-from-libs = $(addprefix -l,$(1)) + +WARNINGS = -Wall -W -Wstrict-prototypes -Wextra -Wcast-align -Wnested-externs -Wshadow +CFLAGS += -O2 -g $(WARNINGS) -DOPUS_BUILD +CINCLUDES = include silk celt + +ifdef FIXED_POINT +CFLAGS += -DFIXED_POINT=1 -DDISABLE_FLOAT_API +CINCLUDES += silk/fixed +else +CINCLUDES += silk/float +endif + + +LIBS = m + +LDLIBDIRS = ./ + +CFLAGS += $(call cppflags-from-defines,$(CDEFINES)) +CFLAGS += $(call cppflags-from-includes,$(CINCLUDES)) +LDFLAGS += $(call ldflags-from-ldlibdirs,$(LDLIBDIRS)) +LDLIBS += $(call ldlibs-from-libs,$(LIBS)) + +COMPILE.c.cmdline = $(CC) -c $(CFLAGS) -o $@ $< +LINK.o = $(CC) $(LDPREFLAGS) $(LDFLAGS) +LINK.o.cmdline = $(LINK.o) $^ $(LDLIBS) -o $@$(EXESUFFIX) + +ARCHIVE.cmdline = $(AR) $(ARFLAGS) $@ $^ && $(RANLIB) $@ + +%$(OBJSUFFIX):%.c + $(COMPILE.c.cmdline) + +%$(OBJSUFFIX):%.cpp + $(COMPILE.cpp.cmdline) + +# Directives + + +# Variable definitions +LIB_NAME = opus +TARGET = $(LIBPREFIX)$(LIB_NAME)$(LIBSUFFIX) + +SRCS_C = $(SILK_SOURCES) $(CELT_SOURCES) $(OPUS_SOURCES) + +OBJS := $(patsubst %.c,%$(OBJSUFFIX),$(SRCS_C)) + +OPUSDEMO_SRCS_C = src/opus_demo.c +OPUSDEMO_OBJS := $(patsubst %.c,%$(OBJSUFFIX),$(OPUSDEMO_SRCS_C)) + +TESTOPUSAPI_SRCS_C = tests/test_opus_api.c +TESTOPUSAPI_OBJS := $(patsubst %.c,%$(OBJSUFFIX),$(TESTOPUSAPI_SRCS_C)) + +TESTOPUSDECODE_SRCS_C = tests/test_opus_decode.c +TESTOPUSDECODE_OBJS := $(patsubst %.c,%$(OBJSUFFIX),$(TESTOPUSDECODE_SRCS_C)) + +TESTOPUSENCODE_SRCS_C = tests/test_opus_encode.c tests/opus_encode_regressions.c +TESTOPUSENCODE_OBJS := $(patsubst %.c,%$(OBJSUFFIX),$(TESTOPUSENCODE_SRCS_C)) + +TESTOPUSPADDING_SRCS_C = tests/test_opus_padding.c +TESTOPUSPADDING_OBJS := $(patsubst %.c,%$(OBJSUFFIX),$(TESTOPUSPADDING_SRCS_C)) + +OPUSCOMPARE_SRCS_C = src/opus_compare.c +OPUSCOMPARE_OBJS := $(patsubst %.c,%$(OBJSUFFIX),$(OPUSCOMPARE_SRCS_C)) + +TESTS := test_opus_api test_opus_decode test_opus_encode test_opus_padding + +# Rules +all: lib opus_demo opus_compare $(TESTS) + +lib: $(TARGET) + +check: all + for test in $(TESTS); do ./$$test; done + +$(TARGET): $(OBJS) + $(ARCHIVE.cmdline) + +opus_demo$(EXESUFFIX): $(OPUSDEMO_OBJS) $(TARGET) + $(LINK.o.cmdline) + +test_opus_api$(EXESUFFIX): $(TESTOPUSAPI_OBJS) $(TARGET) + $(LINK.o.cmdline) + +test_opus_decode$(EXESUFFIX): $(TESTOPUSDECODE_OBJS) $(TARGET) + $(LINK.o.cmdline) + +test_opus_encode$(EXESUFFIX): $(TESTOPUSENCODE_OBJS) $(TARGET) + $(LINK.o.cmdline) + +test_opus_padding$(EXESUFFIX): $(TESTOPUSPADDING_OBJS) $(TARGET) + $(LINK.o.cmdline) + +opus_compare$(EXESUFFIX): $(OPUSCOMPARE_OBJS) + $(LINK.o.cmdline) + +celt/celt.o: CFLAGS += -DPACKAGE_VERSION='$(PACKAGE_VERSION)' +celt/celt.o: package_version + +package_version: force + @if [ -x ./update_version ]; then \ + ./update_version || true; \ + elif [ ! -e ./package_version ]; then \ + echo 'PACKAGE_VERSION="unknown"' > ./package_version; \ + fi + +force: + +clean: + rm -f opus_demo$(EXESUFFIX) opus_compare$(EXESUFFIX) $(TARGET) \ + test_opus_api$(EXESUFFIX) test_opus_decode$(EXESUFFIX) \ + test_opus_encode$(EXESUFFIX) test_opus_padding$(EXESUFFIX) \ + $(OBJS) $(OPUSDEMO_OBJS) $(OPUSCOMPARE_OBJS) $(TESTOPUSAPI_OBJS) \ + $(TESTOPUSDECODE_OBJS) $(TESTOPUSENCODE_OBJS) $(TESTOPUSPADDING_OBJS) + +.PHONY: all lib clean force check diff --git a/extern/opus/NEWS b/extern/opus/NEWS new file mode 100644 index 0000000..e69de29 diff --git a/extern/opus/OpusConfig.cmake.in b/extern/opus/OpusConfig.cmake.in new file mode 100644 index 0000000..1577174 --- /dev/null +++ b/extern/opus/OpusConfig.cmake.in @@ -0,0 +1,19 @@ +set(OPUS_VERSION @PROJECT_VERSION@) +set(OPUS_VERSION_STRING @PROJECT_VERSION@) +set(OPUS_VERSION_MAJOR @PROJECT_VERSION_MAJOR@) +set(OPUS_VERSION_MINOR @PROJECT_VERSION_MINOR@) +set(OPUS_VERSION_PATCH @PROJECT_VERSION_PATCH@) + +@PACKAGE_INIT@ + +set_and_check(OPUS_INCLUDE_DIR "@PACKAGE_INCLUDE_INSTALL_DIR@") +set_and_check(OPUS_INCLUDE_DIRS "@PACKAGE_INCLUDE_INSTALL_DIR@") + +include(${CMAKE_CURRENT_LIST_DIR}/OpusTargets.cmake) + +set(OPUS_LIBRARY Opus::opus) +set(OPUS_LIBRARIES Opus::opus) + +check_required_components(Opus) + +set(OPUS_FOUND 1) diff --git a/extern/opus/README b/extern/opus/README new file mode 100644 index 0000000..27fddf9 --- /dev/null +++ b/extern/opus/README @@ -0,0 +1,161 @@ +== Opus audio codec == + +Opus is a codec for interactive speech and audio transmission over the Internet. + + Opus can handle a wide range of interactive audio applications, including +Voice over IP, videoconferencing, in-game chat, and even remote live music +performances. It can scale from low bit-rate narrowband speech to very high +quality stereo music. + + Opus, when coupled with an appropriate container format, is also suitable +for non-realtime stored-file applications such as music distribution, game +soundtracks, portable music players, jukeboxes, and other applications that +have historically used high latency formats such as MP3, AAC, or Vorbis. + + Opus is specified by IETF RFC 6716: + https://tools.ietf.org/html/rfc6716 + + The Opus format and this implementation of it are subject to the royalty- +free patent and copyright licenses specified in the file COPYING. + +This package implements a shared library for encoding and decoding raw Opus +bitstreams. Raw Opus bitstreams should be used over RTP according to + https://tools.ietf.org/html/rfc7587 + +The package also includes a number of test tools used for testing the +correct operation of the library. The bitstreams read/written by these +tools should not be used for Opus file distribution: They include +additional debugging data and cannot support seeking. + +Opus stored in files should use the Ogg encapsulation for Opus which is +described at: + https://tools.ietf.org/html/rfc7845 + +An opus-tools package is available which provides encoding and decoding of +Ogg encapsulated Opus files and includes a number of useful features. + +Opus-tools can be found at: + https://git.xiph.org/?p=opus-tools.git +or on the main Opus website: + https://opus-codec.org/ + +== Compiling libopus == + +To build from a distribution tarball, you only need to do the following: + + % ./configure + % make + +To build from the git repository, the following steps are necessary: + +0) Set up a development environment: + +On an Ubuntu or Debian family Linux distribution: + + % sudo apt-get install git autoconf automake libtool gcc make + +On a Fedora/Redhat based Linux: + + % sudo dnf install git autoconf automake libtool gcc make + +Or for older Redhat/Centos Linux releases: + + % sudo yum install git autoconf automake libtool gcc make + +On Apple macOS, install Xcode and brew.sh, then in the Terminal enter: + + % brew install autoconf automake libtool + +1) Clone the repository: + + % git clone https://git.xiph.org/opus.git + % cd opus + +2) Compiling the source + + % ./autogen.sh + % ./configure + % make + +3) Install the codec libraries (optional) + + % sudo make install + +Once you have compiled the codec, there will be a opus_demo executable +in the top directory. + +Usage: opus_demo [-e] + [options] + opus_demo -d [options] + + +mode: voip | audio | restricted-lowdelay +options: + -e : only runs the encoder (output the bit-stream) + -d : only runs the decoder (reads the bit-stream as input) + -cbr : enable constant bitrate; default: variable bitrate + -cvbr : enable constrained variable bitrate; default: + unconstrained + -bandwidth + : audio bandwidth (from narrowband to fullband); + default: sampling rate + -framesize <2.5|5|10|20|40|60> + : frame size in ms; default: 20 + -max_payload + : maximum payload size in bytes, default: 1024 + -complexity + : complexity, 0 (lowest) ... 10 (highest); default: 10 + -inbandfec : enable SILK inband FEC + -forcemono : force mono encoding, even for stereo input + -dtx : enable SILK DTX + -loss : simulate packet loss, in percent (0-100); default: 0 + +input and output are little-endian signed 16-bit PCM files or opus +bitstreams with simple opus_demo proprietary framing. + +== Testing == + +This package includes a collection of automated unit and system tests +which SHOULD be run after compiling the package especially the first +time it is run on a new platform. + +To run the integrated tests: + + % make check + +There is also collection of standard test vectors which are not +included in this package for size reasons but can be obtained from: +https://opus-codec.org/docs/opus_testvectors-rfc8251.tar.gz + +To run compare the code to these test vectors: + + % curl -OL https://opus-codec.org/docs/opus_testvectors-rfc8251.tar.gz + % tar -zxf opus_testvectors-rfc8251.tar.gz + % ./tests/run_vectors.sh ./ opus_newvectors 48000 + +== Portability notes == + +This implementation uses floating-point by default but can be compiled to +use only fixed-point arithmetic by setting --enable-fixed-point (if using +autoconf) or by defining the FIXED_POINT macro (if building manually). +The fixed point implementation has somewhat lower audio quality and is +slower on platforms with fast FPUs, it is normally only used in embedded +environments. + +The implementation can be compiled with either a C89 or a C99 compiler. +While it does not rely on any _undefined behavior_ as defined by C89 or +C99, it relies on common _implementation-defined behavior_ for two's +complement architectures: + +o Right shifts of negative values are consistent with two's + complement arithmetic, so that a>>b is equivalent to + floor(a/(2^b)), + +o For conversion to a signed integer of N bits, the value is reduced + modulo 2^N to be within range of the type, + +o The result of integer division of a negative value is truncated + towards zero, and + +o The compiler provides a 64-bit integer type (a C99 requirement + which is supported by most C89 compilers). diff --git a/extern/opus/README.draft b/extern/opus/README.draft new file mode 100644 index 0000000..8d8e24d --- /dev/null +++ b/extern/opus/README.draft @@ -0,0 +1,54 @@ +To build this source code, simply type: + +% make + +If this does not work, or if you want to change the default configuration +(e.g., to compile for a fixed-point architecture), simply edit the options +in the Makefile. + +An up-to-date implementation conforming to this standard is available in a +Git repository at https://git.xiph.org/opus.git or on a website at: +https://opus-codec.org/ +However, although that implementation is expected to remain conformant +with the standard, it is the code in this RFC that shall remain normative. +To build from the git repository instead of using this RFC, follow these +steps: + +1) Clone the repository (latest implementation of this standard at the time +of publication) + +% git clone https://git.xiph.org/opus.git +% cd opus + +2) Compile + +% ./autogen.sh +% ./configure +% make + +Once you have compiled the codec, there will be a opus_demo executable in +the top directory. + +Usage: opus_demo [-e] + [options] + opus_demo -d [options] + + +mode: voip | audio | restricted-lowdelay +options: +-e : only runs the encoder (output the bit-stream) +-d : only runs the decoder (reads the bit-stream as input) +-cbr : enable constant bitrate; default: variable bitrate +-cvbr : enable constrained variable bitrate; default: unconstrained +-bandwidth : audio bandwidth (from narrowband to fullband); + default: sampling rate +-framesize <2.5|5|10|20|40|60> : frame size in ms; default: 20 +-max_payload : maximum payload size in bytes, default: 1024 +-complexity : complexity, 0 (lowest) ... 10 (highest); default: 10 +-inbandfec : enable SILK inband FEC +-forcemono : force mono encoding, even for stereo input +-dtx : enable SILK DTX +-loss : simulate packet loss, in percent (0-100); default: 0 + +input and output are little endian signed 16-bit PCM files or opus bitstreams +with simple opus_demo proprietary framing. diff --git a/extern/opus/autogen.sh b/extern/opus/autogen.sh new file mode 100755 index 0000000..380d1f3 --- /dev/null +++ b/extern/opus/autogen.sh @@ -0,0 +1,14 @@ +#!/bin/sh +# Copyright (c) 2010-2015 Xiph.Org Foundation and contributors. +# Use of this source code is governed by a BSD-style license that can be +# found in the COPYING file. + +# Run this to set up the build system: configure, makefiles, etc. +set -e + +srcdir=`dirname $0` +test -n "$srcdir" && cd "$srcdir" + +echo "Updating build configuration files, please wait...." + +autoreconf -isf diff --git a/extern/opus/celt/_kiss_fft_guts.h b/extern/opus/celt/_kiss_fft_guts.h new file mode 100644 index 0000000..17392b3 --- /dev/null +++ b/extern/opus/celt/_kiss_fft_guts.h @@ -0,0 +1,182 @@ +/*Copyright (c) 2003-2004, Mark Borgerding + + All rights reserved. + + 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. + + 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 OWNER 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.*/ + +#ifndef KISS_FFT_GUTS_H +#define KISS_FFT_GUTS_H + +#define MIN(a,b) ((a)<(b) ? (a):(b)) +#define MAX(a,b) ((a)>(b) ? (a):(b)) + +/* kiss_fft.h + defines kiss_fft_scalar as either short or a float type + and defines + typedef struct { kiss_fft_scalar r; kiss_fft_scalar i; }kiss_fft_cpx; */ +#include "kiss_fft.h" + +/* + Explanation of macros dealing with complex math: + + C_MUL(m,a,b) : m = a*b + C_FIXDIV( c , div ) : if a fixed point impl., c /= div. noop otherwise + C_SUB( res, a,b) : res = a - b + C_SUBFROM( res , a) : res -= a + C_ADDTO( res , a) : res += a + * */ +#ifdef FIXED_POINT +#include "arch.h" + + +#define SAMP_MAX 2147483647 +#define TWID_MAX 32767 +#define TRIG_UPSCALE 1 + +#define SAMP_MIN -SAMP_MAX + + +# define S_MUL(a,b) MULT16_32_Q15(b, a) + +# define C_MUL(m,a,b) \ + do{ (m).r = SUB32_ovflw(S_MUL((a).r,(b).r) , S_MUL((a).i,(b).i)); \ + (m).i = ADD32_ovflw(S_MUL((a).r,(b).i) , S_MUL((a).i,(b).r)); }while(0) + +# define C_MULC(m,a,b) \ + do{ (m).r = ADD32_ovflw(S_MUL((a).r,(b).r) , S_MUL((a).i,(b).i)); \ + (m).i = SUB32_ovflw(S_MUL((a).i,(b).r) , S_MUL((a).r,(b).i)); }while(0) + +# define C_MULBYSCALAR( c, s ) \ + do{ (c).r = S_MUL( (c).r , s ) ;\ + (c).i = S_MUL( (c).i , s ) ; }while(0) + +# define DIVSCALAR(x,k) \ + (x) = S_MUL( x, (TWID_MAX-((k)>>1))/(k)+1 ) + +# define C_FIXDIV(c,div) \ + do { DIVSCALAR( (c).r , div); \ + DIVSCALAR( (c).i , div); }while (0) + +#define C_ADD( res, a,b)\ + do {(res).r=ADD32_ovflw((a).r,(b).r); (res).i=ADD32_ovflw((a).i,(b).i); \ + }while(0) +#define C_SUB( res, a,b)\ + do {(res).r=SUB32_ovflw((a).r,(b).r); (res).i=SUB32_ovflw((a).i,(b).i); \ + }while(0) +#define C_ADDTO( res , a)\ + do {(res).r = ADD32_ovflw((res).r, (a).r); (res).i = ADD32_ovflw((res).i,(a).i);\ + }while(0) + +#define C_SUBFROM( res , a)\ + do {(res).r = ADD32_ovflw((res).r,(a).r); (res).i = SUB32_ovflw((res).i,(a).i); \ + }while(0) + +#if defined(OPUS_ARM_INLINE_ASM) +#include "arm/kiss_fft_armv4.h" +#endif + +#if defined(OPUS_ARM_INLINE_EDSP) +#include "arm/kiss_fft_armv5e.h" +#endif +#if defined(MIPSr1_ASM) +#include "mips/kiss_fft_mipsr1.h" +#endif + +#else /* not FIXED_POINT*/ + +# define S_MUL(a,b) ( (a)*(b) ) +#define C_MUL(m,a,b) \ + do{ (m).r = (a).r*(b).r - (a).i*(b).i;\ + (m).i = (a).r*(b).i + (a).i*(b).r; }while(0) +#define C_MULC(m,a,b) \ + do{ (m).r = (a).r*(b).r + (a).i*(b).i;\ + (m).i = (a).i*(b).r - (a).r*(b).i; }while(0) + +#define C_MUL4(m,a,b) C_MUL(m,a,b) + +# define C_FIXDIV(c,div) /* NOOP */ +# define C_MULBYSCALAR( c, s ) \ + do{ (c).r *= (s);\ + (c).i *= (s); }while(0) +#endif + +#ifndef CHECK_OVERFLOW_OP +# define CHECK_OVERFLOW_OP(a,op,b) /* noop */ +#endif + +#ifndef C_ADD +#define C_ADD( res, a,b)\ + do { \ + CHECK_OVERFLOW_OP((a).r,+,(b).r)\ + CHECK_OVERFLOW_OP((a).i,+,(b).i)\ + (res).r=(a).r+(b).r; (res).i=(a).i+(b).i; \ + }while(0) +#define C_SUB( res, a,b)\ + do { \ + CHECK_OVERFLOW_OP((a).r,-,(b).r)\ + CHECK_OVERFLOW_OP((a).i,-,(b).i)\ + (res).r=(a).r-(b).r; (res).i=(a).i-(b).i; \ + }while(0) +#define C_ADDTO( res , a)\ + do { \ + CHECK_OVERFLOW_OP((res).r,+,(a).r)\ + CHECK_OVERFLOW_OP((res).i,+,(a).i)\ + (res).r += (a).r; (res).i += (a).i;\ + }while(0) + +#define C_SUBFROM( res , a)\ + do {\ + CHECK_OVERFLOW_OP((res).r,-,(a).r)\ + CHECK_OVERFLOW_OP((res).i,-,(a).i)\ + (res).r -= (a).r; (res).i -= (a).i; \ + }while(0) +#endif /* C_ADD defined */ + +#ifdef FIXED_POINT +/*# define KISS_FFT_COS(phase) TRIG_UPSCALE*floor(MIN(32767,MAX(-32767,.5+32768 * cos (phase)))) +# define KISS_FFT_SIN(phase) TRIG_UPSCALE*floor(MIN(32767,MAX(-32767,.5+32768 * sin (phase))))*/ +# define KISS_FFT_COS(phase) floor(.5+TWID_MAX*cos (phase)) +# define KISS_FFT_SIN(phase) floor(.5+TWID_MAX*sin (phase)) +# define HALF_OF(x) ((x)>>1) +#elif defined(USE_SIMD) +# define KISS_FFT_COS(phase) _mm_set1_ps( cos(phase) ) +# define KISS_FFT_SIN(phase) _mm_set1_ps( sin(phase) ) +# define HALF_OF(x) ((x)*_mm_set1_ps(.5f)) +#else +# define KISS_FFT_COS(phase) (kiss_fft_scalar) cos(phase) +# define KISS_FFT_SIN(phase) (kiss_fft_scalar) sin(phase) +# define HALF_OF(x) ((x)*.5f) +#endif + +#define kf_cexp(x,phase) \ + do{ \ + (x)->r = KISS_FFT_COS(phase);\ + (x)->i = KISS_FFT_SIN(phase);\ + }while(0) + +#define kf_cexp2(x,phase) \ + do{ \ + (x)->r = TRIG_UPSCALE*celt_cos_norm((phase));\ + (x)->i = TRIG_UPSCALE*celt_cos_norm((phase)-32768);\ +}while(0) + +#endif /* KISS_FFT_GUTS_H */ diff --git a/extern/opus/celt/arch.h b/extern/opus/celt/arch.h new file mode 100644 index 0000000..08b07db --- /dev/null +++ b/extern/opus/celt/arch.h @@ -0,0 +1,288 @@ +/* Copyright (c) 2003-2008 Jean-Marc Valin + Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/** + @file arch.h + @brief Various architecture definitions for CELT +*/ +/* + 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. + + 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 OWNER + 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. +*/ + +#ifndef ARCH_H +#define ARCH_H + +#include "opus_types.h" +#include "opus_defines.h" + +# if !defined(__GNUC_PREREQ) +# if defined(__GNUC__)&&defined(__GNUC_MINOR__) +# define __GNUC_PREREQ(_maj,_min) \ + ((__GNUC__<<16)+__GNUC_MINOR__>=((_maj)<<16)+(_min)) +# else +# define __GNUC_PREREQ(_maj,_min) 0 +# endif +# endif + +#if OPUS_GNUC_PREREQ(3, 0) +#define opus_likely(x) (__builtin_expect(!!(x), 1)) +#define opus_unlikely(x) (__builtin_expect(!!(x), 0)) +#else +#define opus_likely(x) (!!(x)) +#define opus_unlikely(x) (!!(x)) +#endif + +#define CELT_SIG_SCALE 32768.f + +#define CELT_FATAL(str) celt_fatal(str, __FILE__, __LINE__); + +#if defined(ENABLE_ASSERTIONS) || defined(ENABLE_HARDENING) +#ifdef __GNUC__ +__attribute__((noreturn)) +#endif +void celt_fatal(const char *str, const char *file, int line); + +#if defined(CELT_C) && !defined(OVERRIDE_celt_fatal) +#include +#include +#ifdef __GNUC__ +__attribute__((noreturn)) +#endif +void celt_fatal(const char *str, const char *file, int line) +{ + fprintf (stderr, "Fatal (internal) error in %s, line %d: %s\n", file, line, str); + abort(); +} +#endif + +#define celt_assert(cond) {if (!(cond)) {CELT_FATAL("assertion failed: " #cond);}} +#define celt_assert2(cond, message) {if (!(cond)) {CELT_FATAL("assertion failed: " #cond "\n" message);}} +#define MUST_SUCCEED(call) celt_assert((call) == OPUS_OK) +#else +#define celt_assert(cond) +#define celt_assert2(cond, message) +#define MUST_SUCCEED(call) do {if((call) != OPUS_OK) {RESTORE_STACK; return OPUS_INTERNAL_ERROR;} } while (0) +#endif + +#if defined(ENABLE_ASSERTIONS) +#define celt_sig_assert(cond) {if (!(cond)) {CELT_FATAL("signal assertion failed: " #cond);}} +#else +#define celt_sig_assert(cond) +#endif + +#define IMUL32(a,b) ((a)*(b)) + +#define MIN16(a,b) ((a) < (b) ? (a) : (b)) /**< Minimum 16-bit value. */ +#define MAX16(a,b) ((a) > (b) ? (a) : (b)) /**< Maximum 16-bit value. */ +#define MIN32(a,b) ((a) < (b) ? (a) : (b)) /**< Minimum 32-bit value. */ +#define MAX32(a,b) ((a) > (b) ? (a) : (b)) /**< Maximum 32-bit value. */ +#define IMIN(a,b) ((a) < (b) ? (a) : (b)) /**< Minimum int value. */ +#define IMAX(a,b) ((a) > (b) ? (a) : (b)) /**< Maximum int value. */ +#define UADD32(a,b) ((a)+(b)) +#define USUB32(a,b) ((a)-(b)) + +/* Set this if opus_int64 is a native type of the CPU. */ +/* Assume that all LP64 architectures have fast 64-bit types; also x86_64 + (which can be ILP32 for x32) and Win64 (which is LLP64). */ +#if defined(__x86_64__) || defined(__LP64__) || defined(_WIN64) +#define OPUS_FAST_INT64 1 +#else +#define OPUS_FAST_INT64 0 +#endif + +#define PRINT_MIPS(file) + +#ifdef FIXED_POINT + +typedef opus_int16 opus_val16; +typedef opus_int32 opus_val32; +typedef opus_int64 opus_val64; + +typedef opus_val32 celt_sig; +typedef opus_val16 celt_norm; +typedef opus_val32 celt_ener; + +#define celt_isnan(x) 0 + +#define Q15ONE 32767 + +#define SIG_SHIFT 12 +/* Safe saturation value for 32-bit signals. Should be less than + 2^31*(1-0.85) to avoid blowing up on DC at deemphasis.*/ +#define SIG_SAT (300000000) + +#define NORM_SCALING 16384 + +#define DB_SHIFT 10 + +#define EPSILON 1 +#define VERY_SMALL 0 +#define VERY_LARGE16 ((opus_val16)32767) +#define Q15_ONE ((opus_val16)32767) + +#define SCALEIN(a) (a) +#define SCALEOUT(a) (a) + +#define ABS16(x) ((x) < 0 ? (-(x)) : (x)) +#define ABS32(x) ((x) < 0 ? (-(x)) : (x)) + +static OPUS_INLINE opus_int16 SAT16(opus_int32 x) { + return x > 32767 ? 32767 : x < -32768 ? -32768 : (opus_int16)x; +} + +#ifdef FIXED_DEBUG +#include "fixed_debug.h" +#else + +#include "fixed_generic.h" + +#ifdef OPUS_ARM_PRESUME_AARCH64_NEON_INTR +#include "arm/fixed_arm64.h" +#elif defined (OPUS_ARM_INLINE_EDSP) +#include "arm/fixed_armv5e.h" +#elif defined (OPUS_ARM_INLINE_ASM) +#include "arm/fixed_armv4.h" +#elif defined (BFIN_ASM) +#include "fixed_bfin.h" +#elif defined (TI_C5X_ASM) +#include "fixed_c5x.h" +#elif defined (TI_C6X_ASM) +#include "fixed_c6x.h" +#endif + +#endif + +#else /* FIXED_POINT */ + +typedef float opus_val16; +typedef float opus_val32; +typedef float opus_val64; + +typedef float celt_sig; +typedef float celt_norm; +typedef float celt_ener; + +#ifdef FLOAT_APPROX +/* This code should reliably detect NaN/inf even when -ffast-math is used. + Assumes IEEE 754 format. */ +static OPUS_INLINE int celt_isnan(float x) +{ + union {float f; opus_uint32 i;} in; + in.f = x; + return ((in.i>>23)&0xFF)==0xFF && (in.i&0x007FFFFF)!=0; +} +#else +#ifdef __FAST_MATH__ +#error Cannot build libopus with -ffast-math unless FLOAT_APPROX is defined. This could result in crashes on extreme (e.g. NaN) input +#endif +#define celt_isnan(x) ((x)!=(x)) +#endif + +#define Q15ONE 1.0f + +#define NORM_SCALING 1.f + +#define EPSILON 1e-15f +#define VERY_SMALL 1e-30f +#define VERY_LARGE16 1e15f +#define Q15_ONE ((opus_val16)1.f) + +/* This appears to be the same speed as C99's fabsf() but it's more portable. */ +#define ABS16(x) ((float)fabs(x)) +#define ABS32(x) ((float)fabs(x)) + +#define QCONST16(x,bits) (x) +#define QCONST32(x,bits) (x) + +#define NEG16(x) (-(x)) +#define NEG32(x) (-(x)) +#define NEG32_ovflw(x) (-(x)) +#define EXTRACT16(x) (x) +#define EXTEND32(x) (x) +#define SHR16(a,shift) (a) +#define SHL16(a,shift) (a) +#define SHR32(a,shift) (a) +#define SHL32(a,shift) (a) +#define PSHR32(a,shift) (a) +#define VSHR32(a,shift) (a) + +#define PSHR(a,shift) (a) +#define SHR(a,shift) (a) +#define SHL(a,shift) (a) +#define SATURATE(x,a) (x) +#define SATURATE16(x) (x) + +#define ROUND16(a,shift) (a) +#define SROUND16(a,shift) (a) +#define HALF16(x) (.5f*(x)) +#define HALF32(x) (.5f*(x)) + +#define ADD16(a,b) ((a)+(b)) +#define SUB16(a,b) ((a)-(b)) +#define ADD32(a,b) ((a)+(b)) +#define SUB32(a,b) ((a)-(b)) +#define ADD32_ovflw(a,b) ((a)+(b)) +#define SUB32_ovflw(a,b) ((a)-(b)) +#define MULT16_16_16(a,b) ((a)*(b)) +#define MULT16_16(a,b) ((opus_val32)(a)*(opus_val32)(b)) +#define MAC16_16(c,a,b) ((c)+(opus_val32)(a)*(opus_val32)(b)) + +#define MULT16_32_Q15(a,b) ((a)*(b)) +#define MULT16_32_Q16(a,b) ((a)*(b)) + +#define MULT32_32_Q31(a,b) ((a)*(b)) + +#define MAC16_32_Q15(c,a,b) ((c)+(a)*(b)) +#define MAC16_32_Q16(c,a,b) ((c)+(a)*(b)) + +#define MULT16_16_Q11_32(a,b) ((a)*(b)) +#define MULT16_16_Q11(a,b) ((a)*(b)) +#define MULT16_16_Q13(a,b) ((a)*(b)) +#define MULT16_16_Q14(a,b) ((a)*(b)) +#define MULT16_16_Q15(a,b) ((a)*(b)) +#define MULT16_16_P15(a,b) ((a)*(b)) +#define MULT16_16_P13(a,b) ((a)*(b)) +#define MULT16_16_P14(a,b) ((a)*(b)) +#define MULT16_32_P16(a,b) ((a)*(b)) + +#define DIV32_16(a,b) (((opus_val32)(a))/(opus_val16)(b)) +#define DIV32(a,b) (((opus_val32)(a))/(opus_val32)(b)) + +#define SCALEIN(a) ((a)*CELT_SIG_SCALE) +#define SCALEOUT(a) ((a)*(1/CELT_SIG_SCALE)) + +#define SIG2WORD16(x) (x) + +#endif /* !FIXED_POINT */ + +#ifndef GLOBAL_STACK_SIZE +#ifdef FIXED_POINT +#define GLOBAL_STACK_SIZE 120000 +#else +#define GLOBAL_STACK_SIZE 120000 +#endif +#endif + +#endif /* ARCH_H */ diff --git a/extern/opus/celt/arm/arm2gnu.pl b/extern/opus/celt/arm/arm2gnu.pl new file mode 100755 index 0000000..a2895f7 --- /dev/null +++ b/extern/opus/celt/arm/arm2gnu.pl @@ -0,0 +1,353 @@ +#!/usr/bin/perl +# Copyright (C) 2002-2013 Xiph.org Foundation +# +# 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. +# +# 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 OWNER +# 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. + +my $bigend; # little/big endian +my $nxstack; +my $apple = 0; +my $symprefix = ""; + +$nxstack = 0; + +eval 'exec /usr/local/bin/perl -S $0 ${1+"$@"}' + if $running_under_some_shell; + +while ($ARGV[0] =~ /^-/) { + $_ = shift; + last if /^--$/; + if (/^-n$/) { + $nflag++; + next; + } + if (/^--apple$/) { + $apple = 1; + $symprefix = "_"; + next; + } + die "I don't recognize this switch: $_\\n"; +} +$printit++ unless $nflag; + +$\ = "\n"; # automatically add newline on print +$n=0; + +$thumb = 0; # ARM mode by default, not Thumb. +@proc_stack = (); + +printf (" .syntax unified\n"); + +LINE: +while (<>) { + + # For ADRLs we need to add a new line after the substituted one. + $addPadding = 0; + + # First, we do not dare to touch *anything* inside double quotes, do we? + # Second, if you want a dollar character in the string, + # insert two of them -- that's how ARM C and assembler treat strings. + s/^([A-Za-z_]\w*)[ \t]+DCB[ \t]*\"/$1: .ascii \"/ && do { s/\$\$/\$/g; next }; + s/\bDCB\b[ \t]*\"/.ascii \"/ && do { s/\$\$/\$/g; next }; + s/^(\S+)\s+RN\s+(\S+)/$1 .req r$2/ && do { s/\$\$/\$/g; next }; + # If there's nothing on a line but a comment, don't try to apply any further + # substitutions (this is a cheap hack to avoid mucking up the license header) + s/^([ \t]*);/$1@/ && do { s/\$\$/\$/g; next }; + # If substituted -- leave immediately ! + + s/@/,:/; + s/;/@/; + while ( /@.*'/ ) { + s/(@.*)'/$1/g; + } + s/\{FALSE\}/0/g; + s/\{TRUE\}/1/g; + s/\{(\w\w\w\w+)\}/$1/g; + s/\bINCLUDE[ \t]*([^ \t\n]+)/.include \"$1\"/; + s/\bGET[ \t]*([^ \t\n]+)/.include \"${ my $x=$1; $x =~ s|\.s|-gnu.S|; \$x }\"/; + s/\bIMPORT\b/.extern/; + s/\bEXPORT\b\s*/.global $symprefix/; + s/^(\s+)\[/$1IF/; + s/^(\s+)\|/$1ELSE/; + s/^(\s+)\]/$1ENDIF/; + s/IF *:DEF:/ .ifdef/; + s/IF *:LNOT: *:DEF:/ .ifndef/; + s/ELSE/ .else/; + s/ENDIF/ .endif/; + + if( /\bIF\b/ ) { + s/\bIF\b/ .if/; + s/=/==/; + } + if ( $n == 2) { + s/\$/\\/g; + } + if ($n == 1) { + s/\$//g; + s/label//g; + $n = 2; + } + if ( /MACRO/ ) { + s/MACRO *\n/.macro/; + $n=1; + } + if ( /\bMEND\b/ ) { + s/\bMEND\b/.endm/; + $n=0; + } + + # ".rdata" doesn't work in 'as' version 2.13.2, as it is ".rodata" there. + # + if ( /\bAREA\b/ ) { + my $align; + $align = "2"; + if ( /ALIGN=(\d+)/ ) { + $align = $1; + } + if ( /CODE/ ) { + $nxstack = 1; + } + s/^(.+)CODE(.+)READONLY(.*)/ .text/; + s/^(.+)DATA(.+)READONLY(.*)/ .section .rdata/; + s/^(.+)\|\|\.data\|\|(.+)/ .data/; + s/^(.+)\|\|\.bss\|\|(.+)/ .bss/; + s/$/; .p2align $align/; + # Enable NEON instructions but don't produce a binary that requires + # ARMv7. RVCT does not have equivalent directives, so we just do this + # for all CODE areas. + if ( /.text/ ) { + # Separating .arch, .fpu, etc., by semicolons does not work (gas + # thinks the semicolon is part of the arch name, even when there's + # whitespace separating them). Sadly this means our line numbers + # won't match the original source file (we could use the .line + # directive, which is documented to be obsolete, but then gdb will + # show the wrong line in the translated source file). + s/$/; .arch armv7-a\n .fpu neon\n .object_arch armv4t/ unless ($apple); + } + } + + s/\|\|\.constdata\$(\d+)\|\|/.L_CONST$1/; # ||.constdata$3|| + s/\|\|\.bss\$(\d+)\|\|/.L_BSS$1/; # ||.bss$2|| + s/\|\|\.data\$(\d+)\|\|/.L_DATA$1/; # ||.data$2|| + s/\|\|([a-zA-Z0-9_]+)\@([a-zA-Z0-9_]+)\|\|/@ $&/; + s/^(\s+)\%(\s)/ .space $1/; + + s/\|(.+)\.(\d+)\|/\.$1_$2/; # |L80.123| -> .L80_123 + s/\bCODE32\b/.code 32/ && do {$thumb = 0}; + s/\bCODE16\b/.code 16/ && do {$thumb = 1}; + if (/\bPROC\b/) + { + my $prefix; + my $proc; + /^([A-Za-z_\.]\w+)\b/; + $proc = $1; + $prefix = ""; + if ($proc) + { + $prefix = $prefix.sprintf("\t.type\t%s, %%function", $proc) unless ($apple); + # Make sure we $prefix isn't empty here (for the $apple case). + # We handle mangling the label here, make sure it doesn't match + # the label handling below (if $prefix would be empty). + $prefix = $prefix."; "; + push(@proc_stack, $proc); + s/^[A-Za-z_\.]\w+/$symprefix$&:/; + } + $prefix = $prefix."\t.thumb_func; " if ($thumb); + s/\bPROC\b/@ $&/; + $_ = $prefix.$_; + } + s/^(\s*)(S|Q|SH|U|UQ|UH)ASX\b/$1$2ADDSUBX/; + s/^(\s*)(S|Q|SH|U|UQ|UH)SAX\b/$1$2SUBADDX/; + if (/\bENDP\b/) + { + my $proc; + s/\bENDP\b/@ $&/; + $proc = pop(@proc_stack); + $_ = "\t.size $proc, .-$proc".$_ if ($proc && !$apple); + } + s/\bSUBT\b/@ $&/; + s/\bDATA\b/@ $&/; # DATA directive is deprecated -- Asm guide, p.7-25 + s/\bKEEP\b/@ $&/; + s/\bEXPORTAS\b/@ $&/; + s/\|\|(.)+\bEQU\b/@ $&/; + s/\|\|([\w\$]+)\|\|/$1/; + s/\bENTRY\b/@ $&/; + s/\bASSERT\b/@ $&/; + s/\bGBLL\b/@ $&/; + s/\bGBLA\b/@ $&/; + s/^\W+OPT\b/@ $&/; + s/:OR:/|/g; + s/:SHL:/<>/g; + s/:AND:/&/g; + s/:LAND:/&&/g; + s/CPSR/cpsr/; + s/SPSR/spsr/; + s/ALIGN$/.balign 4/; + s/ALIGN\s+([0-9x]+)$/.balign $1/; + s/psr_cxsf/psr_all/; + s/LTORG/.ltorg/; + s/^([A-Za-z_]\w*)[ \t]+EQU/ .set $1,/; + s/^([A-Za-z_]\w*)[ \t]+SETL/ .set $1,/; + s/^([A-Za-z_]\w*)[ \t]+SETA/ .set $1,/; + s/^([A-Za-z_]\w*)[ \t]+\*/ .set $1,/; + + # {PC} + 0xdeadfeed --> . + 0xdeadfeed + s/\{PC\} \+/ \. +/; + + # Single hex constant on the line ! + # + # >>> NOTE <<< + # Double-precision floats in gcc are always mixed-endian, which means + # bytes in two words are little-endian, but words are big-endian. + # So, 0x0000deadfeed0000 would be stored as 0x0000dead at low address + # and 0xfeed0000 at high address. + # + s/\bDCFD\b[ \t]+0x([a-fA-F0-9]{8})([a-fA-F0-9]{8})/.long 0x$1, 0x$2/; + # Only decimal constants on the line, no hex ! + s/\bDCFD\b[ \t]+([0-9\.\-]+)/.double $1/; + + # Single hex constant on the line ! +# s/\bDCFS\b[ \t]+0x([a-f0-9]{8})([a-f0-9]{8})/.long 0x$1, 0x$2/; + # Only decimal constants on the line, no hex ! +# s/\bDCFS\b[ \t]+([0-9\.\-]+)/.double $1/; + s/\bDCFS[ \t]+0x/.word 0x/; + s/\bDCFS\b/.float/; + + s/^([A-Za-z_]\w*)[ \t]+DCD/$1 .word/; + s/\bDCD\b/.word/; + s/^([A-Za-z_]\w*)[ \t]+DCW/$1 .short/; + s/\bDCW\b/.short/; + s/^([A-Za-z_]\w*)[ \t]+DCB/$1 .byte/; + s/\bDCB\b/.byte/; + s/^([A-Za-z_]\w*)[ \t]+\%/.comm $1,/; + s/^[A-Za-z_\.]\w+/$&:/; + s/^(\d+)/$1:/; + s/\%(\d+)/$1b_or_f/; + s/\%[Bb](\d+)/$1b/; + s/\%[Ff](\d+)/$1f/; + s/\%[Ff][Tt](\d+)/$1f/; + s/&([\dA-Fa-f]+)/0x$1/; + if ( /\b2_[01]+\b/ ) { + s/\b2_([01]+)\b/conv$1&&&&/g; + while ( /[01][01][01][01]&&&&/ ) { + s/0000&&&&/&&&&0/g; + s/0001&&&&/&&&&1/g; + s/0010&&&&/&&&&2/g; + s/0011&&&&/&&&&3/g; + s/0100&&&&/&&&&4/g; + s/0101&&&&/&&&&5/g; + s/0110&&&&/&&&&6/g; + s/0111&&&&/&&&&7/g; + s/1000&&&&/&&&&8/g; + s/1001&&&&/&&&&9/g; + s/1010&&&&/&&&&A/g; + s/1011&&&&/&&&&B/g; + s/1100&&&&/&&&&C/g; + s/1101&&&&/&&&&D/g; + s/1110&&&&/&&&&E/g; + s/1111&&&&/&&&&F/g; + } + s/000&&&&/&&&&0/g; + s/001&&&&/&&&&1/g; + s/010&&&&/&&&&2/g; + s/011&&&&/&&&&3/g; + s/100&&&&/&&&&4/g; + s/101&&&&/&&&&5/g; + s/110&&&&/&&&&6/g; + s/111&&&&/&&&&7/g; + s/00&&&&/&&&&0/g; + s/01&&&&/&&&&1/g; + s/10&&&&/&&&&2/g; + s/11&&&&/&&&&3/g; + s/0&&&&/&&&&0/g; + s/1&&&&/&&&&1/g; + s/conv&&&&/0x/g; + } + + if ( /commandline/) + { + if( /-bigend/) + { + $bigend=1; + } + } + + if ( /\bDCDU\b/ ) + { + my $cmd=$_; + my $value; + my $prefix; + my $w1; + my $w2; + my $w3; + my $w4; + + s/\s+DCDU\b/@ $&/; + + $cmd =~ /\bDCDU\b\s+0x(\d+)/; + $value = $1; + $value =~ /(\w\w)(\w\w)(\w\w)(\w\w)/; + $w1 = $1; + $w2 = $2; + $w3 = $3; + $w4 = $4; + + if( $bigend ne "") + { + # big endian + $prefix = "\t.byte\t0x".$w1.";". + "\t.byte\t0x".$w2.";". + "\t.byte\t0x".$w3.";". + "\t.byte\t0x".$w4."; "; + } + else + { + # little endian + $prefix = "\t.byte\t0x".$w4.";". + "\t.byte\t0x".$w3.";". + "\t.byte\t0x".$w2.";". + "\t.byte\t0x".$w1."; "; + } + $_=$prefix.$_; + } + + if ( /\badrl\b/i ) + { + s/\badrl\s+(\w+)\s*,\s*(\w+)/ldr $1,=$2/i; + $addPadding = 1; + } + s/\bEND\b/@ END/; +} continue { + printf ("%s", $_) if $printit; + if ($addPadding != 0) + { + printf (" mov r0,r0\n"); + $addPadding = 0; + } +} +#If we had a code section, mark that this object doesn't need an executable +# stack. +if ($nxstack && !$apple) { + printf (" .section\t.note.GNU-stack,\"\",\%\%progbits\n"); +} diff --git a/extern/opus/celt/arm/arm_celt_map.c b/extern/opus/celt/arm/arm_celt_map.c new file mode 100644 index 0000000..ca988b6 --- /dev/null +++ b/extern/opus/celt/arm/arm_celt_map.c @@ -0,0 +1,160 @@ +/* Copyright (c) 2010 Xiph.Org Foundation + * Copyright (c) 2013 Parrot */ +/* + 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. + + 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 OWNER + 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. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "pitch.h" +#include "kiss_fft.h" +#include "mdct.h" + +#if defined(OPUS_HAVE_RTCD) + +# if defined(OPUS_ARM_MAY_HAVE_NEON_INTR) && !defined(OPUS_ARM_PRESUME_NEON_INTR) +opus_val32 (*const CELT_INNER_PROD_IMPL[OPUS_ARCHMASK+1])(const opus_val16 *x, const opus_val16 *y, int N) = { + celt_inner_prod_c, /* ARMv4 */ + celt_inner_prod_c, /* EDSP */ + celt_inner_prod_c, /* Media */ + celt_inner_prod_neon /* NEON */ +}; + +void (*const DUAL_INNER_PROD_IMPL[OPUS_ARCHMASK+1])(const opus_val16 *x, const opus_val16 *y01, const opus_val16 *y02, + int N, opus_val32 *xy1, opus_val32 *xy2) = { + dual_inner_prod_c, /* ARMv4 */ + dual_inner_prod_c, /* EDSP */ + dual_inner_prod_c, /* Media */ + dual_inner_prod_neon /* NEON */ +}; +# endif + +# if defined(FIXED_POINT) +# if ((defined(OPUS_ARM_MAY_HAVE_NEON) && !defined(OPUS_ARM_PRESUME_NEON)) || \ + (defined(OPUS_ARM_MAY_HAVE_MEDIA) && !defined(OPUS_ARM_PRESUME_MEDIA)) || \ + (defined(OPUS_ARM_MAY_HAVE_EDSP) && !defined(OPUS_ARM_PRESUME_EDSP))) +opus_val32 (*const CELT_PITCH_XCORR_IMPL[OPUS_ARCHMASK+1])(const opus_val16 *, + const opus_val16 *, opus_val32 *, int, int, int) = { + celt_pitch_xcorr_c, /* ARMv4 */ + MAY_HAVE_EDSP(celt_pitch_xcorr), /* EDSP */ + MAY_HAVE_MEDIA(celt_pitch_xcorr), /* Media */ + MAY_HAVE_NEON(celt_pitch_xcorr) /* NEON */ +}; + +# endif +# else /* !FIXED_POINT */ +# if defined(OPUS_ARM_MAY_HAVE_NEON_INTR) && !defined(OPUS_ARM_PRESUME_NEON_INTR) +void (*const CELT_PITCH_XCORR_IMPL[OPUS_ARCHMASK+1])(const opus_val16 *, + const opus_val16 *, opus_val32 *, int, int, int) = { + celt_pitch_xcorr_c, /* ARMv4 */ + celt_pitch_xcorr_c, /* EDSP */ + celt_pitch_xcorr_c, /* Media */ + celt_pitch_xcorr_float_neon /* Neon */ +}; +# endif +# endif /* FIXED_POINT */ + +#if defined(FIXED_POINT) && defined(OPUS_HAVE_RTCD) && \ + defined(OPUS_ARM_MAY_HAVE_NEON_INTR) && !defined(OPUS_ARM_PRESUME_NEON_INTR) + +void (*const XCORR_KERNEL_IMPL[OPUS_ARCHMASK + 1])( + const opus_val16 *x, + const opus_val16 *y, + opus_val32 sum[4], + int len +) = { + xcorr_kernel_c, /* ARMv4 */ + xcorr_kernel_c, /* EDSP */ + xcorr_kernel_c, /* Media */ + xcorr_kernel_neon_fixed, /* Neon */ +}; + +#endif + +# if defined(OPUS_ARM_MAY_HAVE_NEON_INTR) +# if defined(HAVE_ARM_NE10) +# if defined(CUSTOM_MODES) +int (*const OPUS_FFT_ALLOC_ARCH_IMPL[OPUS_ARCHMASK+1])(kiss_fft_state *st) = { + opus_fft_alloc_arch_c, /* ARMv4 */ + opus_fft_alloc_arch_c, /* EDSP */ + opus_fft_alloc_arch_c, /* Media */ + opus_fft_alloc_arm_neon /* Neon with NE10 library support */ +}; + +void (*const OPUS_FFT_FREE_ARCH_IMPL[OPUS_ARCHMASK+1])(kiss_fft_state *st) = { + opus_fft_free_arch_c, /* ARMv4 */ + opus_fft_free_arch_c, /* EDSP */ + opus_fft_free_arch_c, /* Media */ + opus_fft_free_arm_neon /* Neon with NE10 */ +}; +# endif /* CUSTOM_MODES */ + +void (*const OPUS_FFT[OPUS_ARCHMASK+1])(const kiss_fft_state *cfg, + const kiss_fft_cpx *fin, + kiss_fft_cpx *fout) = { + opus_fft_c, /* ARMv4 */ + opus_fft_c, /* EDSP */ + opus_fft_c, /* Media */ + opus_fft_neon /* Neon with NE10 */ +}; + +void (*const OPUS_IFFT[OPUS_ARCHMASK+1])(const kiss_fft_state *cfg, + const kiss_fft_cpx *fin, + kiss_fft_cpx *fout) = { + opus_ifft_c, /* ARMv4 */ + opus_ifft_c, /* EDSP */ + opus_ifft_c, /* Media */ + opus_ifft_neon /* Neon with NE10 */ +}; + +void (*const CLT_MDCT_FORWARD_IMPL[OPUS_ARCHMASK+1])(const mdct_lookup *l, + kiss_fft_scalar *in, + kiss_fft_scalar * OPUS_RESTRICT out, + const opus_val16 *window, + int overlap, int shift, + int stride, int arch) = { + clt_mdct_forward_c, /* ARMv4 */ + clt_mdct_forward_c, /* EDSP */ + clt_mdct_forward_c, /* Media */ + clt_mdct_forward_neon /* Neon with NE10 */ +}; + +void (*const CLT_MDCT_BACKWARD_IMPL[OPUS_ARCHMASK+1])(const mdct_lookup *l, + kiss_fft_scalar *in, + kiss_fft_scalar * OPUS_RESTRICT out, + const opus_val16 *window, + int overlap, int shift, + int stride, int arch) = { + clt_mdct_backward_c, /* ARMv4 */ + clt_mdct_backward_c, /* EDSP */ + clt_mdct_backward_c, /* Media */ + clt_mdct_backward_neon /* Neon with NE10 */ +}; + +# endif /* HAVE_ARM_NE10 */ +# endif /* OPUS_ARM_MAY_HAVE_NEON_INTR */ + +#endif /* OPUS_HAVE_RTCD */ diff --git a/extern/opus/celt/arm/armcpu.c b/extern/opus/celt/arm/armcpu.c new file mode 100644 index 0000000..694a63b --- /dev/null +++ b/extern/opus/celt/arm/armcpu.c @@ -0,0 +1,185 @@ +/* Copyright (c) 2010 Xiph.Org Foundation + * Copyright (c) 2013 Parrot */ +/* + 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. + + 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 OWNER + 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. +*/ + +/* Original code from libtheora modified to suit to Opus */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef OPUS_HAVE_RTCD + +#include "armcpu.h" +#include "cpu_support.h" +#include "os_support.h" +#include "opus_types.h" +#include "arch.h" + +#define OPUS_CPU_ARM_V4_FLAG (1< + +static OPUS_INLINE opus_uint32 opus_cpu_capabilities(void){ + opus_uint32 flags; + flags=0; + /* MSVC has no OPUS_INLINE __asm support for ARM, but it does let you __emit + * instructions via their assembled hex code. + * All of these instructions should be essentially nops. */ +# if defined(OPUS_ARM_MAY_HAVE_EDSP) || defined(OPUS_ARM_MAY_HAVE_MEDIA) \ + || defined(OPUS_ARM_MAY_HAVE_NEON) || defined(OPUS_ARM_MAY_HAVE_NEON_INTR) + __try{ + /*PLD [r13]*/ + __emit(0xF5DDF000); + flags|=OPUS_CPU_ARM_EDSP_FLAG; + } + __except(GetExceptionCode()==EXCEPTION_ILLEGAL_INSTRUCTION){ + /*Ignore exception.*/ + } +# if defined(OPUS_ARM_MAY_HAVE_MEDIA) \ + || defined(OPUS_ARM_MAY_HAVE_NEON) || defined(OPUS_ARM_MAY_HAVE_NEON_INTR) + __try{ + /*SHADD8 r3,r3,r3*/ + __emit(0xE6333F93); + flags|=OPUS_CPU_ARM_MEDIA_FLAG; + } + __except(GetExceptionCode()==EXCEPTION_ILLEGAL_INSTRUCTION){ + /*Ignore exception.*/ + } +# if defined(OPUS_ARM_MAY_HAVE_NEON) || defined(OPUS_ARM_MAY_HAVE_NEON_INTR) + __try{ + /*VORR q0,q0,q0*/ + __emit(0xF2200150); + flags|=OPUS_CPU_ARM_NEON_FLAG; + } + __except(GetExceptionCode()==EXCEPTION_ILLEGAL_INSTRUCTION){ + /*Ignore exception.*/ + } +# endif +# endif +# endif + return flags; +} + +#elif defined(__linux__) +/* Linux based */ +opus_uint32 opus_cpu_capabilities(void) +{ + opus_uint32 flags = 0; + FILE *cpuinfo; + + /* Reading /proc/self/auxv would be easier, but that doesn't work reliably on + * Android */ + cpuinfo = fopen("/proc/cpuinfo", "r"); + + if(cpuinfo != NULL) + { + /* 512 should be enough for anybody (it's even enough for all the flags that + * x86 has accumulated... so far). */ + char buf[512]; + + while(fgets(buf, 512, cpuinfo) != NULL) + { +# if defined(OPUS_ARM_MAY_HAVE_EDSP) || defined(OPUS_ARM_MAY_HAVE_MEDIA) \ + || defined(OPUS_ARM_MAY_HAVE_NEON) || defined(OPUS_ARM_MAY_HAVE_NEON_INTR) + /* Search for edsp and neon flag */ + if(memcmp(buf, "Features", 8) == 0) + { + char *p; + p = strstr(buf, " edsp"); + if(p != NULL && (p[5] == ' ' || p[5] == '\n')) + flags |= OPUS_CPU_ARM_EDSP_FLAG; + +# if defined(OPUS_ARM_MAY_HAVE_NEON) || defined(OPUS_ARM_MAY_HAVE_NEON_INTR) + p = strstr(buf, " neon"); + if(p != NULL && (p[5] == ' ' || p[5] == '\n')) + flags |= OPUS_CPU_ARM_NEON_FLAG; +# endif + } +# endif + +# if defined(OPUS_ARM_MAY_HAVE_MEDIA) \ + || defined(OPUS_ARM_MAY_HAVE_NEON) || defined(OPUS_ARM_MAY_HAVE_NEON_INTR) + /* Search for media capabilities (>= ARMv6) */ + if(memcmp(buf, "CPU architecture:", 17) == 0) + { + int version; + version = atoi(buf+17); + + if(version >= 6) + flags |= OPUS_CPU_ARM_MEDIA_FLAG; + } +# endif + } + + fclose(cpuinfo); + } + return flags; +} +#else +/* The feature registers which can tell us what the processor supports are + * accessible in priveleged modes only, so we can't have a general user-space + * detection method like on x86.*/ +# error "Configured to use ARM asm but no CPU detection method available for " \ + "your platform. Reconfigure with --disable-rtcd (or send patches)." +#endif + +int opus_select_arch(void) +{ + opus_uint32 flags = opus_cpu_capabilities(); + int arch = 0; + + if(!(flags & OPUS_CPU_ARM_EDSP_FLAG)) { + /* Asserts ensure arch values are sequential */ + celt_assert(arch == OPUS_ARCH_ARM_V4); + return arch; + } + arch++; + + if(!(flags & OPUS_CPU_ARM_MEDIA_FLAG)) { + celt_assert(arch == OPUS_ARCH_ARM_EDSP); + return arch; + } + arch++; + + if(!(flags & OPUS_CPU_ARM_NEON_FLAG)) { + celt_assert(arch == OPUS_ARCH_ARM_MEDIA); + return arch; + } + arch++; + + celt_assert(arch == OPUS_ARCH_ARM_NEON); + return arch; +} + +#endif diff --git a/extern/opus/celt/arm/armcpu.h b/extern/opus/celt/arm/armcpu.h new file mode 100644 index 0000000..820262f --- /dev/null +++ b/extern/opus/celt/arm/armcpu.h @@ -0,0 +1,77 @@ +/* Copyright (c) 2010 Xiph.Org Foundation + * Copyright (c) 2013 Parrot */ +/* + 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. + + 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 OWNER + 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. +*/ + +#if !defined(ARMCPU_H) +# define ARMCPU_H + +# if defined(OPUS_ARM_MAY_HAVE_EDSP) +# define MAY_HAVE_EDSP(name) name ## _edsp +# else +# define MAY_HAVE_EDSP(name) name ## _c +# endif + +# if defined(OPUS_ARM_MAY_HAVE_MEDIA) +# define MAY_HAVE_MEDIA(name) name ## _media +# else +# define MAY_HAVE_MEDIA(name) MAY_HAVE_EDSP(name) +# endif + +# if defined(OPUS_ARM_MAY_HAVE_NEON) +# define MAY_HAVE_NEON(name) name ## _neon +# else +# define MAY_HAVE_NEON(name) MAY_HAVE_MEDIA(name) +# endif + +# if defined(OPUS_ARM_PRESUME_EDSP) +# define PRESUME_EDSP(name) name ## _edsp +# else +# define PRESUME_EDSP(name) name ## _c +# endif + +# if defined(OPUS_ARM_PRESUME_MEDIA) +# define PRESUME_MEDIA(name) name ## _media +# else +# define PRESUME_MEDIA(name) PRESUME_EDSP(name) +# endif + +# if defined(OPUS_ARM_PRESUME_NEON) +# define PRESUME_NEON(name) name ## _neon +# else +# define PRESUME_NEON(name) PRESUME_MEDIA(name) +# endif + +# if defined(OPUS_HAVE_RTCD) +int opus_select_arch(void); + +#define OPUS_ARCH_ARM_V4 (0) +#define OPUS_ARCH_ARM_EDSP (1) +#define OPUS_ARCH_ARM_MEDIA (2) +#define OPUS_ARCH_ARM_NEON (3) + +# endif + +#endif diff --git a/extern/opus/celt/arm/armopts.s.in b/extern/opus/celt/arm/armopts.s.in new file mode 100644 index 0000000..3d8aaf2 --- /dev/null +++ b/extern/opus/celt/arm/armopts.s.in @@ -0,0 +1,37 @@ +/* Copyright (C) 2013 Mozilla Corporation */ +/* + 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. + + 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 OWNER + 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. +*/ + +; Set the following to 1 if we have EDSP instructions +; (LDRD/STRD, etc., ARMv5E and later). +OPUS_ARM_MAY_HAVE_EDSP * @OPUS_ARM_MAY_HAVE_EDSP@ + +; Set the following to 1 if we have ARMv6 media instructions. +OPUS_ARM_MAY_HAVE_MEDIA * @OPUS_ARM_MAY_HAVE_MEDIA@ + +; Set the following to 1 if we have NEON (some ARMv7) +OPUS_ARM_MAY_HAVE_NEON * @OPUS_ARM_MAY_HAVE_NEON@ + +END diff --git a/extern/opus/celt/arm/celt_fft_ne10.c b/extern/opus/celt/arm/celt_fft_ne10.c new file mode 100644 index 0000000..ea5fd78 --- /dev/null +++ b/extern/opus/celt/arm/celt_fft_ne10.c @@ -0,0 +1,173 @@ +/* Copyright (c) 2015 Xiph.Org Foundation + Written by Viswanath Puttagunta */ +/** + @file celt_fft_ne10.c + @brief ARM Neon optimizations for fft using NE10 library + */ + +/* + 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. + + 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 OWNER + 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. +*/ + +#ifndef SKIP_CONFIG_H +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#endif + +#include +#include "os_support.h" +#include "kiss_fft.h" +#include "stack_alloc.h" + +#if !defined(FIXED_POINT) +# define NE10_FFT_ALLOC_C2C_TYPE_NEON ne10_fft_alloc_c2c_float32_neon +# define NE10_FFT_CFG_TYPE_T ne10_fft_cfg_float32_t +# define NE10_FFT_STATE_TYPE_T ne10_fft_state_float32_t +# define NE10_FFT_DESTROY_C2C_TYPE ne10_fft_destroy_c2c_float32 +# define NE10_FFT_CPX_TYPE_T ne10_fft_cpx_float32_t +# define NE10_FFT_C2C_1D_TYPE_NEON ne10_fft_c2c_1d_float32_neon +#else +# define NE10_FFT_ALLOC_C2C_TYPE_NEON(nfft) ne10_fft_alloc_c2c_int32_neon(nfft) +# define NE10_FFT_CFG_TYPE_T ne10_fft_cfg_int32_t +# define NE10_FFT_STATE_TYPE_T ne10_fft_state_int32_t +# define NE10_FFT_DESTROY_C2C_TYPE ne10_fft_destroy_c2c_int32 +# define NE10_FFT_DESTROY_C2C_TYPE ne10_fft_destroy_c2c_int32 +# define NE10_FFT_CPX_TYPE_T ne10_fft_cpx_int32_t +# define NE10_FFT_C2C_1D_TYPE_NEON ne10_fft_c2c_1d_int32_neon +#endif + +#if defined(CUSTOM_MODES) + +/* nfft lengths in NE10 that support scaled fft */ +# define NE10_FFTSCALED_SUPPORT_MAX 4 +static const int ne10_fft_scaled_support[NE10_FFTSCALED_SUPPORT_MAX] = { + 480, 240, 120, 60 +}; + +int opus_fft_alloc_arm_neon(kiss_fft_state *st) +{ + int i; + size_t memneeded = sizeof(struct arch_fft_state); + + st->arch_fft = (arch_fft_state *)opus_alloc(memneeded); + if (!st->arch_fft) + return -1; + + for (i = 0; i < NE10_FFTSCALED_SUPPORT_MAX; i++) { + if(st->nfft == ne10_fft_scaled_support[i]) + break; + } + if (i == NE10_FFTSCALED_SUPPORT_MAX) { + /* This nfft length (scaled fft) is not supported in NE10 */ + st->arch_fft->is_supported = 0; + st->arch_fft->priv = NULL; + } + else { + st->arch_fft->is_supported = 1; + st->arch_fft->priv = (void *)NE10_FFT_ALLOC_C2C_TYPE_NEON(st->nfft); + if (st->arch_fft->priv == NULL) { + return -1; + } + } + return 0; +} + +void opus_fft_free_arm_neon(kiss_fft_state *st) +{ + NE10_FFT_CFG_TYPE_T cfg; + + if (!st->arch_fft) + return; + + cfg = (NE10_FFT_CFG_TYPE_T)st->arch_fft->priv; + if (cfg) + NE10_FFT_DESTROY_C2C_TYPE(cfg); + opus_free(st->arch_fft); +} +#endif + +void opus_fft_neon(const kiss_fft_state *st, + const kiss_fft_cpx *fin, + kiss_fft_cpx *fout) +{ + NE10_FFT_STATE_TYPE_T state; + NE10_FFT_CFG_TYPE_T cfg = &state; + VARDECL(NE10_FFT_CPX_TYPE_T, buffer); + SAVE_STACK; + ALLOC(buffer, st->nfft, NE10_FFT_CPX_TYPE_T); + + if (!st->arch_fft->is_supported) { + /* This nfft length (scaled fft) not supported in NE10 */ + opus_fft_c(st, fin, fout); + } + else { + memcpy((void *)cfg, st->arch_fft->priv, sizeof(NE10_FFT_STATE_TYPE_T)); + state.buffer = (NE10_FFT_CPX_TYPE_T *)&buffer[0]; +#if !defined(FIXED_POINT) + state.is_forward_scaled = 1; + + NE10_FFT_C2C_1D_TYPE_NEON((NE10_FFT_CPX_TYPE_T *)fout, + (NE10_FFT_CPX_TYPE_T *)fin, + cfg, 0); +#else + NE10_FFT_C2C_1D_TYPE_NEON((NE10_FFT_CPX_TYPE_T *)fout, + (NE10_FFT_CPX_TYPE_T *)fin, + cfg, 0, 1); +#endif + } + RESTORE_STACK; +} + +void opus_ifft_neon(const kiss_fft_state *st, + const kiss_fft_cpx *fin, + kiss_fft_cpx *fout) +{ + NE10_FFT_STATE_TYPE_T state; + NE10_FFT_CFG_TYPE_T cfg = &state; + VARDECL(NE10_FFT_CPX_TYPE_T, buffer); + SAVE_STACK; + ALLOC(buffer, st->nfft, NE10_FFT_CPX_TYPE_T); + + if (!st->arch_fft->is_supported) { + /* This nfft length (scaled fft) not supported in NE10 */ + opus_ifft_c(st, fin, fout); + } + else { + memcpy((void *)cfg, st->arch_fft->priv, sizeof(NE10_FFT_STATE_TYPE_T)); + state.buffer = (NE10_FFT_CPX_TYPE_T *)&buffer[0]; +#if !defined(FIXED_POINT) + state.is_backward_scaled = 0; + + NE10_FFT_C2C_1D_TYPE_NEON((NE10_FFT_CPX_TYPE_T *)fout, + (NE10_FFT_CPX_TYPE_T *)fin, + cfg, 1); +#else + NE10_FFT_C2C_1D_TYPE_NEON((NE10_FFT_CPX_TYPE_T *)fout, + (NE10_FFT_CPX_TYPE_T *)fin, + cfg, 1, 0); +#endif + } + RESTORE_STACK; +} diff --git a/extern/opus/celt/arm/celt_mdct_ne10.c b/extern/opus/celt/arm/celt_mdct_ne10.c new file mode 100644 index 0000000..3531d02 --- /dev/null +++ b/extern/opus/celt/arm/celt_mdct_ne10.c @@ -0,0 +1,258 @@ +/* Copyright (c) 2015 Xiph.Org Foundation + Written by Viswanath Puttagunta */ +/** + @file celt_mdct_ne10.c + @brief ARM Neon optimizations for mdct using NE10 library + */ + +/* + 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. + + 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 OWNER + 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. +*/ + +#ifndef SKIP_CONFIG_H +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#endif + +#include "kiss_fft.h" +#include "_kiss_fft_guts.h" +#include "mdct.h" +#include "stack_alloc.h" + +void clt_mdct_forward_neon(const mdct_lookup *l, + kiss_fft_scalar *in, + kiss_fft_scalar * OPUS_RESTRICT out, + const opus_val16 *window, + int overlap, int shift, int stride, int arch) +{ + int i; + int N, N2, N4; + VARDECL(kiss_fft_scalar, f); + VARDECL(kiss_fft_cpx, f2); + const kiss_fft_state *st = l->kfft[shift]; + const kiss_twiddle_scalar *trig; + + SAVE_STACK; + + N = l->n; + trig = l->trig; + for (i=0;i>= 1; + trig += N; + } + N2 = N>>1; + N4 = N>>2; + + ALLOC(f, N2, kiss_fft_scalar); + ALLOC(f2, N4, kiss_fft_cpx); + + /* Consider the input to be composed of four blocks: [a, b, c, d] */ + /* Window, shuffle, fold */ + { + /* Temp pointers to make it really clear to the compiler what we're doing */ + const kiss_fft_scalar * OPUS_RESTRICT xp1 = in+(overlap>>1); + const kiss_fft_scalar * OPUS_RESTRICT xp2 = in+N2-1+(overlap>>1); + kiss_fft_scalar * OPUS_RESTRICT yp = f; + const opus_val16 * OPUS_RESTRICT wp1 = window+(overlap>>1); + const opus_val16 * OPUS_RESTRICT wp2 = window+(overlap>>1)-1; + for(i=0;i<((overlap+3)>>2);i++) + { + /* Real part arranged as -d-cR, Imag part arranged as -b+aR*/ + *yp++ = MULT16_32_Q15(*wp2, xp1[N2]) + MULT16_32_Q15(*wp1,*xp2); + *yp++ = MULT16_32_Q15(*wp1, *xp1) - MULT16_32_Q15(*wp2, xp2[-N2]); + xp1+=2; + xp2-=2; + wp1+=2; + wp2-=2; + } + wp1 = window; + wp2 = window+overlap-1; + for(;i>2);i++) + { + /* Real part arranged as a-bR, Imag part arranged as -c-dR */ + *yp++ = *xp2; + *yp++ = *xp1; + xp1+=2; + xp2-=2; + } + for(;ii,t[N4+i]) - S_MUL(fp->r,t[i]); + yi = S_MUL(fp->r,t[N4+i]) + S_MUL(fp->i,t[i]); + *yp1 = yr; + *yp2 = yi; + fp++; + yp1 += 2*stride; + yp2 -= 2*stride; + } + } + RESTORE_STACK; +} + +void clt_mdct_backward_neon(const mdct_lookup *l, + kiss_fft_scalar *in, + kiss_fft_scalar * OPUS_RESTRICT out, + const opus_val16 * OPUS_RESTRICT window, + int overlap, int shift, int stride, int arch) +{ + int i; + int N, N2, N4; + VARDECL(kiss_fft_scalar, f); + const kiss_twiddle_scalar *trig; + const kiss_fft_state *st = l->kfft[shift]; + + N = l->n; + trig = l->trig; + for (i=0;i>= 1; + trig += N; + } + N2 = N>>1; + N4 = N>>2; + + ALLOC(f, N2, kiss_fft_scalar); + + /* Pre-rotate */ + { + /* Temp pointers to make it really clear to the compiler what we're doing */ + const kiss_fft_scalar * OPUS_RESTRICT xp1 = in; + const kiss_fft_scalar * OPUS_RESTRICT xp2 = in+stride*(N2-1); + kiss_fft_scalar * OPUS_RESTRICT yp = f; + const kiss_twiddle_scalar * OPUS_RESTRICT t = &trig[0]; + for(i=0;i>1)), arch); + + /* Post-rotate and de-shuffle from both ends of the buffer at once to make + it in-place. */ + { + kiss_fft_scalar * yp0 = out+(overlap>>1); + kiss_fft_scalar * yp1 = out+(overlap>>1)+N2-2; + const kiss_twiddle_scalar *t = &trig[0]; + /* Loop to (N4+1)>>1 to handle odd N4. When N4 is odd, the + middle pair will be computed twice. */ + for(i=0;i<(N4+1)>>1;i++) + { + kiss_fft_scalar re, im, yr, yi; + kiss_twiddle_scalar t0, t1; + re = yp0[0]; + im = yp0[1]; + t0 = t[i]; + t1 = t[N4+i]; + /* We'd scale up by 2 here, but instead it's done when mixing the windows */ + yr = S_MUL(re,t0) + S_MUL(im,t1); + yi = S_MUL(re,t1) - S_MUL(im,t0); + re = yp1[0]; + im = yp1[1]; + yp0[0] = yr; + yp1[1] = yi; + + t0 = t[(N4-i-1)]; + t1 = t[(N2-i-1)]; + /* We'd scale up by 2 here, but instead it's done when mixing the windows */ + yr = S_MUL(re,t0) + S_MUL(im,t1); + yi = S_MUL(re,t1) - S_MUL(im,t0); + yp1[0] = yr; + yp0[1] = yi; + yp0 += 2; + yp1 -= 2; + } + } + + /* Mirror on both sides for TDAC */ + { + kiss_fft_scalar * OPUS_RESTRICT xp1 = out+overlap-1; + kiss_fft_scalar * OPUS_RESTRICT yp1 = out; + const opus_val16 * OPUS_RESTRICT wp1 = window; + const opus_val16 * OPUS_RESTRICT wp2 = window+overlap-1; + + for(i = 0; i < overlap/2; i++) + { + kiss_fft_scalar x1, x2; + x1 = *xp1; + x2 = *yp1; + *yp1++ = MULT16_32_Q15(*wp2, x2) - MULT16_32_Q15(*wp1, x1); + *xp1-- = MULT16_32_Q15(*wp1, x2) + MULT16_32_Q15(*wp2, x1); + wp1++; + wp2--; + } + } + RESTORE_STACK; +} diff --git a/extern/opus/celt/arm/celt_neon_intr.c b/extern/opus/celt/arm/celt_neon_intr.c new file mode 100644 index 0000000..effda76 --- /dev/null +++ b/extern/opus/celt/arm/celt_neon_intr.c @@ -0,0 +1,211 @@ +/* Copyright (c) 2014-2015 Xiph.Org Foundation + Written by Viswanath Puttagunta */ +/** + @file celt_neon_intr.c + @brief ARM Neon Intrinsic optimizations for celt + */ + +/* + 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. + + 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 OWNER + 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. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "../pitch.h" + +#if defined(FIXED_POINT) +void xcorr_kernel_neon_fixed(const opus_val16 * x, const opus_val16 * y, opus_val32 sum[4], int len) +{ + int j; + int32x4_t a = vld1q_s32(sum); + /* Load y[0...3] */ + /* This requires len>0 to always be valid (which we assert in the C code). */ + int16x4_t y0 = vld1_s16(y); + y += 4; + + for (j = 0; j + 8 <= len; j += 8) + { + /* Load x[0...7] */ + int16x8_t xx = vld1q_s16(x); + int16x4_t x0 = vget_low_s16(xx); + int16x4_t x4 = vget_high_s16(xx); + /* Load y[4...11] */ + int16x8_t yy = vld1q_s16(y); + int16x4_t y4 = vget_low_s16(yy); + int16x4_t y8 = vget_high_s16(yy); + int32x4_t a0 = vmlal_lane_s16(a, y0, x0, 0); + int32x4_t a1 = vmlal_lane_s16(a0, y4, x4, 0); + + int16x4_t y1 = vext_s16(y0, y4, 1); + int16x4_t y5 = vext_s16(y4, y8, 1); + int32x4_t a2 = vmlal_lane_s16(a1, y1, x0, 1); + int32x4_t a3 = vmlal_lane_s16(a2, y5, x4, 1); + + int16x4_t y2 = vext_s16(y0, y4, 2); + int16x4_t y6 = vext_s16(y4, y8, 2); + int32x4_t a4 = vmlal_lane_s16(a3, y2, x0, 2); + int32x4_t a5 = vmlal_lane_s16(a4, y6, x4, 2); + + int16x4_t y3 = vext_s16(y0, y4, 3); + int16x4_t y7 = vext_s16(y4, y8, 3); + int32x4_t a6 = vmlal_lane_s16(a5, y3, x0, 3); + int32x4_t a7 = vmlal_lane_s16(a6, y7, x4, 3); + + y0 = y8; + a = a7; + x += 8; + y += 8; + } + + for (; j < len; j++) + { + int16x4_t x0 = vld1_dup_s16(x); /* load next x */ + int32x4_t a0 = vmlal_s16(a, y0, x0); + + int16x4_t y4 = vld1_dup_s16(y); /* load next y */ + y0 = vext_s16(y0, y4, 1); + a = a0; + x++; + y++; + } + + vst1q_s32(sum, a); +} + +#else +/* + * Function: xcorr_kernel_neon_float + * --------------------------------- + * Computes 4 correlation values and stores them in sum[4] + */ +static void xcorr_kernel_neon_float(const float32_t *x, const float32_t *y, + float32_t sum[4], int len) { + float32x4_t YY[3]; + float32x4_t YEXT[3]; + float32x4_t XX[2]; + float32x2_t XX_2; + float32x4_t SUMM; + const float32_t *xi = x; + const float32_t *yi = y; + + celt_assert(len>0); + + YY[0] = vld1q_f32(yi); + SUMM = vdupq_n_f32(0); + + /* Consume 8 elements in x vector and 12 elements in y + * vector. However, the 12'th element never really gets + * touched in this loop. So, if len == 8, then we only + * must access y[0] to y[10]. y[11] must not be accessed + * hence make sure len > 8 and not len >= 8 + */ + while (len > 8) { + yi += 4; + YY[1] = vld1q_f32(yi); + yi += 4; + YY[2] = vld1q_f32(yi); + + XX[0] = vld1q_f32(xi); + xi += 4; + XX[1] = vld1q_f32(xi); + xi += 4; + + SUMM = vmlaq_lane_f32(SUMM, YY[0], vget_low_f32(XX[0]), 0); + YEXT[0] = vextq_f32(YY[0], YY[1], 1); + SUMM = vmlaq_lane_f32(SUMM, YEXT[0], vget_low_f32(XX[0]), 1); + YEXT[1] = vextq_f32(YY[0], YY[1], 2); + SUMM = vmlaq_lane_f32(SUMM, YEXT[1], vget_high_f32(XX[0]), 0); + YEXT[2] = vextq_f32(YY[0], YY[1], 3); + SUMM = vmlaq_lane_f32(SUMM, YEXT[2], vget_high_f32(XX[0]), 1); + + SUMM = vmlaq_lane_f32(SUMM, YY[1], vget_low_f32(XX[1]), 0); + YEXT[0] = vextq_f32(YY[1], YY[2], 1); + SUMM = vmlaq_lane_f32(SUMM, YEXT[0], vget_low_f32(XX[1]), 1); + YEXT[1] = vextq_f32(YY[1], YY[2], 2); + SUMM = vmlaq_lane_f32(SUMM, YEXT[1], vget_high_f32(XX[1]), 0); + YEXT[2] = vextq_f32(YY[1], YY[2], 3); + SUMM = vmlaq_lane_f32(SUMM, YEXT[2], vget_high_f32(XX[1]), 1); + + YY[0] = YY[2]; + len -= 8; + } + + /* Consume 4 elements in x vector and 8 elements in y + * vector. However, the 8'th element in y never really gets + * touched in this loop. So, if len == 4, then we only + * must access y[0] to y[6]. y[7] must not be accessed + * hence make sure len>4 and not len>=4 + */ + if (len > 4) { + yi += 4; + YY[1] = vld1q_f32(yi); + + XX[0] = vld1q_f32(xi); + xi += 4; + + SUMM = vmlaq_lane_f32(SUMM, YY[0], vget_low_f32(XX[0]), 0); + YEXT[0] = vextq_f32(YY[0], YY[1], 1); + SUMM = vmlaq_lane_f32(SUMM, YEXT[0], vget_low_f32(XX[0]), 1); + YEXT[1] = vextq_f32(YY[0], YY[1], 2); + SUMM = vmlaq_lane_f32(SUMM, YEXT[1], vget_high_f32(XX[0]), 0); + YEXT[2] = vextq_f32(YY[0], YY[1], 3); + SUMM = vmlaq_lane_f32(SUMM, YEXT[2], vget_high_f32(XX[0]), 1); + + YY[0] = YY[1]; + len -= 4; + } + + while (--len > 0) { + XX_2 = vld1_dup_f32(xi++); + SUMM = vmlaq_lane_f32(SUMM, YY[0], XX_2, 0); + YY[0]= vld1q_f32(++yi); + } + + XX_2 = vld1_dup_f32(xi); + SUMM = vmlaq_lane_f32(SUMM, YY[0], XX_2, 0); + + vst1q_f32(sum, SUMM); +} + +void celt_pitch_xcorr_float_neon(const opus_val16 *_x, const opus_val16 *_y, + opus_val32 *xcorr, int len, int max_pitch, int arch) { + int i; + (void)arch; + celt_assert(max_pitch > 0); + celt_sig_assert((((unsigned char *)_x-(unsigned char *)NULL)&3)==0); + + for (i = 0; i < (max_pitch-3); i += 4) { + xcorr_kernel_neon_float((const float32_t *)_x, (const float32_t *)_y+i, + (float32_t *)xcorr+i, len); + } + + /* In case max_pitch isn't a multiple of 4, do non-unrolled version. */ + for (; i < max_pitch; i++) { + xcorr[i] = celt_inner_prod_neon(_x, _y+i, len); + } +} +#endif diff --git a/extern/opus/celt/arm/celt_pitch_xcorr_arm.s b/extern/opus/celt/arm/celt_pitch_xcorr_arm.s new file mode 100644 index 0000000..6e873af --- /dev/null +++ b/extern/opus/celt/arm/celt_pitch_xcorr_arm.s @@ -0,0 +1,551 @@ +; Copyright (c) 2007-2008 CSIRO +; Copyright (c) 2007-2009 Xiph.Org Foundation +; Copyright (c) 2013 Parrot +; Written by Aurélien Zanelli +; +; 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. +; +; 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 OWNER +; 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. + + AREA |.text|, CODE, READONLY + + GET celt/arm/armopts.s + +IF OPUS_ARM_MAY_HAVE_EDSP + EXPORT celt_pitch_xcorr_edsp +ENDIF + +IF OPUS_ARM_MAY_HAVE_NEON + EXPORT celt_pitch_xcorr_neon +ENDIF + +IF OPUS_ARM_MAY_HAVE_NEON + +; Compute sum[k]=sum(x[j]*y[j+k],j=0...len-1), k=0...3 +xcorr_kernel_neon PROC +xcorr_kernel_neon_start + ; input: + ; r3 = int len + ; r4 = opus_val16 *x + ; r5 = opus_val16 *y + ; q0 = opus_val32 sum[4] + ; output: + ; q0 = opus_val32 sum[4] + ; preserved: r0-r3, r6-r11, d2, q4-q7, q9-q15 + ; internal usage: + ; r12 = int j + ; d3 = y_3|y_2|y_1|y_0 + ; q2 = y_B|y_A|y_9|y_8|y_7|y_6|y_5|y_4 + ; q3 = x_7|x_6|x_5|x_4|x_3|x_2|x_1|x_0 + ; q8 = scratch + ; + ; Load y[0...3] + ; This requires len>0 to always be valid (which we assert in the C code). + VLD1.16 {d5}, [r5]! + SUBS r12, r3, #8 + BLE xcorr_kernel_neon_process4 +; Process 8 samples at a time. +; This loop loads one y value more than we actually need. Therefore we have to +; stop as soon as there are 8 or fewer samples left (instead of 7), to avoid +; reading past the end of the array. +xcorr_kernel_neon_process8 + ; This loop has 19 total instructions (10 cycles to issue, minimum), with + ; - 2 cycles of ARM insrtuctions, + ; - 10 cycles of load/store/byte permute instructions, and + ; - 9 cycles of data processing instructions. + ; On a Cortex A8, we dual-issue the maximum amount (9 cycles) between the + ; latter two categories, meaning the whole loop should run in 10 cycles per + ; iteration, barring cache misses. + ; + ; Load x[0...7] + VLD1.16 {d6, d7}, [r4]! + ; Unlike VMOV, VAND is a data processsing instruction (and doesn't get + ; assembled to VMOV, like VORR would), so it dual-issues with the prior VLD1. + VAND d3, d5, d5 + SUBS r12, r12, #8 + ; Load y[4...11] + VLD1.16 {d4, d5}, [r5]! + VMLAL.S16 q0, d3, d6[0] + VEXT.16 d16, d3, d4, #1 + VMLAL.S16 q0, d4, d7[0] + VEXT.16 d17, d4, d5, #1 + VMLAL.S16 q0, d16, d6[1] + VEXT.16 d16, d3, d4, #2 + VMLAL.S16 q0, d17, d7[1] + VEXT.16 d17, d4, d5, #2 + VMLAL.S16 q0, d16, d6[2] + VEXT.16 d16, d3, d4, #3 + VMLAL.S16 q0, d17, d7[2] + VEXT.16 d17, d4, d5, #3 + VMLAL.S16 q0, d16, d6[3] + VMLAL.S16 q0, d17, d7[3] + BGT xcorr_kernel_neon_process8 +; Process 4 samples here if we have > 4 left (still reading one extra y value). +xcorr_kernel_neon_process4 + ADDS r12, r12, #4 + BLE xcorr_kernel_neon_process2 + ; Load x[0...3] + VLD1.16 d6, [r4]! + ; Use VAND since it's a data processing instruction again. + VAND d4, d5, d5 + SUB r12, r12, #4 + ; Load y[4...7] + VLD1.16 d5, [r5]! + VMLAL.S16 q0, d4, d6[0] + VEXT.16 d16, d4, d5, #1 + VMLAL.S16 q0, d16, d6[1] + VEXT.16 d16, d4, d5, #2 + VMLAL.S16 q0, d16, d6[2] + VEXT.16 d16, d4, d5, #3 + VMLAL.S16 q0, d16, d6[3] +; Process 2 samples here if we have > 2 left (still reading one extra y value). +xcorr_kernel_neon_process2 + ADDS r12, r12, #2 + BLE xcorr_kernel_neon_process1 + ; Load x[0...1] + VLD2.16 {d6[],d7[]}, [r4]! + ; Use VAND since it's a data processing instruction again. + VAND d4, d5, d5 + SUB r12, r12, #2 + ; Load y[4...5] + VLD1.32 {d5[]}, [r5]! + VMLAL.S16 q0, d4, d6 + VEXT.16 d16, d4, d5, #1 + ; Replace bottom copy of {y5,y4} in d5 with {y3,y2} from d4, using VSRI + ; instead of VEXT, since it's a data-processing instruction. + VSRI.64 d5, d4, #32 + VMLAL.S16 q0, d16, d7 +; Process 1 sample using the extra y value we loaded above. +xcorr_kernel_neon_process1 + ; Load next *x + VLD1.16 {d6[]}, [r4]! + ADDS r12, r12, #1 + ; y[0...3] are left in d5 from prior iteration(s) (if any) + VMLAL.S16 q0, d5, d6 + MOVLE pc, lr +; Now process 1 last sample, not reading ahead. + ; Load last *y + VLD1.16 {d4[]}, [r5]! + VSRI.64 d4, d5, #16 + ; Load last *x + VLD1.16 {d6[]}, [r4]! + VMLAL.S16 q0, d4, d6 + MOV pc, lr + ENDP + +; opus_val32 celt_pitch_xcorr_neon(opus_val16 *_x, opus_val16 *_y, +; opus_val32 *xcorr, int len, int max_pitch, int arch) +celt_pitch_xcorr_neon PROC + ; input: + ; r0 = opus_val16 *_x + ; r1 = opus_val16 *_y + ; r2 = opus_val32 *xcorr + ; r3 = int len + ; output: + ; r0 = int maxcorr + ; internal usage: + ; r4 = opus_val16 *x (for xcorr_kernel_neon()) + ; r5 = opus_val16 *y (for xcorr_kernel_neon()) + ; r6 = int max_pitch + ; r12 = int j + ; q15 = int maxcorr[4] (q15 is not used by xcorr_kernel_neon()) + ; ignored: + ; int arch + STMFD sp!, {r4-r6, lr} + LDR r6, [sp, #16] + VMOV.S32 q15, #1 + ; if (max_pitch < 4) goto celt_pitch_xcorr_neon_process4_done + SUBS r6, r6, #4 + BLT celt_pitch_xcorr_neon_process4_done +celt_pitch_xcorr_neon_process4 + ; xcorr_kernel_neon parameters: + ; r3 = len, r4 = _x, r5 = _y, q0 = {0, 0, 0, 0} + MOV r4, r0 + MOV r5, r1 + VEOR q0, q0, q0 + ; xcorr_kernel_neon only modifies r4, r5, r12, and q0...q3. + ; So we don't save/restore any other registers. + BL xcorr_kernel_neon_start + SUBS r6, r6, #4 + VST1.32 {q0}, [r2]! + ; _y += 4 + ADD r1, r1, #8 + VMAX.S32 q15, q15, q0 + ; if (max_pitch < 4) goto celt_pitch_xcorr_neon_process4_done + BGE celt_pitch_xcorr_neon_process4 +; We have less than 4 sums left to compute. +celt_pitch_xcorr_neon_process4_done + ADDS r6, r6, #4 + ; Reduce maxcorr to a single value + VMAX.S32 d30, d30, d31 + VPMAX.S32 d30, d30, d30 + ; if (max_pitch <= 0) goto celt_pitch_xcorr_neon_done + BLE celt_pitch_xcorr_neon_done +; Now compute each remaining sum one at a time. +celt_pitch_xcorr_neon_process_remaining + MOV r4, r0 + MOV r5, r1 + VMOV.I32 q0, #0 + SUBS r12, r3, #8 + BLT celt_pitch_xcorr_neon_process_remaining4 +; Sum terms 8 at a time. +celt_pitch_xcorr_neon_process_remaining_loop8 + ; Load x[0...7] + VLD1.16 {q1}, [r4]! + ; Load y[0...7] + VLD1.16 {q2}, [r5]! + SUBS r12, r12, #8 + VMLAL.S16 q0, d4, d2 + VMLAL.S16 q0, d5, d3 + BGE celt_pitch_xcorr_neon_process_remaining_loop8 +; Sum terms 4 at a time. +celt_pitch_xcorr_neon_process_remaining4 + ADDS r12, r12, #4 + BLT celt_pitch_xcorr_neon_process_remaining4_done + ; Load x[0...3] + VLD1.16 {d2}, [r4]! + ; Load y[0...3] + VLD1.16 {d3}, [r5]! + SUB r12, r12, #4 + VMLAL.S16 q0, d3, d2 +celt_pitch_xcorr_neon_process_remaining4_done + ; Reduce the sum to a single value. + VADD.S32 d0, d0, d1 + VPADDL.S32 d0, d0 + ADDS r12, r12, #4 + BLE celt_pitch_xcorr_neon_process_remaining_loop_done +; Sum terms 1 at a time. +celt_pitch_xcorr_neon_process_remaining_loop1 + VLD1.16 {d2[]}, [r4]! + VLD1.16 {d3[]}, [r5]! + SUBS r12, r12, #1 + VMLAL.S16 q0, d2, d3 + BGT celt_pitch_xcorr_neon_process_remaining_loop1 +celt_pitch_xcorr_neon_process_remaining_loop_done + VST1.32 {d0[0]}, [r2]! + VMAX.S32 d30, d30, d0 + SUBS r6, r6, #1 + ; _y++ + ADD r1, r1, #2 + ; if (--max_pitch > 0) goto celt_pitch_xcorr_neon_process_remaining + BGT celt_pitch_xcorr_neon_process_remaining +celt_pitch_xcorr_neon_done + VMOV.32 r0, d30[0] + LDMFD sp!, {r4-r6, pc} + ENDP + +ENDIF + +IF OPUS_ARM_MAY_HAVE_EDSP + +; This will get used on ARMv7 devices without NEON, so it has been optimized +; to take advantage of dual-issuing where possible. +xcorr_kernel_edsp PROC +xcorr_kernel_edsp_start + ; input: + ; r3 = int len + ; r4 = opus_val16 *_x (must be 32-bit aligned) + ; r5 = opus_val16 *_y (must be 32-bit aligned) + ; r6...r9 = opus_val32 sum[4] + ; output: + ; r6...r9 = opus_val32 sum[4] + ; preserved: r0-r5 + ; internal usage + ; r2 = int j + ; r12,r14 = opus_val16 x[4] + ; r10,r11 = opus_val16 y[4] + STMFD sp!, {r2,r4,r5,lr} + LDR r10, [r5], #4 ; Load y[0...1] + SUBS r2, r3, #4 ; j = len-4 + LDR r11, [r5], #4 ; Load y[2...3] + BLE xcorr_kernel_edsp_process4_done + LDR r12, [r4], #4 ; Load x[0...1] + ; Stall +xcorr_kernel_edsp_process4 + ; The multiplies must issue from pipeline 0, and can't dual-issue with each + ; other. Every other instruction here dual-issues with a multiply, and is + ; thus "free". There should be no stalls in the body of the loop. + SMLABB r6, r12, r10, r6 ; sum[0] = MAC16_16(sum[0],x_0,y_0) + LDR r14, [r4], #4 ; Load x[2...3] + SMLABT r7, r12, r10, r7 ; sum[1] = MAC16_16(sum[1],x_0,y_1) + SUBS r2, r2, #4 ; j-=4 + SMLABB r8, r12, r11, r8 ; sum[2] = MAC16_16(sum[2],x_0,y_2) + SMLABT r9, r12, r11, r9 ; sum[3] = MAC16_16(sum[3],x_0,y_3) + SMLATT r6, r12, r10, r6 ; sum[0] = MAC16_16(sum[0],x_1,y_1) + LDR r10, [r5], #4 ; Load y[4...5] + SMLATB r7, r12, r11, r7 ; sum[1] = MAC16_16(sum[1],x_1,y_2) + SMLATT r8, r12, r11, r8 ; sum[2] = MAC16_16(sum[2],x_1,y_3) + SMLATB r9, r12, r10, r9 ; sum[3] = MAC16_16(sum[3],x_1,y_4) + LDRGT r12, [r4], #4 ; Load x[0...1] + SMLABB r6, r14, r11, r6 ; sum[0] = MAC16_16(sum[0],x_2,y_2) + SMLABT r7, r14, r11, r7 ; sum[1] = MAC16_16(sum[1],x_2,y_3) + SMLABB r8, r14, r10, r8 ; sum[2] = MAC16_16(sum[2],x_2,y_4) + SMLABT r9, r14, r10, r9 ; sum[3] = MAC16_16(sum[3],x_2,y_5) + SMLATT r6, r14, r11, r6 ; sum[0] = MAC16_16(sum[0],x_3,y_3) + LDR r11, [r5], #4 ; Load y[6...7] + SMLATB r7, r14, r10, r7 ; sum[1] = MAC16_16(sum[1],x_3,y_4) + SMLATT r8, r14, r10, r8 ; sum[2] = MAC16_16(sum[2],x_3,y_5) + SMLATB r9, r14, r11, r9 ; sum[3] = MAC16_16(sum[3],x_3,y_6) + BGT xcorr_kernel_edsp_process4 +xcorr_kernel_edsp_process4_done + ADDS r2, r2, #4 + BLE xcorr_kernel_edsp_done + LDRH r12, [r4], #2 ; r12 = *x++ + SUBS r2, r2, #1 ; j-- + ; Stall + SMLABB r6, r12, r10, r6 ; sum[0] = MAC16_16(sum[0],x,y_0) + LDRHGT r14, [r4], #2 ; r14 = *x++ + SMLABT r7, r12, r10, r7 ; sum[1] = MAC16_16(sum[1],x,y_1) + SMLABB r8, r12, r11, r8 ; sum[2] = MAC16_16(sum[2],x,y_2) + SMLABT r9, r12, r11, r9 ; sum[3] = MAC16_16(sum[3],x,y_3) + BLE xcorr_kernel_edsp_done + SMLABT r6, r14, r10, r6 ; sum[0] = MAC16_16(sum[0],x,y_1) + SUBS r2, r2, #1 ; j-- + SMLABB r7, r14, r11, r7 ; sum[1] = MAC16_16(sum[1],x,y_2) + LDRH r10, [r5], #2 ; r10 = y_4 = *y++ + SMLABT r8, r14, r11, r8 ; sum[2] = MAC16_16(sum[2],x,y_3) + LDRHGT r12, [r4], #2 ; r12 = *x++ + SMLABB r9, r14, r10, r9 ; sum[3] = MAC16_16(sum[3],x,y_4) + BLE xcorr_kernel_edsp_done + SMLABB r6, r12, r11, r6 ; sum[0] = MAC16_16(sum[0],tmp,y_2) + CMP r2, #1 ; j-- + SMLABT r7, r12, r11, r7 ; sum[1] = MAC16_16(sum[1],tmp,y_3) + LDRH r2, [r5], #2 ; r2 = y_5 = *y++ + SMLABB r8, r12, r10, r8 ; sum[2] = MAC16_16(sum[2],tmp,y_4) + LDRHGT r14, [r4] ; r14 = *x + SMLABB r9, r12, r2, r9 ; sum[3] = MAC16_16(sum[3],tmp,y_5) + BLE xcorr_kernel_edsp_done + SMLABT r6, r14, r11, r6 ; sum[0] = MAC16_16(sum[0],tmp,y_3) + LDRH r11, [r5] ; r11 = y_6 = *y + SMLABB r7, r14, r10, r7 ; sum[1] = MAC16_16(sum[1],tmp,y_4) + SMLABB r8, r14, r2, r8 ; sum[2] = MAC16_16(sum[2],tmp,y_5) + SMLABB r9, r14, r11, r9 ; sum[3] = MAC16_16(sum[3],tmp,y_6) +xcorr_kernel_edsp_done + LDMFD sp!, {r2,r4,r5,pc} + ENDP + +celt_pitch_xcorr_edsp PROC + ; input: + ; r0 = opus_val16 *_x (must be 32-bit aligned) + ; r1 = opus_val16 *_y (only needs to be 16-bit aligned) + ; r2 = opus_val32 *xcorr + ; r3 = int len + ; output: + ; r0 = maxcorr + ; internal usage + ; r4 = opus_val16 *x + ; r5 = opus_val16 *y + ; r6 = opus_val32 sum0 + ; r7 = opus_val32 sum1 + ; r8 = opus_val32 sum2 + ; r9 = opus_val32 sum3 + ; r1 = int max_pitch + ; r12 = int j + ; ignored: + ; int arch + STMFD sp!, {r4-r11, lr} + MOV r5, r1 + LDR r1, [sp, #36] + MOV r4, r0 + TST r5, #3 + ; maxcorr = 1 + MOV r0, #1 + BEQ celt_pitch_xcorr_edsp_process1u_done +; Compute one sum at the start to make y 32-bit aligned. + SUBS r12, r3, #4 + ; r14 = sum = 0 + MOV r14, #0 + LDRH r8, [r5], #2 + BLE celt_pitch_xcorr_edsp_process1u_loop4_done + LDR r6, [r4], #4 + MOV r8, r8, LSL #16 +celt_pitch_xcorr_edsp_process1u_loop4 + LDR r9, [r5], #4 + SMLABT r14, r6, r8, r14 ; sum = MAC16_16(sum, x_0, y_0) + LDR r7, [r4], #4 + SMLATB r14, r6, r9, r14 ; sum = MAC16_16(sum, x_1, y_1) + LDR r8, [r5], #4 + SMLABT r14, r7, r9, r14 ; sum = MAC16_16(sum, x_2, y_2) + SUBS r12, r12, #4 ; j-=4 + SMLATB r14, r7, r8, r14 ; sum = MAC16_16(sum, x_3, y_3) + LDRGT r6, [r4], #4 + BGT celt_pitch_xcorr_edsp_process1u_loop4 + MOV r8, r8, LSR #16 +celt_pitch_xcorr_edsp_process1u_loop4_done + ADDS r12, r12, #4 +celt_pitch_xcorr_edsp_process1u_loop1 + LDRHGE r6, [r4], #2 + ; Stall + SMLABBGE r14, r6, r8, r14 ; sum = MAC16_16(sum, *x, *y) + SUBSGE r12, r12, #1 + LDRHGT r8, [r5], #2 + BGT celt_pitch_xcorr_edsp_process1u_loop1 + ; Restore _x + SUB r4, r4, r3, LSL #1 + ; Restore and advance _y + SUB r5, r5, r3, LSL #1 + ; maxcorr = max(maxcorr, sum) + CMP r0, r14 + ADD r5, r5, #2 + MOVLT r0, r14 + SUBS r1, r1, #1 + ; xcorr[i] = sum + STR r14, [r2], #4 + BLE celt_pitch_xcorr_edsp_done +celt_pitch_xcorr_edsp_process1u_done + ; if (max_pitch < 4) goto celt_pitch_xcorr_edsp_process2 + SUBS r1, r1, #4 + BLT celt_pitch_xcorr_edsp_process2 +celt_pitch_xcorr_edsp_process4 + ; xcorr_kernel_edsp parameters: + ; r3 = len, r4 = _x, r5 = _y, r6...r9 = sum[4] = {0, 0, 0, 0} + MOV r6, #0 + MOV r7, #0 + MOV r8, #0 + MOV r9, #0 + BL xcorr_kernel_edsp_start ; xcorr_kernel_edsp(_x, _y+i, xcorr+i, len) + ; maxcorr = max(maxcorr, sum0, sum1, sum2, sum3) + CMP r0, r6 + ; _y+=4 + ADD r5, r5, #8 + MOVLT r0, r6 + CMP r0, r7 + MOVLT r0, r7 + CMP r0, r8 + MOVLT r0, r8 + CMP r0, r9 + MOVLT r0, r9 + STMIA r2!, {r6-r9} + SUBS r1, r1, #4 + BGE celt_pitch_xcorr_edsp_process4 +celt_pitch_xcorr_edsp_process2 + ADDS r1, r1, #2 + BLT celt_pitch_xcorr_edsp_process1a + SUBS r12, r3, #4 + ; {r10, r11} = {sum0, sum1} = {0, 0} + MOV r10, #0 + MOV r11, #0 + LDR r8, [r5], #4 + BLE celt_pitch_xcorr_edsp_process2_loop_done + LDR r6, [r4], #4 + LDR r9, [r5], #4 +celt_pitch_xcorr_edsp_process2_loop4 + SMLABB r10, r6, r8, r10 ; sum0 = MAC16_16(sum0, x_0, y_0) + LDR r7, [r4], #4 + SMLABT r11, r6, r8, r11 ; sum1 = MAC16_16(sum1, x_0, y_1) + SUBS r12, r12, #4 ; j-=4 + SMLATT r10, r6, r8, r10 ; sum0 = MAC16_16(sum0, x_1, y_1) + LDR r8, [r5], #4 + SMLATB r11, r6, r9, r11 ; sum1 = MAC16_16(sum1, x_1, y_2) + LDRGT r6, [r4], #4 + SMLABB r10, r7, r9, r10 ; sum0 = MAC16_16(sum0, x_2, y_2) + SMLABT r11, r7, r9, r11 ; sum1 = MAC16_16(sum1, x_2, y_3) + SMLATT r10, r7, r9, r10 ; sum0 = MAC16_16(sum0, x_3, y_3) + LDRGT r9, [r5], #4 + SMLATB r11, r7, r8, r11 ; sum1 = MAC16_16(sum1, x_3, y_4) + BGT celt_pitch_xcorr_edsp_process2_loop4 +celt_pitch_xcorr_edsp_process2_loop_done + ADDS r12, r12, #2 + BLE celt_pitch_xcorr_edsp_process2_1 + LDR r6, [r4], #4 + ; Stall + SMLABB r10, r6, r8, r10 ; sum0 = MAC16_16(sum0, x_0, y_0) + LDR r9, [r5], #4 + SMLABT r11, r6, r8, r11 ; sum1 = MAC16_16(sum1, x_0, y_1) + SUB r12, r12, #2 + SMLATT r10, r6, r8, r10 ; sum0 = MAC16_16(sum0, x_1, y_1) + MOV r8, r9 + SMLATB r11, r6, r9, r11 ; sum1 = MAC16_16(sum1, x_1, y_2) +celt_pitch_xcorr_edsp_process2_1 + LDRH r6, [r4], #2 + ADDS r12, r12, #1 + ; Stall + SMLABB r10, r6, r8, r10 ; sum0 = MAC16_16(sum0, x_0, y_0) + LDRHGT r7, [r4], #2 + SMLABT r11, r6, r8, r11 ; sum1 = MAC16_16(sum1, x_0, y_1) + BLE celt_pitch_xcorr_edsp_process2_done + LDRH r9, [r5], #2 + SMLABT r10, r7, r8, r10 ; sum0 = MAC16_16(sum0, x_0, y_1) + SMLABB r11, r7, r9, r11 ; sum1 = MAC16_16(sum1, x_0, y_2) +celt_pitch_xcorr_edsp_process2_done + ; Restore _x + SUB r4, r4, r3, LSL #1 + ; Restore and advance _y + SUB r5, r5, r3, LSL #1 + ; maxcorr = max(maxcorr, sum0) + CMP r0, r10 + ADD r5, r5, #2 + MOVLT r0, r10 + SUB r1, r1, #2 + ; maxcorr = max(maxcorr, sum1) + CMP r0, r11 + ; xcorr[i] = sum + STR r10, [r2], #4 + MOVLT r0, r11 + STR r11, [r2], #4 +celt_pitch_xcorr_edsp_process1a + ADDS r1, r1, #1 + BLT celt_pitch_xcorr_edsp_done + SUBS r12, r3, #4 + ; r14 = sum = 0 + MOV r14, #0 + BLT celt_pitch_xcorr_edsp_process1a_loop_done + LDR r6, [r4], #4 + LDR r8, [r5], #4 + LDR r7, [r4], #4 + LDR r9, [r5], #4 +celt_pitch_xcorr_edsp_process1a_loop4 + SMLABB r14, r6, r8, r14 ; sum = MAC16_16(sum, x_0, y_0) + SUBS r12, r12, #4 ; j-=4 + SMLATT r14, r6, r8, r14 ; sum = MAC16_16(sum, x_1, y_1) + LDRGE r6, [r4], #4 + SMLABB r14, r7, r9, r14 ; sum = MAC16_16(sum, x_2, y_2) + LDRGE r8, [r5], #4 + SMLATT r14, r7, r9, r14 ; sum = MAC16_16(sum, x_3, y_3) + LDRGE r7, [r4], #4 + LDRGE r9, [r5], #4 + BGE celt_pitch_xcorr_edsp_process1a_loop4 +celt_pitch_xcorr_edsp_process1a_loop_done + ADDS r12, r12, #2 + LDRGE r6, [r4], #4 + LDRGE r8, [r5], #4 + ; Stall + SMLABBGE r14, r6, r8, r14 ; sum = MAC16_16(sum, x_0, y_0) + SUBGE r12, r12, #2 + SMLATTGE r14, r6, r8, r14 ; sum = MAC16_16(sum, x_1, y_1) + ADDS r12, r12, #1 + LDRHGE r6, [r4], #2 + LDRHGE r8, [r5], #2 + ; Stall + SMLABBGE r14, r6, r8, r14 ; sum = MAC16_16(sum, *x, *y) + ; maxcorr = max(maxcorr, sum) + CMP r0, r14 + ; xcorr[i] = sum + STR r14, [r2], #4 + MOVLT r0, r14 +celt_pitch_xcorr_edsp_done + LDMFD sp!, {r4-r11, pc} + ENDP + +ENDIF + +END diff --git a/extern/opus/celt/arm/fft_arm.h b/extern/opus/celt/arm/fft_arm.h new file mode 100644 index 0000000..0b78175 --- /dev/null +++ b/extern/opus/celt/arm/fft_arm.h @@ -0,0 +1,71 @@ +/* Copyright (c) 2015 Xiph.Org Foundation + Written by Viswanath Puttagunta */ +/** + @file fft_arm.h + @brief ARM Neon Intrinsic optimizations for fft using NE10 library + */ + +/* + 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. + + 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 OWNER + 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. +*/ + + +#if !defined(FFT_ARM_H) +#define FFT_ARM_H + +#include "kiss_fft.h" + +#if defined(HAVE_ARM_NE10) + +int opus_fft_alloc_arm_neon(kiss_fft_state *st); +void opus_fft_free_arm_neon(kiss_fft_state *st); + +void opus_fft_neon(const kiss_fft_state *st, + const kiss_fft_cpx *fin, + kiss_fft_cpx *fout); + +void opus_ifft_neon(const kiss_fft_state *st, + const kiss_fft_cpx *fin, + kiss_fft_cpx *fout); + +#if !defined(OPUS_HAVE_RTCD) +#define OVERRIDE_OPUS_FFT (1) + +#define opus_fft_alloc_arch(_st, arch) \ + ((void)(arch), opus_fft_alloc_arm_neon(_st)) + +#define opus_fft_free_arch(_st, arch) \ + ((void)(arch), opus_fft_free_arm_neon(_st)) + +#define opus_fft(_st, _fin, _fout, arch) \ + ((void)(arch), opus_fft_neon(_st, _fin, _fout)) + +#define opus_ifft(_st, _fin, _fout, arch) \ + ((void)(arch), opus_ifft_neon(_st, _fin, _fout)) + +#endif /* OPUS_HAVE_RTCD */ + +#endif /* HAVE_ARM_NE10 */ + +#endif diff --git a/extern/opus/celt/arm/fixed_arm64.h b/extern/opus/celt/arm/fixed_arm64.h new file mode 100644 index 0000000..c6fbd3d --- /dev/null +++ b/extern/opus/celt/arm/fixed_arm64.h @@ -0,0 +1,35 @@ +/* Copyright (C) 2015 Vidyo */ +/* + 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. + + 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 OWNER + 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. +*/ + +#ifndef FIXED_ARM64_H +#define FIXED_ARM64_H + +#include + +#undef SIG2WORD16 +#define SIG2WORD16(x) (vqmovns_s32(PSHR32((x), SIG_SHIFT))) + +#endif diff --git a/extern/opus/celt/arm/fixed_armv4.h b/extern/opus/celt/arm/fixed_armv4.h new file mode 100644 index 0000000..d84888a --- /dev/null +++ b/extern/opus/celt/arm/fixed_armv4.h @@ -0,0 +1,80 @@ +/* Copyright (C) 2013 Xiph.Org Foundation and contributors */ +/* + 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. + + 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 OWNER + 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. +*/ + +#ifndef FIXED_ARMv4_H +#define FIXED_ARMv4_H + +/** 16x32 multiplication, followed by a 16-bit shift right. Results fits in 32 bits */ +#undef MULT16_32_Q16 +static OPUS_INLINE opus_val32 MULT16_32_Q16_armv4(opus_val16 a, opus_val32 b) +{ + unsigned rd_lo; + int rd_hi; + __asm__( + "#MULT16_32_Q16\n\t" + "smull %0, %1, %2, %3\n\t" + : "=&r"(rd_lo), "=&r"(rd_hi) + : "%r"(b),"r"(SHL32(a,16)) + ); + return rd_hi; +} +#define MULT16_32_Q16(a, b) (MULT16_32_Q16_armv4(a, b)) + + +/** 16x32 multiplication, followed by a 15-bit shift right. Results fits in 32 bits */ +#undef MULT16_32_Q15 +static OPUS_INLINE opus_val32 MULT16_32_Q15_armv4(opus_val16 a, opus_val32 b) +{ + unsigned rd_lo; + int rd_hi; + __asm__( + "#MULT16_32_Q15\n\t" + "smull %0, %1, %2, %3\n\t" + : "=&r"(rd_lo), "=&r"(rd_hi) + : "%r"(b), "r"(SHL32(a,16)) + ); + /*We intentionally don't OR in the high bit of rd_lo for speed.*/ + return SHL32(rd_hi,1); +} +#define MULT16_32_Q15(a, b) (MULT16_32_Q15_armv4(a, b)) + + +/** 16x32 multiply, followed by a 15-bit shift right and 32-bit add. + b must fit in 31 bits. + Result fits in 32 bits. */ +#undef MAC16_32_Q15 +#define MAC16_32_Q15(c, a, b) ADD32(c, MULT16_32_Q15(a, b)) + +/** 16x32 multiply, followed by a 16-bit shift right and 32-bit add. + Result fits in 32 bits. */ +#undef MAC16_32_Q16 +#define MAC16_32_Q16(c, a, b) ADD32(c, MULT16_32_Q16(a, b)) + +/** 32x32 multiplication, followed by a 31-bit shift right. Results fits in 32 bits */ +#undef MULT32_32_Q31 +#define MULT32_32_Q31(a,b) (opus_val32)((((opus_int64)(a)) * ((opus_int64)(b)))>>31) + +#endif diff --git a/extern/opus/celt/arm/fixed_armv5e.h b/extern/opus/celt/arm/fixed_armv5e.h new file mode 100644 index 0000000..6bf73cb --- /dev/null +++ b/extern/opus/celt/arm/fixed_armv5e.h @@ -0,0 +1,151 @@ +/* Copyright (C) 2007-2009 Xiph.Org Foundation + Copyright (C) 2003-2008 Jean-Marc Valin + Copyright (C) 2007-2008 CSIRO + Copyright (C) 2013 Parrot */ +/* + 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. + + 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 OWNER + 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. +*/ + +#ifndef FIXED_ARMv5E_H +#define FIXED_ARMv5E_H + +#include "fixed_armv4.h" + +/** 16x32 multiplication, followed by a 16-bit shift right. Results fits in 32 bits */ +#undef MULT16_32_Q16 +static OPUS_INLINE opus_val32 MULT16_32_Q16_armv5e(opus_val16 a, opus_val32 b) +{ + int res; + __asm__( + "#MULT16_32_Q16\n\t" + "smulwb %0, %1, %2\n\t" + : "=r"(res) + : "r"(b),"r"(a) + ); + return res; +} +#define MULT16_32_Q16(a, b) (MULT16_32_Q16_armv5e(a, b)) + + +/** 16x32 multiplication, followed by a 15-bit shift right. Results fits in 32 bits */ +#undef MULT16_32_Q15 +static OPUS_INLINE opus_val32 MULT16_32_Q15_armv5e(opus_val16 a, opus_val32 b) +{ + int res; + __asm__( + "#MULT16_32_Q15\n\t" + "smulwb %0, %1, %2\n\t" + : "=r"(res) + : "r"(b), "r"(a) + ); + return SHL32(res,1); +} +#define MULT16_32_Q15(a, b) (MULT16_32_Q15_armv5e(a, b)) + + +/** 16x32 multiply, followed by a 15-bit shift right and 32-bit add. + b must fit in 31 bits. + Result fits in 32 bits. */ +#undef MAC16_32_Q15 +static OPUS_INLINE opus_val32 MAC16_32_Q15_armv5e(opus_val32 c, opus_val16 a, + opus_val32 b) +{ + int res; + __asm__( + "#MAC16_32_Q15\n\t" + "smlawb %0, %1, %2, %3;\n" + : "=r"(res) + : "r"(SHL32(b,1)), "r"(a), "r"(c) + ); + return res; +} +#define MAC16_32_Q15(c, a, b) (MAC16_32_Q15_armv5e(c, a, b)) + +/** 16x32 multiply, followed by a 16-bit shift right and 32-bit add. + Result fits in 32 bits. */ +#undef MAC16_32_Q16 +static OPUS_INLINE opus_val32 MAC16_32_Q16_armv5e(opus_val32 c, opus_val16 a, + opus_val32 b) +{ + int res; + __asm__( + "#MAC16_32_Q16\n\t" + "smlawb %0, %1, %2, %3;\n" + : "=r"(res) + : "r"(b), "r"(a), "r"(c) + ); + return res; +} +#define MAC16_32_Q16(c, a, b) (MAC16_32_Q16_armv5e(c, a, b)) + +/** 16x16 multiply-add where the result fits in 32 bits */ +#undef MAC16_16 +static OPUS_INLINE opus_val32 MAC16_16_armv5e(opus_val32 c, opus_val16 a, + opus_val16 b) +{ + int res; + __asm__( + "#MAC16_16\n\t" + "smlabb %0, %1, %2, %3;\n" + : "=r"(res) + : "r"(a), "r"(b), "r"(c) + ); + return res; +} +#define MAC16_16(c, a, b) (MAC16_16_armv5e(c, a, b)) + +/** 16x16 multiplication where the result fits in 32 bits */ +#undef MULT16_16 +static OPUS_INLINE opus_val32 MULT16_16_armv5e(opus_val16 a, opus_val16 b) +{ + int res; + __asm__( + "#MULT16_16\n\t" + "smulbb %0, %1, %2;\n" + : "=r"(res) + : "r"(a), "r"(b) + ); + return res; +} +#define MULT16_16(a, b) (MULT16_16_armv5e(a, b)) + +#ifdef OPUS_ARM_INLINE_MEDIA + +#undef SIG2WORD16 +static OPUS_INLINE opus_val16 SIG2WORD16_armv6(opus_val32 x) +{ + celt_sig res; + __asm__( + "#SIG2WORD16\n\t" + "ssat %0, #16, %1, ASR #12\n\t" + : "=r"(res) + : "r"(x+2048) + ); + return EXTRACT16(res); +} +#define SIG2WORD16(x) (SIG2WORD16_armv6(x)) + +#endif /* OPUS_ARM_INLINE_MEDIA */ + +#endif diff --git a/extern/opus/celt/arm/kiss_fft_armv4.h b/extern/opus/celt/arm/kiss_fft_armv4.h new file mode 100644 index 0000000..e4faad6 --- /dev/null +++ b/extern/opus/celt/arm/kiss_fft_armv4.h @@ -0,0 +1,121 @@ +/*Copyright (c) 2013, Xiph.Org Foundation and contributors. + + All rights reserved. + + 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. + + 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 OWNER 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.*/ + +#ifndef KISS_FFT_ARMv4_H +#define KISS_FFT_ARMv4_H + +#if !defined(KISS_FFT_GUTS_H) +#error "This file should only be included from _kiss_fft_guts.h" +#endif + +#ifdef FIXED_POINT + +#undef C_MUL +#define C_MUL(m,a,b) \ + do{ \ + int br__; \ + int bi__; \ + int tt__; \ + __asm__ __volatile__( \ + "#C_MUL\n\t" \ + "ldrsh %[br], [%[bp], #0]\n\t" \ + "ldm %[ap], {r0,r1}\n\t" \ + "ldrsh %[bi], [%[bp], #2]\n\t" \ + "smull %[tt], %[mi], r1, %[br]\n\t" \ + "smlal %[tt], %[mi], r0, %[bi]\n\t" \ + "rsb %[bi], %[bi], #0\n\t" \ + "smull %[br], %[mr], r0, %[br]\n\t" \ + "mov %[tt], %[tt], lsr #15\n\t" \ + "smlal %[br], %[mr], r1, %[bi]\n\t" \ + "orr %[mi], %[tt], %[mi], lsl #17\n\t" \ + "mov %[br], %[br], lsr #15\n\t" \ + "orr %[mr], %[br], %[mr], lsl #17\n\t" \ + : [mr]"=r"((m).r), [mi]"=r"((m).i), \ + [br]"=&r"(br__), [bi]"=r"(bi__), [tt]"=r"(tt__) \ + : [ap]"r"(&(a)), [bp]"r"(&(b)) \ + : "r0", "r1" \ + ); \ + } \ + while(0) + +#undef C_MUL4 +#define C_MUL4(m,a,b) \ + do{ \ + int br__; \ + int bi__; \ + int tt__; \ + __asm__ __volatile__( \ + "#C_MUL4\n\t" \ + "ldrsh %[br], [%[bp], #0]\n\t" \ + "ldm %[ap], {r0,r1}\n\t" \ + "ldrsh %[bi], [%[bp], #2]\n\t" \ + "smull %[tt], %[mi], r1, %[br]\n\t" \ + "smlal %[tt], %[mi], r0, %[bi]\n\t" \ + "rsb %[bi], %[bi], #0\n\t" \ + "smull %[br], %[mr], r0, %[br]\n\t" \ + "mov %[tt], %[tt], lsr #17\n\t" \ + "smlal %[br], %[mr], r1, %[bi]\n\t" \ + "orr %[mi], %[tt], %[mi], lsl #15\n\t" \ + "mov %[br], %[br], lsr #17\n\t" \ + "orr %[mr], %[br], %[mr], lsl #15\n\t" \ + : [mr]"=r"((m).r), [mi]"=r"((m).i), \ + [br]"=&r"(br__), [bi]"=r"(bi__), [tt]"=r"(tt__) \ + : [ap]"r"(&(a)), [bp]"r"(&(b)) \ + : "r0", "r1" \ + ); \ + } \ + while(0) + +#undef C_MULC +#define C_MULC(m,a,b) \ + do{ \ + int br__; \ + int bi__; \ + int tt__; \ + __asm__ __volatile__( \ + "#C_MULC\n\t" \ + "ldrsh %[br], [%[bp], #0]\n\t" \ + "ldm %[ap], {r0,r1}\n\t" \ + "ldrsh %[bi], [%[bp], #2]\n\t" \ + "smull %[tt], %[mr], r0, %[br]\n\t" \ + "smlal %[tt], %[mr], r1, %[bi]\n\t" \ + "rsb %[bi], %[bi], #0\n\t" \ + "smull %[br], %[mi], r1, %[br]\n\t" \ + "mov %[tt], %[tt], lsr #15\n\t" \ + "smlal %[br], %[mi], r0, %[bi]\n\t" \ + "orr %[mr], %[tt], %[mr], lsl #17\n\t" \ + "mov %[br], %[br], lsr #15\n\t" \ + "orr %[mi], %[br], %[mi], lsl #17\n\t" \ + : [mr]"=r"((m).r), [mi]"=r"((m).i), \ + [br]"=&r"(br__), [bi]"=r"(bi__), [tt]"=r"(tt__) \ + : [ap]"r"(&(a)), [bp]"r"(&(b)) \ + : "r0", "r1" \ + ); \ + } \ + while(0) + +#endif /* FIXED_POINT */ + +#endif /* KISS_FFT_ARMv4_H */ diff --git a/extern/opus/celt/arm/kiss_fft_armv5e.h b/extern/opus/celt/arm/kiss_fft_armv5e.h new file mode 100644 index 0000000..9eca183 --- /dev/null +++ b/extern/opus/celt/arm/kiss_fft_armv5e.h @@ -0,0 +1,118 @@ +/*Copyright (c) 2013, Xiph.Org Foundation and contributors. + + All rights reserved. + + 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. + + 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 OWNER 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.*/ + +#ifndef KISS_FFT_ARMv5E_H +#define KISS_FFT_ARMv5E_H + +#if !defined(KISS_FFT_GUTS_H) +#error "This file should only be included from _kiss_fft_guts.h" +#endif + +#ifdef FIXED_POINT + +#if defined(__thumb__)||defined(__thumb2__) +#define LDRD_CONS "Q" +#else +#define LDRD_CONS "Uq" +#endif + +#undef C_MUL +#define C_MUL(m,a,b) \ + do{ \ + int mr1__; \ + int mr2__; \ + int mi__; \ + long long aval__; \ + int bval__; \ + __asm__( \ + "#C_MUL\n\t" \ + "ldrd %[aval], %H[aval], %[ap]\n\t" \ + "ldr %[bval], %[bp]\n\t" \ + "smulwb %[mi], %H[aval], %[bval]\n\t" \ + "smulwb %[mr1], %[aval], %[bval]\n\t" \ + "smulwt %[mr2], %H[aval], %[bval]\n\t" \ + "smlawt %[mi], %[aval], %[bval], %[mi]\n\t" \ + : [mr1]"=r"(mr1__), [mr2]"=r"(mr2__), [mi]"=r"(mi__), \ + [aval]"=&r"(aval__), [bval]"=r"(bval__) \ + : [ap]LDRD_CONS(a), [bp]"m"(b) \ + ); \ + (m).r = SHL32(SUB32(mr1__, mr2__), 1); \ + (m).i = SHL32(mi__, 1); \ + } \ + while(0) + +#undef C_MUL4 +#define C_MUL4(m,a,b) \ + do{ \ + int mr1__; \ + int mr2__; \ + int mi__; \ + long long aval__; \ + int bval__; \ + __asm__( \ + "#C_MUL4\n\t" \ + "ldrd %[aval], %H[aval], %[ap]\n\t" \ + "ldr %[bval], %[bp]\n\t" \ + "smulwb %[mi], %H[aval], %[bval]\n\t" \ + "smulwb %[mr1], %[aval], %[bval]\n\t" \ + "smulwt %[mr2], %H[aval], %[bval]\n\t" \ + "smlawt %[mi], %[aval], %[bval], %[mi]\n\t" \ + : [mr1]"=r"(mr1__), [mr2]"=r"(mr2__), [mi]"=r"(mi__), \ + [aval]"=&r"(aval__), [bval]"=r"(bval__) \ + : [ap]LDRD_CONS(a), [bp]"m"(b) \ + ); \ + (m).r = SHR32(SUB32(mr1__, mr2__), 1); \ + (m).i = SHR32(mi__, 1); \ + } \ + while(0) + +#undef C_MULC +#define C_MULC(m,a,b) \ + do{ \ + int mr__; \ + int mi1__; \ + int mi2__; \ + long long aval__; \ + int bval__; \ + __asm__( \ + "#C_MULC\n\t" \ + "ldrd %[aval], %H[aval], %[ap]\n\t" \ + "ldr %[bval], %[bp]\n\t" \ + "smulwb %[mr], %[aval], %[bval]\n\t" \ + "smulwb %[mi1], %H[aval], %[bval]\n\t" \ + "smulwt %[mi2], %[aval], %[bval]\n\t" \ + "smlawt %[mr], %H[aval], %[bval], %[mr]\n\t" \ + : [mr]"=r"(mr__), [mi1]"=r"(mi1__), [mi2]"=r"(mi2__), \ + [aval]"=&r"(aval__), [bval]"=r"(bval__) \ + : [ap]LDRD_CONS(a), [bp]"m"(b) \ + ); \ + (m).r = SHL32(mr__, 1); \ + (m).i = SHL32(SUB32(mi1__, mi2__), 1); \ + } \ + while(0) + +#endif /* FIXED_POINT */ + +#endif /* KISS_FFT_GUTS_H */ diff --git a/extern/opus/celt/arm/mdct_arm.h b/extern/opus/celt/arm/mdct_arm.h new file mode 100644 index 0000000..14200ba --- /dev/null +++ b/extern/opus/celt/arm/mdct_arm.h @@ -0,0 +1,59 @@ +/* Copyright (c) 2015 Xiph.Org Foundation + Written by Viswanath Puttagunta */ +/** + @file arm_mdct.h + @brief ARM Neon Intrinsic optimizations for mdct using NE10 library + */ + +/* + 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. + + 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 OWNER + 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. +*/ + +#if !defined(MDCT_ARM_H) +#define MDCT_ARM_H + +#include "mdct.h" + +#if defined(HAVE_ARM_NE10) +/** Compute a forward MDCT and scale by 4/N, trashes the input array */ +void clt_mdct_forward_neon(const mdct_lookup *l, kiss_fft_scalar *in, + kiss_fft_scalar * OPUS_RESTRICT out, + const opus_val16 *window, int overlap, + int shift, int stride, int arch); + +void clt_mdct_backward_neon(const mdct_lookup *l, kiss_fft_scalar *in, + kiss_fft_scalar * OPUS_RESTRICT out, + const opus_val16 *window, int overlap, + int shift, int stride, int arch); + +#if !defined(OPUS_HAVE_RTCD) +#define OVERRIDE_OPUS_MDCT (1) +#define clt_mdct_forward(_l, _in, _out, _window, _int, _shift, _stride, _arch) \ + clt_mdct_forward_neon(_l, _in, _out, _window, _int, _shift, _stride, _arch) +#define clt_mdct_backward(_l, _in, _out, _window, _int, _shift, _stride, _arch) \ + clt_mdct_backward_neon(_l, _in, _out, _window, _int, _shift, _stride, _arch) +#endif /* OPUS_HAVE_RTCD */ +#endif /* HAVE_ARM_NE10 */ + +#endif diff --git a/extern/opus/celt/arm/pitch_arm.h b/extern/opus/celt/arm/pitch_arm.h new file mode 100644 index 0000000..bed8b04 --- /dev/null +++ b/extern/opus/celt/arm/pitch_arm.h @@ -0,0 +1,160 @@ +/* Copyright (c) 2010 Xiph.Org Foundation + * Copyright (c) 2013 Parrot */ +/* + 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. + + 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 OWNER + 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. +*/ + +#if !defined(PITCH_ARM_H) +# define PITCH_ARM_H + +# include "armcpu.h" + +# if defined(OPUS_ARM_MAY_HAVE_NEON_INTR) +opus_val32 celt_inner_prod_neon(const opus_val16 *x, const opus_val16 *y, int N); +void dual_inner_prod_neon(const opus_val16 *x, const opus_val16 *y01, + const opus_val16 *y02, int N, opus_val32 *xy1, opus_val32 *xy2); + +# if !defined(OPUS_HAVE_RTCD) && defined(OPUS_ARM_PRESUME_NEON) +# define OVERRIDE_CELT_INNER_PROD (1) +# define OVERRIDE_DUAL_INNER_PROD (1) +# define celt_inner_prod(x, y, N, arch) ((void)(arch), PRESUME_NEON(celt_inner_prod)(x, y, N)) +# define dual_inner_prod(x, y01, y02, N, xy1, xy2, arch) ((void)(arch), PRESUME_NEON(dual_inner_prod)(x, y01, y02, N, xy1, xy2)) +# endif +# endif + +# if !defined(OVERRIDE_CELT_INNER_PROD) +# if defined(OPUS_HAVE_RTCD) && (defined(OPUS_ARM_MAY_HAVE_NEON_INTR) && !defined(OPUS_ARM_PRESUME_NEON_INTR)) +extern opus_val32 (*const CELT_INNER_PROD_IMPL[OPUS_ARCHMASK+1])(const opus_val16 *x, const opus_val16 *y, int N); +# define OVERRIDE_CELT_INNER_PROD (1) +# define celt_inner_prod(x, y, N, arch) ((*CELT_INNER_PROD_IMPL[(arch)&OPUS_ARCHMASK])(x, y, N)) +# elif defined(OPUS_ARM_PRESUME_NEON_INTR) +# define OVERRIDE_CELT_INNER_PROD (1) +# define celt_inner_prod(x, y, N, arch) ((void)(arch), celt_inner_prod_neon(x, y, N)) +# endif +# endif + +# if !defined(OVERRIDE_DUAL_INNER_PROD) +# if defined(OPUS_HAVE_RTCD) && (defined(OPUS_ARM_MAY_HAVE_NEON_INTR) && !defined(OPUS_ARM_PRESUME_NEON_INTR)) +extern void (*const DUAL_INNER_PROD_IMPL[OPUS_ARCHMASK+1])(const opus_val16 *x, + const opus_val16 *y01, const opus_val16 *y02, int N, opus_val32 *xy1, opus_val32 *xy2); +# define OVERRIDE_DUAL_INNER_PROD (1) +# define dual_inner_prod(x, y01, y02, N, xy1, xy2, arch) ((*DUAL_INNER_PROD_IMPL[(arch)&OPUS_ARCHMASK])(x, y01, y02, N, xy1, xy2)) +# elif defined(OPUS_ARM_PRESUME_NEON_INTR) +# define OVERRIDE_DUAL_INNER_PROD (1) +# define dual_inner_prod(x, y01, y02, N, xy1, xy2, arch) ((void)(arch), dual_inner_prod_neon(x, y01, y02, N, xy1, xy2)) +# endif +# endif + +# if defined(FIXED_POINT) + +# if defined(OPUS_ARM_MAY_HAVE_NEON) +opus_val32 celt_pitch_xcorr_neon(const opus_val16 *_x, const opus_val16 *_y, + opus_val32 *xcorr, int len, int max_pitch, int arch); +# endif + +# if defined(OPUS_ARM_MAY_HAVE_MEDIA) +# define celt_pitch_xcorr_media MAY_HAVE_EDSP(celt_pitch_xcorr) +# endif + +# if defined(OPUS_ARM_MAY_HAVE_EDSP) +opus_val32 celt_pitch_xcorr_edsp(const opus_val16 *_x, const opus_val16 *_y, + opus_val32 *xcorr, int len, int max_pitch, int arch); +# endif + +# if defined(OPUS_HAVE_RTCD) && \ + ((defined(OPUS_ARM_MAY_HAVE_NEON) && !defined(OPUS_ARM_PRESUME_NEON)) || \ + (defined(OPUS_ARM_MAY_HAVE_MEDIA) && !defined(OPUS_ARM_PRESUME_MEDIA)) || \ + (defined(OPUS_ARM_MAY_HAVE_EDSP) && !defined(OPUS_ARM_PRESUME_EDSP))) +extern opus_val32 +(*const CELT_PITCH_XCORR_IMPL[OPUS_ARCHMASK+1])(const opus_val16 *, + const opus_val16 *, opus_val32 *, int, int, int); +# define OVERRIDE_PITCH_XCORR (1) +# define celt_pitch_xcorr(_x, _y, xcorr, len, max_pitch, arch) \ + ((*CELT_PITCH_XCORR_IMPL[(arch)&OPUS_ARCHMASK])(_x, _y, \ + xcorr, len, max_pitch, arch)) + +# elif defined(OPUS_ARM_PRESUME_EDSP) || \ + defined(OPUS_ARM_PRESUME_MEDIA) || \ + defined(OPUS_ARM_PRESUME_NEON) +# define OVERRIDE_PITCH_XCORR (1) +# define celt_pitch_xcorr (PRESUME_NEON(celt_pitch_xcorr)) + +# endif + +# if defined(OPUS_ARM_MAY_HAVE_NEON_INTR) +void xcorr_kernel_neon_fixed( + const opus_val16 *x, + const opus_val16 *y, + opus_val32 sum[4], + int len); +# endif + +# if defined(OPUS_HAVE_RTCD) && \ + (defined(OPUS_ARM_MAY_HAVE_NEON_INTR) && !defined(OPUS_ARM_PRESUME_NEON_INTR)) + +extern void (*const XCORR_KERNEL_IMPL[OPUS_ARCHMASK + 1])( + const opus_val16 *x, + const opus_val16 *y, + opus_val32 sum[4], + int len); + +# define OVERRIDE_XCORR_KERNEL (1) +# define xcorr_kernel(x, y, sum, len, arch) \ + ((*XCORR_KERNEL_IMPL[(arch) & OPUS_ARCHMASK])(x, y, sum, len)) + +# elif defined(OPUS_ARM_PRESUME_NEON_INTR) +# define OVERRIDE_XCORR_KERNEL (1) +# define xcorr_kernel(x, y, sum, len, arch) \ + ((void)arch, xcorr_kernel_neon_fixed(x, y, sum, len)) + +# endif + +#else /* Start !FIXED_POINT */ +/* Float case */ +#if defined(OPUS_ARM_MAY_HAVE_NEON_INTR) +void celt_pitch_xcorr_float_neon(const opus_val16 *_x, const opus_val16 *_y, + opus_val32 *xcorr, int len, int max_pitch, int arch); +#endif + +# if defined(OPUS_HAVE_RTCD) && \ + (defined(OPUS_ARM_MAY_HAVE_NEON_INTR) && !defined(OPUS_ARM_PRESUME_NEON_INTR)) +extern void +(*const CELT_PITCH_XCORR_IMPL[OPUS_ARCHMASK+1])(const opus_val16 *, + const opus_val16 *, opus_val32 *, int, int, int); + +# define OVERRIDE_PITCH_XCORR (1) +# define celt_pitch_xcorr(_x, _y, xcorr, len, max_pitch, arch) \ + ((*CELT_PITCH_XCORR_IMPL[(arch)&OPUS_ARCHMASK])(_x, _y, \ + xcorr, len, max_pitch, arch)) + +# elif defined(OPUS_ARM_PRESUME_NEON_INTR) + +# define OVERRIDE_PITCH_XCORR (1) +# define celt_pitch_xcorr celt_pitch_xcorr_float_neon + +# endif + +#endif /* end !FIXED_POINT */ + +#endif diff --git a/extern/opus/celt/arm/pitch_neon_intr.c b/extern/opus/celt/arm/pitch_neon_intr.c new file mode 100644 index 0000000..1ac38c4 --- /dev/null +++ b/extern/opus/celt/arm/pitch_neon_intr.c @@ -0,0 +1,290 @@ +/*********************************************************************** +Copyright (c) 2017 Google Inc. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "pitch.h" + +#ifdef FIXED_POINT + +opus_val32 celt_inner_prod_neon(const opus_val16 *x, const opus_val16 *y, int N) +{ + int i; + opus_val32 xy; + int16x8_t x_s16x8, y_s16x8; + int32x4_t xy_s32x4 = vdupq_n_s32(0); + int64x2_t xy_s64x2; + int64x1_t xy_s64x1; + + for (i = 0; i < N - 7; i += 8) { + x_s16x8 = vld1q_s16(&x[i]); + y_s16x8 = vld1q_s16(&y[i]); + xy_s32x4 = vmlal_s16(xy_s32x4, vget_low_s16 (x_s16x8), vget_low_s16 (y_s16x8)); + xy_s32x4 = vmlal_s16(xy_s32x4, vget_high_s16(x_s16x8), vget_high_s16(y_s16x8)); + } + + if (N - i >= 4) { + const int16x4_t x_s16x4 = vld1_s16(&x[i]); + const int16x4_t y_s16x4 = vld1_s16(&y[i]); + xy_s32x4 = vmlal_s16(xy_s32x4, x_s16x4, y_s16x4); + i += 4; + } + + xy_s64x2 = vpaddlq_s32(xy_s32x4); + xy_s64x1 = vadd_s64(vget_low_s64(xy_s64x2), vget_high_s64(xy_s64x2)); + xy = vget_lane_s32(vreinterpret_s32_s64(xy_s64x1), 0); + + for (; i < N; i++) { + xy = MAC16_16(xy, x[i], y[i]); + } + +#ifdef OPUS_CHECK_ASM + celt_assert(celt_inner_prod_c(x, y, N) == xy); +#endif + + return xy; +} + +void dual_inner_prod_neon(const opus_val16 *x, const opus_val16 *y01, const opus_val16 *y02, + int N, opus_val32 *xy1, opus_val32 *xy2) +{ + int i; + opus_val32 xy01, xy02; + int16x8_t x_s16x8, y01_s16x8, y02_s16x8; + int32x4_t xy01_s32x4 = vdupq_n_s32(0); + int32x4_t xy02_s32x4 = vdupq_n_s32(0); + int64x2_t xy01_s64x2, xy02_s64x2; + int64x1_t xy01_s64x1, xy02_s64x1; + + for (i = 0; i < N - 7; i += 8) { + x_s16x8 = vld1q_s16(&x[i]); + y01_s16x8 = vld1q_s16(&y01[i]); + y02_s16x8 = vld1q_s16(&y02[i]); + xy01_s32x4 = vmlal_s16(xy01_s32x4, vget_low_s16 (x_s16x8), vget_low_s16 (y01_s16x8)); + xy02_s32x4 = vmlal_s16(xy02_s32x4, vget_low_s16 (x_s16x8), vget_low_s16 (y02_s16x8)); + xy01_s32x4 = vmlal_s16(xy01_s32x4, vget_high_s16(x_s16x8), vget_high_s16(y01_s16x8)); + xy02_s32x4 = vmlal_s16(xy02_s32x4, vget_high_s16(x_s16x8), vget_high_s16(y02_s16x8)); + } + + if (N - i >= 4) { + const int16x4_t x_s16x4 = vld1_s16(&x[i]); + const int16x4_t y01_s16x4 = vld1_s16(&y01[i]); + const int16x4_t y02_s16x4 = vld1_s16(&y02[i]); + xy01_s32x4 = vmlal_s16(xy01_s32x4, x_s16x4, y01_s16x4); + xy02_s32x4 = vmlal_s16(xy02_s32x4, x_s16x4, y02_s16x4); + i += 4; + } + + xy01_s64x2 = vpaddlq_s32(xy01_s32x4); + xy02_s64x2 = vpaddlq_s32(xy02_s32x4); + xy01_s64x1 = vadd_s64(vget_low_s64(xy01_s64x2), vget_high_s64(xy01_s64x2)); + xy02_s64x1 = vadd_s64(vget_low_s64(xy02_s64x2), vget_high_s64(xy02_s64x2)); + xy01 = vget_lane_s32(vreinterpret_s32_s64(xy01_s64x1), 0); + xy02 = vget_lane_s32(vreinterpret_s32_s64(xy02_s64x1), 0); + + for (; i < N; i++) { + xy01 = MAC16_16(xy01, x[i], y01[i]); + xy02 = MAC16_16(xy02, x[i], y02[i]); + } + *xy1 = xy01; + *xy2 = xy02; + +#ifdef OPUS_CHECK_ASM + { + opus_val32 xy1_c, xy2_c; + dual_inner_prod_c(x, y01, y02, N, &xy1_c, &xy2_c); + celt_assert(xy1_c == *xy1); + celt_assert(xy2_c == *xy2); + } +#endif +} + +#else /* !FIXED_POINT */ + +/* ========================================================================== */ + +#ifdef OPUS_CHECK_ASM + +/* This part of code simulates floating-point NEON operations. */ + +/* celt_inner_prod_neon_float_c_simulation() simulates the floating-point */ +/* operations of celt_inner_prod_neon(), and both functions should have bit */ +/* exact output. */ +static opus_val32 celt_inner_prod_neon_float_c_simulation(const opus_val16 *x, const opus_val16 *y, int N) +{ + int i; + opus_val32 xy, xy0 = 0, xy1 = 0, xy2 = 0, xy3 = 0; + for (i = 0; i < N - 3; i += 4) { + xy0 = MAC16_16(xy0, x[i + 0], y[i + 0]); + xy1 = MAC16_16(xy1, x[i + 1], y[i + 1]); + xy2 = MAC16_16(xy2, x[i + 2], y[i + 2]); + xy3 = MAC16_16(xy3, x[i + 3], y[i + 3]); + } + xy0 += xy2; + xy1 += xy3; + xy = xy0 + xy1; + for (; i < N; i++) { + xy = MAC16_16(xy, x[i], y[i]); + } + return xy; +} + +/* dual_inner_prod_neon_float_c_simulation() simulates the floating-point */ +/* operations of dual_inner_prod_neon(), and both functions should have bit */ +/* exact output. */ +static void dual_inner_prod_neon_float_c_simulation(const opus_val16 *x, const opus_val16 *y01, const opus_val16 *y02, + int N, opus_val32 *xy1, opus_val32 *xy2) +{ + int i; + opus_val32 xy01, xy02, xy01_0 = 0, xy01_1 = 0, xy01_2 = 0, xy01_3 = 0, xy02_0 = 0, xy02_1 = 0, xy02_2 = 0, xy02_3 = 0; + for (i = 0; i < N - 3; i += 4) { + xy01_0 = MAC16_16(xy01_0, x[i + 0], y01[i + 0]); + xy01_1 = MAC16_16(xy01_1, x[i + 1], y01[i + 1]); + xy01_2 = MAC16_16(xy01_2, x[i + 2], y01[i + 2]); + xy01_3 = MAC16_16(xy01_3, x[i + 3], y01[i + 3]); + xy02_0 = MAC16_16(xy02_0, x[i + 0], y02[i + 0]); + xy02_1 = MAC16_16(xy02_1, x[i + 1], y02[i + 1]); + xy02_2 = MAC16_16(xy02_2, x[i + 2], y02[i + 2]); + xy02_3 = MAC16_16(xy02_3, x[i + 3], y02[i + 3]); + } + xy01_0 += xy01_2; + xy02_0 += xy02_2; + xy01_1 += xy01_3; + xy02_1 += xy02_3; + xy01 = xy01_0 + xy01_1; + xy02 = xy02_0 + xy02_1; + for (; i < N; i++) { + xy01 = MAC16_16(xy01, x[i], y01[i]); + xy02 = MAC16_16(xy02, x[i], y02[i]); + } + *xy1 = xy01; + *xy2 = xy02; +} + +#endif /* OPUS_CHECK_ASM */ + +/* ========================================================================== */ + +opus_val32 celt_inner_prod_neon(const opus_val16 *x, const opus_val16 *y, int N) +{ + int i; + opus_val32 xy; + float32x4_t xy_f32x4 = vdupq_n_f32(0); + float32x2_t xy_f32x2; + + for (i = 0; i < N - 7; i += 8) { + float32x4_t x_f32x4, y_f32x4; + x_f32x4 = vld1q_f32(&x[i]); + y_f32x4 = vld1q_f32(&y[i]); + xy_f32x4 = vmlaq_f32(xy_f32x4, x_f32x4, y_f32x4); + x_f32x4 = vld1q_f32(&x[i + 4]); + y_f32x4 = vld1q_f32(&y[i + 4]); + xy_f32x4 = vmlaq_f32(xy_f32x4, x_f32x4, y_f32x4); + } + + if (N - i >= 4) { + const float32x4_t x_f32x4 = vld1q_f32(&x[i]); + const float32x4_t y_f32x4 = vld1q_f32(&y[i]); + xy_f32x4 = vmlaq_f32(xy_f32x4, x_f32x4, y_f32x4); + i += 4; + } + + xy_f32x2 = vadd_f32(vget_low_f32(xy_f32x4), vget_high_f32(xy_f32x4)); + xy_f32x2 = vpadd_f32(xy_f32x2, xy_f32x2); + xy = vget_lane_f32(xy_f32x2, 0); + + for (; i < N; i++) { + xy = MAC16_16(xy, x[i], y[i]); + } + +#ifdef OPUS_CHECK_ASM + celt_assert(ABS32(celt_inner_prod_neon_float_c_simulation(x, y, N) - xy) <= VERY_SMALL); +#endif + + return xy; +} + +void dual_inner_prod_neon(const opus_val16 *x, const opus_val16 *y01, const opus_val16 *y02, + int N, opus_val32 *xy1, opus_val32 *xy2) +{ + int i; + opus_val32 xy01, xy02; + float32x4_t xy01_f32x4 = vdupq_n_f32(0); + float32x4_t xy02_f32x4 = vdupq_n_f32(0); + float32x2_t xy01_f32x2, xy02_f32x2; + + for (i = 0; i < N - 7; i += 8) { + float32x4_t x_f32x4, y01_f32x4, y02_f32x4; + x_f32x4 = vld1q_f32(&x[i]); + y01_f32x4 = vld1q_f32(&y01[i]); + y02_f32x4 = vld1q_f32(&y02[i]); + xy01_f32x4 = vmlaq_f32(xy01_f32x4, x_f32x4, y01_f32x4); + xy02_f32x4 = vmlaq_f32(xy02_f32x4, x_f32x4, y02_f32x4); + x_f32x4 = vld1q_f32(&x[i + 4]); + y01_f32x4 = vld1q_f32(&y01[i + 4]); + y02_f32x4 = vld1q_f32(&y02[i + 4]); + xy01_f32x4 = vmlaq_f32(xy01_f32x4, x_f32x4, y01_f32x4); + xy02_f32x4 = vmlaq_f32(xy02_f32x4, x_f32x4, y02_f32x4); + } + + if (N - i >= 4) { + const float32x4_t x_f32x4 = vld1q_f32(&x[i]); + const float32x4_t y01_f32x4 = vld1q_f32(&y01[i]); + const float32x4_t y02_f32x4 = vld1q_f32(&y02[i]); + xy01_f32x4 = vmlaq_f32(xy01_f32x4, x_f32x4, y01_f32x4); + xy02_f32x4 = vmlaq_f32(xy02_f32x4, x_f32x4, y02_f32x4); + i += 4; + } + + xy01_f32x2 = vadd_f32(vget_low_f32(xy01_f32x4), vget_high_f32(xy01_f32x4)); + xy02_f32x2 = vadd_f32(vget_low_f32(xy02_f32x4), vget_high_f32(xy02_f32x4)); + xy01_f32x2 = vpadd_f32(xy01_f32x2, xy01_f32x2); + xy02_f32x2 = vpadd_f32(xy02_f32x2, xy02_f32x2); + xy01 = vget_lane_f32(xy01_f32x2, 0); + xy02 = vget_lane_f32(xy02_f32x2, 0); + + for (; i < N; i++) { + xy01 = MAC16_16(xy01, x[i], y01[i]); + xy02 = MAC16_16(xy02, x[i], y02[i]); + } + *xy1 = xy01; + *xy2 = xy02; + +#ifdef OPUS_CHECK_ASM + { + opus_val32 xy1_c, xy2_c; + dual_inner_prod_neon_float_c_simulation(x, y01, y02, N, &xy1_c, &xy2_c); + celt_assert(ABS32(xy1_c - *xy1) <= VERY_SMALL); + celt_assert(ABS32(xy2_c - *xy2) <= VERY_SMALL); + } +#endif +} + +#endif /* FIXED_POINT */ diff --git a/extern/opus/celt/bands.c b/extern/opus/celt/bands.c new file mode 100644 index 0000000..2702963 --- /dev/null +++ b/extern/opus/celt/bands.c @@ -0,0 +1,1672 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Copyright (c) 2008-2009 Gregory Maxwell + Written by Jean-Marc Valin and Gregory Maxwell */ +/* + 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. + + 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 OWNER + 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. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "bands.h" +#include "modes.h" +#include "vq.h" +#include "cwrs.h" +#include "stack_alloc.h" +#include "os_support.h" +#include "mathops.h" +#include "rate.h" +#include "quant_bands.h" +#include "pitch.h" + +int hysteresis_decision(opus_val16 val, const opus_val16 *thresholds, const opus_val16 *hysteresis, int N, int prev) +{ + int i; + for (i=0;iprev && val < thresholds[prev]+hysteresis[prev]) + i=prev; + if (i thresholds[prev-1]-hysteresis[prev-1]) + i=prev; + return i; +} + +opus_uint32 celt_lcg_rand(opus_uint32 seed) +{ + return 1664525 * seed + 1013904223; +} + +/* This is a cos() approximation designed to be bit-exact on any platform. Bit exactness + with this approximation is important because it has an impact on the bit allocation */ +opus_int16 bitexact_cos(opus_int16 x) +{ + opus_int32 tmp; + opus_int16 x2; + tmp = (4096+((opus_int32)(x)*(x)))>>13; + celt_sig_assert(tmp<=32767); + x2 = tmp; + x2 = (32767-x2) + FRAC_MUL16(x2, (-7651 + FRAC_MUL16(x2, (8277 + FRAC_MUL16(-626, x2))))); + celt_sig_assert(x2<=32766); + return 1+x2; +} + +int bitexact_log2tan(int isin,int icos) +{ + int lc; + int ls; + lc=EC_ILOG(icos); + ls=EC_ILOG(isin); + icos<<=15-lc; + isin<<=15-ls; + return (ls-lc)*(1<<11) + +FRAC_MUL16(isin, FRAC_MUL16(isin, -2597) + 7932) + -FRAC_MUL16(icos, FRAC_MUL16(icos, -2597) + 7932); +} + +#ifdef FIXED_POINT +/* Compute the amplitude (sqrt energy) in each of the bands */ +void compute_band_energies(const CELTMode *m, const celt_sig *X, celt_ener *bandE, int end, int C, int LM, int arch) +{ + int i, c, N; + const opus_int16 *eBands = m->eBands; + (void)arch; + N = m->shortMdctSize< 0) + { + int shift = celt_ilog2(maxval) - 14 + (((m->logN[i]>>BITRES)+LM+1)>>1); + j=eBands[i]<0) + { + do { + sum = MAC16_16(sum, EXTRACT16(SHR32(X[j+c*N],shift)), + EXTRACT16(SHR32(X[j+c*N],shift))); + } while (++jnbEBands] = EPSILON+VSHR32(EXTEND32(celt_sqrt(sum)),-shift); + } else { + bandE[i+c*m->nbEBands] = EPSILON; + } + /*printf ("%f ", bandE[i+c*m->nbEBands]);*/ + } + } while (++ceBands; + N = M*m->shortMdctSize; + c=0; do { + i=0; do { + opus_val16 g; + int j,shift; + opus_val16 E; + shift = celt_zlog2(bandE[i+c*m->nbEBands])-13; + E = VSHR32(bandE[i+c*m->nbEBands], shift); + g = EXTRACT16(celt_rcp(SHL32(E,3))); + j=M*eBands[i]; do { + X[j+c*N] = MULT16_16_Q15(VSHR32(freq[j+c*N],shift-1),g); + } while (++jeBands; + N = m->shortMdctSize<nbEBands] = celt_sqrt(sum); + /*printf ("%f ", bandE[i+c*m->nbEBands]);*/ + } + } while (++ceBands; + N = M*m->shortMdctSize; + c=0; do { + for (i=0;inbEBands]); + for (j=M*eBands[i];jeBands; + N = M*m->shortMdctSize; + bound = M*eBands[end]; + if (downsample!=1) + bound = IMIN(bound, N/downsample); + if (silence) + { + bound = 0; + start = end = 0; + } + f = freq; + x = X+M*eBands[start]; + for (i=0;i>DB_SHIFT); + if (shift>31) + { + shift=0; + g=0; + } else { + /* Handle the fractional part. */ + g = celt_exp2_frac(lg&((1< 16384 we'd be likely to overflow, so we're + capping the gain here, which is equivalent to a cap of 18 on lg. + This shouldn't trigger unless the bitstream is already corrupted. */ + if (shift <= -2) + { + g = 16384; + shift = -2; + } + do { + *f++ = SHL32(MULT16_16(*x++, g), -shift); + } while (++jeBands[i+1]-m->eBands[i]; + /* depth in 1/8 bits */ + celt_sig_assert(pulses[i]>=0); + depth = celt_udiv(1+pulses[i], (m->eBands[i+1]-m->eBands[i]))>>LM; + +#ifdef FIXED_POINT + thresh32 = SHR32(celt_exp2(-SHL16(depth, 10-BITRES)),1); + thresh = MULT16_32_Q15(QCONST16(0.5f, 15), MIN32(32767,thresh32)); + { + opus_val32 t; + t = N0<>1; + t = SHL32(t, (7-shift)<<1); + sqrt_1 = celt_rsqrt_norm(t); + } +#else + thresh = .5f*celt_exp2(-.125f*depth); + sqrt_1 = celt_rsqrt(N0<nbEBands+i]; + prev2 = prev2logE[c*m->nbEBands+i]; + if (C==1) + { + prev1 = MAX16(prev1,prev1logE[m->nbEBands+i]); + prev2 = MAX16(prev2,prev2logE[m->nbEBands+i]); + } + Ediff = EXTEND32(logE[c*m->nbEBands+i])-EXTEND32(MIN16(prev1,prev2)); + Ediff = MAX32(0, Ediff); + +#ifdef FIXED_POINT + if (Ediff < 16384) + { + opus_val32 r32 = SHR32(celt_exp2(-EXTRACT16(Ediff)),1); + r = 2*MIN16(16383,r32); + } else { + r = 0; + } + if (LM==3) + r = MULT16_16_Q14(23170, MIN32(23169, r)); + r = SHR16(MIN16(thresh, r),1); + r = SHR32(MULT16_16_Q15(sqrt_1, r),shift); +#else + /* r needs to be multiplied by 2 or 2*sqrt(2) depending on LM because + short blocks don't have the same energy as long */ + r = 2.f*celt_exp2(-Ediff); + if (LM==3) + r *= 1.41421356f; + r = MIN16(thresh, r); + r = r*sqrt_1; +#endif + X = X_+c*size+(m->eBands[i]<nbEBands]))-13; +#endif + left = VSHR32(bandE[i],shift); + right = VSHR32(bandE[i+m->nbEBands],shift); + norm = EPSILON + celt_sqrt(EPSILON+MULT16_16(left,left)+MULT16_16(right,right)); + a1 = DIV32_16(SHL32(EXTEND32(left),14),norm); + a2 = DIV32_16(SHL32(EXTEND32(right),14),norm); + for (j=0;j>1; + kr = celt_ilog2(Er)>>1; +#endif + t = VSHR32(El, (kl-7)<<1); + lgain = celt_rsqrt_norm(t); + t = VSHR32(Er, (kr-7)<<1); + rgain = celt_rsqrt_norm(t); + +#ifdef FIXED_POINT + if (kl < 7) + kl = 7; + if (kr < 7) + kr = 7; +#endif + + for (j=0;jeBands; + int decision; + int hf_sum=0; + + celt_assert(end>0); + + N0 = M*m->shortMdctSize; + + if (M*(eBands[end]-eBands[end-1]) <= 8) + return SPREAD_NONE; + c=0; do { + for (i=0;im->nbEBands-4) + hf_sum += celt_udiv(32*(tcount[1]+tcount[0]), N); + tmp = (2*tcount[2] >= N) + (2*tcount[1] >= N) + (2*tcount[0] >= N); + sum += tmp*spread_weight[i]; + nbBands+=spread_weight[i]; + } + } while (++cnbEBands+end)); + *hf_average = (*hf_average+hf_sum)>>1; + hf_sum = *hf_average; + if (*tapset_decision==2) + hf_sum += 4; + else if (*tapset_decision==0) + hf_sum -= 4; + if (hf_sum > 22) + *tapset_decision=2; + else if (hf_sum > 18) + *tapset_decision=1; + else + *tapset_decision=0; + } + /*printf("%d %d %d\n", hf_sum, *hf_average, *tapset_decision);*/ + celt_assert(nbBands>0); /* end has to be non-zero */ + celt_assert(sum>=0); + sum = celt_udiv((opus_int32)sum<<8, nbBands); + /* Recursive averaging */ + sum = (sum+*average)>>1; + *average = sum; + /* Hysteresis */ + sum = (3*sum + (((3-last_decision)<<7) + 64) + 2)>>2; + if (sum < 80) + { + decision = SPREAD_AGGRESSIVE; + } else if (sum < 256) + { + decision = SPREAD_NORMAL; + } else if (sum < 384) + { + decision = SPREAD_LIGHT; + } else { + decision = SPREAD_NONE; + } +#ifdef FUZZING + decision = rand()&0x3; + *tapset_decision=rand()%3; +#endif + return decision; +} + +/* Indexing table for converting from natural Hadamard to ordery Hadamard + This is essentially a bit-reversed Gray, on top of which we've added + an inversion of the order because we want the DC at the end rather than + the beginning. The lines are for N=2, 4, 8, 16 */ +static const int ordery_table[] = { + 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 void deinterleave_hadamard(celt_norm *X, int N0, int stride, int hadamard) +{ + int i,j; + VARDECL(celt_norm, tmp); + int N; + SAVE_STACK; + N = N0*stride; + ALLOC(tmp, N, celt_norm); + celt_assert(stride>0); + if (hadamard) + { + const int *ordery = ordery_table+stride-2; + for (i=0;i>= 1; + for (i=0;i>1)) { + qn = 1; + } else { + qn = exp2_table8[qb&0x7]>>(14-(qb>>BITRES)); + qn = (qn+1)>>1<<1; + } + celt_assert(qn <= 256); + return qn; +} + +struct band_ctx { + int encode; + int resynth; + const CELTMode *m; + int i; + int intensity; + int spread; + int tf_change; + ec_ctx *ec; + opus_int32 remaining_bits; + const celt_ener *bandE; + opus_uint32 seed; + int arch; + int theta_round; + int disable_inv; + int avoid_split_noise; +}; + +struct split_ctx { + int inv; + int imid; + int iside; + int delta; + int itheta; + int qalloc; +}; + +static void compute_theta(struct band_ctx *ctx, struct split_ctx *sctx, + celt_norm *X, celt_norm *Y, int N, int *b, int B, int B0, + int LM, + int stereo, int *fill) +{ + int qn; + int itheta=0; + int delta; + int imid, iside; + int qalloc; + int pulse_cap; + int offset; + opus_int32 tell; + int inv=0; + int encode; + const CELTMode *m; + int i; + int intensity; + ec_ctx *ec; + const celt_ener *bandE; + + encode = ctx->encode; + m = ctx->m; + i = ctx->i; + intensity = ctx->intensity; + ec = ctx->ec; + bandE = ctx->bandE; + + /* Decide on the resolution to give to the split parameter theta */ + pulse_cap = m->logN[i]+LM*(1<>1) - (stereo&&N==2 ? QTHETA_OFFSET_TWOPHASE : QTHETA_OFFSET); + qn = compute_qn(N, *b, offset, pulse_cap, stereo); + if (stereo && i>=intensity) + qn = 1; + if (encode) + { + /* theta is the atan() of the ratio between the (normalized) + side and mid. With just that parameter, we can re-scale both + mid and side because we know that 1) they have unit norm and + 2) they are orthogonal. */ + itheta = stereo_itheta(X, Y, stereo, N, ctx->arch); + } + tell = ec_tell_frac(ec); + if (qn!=1) + { + if (encode) + { + if (!stereo || ctx->theta_round == 0) + { + itheta = (itheta*(opus_int32)qn+8192)>>14; + if (!stereo && ctx->avoid_split_noise && itheta > 0 && itheta < qn) + { + /* Check if the selected value of theta will cause the bit allocation + to inject noise on one side. If so, make sure the energy of that side + is zero. */ + int unquantized = celt_udiv((opus_int32)itheta*16384, qn); + imid = bitexact_cos((opus_int16)unquantized); + iside = bitexact_cos((opus_int16)(16384-unquantized)); + delta = FRAC_MUL16((N-1)<<7,bitexact_log2tan(iside,imid)); + if (delta > *b) + itheta = qn; + else if (delta < -*b) + itheta = 0; + } + } else { + int down; + /* Bias quantization towards itheta=0 and itheta=16384. */ + int bias = itheta > 8192 ? 32767/qn : -32767/qn; + down = IMIN(qn-1, IMAX(0, (itheta*(opus_int32)qn + bias)>>14)); + if (ctx->theta_round < 0) + itheta = down; + else + itheta = down+1; + } + } + /* Entropy coding of the angle. We use a uniform pdf for the + time split, a step for stereo, and a triangular one for the rest. */ + if (stereo && N>2) + { + int p0 = 3; + int x = itheta; + int x0 = qn/2; + int ft = p0*(x0+1) + x0; + /* Use a probability of p0 up to itheta=8192 and then use 1 after */ + if (encode) + { + ec_encode(ec,x<=x0?p0*x:(x-1-x0)+(x0+1)*p0,x<=x0?p0*(x+1):(x-x0)+(x0+1)*p0,ft); + } else { + int fs; + fs=ec_decode(ec,ft); + if (fs<(x0+1)*p0) + x=fs/p0; + else + x=x0+1+(fs-(x0+1)*p0); + ec_dec_update(ec,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) { + /* Uniform pdf */ + if (encode) + ec_enc_uint(ec, itheta, qn+1); + else + itheta = ec_dec_uint(ec, qn+1); + } else { + int fs=1, ft; + ft = ((qn>>1)+1)*((qn>>1)+1); + if (encode) + { + int fl; + + fs = itheta <= (qn>>1) ? itheta + 1 : qn + 1 - itheta; + fl = itheta <= (qn>>1) ? itheta*(itheta + 1)>>1 : + ft - ((qn + 1 - itheta)*(qn + 2 - itheta)>>1); + + ec_encode(ec, fl, fl+fs, ft); + } else { + /* Triangular pdf */ + int fl=0; + int fm; + fm = ec_decode(ec, ft); + + if (fm < ((qn>>1)*((qn>>1) + 1)>>1)) + { + itheta = (isqrt32(8*(opus_uint32)fm + 1) - 1)>>1; + fs = itheta + 1; + fl = itheta*(itheta + 1)>>1; + } + else + { + itheta = (2*(qn + 1) + - isqrt32(8*(opus_uint32)(ft - fm - 1) + 1))>>1; + fs = qn + 1 - itheta; + fl = ft - ((qn + 1 - itheta)*(qn + 2 - itheta)>>1); + } + + ec_dec_update(ec, fl, fl+fs, ft); + } + } + celt_assert(itheta>=0); + itheta = celt_udiv((opus_int32)itheta*16384, qn); + if (encode && stereo) + { + if (itheta==0) + intensity_stereo(m, X, Y, bandE, i, N); + else + stereo_split(X, Y, N); + } + /* NOTE: Renormalising X and Y *may* help fixed-point a bit at very high rate. + Let's do that at higher complexity */ + } else if (stereo) { + if (encode) + { + inv = itheta > 8192 && !ctx->disable_inv; + if (inv) + { + int j; + for (j=0;j2<remaining_bits > 2<disable_inv) + inv = 0; + itheta = 0; + } + qalloc = ec_tell_frac(ec) - tell; + *b -= qalloc; + + if (itheta == 0) + { + imid = 32767; + iside = 0; + *fill &= (1<inv = inv; + sctx->imid = imid; + sctx->iside = iside; + sctx->delta = delta; + sctx->itheta = itheta; + sctx->qalloc = qalloc; +} +static unsigned quant_band_n1(struct band_ctx *ctx, celt_norm *X, celt_norm *Y, int b, + celt_norm *lowband_out) +{ + int c; + int stereo; + celt_norm *x = X; + int encode; + ec_ctx *ec; + + encode = ctx->encode; + ec = ctx->ec; + + stereo = Y != NULL; + c=0; do { + int sign=0; + if (ctx->remaining_bits>=1<remaining_bits -= 1<resynth) + x[0] = sign ? -NORM_SCALING : NORM_SCALING; + x = Y; + } while (++c<1+stereo); + if (lowband_out) + lowband_out[0] = SHR16(X[0],4); + return 1; +} + +/* This function is responsible for encoding and decoding a mono partition. + It can split the band in two and transmit the energy difference with + the two half-bands. It can be called recursively so bands can end up being + split in 8 parts. */ +static unsigned quant_partition(struct band_ctx *ctx, celt_norm *X, + int N, int b, int B, celt_norm *lowband, + int LM, + opus_val16 gain, int fill) +{ + const unsigned char *cache; + int q; + int curr_bits; + int imid=0, iside=0; + int B0=B; + opus_val16 mid=0, side=0; + unsigned cm=0; + celt_norm *Y=NULL; + int encode; + const CELTMode *m; + int i; + int spread; + ec_ctx *ec; + + encode = ctx->encode; + m = ctx->m; + i = ctx->i; + spread = ctx->spread; + ec = ctx->ec; + + /* If we need 1.5 more bit than we can produce, split the band in two. */ + cache = m->cache.bits + m->cache.index[(LM+1)*m->nbEBands+i]; + if (LM != -1 && b > cache[cache[0]]+12 && N>2) + { + int mbits, sbits, delta; + int itheta; + int qalloc; + struct split_ctx sctx; + celt_norm *next_lowband2=NULL; + opus_int32 rebalance; + + N >>= 1; + Y = X+N; + LM -= 1; + if (B==1) + fill = (fill&1)|(fill<<1); + B = (B+1)>>1; + + compute_theta(ctx, &sctx, X, Y, N, &b, B, B0, LM, 0, &fill); + imid = sctx.imid; + iside = sctx.iside; + delta = sctx.delta; + itheta = sctx.itheta; + qalloc = sctx.qalloc; +#ifdef FIXED_POINT + mid = imid; + side = iside; +#else + mid = (1.f/32768)*imid; + side = (1.f/32768)*iside; +#endif + + /* Give more bits to low-energy MDCTs than they would otherwise deserve */ + if (B0>1 && (itheta&0x3fff)) + { + if (itheta > 8192) + /* Rough approximation for pre-echo masking */ + delta -= delta>>(4-LM); + else + /* Corresponds to a forward-masking slope of 1.5 dB per 10 ms */ + delta = IMIN(0, delta + (N<>(5-LM))); + } + mbits = IMAX(0, IMIN(b, (b-delta)/2)); + sbits = b-mbits; + ctx->remaining_bits -= qalloc; + + if (lowband) + next_lowband2 = lowband+N; /* >32-bit split case */ + + rebalance = ctx->remaining_bits; + if (mbits >= sbits) + { + cm = quant_partition(ctx, X, N, mbits, B, lowband, LM, + MULT16_16_P15(gain,mid), fill); + rebalance = mbits - (rebalance-ctx->remaining_bits); + if (rebalance > 3<>B)<<(B0>>1); + } else { + cm = quant_partition(ctx, Y, N, sbits, B, next_lowband2, LM, + MULT16_16_P15(gain,side), fill>>B)<<(B0>>1); + rebalance = sbits - (rebalance-ctx->remaining_bits); + if (rebalance > 3<remaining_bits -= curr_bits; + + /* Ensures we can never bust the budget */ + while (ctx->remaining_bits < 0 && q > 0) + { + ctx->remaining_bits += curr_bits; + q--; + curr_bits = pulses2bits(m, i, LM, q); + ctx->remaining_bits -= curr_bits; + } + + if (q!=0) + { + int K = get_pulses(q); + + /* Finally do the actual quantization */ + if (encode) + { + cm = alg_quant(X, N, K, spread, B, ec, gain, ctx->resynth, ctx->arch); + } else { + cm = alg_unquant(X, N, K, spread, B, ec, gain); + } + } else { + /* If there's no pulse, fill the band anyway */ + int j; + if (ctx->resynth) + { + unsigned cm_mask; + /* B can be as large as 16, so this shift might overflow an int on a + 16-bit platform; use a long to get defined behavior.*/ + cm_mask = (unsigned)(1UL<seed = celt_lcg_rand(ctx->seed); + X[j] = (celt_norm)((opus_int32)ctx->seed>>20); + } + cm = cm_mask; + } else { + /* Folded spectrum */ + for (j=0;jseed = celt_lcg_rand(ctx->seed); + /* About 48 dB below the "normal" folding level */ + tmp = QCONST16(1.0f/256, 10); + tmp = (ctx->seed)&0x8000 ? tmp : -tmp; + X[j] = lowband[j]+tmp; + } + cm = fill; + } + renormalise_vector(X, N, gain, ctx->arch); + } + } + } + } + + return cm; +} + + +/* This function is responsible for encoding and decoding a band for the mono case. */ +static unsigned quant_band(struct band_ctx *ctx, celt_norm *X, + int N, int b, int B, celt_norm *lowband, + int LM, celt_norm *lowband_out, + opus_val16 gain, celt_norm *lowband_scratch, int fill) +{ + int N0=N; + int N_B=N; + int N_B0; + int B0=B; + int time_divide=0; + int recombine=0; + int longBlocks; + unsigned cm=0; + int k; + int encode; + int tf_change; + + encode = ctx->encode; + tf_change = ctx->tf_change; + + longBlocks = B0==1; + + N_B = celt_udiv(N_B, B); + + /* Special case for one sample */ + if (N==1) + { + return quant_band_n1(ctx, X, NULL, b, lowband_out); + } + + if (tf_change>0) + recombine = tf_change; + /* Band recombining to increase frequency resolution */ + + if (lowband_scratch && lowband && (recombine || ((N_B&1) == 0 && tf_change<0) || B0>1)) + { + OPUS_COPY(lowband_scratch, lowband, N); + lowband = lowband_scratch; + } + + for (k=0;k>k, 1<>k, 1<>4]<<2; + } + B>>=recombine; + N_B<<=recombine; + + /* Increasing the time resolution */ + while ((N_B&1) == 0 && tf_change<0) + { + if (encode) + haar1(X, N_B, B); + if (lowband) + haar1(lowband, N_B, B); + fill |= fill<>= 1; + time_divide++; + tf_change++; + } + B0=B; + N_B0 = N_B; + + /* Reorganize the samples in time order instead of frequency order */ + if (B0>1) + { + if (encode) + deinterleave_hadamard(X, N_B>>recombine, B0<>recombine, B0<resynth) + { + /* Undo the sample reorganization going from time order to frequency order */ + if (B0>1) + interleave_hadamard(X, N_B>>recombine, B0<>= 1; + N_B <<= 1; + cm |= cm>>B; + haar1(X, N_B, B); + } + + for (k=0;k>k, 1<encode; + ec = ctx->ec; + + /* Special case for one sample */ + if (N==1) + { + return quant_band_n1(ctx, X, Y, b, lowband_out); + } + + orig_fill = fill; + + compute_theta(ctx, &sctx, X, Y, N, &b, B, B, LM, 1, &fill); + inv = sctx.inv; + imid = sctx.imid; + iside = sctx.iside; + delta = sctx.delta; + itheta = sctx.itheta; + qalloc = sctx.qalloc; +#ifdef FIXED_POINT + mid = imid; + side = iside; +#else + mid = (1.f/32768)*imid; + side = (1.f/32768)*iside; +#endif + + /* This is a special case for N=2 that only works for stereo and takes + advantage of the fact that mid and side are orthogonal to encode + the side with just one bit. */ + if (N==2) + { + int c; + int sign=0; + celt_norm *x2, *y2; + mbits = b; + sbits = 0; + /* Only need one bit for the side. */ + if (itheta != 0 && itheta != 16384) + sbits = 1< 8192; + ctx->remaining_bits -= qalloc+sbits; + + x2 = c ? Y : X; + y2 = c ? X : Y; + if (sbits) + { + if (encode) + { + /* Here we only need to encode a sign for the side. */ + sign = x2[0]*y2[1] - x2[1]*y2[0] < 0; + ec_enc_bits(ec, sign, 1); + } else { + sign = ec_dec_bits(ec, 1); + } + } + sign = 1-2*sign; + /* We use orig_fill here because we want to fold the side, but if + itheta==16384, we'll have cleared the low bits of fill. */ + cm = quant_band(ctx, x2, N, mbits, B, lowband, LM, lowband_out, Q15ONE, + lowband_scratch, orig_fill); + /* We don't split N=2 bands, so cm is either 1 or 0 (for a fold-collapse), + and there's no need to worry about mixing with the other channel. */ + y2[0] = -sign*x2[1]; + y2[1] = sign*x2[0]; + if (ctx->resynth) + { + celt_norm tmp; + X[0] = MULT16_16_Q15(mid, X[0]); + X[1] = MULT16_16_Q15(mid, X[1]); + Y[0] = MULT16_16_Q15(side, Y[0]); + Y[1] = MULT16_16_Q15(side, Y[1]); + tmp = X[0]; + X[0] = SUB16(tmp,Y[0]); + Y[0] = ADD16(tmp,Y[0]); + tmp = X[1]; + X[1] = SUB16(tmp,Y[1]); + Y[1] = ADD16(tmp,Y[1]); + } + } else { + /* "Normal" split code */ + opus_int32 rebalance; + + mbits = IMAX(0, IMIN(b, (b-delta)/2)); + sbits = b-mbits; + ctx->remaining_bits -= qalloc; + + rebalance = ctx->remaining_bits; + if (mbits >= sbits) + { + /* In stereo mode, we do not apply a scaling to the mid because we need the normalized + mid for folding later. */ + cm = quant_band(ctx, X, N, mbits, B, lowband, LM, lowband_out, Q15ONE, + lowband_scratch, fill); + rebalance = mbits - (rebalance-ctx->remaining_bits); + if (rebalance > 3<>B); + } else { + /* For a stereo split, the high bits of fill are always zero, so no + folding will be done to the side. */ + cm = quant_band(ctx, Y, N, sbits, B, NULL, LM, NULL, side, NULL, fill>>B); + rebalance = sbits - (rebalance-ctx->remaining_bits); + if (rebalance > 3<resynth) + { + if (N!=2) + stereo_merge(X, Y, mid, N, ctx->arch); + if (inv) + { + int j; + for (j=0;jeBands; + n1 = M*(eBands[start+1]-eBands[start]); + n2 = M*(eBands[start+2]-eBands[start+1]); + /* Duplicate enough of the first band folding data to be able to fold the second band. + Copies no data for CELT-only mode. */ + OPUS_COPY(&norm[n1], &norm[2*n1 - n2], n2-n1); + if (dual_stereo) + OPUS_COPY(&norm2[n1], &norm2[2*n1 - n2], n2-n1); +} + +void quant_all_bands(int encode, const CELTMode *m, int start, int end, + celt_norm *X_, celt_norm *Y_, unsigned char *collapse_masks, + const celt_ener *bandE, int *pulses, int shortBlocks, int spread, + int dual_stereo, int intensity, int *tf_res, opus_int32 total_bits, + opus_int32 balance, ec_ctx *ec, int LM, int codedBands, + opus_uint32 *seed, int complexity, int arch, int disable_inv) +{ + int i; + opus_int32 remaining_bits; + const opus_int16 * OPUS_RESTRICT eBands = m->eBands; + celt_norm * OPUS_RESTRICT norm, * OPUS_RESTRICT norm2; + VARDECL(celt_norm, _norm); + VARDECL(celt_norm, _lowband_scratch); + VARDECL(celt_norm, X_save); + VARDECL(celt_norm, Y_save); + VARDECL(celt_norm, X_save2); + VARDECL(celt_norm, Y_save2); + VARDECL(celt_norm, norm_save2); + int resynth_alloc; + celt_norm *lowband_scratch; + int B; + int M; + int lowband_offset; + int update_lowband = 1; + int C = Y_ != NULL ? 2 : 1; + int norm_offset; + int theta_rdo = encode && Y_!=NULL && !dual_stereo && complexity>=8; +#ifdef RESYNTH + int resynth = 1; +#else + int resynth = !encode || theta_rdo; +#endif + struct band_ctx ctx; + SAVE_STACK; + + M = 1<nbEBands-1]-norm_offset), celt_norm); + norm = _norm; + norm2 = norm + M*eBands[m->nbEBands-1]-norm_offset; + + /* For decoding, we can use the last band as scratch space because we don't need that + scratch space for the last band and we don't care about the data there until we're + decoding the last band. */ + if (encode && resynth) + resynth_alloc = M*(eBands[m->nbEBands]-eBands[m->nbEBands-1]); + else + resynth_alloc = ALLOC_NONE; + ALLOC(_lowband_scratch, resynth_alloc, celt_norm); + if (encode && resynth) + lowband_scratch = _lowband_scratch; + else + lowband_scratch = X_+M*eBands[m->nbEBands-1]; + ALLOC(X_save, resynth_alloc, celt_norm); + ALLOC(Y_save, resynth_alloc, celt_norm); + ALLOC(X_save2, resynth_alloc, celt_norm); + ALLOC(Y_save2, resynth_alloc, celt_norm); + ALLOC(norm_save2, resynth_alloc, celt_norm); + + lowband_offset = 0; + ctx.bandE = bandE; + ctx.ec = ec; + ctx.encode = encode; + ctx.intensity = intensity; + ctx.m = m; + ctx.seed = *seed; + ctx.spread = spread; + ctx.arch = arch; + ctx.disable_inv = disable_inv; + ctx.resynth = resynth; + ctx.theta_round = 0; + /* Avoid injecting noise in the first band on transients. */ + ctx.avoid_split_noise = B > 1; + for (i=start;i 0); + tell = ec_tell_frac(ec); + + /* Compute how many bits we want to allocate to this band */ + if (i != start) + balance -= tell; + remaining_bits = total_bits-tell-1; + ctx.remaining_bits = remaining_bits; + if (i <= codedBands-1) + { + curr_balance = celt_sudiv(balance, IMIN(3, codedBands-i)); + b = IMAX(0, IMIN(16383, IMIN(remaining_bits+1,pulses[i]+curr_balance))); + } else { + b = 0; + } + +#ifndef DISABLE_UPDATE_DRAFT + if (resynth && (M*eBands[i]-N >= M*eBands[start] || i==start+1) && (update_lowband || lowband_offset==0)) + lowband_offset = i; + if (i == start+1) + special_hybrid_folding(m, norm, norm2, start, M, dual_stereo); +#else + if (resynth && M*eBands[i]-N >= M*eBands[start] && (update_lowband || lowband_offset==0)) + lowband_offset = i; +#endif + + tf_change = tf_res[i]; + ctx.tf_change = tf_change; + if (i>=m->effEBands) + { + X=norm; + if (Y_!=NULL) + Y = norm; + lowband_scratch = NULL; + } + if (last && !theta_rdo) + lowband_scratch = NULL; + + /* Get a conservative estimate of the collapse_mask's for the bands we're + going to be folding from. */ + if (lowband_offset != 0 && (spread!=SPREAD_AGGRESSIVE || B>1 || tf_change<0)) + { + int fold_start; + int fold_end; + int fold_i; + /* This ensures we never repeat spectral content within one band */ + effective_lowband = IMAX(0, M*eBands[lowband_offset]-norm_offset-N); + fold_start = lowband_offset; + while(M*eBands[--fold_start] > effective_lowband+norm_offset); + fold_end = lowband_offset-1; +#ifndef DISABLE_UPDATE_DRAFT + while(++fold_end < i && M*eBands[fold_end] < effective_lowband+norm_offset+N); +#else + while(M*eBands[++fold_end] < effective_lowband+norm_offset+N); +#endif + x_cm = y_cm = 0; + fold_i = fold_start; do { + x_cm |= collapse_masks[fold_i*C+0]; + y_cm |= collapse_masks[fold_i*C+C-1]; + } while (++fold_inbEBands], w); + /* Make a copy. */ + cm = x_cm|y_cm; + ec_save = *ec; + ctx_save = ctx; + OPUS_COPY(X_save, X, N); + OPUS_COPY(Y_save, Y, N); + /* Encode and round down. */ + ctx.theta_round = -1; + x_cm = quant_band_stereo(&ctx, X, Y, N, b, B, + effective_lowband != -1 ? norm+effective_lowband : NULL, LM, + last?NULL:norm+M*eBands[i]-norm_offset, lowband_scratch, cm); + dist0 = MULT16_32_Q15(w[0], celt_inner_prod(X_save, X, N, arch)) + MULT16_32_Q15(w[1], celt_inner_prod(Y_save, Y, N, arch)); + + /* Save first result. */ + cm2 = x_cm; + ec_save2 = *ec; + ctx_save2 = ctx; + OPUS_COPY(X_save2, X, N); + OPUS_COPY(Y_save2, Y, N); + if (!last) + OPUS_COPY(norm_save2, norm+M*eBands[i]-norm_offset, N); + nstart_bytes = ec_save.offs; + nend_bytes = ec_save.storage; + bytes_buf = ec_save.buf+nstart_bytes; + save_bytes = nend_bytes-nstart_bytes; + OPUS_COPY(bytes_save, bytes_buf, save_bytes); + + /* Restore */ + *ec = ec_save; + ctx = ctx_save; + OPUS_COPY(X, X_save, N); + OPUS_COPY(Y, Y_save, N); +#ifndef DISABLE_UPDATE_DRAFT + if (i == start+1) + special_hybrid_folding(m, norm, norm2, start, M, dual_stereo); +#endif + /* Encode and round up. */ + ctx.theta_round = 1; + x_cm = quant_band_stereo(&ctx, X, Y, N, b, B, + effective_lowband != -1 ? norm+effective_lowband : NULL, LM, + last?NULL:norm+M*eBands[i]-norm_offset, lowband_scratch, cm); + dist1 = MULT16_32_Q15(w[0], celt_inner_prod(X_save, X, N, arch)) + MULT16_32_Q15(w[1], celt_inner_prod(Y_save, Y, N, arch)); + if (dist0 >= dist1) { + x_cm = cm2; + *ec = ec_save2; + ctx = ctx_save2; + OPUS_COPY(X, X_save2, N); + OPUS_COPY(Y, Y_save2, N); + if (!last) + OPUS_COPY(norm+M*eBands[i]-norm_offset, norm_save2, N); + OPUS_COPY(bytes_buf, bytes_save, save_bytes); + } + } else { + ctx.theta_round = 0; + x_cm = quant_band_stereo(&ctx, X, Y, N, b, B, + effective_lowband != -1 ? norm+effective_lowband : NULL, LM, + last?NULL:norm+M*eBands[i]-norm_offset, lowband_scratch, x_cm|y_cm); + } + } else { + x_cm = quant_band(&ctx, X, N, b, B, + effective_lowband != -1 ? norm+effective_lowband : NULL, LM, + last?NULL:norm+M*eBands[i]-norm_offset, Q15ONE, lowband_scratch, x_cm|y_cm); + } + y_cm = x_cm; + } + collapse_masks[i*C+0] = (unsigned char)x_cm; + collapse_masks[i*C+C-1] = (unsigned char)y_cm; + balance += pulses[i] + tell; + + /* Update the folding position only as long as we have 1 bit/sample depth. */ + update_lowband = b>(N< +#include "celt.h" +#include "pitch.h" +#include "bands.h" +#include "modes.h" +#include "entcode.h" +#include "quant_bands.h" +#include "rate.h" +#include "stack_alloc.h" +#include "mathops.h" +#include "float_cast.h" +#include +#include "celt_lpc.h" +#include "vq.h" + +#ifndef PACKAGE_VERSION +#define PACKAGE_VERSION "unknown" +#endif + +#if defined(MIPSr1_ASM) +#include "mips/celt_mipsr1.h" +#endif + + +int resampling_factor(opus_int32 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: +#ifndef CUSTOM_MODES + celt_assert(0); +#endif + ret = 0; + break; + } + return ret; +} + +#if !defined(OVERRIDE_COMB_FILTER_CONST) || defined(NON_STATIC_COMB_FILTER_CONST_C) +/* This version should be faster on ARM */ +#ifdef OPUS_ARM_ASM +#ifndef NON_STATIC_COMB_FILTER_CONST_C +static +#endif +void comb_filter_const_c(opus_val32 *y, opus_val32 *x, int T, int N, + opus_val16 g10, opus_val16 g11, opus_val16 g12) +{ + opus_val32 x0, x1, x2, x3, x4; + int i; + x4 = SHL32(x[-T-2], 1); + x3 = SHL32(x[-T-1], 1); + x2 = SHL32(x[-T], 1); + x1 = SHL32(x[-T+1], 1); + for (i=0;inbEBands;i++) + { + int N; + N=(m->eBands[i+1]-m->eBands[i])<cache.caps[m->nbEBands*(2*LM+C-1)+i]+64)*C*N>>2; + } +} + + + +const char *opus_strerror(int error) +{ + static const char * const error_strings[8] = { + "success", + "invalid argument", + "buffer too small", + "internal error", + "corrupted stream", + "request not implemented", + "invalid state", + "memory allocation failed" + }; + if (error > 0 || error < -7) + return "unknown error"; + else + return error_strings[-error]; +} + +const char *opus_get_version_string(void) +{ + return "libopus " PACKAGE_VERSION + /* Applications may rely on the presence of this substring in the version + string to determine if they have a fixed-point or floating-point build + at runtime. */ +#ifdef FIXED_POINT + "-fixed" +#endif +#ifdef FUZZING + "-fuzzing" +#endif + ; +} diff --git a/extern/opus/celt/celt.h b/extern/opus/celt/celt.h new file mode 100644 index 0000000..24b6b2b --- /dev/null +++ b/extern/opus/celt/celt.h @@ -0,0 +1,251 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Copyright (c) 2008 Gregory Maxwell + Written by Jean-Marc Valin and Gregory Maxwell */ +/** + @file celt.h + @brief Contains all the functions for encoding and decoding audio + */ + +/* + 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. + + 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 OWNER + 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. +*/ + +#ifndef CELT_H +#define CELT_H + +#include "opus_types.h" +#include "opus_defines.h" +#include "opus_custom.h" +#include "entenc.h" +#include "entdec.h" +#include "arch.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define CELTEncoder OpusCustomEncoder +#define CELTDecoder OpusCustomDecoder +#define CELTMode OpusCustomMode + +#define LEAK_BANDS 19 + +typedef struct { + int valid; + float tonality; + float tonality_slope; + float noisiness; + float activity; + float music_prob; + float music_prob_min; + float music_prob_max; + int bandwidth; + float activity_probability; + float max_pitch_ratio; + /* Store as Q6 char to save space. */ + unsigned char leak_boost[LEAK_BANDS]; +} AnalysisInfo; + +typedef struct { + int signalType; + int offset; +} SILKInfo; + +#define __celt_check_mode_ptr_ptr(ptr) ((ptr) + ((ptr) - (const CELTMode**)(ptr))) + +#define __celt_check_analysis_ptr(ptr) ((ptr) + ((ptr) - (const AnalysisInfo*)(ptr))) + +#define __celt_check_silkinfo_ptr(ptr) ((ptr) + ((ptr) - (const SILKInfo*)(ptr))) + +/* Encoder/decoder Requests */ + + +#define CELT_SET_PREDICTION_REQUEST 10002 +/** Controls the use of interframe prediction. + 0=Independent frames + 1=Short term interframe prediction allowed + 2=Long term prediction allowed + */ +#define CELT_SET_PREDICTION(x) CELT_SET_PREDICTION_REQUEST, __opus_check_int(x) + +#define CELT_SET_INPUT_CLIPPING_REQUEST 10004 +#define CELT_SET_INPUT_CLIPPING(x) CELT_SET_INPUT_CLIPPING_REQUEST, __opus_check_int(x) + +#define CELT_GET_AND_CLEAR_ERROR_REQUEST 10007 +#define CELT_GET_AND_CLEAR_ERROR(x) CELT_GET_AND_CLEAR_ERROR_REQUEST, __opus_check_int_ptr(x) + +#define CELT_SET_CHANNELS_REQUEST 10008 +#define CELT_SET_CHANNELS(x) CELT_SET_CHANNELS_REQUEST, __opus_check_int(x) + + +/* Internal */ +#define CELT_SET_START_BAND_REQUEST 10010 +#define CELT_SET_START_BAND(x) CELT_SET_START_BAND_REQUEST, __opus_check_int(x) + +#define CELT_SET_END_BAND_REQUEST 10012 +#define CELT_SET_END_BAND(x) CELT_SET_END_BAND_REQUEST, __opus_check_int(x) + +#define CELT_GET_MODE_REQUEST 10015 +/** Get the CELTMode used by an encoder or decoder */ +#define CELT_GET_MODE(x) CELT_GET_MODE_REQUEST, __celt_check_mode_ptr_ptr(x) + +#define CELT_SET_SIGNALLING_REQUEST 10016 +#define CELT_SET_SIGNALLING(x) CELT_SET_SIGNALLING_REQUEST, __opus_check_int(x) + +#define CELT_SET_TONALITY_REQUEST 10018 +#define CELT_SET_TONALITY(x) CELT_SET_TONALITY_REQUEST, __opus_check_int(x) +#define CELT_SET_TONALITY_SLOPE_REQUEST 10020 +#define CELT_SET_TONALITY_SLOPE(x) CELT_SET_TONALITY_SLOPE_REQUEST, __opus_check_int(x) + +#define CELT_SET_ANALYSIS_REQUEST 10022 +#define CELT_SET_ANALYSIS(x) CELT_SET_ANALYSIS_REQUEST, __celt_check_analysis_ptr(x) + +#define OPUS_SET_LFE_REQUEST 10024 +#define OPUS_SET_LFE(x) OPUS_SET_LFE_REQUEST, __opus_check_int(x) + +#define OPUS_SET_ENERGY_MASK_REQUEST 10026 +#define OPUS_SET_ENERGY_MASK(x) OPUS_SET_ENERGY_MASK_REQUEST, __opus_check_val16_ptr(x) + +#define CELT_SET_SILK_INFO_REQUEST 10028 +#define CELT_SET_SILK_INFO(x) CELT_SET_SILK_INFO_REQUEST, __celt_check_silkinfo_ptr(x) + +/* Encoder stuff */ + +int celt_encoder_get_size(int channels); + +int celt_encode_with_ec(OpusCustomEncoder * OPUS_RESTRICT st, const opus_val16 * pcm, int frame_size, unsigned char *compressed, int nbCompressedBytes, ec_enc *enc); + +int celt_encoder_init(CELTEncoder *st, opus_int32 sampling_rate, int channels, + int arch); + + + +/* Decoder stuff */ + +int celt_decoder_get_size(int channels); + + +int celt_decoder_init(CELTDecoder *st, opus_int32 sampling_rate, int channels); + +int celt_decode_with_ec(OpusCustomDecoder * OPUS_RESTRICT st, const unsigned char *data, + int len, opus_val16 * OPUS_RESTRICT pcm, int frame_size, ec_dec *dec, int accum); + +#define celt_encoder_ctl opus_custom_encoder_ctl +#define celt_decoder_ctl opus_custom_decoder_ctl + + +#ifdef CUSTOM_MODES +#define OPUS_CUSTOM_NOSTATIC +#else +#define OPUS_CUSTOM_NOSTATIC static OPUS_INLINE +#endif + +static const unsigned char trim_icdf[11] = {126, 124, 119, 109, 87, 41, 19, 9, 4, 2, 0}; +/* Probs: NONE: 21.875%, LIGHT: 6.25%, NORMAL: 65.625%, AGGRESSIVE: 6.25% */ +static const unsigned char spread_icdf[4] = {25, 23, 2, 0}; + +static const unsigned char tapset_icdf[3]={2,1,0}; + +#ifdef CUSTOM_MODES +static const unsigned char toOpusTable[20] = { + 0xE0, 0xE8, 0xF0, 0xF8, + 0xC0, 0xC8, 0xD0, 0xD8, + 0xA0, 0xA8, 0xB0, 0xB8, + 0x00, 0x00, 0x00, 0x00, + 0x80, 0x88, 0x90, 0x98, +}; + +static const unsigned char fromOpusTable[16] = { + 0x80, 0x88, 0x90, 0x98, + 0x40, 0x48, 0x50, 0x58, + 0x20, 0x28, 0x30, 0x38, + 0x00, 0x08, 0x10, 0x18 +}; + +static OPUS_INLINE int toOpus(unsigned char c) +{ + int ret=0; + if (c<0xA0) + ret = toOpusTable[c>>3]; + if (ret == 0) + return -1; + else + return ret|(c&0x7); +} + +static OPUS_INLINE int fromOpus(unsigned char c) +{ + if (c<0x80) + return -1; + else + return fromOpusTable[(c>>3)-16] | (c&0x7); +} +#endif /* CUSTOM_MODES */ + +#define COMBFILTER_MAXPERIOD 1024 +#define COMBFILTER_MINPERIOD 15 + +extern const signed char tf_select_table[4][8]; + +#if defined(ENABLE_HARDENING) || defined(ENABLE_ASSERTIONS) +void validate_celt_decoder(CELTDecoder *st); +#define VALIDATE_CELT_DECODER(st) validate_celt_decoder(st) +#else +#define VALIDATE_CELT_DECODER(st) +#endif + +int resampling_factor(opus_int32 rate); + +void celt_preemphasis(const opus_val16 * OPUS_RESTRICT pcmp, celt_sig * OPUS_RESTRICT inp, + int N, int CC, int upsample, const opus_val16 *coef, celt_sig *mem, int clip); + +void comb_filter(opus_val32 *y, opus_val32 *x, int T0, int T1, int N, + opus_val16 g0, opus_val16 g1, int tapset0, int tapset1, + const opus_val16 *window, int overlap, int arch); + +#ifdef NON_STATIC_COMB_FILTER_CONST_C +void comb_filter_const_c(opus_val32 *y, opus_val32 *x, int T, int N, + opus_val16 g10, opus_val16 g11, opus_val16 g12); +#endif + +#ifndef OVERRIDE_COMB_FILTER_CONST +# define comb_filter_const(y, x, T, N, g10, g11, g12, arch) \ + ((void)(arch),comb_filter_const_c(y, x, T, N, g10, g11, g12)) +#endif + +void init_caps(const CELTMode *m,int *cap,int LM,int C); + +#ifdef RESYNTH +void deemphasis(celt_sig *in[], opus_val16 *pcm, int N, int C, int downsample, const opus_val16 *coef, celt_sig *mem); +void celt_synthesis(const CELTMode *mode, celt_norm *X, celt_sig * out_syn[], + opus_val16 *oldBandE, int start, int effEnd, int C, int CC, int isTransient, + int LM, int downsample, int silence); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* CELT_H */ diff --git a/extern/opus/celt/celt_decoder.c b/extern/opus/celt/celt_decoder.c new file mode 100644 index 0000000..e6efce9 --- /dev/null +++ b/extern/opus/celt/celt_decoder.c @@ -0,0 +1,1372 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2010 Xiph.Org Foundation + Copyright (c) 2008 Gregory Maxwell + Written by Jean-Marc Valin and Gregory Maxwell */ +/* + 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. + + 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 OWNER + 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. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#define CELT_DECODER_C + +#include "cpu_support.h" +#include "os_support.h" +#include "mdct.h" +#include +#include "celt.h" +#include "pitch.h" +#include "bands.h" +#include "modes.h" +#include "entcode.h" +#include "quant_bands.h" +#include "rate.h" +#include "stack_alloc.h" +#include "mathops.h" +#include "float_cast.h" +#include +#include "celt_lpc.h" +#include "vq.h" + +/* The maximum pitch lag to allow in the pitch-based PLC. It's possible to save + CPU time in the PLC pitch search by making this smaller than MAX_PERIOD. The + current value corresponds to a pitch of 66.67 Hz. */ +#define PLC_PITCH_LAG_MAX (720) +/* The minimum pitch lag to allow in the pitch-based PLC. This corresponds to a + pitch of 480 Hz. */ +#define PLC_PITCH_LAG_MIN (100) + +#if defined(SMALL_FOOTPRINT) && defined(FIXED_POINT) +#define NORM_ALIASING_HACK +#endif +/**********************************************************************/ +/* */ +/* DECODER */ +/* */ +/**********************************************************************/ +#define DECODE_BUFFER_SIZE 2048 + +/** Decoder state + @brief Decoder state + */ +struct OpusCustomDecoder { + const OpusCustomMode *mode; + int overlap; + int channels; + int stream_channels; + + int downsample; + int start, end; + int signalling; + int disable_inv; + int arch; + + /* Everything beyond this point gets cleared on a reset */ +#define DECODER_RESET_START rng + + opus_uint32 rng; + int error; + int last_pitch_index; + int loss_count; + int skip_plc; + int postfilter_period; + int postfilter_period_old; + opus_val16 postfilter_gain; + opus_val16 postfilter_gain_old; + int postfilter_tapset; + int postfilter_tapset_old; + + celt_sig preemph_memD[2]; + + celt_sig _decode_mem[1]; /* Size = channels*(DECODE_BUFFER_SIZE+mode->overlap) */ + /* opus_val16 lpc[], Size = channels*LPC_ORDER */ + /* opus_val16 oldEBands[], Size = 2*mode->nbEBands */ + /* opus_val16 oldLogE[], Size = 2*mode->nbEBands */ + /* opus_val16 oldLogE2[], Size = 2*mode->nbEBands */ + /* opus_val16 backgroundLogE[], Size = 2*mode->nbEBands */ +}; + +#if defined(ENABLE_HARDENING) || defined(ENABLE_ASSERTIONS) +/* Make basic checks on the CELT state to ensure we don't end + up writing all over memory. */ +void validate_celt_decoder(CELTDecoder *st) +{ +#ifndef CUSTOM_MODES + celt_assert(st->mode == opus_custom_mode_create(48000, 960, NULL)); + celt_assert(st->overlap == 120); +#endif + celt_assert(st->channels == 1 || st->channels == 2); + celt_assert(st->stream_channels == 1 || st->stream_channels == 2); + celt_assert(st->downsample > 0); + celt_assert(st->start == 0 || st->start == 17); + celt_assert(st->start < st->end); + celt_assert(st->end <= 21); +#ifdef OPUS_ARCHMASK + celt_assert(st->arch >= 0); + celt_assert(st->arch <= OPUS_ARCHMASK); +#endif + celt_assert(st->last_pitch_index <= PLC_PITCH_LAG_MAX); + celt_assert(st->last_pitch_index >= PLC_PITCH_LAG_MIN || st->last_pitch_index == 0); + celt_assert(st->postfilter_period < MAX_PERIOD); + celt_assert(st->postfilter_period >= COMBFILTER_MINPERIOD || st->postfilter_period == 0); + celt_assert(st->postfilter_period_old < MAX_PERIOD); + celt_assert(st->postfilter_period_old >= COMBFILTER_MINPERIOD || st->postfilter_period_old == 0); + celt_assert(st->postfilter_tapset <= 2); + celt_assert(st->postfilter_tapset >= 0); + celt_assert(st->postfilter_tapset_old <= 2); + celt_assert(st->postfilter_tapset_old >= 0); +} +#endif + +int celt_decoder_get_size(int channels) +{ + const CELTMode *mode = opus_custom_mode_create(48000, 960, NULL); + return opus_custom_decoder_get_size(mode, channels); +} + +OPUS_CUSTOM_NOSTATIC int opus_custom_decoder_get_size(const CELTMode *mode, int channels) +{ + int size = sizeof(struct CELTDecoder) + + (channels*(DECODE_BUFFER_SIZE+mode->overlap)-1)*sizeof(celt_sig) + + channels*LPC_ORDER*sizeof(opus_val16) + + 4*2*mode->nbEBands*sizeof(opus_val16); + return size; +} + +#ifdef CUSTOM_MODES +CELTDecoder *opus_custom_decoder_create(const CELTMode *mode, int channels, int *error) +{ + int ret; + CELTDecoder *st = (CELTDecoder *)opus_alloc(opus_custom_decoder_get_size(mode, channels)); + ret = opus_custom_decoder_init(st, mode, channels); + if (ret != OPUS_OK) + { + opus_custom_decoder_destroy(st); + st = NULL; + } + if (error) + *error = ret; + return st; +} +#endif /* CUSTOM_MODES */ + +int celt_decoder_init(CELTDecoder *st, opus_int32 sampling_rate, int channels) +{ + int ret; + ret = opus_custom_decoder_init(st, opus_custom_mode_create(48000, 960, NULL), channels); + if (ret != OPUS_OK) + return ret; + st->downsample = resampling_factor(sampling_rate); + if (st->downsample==0) + return OPUS_BAD_ARG; + else + return OPUS_OK; +} + +OPUS_CUSTOM_NOSTATIC int opus_custom_decoder_init(CELTDecoder *st, const CELTMode *mode, int channels) +{ + if (channels < 0 || channels > 2) + return OPUS_BAD_ARG; + + if (st==NULL) + return OPUS_ALLOC_FAIL; + + OPUS_CLEAR((char*)st, opus_custom_decoder_get_size(mode, channels)); + + st->mode = mode; + st->overlap = mode->overlap; + st->stream_channels = st->channels = channels; + + st->downsample = 1; + st->start = 0; + st->end = st->mode->effEBands; + st->signalling = 1; +#ifndef DISABLE_UPDATE_DRAFT + st->disable_inv = channels == 1; +#else + st->disable_inv = 0; +#endif + st->arch = opus_select_arch(); + + opus_custom_decoder_ctl(st, OPUS_RESET_STATE); + + return OPUS_OK; +} + +#ifdef CUSTOM_MODES +void opus_custom_decoder_destroy(CELTDecoder *st) +{ + opus_free(st); +} +#endif /* CUSTOM_MODES */ + +#ifndef CUSTOM_MODES +/* Special case for stereo with no downsampling and no accumulation. This is + quite common and we can make it faster by processing both channels in the + same loop, reducing overhead due to the dependency loop in the IIR filter. */ +static void deemphasis_stereo_simple(celt_sig *in[], opus_val16 *pcm, int N, const opus_val16 coef0, + celt_sig *mem) +{ + celt_sig * OPUS_RESTRICT x0; + celt_sig * OPUS_RESTRICT x1; + celt_sig m0, m1; + int j; + x0=in[0]; + x1=in[1]; + m0 = mem[0]; + m1 = mem[1]; + for (j=0;j1) + { + /* Shortcut for the standard (non-custom modes) case */ + for (j=0;joverlap; + nbEBands = mode->nbEBands; + N = mode->shortMdctSize<shortMdctSize; + shift = mode->maxLM; + } else { + B = 1; + NB = mode->shortMdctSize<maxLM-LM; + } + + if (CC==2&&C==1) + { + /* Copying a mono streams to two channels */ + celt_sig *freq2; + denormalise_bands(mode, X, freq, oldBandE, start, effEnd, M, + downsample, silence); + /* Store a temporary copy in the output buffer because the IMDCT destroys its input. */ + freq2 = out_syn[1]+overlap/2; + OPUS_COPY(freq2, freq, N); + for (b=0;bmdct, &freq2[b], out_syn[0]+NB*b, mode->window, overlap, shift, B, arch); + for (b=0;bmdct, &freq[b], out_syn[1]+NB*b, mode->window, overlap, shift, B, arch); + } else if (CC==1&&C==2) + { + /* Downmixing a stereo stream to mono */ + celt_sig *freq2; + freq2 = out_syn[0]+overlap/2; + denormalise_bands(mode, X, freq, oldBandE, start, effEnd, M, + downsample, silence); + /* Use the output buffer as temp array before downmixing. */ + denormalise_bands(mode, X+N, freq2, oldBandE+nbEBands, start, effEnd, M, + downsample, silence); + for (i=0;imdct, &freq[b], out_syn[0]+NB*b, mode->window, overlap, shift, B, arch); + } else { + /* Normal case (mono or stereo) */ + c=0; do { + denormalise_bands(mode, X+c*N, freq, oldBandE+c*nbEBands, start, effEnd, M, + downsample, silence); + for (b=0;bmdct, &freq[b], out_syn[c]+NB*b, mode->window, overlap, shift, B, arch); + } while (++cstorage*8; + tell = ec_tell(dec); + logp = isTransient ? 2 : 4; + tf_select_rsv = LM>0 && tell+logp+1<=budget; + budget -= tf_select_rsv; + tf_changed = curr = 0; + for (i=start;i>1, opus_val16 ); + pitch_downsample(decode_mem, lp_pitch_buf, + DECODE_BUFFER_SIZE, C, arch); + pitch_search(lp_pitch_buf+(PLC_PITCH_LAG_MAX>>1), lp_pitch_buf, + DECODE_BUFFER_SIZE-PLC_PITCH_LAG_MAX, + PLC_PITCH_LAG_MAX-PLC_PITCH_LAG_MIN, &pitch_index, arch); + pitch_index = PLC_PITCH_LAG_MAX-pitch_index; + RESTORE_STACK; + return pitch_index; +} + +static void celt_decode_lost(CELTDecoder * OPUS_RESTRICT st, int N, int LM) +{ + int c; + int i; + const int C = st->channels; + celt_sig *decode_mem[2]; + celt_sig *out_syn[2]; + opus_val16 *lpc; + opus_val16 *oldBandE, *oldLogE, *oldLogE2, *backgroundLogE; + const OpusCustomMode *mode; + int nbEBands; + int overlap; + int start; + int loss_count; + int noise_based; + const opus_int16 *eBands; + SAVE_STACK; + + mode = st->mode; + nbEBands = mode->nbEBands; + overlap = mode->overlap; + eBands = mode->eBands; + + c=0; do { + decode_mem[c] = st->_decode_mem + c*(DECODE_BUFFER_SIZE+overlap); + out_syn[c] = decode_mem[c]+DECODE_BUFFER_SIZE-N; + } while (++c_decode_mem+(DECODE_BUFFER_SIZE+overlap)*C); + oldBandE = lpc+C*LPC_ORDER; + oldLogE = oldBandE + 2*nbEBands; + oldLogE2 = oldLogE + 2*nbEBands; + backgroundLogE = oldLogE2 + 2*nbEBands; + + loss_count = st->loss_count; + start = st->start; + noise_based = loss_count >= 5 || start != 0 || st->skip_plc; + if (noise_based) + { + /* Noise-based PLC/CNG */ +#ifdef NORM_ALIASING_HACK + celt_norm *X; +#else + VARDECL(celt_norm, X); +#endif + opus_uint32 seed; + int end; + int effEnd; + opus_val16 decay; + end = st->end; + effEnd = IMAX(start, IMIN(end, mode->effEBands)); + +#ifdef NORM_ALIASING_HACK + /* This is an ugly hack that breaks aliasing rules and would be easily broken, + but it saves almost 4kB of stack. */ + X = (celt_norm*)(out_syn[C-1]+overlap/2); +#else + ALLOC(X, C*N, celt_norm); /**< Interleaved normalised MDCTs */ +#endif + + /* Energy decay */ + decay = loss_count==0 ? QCONST16(1.5f, DB_SHIFT) : QCONST16(.5f, DB_SHIFT); + c=0; do + { + for (i=start;irng; + for (c=0;c>20); + } + renormalise_vector(X+boffs, blen, Q15ONE, st->arch); + } + } + st->rng = seed; + + c=0; do { + OPUS_MOVE(decode_mem[c], decode_mem[c]+N, + DECODE_BUFFER_SIZE-N+(overlap>>1)); + } while (++cdownsample, 0, st->arch); + } else { + int exc_length; + /* Pitch-based PLC */ + const opus_val16 *window; + opus_val16 *exc; + opus_val16 fade = Q15ONE; + int pitch_index; + VARDECL(opus_val32, etmp); + VARDECL(opus_val16, _exc); + VARDECL(opus_val16, fir_tmp); + + if (loss_count == 0) + { + st->last_pitch_index = pitch_index = celt_plc_pitch_search(decode_mem, C, st->arch); + } else { + pitch_index = st->last_pitch_index; + fade = QCONST16(.8f,15); + } + + /* We want the excitation for 2 pitch periods in order to look for a + decaying signal, but we can't get more than MAX_PERIOD. */ + exc_length = IMIN(2*pitch_index, MAX_PERIOD); + + ALLOC(etmp, overlap, opus_val32); + ALLOC(_exc, MAX_PERIOD+LPC_ORDER, opus_val16); + ALLOC(fir_tmp, exc_length, opus_val16); + exc = _exc+LPC_ORDER; + window = mode->window; + c=0; do { + opus_val16 decay; + opus_val16 attenuation; + opus_val32 S1=0; + celt_sig *buf; + int extrapolation_offset; + int extrapolation_len; + int j; + + buf = decode_mem[c]; + for (i=0;iarch); + /* Add a noise floor of -40 dB. */ +#ifdef FIXED_POINT + ac[0] += SHR32(ac[0],13); +#else + ac[0] *= 1.0001f; +#endif + /* Use lag windowing to stabilize the Levinson-Durbin recursion. */ + for (i=1;i<=LPC_ORDER;i++) + { + /*ac[i] *= exp(-.5*(2*M_PI*.002*i)*(2*M_PI*.002*i));*/ +#ifdef FIXED_POINT + ac[i] -= MULT16_32_Q15(2*i*i, ac[i]); +#else + ac[i] -= ac[i]*(0.008f*0.008f)*i*i; +#endif + } + _celt_lpc(lpc+c*LPC_ORDER, ac, LPC_ORDER); +#ifdef FIXED_POINT + /* For fixed-point, apply bandwidth expansion until we can guarantee that + no overflow can happen in the IIR filter. This means: + 32768*sum(abs(filter)) < 2^31 */ + while (1) { + opus_val16 tmp=Q15ONE; + opus_val32 sum=QCONST16(1., SIG_SHIFT); + for (i=0;iarch); + OPUS_COPY(exc+MAX_PERIOD-exc_length, fir_tmp, exc_length); + } + + /* Check if the waveform is decaying, and if so how fast. + We do this to avoid adding energy when concealing in a segment + with decaying energy. */ + { + opus_val32 E1=1, E2=1; + int decay_length; +#ifdef FIXED_POINT + int shift = IMAX(0,2*celt_zlog2(celt_maxabs16(&exc[MAX_PERIOD-exc_length], exc_length))-20); +#endif + decay_length = exc_length>>1; + for (i=0;i= pitch_index) { + j -= pitch_index; + attenuation = MULT16_16_Q15(attenuation, decay); + } + buf[DECODE_BUFFER_SIZE-N+i] = + SHL32(EXTEND32(MULT16_16_Q15(attenuation, + exc[extrapolation_offset+j])), SIG_SHIFT); + /* Compute the energy of the previously decoded signal whose + excitation we're copying. */ + tmp = ROUND16( + buf[DECODE_BUFFER_SIZE-MAX_PERIOD-N+extrapolation_offset+j], + SIG_SHIFT); + S1 += SHR32(MULT16_16(tmp, tmp), 10); + } + { + opus_val16 lpc_mem[LPC_ORDER]; + /* Copy the last decoded samples (prior to the overlap region) to + synthesis filter memory so we can have a continuous signal. */ + for (i=0;iarch); +#ifdef FIXED_POINT + for (i=0; i < extrapolation_len; i++) + buf[DECODE_BUFFER_SIZE-N+i] = SATURATE(buf[DECODE_BUFFER_SIZE-N+i], SIG_SAT); +#endif + } + + /* Check if the synthesis energy is higher than expected, which can + happen with the signal changes during our window. If so, + attenuate. */ + { + opus_val32 S2=0; + for (i=0;i SHR32(S2,2))) +#else + /* The float test is written this way to catch NaNs in the output + of the IIR filter at the same time. */ + if (!(S1 > 0.2f*S2)) +#endif + { + for (i=0;ipostfilter_period, st->postfilter_period, overlap, + -st->postfilter_gain, -st->postfilter_gain, + st->postfilter_tapset, st->postfilter_tapset, NULL, 0, st->arch); + + /* Simulate TDAC on the concealed audio so that it blends with the + MDCT of the next frame. */ + for (i=0;iloss_count = loss_count+1; + + RESTORE_STACK; +} + +int celt_decode_with_ec(CELTDecoder * OPUS_RESTRICT st, const unsigned char *data, + int len, opus_val16 * OPUS_RESTRICT pcm, int frame_size, ec_dec *dec, int accum) +{ + int c, i, N; + int spread_decision; + opus_int32 bits; + ec_dec _dec; +#ifdef NORM_ALIASING_HACK + celt_norm *X; +#else + VARDECL(celt_norm, X); +#endif + VARDECL(int, fine_quant); + VARDECL(int, pulses); + VARDECL(int, cap); + VARDECL(int, offsets); + VARDECL(int, fine_priority); + VARDECL(int, tf_res); + VARDECL(unsigned char, collapse_masks); + celt_sig *decode_mem[2]; + celt_sig *out_syn[2]; + opus_val16 *lpc; + opus_val16 *oldBandE, *oldLogE, *oldLogE2, *backgroundLogE; + + int shortBlocks; + int isTransient; + int intra_ener; + const int CC = st->channels; + int LM, M; + int start; + int end; + int effEnd; + int codedBands; + int alloc_trim; + int postfilter_pitch; + opus_val16 postfilter_gain; + int intensity=0; + int dual_stereo=0; + opus_int32 total_bits; + opus_int32 balance; + opus_int32 tell; + int dynalloc_logp; + int postfilter_tapset; + int anti_collapse_rsv; + int anti_collapse_on=0; + int silence; + int C = st->stream_channels; + const OpusCustomMode *mode; + int nbEBands; + int overlap; + const opus_int16 *eBands; + ALLOC_STACK; + + VALIDATE_CELT_DECODER(st); + mode = st->mode; + nbEBands = mode->nbEBands; + overlap = mode->overlap; + eBands = mode->eBands; + start = st->start; + end = st->end; + frame_size *= st->downsample; + + lpc = (opus_val16*)(st->_decode_mem+(DECODE_BUFFER_SIZE+overlap)*CC); + oldBandE = lpc+CC*LPC_ORDER; + oldLogE = oldBandE + 2*nbEBands; + oldLogE2 = oldLogE + 2*nbEBands; + backgroundLogE = oldLogE2 + 2*nbEBands; + +#ifdef CUSTOM_MODES + if (st->signalling && data!=NULL) + { + int data0=data[0]; + /* Convert "standard mode" to Opus header */ + if (mode->Fs==48000 && mode->shortMdctSize==120) + { + data0 = fromOpus(data0); + if (data0<0) + return OPUS_INVALID_PACKET; + } + st->end = end = IMAX(1, mode->effEBands-2*(data0>>5)); + LM = (data0>>3)&0x3; + C = 1 + ((data0>>2)&0x1); + data++; + len--; + if (LM>mode->maxLM) + return OPUS_INVALID_PACKET; + if (frame_size < mode->shortMdctSize<shortMdctSize<maxLM;LM++) + if (mode->shortMdctSize<mode->maxLM) + return OPUS_BAD_ARG; + } + M=1<1275 || pcm==NULL) + return OPUS_BAD_ARG; + + N = M*mode->shortMdctSize; + c=0; do { + decode_mem[c] = st->_decode_mem + c*(DECODE_BUFFER_SIZE+overlap); + out_syn[c] = decode_mem[c]+DECODE_BUFFER_SIZE-N; + } while (++c mode->effEBands) + effEnd = mode->effEBands; + + if (data == NULL || len<=1) + { + celt_decode_lost(st, N, LM); + deemphasis(out_syn, pcm, N, CC, st->downsample, mode->preemph, st->preemph_memD, accum); + RESTORE_STACK; + return frame_size/st->downsample; + } + + /* Check if there are at least two packets received consecutively before + * turning on the pitch-based PLC */ + st->skip_plc = st->loss_count != 0; + + if (dec == NULL) + { + ec_dec_init(&_dec,(unsigned char*)data,len); + dec = &_dec; + } + + if (C==1) + { + for (i=0;i= total_bits) + silence = 1; + else if (tell==1) + silence = ec_dec_bit_logp(dec, 15); + else + silence = 0; + if (silence) + { + /* Pretend we've read all the remaining bits */ + tell = len*8; + dec->nbits_total+=tell-ec_tell(dec); + } + + postfilter_gain = 0; + postfilter_pitch = 0; + postfilter_tapset = 0; + if (start==0 && tell+16 <= total_bits) + { + if(ec_dec_bit_logp(dec, 1)) + { + int qg, octave; + octave = ec_dec_uint(dec, 6); + postfilter_pitch = (16< 0 && tell+3 <= total_bits) + { + isTransient = ec_dec_bit_logp(dec, 3); + tell = ec_tell(dec); + } + else + isTransient = 0; + + if (isTransient) + shortBlocks = M; + else + shortBlocks = 0; + + /* Decode the global flags (first symbols in the stream) */ + intra_ener = tell+3<=total_bits ? ec_dec_bit_logp(dec, 3) : 0; + /* Get band energies */ + unquant_coarse_energy(mode, start, end, oldBandE, + intra_ener, dec, C, LM); + + ALLOC(tf_res, nbEBands, int); + tf_decode(start, end, isTransient, tf_res, LM, dec); + + tell = ec_tell(dec); + spread_decision = SPREAD_NORMAL; + if (tell+4 <= total_bits) + spread_decision = ec_dec_icdf(dec, spread_icdf, 5); + + ALLOC(cap, nbEBands, int); + + init_caps(mode,cap,LM,C); + + ALLOC(offsets, nbEBands, int); + + dynalloc_logp = 6; + total_bits<<=BITRES; + tell = ec_tell_frac(dec); + for (i=start;i0) + dynalloc_logp = IMAX(2, dynalloc_logp-1); + } + + ALLOC(fine_quant, nbEBands, int); + alloc_trim = tell+(6<=2&&bits>=((LM+2)<rng, 0, + st->arch, st->disable_inv); + + if (anti_collapse_rsv > 0) + { + anti_collapse_on = ec_dec_bits(dec, 1); + } + + unquant_energy_finalise(mode, start, end, oldBandE, + fine_quant, fine_priority, len*8-ec_tell(dec), dec, C); + + if (anti_collapse_on) + anti_collapse(mode, X, collapse_masks, LM, C, N, + start, end, oldBandE, oldLogE, oldLogE2, pulses, st->rng, st->arch); + + if (silence) + { + for (i=0;idownsample, silence, st->arch); + + c=0; do { + st->postfilter_period=IMAX(st->postfilter_period, COMBFILTER_MINPERIOD); + st->postfilter_period_old=IMAX(st->postfilter_period_old, COMBFILTER_MINPERIOD); + comb_filter(out_syn[c], out_syn[c], st->postfilter_period_old, st->postfilter_period, mode->shortMdctSize, + st->postfilter_gain_old, st->postfilter_gain, st->postfilter_tapset_old, st->postfilter_tapset, + mode->window, overlap, st->arch); + if (LM!=0) + comb_filter(out_syn[c]+mode->shortMdctSize, out_syn[c]+mode->shortMdctSize, st->postfilter_period, postfilter_pitch, N-mode->shortMdctSize, + st->postfilter_gain, postfilter_gain, st->postfilter_tapset, postfilter_tapset, + mode->window, overlap, st->arch); + + } while (++cpostfilter_period_old = st->postfilter_period; + st->postfilter_gain_old = st->postfilter_gain; + st->postfilter_tapset_old = st->postfilter_tapset; + st->postfilter_period = postfilter_pitch; + st->postfilter_gain = postfilter_gain; + st->postfilter_tapset = postfilter_tapset; + if (LM!=0) + { + st->postfilter_period_old = st->postfilter_period; + st->postfilter_gain_old = st->postfilter_gain; + st->postfilter_tapset_old = st->postfilter_tapset; + } + + if (C==1) + OPUS_COPY(&oldBandE[nbEBands], oldBandE, nbEBands); + + /* In case start or end were to change */ + if (!isTransient) + { + opus_val16 max_background_increase; + OPUS_COPY(oldLogE2, oldLogE, 2*nbEBands); + OPUS_COPY(oldLogE, oldBandE, 2*nbEBands); + /* In normal circumstances, we only allow the noise floor to increase by + up to 2.4 dB/second, but when we're in DTX, we allow up to 6 dB + increase for each update.*/ + if (st->loss_count < 10) + max_background_increase = M*QCONST16(0.001f,DB_SHIFT); + else + max_background_increase = QCONST16(1.f,DB_SHIFT); + for (i=0;i<2*nbEBands;i++) + backgroundLogE[i] = MIN16(backgroundLogE[i] + max_background_increase, oldBandE[i]); + } else { + for (i=0;i<2*nbEBands;i++) + oldLogE[i] = MIN16(oldLogE[i], oldBandE[i]); + } + c=0; do + { + for (i=0;irng = dec->rng; + + deemphasis(out_syn, pcm, N, CC, st->downsample, mode->preemph, st->preemph_memD, accum); + st->loss_count = 0; + RESTORE_STACK; + if (ec_tell(dec) > 8*len) + return OPUS_INTERNAL_ERROR; + if(ec_get_error(dec)) + st->error = 1; + return frame_size/st->downsample; +} + + +#ifdef CUSTOM_MODES + +#ifdef FIXED_POINT +int opus_custom_decode(CELTDecoder * OPUS_RESTRICT st, const unsigned char *data, int len, opus_int16 * OPUS_RESTRICT pcm, int frame_size) +{ + return celt_decode_with_ec(st, data, len, pcm, frame_size, NULL, 0); +} + +#ifndef DISABLE_FLOAT_API +int opus_custom_decode_float(CELTDecoder * OPUS_RESTRICT st, const unsigned char *data, int len, float * OPUS_RESTRICT pcm, int frame_size) +{ + int j, ret, C, N; + VARDECL(opus_int16, out); + ALLOC_STACK; + + if (pcm==NULL) + return OPUS_BAD_ARG; + + C = st->channels; + N = frame_size; + + ALLOC(out, C*N, opus_int16); + ret=celt_decode_with_ec(st, data, len, out, frame_size, NULL, 0); + if (ret>0) + for (j=0;jchannels; + N = frame_size; + ALLOC(out, C*N, celt_sig); + + ret=celt_decode_with_ec(st, data, len, out, frame_size, NULL, 0); + + if (ret>0) + for (j=0;j=st->mode->nbEBands) + goto bad_arg; + st->start = value; + } + break; + case CELT_SET_END_BAND_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if (value<1 || value>st->mode->nbEBands) + goto bad_arg; + st->end = value; + } + break; + case CELT_SET_CHANNELS_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if (value<1 || value>2) + goto bad_arg; + st->stream_channels = value; + } + break; + case CELT_GET_AND_CLEAR_ERROR_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (value==NULL) + goto bad_arg; + *value=st->error; + st->error = 0; + } + break; + case OPUS_GET_LOOKAHEAD_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (value==NULL) + goto bad_arg; + *value = st->overlap/st->downsample; + } + break; + case OPUS_RESET_STATE: + { + int i; + opus_val16 *lpc, *oldBandE, *oldLogE, *oldLogE2; + lpc = (opus_val16*)(st->_decode_mem+(DECODE_BUFFER_SIZE+st->overlap)*st->channels); + oldBandE = lpc+st->channels*LPC_ORDER; + oldLogE = oldBandE + 2*st->mode->nbEBands; + oldLogE2 = oldLogE + 2*st->mode->nbEBands; + OPUS_CLEAR((char*)&st->DECODER_RESET_START, + opus_custom_decoder_get_size(st->mode, st->channels)- + ((char*)&st->DECODER_RESET_START - (char*)st)); + for (i=0;i<2*st->mode->nbEBands;i++) + oldLogE[i]=oldLogE2[i]=-QCONST16(28.f,DB_SHIFT); + st->skip_plc = 1; + } + break; + case OPUS_GET_PITCH_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (value==NULL) + goto bad_arg; + *value = st->postfilter_period; + } + break; + case CELT_GET_MODE_REQUEST: + { + const CELTMode ** value = va_arg(ap, const CELTMode**); + if (value==0) + goto bad_arg; + *value=st->mode; + } + break; + case CELT_SET_SIGNALLING_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + st->signalling = value; + } + break; + case OPUS_GET_FINAL_RANGE_REQUEST: + { + opus_uint32 * value = va_arg(ap, opus_uint32 *); + if (value==0) + goto bad_arg; + *value=st->rng; + } + break; + case OPUS_SET_PHASE_INVERSION_DISABLED_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if(value<0 || value>1) + { + goto bad_arg; + } + st->disable_inv = value; + } + break; + case OPUS_GET_PHASE_INVERSION_DISABLED_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = st->disable_inv; + } + break; + default: + goto bad_request; + } + va_end(ap); + return OPUS_OK; +bad_arg: + va_end(ap); + return OPUS_BAD_ARG; +bad_request: + va_end(ap); + return OPUS_UNIMPLEMENTED; +} diff --git a/extern/opus/celt/celt_encoder.c b/extern/opus/celt/celt_encoder.c new file mode 100644 index 0000000..44cb085 --- /dev/null +++ b/extern/opus/celt/celt_encoder.c @@ -0,0 +1,2607 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2010 Xiph.Org Foundation + Copyright (c) 2008 Gregory Maxwell + Written by Jean-Marc Valin and Gregory Maxwell */ +/* + 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. + + 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 OWNER + 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. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#define CELT_ENCODER_C + +#include "cpu_support.h" +#include "os_support.h" +#include "mdct.h" +#include +#include "celt.h" +#include "pitch.h" +#include "bands.h" +#include "modes.h" +#include "entcode.h" +#include "quant_bands.h" +#include "rate.h" +#include "stack_alloc.h" +#include "mathops.h" +#include "float_cast.h" +#include +#include "celt_lpc.h" +#include "vq.h" + + +/** Encoder state + @brief Encoder state + */ +struct OpusCustomEncoder { + const OpusCustomMode *mode; /**< Mode used by the encoder */ + int channels; + int stream_channels; + + int force_intra; + int clip; + int disable_pf; + int complexity; + int upsample; + int start, end; + + opus_int32 bitrate; + int vbr; + int signalling; + int constrained_vbr; /* If zero, VBR can do whatever it likes with the rate */ + int loss_rate; + int lsb_depth; + int lfe; + int disable_inv; + int arch; + + /* Everything beyond this point gets cleared on a reset */ +#define ENCODER_RESET_START rng + + opus_uint32 rng; + int spread_decision; + opus_val32 delayedIntra; + int tonal_average; + int lastCodedBands; + int hf_average; + int tapset_decision; + + int prefilter_period; + opus_val16 prefilter_gain; + int prefilter_tapset; +#ifdef RESYNTH + int prefilter_period_old; + opus_val16 prefilter_gain_old; + int prefilter_tapset_old; +#endif + int consec_transient; + AnalysisInfo analysis; + SILKInfo silk_info; + + opus_val32 preemph_memE[2]; + opus_val32 preemph_memD[2]; + + /* VBR-related parameters */ + opus_int32 vbr_reservoir; + opus_int32 vbr_drift; + opus_int32 vbr_offset; + opus_int32 vbr_count; + opus_val32 overlap_max; + opus_val16 stereo_saving; + int intensity; + opus_val16 *energy_mask; + opus_val16 spec_avg; + +#ifdef RESYNTH + /* +MAX_PERIOD/2 to make space for overlap */ + celt_sig syn_mem[2][2*MAX_PERIOD+MAX_PERIOD/2]; +#endif + + celt_sig in_mem[1]; /* Size = channels*mode->overlap */ + /* celt_sig prefilter_mem[], Size = channels*COMBFILTER_MAXPERIOD */ + /* opus_val16 oldBandE[], Size = channels*mode->nbEBands */ + /* opus_val16 oldLogE[], Size = channels*mode->nbEBands */ + /* opus_val16 oldLogE2[], Size = channels*mode->nbEBands */ + /* opus_val16 energyError[], Size = channels*mode->nbEBands */ +}; + +int celt_encoder_get_size(int channels) +{ + CELTMode *mode = opus_custom_mode_create(48000, 960, NULL); + return opus_custom_encoder_get_size(mode, channels); +} + +OPUS_CUSTOM_NOSTATIC int opus_custom_encoder_get_size(const CELTMode *mode, int channels) +{ + int size = sizeof(struct CELTEncoder) + + (channels*mode->overlap-1)*sizeof(celt_sig) /* celt_sig in_mem[channels*mode->overlap]; */ + + channels*COMBFILTER_MAXPERIOD*sizeof(celt_sig) /* celt_sig prefilter_mem[channels*COMBFILTER_MAXPERIOD]; */ + + 4*channels*mode->nbEBands*sizeof(opus_val16); /* opus_val16 oldBandE[channels*mode->nbEBands]; */ + /* opus_val16 oldLogE[channels*mode->nbEBands]; */ + /* opus_val16 oldLogE2[channels*mode->nbEBands]; */ + /* opus_val16 energyError[channels*mode->nbEBands]; */ + return size; +} + +#ifdef CUSTOM_MODES +CELTEncoder *opus_custom_encoder_create(const CELTMode *mode, int channels, int *error) +{ + int ret; + CELTEncoder *st = (CELTEncoder *)opus_alloc(opus_custom_encoder_get_size(mode, channels)); + /* init will handle the NULL case */ + ret = opus_custom_encoder_init(st, mode, channels); + if (ret != OPUS_OK) + { + opus_custom_encoder_destroy(st); + st = NULL; + } + if (error) + *error = ret; + return st; +} +#endif /* CUSTOM_MODES */ + +static int opus_custom_encoder_init_arch(CELTEncoder *st, const CELTMode *mode, + int channels, int arch) +{ + if (channels < 0 || channels > 2) + return OPUS_BAD_ARG; + + if (st==NULL || mode==NULL) + return OPUS_ALLOC_FAIL; + + OPUS_CLEAR((char*)st, opus_custom_encoder_get_size(mode, channels)); + + st->mode = mode; + st->stream_channels = st->channels = channels; + + st->upsample = 1; + st->start = 0; + st->end = st->mode->effEBands; + st->signalling = 1; + st->arch = arch; + + st->constrained_vbr = 1; + st->clip = 1; + + st->bitrate = OPUS_BITRATE_MAX; + st->vbr = 0; + st->force_intra = 0; + st->complexity = 5; + st->lsb_depth=24; + + opus_custom_encoder_ctl(st, OPUS_RESET_STATE); + + return OPUS_OK; +} + +#ifdef CUSTOM_MODES +int opus_custom_encoder_init(CELTEncoder *st, const CELTMode *mode, int channels) +{ + return opus_custom_encoder_init_arch(st, mode, channels, opus_select_arch()); +} +#endif + +int celt_encoder_init(CELTEncoder *st, opus_int32 sampling_rate, int channels, + int arch) +{ + int ret; + ret = opus_custom_encoder_init_arch(st, + opus_custom_mode_create(48000, 960, NULL), channels, arch); + if (ret != OPUS_OK) + return ret; + st->upsample = resampling_factor(sampling_rate); + return OPUS_OK; +} + +#ifdef CUSTOM_MODES +void opus_custom_encoder_destroy(CELTEncoder *st) +{ + opus_free(st); +} +#endif /* CUSTOM_MODES */ + + +static int transient_analysis(const opus_val32 * OPUS_RESTRICT in, int len, int C, + opus_val16 *tf_estimate, int *tf_chan, int allow_weak_transients, + int *weak_transient) +{ + int i; + VARDECL(opus_val16, tmp); + opus_val32 mem0,mem1; + int is_transient = 0; + opus_int32 mask_metric = 0; + int c; + opus_val16 tf_max; + int len2; + /* Forward masking: 6.7 dB/ms. */ +#ifdef FIXED_POINT + int forward_shift = 4; +#else + opus_val16 forward_decay = QCONST16(.0625f,15); +#endif + /* Table of 6*64/x, trained on real data to minimize the average error */ + static const unsigned char inv_table[128] = { + 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, + }; + SAVE_STACK; + ALLOC(tmp, len, opus_val16); + + *weak_transient = 0; + /* For lower bitrates, let's be more conservative and have a forward masking + decay of 3.3 dB/ms. This avoids having to code transients at very low + bitrate (mostly for hybrid), which can result in unstable energy and/or + partial collapse. */ + if (allow_weak_transients) + { +#ifdef FIXED_POINT + forward_shift = 5; +#else + forward_decay = QCONST16(.03125f,15); +#endif + } + len2=len/2; + for (c=0;c=0;i--) + { + /* Backward masking: 13.9 dB/ms. */ +#ifdef FIXED_POINT + /* FIXME: Use PSHR16() instead */ + tmp[i] = mem0 + PSHR32(tmp[i]-mem0,3); +#else + tmp[i] = mem0 + MULT16_16_P15(QCONST16(0.125f,15),tmp[i]-mem0); +#endif + mem0 = tmp[i]; + maxE = MAX16(maxE, mem0); + } + /*for (i=0;i>1))); +#else + mean = celt_sqrt(mean * maxE*.5*len2); +#endif + /* Inverse of the mean energy in Q15+6 */ + norm = SHL32(EXTEND32(len2),6+14)/ADD32(EPSILON,SHR32(mean,1)); + /* Compute harmonic mean discarding the unreliable boundaries + The data is smooth, so we only take 1/4th of the samples */ + unmask=0; + /* We should never see NaNs here. If we find any, then something really bad happened and we better abort + before it does any damage later on. If these asserts are disabled (no hardening), then the table + lookup a few lines below (id = ...) is likely to crash dur to an out-of-bounds read. DO NOT FIX + that crash on NaN since it could result in a worse issue later on. */ + celt_assert(!celt_isnan(tmp[0])); + celt_assert(!celt_isnan(norm)); + for (i=12;imask_metric) + { + *tf_chan = c; + mask_metric = unmask; + } + } + is_transient = mask_metric>200; + /* For low bitrates, define "weak transients" that need to be + handled differently to avoid partial collapse. */ + if (allow_weak_transients && is_transient && mask_metric<600) { + is_transient = 0; + *weak_transient = 1; + } + /* Arbitrary metric for VBR boost */ + tf_max = MAX16(0,celt_sqrt(27*mask_metric)-42); + /* *tf_estimate = 1 + MIN16(1, sqrt(MAX16(0, tf_max-30))/20); */ + *tf_estimate = celt_sqrt(MAX32(0, SHL32(MULT16_16(QCONST16(0.0069,14),MIN16(163,tf_max)),14)-QCONST32(0.139,28))); + /*printf("%d %f\n", tf_max, mask_metric);*/ + RESTORE_STACK; +#ifdef FUZZING + is_transient = rand()&0x1; +#endif + /*printf("%d %f %d\n", is_transient, (float)*tf_estimate, tf_max);*/ + return is_transient; +} + +/* Looks for sudden increases of energy to decide whether we need to patch + the transient decision */ +static int patch_transient_decision(opus_val16 *newE, opus_val16 *oldE, int nbEBands, + int start, int end, int C) +{ + int i, c; + opus_val32 mean_diff=0; + opus_val16 spread_old[26]; + /* Apply an aggressive (-6 dB/Bark) spreading function to the old frame to + avoid false detection caused by irrelevant bands */ + if (C==1) + { + spread_old[start] = oldE[start]; + for (i=start+1;i=start;i--) + spread_old[i] = MAX16(spread_old[i], spread_old[i+1]-QCONST16(1.0f, DB_SHIFT)); + /* Compute mean increase */ + c=0; do { + for (i=IMAX(2,start);i QCONST16(1.f, DB_SHIFT); +} + +/** Apply window and compute the MDCT for all sub-frames and + all channels in a frame */ +static void compute_mdcts(const CELTMode *mode, int shortBlocks, celt_sig * OPUS_RESTRICT in, + celt_sig * OPUS_RESTRICT out, int C, int CC, int LM, int upsample, + int arch) +{ + const int overlap = mode->overlap; + int N; + int B; + int shift; + int i, b, c; + if (shortBlocks) + { + B = shortBlocks; + N = mode->shortMdctSize; + shift = mode->maxLM; + } else { + B = 1; + N = mode->shortMdctSize<maxLM-LM; + } + c=0; do { + for (b=0;bmdct, in+c*(B*N+overlap)+b*N, + &out[b+c*N*B], mode->window, overlap, shift, B, + arch); + } + } while (++ceBands[len]-m->eBands[len-1])<eBands[len]-m->eBands[len-1])<eBands[i+1]-m->eBands[i])<eBands[i+1]-m->eBands[i])==1; + OPUS_COPY(tmp, &X[tf_chan*N0 + (m->eBands[i]<eBands[i]<>LM, 1<>k, 1<=0;i--) + { + if (tf_res[i+1] == 1) + tf_res[i] = path1[i+1]; + else + tf_res[i] = path0[i+1]; + } + /*printf("%d %f\n", *tf_sum, tf_estimate);*/ + RESTORE_STACK; +#ifdef FUZZING + tf_select = rand()&0x1; + tf_res[0] = rand()&0x1; + for (i=1;istorage*8; + tell = ec_tell(enc); + logp = isTransient ? 2 : 4; + /* Reserve space to code the tf_select decision. */ + tf_select_rsv = LM>0 && tell+logp+1 <= budget; + budget -= tf_select_rsv; + curr = tf_changed = 0; + for (i=start;i> 10; + trim = QCONST16(4.f, 8) + QCONST16(1.f/16.f, 8)*frac; + } + if (C==2) + { + opus_val16 sum = 0; /* Q10 */ + opus_val16 minXC; /* Q10 */ + /* Compute inter-channel correlation for low frequencies */ + for (i=0;i<8;i++) + { + opus_val32 partial; + partial = celt_inner_prod(&X[m->eBands[i]<eBands[i]<eBands[i+1]-m->eBands[i])<eBands[i]<eBands[i]<eBands[i+1]-m->eBands[i])<nbEBands]*(opus_int32)(2+2*i-end); + } + } while (++cvalid) + { + trim -= MAX16(-QCONST16(2.f, 8), MIN16(QCONST16(2.f, 8), + (opus_val16)(QCONST16(2.f, 8)*(analysis->tonality_slope+.05f)))); + } +#else + (void)analysis; +#endif + +#ifdef FIXED_POINT + trim_index = PSHR32(trim, 8); +#else + trim_index = (int)floor(.5f+trim); +#endif + trim_index = IMAX(0, IMIN(10, trim_index)); + /*printf("%d\n", trim_index);*/ +#ifdef FUZZING + trim_index = rand()%11; +#endif + return trim_index; +} + +static int stereo_analysis(const CELTMode *m, const celt_norm *X, + int LM, int N0) +{ + int i; + int thetas; + opus_val32 sumLR = EPSILON, sumMS = EPSILON; + + /* Use the L1 norm to model the entropy of the L/R signal vs the M/S signal */ + for (i=0;i<13;i++) + { + int j; + for (j=m->eBands[i]<eBands[i+1]<eBands[13]<<(LM+1))+thetas, sumMS) + > MULT16_32_Q15(m->eBands[13]<<(LM+1), sumLR); +} + +#define MSWAP(a,b) do {opus_val16 tmp = a;a=b;b=tmp;} while(0) +static opus_val16 median_of_5(const opus_val16 *x) +{ + opus_val16 t0, t1, t2, t3, t4; + t2 = x[2]; + if (x[0] > x[1]) + { + t0 = x[1]; + t1 = x[0]; + } else { + t0 = x[0]; + t1 = x[1]; + } + if (x[3] > x[4]) + { + t3 = x[4]; + t4 = x[3]; + } else { + t3 = x[3]; + t4 = x[4]; + } + if (t0 > t3) + { + MSWAP(t0, t3); + MSWAP(t1, t4); + } + if (t2 > t1) + { + if (t1 < t3) + return MIN16(t2, t3); + else + return MIN16(t4, t1); + } else { + if (t2 < t3) + return MIN16(t1, t3); + else + return MIN16(t2, t4); + } +} + +static opus_val16 median_of_3(const opus_val16 *x) +{ + opus_val16 t0, t1, t2; + if (x[0] > x[1]) + { + t0 = x[1]; + t1 = x[0]; + } else { + t0 = x[0]; + t1 = x[1]; + } + t2 = x[2]; + if (t1 < t2) + return t1; + else if (t0 < t2) + return t2; + else + return t0; +} + +static opus_val16 dynalloc_analysis(const opus_val16 *bandLogE, const opus_val16 *bandLogE2, + int nbEBands, int start, int end, int C, int *offsets, int lsb_depth, const opus_int16 *logN, + int isTransient, int vbr, int constrained_vbr, const opus_int16 *eBands, int LM, + int effectiveBytes, opus_int32 *tot_boost_, int lfe, opus_val16 *surround_dynalloc, + AnalysisInfo *analysis, int *importance, int *spread_weight) +{ + int i, c; + opus_int32 tot_boost=0; + opus_val16 maxDepth; + VARDECL(opus_val16, follower); + VARDECL(opus_val16, noise_floor); + SAVE_STACK; + ALLOC(follower, C*nbEBands, opus_val16); + ALLOC(noise_floor, C*nbEBands, opus_val16); + OPUS_CLEAR(offsets, nbEBands); + /* Dynamic allocation code */ + maxDepth=-QCONST16(31.9f, DB_SHIFT); + for (i=0;i=0;i--) + mask[i] = MAX16(mask[i], mask[i+1] - QCONST16(3.f, DB_SHIFT)); + for (i=0;i> shift; + } + /*for (i=0;i 50 && LM>=1 && !lfe) + { + int last=0; + c=0;do + { + opus_val16 offset; + opus_val16 tmp; + opus_val16 *f; + f = &follower[c*nbEBands]; + f[0] = bandLogE2[c*nbEBands]; + for (i=1;i bandLogE2[c*nbEBands+i-1]+QCONST16(.5f,DB_SHIFT)) + last=i; + f[i] = MIN16(f[i-1]+QCONST16(1.5f,DB_SHIFT), bandLogE2[c*nbEBands+i]); + } + for (i=last-1;i>=0;i--) + f[i] = MIN16(f[i], MIN16(f[i+1]+QCONST16(2.f,DB_SHIFT), bandLogE2[c*nbEBands+i])); + + /* Combine with a median filter to avoid dynalloc triggering unnecessarily. + The "offset" value controls how conservative we are -- a higher offset + reduces the impact of the median filter and makes dynalloc use more bits. */ + offset = QCONST16(1.f, DB_SHIFT); + for (i=2;i=12) + follower[i] = HALF16(follower[i]); + } +#ifdef DISABLE_FLOAT_API + (void)analysis; +#else + if (analysis->valid) + { + for (i=start;ileak_boost[i]; + } +#endif + for (i=start;i 48) { + boost = (int)SHR32(EXTEND32(follower[i])*8,DB_SHIFT); + boost_bits = (boost*width<>BITRES>>3 > 2*effectiveBytes/3) + { + opus_int32 cap = ((2*effectiveBytes/3)<mode; + overlap = mode->overlap; + ALLOC(_pre, CC*(N+COMBFILTER_MAXPERIOD), celt_sig); + + pre[0] = _pre; + pre[1] = _pre + (N+COMBFILTER_MAXPERIOD); + + + c=0; do { + OPUS_COPY(pre[c], prefilter_mem+c*COMBFILTER_MAXPERIOD, COMBFILTER_MAXPERIOD); + OPUS_COPY(pre[c]+COMBFILTER_MAXPERIOD, in+c*(N+overlap)+overlap, N); + } while (++c>1, opus_val16); + + pitch_downsample(pre, pitch_buf, COMBFILTER_MAXPERIOD+N, CC, st->arch); + /* Don't search for the fir last 1.5 octave of the range because + there's too many false-positives due to short-term correlation */ + pitch_search(pitch_buf+(COMBFILTER_MAXPERIOD>>1), pitch_buf, N, + COMBFILTER_MAXPERIOD-3*COMBFILTER_MINPERIOD, &pitch_index, + st->arch); + pitch_index = COMBFILTER_MAXPERIOD-pitch_index; + + gain1 = remove_doubling(pitch_buf, COMBFILTER_MAXPERIOD, COMBFILTER_MINPERIOD, + N, &pitch_index, st->prefilter_period, st->prefilter_gain, st->arch); + if (pitch_index > COMBFILTER_MAXPERIOD-2) + pitch_index = COMBFILTER_MAXPERIOD-2; + gain1 = MULT16_16_Q15(QCONST16(.7f,15),gain1); + /*printf("%d %d %f %f\n", pitch_change, pitch_index, gain1, st->analysis.tonality);*/ + if (st->loss_rate>2) + gain1 = HALF32(gain1); + if (st->loss_rate>4) + gain1 = HALF32(gain1); + if (st->loss_rate>8) + gain1 = 0; + } else { + gain1 = 0; + pitch_index = COMBFILTER_MINPERIOD; + } +#ifndef DISABLE_FLOAT_API + if (analysis->valid) + gain1 = (opus_val16)(gain1 * analysis->max_pitch_ratio); +#else + (void)analysis; +#endif + /* Gain threshold for enabling the prefilter/postfilter */ + pf_threshold = QCONST16(.2f,15); + + /* Adjusting the threshold based on rate and continuity */ + if (abs(pitch_index-st->prefilter_period)*10>pitch_index) + pf_threshold += QCONST16(.2f,15); + if (nbAvailableBytes<25) + pf_threshold += QCONST16(.1f,15); + if (nbAvailableBytes<35) + pf_threshold += QCONST16(.1f,15); + if (st->prefilter_gain > QCONST16(.4f,15)) + pf_threshold -= QCONST16(.1f,15); + if (st->prefilter_gain > QCONST16(.55f,15)) + pf_threshold -= QCONST16(.1f,15); + + /* Hard threshold at 0.2 */ + pf_threshold = MAX16(pf_threshold, QCONST16(.2f,15)); + if (gain1prefilter_gain)prefilter_gain; + +#ifdef FIXED_POINT + qg = ((gain1+1536)>>10)/3-1; +#else + qg = (int)floor(.5f+gain1*32/3)-1; +#endif + qg = IMAX(0, IMIN(7, qg)); + gain1 = QCONST16(0.09375f,15)*(qg+1); + pf_on = 1; + } + /*printf("%d %f\n", pitch_index, gain1);*/ + + c=0; do { + int offset = mode->shortMdctSize-overlap; + st->prefilter_period=IMAX(st->prefilter_period, COMBFILTER_MINPERIOD); + OPUS_COPY(in+c*(N+overlap), st->in_mem+c*(overlap), overlap); + if (offset) + comb_filter(in+c*(N+overlap)+overlap, pre[c]+COMBFILTER_MAXPERIOD, + st->prefilter_period, st->prefilter_period, offset, -st->prefilter_gain, -st->prefilter_gain, + st->prefilter_tapset, st->prefilter_tapset, NULL, 0, st->arch); + + comb_filter(in+c*(N+overlap)+overlap+offset, pre[c]+COMBFILTER_MAXPERIOD+offset, + st->prefilter_period, pitch_index, N-offset, -st->prefilter_gain, -gain1, + st->prefilter_tapset, prefilter_tapset, mode->window, overlap, st->arch); + OPUS_COPY(st->in_mem+c*(overlap), in+c*(N+overlap)+N, overlap); + + if (N>COMBFILTER_MAXPERIOD) + { + OPUS_COPY(prefilter_mem+c*COMBFILTER_MAXPERIOD, pre[c]+N, COMBFILTER_MAXPERIOD); + } else { + OPUS_MOVE(prefilter_mem+c*COMBFILTER_MAXPERIOD, prefilter_mem+c*COMBFILTER_MAXPERIOD+N, COMBFILTER_MAXPERIOD-N); + OPUS_COPY(prefilter_mem+c*COMBFILTER_MAXPERIOD+COMBFILTER_MAXPERIOD-N, pre[c]+COMBFILTER_MAXPERIOD, N); + } + } while (++cnbEBands; + eBands = mode->eBands; + + coded_bands = lastCodedBands ? lastCodedBands : nbEBands; + coded_bins = eBands[coded_bands]<analysis.activity, st->analysis.tonality, tf_estimate, st->stereo_saving, tot_boost, coded_bands);*/ +#ifndef DISABLE_FLOAT_API + if (analysis->valid && analysis->activity<.4) + target -= (opus_int32)((coded_bins<activity)); +#endif + /* Stereo savings */ + if (C==2) + { + int coded_stereo_bands; + int coded_stereo_dof; + opus_val16 max_frac; + coded_stereo_bands = IMIN(intensity, coded_bands); + coded_stereo_dof = (eBands[coded_stereo_bands]<valid && !lfe) + { + opus_int32 tonal_target; + float tonal; + + /* Tonality boost (compensating for the average). */ + tonal = MAX16(0.f,analysis->tonality-.15f)-0.12f; + tonal_target = target + (opus_int32)((coded_bins<tonality, tonal);*/ + target = tonal_target; + } +#else + (void)analysis; + (void)pitch_change; +#endif + + if (has_surround_mask&&!lfe) + { + opus_int32 surround_target = target + (opus_int32)SHR32(MULT16_16(surround_masking,coded_bins<end, st->intensity, surround_target, target, st->bitrate);*/ + target = IMAX(target/4, surround_target); + } + + { + opus_int32 floor_depth; + int bins; + bins = eBands[nbEBands-2]<>2); + target = IMIN(target, floor_depth); + /*printf("%f %d\n", maxDepth, floor_depth);*/ + } + + /* Make VBR less aggressive for constrained VBR because we can't keep a higher bitrate + for long. Needs tuning. */ + if ((!has_surround_mask||lfe) && constrained_vbr) + { + target = base_target + (opus_int32)MULT16_32_Q15(QCONST16(0.67f, 15), target-base_target); + } + + if (!has_surround_mask && tf_estimate < QCONST16(.2f, 14)) + { + opus_val16 amount; + opus_val16 tvbr_factor; + amount = MULT16_16_Q15(QCONST16(.0000031f, 30), IMAX(0, IMIN(32000, 96000-bitrate))); + tvbr_factor = SHR32(MULT16_16(temporal_vbr, amount), DB_SHIFT); + target += (opus_int32)MULT16_32_Q15(tvbr_factor, target); + } + + /* Don't allow more than doubling the rate */ + target = IMIN(2*base_target, target); + + return target; +} + +int celt_encode_with_ec(CELTEncoder * OPUS_RESTRICT st, const opus_val16 * pcm, int frame_size, unsigned char *compressed, int nbCompressedBytes, ec_enc *enc) +{ + int i, c, N; + opus_int32 bits; + ec_enc _enc; + VARDECL(celt_sig, in); + VARDECL(celt_sig, freq); + VARDECL(celt_norm, X); + VARDECL(celt_ener, bandE); + VARDECL(opus_val16, bandLogE); + VARDECL(opus_val16, bandLogE2); + VARDECL(int, fine_quant); + VARDECL(opus_val16, error); + VARDECL(int, pulses); + VARDECL(int, cap); + VARDECL(int, offsets); + VARDECL(int, importance); + VARDECL(int, spread_weight); + VARDECL(int, fine_priority); + VARDECL(int, tf_res); + VARDECL(unsigned char, collapse_masks); + celt_sig *prefilter_mem; + opus_val16 *oldBandE, *oldLogE, *oldLogE2, *energyError; + int shortBlocks=0; + int isTransient=0; + const int CC = st->channels; + const int C = st->stream_channels; + int LM, M; + int tf_select; + int nbFilledBytes, nbAvailableBytes; + int start; + int end; + int effEnd; + int codedBands; + int alloc_trim; + int pitch_index=COMBFILTER_MINPERIOD; + opus_val16 gain1 = 0; + int dual_stereo=0; + int effectiveBytes; + int dynalloc_logp; + opus_int32 vbr_rate; + opus_int32 total_bits; + opus_int32 total_boost; + opus_int32 balance; + opus_int32 tell; + opus_int32 tell0_frac; + int prefilter_tapset=0; + int pf_on; + int anti_collapse_rsv; + int anti_collapse_on=0; + int silence=0; + int tf_chan = 0; + opus_val16 tf_estimate; + int pitch_change=0; + opus_int32 tot_boost; + opus_val32 sample_max; + opus_val16 maxDepth; + const OpusCustomMode *mode; + int nbEBands; + int overlap; + const opus_int16 *eBands; + int secondMdct; + int signalBandwidth; + int transient_got_disabled=0; + opus_val16 surround_masking=0; + opus_val16 temporal_vbr=0; + opus_val16 surround_trim = 0; + opus_int32 equiv_rate; + int hybrid; + int weak_transient = 0; + int enable_tf_analysis; + VARDECL(opus_val16, surround_dynalloc); + ALLOC_STACK; + + mode = st->mode; + nbEBands = mode->nbEBands; + overlap = mode->overlap; + eBands = mode->eBands; + start = st->start; + end = st->end; + hybrid = start != 0; + tf_estimate = 0; + if (nbCompressedBytes<2 || pcm==NULL) + { + RESTORE_STACK; + return OPUS_BAD_ARG; + } + + frame_size *= st->upsample; + for (LM=0;LM<=mode->maxLM;LM++) + if (mode->shortMdctSize<mode->maxLM) + { + RESTORE_STACK; + return OPUS_BAD_ARG; + } + M=1<shortMdctSize; + + prefilter_mem = st->in_mem+CC*(overlap); + oldBandE = (opus_val16*)(st->in_mem+CC*(overlap+COMBFILTER_MAXPERIOD)); + oldLogE = oldBandE + CC*nbEBands; + oldLogE2 = oldLogE + CC*nbEBands; + energyError = oldLogE2 + CC*nbEBands; + + if (enc==NULL) + { + tell0_frac=tell=1; + nbFilledBytes=0; + } else { + tell0_frac=ec_tell_frac(enc); + tell=ec_tell(enc); + nbFilledBytes=(tell+4)>>3; + } + +#ifdef CUSTOM_MODES + if (st->signalling && enc==NULL) + { + int tmp = (mode->effEBands-end)>>1; + end = st->end = IMAX(1, mode->effEBands-tmp); + compressed[0] = tmp<<5; + compressed[0] |= LM<<3; + compressed[0] |= (C==2)<<2; + /* Convert "standard mode" to Opus header */ + if (mode->Fs==48000 && mode->shortMdctSize==120) + { + int c0 = toOpus(compressed[0]); + if (c0<0) + { + RESTORE_STACK; + return OPUS_BAD_ARG; + } + compressed[0] = c0; + } + compressed++; + nbCompressedBytes--; + } +#else + celt_assert(st->signalling==0); +#endif + + /* Can't produce more than 1275 output bytes */ + nbCompressedBytes = IMIN(nbCompressedBytes,1275); + nbAvailableBytes = nbCompressedBytes - nbFilledBytes; + + if (st->vbr && st->bitrate!=OPUS_BITRATE_MAX) + { + opus_int32 den=mode->Fs>>BITRES; + vbr_rate=(st->bitrate*frame_size+(den>>1))/den; +#ifdef CUSTOM_MODES + if (st->signalling) + vbr_rate -= 8<>(3+BITRES); + } else { + opus_int32 tmp; + vbr_rate = 0; + tmp = st->bitrate*frame_size; + if (tell>1) + tmp += tell; + if (st->bitrate!=OPUS_BITRATE_MAX) + nbCompressedBytes = IMAX(2, IMIN(nbCompressedBytes, + (tmp+4*mode->Fs)/(8*mode->Fs)-!!st->signalling)); + effectiveBytes = nbCompressedBytes - nbFilledBytes; + } + equiv_rate = ((opus_int32)nbCompressedBytes*8*50 >> (3-LM)) - (40*C+20)*((400>>LM) - 50); + if (st->bitrate != OPUS_BITRATE_MAX) + equiv_rate = IMIN(equiv_rate, st->bitrate - (40*C+20)*((400>>LM) - 50)); + + if (enc==NULL) + { + ec_enc_init(&_enc, compressed, nbCompressedBytes); + enc = &_enc; + } + + if (vbr_rate>0) + { + /* Computes the max bit-rate allowed in VBR mode to avoid violating the + target rate and buffering. + We must do this up front so that bust-prevention logic triggers + correctly if we don't have enough bits. */ + if (st->constrained_vbr) + { + opus_int32 vbr_bound; + opus_int32 max_allowed; + /* We could use any multiple of vbr_rate as bound (depending on the + delay). + This is clamped to ensure we use at least two bytes if the encoder + was entirely empty, but to allow 0 in hybrid mode. */ + vbr_bound = vbr_rate; + max_allowed = IMIN(IMAX(tell==1?2:0, + (vbr_rate+vbr_bound-st->vbr_reservoir)>>(BITRES+3)), + nbAvailableBytes); + if(max_allowed < nbAvailableBytes) + { + nbCompressedBytes = nbFilledBytes+max_allowed; + nbAvailableBytes = max_allowed; + ec_enc_shrink(enc, nbCompressedBytes); + } + } + } + total_bits = nbCompressedBytes*8; + + effEnd = end; + if (effEnd > mode->effEBands) + effEnd = mode->effEBands; + + ALLOC(in, CC*(N+overlap), celt_sig); + + sample_max=MAX32(st->overlap_max, celt_maxabs16(pcm, C*(N-overlap)/st->upsample)); + st->overlap_max=celt_maxabs16(pcm+C*(N-overlap)/st->upsample, C*overlap/st->upsample); + sample_max=MAX32(sample_max, st->overlap_max); +#ifdef FIXED_POINT + silence = (sample_max==0); +#else + silence = (sample_max <= (opus_val16)1/(1<lsb_depth)); +#endif +#ifdef FUZZING + if ((rand()&0x3F)==0) + silence = 1; +#endif + if (tell==1) + ec_enc_bit_logp(enc, silence, 15); + else + silence=0; + if (silence) + { + /*In VBR mode there is no need to send more than the minimum. */ + if (vbr_rate>0) + { + effectiveBytes=nbCompressedBytes=IMIN(nbCompressedBytes, nbFilledBytes+2); + total_bits=nbCompressedBytes*8; + nbAvailableBytes=2; + ec_enc_shrink(enc, nbCompressedBytes); + } + /* Pretend we've filled all the remaining bits with zeros + (that's what the initialiser did anyway) */ + tell = nbCompressedBytes*8; + enc->nbits_total+=tell-ec_tell(enc); + } + c=0; do { + int need_clip=0; +#ifndef FIXED_POINT + need_clip = st->clip && sample_max>65536.f; +#endif + celt_preemphasis(pcm+c, in+c*(N+overlap)+overlap, N, CC, st->upsample, + mode->preemph, st->preemph_memE+c, need_clip); + } while (++clfe&&nbAvailableBytes>3) || nbAvailableBytes>12*C) && !hybrid && !silence && !st->disable_pf + && st->complexity >= 5; + + prefilter_tapset = st->tapset_decision; + pf_on = run_prefilter(st, in, prefilter_mem, CC, N, prefilter_tapset, &pitch_index, &gain1, &qg, enabled, nbAvailableBytes, &st->analysis); + if ((gain1 > QCONST16(.4f,15) || st->prefilter_gain > QCONST16(.4f,15)) && (!st->analysis.valid || st->analysis.tonality > .3) + && (pitch_index > 1.26*st->prefilter_period || pitch_index < .79*st->prefilter_period)) + pitch_change = 1; + if (pf_on==0) + { + if(!hybrid && tell+16<=total_bits) + ec_enc_bit_logp(enc, 0, 1); + } else { + /*This block is not gated by a total bits check only because + of the nbAvailableBytes check above.*/ + int octave; + ec_enc_bit_logp(enc, 1, 1); + pitch_index += 1; + octave = EC_ILOG(pitch_index)-5; + ec_enc_uint(enc, octave, 6); + ec_enc_bits(enc, pitch_index-(16<complexity >= 1 && !st->lfe) + { + /* Reduces the likelihood of energy instability on fricatives at low bitrate + in hybrid mode. It seems like we still want to have real transients on vowels + though (small SILK quantization offset value). */ + int allow_weak_transients = hybrid && effectiveBytes<15 && st->silk_info.signalType != 2; + isTransient = transient_analysis(in, N+overlap, CC, + &tf_estimate, &tf_chan, allow_weak_transients, &weak_transient); + } + if (LM>0 && ec_tell(enc)+3<=total_bits) + { + if (isTransient) + shortBlocks = M; + } else { + isTransient = 0; + transient_got_disabled=1; + } + + ALLOC(freq, CC*N, celt_sig); /**< Interleaved signal MDCTs */ + ALLOC(bandE,nbEBands*CC, celt_ener); + ALLOC(bandLogE,nbEBands*CC, opus_val16); + + secondMdct = shortBlocks && st->complexity>=8; + ALLOC(bandLogE2, C*nbEBands, opus_val16); + if (secondMdct) + { + compute_mdcts(mode, 0, in, freq, C, CC, LM, st->upsample, st->arch); + compute_band_energies(mode, freq, bandE, effEnd, C, LM, st->arch); + amp2Log2(mode, effEnd, end, bandE, bandLogE2, C); + for (i=0;iupsample, st->arch); + /* This should catch any NaN in the CELT input. Since we're not supposed to see any (they're filtered + at the Opus layer), just abort. */ + celt_assert(!celt_isnan(freq[0]) && (C==1 || !celt_isnan(freq[N]))); + if (CC==2&&C==1) + tf_chan = 0; + compute_band_energies(mode, freq, bandE, effEnd, C, LM, st->arch); + + if (st->lfe) + { + for (i=2;ienergy_mask&&!st->lfe) + { + int mask_end; + int midband; + int count_dynalloc; + opus_val32 mask_avg=0; + opus_val32 diff=0; + int count=0; + mask_end = IMAX(2,st->lastCodedBands); + for (c=0;cenergy_mask[nbEBands*c+i], + QCONST16(.25f, DB_SHIFT)), -QCONST16(2.0f, DB_SHIFT)); + if (mask > 0) + mask = HALF16(mask); + mask_avg += MULT16_16(mask, eBands[i+1]-eBands[i]); + count += eBands[i+1]-eBands[i]; + diff += MULT16_16(mask, 1+2*i-mask_end); + } + } + celt_assert(count>0); + mask_avg = DIV32_16(mask_avg,count); + mask_avg += QCONST16(.2f, DB_SHIFT); + diff = diff*6/(C*(mask_end-1)*(mask_end+1)*mask_end); + /* Again, being conservative */ + diff = HALF32(diff); + diff = MAX32(MIN32(diff, QCONST32(.031f, DB_SHIFT)), -QCONST32(.031f, DB_SHIFT)); + /* Find the band that's in the middle of the coded spectrum */ + for (midband=0;eBands[midband+1] < eBands[mask_end]/2;midband++); + count_dynalloc=0; + for(i=0;ienergy_mask[i], st->energy_mask[nbEBands+i]); + else + unmask = st->energy_mask[i]; + unmask = MIN16(unmask, QCONST16(.0f, DB_SHIFT)); + unmask -= lin; + if (unmask > QCONST16(.25f, DB_SHIFT)) + { + surround_dynalloc[i] = unmask - QCONST16(.25f, DB_SHIFT); + count_dynalloc++; + } + } + if (count_dynalloc>=3) + { + /* If we need dynalloc in many bands, it's probably because our + initial masking rate was too low. */ + mask_avg += QCONST16(.25f, DB_SHIFT); + if (mask_avg>0) + { + /* Something went really wrong in the original calculations, + disabling masking. */ + mask_avg = 0; + diff = 0; + OPUS_CLEAR(surround_dynalloc, mask_end); + } else { + for(i=0;ilfe) + { + opus_val16 follow=-QCONST16(10.0f,DB_SHIFT); + opus_val32 frame_avg=0; + opus_val16 offset = shortBlocks?HALF16(SHL16(LM, DB_SHIFT)):0; + for(i=start;ispec_avg); + temporal_vbr = MIN16(QCONST16(3.f, DB_SHIFT), MAX16(-QCONST16(1.5f, DB_SHIFT), temporal_vbr)); + st->spec_avg += MULT16_16_Q15(QCONST16(.02f, 15), temporal_vbr); + } + /*for (i=0;i<21;i++) + printf("%f ", bandLogE[i]); + printf("\n");*/ + + if (!secondMdct) + { + OPUS_COPY(bandLogE2, bandLogE, C*nbEBands); + } + + /* Last chance to catch any transient we might have missed in the + time-domain analysis */ + if (LM>0 && ec_tell(enc)+3<=total_bits && !isTransient && st->complexity>=5 && !st->lfe && !hybrid) + { + if (patch_transient_decision(bandLogE, oldBandE, nbEBands, start, end, C)) + { + isTransient = 1; + shortBlocks = M; + compute_mdcts(mode, shortBlocks, in, freq, C, CC, LM, st->upsample, st->arch); + compute_band_energies(mode, freq, bandE, effEnd, C, LM, st->arch); + amp2Log2(mode, effEnd, end, bandE, bandLogE, C); + /* Compensate for the scaling of short vs long mdcts */ + for (i=0;i0 && ec_tell(enc)+3<=total_bits) + ec_enc_bit_logp(enc, isTransient, 3); + + ALLOC(X, C*N, celt_norm); /**< Interleaved normalised MDCTs */ + + /* Band normalisation */ + normalise_bands(mode, freq, X, bandE, effEnd, C, M); + + enable_tf_analysis = effectiveBytes>=15*C && !hybrid && st->complexity>=2 && !st->lfe; + + ALLOC(offsets, nbEBands, int); + ALLOC(importance, nbEBands, int); + ALLOC(spread_weight, nbEBands, int); + + maxDepth = dynalloc_analysis(bandLogE, bandLogE2, nbEBands, start, end, C, offsets, + st->lsb_depth, mode->logN, isTransient, st->vbr, st->constrained_vbr, + eBands, LM, effectiveBytes, &tot_boost, st->lfe, surround_dynalloc, &st->analysis, importance, spread_weight); + + ALLOC(tf_res, nbEBands, int); + /* Disable variable tf resolution for hybrid and at very low bitrate */ + if (enable_tf_analysis) + { + int lambda; + lambda = IMAX(80, 20480/effectiveBytes + 2); + tf_select = tf_analysis(mode, effEnd, isTransient, tf_res, lambda, X, N, LM, tf_estimate, tf_chan, importance); + for (i=effEnd;isilk_info.signalType != 2) + { + /* For low bitrate hybrid, we force temporal resolution to 5 ms rather than 2.5 ms. */ + for (i=0;iforce_intra, + &st->delayedIntra, st->complexity >= 4, st->loss_rate, st->lfe); + + tf_encode(start, end, isTransient, tf_res, LM, tf_select, enc); + + if (ec_tell(enc)+4<=total_bits) + { + if (st->lfe) + { + st->tapset_decision = 0; + st->spread_decision = SPREAD_NORMAL; + } else if (hybrid) + { + if (st->complexity == 0) + st->spread_decision = SPREAD_NONE; + else if (isTransient) + st->spread_decision = SPREAD_NORMAL; + else + st->spread_decision = SPREAD_AGGRESSIVE; + } else if (shortBlocks || st->complexity < 3 || nbAvailableBytes < 10*C) + { + if (st->complexity == 0) + st->spread_decision = SPREAD_NONE; + else + st->spread_decision = SPREAD_NORMAL; + } else { + /* Disable new spreading+tapset estimator until we can show it works + better than the old one. So far it seems like spreading_decision() + works best. */ +#if 0 + if (st->analysis.valid) + { + static const opus_val16 spread_thresholds[3] = {-QCONST16(.6f, 15), -QCONST16(.2f, 15), -QCONST16(.07f, 15)}; + static const opus_val16 spread_histeresis[3] = {QCONST16(.15f, 15), QCONST16(.07f, 15), QCONST16(.02f, 15)}; + static const opus_val16 tapset_thresholds[2] = {QCONST16(.0f, 15), QCONST16(.15f, 15)}; + static const opus_val16 tapset_histeresis[2] = {QCONST16(.1f, 15), QCONST16(.05f, 15)}; + st->spread_decision = hysteresis_decision(-st->analysis.tonality, spread_thresholds, spread_histeresis, 3, st->spread_decision); + st->tapset_decision = hysteresis_decision(st->analysis.tonality_slope, tapset_thresholds, tapset_histeresis, 2, st->tapset_decision); + } else +#endif + { + st->spread_decision = spreading_decision(mode, X, + &st->tonal_average, st->spread_decision, &st->hf_average, + &st->tapset_decision, pf_on&&!shortBlocks, effEnd, C, M, spread_weight); + } + /*printf("%d %d\n", st->tapset_decision, st->spread_decision);*/ + /*printf("%f %d %f %d\n\n", st->analysis.tonality, st->spread_decision, st->analysis.tonality_slope, st->tapset_decision);*/ + } + ec_enc_icdf(enc, st->spread_decision, spread_icdf, 5); + } + + /* For LFE, everything interesting is in the first band */ + if (st->lfe) + offsets[0] = IMIN(8, effectiveBytes/3); + ALLOC(cap, nbEBands, int); + init_caps(mode,cap,LM,C); + + dynalloc_logp = 6; + total_bits<<=BITRES; + total_boost = 0; + tell = ec_tell_frac(enc); + for (i=start;iintensity = hysteresis_decision((opus_val16)(equiv_rate/1000), + intensity_thresholds, intensity_histeresis, 21, st->intensity); + st->intensity = IMIN(end,IMAX(start, st->intensity)); + } + + alloc_trim = 5; + if (tell+(6< 0 || st->lfe) + { + st->stereo_saving = 0; + alloc_trim = 5; + } else { + alloc_trim = alloc_trim_analysis(mode, X, bandLogE, + end, LM, C, N, &st->analysis, &st->stereo_saving, tf_estimate, + st->intensity, surround_trim, equiv_rate, st->arch); + } + ec_enc_icdf(enc, alloc_trim, trim_icdf, 7); + tell = ec_tell_frac(enc); + } + + /* Variable bitrate */ + if (vbr_rate>0) + { + opus_val16 alpha; + opus_int32 delta; + /* The target rate in 8th bits per frame */ + opus_int32 target, base_target; + opus_int32 min_allowed; + int lm_diff = mode->maxLM - LM; + + /* Don't attempt to use more than 510 kb/s, even for frames smaller than 20 ms. + The CELT allocator will just not be able to use more than that anyway. */ + nbCompressedBytes = IMIN(nbCompressedBytes,1275>>(3-LM)); + if (!hybrid) + { + base_target = vbr_rate - ((40*C+20)<constrained_vbr) + base_target += (st->vbr_offset>>lm_diff); + + if (!hybrid) + { + target = compute_vbr(mode, &st->analysis, base_target, LM, equiv_rate, + st->lastCodedBands, C, st->intensity, st->constrained_vbr, + st->stereo_saving, tot_boost, tf_estimate, pitch_change, maxDepth, + st->lfe, st->energy_mask!=NULL, surround_masking, + temporal_vbr); + } else { + target = base_target; + /* Tonal frames (offset<100) need more bits than noisy (offset>100) ones. */ + if (st->silk_info.offset < 100) target += 12 << BITRES >> (3-LM); + if (st->silk_info.offset > 100) target -= 18 << BITRES >> (3-LM); + /* Boosting bitrate on transients and vowels with significant temporal + spikes. */ + target += (opus_int32)MULT16_16_Q14(tf_estimate-QCONST16(.25f,14), (50< QCONST16(.7f,14)) + target = IMAX(target, 50<>(BITRES+3)) + 2; + /* Take into account the 37 bits we need to have left in the packet to + signal a redundant frame in hybrid mode. Creating a shorter packet would + create an entropy coder desync. */ + if (hybrid) + min_allowed = IMAX(min_allowed, (tell0_frac+(37<>(BITRES+3)); + + nbAvailableBytes = (target+(1<<(BITRES+2)))>>(BITRES+3); + nbAvailableBytes = IMAX(min_allowed,nbAvailableBytes); + nbAvailableBytes = IMIN(nbCompressedBytes,nbAvailableBytes); + + /* By how much did we "miss" the target on that frame */ + delta = target - vbr_rate; + + target=nbAvailableBytes<<(BITRES+3); + + /*If the frame is silent we don't adjust our drift, otherwise + the encoder will shoot to very high rates after hitting a + span of silence, but we do allow the bitres to refill. + This means that we'll undershoot our target in CVBR/VBR modes + on files with lots of silence. */ + if(silence) + { + nbAvailableBytes = 2; + target = 2*8<vbr_count < 970) + { + st->vbr_count++; + alpha = celt_rcp(SHL32(EXTEND32(st->vbr_count+20),16)); + } else + alpha = QCONST16(.001f,15); + /* How many bits have we used in excess of what we're allowed */ + if (st->constrained_vbr) + st->vbr_reservoir += target - vbr_rate; + /*printf ("%d\n", st->vbr_reservoir);*/ + + /* Compute the offset we need to apply in order to reach the target */ + if (st->constrained_vbr) + { + st->vbr_drift += (opus_int32)MULT16_32_Q15(alpha,(delta*(1<vbr_offset-st->vbr_drift); + st->vbr_offset = -st->vbr_drift; + } + /*printf ("%d\n", st->vbr_drift);*/ + + if (st->constrained_vbr && st->vbr_reservoir < 0) + { + /* We're under the min value -- increase rate */ + int adjust = (-st->vbr_reservoir)/(8<vbr_reservoir = 0; + /*printf ("+%d\n", adjust);*/ + } + nbCompressedBytes = IMIN(nbCompressedBytes,nbAvailableBytes); + /*printf("%d\n", nbCompressedBytes*50*8);*/ + /* This moves the raw bits to take into account the new compressed size */ + ec_enc_shrink(enc, nbCompressedBytes); + } + + /* Bit allocation */ + ALLOC(fine_quant, nbEBands, int); + ALLOC(pulses, nbEBands, int); + ALLOC(fine_priority, nbEBands, int); + + /* bits = packet size - where we are - safety*/ + bits = (((opus_int32)nbCompressedBytes*8)<=2&&bits>=((LM+2)<analysis.valid) + { + int min_bandwidth; + if (equiv_rate < (opus_int32)32000*C) + min_bandwidth = 13; + else if (equiv_rate < (opus_int32)48000*C) + min_bandwidth = 16; + else if (equiv_rate < (opus_int32)60000*C) + min_bandwidth = 18; + else if (equiv_rate < (opus_int32)80000*C) + min_bandwidth = 19; + else + min_bandwidth = 20; + signalBandwidth = IMAX(st->analysis.bandwidth, min_bandwidth); + } +#endif + if (st->lfe) + signalBandwidth = 1; + codedBands = clt_compute_allocation(mode, start, end, offsets, cap, + alloc_trim, &st->intensity, &dual_stereo, bits, &balance, pulses, + fine_quant, fine_priority, C, LM, enc, 1, st->lastCodedBands, signalBandwidth); + if (st->lastCodedBands) + st->lastCodedBands = IMIN(st->lastCodedBands+1,IMAX(st->lastCodedBands-1,codedBands)); + else + st->lastCodedBands = codedBands; + + quant_fine_energy(mode, start, end, oldBandE, error, fine_quant, enc, C); + + /* Residual quantisation */ + ALLOC(collapse_masks, C*nbEBands, unsigned char); + quant_all_bands(1, mode, start, end, X, C==2 ? X+N : NULL, collapse_masks, + bandE, pulses, shortBlocks, st->spread_decision, + dual_stereo, st->intensity, tf_res, nbCompressedBytes*(8<rng, st->complexity, st->arch, st->disable_inv); + + if (anti_collapse_rsv > 0) + { + anti_collapse_on = st->consec_transient<2; +#ifdef FUZZING + anti_collapse_on = rand()&0x1; +#endif + ec_enc_bits(enc, anti_collapse_on, 1); + } + quant_energy_finalise(mode, start, end, oldBandE, error, fine_quant, fine_priority, nbCompressedBytes*8-ec_tell(enc), enc, C); + OPUS_CLEAR(energyError, nbEBands*CC); + c=0; + do { + for (i=start;irng); + } + + c=0; do { + OPUS_MOVE(st->syn_mem[c], st->syn_mem[c]+N, 2*MAX_PERIOD-N+overlap/2); + } while (++csyn_mem[c]+2*MAX_PERIOD-N; + } while (++cupsample, silence, st->arch); + + c=0; do { + st->prefilter_period=IMAX(st->prefilter_period, COMBFILTER_MINPERIOD); + st->prefilter_period_old=IMAX(st->prefilter_period_old, COMBFILTER_MINPERIOD); + comb_filter(out_mem[c], out_mem[c], st->prefilter_period_old, st->prefilter_period, mode->shortMdctSize, + st->prefilter_gain_old, st->prefilter_gain, st->prefilter_tapset_old, st->prefilter_tapset, + mode->window, overlap); + if (LM!=0) + comb_filter(out_mem[c]+mode->shortMdctSize, out_mem[c]+mode->shortMdctSize, st->prefilter_period, pitch_index, N-mode->shortMdctSize, + st->prefilter_gain, gain1, st->prefilter_tapset, prefilter_tapset, + mode->window, overlap); + } while (++cupsample, mode->preemph, st->preemph_memD); + st->prefilter_period_old = st->prefilter_period; + st->prefilter_gain_old = st->prefilter_gain; + st->prefilter_tapset_old = st->prefilter_tapset; + } +#endif + + st->prefilter_period = pitch_index; + st->prefilter_gain = gain1; + st->prefilter_tapset = prefilter_tapset; +#ifdef RESYNTH + if (LM!=0) + { + st->prefilter_period_old = st->prefilter_period; + st->prefilter_gain_old = st->prefilter_gain; + st->prefilter_tapset_old = st->prefilter_tapset; + } +#endif + + if (CC==2&&C==1) { + OPUS_COPY(&oldBandE[nbEBands], oldBandE, nbEBands); + } + + if (!isTransient) + { + OPUS_COPY(oldLogE2, oldLogE, CC*nbEBands); + OPUS_COPY(oldLogE, oldBandE, CC*nbEBands); + } else { + for (i=0;iconsec_transient++; + else + st->consec_transient=0; + st->rng = enc->rng; + + /* If there's any room left (can only happen for very high rates), + it's already filled with zeros */ + ec_enc_done(enc); + +#ifdef CUSTOM_MODES + if (st->signalling) + nbCompressedBytes++; +#endif + + RESTORE_STACK; + if (ec_get_error(enc)) + return OPUS_INTERNAL_ERROR; + else + return nbCompressedBytes; +} + + +#ifdef CUSTOM_MODES + +#ifdef FIXED_POINT +int opus_custom_encode(CELTEncoder * OPUS_RESTRICT st, const opus_int16 * pcm, int frame_size, unsigned char *compressed, int nbCompressedBytes) +{ + return celt_encode_with_ec(st, pcm, frame_size, compressed, nbCompressedBytes, NULL); +} + +#ifndef DISABLE_FLOAT_API +int opus_custom_encode_float(CELTEncoder * OPUS_RESTRICT st, const float * pcm, int frame_size, unsigned char *compressed, int nbCompressedBytes) +{ + int j, ret, C, N; + VARDECL(opus_int16, in); + ALLOC_STACK; + + if (pcm==NULL) + return OPUS_BAD_ARG; + + C = st->channels; + N = frame_size; + ALLOC(in, C*N, opus_int16); + + for (j=0;jchannels; + N=frame_size; + ALLOC(in, C*N, celt_sig); + for (j=0;j10) + goto bad_arg; + st->complexity = value; + } + break; + case CELT_SET_START_BAND_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if (value<0 || value>=st->mode->nbEBands) + goto bad_arg; + st->start = value; + } + break; + case CELT_SET_END_BAND_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if (value<1 || value>st->mode->nbEBands) + goto bad_arg; + st->end = value; + } + break; + case CELT_SET_PREDICTION_REQUEST: + { + int value = va_arg(ap, opus_int32); + if (value<0 || value>2) + goto bad_arg; + st->disable_pf = value<=1; + st->force_intra = value==0; + } + break; + case OPUS_SET_PACKET_LOSS_PERC_REQUEST: + { + int value = va_arg(ap, opus_int32); + if (value<0 || value>100) + goto bad_arg; + st->loss_rate = value; + } + break; + case OPUS_SET_VBR_CONSTRAINT_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + st->constrained_vbr = value; + } + break; + case OPUS_SET_VBR_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + st->vbr = value; + } + break; + case OPUS_SET_BITRATE_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if (value<=500 && value!=OPUS_BITRATE_MAX) + goto bad_arg; + value = IMIN(value, 260000*st->channels); + st->bitrate = value; + } + break; + case CELT_SET_CHANNELS_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if (value<1 || value>2) + goto bad_arg; + st->stream_channels = value; + } + break; + case OPUS_SET_LSB_DEPTH_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if (value<8 || value>24) + goto bad_arg; + st->lsb_depth=value; + } + break; + case OPUS_GET_LSB_DEPTH_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + *value=st->lsb_depth; + } + break; + case OPUS_SET_PHASE_INVERSION_DISABLED_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if(value<0 || value>1) + { + goto bad_arg; + } + st->disable_inv = value; + } + break; + case OPUS_GET_PHASE_INVERSION_DISABLED_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = st->disable_inv; + } + break; + case OPUS_RESET_STATE: + { + int i; + opus_val16 *oldBandE, *oldLogE, *oldLogE2; + oldBandE = (opus_val16*)(st->in_mem+st->channels*(st->mode->overlap+COMBFILTER_MAXPERIOD)); + oldLogE = oldBandE + st->channels*st->mode->nbEBands; + oldLogE2 = oldLogE + st->channels*st->mode->nbEBands; + OPUS_CLEAR((char*)&st->ENCODER_RESET_START, + opus_custom_encoder_get_size(st->mode, st->channels)- + ((char*)&st->ENCODER_RESET_START - (char*)st)); + for (i=0;ichannels*st->mode->nbEBands;i++) + oldLogE[i]=oldLogE2[i]=-QCONST16(28.f,DB_SHIFT); + st->vbr_offset = 0; + st->delayedIntra = 1; + st->spread_decision = SPREAD_NORMAL; + st->tonal_average = 256; + st->hf_average = 0; + st->tapset_decision = 0; + } + break; +#ifdef CUSTOM_MODES + case CELT_SET_INPUT_CLIPPING_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + st->clip = value; + } + break; +#endif + case CELT_SET_SIGNALLING_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + st->signalling = value; + } + break; + case CELT_SET_ANALYSIS_REQUEST: + { + AnalysisInfo *info = va_arg(ap, AnalysisInfo *); + if (info) + OPUS_COPY(&st->analysis, info, 1); + } + break; + case CELT_SET_SILK_INFO_REQUEST: + { + SILKInfo *info = va_arg(ap, SILKInfo *); + if (info) + OPUS_COPY(&st->silk_info, info, 1); + } + break; + case CELT_GET_MODE_REQUEST: + { + const CELTMode ** value = va_arg(ap, const CELTMode**); + if (value==0) + goto bad_arg; + *value=st->mode; + } + break; + case OPUS_GET_FINAL_RANGE_REQUEST: + { + opus_uint32 * value = va_arg(ap, opus_uint32 *); + if (value==0) + goto bad_arg; + *value=st->rng; + } + break; + case OPUS_SET_LFE_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + st->lfe = value; + } + break; + case OPUS_SET_ENERGY_MASK_REQUEST: + { + opus_val16 *value = va_arg(ap, opus_val16*); + st->energy_mask = value; + } + break; + default: + goto bad_request; + } + va_end(ap); + return OPUS_OK; +bad_arg: + va_end(ap); + return OPUS_BAD_ARG; +bad_request: + va_end(ap); + return OPUS_UNIMPLEMENTED; +} diff --git a/extern/opus/celt/celt_lpc.c b/extern/opus/celt/celt_lpc.c new file mode 100644 index 0000000..8ecb693 --- /dev/null +++ b/extern/opus/celt/celt_lpc.c @@ -0,0 +1,296 @@ +/* Copyright (c) 2009-2010 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + 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. + + 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 OWNER + 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. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "celt_lpc.h" +#include "stack_alloc.h" +#include "mathops.h" +#include "pitch.h" + +void _celt_lpc( + opus_val16 *_lpc, /* out: [0...p-1] LPC coefficients */ +const opus_val32 *ac, /* in: [0...p] autocorrelation values */ +int p +) +{ + int i, j; + opus_val32 r; + opus_val32 error = ac[0]; +#ifdef FIXED_POINT + opus_val32 lpc[LPC_ORDER]; +#else + float *lpc = _lpc; +#endif + + OPUS_CLEAR(lpc, p); + if (ac[0] != 0) + { + for (i = 0; i < p; i++) { + /* Sum up this iteration's reflection coefficient */ + opus_val32 rr = 0; + for (j = 0; j < i; j++) + rr += MULT32_32_Q31(lpc[j],ac[i - j]); + rr += SHR32(ac[i + 1],3); + r = -frac_div32(SHL32(rr,3), error); + /* Update LPC coefficients and total error */ + lpc[i] = SHR32(r,3); + for (j = 0; j < (i+1)>>1; j++) + { + opus_val32 tmp1, tmp2; + tmp1 = lpc[j]; + tmp2 = lpc[i-1-j]; + lpc[j] = tmp1 + MULT32_32_Q31(r,tmp2); + lpc[i-1-j] = tmp2 + MULT32_32_Q31(r,tmp1); + } + + error = error - MULT32_32_Q31(MULT32_32_Q31(r,r),error); + /* Bail out once we get 30 dB gain */ +#ifdef FIXED_POINT + if (error=1;j--) + { + mem[j]=mem[j-1]; + } + mem[0] = SROUND16(sum, SIG_SHIFT); + _y[i] = sum; + } +#else + int i,j; + VARDECL(opus_val16, rden); + VARDECL(opus_val16, y); + SAVE_STACK; + + celt_assert((ord&3)==0); + ALLOC(rden, ord, opus_val16); + ALLOC(y, N+ord, opus_val16); + for(i=0;i0); + celt_assert(overlap>=0); + if (overlap == 0) + { + xptr = x; + } else { + for (i=0;i0) + { + for(i=0;i= 536870912) + { + int shift2=1; + if (ac[0] >= 1073741824) + shift2++; + for (i=0;i<=lag;i++) + ac[i] = SHR32(ac[i], shift2); + shift += shift2; + } +#endif + + RESTORE_STACK; + return shift; +} diff --git a/extern/opus/celt/celt_lpc.h b/extern/opus/celt/celt_lpc.h new file mode 100644 index 0000000..a4c5fd6 --- /dev/null +++ b/extern/opus/celt/celt_lpc.h @@ -0,0 +1,66 @@ +/* Copyright (c) 2009-2010 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + 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. + + 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 OWNER + 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. +*/ + +#ifndef PLC_H +#define PLC_H + +#include "arch.h" +#include "cpu_support.h" + +#if defined(OPUS_X86_MAY_HAVE_SSE4_1) +#include "x86/celt_lpc_sse.h" +#endif + +#define LPC_ORDER 24 + +void _celt_lpc(opus_val16 *_lpc, const opus_val32 *ac, int p); + +void celt_fir_c( + const opus_val16 *x, + const opus_val16 *num, + opus_val16 *y, + int N, + int ord, + int arch); + +#if !defined(OVERRIDE_CELT_FIR) +#define celt_fir(x, num, y, N, ord, arch) \ + (celt_fir_c(x, num, y, N, ord, arch)) +#endif + +void celt_iir(const opus_val32 *x, + const opus_val16 *den, + opus_val32 *y, + int N, + int ord, + opus_val16 *mem, + int arch); + +int _celt_autocorr(const opus_val16 *x, opus_val32 *ac, + const opus_val16 *window, int overlap, int lag, int n, int arch); + +#endif /* PLC_H */ diff --git a/extern/opus/celt/cpu_support.h b/extern/opus/celt/cpu_support.h new file mode 100644 index 0000000..68fc606 --- /dev/null +++ b/extern/opus/celt/cpu_support.h @@ -0,0 +1,70 @@ +/* Copyright (c) 2010 Xiph.Org Foundation + * Copyright (c) 2013 Parrot */ +/* + 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. + + 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 OWNER + 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. +*/ + +#ifndef CPU_SUPPORT_H +#define CPU_SUPPORT_H + +#include "opus_types.h" +#include "opus_defines.h" + +#if defined(OPUS_HAVE_RTCD) && \ + (defined(OPUS_ARM_ASM) || defined(OPUS_ARM_MAY_HAVE_NEON_INTR)) +#include "arm/armcpu.h" + +/* We currently support 4 ARM variants: + * arch[0] -> ARMv4 + * arch[1] -> ARMv5E + * arch[2] -> ARMv6 + * arch[3] -> NEON + */ +#define OPUS_ARCHMASK 3 + +#elif (defined(OPUS_X86_MAY_HAVE_SSE) && !defined(OPUS_X86_PRESUME_SSE)) || \ + (defined(OPUS_X86_MAY_HAVE_SSE2) && !defined(OPUS_X86_PRESUME_SSE2)) || \ + (defined(OPUS_X86_MAY_HAVE_SSE4_1) && !defined(OPUS_X86_PRESUME_SSE4_1)) || \ + (defined(OPUS_X86_MAY_HAVE_AVX) && !defined(OPUS_X86_PRESUME_AVX)) + +#include "x86/x86cpu.h" +/* We currently support 5 x86 variants: + * arch[0] -> non-sse + * arch[1] -> sse + * arch[2] -> sse2 + * arch[3] -> sse4.1 + * arch[4] -> avx + */ +#define OPUS_ARCHMASK 7 +int opus_select_arch(void); + +#else +#define OPUS_ARCHMASK 0 + +static OPUS_INLINE int opus_select_arch(void) +{ + return 0; +} +#endif +#endif diff --git a/extern/opus/celt/cwrs.c b/extern/opus/celt/cwrs.c new file mode 100644 index 0000000..a552e4f --- /dev/null +++ b/extern/opus/celt/cwrs.c @@ -0,0 +1,715 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Copyright (c) 2007-2009 Timothy B. Terriberry + Written by Timothy B. Terriberry and Jean-Marc Valin */ +/* + 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. + + 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 OWNER + 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. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "os_support.h" +#include "cwrs.h" +#include "mathops.h" +#include "arch.h" + +#ifdef CUSTOM_MODES + +/*Guaranteed to return a conservatively large estimate of the binary logarithm + with frac bits of fractional precision. + Tested for all possible 32-bit inputs with frac=4, where the maximum + overestimation is 0.06254243 bits.*/ +int log2_frac(opus_uint32 val, int frac) +{ + int l; + l=EC_ILOG(val); + if(val&(val-1)){ + /*This is (val>>l-16), but guaranteed to round up, even if adding a bias + before the shift would cause overflow (e.g., for 0xFFFFxxxx). + Doesn't work for val=0, but that case fails the test above.*/ + if(l>16)val=((val-1)>>(l-16))+1; + else val<<=16-l; + l=(l-1)<>16); + l+=b<>b; + val=(val*val+0x7FFF)>>15; + } + while(frac-->0); + /*If val is not exactly 0x8000, then we have to round up the remainder.*/ + return l+(val>0x8000); + } + /*Exact powers of two require no rounding.*/ + else return (l-1)<0 ? sum(k=1...K,2**k*choose(N,k)*choose(K-1,k-1)) : 1, + where choose() is the binomial function. + A table of values for N<10 and K<10 looks like: + V[10][10] = { + {1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {1, 2, 2, 2, 2, 2, 2, 2, 2, 2}, + {1, 4, 8, 12, 16, 20, 24, 28, 32, 36}, + {1, 6, 18, 38, 66, 102, 146, 198, 258, 326}, + {1, 8, 32, 88, 192, 360, 608, 952, 1408, 1992}, + {1, 10, 50, 170, 450, 1002, 1970, 3530, 5890, 9290}, + {1, 12, 72, 292, 912, 2364, 5336, 10836, 20256, 35436}, + {1, 14, 98, 462, 1666, 4942, 12642, 28814, 59906, 115598}, + {1, 16, 128, 688, 2816, 9424, 27008, 68464, 157184, 332688}, + {1, 18, 162, 978, 4482, 16722, 53154, 148626, 374274, 864146} + }; + + U(N,K) = the number of such combinations wherein N-1 objects are taken at + most K-1 at a time. + This is given by + U(N,K) = sum(k=0...K-1,V(N-1,k)) + = K>0 ? (V(N-1,K-1) + V(N,K-1))/2 : 0. + The latter expression also makes clear that U(N,K) is half the number of such + combinations wherein the first object is taken at least once. + Although it may not be clear from either of these definitions, U(N,K) is the + natural function to work with when enumerating the pulse vector codebooks, + not V(N,K). + U(N,K) is not well-defined for N=0, but with the extension + U(0,K) = K>0 ? 0 : 1, + the function becomes symmetric: U(N,K) = U(K,N), with a similar table: + U[10][10] = { + {1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 1, 1, 1, 1, 1, 1, 1, 1, 1}, + {0, 1, 3, 5, 7, 9, 11, 13, 15, 17}, + {0, 1, 5, 13, 25, 41, 61, 85, 113, 145}, + {0, 1, 7, 25, 63, 129, 231, 377, 575, 833}, + {0, 1, 9, 41, 129, 321, 681, 1289, 2241, 3649}, + {0, 1, 11, 61, 231, 681, 1683, 3653, 7183, 13073}, + {0, 1, 13, 85, 377, 1289, 3653, 8989, 19825, 40081}, + {0, 1, 15, 113, 575, 2241, 7183, 19825, 48639, 108545}, + {0, 1, 17, 145, 833, 3649, 13073, 40081, 108545, 265729} + }; + + With this extension, V(N,K) may be written in terms of U(N,K): + V(N,K) = U(N,K) + U(N,K+1) + for all N>=0, K>=0. + Thus U(N,K+1) represents the number of combinations where the first element + is positive or zero, and U(N,K) represents the number of combinations where + it is negative. + With a large enough table of U(N,K) values, we could write O(N) encoding + and O(min(N*log(K),N+K)) decoding routines, but such a table would be + prohibitively large for small embedded devices (K may be as large as 32767 + for small N, and N may be as large as 200). + + Both functions obey the same recurrence relation: + V(N,K) = V(N-1,K) + V(N,K-1) + V(N-1,K-1), + U(N,K) = U(N-1,K) + U(N,K-1) + U(N-1,K-1), + for all N>0, K>0, with different initial conditions at N=0 or K=0. + This allows us to construct a row of one of the tables above given the + previous row or the next row. + Thus we can derive O(NK) encoding and decoding routines with O(K) memory + using only addition and subtraction. + + When encoding, we build up from the U(2,K) row and work our way forwards. + When decoding, we need to start at the U(N,K) row and work our way backwards, + which requires a means of computing U(N,K). + U(N,K) may be computed from two previous values with the same N: + U(N,K) = ((2*N-1)*U(N,K-1) - U(N,K-2))/(K-1) + U(N,K-2) + for all N>1, and since U(N,K) is symmetric, a similar relation holds for two + previous values with the same K: + U(N,K>1) = ((2*K-1)*U(N-1,K) - U(N-2,K))/(N-1) + U(N-2,K) + for all K>1. + This allows us to construct an arbitrary row of the U(N,K) table by starting + with the first two values, which are constants. + This saves roughly 2/3 the work in our O(NK) decoding routine, but costs O(K) + multiplications. + Similar relations can be derived for V(N,K), but are not used here. + + For N>0 and K>0, U(N,K) and V(N,K) take on the form of an (N-1)-degree + polynomial for fixed N. + The first few are + U(1,K) = 1, + U(2,K) = 2*K-1, + U(3,K) = (2*K-2)*K+1, + U(4,K) = (((4*K-6)*K+8)*K-3)/3, + U(5,K) = ((((2*K-4)*K+10)*K-8)*K+3)/3, + and + V(1,K) = 2, + V(2,K) = 4*K, + V(3,K) = 4*K*K+2, + V(4,K) = 8*(K*K+2)*K/3, + V(5,K) = ((4*K*K+20)*K*K+6)/3, + for all K>0. + This allows us to derive O(N) encoding and O(N*log(K)) decoding routines for + small N (and indeed decoding is also O(N) for N<3). + + @ARTICLE{Fis86, + author="Thomas R. Fischer", + title="A Pyramid Vector Quantizer", + journal="IEEE Transactions on Information Theory", + volume="IT-32", + number=4, + pages="568--583", + month=Jul, + year=1986 + }*/ + +#if !defined(SMALL_FOOTPRINT) + +/*U(N,K) = U(K,N) := N>0?K>0?U(N-1,K)+U(N,K-1)+U(N-1,K-1):0:K>0?1:0*/ +# define CELT_PVQ_U(_n,_k) (CELT_PVQ_U_ROW[IMIN(_n,_k)][IMAX(_n,_k)]) +/*V(N,K) := U(N,K)+U(N,K+1) = the number of PVQ codewords for a band of size N + with K pulses allocated to it.*/ +# define CELT_PVQ_V(_n,_k) (CELT_PVQ_U(_n,_k)+CELT_PVQ_U(_n,(_k)+1)) + +/*For each V(N,K) supported, we will access element U(min(N,K+1),max(N,K+1)). + Thus, the number of entries in row I is the larger of the maximum number of + pulses we will ever allocate for a given N=I (K=128, or however many fit in + 32 bits, whichever is smaller), plus one, and the maximum N for which + K=I-1 pulses fit in 32 bits. + The largest band size in an Opus Custom mode is 208. + Otherwise, we can limit things to the set of N which can be achieved by + splitting a band from a standard Opus mode: 176, 144, 96, 88, 72, 64, 48, + 44, 36, 32, 24, 22, 18, 16, 8, 4, 2).*/ +#if defined(CUSTOM_MODES) +static const opus_uint32 CELT_PVQ_U_DATA[1488]={ +#else +static const opus_uint32 CELT_PVQ_U_DATA[1272]={ +#endif + /*N=0, K=0...176:*/ + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +#if defined(CUSTOM_MODES) + /*...208:*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, +#endif + /*N=1, K=1...176:*/ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, +#if defined(CUSTOM_MODES) + /*...208:*/ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, +#endif + /*N=2, K=2...176:*/ + 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39, 41, + 43, 45, 47, 49, 51, 53, 55, 57, 59, 61, 63, 65, 67, 69, 71, 73, 75, 77, 79, + 81, 83, 85, 87, 89, 91, 93, 95, 97, 99, 101, 103, 105, 107, 109, 111, 113, + 115, 117, 119, 121, 123, 125, 127, 129, 131, 133, 135, 137, 139, 141, 143, + 145, 147, 149, 151, 153, 155, 157, 159, 161, 163, 165, 167, 169, 171, 173, + 175, 177, 179, 181, 183, 185, 187, 189, 191, 193, 195, 197, 199, 201, 203, + 205, 207, 209, 211, 213, 215, 217, 219, 221, 223, 225, 227, 229, 231, 233, + 235, 237, 239, 241, 243, 245, 247, 249, 251, 253, 255, 257, 259, 261, 263, + 265, 267, 269, 271, 273, 275, 277, 279, 281, 283, 285, 287, 289, 291, 293, + 295, 297, 299, 301, 303, 305, 307, 309, 311, 313, 315, 317, 319, 321, 323, + 325, 327, 329, 331, 333, 335, 337, 339, 341, 343, 345, 347, 349, 351, +#if defined(CUSTOM_MODES) + /*...208:*/ + 353, 355, 357, 359, 361, 363, 365, 367, 369, 371, 373, 375, 377, 379, 381, + 383, 385, 387, 389, 391, 393, 395, 397, 399, 401, 403, 405, 407, 409, 411, + 413, 415, +#endif + /*N=3, K=3...176:*/ + 13, 25, 41, 61, 85, 113, 145, 181, 221, 265, 313, 365, 421, 481, 545, 613, + 685, 761, 841, 925, 1013, 1105, 1201, 1301, 1405, 1513, 1625, 1741, 1861, + 1985, 2113, 2245, 2381, 2521, 2665, 2813, 2965, 3121, 3281, 3445, 3613, 3785, + 3961, 4141, 4325, 4513, 4705, 4901, 5101, 5305, 5513, 5725, 5941, 6161, 6385, + 6613, 6845, 7081, 7321, 7565, 7813, 8065, 8321, 8581, 8845, 9113, 9385, 9661, + 9941, 10225, 10513, 10805, 11101, 11401, 11705, 12013, 12325, 12641, 12961, + 13285, 13613, 13945, 14281, 14621, 14965, 15313, 15665, 16021, 16381, 16745, + 17113, 17485, 17861, 18241, 18625, 19013, 19405, 19801, 20201, 20605, 21013, + 21425, 21841, 22261, 22685, 23113, 23545, 23981, 24421, 24865, 25313, 25765, + 26221, 26681, 27145, 27613, 28085, 28561, 29041, 29525, 30013, 30505, 31001, + 31501, 32005, 32513, 33025, 33541, 34061, 34585, 35113, 35645, 36181, 36721, + 37265, 37813, 38365, 38921, 39481, 40045, 40613, 41185, 41761, 42341, 42925, + 43513, 44105, 44701, 45301, 45905, 46513, 47125, 47741, 48361, 48985, 49613, + 50245, 50881, 51521, 52165, 52813, 53465, 54121, 54781, 55445, 56113, 56785, + 57461, 58141, 58825, 59513, 60205, 60901, 61601, +#if defined(CUSTOM_MODES) + /*...208:*/ + 62305, 63013, 63725, 64441, 65161, 65885, 66613, 67345, 68081, 68821, 69565, + 70313, 71065, 71821, 72581, 73345, 74113, 74885, 75661, 76441, 77225, 78013, + 78805, 79601, 80401, 81205, 82013, 82825, 83641, 84461, 85285, 86113, +#endif + /*N=4, K=4...176:*/ + 63, 129, 231, 377, 575, 833, 1159, 1561, 2047, 2625, 3303, 4089, 4991, 6017, + 7175, 8473, 9919, 11521, 13287, 15225, 17343, 19649, 22151, 24857, 27775, + 30913, 34279, 37881, 41727, 45825, 50183, 54809, 59711, 64897, 70375, 76153, + 82239, 88641, 95367, 102425, 109823, 117569, 125671, 134137, 142975, 152193, + 161799, 171801, 182207, 193025, 204263, 215929, 228031, 240577, 253575, + 267033, 280959, 295361, 310247, 325625, 341503, 357889, 374791, 392217, + 410175, 428673, 447719, 467321, 487487, 508225, 529543, 551449, 573951, + 597057, 620775, 645113, 670079, 695681, 721927, 748825, 776383, 804609, + 833511, 863097, 893375, 924353, 956039, 988441, 1021567, 1055425, 1090023, + 1125369, 1161471, 1198337, 1235975, 1274393, 1313599, 1353601, 1394407, + 1436025, 1478463, 1521729, 1565831, 1610777, 1656575, 1703233, 1750759, + 1799161, 1848447, 1898625, 1949703, 2001689, 2054591, 2108417, 2163175, + 2218873, 2275519, 2333121, 2391687, 2451225, 2511743, 2573249, 2635751, + 2699257, 2763775, 2829313, 2895879, 2963481, 3032127, 3101825, 3172583, + 3244409, 3317311, 3391297, 3466375, 3542553, 3619839, 3698241, 3777767, + 3858425, 3940223, 4023169, 4107271, 4192537, 4278975, 4366593, 4455399, + 4545401, 4636607, 4729025, 4822663, 4917529, 5013631, 5110977, 5209575, + 5309433, 5410559, 5512961, 5616647, 5721625, 5827903, 5935489, 6044391, + 6154617, 6266175, 6379073, 6493319, 6608921, 6725887, 6844225, 6963943, + 7085049, 7207551, +#if defined(CUSTOM_MODES) + /*...208:*/ + 7331457, 7456775, 7583513, 7711679, 7841281, 7972327, 8104825, 8238783, + 8374209, 8511111, 8649497, 8789375, 8930753, 9073639, 9218041, 9363967, + 9511425, 9660423, 9810969, 9963071, 10116737, 10271975, 10428793, 10587199, + 10747201, 10908807, 11072025, 11236863, 11403329, 11571431, 11741177, + 11912575, +#endif + /*N=5, K=5...176:*/ + 321, 681, 1289, 2241, 3649, 5641, 8361, 11969, 16641, 22569, 29961, 39041, + 50049, 63241, 78889, 97281, 118721, 143529, 172041, 204609, 241601, 283401, + 330409, 383041, 441729, 506921, 579081, 658689, 746241, 842249, 947241, + 1061761, 1186369, 1321641, 1468169, 1626561, 1797441, 1981449, 2179241, + 2391489, 2618881, 2862121, 3121929, 3399041, 3694209, 4008201, 4341801, + 4695809, 5071041, 5468329, 5888521, 6332481, 6801089, 7295241, 7815849, + 8363841, 8940161, 9545769, 10181641, 10848769, 11548161, 12280841, 13047849, + 13850241, 14689089, 15565481, 16480521, 17435329, 18431041, 19468809, + 20549801, 21675201, 22846209, 24064041, 25329929, 26645121, 28010881, + 29428489, 30899241, 32424449, 34005441, 35643561, 37340169, 39096641, + 40914369, 42794761, 44739241, 46749249, 48826241, 50971689, 53187081, + 55473921, 57833729, 60268041, 62778409, 65366401, 68033601, 70781609, + 73612041, 76526529, 79526721, 82614281, 85790889, 89058241, 92418049, + 95872041, 99421961, 103069569, 106816641, 110664969, 114616361, 118672641, + 122835649, 127107241, 131489289, 135983681, 140592321, 145317129, 150160041, + 155123009, 160208001, 165417001, 170752009, 176215041, 181808129, 187533321, + 193392681, 199388289, 205522241, 211796649, 218213641, 224775361, 231483969, + 238341641, 245350569, 252512961, 259831041, 267307049, 274943241, 282741889, + 290705281, 298835721, 307135529, 315607041, 324252609, 333074601, 342075401, + 351257409, 360623041, 370174729, 379914921, 389846081, 399970689, 410291241, + 420810249, 431530241, 442453761, 453583369, 464921641, 476471169, 488234561, + 500214441, 512413449, 524834241, 537479489, 550351881, 563454121, 576788929, + 590359041, 604167209, 618216201, 632508801, +#if defined(CUSTOM_MODES) + /*...208:*/ + 647047809, 661836041, 676876329, 692171521, 707724481, 723538089, 739615241, + 755958849, 772571841, 789457161, 806617769, 824056641, 841776769, 859781161, + 878072841, 896654849, 915530241, 934702089, 954173481, 973947521, 994027329, + 1014416041, 1035116809, 1056132801, 1077467201, 1099123209, 1121104041, + 1143412929, 1166053121, 1189027881, 1212340489, 1235994241, +#endif + /*N=6, K=6...96:*/ + 1683, 3653, 7183, 13073, 22363, 36365, 56695, 85305, 124515, 177045, 246047, + 335137, 448427, 590557, 766727, 982729, 1244979, 1560549, 1937199, 2383409, + 2908411, 3522221, 4235671, 5060441, 6009091, 7095093, 8332863, 9737793, + 11326283, 13115773, 15124775, 17372905, 19880915, 22670725, 25765455, + 29189457, 32968347, 37129037, 41699767, 46710137, 52191139, 58175189, + 64696159, 71789409, 79491819, 87841821, 96879431, 106646281, 117185651, + 128542501, 140763503, 153897073, 167993403, 183104493, 199284183, 216588185, + 235074115, 254801525, 275831935, 298228865, 322057867, 347386557, 374284647, + 402823977, 433078547, 465124549, 499040399, 534906769, 572806619, 612825229, + 655050231, 699571641, 746481891, 795875861, 847850911, 902506913, 959946283, + 1020274013, 1083597703, 1150027593, 1219676595, 1292660325, 1369097135, + 1449108145, 1532817275, 1620351277, 1711839767, 1807415257, 1907213187, + 2011371957, 2120032959, +#if defined(CUSTOM_MODES) + /*...109:*/ + 2233340609U, 2351442379U, 2474488829U, 2602633639U, 2736033641U, 2874848851U, + 3019242501U, 3169381071U, 3325434321U, 3487575323U, 3655980493U, 3830829623U, + 4012305913U, +#endif + /*N=7, K=7...54*/ + 8989, 19825, 40081, 75517, 134245, 227305, 369305, 579125, 880685, 1303777, + 1884961, 2668525, 3707509, 5064793, 6814249, 9041957, 11847485, 15345233, + 19665841, 24957661, 31388293, 39146185, 48442297, 59511829, 72616013, + 88043969, 106114625, 127178701, 151620757, 179861305, 212358985, 249612805, + 292164445, 340600625, 395555537, 457713341, 527810725, 606639529, 695049433, + 793950709, 904317037, 1027188385, 1163673953, 1314955181, 1482288821, + 1667010073, 1870535785, 2094367717, +#if defined(CUSTOM_MODES) + /*...60:*/ + 2340095869U, 2609401873U, 2904062449U, 3225952925U, 3577050821U, 3959439497U, +#endif + /*N=8, K=8...37*/ + 48639, 108545, 224143, 433905, 795455, 1392065, 2340495, 3800305, 5984767, + 9173505, 13726991, 20103025, 28875327, 40754369, 56610575, 77500017, + 104692735, 139703809, 184327311, 240673265, 311207743, 398796225, 506750351, + 638878193, 799538175, 993696769, 1226990095, 1505789553, 1837271615, + 2229491905U, +#if defined(CUSTOM_MODES) + /*...40:*/ + 2691463695U, 3233240945U, 3866006015U, +#endif + /*N=9, K=9...28:*/ + 265729, 598417, 1256465, 2485825, 4673345, 8405905, 14546705, 24331777, + 39490049, 62390545, 96220561, 145198913, 214828609, 312193553, 446304145, + 628496897, 872893441, 1196924561, 1621925137, 2173806145U, +#if defined(CUSTOM_MODES) + /*...29:*/ + 2883810113U, +#endif + /*N=10, K=10...24:*/ + 1462563, 3317445, 7059735, 14218905, 27298155, 50250765, 89129247, 152951073, + 254831667, 413442773, 654862247, 1014889769, 1541911931, 2300409629U, + 3375210671U, + /*N=11, K=11...19:*/ + 8097453, 18474633, 39753273, 81270333, 158819253, 298199265, 540279585, + 948062325, 1616336765, +#if defined(CUSTOM_MODES) + /*...20:*/ + 2684641785U, +#endif + /*N=12, K=12...18:*/ + 45046719, 103274625, 224298231, 464387817, 921406335, 1759885185, + 3248227095U, + /*N=13, K=13...16:*/ + 251595969, 579168825, 1267854873, 2653649025U, + /*N=14, K=14:*/ + 1409933619 +}; + +#if defined(CUSTOM_MODES) +static const opus_uint32 *const CELT_PVQ_U_ROW[15]={ + CELT_PVQ_U_DATA+ 0,CELT_PVQ_U_DATA+ 208,CELT_PVQ_U_DATA+ 415, + CELT_PVQ_U_DATA+ 621,CELT_PVQ_U_DATA+ 826,CELT_PVQ_U_DATA+1030, + CELT_PVQ_U_DATA+1233,CELT_PVQ_U_DATA+1336,CELT_PVQ_U_DATA+1389, + CELT_PVQ_U_DATA+1421,CELT_PVQ_U_DATA+1441,CELT_PVQ_U_DATA+1455, + CELT_PVQ_U_DATA+1464,CELT_PVQ_U_DATA+1470,CELT_PVQ_U_DATA+1473 +}; +#else +static const opus_uint32 *const CELT_PVQ_U_ROW[15]={ + CELT_PVQ_U_DATA+ 0,CELT_PVQ_U_DATA+ 176,CELT_PVQ_U_DATA+ 351, + CELT_PVQ_U_DATA+ 525,CELT_PVQ_U_DATA+ 698,CELT_PVQ_U_DATA+ 870, + CELT_PVQ_U_DATA+1041,CELT_PVQ_U_DATA+1131,CELT_PVQ_U_DATA+1178, + CELT_PVQ_U_DATA+1207,CELT_PVQ_U_DATA+1226,CELT_PVQ_U_DATA+1240, + CELT_PVQ_U_DATA+1248,CELT_PVQ_U_DATA+1254,CELT_PVQ_U_DATA+1257 +}; +#endif + +#if defined(CUSTOM_MODES) +void get_required_bits(opus_int16 *_bits,int _n,int _maxk,int _frac){ + int k; + /*_maxk==0 => there's nothing to do.*/ + celt_assert(_maxk>0); + _bits[0]=0; + for(k=1;k<=_maxk;k++)_bits[k]=log2_frac(CELT_PVQ_V(_n,k),_frac); +} +#endif + +static opus_uint32 icwrs(int _n,const int *_y){ + opus_uint32 i; + int j; + int k; + celt_assert(_n>=2); + j=_n-1; + i=_y[j]<0; + k=abs(_y[j]); + do{ + j--; + i+=CELT_PVQ_U(_n-j,k); + k+=abs(_y[j]); + if(_y[j]<0)i+=CELT_PVQ_U(_n-j,k+1); + } + while(j>0); + return i; +} + +void encode_pulses(const int *_y,int _n,int _k,ec_enc *_enc){ + celt_assert(_k>0); + ec_enc_uint(_enc,icwrs(_n,_y),CELT_PVQ_V(_n,_k)); +} + +static opus_val32 cwrsi(int _n,int _k,opus_uint32 _i,int *_y){ + opus_uint32 p; + int s; + int k0; + opus_int16 val; + opus_val32 yy=0; + celt_assert(_k>0); + celt_assert(_n>1); + while(_n>2){ + opus_uint32 q; + /*Lots of pulses case:*/ + if(_k>=_n){ + const opus_uint32 *row; + row=CELT_PVQ_U_ROW[_n]; + /*Are the pulses in this dimension negative?*/ + p=row[_k+1]; + s=-(_i>=p); + _i-=p&s; + /*Count how many pulses were placed in this dimension.*/ + k0=_k; + q=row[_n]; + if(q>_i){ + celt_sig_assert(p>q); + _k=_n; + do p=CELT_PVQ_U_ROW[--_k][_n]; + while(p>_i); + } + else for(p=row[_k];p>_i;p=row[_k])_k--; + _i-=p; + val=(k0-_k+s)^s; + *_y++=val; + yy=MAC16_16(yy,val,val); + } + /*Lots of dimensions case:*/ + else{ + /*Are there any pulses in this dimension at all?*/ + p=CELT_PVQ_U_ROW[_k][_n]; + q=CELT_PVQ_U_ROW[_k+1][_n]; + if(p<=_i&&_i=q); + _i-=q&s; + /*Count how many pulses were placed in this dimension.*/ + k0=_k; + do p=CELT_PVQ_U_ROW[--_k][_n]; + while(p>_i); + _i-=p; + val=(k0-_k+s)^s; + *_y++=val; + yy=MAC16_16(yy,val,val); + } + } + _n--; + } + /*_n==2*/ + p=2*_k+1; + s=-(_i>=p); + _i-=p&s; + k0=_k; + _k=(_i+1)>>1; + if(_k)_i-=2*_k-1; + val=(k0-_k+s)^s; + *_y++=val; + yy=MAC16_16(yy,val,val); + /*_n==1*/ + s=-(int)_i; + val=(_k+s)^s; + *_y=val; + yy=MAC16_16(yy,val,val); + return yy; +} + +opus_val32 decode_pulses(int *_y,int _n,int _k,ec_dec *_dec){ + return cwrsi(_n,_k,ec_dec_uint(_dec,CELT_PVQ_V(_n,_k)),_y); +} + +#else /* SMALL_FOOTPRINT */ + +/*Computes the next row/column of any recurrence that obeys the relation + u[i][j]=u[i-1][j]+u[i][j-1]+u[i-1][j-1]. + _ui0 is the base case for the new row/column.*/ +static OPUS_INLINE void unext(opus_uint32 *_ui,unsigned _len,opus_uint32 _ui0){ + opus_uint32 ui1; + unsigned j; + /*This do-while will overrun the array if we don't have storage for at least + 2 values.*/ + j=1; do { + ui1=UADD32(UADD32(_ui[j],_ui[j-1]),_ui0); + _ui[j-1]=_ui0; + _ui0=ui1; + } while (++j<_len); + _ui[j-1]=_ui0; +} + +/*Computes the previous row/column of any recurrence that obeys the relation + u[i-1][j]=u[i][j]-u[i][j-1]-u[i-1][j-1]. + _ui0 is the base case for the new row/column.*/ +static OPUS_INLINE void uprev(opus_uint32 *_ui,unsigned _n,opus_uint32 _ui0){ + opus_uint32 ui1; + unsigned j; + /*This do-while will overrun the array if we don't have storage for at least + 2 values.*/ + j=1; do { + ui1=USUB32(USUB32(_ui[j],_ui[j-1]),_ui0); + _ui[j-1]=_ui0; + _ui0=ui1; + } while (++j<_n); + _ui[j-1]=_ui0; +} + +/*Compute V(_n,_k), as well as U(_n,0..._k+1). + _u: On exit, _u[i] contains U(_n,i) for i in [0..._k+1].*/ +static opus_uint32 ncwrs_urow(unsigned _n,unsigned _k,opus_uint32 *_u){ + opus_uint32 um2; + unsigned len; + unsigned k; + len=_k+2; + /*We require storage at least 3 values (e.g., _k>0).*/ + celt_assert(len>=3); + _u[0]=0; + _u[1]=um2=1; + /*If _n==0, _u[0] should be 1 and the rest should be 0.*/ + /*If _n==1, _u[i] should be 1 for i>1.*/ + celt_assert(_n>=2); + /*If _k==0, the following do-while loop will overflow the buffer.*/ + celt_assert(_k>0); + k=2; + do _u[k]=(k<<1)-1; + while(++k0); + j=0; + do{ + opus_uint32 p; + int s; + int yj; + p=_u[_k+1]; + s=-(_i>=p); + _i-=p&s; + yj=_k; + p=_u[_k]; + while(p>_i)p=_u[--_k]; + _i-=p; + yj-=_k; + val=(yj+s)^s; + _y[j]=val; + yy=MAC16_16(yy,val,val); + uprev(_u,_k+2,0); + } + while(++j<_n); + return yy; +} + +/*Returns the index of the given combination of K elements chosen from a set + of size 1 with associated sign bits. + _y: The vector of pulses, whose sum of absolute values is K. + _k: Returns K.*/ +static OPUS_INLINE opus_uint32 icwrs1(const int *_y,int *_k){ + *_k=abs(_y[0]); + return _y[0]<0; +} + +/*Returns the index of the given combination of K elements chosen from a set + of size _n with associated sign bits. + _y: The vector of pulses, whose sum of absolute values must be _k. + _nc: Returns V(_n,_k).*/ +static OPUS_INLINE opus_uint32 icwrs(int _n,int _k,opus_uint32 *_nc,const int *_y, + opus_uint32 *_u){ + opus_uint32 i; + int j; + int k; + /*We can't unroll the first two iterations of the loop unless _n>=2.*/ + celt_assert(_n>=2); + _u[0]=0; + for(k=1;k<=_k+1;k++)_u[k]=(k<<1)-1; + i=icwrs1(_y+_n-1,&k); + j=_n-2; + i+=_u[k]; + k+=abs(_y[j]); + if(_y[j]<0)i+=_u[k+1]; + while(j-->0){ + unext(_u,_k+2,0); + i+=_u[k]; + k+=abs(_y[j]); + if(_y[j]<0)i+=_u[k+1]; + } + *_nc=_u[k]+_u[k+1]; + return i; +} + +#ifdef CUSTOM_MODES +void get_required_bits(opus_int16 *_bits,int _n,int _maxk,int _frac){ + int k; + /*_maxk==0 => there's nothing to do.*/ + celt_assert(_maxk>0); + _bits[0]=0; + if (_n==1) + { + for (k=1;k<=_maxk;k++) + _bits[k] = 1<<_frac; + } + else { + VARDECL(opus_uint32,u); + SAVE_STACK; + ALLOC(u,_maxk+2U,opus_uint32); + ncwrs_urow(_n,_maxk,u); + for(k=1;k<=_maxk;k++) + _bits[k]=log2_frac(u[k]+u[k+1],_frac); + RESTORE_STACK; + } +} +#endif /* CUSTOM_MODES */ + +void encode_pulses(const int *_y,int _n,int _k,ec_enc *_enc){ + opus_uint32 i; + VARDECL(opus_uint32,u); + opus_uint32 nc; + SAVE_STACK; + celt_assert(_k>0); + ALLOC(u,_k+2U,opus_uint32); + i=icwrs(_n,_k,&nc,_y,u); + ec_enc_uint(_enc,i,nc); + RESTORE_STACK; +} + +opus_val32 decode_pulses(int *_y,int _n,int _k,ec_dec *_dec){ + VARDECL(opus_uint32,u); + int ret; + SAVE_STACK; + celt_assert(_k>0); + ALLOC(u,_k+2U,opus_uint32); + ret = cwrsi(_n,_k,ec_dec_uint(_dec,ncwrs_urow(_n,_k,u)),_y,u); + RESTORE_STACK; + return ret; +} + +#endif /* SMALL_FOOTPRINT */ diff --git a/extern/opus/celt/cwrs.h b/extern/opus/celt/cwrs.h new file mode 100644 index 0000000..7cd4717 --- /dev/null +++ b/extern/opus/celt/cwrs.h @@ -0,0 +1,48 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Copyright (c) 2007-2009 Timothy B. Terriberry + Written by Timothy B. Terriberry and Jean-Marc Valin */ +/* + 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. + + 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 OWNER + 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. +*/ + +#ifndef CWRS_H +#define CWRS_H + +#include "arch.h" +#include "stack_alloc.h" +#include "entenc.h" +#include "entdec.h" + +#ifdef CUSTOM_MODES +int log2_frac(opus_uint32 val, int frac); +#endif + +void get_required_bits(opus_int16 *bits, int N, int K, int frac); + +void encode_pulses(const int *_y, int N, int K, ec_enc *enc); + +opus_val32 decode_pulses(int *_y, int N, int K, ec_dec *dec); + +#endif /* CWRS_H */ diff --git a/extern/opus/celt/dump_modes/dump_modes.c b/extern/opus/celt/dump_modes/dump_modes.c new file mode 100644 index 0000000..9105a53 --- /dev/null +++ b/extern/opus/celt/dump_modes/dump_modes.c @@ -0,0 +1,353 @@ +/* Copyright (c) 2008 CSIRO + Copyright (c) 2008-2009 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + 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. + + 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 OWNER + 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. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include "modes.h" +#include "celt.h" +#include "rate.h" +#include "dump_modes_arch.h" + +#define INT16 "%d" +#define INT32 "%d" +#define FLOAT "%#0.8gf" + +#ifdef FIXED_POINT +#define WORD16 INT16 +#define WORD32 INT32 +#else +#define WORD16 FLOAT +#define WORD32 FLOAT +#endif + +void dump_modes(FILE *file, CELTMode **modes, int nb_modes) +{ + int i, j, k; + int mdct_twiddles_size; + fprintf(file, "/* The contents of this file was automatically generated by dump_modes.c\n"); + fprintf(file, " with arguments:"); + for (i=0;iFs,mode->shortMdctSize*mode->nbShortMdcts); + } + fprintf(file, "\n It contains static definitions for some pre-defined modes. */\n"); + fprintf(file, "#include \"modes.h\"\n"); + fprintf(file, "#include \"rate.h\"\n"); + fprintf(file, "\n#ifdef HAVE_ARM_NE10\n"); + fprintf(file, "#define OVERRIDE_FFT 1\n"); + fprintf(file, "#include \"%s\"\n", ARM_NE10_ARCH_FILE_NAME); + fprintf(file, "#endif\n"); + + fprintf(file, "\n"); + + for (i=0;ishortMdctSize*mode->nbShortMdcts; + standard = (mode->Fs == 400*(opus_int32)mode->shortMdctSize); + framerate = mode->Fs/mode->shortMdctSize; + + if (!standard) + { + fprintf(file, "#ifndef DEF_EBANDS%d_%d\n", mode->Fs, mdctSize); + fprintf(file, "#define DEF_EBANDS%d_%d\n", mode->Fs, mdctSize); + fprintf (file, "static const opus_int16 eBands%d_%d[%d] = {\n", mode->Fs, mdctSize, mode->nbEBands+2); + for (j=0;jnbEBands+2;j++) + fprintf (file, "%d, ", mode->eBands[j]); + fprintf (file, "};\n"); + fprintf(file, "#endif\n"); + fprintf(file, "\n"); + } + + fprintf(file, "#ifndef DEF_WINDOW%d\n", mode->overlap); + fprintf(file, "#define DEF_WINDOW%d\n", mode->overlap); + fprintf (file, "static const opus_val16 window%d[%d] = {\n", mode->overlap, mode->overlap); + for (j=0;joverlap;j++) + fprintf (file, WORD16 ",%c", mode->window[j],(j+6)%5==0?'\n':' '); + fprintf (file, "};\n"); + fprintf(file, "#endif\n"); + fprintf(file, "\n"); + + if (!standard) + { + fprintf(file, "#ifndef DEF_ALLOC_VECTORS%d_%d\n", mode->Fs, mdctSize); + fprintf(file, "#define DEF_ALLOC_VECTORS%d_%d\n", mode->Fs, mdctSize); + fprintf (file, "static const unsigned char allocVectors%d_%d[%d] = {\n", mode->Fs, mdctSize, mode->nbEBands*mode->nbAllocVectors); + for (j=0;jnbAllocVectors;j++) + { + for (k=0;knbEBands;k++) + fprintf (file, "%2d, ", mode->allocVectors[j*mode->nbEBands+k]); + fprintf (file, "\n"); + } + fprintf (file, "};\n"); + fprintf(file, "#endif\n"); + fprintf(file, "\n"); + } + + fprintf(file, "#ifndef DEF_LOGN%d\n", framerate); + fprintf(file, "#define DEF_LOGN%d\n", framerate); + fprintf (file, "static const opus_int16 logN%d[%d] = {\n", framerate, mode->nbEBands); + for (j=0;jnbEBands;j++) + fprintf (file, "%d, ", mode->logN[j]); + fprintf (file, "};\n"); + fprintf(file, "#endif\n"); + fprintf(file, "\n"); + + /* Pulse cache */ + fprintf(file, "#ifndef DEF_PULSE_CACHE%d\n", mode->Fs/mdctSize); + fprintf(file, "#define DEF_PULSE_CACHE%d\n", mode->Fs/mdctSize); + fprintf (file, "static const opus_int16 cache_index%d[%d] = {\n", mode->Fs/mdctSize, (mode->maxLM+2)*mode->nbEBands); + for (j=0;jnbEBands*(mode->maxLM+2);j++) + fprintf (file, "%d,%c", mode->cache.index[j],(j+16)%15==0?'\n':' '); + fprintf (file, "};\n"); + fprintf (file, "static const unsigned char cache_bits%d[%d] = {\n", mode->Fs/mdctSize, mode->cache.size); + for (j=0;jcache.size;j++) + fprintf (file, "%d,%c", mode->cache.bits[j],(j+16)%15==0?'\n':' '); + fprintf (file, "};\n"); + fprintf (file, "static const unsigned char cache_caps%d[%d] = {\n", mode->Fs/mdctSize, (mode->maxLM+1)*2*mode->nbEBands); + for (j=0;j<(mode->maxLM+1)*2*mode->nbEBands;j++) + fprintf (file, "%d,%c", mode->cache.caps[j],(j+16)%15==0?'\n':' '); + fprintf (file, "};\n"); + + fprintf(file, "#endif\n"); + fprintf(file, "\n"); + + /* FFT twiddles */ + fprintf(file, "#ifndef FFT_TWIDDLES%d_%d\n", mode->Fs, mdctSize); + fprintf(file, "#define FFT_TWIDDLES%d_%d\n", mode->Fs, mdctSize); + fprintf (file, "static const kiss_twiddle_cpx fft_twiddles%d_%d[%d] = {\n", + mode->Fs, mdctSize, mode->mdct.kfft[0]->nfft); + for (j=0;jmdct.kfft[0]->nfft;j++) + fprintf (file, "{" WORD16 ", " WORD16 "},%c", mode->mdct.kfft[0]->twiddles[j].r, mode->mdct.kfft[0]->twiddles[j].i,(j+3)%2==0?'\n':' '); + fprintf (file, "};\n"); + +#ifdef OVERRIDE_FFT + dump_mode_arch(mode); +#endif + /* FFT Bitrev tables */ + for (k=0;k<=mode->mdct.maxshift;k++) + { + fprintf(file, "#ifndef FFT_BITREV%d\n", mode->mdct.kfft[k]->nfft); + fprintf(file, "#define FFT_BITREV%d\n", mode->mdct.kfft[k]->nfft); + fprintf (file, "static const opus_int16 fft_bitrev%d[%d] = {\n", + mode->mdct.kfft[k]->nfft, mode->mdct.kfft[k]->nfft); + for (j=0;jmdct.kfft[k]->nfft;j++) + fprintf (file, "%d,%c", mode->mdct.kfft[k]->bitrev[j],(j+16)%15==0?'\n':' '); + fprintf (file, "};\n"); + + fprintf(file, "#endif\n"); + fprintf(file, "\n"); + } + + /* FFT States */ + for (k=0;k<=mode->mdct.maxshift;k++) + { + fprintf(file, "#ifndef FFT_STATE%d_%d_%d\n", mode->Fs, mdctSize, k); + fprintf(file, "#define FFT_STATE%d_%d_%d\n", mode->Fs, mdctSize, k); + fprintf (file, "static const kiss_fft_state fft_state%d_%d_%d = {\n", + mode->Fs, mdctSize, k); + fprintf (file, "%d, /* nfft */\n", mode->mdct.kfft[k]->nfft); + fprintf (file, WORD16 ", /* scale */\n", mode->mdct.kfft[k]->scale); +#ifdef FIXED_POINT + fprintf (file, "%d, /* scale_shift */\n", mode->mdct.kfft[k]->scale_shift); +#endif + fprintf (file, "%d, /* shift */\n", mode->mdct.kfft[k]->shift); + fprintf (file, "{"); + for (j=0;j<2*MAXFACTORS;j++) + fprintf (file, "%d, ", mode->mdct.kfft[k]->factors[j]); + fprintf (file, "}, /* factors */\n"); + fprintf (file, "fft_bitrev%d, /* bitrev */\n", mode->mdct.kfft[k]->nfft); + fprintf (file, "fft_twiddles%d_%d, /* bitrev */\n", mode->Fs, mdctSize); + + fprintf (file, "#ifdef OVERRIDE_FFT\n"); + fprintf (file, "(arch_fft_state *)&cfg_arch_%d,\n", mode->mdct.kfft[k]->nfft); + fprintf (file, "#else\n"); + fprintf (file, "NULL,\n"); + fprintf(file, "#endif\n"); + + fprintf (file, "};\n"); + + fprintf(file, "#endif\n"); + fprintf(file, "\n"); + } + + fprintf(file, "#endif\n"); + fprintf(file, "\n"); + + /* MDCT twiddles */ + mdct_twiddles_size = mode->mdct.n-(mode->mdct.n/2>>mode->mdct.maxshift); + fprintf(file, "#ifndef MDCT_TWIDDLES%d\n", mdctSize); + fprintf(file, "#define MDCT_TWIDDLES%d\n", mdctSize); + fprintf (file, "static const opus_val16 mdct_twiddles%d[%d] = {\n", + mdctSize, mdct_twiddles_size); + for (j=0;jmdct.trig[j],(j+6)%5==0?'\n':' '); + fprintf (file, "};\n"); + + fprintf(file, "#endif\n"); + fprintf(file, "\n"); + + + /* Print the actual mode data */ + fprintf(file, "static const CELTMode mode%d_%d_%d = {\n", mode->Fs, mdctSize, mode->overlap); + fprintf(file, INT32 ", /* Fs */\n", mode->Fs); + fprintf(file, "%d, /* overlap */\n", mode->overlap); + fprintf(file, "%d, /* nbEBands */\n", mode->nbEBands); + fprintf(file, "%d, /* effEBands */\n", mode->effEBands); + fprintf(file, "{"); + for (j=0;j<4;j++) + fprintf(file, WORD16 ", ", mode->preemph[j]); + fprintf(file, "}, /* preemph */\n"); + if (standard) + fprintf(file, "eband5ms, /* eBands */\n"); + else + fprintf(file, "eBands%d_%d, /* eBands */\n", mode->Fs, mdctSize); + + fprintf(file, "%d, /* maxLM */\n", mode->maxLM); + fprintf(file, "%d, /* nbShortMdcts */\n", mode->nbShortMdcts); + fprintf(file, "%d, /* shortMdctSize */\n", mode->shortMdctSize); + + fprintf(file, "%d, /* nbAllocVectors */\n", mode->nbAllocVectors); + if (standard) + fprintf(file, "band_allocation, /* allocVectors */\n"); + else + fprintf(file, "allocVectors%d_%d, /* allocVectors */\n", mode->Fs, mdctSize); + + fprintf(file, "logN%d, /* logN */\n", framerate); + fprintf(file, "window%d, /* window */\n", mode->overlap); + fprintf(file, "{%d, %d, {", mode->mdct.n, mode->mdct.maxshift); + for (k=0;k<=mode->mdct.maxshift;k++) + fprintf(file, "&fft_state%d_%d_%d, ", mode->Fs, mdctSize, k); + fprintf (file, "}, mdct_twiddles%d}, /* mdct */\n", mdctSize); + + fprintf(file, "{%d, cache_index%d, cache_bits%d, cache_caps%d}, /* cache */\n", + mode->cache.size, mode->Fs/mdctSize, mode->Fs/mdctSize, mode->Fs/mdctSize); + fprintf(file, "};\n"); + } + fprintf(file, "\n"); + fprintf(file, "/* List of all the available modes */\n"); + fprintf(file, "#define TOTAL_MODES %d\n", nb_modes); + fprintf(file, "static const CELTMode * const static_mode_list[TOTAL_MODES] = {\n"); + for (i=0;ishortMdctSize*mode->nbShortMdcts; + fprintf(file, "&mode%d_%d_%d,\n", mode->Fs, mdctSize, mode->overlap); + } + fprintf(file, "};\n"); +} + +void dump_header(FILE *file, CELTMode **modes, int nb_modes) +{ + int i; + int channels = 0; + int frame_size = 0; + int overlap = 0; + fprintf (file, "/* This header file is generated automatically*/\n"); + for (i=0;ishortMdctSize*mode->nbShortMdcts; + else if (frame_size != mode->shortMdctSize*mode->nbShortMdcts) + frame_size = -1; + if (overlap==0) + overlap = mode->overlap; + else if (overlap != mode->overlap) + overlap = -1; + } + if (channels>0) + { + fprintf (file, "#define CHANNELS(mode) %d\n", channels); + if (channels==1) + fprintf (file, "#define DISABLE_STEREO\n"); + } + if (frame_size>0) + { + fprintf (file, "#define FRAMESIZE(mode) %d\n", frame_size); + } + if (overlap>0) + { + fprintf (file, "#define OVERLAP(mode) %d\n", overlap); + } +} + +#ifdef FIXED_POINT +#define BASENAME "static_modes_fixed" +#else +#define BASENAME "static_modes_float" +#endif + +int main(int argc, char **argv) +{ + int i, nb; + FILE *file; + CELTMode **m; + if (argc%2 != 1 || argc<3) + { + fprintf (stderr, "Usage: %s rate frame_size [rate frame_size] [rate frame_size]...\n",argv[0]); + return 1; + } + nb = (argc-1)/2; + m = malloc(nb*sizeof(CELTMode*)); + for (i=0;i +#include +#include "modes.h" +#include "dump_modes_arch.h" +#include + +#if !defined(FIXED_POINT) +# define NE10_FFT_CFG_TYPE_T ne10_fft_cfg_float32_t +# define NE10_FFT_CPX_TYPE_T_STR "ne10_fft_cpx_float32_t" +# define NE10_FFT_STATE_TYPE_T_STR "ne10_fft_state_float32_t" +#else +# define NE10_FFT_CFG_TYPE_T ne10_fft_cfg_int32_t +# define NE10_FFT_CPX_TYPE_T_STR "ne10_fft_cpx_int32_t" +# define NE10_FFT_STATE_TYPE_T_STR "ne10_fft_state_int32_t" +#endif + +static FILE *file; + +void dump_modes_arch_init(CELTMode **modes, int nb_modes) +{ + int i; + + file = fopen(ARM_NE10_ARCH_FILE_NAME, "w"); + fprintf(file, "/* The contents of this file was automatically generated by\n"); + fprintf(file, " * dump_mode_arm_ne10.c with arguments:"); + for (i=0;iFs,mode->shortMdctSize*mode->nbShortMdcts); + } + fprintf(file, "\n * It contains static definitions for some pre-defined modes. */\n"); + fprintf(file, "#include \n\n"); +} + +void dump_modes_arch_finalize() +{ + fclose(file); +} + +void dump_mode_arch(CELTMode *mode) +{ + int k, j; + int mdctSize; + + mdctSize = mode->shortMdctSize*mode->nbShortMdcts; + + fprintf(file, "#ifndef NE10_FFT_PARAMS%d_%d\n", mode->Fs, mdctSize); + fprintf(file, "#define NE10_FFT_PARAMS%d_%d\n", mode->Fs, mdctSize); + /* cfg->factors */ + for(k=0;k<=mode->mdct.maxshift;k++) { + NE10_FFT_CFG_TYPE_T cfg; + cfg = (NE10_FFT_CFG_TYPE_T)mode->mdct.kfft[k]->arch_fft->priv; + if (!cfg) + continue; + fprintf(file, "static const ne10_int32_t ne10_factors_%d[%d] = {\n", + mode->mdct.kfft[k]->nfft, (NE10_MAXFACTORS * 2)); + for(j=0;j<(NE10_MAXFACTORS * 2);j++) { + fprintf(file, "%d,%c", cfg->factors[j],(j+16)%15==0?'\n':' '); + } + fprintf (file, "};\n"); + } + + /* cfg->twiddles */ + for(k=0;k<=mode->mdct.maxshift;k++) { + NE10_FFT_CFG_TYPE_T cfg; + cfg = (NE10_FFT_CFG_TYPE_T)mode->mdct.kfft[k]->arch_fft->priv; + if (!cfg) + continue; + fprintf(file, "static const %s ne10_twiddles_%d[%d] = {\n", + NE10_FFT_CPX_TYPE_T_STR, mode->mdct.kfft[k]->nfft, + mode->mdct.kfft[k]->nfft); + for(j=0;jmdct.kfft[k]->nfft;j++) { +#if !defined(FIXED_POINT) + fprintf(file, "{%#0.8gf,%#0.8gf},%c", + cfg->twiddles[j].r, cfg->twiddles[j].i,(j+4)%3==0?'\n':' '); +#else + fprintf(file, "{%d,%d},%c", + cfg->twiddles[j].r, cfg->twiddles[j].i,(j+4)%3==0?'\n':' '); +#endif + } + fprintf (file, "};\n"); + } + + for(k=0;k<=mode->mdct.maxshift;k++) { + NE10_FFT_CFG_TYPE_T cfg; + cfg = (NE10_FFT_CFG_TYPE_T)mode->mdct.kfft[k]->arch_fft->priv; + if (!cfg) { + fprintf(file, "/* Ne10 does not support scaled FFT for length = %d */\n", + mode->mdct.kfft[k]->nfft); + fprintf(file, "static const arch_fft_state cfg_arch_%d = {\n", mode->mdct.kfft[k]->nfft); + fprintf(file, "0,\n"); + fprintf(file, "NULL\n"); + fprintf(file, "};\n"); + continue; + } + fprintf(file, "static const %s %s_%d = {\n", NE10_FFT_STATE_TYPE_T_STR, + NE10_FFT_STATE_TYPE_T_STR, mode->mdct.kfft[k]->nfft); + fprintf(file, "%d,\n", cfg->nfft); + fprintf(file, "(ne10_int32_t *)ne10_factors_%d,\n", mode->mdct.kfft[k]->nfft); + fprintf(file, "(%s *)ne10_twiddles_%d,\n", + NE10_FFT_CPX_TYPE_T_STR, mode->mdct.kfft[k]->nfft); + fprintf(file, "NULL,\n"); /* buffer */ + fprintf(file, "(%s *)&ne10_twiddles_%d[%d],\n", + NE10_FFT_CPX_TYPE_T_STR, mode->mdct.kfft[k]->nfft, cfg->nfft); +#if !defined(FIXED_POINT) + fprintf(file, "/* is_forward_scaled = true */\n"); + fprintf(file, "(ne10_int32_t) 1,\n"); + fprintf(file, "/* is_backward_scaled = false */\n"); + fprintf(file, "(ne10_int32_t) 0,\n"); +#endif + fprintf(file, "};\n"); + + fprintf(file, "static const arch_fft_state cfg_arch_%d = {\n", + mode->mdct.kfft[k]->nfft); + fprintf(file, "1,\n"); + fprintf(file, "(void *)&%s_%d,\n", + NE10_FFT_STATE_TYPE_T_STR, mode->mdct.kfft[k]->nfft); + fprintf(file, "};\n\n"); + } + fprintf(file, "#endif /* end NE10_FFT_PARAMS%d_%d */\n", mode->Fs, mdctSize); +} diff --git a/extern/opus/celt/ecintrin.h b/extern/opus/celt/ecintrin.h new file mode 100644 index 0000000..2263cff --- /dev/null +++ b/extern/opus/celt/ecintrin.h @@ -0,0 +1,87 @@ +/* Copyright (c) 2003-2008 Timothy B. Terriberry + Copyright (c) 2008 Xiph.Org Foundation */ +/* + 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. + + 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 OWNER + 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. +*/ + +/*Some common macros for potential platform-specific optimization.*/ +#include "opus_types.h" +#include +#include +#include "arch.h" +#if !defined(_ecintrin_H) +# define _ecintrin_H (1) + +/*Some specific platforms may have optimized intrinsic or OPUS_INLINE assembly + versions of these functions which can substantially improve performance. + We define macros for them to allow easy incorporation of these non-ANSI + features.*/ + +/*Modern gcc (4.x) can compile the naive versions of min and max with cmov if + given an appropriate architecture, but the branchless bit-twiddling versions + are just as fast, and do not require any special target architecture. + Earlier gcc versions (3.x) compiled both code to the same assembly + instructions, because of the way they represented ((_b)>(_a)) internally.*/ +# define EC_MINI(_a,_b) ((_a)+(((_b)-(_a))&-((_b)<(_a)))) + +/*Count leading zeros. + This macro should only be used for implementing ec_ilog(), if it is defined. + All other code should use EC_ILOG() instead.*/ +#if defined(_MSC_VER) && (_MSC_VER >= 1400) +# include +/*In _DEBUG mode this is not an intrinsic by default.*/ +# pragma intrinsic(_BitScanReverse) + +static __inline int ec_bsr(unsigned long _x){ + unsigned long ret; + _BitScanReverse(&ret,_x); + return (int)ret; +} +# define EC_CLZ0 (1) +# define EC_CLZ(_x) (-ec_bsr(_x)) +#elif defined(ENABLE_TI_DSPLIB) +# include "dsplib.h" +# define EC_CLZ0 (31) +# define EC_CLZ(_x) (_lnorm(_x)) +#elif __GNUC_PREREQ(3,4) +# if INT_MAX>=2147483647 +# define EC_CLZ0 ((int)sizeof(unsigned)*CHAR_BIT) +# define EC_CLZ(_x) (__builtin_clz(_x)) +# elif LONG_MAX>=2147483647L +# define EC_CLZ0 ((int)sizeof(unsigned long)*CHAR_BIT) +# define EC_CLZ(_x) (__builtin_clzl(_x)) +# endif +#endif + +#if defined(EC_CLZ) +/*Note that __builtin_clz is not defined when _x==0, according to the gcc + documentation (and that of the BSR instruction that implements it on x86). + The majority of the time we can never pass it zero. + When we need to, it can be special cased.*/ +# define EC_ILOG(_x) (EC_CLZ0-EC_CLZ(_x)) +#else +int ec_ilog(opus_uint32 _v); +# define EC_ILOG(_x) (ec_ilog(_x)) +#endif +#endif diff --git a/extern/opus/celt/entcode.c b/extern/opus/celt/entcode.c new file mode 100644 index 0000000..70f3201 --- /dev/null +++ b/extern/opus/celt/entcode.c @@ -0,0 +1,153 @@ +/* Copyright (c) 2001-2011 Timothy B. Terriberry +*/ +/* + 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. + + 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 OWNER + 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. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "entcode.h" +#include "arch.h" + +#if !defined(EC_CLZ) +/*This is a fallback for systems where we don't know how to access + a BSR or CLZ instruction (see ecintrin.h). + If you are optimizing Opus on a new platform and it has a native CLZ or + BZR (e.g. cell, MIPS, x86, etc) then making it available to Opus will be + an easy performance win.*/ +int ec_ilog(opus_uint32 _v){ + /*On a Pentium M, this branchless version tested as the fastest on + 1,000,000,000 random 32-bit integers, edging out a similar version with + branches, and a 256-entry LUT version.*/ + int ret; + int m; + ret=!!_v; + m=!!(_v&0xFFFF0000)<<4; + _v>>=m; + ret|=m; + m=!!(_v&0xFF00)<<3; + _v>>=m; + ret|=m; + m=!!(_v&0xF0)<<2; + _v>>=m; + ret|=m; + m=!!(_v&0xC)<<1; + _v>>=m; + ret|=m; + ret+=!!(_v&0x2); + return ret; +} +#endif + +#if 1 +/* This is a faster version of ec_tell_frac() that takes advantage + of the low (1/8 bit) resolution to use just a linear function + followed by a lookup to determine the exact transition thresholds. */ +opus_uint32 ec_tell_frac(ec_ctx *_this){ + static const unsigned correction[8] = + {35733, 38967, 42495, 46340, + 50535, 55109, 60097, 65535}; + opus_uint32 nbits; + opus_uint32 r; + int l; + unsigned b; + nbits=_this->nbits_total<rng); + r=_this->rng>>(l-16); + b = (r>>12)-8; + b += r>correction[b]; + l = (l<<3)+b; + return nbits-l; +} +#else +opus_uint32 ec_tell_frac(ec_ctx *_this){ + opus_uint32 nbits; + opus_uint32 r; + int l; + int i; + /*To handle the non-integral number of bits still left in the encoder/decoder + state, we compute the worst-case number of bits of val that must be + encoded to ensure that the value is inside the range for any possible + subsequent bits. + The computation here is independent of val itself (the decoder does not + even track that value), even though the real number of bits used after + ec_enc_done() may be 1 smaller if rng is a power of two and the + corresponding trailing bits of val are all zeros. + If we did try to track that special case, then coding a value with a + probability of 1/(1<nbits_total<rng); + r=_this->rng>>(l-16); + for(i=BITRES;i-->0;){ + int b; + r=r*r>>15; + b=(int)(r>>16); + l=l<<1|b; + r>>=b; + } + return nbits-l; +} +#endif + +#ifdef USE_SMALL_DIV_TABLE +/* Result of 2^32/(2*i+1), except for i=0. */ +const opus_uint32 SMALL_DIV_TABLE[129] = { + 0xFFFFFFFF, 0x55555555, 0x33333333, 0x24924924, + 0x1C71C71C, 0x1745D174, 0x13B13B13, 0x11111111, + 0x0F0F0F0F, 0x0D79435E, 0x0C30C30C, 0x0B21642C, + 0x0A3D70A3, 0x097B425E, 0x08D3DCB0, 0x08421084, + 0x07C1F07C, 0x07507507, 0x06EB3E45, 0x06906906, + 0x063E7063, 0x05F417D0, 0x05B05B05, 0x0572620A, + 0x05397829, 0x05050505, 0x04D4873E, 0x04A7904A, + 0x047DC11F, 0x0456C797, 0x04325C53, 0x04104104, + 0x03F03F03, 0x03D22635, 0x03B5CC0E, 0x039B0AD1, + 0x0381C0E0, 0x0369D036, 0x03531DEC, 0x033D91D2, + 0x0329161F, 0x03159721, 0x03030303, 0x02F14990, + 0x02E05C0B, 0x02D02D02, 0x02C0B02C, 0x02B1DA46, + 0x02A3A0FD, 0x0295FAD4, 0x0288DF0C, 0x027C4597, + 0x02702702, 0x02647C69, 0x02593F69, 0x024E6A17, + 0x0243F6F0, 0x0239E0D5, 0x02302302, 0x0226B902, + 0x021D9EAD, 0x0214D021, 0x020C49BA, 0x02040810, + 0x01FC07F0, 0x01F44659, 0x01ECC07B, 0x01E573AC, + 0x01DE5D6E, 0x01D77B65, 0x01D0CB58, 0x01CA4B30, + 0x01C3F8F0, 0x01BDD2B8, 0x01B7D6C3, 0x01B20364, + 0x01AC5701, 0x01A6D01A, 0x01A16D3F, 0x019C2D14, + 0x01970E4F, 0x01920FB4, 0x018D3018, 0x01886E5F, + 0x0183C977, 0x017F405F, 0x017AD220, 0x01767DCE, + 0x01724287, 0x016E1F76, 0x016A13CD, 0x01661EC6, + 0x01623FA7, 0x015E75BB, 0x015AC056, 0x01571ED3, + 0x01539094, 0x01501501, 0x014CAB88, 0x0149539E, + 0x01460CBC, 0x0142D662, 0x013FB013, 0x013C995A, + 0x013991C2, 0x013698DF, 0x0133AE45, 0x0130D190, + 0x012E025C, 0x012B404A, 0x01288B01, 0x0125E227, + 0x01234567, 0x0120B470, 0x011E2EF3, 0x011BB4A4, + 0x01194538, 0x0116E068, 0x011485F0, 0x0112358E, + 0x010FEF01, 0x010DB20A, 0x010B7E6E, 0x010953F3, + 0x01073260, 0x0105197F, 0x0103091B, 0x01010101 +}; +#endif diff --git a/extern/opus/celt/entcode.h b/extern/opus/celt/entcode.h new file mode 100644 index 0000000..3763e3f --- /dev/null +++ b/extern/opus/celt/entcode.h @@ -0,0 +1,152 @@ +/* Copyright (c) 2001-2011 Timothy B. Terriberry + Copyright (c) 2008-2009 Xiph.Org Foundation */ +/* + 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. + + 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 OWNER + 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. +*/ + +#include "opus_types.h" +#include "opus_defines.h" + +#if !defined(_entcode_H) +# define _entcode_H (1) +# include +# include +# include "ecintrin.h" + +extern const opus_uint32 SMALL_DIV_TABLE[129]; + +#ifdef OPUS_ARM_ASM +#define USE_SMALL_DIV_TABLE +#endif + +/*OPT: ec_window must be at least 32 bits, but if you have fast arithmetic on a + larger type, you can speed up the decoder by using it here.*/ +typedef opus_uint32 ec_window; +typedef struct ec_ctx ec_ctx; +typedef struct ec_ctx ec_enc; +typedef struct ec_ctx ec_dec; + +# define EC_WINDOW_SIZE ((int)sizeof(ec_window)*CHAR_BIT) + +/*The number of bits to use for the range-coded part of unsigned integers.*/ +# define EC_UINT_BITS (8) + +/*The resolution of fractional-precision bit usage measurements, i.e., + 3 => 1/8th bits.*/ +# define BITRES 3 + +/*The entropy encoder/decoder context. + We use the same structure for both, so that common functions like ec_tell() + can be used on either one.*/ +struct ec_ctx{ + /*Buffered input/output.*/ + unsigned char *buf; + /*The size of the buffer.*/ + opus_uint32 storage; + /*The offset at which the last byte containing raw bits was read/written.*/ + opus_uint32 end_offs; + /*Bits that will be read from/written at the end.*/ + ec_window end_window; + /*Number of valid bits in end_window.*/ + int nend_bits; + /*The total number of whole bits read/written. + This does not include partial bits currently in the range coder.*/ + int nbits_total; + /*The offset at which the next range coder byte will be read/written.*/ + opus_uint32 offs; + /*The number of values in the current range.*/ + opus_uint32 rng; + /*In the decoder: the difference between the top of the current range and + the input value, minus one. + In the encoder: the low end of the current range.*/ + opus_uint32 val; + /*In the decoder: the saved normalization factor from ec_decode(). + In the encoder: the number of oustanding carry propagating symbols.*/ + opus_uint32 ext; + /*A buffered input/output symbol, awaiting carry propagation.*/ + int rem; + /*Nonzero if an error occurred.*/ + int error; +}; + +static OPUS_INLINE opus_uint32 ec_range_bytes(ec_ctx *_this){ + return _this->offs; +} + +static OPUS_INLINE unsigned char *ec_get_buffer(ec_ctx *_this){ + return _this->buf; +} + +static OPUS_INLINE int ec_get_error(ec_ctx *_this){ + return _this->error; +} + +/*Returns the number of bits "used" by the encoded or decoded symbols so far. + This same number can be computed in either the encoder or the decoder, and is + suitable for making coding decisions. + Return: The number of bits. + This will always be slightly larger than the exact value (e.g., all + rounding error is in the positive direction).*/ +static OPUS_INLINE int ec_tell(ec_ctx *_this){ + return _this->nbits_total-EC_ILOG(_this->rng); +} + +/*Returns the number of bits "used" by the encoded or decoded symbols so far. + This same number can be computed in either the encoder or the decoder, and is + suitable for making coding decisions. + Return: The number of bits scaled by 2**BITRES. + This will always be slightly larger than the exact value (e.g., all + rounding error is in the positive direction).*/ +opus_uint32 ec_tell_frac(ec_ctx *_this); + +/* Tested exhaustively for all n and for 1<=d<=256 */ +static OPUS_INLINE opus_uint32 celt_udiv(opus_uint32 n, opus_uint32 d) { + celt_sig_assert(d>0); +#ifdef USE_SMALL_DIV_TABLE + if (d>256) + return n/d; + else { + opus_uint32 t, q; + t = EC_ILOG(d&-d); + q = (opus_uint64)SMALL_DIV_TABLE[d>>t]*(n>>(t-1))>>32; + return q+(n-q*d >= d); + } +#else + return n/d; +#endif +} + +static OPUS_INLINE opus_int32 celt_sudiv(opus_int32 n, opus_int32 d) { + celt_sig_assert(d>0); +#ifdef USE_SMALL_DIV_TABLE + if (n<0) + return -(opus_int32)celt_udiv(-n, d); + else + return celt_udiv(n, d); +#else + return n/d; +#endif +} + +#endif diff --git a/extern/opus/celt/entdec.c b/extern/opus/celt/entdec.c new file mode 100644 index 0000000..0b3433e --- /dev/null +++ b/extern/opus/celt/entdec.c @@ -0,0 +1,245 @@ +/* Copyright (c) 2001-2011 Timothy B. Terriberry + Copyright (c) 2008-2009 Xiph.Org Foundation */ +/* + 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. + + 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 OWNER + 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. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "os_support.h" +#include "arch.h" +#include "entdec.h" +#include "mfrngcod.h" + +/*A range decoder. + This is an entropy decoder based upon \cite{Mar79}, which is itself a + rediscovery of the FIFO arithmetic code introduced by \cite{Pas76}. + It is very similar to arithmetic encoding, except that encoding is done with + digits in any base, instead of with bits, and so it is faster when using + larger bases (i.e.: a byte). + The author claims an average waste of $\frac{1}{2}\log_b(2b)$ bits, where $b$ + is the base, longer than the theoretical optimum, but to my knowledge there + is no published justification for this claim. + This only seems true when using near-infinite precision arithmetic so that + the process is carried out with no rounding errors. + + An excellent description of implementation details is available at + http://www.arturocampos.com/ac_range.html + A recent work \cite{MNW98} which proposes several changes to arithmetic + encoding for efficiency actually re-discovers many of the principles + behind range encoding, and presents a good theoretical analysis of them. + + End of stream is handled by writing out the smallest number of bits that + ensures that the stream will be correctly decoded regardless of the value of + any subsequent bits. + ec_tell() can be used to determine how many bits were needed to decode + all the symbols thus far; other data can be packed in the remaining bits of + the input buffer. + @PHDTHESIS{Pas76, + author="Richard Clark Pasco", + title="Source coding algorithms for fast data compression", + school="Dept. of Electrical Engineering, Stanford University", + address="Stanford, CA", + month=May, + year=1976 + } + @INPROCEEDINGS{Mar79, + author="Martin, G.N.N.", + title="Range encoding: an algorithm for removing redundancy from a digitised + message", + booktitle="Video & Data Recording Conference", + year=1979, + address="Southampton", + month=Jul + } + @ARTICLE{MNW98, + author="Alistair Moffat and Radford Neal and Ian H. Witten", + title="Arithmetic Coding Revisited", + journal="{ACM} Transactions on Information Systems", + year=1998, + volume=16, + number=3, + pages="256--294", + month=Jul, + URL="http://www.stanford.edu/class/ee398a/handouts/papers/Moffat98ArithmCoding.pdf" + }*/ + +static int ec_read_byte(ec_dec *_this){ + return _this->offs<_this->storage?_this->buf[_this->offs++]:0; +} + +static int ec_read_byte_from_end(ec_dec *_this){ + return _this->end_offs<_this->storage? + _this->buf[_this->storage-++(_this->end_offs)]:0; +} + +/*Normalizes the contents of val and rng so that rng lies entirely in the + high-order symbol.*/ +static void ec_dec_normalize(ec_dec *_this){ + /*If the range is too small, rescale it and input some bits.*/ + while(_this->rng<=EC_CODE_BOT){ + int sym; + _this->nbits_total+=EC_SYM_BITS; + _this->rng<<=EC_SYM_BITS; + /*Use up the remaining bits from our last symbol.*/ + sym=_this->rem; + /*Read the next value from the input.*/ + _this->rem=ec_read_byte(_this); + /*Take the rest of the bits we need from this new symbol.*/ + sym=(sym<rem)>>(EC_SYM_BITS-EC_CODE_EXTRA); + /*And subtract them from val, capped to be less than EC_CODE_TOP.*/ + _this->val=((_this->val<buf=_buf; + _this->storage=_storage; + _this->end_offs=0; + _this->end_window=0; + _this->nend_bits=0; + /*This is the offset from which ec_tell() will subtract partial bits. + The final value after the ec_dec_normalize() call will be the same as in + the encoder, but we have to compensate for the bits that are added there.*/ + _this->nbits_total=EC_CODE_BITS+1 + -((EC_CODE_BITS-EC_CODE_EXTRA)/EC_SYM_BITS)*EC_SYM_BITS; + _this->offs=0; + _this->rng=1U<rem=ec_read_byte(_this); + _this->val=_this->rng-1-(_this->rem>>(EC_SYM_BITS-EC_CODE_EXTRA)); + _this->error=0; + /*Normalize the interval.*/ + ec_dec_normalize(_this); +} + +unsigned ec_decode(ec_dec *_this,unsigned _ft){ + unsigned s; + _this->ext=celt_udiv(_this->rng,_ft); + s=(unsigned)(_this->val/_this->ext); + return _ft-EC_MINI(s+1,_ft); +} + +unsigned ec_decode_bin(ec_dec *_this,unsigned _bits){ + unsigned s; + _this->ext=_this->rng>>_bits; + s=(unsigned)(_this->val/_this->ext); + return (1U<<_bits)-EC_MINI(s+1U,1U<<_bits); +} + +void ec_dec_update(ec_dec *_this,unsigned _fl,unsigned _fh,unsigned _ft){ + opus_uint32 s; + s=IMUL32(_this->ext,_ft-_fh); + _this->val-=s; + _this->rng=_fl>0?IMUL32(_this->ext,_fh-_fl):_this->rng-s; + ec_dec_normalize(_this); +} + +/*The probability of having a "one" is 1/(1<<_logp).*/ +int ec_dec_bit_logp(ec_dec *_this,unsigned _logp){ + opus_uint32 r; + opus_uint32 d; + opus_uint32 s; + int ret; + r=_this->rng; + d=_this->val; + s=r>>_logp; + ret=dval=d-s; + _this->rng=ret?s:r-s; + ec_dec_normalize(_this); + return ret; +} + +int ec_dec_icdf(ec_dec *_this,const unsigned char *_icdf,unsigned _ftb){ + opus_uint32 r; + opus_uint32 d; + opus_uint32 s; + opus_uint32 t; + int ret; + s=_this->rng; + d=_this->val; + r=s>>_ftb; + ret=-1; + do{ + t=s; + s=IMUL32(r,_icdf[++ret]); + } + while(dval=d-s; + _this->rng=t-s; + ec_dec_normalize(_this); + return ret; +} + +opus_uint32 ec_dec_uint(ec_dec *_this,opus_uint32 _ft){ + unsigned ft; + unsigned s; + int ftb; + /*In order to optimize EC_ILOG(), it is undefined for the value 0.*/ + celt_assert(_ft>1); + _ft--; + ftb=EC_ILOG(_ft); + if(ftb>EC_UINT_BITS){ + opus_uint32 t; + ftb-=EC_UINT_BITS; + ft=(unsigned)(_ft>>ftb)+1; + s=ec_decode(_this,ft); + ec_dec_update(_this,s,s+1,ft); + t=(opus_uint32)s<error=1; + return _ft; + } + else{ + _ft++; + s=ec_decode(_this,(unsigned)_ft); + ec_dec_update(_this,s,s+1,(unsigned)_ft); + return s; + } +} + +opus_uint32 ec_dec_bits(ec_dec *_this,unsigned _bits){ + ec_window window; + int available; + opus_uint32 ret; + window=_this->end_window; + available=_this->nend_bits; + if((unsigned)available<_bits){ + do{ + window|=(ec_window)ec_read_byte_from_end(_this)<>=_bits; + available-=_bits; + _this->end_window=window; + _this->nend_bits=available; + _this->nbits_total+=_bits; + return ret; +} diff --git a/extern/opus/celt/entdec.h b/extern/opus/celt/entdec.h new file mode 100644 index 0000000..025fc18 --- /dev/null +++ b/extern/opus/celt/entdec.h @@ -0,0 +1,100 @@ +/* Copyright (c) 2001-2011 Timothy B. Terriberry + Copyright (c) 2008-2009 Xiph.Org Foundation */ +/* + 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. + + 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 OWNER + 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. +*/ + +#if !defined(_entdec_H) +# define _entdec_H (1) +# include +# include "entcode.h" + +/*Initializes the decoder. + _buf: The input buffer to use. + Return: 0 on success, or a negative value on error.*/ +void ec_dec_init(ec_dec *_this,unsigned char *_buf,opus_uint32 _storage); + +/*Calculates the cumulative frequency for the next symbol. + This can then be fed into the probability model to determine what that + symbol is, and the additional frequency information required to advance to + the next symbol. + This function cannot be called more than once without a corresponding call to + ec_dec_update(), or decoding will not proceed correctly. + _ft: The total frequency of the symbols in the alphabet the next symbol was + encoded with. + Return: A cumulative frequency representing the encoded symbol. + If the cumulative frequency of all the symbols before the one that + was encoded was fl, and the cumulative frequency of all the symbols + up to and including the one encoded is fh, then the returned value + will fall in the range [fl,fh).*/ +unsigned ec_decode(ec_dec *_this,unsigned _ft); + +/*Equivalent to ec_decode() with _ft==1<<_bits.*/ +unsigned ec_decode_bin(ec_dec *_this,unsigned _bits); + +/*Advance the decoder past the next symbol using the frequency information the + symbol was encoded with. + Exactly one call to ec_decode() must have been made so that all necessary + intermediate calculations are performed. + _fl: The cumulative frequency of all symbols that come before the symbol + decoded. + _fh: The cumulative frequency of all symbols up to and including the symbol + decoded. + Together with _fl, this defines the range [_fl,_fh) in which the value + returned above must fall. + _ft: The total frequency of the symbols in the alphabet the symbol decoded + was encoded in. + This must be the same as passed to the preceding call to ec_decode().*/ +void ec_dec_update(ec_dec *_this,unsigned _fl,unsigned _fh,unsigned _ft); + +/* Decode a bit that has a 1/(1<<_logp) probability of being a one */ +int ec_dec_bit_logp(ec_dec *_this,unsigned _logp); + +/*Decodes a symbol given an "inverse" CDF table. + No call to ec_dec_update() is necessary after this call. + _icdf: The "inverse" CDF, such that symbol s falls in the range + [s>0?ft-_icdf[s-1]:0,ft-_icdf[s]), where ft=1<<_ftb. + The values must be monotonically non-increasing, and the last value + must be 0. + _ftb: The number of bits of precision in the cumulative distribution. + Return: The decoded symbol s.*/ +int ec_dec_icdf(ec_dec *_this,const unsigned char *_icdf,unsigned _ftb); + +/*Extracts a raw unsigned integer with a non-power-of-2 range from the stream. + The bits must have been encoded with ec_enc_uint(). + No call to ec_dec_update() is necessary after this call. + _ft: The number of integers that can be decoded (one more than the max). + This must be at least 2, and no more than 2**32-1. + Return: The decoded bits.*/ +opus_uint32 ec_dec_uint(ec_dec *_this,opus_uint32 _ft); + +/*Extracts a sequence of raw bits from the stream. + The bits must have been encoded with ec_enc_bits(). + No call to ec_dec_update() is necessary after this call. + _ftb: The number of bits to extract. + This must be between 0 and 25, inclusive. + Return: The decoded bits.*/ +opus_uint32 ec_dec_bits(ec_dec *_this,unsigned _ftb); + +#endif diff --git a/extern/opus/celt/entenc.c b/extern/opus/celt/entenc.c new file mode 100644 index 0000000..f1750d2 --- /dev/null +++ b/extern/opus/celt/entenc.c @@ -0,0 +1,294 @@ +/* Copyright (c) 2001-2011 Timothy B. Terriberry + Copyright (c) 2008-2009 Xiph.Org Foundation */ +/* + 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. + + 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 OWNER + 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. +*/ + +#if defined(HAVE_CONFIG_H) +# include "config.h" +#endif +#include "os_support.h" +#include "arch.h" +#include "entenc.h" +#include "mfrngcod.h" + +/*A range encoder. + See entdec.c and the references for implementation details \cite{Mar79,MNW98}. + + @INPROCEEDINGS{Mar79, + author="Martin, G.N.N.", + title="Range encoding: an algorithm for removing redundancy from a digitised + message", + booktitle="Video \& Data Recording Conference", + year=1979, + address="Southampton", + month=Jul + } + @ARTICLE{MNW98, + author="Alistair Moffat and Radford Neal and Ian H. Witten", + title="Arithmetic Coding Revisited", + journal="{ACM} Transactions on Information Systems", + year=1998, + volume=16, + number=3, + pages="256--294", + month=Jul, + URL="http://www.stanford.edu/class/ee398/handouts/papers/Moffat98ArithmCoding.pdf" + }*/ + +static int ec_write_byte(ec_enc *_this,unsigned _value){ + if(_this->offs+_this->end_offs>=_this->storage)return -1; + _this->buf[_this->offs++]=(unsigned char)_value; + return 0; +} + +static int ec_write_byte_at_end(ec_enc *_this,unsigned _value){ + if(_this->offs+_this->end_offs>=_this->storage)return -1; + _this->buf[_this->storage-++(_this->end_offs)]=(unsigned char)_value; + return 0; +} + +/*Outputs a symbol, with a carry bit. + If there is a potential to propagate a carry over several symbols, they are + buffered until it can be determined whether or not an actual carry will + occur. + If the counter for the buffered symbols overflows, then the stream becomes + undecodable. + This gives a theoretical limit of a few billion symbols in a single packet on + 32-bit systems. + The alternative is to truncate the range in order to force a carry, but + requires similar carry tracking in the decoder, needlessly slowing it down.*/ +static void ec_enc_carry_out(ec_enc *_this,int _c){ + if(_c!=EC_SYM_MAX){ + /*No further carry propagation possible, flush buffer.*/ + int carry; + carry=_c>>EC_SYM_BITS; + /*Don't output a byte on the first write. + This compare should be taken care of by branch-prediction thereafter.*/ + if(_this->rem>=0)_this->error|=ec_write_byte(_this,_this->rem+carry); + if(_this->ext>0){ + unsigned sym; + sym=(EC_SYM_MAX+carry)&EC_SYM_MAX; + do _this->error|=ec_write_byte(_this,sym); + while(--(_this->ext)>0); + } + _this->rem=_c&EC_SYM_MAX; + } + else _this->ext++; +} + +static OPUS_INLINE void ec_enc_normalize(ec_enc *_this){ + /*If the range is too small, output some bits and rescale it.*/ + while(_this->rng<=EC_CODE_BOT){ + ec_enc_carry_out(_this,(int)(_this->val>>EC_CODE_SHIFT)); + /*Move the next-to-high-order symbol into the high-order position.*/ + _this->val=(_this->val<rng<<=EC_SYM_BITS; + _this->nbits_total+=EC_SYM_BITS; + } +} + +void ec_enc_init(ec_enc *_this,unsigned char *_buf,opus_uint32 _size){ + _this->buf=_buf; + _this->end_offs=0; + _this->end_window=0; + _this->nend_bits=0; + /*This is the offset from which ec_tell() will subtract partial bits.*/ + _this->nbits_total=EC_CODE_BITS+1; + _this->offs=0; + _this->rng=EC_CODE_TOP; + _this->rem=-1; + _this->val=0; + _this->ext=0; + _this->storage=_size; + _this->error=0; +} + +void ec_encode(ec_enc *_this,unsigned _fl,unsigned _fh,unsigned _ft){ + opus_uint32 r; + r=celt_udiv(_this->rng,_ft); + if(_fl>0){ + _this->val+=_this->rng-IMUL32(r,(_ft-_fl)); + _this->rng=IMUL32(r,(_fh-_fl)); + } + else _this->rng-=IMUL32(r,(_ft-_fh)); + ec_enc_normalize(_this); +} + +void ec_encode_bin(ec_enc *_this,unsigned _fl,unsigned _fh,unsigned _bits){ + opus_uint32 r; + r=_this->rng>>_bits; + if(_fl>0){ + _this->val+=_this->rng-IMUL32(r,((1U<<_bits)-_fl)); + _this->rng=IMUL32(r,(_fh-_fl)); + } + else _this->rng-=IMUL32(r,((1U<<_bits)-_fh)); + ec_enc_normalize(_this); +} + +/*The probability of having a "one" is 1/(1<<_logp).*/ +void ec_enc_bit_logp(ec_enc *_this,int _val,unsigned _logp){ + opus_uint32 r; + opus_uint32 s; + opus_uint32 l; + r=_this->rng; + l=_this->val; + s=r>>_logp; + r-=s; + if(_val)_this->val=l+r; + _this->rng=_val?s:r; + ec_enc_normalize(_this); +} + +void ec_enc_icdf(ec_enc *_this,int _s,const unsigned char *_icdf,unsigned _ftb){ + opus_uint32 r; + r=_this->rng>>_ftb; + if(_s>0){ + _this->val+=_this->rng-IMUL32(r,_icdf[_s-1]); + _this->rng=IMUL32(r,_icdf[_s-1]-_icdf[_s]); + } + else _this->rng-=IMUL32(r,_icdf[_s]); + ec_enc_normalize(_this); +} + +void ec_enc_uint(ec_enc *_this,opus_uint32 _fl,opus_uint32 _ft){ + unsigned ft; + unsigned fl; + int ftb; + /*In order to optimize EC_ILOG(), it is undefined for the value 0.*/ + celt_assert(_ft>1); + _ft--; + ftb=EC_ILOG(_ft); + if(ftb>EC_UINT_BITS){ + ftb-=EC_UINT_BITS; + ft=(_ft>>ftb)+1; + fl=(unsigned)(_fl>>ftb); + ec_encode(_this,fl,fl+1,ft); + ec_enc_bits(_this,_fl&(((opus_uint32)1<end_window; + used=_this->nend_bits; + celt_assert(_bits>0); + if(used+_bits>EC_WINDOW_SIZE){ + do{ + _this->error|=ec_write_byte_at_end(_this,(unsigned)window&EC_SYM_MAX); + window>>=EC_SYM_BITS; + used-=EC_SYM_BITS; + } + while(used>=EC_SYM_BITS); + } + window|=(ec_window)_fl<end_window=window; + _this->nend_bits=used; + _this->nbits_total+=_bits; +} + +void ec_enc_patch_initial_bits(ec_enc *_this,unsigned _val,unsigned _nbits){ + int shift; + unsigned mask; + celt_assert(_nbits<=EC_SYM_BITS); + shift=EC_SYM_BITS-_nbits; + mask=((1<<_nbits)-1)<offs>0){ + /*The first byte has been finalized.*/ + _this->buf[0]=(unsigned char)((_this->buf[0]&~mask)|_val<rem>=0){ + /*The first byte is still awaiting carry propagation.*/ + _this->rem=(_this->rem&~mask)|_val<rng<=(EC_CODE_TOP>>_nbits)){ + /*The renormalization loop has never been run.*/ + _this->val=(_this->val&~((opus_uint32)mask<error=-1; +} + +void ec_enc_shrink(ec_enc *_this,opus_uint32 _size){ + celt_assert(_this->offs+_this->end_offs<=_size); + OPUS_MOVE(_this->buf+_size-_this->end_offs, + _this->buf+_this->storage-_this->end_offs,_this->end_offs); + _this->storage=_size; +} + +void ec_enc_done(ec_enc *_this){ + ec_window window; + int used; + opus_uint32 msk; + opus_uint32 end; + int l; + /*We output the minimum number of bits that ensures that the symbols encoded + thus far will be decoded correctly regardless of the bits that follow.*/ + l=EC_CODE_BITS-EC_ILOG(_this->rng); + msk=(EC_CODE_TOP-1)>>l; + end=(_this->val+msk)&~msk; + if((end|msk)>=_this->val+_this->rng){ + l++; + msk>>=1; + end=(_this->val+msk)&~msk; + } + while(l>0){ + ec_enc_carry_out(_this,(int)(end>>EC_CODE_SHIFT)); + end=(end<rem>=0||_this->ext>0)ec_enc_carry_out(_this,0); + /*If we have buffered extra bits, flush them as well.*/ + window=_this->end_window; + used=_this->nend_bits; + while(used>=EC_SYM_BITS){ + _this->error|=ec_write_byte_at_end(_this,(unsigned)window&EC_SYM_MAX); + window>>=EC_SYM_BITS; + used-=EC_SYM_BITS; + } + /*Clear any excess space and add any remaining extra bits to the last byte.*/ + if(!_this->error){ + OPUS_CLEAR(_this->buf+_this->offs, + _this->storage-_this->offs-_this->end_offs); + if(used>0){ + /*If there's no range coder data at all, give up.*/ + if(_this->end_offs>=_this->storage)_this->error=-1; + else{ + l=-l; + /*If we've busted, don't add too many extra bits to the last byte; it + would corrupt the range coder data, and that's more important.*/ + if(_this->offs+_this->end_offs>=_this->storage&&lerror=-1; + } + _this->buf[_this->storage-_this->end_offs-1]|=(unsigned char)window; + } + } + } +} diff --git a/extern/opus/celt/entenc.h b/extern/opus/celt/entenc.h new file mode 100644 index 0000000..f502eaf --- /dev/null +++ b/extern/opus/celt/entenc.h @@ -0,0 +1,110 @@ +/* Copyright (c) 2001-2011 Timothy B. Terriberry + Copyright (c) 2008-2009 Xiph.Org Foundation */ +/* + 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. + + 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 OWNER + 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. +*/ + +#if !defined(_entenc_H) +# define _entenc_H (1) +# include +# include "entcode.h" + +/*Initializes the encoder. + _buf: The buffer to store output bytes in. + _size: The size of the buffer, in chars.*/ +void ec_enc_init(ec_enc *_this,unsigned char *_buf,opus_uint32 _size); +/*Encodes a symbol given its frequency information. + The frequency information must be discernable by the decoder, assuming it + has read only the previous symbols from the stream. + It is allowable to change the frequency information, or even the entire + source alphabet, so long as the decoder can tell from the context of the + previously encoded information that it is supposed to do so as well. + _fl: The cumulative frequency of all symbols that come before the one to be + encoded. + _fh: The cumulative frequency of all symbols up to and including the one to + be encoded. + Together with _fl, this defines the range [_fl,_fh) in which the + decoded value will fall. + _ft: The sum of the frequencies of all the symbols*/ +void ec_encode(ec_enc *_this,unsigned _fl,unsigned _fh,unsigned _ft); + +/*Equivalent to ec_encode() with _ft==1<<_bits.*/ +void ec_encode_bin(ec_enc *_this,unsigned _fl,unsigned _fh,unsigned _bits); + +/* Encode a bit that has a 1/(1<<_logp) probability of being a one */ +void ec_enc_bit_logp(ec_enc *_this,int _val,unsigned _logp); + +/*Encodes a symbol given an "inverse" CDF table. + _s: The index of the symbol to encode. + _icdf: The "inverse" CDF, such that symbol _s falls in the range + [_s>0?ft-_icdf[_s-1]:0,ft-_icdf[_s]), where ft=1<<_ftb. + The values must be monotonically non-increasing, and the last value + must be 0. + _ftb: The number of bits of precision in the cumulative distribution.*/ +void ec_enc_icdf(ec_enc *_this,int _s,const unsigned char *_icdf,unsigned _ftb); + +/*Encodes a raw unsigned integer in the stream. + _fl: The integer to encode. + _ft: The number of integers that can be encoded (one more than the max). + This must be at least 2, and no more than 2**32-1.*/ +void ec_enc_uint(ec_enc *_this,opus_uint32 _fl,opus_uint32 _ft); + +/*Encodes a sequence of raw bits in the stream. + _fl: The bits to encode. + _ftb: The number of bits to encode. + This must be between 1 and 25, inclusive.*/ +void ec_enc_bits(ec_enc *_this,opus_uint32 _fl,unsigned _ftb); + +/*Overwrites a few bits at the very start of an existing stream, after they + have already been encoded. + This makes it possible to have a few flags up front, where it is easy for + decoders to access them without parsing the whole stream, even if their + values are not determined until late in the encoding process, without having + to buffer all the intermediate symbols in the encoder. + In order for this to work, at least _nbits bits must have already been + encoded using probabilities that are an exact power of two. + The encoder can verify the number of encoded bits is sufficient, but cannot + check this latter condition. + _val: The bits to encode (in the least _nbits significant bits). + They will be decoded in order from most-significant to least. + _nbits: The number of bits to overwrite. + This must be no more than 8.*/ +void ec_enc_patch_initial_bits(ec_enc *_this,unsigned _val,unsigned _nbits); + +/*Compacts the data to fit in the target size. + This moves up the raw bits at the end of the current buffer so they are at + the end of the new buffer size. + The caller must ensure that the amount of data that's already been written + will fit in the new size. + _size: The number of bytes in the new buffer. + This must be large enough to contain the bits already written, and + must be no larger than the existing size.*/ +void ec_enc_shrink(ec_enc *_this,opus_uint32 _size); + +/*Indicates that there are no more symbols to encode. + All reamining output bytes are flushed to the output buffer. + ec_enc_init() must be called before the encoder can be used again.*/ +void ec_enc_done(ec_enc *_this); + +#endif diff --git a/extern/opus/celt/fixed_c5x.h b/extern/opus/celt/fixed_c5x.h new file mode 100644 index 0000000..ea95a99 --- /dev/null +++ b/extern/opus/celt/fixed_c5x.h @@ -0,0 +1,79 @@ +/* Copyright (C) 2003 Jean-Marc Valin */ +/** + @file fixed_c5x.h + @brief Fixed-point operations for the TI C5x DSP family +*/ +/* + 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. + + 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 OWNER + 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. +*/ + +#ifndef FIXED_C5X_H +#define FIXED_C5X_H + +#include "dsplib.h" + +#undef IMUL32 +static OPUS_INLINE long IMUL32(long i, long j) +{ + long ac0, ac1; + ac0 = _lmpy(i>>16,j); + ac1 = ac0 + _lmpy(i,j>>16); + return _lmpyu(i,j) + (ac1<<16); +} + +#undef MAX16 +#define MAX16(a,b) _max(a,b) + +#undef MIN16 +#define MIN16(a,b) _min(a,b) + +#undef MAX32 +#define MAX32(a,b) _lmax(a,b) + +#undef MIN32 +#define MIN32(a,b) _lmin(a,b) + +#undef VSHR32 +#define VSHR32(a, shift) _lshl(a,-(shift)) + +#undef MULT16_16_Q15 +#define MULT16_16_Q15(a,b) (_smpy(a,b)) + +#undef MULT16_16SU +#define MULT16_16SU(a,b) _lmpysu(a,b) + +#undef MULT_16_16 +#define MULT_16_16(a,b) _lmpy(a,b) + +/* FIXME: This is technically incorrect and is bound to cause problems. Is there any cleaner solution? */ +#undef MULT16_32_Q15 +#define MULT16_32_Q15(a,b) ADD32(SHL(MULT16_16((a),SHR((b),16)),1), SHR(MULT16_16SU((a),(b)),15)) + +#define celt_ilog2(x) (30 - _lnorm(x)) +#define OVERRIDE_CELT_ILOG2 + +#define celt_maxabs16(x, len) MAX32(EXTEND32(maxval((DATA *)x, len)),-EXTEND32(minval((DATA *)x, len))) +#define OVERRIDE_CELT_MAXABS16 + +#endif /* FIXED_C5X_H */ diff --git a/extern/opus/celt/fixed_c6x.h b/extern/opus/celt/fixed_c6x.h new file mode 100644 index 0000000..bb6ad92 --- /dev/null +++ b/extern/opus/celt/fixed_c6x.h @@ -0,0 +1,70 @@ +/* Copyright (C) 2008 CSIRO */ +/** + @file fixed_c6x.h + @brief Fixed-point operations for the TI C6x DSP family +*/ +/* + 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. + + 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 OWNER + 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. +*/ + +#ifndef FIXED_C6X_H +#define FIXED_C6X_H + +#undef MULT16_16SU +#define MULT16_16SU(a,b) _mpysu(a,b) + +#undef MULT_16_16 +#define MULT_16_16(a,b) _mpy(a,b) + +#define celt_ilog2(x) (30 - _norm(x)) +#define OVERRIDE_CELT_ILOG2 + +#undef MULT16_32_Q15 +#define MULT16_32_Q15(a,b) (_mpylill(a, b) >> 15) + +#if 0 +#include "dsplib.h" + +#undef MAX16 +#define MAX16(a,b) _max(a,b) + +#undef MIN16 +#define MIN16(a,b) _min(a,b) + +#undef MAX32 +#define MAX32(a,b) _lmax(a,b) + +#undef MIN32 +#define MIN32(a,b) _lmin(a,b) + +#undef VSHR32 +#define VSHR32(a, shift) _lshl(a,-(shift)) + +#undef MULT16_16_Q15 +#define MULT16_16_Q15(a,b) (_smpy(a,b)) + +#define celt_maxabs16(x, len) MAX32(EXTEND32(maxval((DATA *)x, len)),-EXTEND32(minval((DATA *)x, len))) +#define OVERRIDE_CELT_MAXABS16 + +#endif /* FIXED_C6X_H */ diff --git a/extern/opus/celt/fixed_debug.h b/extern/opus/celt/fixed_debug.h new file mode 100644 index 0000000..f435295 --- /dev/null +++ b/extern/opus/celt/fixed_debug.h @@ -0,0 +1,791 @@ +/* Copyright (C) 2003-2008 Jean-Marc Valin + Copyright (C) 2007-2012 Xiph.Org Foundation */ +/** + @file fixed_debug.h + @brief Fixed-point operations with debugging +*/ +/* + 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. + + 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 OWNER + 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. +*/ + +#ifndef FIXED_DEBUG_H +#define FIXED_DEBUG_H + +#include +#include "opus_defines.h" + +#ifdef CELT_C +OPUS_EXPORT opus_int64 celt_mips=0; +#else +extern opus_int64 celt_mips; +#endif + +#define MULT16_16SU(a,b) ((opus_val32)(opus_val16)(a)*(opus_val32)(opus_uint16)(b)) +#define MULT32_32_Q31(a,b) ADD32(ADD32(SHL32(MULT16_16(SHR32((a),16),SHR((b),16)),1), SHR32(MULT16_16SU(SHR32((a),16),((b)&0x0000ffff)),15)), SHR32(MULT16_16SU(SHR32((b),16),((a)&0x0000ffff)),15)) + +/** 16x32 multiplication, followed by a 16-bit shift right. Results fits in 32 bits */ +#define MULT16_32_Q16(a,b) ADD32(MULT16_16((a),SHR32((b),16)), SHR32(MULT16_16SU((a),((b)&0x0000ffff)),16)) + +#define MULT16_32_P16(a,b) MULT16_32_PX(a,b,16) + +#define QCONST16(x,bits) ((opus_val16)(.5+(x)*(((opus_val32)1)<<(bits)))) +#define QCONST32(x,bits) ((opus_val32)(.5+(x)*(((opus_val32)1)<<(bits)))) + +#define VERIFY_SHORT(x) ((x)<=32767&&(x)>=-32768) +#define VERIFY_INT(x) ((x)<=2147483647LL&&(x)>=-2147483648LL) +#define VERIFY_UINT(x) ((x)<=(2147483647LLU<<1)) + +#define SHR(a,b) SHR32(a,b) +#define PSHR(a,b) PSHR32(a,b) + +/** Add two 32-bit values, ignore any overflows */ +#define ADD32_ovflw(a,b) (celt_mips+=2,(opus_val32)((opus_uint32)(a)+(opus_uint32)(b))) +/** Subtract two 32-bit values, ignore any overflows */ +#define SUB32_ovflw(a,b) (celt_mips+=2,(opus_val32)((opus_uint32)(a)-(opus_uint32)(b))) +/* Avoid MSVC warning C4146: unary minus operator applied to unsigned type */ +/** Negate 32-bit value, ignore any overflows */ +#define NEG32_ovflw(a) (celt_mips+=2,(opus_val32)(0-(opus_uint32)(a))) + +static OPUS_INLINE short NEG16(int x) +{ + int res; + if (!VERIFY_SHORT(x)) + { + fprintf (stderr, "NEG16: input is not short: %d\n", (int)x); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = -x; + if (!VERIFY_SHORT(res)) + { + fprintf (stderr, "NEG16: output is not short: %d\n", (int)res); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + celt_mips++; + return res; +} +static OPUS_INLINE int NEG32(opus_int64 x) +{ + opus_int64 res; + if (!VERIFY_INT(x)) + { + fprintf (stderr, "NEG16: input is not int: %d\n", (int)x); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = -x; + if (!VERIFY_INT(res)) + { + fprintf (stderr, "NEG16: output is not int: %d\n", (int)res); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + celt_mips+=2; + return res; +} + +#define EXTRACT16(x) EXTRACT16_(x, __FILE__, __LINE__) +static OPUS_INLINE short EXTRACT16_(int x, char *file, int line) +{ + int res; + if (!VERIFY_SHORT(x)) + { + fprintf (stderr, "EXTRACT16: input is not short: %d in %s: line %d\n", x, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = x; + celt_mips++; + return res; +} + +#define EXTEND32(x) EXTEND32_(x, __FILE__, __LINE__) +static OPUS_INLINE int EXTEND32_(int x, char *file, int line) +{ + int res; + if (!VERIFY_SHORT(x)) + { + fprintf (stderr, "EXTEND32: input is not short: %d in %s: line %d\n", x, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = x; + celt_mips++; + return res; +} + +#define SHR16(a, shift) SHR16_(a, shift, __FILE__, __LINE__) +static OPUS_INLINE short SHR16_(int a, int shift, char *file, int line) +{ + int res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(shift)) + { + fprintf (stderr, "SHR16: inputs are not short: %d >> %d in %s: line %d\n", a, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = a>>shift; + if (!VERIFY_SHORT(res)) + { + fprintf (stderr, "SHR16: output is not short: %d in %s: line %d\n", res, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + celt_mips++; + return res; +} +#define SHL16(a, shift) SHL16_(a, shift, __FILE__, __LINE__) +static OPUS_INLINE short SHL16_(int a, int shift, char *file, int line) +{ + int res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(shift)) + { + fprintf (stderr, "SHL16: inputs are not short: %d %d in %s: line %d\n", a, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = a<>shift; + if (!VERIFY_INT(res)) + { + fprintf (stderr, "SHR32: output is not int: %d\n", (int)res); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + celt_mips+=2; + return res; +} +#define SHL32(a, shift) SHL32_(a, shift, __FILE__, __LINE__) +static OPUS_INLINE int SHL32_(opus_int64 a, int shift, char *file, int line) +{ + opus_int64 res; + if (!VERIFY_INT(a) || !VERIFY_SHORT(shift)) + { + fprintf (stderr, "SHL32: inputs are not int: %lld %d in %s: line %d\n", a, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = a<>1))),shift)) +#define VSHR32(a, shift) (((shift)>0) ? SHR32(a, shift) : SHL32(a, -(shift))) + +#define ROUND16(x,a) (celt_mips--,EXTRACT16(PSHR32((x),(a)))) +#define SROUND16(x,a) (celt_mips--,EXTRACT16(SATURATE(PSHR32(x,a), 32767))); + +#define HALF16(x) (SHR16(x,1)) +#define HALF32(x) (SHR32(x,1)) + +#define ADD16(a, b) ADD16_(a, b, __FILE__, __LINE__) +static OPUS_INLINE short ADD16_(int a, int b, char *file, int line) +{ + int res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "ADD16: inputs are not short: %d %d in %s: line %d\n", a, b, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = a+b; + if (!VERIFY_SHORT(res)) + { + fprintf (stderr, "ADD16: output is not short: %d+%d=%d in %s: line %d\n", a,b,res, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + celt_mips++; + return res; +} + +#define SUB16(a, b) SUB16_(a, b, __FILE__, __LINE__) +static OPUS_INLINE short SUB16_(int a, int b, char *file, int line) +{ + int res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "SUB16: inputs are not short: %d %d in %s: line %d\n", a, b, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = a-b; + if (!VERIFY_SHORT(res)) + { + fprintf (stderr, "SUB16: output is not short: %d in %s: line %d\n", res, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + celt_mips++; + return res; +} + +#define ADD32(a, b) ADD32_(a, b, __FILE__, __LINE__) +static OPUS_INLINE int ADD32_(opus_int64 a, opus_int64 b, char *file, int line) +{ + opus_int64 res; + if (!VERIFY_INT(a) || !VERIFY_INT(b)) + { + fprintf (stderr, "ADD32: inputs are not int: %d %d in %s: line %d\n", (int)a, (int)b, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = a+b; + if (!VERIFY_INT(res)) + { + fprintf (stderr, "ADD32: output is not int: %d in %s: line %d\n", (int)res, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + celt_mips+=2; + return res; +} + +#define SUB32(a, b) SUB32_(a, b, __FILE__, __LINE__) +static OPUS_INLINE int SUB32_(opus_int64 a, opus_int64 b, char *file, int line) +{ + opus_int64 res; + if (!VERIFY_INT(a) || !VERIFY_INT(b)) + { + fprintf (stderr, "SUB32: inputs are not int: %d %d in %s: line %d\n", (int)a, (int)b, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = a-b; + if (!VERIFY_INT(res)) + { + fprintf (stderr, "SUB32: output is not int: %d in %s: line %d\n", (int)res, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + celt_mips+=2; + return res; +} + +#undef UADD32 +#define UADD32(a, b) UADD32_(a, b, __FILE__, __LINE__) +static OPUS_INLINE unsigned int UADD32_(opus_uint64 a, opus_uint64 b, char *file, int line) +{ + opus_uint64 res; + if (!VERIFY_UINT(a) || !VERIFY_UINT(b)) + { + fprintf (stderr, "UADD32: inputs are not uint32: %llu %llu in %s: line %d\n", a, b, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = a+b; + if (!VERIFY_UINT(res)) + { + fprintf (stderr, "UADD32: output is not uint32: %llu in %s: line %d\n", res, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + celt_mips+=2; + return res; +} + +#undef USUB32 +#define USUB32(a, b) USUB32_(a, b, __FILE__, __LINE__) +static OPUS_INLINE unsigned int USUB32_(opus_uint64 a, opus_uint64 b, char *file, int line) +{ + opus_uint64 res; + if (!VERIFY_UINT(a) || !VERIFY_UINT(b)) + { + fprintf (stderr, "USUB32: inputs are not uint32: %llu %llu in %s: line %d\n", a, b, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + if (a=((opus_val32)(1)<<(15+Q))) + { + fprintf (stderr, "MULT16_32_Q%d: second operand too large: %d %d in %s: line %d\n", Q, (int)a, (int)b, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = (((opus_int64)a)*(opus_int64)b) >> Q; + if (!VERIFY_INT(res)) + { + fprintf (stderr, "MULT16_32_Q%d: output is not int: %d*%d=%d in %s: line %d\n", Q, (int)a, (int)b,(int)res, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + if (Q==15) + celt_mips+=3; + else + celt_mips+=4; + return res; +} + +#define MULT16_32_PX(a, b, Q) MULT16_32_PX_(a, b, Q, __FILE__, __LINE__) +static OPUS_INLINE int MULT16_32_PX_(int a, opus_int64 b, int Q, char *file, int line) +{ + opus_int64 res; + if (!VERIFY_SHORT(a) || !VERIFY_INT(b)) + { + fprintf (stderr, "MULT16_32_P%d: inputs are not short+int: %d %d in %s: line %d\n\n", Q, (int)a, (int)b, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + if (ABS32(b)>=((opus_int64)(1)<<(15+Q))) + { + fprintf (stderr, "MULT16_32_Q%d: second operand too large: %d %d in %s: line %d\n\n", Q, (int)a, (int)b,file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = ((((opus_int64)a)*(opus_int64)b) + (((opus_val32)(1)<>1))>> Q; + if (!VERIFY_INT(res)) + { + fprintf (stderr, "MULT16_32_P%d: output is not int: %d*%d=%d in %s: line %d\n\n", Q, (int)a, (int)b,(int)res, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + if (Q==15) + celt_mips+=4; + else + celt_mips+=5; + return res; +} + +#define MULT16_32_Q15(a,b) MULT16_32_QX(a,b,15) +#define MAC16_32_Q15(c,a,b) (celt_mips-=2,ADD32((c),MULT16_32_Q15((a),(b)))) +#define MAC16_32_Q16(c,a,b) (celt_mips-=2,ADD32((c),MULT16_32_Q16((a),(b)))) + +static OPUS_INLINE int SATURATE(int a, int b) +{ + if (a>b) + a=b; + if (a<-b) + a = -b; + celt_mips+=3; + return a; +} + +static OPUS_INLINE opus_int16 SATURATE16(opus_int32 a) +{ + celt_mips+=3; + if (a>32767) + return 32767; + else if (a<-32768) + return -32768; + else return a; +} + +static OPUS_INLINE int MULT16_16_Q11_32(int a, int b) +{ + opus_int64 res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "MULT16_16_Q11: inputs are not short: %d %d\n", a, b); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = ((opus_int64)a)*b; + res >>= 11; + if (!VERIFY_INT(res)) + { + fprintf (stderr, "MULT16_16_Q11: output is not short: %d*%d=%d\n", (int)a, (int)b, (int)res); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + celt_mips+=3; + return res; +} +static OPUS_INLINE short MULT16_16_Q13(int a, int b) +{ + opus_int64 res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "MULT16_16_Q13: inputs are not short: %d %d\n", a, b); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = ((opus_int64)a)*b; + res >>= 13; + if (!VERIFY_SHORT(res)) + { + fprintf (stderr, "MULT16_16_Q13: output is not short: %d*%d=%d\n", a, b, (int)res); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + celt_mips+=3; + return res; +} +static OPUS_INLINE short MULT16_16_Q14(int a, int b) +{ + opus_int64 res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "MULT16_16_Q14: inputs are not short: %d %d\n", a, b); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = ((opus_int64)a)*b; + res >>= 14; + if (!VERIFY_SHORT(res)) + { + fprintf (stderr, "MULT16_16_Q14: output is not short: %d\n", (int)res); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + celt_mips+=3; + return res; +} + +#define MULT16_16_Q15(a, b) MULT16_16_Q15_(a, b, __FILE__, __LINE__) +static OPUS_INLINE short MULT16_16_Q15_(int a, int b, char *file, int line) +{ + opus_int64 res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "MULT16_16_Q15: inputs are not short: %d %d in %s: line %d\n", a, b, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = ((opus_int64)a)*b; + res >>= 15; + if (!VERIFY_SHORT(res)) + { + fprintf (stderr, "MULT16_16_Q15: output is not short: %d in %s: line %d\n", (int)res, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + celt_mips+=1; + return res; +} + +static OPUS_INLINE short MULT16_16_P13(int a, int b) +{ + opus_int64 res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "MULT16_16_P13: inputs are not short: %d %d\n", a, b); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = ((opus_int64)a)*b; + res += 4096; + if (!VERIFY_INT(res)) + { + fprintf (stderr, "MULT16_16_P13: overflow: %d*%d=%d\n", a, b, (int)res); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res >>= 13; + if (!VERIFY_SHORT(res)) + { + fprintf (stderr, "MULT16_16_P13: output is not short: %d*%d=%d\n", a, b, (int)res); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + celt_mips+=4; + return res; +} +static OPUS_INLINE short MULT16_16_P14(int a, int b) +{ + opus_int64 res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "MULT16_16_P14: inputs are not short: %d %d\n", a, b); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = ((opus_int64)a)*b; + res += 8192; + if (!VERIFY_INT(res)) + { + fprintf (stderr, "MULT16_16_P14: overflow: %d*%d=%d\n", a, b, (int)res); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res >>= 14; + if (!VERIFY_SHORT(res)) + { + fprintf (stderr, "MULT16_16_P14: output is not short: %d*%d=%d\n", a, b, (int)res); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + celt_mips+=4; + return res; +} +static OPUS_INLINE short MULT16_16_P15(int a, int b) +{ + opus_int64 res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "MULT16_16_P15: inputs are not short: %d %d\n", a, b); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = ((opus_int64)a)*b; + res += 16384; + if (!VERIFY_INT(res)) + { + fprintf (stderr, "MULT16_16_P15: overflow: %d*%d=%d\n", a, b, (int)res); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res >>= 15; + if (!VERIFY_SHORT(res)) + { + fprintf (stderr, "MULT16_16_P15: output is not short: %d*%d=%d\n", a, b, (int)res); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + celt_mips+=2; + return res; +} + +#define DIV32_16(a, b) DIV32_16_(a, b, __FILE__, __LINE__) + +static OPUS_INLINE int DIV32_16_(opus_int64 a, opus_int64 b, char *file, int line) +{ + opus_int64 res; + if (b==0) + { + fprintf(stderr, "DIV32_16: divide by zero: %d/%d in %s: line %d\n", (int)a, (int)b, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + return 0; + } + if (!VERIFY_INT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "DIV32_16: inputs are not int/short: %d %d in %s: line %d\n", (int)a, (int)b, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = a/b; + if (!VERIFY_SHORT(res)) + { + fprintf (stderr, "DIV32_16: output is not short: %d / %d = %d in %s: line %d\n", (int)a,(int)b,(int)res, file, line); + if (res>32767) + res = 32767; + if (res<-32768) + res = -32768; +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + celt_mips+=35; + return res; +} + +#define DIV32(a, b) DIV32_(a, b, __FILE__, __LINE__) +static OPUS_INLINE int DIV32_(opus_int64 a, opus_int64 b, char *file, int line) +{ + opus_int64 res; + if (b==0) + { + fprintf(stderr, "DIV32: divide by zero: %d/%d in %s: line %d\n", (int)a, (int)b, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + return 0; + } + + if (!VERIFY_INT(a) || !VERIFY_INT(b)) + { + fprintf (stderr, "DIV32: inputs are not int/short: %d %d in %s: line %d\n", (int)a, (int)b, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = a/b; + if (!VERIFY_INT(res)) + { + fprintf (stderr, "DIV32: output is not int: %d in %s: line %d\n", (int)res, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + celt_mips+=70; + return res; +} + +static OPUS_INLINE opus_val16 SIG2WORD16_generic(celt_sig x) +{ + x = PSHR32(x, SIG_SHIFT); + x = MAX32(x, -32768); + x = MIN32(x, 32767); + return EXTRACT16(x); +} +#define SIG2WORD16(x) (SIG2WORD16_generic(x)) + + +#undef PRINT_MIPS +#define PRINT_MIPS(file) do {fprintf (file, "total complexity = %llu MIPS\n", celt_mips);} while (0); + +#endif diff --git a/extern/opus/celt/fixed_generic.h b/extern/opus/celt/fixed_generic.h new file mode 100644 index 0000000..5f4abda --- /dev/null +++ b/extern/opus/celt/fixed_generic.h @@ -0,0 +1,178 @@ +/* Copyright (C) 2007-2009 Xiph.Org Foundation + Copyright (C) 2003-2008 Jean-Marc Valin + Copyright (C) 2007-2008 CSIRO */ +/** + @file fixed_generic.h + @brief Generic fixed-point operations +*/ +/* + 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. + + 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 OWNER + 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. +*/ + +#ifndef FIXED_GENERIC_H +#define FIXED_GENERIC_H + +/** Multiply a 16-bit signed value by a 16-bit unsigned value. The result is a 32-bit signed value */ +#define MULT16_16SU(a,b) ((opus_val32)(opus_val16)(a)*(opus_val32)(opus_uint16)(b)) + +/** 16x32 multiplication, followed by a 16-bit shift right. Results fits in 32 bits */ +#if OPUS_FAST_INT64 +#define MULT16_32_Q16(a,b) ((opus_val32)SHR((opus_int64)((opus_val16)(a))*(b),16)) +#else +#define MULT16_32_Q16(a,b) ADD32(MULT16_16((a),SHR((b),16)), SHR(MULT16_16SU((a),((b)&0x0000ffff)),16)) +#endif + +/** 16x32 multiplication, followed by a 16-bit shift right (round-to-nearest). Results fits in 32 bits */ +#if OPUS_FAST_INT64 +#define MULT16_32_P16(a,b) ((opus_val32)PSHR((opus_int64)((opus_val16)(a))*(b),16)) +#else +#define MULT16_32_P16(a,b) ADD32(MULT16_16((a),SHR((b),16)), PSHR(MULT16_16SU((a),((b)&0x0000ffff)),16)) +#endif + +/** 16x32 multiplication, followed by a 15-bit shift right. Results fits in 32 bits */ +#if OPUS_FAST_INT64 +#define MULT16_32_Q15(a,b) ((opus_val32)SHR((opus_int64)((opus_val16)(a))*(b),15)) +#else +#define MULT16_32_Q15(a,b) ADD32(SHL(MULT16_16((a),SHR((b),16)),1), SHR(MULT16_16SU((a),((b)&0x0000ffff)),15)) +#endif + +/** 32x32 multiplication, followed by a 31-bit shift right. Results fits in 32 bits */ +#if OPUS_FAST_INT64 +#define MULT32_32_Q31(a,b) ((opus_val32)SHR((opus_int64)(a)*(opus_int64)(b),31)) +#else +#define MULT32_32_Q31(a,b) ADD32(ADD32(SHL(MULT16_16(SHR((a),16),SHR((b),16)),1), SHR(MULT16_16SU(SHR((a),16),((b)&0x0000ffff)),15)), SHR(MULT16_16SU(SHR((b),16),((a)&0x0000ffff)),15)) +#endif + +/** Compile-time conversion of float constant to 16-bit value */ +#define QCONST16(x,bits) ((opus_val16)(.5+(x)*(((opus_val32)1)<<(bits)))) + +/** Compile-time conversion of float constant to 32-bit value */ +#define QCONST32(x,bits) ((opus_val32)(.5+(x)*(((opus_val32)1)<<(bits)))) + +/** Negate a 16-bit value */ +#define NEG16(x) (-(x)) +/** Negate a 32-bit value */ +#define NEG32(x) (-(x)) + +/** Change a 32-bit value into a 16-bit value. The value is assumed to fit in 16-bit, otherwise the result is undefined */ +#define EXTRACT16(x) ((opus_val16)(x)) +/** Change a 16-bit value into a 32-bit value */ +#define EXTEND32(x) ((opus_val32)(x)) + +/** Arithmetic shift-right of a 16-bit value */ +#define SHR16(a,shift) ((a) >> (shift)) +/** Arithmetic shift-left of a 16-bit value */ +#define SHL16(a,shift) ((opus_int16)((opus_uint16)(a)<<(shift))) +/** Arithmetic shift-right of a 32-bit value */ +#define SHR32(a,shift) ((a) >> (shift)) +/** Arithmetic shift-left of a 32-bit value */ +#define SHL32(a,shift) ((opus_int32)((opus_uint32)(a)<<(shift))) + +/** 32-bit arithmetic shift right with rounding-to-nearest instead of rounding down */ +#define PSHR32(a,shift) (SHR32((a)+((EXTEND32(1)<<((shift))>>1)),shift)) +/** 32-bit arithmetic shift right where the argument can be negative */ +#define VSHR32(a, shift) (((shift)>0) ? SHR32(a, shift) : SHL32(a, -(shift))) + +/** "RAW" macros, should not be used outside of this header file */ +#define SHR(a,shift) ((a) >> (shift)) +#define SHL(a,shift) SHL32(a,shift) +#define PSHR(a,shift) (SHR((a)+((EXTEND32(1)<<((shift))>>1)),shift)) +#define SATURATE(x,a) (((x)>(a) ? (a) : (x)<-(a) ? -(a) : (x))) + +#define SATURATE16(x) (EXTRACT16((x)>32767 ? 32767 : (x)<-32768 ? -32768 : (x))) + +/** Shift by a and round-to-neareast 32-bit value. Result is a 16-bit value */ +#define ROUND16(x,a) (EXTRACT16(PSHR32((x),(a)))) +/** Shift by a and round-to-neareast 32-bit value. Result is a saturated 16-bit value */ +#define SROUND16(x,a) EXTRACT16(SATURATE(PSHR32(x,a), 32767)); + +/** Divide by two */ +#define HALF16(x) (SHR16(x,1)) +#define HALF32(x) (SHR32(x,1)) + +/** Add two 16-bit values */ +#define ADD16(a,b) ((opus_val16)((opus_val16)(a)+(opus_val16)(b))) +/** Subtract two 16-bit values */ +#define SUB16(a,b) ((opus_val16)(a)-(opus_val16)(b)) +/** Add two 32-bit values */ +#define ADD32(a,b) ((opus_val32)(a)+(opus_val32)(b)) +/** Subtract two 32-bit values */ +#define SUB32(a,b) ((opus_val32)(a)-(opus_val32)(b)) + +/** Add two 32-bit values, ignore any overflows */ +#define ADD32_ovflw(a,b) ((opus_val32)((opus_uint32)(a)+(opus_uint32)(b))) +/** Subtract two 32-bit values, ignore any overflows */ +#define SUB32_ovflw(a,b) ((opus_val32)((opus_uint32)(a)-(opus_uint32)(b))) +/* Avoid MSVC warning C4146: unary minus operator applied to unsigned type */ +/** Negate 32-bit value, ignore any overflows */ +#define NEG32_ovflw(a) ((opus_val32)(0-(opus_uint32)(a))) + +/** 16x16 multiplication where the result fits in 16 bits */ +#define MULT16_16_16(a,b) ((((opus_val16)(a))*((opus_val16)(b)))) + +/* (opus_val32)(opus_val16) gives TI compiler a hint that it's 16x16->32 multiply */ +/** 16x16 multiplication where the result fits in 32 bits */ +#define MULT16_16(a,b) (((opus_val32)(opus_val16)(a))*((opus_val32)(opus_val16)(b))) + +/** 16x16 multiply-add where the result fits in 32 bits */ +#define MAC16_16(c,a,b) (ADD32((c),MULT16_16((a),(b)))) +/** 16x32 multiply, followed by a 15-bit shift right and 32-bit add. + b must fit in 31 bits. + Result fits in 32 bits. */ +#define MAC16_32_Q15(c,a,b) ADD32((c),ADD32(MULT16_16((a),SHR((b),15)), SHR(MULT16_16((a),((b)&0x00007fff)),15))) + +/** 16x32 multiplication, followed by a 16-bit shift right and 32-bit add. + Results fits in 32 bits */ +#define MAC16_32_Q16(c,a,b) ADD32((c),ADD32(MULT16_16((a),SHR((b),16)), SHR(MULT16_16SU((a),((b)&0x0000ffff)),16))) + +#define MULT16_16_Q11_32(a,b) (SHR(MULT16_16((a),(b)),11)) +#define MULT16_16_Q11(a,b) (SHR(MULT16_16((a),(b)),11)) +#define MULT16_16_Q13(a,b) (SHR(MULT16_16((a),(b)),13)) +#define MULT16_16_Q14(a,b) (SHR(MULT16_16((a),(b)),14)) +#define MULT16_16_Q15(a,b) (SHR(MULT16_16((a),(b)),15)) + +#define MULT16_16_P13(a,b) (SHR(ADD32(4096,MULT16_16((a),(b))),13)) +#define MULT16_16_P14(a,b) (SHR(ADD32(8192,MULT16_16((a),(b))),14)) +#define MULT16_16_P15(a,b) (SHR(ADD32(16384,MULT16_16((a),(b))),15)) + +/** Divide a 32-bit value by a 16-bit value. Result fits in 16 bits */ +#define DIV32_16(a,b) ((opus_val16)(((opus_val32)(a))/((opus_val16)(b)))) + +/** Divide a 32-bit value by a 32-bit value. Result fits in 32 bits */ +#define DIV32(a,b) (((opus_val32)(a))/((opus_val32)(b))) + +#if defined(MIPSr1_ASM) +#include "mips/fixed_generic_mipsr1.h" +#endif + +static OPUS_INLINE opus_val16 SIG2WORD16_generic(celt_sig x) +{ + x = PSHR32(x, SIG_SHIFT); + x = MAX32(x, -32768); + x = MIN32(x, 32767); + return EXTRACT16(x); +} +#define SIG2WORD16(x) (SIG2WORD16_generic(x)) + +#endif diff --git a/extern/opus/celt/float_cast.h b/extern/opus/celt/float_cast.h new file mode 100644 index 0000000..889dae9 --- /dev/null +++ b/extern/opus/celt/float_cast.h @@ -0,0 +1,146 @@ +/* Copyright (C) 2001 Erik de Castro Lopo */ +/* + 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. + + 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 OWNER + 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. +*/ + +/* Version 1.1 */ + +#ifndef FLOAT_CAST_H +#define FLOAT_CAST_H + + +#include "arch.h" + +/*============================================================================ +** On Intel Pentium processors (especially PIII and probably P4), converting +** from float to int is very slow. To meet the C specs, the code produced by +** most C compilers targeting Pentium needs to change the FPU rounding mode +** before the float to int conversion is performed. +** +** Changing the FPU rounding mode causes the FPU pipeline to be flushed. It +** is this flushing of the pipeline which is so slow. +** +** Fortunately the ISO C99 specifications define the functions lrint, lrintf, +** llrint and llrintf which fix this problem as a side effect. +** +** On Unix-like systems, the configure process should have detected the +** presence of these functions. If they weren't found we have to replace them +** here with a standard C cast. +*/ + +/* +** The C99 prototypes for lrint and lrintf are as follows: +** +** long int lrintf (float x) ; +** long int lrint (double x) ; +*/ + +/* The presence of the required functions are detected during the configure +** process and the values HAVE_LRINT and HAVE_LRINTF are set accordingly in +** the config.h file. +*/ + +/* With GCC, when SSE is available, the fastest conversion is cvtss2si. */ +#if defined(__GNUC__) && defined(__SSE__) + +#include +static OPUS_INLINE opus_int32 float2int(float x) {return _mm_cvt_ss2si(_mm_set_ss(x));} + +#elif defined(HAVE_LRINTF) + +/* These defines enable functionality introduced with the 1999 ISO C +** standard. They must be defined before the inclusion of math.h to +** engage them. If optimisation is enabled, these functions will be +** inlined. With optimisation switched off, you have to link in the +** maths library using -lm. +*/ + +#define _ISOC9X_SOURCE 1 +#define _ISOC99_SOURCE 1 + +#define __USE_ISOC9X 1 +#define __USE_ISOC99 1 + +#include +#define float2int(x) lrintf(x) + +#elif (defined(HAVE_LRINT)) + +#define _ISOC9X_SOURCE 1 +#define _ISOC99_SOURCE 1 + +#define __USE_ISOC9X 1 +#define __USE_ISOC99 1 + +#include +#define float2int(x) lrint(x) + +#elif (defined(_MSC_VER) && _MSC_VER >= 1400) && (defined(_M_X64) || (defined(_M_IX86_FP) && _M_IX86_FP >= 1)) + #include + + static __inline long int float2int(float value) + { + return _mm_cvtss_si32(_mm_load_ss(&value)); + } +#elif (defined(_MSC_VER) && _MSC_VER >= 1400) && defined (_M_IX86) + #include + + /* Win32 doesn't seem to have these functions. + ** Therefore implement OPUS_INLINE versions of these functions here. + */ + + static __inline long int + float2int (float flt) + { int intgr; + + _asm + { fld flt + fistp intgr + } ; + + return intgr ; + } + +#else + +#if (defined(__GNUC__) && defined(__STDC__) && __STDC__ && __STDC_VERSION__ >= 199901L) + /* supported by gcc in C99 mode, but not by all other compilers */ + #warning "Don't have the functions lrint() and lrintf ()." + #warning "Replacing these functions with a standard C cast." +#endif /* __STDC_VERSION__ >= 199901L */ + #include + #define float2int(flt) ((int)(floor(.5+flt))) +#endif + +#ifndef DISABLE_FLOAT_API +static OPUS_INLINE opus_int16 FLOAT2INT16(float x) +{ + x = x*CELT_SIG_SCALE; + x = MAX32(x, -32768); + x = MIN32(x, 32767); + return (opus_int16)float2int(x); +} +#endif /* DISABLE_FLOAT_API */ + +#endif /* FLOAT_CAST_H */ diff --git a/extern/opus/celt/kiss_fft.c b/extern/opus/celt/kiss_fft.c new file mode 100644 index 0000000..8377516 --- /dev/null +++ b/extern/opus/celt/kiss_fft.c @@ -0,0 +1,604 @@ +/*Copyright (c) 2003-2004, Mark Borgerding + Lots of modifications by Jean-Marc Valin + Copyright (c) 2005-2007, Xiph.Org Foundation + Copyright (c) 2008, Xiph.Org Foundation, CSIRO + + All rights reserved. + + 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. + + 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 OWNER 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 code is originally from Mark Borgerding's KISS-FFT but has been + heavily modified to better suit Opus */ + +#ifndef SKIP_CONFIG_H +# ifdef HAVE_CONFIG_H +# include "config.h" +# endif +#endif + +#include "_kiss_fft_guts.h" +#include "arch.h" +#include "os_support.h" +#include "mathops.h" +#include "stack_alloc.h" + +/* The guts header contains all the multiplication and addition macros that are defined for + complex numbers. It also delares the kf_ internal functions. +*/ + +static void kf_bfly2( + kiss_fft_cpx * Fout, + int m, + int N + ) +{ + kiss_fft_cpx * Fout2; + int i; + (void)m; +#ifdef CUSTOM_MODES + if (m==1) + { + celt_assert(m==1); + for (i=0;itwiddles; + /* m is guaranteed to be a multiple of 4. */ + for (j=0;jtwiddles[fstride*m]; +#endif + for (i=0;itwiddles; + /* For non-custom modes, m is guaranteed to be a multiple of 4. */ + k=m; + do { + + C_MUL(scratch[1],Fout[m] , *tw1); + C_MUL(scratch[2],Fout[m2] , *tw2); + + C_ADD(scratch[3],scratch[1],scratch[2]); + C_SUB(scratch[0],scratch[1],scratch[2]); + tw1 += fstride; + tw2 += fstride*2; + + Fout[m].r = SUB32_ovflw(Fout->r, HALF_OF(scratch[3].r)); + Fout[m].i = SUB32_ovflw(Fout->i, HALF_OF(scratch[3].i)); + + C_MULBYSCALAR( scratch[0] , epi3.i ); + + C_ADDTO(*Fout,scratch[3]); + + Fout[m2].r = ADD32_ovflw(Fout[m].r, scratch[0].i); + Fout[m2].i = SUB32_ovflw(Fout[m].i, scratch[0].r); + + Fout[m].r = SUB32_ovflw(Fout[m].r, scratch[0].i); + Fout[m].i = ADD32_ovflw(Fout[m].i, scratch[0].r); + + ++Fout; + } while(--k); + } +} + + +#ifndef OVERRIDE_kf_bfly5 +static void kf_bfly5( + kiss_fft_cpx * Fout, + const size_t fstride, + const kiss_fft_state *st, + int m, + int N, + int mm + ) +{ + kiss_fft_cpx *Fout0,*Fout1,*Fout2,*Fout3,*Fout4; + int i, u; + kiss_fft_cpx scratch[13]; + const kiss_twiddle_cpx *tw; + kiss_twiddle_cpx ya,yb; + kiss_fft_cpx * Fout_beg = Fout; + +#ifdef FIXED_POINT + ya.r = 10126; + ya.i = -31164; + yb.r = -26510; + yb.i = -19261; +#else + ya = st->twiddles[fstride*m]; + yb = st->twiddles[fstride*2*m]; +#endif + tw=st->twiddles; + + for (i=0;ir = ADD32_ovflw(Fout0->r, ADD32_ovflw(scratch[7].r, scratch[8].r)); + Fout0->i = ADD32_ovflw(Fout0->i, ADD32_ovflw(scratch[7].i, scratch[8].i)); + + scratch[5].r = ADD32_ovflw(scratch[0].r, ADD32_ovflw(S_MUL(scratch[7].r,ya.r), S_MUL(scratch[8].r,yb.r))); + scratch[5].i = ADD32_ovflw(scratch[0].i, ADD32_ovflw(S_MUL(scratch[7].i,ya.r), S_MUL(scratch[8].i,yb.r))); + + scratch[6].r = ADD32_ovflw(S_MUL(scratch[10].i,ya.i), S_MUL(scratch[9].i,yb.i)); + scratch[6].i = NEG32_ovflw(ADD32_ovflw(S_MUL(scratch[10].r,ya.i), S_MUL(scratch[9].r,yb.i))); + + C_SUB(*Fout1,scratch[5],scratch[6]); + C_ADD(*Fout4,scratch[5],scratch[6]); + + scratch[11].r = ADD32_ovflw(scratch[0].r, ADD32_ovflw(S_MUL(scratch[7].r,yb.r), S_MUL(scratch[8].r,ya.r))); + scratch[11].i = ADD32_ovflw(scratch[0].i, ADD32_ovflw(S_MUL(scratch[7].i,yb.r), S_MUL(scratch[8].i,ya.r))); + scratch[12].r = SUB32_ovflw(S_MUL(scratch[9].i,ya.i), S_MUL(scratch[10].i,yb.i)); + scratch[12].i = SUB32_ovflw(S_MUL(scratch[10].r,yb.i), S_MUL(scratch[9].r,ya.i)); + + C_ADD(*Fout2,scratch[11],scratch[12]); + C_SUB(*Fout3,scratch[11],scratch[12]); + + ++Fout0;++Fout1;++Fout2;++Fout3;++Fout4; + } + } +} +#endif /* OVERRIDE_kf_bfly5 */ + + +#endif + + +#ifdef CUSTOM_MODES + +static +void compute_bitrev_table( + int Fout, + opus_int16 *f, + const size_t fstride, + int in_stride, + opus_int16 * factors, + const kiss_fft_state *st + ) +{ + const int p=*factors++; /* the radix */ + const int m=*factors++; /* stage's fft length/p */ + + /*printf ("fft %d %d %d %d %d %d\n", p*m, m, p, s2, fstride*in_stride, N);*/ + if (m==1) + { + int j; + for (j=0;j32000 || (opus_int32)p*(opus_int32)p > n) + p = n; /* no more factors, skip to end */ + } + n /= p; +#ifdef RADIX_TWO_ONLY + if (p!=2 && p != 4) +#else + if (p>5) +#endif + { + return 0; + } + facbuf[2*stages] = p; + if (p==2 && stages > 1) + { + facbuf[2*stages] = 4; + facbuf[2] = 2; + } + stages++; + } while (n > 1); + n = nbak; + /* Reverse the order to get the radix 4 at the end, so we can use the + fast degenerate case. It turns out that reversing the order also + improves the noise behaviour. */ + for (i=0;i= memneeded) + st = (kiss_fft_state*)mem; + *lenmem = memneeded; + } + if (st) { + opus_int16 *bitrev; + kiss_twiddle_cpx *twiddles; + + st->nfft=nfft; +#ifdef FIXED_POINT + st->scale_shift = celt_ilog2(st->nfft); + if (st->nfft == 1<scale_shift) + st->scale = Q15ONE; + else + st->scale = (1073741824+st->nfft/2)/st->nfft>>(15-st->scale_shift); +#else + st->scale = 1.f/nfft; +#endif + if (base != NULL) + { + st->twiddles = base->twiddles; + st->shift = 0; + while (st->shift < 32 && nfft<shift != base->nfft) + st->shift++; + if (st->shift>=32) + goto fail; + } else { + st->twiddles = twiddles = (kiss_twiddle_cpx*)KISS_FFT_MALLOC(sizeof(kiss_twiddle_cpx)*nfft); + compute_twiddles(twiddles, nfft); + st->shift = -1; + } + if (!kf_factor(nfft,st->factors)) + { + goto fail; + } + + /* bitrev */ + st->bitrev = bitrev = (opus_int16*)KISS_FFT_MALLOC(sizeof(opus_int16)*nfft); + if (st->bitrev==NULL) + goto fail; + compute_bitrev_table(0, bitrev, 1,1, st->factors,st); + + /* Initialize architecture specific fft parameters */ + if (opus_fft_alloc_arch(st, arch)) + goto fail; + } + return st; +fail: + opus_fft_free(st, arch); + return NULL; +} + +kiss_fft_state *opus_fft_alloc(int nfft,void * mem,size_t * lenmem, int arch) +{ + return opus_fft_alloc_twiddles(nfft, mem, lenmem, NULL, arch); +} + +void opus_fft_free_arch_c(kiss_fft_state *st) { + (void)st; +} + +void opus_fft_free(const kiss_fft_state *cfg, int arch) +{ + if (cfg) + { + opus_fft_free_arch((kiss_fft_state *)cfg, arch); + opus_free((opus_int16*)cfg->bitrev); + if (cfg->shift < 0) + opus_free((kiss_twiddle_cpx*)cfg->twiddles); + opus_free((kiss_fft_state*)cfg); + } +} + +#endif /* CUSTOM_MODES */ + +void opus_fft_impl(const kiss_fft_state *st,kiss_fft_cpx *fout) +{ + int m2, m; + int p; + int L; + int fstride[MAXFACTORS]; + int i; + int shift; + + /* st->shift can be -1 */ + shift = st->shift>0 ? st->shift : 0; + + fstride[0] = 1; + L=0; + do { + 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 (i=L-1;i>=0;i--) + { + if (i!=0) + m2 = st->factors[2*i-1]; + else + m2 = 1; + switch (st->factors[2*i]) + { + case 2: + kf_bfly2(fout, m, fstride[i]); + break; + case 4: + kf_bfly4(fout,fstride[i]<scale_shift-1; +#endif + scale = st->scale; + + celt_assert2 (fin != fout, "In-place FFT not supported"); + /* Bit-reverse the input */ + for (i=0;infft;i++) + { + kiss_fft_cpx x = fin[i]; + fout[st->bitrev[i]].r = SHR32(MULT16_32_Q16(scale, x.r), scale_shift); + fout[st->bitrev[i]].i = SHR32(MULT16_32_Q16(scale, x.i), scale_shift); + } + opus_fft_impl(st, fout); +} + + +void opus_ifft_c(const kiss_fft_state *st,const kiss_fft_cpx *fin,kiss_fft_cpx *fout) +{ + int i; + celt_assert2 (fin != fout, "In-place FFT not supported"); + /* Bit-reverse the input */ + for (i=0;infft;i++) + fout[st->bitrev[i]] = fin[i]; + for (i=0;infft;i++) + fout[i].i = -fout[i].i; + opus_fft_impl(st, fout); + for (i=0;infft;i++) + fout[i].i = -fout[i].i; +} diff --git a/extern/opus/celt/kiss_fft.h b/extern/opus/celt/kiss_fft.h new file mode 100644 index 0000000..bffa2bf --- /dev/null +++ b/extern/opus/celt/kiss_fft.h @@ -0,0 +1,200 @@ +/*Copyright (c) 2003-2004, Mark Borgerding + Lots of modifications by Jean-Marc Valin + Copyright (c) 2005-2007, Xiph.Org Foundation + Copyright (c) 2008, Xiph.Org Foundation, CSIRO + + All rights reserved. + + 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. + + 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 OWNER 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.*/ + +#ifndef KISS_FFT_H +#define KISS_FFT_H + +#include +#include +#include "arch.h" +#include "cpu_support.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef USE_SIMD +# include +# define kiss_fft_scalar __m128 +#define KISS_FFT_MALLOC(nbytes) memalign(16,nbytes) +#else +#define KISS_FFT_MALLOC opus_alloc +#endif + +#ifdef FIXED_POINT +#include "arch.h" + +# define kiss_fft_scalar opus_int32 +# define kiss_twiddle_scalar opus_int16 + + +#else +# ifndef kiss_fft_scalar +/* default is float */ +# define kiss_fft_scalar float +# define kiss_twiddle_scalar float +# define KF_SUFFIX _celt_single +# endif +#endif + +typedef struct { + kiss_fft_scalar r; + kiss_fft_scalar i; +}kiss_fft_cpx; + +typedef struct { + kiss_twiddle_scalar r; + kiss_twiddle_scalar i; +}kiss_twiddle_cpx; + +#define MAXFACTORS 8 +/* e.g. an fft of length 128 has 4 factors + as far as kissfft is concerned + 4*4*4*2 + */ + +typedef struct arch_fft_state{ + int is_supported; + void *priv; +} arch_fft_state; + +typedef struct kiss_fft_state{ + int nfft; + opus_val16 scale; +#ifdef FIXED_POINT + int scale_shift; +#endif + int shift; + opus_int16 factors[2*MAXFACTORS]; + const opus_int16 *bitrev; + const kiss_twiddle_cpx *twiddles; + arch_fft_state *arch_fft; +} kiss_fft_state; + +#if defined(HAVE_ARM_NE10) +#include "arm/fft_arm.h" +#endif + +/*typedef struct kiss_fft_state* kiss_fft_cfg;*/ + +/** + * opus_fft_alloc + * + * Initialize a FFT (or IFFT) algorithm's cfg/state buffer. + * + * typical usage: kiss_fft_cfg mycfg=opus_fft_alloc(1024,0,NULL,NULL); + * + * The return value from fft_alloc is a cfg buffer used internally + * by the fft routine or NULL. + * + * If lenmem is NULL, then opus_fft_alloc will allocate a cfg buffer using malloc. + * The returned value should be free()d when done to avoid memory leaks. + * + * The state can be placed in a user supplied buffer 'mem': + * If lenmem is not NULL and mem is not NULL and *lenmem is large enough, + * then the function places the cfg in mem and the size used in *lenmem + * and returns mem. + * + * If lenmem is not NULL and ( mem is NULL or *lenmem is not large enough), + * then the function returns NULL and places the minimum cfg + * buffer size in *lenmem. + * */ + +kiss_fft_state *opus_fft_alloc_twiddles(int nfft,void * mem,size_t * lenmem, const kiss_fft_state *base, int arch); + +kiss_fft_state *opus_fft_alloc(int nfft,void * mem,size_t * lenmem, int arch); + +/** + * opus_fft(cfg,in_out_buf) + * + * Perform an FFT on a complex input buffer. + * for a forward FFT, + * fin should be f[0] , f[1] , ... ,f[nfft-1] + * fout will be F[0] , F[1] , ... ,F[nfft-1] + * Note that each element is complex and can be accessed like + f[k].r and f[k].i + * */ +void opus_fft_c(const kiss_fft_state *cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fout); +void opus_ifft_c(const kiss_fft_state *cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fout); + +void opus_fft_impl(const kiss_fft_state *st,kiss_fft_cpx *fout); +void opus_ifft_impl(const kiss_fft_state *st,kiss_fft_cpx *fout); + +void opus_fft_free(const kiss_fft_state *cfg, int arch); + + +void opus_fft_free_arch_c(kiss_fft_state *st); +int opus_fft_alloc_arch_c(kiss_fft_state *st); + +#if !defined(OVERRIDE_OPUS_FFT) +/* Is run-time CPU detection enabled on this platform? */ +#if defined(OPUS_HAVE_RTCD) && (defined(HAVE_ARM_NE10)) + +extern int (*const OPUS_FFT_ALLOC_ARCH_IMPL[OPUS_ARCHMASK+1])( + kiss_fft_state *st); + +#define opus_fft_alloc_arch(_st, arch) \ + ((*OPUS_FFT_ALLOC_ARCH_IMPL[(arch)&OPUS_ARCHMASK])(_st)) + +extern void (*const OPUS_FFT_FREE_ARCH_IMPL[OPUS_ARCHMASK+1])( + kiss_fft_state *st); +#define opus_fft_free_arch(_st, arch) \ + ((*OPUS_FFT_FREE_ARCH_IMPL[(arch)&OPUS_ARCHMASK])(_st)) + +extern void (*const OPUS_FFT[OPUS_ARCHMASK+1])(const kiss_fft_state *cfg, + const kiss_fft_cpx *fin, kiss_fft_cpx *fout); +#define opus_fft(_cfg, _fin, _fout, arch) \ + ((*OPUS_FFT[(arch)&OPUS_ARCHMASK])(_cfg, _fin, _fout)) + +extern void (*const OPUS_IFFT[OPUS_ARCHMASK+1])(const kiss_fft_state *cfg, + const kiss_fft_cpx *fin, kiss_fft_cpx *fout); +#define opus_ifft(_cfg, _fin, _fout, arch) \ + ((*OPUS_IFFT[(arch)&OPUS_ARCHMASK])(_cfg, _fin, _fout)) + +#else /* else for if defined(OPUS_HAVE_RTCD) && (defined(HAVE_ARM_NE10)) */ + +#define opus_fft_alloc_arch(_st, arch) \ + ((void)(arch), opus_fft_alloc_arch_c(_st)) + +#define opus_fft_free_arch(_st, arch) \ + ((void)(arch), opus_fft_free_arch_c(_st)) + +#define opus_fft(_cfg, _fin, _fout, arch) \ + ((void)(arch), opus_fft_c(_cfg, _fin, _fout)) + +#define opus_ifft(_cfg, _fin, _fout, arch) \ + ((void)(arch), opus_ifft_c(_cfg, _fin, _fout)) + +#endif /* end if defined(OPUS_HAVE_RTCD) && (defined(HAVE_ARM_NE10)) */ +#endif /* end if !defined(OVERRIDE_OPUS_FFT) */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/extern/opus/celt/laplace.c b/extern/opus/celt/laplace.c new file mode 100644 index 0000000..a7bca87 --- /dev/null +++ b/extern/opus/celt/laplace.c @@ -0,0 +1,134 @@ +/* Copyright (c) 2007 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + 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. + + 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 OWNER + 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. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "laplace.h" +#include "mathops.h" + +/* The minimum probability of an energy delta (out of 32768). */ +#define LAPLACE_LOG_MINP (0) +#define LAPLACE_MINP (1<>15; +} + +void ec_laplace_encode(ec_enc *enc, int *value, unsigned fs, int decay) +{ + unsigned fl; + int val = *value; + fl = 0; + if (val) + { + int s; + int i; + s = -(val<0); + val = (val+s)^s; + fl = fs; + fs = ec_laplace_get_freq1(fs, decay); + /* Search the decaying part of the PDF.*/ + for (i=1; fs > 0 && i < val; i++) + { + fs *= 2; + fl += fs+2*LAPLACE_MINP; + fs = (fs*(opus_int32)decay)>>15; + } + /* Everything beyond that has probability LAPLACE_MINP. */ + if (!fs) + { + int di; + int ndi_max; + ndi_max = (32768-fl+LAPLACE_MINP-1)>>LAPLACE_LOG_MINP; + ndi_max = (ndi_max-s)>>1; + di = IMIN(val - i, ndi_max - 1); + fl += (2*di+1+s)*LAPLACE_MINP; + fs = IMIN(LAPLACE_MINP, 32768-fl); + *value = (i+di+s)^s; + } + else + { + fs += LAPLACE_MINP; + fl += fs&~s; + } + celt_assert(fl+fs<=32768); + celt_assert(fs>0); + } + ec_encode_bin(enc, fl, fl+fs, 15); +} + +int ec_laplace_decode(ec_dec *dec, unsigned fs, int decay) +{ + int val=0; + unsigned fl; + unsigned fm; + fm = ec_decode_bin(dec, 15); + fl = 0; + if (fm >= fs) + { + val++; + fl = fs; + fs = ec_laplace_get_freq1(fs, decay)+LAPLACE_MINP; + /* Search the decaying part of the PDF.*/ + while(fs > LAPLACE_MINP && fm >= fl+2*fs) + { + fs *= 2; + fl += fs; + fs = ((fs-2*LAPLACE_MINP)*(opus_int32)decay)>>15; + fs += LAPLACE_MINP; + val++; + } + /* Everything beyond that has probability LAPLACE_MINP. */ + if (fs <= LAPLACE_MINP) + { + int di; + di = (fm-fl)>>(LAPLACE_LOG_MINP+1); + val += di; + fl += 2*di*LAPLACE_MINP; + } + if (fm < fl+fs) + val = -val; + else + fl += fs; + } + celt_assert(fl<32768); + celt_assert(fs>0); + celt_assert(fl<=fm); + celt_assert(fm>1; + b=1U<>=1; + bshift--; + } + while(bshift>=0); + return g; +} + +#ifdef FIXED_POINT + +opus_val32 frac_div32(opus_val32 a, opus_val32 b) +{ + opus_val16 rcp; + opus_val32 result, rem; + int shift = celt_ilog2(b)-29; + a = VSHR32(a,shift); + b = VSHR32(b,shift); + /* 16-bit reciprocal */ + rcp = ROUND16(celt_rcp(ROUND16(b,16)),3); + result = MULT16_32_Q15(rcp, a); + rem = PSHR32(a,2)-MULT32_32_Q31(result, b); + result = ADD32(result, SHL32(MULT16_32_Q15(rcp, rem),2)); + if (result >= 536870912) /* 2^29 */ + return 2147483647; /* 2^31 - 1 */ + else if (result <= -536870912) /* -2^29 */ + return -2147483647; /* -2^31 */ + else + return SHL32(result, 2); +} + +/** Reciprocal sqrt approximation in the range [0.25,1) (Q16 in, Q14 out) */ +opus_val16 celt_rsqrt_norm(opus_val32 x) +{ + opus_val16 n; + opus_val16 r; + opus_val16 r2; + opus_val16 y; + /* Range of n is [-16384,32767] ([-0.5,1) in Q15). */ + n = x-32768; + /* Get a rough initial guess for the root. + The optimal minimax quadratic approximation (using relative error) is + r = 1.437799046117536+n*(-0.823394375837328+n*0.4096419668459485). + Coefficients here, and the final result r, are Q14.*/ + r = ADD16(23557, MULT16_16_Q15(n, ADD16(-13490, MULT16_16_Q15(n, 6713)))); + /* We want y = x*r*r-1 in Q15, but x is 32-bit Q16 and r is Q14. + We can compute the result from n and r using Q15 multiplies with some + adjustment, carefully done to avoid overflow. + Range of y is [-1564,1594]. */ + r2 = MULT16_16_Q15(r, r); + y = SHL16(SUB16(ADD16(MULT16_16_Q15(r2, n), r2), 16384), 1); + /* Apply a 2nd-order Householder iteration: r += r*y*(y*0.375-0.5). + This yields the Q14 reciprocal square root of the Q16 x, with a maximum + relative error of 1.04956E-4, a (relative) RMSE of 2.80979E-5, and a + peak absolute error of 2.26591/16384. */ + return ADD16(r, MULT16_16_Q15(r, MULT16_16_Q15(y, + SUB16(MULT16_16_Q15(y, 12288), 16384)))); +} + +/** Sqrt approximation (QX input, QX/2 output) */ +opus_val32 celt_sqrt(opus_val32 x) +{ + int k; + opus_val16 n; + opus_val32 rt; + static const opus_val16 C[5] = {23175, 11561, -3011, 1699, -664}; + if (x==0) + return 0; + else if (x>=1073741824) + return 32767; + k = (celt_ilog2(x)>>1)-7; + x = VSHR32(x, 2*k); + n = x-32768; + rt = ADD16(C[0], MULT16_16_Q15(n, ADD16(C[1], MULT16_16_Q15(n, ADD16(C[2], + MULT16_16_Q15(n, ADD16(C[3], MULT16_16_Q15(n, (C[4]))))))))); + rt = VSHR32(rt,7-k); + return rt; +} + +#define L1 32767 +#define L2 -7651 +#define L3 8277 +#define L4 -626 + +static OPUS_INLINE opus_val16 _celt_cos_pi_2(opus_val16 x) +{ + opus_val16 x2; + + x2 = MULT16_16_P15(x,x); + return ADD16(1,MIN16(32766,ADD32(SUB16(L1,x2), MULT16_16_P15(x2, ADD32(L2, MULT16_16_P15(x2, ADD32(L3, MULT16_16_P15(L4, x2 + )))))))); +} + +#undef L1 +#undef L2 +#undef L3 +#undef L4 + +opus_val16 celt_cos_norm(opus_val32 x) +{ + x = x&0x0001ffff; + if (x>SHL32(EXTEND32(1), 16)) + x = SUB32(SHL32(EXTEND32(1), 17),x); + if (x&0x00007fff) + { + if (x0); + i = celt_ilog2(x); + /* n is Q15 with range [0,1). */ + n = VSHR32(x,i-15)-32768; + /* Start with a linear approximation: + r = 1.8823529411764706-0.9411764705882353*n. + The coefficients and the result are Q14 in the range [15420,30840].*/ + r = ADD16(30840, MULT16_16_Q15(-15420, n)); + /* Perform two Newton iterations: + r -= r*((r*n)-1.Q15) + = r*((r*n)+(r-1.Q15)). */ + r = SUB16(r, MULT16_16_Q15(r, + ADD16(MULT16_16_Q15(r, n), ADD16(r, -32768)))); + /* We subtract an extra 1 in the second iteration to avoid overflow; it also + neatly compensates for truncation error in the rest of the process. */ + r = SUB16(r, ADD16(1, MULT16_16_Q15(r, + ADD16(MULT16_16_Q15(r, n), ADD16(r, -32768))))); + /* r is now the Q15 solution to 2/(n+1), with a maximum relative error + of 7.05346E-5, a (relative) RMSE of 2.14418E-5, and a peak absolute + error of 1.24665/32768. */ + return VSHR32(EXTEND32(r),i-16); +} + +#endif diff --git a/extern/opus/celt/mathops.h b/extern/opus/celt/mathops.h new file mode 100644 index 0000000..5e86ff0 --- /dev/null +++ b/extern/opus/celt/mathops.h @@ -0,0 +1,290 @@ +/* Copyright (c) 2002-2008 Jean-Marc Valin + Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/** + @file mathops.h + @brief Various math functions +*/ +/* + 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. + + 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 OWNER + 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. +*/ + +#ifndef MATHOPS_H +#define MATHOPS_H + +#include "arch.h" +#include "entcode.h" +#include "os_support.h" + +#define PI 3.141592653f + +/* Multiplies two 16-bit fractional values. Bit-exactness of this macro is important */ +#define FRAC_MUL16(a,b) ((16384+((opus_int32)(opus_int16)(a)*(opus_int16)(b)))>>15) + +unsigned isqrt32(opus_uint32 _val); + +/* CELT doesn't need it for fixed-point, by analysis.c does. */ +#if !defined(FIXED_POINT) || defined(ANALYSIS_C) +#define cA 0.43157974f +#define cB 0.67848403f +#define cC 0.08595542f +#define cE ((float)PI/2) +static OPUS_INLINE float fast_atan2f(float y, float x) { + float x2, y2; + x2 = x*x; + y2 = y*y; + /* For very small values, we don't care about the answer, so + we can just return 0. */ + if (x2 + y2 < 1e-18f) + { + return 0; + } + if(x2>23)-127; + in.i -= integer<<23; + frac = in.f - 1.5f; + frac = -0.41445418f + frac*(0.95909232f + + frac*(-0.33951290f + frac*0.16541097f)); + return 1+integer+frac; +} + +/** Base-2 exponential approximation (2^x). */ +static OPUS_INLINE float celt_exp2(float x) +{ + int integer; + float frac; + union { + float f; + opus_uint32 i; + } res; + integer = floor(x); + if (integer < -50) + return 0; + frac = x-integer; + /* K0 = 1, K1 = log(2), K2 = 3-4*log(2), K3 = 3*log(2) - 2 */ + res.f = 0.99992522f + frac * (0.69583354f + + frac * (0.22606716f + 0.078024523f*frac)); + res.i = (res.i + (integer<<23)) & 0x7fffffff; + return res.f; +} + +#else +#define celt_log2(x) ((float)(1.442695040888963387*log(x))) +#define celt_exp2(x) ((float)exp(0.6931471805599453094*(x))) +#endif + +#endif + +#ifdef FIXED_POINT + +#include "os_support.h" + +#ifndef OVERRIDE_CELT_ILOG2 +/** Integer log in base2. Undefined for zero and negative numbers */ +static OPUS_INLINE opus_int16 celt_ilog2(opus_int32 x) +{ + celt_sig_assert(x>0); + return EC_ILOG(x)-1; +} +#endif + + +/** Integer log in base2. Defined for zero, but not for negative numbers */ +static OPUS_INLINE opus_int16 celt_zlog2(opus_val32 x) +{ + return x <= 0 ? 0 : celt_ilog2(x); +} + +opus_val16 celt_rsqrt_norm(opus_val32 x); + +opus_val32 celt_sqrt(opus_val32 x); + +opus_val16 celt_cos_norm(opus_val32 x); + +/** Base-2 logarithm approximation (log2(x)). (Q14 input, Q10 output) */ +static OPUS_INLINE opus_val16 celt_log2(opus_val32 x) +{ + int i; + opus_val16 n, frac; + /* -0.41509302963303146, 0.9609890551383969, -0.31836011537636605, + 0.15530808010959576, -0.08556153059057618 */ + static const opus_val16 C[5] = {-6801+(1<<(13-DB_SHIFT)), 15746, -5217, 2545, -1401}; + if (x==0) + return -32767; + i = celt_ilog2(x); + n = VSHR32(x,i-15)-32768-16384; + frac = ADD16(C[0], MULT16_16_Q15(n, ADD16(C[1], MULT16_16_Q15(n, ADD16(C[2], MULT16_16_Q15(n, ADD16(C[3], MULT16_16_Q15(n, C[4])))))))); + return SHL16(i-13,DB_SHIFT)+SHR16(frac,14-DB_SHIFT); +} + +/* + K0 = 1 + K1 = log(2) + K2 = 3-4*log(2) + K3 = 3*log(2) - 2 +*/ +#define D0 16383 +#define D1 22804 +#define D2 14819 +#define D3 10204 + +static OPUS_INLINE opus_val32 celt_exp2_frac(opus_val16 x) +{ + opus_val16 frac; + frac = SHL16(x, 4); + return ADD16(D0, MULT16_16_Q15(frac, ADD16(D1, MULT16_16_Q15(frac, ADD16(D2 , MULT16_16_Q15(D3,frac)))))); +} +/** Base-2 exponential approximation (2^x). (Q10 input, Q16 output) */ +static OPUS_INLINE opus_val32 celt_exp2(opus_val16 x) +{ + int integer; + opus_val16 frac; + integer = SHR16(x,10); + if (integer>14) + return 0x7f000000; + else if (integer < -15) + return 0; + frac = celt_exp2_frac(x-SHL16(integer,10)); + return VSHR32(EXTEND32(frac), -integer-2); +} + +opus_val32 celt_rcp(opus_val32 x); + +#define celt_div(a,b) MULT32_32_Q31((opus_val32)(a),celt_rcp(b)) + +opus_val32 frac_div32(opus_val32 a, opus_val32 b); + +#define M1 32767 +#define M2 -21 +#define M3 -11943 +#define M4 4936 + +/* Atan approximation using a 4th order polynomial. Input is in Q15 format + and normalized by pi/4. Output is in Q15 format */ +static OPUS_INLINE opus_val16 celt_atan01(opus_val16 x) +{ + return MULT16_16_P15(x, ADD32(M1, MULT16_16_P15(x, ADD32(M2, MULT16_16_P15(x, ADD32(M3, MULT16_16_P15(M4, x))))))); +} + +#undef M1 +#undef M2 +#undef M3 +#undef M4 + +/* atan2() approximation valid for positive input values */ +static OPUS_INLINE opus_val16 celt_atan2p(opus_val16 y, opus_val16 x) +{ + if (y < x) + { + opus_val32 arg; + arg = celt_div(SHL32(EXTEND32(y),15),x); + if (arg >= 32767) + arg = 32767; + return SHR16(celt_atan01(EXTRACT16(arg)),1); + } else { + opus_val32 arg; + arg = celt_div(SHL32(EXTEND32(x),15),y); + if (arg >= 32767) + arg = 32767; + return 25736-SHR16(celt_atan01(EXTRACT16(arg)),1); + } +} + +#endif /* FIXED_POINT */ +#endif /* MATHOPS_H */ diff --git a/extern/opus/celt/mdct.c b/extern/opus/celt/mdct.c new file mode 100644 index 0000000..5c6dab5 --- /dev/null +++ b/extern/opus/celt/mdct.c @@ -0,0 +1,343 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2008 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + 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. + + 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 OWNER + 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 is a simple MDCT implementation that uses a N/4 complex FFT + to do most of the work. It should be relatively straightforward to + plug in pretty much and FFT here. + + This replaces the Vorbis FFT (and uses the exact same API), which + was a bit too messy and that was ending up duplicating code + (might as well use the same FFT everywhere). + + The algorithm is similar to (and inspired from) Fabrice Bellard's + MDCT implementation in FFMPEG, but has differences in signs, ordering + and scaling in many places. +*/ + +#ifndef SKIP_CONFIG_H +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#endif + +#include "mdct.h" +#include "kiss_fft.h" +#include "_kiss_fft_guts.h" +#include +#include "os_support.h" +#include "mathops.h" +#include "stack_alloc.h" + +#if defined(MIPSr1_ASM) +#include "mips/mdct_mipsr1.h" +#endif + + +#ifdef CUSTOM_MODES + +int clt_mdct_init(mdct_lookup *l,int N, int maxshift, int arch) +{ + int i; + kiss_twiddle_scalar *trig; + int shift; + int N2=N>>1; + l->n = N; + l->maxshift = maxshift; + for (i=0;i<=maxshift;i++) + { + if (i==0) + l->kfft[i] = opus_fft_alloc(N>>2>>i, 0, 0, arch); + else + l->kfft[i] = opus_fft_alloc_twiddles(N>>2>>i, 0, 0, l->kfft[0], arch); +#ifndef ENABLE_TI_DSPLIB55 + if (l->kfft[i]==NULL) + return 0; +#endif + } + l->trig = trig = (kiss_twiddle_scalar*)opus_alloc((N-(N2>>maxshift))*sizeof(kiss_twiddle_scalar)); + if (l->trig==NULL) + return 0; + for (shift=0;shift<=maxshift;shift++) + { + /* We have enough points that sine isn't necessary */ +#if defined(FIXED_POINT) +#if 1 + for (i=0;i>= 1; + N >>= 1; + } + return 1; +} + +void clt_mdct_clear(mdct_lookup *l, int arch) +{ + int i; + for (i=0;i<=l->maxshift;i++) + opus_fft_free(l->kfft[i], arch); + opus_free((kiss_twiddle_scalar*)l->trig); +} + +#endif /* CUSTOM_MODES */ + +/* Forward MDCT trashes the input array */ +#ifndef OVERRIDE_clt_mdct_forward +void clt_mdct_forward_c(const mdct_lookup *l, kiss_fft_scalar *in, kiss_fft_scalar * OPUS_RESTRICT out, + const opus_val16 *window, int overlap, int shift, int stride, int arch) +{ + int i; + int N, N2, N4; + VARDECL(kiss_fft_scalar, f); + VARDECL(kiss_fft_cpx, f2); + const kiss_fft_state *st = l->kfft[shift]; + const kiss_twiddle_scalar *trig; + opus_val16 scale; +#ifdef FIXED_POINT + /* Allows us to scale with MULT16_32_Q16(), which is faster than + MULT16_32_Q15() on ARM. */ + int scale_shift = st->scale_shift-1; +#endif + SAVE_STACK; + (void)arch; + scale = st->scale; + + N = l->n; + trig = l->trig; + for (i=0;i>= 1; + trig += N; + } + N2 = N>>1; + N4 = N>>2; + + ALLOC(f, N2, kiss_fft_scalar); + ALLOC(f2, N4, kiss_fft_cpx); + + /* Consider the input to be composed of four blocks: [a, b, c, d] */ + /* Window, shuffle, fold */ + { + /* Temp pointers to make it really clear to the compiler what we're doing */ + const kiss_fft_scalar * OPUS_RESTRICT xp1 = in+(overlap>>1); + const kiss_fft_scalar * OPUS_RESTRICT xp2 = in+N2-1+(overlap>>1); + kiss_fft_scalar * OPUS_RESTRICT yp = f; + const opus_val16 * OPUS_RESTRICT wp1 = window+(overlap>>1); + const opus_val16 * OPUS_RESTRICT wp2 = window+(overlap>>1)-1; + for(i=0;i<((overlap+3)>>2);i++) + { + /* Real part arranged as -d-cR, Imag part arranged as -b+aR*/ + *yp++ = MULT16_32_Q15(*wp2, xp1[N2]) + MULT16_32_Q15(*wp1,*xp2); + *yp++ = MULT16_32_Q15(*wp1, *xp1) - MULT16_32_Q15(*wp2, xp2[-N2]); + xp1+=2; + xp2-=2; + wp1+=2; + wp2-=2; + } + wp1 = window; + wp2 = window+overlap-1; + for(;i>2);i++) + { + /* Real part arranged as a-bR, Imag part arranged as -c-dR */ + *yp++ = *xp2; + *yp++ = *xp1; + xp1+=2; + xp2-=2; + } + for(;ibitrev[i]] = yc; + } + } + + /* N/4 complex FFT, does not downscale anymore */ + opus_fft_impl(st, f2); + + /* Post-rotate */ + { + /* Temp pointers to make it really clear to the compiler what we're doing */ + const kiss_fft_cpx * OPUS_RESTRICT fp = f2; + kiss_fft_scalar * OPUS_RESTRICT yp1 = out; + kiss_fft_scalar * OPUS_RESTRICT yp2 = out+stride*(N2-1); + const kiss_twiddle_scalar *t = &trig[0]; + /* Temp pointers to make it really clear to the compiler what we're doing */ + for(i=0;ii,t[N4+i]) - S_MUL(fp->r,t[i]); + yi = S_MUL(fp->r,t[N4+i]) + S_MUL(fp->i,t[i]); + *yp1 = yr; + *yp2 = yi; + fp++; + yp1 += 2*stride; + yp2 -= 2*stride; + } + } + RESTORE_STACK; +} +#endif /* OVERRIDE_clt_mdct_forward */ + +#ifndef OVERRIDE_clt_mdct_backward +void clt_mdct_backward_c(const mdct_lookup *l, kiss_fft_scalar *in, kiss_fft_scalar * OPUS_RESTRICT out, + const opus_val16 * OPUS_RESTRICT window, int overlap, int shift, int stride, int arch) +{ + int i; + int N, N2, N4; + const kiss_twiddle_scalar *trig; + (void) arch; + + N = l->n; + trig = l->trig; + for (i=0;i>= 1; + trig += N; + } + N2 = N>>1; + N4 = N>>2; + + /* Pre-rotate */ + { + /* Temp pointers to make it really clear to the compiler what we're doing */ + const kiss_fft_scalar * OPUS_RESTRICT xp1 = in; + const kiss_fft_scalar * OPUS_RESTRICT xp2 = in+stride*(N2-1); + kiss_fft_scalar * OPUS_RESTRICT yp = out+(overlap>>1); + const kiss_twiddle_scalar * OPUS_RESTRICT t = &trig[0]; + const opus_int16 * OPUS_RESTRICT bitrev = l->kfft[shift]->bitrev; + for(i=0;ikfft[shift], (kiss_fft_cpx*)(out+(overlap>>1))); + + /* Post-rotate and de-shuffle from both ends of the buffer at once to make + it in-place. */ + { + kiss_fft_scalar * yp0 = out+(overlap>>1); + kiss_fft_scalar * yp1 = out+(overlap>>1)+N2-2; + const kiss_twiddle_scalar *t = &trig[0]; + /* Loop to (N4+1)>>1 to handle odd N4. When N4 is odd, the + middle pair will be computed twice. */ + for(i=0;i<(N4+1)>>1;i++) + { + kiss_fft_scalar re, im, yr, yi; + kiss_twiddle_scalar t0, t1; + /* We swap real and imag because we're using an FFT instead of an IFFT. */ + re = yp0[1]; + im = yp0[0]; + t0 = t[i]; + t1 = t[N4+i]; + /* We'd scale up by 2 here, but instead it's done when mixing the windows */ + yr = ADD32_ovflw(S_MUL(re,t0), S_MUL(im,t1)); + yi = SUB32_ovflw(S_MUL(re,t1), S_MUL(im,t0)); + /* We swap real and imag because we're using an FFT instead of an IFFT. */ + re = yp1[1]; + im = yp1[0]; + yp0[0] = yr; + yp1[1] = yi; + + t0 = t[(N4-i-1)]; + t1 = t[(N2-i-1)]; + /* We'd scale up by 2 here, but instead it's done when mixing the windows */ + yr = ADD32_ovflw(S_MUL(re,t0), S_MUL(im,t1)); + yi = SUB32_ovflw(S_MUL(re,t1), S_MUL(im,t0)); + yp1[0] = yr; + yp0[1] = yi; + yp0 += 2; + yp1 -= 2; + } + } + + /* Mirror on both sides for TDAC */ + { + kiss_fft_scalar * OPUS_RESTRICT xp1 = out+overlap-1; + kiss_fft_scalar * OPUS_RESTRICT yp1 = out; + const opus_val16 * OPUS_RESTRICT wp1 = window; + const opus_val16 * OPUS_RESTRICT wp2 = window+overlap-1; + + for(i = 0; i < overlap/2; i++) + { + kiss_fft_scalar x1, x2; + x1 = *xp1; + x2 = *yp1; + *yp1++ = SUB32_ovflw(MULT16_32_Q15(*wp2, x2), MULT16_32_Q15(*wp1, x1)); + *xp1-- = ADD32_ovflw(MULT16_32_Q15(*wp1, x2), MULT16_32_Q15(*wp2, x1)); + wp1++; + wp2--; + } + } +} +#endif /* OVERRIDE_clt_mdct_backward */ diff --git a/extern/opus/celt/mdct.h b/extern/opus/celt/mdct.h new file mode 100644 index 0000000..160ae4e --- /dev/null +++ b/extern/opus/celt/mdct.h @@ -0,0 +1,112 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2008 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + 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. + + 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 OWNER + 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 is a simple MDCT implementation that uses a N/4 complex FFT + to do most of the work. It should be relatively straightforward to + plug in pretty much and FFT here. + + This replaces the Vorbis FFT (and uses the exact same API), which + was a bit too messy and that was ending up duplicating code + (might as well use the same FFT everywhere). + + The algorithm is similar to (and inspired from) Fabrice Bellard's + MDCT implementation in FFMPEG, but has differences in signs, ordering + and scaling in many places. +*/ + +#ifndef MDCT_H +#define MDCT_H + +#include "opus_defines.h" +#include "kiss_fft.h" +#include "arch.h" + +typedef struct { + int n; + int maxshift; + const kiss_fft_state *kfft[4]; + const kiss_twiddle_scalar * OPUS_RESTRICT trig; +} mdct_lookup; + +#if defined(HAVE_ARM_NE10) +#include "arm/mdct_arm.h" +#endif + + +int clt_mdct_init(mdct_lookup *l,int N, int maxshift, int arch); +void clt_mdct_clear(mdct_lookup *l, int arch); + +/** Compute a forward MDCT and scale by 4/N, trashes the input array */ +void clt_mdct_forward_c(const mdct_lookup *l, kiss_fft_scalar *in, + kiss_fft_scalar * OPUS_RESTRICT out, + const opus_val16 *window, int overlap, + int shift, int stride, int arch); + +/** Compute a backward MDCT (no scaling) and performs weighted overlap-add + (scales implicitly by 1/2) */ +void clt_mdct_backward_c(const mdct_lookup *l, kiss_fft_scalar *in, + kiss_fft_scalar * OPUS_RESTRICT out, + const opus_val16 * OPUS_RESTRICT window, + int overlap, int shift, int stride, int arch); + +#if !defined(OVERRIDE_OPUS_MDCT) +/* Is run-time CPU detection enabled on this platform? */ +#if defined(OPUS_HAVE_RTCD) && defined(HAVE_ARM_NE10) + +extern void (*const CLT_MDCT_FORWARD_IMPL[OPUS_ARCHMASK+1])( + const mdct_lookup *l, kiss_fft_scalar *in, + kiss_fft_scalar * OPUS_RESTRICT out, const opus_val16 *window, + int overlap, int shift, int stride, int arch); + +#define clt_mdct_forward(_l, _in, _out, _window, _overlap, _shift, _stride, _arch) \ + ((*CLT_MDCT_FORWARD_IMPL[(arch)&OPUS_ARCHMASK])(_l, _in, _out, \ + _window, _overlap, _shift, \ + _stride, _arch)) + +extern void (*const CLT_MDCT_BACKWARD_IMPL[OPUS_ARCHMASK+1])( + const mdct_lookup *l, kiss_fft_scalar *in, + kiss_fft_scalar * OPUS_RESTRICT out, const opus_val16 *window, + int overlap, int shift, int stride, int arch); + +#define clt_mdct_backward(_l, _in, _out, _window, _overlap, _shift, _stride, _arch) \ + (*CLT_MDCT_BACKWARD_IMPL[(arch)&OPUS_ARCHMASK])(_l, _in, _out, \ + _window, _overlap, _shift, \ + _stride, _arch) + +#else /* if defined(OPUS_HAVE_RTCD) && defined(HAVE_ARM_NE10) */ + +#define clt_mdct_forward(_l, _in, _out, _window, _overlap, _shift, _stride, _arch) \ + clt_mdct_forward_c(_l, _in, _out, _window, _overlap, _shift, _stride, _arch) + +#define clt_mdct_backward(_l, _in, _out, _window, _overlap, _shift, _stride, _arch) \ + clt_mdct_backward_c(_l, _in, _out, _window, _overlap, _shift, _stride, _arch) + +#endif /* end if defined(OPUS_HAVE_RTCD) && defined(HAVE_ARM_NE10) && !defined(FIXED_POINT) */ +#endif /* end if !defined(OVERRIDE_OPUS_MDCT) */ + +#endif diff --git a/extern/opus/celt/mfrngcod.h b/extern/opus/celt/mfrngcod.h new file mode 100644 index 0000000..809152a --- /dev/null +++ b/extern/opus/celt/mfrngcod.h @@ -0,0 +1,48 @@ +/* Copyright (c) 2001-2008 Timothy B. Terriberry + Copyright (c) 2008-2009 Xiph.Org Foundation */ +/* + 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. + + 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 OWNER + 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. +*/ + +#if !defined(_mfrngcode_H) +# define _mfrngcode_H (1) +# include "entcode.h" + +/*Constants used by the entropy encoder/decoder.*/ + +/*The number of bits to output at a time.*/ +# define EC_SYM_BITS (8) +/*The total number of bits in each of the state registers.*/ +# define EC_CODE_BITS (32) +/*The maximum symbol value.*/ +# define EC_SYM_MAX ((1U<>EC_SYM_BITS) +/*The number of bits available for the last, partial symbol in the code field.*/ +# define EC_CODE_EXTRA ((EC_CODE_BITS-2)%EC_SYM_BITS+1) +#endif diff --git a/extern/opus/celt/mips/celt_mipsr1.h b/extern/opus/celt/mips/celt_mipsr1.h new file mode 100644 index 0000000..c332fe0 --- /dev/null +++ b/extern/opus/celt/mips/celt_mipsr1.h @@ -0,0 +1,152 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2010 Xiph.Org Foundation + Copyright (c) 2008 Gregory Maxwell + Written by Jean-Marc Valin and Gregory Maxwell */ +/* + 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. + + 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 OWNER + 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. +*/ + +#ifndef __CELT_MIPSR1_H__ +#define __CELT_MIPSR1_H__ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#define CELT_C + +#include "os_support.h" +#include "mdct.h" +#include +#include "celt.h" +#include "pitch.h" +#include "bands.h" +#include "modes.h" +#include "entcode.h" +#include "quant_bands.h" +#include "rate.h" +#include "stack_alloc.h" +#include "mathops.h" +#include "float_cast.h" +#include +#include "celt_lpc.h" +#include "vq.h" + +#define OVERRIDE_COMB_FILTER_CONST +#define OVERRIDE_comb_filter +void comb_filter(opus_val32 *y, opus_val32 *x, int T0, int T1, int N, + opus_val16 g0, opus_val16 g1, int tapset0, int tapset1, + const opus_val16 *window, int overlap, int arch) +{ + int i; + opus_val32 x0, x1, x2, x3, x4; + + (void)arch; + + /* printf ("%d %d %f %f\n", T0, T1, g0, g1); */ + opus_val16 g00, g01, g02, g10, g11, g12; + static const opus_val16 gains[3][3] = { + {QCONST16(0.3066406250f, 15), QCONST16(0.2170410156f, 15), QCONST16(0.1296386719f, 15)}, + {QCONST16(0.4638671875f, 15), QCONST16(0.2680664062f, 15), QCONST16(0.f, 15)}, + {QCONST16(0.7998046875f, 15), QCONST16(0.1000976562f, 15), QCONST16(0.f, 15)}}; + + if (g0==0 && g1==0) + { + /* OPT: Happens to work without the OPUS_MOVE(), but only because the current encoder already copies x to y */ + if (x!=y) + OPUS_MOVE(y, x, N); + return; + } + + g00 = MULT16_16_P15(g0, gains[tapset0][0]); + g01 = MULT16_16_P15(g0, gains[tapset0][1]); + g02 = MULT16_16_P15(g0, gains[tapset0][2]); + g10 = MULT16_16_P15(g1, gains[tapset1][0]); + g11 = MULT16_16_P15(g1, gains[tapset1][1]); + g12 = MULT16_16_P15(g1, gains[tapset1][2]); + x1 = x[-T1+1]; + x2 = x[-T1 ]; + x3 = x[-T1-1]; + x4 = x[-T1-2]; + /* If the filter didn't change, we don't need the overlap */ + if (g0==g1 && T0==T1 && tapset0==tapset1) + overlap=0; + + for (i=0;itwiddles[fstride*m]; + yb = st->twiddles[fstride*2*m]; +#endif + + tw=st->twiddles; + + for (i=0;ir += scratch[7].r + scratch[8].r; + Fout0->i += scratch[7].i + scratch[8].i; + scratch[5].r = scratch[0].r + S_MUL_ADD(scratch[7].r,ya.r,scratch[8].r,yb.r); + scratch[5].i = scratch[0].i + S_MUL_ADD(scratch[7].i,ya.r,scratch[8].i,yb.r); + + scratch[6].r = S_MUL_ADD(scratch[10].i,ya.i,scratch[9].i,yb.i); + scratch[6].i = -S_MUL_ADD(scratch[10].r,ya.i,scratch[9].r,yb.i); + + C_SUB(*Fout1,scratch[5],scratch[6]); + C_ADD(*Fout4,scratch[5],scratch[6]); + + scratch[11].r = scratch[0].r + S_MUL_ADD(scratch[7].r,yb.r,scratch[8].r,ya.r); + scratch[11].i = scratch[0].i + S_MUL_ADD(scratch[7].i,yb.r,scratch[8].i,ya.r); + + scratch[12].r = S_MUL_SUB(scratch[9].i,ya.i,scratch[10].i,yb.i); + scratch[12].i = S_MUL_SUB(scratch[10].r,yb.i,scratch[9].r,ya.i); + + C_ADD(*Fout2,scratch[11],scratch[12]); + C_SUB(*Fout3,scratch[11],scratch[12]); + + ++Fout0;++Fout1;++Fout2;++Fout3;++Fout4; + } + } +} + + +#endif /* KISS_FFT_MIPSR1_H */ diff --git a/extern/opus/celt/mips/mdct_mipsr1.h b/extern/opus/celt/mips/mdct_mipsr1.h new file mode 100644 index 0000000..2934dab --- /dev/null +++ b/extern/opus/celt/mips/mdct_mipsr1.h @@ -0,0 +1,288 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2008 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + 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. + + 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 OWNER + 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 is a simple MDCT implementation that uses a N/4 complex FFT + to do most of the work. It should be relatively straightforward to + plug in pretty much and FFT here. + + This replaces the Vorbis FFT (and uses the exact same API), which + was a bit too messy and that was ending up duplicating code + (might as well use the same FFT everywhere). + + The algorithm is similar to (and inspired from) Fabrice Bellard's + MDCT implementation in FFMPEG, but has differences in signs, ordering + and scaling in many places. +*/ +#ifndef __MDCT_MIPSR1_H__ +#define __MDCT_MIPSR1_H__ + +#ifndef SKIP_CONFIG_H +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#endif + +#include "mdct.h" +#include "kiss_fft.h" +#include "_kiss_fft_guts.h" +#include +#include "os_support.h" +#include "mathops.h" +#include "stack_alloc.h" + +/* Forward MDCT trashes the input array */ +#define OVERRIDE_clt_mdct_forward +void clt_mdct_forward(const mdct_lookup *l, kiss_fft_scalar *in, kiss_fft_scalar * OPUS_RESTRICT out, + const opus_val16 *window, int overlap, int shift, int stride, int arch) +{ + int i; + int N, N2, N4; + VARDECL(kiss_fft_scalar, f); + VARDECL(kiss_fft_cpx, f2); + const kiss_fft_state *st = l->kfft[shift]; + const kiss_twiddle_scalar *trig; + opus_val16 scale; +#ifdef FIXED_POINT + /* Allows us to scale with MULT16_32_Q16(), which is faster than + MULT16_32_Q15() on ARM. */ + int scale_shift = st->scale_shift-1; +#endif + + (void)arch; + + SAVE_STACK; + scale = st->scale; + + N = l->n; + trig = l->trig; + for (i=0;i>= 1; + trig += N; + } + N2 = N>>1; + N4 = N>>2; + + ALLOC(f, N2, kiss_fft_scalar); + ALLOC(f2, N4, kiss_fft_cpx); + + /* Consider the input to be composed of four blocks: [a, b, c, d] */ + /* Window, shuffle, fold */ + { + /* Temp pointers to make it really clear to the compiler what we're doing */ + const kiss_fft_scalar * OPUS_RESTRICT xp1 = in+(overlap>>1); + const kiss_fft_scalar * OPUS_RESTRICT xp2 = in+N2-1+(overlap>>1); + kiss_fft_scalar * OPUS_RESTRICT yp = f; + const opus_val16 * OPUS_RESTRICT wp1 = window+(overlap>>1); + const opus_val16 * OPUS_RESTRICT wp2 = window+(overlap>>1)-1; + for(i=0;i<((overlap+3)>>2);i++) + { + /* Real part arranged as -d-cR, Imag part arranged as -b+aR*/ + *yp++ = S_MUL_ADD(*wp2, xp1[N2],*wp1,*xp2); + *yp++ = S_MUL_SUB(*wp1, *xp1,*wp2, xp2[-N2]); + xp1+=2; + xp2-=2; + wp1+=2; + wp2-=2; + } + wp1 = window; + wp2 = window+overlap-1; + for(;i>2);i++) + { + /* Real part arranged as a-bR, Imag part arranged as -c-dR */ + *yp++ = *xp2; + *yp++ = *xp1; + xp1+=2; + xp2-=2; + } + for(;ibitrev[i]] = yc; + } + } + + /* N/4 complex FFT, does not downscale anymore */ + opus_fft_impl(st, f2); + + /* Post-rotate */ + { + /* Temp pointers to make it really clear to the compiler what we're doing */ + const kiss_fft_cpx * OPUS_RESTRICT fp = f2; + kiss_fft_scalar * OPUS_RESTRICT yp1 = out; + kiss_fft_scalar * OPUS_RESTRICT yp2 = out+stride*(N2-1); + const kiss_twiddle_scalar *t = &trig[0]; + /* Temp pointers to make it really clear to the compiler what we're doing */ + for(i=0;ii,t[N4+i] , fp->r,t[i]); + yi = S_MUL_ADD(fp->r,t[N4+i] ,fp->i,t[i]); + *yp1 = yr; + *yp2 = yi; + fp++; + yp1 += 2*stride; + yp2 -= 2*stride; + } + } + RESTORE_STACK; +} + +#define OVERRIDE_clt_mdct_backward +void clt_mdct_backward(const mdct_lookup *l, kiss_fft_scalar *in, kiss_fft_scalar * OPUS_RESTRICT out, + const opus_val16 * OPUS_RESTRICT window, int overlap, int shift, int stride, int arch) +{ + int i; + int N, N2, N4; + const kiss_twiddle_scalar *trig; + + (void)arch; + + N = l->n; + trig = l->trig; + for (i=0;i>= 1; + trig += N; + } + N2 = N>>1; + N4 = N>>2; + + /* Pre-rotate */ + { + /* Temp pointers to make it really clear to the compiler what we're doing */ + const kiss_fft_scalar * OPUS_RESTRICT xp1 = in; + const kiss_fft_scalar * OPUS_RESTRICT xp2 = in+stride*(N2-1); + kiss_fft_scalar * OPUS_RESTRICT yp = out+(overlap>>1); + const kiss_twiddle_scalar * OPUS_RESTRICT t = &trig[0]; + const opus_int16 * OPUS_RESTRICT bitrev = l->kfft[shift]->bitrev; + for(i=0;ikfft[shift], (kiss_fft_cpx*)(out+(overlap>>1))); + + /* Post-rotate and de-shuffle from both ends of the buffer at once to make + it in-place. */ + { + kiss_fft_scalar * OPUS_RESTRICT yp0 = out+(overlap>>1); + kiss_fft_scalar * OPUS_RESTRICT yp1 = out+(overlap>>1)+N2-2; + const kiss_twiddle_scalar *t = &trig[0]; + /* Loop to (N4+1)>>1 to handle odd N4. When N4 is odd, the + middle pair will be computed twice. */ + for(i=0;i<(N4+1)>>1;i++) + { + kiss_fft_scalar re, im, yr, yi; + kiss_twiddle_scalar t0, t1; + /* We swap real and imag because we're using an FFT instead of an IFFT. */ + re = yp0[1]; + im = yp0[0]; + t0 = t[i]; + t1 = t[N4+i]; + /* We'd scale up by 2 here, but instead it's done when mixing the windows */ + yr = S_MUL_ADD(re,t0 , im,t1); + yi = S_MUL_SUB(re,t1 , im,t0); + /* We swap real and imag because we're using an FFT instead of an IFFT. */ + re = yp1[1]; + im = yp1[0]; + yp0[0] = yr; + yp1[1] = yi; + + t0 = t[(N4-i-1)]; + t1 = t[(N2-i-1)]; + /* We'd scale up by 2 here, but instead it's done when mixing the windows */ + yr = S_MUL_ADD(re,t0,im,t1); + yi = S_MUL_SUB(re,t1,im,t0); + yp1[0] = yr; + yp0[1] = yi; + yp0 += 2; + yp1 -= 2; + } + } + + /* Mirror on both sides for TDAC */ + { + kiss_fft_scalar * OPUS_RESTRICT xp1 = out+overlap-1; + kiss_fft_scalar * OPUS_RESTRICT yp1 = out; + const opus_val16 * OPUS_RESTRICT wp1 = window; + const opus_val16 * OPUS_RESTRICT wp2 = window+overlap-1; + + for(i = 0; i < overlap/2; i++) + { + kiss_fft_scalar x1, x2; + x1 = *xp1; + x2 = *yp1; + *yp1++ = MULT16_32_Q15(*wp2, x2) - MULT16_32_Q15(*wp1, x1); + *xp1-- = MULT16_32_Q15(*wp1, x2) + MULT16_32_Q15(*wp2, x1); + wp1++; + wp2--; + } + } +} +#endif /* __MDCT_MIPSR1_H__ */ diff --git a/extern/opus/celt/mips/pitch_mipsr1.h b/extern/opus/celt/mips/pitch_mipsr1.h new file mode 100644 index 0000000..a9500af --- /dev/null +++ b/extern/opus/celt/mips/pitch_mipsr1.h @@ -0,0 +1,161 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/** + @file pitch.h + @brief Pitch analysis + */ + +/* + 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. + + 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 OWNER + 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. +*/ + +#ifndef PITCH_MIPSR1_H +#define PITCH_MIPSR1_H + +#define OVERRIDE_DUAL_INNER_PROD +static inline void dual_inner_prod(const opus_val16 *x, const opus_val16 *y01, const opus_val16 *y02, + int N, opus_val32 *xy1, opus_val32 *xy2, int arch) +{ + int j; + opus_val32 xy01=0; + opus_val32 xy02=0; + + (void)arch; + + asm volatile("MULT $ac1, $0, $0"); + asm volatile("MULT $ac2, $0, $0"); + /* Compute the norm of X+Y and X-Y as |X|^2 + |Y|^2 +/- sum(xy) */ + for (j=0;j=0;i--) + { + celt_norm x1, x2; + x1 = Xptr[0]; + x2 = Xptr[stride]; + Xptr[stride] = EXTRACT16(PSHR32(MAC16_16(MULT16_16(c, x2), s, x1), 15)); + *Xptr-- = EXTRACT16(PSHR32(MAC16_16(MULT16_16(c, x1), ms, x2), 15)); + } +} + +#define OVERRIDE_renormalise_vector +void renormalise_vector(celt_norm *X, int N, opus_val16 gain, int arch) +{ + int i; +#ifdef FIXED_POINT + int k; +#endif + opus_val32 E = EPSILON; + opus_val16 g; + opus_val32 t; + celt_norm *xptr = X; + int X0, X1; + + (void)arch; + + asm volatile("mult $ac1, $0, $0"); + asm volatile("MTLO %0, $ac1" : :"r" (E)); + /*if(N %4) + printf("error");*/ + for (i=0;i>1; +#endif + t = VSHR32(E, 2*(k-7)); + g = MULT16_16_P15(celt_rsqrt_norm(t),gain); + + xptr = X; + for (i=0;i= Fs) + break; + + /* Find where the linear part ends (i.e. where the spacing is more than min_width */ + for (lin=0;lin= res) + break; + + low = (bark_freq[lin]+res/2)/res; + high = nBark-lin; + *nbEBands = low+high; + eBands = opus_alloc(sizeof(opus_int16)*(*nbEBands+2)); + + if (eBands==NULL) + return NULL; + + /* Linear spacing (min_width) */ + for (i=0;i0) + offset = eBands[low-1]*res - bark_freq[lin-1]; + /* Spacing follows critical bands */ + for (i=0;i frame_size) + eBands[*nbEBands] = frame_size; + for (i=1;i<*nbEBands-1;i++) + { + if (eBands[i+1]-eBands[i] < eBands[i]-eBands[i-1]) + { + eBands[i] -= (2*eBands[i]-eBands[i-1]-eBands[i+1])/2; + } + } + /* Remove any empty bands. */ + for (i=j=0;i<*nbEBands;i++) + if(eBands[i+1]>eBands[j]) + eBands[++j]=eBands[i+1]; + *nbEBands=j; + + for (i=1;i<*nbEBands;i++) + { + /* Every band must be smaller than the last band. */ + celt_assert(eBands[i]-eBands[i-1]<=eBands[*nbEBands]-eBands[*nbEBands-1]); + /* Each band must be no larger than twice the size of the previous one. */ + celt_assert(eBands[i+1]-eBands[i]<=2*(eBands[i]-eBands[i-1])); + } + + return eBands; +} + +static void compute_allocation_table(CELTMode *mode) +{ + int i, j; + unsigned char *allocVectors; + int maxBands = sizeof(eband5ms)/sizeof(eband5ms[0])-1; + + mode->nbAllocVectors = BITALLOC_SIZE; + allocVectors = opus_alloc(sizeof(unsigned char)*(BITALLOC_SIZE*mode->nbEBands)); + if (allocVectors==NULL) + return; + + /* Check for standard mode */ + if (mode->Fs == 400*(opus_int32)mode->shortMdctSize) + { + for (i=0;inbEBands;i++) + allocVectors[i] = band_allocation[i]; + mode->allocVectors = allocVectors; + return; + } + /* If not the standard mode, interpolate */ + /* Compute per-codec-band allocation from per-critical-band matrix */ + for (i=0;inbEBands;j++) + { + int k; + for (k=0;k mode->eBands[j]*(opus_int32)mode->Fs/mode->shortMdctSize) + break; + } + if (k>maxBands-1) + allocVectors[i*mode->nbEBands+j] = band_allocation[i*maxBands + maxBands-1]; + else { + opus_int32 a0, a1; + a1 = mode->eBands[j]*(opus_int32)mode->Fs/mode->shortMdctSize - 400*(opus_int32)eband5ms[k-1]; + a0 = 400*(opus_int32)eband5ms[k] - mode->eBands[j]*(opus_int32)mode->Fs/mode->shortMdctSize; + allocVectors[i*mode->nbEBands+j] = (a0*band_allocation[i*maxBands+k-1] + + a1*band_allocation[i*maxBands+k])/(a0+a1); + } + } + } + + /*printf ("\n"); + for (i=0;inbEBands;j++) + printf ("%d ", allocVectors[i*mode->nbEBands+j]); + printf ("\n"); + } + exit(0);*/ + + mode->allocVectors = allocVectors; +} + +#endif /* CUSTOM_MODES */ + +CELTMode *opus_custom_mode_create(opus_int32 Fs, int frame_size, int *error) +{ + int i; +#ifdef CUSTOM_MODES + CELTMode *mode=NULL; + int res; + opus_val16 *window; + opus_int16 *logN; + int LM; + int arch = opus_select_arch(); + ALLOC_STACK; +#if !defined(VAR_ARRAYS) && !defined(USE_ALLOCA) + if (global_stack==NULL) + goto failure; +#endif +#endif + +#ifndef CUSTOM_MODES_ONLY + for (i=0;iFs && + (frame_size<shortMdctSize*static_mode_list[i]->nbShortMdcts) + { + if (error) + *error = OPUS_OK; + return (CELTMode*)static_mode_list[i]; + } + } + } +#endif /* CUSTOM_MODES_ONLY */ + +#ifndef CUSTOM_MODES + if (error) + *error = OPUS_BAD_ARG; + return NULL; +#else + + /* The good thing here is that permutation of the arguments will automatically be invalid */ + + if (Fs < 8000 || Fs > 96000) + { + if (error) + *error = OPUS_BAD_ARG; + return NULL; + } + if (frame_size < 40 || frame_size > 1024 || frame_size%2!=0) + { + if (error) + *error = OPUS_BAD_ARG; + return NULL; + } + /* Frames of less than 1ms are not supported. */ + if ((opus_int32)frame_size*1000 < Fs) + { + if (error) + *error = OPUS_BAD_ARG; + return NULL; + } + + if ((opus_int32)frame_size*75 >= Fs && (frame_size%16)==0) + { + LM = 3; + } else if ((opus_int32)frame_size*150 >= Fs && (frame_size%8)==0) + { + LM = 2; + } else if ((opus_int32)frame_size*300 >= Fs && (frame_size%4)==0) + { + LM = 1; + } else + { + LM = 0; + } + + /* Shorts longer than 3.3ms are not supported. */ + if ((opus_int32)(frame_size>>LM)*300 > Fs) + { + if (error) + *error = OPUS_BAD_ARG; + return NULL; + } + + mode = opus_alloc(sizeof(CELTMode)); + if (mode==NULL) + goto failure; + mode->Fs = Fs; + + /* Pre/de-emphasis depends on sampling rate. The "standard" pre-emphasis + is defined as A(z) = 1 - 0.85*z^-1 at 48 kHz. Other rates should + approximate that. */ + if(Fs < 12000) /* 8 kHz */ + { + mode->preemph[0] = QCONST16(0.3500061035f, 15); + mode->preemph[1] = -QCONST16(0.1799926758f, 15); + mode->preemph[2] = QCONST16(0.2719968125f, SIG_SHIFT); /* exact 1/preemph[3] */ + mode->preemph[3] = QCONST16(3.6765136719f, 13); + } else if(Fs < 24000) /* 16 kHz */ + { + mode->preemph[0] = QCONST16(0.6000061035f, 15); + mode->preemph[1] = -QCONST16(0.1799926758f, 15); + mode->preemph[2] = QCONST16(0.4424998650f, SIG_SHIFT); /* exact 1/preemph[3] */ + mode->preemph[3] = QCONST16(2.2598876953f, 13); + } else if(Fs < 40000) /* 32 kHz */ + { + mode->preemph[0] = QCONST16(0.7799987793f, 15); + mode->preemph[1] = -QCONST16(0.1000061035f, 15); + mode->preemph[2] = QCONST16(0.7499771125f, SIG_SHIFT); /* exact 1/preemph[3] */ + mode->preemph[3] = QCONST16(1.3333740234f, 13); + } else /* 48 kHz */ + { + mode->preemph[0] = QCONST16(0.8500061035f, 15); + mode->preemph[1] = QCONST16(0.0f, 15); + mode->preemph[2] = QCONST16(1.f, SIG_SHIFT); + mode->preemph[3] = QCONST16(1.f, 13); + } + + mode->maxLM = LM; + mode->nbShortMdcts = 1<shortMdctSize = frame_size/mode->nbShortMdcts; + res = (mode->Fs+mode->shortMdctSize)/(2*mode->shortMdctSize); + + mode->eBands = compute_ebands(Fs, mode->shortMdctSize, res, &mode->nbEBands); + if (mode->eBands==NULL) + goto failure; +#if !defined(SMALL_FOOTPRINT) + /* Make sure we don't allocate a band larger than our PVQ table. + 208 should be enough, but let's be paranoid. */ + if ((mode->eBands[mode->nbEBands] - mode->eBands[mode->nbEBands-1])< + 208) { + goto failure; + } +#endif + + mode->effEBands = mode->nbEBands; + while (mode->eBands[mode->effEBands] > mode->shortMdctSize) + mode->effEBands--; + + /* Overlap must be divisible by 4 */ + mode->overlap = ((mode->shortMdctSize>>2)<<2); + + compute_allocation_table(mode); + if (mode->allocVectors==NULL) + goto failure; + + window = (opus_val16*)opus_alloc(mode->overlap*sizeof(opus_val16)); + if (window==NULL) + goto failure; + +#ifndef FIXED_POINT + for (i=0;ioverlap;i++) + window[i] = Q15ONE*sin(.5*M_PI* sin(.5*M_PI*(i+.5)/mode->overlap) * sin(.5*M_PI*(i+.5)/mode->overlap)); +#else + for (i=0;ioverlap;i++) + window[i] = MIN32(32767,floor(.5+32768.*sin(.5*M_PI* sin(.5*M_PI*(i+.5)/mode->overlap) * sin(.5*M_PI*(i+.5)/mode->overlap)))); +#endif + mode->window = window; + + logN = (opus_int16*)opus_alloc(mode->nbEBands*sizeof(opus_int16)); + if (logN==NULL) + goto failure; + + for (i=0;inbEBands;i++) + logN[i] = log2_frac(mode->eBands[i+1]-mode->eBands[i], BITRES); + mode->logN = logN; + + compute_pulse_cache(mode, mode->maxLM); + + if (clt_mdct_init(&mode->mdct, 2*mode->shortMdctSize*mode->nbShortMdcts, + mode->maxLM, arch) == 0) + goto failure; + + if (error) + *error = OPUS_OK; + + return mode; +failure: + if (error) + *error = OPUS_ALLOC_FAIL; + if (mode!=NULL) + opus_custom_mode_destroy(mode); + return NULL; +#endif /* !CUSTOM_MODES */ +} + +#ifdef CUSTOM_MODES +void opus_custom_mode_destroy(CELTMode *mode) +{ + int arch = opus_select_arch(); + + if (mode == NULL) + return; +#ifndef CUSTOM_MODES_ONLY + { + int i; + for (i=0;ieBands); + opus_free((unsigned char*)mode->allocVectors); + + opus_free((opus_val16*)mode->window); + opus_free((opus_int16*)mode->logN); + + opus_free((opus_int16*)mode->cache.index); + opus_free((unsigned char*)mode->cache.bits); + opus_free((unsigned char*)mode->cache.caps); + clt_mdct_clear(&mode->mdct, arch); + + opus_free((CELTMode *)mode); +} +#endif diff --git a/extern/opus/celt/modes.h b/extern/opus/celt/modes.h new file mode 100644 index 0000000..be813cc --- /dev/null +++ b/extern/opus/celt/modes.h @@ -0,0 +1,75 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Copyright (c) 2008 Gregory Maxwell + Written by Jean-Marc Valin and Gregory Maxwell */ +/* + 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. + + 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 OWNER + 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. +*/ + +#ifndef MODES_H +#define MODES_H + +#include "opus_types.h" +#include "celt.h" +#include "arch.h" +#include "mdct.h" +#include "entenc.h" +#include "entdec.h" + +#define MAX_PERIOD 1024 + +typedef struct { + int size; + const opus_int16 *index; + const unsigned char *bits; + const unsigned char *caps; +} PulseCache; + +/** Mode definition (opaque) + @brief Mode definition + */ +struct OpusCustomMode { + opus_int32 Fs; + int overlap; + + int nbEBands; + int effEBands; + opus_val16 preemph[4]; + const opus_int16 *eBands; /**< Definition for each "pseudo-critical band" */ + + int maxLM; + int nbShortMdcts; + int shortMdctSize; + + int nbAllocVectors; /**< Number of lines in the matrix below */ + const unsigned char *allocVectors; /**< Number of bits in each band for several rates */ + const opus_int16 *logN; + + const opus_val16 *window; + mdct_lookup mdct; + PulseCache cache; +}; + + +#endif diff --git a/extern/opus/celt/opus_custom_demo.c b/extern/opus/celt/opus_custom_demo.c new file mode 100644 index 0000000..ae41c0d --- /dev/null +++ b/extern/opus/celt/opus_custom_demo.c @@ -0,0 +1,210 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + 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. + + 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 OWNER + 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. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "opus_custom.h" +#include "arch.h" +#include +#include +#include +#include + +#define MAX_PACKET 1275 + +int main(int argc, char *argv[]) +{ + int err; + char *inFile, *outFile; + FILE *fin, *fout; + OpusCustomMode *mode=NULL; + OpusCustomEncoder *enc; + OpusCustomDecoder *dec; + int len; + opus_int32 frame_size, channels, rate; + int bytes_per_packet; + unsigned char data[MAX_PACKET]; + int complexity; +#if !(defined (FIXED_POINT) && !defined(CUSTOM_MODES)) && defined(RESYNTH) + int i; + double rmsd = 0; +#endif + int count = 0; + opus_int32 skip; + opus_int16 *in, *out; + if (argc != 9 && argc != 8 && argc != 7) + { + fprintf (stderr, "Usage: test_opus_custom " + " [ [packet loss rate]] " + " \n"); + return 1; + } + + rate = (opus_int32)atol(argv[1]); + channels = atoi(argv[2]); + frame_size = atoi(argv[3]); + mode = opus_custom_mode_create(rate, frame_size, NULL); + if (mode == NULL) + { + fprintf(stderr, "failed to create a mode\n"); + return 1; + } + + bytes_per_packet = atoi(argv[4]); + if (bytes_per_packet < 0 || bytes_per_packet > MAX_PACKET) + { + fprintf (stderr, "bytes per packet must be between 0 and %d\n", + MAX_PACKET); + return 1; + } + + inFile = argv[argc-2]; + fin = fopen(inFile, "rb"); + if (!fin) + { + fprintf (stderr, "Could not open input file %s\n", argv[argc-2]); + return 1; + } + outFile = argv[argc-1]; + fout = fopen(outFile, "wb+"); + if (!fout) + { + fprintf (stderr, "Could not open output file %s\n", argv[argc-1]); + fclose(fin); + return 1; + } + + enc = opus_custom_encoder_create(mode, channels, &err); + if (err != 0) + { + fprintf(stderr, "Failed to create the encoder: %s\n", opus_strerror(err)); + fclose(fin); + fclose(fout); + return 1; + } + dec = opus_custom_decoder_create(mode, channels, &err); + if (err != 0) + { + fprintf(stderr, "Failed to create the decoder: %s\n", opus_strerror(err)); + fclose(fin); + fclose(fout); + return 1; + } + opus_custom_decoder_ctl(dec, OPUS_GET_LOOKAHEAD(&skip)); + + if (argc>7) + { + complexity=atoi(argv[5]); + opus_custom_encoder_ctl(enc,OPUS_SET_COMPLEXITY(complexity)); + } + + in = (opus_int16*)malloc(frame_size*channels*sizeof(opus_int16)); + out = (opus_int16*)malloc(frame_size*channels*sizeof(opus_int16)); + + while (!feof(fin)) + { + int ret; + err = fread(in, sizeof(short), frame_size*channels, fin); + if (feof(fin)) + break; + len = opus_custom_encode(enc, in, frame_size, data, bytes_per_packet); + if (len <= 0) + fprintf (stderr, "opus_custom_encode() failed: %s\n", opus_strerror(len)); + + /* This is for simulating bit errors */ +#if 0 + int errors = 0; + int eid = 0; + /* This simulates random bit error */ + for (i=0;i 0) + { + rmsd = sqrt(rmsd/(1.0*frame_size*channels*count)); + fprintf (stderr, "Error: encoder doesn't match decoder\n"); + fprintf (stderr, "RMS mismatch is %f\n", rmsd); + return 1; + } else { + fprintf (stderr, "Encoder matches decoder!!\n"); + } +#endif + return 0; +} + diff --git a/extern/opus/celt/os_support.h b/extern/opus/celt/os_support.h new file mode 100644 index 0000000..a217197 --- /dev/null +++ b/extern/opus/celt/os_support.h @@ -0,0 +1,92 @@ +/* Copyright (C) 2007 Jean-Marc Valin + + File: os_support.h + This is the (tiny) OS abstraction layer. Aside from math.h, this is the + only place where system headers are allowed. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef OS_SUPPORT_H +#define OS_SUPPORT_H + +#ifdef CUSTOM_SUPPORT +# include "custom_support.h" +#endif + +#include "opus_types.h" +#include "opus_defines.h" + +#include +#include +#include + +/** Opus wrapper for malloc(). To do your own dynamic allocation, all you need to do is replace this function and opus_free */ +#ifndef OVERRIDE_OPUS_ALLOC +static OPUS_INLINE void *opus_alloc (size_t size) +{ + return malloc(size); +} +#endif + +/** Same as celt_alloc(), except that the area is only needed inside a CELT call (might cause problem with wideband though) */ +#ifndef OVERRIDE_OPUS_ALLOC_SCRATCH +static OPUS_INLINE void *opus_alloc_scratch (size_t size) +{ + /* Scratch space doesn't need to be cleared */ + return opus_alloc(size); +} +#endif + +/** Opus wrapper for free(). To do your own dynamic allocation, all you need to do is replace this function and opus_alloc */ +#ifndef OVERRIDE_OPUS_FREE +static OPUS_INLINE void opus_free (void *ptr) +{ + free(ptr); +} +#endif + +/** Copy n elements from src to dst. The 0* term provides compile-time type checking */ +#ifndef OVERRIDE_OPUS_COPY +#define OPUS_COPY(dst, src, n) (memcpy((dst), (src), (n)*sizeof(*(dst)) + 0*((dst)-(src)) )) +#endif + +/** Copy n elements from src to dst, allowing overlapping regions. The 0* term + provides compile-time type checking */ +#ifndef OVERRIDE_OPUS_MOVE +#define OPUS_MOVE(dst, src, n) (memmove((dst), (src), (n)*sizeof(*(dst)) + 0*((dst)-(src)) )) +#endif + +/** Set n elements of dst to zero */ +#ifndef OVERRIDE_OPUS_CLEAR +#define OPUS_CLEAR(dst, n) (memset((dst), 0, (n)*sizeof(*(dst)))) +#endif + +/*#ifdef __GNUC__ +#pragma GCC poison printf sprintf +#pragma GCC poison malloc free realloc calloc +#endif*/ + +#endif /* OS_SUPPORT_H */ + diff --git a/extern/opus/celt/pitch.c b/extern/opus/celt/pitch.c new file mode 100644 index 0000000..872582a --- /dev/null +++ b/extern/opus/celt/pitch.c @@ -0,0 +1,537 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/** + @file pitch.c + @brief Pitch analysis + */ + +/* + 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. + + 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 OWNER + 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. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "pitch.h" +#include "os_support.h" +#include "modes.h" +#include "stack_alloc.h" +#include "mathops.h" +#include "celt_lpc.h" + +static void find_best_pitch(opus_val32 *xcorr, opus_val16 *y, int len, + int max_pitch, int *best_pitch +#ifdef FIXED_POINT + , int yshift, opus_val32 maxcorr +#endif + ) +{ + int i, j; + opus_val32 Syy=1; + opus_val16 best_num[2]; + opus_val32 best_den[2]; +#ifdef FIXED_POINT + int xshift; + + xshift = celt_ilog2(maxcorr)-14; +#endif + + best_num[0] = -1; + best_num[1] = -1; + best_den[0] = 0; + best_den[1] = 0; + best_pitch[0] = 0; + best_pitch[1] = 1; + for (j=0;j0) + { + opus_val16 num; + opus_val32 xcorr16; + xcorr16 = EXTRACT16(VSHR32(xcorr[i], xshift)); +#ifndef FIXED_POINT + /* Considering the range of xcorr16, this should avoid both underflows + and overflows (inf) when squaring xcorr16 */ + xcorr16 *= 1e-12f; +#endif + num = MULT16_16_Q15(xcorr16,xcorr16); + if (MULT16_32_Q15(num,best_den[1]) > MULT16_32_Q15(best_num[1],Syy)) + { + if (MULT16_32_Q15(num,best_den[0]) > 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 += SHR32(MULT16_16(y[i+len],y[i+len]),yshift) - SHR32(MULT16_16(y[i],y[i]),yshift); + Syy = MAX32(1, Syy); + } +} + +static void celt_fir5(opus_val16 *x, + const opus_val16 *num, + int N) +{ + int i; + opus_val16 num0, num1, num2, num3, num4; + opus_val32 mem0, mem1, mem2, mem3, mem4; + num0=num[0]; + num1=num[1]; + num2=num[2]; + num3=num[3]; + num4=num[4]; + mem0=0; + mem1=0; + mem2=0; + mem3=0; + mem4=0; + for (i=0;i>1;i++) + x_lp[i] = SHR32(HALF32(HALF32(x[0][(2*i-1)]+x[0][(2*i+1)])+x[0][2*i]), shift); + x_lp[0] = SHR32(HALF32(HALF32(x[0][1])+x[0][0]), shift); + if (C==2) + { + for (i=1;i>1;i++) + x_lp[i] += SHR32(HALF32(HALF32(x[1][(2*i-1)]+x[1][(2*i+1)])+x[1][2*i]), shift); + x_lp[0] += SHR32(HALF32(HALF32(x[1][1])+x[1][0]), shift); + } + + _celt_autocorr(x_lp, ac, NULL, 0, + 4, len>>1, arch); + + /* Noise floor -40 dB */ +#ifdef FIXED_POINT + ac[0] += SHR32(ac[0],13); +#else + ac[0] *= 1.0001f; +#endif + /* Lag windowing */ + for (i=1;i<=4;i++) + { + /*ac[i] *= exp(-.5*(2*M_PI*.002*i)*(2*M_PI*.002*i));*/ +#ifdef FIXED_POINT + ac[i] -= MULT16_32_Q15(2*i*i, ac[i]); +#else + ac[i] -= ac[i]*(.008f*i)*(.008f*i); +#endif + } + + _celt_lpc(lpc, ac, 4); + for (i=0;i<4;i++) + { + tmp = MULT16_16_Q15(QCONST16(.9f,15), tmp); + lpc[i] = MULT16_16_Q15(lpc[i], tmp); + } + /* Add a zero */ + lpc2[0] = lpc[0] + QCONST16(.8f,SIG_SHIFT); + lpc2[1] = lpc[1] + MULT16_16_Q15(c1,lpc[0]); + lpc2[2] = lpc[2] + MULT16_16_Q15(c1,lpc[1]); + lpc2[3] = lpc[3] + MULT16_16_Q15(c1,lpc[2]); + lpc2[4] = MULT16_16_Q15(c1,lpc[3]); + celt_fir5(x_lp, lpc2, len>>1); +} + +/* Pure C implementation. */ +#ifdef FIXED_POINT +opus_val32 +#else +void +#endif +celt_pitch_xcorr_c(const opus_val16 *_x, const opus_val16 *_y, + opus_val32 *xcorr, int len, int max_pitch, int arch) +{ + +#if 0 /* This is a simple version of the pitch correlation that should work + well on DSPs like Blackfin and TI C5x/C6x */ + int i, j; +#ifdef FIXED_POINT + opus_val32 maxcorr=1; +#endif +#if !defined(OVERRIDE_PITCH_XCORR) + (void)arch; +#endif + for (i=0;i0); + celt_sig_assert((((unsigned char *)_x-(unsigned char *)NULL)&3)==0); + for (i=0;i0); + celt_assert(max_pitch>0); + lag = len+max_pitch; + + ALLOC(x_lp4, len>>2, opus_val16); + ALLOC(y_lp4, lag>>2, opus_val16); + ALLOC(xcorr, max_pitch>>1, opus_val32); + + /* Downsample by 2 again */ + for (j=0;j>2;j++) + x_lp4[j] = x_lp[2*j]; + for (j=0;j>2;j++) + y_lp4[j] = y[2*j]; + +#ifdef FIXED_POINT + xmax = celt_maxabs16(x_lp4, len>>2); + ymax = celt_maxabs16(y_lp4, lag>>2); + shift = celt_ilog2(MAX32(1, MAX32(xmax, ymax)))-11; + if (shift>0) + { + for (j=0;j>2;j++) + x_lp4[j] = SHR16(x_lp4[j], shift); + for (j=0;j>2;j++) + y_lp4[j] = SHR16(y_lp4[j], shift); + /* Use double the shift for a MAC */ + shift *= 2; + } else { + shift = 0; + } +#endif + + /* Coarse search with 4x decimation */ + +#ifdef FIXED_POINT + maxcorr = +#endif + celt_pitch_xcorr(x_lp4, y_lp4, xcorr, len>>2, max_pitch>>2, arch); + + find_best_pitch(xcorr, y_lp4, len>>2, max_pitch>>2, best_pitch +#ifdef FIXED_POINT + , 0, maxcorr +#endif + ); + + /* Finer search with 2x decimation */ +#ifdef FIXED_POINT + maxcorr=1; +#endif + for (i=0;i>1;i++) + { + opus_val32 sum; + xcorr[i] = 0; + if (abs(i-2*best_pitch[0])>2 && abs(i-2*best_pitch[1])>2) + continue; +#ifdef FIXED_POINT + sum = 0; + for (j=0;j>1;j++) + sum += SHR32(MULT16_16(x_lp[j],y[i+j]), shift); +#else + sum = celt_inner_prod(x_lp, y+i, len>>1, arch); +#endif + xcorr[i] = MAX32(-1, sum); +#ifdef FIXED_POINT + maxcorr = MAX32(maxcorr, sum); +#endif + } + find_best_pitch(xcorr, y, len>>1, max_pitch>>1, best_pitch +#ifdef FIXED_POINT + , shift+1, maxcorr +#endif + ); + + /* Refine by pseudo-interpolation */ + if (best_pitch[0]>0 && best_pitch[0]<(max_pitch>>1)-1) + { + opus_val32 a, b, c; + a = xcorr[best_pitch[0]-1]; + b = xcorr[best_pitch[0]]; + c = xcorr[best_pitch[0]+1]; + if ((c-a) > MULT16_32_Q15(QCONST16(.7f,15),b-a)) + offset = 1; + else if ((a-c) > MULT16_32_Q15(QCONST16(.7f,15),b-c)) + offset = -1; + else + offset = 0; + } else { + offset = 0; + } + *pitch = 2*best_pitch[0]-offset; + + RESTORE_STACK; +} + +#ifdef FIXED_POINT +static opus_val16 compute_pitch_gain(opus_val32 xy, opus_val32 xx, opus_val32 yy) +{ + opus_val32 x2y2; + int sx, sy, shift; + opus_val32 g; + opus_val16 den; + if (xy == 0 || xx == 0 || yy == 0) + return 0; + sx = celt_ilog2(xx)-14; + sy = celt_ilog2(yy)-14; + shift = sx + sy; + x2y2 = SHR32(MULT16_16(VSHR32(xx, sx), VSHR32(yy, sy)), 14); + if (shift & 1) { + if (x2y2 < 32768) + { + x2y2 <<= 1; + shift--; + } else { + x2y2 >>= 1; + shift++; + } + } + den = celt_rsqrt_norm(x2y2); + g = MULT16_32_Q15(den, xy); + g = VSHR32(g, (shift>>1)-1); + return EXTRACT16(MIN32(g, Q15ONE)); +} +#else +static opus_val16 compute_pitch_gain(opus_val32 xy, opus_val32 xx, opus_val32 yy) +{ + return xy/celt_sqrt(1+xx*yy); +} +#endif + +static const int second_check[16] = {0, 0, 3, 2, 3, 2, 5, 2, 3, 2, 3, 2, 5, 2, 3, 2}; +opus_val16 remove_doubling(opus_val16 *x, int maxperiod, int minperiod, + int N, int *T0_, int prev_period, opus_val16 prev_gain, int arch) +{ + int k, i, T, T0; + opus_val16 g, g0; + opus_val16 pg; + opus_val32 xy,xx,yy,xy2; + opus_val32 xcorr[3]; + opus_val32 best_xy, best_yy; + int offset; + int minperiod0; + VARDECL(opus_val32, yy_lookup); + SAVE_STACK; + + minperiod0 = minperiod; + maxperiod /= 2; + minperiod /= 2; + *T0_ /= 2; + prev_period /= 2; + N /= 2; + x += maxperiod; + if (*T0_>=maxperiod) + *T0_=maxperiod-1; + + T = T0 = *T0_; + ALLOC(yy_lookup, maxperiod+1, opus_val32); + dual_inner_prod(x, x, x-T0, N, &xx, &xy, arch); + yy_lookup[0] = xx; + yy=xx; + for (i=1;i<=maxperiod;i++) + { + yy = yy+MULT16_16(x[-i],x[-i])-MULT16_16(x[N-i],x[N-i]); + yy_lookup[i] = MAX32(0, yy); + } + yy = yy_lookup[T0]; + best_xy = xy; + best_yy = yy; + g = g0 = compute_pitch_gain(xy, xx, yy); + /* Look for any pitch at T/k */ + for (k=2;k<=15;k++) + { + int T1, T1b; + opus_val16 g1; + opus_val16 cont=0; + opus_val16 thresh; + T1 = celt_udiv(2*T0+k, 2*k); + if (T1 < minperiod) + break; + /* Look for another strong correlation at T1b */ + if (k==2) + { + if (T1+T0>maxperiod) + T1b = T0; + else + T1b = T0+T1; + } else + { + T1b = celt_udiv(2*second_check[k]*T0+k, 2*k); + } + dual_inner_prod(x, &x[-T1], &x[-T1b], N, &xy, &xy2, arch); + xy = HALF32(xy + xy2); + yy = HALF32(yy_lookup[T1] + yy_lookup[T1b]); + g1 = compute_pitch_gain(xy, xx, yy); + if (abs(T1-prev_period)<=1) + cont = prev_gain; + else if (abs(T1-prev_period)<=2 && 5*k*k < T0) + cont = HALF16(prev_gain); + else + cont = 0; + thresh = MAX16(QCONST16(.3f,15), MULT16_16_Q15(QCONST16(.7f,15),g0)-cont); + /* Bias against very high pitch (very short period) to avoid false-positives + due to short-term correlation */ + if (T1<3*minperiod) + thresh = MAX16(QCONST16(.4f,15), MULT16_16_Q15(QCONST16(.85f,15),g0)-cont); + else if (T1<2*minperiod) + thresh = MAX16(QCONST16(.5f,15), MULT16_16_Q15(QCONST16(.9f,15),g0)-cont); + if (g1 > thresh) + { + best_xy = xy; + best_yy = yy; + T = T1; + g = g1; + } + } + best_xy = MAX32(0, best_xy); + if (best_yy <= best_xy) + pg = Q15ONE; + else + pg = SHR32(frac_div32(best_xy,best_yy+1),16); + + for (k=0;k<3;k++) + xcorr[k] = celt_inner_prod(x, x-(T+k-1), N, arch); + if ((xcorr[2]-xcorr[0]) > MULT16_32_Q15(QCONST16(.7f,15),xcorr[1]-xcorr[0])) + offset = 1; + else if ((xcorr[0]-xcorr[2]) > MULT16_32_Q15(QCONST16(.7f,15),xcorr[1]-xcorr[2])) + offset = -1; + else + offset = 0; + if (pg > g) + pg = g; + *T0_ = 2*T+offset; + + if (*T0_=3); + y_3=0; /* gcc doesn't realize that y_3 can't be used uninitialized */ + y_0=*y++; + y_1=*y++; + y_2=*y++; + for (j=0;j +#include "os_support.h" +#include "arch.h" +#include "mathops.h" +#include "stack_alloc.h" +#include "rate.h" + +#ifdef FIXED_POINT +/* Mean energy in each band quantized in Q4 */ +const signed char eMeans[25] = { + 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 +}; +#else +/* Mean energy in each band quantized in Q4 and converted back to float */ +const opus_val16 eMeans[25] = { + 6.437500f, 6.250000f, 5.750000f, 5.312500f, 5.062500f, + 4.812500f, 4.500000f, 4.375000f, 4.875000f, 4.687500f, + 4.562500f, 4.437500f, 4.875000f, 4.625000f, 4.312500f, + 4.500000f, 4.375000f, 4.625000f, 4.750000f, 4.437500f, + 3.750000f, 3.750000f, 3.750000f, 3.750000f, 3.750000f +}; +#endif +/* prediction coefficients: 0.9, 0.8, 0.65, 0.5 */ +#ifdef FIXED_POINT +static const opus_val16 pred_coef[4] = {29440, 26112, 21248, 16384}; +static const opus_val16 beta_coef[4] = {30147, 22282, 12124, 6554}; +static const opus_val16 beta_intra = 4915; +#else +static const opus_val16 pred_coef[4] = {29440/32768., 26112/32768., 21248/32768., 16384/32768.}; +static const opus_val16 beta_coef[4] = {30147/32768., 22282/32768., 12124/32768., 6554/32768.}; +static const opus_val16 beta_intra = 4915/32768.; +#endif + +/*Parameters of the Laplace-like probability models used for the coarse energy. + There is one pair of parameters for each frame size, prediction type + (inter/intra), and band number. + The first number of each pair is the probability of 0, and the second is the + decay rate, both in Q8 precision.*/ +static const unsigned char e_prob_model[4][2][42] = { + /*120 sample frames.*/ + { + /*Inter*/ + { + 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 + }, + /*Intra*/ + { + 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 + } + }, + /*240 sample frames.*/ + { + /*Inter*/ + { + 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 + }, + /*Intra*/ + { + 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 + } + }, + /*480 sample frames.*/ + { + /*Inter*/ + { + 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 + }, + /*Intra*/ + { + 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 + } + }, + /*960 sample frames.*/ + { + /*Inter*/ + { + 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 + }, + /*Intra*/ + { + 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 const unsigned char small_energy_icdf[3]={2,1,0}; + +static opus_val32 loss_distortion(const opus_val16 *eBands, opus_val16 *oldEBands, int start, int end, int len, int C) +{ + int c, i; + opus_val32 dist = 0; + c=0; do { + for (i=start;inbEBands]; + oldE = MAX16(-QCONST16(9.f,DB_SHIFT), oldEBands[i+c*m->nbEBands]); +#ifdef FIXED_POINT + f = SHL32(EXTEND32(x),7) - PSHR32(MULT16_16(coef,oldE), 8) - prev[c]; + /* Rounding to nearest integer here is really important! */ + qi = (f+QCONST32(.5f,DB_SHIFT+7))>>(DB_SHIFT+7); + decay_bound = EXTRACT16(MAX32(-QCONST16(28.f,DB_SHIFT), + SUB32((opus_val32)oldEBands[i+c*m->nbEBands],max_decay))); +#else + f = x-coef*oldE-prev[c]; + /* Rounding to nearest integer here is really important! */ + qi = (int)floor(.5f+f); + decay_bound = MAX16(-QCONST16(28.f,DB_SHIFT), oldEBands[i+c*m->nbEBands]) - max_decay; +#endif + /* Prevent the energy from going down too quickly (e.g. for bands + that have just one bin) */ + if (qi < 0 && x < decay_bound) + { + qi += (int)SHR16(SUB16(decay_bound,x), DB_SHIFT); + if (qi > 0) + qi = 0; + } + qi0 = qi; + /* If we don't have enough bits to encode all the energy, just assume + something safe. */ + tell = ec_tell(enc); + bits_left = budget-tell-3*C*(end-i); + if (i!=start && bits_left < 30) + { + if (bits_left < 24) + qi = IMIN(1, qi); + if (bits_left < 16) + qi = IMAX(-1, qi); + } + if (lfe && i>=2) + qi = IMIN(qi, 0); + if (budget-tell >= 15) + { + int pi; + pi = 2*IMIN(i,20); + ec_laplace_encode(enc, &qi, + prob_model[pi]<<7, prob_model[pi+1]<<6); + } + else if(budget-tell >= 2) + { + qi = IMAX(-1, IMIN(qi, 1)); + ec_enc_icdf(enc, 2*qi^-(qi<0), small_energy_icdf, 2); + } + else if(budget-tell >= 1) + { + qi = IMIN(0, qi); + ec_enc_bit_logp(enc, -qi, 1); + } + else + qi = -1; + error[i+c*m->nbEBands] = PSHR32(f,7) - SHL16(qi,DB_SHIFT); + badness += abs(qi0-qi); + q = (opus_val32)SHL32(EXTEND32(qi),DB_SHIFT); + + tmp = PSHR32(MULT16_16(coef,oldE),8) + prev[c] + SHL32(q,7); +#ifdef FIXED_POINT + tmp = MAX32(-QCONST32(28.f, DB_SHIFT+7), tmp); +#endif + oldEBands[i+c*m->nbEBands] = PSHR32(tmp, 7); + prev[c] = prev[c] + SHL32(q,7) - MULT16_16(beta,PSHR32(q,8)); + } while (++c < C); + } + return lfe ? 0 : badness; +} + +void quant_coarse_energy(const CELTMode *m, int start, int end, int effEnd, + const opus_val16 *eBands, opus_val16 *oldEBands, opus_uint32 budget, + opus_val16 *error, ec_enc *enc, int C, int LM, int nbAvailableBytes, + int force_intra, opus_val32 *delayedIntra, int two_pass, int loss_rate, int lfe) +{ + int intra; + opus_val16 max_decay; + VARDECL(opus_val16, oldEBands_intra); + VARDECL(opus_val16, error_intra); + ec_enc enc_start_state; + opus_uint32 tell; + int badness1=0; + opus_int32 intra_bias; + opus_val32 new_distortion; + SAVE_STACK; + + intra = force_intra || (!two_pass && *delayedIntra>2*C*(end-start) && nbAvailableBytes > (end-start)*C); + intra_bias = (opus_int32)((budget**delayedIntra*loss_rate)/(C*512)); + new_distortion = loss_distortion(eBands, oldEBands, start, effEnd, m->nbEBands, C); + + tell = ec_tell(enc); + if (tell+3 > budget) + two_pass = intra = 0; + + max_decay = QCONST16(16.f,DB_SHIFT); + if (end-start>10) + { +#ifdef FIXED_POINT + max_decay = MIN32(max_decay, SHL32(EXTEND32(nbAvailableBytes),DB_SHIFT-3)); +#else + max_decay = MIN32(max_decay, .125f*nbAvailableBytes); +#endif + } + if (lfe) + max_decay = QCONST16(3.f,DB_SHIFT); + enc_start_state = *enc; + + ALLOC(oldEBands_intra, C*m->nbEBands, opus_val16); + ALLOC(error_intra, C*m->nbEBands, opus_val16); + OPUS_COPY(oldEBands_intra, oldEBands, C*m->nbEBands); + + if (two_pass || intra) + { + badness1 = quant_coarse_energy_impl(m, start, end, eBands, oldEBands_intra, budget, + tell, e_prob_model[LM][1], error_intra, enc, C, LM, 1, max_decay, lfe); + } + + if (!intra) + { + unsigned char *intra_buf; + ec_enc enc_intra_state; + opus_int32 tell_intra; + opus_uint32 nstart_bytes; + opus_uint32 nintra_bytes; + opus_uint32 save_bytes; + int badness2; + VARDECL(unsigned char, intra_bits); + + tell_intra = ec_tell_frac(enc); + + enc_intra_state = *enc; + + nstart_bytes = ec_range_bytes(&enc_start_state); + nintra_bytes = ec_range_bytes(&enc_intra_state); + intra_buf = ec_get_buffer(&enc_intra_state) + nstart_bytes; + save_bytes = nintra_bytes-nstart_bytes; + if (save_bytes == 0) + save_bytes = ALLOC_NONE; + ALLOC(intra_bits, save_bytes, unsigned char); + /* Copy bits from intra bit-stream */ + OPUS_COPY(intra_bits, intra_buf, nintra_bytes - nstart_bytes); + + *enc = enc_start_state; + + badness2 = quant_coarse_energy_impl(m, start, end, eBands, oldEBands, budget, + tell, e_prob_model[LM][intra], error, enc, C, LM, 0, max_decay, lfe); + + if (two_pass && (badness1 < badness2 || (badness1 == badness2 && ((opus_int32)ec_tell_frac(enc))+intra_bias > tell_intra))) + { + *enc = enc_intra_state; + /* Copy intra bits to bit-stream */ + OPUS_COPY(intra_buf, intra_bits, nintra_bytes - nstart_bytes); + OPUS_COPY(oldEBands, oldEBands_intra, C*m->nbEBands); + OPUS_COPY(error, error_intra, C*m->nbEBands); + intra = 1; + } + } else { + OPUS_COPY(oldEBands, oldEBands_intra, C*m->nbEBands); + OPUS_COPY(error, error_intra, C*m->nbEBands); + } + + if (intra) + *delayedIntra = new_distortion; + else + *delayedIntra = ADD32(MULT16_32_Q15(MULT16_16_Q15(pred_coef[LM], pred_coef[LM]),*delayedIntra), + new_distortion); + + RESTORE_STACK; +} + +void quant_fine_energy(const CELTMode *m, int start, int end, opus_val16 *oldEBands, opus_val16 *error, int *fine_quant, ec_enc *enc, int C) +{ + int i, c; + + /* Encode finer resolution */ + for (i=start;inbEBands]+QCONST16(.5f,DB_SHIFT))>>(DB_SHIFT-fine_quant[i]); +#else + q2 = (int)floor((error[i+c*m->nbEBands]+.5f)*frac); +#endif + if (q2 > frac-1) + q2 = frac-1; + if (q2<0) + q2 = 0; + ec_enc_bits(enc, q2, fine_quant[i]); +#ifdef FIXED_POINT + offset = SUB16(SHR32(SHL32(EXTEND32(q2),DB_SHIFT)+QCONST16(.5f,DB_SHIFT),fine_quant[i]),QCONST16(.5f,DB_SHIFT)); +#else + offset = (q2+.5f)*(1<<(14-fine_quant[i]))*(1.f/16384) - .5f; +#endif + oldEBands[i+c*m->nbEBands] += offset; + error[i+c*m->nbEBands] -= offset; + /*printf ("%f ", error[i] - offset);*/ + } while (++c < C); + } +} + +void quant_energy_finalise(const CELTMode *m, int start, int end, opus_val16 *oldEBands, opus_val16 *error, int *fine_quant, int *fine_priority, int bits_left, ec_enc *enc, int C) +{ + int i, prio, c; + + /* Use up the remaining bits */ + for (prio=0;prio<2;prio++) + { + for (i=start;i=C ;i++) + { + if (fine_quant[i] >= MAX_FINE_BITS || fine_priority[i]!=prio) + continue; + c=0; + do { + int q2; + opus_val16 offset; + q2 = error[i+c*m->nbEBands]<0 ? 0 : 1; + ec_enc_bits(enc, q2, 1); +#ifdef FIXED_POINT + offset = SHR16(SHL16(q2,DB_SHIFT)-QCONST16(.5f,DB_SHIFT),fine_quant[i]+1); +#else + offset = (q2-.5f)*(1<<(14-fine_quant[i]-1))*(1.f/16384); +#endif + oldEBands[i+c*m->nbEBands] += offset; + error[i+c*m->nbEBands] -= offset; + bits_left--; + } while (++c < C); + } + } +} + +void unquant_coarse_energy(const CELTMode *m, int start, int end, opus_val16 *oldEBands, int intra, ec_dec *dec, int C, int LM) +{ + const unsigned char *prob_model = e_prob_model[LM][intra]; + int i, c; + opus_val32 prev[2] = {0, 0}; + opus_val16 coef; + opus_val16 beta; + opus_int32 budget; + opus_int32 tell; + + if (intra) + { + coef = 0; + beta = beta_intra; + } else { + beta = beta_coef[LM]; + coef = pred_coef[LM]; + } + + budget = dec->storage*8; + + /* Decode at a fixed coarse resolution */ + for (i=start;i=15) + { + int pi; + pi = 2*IMIN(i,20); + qi = ec_laplace_decode(dec, + prob_model[pi]<<7, prob_model[pi+1]<<6); + } + else if(budget-tell>=2) + { + qi = ec_dec_icdf(dec, small_energy_icdf, 2); + qi = (qi>>1)^-(qi&1); + } + else if(budget-tell>=1) + { + qi = -ec_dec_bit_logp(dec, 1); + } + else + qi = -1; + q = (opus_val32)SHL32(EXTEND32(qi),DB_SHIFT); + + oldEBands[i+c*m->nbEBands] = MAX16(-QCONST16(9.f,DB_SHIFT), oldEBands[i+c*m->nbEBands]); + tmp = PSHR32(MULT16_16(coef,oldEBands[i+c*m->nbEBands]),8) + prev[c] + SHL32(q,7); +#ifdef FIXED_POINT + tmp = MAX32(-QCONST32(28.f, DB_SHIFT+7), tmp); +#endif + oldEBands[i+c*m->nbEBands] = PSHR32(tmp, 7); + prev[c] = prev[c] + SHL32(q,7) - MULT16_16(beta,PSHR32(q,8)); + } while (++c < C); + } +} + +void unquant_fine_energy(const CELTMode *m, int start, int end, opus_val16 *oldEBands, int *fine_quant, ec_dec *dec, int C) +{ + int i, c; + /* Decode finer resolution */ + for (i=start;inbEBands] += offset; + } while (++c < C); + } +} + +void unquant_energy_finalise(const CELTMode *m, int start, int end, opus_val16 *oldEBands, int *fine_quant, int *fine_priority, int bits_left, ec_dec *dec, int C) +{ + int i, prio, c; + + /* Use up the remaining bits */ + for (prio=0;prio<2;prio++) + { + for (i=start;i=C ;i++) + { + if (fine_quant[i] >= MAX_FINE_BITS || fine_priority[i]!=prio) + continue; + c=0; + do { + int q2; + opus_val16 offset; + q2 = ec_dec_bits(dec, 1); +#ifdef FIXED_POINT + offset = SHR16(SHL16(q2,DB_SHIFT)-QCONST16(.5f,DB_SHIFT),fine_quant[i]+1); +#else + offset = (q2-.5f)*(1<<(14-fine_quant[i]-1))*(1.f/16384); +#endif + oldEBands[i+c*m->nbEBands] += offset; + bits_left--; + } while (++c < C); + } + } +} + +void amp2Log2(const CELTMode *m, int effEnd, int end, + celt_ener *bandE, opus_val16 *bandLogE, int C) +{ + int c, i; + c=0; + do { + for (i=0;inbEBands] = + celt_log2(bandE[i+c*m->nbEBands]) + - SHL16((opus_val16)eMeans[i],6); +#ifdef FIXED_POINT + /* Compensate for bandE[] being Q12 but celt_log2() taking a Q14 input. */ + bandLogE[i+c*m->nbEBands] += QCONST16(2.f, DB_SHIFT); +#endif + } + for (i=effEnd;inbEBands+i] = -QCONST16(14.f,DB_SHIFT); + } while (++c < C); +} diff --git a/extern/opus/celt/quant_bands.h b/extern/opus/celt/quant_bands.h new file mode 100644 index 0000000..0490bca --- /dev/null +++ b/extern/opus/celt/quant_bands.h @@ -0,0 +1,66 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + 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. + + 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 OWNER + 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. +*/ + +#ifndef QUANT_BANDS +#define QUANT_BANDS + +#include "arch.h" +#include "modes.h" +#include "entenc.h" +#include "entdec.h" +#include "mathops.h" + +#ifdef FIXED_POINT +extern const signed char eMeans[25]; +#else +extern const opus_val16 eMeans[25]; +#endif + +void amp2Log2(const CELTMode *m, int effEnd, int end, + celt_ener *bandE, opus_val16 *bandLogE, int C); + +void log2Amp(const CELTMode *m, int start, int end, + celt_ener *eBands, const opus_val16 *oldEBands, int C); + +void quant_coarse_energy(const CELTMode *m, int start, int end, int effEnd, + const opus_val16 *eBands, opus_val16 *oldEBands, opus_uint32 budget, + opus_val16 *error, ec_enc *enc, int C, int LM, + int nbAvailableBytes, int force_intra, opus_val32 *delayedIntra, + int two_pass, int loss_rate, int lfe); + +void quant_fine_energy(const CELTMode *m, int start, int end, opus_val16 *oldEBands, opus_val16 *error, int *fine_quant, ec_enc *enc, int C); + +void quant_energy_finalise(const CELTMode *m, int start, int end, opus_val16 *oldEBands, opus_val16 *error, int *fine_quant, int *fine_priority, int bits_left, ec_enc *enc, int C); + +void unquant_coarse_energy(const CELTMode *m, int start, int end, opus_val16 *oldEBands, int intra, ec_dec *dec, int C, int LM); + +void unquant_fine_energy(const CELTMode *m, int start, int end, opus_val16 *oldEBands, int *fine_quant, ec_dec *dec, int C); + +void unquant_energy_finalise(const CELTMode *m, int start, int end, opus_val16 *oldEBands, int *fine_quant, int *fine_priority, int bits_left, ec_dec *dec, int C); + +#endif /* QUANT_BANDS */ diff --git a/extern/opus/celt/rate.c b/extern/opus/celt/rate.c new file mode 100644 index 0000000..465e1ba --- /dev/null +++ b/extern/opus/celt/rate.c @@ -0,0 +1,644 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + 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. + + 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 OWNER + 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. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "modes.h" +#include "cwrs.h" +#include "arch.h" +#include "os_support.h" + +#include "entcode.h" +#include "rate.h" + +static const unsigned char LOG2_FRAC_TABLE[24]={ + 0, + 8,13, + 16,19,21,23, + 24,26,27,28,29,30,31,32, + 32,33,34,34,35,36,36,37,37 +}; + +#ifdef CUSTOM_MODES + +/*Determines if V(N,K) fits in a 32-bit unsigned integer. + N and K are themselves limited to 15 bits.*/ +static int fits_in32(int _n, int _k) +{ + static const opus_int16 maxN[15] = { + 32767, 32767, 32767, 1476, 283, 109, 60, 40, + 29, 24, 20, 18, 16, 14, 13}; + static const opus_int16 maxK[15] = { + 32767, 32767, 32767, 32767, 1172, 238, 95, 53, + 36, 27, 22, 18, 16, 15, 13}; + if (_n>=14) + { + if (_k>=14) + return 0; + else + return _n <= maxN[_k]; + } else { + return _k <= maxK[_n]; + } +} + +void compute_pulse_cache(CELTMode *m, int LM) +{ + int C; + int i; + int j; + int curr=0; + int nbEntries=0; + int entryN[100], entryK[100], entryI[100]; + const opus_int16 *eBands = m->eBands; + PulseCache *cache = &m->cache; + opus_int16 *cindex; + unsigned char *bits; + unsigned char *cap; + + cindex = (opus_int16 *)opus_alloc(sizeof(cache->index[0])*m->nbEBands*(LM+2)); + cache->index = cindex; + + /* Scan for all unique band sizes */ + for (i=0;i<=LM+1;i++) + { + for (j=0;jnbEBands;j++) + { + int k; + int N = (eBands[j+1]-eBands[j])<>1; + cindex[i*m->nbEBands+j] = -1; + /* Find other bands that have the same size */ + for (k=0;k<=i;k++) + { + int n; + for (n=0;nnbEBands && (k!=i || n>1) + { + cindex[i*m->nbEBands+j] = cindex[k*m->nbEBands+n]; + break; + } + } + } + if (cache->index[i*m->nbEBands+j] == -1 && N!=0) + { + int K; + entryN[nbEntries] = N; + K = 0; + while (fits_in32(N,get_pulses(K+1)) && KnbEBands+j] = curr; + entryI[nbEntries] = curr; + + curr += K+1; + nbEntries++; + } + } + } + bits = (unsigned char *)opus_alloc(sizeof(unsigned char)*curr); + cache->bits = bits; + cache->size = curr; + /* Compute the cache for all unique sizes */ + for (i=0;icaps = cap = (unsigned char *)opus_alloc(sizeof(cache->caps[0])*(LM+1)*2*m->nbEBands); + for (i=0;i<=LM;i++) + { + for (C=1;C<=2;C++) + { + for (j=0;jnbEBands;j++) + { + int N0; + int max_bits; + N0 = m->eBands[j+1]-m->eBands[j]; + /* N=1 bands only have a sign bit and fine bits. */ + if (N0<1 are even, including custom modes.*/ + if (N0 > 2) + { + N0>>=1; + LM0--; + } + /* N0=1 bands can't be split down to N<2. */ + else if (N0 <= 1) + { + LM0=IMIN(i,1); + N0<<=LM0; + } + /* Compute the cost for the lowest-level PVQ of a fully split + band. */ + pcache = bits + cindex[(LM0+1)*m->nbEBands+j]; + max_bits = pcache[pcache[0]]+1; + /* Add in the cost of coding regular splits. */ + N = N0; + for(k=0;klogN[j]+((LM0+k)<>1)-QTHETA_OFFSET; + /* The number of qtheta bits we'll allocate if the remainder + is to be max_bits. + The average measured cost for theta is 0.89701 times qb, + approximated here as 459/512. */ + num=459*(opus_int32)((2*N-1)*offset+max_bits); + den=((opus_int32)(2*N-1)<<9)-459; + qb = IMIN((num+(den>>1))/den, 57); + celt_assert(qb >= 0); + max_bits += qb; + N <<= 1; + } + /* Add in the cost of a stereo split, if necessary. */ + if (C==2) + { + max_bits <<= 1; + offset = ((m->logN[j]+(i<>1)-(N==2?QTHETA_OFFSET_TWOPHASE:QTHETA_OFFSET); + ndof = 2*N-1-(N==2); + /* The average measured cost for theta with the step PDF is + 0.95164 times qb, approximated here as 487/512. */ + num = (N==2?512:487)*(opus_int32)(max_bits+ndof*offset); + den = ((opus_int32)ndof<<9)-(N==2?512:487); + qb = IMIN((num+(den>>1))/den, (N==2?64:61)); + celt_assert(qb >= 0); + max_bits += qb; + } + /* Add the fine bits we'll use. */ + /* Compensate for the extra DoF in stereo */ + ndof = C*N + ((C==2 && N>2) ? 1 : 0); + /* Offset the number of fine bits by log2(N)/2 + FINE_OFFSET + compared to their "fair share" of total/N */ + offset = ((m->logN[j] + (i<>1)-FINE_OFFSET; + /* N=2 is the only point that doesn't match the curve */ + if (N==2) + offset += 1<>2; + /* The number of fine bits we'll allocate if the remainder is + to be max_bits. */ + num = max_bits+ndof*offset; + den = (ndof-1)<>1))/den, MAX_FINE_BITS); + celt_assert(qb >= 0); + max_bits += C*qb<eBands[j+1]-m->eBands[j])<= 0); + celt_assert(max_bits < 256); + *cap++ = (unsigned char)max_bits; + } + } + } +} + +#endif /* CUSTOM_MODES */ + +#define ALLOC_STEPS 6 + +static OPUS_INLINE int interp_bits2pulses(const CELTMode *m, int start, int end, int skip_start, + const int *bits1, const int *bits2, const int *thresh, const int *cap, opus_int32 total, opus_int32 *_balance, + int skip_rsv, int *intensity, int intensity_rsv, int *dual_stereo, int dual_stereo_rsv, int *bits, + int *ebits, int *fine_priority, int C, int LM, ec_ctx *ec, int encode, int prev, int signalBandwidth) +{ + opus_int32 psum; + int lo, hi; + int i, j; + int logM; + int stereo; + int codedBands=-1; + int alloc_floor; + opus_int32 left, percoeff; + int done; + opus_int32 balance; + SAVE_STACK; + + alloc_floor = C<1; + + logM = LM<>1; + psum = 0; + done = 0; + for (j=end;j-->start;) + { + int tmp = bits1[j] + (mid*(opus_int32)bits2[j]>>ALLOC_STEPS); + if (tmp >= thresh[j] || done) + { + done = 1; + /* Don't allocate more than we can actually use */ + psum += IMIN(tmp, cap[j]); + } else { + if (tmp >= alloc_floor) + psum += alloc_floor; + } + } + if (psum > total) + hi = mid; + else + lo = mid; + } + psum = 0; + /*printf ("interp bisection gave %d\n", lo);*/ + done = 0; + for (j=end;j-->start;) + { + int tmp = bits1[j] + ((opus_int32)lo*bits2[j]>>ALLOC_STEPS); + if (tmp < thresh[j] && !done) + { + if (tmp >= alloc_floor) + tmp = alloc_floor; + else + tmp = 0; + } else + done = 1; + /* Don't allocate more than we can actually use */ + tmp = IMIN(tmp, cap[j]); + bits[j] = tmp; + psum += tmp; + } + + /* Decide which bands to skip, working backwards from the end. */ + for (codedBands=end;;codedBands--) + { + int band_width; + int band_bits; + int rem; + j = codedBands-1; + /* Never skip the first band, nor a band that has been boosted by + dynalloc. + In the first case, we'd be coding a bit to signal we're going to waste + all the other bits. + In the second case, we'd be coding a bit to redistribute all the bits + we just signaled should be cocentrated in this band. */ + if (j<=skip_start) + { + /* Give the bit we reserved to end skipping back. */ + total += skip_rsv; + break; + } + /*Figure out how many left-over bits we would be adding to this band. + This can include bits we've stolen back from higher, skipped bands.*/ + left = total-psum; + percoeff = celt_udiv(left, m->eBands[codedBands]-m->eBands[start]); + left -= (m->eBands[codedBands]-m->eBands[start])*percoeff; + rem = IMAX(left-(m->eBands[j]-m->eBands[start]),0); + band_width = m->eBands[codedBands]-m->eBands[j]; + band_bits = (int)(bits[j] + percoeff*band_width + rem); + /*Only code a skip decision if we're above the threshold for this band. + Otherwise it is force-skipped. + This ensures that we have enough bits to code the skip flag.*/ + if (band_bits >= IMAX(thresh[j], alloc_floor+(1< 17) + depth_threshold = j (depth_threshold*band_width<>4 && j<=signalBandwidth)) +#endif + { + ec_enc_bit_logp(ec, 1, 1); + break; + } + ec_enc_bit_logp(ec, 0, 1); + } else if (ec_dec_bit_logp(ec, 1)) { + break; + } + /*We used a bit to skip this band.*/ + psum += 1< 0) + intensity_rsv = LOG2_FRAC_TABLE[j-start]; + psum += intensity_rsv; + if (band_bits >= alloc_floor) + { + /*If we have enough for a fine energy bit per channel, use it.*/ + psum += alloc_floor; + bits[j] = alloc_floor; + } else { + /*Otherwise this band gets nothing at all.*/ + bits[j] = 0; + } + } + + celt_assert(codedBands > start); + /* Code the intensity and dual stereo parameters. */ + if (intensity_rsv > 0) + { + if (encode) + { + *intensity = IMIN(*intensity, codedBands); + ec_enc_uint(ec, *intensity-start, codedBands+1-start); + } + else + *intensity = start+ec_dec_uint(ec, codedBands+1-start); + } + else + *intensity = 0; + if (*intensity <= start) + { + total += dual_stereo_rsv; + dual_stereo_rsv = 0; + } + if (dual_stereo_rsv > 0) + { + if (encode) + ec_enc_bit_logp(ec, *dual_stereo, 1); + else + *dual_stereo = ec_dec_bit_logp(ec, 1); + } + else + *dual_stereo = 0; + + /* Allocate the remaining bits */ + left = total-psum; + percoeff = celt_udiv(left, m->eBands[codedBands]-m->eBands[start]); + left -= (m->eBands[codedBands]-m->eBands[start])*percoeff; + for (j=start;jeBands[j+1]-m->eBands[j])); + for (j=start;jeBands[j+1]-m->eBands[j]); + bits[j] += tmp; + left -= tmp; + } + /*for (j=0;j= 0); + N0 = m->eBands[j+1]-m->eBands[j]; + N=N0<1) + { + excess = MAX32(bit-cap[j],0); + bits[j] = bit-excess; + + /* Compensate for the extra DoF in stereo */ + den=(C*N+ ((C==2 && N>2 && !*dual_stereo && j<*intensity) ? 1 : 0)); + + NClogN = den*(m->logN[j] + logM); + + /* Offset for the number of fine bits by log2(N)/2 + FINE_OFFSET + compared to their "fair share" of total/N */ + offset = (NClogN>>1)-den*FINE_OFFSET; + + /* N=2 is the only point that doesn't match the curve */ + if (N==2) + offset += den<>2; + + /* Changing the offset for allocating the second and third + fine energy bit */ + if (bits[j] + offset < den*2<>2; + else if (bits[j] + offset < den*3<>3; + + /* Divide with rounding */ + ebits[j] = IMAX(0, (bits[j] + offset + (den<<(BITRES-1)))); + ebits[j] = celt_udiv(ebits[j], den)>>BITRES; + + /* Make sure not to bust */ + if (C*ebits[j] > (bits[j]>>BITRES)) + ebits[j] = bits[j] >> stereo >> BITRES; + + /* More than that is useless because that's about as far as PVQ can go */ + ebits[j] = IMIN(ebits[j], MAX_FINE_BITS); + + /* If we rounded down or capped this band, make it a candidate for the + final fine energy pass */ + fine_priority[j] = ebits[j]*(den<= bits[j]+offset; + + /* Remove the allocated fine bits; the rest are assigned to PVQ */ + bits[j] -= C*ebits[j]< 0) + { + int extra_fine; + int extra_bits; + extra_fine = IMIN(excess>>(stereo+BITRES),MAX_FINE_BITS-ebits[j]); + ebits[j] += extra_fine; + extra_bits = extra_fine*C<= excess-balance; + excess -= extra_bits; + } + balance = excess; + + celt_assert(bits[j] >= 0); + celt_assert(ebits[j] >= 0); + } + /* Save any remaining bits over the cap for the rebalancing in + quant_all_bands(). */ + *_balance = balance; + + /* The skipped bands use all their bits for fine energy. */ + for (;j> stereo >> BITRES; + celt_assert(C*ebits[j]<nbEBands; + skip_start = start; + /* Reserve a bit to signal the end of manually skipped bands. */ + skip_rsv = total >= 1<total) + intensity_rsv = 0; + else + { + total -= intensity_rsv; + dual_stereo_rsv = total>=1<eBands[j+1]-m->eBands[j])<>4); + /* Tilt of the allocation curve */ + trim_offset[j] = C*(m->eBands[j+1]-m->eBands[j])*(alloc_trim-5-LM)*(end-j-1) + *(1<<(LM+BITRES))>>6; + /* Giving less resolution to single-coefficient bands because they get + more benefit from having one coarse value per coefficient*/ + if ((m->eBands[j+1]-m->eBands[j])<nbAllocVectors - 1; + do + { + int done = 0; + int psum = 0; + int mid = (lo+hi) >> 1; + for (j=end;j-->start;) + { + int bitsj; + int N = m->eBands[j+1]-m->eBands[j]; + bitsj = C*N*m->allocVectors[mid*len+j]<>2; + if (bitsj > 0) + bitsj = IMAX(0, bitsj + trim_offset[j]); + bitsj += offsets[j]; + if (bitsj >= thresh[j] || done) + { + done = 1; + /* Don't allocate more than we can actually use */ + psum += IMIN(bitsj, cap[j]); + } else { + if (bitsj >= C< total) + hi = mid - 1; + else + lo = mid + 1; + /*printf ("lo = %d, hi = %d\n", lo, hi);*/ + } + while (lo <= hi); + hi = lo--; + /*printf ("interp between %d and %d\n", lo, hi);*/ + for (j=start;jeBands[j+1]-m->eBands[j]; + bits1j = C*N*m->allocVectors[lo*len+j]<>2; + bits2j = hi>=m->nbAllocVectors ? + cap[j] : C*N*m->allocVectors[hi*len+j]<>2; + if (bits1j > 0) + bits1j = IMAX(0, bits1j + trim_offset[j]); + if (bits2j > 0) + bits2j = IMAX(0, bits2j + trim_offset[j]); + if (lo > 0) + bits1j += offsets[j]; + bits2j += offsets[j]; + if (offsets[j]>0) + skip_start = j; + bits2j = IMAX(0,bits2j-bits1j); + bits1[j] = bits1j; + bits2[j] = bits2j; + } + codedBands = 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); + RESTORE_STACK; + return codedBands; +} + diff --git a/extern/opus/celt/rate.h b/extern/opus/celt/rate.h new file mode 100644 index 0000000..fad5e41 --- /dev/null +++ b/extern/opus/celt/rate.h @@ -0,0 +1,101 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + 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. + + 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 OWNER + 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. +*/ + +#ifndef RATE_H +#define RATE_H + +#define MAX_PSEUDO 40 +#define LOG_MAX_PSEUDO 6 + +#define CELT_MAX_PULSES 128 + +#define MAX_FINE_BITS 8 + +#define FINE_OFFSET 21 +#define QTHETA_OFFSET 4 +#define QTHETA_OFFSET_TWOPHASE 16 + +#include "cwrs.h" +#include "modes.h" + +void compute_pulse_cache(CELTMode *m, int LM); + +static OPUS_INLINE int get_pulses(int i) +{ + return i<8 ? i : (8 + (i&7)) << ((i>>3)-1); +} + +static OPUS_INLINE int bits2pulses(const CELTMode *m, int band, int LM, int bits) +{ + int i; + int lo, hi; + const unsigned char *cache; + + LM++; + cache = m->cache.bits + m->cache.index[LM*m->nbEBands+band]; + + lo = 0; + hi = cache[0]; + bits--; + for (i=0;i>1; + /* OPT: Make sure this is implemented with a conditional move */ + if ((int)cache[mid] >= bits) + hi = mid; + else + lo = mid; + } + if (bits- (lo == 0 ? -1 : (int)cache[lo]) <= (int)cache[hi]-bits) + return lo; + else + return hi; +} + +static OPUS_INLINE int pulses2bits(const CELTMode *m, int band, int LM, int pulses) +{ + const unsigned char *cache; + + LM++; + cache = m->cache.bits + m->cache.index[LM*m->nbEBands+band]; + return pulses == 0 ? 0 : cache[pulses]+1; +} + +/** Compute the pulse allocation, i.e. how many pulses will go in each + * band. + @param m mode + @param offsets Requested increase or decrease in the number of bits for + each band + @param total Number of bands + @param pulses Number of pulses per band (returned) + @return Total number of bits allocated +*/ +int clt_compute_allocation(const CELTMode *m, int start, int end, const int *offsets, const int *cap, int alloc_trim, int *intensity, int *dual_stereo, + opus_int32 total, opus_int32 *balance, int *pulses, int *ebits, int *fine_priority, int C, int LM, ec_ctx *ec, int encode, int prev, int signalBandwidth); + +#endif diff --git a/extern/opus/celt/stack_alloc.h b/extern/opus/celt/stack_alloc.h new file mode 100644 index 0000000..2b51c8d --- /dev/null +++ b/extern/opus/celt/stack_alloc.h @@ -0,0 +1,184 @@ +/* Copyright (C) 2002-2003 Jean-Marc Valin + Copyright (C) 2007-2009 Xiph.Org Foundation */ +/** + @file stack_alloc.h + @brief Temporary memory allocation on stack +*/ +/* + 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. + + 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 OWNER + 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. +*/ + +#ifndef STACK_ALLOC_H +#define STACK_ALLOC_H + +#include "opus_types.h" +#include "opus_defines.h" + +#if (!defined (VAR_ARRAYS) && !defined (USE_ALLOCA) && !defined (NONTHREADSAFE_PSEUDOSTACK)) +#error "Opus requires one of VAR_ARRAYS, USE_ALLOCA, or NONTHREADSAFE_PSEUDOSTACK be defined to select the temporary allocation mode." +#endif + +#ifdef USE_ALLOCA +# ifdef WIN32 +# include +# else +# ifdef HAVE_ALLOCA_H +# include +# else +# include +# endif +# endif +#endif + +/** + * @def ALIGN(stack, size) + * + * Aligns the stack to a 'size' boundary + * + * @param stack Stack + * @param size New size boundary + */ + +/** + * @def PUSH(stack, size, type) + * + * Allocates 'size' elements of type 'type' on the stack + * + * @param stack Stack + * @param size Number of elements + * @param type Type of element + */ + +/** + * @def VARDECL(var) + * + * Declare variable on stack + * + * @param var Variable to declare + */ + +/** + * @def ALLOC(var, size, type) + * + * Allocate 'size' elements of 'type' on stack + * + * @param var Name of variable to allocate + * @param size Number of elements + * @param type Type of element + */ + +#if defined(VAR_ARRAYS) + +#define VARDECL(type, var) +#define ALLOC(var, size, type) type var[size] +#define SAVE_STACK +#define RESTORE_STACK +#define ALLOC_STACK +/* C99 does not allow VLAs of size zero */ +#define ALLOC_NONE 1 + +#elif defined(USE_ALLOCA) + +#define VARDECL(type, var) type *var + +# ifdef WIN32 +# define ALLOC(var, size, type) var = ((type*)_alloca(sizeof(type)*(size))) +# else +# define ALLOC(var, size, type) var = ((type*)alloca(sizeof(type)*(size))) +# endif + +#define SAVE_STACK +#define RESTORE_STACK +#define ALLOC_STACK +#define ALLOC_NONE 0 + +#else + +#ifdef CELT_C +char *scratch_ptr=0; +char *global_stack=0; +#else +extern char *global_stack; +extern char *scratch_ptr; +#endif /* CELT_C */ + +#ifdef ENABLE_VALGRIND + +#include + +#ifdef CELT_C +char *global_stack_top=0; +#else +extern char *global_stack_top; +#endif /* CELT_C */ + +#define ALIGN(stack, size) ((stack) += ((size) - (long)(stack)) & ((size) - 1)) +#define PUSH(stack, size, type) (VALGRIND_MAKE_MEM_NOACCESS(stack, global_stack_top-stack),ALIGN((stack),sizeof(type)/sizeof(char)),VALGRIND_MAKE_MEM_UNDEFINED(stack, ((size)*sizeof(type)/sizeof(char))),(stack)+=(2*(size)*sizeof(type)/sizeof(char)),(type*)((stack)-(2*(size)*sizeof(type)/sizeof(char)))) +#define RESTORE_STACK ((global_stack = _saved_stack),VALGRIND_MAKE_MEM_NOACCESS(global_stack, global_stack_top-global_stack)) +#define ALLOC_STACK char *_saved_stack; ((global_stack = (global_stack==0) ? ((global_stack_top=opus_alloc_scratch(GLOBAL_STACK_SIZE*2)+(GLOBAL_STACK_SIZE*2))-(GLOBAL_STACK_SIZE*2)) : global_stack),VALGRIND_MAKE_MEM_NOACCESS(global_stack, global_stack_top-global_stack)); _saved_stack = global_stack; + +#else + +#define ALIGN(stack, size) ((stack) += ((size) - (long)(stack)) & ((size) - 1)) +#define PUSH(stack, size, type) (ALIGN((stack),sizeof(type)/sizeof(char)),(stack)+=(size)*(sizeof(type)/sizeof(char)),(type*)((stack)-(size)*(sizeof(type)/sizeof(char)))) +#if 0 /* Set this to 1 to instrument pseudostack usage */ +#define RESTORE_STACK (printf("%ld %s:%d\n", global_stack-scratch_ptr, __FILE__, __LINE__),global_stack = _saved_stack) +#else +#define RESTORE_STACK (global_stack = _saved_stack) +#endif +#define ALLOC_STACK char *_saved_stack; (global_stack = (global_stack==0) ? (scratch_ptr=opus_alloc_scratch(GLOBAL_STACK_SIZE)) : global_stack); _saved_stack = global_stack; + +#endif /* ENABLE_VALGRIND */ + +#include "os_support.h" +#define VARDECL(type, var) type *var +#define ALLOC(var, size, type) var = PUSH(global_stack, size, type) +#define SAVE_STACK char *_saved_stack = global_stack; +#define ALLOC_NONE 0 + +#endif /* VAR_ARRAYS */ + + +#ifdef ENABLE_VALGRIND + +#include +#define OPUS_CHECK_ARRAY(ptr, len) VALGRIND_CHECK_MEM_IS_DEFINED(ptr, len*sizeof(*ptr)) +#define OPUS_CHECK_VALUE(value) VALGRIND_CHECK_VALUE_IS_DEFINED(value) +#define OPUS_CHECK_ARRAY_COND(ptr, len) VALGRIND_CHECK_MEM_IS_DEFINED(ptr, len*sizeof(*ptr)) +#define OPUS_CHECK_VALUE_COND(value) VALGRIND_CHECK_VALUE_IS_DEFINED(value) +#define OPUS_PRINT_INT(value) do {fprintf(stderr, #value " = %d at %s:%d\n", value, __FILE__, __LINE__);}while(0) +#define OPUS_FPRINTF fprintf + +#else + +static OPUS_INLINE int _opus_false(void) {return 0;} +#define OPUS_CHECK_ARRAY(ptr, len) _opus_false() +#define OPUS_CHECK_VALUE(value) _opus_false() +#define OPUS_PRINT_INT(value) do{}while(0) +#define OPUS_FPRINTF (void) + +#endif + + +#endif /* STACK_ALLOC_H */ diff --git a/extern/opus/celt/static_modes_fixed.h b/extern/opus/celt/static_modes_fixed.h new file mode 100644 index 0000000..8717d62 --- /dev/null +++ b/extern/opus/celt/static_modes_fixed.h @@ -0,0 +1,892 @@ +/* The contents of this file was automatically generated by dump_modes.c + with arguments: 48000 960 + It contains static definitions for some pre-defined modes. */ +#include "modes.h" +#include "rate.h" + +#ifdef HAVE_ARM_NE10 +#define OVERRIDE_FFT 1 +#include "static_modes_fixed_arm_ne10.h" +#endif + +#ifndef DEF_WINDOW120 +#define DEF_WINDOW120 +static const opus_val16 window120[120] = { +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, 32767, +32767, 32767, 32767, 32767, 32767, +}; +#endif + +#ifndef DEF_LOGN400 +#define DEF_LOGN400 +static const opus_int16 logN400[21] = { +0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 16, 16, 16, 21, 21, 24, 29, 34, 36, }; +#endif + +#ifndef DEF_PULSE_CACHE50 +#define DEF_PULSE_CACHE50 +static const opus_int16 cache_index50[105] = { +-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 const unsigned char cache_bits50[392] = { +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 const unsigned char cache_caps50[168] = { +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, }; +#endif + +#ifndef FFT_TWIDDLES48000_960 +#define FFT_TWIDDLES48000_960 +static const kiss_twiddle_cpx fft_twiddles48000_960[480] = { +{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, -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, 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}, +}; +#ifndef FFT_BITREV480 +#define FFT_BITREV480 +static const opus_int16 fft_bitrev480[480] = { +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, +}; +#endif + +#ifndef FFT_BITREV240 +#define FFT_BITREV240 +static const opus_int16 fft_bitrev240[240] = { +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, +}; +#endif + +#ifndef FFT_BITREV120 +#define FFT_BITREV120 +static const opus_int16 fft_bitrev120[120] = { +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, +}; +#endif + +#ifndef FFT_BITREV60 +#define FFT_BITREV60 +static const opus_int16 fft_bitrev60[60] = { +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, +}; +#endif + +#ifndef FFT_STATE48000_960_0 +#define FFT_STATE48000_960_0 +static const kiss_fft_state fft_state48000_960_0 = { +480, /* nfft */ +17476, /* scale */ +8, /* scale_shift */ +-1, /* shift */ +{5, 96, 3, 32, 4, 8, 2, 4, 4, 1, 0, 0, 0, 0, 0, 0, }, /* factors */ +fft_bitrev480, /* bitrev */ +fft_twiddles48000_960, /* bitrev */ +#ifdef OVERRIDE_FFT +(arch_fft_state *)&cfg_arch_480, +#else +NULL, +#endif +}; +#endif + +#ifndef FFT_STATE48000_960_1 +#define FFT_STATE48000_960_1 +static const kiss_fft_state fft_state48000_960_1 = { +240, /* nfft */ +17476, /* scale */ +7, /* scale_shift */ +1, /* shift */ +{5, 48, 3, 16, 4, 4, 4, 1, 0, 0, 0, 0, 0, 0, 0, 0, }, /* factors */ +fft_bitrev240, /* bitrev */ +fft_twiddles48000_960, /* bitrev */ +#ifdef OVERRIDE_FFT +(arch_fft_state *)&cfg_arch_240, +#else +NULL, +#endif +}; +#endif + +#ifndef FFT_STATE48000_960_2 +#define FFT_STATE48000_960_2 +static const kiss_fft_state fft_state48000_960_2 = { +120, /* nfft */ +17476, /* scale */ +6, /* scale_shift */ +2, /* shift */ +{5, 24, 3, 8, 2, 4, 4, 1, 0, 0, 0, 0, 0, 0, 0, 0, }, /* factors */ +fft_bitrev120, /* bitrev */ +fft_twiddles48000_960, /* bitrev */ +#ifdef OVERRIDE_FFT +(arch_fft_state *)&cfg_arch_120, +#else +NULL, +#endif +}; +#endif + +#ifndef FFT_STATE48000_960_3 +#define FFT_STATE48000_960_3 +static const kiss_fft_state fft_state48000_960_3 = { +60, /* nfft */ +17476, /* scale */ +5, /* scale_shift */ +3, /* shift */ +{5, 12, 3, 4, 4, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, /* factors */ +fft_bitrev60, /* bitrev */ +fft_twiddles48000_960, /* bitrev */ +#ifdef OVERRIDE_FFT +(arch_fft_state *)&cfg_arch_60, +#else +NULL, +#endif +}; +#endif + +#endif + +#ifndef MDCT_TWIDDLES960 +#define MDCT_TWIDDLES960 +static const opus_val16 mdct_twiddles960[1800] = { +32767, 32767, 32767, 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, +32767, 32767, 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, +32767, 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, +32767, 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, +}; +#endif + +static const CELTMode mode48000_960_120 = { +48000, /* Fs */ +120, /* overlap */ +21, /* nbEBands */ +21, /* effEBands */ +{27853, 0, 4096, 8192, }, /* preemph */ +eband5ms, /* eBands */ +3, /* maxLM */ +8, /* nbShortMdcts */ +120, /* shortMdctSize */ +11, /* nbAllocVectors */ +band_allocation, /* allocVectors */ +logN400, /* logN */ +window120, /* window */ +{1920, 3, {&fft_state48000_960_0, &fft_state48000_960_1, &fft_state48000_960_2, &fft_state48000_960_3, }, mdct_twiddles960}, /* mdct */ +{392, cache_index50, cache_bits50, cache_caps50}, /* cache */ +}; + +/* List of all the available modes */ +#define TOTAL_MODES 1 +static const CELTMode * const static_mode_list[TOTAL_MODES] = { +&mode48000_960_120, +}; diff --git a/extern/opus/celt/static_modes_fixed_arm_ne10.h b/extern/opus/celt/static_modes_fixed_arm_ne10.h new file mode 100644 index 0000000..7623092 --- /dev/null +++ b/extern/opus/celt/static_modes_fixed_arm_ne10.h @@ -0,0 +1,388 @@ +/* The contents of this file was automatically generated by + * dump_mode_arm_ne10.c with arguments: 48000 960 + * It contains static definitions for some pre-defined modes. */ +#include + +#ifndef NE10_FFT_PARAMS48000_960 +#define NE10_FFT_PARAMS48000_960 +static const ne10_int32_t ne10_factors_480[64] = { +4, 40, 4, 30, 2, 15, 5, 3, 3, 1, 1, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, }; +static const ne10_int32_t ne10_factors_240[64] = { +3, 20, 4, 15, 5, 3, 3, 1, 1, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, }; +static const ne10_int32_t ne10_factors_120[64] = { +3, 10, 2, 15, 5, 3, 3, 1, 1, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, }; +static const ne10_int32_t ne10_factors_60[64] = { +2, 5, 5, 3, 3, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, }; +static const ne10_fft_cpx_int32_t ne10_twiddles_480[480] = { +{0,0}, {2147483647,0}, {2147483647,0}, +{2147483647,0}, {1961823921,-873460313}, {1436946998,-1595891394}, +{2147483647,0}, {1436946998,-1595891394}, {-224473265,-2135719496}, +{2147483647,0}, {663608871,-2042378339}, {-1737350854,-1262259096}, +{2147483647,0}, {-224473265,-2135719496}, {-2100555935,446487152}, +{2147483647,0}, {2100555974,-446486968}, {1961823921,-873460313}, +{1737350743,-1262259248}, {1436946998,-1595891394}, {1073741769,-1859775424}, +{663608871,-2042378339}, {224473078,-2135719516}, {-224473265,-2135719496}, +{-663609049,-2042378281}, {-1073741932,-1859775330}, {-1436947137,-1595891268}, +{-1737350854,-1262259096}, {-1961823997,-873460141}, {-2100556013,-446486785}, +{2147483647,0}, {2144540595,-112390613}, {2135719506,-224473172}, +{2121044558,-335940465}, {2100555974,-446486968}, {2074309912,-555809682}, +{2042378310,-663608960}, {2004848691,-769589332}, {1961823921,-873460313}, +{1913421927,-974937199}, {1859775377,-1073741851}, {1801031311,-1169603450}, +{1737350743,-1262259248}, {1668908218,-1351455280}, {1595891331,-1436947067}, +{1518500216,-1518500282}, {1436946998,-1595891394}, {1351455207,-1668908277}, +{1262259172,-1737350799}, {1169603371,-1801031362}, {1073741769,-1859775424}, +{974937230,-1913421912}, {873460227,-1961823959}, {769589125,-2004848771}, +{663608871,-2042378339}, {555809715,-2074309903}, {446486876,-2100555994}, +{335940246,-2121044593}, {224473078,-2135719516}, {112390647,-2144540593}, +{2147483647,0}, {2135719506,-224473172}, {2100555974,-446486968}, +{2042378310,-663608960}, {1961823921,-873460313}, {1859775377,-1073741851}, +{1737350743,-1262259248}, {1595891331,-1436947067}, {1436946998,-1595891394}, +{1262259172,-1737350799}, {1073741769,-1859775424}, {873460227,-1961823959}, +{663608871,-2042378339}, {446486876,-2100555994}, {224473078,-2135719516}, +{-94,-2147483647}, {-224473265,-2135719496}, {-446487060,-2100555955}, +{-663609049,-2042378281}, {-873460398,-1961823883}, {-1073741932,-1859775330}, +{-1262259116,-1737350839}, {-1436947137,-1595891268}, {-1595891628,-1436946738}, +{-1737350854,-1262259096}, {-1859775343,-1073741910}, {-1961823997,-873460141}, +{-2042378447,-663608538}, {-2100556013,-446486785}, {-2135719499,-224473240}, +{2147483647,0}, {2121044558,-335940465}, {2042378310,-663608960}, +{1913421927,-974937199}, {1737350743,-1262259248}, {1518500216,-1518500282}, +{1262259172,-1737350799}, {974937230,-1913421912}, {663608871,-2042378339}, +{335940246,-2121044593}, {-94,-2147483647}, {-335940431,-2121044564}, +{-663609049,-2042378281}, {-974937397,-1913421827}, {-1262259116,-1737350839}, +{-1518500258,-1518500240}, {-1737350854,-1262259096}, {-1913422071,-974936918}, +{-2042378447,-663608538}, {-2121044568,-335940406}, {-2147483647,188}, +{-2121044509,335940777}, {-2042378331,663608895}, {-1913421900,974937252}, +{-1737350633,1262259400}, {-1518499993,1518500506}, {-1262258813,1737351059}, +{-974936606,1913422229}, {-663609179,2042378239}, {-335940566,2121044542}, +{2147483647,0}, {2147299667,-28109693}, {2146747758,-56214570}, +{2145828015,-84309815}, {2144540595,-112390613}, {2142885719,-140452154}, +{2140863671,-168489630}, {2138474797,-196498235}, {2135719506,-224473172}, +{2132598271,-252409646}, {2129111626,-280302871}, {2125260168,-308148068}, +{2121044558,-335940465}, {2116465518,-363675300}, {2111523833,-391347822}, +{2106220349,-418953288}, {2100555974,-446486968}, {2094531681,-473944146}, +{2088148500,-501320115}, {2081407525,-528610186}, {2074309912,-555809682}, +{2066856885,-582913912}, {2059049696,-609918325}, {2050889698,-636818231}, +{2042378310,-663608960}, {2033516972,-690285983}, {2024307180,-716844791}, +{2014750533,-743280770}, {2004848691,-769589332}, {1994603329,-795766029}, +{1984016179,-821806435}, {1973089077,-847706028}, {1961823921,-873460313}, +{1950222618,-899064934}, {1938287127,-924515564}, {1926019520,-949807783}, +{1913421927,-974937199}, {1900496481,-999899565}, {1887245364,-1024690661}, +{1873670877,-1049306180}, {1859775377,-1073741851}, {1845561215,-1097993541}, +{1831030826,-1122057097}, {1816186632,-1145928502}, {1801031311,-1169603450}, +{1785567394,-1193077993}, {1769797456,-1216348214}, {1753724345,-1239409914}, +{1737350743,-1262259248}, {1720679456,-1284892300}, {1703713340,-1307305194}, +{1686455222,-1329494189}, {1668908218,-1351455280}, {1651075255,-1373184807}, +{1632959307,-1394679144}, {1614563642,-1415934412}, {1595891331,-1436947067}, +{1576945572,-1457713510}, {1557729613,-1478230181}, {1538246655,-1498493658}, +{1518500216,-1518500282}, {1498493590,-1538246721}, {1478230113,-1557729677}, +{1457713441,-1576945636}, {1436946998,-1595891394}, {1415934341,-1614563704}, +{1394679073,-1632959368}, {1373184735,-1651075315}, {1351455207,-1668908277}, +{1329494115,-1686455280}, {1307305120,-1703713397}, {1284892225,-1720679512}, +{1262259172,-1737350799}, {1239409837,-1753724400}, {1216348136,-1769797510}, +{1193077915,-1785567446}, {1169603371,-1801031362}, {1145928423,-1816186682}, +{1122057017,-1831030875}, {1097993571,-1845561197}, {1073741769,-1859775424}, +{1049305987,-1873670985}, {1024690635,-1887245378}, {999899482,-1900496524}, +{974937230,-1913421912}, {949807699,-1926019561}, {924515422,-1938287195}, +{899064965,-1950222603}, {873460227,-1961823959}, {847705824,-1973089164}, +{821806407,-1984016190}, {795765941,-1994603364}, {769589125,-2004848771}, +{743280682,-2014750566}, {716844642,-2024307233}, {690286016,-2033516961}, +{663608871,-2042378339}, {636818019,-2050889764}, {609918296,-2059049705}, +{582913822,-2066856911}, {555809715,-2074309903}, {528610126,-2081407540}, +{501319962,-2088148536}, {473944148,-2094531680}, {446486876,-2100555994}, +{418953102,-2106220386}, {391347792,-2111523838}, {363675176,-2116465540}, +{335940246,-2121044593}, {308148006,-2125260177}, {280302715,-2129111646}, +{252409648,-2132598271}, {224473078,-2135719516}, {196498046,-2138474814}, +{168489600,-2140863674}, {140452029,-2142885728}, {112390647,-2144540593}, +{84309753,-2145828017}, {56214412,-2146747762}, {28109695,-2147299667}, +{2147483647,0}, {2146747758,-56214570}, {2144540595,-112390613}, +{2140863671,-168489630}, {2135719506,-224473172}, {2129111626,-280302871}, +{2121044558,-335940465}, {2111523833,-391347822}, {2100555974,-446486968}, +{2088148500,-501320115}, {2074309912,-555809682}, {2059049696,-609918325}, +{2042378310,-663608960}, {2024307180,-716844791}, {2004848691,-769589332}, +{1984016179,-821806435}, {1961823921,-873460313}, {1938287127,-924515564}, +{1913421927,-974937199}, {1887245364,-1024690661}, {1859775377,-1073741851}, +{1831030826,-1122057097}, {1801031311,-1169603450}, {1769797456,-1216348214}, +{1737350743,-1262259248}, {1703713340,-1307305194}, {1668908218,-1351455280}, +{1632959307,-1394679144}, {1595891331,-1436947067}, {1557729613,-1478230181}, +{1518500216,-1518500282}, {1478230113,-1557729677}, {1436946998,-1595891394}, +{1394679073,-1632959368}, {1351455207,-1668908277}, {1307305120,-1703713397}, +{1262259172,-1737350799}, {1216348136,-1769797510}, {1169603371,-1801031362}, +{1122057017,-1831030875}, {1073741769,-1859775424}, {1024690635,-1887245378}, +{974937230,-1913421912}, {924515422,-1938287195}, {873460227,-1961823959}, +{821806407,-1984016190}, {769589125,-2004848771}, {716844642,-2024307233}, +{663608871,-2042378339}, {609918296,-2059049705}, {555809715,-2074309903}, +{501319962,-2088148536}, {446486876,-2100555994}, {391347792,-2111523838}, +{335940246,-2121044593}, {280302715,-2129111646}, {224473078,-2135719516}, +{168489600,-2140863674}, {112390647,-2144540593}, {56214412,-2146747762}, +{-94,-2147483647}, {-56214600,-2146747757}, {-112390835,-2144540584}, +{-168489787,-2140863659}, {-224473265,-2135719496}, {-280302901,-2129111622}, +{-335940431,-2121044564}, {-391347977,-2111523804}, {-446487060,-2100555955}, +{-501320144,-2088148493}, {-555809896,-2074309855}, {-609918476,-2059049651}, +{-663609049,-2042378281}, {-716844819,-2024307170}, {-769589300,-2004848703}, +{-821806581,-1984016118}, {-873460398,-1961823883}, {-924515591,-1938287114}, +{-974937397,-1913421827}, {-1024690575,-1887245411}, {-1073741932,-1859775330}, +{-1122057395,-1831030643}, {-1169603421,-1801031330}, {-1216348291,-1769797403}, +{-1262259116,-1737350839}, {-1307305268,-1703713283}, {-1351455453,-1668908078}, +{-1394679021,-1632959413}, {-1436947137,-1595891268}, {-1478230435,-1557729372}, +{-1518500258,-1518500240}, {-1557729742,-1478230045}, {-1595891628,-1436946738}, +{-1632959429,-1394679001}, {-1668908417,-1351455035}, {-1703713298,-1307305248}, +{-1737350854,-1262259096}, {-1769797708,-1216347848}, {-1801031344,-1169603400}, +{-1831030924,-1122056937}, {-1859775343,-1073741910}, {-1887245423,-1024690552}, +{-1913422071,-974936918}, {-1938287125,-924515568}, {-1961823997,-873460141}, +{-1984016324,-821806084}, {-2004848713,-769589276}, {-2024307264,-716844553}, +{-2042378447,-663608538}, {-2059049731,-609918206}, {-2074309994,-555809377}, +{-2088148499,-501320119}, {-2100556013,-446486785}, {-2111523902,-391347448}, +{-2121044568,-335940406}, {-2129111659,-280302621}, {-2135719499,-224473240}, +{-2140863681,-168489506}, {-2144540612,-112390298}, {-2146747758,-56214574}, +{2147483647,0}, {2145828015,-84309815}, {2140863671,-168489630}, +{2132598271,-252409646}, {2121044558,-335940465}, {2106220349,-418953288}, +{2088148500,-501320115}, {2066856885,-582913912}, {2042378310,-663608960}, +{2014750533,-743280770}, {1984016179,-821806435}, {1950222618,-899064934}, +{1913421927,-974937199}, {1873670877,-1049306180}, {1831030826,-1122057097}, +{1785567394,-1193077993}, {1737350743,-1262259248}, {1686455222,-1329494189}, +{1632959307,-1394679144}, {1576945572,-1457713510}, {1518500216,-1518500282}, +{1457713441,-1576945636}, {1394679073,-1632959368}, {1329494115,-1686455280}, +{1262259172,-1737350799}, {1193077915,-1785567446}, {1122057017,-1831030875}, +{1049305987,-1873670985}, {974937230,-1913421912}, {899064965,-1950222603}, +{821806407,-1984016190}, {743280682,-2014750566}, {663608871,-2042378339}, +{582913822,-2066856911}, {501319962,-2088148536}, {418953102,-2106220386}, +{335940246,-2121044593}, {252409648,-2132598271}, {168489600,-2140863674}, +{84309753,-2145828017}, {-94,-2147483647}, {-84309940,-2145828010}, +{-168489787,-2140863659}, {-252409834,-2132598249}, {-335940431,-2121044564}, +{-418953286,-2106220349}, {-501320144,-2088148493}, {-582914003,-2066856860}, +{-663609049,-2042378281}, {-743280858,-2014750501}, {-821806581,-1984016118}, +{-899065136,-1950222525}, {-974937397,-1913421827}, {-1049306374,-1873670768}, +{-1122057395,-1831030643}, {-1193078284,-1785567199}, {-1262259116,-1737350839}, +{-1329494061,-1686455323}, {-1394679021,-1632959413}, {-1457713485,-1576945595}, +{-1518500258,-1518500240}, {-1576945613,-1457713466}, {-1632959429,-1394679001}, +{-1686455338,-1329494041}, {-1737350854,-1262259096}, {-1785567498,-1193077837}, +{-1831030924,-1122056937}, {-1873671031,-1049305905}, {-1913422071,-974936918}, +{-1950222750,-899064648}, {-1984016324,-821806084}, {-2014750687,-743280354}, +{-2042378447,-663608538}, {-2066856867,-582913978}, {-2088148499,-501320119}, +{-2106220354,-418953261}, {-2121044568,-335940406}, {-2132598282,-252409555}, +{-2140863681,-168489506}, {-2145828021,-84309659}, {-2147483647,188}, +{-2145828006,84310034}, {-2140863651,168489881}, {-2132598237,252409928}, +{-2121044509,335940777}, {-2106220281,418953629}, {-2088148411,501320484}, +{-2066856765,582914339}, {-2042378331,663608895}, {-2014750557,743280706}, +{-1984016181,821806431}, {-1950222593,899064989}, {-1913421900,974937252}, +{-1873670848,1049306232}, {-1831030728,1122057257}, {-1785567289,1193078149}, +{-1737350633,1262259400}, {-1686455106,1329494336}, {-1632959185,1394679287}, +{-1576945358,1457713742}, {-1518499993,1518500506}, {-1457713209,1576945850}, +{-1394678735,1632959656}, {-1329493766,1686455555}, {-1262258813,1737351059}, +{-1193077546,1785567692}, {-1122056638,1831031107}, {-1049305599,1873671202}, +{-974936606,1913422229}, {-899064330,1950222896}, {-821805761,1984016458}, +{-743280025,2014750808}, {-663609179,2042378239}, {-582914134,2066856823}, +{-501320277,2088148461}, {-418953420,2106220322}, {-335940566,2121044542}, +{-252409716,2132598263}, {-168489668,2140863668}, {-84309821,2145828015}, +}; +static const ne10_fft_cpx_int32_t ne10_twiddles_240[240] = { +{0,0}, {2147483647,0}, {2147483647,0}, +{2147483647,0}, {1961823921,-873460313}, {1436946998,-1595891394}, +{2147483647,0}, {1436946998,-1595891394}, {-224473265,-2135719496}, +{2147483647,0}, {663608871,-2042378339}, {-1737350854,-1262259096}, +{2147483647,0}, {-224473265,-2135719496}, {-2100555935,446487152}, +{2147483647,0}, {2135719506,-224473172}, {2100555974,-446486968}, +{2042378310,-663608960}, {1961823921,-873460313}, {1859775377,-1073741851}, +{1737350743,-1262259248}, {1595891331,-1436947067}, {1436946998,-1595891394}, +{1262259172,-1737350799}, {1073741769,-1859775424}, {873460227,-1961823959}, +{663608871,-2042378339}, {446486876,-2100555994}, {224473078,-2135719516}, +{2147483647,0}, {2100555974,-446486968}, {1961823921,-873460313}, +{1737350743,-1262259248}, {1436946998,-1595891394}, {1073741769,-1859775424}, +{663608871,-2042378339}, {224473078,-2135719516}, {-224473265,-2135719496}, +{-663609049,-2042378281}, {-1073741932,-1859775330}, {-1436947137,-1595891268}, +{-1737350854,-1262259096}, {-1961823997,-873460141}, {-2100556013,-446486785}, +{2147483647,0}, {2042378310,-663608960}, {1737350743,-1262259248}, +{1262259172,-1737350799}, {663608871,-2042378339}, {-94,-2147483647}, +{-663609049,-2042378281}, {-1262259116,-1737350839}, {-1737350854,-1262259096}, +{-2042378447,-663608538}, {-2147483647,188}, {-2042378331,663608895}, +{-1737350633,1262259400}, {-1262258813,1737351059}, {-663609179,2042378239}, +{2147483647,0}, {2146747758,-56214570}, {2144540595,-112390613}, +{2140863671,-168489630}, {2135719506,-224473172}, {2129111626,-280302871}, +{2121044558,-335940465}, {2111523833,-391347822}, {2100555974,-446486968}, +{2088148500,-501320115}, {2074309912,-555809682}, {2059049696,-609918325}, +{2042378310,-663608960}, {2024307180,-716844791}, {2004848691,-769589332}, +{1984016179,-821806435}, {1961823921,-873460313}, {1938287127,-924515564}, +{1913421927,-974937199}, {1887245364,-1024690661}, {1859775377,-1073741851}, +{1831030826,-1122057097}, {1801031311,-1169603450}, {1769797456,-1216348214}, +{1737350743,-1262259248}, {1703713340,-1307305194}, {1668908218,-1351455280}, +{1632959307,-1394679144}, {1595891331,-1436947067}, {1557729613,-1478230181}, +{1518500216,-1518500282}, {1478230113,-1557729677}, {1436946998,-1595891394}, +{1394679073,-1632959368}, {1351455207,-1668908277}, {1307305120,-1703713397}, +{1262259172,-1737350799}, {1216348136,-1769797510}, {1169603371,-1801031362}, +{1122057017,-1831030875}, {1073741769,-1859775424}, {1024690635,-1887245378}, +{974937230,-1913421912}, {924515422,-1938287195}, {873460227,-1961823959}, +{821806407,-1984016190}, {769589125,-2004848771}, {716844642,-2024307233}, +{663608871,-2042378339}, {609918296,-2059049705}, {555809715,-2074309903}, +{501319962,-2088148536}, {446486876,-2100555994}, {391347792,-2111523838}, +{335940246,-2121044593}, {280302715,-2129111646}, {224473078,-2135719516}, +{168489600,-2140863674}, {112390647,-2144540593}, {56214412,-2146747762}, +{2147483647,0}, {2144540595,-112390613}, {2135719506,-224473172}, +{2121044558,-335940465}, {2100555974,-446486968}, {2074309912,-555809682}, +{2042378310,-663608960}, {2004848691,-769589332}, {1961823921,-873460313}, +{1913421927,-974937199}, {1859775377,-1073741851}, {1801031311,-1169603450}, +{1737350743,-1262259248}, {1668908218,-1351455280}, {1595891331,-1436947067}, +{1518500216,-1518500282}, {1436946998,-1595891394}, {1351455207,-1668908277}, +{1262259172,-1737350799}, {1169603371,-1801031362}, {1073741769,-1859775424}, +{974937230,-1913421912}, {873460227,-1961823959}, {769589125,-2004848771}, +{663608871,-2042378339}, {555809715,-2074309903}, {446486876,-2100555994}, +{335940246,-2121044593}, {224473078,-2135719516}, {112390647,-2144540593}, +{-94,-2147483647}, {-112390835,-2144540584}, {-224473265,-2135719496}, +{-335940431,-2121044564}, {-446487060,-2100555955}, {-555809896,-2074309855}, +{-663609049,-2042378281}, {-769589300,-2004848703}, {-873460398,-1961823883}, +{-974937397,-1913421827}, {-1073741932,-1859775330}, {-1169603421,-1801031330}, +{-1262259116,-1737350839}, {-1351455453,-1668908078}, {-1436947137,-1595891268}, +{-1518500258,-1518500240}, {-1595891628,-1436946738}, {-1668908417,-1351455035}, +{-1737350854,-1262259096}, {-1801031344,-1169603400}, {-1859775343,-1073741910}, +{-1913422071,-974936918}, {-1961823997,-873460141}, {-2004848713,-769589276}, +{-2042378447,-663608538}, {-2074309994,-555809377}, {-2100556013,-446486785}, +{-2121044568,-335940406}, {-2135719499,-224473240}, {-2144540612,-112390298}, +{2147483647,0}, {2140863671,-168489630}, {2121044558,-335940465}, +{2088148500,-501320115}, {2042378310,-663608960}, {1984016179,-821806435}, +{1913421927,-974937199}, {1831030826,-1122057097}, {1737350743,-1262259248}, +{1632959307,-1394679144}, {1518500216,-1518500282}, {1394679073,-1632959368}, +{1262259172,-1737350799}, {1122057017,-1831030875}, {974937230,-1913421912}, +{821806407,-1984016190}, {663608871,-2042378339}, {501319962,-2088148536}, +{335940246,-2121044593}, {168489600,-2140863674}, {-94,-2147483647}, +{-168489787,-2140863659}, {-335940431,-2121044564}, {-501320144,-2088148493}, +{-663609049,-2042378281}, {-821806581,-1984016118}, {-974937397,-1913421827}, +{-1122057395,-1831030643}, {-1262259116,-1737350839}, {-1394679021,-1632959413}, +{-1518500258,-1518500240}, {-1632959429,-1394679001}, {-1737350854,-1262259096}, +{-1831030924,-1122056937}, {-1913422071,-974936918}, {-1984016324,-821806084}, +{-2042378447,-663608538}, {-2088148499,-501320119}, {-2121044568,-335940406}, +{-2140863681,-168489506}, {-2147483647,188}, {-2140863651,168489881}, +{-2121044509,335940777}, {-2088148411,501320484}, {-2042378331,663608895}, +{-1984016181,821806431}, {-1913421900,974937252}, {-1831030728,1122057257}, +{-1737350633,1262259400}, {-1632959185,1394679287}, {-1518499993,1518500506}, +{-1394678735,1632959656}, {-1262258813,1737351059}, {-1122056638,1831031107}, +{-974936606,1913422229}, {-821805761,1984016458}, {-663609179,2042378239}, +{-501320277,2088148461}, {-335940566,2121044542}, {-168489668,2140863668}, +}; +static const ne10_fft_cpx_int32_t ne10_twiddles_120[120] = { +{0,0}, {2147483647,0}, {2147483647,0}, +{2147483647,0}, {1961823921,-873460313}, {1436946998,-1595891394}, +{2147483647,0}, {1436946998,-1595891394}, {-224473265,-2135719496}, +{2147483647,0}, {663608871,-2042378339}, {-1737350854,-1262259096}, +{2147483647,0}, {-224473265,-2135719496}, {-2100555935,446487152}, +{2147483647,0}, {2100555974,-446486968}, {1961823921,-873460313}, +{1737350743,-1262259248}, {1436946998,-1595891394}, {1073741769,-1859775424}, +{663608871,-2042378339}, {224473078,-2135719516}, {-224473265,-2135719496}, +{-663609049,-2042378281}, {-1073741932,-1859775330}, {-1436947137,-1595891268}, +{-1737350854,-1262259096}, {-1961823997,-873460141}, {-2100556013,-446486785}, +{2147483647,0}, {2144540595,-112390613}, {2135719506,-224473172}, +{2121044558,-335940465}, {2100555974,-446486968}, {2074309912,-555809682}, +{2042378310,-663608960}, {2004848691,-769589332}, {1961823921,-873460313}, +{1913421927,-974937199}, {1859775377,-1073741851}, {1801031311,-1169603450}, +{1737350743,-1262259248}, {1668908218,-1351455280}, {1595891331,-1436947067}, +{1518500216,-1518500282}, {1436946998,-1595891394}, {1351455207,-1668908277}, +{1262259172,-1737350799}, {1169603371,-1801031362}, {1073741769,-1859775424}, +{974937230,-1913421912}, {873460227,-1961823959}, {769589125,-2004848771}, +{663608871,-2042378339}, {555809715,-2074309903}, {446486876,-2100555994}, +{335940246,-2121044593}, {224473078,-2135719516}, {112390647,-2144540593}, +{2147483647,0}, {2135719506,-224473172}, {2100555974,-446486968}, +{2042378310,-663608960}, {1961823921,-873460313}, {1859775377,-1073741851}, +{1737350743,-1262259248}, {1595891331,-1436947067}, {1436946998,-1595891394}, +{1262259172,-1737350799}, {1073741769,-1859775424}, {873460227,-1961823959}, +{663608871,-2042378339}, {446486876,-2100555994}, {224473078,-2135719516}, +{-94,-2147483647}, {-224473265,-2135719496}, {-446487060,-2100555955}, +{-663609049,-2042378281}, {-873460398,-1961823883}, {-1073741932,-1859775330}, +{-1262259116,-1737350839}, {-1436947137,-1595891268}, {-1595891628,-1436946738}, +{-1737350854,-1262259096}, {-1859775343,-1073741910}, {-1961823997,-873460141}, +{-2042378447,-663608538}, {-2100556013,-446486785}, {-2135719499,-224473240}, +{2147483647,0}, {2121044558,-335940465}, {2042378310,-663608960}, +{1913421927,-974937199}, {1737350743,-1262259248}, {1518500216,-1518500282}, +{1262259172,-1737350799}, {974937230,-1913421912}, {663608871,-2042378339}, +{335940246,-2121044593}, {-94,-2147483647}, {-335940431,-2121044564}, +{-663609049,-2042378281}, {-974937397,-1913421827}, {-1262259116,-1737350839}, +{-1518500258,-1518500240}, {-1737350854,-1262259096}, {-1913422071,-974936918}, +{-2042378447,-663608538}, {-2121044568,-335940406}, {-2147483647,188}, +{-2121044509,335940777}, {-2042378331,663608895}, {-1913421900,974937252}, +{-1737350633,1262259400}, {-1518499993,1518500506}, {-1262258813,1737351059}, +{-974936606,1913422229}, {-663609179,2042378239}, {-335940566,2121044542}, +}; +static const ne10_fft_cpx_int32_t ne10_twiddles_60[60] = { +{0,0}, {2147483647,0}, {2147483647,0}, +{2147483647,0}, {1961823921,-873460313}, {1436946998,-1595891394}, +{2147483647,0}, {1436946998,-1595891394}, {-224473265,-2135719496}, +{2147483647,0}, {663608871,-2042378339}, {-1737350854,-1262259096}, +{2147483647,0}, {-224473265,-2135719496}, {-2100555935,446487152}, +{2147483647,0}, {2135719506,-224473172}, {2100555974,-446486968}, +{2042378310,-663608960}, {1961823921,-873460313}, {1859775377,-1073741851}, +{1737350743,-1262259248}, {1595891331,-1436947067}, {1436946998,-1595891394}, +{1262259172,-1737350799}, {1073741769,-1859775424}, {873460227,-1961823959}, +{663608871,-2042378339}, {446486876,-2100555994}, {224473078,-2135719516}, +{2147483647,0}, {2100555974,-446486968}, {1961823921,-873460313}, +{1737350743,-1262259248}, {1436946998,-1595891394}, {1073741769,-1859775424}, +{663608871,-2042378339}, {224473078,-2135719516}, {-224473265,-2135719496}, +{-663609049,-2042378281}, {-1073741932,-1859775330}, {-1436947137,-1595891268}, +{-1737350854,-1262259096}, {-1961823997,-873460141}, {-2100556013,-446486785}, +{2147483647,0}, {2042378310,-663608960}, {1737350743,-1262259248}, +{1262259172,-1737350799}, {663608871,-2042378339}, {-94,-2147483647}, +{-663609049,-2042378281}, {-1262259116,-1737350839}, {-1737350854,-1262259096}, +{-2042378447,-663608538}, {-2147483647,188}, {-2042378331,663608895}, +{-1737350633,1262259400}, {-1262258813,1737351059}, {-663609179,2042378239}, +}; +static const ne10_fft_state_int32_t ne10_fft_state_int32_t_480 = { +120, +(ne10_int32_t *)ne10_factors_480, +(ne10_fft_cpx_int32_t *)ne10_twiddles_480, +NULL, +(ne10_fft_cpx_int32_t *)&ne10_twiddles_480[120], +}; +static const arch_fft_state cfg_arch_480 = { +1, +(void *)&ne10_fft_state_int32_t_480, +}; + +static const ne10_fft_state_int32_t ne10_fft_state_int32_t_240 = { +60, +(ne10_int32_t *)ne10_factors_240, +(ne10_fft_cpx_int32_t *)ne10_twiddles_240, +NULL, +(ne10_fft_cpx_int32_t *)&ne10_twiddles_240[60], +}; +static const arch_fft_state cfg_arch_240 = { +1, +(void *)&ne10_fft_state_int32_t_240, +}; + +static const ne10_fft_state_int32_t ne10_fft_state_int32_t_120 = { +30, +(ne10_int32_t *)ne10_factors_120, +(ne10_fft_cpx_int32_t *)ne10_twiddles_120, +NULL, +(ne10_fft_cpx_int32_t *)&ne10_twiddles_120[30], +}; +static const arch_fft_state cfg_arch_120 = { +1, +(void *)&ne10_fft_state_int32_t_120, +}; + +static const ne10_fft_state_int32_t ne10_fft_state_int32_t_60 = { +15, +(ne10_int32_t *)ne10_factors_60, +(ne10_fft_cpx_int32_t *)ne10_twiddles_60, +NULL, +(ne10_fft_cpx_int32_t *)&ne10_twiddles_60[15], +}; +static const arch_fft_state cfg_arch_60 = { +1, +(void *)&ne10_fft_state_int32_t_60, +}; + +#endif /* end NE10_FFT_PARAMS48000_960 */ diff --git a/extern/opus/celt/static_modes_float.h b/extern/opus/celt/static_modes_float.h new file mode 100644 index 0000000..e102a38 --- /dev/null +++ b/extern/opus/celt/static_modes_float.h @@ -0,0 +1,888 @@ +/* The contents of this file was automatically generated by dump_modes.c + with arguments: 48000 960 + It contains static definitions for some pre-defined modes. */ +#include "modes.h" +#include "rate.h" + +#ifdef HAVE_ARM_NE10 +#define OVERRIDE_FFT 1 +#include "static_modes_float_arm_ne10.h" +#endif + +#ifndef DEF_WINDOW120 +#define DEF_WINDOW120 +static const opus_val16 window120[120] = { +6.7286966e-05f, 0.00060551348f, 0.0016815970f, 0.0032947962f, 0.0054439943f, +0.0081276923f, 0.011344001f, 0.015090633f, 0.019364886f, 0.024163635f, +0.029483315f, 0.035319905f, 0.041668911f, 0.048525347f, 0.055883718f, +0.063737999f, 0.072081616f, 0.080907428f, 0.090207705f, 0.099974111f, +0.11019769f, 0.12086883f, 0.13197729f, 0.14351214f, 0.15546177f, +0.16781389f, 0.18055550f, 0.19367290f, 0.20715171f, 0.22097682f, +0.23513243f, 0.24960208f, 0.26436860f, 0.27941419f, 0.29472040f, +0.31026818f, 0.32603788f, 0.34200931f, 0.35816177f, 0.37447407f, +0.39092462f, 0.40749142f, 0.42415215f, 0.44088423f, 0.45766484f, +0.47447104f, 0.49127978f, 0.50806798f, 0.52481261f, 0.54149077f, +0.55807973f, 0.57455701f, 0.59090049f, 0.60708841f, 0.62309951f, +0.63891306f, 0.65450896f, 0.66986776f, 0.68497077f, 0.69980010f, +0.71433873f, 0.72857055f, 0.74248043f, 0.75605424f, 0.76927895f, +0.78214257f, 0.79463430f, 0.80674445f, 0.81846456f, 0.82978733f, +0.84070669f, 0.85121779f, 0.86131698f, 0.87100183f, 0.88027111f, +0.88912479f, 0.89756398f, 0.90559094f, 0.91320904f, 0.92042270f, +0.92723738f, 0.93365955f, 0.93969656f, 0.94535671f, 0.95064907f, +0.95558353f, 0.96017067f, 0.96442171f, 0.96834849f, 0.97196334f, +0.97527906f, 0.97830883f, 0.98106616f, 0.98356480f, 0.98581869f, +0.98784191f, 0.98964856f, 0.99125274f, 0.99266849f, 0.99390969f, +0.99499004f, 0.99592297f, 0.99672162f, 0.99739874f, 0.99796667f, +0.99843728f, 0.99882195f, 0.99913147f, 0.99937606f, 0.99956527f, +0.99970802f, 0.99981248f, 0.99988613f, 0.99993565f, 0.99996697f, +0.99998518f, 0.99999457f, 0.99999859f, 0.99999982f, 1.0000000f, +}; +#endif + +#ifndef DEF_LOGN400 +#define DEF_LOGN400 +static const opus_int16 logN400[21] = { +0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 16, 16, 16, 21, 21, 24, 29, 34, 36, }; +#endif + +#ifndef DEF_PULSE_CACHE50 +#define DEF_PULSE_CACHE50 +static const opus_int16 cache_index50[105] = { +-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 const unsigned char cache_bits50[392] = { +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 const unsigned char cache_caps50[168] = { +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, }; +#endif + +#ifndef FFT_TWIDDLES48000_960 +#define FFT_TWIDDLES48000_960 +static const kiss_twiddle_cpx fft_twiddles48000_960[480] = { +{1.0000000f, -0.0000000f}, {0.99991433f, -0.013089596f}, +{0.99965732f, -0.026176948f}, {0.99922904f, -0.039259816f}, +{0.99862953f, -0.052335956f}, {0.99785892f, -0.065403129f}, +{0.99691733f, -0.078459096f}, {0.99580493f, -0.091501619f}, +{0.99452190f, -0.10452846f}, {0.99306846f, -0.11753740f}, +{0.99144486f, -0.13052619f}, {0.98965139f, -0.14349262f}, +{0.98768834f, -0.15643447f}, {0.98555606f, -0.16934950f}, +{0.98325491f, -0.18223553f}, {0.98078528f, -0.19509032f}, +{0.97814760f, -0.20791169f}, {0.97534232f, -0.22069744f}, +{0.97236992f, -0.23344536f}, {0.96923091f, -0.24615329f}, +{0.96592583f, -0.25881905f}, {0.96245524f, -0.27144045f}, +{0.95881973f, -0.28401534f}, {0.95501994f, -0.29654157f}, +{0.95105652f, -0.30901699f}, {0.94693013f, -0.32143947f}, +{0.94264149f, -0.33380686f}, {0.93819134f, -0.34611706f}, +{0.93358043f, -0.35836795f}, {0.92880955f, -0.37055744f}, +{0.92387953f, -0.38268343f}, {0.91879121f, -0.39474386f}, +{0.91354546f, -0.40673664f}, {0.90814317f, -0.41865974f}, +{0.90258528f, -0.43051110f}, {0.89687274f, -0.44228869f}, +{0.89100652f, -0.45399050f}, {0.88498764f, -0.46561452f}, +{0.87881711f, -0.47715876f}, {0.87249601f, -0.48862124f}, +{0.86602540f, -0.50000000f}, {0.85940641f, -0.51129309f}, +{0.85264016f, -0.52249856f}, {0.84572782f, -0.53361452f}, +{0.83867057f, -0.54463904f}, {0.83146961f, -0.55557023f}, +{0.82412619f, -0.56640624f}, {0.81664156f, -0.57714519f}, +{0.80901699f, -0.58778525f}, {0.80125381f, -0.59832460f}, +{0.79335334f, -0.60876143f}, {0.78531693f, -0.61909395f}, +{0.77714596f, -0.62932039f}, {0.76884183f, -0.63943900f}, +{0.76040597f, -0.64944805f}, {0.75183981f, -0.65934582f}, +{0.74314483f, -0.66913061f}, {0.73432251f, -0.67880075f}, +{0.72537437f, -0.68835458f}, {0.71630194f, -0.69779046f}, +{0.70710678f, -0.70710678f}, {0.69779046f, -0.71630194f}, +{0.68835458f, -0.72537437f}, {0.67880075f, -0.73432251f}, +{0.66913061f, -0.74314483f}, {0.65934582f, -0.75183981f}, +{0.64944805f, -0.76040597f}, {0.63943900f, -0.76884183f}, +{0.62932039f, -0.77714596f}, {0.61909395f, -0.78531693f}, +{0.60876143f, -0.79335334f}, {0.59832460f, -0.80125381f}, +{0.58778525f, -0.80901699f}, {0.57714519f, -0.81664156f}, +{0.56640624f, -0.82412619f}, {0.55557023f, -0.83146961f}, +{0.54463904f, -0.83867057f}, {0.53361452f, -0.84572782f}, +{0.52249856f, -0.85264016f}, {0.51129309f, -0.85940641f}, +{0.50000000f, -0.86602540f}, {0.48862124f, -0.87249601f}, +{0.47715876f, -0.87881711f}, {0.46561452f, -0.88498764f}, +{0.45399050f, -0.89100652f}, {0.44228869f, -0.89687274f}, +{0.43051110f, -0.90258528f}, {0.41865974f, -0.90814317f}, +{0.40673664f, -0.91354546f}, {0.39474386f, -0.91879121f}, +{0.38268343f, -0.92387953f}, {0.37055744f, -0.92880955f}, +{0.35836795f, -0.93358043f}, {0.34611706f, -0.93819134f}, +{0.33380686f, -0.94264149f}, {0.32143947f, -0.94693013f}, +{0.30901699f, -0.95105652f}, {0.29654157f, -0.95501994f}, +{0.28401534f, -0.95881973f}, {0.27144045f, -0.96245524f}, +{0.25881905f, -0.96592583f}, {0.24615329f, -0.96923091f}, +{0.23344536f, -0.97236992f}, {0.22069744f, -0.97534232f}, +{0.20791169f, -0.97814760f}, {0.19509032f, -0.98078528f}, +{0.18223553f, -0.98325491f}, {0.16934950f, -0.98555606f}, +{0.15643447f, -0.98768834f}, {0.14349262f, -0.98965139f}, +{0.13052619f, -0.99144486f}, {0.11753740f, -0.99306846f}, +{0.10452846f, -0.99452190f}, {0.091501619f, -0.99580493f}, +{0.078459096f, -0.99691733f}, {0.065403129f, -0.99785892f}, +{0.052335956f, -0.99862953f}, {0.039259816f, -0.99922904f}, +{0.026176948f, -0.99965732f}, {0.013089596f, -0.99991433f}, +{6.1230318e-17f, -1.0000000f}, {-0.013089596f, -0.99991433f}, +{-0.026176948f, -0.99965732f}, {-0.039259816f, -0.99922904f}, +{-0.052335956f, -0.99862953f}, {-0.065403129f, -0.99785892f}, +{-0.078459096f, -0.99691733f}, {-0.091501619f, -0.99580493f}, +{-0.10452846f, -0.99452190f}, {-0.11753740f, -0.99306846f}, +{-0.13052619f, -0.99144486f}, {-0.14349262f, -0.98965139f}, +{-0.15643447f, -0.98768834f}, {-0.16934950f, -0.98555606f}, +{-0.18223553f, -0.98325491f}, {-0.19509032f, -0.98078528f}, +{-0.20791169f, -0.97814760f}, {-0.22069744f, -0.97534232f}, +{-0.23344536f, -0.97236992f}, {-0.24615329f, -0.96923091f}, +{-0.25881905f, -0.96592583f}, {-0.27144045f, -0.96245524f}, +{-0.28401534f, -0.95881973f}, {-0.29654157f, -0.95501994f}, +{-0.30901699f, -0.95105652f}, {-0.32143947f, -0.94693013f}, +{-0.33380686f, -0.94264149f}, {-0.34611706f, -0.93819134f}, +{-0.35836795f, -0.93358043f}, {-0.37055744f, -0.92880955f}, +{-0.38268343f, -0.92387953f}, {-0.39474386f, -0.91879121f}, +{-0.40673664f, -0.91354546f}, {-0.41865974f, -0.90814317f}, +{-0.43051110f, -0.90258528f}, {-0.44228869f, -0.89687274f}, +{-0.45399050f, -0.89100652f}, {-0.46561452f, -0.88498764f}, +{-0.47715876f, -0.87881711f}, {-0.48862124f, -0.87249601f}, +{-0.50000000f, -0.86602540f}, {-0.51129309f, -0.85940641f}, +{-0.52249856f, -0.85264016f}, {-0.53361452f, -0.84572782f}, +{-0.54463904f, -0.83867057f}, {-0.55557023f, -0.83146961f}, +{-0.56640624f, -0.82412619f}, {-0.57714519f, -0.81664156f}, +{-0.58778525f, -0.80901699f}, {-0.59832460f, -0.80125381f}, +{-0.60876143f, -0.79335334f}, {-0.61909395f, -0.78531693f}, +{-0.62932039f, -0.77714596f}, {-0.63943900f, -0.76884183f}, +{-0.64944805f, -0.76040597f}, {-0.65934582f, -0.75183981f}, +{-0.66913061f, -0.74314483f}, {-0.67880075f, -0.73432251f}, +{-0.68835458f, -0.72537437f}, {-0.69779046f, -0.71630194f}, +{-0.70710678f, -0.70710678f}, {-0.71630194f, -0.69779046f}, +{-0.72537437f, -0.68835458f}, {-0.73432251f, -0.67880075f}, +{-0.74314483f, -0.66913061f}, {-0.75183981f, -0.65934582f}, +{-0.76040597f, -0.64944805f}, {-0.76884183f, -0.63943900f}, +{-0.77714596f, -0.62932039f}, {-0.78531693f, -0.61909395f}, +{-0.79335334f, -0.60876143f}, {-0.80125381f, -0.59832460f}, +{-0.80901699f, -0.58778525f}, {-0.81664156f, -0.57714519f}, +{-0.82412619f, -0.56640624f}, {-0.83146961f, -0.55557023f}, +{-0.83867057f, -0.54463904f}, {-0.84572782f, -0.53361452f}, +{-0.85264016f, -0.52249856f}, {-0.85940641f, -0.51129309f}, +{-0.86602540f, -0.50000000f}, {-0.87249601f, -0.48862124f}, +{-0.87881711f, -0.47715876f}, {-0.88498764f, -0.46561452f}, +{-0.89100652f, -0.45399050f}, {-0.89687274f, -0.44228869f}, +{-0.90258528f, -0.43051110f}, {-0.90814317f, -0.41865974f}, +{-0.91354546f, -0.40673664f}, {-0.91879121f, -0.39474386f}, +{-0.92387953f, -0.38268343f}, {-0.92880955f, -0.37055744f}, +{-0.93358043f, -0.35836795f}, {-0.93819134f, -0.34611706f}, +{-0.94264149f, -0.33380686f}, {-0.94693013f, -0.32143947f}, +{-0.95105652f, -0.30901699f}, {-0.95501994f, -0.29654157f}, +{-0.95881973f, -0.28401534f}, {-0.96245524f, -0.27144045f}, +{-0.96592583f, -0.25881905f}, {-0.96923091f, -0.24615329f}, +{-0.97236992f, -0.23344536f}, {-0.97534232f, -0.22069744f}, +{-0.97814760f, -0.20791169f}, {-0.98078528f, -0.19509032f}, +{-0.98325491f, -0.18223553f}, {-0.98555606f, -0.16934950f}, +{-0.98768834f, -0.15643447f}, {-0.98965139f, -0.14349262f}, +{-0.99144486f, -0.13052619f}, {-0.99306846f, -0.11753740f}, +{-0.99452190f, -0.10452846f}, {-0.99580493f, -0.091501619f}, +{-0.99691733f, -0.078459096f}, {-0.99785892f, -0.065403129f}, +{-0.99862953f, -0.052335956f}, {-0.99922904f, -0.039259816f}, +{-0.99965732f, -0.026176948f}, {-0.99991433f, -0.013089596f}, +{-1.0000000f, -1.2246064e-16f}, {-0.99991433f, 0.013089596f}, +{-0.99965732f, 0.026176948f}, {-0.99922904f, 0.039259816f}, +{-0.99862953f, 0.052335956f}, {-0.99785892f, 0.065403129f}, +{-0.99691733f, 0.078459096f}, {-0.99580493f, 0.091501619f}, +{-0.99452190f, 0.10452846f}, {-0.99306846f, 0.11753740f}, +{-0.99144486f, 0.13052619f}, {-0.98965139f, 0.14349262f}, +{-0.98768834f, 0.15643447f}, {-0.98555606f, 0.16934950f}, +{-0.98325491f, 0.18223553f}, {-0.98078528f, 0.19509032f}, +{-0.97814760f, 0.20791169f}, {-0.97534232f, 0.22069744f}, +{-0.97236992f, 0.23344536f}, {-0.96923091f, 0.24615329f}, +{-0.96592583f, 0.25881905f}, {-0.96245524f, 0.27144045f}, +{-0.95881973f, 0.28401534f}, {-0.95501994f, 0.29654157f}, +{-0.95105652f, 0.30901699f}, {-0.94693013f, 0.32143947f}, +{-0.94264149f, 0.33380686f}, {-0.93819134f, 0.34611706f}, +{-0.93358043f, 0.35836795f}, {-0.92880955f, 0.37055744f}, +{-0.92387953f, 0.38268343f}, {-0.91879121f, 0.39474386f}, +{-0.91354546f, 0.40673664f}, {-0.90814317f, 0.41865974f}, +{-0.90258528f, 0.43051110f}, {-0.89687274f, 0.44228869f}, +{-0.89100652f, 0.45399050f}, {-0.88498764f, 0.46561452f}, +{-0.87881711f, 0.47715876f}, {-0.87249601f, 0.48862124f}, +{-0.86602540f, 0.50000000f}, {-0.85940641f, 0.51129309f}, +{-0.85264016f, 0.52249856f}, {-0.84572782f, 0.53361452f}, +{-0.83867057f, 0.54463904f}, {-0.83146961f, 0.55557023f}, +{-0.82412619f, 0.56640624f}, {-0.81664156f, 0.57714519f}, +{-0.80901699f, 0.58778525f}, {-0.80125381f, 0.59832460f}, +{-0.79335334f, 0.60876143f}, {-0.78531693f, 0.61909395f}, +{-0.77714596f, 0.62932039f}, {-0.76884183f, 0.63943900f}, +{-0.76040597f, 0.64944805f}, {-0.75183981f, 0.65934582f}, +{-0.74314483f, 0.66913061f}, {-0.73432251f, 0.67880075f}, +{-0.72537437f, 0.68835458f}, {-0.71630194f, 0.69779046f}, +{-0.70710678f, 0.70710678f}, {-0.69779046f, 0.71630194f}, +{-0.68835458f, 0.72537437f}, {-0.67880075f, 0.73432251f}, +{-0.66913061f, 0.74314483f}, {-0.65934582f, 0.75183981f}, +{-0.64944805f, 0.76040597f}, {-0.63943900f, 0.76884183f}, +{-0.62932039f, 0.77714596f}, {-0.61909395f, 0.78531693f}, +{-0.60876143f, 0.79335334f}, {-0.59832460f, 0.80125381f}, +{-0.58778525f, 0.80901699f}, {-0.57714519f, 0.81664156f}, +{-0.56640624f, 0.82412619f}, {-0.55557023f, 0.83146961f}, +{-0.54463904f, 0.83867057f}, {-0.53361452f, 0.84572782f}, +{-0.52249856f, 0.85264016f}, {-0.51129309f, 0.85940641f}, +{-0.50000000f, 0.86602540f}, {-0.48862124f, 0.87249601f}, +{-0.47715876f, 0.87881711f}, {-0.46561452f, 0.88498764f}, +{-0.45399050f, 0.89100652f}, {-0.44228869f, 0.89687274f}, +{-0.43051110f, 0.90258528f}, {-0.41865974f, 0.90814317f}, +{-0.40673664f, 0.91354546f}, {-0.39474386f, 0.91879121f}, +{-0.38268343f, 0.92387953f}, {-0.37055744f, 0.92880955f}, +{-0.35836795f, 0.93358043f}, {-0.34611706f, 0.93819134f}, +{-0.33380686f, 0.94264149f}, {-0.32143947f, 0.94693013f}, +{-0.30901699f, 0.95105652f}, {-0.29654157f, 0.95501994f}, +{-0.28401534f, 0.95881973f}, {-0.27144045f, 0.96245524f}, +{-0.25881905f, 0.96592583f}, {-0.24615329f, 0.96923091f}, +{-0.23344536f, 0.97236992f}, {-0.22069744f, 0.97534232f}, +{-0.20791169f, 0.97814760f}, {-0.19509032f, 0.98078528f}, +{-0.18223553f, 0.98325491f}, {-0.16934950f, 0.98555606f}, +{-0.15643447f, 0.98768834f}, {-0.14349262f, 0.98965139f}, +{-0.13052619f, 0.99144486f}, {-0.11753740f, 0.99306846f}, +{-0.10452846f, 0.99452190f}, {-0.091501619f, 0.99580493f}, +{-0.078459096f, 0.99691733f}, {-0.065403129f, 0.99785892f}, +{-0.052335956f, 0.99862953f}, {-0.039259816f, 0.99922904f}, +{-0.026176948f, 0.99965732f}, {-0.013089596f, 0.99991433f}, +{-1.8369095e-16f, 1.0000000f}, {0.013089596f, 0.99991433f}, +{0.026176948f, 0.99965732f}, {0.039259816f, 0.99922904f}, +{0.052335956f, 0.99862953f}, {0.065403129f, 0.99785892f}, +{0.078459096f, 0.99691733f}, {0.091501619f, 0.99580493f}, +{0.10452846f, 0.99452190f}, {0.11753740f, 0.99306846f}, +{0.13052619f, 0.99144486f}, {0.14349262f, 0.98965139f}, +{0.15643447f, 0.98768834f}, {0.16934950f, 0.98555606f}, +{0.18223553f, 0.98325491f}, {0.19509032f, 0.98078528f}, +{0.20791169f, 0.97814760f}, {0.22069744f, 0.97534232f}, +{0.23344536f, 0.97236992f}, {0.24615329f, 0.96923091f}, +{0.25881905f, 0.96592583f}, {0.27144045f, 0.96245524f}, +{0.28401534f, 0.95881973f}, {0.29654157f, 0.95501994f}, +{0.30901699f, 0.95105652f}, {0.32143947f, 0.94693013f}, +{0.33380686f, 0.94264149f}, {0.34611706f, 0.93819134f}, +{0.35836795f, 0.93358043f}, {0.37055744f, 0.92880955f}, +{0.38268343f, 0.92387953f}, {0.39474386f, 0.91879121f}, +{0.40673664f, 0.91354546f}, {0.41865974f, 0.90814317f}, +{0.43051110f, 0.90258528f}, {0.44228869f, 0.89687274f}, +{0.45399050f, 0.89100652f}, {0.46561452f, 0.88498764f}, +{0.47715876f, 0.87881711f}, {0.48862124f, 0.87249601f}, +{0.50000000f, 0.86602540f}, {0.51129309f, 0.85940641f}, +{0.52249856f, 0.85264016f}, {0.53361452f, 0.84572782f}, +{0.54463904f, 0.83867057f}, {0.55557023f, 0.83146961f}, +{0.56640624f, 0.82412619f}, {0.57714519f, 0.81664156f}, +{0.58778525f, 0.80901699f}, {0.59832460f, 0.80125381f}, +{0.60876143f, 0.79335334f}, {0.61909395f, 0.78531693f}, +{0.62932039f, 0.77714596f}, {0.63943900f, 0.76884183f}, +{0.64944805f, 0.76040597f}, {0.65934582f, 0.75183981f}, +{0.66913061f, 0.74314483f}, {0.67880075f, 0.73432251f}, +{0.68835458f, 0.72537437f}, {0.69779046f, 0.71630194f}, +{0.70710678f, 0.70710678f}, {0.71630194f, 0.69779046f}, +{0.72537437f, 0.68835458f}, {0.73432251f, 0.67880075f}, +{0.74314483f, 0.66913061f}, {0.75183981f, 0.65934582f}, +{0.76040597f, 0.64944805f}, {0.76884183f, 0.63943900f}, +{0.77714596f, 0.62932039f}, {0.78531693f, 0.61909395f}, +{0.79335334f, 0.60876143f}, {0.80125381f, 0.59832460f}, +{0.80901699f, 0.58778525f}, {0.81664156f, 0.57714519f}, +{0.82412619f, 0.56640624f}, {0.83146961f, 0.55557023f}, +{0.83867057f, 0.54463904f}, {0.84572782f, 0.53361452f}, +{0.85264016f, 0.52249856f}, {0.85940641f, 0.51129309f}, +{0.86602540f, 0.50000000f}, {0.87249601f, 0.48862124f}, +{0.87881711f, 0.47715876f}, {0.88498764f, 0.46561452f}, +{0.89100652f, 0.45399050f}, {0.89687274f, 0.44228869f}, +{0.90258528f, 0.43051110f}, {0.90814317f, 0.41865974f}, +{0.91354546f, 0.40673664f}, {0.91879121f, 0.39474386f}, +{0.92387953f, 0.38268343f}, {0.92880955f, 0.37055744f}, +{0.93358043f, 0.35836795f}, {0.93819134f, 0.34611706f}, +{0.94264149f, 0.33380686f}, {0.94693013f, 0.32143947f}, +{0.95105652f, 0.30901699f}, {0.95501994f, 0.29654157f}, +{0.95881973f, 0.28401534f}, {0.96245524f, 0.27144045f}, +{0.96592583f, 0.25881905f}, {0.96923091f, 0.24615329f}, +{0.97236992f, 0.23344536f}, {0.97534232f, 0.22069744f}, +{0.97814760f, 0.20791169f}, {0.98078528f, 0.19509032f}, +{0.98325491f, 0.18223553f}, {0.98555606f, 0.16934950f}, +{0.98768834f, 0.15643447f}, {0.98965139f, 0.14349262f}, +{0.99144486f, 0.13052619f}, {0.99306846f, 0.11753740f}, +{0.99452190f, 0.10452846f}, {0.99580493f, 0.091501619f}, +{0.99691733f, 0.078459096f}, {0.99785892f, 0.065403129f}, +{0.99862953f, 0.052335956f}, {0.99922904f, 0.039259816f}, +{0.99965732f, 0.026176948f}, {0.99991433f, 0.013089596f}, +}; +#ifndef FFT_BITREV480 +#define FFT_BITREV480 +static const opus_int16 fft_bitrev480[480] = { +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, +}; +#endif + +#ifndef FFT_BITREV240 +#define FFT_BITREV240 +static const opus_int16 fft_bitrev240[240] = { +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, +}; +#endif + +#ifndef FFT_BITREV120 +#define FFT_BITREV120 +static const opus_int16 fft_bitrev120[120] = { +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, +}; +#endif + +#ifndef FFT_BITREV60 +#define FFT_BITREV60 +static const opus_int16 fft_bitrev60[60] = { +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, +}; +#endif + +#ifndef FFT_STATE48000_960_0 +#define FFT_STATE48000_960_0 +static const kiss_fft_state fft_state48000_960_0 = { +480, /* nfft */ +0.002083333f, /* scale */ +-1, /* shift */ +{5, 96, 3, 32, 4, 8, 2, 4, 4, 1, 0, 0, 0, 0, 0, 0, }, /* factors */ +fft_bitrev480, /* bitrev */ +fft_twiddles48000_960, /* bitrev */ +#ifdef OVERRIDE_FFT +(arch_fft_state *)&cfg_arch_480, +#else +NULL, +#endif +}; +#endif + +#ifndef FFT_STATE48000_960_1 +#define FFT_STATE48000_960_1 +static const kiss_fft_state fft_state48000_960_1 = { +240, /* nfft */ +0.004166667f, /* scale */ +1, /* shift */ +{5, 48, 3, 16, 4, 4, 4, 1, 0, 0, 0, 0, 0, 0, 0, 0, }, /* factors */ +fft_bitrev240, /* bitrev */ +fft_twiddles48000_960, /* bitrev */ +#ifdef OVERRIDE_FFT +(arch_fft_state *)&cfg_arch_240, +#else +NULL, +#endif +}; +#endif + +#ifndef FFT_STATE48000_960_2 +#define FFT_STATE48000_960_2 +static const kiss_fft_state fft_state48000_960_2 = { +120, /* nfft */ +0.008333333f, /* scale */ +2, /* shift */ +{5, 24, 3, 8, 2, 4, 4, 1, 0, 0, 0, 0, 0, 0, 0, 0, }, /* factors */ +fft_bitrev120, /* bitrev */ +fft_twiddles48000_960, /* bitrev */ +#ifdef OVERRIDE_FFT +(arch_fft_state *)&cfg_arch_120, +#else +NULL, +#endif +}; +#endif + +#ifndef FFT_STATE48000_960_3 +#define FFT_STATE48000_960_3 +static const kiss_fft_state fft_state48000_960_3 = { +60, /* nfft */ +0.016666667f, /* scale */ +3, /* shift */ +{5, 12, 3, 4, 4, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, /* factors */ +fft_bitrev60, /* bitrev */ +fft_twiddles48000_960, /* bitrev */ +#ifdef OVERRIDE_FFT +(arch_fft_state *)&cfg_arch_60, +#else +NULL, +#endif +}; +#endif + +#endif + +#ifndef MDCT_TWIDDLES960 +#define MDCT_TWIDDLES960 +static const opus_val16 mdct_twiddles960[1800] = { +0.99999994f, 0.99999321f, 0.99997580f, 0.99994773f, 0.99990886f, +0.99985933f, 0.99979913f, 0.99972820f, 0.99964654f, 0.99955416f, +0.99945110f, 0.99933738f, 0.99921292f, 0.99907774f, 0.99893188f, +0.99877530f, 0.99860805f, 0.99843007f, 0.99824142f, 0.99804211f, +0.99783206f, 0.99761140f, 0.99737996f, 0.99713790f, 0.99688518f, +0.99662173f, 0.99634761f, 0.99606287f, 0.99576741f, 0.99546129f, +0.99514455f, 0.99481714f, 0.99447906f, 0.99413031f, 0.99377096f, +0.99340093f, 0.99302030f, 0.99262899f, 0.99222708f, 0.99181455f, +0.99139136f, 0.99095762f, 0.99051321f, 0.99005818f, 0.98959261f, +0.98911643f, 0.98862964f, 0.98813224f, 0.98762429f, 0.98710573f, +0.98657662f, 0.98603696f, 0.98548669f, 0.98492593f, 0.98435456f, +0.98377270f, 0.98318028f, 0.98257732f, 0.98196387f, 0.98133987f, +0.98070538f, 0.98006040f, 0.97940493f, 0.97873890f, 0.97806245f, +0.97737551f, 0.97667813f, 0.97597027f, 0.97525197f, 0.97452319f, +0.97378403f, 0.97303438f, 0.97227436f, 0.97150391f, 0.97072303f, +0.96993178f, 0.96913016f, 0.96831810f, 0.96749574f, 0.96666300f, +0.96581990f, 0.96496642f, 0.96410263f, 0.96322852f, 0.96234411f, +0.96144938f, 0.96054435f, 0.95962906f, 0.95870346f, 0.95776761f, +0.95682150f, 0.95586514f, 0.95489854f, 0.95392174f, 0.95293468f, +0.95193744f, 0.95093000f, 0.94991243f, 0.94888461f, 0.94784665f, +0.94679856f, 0.94574034f, 0.94467193f, 0.94359344f, 0.94250488f, +0.94140619f, 0.94029742f, 0.93917859f, 0.93804967f, 0.93691075f, +0.93576175f, 0.93460274f, 0.93343377f, 0.93225473f, 0.93106574f, +0.92986679f, 0.92865789f, 0.92743903f, 0.92621022f, 0.92497152f, +0.92372292f, 0.92246443f, 0.92119598f, 0.91991776f, 0.91862965f, +0.91733170f, 0.91602397f, 0.91470635f, 0.91337901f, 0.91204184f, +0.91069490f, 0.90933824f, 0.90797186f, 0.90659571f, 0.90520984f, +0.90381432f, 0.90240908f, 0.90099424f, 0.89956969f, 0.89813554f, +0.89669174f, 0.89523834f, 0.89377540f, 0.89230281f, 0.89082074f, +0.88932908f, 0.88782793f, 0.88631725f, 0.88479710f, 0.88326746f, +0.88172835f, 0.88017982f, 0.87862182f, 0.87705445f, 0.87547767f, +0.87389153f, 0.87229604f, 0.87069118f, 0.86907703f, 0.86745358f, +0.86582077f, 0.86417878f, 0.86252749f, 0.86086690f, 0.85919720f, +0.85751826f, 0.85583007f, 0.85413277f, 0.85242635f, 0.85071075f, +0.84898609f, 0.84725231f, 0.84550947f, 0.84375757f, 0.84199661f, +0.84022665f, 0.83844769f, 0.83665979f, 0.83486289f, 0.83305705f, +0.83124226f, 0.82941860f, 0.82758605f, 0.82574469f, 0.82389444f, +0.82203537f, 0.82016748f, 0.81829083f, 0.81640542f, 0.81451124f, +0.81260836f, 0.81069672f, 0.80877650f, 0.80684757f, 0.80490994f, +0.80296379f, 0.80100900f, 0.79904562f, 0.79707366f, 0.79509324f, +0.79310423f, 0.79110676f, 0.78910083f, 0.78708643f, 0.78506362f, +0.78303236f, 0.78099275f, 0.77894479f, 0.77688843f, 0.77482378f, +0.77275085f, 0.77066964f, 0.76858020f, 0.76648247f, 0.76437658f, +0.76226246f, 0.76014024f, 0.75800985f, 0.75587130f, 0.75372469f, +0.75157005f, 0.74940729f, 0.74723655f, 0.74505776f, 0.74287105f, +0.74067634f, 0.73847371f, 0.73626316f, 0.73404479f, 0.73181850f, +0.72958434f, 0.72734243f, 0.72509271f, 0.72283524f, 0.72057003f, +0.71829706f, 0.71601641f, 0.71372813f, 0.71143216f, 0.70912862f, +0.70681745f, 0.70449871f, 0.70217246f, 0.69983864f, 0.69749737f, +0.69514859f, 0.69279242f, 0.69042879f, 0.68805778f, 0.68567938f, +0.68329364f, 0.68090063f, 0.67850029f, 0.67609268f, 0.67367786f, +0.67125577f, 0.66882652f, 0.66639012f, 0.66394657f, 0.66149592f, +0.65903819f, 0.65657341f, 0.65410155f, 0.65162271f, 0.64913690f, +0.64664418f, 0.64414448f, 0.64163786f, 0.63912445f, 0.63660413f, +0.63407701f, 0.63154310f, 0.62900239f, 0.62645501f, 0.62390089f, +0.62134010f, 0.61877263f, 0.61619854f, 0.61361790f, 0.61103064f, +0.60843682f, 0.60583651f, 0.60322970f, 0.60061646f, 0.59799677f, +0.59537065f, 0.59273821f, 0.59009939f, 0.58745426f, 0.58480281f, +0.58214509f, 0.57948118f, 0.57681108f, 0.57413477f, 0.57145232f, +0.56876373f, 0.56606907f, 0.56336832f, 0.56066155f, 0.55794877f, +0.55523002f, 0.55250537f, 0.54977477f, 0.54703826f, 0.54429591f, +0.54154772f, 0.53879374f, 0.53603399f, 0.53326851f, 0.53049731f, +0.52772039f, 0.52493787f, 0.52214974f, 0.51935595f, 0.51655668f, +0.51375180f, 0.51094145f, 0.50812566f, 0.50530440f, 0.50247771f, +0.49964568f, 0.49680826f, 0.49396557f, 0.49111754f, 0.48826426f, +0.48540577f, 0.48254207f, 0.47967321f, 0.47679919f, 0.47392011f, +0.47103590f, 0.46814668f, 0.46525243f, 0.46235323f, 0.45944905f, +0.45653993f, 0.45362595f, 0.45070711f, 0.44778344f, 0.44485497f, +0.44192174f, 0.43898380f, 0.43604112f, 0.43309379f, 0.43014181f, +0.42718524f, 0.42422408f, 0.42125839f, 0.41828820f, 0.41531351f, +0.41233435f, 0.40935081f, 0.40636289f, 0.40337059f, 0.40037400f, +0.39737311f, 0.39436796f, 0.39135858f, 0.38834500f, 0.38532731f, +0.38230544f, 0.37927949f, 0.37624949f, 0.37321547f, 0.37017745f, +0.36713544f, 0.36408952f, 0.36103970f, 0.35798600f, 0.35492846f, +0.35186714f, 0.34880206f, 0.34573323f, 0.34266070f, 0.33958447f, +0.33650464f, 0.33342120f, 0.33033419f, 0.32724363f, 0.32414958f, +0.32105204f, 0.31795108f, 0.31484672f, 0.31173897f, 0.30862790f, +0.30551350f, 0.30239585f, 0.29927495f, 0.29615086f, 0.29302359f, +0.28989318f, 0.28675964f, 0.28362307f, 0.28048345f, 0.27734083f, +0.27419522f, 0.27104670f, 0.26789525f, 0.26474094f, 0.26158381f, +0.25842386f, 0.25526115f, 0.25209570f, 0.24892756f, 0.24575676f, +0.24258332f, 0.23940729f, 0.23622867f, 0.23304754f, 0.22986393f, +0.22667783f, 0.22348931f, 0.22029841f, 0.21710514f, 0.21390954f, +0.21071166f, 0.20751151f, 0.20430915f, 0.20110460f, 0.19789790f, +0.19468907f, 0.19147816f, 0.18826519f, 0.18505022f, 0.18183327f, +0.17861435f, 0.17539354f, 0.17217083f, 0.16894630f, 0.16571994f, +0.16249183f, 0.15926196f, 0.15603039f, 0.15279715f, 0.14956227f, +0.14632578f, 0.14308774f, 0.13984816f, 0.13660708f, 0.13336454f, +0.13012058f, 0.12687522f, 0.12362850f, 0.12038045f, 0.11713112f, +0.11388054f, 0.11062872f, 0.10737573f, 0.10412160f, 0.10086634f, +0.097609997f, 0.094352618f, 0.091094226f, 0.087834857f, 0.084574550f, +0.081313334f, 0.078051247f, 0.074788325f, 0.071524605f, 0.068260118f, +0.064994894f, 0.061728980f, 0.058462404f, 0.055195201f, 0.051927410f, +0.048659060f, 0.045390189f, 0.042120833f, 0.038851023f, 0.035580799f, +0.032310195f, 0.029039243f, 0.025767982f, 0.022496443f, 0.019224664f, +0.015952680f, 0.012680525f, 0.0094082337f, 0.0061358409f, 0.0028633832f, +-0.00040910527f, -0.0036815894f, -0.0069540343f, -0.010226404f, -0.013498665f, +-0.016770782f, -0.020042717f, -0.023314439f, -0.026585912f, -0.029857099f, +-0.033127967f, -0.036398482f, -0.039668605f, -0.042938303f, -0.046207540f, +-0.049476285f, -0.052744497f, -0.056012146f, -0.059279196f, -0.062545612f, +-0.065811358f, -0.069076397f, -0.072340697f, -0.075604223f, -0.078866936f, +-0.082128808f, -0.085389800f, -0.088649876f, -0.091909006f, -0.095167145f, +-0.098424271f, -0.10168034f, -0.10493532f, -0.10818918f, -0.11144188f, +-0.11469338f, -0.11794366f, -0.12119267f, -0.12444039f, -0.12768677f, +-0.13093179f, -0.13417540f, -0.13741758f, -0.14065829f, -0.14389749f, +-0.14713514f, -0.15037122f, -0.15360570f, -0.15683852f, -0.16006967f, +-0.16329910f, -0.16652679f, -0.16975269f, -0.17297678f, -0.17619900f, +-0.17941935f, -0.18263777f, -0.18585424f, -0.18906870f, -0.19228116f, +-0.19549155f, -0.19869985f, -0.20190603f, -0.20511003f, -0.20831184f, +-0.21151142f, -0.21470875f, -0.21790376f, -0.22109644f, -0.22428675f, +-0.22747467f, -0.23066014f, -0.23384315f, -0.23702365f, -0.24020162f, +-0.24337701f, -0.24654980f, -0.24971995f, -0.25288740f, -0.25605217f, +-0.25921419f, -0.26237345f, -0.26552987f, -0.26868346f, -0.27183419f, +-0.27498198f, -0.27812684f, -0.28126872f, -0.28440759f, -0.28754342f, +-0.29067615f, -0.29380578f, -0.29693225f, -0.30005556f, -0.30317566f, +-0.30629250f, -0.30940607f, -0.31251630f, -0.31562322f, -0.31872672f, +-0.32182685f, -0.32492352f, -0.32801670f, -0.33110636f, -0.33419248f, +-0.33727503f, -0.34035397f, -0.34342924f, -0.34650084f, -0.34956875f, +-0.35263291f, -0.35569328f, -0.35874987f, -0.36180258f, -0.36485144f, +-0.36789638f, -0.37093741f, -0.37397444f, -0.37700745f, -0.38003644f, +-0.38306138f, -0.38608220f, -0.38909888f, -0.39211139f, -0.39511973f, +-0.39812380f, -0.40112361f, -0.40411916f, -0.40711036f, -0.41009718f, +-0.41307965f, -0.41605768f, -0.41903123f, -0.42200032f, -0.42496487f, +-0.42792490f, -0.43088034f, -0.43383113f, -0.43677729f, -0.43971881f, +-0.44265559f, -0.44558764f, -0.44851488f, -0.45143735f, -0.45435500f, +-0.45726776f, -0.46017563f, -0.46307856f, -0.46597654f, -0.46886954f, +-0.47175750f, -0.47464043f, -0.47751826f, -0.48039100f, -0.48325855f, +-0.48612097f, -0.48897815f, -0.49183011f, -0.49467680f, -0.49751821f, +-0.50035429f, -0.50318497f, -0.50601029f, -0.50883019f, -0.51164466f, +-0.51445359f, -0.51725709f, -0.52005500f, -0.52284735f, -0.52563411f, +-0.52841520f, -0.53119069f, -0.53396046f, -0.53672451f, -0.53948283f, +-0.54223537f, -0.54498214f, -0.54772300f, -0.55045801f, -0.55318713f, +-0.55591035f, -0.55862761f, -0.56133890f, -0.56404412f, -0.56674337f, +-0.56943649f, -0.57212353f, -0.57480448f, -0.57747924f, -0.58014780f, +-0.58281022f, -0.58546633f, -0.58811617f, -0.59075975f, -0.59339696f, +-0.59602785f, -0.59865236f, -0.60127044f, -0.60388207f, -0.60648727f, +-0.60908598f, -0.61167812f, -0.61426371f, -0.61684275f, -0.61941516f, +-0.62198097f, -0.62454009f, -0.62709254f, -0.62963831f, -0.63217729f, +-0.63470948f, -0.63723493f, -0.63975352f, -0.64226526f, -0.64477009f, +-0.64726806f, -0.64975911f, -0.65224314f, -0.65472025f, -0.65719032f, +-0.65965337f, -0.66210932f, -0.66455823f, -0.66700000f, -0.66943461f, +-0.67186207f, -0.67428231f, -0.67669535f, -0.67910111f, -0.68149966f, +-0.68389088f, -0.68627477f, -0.68865126f, -0.69102043f, -0.69338220f, +-0.69573659f, -0.69808346f, -0.70042288f, -0.70275480f, -0.70507920f, +-0.70739603f, -0.70970529f, -0.71200693f, -0.71430099f, -0.71658736f, +-0.71886611f, -0.72113711f, -0.72340041f, -0.72565591f, -0.72790372f, +-0.73014367f, -0.73237586f, -0.73460019f, -0.73681659f, -0.73902518f, +-0.74122584f, -0.74341851f, -0.74560326f, -0.74778003f, -0.74994880f, +-0.75210953f, -0.75426215f, -0.75640678f, -0.75854325f, -0.76067162f, +-0.76279181f, -0.76490390f, -0.76700771f, -0.76910341f, -0.77119076f, +-0.77326995f, -0.77534080f, -0.77740335f, -0.77945763f, -0.78150350f, +-0.78354102f, -0.78557014f, -0.78759086f, -0.78960317f, -0.79160696f, +-0.79360235f, -0.79558921f, -0.79756755f, -0.79953730f, -0.80149853f, +-0.80345118f, -0.80539525f, -0.80733067f, -0.80925739f, -0.81117553f, +-0.81308490f, -0.81498563f, -0.81687760f, -0.81876087f, -0.82063532f, +-0.82250100f, -0.82435787f, -0.82620591f, -0.82804507f, -0.82987541f, +-0.83169687f, -0.83350939f, -0.83531296f, -0.83710766f, -0.83889335f, +-0.84067005f, -0.84243774f, -0.84419644f, -0.84594607f, -0.84768665f, +-0.84941816f, -0.85114056f, -0.85285389f, -0.85455805f, -0.85625303f, +-0.85793889f, -0.85961550f, -0.86128294f, -0.86294121f, -0.86459017f, +-0.86622989f, -0.86786032f, -0.86948150f, -0.87109333f, -0.87269586f, +-0.87428904f, -0.87587279f, -0.87744725f, -0.87901229f, -0.88056785f, +-0.88211405f, -0.88365078f, -0.88517809f, -0.88669586f, -0.88820416f, +-0.88970292f, -0.89119220f, -0.89267188f, -0.89414203f, -0.89560264f, +-0.89705360f, -0.89849502f, -0.89992678f, -0.90134889f, -0.90276134f, +-0.90416414f, -0.90555727f, -0.90694070f, -0.90831441f, -0.90967834f, +-0.91103262f, -0.91237706f, -0.91371179f, -0.91503674f, -0.91635185f, +-0.91765714f, -0.91895264f, -0.92023826f, -0.92151409f, -0.92277998f, +-0.92403603f, -0.92528218f, -0.92651838f, -0.92774469f, -0.92896110f, +-0.93016750f, -0.93136400f, -0.93255049f, -0.93372697f, -0.93489349f, +-0.93604994f, -0.93719643f, -0.93833286f, -0.93945926f, -0.94057560f, +-0.94168180f, -0.94277799f, -0.94386405f, -0.94494003f, -0.94600588f, +-0.94706154f, -0.94810712f, -0.94914252f, -0.95016778f, -0.95118284f, +-0.95218778f, -0.95318246f, -0.95416695f, -0.95514119f, -0.95610523f, +-0.95705903f, -0.95800257f, -0.95893586f, -0.95985889f, -0.96077162f, +-0.96167403f, -0.96256620f, -0.96344805f, -0.96431959f, -0.96518075f, +-0.96603161f, -0.96687216f, -0.96770233f, -0.96852213f, -0.96933156f, +-0.97013056f, -0.97091925f, -0.97169751f, -0.97246534f, -0.97322279f, +-0.97396982f, -0.97470641f, -0.97543252f, -0.97614825f, -0.97685349f, +-0.97754824f, -0.97823256f, -0.97890645f, -0.97956979f, -0.98022264f, +-0.98086500f, -0.98149687f, -0.98211825f, -0.98272908f, -0.98332942f, +-0.98391914f, -0.98449844f, -0.98506713f, -0.98562527f, -0.98617285f, +-0.98670989f, -0.98723638f, -0.98775226f, -0.98825759f, -0.98875231f, +-0.98923647f, -0.98971003f, -0.99017298f, -0.99062532f, -0.99106705f, +-0.99149817f, -0.99191868f, -0.99232858f, -0.99272782f, -0.99311644f, +-0.99349445f, -0.99386179f, -0.99421853f, -0.99456459f, -0.99489999f, +-0.99522477f, -0.99553883f, -0.99584228f, -0.99613506f, -0.99641716f, +-0.99668860f, -0.99694937f, -0.99719942f, -0.99743885f, -0.99766755f, +-0.99788558f, -0.99809295f, -0.99828959f, -0.99847561f, -0.99865085f, +-0.99881548f, -0.99896932f, -0.99911255f, -0.99924499f, -0.99936682f, +-0.99947786f, -0.99957830f, -0.99966794f, -0.99974692f, -0.99981517f, +-0.99987274f, -0.99991959f, -0.99995571f, -0.99998116f, -0.99999589f, +0.99999964f, 0.99997288f, 0.99990326f, 0.99979085f, 0.99963558f, +0.99943751f, 0.99919659f, 0.99891287f, 0.99858636f, 0.99821711f, +0.99780506f, 0.99735034f, 0.99685282f, 0.99631262f, 0.99572974f, +0.99510419f, 0.99443603f, 0.99372530f, 0.99297196f, 0.99217612f, +0.99133772f, 0.99045694f, 0.98953366f, 0.98856801f, 0.98756003f, +0.98650974f, 0.98541719f, 0.98428243f, 0.98310548f, 0.98188645f, +0.98062533f, 0.97932225f, 0.97797716f, 0.97659022f, 0.97516143f, +0.97369087f, 0.97217858f, 0.97062469f, 0.96902919f, 0.96739221f, +0.96571374f, 0.96399397f, 0.96223283f, 0.96043050f, 0.95858705f, +0.95670253f, 0.95477700f, 0.95281059f, 0.95080340f, 0.94875544f, +0.94666684f, 0.94453770f, 0.94236809f, 0.94015813f, 0.93790787f, +0.93561745f, 0.93328691f, 0.93091643f, 0.92850608f, 0.92605597f, +0.92356616f, 0.92103678f, 0.91846794f, 0.91585976f, 0.91321236f, +0.91052586f, 0.90780038f, 0.90503591f, 0.90223277f, 0.89939094f, +0.89651060f, 0.89359182f, 0.89063478f, 0.88763964f, 0.88460642f, +0.88153529f, 0.87842643f, 0.87527996f, 0.87209594f, 0.86887461f, +0.86561602f, 0.86232042f, 0.85898781f, 0.85561842f, 0.85221243f, +0.84876984f, 0.84529096f, 0.84177583f, 0.83822471f, 0.83463764f, +0.83101481f, 0.82735640f, 0.82366252f, 0.81993335f, 0.81616908f, +0.81236988f, 0.80853581f, 0.80466717f, 0.80076402f, 0.79682660f, +0.79285502f, 0.78884947f, 0.78481019f, 0.78073722f, 0.77663082f, +0.77249116f, 0.76831841f, 0.76411277f, 0.75987434f, 0.75560343f, +0.75130010f, 0.74696463f, 0.74259710f, 0.73819780f, 0.73376691f, +0.72930455f, 0.72481096f, 0.72028631f, 0.71573079f, 0.71114463f, +0.70652801f, 0.70188117f, 0.69720417f, 0.69249737f, 0.68776089f, +0.68299496f, 0.67819971f, 0.67337549f, 0.66852236f, 0.66364062f, +0.65873051f, 0.65379208f, 0.64882571f, 0.64383155f, 0.63880974f, +0.63376063f, 0.62868434f, 0.62358117f, 0.61845124f, 0.61329484f, +0.60811216f, 0.60290343f, 0.59766883f, 0.59240872f, 0.58712316f, +0.58181250f, 0.57647687f, 0.57111657f, 0.56573176f, 0.56032276f, +0.55488980f, 0.54943299f, 0.54395270f, 0.53844911f, 0.53292239f, +0.52737290f, 0.52180082f, 0.51620632f, 0.51058978f, 0.50495136f, +0.49929130f, 0.49360985f, 0.48790723f, 0.48218375f, 0.47643960f, +0.47067502f, 0.46489030f, 0.45908567f, 0.45326138f, 0.44741765f, +0.44155475f, 0.43567297f, 0.42977250f, 0.42385364f, 0.41791660f, +0.41196167f, 0.40598908f, 0.39999911f, 0.39399201f, 0.38796803f, +0.38192743f, 0.37587047f, 0.36979741f, 0.36370850f, 0.35760403f, +0.35148421f, 0.34534934f, 0.33919969f, 0.33303553f, 0.32685706f, +0.32066461f, 0.31445843f, 0.30823877f, 0.30200592f, 0.29576012f, +0.28950164f, 0.28323078f, 0.27694780f, 0.27065292f, 0.26434645f, +0.25802869f, 0.25169984f, 0.24536023f, 0.23901010f, 0.23264973f, +0.22627939f, 0.21989937f, 0.21350993f, 0.20711134f, 0.20070387f, +0.19428782f, 0.18786344f, 0.18143101f, 0.17499080f, 0.16854310f, +0.16208819f, 0.15562633f, 0.14915779f, 0.14268288f, 0.13620184f, +0.12971498f, 0.12322257f, 0.11672486f, 0.11022217f, 0.10371475f, +0.097202882f, 0.090686858f, 0.084166944f, 0.077643424f, 0.071116582f, +0.064586692f, 0.058054037f, 0.051518895f, 0.044981543f, 0.038442269f, +0.031901345f, 0.025359053f, 0.018815678f, 0.012271495f, 0.0057267868f, +-0.00081816671f, -0.0073630852f, -0.013907688f, -0.020451695f, -0.026994826f, +-0.033536803f, -0.040077340f, -0.046616159f, -0.053152986f, -0.059687532f, +-0.066219524f, -0.072748676f, -0.079274714f, -0.085797355f, -0.092316322f, +-0.098831341f, -0.10534211f, -0.11184838f, -0.11834986f, -0.12484626f, +-0.13133731f, -0.13782275f, -0.14430228f, -0.15077563f, -0.15724251f, +-0.16370267f, -0.17015581f, -0.17660165f, -0.18303993f, -0.18947038f, +-0.19589271f, -0.20230664f, -0.20871192f, -0.21510825f, -0.22149536f, +-0.22787298f, -0.23424086f, -0.24059868f, -0.24694622f, -0.25328314f, +-0.25960925f, -0.26592422f, -0.27222782f, -0.27851975f, -0.28479972f, +-0.29106751f, -0.29732284f, -0.30356544f, -0.30979502f, -0.31601134f, +-0.32221413f, -0.32840309f, -0.33457801f, -0.34073856f, -0.34688455f, +-0.35301566f, -0.35913166f, -0.36523229f, -0.37131724f, -0.37738630f, +-0.38343921f, -0.38947567f, -0.39549544f, -0.40149832f, -0.40748394f, +-0.41345215f, -0.41940263f, -0.42533514f, -0.43124944f, -0.43714526f, +-0.44302234f, -0.44888046f, -0.45471936f, -0.46053877f, -0.46633846f, +-0.47211814f, -0.47787762f, -0.48361665f, -0.48933494f, -0.49503228f, +-0.50070840f, -0.50636309f, -0.51199609f, -0.51760709f, -0.52319598f, +-0.52876246f, -0.53430629f, -0.53982723f, -0.54532504f, -0.55079949f, +-0.55625033f, -0.56167740f, -0.56708032f, -0.57245898f, -0.57781315f, +-0.58314258f, -0.58844697f, -0.59372622f, -0.59897995f, -0.60420811f, +-0.60941035f, -0.61458647f, -0.61973625f, -0.62485951f, -0.62995601f, +-0.63502556f, -0.64006782f, -0.64508271f, -0.65007001f, -0.65502942f, +-0.65996075f, -0.66486382f, -0.66973841f, -0.67458433f, -0.67940134f, +-0.68418926f, -0.68894786f, -0.69367695f, -0.69837630f, -0.70304573f, +-0.70768511f, -0.71229410f, -0.71687263f, -0.72142041f, -0.72593731f, +-0.73042315f, -0.73487765f, -0.73930067f, -0.74369204f, -0.74805158f, +-0.75237900f, -0.75667429f, -0.76093709f, -0.76516730f, -0.76936477f, +-0.77352923f, -0.77766061f, -0.78175867f, -0.78582323f, -0.78985411f, +-0.79385114f, -0.79781419f, -0.80174309f, -0.80563760f, -0.80949765f, +-0.81332302f, -0.81711352f, -0.82086903f, -0.82458937f, -0.82827437f, +-0.83192390f, -0.83553779f, -0.83911592f, -0.84265804f, -0.84616417f, +-0.84963393f, -0.85306740f, -0.85646427f, -0.85982448f, -0.86314780f, +-0.86643422f, -0.86968350f, -0.87289548f, -0.87607014f, -0.87920725f, +-0.88230664f, -0.88536829f, -0.88839203f, -0.89137769f, -0.89432514f, +-0.89723432f, -0.90010506f, -0.90293723f, -0.90573072f, -0.90848541f, +-0.91120118f, -0.91387796f, -0.91651553f, -0.91911387f, -0.92167282f, +-0.92419231f, -0.92667222f, -0.92911243f, -0.93151283f, -0.93387336f, +-0.93619382f, -0.93847424f, -0.94071442f, -0.94291431f, -0.94507378f, +-0.94719279f, -0.94927126f, -0.95130903f, -0.95330608f, -0.95526224f, +-0.95717752f, -0.95905179f, -0.96088499f, -0.96267700f, -0.96442777f, +-0.96613729f, -0.96780539f, -0.96943200f, -0.97101706f, -0.97256058f, +-0.97406244f, -0.97552258f, -0.97694093f, -0.97831738f, -0.97965199f, +-0.98094457f, -0.98219514f, -0.98340368f, -0.98457009f, -0.98569429f, +-0.98677629f, -0.98781598f, -0.98881340f, -0.98976845f, -0.99068111f, +-0.99155134f, -0.99237907f, -0.99316430f, -0.99390697f, -0.99460709f, +-0.99526459f, -0.99587947f, -0.99645168f, -0.99698120f, -0.99746799f, +-0.99791211f, -0.99831343f, -0.99867201f, -0.99898779f, -0.99926084f, +-0.99949104f, -0.99967843f, -0.99982297f, -0.99992472f, -0.99998361f, +0.99999869f, 0.99989158f, 0.99961317f, 0.99916345f, 0.99854255f, +0.99775058f, 0.99678761f, 0.99565387f, 0.99434954f, 0.99287480f, +0.99122995f, 0.98941529f, 0.98743105f, 0.98527765f, 0.98295540f, +0.98046476f, 0.97780609f, 0.97497988f, 0.97198665f, 0.96882683f, +0.96550101f, 0.96200979f, 0.95835376f, 0.95453346f, 0.95054960f, +0.94640291f, 0.94209403f, 0.93762374f, 0.93299282f, 0.92820197f, +0.92325211f, 0.91814411f, 0.91287869f, 0.90745693f, 0.90187967f, +0.89614785f, 0.89026248f, 0.88422459f, 0.87803519f, 0.87169534f, +0.86520612f, 0.85856867f, 0.85178405f, 0.84485358f, 0.83777827f, +0.83055943f, 0.82319832f, 0.81569612f, 0.80805415f, 0.80027372f, +0.79235619f, 0.78430289f, 0.77611518f, 0.76779449f, 0.75934225f, +0.75075996f, 0.74204898f, 0.73321080f, 0.72424710f, 0.71515924f, +0.70594883f, 0.69661748f, 0.68716675f, 0.67759830f, 0.66791373f, +0.65811473f, 0.64820296f, 0.63818014f, 0.62804794f, 0.61780810f, +0.60746247f, 0.59701276f, 0.58646071f, 0.57580817f, 0.56505698f, +0.55420899f, 0.54326600f, 0.53222996f, 0.52110273f, 0.50988621f, +0.49858227f, 0.48719296f, 0.47572014f, 0.46416581f, 0.45253196f, +0.44082057f, 0.42903364f, 0.41717321f, 0.40524128f, 0.39323992f, +0.38117120f, 0.36903715f, 0.35683987f, 0.34458145f, 0.33226398f, +0.31988961f, 0.30746040f, 0.29497850f, 0.28244606f, 0.26986524f, +0.25723818f, 0.24456702f, 0.23185398f, 0.21910121f, 0.20631088f, +0.19348522f, 0.18062639f, 0.16773662f, 0.15481812f, 0.14187308f, +0.12890373f, 0.11591230f, 0.10290100f, 0.089872077f, 0.076827750f, +0.063770257f, 0.050701842f, 0.037624735f, 0.024541186f, 0.011453429f, +-0.0016362892f, -0.014725727f, -0.027812643f, -0.040894791f, -0.053969935f, +-0.067035832f, -0.080090240f, -0.093130924f, -0.10615565f, -0.11916219f, +-0.13214831f, -0.14511178f, -0.15805040f, -0.17096193f, -0.18384418f, +-0.19669491f, -0.20951195f, -0.22229309f, -0.23503613f, -0.24773891f, +-0.26039925f, -0.27301496f, -0.28558388f, -0.29810387f, -0.31057280f, +-0.32298848f, -0.33534884f, -0.34765175f, -0.35989508f, -0.37207675f, +-0.38419467f, -0.39624676f, -0.40823093f, -0.42014518f, -0.43198743f, +-0.44375566f, -0.45544785f, -0.46706200f, -0.47859612f, -0.49004826f, +-0.50141639f, -0.51269865f, -0.52389306f, -0.53499764f, -0.54601061f, +-0.55693001f, -0.56775403f, -0.57848072f, -0.58910829f, -0.59963489f, +-0.61005878f, -0.62037814f, -0.63059121f, -0.64069623f, -0.65069145f, +-0.66057515f, -0.67034572f, -0.68000144f, -0.68954057f, -0.69896162f, +-0.70826286f, -0.71744281f, -0.72649974f, -0.73543227f, -0.74423873f, +-0.75291771f, -0.76146764f, -0.76988715f, -0.77817470f, -0.78632891f, +-0.79434842f, -0.80223179f, -0.80997771f, -0.81758487f, -0.82505190f, +-0.83237761f, -0.83956063f, -0.84659988f, -0.85349399f, -0.86024189f, +-0.86684239f, -0.87329435f, -0.87959671f, -0.88574833f, -0.89174819f, +-0.89759529f, -0.90328854f, -0.90882701f, -0.91420978f, -0.91943592f, +-0.92450452f, -0.92941469f, -0.93416560f, -0.93875647f, -0.94318646f, +-0.94745487f, -0.95156091f, -0.95550388f, -0.95928317f, -0.96289814f, +-0.96634805f, -0.96963239f, -0.97275060f, -0.97570217f, -0.97848648f, +-0.98110318f, -0.98355180f, -0.98583186f, -0.98794299f, -0.98988485f, +-0.99165714f, -0.99325943f, -0.99469161f, -0.99595332f, -0.99704438f, +-0.99796462f, -0.99871385f, -0.99929196f, -0.99969882f, -0.99993443f, +0.99999464f, 0.99956632f, 0.99845290f, 0.99665523f, 0.99417448f, +0.99101239f, 0.98717111f, 0.98265326f, 0.97746199f, 0.97160077f, +0.96507365f, 0.95788515f, 0.95004016f, 0.94154406f, 0.93240267f, +0.92262226f, 0.91220951f, 0.90117162f, 0.88951606f, 0.87725091f, +0.86438453f, 0.85092574f, 0.83688372f, 0.82226819f, 0.80708915f, +0.79135692f, 0.77508235f, 0.75827658f, 0.74095112f, 0.72311783f, +0.70478898f, 0.68597710f, 0.66669506f, 0.64695615f, 0.62677377f, +0.60616189f, 0.58513457f, 0.56370622f, 0.54189157f, 0.51970547f, +0.49716324f, 0.47428027f, 0.45107225f, 0.42755505f, 0.40374488f, +0.37965798f, 0.35531086f, 0.33072025f, 0.30590299f, 0.28087607f, +0.25565663f, 0.23026201f, 0.20470956f, 0.17901683f, 0.15320139f, +0.12728097f, 0.10127331f, 0.075196236f, 0.049067631f, 0.022905400f, +-0.0032725304f, -0.029448219f, -0.055603724f, -0.081721120f, -0.10778251f, +-0.13377003f, -0.15966587f, -0.18545228f, -0.21111161f, -0.23662624f, +-0.26197869f, -0.28715160f, -0.31212771f, -0.33688989f, -0.36142120f, +-0.38570482f, -0.40972409f, -0.43346253f, -0.45690393f, -0.48003218f, +-0.50283146f, -0.52528608f, -0.54738069f, -0.56910020f, -0.59042966f, +-0.61135447f, -0.63186026f, -0.65193301f, -0.67155898f, -0.69072473f, +-0.70941705f, -0.72762316f, -0.74533063f, -0.76252723f, -0.77920127f, +-0.79534131f, -0.81093621f, -0.82597536f, -0.84044844f, -0.85434550f, +-0.86765707f, -0.88037395f, -0.89248747f, -0.90398932f, -0.91487163f, +-0.92512697f, -0.93474823f, -0.94372886f, -0.95206273f, -0.95974404f, +-0.96676767f, -0.97312868f, -0.97882277f, -0.98384601f, -0.98819500f, +-0.99186671f, -0.99485862f, -0.99716878f, -0.99879545f, -0.99973762f, +}; +#endif + +static const CELTMode mode48000_960_120 = { +48000, /* Fs */ +120, /* overlap */ +21, /* nbEBands */ +21, /* effEBands */ +{0.85000610f, 0.0000000f, 1.0000000f, 1.0000000f, }, /* preemph */ +eband5ms, /* eBands */ +3, /* maxLM */ +8, /* nbShortMdcts */ +120, /* shortMdctSize */ +11, /* nbAllocVectors */ +band_allocation, /* allocVectors */ +logN400, /* logN */ +window120, /* window */ +{1920, 3, {&fft_state48000_960_0, &fft_state48000_960_1, &fft_state48000_960_2, &fft_state48000_960_3, }, mdct_twiddles960}, /* mdct */ +{392, cache_index50, cache_bits50, cache_caps50}, /* cache */ +}; + +/* List of all the available modes */ +#define TOTAL_MODES 1 +static const CELTMode * const static_mode_list[TOTAL_MODES] = { +&mode48000_960_120, +}; diff --git a/extern/opus/celt/static_modes_float_arm_ne10.h b/extern/opus/celt/static_modes_float_arm_ne10.h new file mode 100644 index 0000000..66e1abb --- /dev/null +++ b/extern/opus/celt/static_modes_float_arm_ne10.h @@ -0,0 +1,404 @@ +/* The contents of this file was automatically generated by + * dump_mode_arm_ne10.c with arguments: 48000 960 + * It contains static definitions for some pre-defined modes. */ +#include + +#ifndef NE10_FFT_PARAMS48000_960 +#define NE10_FFT_PARAMS48000_960 +static const ne10_int32_t ne10_factors_480[64] = { +4, 40, 4, 30, 2, 15, 5, 3, 3, 1, 1, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, }; +static const ne10_int32_t ne10_factors_240[64] = { +3, 20, 4, 15, 5, 3, 3, 1, 1, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, }; +static const ne10_int32_t ne10_factors_120[64] = { +3, 10, 2, 15, 5, 3, 3, 1, 1, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, }; +static const ne10_int32_t ne10_factors_60[64] = { +2, 5, 5, 3, 3, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, }; +static const ne10_fft_cpx_float32_t ne10_twiddles_480[480] = { +{1.0000000f,0.0000000f}, {1.0000000f,-0.0000000f}, {1.0000000f,-0.0000000f}, +{1.0000000f,-0.0000000f}, {0.91354543f,-0.40673664f}, {0.66913056f,-0.74314487f}, +{1.0000000f,-0.0000000f}, {0.66913056f,-0.74314487f}, {-0.10452851f,-0.99452192f}, +{1.0000000f,-0.0000000f}, {0.30901697f,-0.95105654f}, {-0.80901700f,-0.58778518f}, +{1.0000000f,-0.0000000f}, {-0.10452851f,-0.99452192f}, {-0.97814757f,0.20791179f}, +{1.0000000f,-0.0000000f}, {0.97814763f,-0.20791170f}, {0.91354543f,-0.40673664f}, +{0.80901700f,-0.58778524f}, {0.66913056f,-0.74314487f}, {0.49999997f,-0.86602545f}, +{0.30901697f,-0.95105654f}, {0.10452842f,-0.99452192f}, {-0.10452851f,-0.99452192f}, +{-0.30901703f,-0.95105648f}, {-0.50000006f,-0.86602533f}, {-0.66913068f,-0.74314475f}, +{-0.80901700f,-0.58778518f}, {-0.91354549f,-0.40673658f}, {-0.97814763f,-0.20791161f}, +{1.0000000f,-0.0000000f}, {0.99862951f,-0.052335959f}, {0.99452192f,-0.10452846f}, +{0.98768836f,-0.15643448f}, {0.97814763f,-0.20791170f}, {0.96592581f,-0.25881904f}, +{0.95105648f,-0.30901700f}, {0.93358040f,-0.35836795f}, {0.91354543f,-0.40673664f}, +{0.89100653f,-0.45399052f}, {0.86602545f,-0.50000000f}, {0.83867055f,-0.54463905f}, +{0.80901700f,-0.58778524f}, {0.77714598f,-0.62932038f}, {0.74314475f,-0.66913062f}, +{0.70710677f,-0.70710683f}, {0.66913056f,-0.74314487f}, {0.62932038f,-0.77714598f}, +{0.58778524f,-0.80901700f}, {0.54463899f,-0.83867055f}, {0.49999997f,-0.86602545f}, +{0.45399052f,-0.89100653f}, {0.40673661f,-0.91354549f}, {0.35836786f,-0.93358046f}, +{0.30901697f,-0.95105654f}, {0.25881907f,-0.96592581f}, {0.20791166f,-0.97814763f}, +{0.15643437f,-0.98768836f}, {0.10452842f,-0.99452192f}, {0.052335974f,-0.99862951f}, +{1.0000000f,-0.0000000f}, {0.99452192f,-0.10452846f}, {0.97814763f,-0.20791170f}, +{0.95105648f,-0.30901700f}, {0.91354543f,-0.40673664f}, {0.86602545f,-0.50000000f}, +{0.80901700f,-0.58778524f}, {0.74314475f,-0.66913062f}, {0.66913056f,-0.74314487f}, +{0.58778524f,-0.80901700f}, {0.49999997f,-0.86602545f}, {0.40673661f,-0.91354549f}, +{0.30901697f,-0.95105654f}, {0.20791166f,-0.97814763f}, {0.10452842f,-0.99452192f}, +{-4.3711388e-08f,-1.0000000f}, {-0.10452851f,-0.99452192f}, {-0.20791174f,-0.97814757f}, +{-0.30901703f,-0.95105648f}, {-0.40673670f,-0.91354543f}, {-0.50000006f,-0.86602533f}, +{-0.58778518f,-0.80901700f}, {-0.66913068f,-0.74314475f}, {-0.74314493f,-0.66913044f}, +{-0.80901700f,-0.58778518f}, {-0.86602539f,-0.50000006f}, {-0.91354549f,-0.40673658f}, +{-0.95105654f,-0.30901679f}, {-0.97814763f,-0.20791161f}, {-0.99452192f,-0.10452849f}, +{1.0000000f,-0.0000000f}, {0.98768836f,-0.15643448f}, {0.95105648f,-0.30901700f}, +{0.89100653f,-0.45399052f}, {0.80901700f,-0.58778524f}, {0.70710677f,-0.70710683f}, +{0.58778524f,-0.80901700f}, {0.45399052f,-0.89100653f}, {0.30901697f,-0.95105654f}, +{0.15643437f,-0.98768836f}, {-4.3711388e-08f,-1.0000000f}, {-0.15643445f,-0.98768836f}, +{-0.30901703f,-0.95105648f}, {-0.45399061f,-0.89100647f}, {-0.58778518f,-0.80901700f}, +{-0.70710677f,-0.70710677f}, {-0.80901700f,-0.58778518f}, {-0.89100659f,-0.45399037f}, +{-0.95105654f,-0.30901679f}, {-0.98768836f,-0.15643445f}, {-1.0000000f,8.7422777e-08f}, +{-0.98768830f,0.15643461f}, {-0.95105654f,0.30901697f}, {-0.89100653f,0.45399055f}, +{-0.80901694f,0.58778536f}, {-0.70710665f,0.70710689f}, {-0.58778507f,0.80901712f}, +{-0.45399022f,0.89100665f}, {-0.30901709f,0.95105648f}, {-0.15643452f,0.98768830f}, +{1.0000000f,-0.0000000f}, {0.99991435f,-0.013089596f}, {0.99965733f,-0.026176950f}, +{0.99922901f,-0.039259817f}, {0.99862951f,-0.052335959f}, {0.99785894f,-0.065403134f}, +{0.99691731f,-0.078459099f}, {0.99580491f,-0.091501623f}, {0.99452192f,-0.10452846f}, +{0.99306846f,-0.11753740f}, {0.99144489f,-0.13052620f}, {0.98965138f,-0.14349262f}, +{0.98768836f,-0.15643448f}, {0.98555607f,-0.16934951f}, {0.98325491f,-0.18223552f}, +{0.98078525f,-0.19509032f}, {0.97814763f,-0.20791170f}, {0.97534233f,-0.22069745f}, +{0.97236991f,-0.23344538f}, {0.96923089f,-0.24615330f}, {0.96592581f,-0.25881904f}, +{0.96245521f,-0.27144045f}, {0.95881975f,-0.28401536f}, {0.95501995f,-0.29654160f}, +{0.95105648f,-0.30901700f}, {0.94693011f,-0.32143945f}, {0.94264150f,-0.33380687f}, +{0.93819129f,-0.34611708f}, {0.93358040f,-0.35836795f}, {0.92880952f,-0.37055743f}, +{0.92387956f,-0.38268346f}, {0.91879117f,-0.39474389f}, {0.91354543f,-0.40673664f}, +{0.90814316f,-0.41865975f}, {0.90258527f,-0.43051112f}, {0.89687270f,-0.44228873f}, +{0.89100653f,-0.45399052f}, {0.88498765f,-0.46561453f}, {0.87881708f,-0.47715878f}, +{0.87249601f,-0.48862126f}, {0.86602545f,-0.50000000f}, {0.85940641f,-0.51129311f}, +{0.85264015f,-0.52249855f}, {0.84572786f,-0.53361452f}, {0.83867055f,-0.54463905f}, +{0.83146960f,-0.55557024f}, {0.82412618f,-0.56640625f}, {0.81664151f,-0.57714522f}, +{0.80901700f,-0.58778524f}, {0.80125380f,-0.59832460f}, {0.79335332f,-0.60876143f}, +{0.78531694f,-0.61909395f}, {0.77714598f,-0.62932038f}, {0.76884180f,-0.63943899f}, +{0.76040596f,-0.64944810f}, {0.75183982f,-0.65934587f}, {0.74314475f,-0.66913062f}, +{0.73432249f,-0.67880076f}, {0.72537434f,-0.68835455f}, {0.71630192f,-0.69779050f}, +{0.70710677f,-0.70710683f}, {0.69779044f,-0.71630198f}, {0.68835455f,-0.72537440f}, +{0.67880070f,-0.73432255f}, {0.66913056f,-0.74314487f}, {0.65934581f,-0.75183982f}, +{0.64944804f,-0.76040596f}, {0.63943899f,-0.76884186f}, {0.62932038f,-0.77714598f}, +{0.61909395f,-0.78531694f}, {0.60876137f,-0.79335338f}, {0.59832460f,-0.80125386f}, +{0.58778524f,-0.80901700f}, {0.57714516f,-0.81664151f}, {0.56640625f,-0.82412618f}, +{0.55557019f,-0.83146960f}, {0.54463899f,-0.83867055f}, {0.53361452f,-0.84572786f}, +{0.52249849f,-0.85264015f}, {0.51129311f,-0.85940641f}, {0.49999997f,-0.86602545f}, +{0.48862118f,-0.87249601f}, {0.47715876f,-0.87881708f}, {0.46561447f,-0.88498765f}, +{0.45399052f,-0.89100653f}, {0.44228867f,-0.89687276f}, {0.43051103f,-0.90258533f}, +{0.41865975f,-0.90814316f}, {0.40673661f,-0.91354549f}, {0.39474380f,-0.91879129f}, +{0.38268343f,-0.92387956f}, {0.37055740f,-0.92880958f}, {0.35836786f,-0.93358046f}, +{0.34611705f,-0.93819135f}, {0.33380681f,-0.94264150f}, {0.32143947f,-0.94693011f}, +{0.30901697f,-0.95105654f}, {0.29654151f,-0.95501995f}, {0.28401533f,-0.95881975f}, +{0.27144039f,-0.96245527f}, {0.25881907f,-0.96592581f}, {0.24615327f,-0.96923089f}, +{0.23344530f,-0.97236991f}, {0.22069745f,-0.97534233f}, {0.20791166f,-0.97814763f}, +{0.19509023f,-0.98078531f}, {0.18223552f,-0.98325491f}, {0.16934945f,-0.98555607f}, +{0.15643437f,-0.98768836f}, {0.14349259f,-0.98965138f}, {0.13052613f,-0.99144489f}, +{0.11753740f,-0.99306846f}, {0.10452842f,-0.99452192f}, {0.091501534f,-0.99580491f}, +{0.078459084f,-0.99691731f}, {0.065403074f,-0.99785894f}, {0.052335974f,-0.99862951f}, +{0.039259788f,-0.99922901f}, {0.026176875f,-0.99965733f}, {0.013089597f,-0.99991435f}, +{1.0000000f,-0.0000000f}, {0.99965733f,-0.026176950f}, {0.99862951f,-0.052335959f}, +{0.99691731f,-0.078459099f}, {0.99452192f,-0.10452846f}, {0.99144489f,-0.13052620f}, +{0.98768836f,-0.15643448f}, {0.98325491f,-0.18223552f}, {0.97814763f,-0.20791170f}, +{0.97236991f,-0.23344538f}, {0.96592581f,-0.25881904f}, {0.95881975f,-0.28401536f}, +{0.95105648f,-0.30901700f}, {0.94264150f,-0.33380687f}, {0.93358040f,-0.35836795f}, +{0.92387956f,-0.38268346f}, {0.91354543f,-0.40673664f}, {0.90258527f,-0.43051112f}, +{0.89100653f,-0.45399052f}, {0.87881708f,-0.47715878f}, {0.86602545f,-0.50000000f}, +{0.85264015f,-0.52249855f}, {0.83867055f,-0.54463905f}, {0.82412618f,-0.56640625f}, +{0.80901700f,-0.58778524f}, {0.79335332f,-0.60876143f}, {0.77714598f,-0.62932038f}, +{0.76040596f,-0.64944810f}, {0.74314475f,-0.66913062f}, {0.72537434f,-0.68835455f}, +{0.70710677f,-0.70710683f}, {0.68835455f,-0.72537440f}, {0.66913056f,-0.74314487f}, +{0.64944804f,-0.76040596f}, {0.62932038f,-0.77714598f}, {0.60876137f,-0.79335338f}, +{0.58778524f,-0.80901700f}, {0.56640625f,-0.82412618f}, {0.54463899f,-0.83867055f}, +{0.52249849f,-0.85264015f}, {0.49999997f,-0.86602545f}, {0.47715876f,-0.87881708f}, +{0.45399052f,-0.89100653f}, {0.43051103f,-0.90258533f}, {0.40673661f,-0.91354549f}, +{0.38268343f,-0.92387956f}, {0.35836786f,-0.93358046f}, {0.33380681f,-0.94264150f}, +{0.30901697f,-0.95105654f}, {0.28401533f,-0.95881975f}, {0.25881907f,-0.96592581f}, +{0.23344530f,-0.97236991f}, {0.20791166f,-0.97814763f}, {0.18223552f,-0.98325491f}, +{0.15643437f,-0.98768836f}, {0.13052613f,-0.99144489f}, {0.10452842f,-0.99452192f}, +{0.078459084f,-0.99691731f}, {0.052335974f,-0.99862951f}, {0.026176875f,-0.99965733f}, +{-4.3711388e-08f,-1.0000000f}, {-0.026176963f,-0.99965733f}, {-0.052336060f,-0.99862951f}, +{-0.078459173f,-0.99691731f}, {-0.10452851f,-0.99452192f}, {-0.13052621f,-0.99144489f}, +{-0.15643445f,-0.98768836f}, {-0.18223560f,-0.98325491f}, {-0.20791174f,-0.97814757f}, +{-0.23344538f,-0.97236991f}, {-0.25881916f,-0.96592581f}, {-0.28401542f,-0.95881969f}, +{-0.30901703f,-0.95105648f}, {-0.33380687f,-0.94264150f}, {-0.35836795f,-0.93358040f}, +{-0.38268352f,-0.92387950f}, {-0.40673670f,-0.91354543f}, {-0.43051112f,-0.90258527f}, +{-0.45399061f,-0.89100647f}, {-0.47715873f,-0.87881708f}, {-0.50000006f,-0.86602533f}, +{-0.52249867f,-0.85264009f}, {-0.54463905f,-0.83867055f}, {-0.56640631f,-0.82412612f}, +{-0.58778518f,-0.80901700f}, {-0.60876143f,-0.79335332f}, {-0.62932050f,-0.77714586f}, +{-0.64944804f,-0.76040596f}, {-0.66913068f,-0.74314475f}, {-0.68835467f,-0.72537428f}, +{-0.70710677f,-0.70710677f}, {-0.72537446f,-0.68835449f}, {-0.74314493f,-0.66913044f}, +{-0.76040596f,-0.64944804f}, {-0.77714604f,-0.62932026f}, {-0.79335332f,-0.60876143f}, +{-0.80901700f,-0.58778518f}, {-0.82412624f,-0.56640613f}, {-0.83867055f,-0.54463899f}, +{-0.85264021f,-0.52249849f}, {-0.86602539f,-0.50000006f}, {-0.87881714f,-0.47715873f}, +{-0.89100659f,-0.45399037f}, {-0.90258527f,-0.43051112f}, {-0.91354549f,-0.40673658f}, +{-0.92387956f,-0.38268328f}, {-0.93358040f,-0.35836792f}, {-0.94264150f,-0.33380675f}, +{-0.95105654f,-0.30901679f}, {-0.95881975f,-0.28401530f}, {-0.96592587f,-0.25881892f}, +{-0.97236991f,-0.23344538f}, {-0.97814763f,-0.20791161f}, {-0.98325491f,-0.18223536f}, +{-0.98768836f,-0.15643445f}, {-0.99144489f,-0.13052608f}, {-0.99452192f,-0.10452849f}, +{-0.99691737f,-0.078459039f}, {-0.99862957f,-0.052335810f}, {-0.99965733f,-0.026176952f}, +{1.0000000f,-0.0000000f}, {0.99922901f,-0.039259817f}, {0.99691731f,-0.078459099f}, +{0.99306846f,-0.11753740f}, {0.98768836f,-0.15643448f}, {0.98078525f,-0.19509032f}, +{0.97236991f,-0.23344538f}, {0.96245521f,-0.27144045f}, {0.95105648f,-0.30901700f}, +{0.93819129f,-0.34611708f}, {0.92387956f,-0.38268346f}, {0.90814316f,-0.41865975f}, +{0.89100653f,-0.45399052f}, {0.87249601f,-0.48862126f}, {0.85264015f,-0.52249855f}, +{0.83146960f,-0.55557024f}, {0.80901700f,-0.58778524f}, {0.78531694f,-0.61909395f}, +{0.76040596f,-0.64944810f}, {0.73432249f,-0.67880076f}, {0.70710677f,-0.70710683f}, +{0.67880070f,-0.73432255f}, {0.64944804f,-0.76040596f}, {0.61909395f,-0.78531694f}, +{0.58778524f,-0.80901700f}, {0.55557019f,-0.83146960f}, {0.52249849f,-0.85264015f}, +{0.48862118f,-0.87249601f}, {0.45399052f,-0.89100653f}, {0.41865975f,-0.90814316f}, +{0.38268343f,-0.92387956f}, {0.34611705f,-0.93819135f}, {0.30901697f,-0.95105654f}, +{0.27144039f,-0.96245527f}, {0.23344530f,-0.97236991f}, {0.19509023f,-0.98078531f}, +{0.15643437f,-0.98768836f}, {0.11753740f,-0.99306846f}, {0.078459084f,-0.99691731f}, +{0.039259788f,-0.99922901f}, {-4.3711388e-08f,-1.0000000f}, {-0.039259877f,-0.99922901f}, +{-0.078459173f,-0.99691731f}, {-0.11753749f,-0.99306846f}, {-0.15643445f,-0.98768836f}, +{-0.19509032f,-0.98078525f}, {-0.23344538f,-0.97236991f}, {-0.27144048f,-0.96245521f}, +{-0.30901703f,-0.95105648f}, {-0.34611711f,-0.93819129f}, {-0.38268352f,-0.92387950f}, +{-0.41865984f,-0.90814310f}, {-0.45399061f,-0.89100647f}, {-0.48862135f,-0.87249595f}, +{-0.52249867f,-0.85264009f}, {-0.55557036f,-0.83146954f}, {-0.58778518f,-0.80901700f}, +{-0.61909389f,-0.78531694f}, {-0.64944804f,-0.76040596f}, {-0.67880076f,-0.73432249f}, +{-0.70710677f,-0.70710677f}, {-0.73432249f,-0.67880070f}, {-0.76040596f,-0.64944804f}, +{-0.78531694f,-0.61909389f}, {-0.80901700f,-0.58778518f}, {-0.83146966f,-0.55557019f}, +{-0.85264021f,-0.52249849f}, {-0.87249607f,-0.48862115f}, {-0.89100659f,-0.45399037f}, +{-0.90814322f,-0.41865960f}, {-0.92387956f,-0.38268328f}, {-0.93819135f,-0.34611690f}, +{-0.95105654f,-0.30901679f}, {-0.96245521f,-0.27144048f}, {-0.97236991f,-0.23344538f}, +{-0.98078531f,-0.19509031f}, {-0.98768836f,-0.15643445f}, {-0.99306846f,-0.11753736f}, +{-0.99691737f,-0.078459039f}, {-0.99922901f,-0.039259743f}, {-1.0000000f,8.7422777e-08f}, +{-0.99922901f,0.039259918f}, {-0.99691731f,0.078459218f}, {-0.99306846f,0.11753753f}, +{-0.98768830f,0.15643461f}, {-0.98078525f,0.19509049f}, {-0.97236985f,0.23344554f}, +{-0.96245515f,0.27144065f}, {-0.95105654f,0.30901697f}, {-0.93819135f,0.34611705f}, +{-0.92387956f,0.38268346f}, {-0.90814316f,0.41865975f}, {-0.89100653f,0.45399055f}, +{-0.87249601f,0.48862129f}, {-0.85264015f,0.52249861f}, {-0.83146960f,0.55557030f}, +{-0.80901694f,0.58778536f}, {-0.78531688f,0.61909401f}, {-0.76040590f,0.64944816f}, +{-0.73432243f,0.67880082f}, {-0.70710665f,0.70710689f}, {-0.67880058f,0.73432261f}, +{-0.64944792f,0.76040608f}, {-0.61909378f,0.78531706f}, {-0.58778507f,0.80901712f}, +{-0.55557001f,0.83146977f}, {-0.52249837f,0.85264033f}, {-0.48862100f,0.87249613f}, +{-0.45399022f,0.89100665f}, {-0.41865945f,0.90814328f}, {-0.38268313f,0.92387968f}, +{-0.34611672f,0.93819147f}, {-0.30901709f,0.95105648f}, {-0.27144054f,0.96245521f}, +{-0.23344545f,0.97236991f}, {-0.19509038f,0.98078525f}, {-0.15643452f,0.98768830f}, +{-0.11753743f,0.99306846f}, {-0.078459114f,0.99691731f}, {-0.039259821f,0.99922901f}, +}; +static const ne10_fft_cpx_float32_t ne10_twiddles_240[240] = { +{1.0000000f,0.0000000f}, {1.0000000f,-0.0000000f}, {1.0000000f,-0.0000000f}, +{1.0000000f,-0.0000000f}, {0.91354543f,-0.40673664f}, {0.66913056f,-0.74314487f}, +{1.0000000f,-0.0000000f}, {0.66913056f,-0.74314487f}, {-0.10452851f,-0.99452192f}, +{1.0000000f,-0.0000000f}, {0.30901697f,-0.95105654f}, {-0.80901700f,-0.58778518f}, +{1.0000000f,-0.0000000f}, {-0.10452851f,-0.99452192f}, {-0.97814757f,0.20791179f}, +{1.0000000f,-0.0000000f}, {0.99452192f,-0.10452846f}, {0.97814763f,-0.20791170f}, +{0.95105648f,-0.30901700f}, {0.91354543f,-0.40673664f}, {0.86602545f,-0.50000000f}, +{0.80901700f,-0.58778524f}, {0.74314475f,-0.66913062f}, {0.66913056f,-0.74314487f}, +{0.58778524f,-0.80901700f}, {0.49999997f,-0.86602545f}, {0.40673661f,-0.91354549f}, +{0.30901697f,-0.95105654f}, {0.20791166f,-0.97814763f}, {0.10452842f,-0.99452192f}, +{1.0000000f,-0.0000000f}, {0.97814763f,-0.20791170f}, {0.91354543f,-0.40673664f}, +{0.80901700f,-0.58778524f}, {0.66913056f,-0.74314487f}, {0.49999997f,-0.86602545f}, +{0.30901697f,-0.95105654f}, {0.10452842f,-0.99452192f}, {-0.10452851f,-0.99452192f}, +{-0.30901703f,-0.95105648f}, {-0.50000006f,-0.86602533f}, {-0.66913068f,-0.74314475f}, +{-0.80901700f,-0.58778518f}, {-0.91354549f,-0.40673658f}, {-0.97814763f,-0.20791161f}, +{1.0000000f,-0.0000000f}, {0.95105648f,-0.30901700f}, {0.80901700f,-0.58778524f}, +{0.58778524f,-0.80901700f}, {0.30901697f,-0.95105654f}, {-4.3711388e-08f,-1.0000000f}, +{-0.30901703f,-0.95105648f}, {-0.58778518f,-0.80901700f}, {-0.80901700f,-0.58778518f}, +{-0.95105654f,-0.30901679f}, {-1.0000000f,8.7422777e-08f}, {-0.95105654f,0.30901697f}, +{-0.80901694f,0.58778536f}, {-0.58778507f,0.80901712f}, {-0.30901709f,0.95105648f}, +{1.0000000f,-0.0000000f}, {0.99965733f,-0.026176950f}, {0.99862951f,-0.052335959f}, +{0.99691731f,-0.078459099f}, {0.99452192f,-0.10452846f}, {0.99144489f,-0.13052620f}, +{0.98768836f,-0.15643448f}, {0.98325491f,-0.18223552f}, {0.97814763f,-0.20791170f}, +{0.97236991f,-0.23344538f}, {0.96592581f,-0.25881904f}, {0.95881975f,-0.28401536f}, +{0.95105648f,-0.30901700f}, {0.94264150f,-0.33380687f}, {0.93358040f,-0.35836795f}, +{0.92387956f,-0.38268346f}, {0.91354543f,-0.40673664f}, {0.90258527f,-0.43051112f}, +{0.89100653f,-0.45399052f}, {0.87881708f,-0.47715878f}, {0.86602545f,-0.50000000f}, +{0.85264015f,-0.52249855f}, {0.83867055f,-0.54463905f}, {0.82412618f,-0.56640625f}, +{0.80901700f,-0.58778524f}, {0.79335332f,-0.60876143f}, {0.77714598f,-0.62932038f}, +{0.76040596f,-0.64944810f}, {0.74314475f,-0.66913062f}, {0.72537434f,-0.68835455f}, +{0.70710677f,-0.70710683f}, {0.68835455f,-0.72537440f}, {0.66913056f,-0.74314487f}, +{0.64944804f,-0.76040596f}, {0.62932038f,-0.77714598f}, {0.60876137f,-0.79335338f}, +{0.58778524f,-0.80901700f}, {0.56640625f,-0.82412618f}, {0.54463899f,-0.83867055f}, +{0.52249849f,-0.85264015f}, {0.49999997f,-0.86602545f}, {0.47715876f,-0.87881708f}, +{0.45399052f,-0.89100653f}, {0.43051103f,-0.90258533f}, {0.40673661f,-0.91354549f}, +{0.38268343f,-0.92387956f}, {0.35836786f,-0.93358046f}, {0.33380681f,-0.94264150f}, +{0.30901697f,-0.95105654f}, {0.28401533f,-0.95881975f}, {0.25881907f,-0.96592581f}, +{0.23344530f,-0.97236991f}, {0.20791166f,-0.97814763f}, {0.18223552f,-0.98325491f}, +{0.15643437f,-0.98768836f}, {0.13052613f,-0.99144489f}, {0.10452842f,-0.99452192f}, +{0.078459084f,-0.99691731f}, {0.052335974f,-0.99862951f}, {0.026176875f,-0.99965733f}, +{1.0000000f,-0.0000000f}, {0.99862951f,-0.052335959f}, {0.99452192f,-0.10452846f}, +{0.98768836f,-0.15643448f}, {0.97814763f,-0.20791170f}, {0.96592581f,-0.25881904f}, +{0.95105648f,-0.30901700f}, {0.93358040f,-0.35836795f}, {0.91354543f,-0.40673664f}, +{0.89100653f,-0.45399052f}, {0.86602545f,-0.50000000f}, {0.83867055f,-0.54463905f}, +{0.80901700f,-0.58778524f}, {0.77714598f,-0.62932038f}, {0.74314475f,-0.66913062f}, +{0.70710677f,-0.70710683f}, {0.66913056f,-0.74314487f}, {0.62932038f,-0.77714598f}, +{0.58778524f,-0.80901700f}, {0.54463899f,-0.83867055f}, {0.49999997f,-0.86602545f}, +{0.45399052f,-0.89100653f}, {0.40673661f,-0.91354549f}, {0.35836786f,-0.93358046f}, +{0.30901697f,-0.95105654f}, {0.25881907f,-0.96592581f}, {0.20791166f,-0.97814763f}, +{0.15643437f,-0.98768836f}, {0.10452842f,-0.99452192f}, {0.052335974f,-0.99862951f}, +{-4.3711388e-08f,-1.0000000f}, {-0.052336060f,-0.99862951f}, {-0.10452851f,-0.99452192f}, +{-0.15643445f,-0.98768836f}, {-0.20791174f,-0.97814757f}, {-0.25881916f,-0.96592581f}, +{-0.30901703f,-0.95105648f}, {-0.35836795f,-0.93358040f}, {-0.40673670f,-0.91354543f}, +{-0.45399061f,-0.89100647f}, {-0.50000006f,-0.86602533f}, {-0.54463905f,-0.83867055f}, +{-0.58778518f,-0.80901700f}, {-0.62932050f,-0.77714586f}, {-0.66913068f,-0.74314475f}, +{-0.70710677f,-0.70710677f}, {-0.74314493f,-0.66913044f}, {-0.77714604f,-0.62932026f}, +{-0.80901700f,-0.58778518f}, {-0.83867055f,-0.54463899f}, {-0.86602539f,-0.50000006f}, +{-0.89100659f,-0.45399037f}, {-0.91354549f,-0.40673658f}, {-0.93358040f,-0.35836792f}, +{-0.95105654f,-0.30901679f}, {-0.96592587f,-0.25881892f}, {-0.97814763f,-0.20791161f}, +{-0.98768836f,-0.15643445f}, {-0.99452192f,-0.10452849f}, {-0.99862957f,-0.052335810f}, +{1.0000000f,-0.0000000f}, {0.99691731f,-0.078459099f}, {0.98768836f,-0.15643448f}, +{0.97236991f,-0.23344538f}, {0.95105648f,-0.30901700f}, {0.92387956f,-0.38268346f}, +{0.89100653f,-0.45399052f}, {0.85264015f,-0.52249855f}, {0.80901700f,-0.58778524f}, +{0.76040596f,-0.64944810f}, {0.70710677f,-0.70710683f}, {0.64944804f,-0.76040596f}, +{0.58778524f,-0.80901700f}, {0.52249849f,-0.85264015f}, {0.45399052f,-0.89100653f}, +{0.38268343f,-0.92387956f}, {0.30901697f,-0.95105654f}, {0.23344530f,-0.97236991f}, +{0.15643437f,-0.98768836f}, {0.078459084f,-0.99691731f}, {-4.3711388e-08f,-1.0000000f}, +{-0.078459173f,-0.99691731f}, {-0.15643445f,-0.98768836f}, {-0.23344538f,-0.97236991f}, +{-0.30901703f,-0.95105648f}, {-0.38268352f,-0.92387950f}, {-0.45399061f,-0.89100647f}, +{-0.52249867f,-0.85264009f}, {-0.58778518f,-0.80901700f}, {-0.64944804f,-0.76040596f}, +{-0.70710677f,-0.70710677f}, {-0.76040596f,-0.64944804f}, {-0.80901700f,-0.58778518f}, +{-0.85264021f,-0.52249849f}, {-0.89100659f,-0.45399037f}, {-0.92387956f,-0.38268328f}, +{-0.95105654f,-0.30901679f}, {-0.97236991f,-0.23344538f}, {-0.98768836f,-0.15643445f}, +{-0.99691737f,-0.078459039f}, {-1.0000000f,8.7422777e-08f}, {-0.99691731f,0.078459218f}, +{-0.98768830f,0.15643461f}, {-0.97236985f,0.23344554f}, {-0.95105654f,0.30901697f}, +{-0.92387956f,0.38268346f}, {-0.89100653f,0.45399055f}, {-0.85264015f,0.52249861f}, +{-0.80901694f,0.58778536f}, {-0.76040590f,0.64944816f}, {-0.70710665f,0.70710689f}, +{-0.64944792f,0.76040608f}, {-0.58778507f,0.80901712f}, {-0.52249837f,0.85264033f}, +{-0.45399022f,0.89100665f}, {-0.38268313f,0.92387968f}, {-0.30901709f,0.95105648f}, +{-0.23344545f,0.97236991f}, {-0.15643452f,0.98768830f}, {-0.078459114f,0.99691731f}, +}; +static const ne10_fft_cpx_float32_t ne10_twiddles_120[120] = { +{1.0000000f,0.0000000f}, {1.0000000f,-0.0000000f}, {1.0000000f,-0.0000000f}, +{1.0000000f,-0.0000000f}, {0.91354543f,-0.40673664f}, {0.66913056f,-0.74314487f}, +{1.0000000f,-0.0000000f}, {0.66913056f,-0.74314487f}, {-0.10452851f,-0.99452192f}, +{1.0000000f,-0.0000000f}, {0.30901697f,-0.95105654f}, {-0.80901700f,-0.58778518f}, +{1.0000000f,-0.0000000f}, {-0.10452851f,-0.99452192f}, {-0.97814757f,0.20791179f}, +{1.0000000f,-0.0000000f}, {0.97814763f,-0.20791170f}, {0.91354543f,-0.40673664f}, +{0.80901700f,-0.58778524f}, {0.66913056f,-0.74314487f}, {0.49999997f,-0.86602545f}, +{0.30901697f,-0.95105654f}, {0.10452842f,-0.99452192f}, {-0.10452851f,-0.99452192f}, +{-0.30901703f,-0.95105648f}, {-0.50000006f,-0.86602533f}, {-0.66913068f,-0.74314475f}, +{-0.80901700f,-0.58778518f}, {-0.91354549f,-0.40673658f}, {-0.97814763f,-0.20791161f}, +{1.0000000f,-0.0000000f}, {0.99862951f,-0.052335959f}, {0.99452192f,-0.10452846f}, +{0.98768836f,-0.15643448f}, {0.97814763f,-0.20791170f}, {0.96592581f,-0.25881904f}, +{0.95105648f,-0.30901700f}, {0.93358040f,-0.35836795f}, {0.91354543f,-0.40673664f}, +{0.89100653f,-0.45399052f}, {0.86602545f,-0.50000000f}, {0.83867055f,-0.54463905f}, +{0.80901700f,-0.58778524f}, {0.77714598f,-0.62932038f}, {0.74314475f,-0.66913062f}, +{0.70710677f,-0.70710683f}, {0.66913056f,-0.74314487f}, {0.62932038f,-0.77714598f}, +{0.58778524f,-0.80901700f}, {0.54463899f,-0.83867055f}, {0.49999997f,-0.86602545f}, +{0.45399052f,-0.89100653f}, {0.40673661f,-0.91354549f}, {0.35836786f,-0.93358046f}, +{0.30901697f,-0.95105654f}, {0.25881907f,-0.96592581f}, {0.20791166f,-0.97814763f}, +{0.15643437f,-0.98768836f}, {0.10452842f,-0.99452192f}, {0.052335974f,-0.99862951f}, +{1.0000000f,-0.0000000f}, {0.99452192f,-0.10452846f}, {0.97814763f,-0.20791170f}, +{0.95105648f,-0.30901700f}, {0.91354543f,-0.40673664f}, {0.86602545f,-0.50000000f}, +{0.80901700f,-0.58778524f}, {0.74314475f,-0.66913062f}, {0.66913056f,-0.74314487f}, +{0.58778524f,-0.80901700f}, {0.49999997f,-0.86602545f}, {0.40673661f,-0.91354549f}, +{0.30901697f,-0.95105654f}, {0.20791166f,-0.97814763f}, {0.10452842f,-0.99452192f}, +{-4.3711388e-08f,-1.0000000f}, {-0.10452851f,-0.99452192f}, {-0.20791174f,-0.97814757f}, +{-0.30901703f,-0.95105648f}, {-0.40673670f,-0.91354543f}, {-0.50000006f,-0.86602533f}, +{-0.58778518f,-0.80901700f}, {-0.66913068f,-0.74314475f}, {-0.74314493f,-0.66913044f}, +{-0.80901700f,-0.58778518f}, {-0.86602539f,-0.50000006f}, {-0.91354549f,-0.40673658f}, +{-0.95105654f,-0.30901679f}, {-0.97814763f,-0.20791161f}, {-0.99452192f,-0.10452849f}, +{1.0000000f,-0.0000000f}, {0.98768836f,-0.15643448f}, {0.95105648f,-0.30901700f}, +{0.89100653f,-0.45399052f}, {0.80901700f,-0.58778524f}, {0.70710677f,-0.70710683f}, +{0.58778524f,-0.80901700f}, {0.45399052f,-0.89100653f}, {0.30901697f,-0.95105654f}, +{0.15643437f,-0.98768836f}, {-4.3711388e-08f,-1.0000000f}, {-0.15643445f,-0.98768836f}, +{-0.30901703f,-0.95105648f}, {-0.45399061f,-0.89100647f}, {-0.58778518f,-0.80901700f}, +{-0.70710677f,-0.70710677f}, {-0.80901700f,-0.58778518f}, {-0.89100659f,-0.45399037f}, +{-0.95105654f,-0.30901679f}, {-0.98768836f,-0.15643445f}, {-1.0000000f,8.7422777e-08f}, +{-0.98768830f,0.15643461f}, {-0.95105654f,0.30901697f}, {-0.89100653f,0.45399055f}, +{-0.80901694f,0.58778536f}, {-0.70710665f,0.70710689f}, {-0.58778507f,0.80901712f}, +{-0.45399022f,0.89100665f}, {-0.30901709f,0.95105648f}, {-0.15643452f,0.98768830f}, +}; +static const ne10_fft_cpx_float32_t ne10_twiddles_60[60] = { +{1.0000000f,0.0000000f}, {1.0000000f,-0.0000000f}, {1.0000000f,-0.0000000f}, +{1.0000000f,-0.0000000f}, {0.91354543f,-0.40673664f}, {0.66913056f,-0.74314487f}, +{1.0000000f,-0.0000000f}, {0.66913056f,-0.74314487f}, {-0.10452851f,-0.99452192f}, +{1.0000000f,-0.0000000f}, {0.30901697f,-0.95105654f}, {-0.80901700f,-0.58778518f}, +{1.0000000f,-0.0000000f}, {-0.10452851f,-0.99452192f}, {-0.97814757f,0.20791179f}, +{1.0000000f,-0.0000000f}, {0.99452192f,-0.10452846f}, {0.97814763f,-0.20791170f}, +{0.95105648f,-0.30901700f}, {0.91354543f,-0.40673664f}, {0.86602545f,-0.50000000f}, +{0.80901700f,-0.58778524f}, {0.74314475f,-0.66913062f}, {0.66913056f,-0.74314487f}, +{0.58778524f,-0.80901700f}, {0.49999997f,-0.86602545f}, {0.40673661f,-0.91354549f}, +{0.30901697f,-0.95105654f}, {0.20791166f,-0.97814763f}, {0.10452842f,-0.99452192f}, +{1.0000000f,-0.0000000f}, {0.97814763f,-0.20791170f}, {0.91354543f,-0.40673664f}, +{0.80901700f,-0.58778524f}, {0.66913056f,-0.74314487f}, {0.49999997f,-0.86602545f}, +{0.30901697f,-0.95105654f}, {0.10452842f,-0.99452192f}, {-0.10452851f,-0.99452192f}, +{-0.30901703f,-0.95105648f}, {-0.50000006f,-0.86602533f}, {-0.66913068f,-0.74314475f}, +{-0.80901700f,-0.58778518f}, {-0.91354549f,-0.40673658f}, {-0.97814763f,-0.20791161f}, +{1.0000000f,-0.0000000f}, {0.95105648f,-0.30901700f}, {0.80901700f,-0.58778524f}, +{0.58778524f,-0.80901700f}, {0.30901697f,-0.95105654f}, {-4.3711388e-08f,-1.0000000f}, +{-0.30901703f,-0.95105648f}, {-0.58778518f,-0.80901700f}, {-0.80901700f,-0.58778518f}, +{-0.95105654f,-0.30901679f}, {-1.0000000f,8.7422777e-08f}, {-0.95105654f,0.30901697f}, +{-0.80901694f,0.58778536f}, {-0.58778507f,0.80901712f}, {-0.30901709f,0.95105648f}, +}; +static const ne10_fft_state_float32_t ne10_fft_state_float32_t_480 = { +120, +(ne10_int32_t *)ne10_factors_480, +(ne10_fft_cpx_float32_t *)ne10_twiddles_480, +NULL, +(ne10_fft_cpx_float32_t *)&ne10_twiddles_480[120], +/* is_forward_scaled = true */ +(ne10_int32_t) 1, +/* is_backward_scaled = false */ +(ne10_int32_t) 0, +}; +static const arch_fft_state cfg_arch_480 = { +1, +(void *)&ne10_fft_state_float32_t_480, +}; + +static const ne10_fft_state_float32_t ne10_fft_state_float32_t_240 = { +60, +(ne10_int32_t *)ne10_factors_240, +(ne10_fft_cpx_float32_t *)ne10_twiddles_240, +NULL, +(ne10_fft_cpx_float32_t *)&ne10_twiddles_240[60], +/* is_forward_scaled = true */ +(ne10_int32_t) 1, +/* is_backward_scaled = false */ +(ne10_int32_t) 0, +}; +static const arch_fft_state cfg_arch_240 = { +1, +(void *)&ne10_fft_state_float32_t_240, +}; + +static const ne10_fft_state_float32_t ne10_fft_state_float32_t_120 = { +30, +(ne10_int32_t *)ne10_factors_120, +(ne10_fft_cpx_float32_t *)ne10_twiddles_120, +NULL, +(ne10_fft_cpx_float32_t *)&ne10_twiddles_120[30], +/* is_forward_scaled = true */ +(ne10_int32_t) 1, +/* is_backward_scaled = false */ +(ne10_int32_t) 0, +}; +static const arch_fft_state cfg_arch_120 = { +1, +(void *)&ne10_fft_state_float32_t_120, +}; + +static const ne10_fft_state_float32_t ne10_fft_state_float32_t_60 = { +15, +(ne10_int32_t *)ne10_factors_60, +(ne10_fft_cpx_float32_t *)ne10_twiddles_60, +NULL, +(ne10_fft_cpx_float32_t *)&ne10_twiddles_60[15], +/* is_forward_scaled = true */ +(ne10_int32_t) 1, +/* is_backward_scaled = false */ +(ne10_int32_t) 0, +}; +static const arch_fft_state cfg_arch_60 = { +1, +(void *)&ne10_fft_state_float32_t_60, +}; + +#endif /* end NE10_FFT_PARAMS48000_960 */ diff --git a/extern/opus/celt/tests/test_unit_cwrs32.c b/extern/opus/celt/tests/test_unit_cwrs32.c new file mode 100644 index 0000000..36dd8af --- /dev/null +++ b/extern/opus/celt/tests/test_unit_cwrs32.c @@ -0,0 +1,161 @@ +/* Copyright (c) 2008-2011 Xiph.Org Foundation, Mozilla Corporation, + Gregory Maxwell + Written by Jean-Marc Valin, Gregory Maxwell, and Timothy B. Terriberry */ +/* + 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. + + 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 OWNER + 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. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +#ifndef CUSTOM_MODES +#define CUSTOM_MODES +#else +#define TEST_CUSTOM_MODES +#endif + +#define CELT_C +#include "stack_alloc.h" +#include "entenc.c" +#include "entdec.c" +#include "entcode.c" +#include "cwrs.c" +#include "mathops.c" +#include "rate.h" + +#define NMAX (240) +#define KMAX (128) + +#ifdef TEST_CUSTOM_MODES + +#define NDIMS (44) +static const int pn[NDIMS]={ + 2, 3, 4, 5, 6, 7, 8, 9, 10, + 11, 12, 13, 14, 15, 16, 18, 20, 22, + 24, 26, 28, 30, 32, 36, 40, 44, 48, + 52, 56, 60, 64, 72, 80, 88, 96, 104, + 112, 120, 128, 144, 160, 176, 192, 208 +}; +static const int pkmax[NDIMS]={ + 128, 128, 128, 128, 88, 52, 36, 26, 22, + 18, 16, 15, 13, 12, 12, 11, 10, 9, + 9, 8, 8, 7, 7, 7, 7, 6, 6, + 6, 6, 6, 5, 5, 5, 5, 5, 5, + 4, 4, 4, 4, 4, 4, 4, 4 +}; + +#else /* TEST_CUSTOM_MODES */ + +#define NDIMS (22) +static const int pn[NDIMS]={ + 2, 3, 4, 6, 8, 9, 11, 12, 16, + 18, 22, 24, 32, 36, 44, 48, 64, 72, + 88, 96, 144, 176 +}; +static const int pkmax[NDIMS]={ + 128, 128, 128, 88, 36, 26, 18, 16, 12, + 11, 9, 9, 7, 7, 6, 6, 5, 5, + 5, 5, 4, 4 +}; + +#endif + +int main(void){ + int t; + int n; + ALLOC_STACK; + for(t=0;tpkmax[t])break; + printf("Testing CWRS with N=%i, K=%i...\n",n,k); +#if defined(SMALL_FOOTPRINT) + nc=ncwrs_urow(n,k,uu); +#else + nc=CELT_PVQ_V(n,k); +#endif + inc=nc/20000; + if(inc<1)inc=1; + for(i=0;i");*/ +#if defined(SMALL_FOOTPRINT) + ii=icwrs(n,k,&v,y,u); +#else + ii=icwrs(n,y); + v=CELT_PVQ_V(n,k); +#endif + if(ii!=i){ + fprintf(stderr,"Combination-index mismatch (%lu!=%lu).\n", + (long)ii,(long)i); + return 1; + } + if(v!=nc){ + fprintf(stderr,"Combination count mismatch (%lu!=%lu).\n", + (long)v,(long)nc); + return 2; + } + /*printf(" %6u\n",i);*/ + } + /*printf("\n");*/ + } + } + return 0; +} diff --git a/extern/opus/celt/tests/test_unit_dft.c b/extern/opus/celt/tests/test_unit_dft.c new file mode 100644 index 0000000..70f8f49 --- /dev/null +++ b/extern/opus/celt/tests/test_unit_dft.c @@ -0,0 +1,179 @@ +/* Copyright (c) 2008 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + 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. + + 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 OWNER + 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. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include "stack_alloc.h" +#include "kiss_fft.h" +#include "mathops.h" +#include "modes.h" + +#ifndef M_PI +#define M_PI 3.141592653 +#endif + +int ret = 0; + +void check(kiss_fft_cpx * in,kiss_fft_cpx * out,int nfft,int isinverse) +{ + int bin,k; + double errpow=0,sigpow=0, snr; + + for (bin=0;binmdct.kfft[id]; +#endif + + in = (kiss_fft_cpx*)malloc(buflen); + out = (kiss_fft_cpx*)malloc(buflen); + + for (k=0;k1) { + int k; + for (k=1;k +#include +#include +#include +#define CELT_C +#include "entcode.h" +#include "entenc.h" +#include "entdec.h" +#include + +#include "entenc.c" +#include "entdec.c" +#include "entcode.c" + +#ifndef M_LOG2E +# define M_LOG2E 1.4426950408889634074 +#endif +#define DATA_SIZE 10000000 +#define DATA_SIZE2 10000 + +int main(int _argc,char **_argv){ + ec_enc enc; + ec_dec dec; + long nbits; + long nbits2; + double entropy; + int ft; + int ftb; + int sz; + int i; + int ret; + unsigned int sym; + unsigned int seed; + unsigned char *ptr; + const char *env_seed; + ret=0; + entropy=0; + if (_argc > 2) { + fprintf(stderr, "Usage: %s []\n", _argv[0]); + return 1; + } + env_seed = getenv("SEED"); + if (_argc > 1) + seed = atoi(_argv[1]); + else if (env_seed) + seed = atoi(env_seed); + else + seed = time(NULL); + /*Testing encoding of raw bit values.*/ + ptr = (unsigned char *)malloc(DATA_SIZE); + ec_enc_init(&enc,ptr, DATA_SIZE); + for(ft=2;ft<1024;ft++){ + for(i=0;i>(rand()%11U))+1U)+10; + sz=rand()/((RAND_MAX>>(rand()%9U))+1U); + data=(unsigned *)malloc(sz*sizeof(*data)); + tell=(unsigned *)malloc((sz+1)*sizeof(*tell)); + ec_enc_init(&enc,ptr,DATA_SIZE2); + zeros = rand()%13==0; + tell[0]=ec_tell_frac(&enc); + for(j=0;j>(rand()%9U))+1U); + logp1=(unsigned *)malloc(sz*sizeof(*logp1)); + data=(unsigned *)malloc(sz*sizeof(*data)); + tell=(unsigned *)malloc((sz+1)*sizeof(*tell)); + enc_method=(unsigned *)malloc(sz*sizeof(*enc_method)); + ec_enc_init(&enc,ptr,DATA_SIZE2); + tell[0]=ec_tell_frac(&enc); + for(j=0;j>1)+1); + logp1[j]=(rand()%15)+1; + enc_method[j]=rand()/((RAND_MAX>>2)+1); + switch(enc_method[j]){ + case 0:{ + ec_encode(&enc,data[j]?(1<>2)+1); + switch(dec_method){ + case 0:{ + fs=ec_decode(&dec,1<=(1<=(1< +#include +#define CELT_C +#include "laplace.h" +#include "stack_alloc.h" + +#include "entenc.c" +#include "entdec.c" +#include "entcode.c" +#include "laplace.c" + +#define DATA_SIZE 40000 + +int ec_laplace_get_start_freq(int decay) +{ + opus_uint32 ft = 32768 - LAPLACE_MINP*(2*LAPLACE_NMIN+1); + int fs = (ft*(16384-decay))/(16384+decay); + return fs+LAPLACE_MINP; +} + +int main(void) +{ + int i; + int ret = 0; + ec_enc enc; + ec_dec dec; + unsigned char *ptr; + int val[10000], decay[10000]; + ALLOC_STACK; + ptr = (unsigned char *)malloc(DATA_SIZE); + ec_enc_init(&enc,ptr,DATA_SIZE); + + val[0] = 3; decay[0] = 6000; + val[1] = 0; decay[1] = 5800; + val[2] = -1; decay[2] = 5600; + for (i=3;i<10000;i++) + { + val[i] = rand()%15-7; + decay[i] = rand()%11000+5000; + } + for (i=0;i<10000;i++) + ec_laplace_encode(&enc, &val[i], + ec_laplace_get_start_freq(decay[i]), decay[i]); + + ec_enc_done(&enc); + + ec_dec_init(&dec,ec_get_buffer(&enc),ec_range_bytes(&enc)); + + for (i=0;i<10000;i++) + { + int d = ec_laplace_decode(&dec, + ec_laplace_get_start_freq(decay[i]), decay[i]); + if (d != val[i]) + { + fprintf (stderr, "Got %d instead of %d\n", d, val[i]); + ret = 1; + } + } + + free(ptr); + return ret; +} diff --git a/extern/opus/celt/tests/test_unit_mathops.c b/extern/opus/celt/tests/test_unit_mathops.c new file mode 100644 index 0000000..874e9ad --- /dev/null +++ b/extern/opus/celt/tests/test_unit_mathops.c @@ -0,0 +1,266 @@ +/* Copyright (c) 2008-2011 Xiph.Org Foundation, Mozilla Corporation, + Gregory Maxwell + Written by Jean-Marc Valin, Gregory Maxwell, and Timothy B. Terriberry */ +/* + 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. + + 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 OWNER + 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. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifndef CUSTOM_MODES +#define CUSTOM_MODES +#endif + +#include +#include +#include "mathops.h" +#include "bands.h" + +#ifdef FIXED_POINT +#define WORD "%d" +#else +#define WORD "%f" +#endif + +int ret = 0; + +void testdiv(void) +{ + opus_int32 i; + for (i=1;i<=327670;i++) + { + double prod; + opus_val32 val; + val = celt_rcp(i); +#ifdef FIXED_POINT + prod = (1./32768./65526.)*val*i; +#else + prod = val*i; +#endif + if (fabs(prod-1) > .00025) + { + fprintf (stderr, "div failed: 1/%d="WORD" (product = %f)\n", i, val, prod); + ret = 1; + } + } +} + +void testsqrt(void) +{ + opus_int32 i; + for (i=1;i<=1000000000;i++) + { + double ratio; + opus_val16 val; + val = celt_sqrt(i); + ratio = val/sqrt(i); + if (fabs(ratio - 1) > .0005 && fabs(val-sqrt(i)) > 2) + { + fprintf (stderr, "sqrt failed: sqrt(%d)="WORD" (ratio = %f)\n", i, val, ratio); + ret = 1; + } + i+= i>>10; + } +} + +void testbitexactcos(void) +{ + int i; + opus_int32 min_d,max_d,last,chk; + chk=max_d=0; + last=min_d=32767; + for(i=64;i<=16320;i++) + { + opus_int32 d; + opus_int32 q=bitexact_cos(i); + chk ^= q*i; + d = last - q; + if (d>max_d)max_d=d; + if (dmax_d)max_d=d; + if (d0.0009) + { + fprintf (stderr, "celt_log2 failed: fabs((1.442695040888963387*log(x))-celt_log2(x))>0.001 (x = %f, error = %f)\n", x,error); + ret = 1; + } + } +} + +void testexp2(void) +{ + float x; + for (x=-11.0;x<24.0;x+=0.0007) + { + float error = fabs(x-(1.442695040888963387*log(celt_exp2(x)))); + if (error>0.0002) + { + fprintf (stderr, "celt_exp2 failed: fabs(x-(1.442695040888963387*log(celt_exp2(x))))>0.0005 (x = %f, error = %f)\n", x,error); + ret = 1; + } + } +} + +void testexp2log2(void) +{ + float x; + for (x=-11.0;x<24.0;x+=0.0007) + { + float error = fabs(x-(celt_log2(celt_exp2(x)))); + if (error>0.001) + { + fprintf (stderr, "celt_log2/celt_exp2 failed: fabs(x-(celt_log2(celt_exp2(x))))>0.001 (x = %f, error = %f)\n", x,error); + ret = 1; + } + } +} +#else +void testlog2(void) +{ + opus_val32 x; + for (x=8;x<1073741824;x+=(x>>3)) + { + float error = fabs((1.442695040888963387*log(x/16384.0))-celt_log2(x)/1024.0); + if (error>0.003) + { + fprintf (stderr, "celt_log2 failed: x = %ld, error = %f\n", (long)x,error); + ret = 1; + } + } +} + +void testexp2(void) +{ + opus_val16 x; + for (x=-32768;x<15360;x++) + { + float error1 = fabs(x/1024.0-(1.442695040888963387*log(celt_exp2(x)/65536.0))); + float error2 = fabs(exp(0.6931471805599453094*x/1024.0)-celt_exp2(x)/65536.0); + if (error1>0.0002&&error2>0.00004) + { + fprintf (stderr, "celt_exp2 failed: x = "WORD", error1 = %f, error2 = %f\n", x,error1,error2); + ret = 1; + } + } +} + +void testexp2log2(void) +{ + opus_val32 x; + for (x=8;x<65536;x+=(x>>3)) + { + float error = fabs(x-0.25*celt_exp2(celt_log2(x)))/16384; + if (error>0.004) + { + fprintf (stderr, "celt_log2/celt_exp2 failed: fabs(x-(celt_exp2(celt_log2(x))))>0.001 (x = %ld, error = %f)\n", (long)x,error); + ret = 1; + } + } +} + +void testilog2(void) +{ + opus_val32 x; + for (x=1;x<=268435455;x+=127) + { + opus_val32 lg; + opus_val32 y; + + lg = celt_ilog2(x); + if (lg<0 || lg>=31) + { + printf("celt_ilog2 failed: 0<=celt_ilog2(x)<31 (x = %d, celt_ilog2(x) = %d)\n",x,lg); + ret = 1; + } + y = 1<>1)>=y) + { + printf("celt_ilog2 failed: 2**celt_ilog2(x)<=x<2**(celt_ilog2(x)+1) (x = %d, 2**celt_ilog2(x) = %d)\n",x,y); + ret = 1; + } + } +} +#endif + +int main(void) +{ + testbitexactcos(); + testbitexactlog2tan(); + testdiv(); + testsqrt(); + testlog2(); + testexp2(); + testexp2log2(); +#ifdef FIXED_POINT + testilog2(); +#endif + return ret; +} diff --git a/extern/opus/celt/tests/test_unit_mdct.c b/extern/opus/celt/tests/test_unit_mdct.c new file mode 100644 index 0000000..4a563cc --- /dev/null +++ b/extern/opus/celt/tests/test_unit_mdct.c @@ -0,0 +1,227 @@ +/* Copyright (c) 2008-2011 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + 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. + + 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 OWNER + 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. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include "mdct.h" +#include "stack_alloc.h" +#include "kiss_fft.h" +#include "mdct.h" +#include "modes.h" + +#ifndef M_PI +#define M_PI 3.141592653 +#endif + +int ret = 0; +void check(kiss_fft_scalar * in,kiss_fft_scalar * out,int nfft,int isinverse) +{ + int bin,k; + double errpow=0,sigpow=0; + double snr; + for (bin=0;binmdct; +#endif + + in = (kiss_fft_scalar*)malloc(buflen); + in_copy = (kiss_fft_scalar*)malloc(buflen); + out = (kiss_fft_scalar*)malloc(buflen); + window = (opus_val16*)malloc(sizeof(opus_val16)*nfft/2); + + for (k=0;k1) { + int k; + for (k=1;k +#include +#include "vq.h" +#include "bands.h" +#include "stack_alloc.h" +#include + + +#define MAX_SIZE 100 + +int ret=0; +void test_rotation(int N, int K) +{ + int i; + double err = 0, ener = 0, snr, snr0; + opus_val16 x0[MAX_SIZE]; + opus_val16 x1[MAX_SIZE]; + for (i=0;i 20) + { + fprintf(stderr, "FAIL!\n"); + ret = 1; + } +} + +int main(void) +{ + ALLOC_STACK; + test_rotation(15, 3); + test_rotation(23, 5); + test_rotation(50, 3); + test_rotation(80, 1); + return ret; +} diff --git a/extern/opus/celt/tests/test_unit_types.c b/extern/opus/celt/tests/test_unit_types.c new file mode 100644 index 0000000..67a0fb8 --- /dev/null +++ b/extern/opus/celt/tests/test_unit_types.c @@ -0,0 +1,50 @@ +/* Copyright (c) 2008-2011 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + 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. + + 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 OWNER + 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. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "opus_types.h" +#include + +int main(void) +{ + opus_int16 i = 1; + i <<= 14; + if (i>>14 != 1) + { + fprintf(stderr, "opus_int16 isn't 16 bits\n"); + return 1; + } + if (sizeof(opus_int16)*2 != sizeof(opus_int32)) + { + fprintf(stderr, "16*2 != 32\n"); + return 1; + } + return 0; +} diff --git a/extern/opus/celt/vq.c b/extern/opus/celt/vq.c new file mode 100644 index 0000000..8011e22 --- /dev/null +++ b/extern/opus/celt/vq.c @@ -0,0 +1,442 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + 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. + + 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 OWNER + 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. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "mathops.h" +#include "cwrs.h" +#include "vq.h" +#include "arch.h" +#include "os_support.h" +#include "bands.h" +#include "rate.h" +#include "pitch.h" + +#if defined(MIPSr1_ASM) +#include "mips/vq_mipsr1.h" +#endif + +#ifndef OVERRIDE_vq_exp_rotation1 +static void exp_rotation1(celt_norm *X, int len, int stride, opus_val16 c, opus_val16 s) +{ + int i; + opus_val16 ms; + celt_norm *Xptr; + Xptr = X; + ms = NEG16(s); + for (i=0;i=0;i--) + { + celt_norm x1, x2; + x1 = Xptr[0]; + x2 = Xptr[stride]; + Xptr[stride] = EXTRACT16(PSHR32(MAC16_16(MULT16_16(c, x2), s, x1), 15)); + *Xptr-- = EXTRACT16(PSHR32(MAC16_16(MULT16_16(c, x1), ms, x2), 15)); + } +} +#endif /* OVERRIDE_vq_exp_rotation1 */ + +void exp_rotation(celt_norm *X, int len, int dir, int stride, int K, int spread) +{ + static const int SPREAD_FACTOR[3]={15,10,5}; + int i; + opus_val16 c, s; + opus_val16 gain, theta; + int stride2=0; + int factor; + + if (2*K>=len || spread==SPREAD_NONE) + return; + factor = SPREAD_FACTOR[spread-1]; + + gain = celt_div((opus_val32)MULT16_16(Q15_ONE,len),(opus_val32)(len+factor*K)); + theta = HALF16(MULT16_16_Q15(gain,gain)); + + c = celt_cos_norm(EXTEND32(theta)); + s = celt_cos_norm(EXTEND32(SUB16(Q15ONE,theta))); /* sin(theta) */ + + if (len>=8*stride) + { + stride2 = 1; + /* This is just a simple (equivalent) way of computing sqrt(len/stride) with rounding. + It's basically incrementing long as (stride2+0.5)^2 < len/stride. */ + while ((stride2*stride2+stride2)*stride + (stride>>2) < len) + stride2++; + } + /*NOTE: As a minor optimization, we could be passing around log2(B), not B, for both this and for + extract_collapse_mask().*/ + len = celt_udiv(len, stride); + for (i=0;i>1; +#endif + t = VSHR32(Ryy, 2*(k-7)); + g = MULT16_16_P15(celt_rsqrt_norm(t),gain); + + i=0; + do + X[i] = EXTRACT16(PSHR32(MULT16_16(g, iy[i]), k+1)); + while (++i < N); +} + +static unsigned extract_collapse_mask(int *iy, int N, int B) +{ + unsigned collapse_mask; + int N0; + int i; + if (B<=1) + return 1; + /*NOTE: As a minor optimization, we could be passing around log2(B), not B, for both this and for + exp_rotation().*/ + N0 = celt_udiv(N, B); + collapse_mask = 0; + i=0; do { + int j; + unsigned tmp=0; + j=0; do { + tmp |= iy[i*N0+j]; + } while (++j (N>>1)) + { + opus_val16 rcp; + j=0; do { + sum += X[j]; + } while (++j EPSILON && sum < 64)) +#endif + { + X[0] = QCONST16(1.f,14); + j=1; do + X[j]=0; + while (++j=0); + + /* This should never happen, but just in case it does (e.g. on silence) + we fill the first bin with pulses. */ +#ifdef FIXED_POINT_DEBUG + celt_sig_assert(pulsesLeft<=N+3); +#endif + if (pulsesLeft > N+3) + { + opus_val16 tmp = (opus_val16)pulsesLeft; + yy = MAC16_16(yy, tmp, tmp); + yy = MAC16_16(yy, tmp, y[0]); + iy[0] += pulsesLeft; + pulsesLeft=0; + } + + for (i=0;i= best_num/best_den, but that way + we can do it without any division */ + /* OPT: It's not clear whether a cmov is faster than a branch here + since the condition is more often false than true and using + a cmov introduces data dependencies across iterations. The optimal + choice may be architecture-dependent. */ + if (opus_unlikely(MULT16_16(best_den, Rxy) > MULT16_16(Ryy, best_num))) + { + best_den = Ryy; + best_num = Rxy; + best_id = j; + } + } while (++j0, "alg_quant() needs at least one pulse"); + celt_assert2(N>1, "alg_quant() needs at least two dimensions"); + + /* Covers vectorization by up to 4. */ + ALLOC(iy, N+3, int); + + exp_rotation(X, N, 1, B, K, spread); + + yy = op_pvq_search(X, iy, K, N, arch); + + encode_pulses(iy, N, K, enc); + + if (resynth) + { + normalise_residual(iy, X, N, yy, gain); + exp_rotation(X, N, -1, B, K, spread); + } + + collapse_mask = extract_collapse_mask(iy, N, B); + RESTORE_STACK; + return collapse_mask; +} + +/** Decode pulse vector and combine the result with the pitch vector to produce + the final normalised signal in the current band. */ +unsigned alg_unquant(celt_norm *X, int N, int K, int spread, int B, + ec_dec *dec, opus_val16 gain) +{ + opus_val32 Ryy; + unsigned collapse_mask; + VARDECL(int, iy); + SAVE_STACK; + + celt_assert2(K>0, "alg_unquant() needs at least one pulse"); + celt_assert2(N>1, "alg_unquant() needs at least two dimensions"); + ALLOC(iy, N, int); + Ryy = decode_pulses(iy, N, K, dec); + normalise_residual(iy, X, N, Ryy, gain); + exp_rotation(X, N, -1, B, K, spread); + collapse_mask = extract_collapse_mask(iy, N, B); + RESTORE_STACK; + return collapse_mask; +} + +#ifndef OVERRIDE_renormalise_vector +void renormalise_vector(celt_norm *X, int N, opus_val16 gain, int arch) +{ + int i; +#ifdef FIXED_POINT + int k; +#endif + opus_val32 E; + opus_val16 g; + opus_val32 t; + celt_norm *xptr; + E = EPSILON + celt_inner_prod(X, X, N, arch); +#ifdef FIXED_POINT + k = celt_ilog2(E)>>1; +#endif + t = VSHR32(E, 2*(k-7)); + g = MULT16_16_P15(celt_rsqrt_norm(t),gain); + + xptr = X; + for (i=0;i +#include +#include +#include "celt_lpc.h" +#include "stack_alloc.h" +#include "mathops.h" +#include "pitch.h" +#include "x86cpu.h" + +#if defined(FIXED_POINT) + +void celt_fir_sse4_1(const opus_val16 *x, + const opus_val16 *num, + opus_val16 *y, + int N, + int ord, + int arch) +{ + int i,j; + VARDECL(opus_val16, rnum); + + __m128i vecNoA; + opus_int32 noA ; + SAVE_STACK; + + ALLOC(rnum, ord, opus_val16); + for(i=0;i> 1; + vecNoA = _mm_set_epi32(noA, noA, noA, noA); + + for (i=0;i +#include "arch.h" + +void xcorr_kernel_sse(const opus_val16 *x, const opus_val16 *y, opus_val32 sum[4], int len) +{ + int j; + __m128 xsum1, xsum2; + xsum1 = _mm_loadu_ps(sum); + xsum2 = _mm_setzero_ps(); + + for (j = 0; j < len-3; j += 4) + { + __m128 x0 = _mm_loadu_ps(x+j); + __m128 yj = _mm_loadu_ps(y+j); + __m128 y3 = _mm_loadu_ps(y+j+3); + + xsum1 = _mm_add_ps(xsum1,_mm_mul_ps(_mm_shuffle_ps(x0,x0,0x00),yj)); + xsum2 = _mm_add_ps(xsum2,_mm_mul_ps(_mm_shuffle_ps(x0,x0,0x55), + _mm_shuffle_ps(yj,y3,0x49))); + xsum1 = _mm_add_ps(xsum1,_mm_mul_ps(_mm_shuffle_ps(x0,x0,0xaa), + _mm_shuffle_ps(yj,y3,0x9e))); + xsum2 = _mm_add_ps(xsum2,_mm_mul_ps(_mm_shuffle_ps(x0,x0,0xff),y3)); + } + if (j < len) + { + xsum1 = _mm_add_ps(xsum1,_mm_mul_ps(_mm_load1_ps(x+j),_mm_loadu_ps(y+j))); + if (++j < len) + { + xsum2 = _mm_add_ps(xsum2,_mm_mul_ps(_mm_load1_ps(x+j),_mm_loadu_ps(y+j))); + if (++j < len) + { + xsum1 = _mm_add_ps(xsum1,_mm_mul_ps(_mm_load1_ps(x+j),_mm_loadu_ps(y+j))); + } + } + } + _mm_storeu_ps(sum,_mm_add_ps(xsum1,xsum2)); +} + + +void dual_inner_prod_sse(const opus_val16 *x, const opus_val16 *y01, const opus_val16 *y02, + int N, opus_val32 *xy1, opus_val32 *xy2) +{ + int i; + __m128 xsum1, xsum2; + xsum1 = _mm_setzero_ps(); + xsum2 = _mm_setzero_ps(); + for (i=0;i +#include + +#include "macros.h" +#include "celt_lpc.h" +#include "stack_alloc.h" +#include "mathops.h" +#include "pitch.h" + +#if defined(OPUS_X86_MAY_HAVE_SSE2) && defined(FIXED_POINT) +opus_val32 celt_inner_prod_sse2(const opus_val16 *x, const opus_val16 *y, + int N) +{ + opus_int i, dataSize16; + opus_int32 sum; + + __m128i inVec1_76543210, inVec1_FEDCBA98, acc1; + __m128i inVec2_76543210, inVec2_FEDCBA98, acc2; + + sum = 0; + dataSize16 = N & ~15; + + acc1 = _mm_setzero_si128(); + acc2 = _mm_setzero_si128(); + + for (i=0;i= 8) + { + inVec1_76543210 = _mm_loadu_si128((__m128i *)(&x[i + 0])); + inVec2_76543210 = _mm_loadu_si128((__m128i *)(&y[i + 0])); + + inVec1_76543210 = _mm_madd_epi16(inVec1_76543210, inVec2_76543210); + + acc1 = _mm_add_epi32(acc1, inVec1_76543210); + i += 8; + } + + acc1 = _mm_add_epi32(acc1, _mm_unpackhi_epi64( acc1, acc1)); + acc1 = _mm_add_epi32(acc1, _mm_shufflelo_epi16( acc1, 0x0E)); + sum += _mm_cvtsi128_si32(acc1); + + for (;i +#include + +#include "macros.h" +#include "celt_lpc.h" +#include "stack_alloc.h" +#include "mathops.h" +#include "pitch.h" + +#if defined(OPUS_X86_MAY_HAVE_SSE4_1) && defined(FIXED_POINT) +#include +#include "x86cpu.h" + +opus_val32 celt_inner_prod_sse4_1(const opus_val16 *x, const opus_val16 *y, + int N) +{ + opus_int i, dataSize16; + opus_int32 sum; + __m128i inVec1_76543210, inVec1_FEDCBA98, acc1; + __m128i inVec2_76543210, inVec2_FEDCBA98, acc2; + __m128i inVec1_3210, inVec2_3210; + + sum = 0; + dataSize16 = N & ~15; + + acc1 = _mm_setzero_si128(); + acc2 = _mm_setzero_si128(); + + for (i=0;i= 8) + { + inVec1_76543210 = _mm_loadu_si128((__m128i *)(&x[i + 0])); + inVec2_76543210 = _mm_loadu_si128((__m128i *)(&y[i + 0])); + + inVec1_76543210 = _mm_madd_epi16(inVec1_76543210, inVec2_76543210); + + acc1 = _mm_add_epi32(acc1, inVec1_76543210); + i += 8; + } + + if (N - i >= 4) + { + inVec1_3210 = OP_CVTEPI16_EPI32_M64(&x[i + 0]); + inVec2_3210 = OP_CVTEPI16_EPI32_M64(&y[i + 0]); + + inVec1_3210 = _mm_mullo_epi32(inVec1_3210, inVec2_3210); + + acc1 = _mm_add_epi32(acc1, inVec1_3210); + i += 4; + } + + acc1 = _mm_add_epi32(acc1, _mm_unpackhi_epi64(acc1, acc1)); + acc1 = _mm_add_epi32(acc1, _mm_shufflelo_epi16(acc1, 0x0E)); + + sum += _mm_cvtsi128_si32(acc1); + + for (;i= 3); + + sum0 = _mm_setzero_si128(); + sum1 = _mm_setzero_si128(); + sum2 = _mm_setzero_si128(); + sum3 = _mm_setzero_si128(); + + for (j=0;j<(len-7);j+=8) + { + vecX = _mm_loadu_si128((__m128i *)(&x[j + 0])); + vecY0 = _mm_loadu_si128((__m128i *)(&y[j + 0])); + vecY1 = _mm_loadu_si128((__m128i *)(&y[j + 1])); + vecY2 = _mm_loadu_si128((__m128i *)(&y[j + 2])); + vecY3 = _mm_loadu_si128((__m128i *)(&y[j + 3])); + + sum0 = _mm_add_epi32(sum0, _mm_madd_epi16(vecX, vecY0)); + sum1 = _mm_add_epi32(sum1, _mm_madd_epi16(vecX, vecY1)); + sum2 = _mm_add_epi32(sum2, _mm_madd_epi16(vecX, vecY2)); + sum3 = _mm_add_epi32(sum3, _mm_madd_epi16(vecX, vecY3)); + } + + sum0 = _mm_add_epi32(sum0, _mm_unpackhi_epi64( sum0, sum0)); + sum0 = _mm_add_epi32(sum0, _mm_shufflelo_epi16( sum0, 0x0E)); + + sum1 = _mm_add_epi32(sum1, _mm_unpackhi_epi64( sum1, sum1)); + sum1 = _mm_add_epi32(sum1, _mm_shufflelo_epi16( sum1, 0x0E)); + + sum2 = _mm_add_epi32(sum2, _mm_unpackhi_epi64( sum2, sum2)); + sum2 = _mm_add_epi32(sum2, _mm_shufflelo_epi16( sum2, 0x0E)); + + sum3 = _mm_add_epi32(sum3, _mm_unpackhi_epi64( sum3, sum3)); + sum3 = _mm_add_epi32(sum3, _mm_shufflelo_epi16( sum3, 0x0E)); + + vecSum = _mm_unpacklo_epi64(_mm_unpacklo_epi32(sum0, sum1), + _mm_unpacklo_epi32(sum2, sum3)); + + for (;j<(len-3);j+=4) + { + vecX = OP_CVTEPI16_EPI32_M64(&x[j + 0]); + vecX0 = _mm_shuffle_epi32(vecX, 0x00); + vecX1 = _mm_shuffle_epi32(vecX, 0x55); + vecX2 = _mm_shuffle_epi32(vecX, 0xaa); + vecX3 = _mm_shuffle_epi32(vecX, 0xff); + + vecY0 = OP_CVTEPI16_EPI32_M64(&y[j + 0]); + vecY1 = OP_CVTEPI16_EPI32_M64(&y[j + 1]); + vecY2 = OP_CVTEPI16_EPI32_M64(&y[j + 2]); + vecY3 = OP_CVTEPI16_EPI32_M64(&y[j + 3]); + + sum0 = _mm_mullo_epi32(vecX0, vecY0); + sum1 = _mm_mullo_epi32(vecX1, vecY1); + sum2 = _mm_mullo_epi32(vecX2, vecY2); + sum3 = _mm_mullo_epi32(vecX3, vecY3); + + sum0 = _mm_add_epi32(sum0, sum1); + sum2 = _mm_add_epi32(sum2, sum3); + vecSum = _mm_add_epi32(vecSum, sum0); + vecSum = _mm_add_epi32(vecSum, sum2); + } + + for (;j +#include +#include "celt_lpc.h" +#include "stack_alloc.h" +#include "mathops.h" +#include "vq.h" +#include "x86cpu.h" + + +#ifndef FIXED_POINT + +opus_val16 op_pvq_search_sse2(celt_norm *_X, int *iy, int K, int N, int arch) +{ + int i, j; + int pulsesLeft; + float xy, yy; + VARDECL(celt_norm, y); + VARDECL(celt_norm, X); + VARDECL(float, signy); + __m128 signmask; + __m128 sums; + __m128i fours; + SAVE_STACK; + + (void)arch; + /* All bits set to zero, except for the sign bit. */ + signmask = _mm_set_ps1(-0.f); + fours = _mm_set_epi32(4, 4, 4, 4); + ALLOC(y, N+3, celt_norm); + ALLOC(X, N+3, celt_norm); + ALLOC(signy, N+3, float); + + OPUS_COPY(X, _X, N); + X[N] = X[N+1] = X[N+2] = 0; + sums = _mm_setzero_ps(); + for (j=0;j (N>>1)) + { + __m128i pulses_sum; + __m128 yy4, xy4; + __m128 rcp4; + opus_val32 sum = _mm_cvtss_f32(sums); + /* If X is too small, just replace it with a pulse at 0 */ + /* Prevents infinities and NaNs from causing too many pulses + to be allocated. 64 is an approximation of infinity here. */ + if (!(sum > EPSILON && sum < 64)) + { + X[0] = QCONST16(1.f,14); + j=1; do + X[j]=0; + while (++j=0); + + /* This should never happen, but just in case it does (e.g. on silence) + we fill the first bin with pulses. */ + if (pulsesLeft > N+3) + { + opus_val16 tmp = (opus_val16)pulsesLeft; + yy = MAC16_16(yy, tmp, tmp); + yy = MAC16_16(yy, tmp, y[0]); + iy[0] += pulsesLeft; + pulsesLeft=0; + } + + for (i=0;i +static _inline void cpuid(unsigned int CPUInfo[4], unsigned int InfoType) +{ + __cpuid((int*)CPUInfo, InfoType); +} + +#else + +#if defined(CPU_INFO_BY_C) +#include +#endif + +static void cpuid(unsigned int CPUInfo[4], unsigned int InfoType) +{ +#if defined(CPU_INFO_BY_ASM) +#if defined(__i386__) && defined(__PIC__) +/* %ebx is PIC register in 32-bit, so mustn't clobber it. */ + __asm__ __volatile__ ( + "xchg %%ebx, %1\n" + "cpuid\n" + "xchg %%ebx, %1\n": + "=a" (CPUInfo[0]), + "=r" (CPUInfo[1]), + "=c" (CPUInfo[2]), + "=d" (CPUInfo[3]) : + "0" (InfoType) + ); +#else + __asm__ __volatile__ ( + "cpuid": + "=a" (CPUInfo[0]), + "=b" (CPUInfo[1]), + "=c" (CPUInfo[2]), + "=d" (CPUInfo[3]) : + "0" (InfoType) + ); +#endif +#elif defined(CPU_INFO_BY_C) + __get_cpuid(InfoType, &(CPUInfo[0]), &(CPUInfo[1]), &(CPUInfo[2]), &(CPUInfo[3])); +#endif +} + +#endif + +typedef struct CPU_Feature{ + /* SIMD: 128-bit */ + int HW_SSE; + int HW_SSE2; + int HW_SSE41; + /* SIMD: 256-bit */ + int HW_AVX; +} CPU_Feature; + +static void opus_cpu_feature_check(CPU_Feature *cpu_feature) +{ + unsigned int info[4] = {0}; + unsigned int nIds = 0; + + cpuid(info, 0); + nIds = info[0]; + + if (nIds >= 1){ + cpuid(info, 1); + cpu_feature->HW_SSE = (info[3] & (1 << 25)) != 0; + cpu_feature->HW_SSE2 = (info[3] & (1 << 26)) != 0; + cpu_feature->HW_SSE41 = (info[2] & (1 << 19)) != 0; + cpu_feature->HW_AVX = (info[2] & (1 << 28)) != 0; + } + else { + cpu_feature->HW_SSE = 0; + cpu_feature->HW_SSE2 = 0; + cpu_feature->HW_SSE41 = 0; + cpu_feature->HW_AVX = 0; + } +} + +int opus_select_arch(void) +{ + CPU_Feature cpu_feature; + int arch; + + opus_cpu_feature_check(&cpu_feature); + + arch = 0; + if (!cpu_feature.HW_SSE) + { + return arch; + } + arch++; + + if (!cpu_feature.HW_SSE2) + { + return arch; + } + arch++; + + if (!cpu_feature.HW_SSE41) + { + return arch; + } + arch++; + + if (!cpu_feature.HW_AVX) + { + return arch; + } + arch++; + + return arch; +} + +#endif diff --git a/extern/opus/celt/x86/x86cpu.h b/extern/opus/celt/x86/x86cpu.h new file mode 100644 index 0000000..1e2bf17 --- /dev/null +++ b/extern/opus/celt/x86/x86cpu.h @@ -0,0 +1,95 @@ +/* Copyright (c) 2014, Cisco Systems, INC + Written by XiangMingZhu WeiZhou MinPeng YanWang + + 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. + + 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 OWNER + 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. +*/ + +#if !defined(X86CPU_H) +# define X86CPU_H + +# if defined(OPUS_X86_MAY_HAVE_SSE) +# define MAY_HAVE_SSE(name) name ## _sse +# else +# define MAY_HAVE_SSE(name) name ## _c +# endif + +# if defined(OPUS_X86_MAY_HAVE_SSE2) +# define MAY_HAVE_SSE2(name) name ## _sse2 +# else +# define MAY_HAVE_SSE2(name) name ## _c +# endif + +# if defined(OPUS_X86_MAY_HAVE_SSE4_1) +# define MAY_HAVE_SSE4_1(name) name ## _sse4_1 +# else +# define MAY_HAVE_SSE4_1(name) name ## _c +# endif + +# if defined(OPUS_X86_MAY_HAVE_AVX) +# define MAY_HAVE_AVX(name) name ## _avx +# else +# define MAY_HAVE_AVX(name) name ## _c +# endif + +# if defined(OPUS_HAVE_RTCD) +int opus_select_arch(void); +# endif + +/*gcc appears to emit MOVDQA's to load the argument of an _mm_cvtepi8_epi32() + or _mm_cvtepi16_epi32() when optimizations are disabled, even though the + actual PMOVSXWD instruction takes an m32 or m64. Unlike a normal memory + reference, these require 16-byte alignment and load a full 16 bytes (instead + of 4 or 8), possibly reading out of bounds. + + We can insert an explicit MOVD or MOVQ using _mm_cvtsi32_si128() or + _mm_loadl_epi64(), which should have the same semantics as an m32 or m64 + reference in the PMOVSXWD instruction itself, but gcc is not smart enough to + optimize this out when optimizations ARE enabled. + + Clang, in contrast, requires us to do this always for _mm_cvtepi8_epi32 + (which is fair, since technically the compiler is always allowed to do the + dereference before invoking the function implementing the intrinsic). + However, it is smart enough to eliminate the extra MOVD instruction. + For _mm_cvtepi16_epi32, it does the right thing, though does *not* optimize out + the extra MOVQ if it's specified explicitly */ + +# if defined(__clang__) || !defined(__OPTIMIZE__) +# define OP_CVTEPI8_EPI32_M32(x) \ + (_mm_cvtepi8_epi32(_mm_cvtsi32_si128(*(int *)(x)))) +# else +# define OP_CVTEPI8_EPI32_M32(x) \ + (_mm_cvtepi8_epi32(*(__m128i *)(x))) +#endif + +/* similar reasoning about the instruction sequence as in the 32-bit macro above, + */ +# if defined(__clang__) || !defined(__OPTIMIZE__) +# define OP_CVTEPI16_EPI32_M64(x) \ + (_mm_cvtepi16_epi32(_mm_loadl_epi64((__m128i *)(x)))) +# else +# define OP_CVTEPI16_EPI32_M64(x) \ + (_mm_cvtepi16_epi32(*(__m128i *)(x))) +# endif + +#endif diff --git a/extern/opus/celt_headers.mk b/extern/opus/celt_headers.mk new file mode 100644 index 0000000..706185d --- /dev/null +++ b/extern/opus/celt_headers.mk @@ -0,0 +1,53 @@ +CELT_HEAD = \ +celt/arch.h \ +celt/bands.h \ +celt/celt.h \ +celt/cpu_support.h \ +include/opus_types.h \ +include/opus_defines.h \ +include/opus_custom.h \ +celt/cwrs.h \ +celt/ecintrin.h \ +celt/entcode.h \ +celt/entdec.h \ +celt/entenc.h \ +celt/fixed_debug.h \ +celt/fixed_generic.h \ +celt/float_cast.h \ +celt/_kiss_fft_guts.h \ +celt/kiss_fft.h \ +celt/laplace.h \ +celt/mathops.h \ +celt/mdct.h \ +celt/mfrngcod.h \ +celt/modes.h \ +celt/os_support.h \ +celt/pitch.h \ +celt/celt_lpc.h \ +celt/x86/celt_lpc_sse.h \ +celt/quant_bands.h \ +celt/rate.h \ +celt/stack_alloc.h \ +celt/vq.h \ +celt/static_modes_float.h \ +celt/static_modes_fixed.h \ +celt/static_modes_float_arm_ne10.h \ +celt/static_modes_fixed_arm_ne10.h \ +celt/arm/armcpu.h \ +celt/arm/fixed_armv4.h \ +celt/arm/fixed_armv5e.h \ +celt/arm/fixed_arm64.h \ +celt/arm/kiss_fft_armv4.h \ +celt/arm/kiss_fft_armv5e.h \ +celt/arm/pitch_arm.h \ +celt/arm/fft_arm.h \ +celt/arm/mdct_arm.h \ +celt/mips/celt_mipsr1.h \ +celt/mips/fixed_generic_mipsr1.h \ +celt/mips/kiss_fft_mipsr1.h \ +celt/mips/mdct_mipsr1.h \ +celt/mips/pitch_mipsr1.h \ +celt/mips/vq_mipsr1.h \ +celt/x86/pitch_sse.h \ +celt/x86/vq_sse.h \ +celt/x86/x86cpu.h diff --git a/extern/opus/celt_sources.mk b/extern/opus/celt_sources.mk new file mode 100644 index 0000000..c9dab06 --- /dev/null +++ b/extern/opus/celt_sources.mk @@ -0,0 +1,50 @@ +CELT_SOURCES = \ +celt/bands.c \ +celt/celt.c \ +celt/celt_encoder.c \ +celt/celt_decoder.c \ +celt/cwrs.c \ +celt/entcode.c \ +celt/entdec.c \ +celt/entenc.c \ +celt/kiss_fft.c \ +celt/laplace.c \ +celt/mathops.c \ +celt/mdct.c \ +celt/modes.c \ +celt/pitch.c \ +celt/celt_lpc.c \ +celt/quant_bands.c \ +celt/rate.c \ +celt/vq.c + +CELT_SOURCES_SSE = \ +celt/x86/x86cpu.c \ +celt/x86/x86_celt_map.c \ +celt/x86/pitch_sse.c + +CELT_SOURCES_SSE2 = \ +celt/x86/pitch_sse2.c \ +celt/x86/vq_sse2.c + +CELT_SOURCES_SSE4_1 = \ +celt/x86/celt_lpc_sse4_1.c \ +celt/x86/pitch_sse4_1.c + +CELT_SOURCES_ARM = \ +celt/arm/armcpu.c \ +celt/arm/arm_celt_map.c + +CELT_SOURCES_ARM_ASM = \ +celt/arm/celt_pitch_xcorr_arm.s + +CELT_AM_SOURCES_ARM_ASM = \ +celt/arm/armopts.s.in + +CELT_SOURCES_ARM_NEON_INTR = \ +celt/arm/celt_neon_intr.c \ +celt/arm/pitch_neon_intr.c + +CELT_SOURCES_ARM_NE10 = \ +celt/arm/celt_fft_ne10.c \ +celt/arm/celt_mdct_ne10.c diff --git a/extern/opus/config.h.cmake.in b/extern/opus/config.h.cmake.in new file mode 100644 index 0000000..5550842 --- /dev/null +++ b/extern/opus/config.h.cmake.in @@ -0,0 +1 @@ +#cmakedefine PACKAGE_VERSION "@PACKAGE_VERSION@" \ No newline at end of file diff --git a/extern/opus/configure.ac b/extern/opus/configure.ac new file mode 100644 index 0000000..18ece29 --- /dev/null +++ b/extern/opus/configure.ac @@ -0,0 +1,933 @@ +dnl Process this file with autoconf to produce a configure script. -*-m4-*- + +dnl The package_version file will be automatically synced to the git revision +dnl by the update_version script when configured in the repository, but will +dnl remain constant in tarball releases unless it is manually edited. +m4_define([CURRENT_VERSION], + m4_esyscmd([ ./update_version 2>/dev/null || true + if test -e package_version; then + . ./package_version + printf "$PACKAGE_VERSION" + else + printf "unknown" + fi ])) + +AC_INIT([opus],[CURRENT_VERSION],[opus@xiph.org]) + +AC_CONFIG_SRCDIR(src/opus_encoder.c) +AC_CONFIG_MACRO_DIR([m4]) + +dnl enable silent rules on automake 1.11 and later +m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) + +# For libtool. +dnl Please update these for releases. +OPUS_LT_CURRENT=8 +OPUS_LT_REVISION=0 +OPUS_LT_AGE=8 + +AC_SUBST(OPUS_LT_CURRENT) +AC_SUBST(OPUS_LT_REVISION) +AC_SUBST(OPUS_LT_AGE) + +AM_INIT_AUTOMAKE([no-define]) +AM_MAINTAINER_MODE([enable]) + +AC_CANONICAL_HOST +AC_MINGW32 +AM_PROG_LIBTOOL +AM_PROG_CC_C_O + +AC_PROG_CC_C99 +AC_C_CONST +AC_C_INLINE + +AM_PROG_AS + +AC_DEFINE([OPUS_BUILD], [], [This is a build of OPUS]) + +#Use a hacked up version of autoconf's AC_C_RESTRICT because it's not +#strong enough a test to detect old buggy versions of GCC (e.g. 2.95.3) +#Note: Both this and the test for variable-size arrays below are also +# done by AC_PROG_CC_C99, but not thoroughly enough apparently. +AC_CACHE_CHECK([for C/C++ restrict keyword], ac_cv_c_restrict, + [ac_cv_c_restrict=no + # The order here caters to the fact that C++ does not require restrict. + for ac_kw in __restrict __restrict__ _Restrict restrict; do + AC_COMPILE_IFELSE([AC_LANG_PROGRAM( + [[typedef int * int_ptr; + int foo (int_ptr $ac_kw ip, int * $ac_kw baz[]) { + return ip[0]; + }]], + [[int s[1]; + int * $ac_kw t = s; + t[0] = 0; + return foo(t, (void *)0)]])], + [ac_cv_c_restrict=$ac_kw]) + test "$ac_cv_c_restrict" != no && break + done + ]) + +AH_VERBATIM([restrict], +[/* Define to the equivalent of the C99 'restrict' keyword, or to + nothing if this is not supported. Do not define if restrict is + supported directly. */ +#undef restrict +/* Work around a bug in Sun C++: it does not support _Restrict or + __restrict__, even though the corresponding Sun C compiler ends up with + "#define restrict _Restrict" or "#define restrict __restrict__" in the + previous line. Perhaps some future version of Sun C++ will work with + restrict; if so, hopefully it defines __RESTRICT like Sun C does. */ +#if defined __SUNPRO_CC && !defined __RESTRICT +# define _Restrict +# define __restrict__ +#endif]) + +case $ac_cv_c_restrict in + restrict) ;; + no) AC_DEFINE([restrict], []) ;; + *) AC_DEFINE_UNQUOTED([restrict], [$ac_cv_c_restrict]) ;; +esac + +AC_MSG_CHECKING(for C99 variable-size arrays) +AC_COMPILE_IFELSE([AC_LANG_PROGRAM([], + [[static int x; char a[++x]; a[sizeof a - 1] = 0; int N; return a[0];]])], + [ has_var_arrays=yes + use_alloca="no (using var arrays)" + AC_DEFINE([VAR_ARRAYS], [1], [Use C99 variable-size arrays]) + ],[ + has_var_arrays=no + ]) +AC_MSG_RESULT([$has_var_arrays]) + +AS_IF([test "$has_var_arrays" = "no"], + [ + AC_CHECK_HEADERS([alloca.h]) + AC_MSG_CHECKING(for alloca) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], + [[int foo=10; int *array = alloca(foo);]])], + [ use_alloca=yes; + AC_DEFINE([USE_ALLOCA], [], [Make use of alloca]) + ],[ + use_alloca=no + ]) + AC_MSG_RESULT([$use_alloca]) + ]) + +LT_LIB_M + +AC_ARG_ENABLE([fixed-point], + [AS_HELP_STRING([--enable-fixed-point], + [compile without floating point (for machines without a fast enough FPU)])],, + [enable_fixed_point=no]) + +AS_IF([test "$enable_fixed_point" = "yes"],[ + enable_float="no" + AC_DEFINE([FIXED_POINT], [1], [Compile as fixed-point (for machines without a fast enough FPU)]) + PC_BUILD="fixed-point" +],[ + enable_float="yes"; + PC_BUILD="floating-point" +]) + +AM_CONDITIONAL([FIXED_POINT], [test "$enable_fixed_point" = "yes"]) + +AC_ARG_ENABLE([fixed-point-debug], + [AS_HELP_STRING([--enable-fixed-point-debug], [debug fixed-point implementation])],, + [enable_fixed_point_debug=no]) + +AS_IF([test "$enable_fixed_point_debug" = "yes"],[ + AC_DEFINE([FIXED_DEBUG], [1], [Debug fixed-point implementation]) +]) + +AC_ARG_ENABLE([float_api], + [AS_HELP_STRING([--disable-float-api], + [compile without the floating point API (for machines with no float library)])],, + [enable_float_api=yes]) + +AM_CONDITIONAL([DISABLE_FLOAT_API], [test "$enable_float_api" = "no"]) + +AS_IF([test "$enable_float_api" = "no"],[ + AC_DEFINE([DISABLE_FLOAT_API], [1], [Do not build the float API]) +]) + +AC_ARG_ENABLE([custom-modes], + [AS_HELP_STRING([--enable-custom-modes], [enable non-Opus modes, e.g. 44.1 kHz & 2^n frames])],, + [enable_custom_modes=no]) + +AS_IF([test "$enable_custom_modes" = "yes"],[ + AC_DEFINE([CUSTOM_MODES], [1], [Custom modes]) + PC_BUILD="$PC_BUILD, custom modes" +]) + +AM_CONDITIONAL([CUSTOM_MODES], [test "$enable_custom_modes" = "yes"]) + +has_float_approx=no +#case "$host_cpu" in +#i[[3456]]86 | x86_64 | powerpc64 | powerpc32 | ia64) +# has_float_approx=yes +# ;; +#esac + +AC_ARG_ENABLE([float-approx], + [AS_HELP_STRING([--enable-float-approx], [enable fast approximations for floating point])], + [if test "$enable_float_approx" = "yes"; then + AC_WARN([Floating point approximations are not supported on all platforms.]) + fi + ], + [enable_float_approx=$has_float_approx]) + +AS_IF([test "$enable_float_approx" = "yes"],[ + AC_DEFINE([FLOAT_APPROX], [1], [Float approximations]) +]) + +AC_ARG_ENABLE([asm], + [AS_HELP_STRING([--disable-asm], [Disable assembly optimizations])],, + [enable_asm=yes]) + +AC_ARG_ENABLE([rtcd], + [AS_HELP_STRING([--disable-rtcd], [Disable run-time CPU capabilities detection])],, + [enable_rtcd=yes]) + +AC_ARG_ENABLE([intrinsics], + [AS_HELP_STRING([--disable-intrinsics], [Disable intrinsics optimizations])],, + [enable_intrinsics=yes]) + +rtcd_support=no +cpu_arm=no + +AS_IF([test x"${enable_asm}" = x"yes"],[ + inline_optimization="No inline ASM for your platform, please send patches" + case $host_cpu in + arm*) + dnl Currently we only have asm for fixed-point + AS_IF([test "$enable_float" != "yes"],[ + cpu_arm=yes + AC_DEFINE([OPUS_ARM_ASM], [], [Make use of ARM asm optimization]) + AS_GCC_INLINE_ASSEMBLY( + [inline_optimization="ARM"], + [inline_optimization="disabled"] + ) + AS_ASM_ARM_EDSP([OPUS_ARM_INLINE_EDSP=1],[OPUS_ARM_INLINE_EDSP=0]) + AS_ASM_ARM_MEDIA([OPUS_ARM_INLINE_MEDIA=1], + [OPUS_ARM_INLINE_MEDIA=0]) + AS_ASM_ARM_NEON([OPUS_ARM_INLINE_NEON=1],[OPUS_ARM_INLINE_NEON=0]) + AS_IF([test x"$inline_optimization" = x"ARM"],[ + AM_CONDITIONAL([OPUS_ARM_INLINE_ASM],[true]) + AC_DEFINE([OPUS_ARM_INLINE_ASM], 1, + [Use generic ARMv4 inline asm optimizations]) + AS_IF([test x"$OPUS_ARM_INLINE_EDSP" = x"1"],[ + AC_DEFINE([OPUS_ARM_INLINE_EDSP], [1], + [Use ARMv5E inline asm optimizations]) + inline_optimization="$inline_optimization (EDSP)" + ]) + AS_IF([test x"$OPUS_ARM_INLINE_MEDIA" = x"1"],[ + AC_DEFINE([OPUS_ARM_INLINE_MEDIA], [1], + [Use ARMv6 inline asm optimizations]) + inline_optimization="$inline_optimization (Media)" + ]) + AS_IF([test x"$OPUS_ARM_INLINE_NEON" = x"1"],[ + AC_DEFINE([OPUS_ARM_INLINE_NEON], 1, + [Use ARM NEON inline asm optimizations]) + inline_optimization="$inline_optimization (NEON)" + ]) + ]) + dnl We need Perl to translate RVCT-syntax asm to gas syntax. + AC_CHECK_PROG([HAVE_PERL], perl, yes, no) + AS_IF([test x"$HAVE_PERL" = x"yes"],[ + AM_CONDITIONAL([OPUS_ARM_EXTERNAL_ASM],[true]) + asm_optimization="ARM" + AS_IF([test x"$OPUS_ARM_INLINE_EDSP" = x"1"], [ + OPUS_ARM_PRESUME_EDSP=1 + OPUS_ARM_MAY_HAVE_EDSP=1 + ], + [ + OPUS_ARM_PRESUME_EDSP=0 + OPUS_ARM_MAY_HAVE_EDSP=0 + ]) + AS_IF([test x"$OPUS_ARM_INLINE_MEDIA" = x"1"], [ + OPUS_ARM_PRESUME_MEDIA=1 + OPUS_ARM_MAY_HAVE_MEDIA=1 + ], + [ + OPUS_ARM_PRESUME_MEDIA=0 + OPUS_ARM_MAY_HAVE_MEDIA=0 + ]) + AS_IF([test x"$OPUS_ARM_INLINE_NEON" = x"1"], [ + OPUS_ARM_PRESUME_NEON=1 + OPUS_ARM_MAY_HAVE_NEON=1 + ], + [ + OPUS_ARM_PRESUME_NEON=0 + OPUS_ARM_MAY_HAVE_NEON=0 + ]) + AS_IF([test x"$enable_rtcd" = x"yes"],[ + AS_IF([test x"$OPUS_ARM_MAY_HAVE_EDSP" != x"1"],[ + AC_MSG_NOTICE( + [Trying to force-enable armv5e EDSP instructions...]) + AS_ASM_ARM_EDSP_FORCE([OPUS_ARM_MAY_HAVE_EDSP=1]) + ]) + AS_IF([test x"$OPUS_ARM_MAY_HAVE_MEDIA" != x"1"],[ + AC_MSG_NOTICE( + [Trying to force-enable ARMv6 media instructions...]) + AS_ASM_ARM_MEDIA_FORCE([OPUS_ARM_MAY_HAVE_MEDIA=1]) + ]) + AS_IF([test x"$OPUS_ARM_MAY_HAVE_NEON" != x"1"],[ + AC_MSG_NOTICE( + [Trying to force-enable NEON instructions...]) + AS_ASM_ARM_NEON_FORCE([OPUS_ARM_MAY_HAVE_NEON=1]) + ]) + ]) + rtcd_support= + AS_IF([test x"$OPUS_ARM_MAY_HAVE_EDSP" = x"1"],[ + AC_DEFINE(OPUS_ARM_MAY_HAVE_EDSP, 1, + [Define if assembler supports EDSP instructions]) + AS_IF([test x"$OPUS_ARM_PRESUME_EDSP" = x"1"],[ + AC_DEFINE(OPUS_ARM_PRESUME_EDSP, 1, + [Define if binary requires EDSP instruction support]) + asm_optimization="$asm_optimization (EDSP)" + ], + [rtcd_support="$rtcd_support (EDSP)"] + ) + ]) + AC_SUBST(OPUS_ARM_MAY_HAVE_EDSP) + AS_IF([test x"$OPUS_ARM_MAY_HAVE_MEDIA" = x"1"],[ + AC_DEFINE(OPUS_ARM_MAY_HAVE_MEDIA, 1, + [Define if assembler supports ARMv6 media instructions]) + AS_IF([test x"$OPUS_ARM_PRESUME_MEDIA" = x"1"],[ + AC_DEFINE(OPUS_ARM_PRESUME_MEDIA, 1, + [Define if binary requires ARMv6 media instruction support]) + asm_optimization="$asm_optimization (Media)" + ], + [rtcd_support="$rtcd_support (Media)"] + ) + ]) + AC_SUBST(OPUS_ARM_MAY_HAVE_MEDIA) + AS_IF([test x"$OPUS_ARM_MAY_HAVE_NEON" = x"1"],[ + AC_DEFINE(OPUS_ARM_MAY_HAVE_NEON, 1, + [Define if compiler supports NEON instructions]) + AS_IF([test x"$OPUS_ARM_PRESUME_NEON" = x"1"], [ + AC_DEFINE(OPUS_ARM_PRESUME_NEON, 1, + [Define if binary requires NEON instruction support]) + asm_optimization="$asm_optimization (NEON)" + ], + [rtcd_support="$rtcd_support (NEON)"] + ) + ]) + AC_SUBST(OPUS_ARM_MAY_HAVE_NEON) + dnl Make sure turning on RTCD gets us at least one + dnl instruction set. + AS_IF([test x"$rtcd_support" != x""], + [rtcd_support=ARM"$rtcd_support"], + [rtcd_support="no"] + ) + AC_MSG_CHECKING([for apple style tools]) + AC_PREPROC_IFELSE([AC_LANG_PROGRAM([ +#ifndef __APPLE__ +#error 1 +#endif],[])], + [AC_MSG_RESULT([yes]); ARM2GNU_PARAMS="--apple"], + [AC_MSG_RESULT([no]); ARM2GNU_PARAMS=""]) + AC_SUBST(ARM2GNU_PARAMS) + ], + [ + AC_MSG_WARN( + [*** ARM assembly requires perl -- disabling optimizations]) + asm_optimization="(missing perl dependency for ARM)" + ]) + ]) + ;; + esac +],[ + inline_optimization="disabled" + asm_optimization="disabled" +]) + +AM_CONDITIONAL([OPUS_ARM_INLINE_ASM], + [test x"${inline_optimization%% *}" = x"ARM"]) +AM_CONDITIONAL([OPUS_ARM_EXTERNAL_ASM], + [test x"${asm_optimization%% *}" = x"ARM"]) + +AM_CONDITIONAL([HAVE_SSE], [false]) +AM_CONDITIONAL([HAVE_SSE2], [false]) +AM_CONDITIONAL([HAVE_SSE4_1], [false]) +AM_CONDITIONAL([HAVE_AVX], [false]) + +m4_define([DEFAULT_X86_SSE_CFLAGS], [-msse]) +m4_define([DEFAULT_X86_SSE2_CFLAGS], [-msse2]) +m4_define([DEFAULT_X86_SSE4_1_CFLAGS], [-msse4.1]) +m4_define([DEFAULT_X86_AVX_CFLAGS], [-mavx]) +m4_define([DEFAULT_ARM_NEON_INTR_CFLAGS], [-mfpu=neon]) +# With GCC on ARM32 softfp architectures (e.g. Android, or older Ubuntu) you need to specify +# -mfloat-abi=softfp for -mfpu=neon to work. However, on ARM32 hardfp architectures (e.g. newer Ubuntu), +# this option will break things. + +# As a heuristic, if host matches arm*eabi* but not arm*hf*, it's probably soft-float. +m4_define([DEFAULT_ARM_NEON_SOFTFP_INTR_CFLAGS], [-mfpu=neon -mfloat-abi=softfp]) + +AS_CASE([$host], + [arm*hf*], [AS_VAR_SET([RESOLVED_DEFAULT_ARM_NEON_INTR_CFLAGS], "DEFAULT_ARM_NEON_INTR_CFLAGS")], + [arm*eabi*], [AS_VAR_SET([RESOLVED_DEFAULT_ARM_NEON_INTR_CFLAGS], "DEFAULT_ARM_NEON_SOFTFP_INTR_CFLAGS")], + [AS_VAR_SET([RESOLVED_DEFAULT_ARM_NEON_INTR_CFLAGS], "DEFAULT_ARM_NEON_INTR_CFLAGS")]) + +AC_ARG_VAR([X86_SSE_CFLAGS], [C compiler flags to compile SSE intrinsics @<:@default=]DEFAULT_X86_SSE_CFLAGS[@:>@]) +AC_ARG_VAR([X86_SSE2_CFLAGS], [C compiler flags to compile SSE2 intrinsics @<:@default=]DEFAULT_X86_SSE2_CFLAGS[@:>@]) +AC_ARG_VAR([X86_SSE4_1_CFLAGS], [C compiler flags to compile SSE4.1 intrinsics @<:@default=]DEFAULT_X86_SSE4_1_CFLAGS[@:>@]) +AC_ARG_VAR([X86_AVX_CFLAGS], [C compiler flags to compile AVX intrinsics @<:@default=]DEFAULT_X86_AVX_CFLAGS[@:>@]) +AC_ARG_VAR([ARM_NEON_INTR_CFLAGS], [C compiler flags to compile ARM NEON intrinsics @<:@default=]DEFAULT_ARM_NEON_INTR_CFLAGS / DEFAULT_ARM_NEON_SOFTFP_INTR_CFLAGS[@:>@]) + +AS_VAR_SET_IF([X86_SSE_CFLAGS], [], [AS_VAR_SET([X86_SSE_CFLAGS], "DEFAULT_X86_SSE_CFLAGS")]) +AS_VAR_SET_IF([X86_SSE2_CFLAGS], [], [AS_VAR_SET([X86_SSE2_CFLAGS], "DEFAULT_X86_SSE2_CFLAGS")]) +AS_VAR_SET_IF([X86_SSE4_1_CFLAGS], [], [AS_VAR_SET([X86_SSE4_1_CFLAGS], "DEFAULT_X86_SSE4_1_CFLAGS")]) +AS_VAR_SET_IF([X86_AVX_CFLAGS], [], [AS_VAR_SET([X86_AVX_CFLAGS], "DEFAULT_X86_AVX_CFLAGS")]) +AS_VAR_SET_IF([ARM_NEON_INTR_CFLAGS], [], [AS_VAR_SET([ARM_NEON_INTR_CFLAGS], ["$RESOLVED_DEFAULT_ARM_NEON_INTR_CFLAGS"])]) + +AC_DEFUN([OPUS_PATH_NE10], + [ + AC_ARG_WITH(NE10, + AC_HELP_STRING([--with-NE10=PFX],[Prefix where libNE10 is installed (optional)]), + NE10_prefix="$withval", NE10_prefix="") + AC_ARG_WITH(NE10-libraries, + AC_HELP_STRING([--with-NE10-libraries=DIR], + [Directory where libNE10 library is installed (optional)]), + NE10_libraries="$withval", NE10_libraries="") + AC_ARG_WITH(NE10-includes, + AC_HELP_STRING([--with-NE10-includes=DIR], + [Directory where libNE10 header files are installed (optional)]), + NE10_includes="$withval", NE10_includes="") + + if test "x$NE10_libraries" != "x" ; then + NE10_LIBS="-L$NE10_libraries" + elif test "x$NE10_prefix" = "xno" || test "x$NE10_prefix" = "xyes" ; then + NE10_LIBS="" + elif test "x$NE10_prefix" != "x" ; then + NE10_LIBS="-L$NE10_prefix/lib" + elif test "x$prefix" != "xNONE" ; then + NE10_LIBS="-L$prefix/lib" + fi + + if test "x$NE10_prefix" != "xno" ; then + NE10_LIBS="$NE10_LIBS -lNE10" + fi + + if test "x$NE10_includes" != "x" ; then + NE10_CFLAGS="-I$NE10_includes" + elif test "x$NE10_prefix" = "xno" || test "x$NE10_prefix" = "xyes" ; then + NE10_CFLAGS="" + elif test "x$NE10_prefix" != "x" ; then + NE10_CFLAGS="-I$NE10_prefix/include" + elif test "x$prefix" != "xNONE"; then + NE10_CFLAGS="-I$prefix/include" + fi + + AC_MSG_CHECKING(for NE10) + save_CFLAGS="$CFLAGS"; CFLAGS="$CFLAGS $NE10_CFLAGS" + save_LIBS="$LIBS"; LIBS="$LIBS $NE10_LIBS $LIBM" + AC_LINK_IFELSE( + [ + AC_LANG_PROGRAM( + [[#include + ]], + [[ + ne10_fft_cfg_float32_t cfg; + cfg = ne10_fft_alloc_c2c_float32_neon(480); + ]] + ) + ],[ + HAVE_ARM_NE10=1 + AC_MSG_RESULT([yes]) + ],[ + HAVE_ARM_NE10=0 + AC_MSG_RESULT([no]) + NE10_CFLAGS="" + NE10_LIBS="" + ] + ) + CFLAGS="$save_CFLAGS"; LIBS="$save_LIBS" + #Now we know if libNE10 is installed or not + AS_IF([test x"$HAVE_ARM_NE10" = x"1"], + [ + AC_DEFINE([HAVE_ARM_NE10], 1, [NE10 library is installed on host. Make sure it is on target!]) + AC_SUBST(HAVE_ARM_NE10) + AC_SUBST(NE10_CFLAGS) + AC_SUBST(NE10_LIBS) + ] + ) + ] +) + +AS_IF([test x"$enable_intrinsics" = x"yes"],[ + intrinsics_support="" + AS_CASE([$host_cpu], + [arm*|aarch64*], + [ + cpu_arm=yes + OPUS_CHECK_INTRINSICS( + [ARM Neon], + [$ARM_NEON_INTR_CFLAGS], + [OPUS_ARM_MAY_HAVE_NEON_INTR], + [OPUS_ARM_PRESUME_NEON_INTR], + [[#include + ]], + [[ + static float32x4_t A0, A1, SUMM; + SUMM = vmlaq_f32(SUMM, A0, A1); + return (int)vgetq_lane_f32(SUMM, 0); + ]] + ) + AS_IF([test x"$OPUS_ARM_MAY_HAVE_NEON_INTR" = x"1" && test x"$OPUS_ARM_PRESUME_NEON_INTR" != x"1"], + [ + OPUS_ARM_NEON_INTR_CFLAGS="$ARM_NEON_INTR_CFLAGS" + AC_SUBST([OPUS_ARM_NEON_INTR_CFLAGS]) + ] + ) + + AS_IF([test x"$OPUS_ARM_MAY_HAVE_NEON_INTR" = x"1"], + [ + AC_DEFINE([OPUS_ARM_MAY_HAVE_NEON_INTR], 1, [Compiler supports ARMv7/Aarch64 Neon Intrinsics]) + intrinsics_support="$intrinsics_support (NEON)" + + AS_IF([test x"$enable_rtcd" != x"no" && test x"$OPUS_ARM_PRESUME_NEON_INTR" != x"1"], + [AS_IF([test x"$rtcd_support" = x"no"], + [rtcd_support="ARM (NEON Intrinsics)"], + [rtcd_support="$rtcd_support (NEON Intrinsics)"])]) + + AS_IF([test x"$OPUS_ARM_PRESUME_NEON_INTR" = x"1"], + [AC_DEFINE([OPUS_ARM_PRESUME_NEON_INTR], 1, [Define if binary requires NEON intrinsics support])]) + + OPUS_PATH_NE10() + AS_IF([test x"$NE10_LIBS" != x""], + [ + intrinsics_support="$intrinsics_support (NE10)" + AS_IF([test x"enable_rtcd" != x"" \ + && test x"$OPUS_ARM_PRESUME_NEON_INTR" != x"1"], + [rtcd_support="$rtcd_support (NE10)"]) + ]) + + OPUS_CHECK_INTRINSICS( + [Aarch64 Neon], + [$ARM_NEON_INTR_CFLAGS], + [OPUS_ARM_MAY_HAVE_AARCH64_NEON_INTR], + [OPUS_ARM_PRESUME_AARCH64_NEON_INTR], + [[#include + ]], + [[ + static int32_t IN; + static int16_t OUT; + OUT = vqmovns_s32(IN); + ]] + ) + + AS_IF([test x"$OPUS_ARM_PRESUME_AARCH64_NEON_INTR" = x"1"], + [ + AC_DEFINE([OPUS_ARM_PRESUME_AARCH64_NEON_INTR], 1, [Define if binary requires Aarch64 Neon Intrinsics]) + intrinsics_support="$intrinsics_support (NEON [Aarch64])" + ]) + + AS_IF([test x"$intrinsics_support" = x""], + [intrinsics_support=no], + [intrinsics_support="ARM$intrinsics_support"]) + ], + [ + AC_MSG_WARN([Compiler does not support ARM intrinsics]) + intrinsics_support=no + ]) + ], + [i?86|x86_64], + [ + OPUS_CHECK_INTRINSICS( + [SSE], + [$X86_SSE_CFLAGS], + [OPUS_X86_MAY_HAVE_SSE], + [OPUS_X86_PRESUME_SSE], + [[#include + #include + ]], + [[ + __m128 mtest; + mtest = _mm_set1_ps((float)time(NULL)); + mtest = _mm_mul_ps(mtest, mtest); + return _mm_cvtss_si32(mtest); + ]] + ) + AS_IF([test x"$OPUS_X86_MAY_HAVE_SSE" = x"1" && test x"$OPUS_X86_PRESUME_SSE" != x"1"], + [ + OPUS_X86_SSE_CFLAGS="$X86_SSE_CFLAGS" + AC_SUBST([OPUS_X86_SSE_CFLAGS]) + ] + ) + OPUS_CHECK_INTRINSICS( + [SSE2], + [$X86_SSE2_CFLAGS], + [OPUS_X86_MAY_HAVE_SSE2], + [OPUS_X86_PRESUME_SSE2], + [[#include + #include + ]], + [[ + __m128i mtest; + mtest = _mm_set1_epi32((int)time(NULL)); + mtest = _mm_mul_epu32(mtest, mtest); + return _mm_cvtsi128_si32(mtest); + ]] + ) + AS_IF([test x"$OPUS_X86_MAY_HAVE_SSE2" = x"1" && test x"$OPUS_X86_PRESUME_SSE2" != x"1"], + [ + OPUS_X86_SSE2_CFLAGS="$X86_SSE2_CFLAGS" + AC_SUBST([OPUS_X86_SSE2_CFLAGS]) + ] + ) + OPUS_CHECK_INTRINSICS( + [SSE4.1], + [$X86_SSE4_1_CFLAGS], + [OPUS_X86_MAY_HAVE_SSE4_1], + [OPUS_X86_PRESUME_SSE4_1], + [[#include + #include + ]], + [[ + __m128i mtest; + mtest = _mm_set1_epi32((int)time(NULL)); + mtest = _mm_mul_epi32(mtest, mtest); + return _mm_cvtsi128_si32(mtest); + ]] + ) + AS_IF([test x"$OPUS_X86_MAY_HAVE_SSE4_1" = x"1" && test x"$OPUS_X86_PRESUME_SSE4_1" != x"1"], + [ + OPUS_X86_SSE4_1_CFLAGS="$X86_SSE4_1_CFLAGS" + AC_SUBST([OPUS_X86_SSE4_1_CFLAGS]) + ] + ) + OPUS_CHECK_INTRINSICS( + [AVX], + [$X86_AVX_CFLAGS], + [OPUS_X86_MAY_HAVE_AVX], + [OPUS_X86_PRESUME_AVX], + [[#include + #include + ]], + [[ + __m256 mtest; + mtest = _mm256_set1_ps((float)time(NULL)); + mtest = _mm256_addsub_ps(mtest, mtest); + return _mm_cvtss_si32(_mm256_extractf128_ps(mtest, 0)); + ]] + ) + AS_IF([test x"$OPUS_X86_MAY_HAVE_AVX" = x"1" && test x"$OPUS_X86_PRESUME_AVX" != x"1"], + [ + OPUS_X86_AVX_CFLAGS="$X86_AVX_CFLAGS" + AC_SUBST([OPUS_X86_AVX_CFLAGS]) + ] + ) + AS_IF([test x"$rtcd_support" = x"no"], [rtcd_support=""]) + AS_IF([test x"$OPUS_X86_MAY_HAVE_SSE" = x"1"], + [ + AC_DEFINE([OPUS_X86_MAY_HAVE_SSE], 1, [Compiler supports X86 SSE Intrinsics]) + intrinsics_support="$intrinsics_support SSE" + + AS_IF([test x"$OPUS_X86_PRESUME_SSE" = x"1"], + [AC_DEFINE([OPUS_X86_PRESUME_SSE], 1, [Define if binary requires SSE intrinsics support])], + [rtcd_support="$rtcd_support SSE"]) + ], + [ + AC_MSG_WARN([Compiler does not support SSE intrinsics]) + ]) + + AS_IF([test x"$OPUS_X86_MAY_HAVE_SSE2" = x"1"], + [ + AC_DEFINE([OPUS_X86_MAY_HAVE_SSE2], 1, [Compiler supports X86 SSE2 Intrinsics]) + intrinsics_support="$intrinsics_support SSE2" + + AS_IF([test x"$OPUS_X86_PRESUME_SSE2" = x"1"], + [AC_DEFINE([OPUS_X86_PRESUME_SSE2], 1, [Define if binary requires SSE2 intrinsics support])], + [rtcd_support="$rtcd_support SSE2"]) + ], + [ + AC_MSG_WARN([Compiler does not support SSE2 intrinsics]) + ]) + + AS_IF([test x"$OPUS_X86_MAY_HAVE_SSE4_1" = x"1"], + [ + AC_DEFINE([OPUS_X86_MAY_HAVE_SSE4_1], 1, [Compiler supports X86 SSE4.1 Intrinsics]) + intrinsics_support="$intrinsics_support SSE4.1" + + AS_IF([test x"$OPUS_X86_PRESUME_SSE4_1" = x"1"], + [AC_DEFINE([OPUS_X86_PRESUME_SSE4_1], 1, [Define if binary requires SSE4.1 intrinsics support])], + [rtcd_support="$rtcd_support SSE4.1"]) + ], + [ + AC_MSG_WARN([Compiler does not support SSE4.1 intrinsics]) + ]) + AS_IF([test x"$OPUS_X86_MAY_HAVE_AVX" = x"1"], + [ + AC_DEFINE([OPUS_X86_MAY_HAVE_AVX], 1, [Compiler supports X86 AVX Intrinsics]) + intrinsics_support="$intrinsics_support AVX" + + AS_IF([test x"$OPUS_X86_PRESUME_AVX" = x"1"], + [AC_DEFINE([OPUS_X86_PRESUME_AVX], 1, [Define if binary requires AVX intrinsics support])], + [rtcd_support="$rtcd_support AVX"]) + ], + [ + AC_MSG_WARN([Compiler does not support AVX intrinsics]) + ]) + + AS_IF([test x"$intrinsics_support" = x""], + [intrinsics_support=no], + [intrinsics_support="x86$intrinsics_support"] + ) + AS_IF([test x"$rtcd_support" = x""], + [rtcd_support=no], + [rtcd_support="x86$rtcd_support"], + ) + + AS_IF([test x"$enable_rtcd" = x"yes" && test x"$rtcd_support" != x""],[ + get_cpuid_by_asm="no" + AC_MSG_CHECKING([How to get X86 CPU Info]) + AC_LINK_IFELSE([AC_LANG_PROGRAM([[ + #include + ]],[[ + unsigned int CPUInfo0; + unsigned int CPUInfo1; + unsigned int CPUInfo2; + unsigned int CPUInfo3; + unsigned int InfoType; + __asm__ __volatile__ ( + "cpuid": + "=a" (CPUInfo0), + "=b" (CPUInfo1), + "=c" (CPUInfo2), + "=d" (CPUInfo3) : + "a" (InfoType), "c" (0) + ); + ]])], + [get_cpuid_by_asm="yes" + AC_MSG_RESULT([Inline Assembly]) + AC_DEFINE([CPU_INFO_BY_ASM], [1], [Get CPU Info by asm method])], + [AC_LINK_IFELSE([AC_LANG_PROGRAM([[ + #include + ]],[[ + unsigned int CPUInfo0; + unsigned int CPUInfo1; + unsigned int CPUInfo2; + unsigned int CPUInfo3; + unsigned int InfoType; + __get_cpuid(InfoType, &CPUInfo0, &CPUInfo1, &CPUInfo2, &CPUInfo3); + ]])], + [AC_MSG_RESULT([C method]) + AC_DEFINE([CPU_INFO_BY_C], [1], [Get CPU Info by c method])], + [AC_MSG_ERROR([no supported Get CPU Info method, please disable run-time CPU capabilities detection or intrinsics])])])]) + ], + [ + AC_MSG_WARN([No intrinsics support for your architecture]) + intrinsics_support="no" + ]) +], +[ + intrinsics_support="no" +]) + +AM_CONDITIONAL([CPU_ARM], [test "$cpu_arm" = "yes"]) +AM_CONDITIONAL([HAVE_ARM_NEON_INTR], + [test x"$OPUS_ARM_MAY_HAVE_NEON_INTR" = x"1"]) +AM_CONDITIONAL([HAVE_ARM_NE10], + [test x"$HAVE_ARM_NE10" = x"1"]) +AM_CONDITIONAL([HAVE_SSE], + [test x"$OPUS_X86_MAY_HAVE_SSE" = x"1"]) +AM_CONDITIONAL([HAVE_SSE2], + [test x"$OPUS_X86_MAY_HAVE_SSE2" = x"1"]) +AM_CONDITIONAL([HAVE_SSE4_1], + [test x"$OPUS_X86_MAY_HAVE_SSE4_1" = x"1"]) +AM_CONDITIONAL([HAVE_AVX], + [test x"$OPUS_X86_MAY_HAVE_AVX" = x"1"]) + +AS_IF([test x"$enable_rtcd" = x"yes"],[ + AS_IF([test x"$rtcd_support" != x"no"],[ + AC_DEFINE([OPUS_HAVE_RTCD], [1], + [Use run-time CPU capabilities detection]) + OPUS_HAVE_RTCD=1 + AC_SUBST(OPUS_HAVE_RTCD) + ]) +],[ + rtcd_support="disabled" +]) + +AC_ARG_ENABLE([assertions], + [AS_HELP_STRING([--enable-assertions],[enable additional software error checking])],, + [enable_assertions=no]) + +AS_IF([test "$enable_assertions" = "yes"], [ + AC_DEFINE([ENABLE_ASSERTIONS], [1], [Assertions]) +]) + +AC_ARG_ENABLE([hardening], + [AS_HELP_STRING([--disable-hardening],[disable run-time checks that are cheap and safe for use in production])],, + [enable_hardening=yes]) + +AS_IF([test "$enable_hardening" = "yes"], [ + AC_DEFINE([ENABLE_HARDENING], [1], [Hardening]) +]) + +AC_ARG_ENABLE([fuzzing], + [AS_HELP_STRING([--enable-fuzzing],[causes the encoder to make random decisions (do not use in production)])],, + [enable_fuzzing=no]) + +AS_IF([test "$enable_fuzzing" = "yes"], [ + AC_DEFINE([FUZZING], [1], [Fuzzing]) +]) + +AC_ARG_ENABLE([check-asm], + [AS_HELP_STRING([--enable-check-asm], + [enable bit-exactness checks between optimized and c implementations])],, + [enable_check_asm=no]) + +AS_IF([test "$enable_check_asm" = "yes"], [ + AC_DEFINE([OPUS_CHECK_ASM], [1], [Run bit-exactness checks between optimized and c implementations]) +]) + +AC_ARG_ENABLE([doc], + [AS_HELP_STRING([--disable-doc], [Do not build API documentation])],, + [enable_doc=yes]) + +AS_IF([test "$enable_doc" = "yes"], [ + AC_CHECK_PROG(HAVE_DOXYGEN, [doxygen], [yes], [no]) + AC_CHECK_PROG(HAVE_DOT, [dot], [yes], [no]) +],[ + HAVE_DOXYGEN=no +]) + +AM_CONDITIONAL([HAVE_DOXYGEN], [test "$HAVE_DOXYGEN" = "yes"]) + +AC_ARG_ENABLE([extra-programs], + [AS_HELP_STRING([--disable-extra-programs], [Do not build extra programs (demo and tests)])],, + [enable_extra_programs=yes]) + +AM_CONDITIONAL([EXTRA_PROGRAMS], [test "$enable_extra_programs" = "yes"]) + + +AC_ARG_ENABLE([rfc8251], + AS_HELP_STRING([--disable-rfc8251], [Disable bitstream fixes from RFC 8251]),, + [enable_rfc8251=yes]) + +AS_IF([test "$enable_rfc8251" = "no"], [ + AC_DEFINE([DISABLE_UPDATE_DRAFT], [1], [Disable bitstream fixes from RFC 8251]) +]) + + +saved_CFLAGS="$CFLAGS" +CFLAGS="$CFLAGS -fvisibility=hidden" +AC_MSG_CHECKING([if ${CC} supports -fvisibility=hidden]) +AC_COMPILE_IFELSE([AC_LANG_SOURCE([[char foo;]])], + [ AC_MSG_RESULT([yes]) ], + [ AC_MSG_RESULT([no]) + CFLAGS="$saved_CFLAGS" + ]) + +on_x86=no +case "$host_cpu" in +i[[3456]]86 | x86_64) + on_x86=yes + ;; +esac + +on_windows=no +case $host in +*cygwin*|*mingw*) + on_windows=yes + ;; +esac + +dnl Enable stack-protector-all only on x86 where it's well supported. +dnl on some platforms it causes crashes. Hopefully the OS's default's +dnl include this on platforms that work but have been missed here. +AC_ARG_ENABLE([stack-protector], + [AS_HELP_STRING([--disable-stack-protector],[Disable compiler stack hardening])],, + [ + AS_IF([test "$ac_cv_c_compiler_gnu" = "yes" && test "$on_x86" = "yes" && test "$on_windows" = "no"], + [enable_stack_protector=yes],[enable_stack_protector=no]) + ]) + +AS_IF([test "$enable_stack_protector" = "yes"], + [ + saved_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -fstack-protector-strong" + AC_MSG_CHECKING([if ${CC} supports -fstack-protector-strong]) + AC_LINK_IFELSE([AC_LANG_PROGRAM([],[[char foo;]])], + [ AC_MSG_RESULT([yes]) ], + [ + AC_MSG_RESULT([no]) + enable_stack_protector=no + CFLAGS="$saved_CFLAGS" + ]) + ]) + +AS_IF([test x$ac_cv_c_compiler_gnu = xyes], + [AX_ADD_FORTIFY_SOURCE] +) + +CFLAGS="$CFLAGS -W" + +warn_CFLAGS="-Wall -Wextra -Wcast-align -Wnested-externs -Wshadow -Wstrict-prototypes" +saved_CFLAGS="$CFLAGS" +CFLAGS="$CFLAGS $warn_CFLAGS" +AC_MSG_CHECKING([if ${CC} supports ${warn_CFLAGS}]) +AC_COMPILE_IFELSE([AC_LANG_SOURCE([[char foo;]])], + [ AC_MSG_RESULT([yes]) ], + [ AC_MSG_RESULT([no]) + CFLAGS="$saved_CFLAGS" + ]) + +saved_LIBS="$LIBS" +LIBS="$LIBS $LIBM" +AC_CHECK_FUNCS([lrintf]) +AC_CHECK_FUNCS([lrint]) +LIBS="$saved_LIBS" + +AC_CHECK_FUNCS([__malloc_hook]) + +AC_SUBST([PC_BUILD]) + +AC_CONFIG_FILES([ + Makefile + opus.pc + opus-uninstalled.pc + celt/arm/armopts.s + doc/Makefile + doc/Doxyfile +]) +AC_CONFIG_HEADERS([config.h]) + +AC_OUTPUT + +AC_MSG_NOTICE([ +------------------------------------------------------------------------ + $PACKAGE_NAME $PACKAGE_VERSION: Automatic configuration OK. + + Compiler support: + + C99 var arrays: ................ ${has_var_arrays} + C99 lrintf: .................... ${ac_cv_func_lrintf} + Use alloca: .................... ${use_alloca} + + General configuration: + + Floating point support: ........ ${enable_float} + Fast float approximations: ..... ${enable_float_approx} + Fixed point debugging: ......... ${enable_fixed_point_debug} + Inline Assembly Optimizations: . ${inline_optimization} + External Assembly Optimizations: ${asm_optimization} + Intrinsics Optimizations: ...... ${intrinsics_support} + Run-time CPU detection: ........ ${rtcd_support} + Custom modes: .................. ${enable_custom_modes} + Assertion checking: ............ ${enable_assertions} + Hardening: ..................... ${enable_hardening} + Fuzzing: ....................... ${enable_fuzzing} + Check ASM: ..................... ${enable_check_asm} + + API documentation: ............. ${enable_doc} + Extra programs: ................ ${enable_extra_programs} +------------------------------------------------------------------------ + + Type "make; make install" to compile and install + Type "make check" to run the test suite +]) + diff --git a/extern/opus/doc/Doxyfile.in b/extern/opus/doc/Doxyfile.in new file mode 100644 index 0000000..36eee0b --- /dev/null +++ b/extern/opus/doc/Doxyfile.in @@ -0,0 +1,335 @@ +# Doxyfile 1.8.10 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project. +# +# All text after a double hash (##) is considered a comment and is placed in +# front of the TAG it is preceding. +# +# All text after a single hash (#) is considered a comment and will be ignored. +# The format is: +# TAG = value [value, ...] +# For lists, items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (\" \"). + +# Only non-default options are included below to improve portability +# between doxygen versions. +# +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by +# double-quotes, unless you are using Doxywizard) that should identify the +# project for which the documentation is generated. This name is used in the +# title of most generated pages and in a few other places. +# The default value is: My Project. + +PROJECT_NAME = Opus + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. This +# could be handy for archiving the generated documentation or if some version +# control system is used. + +PROJECT_NUMBER = @VERSION@ + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer a +# quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = "Opus audio codec (RFC 6716): API and operations manual" + +# With the PROJECT_LOGO tag one can specify a logo or an icon that is included +# in the documentation. The maximum height of the logo should not exceed 55 +# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy +# the logo to the output directory. + +PROJECT_LOGO = + +# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path +# before files name in the file list and in the header files. If set to NO the +# shortest path that makes the file name unique will be used +# The default value is: YES. + +FULL_PATH_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the +# first line (until the first dot) of a Javadoc-style comment as the brief +# description. If set to NO, the Javadoc-style will behave just like regular Qt- +# style comments (thus requiring an explicit @brief command for a brief +# description.) +# The default value is: NO. + +JAVADOC_AUTOBRIEF = YES + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen +# uses this value to replace tabs by spaces in code fragments. +# Minimum value: 1, maximum value: 16, default value: 4. + +TAB_SIZE = 8 + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources +# only. Doxygen will then generate output that is more tailored for C. For +# instance, some of the names that are used will be different. The list of all +# members will be omitted, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_FOR_C = YES + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in +# documentation are documented, even if no documentation was available. Private +# class members and static file members will be hidden unless the +# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. +# Note: This will also disable the warnings about undocumented members that are +# normally produced when WARNINGS is set to YES. +# The default value is: NO. + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will +# be included in the documentation. +# The default value is: NO. + +EXTRACT_PRIVATE = NO + +# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file +# names in lower-case letters. If set to YES, upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. +# The default value is: system dependent. + +CASE_SENSE_NAMES = YES + +# The ENABLED_SECTIONS tag can be used to enable conditional documentation +# sections, marked by \if ... \endif and \cond +# ... \endcond blocks. + +ENABLED_SECTIONS = + +#--------------------------------------------------------------------------- +# Configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated to +# standard output by doxygen. If QUIET is set to YES this implies that the +# messages are off. +# The default value is: NO. + +QUIET = YES + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES +# this implies that the warnings are on. +# +# Tip: Turn warnings on while writing the documentation. +# The default value is: YES. + +WARNINGS = YES + +#--------------------------------------------------------------------------- +# Configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag is used to specify the files and/or directories that contain +# documented source files. You may enter file names like myfile.cpp or +# directories like /usr/src/myproject. Separate the files or directories with +# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING +# Note: If this tag is empty the current directory is searched. + +INPUT = @top_srcdir@/include/opus.h \ + @top_srcdir@/include/opus_types.h \ + @top_srcdir@/include/opus_defines.h \ + @top_srcdir@/include/opus_multistream.h \ + @top_srcdir@/include/opus_custom.h + +# The EXCLUDE tag can be used to specify files and/or directories that should be +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. +# +# Note that relative paths are relative to the directory from which doxygen is +# run. + +EXCLUDE = + +#--------------------------------------------------------------------------- +# Configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all +# compounds will be generated. Enable this if the project contains a lot of +# classes, structs, unions or interfaces. +# The default value is: YES. + +ALPHABETICAL_INDEX = NO + +#--------------------------------------------------------------------------- +# Configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# The HTML_HEADER tag can be used to specify a user-defined HTML header file for +# each generated HTML page. If the tag is left blank doxygen will generate a +# standard header. +# +# To get valid HTML the header file that includes any scripts and style sheets +# that doxygen needs, which is dependent on the configuration options used (e.g. +# the setting GENERATE_TREEVIEW). It is highly recommended to start with a +# default header using +# doxygen -w html new_header.html new_footer.html new_stylesheet.css +# YourConfigFile +# and then modify the file new_header.html. See also section "Doxygen usage" +# for information on how to generate the default header that doxygen normally +# uses. +# Note: The header is subject to change so you typically have to regenerate the +# default header when upgrading to a newer version of doxygen. For a description +# of the possible markers and block names see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_HEADER = @top_srcdir@/doc/header.html + +# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each +# generated HTML page. If the tag is left blank doxygen will generate a standard +# footer. See HTML_HEADER for more information on how to generate a default +# footer and what special commands can be used inside the footer. See also +# section "Doxygen usage" for information on how to generate the default footer +# that doxygen normally uses. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FOOTER = @top_srcdir@/doc/footer.html + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style +# sheet that is used by each HTML page. It can be used to fine-tune the look of +# the HTML output. If left blank doxygen will generate a default style sheet. +# See also section "Doxygen usage" for information on how to generate the style +# sheet that doxygen normally uses. +# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as +# it is more robust and this tag (HTML_STYLESHEET) will in the future become +# obsolete. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_STYLESHEET = @top_srcdir@/doc/customdoxygen.css + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that the +# files will be copied as-is; there are no commands or markers available. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_FILES = @top_srcdir@/doc/opus_logo.svg + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors +# in the HTML output. For a value of 0 the output will use grayscales only. A +# value of 255 will produce the most vivid colors. +# Minimum value: 0, maximum value: 255, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_SAT = 0 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting this +# to YES can help to show when doxygen was last run and thus if the +# documentation is up to date. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_TIMESTAMP = YES + +# When MathJax is enabled you need to specify the location relative to the HTML +# output directory using the MATHJAX_RELPATH option. The destination directory +# should contain the MathJax.js script. For instance, if the mathjax directory +# is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax +# Content Delivery Network so you can quickly see the result without installing +# MathJax. However, it is strongly recommended to install a local copy of +# MathJax from http://www.mathjax.org before deployment. +# The default value is: http://cdn.mathjax.org/mathjax/latest. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_RELPATH = https://www.mathjax.org/mathjax + +#--------------------------------------------------------------------------- +# Configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# The PAPER_TYPE tag can be used to set the paper type that is used by the +# printer. +# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x +# 14 inches) and executive (7.25 x 10.5 inches). +# The default value is: a4. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +PAPER_TYPE = letter + +#--------------------------------------------------------------------------- +# Configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for +# classes and files. +# The default value is: NO. + +GENERATE_MAN = YES + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names +# in the source code. If set to NO, only conditional compilation will be +# performed. Macro expansion can be done in a controlled way by setting +# EXPAND_ONLY_PREDEF to YES. +# The default value is: NO. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +MACRO_EXPANSION = YES + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then +# the macro expansion is limited to the macros specified with the PREDEFINED and +# EXPAND_AS_DEFINED tags. +# The default value is: NO. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +EXPAND_ONLY_PREDEF = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by the +# preprocessor. +# This tag requires that the tag SEARCH_INCLUDES is set to YES. + +INCLUDE_PATH = + +# The PREDEFINED tag can be used to specify one or more macro names that are +# defined before the preprocessor is started (similar to the -D option of e.g. +# gcc). The argument of the tag is a list of macros of the form: name or +# name=definition (no spaces). If the definition and the "=" are omitted, "=1" +# is assumed. To prevent a macro definition from being undefined via #undef or +# recursively expanded use the := operator instead of the = operator. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +PREDEFINED = OPUS_EXPORT= \ + OPUS_CUSTOM_EXPORT= \ + OPUS_CUSTOM_EXPORT_STATIC= \ + OPUS_WARN_UNUSED_RESULT= \ + OPUS_ARG_NONNULL(_x)= + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz (see: +# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent +# Bell Labs. + +# Debian defaults to YES here, while Fedora and Homebrew default to NO. +# So we set this based on whether the graphviz package is available at +# configure time. +# +HAVE_DOT = @HAVE_DOT@ diff --git a/extern/opus/doc/Makefile.am b/extern/opus/doc/Makefile.am new file mode 100644 index 0000000..31fddab --- /dev/null +++ b/extern/opus/doc/Makefile.am @@ -0,0 +1,45 @@ +## Process this file with automake to produce Makefile.in + +DOCINPUTS = $(top_srcdir)/include/opus.h \ + $(top_srcdir)/include/opus_multistream.h \ + $(top_srcdir)/include/opus_defines.h \ + $(top_srcdir)/include/opus_types.h \ + $(top_srcdir)/include/opus_custom.h \ + $(top_srcdir)/doc/header.html \ + $(top_srcdir)/doc/footer.html \ + $(top_srcdir)/doc/customdoxygen.css + +EXTRA_DIST = customdoxygen.css Doxyfile.in footer.html header.html \ + opus_logo.svg trivial_example.c + + +if HAVE_DOXYGEN + +all-local: doxygen-build.stamp + +doxygen-build.stamp: Doxyfile $(DOCINPUTS) + doxygen + touch $@ + +install-data-local: + $(INSTALL) -d $(DESTDIR)$(docdir)/html/search + for f in `find html -type f \! -name "installdox"`; do \ + $(INSTALL_DATA) $$f $(DESTDIR)$(docdir)/$$f; \ + done + + $(INSTALL) -d $(DESTDIR)$(mandir)/man3 + cd man && find man3 -type f -name opus_*.3 \ + -exec $(INSTALL_DATA) \{} $(DESTDIR)$(mandir)/man3 \; + +clean-local: + $(RM) -r html + $(RM) -r latex + $(RM) -r man + $(RM) doxygen-build.stamp + $(RM) doxygen_sqlite3.db + +uninstall-local: + $(RM) -r $(DESTDIR)$(docdir)/html + $(RM) $(DESTDIR)$(mandir)/man3/opus_*.3 $(DESTDIR)$(mandir)/man3/opus.h.3 + +endif diff --git a/extern/opus/doc/build_draft.sh b/extern/opus/doc/build_draft.sh new file mode 100755 index 0000000..d15b22a --- /dev/null +++ b/extern/opus/doc/build_draft.sh @@ -0,0 +1,104 @@ +#!/bin/sh + +# Copyright (c) 2011-2012 Xiph.Org Foundation and Mozilla Corporation +# +# This file is extracted from RFC6716. Please see that RFC for additional +# information. +# +# 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 OWNER +# 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. + +#Stop on errors +set -e +#Set the CWD to the location of this script +[ -n "${0%/*}" ] && cd "${0%/*}" + +toplevel=".." +destdir="opus_source" + +echo packaging source code +rm -rf "${destdir}" +mkdir "${destdir}" +mkdir "${destdir}/src" +mkdir "${destdir}/silk" +mkdir "${destdir}/silk/float" +mkdir "${destdir}/silk/fixed" +mkdir "${destdir}/celt" +mkdir "${destdir}/include" +for f in `cat "${toplevel}"/opus_sources.mk "${toplevel}"/celt_sources.mk \ + "${toplevel}"/silk_sources.mk "${toplevel}"/opus_headers.mk \ + "${toplevel}"/celt_headers.mk "${toplevel}"/silk_headers.mk \ + | grep '\.[ch]' | sed -e 's/^.*=//' -e 's/\\\\//'` ; do + cp -a "${toplevel}/${f}" "${destdir}/${f}" +done +cp -a "${toplevel}"/src/opus_demo.c "${destdir}"/src/ +cp -a "${toplevel}"/src/opus_compare.c "${destdir}"/src/ +cp -a "${toplevel}"/celt/opus_custom_demo.c "${destdir}"/celt/ +cp -a "${toplevel}"/Makefile.unix "${destdir}"/Makefile +cp -a "${toplevel}"/opus_sources.mk "${destdir}"/ +cp -a "${toplevel}"/celt_sources.mk "${destdir}"/ +cp -a "${toplevel}"/silk_sources.mk "${destdir}"/ +cp -a "${toplevel}"/README.draft "${destdir}"/README +cp -a "${toplevel}"/COPYING "${destdir}"/COPYING +cp -a "${toplevel}"/tests/run_vectors.sh "${destdir}"/ + +GZIP=-9 tar --owner=root --group=root --format=v7 -czf opus_source.tar.gz "${destdir}" +echo building base64 version +cat opus_source.tar.gz| base64 | tr -d '\n' | fold -w 64 | \ + sed -e 's/^/\###/' -e 's/$/\<\/spanx\>\/' > \ + opus_source.base64 + + +#echo '
    ' > opus_compare_escaped.c +#echo '' >> opus_compare_escaped.c +#echo '> opus_compare_escaped.c +#cat opus_compare.c >> opus_compare_escaped.c +#echo ']]>' >> opus_compare_escaped.c +#echo '' >> opus_compare_escaped.c +#echo '
    ' >> opus_compare_escaped.c + +if [[ ! -d ../opus_testvectors ]] ; then + echo "Downloading test vectors..." + wget 'http://opus-codec.org/testvectors/opus_testvectors.tar.gz' + tar -C .. -xvzf opus_testvectors.tar.gz +fi +echo '
    ' > testvectors_sha1 +echo '' >> testvectors_sha1 +echo '> testvectors_sha1 +(cd ../opus_testvectors; sha1sum *.bit *.dec) >> testvectors_sha1 +#cd opus_testvectors +#sha1sum *.bit *.dec >> ../testvectors_sha1 +#cd .. +echo ']]>' >> testvectors_sha1 +echo '' >> testvectors_sha1 +echo '
    ' >> testvectors_sha1 + +echo running xml2rfc +xml2rfc draft-ietf-codec-opus.xml draft-ietf-codec-opus.html & +xml2rfc draft-ietf-codec-opus.xml +wait diff --git a/extern/opus/doc/build_isobmff.sh b/extern/opus/doc/build_isobmff.sh new file mode 100755 index 0000000..95ea202 --- /dev/null +++ b/extern/opus/doc/build_isobmff.sh @@ -0,0 +1,50 @@ +#!/bin/sh + +# Copyright (c) 2014 Xiph.Org Foundation and Mozilla Foundation +# +# 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. +# +# 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 OWNER +# 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. + +#Stop on errors +set -e +#Set the CWD to the location of this script +[ -n "${0%/*}" ] && cd "${0%/*}" + +HTML=opus_in_isobmff.html + +echo downloading updates... +CSS=${HTML%%.html}.css +wget -q http://vfrmaniac.fushizen.eu/contents/${HTML} -O ${HTML} +wget -q http://vfrmaniac.fushizen.eu/style.css -O ${CSS} + +echo updating links... +cat ${HTML} | sed -e "s/\\.\\.\\/style.css/${CSS}/" > ${HTML}+ && mv ${HTML}+ ${HTML} + +echo stripping... +cat ${HTML} | sed -e 's///g' > ${HTML}+ && mv ${HTML}+ ${HTML} +cat ${HTML} | sed -e 's/ *$//g' > ${HTML}+ && mv ${HTML}+ ${HTML} +cat ${CSS} | sed -e 's/ *$//g' > ${CSS}+ && mv ${CSS}+ ${CSS} + + +VERSION=$(fgrep Version ${HTML} | sed 's/.*Version \([0-9]\.[0-9]\.[0-9]\).*/\1/') +echo Now at version ${VERSION} diff --git a/extern/opus/doc/build_oggdraft.sh b/extern/opus/doc/build_oggdraft.sh new file mode 100755 index 0000000..30ee534 --- /dev/null +++ b/extern/opus/doc/build_oggdraft.sh @@ -0,0 +1,52 @@ +#!/bin/sh + +# Copyright (c) 2012 Xiph.Org Foundation and Mozilla Corporation +# +# This file is extracted from RFC6716. Please see that RFC for additional +# information. +# +# 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 OWNER +# 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. + +#Stop on errors +set -e +#Set the CWD to the location of this script +[ -n "${0%/*}" ] && cd "${0%/*}" + +if test -z `which xml2rfc 2> /dev/null`; then + echo "Error: couldn't find xml2rfc." + echo + echo "Please install xml2rfc version 2 or later." + echo "E.g. 'pip install xml2rfc' or follow the instructions" + echo "on http://pypi.python.org/pypi/xml2rfc/ or tools.ietf.org." + exit 1 +fi + +echo running xml2rfc +# version 2 syntax +xml2rfc draft-ietf-codec-oggopus.xml --text --html diff --git a/extern/opus/doc/customdoxygen.css b/extern/opus/doc/customdoxygen.css new file mode 100644 index 0000000..7004778 --- /dev/null +++ b/extern/opus/doc/customdoxygen.css @@ -0,0 +1,1011 @@ +/* The standard CSS for doxygen */ + +body, table, div, p, dl { + font-family: Lucida Grande, Verdana, Geneva, Arial, sans-serif; + font-size: 13px; + line-height: 1.3; +} + +/* @group Heading Levels */ + +h1 { + font-size: 150%; +} + +.title { + font-size: 150%; + font-weight: bold; + margin: 10px 2px; +} + +h2 { + font-size: 120%; +} + +h3 { + font-size: 100%; +} + +dt { + font-weight: bold; +} + +div.multicol { + -moz-column-gap: 1em; + -webkit-column-gap: 1em; + -moz-column-count: 3; + -webkit-column-count: 3; +} + +p.startli, p.startdd, p.starttd { + margin-top: 2px; +} + +p.endli { + margin-bottom: 0px; +} + +p.enddd { + margin-bottom: 4px; +} + +p.endtd { + margin-bottom: 2px; +} + +/* @end */ + +caption { + font-weight: bold; +} + +span.legend { + font-size: 70%; + text-align: center; +} + +h3.version { + font-size: 90%; + text-align: center; +} + +div.qindex, div.navtab{ + background-color: #F1F1F1; + border: 1px solid #BDBDBD; + text-align: center; +} + +div.qindex, div.navpath { + width: 100%; + line-height: 140%; +} + +div.navtab { + margin-right: 15px; +} + +/* @group Link Styling */ + +a { + color: #646464; + font-weight: normal; + text-decoration: none; +} + +.contents a:visited { + color: #747474; +} + +a:hover { + text-decoration: underline; +} + +a.qindex { + font-weight: bold; +} + +a.qindexHL { + font-weight: bold; + background-color: #B8B8B8; + color: #ffffff; + border: 1px double #A8A8A8; +} + +.contents a.qindexHL:visited { + color: #ffffff; +} + +a.el { + font-weight: bold; +} + +a.elRef { +} + +a.code, a.code:visited { + color: #4665A2; +} + +a.codeRef, a.codeRef:visited { + color: #4665A2; +} + +/* @end */ + +dl.el { + margin-left: -1cm; +} + +.fragment { + font-family: monospace, fixed; + font-size: 105%; +} + +pre.fragment { + border: 1px solid #D5D5D5; + background-color: #FCFCFC; + padding: 4px 6px; + margin: 4px 8px 4px 2px; + overflow: auto; + word-wrap: break-word; + font-size: 9pt; + line-height: 125%; +} + +div.ah { + background-color: black; + font-weight: bold; + color: #ffffff; + margin-bottom: 3px; + margin-top: 3px; + padding: 0.2em; + border: solid thin #333; + border-radius: 0.5em; + -webkit-border-radius: .5em; + -moz-border-radius: .5em; + box-shadow: 2px 2px 3px #999; + -webkit-box-shadow: 2px 2px 3px #999; + -moz-box-shadow: rgba(0, 0, 0, 0.15) 2px 2px 2px; + background-image: -webkit-gradient(linear, left top, left bottom, from(#eee), to(#000),color-stop(0.3, #444)); + background-image: -moz-linear-gradient(center top, #eee 0%, #444 40%, #000); +} + +div.groupHeader { + margin-left: 16px; + margin-top: 12px; + font-weight: bold; +} + +div.groupText { + margin-left: 16px; + font-style: italic; +} + +body { + background-color: white; + color: black; + margin: 0; +} + +div.contents { + margin-top: 10px; + margin-left: 8px; + margin-right: 8px; +} + +td.indexkey { + background-color: #F1F1F1; + font-weight: bold; + border: 1px solid #D5D5D5; + margin: 2px 0px 2px 0; + padding: 2px 10px; + white-space: nowrap; + vertical-align: top; +} + +td.indexvalue { + background-color: #F1F1F1; + border: 1px solid #D5D5D5; + padding: 2px 10px; + margin: 2px 0px; +} + +tr.memlist { + background-color: #F2F2F2; +} + +p.formulaDsp { + text-align: center; +} + +img.formulaDsp { + +} + +img.formulaInl { + vertical-align: middle; +} + +div.center { + text-align: center; + margin-top: 0px; + margin-bottom: 0px; + padding: 0px; +} + +div.center img { + border: 0px; +} + +address.footer { + text-align: right; + padding-right: 12px; +} + +img.footer { + border: 0px; + vertical-align: middle; +} + +/* @group Code Colorization */ + +span.keyword { + color: #008000 +} + +span.keywordtype { + color: #604020 +} + +span.keywordflow { + color: #e08000 +} + +span.comment { + color: #800000 +} + +span.preprocessor { + color: #806020 +} + +span.stringliteral { + color: #002080 +} + +span.charliteral { + color: #008080 +} + +span.vhdldigit { + color: #ff00ff +} + +span.vhdlchar { + color: #000000 +} + +span.vhdlkeyword { + color: #700070 +} + +span.vhdllogic { + color: #ff0000 +} + +blockquote { + background-color: #F9F9F9; + border-left: 2px solid #B8B8B8; + margin: 0 24px 0 4px; + padding: 0 12px 0 16px; +} + +/* @end */ + +/* +.search { + color: #003399; + font-weight: bold; +} + +form.search { + margin-bottom: 0px; + margin-top: 0px; +} + +input.search { + font-size: 75%; + color: #000080; + font-weight: normal; + background-color: #e8eef2; +} +*/ + +td.tiny { + font-size: 75%; +} + +.dirtab { + padding: 4px; + border-collapse: collapse; + border: 1px solid #BDBDBD; +} + +th.dirtab { + background: #F1F1F1; + font-weight: bold; +} + +hr { + height: 0px; + border: none; + border-top: 1px solid #7A7A7A; +} + +hr.footer { + height: 1px; +} + +/* @group Member Descriptions */ + +table.memberdecls { + border-spacing: 0px; + padding: 0px; +} + +.mdescLeft, .mdescRight, +.memItemLeft, .memItemRight, +.memTemplItemLeft, .memTemplItemRight, .memTemplParams { + background-color: #FAFAFA; + border: none; + margin: 4px; + padding: 1px 0 0 8px; +} + +.mdescLeft, .mdescRight { + padding: 0px 8px 4px 8px; + color: #555; +} + +.memItemLeft, .memItemRight, .memTemplParams { + border-top: 1px solid #D5D5D5; +} + +.memItemLeft, .memTemplItemLeft { + white-space: nowrap; +} + +.memItemRight { + width: 100%; +} + +.memTemplParams { + color: #747474; + white-space: nowrap; +} + +/* @end */ + +/* @group Member Details */ + +/* Styles for detailed member documentation */ + +.memtemplate { + font-size: 80%; + color: #747474; + font-weight: normal; + margin-left: 9px; +} + +.memnav { + background-color: #F1F1F1; + border: 1px solid #BDBDBD; + text-align: center; + margin: 2px; + margin-right: 15px; + padding: 2px; +} + +.mempage { + width: 100%; +} + +.memitem { + padding: 0; + margin-bottom: 10px; + margin-right: 5px; +} + +.memname { + white-space: nowrap; + font-weight: bold; + margin-left: 6px; +} + +.memproto, dl.reflist dt { + border-top: 1px solid #C0C0C0; + border-left: 1px solid #C0C0C0; + border-right: 1px solid #C0C0C0; + padding: 6px 0px 6px 0px; + color: #3D3D3D; + font-weight: bold; + text-shadow: 0px 1px 1px rgba(255, 255, 255, 0.9); + /* opera specific markup */ + box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); + border-top-right-radius: 8px; + border-top-left-radius: 8px; + /* firefox specific markup */ + -moz-box-shadow: rgba(0, 0, 0, 0.15) 5px 5px 5px; + -moz-border-radius-topright: 8px; + -moz-border-radius-topleft: 8px; + /* webkit specific markup */ + -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); + -webkit-border-top-right-radius: 8px; + -webkit-border-top-left-radius: 8px; + background-image:url('nav_f.png'); + background-repeat:repeat-x; + background-color: #EAEAEA; + +} + +.memdoc, dl.reflist dd { + border-bottom: 1px solid #C0C0C0; + border-left: 1px solid #C0C0C0; + border-right: 1px solid #C0C0C0; + padding: 2px 5px; + background-color: #FCFCFC; + border-top-width: 0; + /* opera specific markup */ + border-bottom-left-radius: 8px; + border-bottom-right-radius: 8px; + box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); + /* firefox specific markup */ + -moz-border-radius-bottomleft: 8px; + -moz-border-radius-bottomright: 8px; + -moz-box-shadow: rgba(0, 0, 0, 0.15) 5px 5px 5px; + background-image: -moz-linear-gradient(center top, #FFFFFF 0%, #FFFFFF 60%, #F9F9F9 95%, #F2F2F2); + /* webkit specific markup */ + -webkit-border-bottom-left-radius: 8px; + -webkit-border-bottom-right-radius: 8px; + -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); + background-image: -webkit-gradient(linear,center top,center bottom,from(#FFFFFF), color-stop(0.6,#FFFFFF), color-stop(0.60,#FFFFFF), color-stop(0.95,#F9F9F9), to(#F2F2F2)); +} + +dl.reflist dt { + padding: 5px; +} + +dl.reflist dd { + margin: 0px 0px 10px 0px; + padding: 5px; +} + +.paramkey { + text-align: right; +} + +.paramtype { + white-space: nowrap; +} + +.paramname { + color: #602020; + white-space: nowrap; +} +.paramname em { + font-style: normal; +} + +.params, .retval, .exception, .tparams { + border-spacing: 6px 2px; +} + +.params .paramname, .retval .paramname { + font-weight: bold; + vertical-align: top; +} + +.params .paramtype { + font-style: italic; + vertical-align: top; +} + +.params .paramdir { + font-family: "courier new",courier,monospace; + vertical-align: top; +} + + + + +/* @end */ + +/* @group Directory (tree) */ + +/* for the tree view */ + +.ftvtree { + font-family: sans-serif; + margin: 0px; +} + +/* these are for tree view when used as main index */ + +.directory { + font-size: 9pt; + font-weight: bold; + margin: 5px; +} + +.directory h3 { + margin: 0px; + margin-top: 1em; + font-size: 11pt; +} + +/* +The following two styles can be used to replace the root node title +with an image of your choice. Simply uncomment the next two styles, +specify the name of your image and be sure to set 'height' to the +proper pixel height of your image. +*/ + +/* +.directory h3.swap { + height: 61px; + background-repeat: no-repeat; + background-image: url("yourimage.gif"); +} +.directory h3.swap span { + display: none; +} +*/ + +.directory > h3 { + margin-top: 0; +} + +.directory p { + margin: 0px; + white-space: nowrap; +} + +.directory div { + display: none; + margin: 0px; +} + +.directory img { + vertical-align: -30%; +} + +/* these are for tree view when not used as main index */ + +.directory-alt { + font-size: 100%; + font-weight: bold; +} + +.directory-alt h3 { + margin: 0px; + margin-top: 1em; + font-size: 11pt; +} + +.directory-alt > h3 { + margin-top: 0; +} + +.directory-alt p { + margin: 0px; + white-space: nowrap; +} + +.directory-alt div { + display: none; + margin: 0px; +} + +.directory-alt img { + vertical-align: -30%; +} + +/* @end */ + +div.dynheader { + margin-top: 8px; +} + +address { + font-style: normal; + color: #464646; +} + +table.doxtable { + border-collapse:collapse; + margin-top: 4px; + margin-bottom: 4px; +} + +table.doxtable td, table.doxtable th { + border: 1px solid #4A4A4A; + padding: 3px 7px 2px; +} + +table.doxtable th { + background-color: #5B5B5B; + color: #FFFFFF; + font-size: 110%; + padding-bottom: 4px; + padding-top: 5px; +} + +table.fieldtable { + width: 100%; + margin-bottom: 10px; + border: 1px solid #C0C0C0; + border-spacing: 0px; + -moz-border-radius: 4px; + -webkit-border-radius: 4px; + border-radius: 4px; + -moz-box-shadow: rgba(0, 0, 0, 0.15) 2px 2px 2px; + -webkit-box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.15); + box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.15); +} + +.fieldtable td, .fieldtable th { + padding: 3px 7px 2px; +} + +.fieldtable td.fieldtype, .fieldtable td.fieldname { + white-space: nowrap; + border-right: 1px solid #C0C0C0; + border-bottom: 1px solid #C0C0C0; + vertical-align: top; +} + +.fieldtable td.fielddoc { + border-bottom: 1px solid #C0C0C0; + width: 100%; +} + +.fieldtable tr:last-child td { + border-bottom: none; +} + +.fieldtable th { + background-image:url('nav_f.png'); + background-repeat:repeat-x; + background-color: #EAEAEA; + font-size: 90%; + color: #3D3D3D; + padding-bottom: 4px; + padding-top: 5px; + text-align:left; + -moz-border-radius-topleft: 4px; + -moz-border-radius-topright: 4px; + -webkit-border-top-left-radius: 4px; + -webkit-border-top-right-radius: 4px; + border-top-left-radius: 4px; + border-top-right-radius: 4px; + border-bottom: 1px solid #C0C0C0; +} + + +.tabsearch { + top: 0px; + left: 10px; + height: 36px; + background-image: url('tab_b.png'); + z-index: 101; + overflow: hidden; + font-size: 13px; +} + +.navpath ul +{ + font-size: 11px; + background-image:url('tab_b.png'); + background-repeat:repeat-x; + height:30px; + line-height:30px; + color:#ABABAB; + border:solid 1px #D3D3D3; + overflow:hidden; + margin:0px; + padding:0px; +} + +.navpath li +{ + list-style-type:none; + float:left; + padding-left:10px; + padding-right:15px; + background-image:url('bc_s.png'); + background-repeat:no-repeat; + background-position:right; + color:#595959; +} + +.navpath li.navelem a +{ + height:32px; + display:block; + text-decoration: none; + outline: none; +} + +.navpath li.navelem a:hover +{ + color:#929292; +} + +.navpath li.footer +{ + list-style-type:none; + float:right; + padding-left:10px; + padding-right:15px; + background-image:none; + background-repeat:no-repeat; + background-position:right; + color:#595959; + font-size: 8pt; +} + + +div.summary +{ + float: right; + font-size: 8pt; + padding-right: 5px; + width: 50%; + text-align: right; +} + +div.summary a +{ + white-space: nowrap; +} + +div.ingroups +{ + margin-left: 5px; + font-size: 8pt; + padding-left: 5px; + width: 50%; + text-align: left; +} + +div.ingroups a +{ + white-space: nowrap; +} + +div.header +{ + background-image:url('nav_h.png'); + background-repeat:repeat-x; + background-color: #FAFAFA; + margin: 0px; + border-bottom: 1px solid #D5D5D5; +} + +div.headertitle +{ + padding: 5px 5px 5px 7px; +} + +dl +{ + padding: 0 0 0 10px; +} + +/* dl.note, dl.warning, dl.attention, dl.pre, dl.post, dl.invariant, dl.deprecated, dl.todo, dl.test, dl.bug */ +dl.section +{ + border-left:4px solid; + padding: 0 0 0 6px; +} + +dl.note +{ + border-color: #D0C000; +} + +dl.warning, dl.attention +{ + border-color: #FF0000; +} + +dl.pre, dl.post, dl.invariant +{ + border-color: #00D000; +} + +dl.deprecated +{ + border-color: #505050; +} + +dl.todo +{ + border-color: #00C0E0; +} + +dl.test +{ + border-color: #3030E0; +} + +dl.bug +{ + border-color: #C08050; +} + +dl.section dd { + margin-bottom: 6px; +} + + +#projectlogo +{ + text-align: center; + vertical-align: bottom; + border-collapse: separate; +} + +#projectlogo img +{ + border: 0px none; +} + +#projectname +{ + font: 300% Tahoma, Arial,sans-serif; + margin: 0px; + padding: 2px 0px; +} + +#projectbrief +{ + font: 120% Tahoma, Arial,sans-serif; + margin: 0px; + padding: 0px; +} + +#projectnumber +{ + font: 100% Tahoma, Arial,sans-serif; + margin: 0px; + padding: 0px; +} + +#titlearea +{ + padding: 0px; + margin: 0px; + width: 100%; + border-bottom: 1px solid #848484; +} + +.image +{ + text-align: center; +} + +.dotgraph +{ + text-align: center; +} + +.mscgraph +{ + text-align: center; +} + +.caption +{ + font-weight: bold; +} + +div.zoom +{ + border: 1px solid #AFAFAF; +} + +dl.citelist { + margin-bottom:50px; +} + +dl.citelist dt { + color:#545454; + float:left; + font-weight:bold; + margin-right:10px; + padding:5px; +} + +dl.citelist dd { + margin:2px 0; + padding:5px 0; +} + +div.toc { + padding: 14px 25px; + background-color: #F7F7F7; + border: 1px solid #E3E3E3; + border-radius: 7px 7px 7px 7px; + float: right; + height: auto; + margin: 0 20px 10px 10px; + width: 200px; +} + +div.toc li { + background: url("bdwn.png") no-repeat scroll 0 5px transparent; + font: 10px/1.2 Verdana,DejaVu Sans,Geneva,sans-serif; + margin-top: 5px; + padding-left: 10px; + padding-top: 2px; +} + +div.toc h3 { + font: bold 12px/1.2 Arial,FreeSans,sans-serif; + color: #747474; + border-bottom: 0 none; + margin: 0; +} + +div.toc ul { + list-style: none outside none; + border: medium none; + padding: 0px; +} + +div.toc li.level1 { + margin-left: 0px; +} + +div.toc li.level2 { + margin-left: 15px; +} + +div.toc li.level3 { + margin-left: 30px; +} + +div.toc li.level4 { + margin-left: 45px; +} + + +@media print +{ + #top { display: none; } + #side-nav { display: none; } + #nav-path { display: none; } + body { overflow:visible; } + h1, h2, h3, h4, h5, h6 { page-break-after: avoid; } + .summary { display: none; } + .memitem { page-break-inside: avoid; } + #doc-content + { + margin-left:0 !important; + height:auto !important; + width:auto !important; + overflow:inherit; + display:inline; + } + pre.fragment + { + overflow: visible; + text-wrap: unrestricted; + white-space: -moz-pre-wrap; /* Moz */ + white-space: -pre-wrap; /* Opera 4-6 */ + white-space: -o-pre-wrap; /* Opera 7 */ + white-space: pre-wrap; /* CSS3 */ + word-wrap: break-word; /* IE 5.5+ */ + } +} diff --git a/extern/opus/doc/draft-ietf-codec-oggopus.xml b/extern/opus/doc/draft-ietf-codec-oggopus.xml new file mode 100644 index 0000000..128816e --- /dev/null +++ b/extern/opus/doc/draft-ietf-codec-oggopus.xml @@ -0,0 +1,1873 @@ + + + + + + + + + + + + +]> + + + + + +Ogg Encapsulation for the Opus Audio Codec + +Mozilla Corporation +
    + +650 Castro Street +Mountain View +CA +94041 +USA + ++1 650 903-0800 +tterribe@xiph.org +
    +
    + + +Voicetronix +
    + +246 Pulteney Street, Level 1 +Adelaide +SA +5000 +Australia + ++61 8 8232 9112 +ron@debian.org +
    +
    + + +Mozilla Corporation +
    + +163 West Hastings Street +Vancouver +BC +V6B 1H5 +Canada + ++1 778 785 1540 +giles@xiph.org +
    +
    + + +RAI +codec + + + +This document defines the Ogg encapsulation for the Opus interactive speech and + audio codec. +This allows data encoded in the Opus format to be stored in an Ogg logical + bitstream. + + +
    + + +
    + +The IETF Opus codec is a low-latency audio codec optimized for both voice and + general-purpose audio. +See for technical details. +This document defines the encapsulation of Opus in a continuous, logical Ogg + bitstream . +Ogg encapsulation provides Opus with a long-term storage format supporting + all of the essential features, including metadata, fast and accurate seeking, + corruption detection, recapture after errors, low overhead, and the ability to + multiplex Opus with other codecs (including video) with minimal buffering. +It also provides a live streamable format, capable of delivery over a reliable + stream-oriented transport, without requiring all the data, or even the total + length of the data, up-front, in a form that is identical to the on-disk + storage format. + + +Ogg bitstreams are made up of a series of 'pages', each of which contains data + from one or more 'packets'. +Pages are the fundamental unit of multiplexing in an Ogg stream. +Each page is associated with a particular logical stream and contains a capture + pattern and checksum, flags to mark the beginning and end of the logical + stream, and a 'granule position' that represents an absolute position in the + stream, to aid seeking. +A single page can contain up to 65,025 octets of packet data from up to 255 + different packets. +Packets can be split arbitrarily across pages, and continued from one page to + the next (allowing packets much larger than would fit on a single page). +Each page contains 'lacing values' that indicate how the data is partitioned + into packets, allowing a demultiplexer (demuxer) to recover the packet + boundaries without examining the encoded data. +A packet is said to 'complete' on a page when the page contains the final + lacing value corresponding to that packet. + + +This encapsulation defines the contents of the packet data, including + the necessary headers, the organization of those packets into a logical + stream, and the interpretation of the codec-specific granule position field. +It does not attempt to describe or specify the existing Ogg container format. +Readers unfamiliar with the basic concepts mentioned above are encouraged to + review the details in . + + +
    + +
    + +The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", + "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this + document are to be interpreted as described in . + + +
    + +
    + +An Ogg Opus stream is organized as follows (see + for an example). + + +
    + +
    + + +There are two mandatory header packets. +The first packet in the logical Ogg bitstream MUST contain the identification + (ID) header, which uniquely identifies a stream as Opus audio. +The format of this header is defined in . +It is placed alone (without any other packet data) on the first page of + the logical Ogg bitstream, and completes on that page. +This page has its 'beginning of stream' flag set. + + +The second packet in the logical Ogg bitstream MUST contain the comment header, + which contains user-supplied metadata. +The format of this header is defined in . +It MAY span multiple pages, beginning on the second page of the logical + stream. +However many pages it spans, the comment header packet MUST finish the page on + which it completes. + + +All subsequent pages are audio data pages, and the Ogg packets they contain are + audio data packets. +Each audio data packet contains one Opus packet for each of N different + streams, where N is typically one for mono or stereo, but MAY be greater than + one for multichannel audio. +The value N is specified in the ID header (see + ), and is fixed over the entire length of the + logical Ogg bitstream. + + +The first (N - 1) Opus packets, if any, are packed one after another + into the Ogg packet, using the self-delimiting framing from Appendix B of + . +The remaining Opus packet is packed at the end of the Ogg packet using the + regular, undelimited framing from Section 3 of . +All of the Opus packets in a single Ogg packet MUST be constrained to have the + same duration. +An implementation of this specification SHOULD treat any Opus packet whose + duration is different from that of the first Opus packet in an Ogg packet as + if it were a malformed Opus packet with an invalid Table Of Contents (TOC) + sequence. + + +The TOC sequence at the beginning of each Opus packet indicates the coding + mode, audio bandwidth, channel count, duration (frame size), and number of + frames per packet, as described in Section 3.1 + of . +The coding mode is one of SILK, Hybrid, or Constrained Energy Lapped Transform + (CELT). +The combination of coding mode, audio bandwidth, and frame size is referred to + as the configuration of an Opus packet. + + +Packets are placed into Ogg pages in order until the end of stream. +Audio data packets might span page boundaries. +The first audio data page could have the 'continued packet' flag set + (indicating the first audio data packet is continued from a previous page) if, + for example, it was a live stream joined mid-broadcast, with the headers + pasted on the front. +If a page has the 'continued packet' flag set and one of the following + conditions is also true: + +the previous page with packet data does not end in a continued packet (does + not end with a lacing value of 255) OR +the page sequence numbers are not consecutive, + + then a demuxer MUST NOT attempt to decode the data for the first packet on the + page unless the demuxer has some special knowledge that would allow it to + interpret this data despite the missing pieces. +An implementation MUST treat a zero-octet audio data packet as if it were a + malformed Opus packet as described in + Section 3.4 of . + + +A logical stream ends with a page with the 'end of stream' flag set, but + implementations need to be prepared to deal with truncated streams that do not + have a page marked 'end of stream'. +There is no reason for the final packet on the last page to be a continued + packet, i.e., for the final lacing value to be 255. +However, demuxers might encounter such streams, possibly as the result of a + transfer that did not complete or of corruption. +If a packet continues onto a subsequent page (i.e., when the page ends with a + lacing value of 255) and one of the following conditions is also true: + +the next page with packet data does not have the 'continued packet' flag + set OR +there is no next page with packet data OR +the page sequence numbers are not consecutive, + + then a demuxer MUST NOT attempt to decode the data from that packet unless the + demuxer has some special knowledge that would allow it to interpret this data + despite the missing pieces. +There MUST NOT be any more pages in an Opus logical bitstream after a page + marked 'end of stream'. + +
    + +
    + +The granule position MUST be zero for the ID header page and the + page where the comment header completes. +That is, the first page in the logical stream, and the last header + page before the first audio data page both have a granule position of zero. + + +The granule position of an audio data page encodes the total number of PCM + samples in the stream up to and including the last fully-decodable sample from + the last packet completed on that page. +The granule position of the first audio data page will usually be larger than + zero, as described in . + + + +A page that is entirely spanned by a single packet (that completes on a + subsequent page) has no granule position, and the granule position field is + set to the special value '-1' in two's complement. + + + +The granule position of an audio data page is in units of PCM audio samples at + a fixed rate of 48 kHz (per channel; a stereo stream's granule position + does not increment at twice the speed of a mono stream). +It is possible to run an Opus decoder at other sampling rates, + but all Opus packets encode samples at a sampling rate that evenly divides + 48 kHz. +Therefore, the value in the granule position field always counts samples + assuming a 48 kHz decoding rate, and the rest of this specification makes + the same assumption. + + + +The duration of an Opus packet as defined in can be + any multiple of 2.5 ms, up to a maximum of 120 ms. +This duration is encoded in the TOC sequence at the beginning of each packet. +The number of samples returned by a decoder corresponds to this duration + exactly, even for the first few packets. +For example, a 20 ms packet fed to a decoder running at 48 kHz will + always return 960 samples. +A demuxer can parse the TOC sequence at the beginning of each Ogg packet to + work backwards or forwards from a packet with a known granule position (i.e., + the last packet completed on some page) in order to assign granule positions + to every packet, or even every individual sample. +The one exception is the last page in the stream, as described below. + + + +All other pages with completed packets after the first MUST have a granule + position equal to the number of samples contained in packets that complete on + that page plus the granule position of the most recent page with completed + packets. +This guarantees that a demuxer can assign individual packets the same granule + position when working forwards as when working backwards. +For this to work, there cannot be any gaps. + + +
    + +In order to support capturing a real-time stream that has lost or not + transmitted packets, a multiplexer (muxer) SHOULD emit packets that explicitly + request the use of Packet Loss Concealment (PLC) in place of the missing + packets. +Implementations that fail to do so still MUST NOT increment the granule + position for a page by anything other than the number of samples contained in + packets that actually complete on that page. + + +Only gaps that are a multiple of 2.5 ms are repairable, as these are the + only durations that can be created by packet loss or discontinuous + transmission. +Muxers need not handle other gap sizes. +Creating the necessary packets involves synthesizing a TOC byte (defined in +Section 3.1 of )—and whatever + additional internal framing is needed—to indicate the packet duration + for each stream. +The actual length of each missing Opus frame inside the packet is zero bytes, + as defined in Section 3.2.1 of . + + + +Zero-byte frames MAY be packed into packets using any of codes 0, 1, + 2, or 3. +When successive frames have the same configuration, the higher code packings + reduce overhead. +Likewise, if the TOC configuration matches, the muxer MAY further combine the + empty frames with previous or subsequent non-zero-length frames (using + code 2 or VBR code 3). + + + + does not impose any requirements on the PLC, but this + section outlines choices that are expected to have a positive influence on + most PLC implementations, including the reference implementation. +Synthesized TOC sequences SHOULD maintain the same mode, audio bandwidth, + channel count, and frame size as the previous packet (if any). +This is the simplest and usually the most well-tested case for the PLC to + handle and it covers all losses that do not include a configuration switch, + as defined in Section 4.5 of . + + + +When a previous packet is available, keeping the audio bandwidth and channel + count the same allows the PLC to provide maximum continuity in the concealment + data it generates. +However, if the size of the gap is not a multiple of the most recent frame + size, then the frame size will have to change for at least some frames. +Such changes SHOULD be delayed as long as possible to simplify + things for PLC implementations. + + + +As an example, a 95 ms gap could be encoded as nineteen 5 ms frames + in two bytes with a single CBR code 3 packet. +If the previous frame size was 20 ms, using four 20 ms frames + followed by three 5 ms frames requires 4 bytes (plus an extra byte + of Ogg lacing overhead), but allows the PLC to use its well-tested steady + state behavior for as long as possible. +The total bitrate of the latter approach, including Ogg overhead, is about + 0.4 kbps, so the impact on file size is minimal. + + + +Changing modes is discouraged, since this causes some decoder implementations + to reset their PLC state. +However, SILK and Hybrid mode frames cannot fill gaps that are not a multiple + of 10 ms. +If switching to CELT mode is needed to match the gap size, a muxer SHOULD do + so at the end of the gap to allow the PLC to function for as long as possible. + + + +In the example above, if the previous frame was a 20 ms SILK mode frame, + the better solution is to synthesize a packet describing four 20 ms SILK + frames, followed by a packet with a single 10 ms SILK + frame, and finally a packet with a 5 ms CELT frame, to fill the 95 ms + gap. +This also requires four bytes to describe the synthesized packet data (two + bytes for a CBR code 3 and one byte each for two code 0 packets) but three + bytes of Ogg lacing overhead are needed to mark the packet boundaries. +At 0.6 kbps, this is still a minimal bitrate impact over a naive, low quality + solution. + + + +Since medium-band audio is an option only in the SILK mode, wideband frames + SHOULD be generated if switching from that configuration to CELT mode, to + ensure that any PLC implementation which does try to migrate state between + the modes will be able to preserve all of the available audio bandwidth. + + +
    + +
    + +There is some amount of latency introduced during the decoding process, to + allow for overlap in the CELT mode, stereo mixing in the SILK mode, and + resampling. +The encoder might have introduced additional latency through its own resampling + and analysis (though the exact amount is not specified). +Therefore, the first few samples produced by the decoder do not correspond to + real input audio, but are instead composed of padding inserted by the encoder + to compensate for this latency. +These samples need to be stored and decoded, as Opus is an asymptotically + convergent predictive codec, meaning the decoded contents of each frame depend + on the recent history of decoder inputs. +However, a player will want to skip these samples after decoding them. + + + +A 'pre-skip' field in the ID header (see ) signals + the number of samples that SHOULD be skipped (decoded but discarded) at the + beginning of the stream, though some specific applications might have a reason + for looking at that data. +This amount need not be a multiple of 2.5 ms, MAY be smaller than a single + packet, or MAY span the contents of several packets. +These samples are not valid audio. + + + +For example, if the first Opus frame uses the CELT mode, it will always + produce 120 samples of windowed overlap-add data. +However, the overlap data is initially all zeros (since there is no prior + frame), meaning this cannot, in general, accurately represent the original + audio. +The SILK mode requires additional delay to account for its analysis and + resampling latency. +The encoder delays the original audio to avoid this problem. + + + +The pre-skip field MAY also be used to perform sample-accurate cropping of + already encoded streams. +In this case, a value of at least 3840 samples (80 ms) provides + sufficient history to the decoder that it will have converged + before the stream's output begins. + + +
    + +
    + +The PCM sample position is determined from the granule position using the + formula + +
    + +
    + + +For example, if the granule position of the first audio data page is 59,971, + and the pre-skip is 11,971, then the PCM sample position of the last decoded + sample from that page is 48,000. + + +This can be converted into a playback time using the formula + +
    + +
    + + +The initial PCM sample position before any samples are played is normally '0'. +In this case, the PCM sample position of the first audio sample to be played + starts at '1', because it marks the time on the clock + after that sample has been played, and a stream + that is exactly one second long has a final PCM sample position of '48000', + as in the example here. + + + +Vorbis streams use a granule position smaller than the number of audio samples + contained in the first audio data page to indicate that some of those samples + are trimmed from the output (see ). +However, to do so, Vorbis requires that the first audio data page contains + exactly two packets, in order to allow the decoder to perform PCM position + adjustments before needing to return any PCM data. +Opus uses the pre-skip mechanism for this purpose instead, since the encoder + might introduce more than a single packet's worth of latency, and since very + large packets in streams with a very large number of channels might not fit + on a single page. + +
    + +
    + +The page with the 'end of stream' flag set MAY have a granule position that + indicates the page contains less audio data than would normally be returned by + decoding up through the final packet. +This is used to end the stream somewhere other than an even frame boundary. +The granule position of the most recent audio data page with completed packets + is used to make this determination, or '0' is used if there were no previous + audio data pages with a completed packet. +The difference between these granule positions indicates how many samples to + keep after decoding the packets that completed on the final page. +The remaining samples are discarded. +The number of discarded samples SHOULD be no larger than the number decoded + from the last packet. + +
    + +
    + +The granule position of the first audio data page with a completed packet MAY + be larger than the number of samples contained in packets that complete on + that page, however it MUST NOT be smaller, unless that page has the 'end of + stream' flag set. +Allowing a granule position larger than the number of samples allows the + beginning of a stream to be cropped or a live stream to be joined without + rewriting the granule position of all the remaining pages. +This means that the PCM sample position just before the first sample to be + played MAY be larger than '0'. +Synchronization when multiplexing with other logical streams still uses the PCM + sample position relative to '0' to compute sample times. +This does not affect the behavior of pre-skip: exactly 'pre-skip' samples + SHOULD be skipped from the beginning of the decoded output, even if the + initial PCM sample position is greater than zero. + + + +On the other hand, a granule position that is smaller than the number of + decoded samples prevents a demuxer from working backwards to assign each + packet or each individual sample a valid granule position, since granule + positions are non-negative. +An implementation MUST treat any stream as invalid if the granule position + is smaller than the number of samples contained in packets that complete on + the first audio data page with a completed packet, unless that page has the + 'end of stream' flag set. +It MAY defer this action until it decodes the last packet completed on that + page. + + + +If that page has the 'end of stream' flag set, a demuxer MUST treat any stream + as invalid if its granule position is smaller than the 'pre-skip' amount. +This would indicate that there are more samples to be skipped from the initial + decoded output than exist in the stream. +If the granule position is smaller than the number of decoded samples produced + by the packets that complete on that page, then a demuxer MUST use an initial + granule position of '0', and can work forwards from '0' to timestamp + individual packets. +If the granule position is larger than the number of decoded samples available, + then the demuxer MUST still work backwards as described above, even if the + 'end of stream' flag is set, to determine the initial granule position, and + thus the initial PCM sample position. +Both of these will be greater than '0' in this case. + +
    + +
    + +Seeking in Ogg files is best performed using a bisection search for a page + whose granule position corresponds to a PCM position at or before the seek + target. +With appropriately weighted bisection, accurate seeking can be performed in + just one or two bisections on average, even in multi-gigabyte files. +See for an example of general implementation guidance. + + + +When seeking within an Ogg Opus stream, an implementation SHOULD start decoding + (and discarding the output) at least 3840 samples (80 ms) prior to + the seek target in order to ensure that the output audio is correct by the + time it reaches the seek target. +This 'pre-roll' is separate from, and unrelated to, the 'pre-skip' used at the + beginning of the stream. +If the point 80 ms prior to the seek target comes before the initial PCM + sample position, an implementation SHOULD start decoding from the beginning of + the stream, applying pre-skip as normal, regardless of whether the pre-skip is + larger or smaller than 80 ms, and then continue to discard samples + to reach the seek target (if any). + +
    + +
    + +
    + +An Ogg Opus logical stream contains exactly two mandatory header packets: + an identification header and a comment header. + + +
    + +
    + +
    + + +The fields in the identification (ID) header have the following meaning: + +Magic Signature: + +This is an 8-octet (64-bit) field that allows codec identification and is + human-readable. +It contains, in order, the magic numbers: + +0x4F 'O' +0x70 'p' +0x75 'u' +0x73 's' +0x48 'H' +0x65 'e' +0x61 'a' +0x64 'd' + +Starting with "Op" helps distinguish it from audio data packets, as this is an + invalid TOC sequence. + + +Version (8 bits, unsigned): + +The version number MUST always be '1' for this version of the encapsulation + specification. +Implementations SHOULD treat streams where the upper four bits of the version + number match that of a recognized specification as backwards-compatible with + that specification. +That is, the version number can be split into "major" and "minor" version + sub-fields, with changes to the "minor" sub-field (in the lower four bits) + signaling compatible changes. +For example, an implementation of this specification SHOULD accept any stream + with a version number of '15' or less, and SHOULD assume any stream with a + version number '16' or greater is incompatible. +The initial version '1' was chosen to keep implementations from relying on this + octet as a null terminator for the "OpusHead" string. + + +Output Channel Count 'C' (8 bits, unsigned): + +This is the number of output channels. +This might be different than the number of encoded channels, which can change + on a packet-by-packet basis. +This value MUST NOT be zero. +The maximum allowable value depends on the channel mapping family, and might be + as large as 255. +See for details. + + +Pre-skip (16 bits, unsigned, little + endian): + +This is the number of samples (at 48 kHz) to discard from the decoder + output when starting playback, and also the number to subtract from a page's + granule position to calculate its PCM sample position. +When cropping the beginning of existing Ogg Opus streams, a pre-skip of at + least 3,840 samples (80 ms) is RECOMMENDED to ensure complete + convergence in the decoder. + + +Input Sample Rate (32 bits, unsigned, little + endian): + +This is the sample rate of the original input (before encoding), in Hz. +This field is not the sample rate to use for + playback of the encoded data. + +Opus can switch between internal audio bandwidths of 4, 6, 8, 12, and + 20 kHz. +Each packet in the stream can have a different audio bandwidth. +Regardless of the audio bandwidth, the reference decoder supports decoding any + stream at a sample rate of 8, 12, 16, 24, or 48 kHz. +The original sample rate of the audio passed to the encoder is not preserved + by the lossy compression. + +An Ogg Opus player SHOULD select the playback sample rate according to the + following procedure: + +If the hardware supports 48 kHz playback, decode at 48 kHz. +Otherwise, if the hardware's highest available sample rate is a supported + rate, decode at this sample rate. +Otherwise, if the hardware's highest available sample rate is less than + 48 kHz, decode at the next higher Opus supported rate above the highest + available hardware rate and resample. +Otherwise, decode at 48 kHz and resample. + +However, the 'Input Sample Rate' field allows the muxer to pass the sample + rate of the original input stream as metadata. +This is useful when the user requires the output sample rate to match the + input sample rate. +For example, when not playing the output, an implementation writing PCM format + samples to disk might choose to resample the audio back to the original input + sample rate to reduce surprise to the user, who might reasonably expect to get + back a file with the same sample rate. + +A value of zero indicates 'unspecified'. +Muxers SHOULD write the actual input sample rate or zero, but implementations + which do something with this field SHOULD take care to behave sanely if given + crazy values (e.g., do not actually upsample the output to 10 MHz if + requested). +Implementations SHOULD support input sample rates between 8 kHz and + 192 kHz (inclusive). +Rates outside this range MAY be ignored by falling back to the default rate of + 48 kHz instead. + + +Output Gain (16 bits, signed, little endian): + +This is a gain to be applied when decoding. +It is 20*log10 of the factor by which to scale the decoder output to achieve + the desired playback volume, stored in a 16-bit, signed, two's complement + fixed-point value with 8 fractional bits (i.e., + Q7.8 ). + +To apply the gain, an implementation could use +
    + +
    + where output_gain is the raw 16-bit value from the header. + +Players and media frameworks SHOULD apply it by default. +If a player chooses to apply any volume adjustment or gain modification, such + as the R128_TRACK_GAIN (see ), the adjustment + MUST be applied in addition to this output gain in order to achieve playback + at the normalized volume. + +A muxer SHOULD set this field to zero, and instead apply any gain prior to + encoding, when this is possible and does not conflict with the user's wishes. +A nonzero output gain indicates the gain was adjusted after encoding, or that + a user wished to adjust the gain for playback while preserving the ability + to recover the original signal amplitude. + +Although the output gain has enormous range (+/- 128 dB, enough to amplify + inaudible sounds to the threshold of physical pain), most applications can + only reasonably use a small portion of this range around zero. +The large range serves in part to ensure that gain can always be losslessly + transferred between OpusHead and R128 gain tags (see below) without + saturating. + +
    +Channel Mapping Family (8 bits, unsigned): + +This octet indicates the order and semantic meaning of the output channels. + +Each currently specified value of this octet indicates a mapping family, which + defines a set of allowed channel counts, and the ordered set of channel names + for each allowed channel count. +The details are described in . + +Channel Mapping Table: +This table defines the mapping from encoded streams to output channels. +Its contents are specified in . + +
    +
    + + +All fields in the ID headers are REQUIRED, except for the channel mapping + table, which MUST be omitted when the channel mapping family is 0, but + is REQUIRED otherwise. +Implementations SHOULD treat a stream as invalid if it contains an ID header + that does not have enough data for these fields, even if it contain a valid + Magic Signature. +Future versions of this specification, even backwards-compatible versions, + might include additional fields in the ID header. +If an ID header has a compatible major version, but a larger minor version, + an implementation MUST NOT treat it as invalid for containing additional data + not specified here, provided it still completes on the first page. + + +
    + +An Ogg Opus stream allows mapping one number of Opus streams (N) to a possibly + larger number of decoded channels (M + N) to yet another number of + output channels (C), which might be larger or smaller than the number of + decoded channels. +The order and meaning of these channels are defined by a channel mapping, + which consists of the 'channel mapping family' octet and, for channel mapping + families other than family 0, a channel mapping table, as illustrated in + . + + +
    + +
    + + +The fields in the channel mapping table have the following meaning: + +Stream Count 'N' (8 bits, unsigned): + +This is the total number of streams encoded in each Ogg packet. +This value is necessary to correctly parse the packed Opus packets inside an + Ogg packet, as described in . +This value MUST NOT be zero, as without at least one Opus packet with a valid + TOC sequence, a demuxer cannot recover the duration of an Ogg packet. + +For channel mapping family 0, this value defaults to 1, and is not coded. + + +Coupled Stream Count 'M' (8 bits, unsigned): +This is the number of streams whose decoders are to be configured to produce + two channels (stereo). +This MUST be no larger than the total number of streams, N. + +Each packet in an Opus stream has an internal channel count of 1 or 2, which + can change from packet to packet. +This is selected by the encoder depending on the bitrate and the audio being + encoded. +The original channel count of the audio passed to the encoder is not + necessarily preserved by the lossy compression. + +Regardless of the internal channel count, any Opus stream can be decoded as + mono (a single channel) or stereo (two channels) by appropriate initialization + of the decoder. +The 'coupled stream count' field indicates that the decoders for the first M + Opus streams are to be initialized for stereo (two-channel) output, and the + remaining (N - M) decoders are to be initialized for mono (a single + channel) only. +The total number of decoded channels, (M + N), MUST be no larger than + 255, as there is no way to index more channels than that in the channel + mapping. + +For channel mapping family 0, this value defaults to (C - 1) + (i.e., 0 for mono and 1 for stereo), and is not coded. + + +Channel Mapping (8*C bits): +This contains one octet per output channel, indicating which decoded channel + is to be used for each one. +Let 'index' be the value of this octet for a particular output channel. +This value MUST either be smaller than (M + N), or be the special + value 255. +If 'index' is less than 2*M, the output MUST be taken from decoding stream + ('index'/2) as stereo and selecting the left channel if 'index' is even, and + the right channel if 'index' is odd. +If 'index' is 2*M or larger, but less than 255, the output MUST be taken from + decoding stream ('index' - M) as mono. +If 'index' is 255, the corresponding output channel MUST contain pure silence. + +The number of output channels, C, is not constrained to match the number of + decoded channels (M + N). +A single index value MAY appear multiple times, i.e., the same decoded channel + might be mapped to multiple output channels. +Some decoded channels might not be assigned to any output channel, as well. + +For channel mapping family 0, the first index defaults to 0, and if + C == 2, the second index defaults to 1. +Neither index is coded. + + + + + +After producing the output channels, the channel mapping family determines the + semantic meaning of each one. +There are three defined mapping families in this specification. + + +
    + +Allowed numbers of channels: 1 or 2. +RTP mapping. +This is the same channel interpretation as . + + + +1 channel: monophonic (mono). +2 channels: stereo (left, right). + +Special mapping: This channel mapping value also + indicates that the contents consists of a single Opus stream that is stereo if + and only if C == 2, with stream index 0 mapped to output + channel 0 (mono, or left channel) and stream index 1 mapped to + output channel 1 (right channel) if stereo. +When the 'channel mapping family' octet has this value, the channel mapping + table MUST be omitted from the ID header packet. + +
    + +
    + +Allowed numbers of channels: 1...8. +Vorbis channel order (see below). + + +Each channel is assigned to a speaker location in a conventional surround + arrangement. +Specific locations depend on the number of channels, and are given below + in order of the corresponding channel indices. + + 1 channel: monophonic (mono). + 2 channels: stereo (left, right). + 3 channels: linear surround (left, center, right) + 4 channels: quadraphonic (front left, front right, rear left, rear right). + 5 channels: 5.0 surround (front left, front center, front right, rear left, rear right). + 6 channels: 5.1 surround (front left, front center, front right, rear left, rear right, LFE). + 7 channels: 6.1 surround (front left, front center, front right, side left, side right, rear center, LFE). + 8 channels: 7.1 surround (front left, front center, front right, side left, side right, rear left, rear right, LFE) + + + +This set of surround options and speaker location orderings is the same + as those used by the Vorbis codec . +The ordering is different from the one used by the + WAVE and + Free Lossless Audio Codec (FLAC) formats, + so correct ordering requires permutation of the output channels when decoding + to or encoding from those formats. +'LFE' here refers to a Low Frequency Effects channel, often mapped to a + subwoofer with no particular spatial position. +Implementations SHOULD identify 'side' or 'rear' speaker locations with + 'surround' and 'back' as appropriate when interfacing with audio formats + or systems which prefer that terminology. + +
    + +
    + +Allowed numbers of channels: 1...255. +No defined channel meaning. + + +Channels are unidentified. +General-purpose players SHOULD NOT attempt to play these streams. +Offline implementations MAY deinterleave the output into separate PCM files, + one per channel. +Implementations SHOULD NOT produce output for channels mapped to stream index + 255 (pure silence) unless they have no other way to indicate the index of + non-silent channels. + +
    + +
    + +The remaining channel mapping families (2...254) are reserved. +A demuxer implementation encountering a reserved channel mapping family value + SHOULD act as though the value is 255. + +
    + +
    + +An Ogg Opus player MUST support any valid channel mapping with a channel + mapping family of 0 or 1, even if the number of channels does not match the + physically connected audio hardware. +Players SHOULD perform channel mixing to increase or reduce the number of + channels as needed. + + + +Implementations MAY use the matrices in + Figures  + through  to implement + downmixing from multichannel files using + Channel Mapping Family 1, which are + known to give acceptable results for stereo. +Matrices for 3 and 4 channels are normalized so each coefficient row sums + to 1 to avoid clipping. +For 5 or more channels they are normalized to 2 as a compromise between + clipping and dynamic range reduction. + + +In these matrices the front left and front right channels are generally +passed through directly. +When a surround channel is split between both the left and right stereo + channels, coefficients are chosen so their squares sum to 1, which + helps preserve the perceived intensity. +Rear channels are mixed more diffusely or attenuated to maintain focus + on the front channels. + + +
    + + +Exact coefficient values are 1 and 1/sqrt(2), multiplied by + 1/(1 + 1/sqrt(2)) for normalization. + +
    + +
    + + +Exact coefficient values are 1, sqrt(3)/2 and 1/2, multiplied by + 1/(1 + sqrt(3)/2 + 1/2) for normalization. + +
    + +
    + + +Exact coefficient values are 1, 1/sqrt(2), sqrt(3)/2 and 1/2, multiplied by + 2/(1 + 1/sqrt(2) + sqrt(3)/2 + 1/2) + for normalization. + +
    + +
    + + +Exact coefficient values are 1, 1/sqrt(2), sqrt(3)/2 and 1/2, multiplied by +2/(1 + 1/sqrt(2) + sqrt(3)/2 + 1/2 + 1/sqrt(2)) + for normalization. + +
    + +
    + + +Exact coefficient values are 1, 1/sqrt(2), sqrt(3)/2, 1/2 and + sqrt(3)/2/sqrt(2), multiplied by + 2/(1 + 1/sqrt(2) + sqrt(3)/2 + 1/2 + + sqrt(3)/2/sqrt(2) + 1/sqrt(2)) for normalization. +The coefficients are in the same order as in , + and the matrices above. + +
    + +
    + + +Exact coefficient values are 1, 1/sqrt(2), sqrt(3)/2 and 1/2, multiplied by + 2/(2 + 2/sqrt(2) + sqrt(3)) for normalization. +The coefficients are in the same order as in , + and the matrices above. + +
    + +
    + +
    + +
    + +
    + +
    + +
    + + +The comment header consists of a 64-bit magic signature, followed by data in + the same format as the header used in Ogg + Vorbis, except (like Ogg Theora and Speex) the final "framing bit" specified + in the Vorbis spec is not present. + +Magic Signature: + +This is an 8-octet (64-bit) field that allows codec identification and is + human-readable. +It contains, in order, the magic numbers: + +0x4F 'O' +0x70 'p' +0x75 'u' +0x73 's' +0x54 'T' +0x61 'a' +0x67 'g' +0x73 's' + +Starting with "Op" helps distinguish it from audio data packets, as this is an + invalid TOC sequence. + + +Vendor String Length (32 bits, unsigned, little endian): + +This field gives the length of the following vendor string, in octets. +It MUST NOT indicate that the vendor string is longer than the rest of the + packet. + + +Vendor String (variable length, UTF-8 vector): + +This is a simple human-readable tag for vendor information, encoded as a UTF-8 + string . +No terminating null octet is necessary. + +This tag is intended to identify the codec encoder and encapsulation + implementations, for tracing differences in technical behavior. +User-facing applications can use the 'ENCODER' user comment tag to identify + themselves. + + +User Comment List Length (32 bits, unsigned, little endian): + +This field indicates the number of user-supplied comments. +It MAY indicate there are zero user-supplied comments, in which case there are + no additional fields in the packet. +It MUST NOT indicate that there are so many comments that the comment string + lengths would require more data than is available in the rest of the packet. + + +User Comment #i String Length (32 bits, unsigned, little endian): + +This field gives the length of the following user comment string, in octets. +There is one for each user comment indicated by the 'user comment list length' + field. +It MUST NOT indicate that the string is longer than the rest of the packet. + + +User Comment #i String (variable length, UTF-8 vector): + +This field contains a single user comment encoded as a UTF-8 + string . +There is one for each user comment indicated by the 'user comment list length' + field. + + + + + +The vendor string length and user comment list length are REQUIRED, and + implementations SHOULD treat a stream as invalid if it contains a comment + header that does not have enough data for these fields, or that does not + contain enough data for the corresponding vendor string or user comments they + describe. +Making this check before allocating the associated memory to contain the data + helps prevent a possible Denial-of-Service (DoS) attack from small comment + headers that claim to contain strings longer than the entire packet or more + user comments than than could possibly fit in the packet. + + + +Immediately following the user comment list, the comment header MAY + contain zero-padding or other binary data which is not specified here. +If the least-significant bit of the first byte of this data is 1, then editors + SHOULD preserve the contents of this data when updating the tags, but if this + bit is 0, all such data MAY be treated as padding, and truncated or discarded + as desired. +This allows informal experimentation with the format of this binary data until + it can be specified later. + + + +The comment header can be arbitrarily large and might be spread over a large + number of Ogg pages. +Implementations MUST avoid attempting to allocate excessive amounts of memory + when presented with a very large comment header. +To accomplish this, implementations MAY treat a stream as invalid if it has a + comment header larger than 125,829,120 octets (120 MB), and MAY + ignore individual comments that are not fully contained within the first + 61,440 octets of the comment header. + + +
    + +The user comment strings follow the NAME=value format described by + with the same recommended tag names: + ARTIST, TITLE, DATE, ALBUM, and so on. + + +Two new comment tags are introduced here: + + +First, an optional gain for track normalization: +
    + +
    + + representing the volume shift needed to normalize the track's volume + during isolated playback, in random shuffle, and so on. +The gain is a Q7.8 fixed point number in dB, as in the ID header's 'output + gain' field. +This tag is similar to the REPLAYGAIN_TRACK_GAIN tag in + Vorbis , except that the normal volume + reference is the standard. + +Second, an optional gain for album normalization: +
    + +
    + + representing the volume shift needed to normalize the overall volume when + played as part of a particular collection of tracks. +The gain is also a Q7.8 fixed point number in dB, as in the ID header's + 'output gain' field. +The values '-573' and '111' given here are just examples. + + +An Ogg Opus stream MUST NOT have more than one of each of these tags, and if + present their values MUST be an integer from -32768 to 32767, inclusive, + represented in ASCII as a base 10 number with no whitespace. +A leading '+' or '-' character is valid. +Leading zeros are also permitted, but the value MUST be represented by + no more than 6 characters. +Other non-digit characters MUST NOT be present. + + +If present, R128_TRACK_GAIN and R128_ALBUM_GAIN MUST correctly represent + the R128 normalization gain relative to the 'output gain' field specified + in the ID header. +If a player chooses to make use of the R128_TRACK_GAIN tag or the + R128_ALBUM_GAIN tag, it MUST apply those gains + in addition to the 'output gain' value. +If a tool modifies the ID header's 'output gain' field, it MUST also update or + remove the R128_TRACK_GAIN and R128_ALBUM_GAIN comment tags if present. +A muxer SHOULD place the gain it wants other tools to use by default into the + 'output gain' field, and not the comment tag. + + +To avoid confusion with multiple normalization schemes, an Opus comment header + SHOULD NOT contain any of the REPLAYGAIN_TRACK_GAIN, REPLAYGAIN_TRACK_PEAK, + REPLAYGAIN_ALBUM_GAIN, or REPLAYGAIN_ALBUM_PEAK tags, unless they are only + to be used in some context where there is guaranteed to be no such confusion. + normalization is preferred to the earlier + REPLAYGAIN schemes because of its clear definition and adoption by industry. +Peak normalizations are difficult to calculate reliably for lossy codecs + because of variation in excursion heights due to decoder differences. +In the authors' investigations they were not applied consistently or broadly + enough to merit inclusion here. + +
    +
    + +
    + +
    + +Technically, valid Opus packets can be arbitrarily large due to the padding + format, although the amount of non-padding data they can contain is bounded. +These packets might be spread over a similarly enormous number of Ogg pages. +When encoding, implementations SHOULD limit the use of padding in audio data + packets to no more than is necessary to make a variable bitrate (VBR) stream + constant bitrate (CBR), unless they have no reasonable way to determine what + is necessary. +Demuxers SHOULD treat audio data packets as invalid (treat them as if they were + malformed Opus packets with an invalid TOC sequence) if they are larger than + 61,440 octets per Opus stream, unless they have a specific reason for + allowing extra padding. +Such packets necessarily contain more padding than needed to make a stream CBR. +Demuxers MUST avoid attempting to allocate excessive amounts of memory when + presented with a very large packet. +Demuxers MAY treat audio data packets as invalid or partially process them if + they are larger than 61,440 octets in an Ogg Opus stream with channel + mapping families 0 or 1. +Demuxers MAY treat audio data packets as invalid or partially process them in + any Ogg Opus stream if the packet is larger than 61,440 octets and also + larger than 7,680 octets per Opus stream. +The presence of an extremely large packet in the stream could indicate a + memory exhaustion attack or stream corruption. + + +In an Ogg Opus stream, the largest possible valid packet that does not use + padding has a size of (61,298*N - 2) octets. +With 255 streams, this is 15,630,988 octets and can + span up to 61,298 Ogg pages, all but one of which will have a granule + position of -1. +This is of course a very extreme packet, consisting of 255 streams, each + containing 120 ms of audio encoded as 2.5 ms frames, each frame + using the maximum possible number of octets (1275) and stored in the least + efficient manner allowed (a VBR code 3 Opus packet). +Even in such a packet, most of the data will be zeros as 2.5 ms frames + cannot actually use all 1275 octets. + + +The largest packet consisting of entirely useful data is + (15,326*N - 2) octets. +This corresponds to 120 ms of audio encoded as 10 ms frames in either + SILK or Hybrid mode, but at a data rate of over 1 Mbps, which makes little + sense for the quality achieved. + + +A more reasonable limit is (7,664*N - 2) octets. +This corresponds to 120 ms of audio encoded as 20 ms stereo CELT mode + frames, with a total bitrate just under 511 kbps (not counting the Ogg + encapsulation overhead). +For channel mapping family 1, N=8 provides a reasonable upper bound, as it + allows for each of the 8 possible output channels to be decoded from a + separate stereo Opus stream. +This gives a size of 61,310 octets, which is rounded up to a multiple of + 1,024 octets to yield the audio data packet size of 61,440 octets + that any implementation is expected to be able to process successfully. + +
    + +
    + +When encoding Opus streams, Ogg muxers SHOULD take into account the + algorithmic delay of the Opus encoder. + + +In encoders derived from the reference + implementation , the number of samples can be + queried with: + +
    + +
    + +To achieve good quality in the very first samples of a stream, implementations + MAY use linear predictive coding (LPC) extrapolation to generate at least 120 + extra samples at the beginning to avoid the Opus encoder having to encode a + discontinuous signal. +For more information on linear prediction, see + . +For an input file containing 'length' samples, the implementation SHOULD set + the pre-skip header value to (delay_samples + extra_samples), encode + at least (length + delay_samples + extra_samples) + samples, and set the granule position of the last page to + (length + delay_samples + extra_samples). +This ensures that the encoded file has the same duration as the original, with + no time offset. The best way to pad the end of the stream is to also use LPC + extrapolation, but zero-padding is also acceptable. + + +
    + +The first step in LPC extrapolation is to compute linear prediction + coefficients. +When extending the end of the signal, order-N (typically with N ranging from 8 + to 40) LPC analysis is performed on a window near the end of the signal. +The last N samples are used as memory to an infinite impulse response (IIR) + filter. + + +The filter is then applied on a zero input to extrapolate the end of the signal. +Let a(k) be the kth LPC coefficient and x(n) be the nth sample of the signal, + each new sample past the end of the signal is computed as: + +
    + +
    + +The process is repeated independently for each channel. +It is possible to extend the beginning of the signal by applying the same + process backward in time. +When extending the beginning of the signal, it is best to apply a "fade in" to + the extrapolated signal, e.g. by multiplying it by a half-Hanning window + . + + +
    + +
    + +In some applications, such as Internet radio, it is desirable to cut a long + stream into smaller chains, e.g. so the comment header can be updated. +This can be done simply by separating the input streams into segments and + encoding each segment independently. +The drawback of this approach is that it creates a small discontinuity + at the boundary due to the lossy nature of Opus. +A muxer MAY avoid this discontinuity by using the following procedure: + +Encode the last frame of the first segment as an independent frame by + turning off all forms of inter-frame prediction. +De-emphasis is allowed. +Set the granule position of the last page to a point near the end of the + last frame. +Begin the second segment with a copy of the last frame of the first + segment. +Set the pre-skip value of the second stream in such a way as to properly + join the two streams. +Continue the encoding process normally from there, without any reset to + the encoder. + + + +In encoders derived from the reference implementation, inter-frame prediction + can be turned off by calling: + +
    + +
    + +For best results, this implementation requires that prediction be explicitly + enabled again before resuming normal encoding, even after a reset. + + +
    + +
    + +
    + +A brief summary of major implementations of this draft is available + at , + along with their status. + + +[Note to RFC Editor: please remove this entire section before + final publication per , along with + its references.] + +
    + +
    + +Implementations of the Opus codec need to take appropriate security + considerations into account, as outlined in . +This is just as much a problem for the container as it is for the codec itself. +Malicious payloads and/or input streams can be used to attack codec + implementations. +Implementations MUST NOT overrun their allocated memory nor consume excessive + resources when decoding payloads or processing input streams. +Although problems in encoding applications are typically rarer, this still + applies to a muxer, as vulnerabilities would allow an attacker to attack + transcoding gateways. + + + +Header parsing code contains the most likely area for potential overruns. +It is important for implementations to ensure their buffers contain enough + data for all of the required fields before attempting to read it (for example, + for all of the channel map data in the ID header). +Implementations would do well to validate the indices of the channel map, also, + to ensure they meet all of the restrictions outlined in + , in order to avoid attempting to read data + from channels that do not exist. + + + +To avoid excessive resource usage, we advise implementations to be especially + wary of streams that might cause them to process far more data than was + actually transmitted. +For example, a relatively small comment header may contain values for the + string lengths or user comment list length that imply that it is many + gigabytes in size. +Even computing the size of the required buffer could overflow a 32-bit integer, + and actually attempting to allocate such a buffer before verifying it would be + a reasonable size is a bad idea. +After reading the user comment list length, implementations might wish to + verify that the header contains at least the minimum amount of data for that + many comments (4 additional octets per comment, to indicate each has a + length of zero) before proceeding any further, again taking care to avoid + overflow in these calculations. +If allocating an array of pointers to point at these strings, the size of the + pointers may be larger than 4 octets, potentially requiring a separate + overflow check. + + + +Another bug in this class we have observed more than once involves the handling + of invalid data at the end of a stream. +Often, implementations will seek to the end of a stream to locate the last + timestamp in order to compute its total duration. +If they do not find a valid capture pattern and Ogg page from the desired + logical stream, they will back up and try again. +If care is not taken to avoid re-scanning data that was already scanned, this + search can quickly devolve into something with a complexity that is quadratic + in the amount of invalid data. + + + +In general when seeking, implementations will wish to be cautious about the + effects of invalid granule position values, and ensure all algorithms will + continue to make progress and eventually terminate, even if these are missing + or out-of-order. + + + +Like most other container formats, Ogg Opus streams SHOULD NOT be used with + insecure ciphers or cipher modes that are vulnerable to known-plaintext + attacks. +Elements such as the Ogg page capture pattern and the magic signatures in the + ID header and the comment header all have easily predictable values, in + addition to various elements of the codec data itself. + +
    + +
    + +An "Ogg Opus file" consists of one or more sequentially multiplexed segments, + each containing exactly one Ogg Opus stream. +The RECOMMENDED mime-type for Ogg Opus files is "audio/ogg". + + + +If more specificity is desired, one MAY indicate the presence of Opus streams + using the codecs parameter defined in and + , e.g., + +
    + +
    + + for an Ogg Opus file. + + + +The RECOMMENDED filename extension for Ogg Opus files is '.opus'. + + + +When Opus is concurrently multiplexed with other streams in an Ogg container, + one SHOULD use one of the "audio/ogg", "video/ogg", or "application/ogg" + mime-types, as defined in . +Such streams are not strictly "Ogg Opus files" as described above, + since they contain more than a single Opus stream per sequentially + multiplexed segment, e.g. video or multiple audio tracks. +In such cases the the '.opus' filename extension is NOT RECOMMENDED. + + + +In either case, this document updates + to add 'opus' as a codecs parameter value with char[8]: 'OpusHead' + as Codec Identifier. + +
    + +
    + +This document updates the IANA Media Types registry to add .opus + as a file extension for "audio/ogg", and to add itself as a reference + alongside for "audio/ogg", "video/ogg", and + "application/ogg" Media Types. + + +This document defines a new registry "Opus Channel Mapping Families" to + indicate how the semantic meanings of the channels in a multi-channel Opus + stream are described. +IANA is requested to create a new name space of "Opus Channel Mapping + Families". +This will be a new registry on the IANA Matrix, and not a subregistry of an + existing registry. +Modifications to this registry follow the "Specification Required" registration + policy as defined in . +Each registry entry consists of a Channel Mapping Family Number, which is + specified in decimal in the range 0 to 255, inclusive, and a Reference (or + list of references) +Each Reference must point to sufficient documentation to describe what + information is coded in the Opus identification header for this channel + mapping family, how a demuxer determines the Stream Count ('N') and Coupled + Stream Count ('M') from this information, and how it determines the proper + interpretation of each of the decoded channels. + + +This document defines three initial assignments for this registry. + + +ValueReference +0[RFCXXXX] +1[RFCXXXX] +255[RFCXXXX] + + +The designated expert will determine if the Reference points to a specification + that meets the requirements for permanence and ready availability laid out + in  and that it specifies the information + described above with sufficient clarity to allow interoperable + implementations. + +
    + +
    + +Thanks to Ben Campbell, Joel M. Halpern, Mark Harris, Greg Maxwell, + Christopher "Monty" Montgomery, Jean-Marc Valin, Stephan Wenger, and Mo Zanaty + for their valuable contributions to this document. +Additional thanks to Andrew D'Addesio, Greg Maxwell, and Vincent Penquerc'h for + their feedback based on early implementations. + +
    + +
    + +In , "RFCXXXX" is to be replaced with the RFC number + assigned to this draft. + +
    + +
    + + + &rfc2119; + &rfc3533; + &rfc3629; + &rfc5226; + &rfc5334; + &rfc6381; + &rfc6716; + + + + Loudness Recommendation EBU R128 + + EBU Technical Committee + + + + + + + +Ogg Vorbis I Format Specification: Comment Field and Header + Specification + + + + + + + + + + + &rfc4732; + &rfc6982; + &rfc7587; + + + + FLAC - Free Lossless Audio Codec Format Description + + + + + + + + Hann window + + Wikipedia + + + + + + + + Linear Predictive Coding + + Wikipedia + + + + + + + + Autocorrelation LPC coeff generation algorithm + (Vorbis source code) + + + + + + + + +Q (number format) +Wikipedia + + + + + + +VorbisComment: Replay Gain + + + + + + + + +Granulepos Encoding and How Seeking Really Works + + + + + + + + + +The Vorbis I Specification, Section 4.3.9 Output Channel Order + + + + + + + + The Vorbis I Specification, Appendix A: Embedding Vorbis + into an Ogg stream + + + + + + + + Multiple Channel Audio Data and WAVE Files + + Microsoft Corporation + + + + + + + + +
    diff --git a/extern/opus/doc/draft-ietf-codec-opus-update.xml b/extern/opus/doc/draft-ietf-codec-opus-update.xml new file mode 100644 index 0000000..3124e22 --- /dev/null +++ b/extern/opus/doc/draft-ietf-codec-opus-update.xml @@ -0,0 +1,513 @@ + + + + + + + + + + + + + + + Updates to the Opus Audio Codec + + +Mozilla Corporation +
    + +331 E. Evelyn Avenue +Mountain View +CA +94041 +USA + ++1 650 903-0800 +jmvalin@jmvalin.ca +
    +
    + + +vocTone +
    + + + + + + + + +koenvos74@gmail.com +
    +
    + + + + + + + This document addresses minor issues that were found in the specification + of the Opus audio codec in RFC 6716. It updates the normative decoder implementation + included in the appendix of RFC 6716. The changes fixes real and potential security-related + issues, as well minor quality-related issues. + +
    + + +
    + This document addresses minor issues that were discovered in the reference + implementation of the Opus codec. Unlike most IETF specifications, Opus is defined + in RFC 6716 in terms of a normative reference + decoder implementation rather than from the associated text description. + That RFC includes the reference decoder implementation as Appendix A. + That's why only issues affecting the decoder are + listed here. An up-to-date implementation of the Opus encoder can be found at + . + + Some of the changes in this document update normative behaviour in a way that requires + new test vectors. The English text of the specification is unaffected, only + the C implementation is. The updated specification remains fully compatible with + the original specification. + + + + Note: due to RFC formatting conventions, lines exceeding the column width + in the patch are split using a backslash character. The backslashes + at the end of a line and the white space at the beginning + of the following line are not part of the patch. A properly formatted patch + including all changes is available at + + and has a SHA-1 hash of 029e3aa88fc342c91e67a21e7bfbc9458661cd5f. + + +
    + +
    + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this + document are to be interpreted as described in RFC 2119. +
    + +
    + The reference implementation does not reinitialize the stereo state + during a mode switch. The old stereo memory can produce a brief impulse + (i.e. single sample) in the decoded audio. This can be fixed by changing + silk/dec_API.c at line 72: + +
    + + for( n = 0; n < DECODER_NUM_CHANNELS; n++ ) { + ret = silk_init_decoder( &channel_state[ n ] ); + } ++ silk_memset(&((silk_decoder *)decState)->sStereo, 0, ++ sizeof(((silk_decoder *)decState)->sStereo)); ++ /* Not strictly needed, but it's cleaner that way */ ++ ((silk_decoder *)decState)->prev_decode_only_middle = 0; + + return ret; + } + +]]> +
    + + This change affects the normative output of the decoder, but the + amount of change is within the tolerance and too small to make the testvector check fail. + +
    + +
    + It was discovered that some invalid packets of very large size could trigger + an out-of-bounds read in the Opus packet parsing code responsible for padding. + This is due to an integer overflow if the signaled padding exceeds 2^31-1 bytes + (the actual packet may be smaller). The code can be fixed by decrementing the + (signed) len value, instead of incrementing a separate padding counter. + This is done by applying the following changes at line 596 of src/opus_decoder.c: + +
    + + /* Padding flag is bit 6 */ + if (ch&0x40) + { +- int padding=0; + int p; + do { + if (len<=0) + return OPUS_INVALID_PACKET; + p = *data++; + len--; +- padding += p==255 ? 254: p; ++ len -= p==255 ? 254: p; + } while (p==255); +- len -= padding; + } + +]]> +
    + This packet parsing issue is limited to reading memory up + to about 60 kB beyond the compressed buffer. This can only be triggered + by a compressed packet more than about 16 MB long, so it's not a problem + for RTP. In theory, it could crash a file + decoder (e.g. Opus in Ogg) if the memory just after the incoming packet + is out-of-range, but our attempts to trigger such a crash in a production + application built using an affected version of the Opus decoder failed. +
    + +
    + The SILK resampler had the following issues: + + The calls to memcpy() were using sizeof(opus_int32), but the type of the + local buffer was opus_int16. + Because the size was wrong, this potentially allowed the source + and destination regions of the memcpy() to overlap on the copy from "buf" to "buf". + We believe that nSamplesIn (number of input samples) is at least fs_in_khZ (sampling rate in kHz), + which is at least 8. + Since RESAMPLER_ORDER_FIR_12 is only 8, that should not be a problem once + the type size is fixed. + The size of the buffer used RESAMPLER_MAX_BATCH_SIZE_IN, but the + data stored in it was actually twice the input batch size + (nSamplesIn<<1). + + The code can be fixed by applying the following changes to line 78 of silk/resampler_private_IIR_FIR.c: + +
    + + ) + { + silk_resampler_state_struct *S = \ +(silk_resampler_state_struct *)SS; + opus_int32 nSamplesIn; + opus_int32 max_index_Q16, index_increment_Q16; +- opus_int16 buf[ RESAMPLER_MAX_BATCH_SIZE_IN + \ +RESAMPLER_ORDER_FIR_12 ]; ++ opus_int16 buf[ 2*RESAMPLER_MAX_BATCH_SIZE_IN + \ +RESAMPLER_ORDER_FIR_12 ]; + + /* Copy buffered samples to start of buffer */ +- silk_memcpy( buf, S->sFIR, RESAMPLER_ORDER_FIR_12 \ +* sizeof( opus_int32 ) ); ++ silk_memcpy( buf, S->sFIR, RESAMPLER_ORDER_FIR_12 \ +* sizeof( opus_int16 ) ); + + /* Iterate over blocks of frameSizeIn input samples */ + index_increment_Q16 = S->invRatio_Q16; + while( 1 ) { + nSamplesIn = silk_min( inLen, S->batchSize ); + + /* Upsample 2x */ + silk_resampler_private_up2_HQ( S->sIIR, &buf[ \ +RESAMPLER_ORDER_FIR_12 ], in, nSamplesIn ); + + max_index_Q16 = silk_LSHIFT32( nSamplesIn, 16 + 1 \ +); /* + 1 because 2x upsampling */ + out = silk_resampler_private_IIR_FIR_INTERPOL( out, \ +buf, max_index_Q16, index_increment_Q16 ); + in += nSamplesIn; + inLen -= nSamplesIn; + + if( inLen > 0 ) { + /* More iterations to do; copy last part of \ +filtered signal to beginning of buffer */ +- silk_memcpy( buf, &buf[ nSamplesIn << 1 ], \ +RESAMPLER_ORDER_FIR_12 * sizeof( opus_int32 ) ); ++ silk_memmove( buf, &buf[ nSamplesIn << 1 ], \ +RESAMPLER_ORDER_FIR_12 * sizeof( opus_int16 ) ); + } else { + break; + } + } + + /* Copy last part of filtered signal to the state for \ +the next call */ +- silk_memcpy( S->sFIR, &buf[ nSamplesIn << 1 ], \ +RESAMPLER_ORDER_FIR_12 * sizeof( opus_int32 ) ); ++ silk_memcpy( S->sFIR, &buf[ nSamplesIn << 1 ], \ +RESAMPLER_ORDER_FIR_12 * sizeof( opus_int16 ) ); + } + +]]> +
    +
    + +
    + + It was discovered through decoder fuzzing that some bitstreams could produce + integer values exceeding 32-bits in LPC_inverse_pred_gain_QA(), causing + a wrap-around. The C standard considers + this behavior as undefined. The following patch to line 87 of silk/LPC_inv_pred_gain.c + detects values that do not fit in a 32-bit integer and considers the corresponding filters unstable: + +
    + + /* Update AR coefficient */ + for( n = 0; n < k; n++ ) { +- tmp_QA = Aold_QA[ n ] - MUL32_FRAC_Q( \ +Aold_QA[ k - n - 1 ], rc_Q31, 31 ); +- Anew_QA[ n ] = MUL32_FRAC_Q( tmp_QA, rc_mult2 , mult2Q ); ++ opus_int64 tmp64; ++ tmp_QA = silk_SUB_SAT32( Aold_QA[ n ], MUL32_FRAC_Q( \ +Aold_QA[ k - n - 1 ], rc_Q31, 31 ) ); ++ tmp64 = silk_RSHIFT_ROUND64( silk_SMULL( tmp_QA, \ +rc_mult2 ), mult2Q); ++ if( tmp64 > silk_int32_MAX || tmp64 < silk_int32_MIN ) { ++ return 0; ++ } ++ Anew_QA[ n ] = ( opus_int32 )tmp64; + } + +]]> +
    +
    + +
    + + It was discovered -- also from decoder fuzzing -- that an integer wrap-around could + occur when decoding bitstreams with extremely large values for the high LSF parameters. + The end result of the wrap-around is an illegal read access on the stack, which + the authors do not believe is exploitable but should nonetheless be fixed. The following + patch to line 137 of silk/NLSF_stabilize.c prevents the problem: + +
    + + /* Keep delta_min distance between the NLSFs */ + for( i = 1; i < L; i++ ) +- NLSF_Q15[i] = silk_max_int( NLSF_Q15[i], \ +NLSF_Q15[i-1] + NDeltaMin_Q15[i] ); ++ NLSF_Q15[i] = silk_max_int( NLSF_Q15[i], \ +silk_ADD_SAT16( NLSF_Q15[i-1], NDeltaMin_Q15[i] ) ); + + /* Last NLSF should be no higher than 1 - NDeltaMin[L] */ + +]]> +
    + +
    + +
    + On extreme bit-streams, it is possible for log-domain band energy levels + to exceed the maximum single-precision floating point value once converted + to a linear scale. This would later cause the decoded values to be NaN (not a number), + possibly causing problems in the software using the PCM values. This can be + avoided with the following patch to line 552 of celt/quant_bands.c: + +
    + + { + opus_val16 lg = ADD16(oldEBands[i+c*m->nbEBands], + SHL16((opus_val16)eMeans[i],6)); ++ lg = MIN32(QCONST32(32.f, 16), lg); + eBands[i+c*m->nbEBands] = PSHR32(celt_exp2(lg),4); + } + for (;inbEBands;i++) + +]]> +
    +
    + +
    + When encoding in hybrid mode at low bitrate, we sometimes only have + enough bits to code a single CELT band (8 - 9.6 kHz). When that happens, + the second band (CELT band 18, from 9.6 to 12 kHz) cannot use folding + because it is wider than the amount already coded, and falls back to + white noise. Because it can also happen on transients (e.g. stops), it + can cause audible pre-echo. + + + To address the issue, we change the folding behavior so that it is + never forced to fall back to LCG due to the first band not containing + enough coefficients to fold onto the second band. This + is achieved by simply repeating part of the first band in the folding + of the second band. This changes the code in celt/bands.c around line 1237: + +
    + + b = 0; + } + +- if (resynth && M*eBands[i]-N >= M*eBands[start] && \ +(update_lowband || lowband_offset==0)) ++ if (resynth && (M*eBands[i]-N >= M*eBands[start] || \ +i==start+1) && (update_lowband || lowband_offset==0)) + lowband_offset = i; + ++ if (i == start+1) ++ { ++ int n1, n2; ++ int offset; ++ n1 = M*(eBands[start+1]-eBands[start]); ++ n2 = M*(eBands[start+2]-eBands[start+1]); ++ offset = M*eBands[start]; ++ /* Duplicate enough of the first band folding data to \ +be able to fold the second band. ++ Copies no data for CELT-only mode. */ ++ OPUS_COPY(&norm[offset+n1], &norm[offset+2*n1 - n2], n2-n1); ++ if (C==2) ++ OPUS_COPY(&norm2[offset+n1], &norm2[offset+2*n1 - n2], \ +n2-n1); ++ } ++ + tf_change = tf_res[i]; + if (i>=m->effEBands) + { + +]]> +
    + + + as well as line 1260: + + +
    + + fold_start = lowband_offset; + while(M*eBands[--fold_start] > effective_lowband); + fold_end = lowband_offset-1; +- while(M*eBands[++fold_end] < effective_lowband+N); ++ while(++fold_end < i && M*eBands[fold_end] < \ +effective_lowband+N); + x_cm = y_cm = 0; + fold_i = fold_start; do { + x_cm |= collapse_masks[fold_i*C+0]; + + +]]> +
    + + The fix does not impact compatibility, because the improvement does + not depend on the encoder doing anything special. There is also no + reasonable way for an encoder to use the original behavior to + improve quality over the proposed change. + +
    + +
    + The last issue is not strictly a bug, but it is an issue that has been reported + when downmixing an Opus decoded stream to mono, whether this is done inside the decoder + or as a post-processing step on the stereo decoder output. Opus intensity stereo allows + optionally coding the two channels 180-degrees out of phase on a per-band basis. + This provides better stereo quality than forcing the two channels to be in phase, + but when the output is downmixed to mono, the energy in the affected bands is cancelled + sometimes resulting in audible artifacts. + + As a work-around for this issue, the decoder MAY choose not to apply the 180-degree + phase shift. This can be useful when downmixing to mono inside or + outside of the decoder (e.g. user-controllable). + +
    + + +
    + Changes in and have + sufficient impact on the testvectors to make them fail. For this reason, + this document also updates the Opus test vectors. The new test vectors now + include two decoded outputs for the same bitstream. The outputs with + suffix 'm' do not apply the CELT 180-degree phase shift as allowed in + , while the outputs without the suffix do. An + implementation is compliant as long as it passes either set of vectors. + + + Any Opus implementation + that passes either the original test vectors from RFC 6716 + or one of the new sets of test vectors is compliant with the Opus specification. However, newer implementations + SHOULD be based on the new test vectors rather than the old ones. + + The new test vectors are located at + . + The SHA-1 hashes of the test vectors are: +
    + + + +
    + Note that the decoder input bitstream files (.bit) are unchanged. +
    +
    + +
    + This document fixes two security issues reported on Opus and that affect the + reference implementation in RFC 6716: CVE-2013-0899 + + and CVE-2017-0381 . + CVE- 2013-0899 theoretically could have caused an information leak. The leaked + information would have gone through the decoder process before being accessible + to the attacker. It is fixed by . + CVE-2017-0381 could have resulted in a 16-bit out-of-bounds read from a fixed + location. It is fixed in . + Beyond the two fixed CVEs, this document adds no new security considerations on top of + RFC 6716. + +
    + +
    + This document makes no request of IANA. + + Note to RFC Editor: this section may be removed on publication as an + RFC. +
    + +
    + We would like to thank Juri Aedla for reporting the issue with the parsing of + the Opus padding. Thanks to Felicia Lim for reporting the LSF integer overflow issue. + Also, thanks to Tina le Grand, Jonathan Lennox, and Mark Harris for their + feedback on this document. +
    +
    + + + + + + + + + +
    diff --git a/extern/opus/doc/draft-ietf-codec-opus.xml b/extern/opus/doc/draft-ietf-codec-opus.xml new file mode 100644 index 0000000..334cad9 --- /dev/null +++ b/extern/opus/doc/draft-ietf-codec-opus.xml @@ -0,0 +1,8276 @@ + + + + + + + +Definition of the Opus Audio Codec + + + +Mozilla Corporation +
    + +650 Castro Street +Mountain View +CA +94041 +USA + ++1 650 903-0800 +jmvalin@jmvalin.ca +
    +
    + + +Skype Technologies S.A. +
    + +Soder Malarstrand 43 +Stockholm + +11825 +SE + ++46 73 085 7619 +koen.vos@skype.net +
    +
    + + +Mozilla Corporation +
    + +650 Castro Street +Mountain View +CA +94041 +USA + ++1 650 903-0800 +tterriberry@mozilla.com +
    +
    + + + +General + + + + + +This document defines the Opus interactive speech and audio codec. +Opus is designed to handle a wide range of interactive audio applications, + including Voice over IP, videoconferencing, in-game chat, and even live, + distributed music performances. +It scales from low bitrate narrowband speech at 6 kb/s to very high quality + stereo music at 510 kb/s. +Opus uses both linear prediction (LP) and the Modified Discrete Cosine + Transform (MDCT) to achieve good compression of both speech and music. + + +
    + + + +
    + +The Opus codec is a real-time interactive audio codec designed to meet the requirements +described in . +It is composed of a linear + prediction (LP)-based layer and a Modified Discrete Cosine Transform + (MDCT)-based layer. +The main idea behind using two layers is that in speech, linear prediction + techniques (such as Code-Excited Linear Prediction, or CELP) code low frequencies more efficiently than transform + (e.g., MDCT) domain techniques, while the situation is reversed for music and + higher speech frequencies. +Thus a codec with both layers available can operate over a wider range than + either one alone and, by combining them, achieve better quality than either + one individually. + + + +The primary normative part of this specification is provided by the source code + in . +Only the decoder portion of this software is normative, though a + significant amount of code is shared by both the encoder and decoder. + provides a decoder conformance test. +The decoder contains a great deal of integer and fixed-point arithmetic which + needs to be performed exactly, including all rounding considerations, so any + useful specification requires domain-specific symbolic language to adequately + define these operations. +Additionally, any +conflict between the symbolic representation and the included reference +implementation must be resolved. For the practical reasons of compatibility and +testability it would be advantageous to give the reference implementation +priority in any disagreement. The C language is also one of the most +widely understood human-readable symbolic representations for machine +behavior. +For these reasons this RFC uses the reference implementation as the sole + symbolic representation of the codec. + + +While the symbolic representation is unambiguous and complete it is not +always the easiest way to understand the codec's operation. For this reason +this document also describes significant parts of the codec in English and +takes the opportunity to explain the rationale behind many of the more +surprising elements of the design. These descriptions are intended to be +accurate and informative, but the limitations of common English sometimes +result in ambiguity, so it is expected that the reader will always read +them alongside the symbolic representation. Numerous references to the +implementation are provided for this purpose. The descriptions sometimes +differ from the reference in ordering or through mathematical simplification +wherever such deviation makes an explanation easier to understand. +For example, the right shift and left shift operations in the reference +implementation are often described using division and multiplication in the text. +In general, the text is focused on the "what" and "why" while the symbolic +representation most clearly provides the "how". + + +
    + +The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", + "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be + interpreted as described in RFC 2119 . + + +Various operations in the codec require bit-exact fixed-point behavior, even + when writing a floating point implementation. +The notation "Q<n>", where n is an integer, denotes the number of binary + digits to the right of the decimal point in a fixed-point number. +For example, a signed Q14 value in a 16-bit word can represent values from + -2.0 to 1.99993896484375, inclusive. +This notation is for informational purposes only. +Arithmetic, when described, always operates on the underlying integer. +E.g., the text will explicitly indicate any shifts required after a + multiplication. + + +Expressions, where included in the text, follow C operator rules and + precedence, with the exception that the syntax "x**y" indicates x raised to + the power y. +The text also makes use of the following functions: + + +
    + +The smallest of two values x and y. + +
    + +
    + +The largest of two values x and y. + +
    + +
    +
    + +
    + +With this definition, if lo > hi, the lower bound is the one that + is enforced. + +
    + +
    + +The sign of x, i.e., +
    + 0 . +]]> +
    +
    +
    + +
    + +The absolute value of x, i.e., +
    + +
    +
    +
    + +
    + +The largest integer z such that z <= f. + +
    + +
    + +The smallest integer z such that z >= f. + +
    + +
    + +The integer z nearest to f, with ties rounded towards negative infinity, + i.e., +
    + +
    +
    +
    + +
    + +The base-two logarithm of f. + +
    + +
    + +The minimum number of bits required to store a positive integer n in two's + complement notation, or 0 for a non-positive integer n. +
    + 0 +]]> +
    +Examples: + +ilog(-1) = 0 +ilog(0) = 0 +ilog(1) = 1 +ilog(2) = 2 +ilog(3) = 2 +ilog(4) = 3 +ilog(7) = 3 + +
    +
    + +
    + +
    + +
    + + +The Opus codec scales from 6 kb/s narrowband mono speech to 510 kb/s + fullband stereo music, with algorithmic delays ranging from 5 ms to + 65.2 ms. +At any given time, either the LP layer, the MDCT layer, or both, may be active. +It can seamlessly switch between all of its various operating modes, giving it + a great deal of flexibility to adapt to varying content and network + conditions without renegotiating the current session. +The codec allows input and output of various audio bandwidths, defined as + follows: + + +Abbreviation +Audio Bandwidth +Sample Rate (Effective) +NB (narrowband) 4 kHz 8 kHz +MB (medium-band) 6 kHz 12 kHz +WB (wideband) 8 kHz 16 kHz +SWB (super-wideband) 12 kHz 24 kHz +FB (fullband) 20 kHz (*) 48 kHz + + +(*) Although the sampling theorem allows a bandwidth as large as half the + sampling rate, Opus never codes audio above 20 kHz, as that is the + generally accepted upper limit of human hearing. + + + +Opus defines super-wideband (SWB) with an effective sample rate of 24 kHz, + unlike some other audio coding standards that use 32 kHz. +This was chosen for a number of reasons. +The band layout in the MDCT layer naturally allows skipping coefficients for + frequencies over 12 kHz, but does not allow cleanly dropping just those + frequencies over 16 kHz. +A sample rate of 24 kHz also makes resampling in the MDCT layer easier, + as 24 evenly divides 48, and when 24 kHz is sufficient, it can save + computation in other processing, such as Acoustic Echo Cancellation (AEC). +Experimental changes to the band layout to allow a 16 kHz cutoff + (32 kHz effective sample rate) showed potential quality degradations at + other sample rates, and at typical bitrates the number of bits saved by using + such a cutoff instead of coding in fullband (FB) mode is very small. +Therefore, if an application wishes to process a signal sampled at 32 kHz, + it should just use FB. + + + +The LP layer is based on the SILK codec + . +It supports NB, MB, or WB audio and frame sizes from 10 ms to 60 ms, + and requires an additional 5 ms look-ahead for noise shaping estimation. +A small additional delay (up to 1.5 ms) may be required for sampling rate + conversion. +Like Vorbis and many other modern codecs, SILK is inherently designed for + variable-bitrate (VBR) coding, though the encoder can also produce + constant-bitrate (CBR) streams. +The version of SILK used in Opus is substantially modified from, and not + compatible with, the stand-alone SILK codec previously deployed by Skype. +This document does not serve to define that format, but those interested in the + original SILK codec should see instead. + + + +The MDCT layer is based on the CELT codec . +It supports NB, WB, SWB, or FB audio and frame sizes from 2.5 ms to + 20 ms, and requires an additional 2.5 ms look-ahead due to the + overlapping MDCT windows. +The CELT codec is inherently designed for CBR coding, but unlike many CBR + codecs it is not limited to a set of predetermined rates. +It internally allocates bits to exactly fill any given target budget, and an + encoder can produce a VBR stream by varying the target on a per-frame basis. +The MDCT layer is not used for speech when the audio bandwidth is WB or less, + as it is not useful there. +On the other hand, non-speech signals are not always adequately coded using + linear prediction, so for music only the MDCT layer should be used. + + + +A "Hybrid" mode allows the use of both layers simultaneously with a frame size + of 10 or 20 ms and a SWB or FB audio bandwidth. +The LP layer codes the low frequencies by resampling the signal down to WB. +The MDCT layer follows, coding the high frequency portion of the signal. +The cutoff between the two lies at 8 kHz, the maximum WB audio bandwidth. +In the MDCT layer, all bands below 8 kHz are discarded, so there is no + coding redundancy between the two layers. + + + +The sample rate (in contrast to the actual audio bandwidth) can be chosen + independently on the encoder and decoder side, e.g., a fullband signal can be + decoded as wideband, or vice versa. +This approach ensures a sender and receiver can always interoperate, regardless + of the capabilities of their actual audio hardware. +Internally, the LP layer always operates at a sample rate of twice the audio + bandwidth, up to a maximum of 16 kHz, which it continues to use for SWB + and FB. +The decoder simply resamples its output to support different sample rates. +The MDCT layer always operates internally at a sample rate of 48 kHz. +Since all the supported sample rates evenly divide this rate, and since the + the decoder may easily zero out the high frequency portion of the spectrum in + the frequency domain, it can simply decimate the MDCT layer output to achieve + the other supported sample rates very cheaply. + + + +After conversion to the common, desired output sample rate, the decoder simply + adds the output from the two layers together. +To compensate for the different look-ahead required by each layer, the CELT + encoder input is delayed by an additional 2.7 ms. +This ensures that low frequencies and high frequencies arrive at the same time. +This extra delay may be reduced by an encoder by using less look-ahead for noise + shaping or using a simpler resampler in the LP layer, but this will reduce + quality. +However, the base 2.5 ms look-ahead in the CELT layer cannot be reduced in + the encoder because it is needed for the MDCT overlap, whose size is fixed by + the decoder. + + + +Both layers use the same entropy coder, avoiding any waste from "padding bits" + between them. +The hybrid approach makes it easy to support both CBR and VBR coding. +Although the LP layer is VBR, the bit allocation of the MDCT layer can produce + a final stream that is CBR by using all the bits left unused by the LP layer. + + +
    + +The Opus codec includes a number of control parameters which can be changed dynamically during +regular operation of the codec, without interrupting the audio stream from the encoder to the decoder. +These parameters only affect the encoder since any impact they have on the bit-stream is signaled +in-band such that a decoder can decode any Opus stream without any out-of-band signaling. Any Opus +implementation can add or modify these control parameters without affecting interoperability. The most +important encoder control parameters in the reference encoder are listed below. + + +
    + +Opus supports all bitrates from 6 kb/s to 510 kb/s. All other parameters being +equal, higher bitrate results in higher quality. For a frame size of 20 ms, these +are the bitrate "sweet spots" for Opus in various configurations: + +8-12 kb/s for NB speech, +16-20 kb/s for WB speech, +28-40 kb/s for FB speech, +48-64 kb/s for FB mono music, and +64-128 kb/s for FB stereo music. + + +
    + +
    + +Opus can transmit either mono or stereo frames within a single stream. +When decoding a mono frame in a stereo decoder, the left and right channels are + identical, and when decoding a stereo frame in a mono decoder, the mono output + is the average of the left and right channels. +In some cases, it is desirable to encode a stereo input stream in mono (e.g., + because the bitrate is too low to encode stereo with sufficient quality). +The number of channels encoded can be selected in real-time, but by default the + reference encoder attempts to make the best decision possible given the + current bitrate. + +
    + +
    + +The audio bandwidths supported by Opus are listed in + . +Just like for the number of channels, any decoder can decode audio encoded at + any bandwidth. +For example, any Opus decoder operating at 8 kHz can decode a FB Opus + frame, and any Opus decoder operating at 48 kHz can decode a NB frame. +Similarly, the reference encoder can take a 48 kHz input signal and + encode it as NB. +The higher the audio bandwidth, the higher the required bitrate to achieve + acceptable quality. +The audio bandwidth can be explicitly specified in real-time, but by default + the reference encoder attempts to make the best bandwidth decision possible + given the current bitrate. + +
    + + +
    + +Opus can encode frames of 2.5, 5, 10, 20, 40 or 60 ms. +It can also combine multiple frames into packets of up to 120 ms. +For real-time applications, sending fewer packets per second reduces the + bitrate, since it reduces the overhead from IP, UDP, and RTP headers. +However, it increases latency and sensitivity to packet losses, as losing one + packet constitutes a loss of a bigger chunk of audio. +Increasing the frame duration also slightly improves coding efficiency, but the + gain becomes small for frame sizes above 20 ms. +For this reason, 20 ms frames are a good choice for most applications. + +
    + +
    + +There are various aspects of the Opus encoding process where trade-offs +can be made between CPU complexity and quality/bitrate. In the reference +encoder, the complexity is selected using an integer from 0 to 10, where +0 is the lowest complexity and 10 is the highest. Examples of +computations for which such trade-offs may occur are: + +The order of the pitch analysis whitening filter , +The order of the short-term noise shaping filter, +The number of states in delayed decision quantization of the +residual signal, and +The use of certain bit-stream features such as variable time-frequency +resolution and the pitch post-filter. + + +
    + +
    + +Audio codecs often exploit inter-frame correlations to reduce the +bitrate at a cost in error propagation: after losing one packet +several packets need to be received before the decoder is able to +accurately reconstruct the speech signal. The extent to which Opus +exploits inter-frame dependencies can be adjusted on the fly to +choose a trade-off between bitrate and amount of error propagation. + +
    + +
    + + Another mechanism providing robustness against packet loss is the in-band + Forward Error Correction (FEC). Packets that are determined to + contain perceptually important speech information, such as onsets or + transients, are encoded again at a lower bitrate and this re-encoded + information is added to a subsequent packet. + +
    + +
    + +Opus is more efficient when operating with variable bitrate (VBR), which is +the default. However, in some (rare) applications, constant bitrate (CBR) +is required. There are two main reasons to operate in CBR mode: + +When the transport only supports a fixed size for each compressed frame +When encryption is used for an audio stream that is either highly constrained + (e.g. yes/no, recorded prompts) or highly sensitive + + +When low-latency transmission is required over a relatively slow connection, then +constrained VBR can also be used. This uses VBR in a way that simulates a +"bit reservoir" and is equivalent to what MP3 (MPEG 1, Layer 3) and +AAC (Advanced Audio Coding) call CBR (i.e., not true +CBR due to the bit reservoir). + +
    + +
    + + Discontinuous Transmission (DTX) reduces the bitrate during silence + or background noise. When DTX is enabled, only one frame is encoded + every 400 milliseconds. + +
    + +
    + +
    + +
    + + +The Opus encoder produces "packets", which are each a contiguous set of bytes + meant to be transmitted as a single unit. +The packets described here do not include such things as IP, UDP, or RTP + headers which are normally found in a transport-layer packet. +A single packet may contain multiple audio frames, so long as they share a + common set of parameters, including the operating mode, audio bandwidth, frame + size, and channel count (mono vs. stereo). +This section describes the possible combinations of these parameters and the + internal framing used to pack multiple frames into a single packet. +This framing is not self-delimiting. +Instead, it assumes that a higher layer (such as UDP or RTP +or Ogg or Matroska ) + will communicate the length, in bytes, of the packet, and it uses this + information to reduce the framing overhead in the packet itself. +A decoder implementation MUST support the framing described in this section. +An alternative, self-delimiting variant of the framing is described in + . +Support for that variant is OPTIONAL. + + + +All bit diagrams in this document number the bits so that bit 0 is the most + significant bit of the first byte, and bit 7 is the least significant. +Bit 8 is thus the most significant bit of the second byte, etc. +Well-formed Opus packets obey certain requirements, marked [R1] through [R7] + below. +These are summarized in along with + appropriate means of handling malformed packets. + + +
    + +A well-formed Opus packet MUST contain at least one byte [R1]. +This byte forms a table-of-contents (TOC) header that signals which of the + various modes and configurations a given packet uses. +It is composed of a configuration number, "config", a stereo flag, "s", and a + frame count code, "c", arranged as illustrated in + . +A description of each of these fields follows. + + +
    + +
    + + +The top five bits of the TOC byte, labeled "config", encode one of 32 possible + configurations of operating mode, audio bandwidth, and frame size. +As described, the LP (SILK) layer and MDCT (CELT) layer can be combined in three possible + operating modes: + +A SILK-only mode for use in low bitrate connections with an audio bandwidth + of WB or less, +A Hybrid (SILK+CELT) mode for SWB or FB speech at medium bitrates, and +A CELT-only mode for very low delay speech transmission as well as music + transmission (NB to FB). + +The 32 possible configurations each identify which one of these operating modes + the packet uses, as well as the audio bandwidth and the frame size. + lists the parameters for each configuration. + + +Configuration Number(s) +Mode +Bandwidth +Frame Sizes +0...3 SILK-only NB 10, 20, 40, 60 ms +4...7 SILK-only MB 10, 20, 40, 60 ms +8...11 SILK-only WB 10, 20, 40, 60 ms +12...13 Hybrid SWB 10, 20 ms +14...15 Hybrid FB 10, 20 ms +16...19 CELT-only NB 2.5, 5, 10, 20 ms +20...23 CELT-only WB 2.5, 5, 10, 20 ms +24...27 CELT-only SWB 2.5, 5, 10, 20 ms +28...31 CELT-only FB 2.5, 5, 10, 20 ms + + +The configuration numbers in each range (e.g., 0...3 for NB SILK-only) + correspond to the various choices of frame size, in the same order. +For example, configuration 0 has a 10 ms frame size and configuration 3 + has a 60 ms frame size. + + + +One additional bit, labeled "s", signals mono vs. stereo, with 0 indicating + mono and 1 indicating stereo. + + + +The remaining two bits of the TOC byte, labeled "c", code the number of frames + per packet (codes 0 to 3) as follows: + +0: 1 frame in the packet +1: 2 frames in the packet, each with equal compressed size +2: 2 frames in the packet, with different compressed sizes +3: an arbitrary number of frames in the packet + +This draft refers to a packet as a code 0 packet, code 1 packet, etc., based on + the value of "c". + + +
    + +
    + + +This section describes how frames are packed according to each possible value + of "c" in the TOC byte. + + +
    + +When a packet contains multiple VBR frames (i.e., code 2 or 3), the compressed + length of one or more of these frames is indicated with a one- or two-byte + sequence, with the meaning of the first byte as follows: + +0: No frame (discontinuous transmission (DTX) or lost packet) +1...251: Length of the frame in bytes +252...255: A second byte is needed. The total length is (second_byte*4)+first_byte + + + + +The special length 0 indicates that no frame is available, either because it + was dropped during transmission by some intermediary or because the encoder + chose not to transmit it. +Any Opus frame in any mode MAY have a length of 0. + + + +The maximum representable length is 255*4+255=1275 bytes. +For 20 ms frames, this represents a bitrate of 510 kb/s, which is + approximately the highest useful rate for lossily compressed fullband stereo + music. +Beyond this point, lossless codecs are more appropriate. +It is also roughly the maximum useful rate of the MDCT layer, as shortly + thereafter quality no longer improves with additional bits due to limitations + on the codebook sizes. + + + +No length is transmitted for the last frame in a VBR packet, or for any of the + frames in a CBR packet, as it can be inferred from the total size of the + packet and the size of all other data in the packet. +However, the length of any individual frame MUST NOT exceed + 1275 bytes [R2], to allow for repacketization by gateways, + conference bridges, or other software. + +
    + +
    + + +For code 0 packets, the TOC byte is immediately followed by N-1 bytes + of compressed data for a single frame (where N is the size of the packet), + as illustrated in . + +
    + +
    +
    + +
    + +For code 1 packets, the TOC byte is immediately followed by the + (N-1)/2 bytes of compressed data for the first frame, followed by + (N-1)/2 bytes of compressed data for the second frame, as illustrated in + . +The number of payload bytes available for compressed data, N-1, MUST be even + for all code 1 packets [R3]. + +
    + +
    +
    + +
    + +For code 2 packets, the TOC byte is followed by a one- or two-byte sequence + indicating the length of the first frame (marked N1 in ), + followed by N1 bytes of compressed data for the first frame. +The remaining N-N1-2 or N-N1-3 bytes are the compressed data for the + second frame. +This is illustrated in . +A code 2 packet MUST contain enough bytes to represent a valid length. +For example, a 1-byte code 2 packet is always invalid, and a 2-byte code 2 + packet whose second byte is in the range 252...255 is also invalid. +The length of the first frame, N1, MUST also be no larger than the size of the + payload remaining after decoding that length for all code 2 packets [R4]. +This makes, for example, a 2-byte code 2 packet with a second byte in the range + 1...251 invalid as well (the only valid 2-byte code 2 packet is one where the + length of both frames is zero). + +
    + +
    +
    + +
    + +Code 3 packets signal the number of frames, as well as additional + padding, called "Opus padding" to indicate that this padding is added at the + Opus layer, rather than at the transport layer. +Code 3 packets MUST have at least 2 bytes [R6,R7]. +The TOC byte is followed by a byte encoding the number of frames in the packet + in bits 2 to 7 (marked "M" in ), with bit 1 indicating whether + or not Opus padding is inserted (marked "p" in ), and bit 0 + indicating VBR (marked "v" in ). +M MUST NOT be zero, and the audio duration contained within a packet MUST NOT + exceed 120 ms [R5]. +This limits the maximum frame count for any frame size to 48 (for 2.5 ms + frames), with lower limits for longer frame sizes. + illustrates the layout of the frame count + byte. + +
    + +
    + +When Opus padding is used, the number of bytes of padding is encoded in the + bytes following the frame count byte. +Values from 0...254 indicate that 0...254 bytes of padding are included, + in addition to the byte(s) used to indicate the size of the padding. +If the value is 255, then the size of the additional padding is 254 bytes, + plus the padding value encoded in the next byte. +There MUST be at least one more byte in the packet in this case [R6,R7]. +The additional padding bytes appear at the end of the packet, and MUST be set + to zero by the encoder to avoid creating a covert channel. +The decoder MUST accept any value for the padding bytes, however. + + +Although this encoding provides multiple ways to indicate a given number of + padding bytes, each uses a different number of bytes to indicate the padding + size, and thus will increase the total packet size by a different amount. +For example, to add 255 bytes to a packet, set the padding bit, p, to 1, insert + a single byte after the frame count byte with a value of 254, and append 254 + padding bytes with the value zero to the end of the packet. +To add 256 bytes to a packet, set the padding bit to 1, insert two bytes after + the frame count byte with the values 255 and 0, respectively, and append 254 + padding bytes with the value zero to the end of the packet. +By using the value 255 multiple times, it is possible to create a packet of any + specific, desired size. +Let P be the number of header bytes used to indicate the padding size plus the + number of padding bytes themselves (i.e., P is the total number of bytes added + to the packet). +Then P MUST be no more than N-2 [R6,R7]. + + +In the CBR case, let R=N-2-P be the number of bytes remaining in the packet + after subtracting the (optional) padding. +Then the compressed length of each frame in bytes is equal to R/M. +The value R MUST be a non-negative integer multiple of M [R6]. +The compressed data for all M frames follows, each of size + R/M bytes, as illustrated in . + + +
    + +
    + + +In the VBR case, the (optional) padding length is followed by M-1 frame + lengths (indicated by "N1" to "N[M-1]" in ), each encoded in a + one- or two-byte sequence as described above. +The packet MUST contain enough data for the M-1 lengths after removing the + (optional) padding, and the sum of these lengths MUST be no larger than the + number of bytes remaining in the packet after decoding them [R7]. +The compressed data for all M frames follows, each frame consisting of the + indicated number of bytes, with the final frame consuming any remaining bytes + before the final padding, as illustrated in . +The number of header bytes (TOC byte, frame count byte, padding length bytes, + and frame length bytes), plus the signaled length of the first M-1 frames themselves, + plus the signaled length of the padding MUST be no larger than N, the total size of the + packet. + + +
    + +
    +
    +
    + +
    + +Simplest case, one NB mono 20 ms SILK frame: + + +
    + +
    + + +Two FB mono 5 ms CELT frames of the same compressed size: + + +
    + +
    + + +Two FB mono 20 ms Hybrid frames of different compressed size: + + +
    + +
    + + +Four FB stereo 20 ms CELT frames of the same compressed size: + + +
    + +
    +
    + +
    + +A receiver MUST NOT process packets which violate any of the rules above as + normal Opus packets. +They are reserved for future applications, such as in-band headers (containing + metadata, etc.). +Packets which violate these constraints may cause implementations of + this specification to treat them as malformed, and + discard them. + + +These constraints are summarized here for reference: + +Packets are at least one byte. +No implicit frame length is larger than 1275 bytes. +Code 1 packets have an odd total length, N, so that (N-1)/2 is an + integer. +Code 2 packets have enough bytes after the TOC for a valid frame + length, and that length is no larger than the number of bytes remaining in the + packet. +Code 3 packets contain at least one frame, but no more than 120 ms + of audio total. +The length of a CBR code 3 packet, N, is at least two bytes, the number of + bytes added to indicate the padding size plus the trailing padding bytes + themselves, P, is no more than N-2, and the frame count, M, satisfies + the constraint that (N-2-P) is a non-negative integer multiple of M. +VBR code 3 packets are large enough to contain all the header bytes (TOC + byte, frame count byte, any padding length bytes, and any frame length bytes), + plus the length of the first M-1 frames, plus any trailing padding bytes. + + +
    + +
    + +
    + +The Opus decoder consists of two main blocks: the SILK decoder and the CELT + decoder. +At any given time, one or both of the SILK and CELT decoders may be active. +The output of the Opus decode is the sum of the outputs from the SILK and CELT + decoders with proper sample rate conversion and delay compensation on the SILK + side, and optional decimation (when decoding to sample rates less than + 48 kHz) on the CELT side, as illustrated in the block diagram below. + +
    + +| Decoder |--->| Rate |----+ +Bit- +---------+ | | | | Conversion | v +stream | Range |---+ +---------+ +------------+ /---\ Audio +------->| Decoder | | + |------> + | |---+ +---------+ +------------+ \---/ + +---------+ | | CELT | | Decimation | ^ + +->| Decoder |--->| (Optional) |----+ + | | | | + +---------+ +------------+ +]]> + +
    + +
    + +Opus uses an entropy coder based on range coding +, +which is itself a rediscovery of the FIFO arithmetic code introduced by . +It is very similar to arithmetic encoding, except that encoding is done with +digits in any base instead of with bits, +so it is faster when using larger bases (i.e., a byte). All of the +calculations in the range coder must use bit-exact integer arithmetic. + + +Symbols may also be coded as "raw bits" packed directly into the bitstream, + bypassing the range coder. +These are packed backwards starting at the end of the frame, as illustrated in + . +This reduces complexity and makes the stream more resilient to bit errors, as + corruption in the raw bits will not desynchronize the decoding process, unlike + corruption in the input to the range decoder. +Raw bits are only used in the CELT layer. + + +
    + : ++ + +: : ++ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +: | <- Boundary occurs at an arbitrary bit position : ++-+-+-+ + +: <- Raw bits data (packed LSB to MSB) | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +]]> +
    + + +Each symbol coded by the range coder is drawn from a finite alphabet and coded + in a separate "context", which describes the size of the alphabet and the + relative frequency of each symbol in that alphabet. + + +Suppose there is a context with n symbols, identified with an index that ranges + from 0 to n-1. +The parameters needed to encode or decode symbol k in this context are + represented by a three-tuple (fl[k], fh[k], ft), with + 0 <= fl[k] < fh[k] <= ft <= 65535. +The values of this tuple are derived from the probability model for the + symbol, represented by traditional "frequency counts". +Because Opus uses static contexts these are not updated as symbols are decoded. +Let f[i] be the frequency of symbol i. +Then the three-tuple corresponding to symbol k is given by + +
    + +
    + +The range decoder extracts the symbols and integers encoded using the range + encoder in . +The range decoder maintains an internal state vector composed of the two-tuple + (val, rng), representing the difference between the high end of the + current range and the actual coded value, minus one, and the size of the + current range, respectively. +Both val and rng are 32-bit unsigned integer values. + + +
    + +Let b0 be the first input byte (or zero if there are no bytes in this Opus + frame). +The decoder initializes rng to 128 and initializes val to + (127 - (b0>>1)), where (b0>>1) is the top 7 bits of the + first input byte. +It saves the remaining bit, (b0&1), for use in the renormalization + procedure described in , which the + decoder invokes immediately after initialization to read additional bits and + establish the invariant that rng > 2**23. + +
    + +
    + +Decoding a symbol is a two-step process. +The first step determines a 16-bit unsigned value fs, which lies within the + range of some symbol in the current context. +The second step updates the range decoder state with the three-tuple + (fl[k], fh[k], ft) corresponding to that symbol. + + +The first step is implemented by ec_decode() (entdec.c), which computes +
    + +
    +The divisions here are integer division. +
    + +The decoder then identifies the symbol in the current context corresponding to + fs; i.e., the value of k whose three-tuple (fl[k], fh[k], ft) + satisfies fl[k] <= fs < fh[k]. +It uses this tuple to update val according to +
    + +
    +If fl[k] is greater than zero, then the decoder updates rng using +
    + +
    +Otherwise, it updates rng using +
    + +
    +
    + +Using a special case for the first symbol (rather than the last symbol, as is + commonly done in other arithmetic coders) ensures that all the truncation + error from the finite precision arithmetic accumulates in symbol 0. +This makes the cost of coding a 0 slightly smaller, on average, than its + estimated probability indicates and makes the cost of coding any other symbol + slightly larger. +When contexts are designed so that 0 is the most probable symbol, which is + often the case, this strategy minimizes the inefficiency introduced by the + finite precision. +It also makes some of the special-case decoding routines in + particularly simple. + + +After the updates, implemented by ec_dec_update() (entdec.c), the decoder + normalizes the range using the procedure in the next section, and returns the + index k. + + +
    + +To normalize the range, the decoder repeats the following process, implemented + by ec_dec_normalize() (entdec.c), until rng > 2**23. +If rng is already greater than 2**23, the entire process is skipped. +First, it sets rng to (rng<<8). +Then it reads the next byte of the Opus frame and forms an 8-bit value sym, + using the left-over bit buffered from the previous byte as the high bit + and the top 7 bits of the byte just read as the other 7 bits of sym. +The remaining bit in the byte just read is buffered for use in the next + iteration. +If no more input bytes remain, it uses zero bits instead. +See for the initialization used to process + the first byte. +Then, it sets +
    + +
    +
    + +It is normal and expected that the range decoder will read several bytes + into the raw bits data (if any) at the end of the packet by the time the frame + is completely decoded, as illustrated in . +This same data MUST also be returned as raw bits when requested. +The encoder is expected to terminate the stream in such a way that the decoder + will decode the intended values regardless of the data contained in the raw + bits. + describes a procedure for doing this. +If the range decoder consumes all of the bytes belonging to the current frame, + it MUST continue to use zero when any further input bytes are required, even + if there is additional data in the current packet from padding or other + frames. + + +
    + | : ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ^ ^ + | End of data buffered by the range coder | +...-----------------------------------------------+ + | + | End of data consumed by raw bits + +-------------------------------------------------------... +]]> +
    +
    +
    + +
    + +The reference implementation uses three additional decoding methods that are + exactly equivalent to the above, but make assumptions and simplifications that + allow for a more efficient implementation. + +
    + +The first is ec_decode_bin() (entdec.c), defined using the parameter ftb + instead of ft. +It is mathematically equivalent to calling ec_decode() with + ft = (1<<ftb), but avoids one of the divisions. + +
    +
    + +The next is ec_dec_bit_logp() (entdec.c), which decodes a single binary symbol, + replacing both the ec_decode() and ec_dec_update() steps. +The context is described by a single parameter, logp, which is the absolute + value of the base-2 logarithm of the probability of a "1". +It is mathematically equivalent to calling ec_decode() with + ft = (1<<logp), followed by ec_dec_update() with + the 3-tuple (fl[k] = 0, + fh[k] = (1<<logp) - 1, + ft = (1<<logp)) if the returned value + of fs is less than (1<<logp) - 1 (a "0" was decoded), and with + (fl[k] = (1<<logp) - 1, + fh[k] = ft = (1<<logp)) otherwise (a "1" was + decoded). +The implementation requires no multiplications or divisions. + +
    +
    + +The last is ec_dec_icdf() (entdec.c), which decodes a single symbol with a + table-based context of up to 8 bits, also replacing both the ec_decode() and + ec_dec_update() steps, as well as the search for the decoded symbol in between. +The context is described by two parameters, an icdf + ("inverse" cumulative distribution function) table and ftb. +As with ec_decode_bin(), (1<<ftb) is equivalent to ft. +idcf[k], on the other hand, stores (1<<ftb)-fh[k], which is equal to + (1<<ftb) - fl[k+1]. +fl[0] is assumed to be 0, and the table is terminated by a value of 0 (where + fh[k] == ft). + + +The function is mathematically equivalent to calling ec_decode() with + ft = (1<<ftb), using the returned value fs to search the table + for the first entry where fs < (1<<ftb)-icdf[k], and + calling ec_dec_update() with + fl[k] = (1<<ftb) - icdf[k-1] (or 0 + if k == 0), fh[k] = (1<<ftb) - idcf[k], + and ft = (1<<ftb). +Combining the search with the update allows the division to be replaced by a + series of multiplications (which are usually much cheaper), and using an + inverse CDF allows the use of an ftb as large as 8 in an 8-bit table without + any special cases. +This is the primary interface with the range decoder in the SILK layer, though + it is used in a few places in the CELT layer as well. + + +Although icdf[k] is more convenient for the code, the frequency counts, f[k], + are a more natural representation of the probability distribution function + (PDF) for a given symbol. +Therefore this draft lists the latter, not the former, when describing the + context in which a symbol is coded as a list, e.g., {4, 4, 4, 4}/16 for a + uniform context with four possible values and ft = 16. +The value of ft after the slash is always the sum of the entries in the PDF, + but is included for convenience. +Contexts with identical probabilities, f[k]/ft, but different values of ft + (or equivalently, ftb) are not the same, and cannot, in general, be used in + place of one another. +An icdf table is also not capable of representing a PDF where the first symbol + has 0 probability. +In such contexts, ec_dec_icdf() can decode the symbol by using a table that + drops the entries for any initial zero-probability values and adding the + constant offset of the first value with a non-zero probability to its return + value. + +
    +
    + +
    + +The raw bits used by the CELT layer are packed at the end of the packet, with + the least significant bit of the first value packed in the least significant + bit of the last byte, filling up to the most significant bit in the last byte, + continuing on to the least significant bit of the penultimate byte, and so on. +The reference implementation reads them using ec_dec_bits() (entdec.c). +Because the range decoder must read several bytes ahead in the stream, as + described in , the input consumed by the + raw bits may overlap with the input consumed by the range coder, and a decoder + MUST allow this. +The format should render it impossible to attempt to read more raw bits than + there are actual bits in the frame, though a decoder may wish to check for + this and report an error. + +
    + +
    + +The function ec_dec_uint() (entdec.c) decodes one of ft equiprobable values in + the range 0 to (ft - 1), inclusive, each with a frequency of 1, + where ft may be as large as (2**32 - 1). +Because ec_decode() is limited to a total frequency of (2**16 - 1), + it splits up the value into a range coded symbol representing up to 8 of the + high bits, and, if necessary, raw bits representing the remainder of the + value. +The limit of 8 bits in the range coded symbol is a trade-off between + implementation complexity, modeling error (since the symbols no longer truly + have equal coding cost), and rounding error introduced by the range coder + itself (which gets larger as more bits are included). +Using raw bits reduces the maximum number of divisions required in the worst + case, but means that it may be possible to decode a value outside the range + 0 to (ft - 1), inclusive. + + + +ec_dec_uint() takes a single, positive parameter, ft, which is not necessarily + a power of two, and returns an integer, t, whose value lies between 0 and + (ft - 1), inclusive. +Let ftb = ilog(ft - 1), i.e., the number of bits required + to store (ft - 1) in two's complement notation. +If ftb is 8 or less, then t is decoded with t = ec_decode(ft), and + the range coder state is updated using the three-tuple (t, t + 1, + ft). + + +If ftb is greater than 8, then the top 8 bits of t are decoded using +
    +> (ftb - 8)) + 1) , +]]> +
    + the decoder state is updated using the three-tuple + (t, t + 1, + ((ft - 1) >> (ftb - 8)) + 1), + and the remaining bits are decoded as raw bits, setting +
    + +
    +If, at this point, t >= ft, then the current frame is corrupt. +In that case, the decoder should assume there has been an error in the coding, + decoding, or transmission and SHOULD take measures to conceal the + error and/or report to the application that the error has occurred. +
    + +
    + +
    + +The bit allocation routines in the CELT decoder need a conservative upper bound + on the number of bits that have been used from the current frame thus far, + including both range coder bits and raw bits. +This drives allocation decisions that must match those made in the encoder. +The upper bound is computed in the reference implementation to whole-bit + precision by the function ec_tell() (entcode.h) and to fractional 1/8th bit + precision by the function ec_tell_frac() (entcode.c). +Like all operations in the range coder, it must be implemented in a bit-exact + manner, and must produce exactly the same value returned by the same functions + in the encoder after encoding the same symbols. + + +ec_tell() is guaranteed to return ceil(ec_tell_frac()/8.0). +In various places the codec will check to ensure there is enough room to + contain a symbol before attempting to decode it. +In practice, although the number of bits used so far is an upper bound, + decoding a symbol whose probability model suggests it has a worst-case cost of + p 1/8th bits may actually advance the return value of ec_tell_frac() by + p-1, p, or p+1 1/8th bits, due to approximation error in that upper bound, + truncation error in the range coder, and for large values of ft, modeling + error in ec_dec_uint(). + + +However, this error is bounded, and periodic calls to ec_tell() or + ec_tell_frac() at precisely defined points in the decoding process prevent it + from accumulating. +For a range coder symbol that requires a whole number of bits (i.e., + for which ft/(fh[k] - fl[k]) is a power of two), where there are at + least p 1/8th bits available, decoding the symbol will never cause ec_tell() or + ec_tell_frac() to exceed the size of the frame ("bust the budget"). +In this case the return value of ec_tell_frac() will only advance by more than + p 1/8th bits if there was an additional, fractional number of bits remaining, + and it will never advance beyond the next whole-bit boundary, which is safe, + since frames always contain a whole number of bits. +However, when p is not a whole number of bits, an extra 1/8th bit is required + to ensure that decoding the symbol will not bust the budget. + + +The reference implementation keeps track of the total number of whole bits that + have been processed by the decoder so far in the variable nbits_total, + including the (possibly fractional) number of bits that are currently + buffered, but not consumed, inside the range coder. +nbits_total is initialized to 9 just before the initial range renormalization + process completes (or equivalently, it can be initialized to 33 after the + first renormalization). +The extra two bits over the actual amount buffered by the range coder + guarantees that it is an upper bound and that there is enough room for the + encoder to terminate the stream. +Each iteration through the range coder's renormalization loop increases + nbits_total by 8. +Reading raw bits increases nbits_total by the number of raw bits read. + + +
    + +The whole number of bits buffered in rng may be estimated via lg = ilog(rng). +ec_tell() then becomes a simple matter of removing these bits from the total. +It returns (nbits_total - lg). + + +In a newly initialized decoder, before any symbols have been read, this reports + that 1 bit has been used. +This is the bit reserved for termination of the encoder. + +
    + +
    + +ec_tell_frac() estimates the number of bits buffered in rng to fractional + precision. +Since rng must be greater than 2**23 after renormalization, lg must be at least + 24. +Let +
    + +> (lg-16) , +]]> +
    + so that 32768 <= r_Q15 < 65536, an unsigned Q15 value representing the + fractional part of rng. +Then the following procedure can be used to add one bit of precision to lg. +First, update +
    + +> 15 . +]]> +
    +Then add the 16th bit of r_Q15 to lg via +
    + +> 16) . +]]> +
    +Finally, if this bit was a 1, reduce r_Q15 by a factor of two via +
    + +> 1 , +]]> +
    + so that it once again lies in the range 32768 <= r_Q15 < 65536. +
    + +This procedure is repeated three times to extend lg to 1/8th bit precision. +ec_tell_frac() then returns (nbits_total*8 - lg). + +
    + +
    + +
    + +
    + +The decoder's LP layer uses a modified version of the SILK codec (herein simply + called "SILK"), which runs a decoded excitation signal through adaptive + long-term and short-term prediction synthesis filters. +It runs at NB, MB, and WB sample rates internally. +When used in a SWB or FB Hybrid frame, the LP layer itself still only runs in + WB. + + +
    + +An overview of the decoder is given in . + +
    + +| Range |--->| Decode |---------------------------+ + 1 | Decoder | 2 | Parameters |----------+ 5 | + +---------+ +------------+ 4 | | + 3 | | | + \/ \/ \/ + +------------+ +------------+ +------------+ + | Generate |-->| LTP |-->| LPC | + | Excitation | | Synthesis | | Synthesis | + +------------+ +------------+ +------------+ + ^ | + | | + +-------------------+----------------+ + | 6 + | +------------+ +-------------+ + +-->| Stereo |-->| Sample Rate |--> + | Unmixing | 7 | Conversion | 8 + +------------+ +-------------+ + +1: Range encoded bitstream +2: Coded parameters +3: Pulses, LSBs, and signs +4: Pitch lags, Long-Term Prediction (LTP) coefficients +5: Linear Predictive Coding (LPC) coefficients and gains +6: Decoded signal (mono or mid-side stereo) +7: Unmixed signal (mono or left-right stereo) +8: Resampled signal +]]> + +
    + + +The decoder feeds the bitstream (1) to the range decoder from + , and then decodes the parameters in it (2) + using the procedures detailed in + Sections  + through . +These parameters (3, 4, 5) are used to generate an excitation signal (see + ), which is fed to an optional + long-term prediction (LTP) filter (voiced frames only, see + ) and then a short-term prediction filter + (see ), producing the decoded signal (6). +For stereo streams, the mid-side representation is converted to separate left + and right channels (7). +The result is finally resampled to the desired output sample rate (e.g., + 48 kHz) so that the resampled signal (8) can be mixed with the CELT + layer. + + +
    + +
    + + +Internally, the LP layer of a single Opus frame is composed of either a single + 10 ms regular SILK frame or between one and three 20 ms regular SILK + frames. +A stereo Opus frame may double the number of regular SILK frames (up to a total + of six), since it includes separate frames for a mid channel and, optionally, + a side channel. +Optional Low Bit-Rate Redundancy (LBRR) frames, which are reduced-bitrate + encodings of previous SILK frames, may be included to aid in recovery from + packet loss. +If present, these appear before the regular SILK frames. +They are in most respects identical to regular, active SILK frames, except that + they are usually encoded with a lower bitrate. +This draft uses "SILK frame" to refer to either one and "regular SILK frame" if + it needs to draw a distinction between the two. + + +Logically, each SILK frame is in turn composed of either two or four 5 ms + subframes. +Various parameters, such as the quantization gain of the excitation and the + pitch lag and filter coefficients can vary on a subframe-by-subframe basis. +Physically, the parameters for each subframe are interleaved in the bitstream, + as described in the relevant sections for each parameter. + + +All of these frames and subframes are decoded from the same range coder, with + no padding between them. +Thus packing multiple SILK frames in a single Opus frame saves, on average, + half a byte per SILK frame. +It also allows some parameters to be predicted from prior SILK frames in the + same Opus frame, since this does not degrade packet loss robustness (beyond + any penalty for merely using fewer, larger packets to store multiple frames). + + + +Stereo support in SILK uses a variant of mid-side coding, allowing a mono + decoder to simply decode the mid channel. +However, the data for the two channels is interleaved, so a mono decoder must + still unpack the data for the side channel. +It would be required to do so anyway for Hybrid Opus frames, or to support + decoding individual 20 ms frames. + + + + summarizes the overall grouping of the contents of + the LP layer. +Figures  + and  illustrate + the ordering of the various SILK frames for a 60 ms Opus frame, for both + mono and stereo, respectively. + + + +Symbol(s) +PDF(s) +Condition + +Voice Activity Detection (VAD) flags +{1, 1}/2 + + +LBRR flag +{1, 1}/2 + + +Per-frame LBRR flags + + + +LBRR Frame(s) + + + +Regular SILK Frame(s) + + + + + +
    + +
    + +
    + +
    + +
    + +
    + +The LP layer begins with two to eight header bits, decoded in silk_Decode() + (dec_API.c). +These consist of one Voice Activity Detection (VAD) bit per frame (up to 3), + followed by a single flag indicating the presence of LBRR frames. +For a stereo packet, these first flags correspond to the mid channel, and a + second set of flags is included for the side channel. + + +Because these are the first symbols decoded by the range coder and because they + are coded as binary values with uniform probability, they can be extracted + directly from the most significant bits of the first byte of compressed data. +Thus, a receiver can determine if an Opus frame contains any active SILK frames + without the overhead of using the range decoder. + +
    + +
    + +For Opus frames longer than 20 ms, a set of LBRR flags is + decoded for each channel that has its LBRR flag set. +Each set contains one flag per 20 ms SILK frame. +40 ms Opus frames use the 2-frame LBRR flag PDF from + , and 60 ms Opus frames use the + 3-frame LBRR flag PDF. +For each channel, the resulting 2- or 3-bit integer contains the corresponding + LBRR flag for each frame, packed in order from the LSB to the MSB. + + + +Frame Size +PDF +40 ms {0, 53, 53, 150}/256 +60 ms {0, 41, 20, 29, 41, 15, 28, 82}/256 + + + +A 10 or 20 ms Opus frame does not contain any per-frame LBRR flags, + as there may be at most one LBRR frame per channel. +The global LBRR flag in the header bits (see ) + is already sufficient to indicate the presence of that single LBRR frame. + + +
    + +
    + +The LBRR frames, if present, contain an encoded representation of the signal + immediately prior to the current Opus frame as if it were encoded with the + current mode, frame size, audio bandwidth, and channel count, even if those + differ from the prior Opus frame. +When one of these parameters changes from one Opus frame to the next, this + implies that the LBRR frames of the current Opus frame may not be simple + drop-in replacements for the contents of the previous Opus frame. + + + +For example, when switching from 20 ms to 60 ms, the 60 ms Opus + frame may contain LBRR frames covering up to three prior 20 ms Opus + frames, even if those frames already contained LBRR frames covering some of + the same time periods. +When switching from 20 ms to 10 ms, the 10 ms Opus frame can + contain an LBRR frame covering at most half the prior 20 ms Opus frame, + potentially leaving a hole that needs to be concealed from even a single + packet loss (see ). +When switching from mono to stereo, the LBRR frames in the first stereo Opus + frame MAY contain a non-trivial side channel. + + + +In order to properly produce LBRR frames under all conditions, an encoder might + need to buffer up to 60 ms of audio and re-encode it during these + transitions. +However, the reference implementation opts to disable LBRR frames at the + transition point for simplicity. +Since transitions are relatively infrequent in normal usage, this does not have + a significant impact on packet loss robustness. + + + +The LBRR frames immediately follow the LBRR flags, prior to any regular SILK + frames. + describes their exact contents. +LBRR frames do not include their own separate VAD flags. +LBRR frames are only meant to be transmitted for active speech, thus all LBRR + frames are treated as active. + + + +In a stereo Opus frame longer than 20 ms, although the per-frame LBRR + flags for the mid channel are coded as a unit before the per-frame LBRR flags + for the side channel, the LBRR frames themselves are interleaved. +The decoder parses an LBRR frame for the mid channel of a given 20 ms + interval (if present) and then immediately parses the corresponding LBRR + frame for the side channel (if present), before proceeding to the next + 20 ms interval. + +
    + +
    + +The regular SILK frame(s) follow the LBRR frames (if any). + describes their contents, as well. +Unlike the LBRR frames, a regular SILK frame is coded for each time interval in + an Opus frame, even if the corresponding VAD flags are unset. +For stereo Opus frames longer than 20 ms, the regular mid and side SILK + frames for each 20 ms interval are interleaved, just as with the LBRR + frames. +The side frame may be skipped by coding an appropriate flag, as detailed in + . + +
    + +
    + +Each SILK frame includes a set of side information that encodes + +The frame type and quantization type (), +Quantization gains (), +Short-term prediction filter coefficients (), +A Line Spectral Frequencies (LSF) interpolation weight (), + +Long-term prediction filter lags and gains (), + and + +A linear congruential generator (LCG) seed (). + +The quantized excitation signal (see ) follows + these at the end of the frame. + details the overall organization of a + SILK frame. + + + +Symbol(s) +PDF(s) +Condition + +Stereo Prediction Weights + + + +Mid-only Flag + + + +Frame Type + + + +Subframe Gains + + + +Normalized LSF Stage-1 Index + + + +Normalized LSF Stage-2 Residual + + + +Normalized LSF Interpolation Weight + +20 ms frame + +Primary Pitch Lag + +Voiced frame + +Subframe Pitch Contour + +Voiced frame + +Periodicity Index + +Voiced frame + +LTP Filter + +Voiced frame + +LTP Scaling + + + +LCG Seed + + + +Excitation Rate Level + + + +Excitation Pulse Counts + + + +Excitation Pulse Locations + +Non-zero pulse count + +Excitation LSBs + + + +Excitation Signs + + + + + +
    + +A SILK frame corresponding to the mid channel of a stereo Opus frame begins + with a pair of side channel prediction weights, designed such that zeros + indicate normal mid-side coupling. +Since these weights can change on every frame, the first portion of each frame + linearly interpolates between the previous weights and the current ones, using + zeros for the previous weights if none are available. +These prediction weights are never included in a mono Opus frame, and the + previous weights are reset to zeros on any transition from mono to stereo. +They are also not included in an LBRR frame for the side channel, even if the + LBRR flags indicate the corresponding mid channel was not coded. +In that case, the previous weights are used, again substituting in zeros if no + previous weights are available since the last decoder reset + (see ). + + + +To summarize, these weights are coded if and only if + +This is a stereo Opus frame (), and +The current SILK frame corresponds to the mid channel. + + + + +The prediction weights are coded in three separate pieces, which are decoded + by silk_stereo_decode_pred() (decode_stereo_pred.c). +The first piece jointly codes the high-order part of a table index for both + weights. +The second piece codes the low-order part of each table index. +The third piece codes an offset used to linearly interpolate between table + indices. +The details are as follows. + + + +Let n be an index decoded with the 25-element stage-1 PDF in + . +Then let i0 and i1 be indices decoded with the stage-2 and stage-3 PDFs in + , respectively, and let i2 and i3 + be two more indices decoded with the stage-2 and stage-3 PDFs, all in that + order. + + + +Stage +PDF +Stage 1 +{7, 2, 1, 1, 1, + 10, 24, 8, 1, 1, + 3, 23, 92, 23, 3, + 1, 1, 8, 24, 10, + 1, 1, 1, 2, 7}/256 + +Stage 2 +{85, 86, 85}/256 + +Stage 3 +{51, 51, 52, 51, 51}/256 + + + +Then use n, i0, and i2 to form two table indices, wi0 and wi1, according to +
    + +
    + where the division is integer division. +The range of these indices is 0 to 14, inclusive. +Let w[i] be the i'th weight from . +Then the two prediction weights, w0_Q13 and w1_Q13, are +
    +> 16)*(2*i3 + 1) + +w0_Q13 = w_Q13[wi0] + + ((w_Q13[wi0+1] - w_Q13[wi0])*6554) >> 16)*(2*i1 + 1) + - w1_Q13 +]]> +
    +N.b., w1_Q13 is computed first here, because w0_Q13 depends on it. +The constant 6554 is approximately 0.1 in Q16. +Although wi0 and wi1 only have 15 possible values, + contains 16 entries to allow + interpolation between entry wi0 and (wi0 + 1) (and likewise for wi1). +
    + + +Index +Weight (Q13) + 0 -13732 + 1 -10050 + 2 -8266 + 3 -7526 + 4 -6500 + 5 -5000 + 6 -2950 + 7 -820 + 8 820 + 9 2950 +10 5000 +11 6500 +12 7526 +13 8266 +14 10050 +15 13732 + + +
    + +
    + +A flag appears after the stereo prediction weights that indicates if only the + mid channel is coded for this time interval. +It appears only when + +This is a stereo Opus frame (see ), +The current SILK frame corresponds to the mid channel, and +Either + +This is a regular SILK frame where the VAD flags + (see ) indicate that the corresponding side + channel is not active. + +This is an LBRR frame where the LBRR flags + (see and ) + indicate that the corresponding side channel is not coded. + + + + +It is omitted when there are no stereo weights, for all of the same reasons. +It is also omitted for a regular SILK frame when the VAD flag of the + corresponding side channel frame is set (indicating it is active). +The side channel must be coded in this case, making the mid-only flag + redundant. +It is also omitted for an LBRR frame when the corresponding LBRR flags + indicate the side channel is coded. + + + +When the flag is present, the decoder reads a single value using the PDF in + , as implemented in + silk_stereo_decode_mid_only() (decode_stereo_pred.c). +If the flag is set, then there is no corresponding SILK frame for the side + channel, the entire decoding process for the side channel is skipped, and + zeros are fed to the stereo unmixing process (see + ) instead. +As stated above, LBRR frames still include this flag when the LBRR flag + indicates that the side channel is not coded. +In that case, if this flag is zero (indicating that there should be a side + channel), then Packet Loss Concealment (PLC, see + ) SHOULD be invoked to recover a + side channel signal. +Otherwise, the stereo image will collapse. + + + +PDF +{192, 64}/256 + + +
    + +
    + +Each SILK frame contains a single "frame type" symbol that jointly codes the + signal type and quantization offset type of the corresponding frame. +If the current frame is a regular SILK frame whose VAD bit was not set (an + "inactive" frame), then the frame type symbol takes on a value of either 0 or + 1 and is decoded using the first PDF in . +If the frame is an LBRR frame or a regular SILK frame whose VAD flag was set + (an "active" frame), then the value of the symbol may range from 2 to 5, + inclusive, and is decoded using the second PDF in + . + translates between the value of the + frame type symbol and the corresponding signal type and quantization offset + type. + + + +VAD Flag +PDF +Inactive {26, 230, 0, 0, 0, 0}/256 +Active {0, 0, 24, 74, 148, 10}/256 + + + +Frame Type +Signal Type +Quantization Offset Type +0 Inactive Low +1 Inactive High +2 Unvoiced Low +3 Unvoiced High +4 Voiced Low +5 Voiced High + + +
    + +
    + +A separate quantization gain is coded for each 5 ms subframe. +These gains control the step size between quantization levels of the excitation + signal and, therefore, the quality of the reconstruction. +They are independent of and unrelated to the pitch contours coded for voiced + frames. +The quantization gains are themselves uniformly quantized to 6 bits on a + log scale, giving them a resolution of approximately 1.369 dB and a range + of approximately 1.94 dB to 88.21 dB. + + +The subframe gains are either coded independently, or relative to the gain from + the most recent coded subframe in the same channel. +Independent coding is used if and only if + + +This is the first subframe in the current SILK frame, and + +Either + + +This is the first SILK frame of its type (LBRR or regular) for this channel in + the current Opus frame, or + + +The previous SILK frame of the same type (LBRR or regular) for this channel in + the same Opus frame was not coded. + + + + + + + +In an independently coded subframe gain, the 3 most significant bits of the + quantization gain are decoded using a PDF selected from + based on the decoded signal + type (see ). + + + +Signal Type +PDF +Inactive {32, 112, 68, 29, 12, 1, 1, 1}/256 +Unvoiced {2, 17, 45, 60, 62, 47, 19, 4}/256 +Voiced {1, 3, 26, 71, 94, 50, 9, 2}/256 + + + +The 3 least significant bits are decoded using a uniform PDF: + + +PDF +{32, 32, 32, 32, 32, 32, 32, 32}/256 + + + +These 6 bits are combined to form a value, gain_index, between 0 and 63. +When the gain for the previous subframe is available, then the current gain is + limited as follows: +
    + +
    +This may help some implementations limit the change in precision of their + internal LTP history. +The indices which this clamp applies to cannot simply be removed from the + codebook, because previous_log_gain will not be available after packet loss. +The clamping is skipped after a decoder reset, and in the side channel if the + previous frame in the side channel was not coded, since there is no value for + previous_log_gain available. +It MAY also be skipped after packet loss. +
    + + +For subframes which do not have an independent gain (including the first + subframe of frames not listed as using independent coding above), the + quantization gain is coded relative to the gain from the previous subframe (in + the same channel). +The PDF in yields a delta_gain_index value + between 0 and 40, inclusive. + + +PDF +{6, 5, 11, 31, 132, 21, 8, 4, + 3, 2, 2, 2, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1}/256 + + +The following formula translates this index into a quantization gain for the + current subframe using the gain from the previous subframe: +
    + +
    +
    + +silk_gains_dequant() (gain_quant.c) dequantizes log_gain for the k'th subframe + and converts it into a linear Q16 scale factor via +
    +>16) + 2090) +]]> +
    +
    + +The function silk_log2lin() (log2lin.c) computes an approximation of + 2**(inLog_Q7/128.0), where inLog_Q7 is its Q7 input. +Let i = inLog_Q7>>7 be the integer part of inLogQ7 and + f = inLog_Q7&127 be the fractional part. +Then +
    +>16)+f)*((1<>7) +]]> +
    + yields the approximate exponential. +The final Q16 gain values lies between 81920 and 1686110208, inclusive + (representing scale factors of 1.25 to 25728, respectively). +
    +
    + +
    + +A set of normalized Line Spectral Frequency (LSF) coefficients follow the + quantization gains in the bitstream, and represent the Linear Predictive + Coding (LPC) coefficients for the current SILK frame. +Once decoded, the normalized LSFs form an increasing list of Q15 values between + 0 and 1. +These represent the interleaved zeros on the upper half of the unit circle + (between 0 and pi, hence "normalized") in the standard decomposition + of the LPC filter into a symmetric part + and an anti-symmetric part (P and Q in ). +Because of non-linear effects in the decoding process, an implementation SHOULD + match the fixed-point arithmetic described in this section exactly. +An encoder SHOULD also use the same process. + + +The normalized LSFs are coded using a two-stage vector quantizer (VQ) + ( and ). +NB and MB frames use an order-10 predictor, while WB frames use an order-16 + predictor, and thus have different sets of tables. +After reconstructing the normalized LSFs + (), the decoder runs them through a + stabilization process (), interpolates + them between frames (), converts them + back into LPC coefficients (), and then runs + them through further processes to limit the range of the coefficients + () and the gain of the filter + (). +All of this is necessary to ensure the reconstruction process is stable. + + +
    + +The first VQ stage uses a 32-element codebook, coded with one of the PDFs in + , depending on the audio bandwidth and + the signal type of the current SILK frame. +This yields a single index, I1, for the entire frame, which + +Indexes an element in a coarse codebook, +Selects the PDFs for the second stage of the VQ, and +Selects the prediction weights used to remove intra-frame redundancy from + the second stage. + +The actual codebook elements are listed in + and + , but they are not needed until the last + stages of reconstructing the LSF coefficients. + + + +Audio Bandwidth +Signal Type +PDF +NB or MB Inactive or unvoiced + +{44, 34, 30, 19, 21, 12, 11, 3, + 3, 2, 16, 2, 2, 1, 5, 2, + 1, 3, 3, 1, 1, 2, 2, 2, + 3, 1, 9, 9, 2, 7, 2, 1}/256 + +NB or MB Voiced + +{1, 10, 1, 8, 3, 8, 8, 14, +13, 14, 1, 14, 12, 13, 11, 11, +12, 11, 10, 10, 11, 8, 9, 8, + 7, 8, 1, 1, 6, 1, 6, 5}/256 + +WB Inactive or unvoiced + +{31, 21, 3, 17, 1, 8, 17, 4, + 1, 18, 16, 4, 2, 3, 1, 10, + 1, 3, 16, 11, 16, 2, 2, 3, + 2, 11, 1, 4, 9, 8, 7, 3}/256 + +WB Voiced + +{1, 4, 16, 5, 18, 11, 5, 14, +15, 1, 3, 12, 13, 14, 14, 6, +14, 12, 2, 6, 1, 12, 12, 11, +10, 3, 10, 5, 1, 1, 1, 3}/256 + + + +
    + +
    + +A total of 16 PDFs are available for the LSF residual in the second stage: the + 8 (a...h) for NB and MB frames given in + , and the 8 (i...p) for WB frames + given in . +Which PDF is used for which coefficient is driven by the index, I1, + decoded in the first stage. + lists the letter of the + corresponding PDF for each normalized LSF coefficient for NB and MB, and + lists the same information for WB. + + + +Codebook +PDF +a {1, 1, 1, 15, 224, 11, 1, 1, 1}/256 +b {1, 1, 2, 34, 183, 32, 1, 1, 1}/256 +c {1, 1, 4, 42, 149, 55, 2, 1, 1}/256 +d {1, 1, 8, 52, 123, 61, 8, 1, 1}/256 +e {1, 3, 16, 53, 101, 74, 6, 1, 1}/256 +f {1, 3, 17, 55, 90, 73, 15, 1, 1}/256 +g {1, 7, 24, 53, 74, 67, 26, 3, 1}/256 +h {1, 1, 18, 63, 78, 58, 30, 6, 1}/256 + + + +Codebook +PDF +i {1, 1, 1, 9, 232, 9, 1, 1, 1}/256 +j {1, 1, 2, 28, 186, 35, 1, 1, 1}/256 +k {1, 1, 3, 42, 152, 53, 2, 1, 1}/256 +l {1, 1, 10, 49, 126, 65, 2, 1, 1}/256 +m {1, 4, 19, 48, 100, 77, 5, 1, 1}/256 +n {1, 1, 14, 54, 100, 72, 12, 1, 1}/256 +o {1, 1, 15, 61, 87, 61, 25, 4, 1}/256 +p {1, 7, 21, 50, 77, 81, 17, 1, 1}/256 + + + +I1 +Coefficient + +0 1 2 3 4 5 6 7 8 9 + 0 +a a a a a a a a a a + 1 +b d b c c b c b b b + 2 +c b b b b b b b b b + 3 +b c c c c b c b b b + 4 +c d d d d c c c c c + 5 +a f d d c c c c b b + g +a c c c c c c c c b + 7 +c d g e e e f e f f + 8 +c e f f e f e g e e + 9 +c e e h e f e f f e +10 +e d d d c d c c c c +11 +b f f g e f e f f f +12 +c h e g f f f f f f +13 +c h f f f f f g f e +14 +d d f e e f e f e e +15 +c d d f f e e e e e +16 +c e e g e f e f f f +17 +c f e g f f f e f e +18 +c h e f e f e f f f +19 +c f e g h g f g f e +20 +d g h e g f f g e f +21 +c h g e e e f e f f +22 +e f f e g g f g f e +23 +c f f g f g e g e e +24 +e f f f d h e f f e +25 +c d e f f g e f f e +26 +c d c d d e c d d d +27 +b b c c c c c d c c +28 +e f f g g g f g e f +29 +d f f e e e e d d c +30 +c f d h f f e e f e +31 +e e f e f g f g f e + + + +I1 +Coefficient + +0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 + 0 +i  i  i  i  i  i  i  i  i  i  i  i  i  i  i  i + 1 +k  l  l  l  l  l  k  k  k  k  k  j  j  j  i  l + 2 +k  n  n  l  p  m  m  n  k  n  m  n  n  m  l  l + 3 +i  k  j  k  k  j  j  j  j  j  i  i  i  i  i  j + 4 +i  o  n  m  o  m  p  n  m  m  m  n  n  m  m  l + 5 +i  l  n  n  m  l  l  n  l  l  l  l  l  l  k  m + 6 +i  i  i  i  i  i  i  i  i  i  i  i  i  i  i  i + 7 +i  k  o  l  p  k  n  l  m  n  n  m  l  l  k  l + 8 +i  o  k  o  o  m  n  m  o  n  m  m  n  l  l  l + 9 +k  j  i  i  i  i  i  i  i  i  i  i  i  i  i  i +10 +i  j  i  i  i  i  i  i  i  i  i  i  i  i  i  j +11 +k  k  l  m  n  l  l  l  l  l  l  l  k  k  j  l +12 +k  k  l  l  m  l  l  l  l  l  l  l  l  k  j  l +13 +l  m  m  m  o  m  m  n  l  n  m  m  n  m  l  m +14 +i  o  m  n  m  p  n  k  o  n  p  m  m  l  n  l +15 +i  j  i  j  j  j  j  j  j  j  i  i  i  i  j  i +16 +j  o  n  p  n  m  n  l  m  n  m  m  m  l  l  m +17 +j  l  l  m  m  l  l  n  k  l  l  n  n  n  l  m +18 +k  l  l  k  k  k  l  k  j  k  j  k  j  j  j  m +19 +i  k  l  n  l  l  k  k  k  j  j  i  i  i  i  i +20 +l  m  l  n  l  l  k  k  j  j  j  j  j  k  k  m +21 +k  o  l  p  p  m  n  m  n  l  n  l  l  k  l  l +22 +k  l  n  o  o  l  n  l  m  m  l  l  l  l  k  m +23 +j  l  l  m  m  m  m  l  n  n  n  l  j  j  j  j +24 +k  n  l  o  o  m  p  m  m  n  l  m  m  l  l  l +25 +i  o  j  j  i  i  i  i  i  i  i  i  i  i  i  i +26 +i  o  o  l  n  k  n  n  l  m  m  p  p  m  m  m +27 +l  l  p  l  n  m  l  l  l  k  k  l  l  l  k  l +28 +i  i  j  i  i  i  k  j  k  j  j  k  k  k  j  j +29 +i  l  k  n  l  l  k  l  k  j  i  i  j  i  i  j +30 +l  n  n  m  p  n  l  l  k  l  k  k  j  i  j  i +31 +k  l  n  l  m  l  l  l  k  j  k  o  m  i  i  i + + + +Decoding the second stage residual proceeds as follows. +For each coefficient, the decoder reads a symbol using the PDF corresponding to + I1 from either or + , and subtracts 4 from the result + to give an index in the range -4 to 4, inclusive. +If the index is either -4 or 4, it reads a second symbol using the PDF in + , and adds the value of this second symbol + to the index, using the same sign. +This gives the index, I2[k], a total range of -10 to 10, inclusive. + + + +PDF +{156, 60, 24, 9, 4, 2, 1}/256 + + + +The decoded indices from both stages are translated back into normalized LSF + coefficients in silk_NLSF_decode() (NLSF_decode.c). +The stage-2 indices represent residuals after both the first stage of the VQ + and a separate backwards-prediction step. +The backwards prediction process in the encoder subtracts a prediction from + each residual formed by a multiple of the coefficient that follows it. +The decoder must undo this process. + contains lists of prediction weights + for each coefficient. +There are two lists for NB and MB, and another two lists for WB, giving two + possible prediction weights for each coefficient. + + + +Coefficient +A +B +C +D + 0 179 116 175 68 + 1 138 67 148 62 + 2 140 82 160 66 + 3 148 59 176 60 + 4 151 92 178 72 + 5 149 72 173 117 + 6 153 100 174 85 + 7 151 89 164 90 + 8 163 92 177 118 + 9 174 136 +10 196 151 +11 182 142 +12 198 160 +13 192 142 +14 182 155 + + + +The prediction is undone using the procedure implemented in + silk_NLSF_residual_dequant() (NLSF_decode.c), which is as follows. +Each coefficient selects its prediction weight from one of the two lists based + on the stage-1 index, I1. + gives the selections for each + coefficient for NB and MB, and gives + the selections for WB. +Let d_LPC be the order of the codebook, i.e., 10 for NB and MB, and 16 for WB, + and let pred_Q8[k] be the weight for the k'th coefficient selected by this + process for 0 <= k < d_LPC-1. +Then, the stage-2 residual for each coefficient is computed via +
    +>8 : 0) + + ((((I2[k]<<10) - sign(I2[k])*102)*qstep)>>16) , +]]> +
    + where qstep is the Q16 quantization step size, which is 11796 for NB and MB + and 9830 for WB (representing step sizes of approximately 0.18 and 0.15, + respectively). +
    + + +I1 +Coefficient + +0 1 2 3 4 5 6 7 8 + 0 +A B A A A A A A A + 1 +B A A A A A A A A + 2 +A A A A A A A A A + 3 +B B B A A A A B A + 4 +A B A A A A A A A + 5 +A B A A A A A A A + 6 +B A B B A A A B A + 7 +A B B A A B B A A + 8 +A A B B A B A B B + 9 +A A B B A A B B B +10 +A A A A A A A A A +11 +A B A B B B B B A +12 +A B A B B B B B A +13 +A B B B B B B B A +14 +B A B B A B B B B +15 +A B B B B B A B A +16 +A A B B A B A B A +17 +A A B B B A B B B +18 +A B B A A B B B A +19 +A A A B B B A B A +20 +A B B A A B A B A +21 +A B B A A A B B A +22 +A A A A A B B B B +23 +A A B B A A A B B +24 +A A A B A B B B B +25 +A B B B B B B B A +26 +A A A A A A A A A +27 +A A A A A A A A A +28 +A A B A B B A B A +29 +B A A B A A A A A +30 +A A A B B A B A B +31 +B A B B A B B B B + + + +I1 +Coefficient + +0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 + 0 +C  C  C  C  C  C  C  C  C  C  C  C  C  C  D + 1 +C  C  C  C  C  C  C  C  C  C  C  C  C  C  C + 2 +C  C  D  C  C  D  D  D  C  D  D  D  D  C  C + 3 +C  C  C  C  C  C  C  C  C  C  C  C  D  C  C + 4 +C  D  D  C  D  C  D  D  C  D  D  D  D  D  C + 5 +C  C  D  C  C  C  C  C  C  C  C  C  C  C  C + 6 +D  C  C  C  C  C  C  C  C  C  C  D  C  D  C + 7 +C  D  D  C  C  C  D  C  D  D  D  C  D  C  D + 8 +C  D  C  D  D  C  D  C  D  C  D  D  D  D  D + 9 +C  C  C  C  C  C  C  C  C  C  C  C  C  C  D +10 +C  D  C  C  C  C  C  C  C  C  C  C  C  C  C +11 +C  C  D  C  D  D  D  D  D  D  D  C  D  C  C +12 +C  C  D  C  C  D  C  D  C  D  C  C  D  C  C +13 +C  C  C  C  D  D  C  D  C  D  D  D  D  C  C +14 +C  D  C  C  C  D  D  C  D  D  D  C  D  D  D +15 +C  C  D  D  C  C  C  C  C  C  C  C  D  D  C +16 +C  D  D  C  D  C  D  D  D  D  D  C  D  C  C +17 +C  C  D  C  C  C  C  D  C  C  D  D  D  C  C +18 +C  C  C  C  C  C  C  C  C  C  C  C  C  C  D +19 +C  C  C  C  C  C  C  C  C  C  C  C  D  C  C +20 +C  C  C  C  C  C  C  C  C  C  C  C  C  C  C +21 +C  D  C  D  C  D  D  C  D  C  D  C  D  D  C +22 +C  C  D  D  D  D  C  D  D  C  C  D  D  C  C +23 +C  D  D  C  D  C  D  C  D  C  C  C  C  D  C +24 +C  C  C  D  D  C  D  C  D  D  D  D  D  D  D +25 +C  C  C  C  C  C  C  C  C  C  C  C  C  C  D +26 +C  D  D  C  C  C  D  D  C  C  D  D  D  D  D +27 +C  C  C  C  C  D  C  D  D  D  D  C  D  D  D +28 +C  C  C  C  C  C  C  C  C  C  C  C  C  C  D +29 +C  C  C  C  C  C  C  C  C  C  C  C  C  C  D +30 +D  C  C  C  C  C  C  C  C  C  C  D  C  C  C +31 +C  C  D  C  C  D  D  D  C  C  D  C  C  D  C + + +
    + +
    + +Once the stage-1 index I1 and the stage-2 residual res_Q10[] have been decoded, + the final normalized LSF coefficients can be reconstructed. + + +The spectral distortion introduced by the quantization of each LSF coefficient + varies, so the stage-2 residual is weighted accordingly, using the + low-complexity Inverse Harmonic Mean Weighting (IHMW) function proposed in + . +The weights are derived directly from the stage-1 codebook vector. +Let cb1_Q8[k] be the k'th entry of the stage-1 codebook vector from + or + . +Then for 0 <= k < d_LPC the following expression + computes the square of the weight as a Q18 value: +
    + + + +
    + where cb1_Q8[-1] = 0 and cb1_Q8[d_LPC] = 256, and the + division is integer division. +This is reduced to an unsquared, Q9 value using the following square-root + approximation: +
    +>(i-8)) & 127 +y = ((i&1) ? 32768 : 46214) >> ((32-i)>>1) +w_Q9[k] = y + ((213*f*y)>>16) +]]> +
    +The constant 46214 here is approximately the square root of 2 in Q15. +The cb1_Q8[] vector completely determines these weights, and they may be + tabulated and stored as 13-bit unsigned values (with a range of 1819 to 5227, + inclusive) to avoid computing them when decoding. +The reference implementation already requires code to compute these weights on + unquantized coefficients in the encoder, in silk_NLSF_VQ_weights_laroia() + (NLSF_VQ_weights_laroia.c) and its callers, so it reuses that code in the + decoder instead of using a pre-computed table to reduce the amount of ROM + required. +
    + + +I1 +Codebook (Q8) + + 0   1   2   3   4   5   6   7   8   9 +0 +12  35  60  83 108 132 157 180 206 228 +1 +15  32  55  77 101 125 151 175 201 225 +2 +19  42  66  89 114 137 162 184 209 230 +3 +12  25  50  72  97 120 147 172 200 223 +4 +26  44  69  90 114 135 159 180 205 225 +5 +13  22  53  80 106 130 156 180 205 228 +6 +15  25  44  64  90 115 142 168 196 222 +7 +19  24  62  82 100 120 145 168 190 214 +8 +22  31  50  79 103 120 151 170 203 227 +9 +21  29  45  65 106 124 150 171 196 224 +10 +30  49  75  97 121 142 165 186 209 229 +11 +19  25  52  70  93 116 143 166 192 219 +12 +26  34  62  75  97 118 145 167 194 217 +13 +25  33  56  70  91 113 143 165 196 223 +14 +21  34  51  72  97 117 145 171 196 222 +15 +20  29  50  67  90 117 144 168 197 221 +16 +22  31  48  66  95 117 146 168 196 222 +17 +24  33  51  77 116 134 158 180 200 224 +18 +21  28  70  87 106 124 149 170 194 217 +19 +26  33  53  64  83 117 152 173 204 225 +20 +27  34  65  95 108 129 155 174 210 225 +21 +20  26  72  99 113 131 154 176 200 219 +22 +34  43  61  78  93 114 155 177 205 229 +23 +23  29  54  97 124 138 163 179 209 229 +24 +30  38  56  89 118 129 158 178 200 231 +25 +21  29  49  63  85 111 142 163 193 222 +26 +27  48  77 103 133 158 179 196 215 232 +27 +29  47  74  99 124 151 176 198 220 237 +28 +33  42  61  76  93 121 155 174 207 225 +29 +29  53  87 112 136 154 170 188 208 227 +30 +24  30  52  84 131 150 166 186 203 229 +31 +37  48  64  84 104 118 156 177 201 230 + + + +I1 +Codebook (Q8) + + 0  1  2  3  4   5   6   7   8   9  10  11  12  13  14  15 +0 + 7 23 38 54 69  85 100 116 131 147 162 178 193 208 223 239 +1 +13 25 41 55 69  83  98 112 127 142 157 171 187 203 220 236 +2 +15 21 34 51 61  78  92 106 126 136 152 167 185 205 225 240 +3 +10 21 36 50 63  79  95 110 126 141 157 173 189 205 221 237 +4 +17 20 37 51 59  78  89 107 123 134 150 164 184 205 224 240 +5 +10 15 32 51 67  81  96 112 129 142 158 173 189 204 220 236 +6 + 8 21 37 51 65  79  98 113 126 138 155 168 179 192 209 218 +7 +12 15 34 55 63  78  87 108 118 131 148 167 185 203 219 236 +8 +16 19 32 36 56  79  91 108 118 136 154 171 186 204 220 237 +9 +11 28 43 58 74  89 105 120 135 150 165 180 196 211 226 241 +10 + 6 16 33 46 60  75  92 107 123 137 156 169 185 199 214 225 +11 +11 19 30 44 57  74  89 105 121 135 152 169 186 202 218 234 +12 +12 19 29 46 57  71  88 100 120 132 148 165 182 199 216 233 +13 +17 23 35 46 56  77  92 106 123 134 152 167 185 204 222 237 +14 +14 17 45 53 63  75  89 107 115 132 151 171 188 206 221 240 +15 + 9 16 29 40 56  71  88 103 119 137 154 171 189 205 222 237 +16 +16 19 36 48 57  76  87 105 118 132 150 167 185 202 218 236 +17 +12 17 29 54 71  81  94 104 126 136 149 164 182 201 221 237 +18 +15 28 47 62 79  97 115 129 142 155 168 180 194 208 223 238 +19 + 8 14 30 45 62  78  94 111 127 143 159 175 192 207 223 239 +20 +17 30 49 62 79  92 107 119 132 145 160 174 190 204 220 235 +21 +14 19 36 45 61  76  91 108 121 138 154 172 189 205 222 238 +22 +12 18 31 45 60  76  91 107 123 138 154 171 187 204 221 236 +23 +13 17 31 43 53  70  83 103 114 131 149 167 185 203 220 237 +24 +17 22 35 42 58  78  93 110 125 139 155 170 188 206 224 240 +25 + 8 15 34 50 67  83  99 115 131 146 162 178 193 209 224 239 +26 +13 16 41 66 73  86  95 111 128 137 150 163 183 206 225 241 +27 +17 25 37 52 63  75  92 102 119 132 144 160 175 191 212 231 +28 +19 31 49 65 83 100 117 133 147 161 174 187 200 213 227 242 +29 +18 31 52 68 88 103 117 126 138 149 163 177 192 207 223 239 +30 +16 29 47 61 76  90 106 119 133 147 161 176 193 209 224 240 +31 +15 21 35 50 61  73  86  97 110 119 129 141 175 198 218 237 + + + +Given the stage-1 codebook entry cb1_Q8[], the stage-2 residual res_Q10[], and + their corresponding weights, w_Q9[], the reconstructed normalized LSF + coefficients are +
    + +
    + where the division is integer division. +However, nothing in either the reconstruction process or the + quantization process in the encoder thus far guarantees that the coefficients + are monotonically increasing and separated well enough to ensure a stable + filter . +When using the reference encoder, roughly 2% of frames violate this constraint. +The next section describes a stabilization procedure used to make these + guarantees. +
    + +
    + +
    + +The normalized LSF stabilization procedure is implemented in + silk_NLSF_stabilize() (NLSF_stabilize.c). +This process ensures that consecutive values of the normalized LSF + coefficients, NLSF_Q15[], are spaced some minimum distance apart + (predetermined to be the 0.01 percentile of a large training set). + gives the minimum spacings for NB and MB + and those for WB, where row k is the minimum allowed value of + NLSF_Q[k]-NLSF_Q[k-1]. +For the purposes of computing this spacing for the first and last coefficient, + NLSF_Q15[-1] is taken to be 0, and NLSF_Q15[d_LPC] is taken to be 32768. + + + +Coefficient +NB and MB +WB + 0 250 100 + 1 3 3 + 2 6 40 + 3 3 3 + 4 3 3 + 5 3 3 + 6 4 5 + 7 3 14 + 8 3 14 + 9 3 10 +10 461 11 +11 3 +12 8 +13 9 +14 7 +15 3 +16 347 + + + +The procedure starts off by trying to make small adjustments which attempt to + minimize the amount of distortion introduced. +After 20 such adjustments, it falls back to a more direct method which + guarantees the constraints are enforced but may require large adjustments. + + +Let NDeltaMin_Q15[k] be the minimum required spacing for the current audio + bandwidth from . +First, the procedure finds the index i where + NLSF_Q15[i] - NLSF_Q15[i-1] - NDeltaMin_Q15[i] is the + smallest, breaking ties by using the lower value of i. +If this value is non-negative, then the stabilization stops; the coefficients + satisfy all the constraints. +Otherwise, if i == 0, it sets NLSF_Q15[0] to NDeltaMin_Q15[0], and if + i == d_LPC, it sets NLSF_Q15[d_LPC-1] to + (32768 - NDeltaMin_Q15[d_LPC]). +For all other values of i, both NLSF_Q15[i-1] and NLSF_Q15[i] are updated as + follows: +
    +>1) + \ NDeltaMin_Q15[k] + /_ + k=0 + d_LPC + __ + max_center_Q15 = 32768 - (NDeltaMin_Q15[i]>>1) - \ NDeltaMin_Q15[k] + /_ + k=i+1 +center_freq_Q15 = clamp(min_center_Q15[i], + (NLSF_Q15[i-1] + NLSF_Q15[i] + 1)>>1, + max_center_Q15[i]) + + NLSF_Q15[i-1] = center_freq_Q15 - (NDeltaMin_Q15[i]>>1) + + NLSF_Q15[i] = NLSF_Q15[i-1] + NDeltaMin_Q15[i] . +]]> +
    +Then the procedure repeats again, until it has either executed 20 times or + has stopped because the coefficients satisfy all the constraints. +
    + +After the 20th repetition of the above procedure, the following fallback + procedure executes once. +First, the values of NLSF_Q15[k] for 0 <= k < d_LPC + are sorted in ascending order. +Then for each value of k from 0 to d_LPC-1, NLSF_Q15[k] is set to +
    + +
    +Next, for each value of k from d_LPC-1 down to 0, NLSF_Q15[k] is set to +
    + +
    +
    + +
    + +
    + +For 20 ms SILK frames, the first half of the frame (i.e., the first two + subframes) may use normalized LSF coefficients that are interpolated between + the decoded LSFs for the most recent coded frame (in the same channel) and the + current frame. +A Q2 interpolation factor follows the LSF coefficient indices in the bitstream, + which is decoded using the PDF in . +This happens in silk_decode_indices() (decode_indices.c). +After either + +An uncoded regular SILK frame in the side channel, or +A decoder reset (see ), + + the decoder still decodes this factor, but ignores its value and always uses + 4 instead. +For 10 ms SILK frames, this factor is not stored at all. + + + +PDF +{13, 22, 29, 11, 181}/256 + + + +Let n2_Q15[k] be the normalized LSF coefficients decoded by the procedure in + , n0_Q15[k] be the LSF coefficients + decoded for the prior frame, and w_Q2 be the interpolation factor. +Then the normalized LSF coefficients used for the first half of a 20 ms + frame, n1_Q15[k], are +
    +> 2) . +]]> +
    +This interpolation is performed in silk_decode_parameters() + (decode_parameters.c). +
    +
    + +
    + +Any LPC filter A(z) can be split into a symmetric part P(z) and an + anti-symmetric part Q(z) such that +
    + +
    +with +
    + +
    +The even normalized LSF coefficients correspond to a pair of conjugate roots of + P(z), while the odd coefficients correspond to a pair of conjugate roots of + Q(z), all of which lie on the unit circle. +In addition, P(z) has a root at pi and Q(z) has a root at 0. +Thus, they may be reconstructed mathematically from a set of normalized LSF + coefficients, n[k], as +
    + +
    +
    + +However, SILK performs this reconstruction using a fixed-point approximation so + that all decoders can reproduce it in a bit-exact manner to avoid prediction + drift. +The function silk_NLSF2A() (NLSF2A.c) implements this procedure. + + +To start, it approximates cos(pi*n[k]) using a table lookup with linear + interpolation. +The encoder SHOULD use the inverse of this piecewise linear approximation, + rather than the true inverse of the cosine function, when deriving the + normalized LSF coefficients. +These values are also re-ordered to improve numerical accuracy when + constructing the LPC polynomials. + + + +Coefficient +NB and MB +WB + 0 0 0 + 1 9 15 + 2 6 8 + 3 3 7 + 4 4 4 + 5 5 11 + 6 8 12 + 7 1 3 + 8 2 2 + 9 7 13 +10 10 +11 5 +12 6 +13 9 +14 14 +15 1 + + + +The top 7 bits of each normalized LSF coefficient index a value in the table, + and the next 8 bits interpolate between it and the next value. +Let i = (n[k] >> 8) be the integer index and + f = (n[k] & 255) be the fractional part of a given + coefficient. +Then the re-ordered, approximated cosine, c_Q17[ordering[k]], is +
    +> 3 , +]]> +
    + where ordering[k] is the k'th entry of the column of + corresponding to the current audio + bandwidth and cos_Q12[i] is the i'th entry of . +
    + + +i ++0 ++1 ++2 ++3 +0 + 4096 4095 4091 4085 +4 + 4076 4065 4052 4036 +8 + 4017 3997 3973 3948 +12 + 3920 3889 3857 3822 +16 + 3784 3745 3703 3659 +20 + 3613 3564 3513 3461 +24 + 3406 3349 3290 3229 +28 + 3166 3102 3035 2967 +32 + 2896 2824 2751 2676 +36 + 2599 2520 2440 2359 +40 + 2276 2191 2106 2019 +44 + 1931 1842 1751 1660 +48 + 1568 1474 1380 1285 +52 + 1189 1093 995 897 +56 + 799 700 601 501 +60 + 401 301 201 101 +64 + 0 -101 -201 -301 +68 + -401 -501 -601 -700 +72 + -799 -897 -995 -1093 +76 +-1189-1285-1380-1474 +80 +-1568-1660-1751-1842 +84 +-1931-2019-2106-2191 +88 +-2276-2359-2440-2520 +92 +-2599-2676-2751-2824 +96 +-2896-2967-3035-3102 +100 +-3166-3229-3290-3349 +104 +-3406-3461-3513-3564 +108 +-3613-3659-3703-3745 +112 +-3784-3822-3857-3889 +116 +-3920-3948-3973-3997 +120 +-4017-4036-4052-4065 +124 +-4076-4085-4091-4095 +128 +-4096 + + + +Given the list of cosine values, silk_NLSF2A_find_poly() (NLSF2A.c) + computes the coefficients of P and Q, described here via a simple recurrence. +Let p_Q16[k][j] and q_Q16[k][j] be the coefficients of the products of the + first (k+1) root pairs for P and Q, with j indexing the coefficient number. +Only the first (k+2) coefficients are needed, as the products are symmetric. +Let p_Q16[0][0] = q_Q16[0][0] = 1<<16, + p_Q16[0][1] = -c_Q17[0], q_Q16[0][1] = -c_Q17[1], and + d2 = d_LPC/2. +As boundary conditions, assume + p_Q16[k][j] = q_Q16[k][j] = 0 for all + j < 0. +Also, assume p_Q16[k][k+2] = p_Q16[k][k] and + q_Q16[k][k+2] = q_Q16[k][k] (because of the symmetry). +Then, for 0 < k < d2 and 0 <= j <= k+1, +
    +>16) , + +q_Q16[k][j] = q_Q16[k-1][j] + q_Q16[k-1][j-2] + - ((c_Q17[2*k+1]*q_Q16[k-1][j-1] + 32768)>>16) . +]]> +
    +The use of Q17 values for the cosine terms in an otherwise Q16 expression + implicitly scales them by a factor of 2. +The multiplications in this recurrence may require up to 48 bits of precision + in the result to avoid overflow. +In practice, each row of the recurrence only depends on the previous row, so an + implementation does not need to store all of them. +
    + +silk_NLSF2A() uses the values from the last row of this recurrence to + reconstruct a 32-bit version of the LPC filter (without the leading 1.0 + coefficient), a32_Q17[k], 0 <= k < d2: +
    + +
    +The sum and difference of two terms from each of the p_Q16 and q_Q16 + coefficient lists reflect the (1 + z**-1) and + (1 - z**-1) factors of P and Q, respectively. +The promotion of the expression from Q16 to Q17 implicitly scales the result + by 1/2. +
    +
    + +
    + +The a32_Q17[] coefficients are too large to fit in a 16-bit value, which + significantly increases the cost of applying this filter in fixed-point + decoders. +Reducing them to Q12 precision doesn't incur any significant quality loss, + but still does not guarantee they will fit. +silk_NLSF2A() applies up to 10 rounds of bandwidth expansion to limit + the dynamic range of these coefficients. +Even floating-point decoders SHOULD perform these steps, to avoid mismatch. + + +For each round, the process first finds the index k such that abs(a32_Q17[k]) + is largest, breaking ties by choosing the lowest value of k. +Then, it computes the corresponding Q12 precision value, maxabs_Q12, subject to + an upper bound to avoid overflow in subsequent computations: +
    +> 5, 163838) . +]]> +
    +If this is larger than 32767, the procedure derives the chirp factor, + sc_Q16[0], to use in the bandwidth expansion as +
    +> 2 +]]> +
    + where the division here is integer division. +This is an approximation of the chirp factor needed to reduce the target + coefficient to 32767, though it is both less than 0.999 and, for + k > 0 when maxabs_Q12 is much greater than 32767, still slightly + too large. +The upper bound on maxabs_Q12, 163838, was chosen because it is equal to + ((2**31 - 1) >> 14) + 32767, i.e., the + largest value of maxabs_Q12 that would not overflow the numerator in the + equation above when stored in a signed 32-bit integer. +
    + +silk_bwexpander_32() (bwexpander_32.c) performs the bandwidth expansion (again, + only when maxabs_Q12 is greater than 32767) using the following recurrence: +
    +> 16 + +sc_Q16[k+1] = (sc_Q16[0]*sc_Q16[k] + 32768) >> 16 +]]> +
    +The first multiply may require up to 48 bits of precision in the result to + avoid overflow. +The second multiply must be unsigned to avoid overflow with only 32 bits of + precision. +The reference implementation uses a slightly more complex formulation that + avoids the 32-bit overflow using signed multiplication, but is otherwise + equivalent. +
    + +After 10 rounds of bandwidth expansion are performed, they are simply saturated + to 16 bits: +
    +> 5, 32767) << 5 . +]]> +
    +Because this performs the actual saturation in the Q12 domain, but converts the + coefficients back to the Q17 domain for the purposes of prediction gain + limiting, this step must be performed after the 10th round of bandwidth + expansion, regardless of whether or not the Q12 version of any coefficient + still overflows a 16-bit integer. +This saturation is not performed if maxabs_Q12 drops to 32767 or less prior to + the 10th round. +
    +
    + +
    + +The prediction gain of an LPC synthesis filter is the square-root of the output + energy when the filter is excited by a unit-energy impulse. +Even if the Q12 coefficients would fit, the resulting filter may still have a + significant gain (especially for voiced sounds), making the filter unstable. +silk_NLSF2A() applies up to 18 additional rounds of bandwidth expansion to + limit the prediction gain. +Instead of controlling the amount of bandwidth expansion using the prediction + gain itself (which may diverge to infinity for an unstable filter), + silk_NLSF2A() uses silk_LPC_inverse_pred_gain_QA() (LPC_inv_pred_gain.c) to + compute the reflection coefficients associated with the filter. +The filter is stable if and only if the magnitude of these coefficients is + sufficiently less than one. +The reflection coefficients, rc[k], can be computed using a simple Levinson + recurrence, initialized with the LPC coefficients + a[d_LPC-1][n] = a[n], and then updated via +
    + +
    +
    + +However, silk_LPC_inverse_pred_gain_QA() approximates this using fixed-point + arithmetic to guarantee reproducible results across platforms and + implementations. +Since small changes in the coefficients can make a stable filter unstable, it + takes the real Q12 coefficients that will be used during reconstruction as + input. +Thus, let +
    +> 5 +]]> +
    + be the Q12 version of the LPC coefficients that will eventually be used. +As a simple initial check, the decoder computes the DC response as +
    + +
    + and if DC_resp > 4096, the filter is unstable. +
    + +Increasing the precision of these Q12 coefficients to Q24 for intermediate + computations allows more accurate computation of the reflection coefficients, + so the decoder initializes the recurrence via +
    + +
    +Then for each k from d_LPC-1 down to 0, if + abs(a32_Q24[k][k]) > 16773022, the filter is unstable and the + recurrence stops. +The constant 16773022 here is approximately 0.99975 in Q24. +Otherwise, row k-1 of a32_Q24 is computed from row k as +
    +> 32) , + + b1[k] = ilog(div_Q30[k]) , + + b2[k] = b1[k] - 16 , + + (1<<29) - 1 + inv_Qb2[k] = ----------------------- , + div_Q30[k] >> (b2[k]+1) + + err_Q29[k] = (1<<29) + - ((div_Q30[k]<<(15-b2[k]))*inv_Qb2[k] >> 16) , + + gain_Qb1[k] = ((inv_Qb2[k] << 16) + + (err_Q29[k]*inv_Qb2[k] >> 13)) , + +num_Q24[k-1][n] = a32_Q24[k][n] + - ((a32_Q24[k][k-n-1]*rc_Q31[k] + (1<<30)) >> 31) , + +a32_Q24[k-1][n] = (num_Q24[k-1][n]*gain_Qb1[k] + + (1<<(b1[k]-1))) >> b1[k] , +]]> +
    + where 0 <= n < k. +Here, rc_Q30[k] are the reflection coefficients. +div_Q30[k] is the denominator for each iteration, and gain_Qb1[k] is its + multiplicative inverse (with b1[k] fractional bits, where b1[k] ranges from + 20 to 31). +inv_Qb2[k], which ranges from 16384 to 32767, is a low-precision version of + that inverse (with b2[k] fractional bits). +err_Q29[k] is the residual error, ranging from -32763 to 32392, which is used + to improve the accuracy. +The values t_Q24[k-1][n] for each n are the numerators for the next row of + coefficients in the recursion, and a32_Q24[k-1][n] is the final version of + that row. +Every multiply in this procedure except the one used to compute gain_Qb1[k] + requires more than 32 bits of precision, but otherwise all intermediate + results fit in 32 bits or less. +In practice, because each row only depends on the next one, an implementation + does not need to store them all. +
    + +If abs(a32_Q24[k][k]) <= 16773022 for + 0 <= k < d_LPC, then the filter is considered stable. +However, the problem of determining stability is ill-conditioned when the + filter contains several reflection coefficients whose magnitude is very close + to one. +This fixed-point algorithm is not mathematically guaranteed to correctly + classify filters as stable or unstable in this case, though it does very well + in practice. + + +On round i, 1 <= i <= 18, if the filter passes these + stability checks, then this procedure stops, and the final LPC coefficients to + use for reconstruction in are +
    +> 5 . +]]> +
    +Otherwise, a round of bandwidth expansion is applied using the same procedure + as in , with +
    + +
    +During the 15th round, sc_Q16[0] becomes 0 in the above equation, so a_Q12[k] + is set to 0 for all k, guaranteeing a stable filter. +
    +
    + +
    + +
    + +After the normalized LSF indices and, for 20 ms frames, the LSF + interpolation index, voiced frames (see ) + include additional LTP parameters. +There is one primary lag index for each SILK frame, but this is refined to + produce a separate lag index per subframe using a vector quantizer. +Each subframe also gets its own prediction gain coefficient. + + +
    + +The primary lag index is coded either relative to the primary lag of the prior + frame in the same channel, or as an absolute index. +Absolute coding is used if and only if + + +This is the first SILK frame of its type (LBRR or regular) for this channel in + the current Opus frame, + + +The previous SILK frame of the same type (LBRR or regular) for this channel in + the same Opus frame was not coded, or + + +That previous SILK frame was coded, but was not voiced (see + ). + + + + + +With absolute coding, the primary pitch lag may range from 2 ms + (inclusive) up to 18 ms (exclusive), corresponding to pitches from + 500 Hz down to 55.6 Hz, respectively. +It is comprised of a high part and a low part, where the decoder reads the high + part using the 32-entry codebook in + and the low part using the codebook corresponding to the current audio + bandwidth from . +The final primary pitch lag is then +
    + +
    + where lag_high is the high part, lag_low is the low part, and lag_scale + and lag_min are the values from the "Scale" and "Minimum Lag" columns of + , respectively. +
    + + +PDF +{3, 3, 6, 11, 21, 30, 32, 19, + 11, 10, 12, 13, 13, 12, 11, 9, + 8, 7, 6, 4, 2, 2, 2, 1, + 1, 1, 1, 1, 1, 1, 1, 1}/256 + + + +Audio Bandwidth +PDF +Scale +Minimum Lag +Maximum Lag +NB {64, 64, 64, 64}/256 4 16 144 +MB {43, 42, 43, 43, 42, 43}/256 6 24 216 +WB {32, 32, 32, 32, 32, 32, 32, 32}/256 8 32 288 + + + +All frames that do not use absolute coding for the primary lag index use + relative coding instead. +The decoder reads a single delta value using the 21-entry PDF in + . +If the resulting value is zero, it falls back to the absolute coding procedure + from the prior paragraph. +Otherwise, the final primary pitch lag is then +
    + +
    + where previous_lag is the primary pitch lag from the most recent frame in the + same channel and delta_lag_index is the value just decoded. +This allows a per-frame change in the pitch lag of -8 to +11 samples. +The decoder does no clamping at this point, so this value can fall outside the + range of 2 ms to 18 ms, and the decoder must use this unclamped + value when using relative coding in the next SILK frame (if any). +However, because an Opus frame can use relative coding for at most two + consecutive SILK frames, integer overflow should not be an issue. +
    + + +PDF +{46, 2, 2, 3, 4, 6, 10, 15, + 26, 38, 30, 22, 15, 10, 7, 6, + 4, 4, 2, 2, 2}/256 + + + +After the primary pitch lag, a "pitch contour", stored as a single entry from + one of four small VQ codebooks, gives lag offsets for each subframe in the + current SILK frame. +The codebook index is decoded using one of the PDFs in + depending on the current frame size + and audio bandwidth. +Tables  + through  + give the corresponding offsets to apply to the primary pitch lag for each + subframe given the decoded codebook index. + + + +Audio Bandwidth +SILK Frame Size +Codebook Size +PDF +NB 10 ms 3 +{143, 50, 63}/256 +NB 20 ms 11 +{68, 12, 21, 17, 19, 22, 30, 24, + 17, 16, 10}/256 +MB or WB 10 ms 12 +{91, 46, 39, 19, 14, 12, 8, 7, + 6, 5, 5, 4}/256 +MB or WB 20 ms 34 +{33, 22, 18, 16, 15, 14, 14, 13, + 13, 10, 9, 9, 8, 6, 6, 6, + 5, 4, 4, 4, 3, 3, 3, 2, + 2, 2, 2, 2, 2, 2, 1, 1, + 1, 1}/256 + + + +Index +Subframe Offsets +0  0  0 +1  1  0 +2  0  1 + + + +Index +Subframe Offsets + 0  0  0  0  0 + 1  2  1  0 -1 + 2 -1  0  1  2 + 3 -1  0  0  1 + 4 -1  0  0  0 + 5  0  0  0  1 + 6  0  0  1  1 + 7  1  1  0  0 + 8  1  0  0  0 + 9  0  0  0 -1 +10  1  0  0 -1 + + + +Index +Subframe Offsets + 0  0  0 + 1  0  1 + 2  1  0 + 3 -1  1 + 4  1 -1 + 5 -1  2 + 6  2 -1 + 7 -2  2 + 8  2 -2 + 9 -2  3 +10  3 -2 +11 -3  3 + + + +Index +Subframe Offsets + 0  0  0  0  0 + 1  0  0  1  1 + 2  1  1  0  0 + 3 -1  0  0  0 + 4  0  0  0  1 + 5  1  0  0  0 + 6 -1  0  0  1 + 7  0  0  0 -1 + 8 -1  0  1  2 + 9  1  0  0 -1 +10 -2 -1  1  2 +11  2  1  0 -1 +12 -2  0  0  2 +13 -2  0  1  3 +14  2  1 -1 -2 +15 -3 -1  1  3 +16  2  0  0 -2 +17  3  1  0 -2 +18 -3 -1  2  4 +19 -4 -1  1  4 +20  3  1 -1 -3 +21 -4 -1  2  5 +22  4  2 -1 -3 +23  4  1 -1 -4 +24 -5 -1  2  6 +25  5  2 -1 -4 +26 -6 -2  2  6 +27 -5 -2  2  5 +28  6  2 -1 -5 +29 -7 -2  3  8 +30  6  2 -2 -6 +31  5  2 -2 -5 +32  8  3 -2 -7 +33 -9 -3  3  9 + + + +The final pitch lag for each subframe is assembled in silk_decode_pitch() + (decode_pitch.c). +Let lag be the primary pitch lag for the current SILK frame, contour_index be + index of the VQ codebook, and lag_cb[contour_index][k] be the corresponding + entry of the codebook from the appropriate table given above for the k'th + subframe. +Then the final pitch lag for that subframe is +
    + +
    + where lag_min and lag_max are the values from the "Minimum Lag" and + "Maximum Lag" columns of , + respectively. +
    + +
    + +
    + +SILK uses a separate 5-tap pitch filter for each subframe, selected from one + of three codebooks. +The three codebooks each represent different rate-distortion trade-offs, with + average rates of 1.61 bits/subframe, 3.68 bits/subframe, and + 4.85 bits/subframe, respectively. + + + +The importance of the filter coefficients generally depends on two factors: the + periodicity of the signal and relative energy between the current subframe and + the signal from one period earlier. +Greater periodicity and decaying energy both lead to more important filter + coefficients, and thus should be coded with lower distortion and higher rate. +These properties are relatively stable over the duration of a single SILK + frame, hence all of the subframes in a SILK frame choose their filter from the + same codebook. +This is signaled with an explicitly-coded "periodicity index". +This immediately follows the subframe pitch lags, and is coded using the + 3-entry PDF from . + + + +PDF +{77, 80, 99}/256 + + + +The indices of the filters for each subframe follow. +They are all coded using the PDF from + corresponding to the periodicity index. +Tables  + through  + contain the corresponding filter taps as signed Q7 integers. + + + +Periodicity Index +Codebook Size +PDF +0 8 {185, 15, 13, 13, 9, 9, 6, 6}/256 +1 16 {57, 34, 21, 20, 15, 13, 12, 13, + 10, 10, 9, 10, 9, 8, 7, 8}/256 +2 32 {15, 16, 14, 12, 12, 12, 11, 11, + 11, 10, 9, 9, 9, 9, 8, 8, + 8, 8, 7, 7, 6, 6, 5, 4, + 5, 4, 4, 4, 3, 4, 3, 2}/256 + + + +Index +Filter Taps (Q7) + 0 +  4   6  24   7   5 + 1 +  0   0   2   0   0 + 2 + 12  28  41  13  -4 + 3 + -9  15  42  25  14 + 4 +  1  -2  62  41  -9 + 5 +-10  37  65  -4   3 + 6 + -6   4  66   7  -8 + 7 + 16  14  38  -3  33 + + + +Index +Filter Taps (Q7) + + 0 + 13  22  39  23  12 + 1 + -1  36  64  27  -6 + 2 + -7  10  55  43  17 + 3 +  1   1   8   1   1 + 4 +  6 -11  74  53  -9 + 5 +-12  55  76 -12   8 + 6 + -3   3  93  27  -4 + 7 + 26  39  59   3  -8 + 8 +  2   0  77  11   9 + 9 + -8  22  44  -6   7 +10 + 40   9  26   3   9 +11 + -7  20 101  -7   4 +12 +  3  -8  42  26   0 +13 +-15  33  68   2  23 +14 + -2  55  46  -2  15 +15 +  3  -1  21  16  41 + + + +Index +Filter Taps (Q7) + 0 + -6  27  61  39   5 + 1 +-11  42  88   4   1 + 2 + -2  60  65   6  -4 + 3 + -1  -5  73  56   1 + 4 + -9  19  94  29  -9 + 5 +  0  12  99   6   4 + 6 +  8 -19 102  46 -13 + 7 +  3   2  13   3   2 + 8 +  9 -21  84  72 -18 + 9 +-11  46 104 -22   8 +10 + 18  38  48  23   0 +11 +-16  70  83 -21  11 +12 +  5 -11 117  22  -8 +13 + -6  23 117 -12   3 +14 +  3  -8  95  28   4 +15 +-10  15  77  60 -15 +16 + -1   4 124   2  -4 +17 +  3  38  84  24 -25 +18 +  2  13  42  13  31 +19 + 21  -4  56  46  -1 +20 + -1  35  79 -13  19 +21 + -7  65  88  -9 -14 +22 + 20   4  81  49 -29 +23 + 20   0  75   3 -17 +24 +  5  -9  44  92  -8 +25 +  1  -3  22  69  31 +26 + -6  95  41 -12   5 +27 + 39  67  16  -4   1 +28 +  0  -6 120  55 -36 +29 +-13  44 122   4 -24 +30 + 81   5  11   3   7 +31 +  2   0   9  10  88 + + +
    + +
    + +An LTP scaling parameter appears after the LTP filter coefficients if and only + if + +This is a voiced frame (see ), and +Either + + +This SILK frame corresponds to the first time interval of the + current Opus frame for its type (LBRR or regular), or + + +This is an LBRR frame where the LBRR flags (see + ) indicate the previous LBRR frame in the same + channel is not coded. + + + + +This allows the encoder to trade off the prediction gain between + packets against the recovery time after packet loss. +Unlike absolute-coding for pitch lags, regular SILK frames that are not at the + start of an Opus frame (i.e., that do not correspond to the first 20 ms + time interval in Opus frames of 40 or 60 ms) do not include this + field, even if the prior frame was not voiced, or (in the case of the side + channel) not even coded. +After an uncoded frame in the side channel, the LTP buffer (see + ) is cleared to zero, and is thus in a + known state. +In contrast, LBRR frames do include this field when the prior frame was not + coded, since the LTP buffer contains the output of the PLC, which is + non-normative. + + +If present, the decoder reads a value using the 3-entry PDF in + . +The three possible values represent Q14 scale factors of 15565, 12288, and + 8192, respectively (corresponding to approximately 0.95, 0.75, and 0.5). +Frames that do not code the scaling parameter use the default factor of 15565 + (approximately 0.95). + + + +PDF +{128, 64, 64}/256 + + +
    + +
    + +
    + +As described in , SILK uses a + linear congruential generator (LCG) to inject pseudorandom noise into the + quantized excitation. +To ensure synchronization of this process between the encoder and decoder, each + SILK frame stores a 2-bit seed after the LTP parameters (if any). +The encoder may consider the choice of seed during quantization, and the + flexibility of this choice lets it reduce distortion, helping to pay for the + bit cost required to signal it. +The decoder reads the seed using the uniform 4-entry PDF in + , yielding a value between 0 and 3, inclusive. + + + +PDF +{64, 64, 64, 64}/256 + + +
    + +
    + +SILK codes the excitation using a modified version of the Pyramid Vector + Quantization (PVQ) codebook . +The PVQ codebook is designed for Laplace-distributed values and consists of all + sums of K signed, unit pulses in a vector of dimension N, where two pulses at + the same position are required to have the same sign. +Thus the codebook includes all integer codevectors y of dimension N that + satisfy +
    + +
    +Unlike regular PVQ, SILK uses a variable-length, rather than fixed-length, + encoding. +This encoding is better suited to the more Gaussian-like distribution of the + coefficient magnitudes and the non-uniform distribution of their signs (caused + by the quantization offset described below). +SILK also handles large codebooks by coding the least significant bits (LSBs) + of each coefficient directly. +This adds a small coding efficiency loss, but greatly reduces the computation + time and ROM size required for decoding, as implemented in + silk_decode_pulses() (decode_pulses.c). +
    + + +SILK fixes the dimension of the codebook to N = 16. +The excitation is made up of a number of "shell blocks", each 16 samples in + size. + lists the number of shell blocks + required for a SILK frame for each possible audio bandwidth and frame size. +10 ms MB frames nominally contain 120 samples (10 ms at + 12 kHz), which is not a multiple of 16. +This is handled by coding 8 shell blocks (128 samples) and discarding the final + 8 samples of the last block. +The decoder contains no special case that prevents an encoder from placing + pulses in these samples, and they must be correctly parsed from the bitstream + if present, but they are otherwise ignored. + + + +Audio Bandwidth +Frame Size +Number of Shell Blocks +NB 10 ms 5 +MB 10 ms 8 +WB 10 ms 10 +NB 20 ms 10 +MB 20 ms 15 +WB 20 ms 20 + + +
    + +The first symbol in the excitation is a "rate level", which is an index from 0 + to 8, inclusive, coded using the PDF in + corresponding to the signal type of the current frame (from + ). +The rate level selects the PDF used to decode the number of pulses in + the individual shell blocks. +It does not directly convey any information about the bitrate or the number of + pulses itself, but merely changes the probability of the symbols in + . +Level 0 provides a more efficient encoding at low rates generally, and + level 8 provides a more efficient encoding at high rates generally, + though the most efficient level for a particular SILK frame may depend on the + exact distribution of the coded symbols. +An encoder should, but is not required to, use the most efficient rate level. + + + +Signal Type +PDF +Inactive or Unvoiced +{15, 51, 12, 46, 45, 13, 33, 27, 14}/256 +Voiced +{33, 30, 36, 17, 34, 49, 18, 21, 18}/256 + + +
    + +
    + +The total number of pulses in each of the shell blocks follows the rate level. +The pulse counts for all of the shell blocks are coded consecutively, before + the content of any of the blocks. +Each block may have anywhere from 0 to 16 pulses, inclusive, coded using the + 18-entry PDF in corresponding to the + rate level from . +The special value 17 indicates that this block has one or more additional + LSBs to decode for each coefficient. +If the decoder encounters this value, it decodes another value for the actual + pulse count of the block, but uses the PDF corresponding to the special rate + level 9 instead of the normal rate level. +This process repeats until the decoder reads a value less than 17, and it then + sets the number of extra LSBs used to the number of 17's decoded for that + block. +If it reads the value 17 ten times, then the next iteration uses the special + rate level 10 instead of 9. +The probability of decoding a 17 when using the PDF for rate level 10 is + zero, ensuring that the number of LSBs for a block will not exceed 10. +The cumulative distribution for rate level 10 is just a shifted version of + that for 9 and thus does not require any additional storage. + + + +Rate Level +PDF +0 +{131, 74, 25, 8, 3, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}/256 +1 +{58, 93, 60, 23, 7, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}/256 +2 +{43, 51, 46, 33, 24, 16, 11, 8, 6, 3, 3, 3, 2, 1, 1, 2, 1, 2}/256 +3 +{17, 52, 71, 57, 31, 12, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}/256 +4 +{6, 21, 41, 53, 49, 35, 21, 11, 6, 3, 2, 2, 1, 1, 1, 1, 1, 1}/256 +5 +{7, 14, 22, 28, 29, 28, 25, 20, 17, 13, 11, 9, 7, 5, 4, 4, 3, 10}/256 +6 +{2, 5, 14, 29, 42, 46, 41, 31, 19, 11, 6, 3, 2, 1, 1, 1, 1, 1}/256 +7 +{1, 2, 4, 10, 19, 29, 35, 37, 34, 28, 20, 14, 8, 5, 4, 2, 2, 2}/256 +8 +{1, 2, 2, 5, 9, 14, 20, 24, 27, 28, 26, 23, 20, 15, 11, 8, 6, 15}/256 +9 +{1, 1, 1, 6, 27, 58, 56, 39, 25, 14, 10, 6, 3, 3, 2, 1, 1, 2}/256 +10 +{2, 1, 6, 27, 58, 56, 39, 25, 14, 10, 6, 3, 3, 2, 1, 1, 2, 0}/256 + + +
    + +
    + +The locations of the pulses in each shell block follow the pulse counts, + as decoded by silk_shell_decoder() (shell_coder.c). +As with the pulse counts, these locations are coded for all the shell blocks + before any of the remaining information for each block. +Unlike many other codecs, SILK places no restriction on the distribution of + pulses within a shell block. +All of the pulses may be placed in a single location, or each one in a unique + location, or anything in between. + + + +The location of pulses is coded by recursively partitioning each block into + halves, and coding how many pulses fall on the left side of the split. +All remaining pulses must fall on the right side of the split. +The process then recurses into the left half, and after that returns, the + right half (preorder traversal). +The PDF to use is chosen by the size of the current partition (16, 8, 4, or 2) + and the number of pulses in the partition (1 to 16, inclusive). +Tables  + through  list the + PDFs used for each partition size and pulse count. +This process skips partitions without any pulses, i.e., where the initial pulse + count from was zero, or where the split in + the prior level indicated that all of the pulses fell on the other side. +These partitions have nothing to code, so they require no PDF. + + + +Pulse Count +PDF + 1 {126, 130}/256 + 2 {56, 142, 58}/256 + 3 {25, 101, 104, 26}/256 + 4 {12, 60, 108, 64, 12}/256 + 5 {7, 35, 84, 87, 37, 6}/256 + 6 {4, 20, 59, 86, 63, 21, 3}/256 + 7 {3, 12, 38, 72, 75, 42, 12, 2}/256 + 8 {2, 8, 25, 54, 73, 59, 27, 7, 1}/256 + 9 {2, 5, 17, 39, 63, 65, 42, 18, 4, 1}/256 +10 {1, 4, 12, 28, 49, 63, 54, 30, 11, 3, 1}/256 +11 {1, 4, 8, 20, 37, 55, 57, 41, 22, 8, 2, 1}/256 +12 {1, 3, 7, 15, 28, 44, 53, 48, 33, 16, 6, 1, 1}/256 +13 {1, 2, 6, 12, 21, 35, 47, 48, 40, 25, 12, 5, 1, 1}/256 +14 {1, 1, 4, 10, 17, 27, 37, 47, 43, 33, 21, 9, 4, 1, 1}/256 +15 {1, 1, 1, 8, 14, 22, 33, 40, 43, 38, 28, 16, 8, 1, 1, 1}/256 +16 {1, 1, 1, 1, 13, 18, 27, 36, 41, 41, 34, 24, 14, 1, 1, 1, 1}/256 + + + +Pulse Count +PDF + 1 {127, 129}/256 + 2 {53, 149, 54}/256 + 3 {22, 105, 106, 23}/256 + 4 {11, 61, 111, 63, 10}/256 + 5 {6, 35, 86, 88, 36, 5}/256 + 6 {4, 20, 59, 87, 62, 21, 3}/256 + 7 {3, 13, 40, 71, 73, 41, 13, 2}/256 + 8 {3, 9, 27, 53, 70, 56, 28, 9, 1}/256 + 9 {3, 8, 19, 37, 57, 61, 44, 20, 6, 1}/256 +10 {3, 7, 15, 28, 44, 54, 49, 33, 17, 5, 1}/256 +11 {1, 7, 13, 22, 34, 46, 48, 38, 28, 14, 4, 1}/256 +12 {1, 1, 11, 22, 27, 35, 42, 47, 33, 25, 10, 1, 1}/256 +13 {1, 1, 6, 14, 26, 37, 43, 43, 37, 26, 14, 6, 1, 1}/256 +14 {1, 1, 4, 10, 20, 31, 40, 42, 40, 31, 20, 10, 4, 1, 1}/256 +15 {1, 1, 3, 8, 16, 26, 35, 38, 38, 35, 26, 16, 8, 3, 1, 1}/256 +16 {1, 1, 2, 6, 12, 21, 30, 36, 38, 36, 30, 21, 12, 6, 2, 1, 1}/256 + + + +Pulse Count +PDF + 1 {127, 129}/256 + 2 {49, 157, 50}/256 + 3 {20, 107, 109, 20}/256 + 4 {11, 60, 113, 62, 10}/256 + 5 {7, 36, 84, 87, 36, 6}/256 + 6 {6, 24, 57, 82, 60, 23, 4}/256 + 7 {5, 18, 39, 64, 68, 42, 16, 4}/256 + 8 {6, 14, 29, 47, 61, 52, 30, 14, 3}/256 + 9 {1, 15, 23, 35, 51, 50, 40, 30, 10, 1}/256 +10 {1, 1, 21, 32, 42, 52, 46, 41, 18, 1, 1}/256 +11 {1, 6, 16, 27, 36, 42, 42, 36, 27, 16, 6, 1}/256 +12 {1, 5, 12, 21, 31, 38, 40, 38, 31, 21, 12, 5, 1}/256 +13 {1, 3, 9, 17, 26, 34, 38, 38, 34, 26, 17, 9, 3, 1}/256 +14 {1, 3, 7, 14, 22, 29, 34, 36, 34, 29, 22, 14, 7, 3, 1}/256 +15 {1, 2, 5, 11, 18, 25, 31, 35, 35, 31, 25, 18, 11, 5, 2, 1}/256 +16 {1, 1, 4, 9, 15, 21, 28, 32, 34, 32, 28, 21, 15, 9, 4, 1, 1}/256 + + + +Pulse Count +PDF + 1 {128, 128}/256 + 2 {42, 172, 42}/256 + 3 {21, 107, 107, 21}/256 + 4 {12, 60, 112, 61, 11}/256 + 5 {8, 34, 86, 86, 35, 7}/256 + 6 {8, 23, 55, 90, 55, 20, 5}/256 + 7 {5, 15, 38, 72, 72, 36, 15, 3}/256 + 8 {6, 12, 27, 52, 77, 47, 20, 10, 5}/256 + 9 {6, 19, 28, 35, 40, 40, 35, 28, 19, 6}/256 +10 {4, 14, 22, 31, 37, 40, 37, 31, 22, 14, 4}/256 +11 {3, 10, 18, 26, 33, 38, 38, 33, 26, 18, 10, 3}/256 +12 {2, 8, 13, 21, 29, 36, 38, 36, 29, 21, 13, 8, 2}/256 +13 {1, 5, 10, 17, 25, 32, 38, 38, 32, 25, 17, 10, 5, 1}/256 +14 {1, 4, 7, 13, 21, 29, 35, 36, 35, 29, 21, 13, 7, 4, 1}/256 +15 {1, 2, 5, 10, 17, 25, 32, 36, 36, 32, 25, 17, 10, 5, 2, 1}/256 +16 {1, 2, 4, 7, 13, 21, 28, 34, 36, 34, 28, 21, 13, 7, 4, 2, 1}/256 + + +
    + +
    + +After the decoder reads the pulse locations for all blocks, it reads the LSBs + (if any) for each block in turn. +Inside each block, it reads all the LSBs for each coefficient in turn, even + those where no pulses were allocated, before proceeding to the next one. +For 10 ms MB frames, it reads LSBs even for the extra 8 samples in + the last block. +The LSBs are coded from most significant to least significant, and they all use + the PDF in . + + + +PDF +{136, 120}/256 + + + +The number of LSBs read for each coefficient in a block is determined in + . +The magnitude of the coefficient is initially equal to the number of pulses + placed at that location in . +As each LSB is decoded, the magnitude is doubled, and then the value of the LSB + added to it, to obtain an updated magnitude. + +
    + +
    + +After decoding the pulse locations and the LSBs, the decoder knows the + magnitude of each coefficient in the excitation. +It then decodes a sign for all coefficients with a non-zero magnitude, using + one of the PDFs from . +If the value decoded is 0, then the coefficient magnitude is negated. +Otherwise, it remains positive. + + + +The decoder chooses the PDF for the sign based on the signal type and + quantization offset type (from ) and the + number of pulses in the block (from ). +The number of pulses in the block does not take into account any LSBs. +Most PDFs are skewed towards negative signs because of the quantization offset, + but the PDFs for zero pulses are highly skewed towards positive signs. +If a block contains many positive coefficients, it is sometimes beneficial to + code it solely using LSBs (i.e., with zero pulses), since the encoder may be + able to save enough bits on the signs to justify the less efficient + coefficient magnitude encoding. + + + +Signal Type +Quantization Offset Type +Pulse Count +PDF +Inactive Low 0 {2, 254}/256 +Inactive Low 1 {207, 49}/256 +Inactive Low 2 {189, 67}/256 +Inactive Low 3 {179, 77}/256 +Inactive Low 4 {174, 82}/256 +Inactive Low 5 {163, 93}/256 +Inactive Low 6 or more {157, 99}/256 +Inactive High 0 {58, 198}/256 +Inactive High 1 {245, 11}/256 +Inactive High 2 {238, 18}/256 +Inactive High 3 {232, 24}/256 +Inactive High 4 {225, 31}/256 +Inactive High 5 {220, 36}/256 +Inactive High 6 or more {211, 45}/256 +Unvoiced Low 0 {1, 255}/256 +Unvoiced Low 1 {210, 46}/256 +Unvoiced Low 2 {190, 66}/256 +Unvoiced Low 3 {178, 78}/256 +Unvoiced Low 4 {169, 87}/256 +Unvoiced Low 5 {162, 94}/256 +Unvoiced Low 6 or more {152, 104}/256 +Unvoiced High 0 {48, 208}/256 +Unvoiced High 1 {242, 14}/256 +Unvoiced High 2 {235, 21}/256 +Unvoiced High 3 {224, 32}/256 +Unvoiced High 4 {214, 42}/256 +Unvoiced High 5 {205, 51}/256 +Unvoiced High 6 or more {190, 66}/256 +Voiced Low 0 {1, 255}/256 +Voiced Low 1 {162, 94}/256 +Voiced Low 2 {152, 104}/256 +Voiced Low 3 {147, 109}/256 +Voiced Low 4 {144, 112}/256 +Voiced Low 5 {141, 115}/256 +Voiced Low 6 or more {138, 118}/256 +Voiced High 0 {8, 248}/256 +Voiced High 1 {203, 53}/256 +Voiced High 2 {187, 69}/256 +Voiced High 3 {176, 80}/256 +Voiced High 4 {168, 88}/256 +Voiced High 5 {161, 95}/256 +Voiced High 6 or more {154, 102}/256 + + +
    + +
    + + +After the signs have been read, there is enough information to reconstruct the + complete excitation signal. +This requires adding a constant quantization offset to each non-zero sample, + and then pseudorandomly inverting and offsetting every sample. +The constant quantization offset varies depending on the signal type and + quantization offset type (see ). + + + +Signal Type +Quantization Offset Type +Quantization Offset (Q23) +Inactive Low 25 +Inactive High 60 +Unvoiced Low 25 +Unvoiced High 60 +Voiced Low 8 +Voiced High 25 + + + +Let e_raw[i] be the raw excitation value at position i, with a magnitude + composed of the pulses at that location (see + ) combined with any additional LSBs (see + ), and with the corresponding sign decoded in + . +Additionally, let seed be the current pseudorandom seed, which is initialized + to the value decoded from for the first sample in + the current SILK frame, and updated for each subsequent sample according to + the procedure below. +Finally, let offset_Q23 be the quantization offset from + . +Then the following procedure produces the final reconstructed excitation value, + e_Q23[i]: +
    + +
    +When e_raw[i] is zero, sign() returns 0 by the definition in + , so the factor of 20 does not get added. +The final e_Q23[i] value may require more than 16 bits per sample, but will not + require more than 23, including the sign. +
    + +
    + +
    + +
    + + +The remainder of the reconstruction process for the frame does not need to be + bit-exact, as small errors should only introduce proportionally small + distortions. +Although the reference implementation only includes a fixed-point version of + the remaining steps, this section describes them in terms of a floating-point + version for simplicity. +This produces a signal with a nominal range of -1.0 to 1.0. + + + +silk_decode_core() (decode_core.c) contains the code for the main + reconstruction process. +It proceeds subframe-by-subframe, since quantization gains, LTP parameters, and + (in 20 ms SILK frames) LPC coefficients can vary from one to the + next. + + + +Let a_Q12[k] be the LPC coefficients for the current subframe. +If this is the first or second subframe of a 20 ms SILK frame and the LSF + interpolation factor, w_Q2 (see ), is + less than 4, then these correspond to the final LPC coefficients produced by + from the interpolated LSF coefficients, + n1_Q15[k] (computed in ). +Otherwise, they correspond to the final LPC coefficients produced from the + uninterpolated LSF coefficients for the current frame, n2_Q15[k]. + + + +Also, let n be the number of samples in a subframe (40 for NB, 60 for MB, and + 80 for WB), s be the index of the current subframe in this SILK frame (0 or 1 + for 10 ms frames, or 0 to 3 for 20 ms frames), and j be the index of + the first sample in the residual corresponding to the current subframe. + + +
    + +Voiced SILK frames (see ) pass the excitation + through an LTP filter using the parameters decoded in + to produce an LPC residual. +The LTP filter requires LPC residual values from before the current subframe as + input. +However, since the LPC coefficients may have changed, it obtains this residual + by "rewhitening" the corresponding output signal using the LPC coefficients + from the current subframe. +Let out[i] for + (j - pitch_lags[s] - d_LPC - 2) <= i < j + be the fully reconstructed output signal from the last + (pitch_lags[s] + d_LPC + 2) samples of previous subframes + (see ), where pitch_lags[s] is the pitch + lag for the current subframe from . +During reconstruction of the first subframe for this channel after either + +An uncoded regular SILK frame (if this is the side channel), or +A decoder reset (see ), + + out[] is rewhitened into an LPC residual, + res[i], via +
    + +
    +This requires storage to buffer up to 306 values of out[i] from previous + subframes. +This corresponds to WB with a maximum pitch lag of + 18 ms * 16 kHz samples, plus 16 samples for d_LPC, plus 2 + samples for the width of the LTP filter. +
    + + +Let e_Q23[i] for j <= i < (j + n) be the + excitation for the current subframe, and b_Q7[k] for + 0 <= k < 5 be the coefficients of the LTP filter + taken from the codebook entry in one of + Tables  + through  + corresponding to the index decoded for the current subframe in + . +Then for i such that j <= i < (j + n), + the LPC residual is +
    + +
    +
    + + +For unvoiced frames, the LPC residual for + j <= i < (j + n) is simply a normalized + copy of the excitation signal, i.e., +
    + +
    +
    +
    + +
    + +LPC synthesis uses the short-term LPC filter to predict the next output + coefficient. +For i such that (j - d_LPC) <= i < j, let + lpc[i] be the result of LPC synthesis from the last d_LPC samples of the + previous subframe, or zeros in the first subframe for this channel after + either + +An uncoded regular SILK frame (if this is the side channel), or +A decoder reset (see ). + +Then for i such that j <= i < (j + n), the + result of LPC synthesis for the current subframe is +
    + +
    +The decoder saves the final d_LPC values, i.e., lpc[i] such that + (j + n - d_LPC) <= i < (j + n), + to feed into the LPC synthesis of the next subframe. +This requires storage for up to 16 values of lpc[i] (for WB frames). +
    + + +Then, the signal is clamped into the final nominal range: +
    + +
    +This clamping occurs entirely after the LPC synthesis filter has run. +The decoder saves the unclamped values, lpc[i], to feed into the LPC filter for + the next subframe, but saves the clamped values, out[i], for rewhitening in + voiced frames. +
    +
    + +
    + +
    + +
    + +For stereo streams, after decoding a frame from each channel, the decoder must + convert the mid-side (MS) representation into a left-right (LR) + representation. +The function silk_stereo_MS_to_LR (stereo_MS_to_LR.c) implements this process. +In it, the decoder predicts the side channel using a) a simple low-passed + version of the mid channel, and b) the unfiltered mid channel, using the + prediction weights decoded in . +This simple low-pass filter imposes a one-sample delay, and the unfiltered +mid channel is also delayed by one sample. +In order to allow seamless switching between stereo and mono, mono streams must + also impose the same one-sample delay. +The encoder requires an additional one-sample delay for both mono and stereo + streams, though an encoder may omit the delay for mono if it knows it will + never switch to stereo. + + + +The unmixing process operates in two phases. +The first phase lasts for 8 ms, during which it interpolates the + prediction weights from the previous frame, prev_w0_Q13 and prev_w1_Q13, to + the values for the current frame, w0_Q13 and w1_Q13. +The second phase simply uses these weights for the remainder of the frame. + + + +Let mid[i] and side[i] be the contents of out[i] (from + ) for the current mid and side channels, + respectively, and let left[i] and right[i] be the corresponding stereo output + channels. +If the side channel is not coded (see ), + then side[i] is set to zero. +Also let j be defined as in , n1 be + the number of samples in phase 1 (64 for NB, 96 for MB, and 128 for WB), + and n2 be the total number of samples in the frame. +Then for i such that j <= i < (j + n2), + the left and right channel output is +
    + +
    +These formulas require two samples prior to index j, the start of the + frame, for the mid channel, and one prior sample for the side channel. +For the first frame after a decoder reset, zeros are used instead. +
    + +
    + +
    + +After stereo unmixing (if any), the decoder applies resampling to convert the + decoded SILK output to the sample rate desired by the application. +This is necessary when decoding a Hybrid frame at SWB or FB sample rates, or + whenever the decoder wants the output at a different sample rate than the + internal SILK sampling rate (e.g., to allow a constant sample rate when the + audio bandwidth changes, or to allow mixing with audio from other + applications). +The resampler itself is non-normative, and a decoder can use any method it + wants to perform the resampling. + + + +However, a minimum amount of delay is imposed to allow the resampler to + operate, and this delay is normative, so that the corresponding delay can be + applied to the MDCT layer in the encoder. +A decoder is always free to use a resampler which requires more delay than + allowed for here (e.g., to improve quality), but it must then delay the output + of the MDCT layer by this extra amount. +Keeping as much delay as possible on the encoder side allows an encoder which + knows it will never use any of the SILK or Hybrid modes to skip this delay. +By contrast, if it were all applied by the decoder, then a decoder which + processes audio in fixed-size blocks would be forced to delay the output of + CELT frames just in case of a later switch to a SILK or Hybrid mode. + + + + gives the maximum resampler delay + in samples at 48 kHz for each SILK audio bandwidth. +Because the actual output rate may not be 48 kHz, it may not be possible + to achieve exactly these delays while using a whole number of input or output + samples. +The reference implementation is able to resample to any of the supported + output sampling rates (8, 12, 16, 24, or 48 kHz) within or near this + delay constraint. +Some resampling filters (including those used by the reference implementation) + may add a delay that is not an exact integer, or is not linear-phase, and so + cannot be represented by a single delay at all frequencies. +However, such deviations are unlikely to be perceptible, and the comparison + tool described in is designed to be relatively + insensitive to them. +The delays listed here are the ones that should be targeted by the encoder. + + + +Audio Bandwidth +Delay in millisecond +NB 0.538 +MB 0.692 +WB 0.706 + + + +NB is given a smaller decoder delay allocation than MB and WB to allow a + higher-order filter when resampling to 8 kHz in both the encoder and + decoder. +This implies that the audio content of two SILK frames operating at different + bandwidths are not perfectly aligned in time. +This is not an issue for any transitions described in + , because they all involve a SILK decoder reset. +When the decoder is reset, any samples remaining in the resampling buffer + are discarded, and the resampler is re-initialized with silence. + + +
    + +
    + + +
    + + +The CELT layer of Opus is based on the Modified Discrete Cosine Transform + with partially overlapping windows of 5 to 22.5 ms. +The main principle behind CELT is that the MDCT spectrum is divided into +bands that (roughly) follow the Bark scale, i.e., the scale of the ear's +critical bands . The normal CELT layer uses 21 of those bands, though Opus + Custom (see ) may use a different number of bands. +In Hybrid mode, the first 17 bands (up to 8 kHz) are not coded. +A band can contain as little as one MDCT bin per channel, and as many as 176 +bins per channel, as detailed in . +In each band, the gain (energy) is coded separately from +the shape of the spectrum. Coding the gain explicitly makes it easy to +preserve the spectral envelope of the signal. The remaining unit-norm shape +vector is encoded using a Pyramid Vector Quantizer (PVQ) . + + + +Frame Size: +2.5 ms +5 ms +10 ms +20 ms +Start Frequency +Stop Frequency +Band Bins: + 0 1 2 4 8 0 Hz 200 Hz + 1 1 2 4 8 200 Hz 400 Hz + 2 1 2 4 8 400 Hz 600 Hz + 3 1 2 4 8 600 Hz 800 Hz + 4 1 2 4 8 800 Hz 1000 Hz + 5 1 2 4 8 1000 Hz 1200 Hz + 6 1 2 4 8 1200 Hz 1400 Hz + 7 1 2 4 8 1400 Hz 1600 Hz + 8 2 4 8 16 1600 Hz 2000 Hz + 9 2 4 8 16 2000 Hz 2400 Hz +10 2 4 8 16 2400 Hz 2800 Hz +11 2 4 8 16 2800 Hz 3200 Hz +12 4 8 16 32 3200 Hz 4000 Hz +13 4 8 16 32 4000 Hz 4800 Hz +14 4 8 16 32 4800 Hz 5600 Hz +15 6 12 24 48 5600 Hz 6800 Hz +16 6 12 24 48 6800 Hz 8000 Hz +17 8 16 32 64 8000 Hz 9600 Hz +18 12 24 48 96 9600 Hz 12000 Hz +19 18 36 72 144 12000 Hz 15600 Hz +20 22 44 88 176 15600 Hz 20000 Hz + + + +Transients are notoriously difficult for transform codecs to code. +CELT uses two different strategies for them: + +Using multiple smaller MDCTs instead of a single large MDCT, and +Dynamic time-frequency resolution changes (See ). + +To improve quality on highly tonal and periodic signals, CELT includes +a prefilter/postfilter combination. The prefilter on the encoder side +attenuates the signal's harmonics. The postfilter on the decoder side +restores the original gain of the harmonics, while shaping the coding noise +to roughly follow the harmonics. Such noise shaping reduces the perception +of the noise. + + + +When coding a stereo signal, three coding methods are available: + +mid-side stereo: encodes the mean and the difference of the left and right channels, +intensity stereo: only encodes the mean of the left and right channels (discards the difference), +dual stereo: encodes the left and right channels separately. + + + + +An overview of the decoder is given in . + + +
    +| decoder |----+ + | +---------+ | + | | + | +---------+ v + | | Fine | +---+ + +->| decoder |->| + | + | +---------+ +---+ + | ^ | ++---------+ | | | +| Range | | +----------+ v +| Decoder |-+ | Bit | +------+ ++---------+ | |Allocation| | 2**x | + | +----------+ +------+ + | | | + | v v +--------+ + | +---------+ +---+ +-------+ | pitch | + +->| PVQ |->| * |->| IMDCT |->| post- |---> + | | decoder | +---+ +-------+ | filter | + | +---------+ +--------+ + | ^ + +--------------------------------------+ +]]> +
    + + +The decoder is based on the following symbols and sets of symbols: + + + +Symbol(s) +PDF +Condition +silence {32767, 1}/32768 +post-filter {1, 1}/2 +octave uniform (6)post-filter +period raw bits (4+octave)post-filter +gain raw bits (3)post-filter +tapset {2, 1, 1}/4post-filter +transient {7, 1}/8 +intra {7, 1}/8 +coarse energy +tf_change +tf_select {1, 1}/2 +spread {7, 2, 21, 2}/32 +dyn. alloc. +alloc. trim {2, 2, 5, 10, 22, 46, 22, 10, 5, 2, 2}/128 +skip {1, 1}/2 +intensity uniform +dual {1, 1}/2 +fine energy +residual +anti-collapse{1, 1}/2 +finalize + + + +The decoder extracts information from the range-coded bitstream in the order +described in . In some circumstances, it is +possible for a decoded value to be out of range due to a very small amount of redundancy +in the encoding of large integers by the range coder. +In that case, the decoder should assume there has been an error in the coding, +decoding, or transmission and SHOULD take measures to conceal the error and/or report +to the application that a problem has occurred. Such out of range errors cannot occur +in the SILK layer. + + +
    + +The "transient" flag indicates whether the frame uses a single long MDCT or several short MDCTs. +When it is set, then the MDCT coefficients represent multiple +short MDCTs in the frame. When not set, the coefficients represent a single +long MDCT for the frame. The flag is encoded in the bitstream with a probability of 1/8. +In addition to the global transient flag is a per-band +binary flag to change the time-frequency (tf) resolution independently in each band. The +change in tf resolution is defined in tf_select_table[][] in celt.c and depends +on the frame size, whether the transient flag is set, and the value of tf_select. +The tf_select flag uses a 1/2 probability, but is only decoded +if it can have an impact on the result knowing the value of all per-band +tf_change flags. + +
    + +
    + + +It is important to quantize the energy with sufficient resolution because +any energy quantization error cannot be compensated for at a later +stage. Regardless of the resolution used for encoding the spectral shape of a band, +it is perceptually important to preserve the energy in each band. CELT uses a +three-step coarse-fine-fine strategy for encoding the energy in the base-2 log +domain, as implemented in quant_bands.c + +
    + +Coarse quantization of the energy uses a fixed resolution of 6 dB +(integer part of base-2 log). To minimize the bitrate, prediction is applied +both in time (using the previous frame) and in frequency (using the previous +bands). The part of the prediction that is based on the +previous frame can be disabled, creating an "intra" frame where the energy +is coded without reference to prior frames. The decoder first reads the intra flag +to determine what prediction is used. +The 2-D z-transform of +the prediction filter is: +
    + +
    +where b is the band index and l is the frame index. The prediction coefficients +applied depend on the frame size in use when not using intra energy and are alpha=0, beta=4915/32768 +when using intra energy. +The time-domain prediction is based on the final fine quantization of the previous +frame, while the frequency domain (within the current frame) prediction is based +on coarse quantization only (because the fine quantization has not been computed +yet). The prediction is clamped internally so that fixed point implementations with +limited dynamic range always remain in the same state as floating point implementations. +We approximate the ideal +probability distribution of the prediction error using a Laplace distribution +with separate parameters for each frame size in intra- and inter-frame modes. These +parameters are held in the e_prob_model table in quant_bands.c. +The +coarse energy quantization is performed by unquant_coarse_energy() and +unquant_coarse_energy_impl() (quant_bands.c). The encoding of the Laplace-distributed values is +implemented in ec_laplace_decode() (laplace.c). +
    + +
    + +
    + +The number of bits assigned to fine energy quantization in each band is determined +by the bit allocation computation described in . +Let B_i be the number of fine energy bits +for band i; the refinement is an integer f in the range [0,2**B_i-1]. The mapping between f +and the correction applied to the coarse energy is equal to (f+1/2)/2**B_i - 1/2. Fine +energy quantization is implemented in quant_fine_energy() (quant_bands.c). + + +When some bits are left "unused" after all other flags have been decoded, these bits +are assigned to a "final" step of fine allocation. In effect, these bits are used +to add one extra fine energy bit per band per channel. The allocation process +determines two "priorities" for the final fine bits. +Any remaining bits are first assigned only to bands of priority 0, starting +from band 0 and going up. If all bands of priority 0 have received one bit per +channel, then bands of priority 1 are assigned an extra bit per channel, +starting from band 0. If any bits are left after this, they are left unused. +This is implemented in unquant_energy_finalise() (quant_bands.c). + + +
    + +
    + +
    + +Because the bit allocation drives the decoding of the range-coder +stream, it MUST be recovered exactly so that identical coding decisions are +made in the encoder and decoder. Any deviation from the reference's resulting +bit allocation will result in corrupted output, though implementers are +free to implement the procedure in any way which produces identical results. + +The per-band gain-shape structure of the CELT layer ensures that using + the same number of bits for the spectral shape of a band in every frame will + result in a roughly constant signal-to-noise ratio in that band. +This results in coding noise that has the same spectral envelope as the signal. +The masking curve produced by a standard psychoacoustic model also closely + follows the spectral envelope of the signal. +This structure means that the ideal allocation is more consistent from frame to + frame than it is for other codecs without an equivalent structure, and that a + fixed allocation provides fairly consistent perceptual + performance . + +Many codecs transmit significant amounts of side information to control the + bit allocation within a frame. +Often this control is only indirect, and must be exercised carefully to + achieve the desired rate constraints. +The CELT layer, however, can adapt over a very wide range of rates, and thus + has a large number of codebook sizes to choose from for each band. +Explicitly signaling the size of each of these codebooks would impose + considerable overhead, even though the allocation is relatively static from + frame to frame. +This is because all of the information required to compute these codebook sizes + must be derived from a single frame by itself, in order to retain robustness + to packet loss, so the signaling cannot take advantage of knowledge of the + allocation in neighboring frames. +This problem is exacerbated in low-latency (small frame size) applications, + which would include this overhead in every frame. + +For this reason, in the MDCT mode Opus uses a primarily implicit bit +allocation. The available bitstream capacity is known in advance to both +the encoder and decoder without additional signaling, ultimately from the +packet sizes expressed by a higher-level protocol. Using this information, +the codec interpolates an allocation from a hard-coded table. + +While the band-energy structure effectively models intra-band masking, +it ignores the weaker inter-band masking, band-temporal masking, and +other less significant perceptual effects. While these effects can +often be ignored, they can become significant for particular samples. One +mechanism available to encoders would be to simply increase the overall +rate for these frames, but this is not possible in a constant rate mode +and can be fairly inefficient. As a result three explicitly signaled +mechanisms are provided to alter the implicit allocation: + + + +Band boost +Allocation trim +Band skipping + + + +The first of these mechanisms, band boost, allows an encoder to boost +the allocation in specific bands. The second, allocation trim, works by +biasing the overall allocation towards higher or lower frequency bands. The third, band +skipping, selects which low-precision high frequency bands +will be allocated no shape bits at all. + +In stereo mode there are two additional parameters +potentially coded as part of the allocation procedure: a parameter to allow the +selective elimination of allocation for the 'side' (i.e., intensity stereo) in jointly coded bands, +and a flag to deactivate joint coding (i.e., dual stereo). These values are not signaled if +they would be meaningless in the overall context of the allocation. + +Because every signaled adjustment increases overhead and implementation +complexity, none were included speculatively: the reference encoder makes use +of all of these mechanisms. While the decision logic in the reference was +found to be effective enough to justify the overhead and complexity, further +analysis techniques may be discovered which increase the effectiveness of these +parameters. As with other signaled parameters, an encoder is free to choose the +values in any manner, but unless a technique is known to deliver superior +perceptual results the methods used by the reference implementation should be +used. + +The allocation process consists of the following steps: determining the per-band +maximum allocation vector, decoding the boosts, decoding the tilt, determining +the remaining capacity of the frame, searching the mode table for the +entry nearest but not exceeding the available space (subject to the tilt, boosts, band +maximums, and band minimums), linear interpolation, reallocation of +unused bits with concurrent skip decoding, determination of the +fine-energy vs. shape split, and final reallocation. This process results +in a per-band shape allocation (in 1/8th bit units), a per-band fine-energy +allocation (in 1 bit per channel units), a set of band priorities for +controlling the use of remaining bits at the end of the frame, and a +remaining balance of unallocated space, which is usually zero except +at very high rates. + + +The "static" bit allocation (in 1/8 bits) for a quality q, excluding the minimums, maximums, +tilt and boosts, is equal to channels*N*alloc[band][q]<<LM>>2, where +alloc[][] is given in and LM=log2(frame_size/120). The allocation +is obtained by linearly interpolating between two values of q (in steps of 1/64) to find the +highest allocation that does not exceed the number of bits remaining. + + + + Rows indicate the MDCT bands, columns are the different quality (q) parameters. The units are 1/32 bit per MDCT bin. +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +090110118126134144152162172200 +080100110119127137145155165200 +07590103112120130138148158200 +0698493104114124132142152200 +063788695103113123133143200 +05671808997107117127137200 +04965758391101111121131200 +0405870788595105115125200 +034516572788898108118198 +029455966728292102112193 +02039536066768696106188 +01832475460708090100183 +0102640475464748494178 +002031394757677787173 +001223324151617181168 +00015253545556575163 +0004172939495969158 +0000122333435363153 +000011626364656148 +000001015203045129 +00000111120104 + + +The maximum allocation vector is an approximation of the maximum space +that can be used by each band for a given mode. The value is +approximate because the shape encoding is variable rate (due +to entropy coding of splitting parameters). Setting the maximum too low reduces the +maximum achievable quality in a band while setting it too high +may result in waste: bitstream capacity available at the end +of the frame which can not be put to any use. The maximums +specified by the codec reflect the average maximum. In the reference +implementation, the maximums in bits/sample are precomputed in a static table +(see cache_caps50[] in static_modes_float.h) for each band, +for each value of LM, and for both mono and stereo. + +Implementations are expected +to simply use the same table data, but the procedure for generating +this table is included in rate.c as part of compute_pulse_cache(). + +To convert the values in cache.caps into the actual maximums: first +set nbBands to the maximum number of bands for this mode, and stereo to +zero if stereo is not in use and one otherwise. For each band set N +to the number of MDCT bins covered by the band (for one channel), set LM +to the shift value for the frame size, +then set i to nbBands*(2*LM+stereo). Then set the maximum for the band to +the i-th index of cache.caps + 64 and multiply by the number of channels +in the current frame (one or two) and by N, then divide the result by 4 +using integer division. The resulting vector will be called +cap[]. The elements fit in signed 16-bit integers but do not fit in 8 bits. +This procedure is implemented in the reference in the function init_caps() in celt.c. + + +The band boosts are represented by a series of binary symbols which +are entropy coded with very low probability. Each band can potentially be boosted +multiple times, subject to the frame actually having enough room to obey +the boost and having enough room to code the boost symbol. The default +coding cost for a boost starts out at six bits (probability p=1/64), but subsequent boosts +in a band cost only a single bit and every time a band is boosted the +initial cost is reduced (down to a minimum of two bits, or p=1/4). Since the initial +cost of coding a boost is 6 bits, the coding cost of the boost symbols when +completely unused is 0.48 bits/frame for a 21 band mode (21*-log2(1-1/2**6)). + +To decode the band boosts: First set 'dynalloc_logp' to 6, the initial +amount of storage required to signal a boost in bits, 'total_bits' to the +size of the frame in 8th bits, 'total_boost' to zero, and 'tell' to the total number +of 8th bits decoded +so far. For each band from the coding start (0 normally, but 17 in Hybrid mode) +to the coding end (which changes depending on the signaled bandwidth), the boost quanta +in units of 1/8 bit is calculated as quanta = min(8*N, max(48, N)). +This represents a boost step size of six bits, subject to a lower limit of +1/8th bit/sample and an upper limit of 1 bit/sample. +Set 'boost' to zero and 'dynalloc_loop_logp' +to dynalloc_logp. While dynalloc_loop_log (the current worst case symbol cost) in +8th bits plus tell is less than total_bits plus total_boost and boost is less than cap[] for this +band: Decode a bit from the bitstream with a with dynalloc_loop_logp as the cost +of a one, update tell to reflect the current used capacity, if the decoded value +is zero break the loop otherwise add quanta to boost and total_boost, subtract quanta from +total_bits, and set dynalloc_loop_log to 1. When the while loop finishes +boost contains the boost for this band. If boost is non-zero and dynalloc_logp +is greater than 2, decrease dynalloc_logp. Once this process has been +executed on all bands, the band boosts have been decoded. This procedure +is implemented around line 2474 of celt.c. + +At very low rates it is possible that there won't be enough available +space to execute the inner loop even once. In these cases band boost +is not possible but its overhead is completely eliminated. Because of the +high cost of band boost when activated, a reasonable encoder should not be +using it at very low rates. The reference implements its dynalloc decision +logic around line 1304 of celt.c. + +The allocation trim is a integer value from 0-10. The default value of +5 indicates no trim. The trim parameter is entropy coded in order to +lower the coding cost of less extreme adjustments. Values lower than +5 bias the allocation towards lower frequencies and values above 5 +bias it towards higher frequencies. Like other signaled parameters, signaling +of the trim is gated so that it is not included if there is insufficient space +available in the bitstream. To decode the trim, first set +the trim value to 5, then if and only if the count of decoded 8th bits so far (ec_tell_frac) +plus 48 (6 bits) is less than or equal to the total frame size in 8th +bits minus total_boost (a product of the above band boost procedure), +decode the trim value using the PDF in . + + +PDF +{1, 1, 2, 5, 10, 22, 46, 22, 10, 5, 2, 2}/128 + + +For 10 ms and 20 ms frames using short blocks and that have at least LM+2 bits left prior to +the allocation process, then one anti-collapse bit is reserved in the allocation process so it can +be decoded later. Following the the anti-collapse reservation, one bit is reserved for skip if available. + +For stereo frames, bits are reserved for intensity stereo and for dual stereo. Intensity stereo +requires ilog2(end-start) bits. Those bits are reserved if there is enough bits left. Following this, one +bit is reserved for dual stereo if available. + + +The allocation computation begins by setting up some initial conditions. +'total' is set to the remaining available 8th bits, computed by taking the +size of the coded frame times 8 and subtracting ec_tell_frac(). From this value, one (8th bit) +is subtracted to ensure that the resulting allocation will be conservative. 'anti_collapse_rsv' +is set to 8 (8th bits) if and only if the frame is a transient, LM is greater than 1, and total is +greater than or equal to (LM+2) * 8. Total is then decremented by anti_collapse_rsv and clamped +to be equal to or greater than zero. 'skip_rsv' is set to 8 (8th bits) if total is greater than +8, otherwise it is zero. Total is then decremented by skip_rsv. This reserves space for the +final skipping flag. + +If the current frame is stereo, intensity_rsv is set to the conservative log2 in 8th bits +of the number of coded bands for this frame (given by the table LOG2_FRAC_TABLE in rate.c). If +intensity_rsv is greater than total then intensity_rsv is set to zero. Otherwise total is +decremented by intensity_rsv, and if total is still greater than 8, dual_stereo_rsv is +set to 8 and total is decremented by dual_stereo_rsv. + +The allocation process then computes a vector representing the hard minimum amounts allocation +any band will receive for shape. This minimum is higher than the technical limit of the PVQ +process, but very low rate allocations produce an excessively sparse spectrum and these bands +are better served by having no allocation at all. For each coded band, set thresh[band] to +twenty-four times the number of MDCT bins in the band and divide by 16. If 8 times the number +of channels is greater, use that instead. This sets the minimum allocation to one bit per channel +or 48 128th bits per MDCT bin, whichever is greater. The band-size dependent part of this +value is not scaled by the channel count, because at the very low rates where this limit is +applicable there will usually be no bits allocated to the side. + +The previously decoded allocation trim is used to derive a vector of per-band adjustments, +'trim_offsets[]'. For each coded band take the alloc_trim and subtract 5 and LM. Then multiply +the result by the number of channels, the number of MDCT bins in the shortest frame size for this mode, +the number of remaining bands, 2**LM, and 8. Then divide this value by 64. Finally, if the +number of MDCT bins in the band per channel is only one, 8 times the number of channels is subtracted +in order to diminish the allocation by one bit, because width 1 bands receive greater benefit +from the coarse energy coding. + + +
    + +
    + +In each band, the normalized "shape" is encoded +using a vector quantization scheme called a "pyramid vector quantizer". + + +In +the simplest case, the number of bits allocated in + is converted to a number of pulses as described +by . Knowing the number of pulses and the +number of samples in the band, the decoder calculates the size of the codebook +as detailed in . The size is used to decode +an unsigned integer (uniform probability model), which is the codeword index. +This index is converted into the corresponding vector as explained in +. This vector is then scaled to unit norm. + + +
    + +Although the allocation is performed in 1/8th bit units, the quantization requires +an integer number of pulses K. To do this, the encoder searches for the value +of K that produces the number of bits nearest to the allocated value +(rounding down if exactly halfway between two values), not to exceed +the total number of bits available. For efficiency reasons, the search is performed against a +precomputed allocation table which only permits some K values for each N. The number of +codebook entries can be computed as explained in . The difference +between the number of bits allocated and the number of bits used is accumulated to a +"balance" (initialized to zero) that helps adjust the +allocation for the next bands. One third of the balance is applied to the +bit allocation of each band to help achieve the target allocation. The only +exceptions are the band before the last and the last band, for which half the balance +and the whole balance are applied, respectively. + +
    + +
    + + +Decoding of PVQ vectors is implemented in decode_pulses() (cwrs.c). +The unique codeword index is decoded as a uniformly-distributed integer value between 0 and +V(N,K)-1, where V(N,K) is the number of possible combinations of K pulses in +N samples. The index is then converted to a vector in the same way specified in +. The indexing is based on the calculation of V(N,K) +(denoted N(L,K) in ). + + + + The number of combinations can be computed recursively as +V(N,K) = V(N-1,K) + V(N,K-1) + V(N-1,K-1), with V(N,0) = 1 and V(0,K) = 0, K != 0. +There are many different ways to compute V(N,K), including precomputed tables and direct +use of the recursive formulation. The reference implementation applies the recursive +formulation one line (or column) at a time to save on memory use, +along with an alternate, +univariate recurrence to initialize an arbitrary line, and direct +polynomial solutions for small N. All of these methods are +equivalent, and have different trade-offs in speed, memory usage, and +code size. Implementations MAY use any methods they like, as long as +they are equivalent to the mathematical definition. + + + +The decoded vector X is recovered as follows. +Let i be the index decoded with the procedure in + with ft = V(N,K), so that 0 <= i < V(N,K). +Let k = K. +Then for j = 0 to (N - 1), inclusive, do: + +Let p = (V(N-j-1,k) + V(N-j,k))/2. + +If i < p, then let sgn = 1, else let sgn = -1 + and set i = i - p. + +Let k0 = k and set p = p - V(N-j-1,k). + +While p > i, set k = k - 1 and + p = p - V(N-j-1,k). + + +Set X[j] = sgn*(k0 - k) and i = i - p. + + + + + +The decoded vector X is then normalized such that its +L2-norm equals one. + +
    + +
    + +The normalized vector decoded in is then rotated +for the purpose of avoiding tonal artifacts. The rotation gain is equal to +
    + +
    + +where N is the number of dimensions, K is the number of pulses, and f_r depends on +the value of the "spread" parameter in the bit-stream. +
    + + +Spread value +f_r + 0 infinite (no rotation) + 1 15 + 2 10 + 3 5 + + + +The rotation angle is then calculated as +
    + +
    +A 2-D rotation R(i,j) between points x_i and x_j is defined as: +
    + +
    + +An N-D rotation is then achieved by applying a series of 2-D rotations back and forth, in the +following order: R(x_1, x_2), R(x_2, x_3), ..., R(x_N-2, X_N-1), R(x_N-1, X_N), +R(x_N-2, X_N-1), ..., R(x_1, x_2). +
    + + +If the decoded vector represents more +than one time block, then this spreading process is applied separately on each time block. +Also, if each block represents 8 samples or more, then another N-D rotation, by +(pi/2-theta), is applied before the rotation described above. This +extra rotation is applied in an interleaved manner with a stride equal to round(sqrt(N/nb_blocks)), +i.e., it is applied independently for each set of sample S_k = {stride*n + k}, n=0..N/stride-1. + +
    + +
    + +To avoid the need for multi-precision calculations when decoding PVQ codevectors, +the maximum size allowed for codebooks is 32 bits. When larger codebooks are +needed, the vector is instead split in two sub-vectors of size N/2. +A quantized gain parameter with precision +derived from the current allocation is entropy coded to represent the relative +gains of each side of the split, and the entire decoding process is recursively +applied. Multiple levels of splitting may be applied up to a limit of LM+1 splits. +The same recursive mechanism is applied for the joint coding +of stereo audio. + + +
    + +
    + +The time-frequency (TF) parameters are used to control the time-frequency resolution tradeoff +in each coded band. For each band, there are two possible TF choices. For the first +band coded, the PDF is {3, 1}/4 for frames marked as transient and {15, 1}/16 for +the other frames. For subsequent bands, the TF choice is coded relative to the +previous TF choice with probability {15, 1}/15 for transient frames and {31, 1}/32 +otherwise. The mapping between the decoded TF choices and the adjustment in TF +resolution is shown in the tables below. + + + +Frame size (ms) +0 +1 +2.5 0 -1 +5 0 -1 +10 0 -2 +20 0 -2 + + + +Frame size (ms) +0 +1 +2.5 0 -1 +5 0 -2 +10 0 -3 +20 0 -3 + + + + +Frame size (ms) +0 +1 +2.5 0 -1 +5 1 0 +10 2 0 +20 3 0 + + + +Frame size (ms) +0 +1 +2.5 0 -1 +5 1 -1 +10 1 -1 +20 1 -1 + + + +A negative TF adjustment means that the temporal resolution is increased, +while a positive TF adjustment means that the frequency resolution is increased. +Changes in TF resolution are implemented using the Hadamard transform . To increase +the time resolution by N, N "levels" of the Hadamard transform are applied to the +decoded vector for each interleaved MDCT vector. To increase the frequency resolution +(assumes a transient frame), then N levels of the Hadamard transform are applied +across the interleaved MDCT vector. In the case of increased +time resolution the decoder uses the "sequency order" because the input vector +is sorted in time. + +
    + + +
    + +
    + +The anti-collapse feature is designed to avoid the situation where the use of multiple +short MDCTs causes the energy in one or more of the MDCTs to be zero for +some bands, causing unpleasant artifacts. +When the frame has the transient bit set, an anti-collapse bit is decoded. +When anti-collapse is set, the energy in each small MDCT is prevented +from collapsing to zero. For each band of each MDCT where a collapse is +detected, a pseudo-random signal is inserted with an energy corresponding +to the minimum energy over the two previous frames. A renormalization step is +then required to ensure that the anti-collapse step did not alter the +energy preservation property. + +
    + +
    + +Just as each band was normalized in the encoder, the last step of the decoder before +the inverse MDCT is to denormalize the bands. Each decoded normalized band is +multiplied by the square root of the decoded energy. This is done by denormalise_bands() +(bands.c). + +
    + +
    + + +The inverse MDCT implementation has no special characteristics. The +input is N frequency-domain samples and the output is 2*N time-domain +samples, while scaling by 1/2. A "low-overlap" window reduces the algorithmic delay. +It is derived from a basic (full overlap) 240-sample version of the window used by the Vorbis codec: +
    + +
    +The low-overlap window is created by zero-padding the basic window and inserting ones in the +middle, such that the resulting window still satisfies power complementarity . +The IMDCT and +windowing are performed by mdct_backward (mdct.c). +
    + +
    + +The output of the inverse MDCT (after weighted overlap-add) is sent to the +post-filter. Although the post-filter is applied at the end, the post-filter +parameters are encoded at the beginning, just after the silence flag. +The post-filter can be switched on or off using one bit (logp=1). +If the post-filter is enabled, then the octave is decoded as an integer value +between 0 and 6 of uniform probability. Once the octave is known, the fine pitch +within the octave is decoded using 4+octave raw bits. The final pitch period +is equal to (16<<octave)+fine_pitch-1 so it is bounded between 15 and 1022, +inclusively. Next, the gain is decoded as three raw bits and is equal to +G=3*(int_gain+1)/32. The set of post-filter taps is decoded last, using +a pdf equal to {2, 1, 1}/4. Tapset zero corresponds to the filter coefficients +g0 = 0.3066406250, g1 = 0.2170410156, g2 = 0.1296386719. Tapset one +corresponds to the filter coefficients g0 = 0.4638671875, g1 = 0.2680664062, +g2 = 0, and tapset two uses filter coefficients g0 = 0.7998046875, +g1 = 0.1000976562, g2 = 0. + + + +The post-filter response is thus computed as: +
    + + + +
    + +During a transition between different gains, a smooth transition is calculated +using the square of the MDCT window. It is important that values of y(n) be +interpolated one at a time such that the past value of y(n) used is interpolated. +
    +
    + +
    + +After the post-filter, +the signal is de-emphasized using the inverse of the pre-emphasis filter +used in the encoder: +
    + +
    +where alpha_p=0.8500061035. +
    +
    + +
    + +
    + +
    + +Packet loss concealment (PLC) is an optional decoder-side feature that +SHOULD be included when receiving from an unreliable channel. Because +PLC is not part of the bitstream, there are many acceptable ways to +implement PLC with different complexity/quality trade-offs. + + + +The PLC in +the reference implementation depends on the mode of last packet received. +In CELT mode, the PLC finds a periodicity in the decoded +signal and repeats the windowed waveform using the pitch offset. The windowed +waveform is overlapped in such a way as to preserve the time-domain aliasing +cancellation with the previous frame and the next frame. This is implemented +in celt_decode_lost() (mdct.c). In SILK mode, the PLC uses LPC extrapolation +from the previous frame, implemented in silk_PLC() (PLC.c). + + +
    + +Clock drift refers to the gradual desynchronization of two endpoints +whose sample clocks run at different frequencies while they are streaming +live audio. Differences in clock frequencies are generally attributable to +manufacturing variation in the endpoints' clock hardware. For long-lived +streams, the time difference between sender and receiver can grow without +bound. + + + +When the sender's clock runs slower than the receiver's, the effect is similar +to packet loss: too few packets are received. The receiver can distinguish +between drift and loss if the transport provides packet timestamps. A receiver +for live streams SHOULD conceal the effects of drift, and MAY do so by invoking +the PLC. + + + +When the sender's clock runs faster than the receiver's, too many packets will +be received. The receiver MAY respond by skipping any packet (i.e., not +submitting the packet for decoding). This is likely to produce a less severe +artifact than if the frame were dropped after decoding. + + + +A decoder MAY employ a more sophisticated drift compensation method. For +example, the +NetEQ component +of the +Google WebRTC codebase +compensates for drift by adding or removing +one period when the signal is highly periodic. The reference implementation of +Opus allows a caller to learn whether the current frame's signal is highly +periodic, and if so what the period is, using the OPUS_GET_PITCH() request. + +
    + +
    + +
    + + +Switching between the Opus coding modes, audio bandwidths, and channel counts + requires careful consideration to avoid audible glitches. +Switching between any two configurations of the CELT-only mode, any two + configurations of the Hybrid mode, or from WB SILK to Hybrid mode does not + require any special treatment in the decoder, as the MDCT overlap will smooth + the transition. +Switching from Hybrid mode to WB SILK requires adding in the final contents + of the CELT overlap buffer to the first SILK-only packet. +This can be done by decoding a 2.5 ms silence frame with the CELT decoder + using the channel count of the SILK-only packet (and any choice of audio + bandwidth), which will correctly handle the cases when the channel count + changes as well. + + + +When changing the channel count for SILK-only or Hybrid packets, the encoder + can avoid glitches by smoothly varying the stereo width of the input signal + before or after the transition, and SHOULD do so. +However, other transitions between SILK-only packets or between NB or MB SILK + and Hybrid packets may cause glitches, because neither the LSF coefficients + nor the LTP, LPC, stereo unmixing, and resampler buffers are available at the + new sample rate. +These switches SHOULD be delayed by the encoder until quiet periods or + transients, where the inevitable glitches will be less audible. Additionally, + the bit-stream MAY include redundant side information ("redundancy"), in the + form of additional CELT frames embedded in each of the Opus frames around the + transition. + + + +The other transitions that cannot be easily handled are those where the lower + frequencies switch between the SILK LP-based model and the CELT MDCT model. +However, an encoder may not have an opportunity to delay such a switch to a + convenient point. +For example, if the content switches from speech to music, and the encoder does + not have enough latency in its analysis to detect this in advance, there may + be no convenient silence period during which to make the transition for quite + some time. +To avoid or reduce glitches during these problematic mode transitions, and + also between audio bandwidth changes in the SILK-only modes, transitions MAY + include redundant side information ("redundancy"), in the form of an + additional CELT frame embedded in the Opus frame. + + + +A transition between coding the lower frequencies with the LP model and the + MDCT model or a transition that involves changing the SILK bandwidth + is only normatively specified when it includes redundancy. +For those without redundancy, it is RECOMMENDED that the decoder use a + concealment technique (e.g., make use of a PLC algorithm) to "fill in" the + gap or discontinuity caused by the mode transition. +Therefore, PLC MUST NOT be applied during any normative transition, i.e., when + +A packet includes redundancy for this transition (as described below), +The transition is between any WB SILK packet and any Hybrid packet, or vice + versa, +The transition is between any two Hybrid mode packets, or +The transition is between any two CELT mode packets, + + unless there is actual packet loss. + + +
    + +Transitions with side information include an extra 5 ms "redundant" CELT + frame within the Opus frame. +This frame is designed to fill in the gap or discontinuity in the different + layers without requiring the decoder to conceal it. +For transitions from CELT-only to SILK-only or Hybrid, the redundant frame is + inserted in the first Opus frame after the transition (i.e., the first + SILK-only or Hybrid frame). +For transitions from SILK-only or Hybrid to CELT-only, the redundant frame is + inserted in the last Opus frame before the transition (i.e., the last + SILK-only or Hybrid frame). + + +
    + +The presence of redundancy is signaled in all SILK-only and Hybrid frames, not + just those involved in a mode transition. +This allows the frames to be decoded correctly even if an adjacent frame is + lost. +For SILK-only frames, this signaling is implicit, based on the size of the + of the Opus frame and the number of bits consumed decoding the SILK portion of + it. +After decoding the SILK portion of the Opus frame, the decoder uses ec_tell() + (see ) to check if there are at least 17 bits + remaining. +If so, then the frame contains redundancy. + + + +For Hybrid frames, this signaling is explicit. +After decoding the SILK portion of the Opus frame, the decoder uses ec_tell() + (see ) to ensure there are at least 37 bits remaining. +If so, it reads a symbol with the PDF in + , and if the value is 1, then the + frame contains redundancy. +Otherwise (if there were fewer than 37 bits left or the value was 0), the frame + does not contain redundancy. + + + +PDF +{4095, 1}/4096 + +
    + +
    + +Since the current frame is a SILK-only or a Hybrid frame, it must be at least + 10 ms. +Therefore, it needs an additional flag to indicate whether the redundant + 5 ms CELT frame should be mixed into the beginning of the current frame, + or the end. +After determining that a frame contains redundancy, the decoder reads a + 1 bit symbol with a uniform PDF + (). + + + +PDF +{1, 1}/2 + + + +If the value is zero, this is the first frame in the transition, and the + redundancy belongs at the end. +If the value is one, this is the second frame in the transition, and the + redundancy belongs at the beginning. +There is no way to specify that an Opus frame contains separate redundant CELT + frames at both the beginning and the end. + +
    + +
    + +Unlike the CELT portion of a Hybrid frame, the redundant CELT frame does not + use the same entropy coder state as the rest of the Opus frame, because this + would break the CELT bit allocation mechanism in Hybrid frames. +Thus, a redundant CELT frame always starts and ends on a byte boundary, even in + SILK-only frames, where this is not strictly necessary. + + + +For SILK-only frames, the number of bytes in the redundant CELT frame is simply + the number of whole bytes remaining, which must be at least 2, due to the + space check in . +For Hybrid frames, the number of bytes is equal to 2, plus a decoded unsigned + integer less than 256 (see ). +This may be more than the number of whole bytes remaining in the Opus frame, + in which case the frame is invalid. +However, a decoder is not required to ignore the entire frame, as this may be + the result of a bit error that desynchronized the range coder. +There may still be useful data before the error, and a decoder MAY keep any + audio decoded so far instead of invoking the PLC, but it is RECOMMENDED that + the decoder stop decoding and discard the rest of the current Opus frame. + + + +It would have been possible to avoid these invalid states in the design of Opus + by limiting the range of the explicit length decoded from Hybrid frames by the + actual number of whole bytes remaining. +However, this would require an encoder to determine the rate allocation for the + MDCT layer up front, before it began encoding that layer. +By allowing some invalid sizes, the encoder is able to defer that decision + until much later. +When encoding Hybrid frames which do not include redundancy, the encoder must + still decide up-front if it wishes to use the minimum 37 bits required to + trigger encoding of the redundancy flag, but this is a much looser + restriction. + + + +After determining the size of the redundant CELT frame, the decoder reduces + the size of the buffer currently in use by the range coder by that amount. +The CELT layer read any raw bits from the end of this reduced buffer, and all + calculations of the number of bits remaining in the buffer must be done using + this new, reduced size, rather than the original size of the Opus frame. + +
    + +
    + +The redundant frame is decoded like any other CELT-only frame, with the + exception that it does not contain a TOC byte. +The frame size is fixed at 5 ms, the channel count is set to that of the + current frame, and the audio bandwidth is also set to that of the current + frame, with the exception that for MB SILK frames, it is set to WB. + + + +If the redundancy belongs at the beginning (in a CELT-only to SILK-only or + Hybrid transition), the final reconstructed output uses the first 2.5 ms + of audio output by the decoder for the redundant frame as-is, discarding + the corresponding output from the SILK-only or Hybrid portion of the frame. +The remaining 2.5 ms is cross-lapped with the decoded SILK/Hybrid signal + using the CELT's power-complementary MDCT window to ensure a smooth + transition. + + + +If the redundancy belongs at the end (in a SILK-only or Hybrid to CELT-only + transition), only the second half (2.5 ms) of the audio output by the + decoder for the redundant frame is used. +In that case, the second half of the redundant frame is cross-lapped with the + end of the SILK/Hybrid signal, again using CELT's power-complementary MDCT + window to ensure a smooth transition. + +
    + +
    + +
    + +When a transition occurs, the state of the SILK or the CELT decoder (or both) + may need to be reset before decoding a frame in the new mode. +This avoids reusing "out of date" memory, which may not have been updated in + some time or may not be in a well-defined state due to, e.g., PLC. +The SILK state is reset before every SILK-only or Hybrid frame where the + previous frame was CELT-only. +The CELT state is reset every time the operating mode changes and the new mode + is either Hybrid or CELT-only, except when the transition uses redundancy as + described above. +When switching from SILK-only or Hybrid to CELT-only with redundancy, the CELT + state is reset before decoding the redundant CELT frame embedded in the + SILK-only or Hybrid frame, but it is not reset before decoding the following + CELT-only frame. +When switching from CELT-only mode to SILK-only or Hybrid mode with redundancy, + the CELT decoder is not reset for decoding the redundant CELT frame. + +
    + +
    + + + illustrates all of the normative + transitions involving a mode change, an audio bandwidth change, or both. +Each one uses an S, H, or C to represent an Opus frame in the corresponding + mode. +In addition, an R indicates the presence of redundancy in the Opus frame it is + cross-lapped with. +Its location in the first or last 5 ms is assumed to correspond to whether + it is the frame before or after the transition. +Other uses of redundancy are non-normative. +Finally, a c indicates the contents of the CELT overlap buffer after the + previously decoded frame (i.e., as extracted by decoding a silence frame). +
    + S -> S + & + !R -> R + & + ;S -> S -> S + +NB or MB SILK to Hybrid with Redundancy: S -> S -> S + & + !R ->;H -> H -> H + +WB SILK to Hybrid: S -> S -> S ->!H -> H -> H + +SILK to CELT with Redundancy: S -> S -> S + & + !R -> C -> C -> C + +Hybrid to NB or MB SILK with Redundancy: H -> H -> H + & + !R -> R + & + ;S -> S -> S + +Hybrid to WB SILK: H -> H -> H -> c + \ + + > S -> S -> S + +Hybrid to CELT with Redundancy: H -> H -> H + & + !R -> C -> C -> C + +CELT to SILK with Redundancy: C -> C -> C -> R + & + ;S -> S -> S + +CELT to Hybrid with Redundancy: C -> C -> C -> R + & + |H -> H -> H + +Key: +S SILK-only frame ; SILK decoder reset +H Hybrid frame | CELT and SILK decoder resets +C CELT-only frame ! CELT decoder reset +c CELT overlap + Direct mixing +R Redundant CELT frame & Windowed cross-lap +]]> +
    +The first two and the last two Opus frames in each example are illustrative, + i.e., there is no requirement that a stream remain in the same configuration + for three consecutive frames before or after a switch. +
    + + +The behavior of transitions without redundancy where PLC is allowed is non-normative. +An encoder might still wish to use these transitions if, for example, it + doesn't want to add the extra bitrate required for redundancy or if it makes + a decision to switch after it has already transmitted the frame that would + have had to contain the redundancy. + illustrates the recommended + cross-lapping and decoder resets for these transitions. +
    + S -> S ;S -> S -> S + +NB or MB SILK to Hybrid: S -> S -> S |H -> H -> H + +SILK to CELT without Redundancy: S -> S -> S -> P + & + !C -> C -> C + +Hybrid to NB or MB SILK: H -> H -> H -> c + + + ;S -> S -> S + +Hybrid to CELT without Redundancy: H -> H -> H -> P + & + !C -> C -> C + +CELT to SILK without Redundancy: C -> C -> C -> P + & + ;S -> S -> S + +CELT to Hybrid without Redundancy: C -> C -> C -> P + & + |H -> H -> H + +Key: +S SILK-only frame ; SILK decoder reset +H Hybrid frame | CELT and SILK decoder resets +C CELT-only frame ! CELT decoder reset +c CELT overlap + Direct mixing +P Packet Loss Concealment & Windowed cross-lap +]]> +
    +Encoders SHOULD NOT use other transitions, e.g., those that involve redundancy + in ways not illustrated in . +
    + +
    + +
    + +
    + + + + + + +
    + +Just like the decoder, the Opus encoder also normally consists of two main blocks: the +SILK encoder and the CELT encoder. However, unlike the case of the decoder, a valid +(though potentially suboptimal) Opus encoder is not required to support all modes and +may thus only include a SILK encoder module or a CELT encoder module. +The output bit-stream of the Opus encoding contains bits from the SILK and CELT + encoders, though these are not separable due to the use of a range coder. +A block diagram of the encoder is illustrated below. + +
    + +| Rate |--->| Encoder | V + +-----------+ | | Conversion | | | +---------+ + | Optional | | +------------+ +---------+ | Range | +->| High-pass |--+ | Encoder |----> + | Filter | | +--------------+ +---------+ | | Bit- + +-----------+ | | Delay | | CELT | +---------+ stream + +->| Compensation |->| Encoder | ^ + | | | |------+ + +--------------+ +---------+ +]]> + +
    +
    + + +For a normal encoder where both the SILK and the CELT modules are included, an optimal +encoder should select which coding mode to use at run-time depending on the conditions. +In the reference implementation, the frame size is selected by the application, but the +other configuration parameters (number of channels, bandwidth, mode) are automatically +selected (unless explicitly overridden by the application) depend on the following: + +Requested bitrate +Input sampling rate +Type of signal (speech vs music) +Frame size in use + + +The type of signal currently needs to be provided by the application (though it can be +changed in real-time). An Opus encoder implementation could also do automatic detection, +but since Opus is an interactive codec, such an implementation would likely have to either +delay the signal (for non-interactive applications) or delay the mode switching decisions (for +interactive applications). + + + +When the encoder is configured for voice over IP applications, the input signal is +filtered by a high-pass filter to remove the lowest part of the spectrum +that contains little speech energy and may contain background noise. This is a second order +Auto Regressive Moving Average (i.e., with poles and zeros) filter with a cut-off frequency around 50 Hz. +In the future, a music detector may also be used to lower the cut-off frequency when the +input signal is detected to be music rather than speech. + + +
    + +The range coder acts as the bit-packer for Opus. +It is used in three different ways: to encode + + +Entropy-coded symbols with a fixed probability model using ec_encode() + (entenc.c), + + +Integers from 0 to (2**M - 1) using ec_enc_uint() or ec_enc_bits() + (entenc.c), + +Integers from 0 to (ft - 1) (where ft is not a power of two) using + ec_enc_uint() (entenc.c). + + + + + +The range encoder maintains an internal state vector composed of the four-tuple + (val, rng, rem, ext) representing the low end of the current + range, the size of the current range, a single buffered output byte, and a + count of additional carry-propagating output bytes. +Both val and rng are 32-bit unsigned integer values, rem is a byte value or + less than 255 or the special value -1, and ext is an unsigned integer with at + least 11 bits. +This state vector is initialized at the start of each each frame to the value + (0, 2**31, -1, 0). +After encoding a sequence of symbols, the value of rng in the encoder should + exactly match the value of rng in the decoder after decoding the same sequence + of symbols. +This is a powerful tool for detecting errors in either an encoder or decoder + implementation. +The value of val, on the other hand, represents different things in the encoder + and decoder, and is not expected to match. + + + +The decoder has no analog for rem and ext. +These are used to perform carry propagation in the renormalization loop below. +Each iteration of this loop produces 9 bits of output, consisting of 8 data + bits and a carry flag. +The encoder cannot determine the final value of the output bytes until it + propagates these carry flags. +Therefore the reference implementation buffers a single non-propagating output + byte (i.e., one less than 255) in rem and keeps a count of additional + propagating (i.e., 255) output bytes in ext. +An implementation may choose to use any mathematically equivalent scheme to + perform carry propagation. + + +
    + +The main encoding function is ec_encode() (entenc.c), which encodes symbol k in + the current context using the same three-tuple (fl[k], fh[k], ft) + as the decoder to describe the range of the symbol (see + ). + + +ec_encode() updates the state of the encoder as follows. +If fl[k] is greater than zero, then +
    + +
    +Otherwise, val is unchanged and +
    + +
    +The divisions here are integer division. +
    + +
    + +After this update, the range is normalized using a procedure very similar to + that of , implemented by + ec_enc_normalize() (entenc.c). +The following process is repeated until rng > 2**23. +First, the top 9 bits of val, (val>>23), are sent to the carry buffer, + described in . +Then, the encoder sets +
    + +
    +
    +
    + +
    + +The function ec_enc_carry_out() (entenc.c) implements carry propagation and + output buffering. +It takes as input a 9-bit value, c, consisting of 8 data bits and an additional + carry bit. +If c is equal to the value 255, then ext is simply incremented, and no other + state updates are performed. +Otherwise, let b = (c>>8) be the carry bit. +Then, + + +If the buffered byte rem contains a value other than -1, the encoder outputs + the byte (rem + b). +Otherwise, if rem is -1, no byte is output. + + +If ext is non-zero, then the encoder outputs ext bytes---all with a value of 0 + if b is set, or 255 if b is unset---and sets ext to 0. + + +rem is set to the 8 data bits: +
    + +
    +
    +
    +
    +
    + +
    + +
    + +The reference implementation uses three additional encoding methods that are + exactly equivalent to the above, but make assumptions and simplifications that + allow for a more efficient implementation. + + +
    + +The first is ec_encode_bin() (entenc.c), defined using the parameter ftb + instead of ft. +It is mathematically equivalent to calling ec_encode() with + ft = (1<<ftb), but avoids using division. + +
    + +
    + +The next is ec_enc_bit_logp() (entenc.c), which encodes a single binary symbol. +The context is described by a single parameter, logp, which is the absolute + value of the base-2 logarithm of the probability of a "1". +It is mathematically equivalent to calling ec_encode() with the 3-tuple + (fl[k] = 0, fh[k] = (1<<logp) - 1, + ft = (1<<logp)) if k is 0 and with + (fl[k] = (1<<logp) - 1, + fh[k] = ft = (1<<logp)) if k is 1. +The implementation requires no multiplications or divisions. + +
    + +
    + +The last is ec_enc_icdf() (entenc.c), which encodes a single binary symbol with + a table-based context of up to 8 bits. +This uses the same icdf table as ec_dec_icdf() from + . +The function is mathematically equivalent to calling ec_encode() with + fl[k] = (1<<ftb) - icdf[k-1] (or 0 if + k == 0), fh[k] = (1<<ftb) - icdf[k], and + ft = (1<<ftb). +This only saves a few arithmetic operations over ec_encode_bin(), but allows + the encoder to use the same icdf tables as the decoder. + +
    + +
    + +
    + +The raw bits used by the CELT layer are packed at the end of the buffer using + ec_enc_bits() (entenc.c). +Because the raw bits may continue into the last byte output by the range coder + if there is room in the low-order bits, the encoder must be prepared to merge + these values into a single byte. +The procedure in does this in a way that + ensures both the range coded data and the raw bits can be decoded + successfully. + +
    + +
    + +The function ec_enc_uint() (entenc.c) encodes one of ft equiprobable symbols in + the range 0 to (ft - 1), inclusive, each with a frequency of 1, + where ft may be as large as (2**32 - 1). +Like the decoder (see ), it splits up the + value into a range coded symbol representing up to 8 of the high bits, and, if + necessary, raw bits representing the remainder of the value. + + +ec_enc_uint() takes a two-tuple (t, ft), where t is the value to be + encoded, 0 <= t < ft, and ft is not necessarily a + power of two. +Let ftb = ilog(ft - 1), i.e., the number of bits required + to store (ft - 1) in two's complement notation. +If ftb is 8 or less, then t is encoded directly using ec_encode() with the + three-tuple (t, t + 1, ft). + + +If ftb is greater than 8, then the top 8 bits of t are encoded using the + three-tuple (t>>(ftb - 8), + (t>>(ftb - 8)) + 1, + ((ft - 1)>>(ftb - 8)) + 1), and the + remaining bits, + (t & ((1<<(ftb - 8)) - 1), + are encoded as raw bits with ec_enc_bits(). + +
    + +
    + +After all symbols are encoded, the stream must be finalized by outputting a + value inside the current range. +Let end be the integer in the interval [val, val + rng) with the + largest number of trailing zero bits, b, such that + (end + (1<<b) - 1) is also in the interval + [val, val + rng). +This choice of end allows the maximum number of trailing bits to be set to + arbitrary values while still ensuring the range coded part of the buffer can + be decoded correctly. +Then, while end is not zero, the top 9 bits of end, i.e., (end>>23), are + passed to the carry buffer in accordance with the procedure in + , and end is updated via +
    + +
    +Finally, if the buffered output byte, rem, is neither zero nor the special + value -1, or the carry count, ext, is greater than zero, then 9 zero bits are + sent to the carry buffer to flush it to the output buffer. +When outputting the final byte from the range coder, if it would overlap any + raw bits already packed into the end of the output buffer, they should be ORed + into the same byte. +The bit allocation routines in the CELT layer should ensure that this can be + done without corrupting the range coder data so long as end is chosen as + described above. +If there is any space between the end of the range coder data and the end of + the raw bits, it is padded with zero bits. +This entire process is implemented by ec_enc_done() (entenc.c). +
    +
    + +
    + + The bit allocation routines in Opus need to be able to determine a + conservative upper bound on the number of bits that have been used + to encode the current frame thus far. This drives allocation + decisions and ensures that the range coder and raw bits will not + overflow the output buffer. This is computed in the + reference implementation to whole-bit precision by + the function ec_tell() (entcode.h) and to fractional 1/8th bit + precision by the function ec_tell_frac() (entcode.c). + Like all operations in the range coder, it must be implemented in a + bit-exact manner, and must produce exactly the same value returned by + the same functions in the decoder after decoding the same symbols. + +
    + +
    + +
    + + In many respects the SILK encoder mirrors the SILK decoder described + in . + Details such as the quantization and range coder tables can be found + there, while this section describes the high-level design choices that + were made. + The diagram below shows the basic modules of the SILK encoder. +
    + +| Rate |--->| Mixing |--->| Core |----------> +Input |Conversion| | | | Encoder | Bitstream + +----------+ +--------+ +---------+ +]]> + +
    +
    + +
    + +The input signal's sampling rate is adjusted by a sample rate conversion +module so that it matches the SILK internal sampling rate. +The input to the sample rate converter is delayed by a number of samples +depending on the sample rate ratio, such that the overall delay is constant +for all input and output sample rates. + +
    + +
    + +The stereo mixer is only used for stereo input signals. +It converts a stereo left/right signal into an adaptive +mid/side representation. +The first step is to compute non-adaptive mid/side signals +as half the sum and difference between left and right signals. +The side signal is then minimized in energy by subtracting a +prediction of it based on the mid signal. +This prediction works well when the left and right signals +exhibit linear dependency, for instance for an amplitude-panned +input signal. +Like in the decoder, the prediction coefficients are linearly +interpolated during the first 8 ms of the frame. + The mid signal is always encoded, whereas the residual + side signal is only encoded if it has sufficient + energy compared to the mid signal's energy. + If it has not, + the "mid_only_flag" is set without encoding the side signal. + + +The predictor coefficients are coded regardless of whether +the side signal is encoded. +For each frame, two predictor coefficients are computed, one +that predicts between low-passed mid and side channels, and +one that predicts between high-passed mid and side channels. +The low-pass filter is a simple three-tap filter +and creates a delay of one sample. +The high-pass filtered signal is the difference between +the mid signal delayed by one sample and the low-passed +signal. Instead of explicitly computing the high-passed +signal, it is computationally more efficient to transform +the prediction coefficients before applying them to the +filtered mid signal, as follows +
    + + + +
    +where w0 and w1 are the low-pass and high-pass prediction +coefficients, mid(n-1) is the mid signal delayed by one sample, +LP(n) and HP(n) are the low-passed and high-passed +signals and pred(n) is the prediction signal that is subtracted +from the side signal. +
    +
    + +
    + +What follows is a description of the core encoder and its components. +For simplicity, the core encoder is referred to simply as the encoder in +the remainder of this section. An overview of the encoder is given in +. + +
    + +| | + +---------+ | +---------+ | | + |Voice | | |LTP |12 | | + +-->|Activity |--+ +----->|Scaling |-----------+---->| | + | |Detector |3 | | |Control |<--+ | | | + | +---------+ | | +---------+ | | | | + | | | +---------+ | | | | + | | | |Gains | | | | | + | | | +-->|Processor|---|---+---|---->| R | + | | | | | |11 | | | | a | + | \/ | | +---------+ | | | | n | + | +---------+ | | +---------+ | | | | g | + | |Pitch | | | |LSF | | | | | e | + | +->|Analysis |---+ | |Quantizer|---|---|---|---->| | + | | | |4 | | | |8 | | | | E |--> + | | +---------+ | | +---------+ | | | | n | 2 + | | | | 9/\ 10| | | | | c | + | | | | | \/ | | | | o | + | | +---------+ | | +----------+ | | | | d | + | | |Noise | +--|-->|Prediction|--+---|---|---->| e | + | +->|Shaping |---|--+ |Analysis |7 | | | | r | + | | |Analysis |5 | | | | | | | | | + | | +---------+ | | +----------+ | | | | | + | | | | /\ | | | | | + | | +----------|--|--------+ | | | | | + | | | \/ \/ \/ \/ \/ | | + | | | +---------+ +------------+ | | + | | | | | |Noise | | | +-+-------+-----+------>|Prefilter|--------->|Shaping |-->| | +1 | | 6 |Quantization|13 | | + +---------+ +------------+ +---+ + +1: Input speech signal +2: Range encoded bitstream +3: Voice activity estimate +4: Pitch lags (per 5 ms) and voicing decision (per 20 ms) +5: Noise shaping quantization coefficients + - Short term synthesis and analysis + noise shaping coefficients (per 5 ms) + - Long term synthesis and analysis noise + shaping coefficients (per 5 ms and for voiced speech only) + - Noise shaping tilt (per 5 ms) + - Quantizer gain/step size (per 5 ms) +6: Input signal filtered with analysis noise shaping filters +7: Short and long term prediction coefficients + LTP (per 5 ms) and LPC (per 20 ms) +8: LSF quantization indices +9: LSF coefficients +10: Quantized LSF coefficients +11: Processed gains, and synthesis noise shape coefficients +12: LTP state scaling coefficient. Controlling error propagation + / prediction gain trade-off +13: Quantized signal +]]> + +
    + +
    + +The input signal is processed by a Voice Activity Detector (VAD) to produce +a measure of voice activity, spectral tilt, and signal-to-noise estimates for +each frame. The VAD uses a sequence of half-band filterbanks to split the +signal into four subbands: 0...Fs/16, Fs/16...Fs/8, Fs/8...Fs/4, and +Fs/4...Fs/2, where Fs is the sampling frequency (8, 12, 16, or 24 kHz). +The lowest subband, from 0 - Fs/16, is high-pass filtered with a first-order +moving average (MA) filter (with transfer function H(z) = 1-z**(-1)) to +reduce the energy at the lowest frequencies. For each frame, the signal +energy per subband is computed. +In each subband, a noise level estimator tracks the background noise level +and a Signal-to-Noise Ratio (SNR) value is computed as the logarithm of the +ratio of energy to noise level. +Using these intermediate variables, the following parameters are calculated +for use in other SILK modules: + + +Average SNR. The average of the subband SNR values. + + + +Smoothed subband SNRs. Temporally smoothed subband SNR values. + + + +Speech activity level. Based on the average SNR and a weighted average of the +subband energies. + + + +Spectral tilt. A weighted average of the subband SNRs, with positive weights +for the low subbands and negative weights for the high subbands. + + + +
    + +
    + +The input signal is processed by the open loop pitch estimator shown in +. +
    + +|sampling|->|Correlator| | + | | | | | |4 + | +--------+ +----------+ \/ + | | 2 +-------+ + | | +-->|Speech |5 + +---------+ +--------+ | \/ | |Type |-> + |LPC | |Down | | +----------+ | | + +->|Analysis | +->|sample |-+------------->|Time- | +-------+ + | | | | |to 8 kHz| |Correlator|-----------> + | +---------+ | +--------+ |__________| 6 + | | | |3 + | \/ | \/ + | +---------+ | +----------+ + | |Whitening| | |Time- | +-+->|Filter |-+--------------------------->|Correlator|-----------> +1 | | | | 7 + +---------+ +----------+ + +1: Input signal +2: Lag candidates from stage 1 +3: Lag candidates from stage 2 +4: Correlation threshold +5: Voiced/unvoiced flag +6: Pitch correlation +7: Pitch lags +]]> + +
    +The pitch analysis finds a binary voiced/unvoiced classification, and, for +frames classified as voiced, four pitch lags per frame - one for each +5 ms subframe - and a pitch correlation indicating the periodicity of +the signal. +The input is first whitened using a Linear Prediction (LP) whitening filter, +where the coefficients are computed through standard Linear Prediction Coding +(LPC) analysis. The order of the whitening filter is 16 for best results, but +is reduced to 12 for medium complexity and 8 for low complexity modes. +The whitened signal is analyzed to find pitch lags for which the time +correlation is high. +The analysis consists of three stages for reducing the complexity: + +In the first stage, the whitened signal is downsampled to 4 kHz +(from 8 kHz) and the current frame is correlated to a signal delayed +by a range of lags, starting from a shortest lag corresponding to +500 Hz, to a longest lag corresponding to 56 Hz. + + +The second stage operates on an 8 kHz signal (downsampled from 12, 16, +or 24 kHz) and measures time correlations only near the lags +corresponding to those that had sufficiently high correlations in the first +stage. The resulting correlations are adjusted for a small bias towards +short lags to avoid ending up with a multiple of the true pitch lag. +The highest adjusted correlation is compared to a threshold depending on: + + +Whether the previous frame was classified as voiced + + +The speech activity level + + +The spectral tilt. + + +If the threshold is exceeded, the current frame is classified as voiced and +the lag with the highest adjusted correlation is stored for a final pitch +analysis of the highest precision in the third stage. + + +The last stage operates directly on the whitened input signal to compute time +correlations for each of the four subframes independently in a narrow range +around the lag with highest correlation from the second stage. + + +
    +
    + +
    + +The noise shaping analysis finds gains and filter coefficients used in the +prefilter and noise shaping quantizer. These parameters are chosen such that +they will fulfill several requirements: + + +Balancing quantization noise and bitrate. +The quantization gains determine the step size between reconstruction levels +of the excitation signal. Therefore, increasing the quantization gain +amplifies quantization noise, but also reduces the bitrate by lowering +the entropy of the quantization indices. + + +Spectral shaping of the quantization noise; the noise shaping quantizer is +capable of reducing quantization noise in some parts of the spectrum at the +cost of increased noise in other parts without substantially changing the +bitrate. +By shaping the noise such that it follows the signal spectrum, it becomes +less audible. In practice, best results are obtained by making the shape +of the noise spectrum slightly flatter than the signal spectrum. + + +De-emphasizing spectral valleys; by using different coefficients in the +analysis and synthesis part of the prefilter and noise shaping quantizer, +the levels of the spectral valleys can be decreased relative to the levels +of the spectral peaks such as speech formants and harmonics. +This reduces the entropy of the signal, which is the difference between the +coded signal and the quantization noise, thus lowering the bitrate. + + +Matching the levels of the decoded speech formants to the levels of the +original speech formants; an adjustment gain and a first order tilt +coefficient are computed to compensate for the effect of the noise +shaping quantization on the level and spectral tilt. + + + + +
    + + + Frequency + +1: Input signal spectrum +2: De-emphasized and level matched spectrum +3: Quantization noise spectrum +]]> + +
    + shows an example of an +input signal spectrum (1). +After de-emphasis and level matching, the spectrum has deeper valleys (2). +The quantization noise spectrum (3) more or less follows the input signal +spectrum, while having slightly less pronounced peaks. +The entropy, which provides a lower bound on the bitrate for encoding the +excitation signal, is proportional to the area between the de-emphasized +spectrum (2) and the quantization noise spectrum (3). Without de-emphasis, +the entropy is proportional to the area between input spectrum (1) and +quantization noise (3) - clearly higher. +
    + + +The transformation from input signal to de-emphasized signal can be +described as a filtering operation with a filter +
    + + + +
    +having an adjustment gain G, a first order tilt adjustment filter with +tilt coefficient c_tilt, and where +
    + + + +
    +is the analysis part of the de-emphasis filter, consisting of the short-term +shaping filter with coefficients a_ana(k), and the long-term shaping filter +with coefficients b_ana(k) and pitch lag L. +The parameter d determines the number of long-term shaping filter taps. +
    + + +Similarly, but without the tilt adjustment, the synthesis part can be written as +
    + + + +
    +
    + +All noise shaping parameters are computed and applied per subframe of 5 ms. +First, an LPC analysis is performed on a windowed signal block of 15 ms. +The signal block has a look-ahead of 5 ms relative to the current subframe, +and the window is an asymmetric sine window. The LPC analysis is done with the +autocorrelation method, with an order of between 8, in lowest-complexity mode, +and 16, for best quality. + + +Optionally the LPC analysis and noise shaping filters are warped by replacing +the delay elements by first-order allpass filters. +This increases the frequency resolution at low frequencies and reduces it at +high ones, which better matches the human auditory system and improves +quality. +The warped analysis and filtering comes at a cost in complexity +and is therefore only done in higher complexity modes. + + +The quantization gain is found by taking the square root of the residual energy +from the LPC analysis and multiplying it by a value inversely proportional +to the coding quality control parameter and the pitch correlation. + + +Next the two sets of short-term noise shaping coefficients a_ana(k) and +a_syn(k) are obtained by applying different amounts of bandwidth expansion to the +coefficients found in the LPC analysis. +This bandwidth expansion moves the roots of the LPC polynomial towards the +origin, using the formulas +
    + + + +
    +where a(k) is the k'th LPC coefficient, and the bandwidth expansion factors +g_ana and g_syn are calculated as +
    + + + +
    +where C is the coding quality control parameter between 0 and 1. +Applying more bandwidth expansion to the analysis part than to the synthesis +part gives the desired de-emphasis of spectral valleys in between formants. +
    + + +The long-term shaping is applied only during voiced frames. +It uses three filter taps, described by +
    + + + +
    +For unvoiced frames these coefficients are set to 0. The multiplication factors +F_ana and F_syn are chosen between 0 and 1, depending on the coding quality +control parameter, as well as the calculated pitch correlation and smoothed +subband SNR of the lowest subband. By having F_ana less than F_syn, +the pitch harmonics are emphasized relative to the valleys in between the +harmonics. +
    + + +The tilt coefficient c_tilt is for unvoiced frames chosen as +
    + + + +
    +and as +
    + + + +
    +for voiced frames, where V is the voice activity level between 0 and 1. +
    + +The adjustment gain G serves to correct any level mismatch between the original +and decoded signals that might arise from the noise shaping and de-emphasis. +This gain is computed as the ratio of the prediction gain of the short-term +analysis and synthesis filter coefficients. The prediction gain of an LPC +synthesis filter is the square root of the output energy when the filter is +excited by a unit-energy impulse on the input. +An efficient way to compute the prediction gain is by first computing the +reflection coefficients from the LPC coefficients through the step-down +algorithm, and extracting the prediction gain from the reflection coefficients +as +
    + + + +
    +where r_k is the k'th reflection coefficient. +
    + + +Initial values for the quantization gains are computed as the square-root of +the residual energy of the LPC analysis, adjusted by the coding quality control +parameter. +These quantization gains are later adjusted based on the results of the +prediction analysis. + +
    + +
    + +The prediction analysis is performed in one of two ways depending on how +the pitch estimator classified the frame. +The processing for voiced and unvoiced speech is described in + and + , respectively. + Inputs to this function include the pre-whitened signal from the + pitch estimator (see ). + + +
    + + For a frame of voiced speech the pitch pulses will remain dominant in the + pre-whitened input signal. + Further whitening is desirable as it leads to higher quality at the same + available bitrate. + To achieve this, a Long-Term Prediction (LTP) analysis is carried out to + estimate the coefficients of a fifth-order LTP filter for each of four + subframes. + The LTP coefficients are quantized using the method described in + , and the quantized LTP + coefficients are used to compute the LTP residual signal. + This LTP residual signal is the input to an LPC analysis where the LPC coefficients are + estimated using Burg's method , such that the residual energy is minimized. + The estimated LPC coefficients are converted to a Line Spectral Frequency (LSF) vector + and quantized as described in . +After quantization, the quantized LSF vector is converted back to LPC +coefficients using the full procedure in . +By using quantized LTP coefficients and LPC coefficients derived from the +quantized LSF coefficients, the encoder remains fully synchronized with the +decoder. +The quantized LPC and LTP coefficients are also used to filter the input +signal and measure residual energy for each of the four subframes. + +
    +
    + +For a speech signal that has been classified as unvoiced, there is no need +for LTP filtering, as it has already been determined that the pre-whitened +input signal is not periodic enough within the allowed pitch period range +for LTP analysis to be worth the cost in terms of complexity and bitrate. +The pre-whitened input signal is therefore discarded, and instead the input +signal is used for LPC analysis using Burg's method. +The resulting LPC coefficients are converted to an LSF vector and quantized +as described in the following section. +They are then transformed back to obtain quantized LPC coefficients, which +are then used to filter the input signal and measure residual energy for +each of the four subframes. + +
    + +The main purpose of linear prediction in SILK is to reduce the bitrate by +minimizing the residual energy. +At least at high bitrates, perceptual aspects are handled +independently by the noise shaping filter. +Burg's method is used because it provides higher prediction gain +than the autocorrelation method and, unlike the covariance method, +produces stable filters (assuming numerical errors don't spoil +that). SILK's implementation of Burg's method is also computationally +faster than the autocovariance method. +The implementation of Burg's method differs from traditional +implementations in two aspects. +The first difference is that it +operates on autocorrelations, similar to the Schur algorithm , but +with a simple update to the autocorrelations after finding each +reflection coefficient to make the result identical to Burg's method. +This brings down the complexity of Burg's method to near that of +the autocorrelation method. +The second difference is that the signal in each subframe is scaled +by the inverse of the residual quantization step size. Subframes with +a small quantization step size will on average spend more bits for a +given amount of residual energy than subframes with a large step size. +Without scaling, Burg's method minimizes the total residual energy in +all subframes, which doesn't necessarily minimize the total number of +bits needed for coding the quantized residual. The residual energy +of the scaled subframes is a better measure for that number of +bits. + +
    +
    +
    + +
    + +Unlike many other speech codecs, SILK uses variable bitrate coding +for the LSFs. +This improves the average rate-distortion (R-D) tradeoff and reduces outliers. +The variable bitrate coding minimizes a linear combination of the weighted +quantization errors and the bitrate. +The weights for the quantization errors are the Inverse +Harmonic Mean Weighting (IHMW) function proposed by Laroia et al. +(see ). +These weights are referred to here as Laroia weights. + + +The LSF quantizer consists of two stages. +The first stage is an (unweighted) vector quantizer (VQ), with a +codebook size of 32 vectors. +The quantization errors for the codebook vector are sorted, and +for the N best vectors a second stage quantizer is run. +By varying the number N a tradeoff is made between R-D performance +and computational efficiency. +For each of the N codebook vectors the Laroia weights corresponding +to that vector (and not to the input vector) are calculated. +Then the residual between the input LSF vector and the codebook +vector is scaled by the square roots of these Laroia weights. +This scaling partially normalizes error sensitivity for the +residual vector, so that a uniform quantizer with fixed +step sizes can be used in the second stage without too much +performance loss. +And by scaling with Laroia weights determined from the first-stage +codebook vector, the process can be reversed in the decoder. + + +The second stage uses predictive delayed decision scalar +quantization. +The quantization error is weighted by Laroia weights determined +from the LSF input vector. +The predictor multiplies the previous quantized residual value +by a prediction coefficient that depends on the vector index from the +first stage VQ and on the location in the LSF vector. +The prediction is subtracted from the LSF residual value before +quantizing the result, and added back afterwards. +This subtraction can be interpreted as shifting the quantization levels +of the scalar quantizer, and as a result the quantization error of +each value depends on the quantization decision of the previous value. +This dependency is exploited by the delayed decision mechanism to +search for a quantization sequency with best R-D performance +with a Viterbi-like algorithm . +The quantizer processes the residual LSF vector in reverse order +(i.e., it starts with the highest residual LSF value). +This is done because the prediction works slightly +better in the reverse direction. + + +The quantization index of the first stage is entropy coded. +The quantization sequence from the second stage is also entropy +coded, where for each element the probability table is chosen +depending on the vector index from the first stage and the location +of that element in the LSF vector. + + +
    + +If the input is stable, finding the best candidate usually results in a +quantized vector that is also stable. Because of the two-stage approach, +however, it is possible that the best quantization candidate is unstable. +The encoder applies the same stabilization procedure applied by the decoder + (see to ensure the LSF parameters + are within their valid range, increasingly sorted, and have minimum + distances between each other and the border values. + +
    +
    + +
    + +For voiced frames, the prediction analysis described in + resulted in four sets +(one set per subframe) of five LTP coefficients, plus four weighting matrices. +The LTP coefficients for each subframe are quantized using entropy constrained +vector quantization. +A total of three vector codebooks are available for quantization, with +different rate-distortion trade-offs. The three codebooks have 10, 20, and +40 vectors and average rates of about 3, 4, and 5 bits per vector, respectively. +Consequently, the first codebook has larger average quantization distortion at +a lower rate, whereas the last codebook has smaller average quantization +distortion at a higher rate. +Given the weighting matrix W_ltp and LTP vector b, the weighted rate-distortion +measure for a codebook vector cb_i with rate r_i is give by +
    + + + +
    +where u is a fixed, heuristically-determined parameter balancing the distortion +and rate. +Which codebook gives the best performance for a given LTP vector depends on the +weighting matrix for that LTP vector. +For example, for a low valued W_ltp, it is advantageous to use the codebook +with 10 vectors as it has a lower average rate. +For a large W_ltp, on the other hand, it is often better to use the codebook +with 40 vectors, as it is more likely to contain the best codebook vector. +The weighting matrix W_ltp depends mostly on two aspects of the input signal. +The first is the periodicity of the signal; the more periodic, the larger W_ltp. +The second is the change in signal energy in the current subframe, relative to +the signal one pitch lag earlier. +A decaying energy leads to a larger W_ltp than an increasing energy. +Both aspects fluctuate relatively slowly, which causes the W_ltp matrices for +different subframes of one frame often to be similar. +Because of this, one of the three codebooks typically gives good performance +for all subframes, and therefore the codebook search for the subframe LTP +vectors is constrained to only allow codebook vectors to be chosen from the +same codebook, resulting in a rate reduction. +
    + + +To find the best codebook, each of the three vector codebooks is +used to quantize all subframe LTP vectors and produce a combined +weighted rate-distortion measure for each vector codebook. +The vector codebook with the lowest combined rate-distortion +over all subframes is chosen. The quantized LTP vectors are used +in the noise shaping quantizer, and the index of the codebook +plus the four indices for the four subframe codebook vectors +are passed on to the range encoder. + +
    + +
    + +In the prefilter the input signal is filtered using the spectral valley +de-emphasis filter coefficients from the noise shaping analysis +(see ). +By applying only the noise shaping analysis filter to the input signal, +it provides the input to the noise shaping quantizer. + +
    + +
    + +The noise shaping quantizer independently shapes the signal and coding noise +spectra to obtain a perceptually higher quality at the same bitrate. + + +The prefilter output signal is multiplied with a compensation gain G computed +in the noise shaping analysis. Then the output of a synthesis shaping filter +is added, and the output of a prediction filter is subtracted to create a +residual signal. +The residual signal is multiplied by the inverse quantized quantization gain +from the noise shaping analysis, and input to a scalar quantizer. +The quantization indices of the scalar quantizer represent a signal of pulses +that is input to the pyramid range encoder. +The scalar quantizer also outputs a quantization signal, which is multiplied +by the quantized quantization gain from the noise shaping analysis to create +an excitation signal. +The output of the prediction filter is added to the excitation signal to form +the quantized output signal y(n). +The quantized output signal y(n) is input to the synthesis shaping and +prediction filters. + + +Optionally the noise shaping quantizer operates in a delayed decision +mode. +In this mode it uses a Viterbi algorithm to keep track of +multiple rounding choices in the quantizer and select the best +one after a delay of 32 samples. This improves the rate/distortion +performance of the quantizer. + +
    + +
    + + SILK was designed to run in Variable Bitrate (VBR) mode. However + the reference implementation also has a Constant Bitrate (CBR) mode + for SILK. In CBR mode SILK will attempt to encode each packet with + no more than the allowed number of bits. The Opus wrapper code + then pads the bitstream if any unused bits are left in SILK mode, or + encodes the high band with the remaining number of bits in Hybrid mode. + The number of payload bits is adjusted by changing + the quantization gains and the rate/distortion tradeoff in the noise + shaping quantizer, in an iterative loop + around the noise shaping quantizer and entropy coding. + Compared to the SILK VBR mode, the CBR mode has lower + audio quality at a given average bitrate, and also has higher + computational complexity. + +
    + +
    + +
    + + +
    + +Most of the aspects of the CELT encoder can be directly derived from the description +of the decoder. For example, the filters and rotations in the encoder are simply the +inverse of the operation performed by the decoder. Similarly, the quantizers generally +optimize for the mean square error (because noise shaping is part of the bit-stream itself), +so no special search is required. For this reason, only the less straightforward aspects of the +encoder are described here. + + +
    +The pitch prefilter is applied after the pre-emphasis. It is applied +in such a way as to be the inverse of the decoder's post-filter. The main non-obvious aspect of the +prefilter is the selection of the pitch period. The pitch search should be optimized for the +following criteria: + +continuity: it is important that the pitch period +does not change abruptly between frames; and +avoidance of pitch multiples: when the period used is a multiple of the real period +(lower frequency fundamental), the post-filter loses most of its ability to reduce noise + + +
    + +
    + +The MDCT output is divided into bands that are designed to match the ear's critical +bands for the smallest (2.5 ms) frame size. The larger frame sizes use integer +multiples of the 2.5 ms layout. For each band, the encoder +computes the energy that will later be encoded. Each band is then normalized by the +square root of the unquantized energy, such that each band now forms a unit vector X. +The energy and the normalization are computed by compute_band_energies() +and normalise_bands() (bands.c), respectively. + +
    + +
    + + +Energy quantization (both coarse and fine) can be easily understood from the decoding process. +For all useful bitrates, the coarse quantizer always chooses the quantized log energy value that +minimizes the error for each band. Only at very low rate does the encoder allow larger errors to +minimize the rate and avoid using more bits than are available. When the +available CPU requirements allow it, it is best to try encoding the coarse energy both with and without +inter-frame prediction such that the best prediction mode can be selected. The optimal mode depends on +the coding rate, the available bitrate, and the current rate of packet loss. + + +The fine energy quantizer always chooses the quantized log energy value that +minimizes the error for each band because the rate of the fine quantization depends only +on the bit allocation and not on the values that are coded. + +
    + +
    +The encoder must use exactly the same bit allocation process as used by the decoder +and described in . The three mechanisms that can be used by the +encoder to adjust the bitrate on a frame-by-frame basis are band boost, allocation trim, +and band skipping. + + +
    +The reference encoder makes a decision to boost a band when the energy of that band is significantly +higher than that of the neighboring bands. Let E_j be the log-energy of band j, we define + +D_j = 2*E_j - E_j-1 - E_j+1 + + +The allocation of band j is boosted once if D_j > t1 and twice if D_j > t2. For LM>=1, t1=2 and t2=4, +while for LM<1, t1=3 and t2=5. + + +
    + +
    +The allocation trim is a value between 0 and 10 (inclusively) that controls the allocation +balance between the low and high frequencies. The encoder starts with a safe "default" of 5 +and deviates from that default in two different ways. First the trim can deviate by +/- 2 +depending on the spectral tilt of the input signal. For signals with more low frequencies, the +trim is increased by up to 2, while for signals with more high frequencies, the trim is +decreased by up to 2. +For stereo inputs, the trim value can +be decreased by up to 4 when the inter-channel correlation at low frequency (first 8 bands) +is high. +
    + +
    +The encoder uses band skipping to ensure that the shape of the bands is only coded +if there is at least 1/2 bit per sample available for the PVQ. If not, then no bit is allocated +and folding is used instead. To ensure continuity in the allocation, some amount of hysteresis is +added to the process, such that a band that received PVQ bits in the previous frame only needs 7/16 +bit/sample to be coded for the current frame, while a band that did not receive PVQ bits in the +previous frames needs at least 9/16 bit/sample to be coded. +
    + +
    + +
    +Because CELT applies mid-side stereo coupling in the normalized domain, it does not suffer from +important stereo image problems even when the two channels are completely uncorrelated. For this reason +it is always safe to use stereo coupling on any audio frame. That being said, there are some frames +for which dual (independent) stereo is still more efficient. This decision is made by comparing the estimated +entropy with and without coupling over the first 13 bands, taking into account the fact that all bands with +more than two MDCT bins require one extra degree of freedom when coded in mid-side. Let L1_ms and L1_lr +be the L1-norm of the mid-side vector and the L1-norm of the left-right vector, respectively. The decision +to use mid-side is made if and only if +
    + +
    +where bins is the number of MDCT bins in the first 13 bands and E is the number of extra degrees of +freedom for mid-side coding. For LM>1, E=13, otherwise E=5. +
    + +The reference encoder decides on the intensity stereo threshold based on the bitrate alone. After +taking into account the frame size by subtracting 80 bits per frame for coarse energy, the first +band using intensity coding is as follows: + + + +bitrate (kb/s) +start band +<35 8 +35-50 12 +50-68 16 +84-84 18 +84-102 19 +102-130 20 +>130 disabled + + + +
    + +
    + +The choice of time-frequency resolution used in is based on +R-D optimization. The distortion is the L1-norm (sum of absolute values) of each band +after each TF resolution under consideration. The L1 norm is used because it represents the entropy +for a Laplacian source. The number of bits required to code a change in TF resolution between +two bands is higher than the cost of having those two bands use the same resolution, which is +what requires the R-D optimization. The optimal decision is computed using the Viterbi algorithm. +See tf_analysis() in celt/celt.c. + +
    + +
    + +The choice of the spreading value in has an +impact on the nature of the coding noise introduced by CELT. The larger the f_r value, the +lower the impact of the rotation, and the more tonal the coding noise. The +more tonal the signal, the more tonal the noise should be, so the CELT encoder determines +the optimal value for f_r by estimating how tonal the signal is. The tonality estimate +is based on discrete pdf (4-bin histogram) of each band. Bands that have a large number of small +values are considered more tonal and a decision is made by combining all bands with more than +8 samples. See spreading_decision() in celt/bands.c. + +
    + +
    +CELT uses a Pyramid Vector Quantization (PVQ) +codebook for quantizing the details of the spectrum in each band that have not +been predicted by the pitch predictor. The PVQ codebook consists of all sums +of K signed pulses in a vector of N samples, where two pulses at the same position +are required to have the same sign. Thus the codebook includes +all integer codevectors y of N dimensions that satisfy sum(abs(y(j))) = K. + + + +In bands where there are sufficient bits allocated PVQ is used to encode +the unit vector that results from the normalization in + directly. Given a PVQ codevector y, +the unit vector X is obtained as X = y/||y||, where ||.|| denotes the +L2 norm. + + + +
    + + +The search for the best codevector y is performed by alg_quant() +(vq.c). There are several possible approaches to the +search, with a trade-off between quality and complexity. The method used in the reference +implementation computes an initial codeword y1 by projecting the normalized spectrum +X onto the codebook pyramid of K-1 pulses: + + +y0 = truncate_towards_zero( (K-1) * X / sum(abs(X))) + + + +Depending on N, K and the input data, the initial codeword y0 may contain from +0 to K-1 non-zero values. All the remaining pulses, with the exception of the last one, +are found iteratively with a greedy search that minimizes the normalized correlation +between y and X: +
    + +
    +
    + + +The search described above is considered to be a good trade-off between quality +and computational cost. However, there are other possible ways to search the PVQ +codebook and the implementers MAY use any other search methods. See alg_quant() in celt/vq.c. + +
    + +
    + + +The vector to encode, X, is converted into an index i such that + 0 <= i < V(N,K) as follows. +Let i = 0 and k = 0. +Then for j = (N - 1) down to 0, inclusive, do: + + +If k > 0, set + i = i + (V(N-j-1,k-1) + V(N-j,k-1))/2. + +Set k = k + abs(X[j]). + +If X[j] < 0, set + i = i + (V(N-j-1,k) + V(N-j,k))/2. + + + + + +The index i is then encoded using the procedure in + with ft = V(N,K). + + +
    + +
    + + + + + +
    + +
    + + +
    + + +It is our intention to allow the greatest possible choice of freedom in +implementing the specification. For this reason, outside of the exceptions +noted in this section, conformance is defined through the reference +implementation of the decoder provided in . +Although this document includes an English description of the codec, should +the description contradict the source code of the reference implementation, +the latter shall take precedence. + + + +Compliance with this specification means that in addition to following the normative keywords in this document, + a decoder's output MUST also be + within the thresholds specified by the opus_compare.c tool (included + with the code) when compared to the reference implementation for each of the + test vectors provided (see ) and for each output + sampling rate and channel count supported. In addition, a compliant + decoder implementation MUST have the same final range decoder state as that of the + reference decoder. It is therefore RECOMMENDED that the + decoder implement the same functional behavior as the reference. + + A decoder implementation is not required to support all output sampling + rates or all output channel counts. + + +
    + +Using the reference code provided in , +a test vector can be decoded with + +opus_demo -d <rate> <channels> testvectorX.bit testX.out + +where <rate> is the sampling rate and can be 8000, 12000, 16000, 24000, or 48000, and +<channels> is 1 for mono or 2 for stereo. + + + +If the range decoder state is incorrect for one of the frames, the decoder will exit with +"Error: Range coder state mismatch between encoder and decoder". If the decoder succeeds, then +the output can be compared with the "reference" output with + +opus_compare -s -r <rate> testvectorX.dec testX.out + +for stereo or + +opus_compare -r <rate> testvectorX.dec testX.out + +for mono. + + +In addition to indicating whether the test vector comparison passes, the opus_compare tool +outputs an "Opus quality metric" that indicates how well the tested decoder matches the +reference implementation. A quality of 0 corresponds to the passing threshold, while +a quality of 100 is the highest possible value and means that the output of the tested decoder is identical to the reference +implementation. The passing threshold (quality 0) was calibrated in such a way that it corresponds to +additive white noise with a 48 dB SNR (similar to what can be obtained on a cassette deck). +It is still possible for an implementation to sound very good with such a low quality measure +(e.g. if the deviation is due to inaudible phase distortion), but unless this is verified by +listening tests, it is RECOMMENDED that implementations achieve a quality above 90 for 48 kHz +decoding. For other sampling rates, it is normal for the quality metric to be lower +(typically as low as 50 even for a good implementation) because of harmless mismatch with +the delay and phase of the internal sampling rate conversion. + + + +On POSIX environments, the run_vectors.sh script can be used to verify all test +vectors. This can be done with + +run_vectors.sh <exec path> <vector path> <rate> + +where <exec path> is the directory where the opus_demo and opus_compare executables +are built and <vector path> is the directory containing the test vectors. + +
    + +
    + +Opus Custom is an OPTIONAL part of the specification that is defined to +handle special sample rates and frame rates that are not supported by the +main Opus specification. Use of Opus Custom is discouraged for all but very +special applications for which a frame size different from 2.5, 5, 10, or 20 ms is +needed (for either complexity or latency reasons). Because Opus Custom is +optional, streams encoded using Opus Custom cannot be expected to be decodable by all Opus +implementations. Also, because no in-band mechanism exists for specifying the sampling +rate and frame size of Opus Custom streams, out-of-band signaling is required. +In Opus Custom operation, only the CELT layer is available, using the opus_custom_* function +calls in opus_custom.h. + +
    + +
    + +
    + + +Implementations of the Opus codec need to take appropriate security considerations +into account, as outlined in . +It is extremely important for the decoder to be robust against malicious +payloads. +Malicious payloads must not cause the decoder to overrun its allocated memory + or to take an excessive amount of resources to decode. +Although problems +in encoders are typically rarer, the same applies to the encoder. Malicious +audio streams must not cause the encoder to misbehave because this would +allow an attacker to attack transcoding gateways. + + +The reference implementation contains no known buffer overflow or cases where + a specially crafted packet or audio segment could cause a significant increase + in CPU load. +However, on certain CPU architectures where denormalized floating-point + operations are much slower than normal floating-point operations, it is + possible for some audio content (e.g., silence or near-silence) to cause an + increase in CPU load. +Denormals can be introduced by reordering operations in the compiler and depend + on the target architecture, so it is difficult to guarantee that an implementation + avoids them. +For architectures on which denormals are problematic, adding very small + floating-point offsets to the affected signals to prevent significant numbers + of denormalized operations is RECOMMENDED. +Alternatively, it is often possible to configure the hardware to treat + denormals as zero (DAZ). +No such issue exists for the fixed-point reference implementation. + +The reference implementation was validated in the following conditions: + + +Sending the decoder valid packets generated by the reference encoder and + verifying that the decoder's final range coder state matches that of the + encoder. + + +Sending the decoder packets generated by the reference encoder and then + subjected to random corruption. + +Sending the decoder random packets. + +Sending the decoder packets generated by a version of the reference encoder + modified to make random coding decisions (internal fuzzing), including mode + switching, and verifying that the range coder final states match. + + +In all of the conditions above, both the encoder and the decoder were run + inside the Valgrind memory + debugger, which tracks reads and writes to invalid memory regions as well as + the use of uninitialized memory. +There were no errors reported on any of the tested conditions. + +
    + + +
    + +This document has no actions for IANA. + +
    + +
    + +Thanks to all other developers, including Raymond Chen, Soeren Skak Jensen, Gregory Maxwell, +Christopher Montgomery, and Karsten Vandborg Soerensen. We would also +like to thank Igor Dyakonov, Jan Skoglund, and Christian Hoene for their help with subjective testing of the +Opus codec. Thanks to Ralph Giles, John Ridges, Ben Schwartz, Keith Yan, Christian Hoene, Kat Walsh, and many others on the Opus and CELT mailing lists +for their bug reports and feedback. + +
    + +
    +The authors agree to grant third parties the irrevocable right to copy, use and distribute +the work (excluding Code Components available under the simplified BSD license), with or +without modification, in any medium, without royalty, provided that, unless separate +permission is granted, redistributed modified works do not contain misleading author, version, +name of work, or endorsement information. +
    + +
    + + + + + + + +Key words for use in RFCs to Indicate Requirement Levels + + + + + + + + + + + +Requirements for an Internet Audio Codec + + + + + +IETF + + +This document provides specific requirements for an Internet audio + codec. These requirements address quality, sample rate, bitrate, + and packet-loss robustness, as well as other desirable properties. + + + + + + + + + + +SILK Speech Codec + + + + + + + + + + + + + + + + + +Robust and Efficient Quantization of Speech LSP Parameters Using Structured Vector Quantization + + + + + + + + + + + + + + + + +Constrained-Energy Lapped Transform (CELT) Codec + + + + + + + + + + + + + + + + + + +Guidelines for the use of Variable Bit Rate Audio with Secure RTP + + + + + + + + + + + + + + +Internet Denial-of-Service Considerations + + + + + +IAB + + +This document provides an overview of possible avenues for denial-of-service (DoS) attack on Internet systems. The aim is to encourage protocol designers and network engineers towards designs that are more robust. We discuss partial solutions that reduce the effectiveness of attacks, and how some solutions might inadvertently open up alternative vulnerabilities. This memo provides information for the Internet community. + + + + + + +Range encoding: An algorithm for removing redundancy from a digitised message + + + + + + + + +Source coding algorithms for fast data compression + + + + + + + + +A Pyramid Vector Quantizer + + + + + + + + +The Computation of Line Spectral Frequencies Using Chebyshev Polynomials + + + + + + + + + + +Valgrind website + + + + + + +Google NetEQ code + + + + + + +Google WebRTC code + + + + + + + +Opus Git Repository + + + + + + +Opus website + + + + + + +Vorbis website + + + + + + +Matroska website + + + + + + +Opus Testvectors (webside) + + + + + + +Opus Testvectors (proceedings) + + + + + + +Line Spectral Pairs +Wikipedia + + + + + +Range Coding +Wikipedia + + + + + +Hadamard Transform +Wikipedia + + + + + +Viterbi Algorithm +Wikipedia + + + + + +White Noise +Wikipedia + + + + + +Linear Prediction +Wikipedia + + + + + +Modified Discrete Cosine Transform +Wikipedia + + + + + +Fast Fourier Transform +Wikipedia + + + + + +Z-transform +Wikipedia + + + + + + +Maximum Entropy Spectral Analysis + + + + + + +A fixed point computation of partial correlation coefficients + + + + + + + + +Analysis/synthesis filter bank design based on time domain aliasing cancellation + + + + + + + + +A High-Quality Speech and Audio Codec With Less Than 10 ms delay + + + + + + + + + + + + +Subdivision of the audible frequency range into critical bands + + + + + + + + + +
    + +This appendix contains the complete source code for the +reference implementation of the Opus codec written in C. By default, +this implementation relies on floating-point arithmetic, but it can be +compiled to use only fixed-point arithmetic by defining the FIXED_POINT +macro. Information on building and using the reference implementation is +available in the README file. + + +The implementation can be compiled with either a C89 or a C99 +compiler. It is reasonably optimized for most platforms such that +only architecture-specific optimizations are likely to be useful. +The FFT used is a slightly modified version of the KISS-FFT library, +but it is easy to substitute any other FFT library. + + + +While the reference implementation does not rely on any +undefined behavior as defined by C89 or C99, +it relies on common implementation-defined behavior +for two's complement architectures: + +Right shifts of negative values are consistent with two's complement arithmetic, so that a>>b is equivalent to floor(a/(2**b)), +For conversion to a signed integer of N bits, the value is reduced modulo 2**N to be within range of the type, +The result of integer division of a negative value is truncated towards zero, and +The compiler provides a 64-bit integer type (a C99 requirement which is supported by most C89 compilers). + + + + +In its current form, the reference implementation also requires the following +architectural characteristics to obtain acceptable performance: + +Two's complement arithmetic, +At least a 16 bit by 16 bit integer multiplier (32-bit result), and +At least a 32-bit adder/accumulator. + + + + +
    + +The complete source code can be extracted from this draft, by running the +following command line: + + + opus_source.tar.gz +]]> + +tar xzvf opus_source.tar.gz + +cd opus_source +make + +On systems where the provided Makefile does not work, the following command line may be used to compile +the source code: + + + + + +On systems where the base64 utility is not present, the following commands can be used instead: + + opus.b64 +]]> +openssl base64 -d -in opus.b64 > opus_source.tar.gz + + + +
    + +
    + +As of the time of publication of this memo, an up-to-date implementation conforming to +this standard is available in a + Git repository. +Releases and other resources are available at + . However, although that implementation is expected to + remain conformant with the standard, it is the code in this document that shall + remain normative. + +
    + +
    + + + +
    + +
    + +Because of size constraints, the Opus test vectors are not distributed in this +draft. They are available in the proceedings of the 83th IETF meeting (Paris) and from the Opus codec website at +. These test vectors were created specifically to exercise +all aspects of the decoder and therefore the audio quality of the decoded output is +significantly lower than what Opus can achieve in normal operation. + + + +The SHA1 hash of the files in the test vector package are + + + +
    + +
    + +
    + +To use the internal framing described in , the decoder + must know the total length of the Opus packet, in bytes. +This section describes a simple variation of that framing which can be used + when the total length of the packet is not known. +Nothing in the encoding of the packet itself allows a decoder to distinguish + between the regular, undelimited framing and the self-delimiting framing + described in this appendix. +Which one is used and where must be established by context at the transport + layer. +It is RECOMMENDED that a transport layer choose exactly one framing scheme, + rather than allowing an encoder to signal which one it wants to use. + + + +For example, although a regular Opus stream does not support more than two + channels, a multi-channel Opus stream may be formed from several one- and + two-channel streams. +To pack an Opus packet from each of these streams together in a single packet + at the transport layer, one could use the self-delimiting framing for all but + the last stream, and then the regular, undelimited framing for the last one. +Reverting to the undelimited framing for the last stream saves overhead + (because the total size of the transport-layer packet will still be known), + and ensures that a "multi-channel" stream which only has a single Opus stream + uses the same framing as a regular Opus stream does. +This avoids the need for signaling to distinguish these two cases. + + + +The self-delimiting framing is identical to the regular, undelimited framing + from , except that each Opus packet contains one extra + length field, encoded using the same one- or two-byte scheme from + . +This extra length immediately precedes the compressed data of the first Opus + frame in the packet, and is interpreted in the various modes as follows: + + +Code 0 packets: It is the length of the single Opus frame (see + ). + + +Code 1 packets: It is the length used for both of the Opus frames (see + ). + + +Code 2 packets: It is the length of the second Opus frame (see + ). + +CBR Code 3 packets: It is the length used for all of the Opus frames (see + ). + +VBR Code 3 packets: It is the length of the last Opus frame (see + ). + + + + +
    + +
    + +
    + +
    + +
    + +
    + +
    + +
    + +
    + +
    + +
    + +
    + +
    diff --git a/extern/opus/doc/draft-ietf-payload-rtp-opus.xml b/extern/opus/doc/draft-ietf-payload-rtp-opus.xml new file mode 100644 index 0000000..c4eb210 --- /dev/null +++ b/extern/opus/doc/draft-ietf-payload-rtp-opus.xml @@ -0,0 +1,960 @@ + + + + + + + + + + + + + + + + + + + + + + ]> + + + + + + + + + + + + + + + + + + RTP Payload Format for the Opus Speech and Audio Codec + + + +
    + jspittka@gmail.com +
    +
    + + + vocTone +
    + + + + + + + + koenvos74@gmail.com +
    +
    + + + Mozilla +
    + + 331 E. Evelyn Avenue + Mountain View + CA + 94041 + USA + + jmvalin@jmvalin.ca +
    +
    + + + + + + This document defines the Real-time Transport Protocol (RTP) payload + format for packetization of Opus encoded + speech and audio data necessary to integrate the codec in the + most compatible way. It also provides an applicability statement + for the use of Opus over RTP. Further, it describes media type registrations + for the RTP payload format. + + +
    + + +
    + + Opus is a speech and audio codec developed within the + IETF Internet Wideband Audio Codec working group. The codec + has a very low algorithmic delay and it + is highly scalable in terms of audio bandwidth, bitrate, and + complexity. Further, it provides different modes to efficiently encode speech signals + as well as music signals, thus making it the codec of choice for + various applications using the Internet or similar networks. + + + This document defines the Real-time Transport Protocol (RTP) + payload format for packetization + of Opus encoded speech and audio data necessary to + integrate Opus in the + most compatible way. It also provides an applicability statement + for the use of Opus over RTP. + Further, it describes media type registrations for + the RTP payload format. + +
    + +
    + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this + document are to be interpreted as described in . + + + The range of audio frequecies being coded + Constant bitrate + Central Processing Unit + Discontinuous transmission + Forward error correction + Internet Protocol + Speech or audio samples (per channel) + Session Description Protocol + Variable bitrate + + + + Throughout this document, we refer to the following definitions: + + + Abbreviation + Name + Audio Bandwidth (Hz) + Sampling Rate (Hz) + NB + Narrowband + 0 - 4000 + 8000 + + MB + Mediumband + 0 - 6000 + 12000 + + WB + Wideband + 0 - 8000 + 16000 + + SWB + Super-wideband + 0 - 12000 + 24000 + + FB + Fullband + 0 - 20000 + 48000 + + + Audio bandwidth naming + + +
    + +
    + + Opus encodes speech + signals as well as general audio signals. Two different modes can be + chosen, a voice mode or an audio mode, to allow the most efficient coding + depending on the type of the input signal, the sampling frequency of the + input signal, and the intended application. + + + + The voice mode allows efficient encoding of voice signals at lower bit + rates while the audio mode is optimized for general audio signals at medium and + higher bitrates. + + + + Opus is highly scalable in terms of audio + bandwidth, bitrate, and complexity. Further, Opus allows + transmitting stereo signals with in-band signaling in the bit-stream. + + +
    + + Opus supports bitrates from 6 kb/s to 510 kb/s. + The bitrate can be changed dynamically within that range. + All + other parameters being + equal, higher bitrates result in higher audio quality. + +
    + + For a frame size of + 20 ms, these + are the bitrate "sweet spots" for Opus in various configurations: + + + 8-12 kb/s for NB speech, + 16-20 kb/s for WB speech, + 28-40 kb/s for FB speech, + 48-64 kb/s for FB mono music, and + 64-128 kb/s for FB stereo music. + + +
    +
    + + For the same average bitrate, variable bitrate (VBR) can achieve higher audio quality + than constant bitrate (CBR). For the majority of voice transmission applications, VBR + is the best choice. One reason for choosing CBR is the potential + information leak that might occur when encrypting the + compressed stream. See for guidelines on when VBR is + appropriate for encrypted audio communications. In the case where an existing + VBR stream needs to be converted to CBR for security reasons, then the Opus padding + mechanism described in is the RECOMMENDED way to achieve padding + because the RTP padding bit is unencrypted. + + + The bitrate can be adjusted at any point in time. To avoid congestion, + the average bitrate SHOULD NOT exceed the available + network bandwidth. If no target bitrate is specified, the bitrates specified in + are RECOMMENDED. + + +
    + +
    + + + Opus can, as described in , + be operated with a variable bitrate. In that case, the encoder will + automatically reduce the bitrate for certain input signals, like periods + of silence. When using continuous transmission, it will reduce the + bitrate when the characteristics of the input signal permit, but + will never interrupt the transmission to the receiver. Therefore, the + received signal will maintain the same high level of audio quality over the + full duration of a transmission while minimizing the average bit + rate over time. + + + + In cases where the bitrate of Opus needs to be reduced even + further or in cases where only constant bitrate is available, + the Opus encoder can use discontinuous + transmission (DTX), where parts of the encoded signal that + correspond to periods of silence in the input speech or audio signal + are not transmitted to the receiver. A receiver can distinguish + between DTX and packet loss by looking for gaps in the sequence + number, as described by Section 4.1 + of . + + + + On the receiving side, the non-transmitted parts will be handled by a + frame loss concealment unit in the Opus decoder which generates a + comfort noise signal to replace the non transmitted parts of the + speech or audio signal. Use of Comfort + Noise (CN) with Opus is discouraged. + The transmitter MUST drop whole frames only, + based on the size of the last transmitted frame, + to ensure successive RTP timestamps differ by a multiple of 120 and + to allow the receiver to use whole frames for concealment. + + + + DTX can be used with both variable and constant bitrate. + It will have a slightly lower speech or audio + quality than continuous transmission. Therefore, using continuous + transmission is RECOMMENDED unless constraints on available network bandwidth + are severe. + + +
    + +
    + +
    + + + Complexity of the encoder can be scaled to optimize for CPU resources in real-time, mostly as + a trade-off between audio quality and bitrate. Also, different modes of Opus have different complexity. + + +
    + +
    + + + The voice mode of Opus allows for embedding "in-band" forward error correction (FEC) + data into the Opus bit stream. This FEC scheme adds + redundant information about the previous packet (N-1) to the current + output packet N. For + each frame, the encoder decides whether to use FEC based on (1) an + externally-provided estimate of the channel's packet loss rate; (2) an + externally-provided estimate of the channel's capacity; (3) the + sensitivity of the audio or speech signal to packet loss; (4) whether + the receiving decoder has indicated it can take advantage of "in-band" + FEC information. The decision to send "in-band" FEC information is + entirely controlled by the encoder and therefore no special precautions + for the payload have to be taken. + + + + On the receiving side, the decoder can take advantage of this + additional information when it loses a packet and the next packet + is available. In order to use the FEC data, the jitter buffer needs + to provide access to payloads with the FEC data. + Instead of performing loss concealment for a missing packet, the + receiver can then configure its decoder to decode the FEC data from the next packet. + + + + Any compliant Opus decoder is capable of ignoring + FEC information when it is not needed, so encoding with FEC cannot cause + interoperability problems. + However, if FEC cannot be used on the receiving side, then FEC + SHOULD NOT be used, as it leads to an inefficient usage of network + resources. Decoder support for FEC SHOULD be indicated at the time a + session is set up. + + +
    + +
    + + + Opus allows for transmission of stereo audio signals. This operation + is signaled in-band in the Opus bit-stream and no special arrangement + is needed in the payload format. An + Opus decoder is capable of handling a stereo encoding, but an + application might only be capable of consuming a single audio + channel. + + + If a decoder cannot take advantage of the benefits of a stereo signal + this SHOULD be indicated at the time a session is set up. In that case + the sending side SHOULD NOT send stereo signals as it leads to an + inefficient usage of network resources. + + +
    + +
    + +
    + The payload format for Opus consists of the RTP header and Opus payload + data. +
    + The format of the RTP header is specified in . + The use of the fields of the RTP header by the Opus payload format is + consistent with that specification. + + The payload length of Opus is an integer number of octets and + therefore no padding is necessary. The payload MAY be padded by an + integer number of octets according to , + although the Opus internal padding is preferred. + + The timestamp, sequence number, and marker bit (M) of the RTP header + are used in accordance with Section 4.1 + of . + + The RTP payload type for Opus is to be assigned dynamically. + + The receiving side MUST be prepared to receive duplicate RTP + packets. The receiver MUST provide at most one of those payloads to the + Opus decoder for decoding, and MUST discard the others. + + Opus supports 5 different audio bandwidths, which can be adjusted during + a stream. + The RTP timestamp is incremented with a 48000 Hz clock rate + for all modes of Opus and all sampling rates. + The unit + for the timestamp is samples per single (mono) channel. The RTP timestamp corresponds to the + sample time of the first encoded sample in the encoded frame. + For data encoded with sampling rates other than 48000 Hz, + the sampling rate has to be adjusted to 48000 Hz. + +
    + +
    + + The Opus encoder can output encoded frames representing 2.5, 5, 10, 20, + 40, or 60 ms of speech or audio data. Further, an arbitrary number of frames can be + combined into a packet, up to a maximum packet duration representing + 120 ms of speech or audio data. The grouping of one or more Opus + frames into a single Opus packet is defined in Section 3 of + . An RTP payload MUST contain exactly one + Opus packet as defined by that document. + + + shows the structure combined with the RTP header. + +
    + + + +
    + + + shows supported frame sizes in + milliseconds of encoded speech or audio data for the speech and audio modes + (Mode) and sampling rates (fs) of Opus and shows how the timestamp is + incremented for packetization (ts incr). If the Opus encoder + outputs multiple encoded frames into a single packet, the timestamp + increment is the sum of the increments for the individual frames. + + + + Mode + fs + 2.5 + 5 + 10 + 20 + 40 + 60 + ts incr + all + 120 + 240 + 480 + 960 + 1920 + 2880 + voice + NB/MB/WB/SWB/FB + x + x + o + o + o + o + audio + NB/WB/SWB/FB + o + o + o + o + x + x + + +
    + +
    + +
    + + The target bitrate of Opus can be adjusted at any point in time, thus + allowing efficient congestion control. Furthermore, the amount + of encoded speech or audio data encoded in a + single packet can be used for congestion control, since the transmission + rate is inversely proportional to the packet duration. A lower packet + transmission rate reduces the amount of header overhead, but at the same + time increases latency and loss sensitivity, so it ought to be used with + care. + + Since UDP does not provide congestion control, applications that use + RTP over UDP SHOULD implement their own congestion control above the + UDP layer . Work in the rmcat working group + describes the + interactions and conceptual interfaces necessary between the application + components that relate to congestion control, including the RTP layer, + the higher-level media codec control layer, and the lower-level + transport interface, as well as components dedicated to congestion + control functions. +
    + +
    + One media subtype (audio/opus) has been defined and registered as + described in the following section. + +
    + Media type registration is done according to and . + + Type name: audio + Subtype name: opus + + Required parameters: + + the RTP timestamp is incremented with a + 48000 Hz clock rate for all modes of Opus and all sampling + rates. For data encoded with sampling rates other than 48000 Hz, + the sampling rate has to be adjusted to 48000 Hz. + + + + Optional parameters: + + + + a hint about the maximum output sampling rate that the receiver is + capable of rendering in Hz. + The decoder MUST be capable of decoding + any audio bandwidth but due to hardware limitations only signals + up to the specified sampling rate can be played back. Sending signals + with higher audio bandwidth results in higher than necessary network + usage and encoding complexity, so an encoder SHOULD NOT encode + frequencies above the audio bandwidth specified by maxplaybackrate. + This parameter can take any value between 8000 and 48000, although + commonly the value will match one of the Opus bandwidths + (). + By default, the receiver is assumed to have no limitations, i.e. 48000. + + + + + a hint about the maximum input sampling rate that the sender is likely to produce. + This is not a guarantee that the sender will never send any higher bandwidth + (e.g. it could send a pre-recorded prompt that uses a higher bandwidth), but it + indicates to the receiver that frequencies above this maximum can safely be discarded. + This parameter is useful to avoid wasting receiver resources by operating the audio + processing pipeline (e.g. echo cancellation) at a higher rate than necessary. + This parameter can take any value between 8000 and 48000, although + commonly the value will match one of the Opus bandwidths + (). + By default, the sender is assumed to have no limitations, i.e. 48000. + + + + the maximum duration of media represented + by a packet (according to Section 6 of + ) that a decoder wants to receive, in + milliseconds rounded up to the next full integer value. + Possible values are 3, 5, 10, 20, 40, 60, or an arbitrary + multiple of an Opus frame size rounded up to the next full integer + value, up to a maximum value of 120, as + defined in . If no value is + specified, the default is 120. + + + the preferred duration of media represented + by a packet (according to Section 6 of + ) that a decoder wants to receive, in + milliseconds rounded up to the next full integer value. + Possible values are 3, 5, 10, 20, 40, 60, or an arbitrary + multiple of an Opus frame size rounded up to the next full integer + value, up to a maximum value of 120, as defined in . If no value is + specified, the default is 20. + + + specifies the maximum average + receive bitrate of a session in bits per second (b/s). The actual + value of the bitrate can vary, as it is dependent on the + characteristics of the media in a packet. Note that the maximum + average bitrate MAY be modified dynamically during a session. Any + positive integer is allowed, but values outside the range + 6000 to 510000 SHOULD be ignored. If no value is specified, the + maximum value specified in + for the corresponding mode of Opus and corresponding maxplaybackrate + is the default. + + + specifies whether the decoder prefers receiving stereo or mono signals. + Possible values are 1 and 0 where 1 specifies that stereo signals are preferred, + and 0 specifies that only mono signals are preferred. + Independent of the stereo parameter every receiver MUST be able to receive and + decode stereo signals but sending stereo signals to a receiver that signaled a + preference for mono signals may result in higher than necessary network + utilization and encoding complexity. If no value is specified, + the default is 0 (mono). + + + + specifies whether the sender is likely to produce stereo audio. + Possible values are 1 and 0, where 1 specifies that stereo signals are likely to + be sent, and 0 specifies that the sender will likely only send mono. + This is not a guarantee that the sender will never send stereo audio + (e.g. it could send a pre-recorded prompt that uses stereo), but it + indicates to the receiver that the received signal can be safely downmixed to mono. + This parameter is useful to avoid wasting receiver resources by operating the audio + processing pipeline (e.g. echo cancellation) in stereo when not necessary. + If no value is specified, the default is 0 + (mono). + + + + specifies if the decoder prefers the use of a constant bitrate versus + variable bitrate. Possible values are 1 and 0, where 1 specifies constant + bitrate and 0 specifies variable bitrate. If no value is specified, + the default is 0 (vbr). When cbr is 1, the maximum average bitrate can still + change, e.g. to adapt to changing network conditions. + + + specifies that the decoder has the capability to + take advantage of the Opus in-band FEC. Possible values are 1 and 0. + Providing 0 when FEC cannot be used on the receiving side is + RECOMMENDED. If no + value is specified, useinbandfec is assumed to be 0. + This parameter is only a preference and the receiver MUST be able to process + packets that include FEC information, even if it means the FEC part is discarded. + + + specifies if the decoder prefers the use of + DTX. Possible values are 1 and 0. If no value is specified, the + default is 0. + + + Encoding considerations: + + The Opus media type is framed and consists of binary data according + to Section 4.8 in . + + + Security considerations: + + See of this document. + + + Interoperability considerations: none + Published specification: RFC [XXXX] + Note to the RFC Editor: Replace [XXXX] with the number of the published + RFC. + + Applications that use this media type: + + Any application that requires the transport of + speech or audio data can use this media type. Some examples are, + but not limited to, audio and video conferencing, Voice over IP, + media streaming. + + + Fragment identifier considerations: N/A + + Person & email address to contact for further information: + + SILK Support silksupport@skype.net + Jean-Marc Valin jmvalin@jmvalin.ca + + + Intended usage: COMMON + + Restrictions on usage: + + + For transfer over RTP, the RTP payload format ( of this document) SHALL be + used. + + + Author: + + Julian Spittka jspittka@gmail.com + Koen Vos koenvos74@gmail.com + Jean-Marc Valin jmvalin@jmvalin.ca + + + Change controller: IETF Payload Working Group delegated from the IESG +
    +
    + +
    + The information described in the media type specification has a + specific mapping to fields in the Session Description Protocol (SDP) + , which is commonly used to describe RTP + sessions. When SDP is used to specify sessions employing Opus, + the mapping is as follows: + + + + The media type ("audio") goes in SDP "m=" as the media name. + + The media subtype ("opus") goes in SDP "a=rtpmap" as the encoding + name. The RTP clock rate in "a=rtpmap" MUST be 48000 and the number of + channels MUST be 2. + + The OPTIONAL media type parameters "ptime" and "maxptime" are + mapped to "a=ptime" and "a=maxptime" attributes, respectively, in the + SDP. + + The OPTIONAL media type parameters "maxaveragebitrate", + "maxplaybackrate", "stereo", "cbr", "useinbandfec", and + "usedtx", when present, MUST be included in the "a=fmtp" attribute + in the SDP, expressed as a media type string in the form of a + semicolon-separated list of parameter=value pairs (e.g., + maxplaybackrate=48000). They MUST NOT be specified in an + SSRC-specific "fmtp" source-level attribute (as defined in + Section 6.3 of ). + + The OPTIONAL media type parameters "sprop-maxcapturerate", + and "sprop-stereo" MAY be mapped to the "a=fmtp" SDP attribute by + copying them directly from the media type parameter string as part + of the semicolon-separated list of parameter=value pairs (e.g., + sprop-stereo=1). These same OPTIONAL media type parameters MAY also + be specified using an SSRC-specific "fmtp" source-level attribute + as described in Section 6.3 of . + They MAY be specified in both places, in which case the parameter + in the source-level attribute overrides the one found on the + "a=fmtp" line. The value of any parameter which is not specified in + a source-level source attribute MUST be taken from the "a=fmtp" + line, if it is present there. + + + + + Below are some examples of SDP session descriptions for Opus: + + Example 1: Standard mono session with 48000 Hz clock rate +
    + + + +
    + + + Example 2: 16000 Hz clock rate, maximum packet size of 40 ms, + recommended packet size of 40 ms, maximum average bitrate of 20000 bps, + prefers to receive stereo but only plans to send mono, FEC is desired, + DTX is not desired + +
    + + + +
    + + Example 3: Two-way full-band stereo preferred + +
    + + + +
    + + +
    + + When using the offer-answer procedure described in to negotiate the use of Opus, the following + considerations apply: + + + + Opus supports several clock rates. For signaling purposes only + the highest, i.e. 48000, is used. The actual clock rate of the + corresponding media is signaled inside the payload and is not + restricted by this payload format description. The decoder MUST be + capable of decoding every received clock rate. An example + is shown below: + +
    + + + +
    +
    + + The "ptime" and "maxptime" parameters are unidirectional + receive-only parameters and typically will not compromise + interoperability; however, some values might cause application + performance to suffer. defines the SDP offer-answer handling of the + "ptime" parameter. The "maxptime" parameter MUST be handled in the + same way. + + + The "maxplaybackrate" parameter is a unidirectional receive-only + parameter that reflects limitations of the local receiver. When + sending to a single destination, a sender MUST NOT use an audio + bandwidth higher than necessary to make full use of audio sampled at + a sampling rate of "maxplaybackrate". Gateways or senders that + are sending the same encoded audio to multiple destinations + SHOULD NOT use an audio bandwidth higher than necessary to + represent audio sampled at "maxplaybackrate", as this would lead + to inefficient use of network resources. + The "maxplaybackrate" parameter does not + affect interoperability. Also, this parameter SHOULD NOT be used + to adjust the audio bandwidth as a function of the bitrate, as this + is the responsibility of the Opus encoder implementation. + + + The "maxaveragebitrate" parameter is a unidirectional receive-only + parameter that reflects limitations of the local receiver. The sender + of the other side MUST NOT send with an average bitrate higher than + "maxaveragebitrate" as it might overload the network and/or + receiver. The "maxaveragebitrate" parameter typically will not + compromise interoperability; however, some values might cause + application performance to suffer, and ought to be set with + care. + + The "sprop-maxcapturerate" and "sprop-stereo" parameters are + unidirectional sender-only parameters that reflect limitations of + the sender side. + They allow the receiver to set up a reduced-complexity audio + processing pipeline if the sender is not planning to use the full + range of Opus's capabilities. + Neither "sprop-maxcapturerate" nor "sprop-stereo" affect + interoperability and the receiver MUST be capable of receiving any signal. + + + + The "stereo" parameter is a unidirectional receive-only + parameter. When sending to a single destination, a sender MUST + NOT use stereo when "stereo" is 0. Gateways or senders that are + sending the same encoded audio to multiple destinations SHOULD + NOT use stereo when "stereo" is 0, as this would lead to + inefficient use of network resources. The "stereo" parameter does + not affect interoperability. + + + + The "cbr" parameter is a unidirectional receive-only + parameter. + + + The "useinbandfec" parameter is a unidirectional receive-only + parameter. + + The "usedtx" parameter is a unidirectional receive-only + parameter. + + Any unknown parameter in an offer MUST be ignored by the receiver + and MUST be removed from the answer. + +
    + + + The Opus parameters in an SDP Offer/Answer exchange are completely + orthogonal, and there is no relationship between the SDP Offer and + the Answer. + +
    + +
    + + For declarative use of SDP such as in Session Announcement Protocol + (SAP), , and RTSP, , for + Opus, the following needs to be considered: + + + + The values for "maxptime", "ptime", "maxplaybackrate", and + "maxaveragebitrate" ought to be selected carefully to ensure that a + reasonable performance can be achieved for the participants of a session. + + + The values for "maxptime", "ptime", and of the payload + format configuration are recommendations by the decoding side to ensure + the best performance for the decoder. + + + All other parameters of the payload format configuration are declarative + and a participant MUST use the configurations that are provided for + the session. More than one configuration can be provided if necessary + by declaring multiple RTP payload types; however, the number of types + ought to be kept small. + +
    +
    + +
    + + Use of variable bitrate (VBR) is subject to the security considerations in + . + + RTP packets using the payload format defined in this specification + are subject to the security considerations discussed in the RTP + specification , and in any applicable RTP profile such as + RTP/AVP , RTP/AVPF , + RTP/SAVP or RTP/SAVPF . + However, as "Securing the RTP Protocol Framework: + Why RTP Does Not Mandate a Single Media Security Solution" + discusses, it is not an RTP payload + format's responsibility to discuss or mandate what solutions are used + to meet the basic security goals like confidentiality, integrity and + source authenticity for RTP in general. This responsibility lays on + anyone using RTP in an application. They can find guidance on + available security mechanisms and important considerations in Options + for Securing RTP Sessions [I-D.ietf-avtcore-rtp-security-options]. + Applications SHOULD use one or more appropriate strong security + mechanisms. + + This payload format and the Opus encoding do not exhibit any + significant non-uniformity in the receiver-end computational load and thus + are unlikely to pose a denial-of-service threat due to the receipt of + pathological datagrams. +
    + +
    + Many people have made useful comments and suggestions contributing to this document. + In particular, we would like to thank + Tina le Grand, Cullen Jennings, Jonathan Lennox, Gregory Maxwell, Colin Perkins, Jan Skoglund, + Timothy B. Terriberry, Martin Thompson, Justin Uberti, Magnus Westerlund, and Mo Zanaty. +
    +
    + + + + &rfc2119; + &rfc3389; + &rfc3550; + &rfc3711; + &rfc3551; + &rfc6838; + &rfc4855; + &rfc4566; + &rfc3264; + &rfc2326; + &rfc5576; + &rfc6562; + &rfc6716; + + + + &rfc2974; + &rfc4585; + &rfc5124; + &rfc5405; + &rfc7202; + + + + rmcat documents + + + + + + + + + + + +
    diff --git a/extern/opus/doc/footer.html b/extern/opus/doc/footer.html new file mode 100644 index 0000000..ad4a925 --- /dev/null +++ b/extern/opus/doc/footer.html @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + +
    +For more information visit the Opus Website. + + +
    + + + diff --git a/extern/opus/doc/header.html b/extern/opus/doc/header.html new file mode 100644 index 0000000..b2c906b --- /dev/null +++ b/extern/opus/doc/header.html @@ -0,0 +1,54 @@ + + + + + +$projectname: $title +$title + + +$treeview +$search +$mathjax + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + +
    +
    Opus
    +
    + + +
    +
    $projectbrief
    +
    $projectnumber +
    +
    +
    $projectbrief
    +
    $searchbox
    +
    + diff --git a/extern/opus/doc/opus_in_isobmff.css b/extern/opus/doc/opus_in_isobmff.css new file mode 100644 index 0000000..bffe8f4 --- /dev/null +++ b/extern/opus/doc/opus_in_isobmff.css @@ -0,0 +1,60 @@ +/* Normal links */ +.normal_link a:link +{ + color : yellow; +} +.normal_link a:visited +{ + color : green; +} + +/* Boxes */ +.pre +{ + white-space: pre; /* CSS 2.0 */ + white-space: pre-wrap; /* CSS 2.1 */ + white-space: -pre-wrap; /* Opera 4-6 */ + white-space: -o-pre-wrap; /* Opera 7 */ + white-space: -moz-pre-wrap; /* Mozilla */ + white-space: -hp-pre-wrap; /* HP Printers */ + word-wrap : break-word; /* IE 5+ */ +} + +.title_box +{ + width : 470px; + height : 70px; + margin : 2px 50px 2px 2px; + padding : 10px; + border : 1px solid black; + background-color : #666666; + white-space : pre; + float : left; + text-align : center; + color : #C0C0C0; + font-size : 50pt; + font-style : italic; +} + +.subindex_box +{ + margin : 5px; + padding : 14px 22px; + border : 1px solid black; + background-color : #778877; + float : left; + text-align : center; + color : #115555; + font-size : 32pt; +} + +.frame_box +{ + margin : 10px; + padding : 10px; + border : 0px; + background-color : #084040; + text-align : left; + color : #C0C0C0; + font-family : monospace; +} diff --git a/extern/opus/doc/opus_in_isobmff.html b/extern/opus/doc/opus_in_isobmff.html new file mode 100644 index 0000000..38aefbf --- /dev/null +++ b/extern/opus/doc/opus_in_isobmff.html @@ -0,0 +1,692 @@ + + + + + + Encapsulation of Opus in ISO Base Media File Format + + + Encapsulation of Opus in ISO Base Media File Format
    + last updated: August 28, 2018
    +
    + + + diff --git a/extern/opus/doc/opus_logo.svg b/extern/opus/doc/opus_logo.svg new file mode 100644 index 0000000..db2879e --- /dev/null +++ b/extern/opus/doc/opus_logo.svg @@ -0,0 +1,157 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/extern/opus/doc/opus_update.patch b/extern/opus/doc/opus_update.patch new file mode 100644 index 0000000..11f066c --- /dev/null +++ b/extern/opus/doc/opus_update.patch @@ -0,0 +1,244 @@ +diff --git a/celt/bands.c b/celt/bands.c +index 6962587..32e1de6 100644 +--- a/celt/bands.c ++++ b/celt/bands.c +@@ -1234,9 +1234,23 @@ void quant_all_bands(int encode, const CELTMode *m, int start, int end, + b = 0; + } + +- if (resynth && M*eBands[i]-N >= M*eBands[start] && (update_lowband || lowband_offset==0)) ++ if (resynth && (M*eBands[i]-N >= M*eBands[start] || i==start+1) && (update_lowband || lowband_offset==0)) + lowband_offset = i; + ++ if (i == start+1) ++ { ++ int n1, n2; ++ int offset; ++ n1 = M*(eBands[start+1]-eBands[start]); ++ n2 = M*(eBands[start+2]-eBands[start+1]); ++ offset = M*eBands[start]; ++ /* Duplicate enough of the first band folding data to be able to fold the second band. ++ Copies no data for CELT-only mode. */ ++ OPUS_COPY(&norm[offset+n1], &norm[offset+2*n1 - n2], n2-n1); ++ if (C==2) ++ OPUS_COPY(&norm2[offset+n1], &norm2[offset+2*n1 - n2], n2-n1); ++ } ++ + tf_change = tf_res[i]; + if (i>=m->effEBands) + { +@@ -1257,7 +1271,7 @@ void quant_all_bands(int encode, const CELTMode *m, int start, int end, + fold_start = lowband_offset; + while(M*eBands[--fold_start] > effective_lowband); + fold_end = lowband_offset-1; +- while(M*eBands[++fold_end] < effective_lowband+N); ++ while(++fold_end < i && M*eBands[fold_end] < effective_lowband+N); + x_cm = y_cm = 0; + fold_i = fold_start; do { + x_cm |= collapse_masks[fold_i*C+0]; +diff --git a/celt/quant_bands.c b/celt/quant_bands.c +index e5ed9ef..82fb823 100644 +--- a/celt/quant_bands.c ++++ b/celt/quant_bands.c +@@ -552,6 +552,7 @@ void log2Amp(const CELTMode *m, int start, int end, + { + opus_val16 lg = ADD16(oldEBands[i+c*m->nbEBands], + SHL16((opus_val16)eMeans[i],6)); ++ lg = MIN32(QCONST32(32.f, 16), lg); + eBands[i+c*m->nbEBands] = PSHR32(celt_exp2(lg),4); + } + for (;inbEBands;i++) +diff --git a/silk/LPC_inv_pred_gain.c b/silk/LPC_inv_pred_gain.c +index 60c439b..6c301da 100644 +--- a/silk/LPC_inv_pred_gain.c ++++ b/silk/LPC_inv_pred_gain.c +@@ -84,8 +84,13 @@ static opus_int32 LPC_inverse_pred_gain_QA( /* O Returns inver + + /* Update AR coefficient */ + for( n = 0; n < k; n++ ) { +- tmp_QA = Aold_QA[ n ] - MUL32_FRAC_Q( Aold_QA[ k - n - 1 ], rc_Q31, 31 ); +- Anew_QA[ n ] = MUL32_FRAC_Q( tmp_QA, rc_mult2 , mult2Q ); ++ opus_int64 tmp64; ++ tmp_QA = silk_SUB_SAT32( Aold_QA[ n ], MUL32_FRAC_Q( Aold_QA[ k - n - 1 ], rc_Q31, 31 ) ); ++ tmp64 = silk_RSHIFT_ROUND64( silk_SMULL( tmp_QA, rc_mult2 ), mult2Q); ++ if( tmp64 > silk_int32_MAX || tmp64 < silk_int32_MIN ) { ++ return 0; ++ } ++ Anew_QA[ n ] = ( opus_int32 )tmp64; + } + } + +diff --git a/silk/NLSF_stabilize.c b/silk/NLSF_stabilize.c +index 979aaba..2ef2398 100644 +--- a/silk/NLSF_stabilize.c ++++ b/silk/NLSF_stabilize.c +@@ -134,7 +134,7 @@ void silk_NLSF_stabilize( + + /* Keep delta_min distance between the NLSFs */ + for( i = 1; i < L; i++ ) +- NLSF_Q15[i] = silk_max_int( NLSF_Q15[i], NLSF_Q15[i-1] + NDeltaMin_Q15[i] ); ++ NLSF_Q15[i] = silk_max_int( NLSF_Q15[i], silk_ADD_SAT16( NLSF_Q15[i-1], NDeltaMin_Q15[i] ) ); + + /* Last NLSF should be no higher than 1 - NDeltaMin[L] */ + NLSF_Q15[L-1] = silk_min_int( NLSF_Q15[L-1], (1<<15) - NDeltaMin_Q15[L] ); +diff --git a/silk/dec_API.c b/silk/dec_API.c +index efd7918..21bb7e0 100644 +--- a/silk/dec_API.c ++++ b/silk/dec_API.c +@@ -72,6 +72,9 @@ opus_int silk_InitDecoder( /* O Returns error co + for( n = 0; n < DECODER_NUM_CHANNELS; n++ ) { + ret = silk_init_decoder( &channel_state[ n ] ); + } ++ silk_memset(&((silk_decoder *)decState)->sStereo, 0, sizeof(((silk_decoder *)decState)->sStereo)); ++ /* Not strictly needed, but it's cleaner that way */ ++ ((silk_decoder *)decState)->prev_decode_only_middle = 0; + + return ret; + } +diff --git a/silk/resampler_private_IIR_FIR.c b/silk/resampler_private_IIR_FIR.c +index dbd6d9a..91a43aa 100644 +--- a/silk/resampler_private_IIR_FIR.c ++++ b/silk/resampler_private_IIR_FIR.c +@@ -75,10 +75,10 @@ void silk_resampler_private_IIR_FIR( + silk_resampler_state_struct *S = (silk_resampler_state_struct *)SS; + opus_int32 nSamplesIn; + opus_int32 max_index_Q16, index_increment_Q16; +- opus_int16 buf[ RESAMPLER_MAX_BATCH_SIZE_IN + RESAMPLER_ORDER_FIR_12 ]; ++ opus_int16 buf[ 2*RESAMPLER_MAX_BATCH_SIZE_IN + RESAMPLER_ORDER_FIR_12 ]; + + /* Copy buffered samples to start of buffer */ +- silk_memcpy( buf, S->sFIR, RESAMPLER_ORDER_FIR_12 * sizeof( opus_int32 ) ); ++ silk_memcpy( buf, S->sFIR, RESAMPLER_ORDER_FIR_12 * sizeof( opus_int16 ) ); + + /* Iterate over blocks of frameSizeIn input samples */ + index_increment_Q16 = S->invRatio_Q16; +@@ -95,13 +95,13 @@ void silk_resampler_private_IIR_FIR( + + if( inLen > 0 ) { + /* More iterations to do; copy last part of filtered signal to beginning of buffer */ +- silk_memcpy( buf, &buf[ nSamplesIn << 1 ], RESAMPLER_ORDER_FIR_12 * sizeof( opus_int32 ) ); ++ silk_memmove( buf, &buf[ nSamplesIn << 1 ], RESAMPLER_ORDER_FIR_12 * sizeof( opus_int16 ) ); + } else { + break; + } + } + + /* Copy last part of filtered signal to the state for the next call */ +- silk_memcpy( S->sFIR, &buf[ nSamplesIn << 1 ], RESAMPLER_ORDER_FIR_12 * sizeof( opus_int32 ) ); ++ silk_memcpy( S->sFIR, &buf[ nSamplesIn << 1 ], RESAMPLER_ORDER_FIR_12 * sizeof( opus_int16 ) ); + } + +diff --git a/src/opus_decoder.c b/src/opus_decoder.c +index 0cc56f8..8a30fbc 100644 +--- a/src/opus_decoder.c ++++ b/src/opus_decoder.c +@@ -595,16 +595,14 @@ static int opus_packet_parse_impl(const unsigned char *data, int len, + /* Padding flag is bit 6 */ + if (ch&0x40) + { +- int padding=0; + int p; + do { + if (len<=0) + return OPUS_INVALID_PACKET; + p = *data++; + len--; +- padding += p==255 ? 254: p; ++ len -= p==255 ? 254: p; + } while (p==255); +- len -= padding; + } + if (len<0) + return OPUS_INVALID_PACKET; +diff --git a/run_vectors.sh b/run_vectors.sh +index 7cd23ed..4841b0a 100755 +--- a/run_vectors.sh ++++ b/run_vectors.sh +@@ -1,3 +1,5 @@ ++#!/bin/sh ++# + # Copyright (c) 2011-2012 IETF Trust, Jean-Marc Valin. All rights reserved. + # + # This file is extracted from RFC6716. Please see that RFC for additional +@@ -31,10 +33,8 @@ + # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +-#!/bin/sh +- +-rm logs_mono.txt +-rm logs_stereo.txt ++rm -f logs_mono.txt logs_mono2.txt ++rm -f logs_stereo.txt logs_stereo2.txt + + if [ "$#" -ne "3" ]; then + echo "usage: run_vectors.sh " +@@ -45,18 +45,23 @@ CMD_PATH=$1 + VECTOR_PATH=$2 + RATE=$3 + +-OPUS_DEMO=$CMD_PATH/opus_demo +-OPUS_COMPARE=$CMD_PATH/opus_compare ++: ${OPUS_DEMO:=$CMD_PATH/opus_demo} ++: ${OPUS_COMPARE:=$CMD_PATH/opus_compare} + + if [ -d $VECTOR_PATH ]; then + echo Test vectors found in $VECTOR_PATH + else + echo No test vectors found +- #Don't make the test fail here because the test vectors will be +- #distributed separately ++ #Don't make the test fail here because the test vectors ++ #will be distributed separately + exit 0 + fi + ++if [ ! -x $OPUS_COMPARE ]; then ++ echo ERROR: Compare program not found: $OPUS_COMPARE ++ exit 1 ++fi ++ + if [ -x $OPUS_DEMO ]; then + echo Decoding with $OPUS_DEMO + else +@@ -82,9 +87,11 @@ do + echo ERROR: decoding failed + exit 1 + fi +- $OPUS_COMPARE -r $RATE $VECTOR_PATH/testvector$file.dec tmp.out >> logs_mono.txt 2>&1 ++ $OPUS_COMPARE -r $RATE $VECTOR_PATH/testvector${file}.dec tmp.out >> logs_mono.txt 2>&1 + float_ret=$? +- if [ "$float_ret" -eq "0" ]; then ++ $OPUS_COMPARE -r $RATE $VECTOR_PATH/testvector${file}m.dec tmp.out >> logs_mono2.txt 2>&1 ++ float_ret2=$? ++ if [ "$float_ret" -eq "0" ] || [ "$float_ret2" -eq "0" ]; then + echo output matches reference + else + echo ERROR: output does not match reference +@@ -111,9 +118,11 @@ do + echo ERROR: decoding failed + exit 1 + fi +- $OPUS_COMPARE -s -r $RATE $VECTOR_PATH/testvector$file.dec tmp.out >> logs_stereo.txt 2>&1 ++ $OPUS_COMPARE -s -r $RATE $VECTOR_PATH/testvector${file}.dec tmp.out >> logs_stereo.txt 2>&1 + float_ret=$? +- if [ "$float_ret" -eq "0" ]; then ++ $OPUS_COMPARE -s -r $RATE $VECTOR_PATH/testvector${file}m.dec tmp.out >> logs_stereo2.txt 2>&1 ++ float_ret2=$? ++ if [ "$float_ret" -eq "0" ] || [ "$float_ret2" -eq "0" ]; then + echo output matches reference + else + echo ERROR: output does not match reference +@@ -125,5 +134,10 @@ done + + + echo All tests have passed successfully +-grep quality logs_mono.txt | awk '{sum+=$4}END{print "Average mono quality is", sum/NR, "%"}' +-grep quality logs_stereo.txt | awk '{sum+=$4}END{print "Average stereo quality is", sum/NR, "%"}' ++mono1=`grep quality logs_mono.txt | awk '{sum+=$4}END{if (NR == 12) sum /= 12; else sum = 0; print sum}'` ++mono2=`grep quality logs_mono2.txt | awk '{sum+=$4}END{if (NR == 12) sum /= 12; else sum = 0; print sum}'` ++echo $mono1 $mono2 | awk '{if ($2 > $1) $1 = $2; print "Average mono quality is", $1, "%"}' ++ ++stereo1=`grep quality logs_stereo.txt | awk '{sum+=$4}END{if (NR == 12) sum /= 12; else sum = 0; print sum}'` ++stereo2=`grep quality logs_stereo2.txt | awk '{sum+=$4}END{if (NR == 12) sum /= 12; else sum = 0; print sum}'` ++echo $stereo1 $stereo2 | awk '{if ($2 > $1) $1 = $2; print "Average stereo quality is", $1, "%"}' diff --git a/extern/opus/doc/release.txt b/extern/opus/doc/release.txt new file mode 100644 index 0000000..6d3ffa2 --- /dev/null +++ b/extern/opus/doc/release.txt @@ -0,0 +1,43 @@ += Release checklist = + +== Source release == + +- Check for uncommitted changes to master. +- Update OPUS_LT_* API versioning in configure.ac. +- Tag the release commit with 'git tag -s vN.M'. + - Include release notes in the tag annotation. +- Verify 'make distcheck' produces a tarball with + the desired name. +- Push tag to public repo. +- Upload source package 'opus-${version}.tar.gz' + - Add to https://svn.xiph.org/releases/opus/ + - Update checksum files + - svn commit + - Copy to archive.mozilla.org/pub/opus/ + - Update checksum files there as well. +- Add release notes to https://git.xiph.org/opus-website.git +- Update links and checksums on the downloads page. +- Add a copy of the documentation to + and update the links. +- Update /topic in #opus IRC channel. + +Releases are commited to https://svn.xiph.org/releases/opus/ +which propagates to downloads.xiph.org, and copied manually +to https://archive.mozilla.org/pub/opus/ + +Website updates are committed to https://git.xiph.org/opus-website.git +which propagates to https://opus-codec.org/ + +== Binary release == + +We usually build opus-tools binaries for MacOS and Windows. + +Binary releases are copied manually to +https://archive.mozilla.org/pub/opus/win32/ + +For Mac, submit a pull request to homebrew. + +== Website updates == + +For major releases, recreate the files on https://opus-codec.org/examples/ +with the next encoder. diff --git a/extern/opus/doc/trivial_example.c b/extern/opus/doc/trivial_example.c new file mode 100644 index 0000000..047ca0a --- /dev/null +++ b/extern/opus/doc/trivial_example.c @@ -0,0 +1,160 @@ +/* Copyright (c) 2013 Jean-Marc Valin */ +/* + 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. + + 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 OWNER + 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 is meant to be a simple example of encoding and decoding audio + using Opus. It should make it easy to understand how the Opus API + works. For more information, see the full API documentation at: + https://www.opus-codec.org/docs/ */ + +#include +#include +#include +#include +#include + +/*The frame size is hardcoded for this sample code but it doesn't have to be*/ +#define FRAME_SIZE 960 +#define SAMPLE_RATE 48000 +#define CHANNELS 2 +#define APPLICATION OPUS_APPLICATION_AUDIO +#define BITRATE 64000 + +#define MAX_FRAME_SIZE 6*960 +#define MAX_PACKET_SIZE (3*1276) + +int main(int argc, char **argv) +{ + char *inFile; + FILE *fin; + char *outFile; + FILE *fout; + opus_int16 in[FRAME_SIZE*CHANNELS]; + opus_int16 out[MAX_FRAME_SIZE*CHANNELS]; + unsigned char cbits[MAX_PACKET_SIZE]; + int nbBytes; + /*Holds the state of the encoder and decoder */ + OpusEncoder *encoder; + OpusDecoder *decoder; + int err; + + if (argc != 3) + { + fprintf(stderr, "usage: trivial_example input.pcm output.pcm\n"); + fprintf(stderr, "input and output are 16-bit little-endian raw files\n"); + return EXIT_FAILURE; + } + + /*Create a new encoder state */ + encoder = opus_encoder_create(SAMPLE_RATE, CHANNELS, APPLICATION, &err); + if (err<0) + { + fprintf(stderr, "failed to create an encoder: %s\n", opus_strerror(err)); + return EXIT_FAILURE; + } + /* Set the desired bit-rate. You can also set other parameters if needed. + The Opus library is designed to have good defaults, so only set + parameters you know you need. Doing otherwise is likely to result + in worse quality, but better. */ + err = opus_encoder_ctl(encoder, OPUS_SET_BITRATE(BITRATE)); + if (err<0) + { + fprintf(stderr, "failed to set bitrate: %s\n", opus_strerror(err)); + return EXIT_FAILURE; + } + inFile = argv[1]; + fin = fopen(inFile, "r"); + if (fin==NULL) + { + fprintf(stderr, "failed to open input file: %s\n", strerror(errno)); + return EXIT_FAILURE; + } + + + /* Create a new decoder state. */ + decoder = opus_decoder_create(SAMPLE_RATE, CHANNELS, &err); + if (err<0) + { + fprintf(stderr, "failed to create decoder: %s\n", opus_strerror(err)); + return EXIT_FAILURE; + } + outFile = argv[2]; + fout = fopen(outFile, "w"); + if (fout==NULL) + { + fprintf(stderr, "failed to open output file: %s\n", strerror(errno)); + return EXIT_FAILURE; + } + + while (1) + { + int i; + unsigned char pcm_bytes[MAX_FRAME_SIZE*CHANNELS*2]; + int frame_size; + + /* Read a 16 bits/sample audio frame. */ + fread(pcm_bytes, sizeof(short)*CHANNELS, FRAME_SIZE, fin); + if (feof(fin)) + break; + /* Convert from little-endian ordering. */ + for (i=0;i>8)&0xFF; + } + /* Write the decoded audio to file. */ + fwrite(pcm_bytes, sizeof(short), frame_size*CHANNELS, fout); + } + /*Destroy the encoder state*/ + opus_encoder_destroy(encoder); + opus_decoder_destroy(decoder); + fclose(fin); + fclose(fout); + return EXIT_SUCCESS; +} diff --git a/extern/opus/include/opus.h b/extern/opus/include/opus.h new file mode 100644 index 0000000..d282f21 --- /dev/null +++ b/extern/opus/include/opus.h @@ -0,0 +1,981 @@ +/* Copyright (c) 2010-2011 Xiph.Org Foundation, Skype Limited + Written by Jean-Marc Valin and Koen Vos */ +/* + 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. + + 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 OWNER + 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. +*/ + +/** + * @file opus.h + * @brief Opus reference implementation API + */ + +#ifndef OPUS_H +#define OPUS_H + +#include "opus_types.h" +#include "opus_defines.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @mainpage Opus + * + * The Opus codec is designed for interactive speech and audio transmission over the Internet. + * It is designed by the IETF Codec Working Group and incorporates technology from + * Skype's SILK codec and Xiph.Org's CELT codec. + * + * The Opus codec is designed to handle a wide range of interactive audio applications, + * including Voice over IP, videoconferencing, in-game chat, and even remote live music + * performances. It can scale from low bit-rate narrowband speech to very high quality + * stereo music. Its main features are: + + * @li Sampling rates from 8 to 48 kHz + * @li Bit-rates from 6 kb/s to 510 kb/s + * @li Support for both constant bit-rate (CBR) and variable bit-rate (VBR) + * @li Audio bandwidth from narrowband to full-band + * @li Support for speech and music + * @li Support for mono and stereo + * @li Support for multichannel (up to 255 channels) + * @li Frame sizes from 2.5 ms to 60 ms + * @li Good loss robustness and packet loss concealment (PLC) + * @li Floating point and fixed-point implementation + * + * Documentation sections: + * @li @ref opus_encoder + * @li @ref opus_decoder + * @li @ref opus_repacketizer + * @li @ref opus_multistream + * @li @ref opus_libinfo + * @li @ref opus_custom + */ + +/** @defgroup opus_encoder Opus Encoder + * @{ + * + * @brief This page describes the process and functions used to encode Opus. + * + * Since Opus is a stateful codec, the encoding process starts with creating an encoder + * state. This can be done with: + * + * @code + * int error; + * OpusEncoder *enc; + * enc = opus_encoder_create(Fs, channels, application, &error); + * @endcode + * + * From this point, @c enc can be used for encoding an audio stream. An encoder state + * @b must @b not be used for more than one stream at the same time. Similarly, the encoder + * state @b must @b not be re-initialized for each frame. + * + * While opus_encoder_create() allocates memory for the state, it's also possible + * to initialize pre-allocated memory: + * + * @code + * int size; + * int error; + * OpusEncoder *enc; + * size = opus_encoder_get_size(channels); + * enc = malloc(size); + * error = opus_encoder_init(enc, Fs, channels, application); + * @endcode + * + * where opus_encoder_get_size() returns the required size for the encoder state. Note that + * future versions of this code may change the size, so no assuptions should be made about it. + * + * The encoder state is always continuous in memory and only a shallow copy is sufficient + * to copy it (e.g. memcpy()) + * + * It is possible to change some of the encoder's settings using the opus_encoder_ctl() + * interface. All these settings already default to the recommended value, so they should + * only be changed when necessary. The most common settings one may want to change are: + * + * @code + * opus_encoder_ctl(enc, OPUS_SET_BITRATE(bitrate)); + * opus_encoder_ctl(enc, OPUS_SET_COMPLEXITY(complexity)); + * opus_encoder_ctl(enc, OPUS_SET_SIGNAL(signal_type)); + * @endcode + * + * where + * + * @arg bitrate is in bits per second (b/s) + * @arg complexity is a value from 1 to 10, where 1 is the lowest complexity and 10 is the highest + * @arg signal_type is either OPUS_AUTO (default), OPUS_SIGNAL_VOICE, or OPUS_SIGNAL_MUSIC + * + * See @ref opus_encoderctls and @ref opus_genericctls for a complete list of parameters that can be set or queried. Most parameters can be set or changed at any time during a stream. + * + * To encode a frame, opus_encode() or opus_encode_float() must be called with exactly one frame (2.5, 5, 10, 20, 40 or 60 ms) of audio data: + * @code + * len = opus_encode(enc, audio_frame, frame_size, packet, max_packet); + * @endcode + * + * where + *
      + *
    • audio_frame is the audio data in opus_int16 (or float for opus_encode_float())
    • + *
    • frame_size is the duration of the frame in samples (per channel)
    • + *
    • packet is the byte array to which the compressed data is written
    • + *
    • max_packet is the maximum number of bytes that can be written in the packet (4000 bytes is recommended). + * Do not use max_packet to control VBR target bitrate, instead use the #OPUS_SET_BITRATE CTL.
    • + *
    + * + * opus_encode() and opus_encode_float() return the number of bytes actually written to the packet. + * The return value can be negative, which indicates that an error has occurred. If the return value + * is 2 bytes or less, then the packet does not need to be transmitted (DTX). + * + * Once the encoder state if no longer needed, it can be destroyed with + * + * @code + * opus_encoder_destroy(enc); + * @endcode + * + * If the encoder was created with opus_encoder_init() rather than opus_encoder_create(), + * then no action is required aside from potentially freeing the memory that was manually + * allocated for it (calling free(enc) for the example above) + * + */ + +/** Opus encoder state. + * This contains the complete state of an Opus encoder. + * It is position independent and can be freely copied. + * @see opus_encoder_create,opus_encoder_init + */ +typedef struct OpusEncoder OpusEncoder; + +/** Gets the size of an OpusEncoder structure. + * @param[in] channels int: Number of channels. + * This must be 1 or 2. + * @returns The size in bytes. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_encoder_get_size(int channels); + +/** + */ + +/** Allocates and initializes an encoder state. + * There are three coding modes: + * + * @ref OPUS_APPLICATION_VOIP gives best quality at a given bitrate for voice + * signals. It enhances the input signal by high-pass filtering and + * emphasizing formants and harmonics. Optionally it includes in-band + * forward error correction to protect against packet loss. Use this + * mode for typical VoIP applications. Because of the enhancement, + * even at high bitrates the output may sound different from the input. + * + * @ref OPUS_APPLICATION_AUDIO gives best quality at a given bitrate for most + * non-voice signals like music. Use this mode for music and mixed + * (music/voice) content, broadcast, and applications requiring less + * than 15 ms of coding delay. + * + * @ref OPUS_APPLICATION_RESTRICTED_LOWDELAY configures low-delay mode that + * disables the speech-optimized mode in exchange for slightly reduced delay. + * This mode can only be set on an newly initialized or freshly reset encoder + * because it changes the codec delay. + * + * This is useful when the caller knows that the speech-optimized modes will not be needed (use with caution). + * @param [in] Fs opus_int32: Sampling rate of input signal (Hz) + * This must be one of 8000, 12000, 16000, + * 24000, or 48000. + * @param [in] channels int: Number of channels (1 or 2) in input signal + * @param [in] application int: Coding mode (@ref OPUS_APPLICATION_VOIP/@ref OPUS_APPLICATION_AUDIO/@ref OPUS_APPLICATION_RESTRICTED_LOWDELAY) + * @param [out] error int*: @ref opus_errorcodes + * @note Regardless of the sampling rate and number channels selected, the Opus encoder + * can switch to a lower audio bandwidth or number of channels if the bitrate + * selected is too low. This also means that it is safe to always use 48 kHz stereo input + * and let the encoder optimize the encoding. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT OpusEncoder *opus_encoder_create( + opus_int32 Fs, + int channels, + int application, + int *error +); + +/** Initializes a previously allocated encoder state + * The memory pointed to by st must be at least the size returned by opus_encoder_get_size(). + * This is intended for applications which use their own allocator instead of malloc. + * @see opus_encoder_create(),opus_encoder_get_size() + * To reset a previously initialized state, use the #OPUS_RESET_STATE CTL. + * @param [in] st OpusEncoder*: Encoder state + * @param [in] Fs opus_int32: Sampling rate of input signal (Hz) + * This must be one of 8000, 12000, 16000, + * 24000, or 48000. + * @param [in] channels int: Number of channels (1 or 2) in input signal + * @param [in] application int: Coding mode (OPUS_APPLICATION_VOIP/OPUS_APPLICATION_AUDIO/OPUS_APPLICATION_RESTRICTED_LOWDELAY) + * @retval #OPUS_OK Success or @ref opus_errorcodes + */ +OPUS_EXPORT int opus_encoder_init( + OpusEncoder *st, + opus_int32 Fs, + int channels, + int application +) OPUS_ARG_NONNULL(1); + +/** Encodes an Opus frame. + * @param [in] st OpusEncoder*: Encoder state + * @param [in] pcm opus_int16*: Input signal (interleaved if 2 channels). length is frame_size*channels*sizeof(opus_int16) + * @param [in] frame_size int: Number of samples per channel in the + * input signal. + * This must be an Opus frame size for + * the encoder's sampling rate. + * For example, at 48 kHz the permitted + * values are 120, 240, 480, 960, 1920, + * and 2880. + * Passing in a duration of less than + * 10 ms (480 samples at 48 kHz) will + * prevent the encoder from using the LPC + * or hybrid modes. + * @param [out] data unsigned char*: Output payload. + * This must contain storage for at + * least \a max_data_bytes. + * @param [in] max_data_bytes opus_int32: Size of the allocated + * memory for the output + * payload. This may be + * used to impose an upper limit on + * the instant bitrate, but should + * not be used as the only bitrate + * control. Use #OPUS_SET_BITRATE to + * control the bitrate. + * @returns The length of the encoded packet (in bytes) on success or a + * negative error code (see @ref opus_errorcodes) on failure. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_encode( + OpusEncoder *st, + const opus_int16 *pcm, + int frame_size, + unsigned char *data, + opus_int32 max_data_bytes +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2) OPUS_ARG_NONNULL(4); + +/** Encodes an Opus frame from floating point input. + * @param [in] st OpusEncoder*: Encoder state + * @param [in] pcm float*: Input in float format (interleaved if 2 channels), with a normal range of +/-1.0. + * Samples with a range beyond +/-1.0 are supported but will + * be clipped by decoders using the integer API and should + * only be used if it is known that the far end supports + * extended dynamic range. + * length is frame_size*channels*sizeof(float) + * @param [in] frame_size int: Number of samples per channel in the + * input signal. + * This must be an Opus frame size for + * the encoder's sampling rate. + * For example, at 48 kHz the permitted + * values are 120, 240, 480, 960, 1920, + * and 2880. + * Passing in a duration of less than + * 10 ms (480 samples at 48 kHz) will + * prevent the encoder from using the LPC + * or hybrid modes. + * @param [out] data unsigned char*: Output payload. + * This must contain storage for at + * least \a max_data_bytes. + * @param [in] max_data_bytes opus_int32: Size of the allocated + * memory for the output + * payload. This may be + * used to impose an upper limit on + * the instant bitrate, but should + * not be used as the only bitrate + * control. Use #OPUS_SET_BITRATE to + * control the bitrate. + * @returns The length of the encoded packet (in bytes) on success or a + * negative error code (see @ref opus_errorcodes) on failure. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_encode_float( + OpusEncoder *st, + const float *pcm, + int frame_size, + unsigned char *data, + opus_int32 max_data_bytes +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2) OPUS_ARG_NONNULL(4); + +/** Frees an OpusEncoder allocated by opus_encoder_create(). + * @param[in] st OpusEncoder*: State to be freed. + */ +OPUS_EXPORT void opus_encoder_destroy(OpusEncoder *st); + +/** Perform a CTL function on an Opus encoder. + * + * Generally the request and subsequent arguments are generated + * by a convenience macro. + * @param st OpusEncoder*: Encoder state. + * @param request This and all remaining parameters should be replaced by one + * of the convenience macros in @ref opus_genericctls or + * @ref opus_encoderctls. + * @see opus_genericctls + * @see opus_encoderctls + */ +OPUS_EXPORT int opus_encoder_ctl(OpusEncoder *st, int request, ...) OPUS_ARG_NONNULL(1); +/**@}*/ + +/** @defgroup opus_decoder Opus Decoder + * @{ + * + * @brief This page describes the process and functions used to decode Opus. + * + * The decoding process also starts with creating a decoder + * state. This can be done with: + * @code + * int error; + * OpusDecoder *dec; + * dec = opus_decoder_create(Fs, channels, &error); + * @endcode + * where + * @li Fs is the sampling rate and must be 8000, 12000, 16000, 24000, or 48000 + * @li channels is the number of channels (1 or 2) + * @li error will hold the error code in case of failure (or #OPUS_OK on success) + * @li the return value is a newly created decoder state to be used for decoding + * + * While opus_decoder_create() allocates memory for the state, it's also possible + * to initialize pre-allocated memory: + * @code + * int size; + * int error; + * OpusDecoder *dec; + * size = opus_decoder_get_size(channels); + * dec = malloc(size); + * error = opus_decoder_init(dec, Fs, channels); + * @endcode + * where opus_decoder_get_size() returns the required size for the decoder state. Note that + * future versions of this code may change the size, so no assuptions should be made about it. + * + * The decoder state is always continuous in memory and only a shallow copy is sufficient + * to copy it (e.g. memcpy()) + * + * To decode a frame, opus_decode() or opus_decode_float() must be called with a packet of compressed audio data: + * @code + * frame_size = opus_decode(dec, packet, len, decoded, max_size, 0); + * @endcode + * where + * + * @li packet is the byte array containing the compressed data + * @li len is the exact number of bytes contained in the packet + * @li decoded is the decoded audio data in opus_int16 (or float for opus_decode_float()) + * @li max_size is the max duration of the frame in samples (per channel) that can fit into the decoded_frame array + * + * opus_decode() and opus_decode_float() return the number of samples (per channel) decoded from the packet. + * If that value is negative, then an error has occurred. This can occur if the packet is corrupted or if the audio + * buffer is too small to hold the decoded audio. + * + * Opus is a stateful codec with overlapping blocks and as a result Opus + * packets are not coded independently of each other. Packets must be + * passed into the decoder serially and in the correct order for a correct + * decode. Lost packets can be replaced with loss concealment by calling + * the decoder with a null pointer and zero length for the missing packet. + * + * A single codec state may only be accessed from a single thread at + * a time and any required locking must be performed by the caller. Separate + * streams must be decoded with separate decoder states and can be decoded + * in parallel unless the library was compiled with NONTHREADSAFE_PSEUDOSTACK + * defined. + * + */ + +/** Opus decoder state. + * This contains the complete state of an Opus decoder. + * It is position independent and can be freely copied. + * @see opus_decoder_create,opus_decoder_init + */ +typedef struct OpusDecoder OpusDecoder; + +/** Gets the size of an OpusDecoder structure. + * @param [in] channels int: Number of channels. + * This must be 1 or 2. + * @returns The size in bytes. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_decoder_get_size(int channels); + +/** Allocates and initializes a decoder state. + * @param [in] Fs opus_int32: Sample rate to decode at (Hz). + * This must be one of 8000, 12000, 16000, + * 24000, or 48000. + * @param [in] channels int: Number of channels (1 or 2) to decode + * @param [out] error int*: #OPUS_OK Success or @ref opus_errorcodes + * + * Internally Opus stores data at 48000 Hz, so that should be the default + * value for Fs. However, the decoder can efficiently decode to buffers + * at 8, 12, 16, and 24 kHz so if for some reason the caller cannot use + * data at the full sample rate, or knows the compressed data doesn't + * use the full frequency range, it can request decoding at a reduced + * rate. Likewise, the decoder is capable of filling in either mono or + * interleaved stereo pcm buffers, at the caller's request. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT OpusDecoder *opus_decoder_create( + opus_int32 Fs, + int channels, + int *error +); + +/** Initializes a previously allocated decoder state. + * The state must be at least the size returned by opus_decoder_get_size(). + * This is intended for applications which use their own allocator instead of malloc. @see opus_decoder_create,opus_decoder_get_size + * To reset a previously initialized state, use the #OPUS_RESET_STATE CTL. + * @param [in] st OpusDecoder*: Decoder state. + * @param [in] Fs opus_int32: Sampling rate to decode to (Hz). + * This must be one of 8000, 12000, 16000, + * 24000, or 48000. + * @param [in] channels int: Number of channels (1 or 2) to decode + * @retval #OPUS_OK Success or @ref opus_errorcodes + */ +OPUS_EXPORT int opus_decoder_init( + OpusDecoder *st, + opus_int32 Fs, + int channels +) OPUS_ARG_NONNULL(1); + +/** Decode an Opus packet. + * @param [in] st OpusDecoder*: Decoder state + * @param [in] data char*: Input payload. Use a NULL pointer to indicate packet loss + * @param [in] len opus_int32: Number of bytes in payload* + * @param [out] pcm opus_int16*: Output signal (interleaved if 2 channels). length + * is frame_size*channels*sizeof(opus_int16) + * @param [in] frame_size Number of samples per channel of available space in \a pcm. + * If this is less than the maximum packet duration (120ms; 5760 for 48kHz), this function will + * not be capable of decoding some packets. In the case of PLC (data==NULL) or FEC (decode_fec=1), + * then frame_size needs to be exactly the duration of audio that is missing, otherwise the + * decoder will not be in the optimal state to decode the next incoming packet. For the PLC and + * FEC cases, frame_size must be a multiple of 2.5 ms. + * @param [in] decode_fec int: Flag (0 or 1) to request that any in-band forward error correction data be + * decoded. If no such data is available, the frame is decoded as if it were lost. + * @returns Number of decoded samples or @ref opus_errorcodes + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_decode( + OpusDecoder *st, + const unsigned char *data, + opus_int32 len, + opus_int16 *pcm, + int frame_size, + int decode_fec +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4); + +/** Decode an Opus packet with floating point output. + * @param [in] st OpusDecoder*: Decoder state + * @param [in] data char*: Input payload. Use a NULL pointer to indicate packet loss + * @param [in] len opus_int32: Number of bytes in payload + * @param [out] pcm float*: Output signal (interleaved if 2 channels). length + * is frame_size*channels*sizeof(float) + * @param [in] frame_size Number of samples per channel of available space in \a pcm. + * If this is less than the maximum packet duration (120ms; 5760 for 48kHz), this function will + * not be capable of decoding some packets. In the case of PLC (data==NULL) or FEC (decode_fec=1), + * then frame_size needs to be exactly the duration of audio that is missing, otherwise the + * decoder will not be in the optimal state to decode the next incoming packet. For the PLC and + * FEC cases, frame_size must be a multiple of 2.5 ms. + * @param [in] decode_fec int: Flag (0 or 1) to request that any in-band forward error correction data be + * decoded. If no such data is available the frame is decoded as if it were lost. + * @returns Number of decoded samples or @ref opus_errorcodes + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_decode_float( + OpusDecoder *st, + const unsigned char *data, + opus_int32 len, + float *pcm, + int frame_size, + int decode_fec +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4); + +/** Perform a CTL function on an Opus decoder. + * + * Generally the request and subsequent arguments are generated + * by a convenience macro. + * @param st OpusDecoder*: Decoder state. + * @param request This and all remaining parameters should be replaced by one + * of the convenience macros in @ref opus_genericctls or + * @ref opus_decoderctls. + * @see opus_genericctls + * @see opus_decoderctls + */ +OPUS_EXPORT int opus_decoder_ctl(OpusDecoder *st, int request, ...) OPUS_ARG_NONNULL(1); + +/** Frees an OpusDecoder allocated by opus_decoder_create(). + * @param[in] st OpusDecoder*: State to be freed. + */ +OPUS_EXPORT void opus_decoder_destroy(OpusDecoder *st); + +/** Parse an opus packet into one or more frames. + * Opus_decode will perform this operation internally so most applications do + * not need to use this function. + * This function does not copy the frames, the returned pointers are pointers into + * the input packet. + * @param [in] data char*: Opus packet to be parsed + * @param [in] len opus_int32: size of data + * @param [out] out_toc char*: TOC pointer + * @param [out] frames char*[48] encapsulated frames + * @param [out] size opus_int16[48] sizes of the encapsulated frames + * @param [out] payload_offset int*: returns the position of the payload within the packet (in bytes) + * @returns number of frames + */ +OPUS_EXPORT int opus_packet_parse( + const unsigned char *data, + opus_int32 len, + unsigned char *out_toc, + const unsigned char *frames[48], + opus_int16 size[48], + int *payload_offset +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(5); + +/** Gets the bandwidth of an Opus packet. + * @param [in] data char*: Opus packet + * @retval OPUS_BANDWIDTH_NARROWBAND Narrowband (4kHz bandpass) + * @retval OPUS_BANDWIDTH_MEDIUMBAND Mediumband (6kHz bandpass) + * @retval OPUS_BANDWIDTH_WIDEBAND Wideband (8kHz bandpass) + * @retval OPUS_BANDWIDTH_SUPERWIDEBAND Superwideband (12kHz bandpass) + * @retval OPUS_BANDWIDTH_FULLBAND Fullband (20kHz bandpass) + * @retval OPUS_INVALID_PACKET The compressed data passed is corrupted or of an unsupported type + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_packet_get_bandwidth(const unsigned char *data) OPUS_ARG_NONNULL(1); + +/** Gets the number of samples per frame from an Opus packet. + * @param [in] data char*: Opus packet. + * This must contain at least one byte of + * data. + * @param [in] Fs opus_int32: Sampling rate in Hz. + * This must be a multiple of 400, or + * inaccurate results will be returned. + * @returns Number of samples per frame. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_packet_get_samples_per_frame(const unsigned char *data, opus_int32 Fs) OPUS_ARG_NONNULL(1); + +/** Gets the number of channels from an Opus packet. + * @param [in] data char*: Opus packet + * @returns Number of channels + * @retval OPUS_INVALID_PACKET The compressed data passed is corrupted or of an unsupported type + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_packet_get_nb_channels(const unsigned char *data) OPUS_ARG_NONNULL(1); + +/** Gets the number of frames in an Opus packet. + * @param [in] packet char*: Opus packet + * @param [in] len opus_int32: Length of packet + * @returns Number of frames + * @retval OPUS_BAD_ARG Insufficient data was passed to the function + * @retval OPUS_INVALID_PACKET The compressed data passed is corrupted or of an unsupported type + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_packet_get_nb_frames(const unsigned char packet[], opus_int32 len) OPUS_ARG_NONNULL(1); + +/** Gets the number of samples of an Opus packet. + * @param [in] packet char*: Opus packet + * @param [in] len opus_int32: Length of packet + * @param [in] Fs opus_int32: Sampling rate in Hz. + * This must be a multiple of 400, or + * inaccurate results will be returned. + * @returns Number of samples + * @retval OPUS_BAD_ARG Insufficient data was passed to the function + * @retval OPUS_INVALID_PACKET The compressed data passed is corrupted or of an unsupported type + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_packet_get_nb_samples(const unsigned char packet[], opus_int32 len, opus_int32 Fs) OPUS_ARG_NONNULL(1); + +/** Gets the number of samples of an Opus packet. + * @param [in] dec OpusDecoder*: Decoder state + * @param [in] packet char*: Opus packet + * @param [in] len opus_int32: Length of packet + * @returns Number of samples + * @retval OPUS_BAD_ARG Insufficient data was passed to the function + * @retval OPUS_INVALID_PACKET The compressed data passed is corrupted or of an unsupported type + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_decoder_get_nb_samples(const OpusDecoder *dec, const unsigned char packet[], opus_int32 len) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2); + +/** Applies soft-clipping to bring a float signal within the [-1,1] range. If + * the signal is already in that range, nothing is done. If there are values + * outside of [-1,1], then the signal is clipped as smoothly as possible to + * both fit in the range and avoid creating excessive distortion in the + * process. + * @param [in,out] pcm float*: Input PCM and modified PCM + * @param [in] frame_size int Number of samples per channel to process + * @param [in] channels int: Number of channels + * @param [in,out] softclip_mem float*: State memory for the soft clipping process (one float per channel, initialized to zero) + */ +OPUS_EXPORT void opus_pcm_soft_clip(float *pcm, int frame_size, int channels, float *softclip_mem); + + +/**@}*/ + +/** @defgroup opus_repacketizer Repacketizer + * @{ + * + * The repacketizer can be used to merge multiple Opus packets into a single + * packet or alternatively to split Opus packets that have previously been + * merged. Splitting valid Opus packets is always guaranteed to succeed, + * whereas merging valid packets only succeeds if all frames have the same + * mode, bandwidth, and frame size, and when the total duration of the merged + * packet is no more than 120 ms. The 120 ms limit comes from the + * specification and limits decoder memory requirements at a point where + * framing overhead becomes negligible. + * + * The repacketizer currently only operates on elementary Opus + * streams. It will not manipualte multistream packets successfully, except in + * the degenerate case where they consist of data from a single stream. + * + * The repacketizing process starts with creating a repacketizer state, either + * by calling opus_repacketizer_create() or by allocating the memory yourself, + * e.g., + * @code + * OpusRepacketizer *rp; + * rp = (OpusRepacketizer*)malloc(opus_repacketizer_get_size()); + * if (rp != NULL) + * opus_repacketizer_init(rp); + * @endcode + * + * Then the application should submit packets with opus_repacketizer_cat(), + * extract new packets with opus_repacketizer_out() or + * opus_repacketizer_out_range(), and then reset the state for the next set of + * input packets via opus_repacketizer_init(). + * + * For example, to split a sequence of packets into individual frames: + * @code + * unsigned char *data; + * int len; + * while (get_next_packet(&data, &len)) + * { + * unsigned char out[1276]; + * opus_int32 out_len; + * int nb_frames; + * int err; + * int i; + * err = opus_repacketizer_cat(rp, data, len); + * if (err != OPUS_OK) + * { + * release_packet(data); + * return err; + * } + * nb_frames = opus_repacketizer_get_nb_frames(rp); + * for (i = 0; i < nb_frames; i++) + * { + * out_len = opus_repacketizer_out_range(rp, i, i+1, out, sizeof(out)); + * if (out_len < 0) + * { + * release_packet(data); + * return (int)out_len; + * } + * output_next_packet(out, out_len); + * } + * opus_repacketizer_init(rp); + * release_packet(data); + * } + * @endcode + * + * Alternatively, to combine a sequence of frames into packets that each + * contain up to TARGET_DURATION_MS milliseconds of data: + * @code + * // The maximum number of packets with duration TARGET_DURATION_MS occurs + * // when the frame size is 2.5 ms, for a total of (TARGET_DURATION_MS*2/5) + * // packets. + * unsigned char *data[(TARGET_DURATION_MS*2/5)+1]; + * opus_int32 len[(TARGET_DURATION_MS*2/5)+1]; + * int nb_packets; + * unsigned char out[1277*(TARGET_DURATION_MS*2/2)]; + * opus_int32 out_len; + * int prev_toc; + * nb_packets = 0; + * while (get_next_packet(data+nb_packets, len+nb_packets)) + * { + * int nb_frames; + * int err; + * nb_frames = opus_packet_get_nb_frames(data[nb_packets], len[nb_packets]); + * if (nb_frames < 1) + * { + * release_packets(data, nb_packets+1); + * return nb_frames; + * } + * nb_frames += opus_repacketizer_get_nb_frames(rp); + * // If adding the next packet would exceed our target, or it has an + * // incompatible TOC sequence, output the packets we already have before + * // submitting it. + * // N.B., The nb_packets > 0 check ensures we've submitted at least one + * // packet since the last call to opus_repacketizer_init(). Otherwise a + * // single packet longer than TARGET_DURATION_MS would cause us to try to + * // output an (invalid) empty packet. It also ensures that prev_toc has + * // been set to a valid value. Additionally, len[nb_packets] > 0 is + * // guaranteed by the call to opus_packet_get_nb_frames() above, so the + * // reference to data[nb_packets][0] should be valid. + * if (nb_packets > 0 && ( + * ((prev_toc & 0xFC) != (data[nb_packets][0] & 0xFC)) || + * opus_packet_get_samples_per_frame(data[nb_packets], 48000)*nb_frames > + * TARGET_DURATION_MS*48)) + * { + * out_len = opus_repacketizer_out(rp, out, sizeof(out)); + * if (out_len < 0) + * { + * release_packets(data, nb_packets+1); + * return (int)out_len; + * } + * output_next_packet(out, out_len); + * opus_repacketizer_init(rp); + * release_packets(data, nb_packets); + * data[0] = data[nb_packets]; + * len[0] = len[nb_packets]; + * nb_packets = 0; + * } + * err = opus_repacketizer_cat(rp, data[nb_packets], len[nb_packets]); + * if (err != OPUS_OK) + * { + * release_packets(data, nb_packets+1); + * return err; + * } + * prev_toc = data[nb_packets][0]; + * nb_packets++; + * } + * // Output the final, partial packet. + * if (nb_packets > 0) + * { + * out_len = opus_repacketizer_out(rp, out, sizeof(out)); + * release_packets(data, nb_packets); + * if (out_len < 0) + * return (int)out_len; + * output_next_packet(out, out_len); + * } + * @endcode + * + * An alternate way of merging packets is to simply call opus_repacketizer_cat() + * unconditionally until it fails. At that point, the merged packet can be + * obtained with opus_repacketizer_out() and the input packet for which + * opus_repacketizer_cat() needs to be re-added to a newly reinitialized + * repacketizer state. + */ + +typedef struct OpusRepacketizer OpusRepacketizer; + +/** Gets the size of an OpusRepacketizer structure. + * @returns The size in bytes. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_repacketizer_get_size(void); + +/** (Re)initializes a previously allocated repacketizer state. + * The state must be at least the size returned by opus_repacketizer_get_size(). + * This can be used for applications which use their own allocator instead of + * malloc(). + * It must also be called to reset the queue of packets waiting to be + * repacketized, which is necessary if the maximum packet duration of 120 ms + * is reached or if you wish to submit packets with a different Opus + * configuration (coding mode, audio bandwidth, frame size, or channel count). + * Failure to do so will prevent a new packet from being added with + * opus_repacketizer_cat(). + * @see opus_repacketizer_create + * @see opus_repacketizer_get_size + * @see opus_repacketizer_cat + * @param rp OpusRepacketizer*: The repacketizer state to + * (re)initialize. + * @returns A pointer to the same repacketizer state that was passed in. + */ +OPUS_EXPORT OpusRepacketizer *opus_repacketizer_init(OpusRepacketizer *rp) OPUS_ARG_NONNULL(1); + +/** Allocates memory and initializes the new repacketizer with + * opus_repacketizer_init(). + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT OpusRepacketizer *opus_repacketizer_create(void); + +/** Frees an OpusRepacketizer allocated by + * opus_repacketizer_create(). + * @param[in] rp OpusRepacketizer*: State to be freed. + */ +OPUS_EXPORT void opus_repacketizer_destroy(OpusRepacketizer *rp); + +/** Add a packet to the current repacketizer state. + * This packet must match the configuration of any packets already submitted + * for repacketization since the last call to opus_repacketizer_init(). + * This means that it must have the same coding mode, audio bandwidth, frame + * size, and channel count. + * This can be checked in advance by examining the top 6 bits of the first + * byte of the packet, and ensuring they match the top 6 bits of the first + * byte of any previously submitted packet. + * The total duration of audio in the repacketizer state also must not exceed + * 120 ms, the maximum duration of a single packet, after adding this packet. + * + * The contents of the current repacketizer state can be extracted into new + * packets using opus_repacketizer_out() or opus_repacketizer_out_range(). + * + * In order to add a packet with a different configuration or to add more + * audio beyond 120 ms, you must clear the repacketizer state by calling + * opus_repacketizer_init(). + * If a packet is too large to add to the current repacketizer state, no part + * of it is added, even if it contains multiple frames, some of which might + * fit. + * If you wish to be able to add parts of such packets, you should first use + * another repacketizer to split the packet into pieces and add them + * individually. + * @see opus_repacketizer_out_range + * @see opus_repacketizer_out + * @see opus_repacketizer_init + * @param rp OpusRepacketizer*: The repacketizer state to which to + * add the packet. + * @param[in] data const unsigned char*: The packet data. + * The application must ensure + * this pointer remains valid + * until the next call to + * opus_repacketizer_init() or + * opus_repacketizer_destroy(). + * @param len opus_int32: The number of bytes in the packet data. + * @returns An error code indicating whether or not the operation succeeded. + * @retval #OPUS_OK The packet's contents have been added to the repacketizer + * state. + * @retval #OPUS_INVALID_PACKET The packet did not have a valid TOC sequence, + * the packet's TOC sequence was not compatible + * with previously submitted packets (because + * the coding mode, audio bandwidth, frame size, + * or channel count did not match), or adding + * this packet would increase the total amount of + * audio stored in the repacketizer state to more + * than 120 ms. + */ +OPUS_EXPORT int opus_repacketizer_cat(OpusRepacketizer *rp, const unsigned char *data, opus_int32 len) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2); + + +/** Construct a new packet from data previously submitted to the repacketizer + * state via opus_repacketizer_cat(). + * @param rp OpusRepacketizer*: The repacketizer state from which to + * construct the new packet. + * @param begin int: The index of the first frame in the current + * repacketizer state to include in the output. + * @param end int: One past the index of the last frame in the + * current repacketizer state to include in the + * output. + * @param[out] data const unsigned char*: The buffer in which to + * store the output packet. + * @param maxlen opus_int32: The maximum number of bytes to store in + * the output buffer. In order to guarantee + * success, this should be at least + * 1276 for a single frame, + * or for multiple frames, + * 1277*(end-begin). + * However, 1*(end-begin) plus + * the size of all packet data submitted to + * the repacketizer since the last call to + * opus_repacketizer_init() or + * opus_repacketizer_create() is also + * sufficient, and possibly much smaller. + * @returns The total size of the output packet on success, or an error code + * on failure. + * @retval #OPUS_BAD_ARG [begin,end) was an invalid range of + * frames (begin < 0, begin >= end, or end > + * opus_repacketizer_get_nb_frames()). + * @retval #OPUS_BUFFER_TOO_SMALL \a maxlen was insufficient to contain the + * complete output packet. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_repacketizer_out_range(OpusRepacketizer *rp, int begin, int end, unsigned char *data, opus_int32 maxlen) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4); + +/** Return the total number of frames contained in packet data submitted to + * the repacketizer state so far via opus_repacketizer_cat() since the last + * call to opus_repacketizer_init() or opus_repacketizer_create(). + * This defines the valid range of packets that can be extracted with + * opus_repacketizer_out_range() or opus_repacketizer_out(). + * @param rp OpusRepacketizer*: The repacketizer state containing the + * frames. + * @returns The total number of frames contained in the packet data submitted + * to the repacketizer state. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_repacketizer_get_nb_frames(OpusRepacketizer *rp) OPUS_ARG_NONNULL(1); + +/** Construct a new packet from data previously submitted to the repacketizer + * state via opus_repacketizer_cat(). + * This is a convenience routine that returns all the data submitted so far + * in a single packet. + * It is equivalent to calling + * @code + * opus_repacketizer_out_range(rp, 0, opus_repacketizer_get_nb_frames(rp), + * data, maxlen) + * @endcode + * @param rp OpusRepacketizer*: The repacketizer state from which to + * construct the new packet. + * @param[out] data const unsigned char*: The buffer in which to + * store the output packet. + * @param maxlen opus_int32: The maximum number of bytes to store in + * the output buffer. In order to guarantee + * success, this should be at least + * 1277*opus_repacketizer_get_nb_frames(rp). + * However, + * 1*opus_repacketizer_get_nb_frames(rp) + * plus the size of all packet data + * submitted to the repacketizer since the + * last call to opus_repacketizer_init() or + * opus_repacketizer_create() is also + * sufficient, and possibly much smaller. + * @returns The total size of the output packet on success, or an error code + * on failure. + * @retval #OPUS_BUFFER_TOO_SMALL \a maxlen was insufficient to contain the + * complete output packet. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_repacketizer_out(OpusRepacketizer *rp, unsigned char *data, opus_int32 maxlen) OPUS_ARG_NONNULL(1); + +/** Pads a given Opus packet to a larger size (possibly changing the TOC sequence). + * @param[in,out] data const unsigned char*: The buffer containing the + * packet to pad. + * @param len opus_int32: The size of the packet. + * This must be at least 1. + * @param new_len opus_int32: The desired size of the packet after padding. + * This must be at least as large as len. + * @returns an error code + * @retval #OPUS_OK \a on success. + * @retval #OPUS_BAD_ARG \a len was less than 1 or new_len was less than len. + * @retval #OPUS_INVALID_PACKET \a data did not contain a valid Opus packet. + */ +OPUS_EXPORT int opus_packet_pad(unsigned char *data, opus_int32 len, opus_int32 new_len); + +/** Remove all padding from a given Opus packet and rewrite the TOC sequence to + * minimize space usage. + * @param[in,out] data const unsigned char*: The buffer containing the + * packet to strip. + * @param len opus_int32: The size of the packet. + * This must be at least 1. + * @returns The new size of the output packet on success, or an error code + * on failure. + * @retval #OPUS_BAD_ARG \a len was less than 1. + * @retval #OPUS_INVALID_PACKET \a data did not contain a valid Opus packet. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_packet_unpad(unsigned char *data, opus_int32 len); + +/** Pads a given Opus multi-stream packet to a larger size (possibly changing the TOC sequence). + * @param[in,out] data const unsigned char*: The buffer containing the + * packet to pad. + * @param len opus_int32: The size of the packet. + * This must be at least 1. + * @param new_len opus_int32: The desired size of the packet after padding. + * This must be at least 1. + * @param nb_streams opus_int32: The number of streams (not channels) in the packet. + * This must be at least as large as len. + * @returns an error code + * @retval #OPUS_OK \a on success. + * @retval #OPUS_BAD_ARG \a len was less than 1. + * @retval #OPUS_INVALID_PACKET \a data did not contain a valid Opus packet. + */ +OPUS_EXPORT int opus_multistream_packet_pad(unsigned char *data, opus_int32 len, opus_int32 new_len, int nb_streams); + +/** Remove all padding from a given Opus multi-stream packet and rewrite the TOC sequence to + * minimize space usage. + * @param[in,out] data const unsigned char*: The buffer containing the + * packet to strip. + * @param len opus_int32: The size of the packet. + * This must be at least 1. + * @param nb_streams opus_int32: The number of streams (not channels) in the packet. + * This must be at least 1. + * @returns The new size of the output packet on success, or an error code + * on failure. + * @retval #OPUS_BAD_ARG \a len was less than 1 or new_len was less than len. + * @retval #OPUS_INVALID_PACKET \a data did not contain a valid Opus packet. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_multistream_packet_unpad(unsigned char *data, opus_int32 len, int nb_streams); + +/**@}*/ + +#ifdef __cplusplus +} +#endif + +#endif /* OPUS_H */ diff --git a/extern/opus/include/opus_custom.h b/extern/opus/include/opus_custom.h new file mode 100644 index 0000000..41f36bf --- /dev/null +++ b/extern/opus/include/opus_custom.h @@ -0,0 +1,342 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Copyright (c) 2008-2012 Gregory Maxwell + Written by Jean-Marc Valin and Gregory Maxwell */ +/* + 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. + + 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 OWNER + 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. +*/ + +/** + @file opus_custom.h + @brief Opus-Custom reference implementation API + */ + +#ifndef OPUS_CUSTOM_H +#define OPUS_CUSTOM_H + +#include "opus_defines.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef CUSTOM_MODES +# define OPUS_CUSTOM_EXPORT OPUS_EXPORT +# define OPUS_CUSTOM_EXPORT_STATIC OPUS_EXPORT +#else +# define OPUS_CUSTOM_EXPORT +# ifdef OPUS_BUILD +# define OPUS_CUSTOM_EXPORT_STATIC static OPUS_INLINE +# else +# define OPUS_CUSTOM_EXPORT_STATIC +# endif +#endif + +/** @defgroup opus_custom Opus Custom + * @{ + * Opus Custom is an optional part of the Opus specification and + * reference implementation which uses a distinct API from the regular + * API and supports frame sizes that are not normally supported.\ Use + * of Opus Custom is discouraged for all but very special applications + * for which a frame size different from 2.5, 5, 10, or 20 ms is needed + * (for either complexity or latency reasons) and where interoperability + * is less important. + * + * In addition to the interoperability limitations the use of Opus custom + * disables a substantial chunk of the codec and generally lowers the + * quality available at a given bitrate. Normally when an application needs + * a different frame size from the codec it should buffer to match the + * sizes but this adds a small amount of delay which may be important + * in some very low latency applications. Some transports (especially + * constant rate RF transports) may also work best with frames of + * particular durations. + * + * Libopus only supports custom modes if they are enabled at compile time. + * + * The Opus Custom API is similar to the regular API but the + * @ref opus_encoder_create and @ref opus_decoder_create calls take + * an additional mode parameter which is a structure produced by + * a call to @ref opus_custom_mode_create. Both the encoder and decoder + * must create a mode using the same sample rate (fs) and frame size + * (frame size) so these parameters must either be signaled out of band + * or fixed in a particular implementation. + * + * Similar to regular Opus the custom modes support on the fly frame size + * switching, but the sizes available depend on the particular frame size in + * use. For some initial frame sizes on a single on the fly size is available. + */ + +/** Contains the state of an encoder. One encoder state is needed + for each stream. It is initialized once at the beginning of the + stream. Do *not* re-initialize the state for every frame. + @brief Encoder state + */ +typedef struct OpusCustomEncoder OpusCustomEncoder; + +/** State of the decoder. One decoder state is needed for each stream. + It is initialized once at the beginning of the stream. Do *not* + re-initialize the state for every frame. + @brief Decoder state + */ +typedef struct OpusCustomDecoder OpusCustomDecoder; + +/** The mode contains all the information necessary to create an + encoder. Both the encoder and decoder need to be initialized + with exactly the same mode, otherwise the output will be + corrupted. + @brief Mode configuration + */ +typedef struct OpusCustomMode OpusCustomMode; + +/** Creates a new mode struct. This will be passed to an encoder or + * decoder. The mode MUST NOT BE DESTROYED until the encoders and + * decoders that use it are destroyed as well. + * @param [in] Fs int: Sampling rate (8000 to 96000 Hz) + * @param [in] frame_size int: Number of samples (per channel) to encode in each + * packet (64 - 1024, prime factorization must contain zero or more 2s, 3s, or 5s and no other primes) + * @param [out] error int*: Returned error code (if NULL, no error will be returned) + * @return A newly created mode + */ +OPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT OpusCustomMode *opus_custom_mode_create(opus_int32 Fs, int frame_size, int *error); + +/** Destroys a mode struct. Only call this after all encoders and + * decoders using this mode are destroyed as well. + * @param [in] mode OpusCustomMode*: Mode to be freed. + */ +OPUS_CUSTOM_EXPORT void opus_custom_mode_destroy(OpusCustomMode *mode); + + +#if !defined(OPUS_BUILD) || defined(CELT_ENCODER_C) + +/* Encoder */ +/** Gets the size of an OpusCustomEncoder structure. + * @param [in] mode OpusCustomMode *: Mode configuration + * @param [in] channels int: Number of channels + * @returns size + */ +OPUS_CUSTOM_EXPORT_STATIC OPUS_WARN_UNUSED_RESULT int opus_custom_encoder_get_size( + const OpusCustomMode *mode, + int channels +) OPUS_ARG_NONNULL(1); + +# ifdef CUSTOM_MODES +/** Initializes a previously allocated encoder state + * The memory pointed to by st must be the size returned by opus_custom_encoder_get_size. + * This is intended for applications which use their own allocator instead of malloc. + * @see opus_custom_encoder_create(),opus_custom_encoder_get_size() + * To reset a previously initialized state use the OPUS_RESET_STATE CTL. + * @param [in] st OpusCustomEncoder*: Encoder state + * @param [in] mode OpusCustomMode *: Contains all the information about the characteristics of + * the stream (must be the same characteristics as used for the + * decoder) + * @param [in] channels int: Number of channels + * @return OPUS_OK Success or @ref opus_errorcodes + */ +OPUS_CUSTOM_EXPORT int opus_custom_encoder_init( + OpusCustomEncoder *st, + const OpusCustomMode *mode, + int channels +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2); +# endif +#endif + + +/** Creates a new encoder state. Each stream needs its own encoder + * state (can't be shared across simultaneous streams). + * @param [in] mode OpusCustomMode*: Contains all the information about the characteristics of + * the stream (must be the same characteristics as used for the + * decoder) + * @param [in] channels int: Number of channels + * @param [out] error int*: Returns an error code + * @return Newly created encoder state. +*/ +OPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT OpusCustomEncoder *opus_custom_encoder_create( + const OpusCustomMode *mode, + int channels, + int *error +) OPUS_ARG_NONNULL(1); + + +/** Destroys a an encoder state. + * @param[in] st OpusCustomEncoder*: State to be freed. + */ +OPUS_CUSTOM_EXPORT void opus_custom_encoder_destroy(OpusCustomEncoder *st); + +/** Encodes a frame of audio. + * @param [in] st OpusCustomEncoder*: Encoder state + * @param [in] pcm float*: PCM audio in float format, with a normal range of +/-1.0. + * Samples with a range beyond +/-1.0 are supported but will + * be clipped by decoders using the integer API and should + * only be used if it is known that the far end supports + * extended dynamic range. There must be exactly + * frame_size samples per channel. + * @param [in] frame_size int: Number of samples per frame of input signal + * @param [out] compressed char *: The compressed data is written here. This may not alias pcm and must be at least maxCompressedBytes long. + * @param [in] maxCompressedBytes int: Maximum number of bytes to use for compressing the frame + * (can change from one frame to another) + * @return Number of bytes written to "compressed". + * If negative, an error has occurred (see error codes). It is IMPORTANT that + * the length returned be somehow transmitted to the decoder. Otherwise, no + * decoding is possible. + */ +OPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT int opus_custom_encode_float( + OpusCustomEncoder *st, + const float *pcm, + int frame_size, + unsigned char *compressed, + int maxCompressedBytes +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2) OPUS_ARG_NONNULL(4); + +/** Encodes a frame of audio. + * @param [in] st OpusCustomEncoder*: Encoder state + * @param [in] pcm opus_int16*: PCM audio in signed 16-bit format (native endian). + * There must be exactly frame_size samples per channel. + * @param [in] frame_size int: Number of samples per frame of input signal + * @param [out] compressed char *: The compressed data is written here. This may not alias pcm and must be at least maxCompressedBytes long. + * @param [in] maxCompressedBytes int: Maximum number of bytes to use for compressing the frame + * (can change from one frame to another) + * @return Number of bytes written to "compressed". + * If negative, an error has occurred (see error codes). It is IMPORTANT that + * the length returned be somehow transmitted to the decoder. Otherwise, no + * decoding is possible. + */ +OPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT int opus_custom_encode( + OpusCustomEncoder *st, + const opus_int16 *pcm, + int frame_size, + unsigned char *compressed, + int maxCompressedBytes +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2) OPUS_ARG_NONNULL(4); + +/** Perform a CTL function on an Opus custom encoder. + * + * Generally the request and subsequent arguments are generated + * by a convenience macro. + * @see opus_encoderctls + */ +OPUS_CUSTOM_EXPORT int opus_custom_encoder_ctl(OpusCustomEncoder * OPUS_RESTRICT st, int request, ...) OPUS_ARG_NONNULL(1); + + +#if !defined(OPUS_BUILD) || defined(CELT_DECODER_C) +/* Decoder */ + +/** Gets the size of an OpusCustomDecoder structure. + * @param [in] mode OpusCustomMode *: Mode configuration + * @param [in] channels int: Number of channels + * @returns size + */ +OPUS_CUSTOM_EXPORT_STATIC OPUS_WARN_UNUSED_RESULT int opus_custom_decoder_get_size( + const OpusCustomMode *mode, + int channels +) OPUS_ARG_NONNULL(1); + +/** Initializes a previously allocated decoder state + * The memory pointed to by st must be the size returned by opus_custom_decoder_get_size. + * This is intended for applications which use their own allocator instead of malloc. + * @see opus_custom_decoder_create(),opus_custom_decoder_get_size() + * To reset a previously initialized state use the OPUS_RESET_STATE CTL. + * @param [in] st OpusCustomDecoder*: Decoder state + * @param [in] mode OpusCustomMode *: Contains all the information about the characteristics of + * the stream (must be the same characteristics as used for the + * encoder) + * @param [in] channels int: Number of channels + * @return OPUS_OK Success or @ref opus_errorcodes + */ +OPUS_CUSTOM_EXPORT_STATIC int opus_custom_decoder_init( + OpusCustomDecoder *st, + const OpusCustomMode *mode, + int channels +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2); + +#endif + + +/** Creates a new decoder state. Each stream needs its own decoder state (can't + * be shared across simultaneous streams). + * @param [in] mode OpusCustomMode: Contains all the information about the characteristics of the + * stream (must be the same characteristics as used for the encoder) + * @param [in] channels int: Number of channels + * @param [out] error int*: Returns an error code + * @return Newly created decoder state. + */ +OPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT OpusCustomDecoder *opus_custom_decoder_create( + const OpusCustomMode *mode, + int channels, + int *error +) OPUS_ARG_NONNULL(1); + +/** Destroys a an decoder state. + * @param[in] st OpusCustomDecoder*: State to be freed. + */ +OPUS_CUSTOM_EXPORT void opus_custom_decoder_destroy(OpusCustomDecoder *st); + +/** Decode an opus custom frame with floating point output + * @param [in] st OpusCustomDecoder*: Decoder state + * @param [in] data char*: Input payload. Use a NULL pointer to indicate packet loss + * @param [in] len int: Number of bytes in payload + * @param [out] pcm float*: Output signal (interleaved if 2 channels). length + * is frame_size*channels*sizeof(float) + * @param [in] frame_size Number of samples per channel of available space in *pcm. + * @returns Number of decoded samples or @ref opus_errorcodes + */ +OPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT int opus_custom_decode_float( + OpusCustomDecoder *st, + const unsigned char *data, + int len, + float *pcm, + int frame_size +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4); + +/** Decode an opus custom frame + * @param [in] st OpusCustomDecoder*: Decoder state + * @param [in] data char*: Input payload. Use a NULL pointer to indicate packet loss + * @param [in] len int: Number of bytes in payload + * @param [out] pcm opus_int16*: Output signal (interleaved if 2 channels). length + * is frame_size*channels*sizeof(opus_int16) + * @param [in] frame_size Number of samples per channel of available space in *pcm. + * @returns Number of decoded samples or @ref opus_errorcodes + */ +OPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT int opus_custom_decode( + OpusCustomDecoder *st, + const unsigned char *data, + int len, + opus_int16 *pcm, + int frame_size +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4); + +/** Perform a CTL function on an Opus custom decoder. + * + * Generally the request and subsequent arguments are generated + * by a convenience macro. + * @see opus_genericctls + */ +OPUS_CUSTOM_EXPORT int opus_custom_decoder_ctl(OpusCustomDecoder * OPUS_RESTRICT st, int request, ...) OPUS_ARG_NONNULL(1); + +/**@}*/ + +#ifdef __cplusplus +} +#endif + +#endif /* OPUS_CUSTOM_H */ diff --git a/extern/opus/include/opus_defines.h b/extern/opus/include/opus_defines.h new file mode 100644 index 0000000..d141418 --- /dev/null +++ b/extern/opus/include/opus_defines.h @@ -0,0 +1,799 @@ +/* Copyright (c) 2010-2011 Xiph.Org Foundation, Skype Limited + Written by Jean-Marc Valin and Koen Vos */ +/* + 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. + + 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 OWNER + 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. +*/ + +/** + * @file opus_defines.h + * @brief Opus reference implementation constants + */ + +#ifndef OPUS_DEFINES_H +#define OPUS_DEFINES_H + +#include "opus_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** @defgroup opus_errorcodes Error codes + * @{ + */ +/** No error @hideinitializer*/ +#define OPUS_OK 0 +/** One or more invalid/out of range arguments @hideinitializer*/ +#define OPUS_BAD_ARG -1 +/** Not enough bytes allocated in the buffer @hideinitializer*/ +#define OPUS_BUFFER_TOO_SMALL -2 +/** An internal error was detected @hideinitializer*/ +#define OPUS_INTERNAL_ERROR -3 +/** The compressed data passed is corrupted @hideinitializer*/ +#define OPUS_INVALID_PACKET -4 +/** Invalid/unsupported request number @hideinitializer*/ +#define OPUS_UNIMPLEMENTED -5 +/** An encoder or decoder structure is invalid or already freed @hideinitializer*/ +#define OPUS_INVALID_STATE -6 +/** Memory allocation has failed @hideinitializer*/ +#define OPUS_ALLOC_FAIL -7 +/**@}*/ + +/** @cond OPUS_INTERNAL_DOC */ +/**Export control for opus functions */ + +#ifndef OPUS_EXPORT +# if defined(WIN32) +# if defined(OPUS_BUILD) && defined(DLL_EXPORT) +# define OPUS_EXPORT __declspec(dllexport) +# else +# define OPUS_EXPORT +# endif +# elif defined(__GNUC__) && defined(OPUS_BUILD) +# define OPUS_EXPORT __attribute__ ((visibility ("default"))) +# else +# define OPUS_EXPORT +# endif +#endif + +# if !defined(OPUS_GNUC_PREREQ) +# if defined(__GNUC__)&&defined(__GNUC_MINOR__) +# define OPUS_GNUC_PREREQ(_maj,_min) \ + ((__GNUC__<<16)+__GNUC_MINOR__>=((_maj)<<16)+(_min)) +# else +# define OPUS_GNUC_PREREQ(_maj,_min) 0 +# endif +# endif + +#if (!defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L) ) +# if OPUS_GNUC_PREREQ(3,0) +# define OPUS_RESTRICT __restrict__ +# elif (defined(_MSC_VER) && _MSC_VER >= 1400) +# define OPUS_RESTRICT __restrict +# else +# define OPUS_RESTRICT +# endif +#else +# define OPUS_RESTRICT restrict +#endif + +#if (!defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L) ) +# if OPUS_GNUC_PREREQ(2,7) +# define OPUS_INLINE __inline__ +# elif (defined(_MSC_VER)) +# define OPUS_INLINE __inline +# else +# define OPUS_INLINE +# endif +#else +# define OPUS_INLINE inline +#endif + +/**Warning attributes for opus functions + * NONNULL is not used in OPUS_BUILD to avoid the compiler optimizing out + * some paranoid null checks. */ +#if defined(__GNUC__) && OPUS_GNUC_PREREQ(3, 4) +# define OPUS_WARN_UNUSED_RESULT __attribute__ ((__warn_unused_result__)) +#else +# define OPUS_WARN_UNUSED_RESULT +#endif +#if !defined(OPUS_BUILD) && defined(__GNUC__) && OPUS_GNUC_PREREQ(3, 4) +# define OPUS_ARG_NONNULL(_x) __attribute__ ((__nonnull__(_x))) +#else +# define OPUS_ARG_NONNULL(_x) +#endif + +/** These are the actual Encoder CTL ID numbers. + * They should not be used directly by applications. + * In general, SETs should be even and GETs should be odd.*/ +#define OPUS_SET_APPLICATION_REQUEST 4000 +#define OPUS_GET_APPLICATION_REQUEST 4001 +#define OPUS_SET_BITRATE_REQUEST 4002 +#define OPUS_GET_BITRATE_REQUEST 4003 +#define OPUS_SET_MAX_BANDWIDTH_REQUEST 4004 +#define OPUS_GET_MAX_BANDWIDTH_REQUEST 4005 +#define OPUS_SET_VBR_REQUEST 4006 +#define OPUS_GET_VBR_REQUEST 4007 +#define OPUS_SET_BANDWIDTH_REQUEST 4008 +#define OPUS_GET_BANDWIDTH_REQUEST 4009 +#define OPUS_SET_COMPLEXITY_REQUEST 4010 +#define OPUS_GET_COMPLEXITY_REQUEST 4011 +#define OPUS_SET_INBAND_FEC_REQUEST 4012 +#define OPUS_GET_INBAND_FEC_REQUEST 4013 +#define OPUS_SET_PACKET_LOSS_PERC_REQUEST 4014 +#define OPUS_GET_PACKET_LOSS_PERC_REQUEST 4015 +#define OPUS_SET_DTX_REQUEST 4016 +#define OPUS_GET_DTX_REQUEST 4017 +#define OPUS_SET_VBR_CONSTRAINT_REQUEST 4020 +#define OPUS_GET_VBR_CONSTRAINT_REQUEST 4021 +#define OPUS_SET_FORCE_CHANNELS_REQUEST 4022 +#define OPUS_GET_FORCE_CHANNELS_REQUEST 4023 +#define OPUS_SET_SIGNAL_REQUEST 4024 +#define OPUS_GET_SIGNAL_REQUEST 4025 +#define OPUS_GET_LOOKAHEAD_REQUEST 4027 +/* #define OPUS_RESET_STATE 4028 */ +#define OPUS_GET_SAMPLE_RATE_REQUEST 4029 +#define OPUS_GET_FINAL_RANGE_REQUEST 4031 +#define OPUS_GET_PITCH_REQUEST 4033 +#define OPUS_SET_GAIN_REQUEST 4034 +#define OPUS_GET_GAIN_REQUEST 4045 /* Should have been 4035 */ +#define OPUS_SET_LSB_DEPTH_REQUEST 4036 +#define OPUS_GET_LSB_DEPTH_REQUEST 4037 +#define OPUS_GET_LAST_PACKET_DURATION_REQUEST 4039 +#define OPUS_SET_EXPERT_FRAME_DURATION_REQUEST 4040 +#define OPUS_GET_EXPERT_FRAME_DURATION_REQUEST 4041 +#define OPUS_SET_PREDICTION_DISABLED_REQUEST 4042 +#define OPUS_GET_PREDICTION_DISABLED_REQUEST 4043 +/* Don't use 4045, it's already taken by OPUS_GET_GAIN_REQUEST */ +#define OPUS_SET_PHASE_INVERSION_DISABLED_REQUEST 4046 +#define OPUS_GET_PHASE_INVERSION_DISABLED_REQUEST 4047 +#define OPUS_GET_IN_DTX_REQUEST 4049 + +/** Defines for the presence of extended APIs. */ +#define OPUS_HAVE_OPUS_PROJECTION_H + +/* Macros to trigger compilation errors when the wrong types are provided to a CTL */ +#define __opus_check_int(x) (((void)((x) == (opus_int32)0)), (opus_int32)(x)) +#define __opus_check_int_ptr(ptr) ((ptr) + ((ptr) - (opus_int32*)(ptr))) +#define __opus_check_uint_ptr(ptr) ((ptr) + ((ptr) - (opus_uint32*)(ptr))) +#define __opus_check_val16_ptr(ptr) ((ptr) + ((ptr) - (opus_val16*)(ptr))) +/** @endcond */ + +/** @defgroup opus_ctlvalues Pre-defined values for CTL interface + * @see opus_genericctls, opus_encoderctls + * @{ + */ +/* Values for the various encoder CTLs */ +#define OPUS_AUTO -1000 /**opus_int32: Allowed values: 0-10, inclusive. + * + * @hideinitializer */ +#define OPUS_SET_COMPLEXITY(x) OPUS_SET_COMPLEXITY_REQUEST, __opus_check_int(x) +/** Gets the encoder's complexity configuration. + * @see OPUS_SET_COMPLEXITY + * @param[out] x opus_int32 *: Returns a value in the range 0-10, + * inclusive. + * @hideinitializer */ +#define OPUS_GET_COMPLEXITY(x) OPUS_GET_COMPLEXITY_REQUEST, __opus_check_int_ptr(x) + +/** Configures the bitrate in the encoder. + * Rates from 500 to 512000 bits per second are meaningful, as well as the + * special values #OPUS_AUTO and #OPUS_BITRATE_MAX. + * The value #OPUS_BITRATE_MAX can be used to cause the codec to use as much + * rate as it can, which is useful for controlling the rate by adjusting the + * output buffer size. + * @see OPUS_GET_BITRATE + * @param[in] x opus_int32: Bitrate in bits per second. The default + * is determined based on the number of + * channels and the input sampling rate. + * @hideinitializer */ +#define OPUS_SET_BITRATE(x) OPUS_SET_BITRATE_REQUEST, __opus_check_int(x) +/** Gets the encoder's bitrate configuration. + * @see OPUS_SET_BITRATE + * @param[out] x opus_int32 *: Returns the bitrate in bits per second. + * The default is determined based on the + * number of channels and the input + * sampling rate. + * @hideinitializer */ +#define OPUS_GET_BITRATE(x) OPUS_GET_BITRATE_REQUEST, __opus_check_int_ptr(x) + +/** Enables or disables variable bitrate (VBR) in the encoder. + * The configured bitrate may not be met exactly because frames must + * be an integer number of bytes in length. + * @see OPUS_GET_VBR + * @see OPUS_SET_VBR_CONSTRAINT + * @param[in] x opus_int32: Allowed values: + *
    + *
    0
    Hard CBR. For LPC/hybrid modes at very low bit-rate, this can + * cause noticeable quality degradation.
    + *
    1
    VBR (default). The exact type of VBR is controlled by + * #OPUS_SET_VBR_CONSTRAINT.
    + *
    + * @hideinitializer */ +#define OPUS_SET_VBR(x) OPUS_SET_VBR_REQUEST, __opus_check_int(x) +/** Determine if variable bitrate (VBR) is enabled in the encoder. + * @see OPUS_SET_VBR + * @see OPUS_GET_VBR_CONSTRAINT + * @param[out] x opus_int32 *: Returns one of the following values: + *
    + *
    0
    Hard CBR.
    + *
    1
    VBR (default). The exact type of VBR may be retrieved via + * #OPUS_GET_VBR_CONSTRAINT.
    + *
    + * @hideinitializer */ +#define OPUS_GET_VBR(x) OPUS_GET_VBR_REQUEST, __opus_check_int_ptr(x) + +/** Enables or disables constrained VBR in the encoder. + * This setting is ignored when the encoder is in CBR mode. + * @warning Only the MDCT mode of Opus currently heeds the constraint. + * Speech mode ignores it completely, hybrid mode may fail to obey it + * if the LPC layer uses more bitrate than the constraint would have + * permitted. + * @see OPUS_GET_VBR_CONSTRAINT + * @see OPUS_SET_VBR + * @param[in] x opus_int32: Allowed values: + *
    + *
    0
    Unconstrained VBR.
    + *
    1
    Constrained VBR (default). This creates a maximum of one + * frame of buffering delay assuming a transport with a + * serialization speed of the nominal bitrate.
    + *
    + * @hideinitializer */ +#define OPUS_SET_VBR_CONSTRAINT(x) OPUS_SET_VBR_CONSTRAINT_REQUEST, __opus_check_int(x) +/** Determine if constrained VBR is enabled in the encoder. + * @see OPUS_SET_VBR_CONSTRAINT + * @see OPUS_GET_VBR + * @param[out] x opus_int32 *: Returns one of the following values: + *
    + *
    0
    Unconstrained VBR.
    + *
    1
    Constrained VBR (default).
    + *
    + * @hideinitializer */ +#define OPUS_GET_VBR_CONSTRAINT(x) OPUS_GET_VBR_CONSTRAINT_REQUEST, __opus_check_int_ptr(x) + +/** Configures mono/stereo forcing in the encoder. + * This can force the encoder to produce packets encoded as either mono or + * stereo, regardless of the format of the input audio. This is useful when + * the caller knows that the input signal is currently a mono source embedded + * in a stereo stream. + * @see OPUS_GET_FORCE_CHANNELS + * @param[in] x opus_int32: Allowed values: + *
    + *
    #OPUS_AUTO
    Not forced (default)
    + *
    1
    Forced mono
    + *
    2
    Forced stereo
    + *
    + * @hideinitializer */ +#define OPUS_SET_FORCE_CHANNELS(x) OPUS_SET_FORCE_CHANNELS_REQUEST, __opus_check_int(x) +/** Gets the encoder's forced channel configuration. + * @see OPUS_SET_FORCE_CHANNELS + * @param[out] x opus_int32 *: + *
    + *
    #OPUS_AUTO
    Not forced (default)
    + *
    1
    Forced mono
    + *
    2
    Forced stereo
    + *
    + * @hideinitializer */ +#define OPUS_GET_FORCE_CHANNELS(x) OPUS_GET_FORCE_CHANNELS_REQUEST, __opus_check_int_ptr(x) + +/** Configures the maximum bandpass that the encoder will select automatically. + * Applications should normally use this instead of #OPUS_SET_BANDWIDTH + * (leaving that set to the default, #OPUS_AUTO). This allows the + * application to set an upper bound based on the type of input it is + * providing, but still gives the encoder the freedom to reduce the bandpass + * when the bitrate becomes too low, for better overall quality. + * @see OPUS_GET_MAX_BANDWIDTH + * @param[in] x opus_int32: Allowed values: + *
    + *
    OPUS_BANDWIDTH_NARROWBAND
    4 kHz passband
    + *
    OPUS_BANDWIDTH_MEDIUMBAND
    6 kHz passband
    + *
    OPUS_BANDWIDTH_WIDEBAND
    8 kHz passband
    + *
    OPUS_BANDWIDTH_SUPERWIDEBAND
    12 kHz passband
    + *
    OPUS_BANDWIDTH_FULLBAND
    20 kHz passband (default)
    + *
    + * @hideinitializer */ +#define OPUS_SET_MAX_BANDWIDTH(x) OPUS_SET_MAX_BANDWIDTH_REQUEST, __opus_check_int(x) + +/** Gets the encoder's configured maximum allowed bandpass. + * @see OPUS_SET_MAX_BANDWIDTH + * @param[out] x opus_int32 *: Allowed values: + *
    + *
    #OPUS_BANDWIDTH_NARROWBAND
    4 kHz passband
    + *
    #OPUS_BANDWIDTH_MEDIUMBAND
    6 kHz passband
    + *
    #OPUS_BANDWIDTH_WIDEBAND
    8 kHz passband
    + *
    #OPUS_BANDWIDTH_SUPERWIDEBAND
    12 kHz passband
    + *
    #OPUS_BANDWIDTH_FULLBAND
    20 kHz passband (default)
    + *
    + * @hideinitializer */ +#define OPUS_GET_MAX_BANDWIDTH(x) OPUS_GET_MAX_BANDWIDTH_REQUEST, __opus_check_int_ptr(x) + +/** Sets the encoder's bandpass to a specific value. + * This prevents the encoder from automatically selecting the bandpass based + * on the available bitrate. If an application knows the bandpass of the input + * audio it is providing, it should normally use #OPUS_SET_MAX_BANDWIDTH + * instead, which still gives the encoder the freedom to reduce the bandpass + * when the bitrate becomes too low, for better overall quality. + * @see OPUS_GET_BANDWIDTH + * @param[in] x opus_int32: Allowed values: + *
    + *
    #OPUS_AUTO
    (default)
    + *
    #OPUS_BANDWIDTH_NARROWBAND
    4 kHz passband
    + *
    #OPUS_BANDWIDTH_MEDIUMBAND
    6 kHz passband
    + *
    #OPUS_BANDWIDTH_WIDEBAND
    8 kHz passband
    + *
    #OPUS_BANDWIDTH_SUPERWIDEBAND
    12 kHz passband
    + *
    #OPUS_BANDWIDTH_FULLBAND
    20 kHz passband
    + *
    + * @hideinitializer */ +#define OPUS_SET_BANDWIDTH(x) OPUS_SET_BANDWIDTH_REQUEST, __opus_check_int(x) + +/** Configures the type of signal being encoded. + * This is a hint which helps the encoder's mode selection. + * @see OPUS_GET_SIGNAL + * @param[in] x opus_int32: Allowed values: + *
    + *
    #OPUS_AUTO
    (default)
    + *
    #OPUS_SIGNAL_VOICE
    Bias thresholds towards choosing LPC or Hybrid modes.
    + *
    #OPUS_SIGNAL_MUSIC
    Bias thresholds towards choosing MDCT modes.
    + *
    + * @hideinitializer */ +#define OPUS_SET_SIGNAL(x) OPUS_SET_SIGNAL_REQUEST, __opus_check_int(x) +/** Gets the encoder's configured signal type. + * @see OPUS_SET_SIGNAL + * @param[out] x opus_int32 *: Returns one of the following values: + *
    + *
    #OPUS_AUTO
    (default)
    + *
    #OPUS_SIGNAL_VOICE
    Bias thresholds towards choosing LPC or Hybrid modes.
    + *
    #OPUS_SIGNAL_MUSIC
    Bias thresholds towards choosing MDCT modes.
    + *
    + * @hideinitializer */ +#define OPUS_GET_SIGNAL(x) OPUS_GET_SIGNAL_REQUEST, __opus_check_int_ptr(x) + + +/** Configures the encoder's intended application. + * The initial value is a mandatory argument to the encoder_create function. + * @see OPUS_GET_APPLICATION + * @param[in] x opus_int32: Returns one of the following values: + *
    + *
    #OPUS_APPLICATION_VOIP
    + *
    Process signal for improved speech intelligibility.
    + *
    #OPUS_APPLICATION_AUDIO
    + *
    Favor faithfulness to the original input.
    + *
    #OPUS_APPLICATION_RESTRICTED_LOWDELAY
    + *
    Configure the minimum possible coding delay by disabling certain modes + * of operation.
    + *
    + * @hideinitializer */ +#define OPUS_SET_APPLICATION(x) OPUS_SET_APPLICATION_REQUEST, __opus_check_int(x) +/** Gets the encoder's configured application. + * @see OPUS_SET_APPLICATION + * @param[out] x opus_int32 *: Returns one of the following values: + *
    + *
    #OPUS_APPLICATION_VOIP
    + *
    Process signal for improved speech intelligibility.
    + *
    #OPUS_APPLICATION_AUDIO
    + *
    Favor faithfulness to the original input.
    + *
    #OPUS_APPLICATION_RESTRICTED_LOWDELAY
    + *
    Configure the minimum possible coding delay by disabling certain modes + * of operation.
    + *
    + * @hideinitializer */ +#define OPUS_GET_APPLICATION(x) OPUS_GET_APPLICATION_REQUEST, __opus_check_int_ptr(x) + +/** Gets the total samples of delay added by the entire codec. + * This can be queried by the encoder and then the provided number of samples can be + * skipped on from the start of the decoder's output to provide time aligned input + * and output. From the perspective of a decoding application the real data begins this many + * samples late. + * + * The decoder contribution to this delay is identical for all decoders, but the + * encoder portion of the delay may vary from implementation to implementation, + * version to version, or even depend on the encoder's initial configuration. + * Applications needing delay compensation should call this CTL rather than + * hard-coding a value. + * @param[out] x opus_int32 *: Number of lookahead samples + * @hideinitializer */ +#define OPUS_GET_LOOKAHEAD(x) OPUS_GET_LOOKAHEAD_REQUEST, __opus_check_int_ptr(x) + +/** Configures the encoder's use of inband forward error correction (FEC). + * @note This is only applicable to the LPC layer + * @see OPUS_GET_INBAND_FEC + * @param[in] x opus_int32: Allowed values: + *
    + *
    0
    Disable inband FEC (default).
    + *
    1
    Enable inband FEC.
    + *
    + * @hideinitializer */ +#define OPUS_SET_INBAND_FEC(x) OPUS_SET_INBAND_FEC_REQUEST, __opus_check_int(x) +/** Gets encoder's configured use of inband forward error correction. + * @see OPUS_SET_INBAND_FEC + * @param[out] x opus_int32 *: Returns one of the following values: + *
    + *
    0
    Inband FEC disabled (default).
    + *
    1
    Inband FEC enabled.
    + *
    + * @hideinitializer */ +#define OPUS_GET_INBAND_FEC(x) OPUS_GET_INBAND_FEC_REQUEST, __opus_check_int_ptr(x) + +/** Configures the encoder's expected packet loss percentage. + * Higher values trigger progressively more loss resistant behavior in the encoder + * at the expense of quality at a given bitrate in the absence of packet loss, but + * greater quality under loss. + * @see OPUS_GET_PACKET_LOSS_PERC + * @param[in] x opus_int32: Loss percentage in the range 0-100, inclusive (default: 0). + * @hideinitializer */ +#define OPUS_SET_PACKET_LOSS_PERC(x) OPUS_SET_PACKET_LOSS_PERC_REQUEST, __opus_check_int(x) +/** Gets the encoder's configured packet loss percentage. + * @see OPUS_SET_PACKET_LOSS_PERC + * @param[out] x opus_int32 *: Returns the configured loss percentage + * in the range 0-100, inclusive (default: 0). + * @hideinitializer */ +#define OPUS_GET_PACKET_LOSS_PERC(x) OPUS_GET_PACKET_LOSS_PERC_REQUEST, __opus_check_int_ptr(x) + +/** Configures the encoder's use of discontinuous transmission (DTX). + * @note This is only applicable to the LPC layer + * @see OPUS_GET_DTX + * @param[in] x opus_int32: Allowed values: + *
    + *
    0
    Disable DTX (default).
    + *
    1
    Enabled DTX.
    + *
    + * @hideinitializer */ +#define OPUS_SET_DTX(x) OPUS_SET_DTX_REQUEST, __opus_check_int(x) +/** Gets encoder's configured use of discontinuous transmission. + * @see OPUS_SET_DTX + * @param[out] x opus_int32 *: Returns one of the following values: + *
    + *
    0
    DTX disabled (default).
    + *
    1
    DTX enabled.
    + *
    + * @hideinitializer */ +#define OPUS_GET_DTX(x) OPUS_GET_DTX_REQUEST, __opus_check_int_ptr(x) +/** Configures the depth of signal being encoded. + * + * This is a hint which helps the encoder identify silence and near-silence. + * It represents the number of significant bits of linear intensity below + * which the signal contains ignorable quantization or other noise. + * + * For example, OPUS_SET_LSB_DEPTH(14) would be an appropriate setting + * for G.711 u-law input. OPUS_SET_LSB_DEPTH(16) would be appropriate + * for 16-bit linear pcm input with opus_encode_float(). + * + * When using opus_encode() instead of opus_encode_float(), or when libopus + * is compiled for fixed-point, the encoder uses the minimum of the value + * set here and the value 16. + * + * @see OPUS_GET_LSB_DEPTH + * @param[in] x opus_int32: Input precision in bits, between 8 and 24 + * (default: 24). + * @hideinitializer */ +#define OPUS_SET_LSB_DEPTH(x) OPUS_SET_LSB_DEPTH_REQUEST, __opus_check_int(x) +/** Gets the encoder's configured signal depth. + * @see OPUS_SET_LSB_DEPTH + * @param[out] x opus_int32 *: Input precision in bits, between 8 and + * 24 (default: 24). + * @hideinitializer */ +#define OPUS_GET_LSB_DEPTH(x) OPUS_GET_LSB_DEPTH_REQUEST, __opus_check_int_ptr(x) + +/** Configures the encoder's use of variable duration frames. + * When variable duration is enabled, the encoder is free to use a shorter frame + * size than the one requested in the opus_encode*() call. + * It is then the user's responsibility + * to verify how much audio was encoded by checking the ToC byte of the encoded + * packet. The part of the audio that was not encoded needs to be resent to the + * encoder for the next call. Do not use this option unless you really + * know what you are doing. + * @see OPUS_GET_EXPERT_FRAME_DURATION + * @param[in] x opus_int32: Allowed values: + *
    + *
    OPUS_FRAMESIZE_ARG
    Select frame size from the argument (default).
    + *
    OPUS_FRAMESIZE_2_5_MS
    Use 2.5 ms frames.
    + *
    OPUS_FRAMESIZE_5_MS
    Use 5 ms frames.
    + *
    OPUS_FRAMESIZE_10_MS
    Use 10 ms frames.
    + *
    OPUS_FRAMESIZE_20_MS
    Use 20 ms frames.
    + *
    OPUS_FRAMESIZE_40_MS
    Use 40 ms frames.
    + *
    OPUS_FRAMESIZE_60_MS
    Use 60 ms frames.
    + *
    OPUS_FRAMESIZE_80_MS
    Use 80 ms frames.
    + *
    OPUS_FRAMESIZE_100_MS
    Use 100 ms frames.
    + *
    OPUS_FRAMESIZE_120_MS
    Use 120 ms frames.
    + *
    + * @hideinitializer */ +#define OPUS_SET_EXPERT_FRAME_DURATION(x) OPUS_SET_EXPERT_FRAME_DURATION_REQUEST, __opus_check_int(x) +/** Gets the encoder's configured use of variable duration frames. + * @see OPUS_SET_EXPERT_FRAME_DURATION + * @param[out] x opus_int32 *: Returns one of the following values: + *
    + *
    OPUS_FRAMESIZE_ARG
    Select frame size from the argument (default).
    + *
    OPUS_FRAMESIZE_2_5_MS
    Use 2.5 ms frames.
    + *
    OPUS_FRAMESIZE_5_MS
    Use 5 ms frames.
    + *
    OPUS_FRAMESIZE_10_MS
    Use 10 ms frames.
    + *
    OPUS_FRAMESIZE_20_MS
    Use 20 ms frames.
    + *
    OPUS_FRAMESIZE_40_MS
    Use 40 ms frames.
    + *
    OPUS_FRAMESIZE_60_MS
    Use 60 ms frames.
    + *
    OPUS_FRAMESIZE_80_MS
    Use 80 ms frames.
    + *
    OPUS_FRAMESIZE_100_MS
    Use 100 ms frames.
    + *
    OPUS_FRAMESIZE_120_MS
    Use 120 ms frames.
    + *
    + * @hideinitializer */ +#define OPUS_GET_EXPERT_FRAME_DURATION(x) OPUS_GET_EXPERT_FRAME_DURATION_REQUEST, __opus_check_int_ptr(x) + +/** If set to 1, disables almost all use of prediction, making frames almost + * completely independent. This reduces quality. + * @see OPUS_GET_PREDICTION_DISABLED + * @param[in] x opus_int32: Allowed values: + *
    + *
    0
    Enable prediction (default).
    + *
    1
    Disable prediction.
    + *
    + * @hideinitializer */ +#define OPUS_SET_PREDICTION_DISABLED(x) OPUS_SET_PREDICTION_DISABLED_REQUEST, __opus_check_int(x) +/** Gets the encoder's configured prediction status. + * @see OPUS_SET_PREDICTION_DISABLED + * @param[out] x opus_int32 *: Returns one of the following values: + *
    + *
    0
    Prediction enabled (default).
    + *
    1
    Prediction disabled.
    + *
    + * @hideinitializer */ +#define OPUS_GET_PREDICTION_DISABLED(x) OPUS_GET_PREDICTION_DISABLED_REQUEST, __opus_check_int_ptr(x) + +/**@}*/ + +/** @defgroup opus_genericctls Generic CTLs + * + * These macros are used with the \c opus_decoder_ctl and + * \c opus_encoder_ctl calls to generate a particular + * request. + * + * When called on an \c OpusDecoder they apply to that + * particular decoder instance. When called on an + * \c OpusEncoder they apply to the corresponding setting + * on that encoder instance, if present. + * + * Some usage examples: + * + * @code + * int ret; + * opus_int32 pitch; + * ret = opus_decoder_ctl(dec_ctx, OPUS_GET_PITCH(&pitch)); + * if (ret == OPUS_OK) return ret; + * + * opus_encoder_ctl(enc_ctx, OPUS_RESET_STATE); + * opus_decoder_ctl(dec_ctx, OPUS_RESET_STATE); + * + * opus_int32 enc_bw, dec_bw; + * opus_encoder_ctl(enc_ctx, OPUS_GET_BANDWIDTH(&enc_bw)); + * opus_decoder_ctl(dec_ctx, OPUS_GET_BANDWIDTH(&dec_bw)); + * if (enc_bw != dec_bw) { + * printf("packet bandwidth mismatch!\n"); + * } + * @endcode + * + * @see opus_encoder, opus_decoder_ctl, opus_encoder_ctl, opus_decoderctls, opus_encoderctls + * @{ + */ + +/** Resets the codec state to be equivalent to a freshly initialized state. + * This should be called when switching streams in order to prevent + * the back to back decoding from giving different results from + * one at a time decoding. + * @hideinitializer */ +#define OPUS_RESET_STATE 4028 + +/** Gets the final state of the codec's entropy coder. + * This is used for testing purposes, + * The encoder and decoder state should be identical after coding a payload + * (assuming no data corruption or software bugs) + * + * @param[out] x opus_uint32 *: Entropy coder state + * + * @hideinitializer */ +#define OPUS_GET_FINAL_RANGE(x) OPUS_GET_FINAL_RANGE_REQUEST, __opus_check_uint_ptr(x) + +/** Gets the encoder's configured bandpass or the decoder's last bandpass. + * @see OPUS_SET_BANDWIDTH + * @param[out] x opus_int32 *: Returns one of the following values: + *
    + *
    #OPUS_AUTO
    (default)
    + *
    #OPUS_BANDWIDTH_NARROWBAND
    4 kHz passband
    + *
    #OPUS_BANDWIDTH_MEDIUMBAND
    6 kHz passband
    + *
    #OPUS_BANDWIDTH_WIDEBAND
    8 kHz passband
    + *
    #OPUS_BANDWIDTH_SUPERWIDEBAND
    12 kHz passband
    + *
    #OPUS_BANDWIDTH_FULLBAND
    20 kHz passband
    + *
    + * @hideinitializer */ +#define OPUS_GET_BANDWIDTH(x) OPUS_GET_BANDWIDTH_REQUEST, __opus_check_int_ptr(x) + +/** Gets the sampling rate the encoder or decoder was initialized with. + * This simply returns the Fs value passed to opus_encoder_init() + * or opus_decoder_init(). + * @param[out] x opus_int32 *: Sampling rate of encoder or decoder. + * @hideinitializer + */ +#define OPUS_GET_SAMPLE_RATE(x) OPUS_GET_SAMPLE_RATE_REQUEST, __opus_check_int_ptr(x) + +/** If set to 1, disables the use of phase inversion for intensity stereo, + * improving the quality of mono downmixes, but slightly reducing normal + * stereo quality. Disabling phase inversion in the decoder does not comply + * with RFC 6716, although it does not cause any interoperability issue and + * is expected to become part of the Opus standard once RFC 6716 is updated + * by draft-ietf-codec-opus-update. + * @see OPUS_GET_PHASE_INVERSION_DISABLED + * @param[in] x opus_int32: Allowed values: + *
    + *
    0
    Enable phase inversion (default).
    + *
    1
    Disable phase inversion.
    + *
    + * @hideinitializer */ +#define OPUS_SET_PHASE_INVERSION_DISABLED(x) OPUS_SET_PHASE_INVERSION_DISABLED_REQUEST, __opus_check_int(x) +/** Gets the encoder's configured phase inversion status. + * @see OPUS_SET_PHASE_INVERSION_DISABLED + * @param[out] x opus_int32 *: Returns one of the following values: + *
    + *
    0
    Stereo phase inversion enabled (default).
    + *
    1
    Stereo phase inversion disabled.
    + *
    + * @hideinitializer */ +#define OPUS_GET_PHASE_INVERSION_DISABLED(x) OPUS_GET_PHASE_INVERSION_DISABLED_REQUEST, __opus_check_int_ptr(x) +/** Gets the DTX state of the encoder. + * Returns whether the last encoded frame was either a comfort noise update + * during DTX or not encoded because of DTX. + * @param[out] x opus_int32 *: Returns one of the following values: + *
    + *
    0
    The encoder is not in DTX.
    + *
    1
    The encoder is in DTX.
    + *
    + * @hideinitializer */ +#define OPUS_GET_IN_DTX(x) OPUS_GET_IN_DTX_REQUEST, __opus_check_int_ptr(x) + +/**@}*/ + +/** @defgroup opus_decoderctls Decoder related CTLs + * @see opus_genericctls, opus_encoderctls, opus_decoder + * @{ + */ + +/** Configures decoder gain adjustment. + * Scales the decoded output by a factor specified in Q8 dB units. + * This has a maximum range of -32768 to 32767 inclusive, and returns + * OPUS_BAD_ARG otherwise. The default is zero indicating no adjustment. + * This setting survives decoder reset. + * + * gain = pow(10, x/(20.0*256)) + * + * @param[in] x opus_int32: Amount to scale PCM signal by in Q8 dB units. + * @hideinitializer */ +#define OPUS_SET_GAIN(x) OPUS_SET_GAIN_REQUEST, __opus_check_int(x) +/** Gets the decoder's configured gain adjustment. @see OPUS_SET_GAIN + * + * @param[out] x opus_int32 *: Amount to scale PCM signal by in Q8 dB units. + * @hideinitializer */ +#define OPUS_GET_GAIN(x) OPUS_GET_GAIN_REQUEST, __opus_check_int_ptr(x) + +/** Gets the duration (in samples) of the last packet successfully decoded or concealed. + * @param[out] x opus_int32 *: Number of samples (at current sampling rate). + * @hideinitializer */ +#define OPUS_GET_LAST_PACKET_DURATION(x) OPUS_GET_LAST_PACKET_DURATION_REQUEST, __opus_check_int_ptr(x) + +/** Gets the pitch of the last decoded frame, if available. + * This can be used for any post-processing algorithm requiring the use of pitch, + * e.g. time stretching/shortening. If the last frame was not voiced, or if the + * pitch was not coded in the frame, then zero is returned. + * + * This CTL is only implemented for decoder instances. + * + * @param[out] x opus_int32 *: pitch period at 48 kHz (or 0 if not available) + * + * @hideinitializer */ +#define OPUS_GET_PITCH(x) OPUS_GET_PITCH_REQUEST, __opus_check_int_ptr(x) + +/**@}*/ + +/** @defgroup opus_libinfo Opus library information functions + * @{ + */ + +/** Converts an opus error code into a human readable string. + * + * @param[in] error int: Error number + * @returns Error string + */ +OPUS_EXPORT const char *opus_strerror(int error); + +/** Gets the libopus version string. + * + * Applications may look for the substring "-fixed" in the version string to + * determine whether they have a fixed-point or floating-point build at + * runtime. + * + * @returns Version string + */ +OPUS_EXPORT const char *opus_get_version_string(void); +/**@}*/ + +#ifdef __cplusplus +} +#endif + +#endif /* OPUS_DEFINES_H */ diff --git a/extern/opus/include/opus_multistream.h b/extern/opus/include/opus_multistream.h new file mode 100644 index 0000000..babcee6 --- /dev/null +++ b/extern/opus/include/opus_multistream.h @@ -0,0 +1,660 @@ +/* Copyright (c) 2011 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + 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. + + 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 OWNER + 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. +*/ + +/** + * @file opus_multistream.h + * @brief Opus reference implementation multistream API + */ + +#ifndef OPUS_MULTISTREAM_H +#define OPUS_MULTISTREAM_H + +#include "opus.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** @cond OPUS_INTERNAL_DOC */ + +/** Macros to trigger compilation errors when the wrong types are provided to a + * CTL. */ +/**@{*/ +#define __opus_check_encstate_ptr(ptr) ((ptr) + ((ptr) - (OpusEncoder**)(ptr))) +#define __opus_check_decstate_ptr(ptr) ((ptr) + ((ptr) - (OpusDecoder**)(ptr))) +/**@}*/ + +/** These are the actual encoder and decoder CTL ID numbers. + * They should not be used directly by applications. + * In general, SETs should be even and GETs should be odd.*/ +/**@{*/ +#define OPUS_MULTISTREAM_GET_ENCODER_STATE_REQUEST 5120 +#define OPUS_MULTISTREAM_GET_DECODER_STATE_REQUEST 5122 +/**@}*/ + +/** @endcond */ + +/** @defgroup opus_multistream_ctls Multistream specific encoder and decoder CTLs + * + * These are convenience macros that are specific to the + * opus_multistream_encoder_ctl() and opus_multistream_decoder_ctl() + * interface. + * The CTLs from @ref opus_genericctls, @ref opus_encoderctls, and + * @ref opus_decoderctls may be applied to a multistream encoder or decoder as + * well. + * In addition, you may retrieve the encoder or decoder state for an specific + * stream via #OPUS_MULTISTREAM_GET_ENCODER_STATE or + * #OPUS_MULTISTREAM_GET_DECODER_STATE and apply CTLs to it individually. + */ +/**@{*/ + +/** Gets the encoder state for an individual stream of a multistream encoder. + * @param[in] x opus_int32: The index of the stream whose encoder you + * wish to retrieve. + * This must be non-negative and less than + * the streams parameter used + * to initialize the encoder. + * @param[out] y OpusEncoder**: Returns a pointer to the given + * encoder state. + * @retval OPUS_BAD_ARG The index of the requested stream was out of range. + * @hideinitializer + */ +#define OPUS_MULTISTREAM_GET_ENCODER_STATE(x,y) OPUS_MULTISTREAM_GET_ENCODER_STATE_REQUEST, __opus_check_int(x), __opus_check_encstate_ptr(y) + +/** Gets the decoder state for an individual stream of a multistream decoder. + * @param[in] x opus_int32: The index of the stream whose decoder you + * wish to retrieve. + * This must be non-negative and less than + * the streams parameter used + * to initialize the decoder. + * @param[out] y OpusDecoder**: Returns a pointer to the given + * decoder state. + * @retval OPUS_BAD_ARG The index of the requested stream was out of range. + * @hideinitializer + */ +#define OPUS_MULTISTREAM_GET_DECODER_STATE(x,y) OPUS_MULTISTREAM_GET_DECODER_STATE_REQUEST, __opus_check_int(x), __opus_check_decstate_ptr(y) + +/**@}*/ + +/** @defgroup opus_multistream Opus Multistream API + * @{ + * + * The multistream API allows individual Opus streams to be combined into a + * single packet, enabling support for up to 255 channels. Unlike an + * elementary Opus stream, the encoder and decoder must negotiate the channel + * configuration before the decoder can successfully interpret the data in the + * packets produced by the encoder. Some basic information, such as packet + * duration, can be computed without any special negotiation. + * + * The format for multistream Opus packets is defined in + * RFC 7845 + * and is based on the self-delimited Opus framing described in Appendix B of + * RFC 6716. + * Normal Opus packets are just a degenerate case of multistream Opus packets, + * and can be encoded or decoded with the multistream API by setting + * streams to 1 when initializing the encoder or + * decoder. + * + * Multistream Opus streams can contain up to 255 elementary Opus streams. + * These may be either "uncoupled" or "coupled", indicating that the decoder + * is configured to decode them to either 1 or 2 channels, respectively. + * The streams are ordered so that all coupled streams appear at the + * beginning. + * + * A mapping table defines which decoded channel i + * should be used for each input/output (I/O) channel j. This table is + * typically provided as an unsigned char array. + * Let i = mapping[j] be the index for I/O channel j. + * If i < 2*coupled_streams, then I/O channel j is + * encoded as the left channel of stream (i/2) if i + * is even, or as the right channel of stream (i/2) if + * i is odd. Otherwise, I/O channel j is encoded as + * mono in stream (i - coupled_streams), unless it has the special + * value 255, in which case it is omitted from the encoding entirely (the + * decoder will reproduce it as silence). Each value i must either + * be the special value 255 or be less than streams + coupled_streams. + * + * The output channels specified by the encoder + * should use the + * Vorbis + * channel ordering. A decoder may wish to apply an additional permutation + * to the mapping the encoder used to achieve a different output channel + * order (e.g. for outputing in WAV order). + * + * Each multistream packet contains an Opus packet for each stream, and all of + * the Opus packets in a single multistream packet must have the same + * duration. Therefore the duration of a multistream packet can be extracted + * from the TOC sequence of the first stream, which is located at the + * beginning of the packet, just like an elementary Opus stream: + * + * @code + * int nb_samples; + * int nb_frames; + * nb_frames = opus_packet_get_nb_frames(data, len); + * if (nb_frames < 1) + * return nb_frames; + * nb_samples = opus_packet_get_samples_per_frame(data, 48000) * nb_frames; + * @endcode + * + * The general encoding and decoding process proceeds exactly the same as in + * the normal @ref opus_encoder and @ref opus_decoder APIs. + * See their documentation for an overview of how to use the corresponding + * multistream functions. + */ + +/** Opus multistream encoder state. + * This contains the complete state of a multistream Opus encoder. + * It is position independent and can be freely copied. + * @see opus_multistream_encoder_create + * @see opus_multistream_encoder_init + */ +typedef struct OpusMSEncoder OpusMSEncoder; + +/** Opus multistream decoder state. + * This contains the complete state of a multistream Opus decoder. + * It is position independent and can be freely copied. + * @see opus_multistream_decoder_create + * @see opus_multistream_decoder_init + */ +typedef struct OpusMSDecoder OpusMSDecoder; + +/**\name Multistream encoder functions */ +/**@{*/ + +/** Gets the size of an OpusMSEncoder structure. + * @param streams int: The total number of streams to encode from the + * input. + * This must be no more than 255. + * @param coupled_streams int: Number of coupled (2 channel) streams + * to encode. + * This must be no larger than the total + * number of streams. + * Additionally, The total number of + * encoded channels (streams + + * coupled_streams) must be no + * more than 255. + * @returns The size in bytes on success, or a negative error code + * (see @ref opus_errorcodes) on error. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_multistream_encoder_get_size( + int streams, + int coupled_streams +); + +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_multistream_surround_encoder_get_size( + int channels, + int mapping_family +); + + +/** Allocates and initializes a multistream encoder state. + * Call opus_multistream_encoder_destroy() to release + * this object when finished. + * @param Fs opus_int32: Sampling rate of the input signal (in Hz). + * This must be one of 8000, 12000, 16000, + * 24000, or 48000. + * @param channels int: Number of channels in the input signal. + * This must be at most 255. + * It may be greater than the number of + * coded channels (streams + + * coupled_streams). + * @param streams int: The total number of streams to encode from the + * input. + * This must be no more than the number of channels. + * @param coupled_streams int: Number of coupled (2 channel) streams + * to encode. + * This must be no larger than the total + * number of streams. + * Additionally, The total number of + * encoded channels (streams + + * coupled_streams) must be no + * more than the number of input channels. + * @param[in] mapping const unsigned char[channels]: Mapping from + * encoded channels to input channels, as described in + * @ref opus_multistream. As an extra constraint, the + * multistream encoder does not allow encoding coupled + * streams for which one channel is unused since this + * is never a good idea. + * @param application int: The target encoder application. + * This must be one of the following: + *
    + *
    #OPUS_APPLICATION_VOIP
    + *
    Process signal for improved speech intelligibility.
    + *
    #OPUS_APPLICATION_AUDIO
    + *
    Favor faithfulness to the original input.
    + *
    #OPUS_APPLICATION_RESTRICTED_LOWDELAY
    + *
    Configure the minimum possible coding delay by disabling certain modes + * of operation.
    + *
    + * @param[out] error int *: Returns #OPUS_OK on success, or an error + * code (see @ref opus_errorcodes) on + * failure. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT OpusMSEncoder *opus_multistream_encoder_create( + opus_int32 Fs, + int channels, + int streams, + int coupled_streams, + const unsigned char *mapping, + int application, + int *error +) OPUS_ARG_NONNULL(5); + +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT OpusMSEncoder *opus_multistream_surround_encoder_create( + opus_int32 Fs, + int channels, + int mapping_family, + int *streams, + int *coupled_streams, + unsigned char *mapping, + int application, + int *error +) OPUS_ARG_NONNULL(4) OPUS_ARG_NONNULL(5) OPUS_ARG_NONNULL(6); + +/** Initialize a previously allocated multistream encoder state. + * The memory pointed to by \a st must be at least the size returned by + * opus_multistream_encoder_get_size(). + * This is intended for applications which use their own allocator instead of + * malloc. + * To reset a previously initialized state, use the #OPUS_RESET_STATE CTL. + * @see opus_multistream_encoder_create + * @see opus_multistream_encoder_get_size + * @param st OpusMSEncoder*: Multistream encoder state to initialize. + * @param Fs opus_int32: Sampling rate of the input signal (in Hz). + * This must be one of 8000, 12000, 16000, + * 24000, or 48000. + * @param channels int: Number of channels in the input signal. + * This must be at most 255. + * It may be greater than the number of + * coded channels (streams + + * coupled_streams). + * @param streams int: The total number of streams to encode from the + * input. + * This must be no more than the number of channels. + * @param coupled_streams int: Number of coupled (2 channel) streams + * to encode. + * This must be no larger than the total + * number of streams. + * Additionally, The total number of + * encoded channels (streams + + * coupled_streams) must be no + * more than the number of input channels. + * @param[in] mapping const unsigned char[channels]: Mapping from + * encoded channels to input channels, as described in + * @ref opus_multistream. As an extra constraint, the + * multistream encoder does not allow encoding coupled + * streams for which one channel is unused since this + * is never a good idea. + * @param application int: The target encoder application. + * This must be one of the following: + *
    + *
    #OPUS_APPLICATION_VOIP
    + *
    Process signal for improved speech intelligibility.
    + *
    #OPUS_APPLICATION_AUDIO
    + *
    Favor faithfulness to the original input.
    + *
    #OPUS_APPLICATION_RESTRICTED_LOWDELAY
    + *
    Configure the minimum possible coding delay by disabling certain modes + * of operation.
    + *
    + * @returns #OPUS_OK on success, or an error code (see @ref opus_errorcodes) + * on failure. + */ +OPUS_EXPORT int opus_multistream_encoder_init( + OpusMSEncoder *st, + opus_int32 Fs, + int channels, + int streams, + int coupled_streams, + const unsigned char *mapping, + int application +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(6); + +OPUS_EXPORT int opus_multistream_surround_encoder_init( + OpusMSEncoder *st, + opus_int32 Fs, + int channels, + int mapping_family, + int *streams, + int *coupled_streams, + unsigned char *mapping, + int application +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(5) OPUS_ARG_NONNULL(6) OPUS_ARG_NONNULL(7); + +/** Encodes a multistream Opus frame. + * @param st OpusMSEncoder*: Multistream encoder state. + * @param[in] pcm const opus_int16*: The input signal as interleaved + * samples. + * This must contain + * frame_size*channels + * samples. + * @param frame_size int: Number of samples per channel in the input + * signal. + * This must be an Opus frame size for the + * encoder's sampling rate. + * For example, at 48 kHz the permitted values + * are 120, 240, 480, 960, 1920, and 2880. + * Passing in a duration of less than 10 ms + * (480 samples at 48 kHz) will prevent the + * encoder from using the LPC or hybrid modes. + * @param[out] data unsigned char*: Output payload. + * This must contain storage for at + * least \a max_data_bytes. + * @param [in] max_data_bytes opus_int32: Size of the allocated + * memory for the output + * payload. This may be + * used to impose an upper limit on + * the instant bitrate, but should + * not be used as the only bitrate + * control. Use #OPUS_SET_BITRATE to + * control the bitrate. + * @returns The length of the encoded packet (in bytes) on success or a + * negative error code (see @ref opus_errorcodes) on failure. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_multistream_encode( + OpusMSEncoder *st, + const opus_int16 *pcm, + int frame_size, + unsigned char *data, + opus_int32 max_data_bytes +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2) OPUS_ARG_NONNULL(4); + +/** Encodes a multistream Opus frame from floating point input. + * @param st OpusMSEncoder*: Multistream encoder state. + * @param[in] pcm const float*: The input signal as interleaved + * samples with a normal range of + * +/-1.0. + * Samples with a range beyond +/-1.0 + * are supported but will be clipped by + * decoders using the integer API and + * should only be used if it is known + * that the far end supports extended + * dynamic range. + * This must contain + * frame_size*channels + * samples. + * @param frame_size int: Number of samples per channel in the input + * signal. + * This must be an Opus frame size for the + * encoder's sampling rate. + * For example, at 48 kHz the permitted values + * are 120, 240, 480, 960, 1920, and 2880. + * Passing in a duration of less than 10 ms + * (480 samples at 48 kHz) will prevent the + * encoder from using the LPC or hybrid modes. + * @param[out] data unsigned char*: Output payload. + * This must contain storage for at + * least \a max_data_bytes. + * @param [in] max_data_bytes opus_int32: Size of the allocated + * memory for the output + * payload. This may be + * used to impose an upper limit on + * the instant bitrate, but should + * not be used as the only bitrate + * control. Use #OPUS_SET_BITRATE to + * control the bitrate. + * @returns The length of the encoded packet (in bytes) on success or a + * negative error code (see @ref opus_errorcodes) on failure. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_multistream_encode_float( + OpusMSEncoder *st, + const float *pcm, + int frame_size, + unsigned char *data, + opus_int32 max_data_bytes +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2) OPUS_ARG_NONNULL(4); + +/** Frees an OpusMSEncoder allocated by + * opus_multistream_encoder_create(). + * @param st OpusMSEncoder*: Multistream encoder state to be freed. + */ +OPUS_EXPORT void opus_multistream_encoder_destroy(OpusMSEncoder *st); + +/** Perform a CTL function on a multistream Opus encoder. + * + * Generally the request and subsequent arguments are generated by a + * convenience macro. + * @param st OpusMSEncoder*: Multistream encoder state. + * @param request This and all remaining parameters should be replaced by one + * of the convenience macros in @ref opus_genericctls, + * @ref opus_encoderctls, or @ref opus_multistream_ctls. + * @see opus_genericctls + * @see opus_encoderctls + * @see opus_multistream_ctls + */ +OPUS_EXPORT int opus_multistream_encoder_ctl(OpusMSEncoder *st, int request, ...) OPUS_ARG_NONNULL(1); + +/**@}*/ + +/**\name Multistream decoder functions */ +/**@{*/ + +/** Gets the size of an OpusMSDecoder structure. + * @param streams int: The total number of streams coded in the + * input. + * This must be no more than 255. + * @param coupled_streams int: Number streams to decode as coupled + * (2 channel) streams. + * This must be no larger than the total + * number of streams. + * Additionally, The total number of + * coded channels (streams + + * coupled_streams) must be no + * more than 255. + * @returns The size in bytes on success, or a negative error code + * (see @ref opus_errorcodes) on error. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_multistream_decoder_get_size( + int streams, + int coupled_streams +); + +/** Allocates and initializes a multistream decoder state. + * Call opus_multistream_decoder_destroy() to release + * this object when finished. + * @param Fs opus_int32: Sampling rate to decode at (in Hz). + * This must be one of 8000, 12000, 16000, + * 24000, or 48000. + * @param channels int: Number of channels to output. + * This must be at most 255. + * It may be different from the number of coded + * channels (streams + + * coupled_streams). + * @param streams int: The total number of streams coded in the + * input. + * This must be no more than 255. + * @param coupled_streams int: Number of streams to decode as coupled + * (2 channel) streams. + * This must be no larger than the total + * number of streams. + * Additionally, The total number of + * coded channels (streams + + * coupled_streams) must be no + * more than 255. + * @param[in] mapping const unsigned char[channels]: Mapping from + * coded channels to output channels, as described in + * @ref opus_multistream. + * @param[out] error int *: Returns #OPUS_OK on success, or an error + * code (see @ref opus_errorcodes) on + * failure. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT OpusMSDecoder *opus_multistream_decoder_create( + opus_int32 Fs, + int channels, + int streams, + int coupled_streams, + const unsigned char *mapping, + int *error +) OPUS_ARG_NONNULL(5); + +/** Intialize a previously allocated decoder state object. + * The memory pointed to by \a st must be at least the size returned by + * opus_multistream_encoder_get_size(). + * This is intended for applications which use their own allocator instead of + * malloc. + * To reset a previously initialized state, use the #OPUS_RESET_STATE CTL. + * @see opus_multistream_decoder_create + * @see opus_multistream_deocder_get_size + * @param st OpusMSEncoder*: Multistream encoder state to initialize. + * @param Fs opus_int32: Sampling rate to decode at (in Hz). + * This must be one of 8000, 12000, 16000, + * 24000, or 48000. + * @param channels int: Number of channels to output. + * This must be at most 255. + * It may be different from the number of coded + * channels (streams + + * coupled_streams). + * @param streams int: The total number of streams coded in the + * input. + * This must be no more than 255. + * @param coupled_streams int: Number of streams to decode as coupled + * (2 channel) streams. + * This must be no larger than the total + * number of streams. + * Additionally, The total number of + * coded channels (streams + + * coupled_streams) must be no + * more than 255. + * @param[in] mapping const unsigned char[channels]: Mapping from + * coded channels to output channels, as described in + * @ref opus_multistream. + * @returns #OPUS_OK on success, or an error code (see @ref opus_errorcodes) + * on failure. + */ +OPUS_EXPORT int opus_multistream_decoder_init( + OpusMSDecoder *st, + opus_int32 Fs, + int channels, + int streams, + int coupled_streams, + const unsigned char *mapping +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(6); + +/** Decode a multistream Opus packet. + * @param st OpusMSDecoder*: Multistream decoder state. + * @param[in] data const unsigned char*: Input payload. + * Use a NULL + * pointer to indicate packet + * loss. + * @param len opus_int32: Number of bytes in payload. + * @param[out] pcm opus_int16*: Output signal, with interleaved + * samples. + * This must contain room for + * frame_size*channels + * samples. + * @param frame_size int: The number of samples per channel of + * available space in \a pcm. + * If this is less than the maximum packet duration + * (120 ms; 5760 for 48kHz), this function will not be capable + * of decoding some packets. In the case of PLC (data==NULL) + * or FEC (decode_fec=1), then frame_size needs to be exactly + * the duration of audio that is missing, otherwise the + * decoder will not be in the optimal state to decode the + * next incoming packet. For the PLC and FEC cases, frame_size + * must be a multiple of 2.5 ms. + * @param decode_fec int: Flag (0 or 1) to request that any in-band + * forward error correction data be decoded. + * If no such data is available, the frame is + * decoded as if it were lost. + * @returns Number of samples decoded on success or a negative error code + * (see @ref opus_errorcodes) on failure. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_multistream_decode( + OpusMSDecoder *st, + const unsigned char *data, + opus_int32 len, + opus_int16 *pcm, + int frame_size, + int decode_fec +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4); + +/** Decode a multistream Opus packet with floating point output. + * @param st OpusMSDecoder*: Multistream decoder state. + * @param[in] data const unsigned char*: Input payload. + * Use a NULL + * pointer to indicate packet + * loss. + * @param len opus_int32: Number of bytes in payload. + * @param[out] pcm opus_int16*: Output signal, with interleaved + * samples. + * This must contain room for + * frame_size*channels + * samples. + * @param frame_size int: The number of samples per channel of + * available space in \a pcm. + * If this is less than the maximum packet duration + * (120 ms; 5760 for 48kHz), this function will not be capable + * of decoding some packets. In the case of PLC (data==NULL) + * or FEC (decode_fec=1), then frame_size needs to be exactly + * the duration of audio that is missing, otherwise the + * decoder will not be in the optimal state to decode the + * next incoming packet. For the PLC and FEC cases, frame_size + * must be a multiple of 2.5 ms. + * @param decode_fec int: Flag (0 or 1) to request that any in-band + * forward error correction data be decoded. + * If no such data is available, the frame is + * decoded as if it were lost. + * @returns Number of samples decoded on success or a negative error code + * (see @ref opus_errorcodes) on failure. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_multistream_decode_float( + OpusMSDecoder *st, + const unsigned char *data, + opus_int32 len, + float *pcm, + int frame_size, + int decode_fec +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4); + +/** Perform a CTL function on a multistream Opus decoder. + * + * Generally the request and subsequent arguments are generated by a + * convenience macro. + * @param st OpusMSDecoder*: Multistream decoder state. + * @param request This and all remaining parameters should be replaced by one + * of the convenience macros in @ref opus_genericctls, + * @ref opus_decoderctls, or @ref opus_multistream_ctls. + * @see opus_genericctls + * @see opus_decoderctls + * @see opus_multistream_ctls + */ +OPUS_EXPORT int opus_multistream_decoder_ctl(OpusMSDecoder *st, int request, ...) OPUS_ARG_NONNULL(1); + +/** Frees an OpusMSDecoder allocated by + * opus_multistream_decoder_create(). + * @param st OpusMSDecoder: Multistream decoder state to be freed. + */ +OPUS_EXPORT void opus_multistream_decoder_destroy(OpusMSDecoder *st); + +/**@}*/ + +/**@}*/ + +#ifdef __cplusplus +} +#endif + +#endif /* OPUS_MULTISTREAM_H */ diff --git a/extern/opus/include/opus_projection.h b/extern/opus/include/opus_projection.h new file mode 100644 index 0000000..9dabf4e --- /dev/null +++ b/extern/opus/include/opus_projection.h @@ -0,0 +1,568 @@ +/* Copyright (c) 2017 Google Inc. + Written by Andrew Allen */ +/* + 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. + + 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 OWNER + 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. +*/ + +/** + * @file opus_projection.h + * @brief Opus projection reference API + */ + +#ifndef OPUS_PROJECTION_H +#define OPUS_PROJECTION_H + +#include "opus_multistream.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** @cond OPUS_INTERNAL_DOC */ + +/** These are the actual encoder and decoder CTL ID numbers. + * They should not be used directly by applications.c + * In general, SETs should be even and GETs should be odd.*/ +/**@{*/ +#define OPUS_PROJECTION_GET_DEMIXING_MATRIX_GAIN_REQUEST 6001 +#define OPUS_PROJECTION_GET_DEMIXING_MATRIX_SIZE_REQUEST 6003 +#define OPUS_PROJECTION_GET_DEMIXING_MATRIX_REQUEST 6005 +/**@}*/ + + +/** @endcond */ + +/** @defgroup opus_projection_ctls Projection specific encoder and decoder CTLs + * + * These are convenience macros that are specific to the + * opus_projection_encoder_ctl() and opus_projection_decoder_ctl() + * interface. + * The CTLs from @ref opus_genericctls, @ref opus_encoderctls, + * @ref opus_decoderctls, and @ref opus_multistream_ctls may be applied to a + * projection encoder or decoder as well. + */ +/**@{*/ + +/** Gets the gain (in dB. S7.8-format) of the demixing matrix from the encoder. + * @param[out] x opus_int32 *: Returns the gain (in dB. S7.8-format) + * of the demixing matrix. + * @hideinitializer + */ +#define OPUS_PROJECTION_GET_DEMIXING_MATRIX_GAIN(x) OPUS_PROJECTION_GET_DEMIXING_MATRIX_GAIN_REQUEST, __opus_check_int_ptr(x) + + +/** Gets the size in bytes of the demixing matrix from the encoder. + * @param[out] x opus_int32 *: Returns the size in bytes of the + * demixing matrix. + * @hideinitializer + */ +#define OPUS_PROJECTION_GET_DEMIXING_MATRIX_SIZE(x) OPUS_PROJECTION_GET_DEMIXING_MATRIX_SIZE_REQUEST, __opus_check_int_ptr(x) + + +/** Copies the demixing matrix to the supplied pointer location. + * @param[out] x unsigned char *: Returns the demixing matrix to the + * supplied pointer location. + * @param y opus_int32: The size in bytes of the reserved memory at the + * pointer location. + * @hideinitializer + */ +#define OPUS_PROJECTION_GET_DEMIXING_MATRIX(x,y) OPUS_PROJECTION_GET_DEMIXING_MATRIX_REQUEST, x, __opus_check_int(y) + + +/**@}*/ + +/** Opus projection encoder state. + * This contains the complete state of a projection Opus encoder. + * It is position independent and can be freely copied. + * @see opus_projection_ambisonics_encoder_create + */ +typedef struct OpusProjectionEncoder OpusProjectionEncoder; + + +/** Opus projection decoder state. + * This contains the complete state of a projection Opus decoder. + * It is position independent and can be freely copied. + * @see opus_projection_decoder_create + * @see opus_projection_decoder_init + */ +typedef struct OpusProjectionDecoder OpusProjectionDecoder; + + +/**\name Projection encoder functions */ +/**@{*/ + +/** Gets the size of an OpusProjectionEncoder structure. + * @param channels int: The total number of input channels to encode. + * This must be no more than 255. + * @param mapping_family int: The mapping family to use for selecting + * the appropriate projection. + * @returns The size in bytes on success, or a negative error code + * (see @ref opus_errorcodes) on error. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_projection_ambisonics_encoder_get_size( + int channels, + int mapping_family +); + + +/** Allocates and initializes a projection encoder state. + * Call opus_projection_encoder_destroy() to release + * this object when finished. + * @param Fs opus_int32: Sampling rate of the input signal (in Hz). + * This must be one of 8000, 12000, 16000, + * 24000, or 48000. + * @param channels int: Number of channels in the input signal. + * This must be at most 255. + * It may be greater than the number of + * coded channels (streams + + * coupled_streams). + * @param mapping_family int: The mapping family to use for selecting + * the appropriate projection. + * @param[out] streams int *: The total number of streams that will + * be encoded from the input. + * @param[out] coupled_streams int *: Number of coupled (2 channel) + * streams that will be encoded from the input. + * @param application int: The target encoder application. + * This must be one of the following: + *
    + *
    #OPUS_APPLICATION_VOIP
    + *
    Process signal for improved speech intelligibility.
    + *
    #OPUS_APPLICATION_AUDIO
    + *
    Favor faithfulness to the original input.
    + *
    #OPUS_APPLICATION_RESTRICTED_LOWDELAY
    + *
    Configure the minimum possible coding delay by disabling certain modes + * of operation.
    + *
    + * @param[out] error int *: Returns #OPUS_OK on success, or an error + * code (see @ref opus_errorcodes) on + * failure. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT OpusProjectionEncoder *opus_projection_ambisonics_encoder_create( + opus_int32 Fs, + int channels, + int mapping_family, + int *streams, + int *coupled_streams, + int application, + int *error +) OPUS_ARG_NONNULL(4) OPUS_ARG_NONNULL(5); + + +/** Initialize a previously allocated projection encoder state. + * The memory pointed to by \a st must be at least the size returned by + * opus_projection_ambisonics_encoder_get_size(). + * This is intended for applications which use their own allocator instead of + * malloc. + * To reset a previously initialized state, use the #OPUS_RESET_STATE CTL. + * @see opus_projection_ambisonics_encoder_create + * @see opus_projection_ambisonics_encoder_get_size + * @param st OpusProjectionEncoder*: Projection encoder state to initialize. + * @param Fs opus_int32: Sampling rate of the input signal (in Hz). + * This must be one of 8000, 12000, 16000, + * 24000, or 48000. + * @param channels int: Number of channels in the input signal. + * This must be at most 255. + * It may be greater than the number of + * coded channels (streams + + * coupled_streams). + * @param streams int: The total number of streams to encode from the + * input. + * This must be no more than the number of channels. + * @param coupled_streams int: Number of coupled (2 channel) streams + * to encode. + * This must be no larger than the total + * number of streams. + * Additionally, The total number of + * encoded channels (streams + + * coupled_streams) must be no + * more than the number of input channels. + * @param application int: The target encoder application. + * This must be one of the following: + *
    + *
    #OPUS_APPLICATION_VOIP
    + *
    Process signal for improved speech intelligibility.
    + *
    #OPUS_APPLICATION_AUDIO
    + *
    Favor faithfulness to the original input.
    + *
    #OPUS_APPLICATION_RESTRICTED_LOWDELAY
    + *
    Configure the minimum possible coding delay by disabling certain modes + * of operation.
    + *
    + * @returns #OPUS_OK on success, or an error code (see @ref opus_errorcodes) + * on failure. + */ +OPUS_EXPORT int opus_projection_ambisonics_encoder_init( + OpusProjectionEncoder *st, + opus_int32 Fs, + int channels, + int mapping_family, + int *streams, + int *coupled_streams, + int application +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(5) OPUS_ARG_NONNULL(6); + + +/** Encodes a projection Opus frame. + * @param st OpusProjectionEncoder*: Projection encoder state. + * @param[in] pcm const opus_int16*: The input signal as interleaved + * samples. + * This must contain + * frame_size*channels + * samples. + * @param frame_size int: Number of samples per channel in the input + * signal. + * This must be an Opus frame size for the + * encoder's sampling rate. + * For example, at 48 kHz the permitted values + * are 120, 240, 480, 960, 1920, and 2880. + * Passing in a duration of less than 10 ms + * (480 samples at 48 kHz) will prevent the + * encoder from using the LPC or hybrid modes. + * @param[out] data unsigned char*: Output payload. + * This must contain storage for at + * least \a max_data_bytes. + * @param [in] max_data_bytes opus_int32: Size of the allocated + * memory for the output + * payload. This may be + * used to impose an upper limit on + * the instant bitrate, but should + * not be used as the only bitrate + * control. Use #OPUS_SET_BITRATE to + * control the bitrate. + * @returns The length of the encoded packet (in bytes) on success or a + * negative error code (see @ref opus_errorcodes) on failure. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_projection_encode( + OpusProjectionEncoder *st, + const opus_int16 *pcm, + int frame_size, + unsigned char *data, + opus_int32 max_data_bytes +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2) OPUS_ARG_NONNULL(4); + + +/** Encodes a projection Opus frame from floating point input. + * @param st OpusProjectionEncoder*: Projection encoder state. + * @param[in] pcm const float*: The input signal as interleaved + * samples with a normal range of + * +/-1.0. + * Samples with a range beyond +/-1.0 + * are supported but will be clipped by + * decoders using the integer API and + * should only be used if it is known + * that the far end supports extended + * dynamic range. + * This must contain + * frame_size*channels + * samples. + * @param frame_size int: Number of samples per channel in the input + * signal. + * This must be an Opus frame size for the + * encoder's sampling rate. + * For example, at 48 kHz the permitted values + * are 120, 240, 480, 960, 1920, and 2880. + * Passing in a duration of less than 10 ms + * (480 samples at 48 kHz) will prevent the + * encoder from using the LPC or hybrid modes. + * @param[out] data unsigned char*: Output payload. + * This must contain storage for at + * least \a max_data_bytes. + * @param [in] max_data_bytes opus_int32: Size of the allocated + * memory for the output + * payload. This may be + * used to impose an upper limit on + * the instant bitrate, but should + * not be used as the only bitrate + * control. Use #OPUS_SET_BITRATE to + * control the bitrate. + * @returns The length of the encoded packet (in bytes) on success or a + * negative error code (see @ref opus_errorcodes) on failure. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_projection_encode_float( + OpusProjectionEncoder *st, + const float *pcm, + int frame_size, + unsigned char *data, + opus_int32 max_data_bytes +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2) OPUS_ARG_NONNULL(4); + + +/** Frees an OpusProjectionEncoder allocated by + * opus_projection_ambisonics_encoder_create(). + * @param st OpusProjectionEncoder*: Projection encoder state to be freed. + */ +OPUS_EXPORT void opus_projection_encoder_destroy(OpusProjectionEncoder *st); + + +/** Perform a CTL function on a projection Opus encoder. + * + * Generally the request and subsequent arguments are generated by a + * convenience macro. + * @param st OpusProjectionEncoder*: Projection encoder state. + * @param request This and all remaining parameters should be replaced by one + * of the convenience macros in @ref opus_genericctls, + * @ref opus_encoderctls, @ref opus_multistream_ctls, or + * @ref opus_projection_ctls + * @see opus_genericctls + * @see opus_encoderctls + * @see opus_multistream_ctls + * @see opus_projection_ctls + */ +OPUS_EXPORT int opus_projection_encoder_ctl(OpusProjectionEncoder *st, int request, ...) OPUS_ARG_NONNULL(1); + + +/**@}*/ + +/**\name Projection decoder functions */ +/**@{*/ + +/** Gets the size of an OpusProjectionDecoder structure. + * @param channels int: The total number of output channels. + * This must be no more than 255. + * @param streams int: The total number of streams coded in the + * input. + * This must be no more than 255. + * @param coupled_streams int: Number streams to decode as coupled + * (2 channel) streams. + * This must be no larger than the total + * number of streams. + * Additionally, The total number of + * coded channels (streams + + * coupled_streams) must be no + * more than 255. + * @returns The size in bytes on success, or a negative error code + * (see @ref opus_errorcodes) on error. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_projection_decoder_get_size( + int channels, + int streams, + int coupled_streams +); + + +/** Allocates and initializes a projection decoder state. + * Call opus_projection_decoder_destroy() to release + * this object when finished. + * @param Fs opus_int32: Sampling rate to decode at (in Hz). + * This must be one of 8000, 12000, 16000, + * 24000, or 48000. + * @param channels int: Number of channels to output. + * This must be at most 255. + * It may be different from the number of coded + * channels (streams + + * coupled_streams). + * @param streams int: The total number of streams coded in the + * input. + * This must be no more than 255. + * @param coupled_streams int: Number of streams to decode as coupled + * (2 channel) streams. + * This must be no larger than the total + * number of streams. + * Additionally, The total number of + * coded channels (streams + + * coupled_streams) must be no + * more than 255. + * @param[in] demixing_matrix const unsigned char[demixing_matrix_size]: Demixing matrix + * that mapping from coded channels to output channels, + * as described in @ref opus_projection and + * @ref opus_projection_ctls. + * @param demixing_matrix_size opus_int32: The size in bytes of the + * demixing matrix, as + * described in @ref + * opus_projection_ctls. + * @param[out] error int *: Returns #OPUS_OK on success, or an error + * code (see @ref opus_errorcodes) on + * failure. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT OpusProjectionDecoder *opus_projection_decoder_create( + opus_int32 Fs, + int channels, + int streams, + int coupled_streams, + unsigned char *demixing_matrix, + opus_int32 demixing_matrix_size, + int *error +) OPUS_ARG_NONNULL(5); + + +/** Intialize a previously allocated projection decoder state object. + * The memory pointed to by \a st must be at least the size returned by + * opus_projection_decoder_get_size(). + * This is intended for applications which use their own allocator instead of + * malloc. + * To reset a previously initialized state, use the #OPUS_RESET_STATE CTL. + * @see opus_projection_decoder_create + * @see opus_projection_deocder_get_size + * @param st OpusProjectionDecoder*: Projection encoder state to initialize. + * @param Fs opus_int32: Sampling rate to decode at (in Hz). + * This must be one of 8000, 12000, 16000, + * 24000, or 48000. + * @param channels int: Number of channels to output. + * This must be at most 255. + * It may be different from the number of coded + * channels (streams + + * coupled_streams). + * @param streams int: The total number of streams coded in the + * input. + * This must be no more than 255. + * @param coupled_streams int: Number of streams to decode as coupled + * (2 channel) streams. + * This must be no larger than the total + * number of streams. + * Additionally, The total number of + * coded channels (streams + + * coupled_streams) must be no + * more than 255. + * @param[in] demixing_matrix const unsigned char[demixing_matrix_size]: Demixing matrix + * that mapping from coded channels to output channels, + * as described in @ref opus_projection and + * @ref opus_projection_ctls. + * @param demixing_matrix_size opus_int32: The size in bytes of the + * demixing matrix, as + * described in @ref + * opus_projection_ctls. + * @returns #OPUS_OK on success, or an error code (see @ref opus_errorcodes) + * on failure. + */ +OPUS_EXPORT int opus_projection_decoder_init( + OpusProjectionDecoder *st, + opus_int32 Fs, + int channels, + int streams, + int coupled_streams, + unsigned char *demixing_matrix, + opus_int32 demixing_matrix_size +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(6); + + +/** Decode a projection Opus packet. + * @param st OpusProjectionDecoder*: Projection decoder state. + * @param[in] data const unsigned char*: Input payload. + * Use a NULL + * pointer to indicate packet + * loss. + * @param len opus_int32: Number of bytes in payload. + * @param[out] pcm opus_int16*: Output signal, with interleaved + * samples. + * This must contain room for + * frame_size*channels + * samples. + * @param frame_size int: The number of samples per channel of + * available space in \a pcm. + * If this is less than the maximum packet duration + * (120 ms; 5760 for 48kHz), this function will not be capable + * of decoding some packets. In the case of PLC (data==NULL) + * or FEC (decode_fec=1), then frame_size needs to be exactly + * the duration of audio that is missing, otherwise the + * decoder will not be in the optimal state to decode the + * next incoming packet. For the PLC and FEC cases, frame_size + * must be a multiple of 2.5 ms. + * @param decode_fec int: Flag (0 or 1) to request that any in-band + * forward error correction data be decoded. + * If no such data is available, the frame is + * decoded as if it were lost. + * @returns Number of samples decoded on success or a negative error code + * (see @ref opus_errorcodes) on failure. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_projection_decode( + OpusProjectionDecoder *st, + const unsigned char *data, + opus_int32 len, + opus_int16 *pcm, + int frame_size, + int decode_fec +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4); + + +/** Decode a projection Opus packet with floating point output. + * @param st OpusProjectionDecoder*: Projection decoder state. + * @param[in] data const unsigned char*: Input payload. + * Use a NULL + * pointer to indicate packet + * loss. + * @param len opus_int32: Number of bytes in payload. + * @param[out] pcm opus_int16*: Output signal, with interleaved + * samples. + * This must contain room for + * frame_size*channels + * samples. + * @param frame_size int: The number of samples per channel of + * available space in \a pcm. + * If this is less than the maximum packet duration + * (120 ms; 5760 for 48kHz), this function will not be capable + * of decoding some packets. In the case of PLC (data==NULL) + * or FEC (decode_fec=1), then frame_size needs to be exactly + * the duration of audio that is missing, otherwise the + * decoder will not be in the optimal state to decode the + * next incoming packet. For the PLC and FEC cases, frame_size + * must be a multiple of 2.5 ms. + * @param decode_fec int: Flag (0 or 1) to request that any in-band + * forward error correction data be decoded. + * If no such data is available, the frame is + * decoded as if it were lost. + * @returns Number of samples decoded on success or a negative error code + * (see @ref opus_errorcodes) on failure. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_projection_decode_float( + OpusProjectionDecoder *st, + const unsigned char *data, + opus_int32 len, + float *pcm, + int frame_size, + int decode_fec +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4); + + +/** Perform a CTL function on a projection Opus decoder. + * + * Generally the request and subsequent arguments are generated by a + * convenience macro. + * @param st OpusProjectionDecoder*: Projection decoder state. + * @param request This and all remaining parameters should be replaced by one + * of the convenience macros in @ref opus_genericctls, + * @ref opus_decoderctls, @ref opus_multistream_ctls, or + * @ref opus_projection_ctls. + * @see opus_genericctls + * @see opus_decoderctls + * @see opus_multistream_ctls + * @see opus_projection_ctls + */ +OPUS_EXPORT int opus_projection_decoder_ctl(OpusProjectionDecoder *st, int request, ...) OPUS_ARG_NONNULL(1); + + +/** Frees an OpusProjectionDecoder allocated by + * opus_projection_decoder_create(). + * @param st OpusProjectionDecoder: Projection decoder state to be freed. + */ +OPUS_EXPORT void opus_projection_decoder_destroy(OpusProjectionDecoder *st); + + +/**@}*/ + +/**@}*/ + +#ifdef __cplusplus +} +#endif + +#endif /* OPUS_PROJECTION_H */ diff --git a/extern/opus/include/opus_types.h b/extern/opus/include/opus_types.h new file mode 100644 index 0000000..7cf6755 --- /dev/null +++ b/extern/opus/include/opus_types.h @@ -0,0 +1,166 @@ +/* (C) COPYRIGHT 1994-2002 Xiph.Org Foundation */ +/* Modified by Jean-Marc Valin */ +/* + 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. + + 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 OWNER + 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. +*/ +/* opus_types.h based on ogg_types.h from libogg */ + +/** + @file opus_types.h + @brief Opus reference implementation types +*/ +#ifndef OPUS_TYPES_H +#define OPUS_TYPES_H + +#define opus_int int /* used for counters etc; at least 16 bits */ +#define opus_int64 long long +#define opus_int8 signed char + +#define opus_uint unsigned int /* used for counters etc; at least 16 bits */ +#define opus_uint64 unsigned long long +#define opus_uint8 unsigned char + +/* Use the real stdint.h if it's there (taken from Paul Hsieh's pstdint.h) */ +#if (defined(__STDC__) && __STDC__ && defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || (defined(__GNUC__) && (defined(_STDINT_H) || defined(_STDINT_H_)) || defined (HAVE_STDINT_H)) +#include +# undef opus_int64 +# undef opus_int8 +# undef opus_uint64 +# undef opus_uint8 + typedef int8_t opus_int8; + typedef uint8_t opus_uint8; + typedef int16_t opus_int16; + typedef uint16_t opus_uint16; + typedef int32_t opus_int32; + typedef uint32_t opus_uint32; + typedef int64_t opus_int64; + typedef uint64_t opus_uint64; +#elif defined(_WIN32) + +# if defined(__CYGWIN__) +# include <_G_config.h> + typedef _G_int32_t opus_int32; + typedef _G_uint32_t opus_uint32; + typedef _G_int16 opus_int16; + typedef _G_uint16 opus_uint16; +# elif defined(__MINGW32__) + typedef short opus_int16; + typedef unsigned short opus_uint16; + typedef int opus_int32; + typedef unsigned int opus_uint32; +# elif defined(__MWERKS__) + typedef int opus_int32; + typedef unsigned int opus_uint32; + typedef short opus_int16; + typedef unsigned short opus_uint16; +# else + /* MSVC/Borland */ + typedef __int32 opus_int32; + typedef unsigned __int32 opus_uint32; + typedef __int16 opus_int16; + typedef unsigned __int16 opus_uint16; +# endif + +#elif defined(__MACOS__) + +# include + typedef SInt16 opus_int16; + typedef UInt16 opus_uint16; + typedef SInt32 opus_int32; + typedef UInt32 opus_uint32; + +#elif (defined(__APPLE__) && defined(__MACH__)) /* MacOS X Framework build */ + +# include + typedef int16_t opus_int16; + typedef u_int16_t opus_uint16; + typedef int32_t opus_int32; + typedef u_int32_t opus_uint32; + +#elif defined(__BEOS__) + + /* Be */ +# include + typedef int16 opus_int16; + typedef u_int16 opus_uint16; + typedef int32_t opus_int32; + typedef u_int32_t opus_uint32; + +#elif defined (__EMX__) + + /* OS/2 GCC */ + typedef short opus_int16; + typedef unsigned short opus_uint16; + typedef int opus_int32; + typedef unsigned int opus_uint32; + +#elif defined (DJGPP) + + /* DJGPP */ + typedef short opus_int16; + typedef unsigned short opus_uint16; + typedef int opus_int32; + typedef unsigned int opus_uint32; + +#elif defined(R5900) + + /* PS2 EE */ + typedef int opus_int32; + typedef unsigned opus_uint32; + typedef short opus_int16; + typedef unsigned short opus_uint16; + +#elif defined(__SYMBIAN32__) + + /* Symbian GCC */ + typedef signed short opus_int16; + typedef unsigned short opus_uint16; + typedef signed int opus_int32; + typedef unsigned int opus_uint32; + +#elif defined(CONFIG_TI_C54X) || defined (CONFIG_TI_C55X) + + typedef short opus_int16; + typedef unsigned short opus_uint16; + typedef long opus_int32; + typedef unsigned long opus_uint32; + +#elif defined(CONFIG_TI_C6X) + + typedef short opus_int16; + typedef unsigned short opus_uint16; + typedef int opus_int32; + typedef unsigned int opus_uint32; + +#else + + /* Give up, take a reasonable guess */ + typedef short opus_int16; + typedef unsigned short opus_uint16; + typedef int opus_int32; + typedef unsigned int opus_uint32; + +#endif + +#endif /* OPUS_TYPES_H */ diff --git a/extern/opus/m4/as-gcc-inline-assembly.m4 b/extern/opus/m4/as-gcc-inline-assembly.m4 new file mode 100644 index 0000000..b0d2da4 --- /dev/null +++ b/extern/opus/m4/as-gcc-inline-assembly.m4 @@ -0,0 +1,98 @@ +dnl as-gcc-inline-assembly.m4 0.1.0 + +dnl autostars m4 macro for detection of gcc inline assembly + +dnl David Schleef + +dnl AS_COMPILER_FLAG(ACTION-IF-ACCEPTED, [ACTION-IF-NOT-ACCEPTED]) +dnl Tries to compile with the given CFLAGS. +dnl Runs ACTION-IF-ACCEPTED if the compiler can compile with the flags, +dnl and ACTION-IF-NOT-ACCEPTED otherwise. + +AC_DEFUN([AS_GCC_INLINE_ASSEMBLY], +[ + AC_MSG_CHECKING([if compiler supports gcc-style inline assembly]) + + AC_TRY_COMPILE([], [ +#ifdef __GNUC_MINOR__ +#if (__GNUC__ * 1000 + __GNUC_MINOR__) < 3004 +#error GCC before 3.4 has critical bugs compiling inline assembly +#endif +#endif +__asm__ (""::) ], [flag_ok=yes], [flag_ok=no]) + + if test "X$flag_ok" = Xyes ; then + $1 + true + else + $2 + true + fi + AC_MSG_RESULT([$flag_ok]) +]) + +AC_DEFUN([AS_ASM_ARM_NEON], +[ + AC_MSG_CHECKING([if assembler supports NEON instructions on ARM]) + + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([],[__asm__("vorr d0,d0,d0")])], + [AC_MSG_RESULT([yes]) + $1], + [AC_MSG_RESULT([no]) + $2]) +]) + +AC_DEFUN([AS_ASM_ARM_NEON_FORCE], +[ + AC_MSG_CHECKING([if assembler supports NEON instructions on ARM]) + + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([],[__asm__(".arch armv7-a\n.fpu neon\n.object_arch armv4t\nvorr d0,d0,d0")])], + [AC_MSG_RESULT([yes]) + $1], + [AC_MSG_RESULT([no]) + $2]) +]) + +AC_DEFUN([AS_ASM_ARM_MEDIA], +[ + AC_MSG_CHECKING([if assembler supports ARMv6 media instructions on ARM]) + + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([],[__asm__("shadd8 r3,r3,r3")])], + [AC_MSG_RESULT([yes]) + $1], + [AC_MSG_RESULT([no]) + $2]) +]) + +AC_DEFUN([AS_ASM_ARM_MEDIA_FORCE], +[ + AC_MSG_CHECKING([if assembler supports ARMv6 media instructions on ARM]) + + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([],[__asm__(".arch armv6\n.object_arch armv4t\nshadd8 r3,r3,r3")])], + [AC_MSG_RESULT([yes]) + $1], + [AC_MSG_RESULT([no]) + $2]) +]) + +AC_DEFUN([AS_ASM_ARM_EDSP], +[ + AC_MSG_CHECKING([if assembler supports EDSP instructions on ARM]) + + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([],[__asm__("qadd r3,r3,r3")])], + [AC_MSG_RESULT([yes]) + $1], + [AC_MSG_RESULT([no]) + $2]) +]) + +AC_DEFUN([AS_ASM_ARM_EDSP_FORCE], +[ + AC_MSG_CHECKING([if assembler supports EDSP instructions on ARM]) + + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([],[__asm__(".arch armv5te\n.object_arch armv4t\nqadd r3,r3,r3")])], + [AC_MSG_RESULT([yes]) + $1], + [AC_MSG_RESULT([no]) + $2]) +]) diff --git a/extern/opus/m4/ax_add_fortify_source.m4 b/extern/opus/m4/ax_add_fortify_source.m4 new file mode 100644 index 0000000..1c89e41 --- /dev/null +++ b/extern/opus/m4/ax_add_fortify_source.m4 @@ -0,0 +1,53 @@ +# =========================================================================== +# Modified from https://www.gnu.org/software/autoconf-archive/ax_add_fortify_source.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_ADD_FORTIFY_SOURCE +# +# DESCRIPTION +# +# Check whether -D_FORTIFY_SOURCE=2 can be added to CFLAGS without macro +# redefinition warnings. Some distributions (such as Gentoo Linux) enable +# _FORTIFY_SOURCE globally in their compilers, leading to unnecessary +# warnings in the form of +# +# :0:0: error: "_FORTIFY_SOURCE" redefined [-Werror] +# : note: this is the location of the previous definition +# +# which is a problem if -Werror is enabled. This macro checks whether +# _FORTIFY_SOURCE is already defined, and if not, adds -D_FORTIFY_SOURCE=2 +# to CFLAGS. +# +# LICENSE +# +# Copyright (c) 2017 David Seifert +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 1 + +AC_DEFUN([AX_ADD_FORTIFY_SOURCE],[ + AC_MSG_CHECKING([whether to add -D_FORTIFY_SOURCE=2 to CFLAGS]) + AC_LINK_IFELSE([ + AC_LANG_SOURCE( + [[ + int main() { + #ifndef _FORTIFY_SOURCE + return 0; + #else + this_is_an_error; + #endif + } + ]] + )], [ + AC_MSG_RESULT([yes]) + CFLAGS="$CFLAGS -D_FORTIFY_SOURCE=2" + ], [ + AC_MSG_RESULT([no]) + ]) +]) diff --git a/extern/opus/m4/opus-intrinsics.m4 b/extern/opus/m4/opus-intrinsics.m4 new file mode 100644 index 0000000..a262ca1 --- /dev/null +++ b/extern/opus/m4/opus-intrinsics.m4 @@ -0,0 +1,29 @@ +dnl opus-intrinsics.m4 +dnl macro for testing for support for compiler intrinsics, either by default or with a compiler flag + +dnl OPUS_CHECK_INTRINSICS(NAME-OF-INTRINSICS, COMPILER-FLAG-FOR-INTRINSICS, VAR-IF-PRESENT, VAR-IF-DEFAULT, TEST-PROGRAM-HEADER, TEST-PROGRAM-BODY) +AC_DEFUN([OPUS_CHECK_INTRINSICS], +[ + AC_MSG_CHECKING([if compiler supports $1 intrinsics]) + AC_LINK_IFELSE( + [AC_LANG_PROGRAM($5, $6)], + [ + $3=1 + $4=1 + AC_MSG_RESULT([yes]) + ],[ + $4=0 + AC_MSG_RESULT([no]) + AC_MSG_CHECKING([if compiler supports $1 intrinsics with $2]) + save_CFLAGS="$CFLAGS"; CFLAGS="$CFLAGS $2" + AC_LINK_IFELSE([AC_LANG_PROGRAM($5, $6)], + [ + AC_MSG_RESULT([yes]) + $3=1 + ],[ + AC_MSG_RESULT([no]) + $3=0 + ]) + CFLAGS="$save_CFLAGS" + ]) +]) diff --git a/extern/opus/opus-uninstalled.pc.in b/extern/opus/opus-uninstalled.pc.in new file mode 100644 index 0000000..19f5c93 --- /dev/null +++ b/extern/opus/opus-uninstalled.pc.in @@ -0,0 +1,12 @@ +# Opus codec reference implementation uninstalled pkg-config file + +libdir=${pcfiledir}/.libs +includedir=${pcfiledir} + +Name: opus uninstalled +Description: Opus IETF audio codec (not installed, @PC_BUILD@) +Version: @VERSION@ +Requires: +Conflicts: +Libs: ${libdir}/libopus.la @LIBM@ +Cflags: -I${pcfiledir}/@top_srcdir@/include diff --git a/extern/opus/opus.m4 b/extern/opus/opus.m4 new file mode 100644 index 0000000..47f5ec4 --- /dev/null +++ b/extern/opus/opus.m4 @@ -0,0 +1,117 @@ +# Configure paths for libopus +# Gregory Maxwell 08-30-2012 +# Shamelessly stolen from Jack Moffitt (libogg) who +# Shamelessly stole from Owen Taylor and Manish Singh + +dnl XIPH_PATH_OPUS([ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]) +dnl Test for libopus, and define OPUS_CFLAGS and OPUS_LIBS +dnl +AC_DEFUN([XIPH_PATH_OPUS], +[dnl +dnl Get the cflags and libraries +dnl +AC_ARG_WITH(opus,AC_HELP_STRING([--with-opus=PFX],[Prefix where opus is installed (optional)]), opus_prefix="$withval", opus_prefix="") +AC_ARG_WITH(opus-libraries,AC_HELP_STRING([--with-opus-libraries=DIR],[Directory where the opus library is installed (optional)]), opus_libraries="$withval", opus_libraries="") +AC_ARG_WITH(opus-includes,AC_HELP_STRING([--with-opus-includes=DIR],[Directory where the opus header files are installed (optional)]), opus_includes="$withval", opus_includes="") +AC_ARG_ENABLE(opustest,AC_HELP_STRING([--disable-opustest],[Do not try to compile and run a test opus program]),, enable_opustest=yes) + + if test "x$opus_libraries" != "x" ; then + OPUS_LIBS="-L$opus_libraries" + elif test "x$opus_prefix" = "xno" || test "x$opus_prefix" = "xyes" ; then + OPUS_LIBS="" + elif test "x$opus_prefix" != "x" ; then + OPUS_LIBS="-L$opus_prefix/lib" + elif test "x$prefix" != "xNONE" ; then + OPUS_LIBS="-L$prefix/lib" + fi + + if test "x$opus_prefix" != "xno" ; then + OPUS_LIBS="$OPUS_LIBS -lopus" + fi + + if test "x$opus_includes" != "x" ; then + OPUS_CFLAGS="-I$opus_includes" + elif test "x$opus_prefix" = "xno" || test "x$opus_prefix" = "xyes" ; then + OPUS_CFLAGS="" + elif test "x$opus_prefix" != "x" ; then + OPUS_CFLAGS="-I$opus_prefix/include" + elif test "x$prefix" != "xNONE"; then + OPUS_CFLAGS="-I$prefix/include" + fi + + AC_MSG_CHECKING(for Opus) + if test "x$opus_prefix" = "xno" ; then + no_opus="disabled" + enable_opustest="no" + else + no_opus="" + fi + + + if test "x$enable_opustest" = "xyes" ; then + ac_save_CFLAGS="$CFLAGS" + ac_save_LIBS="$LIBS" + CFLAGS="$CFLAGS $OPUS_CFLAGS" + LIBS="$LIBS $OPUS_LIBS" +dnl +dnl Now check if the installed Opus is sufficiently new. +dnl + rm -f conf.opustest + AC_TRY_RUN([ +#include +#include +#include +#include + +int main () +{ + system("touch conf.opustest"); + return 0; +} + +],, no_opus=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"]) + CFLAGS="$ac_save_CFLAGS" + LIBS="$ac_save_LIBS" + fi + + if test "x$no_opus" = "xdisabled" ; then + AC_MSG_RESULT(no) + ifelse([$2], , :, [$2]) + elif test "x$no_opus" = "x" ; then + AC_MSG_RESULT(yes) + ifelse([$1], , :, [$1]) + else + AC_MSG_RESULT(no) + if test -f conf.opustest ; then + : + else + echo "*** Could not run Opus test program, checking why..." + CFLAGS="$CFLAGS $OPUS_CFLAGS" + LIBS="$LIBS $OPUS_LIBS" + AC_TRY_LINK([ +#include +#include +], [ return 0; ], + [ echo "*** The test program compiled, but did not run. This usually means" + echo "*** that the run-time linker is not finding Opus or finding the wrong" + echo "*** version of Opus. If it is not finding Opus, you'll need to set your" + echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point" + echo "*** to the installed location Also, make sure you have run ldconfig if that" + echo "*** is required on your system" + echo "***" + echo "*** If you have an old version installed, it is best to remove it, although" + echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH"], + [ echo "*** The test program failed to compile or link. See the file config.log for the" + echo "*** exact error that occurred. This usually means Opus was incorrectly installed" + echo "*** or that you have moved Opus since it was installed." ]) + CFLAGS="$ac_save_CFLAGS" + LIBS="$ac_save_LIBS" + fi + OPUS_CFLAGS="" + OPUS_LIBS="" + ifelse([$2], , :, [$2]) + fi + AC_SUBST(OPUS_CFLAGS) + AC_SUBST(OPUS_LIBS) + rm -f conf.opustest +]) diff --git a/extern/opus/opus.pc.in b/extern/opus/opus.pc.in new file mode 100644 index 0000000..6946e7d --- /dev/null +++ b/extern/opus/opus.pc.in @@ -0,0 +1,16 @@ +# Opus codec reference implementation pkg-config file + +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: Opus +Description: Opus IETF audio codec (@PC_BUILD@ build) +URL: https://opus-codec.org/ +Version: @VERSION@ +Requires: +Conflicts: +Libs: -L${libdir} -lopus +Libs.private: @LIBM@ +Cflags: -I${includedir}/opus diff --git a/extern/opus/opus_buildtype.cmake b/extern/opus/opus_buildtype.cmake new file mode 100644 index 0000000..aaee9ef --- /dev/null +++ b/extern/opus/opus_buildtype.cmake @@ -0,0 +1,23 @@ +# Set a default build type if none was specified + +if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + if(CMAKE_C_FLAGS) + message(STATUS "CMAKE_C_FLAGS: " ${CMAKE_C_FLAGS}) + else() + set(default_build_type "Release") + message( + STATUS + "Setting build type to '${default_build_type}' as none was specified and no CFLAGS was exported." + ) + set(CMAKE_BUILD_TYPE "${default_build_type}" + CACHE STRING "Choose the type of build." + FORCE) + # Set the possible values of build type for cmake-gui + set_property(CACHE CMAKE_BUILD_TYPE + PROPERTY STRINGS + "Debug" + "Release" + "MinSizeRel" + "RelWithDebInfo") + endif() +endif() diff --git a/extern/opus/opus_config.cmake b/extern/opus/opus_config.cmake new file mode 100644 index 0000000..a0bfd58 --- /dev/null +++ b/extern/opus/opus_config.cmake @@ -0,0 +1,43 @@ +include(opus_functions.cmake) + +configure_file(config.h.cmake.in config.h @ONLY) +add_definitions(-DHAVE_CONFIG_H) + +set_property(GLOBAL PROPERTY USE_FOLDERS ON) +set_property(GLOBAL PROPERTY C_STANDARD 99) + +if(MSVC) + add_definitions(-D_CRT_SECURE_NO_WARNINGS) +endif() + +include(CheckLibraryExists) +check_library_exists(m floor "" HAVE_LIBM) +if(HAVE_LIBM) + list(APPEND OPUS_REQUIRED_LIBRARIES m) +endif() + +if(CMAKE_SYSTEM_PROCESSOR MATCHES "(i[0-9]86|x86|X86|amd64|AMD64|x86_64)") + if(CMAKE_SIZEOF_VOID_P EQUAL 8) + set(OPUS_CPU_X64 1) + else() + set(OPUS_CPU_X86 1) + endif() +elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "arm") + set(OPUS_CPU_ARM 1) +endif() + +opus_supports_cpu_detection(RUNTIME_CPU_CAPABILITY_DETECTION) + +if(OPUS_CPU_X86 OR OPUS_CPU_X64) + opus_detect_sse(COMPILER_SUPPORT_SIMD) +elseif(OPUS_CPU_ARM) + opus_detect_neon(COMPILER_SUPPORT_NEON) + if(COMPILER_SUPPORT_NEON) + option(OPUS_USE_NEON "Option to turn off SSE" ON) + option(OPUS_MAY_SUPPORT_NEON "Does runtime check for neon support" ON) + option(OPUS_PRESUME_NEON "Assume target CPU has NEON support" OFF) + if(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64") + set(OPUS_PRESUME_NEON ON) + endif() + endif() +endif() diff --git a/extern/opus/opus_functions.cmake b/extern/opus/opus_functions.cmake new file mode 100644 index 0000000..fe309c2 --- /dev/null +++ b/extern/opus/opus_functions.cmake @@ -0,0 +1,262 @@ +#[[Cmake helper function to parse source files from make files +this is to avoid breaking existing make and auto make support +but still have the option to use CMake with only lists at one place]] + +cmake_minimum_required(VERSION 3.1) + +function(get_library_version OPUS_LIBRARY_VERSION OPUS_LIBRARY_VERSION_MAJOR) + file(STRINGS configure.ac opus_lt_current_string + LIMIT_COUNT 1 + REGEX "OPUS_LT_CURRENT=") + string(REGEX MATCH + "OPUS_LT_CURRENT=([0-9]*)" + _ + ${opus_lt_current_string}) + set(OPUS_LT_CURRENT ${CMAKE_MATCH_1}) + + file(STRINGS configure.ac opus_lt_revision_string + LIMIT_COUNT 1 + REGEX "OPUS_LT_REVISION=") + string(REGEX MATCH + "OPUS_LT_REVISION=([0-9]*)" + _ + ${opus_lt_revision_string}) + set(OPUS_LT_REVISION ${CMAKE_MATCH_1}) + + file(STRINGS configure.ac opus_lt_age_string + LIMIT_COUNT 1 + REGEX "OPUS_LT_AGE=") + string(REGEX MATCH + "OPUS_LT_AGE=([0-9]*)" + _ + ${opus_lt_age_string}) + set(OPUS_LT_AGE ${CMAKE_MATCH_1}) + + math(EXPR OPUS_LIBRARY_VERSION_MAJOR "${OPUS_LT_CURRENT} - ${OPUS_LT_AGE}") + set(OPUS_LIBRARY_VERSION_MINOR ${OPUS_LT_AGE}) + set(OPUS_LIBRARY_VERSION_PATCH ${OPUS_LT_REVISION}) + set( + OPUS_LIBRARY_VERSION + "${OPUS_LIBRARY_VERSION_MAJOR}.${OPUS_LIBRARY_VERSION_MINOR}.${OPUS_LIBRARY_VERSION_PATCH}" + PARENT_SCOPE) + set(OPUS_LIBRARY_VERSION_MAJOR ${OPUS_LIBRARY_VERSION_MAJOR} PARENT_SCOPE) +endfunction() + +function(get_package_version PACKAGE_VERSION) + find_package(Git) + if(GIT_FOUND) + execute_process(COMMAND ${GIT_EXECUTABLE} describe --tags --match "v*" + OUTPUT_VARIABLE OPUS_PACKAGE_VERSION) + if(OPUS_PACKAGE_VERSION) + string(STRIP ${OPUS_PACKAGE_VERSION}, OPUS_PACKAGE_VERSION) + string(REPLACE \n + "" + OPUS_PACKAGE_VERSION + ${OPUS_PACKAGE_VERSION}) + string(REPLACE , + "" + OPUS_PACKAGE_VERSION + ${OPUS_PACKAGE_VERSION}) + + string(SUBSTRING ${OPUS_PACKAGE_VERSION} + 1 + -1 + OPUS_PACKAGE_VERSION) + set(PACKAGE_VERSION ${OPUS_PACKAGE_VERSION} PARENT_SCOPE) + return() + endif() + endif() + + if(EXISTS "${CMAKE_SOURCE_DIR}/package_version") + # Not a git repo, lets' try to parse it from package_version file if exists + file(STRINGS package_version opus_package_version_string + LIMIT_COUNT 1 + REGEX "PACKAGE_VERSION=") + string(REPLACE "PACKAGE_VERSION=" + "" + opus_package_version_string + ${opus_package_version_string}) + string(REPLACE "\"" + "" + opus_package_version_string + ${opus_package_version_string}) + set(PACKAGE_VERSION ${opus_package_version_string} PARENT_SCOPE) + return() + endif() + + # if all else fails set to 0 + set(PACKAGE_VERSION 0 PARENT_SCOPE) +endfunction() + +function(check_and_set_flag NAME FLAG) + include(CheckCCompilerFlag) + check_c_compiler_flag(${FLAG} ${NAME}_SUPPORTED) + if(${NAME}_SUPPORTED) + add_definitions(${FLAG}) + endif() +endfunction() + +function(check_flag NAME FLAG) + include(CheckCCompilerFlag) + check_c_compiler_flag(${FLAG} ${NAME}_SUPPORTED) +endfunction() + +include(CheckIncludeFile) +# function to check if compiler supports SSE, SSE2, SSE4.1 and AVX if target +# systems may not have SSE support then use OPUS_MAY_HAVE_SSE option if target +# system is guaranteed to have SSE support then OPUS_PRESUME_SSE can be used to +# skip SSE runtime check +function(opus_detect_sse COMPILER_SUPPORT_SIMD) + message(STATUS "Check SIMD support by compiler") + check_include_file(xmmintrin.h HAVE_XMMINTRIN_H) # SSE1 + if(HAVE_XMMINTRIN_H) + if(MSVC) + # different arch options for 32 and 64 bit target for MSVC + if(CMAKE_SIZEOF_VOID_P EQUAL 4) + check_flag(SSE1 /arch:SSE) + else() + set(SSE1_SUPPORTED 1 PARENT_SCOPE) + endif() + else() + check_and_set_flag(SSE1 -msse) + endif() + else() + set(SSE1_SUPPORTED 0 PARENT_SCOPE) + endif() + + check_include_file(emmintrin.h HAVE_EMMINTRIN_H) # SSE2 + if(HAVE_EMMINTRIN_H) + if(MSVC) + if(CMAKE_SIZEOF_VOID_P EQUAL 4) + check_flag(SSE2 /arch:SSE2) + else() + set(SSE2_SUPPORTED 1 PARENT_SCOPE) + endif() + else() + check_and_set_flag(SSE2 -msse2) + endif() + else() + set(SSE2_SUPPORTED 0 PARENT_SCOPE) + endif() + + check_include_file(smmintrin.h HAVE_SMMINTRIN_H) # SSE4.1 + if(HAVE_SMMINTRIN_H) + if(MSVC) + if(CMAKE_SIZEOF_VOID_P EQUAL 4) + check_flag(SSE4_1 /arch:SSE2) # SSE2 and above + else() + set(SSE4_1_SUPPORTED 1 PARENT_SCOPE) + endif() + else() + check_and_set_flag(SSE4_1 -msse4.1) + endif() + else() + set(SSE4_1_SUPPORTED 0 PARENT_SCOPE) + endif() + + check_include_file(immintrin.h HAVE_IMMINTRIN_H) # AVX + if(HAVE_IMMINTRIN_H) + if(MSVC) + check_flag(AVX /arch:AVX) + else() + check_and_set_flag(AVX -mavx) + endif() + else() + set(AVX_SUPPORTED 0 PARENT_SCOPE) + endif() + + if(MSVC) # To avoid warning D9025 of overriding compiler options + if(AVX_SUPPORTED) # on 64 bit and 32 bits + add_definitions(/arch:AVX) + elseif(CMAKE_SIZEOF_VOID_P EQUAL 4) # if AVX not supported then set SSE flag + if(SSE4_1_SUPPORTED OR SSE2_SUPPORTED) + add_definitions(/arch:SSE2) + elseif(SSE1_SUPPORTED) + add_definitions(/arch:SSE) + endif() + endif() + endif() + + if(SSE1_SUPPORTED OR SSE2_SUPPORTED OR SSE4_1_SUPPORTED OR AVX_SUPPORTED) + set(COMPILER_SUPPORT_SIMD 1 PARENT_SCOPE) + else() + message(STATUS "No SIMD support in compiler") + endif() +endfunction() + +function(opus_detect_neon COMPILER_SUPPORT_NEON) + if(CMAKE_SYSTEM_PROCESSOR MATCHES "(armv7-a|aarch64)") + message(STATUS "Check NEON support by compiler") + check_include_file(arm_neon.h HAVE_ARM_NEON_H) + if(HAVE_ARM_NEON_H) + set(COMPILER_SUPPORT_NEON ${HAVE_ARM_NEON_H} PARENT_SCOPE) + endif() + endif() +endfunction() + +function(opus_supports_cpu_detection RUNTIME_CPU_CAPABILITY_DETECTION) + if(MSVC) + check_include_file(intrin.h HAVE_INTRIN_H) + else() + check_include_file(cpuid.h HAVE_CPUID_H) + endif() + if(HAVE_INTRIN_H OR HAVE_CPUID_H) + set(RUNTIME_CPU_CAPABILITY_DETECTION 1 PARENT_SCOPE) + else() + set(RUNTIME_CPU_CAPABILITY_DETECTION 0 PARENT_SCOPE) + endif() +endfunction() + +function(add_sources_group target group) + target_sources(${target} PRIVATE ${ARGN}) + source_group(${group} FILES ${ARGN}) +endfunction() + +function(get_opus_sources SOURCE_GROUP MAKE_FILE SOURCES) + # read file, each item in list is one group + file(STRINGS ${MAKE_FILE} opus_sources) + + # add wildcard for regex match + string(CONCAT SOURCE_GROUP ${SOURCE_GROUP} ".*$") + + # find group + foreach(val IN LISTS opus_sources) + if(val MATCHES ${SOURCE_GROUP}) + list(LENGTH val list_length) + if(${list_length} EQUAL 1) + # for tests split by '=' and clean up the rest into a list + string(FIND ${val} "=" index) + math(EXPR index "${index} + 1") + string(SUBSTRING ${val} + ${index} + -1 + sources) + string(REPLACE " " + ";" + sources + ${sources}) + else() + # discard the group + list(REMOVE_AT val 0) + set(sources ${val}) + endif() + break() + endif() + endforeach() + + list(LENGTH sources list_length) + if(${list_length} LESS 1) + message( + FATAL_ERROR + "No files parsed succesfully from ${SOURCE_GROUP} in ${MAKE_FILE}") + endif() + + # remove trailing whitespaces + set(list_var "") + foreach(source ${sources}) + string(STRIP "${source}" source) + list(APPEND list_var "${source}") + endforeach() + + set(${SOURCES} ${list_var} PARENT_SCOPE) +endfunction() diff --git a/extern/opus/opus_headers.mk b/extern/opus/opus_headers.mk new file mode 100644 index 0000000..27596f2 --- /dev/null +++ b/extern/opus/opus_headers.mk @@ -0,0 +1,9 @@ +OPUS_HEAD = \ +include/opus.h \ +include/opus_multistream.h \ +include/opus_projection.h \ +src/opus_private.h \ +src/analysis.h \ +src/mapping_matrix.h \ +src/mlp.h \ +src/tansig_table.h diff --git a/extern/opus/opus_sources.cmake b/extern/opus/opus_sources.cmake new file mode 100644 index 0000000..225543a --- /dev/null +++ b/extern/opus/opus_sources.cmake @@ -0,0 +1,38 @@ +include(opus_functions.cmake) + +get_opus_sources(SILK_SOURCES silk_sources.mk silk_sources) +get_opus_sources(SILK_SOURCES_FLOAT silk_sources.mk silk_sources_float) +get_opus_sources(SILK_SOURCES_FIXED silk_sources.mk silk_sources_fixed) +get_opus_sources(SILK_SOURCES_SSE4_1 silk_sources.mk silk_sources_sse4_1) +get_opus_sources(SILK_SOURCES_FIXED_SSE4_1 silk_sources.mk + silk_sources_fixed_sse4_1) +get_opus_sources(SILK_SOURCES_ARM_NEON_INTR silk_sources.mk + silk_sources_arm_neon_intr) +get_opus_sources(SILK_SOURCES_FIXED_ARM_NEON_INTR silk_sources.mk + silk_sources_fixed_arm_neon_intr) + +get_opus_sources(OPUS_SOURCES opus_sources.mk opus_sources) +get_opus_sources(OPUS_SOURCES_FLOAT opus_sources.mk opus_sources_float) + +get_opus_sources(CELT_SOURCES celt_sources.mk celt_sources) +get_opus_sources(CELT_SOURCES_SSE celt_sources.mk celt_sources_sse) +get_opus_sources(CELT_SOURCES_SSE2 celt_sources.mk celt_sources_sse2) +get_opus_sources(CELT_SOURCES_SSE4_1 celt_sources.mk celt_sources_sse4_1) +get_opus_sources(CELT_SOURCES_ARM celt_sources.mk celt_sources_arm) +get_opus_sources(CELT_SOURCES_ARM_ASM celt_sources.mk celt_sources_arm_asm) +get_opus_sources(CELT_AM_SOURCES_ARM_ASM celt_sources.mk + celt_am_sources_arm_asm) +get_opus_sources(CELT_SOURCES_ARM_NEON_INTR celt_sources.mk + celt_sources_arm_neon_intr) +get_opus_sources(CELT_SOURCES_ARM_NE10 celt_sources.mk celt_sources_arm_ne10) + +get_opus_sources(opus_demo_SOURCES Makefile.am opus_demo_sources) +get_opus_sources(opus_custom_demo_SOURCES Makefile.am opus_custom_demo_sources) +get_opus_sources(opus_compare_SOURCES Makefile.am opus_compare_sources) +get_opus_sources(tests_test_opus_api_SOURCES Makefile.am test_opus_api_sources) +get_opus_sources(tests_test_opus_encode_SOURCES Makefile.am + test_opus_encode_sources) +get_opus_sources(tests_test_opus_decode_SOURCES Makefile.am + test_opus_decode_sources) +get_opus_sources(tests_test_opus_padding_SOURCES Makefile.am + test_opus_padding_sources) diff --git a/extern/opus/opus_sources.mk b/extern/opus/opus_sources.mk new file mode 100644 index 0000000..44153b5 --- /dev/null +++ b/extern/opus/opus_sources.mk @@ -0,0 +1,16 @@ +OPUS_SOURCES = \ +src/opus.c \ +src/opus_decoder.c \ +src/opus_encoder.c \ +src/opus_multistream.c \ +src/opus_multistream_encoder.c \ +src/opus_multistream_decoder.c \ +src/repacketizer.c \ +src/opus_projection_encoder.c \ +src/opus_projection_decoder.c \ +src/mapping_matrix.c + +OPUS_SOURCES_FLOAT = \ +src/analysis.c \ +src/mlp.c \ +src/mlp_data.c diff --git a/extern/opus/releases.sha2 b/extern/opus/releases.sha2 new file mode 100644 index 0000000..dc0a6fc --- /dev/null +++ b/extern/opus/releases.sha2 @@ -0,0 +1,78 @@ +b2f75c4ac5ab837845eb028413fae2a28754bfb0a6d76416e2af1441ef447649 opus-0.9.0.tar.gz +4e379a98ba95bbbfe9087ef10fdd05c8ac9060b6d695f587ea82a7b43a0df4fe opus-0.9.10.tar.gz +b1cad6846a8f819a141009fe3f8f10c946e8eff7e9c2339cd517bb136cc59eae opus-0.9.14.tar.gz +206221afc47b87496588013bd4523e1e9f556336c0813f4372773fc536dd4293 opus-0.9.1.tar.gz +6e85c1b57e1d7b7dfe2928bf92586b96b73a9067e054ede45bd8e6d24bd30582 opus-0.9.2.tar.gz +d916e34c18a396eb7dffc47af754f441af52a290b761e20db9aedb65928c699e opus-0.9.3.tar.gz +53801066fa97329768e7b871fd1495740269ec46802e1c9051aa7e78c6edee5b opus-0.9.5.tar.gz +3bfaeb25f4b4a625a0bc994d6fc6f6776a05193f60099e0a99f7530c6b256309 opus-0.9.6.tar.gz +1b69772c31c5cbaa43d1dfa5b1c495fc29712e8e0ff69d6f8ad46459e5c6715f opus-0.9.7.tar.gz +4aa30d2e0652ffb4a7a22cc8a29c4ce78267626f560a2d9213b1d2d4e618cf36 opus-0.9.8.tar.gz +2f62359f09151fa3b242040dc9b4c5b6bda15557c5daea59c8420f1a2ff328b7 opus-0.9.9.tar.gz +43bcea51afa531f32a6a5fdd9cba4bd496993e26a141217db3cccce6caa7cd74 opus-1.0.0-rc.tar.gz +9250fcc74472d45c1e14745542ec9c8d09982538aefed56962495614be3e0d2d opus-1.0.0.tar.gz +76bc0a31502a51dae9ab737b4db043b9ecfcd0b5861f0bfda41b662bd5b92227 opus-1.0.1-rc2.tar.gz +3de8d6809dac38971ebb305532d4ea532519d3bed08985f25d6c557f9ce5e8ff opus-1.0.1-rc3.tar.gz +8044397a6365a07117b08cbe8f9818bf7c93746908806ba74a2917187bbdda5f opus-1.0.1-rc.tar.gz +80fa5c3caf2ac0fd68f8a22cce1564fc46b368c773a17554887d0066fe1841ef opus-1.0.1.tar.gz +da615edbee5d019c1833071d69a4782c19f178cf9ca1401375036ecef25cd78a opus-1.0.2.tar.gz +191a089c92dbc403de6980463dd3604b65beb12d283c607e246c8076363cb49c opus-1.0.3.tar.gz +a8d40efe87f6c3e76725391457d46277878c7a816ae1642843261463133fa5c8 opus-1.1-alpha.tar.gz +ec1784287f385aef994b64734aaecae04860e61aa50fc6eef6643fa7e40dd193 opus-1.1-beta.tar.gz +8aa16360f59a94d3e38f38f28d24039f7663179682cbae82aa42f1dd9e52e6ed opus-1.1-rc.tar.gz +ebc87a086d4fe677c5e42d56888b1fd25af858e4179eae4f8656270410dffac3 opus-1.1-rc2.tar.gz +cbfd09c58cc10a4d3fcb727ad5d46d7bb549f8185ac922ee28b4581b52a7bee9 opus-1.1-rc3.tar.gz +b9727015a58affcf3db527322bf8c4d2fcf39f5f6b8f15dbceca20206cbe1d95 opus-1.1.tar.gz +0c668639dcd16b14709fc9dc49e6686606f5a256f2eaa1ebaa2f39a66f8626cd opus-1.1.1-beta.tar.gz +66f2a5877c8803dc9a5a44b4f3d0bdc8f06bd066324222d144eb255612b68152 opus-1.1.1-rc.tar.gz +9b84ff56bd7720d5554103c557664efac2b8b18acc4bbcc234cb881ab9a3371e opus-1.1.1.tar.gz +0e290078e31211baa7b5886bcc8ab6bc048b9fc83882532da4a1a45e58e907fd opus-1.1.2.tar.gz +58b6fe802e7e30182e95d0cde890c0ace40b6f125cffc50635f0ad2eef69b633 opus-1.1.3.tar.gz +9122b6b380081dd2665189f97bfd777f04f92dc3ab6698eea1dbb27ad59d8692 opus-1.1.4.tar.gz +eb84981ca0f40a3e5d5e58d2e8582cb2fee05a022825a6dfe14d14b04eb563e4 opus-1.1.5.tar.gz +654a9bebb73266271a28edcfff431e4cfd9bfcde71f42849a0cdd73bece803a7 opus-1.2-alpha.tar.gz +c0e90507259cf21ce7b2c82fb9ac55367d8543dae91cc3d4d2c59afd37f44023 opus-1.2-alpha2.tar.gz +291e979a8a2fb679ed35a5dff5d761a9d9a5e22586fd07934ed94461e2636c7a opus-1.2-beta.tar.gz +85343fdaed96529d94c1e1f3a210fa51240d04ca62fa01e97ef02f88020c2ce9 opus-1.2-rc1.tar.gz +77db45a87b51578fbc49555ef1b10926179861d854eb2613207dc79d9ec0a9a9 opus-1.2.tar.gz +cfafd339ccd9c5ef8d6ab15d7e1a412c054bf4cb4ecbbbcc78c12ef2def70732 opus-1.2.1.tar.gz +7f56e058c9549d03ae35511ad9e16ef6d1eb257836830d54abff0f495f17e187 opus-1.3-beta.tar.gz +96fa28598e8ccd558b297277ad59a045c551ba0e06d65a9675938e084f837669 opus-1.3-rc.tar.gz +f6bab321fb81db984766f1e4d340a9e71a5ca2c5d4d53f4ee072e84afda271ca opus-1.3-rc2.tar.gz +4f3d69aefdf2dbaf9825408e452a8a414ffc60494c70633560700398820dc550 opus-1.3.tar.gz +94ac78ca4f74c4e43bc9fe4ec1ad0aa36f38ab90f45b0727c40dd1e96096e767 opus_testvectors-draft11.tar.gz +94ac78ca4f74c4e43bc9fe4ec1ad0aa36f38ab90f45b0727c40dd1e96096e767 opus_testvectors.tar.gz +6b26a22f9ba87b2b836906a9bb7afec5f8e54d49553b1200382520ee6fedfa55 opus_testvectors-rfc8251.tar.gz +5d2b99757bcb628bab2611f3ed27af6f35276ce3abc96c0ed4399d6c6463dda5 opus-tools-0.1.2.tar.gz +008317297d6ce84f84992abf8cc948a048a4fa135e1d1caf429fafde8965a792 opus-tools-0.1.3.tar.gz +de80485c5afa1fd83c0e16a0dd4860470c872997a7dd0a58e99b2ee8a93e5168 opus-tools-0.1.4.tar.gz +76678d0eb7a9b3d793bd0243f9ced9ab0ecdab263f5232ed940c8f5795fb0405 opus-tools-0.1.5.tar.gz +cc86dbc2a4d76da7e1ed9afee85448c8f798c465a5412233f178783220f3a2c1 opus-tools-0.1.6.tar.gz +e0f08d301555dffc417604269b5a85d2bd197f259c7d6c957f370ffd33d6d9cd opus-tools-0.1.7.tar.gz +e4e188579ea1c4e4d5066460d4a7214a7eafe3539e9a4466fdc98af41ba4a2f6 opus-tools-0.1.8.tar.gz +b1873dd78c7fbc98cf65d6e10cfddb5c2c03b3af93f922139a2104baedb4643a opus-tools-0.1.9.tar.gz +a2357532d19471b70666e0e0ec17d514246d8b3cb2eb168f68bb0f6fd372b28c opus-tools-0.1.10.tar.gz +b4e56cb00d3e509acfba9a9b627ffd8273b876b4e2408642259f6da28fa0ff86 opus-tools-0.2.tar.gz +bd6d14e8897a2f80065ef34a516c70e74f8e00060abdbc238e79e5f99bca3e96 libopusenc-0.1.tar.gz +02e6e0b14cbbe0569d948a46420f9c9a81d93bba32dc576a4007cbf96da68ef3 libopusenc-0.1.1.tar.gz +c79e95eeee43a0b965e9b2c59a243763a8f8b0a7e71441df2aa9084f6171c73a libopusenc-0.2.tar.gz +8298db61a8d3d63e41c1a80705baa8ce9ff3f50452ea7ec1c19a564fe106cbb9 libopusenc-0.2.1.tar.gz +8071b968475c1a17f54b6840d6de9d9ee20f930e827b0401abe3c4cf4f3bf30a opusfile-0.1.tar.gz +b4a678b3b6c4adfb6aff1f67ef658becfe146ea7c7ff228e99543762171557f9 opusfile-0.2.tar.gz +4248927f2c4e316ea5b84fb02bd100bfec8fa4624a6910d77f0af7f0c6cb8baa opusfile-0.3.tar.gz +9836ea11706c44f36de92c4c9b1248e03a4c521e7fb2cff18a0cb4f8b0e79140 opusfile-0.4.tar.gz +f187906b1b35f7f0d7de6a759b4aab512a9279d23adb35d8009e7e33bd6a922a opusfile-0.4.zip +2ce52d006aeeec9f10260dbe3073c4636954a1ab19c82b8baafefe0180aa4a39 opusfile-0.5.tar.gz +b940d62beb15b5974764574b9f265481fe5b6ee16902fb705727546caf956261 opusfile-0.5.zip +2428717b356e139f18ed2fdb5ad990b5654a238907a0058200b39c46a7d03ea6 opusfile-0.6.tar.gz +753339225193df605372944889023b9b3c5378d672e8784d69fa241cd465278c opusfile-0.6.zip +9e2bed13bc729058591a0f1cab2505e8cfd8e7ac460bf10a78bcc3b125e7c301 opusfile-0.7.tar.gz +346967d7989bb83b05949483b76bd0f69a12c59bd8b4457e864902b52bb0ac34 opusfile-0.7.zip +2c231ed3cfaa1b3173f52d740e5bbd77d51b9dfecb87014b404917fba4b855a4 opusfile-0.8.tar.gz +89dff4342c3b789574cbea5c57f11b96d4ebe4d28ab90248c1783ea569b1e9e3 opusfile-0.8.zip +f75fb500e40b122775ac1a71ad80c4477698842a8fe9da4a1b4a1a9f16e4e979 opusfile-0.9.tar.gz +e9591da4d4c9e857436c2d46a28a9e470fa5355ea5a76d4d582f137d18755d36 opusfile-0.9.zip +48e03526ba87ef9cf5f1c47b5ebe3aa195bd89b912a57060c36184a6cd19412f opusfile-0.10.tar.gz +9d9e95d01817ecf48bf6daaea8f071f9b45bd1751ca1fc8ce50e5075eb2bc3c8 opusfile-0.10.zip +74ce9b6cf4da103133e7b5c95df810ceb7195471e1162ed57af415fabf5603bf opusfile-0.11.tar.gz +23c5168026c4f1fc34843650135b409d0fc8cf452508163b4ece8077256ac6ff opusfile-0.11.zip diff --git a/extern/opus/scripts/dump_rnn.py b/extern/opus/scripts/dump_rnn.py new file mode 100755 index 0000000..dd66403 --- /dev/null +++ b/extern/opus/scripts/dump_rnn.py @@ -0,0 +1,57 @@ +#!/usr/bin/python + +from __future__ import print_function + +from keras.models import Sequential +from keras.layers import Dense +from keras.layers import LSTM +from keras.layers import GRU +from keras.models import load_model +from keras import backend as K + +import numpy as np + +def printVector(f, vector, name): + v = np.reshape(vector, (-1)); + #print('static const float ', name, '[', len(v), '] = \n', file=f) + f.write('static const opus_int16 {}[{}] = {{\n '.format(name, len(v))) + for i in range(0, len(v)): + f.write('{}'.format(int(round(8192*v[i])))) + if (i!=len(v)-1): + f.write(',') + else: + break; + if (i%8==7): + f.write("\n ") + else: + f.write(" ") + #print(v, file=f) + f.write('\n};\n\n') + return; + +def binary_crossentrop2(y_true, y_pred): + return K.mean(2*K.abs(y_true-0.5) * K.binary_crossentropy(y_pred, y_true), axis=-1) + + +model = load_model("weights.hdf5", custom_objects={'binary_crossentrop2': binary_crossentrop2}) + +weights = model.get_weights() + +f = open('rnn_weights.c', 'w') + +f.write('/*This file is automatically generated from a Keras model*/\n\n') +f.write('#ifdef HAVE_CONFIG_H\n#include "config.h"\n#endif\n\n#include "mlp.h"\n\n') + +printVector(f, weights[0], 'layer0_weights') +printVector(f, weights[1], 'layer0_bias') +printVector(f, weights[2], 'layer1_weights') +printVector(f, weights[3], 'layer1_recur_weights') +printVector(f, weights[4], 'layer1_bias') +printVector(f, weights[5], 'layer2_weights') +printVector(f, weights[6], 'layer2_bias') + +f.write('const DenseLayer layer0 = {\n layer0_bias,\n layer0_weights,\n 25, 16, 0\n};\n\n') +f.write('const GRULayer layer1 = {\n layer1_bias,\n layer1_weights,\n layer1_recur_weights,\n 16, 12\n};\n\n') +f.write('const DenseLayer layer2 = {\n layer2_bias,\n layer2_weights,\n 12, 2, 1\n};\n\n') + +f.close() diff --git a/extern/opus/scripts/rnn_train.py b/extern/opus/scripts/rnn_train.py new file mode 100755 index 0000000..ffdaa1e --- /dev/null +++ b/extern/opus/scripts/rnn_train.py @@ -0,0 +1,67 @@ +#!/usr/bin/python + +from __future__ import print_function + +from keras.models import Sequential +from keras.models import Model +from keras.layers import Input +from keras.layers import Dense +from keras.layers import LSTM +from keras.layers import GRU +from keras.layers import SimpleRNN +from keras.layers import Dropout +from keras import losses +import h5py + +from keras import backend as K +import numpy as np + +def binary_crossentrop2(y_true, y_pred): + return K.mean(2*K.abs(y_true-0.5) * K.binary_crossentropy(y_pred, y_true), axis=-1) + +print('Build model...') +#model = Sequential() +#model.add(Dense(16, activation='tanh', input_shape=(None, 25))) +#model.add(GRU(12, dropout=0.0, recurrent_dropout=0.0, activation='tanh', recurrent_activation='sigmoid', return_sequences=True)) +#model.add(Dense(2, activation='sigmoid')) + +main_input = Input(shape=(None, 25), name='main_input') +x = Dense(16, activation='tanh')(main_input) +x = GRU(12, dropout=0.1, recurrent_dropout=0.1, activation='tanh', recurrent_activation='sigmoid', return_sequences=True)(x) +x = Dense(2, activation='sigmoid')(x) +model = Model(inputs=main_input, outputs=x) + +batch_size = 64 + +print('Loading data...') +with h5py.File('features.h5', 'r') as hf: + all_data = hf['features'][:] +print('done.') + +window_size = 1500 + +nb_sequences = len(all_data)/window_size +print(nb_sequences, ' sequences') +x_train = all_data[:nb_sequences*window_size, :-2] +x_train = np.reshape(x_train, (nb_sequences, window_size, 25)) + +y_train = np.copy(all_data[:nb_sequences*window_size, -2:]) +y_train = np.reshape(y_train, (nb_sequences, window_size, 2)) + +all_data = 0; +x_train = x_train.astype('float32') +y_train = y_train.astype('float32') + +print(len(x_train), 'train sequences. x shape =', x_train.shape, 'y shape = ', y_train.shape) + +# try using different optimizers and different optimizer configs +model.compile(loss=binary_crossentrop2, + optimizer='adam', + metrics=['binary_accuracy']) + +print('Train...') +model.fit(x_train, y_train, + batch_size=batch_size, + epochs=200, + validation_data=(x_train, y_train)) +model.save("newweights.hdf5") diff --git a/extern/opus/silk/A2NLSF.c b/extern/opus/silk/A2NLSF.c new file mode 100644 index 0000000..b487686 --- /dev/null +++ b/extern/opus/silk/A2NLSF.c @@ -0,0 +1,267 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +/* Conversion between prediction filter coefficients and NLSFs */ +/* Requires the order to be an even number */ +/* A piecewise linear approximation maps LSF <-> cos(LSF) */ +/* Therefore the result is not accurate NLSFs, but the two */ +/* functions are accurate inverses of each other */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" +#include "tables.h" + +/* Number of binary divisions, when not in low complexity mode */ +#define BIN_DIV_STEPS_A2NLSF_FIX 3 /* must be no higher than 16 - log2( LSF_COS_TAB_SZ_FIX ) */ +#define MAX_ITERATIONS_A2NLSF_FIX 16 + +/* Helper function for A2NLSF(..) */ +/* Transforms polynomials from cos(n*f) to cos(f)^n */ +static OPUS_INLINE void silk_A2NLSF_trans_poly( + opus_int32 *p, /* I/O Polynomial */ + const opus_int dd /* I Polynomial order (= filter order / 2 ) */ +) +{ + opus_int k, n; + + for( k = 2; k <= dd; k++ ) { + for( n = dd; n > k; n-- ) { + p[ n - 2 ] -= p[ n ]; + } + p[ k - 2 ] -= silk_LSHIFT( p[ k ], 1 ); + } +} +/* Helper function for A2NLSF(..) */ +/* Polynomial evaluation */ +static OPUS_INLINE opus_int32 silk_A2NLSF_eval_poly( /* return the polynomial evaluation, in Q16 */ + opus_int32 *p, /* I Polynomial, Q16 */ + const opus_int32 x, /* I Evaluation point, Q12 */ + const opus_int dd /* I Order */ +) +{ + opus_int n; + opus_int32 x_Q16, y32; + + y32 = p[ dd ]; /* Q16 */ + x_Q16 = silk_LSHIFT( x, 4 ); + + if ( opus_likely( 8 == dd ) ) + { + y32 = silk_SMLAWW( p[ 7 ], y32, x_Q16 ); + y32 = silk_SMLAWW( p[ 6 ], y32, x_Q16 ); + y32 = silk_SMLAWW( p[ 5 ], y32, x_Q16 ); + y32 = silk_SMLAWW( p[ 4 ], y32, x_Q16 ); + y32 = silk_SMLAWW( p[ 3 ], y32, x_Q16 ); + y32 = silk_SMLAWW( p[ 2 ], y32, x_Q16 ); + y32 = silk_SMLAWW( p[ 1 ], y32, x_Q16 ); + y32 = silk_SMLAWW( p[ 0 ], y32, x_Q16 ); + } + else + { + for( n = dd - 1; n >= 0; n-- ) { + y32 = silk_SMLAWW( p[ n ], y32, x_Q16 ); /* Q16 */ + } + } + return y32; +} + +static OPUS_INLINE void silk_A2NLSF_init( + const opus_int32 *a_Q16, + opus_int32 *P, + opus_int32 *Q, + const opus_int dd +) +{ + opus_int k; + + /* Convert filter coefs to even and odd polynomials */ + P[dd] = silk_LSHIFT( 1, 16 ); + Q[dd] = silk_LSHIFT( 1, 16 ); + for( k = 0; k < dd; k++ ) { + P[ k ] = -a_Q16[ dd - k - 1 ] - a_Q16[ dd + k ]; /* Q16 */ + Q[ k ] = -a_Q16[ dd - k - 1 ] + a_Q16[ dd + k ]; /* Q16 */ + } + + /* Divide out zeros as we have that for even filter orders, */ + /* z = 1 is always a root in Q, and */ + /* z = -1 is always a root in P */ + for( k = dd; k > 0; k-- ) { + P[ k - 1 ] -= P[ k ]; + Q[ k - 1 ] += Q[ k ]; + } + + /* Transform polynomials from cos(n*f) to cos(f)^n */ + silk_A2NLSF_trans_poly( P, dd ); + silk_A2NLSF_trans_poly( Q, dd ); +} + +/* Compute Normalized Line Spectral Frequencies (NLSFs) from whitening filter coefficients */ +/* If not all roots are found, the a_Q16 coefficients are bandwidth expanded until convergence. */ +void silk_A2NLSF( + opus_int16 *NLSF, /* O Normalized Line Spectral Frequencies in Q15 (0..2^15-1) [d] */ + opus_int32 *a_Q16, /* I/O Monic whitening filter coefficients in Q16 [d] */ + const opus_int d /* I Filter order (must be even) */ +) +{ + opus_int i, k, m, dd, root_ix, ffrac; + opus_int32 xlo, xhi, xmid; + opus_int32 ylo, yhi, ymid, thr; + opus_int32 nom, den; + opus_int32 P[ SILK_MAX_ORDER_LPC / 2 + 1 ]; + opus_int32 Q[ SILK_MAX_ORDER_LPC / 2 + 1 ]; + opus_int32 *PQ[ 2 ]; + opus_int32 *p; + + /* Store pointers to array */ + PQ[ 0 ] = P; + PQ[ 1 ] = Q; + + dd = silk_RSHIFT( d, 1 ); + + silk_A2NLSF_init( a_Q16, P, Q, dd ); + + /* Find roots, alternating between P and Q */ + p = P; /* Pointer to polynomial */ + + xlo = silk_LSFCosTab_FIX_Q12[ 0 ]; /* Q12*/ + ylo = silk_A2NLSF_eval_poly( p, xlo, dd ); + + if( ylo < 0 ) { + /* Set the first NLSF to zero and move on to the next */ + NLSF[ 0 ] = 0; + p = Q; /* Pointer to polynomial */ + ylo = silk_A2NLSF_eval_poly( p, xlo, dd ); + root_ix = 1; /* Index of current root */ + } else { + root_ix = 0; /* Index of current root */ + } + k = 1; /* Loop counter */ + i = 0; /* Counter for bandwidth expansions applied */ + thr = 0; + while( 1 ) { + /* Evaluate polynomial */ + xhi = silk_LSFCosTab_FIX_Q12[ k ]; /* Q12 */ + yhi = silk_A2NLSF_eval_poly( p, xhi, dd ); + + /* Detect zero crossing */ + if( ( ylo <= 0 && yhi >= thr ) || ( ylo >= 0 && yhi <= -thr ) ) { + if( yhi == 0 ) { + /* If the root lies exactly at the end of the current */ + /* interval, look for the next root in the next interval */ + thr = 1; + } else { + thr = 0; + } + /* Binary division */ + ffrac = -256; + for( m = 0; m < BIN_DIV_STEPS_A2NLSF_FIX; m++ ) { + /* Evaluate polynomial */ + xmid = silk_RSHIFT_ROUND( xlo + xhi, 1 ); + ymid = silk_A2NLSF_eval_poly( p, xmid, dd ); + + /* Detect zero crossing */ + if( ( ylo <= 0 && ymid >= 0 ) || ( ylo >= 0 && ymid <= 0 ) ) { + /* Reduce frequency */ + xhi = xmid; + yhi = ymid; + } else { + /* Increase frequency */ + xlo = xmid; + ylo = ymid; + ffrac = silk_ADD_RSHIFT( ffrac, 128, m ); + } + } + + /* Interpolate */ + if( silk_abs( ylo ) < 65536 ) { + /* Avoid dividing by zero */ + den = ylo - yhi; + nom = silk_LSHIFT( ylo, 8 - BIN_DIV_STEPS_A2NLSF_FIX ) + silk_RSHIFT( den, 1 ); + if( den != 0 ) { + ffrac += silk_DIV32( nom, den ); + } + } else { + /* No risk of dividing by zero because abs(ylo - yhi) >= abs(ylo) >= 65536 */ + ffrac += silk_DIV32( ylo, silk_RSHIFT( ylo - yhi, 8 - BIN_DIV_STEPS_A2NLSF_FIX ) ); + } + NLSF[ root_ix ] = (opus_int16)silk_min_32( silk_LSHIFT( (opus_int32)k, 8 ) + ffrac, silk_int16_MAX ); + + silk_assert( NLSF[ root_ix ] >= 0 ); + + root_ix++; /* Next root */ + if( root_ix >= d ) { + /* Found all roots */ + break; + } + /* Alternate pointer to polynomial */ + p = PQ[ root_ix & 1 ]; + + /* Evaluate polynomial */ + xlo = silk_LSFCosTab_FIX_Q12[ k - 1 ]; /* Q12*/ + ylo = silk_LSHIFT( 1 - ( root_ix & 2 ), 12 ); + } else { + /* Increment loop counter */ + k++; + xlo = xhi; + ylo = yhi; + thr = 0; + + if( k > LSF_COS_TAB_SZ_FIX ) { + i++; + if( i > MAX_ITERATIONS_A2NLSF_FIX ) { + /* Set NLSFs to white spectrum and exit */ + NLSF[ 0 ] = (opus_int16)silk_DIV32_16( 1 << 15, d + 1 ); + for( k = 1; k < d; k++ ) { + NLSF[ k ] = (opus_int16)silk_ADD16( NLSF[ k-1 ], NLSF[ 0 ] ); + } + return; + } + + /* Error: Apply progressively more bandwidth expansion and run again */ + silk_bwexpander_32( a_Q16, d, 65536 - silk_LSHIFT( 1, i ) ); + + silk_A2NLSF_init( a_Q16, P, Q, dd ); + p = P; /* Pointer to polynomial */ + xlo = silk_LSFCosTab_FIX_Q12[ 0 ]; /* Q12*/ + ylo = silk_A2NLSF_eval_poly( p, xlo, dd ); + if( ylo < 0 ) { + /* Set the first NLSF to zero and move on to the next */ + NLSF[ 0 ] = 0; + p = Q; /* Pointer to polynomial */ + ylo = silk_A2NLSF_eval_poly( p, xlo, dd ); + root_ix = 1; /* Index of current root */ + } else { + root_ix = 0; /* Index of current root */ + } + k = 1; /* Reset loop counter */ + } + } + } +} diff --git a/extern/opus/silk/API.h b/extern/opus/silk/API.h new file mode 100644 index 0000000..4d90ff9 --- /dev/null +++ b/extern/opus/silk/API.h @@ -0,0 +1,135 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifndef SILK_API_H +#define SILK_API_H + +#include "control.h" +#include "typedef.h" +#include "errors.h" +#include "entenc.h" +#include "entdec.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +#define SILK_MAX_FRAMES_PER_PACKET 3 + +/* Struct for TOC (Table of Contents) */ +typedef struct { + opus_int VADFlag; /* Voice activity for packet */ + opus_int VADFlags[ SILK_MAX_FRAMES_PER_PACKET ]; /* Voice activity for each frame in packet */ + opus_int inbandFECFlag; /* Flag indicating if packet contains in-band FEC */ +} silk_TOC_struct; + +/****************************************/ +/* Encoder functions */ +/****************************************/ + +/***********************************************/ +/* Get size in bytes of the Silk encoder state */ +/***********************************************/ +opus_int silk_Get_Encoder_Size( /* O Returns error code */ + opus_int *encSizeBytes /* O Number of bytes in SILK encoder state */ +); + +/*************************/ +/* Init or reset encoder */ +/*************************/ +opus_int silk_InitEncoder( /* O Returns error code */ + void *encState, /* I/O State */ + int arch, /* I Run-time architecture */ + silk_EncControlStruct *encStatus /* O Encoder Status */ +); + +/**************************/ +/* Encode frame with Silk */ +/**************************/ +/* Note: if prefillFlag is set, the input must contain 10 ms of audio, irrespective of what */ +/* encControl->payloadSize_ms is set to */ +opus_int silk_Encode( /* O Returns error code */ + void *encState, /* I/O State */ + silk_EncControlStruct *encControl, /* I Control status */ + const opus_int16 *samplesIn, /* I Speech sample input vector */ + opus_int nSamplesIn, /* I Number of samples in input vector */ + ec_enc *psRangeEnc, /* I/O Compressor data structure */ + opus_int32 *nBytesOut, /* I/O Number of bytes in payload (input: Max bytes) */ + const opus_int prefillFlag, /* I Flag to indicate prefilling buffers no coding */ + int activity /* I Decision of Opus voice activity detector */ +); + +/****************************************/ +/* Decoder functions */ +/****************************************/ + +/***********************************************/ +/* Get size in bytes of the Silk decoder state */ +/***********************************************/ +opus_int silk_Get_Decoder_Size( /* O Returns error code */ + opus_int *decSizeBytes /* O Number of bytes in SILK decoder state */ +); + +/*************************/ +/* Init or Reset decoder */ +/*************************/ +opus_int silk_InitDecoder( /* O Returns error code */ + void *decState /* I/O State */ +); + +/******************/ +/* Decode a frame */ +/******************/ +opus_int silk_Decode( /* O Returns error code */ + void* decState, /* I/O State */ + silk_DecControlStruct* decControl, /* I/O Control Structure */ + opus_int lostFlag, /* I 0: no loss, 1 loss, 2 decode fec */ + opus_int newPacketFlag, /* I Indicates first decoder call for this packet */ + ec_dec *psRangeDec, /* I/O Compressor data structure */ + opus_int16 *samplesOut, /* O Decoded output speech vector */ + opus_int32 *nSamplesOut, /* O Number of samples decoded */ + int arch /* I Run-time architecture */ +); + +#if 0 +/**************************************/ +/* Get table of contents for a packet */ +/**************************************/ +opus_int silk_get_TOC( + const opus_uint8 *payload, /* I Payload data */ + const opus_int nBytesIn, /* I Number of input bytes */ + const opus_int nFramesPerPayload, /* I Number of SILK frames per payload */ + silk_TOC_struct *Silk_TOC /* O Type of content */ +); +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/extern/opus/silk/CNG.c b/extern/opus/silk/CNG.c new file mode 100644 index 0000000..ef8e38d --- /dev/null +++ b/extern/opus/silk/CNG.c @@ -0,0 +1,184 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" +#include "stack_alloc.h" + +/* Generates excitation for CNG LPC synthesis */ +static OPUS_INLINE void silk_CNG_exc( + opus_int32 exc_Q14[], /* O CNG excitation signal Q10 */ + opus_int32 exc_buf_Q14[], /* I Random samples buffer Q10 */ + opus_int length, /* I Length */ + opus_int32 *rand_seed /* I/O Seed to random index generator */ +) +{ + opus_int32 seed; + opus_int i, idx, exc_mask; + + exc_mask = CNG_BUF_MASK_MAX; + while( exc_mask > length ) { + exc_mask = silk_RSHIFT( exc_mask, 1 ); + } + + seed = *rand_seed; + for( i = 0; i < length; i++ ) { + seed = silk_RAND( seed ); + idx = (opus_int)( silk_RSHIFT( seed, 24 ) & exc_mask ); + silk_assert( idx >= 0 ); + silk_assert( idx <= CNG_BUF_MASK_MAX ); + exc_Q14[ i ] = exc_buf_Q14[ idx ]; + } + *rand_seed = seed; +} + +void silk_CNG_Reset( + silk_decoder_state *psDec /* I/O Decoder state */ +) +{ + opus_int i, NLSF_step_Q15, NLSF_acc_Q15; + + NLSF_step_Q15 = silk_DIV32_16( silk_int16_MAX, psDec->LPC_order + 1 ); + NLSF_acc_Q15 = 0; + for( i = 0; i < psDec->LPC_order; i++ ) { + NLSF_acc_Q15 += NLSF_step_Q15; + psDec->sCNG.CNG_smth_NLSF_Q15[ i ] = NLSF_acc_Q15; + } + psDec->sCNG.CNG_smth_Gain_Q16 = 0; + psDec->sCNG.rand_seed = 3176576; +} + +/* Updates CNG estimate, and applies the CNG when packet was lost */ +void silk_CNG( + silk_decoder_state *psDec, /* I/O Decoder state */ + silk_decoder_control *psDecCtrl, /* I/O Decoder control */ + opus_int16 frame[], /* I/O Signal */ + opus_int length /* I Length of residual */ +) +{ + opus_int i, subfr; + opus_int32 LPC_pred_Q10, max_Gain_Q16, gain_Q16, gain_Q10; + opus_int16 A_Q12[ MAX_LPC_ORDER ]; + silk_CNG_struct *psCNG = &psDec->sCNG; + SAVE_STACK; + + if( psDec->fs_kHz != psCNG->fs_kHz ) { + /* Reset state */ + silk_CNG_Reset( psDec ); + + psCNG->fs_kHz = psDec->fs_kHz; + } + if( psDec->lossCnt == 0 && psDec->prevSignalType == TYPE_NO_VOICE_ACTIVITY ) { + /* Update CNG parameters */ + + /* Smoothing of LSF's */ + for( i = 0; i < psDec->LPC_order; i++ ) { + psCNG->CNG_smth_NLSF_Q15[ i ] += silk_SMULWB( (opus_int32)psDec->prevNLSF_Q15[ i ] - (opus_int32)psCNG->CNG_smth_NLSF_Q15[ i ], CNG_NLSF_SMTH_Q16 ); + } + /* Find the subframe with the highest gain */ + max_Gain_Q16 = 0; + subfr = 0; + for( i = 0; i < psDec->nb_subfr; i++ ) { + if( psDecCtrl->Gains_Q16[ i ] > max_Gain_Q16 ) { + max_Gain_Q16 = psDecCtrl->Gains_Q16[ i ]; + subfr = i; + } + } + /* Update CNG excitation buffer with excitation from this subframe */ + silk_memmove( &psCNG->CNG_exc_buf_Q14[ psDec->subfr_length ], psCNG->CNG_exc_buf_Q14, ( psDec->nb_subfr - 1 ) * psDec->subfr_length * sizeof( opus_int32 ) ); + silk_memcpy( psCNG->CNG_exc_buf_Q14, &psDec->exc_Q14[ subfr * psDec->subfr_length ], psDec->subfr_length * sizeof( opus_int32 ) ); + + /* Smooth gains */ + for( i = 0; i < psDec->nb_subfr; i++ ) { + psCNG->CNG_smth_Gain_Q16 += silk_SMULWB( psDecCtrl->Gains_Q16[ i ] - psCNG->CNG_smth_Gain_Q16, CNG_GAIN_SMTH_Q16 ); + } + } + + /* Add CNG when packet is lost or during DTX */ + if( psDec->lossCnt ) { + VARDECL( opus_int32, CNG_sig_Q14 ); + ALLOC( CNG_sig_Q14, length + MAX_LPC_ORDER, opus_int32 ); + + /* Generate CNG excitation */ + gain_Q16 = silk_SMULWW( psDec->sPLC.randScale_Q14, psDec->sPLC.prevGain_Q16[1] ); + if( gain_Q16 >= (1 << 21) || psCNG->CNG_smth_Gain_Q16 > (1 << 23) ) { + gain_Q16 = silk_SMULTT( gain_Q16, gain_Q16 ); + gain_Q16 = silk_SUB_LSHIFT32(silk_SMULTT( psCNG->CNG_smth_Gain_Q16, psCNG->CNG_smth_Gain_Q16 ), gain_Q16, 5 ); + gain_Q16 = silk_LSHIFT32( silk_SQRT_APPROX( gain_Q16 ), 16 ); + } else { + gain_Q16 = silk_SMULWW( gain_Q16, gain_Q16 ); + gain_Q16 = silk_SUB_LSHIFT32(silk_SMULWW( psCNG->CNG_smth_Gain_Q16, psCNG->CNG_smth_Gain_Q16 ), gain_Q16, 5 ); + gain_Q16 = silk_LSHIFT32( silk_SQRT_APPROX( gain_Q16 ), 8 ); + } + gain_Q10 = silk_RSHIFT( gain_Q16, 6 ); + + silk_CNG_exc( CNG_sig_Q14 + MAX_LPC_ORDER, psCNG->CNG_exc_buf_Q14, length, &psCNG->rand_seed ); + + /* Convert CNG NLSF to filter representation */ + silk_NLSF2A( A_Q12, psCNG->CNG_smth_NLSF_Q15, psDec->LPC_order, psDec->arch ); + + /* Generate CNG signal, by synthesis filtering */ + silk_memcpy( CNG_sig_Q14, psCNG->CNG_synth_state, MAX_LPC_ORDER * sizeof( opus_int32 ) ); + celt_assert( psDec->LPC_order == 10 || psDec->LPC_order == 16 ); + for( i = 0; i < length; i++ ) { + /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */ + LPC_pred_Q10 = silk_RSHIFT( psDec->LPC_order, 1 ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 1 ], A_Q12[ 0 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 2 ], A_Q12[ 1 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 3 ], A_Q12[ 2 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 4 ], A_Q12[ 3 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 5 ], A_Q12[ 4 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 6 ], A_Q12[ 5 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 7 ], A_Q12[ 6 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 8 ], A_Q12[ 7 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 9 ], A_Q12[ 8 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 10 ], A_Q12[ 9 ] ); + if( psDec->LPC_order == 16 ) { + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 11 ], A_Q12[ 10 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 12 ], A_Q12[ 11 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 13 ], A_Q12[ 12 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 14 ], A_Q12[ 13 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 15 ], A_Q12[ 14 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 16 ], A_Q12[ 15 ] ); + } + + /* Update states */ + CNG_sig_Q14[ MAX_LPC_ORDER + i ] = silk_ADD_SAT32( CNG_sig_Q14[ MAX_LPC_ORDER + i ], silk_LSHIFT_SAT32( LPC_pred_Q10, 4 ) ); + + /* Scale with Gain and add to input signal */ + frame[ i ] = (opus_int16)silk_ADD_SAT16( frame[ i ], silk_SAT16( silk_RSHIFT_ROUND( silk_SMULWW( CNG_sig_Q14[ MAX_LPC_ORDER + i ], gain_Q10 ), 8 ) ) ); + + } + silk_memcpy( psCNG->CNG_synth_state, &CNG_sig_Q14[ length ], MAX_LPC_ORDER * sizeof( opus_int32 ) ); + } else { + silk_memset( psCNG->CNG_synth_state, 0, psDec->LPC_order * sizeof( opus_int32 ) ); + } + RESTORE_STACK; +} diff --git a/extern/opus/silk/HP_variable_cutoff.c b/extern/opus/silk/HP_variable_cutoff.c new file mode 100644 index 0000000..bbe10f0 --- /dev/null +++ b/extern/opus/silk/HP_variable_cutoff.c @@ -0,0 +1,77 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#ifdef FIXED_POINT +#include "main_FIX.h" +#else +#include "main_FLP.h" +#endif +#include "tuning_parameters.h" + +/* High-pass filter with cutoff frequency adaptation based on pitch lag statistics */ +void silk_HP_variable_cutoff( + silk_encoder_state_Fxx state_Fxx[] /* I/O Encoder states */ +) +{ + opus_int quality_Q15; + opus_int32 pitch_freq_Hz_Q16, pitch_freq_log_Q7, delta_freq_Q7; + silk_encoder_state *psEncC1 = &state_Fxx[ 0 ].sCmn; + + /* Adaptive cutoff frequency: estimate low end of pitch frequency range */ + if( psEncC1->prevSignalType == TYPE_VOICED ) { + /* difference, in log domain */ + pitch_freq_Hz_Q16 = silk_DIV32_16( silk_LSHIFT( silk_MUL( psEncC1->fs_kHz, 1000 ), 16 ), psEncC1->prevLag ); + pitch_freq_log_Q7 = silk_lin2log( pitch_freq_Hz_Q16 ) - ( 16 << 7 ); + + /* adjustment based on quality */ + quality_Q15 = psEncC1->input_quality_bands_Q15[ 0 ]; + pitch_freq_log_Q7 = silk_SMLAWB( pitch_freq_log_Q7, silk_SMULWB( silk_LSHIFT( -quality_Q15, 2 ), quality_Q15 ), + pitch_freq_log_Q7 - ( silk_lin2log( SILK_FIX_CONST( VARIABLE_HP_MIN_CUTOFF_HZ, 16 ) ) - ( 16 << 7 ) ) ); + + /* delta_freq = pitch_freq_log - psEnc->variable_HP_smth1; */ + delta_freq_Q7 = pitch_freq_log_Q7 - silk_RSHIFT( psEncC1->variable_HP_smth1_Q15, 8 ); + if( delta_freq_Q7 < 0 ) { + /* less smoothing for decreasing pitch frequency, to track something close to the minimum */ + delta_freq_Q7 = silk_MUL( delta_freq_Q7, 3 ); + } + + /* limit delta, to reduce impact of outliers in pitch estimation */ + delta_freq_Q7 = silk_LIMIT_32( delta_freq_Q7, -SILK_FIX_CONST( VARIABLE_HP_MAX_DELTA_FREQ, 7 ), SILK_FIX_CONST( VARIABLE_HP_MAX_DELTA_FREQ, 7 ) ); + + /* update smoother */ + psEncC1->variable_HP_smth1_Q15 = silk_SMLAWB( psEncC1->variable_HP_smth1_Q15, + silk_SMULBB( psEncC1->speech_activity_Q8, delta_freq_Q7 ), SILK_FIX_CONST( VARIABLE_HP_SMTH_COEF1, 16 ) ); + + /* limit frequency range */ + psEncC1->variable_HP_smth1_Q15 = silk_LIMIT_32( psEncC1->variable_HP_smth1_Q15, + silk_LSHIFT( silk_lin2log( VARIABLE_HP_MIN_CUTOFF_HZ ), 8 ), + silk_LSHIFT( silk_lin2log( VARIABLE_HP_MAX_CUTOFF_HZ ), 8 ) ); + } +} diff --git a/extern/opus/silk/Inlines.h b/extern/opus/silk/Inlines.h new file mode 100644 index 0000000..ec986cd --- /dev/null +++ b/extern/opus/silk/Inlines.h @@ -0,0 +1,188 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +/*! \file silk_Inlines.h + * \brief silk_Inlines.h defines OPUS_INLINE signal processing functions. + */ + +#ifndef SILK_FIX_INLINES_H +#define SILK_FIX_INLINES_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* count leading zeros of opus_int64 */ +static OPUS_INLINE opus_int32 silk_CLZ64( opus_int64 in ) +{ + opus_int32 in_upper; + + in_upper = (opus_int32)silk_RSHIFT64(in, 32); + if (in_upper == 0) { + /* Search in the lower 32 bits */ + return 32 + silk_CLZ32( (opus_int32) in ); + } else { + /* Search in the upper 32 bits */ + return silk_CLZ32( in_upper ); + } +} + +/* get number of leading zeros and fractional part (the bits right after the leading one */ +static OPUS_INLINE void silk_CLZ_FRAC( + opus_int32 in, /* I input */ + opus_int32 *lz, /* O number of leading zeros */ + opus_int32 *frac_Q7 /* O the 7 bits right after the leading one */ +) +{ + opus_int32 lzeros = silk_CLZ32(in); + + * lz = lzeros; + * frac_Q7 = silk_ROR32(in, 24 - lzeros) & 0x7f; +} + +/* Approximation of square root */ +/* Accuracy: < +/- 10% for output values > 15 */ +/* < +/- 2.5% for output values > 120 */ +static OPUS_INLINE opus_int32 silk_SQRT_APPROX( opus_int32 x ) +{ + opus_int32 y, lz, frac_Q7; + + if( x <= 0 ) { + return 0; + } + + silk_CLZ_FRAC(x, &lz, &frac_Q7); + + if( lz & 1 ) { + y = 32768; + } else { + y = 46214; /* 46214 = sqrt(2) * 32768 */ + } + + /* get scaling right */ + y >>= silk_RSHIFT(lz, 1); + + /* increment using fractional part of input */ + y = silk_SMLAWB(y, y, silk_SMULBB(213, frac_Q7)); + + return y; +} + +/* Divide two int32 values and return result as int32 in a given Q-domain */ +static OPUS_INLINE opus_int32 silk_DIV32_varQ( /* O returns a good approximation of "(a32 << Qres) / b32" */ + const opus_int32 a32, /* I numerator (Q0) */ + const opus_int32 b32, /* I denominator (Q0) */ + const opus_int Qres /* I Q-domain of result (>= 0) */ +) +{ + opus_int a_headrm, b_headrm, lshift; + opus_int32 b32_inv, a32_nrm, b32_nrm, result; + + silk_assert( b32 != 0 ); + silk_assert( Qres >= 0 ); + + /* Compute number of bits head room and normalize inputs */ + a_headrm = silk_CLZ32( silk_abs(a32) ) - 1; + a32_nrm = silk_LSHIFT(a32, a_headrm); /* Q: a_headrm */ + b_headrm = silk_CLZ32( silk_abs(b32) ) - 1; + b32_nrm = silk_LSHIFT(b32, b_headrm); /* Q: b_headrm */ + + /* Inverse of b32, with 14 bits of precision */ + b32_inv = silk_DIV32_16( silk_int32_MAX >> 2, silk_RSHIFT(b32_nrm, 16) ); /* Q: 29 + 16 - b_headrm */ + + /* First approximation */ + result = silk_SMULWB(a32_nrm, b32_inv); /* Q: 29 + a_headrm - b_headrm */ + + /* Compute residual by subtracting product of denominator and first approximation */ + /* It's OK to overflow because the final value of a32_nrm should always be small */ + a32_nrm = silk_SUB32_ovflw(a32_nrm, silk_LSHIFT_ovflw( silk_SMMUL(b32_nrm, result), 3 )); /* Q: a_headrm */ + + /* Refinement */ + result = silk_SMLAWB(result, a32_nrm, b32_inv); /* Q: 29 + a_headrm - b_headrm */ + + /* Convert to Qres domain */ + lshift = 29 + a_headrm - b_headrm - Qres; + if( lshift < 0 ) { + return silk_LSHIFT_SAT32(result, -lshift); + } else { + if( lshift < 32){ + return silk_RSHIFT(result, lshift); + } else { + /* Avoid undefined result */ + return 0; + } + } +} + +/* Invert int32 value and return result as int32 in a given Q-domain */ +static OPUS_INLINE opus_int32 silk_INVERSE32_varQ( /* O returns a good approximation of "(1 << Qres) / b32" */ + const opus_int32 b32, /* I denominator (Q0) */ + const opus_int Qres /* I Q-domain of result (> 0) */ +) +{ + opus_int b_headrm, lshift; + opus_int32 b32_inv, b32_nrm, err_Q32, result; + + silk_assert( b32 != 0 ); + silk_assert( Qres > 0 ); + + /* Compute number of bits head room and normalize input */ + b_headrm = silk_CLZ32( silk_abs(b32) ) - 1; + b32_nrm = silk_LSHIFT(b32, b_headrm); /* Q: b_headrm */ + + /* Inverse of b32, with 14 bits of precision */ + b32_inv = silk_DIV32_16( silk_int32_MAX >> 2, silk_RSHIFT(b32_nrm, 16) ); /* Q: 29 + 16 - b_headrm */ + + /* First approximation */ + result = silk_LSHIFT(b32_inv, 16); /* Q: 61 - b_headrm */ + + /* Compute residual by subtracting product of denominator and first approximation from one */ + err_Q32 = silk_LSHIFT( ((opus_int32)1<<29) - silk_SMULWB(b32_nrm, b32_inv), 3 ); /* Q32 */ + + /* Refinement */ + result = silk_SMLAWW(result, err_Q32, b32_inv); /* Q: 61 - b_headrm */ + + /* Convert to Qres domain */ + lshift = 61 - b_headrm - Qres; + if( lshift <= 0 ) { + return silk_LSHIFT_SAT32(result, -lshift); + } else { + if( lshift < 32){ + return silk_RSHIFT(result, lshift); + }else{ + /* Avoid undefined result */ + return 0; + } + } +} + +#ifdef __cplusplus +} +#endif + +#endif /* SILK_FIX_INLINES_H */ diff --git a/extern/opus/silk/LPC_analysis_filter.c b/extern/opus/silk/LPC_analysis_filter.c new file mode 100644 index 0000000..d34b5eb --- /dev/null +++ b/extern/opus/silk/LPC_analysis_filter.c @@ -0,0 +1,111 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" +#include "celt_lpc.h" + +/*******************************************/ +/* LPC analysis filter */ +/* NB! State is kept internally and the */ +/* filter always starts with zero state */ +/* first d output samples are set to zero */ +/*******************************************/ + +/* OPT: Using celt_fir() for this function should be faster, but it may cause + integer overflows in intermediate values (not final results), which the + current implementation silences by casting to unsigned. Enabling + this should be safe in pretty much all cases, even though it is not technically + C89-compliant. */ +#define USE_CELT_FIR 0 + +void silk_LPC_analysis_filter( + opus_int16 *out, /* O Output signal */ + const opus_int16 *in, /* I Input signal */ + const opus_int16 *B, /* I MA prediction coefficients, Q12 [order] */ + const opus_int32 len, /* I Signal length */ + const opus_int32 d, /* I Filter order */ + int arch /* I Run-time architecture */ +) +{ + opus_int j; +#if defined(FIXED_POINT) && USE_CELT_FIR + opus_int16 num[SILK_MAX_ORDER_LPC]; +#else + int ix; + opus_int32 out32_Q12, out32; + const opus_int16 *in_ptr; +#endif + + celt_assert( d >= 6 ); + celt_assert( (d & 1) == 0 ); + celt_assert( d <= len ); + +#if defined(FIXED_POINT) && USE_CELT_FIR + celt_assert( d <= SILK_MAX_ORDER_LPC ); + for ( j = 0; j < d; j++ ) { + num[ j ] = -B[ j ]; + } + celt_fir( in + d, num, out + d, len - d, d, arch ); + for ( j = 0; j < d; j++ ) { + out[ j ] = 0; + } +#else + (void)arch; + for( ix = d; ix < len; ix++ ) { + in_ptr = &in[ ix - 1 ]; + + out32_Q12 = silk_SMULBB( in_ptr[ 0 ], B[ 0 ] ); + /* Allowing wrap around so that two wraps can cancel each other. The rare + cases where the result wraps around can only be triggered by invalid streams*/ + out32_Q12 = silk_SMLABB_ovflw( out32_Q12, in_ptr[ -1 ], B[ 1 ] ); + out32_Q12 = silk_SMLABB_ovflw( out32_Q12, in_ptr[ -2 ], B[ 2 ] ); + out32_Q12 = silk_SMLABB_ovflw( out32_Q12, in_ptr[ -3 ], B[ 3 ] ); + out32_Q12 = silk_SMLABB_ovflw( out32_Q12, in_ptr[ -4 ], B[ 4 ] ); + out32_Q12 = silk_SMLABB_ovflw( out32_Q12, in_ptr[ -5 ], B[ 5 ] ); + for( j = 6; j < d; j += 2 ) { + out32_Q12 = silk_SMLABB_ovflw( out32_Q12, in_ptr[ -j ], B[ j ] ); + out32_Q12 = silk_SMLABB_ovflw( out32_Q12, in_ptr[ -j - 1 ], B[ j + 1 ] ); + } + + /* Subtract prediction */ + out32_Q12 = silk_SUB32_ovflw( silk_LSHIFT( (opus_int32)in_ptr[ 1 ], 12 ), out32_Q12 ); + + /* Scale to Q0 */ + out32 = silk_RSHIFT_ROUND( out32_Q12, 12 ); + + /* Saturate output */ + out[ ix ] = (opus_int16)silk_SAT16( out32 ); + } + + /* Set first d output samples to zero */ + silk_memset( out, 0, d * sizeof( opus_int16 ) ); +#endif +} diff --git a/extern/opus/silk/LPC_fit.c b/extern/opus/silk/LPC_fit.c new file mode 100644 index 0000000..cdea4f3 --- /dev/null +++ b/extern/opus/silk/LPC_fit.c @@ -0,0 +1,81 @@ +/*********************************************************************** +Copyright (c) 2013, Koen Vos. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" + +/* Convert int32 coefficients to int16 coefs and make sure there's no wrap-around */ +void silk_LPC_fit( + opus_int16 *a_QOUT, /* O Output signal */ + opus_int32 *a_QIN, /* I/O Input signal */ + const opus_int QOUT, /* I Input Q domain */ + const opus_int QIN, /* I Input Q domain */ + const opus_int d /* I Filter order */ +) +{ + opus_int i, k, idx = 0; + opus_int32 maxabs, absval, chirp_Q16; + + /* Limit the maximum absolute value of the prediction coefficients, so that they'll fit in int16 */ + for( i = 0; i < 10; i++ ) { + /* Find maximum absolute value and its index */ + maxabs = 0; + for( k = 0; k < d; k++ ) { + absval = silk_abs( a_QIN[k] ); + if( absval > maxabs ) { + maxabs = absval; + idx = k; + } + } + maxabs = silk_RSHIFT_ROUND( maxabs, QIN - QOUT ); + + if( maxabs > silk_int16_MAX ) { + /* Reduce magnitude of prediction coefficients */ + maxabs = silk_min( maxabs, 163838 ); /* ( silk_int32_MAX >> 14 ) + silk_int16_MAX = 163838 */ + chirp_Q16 = SILK_FIX_CONST( 0.999, 16 ) - silk_DIV32( silk_LSHIFT( maxabs - silk_int16_MAX, 14 ), + silk_RSHIFT32( silk_MUL( maxabs, idx + 1), 2 ) ); + silk_bwexpander_32( a_QIN, d, chirp_Q16 ); + } else { + break; + } + } + + if( i == 10 ) { + /* Reached the last iteration, clip the coefficients */ + for( k = 0; k < d; k++ ) { + a_QOUT[ k ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( a_QIN[ k ], QIN - QOUT ) ); + a_QIN[ k ] = silk_LSHIFT( (opus_int32)a_QOUT[ k ], QIN - QOUT ); + } + } else { + for( k = 0; k < d; k++ ) { + a_QOUT[ k ] = (opus_int16)silk_RSHIFT_ROUND( a_QIN[ k ], QIN - QOUT ); + } + } +} diff --git a/extern/opus/silk/LPC_inv_pred_gain.c b/extern/opus/silk/LPC_inv_pred_gain.c new file mode 100644 index 0000000..a3746a6 --- /dev/null +++ b/extern/opus/silk/LPC_inv_pred_gain.c @@ -0,0 +1,141 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" +#include "define.h" + +#define QA 24 +#define A_LIMIT SILK_FIX_CONST( 0.99975, QA ) + +#define MUL32_FRAC_Q(a32, b32, Q) ((opus_int32)(silk_RSHIFT_ROUND64(silk_SMULL(a32, b32), Q))) + +/* Compute inverse of LPC prediction gain, and */ +/* test if LPC coefficients are stable (all poles within unit circle) */ +static opus_int32 LPC_inverse_pred_gain_QA_c( /* O Returns inverse prediction gain in energy domain, Q30 */ + opus_int32 A_QA[ SILK_MAX_ORDER_LPC ], /* I Prediction coefficients */ + const opus_int order /* I Prediction order */ +) +{ + opus_int k, n, mult2Q; + opus_int32 invGain_Q30, rc_Q31, rc_mult1_Q30, rc_mult2, tmp1, tmp2; + + invGain_Q30 = SILK_FIX_CONST( 1, 30 ); + for( k = order - 1; k > 0; k-- ) { + /* Check for stability */ + if( ( A_QA[ k ] > A_LIMIT ) || ( A_QA[ k ] < -A_LIMIT ) ) { + return 0; + } + + /* Set RC equal to negated AR coef */ + rc_Q31 = -silk_LSHIFT( A_QA[ k ], 31 - QA ); + + /* rc_mult1_Q30 range: [ 1 : 2^30 ] */ + rc_mult1_Q30 = silk_SUB32( SILK_FIX_CONST( 1, 30 ), silk_SMMUL( rc_Q31, rc_Q31 ) ); + silk_assert( rc_mult1_Q30 > ( 1 << 15 ) ); /* reduce A_LIMIT if fails */ + silk_assert( rc_mult1_Q30 <= ( 1 << 30 ) ); + + /* Update inverse gain */ + /* invGain_Q30 range: [ 0 : 2^30 ] */ + invGain_Q30 = silk_LSHIFT( silk_SMMUL( invGain_Q30, rc_mult1_Q30 ), 2 ); + silk_assert( invGain_Q30 >= 0 ); + silk_assert( invGain_Q30 <= ( 1 << 30 ) ); + if( invGain_Q30 < SILK_FIX_CONST( 1.0f / MAX_PREDICTION_POWER_GAIN, 30 ) ) { + return 0; + } + + /* rc_mult2 range: [ 2^30 : silk_int32_MAX ] */ + mult2Q = 32 - silk_CLZ32( silk_abs( rc_mult1_Q30 ) ); + rc_mult2 = silk_INVERSE32_varQ( rc_mult1_Q30, mult2Q + 30 ); + + /* Update AR coefficient */ + for( n = 0; n < (k + 1) >> 1; n++ ) { + opus_int64 tmp64; + tmp1 = A_QA[ n ]; + tmp2 = A_QA[ k - n - 1 ]; + tmp64 = silk_RSHIFT_ROUND64( silk_SMULL( silk_SUB_SAT32(tmp1, + MUL32_FRAC_Q( tmp2, rc_Q31, 31 ) ), rc_mult2 ), mult2Q); + if( tmp64 > silk_int32_MAX || tmp64 < silk_int32_MIN ) { + return 0; + } + A_QA[ n ] = ( opus_int32 )tmp64; + tmp64 = silk_RSHIFT_ROUND64( silk_SMULL( silk_SUB_SAT32(tmp2, + MUL32_FRAC_Q( tmp1, rc_Q31, 31 ) ), rc_mult2), mult2Q); + if( tmp64 > silk_int32_MAX || tmp64 < silk_int32_MIN ) { + return 0; + } + A_QA[ k - n - 1 ] = ( opus_int32 )tmp64; + } + } + + /* Check for stability */ + if( ( A_QA[ k ] > A_LIMIT ) || ( A_QA[ k ] < -A_LIMIT ) ) { + return 0; + } + + /* Set RC equal to negated AR coef */ + rc_Q31 = -silk_LSHIFT( A_QA[ 0 ], 31 - QA ); + + /* Range: [ 1 : 2^30 ] */ + rc_mult1_Q30 = silk_SUB32( SILK_FIX_CONST( 1, 30 ), silk_SMMUL( rc_Q31, rc_Q31 ) ); + + /* Update inverse gain */ + /* Range: [ 0 : 2^30 ] */ + invGain_Q30 = silk_LSHIFT( silk_SMMUL( invGain_Q30, rc_mult1_Q30 ), 2 ); + silk_assert( invGain_Q30 >= 0 ); + silk_assert( invGain_Q30 <= ( 1 << 30 ) ); + if( invGain_Q30 < SILK_FIX_CONST( 1.0f / MAX_PREDICTION_POWER_GAIN, 30 ) ) { + return 0; + } + + return invGain_Q30; +} + +/* For input in Q12 domain */ +opus_int32 silk_LPC_inverse_pred_gain_c( /* O Returns inverse prediction gain in energy domain, Q30 */ + const opus_int16 *A_Q12, /* I Prediction coefficients, Q12 [order] */ + const opus_int order /* I Prediction order */ +) +{ + opus_int k; + opus_int32 Atmp_QA[ SILK_MAX_ORDER_LPC ]; + opus_int32 DC_resp = 0; + + /* Increase Q domain of the AR coefficients */ + for( k = 0; k < order; k++ ) { + DC_resp += (opus_int32)A_Q12[ k ]; + Atmp_QA[ k ] = silk_LSHIFT32( (opus_int32)A_Q12[ k ], QA - 12 ); + } + /* If the DC is unstable, we don't even need to do the full calculations */ + if( DC_resp >= 4096 ) { + return 0; + } + return LPC_inverse_pred_gain_QA_c( Atmp_QA, order ); +} diff --git a/extern/opus/silk/LP_variable_cutoff.c b/extern/opus/silk/LP_variable_cutoff.c new file mode 100644 index 0000000..79112ad --- /dev/null +++ b/extern/opus/silk/LP_variable_cutoff.c @@ -0,0 +1,135 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/* + Elliptic/Cauer filters designed with 0.1 dB passband ripple, + 80 dB minimum stopband attenuation, and + [0.95 : 0.15 : 0.35] normalized cut off frequencies. +*/ + +#include "main.h" + +/* Helper function, interpolates the filter taps */ +static OPUS_INLINE void silk_LP_interpolate_filter_taps( + opus_int32 B_Q28[ TRANSITION_NB ], + opus_int32 A_Q28[ TRANSITION_NA ], + const opus_int ind, + const opus_int32 fac_Q16 +) +{ + opus_int nb, na; + + if( ind < TRANSITION_INT_NUM - 1 ) { + if( fac_Q16 > 0 ) { + if( fac_Q16 < 32768 ) { /* fac_Q16 is in range of a 16-bit int */ + /* Piece-wise linear interpolation of B and A */ + for( nb = 0; nb < TRANSITION_NB; nb++ ) { + B_Q28[ nb ] = silk_SMLAWB( + silk_Transition_LP_B_Q28[ ind ][ nb ], + silk_Transition_LP_B_Q28[ ind + 1 ][ nb ] - + silk_Transition_LP_B_Q28[ ind ][ nb ], + fac_Q16 ); + } + for( na = 0; na < TRANSITION_NA; na++ ) { + A_Q28[ na ] = silk_SMLAWB( + silk_Transition_LP_A_Q28[ ind ][ na ], + silk_Transition_LP_A_Q28[ ind + 1 ][ na ] - + silk_Transition_LP_A_Q28[ ind ][ na ], + fac_Q16 ); + } + } else { /* ( fac_Q16 - ( 1 << 16 ) ) is in range of a 16-bit int */ + silk_assert( fac_Q16 - ( 1 << 16 ) == silk_SAT16( fac_Q16 - ( 1 << 16 ) ) ); + /* Piece-wise linear interpolation of B and A */ + for( nb = 0; nb < TRANSITION_NB; nb++ ) { + B_Q28[ nb ] = silk_SMLAWB( + silk_Transition_LP_B_Q28[ ind + 1 ][ nb ], + silk_Transition_LP_B_Q28[ ind + 1 ][ nb ] - + silk_Transition_LP_B_Q28[ ind ][ nb ], + fac_Q16 - ( (opus_int32)1 << 16 ) ); + } + for( na = 0; na < TRANSITION_NA; na++ ) { + A_Q28[ na ] = silk_SMLAWB( + silk_Transition_LP_A_Q28[ ind + 1 ][ na ], + silk_Transition_LP_A_Q28[ ind + 1 ][ na ] - + silk_Transition_LP_A_Q28[ ind ][ na ], + fac_Q16 - ( (opus_int32)1 << 16 ) ); + } + } + } else { + silk_memcpy( B_Q28, silk_Transition_LP_B_Q28[ ind ], TRANSITION_NB * sizeof( opus_int32 ) ); + silk_memcpy( A_Q28, silk_Transition_LP_A_Q28[ ind ], TRANSITION_NA * sizeof( opus_int32 ) ); + } + } else { + silk_memcpy( B_Q28, silk_Transition_LP_B_Q28[ TRANSITION_INT_NUM - 1 ], TRANSITION_NB * sizeof( opus_int32 ) ); + silk_memcpy( A_Q28, silk_Transition_LP_A_Q28[ TRANSITION_INT_NUM - 1 ], TRANSITION_NA * sizeof( opus_int32 ) ); + } +} + +/* Low-pass filter with variable cutoff frequency based on */ +/* piece-wise linear interpolation between elliptic filters */ +/* Start by setting psEncC->mode <> 0; */ +/* Deactivate by setting psEncC->mode = 0; */ +void silk_LP_variable_cutoff( + silk_LP_state *psLP, /* I/O LP filter state */ + opus_int16 *frame, /* I/O Low-pass filtered output signal */ + const opus_int frame_length /* I Frame length */ +) +{ + opus_int32 B_Q28[ TRANSITION_NB ], A_Q28[ TRANSITION_NA ], fac_Q16 = 0; + opus_int ind = 0; + + silk_assert( psLP->transition_frame_no >= 0 && psLP->transition_frame_no <= TRANSITION_FRAMES ); + + /* Run filter if needed */ + if( psLP->mode != 0 ) { + /* Calculate index and interpolation factor for interpolation */ +#if( TRANSITION_INT_STEPS == 64 ) + fac_Q16 = silk_LSHIFT( TRANSITION_FRAMES - psLP->transition_frame_no, 16 - 6 ); +#else + fac_Q16 = silk_DIV32_16( silk_LSHIFT( TRANSITION_FRAMES - psLP->transition_frame_no, 16 ), TRANSITION_FRAMES ); +#endif + ind = silk_RSHIFT( fac_Q16, 16 ); + fac_Q16 -= silk_LSHIFT( ind, 16 ); + + silk_assert( ind >= 0 ); + silk_assert( ind < TRANSITION_INT_NUM ); + + /* Interpolate filter coefficients */ + silk_LP_interpolate_filter_taps( B_Q28, A_Q28, ind, fac_Q16 ); + + /* Update transition frame number for next frame */ + psLP->transition_frame_no = silk_LIMIT( psLP->transition_frame_no + psLP->mode, 0, TRANSITION_FRAMES ); + + /* ARMA low-pass filtering */ + silk_assert( TRANSITION_NB == 3 && TRANSITION_NA == 2 ); + silk_biquad_alt_stride1( frame, B_Q28, A_Q28, psLP->In_LP_State, frame, frame_length); + } +} diff --git a/extern/opus/silk/MacroCount.h b/extern/opus/silk/MacroCount.h new file mode 100644 index 0000000..78100ff --- /dev/null +++ b/extern/opus/silk/MacroCount.h @@ -0,0 +1,710 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifndef SIGPROCFIX_API_MACROCOUNT_H +#define SIGPROCFIX_API_MACROCOUNT_H +#include + +#ifdef silk_MACRO_COUNT +#define varDefine opus_int64 ops_count = 0; + +extern opus_int64 ops_count; + +static OPUS_INLINE opus_int64 silk_SaveCount(){ + return(ops_count); +} + +static OPUS_INLINE opus_int64 silk_SaveResetCount(){ + opus_int64 ret; + + ret = ops_count; + ops_count = 0; + return(ret); +} + +static OPUS_INLINE silk_PrintCount(){ + printf("ops_count = %d \n ", (opus_int32)ops_count); +} + +#undef silk_MUL +static OPUS_INLINE opus_int32 silk_MUL(opus_int32 a32, opus_int32 b32){ + opus_int32 ret; + ops_count += 4; + ret = a32 * b32; + return ret; +} + +#undef silk_MUL_uint +static OPUS_INLINE opus_uint32 silk_MUL_uint(opus_uint32 a32, opus_uint32 b32){ + opus_uint32 ret; + ops_count += 4; + ret = a32 * b32; + return ret; +} +#undef silk_MLA +static OPUS_INLINE opus_int32 silk_MLA(opus_int32 a32, opus_int32 b32, opus_int32 c32){ + opus_int32 ret; + ops_count += 4; + ret = a32 + b32 * c32; + return ret; +} + +#undef silk_MLA_uint +static OPUS_INLINE opus_int32 silk_MLA_uint(opus_uint32 a32, opus_uint32 b32, opus_uint32 c32){ + opus_uint32 ret; + ops_count += 4; + ret = a32 + b32 * c32; + return ret; +} + +#undef silk_SMULWB +static OPUS_INLINE opus_int32 silk_SMULWB(opus_int32 a32, opus_int32 b32){ + opus_int32 ret; + ops_count += 5; + ret = (a32 >> 16) * (opus_int32)((opus_int16)b32) + (((a32 & 0x0000FFFF) * (opus_int32)((opus_int16)b32)) >> 16); + return ret; +} +#undef silk_SMLAWB +static OPUS_INLINE opus_int32 silk_SMLAWB(opus_int32 a32, opus_int32 b32, opus_int32 c32){ + opus_int32 ret; + ops_count += 5; + ret = ((a32) + ((((b32) >> 16) * (opus_int32)((opus_int16)(c32))) + ((((b32) & 0x0000FFFF) * (opus_int32)((opus_int16)(c32))) >> 16))); + return ret; +} + +#undef silk_SMULWT +static OPUS_INLINE opus_int32 silk_SMULWT(opus_int32 a32, opus_int32 b32){ + opus_int32 ret; + ops_count += 4; + ret = (a32 >> 16) * (b32 >> 16) + (((a32 & 0x0000FFFF) * (b32 >> 16)) >> 16); + return ret; +} +#undef silk_SMLAWT +static OPUS_INLINE opus_int32 silk_SMLAWT(opus_int32 a32, opus_int32 b32, opus_int32 c32){ + opus_int32 ret; + ops_count += 4; + ret = a32 + ((b32 >> 16) * (c32 >> 16)) + (((b32 & 0x0000FFFF) * ((c32 >> 16)) >> 16)); + return ret; +} + +#undef silk_SMULBB +static OPUS_INLINE opus_int32 silk_SMULBB(opus_int32 a32, opus_int32 b32){ + opus_int32 ret; + ops_count += 1; + ret = (opus_int32)((opus_int16)a32) * (opus_int32)((opus_int16)b32); + return ret; +} +#undef silk_SMLABB +static OPUS_INLINE opus_int32 silk_SMLABB(opus_int32 a32, opus_int32 b32, opus_int32 c32){ + opus_int32 ret; + ops_count += 1; + ret = a32 + (opus_int32)((opus_int16)b32) * (opus_int32)((opus_int16)c32); + return ret; +} + +#undef silk_SMULBT +static OPUS_INLINE opus_int32 silk_SMULBT(opus_int32 a32, opus_int32 b32 ){ + opus_int32 ret; + ops_count += 4; + ret = ((opus_int32)((opus_int16)a32)) * (b32 >> 16); + return ret; +} + +#undef silk_SMLABT +static OPUS_INLINE opus_int32 silk_SMLABT(opus_int32 a32, opus_int32 b32, opus_int32 c32){ + opus_int32 ret; + ops_count += 1; + ret = a32 + ((opus_int32)((opus_int16)b32)) * (c32 >> 16); + return ret; +} + +#undef silk_SMULTT +static OPUS_INLINE opus_int32 silk_SMULTT(opus_int32 a32, opus_int32 b32){ + opus_int32 ret; + ops_count += 1; + ret = (a32 >> 16) * (b32 >> 16); + return ret; +} + +#undef silk_SMLATT +static OPUS_INLINE opus_int32 silk_SMLATT(opus_int32 a32, opus_int32 b32, opus_int32 c32){ + opus_int32 ret; + ops_count += 1; + ret = a32 + (b32 >> 16) * (c32 >> 16); + return ret; +} + + +/* multiply-accumulate macros that allow overflow in the addition (ie, no asserts in debug mode)*/ +#undef silk_MLA_ovflw +#define silk_MLA_ovflw silk_MLA + +#undef silk_SMLABB_ovflw +#define silk_SMLABB_ovflw silk_SMLABB + +#undef silk_SMLABT_ovflw +#define silk_SMLABT_ovflw silk_SMLABT + +#undef silk_SMLATT_ovflw +#define silk_SMLATT_ovflw silk_SMLATT + +#undef silk_SMLAWB_ovflw +#define silk_SMLAWB_ovflw silk_SMLAWB + +#undef silk_SMLAWT_ovflw +#define silk_SMLAWT_ovflw silk_SMLAWT + +#undef silk_SMULL +static OPUS_INLINE opus_int64 silk_SMULL(opus_int32 a32, opus_int32 b32){ + opus_int64 ret; + ops_count += 8; + ret = ((opus_int64)(a32) * /*(opus_int64)*/(b32)); + return ret; +} + +#undef silk_SMLAL +static OPUS_INLINE opus_int64 silk_SMLAL(opus_int64 a64, opus_int32 b32, opus_int32 c32){ + opus_int64 ret; + ops_count += 8; + ret = a64 + ((opus_int64)(b32) * /*(opus_int64)*/(c32)); + return ret; +} +#undef silk_SMLALBB +static OPUS_INLINE opus_int64 silk_SMLALBB(opus_int64 a64, opus_int16 b16, opus_int16 c16){ + opus_int64 ret; + ops_count += 4; + ret = a64 + ((opus_int64)(b16) * /*(opus_int64)*/(c16)); + return ret; +} + +#undef SigProcFIX_CLZ16 +static OPUS_INLINE opus_int32 SigProcFIX_CLZ16(opus_int16 in16) +{ + opus_int32 out32 = 0; + ops_count += 10; + if( in16 == 0 ) { + return 16; + } + /* test nibbles */ + if( in16 & 0xFF00 ) { + if( in16 & 0xF000 ) { + in16 >>= 12; + } else { + out32 += 4; + in16 >>= 8; + } + } else { + if( in16 & 0xFFF0 ) { + out32 += 8; + in16 >>= 4; + } else { + out32 += 12; + } + } + /* test bits and return */ + if( in16 & 0xC ) { + if( in16 & 0x8 ) + return out32 + 0; + else + return out32 + 1; + } else { + if( in16 & 0xE ) + return out32 + 2; + else + return out32 + 3; + } +} + +#undef SigProcFIX_CLZ32 +static OPUS_INLINE opus_int32 SigProcFIX_CLZ32(opus_int32 in32) +{ + /* test highest 16 bits and convert to opus_int16 */ + ops_count += 2; + if( in32 & 0xFFFF0000 ) { + return SigProcFIX_CLZ16((opus_int16)(in32 >> 16)); + } else { + return SigProcFIX_CLZ16((opus_int16)in32) + 16; + } +} + +#undef silk_DIV32 +static OPUS_INLINE opus_int32 silk_DIV32(opus_int32 a32, opus_int32 b32){ + ops_count += 64; + return a32 / b32; +} + +#undef silk_DIV32_16 +static OPUS_INLINE opus_int32 silk_DIV32_16(opus_int32 a32, opus_int32 b32){ + ops_count += 32; + return a32 / b32; +} + +#undef silk_SAT8 +static OPUS_INLINE opus_int8 silk_SAT8(opus_int64 a){ + opus_int8 tmp; + ops_count += 1; + tmp = (opus_int8)((a) > silk_int8_MAX ? silk_int8_MAX : \ + ((a) < silk_int8_MIN ? silk_int8_MIN : (a))); + return(tmp); +} + +#undef silk_SAT16 +static OPUS_INLINE opus_int16 silk_SAT16(opus_int64 a){ + opus_int16 tmp; + ops_count += 1; + tmp = (opus_int16)((a) > silk_int16_MAX ? silk_int16_MAX : \ + ((a) < silk_int16_MIN ? silk_int16_MIN : (a))); + return(tmp); +} +#undef silk_SAT32 +static OPUS_INLINE opus_int32 silk_SAT32(opus_int64 a){ + opus_int32 tmp; + ops_count += 1; + tmp = (opus_int32)((a) > silk_int32_MAX ? silk_int32_MAX : \ + ((a) < silk_int32_MIN ? silk_int32_MIN : (a))); + return(tmp); +} +#undef silk_POS_SAT32 +static OPUS_INLINE opus_int32 silk_POS_SAT32(opus_int64 a){ + opus_int32 tmp; + ops_count += 1; + tmp = (opus_int32)((a) > silk_int32_MAX ? silk_int32_MAX : (a)); + return(tmp); +} + +#undef silk_ADD_POS_SAT8 +static OPUS_INLINE opus_int8 silk_ADD_POS_SAT8(opus_int64 a, opus_int64 b){ + opus_int8 tmp; + ops_count += 1; + tmp = (opus_int8)((((a)+(b)) & 0x80) ? silk_int8_MAX : ((a)+(b))); + return(tmp); +} +#undef silk_ADD_POS_SAT16 +static OPUS_INLINE opus_int16 silk_ADD_POS_SAT16(opus_int64 a, opus_int64 b){ + opus_int16 tmp; + ops_count += 1; + tmp = (opus_int16)((((a)+(b)) & 0x8000) ? silk_int16_MAX : ((a)+(b))); + return(tmp); +} + +#undef silk_ADD_POS_SAT32 +static OPUS_INLINE opus_int32 silk_ADD_POS_SAT32(opus_int64 a, opus_int64 b){ + opus_int32 tmp; + ops_count += 1; + tmp = (opus_int32)((((a)+(b)) & 0x80000000) ? silk_int32_MAX : ((a)+(b))); + return(tmp); +} + +#undef silk_LSHIFT8 +static OPUS_INLINE opus_int8 silk_LSHIFT8(opus_int8 a, opus_int32 shift){ + opus_int8 ret; + ops_count += 1; + ret = a << shift; + return ret; +} +#undef silk_LSHIFT16 +static OPUS_INLINE opus_int16 silk_LSHIFT16(opus_int16 a, opus_int32 shift){ + opus_int16 ret; + ops_count += 1; + ret = a << shift; + return ret; +} +#undef silk_LSHIFT32 +static OPUS_INLINE opus_int32 silk_LSHIFT32(opus_int32 a, opus_int32 shift){ + opus_int32 ret; + ops_count += 1; + ret = a << shift; + return ret; +} +#undef silk_LSHIFT64 +static OPUS_INLINE opus_int64 silk_LSHIFT64(opus_int64 a, opus_int shift){ + ops_count += 1; + return a << shift; +} + +#undef silk_LSHIFT_ovflw +static OPUS_INLINE opus_int32 silk_LSHIFT_ovflw(opus_int32 a, opus_int32 shift){ + ops_count += 1; + return a << shift; +} + +#undef silk_LSHIFT_uint +static OPUS_INLINE opus_uint32 silk_LSHIFT_uint(opus_uint32 a, opus_int32 shift){ + opus_uint32 ret; + ops_count += 1; + ret = a << shift; + return ret; +} + +#undef silk_RSHIFT8 +static OPUS_INLINE opus_int8 silk_RSHIFT8(opus_int8 a, opus_int32 shift){ + ops_count += 1; + return a >> shift; +} +#undef silk_RSHIFT16 +static OPUS_INLINE opus_int16 silk_RSHIFT16(opus_int16 a, opus_int32 shift){ + ops_count += 1; + return a >> shift; +} +#undef silk_RSHIFT32 +static OPUS_INLINE opus_int32 silk_RSHIFT32(opus_int32 a, opus_int32 shift){ + ops_count += 1; + return a >> shift; +} +#undef silk_RSHIFT64 +static OPUS_INLINE opus_int64 silk_RSHIFT64(opus_int64 a, opus_int64 shift){ + ops_count += 1; + return a >> shift; +} + +#undef silk_RSHIFT_uint +static OPUS_INLINE opus_uint32 silk_RSHIFT_uint(opus_uint32 a, opus_int32 shift){ + ops_count += 1; + return a >> shift; +} + +#undef silk_ADD_LSHIFT +static OPUS_INLINE opus_int32 silk_ADD_LSHIFT(opus_int32 a, opus_int32 b, opus_int32 shift){ + opus_int32 ret; + ops_count += 1; + ret = a + (b << shift); + return ret; /* shift >= 0*/ +} +#undef silk_ADD_LSHIFT32 +static OPUS_INLINE opus_int32 silk_ADD_LSHIFT32(opus_int32 a, opus_int32 b, opus_int32 shift){ + opus_int32 ret; + ops_count += 1; + ret = a + (b << shift); + return ret; /* shift >= 0*/ +} +#undef silk_ADD_LSHIFT_uint +static OPUS_INLINE opus_uint32 silk_ADD_LSHIFT_uint(opus_uint32 a, opus_uint32 b, opus_int32 shift){ + opus_uint32 ret; + ops_count += 1; + ret = a + (b << shift); + return ret; /* shift >= 0*/ +} +#undef silk_ADD_RSHIFT +static OPUS_INLINE opus_int32 silk_ADD_RSHIFT(opus_int32 a, opus_int32 b, opus_int32 shift){ + opus_int32 ret; + ops_count += 1; + ret = a + (b >> shift); + return ret; /* shift > 0*/ +} +#undef silk_ADD_RSHIFT32 +static OPUS_INLINE opus_int32 silk_ADD_RSHIFT32(opus_int32 a, opus_int32 b, opus_int32 shift){ + opus_int32 ret; + ops_count += 1; + ret = a + (b >> shift); + return ret; /* shift > 0*/ +} +#undef silk_ADD_RSHIFT_uint +static OPUS_INLINE opus_uint32 silk_ADD_RSHIFT_uint(opus_uint32 a, opus_uint32 b, opus_int32 shift){ + opus_uint32 ret; + ops_count += 1; + ret = a + (b >> shift); + return ret; /* shift > 0*/ +} +#undef silk_SUB_LSHIFT32 +static OPUS_INLINE opus_int32 silk_SUB_LSHIFT32(opus_int32 a, opus_int32 b, opus_int32 shift){ + opus_int32 ret; + ops_count += 1; + ret = a - (b << shift); + return ret; /* shift >= 0*/ +} +#undef silk_SUB_RSHIFT32 +static OPUS_INLINE opus_int32 silk_SUB_RSHIFT32(opus_int32 a, opus_int32 b, opus_int32 shift){ + opus_int32 ret; + ops_count += 1; + ret = a - (b >> shift); + return ret; /* shift > 0*/ +} + +#undef silk_RSHIFT_ROUND +static OPUS_INLINE opus_int32 silk_RSHIFT_ROUND(opus_int32 a, opus_int32 shift){ + opus_int32 ret; + ops_count += 3; + ret = shift == 1 ? (a >> 1) + (a & 1) : ((a >> (shift - 1)) + 1) >> 1; + return ret; +} + +#undef silk_RSHIFT_ROUND64 +static OPUS_INLINE opus_int64 silk_RSHIFT_ROUND64(opus_int64 a, opus_int32 shift){ + opus_int64 ret; + ops_count += 6; + ret = shift == 1 ? (a >> 1) + (a & 1) : ((a >> (shift - 1)) + 1) >> 1; + return ret; +} + +#undef silk_abs_int64 +static OPUS_INLINE opus_int64 silk_abs_int64(opus_int64 a){ + ops_count += 1; + return (((a) > 0) ? (a) : -(a)); /* Be careful, silk_abs returns wrong when input equals to silk_intXX_MIN*/ +} + +#undef silk_abs_int32 +static OPUS_INLINE opus_int32 silk_abs_int32(opus_int32 a){ + ops_count += 1; + return silk_abs(a); +} + + +#undef silk_min +static silk_min(a, b){ + ops_count += 1; + return (((a) < (b)) ? (a) : (b)); +} +#undef silk_max +static silk_max(a, b){ + ops_count += 1; + return (((a) > (b)) ? (a) : (b)); +} +#undef silk_sign +static silk_sign(a){ + ops_count += 1; + return ((a) > 0 ? 1 : ( (a) < 0 ? -1 : 0 )); +} + +#undef silk_ADD16 +static OPUS_INLINE opus_int16 silk_ADD16(opus_int16 a, opus_int16 b){ + opus_int16 ret; + ops_count += 1; + ret = a + b; + return ret; +} + +#undef silk_ADD32 +static OPUS_INLINE opus_int32 silk_ADD32(opus_int32 a, opus_int32 b){ + opus_int32 ret; + ops_count += 1; + ret = a + b; + return ret; +} + +#undef silk_ADD64 +static OPUS_INLINE opus_int64 silk_ADD64(opus_int64 a, opus_int64 b){ + opus_int64 ret; + ops_count += 2; + ret = a + b; + return ret; +} + +#undef silk_SUB16 +static OPUS_INLINE opus_int16 silk_SUB16(opus_int16 a, opus_int16 b){ + opus_int16 ret; + ops_count += 1; + ret = a - b; + return ret; +} + +#undef silk_SUB32 +static OPUS_INLINE opus_int32 silk_SUB32(opus_int32 a, opus_int32 b){ + opus_int32 ret; + ops_count += 1; + ret = a - b; + return ret; +} + +#undef silk_SUB64 +static OPUS_INLINE opus_int64 silk_SUB64(opus_int64 a, opus_int64 b){ + opus_int64 ret; + ops_count += 2; + ret = a - b; + return ret; +} + +#undef silk_ADD_SAT16 +static OPUS_INLINE opus_int16 silk_ADD_SAT16( opus_int16 a16, opus_int16 b16 ) { + opus_int16 res; + /* Nb will be counted in AKP_add32 and silk_SAT16*/ + res = (opus_int16)silk_SAT16( silk_ADD32( (opus_int32)(a16), (b16) ) ); + return res; +} + +#undef silk_ADD_SAT32 +static OPUS_INLINE opus_int32 silk_ADD_SAT32(opus_int32 a32, opus_int32 b32){ + opus_int32 res; + ops_count += 1; + res = ((((a32) + (b32)) & 0x80000000) == 0 ? \ + ((((a32) & (b32)) & 0x80000000) != 0 ? silk_int32_MIN : (a32)+(b32)) : \ + ((((a32) | (b32)) & 0x80000000) == 0 ? silk_int32_MAX : (a32)+(b32)) ); + return res; +} + +#undef silk_ADD_SAT64 +static OPUS_INLINE opus_int64 silk_ADD_SAT64( opus_int64 a64, opus_int64 b64 ) { + opus_int64 res; + ops_count += 1; + res = ((((a64) + (b64)) & 0x8000000000000000LL) == 0 ? \ + ((((a64) & (b64)) & 0x8000000000000000LL) != 0 ? silk_int64_MIN : (a64)+(b64)) : \ + ((((a64) | (b64)) & 0x8000000000000000LL) == 0 ? silk_int64_MAX : (a64)+(b64)) ); + return res; +} + +#undef silk_SUB_SAT16 +static OPUS_INLINE opus_int16 silk_SUB_SAT16( opus_int16 a16, opus_int16 b16 ) { + opus_int16 res; + silk_assert(0); + /* Nb will be counted in sub-macros*/ + res = (opus_int16)silk_SAT16( silk_SUB32( (opus_int32)(a16), (b16) ) ); + return res; +} + +#undef silk_SUB_SAT32 +static OPUS_INLINE opus_int32 silk_SUB_SAT32( opus_int32 a32, opus_int32 b32 ) { + opus_int32 res; + ops_count += 1; + res = ((((a32)-(b32)) & 0x80000000) == 0 ? \ + (( (a32) & ((b32)^0x80000000) & 0x80000000) ? silk_int32_MIN : (a32)-(b32)) : \ + ((((a32)^0x80000000) & (b32) & 0x80000000) ? silk_int32_MAX : (a32)-(b32)) ); + return res; +} + +#undef silk_SUB_SAT64 +static OPUS_INLINE opus_int64 silk_SUB_SAT64( opus_int64 a64, opus_int64 b64 ) { + opus_int64 res; + ops_count += 1; + res = ((((a64)-(b64)) & 0x8000000000000000LL) == 0 ? \ + (( (a64) & ((b64)^0x8000000000000000LL) & 0x8000000000000000LL) ? silk_int64_MIN : (a64)-(b64)) : \ + ((((a64)^0x8000000000000000LL) & (b64) & 0x8000000000000000LL) ? silk_int64_MAX : (a64)-(b64)) ); + + return res; +} + +#undef silk_SMULWW +static OPUS_INLINE opus_int32 silk_SMULWW(opus_int32 a32, opus_int32 b32){ + opus_int32 ret; + /* Nb will be counted in sub-macros*/ + ret = silk_MLA(silk_SMULWB((a32), (b32)), (a32), silk_RSHIFT_ROUND((b32), 16)); + return ret; +} + +#undef silk_SMLAWW +static OPUS_INLINE opus_int32 silk_SMLAWW(opus_int32 a32, opus_int32 b32, opus_int32 c32){ + opus_int32 ret; + /* Nb will be counted in sub-macros*/ + ret = silk_MLA(silk_SMLAWB((a32), (b32), (c32)), (b32), silk_RSHIFT_ROUND((c32), 16)); + return ret; +} + +#undef silk_min_int +static OPUS_INLINE opus_int silk_min_int(opus_int a, opus_int b) +{ + ops_count += 1; + return (((a) < (b)) ? (a) : (b)); +} + +#undef silk_min_16 +static OPUS_INLINE opus_int16 silk_min_16(opus_int16 a, opus_int16 b) +{ + ops_count += 1; + return (((a) < (b)) ? (a) : (b)); +} +#undef silk_min_32 +static OPUS_INLINE opus_int32 silk_min_32(opus_int32 a, opus_int32 b) +{ + ops_count += 1; + return (((a) < (b)) ? (a) : (b)); +} +#undef silk_min_64 +static OPUS_INLINE opus_int64 silk_min_64(opus_int64 a, opus_int64 b) +{ + ops_count += 1; + return (((a) < (b)) ? (a) : (b)); +} + +/* silk_min() versions with typecast in the function call */ +#undef silk_max_int +static OPUS_INLINE opus_int silk_max_int(opus_int a, opus_int b) +{ + ops_count += 1; + return (((a) > (b)) ? (a) : (b)); +} +#undef silk_max_16 +static OPUS_INLINE opus_int16 silk_max_16(opus_int16 a, opus_int16 b) +{ + ops_count += 1; + return (((a) > (b)) ? (a) : (b)); +} +#undef silk_max_32 +static OPUS_INLINE opus_int32 silk_max_32(opus_int32 a, opus_int32 b) +{ + ops_count += 1; + return (((a) > (b)) ? (a) : (b)); +} + +#undef silk_max_64 +static OPUS_INLINE opus_int64 silk_max_64(opus_int64 a, opus_int64 b) +{ + ops_count += 1; + return (((a) > (b)) ? (a) : (b)); +} + + +#undef silk_LIMIT_int +static OPUS_INLINE opus_int silk_LIMIT_int(opus_int a, opus_int limit1, opus_int limit2) +{ + opus_int ret; + ops_count += 6; + + ret = ((limit1) > (limit2) ? ((a) > (limit1) ? (limit1) : ((a) < (limit2) ? (limit2) : (a))) \ + : ((a) > (limit2) ? (limit2) : ((a) < (limit1) ? (limit1) : (a)))); + + return(ret); +} + +#undef silk_LIMIT_16 +static OPUS_INLINE opus_int16 silk_LIMIT_16(opus_int16 a, opus_int16 limit1, opus_int16 limit2) +{ + opus_int16 ret; + ops_count += 6; + + ret = ((limit1) > (limit2) ? ((a) > (limit1) ? (limit1) : ((a) < (limit2) ? (limit2) : (a))) \ + : ((a) > (limit2) ? (limit2) : ((a) < (limit1) ? (limit1) : (a)))); + +return(ret); +} + + +#undef silk_LIMIT_32 +static OPUS_INLINE opus_int32 silk_LIMIT_32(opus_int32 a, opus_int32 limit1, opus_int32 limit2) +{ + opus_int32 ret; + ops_count += 6; + + ret = ((limit1) > (limit2) ? ((a) > (limit1) ? (limit1) : ((a) < (limit2) ? (limit2) : (a))) \ + : ((a) > (limit2) ? (limit2) : ((a) < (limit1) ? (limit1) : (a)))); + return(ret); +} + +#else +#define varDefine +#define silk_SaveCount() + +#endif +#endif + diff --git a/extern/opus/silk/MacroDebug.h b/extern/opus/silk/MacroDebug.h new file mode 100644 index 0000000..8dd4ce2 --- /dev/null +++ b/extern/opus/silk/MacroDebug.h @@ -0,0 +1,951 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Copyright (C) 2012 Xiph.Org Foundation +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 OWNER 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. +***********************************************************************/ + +#ifndef MACRO_DEBUG_H +#define MACRO_DEBUG_H + +/* Redefine macro functions with extensive assertion in DEBUG mode. + As functions can't be undefined, this file can't work with SigProcFIX_MacroCount.h */ + +#if ( defined (FIXED_DEBUG) || ( 0 && defined (_DEBUG) ) ) && !defined (silk_MACRO_COUNT) + +#undef silk_ADD16 +#define silk_ADD16(a,b) silk_ADD16_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int16 silk_ADD16_(opus_int16 a, opus_int16 b, char *file, int line){ + opus_int16 ret; + + ret = a + b; + if ( ret != silk_ADD_SAT16( a, b ) ) + { + fprintf (stderr, "silk_ADD16(%d, %d) in %s: line %d\n", a, b, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +#undef silk_ADD32 +#define silk_ADD32(a,b) silk_ADD32_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_ADD32_(opus_int32 a, opus_int32 b, char *file, int line){ + opus_int32 ret; + + ret = a + b; + if ( ret != silk_ADD_SAT32( a, b ) ) + { + fprintf (stderr, "silk_ADD32(%d, %d) in %s: line %d\n", a, b, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +#undef silk_ADD64 +#define silk_ADD64(a,b) silk_ADD64_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int64 silk_ADD64_(opus_int64 a, opus_int64 b, char *file, int line){ + opus_int64 ret; + + ret = a + b; + if ( ret != silk_ADD_SAT64( a, b ) ) + { + fprintf (stderr, "silk_ADD64(%lld, %lld) in %s: line %d\n", (long long)a, (long long)b, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +#undef silk_SUB16 +#define silk_SUB16(a,b) silk_SUB16_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int16 silk_SUB16_(opus_int16 a, opus_int16 b, char *file, int line){ + opus_int16 ret; + + ret = a - b; + if ( ret != silk_SUB_SAT16( a, b ) ) + { + fprintf (stderr, "silk_SUB16(%d, %d) in %s: line %d\n", a, b, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +#undef silk_SUB32 +#define silk_SUB32(a,b) silk_SUB32_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_SUB32_(opus_int32 a, opus_int32 b, char *file, int line){ + opus_int32 ret; + + ret = a - b; + if ( ret != silk_SUB_SAT32( a, b ) ) + { + fprintf (stderr, "silk_SUB32(%d, %d) in %s: line %d\n", a, b, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +#undef silk_SUB64 +#define silk_SUB64(a,b) silk_SUB64_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int64 silk_SUB64_(opus_int64 a, opus_int64 b, char *file, int line){ + opus_int64 ret; + + ret = a - b; + if ( ret != silk_SUB_SAT64( a, b ) ) + { + fprintf (stderr, "silk_SUB64(%lld, %lld) in %s: line %d\n", (long long)a, (long long)b, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +#undef silk_ADD_SAT16 +#define silk_ADD_SAT16(a,b) silk_ADD_SAT16_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int16 silk_ADD_SAT16_( opus_int16 a16, opus_int16 b16, char *file, int line) { + opus_int16 res; + res = (opus_int16)silk_SAT16( silk_ADD32( (opus_int32)(a16), (b16) ) ); + if ( res != silk_SAT16( (opus_int32)a16 + (opus_int32)b16 ) ) + { + fprintf (stderr, "silk_ADD_SAT16(%d, %d) in %s: line %d\n", a16, b16, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return res; +} + +#undef silk_ADD_SAT32 +#define silk_ADD_SAT32(a,b) silk_ADD_SAT32_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_ADD_SAT32_(opus_int32 a32, opus_int32 b32, char *file, int line){ + opus_int32 res; + res = ((((opus_uint32)(a32) + (opus_uint32)(b32)) & 0x80000000) == 0 ? \ + ((((a32) & (b32)) & 0x80000000) != 0 ? silk_int32_MIN : (a32)+(b32)) : \ + ((((a32) | (b32)) & 0x80000000) == 0 ? silk_int32_MAX : (a32)+(b32)) ); + if ( res != silk_SAT32( (opus_int64)a32 + (opus_int64)b32 ) ) + { + fprintf (stderr, "silk_ADD_SAT32(%d, %d) in %s: line %d\n", a32, b32, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return res; +} + +#undef silk_ADD_SAT64 +#define silk_ADD_SAT64(a,b) silk_ADD_SAT64_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int64 silk_ADD_SAT64_( opus_int64 a64, opus_int64 b64, char *file, int line) { + opus_int64 res; + int fail = 0; + res = ((((a64) + (b64)) & 0x8000000000000000LL) == 0 ? \ + ((((a64) & (b64)) & 0x8000000000000000LL) != 0 ? silk_int64_MIN : (a64)+(b64)) : \ + ((((a64) | (b64)) & 0x8000000000000000LL) == 0 ? silk_int64_MAX : (a64)+(b64)) ); + if( res != a64 + b64 ) { + /* Check that we saturated to the correct extreme value */ + if ( !(( res == silk_int64_MAX && ( ( a64 >> 1 ) + ( b64 >> 1 ) > ( silk_int64_MAX >> 3 ) ) ) || + ( res == silk_int64_MIN && ( ( a64 >> 1 ) + ( b64 >> 1 ) < ( silk_int64_MIN >> 3 ) ) ) ) ) + { + fail = 1; + } + } else { + /* Saturation not necessary */ + fail = res != a64 + b64; + } + if ( fail ) + { + fprintf (stderr, "silk_ADD_SAT64(%lld, %lld) in %s: line %d\n", (long long)a64, (long long)b64, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return res; +} + +#undef silk_SUB_SAT16 +#define silk_SUB_SAT16(a,b) silk_SUB_SAT16_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int16 silk_SUB_SAT16_( opus_int16 a16, opus_int16 b16, char *file, int line ) { + opus_int16 res; + res = (opus_int16)silk_SAT16( silk_SUB32( (opus_int32)(a16), (b16) ) ); + if ( res != silk_SAT16( (opus_int32)a16 - (opus_int32)b16 ) ) + { + fprintf (stderr, "silk_SUB_SAT16(%d, %d) in %s: line %d\n", a16, b16, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return res; +} + +#undef silk_SUB_SAT32 +#define silk_SUB_SAT32(a,b) silk_SUB_SAT32_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_SUB_SAT32_( opus_int32 a32, opus_int32 b32, char *file, int line ) { + opus_int32 res; + res = ((((opus_uint32)(a32)-(opus_uint32)(b32)) & 0x80000000) == 0 ? \ + (( (a32) & ((b32)^0x80000000) & 0x80000000) ? silk_int32_MIN : (a32)-(b32)) : \ + ((((a32)^0x80000000) & (b32) & 0x80000000) ? silk_int32_MAX : (a32)-(b32)) ); + if ( res != silk_SAT32( (opus_int64)a32 - (opus_int64)b32 ) ) + { + fprintf (stderr, "silk_SUB_SAT32(%d, %d) in %s: line %d\n", a32, b32, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return res; +} + +#undef silk_SUB_SAT64 +#define silk_SUB_SAT64(a,b) silk_SUB_SAT64_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int64 silk_SUB_SAT64_( opus_int64 a64, opus_int64 b64, char *file, int line ) { + opus_int64 res; + int fail = 0; + res = ((((a64)-(b64)) & 0x8000000000000000LL) == 0 ? \ + (( (a64) & ((b64)^0x8000000000000000LL) & 0x8000000000000000LL) ? silk_int64_MIN : (a64)-(b64)) : \ + ((((a64)^0x8000000000000000LL) & (b64) & 0x8000000000000000LL) ? silk_int64_MAX : (a64)-(b64)) ); + if( res != a64 - b64 ) { + /* Check that we saturated to the correct extreme value */ + if( !(( res == silk_int64_MAX && ( ( a64 >> 1 ) + ( b64 >> 1 ) > ( silk_int64_MAX >> 3 ) ) ) || + ( res == silk_int64_MIN && ( ( a64 >> 1 ) + ( b64 >> 1 ) < ( silk_int64_MIN >> 3 ) ) ) )) + { + fail = 1; + } + } else { + /* Saturation not necessary */ + fail = res != a64 - b64; + } + if ( fail ) + { + fprintf (stderr, "silk_SUB_SAT64(%lld, %lld) in %s: line %d\n", (long long)a64, (long long)b64, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return res; +} + +#undef silk_MUL +#define silk_MUL(a,b) silk_MUL_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_MUL_(opus_int32 a32, opus_int32 b32, char *file, int line){ + opus_int32 ret; + opus_int64 ret64; + ret = a32 * b32; + ret64 = (opus_int64)a32 * (opus_int64)b32; + if ( (opus_int64)ret != ret64 ) + { + fprintf (stderr, "silk_MUL(%d, %d) in %s: line %d\n", a32, b32, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +#undef silk_MUL_uint +#define silk_MUL_uint(a,b) silk_MUL_uint_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_uint32 silk_MUL_uint_(opus_uint32 a32, opus_uint32 b32, char *file, int line){ + opus_uint32 ret; + ret = a32 * b32; + if ( (opus_uint64)ret != (opus_uint64)a32 * (opus_uint64)b32 ) + { + fprintf (stderr, "silk_MUL_uint(%u, %u) in %s: line %d\n", a32, b32, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +#undef silk_MLA +#define silk_MLA(a,b,c) silk_MLA_((a), (b), (c), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_MLA_(opus_int32 a32, opus_int32 b32, opus_int32 c32, char *file, int line){ + opus_int32 ret; + ret = a32 + b32 * c32; + if ( (opus_int64)ret != (opus_int64)a32 + (opus_int64)b32 * (opus_int64)c32 ) + { + fprintf (stderr, "silk_MLA(%d, %d, %d) in %s: line %d\n", a32, b32, c32, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +#undef silk_MLA_uint +#define silk_MLA_uint(a,b,c) silk_MLA_uint_((a), (b), (c), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_MLA_uint_(opus_uint32 a32, opus_uint32 b32, opus_uint32 c32, char *file, int line){ + opus_uint32 ret; + ret = a32 + b32 * c32; + if ( (opus_int64)ret != (opus_int64)a32 + (opus_int64)b32 * (opus_int64)c32 ) + { + fprintf (stderr, "silk_MLA_uint(%d, %d, %d) in %s: line %d\n", a32, b32, c32, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +#undef silk_SMULWB +#define silk_SMULWB(a,b) silk_SMULWB_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_SMULWB_(opus_int32 a32, opus_int32 b32, char *file, int line){ + opus_int32 ret; + ret = (a32 >> 16) * (opus_int32)((opus_int16)b32) + (((a32 & 0x0000FFFF) * (opus_int32)((opus_int16)b32)) >> 16); + if ( (opus_int64)ret != ((opus_int64)a32 * (opus_int16)b32) >> 16 ) + { + fprintf (stderr, "silk_SMULWB(%d, %d) in %s: line %d\n", a32, b32, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +#undef silk_SMLAWB +#define silk_SMLAWB(a,b,c) silk_SMLAWB_((a), (b), (c), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_SMLAWB_(opus_int32 a32, opus_int32 b32, opus_int32 c32, char *file, int line){ + opus_int32 ret; + ret = silk_ADD32( a32, silk_SMULWB( b32, c32 ) ); + if ( silk_ADD32( a32, silk_SMULWB( b32, c32 ) ) != silk_ADD_SAT32( a32, silk_SMULWB( b32, c32 ) ) ) + { + fprintf (stderr, "silk_SMLAWB(%d, %d, %d) in %s: line %d\n", a32, b32, c32, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +#undef silk_SMULWT +#define silk_SMULWT(a,b) silk_SMULWT_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_SMULWT_(opus_int32 a32, opus_int32 b32, char *file, int line){ + opus_int32 ret; + ret = (a32 >> 16) * (b32 >> 16) + (((a32 & 0x0000FFFF) * (b32 >> 16)) >> 16); + if ( (opus_int64)ret != ((opus_int64)a32 * (b32 >> 16)) >> 16 ) + { + fprintf (stderr, "silk_SMULWT(%d, %d) in %s: line %d\n", a32, b32, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +#undef silk_SMLAWT +#define silk_SMLAWT(a,b,c) silk_SMLAWT_((a), (b), (c), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_SMLAWT_(opus_int32 a32, opus_int32 b32, opus_int32 c32, char *file, int line){ + opus_int32 ret; + ret = a32 + ((b32 >> 16) * (c32 >> 16)) + (((b32 & 0x0000FFFF) * ((c32 >> 16)) >> 16)); + if ( (opus_int64)ret != (opus_int64)a32 + (((opus_int64)b32 * (c32 >> 16)) >> 16) ) + { + fprintf (stderr, "silk_SMLAWT(%d, %d, %d) in %s: line %d\n", a32, b32, c32, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +#undef silk_SMULL +#define silk_SMULL(a,b) silk_SMULL_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int64 silk_SMULL_(opus_int64 a64, opus_int64 b64, char *file, int line){ + opus_int64 ret64; + int fail = 0; + ret64 = a64 * b64; + if( b64 != 0 ) { + fail = a64 != (ret64 / b64); + } else if( a64 != 0 ) { + fail = b64 != (ret64 / a64); + } + if ( fail ) + { + fprintf (stderr, "silk_SMULL(%lld, %lld) in %s: line %d\n", (long long)a64, (long long)b64, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret64; +} + +/* no checking needed for silk_SMULBB */ +#undef silk_SMLABB +#define silk_SMLABB(a,b,c) silk_SMLABB_((a), (b), (c), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_SMLABB_(opus_int32 a32, opus_int32 b32, opus_int32 c32, char *file, int line){ + opus_int32 ret; + ret = a32 + (opus_int32)((opus_int16)b32) * (opus_int32)((opus_int16)c32); + if ( (opus_int64)ret != (opus_int64)a32 + (opus_int64)b32 * (opus_int16)c32 ) + { + fprintf (stderr, "silk_SMLABB(%d, %d, %d) in %s: line %d\n", a32, b32, c32, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +/* no checking needed for silk_SMULBT */ +#undef silk_SMLABT +#define silk_SMLABT(a,b,c) silk_SMLABT_((a), (b), (c), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_SMLABT_(opus_int32 a32, opus_int32 b32, opus_int32 c32, char *file, int line){ + opus_int32 ret; + ret = a32 + ((opus_int32)((opus_int16)b32)) * (c32 >> 16); + if ( (opus_int64)ret != (opus_int64)a32 + (opus_int64)b32 * (c32 >> 16) ) + { + fprintf (stderr, "silk_SMLABT(%d, %d, %d) in %s: line %d\n", a32, b32, c32, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +/* no checking needed for silk_SMULTT */ +#undef silk_SMLATT +#define silk_SMLATT(a,b,c) silk_SMLATT_((a), (b), (c), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_SMLATT_(opus_int32 a32, opus_int32 b32, opus_int32 c32, char *file, int line){ + opus_int32 ret; + ret = a32 + (b32 >> 16) * (c32 >> 16); + if ( (opus_int64)ret != (opus_int64)a32 + (b32 >> 16) * (c32 >> 16) ) + { + fprintf (stderr, "silk_SMLATT(%d, %d, %d) in %s: line %d\n", a32, b32, c32, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +#undef silk_SMULWW +#define silk_SMULWW(a,b) silk_SMULWW_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_SMULWW_(opus_int32 a32, opus_int32 b32, char *file, int line){ + opus_int32 ret, tmp1, tmp2; + opus_int64 ret64; + int fail = 0; + + ret = silk_SMULWB( a32, b32 ); + tmp1 = silk_RSHIFT_ROUND( b32, 16 ); + tmp2 = silk_MUL( a32, tmp1 ); + + fail |= (opus_int64)tmp2 != (opus_int64) a32 * (opus_int64) tmp1; + + tmp1 = ret; + ret = silk_ADD32( tmp1, tmp2 ); + fail |= silk_ADD32( tmp1, tmp2 ) != silk_ADD_SAT32( tmp1, tmp2 ); + + ret64 = silk_RSHIFT64( silk_SMULL( a32, b32 ), 16 ); + fail |= (opus_int64)ret != ret64; + + if ( fail ) + { + fprintf (stderr, "silk_SMULWT(%d, %d) in %s: line %d\n", a32, b32, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + + return ret; +} + +#undef silk_SMLAWW +#define silk_SMLAWW(a,b,c) silk_SMLAWW_((a), (b), (c), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_SMLAWW_(opus_int32 a32, opus_int32 b32, opus_int32 c32, char *file, int line){ + opus_int32 ret, tmp; + + tmp = silk_SMULWW( b32, c32 ); + ret = silk_ADD32( a32, tmp ); + if ( ret != silk_ADD_SAT32( a32, tmp ) ) + { + fprintf (stderr, "silk_SMLAWW(%d, %d, %d) in %s: line %d\n", a32, b32, c32, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +/* Multiply-accumulate macros that allow overflow in the addition (ie, no asserts in debug mode) */ +#undef silk_MLA_ovflw +#define silk_MLA_ovflw(a32, b32, c32) ((a32) + ((b32) * (c32))) +#undef silk_SMLABB_ovflw +#define silk_SMLABB_ovflw(a32, b32, c32) ((a32) + ((opus_int32)((opus_int16)(b32))) * (opus_int32)((opus_int16)(c32))) + +/* no checking needed for silk_SMULL + no checking needed for silk_SMLAL + no checking needed for silk_SMLALBB + no checking needed for SigProcFIX_CLZ16 + no checking needed for SigProcFIX_CLZ32*/ + +#undef silk_DIV32 +#define silk_DIV32(a,b) silk_DIV32_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_DIV32_(opus_int32 a32, opus_int32 b32, char *file, int line){ + if ( b32 == 0 ) + { + fprintf (stderr, "silk_DIV32(%d, %d) in %s: line %d\n", a32, b32, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return a32 / b32; +} + +#undef silk_DIV32_16 +#define silk_DIV32_16(a,b) silk_DIV32_16_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_DIV32_16_(opus_int32 a32, opus_int32 b32, char *file, int line){ + int fail = 0; + fail |= b32 == 0; + fail |= b32 > silk_int16_MAX; + fail |= b32 < silk_int16_MIN; + if ( fail ) + { + fprintf (stderr, "silk_DIV32_16(%d, %d) in %s: line %d\n", a32, b32, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return a32 / b32; +} + +/* no checking needed for silk_SAT8 + no checking needed for silk_SAT16 + no checking needed for silk_SAT32 + no checking needed for silk_POS_SAT32 + no checking needed for silk_ADD_POS_SAT8 + no checking needed for silk_ADD_POS_SAT16 + no checking needed for silk_ADD_POS_SAT32 */ + +#undef silk_LSHIFT8 +#define silk_LSHIFT8(a,b) silk_LSHIFT8_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int8 silk_LSHIFT8_(opus_int8 a, opus_int32 shift, char *file, int line){ + opus_int8 ret; + int fail = 0; + ret = a << shift; + fail |= shift < 0; + fail |= shift >= 8; + fail |= (opus_int64)ret != ((opus_int64)a) << shift; + if ( fail ) + { + fprintf (stderr, "silk_LSHIFT8(%d, %d) in %s: line %d\n", a, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +#undef silk_LSHIFT16 +#define silk_LSHIFT16(a,b) silk_LSHIFT16_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int16 silk_LSHIFT16_(opus_int16 a, opus_int32 shift, char *file, int line){ + opus_int16 ret; + int fail = 0; + ret = a << shift; + fail |= shift < 0; + fail |= shift >= 16; + fail |= (opus_int64)ret != ((opus_int64)a) << shift; + if ( fail ) + { + fprintf (stderr, "silk_LSHIFT16(%d, %d) in %s: line %d\n", a, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +#undef silk_LSHIFT32 +#define silk_LSHIFT32(a,b) silk_LSHIFT32_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_LSHIFT32_(opus_int32 a, opus_int32 shift, char *file, int line){ + opus_int32 ret; + int fail = 0; + ret = a << shift; + fail |= shift < 0; + fail |= shift >= 32; + fail |= (opus_int64)ret != ((opus_int64)a) << shift; + if ( fail ) + { + fprintf (stderr, "silk_LSHIFT32(%d, %d) in %s: line %d\n", a, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +#undef silk_LSHIFT64 +#define silk_LSHIFT64(a,b) silk_LSHIFT64_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int64 silk_LSHIFT64_(opus_int64 a, opus_int shift, char *file, int line){ + opus_int64 ret; + int fail = 0; + ret = a << shift; + fail |= shift < 0; + fail |= shift >= 64; + fail |= (ret>>shift) != ((opus_int64)a); + if ( fail ) + { + fprintf (stderr, "silk_LSHIFT64(%lld, %d) in %s: line %d\n", (long long)a, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +#undef silk_LSHIFT_ovflw +#define silk_LSHIFT_ovflw(a,b) silk_LSHIFT_ovflw_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_LSHIFT_ovflw_(opus_int32 a, opus_int32 shift, char *file, int line){ + if ( (shift < 0) || (shift >= 32) ) /* no check for overflow */ + { + fprintf (stderr, "silk_LSHIFT_ovflw(%d, %d) in %s: line %d\n", a, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return a << shift; +} + +#undef silk_LSHIFT_uint +#define silk_LSHIFT_uint(a,b) silk_LSHIFT_uint_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_uint32 silk_LSHIFT_uint_(opus_uint32 a, opus_int32 shift, char *file, int line){ + opus_uint32 ret; + ret = a << shift; + if ( (shift < 0) || ((opus_int64)ret != ((opus_int64)a) << shift)) + { + fprintf (stderr, "silk_LSHIFT_uint(%u, %d) in %s: line %d\n", a, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +#undef silk_RSHIFT8 +#define silk_RSHITF8(a,b) silk_RSHIFT8_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int8 silk_RSHIFT8_(opus_int8 a, opus_int32 shift, char *file, int line){ + if ( (shift < 0) || (shift>=8) ) + { + fprintf (stderr, "silk_RSHITF8(%d, %d) in %s: line %d\n", a, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return a >> shift; +} + +#undef silk_RSHIFT16 +#define silk_RSHITF16(a,b) silk_RSHIFT16_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int16 silk_RSHIFT16_(opus_int16 a, opus_int32 shift, char *file, int line){ + if ( (shift < 0) || (shift>=16) ) + { + fprintf (stderr, "silk_RSHITF16(%d, %d) in %s: line %d\n", a, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return a >> shift; +} + +#undef silk_RSHIFT32 +#define silk_RSHIFT32(a,b) silk_RSHIFT32_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_RSHIFT32_(opus_int32 a, opus_int32 shift, char *file, int line){ + if ( (shift < 0) || (shift>=32) ) + { + fprintf (stderr, "silk_RSHITF32(%d, %d) in %s: line %d\n", a, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return a >> shift; +} + +#undef silk_RSHIFT64 +#define silk_RSHIFT64(a,b) silk_RSHIFT64_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int64 silk_RSHIFT64_(opus_int64 a, opus_int64 shift, char *file, int line){ + if ( (shift < 0) || (shift>=64) ) + { + fprintf (stderr, "silk_RSHITF64(%lld, %lld) in %s: line %d\n", (long long)a, (long long)shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return a >> shift; +} + +#undef silk_RSHIFT_uint +#define silk_RSHIFT_uint(a,b) silk_RSHIFT_uint_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_uint32 silk_RSHIFT_uint_(opus_uint32 a, opus_int32 shift, char *file, int line){ + if ( (shift < 0) || (shift>32) ) + { + fprintf (stderr, "silk_RSHIFT_uint(%u, %d) in %s: line %d\n", a, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return a >> shift; +} + +#undef silk_ADD_LSHIFT +#define silk_ADD_LSHIFT(a,b,c) silk_ADD_LSHIFT_((a), (b), (c), __FILE__, __LINE__) +static OPUS_INLINE int silk_ADD_LSHIFT_(int a, int b, int shift, char *file, int line){ + opus_int16 ret; + ret = a + (b << shift); + if ( (shift < 0) || (shift>15) || ((opus_int64)ret != (opus_int64)a + (((opus_int64)b) << shift)) ) + { + fprintf (stderr, "silk_ADD_LSHIFT(%d, %d, %d) in %s: line %d\n", a, b, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; /* shift >= 0 */ +} + +#undef silk_ADD_LSHIFT32 +#define silk_ADD_LSHIFT32(a,b,c) silk_ADD_LSHIFT32_((a), (b), (c), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_ADD_LSHIFT32_(opus_int32 a, opus_int32 b, opus_int32 shift, char *file, int line){ + opus_int32 ret; + ret = a + (b << shift); + if ( (shift < 0) || (shift>31) || ((opus_int64)ret != (opus_int64)a + (((opus_int64)b) << shift)) ) + { + fprintf (stderr, "silk_ADD_LSHIFT32(%d, %d, %d) in %s: line %d\n", a, b, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; /* shift >= 0 */ +} + +#undef silk_ADD_LSHIFT_uint +#define silk_ADD_LSHIFT_uint(a,b,c) silk_ADD_LSHIFT_uint_((a), (b), (c), __FILE__, __LINE__) +static OPUS_INLINE opus_uint32 silk_ADD_LSHIFT_uint_(opus_uint32 a, opus_uint32 b, opus_int32 shift, char *file, int line){ + opus_uint32 ret; + ret = a + (b << shift); + if ( (shift < 0) || (shift>32) || ((opus_int64)ret != (opus_int64)a + (((opus_int64)b) << shift)) ) + { + fprintf (stderr, "silk_ADD_LSHIFT_uint(%u, %u, %d) in %s: line %d\n", a, b, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; /* shift >= 0 */ +} + +#undef silk_ADD_RSHIFT +#define silk_ADD_RSHIFT(a,b,c) silk_ADD_RSHIFT_((a), (b), (c), __FILE__, __LINE__) +static OPUS_INLINE int silk_ADD_RSHIFT_(int a, int b, int shift, char *file, int line){ + opus_int16 ret; + ret = a + (b >> shift); + if ( (shift < 0) || (shift>15) || ((opus_int64)ret != (opus_int64)a + (((opus_int64)b) >> shift)) ) + { + fprintf (stderr, "silk_ADD_RSHIFT(%d, %d, %d) in %s: line %d\n", a, b, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; /* shift > 0 */ +} + +#undef silk_ADD_RSHIFT32 +#define silk_ADD_RSHIFT32(a,b,c) silk_ADD_RSHIFT32_((a), (b), (c), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_ADD_RSHIFT32_(opus_int32 a, opus_int32 b, opus_int32 shift, char *file, int line){ + opus_int32 ret; + ret = a + (b >> shift); + if ( (shift < 0) || (shift>31) || ((opus_int64)ret != (opus_int64)a + (((opus_int64)b) >> shift)) ) + { + fprintf (stderr, "silk_ADD_RSHIFT32(%d, %d, %d) in %s: line %d\n", a, b, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; /* shift > 0 */ +} + +#undef silk_ADD_RSHIFT_uint +#define silk_ADD_RSHIFT_uint(a,b,c) silk_ADD_RSHIFT_uint_((a), (b), (c), __FILE__, __LINE__) +static OPUS_INLINE opus_uint32 silk_ADD_RSHIFT_uint_(opus_uint32 a, opus_uint32 b, opus_int32 shift, char *file, int line){ + opus_uint32 ret; + ret = a + (b >> shift); + if ( (shift < 0) || (shift>32) || ((opus_int64)ret != (opus_int64)a + (((opus_int64)b) >> shift)) ) + { + fprintf (stderr, "silk_ADD_RSHIFT_uint(%u, %u, %d) in %s: line %d\n", a, b, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; /* shift > 0 */ +} + +#undef silk_SUB_LSHIFT32 +#define silk_SUB_LSHIFT32(a,b,c) silk_SUB_LSHIFT32_((a), (b), (c), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_SUB_LSHIFT32_(opus_int32 a, opus_int32 b, opus_int32 shift, char *file, int line){ + opus_int32 ret; + ret = a - (b << shift); + if ( (shift < 0) || (shift>31) || ((opus_int64)ret != (opus_int64)a - (((opus_int64)b) << shift)) ) + { + fprintf (stderr, "silk_SUB_LSHIFT32(%d, %d, %d) in %s: line %d\n", a, b, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; /* shift >= 0 */ +} + +#undef silk_SUB_RSHIFT32 +#define silk_SUB_RSHIFT32(a,b,c) silk_SUB_RSHIFT32_((a), (b), (c), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_SUB_RSHIFT32_(opus_int32 a, opus_int32 b, opus_int32 shift, char *file, int line){ + opus_int32 ret; + ret = a - (b >> shift); + if ( (shift < 0) || (shift>31) || ((opus_int64)ret != (opus_int64)a - (((opus_int64)b) >> shift)) ) + { + fprintf (stderr, "silk_SUB_RSHIFT32(%d, %d, %d) in %s: line %d\n", a, b, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; /* shift > 0 */ +} + +#undef silk_RSHIFT_ROUND +#define silk_RSHIFT_ROUND(a,b) silk_RSHIFT_ROUND_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_RSHIFT_ROUND_(opus_int32 a, opus_int32 shift, char *file, int line){ + opus_int32 ret; + ret = shift == 1 ? (a >> 1) + (a & 1) : ((a >> (shift - 1)) + 1) >> 1; + /* the marco definition can't handle a shift of zero */ + if ( (shift <= 0) || (shift>31) || ((opus_int64)ret != ((opus_int64)a + ((opus_int64)1 << (shift - 1))) >> shift) ) + { + fprintf (stderr, "silk_RSHIFT_ROUND(%d, %d) in %s: line %d\n", a, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +#undef silk_RSHIFT_ROUND64 +#define silk_RSHIFT_ROUND64(a,b) silk_RSHIFT_ROUND64_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int64 silk_RSHIFT_ROUND64_(opus_int64 a, opus_int32 shift, char *file, int line){ + opus_int64 ret; + /* the marco definition can't handle a shift of zero */ + if ( (shift <= 0) || (shift>=64) ) + { + fprintf (stderr, "silk_RSHIFT_ROUND64(%lld, %d) in %s: line %d\n", (long long)a, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + ret = shift == 1 ? (a >> 1) + (a & 1) : ((a >> (shift - 1)) + 1) >> 1; + return ret; +} + +/* silk_abs is used on floats also, so doesn't work... */ +/*#undef silk_abs +static OPUS_INLINE opus_int32 silk_abs(opus_int32 a){ + silk_assert(a != 0x80000000); + return (((a) > 0) ? (a) : -(a)); // Be careful, silk_abs returns wrong when input equals to silk_intXX_MIN +}*/ + +#undef silk_abs_int64 +#define silk_abs_int64(a) silk_abs_int64_((a), __FILE__, __LINE__) +static OPUS_INLINE opus_int64 silk_abs_int64_(opus_int64 a, char *file, int line){ + if ( a == silk_int64_MIN ) + { + fprintf (stderr, "silk_abs_int64(%lld) in %s: line %d\n", (long long)a, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return (((a) > 0) ? (a) : -(a)); /* Be careful, silk_abs returns wrong when input equals to silk_intXX_MIN */ +} + +#undef silk_abs_int32 +#define silk_abs_int32(a) silk_abs_int32_((a), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_abs_int32_(opus_int32 a, char *file, int line){ + if ( a == silk_int32_MIN ) + { + fprintf (stderr, "silk_abs_int32(%d) in %s: line %d\n", a, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return silk_abs(a); +} + +#undef silk_CHECK_FIT8 +#define silk_CHECK_FIT8(a) silk_CHECK_FIT8_((a), __FILE__, __LINE__) +static OPUS_INLINE opus_int8 silk_CHECK_FIT8_( opus_int64 a, char *file, int line ){ + opus_int8 ret; + ret = (opus_int8)a; + if ( (opus_int64)ret != a ) + { + fprintf (stderr, "silk_CHECK_FIT8(%lld) in %s: line %d\n", (long long)a, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return( ret ); +} + +#undef silk_CHECK_FIT16 +#define silk_CHECK_FIT16(a) silk_CHECK_FIT16_((a), __FILE__, __LINE__) +static OPUS_INLINE opus_int16 silk_CHECK_FIT16_( opus_int64 a, char *file, int line ){ + opus_int16 ret; + ret = (opus_int16)a; + if ( (opus_int64)ret != a ) + { + fprintf (stderr, "silk_CHECK_FIT16(%lld) in %s: line %d\n", (long long)a, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return( ret ); +} + +#undef silk_CHECK_FIT32 +#define silk_CHECK_FIT32(a) silk_CHECK_FIT32_((a), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_CHECK_FIT32_( opus_int64 a, char *file, int line ){ + opus_int32 ret; + ret = (opus_int32)a; + if ( (opus_int64)ret != a ) + { + fprintf (stderr, "silk_CHECK_FIT32(%lld) in %s: line %d\n", (long long)a, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return( ret ); +} + +/* no checking for silk_NSHIFT_MUL_32_32 + no checking for silk_NSHIFT_MUL_16_16 + no checking needed for silk_min + no checking needed for silk_max + no checking needed for silk_sign +*/ + +#endif +#endif /* MACRO_DEBUG_H */ diff --git a/extern/opus/silk/NLSF2A.c b/extern/opus/silk/NLSF2A.c new file mode 100644 index 0000000..d5b7730 --- /dev/null +++ b/extern/opus/silk/NLSF2A.c @@ -0,0 +1,141 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/* conversion between prediction filter coefficients and LSFs */ +/* order should be even */ +/* a piecewise linear approximation maps LSF <-> cos(LSF) */ +/* therefore the result is not accurate LSFs, but the two */ +/* functions are accurate inverses of each other */ + +#include "SigProc_FIX.h" +#include "tables.h" + +#define QA 16 + +/* helper function for NLSF2A(..) */ +static OPUS_INLINE void silk_NLSF2A_find_poly( + opus_int32 *out, /* O intermediate polynomial, QA [dd+1] */ + const opus_int32 *cLSF, /* I vector of interleaved 2*cos(LSFs), QA [d] */ + opus_int dd /* I polynomial order (= 1/2 * filter order) */ +) +{ + opus_int k, n; + opus_int32 ftmp; + + out[0] = silk_LSHIFT( 1, QA ); + out[1] = -cLSF[0]; + for( k = 1; k < dd; k++ ) { + ftmp = cLSF[2*k]; /* QA*/ + out[k+1] = silk_LSHIFT( out[k-1], 1 ) - (opus_int32)silk_RSHIFT_ROUND64( silk_SMULL( ftmp, out[k] ), QA ); + for( n = k; n > 1; n-- ) { + out[n] += out[n-2] - (opus_int32)silk_RSHIFT_ROUND64( silk_SMULL( ftmp, out[n-1] ), QA ); + } + out[1] -= ftmp; + } +} + +/* compute whitening filter coefficients from normalized line spectral frequencies */ +void silk_NLSF2A( + opus_int16 *a_Q12, /* O monic whitening filter coefficients in Q12, [ d ] */ + const opus_int16 *NLSF, /* I normalized line spectral frequencies in Q15, [ d ] */ + const opus_int d, /* I filter order (should be even) */ + int arch /* I Run-time architecture */ +) +{ + /* This ordering was found to maximize quality. It improves numerical accuracy of + silk_NLSF2A_find_poly() compared to "standard" ordering. */ + static const unsigned char ordering16[16] = { + 0, 15, 8, 7, 4, 11, 12, 3, 2, 13, 10, 5, 6, 9, 14, 1 + }; + static const unsigned char ordering10[10] = { + 0, 9, 6, 3, 4, 5, 8, 1, 2, 7 + }; + const unsigned char *ordering; + opus_int k, i, dd; + opus_int32 cos_LSF_QA[ SILK_MAX_ORDER_LPC ]; + opus_int32 P[ SILK_MAX_ORDER_LPC / 2 + 1 ], Q[ SILK_MAX_ORDER_LPC / 2 + 1 ]; + opus_int32 Ptmp, Qtmp, f_int, f_frac, cos_val, delta; + opus_int32 a32_QA1[ SILK_MAX_ORDER_LPC ]; + + silk_assert( LSF_COS_TAB_SZ_FIX == 128 ); + celt_assert( d==10 || d==16 ); + + /* convert LSFs to 2*cos(LSF), using piecewise linear curve from table */ + ordering = d == 16 ? ordering16 : ordering10; + for( k = 0; k < d; k++ ) { + silk_assert( NLSF[k] >= 0 ); + + /* f_int on a scale 0-127 (rounded down) */ + f_int = silk_RSHIFT( NLSF[k], 15 - 7 ); + + /* f_frac, range: 0..255 */ + f_frac = NLSF[k] - silk_LSHIFT( f_int, 15 - 7 ); + + silk_assert(f_int >= 0); + silk_assert(f_int < LSF_COS_TAB_SZ_FIX ); + + /* Read start and end value from table */ + cos_val = silk_LSFCosTab_FIX_Q12[ f_int ]; /* Q12 */ + delta = silk_LSFCosTab_FIX_Q12[ f_int + 1 ] - cos_val; /* Q12, with a range of 0..200 */ + + /* Linear interpolation */ + cos_LSF_QA[ordering[k]] = silk_RSHIFT_ROUND( silk_LSHIFT( cos_val, 8 ) + silk_MUL( delta, f_frac ), 20 - QA ); /* QA */ + } + + dd = silk_RSHIFT( d, 1 ); + + /* generate even and odd polynomials using convolution */ + silk_NLSF2A_find_poly( P, &cos_LSF_QA[ 0 ], dd ); + silk_NLSF2A_find_poly( Q, &cos_LSF_QA[ 1 ], dd ); + + /* convert even and odd polynomials to opus_int32 Q12 filter coefs */ + for( k = 0; k < dd; k++ ) { + Ptmp = P[ k+1 ] + P[ k ]; + Qtmp = Q[ k+1 ] - Q[ k ]; + + /* the Ptmp and Qtmp values at this stage need to fit in int32 */ + a32_QA1[ k ] = -Qtmp - Ptmp; /* QA+1 */ + a32_QA1[ d-k-1 ] = Qtmp - Ptmp; /* QA+1 */ + } + + /* Convert int32 coefficients to Q12 int16 coefs */ + silk_LPC_fit( a_Q12, a32_QA1, 12, QA + 1, d ); + + for( i = 0; silk_LPC_inverse_pred_gain( a_Q12, d, arch ) == 0 && i < MAX_LPC_STABILIZE_ITERATIONS; i++ ) { + /* Prediction coefficients are (too close to) unstable; apply bandwidth expansion */ + /* on the unscaled coefficients, convert to Q12 and measure again */ + silk_bwexpander_32( a32_QA1, d, 65536 - silk_LSHIFT( 2, i ) ); + for( k = 0; k < d; k++ ) { + a_Q12[ k ] = (opus_int16)silk_RSHIFT_ROUND( a32_QA1[ k ], QA + 1 - 12 ); /* QA+1 -> Q12 */ + } + } +} + diff --git a/extern/opus/silk/NLSF_VQ.c b/extern/opus/silk/NLSF_VQ.c new file mode 100644 index 0000000..b83182a --- /dev/null +++ b/extern/opus/silk/NLSF_VQ.c @@ -0,0 +1,76 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/* Compute quantization errors for an LPC_order element input vector for a VQ codebook */ +void silk_NLSF_VQ( + opus_int32 err_Q24[], /* O Quantization errors [K] */ + const opus_int16 in_Q15[], /* I Input vectors to be quantized [LPC_order] */ + const opus_uint8 pCB_Q8[], /* I Codebook vectors [K*LPC_order] */ + const opus_int16 pWght_Q9[], /* I Codebook weights [K*LPC_order] */ + const opus_int K, /* I Number of codebook vectors */ + const opus_int LPC_order /* I Number of LPCs */ +) +{ + opus_int i, m; + opus_int32 diff_Q15, diffw_Q24, sum_error_Q24, pred_Q24; + const opus_int16 *w_Q9_ptr; + const opus_uint8 *cb_Q8_ptr; + + celt_assert( ( LPC_order & 1 ) == 0 ); + + /* Loop over codebook */ + cb_Q8_ptr = pCB_Q8; + w_Q9_ptr = pWght_Q9; + for( i = 0; i < K; i++ ) { + sum_error_Q24 = 0; + pred_Q24 = 0; + for( m = LPC_order-2; m >= 0; m -= 2 ) { + /* Compute weighted absolute predictive quantization error for index m + 1 */ + diff_Q15 = silk_SUB_LSHIFT32( in_Q15[ m + 1 ], (opus_int32)cb_Q8_ptr[ m + 1 ], 7 ); /* range: [ -32767 : 32767 ]*/ + diffw_Q24 = silk_SMULBB( diff_Q15, w_Q9_ptr[ m + 1 ] ); + sum_error_Q24 = silk_ADD32( sum_error_Q24, silk_abs( silk_SUB_RSHIFT32( diffw_Q24, pred_Q24, 1 ) ) ); + pred_Q24 = diffw_Q24; + + /* Compute weighted absolute predictive quantization error for index m */ + diff_Q15 = silk_SUB_LSHIFT32( in_Q15[ m ], (opus_int32)cb_Q8_ptr[ m ], 7 ); /* range: [ -32767 : 32767 ]*/ + diffw_Q24 = silk_SMULBB( diff_Q15, w_Q9_ptr[ m ] ); + sum_error_Q24 = silk_ADD32( sum_error_Q24, silk_abs( silk_SUB_RSHIFT32( diffw_Q24, pred_Q24, 1 ) ) ); + pred_Q24 = diffw_Q24; + + silk_assert( sum_error_Q24 >= 0 ); + } + err_Q24[ i ] = sum_error_Q24; + cb_Q8_ptr += LPC_order; + w_Q9_ptr += LPC_order; + } +} diff --git a/extern/opus/silk/NLSF_VQ_weights_laroia.c b/extern/opus/silk/NLSF_VQ_weights_laroia.c new file mode 100644 index 0000000..9873bcd --- /dev/null +++ b/extern/opus/silk/NLSF_VQ_weights_laroia.c @@ -0,0 +1,80 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "define.h" +#include "SigProc_FIX.h" + +/* +R. Laroia, N. Phamdo and N. Farvardin, "Robust and Efficient Quantization of Speech LSP +Parameters Using Structured Vector Quantization", Proc. IEEE Int. Conf. Acoust., Speech, +Signal Processing, pp. 641-644, 1991. +*/ + +/* Laroia low complexity NLSF weights */ +void silk_NLSF_VQ_weights_laroia( + opus_int16 *pNLSFW_Q_OUT, /* O Pointer to input vector weights [D] */ + const opus_int16 *pNLSF_Q15, /* I Pointer to input vector [D] */ + const opus_int D /* I Input vector dimension (even) */ +) +{ + opus_int k; + opus_int32 tmp1_int, tmp2_int; + + celt_assert( D > 0 ); + celt_assert( ( D & 1 ) == 0 ); + + /* First value */ + tmp1_int = silk_max_int( pNLSF_Q15[ 0 ], 1 ); + tmp1_int = silk_DIV32_16( (opus_int32)1 << ( 15 + NLSF_W_Q ), tmp1_int ); + tmp2_int = silk_max_int( pNLSF_Q15[ 1 ] - pNLSF_Q15[ 0 ], 1 ); + tmp2_int = silk_DIV32_16( (opus_int32)1 << ( 15 + NLSF_W_Q ), tmp2_int ); + pNLSFW_Q_OUT[ 0 ] = (opus_int16)silk_min_int( tmp1_int + tmp2_int, silk_int16_MAX ); + silk_assert( pNLSFW_Q_OUT[ 0 ] > 0 ); + + /* Main loop */ + for( k = 1; k < D - 1; k += 2 ) { + tmp1_int = silk_max_int( pNLSF_Q15[ k + 1 ] - pNLSF_Q15[ k ], 1 ); + tmp1_int = silk_DIV32_16( (opus_int32)1 << ( 15 + NLSF_W_Q ), tmp1_int ); + pNLSFW_Q_OUT[ k ] = (opus_int16)silk_min_int( tmp1_int + tmp2_int, silk_int16_MAX ); + silk_assert( pNLSFW_Q_OUT[ k ] > 0 ); + + tmp2_int = silk_max_int( pNLSF_Q15[ k + 2 ] - pNLSF_Q15[ k + 1 ], 1 ); + tmp2_int = silk_DIV32_16( (opus_int32)1 << ( 15 + NLSF_W_Q ), tmp2_int ); + pNLSFW_Q_OUT[ k + 1 ] = (opus_int16)silk_min_int( tmp1_int + tmp2_int, silk_int16_MAX ); + silk_assert( pNLSFW_Q_OUT[ k + 1 ] > 0 ); + } + + /* Last value */ + tmp1_int = silk_max_int( ( 1 << 15 ) - pNLSF_Q15[ D - 1 ], 1 ); + tmp1_int = silk_DIV32_16( (opus_int32)1 << ( 15 + NLSF_W_Q ), tmp1_int ); + pNLSFW_Q_OUT[ D - 1 ] = (opus_int16)silk_min_int( tmp1_int + tmp2_int, silk_int16_MAX ); + silk_assert( pNLSFW_Q_OUT[ D - 1 ] > 0 ); +} diff --git a/extern/opus/silk/NLSF_decode.c b/extern/opus/silk/NLSF_decode.c new file mode 100644 index 0000000..eeb0ba8 --- /dev/null +++ b/extern/opus/silk/NLSF_decode.c @@ -0,0 +1,93 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/* Predictive dequantizer for NLSF residuals */ +static OPUS_INLINE void silk_NLSF_residual_dequant( /* O Returns RD value in Q30 */ + opus_int16 x_Q10[], /* O Output [ order ] */ + const opus_int8 indices[], /* I Quantization indices [ order ] */ + const opus_uint8 pred_coef_Q8[], /* I Backward predictor coefs [ order ] */ + const opus_int quant_step_size_Q16, /* I Quantization step size */ + const opus_int16 order /* I Number of input values */ +) +{ + opus_int i, out_Q10, pred_Q10; + + out_Q10 = 0; + for( i = order-1; i >= 0; i-- ) { + pred_Q10 = silk_RSHIFT( silk_SMULBB( out_Q10, (opus_int16)pred_coef_Q8[ i ] ), 8 ); + out_Q10 = silk_LSHIFT( indices[ i ], 10 ); + if( out_Q10 > 0 ) { + out_Q10 = silk_SUB16( out_Q10, SILK_FIX_CONST( NLSF_QUANT_LEVEL_ADJ, 10 ) ); + } else if( out_Q10 < 0 ) { + out_Q10 = silk_ADD16( out_Q10, SILK_FIX_CONST( NLSF_QUANT_LEVEL_ADJ, 10 ) ); + } + out_Q10 = silk_SMLAWB( pred_Q10, (opus_int32)out_Q10, quant_step_size_Q16 ); + x_Q10[ i ] = out_Q10; + } +} + + +/***********************/ +/* NLSF vector decoder */ +/***********************/ +void silk_NLSF_decode( + opus_int16 *pNLSF_Q15, /* O Quantized NLSF vector [ LPC_ORDER ] */ + opus_int8 *NLSFIndices, /* I Codebook path vector [ LPC_ORDER + 1 ] */ + const silk_NLSF_CB_struct *psNLSF_CB /* I Codebook object */ +) +{ + opus_int i; + opus_uint8 pred_Q8[ MAX_LPC_ORDER ]; + opus_int16 ec_ix[ MAX_LPC_ORDER ]; + opus_int16 res_Q10[ MAX_LPC_ORDER ]; + opus_int32 NLSF_Q15_tmp; + const opus_uint8 *pCB_element; + const opus_int16 *pCB_Wght_Q9; + + /* Unpack entropy table indices and predictor for current CB1 index */ + silk_NLSF_unpack( ec_ix, pred_Q8, psNLSF_CB, NLSFIndices[ 0 ] ); + + /* Predictive residual dequantizer */ + silk_NLSF_residual_dequant( res_Q10, &NLSFIndices[ 1 ], pred_Q8, psNLSF_CB->quantStepSize_Q16, psNLSF_CB->order ); + + /* Apply inverse square-rooted weights to first stage and add to output */ + pCB_element = &psNLSF_CB->CB1_NLSF_Q8[ NLSFIndices[ 0 ] * psNLSF_CB->order ]; + pCB_Wght_Q9 = &psNLSF_CB->CB1_Wght_Q9[ NLSFIndices[ 0 ] * psNLSF_CB->order ]; + for( i = 0; i < psNLSF_CB->order; i++ ) { + NLSF_Q15_tmp = silk_ADD_LSHIFT32( silk_DIV32_16( silk_LSHIFT( (opus_int32)res_Q10[ i ], 14 ), pCB_Wght_Q9[ i ] ), (opus_int16)pCB_element[ i ], 7 ); + pNLSF_Q15[ i ] = (opus_int16)silk_LIMIT( NLSF_Q15_tmp, 0, 32767 ); + } + + /* NLSF stabilization */ + silk_NLSF_stabilize( pNLSF_Q15, psNLSF_CB->deltaMin_Q15, psNLSF_CB->order ); +} diff --git a/extern/opus/silk/NLSF_del_dec_quant.c b/extern/opus/silk/NLSF_del_dec_quant.c new file mode 100644 index 0000000..44a16ac --- /dev/null +++ b/extern/opus/silk/NLSF_del_dec_quant.c @@ -0,0 +1,215 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/* Delayed-decision quantizer for NLSF residuals */ +opus_int32 silk_NLSF_del_dec_quant( /* O Returns RD value in Q25 */ + opus_int8 indices[], /* O Quantization indices [ order ] */ + const opus_int16 x_Q10[], /* I Input [ order ] */ + const opus_int16 w_Q5[], /* I Weights [ order ] */ + const opus_uint8 pred_coef_Q8[], /* I Backward predictor coefs [ order ] */ + const opus_int16 ec_ix[], /* I Indices to entropy coding tables [ order ] */ + const opus_uint8 ec_rates_Q5[], /* I Rates [] */ + const opus_int quant_step_size_Q16, /* I Quantization step size */ + const opus_int16 inv_quant_step_size_Q6, /* I Inverse quantization step size */ + const opus_int32 mu_Q20, /* I R/D tradeoff */ + const opus_int16 order /* I Number of input values */ +) +{ + opus_int i, j, nStates, ind_tmp, ind_min_max, ind_max_min, in_Q10, res_Q10; + opus_int pred_Q10, diff_Q10, rate0_Q5, rate1_Q5; + opus_int16 out0_Q10, out1_Q10; + opus_int32 RD_tmp_Q25, min_Q25, min_max_Q25, max_min_Q25; + opus_int ind_sort[ NLSF_QUANT_DEL_DEC_STATES ]; + opus_int8 ind[ NLSF_QUANT_DEL_DEC_STATES ][ MAX_LPC_ORDER ]; + opus_int16 prev_out_Q10[ 2 * NLSF_QUANT_DEL_DEC_STATES ]; + opus_int32 RD_Q25[ 2 * NLSF_QUANT_DEL_DEC_STATES ]; + opus_int32 RD_min_Q25[ NLSF_QUANT_DEL_DEC_STATES ]; + opus_int32 RD_max_Q25[ NLSF_QUANT_DEL_DEC_STATES ]; + const opus_uint8 *rates_Q5; + + opus_int out0_Q10_table[2 * NLSF_QUANT_MAX_AMPLITUDE_EXT]; + opus_int out1_Q10_table[2 * NLSF_QUANT_MAX_AMPLITUDE_EXT]; + + for (i = -NLSF_QUANT_MAX_AMPLITUDE_EXT; i <= NLSF_QUANT_MAX_AMPLITUDE_EXT-1; i++) + { + out0_Q10 = silk_LSHIFT( i, 10 ); + out1_Q10 = silk_ADD16( out0_Q10, 1024 ); + if( i > 0 ) { + out0_Q10 = silk_SUB16( out0_Q10, SILK_FIX_CONST( NLSF_QUANT_LEVEL_ADJ, 10 ) ); + out1_Q10 = silk_SUB16( out1_Q10, SILK_FIX_CONST( NLSF_QUANT_LEVEL_ADJ, 10 ) ); + } else if( i == 0 ) { + out1_Q10 = silk_SUB16( out1_Q10, SILK_FIX_CONST( NLSF_QUANT_LEVEL_ADJ, 10 ) ); + } else if( i == -1 ) { + out0_Q10 = silk_ADD16( out0_Q10, SILK_FIX_CONST( NLSF_QUANT_LEVEL_ADJ, 10 ) ); + } else { + out0_Q10 = silk_ADD16( out0_Q10, SILK_FIX_CONST( NLSF_QUANT_LEVEL_ADJ, 10 ) ); + out1_Q10 = silk_ADD16( out1_Q10, SILK_FIX_CONST( NLSF_QUANT_LEVEL_ADJ, 10 ) ); + } + out0_Q10_table[ i + NLSF_QUANT_MAX_AMPLITUDE_EXT ] = silk_RSHIFT( silk_SMULBB( out0_Q10, quant_step_size_Q16 ), 16 ); + out1_Q10_table[ i + NLSF_QUANT_MAX_AMPLITUDE_EXT ] = silk_RSHIFT( silk_SMULBB( out1_Q10, quant_step_size_Q16 ), 16 ); + } + + silk_assert( (NLSF_QUANT_DEL_DEC_STATES & (NLSF_QUANT_DEL_DEC_STATES-1)) == 0 ); /* must be power of two */ + + nStates = 1; + RD_Q25[ 0 ] = 0; + prev_out_Q10[ 0 ] = 0; + for( i = order - 1; i >= 0; i-- ) { + rates_Q5 = &ec_rates_Q5[ ec_ix[ i ] ]; + in_Q10 = x_Q10[ i ]; + for( j = 0; j < nStates; j++ ) { + pred_Q10 = silk_RSHIFT( silk_SMULBB( (opus_int16)pred_coef_Q8[ i ], prev_out_Q10[ j ] ), 8 ); + res_Q10 = silk_SUB16( in_Q10, pred_Q10 ); + ind_tmp = silk_RSHIFT( silk_SMULBB( inv_quant_step_size_Q6, res_Q10 ), 16 ); + ind_tmp = silk_LIMIT( ind_tmp, -NLSF_QUANT_MAX_AMPLITUDE_EXT, NLSF_QUANT_MAX_AMPLITUDE_EXT-1 ); + ind[ j ][ i ] = (opus_int8)ind_tmp; + + /* compute outputs for ind_tmp and ind_tmp + 1 */ + out0_Q10 = out0_Q10_table[ ind_tmp + NLSF_QUANT_MAX_AMPLITUDE_EXT ]; + out1_Q10 = out1_Q10_table[ ind_tmp + NLSF_QUANT_MAX_AMPLITUDE_EXT ]; + + out0_Q10 = silk_ADD16( out0_Q10, pred_Q10 ); + out1_Q10 = silk_ADD16( out1_Q10, pred_Q10 ); + prev_out_Q10[ j ] = out0_Q10; + prev_out_Q10[ j + nStates ] = out1_Q10; + + /* compute RD for ind_tmp and ind_tmp + 1 */ + if( ind_tmp + 1 >= NLSF_QUANT_MAX_AMPLITUDE ) { + if( ind_tmp + 1 == NLSF_QUANT_MAX_AMPLITUDE ) { + rate0_Q5 = rates_Q5[ ind_tmp + NLSF_QUANT_MAX_AMPLITUDE ]; + rate1_Q5 = 280; + } else { + rate0_Q5 = silk_SMLABB( 280 - 43 * NLSF_QUANT_MAX_AMPLITUDE, 43, ind_tmp ); + rate1_Q5 = silk_ADD16( rate0_Q5, 43 ); + } + } else if( ind_tmp <= -NLSF_QUANT_MAX_AMPLITUDE ) { + if( ind_tmp == -NLSF_QUANT_MAX_AMPLITUDE ) { + rate0_Q5 = 280; + rate1_Q5 = rates_Q5[ ind_tmp + 1 + NLSF_QUANT_MAX_AMPLITUDE ]; + } else { + rate0_Q5 = silk_SMLABB( 280 - 43 * NLSF_QUANT_MAX_AMPLITUDE, -43, ind_tmp ); + rate1_Q5 = silk_SUB16( rate0_Q5, 43 ); + } + } else { + rate0_Q5 = rates_Q5[ ind_tmp + NLSF_QUANT_MAX_AMPLITUDE ]; + rate1_Q5 = rates_Q5[ ind_tmp + 1 + NLSF_QUANT_MAX_AMPLITUDE ]; + } + RD_tmp_Q25 = RD_Q25[ j ]; + diff_Q10 = silk_SUB16( in_Q10, out0_Q10 ); + RD_Q25[ j ] = silk_SMLABB( silk_MLA( RD_tmp_Q25, silk_SMULBB( diff_Q10, diff_Q10 ), w_Q5[ i ] ), mu_Q20, rate0_Q5 ); + diff_Q10 = silk_SUB16( in_Q10, out1_Q10 ); + RD_Q25[ j + nStates ] = silk_SMLABB( silk_MLA( RD_tmp_Q25, silk_SMULBB( diff_Q10, diff_Q10 ), w_Q5[ i ] ), mu_Q20, rate1_Q5 ); + } + + if( nStates <= NLSF_QUANT_DEL_DEC_STATES/2 ) { + /* double number of states and copy */ + for( j = 0; j < nStates; j++ ) { + ind[ j + nStates ][ i ] = ind[ j ][ i ] + 1; + } + nStates = silk_LSHIFT( nStates, 1 ); + for( j = nStates; j < NLSF_QUANT_DEL_DEC_STATES; j++ ) { + ind[ j ][ i ] = ind[ j - nStates ][ i ]; + } + } else { + /* sort lower and upper half of RD_Q25, pairwise */ + for( j = 0; j < NLSF_QUANT_DEL_DEC_STATES; j++ ) { + if( RD_Q25[ j ] > RD_Q25[ j + NLSF_QUANT_DEL_DEC_STATES ] ) { + RD_max_Q25[ j ] = RD_Q25[ j ]; + RD_min_Q25[ j ] = RD_Q25[ j + NLSF_QUANT_DEL_DEC_STATES ]; + RD_Q25[ j ] = RD_min_Q25[ j ]; + RD_Q25[ j + NLSF_QUANT_DEL_DEC_STATES ] = RD_max_Q25[ j ]; + /* swap prev_out values */ + out0_Q10 = prev_out_Q10[ j ]; + prev_out_Q10[ j ] = prev_out_Q10[ j + NLSF_QUANT_DEL_DEC_STATES ]; + prev_out_Q10[ j + NLSF_QUANT_DEL_DEC_STATES ] = out0_Q10; + ind_sort[ j ] = j + NLSF_QUANT_DEL_DEC_STATES; + } else { + RD_min_Q25[ j ] = RD_Q25[ j ]; + RD_max_Q25[ j ] = RD_Q25[ j + NLSF_QUANT_DEL_DEC_STATES ]; + ind_sort[ j ] = j; + } + } + /* compare the highest RD values of the winning half with the lowest one in the losing half, and copy if necessary */ + /* afterwards ind_sort[] will contain the indices of the NLSF_QUANT_DEL_DEC_STATES winning RD values */ + while( 1 ) { + min_max_Q25 = silk_int32_MAX; + max_min_Q25 = 0; + ind_min_max = 0; + ind_max_min = 0; + for( j = 0; j < NLSF_QUANT_DEL_DEC_STATES; 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 ] ) { + max_min_Q25 = RD_min_Q25[ j ]; + ind_max_min = j; + } + } + if( min_max_Q25 >= max_min_Q25 ) { + break; + } + /* copy ind_min_max to ind_max_min */ + ind_sort[ ind_max_min ] = ind_sort[ ind_min_max ] ^ NLSF_QUANT_DEL_DEC_STATES; + RD_Q25[ ind_max_min ] = RD_Q25[ ind_min_max + NLSF_QUANT_DEL_DEC_STATES ]; + prev_out_Q10[ ind_max_min ] = prev_out_Q10[ ind_min_max + NLSF_QUANT_DEL_DEC_STATES ]; + RD_min_Q25[ ind_max_min ] = 0; + RD_max_Q25[ ind_min_max ] = silk_int32_MAX; + silk_memcpy( ind[ ind_max_min ], ind[ ind_min_max ], MAX_LPC_ORDER * sizeof( opus_int8 ) ); + } + /* increment index if it comes from the upper half */ + for( j = 0; j < NLSF_QUANT_DEL_DEC_STATES; j++ ) { + ind[ j ][ i ] += silk_RSHIFT( ind_sort[ j ], NLSF_QUANT_DEL_DEC_STATES_LOG2 ); + } + } + } + + /* last sample: find winner, copy indices and return RD value */ + ind_tmp = 0; + min_Q25 = silk_int32_MAX; + for( j = 0; j < 2 * NLSF_QUANT_DEL_DEC_STATES; j++ ) { + if( min_Q25 > RD_Q25[ j ] ) { + min_Q25 = RD_Q25[ j ]; + ind_tmp = j; + } + } + for( j = 0; j < order; j++ ) { + indices[ j ] = ind[ ind_tmp & ( NLSF_QUANT_DEL_DEC_STATES - 1 ) ][ j ]; + silk_assert( indices[ j ] >= -NLSF_QUANT_MAX_AMPLITUDE_EXT ); + silk_assert( indices[ j ] <= NLSF_QUANT_MAX_AMPLITUDE_EXT ); + } + indices[ 0 ] += silk_RSHIFT( ind_tmp, NLSF_QUANT_DEL_DEC_STATES_LOG2 ); + silk_assert( indices[ 0 ] <= NLSF_QUANT_MAX_AMPLITUDE_EXT ); + silk_assert( min_Q25 >= 0 ); + return min_Q25; +} diff --git a/extern/opus/silk/NLSF_encode.c b/extern/opus/silk/NLSF_encode.c new file mode 100644 index 0000000..01ac7db --- /dev/null +++ b/extern/opus/silk/NLSF_encode.c @@ -0,0 +1,124 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" +#include "stack_alloc.h" + +/***********************/ +/* NLSF vector encoder */ +/***********************/ +opus_int32 silk_NLSF_encode( /* O Returns RD value in Q25 */ + opus_int8 *NLSFIndices, /* I Codebook path vector [ LPC_ORDER + 1 ] */ + opus_int16 *pNLSF_Q15, /* I/O (Un)quantized NLSF vector [ LPC_ORDER ] */ + const silk_NLSF_CB_struct *psNLSF_CB, /* I Codebook object */ + const opus_int16 *pW_Q2, /* I NLSF weight vector [ LPC_ORDER ] */ + const opus_int NLSF_mu_Q20, /* I Rate weight for the RD optimization */ + const opus_int nSurvivors, /* I Max survivors after first stage */ + const opus_int signalType /* I Signal type: 0/1/2 */ +) +{ + opus_int i, s, ind1, bestIndex, prob_Q8, bits_q7; + opus_int32 W_tmp_Q9, ret; + VARDECL( opus_int32, err_Q24 ); + VARDECL( opus_int32, RD_Q25 ); + VARDECL( opus_int, tempIndices1 ); + VARDECL( opus_int8, tempIndices2 ); + opus_int16 res_Q10[ MAX_LPC_ORDER ]; + opus_int16 NLSF_tmp_Q15[ MAX_LPC_ORDER ]; + opus_int16 W_adj_Q5[ MAX_LPC_ORDER ]; + opus_uint8 pred_Q8[ MAX_LPC_ORDER ]; + opus_int16 ec_ix[ MAX_LPC_ORDER ]; + const opus_uint8 *pCB_element, *iCDF_ptr; + const opus_int16 *pCB_Wght_Q9; + SAVE_STACK; + + celt_assert( signalType >= 0 && signalType <= 2 ); + silk_assert( NLSF_mu_Q20 <= 32767 && NLSF_mu_Q20 >= 0 ); + + /* NLSF stabilization */ + silk_NLSF_stabilize( pNLSF_Q15, psNLSF_CB->deltaMin_Q15, psNLSF_CB->order ); + + /* First stage: VQ */ + ALLOC( err_Q24, psNLSF_CB->nVectors, opus_int32 ); + silk_NLSF_VQ( err_Q24, pNLSF_Q15, psNLSF_CB->CB1_NLSF_Q8, psNLSF_CB->CB1_Wght_Q9, psNLSF_CB->nVectors, psNLSF_CB->order ); + + /* Sort the quantization errors */ + ALLOC( tempIndices1, nSurvivors, opus_int ); + silk_insertion_sort_increasing( err_Q24, tempIndices1, psNLSF_CB->nVectors, nSurvivors ); + + ALLOC( RD_Q25, nSurvivors, opus_int32 ); + ALLOC( tempIndices2, nSurvivors * MAX_LPC_ORDER, opus_int8 ); + + /* Loop over survivors */ + for( s = 0; s < nSurvivors; s++ ) { + ind1 = tempIndices1[ s ]; + + /* Residual after first stage */ + pCB_element = &psNLSF_CB->CB1_NLSF_Q8[ ind1 * psNLSF_CB->order ]; + pCB_Wght_Q9 = &psNLSF_CB->CB1_Wght_Q9[ ind1 * psNLSF_CB->order ]; + for( i = 0; i < psNLSF_CB->order; i++ ) { + NLSF_tmp_Q15[ i ] = silk_LSHIFT16( (opus_int16)pCB_element[ i ], 7 ); + W_tmp_Q9 = pCB_Wght_Q9[ i ]; + res_Q10[ i ] = (opus_int16)silk_RSHIFT( silk_SMULBB( pNLSF_Q15[ i ] - NLSF_tmp_Q15[ i ], W_tmp_Q9 ), 14 ); + W_adj_Q5[ i ] = silk_DIV32_varQ( (opus_int32)pW_Q2[ i ], silk_SMULBB( W_tmp_Q9, W_tmp_Q9 ), 21 ); + } + + /* Unpack entropy table indices and predictor for current CB1 index */ + silk_NLSF_unpack( ec_ix, pred_Q8, psNLSF_CB, ind1 ); + + /* Trellis quantizer */ + RD_Q25[ s ] = silk_NLSF_del_dec_quant( &tempIndices2[ s * MAX_LPC_ORDER ], 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 ); + + /* Add rate for first stage */ + iCDF_ptr = &psNLSF_CB->CB1_iCDF[ ( signalType >> 1 ) * psNLSF_CB->nVectors ]; + if( ind1 == 0 ) { + prob_Q8 = 256 - iCDF_ptr[ ind1 ]; + } else { + prob_Q8 = iCDF_ptr[ ind1 - 1 ] - iCDF_ptr[ ind1 ]; + } + bits_q7 = ( 8 << 7 ) - silk_lin2log( prob_Q8 ); + RD_Q25[ s ] = silk_SMLABB( RD_Q25[ s ], bits_q7, silk_RSHIFT( NLSF_mu_Q20, 2 ) ); + } + + /* Find the lowest rate-distortion error */ + silk_insertion_sort_increasing( RD_Q25, &bestIndex, nSurvivors, 1 ); + + NLSFIndices[ 0 ] = (opus_int8)tempIndices1[ bestIndex ]; + silk_memcpy( &NLSFIndices[ 1 ], &tempIndices2[ bestIndex * MAX_LPC_ORDER ], psNLSF_CB->order * sizeof( opus_int8 ) ); + + /* Decode */ + silk_NLSF_decode( pNLSF_Q15, NLSFIndices, psNLSF_CB ); + + ret = RD_Q25[ 0 ]; + RESTORE_STACK; + return ret; +} diff --git a/extern/opus/silk/NLSF_stabilize.c b/extern/opus/silk/NLSF_stabilize.c new file mode 100644 index 0000000..8f3426b --- /dev/null +++ b/extern/opus/silk/NLSF_stabilize.c @@ -0,0 +1,142 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/* NLSF stabilizer: */ +/* */ +/* - Moves NLSFs further apart if they are too close */ +/* - Moves NLSFs away from borders if they are too close */ +/* - High effort to achieve a modification with minimum */ +/* Euclidean distance to input vector */ +/* - Output are sorted NLSF coefficients */ +/* */ + +#include "SigProc_FIX.h" + +/* Constant Definitions */ +#define MAX_LOOPS 20 + +/* NLSF stabilizer, for a single input data vector */ +void silk_NLSF_stabilize( + opus_int16 *NLSF_Q15, /* I/O Unstable/stabilized normalized LSF vector in Q15 [L] */ + const opus_int16 *NDeltaMin_Q15, /* I Min distance vector, NDeltaMin_Q15[L] must be >= 1 [L+1] */ + const opus_int L /* I Number of NLSF parameters in the input vector */ +) +{ + opus_int i, I=0, k, loops; + opus_int16 center_freq_Q15; + opus_int32 diff_Q15, min_diff_Q15, min_center_Q15, max_center_Q15; + + /* This is necessary to ensure an output within range of a opus_int16 */ + silk_assert( NDeltaMin_Q15[L] >= 1 ); + + for( loops = 0; loops < MAX_LOOPS; loops++ ) { + /**************************/ + /* Find smallest distance */ + /**************************/ + /* First element */ + min_diff_Q15 = NLSF_Q15[0] - NDeltaMin_Q15[0]; + I = 0; + /* Middle elements */ + 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 ) { + min_diff_Q15 = diff_Q15; + I = i; + } + } + /* Last element */ + diff_Q15 = ( 1 << 15 ) - ( NLSF_Q15[L-1] + NDeltaMin_Q15[L] ); + if( diff_Q15 < min_diff_Q15 ) { + min_diff_Q15 = diff_Q15; + I = L; + } + + /***************************************************/ + /* Now check if the smallest distance non-negative */ + /***************************************************/ + if( min_diff_Q15 >= 0 ) { + return; + } + + if( I == 0 ) { + /* Move away from lower limit */ + NLSF_Q15[0] = NDeltaMin_Q15[0]; + + } else if( I == L) { + /* Move away from higher limit */ + NLSF_Q15[L-1] = ( 1 << 15 ) - NDeltaMin_Q15[L]; + + } else { + /* Find the lower extreme for the location of the current center frequency */ + min_center_Q15 = 0; + for( k = 0; k < I; k++ ) { + min_center_Q15 += NDeltaMin_Q15[k]; + } + min_center_Q15 += silk_RSHIFT( NDeltaMin_Q15[I], 1 ); + + /* Find the upper extreme for the location of the current center frequency */ + max_center_Q15 = 1 << 15; + for( k = L; k > I; k-- ) { + max_center_Q15 -= NDeltaMin_Q15[k]; + } + max_center_Q15 -= silk_RSHIFT( NDeltaMin_Q15[I], 1 ); + + /* Move apart, sorted by value, keeping the same center frequency */ + center_freq_Q15 = (opus_int16)silk_LIMIT_32( silk_RSHIFT_ROUND( (opus_int32)NLSF_Q15[I-1] + (opus_int32)NLSF_Q15[I], 1 ), + min_center_Q15, max_center_Q15 ); + NLSF_Q15[I-1] = center_freq_Q15 - silk_RSHIFT( NDeltaMin_Q15[I], 1 ); + NLSF_Q15[I] = NLSF_Q15[I-1] + NDeltaMin_Q15[I]; + } + } + + /* Safe and simple fall back method, which is less ideal than the above */ + if( loops == MAX_LOOPS ) + { + /* Insertion sort (fast for already almost sorted arrays): */ + /* Best case: O(n) for an already sorted array */ + /* Worst case: O(n^2) for an inversely sorted array */ + silk_insertion_sort_increasing_all_values_int16( &NLSF_Q15[0], L ); + + /* First NLSF should be no less than NDeltaMin[0] */ + NLSF_Q15[0] = silk_max_int( NLSF_Q15[0], NDeltaMin_Q15[0] ); + + /* Keep delta_min distance between the NLSFs */ + for( i = 1; i < L; i++ ) + NLSF_Q15[i] = silk_max_int( NLSF_Q15[i], silk_ADD_SAT16( NLSF_Q15[i-1], NDeltaMin_Q15[i] ) ); + + /* Last NLSF should be no higher than 1 - NDeltaMin[L] */ + NLSF_Q15[L-1] = silk_min_int( NLSF_Q15[L-1], (1<<15) - NDeltaMin_Q15[L] ); + + /* Keep NDeltaMin distance between the NLSFs */ + for( i = L-2; i >= 0; i-- ) + NLSF_Q15[i] = silk_min_int( NLSF_Q15[i], NLSF_Q15[i+1] - NDeltaMin_Q15[i+1] ); + } +} diff --git a/extern/opus/silk/NLSF_unpack.c b/extern/opus/silk/NLSF_unpack.c new file mode 100644 index 0000000..17bd23f --- /dev/null +++ b/extern/opus/silk/NLSF_unpack.c @@ -0,0 +1,55 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/* Unpack predictor values and indices for entropy coding tables */ +void silk_NLSF_unpack( + opus_int16 ec_ix[], /* O Indices to entropy tables [ LPC_ORDER ] */ + opus_uint8 pred_Q8[], /* O LSF predictor [ LPC_ORDER ] */ + const silk_NLSF_CB_struct *psNLSF_CB, /* I Codebook object */ + const opus_int CB1_index /* I Index of vector in first LSF codebook */ +) +{ + opus_int i; + opus_uint8 entry; + const opus_uint8 *ec_sel_ptr; + + ec_sel_ptr = &psNLSF_CB->ec_sel[ CB1_index * psNLSF_CB->order / 2 ]; + for( i = 0; i < psNLSF_CB->order; i += 2 ) { + entry = *ec_sel_ptr++; + ec_ix [ i ] = silk_SMULBB( silk_RSHIFT( entry, 1 ) & 7, 2 * NLSF_QUANT_MAX_AMPLITUDE + 1 ); + pred_Q8[ i ] = psNLSF_CB->pred_Q8[ i + ( entry & 1 ) * ( psNLSF_CB->order - 1 ) ]; + ec_ix [ i + 1 ] = silk_SMULBB( silk_RSHIFT( entry, 5 ) & 7, 2 * NLSF_QUANT_MAX_AMPLITUDE + 1 ); + pred_Q8[ i + 1 ] = psNLSF_CB->pred_Q8[ i + ( silk_RSHIFT( entry, 4 ) & 1 ) * ( psNLSF_CB->order - 1 ) + 1 ]; + } +} + diff --git a/extern/opus/silk/NSQ.c b/extern/opus/silk/NSQ.c new file mode 100644 index 0000000..1d64d8e --- /dev/null +++ b/extern/opus/silk/NSQ.c @@ -0,0 +1,437 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" +#include "stack_alloc.h" +#include "NSQ.h" + + +static OPUS_INLINE void silk_nsq_scale_states( + const silk_encoder_state *psEncC, /* I Encoder State */ + silk_nsq_state *NSQ, /* I/O NSQ state */ + const opus_int16 x16[], /* I input */ + opus_int32 x_sc_Q10[], /* O input scaled with 1/Gain */ + const opus_int16 sLTP[], /* I re-whitened LTP state in Q0 */ + opus_int32 sLTP_Q15[], /* O LTP state matching scaled input */ + opus_int subfr, /* I subframe number */ + const opus_int LTP_scale_Q14, /* I */ + const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lag */ + const opus_int signal_type /* I Signal type */ +); + +#if !defined(OPUS_X86_MAY_HAVE_SSE4_1) +static OPUS_INLINE void silk_noise_shape_quantizer( + silk_nsq_state *NSQ, /* I/O NSQ state */ + opus_int signalType, /* I Signal type */ + const opus_int32 x_sc_Q10[], /* I */ + opus_int8 pulses[], /* O */ + opus_int16 xq[], /* O */ + opus_int32 sLTP_Q15[], /* I/O LTP state */ + const opus_int16 a_Q12[], /* I Short term prediction coefs */ + const opus_int16 b_Q14[], /* I Long term prediction coefs */ + const opus_int16 AR_shp_Q13[], /* I Noise shaping AR coefs */ + opus_int lag, /* I Pitch lag */ + opus_int32 HarmShapeFIRPacked_Q14, /* I */ + opus_int Tilt_Q14, /* I Spectral tilt */ + opus_int32 LF_shp_Q14, /* I */ + opus_int32 Gain_Q16, /* I */ + opus_int Lambda_Q10, /* I */ + opus_int offset_Q10, /* I */ + opus_int length, /* I Input length */ + opus_int shapingLPCOrder, /* I Noise shaping AR filter order */ + opus_int predictLPCOrder, /* I Prediction filter order */ + int arch /* I Architecture */ +); +#endif + +void silk_NSQ_c +( + const silk_encoder_state *psEncC, /* I Encoder State */ + silk_nsq_state *NSQ, /* I/O NSQ state */ + SideInfoIndices *psIndices, /* I/O Quantization Indices */ + const opus_int16 x16[], /* I Input */ + opus_int8 pulses[], /* O Quantized pulse signal */ + const opus_int16 PredCoef_Q12[ 2 * MAX_LPC_ORDER ], /* I Short term prediction coefs */ + const opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ], /* I Long term prediction coefs */ + const opus_int16 AR_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ], /* I Noise shaping coefs */ + const opus_int HarmShapeGain_Q14[ MAX_NB_SUBFR ], /* I Long term shaping coefs */ + const opus_int Tilt_Q14[ MAX_NB_SUBFR ], /* I Spectral tilt */ + const opus_int32 LF_shp_Q14[ MAX_NB_SUBFR ], /* I Low frequency shaping coefs */ + const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I Quantization step sizes */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lags */ + const opus_int Lambda_Q10, /* I Rate/distortion tradeoff */ + const opus_int LTP_scale_Q14 /* I LTP state scaling */ +) +{ + opus_int k, lag, start_idx, LSF_interpolation_flag; + const opus_int16 *A_Q12, *B_Q14, *AR_shp_Q13; + opus_int16 *pxq; + VARDECL( opus_int32, sLTP_Q15 ); + VARDECL( opus_int16, sLTP ); + opus_int32 HarmShapeFIRPacked_Q14; + opus_int offset_Q10; + VARDECL( opus_int32, x_sc_Q10 ); + SAVE_STACK; + + NSQ->rand_seed = psIndices->Seed; + + /* Set unvoiced lag to the previous one, overwrite later for voiced */ + lag = NSQ->lagPrev; + + silk_assert( NSQ->prev_gain_Q16 != 0 ); + + offset_Q10 = silk_Quantization_Offsets_Q10[ psIndices->signalType >> 1 ][ psIndices->quantOffsetType ]; + + if( psIndices->NLSFInterpCoef_Q2 == 4 ) { + LSF_interpolation_flag = 0; + } else { + LSF_interpolation_flag = 1; + } + + ALLOC( sLTP_Q15, psEncC->ltp_mem_length + psEncC->frame_length, opus_int32 ); + ALLOC( sLTP, psEncC->ltp_mem_length + psEncC->frame_length, opus_int16 ); + ALLOC( x_sc_Q10, psEncC->subfr_length, opus_int32 ); + /* Set up pointers to start of sub frame */ + NSQ->sLTP_shp_buf_idx = psEncC->ltp_mem_length; + NSQ->sLTP_buf_idx = psEncC->ltp_mem_length; + pxq = &NSQ->xq[ psEncC->ltp_mem_length ]; + for( k = 0; k < psEncC->nb_subfr; k++ ) { + A_Q12 = &PredCoef_Q12[ (( k >> 1 ) | ( 1 - LSF_interpolation_flag )) * MAX_LPC_ORDER ]; + B_Q14 = <PCoef_Q14[ k * LTP_ORDER ]; + AR_shp_Q13 = &AR_Q13[ k * MAX_SHAPE_LPC_ORDER ]; + + /* Noise shape parameters */ + silk_assert( HarmShapeGain_Q14[ k ] >= 0 ); + HarmShapeFIRPacked_Q14 = silk_RSHIFT( HarmShapeGain_Q14[ k ], 2 ); + HarmShapeFIRPacked_Q14 |= silk_LSHIFT( (opus_int32)silk_RSHIFT( HarmShapeGain_Q14[ k ], 1 ), 16 ); + + NSQ->rewhite_flag = 0; + if( psIndices->signalType == TYPE_VOICED ) { + /* Voiced */ + lag = pitchL[ k ]; + + /* Re-whitening */ + if( ( k & ( 3 - silk_LSHIFT( LSF_interpolation_flag, 1 ) ) ) == 0 ) { + /* Rewhiten with new A coefs */ + start_idx = psEncC->ltp_mem_length - lag - psEncC->predictLPCOrder - LTP_ORDER / 2; + celt_assert( start_idx > 0 ); + + silk_LPC_analysis_filter( &sLTP[ start_idx ], &NSQ->xq[ start_idx + k * psEncC->subfr_length ], + A_Q12, psEncC->ltp_mem_length - start_idx, psEncC->predictLPCOrder, psEncC->arch ); + + NSQ->rewhite_flag = 1; + NSQ->sLTP_buf_idx = psEncC->ltp_mem_length; + } + } + + silk_nsq_scale_states( psEncC, NSQ, x16, x_sc_Q10, sLTP, sLTP_Q15, k, LTP_scale_Q14, Gains_Q16, pitchL, psIndices->signalType ); + + silk_noise_shape_quantizer( NSQ, psIndices->signalType, x_sc_Q10, pulses, pxq, sLTP_Q15, A_Q12, B_Q14, + 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, psEncC->arch ); + + x16 += psEncC->subfr_length; + pulses += psEncC->subfr_length; + pxq += psEncC->subfr_length; + } + + /* Update lagPrev for next frame */ + NSQ->lagPrev = pitchL[ psEncC->nb_subfr - 1 ]; + + /* Save quantized speech and noise shaping signals */ + silk_memmove( NSQ->xq, &NSQ->xq[ psEncC->frame_length ], psEncC->ltp_mem_length * sizeof( opus_int16 ) ); + silk_memmove( NSQ->sLTP_shp_Q14, &NSQ->sLTP_shp_Q14[ psEncC->frame_length ], psEncC->ltp_mem_length * sizeof( opus_int32 ) ); + RESTORE_STACK; +} + +/***********************************/ +/* silk_noise_shape_quantizer */ +/***********************************/ + +#if !defined(OPUS_X86_MAY_HAVE_SSE4_1) +static OPUS_INLINE +#endif +void silk_noise_shape_quantizer( + silk_nsq_state *NSQ, /* I/O NSQ state */ + opus_int signalType, /* I Signal type */ + const opus_int32 x_sc_Q10[], /* I */ + opus_int8 pulses[], /* O */ + opus_int16 xq[], /* O */ + opus_int32 sLTP_Q15[], /* I/O LTP state */ + const opus_int16 a_Q12[], /* I Short term prediction coefs */ + const opus_int16 b_Q14[], /* I Long term prediction coefs */ + const opus_int16 AR_shp_Q13[], /* I Noise shaping AR coefs */ + opus_int lag, /* I Pitch lag */ + opus_int32 HarmShapeFIRPacked_Q14, /* I */ + opus_int Tilt_Q14, /* I Spectral tilt */ + opus_int32 LF_shp_Q14, /* I */ + opus_int32 Gain_Q16, /* I */ + opus_int Lambda_Q10, /* I */ + opus_int offset_Q10, /* I */ + opus_int length, /* I Input length */ + opus_int shapingLPCOrder, /* I Noise shaping AR filter order */ + opus_int predictLPCOrder, /* I Prediction filter order */ + int arch /* I Architecture */ +) +{ + opus_int i; + opus_int32 LTP_pred_Q13, LPC_pred_Q10, n_AR_Q12, n_LTP_Q13; + opus_int32 n_LF_Q12, r_Q10, rr_Q10, q1_Q0, q1_Q10, q2_Q10, rd1_Q20, rd2_Q20; + opus_int32 exc_Q14, LPC_exc_Q14, xq_Q14, Gain_Q10; + opus_int32 tmp1, tmp2, sLF_AR_shp_Q14; + opus_int32 *psLPC_Q14, *shp_lag_ptr, *pred_lag_ptr; +#ifdef silk_short_prediction_create_arch_coef + opus_int32 a_Q12_arch[MAX_LPC_ORDER]; +#endif + + shp_lag_ptr = &NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - lag + HARM_SHAPE_FIR_TAPS / 2 ]; + pred_lag_ptr = &sLTP_Q15[ NSQ->sLTP_buf_idx - lag + LTP_ORDER / 2 ]; + Gain_Q10 = silk_RSHIFT( Gain_Q16, 6 ); + + /* Set up short term AR state */ + psLPC_Q14 = &NSQ->sLPC_Q14[ NSQ_LPC_BUF_LENGTH - 1 ]; + +#ifdef silk_short_prediction_create_arch_coef + silk_short_prediction_create_arch_coef(a_Q12_arch, a_Q12, predictLPCOrder); +#endif + + for( i = 0; i < length; i++ ) { + /* Generate dither */ + NSQ->rand_seed = silk_RAND( NSQ->rand_seed ); + + /* Short-term prediction */ + LPC_pred_Q10 = silk_noise_shape_quantizer_short_prediction(psLPC_Q14, a_Q12, a_Q12_arch, predictLPCOrder, arch); + + /* Long-term prediction */ + if( signalType == TYPE_VOICED ) { + /* Unrolled loop */ + /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */ + LTP_pred_Q13 = 2; + LTP_pred_Q13 = silk_SMLAWB( LTP_pred_Q13, pred_lag_ptr[ 0 ], b_Q14[ 0 ] ); + LTP_pred_Q13 = silk_SMLAWB( LTP_pred_Q13, pred_lag_ptr[ -1 ], b_Q14[ 1 ] ); + LTP_pred_Q13 = silk_SMLAWB( LTP_pred_Q13, pred_lag_ptr[ -2 ], b_Q14[ 2 ] ); + LTP_pred_Q13 = silk_SMLAWB( LTP_pred_Q13, pred_lag_ptr[ -3 ], b_Q14[ 3 ] ); + LTP_pred_Q13 = silk_SMLAWB( LTP_pred_Q13, pred_lag_ptr[ -4 ], b_Q14[ 4 ] ); + pred_lag_ptr++; + } else { + LTP_pred_Q13 = 0; + } + + /* Noise shape feedback */ + celt_assert( ( shapingLPCOrder & 1 ) == 0 ); /* check that order is even */ + n_AR_Q12 = silk_NSQ_noise_shape_feedback_loop(&NSQ->sDiff_shp_Q14, NSQ->sAR2_Q14, AR_shp_Q13, shapingLPCOrder, arch); + + n_AR_Q12 = silk_SMLAWB( n_AR_Q12, NSQ->sLF_AR_shp_Q14, Tilt_Q14 ); + + n_LF_Q12 = silk_SMULWB( NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - 1 ], LF_shp_Q14 ); + n_LF_Q12 = silk_SMLAWT( n_LF_Q12, NSQ->sLF_AR_shp_Q14, LF_shp_Q14 ); + + celt_assert( lag > 0 || signalType != TYPE_VOICED ); + + /* Combine prediction and noise shaping signals */ + tmp1 = silk_SUB32( silk_LSHIFT32( LPC_pred_Q10, 2 ), n_AR_Q12 ); /* Q12 */ + tmp1 = silk_SUB32( tmp1, n_LF_Q12 ); /* Q12 */ + if( lag > 0 ) { + /* Symmetric, packed FIR coefficients */ + n_LTP_Q13 = silk_SMULWB( silk_ADD32( shp_lag_ptr[ 0 ], shp_lag_ptr[ -2 ] ), HarmShapeFIRPacked_Q14 ); + n_LTP_Q13 = silk_SMLAWT( n_LTP_Q13, shp_lag_ptr[ -1 ], HarmShapeFIRPacked_Q14 ); + n_LTP_Q13 = silk_LSHIFT( n_LTP_Q13, 1 ); + shp_lag_ptr++; + + tmp2 = silk_SUB32( LTP_pred_Q13, n_LTP_Q13 ); /* Q13 */ + tmp1 = silk_ADD_LSHIFT32( tmp2, tmp1, 1 ); /* Q13 */ + tmp1 = silk_RSHIFT_ROUND( tmp1, 3 ); /* Q10 */ + } else { + tmp1 = silk_RSHIFT_ROUND( tmp1, 2 ); /* Q10 */ + } + + r_Q10 = silk_SUB32( x_sc_Q10[ i ], tmp1 ); /* residual error Q10 */ + + /* Flip sign depending on dither */ + if( NSQ->rand_seed < 0 ) { + r_Q10 = -r_Q10; + } + r_Q10 = silk_LIMIT_32( r_Q10, -(31 << 10), 30 << 10 ); + + /* Find two quantization level candidates and measure their rate-distortion */ + q1_Q10 = silk_SUB32( r_Q10, offset_Q10 ); + q1_Q0 = silk_RSHIFT( q1_Q10, 10 ); + if (Lambda_Q10 > 2048) { + /* For aggressive RDO, the bias becomes more than one pulse. */ + int rdo_offset = Lambda_Q10/2 - 512; + if (q1_Q10 > rdo_offset) { + q1_Q0 = silk_RSHIFT( q1_Q10 - rdo_offset, 10 ); + } else if (q1_Q10 < -rdo_offset) { + q1_Q0 = silk_RSHIFT( q1_Q10 + rdo_offset, 10 ); + } else if (q1_Q10 < 0) { + q1_Q0 = -1; + } else { + q1_Q0 = 0; + } + } + if( q1_Q0 > 0 ) { + q1_Q10 = silk_SUB32( silk_LSHIFT( q1_Q0, 10 ), QUANT_LEVEL_ADJUST_Q10 ); + q1_Q10 = silk_ADD32( q1_Q10, offset_Q10 ); + q2_Q10 = silk_ADD32( q1_Q10, 1024 ); + rd1_Q20 = silk_SMULBB( q1_Q10, Lambda_Q10 ); + rd2_Q20 = silk_SMULBB( q2_Q10, Lambda_Q10 ); + } else if( q1_Q0 == 0 ) { + q1_Q10 = offset_Q10; + q2_Q10 = silk_ADD32( q1_Q10, 1024 - QUANT_LEVEL_ADJUST_Q10 ); + rd1_Q20 = silk_SMULBB( q1_Q10, Lambda_Q10 ); + rd2_Q20 = silk_SMULBB( q2_Q10, Lambda_Q10 ); + } else if( q1_Q0 == -1 ) { + q2_Q10 = offset_Q10; + q1_Q10 = silk_SUB32( q2_Q10, 1024 - QUANT_LEVEL_ADJUST_Q10 ); + rd1_Q20 = silk_SMULBB( -q1_Q10, Lambda_Q10 ); + rd2_Q20 = silk_SMULBB( q2_Q10, Lambda_Q10 ); + } else { /* Q1_Q0 < -1 */ + q1_Q10 = silk_ADD32( silk_LSHIFT( q1_Q0, 10 ), QUANT_LEVEL_ADJUST_Q10 ); + q1_Q10 = silk_ADD32( q1_Q10, offset_Q10 ); + q2_Q10 = silk_ADD32( q1_Q10, 1024 ); + rd1_Q20 = silk_SMULBB( -q1_Q10, Lambda_Q10 ); + rd2_Q20 = silk_SMULBB( -q2_Q10, Lambda_Q10 ); + } + rr_Q10 = silk_SUB32( r_Q10, q1_Q10 ); + rd1_Q20 = silk_SMLABB( rd1_Q20, rr_Q10, rr_Q10 ); + rr_Q10 = silk_SUB32( r_Q10, q2_Q10 ); + rd2_Q20 = silk_SMLABB( rd2_Q20, rr_Q10, rr_Q10 ); + + if( rd2_Q20 < rd1_Q20 ) { + q1_Q10 = q2_Q10; + } + + pulses[ i ] = (opus_int8)silk_RSHIFT_ROUND( q1_Q10, 10 ); + + /* Excitation */ + exc_Q14 = silk_LSHIFT( q1_Q10, 4 ); + if ( NSQ->rand_seed < 0 ) { + exc_Q14 = -exc_Q14; + } + + /* Add predictions */ + LPC_exc_Q14 = silk_ADD_LSHIFT32( exc_Q14, LTP_pred_Q13, 1 ); + xq_Q14 = silk_ADD_LSHIFT32( LPC_exc_Q14, LPC_pred_Q10, 4 ); + + /* Scale XQ back to normal level before saving */ + xq[ i ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( silk_SMULWW( xq_Q14, Gain_Q10 ), 8 ) ); + + /* Update states */ + psLPC_Q14++; + *psLPC_Q14 = xq_Q14; + NSQ->sDiff_shp_Q14 = silk_SUB_LSHIFT32( xq_Q14, x_sc_Q10[ i ], 4 ); + sLF_AR_shp_Q14 = silk_SUB_LSHIFT32( NSQ->sDiff_shp_Q14, n_AR_Q12, 2 ); + NSQ->sLF_AR_shp_Q14 = sLF_AR_shp_Q14; + + NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx ] = silk_SUB_LSHIFT32( sLF_AR_shp_Q14, n_LF_Q12, 2 ); + sLTP_Q15[ NSQ->sLTP_buf_idx ] = silk_LSHIFT( LPC_exc_Q14, 1 ); + NSQ->sLTP_shp_buf_idx++; + NSQ->sLTP_buf_idx++; + + /* Make dither dependent on quantized signal */ + NSQ->rand_seed = silk_ADD32_ovflw( NSQ->rand_seed, pulses[ i ] ); + } + + /* Update LPC synth buffer */ + silk_memcpy( NSQ->sLPC_Q14, &NSQ->sLPC_Q14[ length ], NSQ_LPC_BUF_LENGTH * sizeof( opus_int32 ) ); +} + +static OPUS_INLINE void silk_nsq_scale_states( + const silk_encoder_state *psEncC, /* I Encoder State */ + silk_nsq_state *NSQ, /* I/O NSQ state */ + const opus_int16 x16[], /* I input */ + opus_int32 x_sc_Q10[], /* O input scaled with 1/Gain */ + const opus_int16 sLTP[], /* I re-whitened LTP state in Q0 */ + opus_int32 sLTP_Q15[], /* O LTP state matching scaled input */ + opus_int subfr, /* I subframe number */ + const opus_int LTP_scale_Q14, /* I */ + const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lag */ + const opus_int signal_type /* I Signal type */ +) +{ + opus_int i, lag; + opus_int32 gain_adj_Q16, inv_gain_Q31, inv_gain_Q26; + + lag = pitchL[ subfr ]; + inv_gain_Q31 = silk_INVERSE32_varQ( silk_max( Gains_Q16[ subfr ], 1 ), 47 ); + silk_assert( inv_gain_Q31 != 0 ); + + /* Scale input */ + inv_gain_Q26 = silk_RSHIFT_ROUND( inv_gain_Q31, 5 ); + for( i = 0; i < psEncC->subfr_length; i++ ) { + x_sc_Q10[ i ] = silk_SMULWW( x16[ i ], inv_gain_Q26 ); + } + + /* After rewhitening the LTP state is un-scaled, so scale with inv_gain_Q16 */ + if( NSQ->rewhite_flag ) { + if( subfr == 0 ) { + /* Do LTP downscaling */ + inv_gain_Q31 = silk_LSHIFT( silk_SMULWB( inv_gain_Q31, LTP_scale_Q14 ), 2 ); + } + for( i = NSQ->sLTP_buf_idx - lag - LTP_ORDER / 2; i < NSQ->sLTP_buf_idx; i++ ) { + silk_assert( i < MAX_FRAME_LENGTH ); + sLTP_Q15[ i ] = silk_SMULWB( inv_gain_Q31, sLTP[ i ] ); + } + } + + /* Adjust for changing gain */ + if( Gains_Q16[ subfr ] != NSQ->prev_gain_Q16 ) { + gain_adj_Q16 = silk_DIV32_varQ( NSQ->prev_gain_Q16, Gains_Q16[ subfr ], 16 ); + + /* Scale long-term shaping state */ + for( i = NSQ->sLTP_shp_buf_idx - psEncC->ltp_mem_length; i < NSQ->sLTP_shp_buf_idx; i++ ) { + NSQ->sLTP_shp_Q14[ i ] = silk_SMULWW( gain_adj_Q16, NSQ->sLTP_shp_Q14[ i ] ); + } + + /* Scale long-term prediction state */ + if( signal_type == TYPE_VOICED && NSQ->rewhite_flag == 0 ) { + for( i = NSQ->sLTP_buf_idx - lag - LTP_ORDER / 2; i < NSQ->sLTP_buf_idx; i++ ) { + sLTP_Q15[ i ] = silk_SMULWW( gain_adj_Q16, sLTP_Q15[ i ] ); + } + } + + NSQ->sLF_AR_shp_Q14 = silk_SMULWW( gain_adj_Q16, NSQ->sLF_AR_shp_Q14 ); + NSQ->sDiff_shp_Q14 = silk_SMULWW( gain_adj_Q16, NSQ->sDiff_shp_Q14 ); + + /* Scale short-term prediction and shaping states */ + for( i = 0; i < NSQ_LPC_BUF_LENGTH; i++ ) { + NSQ->sLPC_Q14[ i ] = silk_SMULWW( gain_adj_Q16, NSQ->sLPC_Q14[ i ] ); + } + for( i = 0; i < MAX_SHAPE_LPC_ORDER; i++ ) { + NSQ->sAR2_Q14[ i ] = silk_SMULWW( gain_adj_Q16, NSQ->sAR2_Q14[ i ] ); + } + + /* Save inverse gain */ + NSQ->prev_gain_Q16 = Gains_Q16[ subfr ]; + } +} diff --git a/extern/opus/silk/NSQ.h b/extern/opus/silk/NSQ.h new file mode 100644 index 0000000..971832f --- /dev/null +++ b/extern/opus/silk/NSQ.h @@ -0,0 +1,101 @@ +/*********************************************************************** +Copyright (c) 2014 Vidyo. +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ +#ifndef SILK_NSQ_H +#define SILK_NSQ_H + +#include "SigProc_FIX.h" + +#undef silk_short_prediction_create_arch_coef + +static OPUS_INLINE opus_int32 silk_noise_shape_quantizer_short_prediction_c(const opus_int32 *buf32, const opus_int16 *coef16, opus_int order) +{ + opus_int32 out; + silk_assert( order == 10 || order == 16 ); + + /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */ + out = silk_RSHIFT( order, 1 ); + out = silk_SMLAWB( out, buf32[ 0 ], coef16[ 0 ] ); + out = silk_SMLAWB( out, buf32[ -1 ], coef16[ 1 ] ); + out = silk_SMLAWB( out, buf32[ -2 ], coef16[ 2 ] ); + out = silk_SMLAWB( out, buf32[ -3 ], coef16[ 3 ] ); + out = silk_SMLAWB( out, buf32[ -4 ], coef16[ 4 ] ); + out = silk_SMLAWB( out, buf32[ -5 ], coef16[ 5 ] ); + out = silk_SMLAWB( out, buf32[ -6 ], coef16[ 6 ] ); + out = silk_SMLAWB( out, buf32[ -7 ], coef16[ 7 ] ); + out = silk_SMLAWB( out, buf32[ -8 ], coef16[ 8 ] ); + out = silk_SMLAWB( out, buf32[ -9 ], coef16[ 9 ] ); + + if( order == 16 ) + { + out = silk_SMLAWB( out, buf32[ -10 ], coef16[ 10 ] ); + out = silk_SMLAWB( out, buf32[ -11 ], coef16[ 11 ] ); + out = silk_SMLAWB( out, buf32[ -12 ], coef16[ 12 ] ); + out = silk_SMLAWB( out, buf32[ -13 ], coef16[ 13 ] ); + out = silk_SMLAWB( out, buf32[ -14 ], coef16[ 14 ] ); + out = silk_SMLAWB( out, buf32[ -15 ], coef16[ 15 ] ); + } + return out; +} + +#define silk_noise_shape_quantizer_short_prediction(in, coef, coefRev, order, arch) ((void)arch,silk_noise_shape_quantizer_short_prediction_c(in, coef, order)) + +static OPUS_INLINE opus_int32 silk_NSQ_noise_shape_feedback_loop_c(const opus_int32 *data0, opus_int32 *data1, const opus_int16 *coef, opus_int order) +{ + opus_int32 out; + opus_int32 tmp1, tmp2; + opus_int j; + + tmp2 = data0[0]; + tmp1 = data1[0]; + data1[0] = tmp2; + + out = silk_RSHIFT(order, 1); + out = silk_SMLAWB(out, tmp2, coef[0]); + + for (j = 2; j < order; j += 2) { + tmp2 = data1[j - 1]; + data1[j - 1] = tmp1; + out = silk_SMLAWB(out, tmp1, coef[j - 1]); + tmp1 = data1[j + 0]; + data1[j + 0] = tmp2; + out = silk_SMLAWB(out, tmp2, coef[j]); + } + data1[order - 1] = tmp1; + out = silk_SMLAWB(out, tmp1, coef[order - 1]); + /* Q11 -> Q12 */ + out = silk_LSHIFT32( out, 1 ); + return out; +} + +#define silk_NSQ_noise_shape_feedback_loop(data0, data1, coef, order, arch) ((void)arch,silk_NSQ_noise_shape_feedback_loop_c(data0, data1, coef, order)) + +#if defined(OPUS_ARM_MAY_HAVE_NEON_INTR) +#include "arm/NSQ_neon.h" +#endif + +#endif /* SILK_NSQ_H */ diff --git a/extern/opus/silk/NSQ_del_dec.c b/extern/opus/silk/NSQ_del_dec.c new file mode 100644 index 0000000..3fd9fa0 --- /dev/null +++ b/extern/opus/silk/NSQ_del_dec.c @@ -0,0 +1,733 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" +#include "stack_alloc.h" +#include "NSQ.h" + + +typedef struct { + opus_int32 sLPC_Q14[ MAX_SUB_FRAME_LENGTH + NSQ_LPC_BUF_LENGTH ]; + opus_int32 RandState[ DECISION_DELAY ]; + opus_int32 Q_Q10[ DECISION_DELAY ]; + opus_int32 Xq_Q14[ DECISION_DELAY ]; + opus_int32 Pred_Q15[ DECISION_DELAY ]; + opus_int32 Shape_Q14[ DECISION_DELAY ]; + opus_int32 sAR2_Q14[ MAX_SHAPE_LPC_ORDER ]; + opus_int32 LF_AR_Q14; + opus_int32 Diff_Q14; + opus_int32 Seed; + opus_int32 SeedInit; + opus_int32 RD_Q10; +} NSQ_del_dec_struct; + +typedef struct { + opus_int32 Q_Q10; + opus_int32 RD_Q10; + opus_int32 xq_Q14; + opus_int32 LF_AR_Q14; + opus_int32 Diff_Q14; + opus_int32 sLTP_shp_Q14; + opus_int32 LPC_exc_Q14; +} NSQ_sample_struct; + +typedef NSQ_sample_struct NSQ_sample_pair[ 2 ]; + +#if defined(MIPSr1_ASM) +#include "mips/NSQ_del_dec_mipsr1.h" +#endif +static OPUS_INLINE void silk_nsq_del_dec_scale_states( + const silk_encoder_state *psEncC, /* I Encoder State */ + silk_nsq_state *NSQ, /* I/O NSQ state */ + NSQ_del_dec_struct psDelDec[], /* I/O Delayed decision states */ + const opus_int16 x16[], /* I Input */ + opus_int32 x_sc_Q10[], /* O Input scaled with 1/Gain in Q10 */ + const opus_int16 sLTP[], /* I Re-whitened LTP state in Q0 */ + opus_int32 sLTP_Q15[], /* O LTP state matching scaled input */ + opus_int subfr, /* I Subframe number */ + opus_int nStatesDelayedDecision, /* I Number of del dec states */ + const opus_int LTP_scale_Q14, /* I LTP state scaling */ + const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lag */ + const opus_int signal_type, /* I Signal type */ + const opus_int decisionDelay /* I Decision delay */ +); + +/******************************************/ +/* Noise shape quantizer for one subframe */ +/******************************************/ +static OPUS_INLINE void silk_noise_shape_quantizer_del_dec( + silk_nsq_state *NSQ, /* I/O NSQ state */ + NSQ_del_dec_struct psDelDec[], /* I/O Delayed decision states */ + opus_int signalType, /* I Signal type */ + const opus_int32 x_Q10[], /* I */ + opus_int8 pulses[], /* O */ + opus_int16 xq[], /* O */ + opus_int32 sLTP_Q15[], /* I/O LTP filter state */ + opus_int32 delayedGain_Q10[], /* I/O Gain delay buffer */ + const opus_int16 a_Q12[], /* I Short term prediction coefs */ + const opus_int16 b_Q14[], /* I Long term prediction coefs */ + const opus_int16 AR_shp_Q13[], /* I Noise shaping coefs */ + opus_int lag, /* I Pitch lag */ + opus_int32 HarmShapeFIRPacked_Q14, /* I */ + opus_int Tilt_Q14, /* I Spectral tilt */ + opus_int32 LF_shp_Q14, /* I */ + opus_int32 Gain_Q16, /* I */ + opus_int Lambda_Q10, /* I */ + opus_int offset_Q10, /* I */ + opus_int length, /* I Input length */ + opus_int subfr, /* I Subframe number */ + opus_int shapingLPCOrder, /* I Shaping LPC filter order */ + opus_int predictLPCOrder, /* I Prediction filter order */ + opus_int warping_Q16, /* I */ + opus_int nStatesDelayedDecision, /* I Number of states in decision tree */ + opus_int *smpl_buf_idx, /* I/O Index to newest samples in buffers */ + opus_int decisionDelay, /* I */ + int arch /* I */ +); + +void silk_NSQ_del_dec_c( + const silk_encoder_state *psEncC, /* I Encoder State */ + silk_nsq_state *NSQ, /* I/O NSQ state */ + SideInfoIndices *psIndices, /* I/O Quantization Indices */ + const opus_int16 x16[], /* I Input */ + opus_int8 pulses[], /* O Quantized pulse signal */ + const opus_int16 PredCoef_Q12[ 2 * MAX_LPC_ORDER ], /* I Short term prediction coefs */ + const opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ], /* I Long term prediction coefs */ + const opus_int16 AR_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ], /* I Noise shaping coefs */ + const opus_int HarmShapeGain_Q14[ MAX_NB_SUBFR ], /* I Long term shaping coefs */ + const opus_int Tilt_Q14[ MAX_NB_SUBFR ], /* I Spectral tilt */ + const opus_int32 LF_shp_Q14[ MAX_NB_SUBFR ], /* I Low frequency shaping coefs */ + const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I Quantization step sizes */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lags */ + const opus_int Lambda_Q10, /* I Rate/distortion tradeoff */ + const opus_int LTP_scale_Q14 /* I LTP state scaling */ +) +{ + opus_int i, k, lag, start_idx, LSF_interpolation_flag, Winner_ind, subfr; + opus_int last_smple_idx, smpl_buf_idx, decisionDelay; + const opus_int16 *A_Q12, *B_Q14, *AR_shp_Q13; + opus_int16 *pxq; + VARDECL( opus_int32, sLTP_Q15 ); + VARDECL( opus_int16, sLTP ); + opus_int32 HarmShapeFIRPacked_Q14; + opus_int offset_Q10; + opus_int32 RDmin_Q10, Gain_Q10; + VARDECL( opus_int32, x_sc_Q10 ); + VARDECL( opus_int32, delayedGain_Q10 ); + VARDECL( NSQ_del_dec_struct, psDelDec ); + NSQ_del_dec_struct *psDD; + SAVE_STACK; + + /* Set unvoiced lag to the previous one, overwrite later for voiced */ + lag = NSQ->lagPrev; + + silk_assert( NSQ->prev_gain_Q16 != 0 ); + + /* Initialize delayed decision states */ + ALLOC( psDelDec, psEncC->nStatesDelayedDecision, NSQ_del_dec_struct ); + silk_memset( psDelDec, 0, psEncC->nStatesDelayedDecision * sizeof( NSQ_del_dec_struct ) ); + for( k = 0; k < psEncC->nStatesDelayedDecision; k++ ) { + psDD = &psDelDec[ k ]; + psDD->Seed = ( k + psIndices->Seed ) & 3; + psDD->SeedInit = psDD->Seed; + psDD->RD_Q10 = 0; + psDD->LF_AR_Q14 = NSQ->sLF_AR_shp_Q14; + psDD->Diff_Q14 = NSQ->sDiff_shp_Q14; + psDD->Shape_Q14[ 0 ] = NSQ->sLTP_shp_Q14[ psEncC->ltp_mem_length - 1 ]; + silk_memcpy( psDD->sLPC_Q14, NSQ->sLPC_Q14, NSQ_LPC_BUF_LENGTH * sizeof( opus_int32 ) ); + silk_memcpy( psDD->sAR2_Q14, NSQ->sAR2_Q14, sizeof( NSQ->sAR2_Q14 ) ); + } + + offset_Q10 = silk_Quantization_Offsets_Q10[ psIndices->signalType >> 1 ][ psIndices->quantOffsetType ]; + smpl_buf_idx = 0; /* index of oldest samples */ + + decisionDelay = silk_min_int( DECISION_DELAY, psEncC->subfr_length ); + + /* For voiced frames limit the decision delay to lower than the pitch lag */ + if( psIndices->signalType == TYPE_VOICED ) { + for( k = 0; k < psEncC->nb_subfr; k++ ) { + decisionDelay = silk_min_int( decisionDelay, pitchL[ k ] - LTP_ORDER / 2 - 1 ); + } + } else { + if( lag > 0 ) { + decisionDelay = silk_min_int( decisionDelay, lag - LTP_ORDER / 2 - 1 ); + } + } + + if( psIndices->NLSFInterpCoef_Q2 == 4 ) { + LSF_interpolation_flag = 0; + } else { + LSF_interpolation_flag = 1; + } + + ALLOC( sLTP_Q15, psEncC->ltp_mem_length + psEncC->frame_length, opus_int32 ); + ALLOC( sLTP, psEncC->ltp_mem_length + psEncC->frame_length, opus_int16 ); + ALLOC( x_sc_Q10, psEncC->subfr_length, opus_int32 ); + ALLOC( delayedGain_Q10, DECISION_DELAY, opus_int32 ); + /* Set up pointers to start of sub frame */ + pxq = &NSQ->xq[ psEncC->ltp_mem_length ]; + NSQ->sLTP_shp_buf_idx = psEncC->ltp_mem_length; + NSQ->sLTP_buf_idx = psEncC->ltp_mem_length; + subfr = 0; + for( k = 0; k < psEncC->nb_subfr; k++ ) { + A_Q12 = &PredCoef_Q12[ ( ( k >> 1 ) | ( 1 - LSF_interpolation_flag ) ) * MAX_LPC_ORDER ]; + B_Q14 = <PCoef_Q14[ k * LTP_ORDER ]; + AR_shp_Q13 = &AR_Q13[ k * MAX_SHAPE_LPC_ORDER ]; + + /* Noise shape parameters */ + silk_assert( HarmShapeGain_Q14[ k ] >= 0 ); + HarmShapeFIRPacked_Q14 = silk_RSHIFT( HarmShapeGain_Q14[ k ], 2 ); + HarmShapeFIRPacked_Q14 |= silk_LSHIFT( (opus_int32)silk_RSHIFT( HarmShapeGain_Q14[ k ], 1 ), 16 ); + + NSQ->rewhite_flag = 0; + if( psIndices->signalType == TYPE_VOICED ) { + /* Voiced */ + lag = pitchL[ k ]; + + /* Re-whitening */ + if( ( k & ( 3 - silk_LSHIFT( LSF_interpolation_flag, 1 ) ) ) == 0 ) { + if( k == 2 ) { + /* RESET DELAYED DECISIONS */ + /* Find winner */ + RDmin_Q10 = psDelDec[ 0 ].RD_Q10; + Winner_ind = 0; + for( i = 1; i < psEncC->nStatesDelayedDecision; i++ ) { + if( psDelDec[ i ].RD_Q10 < RDmin_Q10 ) { + RDmin_Q10 = psDelDec[ i ].RD_Q10; + Winner_ind = i; + } + } + for( i = 0; i < psEncC->nStatesDelayedDecision; i++ ) { + if( i != Winner_ind ) { + psDelDec[ i ].RD_Q10 += ( silk_int32_MAX >> 4 ); + silk_assert( psDelDec[ i ].RD_Q10 >= 0 ); + } + } + + /* Copy final part of signals from winner state to output and long-term filter states */ + psDD = &psDelDec[ Winner_ind ]; + last_smple_idx = smpl_buf_idx + decisionDelay; + for( i = 0; i < decisionDelay; i++ ) { + last_smple_idx = ( last_smple_idx - 1 ) % DECISION_DELAY; + if( last_smple_idx < 0 ) last_smple_idx += DECISION_DELAY; + pulses[ i - decisionDelay ] = (opus_int8)silk_RSHIFT_ROUND( psDD->Q_Q10[ last_smple_idx ], 10 ); + pxq[ i - decisionDelay ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( + silk_SMULWW( psDD->Xq_Q14[ last_smple_idx ], Gains_Q16[ 1 ] ), 14 ) ); + NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - decisionDelay + i ] = psDD->Shape_Q14[ last_smple_idx ]; + } + + subfr = 0; + } + + /* Rewhiten with new A coefs */ + start_idx = psEncC->ltp_mem_length - lag - psEncC->predictLPCOrder - LTP_ORDER / 2; + celt_assert( start_idx > 0 ); + + silk_LPC_analysis_filter( &sLTP[ start_idx ], &NSQ->xq[ start_idx + k * psEncC->subfr_length ], + A_Q12, psEncC->ltp_mem_length - start_idx, psEncC->predictLPCOrder, psEncC->arch ); + + NSQ->sLTP_buf_idx = psEncC->ltp_mem_length; + NSQ->rewhite_flag = 1; + } + } + + silk_nsq_del_dec_scale_states( psEncC, NSQ, psDelDec, x16, x_sc_Q10, sLTP, sLTP_Q15, k, + psEncC->nStatesDelayedDecision, LTP_scale_Q14, Gains_Q16, pitchL, psIndices->signalType, decisionDelay ); + + silk_noise_shape_quantizer_del_dec( NSQ, psDelDec, psIndices->signalType, x_sc_Q10, pulses, pxq, sLTP_Q15, + delayedGain_Q10, A_Q12, B_Q14, AR_shp_Q13, 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, decisionDelay, psEncC->arch ); + + x16 += psEncC->subfr_length; + pulses += psEncC->subfr_length; + pxq += psEncC->subfr_length; + } + + /* Find winner */ + RDmin_Q10 = psDelDec[ 0 ].RD_Q10; + Winner_ind = 0; + for( k = 1; k < psEncC->nStatesDelayedDecision; k++ ) { + if( psDelDec[ k ].RD_Q10 < RDmin_Q10 ) { + RDmin_Q10 = psDelDec[ k ].RD_Q10; + Winner_ind = k; + } + } + + /* Copy final part of signals from winner state to output and long-term filter states */ + psDD = &psDelDec[ Winner_ind ]; + psIndices->Seed = psDD->SeedInit; + last_smple_idx = smpl_buf_idx + decisionDelay; + Gain_Q10 = silk_RSHIFT32( Gains_Q16[ psEncC->nb_subfr - 1 ], 6 ); + for( i = 0; i < decisionDelay; i++ ) { + last_smple_idx = ( last_smple_idx - 1 ) % DECISION_DELAY; + if( last_smple_idx < 0 ) last_smple_idx += DECISION_DELAY; + + pulses[ i - decisionDelay ] = (opus_int8)silk_RSHIFT_ROUND( psDD->Q_Q10[ last_smple_idx ], 10 ); + pxq[ i - decisionDelay ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( + silk_SMULWW( psDD->Xq_Q14[ last_smple_idx ], Gain_Q10 ), 8 ) ); + NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - decisionDelay + i ] = psDD->Shape_Q14[ last_smple_idx ]; + } + silk_memcpy( NSQ->sLPC_Q14, &psDD->sLPC_Q14[ psEncC->subfr_length ], NSQ_LPC_BUF_LENGTH * sizeof( opus_int32 ) ); + silk_memcpy( NSQ->sAR2_Q14, psDD->sAR2_Q14, sizeof( psDD->sAR2_Q14 ) ); + + /* Update states */ + NSQ->sLF_AR_shp_Q14 = psDD->LF_AR_Q14; + NSQ->sDiff_shp_Q14 = psDD->Diff_Q14; + NSQ->lagPrev = pitchL[ psEncC->nb_subfr - 1 ]; + + /* Save quantized speech signal */ + silk_memmove( NSQ->xq, &NSQ->xq[ psEncC->frame_length ], psEncC->ltp_mem_length * sizeof( opus_int16 ) ); + silk_memmove( NSQ->sLTP_shp_Q14, &NSQ->sLTP_shp_Q14[ psEncC->frame_length ], psEncC->ltp_mem_length * sizeof( opus_int32 ) ); + RESTORE_STACK; +} + +/******************************************/ +/* Noise shape quantizer for one subframe */ +/******************************************/ +#ifndef OVERRIDE_silk_noise_shape_quantizer_del_dec +static OPUS_INLINE void silk_noise_shape_quantizer_del_dec( + silk_nsq_state *NSQ, /* I/O NSQ state */ + NSQ_del_dec_struct psDelDec[], /* I/O Delayed decision states */ + opus_int signalType, /* I Signal type */ + const opus_int32 x_Q10[], /* I */ + opus_int8 pulses[], /* O */ + opus_int16 xq[], /* O */ + opus_int32 sLTP_Q15[], /* I/O LTP filter state */ + opus_int32 delayedGain_Q10[], /* I/O Gain delay buffer */ + const opus_int16 a_Q12[], /* I Short term prediction coefs */ + const opus_int16 b_Q14[], /* I Long term prediction coefs */ + const opus_int16 AR_shp_Q13[], /* I Noise shaping coefs */ + opus_int lag, /* I Pitch lag */ + opus_int32 HarmShapeFIRPacked_Q14, /* I */ + opus_int Tilt_Q14, /* I Spectral tilt */ + opus_int32 LF_shp_Q14, /* I */ + opus_int32 Gain_Q16, /* I */ + opus_int Lambda_Q10, /* I */ + opus_int offset_Q10, /* I */ + opus_int length, /* I Input length */ + opus_int subfr, /* I Subframe number */ + opus_int shapingLPCOrder, /* I Shaping LPC filter order */ + opus_int predictLPCOrder, /* I Prediction filter order */ + opus_int warping_Q16, /* I */ + opus_int nStatesDelayedDecision, /* I Number of states in decision tree */ + opus_int *smpl_buf_idx, /* I/O Index to newest samples in buffers */ + opus_int decisionDelay, /* I */ + int arch /* I */ +) +{ + opus_int i, j, k, Winner_ind, RDmin_ind, RDmax_ind, last_smple_idx; + opus_int32 Winner_rand_state; + opus_int32 LTP_pred_Q14, LPC_pred_Q14, n_AR_Q14, n_LTP_Q14; + opus_int32 n_LF_Q14, r_Q10, rr_Q10, rd1_Q10, rd2_Q10, RDmin_Q10, RDmax_Q10; + opus_int32 q1_Q0, q1_Q10, q2_Q10, exc_Q14, LPC_exc_Q14, xq_Q14, Gain_Q10; + opus_int32 tmp1, tmp2, sLF_AR_shp_Q14; + opus_int32 *pred_lag_ptr, *shp_lag_ptr, *psLPC_Q14; +#ifdef silk_short_prediction_create_arch_coef + opus_int32 a_Q12_arch[MAX_LPC_ORDER]; +#endif + + VARDECL( NSQ_sample_pair, psSampleState ); + NSQ_del_dec_struct *psDD; + NSQ_sample_struct *psSS; + SAVE_STACK; + + celt_assert( nStatesDelayedDecision > 0 ); + ALLOC( psSampleState, nStatesDelayedDecision, NSQ_sample_pair ); + + shp_lag_ptr = &NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - lag + HARM_SHAPE_FIR_TAPS / 2 ]; + pred_lag_ptr = &sLTP_Q15[ NSQ->sLTP_buf_idx - lag + LTP_ORDER / 2 ]; + Gain_Q10 = silk_RSHIFT( Gain_Q16, 6 ); + +#ifdef silk_short_prediction_create_arch_coef + silk_short_prediction_create_arch_coef(a_Q12_arch, a_Q12, predictLPCOrder); +#endif + + for( i = 0; i < length; i++ ) { + /* Perform common calculations used in all states */ + + /* Long-term prediction */ + if( signalType == TYPE_VOICED ) { + /* Unrolled loop */ + /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */ + LTP_pred_Q14 = 2; + LTP_pred_Q14 = silk_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ 0 ], b_Q14[ 0 ] ); + LTP_pred_Q14 = silk_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ -1 ], b_Q14[ 1 ] ); + LTP_pred_Q14 = silk_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ -2 ], b_Q14[ 2 ] ); + LTP_pred_Q14 = silk_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ -3 ], b_Q14[ 3 ] ); + LTP_pred_Q14 = silk_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ -4 ], b_Q14[ 4 ] ); + LTP_pred_Q14 = silk_LSHIFT( LTP_pred_Q14, 1 ); /* Q13 -> Q14 */ + pred_lag_ptr++; + } else { + LTP_pred_Q14 = 0; + } + + /* Long-term shaping */ + if( lag > 0 ) { + /* Symmetric, packed FIR coefficients */ + n_LTP_Q14 = silk_SMULWB( silk_ADD32( shp_lag_ptr[ 0 ], shp_lag_ptr[ -2 ] ), HarmShapeFIRPacked_Q14 ); + n_LTP_Q14 = silk_SMLAWT( n_LTP_Q14, shp_lag_ptr[ -1 ], HarmShapeFIRPacked_Q14 ); + n_LTP_Q14 = silk_SUB_LSHIFT32( LTP_pred_Q14, n_LTP_Q14, 2 ); /* Q12 -> Q14 */ + shp_lag_ptr++; + } else { + n_LTP_Q14 = 0; + } + + for( k = 0; k < nStatesDelayedDecision; k++ ) { + /* Delayed decision state */ + psDD = &psDelDec[ k ]; + + /* Sample state */ + psSS = psSampleState[ k ]; + + /* Generate dither */ + psDD->Seed = silk_RAND( psDD->Seed ); + + /* Pointer used in short term prediction and shaping */ + psLPC_Q14 = &psDD->sLPC_Q14[ NSQ_LPC_BUF_LENGTH - 1 + i ]; + /* Short-term prediction */ + LPC_pred_Q14 = silk_noise_shape_quantizer_short_prediction(psLPC_Q14, a_Q12, a_Q12_arch, predictLPCOrder, arch); + LPC_pred_Q14 = silk_LSHIFT( LPC_pred_Q14, 4 ); /* Q10 -> Q14 */ + + /* Noise shape feedback */ + celt_assert( ( shapingLPCOrder & 1 ) == 0 ); /* check that order is even */ + /* Output of lowpass section */ + tmp2 = silk_SMLAWB( psDD->Diff_Q14, psDD->sAR2_Q14[ 0 ], warping_Q16 ); + /* Output of allpass section */ + tmp1 = silk_SMLAWB( psDD->sAR2_Q14[ 0 ], psDD->sAR2_Q14[ 1 ] - tmp2, warping_Q16 ); + psDD->sAR2_Q14[ 0 ] = tmp2; + n_AR_Q14 = silk_RSHIFT( shapingLPCOrder, 1 ); + n_AR_Q14 = silk_SMLAWB( n_AR_Q14, tmp2, AR_shp_Q13[ 0 ] ); + /* Loop over allpass sections */ + for( j = 2; j < shapingLPCOrder; j += 2 ) { + /* Output of allpass section */ + tmp2 = silk_SMLAWB( psDD->sAR2_Q14[ j - 1 ], psDD->sAR2_Q14[ j + 0 ] - tmp1, warping_Q16 ); + psDD->sAR2_Q14[ j - 1 ] = tmp1; + n_AR_Q14 = silk_SMLAWB( n_AR_Q14, tmp1, AR_shp_Q13[ j - 1 ] ); + /* Output of allpass section */ + tmp1 = silk_SMLAWB( psDD->sAR2_Q14[ j + 0 ], psDD->sAR2_Q14[ j + 1 ] - tmp2, warping_Q16 ); + psDD->sAR2_Q14[ j + 0 ] = tmp2; + n_AR_Q14 = silk_SMLAWB( n_AR_Q14, tmp2, AR_shp_Q13[ j ] ); + } + psDD->sAR2_Q14[ shapingLPCOrder - 1 ] = tmp1; + n_AR_Q14 = silk_SMLAWB( n_AR_Q14, tmp1, AR_shp_Q13[ shapingLPCOrder - 1 ] ); + + n_AR_Q14 = silk_LSHIFT( n_AR_Q14, 1 ); /* Q11 -> Q12 */ + n_AR_Q14 = silk_SMLAWB( n_AR_Q14, psDD->LF_AR_Q14, Tilt_Q14 ); /* Q12 */ + n_AR_Q14 = silk_LSHIFT( n_AR_Q14, 2 ); /* Q12 -> Q14 */ + + n_LF_Q14 = silk_SMULWB( psDD->Shape_Q14[ *smpl_buf_idx ], LF_shp_Q14 ); /* Q12 */ + n_LF_Q14 = silk_SMLAWT( n_LF_Q14, psDD->LF_AR_Q14, LF_shp_Q14 ); /* Q12 */ + n_LF_Q14 = silk_LSHIFT( n_LF_Q14, 2 ); /* Q12 -> Q14 */ + + /* Input minus prediction plus noise feedback */ + /* r = x[ i ] - LTP_pred - LPC_pred + n_AR + n_Tilt + n_LF + n_LTP */ + tmp1 = silk_ADD32( n_AR_Q14, n_LF_Q14 ); /* Q14 */ + tmp2 = silk_ADD32( n_LTP_Q14, LPC_pred_Q14 ); /* Q13 */ + tmp1 = silk_SUB32( tmp2, tmp1 ); /* Q13 */ + tmp1 = silk_RSHIFT_ROUND( tmp1, 4 ); /* Q10 */ + + r_Q10 = silk_SUB32( x_Q10[ i ], tmp1 ); /* residual error Q10 */ + + /* Flip sign depending on dither */ + if ( psDD->Seed < 0 ) { + r_Q10 = -r_Q10; + } + r_Q10 = silk_LIMIT_32( r_Q10, -(31 << 10), 30 << 10 ); + + /* Find two quantization level candidates and measure their rate-distortion */ + q1_Q10 = silk_SUB32( r_Q10, offset_Q10 ); + q1_Q0 = silk_RSHIFT( q1_Q10, 10 ); + if (Lambda_Q10 > 2048) { + /* For aggressive RDO, the bias becomes more than one pulse. */ + int rdo_offset = Lambda_Q10/2 - 512; + if (q1_Q10 > rdo_offset) { + q1_Q0 = silk_RSHIFT( q1_Q10 - rdo_offset, 10 ); + } else if (q1_Q10 < -rdo_offset) { + q1_Q0 = silk_RSHIFT( q1_Q10 + rdo_offset, 10 ); + } else if (q1_Q10 < 0) { + q1_Q0 = -1; + } else { + q1_Q0 = 0; + } + } + if( q1_Q0 > 0 ) { + q1_Q10 = silk_SUB32( silk_LSHIFT( q1_Q0, 10 ), QUANT_LEVEL_ADJUST_Q10 ); + q1_Q10 = silk_ADD32( q1_Q10, offset_Q10 ); + q2_Q10 = silk_ADD32( q1_Q10, 1024 ); + rd1_Q10 = silk_SMULBB( q1_Q10, Lambda_Q10 ); + rd2_Q10 = silk_SMULBB( q2_Q10, Lambda_Q10 ); + } else if( q1_Q0 == 0 ) { + q1_Q10 = offset_Q10; + q2_Q10 = silk_ADD32( q1_Q10, 1024 - QUANT_LEVEL_ADJUST_Q10 ); + rd1_Q10 = silk_SMULBB( q1_Q10, Lambda_Q10 ); + rd2_Q10 = silk_SMULBB( q2_Q10, Lambda_Q10 ); + } else if( q1_Q0 == -1 ) { + q2_Q10 = offset_Q10; + q1_Q10 = silk_SUB32( q2_Q10, 1024 - QUANT_LEVEL_ADJUST_Q10 ); + rd1_Q10 = silk_SMULBB( -q1_Q10, Lambda_Q10 ); + rd2_Q10 = silk_SMULBB( q2_Q10, Lambda_Q10 ); + } else { /* q1_Q0 < -1 */ + q1_Q10 = silk_ADD32( silk_LSHIFT( q1_Q0, 10 ), QUANT_LEVEL_ADJUST_Q10 ); + q1_Q10 = silk_ADD32( q1_Q10, offset_Q10 ); + q2_Q10 = silk_ADD32( q1_Q10, 1024 ); + rd1_Q10 = silk_SMULBB( -q1_Q10, Lambda_Q10 ); + rd2_Q10 = silk_SMULBB( -q2_Q10, Lambda_Q10 ); + } + rr_Q10 = silk_SUB32( r_Q10, q1_Q10 ); + rd1_Q10 = silk_RSHIFT( silk_SMLABB( rd1_Q10, rr_Q10, rr_Q10 ), 10 ); + rr_Q10 = silk_SUB32( r_Q10, q2_Q10 ); + rd2_Q10 = silk_RSHIFT( silk_SMLABB( rd2_Q10, rr_Q10, rr_Q10 ), 10 ); + + if( rd1_Q10 < rd2_Q10 ) { + psSS[ 0 ].RD_Q10 = silk_ADD32( psDD->RD_Q10, rd1_Q10 ); + psSS[ 1 ].RD_Q10 = silk_ADD32( psDD->RD_Q10, rd2_Q10 ); + psSS[ 0 ].Q_Q10 = q1_Q10; + psSS[ 1 ].Q_Q10 = q2_Q10; + } else { + psSS[ 0 ].RD_Q10 = silk_ADD32( psDD->RD_Q10, rd2_Q10 ); + psSS[ 1 ].RD_Q10 = silk_ADD32( psDD->RD_Q10, rd1_Q10 ); + psSS[ 0 ].Q_Q10 = q2_Q10; + psSS[ 1 ].Q_Q10 = q1_Q10; + } + + /* Update states for best quantization */ + + /* Quantized excitation */ + exc_Q14 = silk_LSHIFT32( psSS[ 0 ].Q_Q10, 4 ); + if ( psDD->Seed < 0 ) { + exc_Q14 = -exc_Q14; + } + + /* Add predictions */ + LPC_exc_Q14 = silk_ADD32( exc_Q14, LTP_pred_Q14 ); + xq_Q14 = silk_ADD32( LPC_exc_Q14, LPC_pred_Q14 ); + + /* Update states */ + psSS[ 0 ].Diff_Q14 = silk_SUB_LSHIFT32( xq_Q14, x_Q10[ i ], 4 ); + sLF_AR_shp_Q14 = silk_SUB32( psSS[ 0 ].Diff_Q14, n_AR_Q14 ); + psSS[ 0 ].sLTP_shp_Q14 = silk_SUB32( sLF_AR_shp_Q14, n_LF_Q14 ); + psSS[ 0 ].LF_AR_Q14 = sLF_AR_shp_Q14; + psSS[ 0 ].LPC_exc_Q14 = LPC_exc_Q14; + psSS[ 0 ].xq_Q14 = xq_Q14; + + /* Update states for second best quantization */ + + /* Quantized excitation */ + exc_Q14 = silk_LSHIFT32( psSS[ 1 ].Q_Q10, 4 ); + if ( psDD->Seed < 0 ) { + exc_Q14 = -exc_Q14; + } + + /* Add predictions */ + LPC_exc_Q14 = silk_ADD32( exc_Q14, LTP_pred_Q14 ); + xq_Q14 = silk_ADD32( LPC_exc_Q14, LPC_pred_Q14 ); + + /* Update states */ + psSS[ 1 ].Diff_Q14 = silk_SUB_LSHIFT32( xq_Q14, x_Q10[ i ], 4 ); + sLF_AR_shp_Q14 = silk_SUB32( psSS[ 1 ].Diff_Q14, n_AR_Q14 ); + psSS[ 1 ].sLTP_shp_Q14 = silk_SUB32( sLF_AR_shp_Q14, n_LF_Q14 ); + psSS[ 1 ].LF_AR_Q14 = sLF_AR_shp_Q14; + psSS[ 1 ].LPC_exc_Q14 = LPC_exc_Q14; + psSS[ 1 ].xq_Q14 = xq_Q14; + } + + *smpl_buf_idx = ( *smpl_buf_idx - 1 ) % DECISION_DELAY; + if( *smpl_buf_idx < 0 ) *smpl_buf_idx += DECISION_DELAY; + last_smple_idx = ( *smpl_buf_idx + decisionDelay ) % DECISION_DELAY; + + /* Find winner */ + RDmin_Q10 = psSampleState[ 0 ][ 0 ].RD_Q10; + Winner_ind = 0; + for( k = 1; k < nStatesDelayedDecision; k++ ) { + if( psSampleState[ k ][ 0 ].RD_Q10 < RDmin_Q10 ) { + RDmin_Q10 = psSampleState[ k ][ 0 ].RD_Q10; + Winner_ind = k; + } + } + + /* Increase RD values of expired states */ + 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 ) { + psSampleState[ k ][ 0 ].RD_Q10 = silk_ADD32( psSampleState[ k ][ 0 ].RD_Q10, silk_int32_MAX >> 4 ); + psSampleState[ k ][ 1 ].RD_Q10 = silk_ADD32( psSampleState[ k ][ 1 ].RD_Q10, silk_int32_MAX >> 4 ); + silk_assert( psSampleState[ k ][ 0 ].RD_Q10 >= 0 ); + } + } + + /* Find worst in first set and best in second set */ + RDmax_Q10 = psSampleState[ 0 ][ 0 ].RD_Q10; + RDmin_Q10 = psSampleState[ 0 ][ 1 ].RD_Q10; + RDmax_ind = 0; + RDmin_ind = 0; + for( k = 1; k < nStatesDelayedDecision; k++ ) { + /* find worst in first set */ + if( psSampleState[ k ][ 0 ].RD_Q10 > RDmax_Q10 ) { + RDmax_Q10 = psSampleState[ k ][ 0 ].RD_Q10; + RDmax_ind = k; + } + /* find best in second set */ + if( psSampleState[ k ][ 1 ].RD_Q10 < RDmin_Q10 ) { + RDmin_Q10 = psSampleState[ k ][ 1 ].RD_Q10; + RDmin_ind = k; + } + } + + /* Replace a state if best from second set outperforms worst in first set */ + if( RDmin_Q10 < RDmax_Q10 ) { + silk_memcpy( ( (opus_int32 *)&psDelDec[ RDmax_ind ] ) + i, + ( (opus_int32 *)&psDelDec[ RDmin_ind ] ) + i, sizeof( NSQ_del_dec_struct ) - i * sizeof( opus_int32) ); + silk_memcpy( &psSampleState[ RDmax_ind ][ 0 ], &psSampleState[ RDmin_ind ][ 1 ], sizeof( NSQ_sample_struct ) ); + } + + /* Write samples from winner to output and long-term filter states */ + psDD = &psDelDec[ Winner_ind ]; + if( subfr > 0 || i >= decisionDelay ) { + pulses[ i - decisionDelay ] = (opus_int8)silk_RSHIFT_ROUND( psDD->Q_Q10[ last_smple_idx ], 10 ); + xq[ i - decisionDelay ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( + silk_SMULWW( psDD->Xq_Q14[ last_smple_idx ], delayedGain_Q10[ last_smple_idx ] ), 8 ) ); + NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - decisionDelay ] = psDD->Shape_Q14[ last_smple_idx ]; + sLTP_Q15[ NSQ->sLTP_buf_idx - decisionDelay ] = psDD->Pred_Q15[ last_smple_idx ]; + } + NSQ->sLTP_shp_buf_idx++; + NSQ->sLTP_buf_idx++; + + /* Update states */ + for( k = 0; k < nStatesDelayedDecision; k++ ) { + psDD = &psDelDec[ k ]; + psSS = &psSampleState[ k ][ 0 ]; + psDD->LF_AR_Q14 = psSS->LF_AR_Q14; + psDD->Diff_Q14 = psSS->Diff_Q14; + psDD->sLPC_Q14[ NSQ_LPC_BUF_LENGTH + i ] = psSS->xq_Q14; + psDD->Xq_Q14[ *smpl_buf_idx ] = psSS->xq_Q14; + psDD->Q_Q10[ *smpl_buf_idx ] = psSS->Q_Q10; + psDD->Pred_Q15[ *smpl_buf_idx ] = silk_LSHIFT32( psSS->LPC_exc_Q14, 1 ); + psDD->Shape_Q14[ *smpl_buf_idx ] = psSS->sLTP_shp_Q14; + psDD->Seed = silk_ADD32_ovflw( psDD->Seed, silk_RSHIFT_ROUND( psSS->Q_Q10, 10 ) ); + psDD->RandState[ *smpl_buf_idx ] = psDD->Seed; + psDD->RD_Q10 = psSS->RD_Q10; + } + delayedGain_Q10[ *smpl_buf_idx ] = Gain_Q10; + } + /* Update LPC states */ + for( k = 0; k < nStatesDelayedDecision; k++ ) { + psDD = &psDelDec[ k ]; + silk_memcpy( psDD->sLPC_Q14, &psDD->sLPC_Q14[ length ], NSQ_LPC_BUF_LENGTH * sizeof( opus_int32 ) ); + } + RESTORE_STACK; +} +#endif /* OVERRIDE_silk_noise_shape_quantizer_del_dec */ + +static OPUS_INLINE void silk_nsq_del_dec_scale_states( + const silk_encoder_state *psEncC, /* I Encoder State */ + silk_nsq_state *NSQ, /* I/O NSQ state */ + NSQ_del_dec_struct psDelDec[], /* I/O Delayed decision states */ + const opus_int16 x16[], /* I Input */ + opus_int32 x_sc_Q10[], /* O Input scaled with 1/Gain in Q10 */ + const opus_int16 sLTP[], /* I Re-whitened LTP state in Q0 */ + opus_int32 sLTP_Q15[], /* O LTP state matching scaled input */ + opus_int subfr, /* I Subframe number */ + opus_int nStatesDelayedDecision, /* I Number of del dec states */ + const opus_int LTP_scale_Q14, /* I LTP state scaling */ + const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lag */ + const opus_int signal_type, /* I Signal type */ + const opus_int decisionDelay /* I Decision delay */ +) +{ + opus_int i, k, lag; + opus_int32 gain_adj_Q16, inv_gain_Q31, inv_gain_Q26; + NSQ_del_dec_struct *psDD; + + lag = pitchL[ subfr ]; + inv_gain_Q31 = silk_INVERSE32_varQ( silk_max( Gains_Q16[ subfr ], 1 ), 47 ); + silk_assert( inv_gain_Q31 != 0 ); + + /* Scale input */ + inv_gain_Q26 = silk_RSHIFT_ROUND( inv_gain_Q31, 5 ); + for( i = 0; i < psEncC->subfr_length; i++ ) { + x_sc_Q10[ i ] = silk_SMULWW( x16[ i ], inv_gain_Q26 ); + } + + /* After rewhitening the LTP state is un-scaled, so scale with inv_gain_Q16 */ + if( NSQ->rewhite_flag ) { + if( subfr == 0 ) { + /* Do LTP downscaling */ + inv_gain_Q31 = silk_LSHIFT( silk_SMULWB( inv_gain_Q31, LTP_scale_Q14 ), 2 ); + } + for( i = NSQ->sLTP_buf_idx - lag - LTP_ORDER / 2; i < NSQ->sLTP_buf_idx; i++ ) { + silk_assert( i < MAX_FRAME_LENGTH ); + sLTP_Q15[ i ] = silk_SMULWB( inv_gain_Q31, sLTP[ i ] ); + } + } + + /* Adjust for changing gain */ + if( Gains_Q16[ subfr ] != NSQ->prev_gain_Q16 ) { + gain_adj_Q16 = silk_DIV32_varQ( NSQ->prev_gain_Q16, Gains_Q16[ subfr ], 16 ); + + /* Scale long-term shaping state */ + for( i = NSQ->sLTP_shp_buf_idx - psEncC->ltp_mem_length; i < NSQ->sLTP_shp_buf_idx; i++ ) { + NSQ->sLTP_shp_Q14[ i ] = silk_SMULWW( gain_adj_Q16, NSQ->sLTP_shp_Q14[ i ] ); + } + + /* Scale long-term prediction state */ + if( signal_type == TYPE_VOICED && NSQ->rewhite_flag == 0 ) { + for( i = NSQ->sLTP_buf_idx - lag - LTP_ORDER / 2; i < NSQ->sLTP_buf_idx - decisionDelay; i++ ) { + sLTP_Q15[ i ] = silk_SMULWW( gain_adj_Q16, sLTP_Q15[ i ] ); + } + } + + for( k = 0; k < nStatesDelayedDecision; k++ ) { + psDD = &psDelDec[ k ]; + + /* Scale scalar states */ + psDD->LF_AR_Q14 = silk_SMULWW( gain_adj_Q16, psDD->LF_AR_Q14 ); + psDD->Diff_Q14 = silk_SMULWW( gain_adj_Q16, psDD->Diff_Q14 ); + + /* Scale short-term prediction and shaping states */ + for( i = 0; i < NSQ_LPC_BUF_LENGTH; i++ ) { + psDD->sLPC_Q14[ i ] = silk_SMULWW( gain_adj_Q16, psDD->sLPC_Q14[ i ] ); + } + for( i = 0; i < MAX_SHAPE_LPC_ORDER; i++ ) { + psDD->sAR2_Q14[ i ] = silk_SMULWW( gain_adj_Q16, psDD->sAR2_Q14[ i ] ); + } + for( i = 0; i < DECISION_DELAY; i++ ) { + psDD->Pred_Q15[ i ] = silk_SMULWW( gain_adj_Q16, psDD->Pred_Q15[ i ] ); + psDD->Shape_Q14[ i ] = silk_SMULWW( gain_adj_Q16, psDD->Shape_Q14[ i ] ); + } + } + + /* Save inverse gain */ + NSQ->prev_gain_Q16 = Gains_Q16[ subfr ]; + } +} diff --git a/extern/opus/silk/PLC.c b/extern/opus/silk/PLC.c new file mode 100644 index 0000000..f893916 --- /dev/null +++ b/extern/opus/silk/PLC.c @@ -0,0 +1,448 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" +#include "stack_alloc.h" +#include "PLC.h" + +#define NB_ATT 2 +static const opus_int16 HARM_ATT_Q15[NB_ATT] = { 32440, 31130 }; /* 0.99, 0.95 */ +static const opus_int16 PLC_RAND_ATTENUATE_V_Q15[NB_ATT] = { 31130, 26214 }; /* 0.95, 0.8 */ +static const opus_int16 PLC_RAND_ATTENUATE_UV_Q15[NB_ATT] = { 32440, 29491 }; /* 0.99, 0.9 */ + +static OPUS_INLINE void silk_PLC_update( + silk_decoder_state *psDec, /* I/O Decoder state */ + silk_decoder_control *psDecCtrl /* I/O Decoder control */ +); + +static OPUS_INLINE void silk_PLC_conceal( + silk_decoder_state *psDec, /* I/O Decoder state */ + silk_decoder_control *psDecCtrl, /* I/O Decoder control */ + opus_int16 frame[], /* O LPC residual signal */ + int arch /* I Run-time architecture */ +); + + +void silk_PLC_Reset( + silk_decoder_state *psDec /* I/O Decoder state */ +) +{ + psDec->sPLC.pitchL_Q8 = silk_LSHIFT( psDec->frame_length, 8 - 1 ); + psDec->sPLC.prevGain_Q16[ 0 ] = SILK_FIX_CONST( 1, 16 ); + psDec->sPLC.prevGain_Q16[ 1 ] = SILK_FIX_CONST( 1, 16 ); + psDec->sPLC.subfr_length = 20; + psDec->sPLC.nb_subfr = 2; +} + +void silk_PLC( + silk_decoder_state *psDec, /* I/O Decoder state */ + silk_decoder_control *psDecCtrl, /* I/O Decoder control */ + opus_int16 frame[], /* I/O signal */ + opus_int lost, /* I Loss flag */ + int arch /* I Run-time architecture */ +) +{ + /* PLC control function */ + if( psDec->fs_kHz != psDec->sPLC.fs_kHz ) { + silk_PLC_Reset( psDec ); + psDec->sPLC.fs_kHz = psDec->fs_kHz; + } + + if( lost ) { + /****************************/ + /* Generate Signal */ + /****************************/ + silk_PLC_conceal( psDec, psDecCtrl, frame, arch ); + + psDec->lossCnt++; + } else { + /****************************/ + /* Update state */ + /****************************/ + silk_PLC_update( psDec, psDecCtrl ); + } +} + +/**************************************************/ +/* Update state of PLC */ +/**************************************************/ +static OPUS_INLINE void silk_PLC_update( + silk_decoder_state *psDec, /* I/O Decoder state */ + silk_decoder_control *psDecCtrl /* I/O Decoder control */ +) +{ + opus_int32 LTP_Gain_Q14, temp_LTP_Gain_Q14; + opus_int i, j; + silk_PLC_struct *psPLC; + + psPLC = &psDec->sPLC; + + /* Update parameters used in case of packet loss */ + psDec->prevSignalType = psDec->indices.signalType; + LTP_Gain_Q14 = 0; + if( psDec->indices.signalType == TYPE_VOICED ) { + /* Find the parameters for the last subframe which contains a pitch pulse */ + for( j = 0; j * psDec->subfr_length < psDecCtrl->pitchL[ psDec->nb_subfr - 1 ]; j++ ) { + if( j == psDec->nb_subfr ) { + break; + } + temp_LTP_Gain_Q14 = 0; + for( i = 0; i < LTP_ORDER; i++ ) { + temp_LTP_Gain_Q14 += psDecCtrl->LTPCoef_Q14[ ( psDec->nb_subfr - 1 - j ) * LTP_ORDER + i ]; + } + if( temp_LTP_Gain_Q14 > LTP_Gain_Q14 ) { + LTP_Gain_Q14 = temp_LTP_Gain_Q14; + silk_memcpy( psPLC->LTPCoef_Q14, + &psDecCtrl->LTPCoef_Q14[ silk_SMULBB( psDec->nb_subfr - 1 - j, LTP_ORDER ) ], + LTP_ORDER * sizeof( opus_int16 ) ); + + psPLC->pitchL_Q8 = silk_LSHIFT( psDecCtrl->pitchL[ psDec->nb_subfr - 1 - j ], 8 ); + } + } + + silk_memset( psPLC->LTPCoef_Q14, 0, LTP_ORDER * sizeof( opus_int16 ) ); + psPLC->LTPCoef_Q14[ LTP_ORDER / 2 ] = LTP_Gain_Q14; + + /* Limit LT coefs */ + if( LTP_Gain_Q14 < V_PITCH_GAIN_START_MIN_Q14 ) { + opus_int scale_Q10; + opus_int32 tmp; + + tmp = silk_LSHIFT( V_PITCH_GAIN_START_MIN_Q14, 10 ); + scale_Q10 = silk_DIV32( tmp, silk_max( LTP_Gain_Q14, 1 ) ); + for( i = 0; i < LTP_ORDER; i++ ) { + psPLC->LTPCoef_Q14[ i ] = silk_RSHIFT( silk_SMULBB( psPLC->LTPCoef_Q14[ i ], scale_Q10 ), 10 ); + } + } else if( LTP_Gain_Q14 > V_PITCH_GAIN_START_MAX_Q14 ) { + opus_int scale_Q14; + opus_int32 tmp; + + tmp = silk_LSHIFT( V_PITCH_GAIN_START_MAX_Q14, 14 ); + scale_Q14 = silk_DIV32( tmp, silk_max( LTP_Gain_Q14, 1 ) ); + for( i = 0; i < LTP_ORDER; i++ ) { + psPLC->LTPCoef_Q14[ i ] = silk_RSHIFT( silk_SMULBB( psPLC->LTPCoef_Q14[ i ], scale_Q14 ), 14 ); + } + } + } else { + psPLC->pitchL_Q8 = silk_LSHIFT( silk_SMULBB( psDec->fs_kHz, 18 ), 8 ); + silk_memset( psPLC->LTPCoef_Q14, 0, LTP_ORDER * sizeof( opus_int16 )); + } + + /* Save LPC coeficients */ + silk_memcpy( psPLC->prevLPC_Q12, psDecCtrl->PredCoef_Q12[ 1 ], psDec->LPC_order * sizeof( opus_int16 ) ); + psPLC->prevLTP_scale_Q14 = psDecCtrl->LTP_scale_Q14; + + /* Save last two gains */ + silk_memcpy( psPLC->prevGain_Q16, &psDecCtrl->Gains_Q16[ psDec->nb_subfr - 2 ], 2 * sizeof( opus_int32 ) ); + + psPLC->subfr_length = psDec->subfr_length; + psPLC->nb_subfr = psDec->nb_subfr; +} + +static OPUS_INLINE void silk_PLC_energy(opus_int32 *energy1, opus_int *shift1, opus_int32 *energy2, opus_int *shift2, + const opus_int32 *exc_Q14, const opus_int32 *prevGain_Q10, int subfr_length, int nb_subfr) +{ + int i, k; + VARDECL( opus_int16, exc_buf ); + opus_int16 *exc_buf_ptr; + SAVE_STACK; + ALLOC( exc_buf, 2*subfr_length, opus_int16 ); + /* Find random noise component */ + /* Scale previous excitation signal */ + exc_buf_ptr = exc_buf; + for( k = 0; k < 2; k++ ) { + for( i = 0; i < subfr_length; i++ ) { + exc_buf_ptr[ i ] = (opus_int16)silk_SAT16( silk_RSHIFT( + silk_SMULWW( exc_Q14[ i + ( k + nb_subfr - 2 ) * subfr_length ], prevGain_Q10[ k ] ), 8 ) ); + } + exc_buf_ptr += subfr_length; + } + /* Find the subframe with lowest energy of the last two and use that as random noise generator */ + silk_sum_sqr_shift( energy1, shift1, exc_buf, subfr_length ); + silk_sum_sqr_shift( energy2, shift2, &exc_buf[ subfr_length ], subfr_length ); + RESTORE_STACK; +} + +static OPUS_INLINE void silk_PLC_conceal( + silk_decoder_state *psDec, /* I/O Decoder state */ + silk_decoder_control *psDecCtrl, /* I/O Decoder control */ + opus_int16 frame[], /* O LPC residual signal */ + int arch /* I Run-time architecture */ +) +{ + opus_int i, j, k; + opus_int lag, idx, sLTP_buf_idx, shift1, shift2; + opus_int32 rand_seed, harm_Gain_Q15, rand_Gain_Q15, inv_gain_Q30; + opus_int32 energy1, energy2, *rand_ptr, *pred_lag_ptr; + opus_int32 LPC_pred_Q10, LTP_pred_Q12; + opus_int16 rand_scale_Q14; + opus_int16 *B_Q14; + opus_int32 *sLPC_Q14_ptr; + opus_int16 A_Q12[ MAX_LPC_ORDER ]; +#ifdef SMALL_FOOTPRINT + opus_int16 *sLTP; +#else + VARDECL( opus_int16, sLTP ); +#endif + VARDECL( opus_int32, sLTP_Q14 ); + silk_PLC_struct *psPLC = &psDec->sPLC; + opus_int32 prevGain_Q10[2]; + SAVE_STACK; + + ALLOC( sLTP_Q14, psDec->ltp_mem_length + psDec->frame_length, opus_int32 ); +#ifdef SMALL_FOOTPRINT + /* Ugly hack that breaks aliasing rules to save stack: put sLTP at the very end of sLTP_Q14. */ + sLTP = ((opus_int16*)&sLTP_Q14[psDec->ltp_mem_length + psDec->frame_length])-psDec->ltp_mem_length; +#else + ALLOC( sLTP, psDec->ltp_mem_length, opus_int16 ); +#endif + + prevGain_Q10[0] = silk_RSHIFT( psPLC->prevGain_Q16[ 0 ], 6); + prevGain_Q10[1] = silk_RSHIFT( psPLC->prevGain_Q16[ 1 ], 6); + + if( psDec->first_frame_after_reset ) { + silk_memset( psPLC->prevLPC_Q12, 0, sizeof( psPLC->prevLPC_Q12 ) ); + } + + silk_PLC_energy(&energy1, &shift1, &energy2, &shift2, psDec->exc_Q14, prevGain_Q10, psDec->subfr_length, psDec->nb_subfr); + + if( silk_RSHIFT( energy1, shift2 ) < silk_RSHIFT( energy2, shift1 ) ) { + /* First sub-frame has lowest energy */ + rand_ptr = &psDec->exc_Q14[ silk_max_int( 0, ( psPLC->nb_subfr - 1 ) * psPLC->subfr_length - RAND_BUF_SIZE ) ]; + } else { + /* Second sub-frame has lowest energy */ + rand_ptr = &psDec->exc_Q14[ silk_max_int( 0, psPLC->nb_subfr * psPLC->subfr_length - RAND_BUF_SIZE ) ]; + } + + /* Set up Gain to random noise component */ + B_Q14 = psPLC->LTPCoef_Q14; + rand_scale_Q14 = psPLC->randScale_Q14; + + /* Set up attenuation gains */ + harm_Gain_Q15 = HARM_ATT_Q15[ silk_min_int( NB_ATT - 1, psDec->lossCnt ) ]; + if( psDec->prevSignalType == TYPE_VOICED ) { + rand_Gain_Q15 = PLC_RAND_ATTENUATE_V_Q15[ silk_min_int( NB_ATT - 1, psDec->lossCnt ) ]; + } else { + rand_Gain_Q15 = PLC_RAND_ATTENUATE_UV_Q15[ silk_min_int( NB_ATT - 1, psDec->lossCnt ) ]; + } + + /* LPC concealment. Apply BWE to previous LPC */ + silk_bwexpander( psPLC->prevLPC_Q12, psDec->LPC_order, SILK_FIX_CONST( BWE_COEF, 16 ) ); + + /* Preload LPC coeficients to array on stack. Gives small performance gain */ + silk_memcpy( A_Q12, psPLC->prevLPC_Q12, psDec->LPC_order * sizeof( opus_int16 ) ); + + /* First Lost frame */ + if( psDec->lossCnt == 0 ) { + rand_scale_Q14 = 1 << 14; + + /* Reduce random noise Gain for voiced frames */ + if( psDec->prevSignalType == TYPE_VOICED ) { + for( i = 0; i < LTP_ORDER; i++ ) { + rand_scale_Q14 -= B_Q14[ i ]; + } + rand_scale_Q14 = silk_max_16( 3277, rand_scale_Q14 ); /* 0.2 */ + rand_scale_Q14 = (opus_int16)silk_RSHIFT( silk_SMULBB( rand_scale_Q14, psPLC->prevLTP_scale_Q14 ), 14 ); + } else { + /* Reduce random noise for unvoiced frames with high LPC gain */ + opus_int32 invGain_Q30, down_scale_Q30; + + invGain_Q30 = silk_LPC_inverse_pred_gain( psPLC->prevLPC_Q12, psDec->LPC_order, arch ); + + down_scale_Q30 = silk_min_32( silk_RSHIFT( (opus_int32)1 << 30, LOG2_INV_LPC_GAIN_HIGH_THRES ), invGain_Q30 ); + down_scale_Q30 = silk_max_32( silk_RSHIFT( (opus_int32)1 << 30, LOG2_INV_LPC_GAIN_LOW_THRES ), down_scale_Q30 ); + down_scale_Q30 = silk_LSHIFT( down_scale_Q30, LOG2_INV_LPC_GAIN_HIGH_THRES ); + + rand_Gain_Q15 = silk_RSHIFT( silk_SMULWB( down_scale_Q30, rand_Gain_Q15 ), 14 ); + } + } + + rand_seed = psPLC->rand_seed; + lag = silk_RSHIFT_ROUND( psPLC->pitchL_Q8, 8 ); + sLTP_buf_idx = psDec->ltp_mem_length; + + /* Rewhiten LTP state */ + idx = psDec->ltp_mem_length - lag - psDec->LPC_order - LTP_ORDER / 2; + celt_assert( idx > 0 ); + silk_LPC_analysis_filter( &sLTP[ idx ], &psDec->outBuf[ idx ], A_Q12, psDec->ltp_mem_length - idx, psDec->LPC_order, arch ); + /* Scale LTP state */ + inv_gain_Q30 = silk_INVERSE32_varQ( psPLC->prevGain_Q16[ 1 ], 46 ); + inv_gain_Q30 = silk_min( inv_gain_Q30, silk_int32_MAX >> 1 ); + for( i = idx + psDec->LPC_order; i < psDec->ltp_mem_length; i++ ) { + sLTP_Q14[ i ] = silk_SMULWB( inv_gain_Q30, sLTP[ i ] ); + } + + /***************************/ + /* LTP synthesis filtering */ + /***************************/ + for( k = 0; k < psDec->nb_subfr; k++ ) { + /* Set up pointer */ + pred_lag_ptr = &sLTP_Q14[ sLTP_buf_idx - lag + LTP_ORDER / 2 ]; + for( i = 0; i < psDec->subfr_length; i++ ) { + /* Unrolled loop */ + /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */ + LTP_pred_Q12 = 2; + LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ 0 ], B_Q14[ 0 ] ); + LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ -1 ], B_Q14[ 1 ] ); + LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ -2 ], B_Q14[ 2 ] ); + LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ -3 ], B_Q14[ 3 ] ); + LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ -4 ], B_Q14[ 4 ] ); + pred_lag_ptr++; + + /* Generate LPC excitation */ + rand_seed = silk_RAND( rand_seed ); + idx = silk_RSHIFT( rand_seed, 25 ) & RAND_BUF_MASK; + sLTP_Q14[ sLTP_buf_idx ] = silk_LSHIFT32( silk_SMLAWB( LTP_pred_Q12, rand_ptr[ idx ], rand_scale_Q14 ), 2 ); + sLTP_buf_idx++; + } + + /* Gradually reduce LTP gain */ + for( j = 0; j < LTP_ORDER; j++ ) { + B_Q14[ j ] = silk_RSHIFT( silk_SMULBB( harm_Gain_Q15, B_Q14[ j ] ), 15 ); + } + if ( psDec->indices.signalType != TYPE_NO_VOICE_ACTIVITY ) { + /* Gradually reduce excitation gain */ + rand_scale_Q14 = silk_RSHIFT( silk_SMULBB( rand_scale_Q14, rand_Gain_Q15 ), 15 ); + } + + /* Slowly increase pitch lag */ + psPLC->pitchL_Q8 = silk_SMLAWB( psPLC->pitchL_Q8, psPLC->pitchL_Q8, PITCH_DRIFT_FAC_Q16 ); + psPLC->pitchL_Q8 = silk_min_32( psPLC->pitchL_Q8, silk_LSHIFT( silk_SMULBB( MAX_PITCH_LAG_MS, psDec->fs_kHz ), 8 ) ); + lag = silk_RSHIFT_ROUND( psPLC->pitchL_Q8, 8 ); + } + + /***************************/ + /* LPC synthesis filtering */ + /***************************/ + sLPC_Q14_ptr = &sLTP_Q14[ psDec->ltp_mem_length - MAX_LPC_ORDER ]; + + /* Copy LPC state */ + silk_memcpy( sLPC_Q14_ptr, psDec->sLPC_Q14_buf, MAX_LPC_ORDER * sizeof( opus_int32 ) ); + + celt_assert( psDec->LPC_order >= 10 ); /* check that unrolling works */ + for( i = 0; i < psDec->frame_length; i++ ) { + /* partly unrolled */ + /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */ + LPC_pred_Q10 = silk_RSHIFT( psDec->LPC_order, 1 ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 1 ], A_Q12[ 0 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 2 ], A_Q12[ 1 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 3 ], A_Q12[ 2 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 4 ], A_Q12[ 3 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 5 ], A_Q12[ 4 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 6 ], A_Q12[ 5 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 7 ], A_Q12[ 6 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 8 ], A_Q12[ 7 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 9 ], A_Q12[ 8 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 10 ], A_Q12[ 9 ] ); + for( j = 10; j < psDec->LPC_order; j++ ) { + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - j - 1 ], A_Q12[ j ] ); + } + + /* Add prediction to LPC excitation */ + sLPC_Q14_ptr[ MAX_LPC_ORDER + i ] = silk_ADD_SAT32( sLPC_Q14_ptr[ MAX_LPC_ORDER + i ], + silk_LSHIFT_SAT32( LPC_pred_Q10, 4 )); + + /* Scale with Gain */ + frame[ i ] = (opus_int16)silk_SAT16( silk_SAT16( silk_RSHIFT_ROUND( silk_SMULWW( sLPC_Q14_ptr[ MAX_LPC_ORDER + i ], prevGain_Q10[ 1 ] ), 8 ) ) ); + } + + /* Save LPC state */ + silk_memcpy( psDec->sLPC_Q14_buf, &sLPC_Q14_ptr[ psDec->frame_length ], MAX_LPC_ORDER * sizeof( opus_int32 ) ); + + /**************************************/ + /* Update states */ + /**************************************/ + psPLC->rand_seed = rand_seed; + psPLC->randScale_Q14 = rand_scale_Q14; + for( i = 0; i < MAX_NB_SUBFR; i++ ) { + psDecCtrl->pitchL[ i ] = lag; + } + RESTORE_STACK; +} + +/* Glues concealed frames with new good received frames */ +void silk_PLC_glue_frames( + silk_decoder_state *psDec, /* I/O decoder state */ + opus_int16 frame[], /* I/O signal */ + opus_int length /* I length of signal */ +) +{ + opus_int i, energy_shift; + opus_int32 energy; + silk_PLC_struct *psPLC; + psPLC = &psDec->sPLC; + + if( psDec->lossCnt ) { + /* Calculate energy in concealed residual */ + silk_sum_sqr_shift( &psPLC->conc_energy, &psPLC->conc_energy_shift, frame, length ); + + psPLC->last_frame_lost = 1; + } else { + if( psDec->sPLC.last_frame_lost ) { + /* Calculate residual in decoded signal if last frame was lost */ + silk_sum_sqr_shift( &energy, &energy_shift, frame, length ); + + /* Normalize energies */ + if( energy_shift > psPLC->conc_energy_shift ) { + psPLC->conc_energy = silk_RSHIFT( psPLC->conc_energy, energy_shift - psPLC->conc_energy_shift ); + } else if( energy_shift < psPLC->conc_energy_shift ) { + energy = silk_RSHIFT( energy, psPLC->conc_energy_shift - energy_shift ); + } + + /* Fade in the energy difference */ + if( energy > psPLC->conc_energy ) { + opus_int32 frac_Q24, LZ; + opus_int32 gain_Q16, slope_Q16; + + LZ = silk_CLZ32( psPLC->conc_energy ); + LZ = LZ - 1; + psPLC->conc_energy = silk_LSHIFT( psPLC->conc_energy, LZ ); + energy = silk_RSHIFT( energy, silk_max_32( 24 - LZ, 0 ) ); + + frac_Q24 = silk_DIV32( psPLC->conc_energy, silk_max( energy, 1 ) ); + + gain_Q16 = silk_LSHIFT( silk_SQRT_APPROX( frac_Q24 ), 4 ); + slope_Q16 = silk_DIV32_16( ( (opus_int32)1 << 16 ) - gain_Q16, length ); + /* Make slope 4x steeper to avoid missing onsets after DTX */ + slope_Q16 = silk_LSHIFT( slope_Q16, 2 ); + + for( i = 0; i < length; i++ ) { + frame[ i ] = silk_SMULWB( gain_Q16, frame[ i ] ); + gain_Q16 += slope_Q16; + if( gain_Q16 > (opus_int32)1 << 16 ) { + break; + } + } + } + } + psPLC->last_frame_lost = 0; + } +} diff --git a/extern/opus/silk/PLC.h b/extern/opus/silk/PLC.h new file mode 100644 index 0000000..6438f51 --- /dev/null +++ b/extern/opus/silk/PLC.h @@ -0,0 +1,62 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifndef SILK_PLC_H +#define SILK_PLC_H + +#include "main.h" + +#define BWE_COEF 0.99 +#define V_PITCH_GAIN_START_MIN_Q14 11469 /* 0.7 in Q14 */ +#define V_PITCH_GAIN_START_MAX_Q14 15565 /* 0.95 in Q14 */ +#define MAX_PITCH_LAG_MS 18 +#define RAND_BUF_SIZE 128 +#define RAND_BUF_MASK ( RAND_BUF_SIZE - 1 ) +#define LOG2_INV_LPC_GAIN_HIGH_THRES 3 /* 2^3 = 8 dB LPC gain */ +#define LOG2_INV_LPC_GAIN_LOW_THRES 8 /* 2^8 = 24 dB LPC gain */ +#define PITCH_DRIFT_FAC_Q16 655 /* 0.01 in Q16 */ + +void silk_PLC_Reset( + silk_decoder_state *psDec /* I/O Decoder state */ +); + +void silk_PLC( + silk_decoder_state *psDec, /* I/O Decoder state */ + silk_decoder_control *psDecCtrl, /* I/O Decoder control */ + opus_int16 frame[], /* I/O signal */ + opus_int lost, /* I Loss flag */ + int arch /* I Run-time architecture */ +); + +void silk_PLC_glue_frames( + silk_decoder_state *psDec, /* I/O decoder state */ + opus_int16 frame[], /* I/O signal */ + opus_int length /* I length of signal */ +); + +#endif + diff --git a/extern/opus/silk/SigProc_FIX.h b/extern/opus/silk/SigProc_FIX.h new file mode 100644 index 0000000..f9ae326 --- /dev/null +++ b/extern/opus/silk/SigProc_FIX.h @@ -0,0 +1,641 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifndef SILK_SIGPROC_FIX_H +#define SILK_SIGPROC_FIX_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/*#define silk_MACRO_COUNT */ /* Used to enable WMOPS counting */ + +#define SILK_MAX_ORDER_LPC 24 /* max order of the LPC analysis in schur() and k2a() */ + +#include /* for memset(), memcpy(), memmove() */ +#include "typedef.h" +#include "resampler_structs.h" +#include "macros.h" +#include "cpu_support.h" + +#if defined(OPUS_X86_MAY_HAVE_SSE4_1) +#include "x86/SigProc_FIX_sse.h" +#endif + +#if (defined(OPUS_ARM_ASM) || defined(OPUS_ARM_MAY_HAVE_NEON_INTR)) +#include "arm/biquad_alt_arm.h" +#include "arm/LPC_inv_pred_gain_arm.h" +#endif + +/********************************************************************/ +/* SIGNAL PROCESSING FUNCTIONS */ +/********************************************************************/ + +/*! + * Initialize/reset the resampler state for a given pair of input/output sampling rates +*/ +opus_int silk_resampler_init( + silk_resampler_state_struct *S, /* I/O Resampler state */ + opus_int32 Fs_Hz_in, /* I Input sampling rate (Hz) */ + opus_int32 Fs_Hz_out, /* I Output sampling rate (Hz) */ + opus_int forEnc /* I If 1: encoder; if 0: decoder */ +); + +/*! + * Resampler: convert from one sampling rate to another + */ +opus_int silk_resampler( + silk_resampler_state_struct *S, /* I/O Resampler state */ + opus_int16 out[], /* O Output signal */ + const opus_int16 in[], /* I Input signal */ + opus_int32 inLen /* I Number of input samples */ +); + +/*! +* Downsample 2x, mediocre quality +*/ +void silk_resampler_down2( + opus_int32 *S, /* I/O State vector [ 2 ] */ + opus_int16 *out, /* O Output signal [ len ] */ + const opus_int16 *in, /* I Input signal [ floor(len/2) ] */ + opus_int32 inLen /* I Number of input samples */ +); + +/*! + * Downsample by a factor 2/3, low quality +*/ +void silk_resampler_down2_3( + opus_int32 *S, /* I/O State vector [ 6 ] */ + opus_int16 *out, /* O Output signal [ floor(2*inLen/3) ] */ + const opus_int16 *in, /* I Input signal [ inLen ] */ + opus_int32 inLen /* I Number of input samples */ +); + +/*! + * second order ARMA filter; + * slower than biquad() but uses more precise coefficients + * can handle (slowly) varying coefficients + */ +void silk_biquad_alt_stride1( + const opus_int16 *in, /* I input signal */ + const opus_int32 *B_Q28, /* I MA coefficients [3] */ + const opus_int32 *A_Q28, /* I AR coefficients [2] */ + opus_int32 *S, /* I/O State vector [2] */ + opus_int16 *out, /* O output signal */ + const opus_int32 len /* I signal length (must be even) */ +); + +void silk_biquad_alt_stride2_c( + const opus_int16 *in, /* I input signal */ + const opus_int32 *B_Q28, /* I MA coefficients [3] */ + const opus_int32 *A_Q28, /* I AR coefficients [2] */ + opus_int32 *S, /* I/O State vector [4] */ + opus_int16 *out, /* O output signal */ + const opus_int32 len /* I signal length (must be even) */ +); + +/* Variable order MA prediction error filter. */ +void silk_LPC_analysis_filter( + opus_int16 *out, /* O Output signal */ + const opus_int16 *in, /* I Input signal */ + const opus_int16 *B, /* I MA prediction coefficients, Q12 [order] */ + const opus_int32 len, /* I Signal length */ + const opus_int32 d, /* I Filter order */ + int arch /* I Run-time architecture */ +); + +/* Chirp (bandwidth expand) LP AR filter */ +void silk_bwexpander( + opus_int16 *ar, /* I/O AR filter to be expanded (without leading 1) */ + const opus_int d, /* I Length of ar */ + opus_int32 chirp_Q16 /* I Chirp factor (typically in the range 0 to 1) */ +); + +/* Chirp (bandwidth expand) LP AR filter */ +void silk_bwexpander_32( + opus_int32 *ar, /* I/O AR filter to be expanded (without leading 1) */ + const opus_int d, /* I Length of ar */ + opus_int32 chirp_Q16 /* I Chirp factor in Q16 */ +); + +/* Compute inverse of LPC prediction gain, and */ +/* test if LPC coefficients are stable (all poles within unit circle) */ +opus_int32 silk_LPC_inverse_pred_gain_c( /* O Returns inverse prediction gain in energy domain, Q30 */ + const opus_int16 *A_Q12, /* I Prediction coefficients, Q12 [order] */ + const opus_int order /* I Prediction order */ +); + +/* Split signal in two decimated bands using first-order allpass filters */ +void silk_ana_filt_bank_1( + const opus_int16 *in, /* I Input signal [N] */ + opus_int32 *S, /* I/O State vector [2] */ + opus_int16 *outL, /* O Low band [N/2] */ + opus_int16 *outH, /* O High band [N/2] */ + const opus_int32 N /* I Number of input samples */ +); + +#if !defined(OVERRIDE_silk_biquad_alt_stride2) +#define silk_biquad_alt_stride2(in, B_Q28, A_Q28, S, out, len, arch) ((void)(arch), silk_biquad_alt_stride2_c(in, B_Q28, A_Q28, S, out, len)) +#endif + +#if !defined(OVERRIDE_silk_LPC_inverse_pred_gain) +#define silk_LPC_inverse_pred_gain(A_Q12, order, arch) ((void)(arch), silk_LPC_inverse_pred_gain_c(A_Q12, order)) +#endif + +/********************************************************************/ +/* SCALAR FUNCTIONS */ +/********************************************************************/ + +/* Approximation of 128 * log2() (exact inverse of approx 2^() below) */ +/* Convert input to a log scale */ +opus_int32 silk_lin2log( + const opus_int32 inLin /* I input in linear scale */ +); + +/* Approximation of a sigmoid function */ +opus_int silk_sigm_Q15( + opus_int in_Q5 /* I */ +); + +/* Approximation of 2^() (exact inverse of approx log2() above) */ +/* Convert input to a linear scale */ +opus_int32 silk_log2lin( + const opus_int32 inLog_Q7 /* I input on log scale */ +); + +/* Compute number of bits to right shift the sum of squares of a vector */ +/* of int16s to make it fit in an int32 */ +void silk_sum_sqr_shift( + opus_int32 *energy, /* O Energy of x, after shifting to the right */ + opus_int *shift, /* O Number of bits right shift applied to energy */ + const opus_int16 *x, /* I Input vector */ + opus_int len /* I Length of input vector */ +); + +/* Calculates the reflection coefficients from the correlation sequence */ +/* Faster than schur64(), but much less accurate. */ +/* uses SMLAWB(), requiring armv5E and higher. */ +opus_int32 silk_schur( /* O Returns residual energy */ + opus_int16 *rc_Q15, /* O reflection coefficients [order] Q15 */ + const opus_int32 *c, /* I correlations [order+1] */ + const opus_int32 order /* I prediction order */ +); + +/* Calculates the reflection coefficients from the correlation sequence */ +/* Slower than schur(), but more accurate. */ +/* Uses SMULL(), available on armv4 */ +opus_int32 silk_schur64( /* O returns residual energy */ + opus_int32 rc_Q16[], /* O Reflection coefficients [order] Q16 */ + const opus_int32 c[], /* I Correlations [order+1] */ + opus_int32 order /* I Prediction order */ +); + +/* Step up function, converts reflection coefficients to prediction coefficients */ +void silk_k2a( + opus_int32 *A_Q24, /* O Prediction coefficients [order] Q24 */ + const opus_int16 *rc_Q15, /* I Reflection coefficients [order] Q15 */ + const opus_int32 order /* I Prediction order */ +); + +/* Step up function, converts reflection coefficients to prediction coefficients */ +void silk_k2a_Q16( + opus_int32 *A_Q24, /* O Prediction coefficients [order] Q24 */ + const opus_int32 *rc_Q16, /* I Reflection coefficients [order] Q16 */ + const opus_int32 order /* I Prediction order */ +); + +/* Apply sine window to signal vector. */ +/* Window types: */ +/* 1 -> sine window from 0 to pi/2 */ +/* 2 -> sine window from pi/2 to pi */ +/* every other sample of window is linearly interpolated, for speed */ +void silk_apply_sine_window( + opus_int16 px_win[], /* O Pointer to windowed signal */ + const opus_int16 px[], /* I Pointer to input signal */ + const opus_int win_type, /* I Selects a window type */ + const opus_int length /* I Window length, multiple of 4 */ +); + +/* Compute autocorrelation */ +void silk_autocorr( + opus_int32 *results, /* O Result (length correlationCount) */ + opus_int *scale, /* O Scaling of the correlation vector */ + const opus_int16 *inputData, /* I Input data to correlate */ + const opus_int inputDataSize, /* I Length of input */ + const opus_int correlationCount, /* I Number of correlation taps to compute */ + int arch /* I Run-time architecture */ +); + +void silk_decode_pitch( + opus_int16 lagIndex, /* I */ + opus_int8 contourIndex, /* O */ + opus_int pitch_lags[], /* O 4 pitch values */ + const opus_int Fs_kHz, /* I sampling frequency (kHz) */ + const opus_int nb_subfr /* I number of sub frames */ +); + +opus_int silk_pitch_analysis_core( /* O Voicing estimate: 0 voiced, 1 unvoiced */ + const opus_int16 *frame, /* I Signal of length PE_FRAME_LENGTH_MS*Fs_kHz */ + opus_int *pitch_out, /* O 4 pitch lag values */ + opus_int16 *lagIndex, /* O Lag Index */ + opus_int8 *contourIndex, /* O Pitch contour Index */ + opus_int *LTPCorr_Q15, /* I/O Normalized correlation; input: value from previous frame */ + opus_int prevLag, /* I Last lag of previous frame; set to zero is unvoiced */ + const opus_int32 search_thres1_Q16, /* I First stage threshold for lag candidates 0 - 1 */ + const opus_int search_thres2_Q13, /* I Final threshold for lag candidates 0 - 1 */ + const opus_int Fs_kHz, /* I Sample frequency (kHz) */ + const opus_int complexity, /* I Complexity setting, 0-2, where 2 is highest */ + const opus_int nb_subfr, /* I number of 5 ms subframes */ + int arch /* I Run-time architecture */ +); + +/* Compute Normalized Line Spectral Frequencies (NLSFs) from whitening filter coefficients */ +/* If not all roots are found, the a_Q16 coefficients are bandwidth expanded until convergence. */ +void silk_A2NLSF( + opus_int16 *NLSF, /* O Normalized Line Spectral Frequencies in Q15 (0..2^15-1) [d] */ + opus_int32 *a_Q16, /* I/O Monic whitening filter coefficients in Q16 [d] */ + const opus_int d /* I Filter order (must be even) */ +); + +/* compute whitening filter coefficients from normalized line spectral frequencies */ +void silk_NLSF2A( + opus_int16 *a_Q12, /* O monic whitening filter coefficients in Q12, [ d ] */ + const opus_int16 *NLSF, /* I normalized line spectral frequencies in Q15, [ d ] */ + const opus_int d, /* I filter order (should be even) */ + int arch /* I Run-time architecture */ +); + +/* Convert int32 coefficients to int16 coefs and make sure there's no wrap-around */ +void silk_LPC_fit( + opus_int16 *a_QOUT, /* O Output signal */ + opus_int32 *a_QIN, /* I/O Input signal */ + const opus_int QOUT, /* I Input Q domain */ + const opus_int QIN, /* I Input Q domain */ + const opus_int d /* I Filter order */ +); + +void silk_insertion_sort_increasing( + opus_int32 *a, /* I/O Unsorted / Sorted vector */ + opus_int *idx, /* O Index vector for the sorted elements */ + const opus_int L, /* I Vector length */ + const opus_int K /* I Number of correctly sorted positions */ +); + +void silk_insertion_sort_decreasing_int16( + opus_int16 *a, /* I/O Unsorted / Sorted vector */ + opus_int *idx, /* O Index vector for the sorted elements */ + const opus_int L, /* I Vector length */ + const opus_int K /* I Number of correctly sorted positions */ +); + +void silk_insertion_sort_increasing_all_values_int16( + opus_int16 *a, /* I/O Unsorted / Sorted vector */ + const opus_int L /* I Vector length */ +); + +/* NLSF stabilizer, for a single input data vector */ +void silk_NLSF_stabilize( + opus_int16 *NLSF_Q15, /* I/O Unstable/stabilized normalized LSF vector in Q15 [L] */ + const opus_int16 *NDeltaMin_Q15, /* I Min distance vector, NDeltaMin_Q15[L] must be >= 1 [L+1] */ + const opus_int L /* I Number of NLSF parameters in the input vector */ +); + +/* Laroia low complexity NLSF weights */ +void silk_NLSF_VQ_weights_laroia( + opus_int16 *pNLSFW_Q_OUT, /* O Pointer to input vector weights [D] */ + const opus_int16 *pNLSF_Q15, /* I Pointer to input vector [D] */ + const opus_int D /* I Input vector dimension (even) */ +); + +/* Compute reflection coefficients from input signal */ +void silk_burg_modified_c( + opus_int32 *res_nrg, /* O Residual energy */ + opus_int *res_nrg_Q, /* O Residual energy Q value */ + opus_int32 A_Q16[], /* O Prediction coefficients (length order) */ + const opus_int16 x[], /* I Input signal, length: nb_subfr * ( D + subfr_length ) */ + const opus_int32 minInvGain_Q30, /* I Inverse of max prediction gain */ + const opus_int subfr_length, /* I Input signal subframe length (incl. D preceding samples) */ + const opus_int nb_subfr, /* I Number of subframes stacked in x */ + const opus_int D, /* I Order */ + int arch /* I Run-time architecture */ +); + +/* Copy and multiply a vector by a constant */ +void silk_scale_copy_vector16( + opus_int16 *data_out, + const opus_int16 *data_in, + opus_int32 gain_Q16, /* I Gain in Q16 */ + const opus_int dataSize /* I Length */ +); + +/* Some for the LTP related function requires Q26 to work.*/ +void silk_scale_vector32_Q26_lshift_18( + opus_int32 *data1, /* I/O Q0/Q18 */ + opus_int32 gain_Q26, /* I Q26 */ + opus_int dataSize /* I length */ +); + +/********************************************************************/ +/* INLINE ARM MATH */ +/********************************************************************/ + +/* return sum( inVec1[i] * inVec2[i] ) */ + +opus_int32 silk_inner_prod_aligned( + const opus_int16 *const inVec1, /* I input vector 1 */ + const opus_int16 *const inVec2, /* I input vector 2 */ + const opus_int len, /* I vector lengths */ + int arch /* I Run-time architecture */ +); + + +opus_int32 silk_inner_prod_aligned_scale( + const opus_int16 *const inVec1, /* I input vector 1 */ + const opus_int16 *const inVec2, /* I input vector 2 */ + const opus_int scale, /* I number of bits to shift */ + const opus_int len /* I vector lengths */ +); + +opus_int64 silk_inner_prod16_aligned_64_c( + const opus_int16 *inVec1, /* I input vector 1 */ + const opus_int16 *inVec2, /* I input vector 2 */ + const opus_int len /* I vector lengths */ +); + +/********************************************************************/ +/* MACROS */ +/********************************************************************/ + +/* Rotate a32 right by 'rot' bits. Negative rot values result in rotating + left. Output is 32bit int. + Note: contemporary compilers recognize the C expression below and + compile it into a 'ror' instruction if available. No need for OPUS_INLINE ASM! */ +static OPUS_INLINE opus_int32 silk_ROR32( opus_int32 a32, opus_int rot ) +{ + opus_uint32 x = (opus_uint32) a32; + opus_uint32 r = (opus_uint32) rot; + opus_uint32 m = (opus_uint32) -rot; + if( rot == 0 ) { + return a32; + } else if( rot < 0 ) { + return (opus_int32) ((x << m) | (x >> (32 - m))); + } else { + return (opus_int32) ((x << (32 - r)) | (x >> r)); + } +} + +/* Allocate opus_int16 aligned to 4-byte memory address */ +#if EMBEDDED_ARM +#define silk_DWORD_ALIGN __attribute__((aligned(4))) +#else +#define silk_DWORD_ALIGN +#endif + +/* Useful Macros that can be adjusted to other platforms */ +#define silk_memcpy(dest, src, size) memcpy((dest), (src), (size)) +#define silk_memset(dest, src, size) memset((dest), (src), (size)) +#define silk_memmove(dest, src, size) memmove((dest), (src), (size)) + +/* Fixed point macros */ + +/* (a32 * b32) output have to be 32bit int */ +#define silk_MUL(a32, b32) ((a32) * (b32)) + +/* (a32 * b32) output have to be 32bit uint */ +#define silk_MUL_uint(a32, b32) silk_MUL(a32, b32) + +/* a32 + (b32 * c32) output have to be 32bit int */ +#define silk_MLA(a32, b32, c32) silk_ADD32((a32),((b32) * (c32))) + +/* a32 + (b32 * c32) output have to be 32bit uint */ +#define silk_MLA_uint(a32, b32, c32) silk_MLA(a32, b32, c32) + +/* ((a32 >> 16) * (b32 >> 16)) output have to be 32bit int */ +#define silk_SMULTT(a32, b32) (((a32) >> 16) * ((b32) >> 16)) + +/* a32 + ((a32 >> 16) * (b32 >> 16)) output have to be 32bit int */ +#define silk_SMLATT(a32, b32, c32) silk_ADD32((a32),((b32) >> 16) * ((c32) >> 16)) + +#define silk_SMLALBB(a64, b16, c16) silk_ADD64((a64),(opus_int64)((opus_int32)(b16) * (opus_int32)(c16))) + +/* (a32 * b32) */ +#define silk_SMULL(a32, b32) ((opus_int64)(a32) * /*(opus_int64)*/(b32)) + +/* Adds two signed 32-bit values in a way that can overflow, while not relying on undefined behaviour + (just standard two's complement implementation-specific behaviour) */ +#define silk_ADD32_ovflw(a, b) ((opus_int32)((opus_uint32)(a) + (opus_uint32)(b))) +/* Subtractss two signed 32-bit values in a way that can overflow, while not relying on undefined behaviour + (just standard two's complement implementation-specific behaviour) */ +#define silk_SUB32_ovflw(a, b) ((opus_int32)((opus_uint32)(a) - (opus_uint32)(b))) + +/* Multiply-accumulate macros that allow overflow in the addition (ie, no asserts in debug mode) */ +#define silk_MLA_ovflw(a32, b32, c32) silk_ADD32_ovflw((a32), (opus_uint32)(b32) * (opus_uint32)(c32)) +#define silk_SMLABB_ovflw(a32, b32, c32) (silk_ADD32_ovflw((a32) , ((opus_int32)((opus_int16)(b32))) * (opus_int32)((opus_int16)(c32)))) + +#define silk_DIV32_16(a32, b16) ((opus_int32)((a32) / (b16))) +#define silk_DIV32(a32, b32) ((opus_int32)((a32) / (b32))) + +/* These macros enables checking for overflow in silk_API_Debug.h*/ +#define silk_ADD16(a, b) ((a) + (b)) +#define silk_ADD32(a, b) ((a) + (b)) +#define silk_ADD64(a, b) ((a) + (b)) + +#define silk_SUB16(a, b) ((a) - (b)) +#define silk_SUB32(a, b) ((a) - (b)) +#define silk_SUB64(a, b) ((a) - (b)) + +#define silk_SAT8(a) ((a) > silk_int8_MAX ? silk_int8_MAX : \ + ((a) < silk_int8_MIN ? silk_int8_MIN : (a))) +#define silk_SAT16(a) ((a) > silk_int16_MAX ? silk_int16_MAX : \ + ((a) < silk_int16_MIN ? silk_int16_MIN : (a))) +#define silk_SAT32(a) ((a) > silk_int32_MAX ? silk_int32_MAX : \ + ((a) < silk_int32_MIN ? silk_int32_MIN : (a))) + +#define silk_CHECK_FIT8(a) (a) +#define silk_CHECK_FIT16(a) (a) +#define silk_CHECK_FIT32(a) (a) + +#define silk_ADD_SAT16(a, b) (opus_int16)silk_SAT16( silk_ADD32( (opus_int32)(a), (b) ) ) +#define silk_ADD_SAT64(a, b) ((((a) + (b)) & 0x8000000000000000LL) == 0 ? \ + ((((a) & (b)) & 0x8000000000000000LL) != 0 ? silk_int64_MIN : (a)+(b)) : \ + ((((a) | (b)) & 0x8000000000000000LL) == 0 ? silk_int64_MAX : (a)+(b)) ) + +#define silk_SUB_SAT16(a, b) (opus_int16)silk_SAT16( silk_SUB32( (opus_int32)(a), (b) ) ) +#define silk_SUB_SAT64(a, b) ((((a)-(b)) & 0x8000000000000000LL) == 0 ? \ + (( (a) & ((b)^0x8000000000000000LL) & 0x8000000000000000LL) ? silk_int64_MIN : (a)-(b)) : \ + ((((a)^0x8000000000000000LL) & (b) & 0x8000000000000000LL) ? silk_int64_MAX : (a)-(b)) ) + +/* Saturation for positive input values */ +#define silk_POS_SAT32(a) ((a) > silk_int32_MAX ? silk_int32_MAX : (a)) + +/* Add with saturation for positive input values */ +#define silk_ADD_POS_SAT8(a, b) ((((a)+(b)) & 0x80) ? silk_int8_MAX : ((a)+(b))) +#define silk_ADD_POS_SAT16(a, b) ((((a)+(b)) & 0x8000) ? silk_int16_MAX : ((a)+(b))) +#define silk_ADD_POS_SAT32(a, b) ((((opus_uint32)(a)+(opus_uint32)(b)) & 0x80000000) ? silk_int32_MAX : ((a)+(b))) + +#define silk_LSHIFT8(a, shift) ((opus_int8)((opus_uint8)(a)<<(shift))) /* shift >= 0, shift < 8 */ +#define silk_LSHIFT16(a, shift) ((opus_int16)((opus_uint16)(a)<<(shift))) /* shift >= 0, shift < 16 */ +#define silk_LSHIFT32(a, shift) ((opus_int32)((opus_uint32)(a)<<(shift))) /* shift >= 0, shift < 32 */ +#define silk_LSHIFT64(a, shift) ((opus_int64)((opus_uint64)(a)<<(shift))) /* shift >= 0, shift < 64 */ +#define silk_LSHIFT(a, shift) silk_LSHIFT32(a, shift) /* shift >= 0, shift < 32 */ + +#define silk_RSHIFT8(a, shift) ((a)>>(shift)) /* shift >= 0, shift < 8 */ +#define silk_RSHIFT16(a, shift) ((a)>>(shift)) /* shift >= 0, shift < 16 */ +#define silk_RSHIFT32(a, shift) ((a)>>(shift)) /* shift >= 0, shift < 32 */ +#define silk_RSHIFT64(a, shift) ((a)>>(shift)) /* shift >= 0, shift < 64 */ +#define silk_RSHIFT(a, shift) silk_RSHIFT32(a, shift) /* shift >= 0, shift < 32 */ + +/* saturates before shifting */ +#define silk_LSHIFT_SAT32(a, shift) (silk_LSHIFT32( silk_LIMIT( (a), silk_RSHIFT32( silk_int32_MIN, (shift) ), \ + silk_RSHIFT32( silk_int32_MAX, (shift) ) ), (shift) )) + +#define silk_LSHIFT_ovflw(a, shift) ((opus_int32)((opus_uint32)(a) << (shift))) /* shift >= 0, allowed to overflow */ +#define silk_LSHIFT_uint(a, shift) ((a) << (shift)) /* shift >= 0 */ +#define silk_RSHIFT_uint(a, shift) ((a) >> (shift)) /* shift >= 0 */ + +#define silk_ADD_LSHIFT(a, b, shift) ((a) + silk_LSHIFT((b), (shift))) /* shift >= 0 */ +#define silk_ADD_LSHIFT32(a, b, shift) silk_ADD32((a), silk_LSHIFT32((b), (shift))) /* shift >= 0 */ +#define silk_ADD_LSHIFT_uint(a, b, shift) ((a) + silk_LSHIFT_uint((b), (shift))) /* shift >= 0 */ +#define silk_ADD_RSHIFT(a, b, shift) ((a) + silk_RSHIFT((b), (shift))) /* shift >= 0 */ +#define silk_ADD_RSHIFT32(a, b, shift) silk_ADD32((a), silk_RSHIFT32((b), (shift))) /* shift >= 0 */ +#define silk_ADD_RSHIFT_uint(a, b, shift) ((a) + silk_RSHIFT_uint((b), (shift))) /* shift >= 0 */ +#define silk_SUB_LSHIFT32(a, b, shift) silk_SUB32((a), silk_LSHIFT32((b), (shift))) /* shift >= 0 */ +#define silk_SUB_RSHIFT32(a, b, shift) silk_SUB32((a), silk_RSHIFT32((b), (shift))) /* shift >= 0 */ + +/* Requires that shift > 0 */ +#define silk_RSHIFT_ROUND(a, shift) ((shift) == 1 ? ((a) >> 1) + ((a) & 1) : (((a) >> ((shift) - 1)) + 1) >> 1) +#define silk_RSHIFT_ROUND64(a, shift) ((shift) == 1 ? ((a) >> 1) + ((a) & 1) : (((a) >> ((shift) - 1)) + 1) >> 1) + +/* Number of rightshift required to fit the multiplication */ +#define silk_NSHIFT_MUL_32_32(a, b) ( -(31- (32-silk_CLZ32(silk_abs(a)) + (32-silk_CLZ32(silk_abs(b))))) ) +#define silk_NSHIFT_MUL_16_16(a, b) ( -(15- (16-silk_CLZ16(silk_abs(a)) + (16-silk_CLZ16(silk_abs(b))))) ) + + +#define silk_min(a, b) (((a) < (b)) ? (a) : (b)) +#define silk_max(a, b) (((a) > (b)) ? (a) : (b)) + +/* Macro to convert floating-point constants to fixed-point */ +#define SILK_FIX_CONST( C, Q ) ((opus_int32)((C) * ((opus_int64)1 << (Q)) + 0.5)) + +/* silk_min() versions with typecast in the function call */ +static OPUS_INLINE opus_int silk_min_int(opus_int a, opus_int b) +{ + return (((a) < (b)) ? (a) : (b)); +} +static OPUS_INLINE opus_int16 silk_min_16(opus_int16 a, opus_int16 b) +{ + return (((a) < (b)) ? (a) : (b)); +} +static OPUS_INLINE opus_int32 silk_min_32(opus_int32 a, opus_int32 b) +{ + return (((a) < (b)) ? (a) : (b)); +} +static OPUS_INLINE opus_int64 silk_min_64(opus_int64 a, opus_int64 b) +{ + return (((a) < (b)) ? (a) : (b)); +} + +/* silk_min() versions with typecast in the function call */ +static OPUS_INLINE opus_int silk_max_int(opus_int a, opus_int b) +{ + return (((a) > (b)) ? (a) : (b)); +} +static OPUS_INLINE opus_int16 silk_max_16(opus_int16 a, opus_int16 b) +{ + return (((a) > (b)) ? (a) : (b)); +} +static OPUS_INLINE opus_int32 silk_max_32(opus_int32 a, opus_int32 b) +{ + return (((a) > (b)) ? (a) : (b)); +} +static OPUS_INLINE opus_int64 silk_max_64(opus_int64 a, opus_int64 b) +{ + return (((a) > (b)) ? (a) : (b)); +} + +#define silk_LIMIT( a, limit1, limit2) ((limit1) > (limit2) ? ((a) > (limit1) ? (limit1) : ((a) < (limit2) ? (limit2) : (a))) \ + : ((a) > (limit2) ? (limit2) : ((a) < (limit1) ? (limit1) : (a)))) + +#define silk_LIMIT_int silk_LIMIT +#define silk_LIMIT_16 silk_LIMIT +#define silk_LIMIT_32 silk_LIMIT + +#define silk_abs(a) (((a) > 0) ? (a) : -(a)) /* Be careful, silk_abs returns wrong when input equals to silk_intXX_MIN */ +#define silk_abs_int(a) (((a) ^ ((a) >> (8 * sizeof(a) - 1))) - ((a) >> (8 * sizeof(a) - 1))) +#define silk_abs_int32(a) (((a) ^ ((a) >> 31)) - ((a) >> 31)) +#define silk_abs_int64(a) (((a) > 0) ? (a) : -(a)) + +#define silk_sign(a) ((a) > 0 ? 1 : ( (a) < 0 ? -1 : 0 )) + +/* PSEUDO-RANDOM GENERATOR */ +/* Make sure to store the result as the seed for the next call (also in between */ +/* frames), otherwise result won't be random at all. When only using some of the */ +/* bits, take the most significant bits by right-shifting. */ +#define RAND_MULTIPLIER 196314165 +#define RAND_INCREMENT 907633515 +#define silk_RAND(seed) (silk_MLA_ovflw((RAND_INCREMENT), (seed), (RAND_MULTIPLIER))) + +/* Add some multiplication functions that can be easily mapped to ARM. */ + +/* silk_SMMUL: Signed top word multiply. + ARMv6 2 instruction cycles. + ARMv3M+ 3 instruction cycles. use SMULL and ignore LSB registers.(except xM)*/ +/*#define silk_SMMUL(a32, b32) (opus_int32)silk_RSHIFT(silk_SMLAL(silk_SMULWB((a32), (b32)), (a32), silk_RSHIFT_ROUND((b32), 16)), 16)*/ +/* the following seems faster on x86 */ +#define silk_SMMUL(a32, b32) (opus_int32)silk_RSHIFT64(silk_SMULL((a32), (b32)), 32) + +#if !defined(OPUS_X86_MAY_HAVE_SSE4_1) +#define silk_burg_modified(res_nrg, res_nrg_Q, A_Q16, x, minInvGain_Q30, subfr_length, nb_subfr, D, arch) \ + ((void)(arch), silk_burg_modified_c(res_nrg, res_nrg_Q, A_Q16, x, minInvGain_Q30, subfr_length, nb_subfr, D, arch)) + +#define silk_inner_prod16_aligned_64(inVec1, inVec2, len, arch) \ + ((void)(arch),silk_inner_prod16_aligned_64_c(inVec1, inVec2, len)) +#endif + +#include "Inlines.h" +#include "MacroCount.h" +#include "MacroDebug.h" + +#ifdef OPUS_ARM_INLINE_ASM +#include "arm/SigProc_FIX_armv4.h" +#endif + +#ifdef OPUS_ARM_INLINE_EDSP +#include "arm/SigProc_FIX_armv5e.h" +#endif + +#if defined(MIPSr1_ASM) +#include "mips/sigproc_fix_mipsr1.h" +#endif + + +#ifdef __cplusplus +} +#endif + +#endif /* SILK_SIGPROC_FIX_H */ diff --git a/extern/opus/silk/VAD.c b/extern/opus/silk/VAD.c new file mode 100644 index 0000000..d0cda52 --- /dev/null +++ b/extern/opus/silk/VAD.c @@ -0,0 +1,360 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" +#include "stack_alloc.h" + +/* Silk VAD noise level estimation */ +# if !defined(OPUS_X86_MAY_HAVE_SSE4_1) +static OPUS_INLINE void silk_VAD_GetNoiseLevels( + const opus_int32 pX[ VAD_N_BANDS ], /* I subband energies */ + silk_VAD_state *psSilk_VAD /* I/O Pointer to Silk VAD state */ +); +#endif + +/**********************************/ +/* Initialization of the Silk VAD */ +/**********************************/ +opus_int silk_VAD_Init( /* O Return value, 0 if success */ + silk_VAD_state *psSilk_VAD /* I/O Pointer to Silk VAD state */ +) +{ + opus_int b, ret = 0; + + /* reset state memory */ + silk_memset( psSilk_VAD, 0, sizeof( silk_VAD_state ) ); + + /* init noise levels */ + /* Initialize array with approx pink noise levels (psd proportional to inverse of frequency) */ + for( b = 0; b < VAD_N_BANDS; b++ ) { + psSilk_VAD->NoiseLevelBias[ b ] = silk_max_32( silk_DIV32_16( VAD_NOISE_LEVELS_BIAS, b + 1 ), 1 ); + } + + /* Initialize state */ + for( b = 0; b < VAD_N_BANDS; b++ ) { + psSilk_VAD->NL[ b ] = silk_MUL( 100, psSilk_VAD->NoiseLevelBias[ b ] ); + psSilk_VAD->inv_NL[ b ] = silk_DIV32( silk_int32_MAX, psSilk_VAD->NL[ b ] ); + } + psSilk_VAD->counter = 15; + + /* init smoothed energy-to-noise ratio*/ + for( b = 0; b < VAD_N_BANDS; b++ ) { + psSilk_VAD->NrgRatioSmth_Q8[ b ] = 100 * 256; /* 100 * 256 --> 20 dB SNR */ + } + + return( ret ); +} + +/* Weighting factors for tilt measure */ +static const opus_int32 tiltWeights[ VAD_N_BANDS ] = { 30000, 6000, -12000, -12000 }; + +/***************************************/ +/* Get the speech activity level in Q8 */ +/***************************************/ +opus_int silk_VAD_GetSA_Q8_c( /* O Return value, 0 if success */ + silk_encoder_state *psEncC, /* I/O Encoder state */ + const opus_int16 pIn[] /* I PCM input */ +) +{ + opus_int SA_Q15, pSNR_dB_Q7, input_tilt; + opus_int decimated_framelength1, decimated_framelength2; + opus_int decimated_framelength; + opus_int dec_subframe_length, dec_subframe_offset, SNR_Q7, i, b, s; + opus_int32 sumSquared, smooth_coef_Q16; + opus_int16 HPstateTmp; + VARDECL( opus_int16, X ); + opus_int32 Xnrg[ VAD_N_BANDS ]; + opus_int32 NrgToNoiseRatio_Q8[ VAD_N_BANDS ]; + opus_int32 speech_nrg, x_tmp; + opus_int X_offset[ VAD_N_BANDS ]; + opus_int ret = 0; + silk_VAD_state *psSilk_VAD = &psEncC->sVAD; + SAVE_STACK; + + /* Safety checks */ + silk_assert( VAD_N_BANDS == 4 ); + celt_assert( MAX_FRAME_LENGTH >= psEncC->frame_length ); + celt_assert( psEncC->frame_length <= 512 ); + celt_assert( psEncC->frame_length == 8 * silk_RSHIFT( psEncC->frame_length, 3 ) ); + + /***********************/ + /* Filter and Decimate */ + /***********************/ + decimated_framelength1 = silk_RSHIFT( psEncC->frame_length, 1 ); + decimated_framelength2 = silk_RSHIFT( psEncC->frame_length, 2 ); + decimated_framelength = silk_RSHIFT( psEncC->frame_length, 3 ); + /* Decimate into 4 bands: + 0 L 3L L 3L 5L + - -- - -- -- + 8 8 2 4 4 + + [0-1 kHz| temp. |1-2 kHz| 2-4 kHz | 4-8 kHz | + + They're arranged to allow the minimal ( frame_length / 4 ) extra + scratch space during the downsampling process */ + 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; + ALLOC( X, X_offset[ 3 ] + decimated_framelength1, opus_int16 ); + + /* 0-8 kHz to 0-4 kHz and 4-8 kHz */ + silk_ana_filt_bank_1( pIn, &psSilk_VAD->AnaState[ 0 ], + X, &X[ X_offset[ 3 ] ], psEncC->frame_length ); + + /* 0-4 kHz to 0-2 kHz and 2-4 kHz */ + silk_ana_filt_bank_1( X, &psSilk_VAD->AnaState1[ 0 ], + X, &X[ X_offset[ 2 ] ], decimated_framelength1 ); + + /* 0-2 kHz to 0-1 kHz and 1-2 kHz */ + silk_ana_filt_bank_1( X, &psSilk_VAD->AnaState2[ 0 ], + X, &X[ X_offset[ 1 ] ], decimated_framelength2 ); + + /*********************************************/ + /* HP filter on lowest band (differentiator) */ + /*********************************************/ + X[ decimated_framelength - 1 ] = silk_RSHIFT( X[ decimated_framelength - 1 ], 1 ); + HPstateTmp = X[ decimated_framelength - 1 ]; + for( i = decimated_framelength - 1; i > 0; i-- ) { + X[ i - 1 ] = silk_RSHIFT( X[ i - 1 ], 1 ); + X[ i ] -= X[ i - 1 ]; + } + X[ 0 ] -= psSilk_VAD->HPstate; + psSilk_VAD->HPstate = HPstateTmp; + + /*************************************/ + /* Calculate the energy in each band */ + /*************************************/ + for( b = 0; b < VAD_N_BANDS; b++ ) { + /* Find the decimated framelength in the non-uniformly divided bands */ + decimated_framelength = silk_RSHIFT( psEncC->frame_length, silk_min_int( VAD_N_BANDS - b, VAD_N_BANDS - 1 ) ); + + /* Split length into subframe lengths */ + dec_subframe_length = silk_RSHIFT( decimated_framelength, VAD_INTERNAL_SUBFRAMES_LOG2 ); + dec_subframe_offset = 0; + + /* Compute energy per sub-frame */ + /* initialize with summed energy of last subframe */ + Xnrg[ b ] = psSilk_VAD->XnrgSubfr[ b ]; + for( s = 0; s < VAD_INTERNAL_SUBFRAMES; s++ ) { + sumSquared = 0; + for( i = 0; i < dec_subframe_length; i++ ) { + /* The energy will be less than dec_subframe_length * ( silk_int16_MIN / 8 ) ^ 2. */ + /* Therefore we can accumulate with no risk of overflow (unless dec_subframe_length > 128) */ + x_tmp = silk_RSHIFT( + X[ X_offset[ b ] + i + dec_subframe_offset ], 3 ); + sumSquared = silk_SMLABB( sumSquared, x_tmp, x_tmp ); + + /* Safety check */ + silk_assert( sumSquared >= 0 ); + } + + /* Add/saturate summed energy of current subframe */ + if( s < VAD_INTERNAL_SUBFRAMES - 1 ) { + Xnrg[ b ] = silk_ADD_POS_SAT32( Xnrg[ b ], sumSquared ); + } else { + /* Look-ahead subframe */ + Xnrg[ b ] = silk_ADD_POS_SAT32( Xnrg[ b ], silk_RSHIFT( sumSquared, 1 ) ); + } + + dec_subframe_offset += dec_subframe_length; + } + psSilk_VAD->XnrgSubfr[ b ] = sumSquared; + } + + /********************/ + /* Noise estimation */ + /********************/ + silk_VAD_GetNoiseLevels( &Xnrg[ 0 ], psSilk_VAD ); + + /***********************************************/ + /* Signal-plus-noise to noise ratio estimation */ + /***********************************************/ + sumSquared = 0; + input_tilt = 0; + for( b = 0; b < VAD_N_BANDS; b++ ) { + speech_nrg = Xnrg[ b ] - psSilk_VAD->NL[ b ]; + if( speech_nrg > 0 ) { + /* Divide, with sufficient resolution */ + if( ( Xnrg[ b ] & 0xFF800000 ) == 0 ) { + NrgToNoiseRatio_Q8[ b ] = silk_DIV32( silk_LSHIFT( Xnrg[ b ], 8 ), psSilk_VAD->NL[ b ] + 1 ); + } else { + NrgToNoiseRatio_Q8[ b ] = silk_DIV32( Xnrg[ b ], silk_RSHIFT( psSilk_VAD->NL[ b ], 8 ) + 1 ); + } + + /* Convert to log domain */ + SNR_Q7 = silk_lin2log( NrgToNoiseRatio_Q8[ b ] ) - 8 * 128; + + /* Sum-of-squares */ + sumSquared = silk_SMLABB( sumSquared, SNR_Q7, SNR_Q7 ); /* Q14 */ + + /* Tilt measure */ + if( speech_nrg < ( (opus_int32)1 << 20 ) ) { + /* Scale down SNR value for small subband speech energies */ + SNR_Q7 = silk_SMULWB( silk_LSHIFT( silk_SQRT_APPROX( speech_nrg ), 6 ), SNR_Q7 ); + } + input_tilt = silk_SMLAWB( input_tilt, tiltWeights[ b ], SNR_Q7 ); + } else { + NrgToNoiseRatio_Q8[ b ] = 256; + } + } + + /* Mean-of-squares */ + sumSquared = silk_DIV32_16( sumSquared, VAD_N_BANDS ); /* Q14 */ + + /* Root-mean-square approximation, scale to dBs, and write to output pointer */ + pSNR_dB_Q7 = (opus_int16)( 3 * silk_SQRT_APPROX( sumSquared ) ); /* Q7 */ + + /*********************************/ + /* Speech Probability Estimation */ + /*********************************/ + SA_Q15 = silk_sigm_Q15( silk_SMULWB( VAD_SNR_FACTOR_Q16, pSNR_dB_Q7 ) - VAD_NEGATIVE_OFFSET_Q5 ); + + /**************************/ + /* Frequency Tilt Measure */ + /**************************/ + psEncC->input_tilt_Q15 = silk_LSHIFT( silk_sigm_Q15( input_tilt ) - 16384, 1 ); + + /**************************************************/ + /* Scale the sigmoid output based on power levels */ + /**************************************************/ + speech_nrg = 0; + for( b = 0; b < VAD_N_BANDS; b++ ) { + /* Accumulate signal-without-noise energies, higher frequency bands have more weight */ + speech_nrg += ( b + 1 ) * silk_RSHIFT( Xnrg[ b ] - psSilk_VAD->NL[ b ], 4 ); + } + + if( psEncC->frame_length == 20 * psEncC->fs_kHz ) { + speech_nrg = silk_RSHIFT32( speech_nrg, 1 ); + } + /* Power scaling */ + if( speech_nrg <= 0 ) { + SA_Q15 = silk_RSHIFT( SA_Q15, 1 ); + } else if( speech_nrg < 16384 ) { + speech_nrg = silk_LSHIFT32( speech_nrg, 16 ); + + /* square-root */ + speech_nrg = silk_SQRT_APPROX( speech_nrg ); + SA_Q15 = silk_SMULWB( 32768 + speech_nrg, SA_Q15 ); + } + + /* Copy the resulting speech activity in Q8 */ + psEncC->speech_activity_Q8 = silk_min_int( silk_RSHIFT( SA_Q15, 7 ), silk_uint8_MAX ); + + /***********************************/ + /* Energy Level and SNR estimation */ + /***********************************/ + /* Smoothing coefficient */ + smooth_coef_Q16 = silk_SMULWB( VAD_SNR_SMOOTH_COEF_Q18, silk_SMULWB( (opus_int32)SA_Q15, SA_Q15 ) ); + + if( psEncC->frame_length == 10 * psEncC->fs_kHz ) { + smooth_coef_Q16 >>= 1; + } + + for( b = 0; b < VAD_N_BANDS; b++ ) { + /* compute smoothed energy-to-noise ratio per band */ + psSilk_VAD->NrgRatioSmth_Q8[ b ] = silk_SMLAWB( psSilk_VAD->NrgRatioSmth_Q8[ b ], + NrgToNoiseRatio_Q8[ b ] - psSilk_VAD->NrgRatioSmth_Q8[ b ], smooth_coef_Q16 ); + + /* signal to noise ratio in dB per band */ + SNR_Q7 = 3 * ( silk_lin2log( psSilk_VAD->NrgRatioSmth_Q8[b] ) - 8 * 128 ); + /* quality = sigmoid( 0.25 * ( SNR_dB - 16 ) ); */ + psEncC->input_quality_bands_Q15[ b ] = silk_sigm_Q15( silk_RSHIFT( SNR_Q7 - 16 * 128, 4 ) ); + } + + RESTORE_STACK; + return( ret ); +} + +/**************************/ +/* Noise level estimation */ +/**************************/ +# if !defined(OPUS_X86_MAY_HAVE_SSE4_1) +static OPUS_INLINE +#endif +void silk_VAD_GetNoiseLevels( + const opus_int32 pX[ VAD_N_BANDS ], /* I subband energies */ + silk_VAD_state *psSilk_VAD /* I/O Pointer to Silk VAD state */ +) +{ + opus_int k; + opus_int32 nl, nrg, inv_nrg; + opus_int coef, min_coef; + + /* Initially faster smoothing */ + if( psSilk_VAD->counter < 1000 ) { /* 1000 = 20 sec */ + min_coef = silk_DIV32_16( silk_int16_MAX, silk_RSHIFT( psSilk_VAD->counter, 4 ) + 1 ); + /* Increment frame counter */ + psSilk_VAD->counter++; + } else { + min_coef = 0; + } + + for( k = 0; k < VAD_N_BANDS; k++ ) { + /* Get old noise level estimate for current band */ + nl = psSilk_VAD->NL[ k ]; + silk_assert( nl >= 0 ); + + /* Add bias */ + nrg = silk_ADD_POS_SAT32( pX[ k ], psSilk_VAD->NoiseLevelBias[ k ] ); + silk_assert( nrg > 0 ); + + /* Invert energies */ + inv_nrg = silk_DIV32( silk_int32_MAX, nrg ); + silk_assert( inv_nrg >= 0 ); + + /* Less update when subband energy is high */ + if( nrg > silk_LSHIFT( nl, 3 ) ) { + coef = VAD_NOISE_LEVEL_SMOOTH_COEF_Q16 >> 3; + } else if( nrg < nl ) { + coef = VAD_NOISE_LEVEL_SMOOTH_COEF_Q16; + } else { + coef = silk_SMULWB( silk_SMULWW( inv_nrg, nl ), VAD_NOISE_LEVEL_SMOOTH_COEF_Q16 << 1 ); + } + + /* Initially faster smoothing */ + coef = silk_max_int( coef, min_coef ); + + /* Smooth inverse energies */ + psSilk_VAD->inv_NL[ k ] = silk_SMLAWB( psSilk_VAD->inv_NL[ k ], inv_nrg - psSilk_VAD->inv_NL[ k ], coef ); + silk_assert( psSilk_VAD->inv_NL[ k ] >= 0 ); + + /* Compute noise level by inverting again */ + nl = silk_DIV32( silk_int32_MAX, psSilk_VAD->inv_NL[ k ] ); + silk_assert( nl >= 0 ); + + /* Limit noise levels (guarantee 7 bits of head room) */ + nl = silk_min( nl, 0x00FFFFFF ); + + /* Store as part of state */ + psSilk_VAD->NL[ k ] = nl; + } +} diff --git a/extern/opus/silk/VQ_WMat_EC.c b/extern/opus/silk/VQ_WMat_EC.c new file mode 100644 index 0000000..0f3d545 --- /dev/null +++ b/extern/opus/silk/VQ_WMat_EC.c @@ -0,0 +1,131 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/* Entropy constrained matrix-weighted VQ, hard-coded to 5-element vectors, for a single input data vector */ +void silk_VQ_WMat_EC_c( + opus_int8 *ind, /* O index of best codebook vector */ + opus_int32 *res_nrg_Q15, /* O best residual energy */ + opus_int32 *rate_dist_Q8, /* O best total bitrate */ + opus_int *gain_Q7, /* O sum of absolute LTP coefficients */ + const opus_int32 *XX_Q17, /* I correlation matrix */ + const opus_int32 *xX_Q17, /* I correlation vector */ + const opus_int8 *cb_Q7, /* I codebook */ + const opus_uint8 *cb_gain_Q7, /* I codebook effective gain */ + const opus_uint8 *cl_Q5, /* I code length for each codebook vector */ + const opus_int subfr_len, /* I number of samples per subframe */ + const opus_int32 max_gain_Q7, /* I maximum sum of absolute LTP coefficients */ + const opus_int L /* I number of vectors in codebook */ +) +{ + opus_int k, gain_tmp_Q7; + const opus_int8 *cb_row_Q7; + opus_int32 neg_xX_Q24[ 5 ]; + opus_int32 sum1_Q15, sum2_Q24; + opus_int32 bits_res_Q8, bits_tot_Q8; + + /* Negate and convert to new Q domain */ + neg_xX_Q24[ 0 ] = -silk_LSHIFT32( xX_Q17[ 0 ], 7 ); + neg_xX_Q24[ 1 ] = -silk_LSHIFT32( xX_Q17[ 1 ], 7 ); + neg_xX_Q24[ 2 ] = -silk_LSHIFT32( xX_Q17[ 2 ], 7 ); + neg_xX_Q24[ 3 ] = -silk_LSHIFT32( xX_Q17[ 3 ], 7 ); + neg_xX_Q24[ 4 ] = -silk_LSHIFT32( xX_Q17[ 4 ], 7 ); + + /* Loop over codebook */ + *rate_dist_Q8 = silk_int32_MAX; + *res_nrg_Q15 = silk_int32_MAX; + cb_row_Q7 = cb_Q7; + /* In things go really bad, at least *ind is set to something safe. */ + *ind = 0; + for( k = 0; k < L; k++ ) { + opus_int32 penalty; + gain_tmp_Q7 = cb_gain_Q7[k]; + /* Weighted rate */ + /* Quantization error: 1 - 2 * xX * cb + cb' * XX * cb */ + sum1_Q15 = SILK_FIX_CONST( 1.001, 15 ); + + /* Penalty for too large gain */ + penalty = silk_LSHIFT32( silk_max( silk_SUB32( gain_tmp_Q7, max_gain_Q7 ), 0 ), 11 ); + + /* first row of XX_Q17 */ + sum2_Q24 = silk_MLA( neg_xX_Q24[ 0 ], XX_Q17[ 1 ], cb_row_Q7[ 1 ] ); + sum2_Q24 = silk_MLA( sum2_Q24, XX_Q17[ 2 ], cb_row_Q7[ 2 ] ); + sum2_Q24 = silk_MLA( sum2_Q24, XX_Q17[ 3 ], cb_row_Q7[ 3 ] ); + sum2_Q24 = silk_MLA( sum2_Q24, XX_Q17[ 4 ], cb_row_Q7[ 4 ] ); + sum2_Q24 = silk_LSHIFT32( sum2_Q24, 1 ); + sum2_Q24 = silk_MLA( sum2_Q24, XX_Q17[ 0 ], cb_row_Q7[ 0 ] ); + sum1_Q15 = silk_SMLAWB( sum1_Q15, sum2_Q24, cb_row_Q7[ 0 ] ); + + /* second row of XX_Q17 */ + sum2_Q24 = silk_MLA( neg_xX_Q24[ 1 ], XX_Q17[ 7 ], cb_row_Q7[ 2 ] ); + sum2_Q24 = silk_MLA( sum2_Q24, XX_Q17[ 8 ], cb_row_Q7[ 3 ] ); + sum2_Q24 = silk_MLA( sum2_Q24, XX_Q17[ 9 ], cb_row_Q7[ 4 ] ); + sum2_Q24 = silk_LSHIFT32( sum2_Q24, 1 ); + sum2_Q24 = silk_MLA( sum2_Q24, XX_Q17[ 6 ], cb_row_Q7[ 1 ] ); + sum1_Q15 = silk_SMLAWB( sum1_Q15, sum2_Q24, cb_row_Q7[ 1 ] ); + + /* third row of XX_Q17 */ + sum2_Q24 = silk_MLA( neg_xX_Q24[ 2 ], XX_Q17[ 13 ], cb_row_Q7[ 3 ] ); + sum2_Q24 = silk_MLA( sum2_Q24, XX_Q17[ 14 ], cb_row_Q7[ 4 ] ); + sum2_Q24 = silk_LSHIFT32( sum2_Q24, 1 ); + sum2_Q24 = silk_MLA( sum2_Q24, XX_Q17[ 12 ], cb_row_Q7[ 2 ] ); + sum1_Q15 = silk_SMLAWB( sum1_Q15, sum2_Q24, cb_row_Q7[ 2 ] ); + + /* fourth row of XX_Q17 */ + sum2_Q24 = silk_MLA( neg_xX_Q24[ 3 ], XX_Q17[ 19 ], cb_row_Q7[ 4 ] ); + sum2_Q24 = silk_LSHIFT32( sum2_Q24, 1 ); + sum2_Q24 = silk_MLA( sum2_Q24, XX_Q17[ 18 ], cb_row_Q7[ 3 ] ); + sum1_Q15 = silk_SMLAWB( sum1_Q15, sum2_Q24, cb_row_Q7[ 3 ] ); + + /* last row of XX_Q17 */ + sum2_Q24 = silk_LSHIFT32( neg_xX_Q24[ 4 ], 1 ); + sum2_Q24 = silk_MLA( sum2_Q24, XX_Q17[ 24 ], cb_row_Q7[ 4 ] ); + sum1_Q15 = silk_SMLAWB( sum1_Q15, sum2_Q24, cb_row_Q7[ 4 ] ); + + /* find best */ + if( sum1_Q15 >= 0 ) { + /* Translate residual energy to bits using high-rate assumption (6 dB ==> 1 bit/sample) */ + bits_res_Q8 = silk_SMULBB( subfr_len, silk_lin2log( sum1_Q15 + penalty) - (15 << 7) ); + /* In the following line we reduce the codelength component by half ("-1"); seems to slghtly improve quality */ + bits_tot_Q8 = silk_ADD_LSHIFT32( bits_res_Q8, cl_Q5[ k ], 3-1 ); + if( bits_tot_Q8 <= *rate_dist_Q8 ) { + *rate_dist_Q8 = bits_tot_Q8; + *res_nrg_Q15 = sum1_Q15 + penalty; + *ind = (opus_int8)k; + *gain_Q7 = gain_tmp_Q7; + } + } + + /* Go to next cbk vector */ + cb_row_Q7 += LTP_ORDER; + } +} diff --git a/extern/opus/silk/ana_filt_bank_1.c b/extern/opus/silk/ana_filt_bank_1.c new file mode 100644 index 0000000..24cfb03 --- /dev/null +++ b/extern/opus/silk/ana_filt_bank_1.c @@ -0,0 +1,74 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" + +/* Coefficients for 2-band filter bank based on first-order allpass filters */ +static opus_int16 A_fb1_20 = 5394 << 1; +static opus_int16 A_fb1_21 = -24290; /* (opus_int16)(20623 << 1) */ + +/* Split signal into two decimated bands using first-order allpass filters */ +void silk_ana_filt_bank_1( + const opus_int16 *in, /* I Input signal [N] */ + opus_int32 *S, /* I/O State vector [2] */ + opus_int16 *outL, /* O Low band [N/2] */ + opus_int16 *outH, /* O High band [N/2] */ + const opus_int32 N /* I Number of input samples */ +) +{ + opus_int k, N2 = silk_RSHIFT( N, 1 ); + opus_int32 in32, X, Y, out_1, out_2; + + /* Internal variables and state are in Q10 format */ + for( k = 0; k < N2; k++ ) { + /* Convert to Q10 */ + in32 = silk_LSHIFT( (opus_int32)in[ 2 * k ], 10 ); + + /* All-pass section for even input sample */ + Y = silk_SUB32( in32, S[ 0 ] ); + X = silk_SMLAWB( Y, Y, A_fb1_21 ); + out_1 = silk_ADD32( S[ 0 ], X ); + S[ 0 ] = silk_ADD32( in32, X ); + + /* Convert to Q10 */ + in32 = silk_LSHIFT( (opus_int32)in[ 2 * k + 1 ], 10 ); + + /* All-pass section for odd input sample, and add to output of previous section */ + Y = silk_SUB32( in32, S[ 1 ] ); + X = silk_SMULWB( Y, A_fb1_20 ); + out_2 = silk_ADD32( S[ 1 ], X ); + S[ 1 ] = silk_ADD32( in32, X ); + + /* Add/subtract, convert back to int16 and store to output */ + outL[ k ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( silk_ADD32( out_2, out_1 ), 11 ) ); + outH[ k ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( silk_SUB32( out_2, out_1 ), 11 ) ); + } +} diff --git a/extern/opus/silk/arm/LPC_inv_pred_gain_arm.h b/extern/opus/silk/arm/LPC_inv_pred_gain_arm.h new file mode 100644 index 0000000..9895b55 --- /dev/null +++ b/extern/opus/silk/arm/LPC_inv_pred_gain_arm.h @@ -0,0 +1,57 @@ +/*********************************************************************** +Copyright (c) 2017 Google Inc. +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 OWNER 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. +***********************************************************************/ + +#ifndef SILK_LPC_INV_PRED_GAIN_ARM_H +# define SILK_LPC_INV_PRED_GAIN_ARM_H + +# include "celt/arm/armcpu.h" + +# if defined(OPUS_ARM_MAY_HAVE_NEON_INTR) +opus_int32 silk_LPC_inverse_pred_gain_neon( /* O Returns inverse prediction gain in energy domain, Q30 */ + const opus_int16 *A_Q12, /* I Prediction coefficients, Q12 [order] */ + const opus_int order /* I Prediction order */ +); + +# if !defined(OPUS_HAVE_RTCD) && defined(OPUS_ARM_PRESUME_NEON) +# define OVERRIDE_silk_LPC_inverse_pred_gain (1) +# define silk_LPC_inverse_pred_gain(A_Q12, order, arch) ((void)(arch), PRESUME_NEON(silk_LPC_inverse_pred_gain)(A_Q12, order)) +# endif +# endif + +# if !defined(OVERRIDE_silk_LPC_inverse_pred_gain) +/*Is run-time CPU detection enabled on this platform?*/ +# if defined(OPUS_HAVE_RTCD) && (defined(OPUS_ARM_MAY_HAVE_NEON_INTR) && !defined(OPUS_ARM_PRESUME_NEON_INTR)) +extern opus_int32 (*const SILK_LPC_INVERSE_PRED_GAIN_IMPL[OPUS_ARCHMASK+1])(const opus_int16 *A_Q12, const opus_int order); +# define OVERRIDE_silk_LPC_inverse_pred_gain (1) +# define silk_LPC_inverse_pred_gain(A_Q12, order, arch) ((*SILK_LPC_INVERSE_PRED_GAIN_IMPL[(arch)&OPUS_ARCHMASK])(A_Q12, order)) +# elif defined(OPUS_ARM_PRESUME_NEON_INTR) +# define OVERRIDE_silk_LPC_inverse_pred_gain (1) +# define silk_LPC_inverse_pred_gain(A_Q12, order, arch) ((void)(arch), silk_LPC_inverse_pred_gain_neon(A_Q12, order)) +# endif +# endif + +#endif /* end SILK_LPC_INV_PRED_GAIN_ARM_H */ diff --git a/extern/opus/silk/arm/LPC_inv_pred_gain_neon_intr.c b/extern/opus/silk/arm/LPC_inv_pred_gain_neon_intr.c new file mode 100644 index 0000000..ab426bc --- /dev/null +++ b/extern/opus/silk/arm/LPC_inv_pred_gain_neon_intr.c @@ -0,0 +1,280 @@ +/*********************************************************************** +Copyright (c) 2017 Google Inc. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "SigProc_FIX.h" +#include "define.h" + +#define QA 24 +#define A_LIMIT SILK_FIX_CONST( 0.99975, QA ) + +#define MUL32_FRAC_Q(a32, b32, Q) ((opus_int32)(silk_RSHIFT_ROUND64(silk_SMULL(a32, b32), Q))) + +/* The difficulty is how to judge a 64-bit signed integer tmp64 is 32-bit overflowed, + * since NEON has no 64-bit min, max or comparison instructions. + * A failed idea is to compare the results of vmovn(tmp64) and vqmovn(tmp64) whether they are equal or not. + * However, this idea fails when the tmp64 is something like 0xFFFFFFF980000000. + * Here we know that mult2Q >= 1, so the highest bit (bit 63, sign bit) of tmp64 must equal to bit 62. + * tmp64 was shifted left by 1 and we got tmp64'. If high_half(tmp64') != 0 and high_half(tmp64') != -1, + * then we know that bit 31 to bit 63 of tmp64 can not all be the sign bit, and therefore tmp64 is 32-bit overflowed. + * That is, we judge if tmp64' > 0x00000000FFFFFFFF, or tmp64' <= 0xFFFFFFFF00000000. + * We use narrowing shift right 31 bits to tmp32' to save data bandwidth and instructions. + * That is, we judge if tmp32' > 0x00000000, or tmp32' <= 0xFFFFFFFF. + */ + +/* Compute inverse of LPC prediction gain, and */ +/* test if LPC coefficients are stable (all poles within unit circle) */ +static OPUS_INLINE opus_int32 LPC_inverse_pred_gain_QA_neon( /* O Returns inverse prediction gain in energy domain, Q30 */ + opus_int32 A_QA[ SILK_MAX_ORDER_LPC ], /* I Prediction coefficients */ + const opus_int order /* I Prediction order */ +) +{ + opus_int k, n, mult2Q; + opus_int32 invGain_Q30, rc_Q31, rc_mult1_Q30, rc_mult2, tmp1, tmp2; + opus_int32 max, min; + int32x4_t max_s32x4, min_s32x4; + int32x2_t max_s32x2, min_s32x2; + + max_s32x4 = vdupq_n_s32( silk_int32_MIN ); + min_s32x4 = vdupq_n_s32( silk_int32_MAX ); + invGain_Q30 = SILK_FIX_CONST( 1, 30 ); + for( k = order - 1; k > 0; k-- ) { + int32x2_t rc_Q31_s32x2, rc_mult2_s32x2; + int64x2_t mult2Q_s64x2; + + /* Check for stability */ + if( ( A_QA[ k ] > A_LIMIT ) || ( A_QA[ k ] < -A_LIMIT ) ) { + return 0; + } + + /* Set RC equal to negated AR coef */ + rc_Q31 = -silk_LSHIFT( A_QA[ k ], 31 - QA ); + + /* rc_mult1_Q30 range: [ 1 : 2^30 ] */ + rc_mult1_Q30 = silk_SUB32( SILK_FIX_CONST( 1, 30 ), silk_SMMUL( rc_Q31, rc_Q31 ) ); + silk_assert( rc_mult1_Q30 > ( 1 << 15 ) ); /* reduce A_LIMIT if fails */ + silk_assert( rc_mult1_Q30 <= ( 1 << 30 ) ); + + /* Update inverse gain */ + /* invGain_Q30 range: [ 0 : 2^30 ] */ + invGain_Q30 = silk_LSHIFT( silk_SMMUL( invGain_Q30, rc_mult1_Q30 ), 2 ); + silk_assert( invGain_Q30 >= 0 ); + silk_assert( invGain_Q30 <= ( 1 << 30 ) ); + if( invGain_Q30 < SILK_FIX_CONST( 1.0f / MAX_PREDICTION_POWER_GAIN, 30 ) ) { + return 0; + } + + /* rc_mult2 range: [ 2^30 : silk_int32_MAX ] */ + mult2Q = 32 - silk_CLZ32( silk_abs( rc_mult1_Q30 ) ); + rc_mult2 = silk_INVERSE32_varQ( rc_mult1_Q30, mult2Q + 30 ); + + /* Update AR coefficient */ + rc_Q31_s32x2 = vdup_n_s32( rc_Q31 ); + mult2Q_s64x2 = vdupq_n_s64( -mult2Q ); + rc_mult2_s32x2 = vdup_n_s32( rc_mult2 ); + + for( n = 0; n < ( ( k + 1 ) >> 1 ) - 3; n += 4 ) { + /* We always calculate extra elements of A_QA buffer when ( k % 4 ) != 0, to take the advantage of SIMD parallelization. */ + int32x4_t tmp1_s32x4, tmp2_s32x4, t0_s32x4, t1_s32x4, s0_s32x4, s1_s32x4, t_QA0_s32x4, t_QA1_s32x4; + int64x2_t t0_s64x2, t1_s64x2, t2_s64x2, t3_s64x2; + tmp1_s32x4 = vld1q_s32( A_QA + n ); + tmp2_s32x4 = vld1q_s32( A_QA + k - n - 4 ); + tmp2_s32x4 = vrev64q_s32( tmp2_s32x4 ); + tmp2_s32x4 = vcombine_s32( vget_high_s32( tmp2_s32x4 ), vget_low_s32( tmp2_s32x4 ) ); + t0_s32x4 = vqrdmulhq_lane_s32( tmp2_s32x4, rc_Q31_s32x2, 0 ); + t1_s32x4 = vqrdmulhq_lane_s32( tmp1_s32x4, rc_Q31_s32x2, 0 ); + t_QA0_s32x4 = vqsubq_s32( tmp1_s32x4, t0_s32x4 ); + t_QA1_s32x4 = vqsubq_s32( tmp2_s32x4, t1_s32x4 ); + t0_s64x2 = vmull_s32( vget_low_s32 ( t_QA0_s32x4 ), rc_mult2_s32x2 ); + t1_s64x2 = vmull_s32( vget_high_s32( t_QA0_s32x4 ), rc_mult2_s32x2 ); + t2_s64x2 = vmull_s32( vget_low_s32 ( t_QA1_s32x4 ), rc_mult2_s32x2 ); + t3_s64x2 = vmull_s32( vget_high_s32( t_QA1_s32x4 ), rc_mult2_s32x2 ); + t0_s64x2 = vrshlq_s64( t0_s64x2, mult2Q_s64x2 ); + t1_s64x2 = vrshlq_s64( t1_s64x2, mult2Q_s64x2 ); + t2_s64x2 = vrshlq_s64( t2_s64x2, mult2Q_s64x2 ); + t3_s64x2 = vrshlq_s64( t3_s64x2, mult2Q_s64x2 ); + t0_s32x4 = vcombine_s32( vmovn_s64( t0_s64x2 ), vmovn_s64( t1_s64x2 ) ); + t1_s32x4 = vcombine_s32( vmovn_s64( t2_s64x2 ), vmovn_s64( t3_s64x2 ) ); + s0_s32x4 = vcombine_s32( vshrn_n_s64( t0_s64x2, 31 ), vshrn_n_s64( t1_s64x2, 31 ) ); + s1_s32x4 = vcombine_s32( vshrn_n_s64( t2_s64x2, 31 ), vshrn_n_s64( t3_s64x2, 31 ) ); + max_s32x4 = vmaxq_s32( max_s32x4, s0_s32x4 ); + min_s32x4 = vminq_s32( min_s32x4, s0_s32x4 ); + max_s32x4 = vmaxq_s32( max_s32x4, s1_s32x4 ); + min_s32x4 = vminq_s32( min_s32x4, s1_s32x4 ); + t1_s32x4 = vrev64q_s32( t1_s32x4 ); + t1_s32x4 = vcombine_s32( vget_high_s32( t1_s32x4 ), vget_low_s32( t1_s32x4 ) ); + vst1q_s32( A_QA + n, t0_s32x4 ); + vst1q_s32( A_QA + k - n - 4, t1_s32x4 ); + } + for( ; n < (k + 1) >> 1; n++ ) { + opus_int64 tmp64; + tmp1 = A_QA[ n ]; + tmp2 = A_QA[ k - n - 1 ]; + tmp64 = silk_RSHIFT_ROUND64( silk_SMULL( silk_SUB_SAT32(tmp1, + MUL32_FRAC_Q( tmp2, rc_Q31, 31 ) ), rc_mult2 ), mult2Q); + if( tmp64 > silk_int32_MAX || tmp64 < silk_int32_MIN ) { + return 0; + } + A_QA[ n ] = ( opus_int32 )tmp64; + tmp64 = silk_RSHIFT_ROUND64( silk_SMULL( silk_SUB_SAT32(tmp2, + MUL32_FRAC_Q( tmp1, rc_Q31, 31 ) ), rc_mult2), mult2Q); + if( tmp64 > silk_int32_MAX || tmp64 < silk_int32_MIN ) { + return 0; + } + A_QA[ k - n - 1 ] = ( opus_int32 )tmp64; + } + } + + /* Check for stability */ + if( ( A_QA[ k ] > A_LIMIT ) || ( A_QA[ k ] < -A_LIMIT ) ) { + return 0; + } + + max_s32x2 = vmax_s32( vget_low_s32( max_s32x4 ), vget_high_s32( max_s32x4 ) ); + min_s32x2 = vmin_s32( vget_low_s32( min_s32x4 ), vget_high_s32( min_s32x4 ) ); + max_s32x2 = vmax_s32( max_s32x2, vreinterpret_s32_s64( vshr_n_s64( vreinterpret_s64_s32( max_s32x2 ), 32 ) ) ); + min_s32x2 = vmin_s32( min_s32x2, vreinterpret_s32_s64( vshr_n_s64( vreinterpret_s64_s32( min_s32x2 ), 32 ) ) ); + max = vget_lane_s32( max_s32x2, 0 ); + min = vget_lane_s32( min_s32x2, 0 ); + if( ( max > 0 ) || ( min < -1 ) ) { + return 0; + } + + /* Set RC equal to negated AR coef */ + rc_Q31 = -silk_LSHIFT( A_QA[ 0 ], 31 - QA ); + + /* Range: [ 1 : 2^30 ] */ + rc_mult1_Q30 = silk_SUB32( SILK_FIX_CONST( 1, 30 ), silk_SMMUL( rc_Q31, rc_Q31 ) ); + + /* Update inverse gain */ + /* Range: [ 0 : 2^30 ] */ + invGain_Q30 = silk_LSHIFT( silk_SMMUL( invGain_Q30, rc_mult1_Q30 ), 2 ); + silk_assert( invGain_Q30 >= 0 ); + silk_assert( invGain_Q30 <= ( 1 << 30 ) ); + if( invGain_Q30 < SILK_FIX_CONST( 1.0f / MAX_PREDICTION_POWER_GAIN, 30 ) ) { + return 0; + } + + return invGain_Q30; +} + +/* For input in Q12 domain */ +opus_int32 silk_LPC_inverse_pred_gain_neon( /* O Returns inverse prediction gain in energy domain, Q30 */ + const opus_int16 *A_Q12, /* I Prediction coefficients, Q12 [order] */ + const opus_int order /* I Prediction order */ +) +{ +#ifdef OPUS_CHECK_ASM + const opus_int32 invGain_Q30_c = silk_LPC_inverse_pred_gain_c( A_Q12, order ); +#endif + + opus_int32 invGain_Q30; + if( ( SILK_MAX_ORDER_LPC != 24 ) || ( order & 1 )) { + invGain_Q30 = silk_LPC_inverse_pred_gain_c( A_Q12, order ); + } + else { + opus_int32 Atmp_QA[ SILK_MAX_ORDER_LPC ]; + opus_int32 DC_resp; + int16x8_t t0_s16x8, t1_s16x8, t2_s16x8; + int32x4_t t0_s32x4; + const opus_int leftover = order & 7; + + /* Increase Q domain of the AR coefficients */ + t0_s16x8 = vld1q_s16( A_Q12 + 0 ); + t1_s16x8 = vld1q_s16( A_Q12 + 8 ); + t2_s16x8 = vld1q_s16( A_Q12 + 16 ); + t0_s32x4 = vpaddlq_s16( t0_s16x8 ); + + switch( order - leftover ) + { + case 24: + t0_s32x4 = vpadalq_s16( t0_s32x4, t2_s16x8 ); + /* FALLTHROUGH */ + + case 16: + t0_s32x4 = vpadalq_s16( t0_s32x4, t1_s16x8 ); + vst1q_s32( Atmp_QA + 16, vshll_n_s16( vget_low_s16 ( t2_s16x8 ), QA - 12 ) ); + vst1q_s32( Atmp_QA + 20, vshll_n_s16( vget_high_s16( t2_s16x8 ), QA - 12 ) ); + /* FALLTHROUGH */ + + case 8: + { + const int32x2_t t_s32x2 = vpadd_s32( vget_low_s32( t0_s32x4 ), vget_high_s32( t0_s32x4 ) ); + const int64x1_t t_s64x1 = vpaddl_s32( t_s32x2 ); + DC_resp = vget_lane_s32( vreinterpret_s32_s64( t_s64x1 ), 0 ); + vst1q_s32( Atmp_QA + 8, vshll_n_s16( vget_low_s16 ( t1_s16x8 ), QA - 12 ) ); + vst1q_s32( Atmp_QA + 12, vshll_n_s16( vget_high_s16( t1_s16x8 ), QA - 12 ) ); + } + break; + + default: + DC_resp = 0; + break; + } + A_Q12 += order - leftover; + + switch( leftover ) + { + case 6: + DC_resp += (opus_int32)A_Q12[ 5 ]; + DC_resp += (opus_int32)A_Q12[ 4 ]; + /* FALLTHROUGH */ + + case 4: + DC_resp += (opus_int32)A_Q12[ 3 ]; + DC_resp += (opus_int32)A_Q12[ 2 ]; + /* FALLTHROUGH */ + + case 2: + DC_resp += (opus_int32)A_Q12[ 1 ]; + DC_resp += (opus_int32)A_Q12[ 0 ]; + /* FALLTHROUGH */ + + default: + break; + } + + /* If the DC is unstable, we don't even need to do the full calculations */ + if( DC_resp >= 4096 ) { + invGain_Q30 = 0; + } else { + vst1q_s32( Atmp_QA + 0, vshll_n_s16( vget_low_s16 ( t0_s16x8 ), QA - 12 ) ); + vst1q_s32( Atmp_QA + 4, vshll_n_s16( vget_high_s16( t0_s16x8 ), QA - 12 ) ); + invGain_Q30 = LPC_inverse_pred_gain_QA_neon( Atmp_QA, order ); + } + } + +#ifdef OPUS_CHECK_ASM + silk_assert( invGain_Q30_c == invGain_Q30 ); +#endif + + return invGain_Q30; +} diff --git a/extern/opus/silk/arm/NSQ_del_dec_arm.h b/extern/opus/silk/arm/NSQ_del_dec_arm.h new file mode 100644 index 0000000..9e76e16 --- /dev/null +++ b/extern/opus/silk/arm/NSQ_del_dec_arm.h @@ -0,0 +1,100 @@ +/*********************************************************************** +Copyright (c) 2017 Google Inc. +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 OWNER 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. +***********************************************************************/ + +#ifndef SILK_NSQ_DEL_DEC_ARM_H +#define SILK_NSQ_DEL_DEC_ARM_H + +#include "celt/arm/armcpu.h" + +#if defined(OPUS_ARM_MAY_HAVE_NEON_INTR) +void silk_NSQ_del_dec_neon( + const silk_encoder_state *psEncC, silk_nsq_state *NSQ, + SideInfoIndices *psIndices, const opus_int16 x16[], opus_int8 pulses[], + const opus_int16 PredCoef_Q12[2 * MAX_LPC_ORDER], + const opus_int16 LTPCoef_Q14[LTP_ORDER * MAX_NB_SUBFR], + const opus_int16 AR_Q13[MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER], + const opus_int HarmShapeGain_Q14[MAX_NB_SUBFR], + const opus_int Tilt_Q14[MAX_NB_SUBFR], + const opus_int32 LF_shp_Q14[MAX_NB_SUBFR], + const opus_int32 Gains_Q16[MAX_NB_SUBFR], + const opus_int pitchL[MAX_NB_SUBFR], const opus_int Lambda_Q10, + const opus_int LTP_scale_Q14); + +#if !defined(OPUS_HAVE_RTCD) +#define OVERRIDE_silk_NSQ_del_dec (1) +#define silk_NSQ_del_dec(psEncC, NSQ, psIndices, x16, pulses, PredCoef_Q12, \ + LTPCoef_Q14, AR_Q13, HarmShapeGain_Q14, Tilt_Q14, \ + LF_shp_Q14, Gains_Q16, pitchL, Lambda_Q10, \ + LTP_scale_Q14, arch) \ + ((void)(arch), \ + PRESUME_NEON(silk_NSQ_del_dec)( \ + psEncC, NSQ, psIndices, x16, pulses, PredCoef_Q12, LTPCoef_Q14, \ + AR_Q13, HarmShapeGain_Q14, Tilt_Q14, LF_shp_Q14, Gains_Q16, pitchL, \ + Lambda_Q10, LTP_scale_Q14)) +#endif +#endif + +#if !defined(OVERRIDE_silk_NSQ_del_dec) +/*Is run-time CPU detection enabled on this platform?*/ +#if defined(OPUS_HAVE_RTCD) && (defined(OPUS_ARM_MAY_HAVE_NEON_INTR) && \ + !defined(OPUS_ARM_PRESUME_NEON_INTR)) +extern void (*const SILK_NSQ_DEL_DEC_IMPL[OPUS_ARCHMASK + 1])( + const silk_encoder_state *psEncC, silk_nsq_state *NSQ, + SideInfoIndices *psIndices, const opus_int16 x16[], opus_int8 pulses[], + const opus_int16 PredCoef_Q12[2 * MAX_LPC_ORDER], + const opus_int16 LTPCoef_Q14[LTP_ORDER * MAX_NB_SUBFR], + const opus_int16 AR_Q13[MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER], + const opus_int HarmShapeGain_Q14[MAX_NB_SUBFR], + const opus_int Tilt_Q14[MAX_NB_SUBFR], + const opus_int32 LF_shp_Q14[MAX_NB_SUBFR], + const opus_int32 Gains_Q16[MAX_NB_SUBFR], + const opus_int pitchL[MAX_NB_SUBFR], const opus_int Lambda_Q10, + const opus_int LTP_scale_Q14); +#define OVERRIDE_silk_NSQ_del_dec (1) +#define silk_NSQ_del_dec(psEncC, NSQ, psIndices, x16, pulses, PredCoef_Q12, \ + LTPCoef_Q14, AR_Q13, HarmShapeGain_Q14, Tilt_Q14, \ + LF_shp_Q14, Gains_Q16, pitchL, Lambda_Q10, \ + LTP_scale_Q14, arch) \ + ((*SILK_NSQ_DEL_DEC_IMPL[(arch)&OPUS_ARCHMASK])( \ + psEncC, NSQ, psIndices, x16, pulses, PredCoef_Q12, LTPCoef_Q14, \ + AR_Q13, HarmShapeGain_Q14, Tilt_Q14, LF_shp_Q14, Gains_Q16, pitchL, \ + Lambda_Q10, LTP_scale_Q14)) +#elif defined(OPUS_ARM_PRESUME_NEON_INTR) +#define OVERRIDE_silk_NSQ_del_dec (1) +#define silk_NSQ_del_dec(psEncC, NSQ, psIndices, x16, pulses, PredCoef_Q12, \ + LTPCoef_Q14, AR_Q13, HarmShapeGain_Q14, Tilt_Q14, \ + LF_shp_Q14, Gains_Q16, pitchL, Lambda_Q10, \ + LTP_scale_Q14, arch) \ + ((void)(arch), \ + silk_NSQ_del_dec_neon(psEncC, NSQ, psIndices, x16, pulses, PredCoef_Q12, \ + LTPCoef_Q14, AR_Q13, HarmShapeGain_Q14, Tilt_Q14, \ + LF_shp_Q14, Gains_Q16, pitchL, Lambda_Q10, \ + LTP_scale_Q14)) +#endif +#endif + +#endif /* end SILK_NSQ_DEL_DEC_ARM_H */ diff --git a/extern/opus/silk/arm/NSQ_del_dec_neon_intr.c b/extern/opus/silk/arm/NSQ_del_dec_neon_intr.c new file mode 100644 index 0000000..212410f --- /dev/null +++ b/extern/opus/silk/arm/NSQ_del_dec_neon_intr.c @@ -0,0 +1,1124 @@ +/*********************************************************************** +Copyright (c) 2017 Google Inc. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#ifdef OPUS_CHECK_ASM +# include +#endif +#include "main.h" +#include "stack_alloc.h" + +/* NEON intrinsics optimization now can only parallelize up to 4 delay decision states. */ +/* If there are more states, C function is called, and this optimization must be expanded. */ +#define NEON_MAX_DEL_DEC_STATES 4 + +typedef struct { + opus_int32 sLPC_Q14[ MAX_SUB_FRAME_LENGTH + NSQ_LPC_BUF_LENGTH ][ NEON_MAX_DEL_DEC_STATES ]; + opus_int32 RandState[ DECISION_DELAY ][ NEON_MAX_DEL_DEC_STATES ]; + opus_int32 Q_Q10[ DECISION_DELAY ][ NEON_MAX_DEL_DEC_STATES ]; + opus_int32 Xq_Q14[ DECISION_DELAY ][ NEON_MAX_DEL_DEC_STATES ]; + opus_int32 Pred_Q15[ DECISION_DELAY ][ NEON_MAX_DEL_DEC_STATES ]; + opus_int32 Shape_Q14[ DECISION_DELAY ][ NEON_MAX_DEL_DEC_STATES ]; + opus_int32 sAR2_Q14[ MAX_SHAPE_LPC_ORDER ][ NEON_MAX_DEL_DEC_STATES ]; + opus_int32 LF_AR_Q14[ NEON_MAX_DEL_DEC_STATES ]; + opus_int32 Diff_Q14[ NEON_MAX_DEL_DEC_STATES ]; + opus_int32 Seed[ NEON_MAX_DEL_DEC_STATES ]; + opus_int32 SeedInit[ NEON_MAX_DEL_DEC_STATES ]; + opus_int32 RD_Q10[ NEON_MAX_DEL_DEC_STATES ]; +} NSQ_del_decs_struct; + +typedef struct { + opus_int32 Q_Q10[ NEON_MAX_DEL_DEC_STATES ]; + opus_int32 RD_Q10[ NEON_MAX_DEL_DEC_STATES ]; + opus_int32 xq_Q14[ NEON_MAX_DEL_DEC_STATES ]; + opus_int32 LF_AR_Q14[ NEON_MAX_DEL_DEC_STATES ]; + opus_int32 Diff_Q14[ NEON_MAX_DEL_DEC_STATES ]; + opus_int32 sLTP_shp_Q14[ NEON_MAX_DEL_DEC_STATES ]; + opus_int32 LPC_exc_Q14[ NEON_MAX_DEL_DEC_STATES ]; +} NSQ_samples_struct; + +static OPUS_INLINE void silk_nsq_del_dec_scale_states_neon( + const silk_encoder_state *psEncC, /* I Encoder State */ + silk_nsq_state *NSQ, /* I/O NSQ state */ + NSQ_del_decs_struct psDelDec[], /* I/O Delayed decision states */ + const opus_int16 x16[], /* I Input */ + opus_int32 x_sc_Q10[], /* O Input scaled with 1/Gain in Q10 */ + const opus_int16 sLTP[], /* I Re-whitened LTP state in Q0 */ + opus_int32 sLTP_Q15[], /* O LTP state matching scaled input */ + opus_int subfr, /* I Subframe number */ + const opus_int LTP_scale_Q14, /* I LTP state scaling */ + const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lag */ + const opus_int signal_type, /* I Signal type */ + const opus_int decisionDelay /* I Decision delay */ +); + +/******************************************/ +/* Noise shape quantizer for one subframe */ +/******************************************/ +static OPUS_INLINE void silk_noise_shape_quantizer_del_dec_neon( + silk_nsq_state *NSQ, /* I/O NSQ state */ + NSQ_del_decs_struct psDelDec[], /* I/O Delayed decision states */ + opus_int signalType, /* I Signal type */ + const opus_int32 x_Q10[], /* I */ + opus_int8 pulses[], /* O */ + opus_int16 xq[], /* O */ + opus_int32 sLTP_Q15[], /* I/O LTP filter state */ + opus_int32 delayedGain_Q10[], /* I/O Gain delay buffer */ + const opus_int16 a_Q12[], /* I Short term prediction coefs */ + const opus_int16 b_Q14[], /* I Long term prediction coefs */ + const opus_int16 AR_shp_Q13[], /* I Noise shaping coefs */ + opus_int lag, /* I Pitch lag */ + opus_int32 HarmShapeFIRPacked_Q14, /* I */ + opus_int Tilt_Q14, /* I Spectral tilt */ + opus_int32 LF_shp_Q14, /* I */ + opus_int32 Gain_Q16, /* I */ + opus_int Lambda_Q10, /* I */ + opus_int offset_Q10, /* I */ + opus_int length, /* I Input length */ + opus_int subfr, /* I Subframe number */ + opus_int shapingLPCOrder, /* I Shaping LPC filter order */ + opus_int predictLPCOrder, /* I Prediction filter order */ + opus_int warping_Q16, /* I */ + opus_int nStatesDelayedDecision, /* I Number of states in decision tree */ + opus_int *smpl_buf_idx, /* I/O Index to newest samples in buffers */ + opus_int decisionDelay /* I */ +); + +static OPUS_INLINE void copy_winner_state_kernel( + const NSQ_del_decs_struct *psDelDec, + const opus_int offset, + const opus_int last_smple_idx, + const opus_int Winner_ind, + const int32x2_t gain_lo_s32x2, + const int32x2_t gain_hi_s32x2, + const int32x4_t shift_s32x4, + int32x4_t t0_s32x4, + int32x4_t t1_s32x4, + opus_int8 *const pulses, + opus_int16 *pxq, + silk_nsq_state *NSQ +) +{ + int16x8_t t_s16x8; + int32x4_t o0_s32x4, o1_s32x4; + + t0_s32x4 = vld1q_lane_s32( &psDelDec->Q_Q10[ last_smple_idx - 0 ][ Winner_ind ], t0_s32x4, 0 ); + t0_s32x4 = vld1q_lane_s32( &psDelDec->Q_Q10[ last_smple_idx - 1 ][ Winner_ind ], t0_s32x4, 1 ); + t0_s32x4 = vld1q_lane_s32( &psDelDec->Q_Q10[ last_smple_idx - 2 ][ Winner_ind ], t0_s32x4, 2 ); + t0_s32x4 = vld1q_lane_s32( &psDelDec->Q_Q10[ last_smple_idx - 3 ][ Winner_ind ], t0_s32x4, 3 ); + t1_s32x4 = vld1q_lane_s32( &psDelDec->Q_Q10[ last_smple_idx - 4 ][ Winner_ind ], t1_s32x4, 0 ); + t1_s32x4 = vld1q_lane_s32( &psDelDec->Q_Q10[ last_smple_idx - 5 ][ Winner_ind ], t1_s32x4, 1 ); + t1_s32x4 = vld1q_lane_s32( &psDelDec->Q_Q10[ last_smple_idx - 6 ][ Winner_ind ], t1_s32x4, 2 ); + t1_s32x4 = vld1q_lane_s32( &psDelDec->Q_Q10[ last_smple_idx - 7 ][ Winner_ind ], t1_s32x4, 3 ); + t_s16x8 = vcombine_s16( vrshrn_n_s32( t0_s32x4, 10 ), vrshrn_n_s32( t1_s32x4, 10 ) ); + vst1_s8( &pulses[ offset ], vmovn_s16( t_s16x8 ) ); + + t0_s32x4 = vld1q_lane_s32( &psDelDec->Xq_Q14[ last_smple_idx - 0 ][ Winner_ind ], t0_s32x4, 0 ); + t0_s32x4 = vld1q_lane_s32( &psDelDec->Xq_Q14[ last_smple_idx - 1 ][ Winner_ind ], t0_s32x4, 1 ); + t0_s32x4 = vld1q_lane_s32( &psDelDec->Xq_Q14[ last_smple_idx - 2 ][ Winner_ind ], t0_s32x4, 2 ); + t0_s32x4 = vld1q_lane_s32( &psDelDec->Xq_Q14[ last_smple_idx - 3 ][ Winner_ind ], t0_s32x4, 3 ); + t1_s32x4 = vld1q_lane_s32( &psDelDec->Xq_Q14[ last_smple_idx - 4 ][ Winner_ind ], t1_s32x4, 0 ); + t1_s32x4 = vld1q_lane_s32( &psDelDec->Xq_Q14[ last_smple_idx - 5 ][ Winner_ind ], t1_s32x4, 1 ); + t1_s32x4 = vld1q_lane_s32( &psDelDec->Xq_Q14[ last_smple_idx - 6 ][ Winner_ind ], t1_s32x4, 2 ); + t1_s32x4 = vld1q_lane_s32( &psDelDec->Xq_Q14[ last_smple_idx - 7 ][ Winner_ind ], t1_s32x4, 3 ); + o0_s32x4 = vqdmulhq_lane_s32( t0_s32x4, gain_lo_s32x2, 0 ); + o1_s32x4 = vqdmulhq_lane_s32( t1_s32x4, gain_lo_s32x2, 0 ); + o0_s32x4 = vmlaq_lane_s32( o0_s32x4, t0_s32x4, gain_hi_s32x2, 0 ); + o1_s32x4 = vmlaq_lane_s32( o1_s32x4, t1_s32x4, gain_hi_s32x2, 0 ); + o0_s32x4 = vrshlq_s32( o0_s32x4, shift_s32x4 ); + o1_s32x4 = vrshlq_s32( o1_s32x4, shift_s32x4 ); + vst1_s16( &pxq[ offset + 0 ], vqmovn_s32( o0_s32x4 ) ); + vst1_s16( &pxq[ offset + 4 ], vqmovn_s32( o1_s32x4 ) ); + + t0_s32x4 = vld1q_lane_s32( &psDelDec->Shape_Q14[ last_smple_idx - 0 ][ Winner_ind ], t0_s32x4, 0 ); + t0_s32x4 = vld1q_lane_s32( &psDelDec->Shape_Q14[ last_smple_idx - 1 ][ Winner_ind ], t0_s32x4, 1 ); + t0_s32x4 = vld1q_lane_s32( &psDelDec->Shape_Q14[ last_smple_idx - 2 ][ Winner_ind ], t0_s32x4, 2 ); + t0_s32x4 = vld1q_lane_s32( &psDelDec->Shape_Q14[ last_smple_idx - 3 ][ Winner_ind ], t0_s32x4, 3 ); + t1_s32x4 = vld1q_lane_s32( &psDelDec->Shape_Q14[ last_smple_idx - 4 ][ Winner_ind ], t1_s32x4, 0 ); + t1_s32x4 = vld1q_lane_s32( &psDelDec->Shape_Q14[ last_smple_idx - 5 ][ Winner_ind ], t1_s32x4, 1 ); + t1_s32x4 = vld1q_lane_s32( &psDelDec->Shape_Q14[ last_smple_idx - 6 ][ Winner_ind ], t1_s32x4, 2 ); + t1_s32x4 = vld1q_lane_s32( &psDelDec->Shape_Q14[ last_smple_idx - 7 ][ Winner_ind ], t1_s32x4, 3 ); + vst1q_s32( &NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx + offset + 0 ], t0_s32x4 ); + vst1q_s32( &NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx + offset + 4 ], t1_s32x4 ); +} + +static OPUS_INLINE void copy_winner_state( + const NSQ_del_decs_struct *psDelDec, + const opus_int decisionDelay, + const opus_int smpl_buf_idx, + const opus_int Winner_ind, + const opus_int32 gain, + const opus_int32 shift, + opus_int8 *const pulses, + opus_int16 *pxq, + silk_nsq_state *NSQ +) +{ + opus_int i, last_smple_idx; + const int32x2_t gain_lo_s32x2 = vdup_n_s32( silk_LSHIFT32( gain & 0x0000FFFF, 15 ) ); + const int32x2_t gain_hi_s32x2 = vdup_n_s32( gain >> 16 ); + const int32x4_t shift_s32x4 = vdupq_n_s32( -shift ); + int32x4_t t0_s32x4, t1_s32x4; + + t0_s32x4 = t1_s32x4 = vdupq_n_s32( 0 ); /* initialization */ + last_smple_idx = smpl_buf_idx + decisionDelay - 1 + DECISION_DELAY; + if( last_smple_idx >= DECISION_DELAY ) last_smple_idx -= DECISION_DELAY; + if( last_smple_idx >= DECISION_DELAY ) last_smple_idx -= DECISION_DELAY; + + for( i = 0; ( i < ( decisionDelay - 7 ) ) && ( last_smple_idx >= 7 ); i += 8, last_smple_idx -= 8 ) { + copy_winner_state_kernel( psDelDec, i - decisionDelay, last_smple_idx, Winner_ind, gain_lo_s32x2, gain_hi_s32x2, shift_s32x4, t0_s32x4, t1_s32x4, pulses, pxq, NSQ ); + } + for( ; ( i < decisionDelay ) && ( last_smple_idx >= 0 ); i++, last_smple_idx-- ) { + pulses[ i - decisionDelay ] = (opus_int8)silk_RSHIFT_ROUND( psDelDec->Q_Q10[ last_smple_idx ][ Winner_ind ], 10 ); + pxq[ i - decisionDelay ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( silk_SMULWW( psDelDec->Xq_Q14[ last_smple_idx ][ Winner_ind ], gain ), shift ) ); + NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - decisionDelay + i ] = psDelDec->Shape_Q14[ last_smple_idx ][ Winner_ind ]; + } + + last_smple_idx += DECISION_DELAY; + for( ; i < ( decisionDelay - 7 ); i++, last_smple_idx-- ) { + copy_winner_state_kernel( psDelDec, i - decisionDelay, last_smple_idx, Winner_ind, gain_lo_s32x2, gain_hi_s32x2, shift_s32x4, t0_s32x4, t1_s32x4, pulses, pxq, NSQ ); + } + for( ; i < decisionDelay; i++, last_smple_idx-- ) { + pulses[ i - decisionDelay ] = (opus_int8)silk_RSHIFT_ROUND( psDelDec->Q_Q10[ last_smple_idx ][ Winner_ind ], 10 ); + pxq[ i - decisionDelay ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( silk_SMULWW( psDelDec->Xq_Q14[ last_smple_idx ][ Winner_ind ], gain ), shift ) ); + NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - decisionDelay + i ] = psDelDec->Shape_Q14[ last_smple_idx ][ Winner_ind ]; + } +} + +void silk_NSQ_del_dec_neon( + const silk_encoder_state *psEncC, /* I Encoder State */ + silk_nsq_state *NSQ, /* I/O NSQ state */ + SideInfoIndices *psIndices, /* I/O Quantization Indices */ + const opus_int16 x16[], /* I Input */ + opus_int8 pulses[], /* O Quantized pulse signal */ + const opus_int16 PredCoef_Q12[ 2 * MAX_LPC_ORDER ], /* I Short term prediction coefs */ + const opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ], /* I Long term prediction coefs */ + const opus_int16 AR_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ], /* I Noise shaping coefs */ + const opus_int HarmShapeGain_Q14[ MAX_NB_SUBFR ], /* I Long term shaping coefs */ + const opus_int Tilt_Q14[ MAX_NB_SUBFR ], /* I Spectral tilt */ + const opus_int32 LF_shp_Q14[ MAX_NB_SUBFR ], /* I Low frequency shaping coefs */ + const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I Quantization step sizes */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lags */ + const opus_int Lambda_Q10, /* I Rate/distortion tradeoff */ + const opus_int LTP_scale_Q14 /* I LTP state scaling */ +) +{ +#ifdef OPUS_CHECK_ASM + silk_nsq_state NSQ_c; + SideInfoIndices psIndices_c; + opus_int8 pulses_c[ MAX_FRAME_LENGTH ]; + const opus_int8 *const pulses_a = pulses; + + ( void )pulses_a; + silk_memcpy( &NSQ_c, NSQ, sizeof( NSQ_c ) ); + silk_memcpy( &psIndices_c, psIndices, sizeof( psIndices_c ) ); + silk_memcpy( pulses_c, pulses, sizeof( pulses_c ) ); + silk_NSQ_del_dec_c( psEncC, &NSQ_c, &psIndices_c, x16, pulses_c, PredCoef_Q12, LTPCoef_Q14, AR_Q13, HarmShapeGain_Q14, Tilt_Q14, LF_shp_Q14, Gains_Q16, + pitchL, Lambda_Q10, LTP_scale_Q14 ); +#endif + + /* The optimization parallelizes the different delay decision states. */ + if(( psEncC->nStatesDelayedDecision > NEON_MAX_DEL_DEC_STATES ) || ( psEncC->nStatesDelayedDecision <= 2 )) { + /* NEON intrinsics optimization now can only parallelize up to 4 delay decision states. */ + /* If there are more states, C function is called, and this optimization must be expanded. */ + /* When the number of delay decision states is less than 3, there are penalties using this */ + /* optimization, and C function is called. */ + /* When the number of delay decision states is 2, it's better to specialize another */ + /* structure NSQ_del_dec2_struct and optimize with shorter NEON registers. (Low priority) */ + silk_NSQ_del_dec_c( psEncC, NSQ, psIndices, x16, pulses, PredCoef_Q12, LTPCoef_Q14, AR_Q13, HarmShapeGain_Q14, + Tilt_Q14, LF_shp_Q14, Gains_Q16, pitchL, Lambda_Q10, LTP_scale_Q14 ); + } else { + opus_int i, k, lag, start_idx, LSF_interpolation_flag, Winner_ind, subfr; + opus_int smpl_buf_idx, decisionDelay; + const opus_int16 *A_Q12, *B_Q14, *AR_shp_Q13; + opus_int16 *pxq; + VARDECL( opus_int32, sLTP_Q15 ); + VARDECL( opus_int16, sLTP ); + opus_int32 HarmShapeFIRPacked_Q14; + opus_int offset_Q10; + opus_int32 RDmin_Q10, Gain_Q10; + VARDECL( opus_int32, x_sc_Q10 ); + VARDECL( opus_int32, delayedGain_Q10 ); + VARDECL( NSQ_del_decs_struct, psDelDec ); + int32x4_t t_s32x4; + SAVE_STACK; + + /* Set unvoiced lag to the previous one, overwrite later for voiced */ + lag = NSQ->lagPrev; + + silk_assert( NSQ->prev_gain_Q16 != 0 ); + + /* Initialize delayed decision states */ + ALLOC( psDelDec, 1, NSQ_del_decs_struct ); + /* Only RandState and RD_Q10 need to be initialized to 0. */ + silk_memset( psDelDec->RandState, 0, sizeof( psDelDec->RandState ) ); + vst1q_s32( psDelDec->RD_Q10, vdupq_n_s32( 0 ) ); + + for( k = 0; k < psEncC->nStatesDelayedDecision; k++ ) { + psDelDec->SeedInit[ k ] = psDelDec->Seed[ k ] = ( k + psIndices->Seed ) & 3; + } + vst1q_s32( psDelDec->LF_AR_Q14, vld1q_dup_s32( &NSQ->sLF_AR_shp_Q14 ) ); + vst1q_s32( psDelDec->Diff_Q14, vld1q_dup_s32( &NSQ->sDiff_shp_Q14 ) ); + vst1q_s32( psDelDec->Shape_Q14[ 0 ], vld1q_dup_s32( &NSQ->sLTP_shp_Q14[ psEncC->ltp_mem_length - 1 ] ) ); + for( i = 0; i < NSQ_LPC_BUF_LENGTH; i++ ) { + vst1q_s32( psDelDec->sLPC_Q14[ i ], vld1q_dup_s32( &NSQ->sLPC_Q14[ i ] ) ); + } + for( i = 0; i < (opus_int)( sizeof( NSQ->sAR2_Q14 ) / sizeof( NSQ->sAR2_Q14[ 0 ] ) ); i++ ) { + vst1q_s32( psDelDec->sAR2_Q14[ i ], vld1q_dup_s32( &NSQ->sAR2_Q14[ i ] ) ); + } + + offset_Q10 = silk_Quantization_Offsets_Q10[ psIndices->signalType >> 1 ][ psIndices->quantOffsetType ]; + smpl_buf_idx = 0; /* index of oldest samples */ + + decisionDelay = silk_min_int( DECISION_DELAY, psEncC->subfr_length ); + + /* For voiced frames limit the decision delay to lower than the pitch lag */ + if( psIndices->signalType == TYPE_VOICED ) { + opus_int pitch_min = pitchL[ 0 ]; + for( k = 1; k < psEncC->nb_subfr; k++ ) { + pitch_min = silk_min_int( pitch_min, pitchL[ k ] ); + } + decisionDelay = silk_min_int( decisionDelay, pitch_min - LTP_ORDER / 2 - 1 ); + } else { + if( lag > 0 ) { + decisionDelay = silk_min_int( decisionDelay, lag - LTP_ORDER / 2 - 1 ); + } + } + + if( psIndices->NLSFInterpCoef_Q2 == 4 ) { + LSF_interpolation_flag = 0; + } else { + LSF_interpolation_flag = 1; + } + + ALLOC( sLTP_Q15, psEncC->ltp_mem_length + psEncC->frame_length, opus_int32 ); + ALLOC( sLTP, psEncC->ltp_mem_length + psEncC->frame_length, opus_int16 ); + ALLOC( x_sc_Q10, psEncC->subfr_length, opus_int32 ); + ALLOC( delayedGain_Q10, DECISION_DELAY, opus_int32 ); + /* Set up pointers to start of sub frame */ + pxq = &NSQ->xq[ psEncC->ltp_mem_length ]; + NSQ->sLTP_shp_buf_idx = psEncC->ltp_mem_length; + NSQ->sLTP_buf_idx = psEncC->ltp_mem_length; + subfr = 0; + for( k = 0; k < psEncC->nb_subfr; k++ ) { + A_Q12 = &PredCoef_Q12[ ( ( k >> 1 ) | ( 1 - LSF_interpolation_flag ) ) * MAX_LPC_ORDER ]; + B_Q14 = <PCoef_Q14[ k * LTP_ORDER ]; + AR_shp_Q13 = &AR_Q13[ k * MAX_SHAPE_LPC_ORDER ]; + + /* Noise shape parameters */ + silk_assert( HarmShapeGain_Q14[ k ] >= 0 ); + HarmShapeFIRPacked_Q14 = silk_RSHIFT( HarmShapeGain_Q14[ k ], 2 ); + HarmShapeFIRPacked_Q14 |= silk_LSHIFT( (opus_int32)silk_RSHIFT( HarmShapeGain_Q14[ k ], 1 ), 16 ); + + NSQ->rewhite_flag = 0; + if( psIndices->signalType == TYPE_VOICED ) { + /* Voiced */ + lag = pitchL[ k ]; + + /* Re-whitening */ + if( ( k & ( 3 - silk_LSHIFT( LSF_interpolation_flag, 1 ) ) ) == 0 ) { + if( k == 2 ) { + /* RESET DELAYED DECISIONS */ + /* Find winner */ + int32x4_t RD_Q10_s32x4; + RDmin_Q10 = psDelDec->RD_Q10[ 0 ]; + Winner_ind = 0; + for( i = 1; i < psEncC->nStatesDelayedDecision; i++ ) { + if( psDelDec->RD_Q10[ i ] < RDmin_Q10 ) { + RDmin_Q10 = psDelDec->RD_Q10[ i ]; + Winner_ind = i; + } + } + psDelDec->RD_Q10[ Winner_ind ] -= ( silk_int32_MAX >> 4 ); + RD_Q10_s32x4 = vld1q_s32( psDelDec->RD_Q10 ); + RD_Q10_s32x4 = vaddq_s32( RD_Q10_s32x4, vdupq_n_s32( silk_int32_MAX >> 4 ) ); + vst1q_s32( psDelDec->RD_Q10, RD_Q10_s32x4 ); + + /* Copy final part of signals from winner state to output and long-term filter states */ + copy_winner_state( psDelDec, decisionDelay, smpl_buf_idx, Winner_ind, Gains_Q16[ 1 ], 14, pulses, pxq, NSQ ); + + subfr = 0; + } + + /* Rewhiten with new A coefs */ + start_idx = psEncC->ltp_mem_length - lag - psEncC->predictLPCOrder - LTP_ORDER / 2; + silk_assert( start_idx > 0 ); + + silk_LPC_analysis_filter( &sLTP[ start_idx ], &NSQ->xq[ start_idx + k * psEncC->subfr_length ], + A_Q12, psEncC->ltp_mem_length - start_idx, psEncC->predictLPCOrder, psEncC->arch ); + + NSQ->sLTP_buf_idx = psEncC->ltp_mem_length; + NSQ->rewhite_flag = 1; + } + } + + silk_nsq_del_dec_scale_states_neon( psEncC, NSQ, psDelDec, x16, x_sc_Q10, sLTP, sLTP_Q15, k, + LTP_scale_Q14, Gains_Q16, pitchL, psIndices->signalType, decisionDelay ); + + silk_noise_shape_quantizer_del_dec_neon( NSQ, psDelDec, psIndices->signalType, x_sc_Q10, pulses, pxq, sLTP_Q15, + delayedGain_Q10, A_Q12, B_Q14, AR_shp_Q13, 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, decisionDelay ); + + x16 += psEncC->subfr_length; + pulses += psEncC->subfr_length; + pxq += psEncC->subfr_length; + } + + /* Find winner */ + RDmin_Q10 = psDelDec->RD_Q10[ 0 ]; + Winner_ind = 0; + for( k = 1; k < psEncC->nStatesDelayedDecision; k++ ) { + if( psDelDec->RD_Q10[ k ] < RDmin_Q10 ) { + RDmin_Q10 = psDelDec->RD_Q10[ k ]; + Winner_ind = k; + } + } + + /* Copy final part of signals from winner state to output and long-term filter states */ + psIndices->Seed = psDelDec->SeedInit[ Winner_ind ]; + Gain_Q10 = silk_RSHIFT32( Gains_Q16[ psEncC->nb_subfr - 1 ], 6 ); + copy_winner_state( psDelDec, decisionDelay, smpl_buf_idx, Winner_ind, Gain_Q10, 8, pulses, pxq, NSQ ); + + t_s32x4 = vdupq_n_s32( 0 ); /* initialization */ + for( i = 0; i < ( NSQ_LPC_BUF_LENGTH - 3 ); i += 4 ) { + t_s32x4 = vld1q_lane_s32( &psDelDec->sLPC_Q14[ i + 0 ][ Winner_ind ], t_s32x4, 0 ); + t_s32x4 = vld1q_lane_s32( &psDelDec->sLPC_Q14[ i + 1 ][ Winner_ind ], t_s32x4, 1 ); + t_s32x4 = vld1q_lane_s32( &psDelDec->sLPC_Q14[ i + 2 ][ Winner_ind ], t_s32x4, 2 ); + t_s32x4 = vld1q_lane_s32( &psDelDec->sLPC_Q14[ i + 3 ][ Winner_ind ], t_s32x4, 3 ); + vst1q_s32( &NSQ->sLPC_Q14[ i ], t_s32x4 ); + } + + for( ; i < NSQ_LPC_BUF_LENGTH; i++ ) { + NSQ->sLPC_Q14[ i ] = psDelDec->sLPC_Q14[ i ][ Winner_ind ]; + } + + for( i = 0; i < (opus_int)( sizeof( NSQ->sAR2_Q14 ) / sizeof( NSQ->sAR2_Q14[ 0 ] ) - 3 ); i += 4 ) { + t_s32x4 = vld1q_lane_s32( &psDelDec->sAR2_Q14[ i + 0 ][ Winner_ind ], t_s32x4, 0 ); + t_s32x4 = vld1q_lane_s32( &psDelDec->sAR2_Q14[ i + 1 ][ Winner_ind ], t_s32x4, 1 ); + t_s32x4 = vld1q_lane_s32( &psDelDec->sAR2_Q14[ i + 2 ][ Winner_ind ], t_s32x4, 2 ); + t_s32x4 = vld1q_lane_s32( &psDelDec->sAR2_Q14[ i + 3 ][ Winner_ind ], t_s32x4, 3 ); + vst1q_s32( &NSQ->sAR2_Q14[ i ], t_s32x4 ); + } + + for( ; i < (opus_int)( sizeof( NSQ->sAR2_Q14 ) / sizeof( NSQ->sAR2_Q14[ 0 ] ) ); i++ ) { + NSQ->sAR2_Q14[ i ] = psDelDec->sAR2_Q14[ i ][ Winner_ind ]; + } + + /* Update states */ + NSQ->sLF_AR_shp_Q14 = psDelDec->LF_AR_Q14[ Winner_ind ]; + NSQ->sDiff_shp_Q14 = psDelDec->Diff_Q14[ Winner_ind ]; + NSQ->lagPrev = pitchL[ psEncC->nb_subfr - 1 ]; + + /* Save quantized speech signal */ + silk_memmove( NSQ->xq, &NSQ->xq[ psEncC->frame_length ], psEncC->ltp_mem_length * sizeof( opus_int16 ) ); + silk_memmove( NSQ->sLTP_shp_Q14, &NSQ->sLTP_shp_Q14[ psEncC->frame_length ], psEncC->ltp_mem_length * sizeof( opus_int32 ) ); + RESTORE_STACK; + } + +#ifdef OPUS_CHECK_ASM + silk_assert( !memcmp( &NSQ_c, NSQ, sizeof( NSQ_c ) ) ); + silk_assert( !memcmp( &psIndices_c, psIndices, sizeof( psIndices_c ) ) ); + silk_assert( !memcmp( pulses_c, pulses_a, sizeof( pulses_c ) ) ); +#endif +} + +/******************************************/ +/* Noise shape quantizer for one subframe */ +/******************************************/ +/* Note: Function silk_short_prediction_create_arch_coef_neon() defined in NSQ_neon.h is actually a hacking C function. */ +/* Therefore here we append "_local" to the NEON function name to avoid confusion. */ +static OPUS_INLINE void silk_short_prediction_create_arch_coef_neon_local(opus_int32 *out, const opus_int16 *in, opus_int order) +{ + int16x8_t t_s16x8; + int32x4_t t0_s32x4, t1_s32x4, t2_s32x4, t3_s32x4; + silk_assert( order == 10 || order == 16 ); + + t_s16x8 = vld1q_s16( in + 0 ); /* 7 6 5 4 3 2 1 0 */ + t_s16x8 = vrev64q_s16( t_s16x8 ); /* 4 5 6 7 0 1 2 3 */ + t2_s32x4 = vshll_n_s16( vget_high_s16( t_s16x8 ), 15 ); /* 4 5 6 7 */ + t3_s32x4 = vshll_n_s16( vget_low_s16( t_s16x8 ), 15 ); /* 0 1 2 3 */ + + if( order == 16 ) { + t_s16x8 = vld1q_s16( in + 8 ); /* F E D C B A 9 8 */ + t_s16x8 = vrev64q_s16( t_s16x8 ); /* C D E F 8 9 A B */ + t0_s32x4 = vshll_n_s16( vget_high_s16( t_s16x8 ), 15 ); /* C D E F */ + t1_s32x4 = vshll_n_s16( vget_low_s16( t_s16x8 ), 15 ); /* 8 9 A B */ + } else { + int16x4_t t_s16x4; + + t0_s32x4 = vdupq_n_s32( 0 ); /* zero zero zero zero */ + t_s16x4 = vld1_s16( in + 6 ); /* 9 8 7 6 */ + t_s16x4 = vrev64_s16( t_s16x4 ); /* 6 7 8 9 */ + t1_s32x4 = vshll_n_s16( t_s16x4, 15 ); + t1_s32x4 = vcombine_s32( vget_low_s32(t0_s32x4), vget_low_s32( t1_s32x4 ) ); /* 8 9 zero zero */ + } + vst1q_s32( out + 0, t0_s32x4 ); + vst1q_s32( out + 4, t1_s32x4 ); + vst1q_s32( out + 8, t2_s32x4 ); + vst1q_s32( out + 12, t3_s32x4 ); +} + +static OPUS_INLINE int32x4_t silk_SMLAWB_lane0_neon( + const int32x4_t out_s32x4, + const int32x4_t in_s32x4, + const int32x2_t coef_s32x2 +) +{ + return vaddq_s32( out_s32x4, vqdmulhq_lane_s32( in_s32x4, coef_s32x2, 0 ) ); +} + +static OPUS_INLINE int32x4_t silk_SMLAWB_lane1_neon( + const int32x4_t out_s32x4, + const int32x4_t in_s32x4, + const int32x2_t coef_s32x2 +) +{ + return vaddq_s32( out_s32x4, vqdmulhq_lane_s32( in_s32x4, coef_s32x2, 1 ) ); +} + +/* Note: This function has different return value than silk_noise_shape_quantizer_short_prediction_neon(). */ +/* Therefore here we append "_local" to the function name to avoid confusion. */ +static OPUS_INLINE int32x4_t silk_noise_shape_quantizer_short_prediction_neon_local(const opus_int32 *buf32, const opus_int32 *a_Q12_arch, opus_int order) +{ + const int32x4_t a_Q12_arch0_s32x4 = vld1q_s32( a_Q12_arch + 0 ); + const int32x4_t a_Q12_arch1_s32x4 = vld1q_s32( a_Q12_arch + 4 ); + const int32x4_t a_Q12_arch2_s32x4 = vld1q_s32( a_Q12_arch + 8 ); + const int32x4_t a_Q12_arch3_s32x4 = vld1q_s32( a_Q12_arch + 12 ); + int32x4_t LPC_pred_Q14_s32x4; + + silk_assert( order == 10 || order == 16 ); + /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */ + LPC_pred_Q14_s32x4 = vdupq_n_s32( silk_RSHIFT( order, 1 ) ); + LPC_pred_Q14_s32x4 = silk_SMLAWB_lane0_neon( LPC_pred_Q14_s32x4, vld1q_s32( buf32 + 0 * NEON_MAX_DEL_DEC_STATES ), vget_low_s32( a_Q12_arch0_s32x4 ) ); + LPC_pred_Q14_s32x4 = silk_SMLAWB_lane1_neon( LPC_pred_Q14_s32x4, vld1q_s32( buf32 + 1 * NEON_MAX_DEL_DEC_STATES ), vget_low_s32( a_Q12_arch0_s32x4 ) ); + LPC_pred_Q14_s32x4 = silk_SMLAWB_lane0_neon( LPC_pred_Q14_s32x4, vld1q_s32( buf32 + 2 * NEON_MAX_DEL_DEC_STATES ), vget_high_s32( a_Q12_arch0_s32x4 ) ); + LPC_pred_Q14_s32x4 = silk_SMLAWB_lane1_neon( LPC_pred_Q14_s32x4, vld1q_s32( buf32 + 3 * NEON_MAX_DEL_DEC_STATES ), vget_high_s32( a_Q12_arch0_s32x4 ) ); + LPC_pred_Q14_s32x4 = silk_SMLAWB_lane0_neon( LPC_pred_Q14_s32x4, vld1q_s32( buf32 + 4 * NEON_MAX_DEL_DEC_STATES ), vget_low_s32( a_Q12_arch1_s32x4 ) ); + LPC_pred_Q14_s32x4 = silk_SMLAWB_lane1_neon( LPC_pred_Q14_s32x4, vld1q_s32( buf32 + 5 * NEON_MAX_DEL_DEC_STATES ), vget_low_s32( a_Q12_arch1_s32x4 ) ); + LPC_pred_Q14_s32x4 = silk_SMLAWB_lane0_neon( LPC_pred_Q14_s32x4, vld1q_s32( buf32 + 6 * NEON_MAX_DEL_DEC_STATES ), vget_high_s32( a_Q12_arch1_s32x4 ) ); + LPC_pred_Q14_s32x4 = silk_SMLAWB_lane1_neon( LPC_pred_Q14_s32x4, vld1q_s32( buf32 + 7 * NEON_MAX_DEL_DEC_STATES ), vget_high_s32( a_Q12_arch1_s32x4 ) ); + LPC_pred_Q14_s32x4 = silk_SMLAWB_lane0_neon( LPC_pred_Q14_s32x4, vld1q_s32( buf32 + 8 * NEON_MAX_DEL_DEC_STATES ), vget_low_s32( a_Q12_arch2_s32x4 ) ); + LPC_pred_Q14_s32x4 = silk_SMLAWB_lane1_neon( LPC_pred_Q14_s32x4, vld1q_s32( buf32 + 9 * NEON_MAX_DEL_DEC_STATES ), vget_low_s32( a_Q12_arch2_s32x4 ) ); + LPC_pred_Q14_s32x4 = silk_SMLAWB_lane0_neon( LPC_pred_Q14_s32x4, vld1q_s32( buf32 + 10 * NEON_MAX_DEL_DEC_STATES ), vget_high_s32( a_Q12_arch2_s32x4 ) ); + LPC_pred_Q14_s32x4 = silk_SMLAWB_lane1_neon( LPC_pred_Q14_s32x4, vld1q_s32( buf32 + 11 * NEON_MAX_DEL_DEC_STATES ), vget_high_s32( a_Q12_arch2_s32x4 ) ); + LPC_pred_Q14_s32x4 = silk_SMLAWB_lane0_neon( LPC_pred_Q14_s32x4, vld1q_s32( buf32 + 12 * NEON_MAX_DEL_DEC_STATES ), vget_low_s32( a_Q12_arch3_s32x4 ) ); + LPC_pred_Q14_s32x4 = silk_SMLAWB_lane1_neon( LPC_pred_Q14_s32x4, vld1q_s32( buf32 + 13 * NEON_MAX_DEL_DEC_STATES ), vget_low_s32( a_Q12_arch3_s32x4 ) ); + LPC_pred_Q14_s32x4 = silk_SMLAWB_lane0_neon( LPC_pred_Q14_s32x4, vld1q_s32( buf32 + 14 * NEON_MAX_DEL_DEC_STATES ), vget_high_s32( a_Q12_arch3_s32x4 ) ); + LPC_pred_Q14_s32x4 = silk_SMLAWB_lane1_neon( LPC_pred_Q14_s32x4, vld1q_s32( buf32 + 15 * NEON_MAX_DEL_DEC_STATES ), vget_high_s32( a_Q12_arch3_s32x4 ) ); + + return LPC_pred_Q14_s32x4; +} + +static OPUS_INLINE void silk_noise_shape_quantizer_del_dec_neon( + silk_nsq_state *NSQ, /* I/O NSQ state */ + NSQ_del_decs_struct psDelDec[], /* I/O Delayed decision states */ + opus_int signalType, /* I Signal type */ + const opus_int32 x_Q10[], /* I */ + opus_int8 pulses[], /* O */ + opus_int16 xq[], /* O */ + opus_int32 sLTP_Q15[], /* I/O LTP filter state */ + opus_int32 delayedGain_Q10[], /* I/O Gain delay buffer */ + const opus_int16 a_Q12[], /* I Short term prediction coefs */ + const opus_int16 b_Q14[], /* I Long term prediction coefs */ + const opus_int16 AR_shp_Q13[], /* I Noise shaping coefs */ + opus_int lag, /* I Pitch lag */ + opus_int32 HarmShapeFIRPacked_Q14, /* I */ + opus_int Tilt_Q14, /* I Spectral tilt */ + opus_int32 LF_shp_Q14, /* I */ + opus_int32 Gain_Q16, /* I */ + opus_int Lambda_Q10, /* I */ + opus_int offset_Q10, /* I */ + opus_int length, /* I Input length */ + opus_int subfr, /* I Subframe number */ + opus_int shapingLPCOrder, /* I Shaping LPC filter order */ + opus_int predictLPCOrder, /* I Prediction filter order */ + opus_int warping_Q16, /* I */ + opus_int nStatesDelayedDecision, /* I Number of states in decision tree */ + opus_int *smpl_buf_idx, /* I/O Index to newest samples in buffers */ + opus_int decisionDelay /* I */ +) +{ + opus_int i, j, k, Winner_ind, RDmin_ind, RDmax_ind, last_smple_idx; + opus_int32 Winner_rand_state; + opus_int32 LTP_pred_Q14, n_LTP_Q14; + opus_int32 RDmin_Q10, RDmax_Q10; + opus_int32 Gain_Q10; + opus_int32 *pred_lag_ptr, *shp_lag_ptr; + opus_int32 a_Q12_arch[MAX_LPC_ORDER]; + const int32x2_t warping_Q16_s32x2 = vdup_n_s32( silk_LSHIFT32( warping_Q16, 16 ) >> 1 ); + const opus_int32 LF_shp_Q29 = silk_LSHIFT32( LF_shp_Q14, 16 ) >> 1; + opus_int32 AR_shp_Q28[ MAX_SHAPE_LPC_ORDER ]; + const uint32x4_t rand_multiplier_u32x4 = vdupq_n_u32( RAND_MULTIPLIER ); + const uint32x4_t rand_increment_u32x4 = vdupq_n_u32( RAND_INCREMENT ); + + VARDECL( NSQ_samples_struct, psSampleState ); + SAVE_STACK; + + silk_assert( nStatesDelayedDecision > 0 ); + silk_assert( ( shapingLPCOrder & 1 ) == 0 ); /* check that order is even */ + ALLOC( psSampleState, 2, NSQ_samples_struct ); + + shp_lag_ptr = &NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - lag + HARM_SHAPE_FIR_TAPS / 2 ]; + pred_lag_ptr = &sLTP_Q15[ NSQ->sLTP_buf_idx - lag + LTP_ORDER / 2 ]; + Gain_Q10 = silk_RSHIFT( Gain_Q16, 6 ); + + for( i = 0; i < ( MAX_SHAPE_LPC_ORDER - 7 ); i += 8 ) { + const int16x8_t t_s16x8 = vld1q_s16( AR_shp_Q13 + i ); + vst1q_s32( AR_shp_Q28 + i + 0, vshll_n_s16( vget_low_s16( t_s16x8 ), 15 ) ); + vst1q_s32( AR_shp_Q28 + i + 4, vshll_n_s16( vget_high_s16( t_s16x8 ), 15 ) ); + } + + for( ; i < MAX_SHAPE_LPC_ORDER; i++ ) { + AR_shp_Q28[i] = silk_LSHIFT32( AR_shp_Q13[i], 15 ); + } + + silk_short_prediction_create_arch_coef_neon_local( a_Q12_arch, a_Q12, predictLPCOrder ); + + for( i = 0; i < length; i++ ) { + int32x4_t Seed_s32x4, LPC_pred_Q14_s32x4; + int32x4_t sign_s32x4, tmp1_s32x4, tmp2_s32x4; + int32x4_t n_AR_Q14_s32x4, n_LF_Q14_s32x4; + int32x2_t AR_shp_Q28_s32x2; + int16x4_t r_Q10_s16x4, rr_Q10_s16x4; + + /* Perform common calculations used in all states */ + + /* Long-term prediction */ + if( signalType == TYPE_VOICED ) { + /* Unrolled loop */ + /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */ + LTP_pred_Q14 = 2; + LTP_pred_Q14 = silk_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ 0 ], b_Q14[ 0 ] ); + LTP_pred_Q14 = silk_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ -1 ], b_Q14[ 1 ] ); + LTP_pred_Q14 = silk_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ -2 ], b_Q14[ 2 ] ); + LTP_pred_Q14 = silk_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ -3 ], b_Q14[ 3 ] ); + LTP_pred_Q14 = silk_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ -4 ], b_Q14[ 4 ] ); + LTP_pred_Q14 = silk_LSHIFT( LTP_pred_Q14, 1 ); /* Q13 -> Q14 */ + pred_lag_ptr++; + } else { + LTP_pred_Q14 = 0; + } + + /* Long-term shaping */ + if( lag > 0 ) { + /* Symmetric, packed FIR coefficients */ + n_LTP_Q14 = silk_SMULWB( silk_ADD32( shp_lag_ptr[ 0 ], shp_lag_ptr[ -2 ] ), HarmShapeFIRPacked_Q14 ); + n_LTP_Q14 = silk_SMLAWT( n_LTP_Q14, shp_lag_ptr[ -1 ], HarmShapeFIRPacked_Q14 ); + n_LTP_Q14 = silk_SUB_LSHIFT32( LTP_pred_Q14, n_LTP_Q14, 2 ); /* Q12 -> Q14 */ + shp_lag_ptr++; + } else { + n_LTP_Q14 = 0; + } + + /* Generate dither */ + Seed_s32x4 = vld1q_s32( psDelDec->Seed ); + Seed_s32x4 = vreinterpretq_s32_u32( vmlaq_u32( rand_increment_u32x4, vreinterpretq_u32_s32( Seed_s32x4 ), rand_multiplier_u32x4 ) ); + vst1q_s32( psDelDec->Seed, Seed_s32x4 ); + + /* Short-term prediction */ + LPC_pred_Q14_s32x4 = silk_noise_shape_quantizer_short_prediction_neon_local(psDelDec->sLPC_Q14[ NSQ_LPC_BUF_LENGTH - 16 + i ], a_Q12_arch, predictLPCOrder); + LPC_pred_Q14_s32x4 = vshlq_n_s32( LPC_pred_Q14_s32x4, 4 ); /* Q10 -> Q14 */ + + /* Noise shape feedback */ + /* Output of lowpass section */ + tmp2_s32x4 = silk_SMLAWB_lane0_neon( vld1q_s32( psDelDec->Diff_Q14 ), vld1q_s32( psDelDec->sAR2_Q14[ 0 ] ), warping_Q16_s32x2 ); + /* Output of allpass section */ + tmp1_s32x4 = vsubq_s32( vld1q_s32( psDelDec->sAR2_Q14[ 1 ] ), tmp2_s32x4 ); + tmp1_s32x4 = silk_SMLAWB_lane0_neon( vld1q_s32( psDelDec->sAR2_Q14[ 0 ] ), tmp1_s32x4, warping_Q16_s32x2 ); + vst1q_s32( psDelDec->sAR2_Q14[ 0 ], tmp2_s32x4 ); + AR_shp_Q28_s32x2 = vld1_s32( AR_shp_Q28 ); + n_AR_Q14_s32x4 = vaddq_s32( vdupq_n_s32( silk_RSHIFT( shapingLPCOrder, 1 ) ), vqdmulhq_lane_s32( tmp2_s32x4, AR_shp_Q28_s32x2, 0 ) ); + + /* Loop over allpass sections */ + for( j = 2; j < shapingLPCOrder; j += 2 ) { + /* Output of allpass section */ + tmp2_s32x4 = vsubq_s32( vld1q_s32( psDelDec->sAR2_Q14[ j + 0 ] ), tmp1_s32x4 ); + tmp2_s32x4 = silk_SMLAWB_lane0_neon( vld1q_s32( psDelDec->sAR2_Q14[ j - 1 ] ), tmp2_s32x4, warping_Q16_s32x2 ); + vst1q_s32( psDelDec->sAR2_Q14[ j - 1 ], tmp1_s32x4 ); + n_AR_Q14_s32x4 = vaddq_s32( n_AR_Q14_s32x4, vqdmulhq_lane_s32( tmp1_s32x4, AR_shp_Q28_s32x2, 1 ) ); + /* Output of allpass section */ + tmp1_s32x4 = vsubq_s32( vld1q_s32( psDelDec->sAR2_Q14[ j + 1 ] ), tmp2_s32x4 ); + tmp1_s32x4 = silk_SMLAWB_lane0_neon( vld1q_s32( psDelDec->sAR2_Q14[ j + 0 ] ), tmp1_s32x4, warping_Q16_s32x2 ); + vst1q_s32( psDelDec->sAR2_Q14[ j + 0 ], tmp2_s32x4 ); + AR_shp_Q28_s32x2 = vld1_s32( &AR_shp_Q28[ j ] ); + n_AR_Q14_s32x4 = vaddq_s32( n_AR_Q14_s32x4, vqdmulhq_lane_s32( tmp2_s32x4, AR_shp_Q28_s32x2, 0 ) ); + } + vst1q_s32( psDelDec->sAR2_Q14[ shapingLPCOrder - 1 ], tmp1_s32x4 ); + n_AR_Q14_s32x4 = vaddq_s32( n_AR_Q14_s32x4, vqdmulhq_lane_s32( tmp1_s32x4, AR_shp_Q28_s32x2, 1 ) ); + n_AR_Q14_s32x4 = vshlq_n_s32( n_AR_Q14_s32x4, 1 ); /* Q11 -> Q12 */ + n_AR_Q14_s32x4 = vaddq_s32( n_AR_Q14_s32x4, vqdmulhq_n_s32( vld1q_s32( psDelDec->LF_AR_Q14 ), silk_LSHIFT32( Tilt_Q14, 16 ) >> 1 ) ); /* Q12 */ + n_AR_Q14_s32x4 = vshlq_n_s32( n_AR_Q14_s32x4, 2 ); /* Q12 -> Q14 */ + n_LF_Q14_s32x4 = vqdmulhq_n_s32( vld1q_s32( psDelDec->Shape_Q14[ *smpl_buf_idx ] ), LF_shp_Q29 ); /* Q12 */ + n_LF_Q14_s32x4 = vaddq_s32( n_LF_Q14_s32x4, vqdmulhq_n_s32( vld1q_s32( psDelDec->LF_AR_Q14 ), silk_LSHIFT32( LF_shp_Q14 >> 16 , 15 ) ) ); /* Q12 */ + n_LF_Q14_s32x4 = vshlq_n_s32( n_LF_Q14_s32x4, 2 ); /* Q12 -> Q14 */ + + /* Input minus prediction plus noise feedback */ + /* r = x[ i ] - LTP_pred - LPC_pred + n_AR + n_Tilt + n_LF + n_LTP */ + tmp1_s32x4 = vaddq_s32( n_AR_Q14_s32x4, n_LF_Q14_s32x4 ); /* Q14 */ + tmp2_s32x4 = vaddq_s32( vdupq_n_s32( n_LTP_Q14 ), LPC_pred_Q14_s32x4 ); /* Q13 */ + tmp1_s32x4 = vsubq_s32( tmp2_s32x4, tmp1_s32x4 ); /* Q13 */ + tmp1_s32x4 = vrshrq_n_s32( tmp1_s32x4, 4 ); /* Q10 */ + tmp1_s32x4 = vsubq_s32( vdupq_n_s32( x_Q10[ i ] ), tmp1_s32x4 ); /* residual error Q10 */ + + /* Flip sign depending on dither */ + sign_s32x4 = vreinterpretq_s32_u32( vcltq_s32( Seed_s32x4, vdupq_n_s32( 0 ) ) ); + tmp1_s32x4 = veorq_s32( tmp1_s32x4, sign_s32x4 ); + tmp1_s32x4 = vsubq_s32( tmp1_s32x4, sign_s32x4 ); + tmp1_s32x4 = vmaxq_s32( tmp1_s32x4, vdupq_n_s32( -( 31 << 10 ) ) ); + tmp1_s32x4 = vminq_s32( tmp1_s32x4, vdupq_n_s32( 30 << 10 ) ); + r_Q10_s16x4 = vmovn_s32( tmp1_s32x4 ); + + /* Find two quantization level candidates and measure their rate-distortion */ + { + int16x4_t q1_Q10_s16x4 = vsub_s16( r_Q10_s16x4, vdup_n_s16( offset_Q10 ) ); + int16x4_t q1_Q0_s16x4 = vshr_n_s16( q1_Q10_s16x4, 10 ); + int16x4_t q2_Q10_s16x4; + int32x4_t rd1_Q10_s32x4, rd2_Q10_s32x4; + uint32x4_t t_u32x4; + + if( Lambda_Q10 > 2048 ) { + /* For aggressive RDO, the bias becomes more than one pulse. */ + const int rdo_offset = Lambda_Q10/2 - 512; + const uint16x4_t greaterThanRdo = vcgt_s16( q1_Q10_s16x4, vdup_n_s16( rdo_offset ) ); + const uint16x4_t lessThanMinusRdo = vclt_s16( q1_Q10_s16x4, vdup_n_s16( -rdo_offset ) ); + /* If Lambda_Q10 > 32767, then q1_Q0, q1_Q10 and q2_Q10 must change to 32-bit. */ + silk_assert( Lambda_Q10 <= 32767 ); + + q1_Q0_s16x4 = vreinterpret_s16_u16( vclt_s16( q1_Q10_s16x4, vdup_n_s16( 0 ) ) ); + q1_Q0_s16x4 = vbsl_s16( greaterThanRdo, vsub_s16( q1_Q10_s16x4, vdup_n_s16( rdo_offset ) ), q1_Q0_s16x4 ); + q1_Q0_s16x4 = vbsl_s16( lessThanMinusRdo, vadd_s16( q1_Q10_s16x4, vdup_n_s16( rdo_offset ) ), q1_Q0_s16x4 ); + q1_Q0_s16x4 = vshr_n_s16( q1_Q0_s16x4, 10 ); + } + { + const uint16x4_t equal0_u16x4 = vceq_s16( q1_Q0_s16x4, vdup_n_s16( 0 ) ); + const uint16x4_t equalMinus1_u16x4 = vceq_s16( q1_Q0_s16x4, vdup_n_s16( -1 ) ); + const uint16x4_t lessThanMinus1_u16x4 = vclt_s16( q1_Q0_s16x4, vdup_n_s16( -1 ) ); + int16x4_t tmp1_s16x4, tmp2_s16x4; + + q1_Q10_s16x4 = vshl_n_s16( q1_Q0_s16x4, 10 ); + tmp1_s16x4 = vadd_s16( q1_Q10_s16x4, vdup_n_s16( offset_Q10 - QUANT_LEVEL_ADJUST_Q10 ) ); + q1_Q10_s16x4 = vadd_s16( q1_Q10_s16x4, vdup_n_s16( offset_Q10 + QUANT_LEVEL_ADJUST_Q10 ) ); + q1_Q10_s16x4 = vbsl_s16( lessThanMinus1_u16x4, q1_Q10_s16x4, tmp1_s16x4 ); + q1_Q10_s16x4 = vbsl_s16( equal0_u16x4, vdup_n_s16( offset_Q10 ), q1_Q10_s16x4 ); + q1_Q10_s16x4 = vbsl_s16( equalMinus1_u16x4, vdup_n_s16( offset_Q10 - ( 1024 - QUANT_LEVEL_ADJUST_Q10 ) ), q1_Q10_s16x4 ); + q2_Q10_s16x4 = vadd_s16( q1_Q10_s16x4, vdup_n_s16( 1024 ) ); + q2_Q10_s16x4 = vbsl_s16( equal0_u16x4, vdup_n_s16( offset_Q10 + 1024 - QUANT_LEVEL_ADJUST_Q10 ), q2_Q10_s16x4 ); + q2_Q10_s16x4 = vbsl_s16( equalMinus1_u16x4, vdup_n_s16( offset_Q10 ), q2_Q10_s16x4 ); + tmp1_s16x4 = q1_Q10_s16x4; + tmp2_s16x4 = q2_Q10_s16x4; + tmp1_s16x4 = vbsl_s16( vorr_u16( equalMinus1_u16x4, lessThanMinus1_u16x4 ), vneg_s16( tmp1_s16x4 ), tmp1_s16x4 ); + tmp2_s16x4 = vbsl_s16( lessThanMinus1_u16x4, vneg_s16( tmp2_s16x4 ), tmp2_s16x4 ); + rd1_Q10_s32x4 = vmull_s16( tmp1_s16x4, vdup_n_s16( Lambda_Q10 ) ); + rd2_Q10_s32x4 = vmull_s16( tmp2_s16x4, vdup_n_s16( Lambda_Q10 ) ); + } + + rr_Q10_s16x4 = vsub_s16( r_Q10_s16x4, q1_Q10_s16x4 ); + rd1_Q10_s32x4 = vmlal_s16( rd1_Q10_s32x4, rr_Q10_s16x4, rr_Q10_s16x4 ); + rd1_Q10_s32x4 = vshrq_n_s32( rd1_Q10_s32x4, 10 ); + + rr_Q10_s16x4 = vsub_s16( r_Q10_s16x4, q2_Q10_s16x4 ); + rd2_Q10_s32x4 = vmlal_s16( rd2_Q10_s32x4, rr_Q10_s16x4, rr_Q10_s16x4 ); + rd2_Q10_s32x4 = vshrq_n_s32( rd2_Q10_s32x4, 10 ); + + tmp2_s32x4 = vld1q_s32( psDelDec->RD_Q10 ); + tmp1_s32x4 = vaddq_s32( tmp2_s32x4, vminq_s32( rd1_Q10_s32x4, rd2_Q10_s32x4 ) ); + tmp2_s32x4 = vaddq_s32( tmp2_s32x4, vmaxq_s32( rd1_Q10_s32x4, rd2_Q10_s32x4 ) ); + vst1q_s32( psSampleState[ 0 ].RD_Q10, tmp1_s32x4 ); + vst1q_s32( psSampleState[ 1 ].RD_Q10, tmp2_s32x4 ); + t_u32x4 = vcltq_s32( rd1_Q10_s32x4, rd2_Q10_s32x4 ); + tmp1_s32x4 = vbslq_s32( t_u32x4, vmovl_s16( q1_Q10_s16x4 ), vmovl_s16( q2_Q10_s16x4 ) ); + tmp2_s32x4 = vbslq_s32( t_u32x4, vmovl_s16( q2_Q10_s16x4 ), vmovl_s16( q1_Q10_s16x4 ) ); + vst1q_s32( psSampleState[ 0 ].Q_Q10, tmp1_s32x4 ); + vst1q_s32( psSampleState[ 1 ].Q_Q10, tmp2_s32x4 ); + } + + { + /* Update states for best quantization */ + int32x4_t exc_Q14_s32x4, LPC_exc_Q14_s32x4, xq_Q14_s32x4, sLF_AR_shp_Q14_s32x4; + + /* Quantized excitation */ + exc_Q14_s32x4 = vshlq_n_s32( tmp1_s32x4, 4 ); + exc_Q14_s32x4 = veorq_s32( exc_Q14_s32x4, sign_s32x4 ); + exc_Q14_s32x4 = vsubq_s32( exc_Q14_s32x4, sign_s32x4 ); + + /* Add predictions */ + LPC_exc_Q14_s32x4 = vaddq_s32( exc_Q14_s32x4, vdupq_n_s32( LTP_pred_Q14 ) ); + xq_Q14_s32x4 = vaddq_s32( LPC_exc_Q14_s32x4, LPC_pred_Q14_s32x4 ); + + /* Update states */ + tmp1_s32x4 = vsubq_s32( xq_Q14_s32x4, vshlq_n_s32( vdupq_n_s32( x_Q10[ i ] ), 4 ) ); + vst1q_s32( psSampleState[ 0 ].Diff_Q14, tmp1_s32x4 ); + sLF_AR_shp_Q14_s32x4 = vsubq_s32( tmp1_s32x4, n_AR_Q14_s32x4 ); + vst1q_s32( psSampleState[ 0 ].sLTP_shp_Q14, vsubq_s32( sLF_AR_shp_Q14_s32x4, n_LF_Q14_s32x4 ) ); + vst1q_s32( psSampleState[ 0 ].LF_AR_Q14, sLF_AR_shp_Q14_s32x4 ); + vst1q_s32( psSampleState[ 0 ].LPC_exc_Q14, LPC_exc_Q14_s32x4 ); + vst1q_s32( psSampleState[ 0 ].xq_Q14, xq_Q14_s32x4 ); + + /* Quantized excitation */ + exc_Q14_s32x4 = vshlq_n_s32( tmp2_s32x4, 4 ); + exc_Q14_s32x4 = veorq_s32( exc_Q14_s32x4, sign_s32x4 ); + exc_Q14_s32x4 = vsubq_s32( exc_Q14_s32x4, sign_s32x4 ); + + /* Add predictions */ + LPC_exc_Q14_s32x4 = vaddq_s32( exc_Q14_s32x4, vdupq_n_s32( LTP_pred_Q14 ) ); + xq_Q14_s32x4 = vaddq_s32( LPC_exc_Q14_s32x4, LPC_pred_Q14_s32x4 ); + + /* Update states */ + tmp1_s32x4 = vsubq_s32( xq_Q14_s32x4, vshlq_n_s32( vdupq_n_s32( x_Q10[ i ] ), 4 ) ); + vst1q_s32( psSampleState[ 1 ].Diff_Q14, tmp1_s32x4 ); + sLF_AR_shp_Q14_s32x4 = vsubq_s32( tmp1_s32x4, n_AR_Q14_s32x4 ); + vst1q_s32( psSampleState[ 1 ].sLTP_shp_Q14, vsubq_s32( sLF_AR_shp_Q14_s32x4, n_LF_Q14_s32x4 ) ); + vst1q_s32( psSampleState[ 1 ].LF_AR_Q14, sLF_AR_shp_Q14_s32x4 ); + vst1q_s32( psSampleState[ 1 ].LPC_exc_Q14, LPC_exc_Q14_s32x4 ); + vst1q_s32( psSampleState[ 1 ].xq_Q14, xq_Q14_s32x4 ); + } + + *smpl_buf_idx = *smpl_buf_idx ? ( *smpl_buf_idx - 1 ) : ( DECISION_DELAY - 1); + last_smple_idx = *smpl_buf_idx + decisionDelay + DECISION_DELAY; + if( last_smple_idx >= DECISION_DELAY ) last_smple_idx -= DECISION_DELAY; + if( last_smple_idx >= DECISION_DELAY ) last_smple_idx -= DECISION_DELAY; + + /* Find winner */ + RDmin_Q10 = psSampleState[ 0 ].RD_Q10[ 0 ]; + Winner_ind = 0; + for( k = 1; k < nStatesDelayedDecision; k++ ) { + if( psSampleState[ 0 ].RD_Q10[ k ] < RDmin_Q10 ) { + RDmin_Q10 = psSampleState[ 0 ].RD_Q10[ k ]; + Winner_ind = k; + } + } + + /* Increase RD values of expired states */ + { + uint32x4_t t_u32x4; + Winner_rand_state = psDelDec->RandState[ last_smple_idx ][ Winner_ind ]; + t_u32x4 = vceqq_s32( vld1q_s32( psDelDec->RandState[ last_smple_idx ] ), vdupq_n_s32( Winner_rand_state ) ); + t_u32x4 = vmvnq_u32( t_u32x4 ); + t_u32x4 = vshrq_n_u32( t_u32x4, 5 ); + tmp1_s32x4 = vld1q_s32( psSampleState[ 0 ].RD_Q10 ); + tmp2_s32x4 = vld1q_s32( psSampleState[ 1 ].RD_Q10 ); + tmp1_s32x4 = vaddq_s32( tmp1_s32x4, vreinterpretq_s32_u32( t_u32x4 ) ); + tmp2_s32x4 = vaddq_s32( tmp2_s32x4, vreinterpretq_s32_u32( t_u32x4 ) ); + vst1q_s32( psSampleState[ 0 ].RD_Q10, tmp1_s32x4 ); + vst1q_s32( psSampleState[ 1 ].RD_Q10, tmp2_s32x4 ); + + /* Find worst in first set and best in second set */ + RDmax_Q10 = psSampleState[ 0 ].RD_Q10[ 0 ]; + RDmin_Q10 = psSampleState[ 1 ].RD_Q10[ 0 ]; + RDmax_ind = 0; + RDmin_ind = 0; + for( k = 1; k < nStatesDelayedDecision; k++ ) { + /* find worst in first set */ + if( psSampleState[ 0 ].RD_Q10[ k ] > RDmax_Q10 ) { + RDmax_Q10 = psSampleState[ 0 ].RD_Q10[ k ]; + RDmax_ind = k; + } + /* find best in second set */ + if( psSampleState[ 1 ].RD_Q10[ k ] < RDmin_Q10 ) { + RDmin_Q10 = psSampleState[ 1 ].RD_Q10[ k ]; + RDmin_ind = k; + } + } + } + + /* Replace a state if best from second set outperforms worst in first set */ + if( RDmin_Q10 < RDmax_Q10 ) { + opus_int32 (*ptr)[NEON_MAX_DEL_DEC_STATES] = psDelDec->RandState; + const int numOthers = (int)( ( sizeof( NSQ_del_decs_struct ) - sizeof( ( (NSQ_del_decs_struct *)0 )->sLPC_Q14 ) ) + / ( NEON_MAX_DEL_DEC_STATES * sizeof( opus_int32 ) ) ); + /* Only ( predictLPCOrder - 1 ) of sLPC_Q14 buffer need to be updated, though the first several */ + /* useless sLPC_Q14[] will be different comparing with C when predictLPCOrder < NSQ_LPC_BUF_LENGTH. */ + /* Here just update constant ( NSQ_LPC_BUF_LENGTH - 1 ) for simplicity. */ + for( j = i + 1; j < i + NSQ_LPC_BUF_LENGTH; j++ ) { + psDelDec->sLPC_Q14[ j ][ RDmax_ind ] = psDelDec->sLPC_Q14[ j ][ RDmin_ind ]; + } + for( j = 0; j < numOthers; j++ ) { + ptr[ j ][ RDmax_ind ] = ptr[ j ][ RDmin_ind ]; + } + + psSampleState[ 0 ].Q_Q10[ RDmax_ind ] = psSampleState[ 1 ].Q_Q10[ RDmin_ind ]; + psSampleState[ 0 ].RD_Q10[ RDmax_ind ] = psSampleState[ 1 ].RD_Q10[ RDmin_ind ]; + psSampleState[ 0 ].xq_Q14[ RDmax_ind ] = psSampleState[ 1 ].xq_Q14[ RDmin_ind ]; + psSampleState[ 0 ].LF_AR_Q14[ RDmax_ind ] = psSampleState[ 1 ].LF_AR_Q14[ RDmin_ind ]; + psSampleState[ 0 ].Diff_Q14[ RDmax_ind ] = psSampleState[ 1 ].Diff_Q14[ RDmin_ind ]; + psSampleState[ 0 ].sLTP_shp_Q14[ RDmax_ind ] = psSampleState[ 1 ].sLTP_shp_Q14[ RDmin_ind ]; + psSampleState[ 0 ].LPC_exc_Q14[ RDmax_ind ] = psSampleState[ 1 ].LPC_exc_Q14[ RDmin_ind ]; + } + + /* Write samples from winner to output and long-term filter states */ + if( subfr > 0 || i >= decisionDelay ) { + pulses[ i - decisionDelay ] = (opus_int8)silk_RSHIFT_ROUND( psDelDec->Q_Q10[ last_smple_idx ][ Winner_ind ], 10 ); + xq[ i - decisionDelay ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( + silk_SMULWW( psDelDec->Xq_Q14[ last_smple_idx ][ Winner_ind ], delayedGain_Q10[ last_smple_idx ] ), 8 ) ); + NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - decisionDelay ] = psDelDec->Shape_Q14[ last_smple_idx ][ Winner_ind ]; + sLTP_Q15[ NSQ->sLTP_buf_idx - decisionDelay ] = psDelDec->Pred_Q15[ last_smple_idx ][ Winner_ind ]; + } + NSQ->sLTP_shp_buf_idx++; + NSQ->sLTP_buf_idx++; + + /* Update states */ + vst1q_s32( psDelDec->LF_AR_Q14, vld1q_s32( psSampleState[ 0 ].LF_AR_Q14 ) ); + vst1q_s32( psDelDec->Diff_Q14, vld1q_s32( psSampleState[ 0 ].Diff_Q14 ) ); + vst1q_s32( psDelDec->sLPC_Q14[ NSQ_LPC_BUF_LENGTH + i ], vld1q_s32( psSampleState[ 0 ].xq_Q14 ) ); + vst1q_s32( psDelDec->Xq_Q14[ *smpl_buf_idx ], vld1q_s32( psSampleState[ 0 ].xq_Q14 ) ); + tmp1_s32x4 = vld1q_s32( psSampleState[ 0 ].Q_Q10 ); + vst1q_s32( psDelDec->Q_Q10[ *smpl_buf_idx ], tmp1_s32x4 ); + vst1q_s32( psDelDec->Pred_Q15[ *smpl_buf_idx ], vshlq_n_s32( vld1q_s32( psSampleState[ 0 ].LPC_exc_Q14 ), 1 ) ); + vst1q_s32( psDelDec->Shape_Q14[ *smpl_buf_idx ], vld1q_s32( psSampleState[ 0 ].sLTP_shp_Q14 ) ); + tmp1_s32x4 = vrshrq_n_s32( tmp1_s32x4, 10 ); + tmp1_s32x4 = vaddq_s32( vld1q_s32( psDelDec->Seed ), tmp1_s32x4 ); + vst1q_s32( psDelDec->Seed, tmp1_s32x4 ); + vst1q_s32( psDelDec->RandState[ *smpl_buf_idx ], tmp1_s32x4 ); + vst1q_s32( psDelDec->RD_Q10, vld1q_s32( psSampleState[ 0 ].RD_Q10 ) ); + delayedGain_Q10[ *smpl_buf_idx ] = Gain_Q10; + } + /* Update LPC states */ + silk_memcpy( psDelDec->sLPC_Q14[ 0 ], psDelDec->sLPC_Q14[ length ], NEON_MAX_DEL_DEC_STATES * NSQ_LPC_BUF_LENGTH * sizeof( opus_int32 ) ); + + RESTORE_STACK; +} + +static OPUS_INLINE void silk_SMULWB_8_neon( + const opus_int16 *a, + const int32x2_t b, + opus_int32 *o +) +{ + const int16x8_t a_s16x8 = vld1q_s16( a ); + int32x4_t o0_s32x4, o1_s32x4; + + o0_s32x4 = vshll_n_s16( vget_low_s16( a_s16x8 ), 15 ); + o1_s32x4 = vshll_n_s16( vget_high_s16( a_s16x8 ), 15 ); + o0_s32x4 = vqdmulhq_lane_s32( o0_s32x4, b, 0 ); + o1_s32x4 = vqdmulhq_lane_s32( o1_s32x4, b, 0 ); + vst1q_s32( o, o0_s32x4 ); + vst1q_s32( o + 4, o1_s32x4 ); +} + +/* Only works when ( b >= -65536 ) && ( b < 65536 ). */ +static OPUS_INLINE void silk_SMULWW_small_b_4_neon( + opus_int32 *a, + const int32x2_t b_s32x2) +{ + int32x4_t o_s32x4; + + o_s32x4 = vld1q_s32( a ); + o_s32x4 = vqdmulhq_lane_s32( o_s32x4, b_s32x2, 0 ); + vst1q_s32( a, o_s32x4 ); +} + +/* Only works when ( b >= -65536 ) && ( b < 65536 ). */ +static OPUS_INLINE void silk_SMULWW_small_b_8_neon( + opus_int32 *a, + const int32x2_t b_s32x2 +) +{ + int32x4_t o0_s32x4, o1_s32x4; + + o0_s32x4 = vld1q_s32( a ); + o1_s32x4 = vld1q_s32( a + 4 ); + o0_s32x4 = vqdmulhq_lane_s32( o0_s32x4, b_s32x2, 0 ); + o1_s32x4 = vqdmulhq_lane_s32( o1_s32x4, b_s32x2, 0 ); + vst1q_s32( a, o0_s32x4 ); + vst1q_s32( a + 4, o1_s32x4 ); +} + +static OPUS_INLINE void silk_SMULWW_4_neon( + opus_int32 *a, + const int32x2_t b_s32x2) +{ + int32x4_t a_s32x4, o_s32x4; + + a_s32x4 = vld1q_s32( a ); + o_s32x4 = vqdmulhq_lane_s32( a_s32x4, b_s32x2, 0 ); + o_s32x4 = vmlaq_lane_s32( o_s32x4, a_s32x4, b_s32x2, 1 ); + vst1q_s32( a, o_s32x4 ); +} + +static OPUS_INLINE void silk_SMULWW_8_neon( + opus_int32 *a, + const int32x2_t b_s32x2 +) +{ + int32x4_t a0_s32x4, a1_s32x4, o0_s32x4, o1_s32x4; + + a0_s32x4 = vld1q_s32( a ); + a1_s32x4 = vld1q_s32( a + 4 ); + o0_s32x4 = vqdmulhq_lane_s32( a0_s32x4, b_s32x2, 0 ); + o1_s32x4 = vqdmulhq_lane_s32( a1_s32x4, b_s32x2, 0 ); + o0_s32x4 = vmlaq_lane_s32( o0_s32x4, a0_s32x4, b_s32x2, 1 ); + o1_s32x4 = vmlaq_lane_s32( o1_s32x4, a1_s32x4, b_s32x2, 1 ); + vst1q_s32( a, o0_s32x4 ); + vst1q_s32( a + 4, o1_s32x4 ); +} + +static OPUS_INLINE void silk_SMULWW_loop_neon( + const opus_int16 *a, + const opus_int32 b, + opus_int32 *o, + const opus_int loop_num +) +{ + opus_int i; + int32x2_t b_s32x2; + + b_s32x2 = vdup_n_s32( b ); + for( i = 0; i < loop_num - 7; i += 8 ) { + silk_SMULWB_8_neon( a + i, b_s32x2, o + i ); + } + for( ; i < loop_num; i++ ) { + o[ i ] = silk_SMULWW( a[ i ], b ); + } +} + +static OPUS_INLINE void silk_nsq_del_dec_scale_states_neon( + const silk_encoder_state *psEncC, /* I Encoder State */ + silk_nsq_state *NSQ, /* I/O NSQ state */ + NSQ_del_decs_struct psDelDec[], /* I/O Delayed decision states */ + const opus_int16 x16[], /* I Input */ + opus_int32 x_sc_Q10[], /* O Input scaled with 1/Gain in Q10 */ + const opus_int16 sLTP[], /* I Re-whitened LTP state in Q0 */ + opus_int32 sLTP_Q15[], /* O LTP state matching scaled input */ + opus_int subfr, /* I Subframe number */ + const opus_int LTP_scale_Q14, /* I LTP state scaling */ + const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lag */ + const opus_int signal_type, /* I Signal type */ + const opus_int decisionDelay /* I Decision delay */ +) +{ + opus_int i, lag; + opus_int32 gain_adj_Q16, inv_gain_Q31, inv_gain_Q26; + + lag = pitchL[ subfr ]; + inv_gain_Q31 = silk_INVERSE32_varQ( silk_max( Gains_Q16[ subfr ], 1 ), 47 ); + silk_assert( inv_gain_Q31 != 0 ); + + /* Scale input */ + inv_gain_Q26 = silk_RSHIFT_ROUND( inv_gain_Q31, 5 ); + silk_SMULWW_loop_neon( x16, inv_gain_Q26, x_sc_Q10, psEncC->subfr_length ); + + /* After rewhitening the LTP state is un-scaled, so scale with inv_gain_Q16 */ + if( NSQ->rewhite_flag ) { + if( subfr == 0 ) { + /* Do LTP downscaling */ + inv_gain_Q31 = silk_LSHIFT( silk_SMULWB( inv_gain_Q31, LTP_scale_Q14 ), 2 ); + } + silk_SMULWW_loop_neon( sLTP + NSQ->sLTP_buf_idx - lag - LTP_ORDER / 2, inv_gain_Q31, sLTP_Q15 + NSQ->sLTP_buf_idx - lag - LTP_ORDER / 2, lag + LTP_ORDER / 2 ); + } + + /* Adjust for changing gain */ + if( Gains_Q16[ subfr ] != NSQ->prev_gain_Q16 ) { + int32x2_t gain_adj_Q16_s32x2; + gain_adj_Q16 = silk_DIV32_varQ( NSQ->prev_gain_Q16, Gains_Q16[ subfr ], 16 ); + + /* Scale long-term shaping state */ + if( ( gain_adj_Q16 >= -65536 ) && ( gain_adj_Q16 < 65536 ) ) { + gain_adj_Q16_s32x2 = vdup_n_s32( silk_LSHIFT32( gain_adj_Q16, 15 ) ); + for( i = NSQ->sLTP_shp_buf_idx - psEncC->ltp_mem_length; i < NSQ->sLTP_shp_buf_idx - 7; i += 8 ) { + silk_SMULWW_small_b_8_neon( NSQ->sLTP_shp_Q14 + i, gain_adj_Q16_s32x2 ); + } + for( ; i < NSQ->sLTP_shp_buf_idx; i++ ) { + NSQ->sLTP_shp_Q14[ i ] = silk_SMULWW( gain_adj_Q16, NSQ->sLTP_shp_Q14[ i ] ); + } + + /* Scale long-term prediction state */ + if( signal_type == TYPE_VOICED && NSQ->rewhite_flag == 0 ) { + for( i = NSQ->sLTP_buf_idx - lag - LTP_ORDER / 2; i < NSQ->sLTP_buf_idx - decisionDelay - 7; i += 8 ) { + silk_SMULWW_small_b_8_neon( sLTP_Q15 + i, gain_adj_Q16_s32x2 ); + } + for( ; i < NSQ->sLTP_buf_idx - decisionDelay; i++ ) { + sLTP_Q15[ i ] = silk_SMULWW( gain_adj_Q16, sLTP_Q15[ i ] ); + } + } + + /* Scale scalar states */ + silk_SMULWW_small_b_4_neon( psDelDec->LF_AR_Q14, gain_adj_Q16_s32x2 ); + silk_SMULWW_small_b_4_neon( psDelDec->Diff_Q14, gain_adj_Q16_s32x2 ); + + /* Scale short-term prediction and shaping states */ + for( i = 0; i < NSQ_LPC_BUF_LENGTH; i++ ) { + silk_SMULWW_small_b_4_neon( psDelDec->sLPC_Q14[ i ], gain_adj_Q16_s32x2 ); + } + + for( i = 0; i < MAX_SHAPE_LPC_ORDER; i++ ) { + silk_SMULWW_small_b_4_neon( psDelDec->sAR2_Q14[ i ], gain_adj_Q16_s32x2 ); + } + + for( i = 0; i < DECISION_DELAY; i++ ) { + silk_SMULWW_small_b_4_neon( psDelDec->Pred_Q15[ i ], gain_adj_Q16_s32x2 ); + silk_SMULWW_small_b_4_neon( psDelDec->Shape_Q14[ i ], gain_adj_Q16_s32x2 ); + } + } else { + gain_adj_Q16_s32x2 = vdup_n_s32( silk_LSHIFT32( gain_adj_Q16 & 0x0000FFFF, 15 ) ); + gain_adj_Q16_s32x2 = vset_lane_s32( gain_adj_Q16 >> 16, gain_adj_Q16_s32x2, 1 ); + for( i = NSQ->sLTP_shp_buf_idx - psEncC->ltp_mem_length; i < NSQ->sLTP_shp_buf_idx - 7; i += 8 ) { + silk_SMULWW_8_neon( NSQ->sLTP_shp_Q14 + i, gain_adj_Q16_s32x2 ); + } + for( ; i < NSQ->sLTP_shp_buf_idx; i++ ) { + NSQ->sLTP_shp_Q14[ i ] = silk_SMULWW( gain_adj_Q16, NSQ->sLTP_shp_Q14[ i ] ); + } + + /* Scale long-term prediction state */ + if( signal_type == TYPE_VOICED && NSQ->rewhite_flag == 0 ) { + for( i = NSQ->sLTP_buf_idx - lag - LTP_ORDER / 2; i < NSQ->sLTP_buf_idx - decisionDelay - 7; i += 8 ) { + silk_SMULWW_8_neon( sLTP_Q15 + i, gain_adj_Q16_s32x2 ); + } + for( ; i < NSQ->sLTP_buf_idx - decisionDelay; i++ ) { + sLTP_Q15[ i ] = silk_SMULWW( gain_adj_Q16, sLTP_Q15[ i ] ); + } + } + + /* Scale scalar states */ + silk_SMULWW_4_neon( psDelDec->LF_AR_Q14, gain_adj_Q16_s32x2 ); + silk_SMULWW_4_neon( psDelDec->Diff_Q14, gain_adj_Q16_s32x2 ); + + /* Scale short-term prediction and shaping states */ + for( i = 0; i < NSQ_LPC_BUF_LENGTH; i++ ) { + silk_SMULWW_4_neon( psDelDec->sLPC_Q14[ i ], gain_adj_Q16_s32x2 ); + } + + for( i = 0; i < MAX_SHAPE_LPC_ORDER; i++ ) { + silk_SMULWW_4_neon( psDelDec->sAR2_Q14[ i ], gain_adj_Q16_s32x2 ); + } + + for( i = 0; i < DECISION_DELAY; i++ ) { + silk_SMULWW_4_neon( psDelDec->Pred_Q15[ i ], gain_adj_Q16_s32x2 ); + silk_SMULWW_4_neon( psDelDec->Shape_Q14[ i ], gain_adj_Q16_s32x2 ); + } + } + + /* Save inverse gain */ + NSQ->prev_gain_Q16 = Gains_Q16[ subfr ]; + } +} diff --git a/extern/opus/silk/arm/NSQ_neon.c b/extern/opus/silk/arm/NSQ_neon.c new file mode 100644 index 0000000..9642529 --- /dev/null +++ b/extern/opus/silk/arm/NSQ_neon.c @@ -0,0 +1,112 @@ +/*********************************************************************** +Copyright (C) 2014 Vidyo +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 OWNER 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. +***********************************************************************/ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "main.h" +#include "stack_alloc.h" +#include "NSQ.h" +#include "celt/cpu_support.h" +#include "celt/arm/armcpu.h" + +opus_int32 silk_noise_shape_quantizer_short_prediction_neon(const opus_int32 *buf32, const opus_int32 *coef32, opus_int order) +{ + int32x4_t coef0 = vld1q_s32(coef32); + int32x4_t coef1 = vld1q_s32(coef32 + 4); + int32x4_t coef2 = vld1q_s32(coef32 + 8); + int32x4_t coef3 = vld1q_s32(coef32 + 12); + + int32x4_t a0 = vld1q_s32(buf32 - 15); + int32x4_t a1 = vld1q_s32(buf32 - 11); + int32x4_t a2 = vld1q_s32(buf32 - 7); + int32x4_t a3 = vld1q_s32(buf32 - 3); + + int32x4_t b0 = vqdmulhq_s32(coef0, a0); + int32x4_t b1 = vqdmulhq_s32(coef1, a1); + int32x4_t b2 = vqdmulhq_s32(coef2, a2); + int32x4_t b3 = vqdmulhq_s32(coef3, a3); + + int32x4_t c0 = vaddq_s32(b0, b1); + int32x4_t c1 = vaddq_s32(b2, b3); + + int32x4_t d = vaddq_s32(c0, c1); + + int64x2_t e = vpaddlq_s32(d); + + int64x1_t f = vadd_s64(vget_low_s64(e), vget_high_s64(e)); + + opus_int32 out = vget_lane_s32(vreinterpret_s32_s64(f), 0); + + out += silk_RSHIFT( order, 1 ); + + return out; +} + + +opus_int32 silk_NSQ_noise_shape_feedback_loop_neon(const opus_int32 *data0, opus_int32 *data1, const opus_int16 *coef, opus_int order) +{ + opus_int32 out; + if (order == 8) + { + int32x4_t a00 = vdupq_n_s32(data0[0]); + int32x4_t a01 = vld1q_s32(data1); /* data1[0] ... [3] */ + + int32x4_t a0 = vextq_s32 (a00, a01, 3); /* data0[0] data1[0] ...[2] */ + int32x4_t a1 = vld1q_s32(data1 + 3); /* data1[3] ... [6] */ + + /*TODO: Convert these once in advance instead of once per sample, like + silk_noise_shape_quantizer_short_prediction_neon() does.*/ + int16x8_t coef16 = vld1q_s16(coef); + int32x4_t coef0 = vmovl_s16(vget_low_s16(coef16)); + int32x4_t coef1 = vmovl_s16(vget_high_s16(coef16)); + + /*This is not bit-exact with the C version, since we do not drop the + lower 16 bits of each multiply, but wait until the end to truncate + precision. This is an encoder-specific calculation (and unlike + silk_noise_shape_quantizer_short_prediction_neon(), is not meant to + simulate what the decoder will do). We still could use vqdmulhq_s32() + like silk_noise_shape_quantizer_short_prediction_neon() and save + half the multiplies, but the speed difference is not large, since we + then need two extra adds.*/ + int64x2_t b0 = vmull_s32(vget_low_s32(a0), vget_low_s32(coef0)); + int64x2_t b1 = vmlal_s32(b0, vget_high_s32(a0), vget_high_s32(coef0)); + int64x2_t b2 = vmlal_s32(b1, vget_low_s32(a1), vget_low_s32(coef1)); + int64x2_t b3 = vmlal_s32(b2, vget_high_s32(a1), vget_high_s32(coef1)); + + int64x1_t c = vadd_s64(vget_low_s64(b3), vget_high_s64(b3)); + int64x1_t cS = vrshr_n_s64(c, 15); + int32x2_t d = vreinterpret_s32_s64(cS); + + out = vget_lane_s32(d, 0); + vst1q_s32(data1, a0); + vst1q_s32(data1 + 4, a1); + return out; + } + return silk_NSQ_noise_shape_feedback_loop_c(data0, data1, coef, order); +} diff --git a/extern/opus/silk/arm/NSQ_neon.h b/extern/opus/silk/arm/NSQ_neon.h new file mode 100644 index 0000000..b31d944 --- /dev/null +++ b/extern/opus/silk/arm/NSQ_neon.h @@ -0,0 +1,114 @@ +/*********************************************************************** +Copyright (C) 2014 Vidyo +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 OWNER 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. +***********************************************************************/ +#ifndef SILK_NSQ_NEON_H +#define SILK_NSQ_NEON_H + +#include "cpu_support.h" +#include "SigProc_FIX.h" + +#undef silk_short_prediction_create_arch_coef +/* For vectorized calc, reverse a_Q12 coefs, convert to 32-bit, and shift for vqdmulhq_s32. */ +static OPUS_INLINE void silk_short_prediction_create_arch_coef_neon(opus_int32 *out, const opus_int16 *in, opus_int order) +{ + out[15] = silk_LSHIFT32(in[0], 15); + out[14] = silk_LSHIFT32(in[1], 15); + out[13] = silk_LSHIFT32(in[2], 15); + out[12] = silk_LSHIFT32(in[3], 15); + out[11] = silk_LSHIFT32(in[4], 15); + out[10] = silk_LSHIFT32(in[5], 15); + out[9] = silk_LSHIFT32(in[6], 15); + out[8] = silk_LSHIFT32(in[7], 15); + out[7] = silk_LSHIFT32(in[8], 15); + out[6] = silk_LSHIFT32(in[9], 15); + + if (order == 16) + { + out[5] = silk_LSHIFT32(in[10], 15); + out[4] = silk_LSHIFT32(in[11], 15); + out[3] = silk_LSHIFT32(in[12], 15); + out[2] = silk_LSHIFT32(in[13], 15); + out[1] = silk_LSHIFT32(in[14], 15); + out[0] = silk_LSHIFT32(in[15], 15); + } + else + { + out[5] = 0; + out[4] = 0; + out[3] = 0; + out[2] = 0; + out[1] = 0; + out[0] = 0; + } +} + +#if defined(OPUS_ARM_PRESUME_NEON_INTR) + +#define silk_short_prediction_create_arch_coef(out, in, order) \ + (silk_short_prediction_create_arch_coef_neon(out, in, order)) + +#elif defined(OPUS_HAVE_RTCD) && defined(OPUS_ARM_MAY_HAVE_NEON_INTR) + +#define silk_short_prediction_create_arch_coef(out, in, order) \ + do { if (arch == OPUS_ARCH_ARM_NEON) { silk_short_prediction_create_arch_coef_neon(out, in, order); } } while (0) + +#endif + +opus_int32 silk_noise_shape_quantizer_short_prediction_neon(const opus_int32 *buf32, const opus_int32 *coef32, opus_int order); + +opus_int32 silk_NSQ_noise_shape_feedback_loop_neon(const opus_int32 *data0, opus_int32 *data1, const opus_int16 *coef, opus_int order); + +#if defined(OPUS_ARM_PRESUME_NEON_INTR) +#undef silk_noise_shape_quantizer_short_prediction +#define silk_noise_shape_quantizer_short_prediction(in, coef, coefRev, order, arch) \ + ((void)arch,silk_noise_shape_quantizer_short_prediction_neon(in, coefRev, order)) + +#undef silk_NSQ_noise_shape_feedback_loop +#define silk_NSQ_noise_shape_feedback_loop(data0, data1, coef, order, arch) ((void)arch,silk_NSQ_noise_shape_feedback_loop_neon(data0, data1, coef, order)) + +#elif defined(OPUS_HAVE_RTCD) && defined(OPUS_ARM_MAY_HAVE_NEON_INTR) + +/* silk_noise_shape_quantizer_short_prediction implementations take different parameters based on arch + (coef vs. coefRev) so can't use the usual IMPL table implementation */ +#undef silk_noise_shape_quantizer_short_prediction +#define silk_noise_shape_quantizer_short_prediction(in, coef, coefRev, order, arch) \ + (arch == OPUS_ARCH_ARM_NEON ? \ + silk_noise_shape_quantizer_short_prediction_neon(in, coefRev, order) : \ + silk_noise_shape_quantizer_short_prediction_c(in, coef, order)) + +extern opus_int32 + (*const SILK_NSQ_NOISE_SHAPE_FEEDBACK_LOOP_IMPL[OPUS_ARCHMASK+1])( + const opus_int32 *data0, opus_int32 *data1, const opus_int16 *coef, + opus_int order); + +#undef silk_NSQ_noise_shape_feedback_loop +#define silk_NSQ_noise_shape_feedback_loop(data0, data1, coef, order, arch) \ + (SILK_NSQ_NOISE_SHAPE_FEEDBACK_LOOP_IMPL[(arch)&OPUS_ARCHMASK](data0, data1, \ + coef, order)) + +#endif + +#endif /* SILK_NSQ_NEON_H */ diff --git a/extern/opus/silk/arm/SigProc_FIX_armv4.h b/extern/opus/silk/arm/SigProc_FIX_armv4.h new file mode 100644 index 0000000..ff62b1e --- /dev/null +++ b/extern/opus/silk/arm/SigProc_FIX_armv4.h @@ -0,0 +1,47 @@ +/*********************************************************************** +Copyright (C) 2013 Xiph.Org Foundation and contributors +Copyright (c) 2013 Parrot +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 OWNER 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. +***********************************************************************/ + +#ifndef SILK_SIGPROC_FIX_ARMv4_H +#define SILK_SIGPROC_FIX_ARMv4_H + +#undef silk_MLA +static OPUS_INLINE opus_int32 silk_MLA_armv4(opus_int32 a, opus_int32 b, + opus_int32 c) +{ + opus_int32 res; + __asm__( + "#silk_MLA\n\t" + "mla %0, %1, %2, %3\n\t" + : "=&r"(res) + : "r"(b), "r"(c), "r"(a) + ); + return res; +} +#define silk_MLA(a, b, c) (silk_MLA_armv4(a, b, c)) + +#endif diff --git a/extern/opus/silk/arm/SigProc_FIX_armv5e.h b/extern/opus/silk/arm/SigProc_FIX_armv5e.h new file mode 100644 index 0000000..617a09c --- /dev/null +++ b/extern/opus/silk/arm/SigProc_FIX_armv5e.h @@ -0,0 +1,61 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Copyright (c) 2013 Parrot +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 OWNER 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. +***********************************************************************/ + +#ifndef SILK_SIGPROC_FIX_ARMv5E_H +#define SILK_SIGPROC_FIX_ARMv5E_H + +#undef silk_SMULTT +static OPUS_INLINE opus_int32 silk_SMULTT_armv5e(opus_int32 a, opus_int32 b) +{ + opus_int32 res; + __asm__( + "#silk_SMULTT\n\t" + "smultt %0, %1, %2\n\t" + : "=r"(res) + : "%r"(a), "r"(b) + ); + return res; +} +#define silk_SMULTT(a, b) (silk_SMULTT_armv5e(a, b)) + +#undef silk_SMLATT +static OPUS_INLINE opus_int32 silk_SMLATT_armv5e(opus_int32 a, opus_int32 b, + opus_int32 c) +{ + opus_int32 res; + __asm__( + "#silk_SMLATT\n\t" + "smlatt %0, %1, %2, %3\n\t" + : "=r"(res) + : "%r"(b), "r"(c), "r"(a) + ); + return res; +} +#define silk_SMLATT(a, b, c) (silk_SMLATT_armv5e(a, b, c)) + +#endif diff --git a/extern/opus/silk/arm/arm_silk_map.c b/extern/opus/silk/arm/arm_silk_map.c new file mode 100644 index 0000000..0b9bfec --- /dev/null +++ b/extern/opus/silk/arm/arm_silk_map.c @@ -0,0 +1,123 @@ +/*********************************************************************** +Copyright (C) 2014 Vidyo +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 OWNER 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. +***********************************************************************/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "main_FIX.h" +#include "NSQ.h" +#include "SigProc_FIX.h" + +#if defined(OPUS_HAVE_RTCD) + +# if (defined(OPUS_ARM_MAY_HAVE_NEON_INTR) && \ + !defined(OPUS_ARM_PRESUME_NEON_INTR)) + +void (*const SILK_BIQUAD_ALT_STRIDE2_IMPL[OPUS_ARCHMASK + 1])( + const opus_int16 *in, /* I input signal */ + const opus_int32 *B_Q28, /* I MA coefficients [3] */ + const opus_int32 *A_Q28, /* I AR coefficients [2] */ + opus_int32 *S, /* I/O State vector [4] */ + opus_int16 *out, /* O output signal */ + const opus_int32 len /* I signal length (must be even) */ +) = { + silk_biquad_alt_stride2_c, /* ARMv4 */ + silk_biquad_alt_stride2_c, /* EDSP */ + silk_biquad_alt_stride2_c, /* Media */ + silk_biquad_alt_stride2_neon, /* Neon */ +}; + +opus_int32 (*const SILK_LPC_INVERSE_PRED_GAIN_IMPL[OPUS_ARCHMASK + 1])( /* O Returns inverse prediction gain in energy domain, Q30 */ + const opus_int16 *A_Q12, /* I Prediction coefficients, Q12 [order] */ + const opus_int order /* I Prediction order */ +) = { + silk_LPC_inverse_pred_gain_c, /* ARMv4 */ + silk_LPC_inverse_pred_gain_c, /* EDSP */ + silk_LPC_inverse_pred_gain_c, /* Media */ + silk_LPC_inverse_pred_gain_neon, /* Neon */ +}; + +void (*const SILK_NSQ_DEL_DEC_IMPL[OPUS_ARCHMASK + 1])( + const silk_encoder_state *psEncC, /* I Encoder State */ + silk_nsq_state *NSQ, /* I/O NSQ state */ + SideInfoIndices *psIndices, /* I/O Quantization Indices */ + const opus_int16 x16[], /* I Input */ + opus_int8 pulses[], /* O Quantized pulse signal */ + const opus_int16 PredCoef_Q12[ 2 * MAX_LPC_ORDER ], /* I Short term prediction coefs */ + const opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ], /* I Long term prediction coefs */ + const opus_int16 AR_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ], /* I Noise shaping coefs */ + const opus_int HarmShapeGain_Q14[ MAX_NB_SUBFR ], /* I Long term shaping coefs */ + const opus_int Tilt_Q14[ MAX_NB_SUBFR ], /* I Spectral tilt */ + const opus_int32 LF_shp_Q14[ MAX_NB_SUBFR ], /* I Low frequency shaping coefs */ + const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I Quantization step sizes */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lags */ + const opus_int Lambda_Q10, /* I Rate/distortion tradeoff */ + const opus_int LTP_scale_Q14 /* I LTP state scaling */ +) = { + silk_NSQ_del_dec_c, /* ARMv4 */ + silk_NSQ_del_dec_c, /* EDSP */ + silk_NSQ_del_dec_c, /* Media */ + silk_NSQ_del_dec_neon, /* Neon */ +}; + +/*There is no table for silk_noise_shape_quantizer_short_prediction because the + NEON version takes different parameters than the C version. + Instead RTCD is done via if statements at the call sites. + See NSQ_neon.h for details.*/ + +opus_int32 + (*const SILK_NSQ_NOISE_SHAPE_FEEDBACK_LOOP_IMPL[OPUS_ARCHMASK+1])( + const opus_int32 *data0, opus_int32 *data1, const opus_int16 *coef, + opus_int order) = { + silk_NSQ_noise_shape_feedback_loop_c, /* ARMv4 */ + silk_NSQ_noise_shape_feedback_loop_c, /* EDSP */ + silk_NSQ_noise_shape_feedback_loop_c, /* Media */ + silk_NSQ_noise_shape_feedback_loop_neon, /* NEON */ +}; + +# endif + +# if defined(FIXED_POINT) && \ + defined(OPUS_ARM_MAY_HAVE_NEON_INTR) && !defined(OPUS_ARM_PRESUME_NEON_INTR) + +void (*const SILK_WARPED_AUTOCORRELATION_FIX_IMPL[OPUS_ARCHMASK + 1])( + opus_int32 *corr, /* O Result [order + 1] */ + opus_int *scale, /* O Scaling of the correlation vector */ + const opus_int16 *input, /* I Input data to correlate */ + const opus_int warping_Q16, /* I Warping coefficient */ + const opus_int length, /* I Length of input */ + const opus_int order /* I Correlation order (even) */ +) = { + silk_warped_autocorrelation_FIX_c, /* ARMv4 */ + silk_warped_autocorrelation_FIX_c, /* EDSP */ + silk_warped_autocorrelation_FIX_c, /* Media */ + silk_warped_autocorrelation_FIX_neon, /* Neon */ +}; + +# endif + +#endif /* OPUS_HAVE_RTCD */ diff --git a/extern/opus/silk/arm/biquad_alt_arm.h b/extern/opus/silk/arm/biquad_alt_arm.h new file mode 100644 index 0000000..66ea9f4 --- /dev/null +++ b/extern/opus/silk/arm/biquad_alt_arm.h @@ -0,0 +1,68 @@ +/*********************************************************************** +Copyright (c) 2017 Google Inc. +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 OWNER 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. +***********************************************************************/ + +#ifndef SILK_BIQUAD_ALT_ARM_H +# define SILK_BIQUAD_ALT_ARM_H + +# include "celt/arm/armcpu.h" + +# if defined(OPUS_ARM_MAY_HAVE_NEON_INTR) +void silk_biquad_alt_stride2_neon( + const opus_int16 *in, /* I input signal */ + const opus_int32 *B_Q28, /* I MA coefficients [3] */ + const opus_int32 *A_Q28, /* I AR coefficients [2] */ + opus_int32 *S, /* I/O State vector [4] */ + opus_int16 *out, /* O output signal */ + const opus_int32 len /* I signal length (must be even) */ +); + +# if !defined(OPUS_HAVE_RTCD) && defined(OPUS_ARM_PRESUME_NEON) +# define OVERRIDE_silk_biquad_alt_stride2 (1) +# define silk_biquad_alt_stride2(in, B_Q28, A_Q28, S, out, len, arch) ((void)(arch), PRESUME_NEON(silk_biquad_alt_stride2)(in, B_Q28, A_Q28, S, out, len)) +# endif +# endif + +# if !defined(OVERRIDE_silk_biquad_alt_stride2) +/*Is run-time CPU detection enabled on this platform?*/ +# if defined(OPUS_HAVE_RTCD) && (defined(OPUS_ARM_MAY_HAVE_NEON_INTR) && !defined(OPUS_ARM_PRESUME_NEON_INTR)) +extern void (*const SILK_BIQUAD_ALT_STRIDE2_IMPL[OPUS_ARCHMASK+1])( + const opus_int16 *in, /* I input signal */ + const opus_int32 *B_Q28, /* I MA coefficients [3] */ + const opus_int32 *A_Q28, /* I AR coefficients [2] */ + opus_int32 *S, /* I/O State vector [4] */ + opus_int16 *out, /* O output signal */ + const opus_int32 len /* I signal length (must be even) */ + ); +# define OVERRIDE_silk_biquad_alt_stride2 (1) +# define silk_biquad_alt_stride2(in, B_Q28, A_Q28, S, out, len, arch) ((*SILK_BIQUAD_ALT_STRIDE2_IMPL[(arch)&OPUS_ARCHMASK])(in, B_Q28, A_Q28, S, out, len)) +# elif defined(OPUS_ARM_PRESUME_NEON_INTR) +# define OVERRIDE_silk_biquad_alt_stride2 (1) +# define silk_biquad_alt_stride2(in, B_Q28, A_Q28, S, out, len, arch) ((void)(arch), silk_biquad_alt_stride2_neon(in, B_Q28, A_Q28, S, out, len)) +# endif +# endif + +#endif /* end SILK_BIQUAD_ALT_ARM_H */ diff --git a/extern/opus/silk/arm/biquad_alt_neon_intr.c b/extern/opus/silk/arm/biquad_alt_neon_intr.c new file mode 100644 index 0000000..9715733 --- /dev/null +++ b/extern/opus/silk/arm/biquad_alt_neon_intr.c @@ -0,0 +1,156 @@ +/*********************************************************************** +Copyright (c) 2017 Google Inc. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#ifdef OPUS_CHECK_ASM +# include +# include "stack_alloc.h" +#endif +#include "SigProc_FIX.h" + +static inline void silk_biquad_alt_stride2_kernel( const int32x4_t A_L_s32x4, const int32x4_t A_U_s32x4, const int32x4_t B_Q28_s32x4, const int32x2_t t_s32x2, const int32x4_t in_s32x4, int32x4_t *S_s32x4, int32x2_t *out32_Q14_s32x2 ) +{ + int32x4_t t_s32x4, out32_Q14_s32x4; + + *out32_Q14_s32x2 = vadd_s32( vget_low_s32( *S_s32x4 ), t_s32x2 ); /* silk_SMLAWB( S{0,1}, B_Q28[ 0 ], in{0,1} ) */ + *S_s32x4 = vcombine_s32( vget_high_s32( *S_s32x4 ), vdup_n_s32( 0 ) ); /* S{0,1} = S{2,3}; S{2,3} = 0; */ + *out32_Q14_s32x2 = vshl_n_s32( *out32_Q14_s32x2, 2 ); /* out32_Q14_{0,1} = silk_LSHIFT( silk_SMLAWB( S{0,1}, B_Q28[ 0 ], in{0,1} ), 2 ); */ + out32_Q14_s32x4 = vcombine_s32( *out32_Q14_s32x2, *out32_Q14_s32x2 ); /* out32_Q14_{0,1,0,1} */ + t_s32x4 = vqdmulhq_s32( out32_Q14_s32x4, A_L_s32x4 ); /* silk_SMULWB( out32_Q14_{0,1,0,1}, A{0,0,1,1}_L_Q28 ) */ + *S_s32x4 = vrsraq_n_s32( *S_s32x4, t_s32x4, 14 ); /* S{0,1} = S{2,3} + silk_RSHIFT_ROUND(); S{2,3} = silk_RSHIFT_ROUND(); */ + t_s32x4 = vqdmulhq_s32( out32_Q14_s32x4, A_U_s32x4 ); /* silk_SMULWB( out32_Q14_{0,1,0,1}, A{0,0,1,1}_U_Q28 ) */ + *S_s32x4 = vaddq_s32( *S_s32x4, t_s32x4 ); /* S0 = silk_SMLAWB( S{0,1,2,3}, out32_Q14_{0,1,0,1}, A{0,0,1,1}_U_Q28 ); */ + t_s32x4 = vqdmulhq_s32( in_s32x4, B_Q28_s32x4 ); /* silk_SMULWB( B_Q28[ {1,1,2,2} ], in{0,1,0,1} ) */ + *S_s32x4 = vaddq_s32( *S_s32x4, t_s32x4 ); /* S0 = silk_SMLAWB( S0, B_Q28[ {1,1,2,2} ], in{0,1,0,1} ); */ +} + +void silk_biquad_alt_stride2_neon( + const opus_int16 *in, /* I input signal */ + const opus_int32 *B_Q28, /* I MA coefficients [3] */ + const opus_int32 *A_Q28, /* I AR coefficients [2] */ + opus_int32 *S, /* I/O State vector [4] */ + opus_int16 *out, /* O output signal */ + const opus_int32 len /* I signal length (must be even) */ +) +{ + /* DIRECT FORM II TRANSPOSED (uses 2 element state vector) */ + opus_int k = 0; + const int32x2_t offset_s32x2 = vdup_n_s32( (1<<14) - 1 ); + const int32x4_t offset_s32x4 = vcombine_s32( offset_s32x2, offset_s32x2 ); + int16x4_t in_s16x4 = vdup_n_s16( 0 ); + int16x4_t out_s16x4; + int32x2_t A_Q28_s32x2, A_L_s32x2, A_U_s32x2, B_Q28_s32x2, t_s32x2; + int32x4_t A_L_s32x4, A_U_s32x4, B_Q28_s32x4, S_s32x4, out32_Q14_s32x4; + int32x2x2_t t0_s32x2x2, t1_s32x2x2, t2_s32x2x2, S_s32x2x2; + +#ifdef OPUS_CHECK_ASM + opus_int32 S_c[ 4 ]; + VARDECL( opus_int16, out_c ); + SAVE_STACK; + ALLOC( out_c, 2 * len, opus_int16 ); + + silk_memcpy( &S_c, S, sizeof( S_c ) ); + silk_biquad_alt_stride2_c( in, B_Q28, A_Q28, S_c, out_c, len ); +#endif + + /* Negate A_Q28 values and split in two parts */ + A_Q28_s32x2 = vld1_s32( A_Q28 ); + A_Q28_s32x2 = vneg_s32( A_Q28_s32x2 ); + A_L_s32x2 = vshl_n_s32( A_Q28_s32x2, 18 ); /* ( -A_Q28[] & 0x00003FFF ) << 18 */ + A_L_s32x2 = vreinterpret_s32_u32( vshr_n_u32( vreinterpret_u32_s32( A_L_s32x2 ), 3 ) ); /* ( -A_Q28[] & 0x00003FFF ) << 15 */ + A_U_s32x2 = vshr_n_s32( A_Q28_s32x2, 14 ); /* silk_RSHIFT( -A_Q28[], 14 ) */ + A_U_s32x2 = vshl_n_s32( A_U_s32x2, 16 ); /* silk_RSHIFT( -A_Q28[], 14 ) << 16 (Clip two leading bits to conform to C function.) */ + A_U_s32x2 = vshr_n_s32( A_U_s32x2, 1 ); /* silk_RSHIFT( -A_Q28[], 14 ) << 15 */ + + B_Q28_s32x2 = vld1_s32( B_Q28 ); + t_s32x2 = vld1_s32( B_Q28 + 1 ); + t0_s32x2x2 = vzip_s32( A_L_s32x2, A_L_s32x2 ); + t1_s32x2x2 = vzip_s32( A_U_s32x2, A_U_s32x2 ); + t2_s32x2x2 = vzip_s32( t_s32x2, t_s32x2 ); + A_L_s32x4 = vcombine_s32( t0_s32x2x2.val[ 0 ], t0_s32x2x2.val[ 1 ] ); /* A{0,0,1,1}_L_Q28 */ + A_U_s32x4 = vcombine_s32( t1_s32x2x2.val[ 0 ], t1_s32x2x2.val[ 1 ] ); /* A{0,0,1,1}_U_Q28 */ + B_Q28_s32x4 = vcombine_s32( t2_s32x2x2.val[ 0 ], t2_s32x2x2.val[ 1 ] ); /* B_Q28[ {1,1,2,2} ] */ + S_s32x4 = vld1q_s32( S ); /* S0 = S[ 0 ]; S3 = S[ 3 ]; */ + S_s32x2x2 = vtrn_s32( vget_low_s32( S_s32x4 ), vget_high_s32( S_s32x4 ) ); /* S2 = S[ 1 ]; S1 = S[ 2 ]; */ + S_s32x4 = vcombine_s32( S_s32x2x2.val[ 0 ], S_s32x2x2.val[ 1 ] ); + + for( ; k < len - 1; k += 2 ) { + int32x4_t in_s32x4[ 2 ], t_s32x4; + int32x2_t out32_Q14_s32x2[ 2 ]; + + /* S[ 2 * i + 0 ], S[ 2 * i + 1 ], S[ 2 * i + 2 ], S[ 2 * i + 3 ]: Q12 */ + in_s16x4 = vld1_s16( &in[ 2 * k ] ); /* in{0,1,2,3} = in[ 2 * k + {0,1,2,3} ]; */ + in_s32x4[ 0 ] = vshll_n_s16( in_s16x4, 15 ); /* in{0,1,2,3} << 15 */ + t_s32x4 = vqdmulhq_lane_s32( in_s32x4[ 0 ], B_Q28_s32x2, 0 ); /* silk_SMULWB( B_Q28[ 0 ], in{0,1,2,3} ) */ + in_s32x4[ 1 ] = vcombine_s32( vget_high_s32( in_s32x4[ 0 ] ), vget_high_s32( in_s32x4[ 0 ] ) ); /* in{2,3,2,3} << 15 */ + in_s32x4[ 0 ] = vcombine_s32( vget_low_s32 ( in_s32x4[ 0 ] ), vget_low_s32 ( in_s32x4[ 0 ] ) ); /* in{0,1,0,1} << 15 */ + silk_biquad_alt_stride2_kernel( A_L_s32x4, A_U_s32x4, B_Q28_s32x4, vget_low_s32 ( t_s32x4 ), in_s32x4[ 0 ], &S_s32x4, &out32_Q14_s32x2[ 0 ] ); + silk_biquad_alt_stride2_kernel( A_L_s32x4, A_U_s32x4, B_Q28_s32x4, vget_high_s32( t_s32x4 ), in_s32x4[ 1 ], &S_s32x4, &out32_Q14_s32x2[ 1 ] ); + + /* Scale back to Q0 and saturate */ + out32_Q14_s32x4 = vcombine_s32( out32_Q14_s32x2[ 0 ], out32_Q14_s32x2[ 1 ] ); /* out32_Q14_{0,1,2,3} */ + out32_Q14_s32x4 = vaddq_s32( out32_Q14_s32x4, offset_s32x4 ); /* out32_Q14_{0,1,2,3} + (1<<14) - 1 */ + out_s16x4 = vqshrn_n_s32( out32_Q14_s32x4, 14 ); /* (opus_int16)silk_SAT16( silk_RSHIFT( out32_Q14_{0,1,2,3} + (1<<14) - 1, 14 ) ) */ + vst1_s16( &out[ 2 * k ], out_s16x4 ); /* out[ 2 * k + {0,1,2,3} ] = (opus_int16)silk_SAT16( silk_RSHIFT( out32_Q14_{0,1,2,3} + (1<<14) - 1, 14 ) ); */ + } + + /* Process leftover. */ + if( k < len ) { + int32x4_t in_s32x4; + int32x2_t out32_Q14_s32x2; + + /* S[ 2 * i + 0 ], S[ 2 * i + 1 ]: Q12 */ + in_s16x4 = vld1_lane_s16( &in[ 2 * k + 0 ], in_s16x4, 0 ); /* in{0,1} = in[ 2 * k + {0,1} ]; */ + in_s16x4 = vld1_lane_s16( &in[ 2 * k + 1 ], in_s16x4, 1 ); /* in{0,1} = in[ 2 * k + {0,1} ]; */ + in_s32x4 = vshll_n_s16( in_s16x4, 15 ); /* in{0,1} << 15 */ + t_s32x2 = vqdmulh_lane_s32( vget_low_s32( in_s32x4 ), B_Q28_s32x2, 0 ); /* silk_SMULWB( B_Q28[ 0 ], in{0,1} ) */ + in_s32x4 = vcombine_s32( vget_low_s32( in_s32x4 ), vget_low_s32( in_s32x4 ) ); /* in{0,1,0,1} << 15 */ + silk_biquad_alt_stride2_kernel( A_L_s32x4, A_U_s32x4, B_Q28_s32x4, t_s32x2, in_s32x4, &S_s32x4, &out32_Q14_s32x2 ); + + /* Scale back to Q0 and saturate */ + out32_Q14_s32x2 = vadd_s32( out32_Q14_s32x2, offset_s32x2 ); /* out32_Q14_{0,1} + (1<<14) - 1 */ + out32_Q14_s32x4 = vcombine_s32( out32_Q14_s32x2, out32_Q14_s32x2 ); /* out32_Q14_{0,1,0,1} + (1<<14) - 1 */ + out_s16x4 = vqshrn_n_s32( out32_Q14_s32x4, 14 ); /* (opus_int16)silk_SAT16( silk_RSHIFT( out32_Q14_{0,1,0,1} + (1<<14) - 1, 14 ) ) */ + vst1_lane_s16( &out[ 2 * k + 0 ], out_s16x4, 0 ); /* out[ 2 * k + 0 ] = (opus_int16)silk_SAT16( silk_RSHIFT( out32_Q14_0 + (1<<14) - 1, 14 ) ); */ + vst1_lane_s16( &out[ 2 * k + 1 ], out_s16x4, 1 ); /* out[ 2 * k + 1 ] = (opus_int16)silk_SAT16( silk_RSHIFT( out32_Q14_1 + (1<<14) - 1, 14 ) ); */ + } + + vst1q_lane_s32( &S[ 0 ], S_s32x4, 0 ); /* S[ 0 ] = S0; */ + vst1q_lane_s32( &S[ 1 ], S_s32x4, 2 ); /* S[ 1 ] = S2; */ + vst1q_lane_s32( &S[ 2 ], S_s32x4, 1 ); /* S[ 2 ] = S1; */ + vst1q_lane_s32( &S[ 3 ], S_s32x4, 3 ); /* S[ 3 ] = S3; */ + +#ifdef OPUS_CHECK_ASM + silk_assert( !memcmp( S_c, S, sizeof( S_c ) ) ); + silk_assert( !memcmp( out_c, out, 2 * len * sizeof( opus_int16 ) ) ); + RESTORE_STACK; +#endif +} diff --git a/extern/opus/silk/arm/macros_arm64.h b/extern/opus/silk/arm/macros_arm64.h new file mode 100644 index 0000000..ed03041 --- /dev/null +++ b/extern/opus/silk/arm/macros_arm64.h @@ -0,0 +1,39 @@ +/*********************************************************************** +Copyright (C) 2015 Vidyo +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 OWNER 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. +***********************************************************************/ + +#ifndef SILK_MACROS_ARM64_H +#define SILK_MACROS_ARM64_H + +#include + +#undef silk_ADD_SAT32 +#define silk_ADD_SAT32(a, b) (vqadds_s32((a), (b))) + +#undef silk_SUB_SAT32 +#define silk_SUB_SAT32(a, b) (vqsubs_s32((a), (b))) + +#endif /* SILK_MACROS_ARM64_H */ diff --git a/extern/opus/silk/arm/macros_armv4.h b/extern/opus/silk/arm/macros_armv4.h new file mode 100644 index 0000000..877eb18 --- /dev/null +++ b/extern/opus/silk/arm/macros_armv4.h @@ -0,0 +1,110 @@ +/*********************************************************************** +Copyright (C) 2013 Xiph.Org Foundation and contributors. +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 OWNER 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. +***********************************************************************/ + +#ifndef SILK_MACROS_ARMv4_H +#define SILK_MACROS_ARMv4_H + +/* This macro only avoids the undefined behaviour from a left shift of + a negative value. It should only be used in macros that can't include + SigProc_FIX.h. In other cases, use silk_LSHIFT32(). */ +#define SAFE_SHL(a,b) ((opus_int32)((opus_uint32)(a) << (b))) + +/* (a32 * (opus_int32)((opus_int16)(b32))) >> 16 output have to be 32bit int */ +#undef silk_SMULWB +static OPUS_INLINE opus_int32 silk_SMULWB_armv4(opus_int32 a, opus_int16 b) +{ + unsigned rd_lo; + int rd_hi; + __asm__( + "#silk_SMULWB\n\t" + "smull %0, %1, %2, %3\n\t" + : "=&r"(rd_lo), "=&r"(rd_hi) + : "%r"(a), "r"(SAFE_SHL(b,16)) + ); + return rd_hi; +} +#define silk_SMULWB(a, b) (silk_SMULWB_armv4(a, b)) + +/* a32 + (b32 * (opus_int32)((opus_int16)(c32))) >> 16 output have to be 32bit int */ +#undef silk_SMLAWB +#define silk_SMLAWB(a, b, c) ((a) + silk_SMULWB(b, c)) + +/* (a32 * (b32 >> 16)) >> 16 */ +#undef silk_SMULWT +static OPUS_INLINE opus_int32 silk_SMULWT_armv4(opus_int32 a, opus_int32 b) +{ + unsigned rd_lo; + int rd_hi; + __asm__( + "#silk_SMULWT\n\t" + "smull %0, %1, %2, %3\n\t" + : "=&r"(rd_lo), "=&r"(rd_hi) + : "%r"(a), "r"(b&~0xFFFF) + ); + return rd_hi; +} +#define silk_SMULWT(a, b) (silk_SMULWT_armv4(a, b)) + +/* a32 + (b32 * (c32 >> 16)) >> 16 */ +#undef silk_SMLAWT +#define silk_SMLAWT(a, b, c) ((a) + silk_SMULWT(b, c)) + +/* (a32 * b32) >> 16 */ +#undef silk_SMULWW +static OPUS_INLINE opus_int32 silk_SMULWW_armv4(opus_int32 a, opus_int32 b) +{ + unsigned rd_lo; + int rd_hi; + __asm__( + "#silk_SMULWW\n\t" + "smull %0, %1, %2, %3\n\t" + : "=&r"(rd_lo), "=&r"(rd_hi) + : "%r"(a), "r"(b) + ); + return SAFE_SHL(rd_hi,16)+(rd_lo>>16); +} +#define silk_SMULWW(a, b) (silk_SMULWW_armv4(a, b)) + +#undef silk_SMLAWW +static OPUS_INLINE opus_int32 silk_SMLAWW_armv4(opus_int32 a, opus_int32 b, + opus_int32 c) +{ + unsigned rd_lo; + int rd_hi; + __asm__( + "#silk_SMLAWW\n\t" + "smull %0, %1, %2, %3\n\t" + : "=&r"(rd_lo), "=&r"(rd_hi) + : "%r"(b), "r"(c) + ); + return a+SAFE_SHL(rd_hi,16)+(rd_lo>>16); +} +#define silk_SMLAWW(a, b, c) (silk_SMLAWW_armv4(a, b, c)) + +#undef SAFE_SHL + +#endif /* SILK_MACROS_ARMv4_H */ diff --git a/extern/opus/silk/arm/macros_armv5e.h b/extern/opus/silk/arm/macros_armv5e.h new file mode 100644 index 0000000..b14ec65 --- /dev/null +++ b/extern/opus/silk/arm/macros_armv5e.h @@ -0,0 +1,220 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Copyright (c) 2013 Parrot +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 OWNER 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. +***********************************************************************/ + +#ifndef SILK_MACROS_ARMv5E_H +#define SILK_MACROS_ARMv5E_H + +/* This macro only avoids the undefined behaviour from a left shift of + a negative value. It should only be used in macros that can't include + SigProc_FIX.h. In other cases, use silk_LSHIFT32(). */ +#define SAFE_SHL(a,b) ((opus_int32)((opus_uint32)(a) << (b))) + +/* (a32 * (opus_int32)((opus_int16)(b32))) >> 16 output have to be 32bit int */ +#undef silk_SMULWB +static OPUS_INLINE opus_int32 silk_SMULWB_armv5e(opus_int32 a, opus_int16 b) +{ + int res; + __asm__( + "#silk_SMULWB\n\t" + "smulwb %0, %1, %2\n\t" + : "=r"(res) + : "r"(a), "r"(b) + ); + return res; +} +#define silk_SMULWB(a, b) (silk_SMULWB_armv5e(a, b)) + +/* a32 + (b32 * (opus_int32)((opus_int16)(c32))) >> 16 output have to be 32bit int */ +#undef silk_SMLAWB +static OPUS_INLINE opus_int32 silk_SMLAWB_armv5e(opus_int32 a, opus_int32 b, + opus_int16 c) +{ + int res; + __asm__( + "#silk_SMLAWB\n\t" + "smlawb %0, %1, %2, %3\n\t" + : "=r"(res) + : "r"(b), "r"(c), "r"(a) + ); + return res; +} +#define silk_SMLAWB(a, b, c) (silk_SMLAWB_armv5e(a, b, c)) + +/* (a32 * (b32 >> 16)) >> 16 */ +#undef silk_SMULWT +static OPUS_INLINE opus_int32 silk_SMULWT_armv5e(opus_int32 a, opus_int32 b) +{ + int res; + __asm__( + "#silk_SMULWT\n\t" + "smulwt %0, %1, %2\n\t" + : "=r"(res) + : "r"(a), "r"(b) + ); + return res; +} +#define silk_SMULWT(a, b) (silk_SMULWT_armv5e(a, b)) + +/* a32 + (b32 * (c32 >> 16)) >> 16 */ +#undef silk_SMLAWT +static OPUS_INLINE opus_int32 silk_SMLAWT_armv5e(opus_int32 a, opus_int32 b, + opus_int32 c) +{ + int res; + __asm__( + "#silk_SMLAWT\n\t" + "smlawt %0, %1, %2, %3\n\t" + : "=r"(res) + : "r"(b), "r"(c), "r"(a) + ); + return res; +} +#define silk_SMLAWT(a, b, c) (silk_SMLAWT_armv5e(a, b, c)) + +/* (opus_int32)((opus_int16)(a3))) * (opus_int32)((opus_int16)(b32)) output have to be 32bit int */ +#undef silk_SMULBB +static OPUS_INLINE opus_int32 silk_SMULBB_armv5e(opus_int32 a, opus_int32 b) +{ + int res; + __asm__( + "#silk_SMULBB\n\t" + "smulbb %0, %1, %2\n\t" + : "=r"(res) + : "%r"(a), "r"(b) + ); + return res; +} +#define silk_SMULBB(a, b) (silk_SMULBB_armv5e(a, b)) + +/* a32 + (opus_int32)((opus_int16)(b32)) * (opus_int32)((opus_int16)(c32)) output have to be 32bit int */ +#undef silk_SMLABB +static OPUS_INLINE opus_int32 silk_SMLABB_armv5e(opus_int32 a, opus_int32 b, + opus_int32 c) +{ + int res; + __asm__( + "#silk_SMLABB\n\t" + "smlabb %0, %1, %2, %3\n\t" + : "=r"(res) + : "%r"(b), "r"(c), "r"(a) + ); + return res; +} +#define silk_SMLABB(a, b, c) (silk_SMLABB_armv5e(a, b, c)) + +/* (opus_int32)((opus_int16)(a32)) * (b32 >> 16) */ +#undef silk_SMULBT +static OPUS_INLINE opus_int32 silk_SMULBT_armv5e(opus_int32 a, opus_int32 b) +{ + int res; + __asm__( + "#silk_SMULBT\n\t" + "smulbt %0, %1, %2\n\t" + : "=r"(res) + : "r"(a), "r"(b) + ); + return res; +} +#define silk_SMULBT(a, b) (silk_SMULBT_armv5e(a, b)) + +/* a32 + (opus_int32)((opus_int16)(b32)) * (c32 >> 16) */ +#undef silk_SMLABT +static OPUS_INLINE opus_int32 silk_SMLABT_armv5e(opus_int32 a, opus_int32 b, + opus_int32 c) +{ + int res; + __asm__( + "#silk_SMLABT\n\t" + "smlabt %0, %1, %2, %3\n\t" + : "=r"(res) + : "r"(b), "r"(c), "r"(a) + ); + return res; +} +#define silk_SMLABT(a, b, c) (silk_SMLABT_armv5e(a, b, c)) + +/* add/subtract with output saturated */ +#undef silk_ADD_SAT32 +static OPUS_INLINE opus_int32 silk_ADD_SAT32_armv5e(opus_int32 a, opus_int32 b) +{ + int res; + __asm__( + "#silk_ADD_SAT32\n\t" + "qadd %0, %1, %2\n\t" + : "=r"(res) + : "%r"(a), "r"(b) + ); + return res; +} +#define silk_ADD_SAT32(a, b) (silk_ADD_SAT32_armv5e(a, b)) + +#undef silk_SUB_SAT32 +static OPUS_INLINE opus_int32 silk_SUB_SAT32_armv5e(opus_int32 a, opus_int32 b) +{ + int res; + __asm__( + "#silk_SUB_SAT32\n\t" + "qsub %0, %1, %2\n\t" + : "=r"(res) + : "r"(a), "r"(b) + ); + return res; +} +#define silk_SUB_SAT32(a, b) (silk_SUB_SAT32_armv5e(a, b)) + +#undef silk_CLZ16 +static OPUS_INLINE opus_int32 silk_CLZ16_armv5(opus_int16 in16) +{ + int res; + __asm__( + "#silk_CLZ16\n\t" + "clz %0, %1;\n" + : "=r"(res) + : "r"(SAFE_SHL(in16,16)|0x8000) + ); + return res; +} +#define silk_CLZ16(in16) (silk_CLZ16_armv5(in16)) + +#undef silk_CLZ32 +static OPUS_INLINE opus_int32 silk_CLZ32_armv5(opus_int32 in32) +{ + int res; + __asm__( + "#silk_CLZ32\n\t" + "clz %0, %1\n\t" + : "=r"(res) + : "r"(in32) + ); + return res; +} +#define silk_CLZ32(in32) (silk_CLZ32_armv5(in32)) + +#undef SAFE_SHL + +#endif /* SILK_MACROS_ARMv5E_H */ diff --git a/extern/opus/silk/biquad_alt.c b/extern/opus/silk/biquad_alt.c new file mode 100644 index 0000000..54566a4 --- /dev/null +++ b/extern/opus/silk/biquad_alt.c @@ -0,0 +1,121 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +/* * + * silk_biquad_alt.c * + * * + * Second order ARMA filter * + * Can handle slowly varying filter coefficients * + * */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" + +/* Second order ARMA filter, alternative implementation */ +void silk_biquad_alt_stride1( + const opus_int16 *in, /* I input signal */ + const opus_int32 *B_Q28, /* I MA coefficients [3] */ + const opus_int32 *A_Q28, /* I AR coefficients [2] */ + opus_int32 *S, /* I/O State vector [2] */ + opus_int16 *out, /* O output signal */ + const opus_int32 len /* I signal length (must be even) */ +) +{ + /* DIRECT FORM II TRANSPOSED (uses 2 element state vector) */ + opus_int k; + opus_int32 inval, A0_U_Q28, A0_L_Q28, A1_U_Q28, A1_L_Q28, out32_Q14; + + /* Negate A_Q28 values and split in two parts */ + A0_L_Q28 = ( -A_Q28[ 0 ] ) & 0x00003FFF; /* lower part */ + A0_U_Q28 = silk_RSHIFT( -A_Q28[ 0 ], 14 ); /* upper part */ + A1_L_Q28 = ( -A_Q28[ 1 ] ) & 0x00003FFF; /* lower part */ + A1_U_Q28 = silk_RSHIFT( -A_Q28[ 1 ], 14 ); /* upper part */ + + for( k = 0; k < len; k++ ) { + /* S[ 0 ], S[ 1 ]: Q12 */ + inval = in[ k ]; + out32_Q14 = silk_LSHIFT( silk_SMLAWB( S[ 0 ], B_Q28[ 0 ], inval ), 2 ); + + S[ 0 ] = S[1] + silk_RSHIFT_ROUND( silk_SMULWB( out32_Q14, A0_L_Q28 ), 14 ); + S[ 0 ] = silk_SMLAWB( S[ 0 ], out32_Q14, A0_U_Q28 ); + S[ 0 ] = silk_SMLAWB( S[ 0 ], B_Q28[ 1 ], inval); + + S[ 1 ] = silk_RSHIFT_ROUND( silk_SMULWB( out32_Q14, A1_L_Q28 ), 14 ); + S[ 1 ] = silk_SMLAWB( S[ 1 ], out32_Q14, A1_U_Q28 ); + S[ 1 ] = silk_SMLAWB( S[ 1 ], B_Q28[ 2 ], inval ); + + /* Scale back to Q0 and saturate */ + out[ k ] = (opus_int16)silk_SAT16( silk_RSHIFT( out32_Q14 + (1<<14) - 1, 14 ) ); + } +} + +void silk_biquad_alt_stride2_c( + const opus_int16 *in, /* I input signal */ + const opus_int32 *B_Q28, /* I MA coefficients [3] */ + const opus_int32 *A_Q28, /* I AR coefficients [2] */ + opus_int32 *S, /* I/O State vector [4] */ + opus_int16 *out, /* O output signal */ + const opus_int32 len /* I signal length (must be even) */ +) +{ + /* DIRECT FORM II TRANSPOSED (uses 2 element state vector) */ + opus_int k; + opus_int32 A0_U_Q28, A0_L_Q28, A1_U_Q28, A1_L_Q28, out32_Q14[ 2 ]; + + /* Negate A_Q28 values and split in two parts */ + A0_L_Q28 = ( -A_Q28[ 0 ] ) & 0x00003FFF; /* lower part */ + A0_U_Q28 = silk_RSHIFT( -A_Q28[ 0 ], 14 ); /* upper part */ + A1_L_Q28 = ( -A_Q28[ 1 ] ) & 0x00003FFF; /* lower part */ + A1_U_Q28 = silk_RSHIFT( -A_Q28[ 1 ], 14 ); /* upper part */ + + for( k = 0; k < len; k++ ) { + /* S[ 0 ], S[ 1 ], S[ 2 ], S[ 3 ]: Q12 */ + out32_Q14[ 0 ] = silk_LSHIFT( silk_SMLAWB( S[ 0 ], B_Q28[ 0 ], in[ 2 * k + 0 ] ), 2 ); + out32_Q14[ 1 ] = silk_LSHIFT( silk_SMLAWB( S[ 2 ], B_Q28[ 0 ], in[ 2 * k + 1 ] ), 2 ); + + S[ 0 ] = S[ 1 ] + silk_RSHIFT_ROUND( silk_SMULWB( out32_Q14[ 0 ], A0_L_Q28 ), 14 ); + S[ 2 ] = S[ 3 ] + silk_RSHIFT_ROUND( silk_SMULWB( out32_Q14[ 1 ], A0_L_Q28 ), 14 ); + S[ 0 ] = silk_SMLAWB( S[ 0 ], out32_Q14[ 0 ], A0_U_Q28 ); + S[ 2 ] = silk_SMLAWB( S[ 2 ], out32_Q14[ 1 ], A0_U_Q28 ); + S[ 0 ] = silk_SMLAWB( S[ 0 ], B_Q28[ 1 ], in[ 2 * k + 0 ] ); + S[ 2 ] = silk_SMLAWB( S[ 2 ], B_Q28[ 1 ], in[ 2 * k + 1 ] ); + + S[ 1 ] = silk_RSHIFT_ROUND( silk_SMULWB( out32_Q14[ 0 ], A1_L_Q28 ), 14 ); + S[ 3 ] = silk_RSHIFT_ROUND( silk_SMULWB( out32_Q14[ 1 ], A1_L_Q28 ), 14 ); + S[ 1 ] = silk_SMLAWB( S[ 1 ], out32_Q14[ 0 ], A1_U_Q28 ); + S[ 3 ] = silk_SMLAWB( S[ 3 ], out32_Q14[ 1 ], A1_U_Q28 ); + S[ 1 ] = silk_SMLAWB( S[ 1 ], B_Q28[ 2 ], in[ 2 * k + 0 ] ); + S[ 3 ] = silk_SMLAWB( S[ 3 ], B_Q28[ 2 ], in[ 2 * k + 1 ] ); + + /* Scale back to Q0 and saturate */ + out[ 2 * k + 0 ] = (opus_int16)silk_SAT16( silk_RSHIFT( out32_Q14[ 0 ] + (1<<14) - 1, 14 ) ); + out[ 2 * k + 1 ] = (opus_int16)silk_SAT16( silk_RSHIFT( out32_Q14[ 1 ] + (1<<14) - 1, 14 ) ); + } +} diff --git a/extern/opus/silk/bwexpander.c b/extern/opus/silk/bwexpander.c new file mode 100644 index 0000000..afa9790 --- /dev/null +++ b/extern/opus/silk/bwexpander.c @@ -0,0 +1,51 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" + +/* Chirp (bandwidth expand) LP AR filter */ +void silk_bwexpander( + opus_int16 *ar, /* I/O AR filter to be expanded (without leading 1) */ + const opus_int d, /* I Length of ar */ + opus_int32 chirp_Q16 /* I Chirp factor (typically in the range 0 to 1) */ +) +{ + opus_int i; + opus_int32 chirp_minus_one_Q16 = chirp_Q16 - 65536; + + /* NB: Dont use silk_SMULWB, instead of silk_RSHIFT_ROUND( silk_MUL(), 16 ), below. */ + /* Bias in silk_SMULWB can lead to unstable filters */ + for( i = 0; i < d - 1; i++ ) { + ar[ i ] = (opus_int16)silk_RSHIFT_ROUND( silk_MUL( chirp_Q16, ar[ i ] ), 16 ); + chirp_Q16 += silk_RSHIFT_ROUND( silk_MUL( chirp_Q16, chirp_minus_one_Q16 ), 16 ); + } + ar[ d - 1 ] = (opus_int16)silk_RSHIFT_ROUND( silk_MUL( chirp_Q16, ar[ d - 1 ] ), 16 ); +} diff --git a/extern/opus/silk/bwexpander_32.c b/extern/opus/silk/bwexpander_32.c new file mode 100644 index 0000000..d0010f7 --- /dev/null +++ b/extern/opus/silk/bwexpander_32.c @@ -0,0 +1,50 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" + +/* Chirp (bandwidth expand) LP AR filter */ +void silk_bwexpander_32( + opus_int32 *ar, /* I/O AR filter to be expanded (without leading 1) */ + const opus_int d, /* I Length of ar */ + opus_int32 chirp_Q16 /* I Chirp factor in Q16 */ +) +{ + opus_int i; + opus_int32 chirp_minus_one_Q16 = chirp_Q16 - 65536; + + for( i = 0; i < d - 1; i++ ) { + ar[ i ] = silk_SMULWW( chirp_Q16, ar[ i ] ); + chirp_Q16 += silk_RSHIFT_ROUND( silk_MUL( chirp_Q16, chirp_minus_one_Q16 ), 16 ); + } + ar[ d - 1 ] = silk_SMULWW( chirp_Q16, ar[ d - 1 ] ); +} + diff --git a/extern/opus/silk/check_control_input.c b/extern/opus/silk/check_control_input.c new file mode 100644 index 0000000..739fb01 --- /dev/null +++ b/extern/opus/silk/check_control_input.c @@ -0,0 +1,106 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" +#include "control.h" +#include "errors.h" + +/* Check encoder control struct */ +opus_int check_control_input( + silk_EncControlStruct *encControl /* I Control structure */ +) +{ + celt_assert( encControl != NULL ); + + if( ( ( encControl->API_sampleRate != 8000 ) && + ( encControl->API_sampleRate != 12000 ) && + ( encControl->API_sampleRate != 16000 ) && + ( encControl->API_sampleRate != 24000 ) && + ( encControl->API_sampleRate != 32000 ) && + ( encControl->API_sampleRate != 44100 ) && + ( encControl->API_sampleRate != 48000 ) ) || + ( ( encControl->desiredInternalSampleRate != 8000 ) && + ( encControl->desiredInternalSampleRate != 12000 ) && + ( encControl->desiredInternalSampleRate != 16000 ) ) || + ( ( encControl->maxInternalSampleRate != 8000 ) && + ( encControl->maxInternalSampleRate != 12000 ) && + ( encControl->maxInternalSampleRate != 16000 ) ) || + ( ( encControl->minInternalSampleRate != 8000 ) && + ( encControl->minInternalSampleRate != 12000 ) && + ( encControl->minInternalSampleRate != 16000 ) ) || + ( encControl->minInternalSampleRate > encControl->desiredInternalSampleRate ) || + ( encControl->maxInternalSampleRate < encControl->desiredInternalSampleRate ) || + ( encControl->minInternalSampleRate > encControl->maxInternalSampleRate ) ) { + celt_assert( 0 ); + return SILK_ENC_FS_NOT_SUPPORTED; + } + if( encControl->payloadSize_ms != 10 && + encControl->payloadSize_ms != 20 && + encControl->payloadSize_ms != 40 && + encControl->payloadSize_ms != 60 ) { + celt_assert( 0 ); + return SILK_ENC_PACKET_SIZE_NOT_SUPPORTED; + } + if( encControl->packetLossPercentage < 0 || encControl->packetLossPercentage > 100 ) { + celt_assert( 0 ); + return SILK_ENC_INVALID_LOSS_RATE; + } + if( encControl->useDTX < 0 || encControl->useDTX > 1 ) { + celt_assert( 0 ); + return SILK_ENC_INVALID_DTX_SETTING; + } + if( encControl->useCBR < 0 || encControl->useCBR > 1 ) { + celt_assert( 0 ); + return SILK_ENC_INVALID_CBR_SETTING; + } + if( encControl->useInBandFEC < 0 || encControl->useInBandFEC > 1 ) { + celt_assert( 0 ); + return SILK_ENC_INVALID_INBAND_FEC_SETTING; + } + if( encControl->nChannelsAPI < 1 || encControl->nChannelsAPI > ENCODER_NUM_CHANNELS ) { + celt_assert( 0 ); + return SILK_ENC_INVALID_NUMBER_OF_CHANNELS_ERROR; + } + if( encControl->nChannelsInternal < 1 || encControl->nChannelsInternal > ENCODER_NUM_CHANNELS ) { + celt_assert( 0 ); + return SILK_ENC_INVALID_NUMBER_OF_CHANNELS_ERROR; + } + if( encControl->nChannelsInternal > encControl->nChannelsAPI ) { + celt_assert( 0 ); + return SILK_ENC_INVALID_NUMBER_OF_CHANNELS_ERROR; + } + if( encControl->complexity < 0 || encControl->complexity > 10 ) { + celt_assert( 0 ); + return SILK_ENC_INVALID_COMPLEXITY_SETTING; + } + + return SILK_NO_ERROR; +} diff --git a/extern/opus/silk/code_signs.c b/extern/opus/silk/code_signs.c new file mode 100644 index 0000000..dfd1dca --- /dev/null +++ b/extern/opus/silk/code_signs.c @@ -0,0 +1,115 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/*#define silk_enc_map(a) ((a) > 0 ? 1 : 0)*/ +/*#define silk_dec_map(a) ((a) > 0 ? 1 : -1)*/ +/* shifting avoids if-statement */ +#define silk_enc_map(a) ( silk_RSHIFT( (a), 15 ) + 1 ) +#define silk_dec_map(a) ( silk_LSHIFT( (a), 1 ) - 1 ) + +/* Encodes signs of excitation */ +void silk_encode_signs( + ec_enc *psRangeEnc, /* I/O Compressor data structure */ + const opus_int8 pulses[], /* I pulse signal */ + opus_int length, /* I length of input */ + const opus_int signalType, /* I Signal type */ + const opus_int quantOffsetType, /* I Quantization offset type */ + const opus_int sum_pulses[ MAX_NB_SHELL_BLOCKS ] /* I Sum of absolute pulses per block */ +) +{ + opus_int i, j, p; + opus_uint8 icdf[ 2 ]; + const opus_int8 *q_ptr; + const opus_uint8 *icdf_ptr; + + icdf[ 1 ] = 0; + q_ptr = pulses; + i = silk_SMULBB( 7, silk_ADD_LSHIFT( quantOffsetType, signalType, 1 ) ); + icdf_ptr = &silk_sign_iCDF[ i ]; + length = silk_RSHIFT( length + SHELL_CODEC_FRAME_LENGTH/2, LOG2_SHELL_CODEC_FRAME_LENGTH ); + for( i = 0; i < length; i++ ) { + p = sum_pulses[ i ]; + if( p > 0 ) { + icdf[ 0 ] = icdf_ptr[ silk_min( p & 0x1F, 6 ) ]; + for( j = 0; j < SHELL_CODEC_FRAME_LENGTH; j++ ) { + if( q_ptr[ j ] != 0 ) { + ec_enc_icdf( psRangeEnc, silk_enc_map( q_ptr[ j ]), icdf, 8 ); + } + } + } + q_ptr += SHELL_CODEC_FRAME_LENGTH; + } +} + +/* Decodes signs of excitation */ +void silk_decode_signs( + ec_dec *psRangeDec, /* I/O Compressor data structure */ + opus_int16 pulses[], /* I/O pulse signal */ + opus_int length, /* I length of input */ + const opus_int signalType, /* I Signal type */ + const opus_int quantOffsetType, /* I Quantization offset type */ + const opus_int sum_pulses[ MAX_NB_SHELL_BLOCKS ] /* I Sum of absolute pulses per block */ +) +{ + opus_int i, j, p; + opus_uint8 icdf[ 2 ]; + opus_int16 *q_ptr; + const opus_uint8 *icdf_ptr; + + icdf[ 1 ] = 0; + q_ptr = pulses; + i = silk_SMULBB( 7, silk_ADD_LSHIFT( quantOffsetType, signalType, 1 ) ); + icdf_ptr = &silk_sign_iCDF[ i ]; + length = silk_RSHIFT( length + SHELL_CODEC_FRAME_LENGTH/2, LOG2_SHELL_CODEC_FRAME_LENGTH ); + for( i = 0; i < length; i++ ) { + p = sum_pulses[ i ]; + if( p > 0 ) { + icdf[ 0 ] = icdf_ptr[ silk_min( p & 0x1F, 6 ) ]; + for( j = 0; j < SHELL_CODEC_FRAME_LENGTH; j++ ) { + if( q_ptr[ j ] > 0 ) { + /* attach sign */ +#if 0 + /* conditional implementation */ + if( ec_dec_icdf( psRangeDec, icdf, 8 ) == 0 ) { + q_ptr[ j ] = -q_ptr[ j ]; + } +#else + /* implementation with shift, subtraction, multiplication */ + q_ptr[ j ] *= silk_dec_map( ec_dec_icdf( psRangeDec, icdf, 8 ) ); +#endif + } + } + } + q_ptr += SHELL_CODEC_FRAME_LENGTH; + } +} diff --git a/extern/opus/silk/control.h b/extern/opus/silk/control.h new file mode 100644 index 0000000..b76ec33 --- /dev/null +++ b/extern/opus/silk/control.h @@ -0,0 +1,150 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifndef SILK_CONTROL_H +#define SILK_CONTROL_H + +#include "typedef.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* Decoder API flags */ +#define FLAG_DECODE_NORMAL 0 +#define FLAG_PACKET_LOST 1 +#define FLAG_DECODE_LBRR 2 + +/***********************************************/ +/* Structure for controlling encoder operation */ +/***********************************************/ +typedef struct { + /* I: Number of channels; 1/2 */ + opus_int32 nChannelsAPI; + + /* I: Number of channels; 1/2 */ + opus_int32 nChannelsInternal; + + /* I: Input signal sampling rate in Hertz; 8000/12000/16000/24000/32000/44100/48000 */ + opus_int32 API_sampleRate; + + /* I: Maximum internal sampling rate in Hertz; 8000/12000/16000 */ + opus_int32 maxInternalSampleRate; + + /* I: Minimum internal sampling rate in Hertz; 8000/12000/16000 */ + opus_int32 minInternalSampleRate; + + /* I: Soft request for internal sampling rate in Hertz; 8000/12000/16000 */ + opus_int32 desiredInternalSampleRate; + + /* I: Number of samples per packet in milliseconds; 10/20/40/60 */ + opus_int payloadSize_ms; + + /* I: Bitrate during active speech in bits/second; internally limited */ + opus_int32 bitRate; + + /* I: Uplink packet loss in percent (0-100) */ + opus_int packetLossPercentage; + + /* I: Complexity mode; 0 is lowest, 10 is highest complexity */ + opus_int complexity; + + /* I: Flag to enable in-band Forward Error Correction (FEC); 0/1 */ + opus_int useInBandFEC; + + /* I: Flag to actually code in-band Forward Error Correction (FEC) in the current packet; 0/1 */ + opus_int LBRR_coded; + + /* I: Flag to enable discontinuous transmission (DTX); 0/1 */ + opus_int useDTX; + + /* I: Flag to use constant bitrate */ + opus_int useCBR; + + /* I: Maximum number of bits allowed for the frame */ + opus_int maxBits; + + /* I: Causes a smooth downmix to mono */ + opus_int toMono; + + /* I: Opus encoder is allowing us to switch bandwidth */ + opus_int opusCanSwitch; + + /* I: Make frames as independent as possible (but still use LPC) */ + opus_int reducedDependency; + + /* O: Internal sampling rate used, in Hertz; 8000/12000/16000 */ + opus_int32 internalSampleRate; + + /* O: Flag that bandwidth switching is allowed (because low voice activity) */ + opus_int allowBandwidthSwitch; + + /* O: Flag that SILK runs in WB mode without variable LP filter (use for switching between WB/SWB/FB) */ + opus_int inWBmodeWithoutVariableLP; + + /* O: Stereo width */ + opus_int stereoWidth_Q14; + + /* O: Tells the Opus encoder we're ready to switch */ + opus_int switchReady; + + /* O: SILK Signal type */ + opus_int signalType; + + /* O: SILK offset (dithering) */ + opus_int offset; +} silk_EncControlStruct; + +/**************************************************************************/ +/* Structure for controlling decoder operation and reading decoder status */ +/**************************************************************************/ +typedef struct { + /* I: Number of channels; 1/2 */ + opus_int32 nChannelsAPI; + + /* I: Number of channels; 1/2 */ + opus_int32 nChannelsInternal; + + /* I: Output signal sampling rate in Hertz; 8000/12000/16000/24000/32000/44100/48000 */ + opus_int32 API_sampleRate; + + /* I: Internal sampling rate used, in Hertz; 8000/12000/16000 */ + opus_int32 internalSampleRate; + + /* I: Number of samples per packet in milliseconds; 10/20/40/60 */ + opus_int payloadSize_ms; + + /* O: Pitch lag of previous frame (0 if unvoiced), measured in samples at 48 kHz */ + opus_int prevPitchLag; +} silk_DecControlStruct; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/extern/opus/silk/control_SNR.c b/extern/opus/silk/control_SNR.c new file mode 100644 index 0000000..9a6db27 --- /dev/null +++ b/extern/opus/silk/control_SNR.c @@ -0,0 +1,113 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" +#include "tuning_parameters.h" + +/* These tables hold SNR values divided by 21 (so they fit in 8 bits) + for different target bitrates spaced at 400 bps interval. The first + 10 values are omitted (0-4 kb/s) because they're all zeros. + These tables were obtained by running different SNRs through the + encoder and measuring the active bitrate. */ +static const unsigned char silk_TargetRate_NB_21[117 - 10] = { + 0, 15, 39, 52, 61, 68, + 74, 79, 84, 88, 92, 95, 99,102,105,108,111,114,117,119,122,124, + 126,129,131,133,135,137,139,142,143,145,147,149,151,153,155,157, + 158,160,162,163,165,167,168,170,171,173,174,176,177,179,180,182, + 183,185,186,187,189,190,192,193,194,196,197,199,200,201,203,204, + 205,207,208,209,211,212,213,215,216,217,219,220,221,223,224,225, + 227,228,230,231,232,234,235,236,238,239,241,242,243,245,246,248, + 249,250,252,253,255 +}; + +static const unsigned char silk_TargetRate_MB_21[165 - 10] = { + 0, 0, 28, 43, 52, 59, + 65, 70, 74, 78, 81, 85, 87, 90, 93, 95, 98,100,102,105,107,109, + 111,113,115,116,118,120,122,123,125,127,128,130,131,133,134,136, + 137,138,140,141,143,144,145,147,148,149,151,152,153,154,156,157, + 158,159,160,162,163,164,165,166,167,168,169,171,172,173,174,175, + 176,177,178,179,180,181,182,183,184,185,186,187,188,188,189,190, + 191,192,193,194,195,196,197,198,199,200,201,202,203,203,204,205, + 206,207,208,209,210,211,212,213,214,214,215,216,217,218,219,220, + 221,222,223,224,224,225,226,227,228,229,230,231,232,233,234,235, + 236,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250, + 251,252,253,254,255 +}; + +static const unsigned char silk_TargetRate_WB_21[201 - 10] = { + 0, 0, 0, 8, 29, 41, + 49, 56, 62, 66, 70, 74, 77, 80, 83, 86, 88, 91, 93, 95, 97, 99, + 101,103,105,107,108,110,112,113,115,116,118,119,121,122,123,125, + 126,127,129,130,131,132,134,135,136,137,138,140,141,142,143,144, + 145,146,147,148,149,150,151,152,153,154,156,157,158,159,159,160, + 161,162,163,164,165,166,167,168,169,170,171,171,172,173,174,175, + 176,177,177,178,179,180,181,181,182,183,184,185,185,186,187,188, + 189,189,190,191,192,192,193,194,195,195,196,197,198,198,199,200, + 200,201,202,203,203,204,205,206,206,207,208,209,209,210,211,211, + 212,213,214,214,215,216,216,217,218,219,219,220,221,221,222,223, + 224,224,225,226,226,227,228,229,229,230,231,232,232,233,234,234, + 235,236,237,237,238,239,240,240,241,242,243,243,244,245,246,246, + 247,248,249,249,250,251,252,253,255 +}; + +/* Control SNR of redidual quantizer */ +opus_int silk_control_SNR( + silk_encoder_state *psEncC, /* I/O Pointer to Silk encoder state */ + opus_int32 TargetRate_bps /* I Target max bitrate (bps) */ +) +{ + int id; + int bound; + const unsigned char *snr_table; + + psEncC->TargetRate_bps = TargetRate_bps; + if( psEncC->nb_subfr == 2 ) { + TargetRate_bps -= 2000 + psEncC->fs_kHz/16; + } + if( psEncC->fs_kHz == 8 ) { + bound = sizeof(silk_TargetRate_NB_21); + snr_table = silk_TargetRate_NB_21; + } else if( psEncC->fs_kHz == 12 ) { + bound = sizeof(silk_TargetRate_MB_21); + snr_table = silk_TargetRate_MB_21; + } else { + bound = sizeof(silk_TargetRate_WB_21); + snr_table = silk_TargetRate_WB_21; + } + id = (TargetRate_bps+200)/400; + id = silk_min(id - 10, bound-1); + if( id <= 0 ) { + psEncC->SNR_dB_Q7 = 0; + } else { + psEncC->SNR_dB_Q7 = snr_table[id]*21; + } + return SILK_NO_ERROR; +} diff --git a/extern/opus/silk/control_audio_bandwidth.c b/extern/opus/silk/control_audio_bandwidth.c new file mode 100644 index 0000000..f6d22d8 --- /dev/null +++ b/extern/opus/silk/control_audio_bandwidth.c @@ -0,0 +1,132 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" +#include "tuning_parameters.h" + +/* Control internal sampling rate */ +opus_int silk_control_audio_bandwidth( + silk_encoder_state *psEncC, /* I/O Pointer to Silk encoder state */ + silk_EncControlStruct *encControl /* I Control structure */ +) +{ + opus_int fs_kHz; + opus_int orig_kHz; + opus_int32 fs_Hz; + + orig_kHz = psEncC->fs_kHz; + /* Handle a bandwidth-switching reset where we need to be aware what the last sampling rate was. */ + if( orig_kHz == 0 ) { + orig_kHz = psEncC->sLP.saved_fs_kHz; + } + fs_kHz = orig_kHz; + fs_Hz = silk_SMULBB( fs_kHz, 1000 ); + if( fs_Hz == 0 ) { + /* Encoder has just been initialized */ + fs_Hz = silk_min( psEncC->desiredInternal_fs_Hz, psEncC->API_fs_Hz ); + fs_kHz = silk_DIV32_16( fs_Hz, 1000 ); + } else if( fs_Hz > psEncC->API_fs_Hz || fs_Hz > psEncC->maxInternal_fs_Hz || fs_Hz < psEncC->minInternal_fs_Hz ) { + /* Make sure internal rate is not higher than external rate or maximum allowed, or lower than minimum allowed */ + fs_Hz = psEncC->API_fs_Hz; + fs_Hz = silk_min( fs_Hz, psEncC->maxInternal_fs_Hz ); + fs_Hz = silk_max( fs_Hz, psEncC->minInternal_fs_Hz ); + fs_kHz = silk_DIV32_16( fs_Hz, 1000 ); + } else { + /* State machine for the internal sampling rate switching */ + if( psEncC->sLP.transition_frame_no >= TRANSITION_FRAMES ) { + /* Stop transition phase */ + psEncC->sLP.mode = 0; + } + if( psEncC->allow_bandwidth_switch || encControl->opusCanSwitch ) { + /* Check if we should switch down */ + if( silk_SMULBB( orig_kHz, 1000 ) > psEncC->desiredInternal_fs_Hz ) + { + /* Switch down */ + if( psEncC->sLP.mode == 0 ) { + /* New transition */ + psEncC->sLP.transition_frame_no = TRANSITION_FRAMES; + + /* Reset transition filter state */ + silk_memset( psEncC->sLP.In_LP_State, 0, sizeof( psEncC->sLP.In_LP_State ) ); + } + if( encControl->opusCanSwitch ) { + /* Stop transition phase */ + psEncC->sLP.mode = 0; + + /* Switch to a lower sample frequency */ + fs_kHz = orig_kHz == 16 ? 12 : 8; + } else { + if( psEncC->sLP.transition_frame_no <= 0 ) { + encControl->switchReady = 1; + /* Make room for redundancy */ + encControl->maxBits -= encControl->maxBits * 5 / ( encControl->payloadSize_ms + 5 ); + } else { + /* Direction: down (at double speed) */ + psEncC->sLP.mode = -2; + } + } + } + else + /* Check if we should switch up */ + if( silk_SMULBB( orig_kHz, 1000 ) < psEncC->desiredInternal_fs_Hz ) + { + /* Switch up */ + if( encControl->opusCanSwitch ) { + /* Switch to a higher sample frequency */ + fs_kHz = orig_kHz == 8 ? 12 : 16; + + /* New transition */ + psEncC->sLP.transition_frame_no = 0; + + /* Reset transition filter state */ + silk_memset( psEncC->sLP.In_LP_State, 0, sizeof( psEncC->sLP.In_LP_State ) ); + + /* Direction: up */ + psEncC->sLP.mode = 1; + } else { + if( psEncC->sLP.mode == 0 ) { + encControl->switchReady = 1; + /* Make room for redundancy */ + encControl->maxBits -= encControl->maxBits * 5 / ( encControl->payloadSize_ms + 5 ); + } else { + /* Direction: up */ + psEncC->sLP.mode = 1; + } + } + } else { + if (psEncC->sLP.mode<0) + psEncC->sLP.mode = 1; + } + } + } + + return fs_kHz; +} diff --git a/extern/opus/silk/control_codec.c b/extern/opus/silk/control_codec.c new file mode 100644 index 0000000..52aa8fd --- /dev/null +++ b/extern/opus/silk/control_codec.c @@ -0,0 +1,423 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#ifdef FIXED_POINT +#include "main_FIX.h" +#define silk_encoder_state_Fxx silk_encoder_state_FIX +#else +#include "main_FLP.h" +#define silk_encoder_state_Fxx silk_encoder_state_FLP +#endif +#include "stack_alloc.h" +#include "tuning_parameters.h" +#include "pitch_est_defines.h" + +static opus_int silk_setup_resamplers( + silk_encoder_state_Fxx *psEnc, /* I/O */ + opus_int fs_kHz /* I */ +); + +static opus_int silk_setup_fs( + silk_encoder_state_Fxx *psEnc, /* I/O */ + opus_int fs_kHz, /* I */ + opus_int PacketSize_ms /* I */ +); + +static opus_int silk_setup_complexity( + silk_encoder_state *psEncC, /* I/O */ + opus_int Complexity /* I */ +); + +static OPUS_INLINE opus_int silk_setup_LBRR( + silk_encoder_state *psEncC, /* I/O */ + const silk_EncControlStruct *encControl /* I */ +); + + +/* Control encoder */ +opus_int silk_control_encoder( + silk_encoder_state_Fxx *psEnc, /* I/O Pointer to Silk encoder state */ + silk_EncControlStruct *encControl, /* I Control structure */ + const opus_int allow_bw_switch, /* I Flag to allow switching audio bandwidth */ + const opus_int channelNb, /* I Channel number */ + const opus_int force_fs_kHz +) +{ + opus_int fs_kHz, ret = 0; + + psEnc->sCmn.useDTX = encControl->useDTX; + psEnc->sCmn.useCBR = encControl->useCBR; + psEnc->sCmn.API_fs_Hz = encControl->API_sampleRate; + psEnc->sCmn.maxInternal_fs_Hz = encControl->maxInternalSampleRate; + psEnc->sCmn.minInternal_fs_Hz = encControl->minInternalSampleRate; + psEnc->sCmn.desiredInternal_fs_Hz = encControl->desiredInternalSampleRate; + psEnc->sCmn.useInBandFEC = encControl->useInBandFEC; + psEnc->sCmn.nChannelsAPI = encControl->nChannelsAPI; + psEnc->sCmn.nChannelsInternal = encControl->nChannelsInternal; + psEnc->sCmn.allow_bandwidth_switch = allow_bw_switch; + psEnc->sCmn.channelNb = channelNb; + + if( psEnc->sCmn.controlled_since_last_payload != 0 && psEnc->sCmn.prefillFlag == 0 ) { + if( psEnc->sCmn.API_fs_Hz != psEnc->sCmn.prev_API_fs_Hz && psEnc->sCmn.fs_kHz > 0 ) { + /* Change in API sampling rate in the middle of encoding a packet */ + ret += silk_setup_resamplers( psEnc, psEnc->sCmn.fs_kHz ); + } + return ret; + } + + /* Beyond this point we know that there are no previously coded frames in the payload buffer */ + + /********************************************/ + /* Determine internal sampling rate */ + /********************************************/ + fs_kHz = silk_control_audio_bandwidth( &psEnc->sCmn, encControl ); + if( force_fs_kHz ) { + fs_kHz = force_fs_kHz; + } + /********************************************/ + /* Prepare resampler and buffered data */ + /********************************************/ + ret += silk_setup_resamplers( psEnc, fs_kHz ); + + /********************************************/ + /* Set internal sampling frequency */ + /********************************************/ + ret += silk_setup_fs( psEnc, fs_kHz, encControl->payloadSize_ms ); + + /********************************************/ + /* Set encoding complexity */ + /********************************************/ + ret += silk_setup_complexity( &psEnc->sCmn, encControl->complexity ); + + /********************************************/ + /* Set packet loss rate measured by farend */ + /********************************************/ + psEnc->sCmn.PacketLoss_perc = encControl->packetLossPercentage; + + /********************************************/ + /* Set LBRR usage */ + /********************************************/ + ret += silk_setup_LBRR( &psEnc->sCmn, encControl ); + + psEnc->sCmn.controlled_since_last_payload = 1; + + return ret; +} + +static opus_int silk_setup_resamplers( + silk_encoder_state_Fxx *psEnc, /* I/O */ + opus_int fs_kHz /* I */ +) +{ + opus_int ret = SILK_NO_ERROR; + SAVE_STACK; + + if( psEnc->sCmn.fs_kHz != fs_kHz || psEnc->sCmn.prev_API_fs_Hz != psEnc->sCmn.API_fs_Hz ) + { + if( psEnc->sCmn.fs_kHz == 0 ) { + /* Initialize the resampler for enc_API.c preparing resampling from API_fs_Hz to fs_kHz */ + ret += silk_resampler_init( &psEnc->sCmn.resampler_state, psEnc->sCmn.API_fs_Hz, fs_kHz * 1000, 1 ); + } else { + VARDECL( opus_int16, x_buf_API_fs_Hz ); + VARDECL( silk_resampler_state_struct, temp_resampler_state ); +#ifdef FIXED_POINT + opus_int16 *x_bufFIX = psEnc->x_buf; +#else + VARDECL( opus_int16, x_bufFIX ); + opus_int32 new_buf_samples; +#endif + opus_int32 api_buf_samples; + opus_int32 old_buf_samples; + opus_int32 buf_length_ms; + + buf_length_ms = silk_LSHIFT( psEnc->sCmn.nb_subfr * 5, 1 ) + LA_SHAPE_MS; + old_buf_samples = buf_length_ms * psEnc->sCmn.fs_kHz; + +#ifndef FIXED_POINT + new_buf_samples = buf_length_ms * fs_kHz; + ALLOC( x_bufFIX, silk_max( old_buf_samples, new_buf_samples ), + opus_int16 ); + silk_float2short_array( x_bufFIX, psEnc->x_buf, old_buf_samples ); +#endif + + /* Initialize resampler for temporary resampling of x_buf data to API_fs_Hz */ + ALLOC( temp_resampler_state, 1, silk_resampler_state_struct ); + ret += silk_resampler_init( temp_resampler_state, silk_SMULBB( psEnc->sCmn.fs_kHz, 1000 ), psEnc->sCmn.API_fs_Hz, 0 ); + + /* Calculate number of samples to temporarily upsample */ + api_buf_samples = buf_length_ms * silk_DIV32_16( psEnc->sCmn.API_fs_Hz, 1000 ); + + /* Temporary resampling of x_buf data to API_fs_Hz */ + ALLOC( x_buf_API_fs_Hz, api_buf_samples, opus_int16 ); + ret += silk_resampler( temp_resampler_state, x_buf_API_fs_Hz, x_bufFIX, old_buf_samples ); + + /* Initialize the resampler for enc_API.c preparing resampling from API_fs_Hz to fs_kHz */ + ret += silk_resampler_init( &psEnc->sCmn.resampler_state, psEnc->sCmn.API_fs_Hz, silk_SMULBB( fs_kHz, 1000 ), 1 ); + + /* Correct resampler state by resampling buffered data from API_fs_Hz to fs_kHz */ + ret += silk_resampler( &psEnc->sCmn.resampler_state, x_bufFIX, x_buf_API_fs_Hz, api_buf_samples ); + +#ifndef FIXED_POINT + silk_short2float_array( psEnc->x_buf, x_bufFIX, new_buf_samples); +#endif + } + } + + psEnc->sCmn.prev_API_fs_Hz = psEnc->sCmn.API_fs_Hz; + + RESTORE_STACK; + return ret; +} + +static opus_int silk_setup_fs( + silk_encoder_state_Fxx *psEnc, /* I/O */ + opus_int fs_kHz, /* I */ + opus_int PacketSize_ms /* I */ +) +{ + opus_int ret = SILK_NO_ERROR; + + /* Set packet size */ + if( PacketSize_ms != psEnc->sCmn.PacketSize_ms ) { + if( ( PacketSize_ms != 10 ) && + ( PacketSize_ms != 20 ) && + ( PacketSize_ms != 40 ) && + ( PacketSize_ms != 60 ) ) { + ret = SILK_ENC_PACKET_SIZE_NOT_SUPPORTED; + } + if( PacketSize_ms <= 10 ) { + psEnc->sCmn.nFramesPerPacket = 1; + psEnc->sCmn.nb_subfr = PacketSize_ms == 10 ? 2 : 1; + psEnc->sCmn.frame_length = silk_SMULBB( PacketSize_ms, fs_kHz ); + psEnc->sCmn.pitch_LPC_win_length = silk_SMULBB( FIND_PITCH_LPC_WIN_MS_2_SF, fs_kHz ); + if( psEnc->sCmn.fs_kHz == 8 ) { + psEnc->sCmn.pitch_contour_iCDF = silk_pitch_contour_10_ms_NB_iCDF; + } else { + psEnc->sCmn.pitch_contour_iCDF = silk_pitch_contour_10_ms_iCDF; + } + } else { + psEnc->sCmn.nFramesPerPacket = silk_DIV32_16( PacketSize_ms, MAX_FRAME_LENGTH_MS ); + psEnc->sCmn.nb_subfr = MAX_NB_SUBFR; + psEnc->sCmn.frame_length = silk_SMULBB( 20, fs_kHz ); + psEnc->sCmn.pitch_LPC_win_length = silk_SMULBB( FIND_PITCH_LPC_WIN_MS, fs_kHz ); + if( psEnc->sCmn.fs_kHz == 8 ) { + psEnc->sCmn.pitch_contour_iCDF = silk_pitch_contour_NB_iCDF; + } else { + psEnc->sCmn.pitch_contour_iCDF = silk_pitch_contour_iCDF; + } + } + psEnc->sCmn.PacketSize_ms = PacketSize_ms; + psEnc->sCmn.TargetRate_bps = 0; /* trigger new SNR computation */ + } + + /* Set internal sampling frequency */ + celt_assert( fs_kHz == 8 || fs_kHz == 12 || fs_kHz == 16 ); + celt_assert( psEnc->sCmn.nb_subfr == 2 || psEnc->sCmn.nb_subfr == 4 ); + if( psEnc->sCmn.fs_kHz != fs_kHz ) { + /* reset part of the state */ + silk_memset( &psEnc->sShape, 0, sizeof( psEnc->sShape ) ); + silk_memset( &psEnc->sCmn.sNSQ, 0, sizeof( psEnc->sCmn.sNSQ ) ); + silk_memset( psEnc->sCmn.prev_NLSFq_Q15, 0, sizeof( psEnc->sCmn.prev_NLSFq_Q15 ) ); + silk_memset( &psEnc->sCmn.sLP.In_LP_State, 0, sizeof( psEnc->sCmn.sLP.In_LP_State ) ); + psEnc->sCmn.inputBufIx = 0; + psEnc->sCmn.nFramesEncoded = 0; + psEnc->sCmn.TargetRate_bps = 0; /* trigger new SNR computation */ + + /* Initialize non-zero parameters */ + psEnc->sCmn.prevLag = 100; + psEnc->sCmn.first_frame_after_reset = 1; + psEnc->sShape.LastGainIndex = 10; + psEnc->sCmn.sNSQ.lagPrev = 100; + psEnc->sCmn.sNSQ.prev_gain_Q16 = 65536; + psEnc->sCmn.prevSignalType = TYPE_NO_VOICE_ACTIVITY; + + psEnc->sCmn.fs_kHz = fs_kHz; + if( psEnc->sCmn.fs_kHz == 8 ) { + if( psEnc->sCmn.nb_subfr == MAX_NB_SUBFR ) { + psEnc->sCmn.pitch_contour_iCDF = silk_pitch_contour_NB_iCDF; + } else { + psEnc->sCmn.pitch_contour_iCDF = silk_pitch_contour_10_ms_NB_iCDF; + } + } else { + if( psEnc->sCmn.nb_subfr == MAX_NB_SUBFR ) { + psEnc->sCmn.pitch_contour_iCDF = silk_pitch_contour_iCDF; + } else { + psEnc->sCmn.pitch_contour_iCDF = silk_pitch_contour_10_ms_iCDF; + } + } + if( psEnc->sCmn.fs_kHz == 8 || psEnc->sCmn.fs_kHz == 12 ) { + psEnc->sCmn.predictLPCOrder = MIN_LPC_ORDER; + psEnc->sCmn.psNLSF_CB = &silk_NLSF_CB_NB_MB; + } else { + psEnc->sCmn.predictLPCOrder = MAX_LPC_ORDER; + psEnc->sCmn.psNLSF_CB = &silk_NLSF_CB_WB; + } + psEnc->sCmn.subfr_length = SUB_FRAME_LENGTH_MS * fs_kHz; + psEnc->sCmn.frame_length = silk_SMULBB( psEnc->sCmn.subfr_length, psEnc->sCmn.nb_subfr ); + psEnc->sCmn.ltp_mem_length = silk_SMULBB( LTP_MEM_LENGTH_MS, fs_kHz ); + psEnc->sCmn.la_pitch = silk_SMULBB( LA_PITCH_MS, fs_kHz ); + psEnc->sCmn.max_pitch_lag = silk_SMULBB( 18, fs_kHz ); + if( psEnc->sCmn.nb_subfr == MAX_NB_SUBFR ) { + psEnc->sCmn.pitch_LPC_win_length = silk_SMULBB( FIND_PITCH_LPC_WIN_MS, fs_kHz ); + } else { + psEnc->sCmn.pitch_LPC_win_length = silk_SMULBB( FIND_PITCH_LPC_WIN_MS_2_SF, fs_kHz ); + } + if( psEnc->sCmn.fs_kHz == 16 ) { + psEnc->sCmn.pitch_lag_low_bits_iCDF = silk_uniform8_iCDF; + } else if( psEnc->sCmn.fs_kHz == 12 ) { + psEnc->sCmn.pitch_lag_low_bits_iCDF = silk_uniform6_iCDF; + } else { + psEnc->sCmn.pitch_lag_low_bits_iCDF = silk_uniform4_iCDF; + } + } + + /* Check that settings are valid */ + celt_assert( ( psEnc->sCmn.subfr_length * psEnc->sCmn.nb_subfr ) == psEnc->sCmn.frame_length ); + + return ret; +} + +static opus_int silk_setup_complexity( + silk_encoder_state *psEncC, /* I/O */ + opus_int Complexity /* I */ +) +{ + opus_int ret = 0; + + /* Set encoding complexity */ + celt_assert( Complexity >= 0 && Complexity <= 10 ); + if( Complexity < 1 ) { + psEncC->pitchEstimationComplexity = SILK_PE_MIN_COMPLEX; + psEncC->pitchEstimationThreshold_Q16 = SILK_FIX_CONST( 0.8, 16 ); + psEncC->pitchEstimationLPCOrder = 6; + psEncC->shapingLPCOrder = 12; + psEncC->la_shape = 3 * psEncC->fs_kHz; + psEncC->nStatesDelayedDecision = 1; + psEncC->useInterpolatedNLSFs = 0; + psEncC->NLSF_MSVQ_Survivors = 2; + psEncC->warping_Q16 = 0; + } else if( Complexity < 2 ) { + psEncC->pitchEstimationComplexity = SILK_PE_MID_COMPLEX; + psEncC->pitchEstimationThreshold_Q16 = SILK_FIX_CONST( 0.76, 16 ); + psEncC->pitchEstimationLPCOrder = 8; + psEncC->shapingLPCOrder = 14; + psEncC->la_shape = 5 * psEncC->fs_kHz; + psEncC->nStatesDelayedDecision = 1; + psEncC->useInterpolatedNLSFs = 0; + psEncC->NLSF_MSVQ_Survivors = 3; + psEncC->warping_Q16 = 0; + } else if( Complexity < 3 ) { + psEncC->pitchEstimationComplexity = SILK_PE_MIN_COMPLEX; + psEncC->pitchEstimationThreshold_Q16 = SILK_FIX_CONST( 0.8, 16 ); + psEncC->pitchEstimationLPCOrder = 6; + psEncC->shapingLPCOrder = 12; + psEncC->la_shape = 3 * psEncC->fs_kHz; + psEncC->nStatesDelayedDecision = 2; + psEncC->useInterpolatedNLSFs = 0; + psEncC->NLSF_MSVQ_Survivors = 2; + psEncC->warping_Q16 = 0; + } else if( Complexity < 4 ) { + psEncC->pitchEstimationComplexity = SILK_PE_MID_COMPLEX; + psEncC->pitchEstimationThreshold_Q16 = SILK_FIX_CONST( 0.76, 16 ); + psEncC->pitchEstimationLPCOrder = 8; + psEncC->shapingLPCOrder = 14; + psEncC->la_shape = 5 * psEncC->fs_kHz; + psEncC->nStatesDelayedDecision = 2; + psEncC->useInterpolatedNLSFs = 0; + psEncC->NLSF_MSVQ_Survivors = 4; + psEncC->warping_Q16 = 0; + } else if( Complexity < 6 ) { + psEncC->pitchEstimationComplexity = SILK_PE_MID_COMPLEX; + psEncC->pitchEstimationThreshold_Q16 = SILK_FIX_CONST( 0.74, 16 ); + psEncC->pitchEstimationLPCOrder = 10; + psEncC->shapingLPCOrder = 16; + psEncC->la_shape = 5 * psEncC->fs_kHz; + psEncC->nStatesDelayedDecision = 2; + psEncC->useInterpolatedNLSFs = 1; + psEncC->NLSF_MSVQ_Survivors = 6; + psEncC->warping_Q16 = psEncC->fs_kHz * SILK_FIX_CONST( WARPING_MULTIPLIER, 16 ); + } else if( Complexity < 8 ) { + psEncC->pitchEstimationComplexity = SILK_PE_MID_COMPLEX; + psEncC->pitchEstimationThreshold_Q16 = SILK_FIX_CONST( 0.72, 16 ); + psEncC->pitchEstimationLPCOrder = 12; + psEncC->shapingLPCOrder = 20; + psEncC->la_shape = 5 * psEncC->fs_kHz; + psEncC->nStatesDelayedDecision = 3; + psEncC->useInterpolatedNLSFs = 1; + psEncC->NLSF_MSVQ_Survivors = 8; + psEncC->warping_Q16 = psEncC->fs_kHz * SILK_FIX_CONST( WARPING_MULTIPLIER, 16 ); + } else { + psEncC->pitchEstimationComplexity = SILK_PE_MAX_COMPLEX; + psEncC->pitchEstimationThreshold_Q16 = SILK_FIX_CONST( 0.7, 16 ); + psEncC->pitchEstimationLPCOrder = 16; + psEncC->shapingLPCOrder = 24; + psEncC->la_shape = 5 * psEncC->fs_kHz; + psEncC->nStatesDelayedDecision = MAX_DEL_DEC_STATES; + psEncC->useInterpolatedNLSFs = 1; + psEncC->NLSF_MSVQ_Survivors = 16; + psEncC->warping_Q16 = psEncC->fs_kHz * SILK_FIX_CONST( WARPING_MULTIPLIER, 16 ); + } + + /* Do not allow higher pitch estimation LPC order than predict LPC order */ + psEncC->pitchEstimationLPCOrder = silk_min_int( psEncC->pitchEstimationLPCOrder, psEncC->predictLPCOrder ); + psEncC->shapeWinLength = SUB_FRAME_LENGTH_MS * psEncC->fs_kHz + 2 * psEncC->la_shape; + psEncC->Complexity = Complexity; + + celt_assert( psEncC->pitchEstimationLPCOrder <= MAX_FIND_PITCH_LPC_ORDER ); + celt_assert( psEncC->shapingLPCOrder <= MAX_SHAPE_LPC_ORDER ); + celt_assert( psEncC->nStatesDelayedDecision <= MAX_DEL_DEC_STATES ); + celt_assert( psEncC->warping_Q16 <= 32767 ); + celt_assert( psEncC->la_shape <= LA_SHAPE_MAX ); + celt_assert( psEncC->shapeWinLength <= SHAPE_LPC_WIN_MAX ); + + return ret; +} + +static OPUS_INLINE opus_int silk_setup_LBRR( + silk_encoder_state *psEncC, /* I/O */ + const silk_EncControlStruct *encControl /* I */ +) +{ + opus_int LBRR_in_previous_packet, ret = SILK_NO_ERROR; + + LBRR_in_previous_packet = psEncC->LBRR_enabled; + psEncC->LBRR_enabled = encControl->LBRR_coded; + if( psEncC->LBRR_enabled ) { + /* Set gain increase for coding LBRR excitation */ + if( LBRR_in_previous_packet == 0 ) { + /* Previous packet did not have LBRR, and was therefore coded at a higher bitrate */ + psEncC->LBRR_GainIncreases = 7; + } else { + psEncC->LBRR_GainIncreases = silk_max_int( 7 - silk_SMULWB( (opus_int32)psEncC->PacketLoss_perc, SILK_FIX_CONST( 0.4, 16 ) ), 2 ); + } + } + + return ret; +} diff --git a/extern/opus/silk/debug.c b/extern/opus/silk/debug.c new file mode 100644 index 0000000..9253faf --- /dev/null +++ b/extern/opus/silk/debug.c @@ -0,0 +1,170 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "debug.h" +#include "SigProc_FIX.h" + +#if SILK_TIC_TOC + +#ifdef _WIN32 + +#if (defined(_WIN32) || defined(_WINCE)) +#include /* timer */ +#else /* Linux or Mac*/ +#include +#endif + +unsigned long silk_GetHighResolutionTime(void) /* O time in usec*/ +{ + /* Returns a time counter in microsec */ + /* the resolution is platform dependent */ + /* but is typically 1.62 us resolution */ + LARGE_INTEGER lpPerformanceCount; + LARGE_INTEGER lpFrequency; + QueryPerformanceCounter(&lpPerformanceCount); + QueryPerformanceFrequency(&lpFrequency); + return (unsigned long)((1000000*(lpPerformanceCount.QuadPart)) / lpFrequency.QuadPart); +} +#else /* Linux or Mac*/ +unsigned long GetHighResolutionTime(void) /* O time in usec*/ +{ + struct timeval tv; + gettimeofday(&tv, 0); + return((tv.tv_sec*1000000)+(tv.tv_usec)); +} +#endif + +int silk_Timer_nTimers = 0; +int silk_Timer_depth_ctr = 0; +char silk_Timer_tags[silk_NUM_TIMERS_MAX][silk_NUM_TIMERS_MAX_TAG_LEN]; +#ifdef WIN32 +LARGE_INTEGER silk_Timer_start[silk_NUM_TIMERS_MAX]; +#else +unsigned long silk_Timer_start[silk_NUM_TIMERS_MAX]; +#endif +unsigned int silk_Timer_cnt[silk_NUM_TIMERS_MAX]; +opus_int64 silk_Timer_min[silk_NUM_TIMERS_MAX]; +opus_int64 silk_Timer_sum[silk_NUM_TIMERS_MAX]; +opus_int64 silk_Timer_max[silk_NUM_TIMERS_MAX]; +opus_int64 silk_Timer_depth[silk_NUM_TIMERS_MAX]; + +#ifdef WIN32 +void silk_TimerSave(char *file_name) +{ + if( silk_Timer_nTimers > 0 ) + { + int k; + FILE *fp; + LARGE_INTEGER lpFrequency; + LARGE_INTEGER lpPerformanceCount1, lpPerformanceCount2; + int del = 0x7FFFFFFF; + double avg, sum_avg; + /* estimate overhead of calling performance counters */ + for( k = 0; k < 1000; k++ ) { + QueryPerformanceCounter(&lpPerformanceCount1); + QueryPerformanceCounter(&lpPerformanceCount2); + lpPerformanceCount2.QuadPart -= lpPerformanceCount1.QuadPart; + if( (int)lpPerformanceCount2.LowPart < del ) + del = lpPerformanceCount2.LowPart; + } + QueryPerformanceFrequency(&lpFrequency); + /* print results to file */ + sum_avg = 0.0f; + for( k = 0; k < silk_Timer_nTimers; k++ ) { + if (silk_Timer_depth[k] == 0) { + sum_avg += (1e6 * silk_Timer_sum[k] / silk_Timer_cnt[k] - del) / lpFrequency.QuadPart * silk_Timer_cnt[k]; + } + } + fp = fopen(file_name, "w"); + fprintf(fp, " min avg %% max count\n"); + for( k = 0; k < silk_Timer_nTimers; k++ ) { + if (silk_Timer_depth[k] == 0) { + fprintf(fp, "%-28s", silk_Timer_tags[k]); + } else if (silk_Timer_depth[k] == 1) { + fprintf(fp, " %-27s", silk_Timer_tags[k]); + } else if (silk_Timer_depth[k] == 2) { + fprintf(fp, " %-26s", silk_Timer_tags[k]); + } else if (silk_Timer_depth[k] == 3) { + fprintf(fp, " %-25s", silk_Timer_tags[k]); + } else { + fprintf(fp, " %-24s", silk_Timer_tags[k]); + } + avg = (1e6 * silk_Timer_sum[k] / silk_Timer_cnt[k] - del) / lpFrequency.QuadPart; + fprintf(fp, "%8.2f", (1e6 * (silk_max_64(silk_Timer_min[k] - del, 0))) / lpFrequency.QuadPart); + fprintf(fp, "%12.2f %6.2f", avg, 100.0 * avg / sum_avg * silk_Timer_cnt[k]); + fprintf(fp, "%12.2f", (1e6 * (silk_max_64(silk_Timer_max[k] - del, 0))) / lpFrequency.QuadPart); + fprintf(fp, "%10d\n", silk_Timer_cnt[k]); + } + fprintf(fp, " microseconds\n"); + fclose(fp); + } +} +#else +void silk_TimerSave(char *file_name) +{ + if( silk_Timer_nTimers > 0 ) + { + int k; + FILE *fp; + /* print results to file */ + fp = fopen(file_name, "w"); + fprintf(fp, " min avg max count\n"); + for( k = 0; k < silk_Timer_nTimers; k++ ) + { + if (silk_Timer_depth[k] == 0) { + fprintf(fp, "%-28s", silk_Timer_tags[k]); + } else if (silk_Timer_depth[k] == 1) { + fprintf(fp, " %-27s", silk_Timer_tags[k]); + } else if (silk_Timer_depth[k] == 2) { + fprintf(fp, " %-26s", silk_Timer_tags[k]); + } else if (silk_Timer_depth[k] == 3) { + fprintf(fp, " %-25s", silk_Timer_tags[k]); + } else { + fprintf(fp, " %-24s", silk_Timer_tags[k]); + } + fprintf(fp, "%d ", silk_Timer_min[k]); + fprintf(fp, "%f ", (double)silk_Timer_sum[k] / (double)silk_Timer_cnt[k]); + fprintf(fp, "%d ", silk_Timer_max[k]); + fprintf(fp, "%10d\n", silk_Timer_cnt[k]); + } + fprintf(fp, " microseconds\n"); + fclose(fp); + } +} +#endif + +#endif /* SILK_TIC_TOC */ + +#if SILK_DEBUG +FILE *silk_debug_store_fp[ silk_NUM_STORES_MAX ]; +int silk_debug_store_count = 0; +#endif /* SILK_DEBUG */ + diff --git a/extern/opus/silk/debug.h b/extern/opus/silk/debug.h new file mode 100644 index 0000000..6f68c1c --- /dev/null +++ b/extern/opus/silk/debug.h @@ -0,0 +1,266 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifndef SILK_DEBUG_H +#define SILK_DEBUG_H + +#include "typedef.h" +#include /* file writing */ +#include /* strcpy, strcmp */ + +#ifdef __cplusplus +extern "C" +{ +#endif + +unsigned long GetHighResolutionTime(void); /* O time in usec*/ + +/* Set to 1 to enable DEBUG_STORE_DATA() macros for dumping + * intermediate signals from the codec. + */ +#define SILK_DEBUG 0 + +/* Flag for using timers */ +#define SILK_TIC_TOC 0 + + +#if SILK_TIC_TOC + +#if (defined(_WIN32) || defined(_WINCE)) +#include /* timer */ +#else /* Linux or Mac*/ +#include +#endif + +/*********************************/ +/* timer functions for profiling */ +/*********************************/ +/* example: */ +/* */ +/* TIC(LPC) */ +/* do_LPC(in_vec, order, acoef); // do LPC analysis */ +/* TOC(LPC) */ +/* */ +/* and call the following just before exiting (from main) */ +/* */ +/* silk_TimerSave("silk_TimingData.txt"); */ +/* */ +/* results are now in silk_TimingData.txt */ + +void silk_TimerSave(char *file_name); + +/* max number of timers (in different locations) */ +#define silk_NUM_TIMERS_MAX 50 +/* max length of name tags in TIC(..), TOC(..) */ +#define silk_NUM_TIMERS_MAX_TAG_LEN 30 + +extern int silk_Timer_nTimers; +extern int silk_Timer_depth_ctr; +extern char silk_Timer_tags[silk_NUM_TIMERS_MAX][silk_NUM_TIMERS_MAX_TAG_LEN]; +#ifdef _WIN32 +extern LARGE_INTEGER silk_Timer_start[silk_NUM_TIMERS_MAX]; +#else +extern unsigned long silk_Timer_start[silk_NUM_TIMERS_MAX]; +#endif +extern unsigned int silk_Timer_cnt[silk_NUM_TIMERS_MAX]; +extern opus_int64 silk_Timer_sum[silk_NUM_TIMERS_MAX]; +extern opus_int64 silk_Timer_max[silk_NUM_TIMERS_MAX]; +extern opus_int64 silk_Timer_min[silk_NUM_TIMERS_MAX]; +extern opus_int64 silk_Timer_depth[silk_NUM_TIMERS_MAX]; + +/* WARNING: TIC()/TOC can measure only up to 0.1 seconds at a time */ +#ifdef _WIN32 +#define TIC(TAG_NAME) { \ + static int init = 0; \ + static int ID = -1; \ + if( init == 0 ) \ + { \ + int k; \ + init = 1; \ + for( k = 0; k < silk_Timer_nTimers; k++ ) { \ + if( strcmp(silk_Timer_tags[k], #TAG_NAME) == 0 ) { \ + ID = k; \ + break; \ + } \ + } \ + if (ID == -1) { \ + ID = silk_Timer_nTimers; \ + silk_Timer_nTimers++; \ + silk_Timer_depth[ID] = silk_Timer_depth_ctr; \ + strcpy(silk_Timer_tags[ID], #TAG_NAME); \ + silk_Timer_cnt[ID] = 0; \ + silk_Timer_sum[ID] = 0; \ + silk_Timer_min[ID] = 0xFFFFFFFF; \ + silk_Timer_max[ID] = 0; \ + } \ + } \ + silk_Timer_depth_ctr++; \ + QueryPerformanceCounter(&silk_Timer_start[ID]); \ +} +#else +#define TIC(TAG_NAME) { \ + static int init = 0; \ + static int ID = -1; \ + if( init == 0 ) \ + { \ + int k; \ + init = 1; \ + for( k = 0; k < silk_Timer_nTimers; k++ ) { \ + if( strcmp(silk_Timer_tags[k], #TAG_NAME) == 0 ) { \ + ID = k; \ + break; \ + } \ + } \ + if (ID == -1) { \ + ID = silk_Timer_nTimers; \ + silk_Timer_nTimers++; \ + silk_Timer_depth[ID] = silk_Timer_depth_ctr; \ + strcpy(silk_Timer_tags[ID], #TAG_NAME); \ + silk_Timer_cnt[ID] = 0; \ + silk_Timer_sum[ID] = 0; \ + silk_Timer_min[ID] = 0xFFFFFFFF; \ + silk_Timer_max[ID] = 0; \ + } \ + } \ + silk_Timer_depth_ctr++; \ + silk_Timer_start[ID] = GetHighResolutionTime(); \ +} +#endif + +#ifdef _WIN32 +#define TOC(TAG_NAME) { \ + LARGE_INTEGER lpPerformanceCount; \ + static int init = 0; \ + static int ID = 0; \ + if( init == 0 ) \ + { \ + int k; \ + init = 1; \ + for( k = 0; k < silk_Timer_nTimers; k++ ) { \ + if( strcmp(silk_Timer_tags[k], #TAG_NAME) == 0 ) { \ + ID = k; \ + break; \ + } \ + } \ + } \ + QueryPerformanceCounter(&lpPerformanceCount); \ + lpPerformanceCount.QuadPart -= silk_Timer_start[ID].QuadPart; \ + if((lpPerformanceCount.QuadPart < 100000000) && \ + (lpPerformanceCount.QuadPart >= 0)) { \ + silk_Timer_cnt[ID]++; \ + silk_Timer_sum[ID] += lpPerformanceCount.QuadPart; \ + if( lpPerformanceCount.QuadPart > silk_Timer_max[ID] ) \ + silk_Timer_max[ID] = lpPerformanceCount.QuadPart; \ + if( lpPerformanceCount.QuadPart < silk_Timer_min[ID] ) \ + silk_Timer_min[ID] = lpPerformanceCount.QuadPart; \ + } \ + silk_Timer_depth_ctr--; \ +} +#else +#define TOC(TAG_NAME) { \ + unsigned long endTime; \ + static int init = 0; \ + static int ID = 0; \ + if( init == 0 ) \ + { \ + int k; \ + init = 1; \ + for( k = 0; k < silk_Timer_nTimers; k++ ) { \ + if( strcmp(silk_Timer_tags[k], #TAG_NAME) == 0 ) { \ + ID = k; \ + break; \ + } \ + } \ + } \ + endTime = GetHighResolutionTime(); \ + endTime -= silk_Timer_start[ID]; \ + if((endTime < 100000000) && \ + (endTime >= 0)) { \ + silk_Timer_cnt[ID]++; \ + silk_Timer_sum[ID] += endTime; \ + if( endTime > silk_Timer_max[ID] ) \ + silk_Timer_max[ID] = endTime; \ + if( endTime < silk_Timer_min[ID] ) \ + silk_Timer_min[ID] = endTime; \ + } \ + silk_Timer_depth_ctr--; \ +} +#endif + +#else /* SILK_TIC_TOC */ + +/* define macros as empty strings */ +#define TIC(TAG_NAME) +#define TOC(TAG_NAME) +#define silk_TimerSave(FILE_NAME) + +#endif /* SILK_TIC_TOC */ + + +#if SILK_DEBUG +/************************************/ +/* write data to file for debugging */ +/************************************/ +/* Example: DEBUG_STORE_DATA(testfile.pcm, &RIN[0], 160*sizeof(opus_int16)); */ + +#define silk_NUM_STORES_MAX 100 +extern FILE *silk_debug_store_fp[ silk_NUM_STORES_MAX ]; +extern int silk_debug_store_count; + +/* Faster way of storing the data */ +#define DEBUG_STORE_DATA( FILE_NAME, DATA_PTR, N_BYTES ) { \ + static opus_int init = 0, cnt = 0; \ + static FILE **fp; \ + if (init == 0) { \ + init = 1; \ + cnt = silk_debug_store_count++; \ + silk_debug_store_fp[ cnt ] = fopen(#FILE_NAME, "wb"); \ + } \ + fwrite((DATA_PTR), (N_BYTES), 1, silk_debug_store_fp[ cnt ]); \ +} + +/* Call this at the end of main() */ +#define SILK_DEBUG_STORE_CLOSE_FILES { \ + opus_int i; \ + for( i = 0; i < silk_debug_store_count; i++ ) { \ + fclose( silk_debug_store_fp[ i ] ); \ + } \ +} + +#else /* SILK_DEBUG */ + +/* define macros as empty strings */ +#define DEBUG_STORE_DATA(FILE_NAME, DATA_PTR, N_BYTES) +#define SILK_DEBUG_STORE_CLOSE_FILES + +#endif /* SILK_DEBUG */ + +#ifdef __cplusplus +} +#endif + +#endif /* SILK_DEBUG_H */ diff --git a/extern/opus/silk/dec_API.c b/extern/opus/silk/dec_API.c new file mode 100644 index 0000000..7d5ca7f --- /dev/null +++ b/extern/opus/silk/dec_API.c @@ -0,0 +1,419 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "API.h" +#include "main.h" +#include "stack_alloc.h" +#include "os_support.h" + +/************************/ +/* Decoder Super Struct */ +/************************/ +typedef struct { + silk_decoder_state channel_state[ DECODER_NUM_CHANNELS ]; + stereo_dec_state sStereo; + opus_int nChannelsAPI; + opus_int nChannelsInternal; + opus_int prev_decode_only_middle; +} silk_decoder; + +/*********************/ +/* Decoder functions */ +/*********************/ + +opus_int silk_Get_Decoder_Size( /* O Returns error code */ + opus_int *decSizeBytes /* O Number of bytes in SILK decoder state */ +) +{ + opus_int ret = SILK_NO_ERROR; + + *decSizeBytes = sizeof( silk_decoder ); + + return ret; +} + +/* Reset decoder state */ +opus_int silk_InitDecoder( /* O Returns error code */ + void *decState /* I/O State */ +) +{ + opus_int n, ret = SILK_NO_ERROR; + silk_decoder_state *channel_state = ((silk_decoder *)decState)->channel_state; + + for( n = 0; n < DECODER_NUM_CHANNELS; n++ ) { + ret = silk_init_decoder( &channel_state[ n ] ); + } + silk_memset(&((silk_decoder *)decState)->sStereo, 0, sizeof(((silk_decoder *)decState)->sStereo)); + /* Not strictly needed, but it's cleaner that way */ + ((silk_decoder *)decState)->prev_decode_only_middle = 0; + + return ret; +} + +/* Decode a frame */ +opus_int silk_Decode( /* O Returns error code */ + void* decState, /* I/O State */ + silk_DecControlStruct* decControl, /* I/O Control Structure */ + opus_int lostFlag, /* I 0: no loss, 1 loss, 2 decode fec */ + opus_int newPacketFlag, /* I Indicates first decoder call for this packet */ + ec_dec *psRangeDec, /* I/O Compressor data structure */ + opus_int16 *samplesOut, /* O Decoded output speech vector */ + opus_int32 *nSamplesOut, /* O Number of samples decoded */ + int arch /* I Run-time architecture */ +) +{ + opus_int i, n, decode_only_middle = 0, ret = SILK_NO_ERROR; + opus_int32 nSamplesOutDec, LBRR_symbol; + opus_int16 *samplesOut1_tmp[ 2 ]; + VARDECL( opus_int16, samplesOut1_tmp_storage1 ); + VARDECL( opus_int16, samplesOut1_tmp_storage2 ); + VARDECL( opus_int16, samplesOut2_tmp ); + opus_int32 MS_pred_Q13[ 2 ] = { 0 }; + opus_int16 *resample_out_ptr; + silk_decoder *psDec = ( silk_decoder * )decState; + silk_decoder_state *channel_state = psDec->channel_state; + opus_int has_side; + opus_int stereo_to_mono; + int delay_stack_alloc; + SAVE_STACK; + + celt_assert( decControl->nChannelsInternal == 1 || decControl->nChannelsInternal == 2 ); + + /**********************************/ + /* Test if first frame in payload */ + /**********************************/ + if( newPacketFlag ) { + for( n = 0; n < decControl->nChannelsInternal; n++ ) { + channel_state[ n ].nFramesDecoded = 0; /* Used to count frames in packet */ + } + } + + /* If Mono -> Stereo transition in bitstream: init state of second channel */ + if( decControl->nChannelsInternal > psDec->nChannelsInternal ) { + ret += silk_init_decoder( &channel_state[ 1 ] ); + } + + 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++ ) { + opus_int fs_kHz_dec; + if( decControl->payloadSize_ms == 0 ) { + /* Assuming packet loss, use 10 ms */ + 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 { + celt_assert( 0 ); + RESTORE_STACK; + return SILK_DEC_INVALID_FRAME_SIZE; + } + fs_kHz_dec = ( decControl->internalSampleRate >> 10 ) + 1; + if( fs_kHz_dec != 8 && fs_kHz_dec != 12 && fs_kHz_dec != 16 ) { + celt_assert( 0 ); + RESTORE_STACK; + return SILK_DEC_INVALID_SAMPLING_FREQUENCY; + } + ret += silk_decoder_set_fs( &channel_state[ n ], fs_kHz_dec, decControl->API_sampleRate ); + } + } + + if( decControl->nChannelsAPI == 2 && decControl->nChannelsInternal == 2 && ( psDec->nChannelsAPI == 1 || psDec->nChannelsInternal == 1 ) ) { + silk_memset( psDec->sStereo.pred_prev_Q13, 0, sizeof( psDec->sStereo.pred_prev_Q13 ) ); + silk_memset( psDec->sStereo.sSide, 0, sizeof( psDec->sStereo.sSide ) ); + silk_memcpy( &channel_state[ 1 ].resampler_state, &channel_state[ 0 ].resampler_state, sizeof( silk_resampler_state_struct ) ); + } + psDec->nChannelsAPI = decControl->nChannelsAPI; + psDec->nChannelsInternal = decControl->nChannelsInternal; + + if( decControl->API_sampleRate > (opus_int32)MAX_API_FS_KHZ * 1000 || decControl->API_sampleRate < 8000 ) { + ret = SILK_DEC_INVALID_SAMPLING_FREQUENCY; + RESTORE_STACK; + return( ret ); + } + + if( lostFlag != FLAG_PACKET_LOST && channel_state[ 0 ].nFramesDecoded == 0 ) { + /* First decoder call for this payload */ + /* Decode VAD flags and LBRR flag */ + for( n = 0; n < decControl->nChannelsInternal; n++ ) { + for( i = 0; i < channel_state[ n ].nFramesPerPacket; i++ ) { + channel_state[ n ].VAD_flags[ i ] = ec_dec_bit_logp(psRangeDec, 1); + } + channel_state[ n ].LBRR_flag = ec_dec_bit_logp(psRangeDec, 1); + } + /* Decode LBRR flags */ + for( n = 0; n < decControl->nChannelsInternal; n++ ) { + silk_memset( channel_state[ n ].LBRR_flags, 0, sizeof( channel_state[ n ].LBRR_flags ) ); + if( channel_state[ n ].LBRR_flag ) { + if( channel_state[ n ].nFramesPerPacket == 1 ) { + channel_state[ n ].LBRR_flags[ 0 ] = 1; + } else { + LBRR_symbol = ec_dec_icdf( psRangeDec, 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 ] = silk_RSHIFT( LBRR_symbol, i ) & 1; + } + } + } + } + + if( lostFlag == FLAG_DECODE_NORMAL ) { + /* Regular decoding: skip all LBRR data */ + for( i = 0; i < channel_state[ 0 ].nFramesPerPacket; i++ ) { + for( n = 0; n < decControl->nChannelsInternal; n++ ) { + if( channel_state[ n ].LBRR_flags[ i ] ) { + opus_int16 pulses[ MAX_FRAME_LENGTH ]; + opus_int condCoding; + + if( decControl->nChannelsInternal == 2 && n == 0 ) { + silk_stereo_decode_pred( psRangeDec, MS_pred_Q13 ); + if( channel_state[ 1 ].LBRR_flags[ i ] == 0 ) { + silk_stereo_decode_mid_only( psRangeDec, &decode_only_middle ); + } + } + /* Use conditional coding if previous frame available */ + if( i > 0 && channel_state[ n ].LBRR_flags[ i - 1 ] ) { + condCoding = CODE_CONDITIONALLY; + } else { + condCoding = CODE_INDEPENDENTLY; + } + silk_decode_indices( &channel_state[ n ], psRangeDec, i, 1, condCoding ); + silk_decode_pulses( psRangeDec, pulses, channel_state[ n ].indices.signalType, + channel_state[ n ].indices.quantOffsetType, channel_state[ n ].frame_length ); + } + } + } + } + } + + /* Get MS predictor index */ + if( decControl->nChannelsInternal == 2 ) { + if( lostFlag == FLAG_DECODE_NORMAL || + ( lostFlag == FLAG_DECODE_LBRR && channel_state[ 0 ].LBRR_flags[ channel_state[ 0 ].nFramesDecoded ] == 1 ) ) + { + silk_stereo_decode_pred( psRangeDec, MS_pred_Q13 ); + /* For LBRR data, decode mid-only flag only if side-channel's LBRR flag is false */ + if( ( lostFlag == FLAG_DECODE_NORMAL && channel_state[ 1 ].VAD_flags[ channel_state[ 0 ].nFramesDecoded ] == 0 ) || + ( lostFlag == FLAG_DECODE_LBRR && channel_state[ 1 ].LBRR_flags[ channel_state[ 0 ].nFramesDecoded ] == 0 ) ) + { + silk_stereo_decode_mid_only( psRangeDec, &decode_only_middle ); + } else { + decode_only_middle = 0; + } + } else { + for( n = 0; n < 2; n++ ) { + MS_pred_Q13[ n ] = psDec->sStereo.pred_prev_Q13[ n ]; + } + } + } + + /* Reset side channel decoder prediction memory for first frame with side coding */ + if( decControl->nChannelsInternal == 2 && decode_only_middle == 0 && psDec->prev_decode_only_middle == 1 ) { + silk_memset( psDec->channel_state[ 1 ].outBuf, 0, sizeof(psDec->channel_state[ 1 ].outBuf) ); + silk_memset( psDec->channel_state[ 1 ].sLPC_Q14_buf, 0, sizeof(psDec->channel_state[ 1 ].sLPC_Q14_buf) ); + psDec->channel_state[ 1 ].lagPrev = 100; + psDec->channel_state[ 1 ].LastGainIndex = 10; + psDec->channel_state[ 1 ].prevSignalType = TYPE_NO_VOICE_ACTIVITY; + psDec->channel_state[ 1 ].first_frame_after_reset = 1; + } + + /* Check if the temp buffer fits into the output PCM buffer. If it fits, + we can delay allocating the temp buffer until after the SILK peak stack + usage. We need to use a < and not a <= because of the two extra samples. */ + delay_stack_alloc = decControl->internalSampleRate*decControl->nChannelsInternal + < decControl->API_sampleRate*decControl->nChannelsAPI; + ALLOC( samplesOut1_tmp_storage1, delay_stack_alloc ? ALLOC_NONE + : decControl->nChannelsInternal*(channel_state[ 0 ].frame_length + 2 ), + opus_int16 ); + if ( delay_stack_alloc ) + { + samplesOut1_tmp[ 0 ] = samplesOut; + samplesOut1_tmp[ 1 ] = samplesOut + channel_state[ 0 ].frame_length + 2; + } else { + samplesOut1_tmp[ 0 ] = samplesOut1_tmp_storage1; + samplesOut1_tmp[ 1 ] = samplesOut1_tmp_storage1 + channel_state[ 0 ].frame_length + 2; + } + + if( lostFlag == FLAG_DECODE_NORMAL ) { + has_side = !decode_only_middle; + } else { + has_side = !psDec->prev_decode_only_middle + || (decControl->nChannelsInternal == 2 && lostFlag == FLAG_DECODE_LBRR && channel_state[1].LBRR_flags[ channel_state[1].nFramesDecoded ] == 1 ); + } + /* Call decoder for one frame */ + for( n = 0; n < decControl->nChannelsInternal; n++ ) { + if( n == 0 || has_side ) { + opus_int FrameIndex; + opus_int condCoding; + + FrameIndex = channel_state[ 0 ].nFramesDecoded - n; + /* Use independent coding if no previous frame available */ + if( FrameIndex <= 0 ) { + condCoding = CODE_INDEPENDENTLY; + } else if( lostFlag == FLAG_DECODE_LBRR ) { + condCoding = channel_state[ n ].LBRR_flags[ FrameIndex - 1 ] ? CODE_CONDITIONALLY : CODE_INDEPENDENTLY; + } else if( n > 0 && psDec->prev_decode_only_middle ) { + /* If we skipped a side frame in this packet, we don't + need LTP scaling; the LTP state is well-defined. */ + condCoding = CODE_INDEPENDENTLY_NO_LTP_SCALING; + } else { + condCoding = CODE_CONDITIONALLY; + } + ret += silk_decode_frame( &channel_state[ n ], psRangeDec, &samplesOut1_tmp[ n ][ 2 ], &nSamplesOutDec, lostFlag, condCoding, arch); + } else { + silk_memset( &samplesOut1_tmp[ n ][ 2 ], 0, nSamplesOutDec * sizeof( opus_int16 ) ); + } + channel_state[ n ].nFramesDecoded++; + } + + if( decControl->nChannelsAPI == 2 && decControl->nChannelsInternal == 2 ) { + /* Convert Mid/Side to Left/Right */ + silk_stereo_MS_to_LR( &psDec->sStereo, samplesOut1_tmp[ 0 ], samplesOut1_tmp[ 1 ], MS_pred_Q13, channel_state[ 0 ].fs_kHz, nSamplesOutDec ); + } else { + /* Buffering */ + silk_memcpy( samplesOut1_tmp[ 0 ], psDec->sStereo.sMid, 2 * sizeof( opus_int16 ) ); + silk_memcpy( psDec->sStereo.sMid, &samplesOut1_tmp[ 0 ][ nSamplesOutDec ], 2 * sizeof( opus_int16 ) ); + } + + /* Number of output samples */ + *nSamplesOut = silk_DIV32( nSamplesOutDec * decControl->API_sampleRate, silk_SMULBB( channel_state[ 0 ].fs_kHz, 1000 ) ); + + /* Set up pointers to temp buffers */ + ALLOC( samplesOut2_tmp, + decControl->nChannelsAPI == 2 ? *nSamplesOut : ALLOC_NONE, opus_int16 ); + if( decControl->nChannelsAPI == 2 ) { + resample_out_ptr = samplesOut2_tmp; + } else { + resample_out_ptr = samplesOut; + } + + ALLOC( samplesOut1_tmp_storage2, delay_stack_alloc + ? decControl->nChannelsInternal*(channel_state[ 0 ].frame_length + 2 ) + : ALLOC_NONE, + opus_int16 ); + if ( delay_stack_alloc ) { + OPUS_COPY(samplesOut1_tmp_storage2, samplesOut, decControl->nChannelsInternal*(channel_state[ 0 ].frame_length + 2)); + samplesOut1_tmp[ 0 ] = samplesOut1_tmp_storage2; + samplesOut1_tmp[ 1 ] = samplesOut1_tmp_storage2 + channel_state[ 0 ].frame_length + 2; + } + for( n = 0; n < silk_min( decControl->nChannelsAPI, decControl->nChannelsInternal ); n++ ) { + + /* Resample decoded signal to API_sampleRate */ + ret += silk_resampler( &channel_state[ n ].resampler_state, resample_out_ptr, &samplesOut1_tmp[ n ][ 1 ], nSamplesOutDec ); + + /* Interleave if stereo output and stereo stream */ + if( decControl->nChannelsAPI == 2 ) { + for( i = 0; i < *nSamplesOut; i++ ) { + samplesOut[ n + 2 * i ] = resample_out_ptr[ i ]; + } + } + } + + /* Create two channel output from mono stream */ + if( decControl->nChannelsAPI == 2 && decControl->nChannelsInternal == 1 ) { + if ( stereo_to_mono ){ + /* Resample right channel for newly collapsed stereo just in case + we weren't doing collapsing when switching to mono */ + ret += silk_resampler( &channel_state[ 1 ].resampler_state, resample_out_ptr, &samplesOut1_tmp[ 0 ][ 1 ], nSamplesOutDec ); + + for( i = 0; i < *nSamplesOut; i++ ) { + samplesOut[ 1 + 2 * i ] = resample_out_ptr[ i ]; + } + } else { + for( i = 0; i < *nSamplesOut; i++ ) { + samplesOut[ 1 + 2 * i ] = samplesOut[ 0 + 2 * i ]; + } + } + } + + /* Export pitch lag, measured at 48 kHz sampling rate */ + if( channel_state[ 0 ].prevSignalType == TYPE_VOICED ) { + int mult_tab[ 3 ] = { 6, 4, 3 }; + decControl->prevPitchLag = channel_state[ 0 ].lagPrev * mult_tab[ ( channel_state[ 0 ].fs_kHz - 8 ) >> 2 ]; + } else { + decControl->prevPitchLag = 0; + } + + if( lostFlag == FLAG_PACKET_LOST ) { + /* On packet loss, remove the gain clamping to prevent having the energy "bounce back" + if we lose packets when the energy is going down */ + for ( i = 0; i < psDec->nChannelsInternal; i++ ) + psDec->channel_state[ i ].LastGainIndex = 10; + } else { + psDec->prev_decode_only_middle = decode_only_middle; + } + RESTORE_STACK; + return ret; +} + +#if 0 +/* Getting table of contents for a packet */ +opus_int silk_get_TOC( + const opus_uint8 *payload, /* I Payload data */ + const opus_int nBytesIn, /* I Number of input bytes */ + const opus_int nFramesPerPayload, /* I Number of SILK frames per payload */ + silk_TOC_struct *Silk_TOC /* O Type of content */ +) +{ + opus_int i, flags, ret = SILK_NO_ERROR; + + if( nBytesIn < 1 ) { + return -1; + } + if( nFramesPerPayload < 0 || nFramesPerPayload > 3 ) { + return -1; + } + + silk_memset( Silk_TOC, 0, sizeof( *Silk_TOC ) ); + + /* For stereo, extract the flags for the mid channel */ + flags = silk_RSHIFT( payload[ 0 ], 7 - nFramesPerPayload ) & ( silk_LSHIFT( 1, nFramesPerPayload + 1 ) - 1 ); + + Silk_TOC->inbandFECFlag = flags & 1; + for( i = nFramesPerPayload - 1; i >= 0 ; i-- ) { + flags = silk_RSHIFT( flags, 1 ); + Silk_TOC->VADFlags[ i ] = flags & 1; + Silk_TOC->VADFlag |= flags & 1; + } + + return ret; +} +#endif diff --git a/extern/opus/silk/decode_core.c b/extern/opus/silk/decode_core.c new file mode 100644 index 0000000..1c352a6 --- /dev/null +++ b/extern/opus/silk/decode_core.c @@ -0,0 +1,237 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" +#include "stack_alloc.h" + +/**********************************************************/ +/* Core decoder. Performs inverse NSQ operation LTP + LPC */ +/**********************************************************/ +void silk_decode_core( + silk_decoder_state *psDec, /* I/O Decoder state */ + silk_decoder_control *psDecCtrl, /* I Decoder control */ + opus_int16 xq[], /* O Decoded speech */ + const opus_int16 pulses[ MAX_FRAME_LENGTH ], /* I Pulse signal */ + int arch /* I Run-time architecture */ +) +{ + opus_int i, k, lag = 0, start_idx, sLTP_buf_idx, NLSF_interpolation_flag, signalType; + opus_int16 *A_Q12, *B_Q14, *pxq, A_Q12_tmp[ MAX_LPC_ORDER ]; + VARDECL( opus_int16, sLTP ); + VARDECL( opus_int32, sLTP_Q15 ); + opus_int32 LTP_pred_Q13, LPC_pred_Q10, Gain_Q10, inv_gain_Q31, gain_adj_Q16, rand_seed, offset_Q10; + opus_int32 *pred_lag_ptr, *pexc_Q14, *pres_Q14; + VARDECL( opus_int32, res_Q14 ); + VARDECL( opus_int32, sLPC_Q14 ); + SAVE_STACK; + + silk_assert( psDec->prev_gain_Q16 != 0 ); + + ALLOC( sLTP, psDec->ltp_mem_length, opus_int16 ); + ALLOC( sLTP_Q15, psDec->ltp_mem_length + psDec->frame_length, opus_int32 ); + ALLOC( res_Q14, psDec->subfr_length, opus_int32 ); + ALLOC( sLPC_Q14, psDec->subfr_length + MAX_LPC_ORDER, opus_int32 ); + + offset_Q10 = silk_Quantization_Offsets_Q10[ psDec->indices.signalType >> 1 ][ psDec->indices.quantOffsetType ]; + + if( psDec->indices.NLSFInterpCoef_Q2 < 1 << 2 ) { + NLSF_interpolation_flag = 1; + } else { + NLSF_interpolation_flag = 0; + } + + /* Decode excitation */ + rand_seed = psDec->indices.Seed; + for( i = 0; i < psDec->frame_length; i++ ) { + rand_seed = silk_RAND( rand_seed ); + psDec->exc_Q14[ i ] = silk_LSHIFT( (opus_int32)pulses[ i ], 14 ); + if( psDec->exc_Q14[ i ] > 0 ) { + psDec->exc_Q14[ i ] -= QUANT_LEVEL_ADJUST_Q10 << 4; + } else + if( psDec->exc_Q14[ i ] < 0 ) { + psDec->exc_Q14[ i ] += QUANT_LEVEL_ADJUST_Q10 << 4; + } + psDec->exc_Q14[ i ] += offset_Q10 << 4; + if( rand_seed < 0 ) { + psDec->exc_Q14[ i ] = -psDec->exc_Q14[ i ]; + } + + rand_seed = silk_ADD32_ovflw( rand_seed, pulses[ i ] ); + } + + /* Copy LPC state */ + silk_memcpy( sLPC_Q14, psDec->sLPC_Q14_buf, MAX_LPC_ORDER * sizeof( opus_int32 ) ); + + pexc_Q14 = psDec->exc_Q14; + pxq = xq; + sLTP_buf_idx = psDec->ltp_mem_length; + /* Loop over subframes */ + for( k = 0; k < psDec->nb_subfr; k++ ) { + pres_Q14 = res_Q14; + A_Q12 = psDecCtrl->PredCoef_Q12[ k >> 1 ]; + + /* Preload LPC coeficients to array on stack. Gives small performance gain */ + silk_memcpy( A_Q12_tmp, A_Q12, psDec->LPC_order * sizeof( opus_int16 ) ); + B_Q14 = &psDecCtrl->LTPCoef_Q14[ k * LTP_ORDER ]; + signalType = psDec->indices.signalType; + + Gain_Q10 = silk_RSHIFT( psDecCtrl->Gains_Q16[ k ], 6 ); + inv_gain_Q31 = silk_INVERSE32_varQ( psDecCtrl->Gains_Q16[ k ], 47 ); + + /* Calculate gain adjustment factor */ + if( psDecCtrl->Gains_Q16[ k ] != psDec->prev_gain_Q16 ) { + gain_adj_Q16 = silk_DIV32_varQ( psDec->prev_gain_Q16, psDecCtrl->Gains_Q16[ k ], 16 ); + + /* Scale short term state */ + for( i = 0; i < MAX_LPC_ORDER; i++ ) { + sLPC_Q14[ i ] = silk_SMULWW( gain_adj_Q16, sLPC_Q14[ i ] ); + } + } else { + gain_adj_Q16 = (opus_int32)1 << 16; + } + + /* Save inv_gain */ + silk_assert( inv_gain_Q31 != 0 ); + psDec->prev_gain_Q16 = psDecCtrl->Gains_Q16[ k ]; + + /* Avoid abrupt transition from voiced PLC to unvoiced normal decoding */ + if( psDec->lossCnt && psDec->prevSignalType == TYPE_VOICED && + psDec->indices.signalType != TYPE_VOICED && k < MAX_NB_SUBFR/2 ) { + + silk_memset( B_Q14, 0, LTP_ORDER * sizeof( opus_int16 ) ); + B_Q14[ LTP_ORDER/2 ] = SILK_FIX_CONST( 0.25, 14 ); + + signalType = TYPE_VOICED; + psDecCtrl->pitchL[ k ] = psDec->lagPrev; + } + + if( signalType == TYPE_VOICED ) { + /* Voiced */ + lag = psDecCtrl->pitchL[ k ]; + + /* Re-whitening */ + if( k == 0 || ( k == 2 && NLSF_interpolation_flag ) ) { + /* Rewhiten with new A coefs */ + start_idx = psDec->ltp_mem_length - lag - psDec->LPC_order - LTP_ORDER / 2; + celt_assert( start_idx > 0 ); + + if( k == 2 ) { + silk_memcpy( &psDec->outBuf[ psDec->ltp_mem_length ], xq, 2 * psDec->subfr_length * sizeof( opus_int16 ) ); + } + + silk_LPC_analysis_filter( &sLTP[ start_idx ], &psDec->outBuf[ start_idx + k * psDec->subfr_length ], + A_Q12, psDec->ltp_mem_length - start_idx, psDec->LPC_order, arch ); + + /* After rewhitening the LTP state is unscaled */ + if( k == 0 ) { + /* Do LTP downscaling to reduce inter-packet dependency */ + inv_gain_Q31 = silk_LSHIFT( silk_SMULWB( inv_gain_Q31, psDecCtrl->LTP_scale_Q14 ), 2 ); + } + for( i = 0; i < lag + LTP_ORDER/2; i++ ) { + sLTP_Q15[ sLTP_buf_idx - i - 1 ] = silk_SMULWB( inv_gain_Q31, sLTP[ psDec->ltp_mem_length - i - 1 ] ); + } + } else { + /* Update LTP state when Gain changes */ + if( gain_adj_Q16 != (opus_int32)1 << 16 ) { + for( i = 0; i < lag + LTP_ORDER/2; i++ ) { + sLTP_Q15[ sLTP_buf_idx - i - 1 ] = silk_SMULWW( gain_adj_Q16, sLTP_Q15[ sLTP_buf_idx - i - 1 ] ); + } + } + } + } + + /* Long-term prediction */ + if( signalType == TYPE_VOICED ) { + /* Set up pointer */ + pred_lag_ptr = &sLTP_Q15[ sLTP_buf_idx - lag + LTP_ORDER / 2 ]; + for( i = 0; i < psDec->subfr_length; i++ ) { + /* Unrolled loop */ + /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */ + LTP_pred_Q13 = 2; + LTP_pred_Q13 = silk_SMLAWB( LTP_pred_Q13, pred_lag_ptr[ 0 ], B_Q14[ 0 ] ); + LTP_pred_Q13 = silk_SMLAWB( LTP_pred_Q13, pred_lag_ptr[ -1 ], B_Q14[ 1 ] ); + LTP_pred_Q13 = silk_SMLAWB( LTP_pred_Q13, pred_lag_ptr[ -2 ], B_Q14[ 2 ] ); + LTP_pred_Q13 = silk_SMLAWB( LTP_pred_Q13, pred_lag_ptr[ -3 ], B_Q14[ 3 ] ); + LTP_pred_Q13 = silk_SMLAWB( LTP_pred_Q13, pred_lag_ptr[ -4 ], B_Q14[ 4 ] ); + pred_lag_ptr++; + + /* Generate LPC excitation */ + pres_Q14[ i ] = silk_ADD_LSHIFT32( pexc_Q14[ i ], LTP_pred_Q13, 1 ); + + /* Update states */ + sLTP_Q15[ sLTP_buf_idx ] = silk_LSHIFT( pres_Q14[ i ], 1 ); + sLTP_buf_idx++; + } + } else { + pres_Q14 = pexc_Q14; + } + + for( i = 0; i < psDec->subfr_length; i++ ) { + /* Short-term prediction */ + celt_assert( psDec->LPC_order == 10 || psDec->LPC_order == 16 ); + /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */ + LPC_pred_Q10 = silk_RSHIFT( psDec->LPC_order, 1 ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 1 ], A_Q12_tmp[ 0 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 2 ], A_Q12_tmp[ 1 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 3 ], A_Q12_tmp[ 2 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 4 ], A_Q12_tmp[ 3 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 5 ], A_Q12_tmp[ 4 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 6 ], A_Q12_tmp[ 5 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 7 ], A_Q12_tmp[ 6 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 8 ], A_Q12_tmp[ 7 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 9 ], A_Q12_tmp[ 8 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 10 ], A_Q12_tmp[ 9 ] ); + if( psDec->LPC_order == 16 ) { + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 11 ], A_Q12_tmp[ 10 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 12 ], A_Q12_tmp[ 11 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 13 ], A_Q12_tmp[ 12 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 14 ], A_Q12_tmp[ 13 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 15 ], A_Q12_tmp[ 14 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 16 ], A_Q12_tmp[ 15 ] ); + } + + /* Add prediction to LPC excitation */ + sLPC_Q14[ MAX_LPC_ORDER + i ] = silk_ADD_SAT32( pres_Q14[ i ], silk_LSHIFT_SAT32( LPC_pred_Q10, 4 ) ); + + /* Scale with gain */ + pxq[ i ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( silk_SMULWW( sLPC_Q14[ MAX_LPC_ORDER + i ], Gain_Q10 ), 8 ) ); + } + + /* Update LPC filter state */ + silk_memcpy( sLPC_Q14, &sLPC_Q14[ psDec->subfr_length ], MAX_LPC_ORDER * sizeof( opus_int32 ) ); + pexc_Q14 += psDec->subfr_length; + pxq += psDec->subfr_length; + } + + /* Save LPC state */ + silk_memcpy( psDec->sLPC_Q14_buf, sLPC_Q14, MAX_LPC_ORDER * sizeof( opus_int32 ) ); + RESTORE_STACK; +} diff --git a/extern/opus/silk/decode_frame.c b/extern/opus/silk/decode_frame.c new file mode 100644 index 0000000..e73825b --- /dev/null +++ b/extern/opus/silk/decode_frame.c @@ -0,0 +1,130 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" +#include "stack_alloc.h" +#include "PLC.h" + +/****************/ +/* Decode frame */ +/****************/ +opus_int silk_decode_frame( + silk_decoder_state *psDec, /* I/O Pointer to Silk decoder state */ + ec_dec *psRangeDec, /* I/O Compressor data structure */ + opus_int16 pOut[], /* O Pointer to output speech frame */ + opus_int32 *pN, /* O Pointer to size of output frame */ + opus_int lostFlag, /* I 0: no loss, 1 loss, 2 decode fec */ + opus_int condCoding, /* I The type of conditional coding to use */ + int arch /* I Run-time architecture */ +) +{ + VARDECL( silk_decoder_control, psDecCtrl ); + opus_int L, mv_len, ret = 0; + SAVE_STACK; + + L = psDec->frame_length; + ALLOC( psDecCtrl, 1, silk_decoder_control ); + psDecCtrl->LTP_scale_Q14 = 0; + + /* Safety checks */ + celt_assert( L > 0 && L <= MAX_FRAME_LENGTH ); + + if( lostFlag == FLAG_DECODE_NORMAL || + ( lostFlag == FLAG_DECODE_LBRR && psDec->LBRR_flags[ psDec->nFramesDecoded ] == 1 ) ) + { + VARDECL( opus_int16, pulses ); + ALLOC( pulses, (L + SHELL_CODEC_FRAME_LENGTH - 1) & + ~(SHELL_CODEC_FRAME_LENGTH - 1), opus_int16 ); + /*********************************************/ + /* Decode quantization indices of side info */ + /*********************************************/ + silk_decode_indices( psDec, psRangeDec, psDec->nFramesDecoded, lostFlag, condCoding ); + + /*********************************************/ + /* Decode quantization indices of excitation */ + /*********************************************/ + silk_decode_pulses( psRangeDec, pulses, psDec->indices.signalType, + psDec->indices.quantOffsetType, psDec->frame_length ); + + /********************************************/ + /* Decode parameters and pulse signal */ + /********************************************/ + silk_decode_parameters( psDec, psDecCtrl, condCoding ); + + /********************************************************/ + /* Run inverse NSQ */ + /********************************************************/ + silk_decode_core( psDec, psDecCtrl, pOut, pulses, arch ); + + /********************************************************/ + /* Update PLC state */ + /********************************************************/ + silk_PLC( psDec, psDecCtrl, pOut, 0, arch ); + + psDec->lossCnt = 0; + psDec->prevSignalType = psDec->indices.signalType; + celt_assert( psDec->prevSignalType >= 0 && psDec->prevSignalType <= 2 ); + + /* A frame has been decoded without errors */ + psDec->first_frame_after_reset = 0; + } else { + /* Handle packet loss by extrapolation */ + psDec->indices.signalType = psDec->prevSignalType; + silk_PLC( psDec, psDecCtrl, pOut, 1, arch ); + } + + /*************************/ + /* Update output buffer. */ + /*************************/ + celt_assert( psDec->ltp_mem_length >= psDec->frame_length ); + mv_len = psDec->ltp_mem_length - psDec->frame_length; + silk_memmove( psDec->outBuf, &psDec->outBuf[ psDec->frame_length ], mv_len * sizeof(opus_int16) ); + silk_memcpy( &psDec->outBuf[ mv_len ], pOut, psDec->frame_length * sizeof( opus_int16 ) ); + + /************************************************/ + /* Comfort noise generation / estimation */ + /************************************************/ + silk_CNG( psDec, psDecCtrl, pOut, L ); + + /****************************************************************/ + /* Ensure smooth connection of extrapolated and good frames */ + /****************************************************************/ + silk_PLC_glue_frames( psDec, pOut, L ); + + /* Update some decoder state variables */ + psDec->lagPrev = psDecCtrl->pitchL[ psDec->nb_subfr - 1 ]; + + /* Set output frame length */ + *pN = L; + + RESTORE_STACK; + return ret; +} diff --git a/extern/opus/silk/decode_indices.c b/extern/opus/silk/decode_indices.c new file mode 100644 index 0000000..0bb4a99 --- /dev/null +++ b/extern/opus/silk/decode_indices.c @@ -0,0 +1,151 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/* Decode side-information parameters from payload */ +void silk_decode_indices( + silk_decoder_state *psDec, /* I/O State */ + ec_dec *psRangeDec, /* I/O Compressor data structure */ + opus_int FrameIndex, /* I Frame number */ + opus_int decode_LBRR, /* I Flag indicating LBRR data is being decoded */ + opus_int condCoding /* I The type of conditional coding to use */ +) +{ + opus_int i, k, Ix; + opus_int decode_absolute_lagIndex, delta_lagIndex; + opus_int16 ec_ix[ MAX_LPC_ORDER ]; + opus_uint8 pred_Q8[ MAX_LPC_ORDER ]; + + /*******************************************/ + /* Decode signal type and quantizer offset */ + /*******************************************/ + if( decode_LBRR || psDec->VAD_flags[ FrameIndex ] ) { + Ix = ec_dec_icdf( psRangeDec, silk_type_offset_VAD_iCDF, 8 ) + 2; + } else { + Ix = ec_dec_icdf( psRangeDec, silk_type_offset_no_VAD_iCDF, 8 ); + } + psDec->indices.signalType = (opus_int8)silk_RSHIFT( Ix, 1 ); + psDec->indices.quantOffsetType = (opus_int8)( Ix & 1 ); + + /****************/ + /* Decode gains */ + /****************/ + /* First subframe */ + if( condCoding == CODE_CONDITIONALLY ) { + /* Conditional coding */ + psDec->indices.GainsIndices[ 0 ] = (opus_int8)ec_dec_icdf( psRangeDec, silk_delta_gain_iCDF, 8 ); + } else { + /* Independent coding, in two stages: MSB bits followed by 3 LSBs */ + psDec->indices.GainsIndices[ 0 ] = (opus_int8)silk_LSHIFT( ec_dec_icdf( psRangeDec, silk_gain_iCDF[ psDec->indices.signalType ], 8 ), 3 ); + psDec->indices.GainsIndices[ 0 ] += (opus_int8)ec_dec_icdf( psRangeDec, silk_uniform8_iCDF, 8 ); + } + + /* Remaining subframes */ + for( i = 1; i < psDec->nb_subfr; i++ ) { + psDec->indices.GainsIndices[ i ] = (opus_int8)ec_dec_icdf( psRangeDec, silk_delta_gain_iCDF, 8 ); + } + + /**********************/ + /* Decode LSF Indices */ + /**********************/ + psDec->indices.NLSFIndices[ 0 ] = (opus_int8)ec_dec_icdf( psRangeDec, &psDec->psNLSF_CB->CB1_iCDF[ ( psDec->indices.signalType >> 1 ) * psDec->psNLSF_CB->nVectors ], 8 ); + silk_NLSF_unpack( ec_ix, pred_Q8, psDec->psNLSF_CB, psDec->indices.NLSFIndices[ 0 ] ); + celt_assert( psDec->psNLSF_CB->order == psDec->LPC_order ); + for( i = 0; i < psDec->psNLSF_CB->order; i++ ) { + Ix = ec_dec_icdf( psRangeDec, &psDec->psNLSF_CB->ec_iCDF[ ec_ix[ i ] ], 8 ); + if( Ix == 0 ) { + Ix -= ec_dec_icdf( psRangeDec, silk_NLSF_EXT_iCDF, 8 ); + } else if( Ix == 2 * NLSF_QUANT_MAX_AMPLITUDE ) { + Ix += ec_dec_icdf( psRangeDec, silk_NLSF_EXT_iCDF, 8 ); + } + psDec->indices.NLSFIndices[ i+1 ] = (opus_int8)( Ix - NLSF_QUANT_MAX_AMPLITUDE ); + } + + /* Decode LSF interpolation factor */ + if( psDec->nb_subfr == MAX_NB_SUBFR ) { + psDec->indices.NLSFInterpCoef_Q2 = (opus_int8)ec_dec_icdf( psRangeDec, silk_NLSF_interpolation_factor_iCDF, 8 ); + } else { + psDec->indices.NLSFInterpCoef_Q2 = 4; + } + + if( psDec->indices.signalType == TYPE_VOICED ) + { + /*********************/ + /* Decode pitch lags */ + /*********************/ + /* Get lag index */ + decode_absolute_lagIndex = 1; + if( condCoding == CODE_CONDITIONALLY && psDec->ec_prevSignalType == TYPE_VOICED ) { + /* Decode Delta index */ + delta_lagIndex = (opus_int16)ec_dec_icdf( psRangeDec, silk_pitch_delta_iCDF, 8 ); + if( delta_lagIndex > 0 ) { + delta_lagIndex = delta_lagIndex - 9; + psDec->indices.lagIndex = (opus_int16)( psDec->ec_prevLagIndex + delta_lagIndex ); + decode_absolute_lagIndex = 0; + } + } + if( decode_absolute_lagIndex ) { + /* Absolute decoding */ + psDec->indices.lagIndex = (opus_int16)ec_dec_icdf( psRangeDec, silk_pitch_lag_iCDF, 8 ) * silk_RSHIFT( psDec->fs_kHz, 1 ); + psDec->indices.lagIndex += (opus_int16)ec_dec_icdf( psRangeDec, psDec->pitch_lag_low_bits_iCDF, 8 ); + } + psDec->ec_prevLagIndex = psDec->indices.lagIndex; + + /* Get countour index */ + psDec->indices.contourIndex = (opus_int8)ec_dec_icdf( psRangeDec, psDec->pitch_contour_iCDF, 8 ); + + /********************/ + /* Decode LTP gains */ + /********************/ + /* Decode PERIndex value */ + psDec->indices.PERIndex = (opus_int8)ec_dec_icdf( psRangeDec, silk_LTP_per_index_iCDF, 8 ); + + for( k = 0; k < psDec->nb_subfr; k++ ) { + psDec->indices.LTPIndex[ k ] = (opus_int8)ec_dec_icdf( psRangeDec, silk_LTP_gain_iCDF_ptrs[ psDec->indices.PERIndex ], 8 ); + } + + /**********************/ + /* Decode LTP scaling */ + /**********************/ + if( condCoding == CODE_INDEPENDENTLY ) { + psDec->indices.LTP_scaleIndex = (opus_int8)ec_dec_icdf( psRangeDec, silk_LTPscale_iCDF, 8 ); + } else { + psDec->indices.LTP_scaleIndex = 0; + } + } + psDec->ec_prevSignalType = psDec->indices.signalType; + + /***************/ + /* Decode seed */ + /***************/ + psDec->indices.Seed = (opus_int8)ec_dec_icdf( psRangeDec, silk_uniform4_iCDF, 8 ); +} diff --git a/extern/opus/silk/decode_parameters.c b/extern/opus/silk/decode_parameters.c new file mode 100644 index 0000000..a56a409 --- /dev/null +++ b/extern/opus/silk/decode_parameters.c @@ -0,0 +1,115 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/* Decode parameters from payload */ +void silk_decode_parameters( + silk_decoder_state *psDec, /* I/O State */ + silk_decoder_control *psDecCtrl, /* I/O Decoder control */ + opus_int condCoding /* I The type of conditional coding to use */ +) +{ + opus_int i, k, Ix; + opus_int16 pNLSF_Q15[ MAX_LPC_ORDER ], pNLSF0_Q15[ MAX_LPC_ORDER ]; + const opus_int8 *cbk_ptr_Q7; + + /* Dequant Gains */ + silk_gains_dequant( psDecCtrl->Gains_Q16, psDec->indices.GainsIndices, + &psDec->LastGainIndex, condCoding == CODE_CONDITIONALLY, psDec->nb_subfr ); + + /****************/ + /* Decode NLSFs */ + /****************/ + silk_NLSF_decode( pNLSF_Q15, psDec->indices.NLSFIndices, psDec->psNLSF_CB ); + + /* Convert NLSF parameters to AR prediction filter coefficients */ + silk_NLSF2A( psDecCtrl->PredCoef_Q12[ 1 ], pNLSF_Q15, psDec->LPC_order, psDec->arch ); + + /* If just reset, e.g., because internal Fs changed, do not allow interpolation */ + /* improves the case of packet loss in the first frame after a switch */ + if( psDec->first_frame_after_reset == 1 ) { + psDec->indices.NLSFInterpCoef_Q2 = 4; + } + + if( psDec->indices.NLSFInterpCoef_Q2 < 4 ) { + /* Calculation of the interpolated NLSF0 vector from the interpolation factor, */ + /* the previous NLSF1, and the current NLSF1 */ + for( i = 0; i < psDec->LPC_order; i++ ) { + pNLSF0_Q15[ i ] = psDec->prevNLSF_Q15[ i ] + silk_RSHIFT( silk_MUL( psDec->indices.NLSFInterpCoef_Q2, + pNLSF_Q15[ i ] - psDec->prevNLSF_Q15[ i ] ), 2 ); + } + + /* Convert NLSF parameters to AR prediction filter coefficients */ + silk_NLSF2A( psDecCtrl->PredCoef_Q12[ 0 ], pNLSF0_Q15, psDec->LPC_order, psDec->arch ); + } else { + /* Copy LPC coefficients for first half from second half */ + silk_memcpy( psDecCtrl->PredCoef_Q12[ 0 ], psDecCtrl->PredCoef_Q12[ 1 ], psDec->LPC_order * sizeof( opus_int16 ) ); + } + + silk_memcpy( psDec->prevNLSF_Q15, pNLSF_Q15, psDec->LPC_order * sizeof( opus_int16 ) ); + + /* After a packet loss do BWE of LPC coefs */ + if( psDec->lossCnt ) { + silk_bwexpander( psDecCtrl->PredCoef_Q12[ 0 ], psDec->LPC_order, BWE_AFTER_LOSS_Q16 ); + silk_bwexpander( psDecCtrl->PredCoef_Q12[ 1 ], psDec->LPC_order, BWE_AFTER_LOSS_Q16 ); + } + + if( psDec->indices.signalType == TYPE_VOICED ) { + /*********************/ + /* Decode pitch lags */ + /*********************/ + + /* Decode pitch values */ + silk_decode_pitch( psDec->indices.lagIndex, psDec->indices.contourIndex, psDecCtrl->pitchL, psDec->fs_kHz, psDec->nb_subfr ); + + /* Decode Codebook Index */ + cbk_ptr_Q7 = silk_LTP_vq_ptrs_Q7[ psDec->indices.PERIndex ]; /* set pointer to start of codebook */ + + for( k = 0; k < psDec->nb_subfr; k++ ) { + Ix = psDec->indices.LTPIndex[ k ]; + for( i = 0; i < LTP_ORDER; i++ ) { + psDecCtrl->LTPCoef_Q14[ k * LTP_ORDER + i ] = silk_LSHIFT( cbk_ptr_Q7[ Ix * LTP_ORDER + i ], 7 ); + } + } + + /**********************/ + /* Decode LTP scaling */ + /**********************/ + Ix = psDec->indices.LTP_scaleIndex; + psDecCtrl->LTP_scale_Q14 = silk_LTPScales_table_Q14[ Ix ]; + } else { + silk_memset( psDecCtrl->pitchL, 0, psDec->nb_subfr * sizeof( opus_int ) ); + silk_memset( psDecCtrl->LTPCoef_Q14, 0, LTP_ORDER * psDec->nb_subfr * sizeof( opus_int16 ) ); + psDec->indices.PERIndex = 0; + psDecCtrl->LTP_scale_Q14 = 0; + } +} diff --git a/extern/opus/silk/decode_pitch.c b/extern/opus/silk/decode_pitch.c new file mode 100644 index 0000000..fd1b6bf --- /dev/null +++ b/extern/opus/silk/decode_pitch.c @@ -0,0 +1,77 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/*********************************************************** +* Pitch analyser function +********************************************************** */ +#include "SigProc_FIX.h" +#include "pitch_est_defines.h" + +void silk_decode_pitch( + opus_int16 lagIndex, /* I */ + opus_int8 contourIndex, /* O */ + opus_int pitch_lags[], /* O 4 pitch values */ + const opus_int Fs_kHz, /* I sampling frequency (kHz) */ + const opus_int nb_subfr /* I number of sub frames */ +) +{ + opus_int lag, k, min_lag, max_lag, cbk_size; + const opus_int8 *Lag_CB_ptr; + + if( Fs_kHz == 8 ) { + if( nb_subfr == PE_MAX_NB_SUBFR ) { + Lag_CB_ptr = &silk_CB_lags_stage2[ 0 ][ 0 ]; + cbk_size = PE_NB_CBKS_STAGE2_EXT; + } else { + celt_assert( nb_subfr == PE_MAX_NB_SUBFR >> 1 ); + Lag_CB_ptr = &silk_CB_lags_stage2_10_ms[ 0 ][ 0 ]; + cbk_size = PE_NB_CBKS_STAGE2_10MS; + } + } else { + if( nb_subfr == PE_MAX_NB_SUBFR ) { + Lag_CB_ptr = &silk_CB_lags_stage3[ 0 ][ 0 ]; + cbk_size = PE_NB_CBKS_STAGE3_MAX; + } else { + celt_assert( nb_subfr == PE_MAX_NB_SUBFR >> 1 ); + Lag_CB_ptr = &silk_CB_lags_stage3_10_ms[ 0 ][ 0 ]; + cbk_size = PE_NB_CBKS_STAGE3_10MS; + } + } + + min_lag = silk_SMULBB( PE_MIN_LAG_MS, Fs_kHz ); + max_lag = silk_SMULBB( PE_MAX_LAG_MS, Fs_kHz ); + lag = min_lag + lagIndex; + + for( k = 0; k < nb_subfr; k++ ) { + pitch_lags[ k ] = lag + matrix_ptr( Lag_CB_ptr, k, contourIndex, cbk_size ); + pitch_lags[ k ] = silk_LIMIT( pitch_lags[ k ], min_lag, max_lag ); + } +} diff --git a/extern/opus/silk/decode_pulses.c b/extern/opus/silk/decode_pulses.c new file mode 100644 index 0000000..a56d2d3 --- /dev/null +++ b/extern/opus/silk/decode_pulses.c @@ -0,0 +1,115 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/*********************************************/ +/* Decode quantization indices of excitation */ +/*********************************************/ +void silk_decode_pulses( + ec_dec *psRangeDec, /* I/O Compressor data structure */ + opus_int16 pulses[], /* O Excitation signal */ + const opus_int signalType, /* I Sigtype */ + const opus_int quantOffsetType, /* I quantOffsetType */ + const opus_int frame_length /* I Frame length */ +) +{ + opus_int i, j, k, iter, abs_q, nLS, RateLevelIndex; + opus_int sum_pulses[ MAX_NB_SHELL_BLOCKS ], nLshifts[ MAX_NB_SHELL_BLOCKS ]; + opus_int16 *pulses_ptr; + const opus_uint8 *cdf_ptr; + + /*********************/ + /* Decode rate level */ + /*********************/ + RateLevelIndex = ec_dec_icdf( psRangeDec, silk_rate_levels_iCDF[ signalType >> 1 ], 8 ); + + /* Calculate number of shell blocks */ + silk_assert( 1 << LOG2_SHELL_CODEC_FRAME_LENGTH == SHELL_CODEC_FRAME_LENGTH ); + iter = silk_RSHIFT( frame_length, LOG2_SHELL_CODEC_FRAME_LENGTH ); + if( iter * SHELL_CODEC_FRAME_LENGTH < frame_length ) { + celt_assert( frame_length == 12 * 10 ); /* Make sure only happens for 10 ms @ 12 kHz */ + iter++; + } + + /***************************************************/ + /* Sum-Weighted-Pulses Decoding */ + /***************************************************/ + cdf_ptr = silk_pulses_per_block_iCDF[ RateLevelIndex ]; + for( i = 0; i < iter; i++ ) { + nLshifts[ i ] = 0; + sum_pulses[ i ] = ec_dec_icdf( psRangeDec, cdf_ptr, 8 ); + + /* LSB indication */ + while( sum_pulses[ i ] == SILK_MAX_PULSES + 1 ) { + nLshifts[ i ]++; + /* When we've already got 10 LSBs, we shift the table to not allow (SILK_MAX_PULSES + 1) */ + sum_pulses[ i ] = ec_dec_icdf( psRangeDec, + silk_pulses_per_block_iCDF[ N_RATE_LEVELS - 1] + ( nLshifts[ i ] == 10 ), 8 ); + } + } + + /***************************************************/ + /* Shell decoding */ + /***************************************************/ + for( i = 0; i < iter; i++ ) { + if( sum_pulses[ i ] > 0 ) { + silk_shell_decoder( &pulses[ silk_SMULBB( i, SHELL_CODEC_FRAME_LENGTH ) ], psRangeDec, sum_pulses[ i ] ); + } else { + silk_memset( &pulses[ silk_SMULBB( i, SHELL_CODEC_FRAME_LENGTH ) ], 0, SHELL_CODEC_FRAME_LENGTH * sizeof( pulses[0] ) ); + } + } + + /***************************************************/ + /* LSB Decoding */ + /***************************************************/ + for( i = 0; i < iter; i++ ) { + if( nLshifts[ i ] > 0 ) { + nLS = nLshifts[ i ]; + pulses_ptr = &pulses[ silk_SMULBB( i, SHELL_CODEC_FRAME_LENGTH ) ]; + for( k = 0; k < SHELL_CODEC_FRAME_LENGTH; k++ ) { + abs_q = pulses_ptr[ k ]; + for( j = 0; j < nLS; j++ ) { + abs_q = silk_LSHIFT( abs_q, 1 ); + abs_q += ec_dec_icdf( psRangeDec, silk_lsb_iCDF, 8 ); + } + pulses_ptr[ k ] = abs_q; + } + /* Mark the number of pulses non-zero for sign decoding. */ + sum_pulses[ i ] |= nLS << 5; + } + } + + /****************************************/ + /* Decode and add signs to pulse signal */ + /****************************************/ + silk_decode_signs( psRangeDec, pulses, frame_length, signalType, quantOffsetType, sum_pulses ); +} diff --git a/extern/opus/silk/decoder_set_fs.c b/extern/opus/silk/decoder_set_fs.c new file mode 100644 index 0000000..d9a13d0 --- /dev/null +++ b/extern/opus/silk/decoder_set_fs.c @@ -0,0 +1,108 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/* Set decoder sampling rate */ +opus_int silk_decoder_set_fs( + silk_decoder_state *psDec, /* I/O Decoder state pointer */ + opus_int fs_kHz, /* I Sampling frequency (kHz) */ + opus_int32 fs_API_Hz /* I API Sampling frequency (Hz) */ +) +{ + opus_int frame_length, ret = 0; + + celt_assert( fs_kHz == 8 || fs_kHz == 12 || fs_kHz == 16 ); + celt_assert( psDec->nb_subfr == MAX_NB_SUBFR || psDec->nb_subfr == MAX_NB_SUBFR/2 ); + + /* New (sub)frame length */ + psDec->subfr_length = silk_SMULBB( SUB_FRAME_LENGTH_MS, fs_kHz ); + frame_length = silk_SMULBB( psDec->nb_subfr, psDec->subfr_length ); + + /* Initialize resampler when switching internal or external sampling frequency */ + if( psDec->fs_kHz != fs_kHz || psDec->fs_API_hz != fs_API_Hz ) { + /* Initialize the resampler for dec_API.c preparing resampling from fs_kHz to API_fs_Hz */ + ret += silk_resampler_init( &psDec->resampler_state, silk_SMULBB( fs_kHz, 1000 ), fs_API_Hz, 0 ); + + psDec->fs_API_hz = fs_API_Hz; + } + + if( psDec->fs_kHz != fs_kHz || frame_length != psDec->frame_length ) { + if( fs_kHz == 8 ) { + if( psDec->nb_subfr == MAX_NB_SUBFR ) { + psDec->pitch_contour_iCDF = silk_pitch_contour_NB_iCDF; + } else { + psDec->pitch_contour_iCDF = silk_pitch_contour_10_ms_NB_iCDF; + } + } else { + if( psDec->nb_subfr == MAX_NB_SUBFR ) { + psDec->pitch_contour_iCDF = silk_pitch_contour_iCDF; + } else { + psDec->pitch_contour_iCDF = silk_pitch_contour_10_ms_iCDF; + } + } + if( psDec->fs_kHz != fs_kHz ) { + psDec->ltp_mem_length = silk_SMULBB( LTP_MEM_LENGTH_MS, fs_kHz ); + if( fs_kHz == 8 || fs_kHz == 12 ) { + psDec->LPC_order = MIN_LPC_ORDER; + psDec->psNLSF_CB = &silk_NLSF_CB_NB_MB; + } else { + psDec->LPC_order = MAX_LPC_ORDER; + psDec->psNLSF_CB = &silk_NLSF_CB_WB; + } + if( fs_kHz == 16 ) { + psDec->pitch_lag_low_bits_iCDF = silk_uniform8_iCDF; + } else if( fs_kHz == 12 ) { + psDec->pitch_lag_low_bits_iCDF = silk_uniform6_iCDF; + } else if( fs_kHz == 8 ) { + psDec->pitch_lag_low_bits_iCDF = silk_uniform4_iCDF; + } else { + /* unsupported sampling rate */ + celt_assert( 0 ); + } + psDec->first_frame_after_reset = 1; + psDec->lagPrev = 100; + psDec->LastGainIndex = 10; + psDec->prevSignalType = TYPE_NO_VOICE_ACTIVITY; + silk_memset( psDec->outBuf, 0, sizeof(psDec->outBuf)); + silk_memset( psDec->sLPC_Q14_buf, 0, sizeof(psDec->sLPC_Q14_buf) ); + } + + psDec->fs_kHz = fs_kHz; + psDec->frame_length = frame_length; + } + + /* Check that settings are valid */ + celt_assert( psDec->frame_length > 0 && psDec->frame_length <= MAX_FRAME_LENGTH ); + + return ret; +} + diff --git a/extern/opus/silk/define.h b/extern/opus/silk/define.h new file mode 100644 index 0000000..247cb0b --- /dev/null +++ b/extern/opus/silk/define.h @@ -0,0 +1,234 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifndef SILK_DEFINE_H +#define SILK_DEFINE_H + +#include "errors.h" +#include "typedef.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* Max number of encoder channels (1/2) */ +#define ENCODER_NUM_CHANNELS 2 +/* Number of decoder channels (1/2) */ +#define DECODER_NUM_CHANNELS 2 + +#define MAX_FRAMES_PER_PACKET 3 + +/* Limits on bitrate */ +#define MIN_TARGET_RATE_BPS 5000 +#define MAX_TARGET_RATE_BPS 80000 + +/* LBRR thresholds */ +#define LBRR_NB_MIN_RATE_BPS 12000 +#define LBRR_MB_MIN_RATE_BPS 14000 +#define LBRR_WB_MIN_RATE_BPS 16000 + +/* DTX settings */ +#define NB_SPEECH_FRAMES_BEFORE_DTX 10 /* eq 200 ms */ +#define MAX_CONSECUTIVE_DTX 20 /* eq 400 ms */ +#define DTX_ACTIVITY_THRESHOLD 0.1f + +/* VAD decision */ +#define VAD_NO_DECISION -1 +#define VAD_NO_ACTIVITY 0 +#define VAD_ACTIVITY 1 + +/* Maximum sampling frequency */ +#define MAX_FS_KHZ 16 +#define MAX_API_FS_KHZ 48 + +/* Signal types */ +#define TYPE_NO_VOICE_ACTIVITY 0 +#define TYPE_UNVOICED 1 +#define TYPE_VOICED 2 + +/* Conditional coding types */ +#define CODE_INDEPENDENTLY 0 +#define CODE_INDEPENDENTLY_NO_LTP_SCALING 1 +#define CODE_CONDITIONALLY 2 + +/* Settings for stereo processing */ +#define STEREO_QUANT_TAB_SIZE 16 +#define STEREO_QUANT_SUB_STEPS 5 +#define STEREO_INTERP_LEN_MS 8 /* must be even */ +#define STEREO_RATIO_SMOOTH_COEF 0.01 /* smoothing coef for signal norms and stereo width */ + +/* Range of pitch lag estimates */ +#define PITCH_EST_MIN_LAG_MS 2 /* 2 ms -> 500 Hz */ +#define PITCH_EST_MAX_LAG_MS 18 /* 18 ms -> 56 Hz */ + +/* Maximum number of subframes */ +#define MAX_NB_SUBFR 4 + +/* Number of samples per frame */ +#define LTP_MEM_LENGTH_MS 20 +#define SUB_FRAME_LENGTH_MS 5 +#define MAX_SUB_FRAME_LENGTH ( SUB_FRAME_LENGTH_MS * MAX_FS_KHZ ) +#define MAX_FRAME_LENGTH_MS ( SUB_FRAME_LENGTH_MS * MAX_NB_SUBFR ) +#define MAX_FRAME_LENGTH ( MAX_FRAME_LENGTH_MS * MAX_FS_KHZ ) + +/* Milliseconds of lookahead for pitch analysis */ +#define LA_PITCH_MS 2 +#define LA_PITCH_MAX ( LA_PITCH_MS * MAX_FS_KHZ ) + +/* Order of LPC used in find pitch */ +#define MAX_FIND_PITCH_LPC_ORDER 16 + +/* Length of LPC window used in find pitch */ +#define FIND_PITCH_LPC_WIN_MS ( 20 + (LA_PITCH_MS << 1) ) +#define FIND_PITCH_LPC_WIN_MS_2_SF ( 10 + (LA_PITCH_MS << 1) ) +#define FIND_PITCH_LPC_WIN_MAX ( FIND_PITCH_LPC_WIN_MS * MAX_FS_KHZ ) + +/* Milliseconds of lookahead for noise shape analysis */ +#define LA_SHAPE_MS 5 +#define LA_SHAPE_MAX ( LA_SHAPE_MS * MAX_FS_KHZ ) + +/* Maximum length of LPC window used in noise shape analysis */ +#define SHAPE_LPC_WIN_MAX ( 15 * MAX_FS_KHZ ) + +/* dB level of lowest gain quantization level */ +#define MIN_QGAIN_DB 2 +/* dB level of highest gain quantization level */ +#define MAX_QGAIN_DB 88 +/* Number of gain quantization levels */ +#define N_LEVELS_QGAIN 64 +/* Max increase in gain quantization index */ +#define MAX_DELTA_GAIN_QUANT 36 +/* Max decrease in gain quantization index */ +#define MIN_DELTA_GAIN_QUANT -4 + +/* Quantization offsets (multiples of 4) */ +#define OFFSET_VL_Q10 32 +#define OFFSET_VH_Q10 100 +#define OFFSET_UVL_Q10 100 +#define OFFSET_UVH_Q10 240 + +#define QUANT_LEVEL_ADJUST_Q10 80 + +/* Maximum numbers of iterations used to stabilize an LPC vector */ +#define MAX_LPC_STABILIZE_ITERATIONS 16 +#define MAX_PREDICTION_POWER_GAIN 1e4f +#define MAX_PREDICTION_POWER_GAIN_AFTER_RESET 1e2f + +#define MAX_LPC_ORDER 16 +#define MIN_LPC_ORDER 10 + +/* Find Pred Coef defines */ +#define LTP_ORDER 5 + +/* LTP quantization settings */ +#define NB_LTP_CBKS 3 + +/* Flag to use harmonic noise shaping */ +#define USE_HARM_SHAPING 1 + +/* Max LPC order of noise shaping filters */ +#define MAX_SHAPE_LPC_ORDER 24 + +#define HARM_SHAPE_FIR_TAPS 3 + +/* Maximum number of delayed decision states */ +#define MAX_DEL_DEC_STATES 4 + +#define LTP_BUF_LENGTH 512 +#define LTP_MASK ( LTP_BUF_LENGTH - 1 ) + +#define DECISION_DELAY 40 + +/* Number of subframes for excitation entropy coding */ +#define SHELL_CODEC_FRAME_LENGTH 16 +#define LOG2_SHELL_CODEC_FRAME_LENGTH 4 +#define MAX_NB_SHELL_BLOCKS ( MAX_FRAME_LENGTH / SHELL_CODEC_FRAME_LENGTH ) + +/* Number of rate levels, for entropy coding of excitation */ +#define N_RATE_LEVELS 10 + +/* Maximum sum of pulses per shell coding frame */ +#define SILK_MAX_PULSES 16 + +#define MAX_MATRIX_SIZE MAX_LPC_ORDER /* Max of LPC Order and LTP order */ + +# define NSQ_LPC_BUF_LENGTH MAX_LPC_ORDER + +/***************************/ +/* Voice activity detector */ +/***************************/ +#define VAD_N_BANDS 4 + +#define VAD_INTERNAL_SUBFRAMES_LOG2 2 +#define VAD_INTERNAL_SUBFRAMES ( 1 << VAD_INTERNAL_SUBFRAMES_LOG2 ) + +#define VAD_NOISE_LEVEL_SMOOTH_COEF_Q16 1024 /* Must be < 4096 */ +#define VAD_NOISE_LEVELS_BIAS 50 + +/* Sigmoid settings */ +#define VAD_NEGATIVE_OFFSET_Q5 128 /* sigmoid is 0 at -128 */ +#define VAD_SNR_FACTOR_Q16 45000 + +/* smoothing for SNR measurement */ +#define VAD_SNR_SMOOTH_COEF_Q18 4096 + +/* Size of the piecewise linear cosine approximation table for the LSFs */ +#define LSF_COS_TAB_SZ_FIX 128 + +/******************/ +/* NLSF quantizer */ +/******************/ +#define NLSF_W_Q 2 +#define NLSF_VQ_MAX_VECTORS 32 +#define NLSF_QUANT_MAX_AMPLITUDE 4 +#define NLSF_QUANT_MAX_AMPLITUDE_EXT 10 +#define NLSF_QUANT_LEVEL_ADJ 0.1 +#define NLSF_QUANT_DEL_DEC_STATES_LOG2 2 +#define NLSF_QUANT_DEL_DEC_STATES ( 1 << NLSF_QUANT_DEL_DEC_STATES_LOG2 ) + +/* Transition filtering for mode switching */ +#define TRANSITION_TIME_MS 5120 /* 5120 = 64 * FRAME_LENGTH_MS * ( TRANSITION_INT_NUM - 1 ) = 64*(20*4)*/ +#define TRANSITION_NB 3 /* Hardcoded in tables */ +#define TRANSITION_NA 2 /* Hardcoded in tables */ +#define TRANSITION_INT_NUM 5 /* Hardcoded in tables */ +#define TRANSITION_FRAMES ( TRANSITION_TIME_MS / MAX_FRAME_LENGTH_MS ) +#define TRANSITION_INT_STEPS ( TRANSITION_FRAMES / ( TRANSITION_INT_NUM - 1 ) ) + +/* BWE factors to apply after packet loss */ +#define BWE_AFTER_LOSS_Q16 63570 + +/* Defines for CN generation */ +#define CNG_BUF_MASK_MAX 255 /* 2^floor(log2(MAX_FRAME_LENGTH))-1 */ +#define CNG_GAIN_SMTH_Q16 4634 /* 0.25^(1/4) */ +#define CNG_NLSF_SMTH_Q16 16348 /* 0.25 */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/extern/opus/silk/enc_API.c b/extern/opus/silk/enc_API.c new file mode 100644 index 0000000..55a33f3 --- /dev/null +++ b/extern/opus/silk/enc_API.c @@ -0,0 +1,576 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "define.h" +#include "API.h" +#include "control.h" +#include "typedef.h" +#include "stack_alloc.h" +#include "structs.h" +#include "tuning_parameters.h" +#ifdef FIXED_POINT +#include "main_FIX.h" +#else +#include "main_FLP.h" +#endif + +/***************************************/ +/* Read control structure from encoder */ +/***************************************/ +static opus_int silk_QueryEncoder( /* O Returns error code */ + const void *encState, /* I State */ + silk_EncControlStruct *encStatus /* O Encoder Status */ +); + +/****************************************/ +/* Encoder functions */ +/****************************************/ + +opus_int silk_Get_Encoder_Size( /* O Returns error code */ + opus_int *encSizeBytes /* O Number of bytes in SILK encoder state */ +) +{ + opus_int ret = SILK_NO_ERROR; + + *encSizeBytes = sizeof( silk_encoder ); + + return ret; +} + +/*************************/ +/* Init or Reset encoder */ +/*************************/ +opus_int silk_InitEncoder( /* O Returns error code */ + void *encState, /* I/O State */ + int arch, /* I Run-time architecture */ + silk_EncControlStruct *encStatus /* O Encoder Status */ +) +{ + silk_encoder *psEnc; + opus_int n, ret = SILK_NO_ERROR; + + psEnc = (silk_encoder *)encState; + + /* Reset encoder */ + silk_memset( psEnc, 0, sizeof( silk_encoder ) ); + for( n = 0; n < ENCODER_NUM_CHANNELS; n++ ) { + if( ret += silk_init_encoder( &psEnc->state_Fxx[ n ], arch ) ) { + celt_assert( 0 ); + } + } + + psEnc->nChannelsAPI = 1; + psEnc->nChannelsInternal = 1; + + /* Read control structure */ + if( ret += silk_QueryEncoder( encState, encStatus ) ) { + celt_assert( 0 ); + } + + return ret; +} + +/***************************************/ +/* Read control structure from encoder */ +/***************************************/ +static opus_int silk_QueryEncoder( /* O Returns error code */ + const void *encState, /* I State */ + silk_EncControlStruct *encStatus /* O Encoder Status */ +) +{ + opus_int ret = SILK_NO_ERROR; + silk_encoder_state_Fxx *state_Fxx; + silk_encoder *psEnc = (silk_encoder *)encState; + + state_Fxx = psEnc->state_Fxx; + + encStatus->nChannelsAPI = psEnc->nChannelsAPI; + encStatus->nChannelsInternal = psEnc->nChannelsInternal; + encStatus->API_sampleRate = state_Fxx[ 0 ].sCmn.API_fs_Hz; + encStatus->maxInternalSampleRate = state_Fxx[ 0 ].sCmn.maxInternal_fs_Hz; + encStatus->minInternalSampleRate = state_Fxx[ 0 ].sCmn.minInternal_fs_Hz; + encStatus->desiredInternalSampleRate = state_Fxx[ 0 ].sCmn.desiredInternal_fs_Hz; + encStatus->payloadSize_ms = state_Fxx[ 0 ].sCmn.PacketSize_ms; + encStatus->bitRate = state_Fxx[ 0 ].sCmn.TargetRate_bps; + encStatus->packetLossPercentage = state_Fxx[ 0 ].sCmn.PacketLoss_perc; + encStatus->complexity = state_Fxx[ 0 ].sCmn.Complexity; + encStatus->useInBandFEC = state_Fxx[ 0 ].sCmn.useInBandFEC; + encStatus->useDTX = state_Fxx[ 0 ].sCmn.useDTX; + encStatus->useCBR = state_Fxx[ 0 ].sCmn.useCBR; + encStatus->internalSampleRate = silk_SMULBB( state_Fxx[ 0 ].sCmn.fs_kHz, 1000 ); + encStatus->allowBandwidthSwitch = state_Fxx[ 0 ].sCmn.allow_bandwidth_switch; + encStatus->inWBmodeWithoutVariableLP = state_Fxx[ 0 ].sCmn.fs_kHz == 16 && state_Fxx[ 0 ].sCmn.sLP.mode == 0; + + return ret; +} + + +/**************************/ +/* Encode frame with Silk */ +/**************************/ +/* Note: if prefillFlag is set, the input must contain 10 ms of audio, irrespective of what */ +/* encControl->payloadSize_ms is set to */ +opus_int silk_Encode( /* O Returns error code */ + void *encState, /* I/O State */ + silk_EncControlStruct *encControl, /* I Control status */ + const opus_int16 *samplesIn, /* I Speech sample input vector */ + opus_int nSamplesIn, /* I Number of samples in input vector */ + ec_enc *psRangeEnc, /* I/O Compressor data structure */ + opus_int32 *nBytesOut, /* I/O Number of bytes in payload (input: Max bytes) */ + const opus_int prefillFlag, /* I Flag to indicate prefilling buffers no coding */ + opus_int activity /* I Decision of Opus voice activity detector */ +) +{ + opus_int n, i, nBits, flags, tmp_payloadSize_ms = 0, tmp_complexity = 0, ret = 0; + opus_int nSamplesToBuffer, nSamplesToBufferMax, nBlocksOf10ms; + opus_int nSamplesFromInput = 0, nSamplesFromInputMax; + opus_int speech_act_thr_for_switch_Q8; + opus_int32 TargetRate_bps, MStargetRates_bps[ 2 ], channelRate_bps, LBRR_symbol, sum; + silk_encoder *psEnc = ( silk_encoder * )encState; + VARDECL( opus_int16, buf ); + opus_int transition, curr_block, tot_blocks; + SAVE_STACK; + + if (encControl->reducedDependency) + { + psEnc->state_Fxx[0].sCmn.first_frame_after_reset = 1; + psEnc->state_Fxx[1].sCmn.first_frame_after_reset = 1; + } + psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded = psEnc->state_Fxx[ 1 ].sCmn.nFramesEncoded = 0; + + /* Check values in encoder control structure */ + if( ( ret = check_control_input( encControl ) ) != 0 ) { + celt_assert( 0 ); + RESTORE_STACK; + return ret; + } + + encControl->switchReady = 0; + + if( encControl->nChannelsInternal > psEnc->nChannelsInternal ) { + /* Mono -> Stereo transition: init state of second channel and stereo state */ + ret += silk_init_encoder( &psEnc->state_Fxx[ 1 ], psEnc->state_Fxx[ 0 ].sCmn.arch ); + silk_memset( psEnc->sStereo.pred_prev_Q13, 0, sizeof( psEnc->sStereo.pred_prev_Q13 ) ); + silk_memset( psEnc->sStereo.sSide, 0, sizeof( psEnc->sStereo.sSide ) ); + 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 = SILK_FIX_CONST( 1, 14 ); + if( psEnc->nChannelsAPI == 2 ) { + silk_memcpy( &psEnc->state_Fxx[ 1 ].sCmn.resampler_state, &psEnc->state_Fxx[ 0 ].sCmn.resampler_state, sizeof( silk_resampler_state_struct ) ); + silk_memcpy( &psEnc->state_Fxx[ 1 ].sCmn.In_HP_State, &psEnc->state_Fxx[ 0 ].sCmn.In_HP_State, sizeof( psEnc->state_Fxx[ 1 ].sCmn.In_HP_State ) ); + } + } + + transition = (encControl->payloadSize_ms != psEnc->state_Fxx[ 0 ].sCmn.PacketSize_ms) || (psEnc->nChannelsInternal != encControl->nChannelsInternal); + + psEnc->nChannelsAPI = encControl->nChannelsAPI; + psEnc->nChannelsInternal = encControl->nChannelsInternal; + + nBlocksOf10ms = silk_DIV32( 100 * nSamplesIn, encControl->API_sampleRate ); + tot_blocks = ( nBlocksOf10ms > 1 ) ? nBlocksOf10ms >> 1 : 1; + curr_block = 0; + if( prefillFlag ) { + silk_LP_state save_LP; + /* Only accept input length of 10 ms */ + if( nBlocksOf10ms != 1 ) { + celt_assert( 0 ); + RESTORE_STACK; + return SILK_ENC_INPUT_INVALID_NO_OF_SAMPLES; + } + if ( prefillFlag == 2 ) { + save_LP = psEnc->state_Fxx[ 0 ].sCmn.sLP; + /* Save the sampling rate so the bandwidth switching code can keep handling transitions. */ + save_LP.saved_fs_kHz = psEnc->state_Fxx[ 0 ].sCmn.fs_kHz; + } + /* Reset Encoder */ + for( n = 0; n < encControl->nChannelsInternal; n++ ) { + ret = silk_init_encoder( &psEnc->state_Fxx[ n ], psEnc->state_Fxx[ n ].sCmn.arch ); + /* Restore the variable LP state. */ + if ( prefillFlag == 2 ) { + psEnc->state_Fxx[ n ].sCmn.sLP = save_LP; + } + celt_assert( !ret ); + } + 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 ].sCmn.controlled_since_last_payload = 0; + psEnc->state_Fxx[ n ].sCmn.prefillFlag = 1; + } + } else { + /* Only accept input lengths that are a multiple of 10 ms */ + if( nBlocksOf10ms * encControl->API_sampleRate != 100 * nSamplesIn || nSamplesIn < 0 ) { + celt_assert( 0 ); + RESTORE_STACK; + return SILK_ENC_INPUT_INVALID_NO_OF_SAMPLES; + } + /* Make sure no more than one packet can be produced */ + if( 1000 * (opus_int32)nSamplesIn > encControl->payloadSize_ms * encControl->API_sampleRate ) { + celt_assert( 0 ); + RESTORE_STACK; + return SILK_ENC_INPUT_INVALID_NO_OF_SAMPLES; + } + } + + for( n = 0; n < encControl->nChannelsInternal; n++ ) { + /* Force the side channel to the same rate as the mid */ + opus_int force_fs_kHz = (n==1) ? psEnc->state_Fxx[0].sCmn.fs_kHz : 0; + if( ( ret = silk_control_encoder( &psEnc->state_Fxx[ n ], encControl, psEnc->allowBandwidthSwitch, n, force_fs_kHz ) ) != 0 ) { + silk_assert( 0 ); + RESTORE_STACK; + return ret; + } + if( psEnc->state_Fxx[n].sCmn.first_frame_after_reset || transition ) { + for( i = 0; i < psEnc->state_Fxx[ 0 ].sCmn.nFramesPerPacket; i++ ) { + psEnc->state_Fxx[ n ].sCmn.LBRR_flags[ i ] = 0; + } + } + psEnc->state_Fxx[ n ].sCmn.inDTX = psEnc->state_Fxx[ n ].sCmn.useDTX; + } + celt_assert( encControl->nChannelsInternal == 1 || psEnc->state_Fxx[ 0 ].sCmn.fs_kHz == psEnc->state_Fxx[ 1 ].sCmn.fs_kHz ); + + /* Input buffering/resampling and encoding */ + nSamplesToBufferMax = + 10 * nBlocksOf10ms * psEnc->state_Fxx[ 0 ].sCmn.fs_kHz; + nSamplesFromInputMax = + silk_DIV32_16( nSamplesToBufferMax * + psEnc->state_Fxx[ 0 ].sCmn.API_fs_Hz, + psEnc->state_Fxx[ 0 ].sCmn.fs_kHz * 1000 ); + ALLOC( buf, nSamplesFromInputMax, opus_int16 ); + while( 1 ) { + nSamplesToBuffer = psEnc->state_Fxx[ 0 ].sCmn.frame_length - psEnc->state_Fxx[ 0 ].sCmn.inputBufIx; + nSamplesToBuffer = silk_min( nSamplesToBuffer, nSamplesToBufferMax ); + nSamplesFromInput = silk_DIV32_16( nSamplesToBuffer * psEnc->state_Fxx[ 0 ].sCmn.API_fs_Hz, psEnc->state_Fxx[ 0 ].sCmn.fs_kHz * 1000 ); + /* Resample and write to buffer */ + if( encControl->nChannelsAPI == 2 && encControl->nChannelsInternal == 2 ) { + opus_int id = psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded; + for( n = 0; n < nSamplesFromInput; n++ ) { + buf[ n ] = samplesIn[ 2 * n ]; + } + /* Making sure to start both resamplers from the same state when switching from mono to stereo */ + if( psEnc->nPrevChannelsInternal == 1 && id==0 ) { + silk_memcpy( &psEnc->state_Fxx[ 1 ].sCmn.resampler_state, &psEnc->state_Fxx[ 0 ].sCmn.resampler_state, sizeof(psEnc->state_Fxx[ 1 ].sCmn.resampler_state)); + } + + ret += silk_resampler( &psEnc->state_Fxx[ 0 ].sCmn.resampler_state, + &psEnc->state_Fxx[ 0 ].sCmn.inputBuf[ psEnc->state_Fxx[ 0 ].sCmn.inputBufIx + 2 ], buf, nSamplesFromInput ); + psEnc->state_Fxx[ 0 ].sCmn.inputBufIx += nSamplesToBuffer; + + nSamplesToBuffer = psEnc->state_Fxx[ 1 ].sCmn.frame_length - psEnc->state_Fxx[ 1 ].sCmn.inputBufIx; + nSamplesToBuffer = silk_min( nSamplesToBuffer, 10 * nBlocksOf10ms * psEnc->state_Fxx[ 1 ].sCmn.fs_kHz ); + for( n = 0; n < nSamplesFromInput; n++ ) { + buf[ n ] = samplesIn[ 2 * n + 1 ]; + } + ret += silk_resampler( &psEnc->state_Fxx[ 1 ].sCmn.resampler_state, + &psEnc->state_Fxx[ 1 ].sCmn.inputBuf[ psEnc->state_Fxx[ 1 ].sCmn.inputBufIx + 2 ], buf, nSamplesFromInput ); + + psEnc->state_Fxx[ 1 ].sCmn.inputBufIx += nSamplesToBuffer; + } else if( encControl->nChannelsAPI == 2 && encControl->nChannelsInternal == 1 ) { + /* Combine left and right channels before resampling */ + for( n = 0; n < nSamplesFromInput; n++ ) { + sum = samplesIn[ 2 * n ] + samplesIn[ 2 * n + 1 ]; + buf[ n ] = (opus_int16)silk_RSHIFT_ROUND( sum, 1 ); + } + ret += silk_resampler( &psEnc->state_Fxx[ 0 ].sCmn.resampler_state, + &psEnc->state_Fxx[ 0 ].sCmn.inputBuf[ psEnc->state_Fxx[ 0 ].sCmn.inputBufIx + 2 ], buf, nSamplesFromInput ); + /* On the first mono frame, average the results for the two resampler states */ + if( psEnc->nPrevChannelsInternal == 2 && psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded == 0 ) { + ret += silk_resampler( &psEnc->state_Fxx[ 1 ].sCmn.resampler_state, + &psEnc->state_Fxx[ 1 ].sCmn.inputBuf[ psEnc->state_Fxx[ 1 ].sCmn.inputBufIx + 2 ], buf, nSamplesFromInput ); + for( n = 0; n < psEnc->state_Fxx[ 0 ].sCmn.frame_length; n++ ) { + psEnc->state_Fxx[ 0 ].sCmn.inputBuf[ psEnc->state_Fxx[ 0 ].sCmn.inputBufIx+n+2 ] = + silk_RSHIFT(psEnc->state_Fxx[ 0 ].sCmn.inputBuf[ psEnc->state_Fxx[ 0 ].sCmn.inputBufIx+n+2 ] + + psEnc->state_Fxx[ 1 ].sCmn.inputBuf[ psEnc->state_Fxx[ 1 ].sCmn.inputBufIx+n+2 ], 1); + } + } + psEnc->state_Fxx[ 0 ].sCmn.inputBufIx += nSamplesToBuffer; + } else { + celt_assert( encControl->nChannelsAPI == 1 && encControl->nChannelsInternal == 1 ); + silk_memcpy(buf, samplesIn, nSamplesFromInput*sizeof(opus_int16)); + ret += silk_resampler( &psEnc->state_Fxx[ 0 ].sCmn.resampler_state, + &psEnc->state_Fxx[ 0 ].sCmn.inputBuf[ psEnc->state_Fxx[ 0 ].sCmn.inputBufIx + 2 ], buf, nSamplesFromInput ); + psEnc->state_Fxx[ 0 ].sCmn.inputBufIx += nSamplesToBuffer; + } + + samplesIn += nSamplesFromInput * encControl->nChannelsAPI; + nSamplesIn -= nSamplesFromInput; + + /* Default */ + psEnc->allowBandwidthSwitch = 0; + + /* Silk encoder */ + if( psEnc->state_Fxx[ 0 ].sCmn.inputBufIx >= psEnc->state_Fxx[ 0 ].sCmn.frame_length ) { + /* Enough data in input buffer, so encode */ + celt_assert( psEnc->state_Fxx[ 0 ].sCmn.inputBufIx == psEnc->state_Fxx[ 0 ].sCmn.frame_length ); + celt_assert( encControl->nChannelsInternal == 1 || psEnc->state_Fxx[ 1 ].sCmn.inputBufIx == psEnc->state_Fxx[ 1 ].sCmn.frame_length ); + + /* Deal with LBRR data */ + if( psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded == 0 && !prefillFlag ) { + /* Create space at start of payload for VAD and FEC flags */ + opus_uint8 iCDF[ 2 ] = { 0, 0 }; + iCDF[ 0 ] = 256 - silk_RSHIFT( 256, ( psEnc->state_Fxx[ 0 ].sCmn.nFramesPerPacket + 1 ) * encControl->nChannelsInternal ); + ec_enc_icdf( psRangeEnc, 0, iCDF, 8 ); + + /* Encode any LBRR data from previous packet */ + /* Encode LBRR flags */ + for( n = 0; n < encControl->nChannelsInternal; n++ ) { + LBRR_symbol = 0; + for( i = 0; i < psEnc->state_Fxx[ n ].sCmn.nFramesPerPacket; i++ ) { + LBRR_symbol |= silk_LSHIFT( psEnc->state_Fxx[ n ].sCmn.LBRR_flags[ i ], i ); + } + psEnc->state_Fxx[ n ].sCmn.LBRR_flag = LBRR_symbol > 0 ? 1 : 0; + if( LBRR_symbol && psEnc->state_Fxx[ n ].sCmn.nFramesPerPacket > 1 ) { + ec_enc_icdf( psRangeEnc, LBRR_symbol - 1, silk_LBRR_flags_iCDF_ptr[ psEnc->state_Fxx[ n ].sCmn.nFramesPerPacket - 2 ], 8 ); + } + } + + /* Code LBRR indices and excitation signals */ + for( i = 0; i < psEnc->state_Fxx[ 0 ].sCmn.nFramesPerPacket; i++ ) { + for( n = 0; n < encControl->nChannelsInternal; n++ ) { + if( psEnc->state_Fxx[ n ].sCmn.LBRR_flags[ i ] ) { + opus_int condCoding; + + if( encControl->nChannelsInternal == 2 && n == 0 ) { + silk_stereo_encode_pred( psRangeEnc, psEnc->sStereo.predIx[ i ] ); + /* For LBRR data there's no need to code the mid-only flag if the side-channel LBRR flag is set */ + if( psEnc->state_Fxx[ 1 ].sCmn.LBRR_flags[ i ] == 0 ) { + silk_stereo_encode_mid_only( psRangeEnc, psEnc->sStereo.mid_only_flags[ i ] ); + } + } + /* Use conditional coding if previous frame available */ + if( i > 0 && psEnc->state_Fxx[ n ].sCmn.LBRR_flags[ i - 1 ] ) { + condCoding = CODE_CONDITIONALLY; + } else { + condCoding = CODE_INDEPENDENTLY; + } + silk_encode_indices( &psEnc->state_Fxx[ n ].sCmn, psRangeEnc, i, 1, condCoding ); + silk_encode_pulses( psRangeEnc, psEnc->state_Fxx[ n ].sCmn.indices_LBRR[i].signalType, psEnc->state_Fxx[ n ].sCmn.indices_LBRR[i].quantOffsetType, + psEnc->state_Fxx[ n ].sCmn.pulses_LBRR[ i ], psEnc->state_Fxx[ n ].sCmn.frame_length ); + } + } + } + + /* Reset LBRR flags */ + for( n = 0; n < encControl->nChannelsInternal; n++ ) { + silk_memset( psEnc->state_Fxx[ n ].sCmn.LBRR_flags, 0, sizeof( psEnc->state_Fxx[ n ].sCmn.LBRR_flags ) ); + } + + psEnc->nBitsUsedLBRR = ec_tell( psRangeEnc ); + } + + silk_HP_variable_cutoff( psEnc->state_Fxx ); + + /* Total target bits for packet */ + nBits = silk_DIV32_16( silk_MUL( encControl->bitRate, encControl->payloadSize_ms ), 1000 ); + /* Subtract bits used for LBRR */ + if( !prefillFlag ) { + nBits -= psEnc->nBitsUsedLBRR; + } + /* Divide by number of uncoded frames left in packet */ + nBits = silk_DIV32_16( nBits, psEnc->state_Fxx[ 0 ].sCmn.nFramesPerPacket ); + /* Convert to bits/second */ + if( encControl->payloadSize_ms == 10 ) { + TargetRate_bps = silk_SMULBB( nBits, 100 ); + } else { + TargetRate_bps = silk_SMULBB( nBits, 50 ); + } + /* Subtract fraction of bits in excess of target in previous frames and packets */ + TargetRate_bps -= silk_DIV32_16( silk_MUL( psEnc->nBitsExceeded, 1000 ), BITRESERVOIR_DECAY_TIME_MS ); + if( !prefillFlag && psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded > 0 ) { + /* Compare actual vs target bits so far in this packet */ + opus_int32 bitsBalance = ec_tell( psRangeEnc ) - psEnc->nBitsUsedLBRR - nBits * psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded; + TargetRate_bps -= silk_DIV32_16( silk_MUL( bitsBalance, 1000 ), BITRESERVOIR_DECAY_TIME_MS ); + } + /* Never exceed input bitrate */ + TargetRate_bps = silk_LIMIT( TargetRate_bps, encControl->bitRate, 5000 ); + + /* Convert Left/Right to Mid/Side */ + if( encControl->nChannelsInternal == 2 ) { + silk_stereo_LR_to_MS( &psEnc->sStereo, &psEnc->state_Fxx[ 0 ].sCmn.inputBuf[ 2 ], &psEnc->state_Fxx[ 1 ].sCmn.inputBuf[ 2 ], + psEnc->sStereo.predIx[ psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded ], &psEnc->sStereo.mid_only_flags[ psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded ], + MStargetRates_bps, TargetRate_bps, psEnc->state_Fxx[ 0 ].sCmn.speech_activity_Q8, encControl->toMono, + psEnc->state_Fxx[ 0 ].sCmn.fs_kHz, psEnc->state_Fxx[ 0 ].sCmn.frame_length ); + if( psEnc->sStereo.mid_only_flags[ psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded ] == 0 ) { + /* Reset side channel encoder memory for first frame with side coding */ + if( psEnc->prev_decode_only_middle == 1 ) { + silk_memset( &psEnc->state_Fxx[ 1 ].sShape, 0, sizeof( psEnc->state_Fxx[ 1 ].sShape ) ); + silk_memset( &psEnc->state_Fxx[ 1 ].sCmn.sNSQ, 0, sizeof( psEnc->state_Fxx[ 1 ].sCmn.sNSQ ) ); + silk_memset( psEnc->state_Fxx[ 1 ].sCmn.prev_NLSFq_Q15, 0, sizeof( psEnc->state_Fxx[ 1 ].sCmn.prev_NLSFq_Q15 ) ); + silk_memset( &psEnc->state_Fxx[ 1 ].sCmn.sLP.In_LP_State, 0, sizeof( psEnc->state_Fxx[ 1 ].sCmn.sLP.In_LP_State ) ); + psEnc->state_Fxx[ 1 ].sCmn.prevLag = 100; + psEnc->state_Fxx[ 1 ].sCmn.sNSQ.lagPrev = 100; + psEnc->state_Fxx[ 1 ].sShape.LastGainIndex = 10; + psEnc->state_Fxx[ 1 ].sCmn.prevSignalType = TYPE_NO_VOICE_ACTIVITY; + psEnc->state_Fxx[ 1 ].sCmn.sNSQ.prev_gain_Q16 = 65536; + psEnc->state_Fxx[ 1 ].sCmn.first_frame_after_reset = 1; + } + silk_encode_do_VAD_Fxx( &psEnc->state_Fxx[ 1 ], activity ); + } else { + psEnc->state_Fxx[ 1 ].sCmn.VAD_flags[ psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded ] = 0; + } + if( !prefillFlag ) { + silk_stereo_encode_pred( psRangeEnc, psEnc->sStereo.predIx[ psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded ] ); + if( psEnc->state_Fxx[ 1 ].sCmn.VAD_flags[ psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded ] == 0 ) { + silk_stereo_encode_mid_only( psRangeEnc, psEnc->sStereo.mid_only_flags[ psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded ] ); + } + } + } else { + /* Buffering */ + silk_memcpy( psEnc->state_Fxx[ 0 ].sCmn.inputBuf, psEnc->sStereo.sMid, 2 * sizeof( opus_int16 ) ); + silk_memcpy( psEnc->sStereo.sMid, &psEnc->state_Fxx[ 0 ].sCmn.inputBuf[ psEnc->state_Fxx[ 0 ].sCmn.frame_length ], 2 * sizeof( opus_int16 ) ); + } + silk_encode_do_VAD_Fxx( &psEnc->state_Fxx[ 0 ], activity ); + + /* Encode */ + for( n = 0; n < encControl->nChannelsInternal; n++ ) { + opus_int maxBits, useCBR; + + /* Handling rate constraints */ + 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; + } + } + useCBR = encControl->useCBR && curr_block == tot_blocks - 1; + + if( encControl->nChannelsInternal == 1 ) { + channelRate_bps = TargetRate_bps; + } else { + channelRate_bps = MStargetRates_bps[ n ]; + if( n == 0 && MStargetRates_bps[ 1 ] > 0 ) { + useCBR = 0; + /* Give mid up to 1/2 of the max bits for that frame */ + maxBits -= encControl->maxBits / ( tot_blocks * 2 ); + } + } + + if( channelRate_bps > 0 ) { + opus_int condCoding; + + silk_control_SNR( &psEnc->state_Fxx[ n ].sCmn, channelRate_bps ); + + /* Use independent coding if no previous frame available */ + if( psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded - n <= 0 ) { + condCoding = CODE_INDEPENDENTLY; + } else if( n > 0 && psEnc->prev_decode_only_middle ) { + /* If we skipped a side frame in this packet, we don't + need LTP scaling; the LTP state is well-defined. */ + condCoding = CODE_INDEPENDENTLY_NO_LTP_SCALING; + } else { + condCoding = CODE_CONDITIONALLY; + } + if( ( ret = silk_encode_frame_Fxx( &psEnc->state_Fxx[ n ], nBytesOut, psRangeEnc, condCoding, maxBits, useCBR ) ) != 0 ) { + silk_assert( 0 ); + } + } + psEnc->state_Fxx[ n ].sCmn.controlled_since_last_payload = 0; + psEnc->state_Fxx[ n ].sCmn.inputBufIx = 0; + psEnc->state_Fxx[ n ].sCmn.nFramesEncoded++; + } + psEnc->prev_decode_only_middle = psEnc->sStereo.mid_only_flags[ psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded - 1 ]; + + /* Insert VAD and FEC flags at beginning of bitstream */ + if( *nBytesOut > 0 && psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded == psEnc->state_Fxx[ 0 ].sCmn.nFramesPerPacket) { + flags = 0; + for( n = 0; n < encControl->nChannelsInternal; n++ ) { + for( i = 0; i < psEnc->state_Fxx[ n ].sCmn.nFramesPerPacket; i++ ) { + flags = silk_LSHIFT( flags, 1 ); + flags |= psEnc->state_Fxx[ n ].sCmn.VAD_flags[ i ]; + } + flags = silk_LSHIFT( flags, 1 ); + flags |= psEnc->state_Fxx[ n ].sCmn.LBRR_flag; + } + if( !prefillFlag ) { + ec_enc_patch_initial_bits( psRangeEnc, flags, ( psEnc->state_Fxx[ 0 ].sCmn.nFramesPerPacket + 1 ) * encControl->nChannelsInternal ); + } + + /* Return zero bytes if all channels DTXed */ + if( psEnc->state_Fxx[ 0 ].sCmn.inDTX && ( encControl->nChannelsInternal == 1 || psEnc->state_Fxx[ 1 ].sCmn.inDTX ) ) { + *nBytesOut = 0; + } + + psEnc->nBitsExceeded += *nBytesOut * 8; + psEnc->nBitsExceeded -= silk_DIV32_16( silk_MUL( encControl->bitRate, encControl->payloadSize_ms ), 1000 ); + psEnc->nBitsExceeded = silk_LIMIT( psEnc->nBitsExceeded, 0, 10000 ); + + /* Update flag indicating if bandwidth switching is allowed */ + speech_act_thr_for_switch_Q8 = silk_SMLAWB( SILK_FIX_CONST( SPEECH_ACTIVITY_DTX_THRES, 8 ), + SILK_FIX_CONST( ( 1 - SPEECH_ACTIVITY_DTX_THRES ) / MAX_BANDWIDTH_SWITCH_DELAY_MS, 16 + 8 ), psEnc->timeSinceSwitchAllowed_ms ); + if( psEnc->state_Fxx[ 0 ].sCmn.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; + } + } else { + break; + } + curr_block++; + } + + psEnc->nPrevChannelsInternal = encControl->nChannelsInternal; + + encControl->allowBandwidthSwitch = psEnc->allowBandwidthSwitch; + encControl->inWBmodeWithoutVariableLP = psEnc->state_Fxx[ 0 ].sCmn.fs_kHz == 16 && psEnc->state_Fxx[ 0 ].sCmn.sLP.mode == 0; + encControl->internalSampleRate = silk_SMULBB( psEnc->state_Fxx[ 0 ].sCmn.fs_kHz, 1000 ); + encControl->stereoWidth_Q14 = encControl->toMono ? 0 : psEnc->sStereo.smth_width_Q14; + if( prefillFlag ) { + encControl->payloadSize_ms = tmp_payloadSize_ms; + encControl->complexity = tmp_complexity; + for( n = 0; n < encControl->nChannelsInternal; n++ ) { + psEnc->state_Fxx[ n ].sCmn.controlled_since_last_payload = 0; + psEnc->state_Fxx[ n ].sCmn.prefillFlag = 0; + } + } + + encControl->signalType = psEnc->state_Fxx[0].sCmn.indices.signalType; + encControl->offset = silk_Quantization_Offsets_Q10 + [ psEnc->state_Fxx[0].sCmn.indices.signalType >> 1 ] + [ psEnc->state_Fxx[0].sCmn.indices.quantOffsetType ]; + RESTORE_STACK; + return ret; +} + diff --git a/extern/opus/silk/encode_indices.c b/extern/opus/silk/encode_indices.c new file mode 100644 index 0000000..4bcbc33 --- /dev/null +++ b/extern/opus/silk/encode_indices.c @@ -0,0 +1,181 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/* Encode side-information parameters to payload */ +void silk_encode_indices( + silk_encoder_state *psEncC, /* I/O Encoder state */ + ec_enc *psRangeEnc, /* I/O Compressor data structure */ + opus_int FrameIndex, /* I Frame number */ + opus_int encode_LBRR, /* I Flag indicating LBRR data is being encoded */ + opus_int condCoding /* I The type of conditional coding to use */ +) +{ + opus_int i, k, typeOffset; + opus_int encode_absolute_lagIndex, delta_lagIndex; + opus_int16 ec_ix[ MAX_LPC_ORDER ]; + opus_uint8 pred_Q8[ MAX_LPC_ORDER ]; + const SideInfoIndices *psIndices; + + if( encode_LBRR ) { + psIndices = &psEncC->indices_LBRR[ FrameIndex ]; + } else { + psIndices = &psEncC->indices; + } + + /*******************************************/ + /* Encode signal type and quantizer offset */ + /*******************************************/ + typeOffset = 2 * psIndices->signalType + psIndices->quantOffsetType; + celt_assert( typeOffset >= 0 && typeOffset < 6 ); + celt_assert( encode_LBRR == 0 || typeOffset >= 2 ); + if( encode_LBRR || typeOffset >= 2 ) { + ec_enc_icdf( psRangeEnc, typeOffset - 2, silk_type_offset_VAD_iCDF, 8 ); + } else { + ec_enc_icdf( psRangeEnc, typeOffset, silk_type_offset_no_VAD_iCDF, 8 ); + } + + /****************/ + /* Encode gains */ + /****************/ + /* first subframe */ + if( condCoding == CODE_CONDITIONALLY ) { + /* conditional coding */ + silk_assert( psIndices->GainsIndices[ 0 ] >= 0 && psIndices->GainsIndices[ 0 ] < MAX_DELTA_GAIN_QUANT - MIN_DELTA_GAIN_QUANT + 1 ); + ec_enc_icdf( psRangeEnc, psIndices->GainsIndices[ 0 ], silk_delta_gain_iCDF, 8 ); + } else { + /* independent coding, in two stages: MSB bits followed by 3 LSBs */ + silk_assert( psIndices->GainsIndices[ 0 ] >= 0 && psIndices->GainsIndices[ 0 ] < N_LEVELS_QGAIN ); + ec_enc_icdf( psRangeEnc, silk_RSHIFT( psIndices->GainsIndices[ 0 ], 3 ), silk_gain_iCDF[ psIndices->signalType ], 8 ); + ec_enc_icdf( psRangeEnc, psIndices->GainsIndices[ 0 ] & 7, silk_uniform8_iCDF, 8 ); + } + + /* remaining subframes */ + for( i = 1; i < psEncC->nb_subfr; i++ ) { + silk_assert( psIndices->GainsIndices[ i ] >= 0 && psIndices->GainsIndices[ i ] < MAX_DELTA_GAIN_QUANT - MIN_DELTA_GAIN_QUANT + 1 ); + ec_enc_icdf( psRangeEnc, psIndices->GainsIndices[ i ], silk_delta_gain_iCDF, 8 ); + } + + /****************/ + /* Encode NLSFs */ + /****************/ + ec_enc_icdf( psRangeEnc, psIndices->NLSFIndices[ 0 ], &psEncC->psNLSF_CB->CB1_iCDF[ ( psIndices->signalType >> 1 ) * psEncC->psNLSF_CB->nVectors ], 8 ); + silk_NLSF_unpack( ec_ix, pred_Q8, psEncC->psNLSF_CB, psIndices->NLSFIndices[ 0 ] ); + celt_assert( psEncC->psNLSF_CB->order == psEncC->predictLPCOrder ); + for( i = 0; i < psEncC->psNLSF_CB->order; i++ ) { + if( psIndices->NLSFIndices[ i+1 ] >= NLSF_QUANT_MAX_AMPLITUDE ) { + ec_enc_icdf( psRangeEnc, 2 * NLSF_QUANT_MAX_AMPLITUDE, &psEncC->psNLSF_CB->ec_iCDF[ ec_ix[ i ] ], 8 ); + ec_enc_icdf( psRangeEnc, psIndices->NLSFIndices[ i+1 ] - NLSF_QUANT_MAX_AMPLITUDE, silk_NLSF_EXT_iCDF, 8 ); + } else if( psIndices->NLSFIndices[ i+1 ] <= -NLSF_QUANT_MAX_AMPLITUDE ) { + ec_enc_icdf( psRangeEnc, 0, &psEncC->psNLSF_CB->ec_iCDF[ ec_ix[ i ] ], 8 ); + ec_enc_icdf( psRangeEnc, -psIndices->NLSFIndices[ i+1 ] - NLSF_QUANT_MAX_AMPLITUDE, silk_NLSF_EXT_iCDF, 8 ); + } else { + ec_enc_icdf( psRangeEnc, psIndices->NLSFIndices[ i+1 ] + NLSF_QUANT_MAX_AMPLITUDE, &psEncC->psNLSF_CB->ec_iCDF[ ec_ix[ i ] ], 8 ); + } + } + + /* Encode NLSF interpolation factor */ + if( psEncC->nb_subfr == MAX_NB_SUBFR ) { + silk_assert( psIndices->NLSFInterpCoef_Q2 >= 0 && psIndices->NLSFInterpCoef_Q2 < 5 ); + ec_enc_icdf( psRangeEnc, psIndices->NLSFInterpCoef_Q2, silk_NLSF_interpolation_factor_iCDF, 8 ); + } + + if( psIndices->signalType == TYPE_VOICED ) + { + /*********************/ + /* Encode pitch lags */ + /*********************/ + /* lag index */ + encode_absolute_lagIndex = 1; + if( condCoding == CODE_CONDITIONALLY && psEncC->ec_prevSignalType == TYPE_VOICED ) { + /* Delta Encoding */ + delta_lagIndex = psIndices->lagIndex - psEncC->ec_prevLagIndex; + if( delta_lagIndex < -8 || delta_lagIndex > 11 ) { + delta_lagIndex = 0; + } else { + delta_lagIndex = delta_lagIndex + 9; + encode_absolute_lagIndex = 0; /* Only use delta */ + } + silk_assert( delta_lagIndex >= 0 && delta_lagIndex < 21 ); + ec_enc_icdf( psRangeEnc, delta_lagIndex, silk_pitch_delta_iCDF, 8 ); + } + if( encode_absolute_lagIndex ) { + /* Absolute encoding */ + opus_int32 pitch_high_bits, pitch_low_bits; + pitch_high_bits = silk_DIV32_16( psIndices->lagIndex, silk_RSHIFT( psEncC->fs_kHz, 1 ) ); + pitch_low_bits = psIndices->lagIndex - silk_SMULBB( pitch_high_bits, silk_RSHIFT( psEncC->fs_kHz, 1 ) ); + silk_assert( pitch_low_bits < psEncC->fs_kHz / 2 ); + silk_assert( pitch_high_bits < 32 ); + ec_enc_icdf( psRangeEnc, pitch_high_bits, silk_pitch_lag_iCDF, 8 ); + ec_enc_icdf( psRangeEnc, pitch_low_bits, psEncC->pitch_lag_low_bits_iCDF, 8 ); + } + psEncC->ec_prevLagIndex = psIndices->lagIndex; + + /* Countour index */ + silk_assert( psIndices->contourIndex >= 0 ); + silk_assert( ( 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 ) ); + ec_enc_icdf( psRangeEnc, psIndices->contourIndex, psEncC->pitch_contour_iCDF, 8 ); + + /********************/ + /* Encode LTP gains */ + /********************/ + /* PERIndex value */ + silk_assert( psIndices->PERIndex >= 0 && psIndices->PERIndex < 3 ); + ec_enc_icdf( psRangeEnc, psIndices->PERIndex, silk_LTP_per_index_iCDF, 8 ); + + /* Codebook Indices */ + for( k = 0; k < psEncC->nb_subfr; k++ ) { + silk_assert( psIndices->LTPIndex[ k ] >= 0 && psIndices->LTPIndex[ k ] < ( 8 << psIndices->PERIndex ) ); + ec_enc_icdf( psRangeEnc, psIndices->LTPIndex[ k ], silk_LTP_gain_iCDF_ptrs[ psIndices->PERIndex ], 8 ); + } + + /**********************/ + /* Encode LTP scaling */ + /**********************/ + if( condCoding == CODE_INDEPENDENTLY ) { + silk_assert( psIndices->LTP_scaleIndex >= 0 && psIndices->LTP_scaleIndex < 3 ); + ec_enc_icdf( psRangeEnc, psIndices->LTP_scaleIndex, silk_LTPscale_iCDF, 8 ); + } + silk_assert( !condCoding || psIndices->LTP_scaleIndex == 0 ); + } + + psEncC->ec_prevSignalType = psIndices->signalType; + + /***************/ + /* Encode seed */ + /***************/ + silk_assert( psIndices->Seed >= 0 && psIndices->Seed < 4 ); + ec_enc_icdf( psRangeEnc, psIndices->Seed, silk_uniform4_iCDF, 8 ); +} diff --git a/extern/opus/silk/encode_pulses.c b/extern/opus/silk/encode_pulses.c new file mode 100644 index 0000000..8a19991 --- /dev/null +++ b/extern/opus/silk/encode_pulses.c @@ -0,0 +1,206 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" +#include "stack_alloc.h" + +/*********************************************/ +/* Encode quantization indices of excitation */ +/*********************************************/ + +static OPUS_INLINE opus_int combine_and_check( /* return ok */ + opus_int *pulses_comb, /* O */ + const opus_int *pulses_in, /* I */ + opus_int max_pulses, /* I max value for sum of pulses */ + opus_int len /* I number of output values */ +) +{ + opus_int k, sum; + + for( k = 0; k < len; k++ ) { + sum = pulses_in[ 2 * k ] + pulses_in[ 2 * k + 1 ]; + if( sum > max_pulses ) { + return 1; + } + pulses_comb[ k ] = sum; + } + + return 0; +} + +/* Encode quantization indices of excitation */ +void silk_encode_pulses( + ec_enc *psRangeEnc, /* I/O compressor data structure */ + const opus_int signalType, /* I Signal type */ + const opus_int quantOffsetType, /* I quantOffsetType */ + opus_int8 pulses[], /* I quantization indices */ + const opus_int frame_length /* I Frame length */ +) +{ + opus_int i, k, j, iter, bit, nLS, scale_down, RateLevelIndex = 0; + opus_int32 abs_q, minSumBits_Q5, sumBits_Q5; + VARDECL( opus_int, abs_pulses ); + VARDECL( opus_int, sum_pulses ); + VARDECL( opus_int, nRshifts ); + opus_int pulses_comb[ 8 ]; + opus_int *abs_pulses_ptr; + const opus_int8 *pulses_ptr; + const opus_uint8 *cdf_ptr; + const opus_uint8 *nBits_ptr; + SAVE_STACK; + + silk_memset( pulses_comb, 0, 8 * sizeof( opus_int ) ); /* Fixing Valgrind reported problem*/ + + /****************************/ + /* Prepare for shell coding */ + /****************************/ + /* Calculate number of shell blocks */ + silk_assert( 1 << LOG2_SHELL_CODEC_FRAME_LENGTH == SHELL_CODEC_FRAME_LENGTH ); + iter = silk_RSHIFT( frame_length, LOG2_SHELL_CODEC_FRAME_LENGTH ); + if( iter * SHELL_CODEC_FRAME_LENGTH < frame_length ) { + celt_assert( frame_length == 12 * 10 ); /* Make sure only happens for 10 ms @ 12 kHz */ + iter++; + silk_memset( &pulses[ frame_length ], 0, SHELL_CODEC_FRAME_LENGTH * sizeof(opus_int8)); + } + + /* Take the absolute value of the pulses */ + ALLOC( abs_pulses, iter * SHELL_CODEC_FRAME_LENGTH, opus_int ); + silk_assert( !( SHELL_CODEC_FRAME_LENGTH & 3 ) ); + for( i = 0; i < iter * SHELL_CODEC_FRAME_LENGTH; i+=4 ) { + abs_pulses[i+0] = ( opus_int )silk_abs( pulses[ i + 0 ] ); + abs_pulses[i+1] = ( opus_int )silk_abs( pulses[ i + 1 ] ); + abs_pulses[i+2] = ( opus_int )silk_abs( pulses[ i + 2 ] ); + abs_pulses[i+3] = ( opus_int )silk_abs( pulses[ i + 3 ] ); + } + + /* Calc sum pulses per shell code frame */ + ALLOC( sum_pulses, iter, opus_int ); + ALLOC( nRshifts, iter, opus_int ); + abs_pulses_ptr = abs_pulses; + for( i = 0; i < iter; i++ ) { + nRshifts[ i ] = 0; + + while( 1 ) { + /* 1+1 -> 2 */ + scale_down = combine_and_check( pulses_comb, abs_pulses_ptr, silk_max_pulses_table[ 0 ], 8 ); + /* 2+2 -> 4 */ + scale_down += combine_and_check( pulses_comb, pulses_comb, silk_max_pulses_table[ 1 ], 4 ); + /* 4+4 -> 8 */ + scale_down += combine_and_check( pulses_comb, pulses_comb, silk_max_pulses_table[ 2 ], 2 ); + /* 8+8 -> 16 */ + scale_down += combine_and_check( &sum_pulses[ i ], pulses_comb, silk_max_pulses_table[ 3 ], 1 ); + + if( scale_down ) { + /* We need to downscale the quantization signal */ + nRshifts[ i ]++; + for( k = 0; k < SHELL_CODEC_FRAME_LENGTH; k++ ) { + abs_pulses_ptr[ k ] = silk_RSHIFT( abs_pulses_ptr[ k ], 1 ); + } + } else { + /* Jump out of while(1) loop and go to next shell coding frame */ + break; + } + } + abs_pulses_ptr += SHELL_CODEC_FRAME_LENGTH; + } + + /**************/ + /* Rate level */ + /**************/ + /* find rate level that leads to fewest bits for coding of pulses per block info */ + minSumBits_Q5 = silk_int32_MAX; + for( k = 0; k < N_RATE_LEVELS - 1; k++ ) { + nBits_ptr = silk_pulses_per_block_BITS_Q5[ k ]; + sumBits_Q5 = silk_rate_levels_BITS_Q5[ signalType >> 1 ][ k ]; + for( i = 0; i < iter; i++ ) { + if( nRshifts[ i ] > 0 ) { + sumBits_Q5 += nBits_ptr[ SILK_MAX_PULSES + 1 ]; + } else { + sumBits_Q5 += nBits_ptr[ sum_pulses[ i ] ]; + } + } + if( sumBits_Q5 < minSumBits_Q5 ) { + minSumBits_Q5 = sumBits_Q5; + RateLevelIndex = k; + } + } + ec_enc_icdf( psRangeEnc, RateLevelIndex, silk_rate_levels_iCDF[ signalType >> 1 ], 8 ); + + /***************************************************/ + /* Sum-Weighted-Pulses Encoding */ + /***************************************************/ + cdf_ptr = silk_pulses_per_block_iCDF[ RateLevelIndex ]; + for( i = 0; i < iter; i++ ) { + if( nRshifts[ i ] == 0 ) { + ec_enc_icdf( psRangeEnc, sum_pulses[ i ], cdf_ptr, 8 ); + } else { + ec_enc_icdf( psRangeEnc, SILK_MAX_PULSES + 1, cdf_ptr, 8 ); + for( k = 0; k < nRshifts[ i ] - 1; k++ ) { + ec_enc_icdf( psRangeEnc, SILK_MAX_PULSES + 1, silk_pulses_per_block_iCDF[ N_RATE_LEVELS - 1 ], 8 ); + } + ec_enc_icdf( psRangeEnc, sum_pulses[ i ], silk_pulses_per_block_iCDF[ N_RATE_LEVELS - 1 ], 8 ); + } + } + + /******************/ + /* Shell Encoding */ + /******************/ + for( i = 0; i < iter; i++ ) { + if( sum_pulses[ i ] > 0 ) { + silk_shell_encoder( psRangeEnc, &abs_pulses[ i * SHELL_CODEC_FRAME_LENGTH ] ); + } + } + + /****************/ + /* LSB Encoding */ + /****************/ + for( i = 0; i < iter; i++ ) { + if( nRshifts[ i ] > 0 ) { + pulses_ptr = &pulses[ i * SHELL_CODEC_FRAME_LENGTH ]; + nLS = nRshifts[ i ] - 1; + for( k = 0; k < SHELL_CODEC_FRAME_LENGTH; k++ ) { + abs_q = (opus_int8)silk_abs( pulses_ptr[ k ] ); + for( j = nLS; j > 0; j-- ) { + bit = silk_RSHIFT( abs_q, j ) & 1; + ec_enc_icdf( psRangeEnc, bit, silk_lsb_iCDF, 8 ); + } + bit = abs_q & 1; + ec_enc_icdf( psRangeEnc, bit, silk_lsb_iCDF, 8 ); + } + } + } + + /****************/ + /* Encode signs */ + /****************/ + silk_encode_signs( psRangeEnc, pulses, frame_length, signalType, quantOffsetType, sum_pulses ); + RESTORE_STACK; +} diff --git a/extern/opus/silk/errors.h b/extern/opus/silk/errors.h new file mode 100644 index 0000000..4507080 --- /dev/null +++ b/extern/opus/silk/errors.h @@ -0,0 +1,98 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifndef SILK_ERRORS_H +#define SILK_ERRORS_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/******************/ +/* Error messages */ +/******************/ +#define SILK_NO_ERROR 0 + +/**************************/ +/* Encoder error messages */ +/**************************/ + +/* Input length is not a multiple of 10 ms, or length is longer than the packet length */ +#define SILK_ENC_INPUT_INVALID_NO_OF_SAMPLES -101 + +/* Sampling frequency not 8000, 12000 or 16000 Hertz */ +#define SILK_ENC_FS_NOT_SUPPORTED -102 + +/* Packet size not 10, 20, 40, or 60 ms */ +#define SILK_ENC_PACKET_SIZE_NOT_SUPPORTED -103 + +/* Allocated payload buffer too short */ +#define SILK_ENC_PAYLOAD_BUF_TOO_SHORT -104 + +/* Loss rate not between 0 and 100 percent */ +#define SILK_ENC_INVALID_LOSS_RATE -105 + +/* Complexity setting not valid, use 0...10 */ +#define SILK_ENC_INVALID_COMPLEXITY_SETTING -106 + +/* Inband FEC setting not valid, use 0 or 1 */ +#define SILK_ENC_INVALID_INBAND_FEC_SETTING -107 + +/* DTX setting not valid, use 0 or 1 */ +#define SILK_ENC_INVALID_DTX_SETTING -108 + +/* CBR setting not valid, use 0 or 1 */ +#define SILK_ENC_INVALID_CBR_SETTING -109 + +/* Internal encoder error */ +#define SILK_ENC_INTERNAL_ERROR -110 + +/* Internal encoder error */ +#define SILK_ENC_INVALID_NUMBER_OF_CHANNELS_ERROR -111 + +/**************************/ +/* Decoder error messages */ +/**************************/ + +/* Output sampling frequency lower than internal decoded sampling frequency */ +#define SILK_DEC_INVALID_SAMPLING_FREQUENCY -200 + +/* Payload size exceeded the maximum allowed 1024 bytes */ +#define SILK_DEC_PAYLOAD_TOO_LARGE -201 + +/* Payload has bit errors */ +#define SILK_DEC_PAYLOAD_ERROR -202 + +/* Payload has bit errors */ +#define SILK_DEC_INVALID_FRAME_SIZE -203 + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/extern/opus/silk/fixed/LTP_analysis_filter_FIX.c b/extern/opus/silk/fixed/LTP_analysis_filter_FIX.c new file mode 100644 index 0000000..5574e70 --- /dev/null +++ b/extern/opus/silk/fixed/LTP_analysis_filter_FIX.c @@ -0,0 +1,90 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FIX.h" + +void silk_LTP_analysis_filter_FIX( + opus_int16 *LTP_res, /* O LTP residual signal of length MAX_NB_SUBFR * ( pre_length + subfr_length ) */ + const opus_int16 *x, /* I Pointer to input signal with at least max( pitchL ) preceding samples */ + const opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ],/* I LTP_ORDER LTP coefficients for each MAX_NB_SUBFR subframe */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lag, one for each subframe */ + const opus_int32 invGains_Q16[ MAX_NB_SUBFR ], /* I Inverse quantization gains, one for each subframe */ + const opus_int subfr_length, /* I Length of each subframe */ + const opus_int nb_subfr, /* I Number of subframes */ + const opus_int pre_length /* I Length of the preceding samples starting at &x[0] for each subframe */ +) +{ + const opus_int16 *x_ptr, *x_lag_ptr; + opus_int16 Btmp_Q14[ LTP_ORDER ]; + opus_int16 *LTP_res_ptr; + opus_int k, i; + opus_int32 LTP_est; + + x_ptr = x; + LTP_res_ptr = LTP_res; + for( k = 0; k < nb_subfr; k++ ) { + + x_lag_ptr = x_ptr - pitchL[ k ]; + + Btmp_Q14[ 0 ] = LTPCoef_Q14[ k * LTP_ORDER ]; + Btmp_Q14[ 1 ] = LTPCoef_Q14[ k * LTP_ORDER + 1 ]; + Btmp_Q14[ 2 ] = LTPCoef_Q14[ k * LTP_ORDER + 2 ]; + Btmp_Q14[ 3 ] = LTPCoef_Q14[ k * LTP_ORDER + 3 ]; + Btmp_Q14[ 4 ] = LTPCoef_Q14[ k * LTP_ORDER + 4 ]; + + /* LTP analysis FIR filter */ + for( i = 0; i < subfr_length + pre_length; i++ ) { + LTP_res_ptr[ i ] = x_ptr[ i ]; + + /* Long-term prediction */ + LTP_est = silk_SMULBB( x_lag_ptr[ LTP_ORDER / 2 ], Btmp_Q14[ 0 ] ); + LTP_est = silk_SMLABB_ovflw( LTP_est, x_lag_ptr[ 1 ], Btmp_Q14[ 1 ] ); + LTP_est = silk_SMLABB_ovflw( LTP_est, x_lag_ptr[ 0 ], Btmp_Q14[ 2 ] ); + LTP_est = silk_SMLABB_ovflw( LTP_est, x_lag_ptr[ -1 ], Btmp_Q14[ 3 ] ); + LTP_est = silk_SMLABB_ovflw( LTP_est, x_lag_ptr[ -2 ], Btmp_Q14[ 4 ] ); + + LTP_est = silk_RSHIFT_ROUND( LTP_est, 14 ); /* round and -> Q0*/ + + /* Subtract long-term prediction */ + LTP_res_ptr[ i ] = (opus_int16)silk_SAT16( (opus_int32)x_ptr[ i ] - LTP_est ); + + /* Scale residual */ + LTP_res_ptr[ i ] = silk_SMULWB( invGains_Q16[ k ], LTP_res_ptr[ i ] ); + + x_lag_ptr++; + } + + /* Update pointers */ + LTP_res_ptr += subfr_length + pre_length; + x_ptr += subfr_length; + } +} + diff --git a/extern/opus/silk/fixed/LTP_scale_ctrl_FIX.c b/extern/opus/silk/fixed/LTP_scale_ctrl_FIX.c new file mode 100644 index 0000000..3dcedef --- /dev/null +++ b/extern/opus/silk/fixed/LTP_scale_ctrl_FIX.c @@ -0,0 +1,53 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FIX.h" + +/* Calculation of LTP state scaling */ +void silk_LTP_scale_ctrl_FIX( + silk_encoder_state_FIX *psEnc, /* I/O encoder state */ + silk_encoder_control_FIX *psEncCtrl, /* I/O encoder control */ + opus_int condCoding /* I The type of conditional coding to use */ +) +{ + opus_int round_loss; + + if( condCoding == CODE_INDEPENDENTLY ) { + /* Only scale if first frame in packet */ + round_loss = psEnc->sCmn.PacketLoss_perc + psEnc->sCmn.nFramesPerPacket; + psEnc->sCmn.indices.LTP_scaleIndex = (opus_int8)silk_LIMIT( + silk_SMULWB( silk_SMULBB( round_loss, psEncCtrl->LTPredCodGain_Q7 ), SILK_FIX_CONST( 0.1, 9 ) ), 0, 2 ); + } else { + /* Default is minimum scaling */ + psEnc->sCmn.indices.LTP_scaleIndex = 0; + } + psEncCtrl->LTP_scale_Q14 = silk_LTPScales_table_Q14[ psEnc->sCmn.indices.LTP_scaleIndex ]; +} diff --git a/extern/opus/silk/fixed/apply_sine_window_FIX.c b/extern/opus/silk/fixed/apply_sine_window_FIX.c new file mode 100644 index 0000000..03e088a --- /dev/null +++ b/extern/opus/silk/fixed/apply_sine_window_FIX.c @@ -0,0 +1,101 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" + +/* Apply sine window to signal vector. */ +/* Window types: */ +/* 1 -> sine window from 0 to pi/2 */ +/* 2 -> sine window from pi/2 to pi */ +/* Every other sample is linearly interpolated, for speed. */ +/* Window length must be between 16 and 120 (incl) and a multiple of 4. */ + +/* Matlab code for table: + for k=16:9*4:16+2*9*4, fprintf(' %7.d,', -round(65536*pi ./ (k:4:k+8*4))); fprintf('\n'); end +*/ +static const opus_int16 freq_table_Q16[ 27 ] = { + 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, +}; + +void silk_apply_sine_window( + opus_int16 px_win[], /* O Pointer to windowed signal */ + const opus_int16 px[], /* I Pointer to input signal */ + const opus_int win_type, /* I Selects a window type */ + const opus_int length /* I Window length, multiple of 4 */ +) +{ + opus_int k, f_Q16, c_Q16; + opus_int32 S0_Q16, S1_Q16; + + celt_assert( win_type == 1 || win_type == 2 ); + + /* Length must be in a range from 16 to 120 and a multiple of 4 */ + celt_assert( length >= 16 && length <= 120 ); + celt_assert( ( length & 3 ) == 0 ); + + /* Frequency */ + k = ( length >> 2 ) - 4; + celt_assert( k >= 0 && k <= 26 ); + f_Q16 = (opus_int)freq_table_Q16[ k ]; + + /* Factor used for cosine approximation */ + c_Q16 = silk_SMULWB( (opus_int32)f_Q16, -f_Q16 ); + silk_assert( c_Q16 >= -32768 ); + + /* initialize state */ + if( win_type == 1 ) { + /* start from 0 */ + S0_Q16 = 0; + /* approximation of sin(f) */ + S1_Q16 = f_Q16 + silk_RSHIFT( length, 3 ); + } else { + /* start from 1 */ + S0_Q16 = ( (opus_int32)1 << 16 ); + /* approximation of cos(f) */ + S1_Q16 = ( (opus_int32)1 << 16 ) + silk_RSHIFT( c_Q16, 1 ) + silk_RSHIFT( length, 4 ); + } + + /* Uses the recursive equation: sin(n*f) = 2 * cos(f) * sin((n-1)*f) - sin((n-2)*f) */ + /* 4 samples at a time */ + for( k = 0; k < length; k += 4 ) { + px_win[ k ] = (opus_int16)silk_SMULWB( silk_RSHIFT( S0_Q16 + S1_Q16, 1 ), px[ k ] ); + px_win[ k + 1 ] = (opus_int16)silk_SMULWB( S1_Q16, px[ k + 1] ); + S0_Q16 = silk_SMULWB( S1_Q16, c_Q16 ) + silk_LSHIFT( S1_Q16, 1 ) - S0_Q16 + 1; + S0_Q16 = silk_min( S0_Q16, ( (opus_int32)1 << 16 ) ); + + px_win[ k + 2 ] = (opus_int16)silk_SMULWB( silk_RSHIFT( S0_Q16 + S1_Q16, 1 ), px[ k + 2] ); + px_win[ k + 3 ] = (opus_int16)silk_SMULWB( S0_Q16, px[ k + 3 ] ); + S1_Q16 = silk_SMULWB( S0_Q16, c_Q16 ) + silk_LSHIFT( S0_Q16, 1 ) - S1_Q16; + S1_Q16 = silk_min( S1_Q16, ( (opus_int32)1 << 16 ) ); + } +} diff --git a/extern/opus/silk/fixed/arm/warped_autocorrelation_FIX_arm.h b/extern/opus/silk/fixed/arm/warped_autocorrelation_FIX_arm.h new file mode 100644 index 0000000..1992e43 --- /dev/null +++ b/extern/opus/silk/fixed/arm/warped_autocorrelation_FIX_arm.h @@ -0,0 +1,68 @@ +/*********************************************************************** +Copyright (c) 2017 Google Inc. +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 OWNER 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. +***********************************************************************/ + +#ifndef SILK_WARPED_AUTOCORRELATION_FIX_ARM_H +# define SILK_WARPED_AUTOCORRELATION_FIX_ARM_H + +# include "celt/arm/armcpu.h" + +# if defined(FIXED_POINT) + +# if defined(OPUS_ARM_MAY_HAVE_NEON_INTR) +void silk_warped_autocorrelation_FIX_neon( + opus_int32 *corr, /* O Result [order + 1] */ + opus_int *scale, /* O Scaling of the correlation vector */ + const opus_int16 *input, /* I Input data to correlate */ + const opus_int warping_Q16, /* I Warping coefficient */ + const opus_int length, /* I Length of input */ + const opus_int order /* I Correlation order (even) */ +); + +# if !defined(OPUS_HAVE_RTCD) && defined(OPUS_ARM_PRESUME_NEON) +# define OVERRIDE_silk_warped_autocorrelation_FIX (1) +# define silk_warped_autocorrelation_FIX(corr, scale, input, warping_Q16, length, order, arch) \ + ((void)(arch), PRESUME_NEON(silk_warped_autocorrelation_FIX)(corr, scale, input, warping_Q16, length, order)) +# endif +# endif + +# if !defined(OVERRIDE_silk_warped_autocorrelation_FIX) +/*Is run-time CPU detection enabled on this platform?*/ +# if defined(OPUS_HAVE_RTCD) && (defined(OPUS_ARM_MAY_HAVE_NEON_INTR) && !defined(OPUS_ARM_PRESUME_NEON_INTR)) +extern void (*const SILK_WARPED_AUTOCORRELATION_FIX_IMPL[OPUS_ARCHMASK+1])(opus_int32*, opus_int*, const opus_int16*, const opus_int, const opus_int, const opus_int); +# define OVERRIDE_silk_warped_autocorrelation_FIX (1) +# define silk_warped_autocorrelation_FIX(corr, scale, input, warping_Q16, length, order, arch) \ + ((*SILK_WARPED_AUTOCORRELATION_FIX_IMPL[(arch)&OPUS_ARCHMASK])(corr, scale, input, warping_Q16, length, order)) +# elif defined(OPUS_ARM_PRESUME_NEON_INTR) +# define OVERRIDE_silk_warped_autocorrelation_FIX (1) +# define silk_warped_autocorrelation_FIX(corr, scale, input, warping_Q16, length, order, arch) \ + ((void)(arch), silk_warped_autocorrelation_FIX_neon(corr, scale, input, warping_Q16, length, order)) +# endif +# endif + +# endif /* end FIXED_POINT */ + +#endif /* end SILK_WARPED_AUTOCORRELATION_FIX_ARM_H */ diff --git a/extern/opus/silk/fixed/arm/warped_autocorrelation_FIX_neon_intr.c b/extern/opus/silk/fixed/arm/warped_autocorrelation_FIX_neon_intr.c new file mode 100644 index 0000000..00a70cb --- /dev/null +++ b/extern/opus/silk/fixed/arm/warped_autocorrelation_FIX_neon_intr.c @@ -0,0 +1,260 @@ +/*********************************************************************** +Copyright (c) 2017 Google Inc., Jean-Marc Valin +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#ifdef OPUS_CHECK_ASM +# include +#endif +#include "stack_alloc.h" +#include "main_FIX.h" + +static OPUS_INLINE void calc_corr( const opus_int32 *const input_QS, opus_int64 *const corr_QC, const opus_int offset, const int32x4_t state_QS_s32x4 ) +{ + int64x2_t corr_QC_s64x2[ 2 ], t_s64x2[ 2 ]; + const int32x4_t input_QS_s32x4 = vld1q_s32( input_QS + offset ); + corr_QC_s64x2[ 0 ] = vld1q_s64( corr_QC + offset + 0 ); + corr_QC_s64x2[ 1 ] = vld1q_s64( corr_QC + offset + 2 ); + t_s64x2[ 0 ] = vmull_s32( vget_low_s32( state_QS_s32x4 ), vget_low_s32( input_QS_s32x4 ) ); + t_s64x2[ 1 ] = vmull_s32( vget_high_s32( state_QS_s32x4 ), vget_high_s32( input_QS_s32x4 ) ); + corr_QC_s64x2[ 0 ] = vsraq_n_s64( corr_QC_s64x2[ 0 ], t_s64x2[ 0 ], 2 * QS - QC ); + corr_QC_s64x2[ 1 ] = vsraq_n_s64( corr_QC_s64x2[ 1 ], t_s64x2[ 1 ], 2 * QS - QC ); + vst1q_s64( corr_QC + offset + 0, corr_QC_s64x2[ 0 ] ); + vst1q_s64( corr_QC + offset + 2, corr_QC_s64x2[ 1 ] ); +} + +static OPUS_INLINE int32x4_t calc_state( const int32x4_t state_QS0_s32x4, const int32x4_t state_QS0_1_s32x4, const int32x4_t state_QS1_1_s32x4, const int32x4_t warping_Q16_s32x4 ) +{ + int32x4_t t_s32x4 = vsubq_s32( state_QS0_s32x4, state_QS0_1_s32x4 ); + t_s32x4 = vqdmulhq_s32( t_s32x4, warping_Q16_s32x4 ); + return vaddq_s32( state_QS1_1_s32x4, t_s32x4 ); +} + +void silk_warped_autocorrelation_FIX_neon( + opus_int32 *corr, /* O Result [order + 1] */ + opus_int *scale, /* O Scaling of the correlation vector */ + const opus_int16 *input, /* I Input data to correlate */ + const opus_int warping_Q16, /* I Warping coefficient */ + const opus_int length, /* I Length of input */ + const opus_int order /* I Correlation order (even) */ +) +{ + if( ( MAX_SHAPE_LPC_ORDER > 24 ) || ( order < 6 ) ) { + silk_warped_autocorrelation_FIX_c( corr, scale, input, warping_Q16, length, order ); + } else { + opus_int n, i, lsh; + opus_int64 corr_QC[ MAX_SHAPE_LPC_ORDER + 1 ] = { 0 }; /* In reverse order */ + opus_int64 corr_QC_orderT; + int64x2_t lsh_s64x2; + const opus_int orderT = ( order + 3 ) & ~3; + opus_int64 *corr_QCT; + opus_int32 *input_QS; + VARDECL( opus_int32, input_QST ); + VARDECL( opus_int32, state ); + SAVE_STACK; + + /* Order must be even */ + silk_assert( ( order & 1 ) == 0 ); + silk_assert( 2 * QS - QC >= 0 ); + + ALLOC( input_QST, length + 2 * MAX_SHAPE_LPC_ORDER, opus_int32 ); + + input_QS = input_QST; + /* input_QS has zero paddings in the beginning and end. */ + vst1q_s32( input_QS, vdupq_n_s32( 0 ) ); + input_QS += 4; + vst1q_s32( input_QS, vdupq_n_s32( 0 ) ); + input_QS += 4; + vst1q_s32( input_QS, vdupq_n_s32( 0 ) ); + input_QS += 4; + vst1q_s32( input_QS, vdupq_n_s32( 0 ) ); + input_QS += 4; + vst1q_s32( input_QS, vdupq_n_s32( 0 ) ); + input_QS += 4; + vst1q_s32( input_QS, vdupq_n_s32( 0 ) ); + input_QS += 4; + + /* Loop over samples */ + for( n = 0; n < length - 7; n += 8, input_QS += 8 ) { + const int16x8_t t0_s16x4 = vld1q_s16( input + n ); + vst1q_s32( input_QS + 0, vshll_n_s16( vget_low_s16( t0_s16x4 ), QS ) ); + vst1q_s32( input_QS + 4, vshll_n_s16( vget_high_s16( t0_s16x4 ), QS ) ); + } + for( ; n < length; n++, input_QS++ ) { + input_QS[ 0 ] = silk_LSHIFT32( (opus_int32)input[ n ], QS ); + } + vst1q_s32( input_QS, vdupq_n_s32( 0 ) ); + input_QS += 4; + vst1q_s32( input_QS, vdupq_n_s32( 0 ) ); + input_QS += 4; + vst1q_s32( input_QS, vdupq_n_s32( 0 ) ); + input_QS += 4; + vst1q_s32( input_QS, vdupq_n_s32( 0 ) ); + input_QS += 4; + vst1q_s32( input_QS, vdupq_n_s32( 0 ) ); + input_QS += 4; + vst1q_s32( input_QS, vdupq_n_s32( 0 ) ); + input_QS = input_QST + MAX_SHAPE_LPC_ORDER - orderT; + + /* The following loop runs ( length + order ) times, with ( order ) extra epilogues. */ + /* The zero paddings in input_QS guarantee corr_QC's correctness even with the extra epilogues. */ + /* The values of state_QS will be polluted by the extra epilogues, however they are temporary values. */ + + /* Keep the C code here to help understand the intrinsics optimization. */ + /* + { + opus_int32 state_QS[ 2 ][ MAX_SHAPE_LPC_ORDER + 1 ] = { 0 }; + opus_int32 *state_QST[ 3 ]; + state_QST[ 0 ] = state_QS[ 0 ]; + state_QST[ 1 ] = state_QS[ 1 ]; + for( n = 0; n < length + order; n++, input_QS++ ) { + state_QST[ 0 ][ orderT ] = input_QS[ orderT ]; + for( i = 0; i < orderT; i++ ) { + corr_QC[ i ] += silk_RSHIFT64( silk_SMULL( state_QST[ 0 ][ i ], input_QS[ i ] ), 2 * QS - QC ); + state_QST[ 1 ][ i ] = silk_SMLAWB( state_QST[ 1 ][ i + 1 ], state_QST[ 0 ][ i ] - state_QST[ 0 ][ i + 1 ], warping_Q16 ); + } + state_QST[ 2 ] = state_QST[ 0 ]; + state_QST[ 0 ] = state_QST[ 1 ]; + state_QST[ 1 ] = state_QST[ 2 ]; + } + } + */ + + { + const int32x4_t warping_Q16_s32x4 = vdupq_n_s32( warping_Q16 << 15 ); + const opus_int32 *in = input_QS + orderT; + opus_int o = orderT; + int32x4_t state_QS_s32x4[ 3 ][ 2 ]; + + ALLOC( state, length + orderT, opus_int32 ); + state_QS_s32x4[ 2 ][ 1 ] = vdupq_n_s32( 0 ); + + /* Calculate 8 taps of all inputs in each loop. */ + do { + state_QS_s32x4[ 0 ][ 0 ] = state_QS_s32x4[ 0 ][ 1 ] = + state_QS_s32x4[ 1 ][ 0 ] = state_QS_s32x4[ 1 ][ 1 ] = vdupq_n_s32( 0 ); + n = 0; + do { + calc_corr( input_QS + n, corr_QC, o - 8, state_QS_s32x4[ 0 ][ 0 ] ); + calc_corr( input_QS + n, corr_QC, o - 4, state_QS_s32x4[ 0 ][ 1 ] ); + state_QS_s32x4[ 2 ][ 1 ] = vld1q_s32( in + n ); + vst1q_lane_s32( state + n, state_QS_s32x4[ 0 ][ 0 ], 0 ); + state_QS_s32x4[ 2 ][ 0 ] = vextq_s32( state_QS_s32x4[ 0 ][ 0 ], state_QS_s32x4[ 0 ][ 1 ], 1 ); + state_QS_s32x4[ 2 ][ 1 ] = vextq_s32( state_QS_s32x4[ 0 ][ 1 ], state_QS_s32x4[ 2 ][ 1 ], 1 ); + state_QS_s32x4[ 0 ][ 0 ] = calc_state( state_QS_s32x4[ 0 ][ 0 ], state_QS_s32x4[ 2 ][ 0 ], state_QS_s32x4[ 1 ][ 0 ], warping_Q16_s32x4 ); + state_QS_s32x4[ 0 ][ 1 ] = calc_state( state_QS_s32x4[ 0 ][ 1 ], state_QS_s32x4[ 2 ][ 1 ], state_QS_s32x4[ 1 ][ 1 ], warping_Q16_s32x4 ); + state_QS_s32x4[ 1 ][ 0 ] = state_QS_s32x4[ 2 ][ 0 ]; + state_QS_s32x4[ 1 ][ 1 ] = state_QS_s32x4[ 2 ][ 1 ]; + } while( ++n < ( length + order ) ); + in = state; + o -= 8; + } while( o > 4 ); + + if( o ) { + /* Calculate the last 4 taps of all inputs. */ + opus_int32 *stateT = state; + silk_assert( o == 4 ); + state_QS_s32x4[ 0 ][ 0 ] = state_QS_s32x4[ 1 ][ 0 ] = vdupq_n_s32( 0 ); + n = length + order; + do { + calc_corr( input_QS, corr_QC, 0, state_QS_s32x4[ 0 ][ 0 ] ); + state_QS_s32x4[ 2 ][ 0 ] = vld1q_s32( stateT ); + vst1q_lane_s32( stateT, state_QS_s32x4[ 0 ][ 0 ], 0 ); + state_QS_s32x4[ 2 ][ 0 ] = vextq_s32( state_QS_s32x4[ 0 ][ 0 ], state_QS_s32x4[ 2 ][ 0 ], 1 ); + state_QS_s32x4[ 0 ][ 0 ] = calc_state( state_QS_s32x4[ 0 ][ 0 ], state_QS_s32x4[ 2 ][ 0 ], state_QS_s32x4[ 1 ][ 0 ], warping_Q16_s32x4 ); + state_QS_s32x4[ 1 ][ 0 ] = state_QS_s32x4[ 2 ][ 0 ]; + input_QS++; + stateT++; + } while( --n ); + } + } + + { + const opus_int16 *inputT = input; + int32x4_t t_s32x4; + int64x1_t t_s64x1; + int64x2_t t_s64x2 = vdupq_n_s64( 0 ); + for( n = 0; n <= length - 8; n += 8 ) { + int16x8_t input_s16x8 = vld1q_s16( inputT ); + t_s32x4 = vmull_s16( vget_low_s16( input_s16x8 ), vget_low_s16( input_s16x8 ) ); + t_s32x4 = vmlal_s16( t_s32x4, vget_high_s16( input_s16x8 ), vget_high_s16( input_s16x8 ) ); + t_s64x2 = vaddw_s32( t_s64x2, vget_low_s32( t_s32x4 ) ); + t_s64x2 = vaddw_s32( t_s64x2, vget_high_s32( t_s32x4 ) ); + inputT += 8; + } + t_s64x1 = vadd_s64( vget_low_s64( t_s64x2 ), vget_high_s64( t_s64x2 ) ); + corr_QC_orderT = vget_lane_s64( t_s64x1, 0 ); + for( ; n < length; n++ ) { + corr_QC_orderT += silk_SMULL( input[ n ], input[ n ] ); + } + corr_QC_orderT = silk_LSHIFT64( corr_QC_orderT, QC ); + corr_QC[ orderT ] = corr_QC_orderT; + } + + corr_QCT = corr_QC + orderT - order; + lsh = silk_CLZ64( corr_QC_orderT ) - 35; + lsh = silk_LIMIT( lsh, -12 - QC, 30 - QC ); + *scale = -( QC + lsh ); + silk_assert( *scale >= -30 && *scale <= 12 ); + lsh_s64x2 = vdupq_n_s64( lsh ); + for( i = 0; i <= order - 3; i += 4 ) { + int32x4_t corr_s32x4; + int64x2_t corr_QC0_s64x2, corr_QC1_s64x2; + corr_QC0_s64x2 = vld1q_s64( corr_QCT + i ); + corr_QC1_s64x2 = vld1q_s64( corr_QCT + i + 2 ); + corr_QC0_s64x2 = vshlq_s64( corr_QC0_s64x2, lsh_s64x2 ); + corr_QC1_s64x2 = vshlq_s64( corr_QC1_s64x2, lsh_s64x2 ); + corr_s32x4 = vcombine_s32( vmovn_s64( corr_QC1_s64x2 ), vmovn_s64( corr_QC0_s64x2 ) ); + corr_s32x4 = vrev64q_s32( corr_s32x4 ); + vst1q_s32( corr + order - i - 3, corr_s32x4 ); + } + if( lsh >= 0 ) { + for( ; i < order + 1; i++ ) { + corr[ order - i ] = (opus_int32)silk_CHECK_FIT32( silk_LSHIFT64( corr_QCT[ i ], lsh ) ); + } + } else { + for( ; i < order + 1; i++ ) { + corr[ order - i ] = (opus_int32)silk_CHECK_FIT32( silk_RSHIFT64( corr_QCT[ i ], -lsh ) ); + } + } + silk_assert( corr_QCT[ order ] >= 0 ); /* If breaking, decrease QC*/ + RESTORE_STACK; + } + +#ifdef OPUS_CHECK_ASM + { + opus_int32 corr_c[ MAX_SHAPE_LPC_ORDER + 1 ]; + opus_int scale_c; + silk_warped_autocorrelation_FIX_c( corr_c, &scale_c, input, warping_Q16, length, order ); + silk_assert( !memcmp( corr_c, corr, sizeof( corr_c[ 0 ] ) * ( order + 1 ) ) ); + silk_assert( scale_c == *scale ); + } +#endif +} diff --git a/extern/opus/silk/fixed/autocorr_FIX.c b/extern/opus/silk/fixed/autocorr_FIX.c new file mode 100644 index 0000000..de95c98 --- /dev/null +++ b/extern/opus/silk/fixed/autocorr_FIX.c @@ -0,0 +1,48 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" +#include "celt_lpc.h" + +/* Compute autocorrelation */ +void silk_autocorr( + opus_int32 *results, /* O Result (length correlationCount) */ + opus_int *scale, /* O Scaling of the correlation vector */ + const opus_int16 *inputData, /* I Input data to correlate */ + const opus_int inputDataSize, /* I Length of input */ + const opus_int correlationCount, /* I Number of correlation taps to compute */ + int arch /* I Run-time architecture */ +) +{ + opus_int corrCount; + corrCount = silk_min_int( inputDataSize, correlationCount ); + *scale = _celt_autocorr(inputData, results, NULL, 0, corrCount-1, inputDataSize, arch); +} diff --git a/extern/opus/silk/fixed/burg_modified_FIX.c b/extern/opus/silk/fixed/burg_modified_FIX.c new file mode 100644 index 0000000..274d4b2 --- /dev/null +++ b/extern/opus/silk/fixed/burg_modified_FIX.c @@ -0,0 +1,280 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" +#include "define.h" +#include "tuning_parameters.h" +#include "pitch.h" + +#define MAX_FRAME_SIZE 384 /* subfr_length * nb_subfr = ( 0.005 * 16000 + 16 ) * 4 = 384 */ + +#define QA 25 +#define N_BITS_HEAD_ROOM 3 +#define MIN_RSHIFTS -16 +#define MAX_RSHIFTS (32 - QA) + +/* Compute reflection coefficients from input signal */ +void silk_burg_modified_c( + opus_int32 *res_nrg, /* O Residual energy */ + opus_int *res_nrg_Q, /* O Residual energy Q value */ + opus_int32 A_Q16[], /* O Prediction coefficients (length order) */ + const opus_int16 x[], /* I Input signal, length: nb_subfr * ( D + subfr_length ) */ + const opus_int32 minInvGain_Q30, /* I Inverse of max prediction gain */ + const opus_int subfr_length, /* I Input signal subframe length (incl. D preceding samples) */ + const opus_int nb_subfr, /* I Number of subframes stacked in x */ + const opus_int D, /* I Order */ + int arch /* I Run-time architecture */ +) +{ + opus_int k, n, s, lz, rshifts, reached_max_gain; + opus_int32 C0, num, nrg, rc_Q31, invGain_Q30, Atmp_QA, Atmp1, tmp1, tmp2, x1, x2; + const opus_int16 *x_ptr; + opus_int32 C_first_row[ SILK_MAX_ORDER_LPC ]; + opus_int32 C_last_row[ SILK_MAX_ORDER_LPC ]; + opus_int32 Af_QA[ SILK_MAX_ORDER_LPC ]; + opus_int32 CAf[ SILK_MAX_ORDER_LPC + 1 ]; + opus_int32 CAb[ SILK_MAX_ORDER_LPC + 1 ]; + opus_int32 xcorr[ SILK_MAX_ORDER_LPC ]; + opus_int64 C0_64; + + celt_assert( subfr_length * nb_subfr <= MAX_FRAME_SIZE ); + + /* Compute autocorrelations, added over subframes */ + C0_64 = silk_inner_prod16_aligned_64( x, x, subfr_length*nb_subfr, arch ); + lz = silk_CLZ64(C0_64); + rshifts = 32 + 1 + N_BITS_HEAD_ROOM - lz; + if (rshifts > MAX_RSHIFTS) rshifts = MAX_RSHIFTS; + if (rshifts < MIN_RSHIFTS) rshifts = MIN_RSHIFTS; + + if (rshifts > 0) { + C0 = (opus_int32)silk_RSHIFT64(C0_64, rshifts ); + } else { + C0 = silk_LSHIFT32((opus_int32)C0_64, -rshifts ); + } + + CAb[ 0 ] = CAf[ 0 ] = C0 + silk_SMMUL( SILK_FIX_CONST( FIND_LPC_COND_FAC, 32 ), C0 ) + 1; /* Q(-rshifts) */ + silk_memset( C_first_row, 0, SILK_MAX_ORDER_LPC * sizeof( opus_int32 ) ); + if( rshifts > 0 ) { + for( s = 0; s < nb_subfr; s++ ) { + x_ptr = x + s * subfr_length; + for( n = 1; n < D + 1; n++ ) { + C_first_row[ n - 1 ] += (opus_int32)silk_RSHIFT64( + silk_inner_prod16_aligned_64( x_ptr, x_ptr + n, subfr_length - n, arch ), rshifts ); + } + } + } else { + for( s = 0; s < nb_subfr; s++ ) { + int i; + opus_int32 d; + x_ptr = x + s * subfr_length; + celt_pitch_xcorr(x_ptr, x_ptr + 1, xcorr, subfr_length - D, D, arch ); + for( n = 1; n < D + 1; n++ ) { + for ( i = n + subfr_length - D, d = 0; i < subfr_length; i++ ) + d = MAC16_16( d, x_ptr[ i ], x_ptr[ i - n ] ); + xcorr[ n - 1 ] += d; + } + for( n = 1; n < D + 1; n++ ) { + C_first_row[ n - 1 ] += silk_LSHIFT32( xcorr[ n - 1 ], -rshifts ); + } + } + } + silk_memcpy( C_last_row, C_first_row, SILK_MAX_ORDER_LPC * sizeof( opus_int32 ) ); + + /* Initialize */ + CAb[ 0 ] = CAf[ 0 ] = C0 + silk_SMMUL( SILK_FIX_CONST( FIND_LPC_COND_FAC, 32 ), C0 ) + 1; /* Q(-rshifts) */ + + invGain_Q30 = (opus_int32)1 << 30; + reached_max_gain = 0; + for( n = 0; n < D; n++ ) { + /* Update first row of correlation matrix (without first element) */ + /* Update last row of correlation matrix (without last element, stored in reversed order) */ + /* Update C * Af */ + /* Update C * flipud(Af) (stored in reversed order) */ + if( rshifts > -2 ) { + for( s = 0; s < nb_subfr; s++ ) { + x_ptr = x + s * subfr_length; + x1 = -silk_LSHIFT32( (opus_int32)x_ptr[ n ], 16 - rshifts ); /* Q(16-rshifts) */ + x2 = -silk_LSHIFT32( (opus_int32)x_ptr[ subfr_length - n - 1 ], 16 - rshifts ); /* Q(16-rshifts) */ + tmp1 = silk_LSHIFT32( (opus_int32)x_ptr[ n ], QA - 16 ); /* Q(QA-16) */ + tmp2 = silk_LSHIFT32( (opus_int32)x_ptr[ subfr_length - n - 1 ], QA - 16 ); /* Q(QA-16) */ + for( k = 0; k < n; k++ ) { + C_first_row[ k ] = silk_SMLAWB( C_first_row[ k ], x1, x_ptr[ n - k - 1 ] ); /* Q( -rshifts ) */ + C_last_row[ k ] = silk_SMLAWB( C_last_row[ k ], x2, x_ptr[ subfr_length - n + k ] ); /* Q( -rshifts ) */ + Atmp_QA = Af_QA[ k ]; + tmp1 = silk_SMLAWB( tmp1, Atmp_QA, x_ptr[ n - k - 1 ] ); /* Q(QA-16) */ + tmp2 = silk_SMLAWB( tmp2, Atmp_QA, x_ptr[ subfr_length - n + k ] ); /* Q(QA-16) */ + } + tmp1 = silk_LSHIFT32( -tmp1, 32 - QA - rshifts ); /* Q(16-rshifts) */ + tmp2 = silk_LSHIFT32( -tmp2, 32 - QA - rshifts ); /* Q(16-rshifts) */ + for( k = 0; k <= n; k++ ) { + CAf[ k ] = silk_SMLAWB( CAf[ k ], tmp1, x_ptr[ n - k ] ); /* Q( -rshift ) */ + CAb[ k ] = silk_SMLAWB( CAb[ k ], tmp2, x_ptr[ subfr_length - n + k - 1 ] ); /* Q( -rshift ) */ + } + } + } else { + for( s = 0; s < nb_subfr; s++ ) { + x_ptr = x + s * subfr_length; + x1 = -silk_LSHIFT32( (opus_int32)x_ptr[ n ], -rshifts ); /* Q( -rshifts ) */ + x2 = -silk_LSHIFT32( (opus_int32)x_ptr[ subfr_length - n - 1 ], -rshifts ); /* Q( -rshifts ) */ + tmp1 = silk_LSHIFT32( (opus_int32)x_ptr[ n ], 17 ); /* Q17 */ + tmp2 = silk_LSHIFT32( (opus_int32)x_ptr[ subfr_length - n - 1 ], 17 ); /* Q17 */ + for( k = 0; k < n; k++ ) { + C_first_row[ k ] = silk_MLA( C_first_row[ k ], x1, x_ptr[ n - k - 1 ] ); /* Q( -rshifts ) */ + C_last_row[ k ] = silk_MLA( C_last_row[ k ], x2, x_ptr[ subfr_length - n + k ] ); /* Q( -rshifts ) */ + Atmp1 = silk_RSHIFT_ROUND( Af_QA[ k ], QA - 17 ); /* Q17 */ + /* We sometimes have get overflows in the multiplications (even beyond +/- 2^32), + but they cancel each other and the real result seems to always fit in a 32-bit + signed integer. This was determined experimentally, not theoretically (unfortunately). */ + tmp1 = silk_MLA_ovflw( tmp1, x_ptr[ n - k - 1 ], Atmp1 ); /* Q17 */ + tmp2 = silk_MLA_ovflw( tmp2, x_ptr[ subfr_length - n + k ], Atmp1 ); /* Q17 */ + } + tmp1 = -tmp1; /* Q17 */ + tmp2 = -tmp2; /* Q17 */ + for( k = 0; k <= n; k++ ) { + CAf[ k ] = silk_SMLAWW( CAf[ k ], tmp1, + silk_LSHIFT32( (opus_int32)x_ptr[ n - k ], -rshifts - 1 ) ); /* Q( -rshift ) */ + CAb[ k ] = silk_SMLAWW( CAb[ k ], tmp2, + silk_LSHIFT32( (opus_int32)x_ptr[ subfr_length - n + k - 1 ], -rshifts - 1 ) ); /* Q( -rshift ) */ + } + } + } + + /* Calculate nominator and denominator for the next order reflection (parcor) coefficient */ + tmp1 = C_first_row[ n ]; /* Q( -rshifts ) */ + tmp2 = C_last_row[ n ]; /* Q( -rshifts ) */ + num = 0; /* Q( -rshifts ) */ + nrg = silk_ADD32( CAb[ 0 ], CAf[ 0 ] ); /* Q( 1-rshifts ) */ + for( k = 0; k < n; k++ ) { + Atmp_QA = Af_QA[ k ]; + lz = silk_CLZ32( silk_abs( Atmp_QA ) ) - 1; + lz = silk_min( 32 - QA, lz ); + Atmp1 = silk_LSHIFT32( Atmp_QA, lz ); /* Q( QA + lz ) */ + + tmp1 = silk_ADD_LSHIFT32( tmp1, silk_SMMUL( C_last_row[ n - k - 1 ], Atmp1 ), 32 - QA - lz ); /* Q( -rshifts ) */ + tmp2 = silk_ADD_LSHIFT32( tmp2, silk_SMMUL( C_first_row[ n - k - 1 ], Atmp1 ), 32 - QA - lz ); /* Q( -rshifts ) */ + num = silk_ADD_LSHIFT32( num, silk_SMMUL( CAb[ n - k ], Atmp1 ), 32 - QA - lz ); /* Q( -rshifts ) */ + nrg = silk_ADD_LSHIFT32( nrg, silk_SMMUL( silk_ADD32( CAb[ k + 1 ], CAf[ k + 1 ] ), + Atmp1 ), 32 - QA - lz ); /* Q( 1-rshifts ) */ + } + CAf[ n + 1 ] = tmp1; /* Q( -rshifts ) */ + CAb[ n + 1 ] = tmp2; /* Q( -rshifts ) */ + num = silk_ADD32( num, tmp2 ); /* Q( -rshifts ) */ + num = silk_LSHIFT32( -num, 1 ); /* Q( 1-rshifts ) */ + + /* Calculate the next order reflection (parcor) coefficient */ + if( silk_abs( num ) < nrg ) { + rc_Q31 = silk_DIV32_varQ( num, nrg, 31 ); + } else { + rc_Q31 = ( num > 0 ) ? silk_int32_MAX : silk_int32_MIN; + } + + /* Update inverse prediction gain */ + tmp1 = ( (opus_int32)1 << 30 ) - silk_SMMUL( rc_Q31, rc_Q31 ); + tmp1 = silk_LSHIFT( silk_SMMUL( invGain_Q30, tmp1 ), 2 ); + if( tmp1 <= minInvGain_Q30 ) { + /* Max prediction gain exceeded; set reflection coefficient such that max prediction gain is exactly hit */ + tmp2 = ( (opus_int32)1 << 30 ) - silk_DIV32_varQ( minInvGain_Q30, invGain_Q30, 30 ); /* Q30 */ + rc_Q31 = silk_SQRT_APPROX( tmp2 ); /* Q15 */ + if( rc_Q31 > 0 ) { + /* Newton-Raphson iteration */ + rc_Q31 = silk_RSHIFT32( rc_Q31 + silk_DIV32( tmp2, rc_Q31 ), 1 ); /* Q15 */ + rc_Q31 = silk_LSHIFT32( rc_Q31, 16 ); /* Q31 */ + if( num < 0 ) { + /* Ensure adjusted reflection coefficients has the original sign */ + rc_Q31 = -rc_Q31; + } + } + invGain_Q30 = minInvGain_Q30; + reached_max_gain = 1; + } else { + invGain_Q30 = tmp1; + } + + /* Update the AR coefficients */ + for( k = 0; k < (n + 1) >> 1; k++ ) { + tmp1 = Af_QA[ k ]; /* QA */ + tmp2 = Af_QA[ n - k - 1 ]; /* QA */ + Af_QA[ k ] = silk_ADD_LSHIFT32( tmp1, silk_SMMUL( tmp2, rc_Q31 ), 1 ); /* QA */ + Af_QA[ n - k - 1 ] = silk_ADD_LSHIFT32( tmp2, silk_SMMUL( tmp1, rc_Q31 ), 1 ); /* QA */ + } + Af_QA[ n ] = silk_RSHIFT32( rc_Q31, 31 - QA ); /* QA */ + + if( reached_max_gain ) { + /* Reached max prediction gain; set remaining coefficients to zero and exit loop */ + for( k = n + 1; k < D; k++ ) { + Af_QA[ k ] = 0; + } + break; + } + + /* Update C * Af and C * Ab */ + for( k = 0; k <= n + 1; k++ ) { + tmp1 = CAf[ k ]; /* Q( -rshifts ) */ + tmp2 = CAb[ n - k + 1 ]; /* Q( -rshifts ) */ + CAf[ k ] = silk_ADD_LSHIFT32( tmp1, silk_SMMUL( tmp2, rc_Q31 ), 1 ); /* Q( -rshifts ) */ + CAb[ n - k + 1 ] = silk_ADD_LSHIFT32( tmp2, silk_SMMUL( tmp1, rc_Q31 ), 1 ); /* Q( -rshifts ) */ + } + } + + if( reached_max_gain ) { + for( k = 0; k < D; k++ ) { + /* Scale coefficients */ + A_Q16[ k ] = -silk_RSHIFT_ROUND( Af_QA[ k ], QA - 16 ); + } + /* Subtract energy of preceding samples from C0 */ + if( rshifts > 0 ) { + for( s = 0; s < nb_subfr; s++ ) { + x_ptr = x + s * subfr_length; + C0 -= (opus_int32)silk_RSHIFT64( silk_inner_prod16_aligned_64( x_ptr, x_ptr, D, arch ), rshifts ); + } + } else { + for( s = 0; s < nb_subfr; s++ ) { + x_ptr = x + s * subfr_length; + C0 -= silk_LSHIFT32( silk_inner_prod_aligned( x_ptr, x_ptr, D, arch), -rshifts); + } + } + /* Approximate residual energy */ + *res_nrg = silk_LSHIFT( silk_SMMUL( invGain_Q30, C0 ), 2 ); + *res_nrg_Q = -rshifts; + } else { + /* Return residual energy */ + nrg = CAf[ 0 ]; /* Q( -rshifts ) */ + tmp1 = (opus_int32)1 << 16; /* Q16 */ + for( k = 0; k < D; k++ ) { + Atmp1 = silk_RSHIFT_ROUND( Af_QA[ k ], QA - 16 ); /* Q16 */ + nrg = silk_SMLAWW( nrg, CAf[ k + 1 ], Atmp1 ); /* Q( -rshifts ) */ + tmp1 = silk_SMLAWW( tmp1, Atmp1, Atmp1 ); /* Q16 */ + A_Q16[ k ] = -Atmp1; + } + *res_nrg = silk_SMLAWW( nrg, silk_SMMUL( SILK_FIX_CONST( FIND_LPC_COND_FAC, 32 ), C0 ), -tmp1 );/* Q( -rshifts ) */ + *res_nrg_Q = -rshifts; + } +} diff --git a/extern/opus/silk/fixed/corrMatrix_FIX.c b/extern/opus/silk/fixed/corrMatrix_FIX.c new file mode 100644 index 0000000..1b4a29c --- /dev/null +++ b/extern/opus/silk/fixed/corrMatrix_FIX.c @@ -0,0 +1,150 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/********************************************************************** + * Correlation Matrix Computations for LS estimate. + **********************************************************************/ + +#include "main_FIX.h" + +/* Calculates correlation vector X'*t */ +void silk_corrVector_FIX( + const opus_int16 *x, /* I x vector [L + order - 1] used to form data matrix X */ + const opus_int16 *t, /* I Target vector [L] */ + const opus_int L, /* I Length of vectors */ + const opus_int order, /* I Max lag for correlation */ + opus_int32 *Xt, /* O Pointer to X'*t correlation vector [order] */ + const opus_int rshifts, /* I Right shifts of correlations */ + int arch /* I Run-time architecture */ +) +{ + opus_int lag, i; + const opus_int16 *ptr1, *ptr2; + opus_int32 inner_prod; + + ptr1 = &x[ order - 1 ]; /* Points to first sample of column 0 of X: X[:,0] */ + ptr2 = t; + /* Calculate X'*t */ + if( rshifts > 0 ) { + /* Right shifting used */ + for( lag = 0; lag < order; lag++ ) { + inner_prod = 0; + for( i = 0; i < L; i++ ) { + inner_prod = silk_ADD_RSHIFT32( inner_prod, silk_SMULBB( ptr1[ i ], ptr2[i] ), rshifts ); + } + Xt[ lag ] = inner_prod; /* X[:,lag]'*t */ + ptr1--; /* Go to next column of X */ + } + } else { + silk_assert( rshifts == 0 ); + for( lag = 0; lag < order; lag++ ) { + Xt[ lag ] = silk_inner_prod_aligned( ptr1, ptr2, L, arch ); /* X[:,lag]'*t */ + ptr1--; /* Go to next column of X */ + } + } +} + +/* Calculates correlation matrix X'*X */ +void silk_corrMatrix_FIX( + const opus_int16 *x, /* I x vector [L + order - 1] used to form data matrix X */ + const opus_int L, /* I Length of vectors */ + const opus_int order, /* I Max lag for correlation */ + opus_int32 *XX, /* O Pointer to X'*X correlation matrix [ order x order ] */ + opus_int32 *nrg, /* O Energy of x vector */ + opus_int *rshifts, /* O Right shifts of correlations and energy */ + int arch /* I Run-time architecture */ +) +{ + opus_int i, j, lag; + opus_int32 energy; + const opus_int16 *ptr1, *ptr2; + + /* Calculate energy to find shift used to fit in 32 bits */ + silk_sum_sqr_shift( nrg, rshifts, x, L + order - 1 ); + energy = *nrg; + + /* Calculate energy of first column (0) of X: X[:,0]'*X[:,0] */ + /* Remove contribution of first order - 1 samples */ + for( i = 0; i < order - 1; i++ ) { + energy -= silk_RSHIFT32( silk_SMULBB( x[ i ], x[ i ] ), *rshifts ); + } + + /* Calculate energy of remaining columns of X: X[:,j]'*X[:,j] */ + /* Fill out the diagonal of the correlation matrix */ + matrix_ptr( XX, 0, 0, order ) = energy; + silk_assert( energy >= 0 ); + ptr1 = &x[ order - 1 ]; /* First sample of column 0 of X */ + for( j = 1; j < order; j++ ) { + energy = silk_SUB32( energy, silk_RSHIFT32( silk_SMULBB( ptr1[ L - j ], ptr1[ L - j ] ), *rshifts ) ); + energy = silk_ADD32( energy, silk_RSHIFT32( silk_SMULBB( ptr1[ -j ], ptr1[ -j ] ), *rshifts ) ); + matrix_ptr( XX, j, j, order ) = energy; + silk_assert( energy >= 0 ); + } + + ptr2 = &x[ order - 2 ]; /* First sample of column 1 of X */ + /* Calculate the remaining elements of the correlation matrix */ + if( *rshifts > 0 ) { + /* Right shifting used */ + for( lag = 1; lag < order; lag++ ) { + /* Inner product of column 0 and column lag: X[:,0]'*X[:,lag] */ + energy = 0; + for( i = 0; i < L; i++ ) { + energy += silk_RSHIFT32( silk_SMULBB( ptr1[ i ], ptr2[i] ), *rshifts ); + } + /* Calculate remaining off diagonal: X[:,j]'*X[:,j + lag] */ + matrix_ptr( XX, lag, 0, order ) = energy; + matrix_ptr( XX, 0, lag, order ) = energy; + for( j = 1; j < ( order - lag ); j++ ) { + energy = silk_SUB32( energy, silk_RSHIFT32( silk_SMULBB( ptr1[ L - j ], ptr2[ L - j ] ), *rshifts ) ); + energy = silk_ADD32( energy, silk_RSHIFT32( silk_SMULBB( ptr1[ -j ], ptr2[ -j ] ), *rshifts ) ); + matrix_ptr( XX, lag + j, j, order ) = energy; + matrix_ptr( XX, j, lag + j, order ) = energy; + } + ptr2--; /* Update pointer to first sample of next column (lag) in X */ + } + } else { + for( lag = 1; lag < order; lag++ ) { + /* Inner product of column 0 and column lag: X[:,0]'*X[:,lag] */ + energy = silk_inner_prod_aligned( ptr1, ptr2, L, arch ); + matrix_ptr( XX, lag, 0, order ) = energy; + matrix_ptr( XX, 0, lag, order ) = energy; + /* Calculate remaining off diagonal: X[:,j]'*X[:,j + lag] */ + for( j = 1; j < ( order - lag ); j++ ) { + energy = silk_SUB32( energy, silk_SMULBB( ptr1[ L - j ], ptr2[ L - j ] ) ); + energy = silk_SMLABB( energy, ptr1[ -j ], ptr2[ -j ] ); + matrix_ptr( XX, lag + j, j, order ) = energy; + matrix_ptr( XX, j, lag + j, order ) = energy; + } + ptr2--;/* Update pointer to first sample of next column (lag) in X */ + } + } +} + diff --git a/extern/opus/silk/fixed/encode_frame_FIX.c b/extern/opus/silk/fixed/encode_frame_FIX.c new file mode 100644 index 0000000..a02bf87 --- /dev/null +++ b/extern/opus/silk/fixed/encode_frame_FIX.c @@ -0,0 +1,448 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "main_FIX.h" +#include "stack_alloc.h" +#include "tuning_parameters.h" + +/* Low Bitrate Redundancy (LBRR) encoding. Reuse all parameters but encode with lower bitrate */ +static OPUS_INLINE void silk_LBRR_encode_FIX( + silk_encoder_state_FIX *psEnc, /* I/O Pointer to Silk FIX encoder state */ + silk_encoder_control_FIX *psEncCtrl, /* I/O Pointer to Silk FIX encoder control struct */ + const opus_int16 x16[], /* I Input signal */ + opus_int condCoding /* I The type of conditional coding used so far for this frame */ +); + +void silk_encode_do_VAD_FIX( + silk_encoder_state_FIX *psEnc, /* I/O Pointer to Silk FIX encoder state */ + opus_int activity /* I Decision of Opus voice activity detector */ +) +{ + const opus_int activity_threshold = SILK_FIX_CONST( SPEECH_ACTIVITY_DTX_THRES, 8 ); + + /****************************/ + /* Voice Activity Detection */ + /****************************/ + silk_VAD_GetSA_Q8( &psEnc->sCmn, psEnc->sCmn.inputBuf + 1, psEnc->sCmn.arch ); + /* If Opus VAD is inactive and Silk VAD is active: lower Silk VAD to just under the threshold */ + if( activity == VAD_NO_ACTIVITY && psEnc->sCmn.speech_activity_Q8 >= activity_threshold ) { + psEnc->sCmn.speech_activity_Q8 = activity_threshold - 1; + } + + /**************************************************/ + /* Convert speech activity into VAD and DTX flags */ + /**************************************************/ + if( psEnc->sCmn.speech_activity_Q8 < activity_threshold ) { + psEnc->sCmn.indices.signalType = TYPE_NO_VOICE_ACTIVITY; + psEnc->sCmn.noSpeechCounter++; + if( psEnc->sCmn.noSpeechCounter <= NB_SPEECH_FRAMES_BEFORE_DTX ) { + psEnc->sCmn.inDTX = 0; + } else if( psEnc->sCmn.noSpeechCounter > MAX_CONSECUTIVE_DTX + NB_SPEECH_FRAMES_BEFORE_DTX ) { + psEnc->sCmn.noSpeechCounter = NB_SPEECH_FRAMES_BEFORE_DTX; + psEnc->sCmn.inDTX = 0; + } + psEnc->sCmn.VAD_flags[ psEnc->sCmn.nFramesEncoded ] = 0; + } else { + psEnc->sCmn.noSpeechCounter = 0; + psEnc->sCmn.inDTX = 0; + psEnc->sCmn.indices.signalType = TYPE_UNVOICED; + psEnc->sCmn.VAD_flags[ psEnc->sCmn.nFramesEncoded ] = 1; + } +} + +/****************/ +/* Encode frame */ +/****************/ +opus_int silk_encode_frame_FIX( + silk_encoder_state_FIX *psEnc, /* I/O Pointer to Silk FIX encoder state */ + opus_int32 *pnBytesOut, /* O Pointer to number of payload bytes; */ + ec_enc *psRangeEnc, /* I/O compressor data structure */ + opus_int condCoding, /* I The type of conditional coding to use */ + opus_int maxBits, /* I If > 0: maximum number of output bits */ + opus_int useCBR /* I Flag to force constant-bitrate operation */ +) +{ + silk_encoder_control_FIX sEncCtrl; + opus_int i, iter, maxIter, found_upper, found_lower, ret = 0; + opus_int16 *x_frame; + ec_enc sRangeEnc_copy, sRangeEnc_copy2; + silk_nsq_state sNSQ_copy, sNSQ_copy2; + opus_int32 seed_copy, nBits, nBits_lower, nBits_upper, gainMult_lower, gainMult_upper; + opus_int32 gainsID, gainsID_lower, gainsID_upper; + opus_int16 gainMult_Q8; + opus_int16 ec_prevLagIndex_copy; + opus_int ec_prevSignalType_copy; + opus_int8 LastGainIndex_copy2; + opus_int gain_lock[ MAX_NB_SUBFR ] = {0}; + opus_int16 best_gain_mult[ MAX_NB_SUBFR ]; + opus_int best_sum[ MAX_NB_SUBFR ]; + SAVE_STACK; + + /* This is totally unnecessary but many compilers (including gcc) are too dumb to realise it */ + LastGainIndex_copy2 = nBits_lower = nBits_upper = gainMult_lower = gainMult_upper = 0; + + psEnc->sCmn.indices.Seed = psEnc->sCmn.frameCounter++ & 3; + + /**************************************************************/ + /* Set up Input Pointers, and insert frame in input buffer */ + /*************************************************************/ + /* start of frame to encode */ + x_frame = psEnc->x_buf + psEnc->sCmn.ltp_mem_length; + + /***************************************/ + /* Ensure smooth bandwidth transitions */ + /***************************************/ + silk_LP_variable_cutoff( &psEnc->sCmn.sLP, psEnc->sCmn.inputBuf + 1, psEnc->sCmn.frame_length ); + + /*******************************************/ + /* Copy new frame to front of input buffer */ + /*******************************************/ + silk_memcpy( x_frame + LA_SHAPE_MS * psEnc->sCmn.fs_kHz, psEnc->sCmn.inputBuf + 1, psEnc->sCmn.frame_length * sizeof( opus_int16 ) ); + + if( !psEnc->sCmn.prefillFlag ) { + VARDECL( opus_int16, res_pitch ); + VARDECL( opus_uint8, ec_buf_copy ); + opus_int16 *res_pitch_frame; + + ALLOC( res_pitch, + psEnc->sCmn.la_pitch + psEnc->sCmn.frame_length + + psEnc->sCmn.ltp_mem_length, opus_int16 ); + /* start of pitch LPC residual frame */ + res_pitch_frame = res_pitch + psEnc->sCmn.ltp_mem_length; + + /*****************************************/ + /* Find pitch lags, initial LPC analysis */ + /*****************************************/ + silk_find_pitch_lags_FIX( psEnc, &sEncCtrl, res_pitch, x_frame - psEnc->sCmn.ltp_mem_length, psEnc->sCmn.arch ); + + /************************/ + /* Noise shape analysis */ + /************************/ + silk_noise_shape_analysis_FIX( psEnc, &sEncCtrl, res_pitch_frame, x_frame, psEnc->sCmn.arch ); + + /***************************************************/ + /* Find linear prediction coefficients (LPC + LTP) */ + /***************************************************/ + silk_find_pred_coefs_FIX( psEnc, &sEncCtrl, res_pitch_frame, x_frame, condCoding ); + + /****************************************/ + /* Process gains */ + /****************************************/ + silk_process_gains_FIX( psEnc, &sEncCtrl, condCoding ); + + /****************************************/ + /* Low Bitrate Redundant Encoding */ + /****************************************/ + silk_LBRR_encode_FIX( psEnc, &sEncCtrl, x_frame, condCoding ); + + /* Loop over quantizer and entropy coding to control bitrate */ + maxIter = 6; + gainMult_Q8 = SILK_FIX_CONST( 1, 8 ); + found_lower = 0; + found_upper = 0; + gainsID = silk_gains_ID( psEnc->sCmn.indices.GainsIndices, psEnc->sCmn.nb_subfr ); + gainsID_lower = -1; + gainsID_upper = -1; + /* Copy part of the input state */ + silk_memcpy( &sRangeEnc_copy, psRangeEnc, sizeof( ec_enc ) ); + silk_memcpy( &sNSQ_copy, &psEnc->sCmn.sNSQ, sizeof( silk_nsq_state ) ); + seed_copy = psEnc->sCmn.indices.Seed; + ec_prevLagIndex_copy = psEnc->sCmn.ec_prevLagIndex; + ec_prevSignalType_copy = psEnc->sCmn.ec_prevSignalType; + ALLOC( ec_buf_copy, 1275, opus_uint8 ); + for( iter = 0; ; iter++ ) { + if( gainsID == gainsID_lower ) { + nBits = nBits_lower; + } else if( gainsID == gainsID_upper ) { + nBits = nBits_upper; + } else { + /* Restore part of the input state */ + if( iter > 0 ) { + silk_memcpy( psRangeEnc, &sRangeEnc_copy, sizeof( ec_enc ) ); + silk_memcpy( &psEnc->sCmn.sNSQ, &sNSQ_copy, sizeof( silk_nsq_state ) ); + psEnc->sCmn.indices.Seed = seed_copy; + psEnc->sCmn.ec_prevLagIndex = ec_prevLagIndex_copy; + psEnc->sCmn.ec_prevSignalType = ec_prevSignalType_copy; + } + + /*****************************************/ + /* Noise shaping quantization */ + /*****************************************/ + if( psEnc->sCmn.nStatesDelayedDecision > 1 || psEnc->sCmn.warping_Q16 > 0 ) { + silk_NSQ_del_dec( &psEnc->sCmn, &psEnc->sCmn.sNSQ, &psEnc->sCmn.indices, x_frame, psEnc->sCmn.pulses, + sEncCtrl.PredCoef_Q12[ 0 ], sEncCtrl.LTPCoef_Q14, sEncCtrl.AR_Q13, sEncCtrl.HarmShapeGain_Q14, + sEncCtrl.Tilt_Q14, sEncCtrl.LF_shp_Q14, sEncCtrl.Gains_Q16, sEncCtrl.pitchL, sEncCtrl.Lambda_Q10, sEncCtrl.LTP_scale_Q14, + psEnc->sCmn.arch ); + } else { + silk_NSQ( &psEnc->sCmn, &psEnc->sCmn.sNSQ, &psEnc->sCmn.indices, x_frame, psEnc->sCmn.pulses, + sEncCtrl.PredCoef_Q12[ 0 ], sEncCtrl.LTPCoef_Q14, sEncCtrl.AR_Q13, sEncCtrl.HarmShapeGain_Q14, + sEncCtrl.Tilt_Q14, sEncCtrl.LF_shp_Q14, sEncCtrl.Gains_Q16, sEncCtrl.pitchL, sEncCtrl.Lambda_Q10, sEncCtrl.LTP_scale_Q14, + psEnc->sCmn.arch); + } + + if ( iter == maxIter && !found_lower ) { + silk_memcpy( &sRangeEnc_copy2, psRangeEnc, sizeof( ec_enc ) ); + } + + /****************************************/ + /* Encode Parameters */ + /****************************************/ + silk_encode_indices( &psEnc->sCmn, psRangeEnc, psEnc->sCmn.nFramesEncoded, 0, condCoding ); + + /****************************************/ + /* Encode Excitation Signal */ + /****************************************/ + silk_encode_pulses( psRangeEnc, psEnc->sCmn.indices.signalType, psEnc->sCmn.indices.quantOffsetType, + psEnc->sCmn.pulses, psEnc->sCmn.frame_length ); + + nBits = ec_tell( psRangeEnc ); + + /* If we still bust after the last iteration, do some damage control. */ + if ( iter == maxIter && !found_lower && nBits > maxBits ) { + silk_memcpy( psRangeEnc, &sRangeEnc_copy2, sizeof( ec_enc ) ); + + /* Keep gains the same as the last frame. */ + psEnc->sShape.LastGainIndex = sEncCtrl.lastGainIndexPrev; + for ( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) { + psEnc->sCmn.indices.GainsIndices[ i ] = 4; + } + if (condCoding != CODE_CONDITIONALLY) { + psEnc->sCmn.indices.GainsIndices[ 0 ] = sEncCtrl.lastGainIndexPrev; + } + psEnc->sCmn.ec_prevLagIndex = ec_prevLagIndex_copy; + psEnc->sCmn.ec_prevSignalType = ec_prevSignalType_copy; + /* Clear all pulses. */ + for ( i = 0; i < psEnc->sCmn.frame_length; i++ ) { + psEnc->sCmn.pulses[ i ] = 0; + } + + silk_encode_indices( &psEnc->sCmn, psRangeEnc, psEnc->sCmn.nFramesEncoded, 0, condCoding ); + + silk_encode_pulses( psRangeEnc, psEnc->sCmn.indices.signalType, psEnc->sCmn.indices.quantOffsetType, + psEnc->sCmn.pulses, psEnc->sCmn.frame_length ); + + nBits = ec_tell( psRangeEnc ); + } + + if( useCBR == 0 && iter == 0 && nBits <= maxBits ) { + break; + } + } + + if( iter == maxIter ) { + if( found_lower && ( gainsID == gainsID_lower || nBits > maxBits ) ) { + /* Restore output state from earlier iteration that did meet the bitrate budget */ + silk_memcpy( psRangeEnc, &sRangeEnc_copy2, sizeof( ec_enc ) ); + celt_assert( sRangeEnc_copy2.offs <= 1275 ); + silk_memcpy( psRangeEnc->buf, ec_buf_copy, sRangeEnc_copy2.offs ); + silk_memcpy( &psEnc->sCmn.sNSQ, &sNSQ_copy2, sizeof( silk_nsq_state ) ); + psEnc->sShape.LastGainIndex = LastGainIndex_copy2; + } + break; + } + + if( nBits > maxBits ) { + if( found_lower == 0 && iter >= 2 ) { + /* Adjust the quantizer's rate/distortion tradeoff and discard previous "upper" results */ + sEncCtrl.Lambda_Q10 = silk_ADD_RSHIFT32( sEncCtrl.Lambda_Q10, sEncCtrl.Lambda_Q10, 1 ); + found_upper = 0; + gainsID_upper = -1; + } else { + found_upper = 1; + nBits_upper = nBits; + gainMult_upper = gainMult_Q8; + gainsID_upper = gainsID; + } + } else if( nBits < maxBits - 5 ) { + found_lower = 1; + nBits_lower = nBits; + gainMult_lower = gainMult_Q8; + if( gainsID != gainsID_lower ) { + gainsID_lower = gainsID; + /* Copy part of the output state */ + silk_memcpy( &sRangeEnc_copy2, psRangeEnc, sizeof( ec_enc ) ); + celt_assert( psRangeEnc->offs <= 1275 ); + silk_memcpy( ec_buf_copy, psRangeEnc->buf, psRangeEnc->offs ); + silk_memcpy( &sNSQ_copy2, &psEnc->sCmn.sNSQ, sizeof( silk_nsq_state ) ); + LastGainIndex_copy2 = psEnc->sShape.LastGainIndex; + } + } else { + /* Within 5 bits of budget: close enough */ + break; + } + + if ( !found_lower && nBits > maxBits ) { + int j; + for ( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) { + int sum=0; + for ( j = i*psEnc->sCmn.subfr_length; j < (i+1)*psEnc->sCmn.subfr_length; j++ ) { + sum += abs( psEnc->sCmn.pulses[j] ); + } + if ( iter == 0 || (sum < best_sum[i] && !gain_lock[i]) ) { + best_sum[i] = sum; + best_gain_mult[i] = gainMult_Q8; + } else { + gain_lock[i] = 1; + } + } + } + if( ( found_lower & found_upper ) == 0 ) { + /* Adjust gain according to high-rate rate/distortion curve */ + if( nBits > maxBits ) { + if (gainMult_Q8 < 16384) { + gainMult_Q8 *= 2; + } else { + gainMult_Q8 = 32767; + } + } else { + opus_int32 gain_factor_Q16; + gain_factor_Q16 = silk_log2lin( silk_LSHIFT( nBits - maxBits, 7 ) / psEnc->sCmn.frame_length + SILK_FIX_CONST( 16, 7 ) ); + gainMult_Q8 = silk_SMULWB( gain_factor_Q16, gainMult_Q8 ); + } + + } else { + /* Adjust gain by interpolating */ + gainMult_Q8 = gainMult_lower + silk_DIV32_16( silk_MUL( gainMult_upper - gainMult_lower, maxBits - nBits_lower ), nBits_upper - nBits_lower ); + /* New gain multplier must be between 25% and 75% of old range (note that gainMult_upper < gainMult_lower) */ + if( gainMult_Q8 > silk_ADD_RSHIFT32( gainMult_lower, gainMult_upper - gainMult_lower, 2 ) ) { + gainMult_Q8 = silk_ADD_RSHIFT32( gainMult_lower, gainMult_upper - gainMult_lower, 2 ); + } else + if( gainMult_Q8 < silk_SUB_RSHIFT32( gainMult_upper, gainMult_upper - gainMult_lower, 2 ) ) { + gainMult_Q8 = silk_SUB_RSHIFT32( gainMult_upper, gainMult_upper - gainMult_lower, 2 ); + } + } + + for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) { + opus_int16 tmp; + if ( gain_lock[i] ) { + tmp = best_gain_mult[i]; + } else { + tmp = gainMult_Q8; + } + sEncCtrl.Gains_Q16[ i ] = silk_LSHIFT_SAT32( silk_SMULWB( sEncCtrl.GainsUnq_Q16[ i ], tmp ), 8 ); + } + + /* Quantize gains */ + psEnc->sShape.LastGainIndex = sEncCtrl.lastGainIndexPrev; + silk_gains_quant( psEnc->sCmn.indices.GainsIndices, sEncCtrl.Gains_Q16, + &psEnc->sShape.LastGainIndex, condCoding == CODE_CONDITIONALLY, psEnc->sCmn.nb_subfr ); + + /* Unique identifier of gains vector */ + gainsID = silk_gains_ID( psEnc->sCmn.indices.GainsIndices, psEnc->sCmn.nb_subfr ); + } + } + + /* Update input buffer */ + silk_memmove( psEnc->x_buf, &psEnc->x_buf[ psEnc->sCmn.frame_length ], + ( psEnc->sCmn.ltp_mem_length + LA_SHAPE_MS * psEnc->sCmn.fs_kHz ) * sizeof( opus_int16 ) ); + + /* Exit without entropy coding */ + if( psEnc->sCmn.prefillFlag ) { + /* No payload */ + *pnBytesOut = 0; + RESTORE_STACK; + return ret; + } + + /* Parameters needed for next frame */ + psEnc->sCmn.prevLag = sEncCtrl.pitchL[ psEnc->sCmn.nb_subfr - 1 ]; + psEnc->sCmn.prevSignalType = psEnc->sCmn.indices.signalType; + + /****************************************/ + /* Finalize payload */ + /****************************************/ + psEnc->sCmn.first_frame_after_reset = 0; + /* Payload size */ + *pnBytesOut = silk_RSHIFT( ec_tell( psRangeEnc ) + 7, 3 ); + + RESTORE_STACK; + return ret; +} + +/* Low-Bitrate Redundancy (LBRR) encoding. Reuse all parameters but encode excitation at lower bitrate */ +static OPUS_INLINE void silk_LBRR_encode_FIX( + silk_encoder_state_FIX *psEnc, /* I/O Pointer to Silk FIX encoder state */ + silk_encoder_control_FIX *psEncCtrl, /* I/O Pointer to Silk FIX encoder control struct */ + const opus_int16 x16[], /* I Input signal */ + opus_int condCoding /* I The type of conditional coding used so far for this frame */ +) +{ + opus_int32 TempGains_Q16[ MAX_NB_SUBFR ]; + SideInfoIndices *psIndices_LBRR = &psEnc->sCmn.indices_LBRR[ psEnc->sCmn.nFramesEncoded ]; + silk_nsq_state sNSQ_LBRR; + + /*******************************************/ + /* Control use of inband LBRR */ + /*******************************************/ + if( psEnc->sCmn.LBRR_enabled && psEnc->sCmn.speech_activity_Q8 > SILK_FIX_CONST( LBRR_SPEECH_ACTIVITY_THRES, 8 ) ) { + psEnc->sCmn.LBRR_flags[ psEnc->sCmn.nFramesEncoded ] = 1; + + /* Copy noise shaping quantizer state and quantization indices from regular encoding */ + silk_memcpy( &sNSQ_LBRR, &psEnc->sCmn.sNSQ, sizeof( silk_nsq_state ) ); + silk_memcpy( psIndices_LBRR, &psEnc->sCmn.indices, sizeof( SideInfoIndices ) ); + + /* Save original gains */ + silk_memcpy( TempGains_Q16, psEncCtrl->Gains_Q16, psEnc->sCmn.nb_subfr * sizeof( opus_int32 ) ); + + if( psEnc->sCmn.nFramesEncoded == 0 || psEnc->sCmn.LBRR_flags[ psEnc->sCmn.nFramesEncoded - 1 ] == 0 ) { + /* First frame in packet or previous frame not LBRR coded */ + psEnc->sCmn.LBRRprevLastGainIndex = psEnc->sShape.LastGainIndex; + + /* Increase Gains to get target LBRR rate */ + psIndices_LBRR->GainsIndices[ 0 ] = psIndices_LBRR->GainsIndices[ 0 ] + psEnc->sCmn.LBRR_GainIncreases; + psIndices_LBRR->GainsIndices[ 0 ] = silk_min_int( psIndices_LBRR->GainsIndices[ 0 ], N_LEVELS_QGAIN - 1 ); + } + + /* Decode to get gains in sync with decoder */ + /* Overwrite unquantized gains with quantized gains */ + silk_gains_dequant( psEncCtrl->Gains_Q16, psIndices_LBRR->GainsIndices, + &psEnc->sCmn.LBRRprevLastGainIndex, condCoding == CODE_CONDITIONALLY, psEnc->sCmn.nb_subfr ); + + /*****************************************/ + /* Noise shaping quantization */ + /*****************************************/ + if( psEnc->sCmn.nStatesDelayedDecision > 1 || psEnc->sCmn.warping_Q16 > 0 ) { + silk_NSQ_del_dec( &psEnc->sCmn, &sNSQ_LBRR, psIndices_LBRR, x16, + psEnc->sCmn.pulses_LBRR[ psEnc->sCmn.nFramesEncoded ], psEncCtrl->PredCoef_Q12[ 0 ], psEncCtrl->LTPCoef_Q14, + psEncCtrl->AR_Q13, psEncCtrl->HarmShapeGain_Q14, psEncCtrl->Tilt_Q14, psEncCtrl->LF_shp_Q14, + psEncCtrl->Gains_Q16, psEncCtrl->pitchL, psEncCtrl->Lambda_Q10, psEncCtrl->LTP_scale_Q14, psEnc->sCmn.arch ); + } else { + silk_NSQ( &psEnc->sCmn, &sNSQ_LBRR, psIndices_LBRR, x16, + psEnc->sCmn.pulses_LBRR[ psEnc->sCmn.nFramesEncoded ], psEncCtrl->PredCoef_Q12[ 0 ], psEncCtrl->LTPCoef_Q14, + psEncCtrl->AR_Q13, psEncCtrl->HarmShapeGain_Q14, psEncCtrl->Tilt_Q14, psEncCtrl->LF_shp_Q14, + psEncCtrl->Gains_Q16, psEncCtrl->pitchL, psEncCtrl->Lambda_Q10, psEncCtrl->LTP_scale_Q14, psEnc->sCmn.arch ); + } + + /* Restore original gains */ + silk_memcpy( psEncCtrl->Gains_Q16, TempGains_Q16, psEnc->sCmn.nb_subfr * sizeof( opus_int32 ) ); + } +} diff --git a/extern/opus/silk/fixed/find_LPC_FIX.c b/extern/opus/silk/fixed/find_LPC_FIX.c new file mode 100644 index 0000000..c762a0f --- /dev/null +++ b/extern/opus/silk/fixed/find_LPC_FIX.c @@ -0,0 +1,151 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FIX.h" +#include "stack_alloc.h" +#include "tuning_parameters.h" + +/* Finds LPC vector from correlations, and converts to NLSF */ +void silk_find_LPC_FIX( + silk_encoder_state *psEncC, /* I/O Encoder state */ + opus_int16 NLSF_Q15[], /* O NLSFs */ + const opus_int16 x[], /* I Input signal */ + const opus_int32 minInvGain_Q30 /* I Inverse of max prediction gain */ +) +{ + opus_int k, subfr_length; + opus_int32 a_Q16[ MAX_LPC_ORDER ]; + opus_int isInterpLower, shift; + opus_int32 res_nrg0, res_nrg1; + opus_int rshift0, rshift1; + + /* Used only for LSF interpolation */ + opus_int32 a_tmp_Q16[ MAX_LPC_ORDER ], res_nrg_interp, res_nrg, res_tmp_nrg; + opus_int res_nrg_interp_Q, res_nrg_Q, res_tmp_nrg_Q; + opus_int16 a_tmp_Q12[ MAX_LPC_ORDER ]; + opus_int16 NLSF0_Q15[ MAX_LPC_ORDER ]; + SAVE_STACK; + + subfr_length = psEncC->subfr_length + psEncC->predictLPCOrder; + + /* Default: no interpolation */ + psEncC->indices.NLSFInterpCoef_Q2 = 4; + + /* Burg AR analysis for the full frame */ + silk_burg_modified( &res_nrg, &res_nrg_Q, a_Q16, x, minInvGain_Q30, subfr_length, psEncC->nb_subfr, psEncC->predictLPCOrder, psEncC->arch ); + + if( psEncC->useInterpolatedNLSFs && !psEncC->first_frame_after_reset && psEncC->nb_subfr == MAX_NB_SUBFR ) { + VARDECL( opus_int16, LPC_res ); + + /* Optimal solution for last 10 ms */ + silk_burg_modified( &res_tmp_nrg, &res_tmp_nrg_Q, a_tmp_Q16, x + 2 * subfr_length, minInvGain_Q30, subfr_length, 2, psEncC->predictLPCOrder, psEncC->arch ); + + /* subtract residual energy here, as that's easier than adding it to the */ + /* residual energy of the first 10 ms in each iteration of the search below */ + shift = res_tmp_nrg_Q - res_nrg_Q; + if( shift >= 0 ) { + if( shift < 32 ) { + res_nrg = res_nrg - silk_RSHIFT( res_tmp_nrg, shift ); + } + } else { + silk_assert( shift > -32 ); + res_nrg = silk_RSHIFT( res_nrg, -shift ) - res_tmp_nrg; + res_nrg_Q = res_tmp_nrg_Q; + } + + /* Convert to NLSFs */ + silk_A2NLSF( NLSF_Q15, a_tmp_Q16, psEncC->predictLPCOrder ); + + ALLOC( LPC_res, 2 * subfr_length, opus_int16 ); + + /* Search over interpolation indices to find the one with lowest residual energy */ + for( k = 3; k >= 0; k-- ) { + /* Interpolate NLSFs for first half */ + silk_interpolate( NLSF0_Q15, psEncC->prev_NLSFq_Q15, NLSF_Q15, k, psEncC->predictLPCOrder ); + + /* Convert to LPC for residual energy evaluation */ + silk_NLSF2A( a_tmp_Q12, NLSF0_Q15, psEncC->predictLPCOrder, psEncC->arch ); + + /* Calculate residual energy with NLSF interpolation */ + silk_LPC_analysis_filter( LPC_res, x, a_tmp_Q12, 2 * subfr_length, psEncC->predictLPCOrder, psEncC->arch ); + + silk_sum_sqr_shift( &res_nrg0, &rshift0, LPC_res + psEncC->predictLPCOrder, subfr_length - psEncC->predictLPCOrder ); + silk_sum_sqr_shift( &res_nrg1, &rshift1, LPC_res + psEncC->predictLPCOrder + subfr_length, subfr_length - psEncC->predictLPCOrder ); + + /* Add subframe energies from first half frame */ + shift = rshift0 - rshift1; + if( shift >= 0 ) { + res_nrg1 = silk_RSHIFT( res_nrg1, shift ); + res_nrg_interp_Q = -rshift0; + } else { + res_nrg0 = silk_RSHIFT( res_nrg0, -shift ); + res_nrg_interp_Q = -rshift1; + } + res_nrg_interp = silk_ADD32( res_nrg0, res_nrg1 ); + + /* Compare with first half energy without NLSF interpolation, or best interpolated value so far */ + shift = res_nrg_interp_Q - res_nrg_Q; + if( shift >= 0 ) { + if( silk_RSHIFT( res_nrg_interp, shift ) < res_nrg ) { + isInterpLower = silk_TRUE; + } else { + isInterpLower = silk_FALSE; + } + } else { + if( -shift < 32 ) { + if( res_nrg_interp < silk_RSHIFT( res_nrg, -shift ) ) { + isInterpLower = silk_TRUE; + } else { + isInterpLower = silk_FALSE; + } + } else { + isInterpLower = silk_FALSE; + } + } + + /* Determine whether current interpolated NLSFs are best so far */ + if( isInterpLower == silk_TRUE ) { + /* Interpolation has lower residual energy */ + res_nrg = res_nrg_interp; + res_nrg_Q = res_nrg_interp_Q; + psEncC->indices.NLSFInterpCoef_Q2 = (opus_int8)k; + } + } + } + + if( psEncC->indices.NLSFInterpCoef_Q2 == 4 ) { + /* NLSF interpolation is currently inactive, calculate NLSFs from full frame AR coefficients */ + silk_A2NLSF( NLSF_Q15, a_Q16, psEncC->predictLPCOrder ); + } + + celt_assert( psEncC->indices.NLSFInterpCoef_Q2 == 4 || ( psEncC->useInterpolatedNLSFs && !psEncC->first_frame_after_reset && psEncC->nb_subfr == MAX_NB_SUBFR ) ); + RESTORE_STACK; +} diff --git a/extern/opus/silk/fixed/find_LTP_FIX.c b/extern/opus/silk/fixed/find_LTP_FIX.c new file mode 100644 index 0000000..62d4afb --- /dev/null +++ b/extern/opus/silk/fixed/find_LTP_FIX.c @@ -0,0 +1,99 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FIX.h" +#include "tuning_parameters.h" + +void silk_find_LTP_FIX( + opus_int32 XXLTP_Q17[ MAX_NB_SUBFR * LTP_ORDER * LTP_ORDER ], /* O Correlation matrix */ + opus_int32 xXLTP_Q17[ MAX_NB_SUBFR * LTP_ORDER ], /* O Correlation vector */ + const opus_int16 r_ptr[], /* I Residual signal after LPC */ + const opus_int lag[ MAX_NB_SUBFR ], /* I LTP lags */ + const opus_int subfr_length, /* I Subframe length */ + const opus_int nb_subfr, /* I Number of subframes */ + int arch /* I Run-time architecture */ +) +{ + opus_int i, k, extra_shifts; + opus_int xx_shifts, xX_shifts, XX_shifts; + const opus_int16 *lag_ptr; + opus_int32 *XXLTP_Q17_ptr, *xXLTP_Q17_ptr; + opus_int32 xx, nrg, temp; + + xXLTP_Q17_ptr = xXLTP_Q17; + XXLTP_Q17_ptr = XXLTP_Q17; + for( k = 0; k < nb_subfr; k++ ) { + lag_ptr = r_ptr - ( lag[ k ] + LTP_ORDER / 2 ); + + silk_sum_sqr_shift( &xx, &xx_shifts, r_ptr, subfr_length + LTP_ORDER ); /* xx in Q( -xx_shifts ) */ + silk_corrMatrix_FIX( lag_ptr, subfr_length, LTP_ORDER, XXLTP_Q17_ptr, &nrg, &XX_shifts, arch ); /* XXLTP_Q17_ptr and nrg in Q( -XX_shifts ) */ + extra_shifts = xx_shifts - XX_shifts; + if( extra_shifts > 0 ) { + /* Shift XX */ + xX_shifts = xx_shifts; + for( i = 0; i < LTP_ORDER * LTP_ORDER; i++ ) { + XXLTP_Q17_ptr[ i ] = silk_RSHIFT32( XXLTP_Q17_ptr[ i ], extra_shifts ); /* Q( -xX_shifts ) */ + } + nrg = silk_RSHIFT32( nrg, extra_shifts ); /* Q( -xX_shifts ) */ + } else if( extra_shifts < 0 ) { + /* Shift xx */ + xX_shifts = XX_shifts; + xx = silk_RSHIFT32( xx, -extra_shifts ); /* Q( -xX_shifts ) */ + } else { + xX_shifts = xx_shifts; + } + silk_corrVector_FIX( lag_ptr, r_ptr, subfr_length, LTP_ORDER, xXLTP_Q17_ptr, xX_shifts, arch ); /* xXLTP_Q17_ptr in Q( -xX_shifts ) */ + + /* At this point all correlations are in Q(-xX_shifts) */ + temp = silk_SMLAWB( 1, nrg, SILK_FIX_CONST( LTP_CORR_INV_MAX, 16 ) ); + temp = silk_max( temp, xx ); +TIC(div) +#if 0 + for( i = 0; i < LTP_ORDER * LTP_ORDER; i++ ) { + XXLTP_Q17_ptr[ i ] = silk_DIV32_varQ( XXLTP_Q17_ptr[ i ], temp, 17 ); + } + for( i = 0; i < LTP_ORDER; i++ ) { + xXLTP_Q17_ptr[ i ] = silk_DIV32_varQ( xXLTP_Q17_ptr[ i ], temp, 17 ); + } +#else + for( i = 0; i < LTP_ORDER * LTP_ORDER; i++ ) { + XXLTP_Q17_ptr[ i ] = (opus_int32)( silk_LSHIFT64( (opus_int64)XXLTP_Q17_ptr[ i ], 17 ) / temp ); + } + for( i = 0; i < LTP_ORDER; i++ ) { + xXLTP_Q17_ptr[ i ] = (opus_int32)( silk_LSHIFT64( (opus_int64)xXLTP_Q17_ptr[ i ], 17 ) / temp ); + } +#endif +TOC(div) + r_ptr += subfr_length; + XXLTP_Q17_ptr += LTP_ORDER * LTP_ORDER; + xXLTP_Q17_ptr += LTP_ORDER; + } +} diff --git a/extern/opus/silk/fixed/find_pitch_lags_FIX.c b/extern/opus/silk/fixed/find_pitch_lags_FIX.c new file mode 100644 index 0000000..6c3379f --- /dev/null +++ b/extern/opus/silk/fixed/find_pitch_lags_FIX.c @@ -0,0 +1,143 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FIX.h" +#include "stack_alloc.h" +#include "tuning_parameters.h" + +/* Find pitch lags */ +void silk_find_pitch_lags_FIX( + silk_encoder_state_FIX *psEnc, /* I/O encoder state */ + silk_encoder_control_FIX *psEncCtrl, /* I/O encoder control */ + opus_int16 res[], /* O residual */ + const opus_int16 x[], /* I Speech signal */ + int arch /* I Run-time architecture */ +) +{ + opus_int buf_len, i, scale; + opus_int32 thrhld_Q13, res_nrg; + const opus_int16 *x_ptr; + VARDECL( opus_int16, Wsig ); + opus_int16 *Wsig_ptr; + opus_int32 auto_corr[ MAX_FIND_PITCH_LPC_ORDER + 1 ]; + opus_int16 rc_Q15[ MAX_FIND_PITCH_LPC_ORDER ]; + opus_int32 A_Q24[ MAX_FIND_PITCH_LPC_ORDER ]; + opus_int16 A_Q12[ MAX_FIND_PITCH_LPC_ORDER ]; + SAVE_STACK; + + /******************************************/ + /* Set up buffer lengths etc based on Fs */ + /******************************************/ + buf_len = psEnc->sCmn.la_pitch + psEnc->sCmn.frame_length + psEnc->sCmn.ltp_mem_length; + + /* Safety check */ + celt_assert( buf_len >= psEnc->sCmn.pitch_LPC_win_length ); + + /*************************************/ + /* Estimate LPC AR coefficients */ + /*************************************/ + + /* Calculate windowed signal */ + + ALLOC( Wsig, psEnc->sCmn.pitch_LPC_win_length, opus_int16 ); + + /* First LA_LTP samples */ + x_ptr = x + buf_len - psEnc->sCmn.pitch_LPC_win_length; + Wsig_ptr = Wsig; + silk_apply_sine_window( Wsig_ptr, x_ptr, 1, psEnc->sCmn.la_pitch ); + + /* Middle un - windowed samples */ + Wsig_ptr += psEnc->sCmn.la_pitch; + x_ptr += psEnc->sCmn.la_pitch; + silk_memcpy( Wsig_ptr, x_ptr, ( psEnc->sCmn.pitch_LPC_win_length - silk_LSHIFT( psEnc->sCmn.la_pitch, 1 ) ) * sizeof( opus_int16 ) ); + + /* Last LA_LTP samples */ + Wsig_ptr += psEnc->sCmn.pitch_LPC_win_length - silk_LSHIFT( psEnc->sCmn.la_pitch, 1 ); + x_ptr += psEnc->sCmn.pitch_LPC_win_length - silk_LSHIFT( psEnc->sCmn.la_pitch, 1 ); + silk_apply_sine_window( Wsig_ptr, x_ptr, 2, psEnc->sCmn.la_pitch ); + + /* Calculate autocorrelation sequence */ + silk_autocorr( auto_corr, &scale, Wsig, psEnc->sCmn.pitch_LPC_win_length, psEnc->sCmn.pitchEstimationLPCOrder + 1, arch ); + + /* Add white noise, as fraction of energy */ + auto_corr[ 0 ] = silk_SMLAWB( auto_corr[ 0 ], auto_corr[ 0 ], SILK_FIX_CONST( FIND_PITCH_WHITE_NOISE_FRACTION, 16 ) ) + 1; + + /* Calculate the reflection coefficients using schur */ + res_nrg = silk_schur( rc_Q15, auto_corr, psEnc->sCmn.pitchEstimationLPCOrder ); + + /* Prediction gain */ + psEncCtrl->predGain_Q16 = silk_DIV32_varQ( auto_corr[ 0 ], silk_max_int( res_nrg, 1 ), 16 ); + + /* Convert reflection coefficients to prediction coefficients */ + silk_k2a( A_Q24, rc_Q15, psEnc->sCmn.pitchEstimationLPCOrder ); + + /* Convert From 32 bit Q24 to 16 bit Q12 coefs */ + for( i = 0; i < psEnc->sCmn.pitchEstimationLPCOrder; i++ ) { + A_Q12[ i ] = (opus_int16)silk_SAT16( silk_RSHIFT( A_Q24[ i ], 12 ) ); + } + + /* Do BWE */ + silk_bwexpander( A_Q12, psEnc->sCmn.pitchEstimationLPCOrder, SILK_FIX_CONST( FIND_PITCH_BANDWIDTH_EXPANSION, 16 ) ); + + /*****************************************/ + /* LPC analysis filtering */ + /*****************************************/ + silk_LPC_analysis_filter( res, x, A_Q12, buf_len, psEnc->sCmn.pitchEstimationLPCOrder, psEnc->sCmn.arch ); + + if( psEnc->sCmn.indices.signalType != TYPE_NO_VOICE_ACTIVITY && psEnc->sCmn.first_frame_after_reset == 0 ) { + /* Threshold for pitch estimator */ + thrhld_Q13 = SILK_FIX_CONST( 0.6, 13 ); + thrhld_Q13 = silk_SMLABB( thrhld_Q13, SILK_FIX_CONST( -0.004, 13 ), psEnc->sCmn.pitchEstimationLPCOrder ); + thrhld_Q13 = silk_SMLAWB( thrhld_Q13, SILK_FIX_CONST( -0.1, 21 ), psEnc->sCmn.speech_activity_Q8 ); + thrhld_Q13 = silk_SMLABB( thrhld_Q13, SILK_FIX_CONST( -0.15, 13 ), silk_RSHIFT( psEnc->sCmn.prevSignalType, 1 ) ); + thrhld_Q13 = silk_SMLAWB( thrhld_Q13, SILK_FIX_CONST( -0.1, 14 ), psEnc->sCmn.input_tilt_Q15 ); + thrhld_Q13 = silk_SAT16( thrhld_Q13 ); + + /*****************************************/ + /* Call pitch estimator */ + /*****************************************/ + if( silk_pitch_analysis_core( res, psEncCtrl->pitchL, &psEnc->sCmn.indices.lagIndex, &psEnc->sCmn.indices.contourIndex, + &psEnc->LTPCorr_Q15, psEnc->sCmn.prevLag, psEnc->sCmn.pitchEstimationThreshold_Q16, + (opus_int)thrhld_Q13, psEnc->sCmn.fs_kHz, psEnc->sCmn.pitchEstimationComplexity, psEnc->sCmn.nb_subfr, + psEnc->sCmn.arch) == 0 ) + { + psEnc->sCmn.indices.signalType = TYPE_VOICED; + } else { + psEnc->sCmn.indices.signalType = TYPE_UNVOICED; + } + } else { + silk_memset( psEncCtrl->pitchL, 0, sizeof( psEncCtrl->pitchL ) ); + psEnc->sCmn.indices.lagIndex = 0; + psEnc->sCmn.indices.contourIndex = 0; + psEnc->LTPCorr_Q15 = 0; + } + RESTORE_STACK; +} diff --git a/extern/opus/silk/fixed/find_pred_coefs_FIX.c b/extern/opus/silk/fixed/find_pred_coefs_FIX.c new file mode 100644 index 0000000..606d863 --- /dev/null +++ b/extern/opus/silk/fixed/find_pred_coefs_FIX.c @@ -0,0 +1,145 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FIX.h" +#include "stack_alloc.h" + +void silk_find_pred_coefs_FIX( + silk_encoder_state_FIX *psEnc, /* I/O encoder state */ + silk_encoder_control_FIX *psEncCtrl, /* I/O encoder control */ + const opus_int16 res_pitch[], /* I Residual from pitch analysis */ + const opus_int16 x[], /* I Speech signal */ + opus_int condCoding /* I The type of conditional coding to use */ +) +{ + opus_int i; + opus_int32 invGains_Q16[ MAX_NB_SUBFR ], local_gains[ MAX_NB_SUBFR ]; + opus_int16 NLSF_Q15[ MAX_LPC_ORDER ]; + const opus_int16 *x_ptr; + opus_int16 *x_pre_ptr; + VARDECL( opus_int16, LPC_in_pre ); + opus_int32 min_gain_Q16, minInvGain_Q30; + SAVE_STACK; + + /* weighting for weighted least squares */ + min_gain_Q16 = silk_int32_MAX >> 6; + for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) { + min_gain_Q16 = silk_min( min_gain_Q16, psEncCtrl->Gains_Q16[ i ] ); + } + for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) { + /* Divide to Q16 */ + silk_assert( psEncCtrl->Gains_Q16[ i ] > 0 ); + /* Invert and normalize gains, and ensure that maximum invGains_Q16 is within range of a 16 bit int */ + invGains_Q16[ i ] = silk_DIV32_varQ( min_gain_Q16, psEncCtrl->Gains_Q16[ i ], 16 - 2 ); + + /* Limit inverse */ + invGains_Q16[ i ] = silk_max( invGains_Q16[ i ], 100 ); + + /* Square the inverted gains */ + silk_assert( invGains_Q16[ i ] == silk_SAT16( invGains_Q16[ i ] ) ); + + /* Invert the inverted and normalized gains */ + local_gains[ i ] = silk_DIV32( ( (opus_int32)1 << 16 ), invGains_Q16[ i ] ); + } + + ALLOC( LPC_in_pre, + psEnc->sCmn.nb_subfr * psEnc->sCmn.predictLPCOrder + + psEnc->sCmn.frame_length, opus_int16 ); + if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) { + VARDECL( opus_int32, xXLTP_Q17 ); + VARDECL( opus_int32, XXLTP_Q17 ); + + /**********/ + /* VOICED */ + /**********/ + celt_assert( psEnc->sCmn.ltp_mem_length - psEnc->sCmn.predictLPCOrder >= psEncCtrl->pitchL[ 0 ] + LTP_ORDER / 2 ); + + ALLOC( xXLTP_Q17, psEnc->sCmn.nb_subfr * LTP_ORDER, opus_int32 ); + ALLOC( XXLTP_Q17, psEnc->sCmn.nb_subfr * LTP_ORDER * LTP_ORDER, opus_int32 ); + + /* LTP analysis */ + silk_find_LTP_FIX( XXLTP_Q17, xXLTP_Q17, res_pitch, + psEncCtrl->pitchL, psEnc->sCmn.subfr_length, psEnc->sCmn.nb_subfr, psEnc->sCmn.arch ); + + /* Quantize LTP gain parameters */ + silk_quant_LTP_gains( psEncCtrl->LTPCoef_Q14, psEnc->sCmn.indices.LTPIndex, &psEnc->sCmn.indices.PERIndex, + &psEnc->sCmn.sum_log_gain_Q7, &psEncCtrl->LTPredCodGain_Q7, XXLTP_Q17, xXLTP_Q17, psEnc->sCmn.subfr_length, psEnc->sCmn.nb_subfr, psEnc->sCmn.arch ); + + /* Control LTP scaling */ + silk_LTP_scale_ctrl_FIX( psEnc, psEncCtrl, condCoding ); + + /* Create LTP residual */ + silk_LTP_analysis_filter_FIX( LPC_in_pre, x - psEnc->sCmn.predictLPCOrder, psEncCtrl->LTPCoef_Q14, + psEncCtrl->pitchL, invGains_Q16, psEnc->sCmn.subfr_length, psEnc->sCmn.nb_subfr, psEnc->sCmn.predictLPCOrder ); + + } else { + /************/ + /* UNVOICED */ + /************/ + /* Create signal with prepended subframes, scaled by inverse gains */ + x_ptr = x - psEnc->sCmn.predictLPCOrder; + x_pre_ptr = LPC_in_pre; + for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) { + silk_scale_copy_vector16( x_pre_ptr, x_ptr, invGains_Q16[ i ], + psEnc->sCmn.subfr_length + psEnc->sCmn.predictLPCOrder ); + x_pre_ptr += psEnc->sCmn.subfr_length + psEnc->sCmn.predictLPCOrder; + x_ptr += psEnc->sCmn.subfr_length; + } + + silk_memset( psEncCtrl->LTPCoef_Q14, 0, psEnc->sCmn.nb_subfr * LTP_ORDER * sizeof( opus_int16 ) ); + psEncCtrl->LTPredCodGain_Q7 = 0; + psEnc->sCmn.sum_log_gain_Q7 = 0; + } + + /* Limit on total predictive coding gain */ + if( psEnc->sCmn.first_frame_after_reset ) { + minInvGain_Q30 = SILK_FIX_CONST( 1.0f / MAX_PREDICTION_POWER_GAIN_AFTER_RESET, 30 ); + } else { + minInvGain_Q30 = silk_log2lin( silk_SMLAWB( 16 << 7, (opus_int32)psEncCtrl->LTPredCodGain_Q7, SILK_FIX_CONST( 1.0 / 3, 16 ) ) ); /* Q16 */ + minInvGain_Q30 = silk_DIV32_varQ( minInvGain_Q30, + silk_SMULWW( SILK_FIX_CONST( MAX_PREDICTION_POWER_GAIN, 0 ), + silk_SMLAWB( SILK_FIX_CONST( 0.25, 18 ), SILK_FIX_CONST( 0.75, 18 ), psEncCtrl->coding_quality_Q14 ) ), 14 ); + } + + /* LPC_in_pre contains the LTP-filtered input for voiced, and the unfiltered input for unvoiced */ + silk_find_LPC_FIX( &psEnc->sCmn, NLSF_Q15, LPC_in_pre, minInvGain_Q30 ); + + /* Quantize LSFs */ + silk_process_NLSFs( &psEnc->sCmn, psEncCtrl->PredCoef_Q12, NLSF_Q15, psEnc->sCmn.prev_NLSFq_Q15 ); + + /* Calculate residual energy using quantized LPC coefficients */ + silk_residual_energy_FIX( psEncCtrl->ResNrg, psEncCtrl->ResNrgQ, LPC_in_pre, psEncCtrl->PredCoef_Q12, local_gains, + psEnc->sCmn.subfr_length, psEnc->sCmn.nb_subfr, psEnc->sCmn.predictLPCOrder, psEnc->sCmn.arch ); + + /* Copy to prediction struct for use in next frame for interpolation */ + silk_memcpy( psEnc->sCmn.prev_NLSFq_Q15, NLSF_Q15, sizeof( psEnc->sCmn.prev_NLSFq_Q15 ) ); + RESTORE_STACK; +} diff --git a/extern/opus/silk/fixed/k2a_FIX.c b/extern/opus/silk/fixed/k2a_FIX.c new file mode 100644 index 0000000..549f6ea --- /dev/null +++ b/extern/opus/silk/fixed/k2a_FIX.c @@ -0,0 +1,54 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" + +/* Step up function, converts reflection coefficients to prediction coefficients */ +void silk_k2a( + opus_int32 *A_Q24, /* O Prediction coefficients [order] Q24 */ + const opus_int16 *rc_Q15, /* I Reflection coefficients [order] Q15 */ + const opus_int32 order /* I Prediction order */ +) +{ + opus_int k, n; + opus_int32 rc, tmp1, tmp2; + + for( k = 0; k < order; k++ ) { + rc = rc_Q15[ k ]; + for( n = 0; n < (k + 1) >> 1; n++ ) { + tmp1 = A_Q24[ n ]; + tmp2 = A_Q24[ k - n - 1 ]; + A_Q24[ n ] = silk_SMLAWB( tmp1, silk_LSHIFT( tmp2, 1 ), rc ); + A_Q24[ k - n - 1 ] = silk_SMLAWB( tmp2, silk_LSHIFT( tmp1, 1 ), rc ); + } + A_Q24[ k ] = -silk_LSHIFT( (opus_int32)rc_Q15[ k ], 9 ); + } +} diff --git a/extern/opus/silk/fixed/k2a_Q16_FIX.c b/extern/opus/silk/fixed/k2a_Q16_FIX.c new file mode 100644 index 0000000..1595aa6 --- /dev/null +++ b/extern/opus/silk/fixed/k2a_Q16_FIX.c @@ -0,0 +1,54 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" + +/* Step up function, converts reflection coefficients to prediction coefficients */ +void silk_k2a_Q16( + opus_int32 *A_Q24, /* O Prediction coefficients [order] Q24 */ + const opus_int32 *rc_Q16, /* I Reflection coefficients [order] Q16 */ + const opus_int32 order /* I Prediction order */ +) +{ + opus_int k, n; + opus_int32 rc, tmp1, tmp2; + + for( k = 0; k < order; k++ ) { + rc = rc_Q16[ k ]; + for( n = 0; n < (k + 1) >> 1; n++ ) { + tmp1 = A_Q24[ n ]; + tmp2 = A_Q24[ k - n - 1 ]; + A_Q24[ n ] = silk_SMLAWW( tmp1, tmp2, rc ); + A_Q24[ k - n - 1 ] = silk_SMLAWW( tmp2, tmp1, rc ); + } + A_Q24[ k ] = -silk_LSHIFT( rc, 8 ); + } +} diff --git a/extern/opus/silk/fixed/main_FIX.h b/extern/opus/silk/fixed/main_FIX.h new file mode 100644 index 0000000..6d2112e --- /dev/null +++ b/extern/opus/silk/fixed/main_FIX.h @@ -0,0 +1,244 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifndef SILK_MAIN_FIX_H +#define SILK_MAIN_FIX_H + +#include "SigProc_FIX.h" +#include "structs_FIX.h" +#include "control.h" +#include "main.h" +#include "PLC.h" +#include "debug.h" +#include "entenc.h" + +#if ((defined(OPUS_ARM_ASM) && defined(FIXED_POINT)) \ + || defined(OPUS_ARM_MAY_HAVE_NEON_INTR)) +#include "fixed/arm/warped_autocorrelation_FIX_arm.h" +#endif + +#ifndef FORCE_CPP_BUILD +#ifdef __cplusplus +extern "C" +{ +#endif +#endif + +#define silk_encoder_state_Fxx silk_encoder_state_FIX +#define silk_encode_do_VAD_Fxx silk_encode_do_VAD_FIX +#define silk_encode_frame_Fxx silk_encode_frame_FIX + +#define QC 10 +#define QS 13 + +/*********************/ +/* Encoder Functions */ +/*********************/ + +/* High-pass filter with cutoff frequency adaptation based on pitch lag statistics */ +void silk_HP_variable_cutoff( + silk_encoder_state_Fxx state_Fxx[] /* I/O Encoder states */ +); + +/* Encoder main function */ +void silk_encode_do_VAD_FIX( + silk_encoder_state_FIX *psEnc, /* I/O Pointer to Silk FIX encoder state */ + opus_int activity /* I Decision of Opus voice activity detector */ +); + +/* Encoder main function */ +opus_int silk_encode_frame_FIX( + silk_encoder_state_FIX *psEnc, /* I/O Pointer to Silk FIX encoder state */ + opus_int32 *pnBytesOut, /* O Pointer to number of payload bytes; */ + ec_enc *psRangeEnc, /* I/O compressor data structure */ + opus_int condCoding, /* I The type of conditional coding to use */ + opus_int maxBits, /* I If > 0: maximum number of output bits */ + opus_int useCBR /* I Flag to force constant-bitrate operation */ +); + +/* Initializes the Silk encoder state */ +opus_int silk_init_encoder( + silk_encoder_state_Fxx *psEnc, /* I/O Pointer to Silk FIX encoder state */ + int arch /* I Run-time architecture */ +); + +/* Control the Silk encoder */ +opus_int silk_control_encoder( + silk_encoder_state_Fxx *psEnc, /* I/O Pointer to Silk encoder state */ + silk_EncControlStruct *encControl, /* I Control structure */ + const opus_int allow_bw_switch, /* I Flag to allow switching audio bandwidth */ + const opus_int channelNb, /* I Channel number */ + const opus_int force_fs_kHz +); + +/**************************/ +/* Noise shaping analysis */ +/**************************/ +/* Compute noise shaping coefficients and initial gain values */ +void silk_noise_shape_analysis_FIX( + silk_encoder_state_FIX *psEnc, /* I/O Encoder state FIX */ + silk_encoder_control_FIX *psEncCtrl, /* I/O Encoder control FIX */ + const opus_int16 *pitch_res, /* I LPC residual from pitch analysis */ + const opus_int16 *x, /* I Input signal [ frame_length + la_shape ] */ + int arch /* I Run-time architecture */ +); + +/* Autocorrelations for a warped frequency axis */ +void silk_warped_autocorrelation_FIX_c( + opus_int32 *corr, /* O Result [order + 1] */ + opus_int *scale, /* O Scaling of the correlation vector */ + const opus_int16 *input, /* I Input data to correlate */ + const opus_int warping_Q16, /* I Warping coefficient */ + const opus_int length, /* I Length of input */ + const opus_int order /* I Correlation order (even) */ +); + +#if !defined(OVERRIDE_silk_warped_autocorrelation_FIX) +#define silk_warped_autocorrelation_FIX(corr, scale, input, warping_Q16, length, order, arch) \ + ((void)(arch), silk_warped_autocorrelation_FIX_c(corr, scale, input, warping_Q16, length, order)) +#endif + +/* Calculation of LTP state scaling */ +void silk_LTP_scale_ctrl_FIX( + silk_encoder_state_FIX *psEnc, /* I/O encoder state */ + silk_encoder_control_FIX *psEncCtrl, /* I/O encoder control */ + opus_int condCoding /* I The type of conditional coding to use */ +); + +/**********************************************/ +/* Prediction Analysis */ +/**********************************************/ +/* Find pitch lags */ +void silk_find_pitch_lags_FIX( + silk_encoder_state_FIX *psEnc, /* I/O encoder state */ + silk_encoder_control_FIX *psEncCtrl, /* I/O encoder control */ + opus_int16 res[], /* O residual */ + const opus_int16 x[], /* I Speech signal */ + int arch /* I Run-time architecture */ +); + +/* Find LPC and LTP coefficients */ +void silk_find_pred_coefs_FIX( + silk_encoder_state_FIX *psEnc, /* I/O encoder state */ + silk_encoder_control_FIX *psEncCtrl, /* I/O encoder control */ + const opus_int16 res_pitch[], /* I Residual from pitch analysis */ + const opus_int16 x[], /* I Speech signal */ + opus_int condCoding /* I The type of conditional coding to use */ +); + +/* LPC analysis */ +void silk_find_LPC_FIX( + silk_encoder_state *psEncC, /* I/O Encoder state */ + opus_int16 NLSF_Q15[], /* O NLSFs */ + const opus_int16 x[], /* I Input signal */ + const opus_int32 minInvGain_Q30 /* I Inverse of max prediction gain */ +); + +/* LTP analysis */ +void silk_find_LTP_FIX( + opus_int32 XXLTP_Q17[ MAX_NB_SUBFR * LTP_ORDER * LTP_ORDER ], /* O Correlation matrix */ + opus_int32 xXLTP_Q17[ MAX_NB_SUBFR * LTP_ORDER ], /* O Correlation vector */ + const opus_int16 r_lpc[], /* I Residual signal after LPC */ + const opus_int lag[ MAX_NB_SUBFR ], /* I LTP lags */ + const opus_int subfr_length, /* I Subframe length */ + const opus_int nb_subfr, /* I Number of subframes */ + int arch /* I Run-time architecture */ +); + +void silk_LTP_analysis_filter_FIX( + opus_int16 *LTP_res, /* O LTP residual signal of length MAX_NB_SUBFR * ( pre_length + subfr_length ) */ + const opus_int16 *x, /* I Pointer to input signal with at least max( pitchL ) preceding samples */ + const opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ],/* I LTP_ORDER LTP coefficients for each MAX_NB_SUBFR subframe */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lag, one for each subframe */ + const opus_int32 invGains_Q16[ MAX_NB_SUBFR ], /* I Inverse quantization gains, one for each subframe */ + const opus_int subfr_length, /* I Length of each subframe */ + const opus_int nb_subfr, /* I Number of subframes */ + const opus_int pre_length /* I Length of the preceding samples starting at &x[0] for each subframe */ +); + +/* Calculates residual energies of input subframes where all subframes have LPC_order */ +/* of preceding samples */ +void silk_residual_energy_FIX( + opus_int32 nrgs[ MAX_NB_SUBFR ], /* O Residual energy per subframe */ + opus_int nrgsQ[ MAX_NB_SUBFR ], /* O Q value per subframe */ + const opus_int16 x[], /* I Input signal */ + opus_int16 a_Q12[ 2 ][ MAX_LPC_ORDER ], /* I AR coefs for each frame half */ + const opus_int32 gains[ MAX_NB_SUBFR ], /* I Quantization gains */ + const opus_int subfr_length, /* I Subframe length */ + const opus_int nb_subfr, /* I Number of subframes */ + const opus_int LPC_order, /* I LPC order */ + int arch /* I Run-time architecture */ +); + +/* Residual energy: nrg = wxx - 2 * wXx * c + c' * wXX * c */ +opus_int32 silk_residual_energy16_covar_FIX( + const opus_int16 *c, /* I Prediction vector */ + const opus_int32 *wXX, /* I Correlation matrix */ + const opus_int32 *wXx, /* I Correlation vector */ + opus_int32 wxx, /* I Signal energy */ + opus_int D, /* I Dimension */ + opus_int cQ /* I Q value for c vector 0 - 15 */ +); + +/* Processing of gains */ +void silk_process_gains_FIX( + silk_encoder_state_FIX *psEnc, /* I/O Encoder state */ + silk_encoder_control_FIX *psEncCtrl, /* I/O Encoder control */ + opus_int condCoding /* I The type of conditional coding to use */ +); + +/******************/ +/* Linear Algebra */ +/******************/ +/* Calculates correlation matrix X'*X */ +void silk_corrMatrix_FIX( + const opus_int16 *x, /* I x vector [L + order - 1] used to form data matrix X */ + const opus_int L, /* I Length of vectors */ + const opus_int order, /* I Max lag for correlation */ + opus_int32 *XX, /* O Pointer to X'*X correlation matrix [ order x order ] */ + opus_int32 *nrg, /* O Energy of x vector */ + opus_int *rshifts, /* O Right shifts of correlations */ + int arch /* I Run-time architecture */ +); + +/* Calculates correlation vector X'*t */ +void silk_corrVector_FIX( + const opus_int16 *x, /* I x vector [L + order - 1] used to form data matrix X */ + const opus_int16 *t, /* I Target vector [L] */ + const opus_int L, /* I Length of vectors */ + const opus_int order, /* I Max lag for correlation */ + opus_int32 *Xt, /* O Pointer to X'*t correlation vector [order] */ + const opus_int rshifts, /* I Right shifts of correlations */ + int arch /* I Run-time architecture */ +); + +#ifndef FORCE_CPP_BUILD +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* FORCE_CPP_BUILD */ +#endif /* SILK_MAIN_FIX_H */ diff --git a/extern/opus/silk/fixed/mips/noise_shape_analysis_FIX_mipsr1.h b/extern/opus/silk/fixed/mips/noise_shape_analysis_FIX_mipsr1.h new file mode 100644 index 0000000..3999b5b --- /dev/null +++ b/extern/opus/silk/fixed/mips/noise_shape_analysis_FIX_mipsr1.h @@ -0,0 +1,336 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + + +/**************************************************************/ +/* Compute noise shaping coefficients and initial gain values */ +/**************************************************************/ +#define OVERRIDE_silk_noise_shape_analysis_FIX + +void silk_noise_shape_analysis_FIX( + silk_encoder_state_FIX *psEnc, /* I/O Encoder state FIX */ + silk_encoder_control_FIX *psEncCtrl, /* I/O Encoder control FIX */ + const opus_int16 *pitch_res, /* I LPC residual from pitch analysis */ + const opus_int16 *x, /* I Input signal [ frame_length + la_shape ] */ + int arch /* I Run-time architecture */ +) +{ + silk_shape_state_FIX *psShapeSt = &psEnc->sShape; + opus_int k, i, nSamples, Qnrg, b_Q14, warping_Q16, scale = 0; + opus_int32 SNR_adj_dB_Q7, HarmBoost_Q16, HarmShapeGain_Q16, Tilt_Q16, tmp32; + opus_int32 nrg, pre_nrg_Q30, log_energy_Q7, log_energy_prev_Q7, energy_variation_Q7; + opus_int32 delta_Q16, BWExp1_Q16, BWExp2_Q16, gain_mult_Q16, gain_add_Q16, strength_Q16, b_Q8; + opus_int32 auto_corr[ MAX_SHAPE_LPC_ORDER + 1 ]; + opus_int32 refl_coef_Q16[ MAX_SHAPE_LPC_ORDER ]; + opus_int32 AR1_Q24[ MAX_SHAPE_LPC_ORDER ]; + opus_int32 AR2_Q24[ MAX_SHAPE_LPC_ORDER ]; + VARDECL( opus_int16, x_windowed ); + const opus_int16 *x_ptr, *pitch_res_ptr; + SAVE_STACK; + + /* Point to start of first LPC analysis block */ + x_ptr = x - psEnc->sCmn.la_shape; + + /****************/ + /* GAIN CONTROL */ + /****************/ + SNR_adj_dB_Q7 = psEnc->sCmn.SNR_dB_Q7; + + /* Input quality is the average of the quality in the lowest two VAD bands */ + psEncCtrl->input_quality_Q14 = ( opus_int )silk_RSHIFT( (opus_int32)psEnc->sCmn.input_quality_bands_Q15[ 0 ] + + psEnc->sCmn.input_quality_bands_Q15[ 1 ], 2 ); + + /* Coding quality level, between 0.0_Q0 and 1.0_Q0, but in Q14 */ + psEncCtrl->coding_quality_Q14 = silk_RSHIFT( silk_sigm_Q15( silk_RSHIFT_ROUND( SNR_adj_dB_Q7 - + SILK_FIX_CONST( 20.0, 7 ), 4 ) ), 1 ); + + /* Reduce coding SNR during low speech activity */ + if( psEnc->sCmn.useCBR == 0 ) { + b_Q8 = SILK_FIX_CONST( 1.0, 8 ) - psEnc->sCmn.speech_activity_Q8; + b_Q8 = silk_SMULWB( silk_LSHIFT( b_Q8, 8 ), b_Q8 ); + SNR_adj_dB_Q7 = silk_SMLAWB( SNR_adj_dB_Q7, + silk_SMULBB( SILK_FIX_CONST( -BG_SNR_DECR_dB, 7 ) >> ( 4 + 1 ), b_Q8 ), /* Q11*/ + silk_SMULWB( SILK_FIX_CONST( 1.0, 14 ) + psEncCtrl->input_quality_Q14, psEncCtrl->coding_quality_Q14 ) ); /* Q12*/ + } + + if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) { + /* Reduce gains for periodic signals */ + SNR_adj_dB_Q7 = silk_SMLAWB( SNR_adj_dB_Q7, SILK_FIX_CONST( HARM_SNR_INCR_dB, 8 ), psEnc->LTPCorr_Q15 ); + } else { + /* For unvoiced signals and low-quality input, adjust the quality slower than SNR_dB setting */ + SNR_adj_dB_Q7 = silk_SMLAWB( SNR_adj_dB_Q7, + silk_SMLAWB( SILK_FIX_CONST( 6.0, 9 ), -SILK_FIX_CONST( 0.4, 18 ), psEnc->sCmn.SNR_dB_Q7 ), + SILK_FIX_CONST( 1.0, 14 ) - psEncCtrl->input_quality_Q14 ); + } + + /*************************/ + /* SPARSENESS PROCESSING */ + /*************************/ + /* Set quantizer offset */ + if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) { + /* Initially set to 0; may be overruled in process_gains(..) */ + psEnc->sCmn.indices.quantOffsetType = 0; + psEncCtrl->sparseness_Q8 = 0; + } else { + /* Sparseness measure, based on relative fluctuations of energy per 2 milliseconds */ + nSamples = silk_LSHIFT( psEnc->sCmn.fs_kHz, 1 ); + energy_variation_Q7 = 0; + log_energy_prev_Q7 = 0; + pitch_res_ptr = pitch_res; + for( k = 0; k < silk_SMULBB( SUB_FRAME_LENGTH_MS, psEnc->sCmn.nb_subfr ) / 2; k++ ) { + silk_sum_sqr_shift( &nrg, &scale, pitch_res_ptr, nSamples ); + nrg += silk_RSHIFT( nSamples, scale ); /* Q(-scale)*/ + + log_energy_Q7 = silk_lin2log( nrg ); + if( k > 0 ) { + energy_variation_Q7 += silk_abs( log_energy_Q7 - log_energy_prev_Q7 ); + } + log_energy_prev_Q7 = log_energy_Q7; + pitch_res_ptr += nSamples; + } + + psEncCtrl->sparseness_Q8 = silk_RSHIFT( silk_sigm_Q15( silk_SMULWB( energy_variation_Q7 - + SILK_FIX_CONST( 5.0, 7 ), SILK_FIX_CONST( 0.1, 16 ) ) ), 7 ); + + /* Set quantization offset depending on sparseness measure */ + if( psEncCtrl->sparseness_Q8 > SILK_FIX_CONST( SPARSENESS_THRESHOLD_QNT_OFFSET, 8 ) ) { + psEnc->sCmn.indices.quantOffsetType = 0; + } else { + psEnc->sCmn.indices.quantOffsetType = 1; + } + + /* Increase coding SNR for sparse signals */ + SNR_adj_dB_Q7 = silk_SMLAWB( SNR_adj_dB_Q7, SILK_FIX_CONST( SPARSE_SNR_INCR_dB, 15 ), psEncCtrl->sparseness_Q8 - SILK_FIX_CONST( 0.5, 8 ) ); + } + + /*******************************/ + /* Control bandwidth expansion */ + /*******************************/ + /* More BWE for signals with high prediction gain */ + strength_Q16 = silk_SMULWB( psEncCtrl->predGain_Q16, SILK_FIX_CONST( FIND_PITCH_WHITE_NOISE_FRACTION, 16 ) ); + BWExp1_Q16 = BWExp2_Q16 = silk_DIV32_varQ( SILK_FIX_CONST( BANDWIDTH_EXPANSION, 16 ), + silk_SMLAWW( SILK_FIX_CONST( 1.0, 16 ), strength_Q16, strength_Q16 ), 16 ); + delta_Q16 = silk_SMULWB( SILK_FIX_CONST( 1.0, 16 ) - silk_SMULBB( 3, psEncCtrl->coding_quality_Q14 ), + SILK_FIX_CONST( LOW_RATE_BANDWIDTH_EXPANSION_DELTA, 16 ) ); + BWExp1_Q16 = silk_SUB32( BWExp1_Q16, delta_Q16 ); + BWExp2_Q16 = silk_ADD32( BWExp2_Q16, delta_Q16 ); + /* BWExp1 will be applied after BWExp2, so make it relative */ + BWExp1_Q16 = silk_DIV32_16( silk_LSHIFT( BWExp1_Q16, 14 ), silk_RSHIFT( BWExp2_Q16, 2 ) ); + + if( psEnc->sCmn.warping_Q16 > 0 ) { + /* Slightly more warping in analysis will move quantization noise up in frequency, where it's better masked */ + warping_Q16 = silk_SMLAWB( psEnc->sCmn.warping_Q16, (opus_int32)psEncCtrl->coding_quality_Q14, SILK_FIX_CONST( 0.01, 18 ) ); + } else { + warping_Q16 = 0; + } + + /********************************************/ + /* Compute noise shaping AR coefs and gains */ + /********************************************/ + ALLOC( x_windowed, psEnc->sCmn.shapeWinLength, opus_int16 ); + for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) { + /* Apply window: sine slope followed by flat part followed by cosine slope */ + opus_int shift, slope_part, flat_part; + flat_part = psEnc->sCmn.fs_kHz * 3; + slope_part = silk_RSHIFT( psEnc->sCmn.shapeWinLength - flat_part, 1 ); + + silk_apply_sine_window( x_windowed, x_ptr, 1, slope_part ); + shift = slope_part; + silk_memcpy( x_windowed + shift, x_ptr + shift, flat_part * sizeof(opus_int16) ); + shift += flat_part; + silk_apply_sine_window( x_windowed + shift, x_ptr + shift, 2, slope_part ); + + /* Update pointer: next LPC analysis block */ + x_ptr += psEnc->sCmn.subfr_length; + + if( psEnc->sCmn.warping_Q16 > 0 ) { + /* Calculate warped auto correlation */ + silk_warped_autocorrelation_FIX( auto_corr, &scale, x_windowed, warping_Q16, psEnc->sCmn.shapeWinLength, psEnc->sCmn.shapingLPCOrder, arch ); + } else { + /* Calculate regular auto correlation */ + silk_autocorr( auto_corr, &scale, x_windowed, psEnc->sCmn.shapeWinLength, psEnc->sCmn.shapingLPCOrder + 1, arch ); + } + + /* Add white noise, as a fraction of energy */ + auto_corr[0] = silk_ADD32( auto_corr[0], silk_max_32( silk_SMULWB( silk_RSHIFT( auto_corr[ 0 ], 4 ), + SILK_FIX_CONST( SHAPE_WHITE_NOISE_FRACTION, 20 ) ), 1 ) ); + + /* Calculate the reflection coefficients using schur */ + nrg = silk_schur64( refl_coef_Q16, auto_corr, psEnc->sCmn.shapingLPCOrder ); + silk_assert( nrg >= 0 ); + + /* Convert reflection coefficients to prediction coefficients */ + silk_k2a_Q16( AR2_Q24, refl_coef_Q16, psEnc->sCmn.shapingLPCOrder ); + + Qnrg = -scale; /* range: -12...30*/ + silk_assert( Qnrg >= -12 ); + silk_assert( Qnrg <= 30 ); + + /* Make sure that Qnrg is an even number */ + if( Qnrg & 1 ) { + Qnrg -= 1; + nrg >>= 1; + } + + tmp32 = silk_SQRT_APPROX( nrg ); + Qnrg >>= 1; /* range: -6...15*/ + + psEncCtrl->Gains_Q16[ k ] = (silk_LSHIFT32( silk_LIMIT( (tmp32), silk_RSHIFT32( silk_int32_MIN, (16 - Qnrg) ), \ + silk_RSHIFT32( silk_int32_MAX, (16 - Qnrg) ) ), (16 - Qnrg) )); + + if( psEnc->sCmn.warping_Q16 > 0 ) { + /* Adjust gain for warping */ + gain_mult_Q16 = warped_gain( AR2_Q24, warping_Q16, psEnc->sCmn.shapingLPCOrder ); + silk_assert( psEncCtrl->Gains_Q16[ k ] >= 0 ); + if ( silk_SMULWW( silk_RSHIFT_ROUND( psEncCtrl->Gains_Q16[ k ], 1 ), gain_mult_Q16 ) >= ( silk_int32_MAX >> 1 ) ) { + psEncCtrl->Gains_Q16[ k ] = silk_int32_MAX; + } else { + psEncCtrl->Gains_Q16[ k ] = silk_SMULWW( psEncCtrl->Gains_Q16[ k ], gain_mult_Q16 ); + } + } + + /* Bandwidth expansion for synthesis filter shaping */ + silk_bwexpander_32( AR2_Q24, psEnc->sCmn.shapingLPCOrder, BWExp2_Q16 ); + + /* Compute noise shaping filter coefficients */ + silk_memcpy( AR1_Q24, AR2_Q24, psEnc->sCmn.shapingLPCOrder * sizeof( opus_int32 ) ); + + /* Bandwidth expansion for analysis filter shaping */ + silk_assert( BWExp1_Q16 <= SILK_FIX_CONST( 1.0, 16 ) ); + silk_bwexpander_32( AR1_Q24, psEnc->sCmn.shapingLPCOrder, BWExp1_Q16 ); + + /* Ratio of prediction gains, in energy domain */ + pre_nrg_Q30 = silk_LPC_inverse_pred_gain_Q24( AR2_Q24, psEnc->sCmn.shapingLPCOrder, arch ); + nrg = silk_LPC_inverse_pred_gain_Q24( AR1_Q24, psEnc->sCmn.shapingLPCOrder, arch ); + + /*psEncCtrl->GainsPre[ k ] = 1.0f - 0.7f * ( 1.0f - pre_nrg / nrg ) = 0.3f + 0.7f * pre_nrg / nrg;*/ + pre_nrg_Q30 = silk_LSHIFT32( silk_SMULWB( pre_nrg_Q30, SILK_FIX_CONST( 0.7, 15 ) ), 1 ); + psEncCtrl->GainsPre_Q14[ k ] = ( opus_int ) SILK_FIX_CONST( 0.3, 14 ) + silk_DIV32_varQ( pre_nrg_Q30, nrg, 14 ); + + /* Convert to monic warped prediction coefficients and limit absolute values */ + limit_warped_coefs( AR2_Q24, AR1_Q24, warping_Q16, SILK_FIX_CONST( 3.999, 24 ), psEnc->sCmn.shapingLPCOrder ); + + /* Convert from Q24 to Q13 and store in int16 */ + for( i = 0; i < psEnc->sCmn.shapingLPCOrder; i++ ) { + psEncCtrl->AR1_Q13[ k * MAX_SHAPE_LPC_ORDER + i ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( AR1_Q24[ i ], 11 ) ); + psEncCtrl->AR2_Q13[ k * MAX_SHAPE_LPC_ORDER + i ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( AR2_Q24[ i ], 11 ) ); + } + } + + /*****************/ + /* Gain tweaking */ + /*****************/ + /* Increase gains during low speech activity and put lower limit on gains */ + gain_mult_Q16 = silk_log2lin( -silk_SMLAWB( -SILK_FIX_CONST( 16.0, 7 ), SNR_adj_dB_Q7, SILK_FIX_CONST( 0.16, 16 ) ) ); + gain_add_Q16 = silk_log2lin( silk_SMLAWB( SILK_FIX_CONST( 16.0, 7 ), SILK_FIX_CONST( MIN_QGAIN_DB, 7 ), SILK_FIX_CONST( 0.16, 16 ) ) ); + silk_assert( gain_mult_Q16 > 0 ); + for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) { + psEncCtrl->Gains_Q16[ k ] = silk_SMULWW( psEncCtrl->Gains_Q16[ k ], gain_mult_Q16 ); + silk_assert( psEncCtrl->Gains_Q16[ k ] >= 0 ); + psEncCtrl->Gains_Q16[ k ] = silk_ADD_POS_SAT32( psEncCtrl->Gains_Q16[ k ], gain_add_Q16 ); + } + + gain_mult_Q16 = SILK_FIX_CONST( 1.0, 16 ) + silk_RSHIFT_ROUND( silk_MLA( SILK_FIX_CONST( INPUT_TILT, 26 ), + psEncCtrl->coding_quality_Q14, SILK_FIX_CONST( HIGH_RATE_INPUT_TILT, 12 ) ), 10 ); + for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) { + psEncCtrl->GainsPre_Q14[ k ] = silk_SMULWB( gain_mult_Q16, psEncCtrl->GainsPre_Q14[ k ] ); + } + + /************************************************/ + /* Control low-frequency shaping and noise tilt */ + /************************************************/ + /* Less low frequency shaping for noisy inputs */ + strength_Q16 = silk_MUL( SILK_FIX_CONST( LOW_FREQ_SHAPING, 4 ), silk_SMLAWB( SILK_FIX_CONST( 1.0, 12 ), + SILK_FIX_CONST( LOW_QUALITY_LOW_FREQ_SHAPING_DECR, 13 ), psEnc->sCmn.input_quality_bands_Q15[ 0 ] - SILK_FIX_CONST( 1.0, 15 ) ) ); + strength_Q16 = silk_RSHIFT( silk_MUL( strength_Q16, psEnc->sCmn.speech_activity_Q8 ), 8 ); + if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) { + /* Reduce low frequencies quantization noise for periodic signals, depending on pitch lag */ + /*f = 400; freqz([1, -0.98 + 2e-4 * f], [1, -0.97 + 7e-4 * f], 2^12, Fs); axis([0, 1000, -10, 1])*/ + opus_int fs_kHz_inv = silk_DIV32_16( SILK_FIX_CONST( 0.2, 14 ), psEnc->sCmn.fs_kHz ); + for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) { + b_Q14 = fs_kHz_inv + silk_DIV32_16( SILK_FIX_CONST( 3.0, 14 ), psEncCtrl->pitchL[ k ] ); + /* Pack two coefficients in one int32 */ + psEncCtrl->LF_shp_Q14[ k ] = silk_LSHIFT( SILK_FIX_CONST( 1.0, 14 ) - b_Q14 - silk_SMULWB( strength_Q16, b_Q14 ), 16 ); + psEncCtrl->LF_shp_Q14[ k ] |= (opus_uint16)( b_Q14 - SILK_FIX_CONST( 1.0, 14 ) ); + } + silk_assert( SILK_FIX_CONST( HARM_HP_NOISE_COEF, 24 ) < SILK_FIX_CONST( 0.5, 24 ) ); /* Guarantees that second argument to SMULWB() is within range of an opus_int16*/ + Tilt_Q16 = - SILK_FIX_CONST( HP_NOISE_COEF, 16 ) - + silk_SMULWB( SILK_FIX_CONST( 1.0, 16 ) - SILK_FIX_CONST( HP_NOISE_COEF, 16 ), + silk_SMULWB( SILK_FIX_CONST( HARM_HP_NOISE_COEF, 24 ), psEnc->sCmn.speech_activity_Q8 ) ); + } else { + b_Q14 = silk_DIV32_16( 21299, psEnc->sCmn.fs_kHz ); /* 1.3_Q0 = 21299_Q14*/ + /* Pack two coefficients in one int32 */ + psEncCtrl->LF_shp_Q14[ 0 ] = silk_LSHIFT( SILK_FIX_CONST( 1.0, 14 ) - b_Q14 - + silk_SMULWB( strength_Q16, silk_SMULWB( SILK_FIX_CONST( 0.6, 16 ), b_Q14 ) ), 16 ); + psEncCtrl->LF_shp_Q14[ 0 ] |= (opus_uint16)( b_Q14 - SILK_FIX_CONST( 1.0, 14 ) ); + for( k = 1; k < psEnc->sCmn.nb_subfr; k++ ) { + psEncCtrl->LF_shp_Q14[ k ] = psEncCtrl->LF_shp_Q14[ 0 ]; + } + Tilt_Q16 = -SILK_FIX_CONST( HP_NOISE_COEF, 16 ); + } + + /****************************/ + /* HARMONIC SHAPING CONTROL */ + /****************************/ + /* Control boosting of harmonic frequencies */ + HarmBoost_Q16 = silk_SMULWB( silk_SMULWB( SILK_FIX_CONST( 1.0, 17 ) - silk_LSHIFT( psEncCtrl->coding_quality_Q14, 3 ), + psEnc->LTPCorr_Q15 ), SILK_FIX_CONST( LOW_RATE_HARMONIC_BOOST, 16 ) ); + + /* More harmonic boost for noisy input signals */ + HarmBoost_Q16 = silk_SMLAWB( HarmBoost_Q16, + SILK_FIX_CONST( 1.0, 16 ) - silk_LSHIFT( psEncCtrl->input_quality_Q14, 2 ), SILK_FIX_CONST( LOW_INPUT_QUALITY_HARMONIC_BOOST, 16 ) ); + + if( USE_HARM_SHAPING && psEnc->sCmn.indices.signalType == TYPE_VOICED ) { + /* More harmonic noise shaping for high bitrates or noisy input */ + HarmShapeGain_Q16 = silk_SMLAWB( SILK_FIX_CONST( HARMONIC_SHAPING, 16 ), + SILK_FIX_CONST( 1.0, 16 ) - silk_SMULWB( SILK_FIX_CONST( 1.0, 18 ) - silk_LSHIFT( psEncCtrl->coding_quality_Q14, 4 ), + psEncCtrl->input_quality_Q14 ), SILK_FIX_CONST( HIGH_RATE_OR_LOW_QUALITY_HARMONIC_SHAPING, 16 ) ); + + /* Less harmonic noise shaping for less periodic signals */ + HarmShapeGain_Q16 = silk_SMULWB( silk_LSHIFT( HarmShapeGain_Q16, 1 ), + silk_SQRT_APPROX( silk_LSHIFT( psEnc->LTPCorr_Q15, 15 ) ) ); + } else { + HarmShapeGain_Q16 = 0; + } + + /*************************/ + /* Smooth over subframes */ + /*************************/ + for( k = 0; k < MAX_NB_SUBFR; k++ ) { + psShapeSt->HarmBoost_smth_Q16 = + silk_SMLAWB( psShapeSt->HarmBoost_smth_Q16, HarmBoost_Q16 - psShapeSt->HarmBoost_smth_Q16, SILK_FIX_CONST( SUBFR_SMTH_COEF, 16 ) ); + psShapeSt->HarmShapeGain_smth_Q16 = + silk_SMLAWB( psShapeSt->HarmShapeGain_smth_Q16, HarmShapeGain_Q16 - psShapeSt->HarmShapeGain_smth_Q16, SILK_FIX_CONST( SUBFR_SMTH_COEF, 16 ) ); + psShapeSt->Tilt_smth_Q16 = + silk_SMLAWB( psShapeSt->Tilt_smth_Q16, Tilt_Q16 - psShapeSt->Tilt_smth_Q16, SILK_FIX_CONST( SUBFR_SMTH_COEF, 16 ) ); + + psEncCtrl->HarmBoost_Q14[ k ] = ( opus_int )silk_RSHIFT_ROUND( psShapeSt->HarmBoost_smth_Q16, 2 ); + psEncCtrl->HarmShapeGain_Q14[ k ] = ( opus_int )silk_RSHIFT_ROUND( psShapeSt->HarmShapeGain_smth_Q16, 2 ); + psEncCtrl->Tilt_Q14[ k ] = ( opus_int )silk_RSHIFT_ROUND( psShapeSt->Tilt_smth_Q16, 2 ); + } + RESTORE_STACK; +} diff --git a/extern/opus/silk/fixed/mips/prefilter_FIX_mipsr1.h b/extern/opus/silk/fixed/mips/prefilter_FIX_mipsr1.h new file mode 100644 index 0000000..21b2568 --- /dev/null +++ b/extern/opus/silk/fixed/mips/prefilter_FIX_mipsr1.h @@ -0,0 +1,184 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ +#ifndef __PREFILTER_FIX_MIPSR1_H__ +#define __PREFILTER_FIX_MIPSR1_H__ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FIX.h" +#include "stack_alloc.h" +#include "tuning_parameters.h" + +#define OVERRIDE_silk_warped_LPC_analysis_filter_FIX +void silk_warped_LPC_analysis_filter_FIX( + opus_int32 state[], /* I/O State [order + 1] */ + opus_int32 res_Q2[], /* O Residual signal [length] */ + const opus_int16 coef_Q13[], /* I Coefficients [order] */ + const opus_int16 input[], /* I Input signal [length] */ + const opus_int16 lambda_Q16, /* I Warping factor */ + const opus_int length, /* I Length of input signal */ + const opus_int order, /* I Filter order (even) */ + int arch +) +{ + opus_int n, i; + opus_int32 acc_Q11, acc_Q22, tmp1, tmp2, tmp3, tmp4; + opus_int32 state_cur, state_next; + + (void)arch; + + /* Order must be even */ + /* Length must be even */ + + silk_assert( ( order & 1 ) == 0 ); + silk_assert( ( length & 1 ) == 0 ); + + for( n = 0; n < length; n+=2 ) { + /* Output of lowpass section */ + tmp2 = silk_SMLAWB( state[ 0 ], state[ 1 ], lambda_Q16 ); + state_cur = silk_LSHIFT( input[ n ], 14 ); + /* Output of allpass section */ + tmp1 = silk_SMLAWB( state[ 1 ], state[ 2 ] - tmp2, lambda_Q16 ); + state_next = tmp2; + acc_Q11 = silk_RSHIFT( order, 1 ); + acc_Q11 = silk_SMLAWB( acc_Q11, tmp2, coef_Q13[ 0 ] ); + + + /* Output of lowpass section */ + tmp4 = silk_SMLAWB( state_cur, state_next, lambda_Q16 ); + state[ 0 ] = silk_LSHIFT( input[ n+1 ], 14 ); + /* Output of allpass section */ + tmp3 = silk_SMLAWB( state_next, tmp1 - tmp4, lambda_Q16 ); + state[ 1 ] = tmp4; + acc_Q22 = silk_RSHIFT( order, 1 ); + acc_Q22 = silk_SMLAWB( acc_Q22, tmp4, coef_Q13[ 0 ] ); + + /* Loop over allpass sections */ + for( i = 2; i < order; i += 2 ) { + /* Output of allpass section */ + tmp2 = silk_SMLAWB( state[ i ], state[ i + 1 ] - tmp1, lambda_Q16 ); + state_cur = tmp1; + acc_Q11 = silk_SMLAWB( acc_Q11, tmp1, coef_Q13[ i - 1 ] ); + /* Output of allpass section */ + tmp1 = silk_SMLAWB( state[ i + 1 ], state[ i + 2 ] - tmp2, lambda_Q16 ); + state_next = tmp2; + acc_Q11 = silk_SMLAWB( acc_Q11, tmp2, coef_Q13[ i ] ); + + + /* Output of allpass section */ + tmp4 = silk_SMLAWB( state_cur, state_next - tmp3, lambda_Q16 ); + state[ i ] = tmp3; + acc_Q22 = silk_SMLAWB( acc_Q22, tmp3, coef_Q13[ i - 1 ] ); + /* Output of allpass section */ + tmp3 = silk_SMLAWB( state_next, tmp1 - tmp4, lambda_Q16 ); + state[ i + 1 ] = tmp4; + acc_Q22 = silk_SMLAWB( acc_Q22, tmp4, coef_Q13[ i ] ); + } + acc_Q11 = silk_SMLAWB( acc_Q11, tmp1, coef_Q13[ order - 1 ] ); + res_Q2[ n ] = silk_LSHIFT( (opus_int32)input[ n ], 2 ) - silk_RSHIFT_ROUND( acc_Q11, 9 ); + + state[ order ] = tmp3; + acc_Q22 = silk_SMLAWB( acc_Q22, tmp3, coef_Q13[ order - 1 ] ); + res_Q2[ n+1 ] = silk_LSHIFT( (opus_int32)input[ n+1 ], 2 ) - silk_RSHIFT_ROUND( acc_Q22, 9 ); + } +} + + + +/* Prefilter for finding Quantizer input signal */ +#define OVERRIDE_silk_prefilt_FIX +static inline void silk_prefilt_FIX( + silk_prefilter_state_FIX *P, /* I/O state */ + opus_int32 st_res_Q12[], /* I short term residual signal */ + opus_int32 xw_Q3[], /* O prefiltered signal */ + opus_int32 HarmShapeFIRPacked_Q12, /* I Harmonic shaping coeficients */ + opus_int Tilt_Q14, /* I Tilt shaping coeficient */ + opus_int32 LF_shp_Q14, /* I Low-frequancy shaping coeficients */ + opus_int lag, /* I Lag for harmonic shaping */ + opus_int length /* I Length of signals */ +) +{ + opus_int i, idx, LTP_shp_buf_idx; + opus_int32 n_LTP_Q12, n_Tilt_Q10, n_LF_Q10; + opus_int32 sLF_MA_shp_Q12, sLF_AR_shp_Q12; + opus_int16 *LTP_shp_buf; + + /* To speed up use temp variables instead of using the struct */ + LTP_shp_buf = P->sLTP_shp; + LTP_shp_buf_idx = P->sLTP_shp_buf_idx; + sLF_AR_shp_Q12 = P->sLF_AR_shp_Q12; + sLF_MA_shp_Q12 = P->sLF_MA_shp_Q12; + + if( lag > 0 ) { + for( i = 0; i < length; i++ ) { + /* unrolled loop */ + silk_assert( HARM_SHAPE_FIR_TAPS == 3 ); + idx = lag + LTP_shp_buf_idx; + n_LTP_Q12 = silk_SMULBB( LTP_shp_buf[ ( idx - HARM_SHAPE_FIR_TAPS / 2 - 1) & LTP_MASK ], HarmShapeFIRPacked_Q12 ); + n_LTP_Q12 = silk_SMLABT( n_LTP_Q12, LTP_shp_buf[ ( idx - HARM_SHAPE_FIR_TAPS / 2 ) & LTP_MASK ], HarmShapeFIRPacked_Q12 ); + n_LTP_Q12 = silk_SMLABB( n_LTP_Q12, LTP_shp_buf[ ( idx - HARM_SHAPE_FIR_TAPS / 2 + 1) & LTP_MASK ], HarmShapeFIRPacked_Q12 ); + + n_Tilt_Q10 = silk_SMULWB( sLF_AR_shp_Q12, Tilt_Q14 ); + n_LF_Q10 = silk_SMLAWB( silk_SMULWT( sLF_AR_shp_Q12, LF_shp_Q14 ), sLF_MA_shp_Q12, LF_shp_Q14 ); + + sLF_AR_shp_Q12 = silk_SUB32( st_res_Q12[ i ], silk_LSHIFT( n_Tilt_Q10, 2 ) ); + sLF_MA_shp_Q12 = silk_SUB32( sLF_AR_shp_Q12, silk_LSHIFT( n_LF_Q10, 2 ) ); + + LTP_shp_buf_idx = ( LTP_shp_buf_idx - 1 ) & LTP_MASK; + LTP_shp_buf[ LTP_shp_buf_idx ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( sLF_MA_shp_Q12, 12 ) ); + + xw_Q3[i] = silk_RSHIFT_ROUND( silk_SUB32( sLF_MA_shp_Q12, n_LTP_Q12 ), 9 ); + } + } + else + { + for( i = 0; i < length; i++ ) { + + n_LTP_Q12 = 0; + + n_Tilt_Q10 = silk_SMULWB( sLF_AR_shp_Q12, Tilt_Q14 ); + n_LF_Q10 = silk_SMLAWB( silk_SMULWT( sLF_AR_shp_Q12, LF_shp_Q14 ), sLF_MA_shp_Q12, LF_shp_Q14 ); + + sLF_AR_shp_Q12 = silk_SUB32( st_res_Q12[ i ], silk_LSHIFT( n_Tilt_Q10, 2 ) ); + sLF_MA_shp_Q12 = silk_SUB32( sLF_AR_shp_Q12, silk_LSHIFT( n_LF_Q10, 2 ) ); + + LTP_shp_buf_idx = ( LTP_shp_buf_idx - 1 ) & LTP_MASK; + LTP_shp_buf[ LTP_shp_buf_idx ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( sLF_MA_shp_Q12, 12 ) ); + + xw_Q3[i] = silk_RSHIFT_ROUND( sLF_MA_shp_Q12, 9 ); + } + } + + /* Copy temp variable back to state */ + 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; +} + +#endif /* __PREFILTER_FIX_MIPSR1_H__ */ diff --git a/extern/opus/silk/fixed/mips/warped_autocorrelation_FIX_mipsr1.h b/extern/opus/silk/fixed/mips/warped_autocorrelation_FIX_mipsr1.h new file mode 100644 index 0000000..66eb2ed --- /dev/null +++ b/extern/opus/silk/fixed/mips/warped_autocorrelation_FIX_mipsr1.h @@ -0,0 +1,165 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifndef __WARPED_AUTOCORRELATION_FIX_MIPSR1_H__ +#define __WARPED_AUTOCORRELATION_FIX_MIPSR1_H__ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FIX.h" + +#undef QC +#define QC 10 + +#undef QS +#define QS 14 + +/* Autocorrelations for a warped frequency axis */ +#define OVERRIDE_silk_warped_autocorrelation_FIX_c +void silk_warped_autocorrelation_FIX_c( + opus_int32 *corr, /* O Result [order + 1] */ + opus_int *scale, /* O Scaling of the correlation vector */ + const opus_int16 *input, /* I Input data to correlate */ + const opus_int warping_Q16, /* I Warping coefficient */ + const opus_int length, /* I Length of input */ + const opus_int order /* I Correlation order (even) */ +) +{ + opus_int n, i, lsh; + opus_int32 tmp1_QS=0, tmp2_QS=0, tmp3_QS=0, tmp4_QS=0, tmp5_QS=0, tmp6_QS=0, tmp7_QS=0, tmp8_QS=0, start_1=0, start_2=0, start_3=0; + opus_int32 state_QS[ MAX_SHAPE_LPC_ORDER + 1 ] = { 0 }; + opus_int64 corr_QC[ MAX_SHAPE_LPC_ORDER + 1 ] = { 0 }; + opus_int64 temp64; + + opus_int32 val; + val = 2 * QS - QC; + + /* Order must be even */ + silk_assert( ( order & 1 ) == 0 ); + silk_assert( 2 * QS - QC >= 0 ); + + /* Loop over samples */ + for( n = 0; n < length; n=n+4 ) { + + tmp1_QS = silk_LSHIFT32( (opus_int32)input[ n ], QS ); + start_1 = tmp1_QS; + tmp3_QS = silk_LSHIFT32( (opus_int32)input[ n+1], QS ); + start_2 = tmp3_QS; + tmp5_QS = silk_LSHIFT32( (opus_int32)input[ n+2], QS ); + start_3 = tmp5_QS; + tmp7_QS = silk_LSHIFT32( (opus_int32)input[ n+3], QS ); + + /* Loop over allpass sections */ + for( i = 0; i < order; i += 2 ) { + /* Output of allpass section */ + tmp2_QS = silk_SMLAWB( state_QS[ i ], state_QS[ i + 1 ] - tmp1_QS, warping_Q16 ); + corr_QC[ i ] = __builtin_mips_madd( corr_QC[ i ], tmp1_QS, start_1); + + tmp4_QS = silk_SMLAWB( tmp1_QS, tmp2_QS - tmp3_QS, warping_Q16 ); + corr_QC[ i ] = __builtin_mips_madd( corr_QC[ i ], tmp3_QS, start_2); + + tmp6_QS = silk_SMLAWB( tmp3_QS, tmp4_QS - tmp5_QS, warping_Q16 ); + corr_QC[ i ] = __builtin_mips_madd( corr_QC[ i ], tmp5_QS, start_3); + + tmp8_QS = silk_SMLAWB( tmp5_QS, tmp6_QS - tmp7_QS, warping_Q16 ); + state_QS[ i ] = tmp7_QS; + corr_QC[ i ] = __builtin_mips_madd( corr_QC[ i ], tmp7_QS, state_QS[0]); + + /* Output of allpass section */ + tmp1_QS = silk_SMLAWB( state_QS[ i + 1 ], state_QS[ i + 2 ] - tmp2_QS, warping_Q16 ); + corr_QC[ i+1 ] = __builtin_mips_madd( corr_QC[ i+1 ], tmp2_QS, start_1); + + tmp3_QS = silk_SMLAWB( tmp2_QS, tmp1_QS - tmp4_QS, warping_Q16 ); + corr_QC[ i+1 ] = __builtin_mips_madd( corr_QC[ i+1 ], tmp4_QS, start_2); + + tmp5_QS = silk_SMLAWB( tmp4_QS, tmp3_QS - tmp6_QS, warping_Q16 ); + corr_QC[ i+1 ] = __builtin_mips_madd( corr_QC[ i+1 ], tmp6_QS, start_3); + + tmp7_QS = silk_SMLAWB( tmp6_QS, tmp5_QS - tmp8_QS, warping_Q16 ); + state_QS[ i + 1 ] = tmp8_QS; + corr_QC[ i+1 ] = __builtin_mips_madd( corr_QC[ i+1 ], tmp8_QS, state_QS[ 0 ]); + + } + state_QS[ order ] = tmp7_QS; + + corr_QC[ order ] = __builtin_mips_madd( corr_QC[ order ], tmp1_QS, start_1); + corr_QC[ order ] = __builtin_mips_madd( corr_QC[ order ], tmp3_QS, start_2); + corr_QC[ order ] = __builtin_mips_madd( corr_QC[ order ], tmp5_QS, start_3); + corr_QC[ order ] = __builtin_mips_madd( corr_QC[ order ], tmp7_QS, state_QS[ 0 ]); + } + + for(;n< length; n++ ) { + + tmp1_QS = silk_LSHIFT32( (opus_int32)input[ n ], QS ); + + /* Loop over allpass sections */ + for( i = 0; i < order; i += 2 ) { + + /* Output of allpass section */ + tmp2_QS = silk_SMLAWB( state_QS[ i ], state_QS[ i + 1 ] - tmp1_QS, warping_Q16 ); + state_QS[ i ] = tmp1_QS; + corr_QC[ i ] = __builtin_mips_madd( corr_QC[ i ], tmp1_QS, state_QS[ 0 ]); + + /* Output of allpass section */ + tmp1_QS = silk_SMLAWB( state_QS[ i + 1 ], state_QS[ i + 2 ] - tmp2_QS, warping_Q16 ); + state_QS[ i + 1 ] = tmp2_QS; + corr_QC[ i+1 ] = __builtin_mips_madd( corr_QC[ i+1 ], tmp2_QS, state_QS[ 0 ]); + } + state_QS[ order ] = tmp1_QS; + corr_QC[ order ] = __builtin_mips_madd( corr_QC[ order ], tmp1_QS, state_QS[ 0 ]); + } + + temp64 = corr_QC[ 0 ]; + temp64 = __builtin_mips_shilo(temp64, val); + + lsh = silk_CLZ64( temp64 ) - 35; + lsh = silk_LIMIT( lsh, -12 - QC, 30 - QC ); + *scale = -( QC + lsh ); + silk_assert( *scale >= -30 && *scale <= 12 ); + if( lsh >= 0 ) { + for( i = 0; i < order + 1; i++ ) { + temp64 = corr_QC[ i ]; + //temp64 = __builtin_mips_shilo(temp64, val); + temp64 = (val >= 0) ? (temp64 >> val) : (temp64 << -val); + corr[ i ] = (opus_int32)silk_CHECK_FIT32( __builtin_mips_shilo( temp64, -lsh ) ); + } + } else { + for( i = 0; i < order + 1; i++ ) { + temp64 = corr_QC[ i ]; + //temp64 = __builtin_mips_shilo(temp64, val); + temp64 = (val >= 0) ? (temp64 >> val) : (temp64 << -val); + corr[ i ] = (opus_int32)silk_CHECK_FIT32( __builtin_mips_shilo( temp64, -lsh ) ); + } + } + + corr_QC[ 0 ] = __builtin_mips_shilo(corr_QC[ 0 ], val); + + silk_assert( corr_QC[ 0 ] >= 0 ); /* If breaking, decrease QC*/ +} +#endif /* __WARPED_AUTOCORRELATION_FIX_MIPSR1_H__ */ diff --git a/extern/opus/silk/fixed/noise_shape_analysis_FIX.c b/extern/opus/silk/fixed/noise_shape_analysis_FIX.c new file mode 100644 index 0000000..85fea0b --- /dev/null +++ b/extern/opus/silk/fixed/noise_shape_analysis_FIX.c @@ -0,0 +1,407 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FIX.h" +#include "stack_alloc.h" +#include "tuning_parameters.h" + +/* Compute gain to make warped filter coefficients have a zero mean log frequency response on a */ +/* non-warped frequency scale. (So that it can be implemented with a minimum-phase monic filter.) */ +/* Note: A monic filter is one with the first coefficient equal to 1.0. In Silk we omit the first */ +/* coefficient in an array of coefficients, for monic filters. */ +static OPUS_INLINE opus_int32 warped_gain( /* gain in Q16*/ + const opus_int32 *coefs_Q24, + opus_int lambda_Q16, + opus_int order +) { + opus_int i; + opus_int32 gain_Q24; + + lambda_Q16 = -lambda_Q16; + gain_Q24 = coefs_Q24[ order - 1 ]; + for( i = order - 2; i >= 0; i-- ) { + gain_Q24 = silk_SMLAWB( coefs_Q24[ i ], gain_Q24, lambda_Q16 ); + } + gain_Q24 = silk_SMLAWB( SILK_FIX_CONST( 1.0, 24 ), gain_Q24, -lambda_Q16 ); + return silk_INVERSE32_varQ( gain_Q24, 40 ); +} + +/* Convert warped filter coefficients to monic pseudo-warped coefficients and limit maximum */ +/* amplitude of monic warped coefficients by using bandwidth expansion on the true coefficients */ +static OPUS_INLINE void limit_warped_coefs( + opus_int32 *coefs_Q24, + opus_int lambda_Q16, + opus_int32 limit_Q24, + opus_int order +) { + opus_int i, iter, ind = 0; + opus_int32 tmp, maxabs_Q24, chirp_Q16, gain_Q16; + opus_int32 nom_Q16, den_Q24; + opus_int32 limit_Q20, maxabs_Q20; + + /* Convert to monic coefficients */ + lambda_Q16 = -lambda_Q16; + for( i = order - 1; i > 0; i-- ) { + coefs_Q24[ i - 1 ] = silk_SMLAWB( coefs_Q24[ i - 1 ], coefs_Q24[ i ], lambda_Q16 ); + } + lambda_Q16 = -lambda_Q16; + nom_Q16 = silk_SMLAWB( SILK_FIX_CONST( 1.0, 16 ), -(opus_int32)lambda_Q16, lambda_Q16 ); + den_Q24 = silk_SMLAWB( SILK_FIX_CONST( 1.0, 24 ), coefs_Q24[ 0 ], lambda_Q16 ); + gain_Q16 = silk_DIV32_varQ( nom_Q16, den_Q24, 24 ); + for( i = 0; i < order; i++ ) { + coefs_Q24[ i ] = silk_SMULWW( gain_Q16, coefs_Q24[ i ] ); + } + limit_Q20 = silk_RSHIFT(limit_Q24, 4); + for( iter = 0; iter < 10; iter++ ) { + /* Find maximum absolute value */ + maxabs_Q24 = -1; + for( i = 0; i < order; i++ ) { + tmp = silk_abs_int32( coefs_Q24[ i ] ); + if( tmp > maxabs_Q24 ) { + maxabs_Q24 = tmp; + ind = i; + } + } + /* Use Q20 to avoid any overflow when multiplying by (ind + 1) later. */ + maxabs_Q20 = silk_RSHIFT(maxabs_Q24, 4); + if( maxabs_Q20 <= limit_Q20 ) { + /* Coefficients are within range - done */ + return; + } + + /* Convert back to true warped coefficients */ + for( i = 1; i < order; i++ ) { + coefs_Q24[ i - 1 ] = silk_SMLAWB( coefs_Q24[ i - 1 ], coefs_Q24[ i ], lambda_Q16 ); + } + gain_Q16 = silk_INVERSE32_varQ( gain_Q16, 32 ); + for( i = 0; i < order; i++ ) { + coefs_Q24[ i ] = silk_SMULWW( gain_Q16, coefs_Q24[ i ] ); + } + + /* Apply bandwidth expansion */ + chirp_Q16 = SILK_FIX_CONST( 0.99, 16 ) - silk_DIV32_varQ( + silk_SMULWB( maxabs_Q20 - limit_Q20, silk_SMLABB( SILK_FIX_CONST( 0.8, 10 ), SILK_FIX_CONST( 0.1, 10 ), iter ) ), + silk_MUL( maxabs_Q20, ind + 1 ), 22 ); + silk_bwexpander_32( coefs_Q24, order, chirp_Q16 ); + + /* Convert to monic warped coefficients */ + lambda_Q16 = -lambda_Q16; + for( i = order - 1; i > 0; i-- ) { + coefs_Q24[ i - 1 ] = silk_SMLAWB( coefs_Q24[ i - 1 ], coefs_Q24[ i ], lambda_Q16 ); + } + lambda_Q16 = -lambda_Q16; + nom_Q16 = silk_SMLAWB( SILK_FIX_CONST( 1.0, 16 ), -(opus_int32)lambda_Q16, lambda_Q16 ); + den_Q24 = silk_SMLAWB( SILK_FIX_CONST( 1.0, 24 ), coefs_Q24[ 0 ], lambda_Q16 ); + gain_Q16 = silk_DIV32_varQ( nom_Q16, den_Q24, 24 ); + for( i = 0; i < order; i++ ) { + coefs_Q24[ i ] = silk_SMULWW( gain_Q16, coefs_Q24[ i ] ); + } + } + silk_assert( 0 ); +} + +/* Disable MIPS version until it's updated. */ +#if 0 && defined(MIPSr1_ASM) +#include "mips/noise_shape_analysis_FIX_mipsr1.h" +#endif + +/**************************************************************/ +/* Compute noise shaping coefficients and initial gain values */ +/**************************************************************/ +#ifndef OVERRIDE_silk_noise_shape_analysis_FIX +void silk_noise_shape_analysis_FIX( + silk_encoder_state_FIX *psEnc, /* I/O Encoder state FIX */ + silk_encoder_control_FIX *psEncCtrl, /* I/O Encoder control FIX */ + const opus_int16 *pitch_res, /* I LPC residual from pitch analysis */ + const opus_int16 *x, /* I Input signal [ frame_length + la_shape ] */ + int arch /* I Run-time architecture */ +) +{ + silk_shape_state_FIX *psShapeSt = &psEnc->sShape; + opus_int k, i, nSamples, nSegs, Qnrg, b_Q14, warping_Q16, scale = 0; + opus_int32 SNR_adj_dB_Q7, HarmShapeGain_Q16, Tilt_Q16, tmp32; + opus_int32 nrg, log_energy_Q7, log_energy_prev_Q7, energy_variation_Q7; + opus_int32 BWExp_Q16, gain_mult_Q16, gain_add_Q16, strength_Q16, b_Q8; + opus_int32 auto_corr[ MAX_SHAPE_LPC_ORDER + 1 ]; + opus_int32 refl_coef_Q16[ MAX_SHAPE_LPC_ORDER ]; + opus_int32 AR_Q24[ MAX_SHAPE_LPC_ORDER ]; + VARDECL( opus_int16, x_windowed ); + const opus_int16 *x_ptr, *pitch_res_ptr; + SAVE_STACK; + + /* Point to start of first LPC analysis block */ + x_ptr = x - psEnc->sCmn.la_shape; + + /****************/ + /* GAIN CONTROL */ + /****************/ + SNR_adj_dB_Q7 = psEnc->sCmn.SNR_dB_Q7; + + /* Input quality is the average of the quality in the lowest two VAD bands */ + psEncCtrl->input_quality_Q14 = ( opus_int )silk_RSHIFT( (opus_int32)psEnc->sCmn.input_quality_bands_Q15[ 0 ] + + psEnc->sCmn.input_quality_bands_Q15[ 1 ], 2 ); + + /* Coding quality level, between 0.0_Q0 and 1.0_Q0, but in Q14 */ + psEncCtrl->coding_quality_Q14 = silk_RSHIFT( silk_sigm_Q15( silk_RSHIFT_ROUND( SNR_adj_dB_Q7 - + SILK_FIX_CONST( 20.0, 7 ), 4 ) ), 1 ); + + /* Reduce coding SNR during low speech activity */ + if( psEnc->sCmn.useCBR == 0 ) { + b_Q8 = SILK_FIX_CONST( 1.0, 8 ) - psEnc->sCmn.speech_activity_Q8; + b_Q8 = silk_SMULWB( silk_LSHIFT( b_Q8, 8 ), b_Q8 ); + SNR_adj_dB_Q7 = silk_SMLAWB( SNR_adj_dB_Q7, + silk_SMULBB( SILK_FIX_CONST( -BG_SNR_DECR_dB, 7 ) >> ( 4 + 1 ), b_Q8 ), /* Q11*/ + silk_SMULWB( SILK_FIX_CONST( 1.0, 14 ) + psEncCtrl->input_quality_Q14, psEncCtrl->coding_quality_Q14 ) ); /* Q12*/ + } + + if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) { + /* Reduce gains for periodic signals */ + SNR_adj_dB_Q7 = silk_SMLAWB( SNR_adj_dB_Q7, SILK_FIX_CONST( HARM_SNR_INCR_dB, 8 ), psEnc->LTPCorr_Q15 ); + } else { + /* For unvoiced signals and low-quality input, adjust the quality slower than SNR_dB setting */ + SNR_adj_dB_Q7 = silk_SMLAWB( SNR_adj_dB_Q7, + silk_SMLAWB( SILK_FIX_CONST( 6.0, 9 ), -SILK_FIX_CONST( 0.4, 18 ), psEnc->sCmn.SNR_dB_Q7 ), + SILK_FIX_CONST( 1.0, 14 ) - psEncCtrl->input_quality_Q14 ); + } + + /*************************/ + /* SPARSENESS PROCESSING */ + /*************************/ + /* Set quantizer offset */ + if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) { + /* Initially set to 0; may be overruled in process_gains(..) */ + psEnc->sCmn.indices.quantOffsetType = 0; + } else { + /* Sparseness measure, based on relative fluctuations of energy per 2 milliseconds */ + nSamples = silk_LSHIFT( psEnc->sCmn.fs_kHz, 1 ); + energy_variation_Q7 = 0; + log_energy_prev_Q7 = 0; + pitch_res_ptr = pitch_res; + nSegs = silk_SMULBB( SUB_FRAME_LENGTH_MS, psEnc->sCmn.nb_subfr ) / 2; + for( k = 0; k < nSegs; k++ ) { + silk_sum_sqr_shift( &nrg, &scale, pitch_res_ptr, nSamples ); + nrg += silk_RSHIFT( nSamples, scale ); /* Q(-scale)*/ + + log_energy_Q7 = silk_lin2log( nrg ); + if( k > 0 ) { + energy_variation_Q7 += silk_abs( log_energy_Q7 - log_energy_prev_Q7 ); + } + log_energy_prev_Q7 = log_energy_Q7; + pitch_res_ptr += nSamples; + } + + /* Set quantization offset depending on sparseness measure */ + if( energy_variation_Q7 > SILK_FIX_CONST( ENERGY_VARIATION_THRESHOLD_QNT_OFFSET, 7 ) * (nSegs-1) ) { + psEnc->sCmn.indices.quantOffsetType = 0; + } else { + psEnc->sCmn.indices.quantOffsetType = 1; + } + } + + /*******************************/ + /* Control bandwidth expansion */ + /*******************************/ + /* More BWE for signals with high prediction gain */ + strength_Q16 = silk_SMULWB( psEncCtrl->predGain_Q16, SILK_FIX_CONST( FIND_PITCH_WHITE_NOISE_FRACTION, 16 ) ); + BWExp_Q16 = silk_DIV32_varQ( SILK_FIX_CONST( BANDWIDTH_EXPANSION, 16 ), + silk_SMLAWW( SILK_FIX_CONST( 1.0, 16 ), strength_Q16, strength_Q16 ), 16 ); + + if( psEnc->sCmn.warping_Q16 > 0 ) { + /* Slightly more warping in analysis will move quantization noise up in frequency, where it's better masked */ + warping_Q16 = silk_SMLAWB( psEnc->sCmn.warping_Q16, (opus_int32)psEncCtrl->coding_quality_Q14, SILK_FIX_CONST( 0.01, 18 ) ); + } else { + warping_Q16 = 0; + } + + /********************************************/ + /* Compute noise shaping AR coefs and gains */ + /********************************************/ + ALLOC( x_windowed, psEnc->sCmn.shapeWinLength, opus_int16 ); + for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) { + /* Apply window: sine slope followed by flat part followed by cosine slope */ + opus_int shift, slope_part, flat_part; + flat_part = psEnc->sCmn.fs_kHz * 3; + slope_part = silk_RSHIFT( psEnc->sCmn.shapeWinLength - flat_part, 1 ); + + silk_apply_sine_window( x_windowed, x_ptr, 1, slope_part ); + shift = slope_part; + silk_memcpy( x_windowed + shift, x_ptr + shift, flat_part * sizeof(opus_int16) ); + shift += flat_part; + silk_apply_sine_window( x_windowed + shift, x_ptr + shift, 2, slope_part ); + + /* Update pointer: next LPC analysis block */ + x_ptr += psEnc->sCmn.subfr_length; + + if( psEnc->sCmn.warping_Q16 > 0 ) { + /* Calculate warped auto correlation */ + silk_warped_autocorrelation_FIX( auto_corr, &scale, x_windowed, warping_Q16, psEnc->sCmn.shapeWinLength, psEnc->sCmn.shapingLPCOrder, arch ); + } else { + /* Calculate regular auto correlation */ + silk_autocorr( auto_corr, &scale, x_windowed, psEnc->sCmn.shapeWinLength, psEnc->sCmn.shapingLPCOrder + 1, arch ); + } + + /* Add white noise, as a fraction of energy */ + auto_corr[0] = silk_ADD32( auto_corr[0], silk_max_32( silk_SMULWB( silk_RSHIFT( auto_corr[ 0 ], 4 ), + SILK_FIX_CONST( SHAPE_WHITE_NOISE_FRACTION, 20 ) ), 1 ) ); + + /* Calculate the reflection coefficients using schur */ + nrg = silk_schur64( refl_coef_Q16, auto_corr, psEnc->sCmn.shapingLPCOrder ); + silk_assert( nrg >= 0 ); + + /* Convert reflection coefficients to prediction coefficients */ + silk_k2a_Q16( AR_Q24, refl_coef_Q16, psEnc->sCmn.shapingLPCOrder ); + + Qnrg = -scale; /* range: -12...30*/ + silk_assert( Qnrg >= -12 ); + silk_assert( Qnrg <= 30 ); + + /* Make sure that Qnrg is an even number */ + if( Qnrg & 1 ) { + Qnrg -= 1; + nrg >>= 1; + } + + tmp32 = silk_SQRT_APPROX( nrg ); + Qnrg >>= 1; /* range: -6...15*/ + + psEncCtrl->Gains_Q16[ k ] = silk_LSHIFT_SAT32( tmp32, 16 - Qnrg ); + + if( psEnc->sCmn.warping_Q16 > 0 ) { + /* Adjust gain for warping */ + gain_mult_Q16 = warped_gain( AR_Q24, warping_Q16, psEnc->sCmn.shapingLPCOrder ); + silk_assert( psEncCtrl->Gains_Q16[ k ] > 0 ); + if( psEncCtrl->Gains_Q16[ k ] < SILK_FIX_CONST( 0.25, 16 ) ) { + psEncCtrl->Gains_Q16[ k ] = silk_SMULWW( psEncCtrl->Gains_Q16[ k ], gain_mult_Q16 ); + } else { + psEncCtrl->Gains_Q16[ k ] = silk_SMULWW( silk_RSHIFT_ROUND( psEncCtrl->Gains_Q16[ k ], 1 ), gain_mult_Q16 ); + if ( psEncCtrl->Gains_Q16[ k ] >= ( silk_int32_MAX >> 1 ) ) { + psEncCtrl->Gains_Q16[ k ] = silk_int32_MAX; + } else { + psEncCtrl->Gains_Q16[ k ] = silk_LSHIFT32( psEncCtrl->Gains_Q16[ k ], 1 ); + } + } + silk_assert( psEncCtrl->Gains_Q16[ k ] > 0 ); + } + + /* Bandwidth expansion */ + silk_bwexpander_32( AR_Q24, psEnc->sCmn.shapingLPCOrder, BWExp_Q16 ); + + if( psEnc->sCmn.warping_Q16 > 0 ) { + /* Convert to monic warped prediction coefficients and limit absolute values */ + limit_warped_coefs( AR_Q24, warping_Q16, SILK_FIX_CONST( 3.999, 24 ), psEnc->sCmn.shapingLPCOrder ); + + /* Convert from Q24 to Q13 and store in int16 */ + for( i = 0; i < psEnc->sCmn.shapingLPCOrder; i++ ) { + psEncCtrl->AR_Q13[ k * MAX_SHAPE_LPC_ORDER + i ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( AR_Q24[ i ], 11 ) ); + } + } else { + silk_LPC_fit( &psEncCtrl->AR_Q13[ k * MAX_SHAPE_LPC_ORDER ], AR_Q24, 13, 24, psEnc->sCmn.shapingLPCOrder ); + } + } + + /*****************/ + /* Gain tweaking */ + /*****************/ + /* Increase gains during low speech activity and put lower limit on gains */ + gain_mult_Q16 = silk_log2lin( -silk_SMLAWB( -SILK_FIX_CONST( 16.0, 7 ), SNR_adj_dB_Q7, SILK_FIX_CONST( 0.16, 16 ) ) ); + gain_add_Q16 = silk_log2lin( silk_SMLAWB( SILK_FIX_CONST( 16.0, 7 ), SILK_FIX_CONST( MIN_QGAIN_DB, 7 ), SILK_FIX_CONST( 0.16, 16 ) ) ); + silk_assert( gain_mult_Q16 > 0 ); + for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) { + psEncCtrl->Gains_Q16[ k ] = silk_SMULWW( psEncCtrl->Gains_Q16[ k ], gain_mult_Q16 ); + silk_assert( psEncCtrl->Gains_Q16[ k ] >= 0 ); + psEncCtrl->Gains_Q16[ k ] = silk_ADD_POS_SAT32( psEncCtrl->Gains_Q16[ k ], gain_add_Q16 ); + } + + + /************************************************/ + /* Control low-frequency shaping and noise tilt */ + /************************************************/ + /* Less low frequency shaping for noisy inputs */ + strength_Q16 = silk_MUL( SILK_FIX_CONST( LOW_FREQ_SHAPING, 4 ), silk_SMLAWB( SILK_FIX_CONST( 1.0, 12 ), + SILK_FIX_CONST( LOW_QUALITY_LOW_FREQ_SHAPING_DECR, 13 ), psEnc->sCmn.input_quality_bands_Q15[ 0 ] - SILK_FIX_CONST( 1.0, 15 ) ) ); + strength_Q16 = silk_RSHIFT( silk_MUL( strength_Q16, psEnc->sCmn.speech_activity_Q8 ), 8 ); + if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) { + /* Reduce low frequencies quantization noise for periodic signals, depending on pitch lag */ + /*f = 400; freqz([1, -0.98 + 2e-4 * f], [1, -0.97 + 7e-4 * f], 2^12, Fs); axis([0, 1000, -10, 1])*/ + opus_int fs_kHz_inv = silk_DIV32_16( SILK_FIX_CONST( 0.2, 14 ), psEnc->sCmn.fs_kHz ); + for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) { + b_Q14 = fs_kHz_inv + silk_DIV32_16( SILK_FIX_CONST( 3.0, 14 ), psEncCtrl->pitchL[ k ] ); + /* Pack two coefficients in one int32 */ + psEncCtrl->LF_shp_Q14[ k ] = silk_LSHIFT( SILK_FIX_CONST( 1.0, 14 ) - b_Q14 - silk_SMULWB( strength_Q16, b_Q14 ), 16 ); + psEncCtrl->LF_shp_Q14[ k ] |= (opus_uint16)( b_Q14 - SILK_FIX_CONST( 1.0, 14 ) ); + } + silk_assert( SILK_FIX_CONST( HARM_HP_NOISE_COEF, 24 ) < SILK_FIX_CONST( 0.5, 24 ) ); /* Guarantees that second argument to SMULWB() is within range of an opus_int16*/ + Tilt_Q16 = - SILK_FIX_CONST( HP_NOISE_COEF, 16 ) - + silk_SMULWB( SILK_FIX_CONST( 1.0, 16 ) - SILK_FIX_CONST( HP_NOISE_COEF, 16 ), + silk_SMULWB( SILK_FIX_CONST( HARM_HP_NOISE_COEF, 24 ), psEnc->sCmn.speech_activity_Q8 ) ); + } else { + b_Q14 = silk_DIV32_16( 21299, psEnc->sCmn.fs_kHz ); /* 1.3_Q0 = 21299_Q14*/ + /* Pack two coefficients in one int32 */ + psEncCtrl->LF_shp_Q14[ 0 ] = silk_LSHIFT( SILK_FIX_CONST( 1.0, 14 ) - b_Q14 - + silk_SMULWB( strength_Q16, silk_SMULWB( SILK_FIX_CONST( 0.6, 16 ), b_Q14 ) ), 16 ); + psEncCtrl->LF_shp_Q14[ 0 ] |= (opus_uint16)( b_Q14 - SILK_FIX_CONST( 1.0, 14 ) ); + for( k = 1; k < psEnc->sCmn.nb_subfr; k++ ) { + psEncCtrl->LF_shp_Q14[ k ] = psEncCtrl->LF_shp_Q14[ 0 ]; + } + Tilt_Q16 = -SILK_FIX_CONST( HP_NOISE_COEF, 16 ); + } + + /****************************/ + /* HARMONIC SHAPING CONTROL */ + /****************************/ + if( USE_HARM_SHAPING && psEnc->sCmn.indices.signalType == TYPE_VOICED ) { + /* More harmonic noise shaping for high bitrates or noisy input */ + HarmShapeGain_Q16 = silk_SMLAWB( SILK_FIX_CONST( HARMONIC_SHAPING, 16 ), + SILK_FIX_CONST( 1.0, 16 ) - silk_SMULWB( SILK_FIX_CONST( 1.0, 18 ) - silk_LSHIFT( psEncCtrl->coding_quality_Q14, 4 ), + psEncCtrl->input_quality_Q14 ), SILK_FIX_CONST( HIGH_RATE_OR_LOW_QUALITY_HARMONIC_SHAPING, 16 ) ); + + /* Less harmonic noise shaping for less periodic signals */ + HarmShapeGain_Q16 = silk_SMULWB( silk_LSHIFT( HarmShapeGain_Q16, 1 ), + silk_SQRT_APPROX( silk_LSHIFT( psEnc->LTPCorr_Q15, 15 ) ) ); + } else { + HarmShapeGain_Q16 = 0; + } + + /*************************/ + /* Smooth over subframes */ + /*************************/ + for( k = 0; k < MAX_NB_SUBFR; k++ ) { + psShapeSt->HarmShapeGain_smth_Q16 = + silk_SMLAWB( psShapeSt->HarmShapeGain_smth_Q16, HarmShapeGain_Q16 - psShapeSt->HarmShapeGain_smth_Q16, SILK_FIX_CONST( SUBFR_SMTH_COEF, 16 ) ); + psShapeSt->Tilt_smth_Q16 = + silk_SMLAWB( psShapeSt->Tilt_smth_Q16, Tilt_Q16 - psShapeSt->Tilt_smth_Q16, SILK_FIX_CONST( SUBFR_SMTH_COEF, 16 ) ); + + psEncCtrl->HarmShapeGain_Q14[ k ] = ( opus_int )silk_RSHIFT_ROUND( psShapeSt->HarmShapeGain_smth_Q16, 2 ); + psEncCtrl->Tilt_Q14[ k ] = ( opus_int )silk_RSHIFT_ROUND( psShapeSt->Tilt_smth_Q16, 2 ); + } + RESTORE_STACK; +} +#endif /* OVERRIDE_silk_noise_shape_analysis_FIX */ diff --git a/extern/opus/silk/fixed/pitch_analysis_core_FIX.c b/extern/opus/silk/fixed/pitch_analysis_core_FIX.c new file mode 100644 index 0000000..1472904 --- /dev/null +++ b/extern/opus/silk/fixed/pitch_analysis_core_FIX.c @@ -0,0 +1,721 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/*********************************************************** +* Pitch analyser function +********************************************************** */ +#include "SigProc_FIX.h" +#include "pitch_est_defines.h" +#include "stack_alloc.h" +#include "debug.h" +#include "pitch.h" + +#define SCRATCH_SIZE 22 +#define SF_LENGTH_4KHZ ( PE_SUBFR_LENGTH_MS * 4 ) +#define SF_LENGTH_8KHZ ( PE_SUBFR_LENGTH_MS * 8 ) +#define MIN_LAG_4KHZ ( PE_MIN_LAG_MS * 4 ) +#define MIN_LAG_8KHZ ( PE_MIN_LAG_MS * 8 ) +#define MAX_LAG_4KHZ ( PE_MAX_LAG_MS * 4 ) +#define MAX_LAG_8KHZ ( PE_MAX_LAG_MS * 8 - 1 ) +#define CSTRIDE_4KHZ ( MAX_LAG_4KHZ + 1 - MIN_LAG_4KHZ ) +#define CSTRIDE_8KHZ ( MAX_LAG_8KHZ + 3 - ( MIN_LAG_8KHZ - 2 ) ) +#define D_COMP_MIN ( MIN_LAG_8KHZ - 3 ) +#define D_COMP_MAX ( MAX_LAG_8KHZ + 4 ) +#define D_COMP_STRIDE ( D_COMP_MAX - D_COMP_MIN ) + +typedef opus_int32 silk_pe_stage3_vals[ PE_NB_STAGE3_LAGS ]; + +/************************************************************/ +/* Internally used functions */ +/************************************************************/ +static void silk_P_Ana_calc_corr_st3( + silk_pe_stage3_vals cross_corr_st3[], /* O 3 DIM correlation array */ + const opus_int16 frame[], /* I vector to correlate */ + opus_int start_lag, /* I lag offset to search around */ + opus_int sf_length, /* I length of a 5 ms subframe */ + opus_int nb_subfr, /* I number of subframes */ + opus_int complexity, /* I Complexity setting */ + int arch /* I Run-time architecture */ +); + +static void silk_P_Ana_calc_energy_st3( + silk_pe_stage3_vals energies_st3[], /* O 3 DIM energy array */ + const opus_int16 frame[], /* I vector to calc energy in */ + opus_int start_lag, /* I lag offset to search around */ + opus_int sf_length, /* I length of one 5 ms subframe */ + opus_int nb_subfr, /* I number of subframes */ + opus_int complexity, /* I Complexity setting */ + int arch /* I Run-time architecture */ +); + +/*************************************************************/ +/* FIXED POINT CORE PITCH ANALYSIS FUNCTION */ +/*************************************************************/ +opus_int silk_pitch_analysis_core( /* O Voicing estimate: 0 voiced, 1 unvoiced */ + const opus_int16 *frame_unscaled, /* I Signal of length PE_FRAME_LENGTH_MS*Fs_kHz */ + opus_int *pitch_out, /* O 4 pitch lag values */ + opus_int16 *lagIndex, /* O Lag Index */ + opus_int8 *contourIndex, /* O Pitch contour Index */ + opus_int *LTPCorr_Q15, /* I/O Normalized correlation; input: value from previous frame */ + opus_int prevLag, /* I Last lag of previous frame; set to zero is unvoiced */ + const opus_int32 search_thres1_Q16, /* I First stage threshold for lag candidates 0 - 1 */ + const opus_int search_thres2_Q13, /* I Final threshold for lag candidates 0 - 1 */ + const opus_int Fs_kHz, /* I Sample frequency (kHz) */ + const opus_int complexity, /* I Complexity setting, 0-2, where 2 is highest */ + const opus_int nb_subfr, /* I number of 5 ms subframes */ + int arch /* I Run-time architecture */ +) +{ + VARDECL( opus_int16, frame_8kHz_buf ); + VARDECL( opus_int16, frame_4kHz ); + VARDECL( opus_int16, frame_scaled ); + opus_int32 filt_state[ 6 ]; + const opus_int16 *frame, *frame_8kHz; + opus_int i, k, d, j; + VARDECL( opus_int16, C ); + VARDECL( opus_int32, xcorr32 ); + const opus_int16 *target_ptr, *basis_ptr; + opus_int32 cross_corr, normalizer, energy, energy_basis, energy_target; + opus_int d_srch[ PE_D_SRCH_LENGTH ], Cmax, length_d_srch, length_d_comp, shift; + VARDECL( opus_int16, d_comp ); + opus_int32 sum, threshold, lag_counter; + opus_int CBimax, CBimax_new, CBimax_old, lag, start_lag, end_lag, lag_new; + opus_int32 CC[ PE_NB_CBKS_STAGE2_EXT ], CCmax, CCmax_b, CCmax_new_b, CCmax_new; + VARDECL( silk_pe_stage3_vals, energies_st3 ); + VARDECL( silk_pe_stage3_vals, cross_corr_st3 ); + opus_int frame_length, frame_length_8kHz, frame_length_4kHz; + opus_int sf_length; + opus_int min_lag; + opus_int max_lag; + opus_int32 contour_bias_Q15, diff; + opus_int nb_cbk_search, cbk_size; + opus_int32 delta_lag_log2_sqr_Q7, lag_log2_Q7, prevLag_log2_Q7, prev_lag_bias_Q13; + const opus_int8 *Lag_CB_ptr; + SAVE_STACK; + + /* Check for valid sampling frequency */ + celt_assert( Fs_kHz == 8 || Fs_kHz == 12 || Fs_kHz == 16 ); + + /* Check for valid complexity setting */ + celt_assert( complexity >= SILK_PE_MIN_COMPLEX ); + celt_assert( complexity <= SILK_PE_MAX_COMPLEX ); + + silk_assert( search_thres1_Q16 >= 0 && search_thres1_Q16 <= (1<<16) ); + silk_assert( search_thres2_Q13 >= 0 && search_thres2_Q13 <= (1<<13) ); + + /* Set up frame lengths max / min lag for the sampling frequency */ + frame_length = ( PE_LTP_MEM_LENGTH_MS + nb_subfr * PE_SUBFR_LENGTH_MS ) * Fs_kHz; + frame_length_4kHz = ( PE_LTP_MEM_LENGTH_MS + nb_subfr * PE_SUBFR_LENGTH_MS ) * 4; + frame_length_8kHz = ( PE_LTP_MEM_LENGTH_MS + nb_subfr * PE_SUBFR_LENGTH_MS ) * 8; + sf_length = PE_SUBFR_LENGTH_MS * Fs_kHz; + min_lag = PE_MIN_LAG_MS * Fs_kHz; + max_lag = PE_MAX_LAG_MS * Fs_kHz - 1; + + /* Downscale input if necessary */ + silk_sum_sqr_shift( &energy, &shift, frame_unscaled, frame_length ); + shift += 3 - silk_CLZ32( energy ); /* at least two bits headroom */ + ALLOC( frame_scaled, frame_length, opus_int16 ); + if( shift > 0 ) { + shift = silk_RSHIFT( shift + 1, 1 ); + for( i = 0; i < frame_length; i++ ) { + frame_scaled[ i ] = silk_RSHIFT( frame_unscaled[ i ], shift ); + } + frame = frame_scaled; + } else { + frame = frame_unscaled; + } + + ALLOC( frame_8kHz_buf, ( Fs_kHz == 8 ) ? 1 : frame_length_8kHz, opus_int16 ); + /* Resample from input sampled at Fs_kHz to 8 kHz */ + if( Fs_kHz == 16 ) { + silk_memset( filt_state, 0, 2 * sizeof( opus_int32 ) ); + silk_resampler_down2( filt_state, frame_8kHz_buf, frame, frame_length ); + frame_8kHz = frame_8kHz_buf; + } else if( Fs_kHz == 12 ) { + silk_memset( filt_state, 0, 6 * sizeof( opus_int32 ) ); + silk_resampler_down2_3( filt_state, frame_8kHz_buf, frame, frame_length ); + frame_8kHz = frame_8kHz_buf; + } else { + celt_assert( Fs_kHz == 8 ); + frame_8kHz = frame; + } + + /* Decimate again to 4 kHz */ + silk_memset( filt_state, 0, 2 * sizeof( opus_int32 ) );/* Set state to zero */ + ALLOC( frame_4kHz, frame_length_4kHz, opus_int16 ); + silk_resampler_down2( filt_state, frame_4kHz, frame_8kHz, frame_length_8kHz ); + + /* Low-pass filter */ + for( i = frame_length_4kHz - 1; i > 0; i-- ) { + frame_4kHz[ i ] = silk_ADD_SAT16( frame_4kHz[ i ], frame_4kHz[ i - 1 ] ); + } + + + /****************************************************************************** + * FIRST STAGE, operating in 4 khz + ******************************************************************************/ + ALLOC( C, nb_subfr * CSTRIDE_8KHZ, opus_int16 ); + ALLOC( xcorr32, MAX_LAG_4KHZ-MIN_LAG_4KHZ+1, opus_int32 ); + silk_memset( C, 0, (nb_subfr >> 1) * CSTRIDE_4KHZ * sizeof( opus_int16 ) ); + target_ptr = &frame_4kHz[ silk_LSHIFT( SF_LENGTH_4KHZ, 2 ) ]; + for( k = 0; k < nb_subfr >> 1; k++ ) { + /* Check that we are within range of the array */ + celt_assert( target_ptr >= frame_4kHz ); + celt_assert( target_ptr + SF_LENGTH_8KHZ <= frame_4kHz + frame_length_4kHz ); + + basis_ptr = target_ptr - MIN_LAG_4KHZ; + + /* Check that we are within range of the array */ + celt_assert( basis_ptr >= frame_4kHz ); + celt_assert( basis_ptr + SF_LENGTH_8KHZ <= frame_4kHz + frame_length_4kHz ); + + celt_pitch_xcorr( target_ptr, target_ptr - MAX_LAG_4KHZ, xcorr32, SF_LENGTH_8KHZ, MAX_LAG_4KHZ - MIN_LAG_4KHZ + 1, arch ); + + /* Calculate first vector products before loop */ + cross_corr = xcorr32[ MAX_LAG_4KHZ - MIN_LAG_4KHZ ]; + normalizer = silk_inner_prod_aligned( target_ptr, target_ptr, SF_LENGTH_8KHZ, arch ); + normalizer = silk_ADD32( normalizer, silk_inner_prod_aligned( basis_ptr, basis_ptr, SF_LENGTH_8KHZ, arch ) ); + normalizer = silk_ADD32( normalizer, silk_SMULBB( SF_LENGTH_8KHZ, 4000 ) ); + + matrix_ptr( C, k, 0, CSTRIDE_4KHZ ) = + (opus_int16)silk_DIV32_varQ( cross_corr, normalizer, 13 + 1 ); /* Q13 */ + + /* From now on normalizer is computed recursively */ + for( d = MIN_LAG_4KHZ + 1; d <= MAX_LAG_4KHZ; d++ ) { + basis_ptr--; + + /* Check that we are within range of the array */ + silk_assert( basis_ptr >= frame_4kHz ); + silk_assert( basis_ptr + SF_LENGTH_8KHZ <= frame_4kHz + frame_length_4kHz ); + + cross_corr = xcorr32[ MAX_LAG_4KHZ - d ]; + + /* Add contribution of new sample and remove contribution from oldest sample */ + normalizer = silk_ADD32( normalizer, + silk_SMULBB( basis_ptr[ 0 ], basis_ptr[ 0 ] ) - + silk_SMULBB( basis_ptr[ SF_LENGTH_8KHZ ], basis_ptr[ SF_LENGTH_8KHZ ] ) ); + + matrix_ptr( C, k, d - MIN_LAG_4KHZ, CSTRIDE_4KHZ) = + (opus_int16)silk_DIV32_varQ( cross_corr, normalizer, 13 + 1 ); /* Q13 */ + } + /* Update target pointer */ + target_ptr += SF_LENGTH_8KHZ; + } + + /* Combine two subframes into single correlation measure and apply short-lag bias */ + if( nb_subfr == PE_MAX_NB_SUBFR ) { + for( i = MAX_LAG_4KHZ; i >= MIN_LAG_4KHZ; i-- ) { + sum = (opus_int32)matrix_ptr( C, 0, i - MIN_LAG_4KHZ, CSTRIDE_4KHZ ) + + (opus_int32)matrix_ptr( C, 1, i - MIN_LAG_4KHZ, CSTRIDE_4KHZ ); /* Q14 */ + sum = silk_SMLAWB( sum, sum, silk_LSHIFT( -i, 4 ) ); /* Q14 */ + C[ i - MIN_LAG_4KHZ ] = (opus_int16)sum; /* Q14 */ + } + } else { + /* Only short-lag bias */ + for( i = MAX_LAG_4KHZ; i >= MIN_LAG_4KHZ; i-- ) { + sum = silk_LSHIFT( (opus_int32)C[ i - MIN_LAG_4KHZ ], 1 ); /* Q14 */ + sum = silk_SMLAWB( sum, sum, silk_LSHIFT( -i, 4 ) ); /* Q14 */ + C[ i - MIN_LAG_4KHZ ] = (opus_int16)sum; /* Q14 */ + } + } + + /* Sort */ + length_d_srch = silk_ADD_LSHIFT32( 4, complexity, 1 ); + celt_assert( 3 * length_d_srch <= PE_D_SRCH_LENGTH ); + silk_insertion_sort_decreasing_int16( C, d_srch, CSTRIDE_4KHZ, + length_d_srch ); + + /* Escape if correlation is very low already here */ + Cmax = (opus_int)C[ 0 ]; /* Q14 */ + if( Cmax < SILK_FIX_CONST( 0.2, 14 ) ) { + silk_memset( pitch_out, 0, nb_subfr * sizeof( opus_int ) ); + *LTPCorr_Q15 = 0; + *lagIndex = 0; + *contourIndex = 0; + RESTORE_STACK; + return 1; + } + + threshold = silk_SMULWB( search_thres1_Q16, Cmax ); + for( i = 0; i < length_d_srch; i++ ) { + /* Convert to 8 kHz indices for the sorted correlation that exceeds the threshold */ + if( C[ i ] > threshold ) { + d_srch[ i ] = silk_LSHIFT( d_srch[ i ] + MIN_LAG_4KHZ, 1 ); + } else { + length_d_srch = i; + break; + } + } + celt_assert( length_d_srch > 0 ); + + ALLOC( d_comp, D_COMP_STRIDE, opus_int16 ); + for( i = D_COMP_MIN; i < D_COMP_MAX; i++ ) { + d_comp[ i - D_COMP_MIN ] = 0; + } + for( i = 0; i < length_d_srch; i++ ) { + d_comp[ d_srch[ i ] - D_COMP_MIN ] = 1; + } + + /* Convolution */ + for( i = D_COMP_MAX - 1; i >= MIN_LAG_8KHZ; i-- ) { + d_comp[ i - D_COMP_MIN ] += + d_comp[ i - 1 - D_COMP_MIN ] + d_comp[ i - 2 - D_COMP_MIN ]; + } + + length_d_srch = 0; + for( i = MIN_LAG_8KHZ; i < MAX_LAG_8KHZ + 1; i++ ) { + if( d_comp[ i + 1 - D_COMP_MIN ] > 0 ) { + d_srch[ length_d_srch ] = i; + length_d_srch++; + } + } + + /* Convolution */ + for( i = D_COMP_MAX - 1; i >= MIN_LAG_8KHZ; i-- ) { + d_comp[ i - D_COMP_MIN ] += d_comp[ i - 1 - D_COMP_MIN ] + + d_comp[ i - 2 - D_COMP_MIN ] + d_comp[ i - 3 - D_COMP_MIN ]; + } + + length_d_comp = 0; + for( i = MIN_LAG_8KHZ; i < D_COMP_MAX; i++ ) { + if( d_comp[ i - D_COMP_MIN ] > 0 ) { + d_comp[ length_d_comp ] = i - 2; + length_d_comp++; + } + } + + /********************************************************************************** + ** SECOND STAGE, operating at 8 kHz, on lag sections with high correlation + *************************************************************************************/ + + /********************************************************************************* + * Find energy of each subframe projected onto its history, for a range of delays + *********************************************************************************/ + silk_memset( C, 0, nb_subfr * CSTRIDE_8KHZ * sizeof( opus_int16 ) ); + + target_ptr = &frame_8kHz[ PE_LTP_MEM_LENGTH_MS * 8 ]; + for( k = 0; k < nb_subfr; k++ ) { + + /* Check that we are within range of the array */ + celt_assert( target_ptr >= frame_8kHz ); + celt_assert( target_ptr + SF_LENGTH_8KHZ <= frame_8kHz + frame_length_8kHz ); + + energy_target = silk_ADD32( silk_inner_prod_aligned( target_ptr, target_ptr, SF_LENGTH_8KHZ, arch ), 1 ); + for( j = 0; j < length_d_comp; j++ ) { + d = d_comp[ j ]; + basis_ptr = target_ptr - d; + + /* Check that we are within range of the array */ + silk_assert( basis_ptr >= frame_8kHz ); + silk_assert( basis_ptr + SF_LENGTH_8KHZ <= frame_8kHz + frame_length_8kHz ); + + cross_corr = silk_inner_prod_aligned( target_ptr, basis_ptr, SF_LENGTH_8KHZ, arch ); + if( cross_corr > 0 ) { + energy_basis = silk_inner_prod_aligned( basis_ptr, basis_ptr, SF_LENGTH_8KHZ, arch ); + matrix_ptr( C, k, d - ( MIN_LAG_8KHZ - 2 ), CSTRIDE_8KHZ ) = + (opus_int16)silk_DIV32_varQ( cross_corr, + silk_ADD32( energy_target, + energy_basis ), + 13 + 1 ); /* Q13 */ + } else { + matrix_ptr( C, k, d - ( MIN_LAG_8KHZ - 2 ), CSTRIDE_8KHZ ) = 0; + } + } + target_ptr += SF_LENGTH_8KHZ; + } + + /* search over lag range and lags codebook */ + /* scale factor for lag codebook, as a function of center lag */ + + CCmax = silk_int32_MIN; + CCmax_b = silk_int32_MIN; + + CBimax = 0; /* To avoid returning undefined lag values */ + lag = -1; /* To check if lag with strong enough correlation has been found */ + + if( prevLag > 0 ) { + if( Fs_kHz == 12 ) { + prevLag = silk_DIV32_16( silk_LSHIFT( prevLag, 1 ), 3 ); + } else if( Fs_kHz == 16 ) { + prevLag = silk_RSHIFT( prevLag, 1 ); + } + prevLag_log2_Q7 = silk_lin2log( (opus_int32)prevLag ); + } else { + prevLag_log2_Q7 = 0; + } + silk_assert( search_thres2_Q13 == silk_SAT16( search_thres2_Q13 ) ); + /* Set up stage 2 codebook based on number of subframes */ + if( nb_subfr == PE_MAX_NB_SUBFR ) { + cbk_size = PE_NB_CBKS_STAGE2_EXT; + Lag_CB_ptr = &silk_CB_lags_stage2[ 0 ][ 0 ]; + if( Fs_kHz == 8 && complexity > SILK_PE_MIN_COMPLEX ) { + /* If input is 8 khz use a larger codebook here because it is last stage */ + nb_cbk_search = PE_NB_CBKS_STAGE2_EXT; + } else { + nb_cbk_search = PE_NB_CBKS_STAGE2; + } + } else { + cbk_size = PE_NB_CBKS_STAGE2_10MS; + Lag_CB_ptr = &silk_CB_lags_stage2_10_ms[ 0 ][ 0 ]; + nb_cbk_search = PE_NB_CBKS_STAGE2_10MS; + } + + 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++ ) { + opus_int d_subfr; + /* Try all codebooks */ + d_subfr = d + matrix_ptr( Lag_CB_ptr, i, j, cbk_size ); + CC[ j ] = CC[ j ] + + (opus_int32)matrix_ptr( C, i, + d_subfr - ( MIN_LAG_8KHZ - 2 ), + CSTRIDE_8KHZ ); + } + } + /* Find best codebook */ + CCmax_new = silk_int32_MIN; + CBimax_new = 0; + for( i = 0; i < nb_cbk_search; i++ ) { + if( CC[ i ] > CCmax_new ) { + CCmax_new = CC[ i ]; + CBimax_new = i; + } + } + + /* Bias towards shorter lags */ + lag_log2_Q7 = silk_lin2log( d ); /* Q7 */ + silk_assert( lag_log2_Q7 == silk_SAT16( lag_log2_Q7 ) ); + silk_assert( nb_subfr * SILK_FIX_CONST( PE_SHORTLAG_BIAS, 13 ) == silk_SAT16( nb_subfr * SILK_FIX_CONST( PE_SHORTLAG_BIAS, 13 ) ) ); + CCmax_new_b = CCmax_new - silk_RSHIFT( silk_SMULBB( nb_subfr * SILK_FIX_CONST( PE_SHORTLAG_BIAS, 13 ), lag_log2_Q7 ), 7 ); /* Q13 */ + + /* Bias towards previous lag */ + silk_assert( nb_subfr * SILK_FIX_CONST( PE_PREVLAG_BIAS, 13 ) == silk_SAT16( nb_subfr * SILK_FIX_CONST( PE_PREVLAG_BIAS, 13 ) ) ); + if( prevLag > 0 ) { + delta_lag_log2_sqr_Q7 = lag_log2_Q7 - prevLag_log2_Q7; + silk_assert( delta_lag_log2_sqr_Q7 == silk_SAT16( delta_lag_log2_sqr_Q7 ) ); + delta_lag_log2_sqr_Q7 = silk_RSHIFT( silk_SMULBB( delta_lag_log2_sqr_Q7, delta_lag_log2_sqr_Q7 ), 7 ); + prev_lag_bias_Q13 = silk_RSHIFT( silk_SMULBB( nb_subfr * SILK_FIX_CONST( PE_PREVLAG_BIAS, 13 ), *LTPCorr_Q15 ), 15 ); /* Q13 */ + prev_lag_bias_Q13 = silk_DIV32( silk_MUL( prev_lag_bias_Q13, delta_lag_log2_sqr_Q7 ), delta_lag_log2_sqr_Q7 + SILK_FIX_CONST( 0.5, 7 ) ); + CCmax_new_b -= prev_lag_bias_Q13; /* Q13 */ + } + + if( CCmax_new_b > CCmax_b && /* Find maximum biased correlation */ + CCmax_new > silk_SMULBB( nb_subfr, search_thres2_Q13 ) && /* Correlation needs to be high enough to be voiced */ + silk_CB_lags_stage2[ 0 ][ CBimax_new ] <= MIN_LAG_8KHZ /* Lag must be in range */ + ) { + CCmax_b = CCmax_new_b; + CCmax = CCmax_new; + lag = d; + CBimax = CBimax_new; + } + } + + if( lag == -1 ) { + /* No suitable candidate found */ + silk_memset( pitch_out, 0, nb_subfr * sizeof( opus_int ) ); + *LTPCorr_Q15 = 0; + *lagIndex = 0; + *contourIndex = 0; + RESTORE_STACK; + return 1; + } + + /* Output normalized correlation */ + *LTPCorr_Q15 = (opus_int)silk_LSHIFT( silk_DIV32_16( CCmax, nb_subfr ), 2 ); + silk_assert( *LTPCorr_Q15 >= 0 ); + + if( Fs_kHz > 8 ) { + /* Search in original signal */ + + CBimax_old = CBimax; + /* Compensate for decimation */ + silk_assert( lag == silk_SAT16( lag ) ); + if( Fs_kHz == 12 ) { + lag = silk_RSHIFT( silk_SMULBB( lag, 3 ), 1 ); + } else if( Fs_kHz == 16 ) { + lag = silk_LSHIFT( lag, 1 ); + } else { + lag = silk_SMULBB( lag, 3 ); + } + + lag = silk_LIMIT_int( lag, min_lag, max_lag ); + start_lag = silk_max_int( lag - 2, min_lag ); + end_lag = silk_min_int( lag + 2, max_lag ); + lag_new = lag; /* to avoid undefined lag */ + CBimax = 0; /* to avoid undefined lag */ + + CCmax = silk_int32_MIN; + /* pitch lags according to second stage */ + for( k = 0; k < nb_subfr; k++ ) { + pitch_out[ k ] = lag + 2 * silk_CB_lags_stage2[ k ][ CBimax_old ]; + } + + /* Set up codebook parameters according to complexity setting and frame length */ + if( nb_subfr == PE_MAX_NB_SUBFR ) { + nb_cbk_search = (opus_int)silk_nb_cbk_searchs_stage3[ complexity ]; + cbk_size = PE_NB_CBKS_STAGE3_MAX; + Lag_CB_ptr = &silk_CB_lags_stage3[ 0 ][ 0 ]; + } else { + nb_cbk_search = PE_NB_CBKS_STAGE3_10MS; + cbk_size = PE_NB_CBKS_STAGE3_10MS; + Lag_CB_ptr = &silk_CB_lags_stage3_10_ms[ 0 ][ 0 ]; + } + + /* Calculate the correlations and energies needed in stage 3 */ + ALLOC( energies_st3, nb_subfr * nb_cbk_search, silk_pe_stage3_vals ); + ALLOC( cross_corr_st3, nb_subfr * nb_cbk_search, silk_pe_stage3_vals ); + silk_P_Ana_calc_corr_st3( cross_corr_st3, frame, start_lag, sf_length, nb_subfr, complexity, arch ); + silk_P_Ana_calc_energy_st3( energies_st3, frame, start_lag, sf_length, nb_subfr, complexity, arch ); + + lag_counter = 0; + silk_assert( lag == silk_SAT16( lag ) ); + contour_bias_Q15 = silk_DIV32_16( SILK_FIX_CONST( PE_FLATCONTOUR_BIAS, 15 ), lag ); + + target_ptr = &frame[ PE_LTP_MEM_LENGTH_MS * Fs_kHz ]; + energy_target = silk_ADD32( silk_inner_prod_aligned( target_ptr, target_ptr, nb_subfr * sf_length, arch ), 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 = silk_ADD32( cross_corr, + matrix_ptr( cross_corr_st3, k, j, + nb_cbk_search )[ lag_counter ] ); + energy = silk_ADD32( energy, + matrix_ptr( energies_st3, k, j, + nb_cbk_search )[ lag_counter ] ); + silk_assert( energy >= 0 ); + } + if( cross_corr > 0 ) { + CCmax_new = silk_DIV32_varQ( cross_corr, energy, 13 + 1 ); /* Q13 */ + /* Reduce depending on flatness of contour */ + diff = silk_int16_MAX - silk_MUL( contour_bias_Q15, j ); /* Q15 */ + silk_assert( diff == silk_SAT16( diff ) ); + CCmax_new = silk_SMULWB( CCmax_new, diff ); /* Q14 */ + } else { + CCmax_new = 0; + } + + if( CCmax_new > CCmax && ( d + silk_CB_lags_stage3[ 0 ][ j ] ) <= max_lag ) { + CCmax = CCmax_new; + lag_new = d; + CBimax = j; + } + } + lag_counter++; + } + + for( k = 0; k < nb_subfr; k++ ) { + pitch_out[ k ] = lag_new + matrix_ptr( Lag_CB_ptr, k, CBimax, cbk_size ); + pitch_out[ k ] = silk_LIMIT( pitch_out[ k ], min_lag, PE_MAX_LAG_MS * Fs_kHz ); + } + *lagIndex = (opus_int16)( lag_new - min_lag); + *contourIndex = (opus_int8)CBimax; + } else { /* Fs_kHz == 8 */ + /* Save Lags */ + for( k = 0; k < nb_subfr; k++ ) { + pitch_out[ k ] = lag + matrix_ptr( Lag_CB_ptr, k, CBimax, cbk_size ); + pitch_out[ k ] = silk_LIMIT( pitch_out[ k ], MIN_LAG_8KHZ, PE_MAX_LAG_MS * 8 ); + } + *lagIndex = (opus_int16)( lag - MIN_LAG_8KHZ ); + *contourIndex = (opus_int8)CBimax; + } + celt_assert( *lagIndex >= 0 ); + /* return as voiced */ + RESTORE_STACK; + return 0; +} + +/*********************************************************************** + * Calculates the correlations used in stage 3 search. In order to cover + * the whole lag codebook for all the searched offset lags (lag +- 2), + * the following correlations are needed in each sub frame: + * + * sf1: lag range [-8,...,7] total 16 correlations + * sf2: lag range [-4,...,4] total 9 correlations + * sf3: lag range [-3,....4] total 8 correltions + * sf4: lag range [-6,....8] total 15 correlations + * + * In total 48 correlations. The direct implementation computed in worst + * case 4*12*5 = 240 correlations, but more likely around 120. + ***********************************************************************/ +static void silk_P_Ana_calc_corr_st3( + silk_pe_stage3_vals cross_corr_st3[], /* O 3 DIM correlation array */ + const opus_int16 frame[], /* I vector to correlate */ + opus_int start_lag, /* I lag offset to search around */ + opus_int sf_length, /* I length of a 5 ms subframe */ + opus_int nb_subfr, /* I number of subframes */ + opus_int complexity, /* I Complexity setting */ + int arch /* I Run-time architecture */ +) +{ + const opus_int16 *target_ptr; + opus_int i, j, k, lag_counter, lag_low, lag_high; + opus_int nb_cbk_search, delta, idx, cbk_size; + VARDECL( opus_int32, scratch_mem ); + VARDECL( opus_int32, xcorr32 ); + const opus_int8 *Lag_range_ptr, *Lag_CB_ptr; + SAVE_STACK; + + celt_assert( complexity >= SILK_PE_MIN_COMPLEX ); + celt_assert( complexity <= SILK_PE_MAX_COMPLEX ); + + if( nb_subfr == PE_MAX_NB_SUBFR ) { + Lag_range_ptr = &silk_Lag_range_stage3[ complexity ][ 0 ][ 0 ]; + Lag_CB_ptr = &silk_CB_lags_stage3[ 0 ][ 0 ]; + nb_cbk_search = silk_nb_cbk_searchs_stage3[ complexity ]; + cbk_size = PE_NB_CBKS_STAGE3_MAX; + } else { + celt_assert( nb_subfr == PE_MAX_NB_SUBFR >> 1); + Lag_range_ptr = &silk_Lag_range_stage3_10_ms[ 0 ][ 0 ]; + Lag_CB_ptr = &silk_CB_lags_stage3_10_ms[ 0 ][ 0 ]; + nb_cbk_search = PE_NB_CBKS_STAGE3_10MS; + cbk_size = PE_NB_CBKS_STAGE3_10MS; + } + ALLOC( scratch_mem, SCRATCH_SIZE, opus_int32 ); + ALLOC( xcorr32, SCRATCH_SIZE, opus_int32 ); + + target_ptr = &frame[ silk_LSHIFT( sf_length, 2 ) ]; /* Pointer to middle of frame */ + for( k = 0; k < nb_subfr; k++ ) { + lag_counter = 0; + + /* Calculate the correlations for each subframe */ + lag_low = matrix_ptr( Lag_range_ptr, k, 0, 2 ); + lag_high = matrix_ptr( Lag_range_ptr, k, 1, 2 ); + celt_assert(lag_high-lag_low+1 <= SCRATCH_SIZE); + celt_pitch_xcorr( target_ptr, target_ptr - start_lag - lag_high, xcorr32, sf_length, lag_high - lag_low + 1, arch ); + for( j = lag_low; j <= lag_high; j++ ) { + silk_assert( lag_counter < SCRATCH_SIZE ); + scratch_mem[ lag_counter ] = xcorr32[ lag_high - j ]; + lag_counter++; + } + + delta = matrix_ptr( Lag_range_ptr, k, 0, 2 ); + for( i = 0; i < nb_cbk_search; i++ ) { + /* Fill out the 3 dim array that stores the correlations for */ + /* each code_book vector for each start lag */ + idx = matrix_ptr( Lag_CB_ptr, k, i, cbk_size ) - delta; + for( j = 0; j < PE_NB_STAGE3_LAGS; j++ ) { + silk_assert( idx + j < SCRATCH_SIZE ); + silk_assert( idx + j < lag_counter ); + matrix_ptr( cross_corr_st3, k, i, nb_cbk_search )[ j ] = + scratch_mem[ idx + j ]; + } + } + target_ptr += sf_length; + } + RESTORE_STACK; +} + +/********************************************************************/ +/* Calculate the energies for first two subframes. The energies are */ +/* calculated recursively. */ +/********************************************************************/ +static void silk_P_Ana_calc_energy_st3( + silk_pe_stage3_vals energies_st3[], /* O 3 DIM energy array */ + const opus_int16 frame[], /* I vector to calc energy in */ + opus_int start_lag, /* I lag offset to search around */ + opus_int sf_length, /* I length of one 5 ms subframe */ + opus_int nb_subfr, /* I number of subframes */ + opus_int complexity, /* I Complexity setting */ + int arch /* I Run-time architecture */ +) +{ + const opus_int16 *target_ptr, *basis_ptr; + opus_int32 energy; + opus_int k, i, j, lag_counter; + opus_int nb_cbk_search, delta, idx, cbk_size, lag_diff; + VARDECL( opus_int32, scratch_mem ); + const opus_int8 *Lag_range_ptr, *Lag_CB_ptr; + SAVE_STACK; + + celt_assert( complexity >= SILK_PE_MIN_COMPLEX ); + celt_assert( complexity <= SILK_PE_MAX_COMPLEX ); + + if( nb_subfr == PE_MAX_NB_SUBFR ) { + Lag_range_ptr = &silk_Lag_range_stage3[ complexity ][ 0 ][ 0 ]; + Lag_CB_ptr = &silk_CB_lags_stage3[ 0 ][ 0 ]; + nb_cbk_search = silk_nb_cbk_searchs_stage3[ complexity ]; + cbk_size = PE_NB_CBKS_STAGE3_MAX; + } else { + celt_assert( nb_subfr == PE_MAX_NB_SUBFR >> 1); + Lag_range_ptr = &silk_Lag_range_stage3_10_ms[ 0 ][ 0 ]; + Lag_CB_ptr = &silk_CB_lags_stage3_10_ms[ 0 ][ 0 ]; + nb_cbk_search = PE_NB_CBKS_STAGE3_10MS; + cbk_size = PE_NB_CBKS_STAGE3_10MS; + } + ALLOC( scratch_mem, SCRATCH_SIZE, opus_int32 ); + + target_ptr = &frame[ silk_LSHIFT( sf_length, 2 ) ]; + for( k = 0; k < nb_subfr; k++ ) { + lag_counter = 0; + + /* Calculate the energy for first lag */ + basis_ptr = target_ptr - ( start_lag + matrix_ptr( Lag_range_ptr, k, 0, 2 ) ); + energy = silk_inner_prod_aligned( basis_ptr, basis_ptr, sf_length, arch ); + silk_assert( energy >= 0 ); + scratch_mem[ lag_counter ] = energy; + lag_counter++; + + lag_diff = ( matrix_ptr( Lag_range_ptr, k, 1, 2 ) - matrix_ptr( Lag_range_ptr, k, 0, 2 ) + 1 ); + for( i = 1; i < lag_diff; i++ ) { + /* remove part outside new window */ + energy -= silk_SMULBB( basis_ptr[ sf_length - i ], basis_ptr[ sf_length - i ] ); + silk_assert( energy >= 0 ); + + /* add part that comes into window */ + energy = silk_ADD_SAT32( energy, silk_SMULBB( basis_ptr[ -i ], basis_ptr[ -i ] ) ); + silk_assert( energy >= 0 ); + silk_assert( lag_counter < SCRATCH_SIZE ); + scratch_mem[ lag_counter ] = energy; + lag_counter++; + } + + delta = matrix_ptr( Lag_range_ptr, k, 0, 2 ); + for( i = 0; i < nb_cbk_search; i++ ) { + /* Fill out the 3 dim array that stores the correlations for */ + /* each code_book vector for each start lag */ + idx = matrix_ptr( Lag_CB_ptr, k, i, cbk_size ) - delta; + for( j = 0; j < PE_NB_STAGE3_LAGS; j++ ) { + silk_assert( idx + j < SCRATCH_SIZE ); + silk_assert( idx + j < lag_counter ); + matrix_ptr( energies_st3, k, i, nb_cbk_search )[ j ] = + scratch_mem[ idx + j ]; + silk_assert( + matrix_ptr( energies_st3, k, i, nb_cbk_search )[ j ] >= 0 ); + } + } + target_ptr += sf_length; + } + RESTORE_STACK; +} diff --git a/extern/opus/silk/fixed/process_gains_FIX.c b/extern/opus/silk/fixed/process_gains_FIX.c new file mode 100644 index 0000000..05aba31 --- /dev/null +++ b/extern/opus/silk/fixed/process_gains_FIX.c @@ -0,0 +1,117 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FIX.h" +#include "tuning_parameters.h" + +/* Processing of gains */ +void silk_process_gains_FIX( + silk_encoder_state_FIX *psEnc, /* I/O Encoder state */ + silk_encoder_control_FIX *psEncCtrl, /* I/O Encoder control */ + opus_int condCoding /* I The type of conditional coding to use */ +) +{ + silk_shape_state_FIX *psShapeSt = &psEnc->sShape; + opus_int k; + opus_int32 s_Q16, InvMaxSqrVal_Q16, gain, gain_squared, ResNrg, ResNrgPart, quant_offset_Q10; + + /* Gain reduction when LTP coding gain is high */ + if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) { + /*s = -0.5f * silk_sigmoid( 0.25f * ( psEncCtrl->LTPredCodGain - 12.0f ) ); */ + s_Q16 = -silk_sigm_Q15( silk_RSHIFT_ROUND( psEncCtrl->LTPredCodGain_Q7 - SILK_FIX_CONST( 12.0, 7 ), 4 ) ); + for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) { + psEncCtrl->Gains_Q16[ k ] = silk_SMLAWB( psEncCtrl->Gains_Q16[ k ], psEncCtrl->Gains_Q16[ k ], s_Q16 ); + } + } + + /* Limit the quantized signal */ + /* InvMaxSqrVal = pow( 2.0f, 0.33f * ( 21.0f - SNR_dB ) ) / subfr_length; */ + InvMaxSqrVal_Q16 = silk_DIV32_16( silk_log2lin( + silk_SMULWB( SILK_FIX_CONST( 21 + 16 / 0.33, 7 ) - psEnc->sCmn.SNR_dB_Q7, SILK_FIX_CONST( 0.33, 16 ) ) ), psEnc->sCmn.subfr_length ); + + for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) { + /* Soft limit on ratio residual energy and squared gains */ + ResNrg = psEncCtrl->ResNrg[ k ]; + ResNrgPart = silk_SMULWW( ResNrg, InvMaxSqrVal_Q16 ); + if( psEncCtrl->ResNrgQ[ k ] > 0 ) { + ResNrgPart = silk_RSHIFT_ROUND( ResNrgPart, psEncCtrl->ResNrgQ[ k ] ); + } else { + if( ResNrgPart >= silk_RSHIFT( silk_int32_MAX, -psEncCtrl->ResNrgQ[ k ] ) ) { + ResNrgPart = silk_int32_MAX; + } else { + ResNrgPart = silk_LSHIFT( ResNrgPart, -psEncCtrl->ResNrgQ[ k ] ); + } + } + gain = psEncCtrl->Gains_Q16[ k ]; + gain_squared = silk_ADD_SAT32( ResNrgPart, silk_SMMUL( gain, gain ) ); + if( gain_squared < silk_int16_MAX ) { + /* recalculate with higher precision */ + gain_squared = silk_SMLAWW( silk_LSHIFT( ResNrgPart, 16 ), gain, gain ); + silk_assert( gain_squared > 0 ); + gain = silk_SQRT_APPROX( gain_squared ); /* Q8 */ + gain = silk_min( gain, silk_int32_MAX >> 8 ); + psEncCtrl->Gains_Q16[ k ] = silk_LSHIFT_SAT32( gain, 8 ); /* Q16 */ + } else { + gain = silk_SQRT_APPROX( gain_squared ); /* Q0 */ + gain = silk_min( gain, silk_int32_MAX >> 16 ); + psEncCtrl->Gains_Q16[ k ] = silk_LSHIFT_SAT32( gain, 16 ); /* Q16 */ + } + } + + /* Save unquantized gains and gain Index */ + silk_memcpy( psEncCtrl->GainsUnq_Q16, psEncCtrl->Gains_Q16, psEnc->sCmn.nb_subfr * sizeof( opus_int32 ) ); + psEncCtrl->lastGainIndexPrev = psShapeSt->LastGainIndex; + + /* Quantize gains */ + silk_gains_quant( psEnc->sCmn.indices.GainsIndices, psEncCtrl->Gains_Q16, + &psShapeSt->LastGainIndex, condCoding == CODE_CONDITIONALLY, psEnc->sCmn.nb_subfr ); + + /* Set quantizer offset for voiced signals. Larger offset when LTP coding gain is low or tilt is high (ie low-pass) */ + if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) { + if( psEncCtrl->LTPredCodGain_Q7 + silk_RSHIFT( psEnc->sCmn.input_tilt_Q15, 8 ) > SILK_FIX_CONST( 1.0, 7 ) ) { + psEnc->sCmn.indices.quantOffsetType = 0; + } else { + psEnc->sCmn.indices.quantOffsetType = 1; + } + } + + /* Quantizer boundary adjustment */ + quant_offset_Q10 = silk_Quantization_Offsets_Q10[ psEnc->sCmn.indices.signalType >> 1 ][ psEnc->sCmn.indices.quantOffsetType ]; + psEncCtrl->Lambda_Q10 = SILK_FIX_CONST( LAMBDA_OFFSET, 10 ) + + silk_SMULBB( SILK_FIX_CONST( LAMBDA_DELAYED_DECISIONS, 10 ), psEnc->sCmn.nStatesDelayedDecision ) + + silk_SMULWB( SILK_FIX_CONST( LAMBDA_SPEECH_ACT, 18 ), psEnc->sCmn.speech_activity_Q8 ) + + silk_SMULWB( SILK_FIX_CONST( LAMBDA_INPUT_QUALITY, 12 ), psEncCtrl->input_quality_Q14 ) + + silk_SMULWB( SILK_FIX_CONST( LAMBDA_CODING_QUALITY, 12 ), psEncCtrl->coding_quality_Q14 ) + + silk_SMULWB( SILK_FIX_CONST( LAMBDA_QUANT_OFFSET, 16 ), quant_offset_Q10 ); + + silk_assert( psEncCtrl->Lambda_Q10 > 0 ); + silk_assert( psEncCtrl->Lambda_Q10 < SILK_FIX_CONST( 2, 10 ) ); +} diff --git a/extern/opus/silk/fixed/regularize_correlations_FIX.c b/extern/opus/silk/fixed/regularize_correlations_FIX.c new file mode 100644 index 0000000..a2836b0 --- /dev/null +++ b/extern/opus/silk/fixed/regularize_correlations_FIX.c @@ -0,0 +1,47 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FIX.h" + +/* Add noise to matrix diagonal */ +void silk_regularize_correlations_FIX( + opus_int32 *XX, /* I/O Correlation matrices */ + opus_int32 *xx, /* I/O Correlation values */ + opus_int32 noise, /* I Noise to add */ + opus_int D /* I Dimension of XX */ +) +{ + opus_int i; + for( i = 0; i < D; i++ ) { + matrix_ptr( &XX[ 0 ], i, i, D ) = silk_ADD32( matrix_ptr( &XX[ 0 ], i, i, D ), noise ); + } + xx[ 0 ] += noise; +} diff --git a/extern/opus/silk/fixed/residual_energy16_FIX.c b/extern/opus/silk/fixed/residual_energy16_FIX.c new file mode 100644 index 0000000..7f130f3 --- /dev/null +++ b/extern/opus/silk/fixed/residual_energy16_FIX.c @@ -0,0 +1,103 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FIX.h" + +/* Residual energy: nrg = wxx - 2 * wXx * c + c' * wXX * c */ +opus_int32 silk_residual_energy16_covar_FIX( + const opus_int16 *c, /* I Prediction vector */ + const opus_int32 *wXX, /* I Correlation matrix */ + const opus_int32 *wXx, /* I Correlation vector */ + opus_int32 wxx, /* I Signal energy */ + opus_int D, /* I Dimension */ + opus_int cQ /* I Q value for c vector 0 - 15 */ +) +{ + opus_int i, j, lshifts, Qxtra; + opus_int32 c_max, w_max, tmp, tmp2, nrg; + opus_int cn[ MAX_MATRIX_SIZE ]; + const opus_int32 *pRow; + + /* Safety checks */ + celt_assert( D >= 0 ); + celt_assert( D <= 16 ); + celt_assert( cQ > 0 ); + celt_assert( cQ < 16 ); + + lshifts = 16 - cQ; + Qxtra = lshifts; + + c_max = 0; + for( i = 0; i < D; i++ ) { + c_max = silk_max_32( c_max, silk_abs( (opus_int32)c[ i ] ) ); + } + Qxtra = silk_min_int( Qxtra, silk_CLZ32( c_max ) - 17 ); + + w_max = silk_max_32( wXX[ 0 ], wXX[ D * D - 1 ] ); + Qxtra = silk_min_int( Qxtra, silk_CLZ32( silk_MUL( D, silk_RSHIFT( silk_SMULWB( w_max, c_max ), 4 ) ) ) - 5 ); + Qxtra = silk_max_int( Qxtra, 0 ); + for( i = 0; i < D; i++ ) { + cn[ i ] = silk_LSHIFT( ( opus_int )c[ i ], Qxtra ); + silk_assert( silk_abs(cn[i]) <= ( silk_int16_MAX + 1 ) ); /* Check that silk_SMLAWB can be used */ + } + lshifts -= Qxtra; + + /* Compute wxx - 2 * wXx * c */ + tmp = 0; + for( i = 0; i < D; i++ ) { + tmp = silk_SMLAWB( tmp, wXx[ i ], cn[ i ] ); + } + nrg = silk_RSHIFT( wxx, 1 + lshifts ) - tmp; /* Q: -lshifts - 1 */ + + /* Add c' * wXX * c, assuming wXX is symmetric */ + tmp2 = 0; + for( i = 0; i < D; i++ ) { + tmp = 0; + pRow = &wXX[ i * D ]; + for( j = i + 1; j < D; j++ ) { + tmp = silk_SMLAWB( tmp, pRow[ j ], cn[ j ] ); + } + tmp = silk_SMLAWB( tmp, silk_RSHIFT( pRow[ i ], 1 ), cn[ i ] ); + tmp2 = silk_SMLAWB( tmp2, tmp, cn[ i ] ); + } + nrg = silk_ADD_LSHIFT32( nrg, tmp2, lshifts ); /* Q: -lshifts - 1 */ + + /* Keep one bit free always, because we add them for LSF interpolation */ + if( nrg < 1 ) { + nrg = 1; + } else if( nrg > silk_RSHIFT( silk_int32_MAX, lshifts + 2 ) ) { + nrg = silk_int32_MAX >> 1; + } else { + nrg = silk_LSHIFT( nrg, lshifts + 1 ); /* Q0 */ + } + return nrg; + +} diff --git a/extern/opus/silk/fixed/residual_energy_FIX.c b/extern/opus/silk/fixed/residual_energy_FIX.c new file mode 100644 index 0000000..6c7cade --- /dev/null +++ b/extern/opus/silk/fixed/residual_energy_FIX.c @@ -0,0 +1,98 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FIX.h" +#include "stack_alloc.h" + +/* Calculates residual energies of input subframes where all subframes have LPC_order */ +/* of preceding samples */ +void silk_residual_energy_FIX( + opus_int32 nrgs[ MAX_NB_SUBFR ], /* O Residual energy per subframe */ + opus_int nrgsQ[ MAX_NB_SUBFR ], /* O Q value per subframe */ + const opus_int16 x[], /* I Input signal */ + opus_int16 a_Q12[ 2 ][ MAX_LPC_ORDER ], /* I AR coefs for each frame half */ + const opus_int32 gains[ MAX_NB_SUBFR ], /* I Quantization gains */ + const opus_int subfr_length, /* I Subframe length */ + const opus_int nb_subfr, /* I Number of subframes */ + const opus_int LPC_order, /* I LPC order */ + int arch /* I Run-time architecture */ +) +{ + opus_int offset, i, j, rshift, lz1, lz2; + opus_int16 *LPC_res_ptr; + VARDECL( opus_int16, LPC_res ); + const opus_int16 *x_ptr; + opus_int32 tmp32; + SAVE_STACK; + + x_ptr = x; + offset = LPC_order + subfr_length; + + /* Filter input to create the LPC residual for each frame half, and measure subframe energies */ + ALLOC( LPC_res, ( MAX_NB_SUBFR >> 1 ) * offset, opus_int16 ); + celt_assert( ( nb_subfr >> 1 ) * ( MAX_NB_SUBFR >> 1 ) == nb_subfr ); + for( i = 0; i < nb_subfr >> 1; i++ ) { + /* Calculate half frame LPC residual signal including preceding samples */ + silk_LPC_analysis_filter( LPC_res, x_ptr, a_Q12[ i ], ( MAX_NB_SUBFR >> 1 ) * offset, LPC_order, arch ); + + /* Point to first subframe of the just calculated LPC residual signal */ + LPC_res_ptr = LPC_res + LPC_order; + for( j = 0; j < ( MAX_NB_SUBFR >> 1 ); j++ ) { + /* Measure subframe energy */ + silk_sum_sqr_shift( &nrgs[ i * ( MAX_NB_SUBFR >> 1 ) + j ], &rshift, LPC_res_ptr, subfr_length ); + + /* Set Q values for the measured energy */ + nrgsQ[ i * ( MAX_NB_SUBFR >> 1 ) + j ] = -rshift; + + /* Move to next subframe */ + LPC_res_ptr += offset; + } + /* Move to next frame half */ + x_ptr += ( MAX_NB_SUBFR >> 1 ) * offset; + } + + /* Apply the squared subframe gains */ + for( i = 0; i < nb_subfr; i++ ) { + /* Fully upscale gains and energies */ + lz1 = silk_CLZ32( nrgs[ i ] ) - 1; + lz2 = silk_CLZ32( gains[ i ] ) - 1; + + tmp32 = silk_LSHIFT32( gains[ i ], lz2 ); + + /* Find squared gains */ + tmp32 = silk_SMMUL( tmp32, tmp32 ); /* Q( 2 * lz2 - 32 )*/ + + /* Scale energies */ + nrgs[ i ] = silk_SMMUL( tmp32, silk_LSHIFT32( nrgs[ i ], lz1 ) ); /* Q( nrgsQ[ i ] + lz1 + 2 * lz2 - 32 - 32 )*/ + nrgsQ[ i ] += lz1 + 2 * lz2 - 32 - 32; + } + RESTORE_STACK; +} diff --git a/extern/opus/silk/fixed/schur64_FIX.c b/extern/opus/silk/fixed/schur64_FIX.c new file mode 100644 index 0000000..4b7e19e --- /dev/null +++ b/extern/opus/silk/fixed/schur64_FIX.c @@ -0,0 +1,93 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" + +/* Slower than schur(), but more accurate. */ +/* Uses SMULL(), available on armv4 */ +opus_int32 silk_schur64( /* O returns residual energy */ + opus_int32 rc_Q16[], /* O Reflection coefficients [order] Q16 */ + const opus_int32 c[], /* I Correlations [order+1] */ + opus_int32 order /* I Prediction order */ +) +{ + opus_int k, n; + opus_int32 C[ SILK_MAX_ORDER_LPC + 1 ][ 2 ]; + opus_int32 Ctmp1_Q30, Ctmp2_Q30, rc_tmp_Q31; + + celt_assert( order >= 0 && order <= SILK_MAX_ORDER_LPC ); + + /* Check for invalid input */ + if( c[ 0 ] <= 0 ) { + silk_memset( rc_Q16, 0, order * sizeof( opus_int32 ) ); + return 0; + } + + k = 0; + do { + C[ k ][ 0 ] = C[ k ][ 1 ] = c[ k ]; + } while( ++k <= order ); + + for( k = 0; k < order; k++ ) { + /* Check that we won't be getting an unstable rc, otherwise stop here. */ + if (silk_abs_int32(C[ k + 1 ][ 0 ]) >= C[ 0 ][ 1 ]) { + if ( C[ k + 1 ][ 0 ] > 0 ) { + rc_Q16[ k ] = -SILK_FIX_CONST( .99f, 16 ); + } else { + rc_Q16[ k ] = SILK_FIX_CONST( .99f, 16 ); + } + k++; + break; + } + + /* Get reflection coefficient: divide two Q30 values and get result in Q31 */ + rc_tmp_Q31 = silk_DIV32_varQ( -C[ k + 1 ][ 0 ], C[ 0 ][ 1 ], 31 ); + + /* Save the output */ + rc_Q16[ k ] = silk_RSHIFT_ROUND( rc_tmp_Q31, 15 ); + + /* Update correlations */ + for( n = 0; n < order - k; n++ ) { + Ctmp1_Q30 = C[ n + k + 1 ][ 0 ]; + Ctmp2_Q30 = C[ n ][ 1 ]; + + /* Multiply and add the highest int32 */ + C[ n + k + 1 ][ 0 ] = Ctmp1_Q30 + silk_SMMUL( silk_LSHIFT( Ctmp2_Q30, 1 ), rc_tmp_Q31 ); + C[ n ][ 1 ] = Ctmp2_Q30 + silk_SMMUL( silk_LSHIFT( Ctmp1_Q30, 1 ), rc_tmp_Q31 ); + } + } + + for(; k < order; k++ ) { + rc_Q16[ k ] = 0; + } + + return silk_max_32( 1, C[ 0 ][ 1 ] ); +} diff --git a/extern/opus/silk/fixed/schur_FIX.c b/extern/opus/silk/fixed/schur_FIX.c new file mode 100644 index 0000000..2840f6b --- /dev/null +++ b/extern/opus/silk/fixed/schur_FIX.c @@ -0,0 +1,107 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" + +/* Faster than schur64(), but much less accurate. */ +/* uses SMLAWB(), requiring armv5E and higher. */ +opus_int32 silk_schur( /* O Returns residual energy */ + opus_int16 *rc_Q15, /* O reflection coefficients [order] Q15 */ + const opus_int32 *c, /* I correlations [order+1] */ + const opus_int32 order /* I prediction order */ +) +{ + opus_int k, n, lz; + opus_int32 C[ SILK_MAX_ORDER_LPC + 1 ][ 2 ]; + opus_int32 Ctmp1, Ctmp2, rc_tmp_Q15; + + celt_assert( order >= 0 && order <= SILK_MAX_ORDER_LPC ); + + /* Get number of leading zeros */ + lz = silk_CLZ32( c[ 0 ] ); + + /* Copy correlations and adjust level to Q30 */ + k = 0; + if( lz < 2 ) { + /* lz must be 1, so shift one to the right */ + do { + C[ k ][ 0 ] = C[ k ][ 1 ] = silk_RSHIFT( c[ k ], 1 ); + } while( ++k <= order ); + } else if( lz > 2 ) { + /* Shift to the left */ + lz -= 2; + do { + C[ k ][ 0 ] = C[ k ][ 1 ] = silk_LSHIFT( c[ k ], lz ); + } while( ++k <= order ); + } else { + /* No need to shift */ + do { + C[ k ][ 0 ] = C[ k ][ 1 ] = c[ k ]; + } while( ++k <= order ); + } + + for( k = 0; k < order; k++ ) { + /* Check that we won't be getting an unstable rc, otherwise stop here. */ + if (silk_abs_int32(C[ k + 1 ][ 0 ]) >= C[ 0 ][ 1 ]) { + if ( C[ k + 1 ][ 0 ] > 0 ) { + rc_Q15[ k ] = -SILK_FIX_CONST( .99f, 15 ); + } else { + rc_Q15[ k ] = SILK_FIX_CONST( .99f, 15 ); + } + k++; + break; + } + + /* Get reflection coefficient */ + rc_tmp_Q15 = -silk_DIV32_16( C[ k + 1 ][ 0 ], silk_max_32( silk_RSHIFT( C[ 0 ][ 1 ], 15 ), 1 ) ); + + /* Clip (shouldn't happen for properly conditioned inputs) */ + rc_tmp_Q15 = silk_SAT16( rc_tmp_Q15 ); + + /* Store */ + rc_Q15[ k ] = (opus_int16)rc_tmp_Q15; + + /* Update correlations */ + for( n = 0; n < order - k; n++ ) { + Ctmp1 = C[ n + k + 1 ][ 0 ]; + Ctmp2 = C[ n ][ 1 ]; + C[ n + k + 1 ][ 0 ] = silk_SMLAWB( Ctmp1, silk_LSHIFT( Ctmp2, 1 ), rc_tmp_Q15 ); + C[ n ][ 1 ] = silk_SMLAWB( Ctmp2, silk_LSHIFT( Ctmp1, 1 ), rc_tmp_Q15 ); + } + } + + for(; k < order; k++ ) { + rc_Q15[ k ] = 0; + } + + /* return residual energy */ + return silk_max_32( 1, C[ 0 ][ 1 ] ); +} diff --git a/extern/opus/silk/fixed/structs_FIX.h b/extern/opus/silk/fixed/structs_FIX.h new file mode 100644 index 0000000..2774a97 --- /dev/null +++ b/extern/opus/silk/fixed/structs_FIX.h @@ -0,0 +1,116 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifndef SILK_STRUCTS_FIX_H +#define SILK_STRUCTS_FIX_H + +#include "typedef.h" +#include "main.h" +#include "structs.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +/********************************/ +/* Noise shaping analysis state */ +/********************************/ +typedef struct { + opus_int8 LastGainIndex; + opus_int32 HarmBoost_smth_Q16; + opus_int32 HarmShapeGain_smth_Q16; + opus_int32 Tilt_smth_Q16; +} silk_shape_state_FIX; + +/********************************/ +/* Encoder state FIX */ +/********************************/ +typedef struct { + silk_encoder_state sCmn; /* Common struct, shared with floating-point code */ + silk_shape_state_FIX sShape; /* Shape state */ + + /* Buffer for find pitch and noise shape analysis */ + silk_DWORD_ALIGN opus_int16 x_buf[ 2 * MAX_FRAME_LENGTH + LA_SHAPE_MAX ];/* Buffer for find pitch and noise shape analysis */ + opus_int LTPCorr_Q15; /* Normalized correlation from pitch lag estimator */ + opus_int32 resNrgSmth; +} silk_encoder_state_FIX; + +/************************/ +/* Encoder control FIX */ +/************************/ +typedef struct { + /* Prediction and coding parameters */ + opus_int32 Gains_Q16[ MAX_NB_SUBFR ]; + silk_DWORD_ALIGN opus_int16 PredCoef_Q12[ 2 ][ MAX_LPC_ORDER ]; + opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ]; + opus_int LTP_scale_Q14; + opus_int pitchL[ MAX_NB_SUBFR ]; + + /* Noise shaping parameters */ + /* Testing */ + silk_DWORD_ALIGN opus_int16 AR_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ]; + opus_int32 LF_shp_Q14[ MAX_NB_SUBFR ]; /* Packs two int16 coefficients per int32 value */ + opus_int Tilt_Q14[ MAX_NB_SUBFR ]; + opus_int HarmShapeGain_Q14[ MAX_NB_SUBFR ]; + opus_int Lambda_Q10; + opus_int input_quality_Q14; + opus_int coding_quality_Q14; + + /* measures */ + opus_int32 predGain_Q16; + opus_int LTPredCodGain_Q7; + opus_int32 ResNrg[ MAX_NB_SUBFR ]; /* Residual energy per subframe */ + opus_int ResNrgQ[ MAX_NB_SUBFR ]; /* Q domain for the residual energy > 0 */ + + /* Parameters for CBR mode */ + opus_int32 GainsUnq_Q16[ MAX_NB_SUBFR ]; + opus_int8 lastGainIndexPrev; +} silk_encoder_control_FIX; + +/************************/ +/* Encoder Super Struct */ +/************************/ +typedef struct { + silk_encoder_state_FIX state_Fxx[ ENCODER_NUM_CHANNELS ]; + stereo_enc_state sStereo; + opus_int32 nBitsUsedLBRR; + opus_int32 nBitsExceeded; + opus_int nChannelsAPI; + opus_int nChannelsInternal; + opus_int nPrevChannelsInternal; + opus_int timeSinceSwitchAllowed_ms; + opus_int allowBandwidthSwitch; + opus_int prev_decode_only_middle; +} silk_encoder; + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/extern/opus/silk/fixed/vector_ops_FIX.c b/extern/opus/silk/fixed/vector_ops_FIX.c new file mode 100644 index 0000000..d949800 --- /dev/null +++ b/extern/opus/silk/fixed/vector_ops_FIX.c @@ -0,0 +1,102 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" +#include "pitch.h" + +/* Copy and multiply a vector by a constant */ +void silk_scale_copy_vector16( + opus_int16 *data_out, + const opus_int16 *data_in, + opus_int32 gain_Q16, /* I Gain in Q16 */ + const opus_int dataSize /* I Length */ +) +{ + opus_int i; + opus_int32 tmp32; + + for( i = 0; i < dataSize; i++ ) { + tmp32 = silk_SMULWB( gain_Q16, data_in[ i ] ); + data_out[ i ] = (opus_int16)silk_CHECK_FIT16( tmp32 ); + } +} + +/* Multiply a vector by a constant */ +void silk_scale_vector32_Q26_lshift_18( + opus_int32 *data1, /* I/O Q0/Q18 */ + opus_int32 gain_Q26, /* I Q26 */ + opus_int dataSize /* I length */ +) +{ + opus_int i; + + for( i = 0; i < dataSize; i++ ) { + data1[ i ] = (opus_int32)silk_CHECK_FIT32( silk_RSHIFT64( silk_SMULL( data1[ i ], gain_Q26 ), 8 ) ); /* OUTPUT: Q18 */ + } +} + +/* sum = for(i=0;i6, memory access can be reduced by half. */ +opus_int32 silk_inner_prod_aligned( + const opus_int16 *const inVec1, /* I input vector 1 */ + const opus_int16 *const inVec2, /* I input vector 2 */ + const opus_int len, /* I vector lengths */ + int arch /* I Run-time architecture */ +) +{ +#ifdef FIXED_POINT + return celt_inner_prod(inVec1, inVec2, len, arch); +#else + opus_int i; + opus_int32 sum = 0; + for( i = 0; i < len; i++ ) { + sum = silk_SMLABB( sum, inVec1[ i ], inVec2[ i ] ); + } + return sum; +#endif +} + +opus_int64 silk_inner_prod16_aligned_64_c( + const opus_int16 *inVec1, /* I input vector 1 */ + const opus_int16 *inVec2, /* I input vector 2 */ + const opus_int len /* I vector lengths */ +) +{ + opus_int i; + opus_int64 sum = 0; + for( i = 0; i < len; i++ ) { + sum = silk_SMLALBB( sum, inVec1[ i ], inVec2[ i ] ); + } + return sum; +} diff --git a/extern/opus/silk/fixed/warped_autocorrelation_FIX.c b/extern/opus/silk/fixed/warped_autocorrelation_FIX.c new file mode 100644 index 0000000..5c79553 --- /dev/null +++ b/extern/opus/silk/fixed/warped_autocorrelation_FIX.c @@ -0,0 +1,92 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FIX.h" + +#if defined(MIPSr1_ASM) +#include "mips/warped_autocorrelation_FIX_mipsr1.h" +#endif + + +/* Autocorrelations for a warped frequency axis */ +#ifndef OVERRIDE_silk_warped_autocorrelation_FIX_c +void silk_warped_autocorrelation_FIX_c( + opus_int32 *corr, /* O Result [order + 1] */ + opus_int *scale, /* O Scaling of the correlation vector */ + const opus_int16 *input, /* I Input data to correlate */ + const opus_int warping_Q16, /* I Warping coefficient */ + const opus_int length, /* I Length of input */ + const opus_int order /* I Correlation order (even) */ +) +{ + opus_int n, i, lsh; + opus_int32 tmp1_QS, tmp2_QS; + opus_int32 state_QS[ MAX_SHAPE_LPC_ORDER + 1 ] = { 0 }; + opus_int64 corr_QC[ MAX_SHAPE_LPC_ORDER + 1 ] = { 0 }; + + /* Order must be even */ + celt_assert( ( order & 1 ) == 0 ); + silk_assert( 2 * QS - QC >= 0 ); + + /* Loop over samples */ + for( n = 0; n < length; n++ ) { + tmp1_QS = silk_LSHIFT32( (opus_int32)input[ n ], QS ); + /* Loop over allpass sections */ + for( i = 0; i < order; i += 2 ) { + /* Output of allpass section */ + tmp2_QS = silk_SMLAWB( state_QS[ i ], state_QS[ i + 1 ] - tmp1_QS, warping_Q16 ); + state_QS[ i ] = tmp1_QS; + corr_QC[ i ] += silk_RSHIFT64( silk_SMULL( tmp1_QS, state_QS[ 0 ] ), 2 * QS - QC ); + /* Output of allpass section */ + tmp1_QS = silk_SMLAWB( state_QS[ i + 1 ], state_QS[ i + 2 ] - tmp2_QS, warping_Q16 ); + state_QS[ i + 1 ] = tmp2_QS; + corr_QC[ i + 1 ] += silk_RSHIFT64( silk_SMULL( tmp2_QS, state_QS[ 0 ] ), 2 * QS - QC ); + } + state_QS[ order ] = tmp1_QS; + corr_QC[ order ] += silk_RSHIFT64( silk_SMULL( tmp1_QS, state_QS[ 0 ] ), 2 * QS - QC ); + } + + lsh = silk_CLZ64( corr_QC[ 0 ] ) - 35; + lsh = silk_LIMIT( lsh, -12 - QC, 30 - QC ); + *scale = -( QC + lsh ); + silk_assert( *scale >= -30 && *scale <= 12 ); + if( lsh >= 0 ) { + for( i = 0; i < order + 1; i++ ) { + corr[ i ] = (opus_int32)silk_CHECK_FIT32( silk_LSHIFT64( corr_QC[ i ], lsh ) ); + } + } else { + for( i = 0; i < order + 1; i++ ) { + corr[ i ] = (opus_int32)silk_CHECK_FIT32( silk_RSHIFT64( corr_QC[ i ], -lsh ) ); + } + } + silk_assert( corr_QC[ 0 ] >= 0 ); /* If breaking, decrease QC*/ +} +#endif /* OVERRIDE_silk_warped_autocorrelation_FIX_c */ diff --git a/extern/opus/silk/fixed/x86/burg_modified_FIX_sse4_1.c b/extern/opus/silk/fixed/x86/burg_modified_FIX_sse4_1.c new file mode 100644 index 0000000..bbb1ce0 --- /dev/null +++ b/extern/opus/silk/fixed/x86/burg_modified_FIX_sse4_1.c @@ -0,0 +1,377 @@ +/* Copyright (c) 2014, Cisco Systems, INC + Written by XiangMingZhu WeiZhou MinPeng YanWang + + 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. + + 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 OWNER + 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. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include + +#include "SigProc_FIX.h" +#include "define.h" +#include "tuning_parameters.h" +#include "pitch.h" +#include "celt/x86/x86cpu.h" + +#define MAX_FRAME_SIZE 384 /* subfr_length * nb_subfr = ( 0.005 * 16000 + 16 ) * 4 = 384 */ + +#define QA 25 +#define N_BITS_HEAD_ROOM 2 +#define MIN_RSHIFTS -16 +#define MAX_RSHIFTS (32 - QA) + +/* Compute reflection coefficients from input signal */ +void silk_burg_modified_sse4_1( + opus_int32 *res_nrg, /* O Residual energy */ + opus_int *res_nrg_Q, /* O Residual energy Q value */ + opus_int32 A_Q16[], /* O Prediction coefficients (length order) */ + const opus_int16 x[], /* I Input signal, length: nb_subfr * ( D + subfr_length ) */ + const opus_int32 minInvGain_Q30, /* I Inverse of max prediction gain */ + const opus_int subfr_length, /* I Input signal subframe length (incl. D preceding samples) */ + const opus_int nb_subfr, /* I Number of subframes stacked in x */ + const opus_int D, /* I Order */ + int arch /* I Run-time architecture */ +) +{ + opus_int k, n, s, lz, rshifts, rshifts_extra, reached_max_gain; + opus_int32 C0, num, nrg, rc_Q31, invGain_Q30, Atmp_QA, Atmp1, tmp1, tmp2, x1, x2; + const opus_int16 *x_ptr; + opus_int32 C_first_row[ SILK_MAX_ORDER_LPC ]; + opus_int32 C_last_row[ SILK_MAX_ORDER_LPC ]; + opus_int32 Af_QA[ SILK_MAX_ORDER_LPC ]; + opus_int32 CAf[ SILK_MAX_ORDER_LPC + 1 ]; + opus_int32 CAb[ SILK_MAX_ORDER_LPC + 1 ]; + opus_int32 xcorr[ SILK_MAX_ORDER_LPC ]; + + __m128i FIRST_3210, LAST_3210, ATMP_3210, TMP1_3210, TMP2_3210, T1_3210, T2_3210, PTR_3210, SUBFR_3210, X1_3210, X2_3210; + __m128i CONST1 = _mm_set1_epi32(1); + + celt_assert( subfr_length * nb_subfr <= MAX_FRAME_SIZE ); + + /* Compute autocorrelations, added over subframes */ + silk_sum_sqr_shift( &C0, &rshifts, x, nb_subfr * subfr_length ); + if( rshifts > MAX_RSHIFTS ) { + C0 = silk_LSHIFT32( C0, rshifts - MAX_RSHIFTS ); + silk_assert( C0 > 0 ); + rshifts = MAX_RSHIFTS; + } else { + lz = silk_CLZ32( C0 ) - 1; + rshifts_extra = N_BITS_HEAD_ROOM - lz; + if( rshifts_extra > 0 ) { + rshifts_extra = silk_min( rshifts_extra, MAX_RSHIFTS - rshifts ); + C0 = silk_RSHIFT32( C0, rshifts_extra ); + } else { + rshifts_extra = silk_max( rshifts_extra, MIN_RSHIFTS - rshifts ); + C0 = silk_LSHIFT32( C0, -rshifts_extra ); + } + rshifts += rshifts_extra; + } + CAb[ 0 ] = CAf[ 0 ] = C0 + silk_SMMUL( SILK_FIX_CONST( FIND_LPC_COND_FAC, 32 ), C0 ) + 1; /* Q(-rshifts) */ + silk_memset( C_first_row, 0, SILK_MAX_ORDER_LPC * sizeof( opus_int32 ) ); + if( rshifts > 0 ) { + for( s = 0; s < nb_subfr; s++ ) { + x_ptr = x + s * subfr_length; + for( n = 1; n < D + 1; n++ ) { + C_first_row[ n - 1 ] += (opus_int32)silk_RSHIFT64( + silk_inner_prod16_aligned_64( x_ptr, x_ptr + n, subfr_length - n, arch ), rshifts ); + } + } + } else { + for( s = 0; s < nb_subfr; s++ ) { + int i; + opus_int32 d; + x_ptr = x + s * subfr_length; + celt_pitch_xcorr(x_ptr, x_ptr + 1, xcorr, subfr_length - D, D, arch ); + for( n = 1; n < D + 1; n++ ) { + for ( i = n + subfr_length - D, d = 0; i < subfr_length; i++ ) + d = MAC16_16( d, x_ptr[ i ], x_ptr[ i - n ] ); + xcorr[ n - 1 ] += d; + } + for( n = 1; n < D + 1; n++ ) { + C_first_row[ n - 1 ] += silk_LSHIFT32( xcorr[ n - 1 ], -rshifts ); + } + } + } + silk_memcpy( C_last_row, C_first_row, SILK_MAX_ORDER_LPC * sizeof( opus_int32 ) ); + + /* Initialize */ + CAb[ 0 ] = CAf[ 0 ] = C0 + silk_SMMUL( SILK_FIX_CONST( FIND_LPC_COND_FAC, 32 ), C0 ) + 1; /* Q(-rshifts) */ + + invGain_Q30 = (opus_int32)1 << 30; + reached_max_gain = 0; + for( n = 0; n < D; n++ ) { + /* Update first row of correlation matrix (without first element) */ + /* Update last row of correlation matrix (without last element, stored in reversed order) */ + /* Update C * Af */ + /* Update C * flipud(Af) (stored in reversed order) */ + if( rshifts > -2 ) { + for( s = 0; s < nb_subfr; s++ ) { + x_ptr = x + s * subfr_length; + x1 = -silk_LSHIFT32( (opus_int32)x_ptr[ n ], 16 - rshifts ); /* Q(16-rshifts) */ + x2 = -silk_LSHIFT32( (opus_int32)x_ptr[ subfr_length - n - 1 ], 16 - rshifts ); /* Q(16-rshifts) */ + tmp1 = silk_LSHIFT32( (opus_int32)x_ptr[ n ], QA - 16 ); /* Q(QA-16) */ + tmp2 = silk_LSHIFT32( (opus_int32)x_ptr[ subfr_length - n - 1 ], QA - 16 ); /* Q(QA-16) */ + for( k = 0; k < n; k++ ) { + C_first_row[ k ] = silk_SMLAWB( C_first_row[ k ], x1, x_ptr[ n - k - 1 ] ); /* Q( -rshifts ) */ + C_last_row[ k ] = silk_SMLAWB( C_last_row[ k ], x2, x_ptr[ subfr_length - n + k ] ); /* Q( -rshifts ) */ + Atmp_QA = Af_QA[ k ]; + tmp1 = silk_SMLAWB( tmp1, Atmp_QA, x_ptr[ n - k - 1 ] ); /* Q(QA-16) */ + tmp2 = silk_SMLAWB( tmp2, Atmp_QA, x_ptr[ subfr_length - n + k ] ); /* Q(QA-16) */ + } + tmp1 = silk_LSHIFT32( -tmp1, 32 - QA - rshifts ); /* Q(16-rshifts) */ + tmp2 = silk_LSHIFT32( -tmp2, 32 - QA - rshifts ); /* Q(16-rshifts) */ + for( k = 0; k <= n; k++ ) { + CAf[ k ] = silk_SMLAWB( CAf[ k ], tmp1, x_ptr[ n - k ] ); /* Q( -rshift ) */ + CAb[ k ] = silk_SMLAWB( CAb[ k ], tmp2, x_ptr[ subfr_length - n + k - 1 ] ); /* Q( -rshift ) */ + } + } + } else { + for( s = 0; s < nb_subfr; s++ ) { + x_ptr = x + s * subfr_length; + x1 = -silk_LSHIFT32( (opus_int32)x_ptr[ n ], -rshifts ); /* Q( -rshifts ) */ + x2 = -silk_LSHIFT32( (opus_int32)x_ptr[ subfr_length - n - 1 ], -rshifts ); /* Q( -rshifts ) */ + tmp1 = silk_LSHIFT32( (opus_int32)x_ptr[ n ], 17 ); /* Q17 */ + tmp2 = silk_LSHIFT32( (opus_int32)x_ptr[ subfr_length - n - 1 ], 17 ); /* Q17 */ + + X1_3210 = _mm_set1_epi32( x1 ); + X2_3210 = _mm_set1_epi32( x2 ); + TMP1_3210 = _mm_setzero_si128(); + TMP2_3210 = _mm_setzero_si128(); + for( k = 0; k < n - 3; k += 4 ) { + PTR_3210 = OP_CVTEPI16_EPI32_M64( &x_ptr[ n - k - 1 - 3 ] ); + SUBFR_3210 = OP_CVTEPI16_EPI32_M64( &x_ptr[ subfr_length - n + k ] ); + FIRST_3210 = _mm_loadu_si128( (__m128i *)&C_first_row[ k ] ); + PTR_3210 = _mm_shuffle_epi32( PTR_3210, _MM_SHUFFLE( 0, 1, 2, 3 ) ); + LAST_3210 = _mm_loadu_si128( (__m128i *)&C_last_row[ k ] ); + ATMP_3210 = _mm_loadu_si128( (__m128i *)&Af_QA[ k ] ); + + T1_3210 = _mm_mullo_epi32( PTR_3210, X1_3210 ); + T2_3210 = _mm_mullo_epi32( SUBFR_3210, X2_3210 ); + + ATMP_3210 = _mm_srai_epi32( ATMP_3210, 7 ); + ATMP_3210 = _mm_add_epi32( ATMP_3210, CONST1 ); + ATMP_3210 = _mm_srai_epi32( ATMP_3210, 1 ); + + FIRST_3210 = _mm_add_epi32( FIRST_3210, T1_3210 ); + LAST_3210 = _mm_add_epi32( LAST_3210, T2_3210 ); + + PTR_3210 = _mm_mullo_epi32( ATMP_3210, PTR_3210 ); + SUBFR_3210 = _mm_mullo_epi32( ATMP_3210, SUBFR_3210 ); + + _mm_storeu_si128( (__m128i *)&C_first_row[ k ], FIRST_3210 ); + _mm_storeu_si128( (__m128i *)&C_last_row[ k ], LAST_3210 ); + + TMP1_3210 = _mm_add_epi32( TMP1_3210, PTR_3210 ); + TMP2_3210 = _mm_add_epi32( TMP2_3210, SUBFR_3210 ); + } + + TMP1_3210 = _mm_add_epi32( TMP1_3210, _mm_unpackhi_epi64(TMP1_3210, TMP1_3210 ) ); + TMP2_3210 = _mm_add_epi32( TMP2_3210, _mm_unpackhi_epi64(TMP2_3210, TMP2_3210 ) ); + TMP1_3210 = _mm_add_epi32( TMP1_3210, _mm_shufflelo_epi16(TMP1_3210, 0x0E ) ); + TMP2_3210 = _mm_add_epi32( TMP2_3210, _mm_shufflelo_epi16(TMP2_3210, 0x0E ) ); + + tmp1 += _mm_cvtsi128_si32( TMP1_3210 ); + tmp2 += _mm_cvtsi128_si32( TMP2_3210 ); + + for( ; k < n; k++ ) { + C_first_row[ k ] = silk_MLA( C_first_row[ k ], x1, x_ptr[ n - k - 1 ] ); /* Q( -rshifts ) */ + C_last_row[ k ] = silk_MLA( C_last_row[ k ], x2, x_ptr[ subfr_length - n + k ] ); /* Q( -rshifts ) */ + Atmp1 = silk_RSHIFT_ROUND( Af_QA[ k ], QA - 17 ); /* Q17 */ + tmp1 = silk_MLA( tmp1, x_ptr[ n - k - 1 ], Atmp1 ); /* Q17 */ + tmp2 = silk_MLA( tmp2, x_ptr[ subfr_length - n + k ], Atmp1 ); /* Q17 */ + } + + tmp1 = -tmp1; /* Q17 */ + tmp2 = -tmp2; /* Q17 */ + + { + __m128i xmm_tmp1, xmm_tmp2; + __m128i xmm_x_ptr_n_k_x2x0, xmm_x_ptr_n_k_x3x1; + __m128i xmm_x_ptr_sub_x2x0, xmm_x_ptr_sub_x3x1; + + xmm_tmp1 = _mm_set1_epi32( tmp1 ); + xmm_tmp2 = _mm_set1_epi32( tmp2 ); + + for( k = 0; k <= n - 3; k += 4 ) { + xmm_x_ptr_n_k_x2x0 = OP_CVTEPI16_EPI32_M64( &x_ptr[ n - k - 3 ] ); + xmm_x_ptr_sub_x2x0 = OP_CVTEPI16_EPI32_M64( &x_ptr[ subfr_length - n + k - 1 ] ); + + xmm_x_ptr_n_k_x2x0 = _mm_shuffle_epi32( xmm_x_ptr_n_k_x2x0, _MM_SHUFFLE( 0, 1, 2, 3 ) ); + + xmm_x_ptr_n_k_x2x0 = _mm_slli_epi32( xmm_x_ptr_n_k_x2x0, -rshifts - 1 ); + xmm_x_ptr_sub_x2x0 = _mm_slli_epi32( xmm_x_ptr_sub_x2x0, -rshifts - 1 ); + + /* equal shift right 4 bytes, xmm_x_ptr_n_k_x3x1 = _mm_srli_si128(xmm_x_ptr_n_k_x2x0, 4)*/ + xmm_x_ptr_n_k_x3x1 = _mm_shuffle_epi32( xmm_x_ptr_n_k_x2x0, _MM_SHUFFLE( 0, 3, 2, 1 ) ); + xmm_x_ptr_sub_x3x1 = _mm_shuffle_epi32( xmm_x_ptr_sub_x2x0, _MM_SHUFFLE( 0, 3, 2, 1 ) ); + + xmm_x_ptr_n_k_x2x0 = _mm_mul_epi32( xmm_x_ptr_n_k_x2x0, xmm_tmp1 ); + xmm_x_ptr_n_k_x3x1 = _mm_mul_epi32( xmm_x_ptr_n_k_x3x1, xmm_tmp1 ); + xmm_x_ptr_sub_x2x0 = _mm_mul_epi32( xmm_x_ptr_sub_x2x0, xmm_tmp2 ); + xmm_x_ptr_sub_x3x1 = _mm_mul_epi32( xmm_x_ptr_sub_x3x1, xmm_tmp2 ); + + xmm_x_ptr_n_k_x2x0 = _mm_srli_epi64( xmm_x_ptr_n_k_x2x0, 16 ); + xmm_x_ptr_n_k_x3x1 = _mm_slli_epi64( xmm_x_ptr_n_k_x3x1, 16 ); + xmm_x_ptr_sub_x2x0 = _mm_srli_epi64( xmm_x_ptr_sub_x2x0, 16 ); + xmm_x_ptr_sub_x3x1 = _mm_slli_epi64( xmm_x_ptr_sub_x3x1, 16 ); + + xmm_x_ptr_n_k_x2x0 = _mm_blend_epi16( xmm_x_ptr_n_k_x2x0, xmm_x_ptr_n_k_x3x1, 0xCC ); + xmm_x_ptr_sub_x2x0 = _mm_blend_epi16( xmm_x_ptr_sub_x2x0, xmm_x_ptr_sub_x3x1, 0xCC ); + + X1_3210 = _mm_loadu_si128( (__m128i *)&CAf[ k ] ); + PTR_3210 = _mm_loadu_si128( (__m128i *)&CAb[ k ] ); + + X1_3210 = _mm_add_epi32( X1_3210, xmm_x_ptr_n_k_x2x0 ); + PTR_3210 = _mm_add_epi32( PTR_3210, xmm_x_ptr_sub_x2x0 ); + + _mm_storeu_si128( (__m128i *)&CAf[ k ], X1_3210 ); + _mm_storeu_si128( (__m128i *)&CAb[ k ], PTR_3210 ); + } + + for( ; k <= n; k++ ) { + CAf[ k ] = silk_SMLAWW( CAf[ k ], tmp1, + silk_LSHIFT32( (opus_int32)x_ptr[ n - k ], -rshifts - 1 ) ); /* Q( -rshift ) */ + CAb[ k ] = silk_SMLAWW( CAb[ k ], tmp2, + silk_LSHIFT32( (opus_int32)x_ptr[ subfr_length - n + k - 1 ], -rshifts - 1 ) ); /* Q( -rshift ) */ + } + } + } + } + + /* Calculate nominator and denominator for the next order reflection (parcor) coefficient */ + tmp1 = C_first_row[ n ]; /* Q( -rshifts ) */ + tmp2 = C_last_row[ n ]; /* Q( -rshifts ) */ + num = 0; /* Q( -rshifts ) */ + nrg = silk_ADD32( CAb[ 0 ], CAf[ 0 ] ); /* Q( 1-rshifts ) */ + for( k = 0; k < n; k++ ) { + Atmp_QA = Af_QA[ k ]; + lz = silk_CLZ32( silk_abs( Atmp_QA ) ) - 1; + lz = silk_min( 32 - QA, lz ); + Atmp1 = silk_LSHIFT32( Atmp_QA, lz ); /* Q( QA + lz ) */ + + tmp1 = silk_ADD_LSHIFT32( tmp1, silk_SMMUL( C_last_row[ n - k - 1 ], Atmp1 ), 32 - QA - lz ); /* Q( -rshifts ) */ + tmp2 = silk_ADD_LSHIFT32( tmp2, silk_SMMUL( C_first_row[ n - k - 1 ], Atmp1 ), 32 - QA - lz ); /* Q( -rshifts ) */ + num = silk_ADD_LSHIFT32( num, silk_SMMUL( CAb[ n - k ], Atmp1 ), 32 - QA - lz ); /* Q( -rshifts ) */ + nrg = silk_ADD_LSHIFT32( nrg, silk_SMMUL( silk_ADD32( CAb[ k + 1 ], CAf[ k + 1 ] ), + Atmp1 ), 32 - QA - lz ); /* Q( 1-rshifts ) */ + } + CAf[ n + 1 ] = tmp1; /* Q( -rshifts ) */ + CAb[ n + 1 ] = tmp2; /* Q( -rshifts ) */ + num = silk_ADD32( num, tmp2 ); /* Q( -rshifts ) */ + num = silk_LSHIFT32( -num, 1 ); /* Q( 1-rshifts ) */ + + /* Calculate the next order reflection (parcor) coefficient */ + if( silk_abs( num ) < nrg ) { + rc_Q31 = silk_DIV32_varQ( num, nrg, 31 ); + } else { + rc_Q31 = ( num > 0 ) ? silk_int32_MAX : silk_int32_MIN; + } + + /* Update inverse prediction gain */ + tmp1 = ( (opus_int32)1 << 30 ) - silk_SMMUL( rc_Q31, rc_Q31 ); + tmp1 = silk_LSHIFT( silk_SMMUL( invGain_Q30, tmp1 ), 2 ); + if( tmp1 <= minInvGain_Q30 ) { + /* Max prediction gain exceeded; set reflection coefficient such that max prediction gain is exactly hit */ + tmp2 = ( (opus_int32)1 << 30 ) - silk_DIV32_varQ( minInvGain_Q30, invGain_Q30, 30 ); /* Q30 */ + rc_Q31 = silk_SQRT_APPROX( tmp2 ); /* Q15 */ + if( rc_Q31 > 0 ) { + /* Newton-Raphson iteration */ + rc_Q31 = silk_RSHIFT32( rc_Q31 + silk_DIV32( tmp2, rc_Q31 ), 1 ); /* Q15 */ + rc_Q31 = silk_LSHIFT32( rc_Q31, 16 ); /* Q31 */ + if( num < 0 ) { + /* Ensure adjusted reflection coefficients has the original sign */ + rc_Q31 = -rc_Q31; + } + } + invGain_Q30 = minInvGain_Q30; + reached_max_gain = 1; + } else { + invGain_Q30 = tmp1; + } + + /* Update the AR coefficients */ + for( k = 0; k < (n + 1) >> 1; k++ ) { + tmp1 = Af_QA[ k ]; /* QA */ + tmp2 = Af_QA[ n - k - 1 ]; /* QA */ + Af_QA[ k ] = silk_ADD_LSHIFT32( tmp1, silk_SMMUL( tmp2, rc_Q31 ), 1 ); /* QA */ + Af_QA[ n - k - 1 ] = silk_ADD_LSHIFT32( tmp2, silk_SMMUL( tmp1, rc_Q31 ), 1 ); /* QA */ + } + Af_QA[ n ] = silk_RSHIFT32( rc_Q31, 31 - QA ); /* QA */ + + if( reached_max_gain ) { + /* Reached max prediction gain; set remaining coefficients to zero and exit loop */ + for( k = n + 1; k < D; k++ ) { + Af_QA[ k ] = 0; + } + break; + } + + /* Update C * Af and C * Ab */ + for( k = 0; k <= n + 1; k++ ) { + tmp1 = CAf[ k ]; /* Q( -rshifts ) */ + tmp2 = CAb[ n - k + 1 ]; /* Q( -rshifts ) */ + CAf[ k ] = silk_ADD_LSHIFT32( tmp1, silk_SMMUL( tmp2, rc_Q31 ), 1 ); /* Q( -rshifts ) */ + CAb[ n - k + 1 ] = silk_ADD_LSHIFT32( tmp2, silk_SMMUL( tmp1, rc_Q31 ), 1 ); /* Q( -rshifts ) */ + } + } + + if( reached_max_gain ) { + for( k = 0; k < D; k++ ) { + /* Scale coefficients */ + A_Q16[ k ] = -silk_RSHIFT_ROUND( Af_QA[ k ], QA - 16 ); + } + /* Subtract energy of preceding samples from C0 */ + if( rshifts > 0 ) { + for( s = 0; s < nb_subfr; s++ ) { + x_ptr = x + s * subfr_length; + C0 -= (opus_int32)silk_RSHIFT64( silk_inner_prod16_aligned_64( x_ptr, x_ptr, D, arch ), rshifts ); + } + } else { + for( s = 0; s < nb_subfr; s++ ) { + x_ptr = x + s * subfr_length; + C0 -= silk_LSHIFT32( silk_inner_prod_aligned( x_ptr, x_ptr, D, arch ), -rshifts ); + } + } + /* Approximate residual energy */ + *res_nrg = silk_LSHIFT( silk_SMMUL( invGain_Q30, C0 ), 2 ); + *res_nrg_Q = -rshifts; + } else { + /* Return residual energy */ + nrg = CAf[ 0 ]; /* Q( -rshifts ) */ + tmp1 = (opus_int32)1 << 16; /* Q16 */ + for( k = 0; k < D; k++ ) { + Atmp1 = silk_RSHIFT_ROUND( Af_QA[ k ], QA - 16 ); /* Q16 */ + nrg = silk_SMLAWW( nrg, CAf[ k + 1 ], Atmp1 ); /* Q( -rshifts ) */ + tmp1 = silk_SMLAWW( tmp1, Atmp1, Atmp1 ); /* Q16 */ + A_Q16[ k ] = -Atmp1; + } + *res_nrg = silk_SMLAWW( nrg, silk_SMMUL( SILK_FIX_CONST( FIND_LPC_COND_FAC, 32 ), C0 ), -tmp1 );/* Q( -rshifts ) */ + *res_nrg_Q = -rshifts; + } +} diff --git a/extern/opus/silk/fixed/x86/prefilter_FIX_sse.c b/extern/opus/silk/fixed/x86/prefilter_FIX_sse.c new file mode 100644 index 0000000..555432c --- /dev/null +++ b/extern/opus/silk/fixed/x86/prefilter_FIX_sse.c @@ -0,0 +1,160 @@ +/* Copyright (c) 2014, Cisco Systems, INC + Written by XiangMingZhu WeiZhou MinPeng YanWang + + 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. + + 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 OWNER + 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. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include "main.h" +#include "celt/x86/x86cpu.h" + +void silk_warped_LPC_analysis_filter_FIX_sse4_1( + opus_int32 state[], /* I/O State [order + 1] */ + opus_int32 res_Q2[], /* O Residual signal [length] */ + const opus_int16 coef_Q13[], /* I Coefficients [order] */ + const opus_int16 input[], /* I Input signal [length] */ + const opus_int16 lambda_Q16, /* I Warping factor */ + const opus_int length, /* I Length of input signal */ + const opus_int order /* I Filter order (even) */ +) +{ + opus_int n, i; + opus_int32 acc_Q11, tmp1, tmp2; + + /* Order must be even */ + celt_assert( ( order & 1 ) == 0 ); + + if (order == 10) + { + if (0 == lambda_Q16) + { + __m128i coef_Q13_3210, coef_Q13_7654; + __m128i coef_Q13_0123, coef_Q13_4567; + __m128i state_0123, state_4567; + __m128i xmm_product1, xmm_product2; + __m128i xmm_tempa, xmm_tempb; + + register opus_int32 sum; + register opus_int32 state_8, state_9, state_a; + register opus_int64 coef_Q13_8, coef_Q13_9; + + celt_assert( length > 0 ); + + coef_Q13_3210 = OP_CVTEPI16_EPI32_M64( &coef_Q13[ 0 ] ); + coef_Q13_7654 = OP_CVTEPI16_EPI32_M64( &coef_Q13[ 4 ] ); + + coef_Q13_0123 = _mm_shuffle_epi32( coef_Q13_3210, _MM_SHUFFLE( 0, 1, 2, 3 ) ); + coef_Q13_4567 = _mm_shuffle_epi32( coef_Q13_7654, _MM_SHUFFLE( 0, 1, 2, 3 ) ); + + coef_Q13_8 = (opus_int64) coef_Q13[ 8 ]; + coef_Q13_9 = (opus_int64) coef_Q13[ 9 ]; + + state_0123 = _mm_loadu_si128( (__m128i *)(&state[ 0 ] ) ); + state_4567 = _mm_loadu_si128( (__m128i *)(&state[ 4 ] ) ); + + state_0123 = _mm_shuffle_epi32( state_0123, _MM_SHUFFLE( 0, 1, 2, 3 ) ); + state_4567 = _mm_shuffle_epi32( state_4567, _MM_SHUFFLE( 0, 1, 2, 3 ) ); + + state_8 = state[ 8 ]; + state_9 = state[ 9 ]; + state_a = 0; + + for( n = 0; n < length; n++ ) + { + xmm_product1 = _mm_mul_epi32( coef_Q13_0123, state_0123 ); /* 64-bit multiply, only 2 pairs */ + xmm_product2 = _mm_mul_epi32( coef_Q13_4567, state_4567 ); + + xmm_tempa = _mm_shuffle_epi32( state_0123, _MM_SHUFFLE( 0, 1, 2, 3 ) ); + xmm_tempb = _mm_shuffle_epi32( state_4567, _MM_SHUFFLE( 0, 1, 2, 3 ) ); + + xmm_product1 = _mm_srli_epi64( xmm_product1, 16 ); /* >> 16, zero extending works */ + xmm_product2 = _mm_srli_epi64( xmm_product2, 16 ); + + xmm_tempa = _mm_mul_epi32( coef_Q13_3210, xmm_tempa ); + xmm_tempb = _mm_mul_epi32( coef_Q13_7654, xmm_tempb ); + + xmm_tempa = _mm_srli_epi64( xmm_tempa, 16 ); + xmm_tempb = _mm_srli_epi64( xmm_tempb, 16 ); + + xmm_tempa = _mm_add_epi32( xmm_tempa, xmm_product1 ); + xmm_tempb = _mm_add_epi32( xmm_tempb, xmm_product2 ); + xmm_tempa = _mm_add_epi32( xmm_tempa, xmm_tempb ); + + sum = (opus_int32)((coef_Q13_8 * state_8) >> 16); + sum += (opus_int32)((coef_Q13_9 * state_9) >> 16); + + xmm_tempa = _mm_add_epi32( xmm_tempa, _mm_shuffle_epi32( xmm_tempa, _MM_SHUFFLE( 0, 0, 0, 2 ) ) ); + sum += _mm_cvtsi128_si32( xmm_tempa); + res_Q2[ n ] = silk_LSHIFT( (opus_int32)input[ n ], 2 ) - silk_RSHIFT_ROUND( ( 5 + sum ), 9); + + /* move right */ + state_a = state_9; + state_9 = state_8; + state_8 = _mm_cvtsi128_si32( state_4567 ); + state_4567 = _mm_alignr_epi8( state_0123, state_4567, 4 ); + + state_0123 = _mm_alignr_epi8( _mm_cvtsi32_si128( silk_LSHIFT( input[ n ], 14 ) ), state_0123, 4 ); + } + + _mm_storeu_si128( (__m128i *)( &state[ 0 ] ), _mm_shuffle_epi32( state_0123, _MM_SHUFFLE( 0, 1, 2, 3 ) ) ); + _mm_storeu_si128( (__m128i *)( &state[ 4 ] ), _mm_shuffle_epi32( state_4567, _MM_SHUFFLE( 0, 1, 2, 3 ) ) ); + state[ 8 ] = state_8; + state[ 9 ] = state_9; + state[ 10 ] = state_a; + + return; + } + } + + for( n = 0; n < length; n++ ) { + /* Output of lowpass section */ + tmp2 = silk_SMLAWB( state[ 0 ], state[ 1 ], lambda_Q16 ); + state[ 0 ] = silk_LSHIFT( input[ n ], 14 ); + /* Output of allpass section */ + tmp1 = silk_SMLAWB( state[ 1 ], state[ 2 ] - tmp2, lambda_Q16 ); + state[ 1 ] = tmp2; + acc_Q11 = silk_RSHIFT( order, 1 ); + acc_Q11 = silk_SMLAWB( acc_Q11, tmp2, coef_Q13[ 0 ] ); + /* Loop over allpass sections */ + for( i = 2; i < order; i += 2 ) { + /* Output of allpass section */ + tmp2 = silk_SMLAWB( state[ i ], state[ i + 1 ] - tmp1, lambda_Q16 ); + state[ i ] = tmp1; + acc_Q11 = silk_SMLAWB( acc_Q11, tmp1, coef_Q13[ i - 1 ] ); + /* Output of allpass section */ + tmp1 = silk_SMLAWB( state[ i + 1 ], state[ i + 2 ] - tmp2, lambda_Q16 ); + state[ i + 1 ] = tmp2; + acc_Q11 = silk_SMLAWB( acc_Q11, tmp2, coef_Q13[ i ] ); + } + state[ order ] = tmp1; + acc_Q11 = silk_SMLAWB( acc_Q11, tmp1, coef_Q13[ order - 1 ] ); + res_Q2[ n ] = silk_LSHIFT( (opus_int32)input[ n ], 2 ) - silk_RSHIFT_ROUND( acc_Q11, 9 ); + } +} diff --git a/extern/opus/silk/fixed/x86/vector_ops_FIX_sse4_1.c b/extern/opus/silk/fixed/x86/vector_ops_FIX_sse4_1.c new file mode 100644 index 0000000..c1e9056 --- /dev/null +++ b/extern/opus/silk/fixed/x86/vector_ops_FIX_sse4_1.c @@ -0,0 +1,88 @@ +/* Copyright (c) 2014, Cisco Systems, INC + Written by XiangMingZhu WeiZhou MinPeng YanWang + + 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. + + 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 OWNER + 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. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include "main.h" + +#include "SigProc_FIX.h" +#include "pitch.h" + +opus_int64 silk_inner_prod16_aligned_64_sse4_1( + const opus_int16 *inVec1, /* I input vector 1 */ + const opus_int16 *inVec2, /* I input vector 2 */ + const opus_int len /* I vector lengths */ +) +{ + opus_int i, dataSize8; + opus_int64 sum; + + __m128i xmm_tempa; + __m128i inVec1_76543210, acc1; + __m128i inVec2_76543210, acc2; + + sum = 0; + dataSize8 = len & ~7; + + acc1 = _mm_setzero_si128(); + acc2 = _mm_setzero_si128(); + + for( i = 0; i < dataSize8; i += 8 ) { + inVec1_76543210 = _mm_loadu_si128( (__m128i *)(&inVec1[i + 0] ) ); + inVec2_76543210 = _mm_loadu_si128( (__m128i *)(&inVec2[i + 0] ) ); + + /* only when all 4 operands are -32768 (0x8000), this results in wrap around */ + inVec1_76543210 = _mm_madd_epi16( inVec1_76543210, inVec2_76543210 ); + + xmm_tempa = _mm_cvtepi32_epi64( inVec1_76543210 ); + /* equal shift right 8 bytes */ + inVec1_76543210 = _mm_shuffle_epi32( inVec1_76543210, _MM_SHUFFLE( 0, 0, 3, 2 ) ); + inVec1_76543210 = _mm_cvtepi32_epi64( inVec1_76543210 ); + + acc1 = _mm_add_epi64( acc1, xmm_tempa ); + acc2 = _mm_add_epi64( acc2, inVec1_76543210 ); + } + + acc1 = _mm_add_epi64( acc1, acc2 ); + + /* equal shift right 8 bytes */ + acc2 = _mm_shuffle_epi32( acc1, _MM_SHUFFLE( 0, 0, 3, 2 ) ); + acc1 = _mm_add_epi64( acc1, acc2 ); + + _mm_storel_epi64( (__m128i *)&sum, acc1 ); + + for( ; i < len; i++ ) { + sum = silk_SMLABB( sum, inVec1[ i ], inVec2[ i ] ); + } + + return sum; +} diff --git a/extern/opus/silk/float/LPC_analysis_filter_FLP.c b/extern/opus/silk/float/LPC_analysis_filter_FLP.c new file mode 100644 index 0000000..0e1a1fe --- /dev/null +++ b/extern/opus/silk/float/LPC_analysis_filter_FLP.c @@ -0,0 +1,249 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "main_FLP.h" + +/************************************************/ +/* LPC analysis filter */ +/* NB! State is kept internally and the */ +/* filter always starts with zero state */ +/* first Order output samples are set to zero */ +/************************************************/ + +/* 16th order LPC analysis filter, does not write first 16 samples */ +static OPUS_INLINE void silk_LPC_analysis_filter16_FLP( + silk_float r_LPC[], /* O LPC residual signal */ + const silk_float PredCoef[], /* I LPC coefficients */ + const silk_float s[], /* I Input signal */ + const opus_int length /* I Length of input signal */ +) +{ + opus_int ix; + silk_float LPC_pred; + const silk_float *s_ptr; + + for( ix = 16; ix < length; ix++ ) { + s_ptr = &s[ix - 1]; + + /* short-term prediction */ + LPC_pred = s_ptr[ 0 ] * PredCoef[ 0 ] + + s_ptr[ -1 ] * PredCoef[ 1 ] + + s_ptr[ -2 ] * PredCoef[ 2 ] + + s_ptr[ -3 ] * PredCoef[ 3 ] + + s_ptr[ -4 ] * PredCoef[ 4 ] + + s_ptr[ -5 ] * PredCoef[ 5 ] + + s_ptr[ -6 ] * PredCoef[ 6 ] + + s_ptr[ -7 ] * PredCoef[ 7 ] + + s_ptr[ -8 ] * PredCoef[ 8 ] + + s_ptr[ -9 ] * PredCoef[ 9 ] + + s_ptr[ -10 ] * PredCoef[ 10 ] + + s_ptr[ -11 ] * PredCoef[ 11 ] + + s_ptr[ -12 ] * PredCoef[ 12 ] + + s_ptr[ -13 ] * PredCoef[ 13 ] + + s_ptr[ -14 ] * PredCoef[ 14 ] + + s_ptr[ -15 ] * PredCoef[ 15 ]; + + /* prediction error */ + r_LPC[ix] = s_ptr[ 1 ] - LPC_pred; + } +} + +/* 12th order LPC analysis filter, does not write first 12 samples */ +static OPUS_INLINE void silk_LPC_analysis_filter12_FLP( + silk_float r_LPC[], /* O LPC residual signal */ + const silk_float PredCoef[], /* I LPC coefficients */ + const silk_float s[], /* I Input signal */ + const opus_int length /* I Length of input signal */ +) +{ + opus_int ix; + silk_float LPC_pred; + const silk_float *s_ptr; + + for( ix = 12; ix < length; ix++ ) { + s_ptr = &s[ix - 1]; + + /* short-term prediction */ + LPC_pred = s_ptr[ 0 ] * PredCoef[ 0 ] + + s_ptr[ -1 ] * PredCoef[ 1 ] + + s_ptr[ -2 ] * PredCoef[ 2 ] + + s_ptr[ -3 ] * PredCoef[ 3 ] + + s_ptr[ -4 ] * PredCoef[ 4 ] + + s_ptr[ -5 ] * PredCoef[ 5 ] + + s_ptr[ -6 ] * PredCoef[ 6 ] + + s_ptr[ -7 ] * PredCoef[ 7 ] + + s_ptr[ -8 ] * PredCoef[ 8 ] + + s_ptr[ -9 ] * PredCoef[ 9 ] + + s_ptr[ -10 ] * PredCoef[ 10 ] + + s_ptr[ -11 ] * PredCoef[ 11 ]; + + /* prediction error */ + r_LPC[ix] = s_ptr[ 1 ] - LPC_pred; + } +} + +/* 10th order LPC analysis filter, does not write first 10 samples */ +static OPUS_INLINE void silk_LPC_analysis_filter10_FLP( + silk_float r_LPC[], /* O LPC residual signal */ + const silk_float PredCoef[], /* I LPC coefficients */ + const silk_float s[], /* I Input signal */ + const opus_int length /* I Length of input signal */ +) +{ + opus_int ix; + silk_float LPC_pred; + const silk_float *s_ptr; + + for( ix = 10; ix < length; ix++ ) { + s_ptr = &s[ix - 1]; + + /* short-term prediction */ + LPC_pred = s_ptr[ 0 ] * PredCoef[ 0 ] + + s_ptr[ -1 ] * PredCoef[ 1 ] + + s_ptr[ -2 ] * PredCoef[ 2 ] + + s_ptr[ -3 ] * PredCoef[ 3 ] + + s_ptr[ -4 ] * PredCoef[ 4 ] + + s_ptr[ -5 ] * PredCoef[ 5 ] + + s_ptr[ -6 ] * PredCoef[ 6 ] + + s_ptr[ -7 ] * PredCoef[ 7 ] + + s_ptr[ -8 ] * PredCoef[ 8 ] + + s_ptr[ -9 ] * PredCoef[ 9 ]; + + /* prediction error */ + r_LPC[ix] = s_ptr[ 1 ] - LPC_pred; + } +} + +/* 8th order LPC analysis filter, does not write first 8 samples */ +static OPUS_INLINE void silk_LPC_analysis_filter8_FLP( + silk_float r_LPC[], /* O LPC residual signal */ + const silk_float PredCoef[], /* I LPC coefficients */ + const silk_float s[], /* I Input signal */ + const opus_int length /* I Length of input signal */ +) +{ + opus_int ix; + silk_float LPC_pred; + const silk_float *s_ptr; + + for( ix = 8; ix < length; ix++ ) { + s_ptr = &s[ix - 1]; + + /* short-term prediction */ + LPC_pred = s_ptr[ 0 ] * PredCoef[ 0 ] + + s_ptr[ -1 ] * PredCoef[ 1 ] + + s_ptr[ -2 ] * PredCoef[ 2 ] + + s_ptr[ -3 ] * PredCoef[ 3 ] + + s_ptr[ -4 ] * PredCoef[ 4 ] + + s_ptr[ -5 ] * PredCoef[ 5 ] + + s_ptr[ -6 ] * PredCoef[ 6 ] + + s_ptr[ -7 ] * PredCoef[ 7 ]; + + /* prediction error */ + r_LPC[ix] = s_ptr[ 1 ] - LPC_pred; + } +} + +/* 6th order LPC analysis filter, does not write first 6 samples */ +static OPUS_INLINE void silk_LPC_analysis_filter6_FLP( + silk_float r_LPC[], /* O LPC residual signal */ + const silk_float PredCoef[], /* I LPC coefficients */ + const silk_float s[], /* I Input signal */ + const opus_int length /* I Length of input signal */ +) +{ + opus_int ix; + silk_float LPC_pred; + const silk_float *s_ptr; + + for( ix = 6; ix < length; ix++ ) { + s_ptr = &s[ix - 1]; + + /* short-term prediction */ + LPC_pred = s_ptr[ 0 ] * PredCoef[ 0 ] + + s_ptr[ -1 ] * PredCoef[ 1 ] + + s_ptr[ -2 ] * PredCoef[ 2 ] + + s_ptr[ -3 ] * PredCoef[ 3 ] + + s_ptr[ -4 ] * PredCoef[ 4 ] + + s_ptr[ -5 ] * PredCoef[ 5 ]; + + /* prediction error */ + r_LPC[ix] = s_ptr[ 1 ] - LPC_pred; + } +} + +/************************************************/ +/* LPC analysis filter */ +/* NB! State is kept internally and the */ +/* filter always starts with zero state */ +/* first Order output samples are set to zero */ +/************************************************/ +void silk_LPC_analysis_filter_FLP( + silk_float r_LPC[], /* O LPC residual signal */ + const silk_float PredCoef[], /* I LPC coefficients */ + const silk_float s[], /* I Input signal */ + const opus_int length, /* I Length of input signal */ + const opus_int Order /* I LPC order */ +) +{ + celt_assert( Order <= length ); + + switch( Order ) { + case 6: + silk_LPC_analysis_filter6_FLP( r_LPC, PredCoef, s, length ); + break; + + case 8: + silk_LPC_analysis_filter8_FLP( r_LPC, PredCoef, s, length ); + break; + + case 10: + silk_LPC_analysis_filter10_FLP( r_LPC, PredCoef, s, length ); + break; + + case 12: + silk_LPC_analysis_filter12_FLP( r_LPC, PredCoef, s, length ); + break; + + case 16: + silk_LPC_analysis_filter16_FLP( r_LPC, PredCoef, s, length ); + break; + + default: + celt_assert( 0 ); + break; + } + + /* Set first Order output samples to zero */ + silk_memset( r_LPC, 0, Order * sizeof( silk_float ) ); +} + diff --git a/extern/opus/silk/float/LPC_inv_pred_gain_FLP.c b/extern/opus/silk/float/LPC_inv_pred_gain_FLP.c new file mode 100644 index 0000000..2be2122 --- /dev/null +++ b/extern/opus/silk/float/LPC_inv_pred_gain_FLP.c @@ -0,0 +1,73 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" +#include "SigProc_FLP.h" +#include "define.h" + +/* compute inverse of LPC prediction gain, and */ +/* test if LPC coefficients are stable (all poles within unit circle) */ +/* this code is based on silk_a2k_FLP() */ +silk_float silk_LPC_inverse_pred_gain_FLP( /* O return inverse prediction gain, energy domain */ + const silk_float *A, /* I prediction coefficients [order] */ + opus_int32 order /* I prediction order */ +) +{ + opus_int k, n; + double invGain, rc, rc_mult1, rc_mult2, tmp1, tmp2; + silk_float Atmp[ SILK_MAX_ORDER_LPC ]; + + silk_memcpy( Atmp, A, order * sizeof(silk_float) ); + + invGain = 1.0; + for( k = order - 1; k > 0; k-- ) { + rc = -Atmp[ k ]; + rc_mult1 = 1.0f - rc * rc; + invGain *= rc_mult1; + if( invGain * MAX_PREDICTION_POWER_GAIN < 1.0f ) { + return 0.0f; + } + rc_mult2 = 1.0f / rc_mult1; + for( n = 0; n < (k + 1) >> 1; n++ ) { + tmp1 = Atmp[ n ]; + tmp2 = Atmp[ k - n - 1 ]; + Atmp[ n ] = (silk_float)( ( tmp1 - tmp2 * rc ) * rc_mult2 ); + Atmp[ k - n - 1 ] = (silk_float)( ( tmp2 - tmp1 * rc ) * rc_mult2 ); + } + } + rc = -Atmp[ 0 ]; + rc_mult1 = 1.0f - rc * rc; + invGain *= rc_mult1; + if( invGain * MAX_PREDICTION_POWER_GAIN < 1.0f ) { + return 0.0f; + } + return (silk_float)invGain; +} diff --git a/extern/opus/silk/float/LTP_analysis_filter_FLP.c b/extern/opus/silk/float/LTP_analysis_filter_FLP.c new file mode 100644 index 0000000..849b7c1 --- /dev/null +++ b/extern/opus/silk/float/LTP_analysis_filter_FLP.c @@ -0,0 +1,75 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FLP.h" + +void silk_LTP_analysis_filter_FLP( + silk_float *LTP_res, /* O LTP res MAX_NB_SUBFR*(pre_lgth+subfr_lngth) */ + const silk_float *x, /* I Input signal, with preceding samples */ + const silk_float B[ LTP_ORDER * MAX_NB_SUBFR ], /* I LTP coefficients for each subframe */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lags */ + const silk_float invGains[ MAX_NB_SUBFR ], /* I Inverse quantization gains */ + const opus_int subfr_length, /* I Length of each subframe */ + const opus_int nb_subfr, /* I number of subframes */ + const opus_int pre_length /* I Preceding samples for each subframe */ +) +{ + const silk_float *x_ptr, *x_lag_ptr; + silk_float Btmp[ LTP_ORDER ]; + silk_float *LTP_res_ptr; + silk_float inv_gain; + opus_int k, i, j; + + x_ptr = x; + LTP_res_ptr = LTP_res; + for( k = 0; k < nb_subfr; k++ ) { + x_lag_ptr = x_ptr - pitchL[ k ]; + inv_gain = invGains[ k ]; + for( i = 0; i < LTP_ORDER; i++ ) { + Btmp[ i ] = B[ k * LTP_ORDER + i ]; + } + + /* LTP analysis FIR filter */ + for( i = 0; i < subfr_length + pre_length; i++ ) { + LTP_res_ptr[ i ] = x_ptr[ i ]; + /* Subtract long-term prediction */ + for( j = 0; j < LTP_ORDER; j++ ) { + LTP_res_ptr[ i ] -= Btmp[ j ] * x_lag_ptr[ LTP_ORDER / 2 - j ]; + } + LTP_res_ptr[ i ] *= inv_gain; + x_lag_ptr++; + } + + /* Update pointers */ + LTP_res_ptr += subfr_length + pre_length; + x_ptr += subfr_length; + } +} diff --git a/extern/opus/silk/float/LTP_scale_ctrl_FLP.c b/extern/opus/silk/float/LTP_scale_ctrl_FLP.c new file mode 100644 index 0000000..8dbe29d --- /dev/null +++ b/extern/opus/silk/float/LTP_scale_ctrl_FLP.c @@ -0,0 +1,52 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FLP.h" + +void silk_LTP_scale_ctrl_FLP( + silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */ + opus_int condCoding /* I The type of conditional coding to use */ +) +{ + opus_int round_loss; + + if( condCoding == CODE_INDEPENDENTLY ) { + /* Only scale if first frame in packet */ + round_loss = psEnc->sCmn.PacketLoss_perc + psEnc->sCmn.nFramesPerPacket; + psEnc->sCmn.indices.LTP_scaleIndex = (opus_int8)silk_LIMIT( round_loss * psEncCtrl->LTPredCodGain * 0.1f, 0.0f, 2.0f ); + } else { + /* Default is minimum scaling */ + psEnc->sCmn.indices.LTP_scaleIndex = 0; + } + + psEncCtrl->LTP_scale = (silk_float)silk_LTPScales_table_Q14[ psEnc->sCmn.indices.LTP_scaleIndex ] / 16384.0f; +} diff --git a/extern/opus/silk/float/SigProc_FLP.h b/extern/opus/silk/float/SigProc_FLP.h new file mode 100644 index 0000000..953de8b --- /dev/null +++ b/extern/opus/silk/float/SigProc_FLP.h @@ -0,0 +1,197 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifndef SILK_SIGPROC_FLP_H +#define SILK_SIGPROC_FLP_H + +#include "SigProc_FIX.h" +#include "float_cast.h" +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + +/********************************************************************/ +/* SIGNAL PROCESSING FUNCTIONS */ +/********************************************************************/ + +/* Chirp (bw expand) LP AR filter */ +void silk_bwexpander_FLP( + silk_float *ar, /* I/O AR filter to be expanded (without leading 1) */ + const opus_int d, /* I length of ar */ + const silk_float chirp /* I chirp factor (typically in range (0..1) ) */ +); + +/* compute inverse of LPC prediction gain, and */ +/* test if LPC coefficients are stable (all poles within unit circle) */ +/* this code is based on silk_FLP_a2k() */ +silk_float silk_LPC_inverse_pred_gain_FLP( /* O return inverse prediction gain, energy domain */ + const silk_float *A, /* I prediction coefficients [order] */ + opus_int32 order /* I prediction order */ +); + +silk_float silk_schur_FLP( /* O returns residual energy */ + silk_float refl_coef[], /* O reflection coefficients (length order) */ + const silk_float auto_corr[], /* I autocorrelation sequence (length order+1) */ + opus_int order /* I order */ +); + +void silk_k2a_FLP( + silk_float *A, /* O prediction coefficients [order] */ + const silk_float *rc, /* I reflection coefficients [order] */ + opus_int32 order /* I prediction order */ +); + +/* compute autocorrelation */ +void silk_autocorrelation_FLP( + silk_float *results, /* O result (length correlationCount) */ + const silk_float *inputData, /* I input data to correlate */ + opus_int inputDataSize, /* I length of input */ + opus_int correlationCount /* I number of correlation taps to compute */ +); + +opus_int silk_pitch_analysis_core_FLP( /* O Voicing estimate: 0 voiced, 1 unvoiced */ + const silk_float *frame, /* I Signal of length PE_FRAME_LENGTH_MS*Fs_kHz */ + opus_int *pitch_out, /* O Pitch lag values [nb_subfr] */ + opus_int16 *lagIndex, /* O Lag Index */ + opus_int8 *contourIndex, /* O Pitch contour Index */ + silk_float *LTPCorr, /* I/O Normalized correlation; input: value from previous frame */ + opus_int prevLag, /* I Last lag of previous frame; set to zero is unvoiced */ + const silk_float search_thres1, /* I First stage threshold for lag candidates 0 - 1 */ + const silk_float search_thres2, /* I Final threshold for lag candidates 0 - 1 */ + const opus_int Fs_kHz, /* I sample frequency (kHz) */ + const opus_int complexity, /* I Complexity setting, 0-2, where 2 is highest */ + const opus_int nb_subfr, /* I Number of 5 ms subframes */ + int arch /* I Run-time architecture */ +); + +void silk_insertion_sort_decreasing_FLP( + silk_float *a, /* I/O Unsorted / Sorted vector */ + opus_int *idx, /* O Index vector for the sorted elements */ + const opus_int L, /* I Vector length */ + const opus_int K /* I Number of correctly sorted positions */ +); + +/* Compute reflection coefficients from input signal */ +silk_float silk_burg_modified_FLP( /* O returns residual energy */ + silk_float A[], /* O prediction coefficients (length order) */ + const silk_float x[], /* I input signal, length: nb_subfr*(D+L_sub) */ + const silk_float minInvGain, /* I minimum inverse prediction gain */ + const opus_int subfr_length, /* I input signal subframe length (incl. D preceding samples) */ + const opus_int nb_subfr, /* I number of subframes stacked in x */ + const opus_int D /* I order */ +); + +/* multiply a vector by a constant */ +void silk_scale_vector_FLP( + silk_float *data1, + silk_float gain, + opus_int dataSize +); + +/* copy and multiply a vector by a constant */ +void silk_scale_copy_vector_FLP( + silk_float *data_out, + const silk_float *data_in, + silk_float gain, + opus_int dataSize +); + +/* inner product of two silk_float arrays, with result as double */ +double silk_inner_product_FLP( + const silk_float *data1, + const silk_float *data2, + opus_int dataSize +); + +/* sum of squares of a silk_float array, with result as double */ +double silk_energy_FLP( + const silk_float *data, + opus_int dataSize +); + +/********************************************************************/ +/* MACROS */ +/********************************************************************/ + +#define PI (3.1415926536f) + +#define silk_min_float( a, b ) (((a) < (b)) ? (a) : (b)) +#define silk_max_float( a, b ) (((a) > (b)) ? (a) : (b)) +#define silk_abs_float( a ) ((silk_float)fabs(a)) + +/* sigmoid function */ +static OPUS_INLINE silk_float silk_sigmoid( silk_float x ) +{ + return (silk_float)(1.0 / (1.0 + exp(-x))); +} + +/* floating-point to integer conversion (rounding) */ +static OPUS_INLINE opus_int32 silk_float2int( silk_float x ) +{ + return (opus_int32)float2int( x ); +} + +/* floating-point to integer conversion (rounding) */ +static OPUS_INLINE void silk_float2short_array( + opus_int16 *out, + const silk_float *in, + opus_int32 length +) +{ + opus_int32 k; + for( k = length - 1; k >= 0; k-- ) { + out[k] = silk_SAT16( (opus_int32)float2int( in[k] ) ); + } +} + +/* integer to floating-point conversion */ +static OPUS_INLINE void silk_short2float_array( + silk_float *out, + const opus_int16 *in, + opus_int32 length +) +{ + opus_int32 k; + for( k = length - 1; k >= 0; k-- ) { + out[k] = (silk_float)in[k]; + } +} + +/* using log2() helps the fixed-point conversion */ +static OPUS_INLINE silk_float silk_log2( double x ) +{ + return ( silk_float )( 3.32192809488736 * log10( x ) ); +} + +#ifdef __cplusplus +} +#endif + +#endif /* SILK_SIGPROC_FLP_H */ diff --git a/extern/opus/silk/float/apply_sine_window_FLP.c b/extern/opus/silk/float/apply_sine_window_FLP.c new file mode 100644 index 0000000..e49e717 --- /dev/null +++ b/extern/opus/silk/float/apply_sine_window_FLP.c @@ -0,0 +1,81 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FLP.h" + +/* Apply sine window to signal vector */ +/* Window types: */ +/* 1 -> sine window from 0 to pi/2 */ +/* 2 -> sine window from pi/2 to pi */ +void silk_apply_sine_window_FLP( + silk_float px_win[], /* O Pointer to windowed signal */ + const silk_float px[], /* I Pointer to input signal */ + const opus_int win_type, /* I Selects a window type */ + const opus_int length /* I Window length, multiple of 4 */ +) +{ + opus_int k; + silk_float freq, c, S0, S1; + + celt_assert( win_type == 1 || win_type == 2 ); + + /* Length must be multiple of 4 */ + celt_assert( ( length & 3 ) == 0 ); + + freq = PI / ( length + 1 ); + + /* Approximation of 2 * cos(f) */ + c = 2.0f - freq * freq; + + /* Initialize state */ + if( win_type < 2 ) { + /* Start from 0 */ + S0 = 0.0f; + /* Approximation of sin(f) */ + S1 = freq; + } else { + /* Start from 1 */ + S0 = 1.0f; + /* Approximation of cos(f) */ + S1 = 0.5f * c; + } + + /* Uses the recursive equation: sin(n*f) = 2 * cos(f) * sin((n-1)*f) - sin((n-2)*f) */ + /* 4 samples at a time */ + for( k = 0; k < length; k += 4 ) { + px_win[ k + 0 ] = px[ k + 0 ] * 0.5f * ( S0 + S1 ); + px_win[ k + 1 ] = px[ k + 1 ] * S1; + S0 = c * S1 - S0; + px_win[ k + 2 ] = px[ k + 2 ] * 0.5f * ( S1 + S0 ); + px_win[ k + 3 ] = px[ k + 3 ] * S0; + S1 = c * S0 - S1; + } +} diff --git a/extern/opus/silk/float/autocorrelation_FLP.c b/extern/opus/silk/float/autocorrelation_FLP.c new file mode 100644 index 0000000..8b8a9e6 --- /dev/null +++ b/extern/opus/silk/float/autocorrelation_FLP.c @@ -0,0 +1,52 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "typedef.h" +#include "SigProc_FLP.h" + +/* compute autocorrelation */ +void silk_autocorrelation_FLP( + silk_float *results, /* O result (length correlationCount) */ + const silk_float *inputData, /* I input data to correlate */ + opus_int inputDataSize, /* I length of input */ + opus_int correlationCount /* I number of correlation taps to compute */ +) +{ + opus_int i; + + if( correlationCount > inputDataSize ) { + correlationCount = inputDataSize; + } + + for( i = 0; i < correlationCount; i++ ) { + results[ i ] = (silk_float)silk_inner_product_FLP( inputData, inputData + i, inputDataSize - i ); + } +} diff --git a/extern/opus/silk/float/burg_modified_FLP.c b/extern/opus/silk/float/burg_modified_FLP.c new file mode 100644 index 0000000..756b76a --- /dev/null +++ b/extern/opus/silk/float/burg_modified_FLP.c @@ -0,0 +1,186 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FLP.h" +#include "tuning_parameters.h" +#include "define.h" + +#define MAX_FRAME_SIZE 384 /* subfr_length * nb_subfr = ( 0.005 * 16000 + 16 ) * 4 = 384*/ + +/* Compute reflection coefficients from input signal */ +silk_float silk_burg_modified_FLP( /* O returns residual energy */ + silk_float A[], /* O prediction coefficients (length order) */ + const silk_float x[], /* I input signal, length: nb_subfr*(D+L_sub) */ + const silk_float minInvGain, /* I minimum inverse prediction gain */ + const opus_int subfr_length, /* I input signal subframe length (incl. D preceding samples) */ + const opus_int nb_subfr, /* I number of subframes stacked in x */ + const opus_int D /* I order */ +) +{ + opus_int k, n, s, reached_max_gain; + double C0, invGain, num, nrg_f, nrg_b, rc, Atmp, tmp1, tmp2; + const silk_float *x_ptr; + double C_first_row[ SILK_MAX_ORDER_LPC ], C_last_row[ SILK_MAX_ORDER_LPC ]; + double CAf[ SILK_MAX_ORDER_LPC + 1 ], CAb[ SILK_MAX_ORDER_LPC + 1 ]; + double Af[ SILK_MAX_ORDER_LPC ]; + + celt_assert( subfr_length * nb_subfr <= MAX_FRAME_SIZE ); + + /* Compute autocorrelations, added over subframes */ + C0 = silk_energy_FLP( x, nb_subfr * subfr_length ); + silk_memset( C_first_row, 0, SILK_MAX_ORDER_LPC * sizeof( double ) ); + for( s = 0; s < nb_subfr; s++ ) { + x_ptr = x + s * subfr_length; + for( n = 1; n < D + 1; n++ ) { + C_first_row[ n - 1 ] += silk_inner_product_FLP( x_ptr, x_ptr + n, subfr_length - n ); + } + } + silk_memcpy( C_last_row, C_first_row, SILK_MAX_ORDER_LPC * sizeof( double ) ); + + /* Initialize */ + CAb[ 0 ] = CAf[ 0 ] = C0 + FIND_LPC_COND_FAC * C0 + 1e-9f; + invGain = 1.0f; + reached_max_gain = 0; + for( n = 0; n < D; n++ ) { + /* Update first row of correlation matrix (without first element) */ + /* Update last row of correlation matrix (without last element, stored in reversed order) */ + /* Update C * Af */ + /* Update C * flipud(Af) (stored in reversed order) */ + for( s = 0; s < nb_subfr; s++ ) { + x_ptr = x + s * subfr_length; + tmp1 = x_ptr[ n ]; + tmp2 = x_ptr[ subfr_length - n - 1 ]; + for( k = 0; k < n; k++ ) { + C_first_row[ k ] -= x_ptr[ n ] * x_ptr[ n - k - 1 ]; + C_last_row[ k ] -= x_ptr[ subfr_length - n - 1 ] * x_ptr[ subfr_length - n + k ]; + Atmp = Af[ k ]; + tmp1 += x_ptr[ n - k - 1 ] * Atmp; + tmp2 += x_ptr[ subfr_length - n + k ] * Atmp; + } + for( k = 0; k <= n; k++ ) { + CAf[ k ] -= tmp1 * x_ptr[ n - k ]; + CAb[ k ] -= tmp2 * x_ptr[ subfr_length - n + k - 1 ]; + } + } + tmp1 = C_first_row[ n ]; + tmp2 = C_last_row[ n ]; + for( k = 0; k < n; k++ ) { + Atmp = Af[ k ]; + tmp1 += C_last_row[ n - k - 1 ] * Atmp; + tmp2 += C_first_row[ n - k - 1 ] * Atmp; + } + CAf[ n + 1 ] = tmp1; + CAb[ n + 1 ] = tmp2; + + /* Calculate nominator and denominator for the next order reflection (parcor) coefficient */ + num = CAb[ n + 1 ]; + nrg_b = CAb[ 0 ]; + nrg_f = CAf[ 0 ]; + for( k = 0; k < n; k++ ) { + Atmp = Af[ k ]; + num += CAb[ n - k ] * Atmp; + nrg_b += CAb[ k + 1 ] * Atmp; + nrg_f += CAf[ k + 1 ] * Atmp; + } + silk_assert( nrg_f > 0.0 ); + silk_assert( nrg_b > 0.0 ); + + /* Calculate the next order reflection (parcor) coefficient */ + rc = -2.0 * num / ( nrg_f + nrg_b ); + silk_assert( rc > -1.0 && rc < 1.0 ); + + /* Update inverse prediction gain */ + tmp1 = invGain * ( 1.0 - rc * rc ); + if( tmp1 <= minInvGain ) { + /* Max prediction gain exceeded; set reflection coefficient such that max prediction gain is exactly hit */ + rc = sqrt( 1.0 - minInvGain / invGain ); + if( num > 0 ) { + /* Ensure adjusted reflection coefficients has the original sign */ + rc = -rc; + } + invGain = minInvGain; + reached_max_gain = 1; + } else { + invGain = tmp1; + } + + /* Update the AR coefficients */ + for( k = 0; k < (n + 1) >> 1; k++ ) { + tmp1 = Af[ k ]; + tmp2 = Af[ n - k - 1 ]; + Af[ k ] = tmp1 + rc * tmp2; + Af[ n - k - 1 ] = tmp2 + rc * tmp1; + } + Af[ n ] = rc; + + if( reached_max_gain ) { + /* Reached max prediction gain; set remaining coefficients to zero and exit loop */ + for( k = n + 1; k < D; k++ ) { + Af[ k ] = 0.0; + } + break; + } + + /* Update C * Af and C * Ab */ + for( k = 0; k <= n + 1; k++ ) { + tmp1 = CAf[ k ]; + CAf[ k ] += rc * CAb[ n - k + 1 ]; + CAb[ n - k + 1 ] += rc * tmp1; + } + } + + if( reached_max_gain ) { + /* Convert to silk_float */ + for( k = 0; k < D; k++ ) { + A[ k ] = (silk_float)( -Af[ k ] ); + } + /* Subtract energy of preceding samples from C0 */ + for( s = 0; s < nb_subfr; s++ ) { + C0 -= silk_energy_FLP( x + s * subfr_length, D ); + } + /* Approximate residual energy */ + nrg_f = C0 * invGain; + } else { + /* Compute residual energy and store coefficients as silk_float */ + nrg_f = CAf[ 0 ]; + tmp1 = 1.0; + for( k = 0; k < D; k++ ) { + Atmp = Af[ k ]; + nrg_f += CAf[ k + 1 ] * Atmp; + tmp1 += Atmp * Atmp; + A[ k ] = (silk_float)(-Atmp); + } + nrg_f -= FIND_LPC_COND_FAC * C0 * tmp1; + } + + /* Return residual energy */ + return (silk_float)nrg_f; +} diff --git a/extern/opus/silk/float/bwexpander_FLP.c b/extern/opus/silk/float/bwexpander_FLP.c new file mode 100644 index 0000000..d55a4d7 --- /dev/null +++ b/extern/opus/silk/float/bwexpander_FLP.c @@ -0,0 +1,49 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FLP.h" + +/* Chirp (bw expand) LP AR filter */ +void silk_bwexpander_FLP( + silk_float *ar, /* I/O AR filter to be expanded (without leading 1) */ + const opus_int d, /* I length of ar */ + const silk_float chirp /* I chirp factor (typically in range (0..1) ) */ +) +{ + opus_int i; + silk_float cfac = chirp; + + for( i = 0; i < d - 1; i++ ) { + ar[ i ] *= cfac; + cfac *= chirp; + } + ar[ d - 1 ] *= cfac; +} diff --git a/extern/opus/silk/float/corrMatrix_FLP.c b/extern/opus/silk/float/corrMatrix_FLP.c new file mode 100644 index 0000000..eae6a1c --- /dev/null +++ b/extern/opus/silk/float/corrMatrix_FLP.c @@ -0,0 +1,93 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/********************************************************************** + * Correlation matrix computations for LS estimate. + **********************************************************************/ + +#include "main_FLP.h" + +/* Calculates correlation vector X'*t */ +void silk_corrVector_FLP( + const silk_float *x, /* I x vector [L+order-1] used to create X */ + const silk_float *t, /* I Target vector [L] */ + const opus_int L, /* I Length of vecors */ + const opus_int Order, /* I Max lag for correlation */ + silk_float *Xt /* O X'*t correlation vector [order] */ +) +{ + opus_int lag; + const silk_float *ptr1; + + ptr1 = &x[ Order - 1 ]; /* Points to first sample of column 0 of X: X[:,0] */ + for( lag = 0; lag < Order; lag++ ) { + /* Calculate X[:,lag]'*t */ + Xt[ lag ] = (silk_float)silk_inner_product_FLP( ptr1, t, L ); + ptr1--; /* Next column of X */ + } +} + +/* Calculates correlation matrix X'*X */ +void silk_corrMatrix_FLP( + const silk_float *x, /* I x vector [ L+order-1 ] used to create X */ + const opus_int L, /* I Length of vectors */ + const opus_int Order, /* I Max lag for correlation */ + silk_float *XX /* O X'*X correlation matrix [order x order] */ +) +{ + opus_int j, lag; + double energy; + const silk_float *ptr1, *ptr2; + + ptr1 = &x[ Order - 1 ]; /* First sample of column 0 of X */ + energy = silk_energy_FLP( ptr1, L ); /* X[:,0]'*X[:,0] */ + matrix_ptr( XX, 0, 0, Order ) = ( silk_float )energy; + for( j = 1; j < Order; j++ ) { + /* Calculate X[:,j]'*X[:,j] */ + energy += ptr1[ -j ] * ptr1[ -j ] - ptr1[ L - j ] * ptr1[ L - j ]; + matrix_ptr( XX, j, j, Order ) = ( silk_float )energy; + } + + ptr2 = &x[ Order - 2 ]; /* First sample of column 1 of X */ + for( lag = 1; lag < Order; lag++ ) { + /* Calculate X[:,0]'*X[:,lag] */ + energy = silk_inner_product_FLP( ptr1, ptr2, L ); + matrix_ptr( XX, lag, 0, Order ) = ( silk_float )energy; + matrix_ptr( XX, 0, lag, Order ) = ( silk_float )energy; + /* Calculate X[:,j]'*X[:,j + lag] */ + for( j = 1; j < ( Order - lag ); j++ ) { + energy += ptr1[ -j ] * ptr2[ -j ] - ptr1[ L - j ] * ptr2[ L - j ]; + matrix_ptr( XX, lag + j, j, Order ) = ( silk_float )energy; + matrix_ptr( XX, j, lag + j, Order ) = ( silk_float )energy; + } + ptr2--; /* Next column of X */ + } +} diff --git a/extern/opus/silk/float/encode_frame_FLP.c b/extern/opus/silk/float/encode_frame_FLP.c new file mode 100644 index 0000000..b029c3f --- /dev/null +++ b/extern/opus/silk/float/encode_frame_FLP.c @@ -0,0 +1,435 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "main_FLP.h" +#include "tuning_parameters.h" + +/* Low Bitrate Redundancy (LBRR) encoding. Reuse all parameters but encode with lower bitrate */ +static OPUS_INLINE void silk_LBRR_encode_FLP( + silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */ + const silk_float xfw[], /* I Input signal */ + opus_int condCoding /* I The type of conditional coding used so far for this frame */ +); + +void silk_encode_do_VAD_FLP( + silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + opus_int activity /* I Decision of Opus voice activity detector */ +) +{ + const opus_int activity_threshold = SILK_FIX_CONST( SPEECH_ACTIVITY_DTX_THRES, 8 ); + + /****************************/ + /* Voice Activity Detection */ + /****************************/ + silk_VAD_GetSA_Q8( &psEnc->sCmn, psEnc->sCmn.inputBuf + 1, psEnc->sCmn.arch ); + /* If Opus VAD is inactive and Silk VAD is active: lower Silk VAD to just under the threshold */ + if( activity == VAD_NO_ACTIVITY && psEnc->sCmn.speech_activity_Q8 >= activity_threshold ) { + psEnc->sCmn.speech_activity_Q8 = activity_threshold - 1; + } + + /**************************************************/ + /* Convert speech activity into VAD and DTX flags */ + /**************************************************/ + if( psEnc->sCmn.speech_activity_Q8 < activity_threshold ) { + psEnc->sCmn.indices.signalType = TYPE_NO_VOICE_ACTIVITY; + psEnc->sCmn.noSpeechCounter++; + if( psEnc->sCmn.noSpeechCounter <= NB_SPEECH_FRAMES_BEFORE_DTX ) { + psEnc->sCmn.inDTX = 0; + } else if( psEnc->sCmn.noSpeechCounter > MAX_CONSECUTIVE_DTX + NB_SPEECH_FRAMES_BEFORE_DTX ) { + psEnc->sCmn.noSpeechCounter = NB_SPEECH_FRAMES_BEFORE_DTX; + psEnc->sCmn.inDTX = 0; + } + psEnc->sCmn.VAD_flags[ psEnc->sCmn.nFramesEncoded ] = 0; + } else { + psEnc->sCmn.noSpeechCounter = 0; + psEnc->sCmn.inDTX = 0; + psEnc->sCmn.indices.signalType = TYPE_UNVOICED; + psEnc->sCmn.VAD_flags[ psEnc->sCmn.nFramesEncoded ] = 1; + } +} + +/****************/ +/* Encode frame */ +/****************/ +opus_int silk_encode_frame_FLP( + silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + opus_int32 *pnBytesOut, /* O Number of payload bytes; */ + ec_enc *psRangeEnc, /* I/O compressor data structure */ + opus_int condCoding, /* I The type of conditional coding to use */ + opus_int maxBits, /* I If > 0: maximum number of output bits */ + opus_int useCBR /* I Flag to force constant-bitrate operation */ +) +{ + silk_encoder_control_FLP sEncCtrl; + opus_int i, iter, maxIter, found_upper, found_lower, ret = 0; + silk_float *x_frame, *res_pitch_frame; + silk_float res_pitch[ 2 * MAX_FRAME_LENGTH + LA_PITCH_MAX ]; + ec_enc sRangeEnc_copy, sRangeEnc_copy2; + silk_nsq_state sNSQ_copy, sNSQ_copy2; + opus_int32 seed_copy, nBits, nBits_lower, nBits_upper, gainMult_lower, gainMult_upper; + opus_int32 gainsID, gainsID_lower, gainsID_upper; + opus_int16 gainMult_Q8; + opus_int16 ec_prevLagIndex_copy; + opus_int ec_prevSignalType_copy; + opus_int8 LastGainIndex_copy2; + opus_int32 pGains_Q16[ MAX_NB_SUBFR ]; + opus_uint8 ec_buf_copy[ 1275 ]; + opus_int gain_lock[ MAX_NB_SUBFR ] = {0}; + opus_int16 best_gain_mult[ MAX_NB_SUBFR ]; + opus_int best_sum[ MAX_NB_SUBFR ]; + + /* This is totally unnecessary but many compilers (including gcc) are too dumb to realise it */ + LastGainIndex_copy2 = nBits_lower = nBits_upper = gainMult_lower = gainMult_upper = 0; + + psEnc->sCmn.indices.Seed = psEnc->sCmn.frameCounter++ & 3; + + /**************************************************************/ + /* Set up Input Pointers, and insert frame in input buffer */ + /**************************************************************/ + /* pointers aligned with start of frame to encode */ + x_frame = psEnc->x_buf + psEnc->sCmn.ltp_mem_length; /* start of frame to encode */ + res_pitch_frame = res_pitch + psEnc->sCmn.ltp_mem_length; /* start of pitch LPC residual frame */ + + /***************************************/ + /* Ensure smooth bandwidth transitions */ + /***************************************/ + silk_LP_variable_cutoff( &psEnc->sCmn.sLP, psEnc->sCmn.inputBuf + 1, psEnc->sCmn.frame_length ); + + /*******************************************/ + /* Copy new frame to front of input buffer */ + /*******************************************/ + silk_short2float_array( x_frame + LA_SHAPE_MS * psEnc->sCmn.fs_kHz, psEnc->sCmn.inputBuf + 1, psEnc->sCmn.frame_length ); + + /* Add tiny signal to avoid high CPU load from denormalized floating point numbers */ + for( i = 0; i < 8; i++ ) { + x_frame[ LA_SHAPE_MS * psEnc->sCmn.fs_kHz + i * ( psEnc->sCmn.frame_length >> 3 ) ] += ( 1 - ( i & 2 ) ) * 1e-6f; + } + + if( !psEnc->sCmn.prefillFlag ) { + /*****************************************/ + /* Find pitch lags, initial LPC analysis */ + /*****************************************/ + silk_find_pitch_lags_FLP( psEnc, &sEncCtrl, res_pitch, x_frame, psEnc->sCmn.arch ); + + /************************/ + /* Noise shape analysis */ + /************************/ + silk_noise_shape_analysis_FLP( psEnc, &sEncCtrl, res_pitch_frame, x_frame ); + + /***************************************************/ + /* Find linear prediction coefficients (LPC + LTP) */ + /***************************************************/ + silk_find_pred_coefs_FLP( psEnc, &sEncCtrl, res_pitch_frame, x_frame, condCoding ); + + /****************************************/ + /* Process gains */ + /****************************************/ + silk_process_gains_FLP( psEnc, &sEncCtrl, condCoding ); + + /****************************************/ + /* Low Bitrate Redundant Encoding */ + /****************************************/ + silk_LBRR_encode_FLP( psEnc, &sEncCtrl, x_frame, condCoding ); + + /* Loop over quantizer and entroy coding to control bitrate */ + maxIter = 6; + gainMult_Q8 = SILK_FIX_CONST( 1, 8 ); + found_lower = 0; + found_upper = 0; + gainsID = silk_gains_ID( psEnc->sCmn.indices.GainsIndices, psEnc->sCmn.nb_subfr ); + gainsID_lower = -1; + gainsID_upper = -1; + /* Copy part of the input state */ + silk_memcpy( &sRangeEnc_copy, psRangeEnc, sizeof( ec_enc ) ); + silk_memcpy( &sNSQ_copy, &psEnc->sCmn.sNSQ, sizeof( silk_nsq_state ) ); + seed_copy = psEnc->sCmn.indices.Seed; + ec_prevLagIndex_copy = psEnc->sCmn.ec_prevLagIndex; + ec_prevSignalType_copy = psEnc->sCmn.ec_prevSignalType; + for( iter = 0; ; iter++ ) { + if( gainsID == gainsID_lower ) { + nBits = nBits_lower; + } else if( gainsID == gainsID_upper ) { + nBits = nBits_upper; + } else { + /* Restore part of the input state */ + if( iter > 0 ) { + silk_memcpy( psRangeEnc, &sRangeEnc_copy, sizeof( ec_enc ) ); + silk_memcpy( &psEnc->sCmn.sNSQ, &sNSQ_copy, sizeof( silk_nsq_state ) ); + psEnc->sCmn.indices.Seed = seed_copy; + psEnc->sCmn.ec_prevLagIndex = ec_prevLagIndex_copy; + psEnc->sCmn.ec_prevSignalType = ec_prevSignalType_copy; + } + + /*****************************************/ + /* Noise shaping quantization */ + /*****************************************/ + silk_NSQ_wrapper_FLP( psEnc, &sEncCtrl, &psEnc->sCmn.indices, &psEnc->sCmn.sNSQ, psEnc->sCmn.pulses, x_frame ); + + if ( iter == maxIter && !found_lower ) { + silk_memcpy( &sRangeEnc_copy2, psRangeEnc, sizeof( ec_enc ) ); + } + + /****************************************/ + /* Encode Parameters */ + /****************************************/ + silk_encode_indices( &psEnc->sCmn, psRangeEnc, psEnc->sCmn.nFramesEncoded, 0, condCoding ); + + /****************************************/ + /* Encode Excitation Signal */ + /****************************************/ + silk_encode_pulses( psRangeEnc, psEnc->sCmn.indices.signalType, psEnc->sCmn.indices.quantOffsetType, + psEnc->sCmn.pulses, psEnc->sCmn.frame_length ); + + nBits = ec_tell( psRangeEnc ); + + /* If we still bust after the last iteration, do some damage control. */ + if ( iter == maxIter && !found_lower && nBits > maxBits ) { + silk_memcpy( psRangeEnc, &sRangeEnc_copy2, sizeof( ec_enc ) ); + + /* Keep gains the same as the last frame. */ + psEnc->sShape.LastGainIndex = sEncCtrl.lastGainIndexPrev; + for ( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) { + psEnc->sCmn.indices.GainsIndices[ i ] = 4; + } + if (condCoding != CODE_CONDITIONALLY) { + psEnc->sCmn.indices.GainsIndices[ 0 ] = sEncCtrl.lastGainIndexPrev; + } + psEnc->sCmn.ec_prevLagIndex = ec_prevLagIndex_copy; + psEnc->sCmn.ec_prevSignalType = ec_prevSignalType_copy; + /* Clear all pulses. */ + for ( i = 0; i < psEnc->sCmn.frame_length; i++ ) { + psEnc->sCmn.pulses[ i ] = 0; + } + + silk_encode_indices( &psEnc->sCmn, psRangeEnc, psEnc->sCmn.nFramesEncoded, 0, condCoding ); + + silk_encode_pulses( psRangeEnc, psEnc->sCmn.indices.signalType, psEnc->sCmn.indices.quantOffsetType, + psEnc->sCmn.pulses, psEnc->sCmn.frame_length ); + + nBits = ec_tell( psRangeEnc ); + } + + if( useCBR == 0 && iter == 0 && nBits <= maxBits ) { + break; + } + } + + if( iter == maxIter ) { + if( found_lower && ( gainsID == gainsID_lower || nBits > maxBits ) ) { + /* Restore output state from earlier iteration that did meet the bitrate budget */ + silk_memcpy( psRangeEnc, &sRangeEnc_copy2, sizeof( ec_enc ) ); + celt_assert( sRangeEnc_copy2.offs <= 1275 ); + silk_memcpy( psRangeEnc->buf, ec_buf_copy, sRangeEnc_copy2.offs ); + silk_memcpy( &psEnc->sCmn.sNSQ, &sNSQ_copy2, sizeof( silk_nsq_state ) ); + psEnc->sShape.LastGainIndex = LastGainIndex_copy2; + } + break; + } + + if( nBits > maxBits ) { + if( found_lower == 0 && iter >= 2 ) { + /* Adjust the quantizer's rate/distortion tradeoff and discard previous "upper" results */ + sEncCtrl.Lambda = silk_max_float(sEncCtrl.Lambda*1.5f, 1.5f); + /* Reducing dithering can help us hit the target. */ + psEnc->sCmn.indices.quantOffsetType = 0; + found_upper = 0; + gainsID_upper = -1; + } else { + found_upper = 1; + nBits_upper = nBits; + gainMult_upper = gainMult_Q8; + gainsID_upper = gainsID; + } + } else if( nBits < maxBits - 5 ) { + found_lower = 1; + nBits_lower = nBits; + gainMult_lower = gainMult_Q8; + if( gainsID != gainsID_lower ) { + gainsID_lower = gainsID; + /* Copy part of the output state */ + silk_memcpy( &sRangeEnc_copy2, psRangeEnc, sizeof( ec_enc ) ); + celt_assert( psRangeEnc->offs <= 1275 ); + silk_memcpy( ec_buf_copy, psRangeEnc->buf, psRangeEnc->offs ); + silk_memcpy( &sNSQ_copy2, &psEnc->sCmn.sNSQ, sizeof( silk_nsq_state ) ); + LastGainIndex_copy2 = psEnc->sShape.LastGainIndex; + } + } else { + /* Within 5 bits of budget: close enough */ + break; + } + + if ( !found_lower && nBits > maxBits ) { + int j; + for ( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) { + int sum=0; + for ( j = i*psEnc->sCmn.subfr_length; j < (i+1)*psEnc->sCmn.subfr_length; j++ ) { + sum += abs( psEnc->sCmn.pulses[j] ); + } + if ( iter == 0 || (sum < best_sum[i] && !gain_lock[i]) ) { + best_sum[i] = sum; + best_gain_mult[i] = gainMult_Q8; + } else { + gain_lock[i] = 1; + } + } + } + if( ( found_lower & found_upper ) == 0 ) { + /* Adjust gain according to high-rate rate/distortion curve */ + if( nBits > maxBits ) { + if (gainMult_Q8 < 16384) { + gainMult_Q8 *= 2; + } else { + gainMult_Q8 = 32767; + } + } else { + opus_int32 gain_factor_Q16; + gain_factor_Q16 = silk_log2lin( silk_LSHIFT( nBits - maxBits, 7 ) / psEnc->sCmn.frame_length + SILK_FIX_CONST( 16, 7 ) ); + gainMult_Q8 = silk_SMULWB( gain_factor_Q16, gainMult_Q8 ); + } + } else { + /* Adjust gain by interpolating */ + gainMult_Q8 = gainMult_lower + ( ( gainMult_upper - gainMult_lower ) * ( maxBits - nBits_lower ) ) / ( nBits_upper - nBits_lower ); + /* New gain multplier must be between 25% and 75% of old range (note that gainMult_upper < gainMult_lower) */ + if( gainMult_Q8 > silk_ADD_RSHIFT32( gainMult_lower, gainMult_upper - gainMult_lower, 2 ) ) { + gainMult_Q8 = silk_ADD_RSHIFT32( gainMult_lower, gainMult_upper - gainMult_lower, 2 ); + } else + if( gainMult_Q8 < silk_SUB_RSHIFT32( gainMult_upper, gainMult_upper - gainMult_lower, 2 ) ) { + gainMult_Q8 = silk_SUB_RSHIFT32( gainMult_upper, gainMult_upper - gainMult_lower, 2 ); + } + } + + for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) { + opus_int16 tmp; + if ( gain_lock[i] ) { + tmp = best_gain_mult[i]; + } else { + tmp = gainMult_Q8; + } + pGains_Q16[ i ] = silk_LSHIFT_SAT32( silk_SMULWB( sEncCtrl.GainsUnq_Q16[ i ], tmp ), 8 ); + } + + /* Quantize gains */ + psEnc->sShape.LastGainIndex = sEncCtrl.lastGainIndexPrev; + silk_gains_quant( psEnc->sCmn.indices.GainsIndices, pGains_Q16, + &psEnc->sShape.LastGainIndex, condCoding == CODE_CONDITIONALLY, psEnc->sCmn.nb_subfr ); + + /* Unique identifier of gains vector */ + gainsID = silk_gains_ID( psEnc->sCmn.indices.GainsIndices, psEnc->sCmn.nb_subfr ); + + /* Overwrite unquantized gains with quantized gains and convert back to Q0 from Q16 */ + for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) { + sEncCtrl.Gains[ i ] = pGains_Q16[ i ] / 65536.0f; + } + } + } + + /* Update input buffer */ + silk_memmove( psEnc->x_buf, &psEnc->x_buf[ psEnc->sCmn.frame_length ], + ( psEnc->sCmn.ltp_mem_length + LA_SHAPE_MS * psEnc->sCmn.fs_kHz ) * sizeof( silk_float ) ); + + /* Exit without entropy coding */ + if( psEnc->sCmn.prefillFlag ) { + /* No payload */ + *pnBytesOut = 0; + return ret; + } + + /* Parameters needed for next frame */ + psEnc->sCmn.prevLag = sEncCtrl.pitchL[ psEnc->sCmn.nb_subfr - 1 ]; + psEnc->sCmn.prevSignalType = psEnc->sCmn.indices.signalType; + + /****************************************/ + /* Finalize payload */ + /****************************************/ + psEnc->sCmn.first_frame_after_reset = 0; + /* Payload size */ + *pnBytesOut = silk_RSHIFT( ec_tell( psRangeEnc ) + 7, 3 ); + + return ret; +} + +/* Low-Bitrate Redundancy (LBRR) encoding. Reuse all parameters but encode excitation at lower bitrate */ +static OPUS_INLINE void silk_LBRR_encode_FLP( + silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */ + const silk_float xfw[], /* I Input signal */ + opus_int condCoding /* I The type of conditional coding used so far for this frame */ +) +{ + opus_int k; + opus_int32 Gains_Q16[ MAX_NB_SUBFR ]; + silk_float TempGains[ MAX_NB_SUBFR ]; + SideInfoIndices *psIndices_LBRR = &psEnc->sCmn.indices_LBRR[ psEnc->sCmn.nFramesEncoded ]; + silk_nsq_state sNSQ_LBRR; + + /*******************************************/ + /* Control use of inband LBRR */ + /*******************************************/ + if( psEnc->sCmn.LBRR_enabled && psEnc->sCmn.speech_activity_Q8 > SILK_FIX_CONST( LBRR_SPEECH_ACTIVITY_THRES, 8 ) ) { + psEnc->sCmn.LBRR_flags[ psEnc->sCmn.nFramesEncoded ] = 1; + + /* Copy noise shaping quantizer state and quantization indices from regular encoding */ + silk_memcpy( &sNSQ_LBRR, &psEnc->sCmn.sNSQ, sizeof( silk_nsq_state ) ); + silk_memcpy( psIndices_LBRR, &psEnc->sCmn.indices, sizeof( SideInfoIndices ) ); + + /* Save original gains */ + silk_memcpy( TempGains, psEncCtrl->Gains, psEnc->sCmn.nb_subfr * sizeof( silk_float ) ); + + if( psEnc->sCmn.nFramesEncoded == 0 || psEnc->sCmn.LBRR_flags[ psEnc->sCmn.nFramesEncoded - 1 ] == 0 ) { + /* First frame in packet or previous frame not LBRR coded */ + psEnc->sCmn.LBRRprevLastGainIndex = psEnc->sShape.LastGainIndex; + + /* Increase Gains to get target LBRR rate */ + psIndices_LBRR->GainsIndices[ 0 ] += psEnc->sCmn.LBRR_GainIncreases; + psIndices_LBRR->GainsIndices[ 0 ] = silk_min_int( psIndices_LBRR->GainsIndices[ 0 ], N_LEVELS_QGAIN - 1 ); + } + + /* Decode to get gains in sync with decoder */ + silk_gains_dequant( Gains_Q16, psIndices_LBRR->GainsIndices, + &psEnc->sCmn.LBRRprevLastGainIndex, condCoding == CODE_CONDITIONALLY, psEnc->sCmn.nb_subfr ); + + /* Overwrite unquantized gains with quantized gains and convert back to Q0 from Q16 */ + for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) { + psEncCtrl->Gains[ k ] = Gains_Q16[ k ] * ( 1.0f / 65536.0f ); + } + + /*****************************************/ + /* Noise shaping quantization */ + /*****************************************/ + silk_NSQ_wrapper_FLP( psEnc, psEncCtrl, psIndices_LBRR, &sNSQ_LBRR, + psEnc->sCmn.pulses_LBRR[ psEnc->sCmn.nFramesEncoded ], xfw ); + + /* Restore original gains */ + silk_memcpy( psEncCtrl->Gains, TempGains, psEnc->sCmn.nb_subfr * sizeof( silk_float ) ); + } +} diff --git a/extern/opus/silk/float/energy_FLP.c b/extern/opus/silk/float/energy_FLP.c new file mode 100644 index 0000000..7bc7173 --- /dev/null +++ b/extern/opus/silk/float/energy_FLP.c @@ -0,0 +1,59 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FLP.h" + +/* sum of squares of a silk_float array, with result as double */ +double silk_energy_FLP( + const silk_float *data, + opus_int dataSize +) +{ + opus_int i; + double result; + + /* 4x unrolled loop */ + result = 0.0; + for( i = 0; i < dataSize - 3; i += 4 ) { + result += data[ i + 0 ] * (double)data[ i + 0 ] + + data[ i + 1 ] * (double)data[ i + 1 ] + + data[ i + 2 ] * (double)data[ i + 2 ] + + data[ i + 3 ] * (double)data[ i + 3 ]; + } + + /* add any remaining products */ + for( ; i < dataSize; i++ ) { + result += data[ i ] * (double)data[ i ]; + } + + silk_assert( result >= 0.0 ); + return result; +} diff --git a/extern/opus/silk/float/find_LPC_FLP.c b/extern/opus/silk/float/find_LPC_FLP.c new file mode 100644 index 0000000..fa3ffe7 --- /dev/null +++ b/extern/opus/silk/float/find_LPC_FLP.c @@ -0,0 +1,104 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "define.h" +#include "main_FLP.h" +#include "tuning_parameters.h" + +/* LPC analysis */ +void silk_find_LPC_FLP( + silk_encoder_state *psEncC, /* I/O Encoder state */ + opus_int16 NLSF_Q15[], /* O NLSFs */ + const silk_float x[], /* I Input signal */ + const silk_float minInvGain /* I Inverse of max prediction gain */ +) +{ + opus_int k, subfr_length; + silk_float a[ MAX_LPC_ORDER ]; + + /* Used only for NLSF interpolation */ + silk_float res_nrg, res_nrg_2nd, res_nrg_interp; + opus_int16 NLSF0_Q15[ MAX_LPC_ORDER ]; + silk_float a_tmp[ MAX_LPC_ORDER ]; + silk_float LPC_res[ MAX_FRAME_LENGTH + MAX_NB_SUBFR * MAX_LPC_ORDER ]; + + subfr_length = psEncC->subfr_length + psEncC->predictLPCOrder; + + /* Default: No interpolation */ + psEncC->indices.NLSFInterpCoef_Q2 = 4; + + /* Burg AR analysis for the full frame */ + res_nrg = silk_burg_modified_FLP( a, x, minInvGain, subfr_length, psEncC->nb_subfr, psEncC->predictLPCOrder ); + + if( psEncC->useInterpolatedNLSFs && !psEncC->first_frame_after_reset && psEncC->nb_subfr == MAX_NB_SUBFR ) { + /* Optimal solution for last 10 ms; subtract residual energy here, as that's easier than */ + /* adding it to the residual energy of the first 10 ms in each iteration of the search below */ + res_nrg -= silk_burg_modified_FLP( a_tmp, x + ( MAX_NB_SUBFR / 2 ) * subfr_length, minInvGain, subfr_length, MAX_NB_SUBFR / 2, psEncC->predictLPCOrder ); + + /* Convert to NLSFs */ + silk_A2NLSF_FLP( NLSF_Q15, a_tmp, psEncC->predictLPCOrder ); + + /* Search over interpolation indices to find the one with lowest residual energy */ + res_nrg_2nd = silk_float_MAX; + for( k = 3; k >= 0; k-- ) { + /* Interpolate NLSFs for first half */ + silk_interpolate( NLSF0_Q15, psEncC->prev_NLSFq_Q15, NLSF_Q15, k, psEncC->predictLPCOrder ); + + /* Convert to LPC for residual energy evaluation */ + silk_NLSF2A_FLP( a_tmp, NLSF0_Q15, psEncC->predictLPCOrder, psEncC->arch ); + + /* Calculate residual energy with LSF interpolation */ + silk_LPC_analysis_filter_FLP( LPC_res, a_tmp, x, 2 * subfr_length, psEncC->predictLPCOrder ); + res_nrg_interp = (silk_float)( + silk_energy_FLP( LPC_res + psEncC->predictLPCOrder, subfr_length - psEncC->predictLPCOrder ) + + silk_energy_FLP( LPC_res + psEncC->predictLPCOrder + subfr_length, subfr_length - psEncC->predictLPCOrder ) ); + + /* Determine whether current interpolated NLSFs are best so far */ + if( res_nrg_interp < res_nrg ) { + /* Interpolation has lower residual energy */ + res_nrg = res_nrg_interp; + psEncC->indices.NLSFInterpCoef_Q2 = (opus_int8)k; + } else if( res_nrg_interp > res_nrg_2nd ) { + /* No reason to continue iterating - residual energies will continue to climb */ + break; + } + res_nrg_2nd = res_nrg_interp; + } + } + + if( psEncC->indices.NLSFInterpCoef_Q2 == 4 ) { + /* NLSF interpolation is currently inactive, calculate NLSFs from full frame AR coefficients */ + silk_A2NLSF_FLP( NLSF_Q15, a, psEncC->predictLPCOrder ); + } + + celt_assert( psEncC->indices.NLSFInterpCoef_Q2 == 4 || + ( psEncC->useInterpolatedNLSFs && !psEncC->first_frame_after_reset && psEncC->nb_subfr == MAX_NB_SUBFR ) ); +} diff --git a/extern/opus/silk/float/find_LTP_FLP.c b/extern/opus/silk/float/find_LTP_FLP.c new file mode 100644 index 0000000..f970649 --- /dev/null +++ b/extern/opus/silk/float/find_LTP_FLP.c @@ -0,0 +1,64 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FLP.h" +#include "tuning_parameters.h" + +void silk_find_LTP_FLP( + silk_float XX[ MAX_NB_SUBFR * LTP_ORDER * LTP_ORDER ], /* O Weight for LTP quantization */ + silk_float xX[ MAX_NB_SUBFR * LTP_ORDER ], /* O Weight for LTP quantization */ + const silk_float r_ptr[], /* I LPC residual */ + const opus_int lag[ MAX_NB_SUBFR ], /* I LTP lags */ + const opus_int subfr_length, /* I Subframe length */ + const opus_int nb_subfr /* I number of subframes */ +) +{ + opus_int k; + silk_float *xX_ptr, *XX_ptr; + const silk_float *lag_ptr; + silk_float xx, temp; + + xX_ptr = xX; + XX_ptr = XX; + for( k = 0; k < nb_subfr; k++ ) { + lag_ptr = r_ptr - ( lag[ k ] + LTP_ORDER / 2 ); + silk_corrMatrix_FLP( lag_ptr, subfr_length, LTP_ORDER, XX_ptr ); + silk_corrVector_FLP( lag_ptr, r_ptr, subfr_length, LTP_ORDER, xX_ptr ); + xx = ( silk_float )silk_energy_FLP( r_ptr, subfr_length + LTP_ORDER ); + temp = 1.0f / silk_max( xx, LTP_CORR_INV_MAX * 0.5f * ( XX_ptr[ 0 ] + XX_ptr[ 24 ] ) + 1.0f ); + silk_scale_vector_FLP( XX_ptr, temp, LTP_ORDER * LTP_ORDER ); + silk_scale_vector_FLP( xX_ptr, temp, LTP_ORDER ); + + r_ptr += subfr_length; + XX_ptr += LTP_ORDER * LTP_ORDER; + xX_ptr += LTP_ORDER; + } +} diff --git a/extern/opus/silk/float/find_pitch_lags_FLP.c b/extern/opus/silk/float/find_pitch_lags_FLP.c new file mode 100644 index 0000000..dedbcd2 --- /dev/null +++ b/extern/opus/silk/float/find_pitch_lags_FLP.c @@ -0,0 +1,132 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "main_FLP.h" +#include "tuning_parameters.h" + +void silk_find_pitch_lags_FLP( + silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */ + silk_float res[], /* O Residual */ + const silk_float x[], /* I Speech signal */ + int arch /* I Run-time architecture */ +) +{ + opus_int buf_len; + silk_float thrhld, res_nrg; + const silk_float *x_buf_ptr, *x_buf; + silk_float auto_corr[ MAX_FIND_PITCH_LPC_ORDER + 1 ]; + silk_float A[ MAX_FIND_PITCH_LPC_ORDER ]; + silk_float refl_coef[ MAX_FIND_PITCH_LPC_ORDER ]; + silk_float Wsig[ FIND_PITCH_LPC_WIN_MAX ]; + silk_float *Wsig_ptr; + + /******************************************/ + /* Set up buffer lengths etc based on Fs */ + /******************************************/ + buf_len = psEnc->sCmn.la_pitch + psEnc->sCmn.frame_length + psEnc->sCmn.ltp_mem_length; + + /* Safety check */ + celt_assert( buf_len >= psEnc->sCmn.pitch_LPC_win_length ); + + x_buf = x - psEnc->sCmn.ltp_mem_length; + + /******************************************/ + /* Estimate LPC AR coeficients */ + /******************************************/ + + /* Calculate windowed signal */ + + /* First LA_LTP samples */ + x_buf_ptr = x_buf + buf_len - psEnc->sCmn.pitch_LPC_win_length; + Wsig_ptr = Wsig; + silk_apply_sine_window_FLP( Wsig_ptr, x_buf_ptr, 1, psEnc->sCmn.la_pitch ); + + /* Middle non-windowed samples */ + Wsig_ptr += psEnc->sCmn.la_pitch; + x_buf_ptr += psEnc->sCmn.la_pitch; + silk_memcpy( Wsig_ptr, x_buf_ptr, ( psEnc->sCmn.pitch_LPC_win_length - ( psEnc->sCmn.la_pitch << 1 ) ) * sizeof( silk_float ) ); + + /* Last LA_LTP samples */ + Wsig_ptr += psEnc->sCmn.pitch_LPC_win_length - ( psEnc->sCmn.la_pitch << 1 ); + x_buf_ptr += psEnc->sCmn.pitch_LPC_win_length - ( psEnc->sCmn.la_pitch << 1 ); + silk_apply_sine_window_FLP( Wsig_ptr, x_buf_ptr, 2, psEnc->sCmn.la_pitch ); + + /* Calculate autocorrelation sequence */ + silk_autocorrelation_FLP( auto_corr, Wsig, psEnc->sCmn.pitch_LPC_win_length, psEnc->sCmn.pitchEstimationLPCOrder + 1 ); + + /* Add white noise, as a fraction of the energy */ + auto_corr[ 0 ] += auto_corr[ 0 ] * FIND_PITCH_WHITE_NOISE_FRACTION + 1; + + /* Calculate the reflection coefficients using Schur */ + res_nrg = silk_schur_FLP( refl_coef, auto_corr, psEnc->sCmn.pitchEstimationLPCOrder ); + + /* Prediction gain */ + psEncCtrl->predGain = auto_corr[ 0 ] / silk_max_float( res_nrg, 1.0f ); + + /* Convert reflection coefficients to prediction coefficients */ + silk_k2a_FLP( A, refl_coef, psEnc->sCmn.pitchEstimationLPCOrder ); + + /* Bandwidth expansion */ + silk_bwexpander_FLP( A, psEnc->sCmn.pitchEstimationLPCOrder, FIND_PITCH_BANDWIDTH_EXPANSION ); + + /*****************************************/ + /* LPC analysis filtering */ + /*****************************************/ + silk_LPC_analysis_filter_FLP( res, A, x_buf, buf_len, psEnc->sCmn.pitchEstimationLPCOrder ); + + if( psEnc->sCmn.indices.signalType != TYPE_NO_VOICE_ACTIVITY && psEnc->sCmn.first_frame_after_reset == 0 ) { + /* Threshold for pitch estimator */ + thrhld = 0.6f; + thrhld -= 0.004f * psEnc->sCmn.pitchEstimationLPCOrder; + thrhld -= 0.1f * psEnc->sCmn.speech_activity_Q8 * ( 1.0f / 256.0f ); + thrhld -= 0.15f * (psEnc->sCmn.prevSignalType >> 1); + thrhld -= 0.1f * psEnc->sCmn.input_tilt_Q15 * ( 1.0f / 32768.0f ); + + /*****************************************/ + /* Call Pitch estimator */ + /*****************************************/ + if( silk_pitch_analysis_core_FLP( res, psEncCtrl->pitchL, &psEnc->sCmn.indices.lagIndex, + &psEnc->sCmn.indices.contourIndex, &psEnc->LTPCorr, psEnc->sCmn.prevLag, psEnc->sCmn.pitchEstimationThreshold_Q16 / 65536.0f, + thrhld, psEnc->sCmn.fs_kHz, psEnc->sCmn.pitchEstimationComplexity, psEnc->sCmn.nb_subfr, arch ) == 0 ) + { + psEnc->sCmn.indices.signalType = TYPE_VOICED; + } else { + psEnc->sCmn.indices.signalType = TYPE_UNVOICED; + } + } else { + silk_memset( psEncCtrl->pitchL, 0, sizeof( psEncCtrl->pitchL ) ); + psEnc->sCmn.indices.lagIndex = 0; + psEnc->sCmn.indices.contourIndex = 0; + psEnc->LTPCorr = 0; + } +} diff --git a/extern/opus/silk/float/find_pred_coefs_FLP.c b/extern/opus/silk/float/find_pred_coefs_FLP.c new file mode 100644 index 0000000..dcf7c52 --- /dev/null +++ b/extern/opus/silk/float/find_pred_coefs_FLP.c @@ -0,0 +1,116 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FLP.h" + +/* Find LPC and LTP coefficients */ +void silk_find_pred_coefs_FLP( + silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */ + const silk_float res_pitch[], /* I Residual from pitch analysis */ + const silk_float x[], /* I Speech signal */ + opus_int condCoding /* I The type of conditional coding to use */ +) +{ + opus_int i; + silk_float XXLTP[ MAX_NB_SUBFR * LTP_ORDER * LTP_ORDER ]; + silk_float xXLTP[ MAX_NB_SUBFR * LTP_ORDER ]; + silk_float invGains[ MAX_NB_SUBFR ]; + opus_int16 NLSF_Q15[ MAX_LPC_ORDER ]; + const silk_float *x_ptr; + silk_float *x_pre_ptr, LPC_in_pre[ MAX_NB_SUBFR * MAX_LPC_ORDER + MAX_FRAME_LENGTH ]; + silk_float minInvGain; + + /* Weighting for weighted least squares */ + for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) { + silk_assert( psEncCtrl->Gains[ i ] > 0.0f ); + invGains[ i ] = 1.0f / psEncCtrl->Gains[ i ]; + } + + if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) { + /**********/ + /* VOICED */ + /**********/ + celt_assert( psEnc->sCmn.ltp_mem_length - psEnc->sCmn.predictLPCOrder >= psEncCtrl->pitchL[ 0 ] + LTP_ORDER / 2 ); + + /* LTP analysis */ + silk_find_LTP_FLP( XXLTP, xXLTP, res_pitch, psEncCtrl->pitchL, psEnc->sCmn.subfr_length, psEnc->sCmn.nb_subfr ); + + /* Quantize LTP gain parameters */ + silk_quant_LTP_gains_FLP( psEncCtrl->LTPCoef, psEnc->sCmn.indices.LTPIndex, &psEnc->sCmn.indices.PERIndex, + &psEnc->sCmn.sum_log_gain_Q7, &psEncCtrl->LTPredCodGain, XXLTP, xXLTP, psEnc->sCmn.subfr_length, psEnc->sCmn.nb_subfr, psEnc->sCmn.arch ); + + /* Control LTP scaling */ + silk_LTP_scale_ctrl_FLP( psEnc, psEncCtrl, condCoding ); + + /* Create LTP residual */ + silk_LTP_analysis_filter_FLP( LPC_in_pre, x - psEnc->sCmn.predictLPCOrder, psEncCtrl->LTPCoef, + psEncCtrl->pitchL, invGains, psEnc->sCmn.subfr_length, psEnc->sCmn.nb_subfr, psEnc->sCmn.predictLPCOrder ); + } else { + /************/ + /* UNVOICED */ + /************/ + /* Create signal with prepended subframes, scaled by inverse gains */ + x_ptr = x - psEnc->sCmn.predictLPCOrder; + x_pre_ptr = LPC_in_pre; + for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) { + silk_scale_copy_vector_FLP( x_pre_ptr, x_ptr, invGains[ i ], + psEnc->sCmn.subfr_length + psEnc->sCmn.predictLPCOrder ); + x_pre_ptr += psEnc->sCmn.subfr_length + psEnc->sCmn.predictLPCOrder; + x_ptr += psEnc->sCmn.subfr_length; + } + silk_memset( psEncCtrl->LTPCoef, 0, psEnc->sCmn.nb_subfr * LTP_ORDER * sizeof( silk_float ) ); + psEncCtrl->LTPredCodGain = 0.0f; + psEnc->sCmn.sum_log_gain_Q7 = 0; + } + + /* Limit on total predictive coding gain */ + if( psEnc->sCmn.first_frame_after_reset ) { + minInvGain = 1.0f / MAX_PREDICTION_POWER_GAIN_AFTER_RESET; + } else { + minInvGain = (silk_float)pow( 2, psEncCtrl->LTPredCodGain / 3 ) / MAX_PREDICTION_POWER_GAIN; + minInvGain /= 0.25f + 0.75f * psEncCtrl->coding_quality; + } + + /* LPC_in_pre contains the LTP-filtered input for voiced, and the unfiltered input for unvoiced */ + silk_find_LPC_FLP( &psEnc->sCmn, NLSF_Q15, LPC_in_pre, minInvGain ); + + /* Quantize LSFs */ + silk_process_NLSFs_FLP( &psEnc->sCmn, psEncCtrl->PredCoef, NLSF_Q15, psEnc->sCmn.prev_NLSFq_Q15 ); + + /* Calculate residual energy using quantized LPC coefficients */ + silk_residual_energy_FLP( psEncCtrl->ResNrg, LPC_in_pre, psEncCtrl->PredCoef, psEncCtrl->Gains, + psEnc->sCmn.subfr_length, psEnc->sCmn.nb_subfr, psEnc->sCmn.predictLPCOrder ); + + /* Copy to prediction struct for use in next frame for interpolation */ + silk_memcpy( psEnc->sCmn.prev_NLSFq_Q15, NLSF_Q15, sizeof( psEnc->sCmn.prev_NLSFq_Q15 ) ); +} + diff --git a/extern/opus/silk/float/inner_product_FLP.c b/extern/opus/silk/float/inner_product_FLP.c new file mode 100644 index 0000000..cdd39d2 --- /dev/null +++ b/extern/opus/silk/float/inner_product_FLP.c @@ -0,0 +1,59 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FLP.h" + +/* inner product of two silk_float arrays, with result as double */ +double silk_inner_product_FLP( + const silk_float *data1, + const silk_float *data2, + opus_int dataSize +) +{ + opus_int i; + double result; + + /* 4x unrolled loop */ + result = 0.0; + for( i = 0; i < dataSize - 3; i += 4 ) { + result += data1[ i + 0 ] * (double)data2[ i + 0 ] + + data1[ i + 1 ] * (double)data2[ i + 1 ] + + data1[ i + 2 ] * (double)data2[ i + 2 ] + + data1[ i + 3 ] * (double)data2[ i + 3 ]; + } + + /* add any remaining products */ + for( ; i < dataSize; i++ ) { + result += data1[ i ] * (double)data2[ i ]; + } + + return result; +} diff --git a/extern/opus/silk/float/k2a_FLP.c b/extern/opus/silk/float/k2a_FLP.c new file mode 100644 index 0000000..1448008 --- /dev/null +++ b/extern/opus/silk/float/k2a_FLP.c @@ -0,0 +1,54 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FLP.h" + +/* step up function, converts reflection coefficients to prediction coefficients */ +void silk_k2a_FLP( + silk_float *A, /* O prediction coefficients [order] */ + const silk_float *rc, /* I reflection coefficients [order] */ + opus_int32 order /* I prediction order */ +) +{ + opus_int k, n; + silk_float rck, tmp1, tmp2; + + for( k = 0; k < order; k++ ) { + rck = rc[ k ]; + for( n = 0; n < (k + 1) >> 1; n++ ) { + tmp1 = A[ n ]; + tmp2 = A[ k - n - 1 ]; + A[ n ] = tmp1 + tmp2 * rck; + A[ k - n - 1 ] = tmp2 + tmp1 * rck; + } + A[ k ] = -rck; + } +} diff --git a/extern/opus/silk/float/main_FLP.h b/extern/opus/silk/float/main_FLP.h new file mode 100644 index 0000000..5dc0ccf --- /dev/null +++ b/extern/opus/silk/float/main_FLP.h @@ -0,0 +1,286 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifndef SILK_MAIN_FLP_H +#define SILK_MAIN_FLP_H + +#include "SigProc_FLP.h" +#include "SigProc_FIX.h" +#include "structs_FLP.h" +#include "main.h" +#include "define.h" +#include "debug.h" +#include "entenc.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +#define silk_encoder_state_Fxx silk_encoder_state_FLP +#define silk_encode_do_VAD_Fxx silk_encode_do_VAD_FLP +#define silk_encode_frame_Fxx silk_encode_frame_FLP + +/*********************/ +/* Encoder Functions */ +/*********************/ + +/* High-pass filter with cutoff frequency adaptation based on pitch lag statistics */ +void silk_HP_variable_cutoff( + silk_encoder_state_Fxx state_Fxx[] /* I/O Encoder states */ +); + +/* Encoder main function */ +void silk_encode_do_VAD_FLP( + silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + opus_int activity /* I Decision of Opus voice activity detector */ +); + +/* Encoder main function */ +opus_int silk_encode_frame_FLP( + silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + opus_int32 *pnBytesOut, /* O Number of payload bytes; */ + ec_enc *psRangeEnc, /* I/O compressor data structure */ + opus_int condCoding, /* I The type of conditional coding to use */ + opus_int maxBits, /* I If > 0: maximum number of output bits */ + opus_int useCBR /* I Flag to force constant-bitrate operation */ +); + +/* Initializes the Silk encoder state */ +opus_int silk_init_encoder( + silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + int arch /* I Run-tim architecture */ +); + +/* Control the Silk encoder */ +opus_int silk_control_encoder( + silk_encoder_state_FLP *psEnc, /* I/O Pointer to Silk encoder state FLP */ + silk_EncControlStruct *encControl, /* I Control structure */ + const opus_int allow_bw_switch, /* I Flag to allow switching audio bandwidth */ + const opus_int channelNb, /* I Channel number */ + const opus_int force_fs_kHz +); + +/**************************/ +/* Noise shaping analysis */ +/**************************/ +/* Compute noise shaping coefficients and initial gain values */ +void silk_noise_shape_analysis_FLP( + silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */ + const silk_float *pitch_res, /* I LPC residual from pitch analysis */ + const silk_float *x /* I Input signal [frame_length + la_shape] */ +); + +/* Autocorrelations for a warped frequency axis */ +void silk_warped_autocorrelation_FLP( + silk_float *corr, /* O Result [order + 1] */ + const silk_float *input, /* I Input data to correlate */ + const silk_float warping, /* I Warping coefficient */ + const opus_int length, /* I Length of input */ + const opus_int order /* I Correlation order (even) */ +); + +/* Calculation of LTP state scaling */ +void silk_LTP_scale_ctrl_FLP( + silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */ + opus_int condCoding /* I The type of conditional coding to use */ +); + +/**********************************************/ +/* Prediction Analysis */ +/**********************************************/ +/* Find pitch lags */ +void silk_find_pitch_lags_FLP( + silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */ + silk_float res[], /* O Residual */ + const silk_float x[], /* I Speech signal */ + int arch /* I Run-time architecture */ +); + +/* Find LPC and LTP coefficients */ +void silk_find_pred_coefs_FLP( + silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */ + const silk_float res_pitch[], /* I Residual from pitch analysis */ + const silk_float x[], /* I Speech signal */ + opus_int condCoding /* I The type of conditional coding to use */ +); + +/* LPC analysis */ +void silk_find_LPC_FLP( + silk_encoder_state *psEncC, /* I/O Encoder state */ + opus_int16 NLSF_Q15[], /* O NLSFs */ + const silk_float x[], /* I Input signal */ + const silk_float minInvGain /* I Prediction gain from LTP (dB) */ +); + +/* LTP analysis */ +void silk_find_LTP_FLP( + silk_float XX[ MAX_NB_SUBFR * LTP_ORDER * LTP_ORDER ], /* O Weight for LTP quantization */ + silk_float xX[ MAX_NB_SUBFR * LTP_ORDER ], /* O Weight for LTP quantization */ + const silk_float r_ptr[], /* I LPC residual */ + const opus_int lag[ MAX_NB_SUBFR ], /* I LTP lags */ + const opus_int subfr_length, /* I Subframe length */ + const opus_int nb_subfr /* I number of subframes */ +); + +void silk_LTP_analysis_filter_FLP( + silk_float *LTP_res, /* O LTP res MAX_NB_SUBFR*(pre_lgth+subfr_lngth) */ + const silk_float *x, /* I Input signal, with preceding samples */ + const silk_float B[ LTP_ORDER * MAX_NB_SUBFR ], /* I LTP coefficients for each subframe */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lags */ + const silk_float invGains[ MAX_NB_SUBFR ], /* I Inverse quantization gains */ + const opus_int subfr_length, /* I Length of each subframe */ + const opus_int nb_subfr, /* I number of subframes */ + const opus_int pre_length /* I Preceding samples for each subframe */ +); + +/* Calculates residual energies of input subframes where all subframes have LPC_order */ +/* of preceding samples */ +void silk_residual_energy_FLP( + silk_float nrgs[ MAX_NB_SUBFR ], /* O Residual energy per subframe */ + const silk_float x[], /* I Input signal */ + silk_float a[ 2 ][ MAX_LPC_ORDER ], /* I AR coefs for each frame half */ + const silk_float gains[], /* I Quantization gains */ + const opus_int subfr_length, /* I Subframe length */ + const opus_int nb_subfr, /* I number of subframes */ + const opus_int LPC_order /* I LPC order */ +); + +/* 16th order LPC analysis filter */ +void silk_LPC_analysis_filter_FLP( + silk_float r_LPC[], /* O LPC residual signal */ + const silk_float PredCoef[], /* I LPC coefficients */ + const silk_float s[], /* I Input signal */ + const opus_int length, /* I Length of input signal */ + const opus_int Order /* I LPC order */ +); + +/* LTP tap quantizer */ +void silk_quant_LTP_gains_FLP( + silk_float B[ MAX_NB_SUBFR * LTP_ORDER ], /* O Quantized LTP gains */ + opus_int8 cbk_index[ MAX_NB_SUBFR ], /* O Codebook index */ + opus_int8 *periodicity_index, /* O Periodicity index */ + opus_int32 *sum_log_gain_Q7, /* I/O Cumulative max prediction gain */ + silk_float *pred_gain_dB, /* O LTP prediction gain */ + const silk_float XX[ MAX_NB_SUBFR * LTP_ORDER * LTP_ORDER ], /* I Correlation matrix */ + const silk_float xX[ MAX_NB_SUBFR * LTP_ORDER ], /* I Correlation vector */ + const opus_int subfr_len, /* I Number of samples per subframe */ + const opus_int nb_subfr, /* I Number of subframes */ + int arch /* I Run-time architecture */ +); + +/* Residual energy: nrg = wxx - 2 * wXx * c + c' * wXX * c */ +silk_float silk_residual_energy_covar_FLP( /* O Weighted residual energy */ + const silk_float *c, /* I Filter coefficients */ + silk_float *wXX, /* I/O Weighted correlation matrix, reg. out */ + const silk_float *wXx, /* I Weighted correlation vector */ + const silk_float wxx, /* I Weighted correlation value */ + const opus_int D /* I Dimension */ +); + +/* Processing of gains */ +void silk_process_gains_FLP( + silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */ + opus_int condCoding /* I The type of conditional coding to use */ +); + +/******************/ +/* Linear Algebra */ +/******************/ +/* Calculates correlation matrix X'*X */ +void silk_corrMatrix_FLP( + const silk_float *x, /* I x vector [ L+order-1 ] used to create X */ + const opus_int L, /* I Length of vectors */ + const opus_int Order, /* I Max lag for correlation */ + silk_float *XX /* O X'*X correlation matrix [order x order] */ +); + +/* Calculates correlation vector X'*t */ +void silk_corrVector_FLP( + const silk_float *x, /* I x vector [L+order-1] used to create X */ + const silk_float *t, /* I Target vector [L] */ + const opus_int L, /* I Length of vecors */ + const opus_int Order, /* I Max lag for correlation */ + silk_float *Xt /* O X'*t correlation vector [order] */ +); + +/* Apply sine window to signal vector. */ +/* Window types: */ +/* 1 -> sine window from 0 to pi/2 */ +/* 2 -> sine window from pi/2 to pi */ +void silk_apply_sine_window_FLP( + silk_float px_win[], /* O Pointer to windowed signal */ + const silk_float px[], /* I Pointer to input signal */ + const opus_int win_type, /* I Selects a window type */ + const opus_int length /* I Window length, multiple of 4 */ +); + +/* Wrapper functions. Call flp / fix code */ + +/* Convert AR filter coefficients to NLSF parameters */ +void silk_A2NLSF_FLP( + opus_int16 *NLSF_Q15, /* O NLSF vector [ LPC_order ] */ + const silk_float *pAR, /* I LPC coefficients [ LPC_order ] */ + const opus_int LPC_order /* I LPC order */ +); + +/* Convert NLSF parameters to AR prediction filter coefficients */ +void silk_NLSF2A_FLP( + silk_float *pAR, /* O LPC coefficients [ LPC_order ] */ + const opus_int16 *NLSF_Q15, /* I NLSF vector [ LPC_order ] */ + const opus_int LPC_order, /* I LPC order */ + int arch /* I Run-time architecture */ +); + +/* Limit, stabilize, and quantize NLSFs */ +void silk_process_NLSFs_FLP( + silk_encoder_state *psEncC, /* I/O Encoder state */ + silk_float PredCoef[ 2 ][ MAX_LPC_ORDER ], /* O Prediction coefficients */ + opus_int16 NLSF_Q15[ MAX_LPC_ORDER ], /* I/O Normalized LSFs (quant out) (0 - (2^15-1)) */ + const opus_int16 prev_NLSF_Q15[ MAX_LPC_ORDER ] /* I Previous Normalized LSFs (0 - (2^15-1)) */ +); + +/* Floating-point Silk NSQ wrapper */ +void silk_NSQ_wrapper_FLP( + silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */ + SideInfoIndices *psIndices, /* I/O Quantization indices */ + silk_nsq_state *psNSQ, /* I/O Noise Shaping Quantzation state */ + opus_int8 pulses[], /* O Quantized pulse signal */ + const silk_float x[] /* I Prefiltered input signal */ +); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/extern/opus/silk/float/noise_shape_analysis_FLP.c b/extern/opus/silk/float/noise_shape_analysis_FLP.c new file mode 100644 index 0000000..cb3d8a5 --- /dev/null +++ b/extern/opus/silk/float/noise_shape_analysis_FLP.c @@ -0,0 +1,350 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FLP.h" +#include "tuning_parameters.h" + +/* Compute gain to make warped filter coefficients have a zero mean log frequency response on a */ +/* non-warped frequency scale. (So that it can be implemented with a minimum-phase monic filter.) */ +/* Note: A monic filter is one with the first coefficient equal to 1.0. In Silk we omit the first */ +/* coefficient in an array of coefficients, for monic filters. */ +static OPUS_INLINE silk_float warped_gain( + const silk_float *coefs, + silk_float lambda, + opus_int order +) { + opus_int i; + silk_float gain; + + lambda = -lambda; + gain = coefs[ order - 1 ]; + for( i = order - 2; i >= 0; i-- ) { + gain = lambda * gain + coefs[ i ]; + } + return (silk_float)( 1.0f / ( 1.0f - lambda * gain ) ); +} + +/* Convert warped filter coefficients to monic pseudo-warped coefficients and limit maximum */ +/* amplitude of monic warped coefficients by using bandwidth expansion on the true coefficients */ +static OPUS_INLINE void warped_true2monic_coefs( + silk_float *coefs, + silk_float lambda, + silk_float limit, + opus_int order +) { + opus_int i, iter, ind = 0; + silk_float tmp, maxabs, chirp, gain; + + /* Convert to monic coefficients */ + for( i = order - 1; i > 0; i-- ) { + coefs[ i - 1 ] -= lambda * coefs[ i ]; + } + gain = ( 1.0f - lambda * lambda ) / ( 1.0f + lambda * coefs[ 0 ] ); + for( i = 0; i < order; i++ ) { + coefs[ i ] *= gain; + } + + /* Limit */ + for( iter = 0; iter < 10; iter++ ) { + /* Find maximum absolute value */ + maxabs = -1.0f; + for( i = 0; i < order; i++ ) { + tmp = silk_abs_float( coefs[ i ] ); + if( tmp > maxabs ) { + maxabs = tmp; + ind = i; + } + } + if( maxabs <= limit ) { + /* Coefficients are within range - done */ + return; + } + + /* Convert back to true warped coefficients */ + for( i = 1; i < order; i++ ) { + coefs[ i - 1 ] += lambda * coefs[ i ]; + } + gain = 1.0f / gain; + for( i = 0; i < order; i++ ) { + coefs[ i ] *= gain; + } + + /* Apply bandwidth expansion */ + chirp = 0.99f - ( 0.8f + 0.1f * iter ) * ( maxabs - limit ) / ( maxabs * ( ind + 1 ) ); + silk_bwexpander_FLP( coefs, order, chirp ); + + /* Convert to monic warped coefficients */ + for( i = order - 1; i > 0; i-- ) { + coefs[ i - 1 ] -= lambda * coefs[ i ]; + } + gain = ( 1.0f - lambda * lambda ) / ( 1.0f + lambda * coefs[ 0 ] ); + for( i = 0; i < order; i++ ) { + coefs[ i ] *= gain; + } + } + silk_assert( 0 ); +} + +static OPUS_INLINE void limit_coefs( + silk_float *coefs, + silk_float limit, + opus_int order +) { + opus_int i, iter, ind = 0; + silk_float tmp, maxabs, chirp; + + for( iter = 0; iter < 10; iter++ ) { + /* Find maximum absolute value */ + maxabs = -1.0f; + for( i = 0; i < order; i++ ) { + tmp = silk_abs_float( coefs[ i ] ); + if( tmp > maxabs ) { + maxabs = tmp; + ind = i; + } + } + if( maxabs <= limit ) { + /* Coefficients are within range - done */ + return; + } + + /* Apply bandwidth expansion */ + chirp = 0.99f - ( 0.8f + 0.1f * iter ) * ( maxabs - limit ) / ( maxabs * ( ind + 1 ) ); + silk_bwexpander_FLP( coefs, order, chirp ); + } + silk_assert( 0 ); +} + +/* Compute noise shaping coefficients and initial gain values */ +void silk_noise_shape_analysis_FLP( + silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */ + const silk_float *pitch_res, /* I LPC residual from pitch analysis */ + const silk_float *x /* I Input signal [frame_length + la_shape] */ +) +{ + silk_shape_state_FLP *psShapeSt = &psEnc->sShape; + opus_int k, nSamples, nSegs; + silk_float SNR_adj_dB, HarmShapeGain, Tilt; + silk_float nrg, log_energy, log_energy_prev, energy_variation; + silk_float BWExp, gain_mult, gain_add, strength, b, warping; + silk_float x_windowed[ SHAPE_LPC_WIN_MAX ]; + silk_float auto_corr[ MAX_SHAPE_LPC_ORDER + 1 ]; + silk_float rc[ MAX_SHAPE_LPC_ORDER + 1 ]; + const silk_float *x_ptr, *pitch_res_ptr; + + /* Point to start of first LPC analysis block */ + x_ptr = x - psEnc->sCmn.la_shape; + + /****************/ + /* GAIN CONTROL */ + /****************/ + SNR_adj_dB = psEnc->sCmn.SNR_dB_Q7 * ( 1 / 128.0f ); + + /* Input quality is the average of the quality in the lowest two VAD bands */ + psEncCtrl->input_quality = 0.5f * ( psEnc->sCmn.input_quality_bands_Q15[ 0 ] + psEnc->sCmn.input_quality_bands_Q15[ 1 ] ) * ( 1.0f / 32768.0f ); + + /* Coding quality level, between 0.0 and 1.0 */ + psEncCtrl->coding_quality = silk_sigmoid( 0.25f * ( SNR_adj_dB - 20.0f ) ); + + if( psEnc->sCmn.useCBR == 0 ) { + /* Reduce coding SNR during low speech activity */ + b = 1.0f - psEnc->sCmn.speech_activity_Q8 * ( 1.0f / 256.0f ); + SNR_adj_dB -= BG_SNR_DECR_dB * psEncCtrl->coding_quality * ( 0.5f + 0.5f * psEncCtrl->input_quality ) * b * b; + } + + if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) { + /* Reduce gains for periodic signals */ + SNR_adj_dB += HARM_SNR_INCR_dB * psEnc->LTPCorr; + } else { + /* For unvoiced signals and low-quality input, adjust the quality slower than SNR_dB setting */ + SNR_adj_dB += ( -0.4f * psEnc->sCmn.SNR_dB_Q7 * ( 1 / 128.0f ) + 6.0f ) * ( 1.0f - psEncCtrl->input_quality ); + } + + /*************************/ + /* SPARSENESS PROCESSING */ + /*************************/ + /* Set quantizer offset */ + if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) { + /* Initially set to 0; may be overruled in process_gains(..) */ + psEnc->sCmn.indices.quantOffsetType = 0; + } else { + /* Sparseness measure, based on relative fluctuations of energy per 2 milliseconds */ + nSamples = 2 * psEnc->sCmn.fs_kHz; + energy_variation = 0.0f; + log_energy_prev = 0.0f; + pitch_res_ptr = pitch_res; + nSegs = silk_SMULBB( SUB_FRAME_LENGTH_MS, psEnc->sCmn.nb_subfr ) / 2; + for( k = 0; k < nSegs; k++ ) { + nrg = ( silk_float )nSamples + ( silk_float )silk_energy_FLP( pitch_res_ptr, nSamples ); + log_energy = silk_log2( nrg ); + if( k > 0 ) { + energy_variation += silk_abs_float( log_energy - log_energy_prev ); + } + log_energy_prev = log_energy; + pitch_res_ptr += nSamples; + } + + /* Set quantization offset depending on sparseness measure */ + if( energy_variation > ENERGY_VARIATION_THRESHOLD_QNT_OFFSET * (nSegs-1) ) { + psEnc->sCmn.indices.quantOffsetType = 0; + } else { + psEnc->sCmn.indices.quantOffsetType = 1; + } + } + + /*******************************/ + /* Control bandwidth expansion */ + /*******************************/ + /* More BWE for signals with high prediction gain */ + strength = FIND_PITCH_WHITE_NOISE_FRACTION * psEncCtrl->predGain; /* between 0.0 and 1.0 */ + BWExp = BANDWIDTH_EXPANSION / ( 1.0f + strength * strength ); + + /* Slightly more warping in analysis will move quantization noise up in frequency, where it's better masked */ + warping = (silk_float)psEnc->sCmn.warping_Q16 / 65536.0f + 0.01f * psEncCtrl->coding_quality; + + /********************************************/ + /* Compute noise shaping AR coefs and gains */ + /********************************************/ + for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) { + /* Apply window: sine slope followed by flat part followed by cosine slope */ + opus_int shift, slope_part, flat_part; + flat_part = psEnc->sCmn.fs_kHz * 3; + slope_part = ( psEnc->sCmn.shapeWinLength - flat_part ) / 2; + + silk_apply_sine_window_FLP( x_windowed, x_ptr, 1, slope_part ); + shift = slope_part; + silk_memcpy( x_windowed + shift, x_ptr + shift, flat_part * sizeof(silk_float) ); + shift += flat_part; + silk_apply_sine_window_FLP( x_windowed + shift, x_ptr + shift, 2, slope_part ); + + /* Update pointer: next LPC analysis block */ + x_ptr += psEnc->sCmn.subfr_length; + + if( psEnc->sCmn.warping_Q16 > 0 ) { + /* Calculate warped auto correlation */ + silk_warped_autocorrelation_FLP( auto_corr, x_windowed, warping, + psEnc->sCmn.shapeWinLength, psEnc->sCmn.shapingLPCOrder ); + } else { + /* Calculate regular auto correlation */ + silk_autocorrelation_FLP( auto_corr, x_windowed, psEnc->sCmn.shapeWinLength, psEnc->sCmn.shapingLPCOrder + 1 ); + } + + /* Add white noise, as a fraction of energy */ + auto_corr[ 0 ] += auto_corr[ 0 ] * SHAPE_WHITE_NOISE_FRACTION + 1.0f; + + /* Convert correlations to prediction coefficients, and compute residual energy */ + nrg = silk_schur_FLP( rc, auto_corr, psEnc->sCmn.shapingLPCOrder ); + silk_k2a_FLP( &psEncCtrl->AR[ k * MAX_SHAPE_LPC_ORDER ], rc, psEnc->sCmn.shapingLPCOrder ); + psEncCtrl->Gains[ k ] = ( silk_float )sqrt( nrg ); + + if( psEnc->sCmn.warping_Q16 > 0 ) { + /* Adjust gain for warping */ + psEncCtrl->Gains[ k ] *= warped_gain( &psEncCtrl->AR[ k * MAX_SHAPE_LPC_ORDER ], warping, psEnc->sCmn.shapingLPCOrder ); + } + + /* Bandwidth expansion for synthesis filter shaping */ + silk_bwexpander_FLP( &psEncCtrl->AR[ k * MAX_SHAPE_LPC_ORDER ], psEnc->sCmn.shapingLPCOrder, BWExp ); + + if( psEnc->sCmn.warping_Q16 > 0 ) { + /* Convert to monic warped prediction coefficients and limit absolute values */ + warped_true2monic_coefs( &psEncCtrl->AR[ k * MAX_SHAPE_LPC_ORDER ], warping, 3.999f, psEnc->sCmn.shapingLPCOrder ); + } else { + /* Limit absolute values */ + limit_coefs( &psEncCtrl->AR[ k * MAX_SHAPE_LPC_ORDER ], 3.999f, psEnc->sCmn.shapingLPCOrder ); + } + } + + /*****************/ + /* Gain tweaking */ + /*****************/ + /* Increase gains during low speech activity */ + gain_mult = (silk_float)pow( 2.0f, -0.16f * SNR_adj_dB ); + gain_add = (silk_float)pow( 2.0f, 0.16f * MIN_QGAIN_DB ); + for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) { + psEncCtrl->Gains[ k ] *= gain_mult; + psEncCtrl->Gains[ k ] += gain_add; + } + + /************************************************/ + /* Control low-frequency shaping and noise tilt */ + /************************************************/ + /* Less low frequency shaping for noisy inputs */ + strength = LOW_FREQ_SHAPING * ( 1.0f + LOW_QUALITY_LOW_FREQ_SHAPING_DECR * ( psEnc->sCmn.input_quality_bands_Q15[ 0 ] * ( 1.0f / 32768.0f ) - 1.0f ) ); + strength *= psEnc->sCmn.speech_activity_Q8 * ( 1.0f / 256.0f ); + if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) { + /* Reduce low frequencies quantization noise for periodic signals, depending on pitch lag */ + /*f = 400; freqz([1, -0.98 + 2e-4 * f], [1, -0.97 + 7e-4 * f], 2^12, Fs); axis([0, 1000, -10, 1])*/ + for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) { + b = 0.2f / psEnc->sCmn.fs_kHz + 3.0f / psEncCtrl->pitchL[ k ]; + psEncCtrl->LF_MA_shp[ k ] = -1.0f + b; + psEncCtrl->LF_AR_shp[ k ] = 1.0f - b - b * strength; + } + Tilt = - HP_NOISE_COEF - + (1 - HP_NOISE_COEF) * HARM_HP_NOISE_COEF * psEnc->sCmn.speech_activity_Q8 * ( 1.0f / 256.0f ); + } else { + b = 1.3f / psEnc->sCmn.fs_kHz; + psEncCtrl->LF_MA_shp[ 0 ] = -1.0f + b; + psEncCtrl->LF_AR_shp[ 0 ] = 1.0f - b - b * strength * 0.6f; + for( k = 1; k < psEnc->sCmn.nb_subfr; k++ ) { + psEncCtrl->LF_MA_shp[ k ] = psEncCtrl->LF_MA_shp[ 0 ]; + psEncCtrl->LF_AR_shp[ k ] = psEncCtrl->LF_AR_shp[ 0 ]; + } + Tilt = -HP_NOISE_COEF; + } + + /****************************/ + /* HARMONIC SHAPING CONTROL */ + /****************************/ + if( USE_HARM_SHAPING && psEnc->sCmn.indices.signalType == TYPE_VOICED ) { + /* Harmonic noise shaping */ + HarmShapeGain = HARMONIC_SHAPING; + + /* More harmonic noise shaping for high bitrates or noisy input */ + HarmShapeGain += HIGH_RATE_OR_LOW_QUALITY_HARMONIC_SHAPING * + ( 1.0f - ( 1.0f - psEncCtrl->coding_quality ) * psEncCtrl->input_quality ); + + /* Less harmonic noise shaping for less periodic signals */ + HarmShapeGain *= ( silk_float )sqrt( psEnc->LTPCorr ); + } else { + HarmShapeGain = 0.0f; + } + + /*************************/ + /* Smooth over subframes */ + /*************************/ + for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) { + psShapeSt->HarmShapeGain_smth += SUBFR_SMTH_COEF * ( HarmShapeGain - psShapeSt->HarmShapeGain_smth ); + psEncCtrl->HarmShapeGain[ k ] = psShapeSt->HarmShapeGain_smth; + psShapeSt->Tilt_smth += SUBFR_SMTH_COEF * ( Tilt - psShapeSt->Tilt_smth ); + psEncCtrl->Tilt[ k ] = psShapeSt->Tilt_smth; + } +} diff --git a/extern/opus/silk/float/pitch_analysis_core_FLP.c b/extern/opus/silk/float/pitch_analysis_core_FLP.c new file mode 100644 index 0000000..f351bc3 --- /dev/null +++ b/extern/opus/silk/float/pitch_analysis_core_FLP.c @@ -0,0 +1,630 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/***************************************************************************** +* Pitch analyser function +******************************************************************************/ +#include "SigProc_FLP.h" +#include "SigProc_FIX.h" +#include "pitch_est_defines.h" +#include "pitch.h" + +#define SCRATCH_SIZE 22 + +/************************************************************/ +/* Internally used functions */ +/************************************************************/ +static void silk_P_Ana_calc_corr_st3( + silk_float cross_corr_st3[ PE_MAX_NB_SUBFR ][ PE_NB_CBKS_STAGE3_MAX ][ PE_NB_STAGE3_LAGS ], /* O 3 DIM correlation array */ + const silk_float frame[], /* I vector to correlate */ + opus_int start_lag, /* I start lag */ + opus_int sf_length, /* I sub frame length */ + opus_int nb_subfr, /* I number of subframes */ + opus_int complexity, /* I Complexity setting */ + int arch /* I Run-time architecture */ +); + +static void silk_P_Ana_calc_energy_st3( + silk_float energies_st3[ PE_MAX_NB_SUBFR ][ PE_NB_CBKS_STAGE3_MAX ][ PE_NB_STAGE3_LAGS ], /* O 3 DIM correlation array */ + const silk_float frame[], /* I vector to correlate */ + opus_int start_lag, /* I start lag */ + opus_int sf_length, /* I sub frame length */ + opus_int nb_subfr, /* I number of subframes */ + opus_int complexity /* I Complexity setting */ +); + +/************************************************************/ +/* CORE PITCH ANALYSIS FUNCTION */ +/************************************************************/ +opus_int silk_pitch_analysis_core_FLP( /* O Voicing estimate: 0 voiced, 1 unvoiced */ + const silk_float *frame, /* I Signal of length PE_FRAME_LENGTH_MS*Fs_kHz */ + opus_int *pitch_out, /* O Pitch lag values [nb_subfr] */ + opus_int16 *lagIndex, /* O Lag Index */ + opus_int8 *contourIndex, /* O Pitch contour Index */ + silk_float *LTPCorr, /* I/O Normalized correlation; input: value from previous frame */ + opus_int prevLag, /* I Last lag of previous frame; set to zero is unvoiced */ + const silk_float search_thres1, /* I First stage threshold for lag candidates 0 - 1 */ + const silk_float search_thres2, /* I Final threshold for lag candidates 0 - 1 */ + const opus_int Fs_kHz, /* I sample frequency (kHz) */ + const opus_int complexity, /* I Complexity setting, 0-2, where 2 is highest */ + const opus_int nb_subfr, /* I Number of 5 ms subframes */ + int arch /* I Run-time architecture */ +) +{ + opus_int i, k, d, j; + silk_float frame_8kHz[ PE_MAX_FRAME_LENGTH_MS * 8 ]; + silk_float frame_4kHz[ PE_MAX_FRAME_LENGTH_MS * 4 ]; + opus_int16 frame_8_FIX[ PE_MAX_FRAME_LENGTH_MS * 8 ]; + opus_int16 frame_4_FIX[ PE_MAX_FRAME_LENGTH_MS * 4 ]; + opus_int32 filt_state[ 6 ]; + silk_float threshold, contour_bias; + silk_float C[ PE_MAX_NB_SUBFR][ (PE_MAX_LAG >> 1) + 5 ]; + opus_val32 xcorr[ PE_MAX_LAG_MS * 4 - PE_MIN_LAG_MS * 4 + 1 ]; + silk_float CC[ PE_NB_CBKS_STAGE2_EXT ]; + const silk_float *target_ptr, *basis_ptr; + double cross_corr, normalizer, energy, energy_tmp; + opus_int d_srch[ PE_D_SRCH_LENGTH ]; + opus_int16 d_comp[ (PE_MAX_LAG >> 1) + 5 ]; + opus_int length_d_srch, length_d_comp; + silk_float Cmax, CCmax, CCmax_b, CCmax_new_b, CCmax_new; + opus_int CBimax, CBimax_new, lag, start_lag, end_lag, lag_new; + opus_int cbk_size; + silk_float lag_log2, prevLag_log2, delta_lag_log2_sqr; + silk_float energies_st3[ PE_MAX_NB_SUBFR ][ PE_NB_CBKS_STAGE3_MAX ][ PE_NB_STAGE3_LAGS ]; + silk_float cross_corr_st3[ PE_MAX_NB_SUBFR ][ PE_NB_CBKS_STAGE3_MAX ][ PE_NB_STAGE3_LAGS ]; + opus_int lag_counter; + opus_int frame_length, frame_length_8kHz, frame_length_4kHz; + opus_int sf_length, sf_length_8kHz, sf_length_4kHz; + opus_int min_lag, min_lag_8kHz, min_lag_4kHz; + opus_int max_lag, max_lag_8kHz, max_lag_4kHz; + opus_int nb_cbk_search; + const opus_int8 *Lag_CB_ptr; + + /* Check for valid sampling frequency */ + celt_assert( Fs_kHz == 8 || Fs_kHz == 12 || Fs_kHz == 16 ); + + /* Check for valid complexity setting */ + celt_assert( complexity >= SILK_PE_MIN_COMPLEX ); + celt_assert( complexity <= SILK_PE_MAX_COMPLEX ); + + silk_assert( search_thres1 >= 0.0f && search_thres1 <= 1.0f ); + silk_assert( search_thres2 >= 0.0f && search_thres2 <= 1.0f ); + + /* Set up frame lengths max / min lag for the sampling frequency */ + frame_length = ( PE_LTP_MEM_LENGTH_MS + nb_subfr * PE_SUBFR_LENGTH_MS ) * Fs_kHz; + frame_length_4kHz = ( PE_LTP_MEM_LENGTH_MS + nb_subfr * PE_SUBFR_LENGTH_MS ) * 4; + frame_length_8kHz = ( PE_LTP_MEM_LENGTH_MS + nb_subfr * PE_SUBFR_LENGTH_MS ) * 8; + sf_length = PE_SUBFR_LENGTH_MS * Fs_kHz; + sf_length_4kHz = PE_SUBFR_LENGTH_MS * 4; + sf_length_8kHz = PE_SUBFR_LENGTH_MS * 8; + min_lag = PE_MIN_LAG_MS * Fs_kHz; + min_lag_4kHz = PE_MIN_LAG_MS * 4; + min_lag_8kHz = PE_MIN_LAG_MS * 8; + max_lag = PE_MAX_LAG_MS * Fs_kHz - 1; + max_lag_4kHz = PE_MAX_LAG_MS * 4; + max_lag_8kHz = PE_MAX_LAG_MS * 8 - 1; + + /* Resample from input sampled at Fs_kHz to 8 kHz */ + if( Fs_kHz == 16 ) { + /* Resample to 16 -> 8 khz */ + opus_int16 frame_16_FIX[ 16 * PE_MAX_FRAME_LENGTH_MS ]; + silk_float2short_array( frame_16_FIX, frame, frame_length ); + silk_memset( filt_state, 0, 2 * sizeof( opus_int32 ) ); + silk_resampler_down2( filt_state, frame_8_FIX, frame_16_FIX, frame_length ); + silk_short2float_array( frame_8kHz, frame_8_FIX, frame_length_8kHz ); + } else if( Fs_kHz == 12 ) { + /* Resample to 12 -> 8 khz */ + opus_int16 frame_12_FIX[ 12 * PE_MAX_FRAME_LENGTH_MS ]; + silk_float2short_array( frame_12_FIX, frame, frame_length ); + silk_memset( filt_state, 0, 6 * sizeof( opus_int32 ) ); + silk_resampler_down2_3( filt_state, frame_8_FIX, frame_12_FIX, frame_length ); + silk_short2float_array( frame_8kHz, frame_8_FIX, frame_length_8kHz ); + } else { + celt_assert( Fs_kHz == 8 ); + silk_float2short_array( frame_8_FIX, frame, frame_length_8kHz ); + } + + /* Decimate again to 4 kHz */ + silk_memset( filt_state, 0, 2 * sizeof( opus_int32 ) ); + silk_resampler_down2( filt_state, frame_4_FIX, frame_8_FIX, frame_length_8kHz ); + silk_short2float_array( frame_4kHz, frame_4_FIX, frame_length_4kHz ); + + /* Low-pass filter */ + for( i = frame_length_4kHz - 1; i > 0; i-- ) { + frame_4kHz[ i ] = silk_ADD_SAT16( frame_4kHz[ i ], frame_4kHz[ i - 1 ] ); + } + + /****************************************************************************** + * FIRST STAGE, operating in 4 khz + ******************************************************************************/ + silk_memset(C, 0, sizeof(silk_float) * nb_subfr * ((PE_MAX_LAG >> 1) + 5)); + target_ptr = &frame_4kHz[ silk_LSHIFT( sf_length_4kHz, 2 ) ]; + for( k = 0; k < nb_subfr >> 1; k++ ) { + /* Check that we are within range of the array */ + celt_assert( target_ptr >= frame_4kHz ); + celt_assert( target_ptr + sf_length_8kHz <= frame_4kHz + frame_length_4kHz ); + + basis_ptr = target_ptr - min_lag_4kHz; + + /* Check that we are within range of the array */ + celt_assert( basis_ptr >= frame_4kHz ); + celt_assert( basis_ptr + sf_length_8kHz <= frame_4kHz + frame_length_4kHz ); + + celt_pitch_xcorr( target_ptr, target_ptr-max_lag_4kHz, xcorr, sf_length_8kHz, max_lag_4kHz - min_lag_4kHz + 1, arch ); + + /* Calculate first vector products before loop */ + cross_corr = xcorr[ max_lag_4kHz - min_lag_4kHz ]; + normalizer = silk_energy_FLP( target_ptr, sf_length_8kHz ) + + silk_energy_FLP( basis_ptr, sf_length_8kHz ) + + sf_length_8kHz * 4000.0f; + + C[ 0 ][ min_lag_4kHz ] += (silk_float)( 2 * cross_corr / normalizer ); + + /* From now on normalizer is computed recursively */ + for( d = min_lag_4kHz + 1; d <= max_lag_4kHz; d++ ) { + basis_ptr--; + + /* Check that we are within range of the array */ + silk_assert( basis_ptr >= frame_4kHz ); + silk_assert( basis_ptr + sf_length_8kHz <= frame_4kHz + frame_length_4kHz ); + + cross_corr = xcorr[ max_lag_4kHz - d ]; + + /* Add contribution of new sample and remove contribution from oldest sample */ + normalizer += + basis_ptr[ 0 ] * (double)basis_ptr[ 0 ] - + basis_ptr[ sf_length_8kHz ] * (double)basis_ptr[ sf_length_8kHz ]; + C[ 0 ][ d ] += (silk_float)( 2 * cross_corr / normalizer ); + } + /* Update target pointer */ + target_ptr += sf_length_8kHz; + } + + /* Apply short-lag bias */ + for( i = max_lag_4kHz; i >= min_lag_4kHz; i-- ) { + C[ 0 ][ i ] -= C[ 0 ][ i ] * i / 4096.0f; + } + + /* Sort */ + length_d_srch = 4 + 2 * complexity; + celt_assert( 3 * length_d_srch <= PE_D_SRCH_LENGTH ); + silk_insertion_sort_decreasing_FLP( &C[ 0 ][ min_lag_4kHz ], d_srch, max_lag_4kHz - min_lag_4kHz + 1, length_d_srch ); + + /* Escape if correlation is very low already here */ + Cmax = C[ 0 ][ min_lag_4kHz ]; + if( Cmax < 0.2f ) { + silk_memset( pitch_out, 0, nb_subfr * sizeof( opus_int ) ); + *LTPCorr = 0.0f; + *lagIndex = 0; + *contourIndex = 0; + return 1; + } + + threshold = search_thres1 * Cmax; + for( i = 0; i < length_d_srch; i++ ) { + /* Convert to 8 kHz indices for the sorted correlation that exceeds the threshold */ + if( C[ 0 ][ min_lag_4kHz + i ] > threshold ) { + d_srch[ i ] = silk_LSHIFT( d_srch[ i ] + min_lag_4kHz, 1 ); + } else { + length_d_srch = i; + break; + } + } + celt_assert( length_d_srch > 0 ); + + for( i = min_lag_8kHz - 5; i < max_lag_8kHz + 5; i++ ) { + d_comp[ i ] = 0; + } + for( i = 0; i < length_d_srch; i++ ) { + d_comp[ d_srch[ i ] ] = 1; + } + + /* Convolution */ + for( i = max_lag_8kHz + 3; i >= min_lag_8kHz; i-- ) { + d_comp[ i ] += d_comp[ i - 1 ] + d_comp[ i - 2 ]; + } + + length_d_srch = 0; + for( i = min_lag_8kHz; i < max_lag_8kHz + 1; i++ ) { + if( d_comp[ i + 1 ] > 0 ) { + d_srch[ length_d_srch ] = i; + length_d_srch++; + } + } + + /* Convolution */ + for( i = max_lag_8kHz + 3; i >= min_lag_8kHz; i-- ) { + d_comp[ i ] += d_comp[ i - 1 ] + d_comp[ i - 2 ] + d_comp[ i - 3 ]; + } + + length_d_comp = 0; + for( i = min_lag_8kHz; i < max_lag_8kHz + 4; i++ ) { + if( d_comp[ i ] > 0 ) { + d_comp[ length_d_comp ] = (opus_int16)( i - 2 ); + length_d_comp++; + } + } + + /********************************************************************************** + ** SECOND STAGE, operating at 8 kHz, on lag sections with high correlation + *************************************************************************************/ + /********************************************************************************* + * Find energy of each subframe projected onto its history, for a range of delays + *********************************************************************************/ + silk_memset( C, 0, PE_MAX_NB_SUBFR*((PE_MAX_LAG >> 1) + 5) * sizeof(silk_float)); + + if( Fs_kHz == 8 ) { + target_ptr = &frame[ PE_LTP_MEM_LENGTH_MS * 8 ]; + } else { + target_ptr = &frame_8kHz[ PE_LTP_MEM_LENGTH_MS * 8 ]; + } + for( k = 0; k < nb_subfr; k++ ) { + energy_tmp = silk_energy_FLP( target_ptr, sf_length_8kHz ) + 1.0; + for( j = 0; j < length_d_comp; j++ ) { + d = d_comp[ j ]; + basis_ptr = target_ptr - d; + cross_corr = silk_inner_product_FLP( basis_ptr, target_ptr, sf_length_8kHz ); + if( cross_corr > 0.0f ) { + energy = silk_energy_FLP( basis_ptr, sf_length_8kHz ); + C[ k ][ d ] = (silk_float)( 2 * cross_corr / ( energy + energy_tmp ) ); + } else { + C[ k ][ d ] = 0.0f; + } + } + target_ptr += sf_length_8kHz; + } + + /* search over lag range and lags codebook */ + /* scale factor for lag codebook, as a function of center lag */ + + CCmax = 0.0f; /* This value doesn't matter */ + CCmax_b = -1000.0f; + + CBimax = 0; /* To avoid returning undefined lag values */ + lag = -1; /* To check if lag with strong enough correlation has been found */ + + if( prevLag > 0 ) { + if( Fs_kHz == 12 ) { + prevLag = silk_LSHIFT( prevLag, 1 ) / 3; + } else if( Fs_kHz == 16 ) { + prevLag = silk_RSHIFT( prevLag, 1 ); + } + prevLag_log2 = silk_log2( (silk_float)prevLag ); + } else { + prevLag_log2 = 0; + } + + /* Set up stage 2 codebook based on number of subframes */ + if( nb_subfr == PE_MAX_NB_SUBFR ) { + cbk_size = PE_NB_CBKS_STAGE2_EXT; + Lag_CB_ptr = &silk_CB_lags_stage2[ 0 ][ 0 ]; + if( Fs_kHz == 8 && complexity > SILK_PE_MIN_COMPLEX ) { + /* If input is 8 khz use a larger codebook here because it is last stage */ + nb_cbk_search = PE_NB_CBKS_STAGE2_EXT; + } else { + nb_cbk_search = PE_NB_CBKS_STAGE2; + } + } else { + cbk_size = PE_NB_CBKS_STAGE2_10MS; + Lag_CB_ptr = &silk_CB_lags_stage2_10_ms[ 0 ][ 0 ]; + nb_cbk_search = PE_NB_CBKS_STAGE2_10MS; + } + + for( k = 0; k < length_d_srch; k++ ) { + d = d_srch[ k ]; + for( j = 0; j < nb_cbk_search; j++ ) { + CC[j] = 0.0f; + for( i = 0; i < nb_subfr; i++ ) { + /* Try all codebooks */ + CC[ j ] += C[ i ][ d + matrix_ptr( Lag_CB_ptr, i, j, cbk_size )]; + } + } + /* Find best codebook */ + CCmax_new = -1000.0f; + CBimax_new = 0; + for( i = 0; i < nb_cbk_search; i++ ) { + if( CC[ i ] > CCmax_new ) { + CCmax_new = CC[ i ]; + CBimax_new = i; + } + } + + /* Bias towards shorter lags */ + lag_log2 = silk_log2( (silk_float)d ); + CCmax_new_b = CCmax_new - PE_SHORTLAG_BIAS * nb_subfr * lag_log2; + + /* Bias towards previous lag */ + if( prevLag > 0 ) { + delta_lag_log2_sqr = lag_log2 - prevLag_log2; + delta_lag_log2_sqr *= delta_lag_log2_sqr; + CCmax_new_b -= PE_PREVLAG_BIAS * nb_subfr * (*LTPCorr) * delta_lag_log2_sqr / ( delta_lag_log2_sqr + 0.5f ); + } + + if( CCmax_new_b > CCmax_b && /* Find maximum biased correlation */ + CCmax_new > nb_subfr * search_thres2 /* Correlation needs to be high enough to be voiced */ + ) { + CCmax_b = CCmax_new_b; + CCmax = CCmax_new; + lag = d; + CBimax = CBimax_new; + } + } + + if( lag == -1 ) { + /* No suitable candidate found */ + silk_memset( pitch_out, 0, PE_MAX_NB_SUBFR * sizeof(opus_int) ); + *LTPCorr = 0.0f; + *lagIndex = 0; + *contourIndex = 0; + return 1; + } + + /* Output normalized correlation */ + *LTPCorr = (silk_float)( CCmax / nb_subfr ); + silk_assert( *LTPCorr >= 0.0f ); + + if( Fs_kHz > 8 ) { + /* Search in original signal */ + + /* Compensate for decimation */ + silk_assert( lag == silk_SAT16( lag ) ); + if( Fs_kHz == 12 ) { + lag = silk_RSHIFT_ROUND( silk_SMULBB( lag, 3 ), 1 ); + } else { /* Fs_kHz == 16 */ + lag = silk_LSHIFT( lag, 1 ); + } + + lag = silk_LIMIT_int( lag, min_lag, max_lag ); + start_lag = silk_max_int( lag - 2, min_lag ); + end_lag = silk_min_int( lag + 2, max_lag ); + lag_new = lag; /* to avoid undefined lag */ + CBimax = 0; /* to avoid undefined lag */ + + CCmax = -1000.0f; + + /* Calculate the correlations and energies needed in stage 3 */ + silk_P_Ana_calc_corr_st3( cross_corr_st3, frame, start_lag, sf_length, nb_subfr, complexity, arch ); + silk_P_Ana_calc_energy_st3( energies_st3, frame, start_lag, sf_length, nb_subfr, complexity ); + + lag_counter = 0; + silk_assert( lag == silk_SAT16( lag ) ); + contour_bias = PE_FLATCONTOUR_BIAS / lag; + + /* Set up cbk parameters according to complexity setting and frame length */ + if( nb_subfr == PE_MAX_NB_SUBFR ) { + nb_cbk_search = (opus_int)silk_nb_cbk_searchs_stage3[ complexity ]; + cbk_size = PE_NB_CBKS_STAGE3_MAX; + Lag_CB_ptr = &silk_CB_lags_stage3[ 0 ][ 0 ]; + } else { + nb_cbk_search = PE_NB_CBKS_STAGE3_10MS; + cbk_size = PE_NB_CBKS_STAGE3_10MS; + Lag_CB_ptr = &silk_CB_lags_stage3_10_ms[ 0 ][ 0 ]; + } + + target_ptr = &frame[ PE_LTP_MEM_LENGTH_MS * Fs_kHz ]; + energy_tmp = silk_energy_FLP( target_ptr, nb_subfr * sf_length ) + 1.0; + for( d = start_lag; d <= end_lag; d++ ) { + for( j = 0; j < nb_cbk_search; j++ ) { + cross_corr = 0.0; + energy = energy_tmp; + for( k = 0; k < nb_subfr; k++ ) { + cross_corr += cross_corr_st3[ k ][ j ][ lag_counter ]; + energy += energies_st3[ k ][ j ][ lag_counter ]; + } + if( cross_corr > 0.0 ) { + CCmax_new = (silk_float)( 2 * cross_corr / energy ); + /* Reduce depending on flatness of contour */ + CCmax_new *= 1.0f - contour_bias * j; + } else { + CCmax_new = 0.0f; + } + + if( CCmax_new > CCmax && ( d + (opus_int)silk_CB_lags_stage3[ 0 ][ j ] ) <= max_lag ) { + CCmax = CCmax_new; + lag_new = d; + CBimax = j; + } + } + lag_counter++; + } + + for( k = 0; k < nb_subfr; k++ ) { + pitch_out[ k ] = lag_new + matrix_ptr( Lag_CB_ptr, k, CBimax, cbk_size ); + pitch_out[ k ] = silk_LIMIT( pitch_out[ k ], min_lag, PE_MAX_LAG_MS * Fs_kHz ); + } + *lagIndex = (opus_int16)( lag_new - min_lag ); + *contourIndex = (opus_int8)CBimax; + } else { /* Fs_kHz == 8 */ + /* Save Lags */ + for( k = 0; k < nb_subfr; k++ ) { + pitch_out[ k ] = lag + matrix_ptr( Lag_CB_ptr, k, CBimax, cbk_size ); + pitch_out[ k ] = silk_LIMIT( pitch_out[ k ], min_lag_8kHz, PE_MAX_LAG_MS * 8 ); + } + *lagIndex = (opus_int16)( lag - min_lag_8kHz ); + *contourIndex = (opus_int8)CBimax; + } + celt_assert( *lagIndex >= 0 ); + /* return as voiced */ + return 0; +} + +/*********************************************************************** + * Calculates the correlations used in stage 3 search. In order to cover + * the whole lag codebook for all the searched offset lags (lag +- 2), + * the following correlations are needed in each sub frame: + * + * sf1: lag range [-8,...,7] total 16 correlations + * sf2: lag range [-4,...,4] total 9 correlations + * sf3: lag range [-3,....4] total 8 correltions + * sf4: lag range [-6,....8] total 15 correlations + * + * In total 48 correlations. The direct implementation computed in worst + * case 4*12*5 = 240 correlations, but more likely around 120. + ***********************************************************************/ +static void silk_P_Ana_calc_corr_st3( + silk_float cross_corr_st3[ PE_MAX_NB_SUBFR ][ PE_NB_CBKS_STAGE3_MAX ][ PE_NB_STAGE3_LAGS ], /* O 3 DIM correlation array */ + const silk_float frame[], /* I vector to correlate */ + opus_int start_lag, /* I start lag */ + opus_int sf_length, /* I sub frame length */ + opus_int nb_subfr, /* I number of subframes */ + opus_int complexity, /* I Complexity setting */ + int arch /* I Run-time architecture */ +) +{ + const silk_float *target_ptr; + opus_int i, j, k, lag_counter, lag_low, lag_high; + opus_int nb_cbk_search, delta, idx, cbk_size; + silk_float scratch_mem[ SCRATCH_SIZE ]; + opus_val32 xcorr[ SCRATCH_SIZE ]; + const opus_int8 *Lag_range_ptr, *Lag_CB_ptr; + + celt_assert( complexity >= SILK_PE_MIN_COMPLEX ); + celt_assert( complexity <= SILK_PE_MAX_COMPLEX ); + + if( nb_subfr == PE_MAX_NB_SUBFR ) { + Lag_range_ptr = &silk_Lag_range_stage3[ complexity ][ 0 ][ 0 ]; + Lag_CB_ptr = &silk_CB_lags_stage3[ 0 ][ 0 ]; + nb_cbk_search = silk_nb_cbk_searchs_stage3[ complexity ]; + cbk_size = PE_NB_CBKS_STAGE3_MAX; + } else { + celt_assert( nb_subfr == PE_MAX_NB_SUBFR >> 1); + Lag_range_ptr = &silk_Lag_range_stage3_10_ms[ 0 ][ 0 ]; + Lag_CB_ptr = &silk_CB_lags_stage3_10_ms[ 0 ][ 0 ]; + nb_cbk_search = PE_NB_CBKS_STAGE3_10MS; + cbk_size = PE_NB_CBKS_STAGE3_10MS; + } + + target_ptr = &frame[ silk_LSHIFT( sf_length, 2 ) ]; /* Pointer to middle of frame */ + for( k = 0; k < nb_subfr; k++ ) { + lag_counter = 0; + + /* Calculate the correlations for each subframe */ + lag_low = matrix_ptr( Lag_range_ptr, k, 0, 2 ); + lag_high = matrix_ptr( Lag_range_ptr, k, 1, 2 ); + silk_assert(lag_high-lag_low+1 <= SCRATCH_SIZE); + celt_pitch_xcorr( target_ptr, target_ptr - start_lag - lag_high, xcorr, sf_length, lag_high - lag_low + 1, arch ); + for( j = lag_low; j <= lag_high; j++ ) { + silk_assert( lag_counter < SCRATCH_SIZE ); + scratch_mem[ lag_counter ] = xcorr[ lag_high - j ]; + lag_counter++; + } + + delta = matrix_ptr( Lag_range_ptr, k, 0, 2 ); + for( i = 0; i < nb_cbk_search; i++ ) { + /* Fill out the 3 dim array that stores the correlations for */ + /* each code_book vector for each start lag */ + idx = matrix_ptr( Lag_CB_ptr, k, i, cbk_size ) - delta; + for( j = 0; j < PE_NB_STAGE3_LAGS; j++ ) { + silk_assert( idx + j < SCRATCH_SIZE ); + silk_assert( idx + j < lag_counter ); + cross_corr_st3[ k ][ i ][ j ] = scratch_mem[ idx + j ]; + } + } + target_ptr += sf_length; + } +} + +/********************************************************************/ +/* Calculate the energies for first two subframes. The energies are */ +/* calculated recursively. */ +/********************************************************************/ +static void silk_P_Ana_calc_energy_st3( + silk_float energies_st3[ PE_MAX_NB_SUBFR ][ PE_NB_CBKS_STAGE3_MAX ][ PE_NB_STAGE3_LAGS ], /* O 3 DIM correlation array */ + const silk_float frame[], /* I vector to correlate */ + opus_int start_lag, /* I start lag */ + opus_int sf_length, /* I sub frame length */ + opus_int nb_subfr, /* I number of subframes */ + opus_int complexity /* I Complexity setting */ +) +{ + const silk_float *target_ptr, *basis_ptr; + double energy; + opus_int k, i, j, lag_counter; + opus_int nb_cbk_search, delta, idx, cbk_size, lag_diff; + silk_float scratch_mem[ SCRATCH_SIZE ]; + const opus_int8 *Lag_range_ptr, *Lag_CB_ptr; + + celt_assert( complexity >= SILK_PE_MIN_COMPLEX ); + celt_assert( complexity <= SILK_PE_MAX_COMPLEX ); + + if( nb_subfr == PE_MAX_NB_SUBFR ) { + Lag_range_ptr = &silk_Lag_range_stage3[ complexity ][ 0 ][ 0 ]; + Lag_CB_ptr = &silk_CB_lags_stage3[ 0 ][ 0 ]; + nb_cbk_search = silk_nb_cbk_searchs_stage3[ complexity ]; + cbk_size = PE_NB_CBKS_STAGE3_MAX; + } else { + celt_assert( nb_subfr == PE_MAX_NB_SUBFR >> 1); + Lag_range_ptr = &silk_Lag_range_stage3_10_ms[ 0 ][ 0 ]; + Lag_CB_ptr = &silk_CB_lags_stage3_10_ms[ 0 ][ 0 ]; + nb_cbk_search = PE_NB_CBKS_STAGE3_10MS; + cbk_size = PE_NB_CBKS_STAGE3_10MS; + } + + target_ptr = &frame[ silk_LSHIFT( sf_length, 2 ) ]; + for( k = 0; k < nb_subfr; k++ ) { + lag_counter = 0; + + /* Calculate the energy for first lag */ + basis_ptr = target_ptr - ( start_lag + matrix_ptr( Lag_range_ptr, k, 0, 2 ) ); + energy = silk_energy_FLP( basis_ptr, sf_length ) + 1e-3; + silk_assert( energy >= 0.0 ); + scratch_mem[lag_counter] = (silk_float)energy; + lag_counter++; + + lag_diff = ( matrix_ptr( Lag_range_ptr, k, 1, 2 ) - matrix_ptr( Lag_range_ptr, k, 0, 2 ) + 1 ); + for( i = 1; i < lag_diff; i++ ) { + /* remove part outside new window */ + energy -= basis_ptr[sf_length - i] * (double)basis_ptr[sf_length - i]; + silk_assert( energy >= 0.0 ); + + /* add part that comes into window */ + energy += basis_ptr[ -i ] * (double)basis_ptr[ -i ]; + silk_assert( energy >= 0.0 ); + silk_assert( lag_counter < SCRATCH_SIZE ); + scratch_mem[lag_counter] = (silk_float)energy; + lag_counter++; + } + + delta = matrix_ptr( Lag_range_ptr, k, 0, 2 ); + for( i = 0; i < nb_cbk_search; i++ ) { + /* Fill out the 3 dim array that stores the correlations for */ + /* each code_book vector for each start lag */ + idx = matrix_ptr( Lag_CB_ptr, k, i, cbk_size ) - delta; + for( j = 0; j < PE_NB_STAGE3_LAGS; j++ ) { + silk_assert( idx + j < SCRATCH_SIZE ); + silk_assert( idx + j < lag_counter ); + energies_st3[ k ][ i ][ j ] = scratch_mem[ idx + j ]; + silk_assert( energies_st3[ k ][ i ][ j ] >= 0.0f ); + } + } + target_ptr += sf_length; + } +} diff --git a/extern/opus/silk/float/process_gains_FLP.c b/extern/opus/silk/float/process_gains_FLP.c new file mode 100644 index 0000000..c0da0da --- /dev/null +++ b/extern/opus/silk/float/process_gains_FLP.c @@ -0,0 +1,103 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FLP.h" +#include "tuning_parameters.h" + +/* Processing of gains */ +void silk_process_gains_FLP( + silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */ + opus_int condCoding /* I The type of conditional coding to use */ +) +{ + silk_shape_state_FLP *psShapeSt = &psEnc->sShape; + opus_int k; + opus_int32 pGains_Q16[ MAX_NB_SUBFR ]; + silk_float s, InvMaxSqrVal, gain, quant_offset; + + /* Gain reduction when LTP coding gain is high */ + if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) { + s = 1.0f - 0.5f * silk_sigmoid( 0.25f * ( psEncCtrl->LTPredCodGain - 12.0f ) ); + for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) { + psEncCtrl->Gains[ k ] *= s; + } + } + + /* Limit the quantized signal */ + InvMaxSqrVal = ( silk_float )( pow( 2.0f, 0.33f * ( 21.0f - psEnc->sCmn.SNR_dB_Q7 * ( 1 / 128.0f ) ) ) / psEnc->sCmn.subfr_length ); + + for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) { + /* Soft limit on ratio residual energy and squared gains */ + gain = psEncCtrl->Gains[ k ]; + gain = ( silk_float )sqrt( gain * gain + psEncCtrl->ResNrg[ k ] * InvMaxSqrVal ); + psEncCtrl->Gains[ k ] = silk_min_float( gain, 32767.0f ); + } + + /* Prepare gains for noise shaping quantization */ + for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) { + pGains_Q16[ k ] = (opus_int32)( psEncCtrl->Gains[ k ] * 65536.0f ); + } + + /* Save unquantized gains and gain Index */ + silk_memcpy( psEncCtrl->GainsUnq_Q16, pGains_Q16, psEnc->sCmn.nb_subfr * sizeof( opus_int32 ) ); + psEncCtrl->lastGainIndexPrev = psShapeSt->LastGainIndex; + + /* Quantize gains */ + silk_gains_quant( psEnc->sCmn.indices.GainsIndices, pGains_Q16, + &psShapeSt->LastGainIndex, condCoding == CODE_CONDITIONALLY, psEnc->sCmn.nb_subfr ); + + /* Overwrite unquantized gains with quantized gains and convert back to Q0 from Q16 */ + for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) { + psEncCtrl->Gains[ k ] = pGains_Q16[ k ] / 65536.0f; + } + + /* Set quantizer offset for voiced signals. Larger offset when LTP coding gain is low or tilt is high (ie low-pass) */ + if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) { + if( psEncCtrl->LTPredCodGain + psEnc->sCmn.input_tilt_Q15 * ( 1.0f / 32768.0f ) > 1.0f ) { + psEnc->sCmn.indices.quantOffsetType = 0; + } else { + psEnc->sCmn.indices.quantOffsetType = 1; + } + } + + /* Quantizer boundary adjustment */ + quant_offset = silk_Quantization_Offsets_Q10[ psEnc->sCmn.indices.signalType >> 1 ][ psEnc->sCmn.indices.quantOffsetType ] / 1024.0f; + psEncCtrl->Lambda = LAMBDA_OFFSET + + LAMBDA_DELAYED_DECISIONS * psEnc->sCmn.nStatesDelayedDecision + + LAMBDA_SPEECH_ACT * psEnc->sCmn.speech_activity_Q8 * ( 1.0f / 256.0f ) + + LAMBDA_INPUT_QUALITY * psEncCtrl->input_quality + + LAMBDA_CODING_QUALITY * psEncCtrl->coding_quality + + LAMBDA_QUANT_OFFSET * quant_offset; + + silk_assert( psEncCtrl->Lambda > 0.0f ); + silk_assert( psEncCtrl->Lambda < 2.0f ); +} diff --git a/extern/opus/silk/float/regularize_correlations_FLP.c b/extern/opus/silk/float/regularize_correlations_FLP.c new file mode 100644 index 0000000..df46126 --- /dev/null +++ b/extern/opus/silk/float/regularize_correlations_FLP.c @@ -0,0 +1,48 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FLP.h" + +/* Add noise to matrix diagonal */ +void silk_regularize_correlations_FLP( + silk_float *XX, /* I/O Correlation matrices */ + silk_float *xx, /* I/O Correlation values */ + const silk_float noise, /* I Noise energy to add */ + const opus_int D /* I Dimension of XX */ +) +{ + opus_int i; + + for( i = 0; i < D; i++ ) { + matrix_ptr( &XX[ 0 ], i, i, D ) += noise; + } + xx[ 0 ] += noise; +} diff --git a/extern/opus/silk/float/residual_energy_FLP.c b/extern/opus/silk/float/residual_energy_FLP.c new file mode 100644 index 0000000..1bd07b3 --- /dev/null +++ b/extern/opus/silk/float/residual_energy_FLP.c @@ -0,0 +1,117 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FLP.h" + +#define MAX_ITERATIONS_RESIDUAL_NRG 10 +#define REGULARIZATION_FACTOR 1e-8f + +/* Residual energy: nrg = wxx - 2 * wXx * c + c' * wXX * c */ +silk_float silk_residual_energy_covar_FLP( /* O Weighted residual energy */ + const silk_float *c, /* I Filter coefficients */ + silk_float *wXX, /* I/O Weighted correlation matrix, reg. out */ + const silk_float *wXx, /* I Weighted correlation vector */ + const silk_float wxx, /* I Weighted correlation value */ + const opus_int D /* I Dimension */ +) +{ + opus_int i, j, k; + silk_float tmp, nrg = 0.0f, regularization; + + /* Safety checks */ + celt_assert( D >= 0 ); + + regularization = REGULARIZATION_FACTOR * ( wXX[ 0 ] + wXX[ D * D - 1 ] ); + for( k = 0; k < MAX_ITERATIONS_RESIDUAL_NRG; k++ ) { + nrg = wxx; + + tmp = 0.0f; + for( i = 0; i < D; i++ ) { + tmp += wXx[ i ] * c[ i ]; + } + nrg -= 2.0f * tmp; + + /* compute c' * wXX * c, assuming wXX is symmetric */ + for( i = 0; i < D; i++ ) { + tmp = 0.0f; + for( j = i + 1; j < D; j++ ) { + tmp += matrix_c_ptr( wXX, i, j, D ) * c[ j ]; + } + nrg += c[ i ] * ( 2.0f * tmp + matrix_c_ptr( wXX, i, i, D ) * c[ i ] ); + } + if( nrg > 0 ) { + break; + } else { + /* Add white noise */ + for( i = 0; i < D; i++ ) { + matrix_c_ptr( wXX, i, i, D ) += regularization; + } + /* Increase noise for next run */ + regularization *= 2.0f; + } + } + if( k == MAX_ITERATIONS_RESIDUAL_NRG ) { + silk_assert( nrg == 0 ); + nrg = 1.0f; + } + + return nrg; +} + +/* Calculates residual energies of input subframes where all subframes have LPC_order */ +/* of preceding samples */ +void silk_residual_energy_FLP( + silk_float nrgs[ MAX_NB_SUBFR ], /* O Residual energy per subframe */ + const silk_float x[], /* I Input signal */ + silk_float a[ 2 ][ MAX_LPC_ORDER ], /* I AR coefs for each frame half */ + const silk_float gains[], /* I Quantization gains */ + const opus_int subfr_length, /* I Subframe length */ + const opus_int nb_subfr, /* I number of subframes */ + const opus_int LPC_order /* I LPC order */ +) +{ + opus_int shift; + silk_float *LPC_res_ptr, LPC_res[ ( MAX_FRAME_LENGTH + MAX_NB_SUBFR * MAX_LPC_ORDER ) / 2 ]; + + LPC_res_ptr = LPC_res + LPC_order; + shift = LPC_order + subfr_length; + + /* Filter input to create the LPC residual for each frame half, and measure subframe energies */ + silk_LPC_analysis_filter_FLP( LPC_res, a[ 0 ], x + 0 * shift, 2 * shift, LPC_order ); + nrgs[ 0 ] = ( silk_float )( gains[ 0 ] * gains[ 0 ] * silk_energy_FLP( LPC_res_ptr + 0 * shift, subfr_length ) ); + nrgs[ 1 ] = ( silk_float )( gains[ 1 ] * gains[ 1 ] * silk_energy_FLP( LPC_res_ptr + 1 * shift, subfr_length ) ); + + if( nb_subfr == MAX_NB_SUBFR ) { + silk_LPC_analysis_filter_FLP( LPC_res, a[ 1 ], x + 2 * shift, 2 * shift, LPC_order ); + nrgs[ 2 ] = ( silk_float )( gains[ 2 ] * gains[ 2 ] * silk_energy_FLP( LPC_res_ptr + 0 * shift, subfr_length ) ); + nrgs[ 3 ] = ( silk_float )( gains[ 3 ] * gains[ 3 ] * silk_energy_FLP( LPC_res_ptr + 1 * shift, subfr_length ) ); + } +} diff --git a/extern/opus/silk/float/scale_copy_vector_FLP.c b/extern/opus/silk/float/scale_copy_vector_FLP.c new file mode 100644 index 0000000..20db32b --- /dev/null +++ b/extern/opus/silk/float/scale_copy_vector_FLP.c @@ -0,0 +1,57 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FLP.h" + +/* copy and multiply a vector by a constant */ +void silk_scale_copy_vector_FLP( + silk_float *data_out, + const silk_float *data_in, + silk_float gain, + opus_int dataSize +) +{ + opus_int i, dataSize4; + + /* 4x unrolled loop */ + dataSize4 = dataSize & 0xFFFC; + for( i = 0; i < dataSize4; i += 4 ) { + data_out[ i + 0 ] = gain * data_in[ i + 0 ]; + data_out[ i + 1 ] = gain * data_in[ i + 1 ]; + data_out[ i + 2 ] = gain * data_in[ i + 2 ]; + data_out[ i + 3 ] = gain * data_in[ i + 3 ]; + } + + /* any remaining elements */ + for( ; i < dataSize; i++ ) { + data_out[ i ] = gain * data_in[ i ]; + } +} diff --git a/extern/opus/silk/float/scale_vector_FLP.c b/extern/opus/silk/float/scale_vector_FLP.c new file mode 100644 index 0000000..108fdcb --- /dev/null +++ b/extern/opus/silk/float/scale_vector_FLP.c @@ -0,0 +1,56 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FLP.h" + +/* multiply a vector by a constant */ +void silk_scale_vector_FLP( + silk_float *data1, + silk_float gain, + opus_int dataSize +) +{ + opus_int i, dataSize4; + + /* 4x unrolled loop */ + dataSize4 = dataSize & 0xFFFC; + for( i = 0; i < dataSize4; i += 4 ) { + data1[ i + 0 ] *= gain; + data1[ i + 1 ] *= gain; + data1[ i + 2 ] *= gain; + data1[ i + 3 ] *= gain; + } + + /* any remaining elements */ + for( ; i < dataSize; i++ ) { + data1[ i ] *= gain; + } +} diff --git a/extern/opus/silk/float/schur_FLP.c b/extern/opus/silk/float/schur_FLP.c new file mode 100644 index 0000000..8526c74 --- /dev/null +++ b/extern/opus/silk/float/schur_FLP.c @@ -0,0 +1,70 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FLP.h" + +silk_float silk_schur_FLP( /* O returns residual energy */ + silk_float refl_coef[], /* O reflection coefficients (length order) */ + const silk_float auto_corr[], /* I autocorrelation sequence (length order+1) */ + opus_int order /* I order */ +) +{ + opus_int k, n; + double C[ SILK_MAX_ORDER_LPC + 1 ][ 2 ]; + double Ctmp1, Ctmp2, rc_tmp; + + celt_assert( order >= 0 && order <= SILK_MAX_ORDER_LPC ); + + /* Copy correlations */ + k = 0; + do { + C[ k ][ 0 ] = C[ k ][ 1 ] = auto_corr[ k ]; + } while( ++k <= order ); + + for( k = 0; k < order; k++ ) { + /* Get reflection coefficient */ + rc_tmp = -C[ k + 1 ][ 0 ] / silk_max_float( C[ 0 ][ 1 ], 1e-9f ); + + /* Save the output */ + refl_coef[ k ] = (silk_float)rc_tmp; + + /* Update correlations */ + for( n = 0; n < order - k; n++ ) { + Ctmp1 = C[ n + k + 1 ][ 0 ]; + Ctmp2 = C[ n ][ 1 ]; + C[ n + k + 1 ][ 0 ] = Ctmp1 + Ctmp2 * rc_tmp; + C[ n ][ 1 ] = Ctmp2 + Ctmp1 * rc_tmp; + } + } + + /* Return residual energy */ + return (silk_float)C[ 0 ][ 1 ]; +} diff --git a/extern/opus/silk/float/sort_FLP.c b/extern/opus/silk/float/sort_FLP.c new file mode 100644 index 0000000..0e18f31 --- /dev/null +++ b/extern/opus/silk/float/sort_FLP.c @@ -0,0 +1,83 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/* Insertion sort (fast for already almost sorted arrays): */ +/* Best case: O(n) for an already sorted array */ +/* Worst case: O(n^2) for an inversely sorted array */ + +#include "typedef.h" +#include "SigProc_FLP.h" + +void silk_insertion_sort_decreasing_FLP( + silk_float *a, /* I/O Unsorted / Sorted vector */ + opus_int *idx, /* O Index vector for the sorted elements */ + const opus_int L, /* I Vector length */ + const opus_int K /* I Number of correctly sorted positions */ +) +{ + silk_float value; + opus_int i, j; + + /* Safety checks */ + celt_assert( K > 0 ); + celt_assert( L > 0 ); + celt_assert( L >= K ); + + /* Write start indices in index vector */ + for( i = 0; i < K; i++ ) { + idx[ i ] = i; + } + + /* Sort vector elements by value, decreasing order */ + for( i = 1; i < K; i++ ) { + value = a[ i ]; + for( j = i - 1; ( j >= 0 ) && ( value > a[ j ] ); j-- ) { + a[ j + 1 ] = a[ j ]; /* Shift value */ + idx[ j + 1 ] = idx[ j ]; /* Shift index */ + } + a[ j + 1 ] = value; /* Write value */ + idx[ j + 1 ] = i; /* Write index */ + } + + /* If less than L values are asked check the remaining values, */ + /* but only spend CPU to ensure that the K first values are correct */ + for( i = K; i < L; i++ ) { + value = a[ i ]; + if( value > a[ K - 1 ] ) { + for( j = K - 2; ( j >= 0 ) && ( value > a[ j ] ); j-- ) { + a[ j + 1 ] = a[ j ]; /* Shift value */ + idx[ j + 1 ] = idx[ j ]; /* Shift index */ + } + a[ j + 1 ] = value; /* Write value */ + idx[ j + 1 ] = i; /* Write index */ + } + } +} diff --git a/extern/opus/silk/float/structs_FLP.h b/extern/opus/silk/float/structs_FLP.h new file mode 100644 index 0000000..3150b38 --- /dev/null +++ b/extern/opus/silk/float/structs_FLP.h @@ -0,0 +1,112 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifndef SILK_STRUCTS_FLP_H +#define SILK_STRUCTS_FLP_H + +#include "typedef.h" +#include "main.h" +#include "structs.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +/********************************/ +/* Noise shaping analysis state */ +/********************************/ +typedef struct { + opus_int8 LastGainIndex; + silk_float HarmShapeGain_smth; + silk_float Tilt_smth; +} silk_shape_state_FLP; + +/********************************/ +/* Encoder state FLP */ +/********************************/ +typedef struct { + silk_encoder_state sCmn; /* Common struct, shared with fixed-point code */ + silk_shape_state_FLP sShape; /* Noise shaping state */ + + /* Buffer for find pitch and noise shape analysis */ + silk_float x_buf[ 2 * MAX_FRAME_LENGTH + LA_SHAPE_MAX ];/* Buffer for find pitch and noise shape analysis */ + silk_float LTPCorr; /* Normalized correlation from pitch lag estimator */ +} silk_encoder_state_FLP; + +/************************/ +/* Encoder control FLP */ +/************************/ +typedef struct { + /* Prediction and coding parameters */ + silk_float Gains[ MAX_NB_SUBFR ]; + silk_float PredCoef[ 2 ][ MAX_LPC_ORDER ]; /* holds interpolated and final coefficients */ + silk_float LTPCoef[LTP_ORDER * MAX_NB_SUBFR]; + silk_float LTP_scale; + opus_int pitchL[ MAX_NB_SUBFR ]; + + /* Noise shaping parameters */ + silk_float AR[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ]; + silk_float LF_MA_shp[ MAX_NB_SUBFR ]; + silk_float LF_AR_shp[ MAX_NB_SUBFR ]; + silk_float Tilt[ MAX_NB_SUBFR ]; + silk_float HarmShapeGain[ MAX_NB_SUBFR ]; + silk_float Lambda; + silk_float input_quality; + silk_float coding_quality; + + /* Measures */ + silk_float predGain; + silk_float LTPredCodGain; + silk_float ResNrg[ MAX_NB_SUBFR ]; /* Residual energy per subframe */ + + /* Parameters for CBR mode */ + opus_int32 GainsUnq_Q16[ MAX_NB_SUBFR ]; + opus_int8 lastGainIndexPrev; +} silk_encoder_control_FLP; + +/************************/ +/* Encoder Super Struct */ +/************************/ +typedef struct { + silk_encoder_state_FLP state_Fxx[ ENCODER_NUM_CHANNELS ]; + stereo_enc_state sStereo; + opus_int32 nBitsUsedLBRR; + opus_int32 nBitsExceeded; + opus_int nChannelsAPI; + opus_int nChannelsInternal; + opus_int nPrevChannelsInternal; + opus_int timeSinceSwitchAllowed_ms; + opus_int allowBandwidthSwitch; + opus_int prev_decode_only_middle; +} silk_encoder; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/extern/opus/silk/float/warped_autocorrelation_FLP.c b/extern/opus/silk/float/warped_autocorrelation_FLP.c new file mode 100644 index 0000000..09186e7 --- /dev/null +++ b/extern/opus/silk/float/warped_autocorrelation_FLP.c @@ -0,0 +1,73 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FLP.h" + +/* Autocorrelations for a warped frequency axis */ +void silk_warped_autocorrelation_FLP( + silk_float *corr, /* O Result [order + 1] */ + const silk_float *input, /* I Input data to correlate */ + const silk_float warping, /* I Warping coefficient */ + const opus_int length, /* I Length of input */ + const opus_int order /* I Correlation order (even) */ +) +{ + opus_int n, i; + double tmp1, tmp2; + double state[ MAX_SHAPE_LPC_ORDER + 1 ] = { 0 }; + double C[ MAX_SHAPE_LPC_ORDER + 1 ] = { 0 }; + + /* Order must be even */ + celt_assert( ( order & 1 ) == 0 ); + + /* Loop over samples */ + for( n = 0; n < length; n++ ) { + tmp1 = input[ n ]; + /* Loop over allpass sections */ + for( i = 0; i < order; i += 2 ) { + /* Output of allpass section */ + tmp2 = state[ i ] + warping * ( state[ i + 1 ] - tmp1 ); + state[ i ] = tmp1; + C[ i ] += state[ 0 ] * tmp1; + /* Output of allpass section */ + tmp1 = state[ i + 1 ] + warping * ( state[ i + 2 ] - tmp2 ); + state[ i + 1 ] = tmp2; + C[ i + 1 ] += state[ 0 ] * tmp2; + } + state[ order ] = tmp1; + C[ order ] += state[ 0 ] * tmp1; + } + + /* Copy correlations in silk_float output format */ + for( i = 0; i < order + 1; i++ ) { + corr[ i ] = ( silk_float )C[ i ]; + } +} diff --git a/extern/opus/silk/float/wrappers_FLP.c b/extern/opus/silk/float/wrappers_FLP.c new file mode 100644 index 0000000..ad90b87 --- /dev/null +++ b/extern/opus/silk/float/wrappers_FLP.c @@ -0,0 +1,207 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FLP.h" + +/* Wrappers. Calls flp / fix code */ + +/* Convert AR filter coefficients to NLSF parameters */ +void silk_A2NLSF_FLP( + opus_int16 *NLSF_Q15, /* O NLSF vector [ LPC_order ] */ + const silk_float *pAR, /* I LPC coefficients [ LPC_order ] */ + const opus_int LPC_order /* I LPC order */ +) +{ + opus_int i; + opus_int32 a_fix_Q16[ MAX_LPC_ORDER ]; + + for( i = 0; i < LPC_order; i++ ) { + a_fix_Q16[ i ] = silk_float2int( pAR[ i ] * 65536.0f ); + } + + silk_A2NLSF( NLSF_Q15, a_fix_Q16, LPC_order ); +} + +/* Convert LSF parameters to AR prediction filter coefficients */ +void silk_NLSF2A_FLP( + silk_float *pAR, /* O LPC coefficients [ LPC_order ] */ + const opus_int16 *NLSF_Q15, /* I NLSF vector [ LPC_order ] */ + const opus_int LPC_order, /* I LPC order */ + int arch /* I Run-time architecture */ +) +{ + opus_int i; + opus_int16 a_fix_Q12[ MAX_LPC_ORDER ]; + + silk_NLSF2A( a_fix_Q12, NLSF_Q15, LPC_order, arch ); + + for( i = 0; i < LPC_order; i++ ) { + pAR[ i ] = ( silk_float )a_fix_Q12[ i ] * ( 1.0f / 4096.0f ); + } +} + +/******************************************/ +/* Floating-point NLSF processing wrapper */ +/******************************************/ +void silk_process_NLSFs_FLP( + silk_encoder_state *psEncC, /* I/O Encoder state */ + silk_float PredCoef[ 2 ][ MAX_LPC_ORDER ], /* O Prediction coefficients */ + opus_int16 NLSF_Q15[ MAX_LPC_ORDER ], /* I/O Normalized LSFs (quant out) (0 - (2^15-1)) */ + const opus_int16 prev_NLSF_Q15[ MAX_LPC_ORDER ] /* I Previous Normalized LSFs (0 - (2^15-1)) */ +) +{ + opus_int i, j; + opus_int16 PredCoef_Q12[ 2 ][ MAX_LPC_ORDER ]; + + silk_process_NLSFs( psEncC, PredCoef_Q12, NLSF_Q15, prev_NLSF_Q15); + + for( j = 0; j < 2; j++ ) { + for( i = 0; i < psEncC->predictLPCOrder; i++ ) { + PredCoef[ j ][ i ] = ( silk_float )PredCoef_Q12[ j ][ i ] * ( 1.0f / 4096.0f ); + } + } +} + +/****************************************/ +/* Floating-point Silk NSQ wrapper */ +/****************************************/ +void silk_NSQ_wrapper_FLP( + silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */ + SideInfoIndices *psIndices, /* I/O Quantization indices */ + silk_nsq_state *psNSQ, /* I/O Noise Shaping Quantzation state */ + opus_int8 pulses[], /* O Quantized pulse signal */ + const silk_float x[] /* I Prefiltered input signal */ +) +{ + opus_int i, j; + opus_int16 x16[ MAX_FRAME_LENGTH ]; + opus_int32 Gains_Q16[ MAX_NB_SUBFR ]; + silk_DWORD_ALIGN opus_int16 PredCoef_Q12[ 2 ][ MAX_LPC_ORDER ]; + opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ]; + opus_int LTP_scale_Q14; + + /* Noise shaping parameters */ + opus_int16 AR_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ]; + opus_int32 LF_shp_Q14[ MAX_NB_SUBFR ]; /* Packs two int16 coefficients per int32 value */ + opus_int Lambda_Q10; + opus_int Tilt_Q14[ MAX_NB_SUBFR ]; + opus_int HarmShapeGain_Q14[ MAX_NB_SUBFR ]; + + /* Convert control struct to fix control struct */ + /* Noise shape parameters */ + for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) { + for( j = 0; j < psEnc->sCmn.shapingLPCOrder; j++ ) { + AR_Q13[ i * MAX_SHAPE_LPC_ORDER + j ] = silk_float2int( psEncCtrl->AR[ i * MAX_SHAPE_LPC_ORDER + j ] * 8192.0f ); + } + } + + for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) { + LF_shp_Q14[ i ] = silk_LSHIFT32( silk_float2int( psEncCtrl->LF_AR_shp[ i ] * 16384.0f ), 16 ) | + (opus_uint16)silk_float2int( psEncCtrl->LF_MA_shp[ i ] * 16384.0f ); + Tilt_Q14[ i ] = (opus_int)silk_float2int( psEncCtrl->Tilt[ i ] * 16384.0f ); + HarmShapeGain_Q14[ i ] = (opus_int)silk_float2int( psEncCtrl->HarmShapeGain[ i ] * 16384.0f ); + } + Lambda_Q10 = ( opus_int )silk_float2int( psEncCtrl->Lambda * 1024.0f ); + + /* prediction and coding parameters */ + for( i = 0; i < psEnc->sCmn.nb_subfr * LTP_ORDER; i++ ) { + LTPCoef_Q14[ i ] = (opus_int16)silk_float2int( psEncCtrl->LTPCoef[ i ] * 16384.0f ); + } + + for( j = 0; j < 2; j++ ) { + for( i = 0; i < psEnc->sCmn.predictLPCOrder; i++ ) { + PredCoef_Q12[ j ][ i ] = (opus_int16)silk_float2int( psEncCtrl->PredCoef[ j ][ i ] * 4096.0f ); + } + } + + for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) { + Gains_Q16[ i ] = silk_float2int( psEncCtrl->Gains[ i ] * 65536.0f ); + silk_assert( Gains_Q16[ i ] > 0 ); + } + + if( psIndices->signalType == TYPE_VOICED ) { + LTP_scale_Q14 = silk_LTPScales_table_Q14[ psIndices->LTP_scaleIndex ]; + } else { + LTP_scale_Q14 = 0; + } + + /* Convert input to fix */ + for( i = 0; i < psEnc->sCmn.frame_length; i++ ) { + x16[ i ] = silk_float2int( x[ i ] ); + } + + /* Call NSQ */ + if( psEnc->sCmn.nStatesDelayedDecision > 1 || psEnc->sCmn.warping_Q16 > 0 ) { + silk_NSQ_del_dec( &psEnc->sCmn, psNSQ, psIndices, x16, pulses, PredCoef_Q12[ 0 ], LTPCoef_Q14, + AR_Q13, HarmShapeGain_Q14, Tilt_Q14, LF_shp_Q14, Gains_Q16, psEncCtrl->pitchL, Lambda_Q10, LTP_scale_Q14, psEnc->sCmn.arch ); + } else { + silk_NSQ( &psEnc->sCmn, psNSQ, psIndices, x16, pulses, PredCoef_Q12[ 0 ], LTPCoef_Q14, + AR_Q13, HarmShapeGain_Q14, Tilt_Q14, LF_shp_Q14, Gains_Q16, psEncCtrl->pitchL, Lambda_Q10, LTP_scale_Q14, psEnc->sCmn.arch ); + } +} + +/***********************************************/ +/* Floating-point Silk LTP quantiation wrapper */ +/***********************************************/ +void silk_quant_LTP_gains_FLP( + silk_float B[ MAX_NB_SUBFR * LTP_ORDER ], /* O Quantized LTP gains */ + opus_int8 cbk_index[ MAX_NB_SUBFR ], /* O Codebook index */ + opus_int8 *periodicity_index, /* O Periodicity index */ + opus_int32 *sum_log_gain_Q7, /* I/O Cumulative max prediction gain */ + silk_float *pred_gain_dB, /* O LTP prediction gain */ + const silk_float XX[ MAX_NB_SUBFR * LTP_ORDER * LTP_ORDER ], /* I Correlation matrix */ + const silk_float xX[ MAX_NB_SUBFR * LTP_ORDER ], /* I Correlation vector */ + const opus_int subfr_len, /* I Number of samples per subframe */ + const opus_int nb_subfr, /* I Number of subframes */ + int arch /* I Run-time architecture */ +) +{ + opus_int i, pred_gain_dB_Q7; + opus_int16 B_Q14[ MAX_NB_SUBFR * LTP_ORDER ]; + opus_int32 XX_Q17[ MAX_NB_SUBFR * LTP_ORDER * LTP_ORDER ]; + opus_int32 xX_Q17[ MAX_NB_SUBFR * LTP_ORDER ]; + + for( i = 0; i < nb_subfr * LTP_ORDER * LTP_ORDER; i++ ) { + XX_Q17[ i ] = (opus_int32)silk_float2int( XX[ i ] * 131072.0f ); + } + for( i = 0; i < nb_subfr * LTP_ORDER; i++ ) { + xX_Q17[ i ] = (opus_int32)silk_float2int( xX[ i ] * 131072.0f ); + } + + silk_quant_LTP_gains( B_Q14, cbk_index, periodicity_index, sum_log_gain_Q7, &pred_gain_dB_Q7, XX_Q17, xX_Q17, subfr_len, nb_subfr, arch ); + + for( i = 0; i < nb_subfr * LTP_ORDER; i++ ) { + B[ i ] = (silk_float)B_Q14[ i ] * ( 1.0f / 16384.0f ); + } + + *pred_gain_dB = (silk_float)pred_gain_dB_Q7 * ( 1.0f / 128.0f ); +} diff --git a/extern/opus/silk/gain_quant.c b/extern/opus/silk/gain_quant.c new file mode 100644 index 0000000..ee65245 --- /dev/null +++ b/extern/opus/silk/gain_quant.c @@ -0,0 +1,142 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +#define OFFSET ( ( MIN_QGAIN_DB * 128 ) / 6 + 16 * 128 ) +#define SCALE_Q16 ( ( 65536 * ( N_LEVELS_QGAIN - 1 ) ) / ( ( ( MAX_QGAIN_DB - MIN_QGAIN_DB ) * 128 ) / 6 ) ) +#define INV_SCALE_Q16 ( ( 65536 * ( ( ( MAX_QGAIN_DB - MIN_QGAIN_DB ) * 128 ) / 6 ) ) / ( N_LEVELS_QGAIN - 1 ) ) + +/* Gain scalar quantization with hysteresis, uniform on log scale */ +void silk_gains_quant( + opus_int8 ind[ MAX_NB_SUBFR ], /* O gain indices */ + opus_int32 gain_Q16[ MAX_NB_SUBFR ], /* I/O gains (quantized out) */ + opus_int8 *prev_ind, /* I/O last index in previous frame */ + const opus_int conditional, /* I first gain is delta coded if 1 */ + const opus_int nb_subfr /* I number of subframes */ +) +{ + opus_int k, double_step_size_threshold; + + for( k = 0; k < nb_subfr; k++ ) { + /* Convert to log scale, scale, floor() */ + ind[ k ] = silk_SMULWB( SCALE_Q16, silk_lin2log( gain_Q16[ k ] ) - OFFSET ); + + /* Round towards previous quantized gain (hysteresis) */ + if( ind[ k ] < *prev_ind ) { + ind[ k ]++; + } + ind[ k ] = silk_LIMIT_int( ind[ k ], 0, N_LEVELS_QGAIN - 1 ); + + /* Compute delta indices and limit */ + if( k == 0 && conditional == 0 ) { + /* Full index */ + ind[ k ] = silk_LIMIT_int( ind[ k ], *prev_ind + MIN_DELTA_GAIN_QUANT, N_LEVELS_QGAIN - 1 ); + *prev_ind = ind[ k ]; + } else { + /* Delta index */ + ind[ k ] = ind[ k ] - *prev_ind; + + /* Double the quantization step size for large gain increases, so that the max gain level can be reached */ + double_step_size_threshold = 2 * MAX_DELTA_GAIN_QUANT - N_LEVELS_QGAIN + *prev_ind; + if( ind[ k ] > double_step_size_threshold ) { + ind[ k ] = double_step_size_threshold + silk_RSHIFT( ind[ k ] - double_step_size_threshold + 1, 1 ); + } + + ind[ k ] = silk_LIMIT_int( ind[ k ], MIN_DELTA_GAIN_QUANT, MAX_DELTA_GAIN_QUANT ); + + /* Accumulate deltas */ + if( ind[ k ] > double_step_size_threshold ) { + *prev_ind += silk_LSHIFT( ind[ k ], 1 ) - double_step_size_threshold; + *prev_ind = silk_min_int( *prev_ind, N_LEVELS_QGAIN - 1 ); + } else { + *prev_ind += ind[ k ]; + } + + /* Shift to make non-negative */ + ind[ k ] -= MIN_DELTA_GAIN_QUANT; + } + + /* Scale and convert to linear scale */ + gain_Q16[ k ] = silk_log2lin( silk_min_32( silk_SMULWB( INV_SCALE_Q16, *prev_ind ) + OFFSET, 3967 ) ); /* 3967 = 31 in Q7 */ + } +} + +/* Gains scalar dequantization, uniform on log scale */ +void silk_gains_dequant( + opus_int32 gain_Q16[ MAX_NB_SUBFR ], /* O quantized gains */ + const opus_int8 ind[ MAX_NB_SUBFR ], /* I gain indices */ + opus_int8 *prev_ind, /* I/O last index in previous frame */ + const opus_int conditional, /* I first gain is delta coded if 1 */ + const opus_int nb_subfr /* I number of subframes */ +) +{ + opus_int k, ind_tmp, double_step_size_threshold; + + for( k = 0; k < nb_subfr; k++ ) { + if( k == 0 && conditional == 0 ) { + /* Gain index is not allowed to go down more than 16 steps (~21.8 dB) */ + *prev_ind = silk_max_int( ind[ k ], *prev_ind - 16 ); + } else { + /* Delta index */ + ind_tmp = ind[ k ] + MIN_DELTA_GAIN_QUANT; + + /* Accumulate deltas */ + double_step_size_threshold = 2 * MAX_DELTA_GAIN_QUANT - N_LEVELS_QGAIN + *prev_ind; + if( ind_tmp > double_step_size_threshold ) { + *prev_ind += silk_LSHIFT( ind_tmp, 1 ) - double_step_size_threshold; + } else { + *prev_ind += ind_tmp; + } + } + *prev_ind = silk_LIMIT_int( *prev_ind, 0, N_LEVELS_QGAIN - 1 ); + + /* Scale and convert to linear scale */ + gain_Q16[ k ] = silk_log2lin( silk_min_32( silk_SMULWB( INV_SCALE_Q16, *prev_ind ) + OFFSET, 3967 ) ); /* 3967 = 31 in Q7 */ + } +} + +/* Compute unique identifier of gain indices vector */ +opus_int32 silk_gains_ID( /* O returns unique identifier of gains */ + const opus_int8 ind[ MAX_NB_SUBFR ], /* I gain indices */ + const opus_int nb_subfr /* I number of subframes */ +) +{ + opus_int k; + opus_int32 gainsID; + + gainsID = 0; + for( k = 0; k < nb_subfr; k++ ) { + gainsID = silk_ADD_LSHIFT32( ind[ k ], gainsID, 8 ); + } + + return gainsID; +} diff --git a/extern/opus/silk/init_decoder.c b/extern/opus/silk/init_decoder.c new file mode 100644 index 0000000..16c03dc --- /dev/null +++ b/extern/opus/silk/init_decoder.c @@ -0,0 +1,57 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/************************/ +/* Init Decoder State */ +/************************/ +opus_int silk_init_decoder( + silk_decoder_state *psDec /* I/O Decoder state pointer */ +) +{ + /* Clear the entire encoder state, except anything copied */ + silk_memset( psDec, 0, sizeof( silk_decoder_state ) ); + + /* Used to deactivate LSF interpolation */ + psDec->first_frame_after_reset = 1; + psDec->prev_gain_Q16 = 65536; + psDec->arch = opus_select_arch(); + + /* Reset CNG state */ + silk_CNG_Reset( psDec ); + + /* Reset PLC state */ + silk_PLC_Reset( psDec ); + + return(0); +} + diff --git a/extern/opus/silk/init_encoder.c b/extern/opus/silk/init_encoder.c new file mode 100644 index 0000000..65995c3 --- /dev/null +++ b/extern/opus/silk/init_encoder.c @@ -0,0 +1,64 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#ifdef FIXED_POINT +#include "main_FIX.h" +#else +#include "main_FLP.h" +#endif +#include "tuning_parameters.h" +#include "cpu_support.h" + +/*********************************/ +/* Initialize Silk Encoder state */ +/*********************************/ +opus_int silk_init_encoder( + silk_encoder_state_Fxx *psEnc, /* I/O Pointer to Silk FIX encoder state */ + int arch /* I Run-time architecture */ +) +{ + opus_int ret = 0; + + /* Clear the entire encoder state */ + silk_memset( psEnc, 0, sizeof( silk_encoder_state_Fxx ) ); + + psEnc->sCmn.arch = arch; + + psEnc->sCmn.variable_HP_smth1_Q15 = silk_LSHIFT( silk_lin2log( SILK_FIX_CONST( VARIABLE_HP_MIN_CUTOFF_HZ, 16 ) ) - ( 16 << 7 ), 8 ); + psEnc->sCmn.variable_HP_smth2_Q15 = psEnc->sCmn.variable_HP_smth1_Q15; + + /* Used to deactivate LSF interpolation, pitch prediction */ + psEnc->sCmn.first_frame_after_reset = 1; + + /* Initialize Silk VAD */ + ret += silk_VAD_Init( &psEnc->sCmn.sVAD ); + + return ret; +} diff --git a/extern/opus/silk/inner_prod_aligned.c b/extern/opus/silk/inner_prod_aligned.c new file mode 100644 index 0000000..257ae9e --- /dev/null +++ b/extern/opus/silk/inner_prod_aligned.c @@ -0,0 +1,47 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" + +opus_int32 silk_inner_prod_aligned_scale( + const opus_int16 *const inVec1, /* I input vector 1 */ + const opus_int16 *const inVec2, /* I input vector 2 */ + const opus_int scale, /* I number of bits to shift */ + const opus_int len /* I vector lengths */ +) +{ + opus_int i; + opus_int32 sum = 0; + for( i = 0; i < len; i++ ) { + sum = silk_ADD_RSHIFT32( sum, silk_SMULBB( inVec1[ i ], inVec2[ i ] ), scale ); + } + return sum; +} diff --git a/extern/opus/silk/interpolate.c b/extern/opus/silk/interpolate.c new file mode 100644 index 0000000..833c28e --- /dev/null +++ b/extern/opus/silk/interpolate.c @@ -0,0 +1,51 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/* Interpolate two vectors */ +void silk_interpolate( + opus_int16 xi[ MAX_LPC_ORDER ], /* O interpolated vector */ + const opus_int16 x0[ MAX_LPC_ORDER ], /* I first vector */ + const opus_int16 x1[ MAX_LPC_ORDER ], /* I second vector */ + const opus_int ifact_Q2, /* I interp. factor, weight on 2nd vector */ + const opus_int d /* I number of parameters */ +) +{ + opus_int i; + + celt_assert( ifact_Q2 >= 0 ); + celt_assert( ifact_Q2 <= 4 ); + + for( i = 0; i < d; i++ ) { + xi[ i ] = (opus_int16)silk_ADD_RSHIFT( x0[ i ], silk_SMULBB( x1[ i ] - x0[ i ], ifact_Q2 ), 2 ); + } +} diff --git a/extern/opus/silk/lin2log.c b/extern/opus/silk/lin2log.c new file mode 100644 index 0000000..0d5155a --- /dev/null +++ b/extern/opus/silk/lin2log.c @@ -0,0 +1,46 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" +/* Approximation of 128 * log2() (very close inverse of silk_log2lin()) */ +/* Convert input to a log scale */ +opus_int32 silk_lin2log( + const opus_int32 inLin /* I input in linear scale */ +) +{ + opus_int32 lz, frac_Q7; + + silk_CLZ_FRAC( inLin, &lz, &frac_Q7 ); + + /* Piece-wise parabolic approximation */ + return silk_ADD_LSHIFT32( silk_SMLAWB( frac_Q7, silk_MUL( frac_Q7, 128 - frac_Q7 ), 179 ), 31 - lz, 7 ); +} + diff --git a/extern/opus/silk/log2lin.c b/extern/opus/silk/log2lin.c new file mode 100644 index 0000000..b7c48e4 --- /dev/null +++ b/extern/opus/silk/log2lin.c @@ -0,0 +1,58 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" + +/* Approximation of 2^() (very close inverse of silk_lin2log()) */ +/* Convert input to a linear scale */ +opus_int32 silk_log2lin( + const opus_int32 inLog_Q7 /* I input on log scale */ +) +{ + opus_int32 out, frac_Q7; + + if( inLog_Q7 < 0 ) { + return 0; + } else if ( inLog_Q7 >= 3967 ) { + return silk_int32_MAX; + } + + out = silk_LSHIFT( 1, silk_RSHIFT( inLog_Q7, 7 ) ); + frac_Q7 = inLog_Q7 & 0x7F; + if( inLog_Q7 < 2048 ) { + /* Piece-wise parabolic approximation */ + out = silk_ADD_RSHIFT32( out, silk_MUL( out, silk_SMLAWB( frac_Q7, silk_SMULBB( frac_Q7, 128 - frac_Q7 ), -174 ) ), 7 ); + } else { + /* Piece-wise parabolic approximation */ + out = silk_MLA( out, silk_RSHIFT( out, 7 ), silk_SMLAWB( frac_Q7, silk_SMULBB( frac_Q7, 128 - frac_Q7 ), -174 ) ); + } + return out; +} diff --git a/extern/opus/silk/macros.h b/extern/opus/silk/macros.h new file mode 100644 index 0000000..3c67b6e --- /dev/null +++ b/extern/opus/silk/macros.h @@ -0,0 +1,151 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifndef SILK_MACROS_H +#define SILK_MACROS_H + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "opus_types.h" +#include "opus_defines.h" +#include "arch.h" + +/* This is an OPUS_INLINE header file for general platform. */ + +/* (a32 * (opus_int32)((opus_int16)(b32))) >> 16 output have to be 32bit int */ +#if OPUS_FAST_INT64 +#define silk_SMULWB(a32, b32) ((opus_int32)(((a32) * (opus_int64)((opus_int16)(b32))) >> 16)) +#else +#define silk_SMULWB(a32, b32) ((((a32) >> 16) * (opus_int32)((opus_int16)(b32))) + ((((a32) & 0x0000FFFF) * (opus_int32)((opus_int16)(b32))) >> 16)) +#endif + +/* a32 + (b32 * (opus_int32)((opus_int16)(c32))) >> 16 output have to be 32bit int */ +#if OPUS_FAST_INT64 +#define silk_SMLAWB(a32, b32, c32) ((opus_int32)((a32) + (((b32) * (opus_int64)((opus_int16)(c32))) >> 16))) +#else +#define silk_SMLAWB(a32, b32, c32) ((a32) + ((((b32) >> 16) * (opus_int32)((opus_int16)(c32))) + ((((b32) & 0x0000FFFF) * (opus_int32)((opus_int16)(c32))) >> 16))) +#endif + +/* (a32 * (b32 >> 16)) >> 16 */ +#if OPUS_FAST_INT64 +#define silk_SMULWT(a32, b32) ((opus_int32)(((a32) * (opus_int64)((b32) >> 16)) >> 16)) +#else +#define silk_SMULWT(a32, b32) (((a32) >> 16) * ((b32) >> 16) + ((((a32) & 0x0000FFFF) * ((b32) >> 16)) >> 16)) +#endif + +/* a32 + (b32 * (c32 >> 16)) >> 16 */ +#if OPUS_FAST_INT64 +#define silk_SMLAWT(a32, b32, c32) ((opus_int32)((a32) + (((b32) * ((opus_int64)(c32) >> 16)) >> 16))) +#else +#define silk_SMLAWT(a32, b32, c32) ((a32) + (((b32) >> 16) * ((c32) >> 16)) + ((((b32) & 0x0000FFFF) * ((c32) >> 16)) >> 16)) +#endif + +/* (opus_int32)((opus_int16)(a3))) * (opus_int32)((opus_int16)(b32)) output have to be 32bit int */ +#define silk_SMULBB(a32, b32) ((opus_int32)((opus_int16)(a32)) * (opus_int32)((opus_int16)(b32))) + +/* a32 + (opus_int32)((opus_int16)(b32)) * (opus_int32)((opus_int16)(c32)) output have to be 32bit int */ +#define silk_SMLABB(a32, b32, c32) ((a32) + ((opus_int32)((opus_int16)(b32))) * (opus_int32)((opus_int16)(c32))) + +/* (opus_int32)((opus_int16)(a32)) * (b32 >> 16) */ +#define silk_SMULBT(a32, b32) ((opus_int32)((opus_int16)(a32)) * ((b32) >> 16)) + +/* a32 + (opus_int32)((opus_int16)(b32)) * (c32 >> 16) */ +#define silk_SMLABT(a32, b32, c32) ((a32) + ((opus_int32)((opus_int16)(b32))) * ((c32) >> 16)) + +/* a64 + (b32 * c32) */ +#define silk_SMLAL(a64, b32, c32) (silk_ADD64((a64), ((opus_int64)(b32) * (opus_int64)(c32)))) + +/* (a32 * b32) >> 16 */ +#if OPUS_FAST_INT64 +#define silk_SMULWW(a32, b32) ((opus_int32)(((opus_int64)(a32) * (b32)) >> 16)) +#else +#define silk_SMULWW(a32, b32) silk_MLA(silk_SMULWB((a32), (b32)), (a32), silk_RSHIFT_ROUND((b32), 16)) +#endif + +/* a32 + ((b32 * c32) >> 16) */ +#if OPUS_FAST_INT64 +#define silk_SMLAWW(a32, b32, c32) ((opus_int32)((a32) + (((opus_int64)(b32) * (c32)) >> 16))) +#else +#define silk_SMLAWW(a32, b32, c32) silk_MLA(silk_SMLAWB((a32), (b32), (c32)), (b32), silk_RSHIFT_ROUND((c32), 16)) +#endif + +/* add/subtract with output saturated */ +#define silk_ADD_SAT32(a, b) ((((opus_uint32)(a) + (opus_uint32)(b)) & 0x80000000) == 0 ? \ + ((((a) & (b)) & 0x80000000) != 0 ? silk_int32_MIN : (a)+(b)) : \ + ((((a) | (b)) & 0x80000000) == 0 ? silk_int32_MAX : (a)+(b)) ) + +#define silk_SUB_SAT32(a, b) ((((opus_uint32)(a)-(opus_uint32)(b)) & 0x80000000) == 0 ? \ + (( (a) & ((b)^0x80000000) & 0x80000000) ? silk_int32_MIN : (a)-(b)) : \ + ((((a)^0x80000000) & (b) & 0x80000000) ? silk_int32_MAX : (a)-(b)) ) + +#if defined(MIPSr1_ASM) +#include "mips/macros_mipsr1.h" +#endif + +#include "ecintrin.h" +#ifndef OVERRIDE_silk_CLZ16 +static OPUS_INLINE opus_int32 silk_CLZ16(opus_int16 in16) +{ + return 32 - EC_ILOG(in16<<16|0x8000); +} +#endif + +#ifndef OVERRIDE_silk_CLZ32 +static OPUS_INLINE opus_int32 silk_CLZ32(opus_int32 in32) +{ + return in32 ? 32 - EC_ILOG(in32) : 32; +} +#endif + +/* Row based */ +#define matrix_ptr(Matrix_base_adr, row, column, N) \ + (*((Matrix_base_adr) + ((row)*(N)+(column)))) +#define matrix_adr(Matrix_base_adr, row, column, N) \ + ((Matrix_base_adr) + ((row)*(N)+(column))) + +/* Column based */ +#ifndef matrix_c_ptr +# define matrix_c_ptr(Matrix_base_adr, row, column, M) \ + (*((Matrix_base_adr) + ((row)+(M)*(column)))) +#endif + +#ifdef OPUS_ARM_INLINE_ASM +#include "arm/macros_armv4.h" +#endif + +#ifdef OPUS_ARM_INLINE_EDSP +#include "arm/macros_armv5e.h" +#endif + +#ifdef OPUS_ARM_PRESUME_AARCH64_NEON_INTR +#include "arm/macros_arm64.h" +#endif + +#endif /* SILK_MACROS_H */ + diff --git a/extern/opus/silk/main.h b/extern/opus/silk/main.h new file mode 100644 index 0000000..1a33eed --- /dev/null +++ b/extern/opus/silk/main.h @@ -0,0 +1,476 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifndef SILK_MAIN_H +#define SILK_MAIN_H + +#include "SigProc_FIX.h" +#include "define.h" +#include "structs.h" +#include "tables.h" +#include "PLC.h" +#include "control.h" +#include "debug.h" +#include "entenc.h" +#include "entdec.h" + +#if defined(OPUS_X86_MAY_HAVE_SSE4_1) +#include "x86/main_sse.h" +#endif + +#if (defined(OPUS_ARM_ASM) || defined(OPUS_ARM_MAY_HAVE_NEON_INTR)) +#include "arm/NSQ_del_dec_arm.h" +#endif + +/* Convert Left/Right stereo signal to adaptive Mid/Side representation */ +void silk_stereo_LR_to_MS( + stereo_enc_state *state, /* I/O State */ + opus_int16 x1[], /* I/O Left input signal, becomes mid signal */ + opus_int16 x2[], /* I/O Right input signal, becomes side signal */ + opus_int8 ix[ 2 ][ 3 ], /* O Quantization indices */ + opus_int8 *mid_only_flag, /* O Flag: only mid signal coded */ + opus_int32 mid_side_rates_bps[], /* O Bitrates for mid and side signals */ + opus_int32 total_rate_bps, /* I Total bitrate */ + opus_int prev_speech_act_Q8, /* I Speech activity level in previous frame */ + opus_int toMono, /* I Last frame before a stereo->mono transition */ + opus_int fs_kHz, /* I Sample rate (kHz) */ + opus_int frame_length /* I Number of samples */ +); + +/* Convert adaptive Mid/Side representation to Left/Right stereo signal */ +void silk_stereo_MS_to_LR( + stereo_dec_state *state, /* I/O State */ + opus_int16 x1[], /* I/O Left input signal, becomes mid signal */ + opus_int16 x2[], /* I/O Right input signal, becomes side signal */ + const opus_int32 pred_Q13[], /* I Predictors */ + opus_int fs_kHz, /* I Samples rate (kHz) */ + opus_int frame_length /* I Number of samples */ +); + +/* Find least-squares prediction gain for one signal based on another and quantize it */ +opus_int32 silk_stereo_find_predictor( /* O Returns predictor in Q13 */ + opus_int32 *ratio_Q14, /* O Ratio of residual and mid energies */ + const opus_int16 x[], /* I Basis signal */ + const opus_int16 y[], /* I Target signal */ + opus_int32 mid_res_amp_Q0[], /* I/O Smoothed mid, residual norms */ + opus_int length, /* I Number of samples */ + opus_int smooth_coef_Q16 /* I Smoothing coefficient */ +); + +/* Quantize mid/side predictors */ +void silk_stereo_quant_pred( + opus_int32 pred_Q13[], /* I/O Predictors (out: quantized) */ + opus_int8 ix[ 2 ][ 3 ] /* O Quantization indices */ +); + +/* Entropy code the mid/side quantization indices */ +void silk_stereo_encode_pred( + ec_enc *psRangeEnc, /* I/O Compressor data structure */ + opus_int8 ix[ 2 ][ 3 ] /* I Quantization indices */ +); + +/* Entropy code the mid-only flag */ +void silk_stereo_encode_mid_only( + ec_enc *psRangeEnc, /* I/O Compressor data structure */ + opus_int8 mid_only_flag +); + +/* Decode mid/side predictors */ +void silk_stereo_decode_pred( + ec_dec *psRangeDec, /* I/O Compressor data structure */ + opus_int32 pred_Q13[] /* O Predictors */ +); + +/* Decode mid-only flag */ +void silk_stereo_decode_mid_only( + ec_dec *psRangeDec, /* I/O Compressor data structure */ + opus_int *decode_only_mid /* O Flag that only mid channel has been coded */ +); + +/* Encodes signs of excitation */ +void silk_encode_signs( + ec_enc *psRangeEnc, /* I/O Compressor data structure */ + const opus_int8 pulses[], /* I pulse signal */ + opus_int length, /* I length of input */ + const opus_int signalType, /* I Signal type */ + const opus_int quantOffsetType, /* I Quantization offset type */ + const opus_int sum_pulses[ MAX_NB_SHELL_BLOCKS ] /* I Sum of absolute pulses per block */ +); + +/* Decodes signs of excitation */ +void silk_decode_signs( + ec_dec *psRangeDec, /* I/O Compressor data structure */ + opus_int16 pulses[], /* I/O pulse signal */ + opus_int length, /* I length of input */ + const opus_int signalType, /* I Signal type */ + const opus_int quantOffsetType, /* I Quantization offset type */ + const opus_int sum_pulses[ MAX_NB_SHELL_BLOCKS ] /* I Sum of absolute pulses per block */ +); + +/* Check encoder control struct */ +opus_int check_control_input( + silk_EncControlStruct *encControl /* I Control structure */ +); + +/* Control internal sampling rate */ +opus_int silk_control_audio_bandwidth( + silk_encoder_state *psEncC, /* I/O Pointer to Silk encoder state */ + silk_EncControlStruct *encControl /* I Control structure */ +); + +/* Control SNR of redidual quantizer */ +opus_int silk_control_SNR( + silk_encoder_state *psEncC, /* I/O Pointer to Silk encoder state */ + opus_int32 TargetRate_bps /* I Target max bitrate (bps) */ +); + +/***************/ +/* Shell coder */ +/***************/ + +/* Encode quantization indices of excitation */ +void silk_encode_pulses( + ec_enc *psRangeEnc, /* I/O compressor data structure */ + const opus_int signalType, /* I Signal type */ + const opus_int quantOffsetType, /* I quantOffsetType */ + opus_int8 pulses[], /* I quantization indices */ + const opus_int frame_length /* I Frame length */ +); + +/* Shell encoder, operates on one shell code frame of 16 pulses */ +void silk_shell_encoder( + ec_enc *psRangeEnc, /* I/O compressor data structure */ + const opus_int *pulses0 /* I data: nonnegative pulse amplitudes */ +); + +/* Shell decoder, operates on one shell code frame of 16 pulses */ +void silk_shell_decoder( + opus_int16 *pulses0, /* O data: nonnegative pulse amplitudes */ + ec_dec *psRangeDec, /* I/O Compressor data structure */ + const opus_int pulses4 /* I number of pulses per pulse-subframe */ +); + +/* Gain scalar quantization with hysteresis, uniform on log scale */ +void silk_gains_quant( + opus_int8 ind[ MAX_NB_SUBFR ], /* O gain indices */ + opus_int32 gain_Q16[ MAX_NB_SUBFR ], /* I/O gains (quantized out) */ + opus_int8 *prev_ind, /* I/O last index in previous frame */ + const opus_int conditional, /* I first gain is delta coded if 1 */ + const opus_int nb_subfr /* I number of subframes */ +); + +/* Gains scalar dequantization, uniform on log scale */ +void silk_gains_dequant( + opus_int32 gain_Q16[ MAX_NB_SUBFR ], /* O quantized gains */ + const opus_int8 ind[ MAX_NB_SUBFR ], /* I gain indices */ + opus_int8 *prev_ind, /* I/O last index in previous frame */ + const opus_int conditional, /* I first gain is delta coded if 1 */ + const opus_int nb_subfr /* I number of subframes */ +); + +/* Compute unique identifier of gain indices vector */ +opus_int32 silk_gains_ID( /* O returns unique identifier of gains */ + const opus_int8 ind[ MAX_NB_SUBFR ], /* I gain indices */ + const opus_int nb_subfr /* I number of subframes */ +); + +/* Interpolate two vectors */ +void silk_interpolate( + opus_int16 xi[ MAX_LPC_ORDER ], /* O interpolated vector */ + const opus_int16 x0[ MAX_LPC_ORDER ], /* I first vector */ + const opus_int16 x1[ MAX_LPC_ORDER ], /* I second vector */ + const opus_int ifact_Q2, /* I interp. factor, weight on 2nd vector */ + const opus_int d /* I number of parameters */ +); + +/* LTP tap quantizer */ +void silk_quant_LTP_gains( + opus_int16 B_Q14[ MAX_NB_SUBFR * LTP_ORDER ], /* O Quantized LTP gains */ + opus_int8 cbk_index[ MAX_NB_SUBFR ], /* O Codebook Index */ + opus_int8 *periodicity_index, /* O Periodicity Index */ + opus_int32 *sum_gain_dB_Q7, /* I/O Cumulative max prediction gain */ + opus_int *pred_gain_dB_Q7, /* O LTP prediction gain */ + const opus_int32 XX_Q17[ MAX_NB_SUBFR*LTP_ORDER*LTP_ORDER ], /* I Correlation matrix in Q18 */ + const opus_int32 xX_Q17[ MAX_NB_SUBFR*LTP_ORDER ], /* I Correlation vector in Q18 */ + const opus_int subfr_len, /* I Number of samples per subframe */ + const opus_int nb_subfr, /* I Number of subframes */ + int arch /* I Run-time architecture */ +); + +/* Entropy constrained matrix-weighted VQ, for a single input data vector */ +void silk_VQ_WMat_EC_c( + opus_int8 *ind, /* O index of best codebook vector */ + opus_int32 *res_nrg_Q15, /* O best residual energy */ + opus_int32 *rate_dist_Q8, /* O best total bitrate */ + opus_int *gain_Q7, /* O sum of absolute LTP coefficients */ + const opus_int32 *XX_Q17, /* I correlation matrix */ + const opus_int32 *xX_Q17, /* I correlation vector */ + const opus_int8 *cb_Q7, /* I codebook */ + const opus_uint8 *cb_gain_Q7, /* I codebook effective gain */ + const opus_uint8 *cl_Q5, /* I code length for each codebook vector */ + const opus_int subfr_len, /* I number of samples per subframe */ + const opus_int32 max_gain_Q7, /* I maximum sum of absolute LTP coefficients */ + const opus_int L /* I number of vectors in codebook */ +); + +#if !defined(OVERRIDE_silk_VQ_WMat_EC) +#define silk_VQ_WMat_EC(ind, res_nrg_Q15, rate_dist_Q8, gain_Q7, XX_Q17, xX_Q17, cb_Q7, cb_gain_Q7, cl_Q5, subfr_len, max_gain_Q7, L, arch) \ + ((void)(arch),silk_VQ_WMat_EC_c(ind, res_nrg_Q15, rate_dist_Q8, gain_Q7, XX_Q17, xX_Q17, cb_Q7, cb_gain_Q7, cl_Q5, subfr_len, max_gain_Q7, L)) +#endif + +/************************************/ +/* Noise shaping quantization (NSQ) */ +/************************************/ + +void silk_NSQ_c( + const silk_encoder_state *psEncC, /* I Encoder State */ + silk_nsq_state *NSQ, /* I/O NSQ state */ + SideInfoIndices *psIndices, /* I/O Quantization Indices */ + const opus_int16 x16[], /* I Input */ + opus_int8 pulses[], /* O Quantized pulse signal */ + const opus_int16 PredCoef_Q12[ 2 * MAX_LPC_ORDER ], /* I Short term prediction coefs */ + const opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ], /* I Long term prediction coefs */ + const opus_int16 AR_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ], /* I Noise shaping coefs */ + const opus_int HarmShapeGain_Q14[ MAX_NB_SUBFR ], /* I Long term shaping coefs */ + const opus_int Tilt_Q14[ MAX_NB_SUBFR ], /* I Spectral tilt */ + const opus_int32 LF_shp_Q14[ MAX_NB_SUBFR ], /* I Low frequency shaping coefs */ + const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I Quantization step sizes */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lags */ + const opus_int Lambda_Q10, /* I Rate/distortion tradeoff */ + const opus_int LTP_scale_Q14 /* I LTP state scaling */ +); + +#if !defined(OVERRIDE_silk_NSQ) +#define silk_NSQ(psEncC, NSQ, psIndices, x16, pulses, PredCoef_Q12, LTPCoef_Q14, AR_Q13, \ + HarmShapeGain_Q14, Tilt_Q14, LF_shp_Q14, Gains_Q16, pitchL, Lambda_Q10, LTP_scale_Q14, arch) \ + ((void)(arch),silk_NSQ_c(psEncC, NSQ, psIndices, x16, pulses, PredCoef_Q12, LTPCoef_Q14, AR_Q13, \ + HarmShapeGain_Q14, Tilt_Q14, LF_shp_Q14, Gains_Q16, pitchL, Lambda_Q10, LTP_scale_Q14)) +#endif + +/* Noise shaping using delayed decision */ +void silk_NSQ_del_dec_c( + const silk_encoder_state *psEncC, /* I Encoder State */ + silk_nsq_state *NSQ, /* I/O NSQ state */ + SideInfoIndices *psIndices, /* I/O Quantization Indices */ + const opus_int16 x16[], /* I Input */ + opus_int8 pulses[], /* O Quantized pulse signal */ + const opus_int16 PredCoef_Q12[ 2 * MAX_LPC_ORDER ], /* I Short term prediction coefs */ + const opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ], /* I Long term prediction coefs */ + const opus_int16 AR_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ], /* I Noise shaping coefs */ + const opus_int HarmShapeGain_Q14[ MAX_NB_SUBFR ], /* I Long term shaping coefs */ + const opus_int Tilt_Q14[ MAX_NB_SUBFR ], /* I Spectral tilt */ + const opus_int32 LF_shp_Q14[ MAX_NB_SUBFR ], /* I Low frequency shaping coefs */ + const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I Quantization step sizes */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lags */ + const opus_int Lambda_Q10, /* I Rate/distortion tradeoff */ + const opus_int LTP_scale_Q14 /* I LTP state scaling */ +); + +#if !defined(OVERRIDE_silk_NSQ_del_dec) +#define silk_NSQ_del_dec(psEncC, NSQ, psIndices, x16, pulses, PredCoef_Q12, LTPCoef_Q14, AR_Q13, \ + HarmShapeGain_Q14, Tilt_Q14, LF_shp_Q14, Gains_Q16, pitchL, Lambda_Q10, LTP_scale_Q14, arch) \ + ((void)(arch),silk_NSQ_del_dec_c(psEncC, NSQ, psIndices, x16, pulses, PredCoef_Q12, LTPCoef_Q14, AR_Q13, \ + HarmShapeGain_Q14, Tilt_Q14, LF_shp_Q14, Gains_Q16, pitchL, Lambda_Q10, LTP_scale_Q14)) +#endif + +/************/ +/* Silk VAD */ +/************/ +/* Initialize the Silk VAD */ +opus_int silk_VAD_Init( /* O Return value, 0 if success */ + silk_VAD_state *psSilk_VAD /* I/O Pointer to Silk VAD state */ +); + +/* Get speech activity level in Q8 */ +opus_int silk_VAD_GetSA_Q8_c( /* O Return value, 0 if success */ + silk_encoder_state *psEncC, /* I/O Encoder state */ + const opus_int16 pIn[] /* I PCM input */ +); + +#if !defined(OVERRIDE_silk_VAD_GetSA_Q8) +#define silk_VAD_GetSA_Q8(psEnC, pIn, arch) ((void)(arch),silk_VAD_GetSA_Q8_c(psEnC, pIn)) +#endif + +/* Low-pass filter with variable cutoff frequency based on */ +/* piece-wise linear interpolation between elliptic filters */ +/* Start by setting transition_frame_no = 1; */ +void silk_LP_variable_cutoff( + silk_LP_state *psLP, /* I/O LP filter state */ + opus_int16 *frame, /* I/O Low-pass filtered output signal */ + const opus_int frame_length /* I Frame length */ +); + +/******************/ +/* NLSF Quantizer */ +/******************/ +/* Limit, stabilize, convert and quantize NLSFs */ +void silk_process_NLSFs( + silk_encoder_state *psEncC, /* I/O Encoder state */ + opus_int16 PredCoef_Q12[ 2 ][ MAX_LPC_ORDER ], /* O Prediction coefficients */ + opus_int16 pNLSF_Q15[ MAX_LPC_ORDER ], /* I/O Normalized LSFs (quant out) (0 - (2^15-1)) */ + const opus_int16 prev_NLSFq_Q15[ MAX_LPC_ORDER ] /* I Previous Normalized LSFs (0 - (2^15-1)) */ +); + +opus_int32 silk_NLSF_encode( /* O Returns RD value in Q25 */ + opus_int8 *NLSFIndices, /* I Codebook path vector [ LPC_ORDER + 1 ] */ + opus_int16 *pNLSF_Q15, /* I/O Quantized NLSF vector [ LPC_ORDER ] */ + const silk_NLSF_CB_struct *psNLSF_CB, /* I Codebook object */ + const opus_int16 *pW_QW, /* I NLSF weight vector [ LPC_ORDER ] */ + const opus_int NLSF_mu_Q20, /* I Rate weight for the RD optimization */ + const opus_int nSurvivors, /* I Max survivors after first stage */ + const opus_int signalType /* I Signal type: 0/1/2 */ +); + +/* Compute quantization errors for an LPC_order element input vector for a VQ codebook */ +void silk_NLSF_VQ( + opus_int32 err_Q26[], /* O Quantization errors [K] */ + const opus_int16 in_Q15[], /* I Input vectors to be quantized [LPC_order] */ + const opus_uint8 pCB_Q8[], /* I Codebook vectors [K*LPC_order] */ + const opus_int16 pWght_Q9[], /* I Codebook weights [K*LPC_order] */ + const opus_int K, /* I Number of codebook vectors */ + const opus_int LPC_order /* I Number of LPCs */ +); + +/* Delayed-decision quantizer for NLSF residuals */ +opus_int32 silk_NLSF_del_dec_quant( /* O Returns RD value in Q25 */ + opus_int8 indices[], /* O Quantization indices [ order ] */ + const opus_int16 x_Q10[], /* I Input [ order ] */ + const opus_int16 w_Q5[], /* I Weights [ order ] */ + const opus_uint8 pred_coef_Q8[], /* I Backward predictor coefs [ order ] */ + const opus_int16 ec_ix[], /* I Indices to entropy coding tables [ order ] */ + const opus_uint8 ec_rates_Q5[], /* I Rates [] */ + const opus_int quant_step_size_Q16, /* I Quantization step size */ + const opus_int16 inv_quant_step_size_Q6, /* I Inverse quantization step size */ + const opus_int32 mu_Q20, /* I R/D tradeoff */ + const opus_int16 order /* I Number of input values */ +); + +/* Unpack predictor values and indices for entropy coding tables */ +void silk_NLSF_unpack( + opus_int16 ec_ix[], /* O Indices to entropy tables [ LPC_ORDER ] */ + opus_uint8 pred_Q8[], /* O LSF predictor [ LPC_ORDER ] */ + const silk_NLSF_CB_struct *psNLSF_CB, /* I Codebook object */ + const opus_int CB1_index /* I Index of vector in first LSF codebook */ +); + +/***********************/ +/* NLSF vector decoder */ +/***********************/ +void silk_NLSF_decode( + opus_int16 *pNLSF_Q15, /* O Quantized NLSF vector [ LPC_ORDER ] */ + opus_int8 *NLSFIndices, /* I Codebook path vector [ LPC_ORDER + 1 ] */ + const silk_NLSF_CB_struct *psNLSF_CB /* I Codebook object */ +); + +/****************************************************/ +/* Decoder Functions */ +/****************************************************/ +opus_int silk_init_decoder( + silk_decoder_state *psDec /* I/O Decoder state pointer */ +); + +/* Set decoder sampling rate */ +opus_int silk_decoder_set_fs( + silk_decoder_state *psDec, /* I/O Decoder state pointer */ + opus_int fs_kHz, /* I Sampling frequency (kHz) */ + opus_int32 fs_API_Hz /* I API Sampling frequency (Hz) */ +); + +/****************/ +/* Decode frame */ +/****************/ +opus_int silk_decode_frame( + silk_decoder_state *psDec, /* I/O Pointer to Silk decoder state */ + ec_dec *psRangeDec, /* I/O Compressor data structure */ + opus_int16 pOut[], /* O Pointer to output speech frame */ + opus_int32 *pN, /* O Pointer to size of output frame */ + opus_int lostFlag, /* I 0: no loss, 1 loss, 2 decode fec */ + opus_int condCoding, /* I The type of conditional coding to use */ + int arch /* I Run-time architecture */ +); + +/* Decode indices from bitstream */ +void silk_decode_indices( + silk_decoder_state *psDec, /* I/O State */ + ec_dec *psRangeDec, /* I/O Compressor data structure */ + opus_int FrameIndex, /* I Frame number */ + opus_int decode_LBRR, /* I Flag indicating LBRR data is being decoded */ + opus_int condCoding /* I The type of conditional coding to use */ +); + +/* Decode parameters from payload */ +void silk_decode_parameters( + silk_decoder_state *psDec, /* I/O State */ + silk_decoder_control *psDecCtrl, /* I/O Decoder control */ + opus_int condCoding /* I The type of conditional coding to use */ +); + +/* Core decoder. Performs inverse NSQ operation LTP + LPC */ +void silk_decode_core( + silk_decoder_state *psDec, /* I/O Decoder state */ + silk_decoder_control *psDecCtrl, /* I Decoder control */ + opus_int16 xq[], /* O Decoded speech */ + const opus_int16 pulses[ MAX_FRAME_LENGTH ], /* I Pulse signal */ + int arch /* I Run-time architecture */ +); + +/* Decode quantization indices of excitation (Shell coding) */ +void silk_decode_pulses( + ec_dec *psRangeDec, /* I/O Compressor data structure */ + opus_int16 pulses[], /* O Excitation signal */ + const opus_int signalType, /* I Sigtype */ + const opus_int quantOffsetType, /* I quantOffsetType */ + const opus_int frame_length /* I Frame length */ +); + +/******************/ +/* CNG */ +/******************/ + +/* Reset CNG */ +void silk_CNG_Reset( + silk_decoder_state *psDec /* I/O Decoder state */ +); + +/* Updates CNG estimate, and applies the CNG when packet was lost */ +void silk_CNG( + silk_decoder_state *psDec, /* I/O Decoder state */ + silk_decoder_control *psDecCtrl, /* I/O Decoder control */ + opus_int16 frame[], /* I/O Signal */ + opus_int length /* I Length of residual */ +); + +/* Encoding of various parameters */ +void silk_encode_indices( + silk_encoder_state *psEncC, /* I/O Encoder state */ + ec_enc *psRangeEnc, /* I/O Compressor data structure */ + opus_int FrameIndex, /* I Frame number */ + opus_int encode_LBRR, /* I Flag indicating LBRR data is being encoded */ + opus_int condCoding /* I The type of conditional coding to use */ +); + +#endif diff --git a/extern/opus/silk/mips/NSQ_del_dec_mipsr1.h b/extern/opus/silk/mips/NSQ_del_dec_mipsr1.h new file mode 100644 index 0000000..cd70713 --- /dev/null +++ b/extern/opus/silk/mips/NSQ_del_dec_mipsr1.h @@ -0,0 +1,410 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifndef __NSQ_DEL_DEC_MIPSR1_H__ +#define __NSQ_DEL_DEC_MIPSR1_H__ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" +#include "stack_alloc.h" + +#define OVERRIDE_silk_noise_shape_quantizer_del_dec +static inline void silk_noise_shape_quantizer_del_dec( + silk_nsq_state *NSQ, /* I/O NSQ state */ + NSQ_del_dec_struct psDelDec[], /* I/O Delayed decision states */ + opus_int signalType, /* I Signal type */ + const opus_int32 x_Q10[], /* I */ + opus_int8 pulses[], /* O */ + opus_int16 xq[], /* O */ + opus_int32 sLTP_Q15[], /* I/O LTP filter state */ + opus_int32 delayedGain_Q10[], /* I/O Gain delay buffer */ + const opus_int16 a_Q12[], /* I Short term prediction coefs */ + const opus_int16 b_Q14[], /* I Long term prediction coefs */ + const opus_int16 AR_shp_Q13[], /* I Noise shaping coefs */ + opus_int lag, /* I Pitch lag */ + opus_int32 HarmShapeFIRPacked_Q14, /* I */ + opus_int Tilt_Q14, /* I Spectral tilt */ + opus_int32 LF_shp_Q14, /* I */ + opus_int32 Gain_Q16, /* I */ + opus_int Lambda_Q10, /* I */ + opus_int offset_Q10, /* I */ + opus_int length, /* I Input length */ + opus_int subfr, /* I Subframe number */ + opus_int shapingLPCOrder, /* I Shaping LPC filter order */ + opus_int predictLPCOrder, /* I Prediction filter order */ + opus_int warping_Q16, /* I */ + opus_int nStatesDelayedDecision, /* I Number of states in decision tree */ + opus_int *smpl_buf_idx, /* I/O Index to newest samples in buffers */ + opus_int decisionDelay, /* I */ + int arch /* I */ +) +{ + opus_int i, j, k, Winner_ind, RDmin_ind, RDmax_ind, last_smple_idx; + opus_int32 Winner_rand_state; + opus_int32 LTP_pred_Q14, LPC_pred_Q14, n_AR_Q14, n_LTP_Q14; + opus_int32 n_LF_Q14, r_Q10, rr_Q10, rd1_Q10, rd2_Q10, RDmin_Q10, RDmax_Q10; + opus_int32 q1_Q0, q1_Q10, q2_Q10, exc_Q14, LPC_exc_Q14, xq_Q14, Gain_Q10; + opus_int32 tmp1, tmp2, sLF_AR_shp_Q14; + opus_int32 *pred_lag_ptr, *shp_lag_ptr, *psLPC_Q14; + NSQ_sample_struct psSampleState[ MAX_DEL_DEC_STATES ][ 2 ]; + NSQ_del_dec_struct *psDD; + NSQ_sample_struct *psSS; + opus_int16 b_Q14_0, b_Q14_1, b_Q14_2, b_Q14_3, b_Q14_4; + opus_int16 a_Q12_0, a_Q12_1, a_Q12_2, a_Q12_3, a_Q12_4, a_Q12_5, a_Q12_6; + opus_int16 a_Q12_7, a_Q12_8, a_Q12_9, a_Q12_10, a_Q12_11, a_Q12_12, a_Q12_13; + opus_int16 a_Q12_14, a_Q12_15; + + opus_int32 cur, prev, next; + + /*Unused.*/ + (void)arch; + + //Intialize b_Q14 variables + b_Q14_0 = b_Q14[ 0 ]; + b_Q14_1 = b_Q14[ 1 ]; + b_Q14_2 = b_Q14[ 2 ]; + b_Q14_3 = b_Q14[ 3 ]; + b_Q14_4 = b_Q14[ 4 ]; + + //Intialize a_Q12 variables + a_Q12_0 = a_Q12[0]; + a_Q12_1 = a_Q12[1]; + a_Q12_2 = a_Q12[2]; + a_Q12_3 = a_Q12[3]; + a_Q12_4 = a_Q12[4]; + a_Q12_5 = a_Q12[5]; + a_Q12_6 = a_Q12[6]; + a_Q12_7 = a_Q12[7]; + a_Q12_8 = a_Q12[8]; + a_Q12_9 = a_Q12[9]; + a_Q12_10 = a_Q12[10]; + a_Q12_11 = a_Q12[11]; + a_Q12_12 = a_Q12[12]; + a_Q12_13 = a_Q12[13]; + a_Q12_14 = a_Q12[14]; + a_Q12_15 = a_Q12[15]; + + long long temp64; + + silk_assert( nStatesDelayedDecision > 0 ); + + shp_lag_ptr = &NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - lag + HARM_SHAPE_FIR_TAPS / 2 ]; + pred_lag_ptr = &sLTP_Q15[ NSQ->sLTP_buf_idx - lag + LTP_ORDER / 2 ]; + Gain_Q10 = silk_RSHIFT( Gain_Q16, 6 ); + + for( i = 0; i < length; i++ ) { + /* Perform common calculations used in all states */ + + /* Long-term prediction */ + if( signalType == TYPE_VOICED ) { + /* Unrolled loop */ + /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */ + temp64 = __builtin_mips_mult(pred_lag_ptr[ 0 ], b_Q14_0 ); + temp64 = __builtin_mips_madd( temp64, pred_lag_ptr[ -1 ], b_Q14_1 ); + temp64 = __builtin_mips_madd( temp64, pred_lag_ptr[ -2 ], b_Q14_2 ); + temp64 = __builtin_mips_madd( temp64, pred_lag_ptr[ -3 ], b_Q14_3 ); + temp64 = __builtin_mips_madd( temp64, pred_lag_ptr[ -4 ], b_Q14_4 ); + temp64 += 32768; + LTP_pred_Q14 = __builtin_mips_extr_w(temp64, 16); + LTP_pred_Q14 = silk_LSHIFT( LTP_pred_Q14, 1 ); /* Q13 -> Q14 */ + pred_lag_ptr++; + } else { + LTP_pred_Q14 = 0; + } + + /* Long-term shaping */ + if( lag > 0 ) { + /* Symmetric, packed FIR coefficients */ + n_LTP_Q14 = silk_SMULWB( silk_ADD32( shp_lag_ptr[ 0 ], shp_lag_ptr[ -2 ] ), HarmShapeFIRPacked_Q14 ); + n_LTP_Q14 = silk_SMLAWT( n_LTP_Q14, shp_lag_ptr[ -1 ], HarmShapeFIRPacked_Q14 ); + n_LTP_Q14 = silk_SUB_LSHIFT32( LTP_pred_Q14, n_LTP_Q14, 2 ); /* Q12 -> Q14 */ + shp_lag_ptr++; + } else { + n_LTP_Q14 = 0; + } + + for( k = 0; k < nStatesDelayedDecision; k++ ) { + /* Delayed decision state */ + psDD = &psDelDec[ k ]; + + /* Sample state */ + psSS = psSampleState[ k ]; + + /* Generate dither */ + psDD->Seed = silk_RAND( psDD->Seed ); + + /* Pointer used in short term prediction and shaping */ + psLPC_Q14 = &psDD->sLPC_Q14[ NSQ_LPC_BUF_LENGTH - 1 + i ]; + /* Short-term prediction */ + silk_assert( predictLPCOrder == 10 || predictLPCOrder == 16 ); + temp64 = __builtin_mips_mult(psLPC_Q14[ 0 ], a_Q12_0 ); + temp64 = __builtin_mips_madd( temp64, psLPC_Q14[ -1 ], a_Q12_1 ); + temp64 = __builtin_mips_madd( temp64, psLPC_Q14[ -2 ], a_Q12_2 ); + temp64 = __builtin_mips_madd( temp64, psLPC_Q14[ -3 ], a_Q12_3 ); + temp64 = __builtin_mips_madd( temp64, psLPC_Q14[ -4 ], a_Q12_4 ); + temp64 = __builtin_mips_madd( temp64, psLPC_Q14[ -5 ], a_Q12_5 ); + temp64 = __builtin_mips_madd( temp64, psLPC_Q14[ -6 ], a_Q12_6 ); + temp64 = __builtin_mips_madd( temp64, psLPC_Q14[ -7 ], a_Q12_7 ); + temp64 = __builtin_mips_madd( temp64, psLPC_Q14[ -8 ], a_Q12_8 ); + temp64 = __builtin_mips_madd( temp64, psLPC_Q14[ -9 ], a_Q12_9 ); + if( predictLPCOrder == 16 ) { + temp64 = __builtin_mips_madd( temp64, psLPC_Q14[ -10 ], a_Q12_10 ); + temp64 = __builtin_mips_madd( temp64, psLPC_Q14[ -11 ], a_Q12_11 ); + temp64 = __builtin_mips_madd( temp64, psLPC_Q14[ -12 ], a_Q12_12 ); + temp64 = __builtin_mips_madd( temp64, psLPC_Q14[ -13 ], a_Q12_13 ); + temp64 = __builtin_mips_madd( temp64, psLPC_Q14[ -14 ], a_Q12_14 ); + temp64 = __builtin_mips_madd( temp64, psLPC_Q14[ -15 ], a_Q12_15 ); + } + temp64 += 32768; + LPC_pred_Q14 = __builtin_mips_extr_w(temp64, 16); + + LPC_pred_Q14 = silk_LSHIFT( LPC_pred_Q14, 4 ); /* Q10 -> Q14 */ + + /* Noise shape feedback */ + silk_assert( ( shapingLPCOrder & 1 ) == 0 ); /* check that order is even */ + /* Output of lowpass section */ + tmp2 = silk_SMLAWB( psLPC_Q14[ 0 ], psDD->sAR2_Q14[ 0 ], warping_Q16 ); + /* Output of allpass section */ + tmp1 = silk_SMLAWB( psDD->sAR2_Q14[ 0 ], psDD->sAR2_Q14[ 1 ] - tmp2, warping_Q16 ); + psDD->sAR2_Q14[ 0 ] = tmp2; + + temp64 = __builtin_mips_mult(tmp2, AR_shp_Q13[ 0 ] ); + + prev = psDD->sAR2_Q14[ 1 ]; + + /* Loop over allpass sections */ + for( j = 2; j < shapingLPCOrder; j += 2 ) { + cur = psDD->sAR2_Q14[ j ]; + next = psDD->sAR2_Q14[ j+1 ]; + /* Output of allpass section */ + tmp2 = silk_SMLAWB( prev, cur - tmp1, warping_Q16 ); + psDD->sAR2_Q14[ j - 1 ] = tmp1; + temp64 = __builtin_mips_madd( temp64, tmp1, AR_shp_Q13[ j - 1 ] ); + temp64 = __builtin_mips_madd( temp64, tmp2, AR_shp_Q13[ j ] ); + /* Output of allpass section */ + tmp1 = silk_SMLAWB( cur, next - tmp2, warping_Q16 ); + psDD->sAR2_Q14[ j + 0 ] = tmp2; + prev = next; + } + psDD->sAR2_Q14[ shapingLPCOrder - 1 ] = tmp1; + temp64 = __builtin_mips_madd( temp64, tmp1, AR_shp_Q13[ shapingLPCOrder - 1 ] ); + temp64 += 32768; + n_AR_Q14 = __builtin_mips_extr_w(temp64, 16); + n_AR_Q14 = silk_LSHIFT( n_AR_Q14, 1 ); /* Q11 -> Q12 */ + n_AR_Q14 = silk_SMLAWB( n_AR_Q14, psDD->LF_AR_Q14, Tilt_Q14 ); /* Q12 */ + n_AR_Q14 = silk_LSHIFT( n_AR_Q14, 2 ); /* Q12 -> Q14 */ + + n_LF_Q14 = silk_SMULWB( psDD->Shape_Q14[ *smpl_buf_idx ], LF_shp_Q14 ); /* Q12 */ + n_LF_Q14 = silk_SMLAWT( n_LF_Q14, psDD->LF_AR_Q14, LF_shp_Q14 ); /* Q12 */ + n_LF_Q14 = silk_LSHIFT( n_LF_Q14, 2 ); /* Q12 -> Q14 */ + + /* Input minus prediction plus noise feedback */ + /* r = x[ i ] - LTP_pred - LPC_pred + n_AR + n_Tilt + n_LF + n_LTP */ + tmp1 = silk_ADD32( n_AR_Q14, n_LF_Q14 ); /* Q14 */ + tmp2 = silk_ADD32( n_LTP_Q14, LPC_pred_Q14 ); /* Q13 */ + tmp1 = silk_SUB32( tmp2, tmp1 ); /* Q13 */ + tmp1 = silk_RSHIFT_ROUND( tmp1, 4 ); /* Q10 */ + + r_Q10 = silk_SUB32( x_Q10[ i ], tmp1 ); /* residual error Q10 */ + + /* Flip sign depending on dither */ + if ( psDD->Seed < 0 ) { + r_Q10 = -r_Q10; + } + r_Q10 = silk_LIMIT_32( r_Q10, -(31 << 10), 30 << 10 ); + + /* Find two quantization level candidates and measure their rate-distortion */ + q1_Q10 = silk_SUB32( r_Q10, offset_Q10 ); + q1_Q0 = silk_RSHIFT( q1_Q10, 10 ); + if( q1_Q0 > 0 ) { + q1_Q10 = silk_SUB32( silk_LSHIFT( q1_Q0, 10 ), QUANT_LEVEL_ADJUST_Q10 ); + q1_Q10 = silk_ADD32( q1_Q10, offset_Q10 ); + q2_Q10 = silk_ADD32( q1_Q10, 1024 ); + rd1_Q10 = silk_SMULBB( q1_Q10, Lambda_Q10 ); + rd2_Q10 = silk_SMULBB( q2_Q10, Lambda_Q10 ); + } else if( q1_Q0 == 0 ) { + q1_Q10 = offset_Q10; + q2_Q10 = silk_ADD32( q1_Q10, 1024 - QUANT_LEVEL_ADJUST_Q10 ); + rd1_Q10 = silk_SMULBB( q1_Q10, Lambda_Q10 ); + rd2_Q10 = silk_SMULBB( q2_Q10, Lambda_Q10 ); + } else if( q1_Q0 == -1 ) { + q2_Q10 = offset_Q10; + q1_Q10 = silk_SUB32( q2_Q10, 1024 - QUANT_LEVEL_ADJUST_Q10 ); + rd1_Q10 = silk_SMULBB( -q1_Q10, Lambda_Q10 ); + rd2_Q10 = silk_SMULBB( q2_Q10, Lambda_Q10 ); + } else { /* q1_Q0 < -1 */ + q1_Q10 = silk_ADD32( silk_LSHIFT( q1_Q0, 10 ), QUANT_LEVEL_ADJUST_Q10 ); + q1_Q10 = silk_ADD32( q1_Q10, offset_Q10 ); + q2_Q10 = silk_ADD32( q1_Q10, 1024 ); + rd1_Q10 = silk_SMULBB( -q1_Q10, Lambda_Q10 ); + rd2_Q10 = silk_SMULBB( -q2_Q10, Lambda_Q10 ); + } + rr_Q10 = silk_SUB32( r_Q10, q1_Q10 ); + rd1_Q10 = silk_RSHIFT( silk_SMLABB( rd1_Q10, rr_Q10, rr_Q10 ), 10 ); + rr_Q10 = silk_SUB32( r_Q10, q2_Q10 ); + rd2_Q10 = silk_RSHIFT( silk_SMLABB( rd2_Q10, rr_Q10, rr_Q10 ), 10 ); + + if( rd1_Q10 < rd2_Q10 ) { + psSS[ 0 ].RD_Q10 = silk_ADD32( psDD->RD_Q10, rd1_Q10 ); + psSS[ 1 ].RD_Q10 = silk_ADD32( psDD->RD_Q10, rd2_Q10 ); + psSS[ 0 ].Q_Q10 = q1_Q10; + psSS[ 1 ].Q_Q10 = q2_Q10; + } else { + psSS[ 0 ].RD_Q10 = silk_ADD32( psDD->RD_Q10, rd2_Q10 ); + psSS[ 1 ].RD_Q10 = silk_ADD32( psDD->RD_Q10, rd1_Q10 ); + psSS[ 0 ].Q_Q10 = q2_Q10; + psSS[ 1 ].Q_Q10 = q1_Q10; + } + + /* Update states for best quantization */ + + /* Quantized excitation */ + exc_Q14 = silk_LSHIFT32( psSS[ 0 ].Q_Q10, 4 ); + if ( psDD->Seed < 0 ) { + exc_Q14 = -exc_Q14; + } + + /* Add predictions */ + LPC_exc_Q14 = silk_ADD32( exc_Q14, LTP_pred_Q14 ); + xq_Q14 = silk_ADD32( LPC_exc_Q14, LPC_pred_Q14 ); + + /* Update states */ + sLF_AR_shp_Q14 = silk_SUB32( xq_Q14, n_AR_Q14 ); + psSS[ 0 ].sLTP_shp_Q14 = silk_SUB32( sLF_AR_shp_Q14, n_LF_Q14 ); + psSS[ 0 ].LF_AR_Q14 = sLF_AR_shp_Q14; + psSS[ 0 ].LPC_exc_Q14 = LPC_exc_Q14; + psSS[ 0 ].xq_Q14 = xq_Q14; + + /* Update states for second best quantization */ + + /* Quantized excitation */ + exc_Q14 = silk_LSHIFT32( psSS[ 1 ].Q_Q10, 4 ); + if ( psDD->Seed < 0 ) { + exc_Q14 = -exc_Q14; + } + + + /* Add predictions */ + LPC_exc_Q14 = silk_ADD32( exc_Q14, LTP_pred_Q14 ); + xq_Q14 = silk_ADD32( LPC_exc_Q14, LPC_pred_Q14 ); + + /* Update states */ + sLF_AR_shp_Q14 = silk_SUB32( xq_Q14, n_AR_Q14 ); + psSS[ 1 ].sLTP_shp_Q14 = silk_SUB32( sLF_AR_shp_Q14, n_LF_Q14 ); + psSS[ 1 ].LF_AR_Q14 = sLF_AR_shp_Q14; + psSS[ 1 ].LPC_exc_Q14 = LPC_exc_Q14; + psSS[ 1 ].xq_Q14 = xq_Q14; + } + + *smpl_buf_idx = ( *smpl_buf_idx - 1 ) % DECISION_DELAY; + if( *smpl_buf_idx < 0 ) *smpl_buf_idx += DECISION_DELAY; + last_smple_idx = ( *smpl_buf_idx + decisionDelay ) % DECISION_DELAY; + + /* Find winner */ + RDmin_Q10 = psSampleState[ 0 ][ 0 ].RD_Q10; + Winner_ind = 0; + for( k = 1; k < nStatesDelayedDecision; k++ ) { + if( psSampleState[ k ][ 0 ].RD_Q10 < RDmin_Q10 ) { + RDmin_Q10 = psSampleState[ k ][ 0 ].RD_Q10; + Winner_ind = k; + } + } + + /* Increase RD values of expired states */ + 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 ) { + psSampleState[ k ][ 0 ].RD_Q10 = silk_ADD32( psSampleState[ k ][ 0 ].RD_Q10, silk_int32_MAX >> 4 ); + psSampleState[ k ][ 1 ].RD_Q10 = silk_ADD32( psSampleState[ k ][ 1 ].RD_Q10, silk_int32_MAX >> 4 ); + silk_assert( psSampleState[ k ][ 0 ].RD_Q10 >= 0 ); + } + } + + /* Find worst in first set and best in second set */ + RDmax_Q10 = psSampleState[ 0 ][ 0 ].RD_Q10; + RDmin_Q10 = psSampleState[ 0 ][ 1 ].RD_Q10; + RDmax_ind = 0; + RDmin_ind = 0; + for( k = 1; k < nStatesDelayedDecision; k++ ) { + /* find worst in first set */ + if( psSampleState[ k ][ 0 ].RD_Q10 > RDmax_Q10 ) { + RDmax_Q10 = psSampleState[ k ][ 0 ].RD_Q10; + RDmax_ind = k; + } + /* find best in second set */ + if( psSampleState[ k ][ 1 ].RD_Q10 < RDmin_Q10 ) { + RDmin_Q10 = psSampleState[ k ][ 1 ].RD_Q10; + RDmin_ind = k; + } + } + + /* Replace a state if best from second set outperforms worst in first set */ + if( RDmin_Q10 < RDmax_Q10 ) { + silk_memcpy( ( (opus_int32 *)&psDelDec[ RDmax_ind ] ) + i, + ( (opus_int32 *)&psDelDec[ RDmin_ind ] ) + i, sizeof( NSQ_del_dec_struct ) - i * sizeof( opus_int32) ); + silk_memcpy( &psSampleState[ RDmax_ind ][ 0 ], &psSampleState[ RDmin_ind ][ 1 ], sizeof( NSQ_sample_struct ) ); + } + + /* Write samples from winner to output and long-term filter states */ + psDD = &psDelDec[ Winner_ind ]; + if( subfr > 0 || i >= decisionDelay ) { + pulses[ i - decisionDelay ] = (opus_int8)silk_RSHIFT_ROUND( psDD->Q_Q10[ last_smple_idx ], 10 ); + xq[ i - decisionDelay ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( + silk_SMULWW( psDD->Xq_Q14[ last_smple_idx ], delayedGain_Q10[ last_smple_idx ] ), 8 ) ); + NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - decisionDelay ] = psDD->Shape_Q14[ last_smple_idx ]; + sLTP_Q15[ NSQ->sLTP_buf_idx - decisionDelay ] = psDD->Pred_Q15[ last_smple_idx ]; + } + NSQ->sLTP_shp_buf_idx++; + NSQ->sLTP_buf_idx++; + + /* Update states */ + for( k = 0; k < nStatesDelayedDecision; k++ ) { + psDD = &psDelDec[ k ]; + psSS = &psSampleState[ k ][ 0 ]; + psDD->LF_AR_Q14 = psSS->LF_AR_Q14; + psDD->sLPC_Q14[ NSQ_LPC_BUF_LENGTH + i ] = psSS->xq_Q14; + psDD->Xq_Q14[ *smpl_buf_idx ] = psSS->xq_Q14; + psDD->Q_Q10[ *smpl_buf_idx ] = psSS->Q_Q10; + psDD->Pred_Q15[ *smpl_buf_idx ] = silk_LSHIFT32( psSS->LPC_exc_Q14, 1 ); + psDD->Shape_Q14[ *smpl_buf_idx ] = psSS->sLTP_shp_Q14; + psDD->Seed = silk_ADD32_ovflw( psDD->Seed, silk_RSHIFT_ROUND( psSS->Q_Q10, 10 ) ); + psDD->RandState[ *smpl_buf_idx ] = psDD->Seed; + psDD->RD_Q10 = psSS->RD_Q10; + } + delayedGain_Q10[ *smpl_buf_idx ] = Gain_Q10; + } + /* Update LPC states */ + for( k = 0; k < nStatesDelayedDecision; k++ ) { + psDD = &psDelDec[ k ]; + silk_memcpy( psDD->sLPC_Q14, &psDD->sLPC_Q14[ length ], NSQ_LPC_BUF_LENGTH * sizeof( opus_int32 ) ); + } +} + +#endif /* __NSQ_DEL_DEC_MIPSR1_H__ */ diff --git a/extern/opus/silk/mips/macros_mipsr1.h b/extern/opus/silk/mips/macros_mipsr1.h new file mode 100644 index 0000000..12ed981 --- /dev/null +++ b/extern/opus/silk/mips/macros_mipsr1.h @@ -0,0 +1,92 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + + +#ifndef __SILK_MACROS_MIPSR1_H__ +#define __SILK_MACROS_MIPSR1_H__ + +#define mips_clz(x) __builtin_clz(x) + +#undef silk_SMULWB +static inline int silk_SMULWB(int a, int b) +{ + long long ac; + int c; + + ac = __builtin_mips_mult(a, (opus_int32)(opus_int16)b); + c = __builtin_mips_extr_w(ac, 16); + + return c; +} + +#undef silk_SMLAWB +#define silk_SMLAWB(a32, b32, c32) ((a32) + silk_SMULWB(b32, c32)) + +#undef silk_SMULWW +static inline int silk_SMULWW(int a, int b) +{ + long long ac; + int c; + + ac = __builtin_mips_mult(a, b); + c = __builtin_mips_extr_w(ac, 16); + + return c; +} + +#undef silk_SMLAWW +static inline int silk_SMLAWW(int a, int b, int c) +{ + long long ac; + int res; + + ac = __builtin_mips_mult(b, c); + res = __builtin_mips_extr_w(ac, 16); + res += a; + + return res; +} + +#define OVERRIDE_silk_CLZ16 +static inline opus_int32 silk_CLZ16(opus_int16 in16) +{ + int re32; + opus_int32 in32 = (opus_int32 )in16; + re32 = mips_clz(in32); + re32-=16; + return re32; +} + +#define OVERRIDE_silk_CLZ32 +static inline opus_int32 silk_CLZ32(opus_int32 in32) +{ + int re32; + re32 = mips_clz(in32); + return re32; +} + +#endif /* __SILK_MACROS_MIPSR1_H__ */ diff --git a/extern/opus/silk/mips/sigproc_fix_mipsr1.h b/extern/opus/silk/mips/sigproc_fix_mipsr1.h new file mode 100644 index 0000000..51520c0 --- /dev/null +++ b/extern/opus/silk/mips/sigproc_fix_mipsr1.h @@ -0,0 +1,60 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifndef SILK_SIGPROC_FIX_MIPSR1_H +#define SILK_SIGPROC_FIX_MIPSR1_H + +#undef silk_SAT16 +static inline short int silk_SAT16(int a) +{ + int c; + c = __builtin_mips_shll_s_w(a, 16); + c = c>>16; + + return c; +} + +#undef silk_LSHIFT_SAT32 +static inline int silk_LSHIFT_SAT32(int a, int shift) +{ + int r; + + r = __builtin_mips_shll_s_w(a, shift); + + return r; +} + +#undef silk_RSHIFT_ROUND +static inline int silk_RSHIFT_ROUND(int a, int shift) +{ + int r; + + r = __builtin_mips_shra_r_w(a, shift); + return r; +} + +#endif /* SILK_SIGPROC_FIX_MIPSR1_H */ diff --git a/extern/opus/silk/pitch_est_defines.h b/extern/opus/silk/pitch_est_defines.h new file mode 100644 index 0000000..e1e4b5d --- /dev/null +++ b/extern/opus/silk/pitch_est_defines.h @@ -0,0 +1,88 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifndef SILK_PE_DEFINES_H +#define SILK_PE_DEFINES_H + +#include "SigProc_FIX.h" + +/********************************************************/ +/* Definitions for pitch estimator */ +/********************************************************/ + +#define PE_MAX_FS_KHZ 16 /* Maximum sampling frequency used */ + +#define PE_MAX_NB_SUBFR 4 +#define PE_SUBFR_LENGTH_MS 5 /* 5 ms */ + +#define PE_LTP_MEM_LENGTH_MS ( 4 * PE_SUBFR_LENGTH_MS ) + +#define PE_MAX_FRAME_LENGTH_MS ( PE_LTP_MEM_LENGTH_MS + PE_MAX_NB_SUBFR * PE_SUBFR_LENGTH_MS ) +#define PE_MAX_FRAME_LENGTH ( PE_MAX_FRAME_LENGTH_MS * PE_MAX_FS_KHZ ) +#define PE_MAX_FRAME_LENGTH_ST_1 ( PE_MAX_FRAME_LENGTH >> 2 ) +#define PE_MAX_FRAME_LENGTH_ST_2 ( PE_MAX_FRAME_LENGTH >> 1 ) + +#define PE_MAX_LAG_MS 18 /* 18 ms -> 56 Hz */ +#define PE_MIN_LAG_MS 2 /* 2 ms -> 500 Hz */ +#define PE_MAX_LAG ( PE_MAX_LAG_MS * PE_MAX_FS_KHZ ) +#define PE_MIN_LAG ( PE_MIN_LAG_MS * PE_MAX_FS_KHZ ) + +#define PE_D_SRCH_LENGTH 24 + +#define PE_NB_STAGE3_LAGS 5 + +#define PE_NB_CBKS_STAGE2 3 +#define PE_NB_CBKS_STAGE2_EXT 11 + +#define PE_NB_CBKS_STAGE3_MAX 34 +#define PE_NB_CBKS_STAGE3_MID 24 +#define PE_NB_CBKS_STAGE3_MIN 16 + +#define PE_NB_CBKS_STAGE3_10MS 12 +#define PE_NB_CBKS_STAGE2_10MS 3 + +#define PE_SHORTLAG_BIAS 0.2f /* for logarithmic weighting */ +#define PE_PREVLAG_BIAS 0.2f /* for logarithmic weighting */ +#define PE_FLATCONTOUR_BIAS 0.05f + +#define SILK_PE_MIN_COMPLEX 0 +#define SILK_PE_MID_COMPLEX 1 +#define SILK_PE_MAX_COMPLEX 2 + +/* Tables for 20 ms frames */ +extern const opus_int8 silk_CB_lags_stage2[ PE_MAX_NB_SUBFR ][ PE_NB_CBKS_STAGE2_EXT ]; +extern const opus_int8 silk_CB_lags_stage3[ PE_MAX_NB_SUBFR ][ PE_NB_CBKS_STAGE3_MAX ]; +extern const opus_int8 silk_Lag_range_stage3[ SILK_PE_MAX_COMPLEX + 1 ] [ PE_MAX_NB_SUBFR ][ 2 ]; +extern const opus_int8 silk_nb_cbk_searchs_stage3[ SILK_PE_MAX_COMPLEX + 1 ]; + +/* Tables for 10 ms frames */ +extern const opus_int8 silk_CB_lags_stage2_10_ms[ PE_MAX_NB_SUBFR >> 1][ 3 ]; +extern const opus_int8 silk_CB_lags_stage3_10_ms[ PE_MAX_NB_SUBFR >> 1 ][ 12 ]; +extern const opus_int8 silk_Lag_range_stage3_10_ms[ PE_MAX_NB_SUBFR >> 1 ][ 2 ]; + +#endif + diff --git a/extern/opus/silk/pitch_est_tables.c b/extern/opus/silk/pitch_est_tables.c new file mode 100644 index 0000000..81a8bac --- /dev/null +++ b/extern/opus/silk/pitch_est_tables.c @@ -0,0 +1,99 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "typedef.h" +#include "pitch_est_defines.h" + +const opus_int8 silk_CB_lags_stage2_10_ms[ PE_MAX_NB_SUBFR >> 1][ PE_NB_CBKS_STAGE2_10MS ] = +{ + {0, 1, 0}, + {0, 0, 1} +}; + +const opus_int8 silk_CB_lags_stage3_10_ms[ PE_MAX_NB_SUBFR >> 1 ][ PE_NB_CBKS_STAGE3_10MS ] = +{ + { 0, 0, 1,-1, 1,-1, 2,-2, 2,-2, 3,-3}, + { 0, 1, 0, 1,-1, 2,-1, 2,-2, 3,-2, 3} +}; + +const opus_int8 silk_Lag_range_stage3_10_ms[ PE_MAX_NB_SUBFR >> 1 ][ 2 ] = +{ + {-3, 7}, + {-2, 7} +}; + +const opus_int8 silk_CB_lags_stage2[ PE_MAX_NB_SUBFR ][ PE_NB_CBKS_STAGE2_EXT ] = +{ + {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} +}; + +const opus_int8 silk_CB_lags_stage3[ PE_MAX_NB_SUBFR ][ PE_NB_CBKS_STAGE3_MAX ] = +{ + {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} +}; + +const opus_int8 silk_Lag_range_stage3[ SILK_PE_MAX_COMPLEX + 1 ] [ PE_MAX_NB_SUBFR ][ 2 ] = +{ + /* Lags to search for low number of stage3 cbks */ + { + {-5,8}, + {-1,6}, + {-1,6}, + {-4,10} + }, + /* Lags to search for middle number of stage3 cbks */ + { + {-6,10}, + {-2,6}, + {-1,6}, + {-5,10} + }, + /* Lags to search for max number of stage3 cbks */ + { + {-9,12}, + {-3,7}, + {-2,7}, + {-7,13} + } +}; + +const opus_int8 silk_nb_cbk_searchs_stage3[ SILK_PE_MAX_COMPLEX + 1 ] = +{ + PE_NB_CBKS_STAGE3_MIN, + PE_NB_CBKS_STAGE3_MID, + PE_NB_CBKS_STAGE3_MAX +}; diff --git a/extern/opus/silk/process_NLSFs.c b/extern/opus/silk/process_NLSFs.c new file mode 100644 index 0000000..d130809 --- /dev/null +++ b/extern/opus/silk/process_NLSFs.c @@ -0,0 +1,107 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/* Limit, stabilize, convert and quantize NLSFs */ +void silk_process_NLSFs( + silk_encoder_state *psEncC, /* I/O Encoder state */ + opus_int16 PredCoef_Q12[ 2 ][ MAX_LPC_ORDER ], /* O Prediction coefficients */ + opus_int16 pNLSF_Q15[ MAX_LPC_ORDER ], /* I/O Normalized LSFs (quant out) (0 - (2^15-1)) */ + const opus_int16 prev_NLSFq_Q15[ MAX_LPC_ORDER ] /* I Previous Normalized LSFs (0 - (2^15-1)) */ +) +{ + opus_int i, doInterpolate; + opus_int NLSF_mu_Q20; + opus_int16 i_sqr_Q15; + opus_int16 pNLSF0_temp_Q15[ MAX_LPC_ORDER ]; + opus_int16 pNLSFW_QW[ MAX_LPC_ORDER ]; + opus_int16 pNLSFW0_temp_QW[ MAX_LPC_ORDER ]; + + silk_assert( psEncC->speech_activity_Q8 >= 0 ); + silk_assert( psEncC->speech_activity_Q8 <= SILK_FIX_CONST( 1.0, 8 ) ); + celt_assert( psEncC->useInterpolatedNLSFs == 1 || psEncC->indices.NLSFInterpCoef_Q2 == ( 1 << 2 ) ); + + /***********************/ + /* Calculate mu values */ + /***********************/ + /* NLSF_mu = 0.003 - 0.0015 * psEnc->speech_activity; */ + NLSF_mu_Q20 = silk_SMLAWB( SILK_FIX_CONST( 0.003, 20 ), SILK_FIX_CONST( -0.001, 28 ), psEncC->speech_activity_Q8 ); + if( psEncC->nb_subfr == 2 ) { + /* Multiply by 1.5 for 10 ms packets */ + NLSF_mu_Q20 = silk_ADD_RSHIFT( NLSF_mu_Q20, NLSF_mu_Q20, 1 ); + } + + celt_assert( NLSF_mu_Q20 > 0 ); + silk_assert( NLSF_mu_Q20 <= SILK_FIX_CONST( 0.005, 20 ) ); + + /* Calculate NLSF weights */ + silk_NLSF_VQ_weights_laroia( pNLSFW_QW, pNLSF_Q15, psEncC->predictLPCOrder ); + + /* Update NLSF weights for interpolated NLSFs */ + doInterpolate = ( psEncC->useInterpolatedNLSFs == 1 ) && ( psEncC->indices.NLSFInterpCoef_Q2 < 4 ); + if( doInterpolate ) { + /* Calculate the interpolated NLSF vector for the first half */ + silk_interpolate( pNLSF0_temp_Q15, prev_NLSFq_Q15, pNLSF_Q15, + psEncC->indices.NLSFInterpCoef_Q2, psEncC->predictLPCOrder ); + + /* Calculate first half NLSF weights for the interpolated NLSFs */ + silk_NLSF_VQ_weights_laroia( pNLSFW0_temp_QW, pNLSF0_temp_Q15, psEncC->predictLPCOrder ); + + /* Update NLSF weights with contribution from first half */ + i_sqr_Q15 = silk_LSHIFT( silk_SMULBB( psEncC->indices.NLSFInterpCoef_Q2, psEncC->indices.NLSFInterpCoef_Q2 ), 11 ); + for( i = 0; i < psEncC->predictLPCOrder; i++ ) { + pNLSFW_QW[ i ] = silk_ADD16( silk_RSHIFT( pNLSFW_QW[ i ], 1 ), silk_RSHIFT( + silk_SMULBB( pNLSFW0_temp_QW[ i ], i_sqr_Q15 ), 16) ); + silk_assert( pNLSFW_QW[ i ] >= 1 ); + } + } + + silk_NLSF_encode( psEncC->indices.NLSFIndices, pNLSF_Q15, psEncC->psNLSF_CB, pNLSFW_QW, + NLSF_mu_Q20, psEncC->NLSF_MSVQ_Survivors, psEncC->indices.signalType ); + + /* Convert quantized NLSFs back to LPC coefficients */ + silk_NLSF2A( PredCoef_Q12[ 1 ], pNLSF_Q15, psEncC->predictLPCOrder, psEncC->arch ); + + if( doInterpolate ) { + /* Calculate the interpolated, quantized LSF vector for the first half */ + silk_interpolate( pNLSF0_temp_Q15, prev_NLSFq_Q15, pNLSF_Q15, + psEncC->indices.NLSFInterpCoef_Q2, psEncC->predictLPCOrder ); + + /* Convert back to LPC coefficients */ + silk_NLSF2A( PredCoef_Q12[ 0 ], pNLSF0_temp_Q15, psEncC->predictLPCOrder, psEncC->arch ); + + } else { + /* Copy LPC coefficients for first half from second half */ + celt_assert( psEncC->predictLPCOrder <= MAX_LPC_ORDER ); + silk_memcpy( PredCoef_Q12[ 0 ], PredCoef_Q12[ 1 ], psEncC->predictLPCOrder * sizeof( opus_int16 ) ); + } +} diff --git a/extern/opus/silk/quant_LTP_gains.c b/extern/opus/silk/quant_LTP_gains.c new file mode 100644 index 0000000..d6b8eff --- /dev/null +++ b/extern/opus/silk/quant_LTP_gains.c @@ -0,0 +1,132 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" +#include "tuning_parameters.h" + +void silk_quant_LTP_gains( + opus_int16 B_Q14[ MAX_NB_SUBFR * LTP_ORDER ], /* O Quantized LTP gains */ + opus_int8 cbk_index[ MAX_NB_SUBFR ], /* O Codebook Index */ + opus_int8 *periodicity_index, /* O Periodicity Index */ + opus_int32 *sum_log_gain_Q7, /* I/O Cumulative max prediction gain */ + opus_int *pred_gain_dB_Q7, /* O LTP prediction gain */ + const opus_int32 XX_Q17[ MAX_NB_SUBFR*LTP_ORDER*LTP_ORDER ], /* I Correlation matrix in Q18 */ + const opus_int32 xX_Q17[ MAX_NB_SUBFR*LTP_ORDER ], /* I Correlation vector in Q18 */ + const opus_int subfr_len, /* I Number of samples per subframe */ + const opus_int nb_subfr, /* I Number of subframes */ + int arch /* I Run-time architecture */ +) +{ + opus_int j, k, cbk_size; + opus_int8 temp_idx[ MAX_NB_SUBFR ]; + const opus_uint8 *cl_ptr_Q5; + const opus_int8 *cbk_ptr_Q7; + const opus_uint8 *cbk_gain_ptr_Q7; + const opus_int32 *XX_Q17_ptr, *xX_Q17_ptr; + opus_int32 res_nrg_Q15_subfr, res_nrg_Q15, rate_dist_Q7_subfr, rate_dist_Q7, min_rate_dist_Q7; + opus_int32 sum_log_gain_tmp_Q7, best_sum_log_gain_Q7, max_gain_Q7; + opus_int gain_Q7; + + /***************************************************/ + /* iterate over different codebooks with different */ + /* rates/distortions, and choose best */ + /***************************************************/ + min_rate_dist_Q7 = silk_int32_MAX; + best_sum_log_gain_Q7 = 0; + for( k = 0; k < 3; k++ ) { + /* Safety margin for pitch gain control, to take into account factors + such as state rescaling/rewhitening. */ + opus_int32 gain_safety = SILK_FIX_CONST( 0.4, 7 ); + + cl_ptr_Q5 = silk_LTP_gain_BITS_Q5_ptrs[ k ]; + cbk_ptr_Q7 = silk_LTP_vq_ptrs_Q7[ k ]; + cbk_gain_ptr_Q7 = silk_LTP_vq_gain_ptrs_Q7[ k ]; + cbk_size = silk_LTP_vq_sizes[ k ]; + + /* Set up pointers to first subframe */ + XX_Q17_ptr = XX_Q17; + xX_Q17_ptr = xX_Q17; + + res_nrg_Q15 = 0; + rate_dist_Q7 = 0; + sum_log_gain_tmp_Q7 = *sum_log_gain_Q7; + for( j = 0; j < nb_subfr; j++ ) { + max_gain_Q7 = silk_log2lin( ( SILK_FIX_CONST( MAX_SUM_LOG_GAIN_DB / 6.0, 7 ) - sum_log_gain_tmp_Q7 ) + + SILK_FIX_CONST( 7, 7 ) ) - gain_safety; + silk_VQ_WMat_EC( + &temp_idx[ j ], /* O index of best codebook vector */ + &res_nrg_Q15_subfr, /* O residual energy */ + &rate_dist_Q7_subfr, /* O best weighted quantization error + mu * rate */ + &gain_Q7, /* O sum of absolute LTP coefficients */ + XX_Q17_ptr, /* I correlation matrix */ + xX_Q17_ptr, /* I correlation vector */ + cbk_ptr_Q7, /* I codebook */ + cbk_gain_ptr_Q7, /* I codebook effective gains */ + cl_ptr_Q5, /* I code length for each codebook vector */ + subfr_len, /* I number of samples per subframe */ + max_gain_Q7, /* I maximum sum of absolute LTP coefficients */ + cbk_size, /* I number of vectors in codebook */ + arch /* I Run-time architecture */ + ); + + res_nrg_Q15 = silk_ADD_POS_SAT32( res_nrg_Q15, res_nrg_Q15_subfr ); + rate_dist_Q7 = silk_ADD_POS_SAT32( rate_dist_Q7, rate_dist_Q7_subfr ); + sum_log_gain_tmp_Q7 = silk_max(0, sum_log_gain_tmp_Q7 + + silk_lin2log( gain_safety + gain_Q7 ) - SILK_FIX_CONST( 7, 7 )); + + XX_Q17_ptr += LTP_ORDER * LTP_ORDER; + xX_Q17_ptr += LTP_ORDER; + } + + if( rate_dist_Q7 <= min_rate_dist_Q7 ) { + min_rate_dist_Q7 = rate_dist_Q7; + *periodicity_index = (opus_int8)k; + silk_memcpy( cbk_index, temp_idx, nb_subfr * sizeof( opus_int8 ) ); + best_sum_log_gain_Q7 = sum_log_gain_tmp_Q7; + } + } + + cbk_ptr_Q7 = silk_LTP_vq_ptrs_Q7[ *periodicity_index ]; + for( j = 0; j < nb_subfr; j++ ) { + for( k = 0; k < LTP_ORDER; k++ ) { + B_Q14[ j * LTP_ORDER + k ] = silk_LSHIFT( cbk_ptr_Q7[ cbk_index[ j ] * LTP_ORDER + k ], 7 ); + } + } + + if( nb_subfr == 2 ) { + res_nrg_Q15 = silk_RSHIFT32( res_nrg_Q15, 1 ); + } else { + res_nrg_Q15 = silk_RSHIFT32( res_nrg_Q15, 2 ); + } + + *sum_log_gain_Q7 = best_sum_log_gain_Q7; + *pred_gain_dB_Q7 = (opus_int)silk_SMULBB( -3, silk_lin2log( res_nrg_Q15 ) - ( 15 << 7 ) ); +} diff --git a/extern/opus/silk/resampler.c b/extern/opus/silk/resampler.c new file mode 100644 index 0000000..1f11e50 --- /dev/null +++ b/extern/opus/silk/resampler.c @@ -0,0 +1,215 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/* + * Matrix of resampling methods used: + * Fs_out (kHz) + * 8 12 16 24 48 + * + * 8 C UF U UF UF + * 12 AF C UF U UF + * Fs_in (kHz) 16 D AF C UF UF + * 24 AF D AF C U + * 48 AF AF AF D C + * + * C -> Copy (no resampling) + * D -> Allpass-based 2x downsampling + * U -> Allpass-based 2x upsampling + * UF -> Allpass-based 2x upsampling followed by FIR interpolation + * AF -> AR2 filter followed by FIR interpolation + */ + +#include "resampler_private.h" + +/* Tables with delay compensation values to equalize total delay for different modes */ +static const opus_int8 delay_matrix_enc[ 5 ][ 3 ] = { +/* in \ out 8 12 16 */ +/* 8 */ { 6, 0, 3 }, +/* 12 */ { 0, 7, 3 }, +/* 16 */ { 0, 1, 10 }, +/* 24 */ { 0, 2, 6 }, +/* 48 */ { 18, 10, 12 } +}; + +static const opus_int8 delay_matrix_dec[ 3 ][ 5 ] = { +/* in \ out 8 12 16 24 48 */ +/* 8 */ { 4, 0, 2, 0, 0 }, +/* 12 */ { 0, 9, 4, 7, 4 }, +/* 16 */ { 0, 3, 12, 7, 7 } +}; + +/* Simple way to make [8000, 12000, 16000, 24000, 48000] to [0, 1, 2, 3, 4] */ +#define rateID(R) ( ( ( ((R)>>12) - ((R)>16000) ) >> ((R)>24000) ) - 1 ) + +#define USE_silk_resampler_copy (0) +#define USE_silk_resampler_private_up2_HQ_wrapper (1) +#define USE_silk_resampler_private_IIR_FIR (2) +#define USE_silk_resampler_private_down_FIR (3) + +/* Initialize/reset the resampler state for a given pair of input/output sampling rates */ +opus_int silk_resampler_init( + silk_resampler_state_struct *S, /* I/O Resampler state */ + opus_int32 Fs_Hz_in, /* I Input sampling rate (Hz) */ + opus_int32 Fs_Hz_out, /* I Output sampling rate (Hz) */ + opus_int forEnc /* I If 1: encoder; if 0: decoder */ +) +{ + opus_int up2x; + + /* Clear state */ + silk_memset( S, 0, sizeof( silk_resampler_state_struct ) ); + + /* Input checking */ + if( forEnc ) { + 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 ) ) { + celt_assert( 0 ); + return -1; + } + S->inputDelay = delay_matrix_enc[ rateID( Fs_Hz_in ) ][ 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 ) ) { + celt_assert( 0 ); + return -1; + } + S->inputDelay = delay_matrix_dec[ rateID( Fs_Hz_in ) ][ rateID( Fs_Hz_out ) ]; + } + + S->Fs_in_kHz = silk_DIV32_16( Fs_Hz_in, 1000 ); + S->Fs_out_kHz = silk_DIV32_16( Fs_Hz_out, 1000 ); + + /* Number of samples processed per batch */ + S->batchSize = S->Fs_in_kHz * RESAMPLER_MAX_BATCH_SIZE_MS; + + /* Find resampler with the right sampling ratio */ + up2x = 0; + if( Fs_Hz_out > Fs_Hz_in ) { + /* Upsample */ + if( Fs_Hz_out == silk_MUL( Fs_Hz_in, 2 ) ) { /* Fs_out : Fs_in = 2 : 1 */ + /* Special case: directly use 2x upsampler */ + S->resampler_function = USE_silk_resampler_private_up2_HQ_wrapper; + } else { + /* Default resampler */ + S->resampler_function = USE_silk_resampler_private_IIR_FIR; + up2x = 1; + } + } else if ( Fs_Hz_out < Fs_Hz_in ) { + /* Downsample */ + S->resampler_function = USE_silk_resampler_private_down_FIR; + if( silk_MUL( Fs_Hz_out, 4 ) == silk_MUL( Fs_Hz_in, 3 ) ) { /* Fs_out : Fs_in = 3 : 4 */ + S->FIR_Fracs = 3; + S->FIR_Order = RESAMPLER_DOWN_ORDER_FIR0; + S->Coefs = silk_Resampler_3_4_COEFS; + } else if( silk_MUL( Fs_Hz_out, 3 ) == silk_MUL( Fs_Hz_in, 2 ) ) { /* Fs_out : Fs_in = 2 : 3 */ + S->FIR_Fracs = 2; + S->FIR_Order = RESAMPLER_DOWN_ORDER_FIR0; + S->Coefs = silk_Resampler_2_3_COEFS; + } else if( silk_MUL( Fs_Hz_out, 2 ) == Fs_Hz_in ) { /* Fs_out : Fs_in = 1 : 2 */ + S->FIR_Fracs = 1; + S->FIR_Order = RESAMPLER_DOWN_ORDER_FIR1; + S->Coefs = silk_Resampler_1_2_COEFS; + } else if( silk_MUL( Fs_Hz_out, 3 ) == Fs_Hz_in ) { /* Fs_out : Fs_in = 1 : 3 */ + S->FIR_Fracs = 1; + S->FIR_Order = RESAMPLER_DOWN_ORDER_FIR2; + S->Coefs = silk_Resampler_1_3_COEFS; + } else if( silk_MUL( Fs_Hz_out, 4 ) == Fs_Hz_in ) { /* Fs_out : Fs_in = 1 : 4 */ + S->FIR_Fracs = 1; + S->FIR_Order = RESAMPLER_DOWN_ORDER_FIR2; + S->Coefs = silk_Resampler_1_4_COEFS; + } else if( silk_MUL( Fs_Hz_out, 6 ) == Fs_Hz_in ) { /* Fs_out : Fs_in = 1 : 6 */ + S->FIR_Fracs = 1; + S->FIR_Order = RESAMPLER_DOWN_ORDER_FIR2; + S->Coefs = silk_Resampler_1_6_COEFS; + } else { + /* None available */ + celt_assert( 0 ); + return -1; + } + } else { + /* Input and output sampling rates are equal: copy */ + S->resampler_function = USE_silk_resampler_copy; + } + + /* Ratio of input/output samples */ + S->invRatio_Q16 = silk_LSHIFT32( silk_DIV32( silk_LSHIFT32( Fs_Hz_in, 14 + up2x ), Fs_Hz_out ), 2 ); + /* Make sure the ratio is rounded up */ + while( silk_SMULWW( S->invRatio_Q16, Fs_Hz_out ) < silk_LSHIFT32( Fs_Hz_in, up2x ) ) { + S->invRatio_Q16++; + } + + return 0; +} + +/* Resampler: convert from one sampling rate to another */ +/* Input and output sampling rate are at most 48000 Hz */ +opus_int silk_resampler( + silk_resampler_state_struct *S, /* I/O Resampler state */ + opus_int16 out[], /* O Output signal */ + const opus_int16 in[], /* I Input signal */ + opus_int32 inLen /* I Number of input samples */ +) +{ + opus_int nSamples; + + /* Need at least 1 ms of input data */ + celt_assert( inLen >= S->Fs_in_kHz ); + /* Delay can't exceed the 1 ms of buffering */ + celt_assert( S->inputDelay <= S->Fs_in_kHz ); + + nSamples = S->Fs_in_kHz - S->inputDelay; + + /* Copy to delay buffer */ + silk_memcpy( &S->delayBuf[ S->inputDelay ], in, nSamples * sizeof( opus_int16 ) ); + + switch( S->resampler_function ) { + case USE_silk_resampler_private_up2_HQ_wrapper: + silk_resampler_private_up2_HQ_wrapper( S, out, S->delayBuf, S->Fs_in_kHz ); + silk_resampler_private_up2_HQ_wrapper( S, &out[ S->Fs_out_kHz ], &in[ nSamples ], inLen - S->Fs_in_kHz ); + break; + case USE_silk_resampler_private_IIR_FIR: + silk_resampler_private_IIR_FIR( S, out, S->delayBuf, S->Fs_in_kHz ); + silk_resampler_private_IIR_FIR( S, &out[ S->Fs_out_kHz ], &in[ nSamples ], inLen - S->Fs_in_kHz ); + break; + case USE_silk_resampler_private_down_FIR: + silk_resampler_private_down_FIR( S, out, S->delayBuf, S->Fs_in_kHz ); + silk_resampler_private_down_FIR( S, &out[ S->Fs_out_kHz ], &in[ nSamples ], inLen - S->Fs_in_kHz ); + break; + default: + silk_memcpy( out, S->delayBuf, S->Fs_in_kHz * sizeof( opus_int16 ) ); + silk_memcpy( &out[ S->Fs_out_kHz ], &in[ nSamples ], ( inLen - S->Fs_in_kHz ) * sizeof( opus_int16 ) ); + } + + /* Copy to delay buffer */ + silk_memcpy( S->delayBuf, &in[ inLen - S->inputDelay ], S->inputDelay * sizeof( opus_int16 ) ); + + return 0; +} diff --git a/extern/opus/silk/resampler_down2.c b/extern/opus/silk/resampler_down2.c new file mode 100644 index 0000000..971d7bf --- /dev/null +++ b/extern/opus/silk/resampler_down2.c @@ -0,0 +1,74 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" +#include "resampler_rom.h" + +/* Downsample by a factor 2 */ +void silk_resampler_down2( + opus_int32 *S, /* I/O State vector [ 2 ] */ + opus_int16 *out, /* O Output signal [ floor(len/2) ] */ + const opus_int16 *in, /* I Input signal [ len ] */ + opus_int32 inLen /* I Number of input samples */ +) +{ + opus_int32 k, len2 = silk_RSHIFT32( inLen, 1 ); + opus_int32 in32, out32, Y, X; + + celt_assert( silk_resampler_down2_0 > 0 ); + celt_assert( silk_resampler_down2_1 < 0 ); + + /* Internal variables and state are in Q10 format */ + for( k = 0; k < len2; k++ ) { + /* Convert to Q10 */ + in32 = silk_LSHIFT( (opus_int32)in[ 2 * k ], 10 ); + + /* All-pass section for even input sample */ + Y = silk_SUB32( in32, S[ 0 ] ); + X = silk_SMLAWB( Y, Y, silk_resampler_down2_1 ); + out32 = silk_ADD32( S[ 0 ], X ); + S[ 0 ] = silk_ADD32( in32, X ); + + /* Convert to Q10 */ + in32 = silk_LSHIFT( (opus_int32)in[ 2 * k + 1 ], 10 ); + + /* All-pass section for odd input sample, and add to output of previous section */ + Y = silk_SUB32( in32, S[ 1 ] ); + X = silk_SMULWB( Y, silk_resampler_down2_0 ); + out32 = silk_ADD32( out32, S[ 1 ] ); + out32 = silk_ADD32( out32, X ); + S[ 1 ] = silk_ADD32( in32, X ); + + /* Add, convert back to int16 and store to output */ + out[ k ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( out32, 11 ) ); + } +} + diff --git a/extern/opus/silk/resampler_down2_3.c b/extern/opus/silk/resampler_down2_3.c new file mode 100644 index 0000000..4342614 --- /dev/null +++ b/extern/opus/silk/resampler_down2_3.c @@ -0,0 +1,103 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" +#include "resampler_private.h" +#include "stack_alloc.h" + +#define ORDER_FIR 4 + +/* Downsample by a factor 2/3, low quality */ +void silk_resampler_down2_3( + opus_int32 *S, /* I/O State vector [ 6 ] */ + opus_int16 *out, /* O Output signal [ floor(2*inLen/3) ] */ + const opus_int16 *in, /* I Input signal [ inLen ] */ + opus_int32 inLen /* I Number of input samples */ +) +{ + opus_int32 nSamplesIn, counter, res_Q6; + VARDECL( opus_int32, buf ); + opus_int32 *buf_ptr; + SAVE_STACK; + + ALLOC( buf, RESAMPLER_MAX_BATCH_SIZE_IN + ORDER_FIR, opus_int32 ); + + /* Copy buffered samples to start of buffer */ + silk_memcpy( buf, S, ORDER_FIR * sizeof( opus_int32 ) ); + + /* Iterate over blocks of frameSizeIn input samples */ + while( 1 ) { + nSamplesIn = silk_min( inLen, RESAMPLER_MAX_BATCH_SIZE_IN ); + + /* Second-order AR filter (output in Q8) */ + silk_resampler_private_AR2( &S[ ORDER_FIR ], &buf[ ORDER_FIR ], in, + silk_Resampler_2_3_COEFS_LQ, nSamplesIn ); + + /* Interpolate filtered signal */ + buf_ptr = buf; + counter = nSamplesIn; + while( counter > 2 ) { + /* Inner product */ + res_Q6 = silk_SMULWB( buf_ptr[ 0 ], silk_Resampler_2_3_COEFS_LQ[ 2 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 1 ], silk_Resampler_2_3_COEFS_LQ[ 3 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 2 ], silk_Resampler_2_3_COEFS_LQ[ 5 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 3 ], silk_Resampler_2_3_COEFS_LQ[ 4 ] ); + + /* Scale down, saturate and store in output array */ + *out++ = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( res_Q6, 6 ) ); + + res_Q6 = silk_SMULWB( buf_ptr[ 1 ], silk_Resampler_2_3_COEFS_LQ[ 4 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 2 ], silk_Resampler_2_3_COEFS_LQ[ 5 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 3 ], silk_Resampler_2_3_COEFS_LQ[ 3 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 4 ], silk_Resampler_2_3_COEFS_LQ[ 2 ] ); + + /* Scale down, saturate and store in output array */ + *out++ = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( res_Q6, 6 ) ); + + buf_ptr += 3; + counter -= 3; + } + + in += nSamplesIn; + inLen -= nSamplesIn; + + if( inLen > 0 ) { + /* More iterations to do; copy last part of filtered signal to beginning of buffer */ + silk_memcpy( buf, &buf[ nSamplesIn ], ORDER_FIR * sizeof( opus_int32 ) ); + } else { + break; + } + } + + /* Copy last part of filtered signal to the state for the next call */ + silk_memcpy( S, &buf[ nSamplesIn ], ORDER_FIR * sizeof( opus_int32 ) ); + RESTORE_STACK; +} diff --git a/extern/opus/silk/resampler_private.h b/extern/opus/silk/resampler_private.h new file mode 100644 index 0000000..422a7d9 --- /dev/null +++ b/extern/opus/silk/resampler_private.h @@ -0,0 +1,88 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifndef SILK_RESAMPLER_PRIVATE_H +#define SILK_RESAMPLER_PRIVATE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "SigProc_FIX.h" +#include "resampler_structs.h" +#include "resampler_rom.h" + +/* Number of input samples to process in the inner loop */ +#define RESAMPLER_MAX_BATCH_SIZE_MS 10 +#define RESAMPLER_MAX_FS_KHZ 48 +#define RESAMPLER_MAX_BATCH_SIZE_IN ( RESAMPLER_MAX_BATCH_SIZE_MS * RESAMPLER_MAX_FS_KHZ ) + +/* Description: Hybrid IIR/FIR polyphase implementation of resampling */ +void silk_resampler_private_IIR_FIR( + void *SS, /* I/O Resampler state */ + opus_int16 out[], /* O Output signal */ + const opus_int16 in[], /* I Input signal */ + opus_int32 inLen /* I Number of input samples */ +); + +/* Description: Hybrid IIR/FIR polyphase implementation of resampling */ +void silk_resampler_private_down_FIR( + void *SS, /* I/O Resampler state */ + opus_int16 out[], /* O Output signal */ + const opus_int16 in[], /* I Input signal */ + opus_int32 inLen /* I Number of input samples */ +); + +/* Upsample by a factor 2, high quality */ +void silk_resampler_private_up2_HQ_wrapper( + void *SS, /* I/O Resampler state (unused) */ + opus_int16 *out, /* O Output signal [ 2 * len ] */ + const opus_int16 *in, /* I Input signal [ len ] */ + opus_int32 len /* I Number of input samples */ +); + +/* Upsample by a factor 2, high quality */ +void silk_resampler_private_up2_HQ( + opus_int32 *S, /* I/O Resampler state [ 6 ] */ + opus_int16 *out, /* O Output signal [ 2 * len ] */ + const opus_int16 *in, /* I Input signal [ len ] */ + opus_int32 len /* I Number of input samples */ +); + +/* Second order AR filter */ +void silk_resampler_private_AR2( + opus_int32 S[], /* I/O State vector [ 2 ] */ + opus_int32 out_Q8[], /* O Output signal */ + const opus_int16 in[], /* I Input signal */ + const opus_int16 A_Q14[], /* I AR coefficients, Q14 */ + opus_int32 len /* I Signal length */ +); + +#ifdef __cplusplus +} +#endif +#endif /* SILK_RESAMPLER_PRIVATE_H */ diff --git a/extern/opus/silk/resampler_private_AR2.c b/extern/opus/silk/resampler_private_AR2.c new file mode 100644 index 0000000..5fff237 --- /dev/null +++ b/extern/opus/silk/resampler_private_AR2.c @@ -0,0 +1,55 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" +#include "resampler_private.h" + +/* Second order AR filter with single delay elements */ +void silk_resampler_private_AR2( + opus_int32 S[], /* I/O State vector [ 2 ] */ + opus_int32 out_Q8[], /* O Output signal */ + const opus_int16 in[], /* I Input signal */ + const opus_int16 A_Q14[], /* I AR coefficients, Q14 */ + opus_int32 len /* I Signal length */ +) +{ + opus_int32 k; + opus_int32 out32; + + for( k = 0; k < len; k++ ) { + out32 = silk_ADD_LSHIFT32( S[ 0 ], (opus_int32)in[ k ], 8 ); + out_Q8[ k ] = out32; + out32 = silk_LSHIFT( out32, 2 ); + S[ 0 ] = silk_SMLAWB( S[ 1 ], out32, A_Q14[ 0 ] ); + S[ 1 ] = silk_SMULWB( out32, A_Q14[ 1 ] ); + } +} + diff --git a/extern/opus/silk/resampler_private_IIR_FIR.c b/extern/opus/silk/resampler_private_IIR_FIR.c new file mode 100644 index 0000000..6b2b3a2 --- /dev/null +++ b/extern/opus/silk/resampler_private_IIR_FIR.c @@ -0,0 +1,107 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" +#include "resampler_private.h" +#include "stack_alloc.h" + +static OPUS_INLINE opus_int16 *silk_resampler_private_IIR_FIR_INTERPOL( + opus_int16 *out, + opus_int16 *buf, + opus_int32 max_index_Q16, + opus_int32 index_increment_Q16 +) +{ + opus_int32 index_Q16, res_Q15; + opus_int16 *buf_ptr; + opus_int32 table_index; + + /* Interpolate upsampled signal and store in output array */ + for( index_Q16 = 0; index_Q16 < max_index_Q16; index_Q16 += index_increment_Q16 ) { + table_index = silk_SMULWB( index_Q16 & 0xFFFF, 12 ); + buf_ptr = &buf[ index_Q16 >> 16 ]; + + res_Q15 = silk_SMULBB( buf_ptr[ 0 ], silk_resampler_frac_FIR_12[ table_index ][ 0 ] ); + res_Q15 = silk_SMLABB( res_Q15, buf_ptr[ 1 ], silk_resampler_frac_FIR_12[ table_index ][ 1 ] ); + res_Q15 = silk_SMLABB( res_Q15, buf_ptr[ 2 ], silk_resampler_frac_FIR_12[ table_index ][ 2 ] ); + res_Q15 = silk_SMLABB( res_Q15, buf_ptr[ 3 ], silk_resampler_frac_FIR_12[ table_index ][ 3 ] ); + res_Q15 = silk_SMLABB( res_Q15, buf_ptr[ 4 ], silk_resampler_frac_FIR_12[ 11 - table_index ][ 3 ] ); + res_Q15 = silk_SMLABB( res_Q15, buf_ptr[ 5 ], silk_resampler_frac_FIR_12[ 11 - table_index ][ 2 ] ); + res_Q15 = silk_SMLABB( res_Q15, buf_ptr[ 6 ], silk_resampler_frac_FIR_12[ 11 - table_index ][ 1 ] ); + res_Q15 = silk_SMLABB( res_Q15, buf_ptr[ 7 ], silk_resampler_frac_FIR_12[ 11 - table_index ][ 0 ] ); + *out++ = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( res_Q15, 15 ) ); + } + return out; +} +/* Upsample using a combination of allpass-based 2x upsampling and FIR interpolation */ +void silk_resampler_private_IIR_FIR( + void *SS, /* I/O Resampler state */ + opus_int16 out[], /* O Output signal */ + const opus_int16 in[], /* I Input signal */ + opus_int32 inLen /* I Number of input samples */ +) +{ + silk_resampler_state_struct *S = (silk_resampler_state_struct *)SS; + opus_int32 nSamplesIn; + opus_int32 max_index_Q16, index_increment_Q16; + VARDECL( opus_int16, buf ); + SAVE_STACK; + + ALLOC( buf, 2 * S->batchSize + RESAMPLER_ORDER_FIR_12, opus_int16 ); + + /* Copy buffered samples to start of buffer */ + silk_memcpy( buf, S->sFIR.i16, RESAMPLER_ORDER_FIR_12 * sizeof( opus_int16 ) ); + + /* Iterate over blocks of frameSizeIn input samples */ + index_increment_Q16 = S->invRatio_Q16; + while( 1 ) { + nSamplesIn = silk_min( inLen, S->batchSize ); + + /* Upsample 2x */ + silk_resampler_private_up2_HQ( S->sIIR, &buf[ RESAMPLER_ORDER_FIR_12 ], in, nSamplesIn ); + + max_index_Q16 = silk_LSHIFT32( nSamplesIn, 16 + 1 ); /* + 1 because 2x upsampling */ + out = silk_resampler_private_IIR_FIR_INTERPOL( out, buf, max_index_Q16, index_increment_Q16 ); + in += nSamplesIn; + inLen -= nSamplesIn; + + if( inLen > 0 ) { + /* More iterations to do; copy last part of filtered signal to beginning of buffer */ + silk_memcpy( buf, &buf[ nSamplesIn << 1 ], RESAMPLER_ORDER_FIR_12 * sizeof( opus_int16 ) ); + } else { + break; + } + } + + /* Copy last part of filtered signal to the state for the next call */ + silk_memcpy( S->sFIR.i16, &buf[ nSamplesIn << 1 ], RESAMPLER_ORDER_FIR_12 * sizeof( opus_int16 ) ); + RESTORE_STACK; +} diff --git a/extern/opus/silk/resampler_private_down_FIR.c b/extern/opus/silk/resampler_private_down_FIR.c new file mode 100644 index 0000000..3e8735a --- /dev/null +++ b/extern/opus/silk/resampler_private_down_FIR.c @@ -0,0 +1,194 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" +#include "resampler_private.h" +#include "stack_alloc.h" + +static OPUS_INLINE opus_int16 *silk_resampler_private_down_FIR_INTERPOL( + opus_int16 *out, + opus_int32 *buf, + const opus_int16 *FIR_Coefs, + opus_int FIR_Order, + opus_int FIR_Fracs, + opus_int32 max_index_Q16, + opus_int32 index_increment_Q16 +) +{ + opus_int32 index_Q16, res_Q6; + opus_int32 *buf_ptr; + opus_int32 interpol_ind; + const opus_int16 *interpol_ptr; + + switch( FIR_Order ) { + case RESAMPLER_DOWN_ORDER_FIR0: + for( index_Q16 = 0; index_Q16 < max_index_Q16; index_Q16 += index_increment_Q16 ) { + /* Integer part gives pointer to buffered input */ + buf_ptr = buf + silk_RSHIFT( index_Q16, 16 ); + + /* Fractional part gives interpolation coefficients */ + interpol_ind = silk_SMULWB( index_Q16 & 0xFFFF, FIR_Fracs ); + + /* Inner product */ + interpol_ptr = &FIR_Coefs[ RESAMPLER_DOWN_ORDER_FIR0 / 2 * interpol_ind ]; + res_Q6 = silk_SMULWB( buf_ptr[ 0 ], interpol_ptr[ 0 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 1 ], interpol_ptr[ 1 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 2 ], interpol_ptr[ 2 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 3 ], interpol_ptr[ 3 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 4 ], interpol_ptr[ 4 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 5 ], interpol_ptr[ 5 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 6 ], interpol_ptr[ 6 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 7 ], interpol_ptr[ 7 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 8 ], interpol_ptr[ 8 ] ); + interpol_ptr = &FIR_Coefs[ RESAMPLER_DOWN_ORDER_FIR0 / 2 * ( FIR_Fracs - 1 - interpol_ind ) ]; + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 17 ], interpol_ptr[ 0 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 16 ], interpol_ptr[ 1 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 15 ], interpol_ptr[ 2 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 14 ], interpol_ptr[ 3 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 13 ], interpol_ptr[ 4 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 12 ], interpol_ptr[ 5 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 11 ], interpol_ptr[ 6 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 10 ], interpol_ptr[ 7 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 9 ], interpol_ptr[ 8 ] ); + + /* Scale down, saturate and store in output array */ + *out++ = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( res_Q6, 6 ) ); + } + break; + case RESAMPLER_DOWN_ORDER_FIR1: + for( index_Q16 = 0; index_Q16 < max_index_Q16; index_Q16 += index_increment_Q16 ) { + /* Integer part gives pointer to buffered input */ + buf_ptr = buf + silk_RSHIFT( index_Q16, 16 ); + + /* Inner product */ + res_Q6 = silk_SMULWB( silk_ADD32( buf_ptr[ 0 ], buf_ptr[ 23 ] ), FIR_Coefs[ 0 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 1 ], buf_ptr[ 22 ] ), FIR_Coefs[ 1 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 2 ], buf_ptr[ 21 ] ), FIR_Coefs[ 2 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 3 ], buf_ptr[ 20 ] ), FIR_Coefs[ 3 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 4 ], buf_ptr[ 19 ] ), FIR_Coefs[ 4 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 5 ], buf_ptr[ 18 ] ), FIR_Coefs[ 5 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 6 ], buf_ptr[ 17 ] ), FIR_Coefs[ 6 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 7 ], buf_ptr[ 16 ] ), FIR_Coefs[ 7 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 8 ], buf_ptr[ 15 ] ), FIR_Coefs[ 8 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 9 ], buf_ptr[ 14 ] ), FIR_Coefs[ 9 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 10 ], buf_ptr[ 13 ] ), FIR_Coefs[ 10 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 11 ], buf_ptr[ 12 ] ), FIR_Coefs[ 11 ] ); + + /* Scale down, saturate and store in output array */ + *out++ = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( res_Q6, 6 ) ); + } + break; + case RESAMPLER_DOWN_ORDER_FIR2: + for( index_Q16 = 0; index_Q16 < max_index_Q16; index_Q16 += index_increment_Q16 ) { + /* Integer part gives pointer to buffered input */ + buf_ptr = buf + silk_RSHIFT( index_Q16, 16 ); + + /* Inner product */ + res_Q6 = silk_SMULWB( silk_ADD32( buf_ptr[ 0 ], buf_ptr[ 35 ] ), FIR_Coefs[ 0 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 1 ], buf_ptr[ 34 ] ), FIR_Coefs[ 1 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 2 ], buf_ptr[ 33 ] ), FIR_Coefs[ 2 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 3 ], buf_ptr[ 32 ] ), FIR_Coefs[ 3 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 4 ], buf_ptr[ 31 ] ), FIR_Coefs[ 4 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 5 ], buf_ptr[ 30 ] ), FIR_Coefs[ 5 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 6 ], buf_ptr[ 29 ] ), FIR_Coefs[ 6 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 7 ], buf_ptr[ 28 ] ), FIR_Coefs[ 7 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 8 ], buf_ptr[ 27 ] ), FIR_Coefs[ 8 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 9 ], buf_ptr[ 26 ] ), FIR_Coefs[ 9 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 10 ], buf_ptr[ 25 ] ), FIR_Coefs[ 10 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 11 ], buf_ptr[ 24 ] ), FIR_Coefs[ 11 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 12 ], buf_ptr[ 23 ] ), FIR_Coefs[ 12 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 13 ], buf_ptr[ 22 ] ), FIR_Coefs[ 13 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 14 ], buf_ptr[ 21 ] ), FIR_Coefs[ 14 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 15 ], buf_ptr[ 20 ] ), FIR_Coefs[ 15 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 16 ], buf_ptr[ 19 ] ), FIR_Coefs[ 16 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 17 ], buf_ptr[ 18 ] ), FIR_Coefs[ 17 ] ); + + /* Scale down, saturate and store in output array */ + *out++ = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( res_Q6, 6 ) ); + } + break; + default: + celt_assert( 0 ); + } + return out; +} + +/* Resample with a 2nd order AR filter followed by FIR interpolation */ +void silk_resampler_private_down_FIR( + void *SS, /* I/O Resampler state */ + opus_int16 out[], /* O Output signal */ + const opus_int16 in[], /* I Input signal */ + opus_int32 inLen /* I Number of input samples */ +) +{ + silk_resampler_state_struct *S = (silk_resampler_state_struct *)SS; + opus_int32 nSamplesIn; + opus_int32 max_index_Q16, index_increment_Q16; + VARDECL( opus_int32, buf ); + const opus_int16 *FIR_Coefs; + SAVE_STACK; + + ALLOC( buf, S->batchSize + S->FIR_Order, opus_int32 ); + + /* Copy buffered samples to start of buffer */ + silk_memcpy( buf, S->sFIR.i32, S->FIR_Order * sizeof( opus_int32 ) ); + + FIR_Coefs = &S->Coefs[ 2 ]; + + /* Iterate over blocks of frameSizeIn input samples */ + index_increment_Q16 = S->invRatio_Q16; + while( 1 ) { + nSamplesIn = silk_min( inLen, S->batchSize ); + + /* Second-order AR filter (output in Q8) */ + silk_resampler_private_AR2( S->sIIR, &buf[ S->FIR_Order ], in, S->Coefs, nSamplesIn ); + + max_index_Q16 = silk_LSHIFT32( nSamplesIn, 16 ); + + /* Interpolate filtered signal */ + out = silk_resampler_private_down_FIR_INTERPOL( out, buf, FIR_Coefs, S->FIR_Order, + S->FIR_Fracs, max_index_Q16, index_increment_Q16 ); + + in += nSamplesIn; + inLen -= nSamplesIn; + + if( inLen > 1 ) { + /* More iterations to do; copy last part of filtered signal to beginning of buffer */ + silk_memcpy( buf, &buf[ nSamplesIn ], S->FIR_Order * sizeof( opus_int32 ) ); + } else { + break; + } + } + + /* Copy last part of filtered signal to the state for the next call */ + silk_memcpy( S->sFIR.i32, &buf[ nSamplesIn ], S->FIR_Order * sizeof( opus_int32 ) ); + RESTORE_STACK; +} diff --git a/extern/opus/silk/resampler_private_up2_HQ.c b/extern/opus/silk/resampler_private_up2_HQ.c new file mode 100644 index 0000000..c7ec8de --- /dev/null +++ b/extern/opus/silk/resampler_private_up2_HQ.c @@ -0,0 +1,113 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" +#include "resampler_private.h" + +/* Upsample by a factor 2, high quality */ +/* Uses 2nd order allpass filters for the 2x upsampling, followed by a */ +/* notch filter just above Nyquist. */ +void silk_resampler_private_up2_HQ( + opus_int32 *S, /* I/O Resampler state [ 6 ] */ + opus_int16 *out, /* O Output signal [ 2 * len ] */ + const opus_int16 *in, /* I Input signal [ len ] */ + opus_int32 len /* I Number of input samples */ +) +{ + opus_int32 k; + opus_int32 in32, out32_1, out32_2, Y, X; + + silk_assert( silk_resampler_up2_hq_0[ 0 ] > 0 ); + silk_assert( silk_resampler_up2_hq_0[ 1 ] > 0 ); + silk_assert( silk_resampler_up2_hq_0[ 2 ] < 0 ); + silk_assert( silk_resampler_up2_hq_1[ 0 ] > 0 ); + silk_assert( silk_resampler_up2_hq_1[ 1 ] > 0 ); + silk_assert( silk_resampler_up2_hq_1[ 2 ] < 0 ); + + /* Internal variables and state are in Q10 format */ + for( k = 0; k < len; k++ ) { + /* Convert to Q10 */ + in32 = silk_LSHIFT( (opus_int32)in[ k ], 10 ); + + /* First all-pass section for even output sample */ + Y = silk_SUB32( in32, S[ 0 ] ); + X = silk_SMULWB( Y, silk_resampler_up2_hq_0[ 0 ] ); + out32_1 = silk_ADD32( S[ 0 ], X ); + S[ 0 ] = silk_ADD32( in32, X ); + + /* Second all-pass section for even output sample */ + Y = silk_SUB32( out32_1, S[ 1 ] ); + X = silk_SMULWB( Y, silk_resampler_up2_hq_0[ 1 ] ); + out32_2 = silk_ADD32( S[ 1 ], X ); + S[ 1 ] = silk_ADD32( out32_1, X ); + + /* Third all-pass section for even output sample */ + Y = silk_SUB32( out32_2, S[ 2 ] ); + X = silk_SMLAWB( Y, Y, silk_resampler_up2_hq_0[ 2 ] ); + out32_1 = silk_ADD32( S[ 2 ], X ); + S[ 2 ] = silk_ADD32( out32_2, X ); + + /* Apply gain in Q15, convert back to int16 and store to output */ + out[ 2 * k ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( out32_1, 10 ) ); + + /* First all-pass section for odd output sample */ + Y = silk_SUB32( in32, S[ 3 ] ); + X = silk_SMULWB( Y, silk_resampler_up2_hq_1[ 0 ] ); + out32_1 = silk_ADD32( S[ 3 ], X ); + S[ 3 ] = silk_ADD32( in32, X ); + + /* Second all-pass section for odd output sample */ + Y = silk_SUB32( out32_1, S[ 4 ] ); + X = silk_SMULWB( Y, silk_resampler_up2_hq_1[ 1 ] ); + out32_2 = silk_ADD32( S[ 4 ], X ); + S[ 4 ] = silk_ADD32( out32_1, X ); + + /* Third all-pass section for odd output sample */ + Y = silk_SUB32( out32_2, S[ 5 ] ); + X = silk_SMLAWB( Y, Y, silk_resampler_up2_hq_1[ 2 ] ); + out32_1 = silk_ADD32( S[ 5 ], X ); + S[ 5 ] = silk_ADD32( out32_2, X ); + + /* Apply gain in Q15, convert back to int16 and store to output */ + out[ 2 * k + 1 ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( out32_1, 10 ) ); + } +} + +void silk_resampler_private_up2_HQ_wrapper( + void *SS, /* I/O Resampler state (unused) */ + opus_int16 *out, /* O Output signal [ 2 * len ] */ + const opus_int16 *in, /* I Input signal [ len ] */ + opus_int32 len /* I Number of input samples */ +) +{ + silk_resampler_state_struct *S = (silk_resampler_state_struct *)SS; + silk_resampler_private_up2_HQ( S->sIIR, out, in, len ); +} diff --git a/extern/opus/silk/resampler_rom.c b/extern/opus/silk/resampler_rom.c new file mode 100644 index 0000000..5e6b044 --- /dev/null +++ b/extern/opus/silk/resampler_rom.c @@ -0,0 +1,96 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/* Filter coefficients for IIR/FIR polyphase resampling * + * Total size: 179 Words (358 Bytes) */ + +#include "resampler_private.h" + +/* Matlab code for the notch filter coefficients: */ +/* B = [1, 0.147, 1]; A = [1, 0.107, 0.89]; G = 0.93; freqz(G * B, A, 2^14, 16e3); axis([0, 8000, -10, 1]) */ +/* fprintf('\t%6d, %6d, %6d, %6d\n', round(B(2)*2^16), round(-A(2)*2^16), round((1-A(3))*2^16), round(G*2^15)) */ +/* const opus_int16 silk_resampler_up2_hq_notch[ 4 ] = { 9634, -7012, 7209, 30474 }; */ + +/* Tables with IIR and FIR coefficients for fractional downsamplers (123 Words) */ +silk_DWORD_ALIGN const opus_int16 silk_Resampler_3_4_COEFS[ 2 + 3 * RESAMPLER_DOWN_ORDER_FIR0 / 2 ] = { + -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_DWORD_ALIGN const opus_int16 silk_Resampler_2_3_COEFS[ 2 + 2 * RESAMPLER_DOWN_ORDER_FIR0 / 2 ] = { + -14457, -14019, + 64, 128, -122, 36, 310, -768, 584, 9267, 17733, + 12, 128, 18, -142, 288, -117, -865, 4123, 14459, +}; + +silk_DWORD_ALIGN const opus_int16 silk_Resampler_1_2_COEFS[ 2 + RESAMPLER_DOWN_ORDER_FIR1 / 2 ] = { + 616, -14323, + -10, 39, 58, -46, -84, 120, 184, -315, -541, 1284, 5380, 9024, +}; + +silk_DWORD_ALIGN const opus_int16 silk_Resampler_1_3_COEFS[ 2 + RESAMPLER_DOWN_ORDER_FIR2 / 2 ] = { + 16102, -15162, + -13, 0, 20, 26, 5, -31, -43, -4, 65, 90, 7, -157, -248, -44, 593, 1583, 2612, 3271, +}; + +silk_DWORD_ALIGN const opus_int16 silk_Resampler_1_4_COEFS[ 2 + RESAMPLER_DOWN_ORDER_FIR2 / 2 ] = { + 22500, -15099, + 3, -14, -20, -15, 2, 25, 37, 25, -16, -71, -107, -79, 50, 292, 623, 982, 1288, 1464, +}; + +silk_DWORD_ALIGN const opus_int16 silk_Resampler_1_6_COEFS[ 2 + RESAMPLER_DOWN_ORDER_FIR2 / 2 ] = { + 27540, -15257, + 17, 12, 8, 1, -10, -22, -30, -32, -22, 3, 44, 100, 168, 243, 317, 381, 429, 455, +}; + +silk_DWORD_ALIGN const opus_int16 silk_Resampler_2_3_COEFS_LQ[ 2 + 2 * 2 ] = { + -2797, -6507, + 4697, 10739, + 1567, 8276, +}; + +/* Table with interplation fractions of 1/24, 3/24, 5/24, ... , 23/24 : 23/24 (46 Words) */ +silk_DWORD_ALIGN const opus_int16 silk_resampler_frac_FIR_12[ 12 ][ RESAMPLER_ORDER_FIR_12 / 2 ] = { + { 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 }, +}; diff --git a/extern/opus/silk/resampler_rom.h b/extern/opus/silk/resampler_rom.h new file mode 100644 index 0000000..490b338 --- /dev/null +++ b/extern/opus/silk/resampler_rom.h @@ -0,0 +1,68 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifndef SILK_FIX_RESAMPLER_ROM_H +#define SILK_FIX_RESAMPLER_ROM_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include "typedef.h" +#include "resampler_structs.h" + +#define RESAMPLER_DOWN_ORDER_FIR0 18 +#define RESAMPLER_DOWN_ORDER_FIR1 24 +#define RESAMPLER_DOWN_ORDER_FIR2 36 +#define RESAMPLER_ORDER_FIR_12 8 + +/* Tables for 2x downsampler */ +static const opus_int16 silk_resampler_down2_0 = 9872; +static const opus_int16 silk_resampler_down2_1 = 39809 - 65536; + +/* Tables for 2x upsampler, high quality */ +static const opus_int16 silk_resampler_up2_hq_0[ 3 ] = { 1746, 14986, 39083 - 65536 }; +static const opus_int16 silk_resampler_up2_hq_1[ 3 ] = { 6854, 25769, 55542 - 65536 }; + +/* Tables with IIR and FIR coefficients for fractional downsamplers */ +extern const opus_int16 silk_Resampler_3_4_COEFS[ 2 + 3 * RESAMPLER_DOWN_ORDER_FIR0 / 2 ]; +extern const opus_int16 silk_Resampler_2_3_COEFS[ 2 + 2 * RESAMPLER_DOWN_ORDER_FIR0 / 2 ]; +extern const opus_int16 silk_Resampler_1_2_COEFS[ 2 + RESAMPLER_DOWN_ORDER_FIR1 / 2 ]; +extern const opus_int16 silk_Resampler_1_3_COEFS[ 2 + RESAMPLER_DOWN_ORDER_FIR2 / 2 ]; +extern const opus_int16 silk_Resampler_1_4_COEFS[ 2 + RESAMPLER_DOWN_ORDER_FIR2 / 2 ]; +extern const opus_int16 silk_Resampler_1_6_COEFS[ 2 + RESAMPLER_DOWN_ORDER_FIR2 / 2 ]; +extern const opus_int16 silk_Resampler_2_3_COEFS_LQ[ 2 + 2 * 2 ]; + +/* Table with interplation fractions of 1/24, 3/24, ..., 23/24 */ +extern const opus_int16 silk_resampler_frac_FIR_12[ 12 ][ RESAMPLER_ORDER_FIR_12 / 2 ]; + +#ifdef __cplusplus +} +#endif + +#endif /* SILK_FIX_RESAMPLER_ROM_H */ diff --git a/extern/opus/silk/resampler_structs.h b/extern/opus/silk/resampler_structs.h new file mode 100644 index 0000000..9e9457d --- /dev/null +++ b/extern/opus/silk/resampler_structs.h @@ -0,0 +1,60 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifndef SILK_RESAMPLER_STRUCTS_H +#define SILK_RESAMPLER_STRUCTS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define SILK_RESAMPLER_MAX_FIR_ORDER 36 +#define SILK_RESAMPLER_MAX_IIR_ORDER 6 + +typedef struct _silk_resampler_state_struct{ + opus_int32 sIIR[ SILK_RESAMPLER_MAX_IIR_ORDER ]; /* this must be the first element of this struct */ + union{ + opus_int32 i32[ SILK_RESAMPLER_MAX_FIR_ORDER ]; + opus_int16 i16[ SILK_RESAMPLER_MAX_FIR_ORDER ]; + } sFIR; + opus_int16 delayBuf[ 48 ]; + opus_int resampler_function; + opus_int batchSize; + opus_int32 invRatio_Q16; + opus_int FIR_Order; + opus_int FIR_Fracs; + opus_int Fs_in_kHz; + opus_int Fs_out_kHz; + opus_int inputDelay; + const opus_int16 *Coefs; +} silk_resampler_state_struct; + +#ifdef __cplusplus +} +#endif +#endif /* SILK_RESAMPLER_STRUCTS_H */ + diff --git a/extern/opus/silk/shell_coder.c b/extern/opus/silk/shell_coder.c new file mode 100644 index 0000000..4af3414 --- /dev/null +++ b/extern/opus/silk/shell_coder.c @@ -0,0 +1,151 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/* shell coder; pulse-subframe length is hardcoded */ + +static OPUS_INLINE void combine_pulses( + opus_int *out, /* O combined pulses vector [len] */ + const opus_int *in, /* I input vector [2 * len] */ + const opus_int len /* I number of OUTPUT samples */ +) +{ + opus_int k; + for( k = 0; k < len; k++ ) { + out[ k ] = in[ 2 * k ] + in[ 2 * k + 1 ]; + } +} + +static OPUS_INLINE void encode_split( + ec_enc *psRangeEnc, /* I/O compressor data structure */ + const opus_int p_child1, /* I pulse amplitude of first child subframe */ + const opus_int p, /* I pulse amplitude of current subframe */ + const opus_uint8 *shell_table /* I table of shell cdfs */ +) +{ + if( p > 0 ) { + ec_enc_icdf( psRangeEnc, p_child1, &shell_table[ silk_shell_code_table_offsets[ p ] ], 8 ); + } +} + +static OPUS_INLINE void decode_split( + opus_int16 *p_child1, /* O pulse amplitude of first child subframe */ + opus_int16 *p_child2, /* O pulse amplitude of second child subframe */ + ec_dec *psRangeDec, /* I/O Compressor data structure */ + const opus_int p, /* I pulse amplitude of current subframe */ + const opus_uint8 *shell_table /* I table of shell cdfs */ +) +{ + if( p > 0 ) { + p_child1[ 0 ] = ec_dec_icdf( psRangeDec, &shell_table[ silk_shell_code_table_offsets[ p ] ], 8 ); + p_child2[ 0 ] = p - p_child1[ 0 ]; + } else { + p_child1[ 0 ] = 0; + p_child2[ 0 ] = 0; + } +} + +/* Shell encoder, operates on one shell code frame of 16 pulses */ +void silk_shell_encoder( + ec_enc *psRangeEnc, /* I/O compressor data structure */ + const opus_int *pulses0 /* I data: nonnegative pulse amplitudes */ +) +{ + opus_int pulses1[ 8 ], pulses2[ 4 ], pulses3[ 2 ], pulses4[ 1 ]; + + /* this function operates on one shell code frame of 16 pulses */ + silk_assert( SHELL_CODEC_FRAME_LENGTH == 16 ); + + /* tree representation per pulse-subframe */ + combine_pulses( pulses1, pulses0, 8 ); + combine_pulses( pulses2, pulses1, 4 ); + combine_pulses( pulses3, pulses2, 2 ); + combine_pulses( pulses4, pulses3, 1 ); + + encode_split( psRangeEnc, pulses3[ 0 ], pulses4[ 0 ], silk_shell_code_table3 ); + + encode_split( psRangeEnc, pulses2[ 0 ], pulses3[ 0 ], silk_shell_code_table2 ); + + encode_split( psRangeEnc, pulses1[ 0 ], pulses2[ 0 ], silk_shell_code_table1 ); + encode_split( psRangeEnc, pulses0[ 0 ], pulses1[ 0 ], silk_shell_code_table0 ); + encode_split( psRangeEnc, pulses0[ 2 ], pulses1[ 1 ], silk_shell_code_table0 ); + + encode_split( psRangeEnc, pulses1[ 2 ], pulses2[ 1 ], silk_shell_code_table1 ); + encode_split( psRangeEnc, pulses0[ 4 ], pulses1[ 2 ], silk_shell_code_table0 ); + encode_split( psRangeEnc, pulses0[ 6 ], pulses1[ 3 ], silk_shell_code_table0 ); + + encode_split( psRangeEnc, pulses2[ 2 ], pulses3[ 1 ], silk_shell_code_table2 ); + + encode_split( psRangeEnc, pulses1[ 4 ], pulses2[ 2 ], silk_shell_code_table1 ); + encode_split( psRangeEnc, pulses0[ 8 ], pulses1[ 4 ], silk_shell_code_table0 ); + encode_split( psRangeEnc, pulses0[ 10 ], pulses1[ 5 ], silk_shell_code_table0 ); + + encode_split( psRangeEnc, pulses1[ 6 ], pulses2[ 3 ], silk_shell_code_table1 ); + encode_split( psRangeEnc, pulses0[ 12 ], pulses1[ 6 ], silk_shell_code_table0 ); + encode_split( psRangeEnc, pulses0[ 14 ], pulses1[ 7 ], silk_shell_code_table0 ); +} + + +/* Shell decoder, operates on one shell code frame of 16 pulses */ +void silk_shell_decoder( + opus_int16 *pulses0, /* O data: nonnegative pulse amplitudes */ + ec_dec *psRangeDec, /* I/O Compressor data structure */ + const opus_int pulses4 /* I number of pulses per pulse-subframe */ +) +{ + opus_int16 pulses3[ 2 ], pulses2[ 4 ], pulses1[ 8 ]; + + /* this function operates on one shell code frame of 16 pulses */ + silk_assert( SHELL_CODEC_FRAME_LENGTH == 16 ); + + decode_split( &pulses3[ 0 ], &pulses3[ 1 ], psRangeDec, pulses4, silk_shell_code_table3 ); + + decode_split( &pulses2[ 0 ], &pulses2[ 1 ], psRangeDec, pulses3[ 0 ], silk_shell_code_table2 ); + + decode_split( &pulses1[ 0 ], &pulses1[ 1 ], psRangeDec, pulses2[ 0 ], silk_shell_code_table1 ); + decode_split( &pulses0[ 0 ], &pulses0[ 1 ], psRangeDec, pulses1[ 0 ], silk_shell_code_table0 ); + decode_split( &pulses0[ 2 ], &pulses0[ 3 ], psRangeDec, pulses1[ 1 ], silk_shell_code_table0 ); + + decode_split( &pulses1[ 2 ], &pulses1[ 3 ], psRangeDec, pulses2[ 1 ], silk_shell_code_table1 ); + decode_split( &pulses0[ 4 ], &pulses0[ 5 ], psRangeDec, pulses1[ 2 ], silk_shell_code_table0 ); + decode_split( &pulses0[ 6 ], &pulses0[ 7 ], psRangeDec, pulses1[ 3 ], silk_shell_code_table0 ); + + decode_split( &pulses2[ 2 ], &pulses2[ 3 ], psRangeDec, pulses3[ 1 ], silk_shell_code_table2 ); + + decode_split( &pulses1[ 4 ], &pulses1[ 5 ], psRangeDec, pulses2[ 2 ], silk_shell_code_table1 ); + decode_split( &pulses0[ 8 ], &pulses0[ 9 ], psRangeDec, pulses1[ 4 ], silk_shell_code_table0 ); + decode_split( &pulses0[ 10 ], &pulses0[ 11 ], psRangeDec, pulses1[ 5 ], silk_shell_code_table0 ); + + decode_split( &pulses1[ 6 ], &pulses1[ 7 ], psRangeDec, pulses2[ 3 ], silk_shell_code_table1 ); + decode_split( &pulses0[ 12 ], &pulses0[ 13 ], psRangeDec, pulses1[ 6 ], silk_shell_code_table0 ); + decode_split( &pulses0[ 14 ], &pulses0[ 15 ], psRangeDec, pulses1[ 7 ], silk_shell_code_table0 ); +} diff --git a/extern/opus/silk/sigm_Q15.c b/extern/opus/silk/sigm_Q15.c new file mode 100644 index 0000000..3c507d2 --- /dev/null +++ b/extern/opus/silk/sigm_Q15.c @@ -0,0 +1,76 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/* Approximate sigmoid function */ + +#include "SigProc_FIX.h" + +/* fprintf(1, '%d, ', round(1024 * ([1 ./ (1 + exp(-(1:5))), 1] - 1 ./ (1 + exp(-(0:5)))))); */ +static const opus_int32 sigm_LUT_slope_Q10[ 6 ] = { + 237, 153, 73, 30, 12, 7 +}; +/* fprintf(1, '%d, ', round(32767 * 1 ./ (1 + exp(-(0:5))))); */ +static const opus_int32 sigm_LUT_pos_Q15[ 6 ] = { + 16384, 23955, 28861, 31213, 32178, 32548 +}; +/* fprintf(1, '%d, ', round(32767 * 1 ./ (1 + exp((0:5))))); */ +static const opus_int32 sigm_LUT_neg_Q15[ 6 ] = { + 16384, 8812, 3906, 1554, 589, 219 +}; + +opus_int silk_sigm_Q15( + opus_int in_Q5 /* I */ +) +{ + opus_int ind; + + if( in_Q5 < 0 ) { + /* Negative input */ + in_Q5 = -in_Q5; + if( in_Q5 >= 6 * 32 ) { + return 0; /* Clip */ + } else { + /* Linear interpolation of look up table */ + ind = silk_RSHIFT( in_Q5, 5 ); + return( sigm_LUT_neg_Q15[ ind ] - silk_SMULBB( sigm_LUT_slope_Q10[ ind ], in_Q5 & 0x1F ) ); + } + } else { + /* Positive input */ + if( in_Q5 >= 6 * 32 ) { + return 32767; /* clip */ + } else { + /* Linear interpolation of look up table */ + ind = silk_RSHIFT( in_Q5, 5 ); + return( sigm_LUT_pos_Q15[ ind ] + silk_SMULBB( sigm_LUT_slope_Q10[ ind ], in_Q5 & 0x1F ) ); + } + } +} + diff --git a/extern/opus/silk/sort.c b/extern/opus/silk/sort.c new file mode 100644 index 0000000..4fba16f --- /dev/null +++ b/extern/opus/silk/sort.c @@ -0,0 +1,154 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/* Insertion sort (fast for already almost sorted arrays): */ +/* Best case: O(n) for an already sorted array */ +/* Worst case: O(n^2) for an inversely sorted array */ +/* */ +/* Shell short: https://en.wikipedia.org/wiki/Shell_sort */ + +#include "SigProc_FIX.h" + +void silk_insertion_sort_increasing( + opus_int32 *a, /* I/O Unsorted / Sorted vector */ + opus_int *idx, /* O Index vector for the sorted elements */ + const opus_int L, /* I Vector length */ + const opus_int K /* I Number of correctly sorted positions */ +) +{ + opus_int32 value; + opus_int i, j; + + /* Safety checks */ + celt_assert( K > 0 ); + celt_assert( L > 0 ); + celt_assert( L >= K ); + + /* Write start indices in index vector */ + for( i = 0; i < K; i++ ) { + idx[ i ] = i; + } + + /* Sort vector elements by value, increasing order */ + for( i = 1; i < K; i++ ) { + value = a[ i ]; + for( j = i - 1; ( j >= 0 ) && ( value < a[ j ] ); j-- ) { + a[ j + 1 ] = a[ j ]; /* Shift value */ + idx[ j + 1 ] = idx[ j ]; /* Shift index */ + } + a[ j + 1 ] = value; /* Write value */ + idx[ j + 1 ] = i; /* Write index */ + } + + /* If less than L values are asked for, check the remaining values, */ + /* but only spend CPU to ensure that the K first values are correct */ + for( i = K; i < L; i++ ) { + value = a[ i ]; + if( value < a[ K - 1 ] ) { + for( j = K - 2; ( j >= 0 ) && ( value < a[ j ] ); j-- ) { + a[ j + 1 ] = a[ j ]; /* Shift value */ + idx[ j + 1 ] = idx[ j ]; /* Shift index */ + } + a[ j + 1 ] = value; /* Write value */ + idx[ j + 1 ] = i; /* Write index */ + } + } +} + +#ifdef FIXED_POINT +/* This function is only used by the fixed-point build */ +void silk_insertion_sort_decreasing_int16( + opus_int16 *a, /* I/O Unsorted / Sorted vector */ + opus_int *idx, /* O Index vector for the sorted elements */ + const opus_int L, /* I Vector length */ + const opus_int K /* I Number of correctly sorted positions */ +) +{ + opus_int i, j; + opus_int value; + + /* Safety checks */ + celt_assert( K > 0 ); + celt_assert( L > 0 ); + celt_assert( L >= K ); + + /* Write start indices in index vector */ + for( i = 0; i < K; i++ ) { + idx[ i ] = i; + } + + /* Sort vector elements by value, decreasing order */ + for( i = 1; i < K; i++ ) { + value = a[ i ]; + for( j = i - 1; ( j >= 0 ) && ( value > a[ j ] ); j-- ) { + a[ j + 1 ] = a[ j ]; /* Shift value */ + idx[ j + 1 ] = idx[ j ]; /* Shift index */ + } + a[ j + 1 ] = value; /* Write value */ + idx[ j + 1 ] = i; /* Write index */ + } + + /* If less than L values are asked for, check the remaining values, */ + /* but only spend CPU to ensure that the K first values are correct */ + for( i = K; i < L; i++ ) { + value = a[ i ]; + if( value > a[ K - 1 ] ) { + for( j = K - 2; ( j >= 0 ) && ( value > a[ j ] ); j-- ) { + a[ j + 1 ] = a[ j ]; /* Shift value */ + idx[ j + 1 ] = idx[ j ]; /* Shift index */ + } + a[ j + 1 ] = value; /* Write value */ + idx[ j + 1 ] = i; /* Write index */ + } + } +} +#endif + +void silk_insertion_sort_increasing_all_values_int16( + opus_int16 *a, /* I/O Unsorted / Sorted vector */ + const opus_int L /* I Vector length */ +) +{ + opus_int value; + opus_int i, j; + + /* Safety checks */ + celt_assert( L > 0 ); + + /* Sort vector elements by value, increasing order */ + for( i = 1; i < L; i++ ) { + value = a[ i ]; + for( j = i - 1; ( j >= 0 ) && ( value < a[ j ] ); j-- ) { + a[ j + 1 ] = a[ j ]; /* Shift value */ + } + a[ j + 1 ] = value; /* Write value */ + } +} diff --git a/extern/opus/silk/stereo_LR_to_MS.c b/extern/opus/silk/stereo_LR_to_MS.c new file mode 100644 index 0000000..c822666 --- /dev/null +++ b/extern/opus/silk/stereo_LR_to_MS.c @@ -0,0 +1,229 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" +#include "stack_alloc.h" + +/* Convert Left/Right stereo signal to adaptive Mid/Side representation */ +void silk_stereo_LR_to_MS( + stereo_enc_state *state, /* I/O State */ + opus_int16 x1[], /* I/O Left input signal, becomes mid signal */ + opus_int16 x2[], /* I/O Right input signal, becomes side signal */ + opus_int8 ix[ 2 ][ 3 ], /* O Quantization indices */ + opus_int8 *mid_only_flag, /* O Flag: only mid signal coded */ + opus_int32 mid_side_rates_bps[], /* O Bitrates for mid and side signals */ + opus_int32 total_rate_bps, /* I Total bitrate */ + opus_int prev_speech_act_Q8, /* I Speech activity level in previous frame */ + opus_int toMono, /* I Last frame before a stereo->mono transition */ + opus_int fs_kHz, /* I Sample rate (kHz) */ + opus_int frame_length /* I Number of samples */ +) +{ + opus_int n, is10msFrame, denom_Q16, delta0_Q13, delta1_Q13; + opus_int32 sum, diff, smooth_coef_Q16, pred_Q13[ 2 ], pred0_Q13, pred1_Q13; + opus_int32 LP_ratio_Q14, HP_ratio_Q14, frac_Q16, frac_3_Q16, min_mid_rate_bps, width_Q14, w_Q24, deltaw_Q24; + VARDECL( opus_int16, side ); + VARDECL( opus_int16, LP_mid ); + VARDECL( opus_int16, HP_mid ); + VARDECL( opus_int16, LP_side ); + VARDECL( opus_int16, HP_side ); + opus_int16 *mid = &x1[ -2 ]; + SAVE_STACK; + + ALLOC( side, frame_length + 2, opus_int16 ); + /* Convert to basic mid/side signals */ + for( n = 0; n < frame_length + 2; n++ ) { + sum = x1[ n - 2 ] + (opus_int32)x2[ n - 2 ]; + diff = x1[ n - 2 ] - (opus_int32)x2[ n - 2 ]; + mid[ n ] = (opus_int16)silk_RSHIFT_ROUND( sum, 1 ); + side[ n ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( diff, 1 ) ); + } + + /* Buffering */ + silk_memcpy( mid, state->sMid, 2 * sizeof( opus_int16 ) ); + silk_memcpy( side, state->sSide, 2 * sizeof( opus_int16 ) ); + silk_memcpy( state->sMid, &mid[ frame_length ], 2 * sizeof( opus_int16 ) ); + silk_memcpy( state->sSide, &side[ frame_length ], 2 * sizeof( opus_int16 ) ); + + /* LP and HP filter mid signal */ + ALLOC( LP_mid, frame_length, opus_int16 ); + ALLOC( HP_mid, frame_length, opus_int16 ); + for( n = 0; n < frame_length; n++ ) { + sum = silk_RSHIFT_ROUND( silk_ADD_LSHIFT( mid[ n ] + (opus_int32)mid[ n + 2 ], mid[ n + 1 ], 1 ), 2 ); + LP_mid[ n ] = sum; + HP_mid[ n ] = mid[ n + 1 ] - sum; + } + + /* LP and HP filter side signal */ + ALLOC( LP_side, frame_length, opus_int16 ); + ALLOC( HP_side, frame_length, opus_int16 ); + for( n = 0; n < frame_length; n++ ) { + sum = silk_RSHIFT_ROUND( silk_ADD_LSHIFT( side[ n ] + (opus_int32)side[ n + 2 ], side[ n + 1 ], 1 ), 2 ); + LP_side[ n ] = sum; + HP_side[ n ] = side[ n + 1 ] - sum; + } + + /* Find energies and predictors */ + is10msFrame = frame_length == 10 * fs_kHz; + smooth_coef_Q16 = is10msFrame ? + SILK_FIX_CONST( STEREO_RATIO_SMOOTH_COEF / 2, 16 ) : + SILK_FIX_CONST( STEREO_RATIO_SMOOTH_COEF, 16 ); + smooth_coef_Q16 = silk_SMULWB( silk_SMULBB( prev_speech_act_Q8, prev_speech_act_Q8 ), smooth_coef_Q16 ); + + pred_Q13[ 0 ] = 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 ] = silk_stereo_find_predictor( &HP_ratio_Q14, HP_mid, HP_side, &state->mid_side_amp_Q0[ 2 ], frame_length, smooth_coef_Q16 ); + /* Ratio of the norms of residual and mid signals */ + frac_Q16 = silk_SMLABB( HP_ratio_Q14, LP_ratio_Q14, 3 ); + frac_Q16 = silk_min( frac_Q16, SILK_FIX_CONST( 1, 16 ) ); + + /* Determine bitrate distribution between mid and side, and possibly reduce stereo width */ + total_rate_bps -= is10msFrame ? 1200 : 600; /* Subtract approximate bitrate for coding stereo parameters */ + if( total_rate_bps < 1 ) { + total_rate_bps = 1; + } + min_mid_rate_bps = silk_SMLABB( 2000, fs_kHz, 600 ); + silk_assert( min_mid_rate_bps < 32767 ); + /* Default bitrate distribution: 8 parts for Mid and (5+3*frac) parts for Side. so: mid_rate = ( 8 / ( 13 + 3 * frac ) ) * total_ rate */ + frac_3_Q16 = silk_MUL( 3, frac_Q16 ); + mid_side_rates_bps[ 0 ] = silk_DIV32_varQ( total_rate_bps, SILK_FIX_CONST( 8 + 5, 16 ) + frac_3_Q16, 16+3 ); + /* If Mid bitrate below minimum, reduce stereo width */ + 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 = 4 * ( 2 * side_rate - min_rate ) / ( ( 1 + 3 * frac ) * min_rate ) */ + width_Q14 = silk_DIV32_varQ( silk_LSHIFT( mid_side_rates_bps[ 1 ], 1 ) - min_mid_rate_bps, + silk_SMULWB( SILK_FIX_CONST( 1, 16 ) + frac_3_Q16, min_mid_rate_bps ), 14+2 ); + width_Q14 = silk_LIMIT( width_Q14, 0, SILK_FIX_CONST( 1, 14 ) ); + } else { + mid_side_rates_bps[ 1 ] = total_rate_bps - mid_side_rates_bps[ 0 ]; + width_Q14 = SILK_FIX_CONST( 1, 14 ); + } + + /* Smoother */ + state->smth_width_Q14 = (opus_int16)silk_SMLAWB( state->smth_width_Q14, width_Q14 - state->smth_width_Q14, smooth_coef_Q16 ); + + /* At very low bitrates or for inputs that are nearly amplitude panned, switch to panned-mono coding */ + *mid_only_flag = 0; + if( toMono ) { + /* Last frame before stereo->mono transition; collapse stereo width */ + width_Q14 = 0; + pred_Q13[ 0 ] = 0; + pred_Q13[ 1 ] = 0; + silk_stereo_quant_pred( pred_Q13, ix ); + } else if( state->width_prev_Q14 == 0 && + ( 8 * total_rate_bps < 13 * min_mid_rate_bps || silk_SMULWB( frac_Q16, state->smth_width_Q14 ) < SILK_FIX_CONST( 0.05, 14 ) ) ) + { + /* Code as panned-mono; previous frame already had zero width */ + /* Scale down and quantize predictors */ + pred_Q13[ 0 ] = silk_RSHIFT( silk_SMULBB( state->smth_width_Q14, pred_Q13[ 0 ] ), 14 ); + pred_Q13[ 1 ] = silk_RSHIFT( silk_SMULBB( state->smth_width_Q14, pred_Q13[ 1 ] ), 14 ); + silk_stereo_quant_pred( pred_Q13, ix ); + /* Collapse stereo width */ + 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 = 1; + } else if( state->width_prev_Q14 != 0 && + ( 8 * total_rate_bps < 11 * min_mid_rate_bps || silk_SMULWB( frac_Q16, state->smth_width_Q14 ) < SILK_FIX_CONST( 0.02, 14 ) ) ) + { + /* Transition to zero-width stereo */ + /* Scale down and quantize predictors */ + pred_Q13[ 0 ] = silk_RSHIFT( silk_SMULBB( state->smth_width_Q14, pred_Q13[ 0 ] ), 14 ); + pred_Q13[ 1 ] = silk_RSHIFT( silk_SMULBB( state->smth_width_Q14, pred_Q13[ 1 ] ), 14 ); + silk_stereo_quant_pred( pred_Q13, ix ); + /* Collapse stereo width */ + width_Q14 = 0; + pred_Q13[ 0 ] = 0; + pred_Q13[ 1 ] = 0; + } else if( state->smth_width_Q14 > SILK_FIX_CONST( 0.95, 14 ) ) { + /* Full-width stereo coding */ + silk_stereo_quant_pred( pred_Q13, ix ); + width_Q14 = SILK_FIX_CONST( 1, 14 ); + } else { + /* Reduced-width stereo coding; scale down and quantize predictors */ + pred_Q13[ 0 ] = silk_RSHIFT( silk_SMULBB( state->smth_width_Q14, pred_Q13[ 0 ] ), 14 ); + pred_Q13[ 1 ] = silk_RSHIFT( silk_SMULBB( state->smth_width_Q14, pred_Q13[ 1 ] ), 14 ); + silk_stereo_quant_pred( pred_Q13, ix ); + width_Q14 = state->smth_width_Q14; + } + + /* Make sure to keep on encoding until the tapered output has been transmitted */ + if( *mid_only_flag == 1 ) { + state->silent_side_len += frame_length - STEREO_INTERP_LEN_MS * fs_kHz; + if( state->silent_side_len < LA_SHAPE_MS * fs_kHz ) { + *mid_only_flag = 0; + } else { + /* Limit to avoid wrapping around */ + state->silent_side_len = 10000; + } + } else { + state->silent_side_len = 0; + } + + if( *mid_only_flag == 0 && mid_side_rates_bps[ 1 ] < 1 ) { + mid_side_rates_bps[ 1 ] = 1; + mid_side_rates_bps[ 0 ] = silk_max_int( 1, total_rate_bps - mid_side_rates_bps[ 1 ]); + } + + /* Interpolate predictors and subtract prediction from side channel */ + pred0_Q13 = -state->pred_prev_Q13[ 0 ]; + pred1_Q13 = -state->pred_prev_Q13[ 1 ]; + w_Q24 = silk_LSHIFT( state->width_prev_Q14, 10 ); + denom_Q16 = silk_DIV32_16( (opus_int32)1 << 16, STEREO_INTERP_LEN_MS * fs_kHz ); + delta0_Q13 = -silk_RSHIFT_ROUND( silk_SMULBB( pred_Q13[ 0 ] - state->pred_prev_Q13[ 0 ], denom_Q16 ), 16 ); + delta1_Q13 = -silk_RSHIFT_ROUND( silk_SMULBB( pred_Q13[ 1 ] - state->pred_prev_Q13[ 1 ], denom_Q16 ), 16 ); + deltaw_Q24 = silk_LSHIFT( silk_SMULWB( width_Q14 - state->width_prev_Q14, denom_Q16 ), 10 ); + for( n = 0; n < STEREO_INTERP_LEN_MS * fs_kHz; n++ ) { + pred0_Q13 += delta0_Q13; + pred1_Q13 += delta1_Q13; + w_Q24 += deltaw_Q24; + sum = silk_LSHIFT( silk_ADD_LSHIFT( mid[ n ] + (opus_int32)mid[ n + 2 ], mid[ n + 1 ], 1 ), 9 ); /* Q11 */ + sum = silk_SMLAWB( silk_SMULWB( w_Q24, side[ n + 1 ] ), sum, pred0_Q13 ); /* Q8 */ + sum = silk_SMLAWB( sum, silk_LSHIFT( (opus_int32)mid[ n + 1 ], 11 ), pred1_Q13 ); /* Q8 */ + x2[ n - 1 ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( sum, 8 ) ); + } + + pred0_Q13 = -pred_Q13[ 0 ]; + pred1_Q13 = -pred_Q13[ 1 ]; + w_Q24 = silk_LSHIFT( width_Q14, 10 ); + for( n = STEREO_INTERP_LEN_MS * fs_kHz; n < frame_length; n++ ) { + sum = silk_LSHIFT( silk_ADD_LSHIFT( mid[ n ] + (opus_int32)mid[ n + 2 ], mid[ n + 1 ], 1 ), 9 ); /* Q11 */ + sum = silk_SMLAWB( silk_SMULWB( w_Q24, side[ n + 1 ] ), sum, pred0_Q13 ); /* Q8 */ + sum = silk_SMLAWB( sum, silk_LSHIFT( (opus_int32)mid[ n + 1 ], 11 ), pred1_Q13 ); /* Q8 */ + x2[ n - 1 ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( sum, 8 ) ); + } + state->pred_prev_Q13[ 0 ] = (opus_int16)pred_Q13[ 0 ]; + state->pred_prev_Q13[ 1 ] = (opus_int16)pred_Q13[ 1 ]; + state->width_prev_Q14 = (opus_int16)width_Q14; + RESTORE_STACK; +} diff --git a/extern/opus/silk/stereo_MS_to_LR.c b/extern/opus/silk/stereo_MS_to_LR.c new file mode 100644 index 0000000..62521a4 --- /dev/null +++ b/extern/opus/silk/stereo_MS_to_LR.c @@ -0,0 +1,85 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/* Convert adaptive Mid/Side representation to Left/Right stereo signal */ +void silk_stereo_MS_to_LR( + stereo_dec_state *state, /* I/O State */ + opus_int16 x1[], /* I/O Left input signal, becomes mid signal */ + opus_int16 x2[], /* I/O Right input signal, becomes side signal */ + const opus_int32 pred_Q13[], /* I Predictors */ + opus_int fs_kHz, /* I Samples rate (kHz) */ + opus_int frame_length /* I Number of samples */ +) +{ + opus_int n, denom_Q16, delta0_Q13, delta1_Q13; + opus_int32 sum, diff, pred0_Q13, pred1_Q13; + + /* Buffering */ + silk_memcpy( x1, state->sMid, 2 * sizeof( opus_int16 ) ); + silk_memcpy( x2, state->sSide, 2 * sizeof( opus_int16 ) ); + silk_memcpy( state->sMid, &x1[ frame_length ], 2 * sizeof( opus_int16 ) ); + silk_memcpy( state->sSide, &x2[ frame_length ], 2 * sizeof( opus_int16 ) ); + + /* Interpolate predictors and add prediction to side channel */ + pred0_Q13 = state->pred_prev_Q13[ 0 ]; + pred1_Q13 = state->pred_prev_Q13[ 1 ]; + denom_Q16 = silk_DIV32_16( (opus_int32)1 << 16, STEREO_INTERP_LEN_MS * fs_kHz ); + delta0_Q13 = silk_RSHIFT_ROUND( silk_SMULBB( pred_Q13[ 0 ] - state->pred_prev_Q13[ 0 ], denom_Q16 ), 16 ); + delta1_Q13 = silk_RSHIFT_ROUND( silk_SMULBB( pred_Q13[ 1 ] - state->pred_prev_Q13[ 1 ], denom_Q16 ), 16 ); + for( n = 0; n < STEREO_INTERP_LEN_MS * fs_kHz; n++ ) { + pred0_Q13 += delta0_Q13; + pred1_Q13 += delta1_Q13; + sum = silk_LSHIFT( silk_ADD_LSHIFT( x1[ n ] + x1[ n + 2 ], x1[ n + 1 ], 1 ), 9 ); /* Q11 */ + sum = silk_SMLAWB( silk_LSHIFT( (opus_int32)x2[ n + 1 ], 8 ), sum, pred0_Q13 ); /* Q8 */ + sum = silk_SMLAWB( sum, silk_LSHIFT( (opus_int32)x1[ n + 1 ], 11 ), pred1_Q13 ); /* Q8 */ + x2[ n + 1 ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( sum, 8 ) ); + } + pred0_Q13 = pred_Q13[ 0 ]; + pred1_Q13 = pred_Q13[ 1 ]; + for( n = STEREO_INTERP_LEN_MS * fs_kHz; n < frame_length; n++ ) { + sum = silk_LSHIFT( silk_ADD_LSHIFT( x1[ n ] + x1[ n + 2 ], x1[ n + 1 ], 1 ), 9 ); /* Q11 */ + sum = silk_SMLAWB( silk_LSHIFT( (opus_int32)x2[ n + 1 ], 8 ), sum, pred0_Q13 ); /* Q8 */ + sum = silk_SMLAWB( sum, silk_LSHIFT( (opus_int32)x1[ n + 1 ], 11 ), pred1_Q13 ); /* Q8 */ + x2[ n + 1 ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( sum, 8 ) ); + } + state->pred_prev_Q13[ 0 ] = pred_Q13[ 0 ]; + state->pred_prev_Q13[ 1 ] = pred_Q13[ 1 ]; + + /* Convert to left/right signals */ + for( n = 0; n < frame_length; n++ ) { + sum = x1[ n + 1 ] + (opus_int32)x2[ n + 1 ]; + diff = x1[ n + 1 ] - (opus_int32)x2[ n + 1 ]; + x1[ n + 1 ] = (opus_int16)silk_SAT16( sum ); + x2[ n + 1 ] = (opus_int16)silk_SAT16( diff ); + } +} diff --git a/extern/opus/silk/stereo_decode_pred.c b/extern/opus/silk/stereo_decode_pred.c new file mode 100644 index 0000000..56ba392 --- /dev/null +++ b/extern/opus/silk/stereo_decode_pred.c @@ -0,0 +1,73 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/* Decode mid/side predictors */ +void silk_stereo_decode_pred( + ec_dec *psRangeDec, /* I/O Compressor data structure */ + opus_int32 pred_Q13[] /* O Predictors */ +) +{ + opus_int n, ix[ 2 ][ 3 ]; + opus_int32 low_Q13, step_Q13; + + /* Entropy decoding */ + n = ec_dec_icdf( psRangeDec, silk_stereo_pred_joint_iCDF, 8 ); + ix[ 0 ][ 2 ] = silk_DIV32_16( n, 5 ); + ix[ 1 ][ 2 ] = n - 5 * ix[ 0 ][ 2 ]; + for( n = 0; n < 2; n++ ) { + ix[ n ][ 0 ] = ec_dec_icdf( psRangeDec, silk_uniform3_iCDF, 8 ); + ix[ n ][ 1 ] = ec_dec_icdf( psRangeDec, silk_uniform5_iCDF, 8 ); + } + + /* Dequantize */ + for( n = 0; n < 2; n++ ) { + ix[ n ][ 0 ] += 3 * ix[ n ][ 2 ]; + low_Q13 = silk_stereo_pred_quant_Q13[ ix[ n ][ 0 ] ]; + step_Q13 = silk_SMULWB( silk_stereo_pred_quant_Q13[ ix[ n ][ 0 ] + 1 ] - low_Q13, + SILK_FIX_CONST( 0.5 / STEREO_QUANT_SUB_STEPS, 16 ) ); + pred_Q13[ n ] = silk_SMLABB( low_Q13, step_Q13, 2 * ix[ n ][ 1 ] + 1 ); + } + + /* Subtract second from first predictor (helps when actually applying these) */ + pred_Q13[ 0 ] -= pred_Q13[ 1 ]; +} + +/* Decode mid-only flag */ +void silk_stereo_decode_mid_only( + ec_dec *psRangeDec, /* I/O Compressor data structure */ + opus_int *decode_only_mid /* O Flag that only mid channel has been coded */ +) +{ + /* Decode flag that only mid channel is coded */ + *decode_only_mid = ec_dec_icdf( psRangeDec, silk_stereo_only_code_mid_iCDF, 8 ); +} diff --git a/extern/opus/silk/stereo_encode_pred.c b/extern/opus/silk/stereo_encode_pred.c new file mode 100644 index 0000000..03becb6 --- /dev/null +++ b/extern/opus/silk/stereo_encode_pred.c @@ -0,0 +1,62 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/* Entropy code the mid/side quantization indices */ +void silk_stereo_encode_pred( + ec_enc *psRangeEnc, /* I/O Compressor data structure */ + opus_int8 ix[ 2 ][ 3 ] /* I Quantization indices */ +) +{ + opus_int n; + + /* Entropy coding */ + n = 5 * ix[ 0 ][ 2 ] + ix[ 1 ][ 2 ]; + celt_assert( n < 25 ); + ec_enc_icdf( psRangeEnc, n, silk_stereo_pred_joint_iCDF, 8 ); + for( n = 0; n < 2; n++ ) { + celt_assert( ix[ n ][ 0 ] < 3 ); + celt_assert( ix[ n ][ 1 ] < STEREO_QUANT_SUB_STEPS ); + ec_enc_icdf( psRangeEnc, ix[ n ][ 0 ], silk_uniform3_iCDF, 8 ); + ec_enc_icdf( psRangeEnc, ix[ n ][ 1 ], silk_uniform5_iCDF, 8 ); + } +} + +/* Entropy code the mid-only flag */ +void silk_stereo_encode_mid_only( + ec_enc *psRangeEnc, /* I/O Compressor data structure */ + opus_int8 mid_only_flag +) +{ + /* Encode flag that only mid channel is coded */ + ec_enc_icdf( psRangeEnc, mid_only_flag, silk_stereo_only_code_mid_iCDF, 8 ); +} diff --git a/extern/opus/silk/stereo_find_predictor.c b/extern/opus/silk/stereo_find_predictor.c new file mode 100644 index 0000000..e30e90b --- /dev/null +++ b/extern/opus/silk/stereo_find_predictor.c @@ -0,0 +1,79 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/* Find least-squares prediction gain for one signal based on another and quantize it */ +opus_int32 silk_stereo_find_predictor( /* O Returns predictor in Q13 */ + opus_int32 *ratio_Q14, /* O Ratio of residual and mid energies */ + const opus_int16 x[], /* I Basis signal */ + const opus_int16 y[], /* I Target signal */ + opus_int32 mid_res_amp_Q0[], /* I/O Smoothed mid, residual norms */ + opus_int length, /* I Number of samples */ + opus_int smooth_coef_Q16 /* I Smoothing coefficient */ +) +{ + opus_int scale, scale1, scale2; + opus_int32 nrgx, nrgy, corr, pred_Q13, pred2_Q10; + + /* Find predictor */ + silk_sum_sqr_shift( &nrgx, &scale1, x, length ); + silk_sum_sqr_shift( &nrgy, &scale2, y, length ); + scale = silk_max_int( scale1, scale2 ); + scale = scale + ( scale & 1 ); /* make even */ + nrgy = silk_RSHIFT32( nrgy, scale - scale2 ); + nrgx = silk_RSHIFT32( nrgx, scale - scale1 ); + nrgx = silk_max_int( nrgx, 1 ); + corr = silk_inner_prod_aligned_scale( x, y, scale, length ); + pred_Q13 = silk_DIV32_varQ( corr, nrgx, 13 ); + pred_Q13 = silk_LIMIT( pred_Q13, -(1 << 14), 1 << 14 ); + pred2_Q10 = silk_SMULWB( pred_Q13, pred_Q13 ); + + /* Faster update for signals with large prediction parameters */ + smooth_coef_Q16 = (opus_int)silk_max_int( smooth_coef_Q16, silk_abs( pred2_Q10 ) ); + + /* Smoothed mid and residual norms */ + silk_assert( smooth_coef_Q16 < 32768 ); + scale = silk_RSHIFT( scale, 1 ); + mid_res_amp_Q0[ 0 ] = silk_SMLAWB( mid_res_amp_Q0[ 0 ], silk_LSHIFT( silk_SQRT_APPROX( nrgx ), scale ) - mid_res_amp_Q0[ 0 ], + smooth_coef_Q16 ); + /* Residual energy = nrgy - 2 * pred * corr + pred^2 * nrgx */ + nrgy = silk_SUB_LSHIFT32( nrgy, silk_SMULWB( corr, pred_Q13 ), 3 + 1 ); + nrgy = silk_ADD_LSHIFT32( nrgy, silk_SMULWB( nrgx, pred2_Q10 ), 6 ); + mid_res_amp_Q0[ 1 ] = silk_SMLAWB( mid_res_amp_Q0[ 1 ], silk_LSHIFT( silk_SQRT_APPROX( nrgy ), scale ) - mid_res_amp_Q0[ 1 ], + smooth_coef_Q16 ); + + /* Ratio of smoothed residual and mid norms */ + *ratio_Q14 = silk_DIV32_varQ( mid_res_amp_Q0[ 1 ], silk_max( mid_res_amp_Q0[ 0 ], 1 ), 14 ); + *ratio_Q14 = silk_LIMIT( *ratio_Q14, 0, 32767 ); + + return pred_Q13; +} diff --git a/extern/opus/silk/stereo_quant_pred.c b/extern/opus/silk/stereo_quant_pred.c new file mode 100644 index 0000000..d4ced6c --- /dev/null +++ b/extern/opus/silk/stereo_quant_pred.c @@ -0,0 +1,73 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/* Quantize mid/side predictors */ +void silk_stereo_quant_pred( + opus_int32 pred_Q13[], /* I/O Predictors (out: quantized) */ + opus_int8 ix[ 2 ][ 3 ] /* O Quantization indices */ +) +{ + opus_int i, j, n; + opus_int32 low_Q13, step_Q13, lvl_Q13, err_min_Q13, err_Q13, quant_pred_Q13 = 0; + + /* Quantize */ + for( n = 0; n < 2; n++ ) { + /* Brute-force search over quantization levels */ + err_min_Q13 = silk_int32_MAX; + for( i = 0; i < STEREO_QUANT_TAB_SIZE - 1; i++ ) { + low_Q13 = silk_stereo_pred_quant_Q13[ i ]; + step_Q13 = silk_SMULWB( silk_stereo_pred_quant_Q13[ i + 1 ] - low_Q13, + SILK_FIX_CONST( 0.5 / STEREO_QUANT_SUB_STEPS, 16 ) ); + for( j = 0; j < STEREO_QUANT_SUB_STEPS; j++ ) { + lvl_Q13 = silk_SMLABB( low_Q13, step_Q13, 2 * j + 1 ); + err_Q13 = 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; + } else { + /* Error increasing, so we're past the optimum */ + goto done; + } + } + } + done: + ix[ n ][ 2 ] = silk_DIV32_16( ix[ n ][ 0 ], 3 ); + ix[ n ][ 0 ] -= ix[ n ][ 2 ] * 3; + pred_Q13[ n ] = quant_pred_Q13; + } + + /* Subtract second from first predictor (helps when actually applying these) */ + pred_Q13[ 0 ] -= pred_Q13[ 1 ]; +} diff --git a/extern/opus/silk/structs.h b/extern/opus/silk/structs.h new file mode 100644 index 0000000..3380c75 --- /dev/null +++ b/extern/opus/silk/structs.h @@ -0,0 +1,329 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifndef SILK_STRUCTS_H +#define SILK_STRUCTS_H + +#include "typedef.h" +#include "SigProc_FIX.h" +#include "define.h" +#include "entenc.h" +#include "entdec.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +/************************************/ +/* Noise shaping quantization state */ +/************************************/ +typedef struct { + opus_int16 xq[ 2 * MAX_FRAME_LENGTH ]; /* Buffer for quantized output signal */ + opus_int32 sLTP_shp_Q14[ 2 * MAX_FRAME_LENGTH ]; + opus_int32 sLPC_Q14[ MAX_SUB_FRAME_LENGTH + NSQ_LPC_BUF_LENGTH ]; + opus_int32 sAR2_Q14[ MAX_SHAPE_LPC_ORDER ]; + opus_int32 sLF_AR_shp_Q14; + opus_int32 sDiff_shp_Q14; + opus_int lagPrev; + opus_int sLTP_buf_idx; + opus_int sLTP_shp_buf_idx; + opus_int32 rand_seed; + opus_int32 prev_gain_Q16; + opus_int rewhite_flag; +} silk_nsq_state; + +/********************************/ +/* VAD state */ +/********************************/ +typedef struct { + opus_int32 AnaState[ 2 ]; /* Analysis filterbank state: 0-8 kHz */ + opus_int32 AnaState1[ 2 ]; /* Analysis filterbank state: 0-4 kHz */ + opus_int32 AnaState2[ 2 ]; /* Analysis filterbank state: 0-2 kHz */ + opus_int32 XnrgSubfr[ VAD_N_BANDS ]; /* Subframe energies */ + opus_int32 NrgRatioSmth_Q8[ VAD_N_BANDS ]; /* Smoothed energy level in each band */ + opus_int16 HPstate; /* State of differentiator in the lowest band */ + opus_int32 NL[ VAD_N_BANDS ]; /* Noise energy level in each band */ + opus_int32 inv_NL[ VAD_N_BANDS ]; /* Inverse noise energy level in each band */ + opus_int32 NoiseLevelBias[ VAD_N_BANDS ]; /* Noise level estimator bias/offset */ + opus_int32 counter; /* Frame counter used in the initial phase */ +} silk_VAD_state; + +/* Variable cut-off low-pass filter state */ +typedef struct { + opus_int32 In_LP_State[ 2 ]; /* Low pass filter state */ + opus_int32 transition_frame_no; /* Counter which is mapped to a cut-off frequency */ + opus_int mode; /* Operating mode, <0: switch down, >0: switch up; 0: do nothing */ + opus_int32 saved_fs_kHz; /* If non-zero, holds the last sampling rate before a bandwidth switching reset. */ +} silk_LP_state; + +/* Structure containing NLSF codebook */ +typedef struct { + const opus_int16 nVectors; + const opus_int16 order; + const opus_int16 quantStepSize_Q16; + const opus_int16 invQuantStepSize_Q6; + const opus_uint8 *CB1_NLSF_Q8; + const opus_int16 *CB1_Wght_Q9; + const opus_uint8 *CB1_iCDF; + const opus_uint8 *pred_Q8; + const opus_uint8 *ec_sel; + const opus_uint8 *ec_iCDF; + const opus_uint8 *ec_Rates_Q5; + const opus_int16 *deltaMin_Q15; +} silk_NLSF_CB_struct; + +typedef struct { + opus_int16 pred_prev_Q13[ 2 ]; + opus_int16 sMid[ 2 ]; + opus_int16 sSide[ 2 ]; + opus_int32 mid_side_amp_Q0[ 4 ]; + opus_int16 smth_width_Q14; + opus_int16 width_prev_Q14; + opus_int16 silent_side_len; + opus_int8 predIx[ MAX_FRAMES_PER_PACKET ][ 2 ][ 3 ]; + opus_int8 mid_only_flags[ MAX_FRAMES_PER_PACKET ]; +} stereo_enc_state; + +typedef struct { + opus_int16 pred_prev_Q13[ 2 ]; + opus_int16 sMid[ 2 ]; + opus_int16 sSide[ 2 ]; +} stereo_dec_state; + +typedef struct { + opus_int8 GainsIndices[ MAX_NB_SUBFR ]; + opus_int8 LTPIndex[ MAX_NB_SUBFR ]; + opus_int8 NLSFIndices[ MAX_LPC_ORDER + 1 ]; + opus_int16 lagIndex; + opus_int8 contourIndex; + opus_int8 signalType; + opus_int8 quantOffsetType; + opus_int8 NLSFInterpCoef_Q2; + opus_int8 PERIndex; + opus_int8 LTP_scaleIndex; + opus_int8 Seed; +} SideInfoIndices; + +/********************************/ +/* Encoder state */ +/********************************/ +typedef struct { + opus_int32 In_HP_State[ 2 ]; /* High pass filter state */ + opus_int32 variable_HP_smth1_Q15; /* State of first smoother */ + opus_int32 variable_HP_smth2_Q15; /* State of second smoother */ + silk_LP_state sLP; /* Low pass filter state */ + silk_VAD_state sVAD; /* Voice activity detector state */ + silk_nsq_state sNSQ; /* Noise Shape Quantizer State */ + opus_int16 prev_NLSFq_Q15[ MAX_LPC_ORDER ]; /* Previously quantized NLSF vector */ + opus_int speech_activity_Q8; /* Speech activity */ + opus_int allow_bandwidth_switch; /* Flag indicating that switching of internal bandwidth is allowed */ + opus_int8 LBRRprevLastGainIndex; + opus_int8 prevSignalType; + opus_int prevLag; + opus_int pitch_LPC_win_length; + opus_int max_pitch_lag; /* Highest possible pitch lag (samples) */ + opus_int32 API_fs_Hz; /* API sampling frequency (Hz) */ + opus_int32 prev_API_fs_Hz; /* Previous API sampling frequency (Hz) */ + opus_int maxInternal_fs_Hz; /* Maximum internal sampling frequency (Hz) */ + opus_int minInternal_fs_Hz; /* Minimum internal sampling frequency (Hz) */ + opus_int desiredInternal_fs_Hz; /* Soft request for internal sampling frequency (Hz) */ + opus_int fs_kHz; /* Internal sampling frequency (kHz) */ + opus_int nb_subfr; /* Number of 5 ms subframes in a frame */ + opus_int frame_length; /* Frame length (samples) */ + opus_int subfr_length; /* Subframe length (samples) */ + opus_int ltp_mem_length; /* Length of LTP memory */ + opus_int la_pitch; /* Look-ahead for pitch analysis (samples) */ + opus_int la_shape; /* Look-ahead for noise shape analysis (samples) */ + opus_int shapeWinLength; /* Window length for noise shape analysis (samples) */ + opus_int32 TargetRate_bps; /* Target bitrate (bps) */ + opus_int PacketSize_ms; /* Number of milliseconds to put in each packet */ + opus_int PacketLoss_perc; /* Packet loss rate measured by farend */ + opus_int32 frameCounter; + opus_int Complexity; /* Complexity setting */ + opus_int nStatesDelayedDecision; /* Number of states in delayed decision quantization */ + opus_int useInterpolatedNLSFs; /* Flag for using NLSF interpolation */ + opus_int shapingLPCOrder; /* Filter order for noise shaping filters */ + opus_int predictLPCOrder; /* Filter order for prediction filters */ + opus_int pitchEstimationComplexity; /* Complexity level for pitch estimator */ + opus_int pitchEstimationLPCOrder; /* Whitening filter order for pitch estimator */ + opus_int32 pitchEstimationThreshold_Q16; /* Threshold for pitch estimator */ + opus_int32 sum_log_gain_Q7; /* Cumulative max prediction gain */ + opus_int NLSF_MSVQ_Survivors; /* Number of survivors in NLSF MSVQ */ + opus_int first_frame_after_reset; /* Flag for deactivating NLSF interpolation, pitch prediction */ + opus_int controlled_since_last_payload; /* Flag for ensuring codec_control only runs once per packet */ + opus_int warping_Q16; /* Warping parameter for warped noise shaping */ + opus_int useCBR; /* Flag to enable constant bitrate */ + opus_int prefillFlag; /* Flag to indicate that only buffers are prefilled, no coding */ + const opus_uint8 *pitch_lag_low_bits_iCDF; /* Pointer to iCDF table for low bits of pitch lag index */ + const opus_uint8 *pitch_contour_iCDF; /* Pointer to iCDF table for pitch contour index */ + const silk_NLSF_CB_struct *psNLSF_CB; /* Pointer to NLSF codebook */ + opus_int input_quality_bands_Q15[ VAD_N_BANDS ]; + opus_int input_tilt_Q15; + opus_int SNR_dB_Q7; /* Quality setting */ + + opus_int8 VAD_flags[ MAX_FRAMES_PER_PACKET ]; + opus_int8 LBRR_flag; + opus_int LBRR_flags[ MAX_FRAMES_PER_PACKET ]; + + SideInfoIndices indices; + opus_int8 pulses[ MAX_FRAME_LENGTH ]; + + int arch; + + /* Input/output buffering */ + opus_int16 inputBuf[ MAX_FRAME_LENGTH + 2 ]; /* Buffer containing input signal */ + opus_int inputBufIx; + opus_int nFramesPerPacket; + opus_int nFramesEncoded; /* Number of frames analyzed in current packet */ + + opus_int nChannelsAPI; + opus_int nChannelsInternal; + opus_int channelNb; + + /* Parameters For LTP scaling Control */ + opus_int frames_since_onset; + + /* Specifically for entropy coding */ + opus_int ec_prevSignalType; + opus_int16 ec_prevLagIndex; + + silk_resampler_state_struct resampler_state; + + /* DTX */ + opus_int useDTX; /* Flag to enable DTX */ + opus_int inDTX; /* Flag to signal DTX period */ + opus_int noSpeechCounter; /* Counts concecutive nonactive frames, used by DTX */ + + /* Inband Low Bitrate Redundancy (LBRR) data */ + opus_int useInBandFEC; /* Saves the API setting for query */ + opus_int LBRR_enabled; /* Depends on useInBandFRC, bitrate and packet loss rate */ + opus_int LBRR_GainIncreases; /* Gains increment for coding LBRR frames */ + SideInfoIndices indices_LBRR[ MAX_FRAMES_PER_PACKET ]; + opus_int8 pulses_LBRR[ MAX_FRAMES_PER_PACKET ][ MAX_FRAME_LENGTH ]; +} silk_encoder_state; + + +/* Struct for Packet Loss Concealment */ +typedef struct { + opus_int32 pitchL_Q8; /* Pitch lag to use for voiced concealment */ + opus_int16 LTPCoef_Q14[ LTP_ORDER ]; /* LTP coeficients to use for voiced concealment */ + opus_int16 prevLPC_Q12[ MAX_LPC_ORDER ]; + opus_int last_frame_lost; /* Was previous frame lost */ + opus_int32 rand_seed; /* Seed for unvoiced signal generation */ + opus_int16 randScale_Q14; /* Scaling of unvoiced random signal */ + opus_int32 conc_energy; + opus_int conc_energy_shift; + opus_int16 prevLTP_scale_Q14; + opus_int32 prevGain_Q16[ 2 ]; + opus_int fs_kHz; + opus_int nb_subfr; + opus_int subfr_length; +} silk_PLC_struct; + +/* Struct for CNG */ +typedef struct { + opus_int32 CNG_exc_buf_Q14[ MAX_FRAME_LENGTH ]; + opus_int16 CNG_smth_NLSF_Q15[ MAX_LPC_ORDER ]; + opus_int32 CNG_synth_state[ MAX_LPC_ORDER ]; + opus_int32 CNG_smth_Gain_Q16; + opus_int32 rand_seed; + opus_int fs_kHz; +} silk_CNG_struct; + +/********************************/ +/* Decoder state */ +/********************************/ +typedef struct { + opus_int32 prev_gain_Q16; + opus_int32 exc_Q14[ MAX_FRAME_LENGTH ]; + opus_int32 sLPC_Q14_buf[ MAX_LPC_ORDER ]; + opus_int16 outBuf[ MAX_FRAME_LENGTH + 2 * MAX_SUB_FRAME_LENGTH ]; /* Buffer for output signal */ + opus_int lagPrev; /* Previous Lag */ + opus_int8 LastGainIndex; /* Previous gain index */ + opus_int fs_kHz; /* Sampling frequency in kHz */ + opus_int32 fs_API_hz; /* API sample frequency (Hz) */ + opus_int nb_subfr; /* Number of 5 ms subframes in a frame */ + opus_int frame_length; /* Frame length (samples) */ + opus_int subfr_length; /* Subframe length (samples) */ + opus_int ltp_mem_length; /* Length of LTP memory */ + opus_int LPC_order; /* LPC order */ + opus_int16 prevNLSF_Q15[ MAX_LPC_ORDER ]; /* Used to interpolate LSFs */ + opus_int first_frame_after_reset; /* Flag for deactivating NLSF interpolation */ + const opus_uint8 *pitch_lag_low_bits_iCDF; /* Pointer to iCDF table for low bits of pitch lag index */ + const opus_uint8 *pitch_contour_iCDF; /* Pointer to iCDF table for pitch contour index */ + + /* For buffering payload in case of more frames per packet */ + opus_int nFramesDecoded; + opus_int nFramesPerPacket; + + /* Specifically for entropy coding */ + opus_int ec_prevSignalType; + opus_int16 ec_prevLagIndex; + + opus_int VAD_flags[ MAX_FRAMES_PER_PACKET ]; + opus_int LBRR_flag; + opus_int LBRR_flags[ MAX_FRAMES_PER_PACKET ]; + + silk_resampler_state_struct resampler_state; + + const silk_NLSF_CB_struct *psNLSF_CB; /* Pointer to NLSF codebook */ + + /* Quantization indices */ + SideInfoIndices indices; + + /* CNG state */ + silk_CNG_struct sCNG; + + /* Stuff used for PLC */ + opus_int lossCnt; + opus_int prevSignalType; + int arch; + + silk_PLC_struct sPLC; + +} silk_decoder_state; + +/************************/ +/* Decoder control */ +/************************/ +typedef struct { + /* Prediction and coding parameters */ + opus_int pitchL[ MAX_NB_SUBFR ]; + opus_int32 Gains_Q16[ MAX_NB_SUBFR ]; + /* Holds interpolated and final coefficients, 4-byte aligned */ + silk_DWORD_ALIGN opus_int16 PredCoef_Q12[ 2 ][ MAX_LPC_ORDER ]; + opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ]; + opus_int LTP_scale_Q14; +} silk_decoder_control; + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/extern/opus/silk/sum_sqr_shift.c b/extern/opus/silk/sum_sqr_shift.c new file mode 100644 index 0000000..4fd0c3d --- /dev/null +++ b/extern/opus/silk/sum_sqr_shift.c @@ -0,0 +1,83 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" + +/* Compute number of bits to right shift the sum of squares of a vector */ +/* of int16s to make it fit in an int32 */ +void silk_sum_sqr_shift( + opus_int32 *energy, /* O Energy of x, after shifting to the right */ + opus_int *shift, /* O Number of bits right shift applied to energy */ + const opus_int16 *x, /* I Input vector */ + opus_int len /* I Length of input vector */ +) +{ + opus_int i, shft; + opus_uint32 nrg_tmp; + opus_int32 nrg; + + /* Do a first run with the maximum shift we could have. */ + shft = 31-silk_CLZ32(len); + /* Let's be conservative with rounding and start with nrg=len. */ + nrg = len; + for( i = 0; i < len - 1; i += 2 ) { + nrg_tmp = silk_SMULBB( x[ i ], x[ i ] ); + nrg_tmp = silk_SMLABB_ovflw( nrg_tmp, x[ i + 1 ], x[ i + 1 ] ); + nrg = (opus_int32)silk_ADD_RSHIFT_uint( nrg, nrg_tmp, shft ); + } + if( i < len ) { + /* One sample left to process */ + nrg_tmp = silk_SMULBB( x[ i ], x[ i ] ); + nrg = (opus_int32)silk_ADD_RSHIFT_uint( nrg, nrg_tmp, shft ); + } + silk_assert( nrg >= 0 ); + /* Make sure the result will fit in a 32-bit signed integer with two bits + of headroom. */ + shft = silk_max_32(0, shft+3 - silk_CLZ32(nrg)); + nrg = 0; + for( i = 0 ; i < len - 1; i += 2 ) { + nrg_tmp = silk_SMULBB( x[ i ], x[ i ] ); + nrg_tmp = silk_SMLABB_ovflw( nrg_tmp, x[ i + 1 ], x[ i + 1 ] ); + nrg = (opus_int32)silk_ADD_RSHIFT_uint( nrg, nrg_tmp, shft ); + } + if( i < len ) { + /* One sample left to process */ + nrg_tmp = silk_SMULBB( x[ i ], x[ i ] ); + nrg = (opus_int32)silk_ADD_RSHIFT_uint( nrg, nrg_tmp, shft ); + } + + silk_assert( nrg >= 0 ); + + /* Output arguments */ + *shift = shft; + *energy = nrg; +} + diff --git a/extern/opus/silk/table_LSF_cos.c b/extern/opus/silk/table_LSF_cos.c new file mode 100644 index 0000000..ec9dc63 --- /dev/null +++ b/extern/opus/silk/table_LSF_cos.c @@ -0,0 +1,70 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "tables.h" + +/* Cosine approximation table for LSF conversion */ +/* Q12 values (even) */ +const opus_int16 silk_LSFCosTab_FIX_Q12[ LSF_COS_TAB_SZ_FIX + 1 ] = { + 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 +}; diff --git a/extern/opus/silk/tables.h b/extern/opus/silk/tables.h new file mode 100644 index 0000000..95230c4 --- /dev/null +++ b/extern/opus/silk/tables.h @@ -0,0 +1,114 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifndef SILK_TABLES_H +#define SILK_TABLES_H + +#include "define.h" +#include "structs.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* Entropy coding tables (with size in bytes indicated) */ +extern const opus_uint8 silk_gain_iCDF[ 3 ][ N_LEVELS_QGAIN / 8 ]; /* 24 */ +extern const opus_uint8 silk_delta_gain_iCDF[ MAX_DELTA_GAIN_QUANT - MIN_DELTA_GAIN_QUANT + 1 ]; /* 41 */ + +extern const opus_uint8 silk_pitch_lag_iCDF[ 2 * ( PITCH_EST_MAX_LAG_MS - PITCH_EST_MIN_LAG_MS ) ];/* 32 */ +extern const opus_uint8 silk_pitch_delta_iCDF[ 21 ]; /* 21 */ +extern const opus_uint8 silk_pitch_contour_iCDF[ 34 ]; /* 34 */ +extern const opus_uint8 silk_pitch_contour_NB_iCDF[ 11 ]; /* 11 */ +extern const opus_uint8 silk_pitch_contour_10_ms_iCDF[ 12 ]; /* 12 */ +extern const opus_uint8 silk_pitch_contour_10_ms_NB_iCDF[ 3 ]; /* 3 */ + +extern const opus_uint8 silk_pulses_per_block_iCDF[ N_RATE_LEVELS ][ SILK_MAX_PULSES + 2 ]; /* 180 */ +extern const opus_uint8 silk_pulses_per_block_BITS_Q5[ N_RATE_LEVELS - 1 ][ SILK_MAX_PULSES + 2 ]; /* 162 */ + +extern const opus_uint8 silk_rate_levels_iCDF[ 2 ][ N_RATE_LEVELS - 1 ]; /* 18 */ +extern const opus_uint8 silk_rate_levels_BITS_Q5[ 2 ][ N_RATE_LEVELS - 1 ]; /* 18 */ + +extern const opus_uint8 silk_max_pulses_table[ 4 ]; /* 4 */ + +extern const opus_uint8 silk_shell_code_table0[ 152 ]; /* 152 */ +extern const opus_uint8 silk_shell_code_table1[ 152 ]; /* 152 */ +extern const opus_uint8 silk_shell_code_table2[ 152 ]; /* 152 */ +extern const opus_uint8 silk_shell_code_table3[ 152 ]; /* 152 */ +extern const opus_uint8 silk_shell_code_table_offsets[ SILK_MAX_PULSES + 1 ]; /* 17 */ + +extern const opus_uint8 silk_lsb_iCDF[ 2 ]; /* 2 */ + +extern const opus_uint8 silk_sign_iCDF[ 42 ]; /* 42 */ + +extern const opus_uint8 silk_uniform3_iCDF[ 3 ]; /* 3 */ +extern const opus_uint8 silk_uniform4_iCDF[ 4 ]; /* 4 */ +extern const opus_uint8 silk_uniform5_iCDF[ 5 ]; /* 5 */ +extern const opus_uint8 silk_uniform6_iCDF[ 6 ]; /* 6 */ +extern const opus_uint8 silk_uniform8_iCDF[ 8 ]; /* 8 */ + +extern const opus_uint8 silk_NLSF_EXT_iCDF[ 7 ]; /* 7 */ + +extern const opus_uint8 silk_LTP_per_index_iCDF[ 3 ]; /* 3 */ +extern const opus_uint8 * const silk_LTP_gain_iCDF_ptrs[ NB_LTP_CBKS ]; /* 3 */ +extern const opus_uint8 * const silk_LTP_gain_BITS_Q5_ptrs[ NB_LTP_CBKS ]; /* 3 */ +extern const opus_int8 * const silk_LTP_vq_ptrs_Q7[ NB_LTP_CBKS ]; /* 168 */ +extern const opus_uint8 * const silk_LTP_vq_gain_ptrs_Q7[NB_LTP_CBKS]; +extern const opus_int8 silk_LTP_vq_sizes[ NB_LTP_CBKS ]; /* 3 */ + +extern const opus_uint8 silk_LTPscale_iCDF[ 3 ]; /* 4 */ +extern const opus_int16 silk_LTPScales_table_Q14[ 3 ]; /* 6 */ + +extern const opus_uint8 silk_type_offset_VAD_iCDF[ 4 ]; /* 4 */ +extern const opus_uint8 silk_type_offset_no_VAD_iCDF[ 2 ]; /* 2 */ + +extern const opus_int16 silk_stereo_pred_quant_Q13[ STEREO_QUANT_TAB_SIZE ]; /* 32 */ +extern const opus_uint8 silk_stereo_pred_joint_iCDF[ 25 ]; /* 25 */ +extern const opus_uint8 silk_stereo_only_code_mid_iCDF[ 2 ]; /* 2 */ + +extern const opus_uint8 * const silk_LBRR_flags_iCDF_ptr[ 2 ]; /* 10 */ + +extern const opus_uint8 silk_NLSF_interpolation_factor_iCDF[ 5 ]; /* 5 */ + +extern const silk_NLSF_CB_struct silk_NLSF_CB_WB; /* 1040 */ +extern const silk_NLSF_CB_struct silk_NLSF_CB_NB_MB; /* 728 */ + +/* Quantization offsets */ +extern const opus_int16 silk_Quantization_Offsets_Q10[ 2 ][ 2 ]; /* 8 */ + +/* Interpolation points for filter coefficients used in the bandwidth transition smoother */ +extern const opus_int32 silk_Transition_LP_B_Q28[ TRANSITION_INT_NUM ][ TRANSITION_NB ]; /* 60 */ +extern const opus_int32 silk_Transition_LP_A_Q28[ TRANSITION_INT_NUM ][ TRANSITION_NA ]; /* 60 */ + +/* Rom table with cosine values */ +extern const opus_int16 silk_LSFCosTab_FIX_Q12[ LSF_COS_TAB_SZ_FIX + 1 ]; /* 258 */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/extern/opus/silk/tables_LTP.c b/extern/opus/silk/tables_LTP.c new file mode 100644 index 0000000..5e12c86 --- /dev/null +++ b/extern/opus/silk/tables_LTP.c @@ -0,0 +1,294 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "tables.h" + +const opus_uint8 silk_LTP_per_index_iCDF[3] = { + 179, 99, 0 +}; + +static const opus_uint8 silk_LTP_gain_iCDF_0[8] = { + 71, 56, 43, 30, 21, 12, 6, 0 +}; + +static const opus_uint8 silk_LTP_gain_iCDF_1[16] = { + 199, 165, 144, 124, 109, 96, 84, 71, + 61, 51, 42, 32, 23, 15, 8, 0 +}; + +static const opus_uint8 silk_LTP_gain_iCDF_2[32] = { + 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 const opus_uint8 silk_LTP_gain_BITS_Q5_0[8] = { + 15, 131, 138, 138, 155, 155, 173, 173 +}; + +static const opus_uint8 silk_LTP_gain_BITS_Q5_1[16] = { + 69, 93, 115, 118, 131, 138, 141, 138, + 150, 150, 155, 150, 155, 160, 166, 160 +}; + +static const opus_uint8 silk_LTP_gain_BITS_Q5_2[32] = { + 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 +}; + +const opus_uint8 * const silk_LTP_gain_iCDF_ptrs[NB_LTP_CBKS] = { + silk_LTP_gain_iCDF_0, + silk_LTP_gain_iCDF_1, + silk_LTP_gain_iCDF_2 +}; + +const opus_uint8 * const silk_LTP_gain_BITS_Q5_ptrs[NB_LTP_CBKS] = { + silk_LTP_gain_BITS_Q5_0, + silk_LTP_gain_BITS_Q5_1, + silk_LTP_gain_BITS_Q5_2 +}; + +static const opus_int8 silk_LTP_gain_vq_0[8][5] = +{ +{ + 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 const opus_int8 silk_LTP_gain_vq_1[16][5] = +{ +{ + 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 const opus_int8 silk_LTP_gain_vq_2[32][5] = +{ +{ + -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 +} +}; + +const opus_int8 * const silk_LTP_vq_ptrs_Q7[NB_LTP_CBKS] = { + (opus_int8 *)&silk_LTP_gain_vq_0[0][0], + (opus_int8 *)&silk_LTP_gain_vq_1[0][0], + (opus_int8 *)&silk_LTP_gain_vq_2[0][0] +}; + +/* Maximum frequency-dependent response of the pitch taps above, + computed as max(abs(freqz(taps))) */ +static const opus_uint8 silk_LTP_gain_vq_0_gain[8] = { + 46, 2, 90, 87, 93, 91, 82, 98 +}; + +static const opus_uint8 silk_LTP_gain_vq_1_gain[16] = { + 109, 120, 118, 12, 113, 115, 117, 119, + 99, 59, 87, 111, 63, 111, 112, 80 +}; + +static const opus_uint8 silk_LTP_gain_vq_2_gain[32] = { + 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 +}; + +const opus_uint8 * const silk_LTP_vq_gain_ptrs_Q7[NB_LTP_CBKS] = { + &silk_LTP_gain_vq_0_gain[0], + &silk_LTP_gain_vq_1_gain[0], + &silk_LTP_gain_vq_2_gain[0] +}; + +const opus_int8 silk_LTP_vq_sizes[NB_LTP_CBKS] = { + 8, 16, 32 +}; diff --git a/extern/opus/silk/tables_NLSF_CB_NB_MB.c b/extern/opus/silk/tables_NLSF_CB_NB_MB.c new file mode 100644 index 0000000..195d5b9 --- /dev/null +++ b/extern/opus/silk/tables_NLSF_CB_NB_MB.c @@ -0,0 +1,195 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "tables.h" + +static const opus_uint8 silk_NLSF_CB1_NB_MB_Q8[ 320 ] = { + 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 const opus_int16 silk_NLSF_CB1_Wght_Q9[ 320 ] = { + 2897, 2314, 2314, 2314, 2287, 2287, 2314, 2300, 2327, 2287, + 2888, 2580, 2394, 2367, 2314, 2274, 2274, 2274, 2274, 2194, + 2487, 2340, 2340, 2314, 2314, 2314, 2340, 2340, 2367, 2354, + 3216, 2766, 2340, 2340, 2314, 2274, 2221, 2207, 2261, 2194, + 2460, 2474, 2367, 2394, 2394, 2394, 2394, 2367, 2407, 2314, + 3479, 3056, 2127, 2207, 2274, 2274, 2274, 2287, 2314, 2261, + 3282, 3141, 2580, 2394, 2247, 2221, 2207, 2194, 2194, 2114, + 4096, 3845, 2221, 2620, 2620, 2407, 2314, 2394, 2367, 2074, + 3178, 3244, 2367, 2221, 2553, 2434, 2340, 2314, 2167, 2221, + 3338, 3488, 2726, 2194, 2261, 2460, 2354, 2367, 2207, 2101, + 2354, 2420, 2327, 2367, 2394, 2420, 2420, 2420, 2460, 2367, + 3779, 3629, 2434, 2527, 2367, 2274, 2274, 2300, 2207, 2048, + 3254, 3225, 2713, 2846, 2447, 2327, 2300, 2300, 2274, 2127, + 3263, 3300, 2753, 2806, 2447, 2261, 2261, 2247, 2127, 2101, + 2873, 2981, 2633, 2367, 2407, 2354, 2194, 2247, 2247, 2114, + 3225, 3197, 2633, 2580, 2274, 2181, 2247, 2221, 2221, 2141, + 3178, 3310, 2740, 2407, 2274, 2274, 2274, 2287, 2194, 2114, + 3141, 3272, 2460, 2061, 2287, 2500, 2367, 2487, 2434, 2181, + 3507, 3282, 2314, 2700, 2647, 2474, 2367, 2394, 2340, 2127, + 3423, 3535, 3038, 3056, 2300, 1950, 2221, 2274, 2274, 2274, + 3404, 3366, 2087, 2687, 2873, 2354, 2420, 2274, 2474, 2540, + 3760, 3488, 1950, 2660, 2897, 2527, 2394, 2367, 2460, 2261, + 3028, 3272, 2740, 2888, 2740, 2154, 2127, 2287, 2234, 2247, + 3695, 3657, 2025, 1969, 2660, 2700, 2580, 2500, 2327, 2367, + 3207, 3413, 2354, 2074, 2888, 2888, 2340, 2487, 2247, 2167, + 3338, 3366, 2846, 2780, 2327, 2154, 2274, 2287, 2114, 2061, + 2327, 2300, 2181, 2167, 2181, 2367, 2633, 2700, 2700, 2553, + 2407, 2434, 2221, 2261, 2221, 2221, 2340, 2420, 2607, 2700, + 3038, 3244, 2806, 2888, 2474, 2074, 2300, 2314, 2354, 2380, + 2221, 2154, 2127, 2287, 2500, 2793, 2793, 2620, 2580, 2367, + 3676, 3713, 2234, 1838, 2181, 2753, 2726, 2673, 2513, 2207, + 2793, 3160, 2726, 2553, 2846, 2513, 2181, 2394, 2221, 2181 +}; + +static const opus_uint8 silk_NLSF_CB1_iCDF_NB_MB[ 64 ] = { + 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 const opus_uint8 silk_NLSF_CB2_SELECT_NB_MB[ 160 ] = { + 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 const opus_uint8 silk_NLSF_CB2_iCDF_NB_MB[ 72 ] = { + 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 const opus_uint8 silk_NLSF_CB2_BITS_NB_MB_Q5[ 72 ] = { + 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 const opus_uint8 silk_NLSF_PRED_NB_MB_Q8[ 18 ] = { + 179, 138, 140, 148, 151, 149, 153, 151, + 163, 116, 67, 82, 59, 92, 72, 100, + 89, 92 +}; + +static const opus_int16 silk_NLSF_DELTA_MIN_NB_MB_Q15[ 11 ] = { + 250, 3, 6, 3, 3, 3, 4, 3, + 3, 3, 461 +}; + +const silk_NLSF_CB_struct silk_NLSF_CB_NB_MB = +{ + 32, + 10, + SILK_FIX_CONST( 0.18, 16 ), + SILK_FIX_CONST( 1.0 / 0.18, 6 ), + silk_NLSF_CB1_NB_MB_Q8, + silk_NLSF_CB1_Wght_Q9, + silk_NLSF_CB1_iCDF_NB_MB, + silk_NLSF_PRED_NB_MB_Q8, + silk_NLSF_CB2_SELECT_NB_MB, + silk_NLSF_CB2_iCDF_NB_MB, + silk_NLSF_CB2_BITS_NB_MB_Q5, + silk_NLSF_DELTA_MIN_NB_MB_Q15, +}; diff --git a/extern/opus/silk/tables_NLSF_CB_WB.c b/extern/opus/silk/tables_NLSF_CB_WB.c new file mode 100644 index 0000000..5cc9f57 --- /dev/null +++ b/extern/opus/silk/tables_NLSF_CB_WB.c @@ -0,0 +1,234 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "tables.h" + +static const opus_uint8 silk_NLSF_CB1_WB_Q8[ 512 ] = { + 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 +}; + +static const opus_int16 silk_NLSF_CB1_WB_Wght_Q9[ 512 ] = { + 3657, 2925, 2925, 2925, 2925, 2925, 2925, 2925, 2925, 2925, 2925, 2925, 2963, 2963, 2925, 2846, + 3216, 3085, 2972, 3056, 3056, 3010, 3010, 3010, 2963, 2963, 3010, 2972, 2888, 2846, 2846, 2726, + 3920, 4014, 2981, 3207, 3207, 2934, 3056, 2846, 3122, 3244, 2925, 2846, 2620, 2553, 2780, 2925, + 3516, 3197, 3010, 3103, 3019, 2888, 2925, 2925, 2925, 2925, 2888, 2888, 2888, 2888, 2888, 2753, + 5054, 5054, 2934, 3573, 3385, 3056, 3085, 2793, 3160, 3160, 2972, 2846, 2513, 2540, 2753, 2888, + 4428, 4149, 2700, 2753, 2972, 3010, 2925, 2846, 2981, 3019, 2925, 2925, 2925, 2925, 2888, 2726, + 3620, 3019, 2972, 3056, 3056, 2873, 2806, 3056, 3216, 3047, 2981, 3291, 3291, 2981, 3310, 2991, + 5227, 5014, 2540, 3338, 3526, 3385, 3197, 3094, 3376, 2981, 2700, 2647, 2687, 2793, 2846, 2673, + 5081, 5174, 4615, 4428, 2460, 2897, 3047, 3207, 3169, 2687, 2740, 2888, 2846, 2793, 2846, 2700, + 3122, 2888, 2963, 2925, 2925, 2925, 2925, 2963, 2963, 2963, 2963, 2925, 2925, 2963, 2963, 2963, + 4202, 3207, 2981, 3103, 3010, 2888, 2888, 2925, 2972, 2873, 2916, 3019, 2972, 3010, 3197, 2873, + 3760, 3760, 3244, 3103, 2981, 2888, 2925, 2888, 2972, 2934, 2793, 2793, 2846, 2888, 2888, 2660, + 3854, 4014, 3207, 3122, 3244, 2934, 3047, 2963, 2963, 3085, 2846, 2793, 2793, 2793, 2793, 2580, + 3845, 4080, 3357, 3516, 3094, 2740, 3010, 2934, 3122, 3085, 2846, 2846, 2647, 2647, 2846, 2806, + 5147, 4894, 3225, 3845, 3441, 3169, 2897, 3413, 3451, 2700, 2580, 2673, 2740, 2846, 2806, 2753, + 4109, 3789, 3291, 3160, 2925, 2888, 2888, 2925, 2793, 2740, 2793, 2740, 2793, 2846, 2888, 2806, + 5081, 5054, 3047, 3545, 3244, 3056, 3085, 2944, 3103, 2897, 2740, 2740, 2740, 2846, 2793, 2620, + 4309, 4309, 2860, 2527, 3207, 3376, 3376, 3075, 3075, 3376, 3056, 2846, 2647, 2580, 2726, 2753, + 3056, 2916, 2806, 2888, 2740, 2687, 2897, 3103, 3150, 3150, 3216, 3169, 3056, 3010, 2963, 2846, + 4375, 3882, 2925, 2888, 2846, 2888, 2846, 2846, 2888, 2888, 2888, 2846, 2888, 2925, 2888, 2846, + 2981, 2916, 2916, 2981, 2981, 3056, 3122, 3216, 3150, 3056, 3010, 2972, 2972, 2972, 2925, 2740, + 4229, 4149, 3310, 3347, 2925, 2963, 2888, 2981, 2981, 2846, 2793, 2740, 2846, 2846, 2846, 2793, + 4080, 4014, 3103, 3010, 2925, 2925, 2925, 2888, 2925, 2925, 2846, 2846, 2846, 2793, 2888, 2780, + 4615, 4575, 3169, 3441, 3207, 2981, 2897, 3038, 3122, 2740, 2687, 2687, 2687, 2740, 2793, 2700, + 4149, 4269, 3789, 3657, 2726, 2780, 2888, 2888, 3010, 2972, 2925, 2846, 2687, 2687, 2793, 2888, + 4215, 3554, 2753, 2846, 2846, 2888, 2888, 2888, 2925, 2925, 2888, 2925, 2925, 2925, 2963, 2888, + 5174, 4921, 2261, 3432, 3789, 3479, 3347, 2846, 3310, 3479, 3150, 2897, 2460, 2487, 2753, 2925, + 3451, 3685, 3122, 3197, 3357, 3047, 3207, 3207, 2981, 3216, 3085, 2925, 2925, 2687, 2540, 2434, + 2981, 3010, 2793, 2793, 2740, 2793, 2846, 2972, 3056, 3103, 3150, 3150, 3150, 3103, 3010, 3010, + 2944, 2873, 2687, 2726, 2780, 3010, 3432, 3545, 3357, 3244, 3056, 3010, 2963, 2925, 2888, 2846, + 3019, 2944, 2897, 3010, 3010, 2972, 3019, 3103, 3056, 3056, 3010, 2888, 2846, 2925, 2925, 2888, + 3920, 3967, 3010, 3197, 3357, 3216, 3291, 3291, 3479, 3704, 3441, 2726, 2181, 2460, 2580, 2607 +}; + +static const opus_uint8 silk_NLSF_CB1_iCDF_WB[ 64 ] = { + 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 +}; + +static const opus_uint8 silk_NLSF_CB2_SELECT_WB[ 256 ] = { + 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 +}; + +static const opus_uint8 silk_NLSF_CB2_iCDF_WB[ 72 ] = { + 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 +}; + +static const opus_uint8 silk_NLSF_CB2_BITS_WB_Q5[ 72 ] = { + 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 +}; + +static const opus_uint8 silk_NLSF_PRED_WB_Q8[ 30 ] = { + 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 +}; + +static const opus_int16 silk_NLSF_DELTA_MIN_WB_Q15[ 17 ] = { + 100, 3, 40, 3, 3, 3, 5, 14, + 14, 10, 11, 3, 8, 9, 7, 3, + 347 +}; + +const silk_NLSF_CB_struct silk_NLSF_CB_WB = +{ + 32, + 16, + SILK_FIX_CONST( 0.15, 16 ), + SILK_FIX_CONST( 1.0 / 0.15, 6 ), + silk_NLSF_CB1_WB_Q8, + silk_NLSF_CB1_WB_Wght_Q9, + silk_NLSF_CB1_iCDF_WB, + silk_NLSF_PRED_WB_Q8, + silk_NLSF_CB2_SELECT_WB, + silk_NLSF_CB2_iCDF_WB, + silk_NLSF_CB2_BITS_WB_Q5, + silk_NLSF_DELTA_MIN_WB_Q15, +}; + diff --git a/extern/opus/silk/tables_gain.c b/extern/opus/silk/tables_gain.c new file mode 100644 index 0000000..37e41d8 --- /dev/null +++ b/extern/opus/silk/tables_gain.c @@ -0,0 +1,63 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "tables.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +const opus_uint8 silk_gain_iCDF[ 3 ][ N_LEVELS_QGAIN / 8 ] = +{ +{ + 224, 112, 44, 15, 3, 2, 1, 0 +}, +{ + 254, 237, 192, 132, 70, 23, 4, 0 +}, +{ + 255, 252, 226, 155, 61, 11, 2, 0 +} +}; + +const opus_uint8 silk_delta_gain_iCDF[ MAX_DELTA_GAIN_QUANT - MIN_DELTA_GAIN_QUANT + 1 ] = { + 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 +}; + +#ifdef __cplusplus +} +#endif diff --git a/extern/opus/silk/tables_other.c b/extern/opus/silk/tables_other.c new file mode 100644 index 0000000..e34d907 --- /dev/null +++ b/extern/opus/silk/tables_other.c @@ -0,0 +1,124 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "structs.h" +#include "define.h" +#include "tables.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* Tables for stereo predictor coding */ +const opus_int16 silk_stereo_pred_quant_Q13[ STEREO_QUANT_TAB_SIZE ] = { + -13732, -10050, -8266, -7526, -6500, -5000, -2950, -820, + 820, 2950, 5000, 6500, 7526, 8266, 10050, 13732 +}; +const opus_uint8 silk_stereo_pred_joint_iCDF[ 25 ] = { + 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 +}; +const opus_uint8 silk_stereo_only_code_mid_iCDF[ 2 ] = { 64, 0 }; + +/* Tables for LBRR flags */ +static const opus_uint8 silk_LBRR_flags_2_iCDF[ 3 ] = { 203, 150, 0 }; +static const opus_uint8 silk_LBRR_flags_3_iCDF[ 7 ] = { 215, 195, 166, 125, 110, 82, 0 }; +const opus_uint8 * const silk_LBRR_flags_iCDF_ptr[ 2 ] = { + silk_LBRR_flags_2_iCDF, + silk_LBRR_flags_3_iCDF +}; + +/* Table for LSB coding */ +const opus_uint8 silk_lsb_iCDF[ 2 ] = { 120, 0 }; + +/* Tables for LTPScale */ +const opus_uint8 silk_LTPscale_iCDF[ 3 ] = { 128, 64, 0 }; + +/* Tables for signal type and offset coding */ +const opus_uint8 silk_type_offset_VAD_iCDF[ 4 ] = { + 232, 158, 10, 0 +}; +const opus_uint8 silk_type_offset_no_VAD_iCDF[ 2 ] = { + 230, 0 +}; + +/* Tables for NLSF interpolation factor */ +const opus_uint8 silk_NLSF_interpolation_factor_iCDF[ 5 ] = { 243, 221, 192, 181, 0 }; + +/* Quantization offsets */ +const opus_int16 silk_Quantization_Offsets_Q10[ 2 ][ 2 ] = { + { OFFSET_UVL_Q10, OFFSET_UVH_Q10 }, { OFFSET_VL_Q10, OFFSET_VH_Q10 } +}; + +/* Table for LTPScale */ +const opus_int16 silk_LTPScales_table_Q14[ 3 ] = { 15565, 12288, 8192 }; + +/* Uniform entropy tables */ +const opus_uint8 silk_uniform3_iCDF[ 3 ] = { 171, 85, 0 }; +const opus_uint8 silk_uniform4_iCDF[ 4 ] = { 192, 128, 64, 0 }; +const opus_uint8 silk_uniform5_iCDF[ 5 ] = { 205, 154, 102, 51, 0 }; +const opus_uint8 silk_uniform6_iCDF[ 6 ] = { 213, 171, 128, 85, 43, 0 }; +const opus_uint8 silk_uniform8_iCDF[ 8 ] = { 224, 192, 160, 128, 96, 64, 32, 0 }; + +const opus_uint8 silk_NLSF_EXT_iCDF[ 7 ] = { 100, 40, 16, 7, 3, 1, 0 }; + +/* Elliptic/Cauer filters designed with 0.1 dB passband ripple, + 80 dB minimum stopband attenuation, and + [0.95 : 0.15 : 0.35] normalized cut off frequencies. */ + +/* Interpolation points for filter coefficients used in the bandwidth transition smoother */ +const opus_int32 silk_Transition_LP_B_Q28[ TRANSITION_INT_NUM ][ TRANSITION_NB ] = +{ +{ 250767114, 501534038, 250767114 }, +{ 209867381, 419732057, 209867381 }, +{ 170987846, 341967853, 170987846 }, +{ 131531482, 263046905, 131531482 }, +{ 89306658, 178584282, 89306658 } +}; + +/* Interpolation points for filter coefficients used in the bandwidth transition smoother */ +const opus_int32 silk_Transition_LP_A_Q28[ TRANSITION_INT_NUM ][ TRANSITION_NA ] = +{ +{ 506393414, 239854379 }, +{ 411067935, 169683996 }, +{ 306733530, 116694253 }, +{ 185807084, 77959395 }, +{ 35497197, 57401098 } +}; + +#ifdef __cplusplus +} +#endif + diff --git a/extern/opus/silk/tables_pitch_lag.c b/extern/opus/silk/tables_pitch_lag.c new file mode 100644 index 0000000..e80cc59 --- /dev/null +++ b/extern/opus/silk/tables_pitch_lag.c @@ -0,0 +1,69 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "tables.h" + +const opus_uint8 silk_pitch_lag_iCDF[ 2 * ( PITCH_EST_MAX_LAG_MS - PITCH_EST_MIN_LAG_MS ) ] = { + 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 +}; + +const opus_uint8 silk_pitch_delta_iCDF[21] = { + 210, 208, 206, 203, 199, 193, 183, 168, + 142, 104, 74, 52, 37, 27, 20, 14, + 10, 6, 4, 2, 0 +}; + +const opus_uint8 silk_pitch_contour_iCDF[34] = { + 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 +}; + +const opus_uint8 silk_pitch_contour_NB_iCDF[11] = { + 188, 176, 155, 138, 119, 97, 67, 43, + 26, 10, 0 +}; + +const opus_uint8 silk_pitch_contour_10_ms_iCDF[12] = { + 165, 119, 80, 61, 47, 35, 27, 20, + 14, 9, 4, 0 +}; + +const opus_uint8 silk_pitch_contour_10_ms_NB_iCDF[3] = { + 113, 63, 0 +}; + + diff --git a/extern/opus/silk/tables_pulses_per_block.c b/extern/opus/silk/tables_pulses_per_block.c new file mode 100644 index 0000000..c7c01c8 --- /dev/null +++ b/extern/opus/silk/tables_pulses_per_block.c @@ -0,0 +1,264 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "tables.h" + +const opus_uint8 silk_max_pulses_table[ 4 ] = { + 8, 10, 12, 16 +}; + +const opus_uint8 silk_pulses_per_block_iCDF[ 10 ][ 18 ] = { +{ + 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 +} +}; + +const opus_uint8 silk_pulses_per_block_BITS_Q5[ 9 ][ 18 ] = { +{ + 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 +} +}; + +const opus_uint8 silk_rate_levels_iCDF[ 2 ][ 9 ] = +{ +{ + 241, 190, 178, 132, 87, 74, 41, 14, + 0 +}, +{ + 223, 193, 157, 140, 106, 57, 39, 18, + 0 +} +}; + +const opus_uint8 silk_rate_levels_BITS_Q5[ 2 ][ 9 ] = +{ +{ + 131, 74, 141, 79, 80, 138, 95, 104, + 134 +}, +{ + 95, 99, 91, 125, 93, 76, 123, 115, + 123 +} +}; + +const opus_uint8 silk_shell_code_table0[ 152 ] = { + 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 +}; + +const opus_uint8 silk_shell_code_table1[ 152 ] = { + 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 +}; + +const opus_uint8 silk_shell_code_table2[ 152 ] = { + 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 +}; + +const opus_uint8 silk_shell_code_table3[ 152 ] = { + 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 +}; + +const opus_uint8 silk_shell_code_table_offsets[ 17 ] = { + 0, 0, 2, 5, 9, 14, 20, 27, + 35, 44, 54, 65, 77, 90, 104, 119, + 135 +}; + +const opus_uint8 silk_sign_iCDF[ 42 ] = { + 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 +}; diff --git a/extern/opus/silk/tests/test_unit_LPC_inv_pred_gain.c b/extern/opus/silk/tests/test_unit_LPC_inv_pred_gain.c new file mode 100644 index 0000000..67067ce --- /dev/null +++ b/extern/opus/silk/tests/test_unit_LPC_inv_pred_gain.c @@ -0,0 +1,129 @@ +/*********************************************************************** +Copyright (c) 2017 Google Inc., Jean-Marc Valin +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 OWNER 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. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include "celt/stack_alloc.h" +#include "cpu_support.h" +#include "SigProc_FIX.h" + +/* Computes the impulse response of the filter so we + can catch filters that are definitely unstable. Some + unstable filters may be classified as stable, but not + the other way around. */ +int check_stability(opus_int16 *A_Q12, int order) { + int i; + int j; + int sum_a, sum_abs_a; + sum_a = sum_abs_a = 0; + for( j = 0; j < order; j++ ) { + sum_a += A_Q12[ j ]; + sum_abs_a += silk_abs( A_Q12[ j ] ); + } + /* Check DC stability. */ + if( sum_a >= 4096 ) { + return 0; + } + /* If the sum of absolute values is less than 1, the filter + has to be stable. */ + if( sum_abs_a < 4096 ) { + return 1; + } + double y[SILK_MAX_ORDER_LPC] = {0}; + y[0] = 1; + for( i = 0; i < 10000; i++ ) { + double sum = 0; + for( j = 0; j < order; j++ ) { + sum += y[ j ]*A_Q12[ j ]; + } + for( j = order - 1; j > 0; j-- ) { + y[ j ] = y[ j - 1 ]; + } + y[ 0 ] = sum*(1./4096); + /* If impulse response reaches +/- 10000, the filter + is definitely unstable. */ + if( !(y[ 0 ] < 10000 && y[ 0 ] > -10000) ) { + return 0; + } + /* Test every 8 sample for low amplitude. */ + if( ( i & 0x7 ) == 0 ) { + double amp = 0; + for( j = 0; j < order; j++ ) { + amp += fabs(y[j]); + } + if( amp < 0.00001 ) { + return 1; + } + } + } + return 1; +} + +int main(void) { + const int arch = opus_select_arch(); + /* Set to 10000 so all branches in C function are triggered */ + const int loop_num = 10000; + int count = 0; + ALLOC_STACK; + + /* FIXME: Make the seed random (with option to set it explicitly) + so we get wider coverage. */ + srand(0); + + printf("Testing silk_LPC_inverse_pred_gain() optimization ...\n"); + for( count = 0; count < loop_num; count++ ) { + unsigned int i; + opus_int order; + unsigned int shift; + opus_int16 A_Q12[ SILK_MAX_ORDER_LPC ]; + opus_int32 gain; + + for( order = 2; order <= SILK_MAX_ORDER_LPC; order += 2 ) { /* order must be even. */ + for( shift = 0; shift < 16; shift++ ) { /* Different dynamic range. */ + for( i = 0; i < SILK_MAX_ORDER_LPC; i++ ) { + A_Q12[i] = ((opus_int16)rand()) >> shift; + } + gain = silk_LPC_inverse_pred_gain(A_Q12, order, arch); + /* Look for filters that silk_LPC_inverse_pred_gain() thinks are + stable but definitely aren't. */ + if( gain != 0 && !check_stability(A_Q12, order) ) { + fprintf(stderr, "**Loop %4d failed!**\n", count); + return 1; + } + } + } + if( !(count % 500) ) { + printf("Loop %4d passed\n", count); + } + } + printf("silk_LPC_inverse_pred_gain() optimization passed\n"); + return 0; +} diff --git a/extern/opus/silk/tuning_parameters.h b/extern/opus/silk/tuning_parameters.h new file mode 100644 index 0000000..d70275f --- /dev/null +++ b/extern/opus/silk/tuning_parameters.h @@ -0,0 +1,155 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifndef SILK_TUNING_PARAMETERS_H +#define SILK_TUNING_PARAMETERS_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* Decay time for bitreservoir */ +#define BITRESERVOIR_DECAY_TIME_MS 500 + +/*******************/ +/* Pitch estimator */ +/*******************/ + +/* Level of noise floor for whitening filter LPC analysis in pitch analysis */ +#define FIND_PITCH_WHITE_NOISE_FRACTION 1e-3f + +/* Bandwidth expansion for whitening filter in pitch analysis */ +#define FIND_PITCH_BANDWIDTH_EXPANSION 0.99f + +/*********************/ +/* Linear prediction */ +/*********************/ + +/* LPC analysis regularization */ +#define FIND_LPC_COND_FAC 1e-5f + +/* Max cumulative LTP gain */ +#define MAX_SUM_LOG_GAIN_DB 250.0f + +/* LTP analysis defines */ +#define LTP_CORR_INV_MAX 0.03f + +/***********************/ +/* High pass filtering */ +/***********************/ + +/* Smoothing parameters for low end of pitch frequency range estimation */ +#define VARIABLE_HP_SMTH_COEF1 0.1f +#define VARIABLE_HP_SMTH_COEF2 0.015f +#define VARIABLE_HP_MAX_DELTA_FREQ 0.4f + +/* Min and max cut-off frequency values (-3 dB points) */ +#define VARIABLE_HP_MIN_CUTOFF_HZ 60 +#define VARIABLE_HP_MAX_CUTOFF_HZ 100 + +/***********/ +/* Various */ +/***********/ + +/* VAD threshold */ +#define SPEECH_ACTIVITY_DTX_THRES 0.05f + +/* Speech Activity LBRR enable threshold */ +#define LBRR_SPEECH_ACTIVITY_THRES 0.3f + +/*************************/ +/* Perceptual parameters */ +/*************************/ + +/* reduction in coding SNR during low speech activity */ +#define BG_SNR_DECR_dB 2.0f + +/* factor for reducing quantization noise during voiced speech */ +#define HARM_SNR_INCR_dB 2.0f + +/* factor for reducing quantization noise for unvoiced sparse signals */ +#define SPARSE_SNR_INCR_dB 2.0f + +/* threshold for sparseness measure above which to use lower quantization offset during unvoiced */ +#define ENERGY_VARIATION_THRESHOLD_QNT_OFFSET 0.6f + +/* warping control */ +#define WARPING_MULTIPLIER 0.015f + +/* fraction added to first autocorrelation value */ +#define SHAPE_WHITE_NOISE_FRACTION 3e-5f + +/* noise shaping filter chirp factor */ +#define BANDWIDTH_EXPANSION 0.94f + +/* harmonic noise shaping */ +#define HARMONIC_SHAPING 0.3f + +/* extra harmonic noise shaping for high bitrates or noisy input */ +#define HIGH_RATE_OR_LOW_QUALITY_HARMONIC_SHAPING 0.2f + +/* parameter for shaping noise towards higher frequencies */ +#define HP_NOISE_COEF 0.25f + +/* parameter for shaping noise even more towards higher frequencies during voiced speech */ +#define HARM_HP_NOISE_COEF 0.35f + +/* parameter for applying a high-pass tilt to the input signal */ +#define INPUT_TILT 0.05f + +/* parameter for extra high-pass tilt to the input signal at high rates */ +#define HIGH_RATE_INPUT_TILT 0.1f + +/* parameter for reducing noise at the very low frequencies */ +#define LOW_FREQ_SHAPING 4.0f + +/* less reduction of noise at the very low frequencies for signals with low SNR at low frequencies */ +#define LOW_QUALITY_LOW_FREQ_SHAPING_DECR 0.5f + +/* subframe smoothing coefficient for HarmBoost, HarmShapeGain, Tilt (lower -> more smoothing) */ +#define SUBFR_SMTH_COEF 0.4f + +/* parameters defining the R/D tradeoff in the residual quantizer */ +#define LAMBDA_OFFSET 1.2f +#define LAMBDA_SPEECH_ACT -0.2f +#define LAMBDA_DELAYED_DECISIONS -0.05f +#define LAMBDA_INPUT_QUALITY -0.1f +#define LAMBDA_CODING_QUALITY -0.2f +#define LAMBDA_QUANT_OFFSET 0.8f + +/* Compensation in bitrate calculations for 10 ms modes */ +#define REDUCE_BITRATE_10_MS_BPS 2200 + +/* Maximum time before allowing a bandwidth transition */ +#define MAX_BANDWIDTH_SWITCH_DELAY_MS 5000 + +#ifdef __cplusplus +} +#endif + +#endif /* SILK_TUNING_PARAMETERS_H */ diff --git a/extern/opus/silk/typedef.h b/extern/opus/silk/typedef.h new file mode 100644 index 0000000..97b7e70 --- /dev/null +++ b/extern/opus/silk/typedef.h @@ -0,0 +1,78 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +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 OWNER 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. +***********************************************************************/ + +#ifndef SILK_TYPEDEF_H +#define SILK_TYPEDEF_H + +#include "opus_types.h" +#include "opus_defines.h" + +#ifndef FIXED_POINT +# include +# define silk_float float +# define silk_float_MAX FLT_MAX +#endif + +#define silk_int64_MAX ((opus_int64)0x7FFFFFFFFFFFFFFFLL) /* 2^63 - 1 */ +#define silk_int64_MIN ((opus_int64)0x8000000000000000LL) /* -2^63 */ +#define silk_int32_MAX 0x7FFFFFFF /* 2^31 - 1 = 2147483647 */ +#define silk_int32_MIN ((opus_int32)0x80000000) /* -2^31 = -2147483648 */ +#define silk_int16_MAX 0x7FFF /* 2^15 - 1 = 32767 */ +#define silk_int16_MIN ((opus_int16)0x8000) /* -2^15 = -32768 */ +#define silk_int8_MAX 0x7F /* 2^7 - 1 = 127 */ +#define silk_int8_MIN ((opus_int8)0x80) /* -2^7 = -128 */ +#define silk_uint8_MAX 0xFF /* 2^8 - 1 = 255 */ + +#define silk_TRUE 1 +#define silk_FALSE 0 + +/* assertions */ +#if (defined _WIN32 && !defined _WINCE && !defined(__GNUC__) && !defined(NO_ASSERTS)) +# ifndef silk_assert +# include /* ASSERTE() */ +# define silk_assert(COND) _ASSERTE(COND) +# endif +#else +# ifdef ENABLE_ASSERTIONS +# include +# include +#define silk_fatal(str) _silk_fatal(str, __FILE__, __LINE__); +#ifdef __GNUC__ +__attribute__((noreturn)) +#endif +static OPUS_INLINE void _silk_fatal(const char *str, const char *file, int line) +{ + fprintf (stderr, "Fatal (internal) error in %s, line %d: %s\n", file, line, str); + abort(); +} +# define silk_assert(COND) {if (!(COND)) {silk_fatal("assertion failed: " #COND);}} +# else +# define silk_assert(COND) +# endif +#endif + +#endif /* SILK_TYPEDEF_H */ diff --git a/extern/opus/silk/x86/NSQ_del_dec_sse4_1.c b/extern/opus/silk/x86/NSQ_del_dec_sse4_1.c new file mode 100644 index 0000000..2c75ede --- /dev/null +++ b/extern/opus/silk/x86/NSQ_del_dec_sse4_1.c @@ -0,0 +1,859 @@ +/* Copyright (c) 2014, Cisco Systems, INC + Written by XiangMingZhu WeiZhou MinPeng YanWang + + 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. + + 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 OWNER + 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. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include "main.h" +#include "celt/x86/x86cpu.h" + +#include "stack_alloc.h" + +typedef struct { + opus_int32 sLPC_Q14[ MAX_SUB_FRAME_LENGTH + NSQ_LPC_BUF_LENGTH ]; + opus_int32 RandState[ DECISION_DELAY ]; + opus_int32 Q_Q10[ DECISION_DELAY ]; + opus_int32 Xq_Q14[ DECISION_DELAY ]; + opus_int32 Pred_Q15[ DECISION_DELAY ]; + opus_int32 Shape_Q14[ DECISION_DELAY ]; + opus_int32 sAR2_Q14[ MAX_SHAPE_LPC_ORDER ]; + opus_int32 LF_AR_Q14; + opus_int32 Seed; + opus_int32 SeedInit; + opus_int32 RD_Q10; +} NSQ_del_dec_struct; + +typedef struct { + opus_int32 Q_Q10; + opus_int32 RD_Q10; + opus_int32 xq_Q14; + opus_int32 LF_AR_Q14; + opus_int32 sLTP_shp_Q14; + opus_int32 LPC_exc_Q14; +} NSQ_sample_struct; + +typedef NSQ_sample_struct NSQ_sample_pair[ 2 ]; + +static OPUS_INLINE void silk_nsq_del_dec_scale_states_sse4_1( + const silk_encoder_state *psEncC, /* I Encoder State */ + silk_nsq_state *NSQ, /* I/O NSQ state */ + NSQ_del_dec_struct psDelDec[], /* I/O Delayed decision states */ + const opus_int32 x_Q3[], /* I Input in Q3 */ + opus_int32 x_sc_Q10[], /* O Input scaled with 1/Gain in Q10 */ + const opus_int16 sLTP[], /* I Re-whitened LTP state in Q0 */ + opus_int32 sLTP_Q15[], /* O LTP state matching scaled input */ + opus_int subfr, /* I Subframe number */ + opus_int nStatesDelayedDecision, /* I Number of del dec states */ + const opus_int LTP_scale_Q14, /* I LTP state scaling */ + const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lag */ + const opus_int signal_type, /* I Signal type */ + const opus_int decisionDelay /* I Decision delay */ +); + +/******************************************/ +/* Noise shape quantizer for one subframe */ +/******************************************/ +static OPUS_INLINE void silk_noise_shape_quantizer_del_dec_sse4_1( + silk_nsq_state *NSQ, /* I/O NSQ state */ + NSQ_del_dec_struct psDelDec[], /* I/O Delayed decision states */ + opus_int signalType, /* I Signal type */ + const opus_int32 x_Q10[], /* I */ + opus_int8 pulses[], /* O */ + opus_int16 xq[], /* O */ + opus_int32 sLTP_Q15[], /* I/O LTP filter state */ + opus_int32 delayedGain_Q10[], /* I/O Gain delay buffer */ + const opus_int16 a_Q12[], /* I Short term prediction coefs */ + const opus_int16 b_Q14[], /* I Long term prediction coefs */ + const opus_int16 AR_shp_Q13[], /* I Noise shaping coefs */ + opus_int lag, /* I Pitch lag */ + opus_int32 HarmShapeFIRPacked_Q14, /* I */ + opus_int Tilt_Q14, /* I Spectral tilt */ + opus_int32 LF_shp_Q14, /* I */ + opus_int32 Gain_Q16, /* I */ + opus_int Lambda_Q10, /* I */ + opus_int offset_Q10, /* I */ + opus_int length, /* I Input length */ + opus_int subfr, /* I Subframe number */ + opus_int shapingLPCOrder, /* I Shaping LPC filter order */ + opus_int predictLPCOrder, /* I Prediction filter order */ + opus_int warping_Q16, /* I */ + opus_int nStatesDelayedDecision, /* I Number of states in decision tree */ + opus_int *smpl_buf_idx, /* I/O Index to newest samples in buffers */ + opus_int decisionDelay /* I */ +); + +void silk_NSQ_del_dec_sse4_1( + const silk_encoder_state *psEncC, /* I Encoder State */ + silk_nsq_state *NSQ, /* I/O NSQ state */ + SideInfoIndices *psIndices, /* I/O Quantization Indices */ + const opus_int32 x_Q3[], /* I Prefiltered input signal */ + opus_int8 pulses[], /* O Quantized pulse signal */ + const opus_int16 PredCoef_Q12[ 2 * MAX_LPC_ORDER ], /* I Short term prediction coefs */ + const opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ], /* I Long term prediction coefs */ + const opus_int16 AR2_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ], /* I Noise shaping coefs */ + const opus_int HarmShapeGain_Q14[ MAX_NB_SUBFR ], /* I Long term shaping coefs */ + const opus_int Tilt_Q14[ MAX_NB_SUBFR ], /* I Spectral tilt */ + const opus_int32 LF_shp_Q14[ MAX_NB_SUBFR ], /* I Low frequency shaping coefs */ + const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I Quantization step sizes */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lags */ + const opus_int Lambda_Q10, /* I Rate/distortion tradeoff */ + const opus_int LTP_scale_Q14 /* I LTP state scaling */ +) +{ + opus_int i, k, lag, start_idx, LSF_interpolation_flag, Winner_ind, subfr; + opus_int last_smple_idx, smpl_buf_idx, decisionDelay; + const opus_int16 *A_Q12, *B_Q14, *AR_shp_Q13; + opus_int16 *pxq; + VARDECL( opus_int32, sLTP_Q15 ); + VARDECL( opus_int16, sLTP ); + opus_int32 HarmShapeFIRPacked_Q14; + opus_int offset_Q10; + opus_int32 RDmin_Q10, Gain_Q10; + VARDECL( opus_int32, x_sc_Q10 ); + VARDECL( opus_int32, delayedGain_Q10 ); + VARDECL( NSQ_del_dec_struct, psDelDec ); + NSQ_del_dec_struct *psDD; + SAVE_STACK; + + /* Set unvoiced lag to the previous one, overwrite later for voiced */ + lag = NSQ->lagPrev; + + silk_assert( NSQ->prev_gain_Q16 != 0 ); + + /* Initialize delayed decision states */ + ALLOC( psDelDec, psEncC->nStatesDelayedDecision, NSQ_del_dec_struct ); + silk_memset( psDelDec, 0, psEncC->nStatesDelayedDecision * sizeof( NSQ_del_dec_struct ) ); + for( k = 0; k < psEncC->nStatesDelayedDecision; k++ ) { + psDD = &psDelDec[ k ]; + psDD->Seed = ( k + psIndices->Seed ) & 3; + psDD->SeedInit = psDD->Seed; + psDD->RD_Q10 = 0; + psDD->LF_AR_Q14 = NSQ->sLF_AR_shp_Q14; + psDD->Shape_Q14[ 0 ] = NSQ->sLTP_shp_Q14[ psEncC->ltp_mem_length - 1 ]; + silk_memcpy( psDD->sLPC_Q14, NSQ->sLPC_Q14, NSQ_LPC_BUF_LENGTH * sizeof( opus_int32 ) ); + silk_memcpy( psDD->sAR2_Q14, NSQ->sAR2_Q14, sizeof( NSQ->sAR2_Q14 ) ); + } + + offset_Q10 = silk_Quantization_Offsets_Q10[ psIndices->signalType >> 1 ][ psIndices->quantOffsetType ]; + smpl_buf_idx = 0; /* index of oldest samples */ + + decisionDelay = silk_min_int( DECISION_DELAY, psEncC->subfr_length ); + + /* For voiced frames limit the decision delay to lower than the pitch lag */ + if( psIndices->signalType == TYPE_VOICED ) { + for( k = 0; k < psEncC->nb_subfr; k++ ) { + decisionDelay = silk_min_int( decisionDelay, pitchL[ k ] - LTP_ORDER / 2 - 1 ); + } + } else { + if( lag > 0 ) { + decisionDelay = silk_min_int( decisionDelay, lag - LTP_ORDER / 2 - 1 ); + } + } + + if( psIndices->NLSFInterpCoef_Q2 == 4 ) { + LSF_interpolation_flag = 0; + } else { + LSF_interpolation_flag = 1; + } + + ALLOC( sLTP_Q15, + psEncC->ltp_mem_length + psEncC->frame_length, opus_int32 ); + ALLOC( sLTP, psEncC->ltp_mem_length + psEncC->frame_length, opus_int16 ); + ALLOC( x_sc_Q10, psEncC->subfr_length, opus_int32 ); + ALLOC( delayedGain_Q10, DECISION_DELAY, opus_int32 ); + /* Set up pointers to start of sub frame */ + pxq = &NSQ->xq[ psEncC->ltp_mem_length ]; + NSQ->sLTP_shp_buf_idx = psEncC->ltp_mem_length; + NSQ->sLTP_buf_idx = psEncC->ltp_mem_length; + subfr = 0; + for( k = 0; k < psEncC->nb_subfr; k++ ) { + A_Q12 = &PredCoef_Q12[ ( ( k >> 1 ) | ( 1 - LSF_interpolation_flag ) ) * MAX_LPC_ORDER ]; + B_Q14 = <PCoef_Q14[ k * LTP_ORDER ]; + AR_shp_Q13 = &AR2_Q13[ k * MAX_SHAPE_LPC_ORDER ]; + + /* Noise shape parameters */ + silk_assert( HarmShapeGain_Q14[ k ] >= 0 ); + HarmShapeFIRPacked_Q14 = silk_RSHIFT( HarmShapeGain_Q14[ k ], 2 ); + HarmShapeFIRPacked_Q14 |= silk_LSHIFT( (opus_int32)silk_RSHIFT( HarmShapeGain_Q14[ k ], 1 ), 16 ); + + NSQ->rewhite_flag = 0; + if( psIndices->signalType == TYPE_VOICED ) { + /* Voiced */ + lag = pitchL[ k ]; + + /* Re-whitening */ + if( ( k & ( 3 - silk_LSHIFT( LSF_interpolation_flag, 1 ) ) ) == 0 ) { + if( k == 2 ) { + /* RESET DELAYED DECISIONS */ + /* Find winner */ + RDmin_Q10 = psDelDec[ 0 ].RD_Q10; + Winner_ind = 0; + for( i = 1; i < psEncC->nStatesDelayedDecision; i++ ) { + if( psDelDec[ i ].RD_Q10 < RDmin_Q10 ) { + RDmin_Q10 = psDelDec[ i ].RD_Q10; + Winner_ind = i; + } + } + for( i = 0; i < psEncC->nStatesDelayedDecision; i++ ) { + if( i != Winner_ind ) { + psDelDec[ i ].RD_Q10 += ( silk_int32_MAX >> 4 ); + silk_assert( psDelDec[ i ].RD_Q10 >= 0 ); + } + } + + /* Copy final part of signals from winner state to output and long-term filter states */ + psDD = &psDelDec[ Winner_ind ]; + last_smple_idx = smpl_buf_idx + decisionDelay; + for( i = 0; i < decisionDelay; i++ ) { + last_smple_idx = ( last_smple_idx - 1 ) % DECISION_DELAY; + if( last_smple_idx < 0 ) last_smple_idx += DECISION_DELAY; + pulses[ i - decisionDelay ] = (opus_int8)silk_RSHIFT_ROUND( psDD->Q_Q10[ last_smple_idx ], 10 ); + pxq[ i - decisionDelay ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( + silk_SMULWW( psDD->Xq_Q14[ last_smple_idx ], Gains_Q16[ 1 ] ), 14 ) ); + NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - decisionDelay + i ] = psDD->Shape_Q14[ last_smple_idx ]; + } + + subfr = 0; + } + + /* Rewhiten with new A coefs */ + start_idx = psEncC->ltp_mem_length - lag - psEncC->predictLPCOrder - LTP_ORDER / 2; + celt_assert( start_idx > 0 ); + + silk_LPC_analysis_filter( &sLTP[ start_idx ], &NSQ->xq[ start_idx + k * psEncC->subfr_length ], + A_Q12, psEncC->ltp_mem_length - start_idx, psEncC->predictLPCOrder, psEncC->arch ); + + NSQ->sLTP_buf_idx = psEncC->ltp_mem_length; + NSQ->rewhite_flag = 1; + } + } + + silk_nsq_del_dec_scale_states_sse4_1( psEncC, NSQ, psDelDec, x_Q3, x_sc_Q10, sLTP, sLTP_Q15, k, + psEncC->nStatesDelayedDecision, LTP_scale_Q14, Gains_Q16, pitchL, psIndices->signalType, decisionDelay ); + + silk_noise_shape_quantizer_del_dec_sse4_1( NSQ, psDelDec, psIndices->signalType, x_sc_Q10, pulses, pxq, sLTP_Q15, + delayedGain_Q10, A_Q12, B_Q14, AR_shp_Q13, 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, decisionDelay ); + + x_Q3 += psEncC->subfr_length; + pulses += psEncC->subfr_length; + pxq += psEncC->subfr_length; + } + + /* Find winner */ + RDmin_Q10 = psDelDec[ 0 ].RD_Q10; + Winner_ind = 0; + for( k = 1; k < psEncC->nStatesDelayedDecision; k++ ) { + if( psDelDec[ k ].RD_Q10 < RDmin_Q10 ) { + RDmin_Q10 = psDelDec[ k ].RD_Q10; + Winner_ind = k; + } + } + + /* Copy final part of signals from winner state to output and long-term filter states */ + psDD = &psDelDec[ Winner_ind ]; + psIndices->Seed = psDD->SeedInit; + last_smple_idx = smpl_buf_idx + decisionDelay; + Gain_Q10 = silk_RSHIFT32( Gains_Q16[ psEncC->nb_subfr - 1 ], 6 ); + for( i = 0; i < decisionDelay; i++ ) { + last_smple_idx = ( last_smple_idx - 1 ) % DECISION_DELAY; + if( last_smple_idx < 0 ) last_smple_idx += DECISION_DELAY; + pulses[ i - decisionDelay ] = (opus_int8)silk_RSHIFT_ROUND( psDD->Q_Q10[ last_smple_idx ], 10 ); + pxq[ i - decisionDelay ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( + silk_SMULWW( psDD->Xq_Q14[ last_smple_idx ], Gain_Q10 ), 8 ) ); + NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - decisionDelay + i ] = psDD->Shape_Q14[ last_smple_idx ]; + } + silk_memcpy( NSQ->sLPC_Q14, &psDD->sLPC_Q14[ psEncC->subfr_length ], NSQ_LPC_BUF_LENGTH * sizeof( opus_int32 ) ); + silk_memcpy( NSQ->sAR2_Q14, psDD->sAR2_Q14, sizeof( psDD->sAR2_Q14 ) ); + + /* Update states */ + NSQ->sLF_AR_shp_Q14 = psDD->LF_AR_Q14; + NSQ->lagPrev = pitchL[ psEncC->nb_subfr - 1 ]; + + /* Save quantized speech signal */ + silk_memmove( NSQ->xq, &NSQ->xq[ psEncC->frame_length ], psEncC->ltp_mem_length * sizeof( opus_int16 ) ); + silk_memmove( NSQ->sLTP_shp_Q14, &NSQ->sLTP_shp_Q14[ psEncC->frame_length ], psEncC->ltp_mem_length * sizeof( opus_int32 ) ); + RESTORE_STACK; +} + +/******************************************/ +/* Noise shape quantizer for one subframe */ +/******************************************/ +static OPUS_INLINE void silk_noise_shape_quantizer_del_dec_sse4_1( + silk_nsq_state *NSQ, /* I/O NSQ state */ + NSQ_del_dec_struct psDelDec[], /* I/O Delayed decision states */ + opus_int signalType, /* I Signal type */ + const opus_int32 x_Q10[], /* I */ + opus_int8 pulses[], /* O */ + opus_int16 xq[], /* O */ + opus_int32 sLTP_Q15[], /* I/O LTP filter state */ + opus_int32 delayedGain_Q10[], /* I/O Gain delay buffer */ + const opus_int16 a_Q12[], /* I Short term prediction coefs */ + const opus_int16 b_Q14[], /* I Long term prediction coefs */ + const opus_int16 AR_shp_Q13[], /* I Noise shaping coefs */ + opus_int lag, /* I Pitch lag */ + opus_int32 HarmShapeFIRPacked_Q14, /* I */ + opus_int Tilt_Q14, /* I Spectral tilt */ + opus_int32 LF_shp_Q14, /* I */ + opus_int32 Gain_Q16, /* I */ + opus_int Lambda_Q10, /* I */ + opus_int offset_Q10, /* I */ + opus_int length, /* I Input length */ + opus_int subfr, /* I Subframe number */ + opus_int shapingLPCOrder, /* I Shaping LPC filter order */ + opus_int predictLPCOrder, /* I Prediction filter order */ + opus_int warping_Q16, /* I */ + opus_int nStatesDelayedDecision, /* I Number of states in decision tree */ + opus_int *smpl_buf_idx, /* I/O Index to newest samples in buffers */ + opus_int decisionDelay /* I */ +) +{ + opus_int i, j, k, Winner_ind, RDmin_ind, RDmax_ind, last_smple_idx; + opus_int32 Winner_rand_state; + opus_int32 LTP_pred_Q14, LPC_pred_Q14, n_AR_Q14, n_LTP_Q14; + opus_int32 n_LF_Q14, r_Q10, rr_Q10, rd1_Q10, rd2_Q10, RDmin_Q10, RDmax_Q10; + opus_int32 q1_Q0, q1_Q10, q2_Q10, exc_Q14, LPC_exc_Q14, xq_Q14, Gain_Q10; + opus_int32 tmp1, tmp2, sLF_AR_shp_Q14; + opus_int32 *pred_lag_ptr, *shp_lag_ptr, *psLPC_Q14; + VARDECL( NSQ_sample_pair, psSampleState ); + NSQ_del_dec_struct *psDD; + NSQ_sample_struct *psSS; + + __m128i a_Q12_0123, a_Q12_4567, a_Q12_89AB, a_Q12_CDEF; + __m128i b_Q12_0123, b_sr_Q12_0123; + SAVE_STACK; + + celt_assert( nStatesDelayedDecision > 0 ); + ALLOC( psSampleState, nStatesDelayedDecision, NSQ_sample_pair ); + + shp_lag_ptr = &NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - lag + HARM_SHAPE_FIR_TAPS / 2 ]; + pred_lag_ptr = &sLTP_Q15[ NSQ->sLTP_buf_idx - lag + LTP_ORDER / 2 ]; + Gain_Q10 = silk_RSHIFT( Gain_Q16, 6 ); + + a_Q12_0123 = OP_CVTEPI16_EPI32_M64( a_Q12 ); + a_Q12_4567 = OP_CVTEPI16_EPI32_M64( a_Q12 + 4 ); + + if( opus_likely( predictLPCOrder == 16 ) ) { + a_Q12_89AB = OP_CVTEPI16_EPI32_M64( a_Q12 + 8 ); + a_Q12_CDEF = OP_CVTEPI16_EPI32_M64( a_Q12 + 12 ); + } + + if( signalType == TYPE_VOICED ){ + b_Q12_0123 = OP_CVTEPI16_EPI32_M64( b_Q14 ); + b_sr_Q12_0123 = _mm_shuffle_epi32( b_Q12_0123, _MM_SHUFFLE( 0, 3, 2, 1 ) ); /* equal shift right 4 bytes */ + } + for( i = 0; i < length; i++ ) { + /* Perform common calculations used in all states */ + + /* Long-term prediction */ + if( signalType == TYPE_VOICED ) { + /* Unrolled loop */ + /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */ + LTP_pred_Q14 = 2; + { + __m128i tmpa, tmpb, pred_lag_ptr_tmp; + pred_lag_ptr_tmp = _mm_loadu_si128( (__m128i *)(&pred_lag_ptr[ -3 ] ) ); + pred_lag_ptr_tmp = _mm_shuffle_epi32( pred_lag_ptr_tmp, 0x1B ); + tmpa = _mm_mul_epi32( pred_lag_ptr_tmp, b_Q12_0123 ); + tmpa = _mm_srli_si128( tmpa, 2 ); + + pred_lag_ptr_tmp = _mm_shuffle_epi32( pred_lag_ptr_tmp, _MM_SHUFFLE( 0, 3, 2, 1 ) );/* equal shift right 4 bytes */ + pred_lag_ptr_tmp = _mm_mul_epi32( pred_lag_ptr_tmp, b_sr_Q12_0123 ); + pred_lag_ptr_tmp = _mm_srli_si128( pred_lag_ptr_tmp, 2 ); + pred_lag_ptr_tmp = _mm_add_epi32( pred_lag_ptr_tmp, tmpa ); + + tmpb = _mm_shuffle_epi32( pred_lag_ptr_tmp, _MM_SHUFFLE( 0, 0, 3, 2 ) );/* equal shift right 8 bytes */ + pred_lag_ptr_tmp = _mm_add_epi32( pred_lag_ptr_tmp, tmpb ); + LTP_pred_Q14 += _mm_cvtsi128_si32( pred_lag_ptr_tmp ); + + LTP_pred_Q14 = silk_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ -4 ], b_Q14[ 4 ] ); + LTP_pred_Q14 = silk_LSHIFT( LTP_pred_Q14, 1 ); /* Q13 -> Q14 */ + pred_lag_ptr++; + } + } else { + LTP_pred_Q14 = 0; + } + + /* Long-term shaping */ + if( lag > 0 ) { + /* Symmetric, packed FIR coefficients */ + n_LTP_Q14 = silk_SMULWB( silk_ADD32( shp_lag_ptr[ 0 ], shp_lag_ptr[ -2 ] ), HarmShapeFIRPacked_Q14 ); + n_LTP_Q14 = silk_SMLAWT( n_LTP_Q14, shp_lag_ptr[ -1 ], HarmShapeFIRPacked_Q14 ); + n_LTP_Q14 = silk_SUB_LSHIFT32( LTP_pred_Q14, n_LTP_Q14, 2 ); /* Q12 -> Q14 */ + shp_lag_ptr++; + } else { + n_LTP_Q14 = 0; + } + { + __m128i tmpa, tmpb, psLPC_Q14_tmp, a_Q12_tmp; + + for( k = 0; k < nStatesDelayedDecision; k++ ) { + /* Delayed decision state */ + psDD = &psDelDec[ k ]; + + /* Sample state */ + psSS = psSampleState[ k ]; + + /* Generate dither */ + psDD->Seed = silk_RAND( psDD->Seed ); + + /* Pointer used in short term prediction and shaping */ + psLPC_Q14 = &psDD->sLPC_Q14[ NSQ_LPC_BUF_LENGTH - 1 + i ]; + /* Short-term prediction */ + silk_assert( predictLPCOrder == 10 || predictLPCOrder == 16 ); + /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */ + LPC_pred_Q14 = silk_RSHIFT( predictLPCOrder, 1 ); + + tmpb = _mm_setzero_si128(); + + /* step 1 */ + psLPC_Q14_tmp = _mm_loadu_si128( (__m128i *)(&psLPC_Q14[ -3 ] ) ); /* -3, -2 , -1, 0 */ + psLPC_Q14_tmp = _mm_shuffle_epi32( psLPC_Q14_tmp, 0x1B ); /* 0, -1, -2, -3 */ + tmpa = _mm_mul_epi32( psLPC_Q14_tmp, a_Q12_0123 ); /* 0, -1, -2, -3 * 0123 -> 0*0, 2*-2 */ + + tmpa = _mm_srli_epi64( tmpa, 16 ); + tmpb = _mm_add_epi32( tmpb, tmpa ); + + psLPC_Q14_tmp = _mm_shuffle_epi32( psLPC_Q14_tmp, _MM_SHUFFLE( 0, 3, 2, 1 ) ); /* equal shift right 4 bytes */ + a_Q12_tmp = _mm_shuffle_epi32( a_Q12_0123, _MM_SHUFFLE(0, 3, 2, 1 ) ); /* equal shift right 4 bytes */ + psLPC_Q14_tmp = _mm_mul_epi32( psLPC_Q14_tmp, a_Q12_tmp ); /* 1*-1, 3*-3 */ + psLPC_Q14_tmp = _mm_srli_epi64( psLPC_Q14_tmp, 16 ); + tmpb = _mm_add_epi32( tmpb, psLPC_Q14_tmp ); + + /* step 2 */ + psLPC_Q14_tmp = _mm_loadu_si128( (__m128i *)(&psLPC_Q14[ -7 ] ) ); + psLPC_Q14_tmp = _mm_shuffle_epi32( psLPC_Q14_tmp, 0x1B ); + tmpa = _mm_mul_epi32( psLPC_Q14_tmp, a_Q12_4567 ); + tmpa = _mm_srli_epi64( tmpa, 16 ); + tmpb = _mm_add_epi32( tmpb, tmpa ); + + psLPC_Q14_tmp = _mm_shuffle_epi32( psLPC_Q14_tmp, _MM_SHUFFLE( 0, 3, 2, 1 ) ); /* equal shift right 4 bytes */ + a_Q12_tmp = _mm_shuffle_epi32( a_Q12_4567, _MM_SHUFFLE(0, 3, 2, 1 ) ); /* equal shift right 4 bytes */ + psLPC_Q14_tmp = _mm_mul_epi32( psLPC_Q14_tmp, a_Q12_tmp ); + psLPC_Q14_tmp = _mm_srli_epi64( psLPC_Q14_tmp, 16 ); + tmpb = _mm_add_epi32( tmpb, psLPC_Q14_tmp ); + + if ( opus_likely( predictLPCOrder == 16 ) ) + { + /* step 3 */ + psLPC_Q14_tmp = _mm_loadu_si128( (__m128i *)(&psLPC_Q14[ -11 ] ) ); + psLPC_Q14_tmp = _mm_shuffle_epi32( psLPC_Q14_tmp, 0x1B ); + tmpa = _mm_mul_epi32( psLPC_Q14_tmp, a_Q12_89AB ); + tmpa = _mm_srli_epi64( tmpa, 16 ); + tmpb = _mm_add_epi32( tmpb, tmpa ); + + psLPC_Q14_tmp = _mm_shuffle_epi32( psLPC_Q14_tmp, _MM_SHUFFLE( 0, 3, 2, 1 ) ); /* equal shift right 4 bytes */ + a_Q12_tmp = _mm_shuffle_epi32( a_Q12_89AB, _MM_SHUFFLE(0, 3, 2, 1 ) );/* equal shift right 4 bytes */ + psLPC_Q14_tmp = _mm_mul_epi32( psLPC_Q14_tmp, a_Q12_tmp ); + psLPC_Q14_tmp = _mm_srli_epi64( psLPC_Q14_tmp, 16 ); + tmpb = _mm_add_epi32( tmpb, psLPC_Q14_tmp ); + + /* setp 4 */ + psLPC_Q14_tmp = _mm_loadu_si128( (__m128i *)(&psLPC_Q14[ -15 ] ) ); + psLPC_Q14_tmp = _mm_shuffle_epi32( psLPC_Q14_tmp, 0x1B ); + tmpa = _mm_mul_epi32( psLPC_Q14_tmp, a_Q12_CDEF ); + tmpa = _mm_srli_epi64( tmpa, 16 ); + tmpb = _mm_add_epi32( tmpb, tmpa ); + + psLPC_Q14_tmp = _mm_shuffle_epi32( psLPC_Q14_tmp, _MM_SHUFFLE( 0, 3, 2, 1 ) ); /* equal shift right 4 bytes */ + a_Q12_tmp = _mm_shuffle_epi32( a_Q12_CDEF, _MM_SHUFFLE(0, 3, 2, 1 ) ); /* equal shift right 4 bytes */ + psLPC_Q14_tmp = _mm_mul_epi32( psLPC_Q14_tmp, a_Q12_tmp ); + psLPC_Q14_tmp = _mm_srli_epi64( psLPC_Q14_tmp, 16 ); + tmpb = _mm_add_epi32( tmpb, psLPC_Q14_tmp ); + + /* add at last */ + /* equal shift right 8 bytes*/ + tmpa = _mm_shuffle_epi32( tmpb, _MM_SHUFFLE( 0, 0, 3, 2 ) ); + tmpb = _mm_add_epi32( tmpb, tmpa ); + LPC_pred_Q14 += _mm_cvtsi128_si32( tmpb ); + } + else + { + /* add at last */ + tmpa = _mm_shuffle_epi32( tmpb, _MM_SHUFFLE( 0, 0, 3, 2 ) ); /* equal shift right 8 bytes*/ + tmpb = _mm_add_epi32( tmpb, tmpa ); + LPC_pred_Q14 += _mm_cvtsi128_si32( tmpb ); + + LPC_pred_Q14 = silk_SMLAWB( LPC_pred_Q14, psLPC_Q14[ -8 ], a_Q12[ 8 ] ); + LPC_pred_Q14 = silk_SMLAWB( LPC_pred_Q14, psLPC_Q14[ -9 ], a_Q12[ 9 ] ); + } + + LPC_pred_Q14 = silk_LSHIFT( LPC_pred_Q14, 4 ); /* Q10 -> Q14 */ + + /* Noise shape feedback */ + silk_assert( ( shapingLPCOrder & 1 ) == 0 ); /* check that order is even */ + /* Output of lowpass section */ + tmp2 = silk_SMLAWB( psLPC_Q14[ 0 ], psDD->sAR2_Q14[ 0 ], warping_Q16 ); + /* Output of allpass section */ + tmp1 = silk_SMLAWB( psDD->sAR2_Q14[ 0 ], psDD->sAR2_Q14[ 1 ] - tmp2, warping_Q16 ); + psDD->sAR2_Q14[ 0 ] = tmp2; + n_AR_Q14 = silk_RSHIFT( shapingLPCOrder, 1 ); + n_AR_Q14 = silk_SMLAWB( n_AR_Q14, tmp2, AR_shp_Q13[ 0 ] ); + /* Loop over allpass sections */ + for( j = 2; j < shapingLPCOrder; j += 2 ) { + /* Output of allpass section */ + tmp2 = silk_SMLAWB( psDD->sAR2_Q14[ j - 1 ], psDD->sAR2_Q14[ j + 0 ] - tmp1, warping_Q16 ); + psDD->sAR2_Q14[ j - 1 ] = tmp1; + n_AR_Q14 = silk_SMLAWB( n_AR_Q14, tmp1, AR_shp_Q13[ j - 1 ] ); + /* Output of allpass section */ + tmp1 = silk_SMLAWB( psDD->sAR2_Q14[ j + 0 ], psDD->sAR2_Q14[ j + 1 ] - tmp2, warping_Q16 ); + psDD->sAR2_Q14[ j + 0 ] = tmp2; + n_AR_Q14 = silk_SMLAWB( n_AR_Q14, tmp2, AR_shp_Q13[ j ] ); + } + psDD->sAR2_Q14[ shapingLPCOrder - 1 ] = tmp1; + n_AR_Q14 = silk_SMLAWB( n_AR_Q14, tmp1, AR_shp_Q13[ shapingLPCOrder - 1 ] ); + + n_AR_Q14 = silk_LSHIFT( n_AR_Q14, 1 ); /* Q11 -> Q12 */ + n_AR_Q14 = silk_SMLAWB( n_AR_Q14, psDD->LF_AR_Q14, Tilt_Q14 ); /* Q12 */ + n_AR_Q14 = silk_LSHIFT( n_AR_Q14, 2 ); /* Q12 -> Q14 */ + + n_LF_Q14 = silk_SMULWB( psDD->Shape_Q14[ *smpl_buf_idx ], LF_shp_Q14 ); /* Q12 */ + n_LF_Q14 = silk_SMLAWT( n_LF_Q14, psDD->LF_AR_Q14, LF_shp_Q14 ); /* Q12 */ + n_LF_Q14 = silk_LSHIFT( n_LF_Q14, 2 ); /* Q12 -> Q14 */ + + /* Input minus prediction plus noise feedback */ + /* r = x[ i ] - LTP_pred - LPC_pred + n_AR + n_Tilt + n_LF + n_LTP */ + tmp1 = silk_ADD32( n_AR_Q14, n_LF_Q14 ); /* Q14 */ + tmp2 = silk_ADD32( n_LTP_Q14, LPC_pred_Q14 ); /* Q13 */ + tmp1 = silk_SUB32( tmp2, tmp1 ); /* Q13 */ + tmp1 = silk_RSHIFT_ROUND( tmp1, 4 ); /* Q10 */ + + r_Q10 = silk_SUB32( x_Q10[ i ], tmp1 ); /* residual error Q10 */ + + /* Flip sign depending on dither */ + if ( psDD->Seed < 0 ) { + r_Q10 = -r_Q10; + } + r_Q10 = silk_LIMIT_32( r_Q10, -(31 << 10), 30 << 10 ); + + /* Find two quantization level candidates and measure their rate-distortion */ + q1_Q10 = silk_SUB32( r_Q10, offset_Q10 ); + q1_Q0 = silk_RSHIFT( q1_Q10, 10 ); + if( q1_Q0 > 0 ) { + q1_Q10 = silk_SUB32( silk_LSHIFT( q1_Q0, 10 ), QUANT_LEVEL_ADJUST_Q10 ); + q1_Q10 = silk_ADD32( q1_Q10, offset_Q10 ); + q2_Q10 = silk_ADD32( q1_Q10, 1024 ); + rd1_Q10 = silk_SMULBB( q1_Q10, Lambda_Q10 ); + rd2_Q10 = silk_SMULBB( q2_Q10, Lambda_Q10 ); + } else if( q1_Q0 == 0 ) { + q1_Q10 = offset_Q10; + q2_Q10 = silk_ADD32( q1_Q10, 1024 - QUANT_LEVEL_ADJUST_Q10 ); + rd1_Q10 = silk_SMULBB( q1_Q10, Lambda_Q10 ); + rd2_Q10 = silk_SMULBB( q2_Q10, Lambda_Q10 ); + } else if( q1_Q0 == -1 ) { + q2_Q10 = offset_Q10; + q1_Q10 = silk_SUB32( q2_Q10, 1024 - QUANT_LEVEL_ADJUST_Q10 ); + rd1_Q10 = silk_SMULBB( -q1_Q10, Lambda_Q10 ); + rd2_Q10 = silk_SMULBB( q2_Q10, Lambda_Q10 ); + } else { /* q1_Q0 < -1 */ + q1_Q10 = silk_ADD32( silk_LSHIFT( q1_Q0, 10 ), QUANT_LEVEL_ADJUST_Q10 ); + q1_Q10 = silk_ADD32( q1_Q10, offset_Q10 ); + q2_Q10 = silk_ADD32( q1_Q10, 1024 ); + rd1_Q10 = silk_SMULBB( -q1_Q10, Lambda_Q10 ); + rd2_Q10 = silk_SMULBB( -q2_Q10, Lambda_Q10 ); + } + rr_Q10 = silk_SUB32( r_Q10, q1_Q10 ); + rd1_Q10 = silk_RSHIFT( silk_SMLABB( rd1_Q10, rr_Q10, rr_Q10 ), 10 ); + rr_Q10 = silk_SUB32( r_Q10, q2_Q10 ); + rd2_Q10 = silk_RSHIFT( silk_SMLABB( rd2_Q10, rr_Q10, rr_Q10 ), 10 ); + + if( rd1_Q10 < rd2_Q10 ) { + psSS[ 0 ].RD_Q10 = silk_ADD32( psDD->RD_Q10, rd1_Q10 ); + psSS[ 1 ].RD_Q10 = silk_ADD32( psDD->RD_Q10, rd2_Q10 ); + psSS[ 0 ].Q_Q10 = q1_Q10; + psSS[ 1 ].Q_Q10 = q2_Q10; + } else { + psSS[ 0 ].RD_Q10 = silk_ADD32( psDD->RD_Q10, rd2_Q10 ); + psSS[ 1 ].RD_Q10 = silk_ADD32( psDD->RD_Q10, rd1_Q10 ); + psSS[ 0 ].Q_Q10 = q2_Q10; + psSS[ 1 ].Q_Q10 = q1_Q10; + } + + /* Update states for best quantization */ + + /* Quantized excitation */ + exc_Q14 = silk_LSHIFT32( psSS[ 0 ].Q_Q10, 4 ); + if ( psDD->Seed < 0 ) { + exc_Q14 = -exc_Q14; + } + + /* Add predictions */ + LPC_exc_Q14 = silk_ADD32( exc_Q14, LTP_pred_Q14 ); + xq_Q14 = silk_ADD32( LPC_exc_Q14, LPC_pred_Q14 ); + + /* Update states */ + sLF_AR_shp_Q14 = silk_SUB32( xq_Q14, n_AR_Q14 ); + psSS[ 0 ].sLTP_shp_Q14 = silk_SUB32( sLF_AR_shp_Q14, n_LF_Q14 ); + psSS[ 0 ].LF_AR_Q14 = sLF_AR_shp_Q14; + psSS[ 0 ].LPC_exc_Q14 = LPC_exc_Q14; + psSS[ 0 ].xq_Q14 = xq_Q14; + + /* Update states for second best quantization */ + + /* Quantized excitation */ + exc_Q14 = silk_LSHIFT32( psSS[ 1 ].Q_Q10, 4 ); + if ( psDD->Seed < 0 ) { + exc_Q14 = -exc_Q14; + } + + + /* Add predictions */ + LPC_exc_Q14 = silk_ADD32( exc_Q14, LTP_pred_Q14 ); + xq_Q14 = silk_ADD32( LPC_exc_Q14, LPC_pred_Q14 ); + + /* Update states */ + sLF_AR_shp_Q14 = silk_SUB32( xq_Q14, n_AR_Q14 ); + psSS[ 1 ].sLTP_shp_Q14 = silk_SUB32( sLF_AR_shp_Q14, n_LF_Q14 ); + psSS[ 1 ].LF_AR_Q14 = sLF_AR_shp_Q14; + psSS[ 1 ].LPC_exc_Q14 = LPC_exc_Q14; + psSS[ 1 ].xq_Q14 = xq_Q14; + } + } + *smpl_buf_idx = ( *smpl_buf_idx - 1 ) % DECISION_DELAY; + if( *smpl_buf_idx < 0 ) *smpl_buf_idx += DECISION_DELAY; + last_smple_idx = ( *smpl_buf_idx + decisionDelay ) % DECISION_DELAY; + + /* Find winner */ + RDmin_Q10 = psSampleState[ 0 ][ 0 ].RD_Q10; + Winner_ind = 0; + for( k = 1; k < nStatesDelayedDecision; k++ ) { + if( psSampleState[ k ][ 0 ].RD_Q10 < RDmin_Q10 ) { + RDmin_Q10 = psSampleState[ k ][ 0 ].RD_Q10; + Winner_ind = k; + } + } + + /* Increase RD values of expired states */ + 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 ) { + psSampleState[ k ][ 0 ].RD_Q10 = silk_ADD32( psSampleState[ k ][ 0 ].RD_Q10, silk_int32_MAX >> 4 ); + psSampleState[ k ][ 1 ].RD_Q10 = silk_ADD32( psSampleState[ k ][ 1 ].RD_Q10, silk_int32_MAX >> 4 ); + silk_assert( psSampleState[ k ][ 0 ].RD_Q10 >= 0 ); + } + } + + /* Find worst in first set and best in second set */ + RDmax_Q10 = psSampleState[ 0 ][ 0 ].RD_Q10; + RDmin_Q10 = psSampleState[ 0 ][ 1 ].RD_Q10; + RDmax_ind = 0; + RDmin_ind = 0; + for( k = 1; k < nStatesDelayedDecision; k++ ) { + /* find worst in first set */ + if( psSampleState[ k ][ 0 ].RD_Q10 > RDmax_Q10 ) { + RDmax_Q10 = psSampleState[ k ][ 0 ].RD_Q10; + RDmax_ind = k; + } + /* find best in second set */ + if( psSampleState[ k ][ 1 ].RD_Q10 < RDmin_Q10 ) { + RDmin_Q10 = psSampleState[ k ][ 1 ].RD_Q10; + RDmin_ind = k; + } + } + + /* Replace a state if best from second set outperforms worst in first set */ + if( RDmin_Q10 < RDmax_Q10 ) { + silk_memcpy( ( (opus_int32 *)&psDelDec[ RDmax_ind ] ) + i, + ( (opus_int32 *)&psDelDec[ RDmin_ind ] ) + i, sizeof( NSQ_del_dec_struct ) - i * sizeof( opus_int32) ); + silk_memcpy( &psSampleState[ RDmax_ind ][ 0 ], &psSampleState[ RDmin_ind ][ 1 ], sizeof( NSQ_sample_struct ) ); + } + + /* Write samples from winner to output and long-term filter states */ + psDD = &psDelDec[ Winner_ind ]; + if( subfr > 0 || i >= decisionDelay ) { + pulses[ i - decisionDelay ] = (opus_int8)silk_RSHIFT_ROUND( psDD->Q_Q10[ last_smple_idx ], 10 ); + xq[ i - decisionDelay ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( + silk_SMULWW( psDD->Xq_Q14[ last_smple_idx ], delayedGain_Q10[ last_smple_idx ] ), 8 ) ); + NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - decisionDelay ] = psDD->Shape_Q14[ last_smple_idx ]; + sLTP_Q15[ NSQ->sLTP_buf_idx - decisionDelay ] = psDD->Pred_Q15[ last_smple_idx ]; + } + NSQ->sLTP_shp_buf_idx++; + NSQ->sLTP_buf_idx++; + + /* Update states */ + for( k = 0; k < nStatesDelayedDecision; k++ ) { + psDD = &psDelDec[ k ]; + psSS = &psSampleState[ k ][ 0 ]; + psDD->LF_AR_Q14 = psSS->LF_AR_Q14; + psDD->sLPC_Q14[ NSQ_LPC_BUF_LENGTH + i ] = psSS->xq_Q14; + psDD->Xq_Q14[ *smpl_buf_idx ] = psSS->xq_Q14; + psDD->Q_Q10[ *smpl_buf_idx ] = psSS->Q_Q10; + psDD->Pred_Q15[ *smpl_buf_idx ] = silk_LSHIFT32( psSS->LPC_exc_Q14, 1 ); + psDD->Shape_Q14[ *smpl_buf_idx ] = psSS->sLTP_shp_Q14; + psDD->Seed = silk_ADD32_ovflw( psDD->Seed, silk_RSHIFT_ROUND( psSS->Q_Q10, 10 ) ); + psDD->RandState[ *smpl_buf_idx ] = psDD->Seed; + psDD->RD_Q10 = psSS->RD_Q10; + } + delayedGain_Q10[ *smpl_buf_idx ] = Gain_Q10; + } + /* Update LPC states */ + for( k = 0; k < nStatesDelayedDecision; k++ ) { + psDD = &psDelDec[ k ]; + silk_memcpy( psDD->sLPC_Q14, &psDD->sLPC_Q14[ length ], NSQ_LPC_BUF_LENGTH * sizeof( opus_int32 ) ); + } + RESTORE_STACK; +} + +static OPUS_INLINE void silk_nsq_del_dec_scale_states_sse4_1( + const silk_encoder_state *psEncC, /* I Encoder State */ + silk_nsq_state *NSQ, /* I/O NSQ state */ + NSQ_del_dec_struct psDelDec[], /* I/O Delayed decision states */ + const opus_int32 x_Q3[], /* I Input in Q3 */ + opus_int32 x_sc_Q10[], /* O Input scaled with 1/Gain in Q10 */ + const opus_int16 sLTP[], /* I Re-whitened LTP state in Q0 */ + opus_int32 sLTP_Q15[], /* O LTP state matching scaled input */ + opus_int subfr, /* I Subframe number */ + opus_int nStatesDelayedDecision, /* I Number of del dec states */ + const opus_int LTP_scale_Q14, /* I LTP state scaling */ + const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lag */ + const opus_int signal_type, /* I Signal type */ + const opus_int decisionDelay /* I Decision delay */ +) +{ + opus_int i, k, lag; + opus_int32 gain_adj_Q16, inv_gain_Q31, inv_gain_Q23; + NSQ_del_dec_struct *psDD; + __m128i xmm_inv_gain_Q23, xmm_x_Q3_x2x0, xmm_x_Q3_x3x1; + + lag = pitchL[ subfr ]; + inv_gain_Q31 = silk_INVERSE32_varQ( silk_max( Gains_Q16[ subfr ], 1 ), 47 ); + + silk_assert( inv_gain_Q31 != 0 ); + + /* Calculate gain adjustment factor */ + if( Gains_Q16[ subfr ] != NSQ->prev_gain_Q16 ) { + gain_adj_Q16 = silk_DIV32_varQ( NSQ->prev_gain_Q16, Gains_Q16[ subfr ], 16 ); + } else { + gain_adj_Q16 = (opus_int32)1 << 16; + } + + /* Scale input */ + inv_gain_Q23 = silk_RSHIFT_ROUND( inv_gain_Q31, 8 ); + + /* prepare inv_gain_Q23 in packed 4 32-bits */ + xmm_inv_gain_Q23 = _mm_set1_epi32(inv_gain_Q23); + + for( i = 0; i < psEncC->subfr_length - 3; i += 4 ) { + xmm_x_Q3_x2x0 = _mm_loadu_si128( (__m128i *)(&(x_Q3[ i ] ) ) ); + /* equal shift right 4 bytes*/ + xmm_x_Q3_x3x1 = _mm_shuffle_epi32( xmm_x_Q3_x2x0, _MM_SHUFFLE( 0, 3, 2, 1 ) ); + + xmm_x_Q3_x2x0 = _mm_mul_epi32( xmm_x_Q3_x2x0, xmm_inv_gain_Q23 ); + xmm_x_Q3_x3x1 = _mm_mul_epi32( xmm_x_Q3_x3x1, xmm_inv_gain_Q23 ); + + xmm_x_Q3_x2x0 = _mm_srli_epi64( xmm_x_Q3_x2x0, 16 ); + xmm_x_Q3_x3x1 = _mm_slli_epi64( xmm_x_Q3_x3x1, 16 ); + + xmm_x_Q3_x2x0 = _mm_blend_epi16( xmm_x_Q3_x2x0, xmm_x_Q3_x3x1, 0xCC ); + + _mm_storeu_si128( (__m128i *)(&(x_sc_Q10[ i ])), xmm_x_Q3_x2x0 ); + } + + for( ; i < psEncC->subfr_length; i++ ) { + x_sc_Q10[ i ] = silk_SMULWW( x_Q3[ i ], inv_gain_Q23 ); + } + + /* Save inverse gain */ + NSQ->prev_gain_Q16 = Gains_Q16[ subfr ]; + + /* After rewhitening the LTP state is un-scaled, so scale with inv_gain_Q16 */ + if( NSQ->rewhite_flag ) { + if( subfr == 0 ) { + /* Do LTP downscaling */ + inv_gain_Q31 = silk_LSHIFT( silk_SMULWB( inv_gain_Q31, LTP_scale_Q14 ), 2 ); + } + for( i = NSQ->sLTP_buf_idx - lag - LTP_ORDER / 2; i < NSQ->sLTP_buf_idx; i++ ) { + silk_assert( i < MAX_FRAME_LENGTH ); + sLTP_Q15[ i ] = silk_SMULWB( inv_gain_Q31, sLTP[ i ] ); + } + } + + /* Adjust for changing gain */ + if( gain_adj_Q16 != (opus_int32)1 << 16 ) { + /* Scale long-term shaping state */ + { + __m128i xmm_gain_adj_Q16, xmm_sLTP_shp_Q14_x2x0, xmm_sLTP_shp_Q14_x3x1; + + /* prepare gain_adj_Q16 in packed 4 32-bits */ + xmm_gain_adj_Q16 = _mm_set1_epi32( gain_adj_Q16 ); + + for( i = NSQ->sLTP_shp_buf_idx - psEncC->ltp_mem_length; i < NSQ->sLTP_shp_buf_idx - 3; i += 4 ) + { + xmm_sLTP_shp_Q14_x2x0 = _mm_loadu_si128( (__m128i *)(&(NSQ->sLTP_shp_Q14[ i ] ) ) ); + /* equal shift right 4 bytes*/ + xmm_sLTP_shp_Q14_x3x1 = _mm_shuffle_epi32( xmm_sLTP_shp_Q14_x2x0, _MM_SHUFFLE( 0, 3, 2, 1 ) ); + + xmm_sLTP_shp_Q14_x2x0 = _mm_mul_epi32( xmm_sLTP_shp_Q14_x2x0, xmm_gain_adj_Q16 ); + xmm_sLTP_shp_Q14_x3x1 = _mm_mul_epi32( xmm_sLTP_shp_Q14_x3x1, xmm_gain_adj_Q16 ); + + xmm_sLTP_shp_Q14_x2x0 = _mm_srli_epi64( xmm_sLTP_shp_Q14_x2x0, 16 ); + xmm_sLTP_shp_Q14_x3x1 = _mm_slli_epi64( xmm_sLTP_shp_Q14_x3x1, 16 ); + + xmm_sLTP_shp_Q14_x2x0 = _mm_blend_epi16( xmm_sLTP_shp_Q14_x2x0, xmm_sLTP_shp_Q14_x3x1, 0xCC ); + + _mm_storeu_si128( (__m128i *)(&(NSQ->sLTP_shp_Q14[ i ] ) ), xmm_sLTP_shp_Q14_x2x0 ); + } + + for( ; i < NSQ->sLTP_shp_buf_idx; i++ ) { + NSQ->sLTP_shp_Q14[ i ] = silk_SMULWW( gain_adj_Q16, NSQ->sLTP_shp_Q14[ i ] ); + } + + /* Scale long-term prediction state */ + if( signal_type == TYPE_VOICED && NSQ->rewhite_flag == 0 ) { + for( i = NSQ->sLTP_buf_idx - lag - LTP_ORDER / 2; i < NSQ->sLTP_buf_idx - decisionDelay; i++ ) { + sLTP_Q15[ i ] = silk_SMULWW( gain_adj_Q16, sLTP_Q15[ i ] ); + } + } + + for( k = 0; k < nStatesDelayedDecision; k++ ) { + psDD = &psDelDec[ k ]; + + /* Scale scalar states */ + psDD->LF_AR_Q14 = silk_SMULWW( gain_adj_Q16, psDD->LF_AR_Q14 ); + + /* Scale short-term prediction and shaping states */ + for( i = 0; i < NSQ_LPC_BUF_LENGTH; i++ ) { + psDD->sLPC_Q14[ i ] = silk_SMULWW( gain_adj_Q16, psDD->sLPC_Q14[ i ] ); + } + for( i = 0; i < MAX_SHAPE_LPC_ORDER; i++ ) { + psDD->sAR2_Q14[ i ] = silk_SMULWW( gain_adj_Q16, psDD->sAR2_Q14[ i ] ); + } + for( i = 0; i < DECISION_DELAY; i++ ) { + psDD->Pred_Q15[ i ] = silk_SMULWW( gain_adj_Q16, psDD->Pred_Q15[ i ] ); + psDD->Shape_Q14[ i ] = silk_SMULWW( gain_adj_Q16, psDD->Shape_Q14[ i ] ); + } + } + } + } +} diff --git a/extern/opus/silk/x86/NSQ_sse4_1.c b/extern/opus/silk/x86/NSQ_sse4_1.c new file mode 100644 index 0000000..b0315e3 --- /dev/null +++ b/extern/opus/silk/x86/NSQ_sse4_1.c @@ -0,0 +1,719 @@ +/* Copyright (c) 2014, Cisco Systems, INC + Written by XiangMingZhu WeiZhou MinPeng YanWang + + 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. + + 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 OWNER + 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. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include "main.h" +#include "celt/x86/x86cpu.h" +#include "stack_alloc.h" + +static OPUS_INLINE void silk_nsq_scale_states_sse4_1( + const silk_encoder_state *psEncC, /* I Encoder State */ + silk_nsq_state *NSQ, /* I/O NSQ state */ + const opus_int32 x_Q3[], /* I input in Q3 */ + opus_int32 x_sc_Q10[], /* O input scaled with 1/Gain */ + const opus_int16 sLTP[], /* I re-whitened LTP state in Q0 */ + opus_int32 sLTP_Q15[], /* O LTP state matching scaled input */ + opus_int subfr, /* I subframe number */ + const opus_int LTP_scale_Q14, /* I */ + const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lag */ + const opus_int signal_type /* I Signal type */ +); + +static OPUS_INLINE void silk_noise_shape_quantizer_10_16_sse4_1( + silk_nsq_state *NSQ, /* I/O NSQ state */ + opus_int signalType, /* I Signal type */ + const opus_int32 x_sc_Q10[], /* I */ + opus_int8 pulses[], /* O */ + opus_int16 xq[], /* O */ + opus_int32 sLTP_Q15[], /* I/O LTP state */ + const opus_int16 a_Q12[], /* I Short term prediction coefs */ + const opus_int16 b_Q14[], /* I Long term prediction coefs */ + const opus_int16 AR_shp_Q13[], /* I Noise shaping AR coefs */ + opus_int lag, /* I Pitch lag */ + opus_int32 HarmShapeFIRPacked_Q14, /* I */ + opus_int Tilt_Q14, /* I Spectral tilt */ + opus_int32 LF_shp_Q14, /* I */ + opus_int32 Gain_Q16, /* I */ + opus_int offset_Q10, /* I */ + opus_int length, /* I Input length */ + opus_int32 table[][4] /* I */ +); + +void silk_NSQ_sse4_1( + const silk_encoder_state *psEncC, /* I Encoder State */ + silk_nsq_state *NSQ, /* I/O NSQ state */ + SideInfoIndices *psIndices, /* I/O Quantization Indices */ + const opus_int32 x_Q3[], /* I Prefiltered input signal */ + opus_int8 pulses[], /* O Quantized pulse signal */ + const opus_int16 PredCoef_Q12[ 2 * MAX_LPC_ORDER ], /* I Short term prediction coefs */ + const opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ], /* I Long term prediction coefs */ + const opus_int16 AR2_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ], /* I Noise shaping coefs */ + const opus_int HarmShapeGain_Q14[ MAX_NB_SUBFR ], /* I Long term shaping coefs */ + const opus_int Tilt_Q14[ MAX_NB_SUBFR ], /* I Spectral tilt */ + const opus_int32 LF_shp_Q14[ MAX_NB_SUBFR ], /* I Low frequency shaping coefs */ + const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I Quantization step sizes */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lags */ + const opus_int Lambda_Q10, /* I Rate/distortion tradeoff */ + const opus_int LTP_scale_Q14 /* I LTP state scaling */ +) +{ + opus_int k, lag, start_idx, LSF_interpolation_flag; + const opus_int16 *A_Q12, *B_Q14, *AR_shp_Q13; + opus_int16 *pxq; + VARDECL( opus_int32, sLTP_Q15 ); + VARDECL( opus_int16, sLTP ); + opus_int32 HarmShapeFIRPacked_Q14; + opus_int offset_Q10; + VARDECL( opus_int32, x_sc_Q10 ); + + opus_int32 table[ 64 ][ 4 ]; + opus_int32 tmp1; + opus_int32 q1_Q10, q2_Q10, rd1_Q20, rd2_Q20; + + SAVE_STACK; + + NSQ->rand_seed = psIndices->Seed; + + /* Set unvoiced lag to the previous one, overwrite later for voiced */ + lag = NSQ->lagPrev; + + silk_assert( NSQ->prev_gain_Q16 != 0 ); + + offset_Q10 = silk_Quantization_Offsets_Q10[ psIndices->signalType >> 1 ][ psIndices->quantOffsetType ]; + + /* 0 */ + q1_Q10 = offset_Q10; + q2_Q10 = offset_Q10 + ( 1024 - QUANT_LEVEL_ADJUST_Q10 ); + rd1_Q20 = q1_Q10 * Lambda_Q10; + rd2_Q20 = q2_Q10 * Lambda_Q10; + + table[ 32 ][ 0 ] = q1_Q10; + table[ 32 ][ 1 ] = q2_Q10; + table[ 32 ][ 2 ] = 2 * (q1_Q10 - q2_Q10); + table[ 32 ][ 3 ] = (rd1_Q20 - rd2_Q20) + (q1_Q10 * q1_Q10 - q2_Q10 * q2_Q10); + + /* -1 */ + q1_Q10 = offset_Q10 - ( 1024 - QUANT_LEVEL_ADJUST_Q10 ); + q2_Q10 = offset_Q10; + rd1_Q20 = - q1_Q10 * Lambda_Q10; + rd2_Q20 = q2_Q10 * Lambda_Q10; + + table[ 31 ][ 0 ] = q1_Q10; + table[ 31 ][ 1 ] = q2_Q10; + table[ 31 ][ 2 ] = 2 * (q1_Q10 - q2_Q10); + table[ 31 ][ 3 ] = (rd1_Q20 - rd2_Q20) + (q1_Q10 * q1_Q10 - q2_Q10 * q2_Q10); + + /* > 0 */ + for (k = 1; k <= 31; k++) + { + tmp1 = offset_Q10 + silk_LSHIFT( k, 10 ); + + q1_Q10 = tmp1 - QUANT_LEVEL_ADJUST_Q10; + q2_Q10 = tmp1 - QUANT_LEVEL_ADJUST_Q10 + 1024; + rd1_Q20 = q1_Q10 * Lambda_Q10; + rd2_Q20 = q2_Q10 * Lambda_Q10; + + table[ 32 + k ][ 0 ] = q1_Q10; + table[ 32 + k ][ 1 ] = q2_Q10; + table[ 32 + k ][ 2 ] = 2 * (q1_Q10 - q2_Q10); + table[ 32 + k ][ 3 ] = (rd1_Q20 - rd2_Q20) + (q1_Q10 * q1_Q10 - q2_Q10 * q2_Q10); + } + + /* < -1 */ + for (k = -32; k <= -2; k++) + { + tmp1 = offset_Q10 + silk_LSHIFT( k, 10 ); + + q1_Q10 = tmp1 + QUANT_LEVEL_ADJUST_Q10; + q2_Q10 = tmp1 + QUANT_LEVEL_ADJUST_Q10 + 1024; + rd1_Q20 = - q1_Q10 * Lambda_Q10; + rd2_Q20 = - q2_Q10 * Lambda_Q10; + + table[ 32 + k ][ 0 ] = q1_Q10; + table[ 32 + k ][ 1 ] = q2_Q10; + table[ 32 + k ][ 2 ] = 2 * (q1_Q10 - q2_Q10); + table[ 32 + k ][ 3 ] = (rd1_Q20 - rd2_Q20) + (q1_Q10 * q1_Q10 - q2_Q10 * q2_Q10); + } + + if( psIndices->NLSFInterpCoef_Q2 == 4 ) { + LSF_interpolation_flag = 0; + } else { + LSF_interpolation_flag = 1; + } + + ALLOC( sLTP_Q15, + psEncC->ltp_mem_length + psEncC->frame_length, opus_int32 ); + ALLOC( sLTP, psEncC->ltp_mem_length + psEncC->frame_length, opus_int16 ); + ALLOC( x_sc_Q10, psEncC->subfr_length, opus_int32 ); + /* Set up pointers to start of sub frame */ + NSQ->sLTP_shp_buf_idx = psEncC->ltp_mem_length; + NSQ->sLTP_buf_idx = psEncC->ltp_mem_length; + pxq = &NSQ->xq[ psEncC->ltp_mem_length ]; + for( k = 0; k < psEncC->nb_subfr; k++ ) { + A_Q12 = &PredCoef_Q12[ (( k >> 1 ) | ( 1 - LSF_interpolation_flag )) * MAX_LPC_ORDER ]; + B_Q14 = <PCoef_Q14[ k * LTP_ORDER ]; + AR_shp_Q13 = &AR2_Q13[ k * MAX_SHAPE_LPC_ORDER ]; + + /* Noise shape parameters */ + silk_assert( HarmShapeGain_Q14[ k ] >= 0 ); + HarmShapeFIRPacked_Q14 = silk_RSHIFT( HarmShapeGain_Q14[ k ], 2 ); + HarmShapeFIRPacked_Q14 |= silk_LSHIFT( (opus_int32)silk_RSHIFT( HarmShapeGain_Q14[ k ], 1 ), 16 ); + + NSQ->rewhite_flag = 0; + if( psIndices->signalType == TYPE_VOICED ) { + /* Voiced */ + lag = pitchL[ k ]; + + /* Re-whitening */ + if( ( k & ( 3 - silk_LSHIFT( LSF_interpolation_flag, 1 ) ) ) == 0 ) { + /* Rewhiten with new A coefs */ + start_idx = psEncC->ltp_mem_length - lag - psEncC->predictLPCOrder - LTP_ORDER / 2; + celt_assert( start_idx > 0 ); + + silk_LPC_analysis_filter( &sLTP[ start_idx ], &NSQ->xq[ start_idx + k * psEncC->subfr_length ], + A_Q12, psEncC->ltp_mem_length - start_idx, psEncC->predictLPCOrder, psEncC->arch ); + + NSQ->rewhite_flag = 1; + NSQ->sLTP_buf_idx = psEncC->ltp_mem_length; + } + } + + silk_nsq_scale_states_sse4_1( psEncC, NSQ, x_Q3, x_sc_Q10, sLTP, sLTP_Q15, k, LTP_scale_Q14, Gains_Q16, pitchL, psIndices->signalType ); + + if ( opus_likely( ( 10 == psEncC->shapingLPCOrder ) && ( 16 == psEncC->predictLPCOrder) ) ) + { + silk_noise_shape_quantizer_10_16_sse4_1( NSQ, psIndices->signalType, x_sc_Q10, pulses, pxq, sLTP_Q15, A_Q12, B_Q14, + AR_shp_Q13, lag, HarmShapeFIRPacked_Q14, Tilt_Q14[ k ], LF_shp_Q14[ k ], Gains_Q16[ k ], + offset_Q10, psEncC->subfr_length, &(table[32]) ); + } + else + { + silk_noise_shape_quantizer( NSQ, psIndices->signalType, x_sc_Q10, pulses, pxq, sLTP_Q15, A_Q12, B_Q14, + 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, psEncC->arch ); + } + + x_Q3 += psEncC->subfr_length; + pulses += psEncC->subfr_length; + pxq += psEncC->subfr_length; + } + + /* Update lagPrev for next frame */ + NSQ->lagPrev = pitchL[ psEncC->nb_subfr - 1 ]; + + /* Save quantized speech and noise shaping signals */ + silk_memmove( NSQ->xq, &NSQ->xq[ psEncC->frame_length ], psEncC->ltp_mem_length * sizeof( opus_int16 ) ); + silk_memmove( NSQ->sLTP_shp_Q14, &NSQ->sLTP_shp_Q14[ psEncC->frame_length ], psEncC->ltp_mem_length * sizeof( opus_int32 ) ); + RESTORE_STACK; +} + +/***********************************/ +/* silk_noise_shape_quantizer_10_16 */ +/***********************************/ +static OPUS_INLINE void silk_noise_shape_quantizer_10_16_sse4_1( + silk_nsq_state *NSQ, /* I/O NSQ state */ + opus_int signalType, /* I Signal type */ + const opus_int32 x_sc_Q10[], /* I */ + opus_int8 pulses[], /* O */ + opus_int16 xq[], /* O */ + opus_int32 sLTP_Q15[], /* I/O LTP state */ + const opus_int16 a_Q12[], /* I Short term prediction coefs */ + const opus_int16 b_Q14[], /* I Long term prediction coefs */ + const opus_int16 AR_shp_Q13[], /* I Noise shaping AR coefs */ + opus_int lag, /* I Pitch lag */ + opus_int32 HarmShapeFIRPacked_Q14, /* I */ + opus_int Tilt_Q14, /* I Spectral tilt */ + opus_int32 LF_shp_Q14, /* I */ + opus_int32 Gain_Q16, /* I */ + opus_int offset_Q10, /* I */ + opus_int length, /* I Input length */ + opus_int32 table[][4] /* I */ +) +{ + opus_int i; + opus_int32 LTP_pred_Q13, LPC_pred_Q10, n_AR_Q12, n_LTP_Q13; + opus_int32 n_LF_Q12, r_Q10, q1_Q0, q1_Q10, q2_Q10; + opus_int32 exc_Q14, LPC_exc_Q14, xq_Q14, Gain_Q10; + opus_int32 tmp1, tmp2, sLF_AR_shp_Q14; + opus_int32 *psLPC_Q14, *shp_lag_ptr, *pred_lag_ptr; + + __m128i xmm_tempa, xmm_tempb; + + __m128i xmm_one; + + __m128i psLPC_Q14_hi_01234567, psLPC_Q14_hi_89ABCDEF; + __m128i psLPC_Q14_lo_01234567, psLPC_Q14_lo_89ABCDEF; + __m128i a_Q12_01234567, a_Q12_89ABCDEF; + + __m128i sAR2_Q14_hi_76543210, sAR2_Q14_lo_76543210; + __m128i AR_shp_Q13_76543210; + + shp_lag_ptr = &NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - lag + HARM_SHAPE_FIR_TAPS / 2 ]; + pred_lag_ptr = &sLTP_Q15[ NSQ->sLTP_buf_idx - lag + LTP_ORDER / 2 ]; + Gain_Q10 = silk_RSHIFT( Gain_Q16, 6 ); + + /* Set up short term AR state */ + psLPC_Q14 = &NSQ->sLPC_Q14[ NSQ_LPC_BUF_LENGTH - 1 ]; + + sLF_AR_shp_Q14 = NSQ->sLF_AR_shp_Q14; + xq_Q14 = psLPC_Q14[ 0 ]; + LTP_pred_Q13 = 0; + + /* load a_Q12 */ + xmm_one = _mm_set_epi8( 1, 0, 3, 2, 5, 4, 7, 6, 9, 8, 11, 10, 13, 12, 15, 14 ); + + /* load a_Q12[0] - a_Q12[7] */ + a_Q12_01234567 = _mm_loadu_si128( (__m128i *)(&a_Q12[ 0 ] ) ); + /* load a_Q12[ 8 ] - a_Q12[ 15 ] */ + a_Q12_89ABCDEF = _mm_loadu_si128( (__m128i *)(&a_Q12[ 8 ] ) ); + + a_Q12_01234567 = _mm_shuffle_epi8( a_Q12_01234567, xmm_one ); + a_Q12_89ABCDEF = _mm_shuffle_epi8( a_Q12_89ABCDEF, xmm_one ); + + /* load AR_shp_Q13 */ + AR_shp_Q13_76543210 = _mm_loadu_si128( (__m128i *)(&AR_shp_Q13[0] ) ); + + /* load psLPC_Q14 */ + xmm_one = _mm_set_epi8(15, 14, 11, 10, 7, 6, 3, 2, 13, 12, 9, 8, 5, 4, 1, 0 ); + + xmm_tempa = _mm_loadu_si128( (__m128i *)(&psLPC_Q14[-16]) ); + xmm_tempb = _mm_loadu_si128( (__m128i *)(&psLPC_Q14[-12]) ); + + xmm_tempa = _mm_shuffle_epi8( xmm_tempa, xmm_one ); + xmm_tempb = _mm_shuffle_epi8( xmm_tempb, xmm_one ); + + psLPC_Q14_hi_89ABCDEF = _mm_unpackhi_epi64( xmm_tempa, xmm_tempb ); + psLPC_Q14_lo_89ABCDEF = _mm_unpacklo_epi64( xmm_tempa, xmm_tempb ); + + xmm_tempa = _mm_loadu_si128( (__m128i *)(&psLPC_Q14[ -8 ]) ); + xmm_tempb = _mm_loadu_si128( (__m128i *)(&psLPC_Q14[ -4 ]) ); + + xmm_tempa = _mm_shuffle_epi8( xmm_tempa, xmm_one ); + xmm_tempb = _mm_shuffle_epi8( xmm_tempb, xmm_one ); + + psLPC_Q14_hi_01234567 = _mm_unpackhi_epi64( xmm_tempa, xmm_tempb ); + psLPC_Q14_lo_01234567 = _mm_unpacklo_epi64( xmm_tempa, xmm_tempb ); + + /* load sAR2_Q14 */ + xmm_tempa = _mm_loadu_si128( (__m128i *)(&(NSQ->sAR2_Q14[ 0 ]) ) ); + xmm_tempb = _mm_loadu_si128( (__m128i *)(&(NSQ->sAR2_Q14[ 4 ]) ) ); + + xmm_tempa = _mm_shuffle_epi8( xmm_tempa, xmm_one ); + xmm_tempb = _mm_shuffle_epi8( xmm_tempb, xmm_one ); + + sAR2_Q14_hi_76543210 = _mm_unpackhi_epi64( xmm_tempa, xmm_tempb ); + sAR2_Q14_lo_76543210 = _mm_unpacklo_epi64( xmm_tempa, xmm_tempb ); + + /* prepare 1 in 8 * 16bit */ + xmm_one = _mm_set1_epi16(1); + + for( i = 0; i < length; i++ ) + { + /* Short-term prediction */ + __m128i xmm_hi_07, xmm_hi_8F, xmm_lo_07, xmm_lo_8F; + + /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */ + LPC_pred_Q10 = 8; /* silk_RSHIFT( predictLPCOrder, 1 ); */ + + /* shift psLPC_Q14 */ + psLPC_Q14_hi_89ABCDEF = _mm_alignr_epi8( psLPC_Q14_hi_01234567, psLPC_Q14_hi_89ABCDEF, 2 ); + psLPC_Q14_lo_89ABCDEF = _mm_alignr_epi8( psLPC_Q14_lo_01234567, psLPC_Q14_lo_89ABCDEF, 2 ); + + psLPC_Q14_hi_01234567 = _mm_srli_si128( psLPC_Q14_hi_01234567, 2 ); + psLPC_Q14_lo_01234567 = _mm_srli_si128( psLPC_Q14_lo_01234567, 2 ); + + psLPC_Q14_hi_01234567 = _mm_insert_epi16( psLPC_Q14_hi_01234567, (xq_Q14 >> 16), 7 ); + psLPC_Q14_lo_01234567 = _mm_insert_epi16( psLPC_Q14_lo_01234567, (xq_Q14), 7 ); + + /* high part, use pmaddwd, results in 4 32-bit */ + xmm_hi_07 = _mm_madd_epi16( psLPC_Q14_hi_01234567, a_Q12_01234567 ); + xmm_hi_8F = _mm_madd_epi16( psLPC_Q14_hi_89ABCDEF, a_Q12_89ABCDEF ); + + /* low part, use pmulhw, results in 8 16-bit, note we need simulate unsigned * signed, _mm_srai_epi16(psLPC_Q14_lo_01234567, 15) */ + xmm_tempa = _mm_cmpgt_epi16( _mm_setzero_si128(), psLPC_Q14_lo_01234567 ); + xmm_tempb = _mm_cmpgt_epi16( _mm_setzero_si128(), psLPC_Q14_lo_89ABCDEF ); + + xmm_tempa = _mm_and_si128( xmm_tempa, a_Q12_01234567 ); + xmm_tempb = _mm_and_si128( xmm_tempb, a_Q12_89ABCDEF ); + + xmm_lo_07 = _mm_mulhi_epi16( psLPC_Q14_lo_01234567, a_Q12_01234567 ); + xmm_lo_8F = _mm_mulhi_epi16( psLPC_Q14_lo_89ABCDEF, a_Q12_89ABCDEF ); + + xmm_lo_07 = _mm_add_epi16( xmm_lo_07, xmm_tempa ); + xmm_lo_8F = _mm_add_epi16( xmm_lo_8F, xmm_tempb ); + + xmm_lo_07 = _mm_madd_epi16( xmm_lo_07, xmm_one ); + xmm_lo_8F = _mm_madd_epi16( xmm_lo_8F, xmm_one ); + + /* accumulate */ + xmm_hi_07 = _mm_add_epi32( xmm_hi_07, xmm_hi_8F ); + xmm_lo_07 = _mm_add_epi32( xmm_lo_07, xmm_lo_8F ); + + xmm_hi_07 = _mm_add_epi32( xmm_hi_07, xmm_lo_07 ); + + xmm_hi_07 = _mm_add_epi32( xmm_hi_07, _mm_unpackhi_epi64(xmm_hi_07, xmm_hi_07 ) ); + xmm_hi_07 = _mm_add_epi32( xmm_hi_07, _mm_shufflelo_epi16(xmm_hi_07, 0x0E ) ); + + LPC_pred_Q10 += _mm_cvtsi128_si32( xmm_hi_07 ); + + /* Long-term prediction */ + if ( opus_likely( signalType == TYPE_VOICED ) ) { + /* Unrolled loop */ + /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */ + LTP_pred_Q13 = 2; + { + __m128i b_Q14_3210, b_Q14_0123, pred_lag_ptr_0123; + + b_Q14_3210 = OP_CVTEPI16_EPI32_M64( b_Q14 ); + b_Q14_0123 = _mm_shuffle_epi32( b_Q14_3210, 0x1B ); + + /* loaded: [0] [-1] [-2] [-3] */ + pred_lag_ptr_0123 = _mm_loadu_si128( (__m128i *)(&pred_lag_ptr[ -3 ] ) ); + /* shuffle to [-3] [-2] [-1] [0] and to new xmm */ + xmm_tempa = _mm_shuffle_epi32( pred_lag_ptr_0123, 0x1B ); + /*64-bit multiply, a[2] * b[-2], a[0] * b[0] */ + xmm_tempa = _mm_mul_epi32( xmm_tempa, b_Q14_3210 ); + /* right shift 2 bytes (16 bits), zero extended */ + xmm_tempa = _mm_srli_si128( xmm_tempa, 2 ); + + /* a[1] * b[-1], a[3] * b[-3] */ + pred_lag_ptr_0123 = _mm_mul_epi32( pred_lag_ptr_0123, b_Q14_0123 ); + pred_lag_ptr_0123 = _mm_srli_si128( pred_lag_ptr_0123, 2 ); + + pred_lag_ptr_0123 = _mm_add_epi32( pred_lag_ptr_0123, xmm_tempa ); + /* equal shift right 8 bytes*/ + xmm_tempa = _mm_shuffle_epi32( pred_lag_ptr_0123, _MM_SHUFFLE( 0, 0, 3, 2 ) ); + xmm_tempa = _mm_add_epi32( xmm_tempa, pred_lag_ptr_0123 ); + + LTP_pred_Q13 += _mm_cvtsi128_si32( xmm_tempa ); + + LTP_pred_Q13 = silk_SMLAWB( LTP_pred_Q13, pred_lag_ptr[ -4 ], b_Q14[ 4 ] ); + pred_lag_ptr++; + } + } + + /* Noise shape feedback */ + NSQ->sAR2_Q14[ 9 ] = NSQ->sAR2_Q14[ 8 ]; + NSQ->sAR2_Q14[ 8 ] = _mm_cvtsi128_si32( _mm_srli_si128(_mm_unpackhi_epi16( sAR2_Q14_lo_76543210, sAR2_Q14_hi_76543210 ), 12 ) ); + + sAR2_Q14_hi_76543210 = _mm_slli_si128( sAR2_Q14_hi_76543210, 2 ); + sAR2_Q14_lo_76543210 = _mm_slli_si128( sAR2_Q14_lo_76543210, 2 ); + + sAR2_Q14_hi_76543210 = _mm_insert_epi16( sAR2_Q14_hi_76543210, (xq_Q14 >> 16), 0 ); + sAR2_Q14_lo_76543210 = _mm_insert_epi16( sAR2_Q14_lo_76543210, (xq_Q14), 0 ); + + /* high part, use pmaddwd, results in 4 32-bit */ + xmm_hi_07 = _mm_madd_epi16( sAR2_Q14_hi_76543210, AR_shp_Q13_76543210 ); + + /* low part, use pmulhw, results in 8 16-bit, note we need simulate unsigned * signed,_mm_srai_epi16(sAR2_Q14_lo_76543210, 15) */ + xmm_tempa = _mm_cmpgt_epi16( _mm_setzero_si128(), sAR2_Q14_lo_76543210 ); + xmm_tempa = _mm_and_si128( xmm_tempa, AR_shp_Q13_76543210 ); + + xmm_lo_07 = _mm_mulhi_epi16( sAR2_Q14_lo_76543210, AR_shp_Q13_76543210 ); + xmm_lo_07 = _mm_add_epi16( xmm_lo_07, xmm_tempa ); + + xmm_lo_07 = _mm_madd_epi16( xmm_lo_07, xmm_one ); + + /* accumulate */ + xmm_hi_07 = _mm_add_epi32( xmm_hi_07, xmm_lo_07 ); + + xmm_hi_07 = _mm_add_epi32( xmm_hi_07, _mm_unpackhi_epi64(xmm_hi_07, xmm_hi_07 ) ); + xmm_hi_07 = _mm_add_epi32( xmm_hi_07, _mm_shufflelo_epi16(xmm_hi_07, 0x0E ) ); + + n_AR_Q12 = 5 + _mm_cvtsi128_si32( xmm_hi_07 ); + + n_AR_Q12 = silk_SMLAWB( n_AR_Q12, NSQ->sAR2_Q14[ 8 ], AR_shp_Q13[ 8 ] ); + n_AR_Q12 = silk_SMLAWB( n_AR_Q12, NSQ->sAR2_Q14[ 9 ], AR_shp_Q13[ 9 ] ); + + n_AR_Q12 = silk_LSHIFT32( n_AR_Q12, 1 ); /* Q11 -> Q12 */ + n_AR_Q12 = silk_SMLAWB( n_AR_Q12, sLF_AR_shp_Q14, Tilt_Q14 ); + + n_LF_Q12 = silk_SMULWB( NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - 1 ], LF_shp_Q14 ); + n_LF_Q12 = silk_SMLAWT( n_LF_Q12, sLF_AR_shp_Q14, LF_shp_Q14 ); + + silk_assert( lag > 0 || signalType != TYPE_VOICED ); + + /* Combine prediction and noise shaping signals */ + tmp1 = silk_SUB32( silk_LSHIFT32( LPC_pred_Q10, 2 ), n_AR_Q12 ); /* Q12 */ + tmp1 = silk_SUB32( tmp1, n_LF_Q12 ); /* Q12 */ + if( lag > 0 ) { + /* Symmetric, packed FIR coefficients */ + n_LTP_Q13 = silk_SMULWB( silk_ADD32( shp_lag_ptr[ 0 ], shp_lag_ptr[ -2 ] ), HarmShapeFIRPacked_Q14 ); + n_LTP_Q13 = silk_SMLAWT( n_LTP_Q13, shp_lag_ptr[ -1 ], HarmShapeFIRPacked_Q14 ); + n_LTP_Q13 = silk_LSHIFT( n_LTP_Q13, 1 ); + shp_lag_ptr++; + + tmp2 = silk_SUB32( LTP_pred_Q13, n_LTP_Q13 ); /* Q13 */ + tmp1 = silk_ADD_LSHIFT32( tmp2, tmp1, 1 ); /* Q13 */ + tmp1 = silk_RSHIFT_ROUND( tmp1, 3 ); /* Q10 */ + } else { + tmp1 = silk_RSHIFT_ROUND( tmp1, 2 ); /* Q10 */ + } + + r_Q10 = silk_SUB32( x_sc_Q10[ i ], tmp1 ); /* residual error Q10 */ + + /* Generate dither */ + NSQ->rand_seed = silk_RAND( NSQ->rand_seed ); + + /* Flip sign depending on dither */ + tmp2 = -r_Q10; + if ( NSQ->rand_seed < 0 ) r_Q10 = tmp2; + + r_Q10 = silk_LIMIT_32( r_Q10, -(31 << 10), 30 << 10 ); + + /* Find two quantization level candidates and measure their rate-distortion */ + q1_Q10 = silk_SUB32( r_Q10, offset_Q10 ); + q1_Q0 = silk_RSHIFT( q1_Q10, 10 ); + + q1_Q10 = table[q1_Q0][0]; + q2_Q10 = table[q1_Q0][1]; + + if (r_Q10 * table[q1_Q0][2] - table[q1_Q0][3] < 0) + { + q1_Q10 = q2_Q10; + } + + pulses[ i ] = (opus_int8)silk_RSHIFT_ROUND( q1_Q10, 10 ); + + /* Excitation */ + exc_Q14 = silk_LSHIFT( q1_Q10, 4 ); + + tmp2 = -exc_Q14; + if ( NSQ->rand_seed < 0 ) exc_Q14 = tmp2; + + /* Add predictions */ + LPC_exc_Q14 = silk_ADD_LSHIFT32( exc_Q14, LTP_pred_Q13, 1 ); + xq_Q14 = silk_ADD_LSHIFT32( LPC_exc_Q14, LPC_pred_Q10, 4 ); + + /* Update states */ + psLPC_Q14++; + *psLPC_Q14 = xq_Q14; + sLF_AR_shp_Q14 = silk_SUB_LSHIFT32( xq_Q14, n_AR_Q12, 2 ); + + NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx ] = silk_SUB_LSHIFT32( sLF_AR_shp_Q14, n_LF_Q12, 2 ); + sLTP_Q15[ NSQ->sLTP_buf_idx ] = silk_LSHIFT( LPC_exc_Q14, 1 ); + NSQ->sLTP_shp_buf_idx++; + NSQ->sLTP_buf_idx++; + + /* Make dither dependent on quantized signal */ + NSQ->rand_seed = silk_ADD32_ovflw( NSQ->rand_seed, pulses[ i ] ); + } + + NSQ->sLF_AR_shp_Q14 = sLF_AR_shp_Q14; + + /* Scale XQ back to normal level before saving */ + psLPC_Q14 = &NSQ->sLPC_Q14[ NSQ_LPC_BUF_LENGTH ]; + + /* write back sAR2_Q14 */ + xmm_tempa = _mm_unpackhi_epi16( sAR2_Q14_lo_76543210, sAR2_Q14_hi_76543210 ); + xmm_tempb = _mm_unpacklo_epi16( sAR2_Q14_lo_76543210, sAR2_Q14_hi_76543210 ); + _mm_storeu_si128( (__m128i *)(&NSQ->sAR2_Q14[ 4 ]), xmm_tempa ); + _mm_storeu_si128( (__m128i *)(&NSQ->sAR2_Q14[ 0 ]), xmm_tempb ); + + /* xq[ i ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( silk_SMULWW( psLPC_Q14[ i ], Gain_Q10 ), 8 ) ); */ + { + __m128i xmm_Gain_Q10; + __m128i xmm_xq_Q14_3210, xmm_xq_Q14_x3x1, xmm_xq_Q14_7654, xmm_xq_Q14_x7x5; + + /* prepare (1 << 7) in packed 4 32-bits */ + xmm_tempa = _mm_set1_epi32( (1 << 7) ); + + /* prepare Gain_Q10 in packed 4 32-bits */ + xmm_Gain_Q10 = _mm_set1_epi32( Gain_Q10 ); + + /* process xq */ + for (i = 0; i < length - 7; i += 8) + { + xmm_xq_Q14_3210 = _mm_loadu_si128( (__m128i *)(&(psLPC_Q14[ i + 0 ] ) ) ); + xmm_xq_Q14_7654 = _mm_loadu_si128( (__m128i *)(&(psLPC_Q14[ i + 4 ] ) ) ); + + /* equal shift right 4 bytes*/ + xmm_xq_Q14_x3x1 = _mm_shuffle_epi32( xmm_xq_Q14_3210, _MM_SHUFFLE( 0, 3, 2, 1 ) ); + /* equal shift right 4 bytes*/ + xmm_xq_Q14_x7x5 = _mm_shuffle_epi32( xmm_xq_Q14_7654, _MM_SHUFFLE( 0, 3, 2, 1 ) ); + + xmm_xq_Q14_3210 = _mm_mul_epi32( xmm_xq_Q14_3210, xmm_Gain_Q10 ); + xmm_xq_Q14_x3x1 = _mm_mul_epi32( xmm_xq_Q14_x3x1, xmm_Gain_Q10 ); + xmm_xq_Q14_7654 = _mm_mul_epi32( xmm_xq_Q14_7654, xmm_Gain_Q10 ); + xmm_xq_Q14_x7x5 = _mm_mul_epi32( xmm_xq_Q14_x7x5, xmm_Gain_Q10 ); + + xmm_xq_Q14_3210 = _mm_srli_epi64( xmm_xq_Q14_3210, 16 ); + xmm_xq_Q14_x3x1 = _mm_slli_epi64( xmm_xq_Q14_x3x1, 16 ); + xmm_xq_Q14_7654 = _mm_srli_epi64( xmm_xq_Q14_7654, 16 ); + xmm_xq_Q14_x7x5 = _mm_slli_epi64( xmm_xq_Q14_x7x5, 16 ); + + xmm_xq_Q14_3210 = _mm_blend_epi16( xmm_xq_Q14_3210, xmm_xq_Q14_x3x1, 0xCC ); + xmm_xq_Q14_7654 = _mm_blend_epi16( xmm_xq_Q14_7654, xmm_xq_Q14_x7x5, 0xCC ); + + /* silk_RSHIFT_ROUND(xq, 8) */ + xmm_xq_Q14_3210 = _mm_add_epi32( xmm_xq_Q14_3210, xmm_tempa ); + xmm_xq_Q14_7654 = _mm_add_epi32( xmm_xq_Q14_7654, xmm_tempa ); + + xmm_xq_Q14_3210 = _mm_srai_epi32( xmm_xq_Q14_3210, 8 ); + xmm_xq_Q14_7654 = _mm_srai_epi32( xmm_xq_Q14_7654, 8 ); + + /* silk_SAT16 */ + xmm_xq_Q14_3210 = _mm_packs_epi32( xmm_xq_Q14_3210, xmm_xq_Q14_7654 ); + + /* save to xq */ + _mm_storeu_si128( (__m128i *)(&xq[ i ] ), xmm_xq_Q14_3210 ); + } + } + for ( ; i < length; i++) + { + xq[i] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( silk_SMULWW( psLPC_Q14[ i ], Gain_Q10 ), 8 ) ); + } + + /* Update LPC synth buffer */ + silk_memcpy( NSQ->sLPC_Q14, &NSQ->sLPC_Q14[ length ], NSQ_LPC_BUF_LENGTH * sizeof( opus_int32 ) ); +} + +static OPUS_INLINE void silk_nsq_scale_states_sse4_1( + const silk_encoder_state *psEncC, /* I Encoder State */ + silk_nsq_state *NSQ, /* I/O NSQ state */ + const opus_int32 x_Q3[], /* I input in Q3 */ + opus_int32 x_sc_Q10[], /* O input scaled with 1/Gain */ + const opus_int16 sLTP[], /* I re-whitened LTP state in Q0 */ + opus_int32 sLTP_Q15[], /* O LTP state matching scaled input */ + opus_int subfr, /* I subframe number */ + const opus_int LTP_scale_Q14, /* I */ + const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lag */ + const opus_int signal_type /* I Signal type */ +) +{ + opus_int i, lag; + opus_int32 gain_adj_Q16, inv_gain_Q31, inv_gain_Q23; + __m128i xmm_inv_gain_Q23, xmm_x_Q3_x2x0, xmm_x_Q3_x3x1; + + lag = pitchL[ subfr ]; + inv_gain_Q31 = silk_INVERSE32_varQ( silk_max( Gains_Q16[ subfr ], 1 ), 47 ); + silk_assert( inv_gain_Q31 != 0 ); + + /* Calculate gain adjustment factor */ + if( Gains_Q16[ subfr ] != NSQ->prev_gain_Q16 ) { + gain_adj_Q16 = silk_DIV32_varQ( NSQ->prev_gain_Q16, Gains_Q16[ subfr ], 16 ); + } else { + gain_adj_Q16 = (opus_int32)1 << 16; + } + + /* Scale input */ + inv_gain_Q23 = silk_RSHIFT_ROUND( inv_gain_Q31, 8 ); + + /* prepare inv_gain_Q23 in packed 4 32-bits */ + xmm_inv_gain_Q23 = _mm_set1_epi32(inv_gain_Q23); + + for( i = 0; i < psEncC->subfr_length - 3; i += 4 ) { + xmm_x_Q3_x2x0 = _mm_loadu_si128( (__m128i *)(&(x_Q3[ i ] ) ) ); + + /* equal shift right 4 bytes*/ + xmm_x_Q3_x3x1 = _mm_shuffle_epi32( xmm_x_Q3_x2x0, _MM_SHUFFLE( 0, 3, 2, 1 ) ); + + xmm_x_Q3_x2x0 = _mm_mul_epi32( xmm_x_Q3_x2x0, xmm_inv_gain_Q23 ); + xmm_x_Q3_x3x1 = _mm_mul_epi32( xmm_x_Q3_x3x1, xmm_inv_gain_Q23 ); + + xmm_x_Q3_x2x0 = _mm_srli_epi64( xmm_x_Q3_x2x0, 16 ); + xmm_x_Q3_x3x1 = _mm_slli_epi64( xmm_x_Q3_x3x1, 16 ); + + xmm_x_Q3_x2x0 = _mm_blend_epi16( xmm_x_Q3_x2x0, xmm_x_Q3_x3x1, 0xCC ); + + _mm_storeu_si128( (__m128i *)(&(x_sc_Q10[ i ] ) ), xmm_x_Q3_x2x0 ); + } + + for( ; i < psEncC->subfr_length; i++ ) { + x_sc_Q10[ i ] = silk_SMULWW( x_Q3[ i ], inv_gain_Q23 ); + } + + /* Save inverse gain */ + NSQ->prev_gain_Q16 = Gains_Q16[ subfr ]; + + /* After rewhitening the LTP state is un-scaled, so scale with inv_gain_Q16 */ + if( NSQ->rewhite_flag ) { + if( subfr == 0 ) { + /* Do LTP downscaling */ + inv_gain_Q31 = silk_LSHIFT( silk_SMULWB( inv_gain_Q31, LTP_scale_Q14 ), 2 ); + } + for( i = NSQ->sLTP_buf_idx - lag - LTP_ORDER / 2; i < NSQ->sLTP_buf_idx; i++ ) { + silk_assert( i < MAX_FRAME_LENGTH ); + sLTP_Q15[ i ] = silk_SMULWB( inv_gain_Q31, sLTP[ i ] ); + } + } + + /* Adjust for changing gain */ + if( gain_adj_Q16 != (opus_int32)1 << 16 ) { + /* Scale long-term shaping state */ + __m128i xmm_gain_adj_Q16, xmm_sLTP_shp_Q14_x2x0, xmm_sLTP_shp_Q14_x3x1; + + /* prepare gain_adj_Q16 in packed 4 32-bits */ + xmm_gain_adj_Q16 = _mm_set1_epi32(gain_adj_Q16); + + for( i = NSQ->sLTP_shp_buf_idx - psEncC->ltp_mem_length; i < NSQ->sLTP_shp_buf_idx - 3; i += 4 ) + { + xmm_sLTP_shp_Q14_x2x0 = _mm_loadu_si128( (__m128i *)(&(NSQ->sLTP_shp_Q14[ i ] ) ) ); + /* equal shift right 4 bytes*/ + xmm_sLTP_shp_Q14_x3x1 = _mm_shuffle_epi32( xmm_sLTP_shp_Q14_x2x0, _MM_SHUFFLE( 0, 3, 2, 1 ) ); + + xmm_sLTP_shp_Q14_x2x0 = _mm_mul_epi32( xmm_sLTP_shp_Q14_x2x0, xmm_gain_adj_Q16 ); + xmm_sLTP_shp_Q14_x3x1 = _mm_mul_epi32( xmm_sLTP_shp_Q14_x3x1, xmm_gain_adj_Q16 ); + + xmm_sLTP_shp_Q14_x2x0 = _mm_srli_epi64( xmm_sLTP_shp_Q14_x2x0, 16 ); + xmm_sLTP_shp_Q14_x3x1 = _mm_slli_epi64( xmm_sLTP_shp_Q14_x3x1, 16 ); + + xmm_sLTP_shp_Q14_x2x0 = _mm_blend_epi16( xmm_sLTP_shp_Q14_x2x0, xmm_sLTP_shp_Q14_x3x1, 0xCC ); + + _mm_storeu_si128( (__m128i *)(&(NSQ->sLTP_shp_Q14[ i ] ) ), xmm_sLTP_shp_Q14_x2x0 ); + } + + for( ; i < NSQ->sLTP_shp_buf_idx; i++ ) { + NSQ->sLTP_shp_Q14[ i ] = silk_SMULWW( gain_adj_Q16, NSQ->sLTP_shp_Q14[ i ] ); + } + + /* Scale long-term prediction state */ + if( signal_type == TYPE_VOICED && NSQ->rewhite_flag == 0 ) { + for( i = NSQ->sLTP_buf_idx - lag - LTP_ORDER / 2; i < NSQ->sLTP_buf_idx; i++ ) { + sLTP_Q15[ i ] = silk_SMULWW( gain_adj_Q16, sLTP_Q15[ i ] ); + } + } + + NSQ->sLF_AR_shp_Q14 = silk_SMULWW( gain_adj_Q16, NSQ->sLF_AR_shp_Q14 ); + + /* Scale short-term prediction and shaping states */ + for( i = 0; i < NSQ_LPC_BUF_LENGTH; i++ ) { + NSQ->sLPC_Q14[ i ] = silk_SMULWW( gain_adj_Q16, NSQ->sLPC_Q14[ i ] ); + } + for( i = 0; i < MAX_SHAPE_LPC_ORDER; i++ ) { + NSQ->sAR2_Q14[ i ] = silk_SMULWW( gain_adj_Q16, NSQ->sAR2_Q14[ i ] ); + } + } +} diff --git a/extern/opus/silk/x86/SigProc_FIX_sse.h b/extern/opus/silk/x86/SigProc_FIX_sse.h new file mode 100644 index 0000000..61efa8d --- /dev/null +++ b/extern/opus/silk/x86/SigProc_FIX_sse.h @@ -0,0 +1,94 @@ +/* Copyright (c) 2014, Cisco Systems, INC + Written by XiangMingZhu WeiZhou MinPeng YanWang + + 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. + + 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 OWNER + 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. +*/ + +#ifndef SIGPROC_FIX_SSE_H +#define SIGPROC_FIX_SSE_H + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#if defined(OPUS_X86_MAY_HAVE_SSE4_1) +void silk_burg_modified_sse4_1( + opus_int32 *res_nrg, /* O Residual energy */ + opus_int *res_nrg_Q, /* O Residual energy Q value */ + opus_int32 A_Q16[], /* O Prediction coefficients (length order) */ + const opus_int16 x[], /* I Input signal, length: nb_subfr * ( D + subfr_length ) */ + const opus_int32 minInvGain_Q30, /* I Inverse of max prediction gain */ + const opus_int subfr_length, /* I Input signal subframe length (incl. D preceding samples) */ + const opus_int nb_subfr, /* I Number of subframes stacked in x */ + const opus_int D, /* I Order */ + int arch /* I Run-time architecture */ +); + +#if defined(OPUS_X86_PRESUME_SSE4_1) +#define silk_burg_modified(res_nrg, res_nrg_Q, A_Q16, x, minInvGain_Q30, subfr_length, nb_subfr, D, arch) \ + ((void)(arch), silk_burg_modified_sse4_1(res_nrg, res_nrg_Q, A_Q16, x, minInvGain_Q30, subfr_length, nb_subfr, D, arch)) + +#else + +extern void (*const SILK_BURG_MODIFIED_IMPL[OPUS_ARCHMASK + 1])( + opus_int32 *res_nrg, /* O Residual energy */ + opus_int *res_nrg_Q, /* O Residual energy Q value */ + opus_int32 A_Q16[], /* O Prediction coefficients (length order) */ + const opus_int16 x[], /* I Input signal, length: nb_subfr * ( D + subfr_length ) */ + const opus_int32 minInvGain_Q30, /* I Inverse of max prediction gain */ + const opus_int subfr_length, /* I Input signal subframe length (incl. D preceding samples) */ + const opus_int nb_subfr, /* I Number of subframes stacked in x */ + const opus_int D, /* I Order */ + int arch /* I Run-time architecture */); + +# define silk_burg_modified(res_nrg, res_nrg_Q, A_Q16, x, minInvGain_Q30, subfr_length, nb_subfr, D, arch) \ + ((*SILK_BURG_MODIFIED_IMPL[(arch) & OPUS_ARCHMASK])(res_nrg, res_nrg_Q, A_Q16, x, minInvGain_Q30, subfr_length, nb_subfr, D, arch)) + +#endif + +opus_int64 silk_inner_prod16_aligned_64_sse4_1( + const opus_int16 *inVec1, + const opus_int16 *inVec2, + const opus_int len +); + + +#if defined(OPUS_X86_PRESUME_SSE4_1) + +#define silk_inner_prod16_aligned_64(inVec1, inVec2, len, arch) \ + ((void)(arch),silk_inner_prod16_aligned_64_sse4_1(inVec1, inVec2, len)) + +#else + +extern opus_int64 (*const SILK_INNER_PROD16_ALIGNED_64_IMPL[OPUS_ARCHMASK + 1])( + const opus_int16 *inVec1, + const opus_int16 *inVec2, + const opus_int len); + +# define silk_inner_prod16_aligned_64(inVec1, inVec2, len, arch) \ + ((*SILK_INNER_PROD16_ALIGNED_64_IMPL[(arch) & OPUS_ARCHMASK])(inVec1, inVec2, len)) + +#endif +#endif +#endif diff --git a/extern/opus/silk/x86/VAD_sse4_1.c b/extern/opus/silk/x86/VAD_sse4_1.c new file mode 100644 index 0000000..d02ddf4 --- /dev/null +++ b/extern/opus/silk/x86/VAD_sse4_1.c @@ -0,0 +1,277 @@ +/* Copyright (c) 2014, Cisco Systems, INC + Written by XiangMingZhu WeiZhou MinPeng YanWang + + 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. + + 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 OWNER + 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. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include + +#include "main.h" +#include "stack_alloc.h" + +/* Weighting factors for tilt measure */ +static const opus_int32 tiltWeights[ VAD_N_BANDS ] = { 30000, 6000, -12000, -12000 }; + +/***************************************/ +/* Get the speech activity level in Q8 */ +/***************************************/ +opus_int silk_VAD_GetSA_Q8_sse4_1( /* O Return value, 0 if success */ + silk_encoder_state *psEncC, /* I/O Encoder state */ + const opus_int16 pIn[] /* I PCM input */ +) +{ + opus_int SA_Q15, pSNR_dB_Q7, input_tilt; + opus_int decimated_framelength1, decimated_framelength2; + opus_int decimated_framelength; + opus_int dec_subframe_length, dec_subframe_offset, SNR_Q7, i, b, s; + opus_int32 sumSquared, smooth_coef_Q16; + opus_int16 HPstateTmp; + VARDECL( opus_int16, X ); + opus_int32 Xnrg[ VAD_N_BANDS ]; + opus_int32 NrgToNoiseRatio_Q8[ VAD_N_BANDS ]; + opus_int32 speech_nrg, x_tmp; + opus_int X_offset[ VAD_N_BANDS ]; + opus_int ret = 0; + silk_VAD_state *psSilk_VAD = &psEncC->sVAD; + + SAVE_STACK; + + /* Safety checks */ + silk_assert( VAD_N_BANDS == 4 ); + celt_assert( MAX_FRAME_LENGTH >= psEncC->frame_length ); + celt_assert( psEncC->frame_length <= 512 ); + celt_assert( psEncC->frame_length == 8 * silk_RSHIFT( psEncC->frame_length, 3 ) ); + + /***********************/ + /* Filter and Decimate */ + /***********************/ + decimated_framelength1 = silk_RSHIFT( psEncC->frame_length, 1 ); + decimated_framelength2 = silk_RSHIFT( psEncC->frame_length, 2 ); + decimated_framelength = silk_RSHIFT( psEncC->frame_length, 3 ); + /* Decimate into 4 bands: + 0 L 3L L 3L 5L + - -- - -- -- + 8 8 2 4 4 + + [0-1 kHz| temp. |1-2 kHz| 2-4 kHz | 4-8 kHz | + + They're arranged to allow the minimal ( frame_length / 4 ) extra + scratch space during the downsampling process */ + 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; + ALLOC( X, X_offset[ 3 ] + decimated_framelength1, opus_int16 ); + + /* 0-8 kHz to 0-4 kHz and 4-8 kHz */ + silk_ana_filt_bank_1( pIn, &psSilk_VAD->AnaState[ 0 ], + X, &X[ X_offset[ 3 ] ], psEncC->frame_length ); + + /* 0-4 kHz to 0-2 kHz and 2-4 kHz */ + silk_ana_filt_bank_1( X, &psSilk_VAD->AnaState1[ 0 ], + X, &X[ X_offset[ 2 ] ], decimated_framelength1 ); + + /* 0-2 kHz to 0-1 kHz and 1-2 kHz */ + silk_ana_filt_bank_1( X, &psSilk_VAD->AnaState2[ 0 ], + X, &X[ X_offset[ 1 ] ], decimated_framelength2 ); + + /*********************************************/ + /* HP filter on lowest band (differentiator) */ + /*********************************************/ + X[ decimated_framelength - 1 ] = silk_RSHIFT( X[ decimated_framelength - 1 ], 1 ); + HPstateTmp = X[ decimated_framelength - 1 ]; + for( i = decimated_framelength - 1; i > 0; i-- ) { + X[ i - 1 ] = silk_RSHIFT( X[ i - 1 ], 1 ); + X[ i ] -= X[ i - 1 ]; + } + X[ 0 ] -= psSilk_VAD->HPstate; + psSilk_VAD->HPstate = HPstateTmp; + + /*************************************/ + /* Calculate the energy in each band */ + /*************************************/ + for( b = 0; b < VAD_N_BANDS; b++ ) { + /* Find the decimated framelength in the non-uniformly divided bands */ + decimated_framelength = silk_RSHIFT( psEncC->frame_length, silk_min_int( VAD_N_BANDS - b, VAD_N_BANDS - 1 ) ); + + /* Split length into subframe lengths */ + dec_subframe_length = silk_RSHIFT( decimated_framelength, VAD_INTERNAL_SUBFRAMES_LOG2 ); + dec_subframe_offset = 0; + + /* Compute energy per sub-frame */ + /* initialize with summed energy of last subframe */ + Xnrg[ b ] = psSilk_VAD->XnrgSubfr[ b ]; + for( s = 0; s < VAD_INTERNAL_SUBFRAMES; s++ ) { + __m128i xmm_X, xmm_acc; + sumSquared = 0; + + xmm_acc = _mm_setzero_si128(); + + for( i = 0; i < dec_subframe_length - 7; i += 8 ) + { + xmm_X = _mm_loadu_si128( (__m128i *)&(X[ X_offset[ b ] + i + dec_subframe_offset ] ) ); + xmm_X = _mm_srai_epi16( xmm_X, 3 ); + xmm_X = _mm_madd_epi16( xmm_X, xmm_X ); + xmm_acc = _mm_add_epi32( xmm_acc, xmm_X ); + } + + xmm_acc = _mm_add_epi32( xmm_acc, _mm_unpackhi_epi64( xmm_acc, xmm_acc ) ); + xmm_acc = _mm_add_epi32( xmm_acc, _mm_shufflelo_epi16( xmm_acc, 0x0E ) ); + + sumSquared += _mm_cvtsi128_si32( xmm_acc ); + + for( ; i < dec_subframe_length; i++ ) { + /* The energy will be less than dec_subframe_length * ( silk_int16_MIN / 8 ) ^ 2. */ + /* Therefore we can accumulate with no risk of overflow (unless dec_subframe_length > 128) */ + x_tmp = silk_RSHIFT( + X[ X_offset[ b ] + i + dec_subframe_offset ], 3 ); + sumSquared = silk_SMLABB( sumSquared, x_tmp, x_tmp ); + + /* Safety check */ + silk_assert( sumSquared >= 0 ); + } + + /* Add/saturate summed energy of current subframe */ + if( s < VAD_INTERNAL_SUBFRAMES - 1 ) { + Xnrg[ b ] = silk_ADD_POS_SAT32( Xnrg[ b ], sumSquared ); + } else { + /* Look-ahead subframe */ + Xnrg[ b ] = silk_ADD_POS_SAT32( Xnrg[ b ], silk_RSHIFT( sumSquared, 1 ) ); + } + + dec_subframe_offset += dec_subframe_length; + } + psSilk_VAD->XnrgSubfr[ b ] = sumSquared; + } + + /********************/ + /* Noise estimation */ + /********************/ + silk_VAD_GetNoiseLevels( &Xnrg[ 0 ], psSilk_VAD ); + + /***********************************************/ + /* Signal-plus-noise to noise ratio estimation */ + /***********************************************/ + sumSquared = 0; + input_tilt = 0; + for( b = 0; b < VAD_N_BANDS; b++ ) { + speech_nrg = Xnrg[ b ] - psSilk_VAD->NL[ b ]; + if( speech_nrg > 0 ) { + /* Divide, with sufficient resolution */ + if( ( Xnrg[ b ] & 0xFF800000 ) == 0 ) { + NrgToNoiseRatio_Q8[ b ] = silk_DIV32( silk_LSHIFT( Xnrg[ b ], 8 ), psSilk_VAD->NL[ b ] + 1 ); + } else { + NrgToNoiseRatio_Q8[ b ] = silk_DIV32( Xnrg[ b ], silk_RSHIFT( psSilk_VAD->NL[ b ], 8 ) + 1 ); + } + + /* Convert to log domain */ + SNR_Q7 = silk_lin2log( NrgToNoiseRatio_Q8[ b ] ) - 8 * 128; + + /* Sum-of-squares */ + sumSquared = silk_SMLABB( sumSquared, SNR_Q7, SNR_Q7 ); /* Q14 */ + + /* Tilt measure */ + if( speech_nrg < ( (opus_int32)1 << 20 ) ) { + /* Scale down SNR value for small subband speech energies */ + SNR_Q7 = silk_SMULWB( silk_LSHIFT( silk_SQRT_APPROX( speech_nrg ), 6 ), SNR_Q7 ); + } + input_tilt = silk_SMLAWB( input_tilt, tiltWeights[ b ], SNR_Q7 ); + } else { + NrgToNoiseRatio_Q8[ b ] = 256; + } + } + + /* Mean-of-squares */ + sumSquared = silk_DIV32_16( sumSquared, VAD_N_BANDS ); /* Q14 */ + + /* Root-mean-square approximation, scale to dBs, and write to output pointer */ + pSNR_dB_Q7 = (opus_int16)( 3 * silk_SQRT_APPROX( sumSquared ) ); /* Q7 */ + + /*********************************/ + /* Speech Probability Estimation */ + /*********************************/ + SA_Q15 = silk_sigm_Q15( silk_SMULWB( VAD_SNR_FACTOR_Q16, pSNR_dB_Q7 ) - VAD_NEGATIVE_OFFSET_Q5 ); + + /**************************/ + /* Frequency Tilt Measure */ + /**************************/ + psEncC->input_tilt_Q15 = silk_LSHIFT( silk_sigm_Q15( input_tilt ) - 16384, 1 ); + + /**************************************************/ + /* Scale the sigmoid output based on power levels */ + /**************************************************/ + speech_nrg = 0; + for( b = 0; b < VAD_N_BANDS; b++ ) { + /* Accumulate signal-without-noise energies, higher frequency bands have more weight */ + speech_nrg += ( b + 1 ) * silk_RSHIFT( Xnrg[ b ] - psSilk_VAD->NL[ b ], 4 ); + } + + /* Power scaling */ + if( speech_nrg <= 0 ) { + SA_Q15 = silk_RSHIFT( SA_Q15, 1 ); + } else if( speech_nrg < 32768 ) { + if( psEncC->frame_length == 10 * psEncC->fs_kHz ) { + speech_nrg = silk_LSHIFT_SAT32( speech_nrg, 16 ); + } else { + speech_nrg = silk_LSHIFT_SAT32( speech_nrg, 15 ); + } + + /* square-root */ + speech_nrg = silk_SQRT_APPROX( speech_nrg ); + SA_Q15 = silk_SMULWB( 32768 + speech_nrg, SA_Q15 ); + } + + /* Copy the resulting speech activity in Q8 */ + psEncC->speech_activity_Q8 = silk_min_int( silk_RSHIFT( SA_Q15, 7 ), silk_uint8_MAX ); + + /***********************************/ + /* Energy Level and SNR estimation */ + /***********************************/ + /* Smoothing coefficient */ + smooth_coef_Q16 = silk_SMULWB( VAD_SNR_SMOOTH_COEF_Q18, silk_SMULWB( (opus_int32)SA_Q15, SA_Q15 ) ); + + if( psEncC->frame_length == 10 * psEncC->fs_kHz ) { + smooth_coef_Q16 >>= 1; + } + + for( b = 0; b < VAD_N_BANDS; b++ ) { + /* compute smoothed energy-to-noise ratio per band */ + psSilk_VAD->NrgRatioSmth_Q8[ b ] = silk_SMLAWB( psSilk_VAD->NrgRatioSmth_Q8[ b ], + NrgToNoiseRatio_Q8[ b ] - psSilk_VAD->NrgRatioSmth_Q8[ b ], smooth_coef_Q16 ); + + /* signal to noise ratio in dB per band */ + SNR_Q7 = 3 * ( silk_lin2log( psSilk_VAD->NrgRatioSmth_Q8[b] ) - 8 * 128 ); + /* quality = sigmoid( 0.25 * ( SNR_dB - 16 ) ); */ + psEncC->input_quality_bands_Q15[ b ] = silk_sigm_Q15( silk_RSHIFT( SNR_Q7 - 16 * 128, 4 ) ); + } + + RESTORE_STACK; + return( ret ); +} diff --git a/extern/opus/silk/x86/VQ_WMat_EC_sse4_1.c b/extern/opus/silk/x86/VQ_WMat_EC_sse4_1.c new file mode 100644 index 0000000..74d6c6d --- /dev/null +++ b/extern/opus/silk/x86/VQ_WMat_EC_sse4_1.c @@ -0,0 +1,142 @@ +/* Copyright (c) 2014, Cisco Systems, INC + Written by XiangMingZhu WeiZhou MinPeng YanWang + + 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. + + 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 OWNER + 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. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include "main.h" +#include "celt/x86/x86cpu.h" + +/* Entropy constrained matrix-weighted VQ, hard-coded to 5-element vectors, for a single input data vector */ +void silk_VQ_WMat_EC_sse4_1( + opus_int8 *ind, /* O index of best codebook vector */ + opus_int32 *rate_dist_Q14, /* O best weighted quant error + mu * rate */ + opus_int *gain_Q7, /* O sum of absolute LTP coefficients */ + const opus_int16 *in_Q14, /* I input vector to be quantized */ + const opus_int32 *W_Q18, /* I weighting matrix */ + const opus_int8 *cb_Q7, /* I codebook */ + const opus_uint8 *cb_gain_Q7, /* I codebook effective gain */ + const opus_uint8 *cl_Q5, /* I code length for each codebook vector */ + const opus_int mu_Q9, /* I tradeoff betw. weighted error and rate */ + const opus_int32 max_gain_Q7, /* I maximum sum of absolute LTP coefficients */ + opus_int L /* I number of vectors in codebook */ +) +{ + opus_int k, gain_tmp_Q7; + const opus_int8 *cb_row_Q7; + opus_int16 diff_Q14[ 5 ]; + opus_int32 sum1_Q14, sum2_Q16; + + __m128i C_tmp1, C_tmp2, C_tmp3, C_tmp4, C_tmp5; + /* Loop over codebook */ + *rate_dist_Q14 = silk_int32_MAX; + cb_row_Q7 = cb_Q7; + for( k = 0; k < L; k++ ) { + gain_tmp_Q7 = cb_gain_Q7[k]; + + diff_Q14[ 0 ] = in_Q14[ 0 ] - silk_LSHIFT( cb_row_Q7[ 0 ], 7 ); + + C_tmp1 = OP_CVTEPI16_EPI32_M64( &in_Q14[ 1 ] ); + C_tmp2 = OP_CVTEPI8_EPI32_M32( &cb_row_Q7[ 1 ] ); + C_tmp2 = _mm_slli_epi32( C_tmp2, 7 ); + C_tmp1 = _mm_sub_epi32( C_tmp1, C_tmp2 ); + + diff_Q14[ 1 ] = _mm_extract_epi16( C_tmp1, 0 ); + diff_Q14[ 2 ] = _mm_extract_epi16( C_tmp1, 2 ); + diff_Q14[ 3 ] = _mm_extract_epi16( C_tmp1, 4 ); + diff_Q14[ 4 ] = _mm_extract_epi16( C_tmp1, 6 ); + + /* Weighted rate */ + sum1_Q14 = silk_SMULBB( mu_Q9, cl_Q5[ k ] ); + + /* Penalty for too large gain */ + sum1_Q14 = silk_ADD_LSHIFT32( sum1_Q14, silk_max( silk_SUB32( gain_tmp_Q7, max_gain_Q7 ), 0 ), 10 ); + + silk_assert( sum1_Q14 >= 0 ); + + /* first row of W_Q18 */ + C_tmp3 = _mm_loadu_si128( (__m128i *)(&W_Q18[ 1 ] ) ); + C_tmp4 = _mm_mul_epi32( C_tmp3, C_tmp1 ); + C_tmp4 = _mm_srli_si128( C_tmp4, 2 ); + + C_tmp1 = _mm_shuffle_epi32( C_tmp1, _MM_SHUFFLE( 0, 3, 2, 1 ) ); /* shift right 4 bytes */ + C_tmp3 = _mm_shuffle_epi32( C_tmp3, _MM_SHUFFLE( 0, 3, 2, 1 ) ); /* shift right 4 bytes */ + + C_tmp5 = _mm_mul_epi32( C_tmp3, C_tmp1 ); + C_tmp5 = _mm_srli_si128( C_tmp5, 2 ); + + C_tmp5 = _mm_add_epi32( C_tmp4, C_tmp5 ); + C_tmp5 = _mm_slli_epi32( C_tmp5, 1 ); + + C_tmp5 = _mm_add_epi32( C_tmp5, _mm_shuffle_epi32( C_tmp5, _MM_SHUFFLE( 0, 0, 0, 2 ) ) ); + sum2_Q16 = _mm_cvtsi128_si32( C_tmp5 ); + + sum2_Q16 = silk_SMLAWB( sum2_Q16, W_Q18[ 0 ], diff_Q14[ 0 ] ); + sum1_Q14 = silk_SMLAWB( sum1_Q14, sum2_Q16, diff_Q14[ 0 ] ); + + /* second row of W_Q18 */ + sum2_Q16 = silk_SMULWB( W_Q18[ 7 ], diff_Q14[ 2 ] ); + sum2_Q16 = silk_SMLAWB( sum2_Q16, W_Q18[ 8 ], diff_Q14[ 3 ] ); + sum2_Q16 = silk_SMLAWB( sum2_Q16, W_Q18[ 9 ], diff_Q14[ 4 ] ); + sum2_Q16 = silk_LSHIFT( sum2_Q16, 1 ); + sum2_Q16 = silk_SMLAWB( sum2_Q16, W_Q18[ 6 ], diff_Q14[ 1 ] ); + sum1_Q14 = silk_SMLAWB( sum1_Q14, sum2_Q16, diff_Q14[ 1 ] ); + + /* third row of W_Q18 */ + sum2_Q16 = silk_SMULWB( W_Q18[ 13 ], diff_Q14[ 3 ] ); + sum2_Q16 = silk_SMLAWB( sum2_Q16, W_Q18[ 14 ], diff_Q14[ 4 ] ); + sum2_Q16 = silk_LSHIFT( sum2_Q16, 1 ); + sum2_Q16 = silk_SMLAWB( sum2_Q16, W_Q18[ 12 ], diff_Q14[ 2 ] ); + sum1_Q14 = silk_SMLAWB( sum1_Q14, sum2_Q16, diff_Q14[ 2 ] ); + + /* fourth row of W_Q18 */ + sum2_Q16 = silk_SMULWB( W_Q18[ 19 ], diff_Q14[ 4 ] ); + sum2_Q16 = silk_LSHIFT( sum2_Q16, 1 ); + sum2_Q16 = silk_SMLAWB( sum2_Q16, W_Q18[ 18 ], diff_Q14[ 3 ] ); + sum1_Q14 = silk_SMLAWB( sum1_Q14, sum2_Q16, diff_Q14[ 3 ] ); + + /* last row of W_Q18 */ + sum2_Q16 = silk_SMULWB( W_Q18[ 24 ], diff_Q14[ 4 ] ); + sum1_Q14 = silk_SMLAWB( sum1_Q14, sum2_Q16, diff_Q14[ 4 ] ); + + silk_assert( sum1_Q14 >= 0 ); + + /* find best */ + if( sum1_Q14 < *rate_dist_Q14 ) { + *rate_dist_Q14 = sum1_Q14; + *ind = (opus_int8)k; + *gain_Q7 = gain_tmp_Q7; + } + + /* Go to next cbk vector */ + cb_row_Q7 += LTP_ORDER; + } +} diff --git a/extern/opus/silk/x86/main_sse.h b/extern/opus/silk/x86/main_sse.h new file mode 100644 index 0000000..2f15d44 --- /dev/null +++ b/extern/opus/silk/x86/main_sse.h @@ -0,0 +1,248 @@ +/* Copyright (c) 2014, Cisco Systems, INC + Written by XiangMingZhu WeiZhou MinPeng YanWang + + 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. + + 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 OWNER + 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. +*/ + +#ifndef MAIN_SSE_H +#define MAIN_SSE_H + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +# if defined(OPUS_X86_MAY_HAVE_SSE4_1) + +#if 0 /* FIXME: SSE disabled until silk_VQ_WMat_EC_sse4_1() gets updated. */ +# define OVERRIDE_silk_VQ_WMat_EC + +void silk_VQ_WMat_EC_sse4_1( + opus_int8 *ind, /* O index of best codebook vector */ + opus_int32 *rate_dist_Q14, /* O best weighted quant error + mu * rate */ + opus_int *gain_Q7, /* O sum of absolute LTP coefficients */ + const opus_int16 *in_Q14, /* I input vector to be quantized */ + const opus_int32 *W_Q18, /* I weighting matrix */ + const opus_int8 *cb_Q7, /* I codebook */ + const opus_uint8 *cb_gain_Q7, /* I codebook effective gain */ + const opus_uint8 *cl_Q5, /* I code length for each codebook vector */ + const opus_int mu_Q9, /* I tradeoff betw. weighted error and rate */ + const opus_int32 max_gain_Q7, /* I maximum sum of absolute LTP coefficients */ + opus_int L /* I number of vectors in codebook */ +); + +#if defined OPUS_X86_PRESUME_SSE4_1 + +#define silk_VQ_WMat_EC(ind, rate_dist_Q14, gain_Q7, in_Q14, W_Q18, cb_Q7, cb_gain_Q7, cl_Q5, \ + mu_Q9, max_gain_Q7, L, arch) \ + ((void)(arch),silk_VQ_WMat_EC_sse4_1(ind, rate_dist_Q14, gain_Q7, in_Q14, W_Q18, cb_Q7, cb_gain_Q7, cl_Q5, \ + mu_Q9, max_gain_Q7, L)) + +#else + +extern void (*const SILK_VQ_WMAT_EC_IMPL[OPUS_ARCHMASK + 1])( + opus_int8 *ind, /* O index of best codebook vector */ + opus_int32 *rate_dist_Q14, /* O best weighted quant error + mu * rate */ + opus_int *gain_Q7, /* O sum of absolute LTP coefficients */ + const opus_int16 *in_Q14, /* I input vector to be quantized */ + const opus_int32 *W_Q18, /* I weighting matrix */ + const opus_int8 *cb_Q7, /* I codebook */ + const opus_uint8 *cb_gain_Q7, /* I codebook effective gain */ + const opus_uint8 *cl_Q5, /* I code length for each codebook vector */ + const opus_int mu_Q9, /* I tradeoff betw. weighted error and rate */ + const opus_int32 max_gain_Q7, /* I maximum sum of absolute LTP coefficients */ + opus_int L /* I number of vectors in codebook */ +); + +# define silk_VQ_WMat_EC(ind, rate_dist_Q14, gain_Q7, in_Q14, W_Q18, cb_Q7, cb_gain_Q7, cl_Q5, \ + mu_Q9, max_gain_Q7, L, arch) \ + ((*SILK_VQ_WMAT_EC_IMPL[(arch) & OPUS_ARCHMASK])(ind, rate_dist_Q14, gain_Q7, in_Q14, W_Q18, cb_Q7, cb_gain_Q7, cl_Q5, \ + mu_Q9, max_gain_Q7, L)) + +#endif +#endif + +#if 0 /* FIXME: SSE disabled until the NSQ code gets updated. */ +# define OVERRIDE_silk_NSQ + +void silk_NSQ_sse4_1( + const silk_encoder_state *psEncC, /* I Encoder State */ + silk_nsq_state *NSQ, /* I/O NSQ state */ + SideInfoIndices *psIndices, /* I/O Quantization Indices */ + const opus_int32 x_Q3[], /* I Prefiltered input signal */ + opus_int8 pulses[], /* O Quantized pulse signal */ + const opus_int16 PredCoef_Q12[ 2 * MAX_LPC_ORDER ], /* I Short term prediction coefs */ + const opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ], /* I Long term prediction coefs */ + const opus_int16 AR2_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ], /* I Noise shaping coefs */ + const opus_int HarmShapeGain_Q14[ MAX_NB_SUBFR ], /* I Long term shaping coefs */ + const opus_int Tilt_Q14[ MAX_NB_SUBFR ], /* I Spectral tilt */ + const opus_int32 LF_shp_Q14[ MAX_NB_SUBFR ], /* I Low frequency shaping coefs */ + const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I Quantization step sizes */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lags */ + const opus_int Lambda_Q10, /* I Rate/distortion tradeoff */ + const opus_int LTP_scale_Q14 /* I LTP state scaling */ +); + +#if defined OPUS_X86_PRESUME_SSE4_1 + +#define silk_NSQ(psEncC, NSQ, psIndices, x_Q3, pulses, PredCoef_Q12, LTPCoef_Q14, AR2_Q13, \ + HarmShapeGain_Q14, Tilt_Q14, LF_shp_Q14, Gains_Q16, pitchL, Lambda_Q10, LTP_scale_Q14, arch) \ + ((void)(arch),silk_NSQ_sse4_1(psEncC, NSQ, psIndices, x_Q3, pulses, PredCoef_Q12, LTPCoef_Q14, AR2_Q13, \ + HarmShapeGain_Q14, Tilt_Q14, LF_shp_Q14, Gains_Q16, pitchL, Lambda_Q10, LTP_scale_Q14)) + +#else + +extern void (*const SILK_NSQ_IMPL[OPUS_ARCHMASK + 1])( + const silk_encoder_state *psEncC, /* I Encoder State */ + silk_nsq_state *NSQ, /* I/O NSQ state */ + SideInfoIndices *psIndices, /* I/O Quantization Indices */ + const opus_int32 x_Q3[], /* I Prefiltered input signal */ + opus_int8 pulses[], /* O Quantized pulse signal */ + const opus_int16 PredCoef_Q12[ 2 * MAX_LPC_ORDER ], /* I Short term prediction coefs */ + const opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ], /* I Long term prediction coefs */ + const opus_int16 AR2_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ], /* I Noise shaping coefs */ + const opus_int HarmShapeGain_Q14[ MAX_NB_SUBFR ], /* I Long term shaping coefs */ + const opus_int Tilt_Q14[ MAX_NB_SUBFR ], /* I Spectral tilt */ + const opus_int32 LF_shp_Q14[ MAX_NB_SUBFR ], /* I Low frequency shaping coefs */ + const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I Quantization step sizes */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lags */ + const opus_int Lambda_Q10, /* I Rate/distortion tradeoff */ + const opus_int LTP_scale_Q14 /* I LTP state scaling */ +); + +# define silk_NSQ(psEncC, NSQ, psIndices, x_Q3, pulses, PredCoef_Q12, LTPCoef_Q14, AR2_Q13, \ + HarmShapeGain_Q14, Tilt_Q14, LF_shp_Q14, Gains_Q16, pitchL, Lambda_Q10, LTP_scale_Q14, arch) \ + ((*SILK_NSQ_IMPL[(arch) & OPUS_ARCHMASK])(psEncC, NSQ, psIndices, x_Q3, pulses, PredCoef_Q12, LTPCoef_Q14, AR2_Q13, \ + HarmShapeGain_Q14, Tilt_Q14, LF_shp_Q14, Gains_Q16, pitchL, Lambda_Q10, LTP_scale_Q14)) + +#endif + +# define OVERRIDE_silk_NSQ_del_dec + +void silk_NSQ_del_dec_sse4_1( + const silk_encoder_state *psEncC, /* I Encoder State */ + silk_nsq_state *NSQ, /* I/O NSQ state */ + SideInfoIndices *psIndices, /* I/O Quantization Indices */ + const opus_int32 x_Q3[], /* I Prefiltered input signal */ + opus_int8 pulses[], /* O Quantized pulse signal */ + const opus_int16 PredCoef_Q12[ 2 * MAX_LPC_ORDER ], /* I Short term prediction coefs */ + const opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ], /* I Long term prediction coefs */ + const opus_int16 AR2_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ], /* I Noise shaping coefs */ + const opus_int HarmShapeGain_Q14[ MAX_NB_SUBFR ], /* I Long term shaping coefs */ + const opus_int Tilt_Q14[ MAX_NB_SUBFR ], /* I Spectral tilt */ + const opus_int32 LF_shp_Q14[ MAX_NB_SUBFR ], /* I Low frequency shaping coefs */ + const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I Quantization step sizes */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lags */ + const opus_int Lambda_Q10, /* I Rate/distortion tradeoff */ + const opus_int LTP_scale_Q14 /* I LTP state scaling */ +); + +#if defined OPUS_X86_PRESUME_SSE4_1 + +#define silk_NSQ_del_dec(psEncC, NSQ, psIndices, x_Q3, pulses, PredCoef_Q12, LTPCoef_Q14, AR2_Q13, \ + HarmShapeGain_Q14, Tilt_Q14, LF_shp_Q14, Gains_Q16, pitchL, Lambda_Q10, LTP_scale_Q14, arch) \ + ((void)(arch),silk_NSQ_del_dec_sse4_1(psEncC, NSQ, psIndices, x_Q3, pulses, PredCoef_Q12, LTPCoef_Q14, AR2_Q13, \ + HarmShapeGain_Q14, Tilt_Q14, LF_shp_Q14, Gains_Q16, pitchL, Lambda_Q10, LTP_scale_Q14)) + +#else + +extern void (*const SILK_NSQ_DEL_DEC_IMPL[OPUS_ARCHMASK + 1])( + const silk_encoder_state *psEncC, /* I Encoder State */ + silk_nsq_state *NSQ, /* I/O NSQ state */ + SideInfoIndices *psIndices, /* I/O Quantization Indices */ + const opus_int32 x_Q3[], /* I Prefiltered input signal */ + opus_int8 pulses[], /* O Quantized pulse signal */ + const opus_int16 PredCoef_Q12[ 2 * MAX_LPC_ORDER ], /* I Short term prediction coefs */ + const opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ], /* I Long term prediction coefs */ + const opus_int16 AR2_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ], /* I Noise shaping coefs */ + const opus_int HarmShapeGain_Q14[ MAX_NB_SUBFR ], /* I Long term shaping coefs */ + const opus_int Tilt_Q14[ MAX_NB_SUBFR ], /* I Spectral tilt */ + const opus_int32 LF_shp_Q14[ MAX_NB_SUBFR ], /* I Low frequency shaping coefs */ + const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I Quantization step sizes */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lags */ + const opus_int Lambda_Q10, /* I Rate/distortion tradeoff */ + const opus_int LTP_scale_Q14 /* I LTP state scaling */ +); + +# define silk_NSQ_del_dec(psEncC, NSQ, psIndices, x_Q3, pulses, PredCoef_Q12, LTPCoef_Q14, AR2_Q13, \ + HarmShapeGain_Q14, Tilt_Q14, LF_shp_Q14, Gains_Q16, pitchL, Lambda_Q10, LTP_scale_Q14, arch) \ + ((*SILK_NSQ_DEL_DEC_IMPL[(arch) & OPUS_ARCHMASK])(psEncC, NSQ, psIndices, x_Q3, pulses, PredCoef_Q12, LTPCoef_Q14, AR2_Q13, \ + HarmShapeGain_Q14, Tilt_Q14, LF_shp_Q14, Gains_Q16, pitchL, Lambda_Q10, LTP_scale_Q14)) + +#endif +#endif + +void silk_noise_shape_quantizer( + silk_nsq_state *NSQ, /* I/O NSQ state */ + opus_int signalType, /* I Signal type */ + const opus_int32 x_sc_Q10[], /* I */ + opus_int8 pulses[], /* O */ + opus_int16 xq[], /* O */ + opus_int32 sLTP_Q15[], /* I/O LTP state */ + const opus_int16 a_Q12[], /* I Short term prediction coefs */ + const opus_int16 b_Q14[], /* I Long term prediction coefs */ + const opus_int16 AR_shp_Q13[], /* I Noise shaping AR coefs */ + opus_int lag, /* I Pitch lag */ + opus_int32 HarmShapeFIRPacked_Q14, /* I */ + opus_int Tilt_Q14, /* I Spectral tilt */ + opus_int32 LF_shp_Q14, /* I */ + opus_int32 Gain_Q16, /* I */ + opus_int Lambda_Q10, /* I */ + opus_int offset_Q10, /* I */ + opus_int length, /* I Input length */ + opus_int shapingLPCOrder, /* I Noise shaping AR filter order */ + opus_int predictLPCOrder, /* I Prediction filter order */ + int arch /* I Architecture */ +); + +/**************************/ +/* Noise level estimation */ +/**************************/ +void silk_VAD_GetNoiseLevels( + const opus_int32 pX[ VAD_N_BANDS ], /* I subband energies */ + silk_VAD_state *psSilk_VAD /* I/O Pointer to Silk VAD state */ +); + +# define OVERRIDE_silk_VAD_GetSA_Q8 + +opus_int silk_VAD_GetSA_Q8_sse4_1( + silk_encoder_state *psEnC, + const opus_int16 pIn[] +); + +#if defined(OPUS_X86_PRESUME_SSE4_1) +#define silk_VAD_GetSA_Q8(psEnC, pIn, arch) ((void)(arch),silk_VAD_GetSA_Q8_sse4_1(psEnC, pIn)) + +#else + +# define silk_VAD_GetSA_Q8(psEnC, pIn, arch) \ + ((*SILK_VAD_GETSA_Q8_IMPL[(arch) & OPUS_ARCHMASK])(psEnC, pIn)) + +extern opus_int (*const SILK_VAD_GETSA_Q8_IMPL[OPUS_ARCHMASK + 1])( + silk_encoder_state *psEnC, + const opus_int16 pIn[]); + +#endif + +# endif +#endif diff --git a/extern/opus/silk/x86/x86_silk_map.c b/extern/opus/silk/x86/x86_silk_map.c new file mode 100644 index 0000000..32dcc3c --- /dev/null +++ b/extern/opus/silk/x86/x86_silk_map.c @@ -0,0 +1,164 @@ +/* Copyright (c) 2014, Cisco Systems, INC + Written by XiangMingZhu WeiZhou MinPeng YanWang + + 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. + + 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 OWNER + 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. +*/ + +#if defined(HAVE_CONFIG_H) +#include "config.h" +#endif + +#include "celt/x86/x86cpu.h" +#include "structs.h" +#include "SigProc_FIX.h" +#include "pitch.h" +#include "main.h" + +#if !defined(OPUS_X86_PRESUME_SSE4_1) + +#if defined(FIXED_POINT) + +#include "fixed/main_FIX.h" + +opus_int64 (*const SILK_INNER_PROD16_ALIGNED_64_IMPL[ OPUS_ARCHMASK + 1 ] )( + const opus_int16 *inVec1, + const opus_int16 *inVec2, + const opus_int len +) = { + silk_inner_prod16_aligned_64_c, /* non-sse */ + silk_inner_prod16_aligned_64_c, + silk_inner_prod16_aligned_64_c, + MAY_HAVE_SSE4_1( silk_inner_prod16_aligned_64 ), /* sse4.1 */ + MAY_HAVE_SSE4_1( silk_inner_prod16_aligned_64 ) /* avx */ +}; + +#endif + +opus_int (*const SILK_VAD_GETSA_Q8_IMPL[ OPUS_ARCHMASK + 1 ] )( + silk_encoder_state *psEncC, + const opus_int16 pIn[] +) = { + silk_VAD_GetSA_Q8_c, /* non-sse */ + silk_VAD_GetSA_Q8_c, + silk_VAD_GetSA_Q8_c, + MAY_HAVE_SSE4_1( silk_VAD_GetSA_Q8 ), /* sse4.1 */ + MAY_HAVE_SSE4_1( silk_VAD_GetSA_Q8 ) /* avx */ +}; + +#if 0 /* FIXME: SSE disabled until the NSQ code gets updated. */ +void (*const SILK_NSQ_IMPL[ OPUS_ARCHMASK + 1 ] )( + const silk_encoder_state *psEncC, /* I Encoder State */ + silk_nsq_state *NSQ, /* I/O NSQ state */ + SideInfoIndices *psIndices, /* I/O Quantization Indices */ + const opus_int32 x_Q3[], /* I Prefiltered input signal */ + opus_int8 pulses[], /* O Quantized pulse signal */ + const opus_int16 PredCoef_Q12[ 2 * MAX_LPC_ORDER ], /* I Short term prediction coefs */ + const opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ], /* I Long term prediction coefs */ + const opus_int16 AR2_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ], /* I Noise shaping coefs */ + const opus_int HarmShapeGain_Q14[ MAX_NB_SUBFR ], /* I Long term shaping coefs */ + const opus_int Tilt_Q14[ MAX_NB_SUBFR ], /* I Spectral tilt */ + const opus_int32 LF_shp_Q14[ MAX_NB_SUBFR ], /* I Low frequency shaping coefs */ + const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I Quantization step sizes */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lags */ + const opus_int Lambda_Q10, /* I Rate/distortion tradeoff */ + const opus_int LTP_scale_Q14 /* I LTP state scaling */ +) = { + silk_NSQ_c, /* non-sse */ + silk_NSQ_c, + silk_NSQ_c, + MAY_HAVE_SSE4_1( silk_NSQ ), /* sse4.1 */ + MAY_HAVE_SSE4_1( silk_NSQ ) /* avx */ +}; +#endif + +#if 0 /* FIXME: SSE disabled until silk_VQ_WMat_EC_sse4_1() gets updated. */ +void (*const SILK_VQ_WMAT_EC_IMPL[ OPUS_ARCHMASK + 1 ] )( + opus_int8 *ind, /* O index of best codebook vector */ + opus_int32 *rate_dist_Q14, /* O best weighted quant error + mu * rate */ + opus_int *gain_Q7, /* O sum of absolute LTP coefficients */ + const opus_int16 *in_Q14, /* I input vector to be quantized */ + const opus_int32 *W_Q18, /* I weighting matrix */ + const opus_int8 *cb_Q7, /* I codebook */ + const opus_uint8 *cb_gain_Q7, /* I codebook effective gain */ + const opus_uint8 *cl_Q5, /* I code length for each codebook vector */ + const opus_int mu_Q9, /* I tradeoff betw. weighted error and rate */ + const opus_int32 max_gain_Q7, /* I maximum sum of absolute LTP coefficients */ + opus_int L /* I number of vectors in codebook */ +) = { + silk_VQ_WMat_EC_c, /* non-sse */ + silk_VQ_WMat_EC_c, + silk_VQ_WMat_EC_c, + MAY_HAVE_SSE4_1( silk_VQ_WMat_EC ), /* sse4.1 */ + MAY_HAVE_SSE4_1( silk_VQ_WMat_EC ) /* avx */ +}; +#endif + +#if 0 /* FIXME: SSE disabled until the NSQ code gets updated. */ +void (*const SILK_NSQ_DEL_DEC_IMPL[ OPUS_ARCHMASK + 1 ] )( + const silk_encoder_state *psEncC, /* I Encoder State */ + silk_nsq_state *NSQ, /* I/O NSQ state */ + SideInfoIndices *psIndices, /* I/O Quantization Indices */ + const opus_int32 x_Q3[], /* I Prefiltered input signal */ + opus_int8 pulses[], /* O Quantized pulse signal */ + const opus_int16 PredCoef_Q12[ 2 * MAX_LPC_ORDER ], /* I Short term prediction coefs */ + const opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ], /* I Long term prediction coefs */ + const opus_int16 AR2_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ], /* I Noise shaping coefs */ + const opus_int HarmShapeGain_Q14[ MAX_NB_SUBFR ], /* I Long term shaping coefs */ + const opus_int Tilt_Q14[ MAX_NB_SUBFR ], /* I Spectral tilt */ + const opus_int32 LF_shp_Q14[ MAX_NB_SUBFR ], /* I Low frequency shaping coefs */ + const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I Quantization step sizes */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lags */ + const opus_int Lambda_Q10, /* I Rate/distortion tradeoff */ + const opus_int LTP_scale_Q14 /* I LTP state scaling */ +) = { + silk_NSQ_del_dec_c, /* non-sse */ + silk_NSQ_del_dec_c, + silk_NSQ_del_dec_c, + MAY_HAVE_SSE4_1( silk_NSQ_del_dec ), /* sse4.1 */ + MAY_HAVE_SSE4_1( silk_NSQ_del_dec ) /* avx */ +}; +#endif + +#if defined(FIXED_POINT) + +void (*const SILK_BURG_MODIFIED_IMPL[ OPUS_ARCHMASK + 1 ] )( + opus_int32 *res_nrg, /* O Residual energy */ + opus_int *res_nrg_Q, /* O Residual energy Q value */ + opus_int32 A_Q16[], /* O Prediction coefficients (length order) */ + const opus_int16 x[], /* I Input signal, length: nb_subfr * ( D + subfr_length ) */ + const opus_int32 minInvGain_Q30, /* I Inverse of max prediction gain */ + const opus_int subfr_length, /* I Input signal subframe length (incl. D preceding samples) */ + const opus_int nb_subfr, /* I Number of subframes stacked in x */ + const opus_int D, /* I Order */ + int arch /* I Run-time architecture */ +) = { + silk_burg_modified_c, /* non-sse */ + silk_burg_modified_c, + silk_burg_modified_c, + MAY_HAVE_SSE4_1( silk_burg_modified ), /* sse4.1 */ + MAY_HAVE_SSE4_1( silk_burg_modified ) /* avx */ +}; + +#endif +#endif diff --git a/extern/opus/silk_headers.mk b/extern/opus/silk_headers.mk new file mode 100644 index 0000000..2588067 --- /dev/null +++ b/extern/opus/silk_headers.mk @@ -0,0 +1,44 @@ +SILK_HEAD = \ +silk/debug.h \ +silk/control.h \ +silk/errors.h \ +silk/API.h \ +silk/typedef.h \ +silk/define.h \ +silk/main.h \ +silk/x86/main_sse.h \ +silk/PLC.h \ +silk/structs.h \ +silk/tables.h \ +silk/tuning_parameters.h \ +silk/Inlines.h \ +silk/MacroCount.h \ +silk/MacroDebug.h \ +silk/macros.h \ +silk/NSQ.h \ +silk/pitch_est_defines.h \ +silk/resampler_private.h \ +silk/resampler_rom.h \ +silk/resampler_structs.h \ +silk/SigProc_FIX.h \ +silk/x86/SigProc_FIX_sse.h \ +silk/arm/biquad_alt_arm.h \ +silk/arm/LPC_inv_pred_gain_arm.h \ +silk/arm/macros_armv4.h \ +silk/arm/macros_armv5e.h \ +silk/arm/macros_arm64.h \ +silk/arm/SigProc_FIX_armv4.h \ +silk/arm/SigProc_FIX_armv5e.h \ +silk/arm/NSQ_del_dec_arm.h \ +silk/arm/NSQ_neon.h \ +silk/fixed/main_FIX.h \ +silk/fixed/structs_FIX.h \ +silk/fixed/arm/warped_autocorrelation_FIX_arm.h \ +silk/fixed/mips/noise_shape_analysis_FIX_mipsr1.h \ +silk/fixed/mips/warped_autocorrelation_FIX_mipsr1.h \ +silk/float/main_FLP.h \ +silk/float/structs_FLP.h \ +silk/float/SigProc_FLP.h \ +silk/mips/macros_mipsr1.h \ +silk/mips/NSQ_del_dec_mipsr1.h \ +silk/mips/sigproc_fix_mipsr1.h diff --git a/extern/opus/silk_sources.mk b/extern/opus/silk_sources.mk new file mode 100644 index 0000000..d2666e6 --- /dev/null +++ b/extern/opus/silk_sources.mk @@ -0,0 +1,154 @@ +SILK_SOURCES = \ +silk/CNG.c \ +silk/code_signs.c \ +silk/init_decoder.c \ +silk/decode_core.c \ +silk/decode_frame.c \ +silk/decode_parameters.c \ +silk/decode_indices.c \ +silk/decode_pulses.c \ +silk/decoder_set_fs.c \ +silk/dec_API.c \ +silk/enc_API.c \ +silk/encode_indices.c \ +silk/encode_pulses.c \ +silk/gain_quant.c \ +silk/interpolate.c \ +silk/LP_variable_cutoff.c \ +silk/NLSF_decode.c \ +silk/NSQ.c \ +silk/NSQ_del_dec.c \ +silk/PLC.c \ +silk/shell_coder.c \ +silk/tables_gain.c \ +silk/tables_LTP.c \ +silk/tables_NLSF_CB_NB_MB.c \ +silk/tables_NLSF_CB_WB.c \ +silk/tables_other.c \ +silk/tables_pitch_lag.c \ +silk/tables_pulses_per_block.c \ +silk/VAD.c \ +silk/control_audio_bandwidth.c \ +silk/quant_LTP_gains.c \ +silk/VQ_WMat_EC.c \ +silk/HP_variable_cutoff.c \ +silk/NLSF_encode.c \ +silk/NLSF_VQ.c \ +silk/NLSF_unpack.c \ +silk/NLSF_del_dec_quant.c \ +silk/process_NLSFs.c \ +silk/stereo_LR_to_MS.c \ +silk/stereo_MS_to_LR.c \ +silk/check_control_input.c \ +silk/control_SNR.c \ +silk/init_encoder.c \ +silk/control_codec.c \ +silk/A2NLSF.c \ +silk/ana_filt_bank_1.c \ +silk/biquad_alt.c \ +silk/bwexpander_32.c \ +silk/bwexpander.c \ +silk/debug.c \ +silk/decode_pitch.c \ +silk/inner_prod_aligned.c \ +silk/lin2log.c \ +silk/log2lin.c \ +silk/LPC_analysis_filter.c \ +silk/LPC_inv_pred_gain.c \ +silk/table_LSF_cos.c \ +silk/NLSF2A.c \ +silk/NLSF_stabilize.c \ +silk/NLSF_VQ_weights_laroia.c \ +silk/pitch_est_tables.c \ +silk/resampler.c \ +silk/resampler_down2_3.c \ +silk/resampler_down2.c \ +silk/resampler_private_AR2.c \ +silk/resampler_private_down_FIR.c \ +silk/resampler_private_IIR_FIR.c \ +silk/resampler_private_up2_HQ.c \ +silk/resampler_rom.c \ +silk/sigm_Q15.c \ +silk/sort.c \ +silk/sum_sqr_shift.c \ +silk/stereo_decode_pred.c \ +silk/stereo_encode_pred.c \ +silk/stereo_find_predictor.c \ +silk/stereo_quant_pred.c \ +silk/LPC_fit.c + +SILK_SOURCES_SSE4_1 = \ +silk/x86/NSQ_sse4_1.c \ +silk/x86/NSQ_del_dec_sse4_1.c \ +silk/x86/x86_silk_map.c \ +silk/x86/VAD_sse4_1.c \ +silk/x86/VQ_WMat_EC_sse4_1.c + +SILK_SOURCES_ARM_NEON_INTR = \ +silk/arm/arm_silk_map.c \ +silk/arm/biquad_alt_neon_intr.c \ +silk/arm/LPC_inv_pred_gain_neon_intr.c \ +silk/arm/NSQ_del_dec_neon_intr.c \ +silk/arm/NSQ_neon.c + +SILK_SOURCES_FIXED = \ +silk/fixed/LTP_analysis_filter_FIX.c \ +silk/fixed/LTP_scale_ctrl_FIX.c \ +silk/fixed/corrMatrix_FIX.c \ +silk/fixed/encode_frame_FIX.c \ +silk/fixed/find_LPC_FIX.c \ +silk/fixed/find_LTP_FIX.c \ +silk/fixed/find_pitch_lags_FIX.c \ +silk/fixed/find_pred_coefs_FIX.c \ +silk/fixed/noise_shape_analysis_FIX.c \ +silk/fixed/process_gains_FIX.c \ +silk/fixed/regularize_correlations_FIX.c \ +silk/fixed/residual_energy16_FIX.c \ +silk/fixed/residual_energy_FIX.c \ +silk/fixed/warped_autocorrelation_FIX.c \ +silk/fixed/apply_sine_window_FIX.c \ +silk/fixed/autocorr_FIX.c \ +silk/fixed/burg_modified_FIX.c \ +silk/fixed/k2a_FIX.c \ +silk/fixed/k2a_Q16_FIX.c \ +silk/fixed/pitch_analysis_core_FIX.c \ +silk/fixed/vector_ops_FIX.c \ +silk/fixed/schur64_FIX.c \ +silk/fixed/schur_FIX.c + +SILK_SOURCES_FIXED_SSE4_1 = \ +silk/fixed/x86/vector_ops_FIX_sse4_1.c \ +silk/fixed/x86/burg_modified_FIX_sse4_1.c + +SILK_SOURCES_FIXED_ARM_NEON_INTR = \ +silk/fixed/arm/warped_autocorrelation_FIX_neon_intr.c + +SILK_SOURCES_FLOAT = \ +silk/float/apply_sine_window_FLP.c \ +silk/float/corrMatrix_FLP.c \ +silk/float/encode_frame_FLP.c \ +silk/float/find_LPC_FLP.c \ +silk/float/find_LTP_FLP.c \ +silk/float/find_pitch_lags_FLP.c \ +silk/float/find_pred_coefs_FLP.c \ +silk/float/LPC_analysis_filter_FLP.c \ +silk/float/LTP_analysis_filter_FLP.c \ +silk/float/LTP_scale_ctrl_FLP.c \ +silk/float/noise_shape_analysis_FLP.c \ +silk/float/process_gains_FLP.c \ +silk/float/regularize_correlations_FLP.c \ +silk/float/residual_energy_FLP.c \ +silk/float/warped_autocorrelation_FLP.c \ +silk/float/wrappers_FLP.c \ +silk/float/autocorrelation_FLP.c \ +silk/float/burg_modified_FLP.c \ +silk/float/bwexpander_FLP.c \ +silk/float/energy_FLP.c \ +silk/float/inner_product_FLP.c \ +silk/float/k2a_FLP.c \ +silk/float/LPC_inv_pred_gain_FLP.c \ +silk/float/pitch_analysis_core_FLP.c \ +silk/float/scale_copy_vector_FLP.c \ +silk/float/scale_vector_FLP.c \ +silk/float/schur_FLP.c \ +silk/float/sort_FLP.c diff --git a/extern/opus/src/analysis.c b/extern/opus/src/analysis.c new file mode 100644 index 0000000..cb46dec --- /dev/null +++ b/extern/opus/src/analysis.c @@ -0,0 +1,981 @@ +/* Copyright (c) 2011 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + 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. + + 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 FOUNDATION 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. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#define ANALYSIS_C + +#include + +#include "mathops.h" +#include "kiss_fft.h" +#include "celt.h" +#include "modes.h" +#include "arch.h" +#include "quant_bands.h" +#include "analysis.h" +#include "mlp.h" +#include "stack_alloc.h" +#include "float_cast.h" + +#ifndef M_PI +#define M_PI 3.141592653 +#endif + +#ifndef DISABLE_FLOAT_API + +#define TRANSITION_PENALTY 10 + +static const float dct_table[128] = { + 0.250000f, 0.250000f, 0.250000f, 0.250000f, 0.250000f, 0.250000f, 0.250000f, 0.250000f, + 0.250000f, 0.250000f, 0.250000f, 0.250000f, 0.250000f, 0.250000f, 0.250000f, 0.250000f, + 0.351851f, 0.338330f, 0.311806f, 0.273300f, 0.224292f, 0.166664f, 0.102631f, 0.034654f, + -0.034654f,-0.102631f,-0.166664f,-0.224292f,-0.273300f,-0.311806f,-0.338330f,-0.351851f, + 0.346760f, 0.293969f, 0.196424f, 0.068975f,-0.068975f,-0.196424f,-0.293969f,-0.346760f, + -0.346760f,-0.293969f,-0.196424f,-0.068975f, 0.068975f, 0.196424f, 0.293969f, 0.346760f, + 0.338330f, 0.224292f, 0.034654f,-0.166664f,-0.311806f,-0.351851f,-0.273300f,-0.102631f, + 0.102631f, 0.273300f, 0.351851f, 0.311806f, 0.166664f,-0.034654f,-0.224292f,-0.338330f, + 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.273300f,-0.338330f,-0.102631f, 0.224292f, 0.351851f, 0.166664f, + -0.166664f,-0.351851f,-0.224292f, 0.102631f, 0.338330f, 0.273300f,-0.034654f,-0.311806f, + 0.293969f,-0.068975f,-0.346760f,-0.196424f, 0.196424f, 0.346760f, 0.068975f,-0.293969f, + -0.293969f, 0.068975f, 0.346760f, 0.196424f,-0.196424f,-0.346760f,-0.068975f, 0.293969f, + 0.273300f,-0.166664f,-0.338330f, 0.034654f, 0.351851f, 0.102631f,-0.311806f,-0.224292f, + 0.224292f, 0.311806f,-0.102631f,-0.351851f,-0.034654f, 0.338330f, 0.166664f,-0.273300f, +}; + +static const float analysis_window[240] = { + 0.000043f, 0.000171f, 0.000385f, 0.000685f, 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.020590f, 0.022490f, 0.024472f, + 0.026535f, 0.028679f, 0.030904f, 0.033210f, 0.035595f, 0.038060f, 0.040604f, 0.043227f, + 0.045928f, 0.048707f, 0.051564f, 0.054497f, 0.057506f, 0.060591f, 0.063752f, 0.066987f, + 0.070297f, 0.073680f, 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.124080f, 0.128428f, + 0.132839f, 0.137313f, 0.141849f, 0.146447f, 0.151105f, 0.155823f, 0.160600f, 0.165435f, + 0.170327f, 0.175276f, 0.180280f, 0.185340f, 0.190453f, 0.195619f, 0.200838f, 0.206107f, + 0.211427f, 0.216797f, 0.222215f, 0.227680f, 0.233193f, 0.238751f, 0.244353f, 0.250000f, + 0.255689f, 0.261421f, 0.267193f, 0.273005f, 0.278856f, 0.284744f, 0.290670f, 0.296632f, + 0.302628f, 0.308658f, 0.314721f, 0.320816f, 0.326941f, 0.333097f, 0.339280f, 0.345492f, + 0.351729f, 0.357992f, 0.364280f, 0.370590f, 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.460770f, 0.467298f, 0.473832f, 0.480370f, 0.486912f, 0.493455f, 0.500000f, + 0.506545f, 0.513088f, 0.519630f, 0.526168f, 0.532702f, 0.539230f, 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.629410f, 0.635720f, 0.642008f, 0.648271f, 0.654508f, + 0.660720f, 0.666903f, 0.673059f, 0.679184f, 0.685279f, 0.691342f, 0.697372f, 0.703368f, + 0.709330f, 0.715256f, 0.721144f, 0.726995f, 0.732807f, 0.738579f, 0.744311f, 0.750000f, + 0.755647f, 0.761249f, 0.766807f, 0.772320f, 0.777785f, 0.783203f, 0.788573f, 0.793893f, + 0.799162f, 0.804381f, 0.809547f, 0.814660f, 0.819720f, 0.824724f, 0.829673f, 0.834565f, + 0.839400f, 0.844177f, 0.848895f, 0.853553f, 0.858151f, 0.862687f, 0.867161f, 0.871572f, + 0.875920f, 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.926320f, 0.929703f, 0.933013f, + 0.936248f, 0.939409f, 0.942494f, 0.945503f, 0.948436f, 0.951293f, 0.954072f, 0.956773f, + 0.959396f, 0.961940f, 0.964405f, 0.966790f, 0.969096f, 0.971321f, 0.973465f, 0.975528f, + 0.977510f, 0.979410f, 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.000000f, +}; + +static const int tbands[NB_TBANDS+1] = { + 4, 8, 12, 16, 20, 24, 28, 32, 40, 48, 56, 64, 80, 96, 112, 136, 160, 192, 240 +}; + +#define NB_TONAL_SKIP_BANDS 9 + +static opus_val32 silk_resampler_down2_hp( + opus_val32 *S, /* I/O State vector [ 2 ] */ + opus_val32 *out, /* O Output signal [ floor(len/2) ] */ + const opus_val32 *in, /* I Input signal [ len ] */ + int inLen /* I Number of input samples */ +) +{ + int k, len2 = inLen/2; + opus_val32 in32, out32, out32_hp, Y, X; + opus_val64 hp_ener = 0; + /* Internal variables and state are in Q10 format */ + for( k = 0; k < len2; k++ ) { + /* Convert to Q10 */ + in32 = in[ 2 * k ]; + + /* All-pass section for even input sample */ + Y = SUB32( in32, S[ 0 ] ); + X = MULT16_32_Q15(QCONST16(0.6074371f, 15), Y); + out32 = ADD32( S[ 0 ], X ); + S[ 0 ] = ADD32( in32, X ); + out32_hp = out32; + /* Convert to Q10 */ + in32 = in[ 2 * k + 1 ]; + + /* All-pass section for odd input sample, and add to output of previous section */ + Y = SUB32( in32, S[ 1 ] ); + X = MULT16_32_Q15(QCONST16(0.15063f, 15), Y); + out32 = ADD32( out32, S[ 1 ] ); + out32 = ADD32( out32, X ); + S[ 1 ] = ADD32( in32, X ); + + Y = SUB32( -in32, S[ 2 ] ); + X = MULT16_32_Q15(QCONST16(0.15063f, 15), Y); + out32_hp = ADD32( out32_hp, S[ 2 ] ); + out32_hp = ADD32( out32_hp, X ); + S[ 2 ] = ADD32( -in32, X ); + + hp_ener += out32_hp*(opus_val64)out32_hp; + /* Add, convert back to int16 and store to output */ + out[ k ] = HALF32(out32); + } +#ifdef FIXED_POINT + /* len2 can be up to 480, so we shift by 8 more to make it fit. */ + hp_ener = hp_ener >> (2*SIG_SHIFT + 8); +#endif + return (opus_val32)hp_ener; +} + +static opus_val32 downmix_and_resample(downmix_func downmix, const void *_x, opus_val32 *y, opus_val32 S[3], int subframe, int offset, int c1, int c2, int C, int Fs) +{ + VARDECL(opus_val32, tmp); + opus_val32 scale; + int j; + opus_val32 ret = 0; + SAVE_STACK; + + if (subframe==0) return 0; + if (Fs == 48000) + { + subframe *= 2; + offset *= 2; + } else if (Fs == 16000) { + subframe = subframe*2/3; + offset = offset*2/3; + } + ALLOC(tmp, subframe, opus_val32); + + downmix(_x, tmp, subframe, offset, c1, c2, C); +#ifdef FIXED_POINT + scale = (1<-1) + scale /= 2; + for (j=0;jarch = opus_select_arch(); + tonal->Fs = Fs; + /* Clear remaining fields. */ + tonality_analysis_reset(tonal); +} + +void tonality_analysis_reset(TonalityAnalysisState *tonal) +{ + /* Clear non-reusable fields. */ + char *start = (char*)&tonal->TONALITY_ANALYSIS_RESET_START; + OPUS_CLEAR(start, sizeof(TonalityAnalysisState) - (start - (char*)tonal)); +} + +void tonality_get_info(TonalityAnalysisState *tonal, AnalysisInfo *info_out, int len) +{ + int pos; + int curr_lookahead; + float tonality_max; + float tonality_avg; + int tonality_count; + int i; + int pos0; + float prob_avg; + float prob_count; + float prob_min, prob_max; + float vad_prob; + int mpos, vpos; + int bandwidth_span; + + pos = tonal->read_pos; + curr_lookahead = tonal->write_pos-tonal->read_pos; + if (curr_lookahead<0) + curr_lookahead += DETECT_SIZE; + + tonal->read_subframe += len/(tonal->Fs/400); + while (tonal->read_subframe>=8) + { + tonal->read_subframe -= 8; + tonal->read_pos++; + } + if (tonal->read_pos>=DETECT_SIZE) + tonal->read_pos-=DETECT_SIZE; + + /* On long frames, look at the second analysis window rather than the first. */ + if (len > tonal->Fs/50 && pos != tonal->write_pos) + { + pos++; + if (pos==DETECT_SIZE) + pos=0; + } + if (pos == tonal->write_pos) + pos--; + if (pos<0) + pos = DETECT_SIZE-1; + pos0 = pos; + OPUS_COPY(info_out, &tonal->info[pos], 1); + if (!info_out->valid) + return; + tonality_max = tonality_avg = info_out->tonality; + tonality_count = 1; + /* Look at the neighbouring frames and pick largest bandwidth found (to be safe). */ + bandwidth_span = 6; + /* If possible, look ahead for a tone to compensate for the delay in the tone detector. */ + for (i=0;i<3;i++) + { + pos++; + if (pos==DETECT_SIZE) + pos = 0; + if (pos == tonal->write_pos) + break; + tonality_max = MAX32(tonality_max, tonal->info[pos].tonality); + tonality_avg += tonal->info[pos].tonality; + tonality_count++; + info_out->bandwidth = IMAX(info_out->bandwidth, tonal->info[pos].bandwidth); + bandwidth_span--; + } + pos = pos0; + /* Look back in time to see if any has a wider bandwidth than the current frame. */ + for (i=0;iwrite_pos) + break; + info_out->bandwidth = IMAX(info_out->bandwidth, tonal->info[pos].bandwidth); + } + info_out->tonality = MAX32(tonality_avg/tonality_count, tonality_max-.2f); + + mpos = vpos = pos0; + /* If we have enough look-ahead, compensate for the ~5-frame delay in the music prob and + ~1 frame delay in the VAD prob. */ + if (curr_lookahead > 15) + { + mpos += 5; + if (mpos>=DETECT_SIZE) + mpos -= DETECT_SIZE; + vpos += 1; + if (vpos>=DETECT_SIZE) + vpos -= DETECT_SIZE; + } + + /* The following calculations attempt to minimize a "badness function" + for the transition. When switching from speech to music, the badness + of switching at frame k is + b_k = S*v_k + \sum_{i=0}^{k-1} v_i*(p_i - T) + where + v_i is the activity probability (VAD) at frame i, + p_i is the music probability at frame i + T is the probability threshold for switching + S is the penalty for switching during active audio rather than silence + the current frame has index i=0 + + Rather than apply badness to directly decide when to switch, what we compute + instead is the threshold for which the optimal switching point is now. When + considering whether to switch now (frame 0) or at frame k, we have: + S*v_0 = S*v_k + \sum_{i=0}^{k-1} v_i*(p_i - T) + which gives us: + T = ( \sum_{i=0}^{k-1} v_i*p_i + S*(v_k-v_0) ) / ( \sum_{i=0}^{k-1} v_i ) + We take the min threshold across all positive values of k (up to the maximum + amount of lookahead we have) to give us the threshold for which the current + frame is the optimal switch point. + + The last step is that we need to consider whether we want to switch at all. + For that we use the average of the music probability over the entire window. + If the threshold is higher than that average we're not going to + switch, so we compute a min with the average as well. The result of all these + min operations is music_prob_min, which gives the threshold for switching to music + if we're currently encoding for speech. + + We do the exact opposite to compute music_prob_max which is used for switching + from music to speech. + */ + prob_min = 1.f; + prob_max = 0.f; + vad_prob = tonal->info[vpos].activity_probability; + prob_count = MAX16(.1f, vad_prob); + prob_avg = MAX16(.1f, vad_prob)*tonal->info[mpos].music_prob; + while (1) + { + float pos_vad; + mpos++; + if (mpos==DETECT_SIZE) + mpos = 0; + if (mpos == tonal->write_pos) + break; + vpos++; + if (vpos==DETECT_SIZE) + vpos = 0; + if (vpos == tonal->write_pos) + break; + pos_vad = tonal->info[vpos].activity_probability; + prob_min = MIN16((prob_avg - TRANSITION_PENALTY*(vad_prob - pos_vad))/prob_count, prob_min); + prob_max = MAX16((prob_avg + TRANSITION_PENALTY*(vad_prob - pos_vad))/prob_count, prob_max); + prob_count += MAX16(.1f, pos_vad); + prob_avg += MAX16(.1f, pos_vad)*tonal->info[mpos].music_prob; + } + info_out->music_prob = prob_avg/prob_count; + prob_min = MIN16(prob_avg/prob_count, prob_min); + prob_max = MAX16(prob_avg/prob_count, prob_max); + prob_min = MAX16(prob_min, 0.f); + prob_max = MIN16(prob_max, 1.f); + + /* If we don't have enough look-ahead, do our best to make a decent decision. */ + if (curr_lookahead < 10) + { + float pmin, pmax; + pmin = prob_min; + pmax = prob_max; + pos = pos0; + /* Look for min/max in the past. */ + for (i=0;icount-1, 15);i++) + { + pos--; + if (pos < 0) + pos = DETECT_SIZE-1; + pmin = MIN16(pmin, tonal->info[pos].music_prob); + pmax = MAX16(pmax, tonal->info[pos].music_prob); + } + /* Bias against switching on active audio. */ + pmin = MAX16(0.f, pmin - .1f*vad_prob); + pmax = MIN16(1.f, pmax + .1f*vad_prob); + prob_min += (1.f-.1f*curr_lookahead)*(pmin - prob_min); + prob_max += (1.f-.1f*curr_lookahead)*(pmax - prob_max); + } + info_out->music_prob_min = prob_min; + info_out->music_prob_max = prob_max; + + /* printf("%f %f %f %f %f\n", prob_min, prob_max, prob_avg/prob_count, vad_prob, info_out->music_prob); */ +} + +static const float std_feature_bias[9] = { + 5.684947f, 3.475288f, 1.770634f, 1.599784f, 3.773215f, + 2.163313f, 1.260756f, 1.116868f, 1.918795f +}; + +#define LEAKAGE_OFFSET 2.5f +#define LEAKAGE_SLOPE 2.f + +#ifdef FIXED_POINT +/* For fixed-point, the input is +/-2^15 shifted up by SIG_SHIFT, so we need to + compensate for that in the energy. */ +#define SCALE_COMPENS (1.f/((opus_int32)1<<(15+SIG_SHIFT))) +#define SCALE_ENER(e) ((SCALE_COMPENS*SCALE_COMPENS)*(e)) +#else +#define SCALE_ENER(e) (e) +#endif + +#ifdef FIXED_POINT +static int is_digital_silence32(const opus_val32* pcm, int frame_size, int channels, int lsb_depth) +{ + int silence = 0; + opus_val32 sample_max = 0; +#ifdef MLP_TRAINING + return 0; +#endif + sample_max = celt_maxabs32(pcm, frame_size*channels); + + silence = (sample_max == 0); + (void)lsb_depth; + return silence; +} +#else +#define is_digital_silence32(pcm, frame_size, channels, lsb_depth) is_digital_silence(pcm, frame_size, channels, lsb_depth) +#endif + +static void tonality_analysis(TonalityAnalysisState *tonal, const CELTMode *celt_mode, const void *x, int len, int offset, int c1, int c2, int C, int lsb_depth, downmix_func downmix) +{ + int i, b; + const kiss_fft_state *kfft; + VARDECL(kiss_fft_cpx, in); + VARDECL(kiss_fft_cpx, out); + int N = 480, N2=240; + float * OPUS_RESTRICT A = tonal->angle; + float * OPUS_RESTRICT dA = tonal->d_angle; + float * OPUS_RESTRICT d2A = tonal->d2_angle; + VARDECL(float, tonality); + VARDECL(float, noisiness); + float band_tonality[NB_TBANDS]; + float logE[NB_TBANDS]; + float BFCC[8]; + float features[25]; + float frame_tonality; + float max_frame_tonality; + /*float tw_sum=0;*/ + float frame_noisiness; + const float pi4 = (float)(M_PI*M_PI*M_PI*M_PI); + float slope=0; + float frame_stationarity; + float relativeE; + float frame_probs[2]; + float alpha, alphaE, alphaE2; + float frame_loudness; + float bandwidth_mask; + int is_masked[NB_TBANDS+1]; + int bandwidth=0; + float maxE = 0; + float noise_floor; + int remaining; + AnalysisInfo *info; + float hp_ener; + float tonality2[240]; + float midE[8]; + float spec_variability=0; + float band_log2[NB_TBANDS+1]; + float leakage_from[NB_TBANDS+1]; + float leakage_to[NB_TBANDS+1]; + float layer_out[MAX_NEURONS]; + float below_max_pitch; + float above_max_pitch; + int is_silence; + SAVE_STACK; + + if (!tonal->initialized) + { + tonal->mem_fill = 240; + tonal->initialized = 1; + } + alpha = 1.f/IMIN(10, 1+tonal->count); + alphaE = 1.f/IMIN(25, 1+tonal->count); + /* Noise floor related decay for bandwidth detection: -2.2 dB/second */ + alphaE2 = 1.f/IMIN(100, 1+tonal->count); + if (tonal->count <= 1) alphaE2 = 1; + + if (tonal->Fs == 48000) + { + /* len and offset are now at 24 kHz. */ + len/= 2; + offset /= 2; + } else if (tonal->Fs == 16000) { + len = 3*len/2; + offset = 3*offset/2; + } + + kfft = celt_mode->mdct.kfft[0]; + tonal->hp_ener_accum += (float)downmix_and_resample(downmix, x, + &tonal->inmem[tonal->mem_fill], tonal->downmix_state, + IMIN(len, ANALYSIS_BUF_SIZE-tonal->mem_fill), offset, c1, c2, C, tonal->Fs); + if (tonal->mem_fill+len < ANALYSIS_BUF_SIZE) + { + tonal->mem_fill += len; + /* Don't have enough to update the analysis */ + RESTORE_STACK; + return; + } + hp_ener = tonal->hp_ener_accum; + info = &tonal->info[tonal->write_pos++]; + if (tonal->write_pos>=DETECT_SIZE) + tonal->write_pos-=DETECT_SIZE; + + is_silence = is_digital_silence32(tonal->inmem, ANALYSIS_BUF_SIZE, 1, lsb_depth); + + ALLOC(in, 480, kiss_fft_cpx); + ALLOC(out, 480, kiss_fft_cpx); + ALLOC(tonality, 240, float); + ALLOC(noisiness, 240, float); + for (i=0;iinmem[i]); + in[i].i = (kiss_fft_scalar)(w*tonal->inmem[N2+i]); + in[N-i-1].r = (kiss_fft_scalar)(w*tonal->inmem[N-i-1]); + in[N-i-1].i = (kiss_fft_scalar)(w*tonal->inmem[N+N2-i-1]); + } + OPUS_MOVE(tonal->inmem, tonal->inmem+ANALYSIS_BUF_SIZE-240, 240); + remaining = len - (ANALYSIS_BUF_SIZE-tonal->mem_fill); + tonal->hp_ener_accum = (float)downmix_and_resample(downmix, x, + &tonal->inmem[240], tonal->downmix_state, remaining, + offset+ANALYSIS_BUF_SIZE-tonal->mem_fill, c1, c2, C, tonal->Fs); + tonal->mem_fill = 240 + remaining; + if (is_silence) + { + /* On silence, copy the previous analysis. */ + int prev_pos = tonal->write_pos-2; + if (prev_pos < 0) + prev_pos += DETECT_SIZE; + OPUS_COPY(info, &tonal->info[prev_pos], 1); + RESTORE_STACK; + return; + } + opus_fft(kfft, in, out, tonal->arch); +#ifndef FIXED_POINT + /* If there's any NaN on the input, the entire output will be NaN, so we only need to check one value. */ + if (celt_isnan(out[0].r)) + { + info->valid = 0; + RESTORE_STACK; + return; + } +#endif + + for (i=1;iactivity = 0; + frame_noisiness = 0; + frame_stationarity = 0; + if (!tonal->count) + { + for (b=0;blowE[b] = 1e10; + tonal->highE[b] = -1e10; + } + } + relativeE = 0; + frame_loudness = 0; + /* The energy of the very first band is special because of DC. */ + { + float E = 0; + float X1r, X2r; + X1r = 2*(float)out[0].r; + X2r = 2*(float)out[0].i; + E = X1r*X1r + X2r*X2r; + for (i=1;i<4;i++) + { + float binE = out[i].r*(float)out[i].r + out[N-i].r*(float)out[N-i].r + + out[i].i*(float)out[i].i + out[N-i].i*(float)out[N-i].i; + E += binE; + } + E = SCALE_ENER(E); + band_log2[0] = .5f*1.442695f*(float)log(E+1e-10f); + } + for (b=0;bvalid = 0; + RESTORE_STACK; + return; + } +#endif + + tonal->E[tonal->E_count][b] = E; + frame_noisiness += nE/(1e-15f+E); + + frame_loudness += (float)sqrt(E+1e-10f); + logE[b] = (float)log(E+1e-10f); + band_log2[b+1] = .5f*1.442695f*(float)log(E+1e-10f); + tonal->logE[tonal->E_count][b] = logE[b]; + if (tonal->count==0) + tonal->highE[b] = tonal->lowE[b] = logE[b]; + if (tonal->highE[b] > tonal->lowE[b] + 7.5) + { + if (tonal->highE[b] - logE[b] > logE[b] - tonal->lowE[b]) + tonal->highE[b] -= .01f; + else + tonal->lowE[b] += .01f; + } + if (logE[b] > tonal->highE[b]) + { + tonal->highE[b] = logE[b]; + tonal->lowE[b] = MAX32(tonal->highE[b]-15, tonal->lowE[b]); + } else if (logE[b] < tonal->lowE[b]) + { + tonal->lowE[b] = logE[b]; + tonal->highE[b] = MIN32(tonal->lowE[b]+15, tonal->highE[b]); + } + relativeE += (logE[b]-tonal->lowE[b])/(1e-5f + (tonal->highE[b]-tonal->lowE[b])); + + L1=L2=0; + for (i=0;iE[i][b]); + L2 += tonal->E[i][b]; + } + + stationarity = MIN16(0.99f,L1/(float)sqrt(1e-15+NB_FRAMES*L2)); + stationarity *= stationarity; + stationarity *= stationarity; + frame_stationarity += stationarity; + /*band_tonality[b] = tE/(1e-15+E)*/; + band_tonality[b] = MAX16(tE/(1e-15f+E), stationarity*tonal->prev_band_tonality[b]); +#if 0 + if (b>=NB_TONAL_SKIP_BANDS) + { + frame_tonality += tweight[b]*band_tonality[b]; + tw_sum += tweight[b]; + } +#else + frame_tonality += band_tonality[b]; + if (b>=NB_TBANDS-NB_TONAL_SKIP_BANDS) + frame_tonality -= band_tonality[b-NB_TBANDS+NB_TONAL_SKIP_BANDS]; +#endif + max_frame_tonality = MAX16(max_frame_tonality, (1.f+.03f*(b-NB_TBANDS))*frame_tonality); + slope += band_tonality[b]*(b-8); + /*printf("%f %f ", band_tonality[b], stationarity);*/ + tonal->prev_band_tonality[b] = band_tonality[b]; + } + + leakage_from[0] = band_log2[0]; + leakage_to[0] = band_log2[0] - LEAKAGE_OFFSET; + for (b=1;b=0;b--) + { + float leak_slope = LEAKAGE_SLOPE*(tbands[b+1]-tbands[b])/4; + leakage_from[b] = MIN16(leakage_from[b+1]+leak_slope, leakage_from[b]); + leakage_to[b] = MAX16(leakage_to[b+1]-leak_slope, leakage_to[b]); + } + celt_assert(NB_TBANDS+1 <= LEAK_BANDS); + for (b=0;bleak_boost[b] = IMIN(255, (int)floor(.5 + 64.f*boost)); + } + for (;bleak_boost[b] = 0; + + for (i=0;ilogE[i][k] - tonal->logE[j][k]; + dist += tmp*tmp; + } + if (j!=i) + mindist = MIN32(mindist, dist); + } + spec_variability += mindist; + } + spec_variability = (float)sqrt(spec_variability/NB_FRAMES/NB_TBANDS); + bandwidth_mask = 0; + bandwidth = 0; + maxE = 0; + noise_floor = 5.7e-4f/(1<<(IMAX(0,lsb_depth-8))); + noise_floor *= noise_floor; + below_max_pitch=0; + above_max_pitch=0; + for (b=0;bmeanE[b] = MAX32((1-alphaE2)*tonal->meanE[b], E); + Em = MAX32(E, tonal->meanE[b]); + /* Consider the band "active" only if all these conditions are met: + 1) less than 90 dB below the peak band (maximal masking possible considering + both the ATH and the loudness-dependent slope of the spreading function) + 2) above the PCM quantization noise floor + We use b+1 because the first CELT band isn't included in tbands[] + */ + if (E*1e9f > maxE && (Em > 3*noise_floor*(band_end-band_start) || E > noise_floor*(band_end-band_start))) + bandwidth = b+1; + /* Check if the band is masked (see below). */ + is_masked[b] = E < (tonal->prev_bandwidth >= b+1 ? .01f : .05f)*bandwidth_mask; + /* Use a simple follower with 13 dB/Bark slope for spreading function. */ + bandwidth_mask = MAX32(.05f*bandwidth_mask, E); + } + /* Special case for the last two bands, for which we don't have spectrum but only + the energy above 12 kHz. The difficulty here is that the high-pass we use + leaks some LF energy, so we need to increase the threshold without accidentally cutting + off the band. */ + if (tonal->Fs == 48000) { + float noise_ratio; + float Em; + float E = hp_ener*(1.f/(60*60)); + noise_ratio = tonal->prev_bandwidth==20 ? 10.f : 30.f; + +#ifdef FIXED_POINT + /* silk_resampler_down2_hp() shifted right by an extra 8 bits. */ + E *= 256.f*(1.f/Q15ONE)*(1.f/Q15ONE); +#endif + above_max_pitch += E; + tonal->meanE[b] = MAX32((1-alphaE2)*tonal->meanE[b], E); + Em = MAX32(E, tonal->meanE[b]); + if (Em > 3*noise_ratio*noise_floor*160 || E > noise_ratio*noise_floor*160) + bandwidth = 20; + /* Check if the band is masked (see below). */ + is_masked[b] = E < (tonal->prev_bandwidth == 20 ? .01f : .05f)*bandwidth_mask; + } + if (above_max_pitch > below_max_pitch) + info->max_pitch_ratio = below_max_pitch/above_max_pitch; + else + info->max_pitch_ratio = 1; + /* In some cases, resampling aliasing can create a small amount of energy in the first band + being cut. So if the last band is masked, we don't include it. */ + if (bandwidth == 20 && is_masked[NB_TBANDS]) + bandwidth-=2; + else if (bandwidth > 0 && bandwidth <= NB_TBANDS && is_masked[bandwidth-1]) + bandwidth--; + if (tonal->count<=2) + bandwidth = 20; + frame_loudness = 20*(float)log10(frame_loudness); + tonal->Etracker = MAX32(tonal->Etracker-.003f, frame_loudness); + tonal->lowECount *= (1-alphaE); + if (frame_loudness < tonal->Etracker-30) + tonal->lowECount += alphaE; + + for (i=0;i<8;i++) + { + float sum=0; + for (b=0;b<16;b++) + sum += dct_table[i*16+b]*logE[b]; + BFCC[i] = sum; + } + for (i=0;i<8;i++) + { + float sum=0; + for (b=0;b<16;b++) + sum += dct_table[i*16+b]*.5f*(tonal->highE[b]+tonal->lowE[b]); + midE[i] = sum; + } + + frame_stationarity /= NB_TBANDS; + relativeE /= NB_TBANDS; + if (tonal->count<10) + relativeE = .5f; + frame_noisiness /= NB_TBANDS; +#if 1 + info->activity = frame_noisiness + (1-frame_noisiness)*relativeE; +#else + info->activity = .5*(1+frame_noisiness-frame_stationarity); +#endif + frame_tonality = (max_frame_tonality/(NB_TBANDS-NB_TONAL_SKIP_BANDS)); + frame_tonality = MAX16(frame_tonality, tonal->prev_tonality*.8f); + tonal->prev_tonality = frame_tonality; + + slope /= 8*8; + info->tonality_slope = slope; + + tonal->E_count = (tonal->E_count+1)%NB_FRAMES; + tonal->count = IMIN(tonal->count+1, ANALYSIS_COUNT_MAX); + 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-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-alpha)*tonal->std[i] + alpha*features[i]*features[i]; + } + for (i=0;i<4;i++) + features[i] = BFCC[i]-midE[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)sqrt(tonal->std[i]) - std_feature_bias[i]; + features[18] = spec_variability - 0.78f; + features[20] = info->tonality - 0.154723f; + features[21] = info->activity - 0.724643f; + features[22] = frame_stationarity - 0.743717f; + features[23] = info->tonality_slope + 0.069216f; + features[24] = tonal->lowECount - 0.067930f; + + compute_dense(&layer0, layer_out, features); + compute_gru(&layer1, tonal->rnn_state, layer_out); + compute_dense(&layer2, frame_probs, tonal->rnn_state); + + /* Probability of speech or music vs noise */ + info->activity_probability = frame_probs[1]; + info->music_prob = frame_probs[0]; + + /*printf("%f %f %f\n", frame_probs[0], frame_probs[1], info->music_prob);*/ +#ifdef MLP_TRAINING + for (i=0;i<25;i++) + printf("%f ", features[i]); + printf("\n"); +#endif + + info->bandwidth = bandwidth; + tonal->prev_bandwidth = bandwidth; + /*printf("%d %d\n", info->bandwidth, info->opus_bandwidth);*/ + info->noisiness = frame_noisiness; + info->valid = 1; + RESTORE_STACK; +} + +void run_analysis(TonalityAnalysisState *analysis, const CELTMode *celt_mode, const void *analysis_pcm, + int analysis_frame_size, int frame_size, int c1, int c2, int C, opus_int32 Fs, + int lsb_depth, downmix_func downmix, AnalysisInfo *analysis_info) +{ + int offset; + int pcm_len; + + analysis_frame_size -= analysis_frame_size&1; + if (analysis_pcm != NULL) + { + /* Avoid overflow/wrap-around of the analysis buffer */ + analysis_frame_size = IMIN((DETECT_SIZE-5)*Fs/50, analysis_frame_size); + + pcm_len = analysis_frame_size - analysis->analysis_offset; + offset = analysis->analysis_offset; + while (pcm_len>0) { + tonality_analysis(analysis, celt_mode, analysis_pcm, IMIN(Fs/50, pcm_len), offset, c1, c2, C, lsb_depth, downmix); + offset += Fs/50; + pcm_len -= Fs/50; + } + analysis->analysis_offset = analysis_frame_size; + + analysis->analysis_offset -= frame_size; + } + + tonality_get_info(analysis, analysis_info, frame_size); +} + +#endif /* DISABLE_FLOAT_API */ diff --git a/extern/opus/src/analysis.h b/extern/opus/src/analysis.h new file mode 100644 index 0000000..0b66555 --- /dev/null +++ b/extern/opus/src/analysis.h @@ -0,0 +1,103 @@ +/* Copyright (c) 2011 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + 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. + + 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 FOUNDATION 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. +*/ + +#ifndef ANALYSIS_H +#define ANALYSIS_H + +#include "celt.h" +#include "opus_private.h" +#include "mlp.h" + +#define NB_FRAMES 8 +#define NB_TBANDS 18 +#define ANALYSIS_BUF_SIZE 720 /* 30 ms at 24 kHz */ + +/* At that point we can stop counting frames because it no longer matters. */ +#define ANALYSIS_COUNT_MAX 10000 + +#define DETECT_SIZE 100 + +/* Uncomment this to print the MLP features on stdout. */ +/*#define MLP_TRAINING*/ + +typedef struct { + int arch; + int application; + opus_int32 Fs; +#define TONALITY_ANALYSIS_RESET_START angle + float angle[240]; + float d_angle[240]; + float d2_angle[240]; + opus_val32 inmem[ANALYSIS_BUF_SIZE]; + int mem_fill; /* number of usable samples in the buffer */ + float prev_band_tonality[NB_TBANDS]; + float prev_tonality; + int prev_bandwidth; + float E[NB_FRAMES][NB_TBANDS]; + float logE[NB_FRAMES][NB_TBANDS]; + float lowE[NB_TBANDS]; + float highE[NB_TBANDS]; + float meanE[NB_TBANDS+1]; + float mem[32]; + float cmean[8]; + float std[9]; + float Etracker; + float lowECount; + int E_count; + int count; + int analysis_offset; + int write_pos; + int read_pos; + int read_subframe; + float hp_ener_accum; + int initialized; + float rnn_state[MAX_NEURONS]; + opus_val32 downmix_state[3]; + AnalysisInfo info[DETECT_SIZE]; +} TonalityAnalysisState; + +/** Initialize a TonalityAnalysisState struct. + * + * This performs some possibly slow initialization steps which should + * not be repeated every analysis step. No allocated memory is retained + * by the state struct, so no cleanup call is required. + */ +void tonality_analysis_init(TonalityAnalysisState *analysis, opus_int32 Fs); + +/** Reset a TonalityAnalysisState stuct. + * + * Call this when there's a discontinuity in the data. + */ +void tonality_analysis_reset(TonalityAnalysisState *analysis); + +void tonality_get_info(TonalityAnalysisState *tonal, AnalysisInfo *info_out, int len); + +void run_analysis(TonalityAnalysisState *analysis, const CELTMode *celt_mode, const void *analysis_pcm, + int analysis_frame_size, int frame_size, int c1, int c2, int C, opus_int32 Fs, + int lsb_depth, downmix_func downmix, AnalysisInfo *analysis_info); + +#endif diff --git a/extern/opus/src/mapping_matrix.c b/extern/opus/src/mapping_matrix.c new file mode 100644 index 0000000..31298af --- /dev/null +++ b/extern/opus/src/mapping_matrix.c @@ -0,0 +1,378 @@ +/* Copyright (c) 2017 Google Inc. + Written by Andrew Allen */ +/* + 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. + + 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 OWNER + 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. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "arch.h" +#include "float_cast.h" +#include "opus_private.h" +#include "opus_defines.h" +#include "mapping_matrix.h" + +#define MATRIX_INDEX(nb_rows, row, col) (nb_rows * col + row) + +opus_int32 mapping_matrix_get_size(int rows, int cols) +{ + opus_int32 size; + + /* Mapping Matrix must only support up to 255 channels in or out. + * Additionally, the total cell count must be <= 65004 octets in order + * for the matrix to be stored in an OGG header. + */ + if (rows > 255 || cols > 255) + return 0; + size = rows * (opus_int32)cols * sizeof(opus_int16); + if (size > 65004) + return 0; + + return align(sizeof(MappingMatrix)) + align(size); +} + +opus_int16 *mapping_matrix_get_data(const MappingMatrix *matrix) +{ + /* void* cast avoids clang -Wcast-align warning */ + return (opus_int16*)(void*)((char*)matrix + align(sizeof(MappingMatrix))); +} + +void mapping_matrix_init(MappingMatrix * const matrix, + int rows, int cols, int gain, const opus_int16 *data, opus_int32 data_size) +{ + int i; + opus_int16 *ptr; + +#if !defined(ENABLE_ASSERTIONS) + (void)data_size; +#endif + celt_assert(align(data_size) == align(rows * cols * sizeof(opus_int16))); + + matrix->rows = rows; + matrix->cols = cols; + matrix->gain = gain; + ptr = mapping_matrix_get_data(matrix); + for (i = 0; i < rows * cols; i++) + { + ptr[i] = data[i]; + } +} + +#ifndef DISABLE_FLOAT_API +void mapping_matrix_multiply_channel_in_float( + const MappingMatrix *matrix, + const float *input, + int input_rows, + opus_val16 *output, + int output_row, + int output_rows, + int frame_size) +{ + /* Matrix data is ordered col-wise. */ + opus_int16* matrix_data; + int i, col; + + celt_assert(input_rows <= matrix->cols && output_rows <= matrix->rows); + + matrix_data = mapping_matrix_get_data(matrix); + + for (i = 0; i < frame_size; i++) + { + float tmp = 0; + for (col = 0; col < input_rows; col++) + { + tmp += + matrix_data[MATRIX_INDEX(matrix->rows, output_row, col)] * + input[MATRIX_INDEX(input_rows, col, i)]; + } +#if defined(FIXED_POINT) + output[output_rows * i] = FLOAT2INT16((1/32768.f)*tmp); +#else + output[output_rows * i] = (1/32768.f)*tmp; +#endif + } +} + +void mapping_matrix_multiply_channel_out_float( + const MappingMatrix *matrix, + const opus_val16 *input, + int input_row, + int input_rows, + float *output, + int output_rows, + int frame_size +) +{ + /* Matrix data is ordered col-wise. */ + opus_int16* matrix_data; + int i, row; + float input_sample; + + celt_assert(input_rows <= matrix->cols && output_rows <= matrix->rows); + + matrix_data = mapping_matrix_get_data(matrix); + + for (i = 0; i < frame_size; i++) + { +#if defined(FIXED_POINT) + input_sample = (1/32768.f)*input[input_rows * i]; +#else + input_sample = input[input_rows * i]; +#endif + for (row = 0; row < output_rows; row++) + { + float tmp = + (1/32768.f)*matrix_data[MATRIX_INDEX(matrix->rows, row, input_row)] * + input_sample; + output[MATRIX_INDEX(output_rows, row, i)] += tmp; + } + } +} +#endif /* DISABLE_FLOAT_API */ + +void mapping_matrix_multiply_channel_in_short( + const MappingMatrix *matrix, + const opus_int16 *input, + int input_rows, + opus_val16 *output, + int output_row, + int output_rows, + int frame_size) +{ + /* Matrix data is ordered col-wise. */ + opus_int16* matrix_data; + int i, col; + + celt_assert(input_rows <= matrix->cols && output_rows <= matrix->rows); + + matrix_data = mapping_matrix_get_data(matrix); + + for (i = 0; i < frame_size; i++) + { + opus_val32 tmp = 0; + for (col = 0; col < input_rows; col++) + { +#if defined(FIXED_POINT) + tmp += + ((opus_int32)matrix_data[MATRIX_INDEX(matrix->rows, output_row, col)] * + (opus_int32)input[MATRIX_INDEX(input_rows, col, i)]) >> 8; +#else + tmp += + matrix_data[MATRIX_INDEX(matrix->rows, output_row, col)] * + input[MATRIX_INDEX(input_rows, col, i)]; +#endif + } +#if defined(FIXED_POINT) + output[output_rows * i] = (opus_int16)((tmp + 64) >> 7); +#else + output[output_rows * i] = (1/(32768.f*32768.f))*tmp; +#endif + } +} + +void mapping_matrix_multiply_channel_out_short( + const MappingMatrix *matrix, + const opus_val16 *input, + int input_row, + int input_rows, + opus_int16 *output, + int output_rows, + int frame_size) +{ + /* Matrix data is ordered col-wise. */ + opus_int16* matrix_data; + int i, row; + opus_int32 input_sample; + + celt_assert(input_rows <= matrix->cols && output_rows <= matrix->rows); + + matrix_data = mapping_matrix_get_data(matrix); + + for (i = 0; i < frame_size; i++) + { +#if defined(FIXED_POINT) + input_sample = (opus_int32)input[input_rows * i]; +#else + input_sample = (opus_int32)FLOAT2INT16(input[input_rows * i]); +#endif + for (row = 0; row < output_rows; row++) + { + opus_int32 tmp = + (opus_int32)matrix_data[MATRIX_INDEX(matrix->rows, row, input_row)] * + input_sample; + output[MATRIX_INDEX(output_rows, row, i)] += (tmp + 16384) >> 15; + } + } +} + +const MappingMatrix mapping_matrix_foa_mixing = { 6, 6, 0 }; +const opus_int16 mapping_matrix_foa_mixing_data[36] = { + 16384, 0, -16384, 23170, 0, 0, 16384, 23170, + 16384, 0, 0, 0, 16384, 0, -16384, -23170, + 0, 0, 16384, -23170, 16384, 0, 0, 0, + 0, 0, 0, 0, 32767, 0, 0, 0, + 0, 0, 0, 32767 +}; + +const MappingMatrix mapping_matrix_soa_mixing = { 11, 11, 0 }; +const opus_int16 mapping_matrix_soa_mixing_data[121] = { + 10923, 7723, 13377, -13377, 11585, 9459, 7723, -16384, + -6689, 0, 0, 10923, 7723, 13377, 13377, -11585, + 9459, 7723, 16384, -6689, 0, 0, 10923, -15447, + 13377, 0, 0, -18919, 7723, 0, 13377, 0, + 0, 10923, 7723, -13377, -13377, 11585, -9459, 7723, + 16384, -6689, 0, 0, 10923, -7723, 0, 13377, + -16384, 0, -15447, 0, 9459, 0, 0, 10923, + -7723, 0, -13377, 16384, 0, -15447, 0, 9459, + 0, 0, 10923, 15447, 0, 0, 0, 0, + -15447, 0, -18919, 0, 0, 10923, 7723, -13377, + 13377, -11585, -9459, 7723, -16384, -6689, 0, 0, + 10923, -15447, -13377, 0, 0, 18919, 7723, 0, + 13377, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 32767, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 32767 +}; + +const MappingMatrix mapping_matrix_toa_mixing = { 18, 18, 0 }; +const opus_int16 mapping_matrix_toa_mixing_data[324] = { + 8208, 0, -881, 14369, 0, 0, -8192, -4163, + 13218, 0, 0, 0, 11095, -8836, -6218, 14833, + 0, 0, 8208, -10161, 881, 10161, -13218, -2944, + -8192, 2944, 0, -10488, -6218, 6248, -11095, -6248, + 0, -10488, 0, 0, 8208, 10161, 881, -10161, + -13218, 2944, -8192, -2944, 0, 10488, -6218, -6248, + -11095, 6248, 0, 10488, 0, 0, 8176, 5566, + -11552, 5566, 9681, -11205, 8192, -11205, 0, 4920, + -15158, 9756, -3334, 9756, 0, -4920, 0, 0, + 8176, 7871, 11552, 0, 0, 15846, 8192, 0, + -9681, -6958, 0, 13797, 3334, 0, -15158, 0, + 0, 0, 8176, 0, 11552, 7871, 0, 0, + 8192, 15846, 9681, 0, 0, 0, 3334, 13797, + 15158, 6958, 0, 0, 8176, 5566, -11552, -5566, + -9681, -11205, 8192, 11205, 0, 4920, 15158, 9756, + -3334, -9756, 0, 4920, 0, 0, 8208, 14369, + -881, 0, 0, -4163, -8192, 0, -13218, -14833, + 0, -8836, 11095, 0, 6218, 0, 0, 0, + 8208, 10161, 881, 10161, 13218, 2944, -8192, 2944, + 0, 10488, 6218, -6248, -11095, -6248, 0, -10488, + 0, 0, 8208, -14369, -881, 0, 0, 4163, + -8192, 0, -13218, 14833, 0, 8836, 11095, 0, + 6218, 0, 0, 0, 8208, 0, -881, -14369, + 0, 0, -8192, 4163, 13218, 0, 0, 0, + 11095, 8836, -6218, -14833, 0, 0, 8176, -5566, + -11552, 5566, -9681, 11205, 8192, -11205, 0, -4920, + 15158, -9756, -3334, 9756, 0, -4920, 0, 0, + 8176, 0, 11552, -7871, 0, 0, 8192, -15846, + 9681, 0, 0, 0, 3334, -13797, 15158, -6958, + 0, 0, 8176, -7871, 11552, 0, 0, -15846, + 8192, 0, -9681, 6958, 0, -13797, 3334, 0, + -15158, 0, 0, 0, 8176, -5566, -11552, -5566, + 9681, 11205, 8192, 11205, 0, -4920, -15158, -9756, + -3334, -9756, 0, 4920, 0, 0, 8208, -10161, + 881, -10161, 13218, -2944, -8192, -2944, 0, -10488, + 6218, 6248, -11095, 6248, 0, 10488, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 32767, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 32767 +}; + +const MappingMatrix mapping_matrix_foa_demixing = { 6, 6, 0 }; +const opus_int16 mapping_matrix_foa_demixing_data[36] = { + 16384, 16384, 16384, 16384, 0, 0, 0, 23170, + 0, -23170, 0, 0, -16384, 16384, -16384, 16384, + 0, 0, 23170, 0, -23170, 0, 0, 0, + 0, 0, 0, 0, 32767, 0, 0, 0, + 0, 0, 0, 32767 +}; + +const MappingMatrix mapping_matrix_soa_demixing = { 11, 11, 3050 }; +const opus_int16 mapping_matrix_soa_demixing_data[121] = { + 2771, 2771, 2771, 2771, 2771, 2771, 2771, 2771, + 2771, 0, 0, 10033, 10033, -20066, 10033, 14189, + 14189, -28378, 10033, -20066, 0, 0, 3393, 3393, + 3393, -3393, 0, 0, 0, -3393, -3393, 0, + 0, -17378, 17378, 0, -17378, -24576, 24576, 0, + 17378, 0, 0, 0, -14189, 14189, 0, -14189, + -28378, 28378, 0, 14189, 0, 0, 0, 2399, + 2399, -4799, -2399, 0, 0, 0, -2399, 4799, + 0, 0, 1959, 1959, 1959, 1959, -3918, -3918, + -3918, 1959, 1959, 0, 0, -4156, 4156, 0, + 4156, 0, 0, 0, -4156, 0, 0, 0, + 8192, 8192, -16384, 8192, 16384, 16384, -32768, 8192, + -16384, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 8312, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 8312 +}; + +const MappingMatrix mapping_matrix_toa_demixing = { 18, 18, 0 }; +const opus_int16 mapping_matrix_toa_demixing_data[324] = { + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 0, 0, 0, -9779, 9779, 6263, 8857, 0, + 6263, 13829, 9779, -13829, 0, -6263, 0, -8857, + -6263, -9779, 0, 0, -3413, 3413, 3413, -11359, + 11359, 11359, -11359, -3413, 3413, -3413, -3413, -11359, + 11359, 11359, -11359, 3413, 0, 0, 13829, 9779, + -9779, 6263, 0, 8857, -6263, 0, 9779, 0, + -13829, 6263, -8857, 0, -6263, -9779, 0, 0, + 0, -15617, -15617, 6406, 0, 0, -6406, 0, + 15617, 0, 0, -6406, 0, 0, 6406, 15617, + 0, 0, 0, -5003, 5003, -10664, 15081, 0, + -10664, -7075, 5003, 7075, 0, 10664, 0, -15081, + 10664, -5003, 0, 0, -8176, -8176, -8176, 8208, + 8208, 8208, 8208, -8176, -8176, -8176, -8176, 8208, + 8208, 8208, 8208, -8176, 0, 0, -7075, 5003, + -5003, -10664, 0, 15081, 10664, 0, 5003, 0, + 7075, -10664, -15081, 0, 10664, -5003, 0, 0, + 15617, 0, 0, 0, -6406, 6406, 0, -15617, + 0, -15617, 15617, 0, 6406, -6406, 0, 0, + 0, 0, 0, -11393, 11393, 2993, -4233, 0, + 2993, -16112, 11393, 16112, 0, -2993, 0, 4233, + -2993, -11393, 0, 0, 0, -9974, -9974, -13617, + 0, 0, 13617, 0, 9974, 0, 0, 13617, + 0, 0, -13617, 9974, 0, 0, 0, 5579, + -5579, 10185, 14403, 0, 10185, -7890, -5579, 7890, + 0, -10185, 0, -14403, -10185, 5579, 0, 0, + 11826, -11826, -11826, -901, 901, 901, -901, 11826, + -11826, 11826, 11826, -901, 901, 901, -901, -11826, + 0, 0, -7890, -5579, 5579, 10185, 0, 14403, + -10185, 0, -5579, 0, 7890, 10185, -14403, 0, + -10185, 5579, 0, 0, -9974, 0, 0, 0, + -13617, 13617, 0, 9974, 0, 9974, -9974, 0, + 13617, -13617, 0, 0, 0, 0, 16112, -11393, + 11393, -2993, 0, 4233, 2993, 0, -11393, 0, + -16112, -2993, -4233, 0, 2993, 11393, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 32767, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 32767 +}; + diff --git a/extern/opus/src/mapping_matrix.h b/extern/opus/src/mapping_matrix.h new file mode 100644 index 0000000..98bc82d --- /dev/null +++ b/extern/opus/src/mapping_matrix.h @@ -0,0 +1,133 @@ +/* Copyright (c) 2017 Google Inc. + Written by Andrew Allen */ +/* + 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. + + 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 OWNER + 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. +*/ + +/** + * @file mapping_matrix.h + * @brief Opus reference implementation mapping matrix API + */ + +#ifndef MAPPING_MATRIX_H +#define MAPPING_MATRIX_H + +#include "opus_types.h" +#include "opus_projection.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct MappingMatrix +{ + int rows; /* number of channels outputted from matrix. */ + int cols; /* number of channels inputted to matrix. */ + int gain; /* in dB. S7.8-format. */ + /* Matrix cell data goes here using col-wise ordering. */ +} MappingMatrix; + +opus_int32 mapping_matrix_get_size(int rows, int cols); + +opus_int16 *mapping_matrix_get_data(const MappingMatrix *matrix); + +void mapping_matrix_init( + MappingMatrix * const matrix, + int rows, + int cols, + int gain, + const opus_int16 *data, + opus_int32 data_size +); + +#ifndef DISABLE_FLOAT_API +void mapping_matrix_multiply_channel_in_float( + const MappingMatrix *matrix, + const float *input, + int input_rows, + opus_val16 *output, + int output_row, + int output_rows, + int frame_size +); + +void mapping_matrix_multiply_channel_out_float( + const MappingMatrix *matrix, + const opus_val16 *input, + int input_row, + int input_rows, + float *output, + int output_rows, + int frame_size +); +#endif /* DISABLE_FLOAT_API */ + +void mapping_matrix_multiply_channel_in_short( + const MappingMatrix *matrix, + const opus_int16 *input, + int input_rows, + opus_val16 *output, + int output_row, + int output_rows, + int frame_size +); + +void mapping_matrix_multiply_channel_out_short( + const MappingMatrix *matrix, + const opus_val16 *input, + int input_row, + int input_rows, + opus_int16 *output, + int output_rows, + int frame_size +); + +/* Pre-computed mixing and demixing matrices for 1st to 3rd-order ambisonics. + * foa: first-order ambisonics + * soa: second-order ambisonics + * toa: third-order ambisonics + */ +extern const MappingMatrix mapping_matrix_foa_mixing; +extern const opus_int16 mapping_matrix_foa_mixing_data[36]; + +extern const MappingMatrix mapping_matrix_soa_mixing; +extern const opus_int16 mapping_matrix_soa_mixing_data[121]; + +extern const MappingMatrix mapping_matrix_toa_mixing; +extern const opus_int16 mapping_matrix_toa_mixing_data[324]; + +extern const MappingMatrix mapping_matrix_foa_demixing; +extern const opus_int16 mapping_matrix_foa_demixing_data[36]; + +extern const MappingMatrix mapping_matrix_soa_demixing; +extern const opus_int16 mapping_matrix_soa_demixing_data[121]; + +extern const MappingMatrix mapping_matrix_toa_demixing; +extern const opus_int16 mapping_matrix_toa_demixing_data[324]; + +#ifdef __cplusplus +} +#endif + +#endif /* MAPPING_MATRIX_H */ diff --git a/extern/opus/src/mlp.c b/extern/opus/src/mlp.c new file mode 100644 index 0000000..964c6a9 --- /dev/null +++ b/extern/opus/src/mlp.c @@ -0,0 +1,144 @@ +/* Copyright (c) 2008-2011 Octasic Inc. + 2012-2017 Jean-Marc Valin */ +/* + 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. + + 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 FOUNDATION 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. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "opus_types.h" +#include "opus_defines.h" +#include "arch.h" +#include "tansig_table.h" +#include "mlp.h" + +static OPUS_INLINE float tansig_approx(float x) +{ + int i; + float y, dy; + float sign=1; + /* Tests are reversed to catch NaNs */ + if (!(x<8)) + return 1; + if (!(x>-8)) + return -1; +#ifndef FIXED_POINT + /* Another check in case of -ffast-math */ + if (celt_isnan(x)) + return 0; +#endif + if (x<0) + { + x=-x; + sign=-1; + } + i = (int)floor(.5f+25*x); + x -= .04f*i; + y = tansig_table[i]; + dy = 1-y*y; + y = y + x*dy*(1 - y*x); + return sign*y; +} + +static OPUS_INLINE float sigmoid_approx(float x) +{ + return .5f + .5f*tansig_approx(.5f*x); +} + +static void gemm_accum(float *out, const opus_int8 *weights, int rows, int cols, int col_stride, const float *x) +{ + int i, j; + for (i=0;inb_inputs; + N = layer->nb_neurons; + stride = N; + for (i=0;ibias[i]; + gemm_accum(output, layer->input_weights, N, M, stride, input); + for (i=0;isigmoid) { + for (i=0;inb_inputs; + N = gru->nb_neurons; + stride = 3*N; + /* Compute update gate. */ + for (i=0;ibias[i]; + gemm_accum(z, gru->input_weights, N, M, stride, input); + gemm_accum(z, gru->recurrent_weights, N, N, stride, state); + for (i=0;ibias[N + i]; + gemm_accum(r, &gru->input_weights[N], N, M, stride, input); + gemm_accum(r, &gru->recurrent_weights[N], N, N, stride, state); + for (i=0;ibias[2*N + i]; + for (i=0;iinput_weights[2*N], N, M, stride, input); + gemm_accum(h, &gru->recurrent_weights[2*N], N, N, stride, tmp); + for (i=0;i=0) + break; + x[i*C] = x[i*C]+a*x[i*C]*x[i*C]; + } + + curr=0; + x0 = x[0]; + while(1) + { + int start, end; + float maxval; + int special=0; + int peak_pos; + for (i=curr;i1 || x[i*C]<-1) + break; + } + if (i==N) + { + a=0; + break; + } + peak_pos = i; + start=end=i; + maxval=ABS16(x[i*C]); + /* Look for first zero crossing before clipping */ + while (start>0 && x[i*C]*x[(start-1)*C]>=0) + start--; + /* Look for first zero crossing after clipping */ + while (end=0) + { + /* Look for other peaks until the next zero-crossing. */ + if (ABS16(x[end*C])>maxval) + { + maxval = ABS16(x[end*C]); + peak_pos = end; + } + end++; + } + /* Detect the special case where we clip before the first zero crossing */ + special = (start==0 && x[i*C]*x[0]>=0); + + /* Compute a such that maxval + a*maxval^2 = 1 */ + a=(maxval-1)/(maxval*maxval); + /* Slightly boost "a" by 2^-22. This is just enough to ensure -ffast-math + does not cause output values larger than +/-1, but small enough not + to matter even for 24-bit output. */ + a += a*2.4e-7f; + if (x[i*C]>0) + a = -a; + /* Apply soft clipping */ + for (i=start;i=2) + { + /* Add a linear ramp from the first sample to the signal peak. + This avoids a discontinuity at the beginning of the frame. */ + float delta; + float offset = x0-x[0]; + delta = offset / peak_pos; + for (i=curr;i>2; + return 2; + } +} + +static int parse_size(const unsigned char *data, opus_int32 len, opus_int16 *size) +{ + if (len<1) + { + *size = -1; + return -1; + } else if (data[0]<252) + { + *size = data[0]; + return 1; + } else if (len<2) + { + *size = -1; + return -1; + } else { + *size = 4*data[1] + data[0]; + return 2; + } +} + +int opus_packet_get_samples_per_frame(const unsigned char *data, + opus_int32 Fs) +{ + int audiosize; + if (data[0]&0x80) + { + audiosize = ((data[0]>>3)&0x3); + audiosize = (Fs<>3)&0x3); + if (audiosize == 3) + audiosize = Fs*60/1000; + else + audiosize = (Fs< len) + return OPUS_INVALID_PACKET; + data += bytes; + last_size = len-size[0]; + break; + /* Multiple CBR/VBR frames (from 0 to 120 ms) */ + default: /*case 3:*/ + if (len<1) + return OPUS_INVALID_PACKET; + /* Number of frames encoded in bits 0 to 5 */ + ch = *data++; + count = ch&0x3F; + if (count <= 0 || framesize*(opus_int32)count > 5760) + return OPUS_INVALID_PACKET; + len--; + /* Padding flag is bit 6 */ + if (ch&0x40) + { + int p; + do { + int tmp; + if (len<=0) + return OPUS_INVALID_PACKET; + p = *data++; + len--; + tmp = p==255 ? 254: p; + len -= tmp; + pad += tmp; + } while (p==255); + } + if (len<0) + return OPUS_INVALID_PACKET; + /* VBR flag is bit 7 */ + cbr = !(ch&0x80); + if (!cbr) + { + /* VBR case */ + last_size = len; + for (i=0;i len) + return OPUS_INVALID_PACKET; + data += bytes; + last_size -= bytes+size[i]; + } + if (last_size<0) + return OPUS_INVALID_PACKET; + } else if (!self_delimited) + { + /* CBR case */ + last_size = len/count; + if (last_size*count!=len) + return OPUS_INVALID_PACKET; + for (i=0;i len) + return OPUS_INVALID_PACKET; + data += bytes; + /* For CBR packets, apply the size to all the frames. */ + if (cbr) + { + if (size[count-1]*count > len) + return OPUS_INVALID_PACKET; + for (i=0;i last_size) + return OPUS_INVALID_PACKET; + } else + { + /* Because it's not encoded explicitly, it's possible the size of the + last packet (or all the packets, for the CBR case) is larger than + 1275. Reject them here.*/ + if (last_size > 1275) + return OPUS_INVALID_PACKET; + size[count-1] = (opus_int16)last_size; + } + + if (payload_offset) + *payload_offset = (int)(data-data0); + + for (i=0;i +#include +#include +#include + +#define OPUS_PI (3.14159265F) + +#define OPUS_COSF(_x) ((float)cos(_x)) +#define OPUS_SINF(_x) ((float)sin(_x)) + +static void *check_alloc(void *_ptr){ + if(_ptr==NULL){ + fprintf(stderr,"Out of memory.\n"); + exit(EXIT_FAILURE); + } + return _ptr; +} + +static void *opus_malloc(size_t _size){ + return check_alloc(malloc(_size)); +} + +static void *opus_realloc(void *_ptr,size_t _size){ + return check_alloc(realloc(_ptr,_size)); +} + +static size_t read_pcm16(float **_samples,FILE *_fin,int _nchannels){ + unsigned char buf[1024]; + float *samples; + size_t nsamples; + size_t csamples; + size_t xi; + size_t nread; + samples=NULL; + nsamples=csamples=0; + for(;;){ + nread=fread(buf,2*_nchannels,1024/(2*_nchannels),_fin); + if(nread<=0)break; + if(nsamples+nread>csamples){ + do csamples=csamples<<1|1; + while(nsamples+nread>csamples); + samples=(float *)opus_realloc(samples, + _nchannels*csamples*sizeof(*samples)); + } + for(xi=0;xi=_window_sz)ti-=_window_sz; + } + re*=_downsample; + im*=_downsample; + _ps[(xi*ps_sz+xj)*_nchannels+ci]=re*re+im*im+100000; + p[ci]+=_ps[(xi*ps_sz+xj)*_nchannels+ci]; + } + } + if(_out){ + _out[(xi*_nbands+bi)*_nchannels]=p[0]/(_bands[bi+1]-_bands[bi]); + if(_nchannels==2){ + _out[(xi*_nbands+bi)*_nchannels+1]=p[1]/(_bands[bi+1]-_bands[bi]); + } + } + } + } + free(window); +} + +#define NBANDS (21) +#define NFREQS (240) + +/*Bands on which we compute the pseudo-NMR (Bark-derived + CELT bands).*/ +static const int BANDS[NBANDS+1]={ + 0,2,4,6,8,10,12,14,16,20,24,28,32,40,48,56,68,80,96,120,156,200 +}; + +#define TEST_WIN_SIZE (480) +#define TEST_WIN_STEP (120) + +int main(int _argc,const char **_argv){ + FILE *fin1; + FILE *fin2; + float *x; + float *y; + float *xb; + float *X; + float *Y; + double err; + float Q; + size_t xlength; + size_t ylength; + size_t nframes; + size_t xi; + int ci; + int xj; + int bi; + int nchannels; + unsigned rate; + int downsample; + int ybands; + int yfreqs; + int max_compare; + if(_argc<3||_argc>6){ + fprintf(stderr,"Usage: %s [-s] [-r rate2] \n", + _argv[0]); + return EXIT_FAILURE; + } + nchannels=1; + if(strcmp(_argv[1],"-s")==0){ + nchannels=2; + _argv++; + } + rate=48000; + ybands=NBANDS; + yfreqs=NFREQS; + downsample=1; + if(strcmp(_argv[1],"-r")==0){ + rate=atoi(_argv[2]); + if(rate!=8000&&rate!=12000&&rate!=16000&&rate!=24000&&rate!=48000){ + fprintf(stderr, + "Sampling rate must be 8000, 12000, 16000, 24000, or 48000\n"); + return EXIT_FAILURE; + } + downsample=48000/rate; + switch(rate){ + case 8000:ybands=13;break; + case 12000:ybands=15;break; + case 16000:ybands=17;break; + case 24000:ybands=19;break; + } + yfreqs=NFREQS/downsample; + _argv+=2; + } + fin1=fopen(_argv[1],"rb"); + if(fin1==NULL){ + fprintf(stderr,"Error opening '%s'.\n",_argv[1]); + return EXIT_FAILURE; + } + fin2=fopen(_argv[2],"rb"); + if(fin2==NULL){ + fprintf(stderr,"Error opening '%s'.\n",_argv[2]); + fclose(fin1); + return EXIT_FAILURE; + } + /*Read in the data and allocate scratch space.*/ + xlength=read_pcm16(&x,fin1,2); + if(nchannels==1){ + for(xi=0;xi0;){ + for(ci=0;ci0){ + /*Temporal masking: -3 dB/2.5ms slope.*/ + for(bi=0;bi=79&&xj<=81)im*=0.1F; + if(xj==80)im*=0.1F; + Eb+=im; + } + } + Eb /= (BANDS[bi+1]-BANDS[bi])*nchannels; + Ef += Eb*Eb; + } + /*Using a fixed normalization value means we're willing to accept slightly + lower quality for lower sampling rates.*/ + Ef/=NBANDS; + Ef*=Ef; + err+=Ef*Ef; + } + free(xb); + free(X); + free(Y); + err=pow(err/nframes,1.0/16); + Q=100*(1-0.5*log(1+err)/log(1.13)); + if(Q<0){ + fprintf(stderr,"Test vector FAILS\n"); + fprintf(stderr,"Internal weighted error is %f\n",err); + return EXIT_FAILURE; + } + else{ + fprintf(stderr,"Test vector PASSES\n"); + fprintf(stderr, + "Opus quality metric: %.1f %% (internal weighted error is %f)\n",Q,err); + return EXIT_SUCCESS; + } +} diff --git a/extern/opus/src/opus_decoder.c b/extern/opus/src/opus_decoder.c new file mode 100644 index 0000000..9113638 --- /dev/null +++ b/extern/opus/src/opus_decoder.c @@ -0,0 +1,1032 @@ +/* Copyright (c) 2010 Xiph.Org Foundation, Skype Limited + Written by Jean-Marc Valin and Koen Vos */ +/* + 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. + + 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 OWNER + 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. +*/ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifndef OPUS_BUILD +# error "OPUS_BUILD _MUST_ be defined to build Opus. This probably means you need other defines as well, as in a config.h. See the included build files for details." +#endif + +#if defined(__GNUC__) && (__GNUC__ >= 2) && !defined(__OPTIMIZE__) && !defined(OPUS_WILL_BE_SLOW) +# pragma message "You appear to be compiling without optimization, if so opus will be very slow." +#endif + +#include +#include "celt.h" +#include "opus.h" +#include "entdec.h" +#include "modes.h" +#include "API.h" +#include "stack_alloc.h" +#include "float_cast.h" +#include "opus_private.h" +#include "os_support.h" +#include "structs.h" +#include "define.h" +#include "mathops.h" +#include "cpu_support.h" + +struct OpusDecoder { + int celt_dec_offset; + int silk_dec_offset; + int channels; + opus_int32 Fs; /** Sampling rate (at the API level) */ + silk_DecControlStruct DecControl; + int decode_gain; + int arch; + + /* Everything beyond this point gets cleared on a reset */ +#define OPUS_DECODER_RESET_START stream_channels + int stream_channels; + + int bandwidth; + int mode; + int prev_mode; + int frame_size; + int prev_redundancy; + int last_packet_duration; +#ifndef FIXED_POINT + opus_val16 softclip_mem[2]; +#endif + + opus_uint32 rangeFinal; +}; + +#if defined(ENABLE_HARDENING) || defined(ENABLE_ASSERTIONS) +static void validate_opus_decoder(OpusDecoder *st) +{ + celt_assert(st->channels == 1 || st->channels == 2); + celt_assert(st->Fs == 48000 || st->Fs == 24000 || st->Fs == 16000 || st->Fs == 12000 || st->Fs == 8000); + celt_assert(st->DecControl.API_sampleRate == st->Fs); + celt_assert(st->DecControl.internalSampleRate == 0 || st->DecControl.internalSampleRate == 16000 || st->DecControl.internalSampleRate == 12000 || st->DecControl.internalSampleRate == 8000); + celt_assert(st->DecControl.nChannelsAPI == st->channels); + celt_assert(st->DecControl.nChannelsInternal == 0 || st->DecControl.nChannelsInternal == 1 || st->DecControl.nChannelsInternal == 2); + celt_assert(st->DecControl.payloadSize_ms == 0 || st->DecControl.payloadSize_ms == 10 || st->DecControl.payloadSize_ms == 20 || st->DecControl.payloadSize_ms == 40 || st->DecControl.payloadSize_ms == 60); +#ifdef OPUS_ARCHMASK + celt_assert(st->arch >= 0); + celt_assert(st->arch <= OPUS_ARCHMASK); +#endif + celt_assert(st->stream_channels == 1 || st->stream_channels == 2); +} +#define VALIDATE_OPUS_DECODER(st) validate_opus_decoder(st) +#else +#define VALIDATE_OPUS_DECODER(st) +#endif + +int opus_decoder_get_size(int channels) +{ + int silkDecSizeBytes, celtDecSizeBytes; + int ret; + if (channels<1 || channels > 2) + return 0; + ret = silk_Get_Decoder_Size( &silkDecSizeBytes ); + if(ret) + return 0; + silkDecSizeBytes = align(silkDecSizeBytes); + celtDecSizeBytes = celt_decoder_get_size(channels); + return align(sizeof(OpusDecoder))+silkDecSizeBytes+celtDecSizeBytes; +} + +int opus_decoder_init(OpusDecoder *st, opus_int32 Fs, int channels) +{ + void *silk_dec; + CELTDecoder *celt_dec; + int ret, silkDecSizeBytes; + + if ((Fs!=48000&&Fs!=24000&&Fs!=16000&&Fs!=12000&&Fs!=8000) + || (channels!=1&&channels!=2)) + return OPUS_BAD_ARG; + + OPUS_CLEAR((char*)st, opus_decoder_get_size(channels)); + /* Initialize SILK decoder */ + ret = silk_Get_Decoder_Size(&silkDecSizeBytes); + if (ret) + return OPUS_INTERNAL_ERROR; + + silkDecSizeBytes = align(silkDecSizeBytes); + st->silk_dec_offset = align(sizeof(OpusDecoder)); + st->celt_dec_offset = st->silk_dec_offset+silkDecSizeBytes; + silk_dec = (char*)st+st->silk_dec_offset; + celt_dec = (CELTDecoder*)((char*)st+st->celt_dec_offset); + st->stream_channels = st->channels = channels; + + st->Fs = Fs; + st->DecControl.API_sampleRate = st->Fs; + st->DecControl.nChannelsAPI = st->channels; + + /* Reset decoder */ + ret = silk_InitDecoder( silk_dec ); + if(ret)return OPUS_INTERNAL_ERROR; + + /* Initialize CELT decoder */ + ret = celt_decoder_init(celt_dec, Fs, channels); + if(ret!=OPUS_OK)return OPUS_INTERNAL_ERROR; + + celt_decoder_ctl(celt_dec, CELT_SET_SIGNALLING(0)); + + st->prev_mode = 0; + st->frame_size = Fs/400; + st->arch = opus_select_arch(); + return OPUS_OK; +} + +OpusDecoder *opus_decoder_create(opus_int32 Fs, int channels, int *error) +{ + int ret; + OpusDecoder *st; + if ((Fs!=48000&&Fs!=24000&&Fs!=16000&&Fs!=12000&&Fs!=8000) + || (channels!=1&&channels!=2)) + { + if (error) + *error = OPUS_BAD_ARG; + return NULL; + } + st = (OpusDecoder *)opus_alloc(opus_decoder_get_size(channels)); + if (st == NULL) + { + if (error) + *error = OPUS_ALLOC_FAIL; + return NULL; + } + ret = opus_decoder_init(st, Fs, channels); + if (error) + *error = ret; + if (ret != OPUS_OK) + { + opus_free(st); + st = NULL; + } + return st; +} + +static void smooth_fade(const opus_val16 *in1, const opus_val16 *in2, + opus_val16 *out, int overlap, int channels, + const opus_val16 *window, opus_int32 Fs) +{ + int i, c; + int inc = 48000/Fs; + for (c=0;csilk_dec_offset; + celt_dec = (CELTDecoder*)((char*)st+st->celt_dec_offset); + F20 = st->Fs/50; + F10 = F20>>1; + F5 = F10>>1; + F2_5 = F5>>1; + if (frame_size < F2_5) + { + RESTORE_STACK; + return OPUS_BUFFER_TOO_SMALL; + } + /* Limit frame_size to avoid excessive stack allocations. */ + frame_size = IMIN(frame_size, st->Fs/25*3); + /* Payloads of 1 (2 including ToC) or 0 trigger the PLC/DTX */ + if (len<=1) + { + data = NULL; + /* In that case, don't conceal more than what the ToC says */ + frame_size = IMIN(frame_size, st->frame_size); + } + if (data != NULL) + { + audiosize = st->frame_size; + mode = st->mode; + bandwidth = st->bandwidth; + ec_dec_init(&dec,(unsigned char*)data,len); + } else { + audiosize = frame_size; + mode = st->prev_mode; + bandwidth = 0; + + if (mode == 0) + { + /* If we haven't got any packet yet, all we can do is return zeros */ + for (i=0;ichannels;i++) + pcm[i] = 0; + RESTORE_STACK; + return audiosize; + } + + /* Avoids trying to run the PLC on sizes other than 2.5 (CELT), 5 (CELT), + 10, or 20 (e.g. 12.5 or 30 ms). */ + if (audiosize > F20) + { + do { + int ret = opus_decode_frame(st, NULL, 0, pcm, IMIN(audiosize, F20), 0); + if (ret<0) + { + RESTORE_STACK; + return ret; + } + pcm += ret*st->channels; + audiosize -= ret; + } while (audiosize > 0); + RESTORE_STACK; + return frame_size; + } else if (audiosize < F20) + { + if (audiosize > F10) + audiosize = F10; + else if (mode != MODE_SILK_ONLY && audiosize > F5 && audiosize < F10) + audiosize = F5; + } + } + + /* In fixed-point, we can tell CELT to do the accumulation on top of the + SILK PCM buffer. This saves some stack space. */ +#ifdef FIXED_POINT + celt_accum = (mode != MODE_CELT_ONLY) && (frame_size >= F10); +#else + celt_accum = 0; +#endif + + pcm_transition_silk_size = ALLOC_NONE; + pcm_transition_celt_size = ALLOC_NONE; + if (data!=NULL && st->prev_mode > 0 && ( + (mode == MODE_CELT_ONLY && st->prev_mode != MODE_CELT_ONLY && !st->prev_redundancy) + || (mode != MODE_CELT_ONLY && st->prev_mode == MODE_CELT_ONLY) ) + ) + { + transition = 1; + /* Decide where to allocate the stack memory for pcm_transition */ + if (mode == MODE_CELT_ONLY) + pcm_transition_celt_size = F5*st->channels; + else + pcm_transition_silk_size = F5*st->channels; + } + ALLOC(pcm_transition_celt, pcm_transition_celt_size, opus_val16); + if (transition && mode == MODE_CELT_ONLY) + { + pcm_transition = pcm_transition_celt; + opus_decode_frame(st, NULL, 0, pcm_transition, IMIN(F5, audiosize), 0); + } + if (audiosize > frame_size) + { + /*fprintf(stderr, "PCM buffer too small: %d vs %d (mode = %d)\n", audiosize, frame_size, mode);*/ + RESTORE_STACK; + return OPUS_BAD_ARG; + } else { + frame_size = audiosize; + } + + /* Don't allocate any memory when in CELT-only mode */ + pcm_silk_size = (mode != MODE_CELT_ONLY && !celt_accum) ? IMAX(F10, frame_size)*st->channels : ALLOC_NONE; + ALLOC(pcm_silk, pcm_silk_size, opus_int16); + + /* SILK processing */ + if (mode != MODE_CELT_ONLY) + { + int lost_flag, decoded_samples; + opus_int16 *pcm_ptr; +#ifdef FIXED_POINT + if (celt_accum) + pcm_ptr = pcm; + else +#endif + pcm_ptr = pcm_silk; + + if (st->prev_mode==MODE_CELT_ONLY) + silk_InitDecoder( silk_dec ); + + /* The SILK PLC cannot produce frames of less than 10 ms */ + st->DecControl.payloadSize_ms = IMAX(10, 1000 * audiosize / st->Fs); + + if (data != NULL) + { + st->DecControl.nChannelsInternal = st->stream_channels; + if( mode == MODE_SILK_ONLY ) { + if( bandwidth == OPUS_BANDWIDTH_NARROWBAND ) { + st->DecControl.internalSampleRate = 8000; + } else if( bandwidth == OPUS_BANDWIDTH_MEDIUMBAND ) { + st->DecControl.internalSampleRate = 12000; + } else if( bandwidth == OPUS_BANDWIDTH_WIDEBAND ) { + st->DecControl.internalSampleRate = 16000; + } else { + st->DecControl.internalSampleRate = 16000; + celt_assert( 0 ); + } + } else { + /* Hybrid mode */ + st->DecControl.internalSampleRate = 16000; + } + } + + lost_flag = data == NULL ? 1 : 2 * decode_fec; + decoded_samples = 0; + do { + /* Call SILK decoder */ + int first_frame = decoded_samples == 0; + silk_ret = silk_Decode( silk_dec, &st->DecControl, + lost_flag, first_frame, &dec, pcm_ptr, &silk_frame_size, st->arch ); + if( silk_ret ) { + if (lost_flag) { + /* PLC failure should not be fatal */ + silk_frame_size = frame_size; + for (i=0;ichannels;i++) + pcm_ptr[i] = 0; + } else { + RESTORE_STACK; + return OPUS_INTERNAL_ERROR; + } + } + pcm_ptr += silk_frame_size * st->channels; + decoded_samples += silk_frame_size; + } while( decoded_samples < frame_size ); + } + + start_band = 0; + if (!decode_fec && mode != MODE_CELT_ONLY && data != NULL + && ec_tell(&dec)+17+20*(st->mode == MODE_HYBRID) <= 8*len) + { + /* Check if we have a redundant 0-8 kHz band */ + if (mode == MODE_HYBRID) + redundancy = ec_dec_bit_logp(&dec, 12); + else + redundancy = 1; + if (redundancy) + { + celt_to_silk = ec_dec_bit_logp(&dec, 1); + /* redundancy_bytes will be at least two, in the non-hybrid + case due to the ec_tell() check above */ + redundancy_bytes = mode==MODE_HYBRID ? + (opus_int32)ec_dec_uint(&dec, 256)+2 : + len-((ec_tell(&dec)+7)>>3); + len -= redundancy_bytes; + /* This is a sanity check. It should never happen for a valid + packet, so the exact behaviour is not normative. */ + if (len*8 < ec_tell(&dec)) + { + len = 0; + redundancy_bytes = 0; + redundancy = 0; + } + /* Shrink decoder because of raw bits */ + dec.storage -= redundancy_bytes; + } + } + if (mode != MODE_CELT_ONLY) + start_band = 17; + + if (redundancy) + { + transition = 0; + pcm_transition_silk_size=ALLOC_NONE; + } + + ALLOC(pcm_transition_silk, pcm_transition_silk_size, opus_val16); + + if (transition && mode != MODE_CELT_ONLY) + { + pcm_transition = pcm_transition_silk; + opus_decode_frame(st, NULL, 0, pcm_transition, IMIN(F5, audiosize), 0); + } + + + if (bandwidth) + { + int endband=21; + + switch(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; + break; + default: + celt_assert(0); + break; + } + MUST_SUCCEED(celt_decoder_ctl(celt_dec, CELT_SET_END_BAND(endband))); + } + MUST_SUCCEED(celt_decoder_ctl(celt_dec, CELT_SET_CHANNELS(st->stream_channels))); + + /* Only allocation memory for redundancy if/when needed */ + redundant_audio_size = redundancy ? F5*st->channels : ALLOC_NONE; + ALLOC(redundant_audio, redundant_audio_size, opus_val16); + + /* 5 ms redundant frame for CELT->SILK*/ + if (redundancy && celt_to_silk) + { + MUST_SUCCEED(celt_decoder_ctl(celt_dec, CELT_SET_START_BAND(0))); + celt_decode_with_ec(celt_dec, data+len, redundancy_bytes, + redundant_audio, F5, NULL, 0); + MUST_SUCCEED(celt_decoder_ctl(celt_dec, OPUS_GET_FINAL_RANGE(&redundant_rng))); + } + + /* MUST be after PLC */ + MUST_SUCCEED(celt_decoder_ctl(celt_dec, CELT_SET_START_BAND(start_band))); + + if (mode != MODE_SILK_ONLY) + { + int celt_frame_size = IMIN(F20, frame_size); + /* Make sure to discard any previous CELT state */ + if (mode != st->prev_mode && st->prev_mode > 0 && !st->prev_redundancy) + MUST_SUCCEED(celt_decoder_ctl(celt_dec, OPUS_RESET_STATE)); + /* Decode CELT */ + celt_ret = celt_decode_with_ec(celt_dec, decode_fec ? NULL : data, + len, pcm, celt_frame_size, &dec, celt_accum); + } else { + unsigned char silence[2] = {0xFF, 0xFF}; + if (!celt_accum) + { + for (i=0;ichannels;i++) + pcm[i] = 0; + } + /* For hybrid -> SILK transitions, we let the CELT MDCT + do a fade-out by decoding a silence frame */ + if (st->prev_mode == MODE_HYBRID && !(redundancy && celt_to_silk && st->prev_redundancy) ) + { + MUST_SUCCEED(celt_decoder_ctl(celt_dec, CELT_SET_START_BAND(0))); + celt_decode_with_ec(celt_dec, silence, 2, pcm, F2_5, NULL, celt_accum); + } + } + + if (mode != MODE_CELT_ONLY && !celt_accum) + { +#ifdef FIXED_POINT + for (i=0;ichannels;i++) + pcm[i] = SAT16(ADD32(pcm[i], pcm_silk[i])); +#else + for (i=0;ichannels;i++) + pcm[i] = pcm[i] + (opus_val16)((1.f/32768.f)*pcm_silk[i]); +#endif + } + + { + const CELTMode *celt_mode; + MUST_SUCCEED(celt_decoder_ctl(celt_dec, CELT_GET_MODE(&celt_mode))); + window = celt_mode->window; + } + + /* 5 ms redundant frame for SILK->CELT */ + if (redundancy && !celt_to_silk) + { + MUST_SUCCEED(celt_decoder_ctl(celt_dec, OPUS_RESET_STATE)); + MUST_SUCCEED(celt_decoder_ctl(celt_dec, CELT_SET_START_BAND(0))); + + celt_decode_with_ec(celt_dec, data+len, redundancy_bytes, redundant_audio, F5, NULL, 0); + MUST_SUCCEED(celt_decoder_ctl(celt_dec, OPUS_GET_FINAL_RANGE(&redundant_rng))); + smooth_fade(pcm+st->channels*(frame_size-F2_5), redundant_audio+st->channels*F2_5, + pcm+st->channels*(frame_size-F2_5), F2_5, st->channels, window, st->Fs); + } + if (redundancy && celt_to_silk) + { + for (c=0;cchannels;c++) + { + for (i=0;ichannels*i+c] = redundant_audio[st->channels*i+c]; + } + smooth_fade(redundant_audio+st->channels*F2_5, pcm+st->channels*F2_5, + pcm+st->channels*F2_5, F2_5, st->channels, window, st->Fs); + } + if (transition) + { + if (audiosize >= F5) + { + for (i=0;ichannels*F2_5;i++) + pcm[i] = pcm_transition[i]; + smooth_fade(pcm_transition+st->channels*F2_5, pcm+st->channels*F2_5, + pcm+st->channels*F2_5, F2_5, + st->channels, window, st->Fs); + } else { + /* Not enough time to do a clean transition, but we do it anyway + This will not preserve amplitude perfectly and may introduce + a bit of temporal aliasing, but it shouldn't be too bad and + that's pretty much the best we can do. In any case, generating this + transition it pretty silly in the first place */ + smooth_fade(pcm_transition, pcm, + pcm, F2_5, + st->channels, window, st->Fs); + } + } + + if(st->decode_gain) + { + opus_val32 gain; + gain = celt_exp2(MULT16_16_P15(QCONST16(6.48814081e-4f, 25), st->decode_gain)); + for (i=0;ichannels;i++) + { + opus_val32 x; + x = MULT16_32_P16(pcm[i],gain); + pcm[i] = SATURATE(x, 32767); + } + } + + if (len <= 1) + st->rangeFinal = 0; + else + st->rangeFinal = dec.rng ^ redundant_rng; + + st->prev_mode = mode; + st->prev_redundancy = redundancy && !celt_to_silk; + + if (celt_ret>=0) + { + if (OPUS_CHECK_ARRAY(pcm, audiosize*st->channels)) + OPUS_PRINT_INT(audiosize); + } + + RESTORE_STACK; + return celt_ret < 0 ? celt_ret : audiosize; + +} + +int opus_decode_native(OpusDecoder *st, const unsigned char *data, + opus_int32 len, opus_val16 *pcm, int frame_size, int decode_fec, + int self_delimited, opus_int32 *packet_offset, int soft_clip) +{ + int i, nb_samples; + int count, offset; + unsigned char toc; + int packet_frame_size, packet_bandwidth, packet_mode, packet_stream_channels; + /* 48 x 2.5 ms = 120 ms */ + opus_int16 size[48]; + VALIDATE_OPUS_DECODER(st); + if (decode_fec<0 || decode_fec>1) + return OPUS_BAD_ARG; + /* For FEC/PLC, frame_size has to be to have a multiple of 2.5 ms */ + if ((decode_fec || len==0 || data==NULL) && frame_size%(st->Fs/400)!=0) + return OPUS_BAD_ARG; + if (len==0 || data==NULL) + { + int pcm_count=0; + do { + int ret; + ret = opus_decode_frame(st, NULL, 0, pcm+pcm_count*st->channels, frame_size-pcm_count, 0); + if (ret<0) + return ret; + pcm_count += ret; + } while (pcm_count < frame_size); + celt_assert(pcm_count == frame_size); + if (OPUS_CHECK_ARRAY(pcm, pcm_count*st->channels)) + OPUS_PRINT_INT(pcm_count); + st->last_packet_duration = pcm_count; + return pcm_count; + } else if (len<0) + return OPUS_BAD_ARG; + + packet_mode = opus_packet_get_mode(data); + packet_bandwidth = opus_packet_get_bandwidth(data); + packet_frame_size = opus_packet_get_samples_per_frame(data, st->Fs); + packet_stream_channels = opus_packet_get_nb_channels(data); + + count = opus_packet_parse_impl(data, len, self_delimited, &toc, NULL, + size, &offset, packet_offset); + if (count<0) + return count; + + data += offset; + + if (decode_fec) + { + int duration_copy; + int ret; + /* If no FEC can be present, run the PLC (recursive call) */ + if (frame_size < packet_frame_size || packet_mode == MODE_CELT_ONLY || st->mode == MODE_CELT_ONLY) + return opus_decode_native(st, NULL, 0, pcm, frame_size, 0, 0, NULL, soft_clip); + /* Otherwise, run the PLC on everything except the size for which we might have FEC */ + duration_copy = st->last_packet_duration; + if (frame_size-packet_frame_size!=0) + { + ret = opus_decode_native(st, NULL, 0, pcm, frame_size-packet_frame_size, 0, 0, NULL, soft_clip); + if (ret<0) + { + st->last_packet_duration = duration_copy; + return ret; + } + celt_assert(ret==frame_size-packet_frame_size); + } + /* Complete with FEC */ + st->mode = packet_mode; + st->bandwidth = packet_bandwidth; + st->frame_size = packet_frame_size; + st->stream_channels = packet_stream_channels; + ret = opus_decode_frame(st, data, size[0], pcm+st->channels*(frame_size-packet_frame_size), + packet_frame_size, 1); + if (ret<0) + return ret; + else { + if (OPUS_CHECK_ARRAY(pcm, frame_size*st->channels)) + OPUS_PRINT_INT(frame_size); + st->last_packet_duration = frame_size; + return frame_size; + } + } + + if (count*packet_frame_size > frame_size) + return OPUS_BUFFER_TOO_SMALL; + + /* Update the state as the last step to avoid updating it on an invalid packet */ + st->mode = packet_mode; + st->bandwidth = packet_bandwidth; + st->frame_size = packet_frame_size; + st->stream_channels = packet_stream_channels; + + nb_samples=0; + for (i=0;ichannels, frame_size-nb_samples, 0); + if (ret<0) + return ret; + celt_assert(ret==packet_frame_size); + data += size[i]; + nb_samples += ret; + } + st->last_packet_duration = nb_samples; + if (OPUS_CHECK_ARRAY(pcm, nb_samples*st->channels)) + OPUS_PRINT_INT(nb_samples); +#ifndef FIXED_POINT + if (soft_clip) + opus_pcm_soft_clip(pcm, nb_samples, st->channels, st->softclip_mem); + else + st->softclip_mem[0]=st->softclip_mem[1]=0; +#endif + return nb_samples; +} + +#ifdef FIXED_POINT + +int opus_decode(OpusDecoder *st, const unsigned char *data, + opus_int32 len, opus_val16 *pcm, int frame_size, int decode_fec) +{ + if(frame_size<=0) + return OPUS_BAD_ARG; + return opus_decode_native(st, data, len, pcm, frame_size, decode_fec, 0, NULL, 0); +} + +#ifndef DISABLE_FLOAT_API +int opus_decode_float(OpusDecoder *st, const unsigned char *data, + opus_int32 len, float *pcm, int frame_size, int decode_fec) +{ + VARDECL(opus_int16, out); + int ret, i; + int nb_samples; + ALLOC_STACK; + + if(frame_size<=0) + { + RESTORE_STACK; + return OPUS_BAD_ARG; + } + if (data != NULL && len > 0 && !decode_fec) + { + nb_samples = opus_decoder_get_nb_samples(st, data, len); + if (nb_samples>0) + frame_size = IMIN(frame_size, nb_samples); + else + return OPUS_INVALID_PACKET; + } + celt_assert(st->channels == 1 || st->channels == 2); + ALLOC(out, frame_size*st->channels, opus_int16); + + ret = opus_decode_native(st, data, len, out, frame_size, decode_fec, 0, NULL, 0); + if (ret > 0) + { + for (i=0;ichannels;i++) + pcm[i] = (1.f/32768.f)*(out[i]); + } + RESTORE_STACK; + return ret; +} +#endif + + +#else +int opus_decode(OpusDecoder *st, const unsigned char *data, + opus_int32 len, opus_int16 *pcm, int frame_size, int decode_fec) +{ + VARDECL(float, out); + int ret, i; + int nb_samples; + ALLOC_STACK; + + if(frame_size<=0) + { + RESTORE_STACK; + return OPUS_BAD_ARG; + } + + if (data != NULL && len > 0 && !decode_fec) + { + nb_samples = opus_decoder_get_nb_samples(st, data, len); + if (nb_samples>0) + frame_size = IMIN(frame_size, nb_samples); + else + return OPUS_INVALID_PACKET; + } + celt_assert(st->channels == 1 || st->channels == 2); + ALLOC(out, frame_size*st->channels, float); + + ret = opus_decode_native(st, data, len, out, frame_size, decode_fec, 0, NULL, 1); + if (ret > 0) + { + for (i=0;ichannels;i++) + pcm[i] = FLOAT2INT16(out[i]); + } + RESTORE_STACK; + return ret; +} + +int opus_decode_float(OpusDecoder *st, const unsigned char *data, + opus_int32 len, opus_val16 *pcm, int frame_size, int decode_fec) +{ + if(frame_size<=0) + return OPUS_BAD_ARG; + return opus_decode_native(st, data, len, pcm, frame_size, decode_fec, 0, NULL, 0); +} + +#endif + +int opus_decoder_ctl(OpusDecoder *st, int request, ...) +{ + int ret = OPUS_OK; + va_list ap; + void *silk_dec; + CELTDecoder *celt_dec; + + silk_dec = (char*)st+st->silk_dec_offset; + celt_dec = (CELTDecoder*)((char*)st+st->celt_dec_offset); + + + va_start(ap, request); + + switch (request) + { + case OPUS_GET_BANDWIDTH_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = st->bandwidth; + } + break; + case OPUS_GET_FINAL_RANGE_REQUEST: + { + opus_uint32 *value = va_arg(ap, opus_uint32*); + if (!value) + { + goto bad_arg; + } + *value = st->rangeFinal; + } + break; + case OPUS_RESET_STATE: + { + OPUS_CLEAR((char*)&st->OPUS_DECODER_RESET_START, + sizeof(OpusDecoder)- + ((char*)&st->OPUS_DECODER_RESET_START - (char*)st)); + + celt_decoder_ctl(celt_dec, OPUS_RESET_STATE); + silk_InitDecoder( silk_dec ); + st->stream_channels = st->channels; + st->frame_size = st->Fs/400; + } + break; + case OPUS_GET_SAMPLE_RATE_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = st->Fs; + } + break; + case OPUS_GET_PITCH_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + if (st->prev_mode == MODE_CELT_ONLY) + ret = celt_decoder_ctl(celt_dec, OPUS_GET_PITCH(value)); + else + *value = st->DecControl.prevPitchLag; + } + break; + case OPUS_GET_GAIN_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = st->decode_gain; + } + break; + case OPUS_SET_GAIN_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if (value<-32768 || value>32767) + { + goto bad_arg; + } + st->decode_gain = value; + } + break; + case OPUS_GET_LAST_PACKET_DURATION_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = st->last_packet_duration; + } + break; + case OPUS_SET_PHASE_INVERSION_DISABLED_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if(value<0 || value>1) + { + goto bad_arg; + } + ret = celt_decoder_ctl(celt_dec, OPUS_SET_PHASE_INVERSION_DISABLED(value)); + } + break; + case OPUS_GET_PHASE_INVERSION_DISABLED_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + ret = celt_decoder_ctl(celt_dec, OPUS_GET_PHASE_INVERSION_DISABLED(value)); + } + break; + default: + /*fprintf(stderr, "unknown opus_decoder_ctl() request: %d", request);*/ + ret = OPUS_UNIMPLEMENTED; + break; + } + + va_end(ap); + return ret; +bad_arg: + va_end(ap); + return OPUS_BAD_ARG; +} + +void opus_decoder_destroy(OpusDecoder *st) +{ + opus_free(st); +} + + +int opus_packet_get_bandwidth(const unsigned char *data) +{ + int bandwidth; + if (data[0]&0x80) + { + bandwidth = OPUS_BANDWIDTH_MEDIUMBAND + ((data[0]>>5)&0x3); + if (bandwidth == OPUS_BANDWIDTH_MEDIUMBAND) + bandwidth = OPUS_BANDWIDTH_NARROWBAND; + } else if ((data[0]&0x60) == 0x60) + { + bandwidth = (data[0]&0x10) ? OPUS_BANDWIDTH_FULLBAND : + OPUS_BANDWIDTH_SUPERWIDEBAND; + } else { + bandwidth = OPUS_BANDWIDTH_NARROWBAND + ((data[0]>>5)&0x3); + } + return bandwidth; +} + +int opus_packet_get_nb_channels(const unsigned char *data) +{ + return (data[0]&0x4) ? 2 : 1; +} + +int opus_packet_get_nb_frames(const unsigned char packet[], opus_int32 len) +{ + int count; + if (len<1) + return OPUS_BAD_ARG; + count = packet[0]&0x3; + if (count==0) + return 1; + else if (count!=3) + return 2; + else if (len<2) + return OPUS_INVALID_PACKET; + else + return packet[1]&0x3F; +} + +int opus_packet_get_nb_samples(const unsigned char packet[], opus_int32 len, + opus_int32 Fs) +{ + int samples; + int count = opus_packet_get_nb_frames(packet, len); + + if (count<0) + return count; + + samples = count*opus_packet_get_samples_per_frame(packet, Fs); + /* Can't have more than 120 ms */ + if (samples*25 > Fs*3) + return OPUS_INVALID_PACKET; + else + return samples; +} + +int opus_decoder_get_nb_samples(const OpusDecoder *dec, + const unsigned char packet[], opus_int32 len) +{ + return opus_packet_get_nb_samples(packet, len, dec->Fs); +} diff --git a/extern/opus/src/opus_demo.c b/extern/opus/src/opus_demo.c new file mode 100644 index 0000000..4cc26a6 --- /dev/null +++ b/extern/opus/src/opus_demo.c @@ -0,0 +1,892 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + 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. + + 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 OWNER + 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. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include "opus.h" +#include "debug.h" +#include "opus_types.h" +#include "opus_private.h" +#include "opus_multistream.h" + +#define MAX_PACKET 1500 + +void print_usage( char* argv[] ) +{ + fprintf(stderr, "Usage: %s [-e] " + " [options] \n", argv[0]); + fprintf(stderr, " %s -d " + "[options] \n\n", argv[0]); + fprintf(stderr, "application: voip | audio | restricted-lowdelay\n" ); + fprintf(stderr, "options:\n" ); + fprintf(stderr, "-e : only runs the encoder (output the bit-stream)\n" ); + fprintf(stderr, "-d : only runs the decoder (reads the bit-stream as input)\n" ); + fprintf(stderr, "-cbr : enable constant bitrate; default: variable bitrate\n" ); + fprintf(stderr, "-cvbr : enable constrained variable bitrate; default: unconstrained\n" ); + fprintf(stderr, "-delayed-decision : use look-ahead for speech/music detection (experts only); default: disabled\n" ); + fprintf(stderr, "-bandwidth : audio bandwidth (from narrowband to fullband); default: sampling rate\n" ); + fprintf(stderr, "-framesize <2.5|5|10|20|40|60|80|100|120> : frame size in ms; default: 20 \n" ); + fprintf(stderr, "-max_payload : maximum payload size in bytes, default: 1024\n" ); + fprintf(stderr, "-complexity : complexity, 0 (lowest) ... 10 (highest); default: 10\n" ); + fprintf(stderr, "-inbandfec : enable SILK inband FEC\n" ); + fprintf(stderr, "-forcemono : force mono encoding, even for stereo input\n" ); + fprintf(stderr, "-dtx : enable SILK DTX\n" ); + fprintf(stderr, "-loss : simulate packet loss, in percent (0-100); default: 0\n" ); +} + +static void int_to_char(opus_uint32 i, unsigned char ch[4]) +{ + ch[0] = i>>24; + ch[1] = (i>>16)&0xFF; + ch[2] = (i>>8)&0xFF; + ch[3] = i&0xFF; +} + +static opus_uint32 char_to_int(unsigned char ch[4]) +{ + return ((opus_uint32)ch[0]<<24) | ((opus_uint32)ch[1]<<16) + | ((opus_uint32)ch[2]<< 8) | (opus_uint32)ch[3]; +} + +#define check_encoder_option(decode_only, opt) do {if (decode_only) {fprintf(stderr, "option %s is only for encoding\n", opt); goto failure;}} while(0) + +static const int silk8_test[][4] = { + {MODE_SILK_ONLY, OPUS_BANDWIDTH_NARROWBAND, 960*3, 1}, + {MODE_SILK_ONLY, OPUS_BANDWIDTH_NARROWBAND, 960*2, 1}, + {MODE_SILK_ONLY, OPUS_BANDWIDTH_NARROWBAND, 960, 1}, + {MODE_SILK_ONLY, OPUS_BANDWIDTH_NARROWBAND, 480, 1}, + {MODE_SILK_ONLY, OPUS_BANDWIDTH_NARROWBAND, 960*3, 2}, + {MODE_SILK_ONLY, OPUS_BANDWIDTH_NARROWBAND, 960*2, 2}, + {MODE_SILK_ONLY, OPUS_BANDWIDTH_NARROWBAND, 960, 2}, + {MODE_SILK_ONLY, OPUS_BANDWIDTH_NARROWBAND, 480, 2} +}; + +static const int silk12_test[][4] = { + {MODE_SILK_ONLY, OPUS_BANDWIDTH_MEDIUMBAND, 960*3, 1}, + {MODE_SILK_ONLY, OPUS_BANDWIDTH_MEDIUMBAND, 960*2, 1}, + {MODE_SILK_ONLY, OPUS_BANDWIDTH_MEDIUMBAND, 960, 1}, + {MODE_SILK_ONLY, OPUS_BANDWIDTH_MEDIUMBAND, 480, 1}, + {MODE_SILK_ONLY, OPUS_BANDWIDTH_MEDIUMBAND, 960*3, 2}, + {MODE_SILK_ONLY, OPUS_BANDWIDTH_MEDIUMBAND, 960*2, 2}, + {MODE_SILK_ONLY, OPUS_BANDWIDTH_MEDIUMBAND, 960, 2}, + {MODE_SILK_ONLY, OPUS_BANDWIDTH_MEDIUMBAND, 480, 2} +}; + +static const int silk16_test[][4] = { + {MODE_SILK_ONLY, OPUS_BANDWIDTH_WIDEBAND, 960*3, 1}, + {MODE_SILK_ONLY, OPUS_BANDWIDTH_WIDEBAND, 960*2, 1}, + {MODE_SILK_ONLY, OPUS_BANDWIDTH_WIDEBAND, 960, 1}, + {MODE_SILK_ONLY, OPUS_BANDWIDTH_WIDEBAND, 480, 1}, + {MODE_SILK_ONLY, OPUS_BANDWIDTH_WIDEBAND, 960*3, 2}, + {MODE_SILK_ONLY, OPUS_BANDWIDTH_WIDEBAND, 960*2, 2}, + {MODE_SILK_ONLY, OPUS_BANDWIDTH_WIDEBAND, 960, 2}, + {MODE_SILK_ONLY, OPUS_BANDWIDTH_WIDEBAND, 480, 2} +}; + +static const int hybrid24_test[][4] = { + {MODE_SILK_ONLY, OPUS_BANDWIDTH_SUPERWIDEBAND, 960, 1}, + {MODE_SILK_ONLY, OPUS_BANDWIDTH_SUPERWIDEBAND, 480, 1}, + {MODE_SILK_ONLY, OPUS_BANDWIDTH_SUPERWIDEBAND, 960, 2}, + {MODE_SILK_ONLY, OPUS_BANDWIDTH_SUPERWIDEBAND, 480, 2} +}; + +static const int hybrid48_test[][4] = { + {MODE_SILK_ONLY, OPUS_BANDWIDTH_FULLBAND, 960, 1}, + {MODE_SILK_ONLY, OPUS_BANDWIDTH_FULLBAND, 480, 1}, + {MODE_SILK_ONLY, OPUS_BANDWIDTH_FULLBAND, 960, 2}, + {MODE_SILK_ONLY, OPUS_BANDWIDTH_FULLBAND, 480, 2} +}; + +static const int celt_test[][4] = { + {MODE_CELT_ONLY, OPUS_BANDWIDTH_FULLBAND, 960, 1}, + {MODE_CELT_ONLY, OPUS_BANDWIDTH_SUPERWIDEBAND, 960, 1}, + {MODE_CELT_ONLY, OPUS_BANDWIDTH_WIDEBAND, 960, 1}, + {MODE_CELT_ONLY, OPUS_BANDWIDTH_NARROWBAND, 960, 1}, + + {MODE_CELT_ONLY, OPUS_BANDWIDTH_FULLBAND, 480, 1}, + {MODE_CELT_ONLY, OPUS_BANDWIDTH_SUPERWIDEBAND, 480, 1}, + {MODE_CELT_ONLY, OPUS_BANDWIDTH_WIDEBAND, 480, 1}, + {MODE_CELT_ONLY, OPUS_BANDWIDTH_NARROWBAND, 480, 1}, + + {MODE_CELT_ONLY, OPUS_BANDWIDTH_FULLBAND, 240, 1}, + {MODE_CELT_ONLY, OPUS_BANDWIDTH_SUPERWIDEBAND, 240, 1}, + {MODE_CELT_ONLY, OPUS_BANDWIDTH_WIDEBAND, 240, 1}, + {MODE_CELT_ONLY, OPUS_BANDWIDTH_NARROWBAND, 240, 1}, + + {MODE_CELT_ONLY, OPUS_BANDWIDTH_FULLBAND, 120, 1}, + {MODE_CELT_ONLY, OPUS_BANDWIDTH_SUPERWIDEBAND, 120, 1}, + {MODE_CELT_ONLY, OPUS_BANDWIDTH_WIDEBAND, 120, 1}, + {MODE_CELT_ONLY, OPUS_BANDWIDTH_NARROWBAND, 120, 1}, + + {MODE_CELT_ONLY, OPUS_BANDWIDTH_FULLBAND, 960, 2}, + {MODE_CELT_ONLY, OPUS_BANDWIDTH_SUPERWIDEBAND, 960, 2}, + {MODE_CELT_ONLY, OPUS_BANDWIDTH_WIDEBAND, 960, 2}, + {MODE_CELT_ONLY, OPUS_BANDWIDTH_NARROWBAND, 960, 2}, + + {MODE_CELT_ONLY, OPUS_BANDWIDTH_FULLBAND, 480, 2}, + {MODE_CELT_ONLY, OPUS_BANDWIDTH_SUPERWIDEBAND, 480, 2}, + {MODE_CELT_ONLY, OPUS_BANDWIDTH_WIDEBAND, 480, 2}, + {MODE_CELT_ONLY, OPUS_BANDWIDTH_NARROWBAND, 480, 2}, + + {MODE_CELT_ONLY, OPUS_BANDWIDTH_FULLBAND, 240, 2}, + {MODE_CELT_ONLY, OPUS_BANDWIDTH_SUPERWIDEBAND, 240, 2}, + {MODE_CELT_ONLY, OPUS_BANDWIDTH_WIDEBAND, 240, 2}, + {MODE_CELT_ONLY, OPUS_BANDWIDTH_NARROWBAND, 240, 2}, + + {MODE_CELT_ONLY, OPUS_BANDWIDTH_FULLBAND, 120, 2}, + {MODE_CELT_ONLY, OPUS_BANDWIDTH_SUPERWIDEBAND, 120, 2}, + {MODE_CELT_ONLY, OPUS_BANDWIDTH_WIDEBAND, 120, 2}, + {MODE_CELT_ONLY, OPUS_BANDWIDTH_NARROWBAND, 120, 2}, + +}; + +static const int celt_hq_test[][4] = { + {MODE_CELT_ONLY, OPUS_BANDWIDTH_FULLBAND, 960, 2}, + {MODE_CELT_ONLY, OPUS_BANDWIDTH_FULLBAND, 480, 2}, + {MODE_CELT_ONLY, OPUS_BANDWIDTH_FULLBAND, 240, 2}, + {MODE_CELT_ONLY, OPUS_BANDWIDTH_FULLBAND, 120, 2}, +}; + +#if 0 /* This is a hack that replaces the normal encoder/decoder with the multistream version */ +#define OpusEncoder OpusMSEncoder +#define OpusDecoder OpusMSDecoder +#define opus_encode opus_multistream_encode +#define opus_decode opus_multistream_decode +#define opus_encoder_ctl opus_multistream_encoder_ctl +#define opus_decoder_ctl opus_multistream_decoder_ctl +#define opus_encoder_create ms_opus_encoder_create +#define opus_decoder_create ms_opus_decoder_create +#define opus_encoder_destroy opus_multistream_encoder_destroy +#define opus_decoder_destroy opus_multistream_decoder_destroy + +static OpusEncoder *ms_opus_encoder_create(opus_int32 Fs, int channels, int application, int *error) +{ + int streams, coupled_streams; + unsigned char mapping[256]; + return (OpusEncoder *)opus_multistream_surround_encoder_create(Fs, channels, 1, &streams, &coupled_streams, mapping, application, error); +} +static OpusDecoder *ms_opus_decoder_create(opus_int32 Fs, int channels, int *error) +{ + int streams; + int coupled_streams; + unsigned char mapping[256]={0,1}; + streams = 1; + coupled_streams = channels==2; + return (OpusDecoder *)opus_multistream_decoder_create(Fs, channels, streams, coupled_streams, mapping, error); +} +#endif + +int main(int argc, char *argv[]) +{ + int err; + char *inFile, *outFile; + FILE *fin=NULL; + FILE *fout=NULL; + OpusEncoder *enc=NULL; + OpusDecoder *dec=NULL; + int args; + int len[2]; + int frame_size, channels; + opus_int32 bitrate_bps=0; + unsigned char *data[2] = {NULL, NULL}; + unsigned char *fbytes=NULL; + opus_int32 sampling_rate; + int use_vbr; + int max_payload_bytes; + int complexity; + int use_inbandfec; + int use_dtx; + int forcechannels; + int cvbr = 0; + int packet_loss_perc; + opus_int32 count=0, count_act=0; + int k; + opus_int32 skip=0; + int stop=0; + short *in=NULL; + short *out=NULL; + int application=OPUS_APPLICATION_AUDIO; + double bits=0.0, bits_max=0.0, bits_act=0.0, bits2=0.0, nrg; + double tot_samples=0; + opus_uint64 tot_in, tot_out; + int bandwidth=OPUS_AUTO; + const char *bandwidth_string; + int lost = 0, lost_prev = 1; + int toggle = 0; + opus_uint32 enc_final_range[2]; + opus_uint32 dec_final_range; + int encode_only=0, decode_only=0; + int max_frame_size = 48000*2; + size_t num_read; + int curr_read=0; + int sweep_bps = 0; + int random_framesize=0, newsize=0, delayed_celt=0; + int sweep_max=0, sweep_min=0; + int random_fec=0; + const int (*mode_list)[4]=NULL; + int nb_modes_in_list=0; + int curr_mode=0; + int curr_mode_count=0; + int mode_switch_time = 48000; + int nb_encoded=0; + int remaining=0; + int variable_duration=OPUS_FRAMESIZE_ARG; + int delayed_decision=0; + int ret = EXIT_FAILURE; + + if (argc < 5 ) + { + print_usage( argv ); + goto failure; + } + + tot_in=tot_out=0; + fprintf(stderr, "%s\n", opus_get_version_string()); + + args = 1; + if (strcmp(argv[args], "-e")==0) + { + encode_only = 1; + args++; + } else if (strcmp(argv[args], "-d")==0) + { + decode_only = 1; + args++; + } + if (!decode_only && argc < 7 ) + { + print_usage( argv ); + goto failure; + } + + if (!decode_only) + { + if (strcmp(argv[args], "voip")==0) + application = OPUS_APPLICATION_VOIP; + else if (strcmp(argv[args], "restricted-lowdelay")==0) + application = OPUS_APPLICATION_RESTRICTED_LOWDELAY; + else if (strcmp(argv[args], "audio")!=0) { + fprintf(stderr, "unknown application: %s\n", argv[args]); + print_usage(argv); + goto failure; + } + args++; + } + sampling_rate = (opus_int32)atol(argv[args]); + args++; + + if (sampling_rate != 8000 && sampling_rate != 12000 + && sampling_rate != 16000 && sampling_rate != 24000 + && sampling_rate != 48000) + { + fprintf(stderr, "Supported sampling rates are 8000, 12000, " + "16000, 24000 and 48000.\n"); + goto failure; + } + frame_size = sampling_rate/50; + + channels = atoi(argv[args]); + args++; + + if (channels < 1 || channels > 2) + { + fprintf(stderr, "Opus_demo supports only 1 or 2 channels.\n"); + goto failure; + } + + if (!decode_only) + { + bitrate_bps = (opus_int32)atol(argv[args]); + args++; + } + + /* defaults: */ + use_vbr = 1; + max_payload_bytes = MAX_PACKET; + complexity = 10; + use_inbandfec = 0; + forcechannels = OPUS_AUTO; + use_dtx = 0; + packet_loss_perc = 0; + + while( args < argc - 2 ) { + /* process command line options */ + if( strcmp( argv[ args ], "-cbr" ) == 0 ) { + check_encoder_option(decode_only, "-cbr"); + use_vbr = 0; + args++; + } else if( strcmp( argv[ args ], "-bandwidth" ) == 0 ) { + check_encoder_option(decode_only, "-bandwidth"); + if (strcmp(argv[ args + 1 ], "NB")==0) + bandwidth = OPUS_BANDWIDTH_NARROWBAND; + else if (strcmp(argv[ args + 1 ], "MB")==0) + bandwidth = OPUS_BANDWIDTH_MEDIUMBAND; + else if (strcmp(argv[ args + 1 ], "WB")==0) + bandwidth = OPUS_BANDWIDTH_WIDEBAND; + else if (strcmp(argv[ args + 1 ], "SWB")==0) + bandwidth = OPUS_BANDWIDTH_SUPERWIDEBAND; + else if (strcmp(argv[ args + 1 ], "FB")==0) + bandwidth = OPUS_BANDWIDTH_FULLBAND; + else { + fprintf(stderr, "Unknown bandwidth %s. " + "Supported are NB, MB, WB, SWB, FB.\n", + argv[ args + 1 ]); + goto failure; + } + args += 2; + } else if( strcmp( argv[ args ], "-framesize" ) == 0 ) { + check_encoder_option(decode_only, "-framesize"); + if (strcmp(argv[ args + 1 ], "2.5")==0) + frame_size = sampling_rate/400; + else if (strcmp(argv[ args + 1 ], "5")==0) + frame_size = sampling_rate/200; + else if (strcmp(argv[ args + 1 ], "10")==0) + frame_size = sampling_rate/100; + else if (strcmp(argv[ args + 1 ], "20")==0) + frame_size = sampling_rate/50; + else if (strcmp(argv[ args + 1 ], "40")==0) + frame_size = sampling_rate/25; + else if (strcmp(argv[ args + 1 ], "60")==0) + frame_size = 3*sampling_rate/50; + else if (strcmp(argv[ args + 1 ], "80")==0) + frame_size = 4*sampling_rate/50; + else if (strcmp(argv[ args + 1 ], "100")==0) + frame_size = 5*sampling_rate/50; + else if (strcmp(argv[ args + 1 ], "120")==0) + frame_size = 6*sampling_rate/50; + else { + fprintf(stderr, "Unsupported frame size: %s ms. " + "Supported are 2.5, 5, 10, 20, 40, 60, 80, 100, 120.\n", + argv[ args + 1 ]); + goto failure; + } + args += 2; + } else if( strcmp( argv[ args ], "-max_payload" ) == 0 ) { + check_encoder_option(decode_only, "-max_payload"); + max_payload_bytes = atoi( argv[ args + 1 ] ); + args += 2; + } else if( strcmp( argv[ args ], "-complexity" ) == 0 ) { + check_encoder_option(decode_only, "-complexity"); + complexity = atoi( argv[ args + 1 ] ); + args += 2; + } else if( strcmp( argv[ args ], "-inbandfec" ) == 0 ) { + use_inbandfec = 1; + args++; + } else if( strcmp( argv[ args ], "-forcemono" ) == 0 ) { + check_encoder_option(decode_only, "-forcemono"); + forcechannels = 1; + args++; + } else if( strcmp( argv[ args ], "-cvbr" ) == 0 ) { + check_encoder_option(decode_only, "-cvbr"); + cvbr = 1; + args++; + } else if( strcmp( argv[ args ], "-delayed-decision" ) == 0 ) { + check_encoder_option(decode_only, "-delayed-decision"); + delayed_decision = 1; + args++; + } else if( strcmp( argv[ args ], "-dtx") == 0 ) { + check_encoder_option(decode_only, "-dtx"); + use_dtx = 1; + args++; + } else if( strcmp( argv[ args ], "-loss" ) == 0 ) { + packet_loss_perc = atoi( argv[ args + 1 ] ); + args += 2; + } else if( strcmp( argv[ args ], "-sweep" ) == 0 ) { + check_encoder_option(decode_only, "-sweep"); + sweep_bps = atoi( argv[ args + 1 ] ); + args += 2; + } else if( strcmp( argv[ args ], "-random_framesize" ) == 0 ) { + check_encoder_option(decode_only, "-random_framesize"); + random_framesize = 1; + args++; + } else if( strcmp( argv[ args ], "-sweep_max" ) == 0 ) { + check_encoder_option(decode_only, "-sweep_max"); + sweep_max = atoi( argv[ args + 1 ] ); + args += 2; + } else if( strcmp( argv[ args ], "-random_fec" ) == 0 ) { + check_encoder_option(decode_only, "-random_fec"); + random_fec = 1; + args++; + } else if( strcmp( argv[ args ], "-silk8k_test" ) == 0 ) { + check_encoder_option(decode_only, "-silk8k_test"); + mode_list = silk8_test; + nb_modes_in_list = 8; + args++; + } else if( strcmp( argv[ args ], "-silk12k_test" ) == 0 ) { + check_encoder_option(decode_only, "-silk12k_test"); + mode_list = silk12_test; + nb_modes_in_list = 8; + args++; + } else if( strcmp( argv[ args ], "-silk16k_test" ) == 0 ) { + check_encoder_option(decode_only, "-silk16k_test"); + mode_list = silk16_test; + nb_modes_in_list = 8; + args++; + } else if( strcmp( argv[ args ], "-hybrid24k_test" ) == 0 ) { + check_encoder_option(decode_only, "-hybrid24k_test"); + mode_list = hybrid24_test; + nb_modes_in_list = 4; + args++; + } else if( strcmp( argv[ args ], "-hybrid48k_test" ) == 0 ) { + check_encoder_option(decode_only, "-hybrid48k_test"); + mode_list = hybrid48_test; + nb_modes_in_list = 4; + args++; + } else if( strcmp( argv[ args ], "-celt_test" ) == 0 ) { + check_encoder_option(decode_only, "-celt_test"); + mode_list = celt_test; + nb_modes_in_list = 32; + args++; + } else if( strcmp( argv[ args ], "-celt_hq_test" ) == 0 ) { + check_encoder_option(decode_only, "-celt_hq_test"); + mode_list = celt_hq_test; + nb_modes_in_list = 4; + args++; + } else { + printf( "Error: unrecognized setting: %s\n\n", argv[ args ] ); + print_usage( argv ); + goto failure; + } + } + + if (sweep_max) + sweep_min = bitrate_bps; + + if (max_payload_bytes < 0 || max_payload_bytes > MAX_PACKET) + { + fprintf (stderr, "max_payload_bytes must be between 0 and %d\n", + MAX_PACKET); + goto failure; + } + + inFile = argv[argc-2]; + fin = fopen(inFile, "rb"); + if (!fin) + { + fprintf (stderr, "Could not open input file %s\n", argv[argc-2]); + goto failure; + } + if (mode_list) + { + int size; + fseek(fin, 0, SEEK_END); + size = ftell(fin); + fprintf(stderr, "File size is %d bytes\n", size); + fseek(fin, 0, SEEK_SET); + mode_switch_time = size/sizeof(short)/channels/nb_modes_in_list; + fprintf(stderr, "Switching mode every %d samples\n", mode_switch_time); + } + + outFile = argv[argc-1]; + fout = fopen(outFile, "wb+"); + if (!fout) + { + fprintf (stderr, "Could not open output file %s\n", argv[argc-1]); + goto failure; + } + + if (!decode_only) + { + enc = opus_encoder_create(sampling_rate, channels, application, &err); + if (err != OPUS_OK) + { + fprintf(stderr, "Cannot create encoder: %s\n", opus_strerror(err)); + goto failure; + } + opus_encoder_ctl(enc, OPUS_SET_BITRATE(bitrate_bps)); + opus_encoder_ctl(enc, OPUS_SET_BANDWIDTH(bandwidth)); + opus_encoder_ctl(enc, OPUS_SET_VBR(use_vbr)); + opus_encoder_ctl(enc, OPUS_SET_VBR_CONSTRAINT(cvbr)); + opus_encoder_ctl(enc, OPUS_SET_COMPLEXITY(complexity)); + opus_encoder_ctl(enc, OPUS_SET_INBAND_FEC(use_inbandfec)); + opus_encoder_ctl(enc, OPUS_SET_FORCE_CHANNELS(forcechannels)); + opus_encoder_ctl(enc, OPUS_SET_DTX(use_dtx)); + opus_encoder_ctl(enc, OPUS_SET_PACKET_LOSS_PERC(packet_loss_perc)); + + opus_encoder_ctl(enc, OPUS_GET_LOOKAHEAD(&skip)); + opus_encoder_ctl(enc, OPUS_SET_LSB_DEPTH(16)); + opus_encoder_ctl(enc, OPUS_SET_EXPERT_FRAME_DURATION(variable_duration)); + } + if (!encode_only) + { + dec = opus_decoder_create(sampling_rate, channels, &err); + if (err != OPUS_OK) + { + fprintf(stderr, "Cannot create decoder: %s\n", opus_strerror(err)); + goto failure; + } + } + + + switch(bandwidth) + { + case OPUS_BANDWIDTH_NARROWBAND: + bandwidth_string = "narrowband"; + break; + case OPUS_BANDWIDTH_MEDIUMBAND: + bandwidth_string = "mediumband"; + break; + case OPUS_BANDWIDTH_WIDEBAND: + bandwidth_string = "wideband"; + break; + case OPUS_BANDWIDTH_SUPERWIDEBAND: + bandwidth_string = "superwideband"; + break; + case OPUS_BANDWIDTH_FULLBAND: + bandwidth_string = "fullband"; + break; + case OPUS_AUTO: + bandwidth_string = "auto bandwidth"; + break; + default: + bandwidth_string = "unknown"; + break; + } + + if (decode_only) + fprintf(stderr, "Decoding with %ld Hz output (%d channels)\n", + (long)sampling_rate, channels); + else + fprintf(stderr, "Encoding %ld Hz input at %.3f kb/s " + "in %s with %d-sample frames.\n", + (long)sampling_rate, bitrate_bps*0.001, + bandwidth_string, frame_size); + + in = (short*)malloc(max_frame_size*channels*sizeof(short)); + out = (short*)malloc(max_frame_size*channels*sizeof(short)); + /* We need to allocate for 16-bit PCM data, but we store it as unsigned char. */ + fbytes = (unsigned char*)malloc(max_frame_size*channels*sizeof(short)); + data[0] = (unsigned char*)calloc(max_payload_bytes,sizeof(unsigned char)); + if ( use_inbandfec ) { + data[1] = (unsigned char*)calloc(max_payload_bytes,sizeof(unsigned char)); + } + if(delayed_decision) + { + if (frame_size==sampling_rate/400) + variable_duration = OPUS_FRAMESIZE_2_5_MS; + else if (frame_size==sampling_rate/200) + variable_duration = OPUS_FRAMESIZE_5_MS; + else if (frame_size==sampling_rate/100) + variable_duration = OPUS_FRAMESIZE_10_MS; + else if (frame_size==sampling_rate/50) + variable_duration = OPUS_FRAMESIZE_20_MS; + else if (frame_size==sampling_rate/25) + variable_duration = OPUS_FRAMESIZE_40_MS; + else if (frame_size==3*sampling_rate/50) + variable_duration = OPUS_FRAMESIZE_60_MS; + else if (frame_size==4*sampling_rate/50) + variable_duration = OPUS_FRAMESIZE_80_MS; + else if (frame_size==5*sampling_rate/50) + variable_duration = OPUS_FRAMESIZE_100_MS; + else + variable_duration = OPUS_FRAMESIZE_120_MS; + opus_encoder_ctl(enc, OPUS_SET_EXPERT_FRAME_DURATION(variable_duration)); + frame_size = 2*48000; + } + while (!stop) + { + if (delayed_celt) + { + frame_size = newsize; + delayed_celt = 0; + } else if (random_framesize && rand()%20==0) + { + newsize = rand()%6; + switch(newsize) + { + case 0: newsize=sampling_rate/400; break; + case 1: newsize=sampling_rate/200; break; + case 2: newsize=sampling_rate/100; break; + case 3: newsize=sampling_rate/50; break; + case 4: newsize=sampling_rate/25; break; + case 5: newsize=3*sampling_rate/50; break; + } + while (newsize < sampling_rate/25 && bitrate_bps-abs(sweep_bps) <= 3*12*sampling_rate/newsize) + newsize*=2; + if (newsize < sampling_rate/100 && frame_size >= sampling_rate/100) + { + opus_encoder_ctl(enc, OPUS_SET_FORCE_MODE(MODE_CELT_ONLY)); + delayed_celt=1; + } else { + frame_size = newsize; + } + } + if (random_fec && rand()%30==0) + { + opus_encoder_ctl(enc, OPUS_SET_INBAND_FEC(rand()%4==0)); + } + if (decode_only) + { + unsigned char ch[4]; + num_read = fread(ch, 1, 4, fin); + if (num_read!=4) + break; + len[toggle] = char_to_int(ch); + if (len[toggle]>max_payload_bytes || len[toggle]<0) + { + fprintf(stderr, "Invalid payload length: %d\n",len[toggle]); + break; + } + num_read = fread(ch, 1, 4, fin); + if (num_read!=4) + break; + enc_final_range[toggle] = char_to_int(ch); + num_read = fread(data[toggle], 1, len[toggle], fin); + if (num_read!=(size_t)len[toggle]) + { + fprintf(stderr, "Ran out of input, " + "expecting %d bytes got %d\n", + len[toggle],(int)num_read); + break; + } + } else { + int i; + if (mode_list!=NULL) + { + opus_encoder_ctl(enc, OPUS_SET_BANDWIDTH(mode_list[curr_mode][1])); + opus_encoder_ctl(enc, OPUS_SET_FORCE_MODE(mode_list[curr_mode][0])); + opus_encoder_ctl(enc, OPUS_SET_FORCE_CHANNELS(mode_list[curr_mode][3])); + frame_size = mode_list[curr_mode][2]; + } + num_read = fread(fbytes, sizeof(short)*channels, frame_size-remaining, fin); + curr_read = (int)num_read; + tot_in += curr_read; + for(i=0;i sweep_max) + sweep_bps = -sweep_bps; + else if (bitrate_bps < sweep_min) + sweep_bps = -sweep_bps; + } + /* safety */ + if (bitrate_bps<1000) + bitrate_bps = 1000; + opus_encoder_ctl(enc, OPUS_SET_BITRATE(bitrate_bps)); + } + opus_encoder_ctl(enc, OPUS_GET_FINAL_RANGE(&enc_final_range[toggle])); + if (len[toggle] < 0) + { + fprintf (stderr, "opus_encode() returned %d\n", len[toggle]); + goto failure; + } + curr_mode_count += frame_size; + if (curr_mode_count > mode_switch_time && curr_mode < nb_modes_in_list-1) + { + curr_mode++; + curr_mode_count = 0; + } + } + +#if 0 /* This is for testing the padding code, do not enable by default */ + if (len[toggle]<1275) + { + int new_len = len[toggle]+rand()%(max_payload_bytes-len[toggle]); + if ((err = opus_packet_pad(data[toggle], len[toggle], new_len)) != OPUS_OK) + { + fprintf(stderr, "padding failed: %s\n", opus_strerror(err)); + goto failure; + } + len[toggle] = new_len; + } +#endif + if (encode_only) + { + unsigned char int_field[4]; + int_to_char(len[toggle], int_field); + if (fwrite(int_field, 1, 4, fout) != 4) { + fprintf(stderr, "Error writing.\n"); + goto failure; + } + int_to_char(enc_final_range[toggle], int_field); + if (fwrite(int_field, 1, 4, fout) != 4) { + fprintf(stderr, "Error writing.\n"); + goto failure; + } + if (fwrite(data[toggle], 1, len[toggle], fout) != (unsigned)len[toggle]) { + fprintf(stderr, "Error writing.\n"); + goto failure; + } + tot_samples += nb_encoded; + } else { + opus_int32 output_samples; + lost = len[toggle]==0 || (packet_loss_perc>0 && rand()%100 < packet_loss_perc); + if (lost) + opus_decoder_ctl(dec, OPUS_GET_LAST_PACKET_DURATION(&output_samples)); + else + output_samples = max_frame_size; + if( count >= use_inbandfec ) { + /* delay by one packet when using in-band FEC */ + if( use_inbandfec ) { + if( lost_prev ) { + /* attempt to decode with in-band FEC from next packet */ + opus_decoder_ctl(dec, OPUS_GET_LAST_PACKET_DURATION(&output_samples)); + output_samples = opus_decode(dec, lost ? NULL : data[toggle], len[toggle], out, output_samples, 1); + } else { + /* regular decode */ + output_samples = max_frame_size; + output_samples = opus_decode(dec, data[1-toggle], len[1-toggle], out, output_samples, 0); + } + } else { + output_samples = opus_decode(dec, lost ? NULL : data[toggle], len[toggle], out, output_samples, 0); + } + if (output_samples>0) + { + if (!decode_only && tot_out + output_samples > tot_in) + { + stop=1; + output_samples = (opus_int32)(tot_in - tot_out); + } + if (output_samples>skip) { + int i; + for(i=0;i<(output_samples-skip)*channels;i++) + { + short s; + s=out[i+(skip*channels)]; + fbytes[2*i]=s&0xFF; + fbytes[2*i+1]=(s>>8)&0xFF; + } + if (fwrite(fbytes, sizeof(short)*channels, output_samples-skip, fout) != (unsigned)(output_samples-skip)){ + fprintf(stderr, "Error writing.\n"); + goto failure; + } + tot_out += output_samples-skip; + } + if (output_samples= use_inbandfec ) { + /* count bits */ + bits += len[toggle]*8; + bits_max = ( len[toggle]*8 > bits_max ) ? len[toggle]*8 : bits_max; + bits2 += len[toggle]*len[toggle]*64; + if (!decode_only) + { + nrg = 0.0; + for ( k = 0; k < frame_size * channels; k++ ) { + nrg += in[ k ] * (double)in[ k ]; + } + nrg /= frame_size * channels; + if( nrg > 1e5 ) { + bits_act += len[toggle]*8; + count_act++; + } + } + } + count++; + toggle = (toggle + use_inbandfec) & 1; + } + + if(decode_only && count > 0) + frame_size = (int)(tot_samples / count); + count -= use_inbandfec; + if (tot_samples >= 1 && count > 0 && frame_size) + { + /* Print out bitrate statistics */ + double var; + fprintf (stderr, "average bitrate: %7.3f kb/s\n", + 1e-3*bits*sampling_rate/tot_samples); + fprintf (stderr, "maximum bitrate: %7.3f kb/s\n", + 1e-3*bits_max*sampling_rate/frame_size); + if (!decode_only) + fprintf (stderr, "active bitrate: %7.3f kb/s\n", + 1e-3*bits_act*sampling_rate/(1e-15+frame_size*(double)count_act)); + var = bits2/count - bits*bits/(count*(double)count); + if (var < 0) + var = 0; + fprintf (stderr, "bitrate standard deviation: %7.3f kb/s\n", + 1e-3*sqrt(var)*sampling_rate/frame_size); + } else { + fprintf(stderr, "bitrate statistics are undefined\n"); + } + silk_TimerSave("opus_timing.txt"); + ret = EXIT_SUCCESS; +failure: + opus_encoder_destroy(enc); + opus_decoder_destroy(dec); + free(data[0]); + free(data[1]); + if (fin) + fclose(fin); + if (fout) + fclose(fout); + free(in); + free(out); + free(fbytes); + return ret; +} diff --git a/extern/opus/src/opus_encoder.c b/extern/opus/src/opus_encoder.c new file mode 100644 index 0000000..e98ac5b --- /dev/null +++ b/extern/opus/src/opus_encoder.c @@ -0,0 +1,2783 @@ +/* Copyright (c) 2010-2011 Xiph.Org Foundation, Skype Limited + Written by Jean-Marc Valin and Koen Vos */ +/* + 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. + + 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 OWNER + 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. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "celt.h" +#include "entenc.h" +#include "modes.h" +#include "API.h" +#include "stack_alloc.h" +#include "float_cast.h" +#include "opus.h" +#include "arch.h" +#include "pitch.h" +#include "opus_private.h" +#include "os_support.h" +#include "cpu_support.h" +#include "analysis.h" +#include "mathops.h" +#include "tuning_parameters.h" +#ifdef FIXED_POINT +#include "fixed/structs_FIX.h" +#else +#include "float/structs_FLP.h" +#endif + +#define MAX_ENCODER_BUFFER 480 + +#ifndef DISABLE_FLOAT_API +#define PSEUDO_SNR_THRESHOLD 316.23f /* 10^(25/10) */ +#endif + +typedef struct { + opus_val32 XX, XY, YY; + opus_val16 smoothed_width; + opus_val16 max_follower; +} StereoWidthState; + +struct OpusEncoder { + int celt_enc_offset; + int silk_enc_offset; + silk_EncControlStruct silk_mode; + int application; + int channels; + int delay_compensation; + int force_channels; + int signal_type; + int user_bandwidth; + int max_bandwidth; + int user_forced_mode; + int voice_ratio; + opus_int32 Fs; + int use_vbr; + int vbr_constraint; + int variable_duration; + opus_int32 bitrate_bps; + opus_int32 user_bitrate_bps; + int lsb_depth; + int encoder_buffer; + int lfe; + int arch; + int use_dtx; /* general DTX for both SILK and CELT */ +#ifndef DISABLE_FLOAT_API + TonalityAnalysisState analysis; +#endif + +#define OPUS_ENCODER_RESET_START stream_channels + int stream_channels; + opus_int16 hybrid_stereo_width_Q14; + opus_int32 variable_HP_smth2_Q15; + opus_val16 prev_HB_gain; + opus_val32 hp_mem[4]; + int mode; + int prev_mode; + int prev_channels; + int prev_framesize; + int bandwidth; + /* Bandwidth determined automatically from the rate (before any other adjustment) */ + int auto_bandwidth; + int silk_bw_switch; + /* Sampling rate (at the API level) */ + int first; + opus_val16 * energy_masking; + StereoWidthState width_mem; + opus_val16 delay_buffer[MAX_ENCODER_BUFFER*2]; +#ifndef DISABLE_FLOAT_API + int detected_bandwidth; + int nb_no_activity_frames; + opus_val32 peak_signal_energy; +#endif + int nonfinal_frame; /* current frame is not the final in a packet */ + opus_uint32 rangeFinal; +}; + +/* Transition tables for the voice and music. First column is the + middle (memoriless) threshold. The second column is the hysteresis + (difference with the middle) */ +static const opus_int32 mono_voice_bandwidth_thresholds[8] = { + 9000, 700, /* NB<->MB */ + 9000, 700, /* MB<->WB */ + 13500, 1000, /* WB<->SWB */ + 14000, 2000, /* SWB<->FB */ +}; +static const opus_int32 mono_music_bandwidth_thresholds[8] = { + 9000, 700, /* NB<->MB */ + 9000, 700, /* MB<->WB */ + 11000, 1000, /* WB<->SWB */ + 12000, 2000, /* SWB<->FB */ +}; +static const opus_int32 stereo_voice_bandwidth_thresholds[8] = { + 9000, 700, /* NB<->MB */ + 9000, 700, /* MB<->WB */ + 13500, 1000, /* WB<->SWB */ + 14000, 2000, /* SWB<->FB */ +}; +static const opus_int32 stereo_music_bandwidth_thresholds[8] = { + 9000, 700, /* NB<->MB */ + 9000, 700, /* MB<->WB */ + 11000, 1000, /* WB<->SWB */ + 12000, 2000, /* SWB<->FB */ +}; +/* Threshold bit-rates for switching between mono and stereo */ +static const opus_int32 stereo_voice_threshold = 19000; +static const opus_int32 stereo_music_threshold = 17000; + +/* Threshold bit-rate for switching between SILK/hybrid and CELT-only */ +static const opus_int32 mode_thresholds[2][2] = { + /* voice */ /* music */ + { 64000, 10000}, /* mono */ + { 44000, 10000}, /* stereo */ +}; + +static const opus_int32 fec_thresholds[] = { + 12000, 1000, /* NB */ + 14000, 1000, /* MB */ + 16000, 1000, /* WB */ + 20000, 1000, /* SWB */ + 22000, 1000, /* FB */ +}; + +int opus_encoder_get_size(int channels) +{ + int silkEncSizeBytes, celtEncSizeBytes; + int ret; + if (channels<1 || channels > 2) + return 0; + ret = silk_Get_Encoder_Size( &silkEncSizeBytes ); + if (ret) + return 0; + silkEncSizeBytes = align(silkEncSizeBytes); + celtEncSizeBytes = celt_encoder_get_size(channels); + return align(sizeof(OpusEncoder))+silkEncSizeBytes+celtEncSizeBytes; +} + +int opus_encoder_init(OpusEncoder* st, opus_int32 Fs, int channels, int application) +{ + void *silk_enc; + CELTEncoder *celt_enc; + int err; + int ret, silkEncSizeBytes; + + if((Fs!=48000&&Fs!=24000&&Fs!=16000&&Fs!=12000&&Fs!=8000)||(channels!=1&&channels!=2)|| + (application != OPUS_APPLICATION_VOIP && application != OPUS_APPLICATION_AUDIO + && application != OPUS_APPLICATION_RESTRICTED_LOWDELAY)) + return OPUS_BAD_ARG; + + OPUS_CLEAR((char*)st, opus_encoder_get_size(channels)); + /* Create SILK encoder */ + ret = silk_Get_Encoder_Size( &silkEncSizeBytes ); + if (ret) + return OPUS_BAD_ARG; + silkEncSizeBytes = align(silkEncSizeBytes); + st->silk_enc_offset = align(sizeof(OpusEncoder)); + st->celt_enc_offset = st->silk_enc_offset+silkEncSizeBytes; + silk_enc = (char*)st+st->silk_enc_offset; + celt_enc = (CELTEncoder*)((char*)st+st->celt_enc_offset); + + st->stream_channels = st->channels = channels; + + st->Fs = Fs; + + st->arch = opus_select_arch(); + + ret = silk_InitEncoder( silk_enc, st->arch, &st->silk_mode ); + if(ret)return OPUS_INTERNAL_ERROR; + + /* default SILK parameters */ + st->silk_mode.nChannelsAPI = channels; + st->silk_mode.nChannelsInternal = channels; + st->silk_mode.API_sampleRate = st->Fs; + st->silk_mode.maxInternalSampleRate = 16000; + st->silk_mode.minInternalSampleRate = 8000; + st->silk_mode.desiredInternalSampleRate = 16000; + st->silk_mode.payloadSize_ms = 20; + st->silk_mode.bitRate = 25000; + st->silk_mode.packetLossPercentage = 0; + st->silk_mode.complexity = 9; + st->silk_mode.useInBandFEC = 0; + st->silk_mode.useDTX = 0; + st->silk_mode.useCBR = 0; + st->silk_mode.reducedDependency = 0; + + /* Create CELT encoder */ + /* Initialize CELT encoder */ + err = celt_encoder_init(celt_enc, Fs, channels, st->arch); + if(err!=OPUS_OK)return OPUS_INTERNAL_ERROR; + + celt_encoder_ctl(celt_enc, CELT_SET_SIGNALLING(0)); + celt_encoder_ctl(celt_enc, OPUS_SET_COMPLEXITY(st->silk_mode.complexity)); + + st->use_vbr = 1; + /* Makes constrained VBR the default (safer for real-time use) */ + st->vbr_constraint = 1; + st->user_bitrate_bps = OPUS_AUTO; + st->bitrate_bps = 3000+Fs*channels; + st->application = application; + st->signal_type = OPUS_AUTO; + st->user_bandwidth = OPUS_AUTO; + st->max_bandwidth = OPUS_BANDWIDTH_FULLBAND; + st->force_channels = OPUS_AUTO; + st->user_forced_mode = OPUS_AUTO; + st->voice_ratio = -1; + st->encoder_buffer = st->Fs/100; + st->lsb_depth = 24; + st->variable_duration = OPUS_FRAMESIZE_ARG; + + /* Delay compensation of 4 ms (2.5 ms for SILK's extra look-ahead + + 1.5 ms for SILK resamplers and stereo prediction) */ + st->delay_compensation = st->Fs/250; + + st->hybrid_stereo_width_Q14 = 1 << 14; + st->prev_HB_gain = Q15ONE; + st->variable_HP_smth2_Q15 = silk_LSHIFT( silk_lin2log( VARIABLE_HP_MIN_CUTOFF_HZ ), 8 ); + st->first = 1; + st->mode = MODE_HYBRID; + st->bandwidth = OPUS_BANDWIDTH_FULLBAND; + +#ifndef DISABLE_FLOAT_API + tonality_analysis_init(&st->analysis, st->Fs); + st->analysis.application = st->application; +#endif + + return OPUS_OK; +} + +static unsigned char gen_toc(int mode, int framerate, int bandwidth, int channels) +{ + int period; + unsigned char toc; + period = 0; + while (framerate < 400) + { + framerate <<= 1; + period++; + } + if (mode == MODE_SILK_ONLY) + { + toc = (bandwidth-OPUS_BANDWIDTH_NARROWBAND)<<5; + toc |= (period-2)<<3; + } else if (mode == MODE_CELT_ONLY) + { + int tmp = bandwidth-OPUS_BANDWIDTH_MEDIUMBAND; + if (tmp < 0) + tmp = 0; + toc = 0x80; + toc |= tmp << 5; + toc |= period<<3; + } else /* Hybrid */ + { + toc = 0x60; + toc |= (bandwidth-OPUS_BANDWIDTH_SUPERWIDEBAND)<<4; + toc |= (period-2)<<3; + } + toc |= (channels==2)<<2; + return toc; +} + +#ifndef FIXED_POINT +static void silk_biquad_float( + const opus_val16 *in, /* I: Input signal */ + const opus_int32 *B_Q28, /* I: MA coefficients [3] */ + const opus_int32 *A_Q28, /* I: AR coefficients [2] */ + opus_val32 *S, /* I/O: State vector [2] */ + opus_val16 *out, /* O: Output signal */ + const opus_int32 len, /* I: Signal length (must be even) */ + int stride +) +{ + /* DIRECT FORM II TRANSPOSED (uses 2 element state vector) */ + opus_int k; + opus_val32 vout; + opus_val32 inval; + opus_val32 A[2], B[3]; + + A[0] = (opus_val32)(A_Q28[0] * (1.f/((opus_int32)1<<28))); + A[1] = (opus_val32)(A_Q28[1] * (1.f/((opus_int32)1<<28))); + B[0] = (opus_val32)(B_Q28[0] * (1.f/((opus_int32)1<<28))); + B[1] = (opus_val32)(B_Q28[1] * (1.f/((opus_int32)1<<28))); + B[2] = (opus_val32)(B_Q28[2] * (1.f/((opus_int32)1<<28))); + + /* Negate A_Q28 values and split in two parts */ + + for( k = 0; k < len; k++ ) { + /* S[ 0 ], S[ 1 ]: Q12 */ + inval = in[ k*stride ]; + vout = S[ 0 ] + B[0]*inval; + + S[ 0 ] = S[1] - vout*A[0] + B[1]*inval; + + S[ 1 ] = - vout*A[1] + B[2]*inval + VERY_SMALL; + + /* Scale back to Q0 and saturate */ + out[ k*stride ] = vout; + } +} +#endif + +static void hp_cutoff(const opus_val16 *in, opus_int32 cutoff_Hz, opus_val16 *out, opus_val32 *hp_mem, int len, int channels, opus_int32 Fs, int arch) +{ + opus_int32 B_Q28[ 3 ], A_Q28[ 2 ]; + opus_int32 Fc_Q19, r_Q28, r_Q22; + (void)arch; + + silk_assert( cutoff_Hz <= silk_int32_MAX / SILK_FIX_CONST( 1.5 * 3.14159 / 1000, 19 ) ); + Fc_Q19 = silk_DIV32_16( silk_SMULBB( SILK_FIX_CONST( 1.5 * 3.14159 / 1000, 19 ), cutoff_Hz ), Fs/1000 ); + silk_assert( Fc_Q19 > 0 && Fc_Q19 < 32768 ); + + r_Q28 = SILK_FIX_CONST( 1.0, 28 ) - silk_MUL( SILK_FIX_CONST( 0.92, 9 ), Fc_Q19 ); + + /* b = r * [ 1; -2; 1 ]; */ + /* a = [ 1; -2 * r * ( 1 - 0.5 * Fc^2 ); r^2 ]; */ + B_Q28[ 0 ] = r_Q28; + B_Q28[ 1 ] = silk_LSHIFT( -r_Q28, 1 ); + B_Q28[ 2 ] = r_Q28; + + /* -r * ( 2 - Fc * Fc ); */ + r_Q22 = silk_RSHIFT( r_Q28, 6 ); + A_Q28[ 0 ] = silk_SMULWW( r_Q22, silk_SMULWW( Fc_Q19, Fc_Q19 ) - SILK_FIX_CONST( 2.0, 22 ) ); + A_Q28[ 1 ] = silk_SMULWW( r_Q22, r_Q22 ); + +#ifdef FIXED_POINT + if( channels == 1 ) { + silk_biquad_alt_stride1( in, B_Q28, A_Q28, hp_mem, out, len ); + } else { + silk_biquad_alt_stride2( in, B_Q28, A_Q28, hp_mem, out, len, arch ); + } +#else + silk_biquad_float( in, B_Q28, A_Q28, hp_mem, out, len, channels ); + if( channels == 2 ) { + silk_biquad_float( in+1, B_Q28, A_Q28, hp_mem+2, out+1, len, channels ); + } +#endif +} + +#ifdef FIXED_POINT +static void dc_reject(const opus_val16 *in, opus_int32 cutoff_Hz, opus_val16 *out, opus_val32 *hp_mem, int len, int channels, opus_int32 Fs) +{ + int c, i; + int shift; + + /* Approximates -round(log2(6.3*cutoff_Hz/Fs)) */ + shift=celt_ilog2(Fs/(cutoff_Hz*4)); + for (c=0;cFs/400; + if (st->user_bitrate_bps==OPUS_AUTO) + return 60*st->Fs/frame_size + st->Fs*st->channels; + else if (st->user_bitrate_bps==OPUS_BITRATE_MAX) + return max_data_bytes*8*st->Fs/frame_size; + else + return st->user_bitrate_bps; +} + +#ifndef DISABLE_FLOAT_API +#ifdef FIXED_POINT +#define PCM2VAL(x) FLOAT2INT16(x) +#else +#define PCM2VAL(x) SCALEIN(x) +#endif + +void downmix_float(const void *_x, opus_val32 *y, int subframe, int offset, int c1, int c2, int C) +{ + const float *x; + int j; + + x = (const float *)_x; + for (j=0;j-1) + { + for (j=0;j-1) + { + for (j=0;j= OPUS_FRAMESIZE_2_5_MS && variable_duration <= OPUS_FRAMESIZE_120_MS) + { + if (variable_duration <= OPUS_FRAMESIZE_40_MS) + new_size = (Fs/400)<<(variable_duration-OPUS_FRAMESIZE_2_5_MS); + else + new_size = (variable_duration-OPUS_FRAMESIZE_2_5_MS-2)*Fs/50; + } + 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 && + 50*new_size!=4*Fs && 50*new_size!=5*Fs && 50*new_size!=6*Fs) + return -1; + return new_size; +} + +opus_val16 compute_stereo_width(const opus_val16 *pcm, int frame_size, opus_int32 Fs, StereoWidthState *mem) +{ + opus_val32 xx, xy, yy; + opus_val16 sqrt_xx, sqrt_yy; + opus_val16 qrrt_xx, qrrt_yy; + int frame_rate; + int i; + opus_val16 short_alpha; + + frame_rate = Fs/frame_size; + short_alpha = Q15ONE - MULT16_16(25, Q15ONE)/IMAX(50,frame_rate); + xx=xy=yy=0; + /* Unroll by 4. The frame size is always a multiple of 4 *except* for + 2.5 ms frames at 12 kHz. Since this setting is very rare (and very + stupid), we just discard the last two samples. */ + for (i=0;iXX += MULT16_32_Q15(short_alpha, xx-mem->XX); + mem->XY += MULT16_32_Q15(short_alpha, xy-mem->XY); + mem->YY += MULT16_32_Q15(short_alpha, yy-mem->YY); + mem->XX = MAX32(0, mem->XX); + mem->XY = MAX32(0, mem->XY); + mem->YY = MAX32(0, mem->YY); + if (MAX32(mem->XX, mem->YY)>QCONST16(8e-4f, 18)) + { + opus_val16 corr; + opus_val16 ldiff; + opus_val16 width; + sqrt_xx = celt_sqrt(mem->XX); + sqrt_yy = celt_sqrt(mem->YY); + qrrt_xx = celt_sqrt(sqrt_xx); + qrrt_yy = celt_sqrt(sqrt_yy); + /* Inter-channel correlation */ + mem->XY = MIN32(mem->XY, sqrt_xx*sqrt_yy); + corr = SHR32(frac_div32(mem->XY,EPSILON+MULT16_16(sqrt_xx,sqrt_yy)),16); + /* Approximate loudness difference */ + ldiff = MULT16_16(Q15ONE, ABS16(qrrt_xx-qrrt_yy))/(EPSILON+qrrt_xx+qrrt_yy); + width = MULT16_16_Q15(celt_sqrt(QCONST32(1.f,30)-MULT16_16(corr,corr)), ldiff); + /* Smoothing over one second */ + mem->smoothed_width += (width-mem->smoothed_width)/frame_rate; + /* Peak follower */ + mem->max_follower = MAX16(mem->max_follower-QCONST16(.02f,15)/frame_rate, mem->smoothed_width); + } + /*printf("%f %f %f %f %f ", corr/(float)Q15ONE, ldiff/(float)Q15ONE, width/(float)Q15ONE, mem->smoothed_width/(float)Q15ONE, mem->max_follower/(float)Q15ONE);*/ + return EXTRACT16(MIN32(Q15ONE, MULT16_16(20, mem->max_follower))); +} + +static int decide_fec(int useInBandFEC, int PacketLoss_perc, int last_fec, int mode, int *bandwidth, opus_int32 rate) +{ + int orig_bandwidth; + if (!useInBandFEC || PacketLoss_perc == 0 || mode == MODE_CELT_ONLY) + return 0; + orig_bandwidth = *bandwidth; + for (;;) + { + opus_int32 hysteresis; + opus_int32 LBRR_rate_thres_bps; + /* Compute threshold for using FEC at the current bandwidth setting */ + LBRR_rate_thres_bps = fec_thresholds[2*(*bandwidth - OPUS_BANDWIDTH_NARROWBAND)]; + hysteresis = fec_thresholds[2*(*bandwidth - OPUS_BANDWIDTH_NARROWBAND) + 1]; + if (last_fec == 1) LBRR_rate_thres_bps -= hysteresis; + if (last_fec == 0) LBRR_rate_thres_bps += hysteresis; + LBRR_rate_thres_bps = silk_SMULWB( silk_MUL( LBRR_rate_thres_bps, + 125 - silk_min( PacketLoss_perc, 25 ) ), SILK_FIX_CONST( 0.01, 16 ) ); + /* If loss <= 5%, we look at whether we have enough rate to enable FEC. + If loss > 5%, we decrease the bandwidth until we can enable FEC. */ + if (rate > LBRR_rate_thres_bps) + return 1; + else if (PacketLoss_perc <= 5) + return 0; + else if (*bandwidth > OPUS_BANDWIDTH_NARROWBAND) + (*bandwidth)--; + else + break; + } + /* Couldn't find any bandwidth to enable FEC, keep original bandwidth. */ + *bandwidth = orig_bandwidth; + return 0; +} + +static int compute_silk_rate_for_hybrid(int rate, int bandwidth, int frame20ms, int vbr, int fec, int channels) { + int entry; + int i; + int N; + int silk_rate; + static int rate_table[][5] = { + /* |total| |-------- SILK------------| + |-- No FEC -| |--- FEC ---| + 10ms 20ms 10ms 20ms */ + { 0, 0, 0, 0, 0}, + {12000, 10000, 10000, 11000, 11000}, + {16000, 13500, 13500, 15000, 15000}, + {20000, 16000, 16000, 18000, 18000}, + {24000, 18000, 18000, 21000, 21000}, + {32000, 22000, 22000, 28000, 28000}, + {64000, 38000, 38000, 50000, 50000} + }; + /* Do the allocation per-channel. */ + rate /= channels; + entry = 1 + frame20ms + 2*fec; + N = sizeof(rate_table)/sizeof(rate_table[0]); + for (i=1;i rate) break; + } + if (i == N) + { + silk_rate = rate_table[i-1][entry]; + /* For now, just give 50% of the extra bits to SILK. */ + silk_rate += (rate-rate_table[i-1][0])/2; + } else { + opus_int32 lo, hi, x0, x1; + lo = rate_table[i-1][entry]; + hi = rate_table[i][entry]; + x0 = rate_table[i-1][0]; + x1 = rate_table[i][0]; + silk_rate = (lo*(x1-rate) + hi*(rate-x0))/(x1-x0); + } + if (!vbr) + { + /* Tiny boost to SILK for CBR. We should probably tune this better. */ + silk_rate += 100; + } + if (bandwidth==OPUS_BANDWIDTH_SUPERWIDEBAND) + silk_rate += 300; + silk_rate *= channels; + /* Small adjustment for stereo (calibrated for 32 kb/s, haven't tried other bitrates). */ + if (channels == 2 && rate >= 12000) + silk_rate -= 1000; + return silk_rate; +} + +/* Returns the equivalent bitrate corresponding to 20 ms frames, + complexity 10 VBR operation. */ +static opus_int32 compute_equiv_rate(opus_int32 bitrate, int channels, + int frame_rate, int vbr, int mode, int complexity, int loss) +{ + opus_int32 equiv; + equiv = bitrate; + /* Take into account overhead from smaller frames. */ + if (frame_rate > 50) + equiv -= (40*channels+20)*(frame_rate - 50); + /* CBR is about a 8% penalty for both SILK and CELT. */ + if (!vbr) + equiv -= equiv/12; + /* Complexity makes about 10% difference (from 0 to 10) in general. */ + equiv = equiv * (90+complexity)/100; + if (mode == MODE_SILK_ONLY || mode == MODE_HYBRID) + { + /* SILK complexity 0-1 uses the non-delayed-decision NSQ, which + costs about 20%. */ + if (complexity<2) + equiv = equiv*4/5; + equiv -= equiv*loss/(6*loss + 10); + } else if (mode == MODE_CELT_ONLY) { + /* CELT complexity 0-4 doesn't have the pitch filter, which costs + about 10%. */ + if (complexity<5) + equiv = equiv*9/10; + } else { + /* Mode not known yet */ + /* Half the SILK loss*/ + equiv -= equiv*loss/(12*loss + 20); + } + return equiv; +} + +#ifndef DISABLE_FLOAT_API + +int is_digital_silence(const opus_val16* pcm, int frame_size, int channels, int lsb_depth) +{ + int silence = 0; + opus_val32 sample_max = 0; +#ifdef MLP_TRAINING + return 0; +#endif + sample_max = celt_maxabs16(pcm, frame_size*channels); + +#ifdef FIXED_POINT + silence = (sample_max == 0); + (void)lsb_depth; +#else + silence = (sample_max <= (opus_val16) 1 / (1 << lsb_depth)); +#endif + + return silence; +} + +#ifdef FIXED_POINT +static opus_val32 compute_frame_energy(const opus_val16 *pcm, int frame_size, int channels, int arch) +{ + int i; + opus_val32 sample_max; + int max_shift; + int shift; + opus_val32 energy = 0; + int len = frame_size*channels; + (void)arch; + /* Max amplitude in the signal */ + sample_max = celt_maxabs16(pcm, len); + + /* Compute the right shift required in the MAC to avoid an overflow */ + max_shift = celt_ilog2(len); + shift = IMAX(0, (celt_ilog2(sample_max) << 1) + max_shift - 28); + + /* Compute the energy */ + for (i=0; i= (PSEUDO_SNR_THRESHOLD * noise_energy); + } + } + + if (is_silence) + { + /* The number of consecutive DTX frames should be within the allowed bounds */ + (*nb_no_activity_frames)++; + + if (*nb_no_activity_frames > NB_SPEECH_FRAMES_BEFORE_DTX) + { + if (*nb_no_activity_frames <= (NB_SPEECH_FRAMES_BEFORE_DTX + MAX_CONSECUTIVE_DTX)) + /* Valid frame for DTX! */ + return 1; + else + (*nb_no_activity_frames) = NB_SPEECH_FRAMES_BEFORE_DTX; + } + } else + (*nb_no_activity_frames) = 0; + + return 0; +} + +#endif + +static opus_int32 encode_multiframe_packet(OpusEncoder *st, + const opus_val16 *pcm, + int nb_frames, + int frame_size, + unsigned char *data, + opus_int32 out_data_bytes, + int to_celt, + int lsb_depth, + int float_api) +{ + int i; + int ret = 0; + VARDECL(unsigned char, tmp_data); + int bak_mode, bak_bandwidth, bak_channels, bak_to_mono; + VARDECL(OpusRepacketizer, rp); + int max_header_bytes; + opus_int32 bytes_per_frame; + opus_int32 cbr_bytes; + opus_int32 repacketize_len; + int tmp_len; + ALLOC_STACK; + + /* Worst cases: + * 2 frames: Code 2 with different compressed sizes + * >2 frames: Code 3 VBR */ + max_header_bytes = nb_frames == 2 ? 3 : (2+(nb_frames-1)*2); + + if (st->use_vbr || st->user_bitrate_bps==OPUS_BITRATE_MAX) + repacketize_len = out_data_bytes; + else { + cbr_bytes = 3*st->bitrate_bps/(3*8*st->Fs/(frame_size*nb_frames)); + repacketize_len = IMIN(cbr_bytes, out_data_bytes); + } + bytes_per_frame = IMIN(1276, 1+(repacketize_len-max_header_bytes)/nb_frames); + + ALLOC(tmp_data, nb_frames*bytes_per_frame, unsigned char); + ALLOC(rp, 1, OpusRepacketizer); + opus_repacketizer_init(rp); + + bak_mode = st->user_forced_mode; + bak_bandwidth = st->user_bandwidth; + bak_channels = st->force_channels; + + st->user_forced_mode = st->mode; + st->user_bandwidth = st->bandwidth; + st->force_channels = st->stream_channels; + + bak_to_mono = st->silk_mode.toMono; + if (bak_to_mono) + st->force_channels = 1; + else + st->prev_channels = st->stream_channels; + + for (i=0;isilk_mode.toMono = 0; + st->nonfinal_frame = i<(nb_frames-1); + + /* When switching from SILK/Hybrid to CELT, only ask for a switch at the last frame */ + if (to_celt && i==nb_frames-1) + st->user_forced_mode = MODE_CELT_ONLY; + + tmp_len = opus_encode_native(st, pcm+i*(st->channels*frame_size), frame_size, + tmp_data+i*bytes_per_frame, bytes_per_frame, lsb_depth, NULL, 0, 0, 0, 0, + NULL, float_api); + + if (tmp_len<0) + { + RESTORE_STACK; + return OPUS_INTERNAL_ERROR; + } + + ret = opus_repacketizer_cat(rp, tmp_data+i*bytes_per_frame, tmp_len); + + if (ret<0) + { + RESTORE_STACK; + return OPUS_INTERNAL_ERROR; + } + } + + ret = opus_repacketizer_out_range_impl(rp, 0, nb_frames, data, repacketize_len, 0, !st->use_vbr); + + if (ret<0) + { + RESTORE_STACK; + return OPUS_INTERNAL_ERROR; + } + + /* Discard configs that were forced locally for the purpose of repacketization */ + st->user_forced_mode = bak_mode; + st->user_bandwidth = bak_bandwidth; + st->force_channels = bak_channels; + st->silk_mode.toMono = bak_to_mono; + + RESTORE_STACK; + return ret; +} + +static int compute_redundancy_bytes(opus_int32 max_data_bytes, opus_int32 bitrate_bps, int frame_rate, int channels) +{ + int redundancy_bytes_cap; + int redundancy_bytes; + opus_int32 redundancy_rate; + int base_bits; + opus_int32 available_bits; + base_bits = (40*channels+20); + + /* Equivalent rate for 5 ms frames. */ + redundancy_rate = bitrate_bps + base_bits*(200 - frame_rate); + /* For VBR, further increase the bitrate if we can afford it. It's pretty short + and we'll avoid artefacts. */ + redundancy_rate = 3*redundancy_rate/2; + redundancy_bytes = redundancy_rate/1600; + + /* Compute the max rate we can use given CBR or VBR with cap. */ + available_bits = max_data_bytes*8 - 2*base_bits; + redundancy_bytes_cap = (available_bits*240/(240+48000/frame_rate) + base_bits)/8; + redundancy_bytes = IMIN(redundancy_bytes, redundancy_bytes_cap); + /* It we can't get enough bits for redundancy to be worth it, rely on the decoder PLC. */ + if (redundancy_bytes > 4 + 8*channels) + redundancy_bytes = IMIN(257, redundancy_bytes); + else + redundancy_bytes = 0; + return redundancy_bytes; +} + +opus_int32 opus_encode_native(OpusEncoder *st, const opus_val16 *pcm, int frame_size, + unsigned char *data, opus_int32 out_data_bytes, int lsb_depth, + const void *analysis_pcm, opus_int32 analysis_size, int c1, int c2, + int analysis_channels, downmix_func downmix, int float_api) +{ + void *silk_enc; + CELTEncoder *celt_enc; + int i; + int ret=0; + opus_int32 nBytes; + ec_enc enc; + int bytes_target; + int prefill=0; + int start_band = 0; + int redundancy = 0; + int redundancy_bytes = 0; /* Number of bytes to use for redundancy frame */ + int celt_to_silk = 0; + VARDECL(opus_val16, pcm_buf); + int nb_compr_bytes; + int to_celt = 0; + opus_uint32 redundant_rng = 0; + int cutoff_Hz, hp_freq_smth1; + int voice_est; /* Probability of voice in Q7 */ + opus_int32 equiv_rate; + int delay_compensation; + int frame_rate; + opus_int32 max_rate; /* Max bitrate we're allowed to use */ + int curr_bandwidth; + opus_val16 HB_gain; + opus_int32 max_data_bytes; /* Max number of bytes we're allowed to use */ + int total_buffer; + opus_val16 stereo_width; + const CELTMode *celt_mode; +#ifndef DISABLE_FLOAT_API + AnalysisInfo analysis_info; + int analysis_read_pos_bak=-1; + int analysis_read_subframe_bak=-1; + int is_silence = 0; +#endif + VARDECL(opus_val16, tmp_prefill); + + ALLOC_STACK; + + max_data_bytes = IMIN(1276, out_data_bytes); + + st->rangeFinal = 0; + if (frame_size <= 0 || max_data_bytes <= 0) + { + RESTORE_STACK; + return OPUS_BAD_ARG; + } + + /* Cannot encode 100 ms in 1 byte */ + if (max_data_bytes==1 && st->Fs==(frame_size*10)) + { + RESTORE_STACK; + return OPUS_BUFFER_TOO_SMALL; + } + + silk_enc = (char*)st+st->silk_enc_offset; + celt_enc = (CELTEncoder*)((char*)st+st->celt_enc_offset); + if (st->application == OPUS_APPLICATION_RESTRICTED_LOWDELAY) + delay_compensation = 0; + else + delay_compensation = st->delay_compensation; + + lsb_depth = IMIN(lsb_depth, st->lsb_depth); + + celt_encoder_ctl(celt_enc, CELT_GET_MODE(&celt_mode)); +#ifndef DISABLE_FLOAT_API + analysis_info.valid = 0; +#ifdef FIXED_POINT + if (st->silk_mode.complexity >= 10 && st->Fs>=16000) +#else + if (st->silk_mode.complexity >= 7 && st->Fs>=16000) +#endif + { + is_silence = is_digital_silence(pcm, frame_size, st->channels, lsb_depth); + analysis_read_pos_bak = st->analysis.read_pos; + analysis_read_subframe_bak = st->analysis.read_subframe; + run_analysis(&st->analysis, celt_mode, analysis_pcm, analysis_size, frame_size, + c1, c2, analysis_channels, st->Fs, + lsb_depth, downmix, &analysis_info); + + /* Track the peak signal energy */ + if (!is_silence && analysis_info.activity_probability > DTX_ACTIVITY_THRESHOLD) + st->peak_signal_energy = MAX32(MULT16_32_Q15(QCONST16(0.999f, 15), st->peak_signal_energy), + compute_frame_energy(pcm, frame_size, st->channels, st->arch)); + } else if (st->analysis.initialized) { + tonality_analysis_reset(&st->analysis); + } +#else + (void)analysis_pcm; + (void)analysis_size; + (void)c1; + (void)c2; + (void)analysis_channels; + (void)downmix; +#endif + +#ifndef DISABLE_FLOAT_API + /* Reset voice_ratio if this frame is not silent or if analysis is disabled. + * Otherwise, preserve voice_ratio from the last non-silent frame */ + if (!is_silence) + st->voice_ratio = -1; + + st->detected_bandwidth = 0; + if (analysis_info.valid) + { + int analysis_bandwidth; + if (st->signal_type == OPUS_AUTO) + { + float prob; + if (st->prev_mode == 0) + prob = analysis_info.music_prob; + else if (st->prev_mode == MODE_CELT_ONLY) + prob = analysis_info.music_prob_max; + else + prob = analysis_info.music_prob_min; + st->voice_ratio = (int)floor(.5+100*(1-prob)); + } + + analysis_bandwidth = analysis_info.bandwidth; + if (analysis_bandwidth<=12) + st->detected_bandwidth = OPUS_BANDWIDTH_NARROWBAND; + else if (analysis_bandwidth<=14) + st->detected_bandwidth = OPUS_BANDWIDTH_MEDIUMBAND; + else if (analysis_bandwidth<=16) + st->detected_bandwidth = OPUS_BANDWIDTH_WIDEBAND; + else if (analysis_bandwidth<=18) + st->detected_bandwidth = OPUS_BANDWIDTH_SUPERWIDEBAND; + else + st->detected_bandwidth = OPUS_BANDWIDTH_FULLBAND; + } +#else + st->voice_ratio = -1; +#endif + + if (st->channels==2 && st->force_channels!=1) + stereo_width = compute_stereo_width(pcm, frame_size, st->Fs, &st->width_mem); + else + stereo_width = 0; + total_buffer = delay_compensation; + st->bitrate_bps = user_bitrate_to_bitrate(st, frame_size, max_data_bytes); + + frame_rate = st->Fs/frame_size; + if (!st->use_vbr) + { + int cbrBytes; + /* Multiply by 12 to make sure the division is exact. */ + int frame_rate12 = 12*st->Fs/frame_size; + /* We need to make sure that "int" values always fit in 16 bits. */ + cbrBytes = IMIN( (12*st->bitrate_bps/8 + frame_rate12/2)/frame_rate12, max_data_bytes); + st->bitrate_bps = cbrBytes*(opus_int32)frame_rate12*8/12; + /* Make sure we provide at least one byte to avoid failing. */ + max_data_bytes = IMAX(1, cbrBytes); + } + if (max_data_bytes<3 || st->bitrate_bps < 3*frame_rate*8 + || (frame_rate<50 && (max_data_bytes*frame_rate<300 || st->bitrate_bps < 2400))) + { + /*If the space is too low to do something useful, emit 'PLC' frames.*/ + int tocmode = st->mode; + int bw = st->bandwidth == 0 ? OPUS_BANDWIDTH_NARROWBAND : st->bandwidth; + int packet_code = 0; + int num_multiframes = 0; + + if (tocmode==0) + tocmode = MODE_SILK_ONLY; + if (frame_rate>100) + tocmode = MODE_CELT_ONLY; + /* 40 ms -> 2 x 20 ms if in CELT_ONLY or HYBRID mode */ + if (frame_rate==25 && tocmode!=MODE_SILK_ONLY) + { + frame_rate = 50; + packet_code = 1; + } + + /* >= 60 ms frames */ + if (frame_rate<=16) + { + /* 1 x 60 ms, 2 x 40 ms, 2 x 60 ms */ + if (out_data_bytes==1 || (tocmode==MODE_SILK_ONLY && frame_rate!=10)) + { + tocmode = MODE_SILK_ONLY; + + packet_code = frame_rate <= 12; + frame_rate = frame_rate == 12 ? 25 : 16; + } + else + { + num_multiframes = 50/frame_rate; + frame_rate = 50; + packet_code = 3; + } + } + + if(tocmode==MODE_SILK_ONLY&&bw>OPUS_BANDWIDTH_WIDEBAND) + bw=OPUS_BANDWIDTH_WIDEBAND; + else if (tocmode==MODE_CELT_ONLY&&bw==OPUS_BANDWIDTH_MEDIUMBAND) + bw=OPUS_BANDWIDTH_NARROWBAND; + else if (tocmode==MODE_HYBRID&&bw<=OPUS_BANDWIDTH_SUPERWIDEBAND) + bw=OPUS_BANDWIDTH_SUPERWIDEBAND; + + data[0] = gen_toc(tocmode, frame_rate, bw, st->stream_channels); + data[0] |= packet_code; + + ret = packet_code <= 1 ? 1 : 2; + + max_data_bytes = IMAX(max_data_bytes, ret); + + if (packet_code==3) + data[1] = num_multiframes; + + if (!st->use_vbr) + { + ret = opus_packet_pad(data, ret, max_data_bytes); + if (ret == OPUS_OK) + ret = max_data_bytes; + else + ret = OPUS_INTERNAL_ERROR; + } + RESTORE_STACK; + return ret; + } + max_rate = frame_rate*max_data_bytes*8; + + /* Equivalent 20-ms rate for mode/channel/bandwidth decisions */ + equiv_rate = compute_equiv_rate(st->bitrate_bps, st->channels, st->Fs/frame_size, + st->use_vbr, 0, st->silk_mode.complexity, st->silk_mode.packetLossPercentage); + + if (st->signal_type == OPUS_SIGNAL_VOICE) + voice_est = 127; + else if (st->signal_type == OPUS_SIGNAL_MUSIC) + voice_est = 0; + else if (st->voice_ratio >= 0) + { + voice_est = st->voice_ratio*327>>8; + /* For AUDIO, never be more than 90% confident of having speech */ + if (st->application == OPUS_APPLICATION_AUDIO) + voice_est = IMIN(voice_est, 115); + } else if (st->application == OPUS_APPLICATION_VOIP) + voice_est = 115; + else + voice_est = 48; + + if (st->force_channels!=OPUS_AUTO && st->channels == 2) + { + st->stream_channels = st->force_channels; + } else { +#ifdef FUZZING + /* Random mono/stereo decision */ + if (st->channels == 2 && (rand()&0x1F)==0) + st->stream_channels = 3-st->stream_channels; +#else + /* Rate-dependent mono-stereo decision */ + if (st->channels == 2) + { + opus_int32 stereo_threshold; + stereo_threshold = stereo_music_threshold + ((voice_est*voice_est*(stereo_voice_threshold-stereo_music_threshold))>>14); + if (st->stream_channels == 2) + stereo_threshold -= 1000; + else + stereo_threshold += 1000; + st->stream_channels = (equiv_rate > stereo_threshold) ? 2 : 1; + } else { + st->stream_channels = st->channels; + } +#endif + } + /* Update equivalent rate for channels decision. */ + equiv_rate = compute_equiv_rate(st->bitrate_bps, st->stream_channels, st->Fs/frame_size, + st->use_vbr, 0, st->silk_mode.complexity, st->silk_mode.packetLossPercentage); + + /* Allow SILK DTX if DTX is enabled but the generalized DTX cannot be used, + e.g. because of the complexity setting or sample rate. */ +#ifndef DISABLE_FLOAT_API + st->silk_mode.useDTX = st->use_dtx && !(analysis_info.valid || is_silence); +#else + st->silk_mode.useDTX = st->use_dtx; +#endif + + /* Mode selection depending on application and signal type */ + if (st->application == OPUS_APPLICATION_RESTRICTED_LOWDELAY) + { + st->mode = MODE_CELT_ONLY; + } else if (st->user_forced_mode == OPUS_AUTO) + { +#ifdef FUZZING + /* Random mode switching */ + if ((rand()&0xF)==0) + { + if ((rand()&0x1)==0) + st->mode = MODE_CELT_ONLY; + else + st->mode = MODE_SILK_ONLY; + } else { + if (st->prev_mode==MODE_CELT_ONLY) + st->mode = MODE_CELT_ONLY; + else + st->mode = MODE_SILK_ONLY; + } +#else + opus_int32 mode_voice, mode_music; + opus_int32 threshold; + + /* Interpolate based on stereo width */ + mode_voice = (opus_int32)(MULT16_32_Q15(Q15ONE-stereo_width,mode_thresholds[0][0]) + + MULT16_32_Q15(stereo_width,mode_thresholds[1][0])); + mode_music = (opus_int32)(MULT16_32_Q15(Q15ONE-stereo_width,mode_thresholds[1][1]) + + MULT16_32_Q15(stereo_width,mode_thresholds[1][1])); + /* Interpolate based on speech/music probability */ + threshold = mode_music + ((voice_est*voice_est*(mode_voice-mode_music))>>14); + /* Bias towards SILK for VoIP because of some useful features */ + if (st->application == OPUS_APPLICATION_VOIP) + threshold += 8000; + + /*printf("%f %d\n", stereo_width/(float)Q15ONE, threshold);*/ + /* Hysteresis */ + if (st->prev_mode == MODE_CELT_ONLY) + threshold -= 4000; + else if (st->prev_mode>0) + threshold += 4000; + + st->mode = (equiv_rate >= threshold) ? MODE_CELT_ONLY: MODE_SILK_ONLY; + + /* When FEC is enabled and there's enough packet loss, use SILK */ + if (st->silk_mode.useInBandFEC && st->silk_mode.packetLossPercentage > (128-voice_est)>>4) + st->mode = MODE_SILK_ONLY; + /* When encoding voice and DTX is enabled but the generalized DTX cannot be used, + use SILK in order to make use of its DTX. */ + if (st->silk_mode.useDTX && voice_est > 100) + st->mode = MODE_SILK_ONLY; +#endif + + /* If max_data_bytes represents less than 6 kb/s, switch to CELT-only mode */ + if (max_data_bytes < (frame_rate > 50 ? 9000 : 6000)*frame_size / (st->Fs * 8)) + st->mode = MODE_CELT_ONLY; + } else { + st->mode = st->user_forced_mode; + } + + /* Override the chosen mode to make sure we meet the requested frame size */ + if (st->mode != MODE_CELT_ONLY && frame_size < st->Fs/100) + st->mode = MODE_CELT_ONLY; + if (st->lfe) + st->mode = MODE_CELT_ONLY; + + if (st->prev_mode > 0 && + ((st->mode != MODE_CELT_ONLY && st->prev_mode == MODE_CELT_ONLY) || + (st->mode == MODE_CELT_ONLY && st->prev_mode != MODE_CELT_ONLY))) + { + redundancy = 1; + celt_to_silk = (st->mode != MODE_CELT_ONLY); + if (!celt_to_silk) + { + /* Switch to SILK/hybrid if frame size is 10 ms or more*/ + if (frame_size >= st->Fs/100) + { + st->mode = st->prev_mode; + to_celt = 1; + } else { + redundancy=0; + } + } + } + + /* When encoding multiframes, we can ask for a switch to CELT only in the last frame. This switch + * is processed above as the requested mode shouldn't interrupt stereo->mono transition. */ + if (st->stream_channels == 1 && st->prev_channels ==2 && st->silk_mode.toMono==0 + && st->mode != MODE_CELT_ONLY && st->prev_mode != MODE_CELT_ONLY) + { + /* Delay stereo->mono transition by two frames so that SILK can do a smooth downmix */ + st->silk_mode.toMono = 1; + st->stream_channels = 2; + } else { + st->silk_mode.toMono = 0; + } + + /* Update equivalent rate with mode decision. */ + equiv_rate = compute_equiv_rate(st->bitrate_bps, st->stream_channels, st->Fs/frame_size, + st->use_vbr, st->mode, st->silk_mode.complexity, st->silk_mode.packetLossPercentage); + + if (st->mode != MODE_CELT_ONLY && st->prev_mode == MODE_CELT_ONLY) + { + silk_EncControlStruct dummy; + silk_InitEncoder( silk_enc, st->arch, &dummy); + prefill=1; + } + + /* Automatic (rate-dependent) bandwidth selection */ + if (st->mode == MODE_CELT_ONLY || st->first || st->silk_mode.allowBandwidthSwitch) + { + const opus_int32 *voice_bandwidth_thresholds, *music_bandwidth_thresholds; + opus_int32 bandwidth_thresholds[8]; + int bandwidth = OPUS_BANDWIDTH_FULLBAND; + + if (st->channels==2 && st->force_channels!=1) + { + voice_bandwidth_thresholds = stereo_voice_bandwidth_thresholds; + music_bandwidth_thresholds = stereo_music_bandwidth_thresholds; + } else { + voice_bandwidth_thresholds = mono_voice_bandwidth_thresholds; + music_bandwidth_thresholds = mono_music_bandwidth_thresholds; + } + /* Interpolate bandwidth thresholds depending on voice estimation */ + 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 { + int threshold, hysteresis; + threshold = bandwidth_thresholds[2*(bandwidth-OPUS_BANDWIDTH_MEDIUMBAND)]; + hysteresis = bandwidth_thresholds[2*(bandwidth-OPUS_BANDWIDTH_MEDIUMBAND)+1]; + if (!st->first) + { + if (st->auto_bandwidth >= bandwidth) + threshold -= hysteresis; + else + threshold += hysteresis; + } + if (equiv_rate >= threshold) + break; + } while (--bandwidth>OPUS_BANDWIDTH_NARROWBAND); + /* We don't use mediumband anymore, except when explicitly requested or during + mode transitions. */ + if (bandwidth == OPUS_BANDWIDTH_MEDIUMBAND) + bandwidth = OPUS_BANDWIDTH_WIDEBAND; + st->bandwidth = st->auto_bandwidth = bandwidth; + /* Prevents any transition to SWB/FB until the SILK layer has fully + switched to WB mode and turned the variable LP filter off */ + if (!st->first && st->mode != MODE_CELT_ONLY && !st->silk_mode.inWBmodeWithoutVariableLP && st->bandwidth > OPUS_BANDWIDTH_WIDEBAND) + st->bandwidth = OPUS_BANDWIDTH_WIDEBAND; + } + + if (st->bandwidth>st->max_bandwidth) + st->bandwidth = st->max_bandwidth; + + if (st->user_bandwidth != OPUS_AUTO) + st->bandwidth = st->user_bandwidth; + + /* This prevents us from using hybrid at unsafe CBR/max rates */ + if (st->mode != MODE_CELT_ONLY && max_rate < 15000) + { + st->bandwidth = IMIN(st->bandwidth, OPUS_BANDWIDTH_WIDEBAND); + } + + /* Prevents Opus from wasting bits on frequencies that are above + the Nyquist rate of the input signal */ + if (st->Fs <= 24000 && st->bandwidth > OPUS_BANDWIDTH_SUPERWIDEBAND) + st->bandwidth = OPUS_BANDWIDTH_SUPERWIDEBAND; + if (st->Fs <= 16000 && st->bandwidth > OPUS_BANDWIDTH_WIDEBAND) + st->bandwidth = OPUS_BANDWIDTH_WIDEBAND; + if (st->Fs <= 12000 && st->bandwidth > OPUS_BANDWIDTH_MEDIUMBAND) + st->bandwidth = OPUS_BANDWIDTH_MEDIUMBAND; + if (st->Fs <= 8000 && st->bandwidth > OPUS_BANDWIDTH_NARROWBAND) + st->bandwidth = OPUS_BANDWIDTH_NARROWBAND; +#ifndef DISABLE_FLOAT_API + /* Use detected bandwidth to reduce the encoded bandwidth. */ + if (st->detected_bandwidth && st->user_bandwidth == OPUS_AUTO) + { + int min_detected_bandwidth; + /* Makes bandwidth detection more conservative just in case the detector + gets it wrong when we could have coded a high bandwidth transparently. + When operating in SILK/hybrid mode, we don't go below wideband to avoid + more complicated switches that require redundancy. */ + if (equiv_rate <= 18000*st->stream_channels && st->mode == MODE_CELT_ONLY) + min_detected_bandwidth = OPUS_BANDWIDTH_NARROWBAND; + else if (equiv_rate <= 24000*st->stream_channels && st->mode == MODE_CELT_ONLY) + min_detected_bandwidth = OPUS_BANDWIDTH_MEDIUMBAND; + else if (equiv_rate <= 30000*st->stream_channels) + min_detected_bandwidth = OPUS_BANDWIDTH_WIDEBAND; + else if (equiv_rate <= 44000*st->stream_channels) + min_detected_bandwidth = OPUS_BANDWIDTH_SUPERWIDEBAND; + else + min_detected_bandwidth = OPUS_BANDWIDTH_FULLBAND; + + st->detected_bandwidth = IMAX(st->detected_bandwidth, min_detected_bandwidth); + st->bandwidth = IMIN(st->bandwidth, st->detected_bandwidth); + } +#endif + st->silk_mode.LBRR_coded = decide_fec(st->silk_mode.useInBandFEC, st->silk_mode.packetLossPercentage, + st->silk_mode.LBRR_coded, st->mode, &st->bandwidth, equiv_rate); + celt_encoder_ctl(celt_enc, OPUS_SET_LSB_DEPTH(lsb_depth)); + + /* CELT mode doesn't support mediumband, use wideband instead */ + if (st->mode == MODE_CELT_ONLY && st->bandwidth == OPUS_BANDWIDTH_MEDIUMBAND) + st->bandwidth = OPUS_BANDWIDTH_WIDEBAND; + if (st->lfe) + st->bandwidth = OPUS_BANDWIDTH_NARROWBAND; + + curr_bandwidth = st->bandwidth; + + /* Chooses the appropriate mode for speech + *NEVER* switch to/from CELT-only mode here as this will invalidate some assumptions */ + if (st->mode == MODE_SILK_ONLY && curr_bandwidth > OPUS_BANDWIDTH_WIDEBAND) + st->mode = MODE_HYBRID; + if (st->mode == MODE_HYBRID && curr_bandwidth <= OPUS_BANDWIDTH_WIDEBAND) + st->mode = MODE_SILK_ONLY; + + /* Can't support higher than >60 ms frames, and >20 ms when in Hybrid or CELT-only modes */ + if ((frame_size > st->Fs/50 && (st->mode != MODE_SILK_ONLY)) || frame_size > 3*st->Fs/50) + { + int enc_frame_size; + int nb_frames; + + if (st->mode == MODE_SILK_ONLY) + { + if (frame_size == 2*st->Fs/25) /* 80 ms -> 2x 40 ms */ + enc_frame_size = st->Fs/25; + else if (frame_size == 3*st->Fs/25) /* 120 ms -> 2x 60 ms */ + enc_frame_size = 3*st->Fs/50; + else /* 100 ms -> 5x 20 ms */ + enc_frame_size = st->Fs/50; + } + else + enc_frame_size = st->Fs/50; + + nb_frames = frame_size/enc_frame_size; + +#ifndef DISABLE_FLOAT_API + if (analysis_read_pos_bak!= -1) + { + st->analysis.read_pos = analysis_read_pos_bak; + st->analysis.read_subframe = analysis_read_subframe_bak; + } +#endif + + ret = encode_multiframe_packet(st, pcm, nb_frames, enc_frame_size, data, + out_data_bytes, to_celt, lsb_depth, float_api); + + RESTORE_STACK; + return ret; + } + + /* For the first frame at a new SILK bandwidth */ + if (st->silk_bw_switch) + { + redundancy = 1; + celt_to_silk = 1; + st->silk_bw_switch = 0; + /* Do a prefill without reseting the sampling rate control. */ + prefill=2; + } + + /* If we decided to go with CELT, make sure redundancy is off, no matter what + we decided earlier. */ + if (st->mode == MODE_CELT_ONLY) + redundancy = 0; + + if (redundancy) + { + redundancy_bytes = compute_redundancy_bytes(max_data_bytes, st->bitrate_bps, frame_rate, st->stream_channels); + if (redundancy_bytes == 0) + redundancy = 0; + } + + /* printf("%d %d %d %d\n", st->bitrate_bps, st->stream_channels, st->mode, curr_bandwidth); */ + bytes_target = IMIN(max_data_bytes-redundancy_bytes, st->bitrate_bps * frame_size / (st->Fs * 8)) - 1; + + data += 1; + + ec_enc_init(&enc, data, max_data_bytes-1); + + ALLOC(pcm_buf, (total_buffer+frame_size)*st->channels, opus_val16); + OPUS_COPY(pcm_buf, &st->delay_buffer[(st->encoder_buffer-total_buffer)*st->channels], total_buffer*st->channels); + + if (st->mode == MODE_CELT_ONLY) + hp_freq_smth1 = silk_LSHIFT( silk_lin2log( VARIABLE_HP_MIN_CUTOFF_HZ ), 8 ); + else + hp_freq_smth1 = ((silk_encoder*)silk_enc)->state_Fxx[0].sCmn.variable_HP_smth1_Q15; + + st->variable_HP_smth2_Q15 = silk_SMLAWB( st->variable_HP_smth2_Q15, + hp_freq_smth1 - st->variable_HP_smth2_Q15, SILK_FIX_CONST( VARIABLE_HP_SMTH_COEF2, 16 ) ); + + /* convert from log scale to Hertz */ + cutoff_Hz = silk_log2lin( silk_RSHIFT( st->variable_HP_smth2_Q15, 8 ) ); + + if (st->application == OPUS_APPLICATION_VOIP) + { + hp_cutoff(pcm, cutoff_Hz, &pcm_buf[total_buffer*st->channels], st->hp_mem, frame_size, st->channels, st->Fs, st->arch); + } else { + dc_reject(pcm, 3, &pcm_buf[total_buffer*st->channels], st->hp_mem, frame_size, st->channels, st->Fs); + } +#ifndef FIXED_POINT + if (float_api) + { + opus_val32 sum; + sum = celt_inner_prod(&pcm_buf[total_buffer*st->channels], &pcm_buf[total_buffer*st->channels], frame_size*st->channels, st->arch); + /* This should filter out both NaNs and ridiculous signals that could + cause NaNs further down. */ + if (!(sum < 1e9f) || celt_isnan(sum)) + { + OPUS_CLEAR(&pcm_buf[total_buffer*st->channels], frame_size*st->channels); + st->hp_mem[0] = st->hp_mem[1] = st->hp_mem[2] = st->hp_mem[3] = 0; + } + } +#endif + + + /* SILK processing */ + HB_gain = Q15ONE; + if (st->mode != MODE_CELT_ONLY) + { + opus_int32 total_bitRate, celt_rate; + opus_int activity; +#ifdef FIXED_POINT + const opus_int16 *pcm_silk; +#else + VARDECL(opus_int16, pcm_silk); + ALLOC(pcm_silk, st->channels*frame_size, opus_int16); +#endif + + activity = VAD_NO_DECISION; +#ifndef DISABLE_FLOAT_API + if( analysis_info.valid ) { + /* Inform SILK about the Opus VAD decision */ + activity = ( analysis_info.activity_probability >= DTX_ACTIVITY_THRESHOLD ); + } +#endif + + /* Distribute bits between SILK and CELT */ + total_bitRate = 8 * bytes_target * frame_rate; + if( st->mode == MODE_HYBRID ) { + /* Base rate for SILK */ + st->silk_mode.bitRate = compute_silk_rate_for_hybrid(total_bitRate, + curr_bandwidth, st->Fs == 50 * frame_size, st->use_vbr, st->silk_mode.LBRR_coded, + st->stream_channels); + if (!st->energy_masking) + { + /* Increasingly attenuate high band when it gets allocated fewer bits */ + celt_rate = total_bitRate - st->silk_mode.bitRate; + HB_gain = Q15ONE - SHR32(celt_exp2(-celt_rate * QCONST16(1.f/1024, 10)), 1); + } + } else { + /* SILK gets all bits */ + st->silk_mode.bitRate = total_bitRate; + } + + /* Surround masking for SILK */ + if (st->energy_masking && st->use_vbr && !st->lfe) + { + opus_val32 mask_sum=0; + opus_val16 masking_depth; + opus_int32 rate_offset; + int c; + int end = 17; + opus_int16 srate = 16000; + if (st->bandwidth == OPUS_BANDWIDTH_NARROWBAND) + { + end = 13; + srate = 8000; + } else if (st->bandwidth == OPUS_BANDWIDTH_MEDIUMBAND) + { + end = 15; + srate = 12000; + } + for (c=0;cchannels;c++) + { + for(i=0;ienergy_masking[21*c+i], + QCONST16(.5f, DB_SHIFT)), -QCONST16(2.0f, DB_SHIFT)); + if (mask > 0) + mask = HALF16(mask); + mask_sum += mask; + } + } + /* Conservative rate reduction, we cut the masking in half */ + masking_depth = mask_sum / end*st->channels; + masking_depth += QCONST16(.2f, DB_SHIFT); + rate_offset = (opus_int32)PSHR32(MULT16_16(srate, masking_depth), DB_SHIFT); + rate_offset = MAX32(rate_offset, -2*st->silk_mode.bitRate/3); + /* Split the rate change between the SILK and CELT part for hybrid. */ + if (st->bandwidth==OPUS_BANDWIDTH_SUPERWIDEBAND || st->bandwidth==OPUS_BANDWIDTH_FULLBAND) + st->silk_mode.bitRate += 3*rate_offset/5; + else + st->silk_mode.bitRate += rate_offset; + } + + st->silk_mode.payloadSize_ms = 1000 * frame_size / st->Fs; + st->silk_mode.nChannelsAPI = st->channels; + st->silk_mode.nChannelsInternal = st->stream_channels; + if (curr_bandwidth == OPUS_BANDWIDTH_NARROWBAND) { + st->silk_mode.desiredInternalSampleRate = 8000; + } else if (curr_bandwidth == OPUS_BANDWIDTH_MEDIUMBAND) { + st->silk_mode.desiredInternalSampleRate = 12000; + } else { + celt_assert( st->mode == MODE_HYBRID || curr_bandwidth == OPUS_BANDWIDTH_WIDEBAND ); + st->silk_mode.desiredInternalSampleRate = 16000; + } + if( st->mode == MODE_HYBRID ) { + /* Don't allow bandwidth reduction at lowest bitrates in hybrid mode */ + st->silk_mode.minInternalSampleRate = 16000; + } else { + st->silk_mode.minInternalSampleRate = 8000; + } + + st->silk_mode.maxInternalSampleRate = 16000; + if (st->mode == MODE_SILK_ONLY) + { + opus_int32 effective_max_rate = max_rate; + if (frame_rate > 50) + effective_max_rate = effective_max_rate*2/3; + if (effective_max_rate < 8000) + { + st->silk_mode.maxInternalSampleRate = 12000; + st->silk_mode.desiredInternalSampleRate = IMIN(12000, st->silk_mode.desiredInternalSampleRate); + } + if (effective_max_rate < 7000) + { + st->silk_mode.maxInternalSampleRate = 8000; + st->silk_mode.desiredInternalSampleRate = IMIN(8000, st->silk_mode.desiredInternalSampleRate); + } + } + + st->silk_mode.useCBR = !st->use_vbr; + + /* Call SILK encoder for the low band */ + + /* Max bits for SILK, counting ToC, redundancy bytes, and optionally redundancy. */ + st->silk_mode.maxBits = (max_data_bytes-1)*8; + if (redundancy && redundancy_bytes >= 2) + { + /* Counting 1 bit for redundancy position and 20 bits for flag+size (only for hybrid). */ + st->silk_mode.maxBits -= redundancy_bytes*8 + 1; + if (st->mode == MODE_HYBRID) + st->silk_mode.maxBits -= 20; + } + if (st->silk_mode.useCBR) + { + if (st->mode == MODE_HYBRID) + { + st->silk_mode.maxBits = IMIN(st->silk_mode.maxBits, st->silk_mode.bitRate * frame_size / st->Fs); + } + } else { + /* Constrained VBR. */ + if (st->mode == MODE_HYBRID) + { + /* Compute SILK bitrate corresponding to the max total bits available */ + opus_int32 maxBitRate = compute_silk_rate_for_hybrid(st->silk_mode.maxBits*st->Fs / frame_size, + curr_bandwidth, st->Fs == 50 * frame_size, st->use_vbr, st->silk_mode.LBRR_coded, + st->stream_channels); + st->silk_mode.maxBits = maxBitRate * frame_size / st->Fs; + } + } + + if (prefill) + { + opus_int32 zero=0; + int prefill_offset; + /* Use a smooth onset for the SILK prefill to avoid the encoder trying to encode + a discontinuity. The exact location is what we need to avoid leaving any "gap" + in the audio when mixing with the redundant CELT frame. Here we can afford to + overwrite st->delay_buffer because the only thing that uses it before it gets + rewritten is tmp_prefill[] and even then only the part after the ramp really + gets used (rather than sent to the encoder and discarded) */ + prefill_offset = st->channels*(st->encoder_buffer-st->delay_compensation-st->Fs/400); + gain_fade(st->delay_buffer+prefill_offset, st->delay_buffer+prefill_offset, + 0, Q15ONE, celt_mode->overlap, st->Fs/400, st->channels, celt_mode->window, st->Fs); + OPUS_CLEAR(st->delay_buffer, prefill_offset); +#ifdef FIXED_POINT + pcm_silk = st->delay_buffer; +#else + for (i=0;iencoder_buffer*st->channels;i++) + pcm_silk[i] = FLOAT2INT16(st->delay_buffer[i]); +#endif + silk_Encode( silk_enc, &st->silk_mode, pcm_silk, st->encoder_buffer, NULL, &zero, prefill, activity ); + /* Prevent a second switch in the real encode call. */ + st->silk_mode.opusCanSwitch = 0; + } + +#ifdef FIXED_POINT + pcm_silk = pcm_buf+total_buffer*st->channels; +#else + for (i=0;ichannels;i++) + pcm_silk[i] = FLOAT2INT16(pcm_buf[total_buffer*st->channels + i]); +#endif + ret = silk_Encode( silk_enc, &st->silk_mode, pcm_silk, frame_size, &enc, &nBytes, 0, activity ); + if( ret ) { + /*fprintf (stderr, "SILK encode error: %d\n", ret);*/ + /* Handle error */ + RESTORE_STACK; + return OPUS_INTERNAL_ERROR; + } + + /* Extract SILK internal bandwidth for signaling in first byte */ + if( st->mode == MODE_SILK_ONLY ) { + if( st->silk_mode.internalSampleRate == 8000 ) { + curr_bandwidth = OPUS_BANDWIDTH_NARROWBAND; + } else if( st->silk_mode.internalSampleRate == 12000 ) { + curr_bandwidth = OPUS_BANDWIDTH_MEDIUMBAND; + } else if( st->silk_mode.internalSampleRate == 16000 ) { + curr_bandwidth = OPUS_BANDWIDTH_WIDEBAND; + } + } else { + celt_assert( st->silk_mode.internalSampleRate == 16000 ); + } + + st->silk_mode.opusCanSwitch = st->silk_mode.switchReady && !st->nonfinal_frame; + + if (nBytes==0) + { + st->rangeFinal = 0; + data[-1] = gen_toc(st->mode, st->Fs/frame_size, curr_bandwidth, st->stream_channels); + RESTORE_STACK; + return 1; + } + + /* FIXME: How do we allocate the redundancy for CBR? */ + if (st->silk_mode.opusCanSwitch) + { + redundancy_bytes = compute_redundancy_bytes(max_data_bytes, st->bitrate_bps, frame_rate, st->stream_channels); + redundancy = (redundancy_bytes != 0); + celt_to_silk = 0; + st->silk_bw_switch = 1; + } + } + + /* CELT processing */ + { + 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; + break; + } + celt_encoder_ctl(celt_enc, CELT_SET_END_BAND(endband)); + celt_encoder_ctl(celt_enc, CELT_SET_CHANNELS(st->stream_channels)); + } + celt_encoder_ctl(celt_enc, OPUS_SET_BITRATE(OPUS_BITRATE_MAX)); + if (st->mode != MODE_SILK_ONLY) + { + opus_val32 celt_pred=2; + celt_encoder_ctl(celt_enc, OPUS_SET_VBR(0)); + /* We may still decide to disable prediction later */ + if (st->silk_mode.reducedDependency) + celt_pred = 0; + celt_encoder_ctl(celt_enc, CELT_SET_PREDICTION(celt_pred)); + + if (st->mode == MODE_HYBRID) + { + if( st->use_vbr ) { + celt_encoder_ctl(celt_enc, OPUS_SET_BITRATE(st->bitrate_bps-st->silk_mode.bitRate)); + celt_encoder_ctl(celt_enc, OPUS_SET_VBR_CONSTRAINT(0)); + } + } else { + if (st->use_vbr) + { + celt_encoder_ctl(celt_enc, OPUS_SET_VBR(1)); + celt_encoder_ctl(celt_enc, OPUS_SET_VBR_CONSTRAINT(st->vbr_constraint)); + celt_encoder_ctl(celt_enc, OPUS_SET_BITRATE(st->bitrate_bps)); + } + } + } + + ALLOC(tmp_prefill, st->channels*st->Fs/400, opus_val16); + if (st->mode != MODE_SILK_ONLY && st->mode != st->prev_mode && st->prev_mode > 0) + { + OPUS_COPY(tmp_prefill, &st->delay_buffer[(st->encoder_buffer-total_buffer-st->Fs/400)*st->channels], st->channels*st->Fs/400); + } + + if (st->channels*(st->encoder_buffer-(frame_size+total_buffer)) > 0) + { + OPUS_MOVE(st->delay_buffer, &st->delay_buffer[st->channels*frame_size], st->channels*(st->encoder_buffer-frame_size-total_buffer)); + OPUS_COPY(&st->delay_buffer[st->channels*(st->encoder_buffer-frame_size-total_buffer)], + &pcm_buf[0], + (frame_size+total_buffer)*st->channels); + } else { + OPUS_COPY(st->delay_buffer, &pcm_buf[(frame_size+total_buffer-st->encoder_buffer)*st->channels], st->encoder_buffer*st->channels); + } + /* gain_fade() and stereo_fade() need to be after the buffer copying + because we don't want any of this to affect the SILK part */ + if( st->prev_HB_gain < Q15ONE || HB_gain < Q15ONE ) { + gain_fade(pcm_buf, pcm_buf, + st->prev_HB_gain, HB_gain, celt_mode->overlap, frame_size, st->channels, celt_mode->window, st->Fs); + } + st->prev_HB_gain = HB_gain; + if (st->mode != MODE_HYBRID || st->stream_channels==1) + { + if (equiv_rate > 32000) + st->silk_mode.stereoWidth_Q14 = 16384; + else if (equiv_rate < 16000) + st->silk_mode.stereoWidth_Q14 = 0; + else + st->silk_mode.stereoWidth_Q14 = 16384 - 2048*(opus_int32)(32000-equiv_rate)/(equiv_rate-14000); + } + if( !st->energy_masking && st->channels == 2 ) { + /* Apply stereo width reduction (at low bitrates) */ + if( st->hybrid_stereo_width_Q14 < (1 << 14) || st->silk_mode.stereoWidth_Q14 < (1 << 14) ) { + opus_val16 g1, g2; + g1 = st->hybrid_stereo_width_Q14; + g2 = (opus_val16)(st->silk_mode.stereoWidth_Q14); +#ifdef FIXED_POINT + g1 = g1==16384 ? Q15ONE : SHL16(g1,1); + g2 = g2==16384 ? Q15ONE : SHL16(g2,1); +#else + g1 *= (1.f/16384); + g2 *= (1.f/16384); +#endif + stereo_fade(pcm_buf, pcm_buf, g1, g2, celt_mode->overlap, + frame_size, st->channels, celt_mode->window, st->Fs); + st->hybrid_stereo_width_Q14 = st->silk_mode.stereoWidth_Q14; + } + } + + if ( st->mode != MODE_CELT_ONLY && ec_tell(&enc)+17+20*(st->mode == MODE_HYBRID) <= 8*(max_data_bytes-1)) + { + /* For SILK mode, the redundancy is inferred from the length */ + if (st->mode == MODE_HYBRID) + ec_enc_bit_logp(&enc, redundancy, 12); + if (redundancy) + { + int max_redundancy; + ec_enc_bit_logp(&enc, celt_to_silk, 1); + if (st->mode == MODE_HYBRID) + { + /* Reserve the 8 bits needed for the redundancy length, + and at least a few bits for CELT if possible */ + max_redundancy = (max_data_bytes-1)-((ec_tell(&enc)+8+3+7)>>3); + } + else + max_redundancy = (max_data_bytes-1)-((ec_tell(&enc)+7)>>3); + /* Target the same bit-rate for redundancy as for the rest, + up to a max of 257 bytes */ + redundancy_bytes = IMIN(max_redundancy, redundancy_bytes); + redundancy_bytes = IMIN(257, IMAX(2, redundancy_bytes)); + if (st->mode == MODE_HYBRID) + ec_enc_uint(&enc, redundancy_bytes-2, 256); + } + } else { + redundancy = 0; + } + + if (!redundancy) + { + st->silk_bw_switch = 0; + redundancy_bytes = 0; + } + if (st->mode != MODE_CELT_ONLY)start_band=17; + + if (st->mode == MODE_SILK_ONLY) + { + ret = (ec_tell(&enc)+7)>>3; + ec_enc_done(&enc); + nb_compr_bytes = ret; + } else { + nb_compr_bytes = (max_data_bytes-1)-redundancy_bytes; + ec_enc_shrink(&enc, nb_compr_bytes); + } + +#ifndef DISABLE_FLOAT_API + if (redundancy || st->mode != MODE_SILK_ONLY) + celt_encoder_ctl(celt_enc, CELT_SET_ANALYSIS(&analysis_info)); +#endif + if (st->mode == MODE_HYBRID) { + SILKInfo info; + info.signalType = st->silk_mode.signalType; + info.offset = st->silk_mode.offset; + celt_encoder_ctl(celt_enc, CELT_SET_SILK_INFO(&info)); + } + + /* 5 ms redundant frame for CELT->SILK */ + if (redundancy && celt_to_silk) + { + int err; + celt_encoder_ctl(celt_enc, CELT_SET_START_BAND(0)); + celt_encoder_ctl(celt_enc, OPUS_SET_VBR(0)); + celt_encoder_ctl(celt_enc, OPUS_SET_BITRATE(OPUS_BITRATE_MAX)); + err = celt_encode_with_ec(celt_enc, pcm_buf, st->Fs/200, data+nb_compr_bytes, redundancy_bytes, NULL); + if (err < 0) + { + RESTORE_STACK; + return OPUS_INTERNAL_ERROR; + } + celt_encoder_ctl(celt_enc, OPUS_GET_FINAL_RANGE(&redundant_rng)); + celt_encoder_ctl(celt_enc, OPUS_RESET_STATE); + } + + celt_encoder_ctl(celt_enc, CELT_SET_START_BAND(start_band)); + + if (st->mode != MODE_SILK_ONLY) + { + if (st->mode != st->prev_mode && st->prev_mode > 0) + { + unsigned char dummy[2]; + celt_encoder_ctl(celt_enc, OPUS_RESET_STATE); + + /* Prefilling */ + celt_encode_with_ec(celt_enc, tmp_prefill, st->Fs/400, dummy, 2, NULL); + celt_encoder_ctl(celt_enc, CELT_SET_PREDICTION(0)); + } + /* If false, we already busted the budget and we'll end up with a "PLC frame" */ + if (ec_tell(&enc) <= 8*nb_compr_bytes) + { + /* Set the bitrate again if it was overridden in the redundancy code above*/ + if (redundancy && celt_to_silk && st->mode==MODE_HYBRID && st->use_vbr) + celt_encoder_ctl(celt_enc, OPUS_SET_BITRATE(st->bitrate_bps-st->silk_mode.bitRate)); + celt_encoder_ctl(celt_enc, OPUS_SET_VBR(st->use_vbr)); + ret = celt_encode_with_ec(celt_enc, pcm_buf, frame_size, NULL, nb_compr_bytes, &enc); + if (ret < 0) + { + RESTORE_STACK; + return OPUS_INTERNAL_ERROR; + } + /* Put CELT->SILK redundancy data in the right place. */ + if (redundancy && celt_to_silk && st->mode==MODE_HYBRID && st->use_vbr) + { + OPUS_MOVE(data+ret, data+nb_compr_bytes, redundancy_bytes); + nb_compr_bytes = nb_compr_bytes+redundancy_bytes; + } + } + } + + /* 5 ms redundant frame for SILK->CELT */ + if (redundancy && !celt_to_silk) + { + int err; + unsigned char dummy[2]; + int N2, N4; + N2 = st->Fs/200; + N4 = st->Fs/400; + + celt_encoder_ctl(celt_enc, OPUS_RESET_STATE); + celt_encoder_ctl(celt_enc, CELT_SET_START_BAND(0)); + celt_encoder_ctl(celt_enc, CELT_SET_PREDICTION(0)); + celt_encoder_ctl(celt_enc, OPUS_SET_VBR(0)); + celt_encoder_ctl(celt_enc, OPUS_SET_BITRATE(OPUS_BITRATE_MAX)); + + if (st->mode == MODE_HYBRID) + { + /* Shrink packet to what the encoder actually used. */ + nb_compr_bytes = ret; + ec_enc_shrink(&enc, nb_compr_bytes); + } + /* NOTE: We could speed this up slightly (at the expense of code size) by just adding a function that prefills the buffer */ + celt_encode_with_ec(celt_enc, pcm_buf+st->channels*(frame_size-N2-N4), N4, dummy, 2, NULL); + + err = celt_encode_with_ec(celt_enc, pcm_buf+st->channels*(frame_size-N2), N2, data+nb_compr_bytes, redundancy_bytes, NULL); + if (err < 0) + { + RESTORE_STACK; + return OPUS_INTERNAL_ERROR; + } + celt_encoder_ctl(celt_enc, OPUS_GET_FINAL_RANGE(&redundant_rng)); + } + + + + /* Signalling the mode in the first byte */ + data--; + data[0] = gen_toc(st->mode, st->Fs/frame_size, curr_bandwidth, st->stream_channels); + + st->rangeFinal = enc.rng ^ redundant_rng; + + if (to_celt) + st->prev_mode = MODE_CELT_ONLY; + else + st->prev_mode = st->mode; + st->prev_channels = st->stream_channels; + st->prev_framesize = frame_size; + + st->first = 0; + + /* DTX decision */ +#ifndef DISABLE_FLOAT_API + if (st->use_dtx && (analysis_info.valid || is_silence)) + { + if (decide_dtx_mode(analysis_info.activity_probability, &st->nb_no_activity_frames, + st->peak_signal_energy, pcm, frame_size, st->channels, is_silence, st->arch)) + { + st->rangeFinal = 0; + data[0] = gen_toc(st->mode, st->Fs/frame_size, curr_bandwidth, st->stream_channels); + RESTORE_STACK; + return 1; + } + } else { + st->nb_no_activity_frames = 0; + } +#endif + + /* In the unlikely case that the SILK encoder busted its target, tell + the decoder to call the PLC */ + if (ec_tell(&enc) > (max_data_bytes-1)*8) + { + if (max_data_bytes < 2) + { + RESTORE_STACK; + return OPUS_BUFFER_TOO_SMALL; + } + data[1] = 0; + ret = 1; + st->rangeFinal = 0; + } else if (st->mode==MODE_SILK_ONLY&&!redundancy) + { + /*When in LPC only mode it's perfectly + reasonable to strip off trailing zero bytes as + the required range decoder behavior is to + fill these in. This can't be done when the MDCT + modes are used because the decoder needs to know + the actual length for allocation purposes.*/ + while(ret>2&&data[ret]==0)ret--; + } + /* Count ToC and redundancy */ + ret += 1+redundancy_bytes; + if (!st->use_vbr) + { + if (opus_packet_pad(data, ret, max_data_bytes) != OPUS_OK) + { + RESTORE_STACK; + return OPUS_INTERNAL_ERROR; + } + ret = max_data_bytes; + } + RESTORE_STACK; + return ret; +} + +#ifdef FIXED_POINT + +#ifndef DISABLE_FLOAT_API +opus_int32 opus_encode_float(OpusEncoder *st, const float *pcm, int analysis_frame_size, + unsigned char *data, opus_int32 max_data_bytes) +{ + int i, ret; + int frame_size; + VARDECL(opus_int16, in); + ALLOC_STACK; + + frame_size = frame_size_select(analysis_frame_size, st->variable_duration, st->Fs); + if (frame_size <= 0) + { + RESTORE_STACK; + return OPUS_BAD_ARG; + } + ALLOC(in, frame_size*st->channels, opus_int16); + + for (i=0;ichannels;i++) + in[i] = FLOAT2INT16(pcm[i]); + ret = opus_encode_native(st, in, frame_size, data, max_data_bytes, 16, + pcm, analysis_frame_size, 0, -2, st->channels, downmix_float, 1); + RESTORE_STACK; + return ret; +} +#endif + +opus_int32 opus_encode(OpusEncoder *st, const opus_int16 *pcm, int analysis_frame_size, + unsigned char *data, opus_int32 out_data_bytes) +{ + int frame_size; + frame_size = frame_size_select(analysis_frame_size, st->variable_duration, st->Fs); + return opus_encode_native(st, pcm, frame_size, data, out_data_bytes, 16, + pcm, analysis_frame_size, 0, -2, st->channels, downmix_int, 0); +} + +#else +opus_int32 opus_encode(OpusEncoder *st, const opus_int16 *pcm, int analysis_frame_size, + unsigned char *data, opus_int32 max_data_bytes) +{ + int i, ret; + int frame_size; + VARDECL(float, in); + ALLOC_STACK; + + frame_size = frame_size_select(analysis_frame_size, st->variable_duration, st->Fs); + if (frame_size <= 0) + { + RESTORE_STACK; + return OPUS_BAD_ARG; + } + ALLOC(in, frame_size*st->channels, float); + + for (i=0;ichannels;i++) + in[i] = (1.0f/32768)*pcm[i]; + ret = opus_encode_native(st, in, frame_size, data, max_data_bytes, 16, + pcm, analysis_frame_size, 0, -2, st->channels, downmix_int, 0); + RESTORE_STACK; + return ret; +} +opus_int32 opus_encode_float(OpusEncoder *st, const float *pcm, int analysis_frame_size, + unsigned char *data, opus_int32 out_data_bytes) +{ + int frame_size; + frame_size = frame_size_select(analysis_frame_size, st->variable_duration, st->Fs); + return opus_encode_native(st, pcm, frame_size, data, out_data_bytes, 24, + pcm, analysis_frame_size, 0, -2, st->channels, downmix_float, 1); +} +#endif + + +int opus_encoder_ctl(OpusEncoder *st, int request, ...) +{ + int ret; + CELTEncoder *celt_enc; + va_list ap; + + ret = OPUS_OK; + va_start(ap, request); + + celt_enc = (CELTEncoder*)((char*)st+st->celt_enc_offset); + + switch (request) + { + case OPUS_SET_APPLICATION_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if ( (value != OPUS_APPLICATION_VOIP && value != OPUS_APPLICATION_AUDIO + && value != OPUS_APPLICATION_RESTRICTED_LOWDELAY) + || (!st->first && st->application != value)) + { + ret = OPUS_BAD_ARG; + break; + } + st->application = value; +#ifndef DISABLE_FLOAT_API + st->analysis.application = value; +#endif + } + break; + case OPUS_GET_APPLICATION_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = st->application; + } + break; + case OPUS_SET_BITRATE_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if (value != OPUS_AUTO && value != OPUS_BITRATE_MAX) + { + if (value <= 0) + goto bad_arg; + else if (value <= 500) + value = 500; + else if (value > (opus_int32)300000*st->channels) + value = (opus_int32)300000*st->channels; + } + st->user_bitrate_bps = value; + } + break; + case OPUS_GET_BITRATE_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = user_bitrate_to_bitrate(st, st->prev_framesize, 1276); + } + break; + case OPUS_SET_FORCE_CHANNELS_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if((value<1 || value>st->channels) && value != OPUS_AUTO) + { + goto bad_arg; + } + st->force_channels = value; + } + break; + case OPUS_GET_FORCE_CHANNELS_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = st->force_channels; + } + break; + case OPUS_SET_MAX_BANDWIDTH_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if (value < OPUS_BANDWIDTH_NARROWBAND || value > OPUS_BANDWIDTH_FULLBAND) + { + goto bad_arg; + } + st->max_bandwidth = value; + if (st->max_bandwidth == OPUS_BANDWIDTH_NARROWBAND) { + st->silk_mode.maxInternalSampleRate = 8000; + } else if (st->max_bandwidth == OPUS_BANDWIDTH_MEDIUMBAND) { + st->silk_mode.maxInternalSampleRate = 12000; + } else { + st->silk_mode.maxInternalSampleRate = 16000; + } + } + break; + case OPUS_GET_MAX_BANDWIDTH_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = st->max_bandwidth; + } + break; + case OPUS_SET_BANDWIDTH_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if ((value < OPUS_BANDWIDTH_NARROWBAND || value > OPUS_BANDWIDTH_FULLBAND) && value != OPUS_AUTO) + { + goto bad_arg; + } + st->user_bandwidth = value; + if (st->user_bandwidth == OPUS_BANDWIDTH_NARROWBAND) { + st->silk_mode.maxInternalSampleRate = 8000; + } else if (st->user_bandwidth == OPUS_BANDWIDTH_MEDIUMBAND) { + st->silk_mode.maxInternalSampleRate = 12000; + } else { + st->silk_mode.maxInternalSampleRate = 16000; + } + } + break; + case OPUS_GET_BANDWIDTH_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = st->bandwidth; + } + break; + case OPUS_SET_DTX_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if(value<0 || value>1) + { + goto bad_arg; + } + st->use_dtx = value; + } + break; + case OPUS_GET_DTX_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = st->use_dtx; + } + break; + case OPUS_SET_COMPLEXITY_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if(value<0 || value>10) + { + goto bad_arg; + } + st->silk_mode.complexity = value; + celt_encoder_ctl(celt_enc, OPUS_SET_COMPLEXITY(value)); + } + break; + case OPUS_GET_COMPLEXITY_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = st->silk_mode.complexity; + } + break; + case OPUS_SET_INBAND_FEC_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if(value<0 || value>1) + { + goto bad_arg; + } + st->silk_mode.useInBandFEC = value; + } + break; + case OPUS_GET_INBAND_FEC_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = st->silk_mode.useInBandFEC; + } + break; + case OPUS_SET_PACKET_LOSS_PERC_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if (value < 0 || value > 100) + { + goto bad_arg; + } + st->silk_mode.packetLossPercentage = value; + celt_encoder_ctl(celt_enc, OPUS_SET_PACKET_LOSS_PERC(value)); + } + break; + case OPUS_GET_PACKET_LOSS_PERC_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = st->silk_mode.packetLossPercentage; + } + break; + case OPUS_SET_VBR_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if(value<0 || value>1) + { + goto bad_arg; + } + st->use_vbr = value; + st->silk_mode.useCBR = 1-value; + } + break; + case OPUS_GET_VBR_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = st->use_vbr; + } + break; + case OPUS_SET_VOICE_RATIO_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if (value<-1 || value>100) + { + goto bad_arg; + } + st->voice_ratio = value; + } + break; + case OPUS_GET_VOICE_RATIO_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = st->voice_ratio; + } + break; + case OPUS_SET_VBR_CONSTRAINT_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if(value<0 || value>1) + { + goto bad_arg; + } + st->vbr_constraint = value; + } + break; + case OPUS_GET_VBR_CONSTRAINT_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = st->vbr_constraint; + } + break; + case OPUS_SET_SIGNAL_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if(value!=OPUS_AUTO && value!=OPUS_SIGNAL_VOICE && value!=OPUS_SIGNAL_MUSIC) + { + goto bad_arg; + } + st->signal_type = value; + } + break; + case OPUS_GET_SIGNAL_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = st->signal_type; + } + break; + case OPUS_GET_LOOKAHEAD_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = st->Fs/400; + if (st->application != OPUS_APPLICATION_RESTRICTED_LOWDELAY) + *value += st->delay_compensation; + } + break; + case OPUS_GET_SAMPLE_RATE_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = st->Fs; + } + break; + case OPUS_GET_FINAL_RANGE_REQUEST: + { + opus_uint32 *value = va_arg(ap, opus_uint32*); + if (!value) + { + goto bad_arg; + } + *value = st->rangeFinal; + } + break; + case OPUS_SET_LSB_DEPTH_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if (value<8 || value>24) + { + goto bad_arg; + } + st->lsb_depth=value; + } + break; + case OPUS_GET_LSB_DEPTH_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = st->lsb_depth; + } + break; + case OPUS_SET_EXPERT_FRAME_DURATION_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if (value != OPUS_FRAMESIZE_ARG && value != OPUS_FRAMESIZE_2_5_MS && + value != OPUS_FRAMESIZE_5_MS && value != OPUS_FRAMESIZE_10_MS && + value != OPUS_FRAMESIZE_20_MS && value != OPUS_FRAMESIZE_40_MS && + value != OPUS_FRAMESIZE_60_MS && value != OPUS_FRAMESIZE_80_MS && + value != OPUS_FRAMESIZE_100_MS && value != OPUS_FRAMESIZE_120_MS) + { + goto bad_arg; + } + st->variable_duration = value; + } + break; + case OPUS_GET_EXPERT_FRAME_DURATION_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = st->variable_duration; + } + break; + case OPUS_SET_PREDICTION_DISABLED_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if (value > 1 || value < 0) + goto bad_arg; + st->silk_mode.reducedDependency = value; + } + break; + case OPUS_GET_PREDICTION_DISABLED_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + goto bad_arg; + *value = st->silk_mode.reducedDependency; + } + break; + case OPUS_SET_PHASE_INVERSION_DISABLED_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if(value<0 || value>1) + { + goto bad_arg; + } + celt_encoder_ctl(celt_enc, OPUS_SET_PHASE_INVERSION_DISABLED(value)); + } + break; + case OPUS_GET_PHASE_INVERSION_DISABLED_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + celt_encoder_ctl(celt_enc, OPUS_GET_PHASE_INVERSION_DISABLED(value)); + } + break; + case OPUS_RESET_STATE: + { + void *silk_enc; + silk_EncControlStruct dummy; + char *start; + silk_enc = (char*)st+st->silk_enc_offset; +#ifndef DISABLE_FLOAT_API + tonality_analysis_reset(&st->analysis); +#endif + + start = (char*)&st->OPUS_ENCODER_RESET_START; + OPUS_CLEAR(start, sizeof(OpusEncoder) - (start - (char*)st)); + + celt_encoder_ctl(celt_enc, OPUS_RESET_STATE); + silk_InitEncoder( silk_enc, st->arch, &dummy ); + st->stream_channels = st->channels; + st->hybrid_stereo_width_Q14 = 1 << 14; + st->prev_HB_gain = Q15ONE; + st->first = 1; + st->mode = MODE_HYBRID; + st->bandwidth = OPUS_BANDWIDTH_FULLBAND; + st->variable_HP_smth2_Q15 = silk_LSHIFT( silk_lin2log( VARIABLE_HP_MIN_CUTOFF_HZ ), 8 ); + } + break; + case OPUS_SET_FORCE_MODE_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if ((value < MODE_SILK_ONLY || value > MODE_CELT_ONLY) && value != OPUS_AUTO) + { + goto bad_arg; + } + st->user_forced_mode = value; + } + break; + case OPUS_SET_LFE_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + st->lfe = value; + ret = celt_encoder_ctl(celt_enc, OPUS_SET_LFE(value)); + } + break; + case OPUS_SET_ENERGY_MASK_REQUEST: + { + opus_val16 *value = va_arg(ap, opus_val16*); + st->energy_masking = value; + ret = celt_encoder_ctl(celt_enc, OPUS_SET_ENERGY_MASK(value)); + } + break; + case OPUS_GET_IN_DTX_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + if (st->silk_mode.useDTX && (st->prev_mode == MODE_SILK_ONLY || st->prev_mode == MODE_HYBRID)) { + /* DTX determined by Silk. */ + int n; + void *silk_enc = (char*)st+st->silk_enc_offset; + *value = 1; + for (n=0;nsilk_mode.nChannelsInternal;n++) { + *value = *value && ((silk_encoder*)silk_enc)->state_Fxx[n].sCmn.noSpeechCounter >= NB_SPEECH_FRAMES_BEFORE_DTX; + } + } +#ifndef DISABLE_FLOAT_API + else if (st->use_dtx) { + /* DTX determined by Opus. */ + *value = st->nb_no_activity_frames >= NB_SPEECH_FRAMES_BEFORE_DTX; + } +#endif + else { + *value = 0; + } + } + break; + + case CELT_GET_MODE_REQUEST: + { + const CELTMode ** value = va_arg(ap, const CELTMode**); + if (!value) + { + goto bad_arg; + } + ret = celt_encoder_ctl(celt_enc, CELT_GET_MODE(value)); + } + break; + default: + /* fprintf(stderr, "unknown opus_encoder_ctl() request: %d", request);*/ + ret = OPUS_UNIMPLEMENTED; + break; + } + va_end(ap); + return ret; +bad_arg: + va_end(ap); + return OPUS_BAD_ARG; +} + +void opus_encoder_destroy(OpusEncoder *st) +{ + opus_free(st); +} diff --git a/extern/opus/src/opus_multistream.c b/extern/opus/src/opus_multistream.c new file mode 100644 index 0000000..09c3639 --- /dev/null +++ b/extern/opus/src/opus_multistream.c @@ -0,0 +1,92 @@ +/* Copyright (c) 2011 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + 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. + + 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 OWNER + 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. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "opus_multistream.h" +#include "opus.h" +#include "opus_private.h" +#include "stack_alloc.h" +#include +#include "float_cast.h" +#include "os_support.h" + + +int validate_layout(const ChannelLayout *layout) +{ + int i, max_channel; + + max_channel = layout->nb_streams+layout->nb_coupled_streams; + if (max_channel>255) + return 0; + for (i=0;inb_channels;i++) + { + if (layout->mapping[i] >= max_channel && layout->mapping[i] != 255) + return 0; + } + return 1; +} + + +int get_left_channel(const ChannelLayout *layout, int stream_id, int prev) +{ + int i; + i = (prev<0) ? 0 : prev+1; + for (;inb_channels;i++) + { + if (layout->mapping[i]==stream_id*2) + return i; + } + return -1; +} + +int get_right_channel(const ChannelLayout *layout, int stream_id, int prev) +{ + int i; + i = (prev<0) ? 0 : prev+1; + for (;inb_channels;i++) + { + if (layout->mapping[i]==stream_id*2+1) + return i; + } + return -1; +} + +int get_mono_channel(const ChannelLayout *layout, int stream_id, int prev) +{ + int i; + i = (prev<0) ? 0 : prev+1; + for (;inb_channels;i++) + { + if (layout->mapping[i]==stream_id+layout->nb_coupled_streams) + return i; + } + return -1; +} + diff --git a/extern/opus/src/opus_multistream_decoder.c b/extern/opus/src/opus_multistream_decoder.c new file mode 100644 index 0000000..0018517 --- /dev/null +++ b/extern/opus/src/opus_multistream_decoder.c @@ -0,0 +1,549 @@ +/* Copyright (c) 2011 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + 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. + + 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 OWNER + 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. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "opus_multistream.h" +#include "opus.h" +#include "opus_private.h" +#include "stack_alloc.h" +#include +#include "float_cast.h" +#include "os_support.h" + +/* DECODER */ + +#if defined(ENABLE_HARDENING) || defined(ENABLE_ASSERTIONS) +static void validate_ms_decoder(OpusMSDecoder *st) +{ + validate_layout(&st->layout); +} +#define VALIDATE_MS_DECODER(st) validate_ms_decoder(st) +#else +#define VALIDATE_MS_DECODER(st) +#endif + + +opus_int32 opus_multistream_decoder_get_size(int nb_streams, int nb_coupled_streams) +{ + int coupled_size; + int mono_size; + + if(nb_streams<1||nb_coupled_streams>nb_streams||nb_coupled_streams<0)return 0; + coupled_size = opus_decoder_get_size(2); + mono_size = opus_decoder_get_size(1); + return align(sizeof(OpusMSDecoder)) + + nb_coupled_streams * align(coupled_size) + + (nb_streams-nb_coupled_streams) * align(mono_size); +} + +int opus_multistream_decoder_init( + OpusMSDecoder *st, + opus_int32 Fs, + int channels, + int streams, + int coupled_streams, + const unsigned char *mapping +) +{ + int coupled_size; + int mono_size; + int i, ret; + char *ptr; + + if ((channels>255) || (channels<1) || (coupled_streams>streams) || + (streams<1) || (coupled_streams<0) || (streams>255-coupled_streams)) + return OPUS_BAD_ARG; + + st->layout.nb_channels = channels; + st->layout.nb_streams = streams; + st->layout.nb_coupled_streams = coupled_streams; + + for (i=0;ilayout.nb_channels;i++) + st->layout.mapping[i] = mapping[i]; + if (!validate_layout(&st->layout)) + return OPUS_BAD_ARG; + + ptr = (char*)st + align(sizeof(OpusMSDecoder)); + coupled_size = opus_decoder_get_size(2); + mono_size = opus_decoder_get_size(1); + + for (i=0;ilayout.nb_coupled_streams;i++) + { + ret=opus_decoder_init((OpusDecoder*)ptr, Fs, 2); + if(ret!=OPUS_OK)return ret; + ptr += align(coupled_size); + } + for (;ilayout.nb_streams;i++) + { + ret=opus_decoder_init((OpusDecoder*)ptr, Fs, 1); + if(ret!=OPUS_OK)return ret; + ptr += align(mono_size); + } + return OPUS_OK; +} + + +OpusMSDecoder *opus_multistream_decoder_create( + opus_int32 Fs, + int channels, + int streams, + int coupled_streams, + const unsigned char *mapping, + int *error +) +{ + int ret; + OpusMSDecoder *st; + if ((channels>255) || (channels<1) || (coupled_streams>streams) || + (streams<1) || (coupled_streams<0) || (streams>255-coupled_streams)) + { + if (error) + *error = OPUS_BAD_ARG; + return NULL; + } + st = (OpusMSDecoder *)opus_alloc(opus_multistream_decoder_get_size(streams, coupled_streams)); + if (st==NULL) + { + if (error) + *error = OPUS_ALLOC_FAIL; + return NULL; + } + ret = opus_multistream_decoder_init(st, Fs, channels, streams, coupled_streams, mapping); + if (error) + *error = ret; + if (ret != OPUS_OK) + { + opus_free(st); + st = NULL; + } + return st; +} + +static int opus_multistream_packet_validate(const unsigned char *data, + opus_int32 len, int nb_streams, opus_int32 Fs) +{ + int s; + int count; + unsigned char toc; + opus_int16 size[48]; + int samples=0; + opus_int32 packet_offset; + + for (s=0;slayout.nb_streams-1) + { + RESTORE_STACK; + return OPUS_INVALID_PACKET; + } + if (!do_plc) + { + int ret = opus_multistream_packet_validate(data, len, st->layout.nb_streams, Fs); + if (ret < 0) + { + RESTORE_STACK; + return ret; + } else if (ret > frame_size) + { + RESTORE_STACK; + return OPUS_BUFFER_TOO_SMALL; + } + } + for (s=0;slayout.nb_streams;s++) + { + OpusDecoder *dec; + opus_int32 packet_offset; + int ret; + + dec = (OpusDecoder*)ptr; + ptr += (s < st->layout.nb_coupled_streams) ? align(coupled_size) : align(mono_size); + + if (!do_plc && len<=0) + { + RESTORE_STACK; + return OPUS_INTERNAL_ERROR; + } + packet_offset = 0; + ret = opus_decode_native(dec, data, len, buf, frame_size, decode_fec, s!=st->layout.nb_streams-1, &packet_offset, soft_clip); + data += packet_offset; + len -= packet_offset; + if (ret <= 0) + { + RESTORE_STACK; + return ret; + } + frame_size = ret; + if (s < st->layout.nb_coupled_streams) + { + int chan, prev; + prev = -1; + /* Copy "left" audio to the channel(s) where it belongs */ + while ( (chan = get_left_channel(&st->layout, s, prev)) != -1) + { + (*copy_channel_out)(pcm, st->layout.nb_channels, chan, + buf, 2, frame_size, user_data); + prev = chan; + } + prev = -1; + /* Copy "right" audio to the channel(s) where it belongs */ + while ( (chan = get_right_channel(&st->layout, s, prev)) != -1) + { + (*copy_channel_out)(pcm, st->layout.nb_channels, chan, + buf+1, 2, frame_size, user_data); + prev = chan; + } + } else { + int chan, prev; + prev = -1; + /* Copy audio to the channel(s) where it belongs */ + while ( (chan = get_mono_channel(&st->layout, s, prev)) != -1) + { + (*copy_channel_out)(pcm, st->layout.nb_channels, chan, + buf, 1, frame_size, user_data); + prev = chan; + } + } + } + /* Handle muted channels */ + for (c=0;clayout.nb_channels;c++) + { + if (st->layout.mapping[c] == 255) + { + (*copy_channel_out)(pcm, st->layout.nb_channels, c, + NULL, 0, frame_size, user_data); + } + } + RESTORE_STACK; + return frame_size; +} + +#if !defined(DISABLE_FLOAT_API) +static void opus_copy_channel_out_float( + void *dst, + int dst_stride, + int dst_channel, + const opus_val16 *src, + int src_stride, + int frame_size, + void *user_data +) +{ + float *float_dst; + opus_int32 i; + (void)user_data; + float_dst = (float*)dst; + if (src != NULL) + { + for (i=0;ilayout.nb_streams;s++) + { + OpusDecoder *dec; + dec = (OpusDecoder*)ptr; + if (s < st->layout.nb_coupled_streams) + ptr += align(coupled_size); + else + ptr += align(mono_size); + ret = opus_decoder_ctl(dec, request, &tmp); + if (ret != OPUS_OK) break; + *value ^= tmp; + } + } + break; + case OPUS_RESET_STATE: + { + int s; + for (s=0;slayout.nb_streams;s++) + { + OpusDecoder *dec; + + dec = (OpusDecoder*)ptr; + if (s < st->layout.nb_coupled_streams) + ptr += align(coupled_size); + else + ptr += align(mono_size); + ret = opus_decoder_ctl(dec, OPUS_RESET_STATE); + if (ret != OPUS_OK) + break; + } + } + break; + case OPUS_MULTISTREAM_GET_DECODER_STATE_REQUEST: + { + int s; + opus_int32 stream_id; + OpusDecoder **value; + stream_id = va_arg(ap, opus_int32); + if (stream_id<0 || stream_id >= st->layout.nb_streams) + goto bad_arg; + value = va_arg(ap, OpusDecoder**); + if (!value) + { + goto bad_arg; + } + for (s=0;slayout.nb_coupled_streams) + ptr += align(coupled_size); + else + ptr += align(mono_size); + } + *value = (OpusDecoder*)ptr; + } + break; + case OPUS_SET_GAIN_REQUEST: + case OPUS_SET_PHASE_INVERSION_DISABLED_REQUEST: + { + int s; + /* This works for int32 params */ + opus_int32 value = va_arg(ap, opus_int32); + for (s=0;slayout.nb_streams;s++) + { + OpusDecoder *dec; + + dec = (OpusDecoder*)ptr; + if (s < st->layout.nb_coupled_streams) + ptr += align(coupled_size); + else + ptr += align(mono_size); + ret = opus_decoder_ctl(dec, request, value); + if (ret != OPUS_OK) + break; + } + } + break; + default: + ret = OPUS_UNIMPLEMENTED; + break; + } + return ret; +bad_arg: + return OPUS_BAD_ARG; +} + +int opus_multistream_decoder_ctl(OpusMSDecoder *st, int request, ...) +{ + int ret; + va_list ap; + va_start(ap, request); + ret = opus_multistream_decoder_ctl_va_list(st, request, ap); + va_end(ap); + return ret; +} + +void opus_multistream_decoder_destroy(OpusMSDecoder *st) +{ + opus_free(st); +} diff --git a/extern/opus/src/opus_multistream_encoder.c b/extern/opus/src/opus_multistream_encoder.c new file mode 100644 index 0000000..93204a1 --- /dev/null +++ b/extern/opus/src/opus_multistream_encoder.c @@ -0,0 +1,1328 @@ +/* Copyright (c) 2011 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + 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. + + 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 OWNER + 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. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "opus_multistream.h" +#include "opus.h" +#include "opus_private.h" +#include "stack_alloc.h" +#include +#include "float_cast.h" +#include "os_support.h" +#include "mathops.h" +#include "mdct.h" +#include "modes.h" +#include "bands.h" +#include "quant_bands.h" +#include "pitch.h" + +typedef struct { + int nb_streams; + int nb_coupled_streams; + unsigned char mapping[8]; +} VorbisLayout; + +/* Index is nb_channel-1*/ +static const VorbisLayout vorbis_mappings[8] = { + {1, 0, {0}}, /* 1: mono */ + {1, 1, {0, 1}}, /* 2: stereo */ + {2, 1, {0, 2, 1}}, /* 3: 1-d surround */ + {2, 2, {0, 1, 2, 3}}, /* 4: quadraphonic surround */ + {3, 2, {0, 4, 1, 2, 3}}, /* 5: 5-channel surround */ + {4, 2, {0, 4, 1, 2, 3, 5}}, /* 6: 5.1 surround */ + {4, 3, {0, 4, 1, 2, 3, 5, 6}}, /* 7: 6.1 surround */ + {5, 3, {0, 6, 1, 2, 3, 4, 5, 7}}, /* 8: 7.1 surround */ +}; + +static opus_val32 *ms_get_preemph_mem(OpusMSEncoder *st) +{ + int s; + char *ptr; + int coupled_size, mono_size; + + coupled_size = opus_encoder_get_size(2); + mono_size = opus_encoder_get_size(1); + ptr = (char*)st + align(sizeof(OpusMSEncoder)); + for (s=0;slayout.nb_streams;s++) + { + if (s < st->layout.nb_coupled_streams) + ptr += align(coupled_size); + else + ptr += align(mono_size); + } + /* void* cast avoids clang -Wcast-align warning */ + return (opus_val32*)(void*)(ptr+st->layout.nb_channels*120*sizeof(opus_val32)); +} + +static opus_val32 *ms_get_window_mem(OpusMSEncoder *st) +{ + int s; + char *ptr; + int coupled_size, mono_size; + + coupled_size = opus_encoder_get_size(2); + mono_size = opus_encoder_get_size(1); + ptr = (char*)st + align(sizeof(OpusMSEncoder)); + for (s=0;slayout.nb_streams;s++) + { + if (s < st->layout.nb_coupled_streams) + ptr += align(coupled_size); + else + ptr += align(mono_size); + } + /* void* cast avoids clang -Wcast-align warning */ + return (opus_val32*)(void*)ptr; +} + +static int validate_ambisonics(int nb_channels, int *nb_streams, int *nb_coupled_streams) +{ + int order_plus_one; + int acn_channels; + int nondiegetic_channels; + + if (nb_channels < 1 || nb_channels > 227) + return 0; + + order_plus_one = isqrt32(nb_channels); + acn_channels = order_plus_one * order_plus_one; + nondiegetic_channels = nb_channels - acn_channels; + + if (nondiegetic_channels != 0 && nondiegetic_channels != 2) + return 0; + + if (nb_streams) + *nb_streams = acn_channels + (nondiegetic_channels != 0); + if (nb_coupled_streams) + *nb_coupled_streams = nondiegetic_channels != 0; + return 1; +} + +static int validate_encoder_layout(const ChannelLayout *layout) +{ + int s; + for (s=0;snb_streams;s++) + { + if (s < layout->nb_coupled_streams) + { + if (get_left_channel(layout, s, -1)==-1) + return 0; + if (get_right_channel(layout, s, -1)==-1) + return 0; + } else { + if (get_mono_channel(layout, s, -1)==-1) + return 0; + } + } + return 1; +} + +static void channel_pos(int channels, int pos[8]) +{ + /* Position in the mix: 0 don't mix, 1: left, 2: center, 3:right */ + 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; + } +} + +#if 1 +/* Computes a rough approximation of log2(2^a + 2^b) */ +static opus_val16 logSum(opus_val16 a, opus_val16 b) +{ + opus_val16 max; + opus_val32 diff; + opus_val16 frac; + static const opus_val16 diff_table[17] = { + QCONST16(0.5000000f, DB_SHIFT), QCONST16(0.2924813f, DB_SHIFT), QCONST16(0.1609640f, DB_SHIFT), QCONST16(0.0849625f, DB_SHIFT), + QCONST16(0.0437314f, DB_SHIFT), QCONST16(0.0221971f, DB_SHIFT), QCONST16(0.0111839f, DB_SHIFT), QCONST16(0.0056136f, DB_SHIFT), + QCONST16(0.0028123f, DB_SHIFT) + }; + int low; + if (a>b) + { + max = a; + diff = SUB32(EXTEND32(a),EXTEND32(b)); + } else { + max = b; + diff = SUB32(EXTEND32(b),EXTEND32(a)); + } + if (!(diff < QCONST16(8.f, DB_SHIFT))) /* inverted to catch NaNs */ + return max; +#ifdef FIXED_POINT + low = SHR32(diff, DB_SHIFT-1); + frac = SHL16(diff - SHL16(low, DB_SHIFT-1), 16-DB_SHIFT); +#else + low = (int)floor(2*diff); + frac = 2*diff - low; +#endif + return max + diff_table[low] + MULT16_16_Q15(frac, SUB16(diff_table[low+1], diff_table[low])); +} +#else +opus_val16 logSum(opus_val16 a, opus_val16 b) +{ + return log2(pow(4, a)+ pow(4, b))/2; +} +#endif + +void surround_analysis(const CELTMode *celt_mode, const void *pcm, opus_val16 *bandLogE, opus_val32 *mem, opus_val32 *preemph_mem, + int len, int overlap, int channels, int rate, opus_copy_channel_in_func copy_channel_in, int arch +) +{ + int c; + int i; + int LM; + int pos[8] = {0}; + int upsample; + int frame_size; + int freq_size; + opus_val16 channel_offset; + opus_val32 bandE[21]; + opus_val16 maskLogE[3][21]; + VARDECL(opus_val32, in); + VARDECL(opus_val16, x); + VARDECL(opus_val32, freq); + SAVE_STACK; + + upsample = resampling_factor(rate); + frame_size = len*upsample; + freq_size = IMIN(960, frame_size); + + /* LM = log2(frame_size / 120) */ + for (LM=0;LMmaxLM;LM++) + if (celt_mode->shortMdctSize<preemph, preemph_mem+c, 0); +#ifndef FIXED_POINT + { + opus_val32 sum; + sum = celt_inner_prod(in, in, frame_size+overlap, 0); + /* This should filter out both NaNs and ridiculous signals that could + cause NaNs further down. */ + if (!(sum < 1e18f) || celt_isnan(sum)) + { + OPUS_CLEAR(in, frame_size+overlap); + preemph_mem[c] = 0; + } + } +#endif + OPUS_CLEAR(bandE, 21); + for (frame=0;framemdct, in+960*frame, freq, celt_mode->window, + overlap, celt_mode->maxLM-LM, 1, arch); + if (upsample != 1) + { + int bound = freq_size/upsample; + for (i=0;i=0;i--) + bandLogE[21*c+i] = MAX16(bandLogE[21*c+i], bandLogE[21*c+i+1]-QCONST16(2.f, DB_SHIFT)); + if (pos[c]==1) + { + for (i=0;i<21;i++) + maskLogE[0][i] = logSum(maskLogE[0][i], bandLogE[21*c+i]); + } else if (pos[c]==3) + { + for (i=0;i<21;i++) + maskLogE[2][i] = logSum(maskLogE[2][i], bandLogE[21*c+i]); + } else if (pos[c]==2) + { + for (i=0;i<21;i++) + { + maskLogE[0][i] = logSum(maskLogE[0][i], bandLogE[21*c+i]-QCONST16(.5f, DB_SHIFT)); + maskLogE[2][i] = logSum(maskLogE[2][i], bandLogE[21*c+i]-QCONST16(.5f, DB_SHIFT)); + } + } +#if 0 + for (i=0;i<21;i++) + printf("%f ", bandLogE[21*c+i]); + float sum=0; + for (i=0;i<21;i++) + sum += bandLogE[21*c+i]; + printf("%f ", sum/21); +#endif + OPUS_COPY(mem+c*overlap, in+frame_size, overlap); + } + for (i=0;i<21;i++) + maskLogE[1][i] = MIN32(maskLogE[0][i],maskLogE[2][i]); + channel_offset = HALF16(celt_log2(QCONST32(2.f,14)/(channels-1))); + for (c=0;c<3;c++) + for (i=0;i<21;i++) + maskLogE[c][i] += channel_offset; +#if 0 + for (c=0;c<3;c++) + { + for (i=0;i<21;i++) + printf("%f ", maskLogE[c][i]); + } +#endif + for (c=0;cnb_streams||nb_coupled_streams<0)return 0; + coupled_size = opus_encoder_get_size(2); + mono_size = opus_encoder_get_size(1); + return align(sizeof(OpusMSEncoder)) + + nb_coupled_streams * align(coupled_size) + + (nb_streams-nb_coupled_streams) * align(mono_size); +} + +opus_int32 opus_multistream_surround_encoder_get_size(int channels, int mapping_family) +{ + int nb_streams; + int nb_coupled_streams; + opus_int32 size; + + if (mapping_family==0) + { + if (channels==1) + { + nb_streams=1; + nb_coupled_streams=0; + } else if (channels==2) + { + nb_streams=1; + nb_coupled_streams=1; + } else + return 0; + } else if (mapping_family==1 && channels<=8 && channels>=1) + { + nb_streams=vorbis_mappings[channels-1].nb_streams; + nb_coupled_streams=vorbis_mappings[channels-1].nb_coupled_streams; + } else if (mapping_family==255) + { + nb_streams=channels; + nb_coupled_streams=0; + } else if (mapping_family==2) + { + if (!validate_ambisonics(channels, &nb_streams, &nb_coupled_streams)) + return 0; + } else + return 0; + size = opus_multistream_encoder_get_size(nb_streams, nb_coupled_streams); + if (channels>2) + { + size += channels*(120*sizeof(opus_val32) + sizeof(opus_val32)); + } + return size; +} + +static int opus_multistream_encoder_init_impl( + OpusMSEncoder *st, + opus_int32 Fs, + int channels, + int streams, + int coupled_streams, + const unsigned char *mapping, + int application, + MappingType mapping_type +) +{ + int coupled_size; + int mono_size; + int i, ret; + char *ptr; + + if ((channels>255) || (channels<1) || (coupled_streams>streams) || + (streams<1) || (coupled_streams<0) || (streams>255-coupled_streams)) + return OPUS_BAD_ARG; + + st->arch = opus_select_arch(); + st->layout.nb_channels = channels; + st->layout.nb_streams = streams; + st->layout.nb_coupled_streams = coupled_streams; + if (mapping_type != MAPPING_TYPE_SURROUND) + st->lfe_stream = -1; + st->bitrate_bps = OPUS_AUTO; + st->application = application; + st->variable_duration = OPUS_FRAMESIZE_ARG; + for (i=0;ilayout.nb_channels;i++) + st->layout.mapping[i] = mapping[i]; + if (!validate_layout(&st->layout)) + return OPUS_BAD_ARG; + if (mapping_type == MAPPING_TYPE_SURROUND && + !validate_encoder_layout(&st->layout)) + return OPUS_BAD_ARG; + if (mapping_type == MAPPING_TYPE_AMBISONICS && + !validate_ambisonics(st->layout.nb_channels, NULL, NULL)) + return OPUS_BAD_ARG; + ptr = (char*)st + align(sizeof(OpusMSEncoder)); + coupled_size = opus_encoder_get_size(2); + mono_size = opus_encoder_get_size(1); + + for (i=0;ilayout.nb_coupled_streams;i++) + { + ret = opus_encoder_init((OpusEncoder*)ptr, Fs, 2, application); + if(ret!=OPUS_OK)return ret; + if (i==st->lfe_stream) + opus_encoder_ctl((OpusEncoder*)ptr, OPUS_SET_LFE(1)); + ptr += align(coupled_size); + } + for (;ilayout.nb_streams;i++) + { + ret = opus_encoder_init((OpusEncoder*)ptr, Fs, 1, application); + if (i==st->lfe_stream) + opus_encoder_ctl((OpusEncoder*)ptr, OPUS_SET_LFE(1)); + if(ret!=OPUS_OK)return ret; + ptr += align(mono_size); + } + if (mapping_type == MAPPING_TYPE_SURROUND) + { + OPUS_CLEAR(ms_get_preemph_mem(st), channels); + OPUS_CLEAR(ms_get_window_mem(st), channels*120); + } + st->mapping_type = mapping_type; + return OPUS_OK; +} + +int opus_multistream_encoder_init( + OpusMSEncoder *st, + opus_int32 Fs, + int channels, + int streams, + int coupled_streams, + const unsigned char *mapping, + int application +) +{ + return opus_multistream_encoder_init_impl(st, Fs, channels, streams, + coupled_streams, mapping, + application, MAPPING_TYPE_NONE); +} + +int opus_multistream_surround_encoder_init( + OpusMSEncoder *st, + opus_int32 Fs, + int channels, + int mapping_family, + int *streams, + int *coupled_streams, + unsigned char *mapping, + int application +) +{ + MappingType mapping_type; + + if ((channels>255) || (channels<1)) + return OPUS_BAD_ARG; + st->lfe_stream = -1; + if (mapping_family==0) + { + if (channels==1) + { + *streams=1; + *coupled_streams=0; + mapping[0]=0; + } else if (channels==2) + { + *streams=1; + *coupled_streams=1; + mapping[0]=0; + mapping[1]=1; + } else + return OPUS_UNIMPLEMENTED; + } else if (mapping_family==1 && channels<=8 && channels>=1) + { + int i; + *streams=vorbis_mappings[channels-1].nb_streams; + *coupled_streams=vorbis_mappings[channels-1].nb_coupled_streams; + for (i=0;i=6) + st->lfe_stream = *streams-1; + } else if (mapping_family==255) + { + int i; + *streams=channels; + *coupled_streams=0; + for(i=0;i2 && mapping_family==1) { + mapping_type = MAPPING_TYPE_SURROUND; + } else if (mapping_family==2) + { + mapping_type = MAPPING_TYPE_AMBISONICS; + } else + { + mapping_type = MAPPING_TYPE_NONE; + } + return opus_multistream_encoder_init_impl(st, Fs, channels, *streams, + *coupled_streams, mapping, + application, mapping_type); +} + +OpusMSEncoder *opus_multistream_encoder_create( + opus_int32 Fs, + int channels, + int streams, + int coupled_streams, + const unsigned char *mapping, + int application, + int *error +) +{ + int ret; + OpusMSEncoder *st; + if ((channels>255) || (channels<1) || (coupled_streams>streams) || + (streams<1) || (coupled_streams<0) || (streams>255-coupled_streams)) + { + if (error) + *error = OPUS_BAD_ARG; + return NULL; + } + st = (OpusMSEncoder *)opus_alloc(opus_multistream_encoder_get_size(streams, coupled_streams)); + if (st==NULL) + { + if (error) + *error = OPUS_ALLOC_FAIL; + return NULL; + } + ret = opus_multistream_encoder_init(st, Fs, channels, streams, coupled_streams, mapping, application); + if (ret != OPUS_OK) + { + opus_free(st); + st = NULL; + } + if (error) + *error = ret; + return st; +} + +OpusMSEncoder *opus_multistream_surround_encoder_create( + opus_int32 Fs, + int channels, + int mapping_family, + int *streams, + int *coupled_streams, + unsigned char *mapping, + int application, + int *error +) +{ + int ret; + opus_int32 size; + OpusMSEncoder *st; + if ((channels>255) || (channels<1)) + { + if (error) + *error = OPUS_BAD_ARG; + return NULL; + } + size = opus_multistream_surround_encoder_get_size(channels, mapping_family); + if (!size) + { + if (error) + *error = OPUS_UNIMPLEMENTED; + return NULL; + } + st = (OpusMSEncoder *)opus_alloc(size); + if (st==NULL) + { + if (error) + *error = OPUS_ALLOC_FAIL; + return NULL; + } + ret = opus_multistream_surround_encoder_init(st, Fs, channels, mapping_family, streams, coupled_streams, mapping, application); + if (ret != OPUS_OK) + { + opus_free(st); + st = NULL; + } + if (error) + *error = ret; + return st; +} + +static void surround_rate_allocation( + OpusMSEncoder *st, + opus_int32 *rate, + int frame_size, + opus_int32 Fs + ) +{ + int i; + opus_int32 channel_rate; + int stream_offset; + int lfe_offset; + int coupled_ratio; /* Q8 */ + int lfe_ratio; /* Q8 */ + int nb_lfe; + int nb_uncoupled; + int nb_coupled; + int nb_normal; + opus_int32 channel_offset; + opus_int32 bitrate; + int total; + + nb_lfe = (st->lfe_stream!=-1); + nb_coupled = st->layout.nb_coupled_streams; + nb_uncoupled = st->layout.nb_streams-nb_coupled-nb_lfe; + nb_normal = 2*nb_coupled + nb_uncoupled; + + /* Give each non-LFE channel enough bits per channel for coding band energy. */ + channel_offset = 40*IMAX(50, Fs/frame_size); + + if (st->bitrate_bps==OPUS_AUTO) + { + bitrate = nb_normal*(channel_offset + Fs + 10000) + 8000*nb_lfe; + } else if (st->bitrate_bps==OPUS_BITRATE_MAX) + { + bitrate = nb_normal*300000 + nb_lfe*128000; + } else { + bitrate = st->bitrate_bps; + } + + /* Give LFE some basic stream_channel allocation but never exceed 1/20 of the + total rate for the non-energy part to avoid problems at really low rate. */ + lfe_offset = IMIN(bitrate/20, 3000) + 15*IMAX(50, Fs/frame_size); + + /* We give each stream (coupled or uncoupled) a starting bitrate. + This models the main saving of coupled channels over uncoupled. */ + stream_offset = (bitrate - channel_offset*nb_normal - lfe_offset*nb_lfe)/nb_normal/2; + stream_offset = IMAX(0, IMIN(20000, stream_offset)); + + /* Coupled streams get twice the mono rate after the offset is allocated. */ + coupled_ratio = 512; + /* Should depend on the bitrate, for now we assume LFE gets 1/8 the bits of mono */ + lfe_ratio = 32; + + total = (nb_uncoupled<<8) /* mono */ + + coupled_ratio*nb_coupled /* stereo */ + + nb_lfe*lfe_ratio; + channel_rate = 256*(opus_int64)(bitrate - lfe_offset*nb_lfe - stream_offset*(nb_coupled+nb_uncoupled) - channel_offset*nb_normal)/total; + + for (i=0;ilayout.nb_streams;i++) + { + if (ilayout.nb_coupled_streams) + rate[i] = 2*channel_offset + IMAX(0, stream_offset+(channel_rate*coupled_ratio>>8)); + else if (i!=st->lfe_stream) + rate[i] = channel_offset + IMAX(0, stream_offset + channel_rate); + else + rate[i] = IMAX(0, lfe_offset+(channel_rate*lfe_ratio>>8)); + } +} + +static void ambisonics_rate_allocation( + OpusMSEncoder *st, + opus_int32 *rate, + int frame_size, + opus_int32 Fs + ) +{ + int i; + opus_int32 total_rate; + opus_int32 per_stream_rate; + + const int nb_channels = st->layout.nb_streams + st->layout.nb_coupled_streams; + + if (st->bitrate_bps==OPUS_AUTO) + { + total_rate = (st->layout.nb_coupled_streams + st->layout.nb_streams) * + (Fs+60*Fs/frame_size) + st->layout.nb_streams * (opus_int32)15000; + } else if (st->bitrate_bps==OPUS_BITRATE_MAX) + { + total_rate = nb_channels * 320000; + } else + { + total_rate = st->bitrate_bps; + } + + /* Allocate equal number of bits to Ambisonic (uncoupled) and non-diegetic + * (coupled) streams */ + per_stream_rate = total_rate / st->layout.nb_streams; + for (i = 0; i < st->layout.nb_streams; i++) + { + rate[i] = per_stream_rate; + } +} + +static opus_int32 rate_allocation( + OpusMSEncoder *st, + opus_int32 *rate, + int frame_size + ) +{ + int i; + opus_int32 rate_sum=0; + opus_int32 Fs; + char *ptr; + + ptr = (char*)st + align(sizeof(OpusMSEncoder)); + opus_encoder_ctl((OpusEncoder*)ptr, OPUS_GET_SAMPLE_RATE(&Fs)); + + if (st->mapping_type == MAPPING_TYPE_AMBISONICS) { + ambisonics_rate_allocation(st, rate, frame_size, Fs); + } else + { + surround_rate_allocation(st, rate, frame_size, Fs); + } + + for (i=0;ilayout.nb_streams;i++) + { + rate[i] = IMAX(rate[i], 500); + rate_sum += rate[i]; + } + return rate_sum; +} + +/* Max size in case the encoder decides to return six frames (6 x 20 ms = 120 ms) */ +#define MS_FRAME_TMP (6*1275+12) +int opus_multistream_encode_native +( + OpusMSEncoder *st, + opus_copy_channel_in_func copy_channel_in, + const void *pcm, + int analysis_frame_size, + unsigned char *data, + opus_int32 max_data_bytes, + int lsb_depth, + downmix_func downmix, + int float_api, + void *user_data +) +{ + opus_int32 Fs; + int coupled_size; + int mono_size; + int s; + char *ptr; + int tot_size; + VARDECL(opus_val16, buf); + VARDECL(opus_val16, bandSMR); + unsigned char tmp_data[MS_FRAME_TMP]; + OpusRepacketizer rp; + opus_int32 vbr; + const CELTMode *celt_mode; + opus_int32 bitrates[256]; + opus_val16 bandLogE[42]; + opus_val32 *mem = NULL; + opus_val32 *preemph_mem=NULL; + int frame_size; + opus_int32 rate_sum; + opus_int32 smallest_packet; + ALLOC_STACK; + + if (st->mapping_type == MAPPING_TYPE_SURROUND) + { + preemph_mem = ms_get_preemph_mem(st); + mem = ms_get_window_mem(st); + } + + ptr = (char*)st + align(sizeof(OpusMSEncoder)); + opus_encoder_ctl((OpusEncoder*)ptr, OPUS_GET_SAMPLE_RATE(&Fs)); + opus_encoder_ctl((OpusEncoder*)ptr, OPUS_GET_VBR(&vbr)); + opus_encoder_ctl((OpusEncoder*)ptr, CELT_GET_MODE(&celt_mode)); + + frame_size = frame_size_select(analysis_frame_size, st->variable_duration, Fs); + if (frame_size <= 0) + { + RESTORE_STACK; + return OPUS_BAD_ARG; + } + + /* Smallest packet the encoder can produce. */ + smallest_packet = st->layout.nb_streams*2-1; + /* 100 ms needs an extra byte per stream for the ToC. */ + if (Fs/frame_size == 10) + smallest_packet += st->layout.nb_streams; + if (max_data_bytes < smallest_packet) + { + RESTORE_STACK; + return OPUS_BUFFER_TOO_SMALL; + } + ALLOC(buf, 2*frame_size, opus_val16); + coupled_size = opus_encoder_get_size(2); + mono_size = opus_encoder_get_size(1); + + ALLOC(bandSMR, 21*st->layout.nb_channels, opus_val16); + if (st->mapping_type == MAPPING_TYPE_SURROUND) + { + surround_analysis(celt_mode, pcm, bandSMR, mem, preemph_mem, frame_size, 120, st->layout.nb_channels, Fs, copy_channel_in, st->arch); + } + + /* Compute bitrate allocation between streams (this could be a lot better) */ + rate_sum = rate_allocation(st, bitrates, frame_size); + + if (!vbr) + { + if (st->bitrate_bps == OPUS_AUTO) + { + max_data_bytes = IMIN(max_data_bytes, 3*rate_sum/(3*8*Fs/frame_size)); + } else if (st->bitrate_bps != OPUS_BITRATE_MAX) + { + max_data_bytes = IMIN(max_data_bytes, IMAX(smallest_packet, + 3*st->bitrate_bps/(3*8*Fs/frame_size))); + } + } + ptr = (char*)st + align(sizeof(OpusMSEncoder)); + for (s=0;slayout.nb_streams;s++) + { + OpusEncoder *enc; + enc = (OpusEncoder*)ptr; + if (s < st->layout.nb_coupled_streams) + ptr += align(coupled_size); + else + ptr += align(mono_size); + opus_encoder_ctl(enc, OPUS_SET_BITRATE(bitrates[s])); + if (st->mapping_type == MAPPING_TYPE_SURROUND) + { + opus_int32 equiv_rate; + equiv_rate = st->bitrate_bps; + if (frame_size*50 < Fs) + equiv_rate -= 60*(Fs/frame_size - 50)*st->layout.nb_channels; + if (equiv_rate > 10000*st->layout.nb_channels) + opus_encoder_ctl(enc, OPUS_SET_BANDWIDTH(OPUS_BANDWIDTH_FULLBAND)); + else if (equiv_rate > 7000*st->layout.nb_channels) + opus_encoder_ctl(enc, OPUS_SET_BANDWIDTH(OPUS_BANDWIDTH_SUPERWIDEBAND)); + else if (equiv_rate > 5000*st->layout.nb_channels) + opus_encoder_ctl(enc, OPUS_SET_BANDWIDTH(OPUS_BANDWIDTH_WIDEBAND)); + else + opus_encoder_ctl(enc, OPUS_SET_BANDWIDTH(OPUS_BANDWIDTH_NARROWBAND)); + if (s < st->layout.nb_coupled_streams) + { + /* To preserve the spatial image, force stereo CELT on coupled streams */ + opus_encoder_ctl(enc, OPUS_SET_FORCE_MODE(MODE_CELT_ONLY)); + opus_encoder_ctl(enc, OPUS_SET_FORCE_CHANNELS(2)); + } + } + else if (st->mapping_type == MAPPING_TYPE_AMBISONICS) { + opus_encoder_ctl(enc, OPUS_SET_FORCE_MODE(MODE_CELT_ONLY)); + } + } + + ptr = (char*)st + align(sizeof(OpusMSEncoder)); + /* Counting ToC */ + tot_size = 0; + for (s=0;slayout.nb_streams;s++) + { + OpusEncoder *enc; + int len; + int curr_max; + int c1, c2; + int ret; + + opus_repacketizer_init(&rp); + enc = (OpusEncoder*)ptr; + if (s < st->layout.nb_coupled_streams) + { + int i; + int left, right; + left = get_left_channel(&st->layout, s, -1); + right = get_right_channel(&st->layout, s, -1); + (*copy_channel_in)(buf, 2, + pcm, st->layout.nb_channels, left, frame_size, user_data); + (*copy_channel_in)(buf+1, 2, + pcm, st->layout.nb_channels, right, frame_size, user_data); + ptr += align(coupled_size); + if (st->mapping_type == MAPPING_TYPE_SURROUND) + { + 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 i; + int chan = get_mono_channel(&st->layout, s, -1); + (*copy_channel_in)(buf, 1, + pcm, st->layout.nb_channels, chan, frame_size, user_data); + ptr += align(mono_size); + if (st->mapping_type == MAPPING_TYPE_SURROUND) + { + for (i=0;i<21;i++) + bandLogE[i] = bandSMR[21*chan+i]; + } + c1 = chan; + c2 = -1; + } + if (st->mapping_type == MAPPING_TYPE_SURROUND) + opus_encoder_ctl(enc, OPUS_SET_ENERGY_MASK(bandLogE)); + /* number of bytes left (+Toc) */ + curr_max = max_data_bytes - tot_size; + /* Reserve one byte for the last stream and two for the others */ + curr_max -= IMAX(0,2*(st->layout.nb_streams-s-1)-1); + /* For 100 ms, reserve an extra byte per stream for the ToC */ + if (Fs/frame_size == 10) + curr_max -= st->layout.nb_streams-s-1; + curr_max = IMIN(curr_max,MS_FRAME_TMP); + /* Repacketizer will add one or two bytes for self-delimited frames */ + if (s != st->layout.nb_streams-1) curr_max -= curr_max>253 ? 2 : 1; + if (!vbr && s == st->layout.nb_streams-1) + opus_encoder_ctl(enc, OPUS_SET_BITRATE(curr_max*(8*Fs/frame_size))); + len = opus_encode_native(enc, buf, frame_size, tmp_data, curr_max, lsb_depth, + pcm, analysis_frame_size, c1, c2, st->layout.nb_channels, downmix, float_api); + if (len<0) + { + RESTORE_STACK; + return len; + } + /* We need to use the repacketizer to add the self-delimiting lengths + while taking into account the fact that the encoder can now return + more than one frame at a time (e.g. 60 ms CELT-only) */ + ret = opus_repacketizer_cat(&rp, tmp_data, len); + /* If the opus_repacketizer_cat() fails, then something's seriously wrong + with the encoder. */ + if (ret != OPUS_OK) + { + RESTORE_STACK; + return OPUS_INTERNAL_ERROR; + } + len = opus_repacketizer_out_range_impl(&rp, 0, opus_repacketizer_get_nb_frames(&rp), + data, max_data_bytes-tot_size, s != st->layout.nb_streams-1, !vbr && s == st->layout.nb_streams-1); + data += len; + tot_size += len; + } + /*printf("\n");*/ + RESTORE_STACK; + return tot_size; +} + +#if !defined(DISABLE_FLOAT_API) +static void opus_copy_channel_in_float( + opus_val16 *dst, + int dst_stride, + const void *src, + int src_stride, + int src_channel, + int frame_size, + void *user_data +) +{ + const float *float_src; + opus_int32 i; + (void)user_data; + float_src = (const float *)src; + for (i=0;ilayout.nb_channels, IMAX(500*st->layout.nb_channels, value)); + } + st->bitrate_bps = value; + } + break; + case OPUS_GET_BITRATE_REQUEST: + { + int s; + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = 0; + for (s=0;slayout.nb_streams;s++) + { + opus_int32 rate; + OpusEncoder *enc; + enc = (OpusEncoder*)ptr; + if (s < st->layout.nb_coupled_streams) + ptr += align(coupled_size); + else + ptr += align(mono_size); + opus_encoder_ctl(enc, request, &rate); + *value += rate; + } + } + break; + case OPUS_GET_LSB_DEPTH_REQUEST: + case OPUS_GET_VBR_REQUEST: + case OPUS_GET_APPLICATION_REQUEST: + case OPUS_GET_BANDWIDTH_REQUEST: + case OPUS_GET_COMPLEXITY_REQUEST: + case OPUS_GET_PACKET_LOSS_PERC_REQUEST: + case OPUS_GET_DTX_REQUEST: + case OPUS_GET_VOICE_RATIO_REQUEST: + case OPUS_GET_VBR_CONSTRAINT_REQUEST: + case OPUS_GET_SIGNAL_REQUEST: + case OPUS_GET_LOOKAHEAD_REQUEST: + case OPUS_GET_SAMPLE_RATE_REQUEST: + case OPUS_GET_INBAND_FEC_REQUEST: + case OPUS_GET_FORCE_CHANNELS_REQUEST: + case OPUS_GET_PREDICTION_DISABLED_REQUEST: + case OPUS_GET_PHASE_INVERSION_DISABLED_REQUEST: + { + OpusEncoder *enc; + /* For int32* GET params, just query the first stream */ + opus_int32 *value = va_arg(ap, opus_int32*); + enc = (OpusEncoder*)ptr; + ret = opus_encoder_ctl(enc, request, value); + } + break; + case OPUS_GET_FINAL_RANGE_REQUEST: + { + int s; + opus_uint32 *value = va_arg(ap, opus_uint32*); + opus_uint32 tmp; + if (!value) + { + goto bad_arg; + } + *value=0; + for (s=0;slayout.nb_streams;s++) + { + OpusEncoder *enc; + enc = (OpusEncoder*)ptr; + if (s < st->layout.nb_coupled_streams) + ptr += align(coupled_size); + else + ptr += align(mono_size); + ret = opus_encoder_ctl(enc, request, &tmp); + if (ret != OPUS_OK) break; + *value ^= tmp; + } + } + break; + case OPUS_SET_LSB_DEPTH_REQUEST: + case OPUS_SET_COMPLEXITY_REQUEST: + case OPUS_SET_VBR_REQUEST: + case OPUS_SET_VBR_CONSTRAINT_REQUEST: + case OPUS_SET_MAX_BANDWIDTH_REQUEST: + case OPUS_SET_BANDWIDTH_REQUEST: + case OPUS_SET_SIGNAL_REQUEST: + case OPUS_SET_APPLICATION_REQUEST: + case OPUS_SET_INBAND_FEC_REQUEST: + case OPUS_SET_PACKET_LOSS_PERC_REQUEST: + case OPUS_SET_DTX_REQUEST: + case OPUS_SET_FORCE_MODE_REQUEST: + case OPUS_SET_FORCE_CHANNELS_REQUEST: + case OPUS_SET_PREDICTION_DISABLED_REQUEST: + case OPUS_SET_PHASE_INVERSION_DISABLED_REQUEST: + { + int s; + /* This works for int32 params */ + opus_int32 value = va_arg(ap, opus_int32); + for (s=0;slayout.nb_streams;s++) + { + OpusEncoder *enc; + + enc = (OpusEncoder*)ptr; + if (s < st->layout.nb_coupled_streams) + ptr += align(coupled_size); + else + ptr += align(mono_size); + ret = opus_encoder_ctl(enc, request, value); + if (ret != OPUS_OK) + break; + } + } + break; + case OPUS_MULTISTREAM_GET_ENCODER_STATE_REQUEST: + { + int s; + opus_int32 stream_id; + OpusEncoder **value; + stream_id = va_arg(ap, opus_int32); + if (stream_id<0 || stream_id >= st->layout.nb_streams) + goto bad_arg; + value = va_arg(ap, OpusEncoder**); + if (!value) + { + goto bad_arg; + } + for (s=0;slayout.nb_coupled_streams) + ptr += align(coupled_size); + else + ptr += align(mono_size); + } + *value = (OpusEncoder*)ptr; + } + break; + case OPUS_SET_EXPERT_FRAME_DURATION_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + st->variable_duration = value; + } + break; + case OPUS_GET_EXPERT_FRAME_DURATION_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = st->variable_duration; + } + break; + case OPUS_RESET_STATE: + { + int s; + if (st->mapping_type == MAPPING_TYPE_SURROUND) + { + OPUS_CLEAR(ms_get_preemph_mem(st), st->layout.nb_channels); + OPUS_CLEAR(ms_get_window_mem(st), st->layout.nb_channels*120); + } + for (s=0;slayout.nb_streams;s++) + { + OpusEncoder *enc; + enc = (OpusEncoder*)ptr; + if (s < st->layout.nb_coupled_streams) + ptr += align(coupled_size); + else + ptr += align(mono_size); + ret = opus_encoder_ctl(enc, OPUS_RESET_STATE); + if (ret != OPUS_OK) + break; + } + } + break; + default: + ret = OPUS_UNIMPLEMENTED; + break; + } + return ret; +bad_arg: + return OPUS_BAD_ARG; +} + +int opus_multistream_encoder_ctl(OpusMSEncoder *st, int request, ...) +{ + int ret; + va_list ap; + va_start(ap, request); + ret = opus_multistream_encoder_ctl_va_list(st, request, ap); + va_end(ap); + return ret; +} + +void opus_multistream_encoder_destroy(OpusMSEncoder *st) +{ + opus_free(st); +} diff --git a/extern/opus/src/opus_private.h b/extern/opus/src/opus_private.h new file mode 100644 index 0000000..5e2463f --- /dev/null +++ b/extern/opus/src/opus_private.h @@ -0,0 +1,201 @@ +/* Copyright (c) 2012 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + 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. + + 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 OWNER + 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. +*/ + + +#ifndef OPUS_PRIVATE_H +#define OPUS_PRIVATE_H + +#include "arch.h" +#include "opus.h" +#include "celt.h" + +#include /* va_list */ +#include /* offsetof */ + +struct OpusRepacketizer { + unsigned char toc; + int nb_frames; + const unsigned char *frames[48]; + opus_int16 len[48]; + int framesize; +}; + +typedef struct ChannelLayout { + int nb_channels; + int nb_streams; + int nb_coupled_streams; + unsigned char mapping[256]; +} ChannelLayout; + +typedef enum { + MAPPING_TYPE_NONE, + MAPPING_TYPE_SURROUND, + MAPPING_TYPE_AMBISONICS +} MappingType; + +struct OpusMSEncoder { + ChannelLayout layout; + int arch; + int lfe_stream; + int application; + int variable_duration; + MappingType mapping_type; + opus_int32 bitrate_bps; + /* Encoder states go here */ + /* then opus_val32 window_mem[channels*120]; */ + /* then opus_val32 preemph_mem[channels]; */ +}; + +struct OpusMSDecoder { + ChannelLayout layout; + /* Decoder states go here */ +}; + +int opus_multistream_encoder_ctl_va_list(struct OpusMSEncoder *st, int request, + va_list ap); +int opus_multistream_decoder_ctl_va_list(struct OpusMSDecoder *st, int request, + va_list ap); + +int validate_layout(const ChannelLayout *layout); +int get_left_channel(const ChannelLayout *layout, int stream_id, int prev); +int get_right_channel(const ChannelLayout *layout, int stream_id, int prev); +int get_mono_channel(const ChannelLayout *layout, int stream_id, int prev); + +typedef void (*opus_copy_channel_in_func)( + opus_val16 *dst, + int dst_stride, + const void *src, + int src_stride, + int src_channel, + int frame_size, + void *user_data +); + +typedef void (*opus_copy_channel_out_func)( + void *dst, + int dst_stride, + int dst_channel, + const opus_val16 *src, + int src_stride, + int frame_size, + void *user_data +); + +#define MODE_SILK_ONLY 1000 +#define MODE_HYBRID 1001 +#define MODE_CELT_ONLY 1002 + +#define OPUS_SET_VOICE_RATIO_REQUEST 11018 +#define OPUS_GET_VOICE_RATIO_REQUEST 11019 + +/** Configures the encoder's expected percentage of voice + * opposed to music or other signals. + * + * @note This interface is currently more aspiration than actuality. It's + * ultimately expected to bias an automatic signal classifier, but it currently + * just shifts the static bitrate to mode mapping around a little bit. + * + * @param[in] x int: Voice percentage in the range 0-100, inclusive. + * @hideinitializer */ +#define OPUS_SET_VOICE_RATIO(x) OPUS_SET_VOICE_RATIO_REQUEST, __opus_check_int(x) +/** Gets the encoder's configured voice ratio value, @see OPUS_SET_VOICE_RATIO + * + * @param[out] x int*: Voice percentage in the range 0-100, inclusive. + * @hideinitializer */ +#define OPUS_GET_VOICE_RATIO(x) OPUS_GET_VOICE_RATIO_REQUEST, __opus_check_int_ptr(x) + + +#define OPUS_SET_FORCE_MODE_REQUEST 11002 +#define OPUS_SET_FORCE_MODE(x) OPUS_SET_FORCE_MODE_REQUEST, __opus_check_int(x) + +typedef void (*downmix_func)(const void *, opus_val32 *, int, int, int, int, int); +void downmix_float(const void *_x, opus_val32 *sub, int subframe, int offset, int c1, int c2, int C); +void downmix_int(const void *_x, opus_val32 *sub, int subframe, int offset, int c1, int c2, int C); +int is_digital_silence(const opus_val16* pcm, int frame_size, int channels, int lsb_depth); + +int encode_size(int size, unsigned char *data); + +opus_int32 frame_size_select(opus_int32 frame_size, int variable_duration, opus_int32 Fs); + +opus_int32 opus_encode_native(OpusEncoder *st, const opus_val16 *pcm, int frame_size, + unsigned char *data, opus_int32 out_data_bytes, int lsb_depth, + const void *analysis_pcm, opus_int32 analysis_size, int c1, int c2, + int analysis_channels, downmix_func downmix, int float_api); + +int opus_decode_native(OpusDecoder *st, const unsigned char *data, opus_int32 len, + opus_val16 *pcm, int frame_size, int decode_fec, int self_delimited, + opus_int32 *packet_offset, int soft_clip); + +/* Make sure everything is properly aligned. */ +static OPUS_INLINE int align(int i) +{ + struct foo {char c; union { void* p; opus_int32 i; opus_val32 v; } u;}; + + unsigned int alignment = offsetof(struct foo, u); + + /* Optimizing compilers should optimize div and multiply into and + for all sensible alignment values. */ + return ((i + alignment - 1) / alignment) * alignment; +} + +int opus_packet_parse_impl(const unsigned char *data, opus_int32 len, + int self_delimited, unsigned char *out_toc, + const unsigned char *frames[48], opus_int16 size[48], + int *payload_offset, opus_int32 *packet_offset); + +opus_int32 opus_repacketizer_out_range_impl(OpusRepacketizer *rp, int begin, int end, + unsigned char *data, opus_int32 maxlen, int self_delimited, int pad); + +int pad_frame(unsigned char *data, opus_int32 len, opus_int32 new_len); + +int opus_multistream_encode_native +( + struct OpusMSEncoder *st, + opus_copy_channel_in_func copy_channel_in, + const void *pcm, + int analysis_frame_size, + unsigned char *data, + opus_int32 max_data_bytes, + int lsb_depth, + downmix_func downmix, + int float_api, + void *user_data +); + +int opus_multistream_decode_native( + struct OpusMSDecoder *st, + const unsigned char *data, + opus_int32 len, + void *pcm, + opus_copy_channel_out_func copy_channel_out, + int frame_size, + int decode_fec, + int soft_clip, + void *user_data +); + +#endif /* OPUS_PRIVATE_H */ diff --git a/extern/opus/src/opus_projection_decoder.c b/extern/opus/src/opus_projection_decoder.c new file mode 100644 index 0000000..c2e07d5 --- /dev/null +++ b/extern/opus/src/opus_projection_decoder.c @@ -0,0 +1,258 @@ +/* Copyright (c) 2017 Google Inc. + Written by Andrew Allen */ +/* + 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. + + 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 OWNER + 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. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "mathops.h" +#include "os_support.h" +#include "opus_private.h" +#include "opus_defines.h" +#include "opus_projection.h" +#include "opus_multistream.h" +#include "mapping_matrix.h" +#include "stack_alloc.h" + +struct OpusProjectionDecoder +{ + opus_int32 demixing_matrix_size_in_bytes; + /* Encoder states go here */ +}; + +#if !defined(DISABLE_FLOAT_API) +static void opus_projection_copy_channel_out_float( + void *dst, + int dst_stride, + int dst_channel, + const opus_val16 *src, + int src_stride, + int frame_size, + void *user_data) +{ + float *float_dst; + const MappingMatrix *matrix; + float_dst = (float *)dst; + matrix = (const MappingMatrix *)user_data; + + if (dst_channel == 0) + OPUS_CLEAR(float_dst, frame_size * dst_stride); + + if (src != NULL) + mapping_matrix_multiply_channel_out_float(matrix, src, dst_channel, + src_stride, float_dst, dst_stride, frame_size); +} +#endif + +static void opus_projection_copy_channel_out_short( + void *dst, + int dst_stride, + int dst_channel, + const opus_val16 *src, + int src_stride, + int frame_size, + void *user_data) +{ + opus_int16 *short_dst; + const MappingMatrix *matrix; + short_dst = (opus_int16 *)dst; + matrix = (const MappingMatrix *)user_data; + if (dst_channel == 0) + OPUS_CLEAR(short_dst, frame_size * dst_stride); + + if (src != NULL) + mapping_matrix_multiply_channel_out_short(matrix, src, dst_channel, + src_stride, short_dst, dst_stride, frame_size); +} + +static MappingMatrix *get_dec_demixing_matrix(OpusProjectionDecoder *st) +{ + /* void* cast avoids clang -Wcast-align warning */ + return (MappingMatrix*)(void*)((char*)st + + align(sizeof(OpusProjectionDecoder))); +} + +static OpusMSDecoder *get_multistream_decoder(OpusProjectionDecoder *st) +{ + /* void* cast avoids clang -Wcast-align warning */ + return (OpusMSDecoder*)(void*)((char*)st + + align(sizeof(OpusProjectionDecoder) + + st->demixing_matrix_size_in_bytes)); +} + +opus_int32 opus_projection_decoder_get_size(int channels, int streams, + int coupled_streams) +{ + opus_int32 matrix_size; + opus_int32 decoder_size; + + matrix_size = + mapping_matrix_get_size(streams + coupled_streams, channels); + if (!matrix_size) + return 0; + + decoder_size = opus_multistream_decoder_get_size(streams, coupled_streams); + if (!decoder_size) + return 0; + + return align(sizeof(OpusProjectionDecoder)) + matrix_size + decoder_size; +} + +int opus_projection_decoder_init(OpusProjectionDecoder *st, opus_int32 Fs, + int channels, int streams, int coupled_streams, + unsigned char *demixing_matrix, opus_int32 demixing_matrix_size) +{ + int nb_input_streams; + opus_int32 expected_matrix_size; + int i, ret; + unsigned char mapping[255]; + VARDECL(opus_int16, buf); + ALLOC_STACK; + + /* Verify supplied matrix size. */ + nb_input_streams = streams + coupled_streams; + expected_matrix_size = nb_input_streams * channels * sizeof(opus_int16); + if (expected_matrix_size != demixing_matrix_size) + { + RESTORE_STACK; + return OPUS_BAD_ARG; + } + + /* Convert demixing matrix input into internal format. */ + ALLOC(buf, nb_input_streams * channels, opus_int16); + for (i = 0; i < nb_input_streams * channels; i++) + { + int s = demixing_matrix[2*i + 1] << 8 | demixing_matrix[2*i]; + s = ((s & 0xFFFF) ^ 0x8000) - 0x8000; + buf[i] = (opus_int16)s; + } + + /* Assign demixing matrix. */ + st->demixing_matrix_size_in_bytes = + mapping_matrix_get_size(channels, nb_input_streams); + if (!st->demixing_matrix_size_in_bytes) + { + RESTORE_STACK; + return OPUS_BAD_ARG; + } + + mapping_matrix_init(get_dec_demixing_matrix(st), channels, nb_input_streams, 0, + buf, demixing_matrix_size); + + /* Set trivial mapping so each input channel pairs with a matrix column. */ + for (i = 0; i < channels; i++) + mapping[i] = i; + + ret = opus_multistream_decoder_init( + get_multistream_decoder(st), Fs, channels, streams, coupled_streams, mapping); + RESTORE_STACK; + return ret; +} + +OpusProjectionDecoder *opus_projection_decoder_create( + opus_int32 Fs, int channels, int streams, int coupled_streams, + unsigned char *demixing_matrix, opus_int32 demixing_matrix_size, int *error) +{ + int size; + int ret; + OpusProjectionDecoder *st; + + /* Allocate space for the projection decoder. */ + size = opus_projection_decoder_get_size(channels, streams, coupled_streams); + if (!size) { + if (error) + *error = OPUS_ALLOC_FAIL; + return NULL; + } + st = (OpusProjectionDecoder *)opus_alloc(size); + if (!st) + { + if (error) + *error = OPUS_ALLOC_FAIL; + return NULL; + } + + /* Initialize projection decoder with provided settings. */ + ret = opus_projection_decoder_init(st, Fs, channels, streams, coupled_streams, + demixing_matrix, demixing_matrix_size); + if (ret != OPUS_OK) + { + opus_free(st); + st = NULL; + } + if (error) + *error = ret; + return st; +} + +#ifdef FIXED_POINT +int opus_projection_decode(OpusProjectionDecoder *st, const unsigned char *data, + opus_int32 len, opus_int16 *pcm, int frame_size, + int decode_fec) +{ + return opus_multistream_decode_native(get_multistream_decoder(st), data, len, + pcm, opus_projection_copy_channel_out_short, frame_size, decode_fec, 0, + get_dec_demixing_matrix(st)); +} +#else +int opus_projection_decode(OpusProjectionDecoder *st, const unsigned char *data, + opus_int32 len, opus_int16 *pcm, int frame_size, + int decode_fec) +{ + return opus_multistream_decode_native(get_multistream_decoder(st), data, len, + pcm, opus_projection_copy_channel_out_short, frame_size, decode_fec, 1, + get_dec_demixing_matrix(st)); +} +#endif + +#ifndef DISABLE_FLOAT_API +int opus_projection_decode_float(OpusProjectionDecoder *st, const unsigned char *data, + opus_int32 len, float *pcm, int frame_size, int decode_fec) +{ + return opus_multistream_decode_native(get_multistream_decoder(st), data, len, + pcm, opus_projection_copy_channel_out_float, frame_size, decode_fec, 0, + get_dec_demixing_matrix(st)); +} +#endif + +int opus_projection_decoder_ctl(OpusProjectionDecoder *st, int request, ...) +{ + va_list ap; + int ret = OPUS_OK; + + va_start(ap, request); + ret = opus_multistream_decoder_ctl_va_list(get_multistream_decoder(st), + request, ap); + va_end(ap); + return ret; +} + +void opus_projection_decoder_destroy(OpusProjectionDecoder *st) +{ + opus_free(st); +} + diff --git a/extern/opus/src/opus_projection_encoder.c b/extern/opus/src/opus_projection_encoder.c new file mode 100644 index 0000000..06fb2d2 --- /dev/null +++ b/extern/opus/src/opus_projection_encoder.c @@ -0,0 +1,468 @@ +/* Copyright (c) 2017 Google Inc. + Written by Andrew Allen */ +/* + 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. + + 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 OWNER + 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. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "mathops.h" +#include "os_support.h" +#include "opus_private.h" +#include "opus_defines.h" +#include "opus_projection.h" +#include "opus_multistream.h" +#include "stack_alloc.h" +#include "mapping_matrix.h" + +struct OpusProjectionEncoder +{ + opus_int32 mixing_matrix_size_in_bytes; + opus_int32 demixing_matrix_size_in_bytes; + /* Encoder states go here */ +}; + +#if !defined(DISABLE_FLOAT_API) +static void opus_projection_copy_channel_in_float( + opus_val16 *dst, + int dst_stride, + const void *src, + int src_stride, + int src_channel, + int frame_size, + void *user_data +) +{ + mapping_matrix_multiply_channel_in_float((const MappingMatrix*)user_data, + (const float*)src, src_stride, dst, src_channel, dst_stride, frame_size); +} +#endif + +static void opus_projection_copy_channel_in_short( + opus_val16 *dst, + int dst_stride, + const void *src, + int src_stride, + int src_channel, + int frame_size, + void *user_data +) +{ + mapping_matrix_multiply_channel_in_short((const MappingMatrix*)user_data, + (const opus_int16*)src, src_stride, dst, src_channel, dst_stride, frame_size); +} + +static int get_order_plus_one_from_channels(int channels, int *order_plus_one) +{ + int order_plus_one_; + int acn_channels; + int nondiegetic_channels; + + /* Allowed numbers of channels: + * (1 + n)^2 + 2j, for n = 0...14 and j = 0 or 1. + */ + if (channels < 1 || channels > 227) + return OPUS_BAD_ARG; + + order_plus_one_ = isqrt32(channels); + acn_channels = order_plus_one_ * order_plus_one_; + nondiegetic_channels = channels - acn_channels; + if (nondiegetic_channels != 0 && nondiegetic_channels != 2) + return OPUS_BAD_ARG; + + if (order_plus_one) + *order_plus_one = order_plus_one_; + return OPUS_OK; +} + +static int get_streams_from_channels(int channels, int mapping_family, + int *streams, int *coupled_streams, + int *order_plus_one) +{ + if (mapping_family == 3) + { + if (get_order_plus_one_from_channels(channels, order_plus_one) != OPUS_OK) + return OPUS_BAD_ARG; + if (streams) + *streams = (channels + 1) / 2; + if (coupled_streams) + *coupled_streams = channels / 2; + return OPUS_OK; + } + return OPUS_BAD_ARG; +} + +static MappingMatrix *get_mixing_matrix(OpusProjectionEncoder *st) +{ + /* void* cast avoids clang -Wcast-align warning */ + return (MappingMatrix *)(void*)((char*)st + + align(sizeof(OpusProjectionEncoder))); +} + +static MappingMatrix *get_enc_demixing_matrix(OpusProjectionEncoder *st) +{ + /* void* cast avoids clang -Wcast-align warning */ + return (MappingMatrix *)(void*)((char*)st + + align(sizeof(OpusProjectionEncoder) + + st->mixing_matrix_size_in_bytes)); +} + +static OpusMSEncoder *get_multistream_encoder(OpusProjectionEncoder *st) +{ + /* void* cast avoids clang -Wcast-align warning */ + return (OpusMSEncoder *)(void*)((char*)st + + align(sizeof(OpusProjectionEncoder) + + st->mixing_matrix_size_in_bytes + + st->demixing_matrix_size_in_bytes)); +} + +opus_int32 opus_projection_ambisonics_encoder_get_size(int channels, + int mapping_family) +{ + int nb_streams; + int nb_coupled_streams; + int order_plus_one; + int mixing_matrix_rows, mixing_matrix_cols; + int demixing_matrix_rows, demixing_matrix_cols; + opus_int32 mixing_matrix_size, demixing_matrix_size; + opus_int32 encoder_size; + int ret; + + ret = get_streams_from_channels(channels, mapping_family, &nb_streams, + &nb_coupled_streams, &order_plus_one); + if (ret != OPUS_OK) + return 0; + + if (order_plus_one == 2) + { + mixing_matrix_rows = mapping_matrix_foa_mixing.rows; + mixing_matrix_cols = mapping_matrix_foa_mixing.cols; + demixing_matrix_rows = mapping_matrix_foa_demixing.rows; + demixing_matrix_cols = mapping_matrix_foa_demixing.cols; + } + else if (order_plus_one == 3) + { + mixing_matrix_rows = mapping_matrix_soa_mixing.rows; + mixing_matrix_cols = mapping_matrix_soa_mixing.cols; + demixing_matrix_rows = mapping_matrix_soa_demixing.rows; + demixing_matrix_cols = mapping_matrix_soa_demixing.cols; + } + else if (order_plus_one == 4) + { + mixing_matrix_rows = mapping_matrix_toa_mixing.rows; + mixing_matrix_cols = mapping_matrix_toa_mixing.cols; + demixing_matrix_rows = mapping_matrix_toa_demixing.rows; + demixing_matrix_cols = mapping_matrix_toa_demixing.cols; + } + else + return 0; + + mixing_matrix_size = + mapping_matrix_get_size(mixing_matrix_rows, mixing_matrix_cols); + if (!mixing_matrix_size) + return 0; + + demixing_matrix_size = + mapping_matrix_get_size(demixing_matrix_rows, demixing_matrix_cols); + if (!demixing_matrix_size) + return 0; + + encoder_size = + opus_multistream_encoder_get_size(nb_streams, nb_coupled_streams); + if (!encoder_size) + return 0; + + return align(sizeof(OpusProjectionEncoder)) + + mixing_matrix_size + demixing_matrix_size + encoder_size; +} + +int opus_projection_ambisonics_encoder_init(OpusProjectionEncoder *st, opus_int32 Fs, + int channels, int mapping_family, + int *streams, int *coupled_streams, + int application) +{ + MappingMatrix *mixing_matrix; + MappingMatrix *demixing_matrix; + OpusMSEncoder *ms_encoder; + int i; + int ret; + int order_plus_one; + unsigned char mapping[255]; + + if (streams == NULL || coupled_streams == NULL) { + return OPUS_BAD_ARG; + } + + if (get_streams_from_channels(channels, mapping_family, streams, + coupled_streams, &order_plus_one) != OPUS_OK) + return OPUS_BAD_ARG; + + if (mapping_family == 3) + { + /* Assign mixing matrix based on available pre-computed matrices. */ + mixing_matrix = get_mixing_matrix(st); + if (order_plus_one == 2) + { + mapping_matrix_init(mixing_matrix, mapping_matrix_foa_mixing.rows, + mapping_matrix_foa_mixing.cols, mapping_matrix_foa_mixing.gain, + mapping_matrix_foa_mixing_data, + sizeof(mapping_matrix_foa_mixing_data)); + } + else if (order_plus_one == 3) + { + mapping_matrix_init(mixing_matrix, mapping_matrix_soa_mixing.rows, + mapping_matrix_soa_mixing.cols, mapping_matrix_soa_mixing.gain, + mapping_matrix_soa_mixing_data, + sizeof(mapping_matrix_soa_mixing_data)); + } + else if (order_plus_one == 4) + { + mapping_matrix_init(mixing_matrix, mapping_matrix_toa_mixing.rows, + mapping_matrix_toa_mixing.cols, mapping_matrix_toa_mixing.gain, + mapping_matrix_toa_mixing_data, + sizeof(mapping_matrix_toa_mixing_data)); + } + else + return OPUS_BAD_ARG; + + st->mixing_matrix_size_in_bytes = mapping_matrix_get_size( + mixing_matrix->rows, mixing_matrix->cols); + if (!st->mixing_matrix_size_in_bytes) + return OPUS_BAD_ARG; + + /* Assign demixing matrix based on available pre-computed matrices. */ + demixing_matrix = get_enc_demixing_matrix(st); + if (order_plus_one == 2) + { + mapping_matrix_init(demixing_matrix, mapping_matrix_foa_demixing.rows, + mapping_matrix_foa_demixing.cols, mapping_matrix_foa_demixing.gain, + mapping_matrix_foa_demixing_data, + sizeof(mapping_matrix_foa_demixing_data)); + } + else if (order_plus_one == 3) + { + mapping_matrix_init(demixing_matrix, mapping_matrix_soa_demixing.rows, + mapping_matrix_soa_demixing.cols, mapping_matrix_soa_demixing.gain, + mapping_matrix_soa_demixing_data, + sizeof(mapping_matrix_soa_demixing_data)); + } + else if (order_plus_one == 4) + { + mapping_matrix_init(demixing_matrix, mapping_matrix_toa_demixing.rows, + mapping_matrix_toa_demixing.cols, mapping_matrix_toa_demixing.gain, + mapping_matrix_toa_demixing_data, + sizeof(mapping_matrix_toa_demixing_data)); + } + else + return OPUS_BAD_ARG; + + st->demixing_matrix_size_in_bytes = mapping_matrix_get_size( + demixing_matrix->rows, demixing_matrix->cols); + if (!st->demixing_matrix_size_in_bytes) + return OPUS_BAD_ARG; + } + else + return OPUS_UNIMPLEMENTED; + + /* Ensure matrices are large enough for desired coding scheme. */ + if (*streams + *coupled_streams > mixing_matrix->rows || + channels > mixing_matrix->cols || + channels > demixing_matrix->rows || + *streams + *coupled_streams > demixing_matrix->cols) + return OPUS_BAD_ARG; + + /* Set trivial mapping so each input channel pairs with a matrix column. */ + for (i = 0; i < channels; i++) + mapping[i] = i; + + /* Initialize multistream encoder with provided settings. */ + ms_encoder = get_multistream_encoder(st); + ret = opus_multistream_encoder_init(ms_encoder, Fs, channels, *streams, + *coupled_streams, mapping, application); + return ret; +} + +OpusProjectionEncoder *opus_projection_ambisonics_encoder_create( + opus_int32 Fs, int channels, int mapping_family, int *streams, + int *coupled_streams, int application, int *error) +{ + int size; + int ret; + OpusProjectionEncoder *st; + + /* Allocate space for the projection encoder. */ + size = opus_projection_ambisonics_encoder_get_size(channels, mapping_family); + if (!size) { + if (error) + *error = OPUS_ALLOC_FAIL; + return NULL; + } + st = (OpusProjectionEncoder *)opus_alloc(size); + if (!st) + { + if (error) + *error = OPUS_ALLOC_FAIL; + return NULL; + } + + /* Initialize projection encoder with provided settings. */ + ret = opus_projection_ambisonics_encoder_init(st, Fs, channels, + mapping_family, streams, coupled_streams, application); + if (ret != OPUS_OK) + { + opus_free(st); + st = NULL; + } + if (error) + *error = ret; + return st; +} + +int opus_projection_encode(OpusProjectionEncoder *st, const opus_int16 *pcm, + int frame_size, unsigned char *data, + opus_int32 max_data_bytes) +{ + return opus_multistream_encode_native(get_multistream_encoder(st), + opus_projection_copy_channel_in_short, pcm, frame_size, data, + max_data_bytes, 16, downmix_int, 0, get_mixing_matrix(st)); +} + +#ifndef DISABLE_FLOAT_API +#ifdef FIXED_POINT +int opus_projection_encode_float(OpusProjectionEncoder *st, const float *pcm, + int frame_size, unsigned char *data, + opus_int32 max_data_bytes) +{ + return opus_multistream_encode_native(get_multistream_encoder(st), + opus_projection_copy_channel_in_float, pcm, frame_size, data, + max_data_bytes, 16, downmix_float, 1, get_mixing_matrix(st)); +} +#else +int opus_projection_encode_float(OpusProjectionEncoder *st, const float *pcm, + int frame_size, unsigned char *data, + opus_int32 max_data_bytes) +{ + return opus_multistream_encode_native(get_multistream_encoder(st), + opus_projection_copy_channel_in_float, pcm, frame_size, data, + max_data_bytes, 24, downmix_float, 1, get_mixing_matrix(st)); +} +#endif +#endif + +void opus_projection_encoder_destroy(OpusProjectionEncoder *st) +{ + opus_free(st); +} + +int opus_projection_encoder_ctl(OpusProjectionEncoder *st, int request, ...) +{ + va_list ap; + MappingMatrix *demixing_matrix; + OpusMSEncoder *ms_encoder; + int ret = OPUS_OK; + + ms_encoder = get_multistream_encoder(st); + demixing_matrix = get_enc_demixing_matrix(st); + + va_start(ap, request); + switch(request) + { + case OPUS_PROJECTION_GET_DEMIXING_MATRIX_SIZE_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = + ms_encoder->layout.nb_channels * (ms_encoder->layout.nb_streams + + ms_encoder->layout.nb_coupled_streams) * sizeof(opus_int16); + } + break; + case OPUS_PROJECTION_GET_DEMIXING_MATRIX_GAIN_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = demixing_matrix->gain; + } + break; + case OPUS_PROJECTION_GET_DEMIXING_MATRIX_REQUEST: + { + int i, j, k, l; + int nb_input_streams; + int nb_output_streams; + unsigned char *external_char; + opus_int16 *internal_short; + opus_int32 external_size; + opus_int32 internal_size; + + /* (I/O is in relation to the decoder's perspective). */ + nb_input_streams = ms_encoder->layout.nb_streams + + ms_encoder->layout.nb_coupled_streams; + nb_output_streams = ms_encoder->layout.nb_channels; + + external_char = va_arg(ap, unsigned char *); + external_size = va_arg(ap, opus_int32); + if (!external_char) + { + goto bad_arg; + } + internal_short = mapping_matrix_get_data(demixing_matrix); + internal_size = nb_input_streams * nb_output_streams * sizeof(opus_int16); + if (external_size != internal_size) + { + goto bad_arg; + } + + /* Copy demixing matrix subset to output destination. */ + l = 0; + for (i = 0; i < nb_input_streams; i++) { + for (j = 0; j < nb_output_streams; j++) { + k = demixing_matrix->rows * i + j; + external_char[2*l] = (unsigned char)internal_short[k]; + external_char[2*l+1] = (unsigned char)(internal_short[k] >> 8); + l++; + } + } + } + break; + default: + { + ret = opus_multistream_encoder_ctl_va_list(ms_encoder, request, ap); + } + break; + } + va_end(ap); + return ret; + +bad_arg: + va_end(ap); + return OPUS_BAD_ARG; +} + diff --git a/extern/opus/src/repacketizer.c b/extern/opus/src/repacketizer.c new file mode 100644 index 0000000..bda44a1 --- /dev/null +++ b/extern/opus/src/repacketizer.c @@ -0,0 +1,349 @@ +/* Copyright (c) 2011 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + 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. + + 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 OWNER + 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. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "opus.h" +#include "opus_private.h" +#include "os_support.h" + + +int opus_repacketizer_get_size(void) +{ + return sizeof(OpusRepacketizer); +} + +OpusRepacketizer *opus_repacketizer_init(OpusRepacketizer *rp) +{ + rp->nb_frames = 0; + return rp; +} + +OpusRepacketizer *opus_repacketizer_create(void) +{ + OpusRepacketizer *rp; + rp=(OpusRepacketizer *)opus_alloc(opus_repacketizer_get_size()); + if(rp==NULL)return NULL; + return opus_repacketizer_init(rp); +} + +void opus_repacketizer_destroy(OpusRepacketizer *rp) +{ + opus_free(rp); +} + +static int opus_repacketizer_cat_impl(OpusRepacketizer *rp, const unsigned char *data, opus_int32 len, int self_delimited) +{ + unsigned char tmp_toc; + int curr_nb_frames,ret; + /* Set of check ToC */ + if (len<1) return OPUS_INVALID_PACKET; + if (rp->nb_frames == 0) + { + rp->toc = data[0]; + rp->framesize = opus_packet_get_samples_per_frame(data, 8000); + } else if ((rp->toc&0xFC) != (data[0]&0xFC)) + { + /*fprintf(stderr, "toc mismatch: 0x%x vs 0x%x\n", rp->toc, data[0]);*/ + return OPUS_INVALID_PACKET; + } + curr_nb_frames = opus_packet_get_nb_frames(data, len); + if(curr_nb_frames<1) return OPUS_INVALID_PACKET; + + /* Check the 120 ms maximum packet size */ + if ((curr_nb_frames+rp->nb_frames)*rp->framesize > 960) + { + return OPUS_INVALID_PACKET; + } + + ret=opus_packet_parse_impl(data, len, self_delimited, &tmp_toc, &rp->frames[rp->nb_frames], &rp->len[rp->nb_frames], NULL, NULL); + if(ret<1)return ret; + + rp->nb_frames += curr_nb_frames; + return OPUS_OK; +} + +int opus_repacketizer_cat(OpusRepacketizer *rp, const unsigned char *data, opus_int32 len) +{ + return opus_repacketizer_cat_impl(rp, data, len, 0); +} + +int opus_repacketizer_get_nb_frames(OpusRepacketizer *rp) +{ + return rp->nb_frames; +} + +opus_int32 opus_repacketizer_out_range_impl(OpusRepacketizer *rp, int begin, int end, + unsigned char *data, opus_int32 maxlen, int self_delimited, int pad) +{ + int i, count; + opus_int32 tot_size; + opus_int16 *len; + const unsigned char **frames; + unsigned char * ptr; + + if (begin<0 || begin>=end || end>rp->nb_frames) + { + /*fprintf(stderr, "%d %d %d\n", begin, end, rp->nb_frames);*/ + return OPUS_BAD_ARG; + } + count = end-begin; + + len = rp->len+begin; + frames = rp->frames+begin; + if (self_delimited) + tot_size = 1 + (len[count-1]>=252); + else + tot_size = 0; + + ptr = data; + if (count==1) + { + /* Code 0 */ + tot_size += len[0]+1; + if (tot_size > maxlen) + return OPUS_BUFFER_TOO_SMALL; + *ptr++ = rp->toc&0xFC; + } else if (count==2) + { + if (len[1] == len[0]) + { + /* Code 1 */ + tot_size += 2*len[0]+1; + if (tot_size > maxlen) + return OPUS_BUFFER_TOO_SMALL; + *ptr++ = (rp->toc&0xFC) | 0x1; + } else { + /* Code 2 */ + tot_size += len[0]+len[1]+2+(len[0]>=252); + if (tot_size > maxlen) + return OPUS_BUFFER_TOO_SMALL; + *ptr++ = (rp->toc&0xFC) | 0x2; + ptr += encode_size(len[0], ptr); + } + } + if (count > 2 || (pad && tot_size < maxlen)) + { + /* Code 3 */ + int vbr; + int pad_amount=0; + + /* Restart the process for the padding case */ + ptr = data; + if (self_delimited) + tot_size = 1 + (len[count-1]>=252); + else + tot_size = 0; + vbr = 0; + for (i=1;i=252) + len[i]; + tot_size += len[count-1]; + + if (tot_size > maxlen) + return OPUS_BUFFER_TOO_SMALL; + *ptr++ = (rp->toc&0xFC) | 0x3; + *ptr++ = count | 0x80; + } else { + tot_size += count*len[0]+2; + if (tot_size > maxlen) + return OPUS_BUFFER_TOO_SMALL; + *ptr++ = (rp->toc&0xFC) | 0x3; + *ptr++ = count; + } + pad_amount = pad ? (maxlen-tot_size) : 0; + if (pad_amount != 0) + { + int nb_255s; + data[1] |= 0x40; + nb_255s = (pad_amount-1)/255; + for (i=0;inb_frames, data, maxlen, 0, 0); +} + +int opus_packet_pad(unsigned char *data, opus_int32 len, opus_int32 new_len) +{ + OpusRepacketizer rp; + opus_int32 ret; + if (len < 1) + return OPUS_BAD_ARG; + if (len==new_len) + return OPUS_OK; + else if (len > new_len) + return OPUS_BAD_ARG; + opus_repacketizer_init(&rp); + /* Moving payload to the end of the packet so we can do in-place padding */ + OPUS_MOVE(data+new_len-len, data, len); + ret = opus_repacketizer_cat(&rp, data+new_len-len, len); + if (ret != OPUS_OK) + return ret; + ret = opus_repacketizer_out_range_impl(&rp, 0, rp.nb_frames, data, new_len, 0, 1); + if (ret > 0) + return OPUS_OK; + else + return ret; +} + +opus_int32 opus_packet_unpad(unsigned char *data, opus_int32 len) +{ + OpusRepacketizer rp; + opus_int32 ret; + if (len < 1) + return OPUS_BAD_ARG; + opus_repacketizer_init(&rp); + ret = opus_repacketizer_cat(&rp, data, len); + if (ret < 0) + return ret; + ret = opus_repacketizer_out_range_impl(&rp, 0, rp.nb_frames, data, len, 0, 0); + celt_assert(ret > 0 && ret <= len); + return ret; +} + +int opus_multistream_packet_pad(unsigned char *data, opus_int32 len, opus_int32 new_len, int nb_streams) +{ + int s; + int count; + unsigned char toc; + opus_int16 size[48]; + opus_int32 packet_offset; + opus_int32 amount; + + if (len < 1) + return OPUS_BAD_ARG; + if (len==new_len) + return OPUS_OK; + else if (len > new_len) + return OPUS_BAD_ARG; + amount = new_len - len; + /* Seek to last stream */ + for (s=0;s +#include +#include + +#define MAX_PACKETOUT 32000 + +void usage(char *argv0) +{ + fprintf(stderr, "usage: %s [options] input_file output_file\n", argv0); +} + +static void int_to_char(opus_uint32 i, unsigned char ch[4]) +{ + ch[0] = i>>24; + ch[1] = (i>>16)&0xFF; + ch[2] = (i>>8)&0xFF; + ch[3] = i&0xFF; +} + +static opus_uint32 char_to_int(unsigned char ch[4]) +{ + return ((opus_uint32)ch[0]<<24) | ((opus_uint32)ch[1]<<16) + | ((opus_uint32)ch[2]<< 8) | (opus_uint32)ch[3]; +} + +int main(int argc, char *argv[]) +{ + int i, eof=0; + FILE *fin, *fout; + unsigned char packets[48][1500]; + int len[48]; + int rng[48]; + OpusRepacketizer *rp; + unsigned char output_packet[MAX_PACKETOUT]; + int merge = 1, split=0; + + if (argc < 3) + { + usage(argv[0]); + return EXIT_FAILURE; + } + for (i=1;i48) + { + fprintf(stderr, "-merge parameter must be less than 48.\n"); + return EXIT_FAILURE; + } + i++; + } else if (strcmp(argv[i], "-split")==0) + split = 1; + else + { + fprintf(stderr, "Unknown option: %s\n", argv[i]); + usage(argv[0]); + return EXIT_FAILURE; + } + } + fin = fopen(argv[argc-2], "r"); + if(fin==NULL) + { + fprintf(stderr, "Error opening input file: %s\n", argv[argc-2]); + return EXIT_FAILURE; + } + fout = fopen(argv[argc-1], "w"); + if(fout==NULL) + { + fprintf(stderr, "Error opening output file: %s\n", argv[argc-1]); + fclose(fin); + return EXIT_FAILURE; + } + + rp = opus_repacketizer_create(); + while (!eof) + { + int err; + int nb_packets=merge; + opus_repacketizer_init(rp); + for (i=0;i1500 || len[i]<0) + { + if (feof(fin)) + { + eof = 1; + } else { + fprintf(stderr, "Invalid payload length\n"); + fclose(fin); + fclose(fout); + return EXIT_FAILURE; + } + break; + } + err = fread(ch, 1, 4, fin); + rng[i] = char_to_int(ch); + err = fread(packets[i], 1, len[i], fin); + if (feof(fin)) + { + eof = 1; + break; + } + err = opus_repacketizer_cat(rp, packets[i], len[i]); + if (err!=OPUS_OK) + { + fprintf(stderr, "opus_repacketizer_cat() failed: %s\n", opus_strerror(err)); + break; + } + } + nb_packets = i; + + if (eof) + break; + + if (!split) + { + err = opus_repacketizer_out(rp, output_packet, MAX_PACKETOUT); + if (err>0) { + unsigned char int_field[4]; + int_to_char(err, int_field); + if(fwrite(int_field, 1, 4, fout)!=4){ + fprintf(stderr, "Error writing.\n"); + return EXIT_FAILURE; + } + int_to_char(rng[nb_packets-1], int_field); + if (fwrite(int_field, 1, 4, fout)!=4) { + fprintf(stderr, "Error writing.\n"); + return EXIT_FAILURE; + } + if (fwrite(output_packet, 1, err, fout)!=(unsigned)err) { + fprintf(stderr, "Error writing.\n"); + return EXIT_FAILURE; + } + /*fprintf(stderr, "out len = %d\n", err);*/ + } else { + fprintf(stderr, "opus_repacketizer_out() failed: %s\n", opus_strerror(err)); + } + } else { + int nb_frames = opus_repacketizer_get_nb_frames(rp); + for (i=0;i0) { + unsigned char int_field[4]; + int_to_char(err, int_field); + if (fwrite(int_field, 1, 4, fout)!=4) { + fprintf(stderr, "Error writing.\n"); + return EXIT_FAILURE; + } + if (i==nb_frames-1) + int_to_char(rng[nb_packets-1], int_field); + else + int_to_char(0, int_field); + if (fwrite(int_field, 1, 4, fout)!=4) { + fprintf(stderr, "Error writing.\n"); + return EXIT_FAILURE; + } + if (fwrite(output_packet, 1, err, fout)!=(unsigned)err) { + fprintf(stderr, "Error writing.\n"); + return EXIT_FAILURE; + } + /*fprintf(stderr, "out len = %d\n", err);*/ + } else { + fprintf(stderr, "opus_repacketizer_out() failed: %s\n", opus_strerror(err)); + } + + } + } + } + + fclose(fin); + fclose(fout); + return EXIT_SUCCESS; +} diff --git a/extern/opus/src/tansig_table.h b/extern/opus/src/tansig_table.h new file mode 100644 index 0000000..c76f844 --- /dev/null +++ b/extern/opus/src/tansig_table.h @@ -0,0 +1,45 @@ +/* This file is auto-generated by gen_tables */ + +static const float tansig_table[201] = { +0.000000f, 0.039979f, 0.079830f, 0.119427f, 0.158649f, +0.197375f, 0.235496f, 0.272905f, 0.309507f, 0.345214f, +0.379949f, 0.413644f, 0.446244f, 0.477700f, 0.507977f, +0.537050f, 0.564900f, 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.821040f, +0.833655f, 0.845456f, 0.856485f, 0.866784f, 0.876393f, +0.885352f, 0.893698f, 0.901468f, 0.908698f, 0.915420f, +0.921669f, 0.927473f, 0.932862f, 0.937863f, 0.942503f, +0.946806f, 0.950795f, 0.954492f, 0.957917f, 0.961090f, +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.992020f, +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.997590f, +0.997775f, 0.997946f, 0.998104f, 0.998249f, 0.998384f, +0.998508f, 0.998623f, 0.998728f, 0.998826f, 0.998916f, +0.999000f, 0.999076f, 0.999147f, 0.999213f, 0.999273f, +0.999329f, 0.999381f, 0.999428f, 0.999472f, 0.999513f, +0.999550f, 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.999970f, +0.999973f, 0.999975f, 0.999977f, 0.999978f, 0.999980f, +0.999982f, 0.999983f, 0.999984f, 0.999986f, 0.999987f, +0.999988f, 0.999989f, 0.999990f, 0.999990f, 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.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, +1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, +1.000000f, +}; diff --git a/extern/opus/tests/opus_decode_fuzzer.c b/extern/opus/tests/opus_decode_fuzzer.c new file mode 100644 index 0000000..9002622 --- /dev/null +++ b/extern/opus/tests/opus_decode_fuzzer.c @@ -0,0 +1,126 @@ +/* Copyright (c) 2017 Google Inc. */ +/* + 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. + + 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 OWNER + 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. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include "opus.h" +#include "opus_types.h" + +#define MAX_FRAME_SAMP 5760 +#define MAX_PACKET 1500 + +/* 4 bytes: packet length, 4 bytes: encoder final range */ +#define SETUP_BYTE_COUNT 8 + +typedef struct { + int fs; + int channels; +} TocInfo; + +static void ParseToc(const uint8_t *toc, TocInfo *const info) { + const int samp_freqs[5] = {8000, 12000, 16000, 24000, 48000}; + const int bandwidth = opus_packet_get_bandwidth(toc); + + info->fs = samp_freqs[bandwidth - OPUS_BANDWIDTH_NARROWBAND]; + info->channels = opus_packet_get_nb_channels(toc); +} + +/* Treats the input data as concatenated packets encoded by opus_demo, + * structured as + * bytes 0..3: packet length + * bytes 4..7: encoder final range + * bytes 8+ : Opus packet, including ToC + */ +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + OpusDecoder *dec; + opus_int16 *pcm; + uint8_t *packet; + TocInfo toc; + int i, err; + + /* Not enough data to setup the decoder (+1 for the ToC) */ + if (size < SETUP_BYTE_COUNT + 1) { + return 0; + } + + /* Create decoder based on info from the first ToC available */ + ParseToc(&data[SETUP_BYTE_COUNT], &toc); + + dec = opus_decoder_create(toc.fs, toc.channels, &err); + if (err != OPUS_OK | dec == NULL) { + return 0; + } + + pcm = (opus_int16*) malloc(sizeof(*pcm) * MAX_FRAME_SAMP * toc.channels); + packet = (uint8_t*) calloc(MAX_PACKET, sizeof(*packet)); + + i = 0; + while (1) { + int len, fec; + + if (i + SETUP_BYTE_COUNT >= size) { + break; + } + + len = (opus_uint32) data[i ] << 24 | + (opus_uint32) data[i + 1] << 16 | + (opus_uint32) data[i + 2] << 8 | + (opus_uint32) data[i + 3]; + if (len > MAX_PACKET || len < 0) { + break; + } + + /* Bytes 4..7 represent encoder final range, but are unused here. + * Instead, byte 4 is repurposed to determine if FEC is used. */ + fec = data[i + 4] & 1; + + /* Lost packet */ + if (len == 0) { + int frame_size; + opus_decoder_ctl(dec, OPUS_GET_LAST_PACKET_DURATION(&frame_size)); + (void) opus_decode(dec, NULL, size, pcm, frame_size, fec); + } else { + if (i + SETUP_BYTE_COUNT + len > size) { + break; + } + memcpy(pcm, &data[i + SETUP_BYTE_COUNT], len); + (void) opus_decode(dec, data, size, pcm, MAX_FRAME_SAMP, fec); + } + + i += SETUP_BYTE_COUNT + len; + } + + opus_decoder_destroy(dec); + free(pcm); + free(packet); + + return 0; +} diff --git a/extern/opus/tests/opus_decode_fuzzer.options b/extern/opus/tests/opus_decode_fuzzer.options new file mode 100644 index 0000000..e5ae71b --- /dev/null +++ b/extern/opus/tests/opus_decode_fuzzer.options @@ -0,0 +1,2 @@ +[libfuzzer] +max_len = 1000000 diff --git a/extern/opus/tests/opus_encode_regressions.c b/extern/opus/tests/opus_encode_regressions.c new file mode 100644 index 0000000..2923473 --- /dev/null +++ b/extern/opus/tests/opus_encode_regressions.c @@ -0,0 +1,1035 @@ +/* Copyright (c) 2016 Mark Harris, Jean-Marc Valin */ +/* + 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. + + 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 OWNER + 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. +*/ + + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include "opus_multistream.h" +#include "opus.h" +#include "test_opus_common.h" + + +static int celt_ec_internal_error(void) +{ + OpusMSEncoder *enc; + int err; + unsigned char data[2460]; + int streams; + int coupled_streams; + unsigned char mapping[1]; + + enc = opus_multistream_surround_encoder_create(16000, 1, 1, &streams, + &coupled_streams, mapping, OPUS_APPLICATION_VOIP, &err); + opus_multistream_encoder_ctl(enc, OPUS_SET_SIGNAL(OPUS_SIGNAL_MUSIC)); + opus_multistream_encoder_ctl(enc, OPUS_SET_VBR(0)); + opus_multistream_encoder_ctl(enc, OPUS_SET_VBR_CONSTRAINT(0)); + opus_multistream_encoder_ctl(enc, OPUS_SET_PREDICTION_DISABLED(1)); + opus_multistream_encoder_ctl(enc, OPUS_SET_PHASE_INVERSION_DISABLED(0)); + opus_multistream_encoder_ctl(enc, OPUS_SET_DTX(0)); + opus_multistream_encoder_ctl(enc, OPUS_SET_COMPLEXITY(0)); + opus_multistream_encoder_ctl(enc, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_NARROWBAND)); + opus_multistream_encoder_ctl(enc, OPUS_SET_BANDWIDTH(OPUS_AUTO)); + opus_multistream_encoder_ctl(enc, OPUS_SET_LSB_DEPTH(8)); + opus_multistream_encoder_ctl(enc, OPUS_SET_INBAND_FEC(0)); + opus_multistream_encoder_ctl(enc, OPUS_SET_PACKET_LOSS_PERC(0)); + opus_multistream_encoder_ctl(enc, OPUS_SET_BITRATE(OPUS_AUTO)); + { + static const short pcm[320] = + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1792, 1799, 1799, + 1799, 1799, 1799, 1799, 1799, 1799, 1799, 1799, 1799, + 1799, 1799, 1799, 1799, 1799, 0, 25600, 1799, 1799, + 1799, 1799, 1799, 1799, 1799, 1799, 1799, 1799, 1799, + 1799, 1799, 1799, 1799, 7, 0, 255, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 32767, -1, + 0, 0, 0, 100, 0, 16384, 0, 0, 0, + 0, 0, 0, 4, 0, 0, -256, 255, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0,-32768, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 128, 0, 0, 0, 0, + 0, 0, 0, 0, -256, 0, 0, 32, 0, + 0, 0, 0, 0, 0, 0, 4352, 4, 228, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 5632, 0, 0, + 0, 0,-32768, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 256, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + -3944, 10500, 4285, 10459, -6474, 10204, -6539, 11601, -6824, + 13385, -7142, 13872,-11553, 13670, -7725, 13463, -6887, 7874, + -5580, 12600, -4964, 12480, 3254, 11741, -4210, 9741, -3155, + 7558, -5468, 5431, -1073, 3641, -1304, 0, -1, 343, + 26, 0, 0, 150, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1799, 1799, 1799, 1799, 1799, -2553, + 7, 1792, 1799, 1799, 1799, 1799, 1799, 1799, 1799, + 1799, 1799, 1799, 1799, -9721 + }; + err = opus_multistream_encode(enc, pcm, 320, data, 2460); + assert(err > 0); + } + opus_multistream_encoder_ctl(enc, OPUS_SET_SIGNAL(OPUS_SIGNAL_MUSIC)); + opus_multistream_encoder_ctl(enc, OPUS_SET_VBR(0)); + opus_multistream_encoder_ctl(enc, OPUS_SET_VBR_CONSTRAINT(1)); + opus_multistream_encoder_ctl(enc, OPUS_SET_PREDICTION_DISABLED(1)); + opus_multistream_encoder_ctl(enc, OPUS_SET_PHASE_INVERSION_DISABLED(0)); + opus_multistream_encoder_ctl(enc, OPUS_SET_DTX(1)); + opus_multistream_encoder_ctl(enc, OPUS_SET_COMPLEXITY(10)); + opus_multistream_encoder_ctl(enc, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_FULLBAND)); + opus_multistream_encoder_ctl(enc, OPUS_SET_BANDWIDTH(OPUS_BANDWIDTH_FULLBAND)); + opus_multistream_encoder_ctl(enc, OPUS_SET_LSB_DEPTH(18)); + opus_multistream_encoder_ctl(enc, OPUS_SET_INBAND_FEC(1)); + opus_multistream_encoder_ctl(enc, OPUS_SET_PACKET_LOSS_PERC(90)); + opus_multistream_encoder_ctl(enc, OPUS_SET_BITRATE(280130)); + { + static const short pcm[160] = + { + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9526, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, 25600, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510 + }; + err = opus_multistream_encode(enc, pcm, 160, data, 2460); + assert(err > 0); + } + opus_multistream_encoder_ctl(enc, OPUS_SET_SIGNAL(OPUS_SIGNAL_MUSIC)); + opus_multistream_encoder_ctl(enc, OPUS_SET_VBR(0)); + opus_multistream_encoder_ctl(enc, OPUS_SET_VBR_CONSTRAINT(1)); + opus_multistream_encoder_ctl(enc, OPUS_SET_PREDICTION_DISABLED(1)); + opus_multistream_encoder_ctl(enc, OPUS_SET_PHASE_INVERSION_DISABLED(0)); + opus_multistream_encoder_ctl(enc, OPUS_SET_DTX(1)); + opus_multistream_encoder_ctl(enc, OPUS_SET_COMPLEXITY(10)); + opus_multistream_encoder_ctl(enc, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_FULLBAND)); + opus_multistream_encoder_ctl(enc, OPUS_SET_BANDWIDTH(OPUS_BANDWIDTH_FULLBAND)); + opus_multistream_encoder_ctl(enc, OPUS_SET_LSB_DEPTH(18)); + opus_multistream_encoder_ctl(enc, OPUS_SET_INBAND_FEC(1)); + opus_multistream_encoder_ctl(enc, OPUS_SET_PACKET_LOSS_PERC(90)); + opus_multistream_encoder_ctl(enc, OPUS_SET_BITRATE(280130)); + { + static const short pcm[160] = + { + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9494, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510 + }; + err = opus_multistream_encode(enc, pcm, 160, data, 2460); + assert(err > 0); + } + opus_multistream_encoder_ctl(enc, OPUS_SET_SIGNAL(OPUS_SIGNAL_MUSIC)); + opus_multistream_encoder_ctl(enc, OPUS_SET_VBR(0)); + opus_multistream_encoder_ctl(enc, OPUS_SET_VBR_CONSTRAINT(1)); + opus_multistream_encoder_ctl(enc, OPUS_SET_PREDICTION_DISABLED(1)); + opus_multistream_encoder_ctl(enc, OPUS_SET_PHASE_INVERSION_DISABLED(0)); + opus_multistream_encoder_ctl(enc, OPUS_SET_DTX(1)); + opus_multistream_encoder_ctl(enc, OPUS_SET_COMPLEXITY(10)); + opus_multistream_encoder_ctl(enc, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_FULLBAND)); + opus_multistream_encoder_ctl(enc, OPUS_SET_BANDWIDTH(OPUS_BANDWIDTH_FULLBAND)); + opus_multistream_encoder_ctl(enc, OPUS_SET_LSB_DEPTH(18)); + opus_multistream_encoder_ctl(enc, OPUS_SET_INBAND_FEC(1)); + opus_multistream_encoder_ctl(enc, OPUS_SET_PACKET_LOSS_PERC(90)); + opus_multistream_encoder_ctl(enc, OPUS_SET_BITRATE(280130)); + { + static const short pcm[160] = + { + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9479, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, -9510, + -9510, -9510, -9510, -9510, -9510, -9510, -9510 + }; + err = opus_multistream_encode(enc, pcm, 160, data, 2460); + assert(err > 0); + } + opus_multistream_encoder_ctl(enc, OPUS_SET_SIGNAL(OPUS_SIGNAL_MUSIC)); + opus_multistream_encoder_ctl(enc, OPUS_SET_VBR(0)); + opus_multistream_encoder_ctl(enc, OPUS_SET_VBR_CONSTRAINT(1)); + opus_multistream_encoder_ctl(enc, OPUS_SET_PREDICTION_DISABLED(1)); + opus_multistream_encoder_ctl(enc, OPUS_SET_PHASE_INVERSION_DISABLED(0)); + opus_multistream_encoder_ctl(enc, OPUS_SET_DTX(1)); + opus_multistream_encoder_ctl(enc, OPUS_SET_COMPLEXITY(10)); + opus_multistream_encoder_ctl(enc, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_FULLBAND)); + opus_multistream_encoder_ctl(enc, OPUS_SET_BANDWIDTH(OPUS_BANDWIDTH_FULLBAND)); + opus_multistream_encoder_ctl(enc, OPUS_SET_LSB_DEPTH(18)); + opus_multistream_encoder_ctl(enc, OPUS_SET_INBAND_FEC(1)); + opus_multistream_encoder_ctl(enc, OPUS_SET_PACKET_LOSS_PERC(90)); + opus_multistream_encoder_ctl(enc, OPUS_SET_BITRATE(280130)); + { + static const short pcm[160] = + { + -9510, -9510, 1799, 1799, 1799, 1799, 1799, 1799, 1799, + 1799, 1799, 1799, 1799, 1799, 1799, 1799, 1799, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + -256, 255, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 128, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 32, 0, 0, 0, 0, 0, 0, 0, + 4352, 4, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 148, 0, 0, 0, 0, + 5632 + }; + err = opus_multistream_encode(enc, pcm, 160, data, 2460); + assert(err > 0); + } + opus_multistream_encoder_ctl(enc, OPUS_SET_SIGNAL(OPUS_SIGNAL_VOICE)); + opus_multistream_encoder_ctl(enc, OPUS_SET_VBR(0)); + opus_multistream_encoder_ctl(enc, OPUS_SET_VBR_CONSTRAINT(1)); + opus_multistream_encoder_ctl(enc, OPUS_SET_PREDICTION_DISABLED(1)); + opus_multistream_encoder_ctl(enc, OPUS_SET_PHASE_INVERSION_DISABLED(1)); + opus_multistream_encoder_ctl(enc, OPUS_SET_DTX(1)); + opus_multistream_encoder_ctl(enc, OPUS_SET_COMPLEXITY(0)); + opus_multistream_encoder_ctl(enc, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_NARROWBAND)); + opus_multistream_encoder_ctl(enc, OPUS_SET_BANDWIDTH(OPUS_AUTO)); + opus_multistream_encoder_ctl(enc, OPUS_SET_LSB_DEPTH(12)); + opus_multistream_encoder_ctl(enc, OPUS_SET_INBAND_FEC(0)); + opus_multistream_encoder_ctl(enc, OPUS_SET_PACKET_LOSS_PERC(41)); + opus_multistream_encoder_ctl(enc, OPUS_SET_BITRATE(21425)); + { + static const short pcm[40] = + { + 10459, -6474, 10204, -6539, 11601, -6824, 13385, -7142, 13872, + -11553, 13670, -7725, 13463, -6887, 12482, -5580, 12600, -4964, + 12480, 3254, 11741, -4210, 9741, -3155, 7558, -5468, 5431, + -1073, 3641, -1304, 0, -1, 343, 26, 0, 0, + 0, 0, -256, 226 + }; + err = opus_multistream_encode(enc, pcm, 40, data, 2460); + assert(err > 0); + /* returns -3 */ + } + opus_multistream_encoder_destroy(enc); + return 0; +} + +static int mscbr_encode_fail10(void) +{ + OpusMSEncoder *enc; + int err; + unsigned char data[627300]; + static const unsigned char mapping[255] = + { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, + 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, + 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, + 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99,100,101, + 102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118, + 119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135, + 136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152, + 153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169, + 170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186, + 187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203, + 204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220, + 221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237, + 238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254 + }; + + enc = opus_multistream_encoder_create(8000, 255, 254, 1, mapping, + OPUS_APPLICATION_RESTRICTED_LOWDELAY, &err); + opus_multistream_encoder_ctl(enc, OPUS_SET_SIGNAL(OPUS_SIGNAL_VOICE)); + opus_multistream_encoder_ctl(enc, OPUS_SET_VBR(0)); + opus_multistream_encoder_ctl(enc, OPUS_SET_VBR_CONSTRAINT(0)); + opus_multistream_encoder_ctl(enc, OPUS_SET_PREDICTION_DISABLED(0)); + opus_multistream_encoder_ctl(enc, OPUS_SET_FORCE_CHANNELS(2)); + opus_multistream_encoder_ctl(enc, OPUS_SET_PHASE_INVERSION_DISABLED(1)); + opus_multistream_encoder_ctl(enc, OPUS_SET_DTX(1)); + opus_multistream_encoder_ctl(enc, OPUS_SET_COMPLEXITY(2)); + opus_multistream_encoder_ctl(enc, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_NARROWBAND)); + opus_multistream_encoder_ctl(enc, OPUS_SET_BANDWIDTH(OPUS_AUTO)); + opus_multistream_encoder_ctl(enc, OPUS_SET_LSB_DEPTH(14)); + opus_multistream_encoder_ctl(enc, OPUS_SET_INBAND_FEC(0)); + opus_multistream_encoder_ctl(enc, OPUS_SET_PACKET_LOSS_PERC(57)); + opus_multistream_encoder_ctl(enc, OPUS_SET_BITRATE(3642675)); + { + static const short pcm[20*255] = + { + 0 + }; + err = opus_multistream_encode(enc, pcm, 20, data, 627300); + assert(err > 0); + /* returns -1 */ + } + opus_multistream_encoder_destroy(enc); + return 0; +} + +static int mscbr_encode_fail(void) +{ + OpusMSEncoder *enc; + int err; + unsigned char data[472320]; + static const unsigned char mapping[192] = + { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, + 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, + 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, + 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99,100,101, + 102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118, + 119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135, + 136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152, + 153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169, + 170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186, + 187,188,189,190,191 + }; + + enc = opus_multistream_encoder_create(8000, 192, 189, 3, mapping, + OPUS_APPLICATION_RESTRICTED_LOWDELAY, &err); + opus_multistream_encoder_ctl(enc, OPUS_SET_SIGNAL(OPUS_SIGNAL_MUSIC)); + opus_multistream_encoder_ctl(enc, OPUS_SET_VBR(0)); + opus_multistream_encoder_ctl(enc, OPUS_SET_VBR_CONSTRAINT(0)); + opus_multistream_encoder_ctl(enc, OPUS_SET_PREDICTION_DISABLED(0)); + opus_multistream_encoder_ctl(enc, OPUS_SET_FORCE_CHANNELS(OPUS_AUTO)); + opus_multistream_encoder_ctl(enc, OPUS_SET_PHASE_INVERSION_DISABLED(0)); + opus_multistream_encoder_ctl(enc, OPUS_SET_DTX(0)); + opus_multistream_encoder_ctl(enc, OPUS_SET_COMPLEXITY(0)); + opus_multistream_encoder_ctl(enc, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_MEDIUMBAND)); + opus_multistream_encoder_ctl(enc, OPUS_SET_BANDWIDTH(OPUS_AUTO)); + opus_multistream_encoder_ctl(enc, OPUS_SET_LSB_DEPTH(8)); + opus_multistream_encoder_ctl(enc, OPUS_SET_INBAND_FEC(0)); + opus_multistream_encoder_ctl(enc, OPUS_SET_PACKET_LOSS_PERC(0)); + opus_multistream_encoder_ctl(enc, OPUS_SET_BITRATE(15360)); + { + static const short pcm[20*192] = + { + 0 + }; + err = opus_multistream_encode(enc, pcm, 20, data, 472320); + assert(err > 0); + /* returns -1 */ + } + opus_multistream_encoder_destroy(enc); + return 0; +} + +static int surround_analysis_uninit(void) +{ + OpusMSEncoder *enc; + int err; + unsigned char data[7380]; + int streams; + int coupled_streams; + unsigned char mapping[3]; + + enc = opus_multistream_surround_encoder_create(24000, 3, 1, &streams, + &coupled_streams, mapping, OPUS_APPLICATION_AUDIO, &err); + opus_multistream_encoder_ctl(enc, OPUS_SET_SIGNAL(OPUS_SIGNAL_VOICE)); + opus_multistream_encoder_ctl(enc, OPUS_SET_VBR(1)); + opus_multistream_encoder_ctl(enc, OPUS_SET_VBR_CONSTRAINT(1)); + opus_multistream_encoder_ctl(enc, OPUS_SET_PREDICTION_DISABLED(0)); + opus_multistream_encoder_ctl(enc, OPUS_SET_FORCE_CHANNELS(OPUS_AUTO)); + opus_multistream_encoder_ctl(enc, OPUS_SET_PHASE_INVERSION_DISABLED(0)); + opus_multistream_encoder_ctl(enc, OPUS_SET_DTX(0)); + opus_multistream_encoder_ctl(enc, OPUS_SET_COMPLEXITY(0)); + opus_multistream_encoder_ctl(enc, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_NARROWBAND)); + opus_multistream_encoder_ctl(enc, OPUS_SET_BANDWIDTH(OPUS_BANDWIDTH_NARROWBAND)); + opus_multistream_encoder_ctl(enc, OPUS_SET_LSB_DEPTH(8)); + opus_multistream_encoder_ctl(enc, OPUS_SET_INBAND_FEC(1)); + opus_multistream_encoder_ctl(enc, OPUS_SET_BITRATE(84315)); + { + static const short pcm[960*3] = + { + -6896, 4901, -6158, 4120, -5164, 3631, -4442, 3153, -4070, + 3349, -4577, 4474, -5541, 5058, -6701, 3881, -7933, 1863, + -8041, 697, -6738,-31464, 14330,-12523, 4096, -6130, 29178, + -250,-21252, 10467, 16907, -3359, -6644, 31965, 14607,-21544, + -32497, 24020, 12557,-26926,-18421, -1842, 24587, 19659, 4878, + 10954, 23060, 8907,-10215,-16179, 31772,-11825,-15590,-23089, + 17173,-25903,-17387, 11733, 4884, 10204,-16476,-14367, 516, + 20453,-16898, 20967,-23813, -20, 22011,-17167, 9459, 32499, + -25855, -523, -3883, -390, -4206, 634, -3767, 2325, -2751, + 3115, -2392, 2746, -2173, 2317, -1147, 2326, 23142, 11314, + -15350,-24529, 3026, 6146, 2150, 2476, 1105, -830, 1775, + -3425, 3674,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + 4293,-14023, 3879,-15553, 3158,-16161, 2629, 18433,-12535, + -6645,-20735,-32763,-13824,-20992, 25859, 13052, -8731, 2292, + -3860, 24049, 10225,-19220, 10478,-22294, 22773, 28137, 13816, + 30953,-25863,-24598, 16888,-14612,-28942, 20974,-27397,-18944, + -18690, 20991,-16638, 5632,-14330, 28911,-25594, 17408, 29958, + -517,-20984, -1800, 11281, 9977,-21221,-14854, 23840, -9477, + 3362,-12805,-22493, 32507, 156, 16384, -1163, 2301, -1874, + 4600, -1748, 6950, 16557, 8192, -7372, -1033, -3278, 2806, + 20275, 3317, -717, 9792, -767, 9099, -613, 8362, 5027, + 7774, 2597, 8549, 5278, 8743, 9343, 6940, 13038, 4826, + 14086, 2964, 13215, 1355, 11596, 455, 9850, -519, 10680, + -2287, 12551, -3736, 13639, -4291, 13790, -2722, 14544, -866, + 15050, -304, 22833, -1196, 13520, -2063, 13051, -2317, 13066, + -2737, 13773, -2664, 14105, -3447, 13854, 24589, 24672, -5280, + 10388, -4933, 7543, -4149, 3654, -1552, 1726, 661, 57, + 2922, -751, 3917, 8419, 3840, -5218, 3435, 5540, -1073, + 4153, -6656, 1649, -769, -7276,-13072, 6380, -7948, 20717, + 18425, 17392, 14335,-18190, -1842, 24587, 19659, 11790, 10954, + 23060, 8907,-10215,-16179, 31772,-11825,-15590,-23101, 17173, + -25903,-17387, 11733, 4884, 10192,-16627,-14367, 516, 20453, + -16898, 20967,-23813, -20, 22011,-17167, 9468, 32499,-25607, + -523, -3883, -390, -4206, 634, -3767, 2325, -2751, 3115, + -2392, 2746, -2161, 2317, -1147, 2326, 23142, 11314,-15350, + -29137, 3026,-15056, -491,-15170, -386,-16015, -641,-16505, + -930,-16206, -717,-16175, -2839,-16374, -4558,-16237, -5207, + -15903, -6421, 6373, -1403, 5431, -1073, 3641, -1304, -4495, + -769, -7276, 2856, -7870, 3314, -8730, 3964,-10183, 4011, + -11135, 3421,-11727, 2966,-12360, 2818,-13472, 3660,-13805, + 5162,-13478, 6434,-12840, 7335,-12420, 6865,-12349, 5541, + -11965, 5530,-10820, 5132, -9197, 3367, -7745, 1223, -6910, + -433, -6211, -1711, -4958, -1025, -3755, -836, -3292, -1666, + -2661,-10755, 31472,-27906, 31471, 18690, 5617, 16649, 11253, + -22516,-17674,-31990, 3575,-31479, 5883, 26121, 12890, -6612, + 12228,-11634, 523, 26136,-21496, 20745,-15868, -4100,-24826, + 23282, 22798, 491, -1774, 15075,-27373,-13094, 6417,-29487, + 14608, 10185, 16143, 22211, -8436, 4288, -8694, 2375, 3023, + 486, 1455, 128, 202, 942, -923, 2068, -1233, -717, + -1042, -2167, 32255, -4632, 310, -4458, -3639, -5258, 2106, + -6857, 2681, -7497, 2765, -6601, 1945, -5219, 19154, -4877, + 619, -5719, -1928, -6208, -121, 593, 188, 1558, -4152, + 1648, 156, 1604, -3664, -6862, -2851, -5112, -3600, -3747, + -5081, -4428, -5592, 20974,-27397,-18944,-18690, 20991,-17406, + 5632,-14330, 28911, 15934, 15934, 15934, 15934, 15934, 15934, + 15934, 15934, 15934, 15934, 15934, 15934,-25594, 17408, 29958, + -7173,-16888, 9098, -613, 8362, 675, 7774, 2597, 8549, + 5278, 8743, 9375, 6940, 13038, 4826, 14598, 7721,-24308, + -29905,-19703,-17106,-16124, -3287,-26118,-19709,-10769, 24353, + 28648, 6946, -1363, 12485, -1187, 26074,-25055, 10004,-24798, + 7204, -4581, -9678, 1554, 10553, 3102, 12193, 2443, 11955, + 1213, 10689, -1293, 921, -4173, 10709, -6049, 8815, -7128, + 8147, -8308, 6847, -2977, 4920,-11447,-22426,-11794, 3514, + -10220, 3430, -7993, 1926, -7072, 327, -7569, -608, -7605, + 3695, -6271, -1579, -4877, -1419, -3103, -2197, 128, -3904, + 3760, -5401, 4906, -6051, 4250, -6272, 3492, -6343, 3197, + -6397, 4041, -6341, 6255, -6381, 7905, 16504, 0, -6144, + 8062, -5606, 8622, -5555, -9, -1, 7423, 0, 1, + 238, 5148, 1309, 4700, 2218, 4403, 2573, 3568, 28303, + 1758, 3454, -1247, 3434, -4912, 2862, -7844, 1718,-10095, + 369,-12631, 128, -3904, 3632, -5401, 4906, -6051, 4250, + -6272, 3492, -6343, 3197, -6397, 4041, -6341, 6255, -6381, + 7905, 16504, 0, -6144, 8062, -5606, 8622, -5555, 8439, + -3382, 7398, -1170, 6132, 238, 5148, 1309, 4700, 2218, + 4403, 2573, 3568, 2703, 1758, 3454, -1247, 3434, -4912, + 2862, -7844, 1718,-10095, 369,-12631, -259,-14632, 234, + -15056, -521,-15170, -386,-16015, -641,-16505, -930,-16206, + -1209,-16146, -2839,-16374, -4558,-16218, -5207,-15903, -6421, + -15615, -6925,-14871, -6149,-13759, -5233,-12844, 18313, -4357, + -5696, 2804, 12992,-22802, -6720, -9770, -7088, -8998, 14330, + -12523, 14843, -6130, 29178, -250,-27396, 10467, 16907, -3359, + -6644, 31965, 14607,-21544,-32497, 24020, 12557,-26926, -173, + -129, -6401, -130,-25089, -3841, -4916, -3048, 224, -237, + -3969, -189, -3529, -535, -3464,-14863,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14395,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907, 0, 32512,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907, 9925, -718, 9753, -767, + 9099, -613, 8362, 675, 7774, 2597, 8549, 5278, 8743, + 9375, 6940, 13038, 4826, 14598, 7721,-24308,-29905,-19703, + -17106,-16124, -3287,-26118,-19709, 0, 24353, 28648, 10274, + -11292,-29665,-16417, 24346, 14553, 18707, 26323, -4596,-17711, + 5133, 26328, 13,-31168, 24583, 18404,-28927,-24350, 19453, + 28642, 1019,-10777, -3079, 30188, -7686, 27635,-32521,-16384, + 12528, -6386, 10986, 23827,-25880,-32752,-23321, 14605, 32231, + 780,-13849, 15119, 28647, 4888, -7705, 30750, 64, 0, + 32488, 6687,-20758, 19745, -2070,-13792, -6414, 28188, -2821, + -4585, 7168, 7444, 23557,-21998, 13064, 3345, -4086,-28915, + -8694, 32262, 8461, 27387,-12275, 12012, 23563,-18719,-28410, + 29144,-22271, -562, -9986, -5434, 12288, 5573,-16642, 32448, + 29182, 32705,-30723, 24255,-19716, 18368, -4357, -5696, 2804, + 12992,-22802,-22080, -7701, -5183, 486, -3133, -5660, -1083, + 16871,-28726,-11029,-30259, -1209,-16146, -2839,-16374, -4558, + -16218,-10523, 20697, -9500, -1316, 5431, -1073, 3641, -1304, + 1649, -769, -7276, 2856, -7870, 3314, -8730, 3964,-10183, + 4011,-11135, 3421,-11727, 21398, 32767, -1, 32486, -1, + 6301,-13071, 6380, -7948, -1, 32767, 240, 14081, -5646, + 30973, -3598,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907, 32767,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907, 8901, 9375, 6940, 13038, 4826, 14598, 7721,-24308, + -29905,-19703,-17106,-16124, -3287,-26118,-19709,-10769, 24361, + 28648, 10274,-11292,-29665,-16417, 24346, 14580, 18707, 26323, + -4440,-17711, 5133, 26328,-14579,-31008, 24583, 18404, 28417, + -24350, 19453, 28642,-32513,-10777, -3079, 30188, -7686, 27635, + -32521,-16384,-20240, -6386, 10986, 23827,-25880,-32752,-23321, + 14605, 32231, 780,-13849, 15119, 28647, 4888, -7705,-15074, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907, 8192,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14897,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -15931,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907, 26121, 12890, 2604, + 12228,-11634, 12299, 5573,-16642, 32452, 29182, 32705,-30723, + 24255,-19716, 13248,-11779, -5696, 2804, 12992,-27666,-22080, + -7701, -5183, -6682,-31464, 14330,-12523, 14843, -6130, 29178, + -18,-27396, 10467, 16907, -3359, -6644, 31965, 14607,-21544, + -32497, 24020, 12557,-26926,-18421, 706, 24587, 19659, 4878, + 10954, 23060, 8907,-10215,-22579, 31772,-11825,-15590,-23089, + 17173,-25903,-17387, 3285, 4884, 10204,-16627,-14367, 516, + 20453,-16898, 20967,-23815, -20, 22011,-17167, 9468, 32499, + -25607, -523, -3883, -390, -4206, 634, -3767, 2325, -2751, + 3115, -2392, 2746, -2173, 2317, -1147, 2326, 23142, 11314, + -15130,-29137, 3026, 6146, 2150, 2476, 1105, -830, 1775, + -3425, 3674, -5287, 4609, -7175, 4922, -9579, 4556,-12007, + 4236,-14023, 3879,-15553, 3158,-16161, 2576, 18398,-12535, + -6645,-20735,-32763,-13824,-20992, 25859, 5372, 12040, 13307, + -4355,-30213, -9, -6019, 14061,-31487,-13842, 30449, 15083, + 14088, 31205,-18678,-12830, 14090,-26138,-25337,-11541, -3254, + 27628,-22270, 30953,-16136,-30745, 20991,-17406, 5632,-14330, + 28911,-25594, 17408,-20474, 13041, -8731, 2292, -3860, 24049, + 10225,-19220, 10478, -4374, -1199, 148, -330, -74, 593, + 188, 1558, -4152, 15984, 15934, 15934, 15934, 15934, 15934, + 15934, 15934, 15934, 15934, 15934, 15934, 1598, 156, 1604, + -1163, 2278,-30018,-25821,-21763,-23776, 24066, 9502, 25866, + -25055, 10004,-24798, 7204, -4581, -9678, 1554, 10553, 3102, + 12193, 2443, 11955, 1213, 10689, -1293, 921, -4173, 8661, + -6049, 8815,-21221,-14854, 23840, -9477, 8549, 5278, 8743, + 9375, 6940, 13038, 4826, 14598, 7721,-24308,-29905,-19703, + -17106,-16124, -3287,-26118,-19709,-10769, 24361, 28648, 10274, + -11292,-29665,-16417, 24346, 14580, 18707, 26323, -4410,-17711, + 5133, 26328,-14579,-31008, 24583, 18404, 28417,-24350, 19453, + 28642,-32513,-10777, -3079, 30188, -7686, 27635,-32521,-16384, + -20240, -6386, 10986, 23827,-25880,-32752,-23321, 14605, 32231, + 780,-13849, 15119, 28647, 4888, -7705, 30750, 64, 0, + 32488, 6687,-20758, 19745, -2070, -1, -1, 28, 256, + -4608, 7168, 7444, 23557,-21998, 13064, 3345, -4086,-28915, + -8594, 32262, 8461, 27387,-12275, 12012, 23563,-18719,-28410, + 29144,-22271,-32562,-16384, 12528, -6386, 10986, 23827,-25880, + -32752,-23321, 14605, 32231, 780,-13849, 15119, 28647, 4888, + -7705, 30750, 64, 0, 32488, 6687,-20758, 19745, -2070, + -13792, -6414, 28188, -2821, -4585, 7168, 7444, 23557,-21998, + 13064, 3345, -4086,-28915, -8694, 32262, 8461, 27387,-12275, + 12012, 23563,-18719,-28410, 29144,-22271, -562, -9986, -5434, + 12288, -2107,-16643, 32452, 29182, 32705,-30723, 24255,-19716, + 18368, -4357, -5696, 2804, 12992,-22802,-22080, -7701, -5183, + 486, -3133, -5660, -1083, 16871,-28726,-11029,-30259, -1209, + -16146, -2839,-16374, -4558,-16218,-10523, 20697, -9500, -1316, + 5431, -1073, 3641, -1304, 1649, -769, -7276, 2856, -7870, + 3314, -8730, 3964,-10183, 4011,-11135, 3421,-11727, 21398, + 32767, -1, 32486, -1, -99,-13072, 6380, -7948, 4864, + 32767, 17392, 14335, -5646, 30973, -3598,-10299,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14905,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-19771,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-16443,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-15931,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907, -1,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907, 7877, 7710, 7710, 7710, 7710, 7710, 7710, + 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, + 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, + 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, + 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, + 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, + 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, + 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, + 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, + 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, + 7710, 7710, 7710, 7710, 7710, -994, -7276, 2856, -7870, + 3314, -8730, 3964,-10183, 4011,-11135, 3421,-11727, 21398, + 32767, -1, 32486, -1, -99,-13072, 6380, -7948, 4864, + 32767, 17392, 14335, -5646, 30973, -3598,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14905,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907, 197, 0,-14977,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907, 12838, 6653, 294, + -29699,-25821,-21763,-23776, 24066, 9502, 25866,-25055, 10004, + -24798, 7204, -4581, -9678, 1554, 10553, 3102, 12193, 2443, + 11955, 1213, 10689, -1293, 921, 179, 8448, -6049, 8815, + -7128, 8147, -8308, 6847, -9889, 4920,-11447, 3174,-11794, + 3514,-10220, 3430, 16384, 1926, -7072, 327, -7537, -608, + -7605, -1169, -6397, -1579, -4877, -1419, -3103, -2197, 128, + -3904, 3632, -5401, 4906, -6051, 4250, -6272, 3492, -6343, + 3197, -6397, 4041, -6341, 6255, -6381, 7905, 16504, 0, + -6144, 8062, -5606, 8622, -5555, 8439, -3382, 7398, -1170, + 6132, 238, 5148, 1309, 4700, 2218, 4403, 2573, 3568, + 2703, 1758, 3454, -1247, 3434, -4912, 2862, -7844, 1718, + -10095, 369,-12631, -259,-14632, 234,-15056, -491,-16194, + -386,-16015, -641,-16505, -930,-16206, -1209,-16146, -2839, + -16374, -4558,-16218, -5207,-15903, -6421,-15615, -6925,-14871, + -6149,-13759, -5233,-12844, 18313, -4357, -5696, 2804, 12992, + -22802, -6720, -9770, -7088, -8998, 14330,-12523, 14843, -6130, + 29178, -250,-27396, 10467, 16907, -3359, -6644, 31965, 14607, + -21544,-32497, 24020, 12557,-26926, -173, -129, -6401, -130, + -25089, -3816, -4916, -3048, -32, -1, -3969, 256, -3529, + -535, -3464,-14863,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -1209,-16146, -2839,-16374, -4558,-16218,-10523, 20697, -9500, + -1316, 5431, -1073, 3641, -1304, 1649, -769, -7276, 2856, + -7870, 3314, -8730, 3964,-10183, 4011,-11135, 3421,-11727, + 21398, 32767, -1, 32486, -1, 6301,-13071, 6380, -7948, + -1, 32767, 240, 14081, -5646, 30973, -3598,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + 32767,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907, 8901, 9375, 6940, + 13038, 4826, 14598, 7721,-24308,-29905,-19703,-17106,-16124, + -3287,-26118,-19709,-10769, 24361, 28648, 10274,-11292,-29665, + -16417, 24346, 14580, 18707, 26323, -4440,-17711, 5133, 26328, + -14579,-31008, 24583, 18404, 28417,-24350, 19453, 28642,-32513, + -10777, -3079, 30188, -7686, 27635,-32521,-16384,-20240, -6386, + 10986, 23827,-25880,-32752,-23321, 14605, 32231, 780,-13849, + 15119, 28647, 4888, -7705,-15074,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, 8192, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14897, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-15931,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907, 26121, 12890, 2604, 12228,-11634, 12299, 5573, + -16642, 32452, 29182, 32705,-30723, 24255,-19716, 13248,-11779, + -5696, 2804, 12992,-27666,-22080, -7701, -5183, -6682,-31464, + 14330,-12523, 14843, -6130, 29178, -18,-27396, 10467, 16907, + -3359, -6644, 31965, 14607,-21544,-32497, 24020, 12557,-26926, + -18421, 706, 24587, 19659, 4878, 10954, 23060, 8907,-10215, + -22579, 31772,-11825,-15590,-23089, 17173,-25903,-17387, 3285, + 4884, 10204,-16627,-14367, 516, 20453,-16898, 20967,-23815, + -20, 22011,-17167, 9468, 32499,-25607, -523, -3883, -390, + -4206, 634, -3767, 2325, -2751, 3115, -2392, 2746, -2173, + 2317, -1147, 2326, 23142, 11314,-15130,-29137, 3026, 6146, + 2150, 2476, 1105, -830, 1775, -3425, 3674, -5287, 4609, + -7175, 4922, -9579, 4556,-12007, 4236,-14023, 3879,-15553, + 3158,-16161, 2576, 18398,-12535, -6645,-20735,-32763,-13824, + -20992, 25859, 5372, 12040, 13307, -4355,-30213, -9, -6019 + }; + err = opus_multistream_encode(enc, pcm, 960, data, 7380); + assert(err > 0); + } + opus_multistream_encoder_ctl(enc, OPUS_SET_SIGNAL(OPUS_SIGNAL_MUSIC)); + opus_multistream_encoder_ctl(enc, OPUS_SET_VBR(1)); + opus_multistream_encoder_ctl(enc, OPUS_SET_VBR_CONSTRAINT(0)); + opus_multistream_encoder_ctl(enc, OPUS_SET_PREDICTION_DISABLED(1)); + opus_multistream_encoder_ctl(enc, OPUS_SET_FORCE_CHANNELS(OPUS_AUTO)); + opus_multistream_encoder_ctl(enc, OPUS_SET_PHASE_INVERSION_DISABLED(1)); + opus_multistream_encoder_ctl(enc, OPUS_SET_DTX(1)); + opus_multistream_encoder_ctl(enc, OPUS_SET_COMPLEXITY(6)); + opus_multistream_encoder_ctl(enc, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_NARROWBAND)); + opus_multistream_encoder_ctl(enc, OPUS_SET_BANDWIDTH(OPUS_AUTO)); + opus_multistream_encoder_ctl(enc, OPUS_SET_LSB_DEPTH(9)); + opus_multistream_encoder_ctl(enc, OPUS_SET_INBAND_FEC(1)); + opus_multistream_encoder_ctl(enc, OPUS_SET_PACKET_LOSS_PERC(5)); + opus_multistream_encoder_ctl(enc, OPUS_SET_BITRATE(775410)); + { + static const short pcm[1440*3] = + { + 30449, 15083, 14088, 31205,-18678,-12830, 14090,-26138,-25337, + -11541, -3254, 27628,-22270, 30953,-16136,-30745, 20991,-17406, + 5632,-14330, 28911,-25594, 17408,-20474, 13041, -8731, 2292, + -3860, 24049, 10225,-19220, 10478, -4374, -1199, 148, -330, + -74, 593, 188, 1558, -4152, 15984, 15934, 15934, 15934, + 15934, 15934, 15934, 15934, 15934, 15934, 15934, 15934, 1598, + 156, 1604, -1163, 2278,-30018,-25821,-21763,-23776, 24066, + 9502, 25866,-25055, 10004,-24798, 7204, -4581, -9678, 1554, + 10553, 3102, 12193, 2443, 11955, 1213, 10689, -1293, 921, + -4173, 8661, -6049, 8815,-21221,-14854, 23840, -9477, 8549, + 5278, 8743, 9375, 6940, 13038, 4826, 14598, 7721,-24308, + -29905,-19703,-17106,-16124, -3287,-26118,-19709,-10769, 24361, + 28648, 10274,-11292,-29665,-16417, 24346, 14580, 18707, 26323, + -4410,-17711, 5133, 26328,-14579,-31008, 24583, 18404, 28417, + -24350, 19453, 28642,-32513,-10777, -3079, 30188, -7686, 27635, + -32521,-16384,-20240, -6386, 10986, 23827,-25880,-32752,-23321, + 14605, 32231, 780,-13849, 15119, 28647, 4888, -7705, 30750, + 64, 0, 32488, 6687,-20758, 19745, -2070, -1, -1, + 28, 256, -4608, 7168, 7444, 23557,-21998, 13064, 3345, + -4086,-28915, -8594, 32262, 8461, 27387,-12275, 12012, 23563, + -18719,-28410, 29144,-22271,-32562,-16384, 12528, -6386, 10986, + 23827,-25880,-32752,-23321, 14605, 32231, 780,-13849, 15119, + 28647, 4888, -7705, 30750, 64, 0, 32488, 6687,-20758, + 19745, -2070,-13792, -6414, 28188, -2821, -4585, 7168, 7444, + 23557,-21998, 13064, 3345, -4086,-28915, -8694, 32262, 8461, + -14853,-14907,-14907,-14907,-14907, 32767,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14891,-14907,-14907,-14907, + -14907,-14907, 8901, 9375, 6940, 13038, 4826, 14598, 7721, + -24308,-29905,-19703,-17106,-16124, -3287,-26118,-19709,-10769, + 24361, 28648, 10274,-11292,-29665,-16417, 24346, 14580, 18707, + 26323, -4440,-17711, 5133, 26328,-14579,-31008, 24583, 18404, + 28417,-24350, 19453, 28642,-32513,-10777, -3079, 30188, -7686, + 27635,-32521,-16384,-20240, -6386, 10986, 23827,-25880,-32752, + -23321, 14605, 32231, 780,-13849, 15119, 28647, 4888, -7705, + -15074,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907, 8192,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14897,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-15931,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907, 26121, 12890, + 2604, 12228,-11634, 12299, 5573,-16642, 32452, 29182, 7710, + 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, + 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, + 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, + 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, + 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, + 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, + 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, + 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, + 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, + 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, + 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, + 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, + 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, + 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, + 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, + 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, + 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, + 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, + 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, + 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, + 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, + 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, + 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, + 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, 7710, + 7710,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-10811,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14917,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14938,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907,-14907, + -14907,-14907,-14907,-14907, -571, -9986, -58, 12542,-18491, + 32507, 12838, 6653, 294, -1, 0,-19968, 18368, -4357, + -5696, 2804, 12998,-22802,-22080, -7701, -5183, 486, -3133, + -5660, -1083, 13799,-28726,-11029, 205,-14848, 32464, -1, + -129,-13072, 6380, -7948, 20717, 18425, 17392, 14335, -5646, + 30973, -3598, 7188, -3867, 3055, -4247, 5597, -4011,-26427, + -11,-30418, 7922, 2614, 237, -5839,-27413,-17624,-29716, + -13539, 239, 20991, 18164, -4082,-16647,-27386, 19458, 20224, + 4619, 19728, -7409,-18186,-25073, 27627,-23539, -7945,-31464, + 14330,-12523,-22021, -7701, -5183, 486, -3133, -5660, -1083, + 13799,-28726,-11029, 205,-14848, 32464, -1, -129,-13072, + 6380, -7948, 20717, 18425, 17392, 14093, -5646, 30973, -3598, + 7188, -3867, 3055, 3689, -5401, 4906, -6051, 4250, -6272, + 3492, -6343, 3197, -6397, 4041, -6341, 6255, -6381, 239, + 20991, 18164, -4082,-16647,-27386, 19458, 20224, 4619, 19728, + -7409,-18186,-25073, 27627,-23539, -7945,-31464, 14330,-12523, + 14843, -6130, 30202, -250,-28420, 10467, 16907, -3359, -6644, + 31965, 3343,-11727, 2966,-12616, 3064,-13472, 6732,-12349, + 5541,-11965, 5530,-10820, -1912, -3637, 32285, -4607, 310, + -32768, 0, -5258, 2106, -6857, 2681, -5449, -3606, -6717, + -5482, -3606, -1853, 4082, -7631, -9808, -1742, -2851, -5112, + 64, -868,-13546,-13365,-13365,-13365,-13365,-13365,-13365, + -13365,-13365,-13365,-13365,-13365,-13365,-13365,-13365,-13365, + -13365,-13365,-13365,-13365,-13365,-13365,-13365,-13365,-13365, + -13365,-13365,-13365,-13365,-13365,-13365,-13365,-13365,-13365, + -13365,-13365,-13365,-13365,-13365,-13365,-13365, 7883, -2316, + 9086, -3944, 10500, 4285, 10459, -6474, 10204, -6539, 11601, + -6824, 13385, -7142, 13872, -7457, 13670, -7725, 13463, -6887, + 12482, -5580, 12600, -4964, 12480, 3254, 11741, -4210,-24819, + 23282, 22798, 491, -1774, -1073, 3641, -1304, 28928, -250, + -27396, 6657, -8961, 22524, 19987, 10231, 1791, 8947,-32763, + -26385,-31227, -792,-30461, 8926, 4866, 27863, 27756, 27756, + 27756, 27756, 27756, 27756, 27756, 27756, 5630,-11070,-16136, + 20671,-11530, 27328, 8179, 5059,-31503,-24379,-19472, 17863, + -29202, 22986, -23, 8909, 8422, 10450 + }; + err = opus_multistream_encode(enc, pcm, 1440, data, 7380); + /* reads uninitialized data at src/opus_multistream_encoder.c:293 */ + assert(err > 0); + } + opus_multistream_encoder_destroy(enc); + return 0; +} + +static int ec_enc_shrink_assert(void) +{ + OpusEncoder *enc; + int err; + int data_len; + unsigned char data[2000]; + static const short pcm1[960] = { 5140 }; + static const short pcm2[2880] = + { + -256,-12033, 0, -2817, 6912, 0, -5359, 5200, 3061, + 0, -2903, 5652, -1281,-24656,-14433,-24678, 32,-29793, + 2870, 0, 4096, 5120, 5140, -234,-20230,-24673,-24633, + -24673,-24705, 0,-32768,-25444,-25444, 0,-25444,-25444, + 156,-20480, -7948, -5920, -7968, -7968, 224, 0, 20480, + 11, 20496, 13, 20496, 11,-20480, 2292,-20240, 244, + 20480, 11, 20496, 11,-20480, 244,-20240, 7156, 20456, + -246,-20243, 244, 128, 244, 20480, 11, 20496, 11, + -20480, 244,-20256, 244, 20480, 256, 0, -246, 16609, + -176, 0, 29872, -4096, -2888, 516, 2896, 4096, 2896, + -20480, -3852, -2896, -1025,-31056,-14433, 244, 1792, -256, + -12033, 0, -2817, 0, 0, -5359, 5200, 3061, 16, + -2903, 5652, -1281,-24656,-14433,-24678, 32,-29793, 2870, + 0, 4096, 5120, 5140, -234,-20230,-24673,-24633,-24673, + -24705, 0,-32768,-25444,-25444, 0,-25444,-25444, 156, + -20480, -7973, -5920, -7968, -7968, 224, 0, 20480, 11, + 20496, 11, 20496, 11,-20480, 2292,-20213, 244, 20480, + 11, 20496, 11,-24698, -2873, 0, 7, -1, 208, + -256, 244, 0, 4352, 20715, -2796, 11,-22272, 5364, + -234,-20230,-24673,-25913, 8351,-24832, 13963, 11, 0, + 16, 5140, 5652, -1281,-24656,-14433,-24673, 32671, 159, + 0,-25472,-25444, 156,-25600,-25444,-25444, 0, -2896, + -7968, -7960, -7968, -7968, 0, 0, 2896, 4096, 2896, + 4096, 2896, 0, -2896, -4088, -2896, 0, 2896, 0, + -2896, -4096, -2896, 11, 2640, -4609, -2896,-32768, -3072, + 0, 2896, 4096, 2896, 0, -2896, -4096, -2896, 0, + 80, 1, 2816, 0, 20656, 255,-20480, 116,-18192 + }; + static const short pcm3[2880] = { 0 }; + + enc = opus_encoder_create(48000, 1, OPUS_APPLICATION_AUDIO, &err); + opus_encoder_ctl(enc, OPUS_SET_COMPLEXITY(10)); + opus_encoder_ctl(enc, OPUS_SET_PACKET_LOSS_PERC(6)); + opus_encoder_ctl(enc, OPUS_SET_BITRATE(6000)); + data_len = opus_encode(enc, pcm1, 960, data, 2000); + assert(data_len > 0); + + opus_encoder_ctl(enc, OPUS_SET_SIGNAL(OPUS_SIGNAL_VOICE)); + opus_encoder_ctl(enc, OPUS_SET_PREDICTION_DISABLED(1)); + opus_encoder_ctl(enc, OPUS_SET_BANDWIDTH(OPUS_BANDWIDTH_SUPERWIDEBAND)); + opus_encoder_ctl(enc, OPUS_SET_INBAND_FEC(1)); + opus_encoder_ctl(enc, OPUS_SET_BITRATE(15600)); + data_len = opus_encode(enc, pcm2, 2880, data, 122); + assert(data_len > 0); + + opus_encoder_ctl(enc, OPUS_SET_SIGNAL(OPUS_SIGNAL_MUSIC)); + opus_encoder_ctl(enc, OPUS_SET_BITRATE(27000)); + data_len = opus_encode(enc, pcm3, 2880, data, 122); /* assertion failure */ + assert(data_len > 0); + + opus_encoder_destroy(enc); + return 0; +} + +static int ec_enc_shrink_assert2(void) +{ + OpusEncoder *enc; + int err; + int data_len; + unsigned char data[2000]; + + enc = opus_encoder_create(48000, 1, OPUS_APPLICATION_AUDIO, &err); + opus_encoder_ctl(enc, OPUS_SET_COMPLEXITY(6)); + opus_encoder_ctl(enc, OPUS_SET_SIGNAL(OPUS_SIGNAL_VOICE)); + opus_encoder_ctl(enc, OPUS_SET_BANDWIDTH(OPUS_BANDWIDTH_FULLBAND)); + opus_encoder_ctl(enc, OPUS_SET_PACKET_LOSS_PERC(26)); + opus_encoder_ctl(enc, OPUS_SET_BITRATE(27000)); + { + static const short pcm[960] = { 0 }; + data_len = opus_encode(enc, pcm, 960, data, 2000); + assert(data_len > 0); + } + opus_encoder_ctl(enc, OPUS_SET_SIGNAL(OPUS_SIGNAL_MUSIC)); + { + static const short pcm[480] = + { + 32767, 32767, 0, 0, 32767, 32767, 0, 0, 32767, 32767, + -32768, -32768, 0, 0, -32768, -32768, 0, 0, -32768, -32768 + }; + data_len = opus_encode(enc, pcm, 480, data, 19); + assert(data_len > 0); + } + opus_encoder_destroy(enc); + return 0; +} + +static int silk_gain_assert(void) +{ + OpusEncoder *enc; + int err; + int data_len; + unsigned char data[1000]; + static const short pcm1[160] = { 0 }; + static const short pcm2[960] = + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 32767, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 32767 + }; + + enc = opus_encoder_create(8000, 1, OPUS_APPLICATION_AUDIO, &err); + opus_encoder_ctl(enc, OPUS_SET_COMPLEXITY(3)); + opus_encoder_ctl(enc, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_NARROWBAND)); + opus_encoder_ctl(enc, OPUS_SET_BITRATE(6000)); + data_len = opus_encode(enc, pcm1, 160, data, 1000); + assert(data_len > 0); + + opus_encoder_ctl(enc, OPUS_SET_VBR(0)); + opus_encoder_ctl(enc, OPUS_SET_COMPLEXITY(0)); + opus_encoder_ctl(enc, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_MEDIUMBAND)); + opus_encoder_ctl(enc, OPUS_SET_BITRATE(2867)); + data_len = opus_encode(enc, pcm2, 960, data, 1000); + assert(data_len > 0); + + opus_encoder_destroy(enc); + return 0; +} + +void regression_test(void) +{ + fprintf(stderr, "Running simple tests for bugs that have been fixed previously\n"); + celt_ec_internal_error(); + mscbr_encode_fail10(); + mscbr_encode_fail(); + surround_analysis_uninit(); + ec_enc_shrink_assert(); + ec_enc_shrink_assert2(); + silk_gain_assert(); +} diff --git a/extern/opus/tests/run_vectors.sh b/extern/opus/tests/run_vectors.sh new file mode 100755 index 0000000..dcb76cf --- /dev/null +++ b/extern/opus/tests/run_vectors.sh @@ -0,0 +1,143 @@ +#!/bin/sh + +# Copyright (c) 2011-2012 Jean-Marc Valin +# +# This file is extracted from RFC6716. Please see that RFC for additional +# information. +# +# 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 OWNER +# 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. + +rm -f logs_mono.txt logs_mono2.txt +rm -f logs_stereo.txt logs_stereo2.txt + +if [ "$#" -ne "3" ]; then + echo "usage: run_vectors.sh " + exit 1 +fi + +CMD_PATH=$1 +VECTOR_PATH=$2 +RATE=$3 + +: ${OPUS_DEMO:=$CMD_PATH/opus_demo} +: ${OPUS_COMPARE:=$CMD_PATH/opus_compare} + +if [ -d "$VECTOR_PATH" ]; then + echo "Test vectors found in $VECTOR_PATH" +else + echo "No test vectors found" + #Don't make the test fail here because the test vectors + #will be distributed separately + exit 0 +fi + +if [ ! -x "$OPUS_COMPARE" ]; then + echo "ERROR: Compare program not found: $OPUS_COMPARE" + exit 1 +fi + +if [ -x "$OPUS_DEMO" ]; then + echo "Decoding with $OPUS_DEMO" +else + echo "ERROR: Decoder not found: $OPUS_DEMO" + exit 1 +fi + +echo "==============" +echo "Testing mono" +echo "==============" +echo + +for file in 01 02 03 04 05 06 07 08 09 10 11 12 +do + if [ -e "$VECTOR_PATH/testvector$file.bit" ]; then + echo "Testing testvector$file" + else + echo "Bitstream file not found: testvector$file.bit" + fi + if "$OPUS_DEMO" -d "$RATE" 1 "$VECTOR_PATH/testvector$file.bit" tmp.out >> logs_mono.txt 2>&1; then + echo "successfully decoded" + else + echo "ERROR: decoding failed" + exit 1 + fi + "$OPUS_COMPARE" -r "$RATE" "$VECTOR_PATH/testvector${file}.dec" tmp.out >> logs_mono.txt 2>&1 + float_ret=$? + "$OPUS_COMPARE" -r "$RATE" "$VECTOR_PATH/testvector${file}m.dec" tmp.out >> logs_mono2.txt 2>&1 + float_ret2=$? + if [ "$float_ret" -eq "0" ] || [ "$float_ret2" -eq "0" ]; then + echo "output matches reference" + else + echo "ERROR: output does not match reference" + exit 1 + fi + echo +done + +echo "==============" +echo Testing stereo +echo "==============" +echo + +for file in 01 02 03 04 05 06 07 08 09 10 11 12 +do + if [ -e "$VECTOR_PATH/testvector$file.bit" ]; then + echo "Testing testvector$file" + else + echo "Bitstream file not found: testvector$file" + fi + if "$OPUS_DEMO" -d "$RATE" 2 "$VECTOR_PATH/testvector$file.bit" tmp.out >> logs_stereo.txt 2>&1; then + echo "successfully decoded" + else + echo "ERROR: decoding failed" + exit 1 + fi + "$OPUS_COMPARE" -s -r "$RATE" "$VECTOR_PATH/testvector${file}.dec" tmp.out >> logs_stereo.txt 2>&1 + float_ret=$? + "$OPUS_COMPARE" -s -r "$RATE" "$VECTOR_PATH/testvector${file}m.dec" tmp.out >> logs_stereo2.txt 2>&1 + float_ret2=$? + if [ "$float_ret" -eq "0" ] || [ "$float_ret2" -eq "0" ]; then + echo "output matches reference" + else + echo "ERROR: output does not match reference" + exit 1 + fi + echo +done + + + +echo "All tests have passed successfully" +mono1=`grep quality logs_mono.txt | awk '{sum+=$4}END{if (NR == 12) sum /= 12; else sum = 0; print sum}'` +mono2=`grep quality logs_mono2.txt | awk '{sum+=$4}END{if (NR == 12) sum /= 12; else sum = 0; print sum}'` +echo $mono1 $mono2 | awk '{if ($2 > $1) $1 = $2; print "Average mono quality is", $1, "%"}' + +stereo1=`grep quality logs_stereo.txt | awk '{sum+=$4}END{if (NR == 12) sum /= 12; else sum = 0; print sum}'` +stereo2=`grep quality logs_stereo2.txt | awk '{sum+=$4}END{if (NR == 12) sum /= 12; else sum = 0; print sum}'` +echo $stereo1 $stereo2 | awk '{if ($2 > $1) $1 = $2; print "Average stereo quality is", $1, "%"}' diff --git a/extern/opus/tests/test_opus_api.c b/extern/opus/tests/test_opus_api.c new file mode 100644 index 0000000..fb385c6 --- /dev/null +++ b/extern/opus/tests/test_opus_api.c @@ -0,0 +1,1904 @@ +/* Copyright (c) 2011-2013 Xiph.Org Foundation + Written by Gregory Maxwell */ +/* + 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. + + 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 OWNER + 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 tests the API presented by the libopus system. + It does not attempt to extensively exercise the codec internals. + The strategy here is to simply the API interface invariants: + That sane options are accepted, insane options are rejected, + and that nothing blows up. In particular we don't actually test + that settings are heeded by the codec (though we do check that + get after set returns a sane value when it should). Other + tests check the actual codec behavior. + In cases where its reasonable to do so we test exhaustively, + but its not reasonable to do so in all cases. + Although these tests are simple they found several library bugs + when they were initially developed. */ + +/* These tests are more sensitive if compiled with -DVALGRIND and + run inside valgrind. Malloc failure testing requires glibc. */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include "arch.h" +#include "opus_multistream.h" +#include "opus.h" +#include "test_opus_common.h" + +#ifdef VALGRIND +#include +#define VG_UNDEF(x,y) VALGRIND_MAKE_MEM_UNDEFINED((x),(y)) +#define VG_CHECK(x,y) VALGRIND_CHECK_MEM_IS_DEFINED((x),(y)) +#else +#define VG_UNDEF(x,y) +#define VG_CHECK(x,y) +#endif + +#if defined(HAVE___MALLOC_HOOK) +#define MALLOC_FAIL +#include "os_support.h" +#include + +static const opus_int32 opus_apps[3] = {OPUS_APPLICATION_VOIP, + OPUS_APPLICATION_AUDIO,OPUS_APPLICATION_RESTRICTED_LOWDELAY}; + +void *malloc_hook(__attribute__((unused)) size_t size, + __attribute__((unused)) const void *caller) +{ + return 0; +} +#endif + +opus_int32 *null_int_ptr = (opus_int32 *)NULL; +opus_uint32 *null_uint_ptr = (opus_uint32 *)NULL; + +static const opus_int32 opus_rates[5] = {48000,24000,16000,12000,8000}; + +opus_int32 test_dec_api(void) +{ + opus_uint32 dec_final_range; + OpusDecoder *dec; + OpusDecoder *dec2; + opus_int32 i,j,cfgs; + unsigned char packet[1276]; +#ifndef DISABLE_FLOAT_API + float fbuf[960*2]; +#endif + short sbuf[960*2]; + int c,err; + + cfgs=0; + /*First test invalid configurations which should fail*/ + fprintf(stdout,"\n Decoder basic API tests\n"); + fprintf(stdout," ---------------------------------------------------\n"); + for(c=0;c<4;c++) + { + i=opus_decoder_get_size(c); + if(((c==1||c==2)&&(i<=2048||i>1<<16))||((c!=1&&c!=2)&&i!=0))test_failed(); + fprintf(stdout," opus_decoder_get_size(%d)=%d ...............%s OK.\n",c,i,i>0?"":"...."); + cfgs++; + } + + /*Test with unsupported sample rates*/ + for(c=0;c<4;c++) + { + for(i=-7;i<=96000;i++) + { + int fs; + if((i==8000||i==12000||i==16000||i==24000||i==48000)&&(c==1||c==2))continue; + switch(i) + { + case(-5):fs=-8000;break; + case(-6):fs=INT32_MAX;break; + case(-7):fs=INT32_MIN;break; + default:fs=i; + } + err = OPUS_OK; + VG_UNDEF(&err,sizeof(err)); + dec = opus_decoder_create(fs, c, &err); + if(err!=OPUS_BAD_ARG || dec!=NULL)test_failed(); + cfgs++; + dec = opus_decoder_create(fs, c, 0); + if(dec!=NULL)test_failed(); + cfgs++; + dec=malloc(opus_decoder_get_size(2)); + if(dec==NULL)test_failed(); + err = opus_decoder_init(dec,fs,c); + if(err!=OPUS_BAD_ARG)test_failed(); + cfgs++; + free(dec); + } + } + + VG_UNDEF(&err,sizeof(err)); + dec = opus_decoder_create(48000, 2, &err); + if(err!=OPUS_OK || dec==NULL)test_failed(); + VG_CHECK(dec,opus_decoder_get_size(2)); + cfgs++; + + fprintf(stdout," opus_decoder_create() ........................ OK.\n"); + fprintf(stdout," opus_decoder_init() .......................... OK.\n"); + + err=opus_decoder_ctl(dec, OPUS_GET_FINAL_RANGE(null_uint_ptr)); + if(err != OPUS_BAD_ARG)test_failed(); + VG_UNDEF(&dec_final_range,sizeof(dec_final_range)); + err=opus_decoder_ctl(dec, OPUS_GET_FINAL_RANGE(&dec_final_range)); + if(err!=OPUS_OK)test_failed(); + VG_CHECK(&dec_final_range,sizeof(dec_final_range)); + fprintf(stdout," OPUS_GET_FINAL_RANGE ......................... OK.\n"); + cfgs++; + + err=opus_decoder_ctl(dec,OPUS_UNIMPLEMENTED); + if(err!=OPUS_UNIMPLEMENTED)test_failed(); + fprintf(stdout," OPUS_UNIMPLEMENTED ........................... OK.\n"); + cfgs++; + + err=opus_decoder_ctl(dec, OPUS_GET_BANDWIDTH(null_int_ptr)); + if(err != OPUS_BAD_ARG)test_failed(); + VG_UNDEF(&i,sizeof(i)); + err=opus_decoder_ctl(dec, OPUS_GET_BANDWIDTH(&i)); + if(err != OPUS_OK || i!=0)test_failed(); + fprintf(stdout," OPUS_GET_BANDWIDTH ........................... OK.\n"); + cfgs++; + + err=opus_decoder_ctl(dec, OPUS_GET_SAMPLE_RATE(null_int_ptr)); + if(err != OPUS_BAD_ARG)test_failed(); + VG_UNDEF(&i,sizeof(i)); + err=opus_decoder_ctl(dec, OPUS_GET_SAMPLE_RATE(&i)); + if(err != OPUS_OK || i!=48000)test_failed(); + fprintf(stdout," OPUS_GET_SAMPLE_RATE ......................... OK.\n"); + cfgs++; + + /*GET_PITCH has different execution paths depending on the previously decoded frame.*/ + err=opus_decoder_ctl(dec, OPUS_GET_PITCH(null_int_ptr)); + if(err!=OPUS_BAD_ARG)test_failed(); + cfgs++; + VG_UNDEF(&i,sizeof(i)); + err=opus_decoder_ctl(dec, OPUS_GET_PITCH(&i)); + if(err != OPUS_OK || i>0 || i<-1)test_failed(); + cfgs++; + VG_UNDEF(packet,sizeof(packet)); + packet[0]=63<<2;packet[1]=packet[2]=0; + if(opus_decode(dec, packet, 3, sbuf, 960, 0)!=960)test_failed(); + cfgs++; + VG_UNDEF(&i,sizeof(i)); + err=opus_decoder_ctl(dec, OPUS_GET_PITCH(&i)); + if(err != OPUS_OK || i>0 || i<-1)test_failed(); + cfgs++; + packet[0]=1; + if(opus_decode(dec, packet, 1, sbuf, 960, 0)!=960)test_failed(); + cfgs++; + VG_UNDEF(&i,sizeof(i)); + err=opus_decoder_ctl(dec, OPUS_GET_PITCH(&i)); + if(err != OPUS_OK || i>0 || i<-1)test_failed(); + cfgs++; + fprintf(stdout," OPUS_GET_PITCH ............................... OK.\n"); + + err=opus_decoder_ctl(dec, OPUS_GET_LAST_PACKET_DURATION(null_int_ptr)); + if(err != OPUS_BAD_ARG)test_failed(); + VG_UNDEF(&i,sizeof(i)); + err=opus_decoder_ctl(dec, OPUS_GET_LAST_PACKET_DURATION(&i)); + if(err != OPUS_OK || i!=960)test_failed(); + cfgs++; + fprintf(stdout," OPUS_GET_LAST_PACKET_DURATION ................ OK.\n"); + + VG_UNDEF(&i,sizeof(i)); + err=opus_decoder_ctl(dec, OPUS_GET_GAIN(&i)); + VG_CHECK(&i,sizeof(i)); + if(err != OPUS_OK || i!=0)test_failed(); + cfgs++; + err=opus_decoder_ctl(dec, OPUS_GET_GAIN(null_int_ptr)); + if(err != OPUS_BAD_ARG)test_failed(); + cfgs++; + err=opus_decoder_ctl(dec, OPUS_SET_GAIN(-32769)); + if(err != OPUS_BAD_ARG)test_failed(); + cfgs++; + err=opus_decoder_ctl(dec, OPUS_SET_GAIN(32768)); + if(err != OPUS_BAD_ARG)test_failed(); + cfgs++; + err=opus_decoder_ctl(dec, OPUS_SET_GAIN(-15)); + if(err != OPUS_OK)test_failed(); + cfgs++; + VG_UNDEF(&i,sizeof(i)); + err=opus_decoder_ctl(dec, OPUS_GET_GAIN(&i)); + VG_CHECK(&i,sizeof(i)); + if(err != OPUS_OK || i!=-15)test_failed(); + cfgs++; + fprintf(stdout," OPUS_SET_GAIN ................................ OK.\n"); + fprintf(stdout," OPUS_GET_GAIN ................................ OK.\n"); + + /*Reset the decoder*/ + dec2=malloc(opus_decoder_get_size(2)); + memcpy(dec2,dec,opus_decoder_get_size(2)); + if(opus_decoder_ctl(dec, OPUS_RESET_STATE)!=OPUS_OK)test_failed(); + if(memcmp(dec2,dec,opus_decoder_get_size(2))==0)test_failed(); + free(dec2); + fprintf(stdout," OPUS_RESET_STATE ............................. OK.\n"); + cfgs++; + + VG_UNDEF(packet,sizeof(packet)); + packet[0]=0; + if(opus_decoder_get_nb_samples(dec,packet,1)!=480)test_failed(); + if(opus_packet_get_nb_samples(packet,1,48000)!=480)test_failed(); + if(opus_packet_get_nb_samples(packet,1,96000)!=960)test_failed(); + if(opus_packet_get_nb_samples(packet,1,32000)!=320)test_failed(); + if(opus_packet_get_nb_samples(packet,1,8000)!=80)test_failed(); + packet[0]=3; + if(opus_packet_get_nb_samples(packet,1,24000)!=OPUS_INVALID_PACKET)test_failed(); + packet[0]=(63<<2)|3; + packet[1]=63; + if(opus_packet_get_nb_samples(packet,0,24000)!=OPUS_BAD_ARG)test_failed(); + if(opus_packet_get_nb_samples(packet,2,48000)!=OPUS_INVALID_PACKET)test_failed(); + if(opus_decoder_get_nb_samples(dec,packet,2)!=OPUS_INVALID_PACKET)test_failed(); + fprintf(stdout," opus_{packet,decoder}_get_nb_samples() ....... OK.\n"); + cfgs+=9; + + if(OPUS_BAD_ARG!=opus_packet_get_nb_frames(packet,0))test_failed(); + for(i=0;i<256;i++) { + int l1res[4]={1,2,2,OPUS_INVALID_PACKET}; + packet[0]=i; + if(l1res[packet[0]&3]!=opus_packet_get_nb_frames(packet,1))test_failed(); + cfgs++; + for(j=0;j<256;j++) { + packet[1]=j; + if(((packet[0]&3)!=3?l1res[packet[0]&3]:packet[1]&63)!=opus_packet_get_nb_frames(packet,2))test_failed(); + cfgs++; + } + } + fprintf(stdout," opus_packet_get_nb_frames() .................. OK.\n"); + + for(i=0;i<256;i++) { + int bw; + packet[0]=i; + bw=packet[0]>>4; + bw=OPUS_BANDWIDTH_NARROWBAND+(((((bw&7)*9)&(63-(bw&8)))+2+12*((bw&8)!=0))>>4); + if(bw!=opus_packet_get_bandwidth(packet))test_failed(); + cfgs++; + } + fprintf(stdout," opus_packet_get_bandwidth() .................. OK.\n"); + + for(i=0;i<256;i++) { + int fp3s,rate; + packet[0]=i; + fp3s=packet[0]>>3; + fp3s=((((3-(fp3s&3))*13&119)+9)>>2)*((fp3s>13)*(3-((fp3s&3)==3))+1)*25; + for(rate=0;rate<5;rate++) { + if((opus_rates[rate]*3/fp3s)!=opus_packet_get_samples_per_frame(packet,opus_rates[rate]))test_failed(); + cfgs++; + } + } + fprintf(stdout," opus_packet_get_samples_per_frame() .......... OK.\n"); + + packet[0]=(63<<2)+3; + packet[1]=49; + for(j=2;j<51;j++)packet[j]=0; + VG_UNDEF(sbuf,sizeof(sbuf)); + if(opus_decode(dec, packet, 51, sbuf, 960, 0)!=OPUS_INVALID_PACKET)test_failed(); + cfgs++; + packet[0]=(63<<2); + packet[1]=packet[2]=0; + if(opus_decode(dec, packet, -1, sbuf, 960, 0)!=OPUS_BAD_ARG)test_failed(); + cfgs++; + if(opus_decode(dec, packet, 3, sbuf, 60, 0)!=OPUS_BUFFER_TOO_SMALL)test_failed(); + cfgs++; + if(opus_decode(dec, packet, 3, sbuf, 480, 0)!=OPUS_BUFFER_TOO_SMALL)test_failed(); + cfgs++; + if(opus_decode(dec, packet, 3, sbuf, 960, 0)!=960)test_failed(); + cfgs++; + fprintf(stdout," opus_decode() ................................ OK.\n"); +#ifndef DISABLE_FLOAT_API + VG_UNDEF(fbuf,sizeof(fbuf)); + if(opus_decode_float(dec, packet, 3, fbuf, 960, 0)!=960)test_failed(); + cfgs++; + fprintf(stdout," opus_decode_float() .......................... OK.\n"); +#endif + +#if 0 + /*These tests are disabled because the library crashes with null states*/ + if(opus_decoder_ctl(0,OPUS_RESET_STATE) !=OPUS_INVALID_STATE)test_failed(); + if(opus_decoder_init(0,48000,1) !=OPUS_INVALID_STATE)test_failed(); + if(opus_decode(0,packet,1,outbuf,2880,0) !=OPUS_INVALID_STATE)test_failed(); + if(opus_decode_float(0,packet,1,0,2880,0) !=OPUS_INVALID_STATE)test_failed(); + if(opus_decoder_get_nb_samples(0,packet,1) !=OPUS_INVALID_STATE)test_failed(); + if(opus_packet_get_nb_frames(NULL,1) !=OPUS_BAD_ARG)test_failed(); + if(opus_packet_get_bandwidth(NULL) !=OPUS_BAD_ARG)test_failed(); + if(opus_packet_get_samples_per_frame(NULL,48000)!=OPUS_BAD_ARG)test_failed(); +#endif + opus_decoder_destroy(dec); + cfgs++; + fprintf(stdout," All decoder interface tests passed\n"); + fprintf(stdout," (%6d API invocations)\n",cfgs); + return cfgs; +} + +opus_int32 test_msdec_api(void) +{ + opus_uint32 dec_final_range; + OpusMSDecoder *dec; + OpusDecoder *streamdec; + opus_int32 i,j,cfgs; + unsigned char packet[1276]; + unsigned char mapping[256]; +#ifndef DISABLE_FLOAT_API + float fbuf[960*2]; +#endif + short sbuf[960*2]; + int a,b,c,err; + + mapping[0]=0; + mapping[1]=1; + for(i=2;i<256;i++)VG_UNDEF(&mapping[i],sizeof(unsigned char)); + + cfgs=0; + /*First test invalid configurations which should fail*/ + fprintf(stdout,"\n Multistream decoder basic API tests\n"); + fprintf(stdout," ---------------------------------------------------\n"); + for(a=-1;a<4;a++) + { + for(b=-1;b<4;b++) + { + i=opus_multistream_decoder_get_size(a,b); + if(((a>0&&b<=a&&b>=0)&&(i<=2048||i>((1<<16)*a)))||((a<1||b>a||b<0)&&i!=0))test_failed(); + fprintf(stdout," opus_multistream_decoder_get_size(%2d,%2d)=%d %sOK.\n",a,b,i,i>0?"":"... "); + cfgs++; + } + } + + /*Test with unsupported sample rates*/ + for(c=1;c<3;c++) + { + for(i=-7;i<=96000;i++) + { + int fs; + if((i==8000||i==12000||i==16000||i==24000||i==48000)&&(c==1||c==2))continue; + switch(i) + { + case(-5):fs=-8000;break; + case(-6):fs=INT32_MAX;break; + case(-7):fs=INT32_MIN;break; + default:fs=i; + } + err = OPUS_OK; + VG_UNDEF(&err,sizeof(err)); + dec = opus_multistream_decoder_create(fs, c, 1, c-1, mapping, &err); + if(err!=OPUS_BAD_ARG || dec!=NULL)test_failed(); + cfgs++; + dec = opus_multistream_decoder_create(fs, c, 1, c-1, mapping, 0); + if(dec!=NULL)test_failed(); + cfgs++; + dec=malloc(opus_multistream_decoder_get_size(1,1)); + if(dec==NULL)test_failed(); + err = opus_multistream_decoder_init(dec,fs,c,1,c-1, mapping); + if(err!=OPUS_BAD_ARG)test_failed(); + cfgs++; + free(dec); + } + } + + for(c=0;c<2;c++) + { + int *ret_err; + ret_err = c?0:&err; + + mapping[0]=0; + mapping[1]=1; + for(i=2;i<256;i++)VG_UNDEF(&mapping[i],sizeof(unsigned char)); + + VG_UNDEF(ret_err,sizeof(*ret_err)); + dec = opus_multistream_decoder_create(48000, 2, 1, 0, mapping, ret_err); + if(ret_err){VG_CHECK(ret_err,sizeof(*ret_err));} + if((ret_err && *ret_err!=OPUS_BAD_ARG) || dec!=NULL)test_failed(); + cfgs++; + + VG_UNDEF(ret_err,sizeof(*ret_err)); + mapping[0]=mapping[1]=0; + dec = opus_multistream_decoder_create(48000, 2, 1, 0, mapping, ret_err); + if(ret_err){VG_CHECK(ret_err,sizeof(*ret_err));} + if((ret_err && *ret_err!=OPUS_OK) || dec==NULL)test_failed(); + cfgs++; + opus_multistream_decoder_destroy(dec); + cfgs++; + + VG_UNDEF(ret_err,sizeof(*ret_err)); + dec = opus_multistream_decoder_create(48000, 1, 4, 1, mapping, ret_err); + if(ret_err){VG_CHECK(ret_err,sizeof(*ret_err));} + if((ret_err && *ret_err!=OPUS_OK) || dec==NULL)test_failed(); + cfgs++; + + err = opus_multistream_decoder_init(dec,48000, 1, 0, 0, mapping); + if(err!=OPUS_BAD_ARG)test_failed(); + cfgs++; + + err = opus_multistream_decoder_init(dec,48000, 1, 1, -1, mapping); + if(err!=OPUS_BAD_ARG)test_failed(); + cfgs++; + + opus_multistream_decoder_destroy(dec); + cfgs++; + + VG_UNDEF(ret_err,sizeof(*ret_err)); + dec = opus_multistream_decoder_create(48000, 2, 1, 1, mapping, ret_err); + if(ret_err){VG_CHECK(ret_err,sizeof(*ret_err));} + if((ret_err && *ret_err!=OPUS_OK) || dec==NULL)test_failed(); + cfgs++; + opus_multistream_decoder_destroy(dec); + cfgs++; + + VG_UNDEF(ret_err,sizeof(*ret_err)); + dec = opus_multistream_decoder_create(48000, 255, 255, 1, mapping, ret_err); + if(ret_err){VG_CHECK(ret_err,sizeof(*ret_err));} + if((ret_err && *ret_err!=OPUS_BAD_ARG) || dec!=NULL)test_failed(); + cfgs++; + + VG_UNDEF(ret_err,sizeof(*ret_err)); + dec = opus_multistream_decoder_create(48000, -1, 1, 1, mapping, ret_err); + if(ret_err){VG_CHECK(ret_err,sizeof(*ret_err));} + if((ret_err && *ret_err!=OPUS_BAD_ARG) || dec!=NULL)test_failed(); + cfgs++; + + VG_UNDEF(ret_err,sizeof(*ret_err)); + dec = opus_multistream_decoder_create(48000, 0, 1, 1, mapping, ret_err); + if(ret_err){VG_CHECK(ret_err,sizeof(*ret_err));} + if((ret_err && *ret_err!=OPUS_BAD_ARG) || dec!=NULL)test_failed(); + cfgs++; + + VG_UNDEF(ret_err,sizeof(*ret_err)); + dec = opus_multistream_decoder_create(48000, 1, -1, 2, mapping, ret_err); + if(ret_err){VG_CHECK(ret_err,sizeof(*ret_err));} + if((ret_err && *ret_err!=OPUS_BAD_ARG) || dec!=NULL)test_failed(); + cfgs++; + + VG_UNDEF(ret_err,sizeof(*ret_err)); + dec = opus_multistream_decoder_create(48000, 1, -1, -1, mapping, ret_err); + if(ret_err){VG_CHECK(ret_err,sizeof(*ret_err));} + if((ret_err && *ret_err!=OPUS_BAD_ARG) || dec!=NULL)test_failed(); + cfgs++; + + VG_UNDEF(ret_err,sizeof(*ret_err)); + dec = opus_multistream_decoder_create(48000, 256, 255, 1, mapping, ret_err); + if(ret_err){VG_CHECK(ret_err,sizeof(*ret_err));} + if((ret_err && *ret_err!=OPUS_BAD_ARG) || dec!=NULL)test_failed(); + cfgs++; + + VG_UNDEF(ret_err,sizeof(*ret_err)); + dec = opus_multistream_decoder_create(48000, 256, 255, 0, mapping, ret_err); + if(ret_err){VG_CHECK(ret_err,sizeof(*ret_err));} + if((ret_err && *ret_err!=OPUS_BAD_ARG) || dec!=NULL)test_failed(); + cfgs++; + + VG_UNDEF(ret_err,sizeof(*ret_err)); + mapping[0]=255; + mapping[1]=1; + mapping[2]=2; + dec = opus_multistream_decoder_create(48000, 3, 2, 0, mapping, ret_err); + if(ret_err){VG_CHECK(ret_err,sizeof(*ret_err));} + if((ret_err && *ret_err!=OPUS_BAD_ARG) || dec!=NULL)test_failed(); + cfgs++; + + VG_UNDEF(ret_err,sizeof(*ret_err)); + mapping[0]=0; + mapping[1]=0; + mapping[2]=0; + dec = opus_multistream_decoder_create(48000, 3, 2, 1, mapping, ret_err); + if(ret_err){VG_CHECK(ret_err,sizeof(*ret_err));} + if((ret_err && *ret_err!=OPUS_OK) || dec==NULL)test_failed(); + cfgs++; + opus_multistream_decoder_destroy(dec); + cfgs++; + + VG_UNDEF(ret_err,sizeof(*ret_err)); + mapping[0]=0; + mapping[1]=255; + mapping[2]=1; + mapping[3]=2; + mapping[4]=3; + dec = opus_multistream_decoder_create(48001, 5, 4, 1, mapping, ret_err); + if(ret_err){VG_CHECK(ret_err,sizeof(*ret_err));} + if((ret_err && *ret_err!=OPUS_BAD_ARG) || dec!=NULL)test_failed(); + cfgs++; + } + + VG_UNDEF(&err,sizeof(err)); + mapping[0]=0; + mapping[1]=255; + mapping[2]=1; + mapping[3]=2; + dec = opus_multistream_decoder_create(48000, 4, 2, 1, mapping, &err); + VG_CHECK(&err,sizeof(err)); + if(err!=OPUS_OK || dec==NULL)test_failed(); + cfgs++; + + fprintf(stdout," opus_multistream_decoder_create() ............ OK.\n"); + fprintf(stdout," opus_multistream_decoder_init() .............. OK.\n"); + + VG_UNDEF(&dec_final_range,sizeof(dec_final_range)); + err=opus_multistream_decoder_ctl(dec, OPUS_GET_FINAL_RANGE(&dec_final_range)); + if(err!=OPUS_OK)test_failed(); + VG_CHECK(&dec_final_range,sizeof(dec_final_range)); + fprintf(stdout," OPUS_GET_FINAL_RANGE ......................... OK.\n"); + cfgs++; + + streamdec=0; + VG_UNDEF(&streamdec,sizeof(streamdec)); + err=opus_multistream_decoder_ctl(dec, OPUS_MULTISTREAM_GET_DECODER_STATE(-1,&streamdec)); + if(err!=OPUS_BAD_ARG)test_failed(); + cfgs++; + err=opus_multistream_decoder_ctl(dec, OPUS_MULTISTREAM_GET_DECODER_STATE(1,&streamdec)); + if(err!=OPUS_OK||streamdec==NULL)test_failed(); + VG_CHECK(streamdec,opus_decoder_get_size(1)); + cfgs++; + err=opus_multistream_decoder_ctl(dec, OPUS_MULTISTREAM_GET_DECODER_STATE(2,&streamdec)); + if(err!=OPUS_BAD_ARG)test_failed(); + cfgs++; + err=opus_multistream_decoder_ctl(dec, OPUS_MULTISTREAM_GET_DECODER_STATE(0,&streamdec)); + if(err!=OPUS_OK||streamdec==NULL)test_failed(); + VG_CHECK(streamdec,opus_decoder_get_size(1)); + fprintf(stdout," OPUS_MULTISTREAM_GET_DECODER_STATE ........... OK.\n"); + cfgs++; + + for(j=0;j<2;j++) + { + OpusDecoder *od; + err=opus_multistream_decoder_ctl(dec,OPUS_MULTISTREAM_GET_DECODER_STATE(j,&od)); + if(err != OPUS_OK)test_failed(); + VG_UNDEF(&i,sizeof(i)); + err=opus_decoder_ctl(od, OPUS_GET_GAIN(&i)); + VG_CHECK(&i,sizeof(i)); + if(err != OPUS_OK || i!=0)test_failed(); + cfgs++; + } + err=opus_multistream_decoder_ctl(dec,OPUS_SET_GAIN(15)); + if(err!=OPUS_OK)test_failed(); + fprintf(stdout," OPUS_SET_GAIN ................................ OK.\n"); + for(j=0;j<2;j++) + { + OpusDecoder *od; + err=opus_multistream_decoder_ctl(dec,OPUS_MULTISTREAM_GET_DECODER_STATE(j,&od)); + if(err != OPUS_OK)test_failed(); + VG_UNDEF(&i,sizeof(i)); + err=opus_decoder_ctl(od, OPUS_GET_GAIN(&i)); + VG_CHECK(&i,sizeof(i)); + if(err != OPUS_OK || i!=15)test_failed(); + cfgs++; + } + fprintf(stdout," OPUS_GET_GAIN ................................ OK.\n"); + + VG_UNDEF(&i,sizeof(i)); + err=opus_multistream_decoder_ctl(dec, OPUS_GET_BANDWIDTH(&i)); + if(err != OPUS_OK || i!=0)test_failed(); + fprintf(stdout," OPUS_GET_BANDWIDTH ........................... OK.\n"); + cfgs++; + + err=opus_multistream_decoder_ctl(dec,OPUS_UNIMPLEMENTED); + if(err!=OPUS_UNIMPLEMENTED)test_failed(); + fprintf(stdout," OPUS_UNIMPLEMENTED ........................... OK.\n"); + cfgs++; + +#if 0 + /*Currently unimplemented for multistream*/ + /*GET_PITCH has different execution paths depending on the previously decoded frame.*/ + err=opus_multistream_decoder_ctl(dec, OPUS_GET_PITCH(null_int_ptr)); + if(err!=OPUS_BAD_ARG)test_failed(); + cfgs++; + VG_UNDEF(&i,sizeof(i)); + err=opus_multistream_decoder_ctl(dec, OPUS_GET_PITCH(&i)); + if(err != OPUS_OK || i>0 || i<-1)test_failed(); + cfgs++; + VG_UNDEF(packet,sizeof(packet)); + packet[0]=63<<2;packet[1]=packet[2]=0; + if(opus_multistream_decode(dec, packet, 3, sbuf, 960, 0)!=960)test_failed(); + cfgs++; + VG_UNDEF(&i,sizeof(i)); + err=opus_multistream_decoder_ctl(dec, OPUS_GET_PITCH(&i)); + if(err != OPUS_OK || i>0 || i<-1)test_failed(); + cfgs++; + packet[0]=1; + if(opus_multistream_decode(dec, packet, 1, sbuf, 960, 0)!=960)test_failed(); + cfgs++; + VG_UNDEF(&i,sizeof(i)); + err=opus_multistream_decoder_ctl(dec, OPUS_GET_PITCH(&i)); + if(err != OPUS_OK || i>0 || i<-1)test_failed(); + cfgs++; + fprintf(stdout," OPUS_GET_PITCH ............................... OK.\n"); +#endif + + /*Reset the decoder*/ + if(opus_multistream_decoder_ctl(dec, OPUS_RESET_STATE)!=OPUS_OK)test_failed(); + fprintf(stdout," OPUS_RESET_STATE ............................. OK.\n"); + cfgs++; + + opus_multistream_decoder_destroy(dec); + cfgs++; + VG_UNDEF(&err,sizeof(err)); + dec = opus_multistream_decoder_create(48000, 2, 1, 1, mapping, &err); + if(err!=OPUS_OK || dec==NULL)test_failed(); + cfgs++; + + packet[0]=(63<<2)+3; + packet[1]=49; + for(j=2;j<51;j++)packet[j]=0; + VG_UNDEF(sbuf,sizeof(sbuf)); + if(opus_multistream_decode(dec, packet, 51, sbuf, 960, 0)!=OPUS_INVALID_PACKET)test_failed(); + cfgs++; + packet[0]=(63<<2); + packet[1]=packet[2]=0; + if(opus_multistream_decode(dec, packet, -1, sbuf, 960, 0)!=OPUS_BAD_ARG){printf("%d\n",opus_multistream_decode(dec, packet, -1, sbuf, 960, 0));test_failed();} + cfgs++; + if(opus_multistream_decode(dec, packet, 3, sbuf, -960, 0)!=OPUS_BAD_ARG)test_failed(); + cfgs++; + if(opus_multistream_decode(dec, packet, 3, sbuf, 60, 0)!=OPUS_BUFFER_TOO_SMALL)test_failed(); + cfgs++; + if(opus_multistream_decode(dec, packet, 3, sbuf, 480, 0)!=OPUS_BUFFER_TOO_SMALL)test_failed(); + cfgs++; + if(opus_multistream_decode(dec, packet, 3, sbuf, 960, 0)!=960)test_failed(); + cfgs++; + fprintf(stdout," opus_multistream_decode() .................... OK.\n"); +#ifndef DISABLE_FLOAT_API + VG_UNDEF(fbuf,sizeof(fbuf)); + if(opus_multistream_decode_float(dec, packet, 3, fbuf, 960, 0)!=960)test_failed(); + cfgs++; + fprintf(stdout," opus_multistream_decode_float() .............. OK.\n"); +#endif + +#if 0 + /*These tests are disabled because the library crashes with null states*/ + if(opus_multistream_decoder_ctl(0,OPUS_RESET_STATE) !=OPUS_INVALID_STATE)test_failed(); + if(opus_multistream_decoder_init(0,48000,1) !=OPUS_INVALID_STATE)test_failed(); + if(opus_multistream_decode(0,packet,1,outbuf,2880,0) !=OPUS_INVALID_STATE)test_failed(); + if(opus_multistream_decode_float(0,packet,1,0,2880,0) !=OPUS_INVALID_STATE)test_failed(); + if(opus_multistream_decoder_get_nb_samples(0,packet,1) !=OPUS_INVALID_STATE)test_failed(); +#endif + opus_multistream_decoder_destroy(dec); + cfgs++; + fprintf(stdout," All multistream decoder interface tests passed\n"); + fprintf(stdout," (%6d API invocations)\n",cfgs); + return cfgs; +} + +#ifdef VALGRIND +#define UNDEFINE_FOR_PARSE toc=-1; \ + frames[0]=(unsigned char *)0; \ + frames[1]=(unsigned char *)0; \ + payload_offset=-1; \ + VG_UNDEF(&toc,sizeof(toc)); \ + VG_UNDEF(frames,sizeof(frames));\ + VG_UNDEF(&payload_offset,sizeof(payload_offset)); +#else +#define UNDEFINE_FOR_PARSE toc=-1; \ + frames[0]=(unsigned char *)0; \ + frames[1]=(unsigned char *)0; \ + payload_offset=-1; +#endif + +/* This test exercises the heck out of the libopus parser. + It is much larger than the parser itself in part because + it tries to hit a lot of corner cases that could never + fail with the libopus code, but might be problematic for + other implementations. */ +opus_int32 test_parse(void) +{ + opus_int32 i,j,jj,sz; + unsigned char packet[1276]; + opus_int32 cfgs,cfgs_total; + unsigned char toc; + const unsigned char *frames[48]; + short size[48]; + int payload_offset, ret; + fprintf(stdout,"\n Packet header parsing tests\n"); + fprintf(stdout," ---------------------------------------------------\n"); + memset(packet,0,sizeof(char)*1276); + packet[0]=63<<2; + if(opus_packet_parse(packet,1,&toc,frames,0,&payload_offset)!=OPUS_BAD_ARG)test_failed(); + cfgs_total=cfgs=1; + /*code 0*/ + for(i=0;i<64;i++) + { + packet[0]=i<<2; + UNDEFINE_FOR_PARSE + ret=opus_packet_parse(packet,4,&toc,frames,size,&payload_offset); + cfgs++; + if(ret!=1)test_failed(); + if(size[0]!=3)test_failed(); + if(frames[0]!=packet+1)test_failed(); + } + fprintf(stdout," code 0 (%2d cases) ............................ OK.\n",cfgs); + cfgs_total+=cfgs;cfgs=0; + + /*code 1, two frames of the same size*/ + for(i=0;i<64;i++) + { + packet[0]=(i<<2)+1; + for(jj=0;jj<=1275*2+3;jj++) + { + UNDEFINE_FOR_PARSE + ret=opus_packet_parse(packet,jj,&toc,frames,size,&payload_offset); + cfgs++; + if((jj&1)==1 && jj<=2551) + { + /* Must pass if payload length even (packet length odd) and + size<=2551, must fail otherwise. */ + if(ret!=2)test_failed(); + if(size[0]!=size[1] || size[0]!=((jj-1)>>1))test_failed(); + if(frames[0]!=packet+1)test_failed(); + if(frames[1]!=frames[0]+size[0])test_failed(); + if((toc>>2)!=i)test_failed(); + } else if(ret!=OPUS_INVALID_PACKET)test_failed(); + } + } + fprintf(stdout," code 1 (%6d cases) ........................ OK.\n",cfgs); + cfgs_total+=cfgs;cfgs=0; + + for(i=0;i<64;i++) + { + /*code 2, length code overflow*/ + packet[0]=(i<<2)+2; + UNDEFINE_FOR_PARSE + ret=opus_packet_parse(packet,1,&toc,frames,size,&payload_offset); + cfgs++; + if(ret!=OPUS_INVALID_PACKET)test_failed(); + packet[1]=252; + UNDEFINE_FOR_PARSE + ret=opus_packet_parse(packet,2,&toc,frames,size,&payload_offset); + cfgs++; + if(ret!=OPUS_INVALID_PACKET)test_failed(); + for(j=0;j<1275;j++) + { + if(j<252)packet[1]=j; + else{packet[1]=252+(j&3);packet[2]=(j-252)>>2;} + /*Code 2, one too short*/ + UNDEFINE_FOR_PARSE + ret=opus_packet_parse(packet,j+(j<252?2:3)-1,&toc,frames,size,&payload_offset); + cfgs++; + if(ret!=OPUS_INVALID_PACKET)test_failed(); + /*Code 2, one too long*/ + UNDEFINE_FOR_PARSE + ret=opus_packet_parse(packet,j+(j<252?2:3)+1276,&toc,frames,size,&payload_offset); + cfgs++; + if(ret!=OPUS_INVALID_PACKET)test_failed(); + /*Code 2, second zero*/ + UNDEFINE_FOR_PARSE + ret=opus_packet_parse(packet,j+(j<252?2:3),&toc,frames,size,&payload_offset); + cfgs++; + if(ret!=2)test_failed(); + if(size[0]!=j||size[1]!=0)test_failed(); + if(frames[1]!=frames[0]+size[0])test_failed(); + if((toc>>2)!=i)test_failed(); + /*Code 2, normal*/ + UNDEFINE_FOR_PARSE + ret=opus_packet_parse(packet,(j<<1)+4,&toc,frames,size,&payload_offset); + cfgs++; + if(ret!=2)test_failed(); + if(size[0]!=j||size[1]!=(j<<1)+3-j-(j<252?1:2))test_failed(); + if(frames[1]!=frames[0]+size[0])test_failed(); + if((toc>>2)!=i)test_failed(); + } + } + fprintf(stdout," code 2 (%6d cases) ........................ OK.\n",cfgs); + cfgs_total+=cfgs;cfgs=0; + + for(i=0;i<64;i++) + { + packet[0]=(i<<2)+3; + /*code 3, length code overflow*/ + UNDEFINE_FOR_PARSE + ret=opus_packet_parse(packet,1,&toc,frames,size,&payload_offset); + cfgs++; + if(ret!=OPUS_INVALID_PACKET)test_failed(); + } + fprintf(stdout," code 3 m-truncation (%2d cases) ............... OK.\n",cfgs); + cfgs_total+=cfgs;cfgs=0; + + for(i=0;i<64;i++) + { + /*code 3, m is zero or 49-63*/ + packet[0]=(i<<2)+3; + for(jj=49;jj<=64;jj++) + { + packet[1]=0+(jj&63); /*CBR, no padding*/ + UNDEFINE_FOR_PARSE + ret=opus_packet_parse(packet,1275,&toc,frames,size,&payload_offset); + cfgs++; + if(ret!=OPUS_INVALID_PACKET)test_failed(); + packet[1]=128+(jj&63); /*VBR, no padding*/ + UNDEFINE_FOR_PARSE + ret=opus_packet_parse(packet,1275,&toc,frames,size,&payload_offset); + cfgs++; + if(ret!=OPUS_INVALID_PACKET)test_failed(); + packet[1]=64+(jj&63); /*CBR, padding*/ + UNDEFINE_FOR_PARSE + ret=opus_packet_parse(packet,1275,&toc,frames,size,&payload_offset); + cfgs++; + if(ret!=OPUS_INVALID_PACKET)test_failed(); + packet[1]=128+64+(jj&63); /*VBR, padding*/ + UNDEFINE_FOR_PARSE + ret=opus_packet_parse(packet,1275,&toc,frames,size,&payload_offset); + cfgs++; + if(ret!=OPUS_INVALID_PACKET)test_failed(); + } + } + fprintf(stdout," code 3 m=0,49-64 (%2d cases) ................ OK.\n",cfgs); + cfgs_total+=cfgs;cfgs=0; + + for(i=0;i<64;i++) + { + packet[0]=(i<<2)+3; + /*code 3, m is one, cbr*/ + packet[1]=1; + for(j=0;j<1276;j++) + { + UNDEFINE_FOR_PARSE + ret=opus_packet_parse(packet,j+2,&toc,frames,size,&payload_offset); + cfgs++; + if(ret!=1)test_failed(); + if(size[0]!=j)test_failed(); + if((toc>>2)!=i)test_failed(); + } + UNDEFINE_FOR_PARSE + ret=opus_packet_parse(packet,1276+2,&toc,frames,size,&payload_offset); + cfgs++; + if(ret!=OPUS_INVALID_PACKET)test_failed(); + } + fprintf(stdout," code 3 m=1 CBR (%2d cases) ................. OK.\n",cfgs); + cfgs_total+=cfgs;cfgs=0; + + for(i=0;i<64;i++) + { + int frame_samp; + /*code 3, m>1 CBR*/ + packet[0]=(i<<2)+3; + frame_samp=opus_packet_get_samples_per_frame(packet,48000); + for(j=2;j<49;j++) + { + packet[1]=j; + for(sz=2;sz<((j+2)*1275);sz++) + { + UNDEFINE_FOR_PARSE + ret=opus_packet_parse(packet,sz,&toc,frames,size,&payload_offset); + cfgs++; + /*Must be <=120ms, must be evenly divisible, can't have frames>1275 bytes*/ + if(frame_samp*j<=5760 && (sz-2)%j==0 && (sz-2)/j<1276) + { + if(ret!=j)test_failed(); + for(jj=1;jj>2)!=i)test_failed(); + } else if(ret!=OPUS_INVALID_PACKET)test_failed(); + } + } + /*Super jumbo packets*/ + packet[1]=5760/frame_samp; + UNDEFINE_FOR_PARSE + ret=opus_packet_parse(packet,1275*packet[1]+2,&toc,frames,size,&payload_offset); + cfgs++; + if(ret!=packet[1])test_failed(); + for(jj=0;jj>2)!=i)test_failed(); + } + UNDEFINE_FOR_PARSE + ret=opus_packet_parse(packet,2+1276,&toc,frames,size,&payload_offset); + cfgs++; + if(ret!=OPUS_INVALID_PACKET)test_failed(); + for(j=2;j<49;j++) + { + packet[1]=128+j; + /*Length code overflow*/ + UNDEFINE_FOR_PARSE + ret=opus_packet_parse(packet,2+j-2,&toc,frames,size,&payload_offset); + cfgs++; + if(ret!=OPUS_INVALID_PACKET)test_failed(); + packet[2]=252; + packet[3]=0; + for(jj=4;jj<2+j;jj++)packet[jj]=0; + UNDEFINE_FOR_PARSE + ret=opus_packet_parse(packet,2+j,&toc,frames,size,&payload_offset); + cfgs++; + if(ret!=OPUS_INVALID_PACKET)test_failed(); + /*One byte too short*/ + for(jj=2;jj<2+j;jj++)packet[jj]=0; + UNDEFINE_FOR_PARSE + ret=opus_packet_parse(packet,2+j-2,&toc,frames,size,&payload_offset); + cfgs++; + if(ret!=OPUS_INVALID_PACKET)test_failed(); + /*One byte too short thanks to length coding*/ + packet[2]=252; + packet[3]=0; + for(jj=4;jj<2+j;jj++)packet[jj]=0; + UNDEFINE_FOR_PARSE + ret=opus_packet_parse(packet,2+j+252-1,&toc,frames,size,&payload_offset); + cfgs++; + if(ret!=OPUS_INVALID_PACKET)test_failed(); + /*Most expensive way of coding zeros*/ + for(jj=2;jj<2+j;jj++)packet[jj]=0; + UNDEFINE_FOR_PARSE + ret=opus_packet_parse(packet,2+j-1,&toc,frames,size,&payload_offset); + cfgs++; + if(frame_samp*j<=5760){ + if(ret!=j)test_failed(); + for(jj=0;jj>2)!=i)test_failed(); + } else if(ret!=OPUS_INVALID_PACKET)test_failed(); + /*Quasi-CBR use of mode 3*/ + for(sz=0;sz<8;sz++) + { + const int tsz[8]={50,201,403,700,1472,5110,20400,61298}; + int pos=0; + int as=(tsz[sz]+i-j-2)/j; + for(jj=0;jj>2;pos+=2;} + } + UNDEFINE_FOR_PARSE + ret=opus_packet_parse(packet,tsz[sz]+i,&toc,frames,size,&payload_offset); + cfgs++; + if(frame_samp*j<=5760 && as<1276 && (tsz[sz]+i-2-pos-as*(j-1))<1276){ + if(ret!=j)test_failed(); + for(jj=0;jj>2)!=i)test_failed(); + } else if(ret!=OPUS_INVALID_PACKET)test_failed(); + } + } + } + fprintf(stdout," code 3 m=1-48 VBR (%2d cases) ............. OK.\n",cfgs); + cfgs_total+=cfgs;cfgs=0; + + for(i=0;i<64;i++) + { + packet[0]=(i<<2)+3; + /*Padding*/ + packet[1]=128+1+64; + /*Overflow the length coding*/ + for(jj=2;jj<127;jj++)packet[jj]=255; + UNDEFINE_FOR_PARSE + ret=opus_packet_parse(packet,127,&toc,frames,size,&payload_offset); + cfgs++; + if(ret!=OPUS_INVALID_PACKET)test_failed(); + + for(sz=0;sz<4;sz++) + { + const int tsz[4]={0,72,512,1275}; + for(jj=sz;jj<65025;jj+=11) + { + int pos; + for(pos=0;pos>2)!=i)test_failed(); + } else if (ret!=OPUS_INVALID_PACKET)test_failed(); + } + } + } + fprintf(stdout," code 3 padding (%2d cases) ............... OK.\n",cfgs); + cfgs_total+=cfgs; + fprintf(stdout," opus_packet_parse ............................ OK.\n"); + fprintf(stdout," All packet parsing tests passed\n"); + fprintf(stdout," (%d API invocations)\n",cfgs_total); + return cfgs_total; +} + +/* This is a helper macro for the encoder tests. + The encoder api tests all have a pattern of set-must-fail, set-must-fail, + set-must-pass, get-and-compare, set-must-pass, get-and-compare. */ +#define CHECK_SETGET(setcall,getcall,badv,badv2,goodv,goodv2,sok,gok) \ + i=(badv);\ + if(opus_encoder_ctl(enc,setcall)==OPUS_OK)test_failed();\ + i=(badv2);\ + if(opus_encoder_ctl(enc,setcall)==OPUS_OK)test_failed();\ + j=i=(goodv);\ + if(opus_encoder_ctl(enc,setcall)!=OPUS_OK)test_failed();\ + i=-12345;\ + VG_UNDEF(&i,sizeof(i)); \ + err=opus_encoder_ctl(enc,getcall);\ + if(err!=OPUS_OK || i!=j)test_failed();\ + j=i=(goodv2);\ + if(opus_encoder_ctl(enc,setcall)!=OPUS_OK)test_failed();\ + fprintf(stdout,sok);\ + i=-12345;\ + VG_UNDEF(&i,sizeof(i)); \ + err=opus_encoder_ctl(enc,getcall);\ + if(err!=OPUS_OK || i!=j)test_failed();\ + fprintf(stdout,gok);\ + cfgs+=6; + +opus_int32 test_enc_api(void) +{ + opus_uint32 enc_final_range; + OpusEncoder *enc; + opus_int32 i,j; + unsigned char packet[1276]; +#ifndef DISABLE_FLOAT_API + float fbuf[960*2]; +#endif + short sbuf[960*2]; + int c,err,cfgs; + + cfgs=0; + /*First test invalid configurations which should fail*/ + fprintf(stdout,"\n Encoder basic API tests\n"); + fprintf(stdout," ---------------------------------------------------\n"); + for(c=0;c<4;c++) + { + i=opus_encoder_get_size(c); + if(((c==1||c==2)&&(i<=2048||i>1<<17))||((c!=1&&c!=2)&&i!=0))test_failed(); + fprintf(stdout," opus_encoder_get_size(%d)=%d ...............%s OK.\n",c,i,i>0?"":"...."); + cfgs++; + } + + /*Test with unsupported sample rates, channel counts*/ + for(c=0;c<4;c++) + { + for(i=-7;i<=96000;i++) + { + int fs; + if((i==8000||i==12000||i==16000||i==24000||i==48000)&&(c==1||c==2))continue; + switch(i) + { + case(-5):fs=-8000;break; + case(-6):fs=INT32_MAX;break; + case(-7):fs=INT32_MIN;break; + default:fs=i; + } + err = OPUS_OK; + VG_UNDEF(&err,sizeof(err)); + enc = opus_encoder_create(fs, c, OPUS_APPLICATION_VOIP, &err); + if(err!=OPUS_BAD_ARG || enc!=NULL)test_failed(); + cfgs++; + enc = opus_encoder_create(fs, c, OPUS_APPLICATION_VOIP, 0); + if(enc!=NULL)test_failed(); + cfgs++; + opus_encoder_destroy(enc); + enc=malloc(opus_encoder_get_size(2)); + if(enc==NULL)test_failed(); + err = opus_encoder_init(enc, fs, c, OPUS_APPLICATION_VOIP); + if(err!=OPUS_BAD_ARG)test_failed(); + cfgs++; + free(enc); + } + } + + enc = opus_encoder_create(48000, 2, OPUS_AUTO, NULL); + if(enc!=NULL)test_failed(); + cfgs++; + + VG_UNDEF(&err,sizeof(err)); + enc = opus_encoder_create(48000, 2, OPUS_AUTO, &err); + if(err!=OPUS_BAD_ARG || enc!=NULL)test_failed(); + cfgs++; + + VG_UNDEF(&err,sizeof(err)); + enc = opus_encoder_create(48000, 2, OPUS_APPLICATION_VOIP, NULL); + if(enc==NULL)test_failed(); + opus_encoder_destroy(enc); + cfgs++; + + VG_UNDEF(&err,sizeof(err)); + enc = opus_encoder_create(48000, 2, OPUS_APPLICATION_RESTRICTED_LOWDELAY, &err); + if(err!=OPUS_OK || enc==NULL)test_failed(); + cfgs++; + err=opus_encoder_ctl(enc,OPUS_GET_LOOKAHEAD(&i)); + if(err!=OPUS_OK || i<0 || i>32766)test_failed(); + cfgs++; + opus_encoder_destroy(enc); + + VG_UNDEF(&err,sizeof(err)); + enc = opus_encoder_create(48000, 2, OPUS_APPLICATION_AUDIO, &err); + if(err!=OPUS_OK || enc==NULL)test_failed(); + cfgs++; + err=opus_encoder_ctl(enc,OPUS_GET_LOOKAHEAD(&i)); + if(err!=OPUS_OK || i<0 || i>32766)test_failed(); + opus_encoder_destroy(enc); + cfgs++; + + VG_UNDEF(&err,sizeof(err)); + enc = opus_encoder_create(48000, 2, OPUS_APPLICATION_VOIP, &err); + if(err!=OPUS_OK || enc==NULL)test_failed(); + cfgs++; + + fprintf(stdout," opus_encoder_create() ........................ OK.\n"); + fprintf(stdout," opus_encoder_init() .......................... OK.\n"); + + i=-12345; + VG_UNDEF(&i,sizeof(i)); + err=opus_encoder_ctl(enc,OPUS_GET_LOOKAHEAD(&i)); + if(err!=OPUS_OK || i<0 || i>32766)test_failed(); + cfgs++; + err=opus_encoder_ctl(enc,OPUS_GET_LOOKAHEAD(null_int_ptr)); + if(err!=OPUS_BAD_ARG)test_failed(); + cfgs++; + fprintf(stdout," OPUS_GET_LOOKAHEAD ........................... OK.\n"); + + err=opus_encoder_ctl(enc,OPUS_GET_SAMPLE_RATE(&i)); + if(err!=OPUS_OK || i!=48000)test_failed(); + cfgs++; + err=opus_encoder_ctl(enc,OPUS_GET_SAMPLE_RATE(null_int_ptr)); + if(err!=OPUS_BAD_ARG)test_failed(); + cfgs++; + fprintf(stdout," OPUS_GET_SAMPLE_RATE ......................... OK.\n"); + + if(opus_encoder_ctl(enc,OPUS_UNIMPLEMENTED)!=OPUS_UNIMPLEMENTED)test_failed(); + fprintf(stdout," OPUS_UNIMPLEMENTED ........................... OK.\n"); + cfgs++; + + err=opus_encoder_ctl(enc,OPUS_GET_APPLICATION(null_int_ptr)); + if(err!=OPUS_BAD_ARG)test_failed(); + cfgs++; + CHECK_SETGET(OPUS_SET_APPLICATION(i),OPUS_GET_APPLICATION(&i),-1,OPUS_AUTO, + OPUS_APPLICATION_AUDIO,OPUS_APPLICATION_RESTRICTED_LOWDELAY, + " OPUS_SET_APPLICATION ......................... OK.\n", + " OPUS_GET_APPLICATION ......................... OK.\n") + + err=opus_encoder_ctl(enc,OPUS_GET_BITRATE(null_int_ptr)); + if(err!=OPUS_BAD_ARG)test_failed(); + cfgs++; + if(opus_encoder_ctl(enc,OPUS_SET_BITRATE(1073741832))!=OPUS_OK)test_failed(); + cfgs++; + VG_UNDEF(&i,sizeof(i)); + if(opus_encoder_ctl(enc,OPUS_GET_BITRATE(&i))!=OPUS_OK)test_failed(); + if(i>700000||i<256000)test_failed(); + cfgs++; + CHECK_SETGET(OPUS_SET_BITRATE(i),OPUS_GET_BITRATE(&i),-12345,0, + 500,256000, + " OPUS_SET_BITRATE ............................. OK.\n", + " OPUS_GET_BITRATE ............................. OK.\n") + + err=opus_encoder_ctl(enc,OPUS_GET_FORCE_CHANNELS(null_int_ptr)); + if(err!=OPUS_BAD_ARG)test_failed(); + cfgs++; + CHECK_SETGET(OPUS_SET_FORCE_CHANNELS(i),OPUS_GET_FORCE_CHANNELS(&i),-1,3, + 1,OPUS_AUTO, + " OPUS_SET_FORCE_CHANNELS ...................... OK.\n", + " OPUS_GET_FORCE_CHANNELS ...................... OK.\n") + + i=-2; + if(opus_encoder_ctl(enc,OPUS_SET_BANDWIDTH(i))==OPUS_OK)test_failed(); + cfgs++; + i=OPUS_BANDWIDTH_FULLBAND+1; + if(opus_encoder_ctl(enc,OPUS_SET_BANDWIDTH(i))==OPUS_OK)test_failed(); + cfgs++; + i=OPUS_BANDWIDTH_NARROWBAND; + if(opus_encoder_ctl(enc,OPUS_SET_BANDWIDTH(i))!=OPUS_OK)test_failed(); + cfgs++; + i=OPUS_BANDWIDTH_FULLBAND; + if(opus_encoder_ctl(enc,OPUS_SET_BANDWIDTH(i))!=OPUS_OK)test_failed(); + cfgs++; + i=OPUS_BANDWIDTH_WIDEBAND; + if(opus_encoder_ctl(enc,OPUS_SET_BANDWIDTH(i))!=OPUS_OK)test_failed(); + cfgs++; + i=OPUS_BANDWIDTH_MEDIUMBAND; + if(opus_encoder_ctl(enc,OPUS_SET_BANDWIDTH(i))!=OPUS_OK)test_failed(); + cfgs++; + fprintf(stdout," OPUS_SET_BANDWIDTH ........................... OK.\n"); + /*We don't test if the bandwidth has actually changed. + because the change may be delayed until the encoder is advanced.*/ + i=-12345; + VG_UNDEF(&i,sizeof(i)); + err=opus_encoder_ctl(enc,OPUS_GET_BANDWIDTH(&i)); + if(err!=OPUS_OK || (i!=OPUS_BANDWIDTH_NARROWBAND&& + i!=OPUS_BANDWIDTH_MEDIUMBAND&&i!=OPUS_BANDWIDTH_WIDEBAND&& + i!=OPUS_BANDWIDTH_FULLBAND&&i!=OPUS_AUTO))test_failed(); + cfgs++; + if(opus_encoder_ctl(enc,OPUS_SET_BANDWIDTH(OPUS_AUTO))!=OPUS_OK)test_failed(); + cfgs++; + err=opus_encoder_ctl(enc,OPUS_GET_BANDWIDTH(null_int_ptr)); + if(err!=OPUS_BAD_ARG)test_failed(); + cfgs++; + fprintf(stdout," OPUS_GET_BANDWIDTH ........................... OK.\n"); + + i=-2; + if(opus_encoder_ctl(enc,OPUS_SET_MAX_BANDWIDTH(i))==OPUS_OK)test_failed(); + cfgs++; + i=OPUS_BANDWIDTH_FULLBAND+1; + if(opus_encoder_ctl(enc,OPUS_SET_MAX_BANDWIDTH(i))==OPUS_OK)test_failed(); + cfgs++; + i=OPUS_BANDWIDTH_NARROWBAND; + if(opus_encoder_ctl(enc,OPUS_SET_MAX_BANDWIDTH(i))!=OPUS_OK)test_failed(); + cfgs++; + i=OPUS_BANDWIDTH_FULLBAND; + if(opus_encoder_ctl(enc,OPUS_SET_MAX_BANDWIDTH(i))!=OPUS_OK)test_failed(); + cfgs++; + i=OPUS_BANDWIDTH_WIDEBAND; + if(opus_encoder_ctl(enc,OPUS_SET_MAX_BANDWIDTH(i))!=OPUS_OK)test_failed(); + cfgs++; + i=OPUS_BANDWIDTH_MEDIUMBAND; + if(opus_encoder_ctl(enc,OPUS_SET_MAX_BANDWIDTH(i))!=OPUS_OK)test_failed(); + cfgs++; + fprintf(stdout," OPUS_SET_MAX_BANDWIDTH ....................... OK.\n"); + /*We don't test if the bandwidth has actually changed. + because the change may be delayed until the encoder is advanced.*/ + i=-12345; + VG_UNDEF(&i,sizeof(i)); + err=opus_encoder_ctl(enc,OPUS_GET_MAX_BANDWIDTH(&i)); + if(err!=OPUS_OK || (i!=OPUS_BANDWIDTH_NARROWBAND&& + i!=OPUS_BANDWIDTH_MEDIUMBAND&&i!=OPUS_BANDWIDTH_WIDEBAND&& + i!=OPUS_BANDWIDTH_FULLBAND))test_failed(); + cfgs++; + err=opus_encoder_ctl(enc,OPUS_GET_MAX_BANDWIDTH(null_int_ptr)); + if(err!=OPUS_BAD_ARG)test_failed(); + cfgs++; + fprintf(stdout," OPUS_GET_MAX_BANDWIDTH ....................... OK.\n"); + + err=opus_encoder_ctl(enc,OPUS_GET_DTX(null_int_ptr)); + if(err!=OPUS_BAD_ARG)test_failed(); + cfgs++; + CHECK_SETGET(OPUS_SET_DTX(i),OPUS_GET_DTX(&i),-1,2, + 1,0, + " OPUS_SET_DTX ................................. OK.\n", + " OPUS_GET_DTX ................................. OK.\n") + + err=opus_encoder_ctl(enc,OPUS_GET_COMPLEXITY(null_int_ptr)); + if(err!=OPUS_BAD_ARG)test_failed(); + cfgs++; + CHECK_SETGET(OPUS_SET_COMPLEXITY(i),OPUS_GET_COMPLEXITY(&i),-1,11, + 0,10, + " OPUS_SET_COMPLEXITY .......................... OK.\n", + " OPUS_GET_COMPLEXITY .......................... OK.\n") + + err=opus_encoder_ctl(enc,OPUS_GET_INBAND_FEC(null_int_ptr)); + if(err!=OPUS_BAD_ARG)test_failed(); + cfgs++; + CHECK_SETGET(OPUS_SET_INBAND_FEC(i),OPUS_GET_INBAND_FEC(&i),-1,2, + 1,0, + " OPUS_SET_INBAND_FEC .......................... OK.\n", + " OPUS_GET_INBAND_FEC .......................... OK.\n") + + err=opus_encoder_ctl(enc,OPUS_GET_PACKET_LOSS_PERC(null_int_ptr)); + if(err!=OPUS_BAD_ARG)test_failed(); + cfgs++; + CHECK_SETGET(OPUS_SET_PACKET_LOSS_PERC(i),OPUS_GET_PACKET_LOSS_PERC(&i),-1,101, + 100,0, + " OPUS_SET_PACKET_LOSS_PERC .................... OK.\n", + " OPUS_GET_PACKET_LOSS_PERC .................... OK.\n") + + err=opus_encoder_ctl(enc,OPUS_GET_VBR(null_int_ptr)); + if(err!=OPUS_BAD_ARG)test_failed(); + cfgs++; + CHECK_SETGET(OPUS_SET_VBR(i),OPUS_GET_VBR(&i),-1,2, + 1,0, + " OPUS_SET_VBR ................................. OK.\n", + " OPUS_GET_VBR ................................. OK.\n") + +/* err=opus_encoder_ctl(enc,OPUS_GET_VOICE_RATIO(null_int_ptr)); + if(err!=OPUS_BAD_ARG)test_failed(); + cfgs++; + CHECK_SETGET(OPUS_SET_VOICE_RATIO(i),OPUS_GET_VOICE_RATIO(&i),-2,101, + 0,50, + " OPUS_SET_VOICE_RATIO ......................... OK.\n", + " OPUS_GET_VOICE_RATIO ......................... OK.\n")*/ + + err=opus_encoder_ctl(enc,OPUS_GET_VBR_CONSTRAINT(null_int_ptr)); + if(err!=OPUS_BAD_ARG)test_failed(); + cfgs++; + CHECK_SETGET(OPUS_SET_VBR_CONSTRAINT(i),OPUS_GET_VBR_CONSTRAINT(&i),-1,2, + 1,0, + " OPUS_SET_VBR_CONSTRAINT ...................... OK.\n", + " OPUS_GET_VBR_CONSTRAINT ...................... OK.\n") + + err=opus_encoder_ctl(enc,OPUS_GET_SIGNAL(null_int_ptr)); + if(err!=OPUS_BAD_ARG)test_failed(); + cfgs++; + CHECK_SETGET(OPUS_SET_SIGNAL(i),OPUS_GET_SIGNAL(&i),-12345,0x7FFFFFFF, + OPUS_SIGNAL_MUSIC,OPUS_AUTO, + " OPUS_SET_SIGNAL .............................. OK.\n", + " OPUS_GET_SIGNAL .............................. OK.\n") + + err=opus_encoder_ctl(enc,OPUS_GET_LSB_DEPTH(null_int_ptr)); + if(err!=OPUS_BAD_ARG)test_failed(); + cfgs++; + CHECK_SETGET(OPUS_SET_LSB_DEPTH(i),OPUS_GET_LSB_DEPTH(&i),7,25,16,24, + " OPUS_SET_LSB_DEPTH ........................... OK.\n", + " OPUS_GET_LSB_DEPTH ........................... OK.\n") + + err=opus_encoder_ctl(enc,OPUS_GET_PREDICTION_DISABLED(&i)); + if(i!=0)test_failed(); + cfgs++; + err=opus_encoder_ctl(enc,OPUS_GET_PREDICTION_DISABLED(null_int_ptr)); + if(err!=OPUS_BAD_ARG)test_failed(); + cfgs++; + CHECK_SETGET(OPUS_SET_PREDICTION_DISABLED(i),OPUS_GET_PREDICTION_DISABLED(&i),-1,2,1,0, + " OPUS_SET_PREDICTION_DISABLED ................. OK.\n", + " OPUS_GET_PREDICTION_DISABLED ................. OK.\n") + + err=opus_encoder_ctl(enc,OPUS_GET_EXPERT_FRAME_DURATION(null_int_ptr)); + if(err!=OPUS_BAD_ARG)test_failed(); + cfgs++; + err=opus_encoder_ctl(enc,OPUS_SET_EXPERT_FRAME_DURATION(OPUS_FRAMESIZE_2_5_MS)); + if(err!=OPUS_OK)test_failed(); + cfgs++; + err=opus_encoder_ctl(enc,OPUS_SET_EXPERT_FRAME_DURATION(OPUS_FRAMESIZE_5_MS)); + if(err!=OPUS_OK)test_failed(); + cfgs++; + err=opus_encoder_ctl(enc,OPUS_SET_EXPERT_FRAME_DURATION(OPUS_FRAMESIZE_10_MS)); + if(err!=OPUS_OK)test_failed(); + cfgs++; + err=opus_encoder_ctl(enc,OPUS_SET_EXPERT_FRAME_DURATION(OPUS_FRAMESIZE_20_MS)); + if(err!=OPUS_OK)test_failed(); + cfgs++; + err=opus_encoder_ctl(enc,OPUS_SET_EXPERT_FRAME_DURATION(OPUS_FRAMESIZE_40_MS)); + if(err!=OPUS_OK)test_failed(); + cfgs++; + err=opus_encoder_ctl(enc,OPUS_SET_EXPERT_FRAME_DURATION(OPUS_FRAMESIZE_60_MS)); + if(err!=OPUS_OK)test_failed(); + cfgs++; + err=opus_encoder_ctl(enc,OPUS_SET_EXPERT_FRAME_DURATION(OPUS_FRAMESIZE_80_MS)); + if(err!=OPUS_OK)test_failed(); + cfgs++; + err=opus_encoder_ctl(enc,OPUS_SET_EXPERT_FRAME_DURATION(OPUS_FRAMESIZE_100_MS)); + if(err!=OPUS_OK)test_failed(); + cfgs++; + err=opus_encoder_ctl(enc,OPUS_SET_EXPERT_FRAME_DURATION(OPUS_FRAMESIZE_120_MS)); + if(err!=OPUS_OK)test_failed(); + cfgs++; + CHECK_SETGET(OPUS_SET_EXPERT_FRAME_DURATION(i),OPUS_GET_EXPERT_FRAME_DURATION(&i),0,-1, + OPUS_FRAMESIZE_60_MS,OPUS_FRAMESIZE_ARG, + " OPUS_SET_EXPERT_FRAME_DURATION ............... OK.\n", + " OPUS_GET_EXPERT_FRAME_DURATION ............... OK.\n") + + /*OPUS_SET_FORCE_MODE is not tested here because it's not a public API, however the encoder tests use it*/ + + err=opus_encoder_ctl(enc,OPUS_GET_FINAL_RANGE(null_uint_ptr)); + if(err!=OPUS_BAD_ARG)test_failed(); + cfgs++; + if(opus_encoder_ctl(enc,OPUS_GET_FINAL_RANGE(&enc_final_range))!=OPUS_OK)test_failed(); + cfgs++; + fprintf(stdout," OPUS_GET_FINAL_RANGE ......................... OK.\n"); + + /*Reset the encoder*/ + if(opus_encoder_ctl(enc, OPUS_RESET_STATE)!=OPUS_OK)test_failed(); + cfgs++; + fprintf(stdout," OPUS_RESET_STATE ............................. OK.\n"); + + memset(sbuf,0,sizeof(short)*2*960); + VG_UNDEF(packet,sizeof(packet)); + i=opus_encode(enc, sbuf, 960, packet, sizeof(packet)); + if(i<1 || (i>(opus_int32)sizeof(packet)))test_failed(); + VG_CHECK(packet,i); + cfgs++; + fprintf(stdout," opus_encode() ................................ OK.\n"); +#ifndef DISABLE_FLOAT_API + memset(fbuf,0,sizeof(float)*2*960); + VG_UNDEF(packet,sizeof(packet)); + i=opus_encode_float(enc, fbuf, 960, packet, sizeof(packet)); + if(i<1 || (i>(opus_int32)sizeof(packet)))test_failed(); + VG_CHECK(packet,i); + cfgs++; + fprintf(stdout," opus_encode_float() .......................... OK.\n"); +#endif + +#if 0 + /*These tests are disabled because the library crashes with null states*/ + if(opus_encoder_ctl(0,OPUS_RESET_STATE) !=OPUS_INVALID_STATE)test_failed(); + if(opus_encoder_init(0,48000,1,OPUS_APPLICATION_VOIP) !=OPUS_INVALID_STATE)test_failed(); + if(opus_encode(0,sbuf,960,packet,sizeof(packet)) !=OPUS_INVALID_STATE)test_failed(); + if(opus_encode_float(0,fbuf,960,packet,sizeof(packet))!=OPUS_INVALID_STATE)test_failed(); +#endif + opus_encoder_destroy(enc); + cfgs++; + fprintf(stdout," All encoder interface tests passed\n"); + fprintf(stdout," (%d API invocations)\n",cfgs); + return cfgs; +} + +#define max_out (1276*48+48*2+2) +int test_repacketizer_api(void) +{ + int ret,cfgs,i,j,k; + OpusRepacketizer *rp; + unsigned char *packet; + unsigned char *po; + cfgs=0; + fprintf(stdout,"\n Repacketizer tests\n"); + fprintf(stdout," ---------------------------------------------------\n"); + + packet=malloc(max_out); + if(packet==NULL)test_failed(); + memset(packet,0,max_out); + po=malloc(max_out+256); + if(po==NULL)test_failed(); + + i=opus_repacketizer_get_size(); + if(i<=0)test_failed(); + cfgs++; + fprintf(stdout," opus_repacketizer_get_size()=%d ............. OK.\n",i); + + rp=malloc(i); + rp=opus_repacketizer_init(rp); + if(rp==NULL)test_failed(); + cfgs++; + free(rp); + fprintf(stdout," opus_repacketizer_init ....................... OK.\n"); + + rp=opus_repacketizer_create(); + if(rp==NULL)test_failed(); + cfgs++; + fprintf(stdout," opus_repacketizer_create ..................... OK.\n"); + + if(opus_repacketizer_get_nb_frames(rp)!=0)test_failed(); + cfgs++; + fprintf(stdout," opus_repacketizer_get_nb_frames .............. OK.\n"); + + /*Length overflows*/ + VG_UNDEF(packet,4); + if(opus_repacketizer_cat(rp,packet,0)!=OPUS_INVALID_PACKET)test_failed(); /* Zero len */ + cfgs++; + packet[0]=1; + if(opus_repacketizer_cat(rp,packet,2)!=OPUS_INVALID_PACKET)test_failed(); /* Odd payload code 1 */ + cfgs++; + packet[0]=2; + if(opus_repacketizer_cat(rp,packet,1)!=OPUS_INVALID_PACKET)test_failed(); /* Code 2 overflow one */ + cfgs++; + packet[0]=3; + if(opus_repacketizer_cat(rp,packet,1)!=OPUS_INVALID_PACKET)test_failed(); /* Code 3 no count */ + cfgs++; + packet[0]=2; + packet[1]=255; + if(opus_repacketizer_cat(rp,packet,2)!=OPUS_INVALID_PACKET)test_failed(); /* Code 2 overflow two */ + cfgs++; + packet[0]=2; + packet[1]=250; + if(opus_repacketizer_cat(rp,packet,251)!=OPUS_INVALID_PACKET)test_failed(); /* Code 2 overflow three */ + cfgs++; + packet[0]=3; + packet[1]=0; + if(opus_repacketizer_cat(rp,packet,2)!=OPUS_INVALID_PACKET)test_failed(); /* Code 3 m=0 */ + cfgs++; + packet[1]=49; + if(opus_repacketizer_cat(rp,packet,100)!=OPUS_INVALID_PACKET)test_failed(); /* Code 3 m=49 */ + cfgs++; + packet[0]=0; + if(opus_repacketizer_cat(rp,packet,3)!=OPUS_OK)test_failed(); + cfgs++; + packet[0]=1<<2; + if(opus_repacketizer_cat(rp,packet,3)!=OPUS_INVALID_PACKET)test_failed(); /* Change in TOC */ + cfgs++; + + /* Code 0,1,3 CBR -> Code 0,1,3 CBR */ + opus_repacketizer_init(rp); + for(j=0;j<32;j++) + { + /* TOC types, test half with stereo */ + int maxi; + packet[0]=((j<<1)+(j&1))<<2; + maxi=960/opus_packet_get_samples_per_frame(packet,8000); + for(i=1;i<=maxi;i++) + { + /* Number of CBR frames in the input packets */ + int maxp; + packet[0]=((j<<1)+(j&1))<<2; + if(i>1)packet[0]+=i==2?1:3; + packet[1]=i>2?i:0; + maxp=960/(i*opus_packet_get_samples_per_frame(packet,8000)); + for(k=0;k<=(1275+75);k+=3) + { + /*Payload size*/ + opus_int32 cnt,rcnt; + if(k%i!=0)continue; /* Only testing CBR here, payload must be a multiple of the count */ + for(cnt=0;cnt0) + { + ret=opus_repacketizer_cat(rp,packet,k+(i>2?2:1)); + if((cnt<=maxp&&k<=(1275*i))?ret!=OPUS_OK:ret!=OPUS_INVALID_PACKET)test_failed(); + cfgs++; + } + rcnt=k<=(1275*i)?(cnt0) + { + int len; + len=k*rcnt+((rcnt*i)>2?2:1); + if(ret!=len)test_failed(); + if((rcnt*i)<2&&(po[0]&3)!=0)test_failed(); /* Code 0 */ + if((rcnt*i)==2&&(po[0]&3)!=1)test_failed(); /* Code 1 */ + if((rcnt*i)>2&&(((po[0]&3)!=3)||(po[1]!=rcnt*i)))test_failed(); /* Code 3 CBR */ + cfgs++; + if(opus_repacketizer_out(rp,po,len)!=len)test_failed(); + cfgs++; + if(opus_packet_unpad(po,len)!=len)test_failed(); + cfgs++; + if(opus_packet_pad(po,len,len+1)!=OPUS_OK)test_failed(); + cfgs++; + if(opus_packet_pad(po,len+1,len+256)!=OPUS_OK)test_failed(); + cfgs++; + if(opus_packet_unpad(po,len+256)!=len)test_failed(); + cfgs++; + if(opus_multistream_packet_unpad(po,len,1)!=len)test_failed(); + cfgs++; + if(opus_multistream_packet_pad(po,len,len+1,1)!=OPUS_OK)test_failed(); + cfgs++; + if(opus_multistream_packet_pad(po,len+1,len+256,1)!=OPUS_OK)test_failed(); + cfgs++; + if(opus_multistream_packet_unpad(po,len+256,1)!=len)test_failed(); + cfgs++; + if(opus_repacketizer_out(rp,po,len-1)!=OPUS_BUFFER_TOO_SMALL)test_failed(); + cfgs++; + if(len>1) + { + if(opus_repacketizer_out(rp,po,1)!=OPUS_BUFFER_TOO_SMALL)test_failed(); + cfgs++; + } + if(opus_repacketizer_out(rp,po,0)!=OPUS_BUFFER_TOO_SMALL)test_failed(); + cfgs++; + } else if (ret!=OPUS_BAD_ARG)test_failed(); /* M must not be 0 */ + } + opus_repacketizer_init(rp); + } + } + } + + /*Change in input count code, CBR out*/ + opus_repacketizer_init(rp); + packet[0]=0; + if(opus_repacketizer_cat(rp,packet,5)!=OPUS_OK)test_failed(); + cfgs++; + packet[0]+=1; + if(opus_repacketizer_cat(rp,packet,9)!=OPUS_OK)test_failed(); + cfgs++; + i=opus_repacketizer_out(rp,po,max_out); + if((i!=(4+8+2))||((po[0]&3)!=3)||((po[1]&63)!=3)||((po[1]>>7)!=0))test_failed(); + cfgs++; + i=opus_repacketizer_out_range(rp,0,1,po,max_out); + if(i!=5||(po[0]&3)!=0)test_failed(); + cfgs++; + i=opus_repacketizer_out_range(rp,1,2,po,max_out); + if(i!=5||(po[0]&3)!=0)test_failed(); + cfgs++; + + /*Change in input count code, VBR out*/ + opus_repacketizer_init(rp); + packet[0]=1; + if(opus_repacketizer_cat(rp,packet,9)!=OPUS_OK)test_failed(); + cfgs++; + packet[0]=0; + if(opus_repacketizer_cat(rp,packet,3)!=OPUS_OK)test_failed(); + cfgs++; + i=opus_repacketizer_out(rp,po,max_out); + if((i!=(2+8+2+2))||((po[0]&3)!=3)||((po[1]&63)!=3)||((po[1]>>7)!=1))test_failed(); + cfgs++; + + /*VBR in, VBR out*/ + opus_repacketizer_init(rp); + packet[0]=2; + packet[1]=4; + if(opus_repacketizer_cat(rp,packet,8)!=OPUS_OK)test_failed(); + cfgs++; + if(opus_repacketizer_cat(rp,packet,8)!=OPUS_OK)test_failed(); + cfgs++; + i=opus_repacketizer_out(rp,po,max_out); + if((i!=(2+1+1+1+4+2+4+2))||((po[0]&3)!=3)||((po[1]&63)!=4)||((po[1]>>7)!=1))test_failed(); + cfgs++; + + /*VBR in, CBR out*/ + opus_repacketizer_init(rp); + packet[0]=2; + packet[1]=4; + if(opus_repacketizer_cat(rp,packet,10)!=OPUS_OK)test_failed(); + cfgs++; + if(opus_repacketizer_cat(rp,packet,10)!=OPUS_OK)test_failed(); + cfgs++; + i=opus_repacketizer_out(rp,po,max_out); + if((i!=(2+4+4+4+4))||((po[0]&3)!=3)||((po[1]&63)!=4)||((po[1]>>7)!=0))test_failed(); + cfgs++; + + /*Count 0 in, VBR out*/ + for(j=0;j<32;j++) + { + /* TOC types, test half with stereo */ + int maxi,sum,rcnt; + packet[0]=((j<<1)+(j&1))<<2; + maxi=960/opus_packet_get_samples_per_frame(packet,8000); + sum=0; + rcnt=0; + opus_repacketizer_init(rp); + for(i=1;i<=maxi+2;i++) + { + int len; + ret=opus_repacketizer_cat(rp,packet,i); + if(rcnt2&&(po[1]&63)!=rcnt)test_failed(); + if(rcnt==2&&(po[0]&3)!=2)test_failed(); + if(rcnt==1&&(po[0]&3)!=0)test_failed(); + cfgs++; + if(opus_repacketizer_out(rp,po,len)!=len)test_failed(); + cfgs++; + if(opus_packet_unpad(po,len)!=len)test_failed(); + cfgs++; + if(opus_packet_pad(po,len,len+1)!=OPUS_OK)test_failed(); + cfgs++; + if(opus_packet_pad(po,len+1,len+256)!=OPUS_OK)test_failed(); + cfgs++; + if(opus_packet_unpad(po,len+256)!=len)test_failed(); + cfgs++; + if(opus_multistream_packet_unpad(po,len,1)!=len)test_failed(); + cfgs++; + if(opus_multistream_packet_pad(po,len,len+1,1)!=OPUS_OK)test_failed(); + cfgs++; + if(opus_multistream_packet_pad(po,len+1,len+256,1)!=OPUS_OK)test_failed(); + cfgs++; + if(opus_multistream_packet_unpad(po,len+256,1)!=len)test_failed(); + cfgs++; + if(opus_repacketizer_out(rp,po,len-1)!=OPUS_BUFFER_TOO_SMALL)test_failed(); + cfgs++; + if(len>1) + { + if(opus_repacketizer_out(rp,po,1)!=OPUS_BUFFER_TOO_SMALL)test_failed(); + cfgs++; + } + if(opus_repacketizer_out(rp,po,0)!=OPUS_BUFFER_TOO_SMALL)test_failed(); + cfgs++; + } + } + + po[0]='O'; + po[1]='p'; + if(opus_packet_pad(po,4,4)!=OPUS_OK)test_failed(); + cfgs++; + if(opus_multistream_packet_pad(po,4,4,1)!=OPUS_OK)test_failed(); + cfgs++; + if(opus_packet_pad(po,4,5)!=OPUS_INVALID_PACKET)test_failed(); + cfgs++; + if(opus_multistream_packet_pad(po,4,5,1)!=OPUS_INVALID_PACKET)test_failed(); + cfgs++; + if(opus_packet_pad(po,0,5)!=OPUS_BAD_ARG)test_failed(); + cfgs++; + if(opus_multistream_packet_pad(po,0,5,1)!=OPUS_BAD_ARG)test_failed(); + cfgs++; + if(opus_packet_unpad(po,0)!=OPUS_BAD_ARG)test_failed(); + cfgs++; + if(opus_multistream_packet_unpad(po,0,1)!=OPUS_BAD_ARG)test_failed(); + cfgs++; + if(opus_packet_unpad(po,4)!=OPUS_INVALID_PACKET)test_failed(); + cfgs++; + if(opus_multistream_packet_unpad(po,4,1)!=OPUS_INVALID_PACKET)test_failed(); + cfgs++; + po[0]=0; + po[1]=0; + po[2]=0; + if(opus_packet_pad(po,5,4)!=OPUS_BAD_ARG)test_failed(); + cfgs++; + if(opus_multistream_packet_pad(po,5,4,1)!=OPUS_BAD_ARG)test_failed(); + cfgs++; + + fprintf(stdout," opus_repacketizer_cat ........................ OK.\n"); + fprintf(stdout," opus_repacketizer_out ........................ OK.\n"); + fprintf(stdout," opus_repacketizer_out_range .................. OK.\n"); + fprintf(stdout," opus_packet_pad .............................. OK.\n"); + fprintf(stdout," opus_packet_unpad ............................ OK.\n"); + fprintf(stdout," opus_multistream_packet_pad .................. OK.\n"); + fprintf(stdout," opus_multistream_packet_unpad ................ OK.\n"); + + opus_repacketizer_destroy(rp); + cfgs++; + free(packet); + free(po); + fprintf(stdout," All repacketizer tests passed\n"); + fprintf(stdout," (%7d API invocations)\n",cfgs); + + return cfgs; +} + +#ifdef MALLOC_FAIL +/* GLIBC 2.14 declares __malloc_hook as deprecated, generating a warning + * under GCC. However, this is the cleanest way to test malloc failure + * handling in our codebase, and the lack of thread safety isn't an + * issue here. We therefore disable the warning for this function. + */ +#if OPUS_GNUC_PREREQ(4,6) +/* Save the current warning settings */ +#pragma GCC diagnostic push +#endif +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" + +typedef void *(*mhook)(size_t __size, __const void *); +#endif + +int test_malloc_fail(void) +{ +#ifdef MALLOC_FAIL + OpusDecoder *dec; + OpusEncoder *enc; + OpusRepacketizer *rp; + unsigned char mapping[256] = {0,1}; + OpusMSDecoder *msdec; + OpusMSEncoder *msenc; + int rate,c,app,cfgs,err,useerr; + int *ep; + mhook orig_malloc; + cfgs=0; +#endif + fprintf(stdout,"\n malloc() failure tests\n"); + fprintf(stdout," ---------------------------------------------------\n"); +#ifdef MALLOC_FAIL + orig_malloc=__malloc_hook; + __malloc_hook=malloc_hook; + ep=(int *)opus_alloc(sizeof(int)); + if(ep!=NULL) + { + if(ep)free(ep); + __malloc_hook=orig_malloc; +#endif + fprintf(stdout," opus_decoder_create() ................... SKIPPED.\n"); + fprintf(stdout," opus_encoder_create() ................... SKIPPED.\n"); + fprintf(stdout," opus_repacketizer_create() .............. SKIPPED.\n"); + fprintf(stdout," opus_multistream_decoder_create() ....... SKIPPED.\n"); + fprintf(stdout," opus_multistream_encoder_create() ....... SKIPPED.\n"); + fprintf(stdout,"(Test only supported with GLIBC and without valgrind)\n"); + return 0; +#ifdef MALLOC_FAIL + } + for(useerr=0;useerr<2;useerr++) + { + ep=useerr?&err:0; + for(rate=0;rate<5;rate++) + { + for(c=1;c<3;c++) + { + err=1; + if(useerr) + { + VG_UNDEF(&err,sizeof(err)); + } + dec=opus_decoder_create(opus_rates[rate], c, ep); + if(dec!=NULL||(useerr&&err!=OPUS_ALLOC_FAIL)) + { + __malloc_hook=orig_malloc; + test_failed(); + } + cfgs++; + msdec=opus_multistream_decoder_create(opus_rates[rate], c, 1, c-1, mapping, ep); + if(msdec!=NULL||(useerr&&err!=OPUS_ALLOC_FAIL)) + { + __malloc_hook=orig_malloc; + test_failed(); + } + cfgs++; + for(app=0;app<3;app++) + { + if(useerr) + { + VG_UNDEF(&err,sizeof(err)); + } + enc=opus_encoder_create(opus_rates[rate], c, opus_apps[app],ep); + if(enc!=NULL||(useerr&&err!=OPUS_ALLOC_FAIL)) + { + __malloc_hook=orig_malloc; + test_failed(); + } + cfgs++; + msenc=opus_multistream_encoder_create(opus_rates[rate], c, 1, c-1, mapping, opus_apps[app],ep); + if(msenc!=NULL||(useerr&&err!=OPUS_ALLOC_FAIL)) + { + __malloc_hook=orig_malloc; + test_failed(); + } + cfgs++; + } + } + } + } + rp=opus_repacketizer_create(); + if(rp!=NULL) + { + __malloc_hook=orig_malloc; + test_failed(); + } + cfgs++; + __malloc_hook=orig_malloc; + fprintf(stdout," opus_decoder_create() ........................ OK.\n"); + fprintf(stdout," opus_encoder_create() ........................ OK.\n"); + fprintf(stdout," opus_repacketizer_create() ................... OK.\n"); + fprintf(stdout," opus_multistream_decoder_create() ............ OK.\n"); + fprintf(stdout," opus_multistream_encoder_create() ............ OK.\n"); + fprintf(stdout," All malloc failure tests passed\n"); + fprintf(stdout," (%2d API invocations)\n",cfgs); + return cfgs; +#endif +} + +#ifdef MALLOC_FAIL +#if __GNUC_PREREQ(4,6) +#pragma GCC diagnostic pop /* restore -Wdeprecated-declarations */ +#endif +#endif + +int main(int _argc, char **_argv) +{ + opus_int32 total; + const char * oversion; + if(_argc>1) + { + fprintf(stderr,"Usage: %s\n",_argv[0]); + return 1; + } + iseed=0; + + oversion=opus_get_version_string(); + if(!oversion)test_failed(); + fprintf(stderr,"Testing the %s API deterministically\n", oversion); + if(opus_strerror(-32768)==NULL)test_failed(); + if(opus_strerror(32767)==NULL)test_failed(); + if(strlen(opus_strerror(0))<1)test_failed(); + total=4; + + total+=test_dec_api(); + total+=test_msdec_api(); + total+=test_parse(); + total+=test_enc_api(); + total+=test_repacketizer_api(); + total+=test_malloc_fail(); + + fprintf(stderr,"\nAll API tests passed.\nThe libopus API was invoked %d times.\n",total); + + return 0; +} diff --git a/extern/opus/tests/test_opus_common.h b/extern/opus/tests/test_opus_common.h new file mode 100644 index 0000000..235cf1c --- /dev/null +++ b/extern/opus/tests/test_opus_common.h @@ -0,0 +1,82 @@ +/* Copyright (c) 2011 Xiph.Org Foundation + Written by Gregory Maxwell */ +/* + 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. + + 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 OWNER + 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. +*/ + +static OPUS_INLINE void deb2_impl(unsigned char *_t,unsigned char **_p,int _k,int _x,int _y) +{ + int i; + if(_x>2){ + if(_y<3)for(i=0;i<_y;i++)*(--*_p)=_t[i+1]; + }else{ + _t[_x]=_t[_x-_y]; + deb2_impl(_t,_p,_k,_x+1,_y); + for(i=_t[_x-_y]+1;i<_k;i++){ + _t[_x]=i; + deb2_impl(_t,_p,_k,_x+1,_x); + } + } +} + +/*Generates a De Bruijn sequence (k,2) with length k^2*/ +static OPUS_INLINE void debruijn2(int _k, unsigned char *_res) +{ + unsigned char *p; + unsigned char *t; + t=malloc(sizeof(unsigned char)*_k*2); + memset(t,0,sizeof(unsigned char)*_k*2); + p=&_res[_k*_k]; + deb2_impl(t,&p,_k,1,1); + free(t); +} + +/*MWC RNG of George Marsaglia*/ +static opus_uint32 Rz, Rw; +static OPUS_INLINE opus_uint32 fast_rand(void) +{ + Rz=36969*(Rz&65535)+(Rz>>16); + Rw=18000*(Rw&65535)+(Rw>>16); + return (Rz<<16)+Rw; +} +static opus_uint32 iseed; + +#ifdef __GNUC__ +__attribute__((noreturn)) +#elif defined(_MSC_VER) +__declspec(noreturn) +#endif +static OPUS_INLINE void _test_failed(const char *file, int line) +{ + fprintf(stderr,"\n ***************************************************\n"); + fprintf(stderr," *** A fatal error was detected. ***\n"); + fprintf(stderr," ***************************************************\n"); + fprintf(stderr,"Please report this failure and include\n"); + fprintf(stderr,"'make check SEED=%u fails %s at line %d for %s'\n",iseed,file,line,opus_get_version_string()); + fprintf(stderr,"and any relevant details about your system.\n\n"); + abort(); +} +#define test_failed() _test_failed(__FILE__, __LINE__); + +void regression_test(void); diff --git a/extern/opus/tests/test_opus_decode.c b/extern/opus/tests/test_opus_decode.c new file mode 100644 index 0000000..5197fa1 --- /dev/null +++ b/extern/opus/tests/test_opus_decode.c @@ -0,0 +1,463 @@ +/* Copyright (c) 2011-2013 Xiph.Org Foundation + Written by Gregory Maxwell */ +/* + 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. + + 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 OWNER + 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. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include +#include +#include +#if (!defined WIN32 && !defined _WIN32) || defined(__MINGW32__) +#include +#else +#include +#define getpid _getpid +#endif +#include "opus.h" +#include "test_opus_common.h" + +#define MAX_PACKET (1500) +#define MAX_FRAME_SAMP (5760) + +int test_decoder_code0(int no_fuzz) +{ + static const opus_int32 fsv[5]={48000,24000,16000,12000,8000}; + int err,skip,plen; + int out_samples,fec; + int t; + opus_int32 i; + OpusDecoder *dec[5*2]; + opus_int32 decsize; + OpusDecoder *decbak; + opus_uint32 dec_final_range1,dec_final_range2,dec_final_acc; + unsigned char *packet; + unsigned char modes[4096]; + short *outbuf_int; + short *outbuf; + + dec_final_range1=dec_final_range2=2; + + packet=malloc(sizeof(unsigned char)*MAX_PACKET); + if(packet==NULL)test_failed(); + + outbuf_int=malloc(sizeof(short)*(MAX_FRAME_SAMP+16)*2); + for(i=0;i<(MAX_FRAME_SAMP+16)*2;i++)outbuf_int[i]=32749; + outbuf=&outbuf_int[8*2]; + + fprintf(stdout," Starting %d decoders...\n",5*2); + for(t=0;t<5*2;t++) + { + int fs=fsv[t>>1]; + int c=(t&1)+1; + err=OPUS_INTERNAL_ERROR; + dec[t] = opus_decoder_create(fs, c, &err); + if(err!=OPUS_OK || dec[t]==NULL)test_failed(); + fprintf(stdout," opus_decoder_create(%5d,%d) OK. Copy ",fs,c); + { + OpusDecoder *dec2; + /*The opus state structures contain no pointers and can be freely copied*/ + dec2=(OpusDecoder *)malloc(opus_decoder_get_size(c)); + if(dec2==NULL)test_failed(); + memcpy(dec2,dec[t],opus_decoder_get_size(c)); + memset(dec[t],255,opus_decoder_get_size(c)); + opus_decoder_destroy(dec[t]); + printf("OK.\n"); + dec[t]=dec2; + } + } + + decsize=opus_decoder_get_size(1); + decbak=(OpusDecoder *)malloc(decsize); + if(decbak==NULL)test_failed(); + + for(t=0;t<5*2;t++) + { + int factor=48000/fsv[t>>1]; + for(fec=0;fec<2;fec++) + { + opus_int32 dur; + /*Test PLC on a fresh decoder*/ + out_samples = opus_decode(dec[t], 0, 0, outbuf, 120/factor, fec); + if(out_samples!=120/factor)test_failed(); + if(opus_decoder_ctl(dec[t], OPUS_GET_LAST_PACKET_DURATION(&dur))!=OPUS_OK)test_failed(); + if(dur!=120/factor)test_failed(); + + /*Test on a size which isn't a multiple of 2.5ms*/ + out_samples = opus_decode(dec[t], 0, 0, outbuf, 120/factor+2, fec); + if(out_samples!=OPUS_BAD_ARG)test_failed(); + + /*Test null pointer input*/ + out_samples = opus_decode(dec[t], 0, -1, outbuf, 120/factor, fec); + if(out_samples!=120/factor)test_failed(); + out_samples = opus_decode(dec[t], 0, 1, outbuf, 120/factor, fec); + if(out_samples!=120/factor)test_failed(); + out_samples = opus_decode(dec[t], 0, 10, outbuf, 120/factor, fec); + if(out_samples!=120/factor)test_failed(); + out_samples = opus_decode(dec[t], 0, fast_rand(), outbuf, 120/factor, fec); + if(out_samples!=120/factor)test_failed(); + if(opus_decoder_ctl(dec[t], OPUS_GET_LAST_PACKET_DURATION(&dur))!=OPUS_OK)test_failed(); + if(dur!=120/factor)test_failed(); + + /*Zero lengths*/ + out_samples = opus_decode(dec[t], packet, 0, outbuf, 120/factor, fec); + if(out_samples!=120/factor)test_failed(); + + /*Zero buffer*/ + outbuf[0]=32749; + out_samples = opus_decode(dec[t], packet, 0, outbuf, 0, fec); + if(out_samples>0)test_failed(); +#if !defined(OPUS_BUILD) && (OPUS_GNUC_PREREQ(4, 6) || (defined(__clang_major__) && __clang_major__ >= 3)) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wnonnull" +#endif + out_samples = opus_decode(dec[t], packet, 0, 0, 0, fec); +#if !defined(OPUS_BUILD) && (OPUS_GNUC_PREREQ(4, 6) || (defined(__clang_major__) && __clang_major__ >= 3)) +#pragma GCC diagnostic pop +#endif + if(out_samples>0)test_failed(); + if(outbuf[0]!=32749)test_failed(); + + /*Invalid lengths*/ + out_samples = opus_decode(dec[t], packet, -1, outbuf, MAX_FRAME_SAMP, fec); + if(out_samples>=0)test_failed(); + out_samples = opus_decode(dec[t], packet, INT_MIN, outbuf, MAX_FRAME_SAMP, fec); + if(out_samples>=0)test_failed(); + out_samples = opus_decode(dec[t], packet, -1, outbuf, -1, fec); + if(out_samples>=0)test_failed(); + + /*Crazy FEC values*/ + out_samples = opus_decode(dec[t], packet, 1, outbuf, MAX_FRAME_SAMP, fec?-1:2); + if(out_samples>=0)test_failed(); + + /*Reset the decoder*/ + if(opus_decoder_ctl(dec[t], OPUS_RESET_STATE)!=OPUS_OK)test_failed(); + } + } + fprintf(stdout," dec[all] initial frame PLC OK.\n"); + + /*Count code 0 tests*/ + for(i=0;i<64;i++) + { + opus_int32 dur; + int j,expected[5*2]; + packet[0]=i<<2; + packet[1]=255; + packet[2]=255; + err=opus_packet_get_nb_channels(packet); + if(err!=(i&1)+1)test_failed(); + + for(t=0;t<5*2;t++){ + expected[t]=opus_decoder_get_nb_samples(dec[t],packet,1); + if(expected[t]>2880)test_failed(); + } + + for(j=0;j<256;j++) + { + packet[1]=j; + for(t=0;t<5*2;t++) + { + out_samples = opus_decode(dec[t], packet, 3, outbuf, MAX_FRAME_SAMP, 0); + if(out_samples!=expected[t])test_failed(); + if(opus_decoder_ctl(dec[t], OPUS_GET_LAST_PACKET_DURATION(&dur))!=OPUS_OK)test_failed(); + if(dur!=out_samples)test_failed(); + opus_decoder_ctl(dec[t], OPUS_GET_FINAL_RANGE(&dec_final_range1)); + if(t==0)dec_final_range2=dec_final_range1; + else if(dec_final_range1!=dec_final_range2)test_failed(); + } + } + + for(t=0;t<5*2;t++){ + int factor=48000/fsv[t>>1]; + /* The PLC is run for 6 frames in order to get better PLC coverage. */ + for(j=0;j<6;j++) + { + out_samples = opus_decode(dec[t], 0, 0, outbuf, expected[t], 0); + if(out_samples!=expected[t])test_failed(); + if(opus_decoder_ctl(dec[t], OPUS_GET_LAST_PACKET_DURATION(&dur))!=OPUS_OK)test_failed(); + if(dur!=out_samples)test_failed(); + } + /* Run the PLC once at 2.5ms, as a simulation of someone trying to + do small drift corrections. */ + if(expected[t]!=120/factor) + { + out_samples = opus_decode(dec[t], 0, 0, outbuf, 120/factor, 0); + if(out_samples!=120/factor)test_failed(); + if(opus_decoder_ctl(dec[t], OPUS_GET_LAST_PACKET_DURATION(&dur))!=OPUS_OK)test_failed(); + if(dur!=out_samples)test_failed(); + } + out_samples = opus_decode(dec[t], packet, 2, outbuf, expected[t]-1, 0); + if(out_samples>0)test_failed(); + } + } + fprintf(stdout," dec[all] all 2-byte prefix for length 3 and PLC, all modes (64) OK.\n"); + + if(no_fuzz) + { + fprintf(stdout," Skipping many tests which fuzz the decoder as requested.\n"); + free(decbak); + for(t=0;t<5*2;t++)opus_decoder_destroy(dec[t]); + printf(" Decoders stopped.\n"); + + err=0; + for(i=0;i<8*2;i++)err|=outbuf_int[i]!=32749; + for(i=MAX_FRAME_SAMP*2;i<(MAX_FRAME_SAMP+8)*2;i++)err|=outbuf[i]!=32749; + if(err)test_failed(); + + free(outbuf_int); + free(packet); + return 0; + } + + { + /*We only test a subset of the modes here simply because the longer + durations end up taking a long time.*/ + static const int cmodes[4]={16,20,24,28}; + static const opus_uint32 cres[4]={116290185,2172123586u,2172123586u,2172123586u}; + static const opus_uint32 lres[3]={3285687739u,1481572662,694350475}; + static const int lmodes[3]={0,4,8}; + int mode=fast_rand()%4; + + packet[0]=cmodes[mode]<<3; + dec_final_acc=0; + t=fast_rand()%10; + + for(i=0;i<65536;i++) + { + int factor=48000/fsv[t>>1]; + packet[1]=i>>8; + packet[2]=i&255; + packet[3]=255; + out_samples = opus_decode(dec[t], packet, 4, outbuf, MAX_FRAME_SAMP, 0); + if(out_samples!=120/factor)test_failed(); + opus_decoder_ctl(dec[t], OPUS_GET_FINAL_RANGE(&dec_final_range1)); + dec_final_acc+=dec_final_range1; + } + if(dec_final_acc!=cres[mode])test_failed(); + fprintf(stdout," dec[%3d] all 3-byte prefix for length 4, mode %2d OK.\n",t,cmodes[mode]); + + mode=fast_rand()%3; + packet[0]=lmodes[mode]<<3; + dec_final_acc=0; + t=fast_rand()%10; + for(i=0;i<65536;i++) + { + int factor=48000/fsv[t>>1]; + packet[1]=i>>8; + packet[2]=i&255; + packet[3]=255; + out_samples = opus_decode(dec[t], packet, 4, outbuf, MAX_FRAME_SAMP, 0); + if(out_samples!=480/factor)test_failed(); + opus_decoder_ctl(dec[t], OPUS_GET_FINAL_RANGE(&dec_final_range1)); + dec_final_acc+=dec_final_range1; + } + if(dec_final_acc!=lres[mode])test_failed(); + fprintf(stdout," dec[%3d] all 3-byte prefix for length 4, mode %2d OK.\n",t,lmodes[mode]); + } + + skip=fast_rand()%7; + for(i=0;i<64;i++) + { + int j,expected[5*2]; + packet[0]=i<<2; + for(t=0;t<5*2;t++)expected[t]=opus_decoder_get_nb_samples(dec[t],packet,1); + for(j=2+skip;j<1275;j+=4) + { + int jj; + for(jj=0;jj1.f)test_failed(); + if(x[j]<-1.f)test_failed(); + } + } + for(i=1;i<9;i++) + { + for (j=0;j<1024;j++) + { + x[j]=(j&255)*(1/32.f)-4.f; + } + opus_pcm_soft_clip(x,1024/i,i,s); + for (j=0;j<(1024/i)*i;j++) + { + if(x[j]>1.f)test_failed(); + if(x[j]<-1.f)test_failed(); + } + } + opus_pcm_soft_clip(x,0,1,s); + opus_pcm_soft_clip(x,1,0,s); + opus_pcm_soft_clip(x,1,1,0); + opus_pcm_soft_clip(x,1,-1,s); + opus_pcm_soft_clip(x,-1,1,s); + opus_pcm_soft_clip(0,1,1,s); + printf("OK.\n"); +} +#endif + +int main(int _argc, char **_argv) +{ + const char * oversion; + const char * env_seed; + int env_used; + + if(_argc>2) + { + fprintf(stderr,"Usage: %s []\n",_argv[0]); + return 1; + } + + env_used=0; + env_seed=getenv("SEED"); + if(_argc>1)iseed=atoi(_argv[1]); + else if(env_seed) + { + iseed=atoi(env_seed); + env_used=1; + } + else iseed=(opus_uint32)time(NULL)^(((opus_uint32)getpid()&65535)<<16); + Rw=Rz=iseed; + + oversion=opus_get_version_string(); + if(!oversion)test_failed(); + fprintf(stderr,"Testing %s decoder. Random seed: %u (%.4X)\n", oversion, iseed, fast_rand() % 65535); + if(env_used)fprintf(stderr," Random seed set from the environment (SEED=%s).\n", env_seed); + + /*Setting TEST_OPUS_NOFUZZ tells the tool not to send garbage data + into the decoders. This is helpful because garbage data + may cause the decoders to clip, which angers CLANG IOC.*/ + test_decoder_code0(getenv("TEST_OPUS_NOFUZZ")!=NULL); +#ifndef DISABLE_FLOAT_API + test_soft_clip(); +#endif + + return 0; +} diff --git a/extern/opus/tests/test_opus_encode.c b/extern/opus/tests/test_opus_encode.c new file mode 100644 index 0000000..00795a1 --- /dev/null +++ b/extern/opus/tests/test_opus_encode.c @@ -0,0 +1,703 @@ +/* Copyright (c) 2011-2013 Xiph.Org Foundation + Written by Gregory Maxwell */ +/* + 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. + + 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 OWNER + 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. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include +#include +#include +#if (!defined WIN32 && !defined _WIN32) || defined(__MINGW32__) +#include +#else +#include +#define getpid _getpid +#endif +#include "opus_multistream.h" +#include "opus.h" +#include "../src/opus_private.h" +#include "test_opus_common.h" + +#define MAX_PACKET (1500) +#define SAMPLES (48000*30) +#define SSAMPLES (SAMPLES/3) +#define MAX_FRAME_SAMP (5760) +#define PI (3.141592653589793238462643f) +#define RAND_SAMPLE(a) (a[fast_rand() % sizeof(a)/sizeof(a[0])]) + +void generate_music(short *buf, opus_int32 len) +{ + opus_int32 a1,b1,a2,b2; + opus_int32 c1,c2,d1,d2; + opus_int32 i,j; + a1=b1=a2=b2=0; + c1=c2=d1=d2=0; + j=0; + /*60ms silence*/ + for(i=0;i<2880;i++)buf[i*2]=buf[i*2+1]=0; + for(i=2880;i>12)^((j>>10|j>>12)&26&j>>7)))&128)+128)<<15; + r=fast_rand();v1+=r&65535;v1-=r>>16; + r=fast_rand();v2+=r&65535;v2-=r>>16; + b1=v1-a1+((b1*61+32)>>6);a1=v1; + b2=v2-a2+((b2*61+32)>>6);a2=v2; + c1=(30*(c1+b1+d1)+32)>>6;d1=b1; + c2=(30*(c2+b2+d2)+32)>>6;d2=b2; + v1=(c1+128)>>8; + v2=(c2+128)>>8; + buf[i*2]=v1>32767?32767:(v1<-32768?-32768:v1); + buf[i*2+1]=v2>32767?32767:(v2<-32768?-32768:v2); + if(i%6==0)j++; + } +} + +#if 0 +static int save_ctr = 0; +static void int_to_char(opus_uint32 i, unsigned char ch[4]) +{ + ch[0] = i>>24; + ch[1] = (i>>16)&0xFF; + ch[2] = (i>>8)&0xFF; + ch[3] = i&0xFF; +} + +static OPUS_INLINE void save_packet(unsigned char* p, int len, opus_uint32 rng) +{ + FILE *fout; + unsigned char int_field[4]; + char name[256]; + snprintf(name,255,"test_opus_encode.%llu.%d.bit",(unsigned long long)iseed,save_ctr); + fprintf(stdout,"writing %d byte packet to %s\n",len,name); + fout=fopen(name, "wb+"); + if(fout==NULL)test_failed(); + int_to_char(len, int_field); + fwrite(int_field, 1, 4, fout); + int_to_char(rng, int_field); + fwrite(int_field, 1, 4, fout); + fwrite(p, 1, len, fout); + fclose(fout); + save_ctr++; +} +#endif + +int get_frame_size_enum(int frame_size, int sampling_rate) +{ + int frame_size_enum; + + if(frame_size==sampling_rate/400) + frame_size_enum = OPUS_FRAMESIZE_2_5_MS; + else if(frame_size==sampling_rate/200) + frame_size_enum = OPUS_FRAMESIZE_5_MS; + else if(frame_size==sampling_rate/100) + frame_size_enum = OPUS_FRAMESIZE_10_MS; + else if(frame_size==sampling_rate/50) + frame_size_enum = OPUS_FRAMESIZE_20_MS; + else if(frame_size==sampling_rate/25) + frame_size_enum = OPUS_FRAMESIZE_40_MS; + else if(frame_size==3*sampling_rate/50) + frame_size_enum = OPUS_FRAMESIZE_60_MS; + else if(frame_size==4*sampling_rate/50) + frame_size_enum = OPUS_FRAMESIZE_80_MS; + else if(frame_size==5*sampling_rate/50) + frame_size_enum = OPUS_FRAMESIZE_100_MS; + else if(frame_size==6*sampling_rate/50) + frame_size_enum = OPUS_FRAMESIZE_120_MS; + else + test_failed(); + + return frame_size_enum; +} + +int test_encode(OpusEncoder *enc, int channels, int frame_size, OpusDecoder *dec) +{ + int samp_count = 0; + opus_int16 *inbuf; + unsigned char packet[MAX_PACKET+257]; + int len; + opus_int16 *outbuf; + int out_samples; + int ret = 0; + + /* Generate input data */ + inbuf = (opus_int16*)malloc(sizeof(*inbuf)*SSAMPLES); + generate_music(inbuf, SSAMPLES/2); + + /* Allocate memory for output data */ + outbuf = (opus_int16*)malloc(sizeof(*outbuf)*MAX_FRAME_SAMP*3); + + /* Encode data, then decode for sanity check */ + do { + len = opus_encode(enc, &inbuf[samp_count*channels], frame_size, packet, MAX_PACKET); + if(len<0 || len>MAX_PACKET) { + fprintf(stderr,"opus_encode() returned %d\n",len); + ret = -1; + break; + } + + out_samples = opus_decode(dec, packet, len, outbuf, MAX_FRAME_SAMP, 0); + if(out_samples!=frame_size) { + fprintf(stderr,"opus_decode() returned %d\n",out_samples); + ret = -1; + break; + } + + samp_count += frame_size; + } while (samp_count < ((SSAMPLES/2)-MAX_FRAME_SAMP)); + + /* Clean up */ + free(inbuf); + free(outbuf); + return ret; +} + +void fuzz_encoder_settings(const int num_encoders, const int num_setting_changes) +{ + OpusEncoder *enc; + OpusDecoder *dec; + int i,j,err; + + /* Parameters to fuzz. Some values are duplicated to increase their probability of being tested. */ + int sampling_rates[5] = {8000, 12000, 16000, 24000, 48000}; + int channels[2] = {1, 2}; + int applications[3] = {OPUS_APPLICATION_AUDIO, OPUS_APPLICATION_VOIP, OPUS_APPLICATION_RESTRICTED_LOWDELAY}; + int bitrates[11] = {6000, 12000, 16000, 24000, 32000, 48000, 64000, 96000, 510000, OPUS_AUTO, OPUS_BITRATE_MAX}; + int force_channels[4] = {OPUS_AUTO, OPUS_AUTO, 1, 2}; + int use_vbr[3] = {0, 1, 1}; + int vbr_constraints[3] = {0, 1, 1}; + int complexities[11] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + int max_bandwidths[6] = {OPUS_BANDWIDTH_NARROWBAND, OPUS_BANDWIDTH_MEDIUMBAND, + OPUS_BANDWIDTH_WIDEBAND, OPUS_BANDWIDTH_SUPERWIDEBAND, + OPUS_BANDWIDTH_FULLBAND, OPUS_BANDWIDTH_FULLBAND}; + int signals[4] = {OPUS_AUTO, OPUS_AUTO, OPUS_SIGNAL_VOICE, OPUS_SIGNAL_MUSIC}; + int inband_fecs[3] = {0, 0, 1}; + int packet_loss_perc[4] = {0, 1, 2, 5}; + int lsb_depths[2] = {8, 24}; + int prediction_disabled[3] = {0, 0, 1}; + int use_dtx[2] = {0, 1}; + int frame_sizes_ms_x2[9] = {5, 10, 20, 40, 80, 120, 160, 200, 240}; /* x2 to avoid 2.5 ms */ + + for (i=0; i=64000?2:1)))!=OPUS_OK)test_failed(); + if(opus_encoder_ctl(enc, OPUS_SET_COMPLEXITY((count>>2)%11))!=OPUS_OK)test_failed(); + if(opus_encoder_ctl(enc, OPUS_SET_PACKET_LOSS_PERC((fast_rand()&15)&(fast_rand()%15)))!=OPUS_OK)test_failed(); + bw=modes[j]==0?OPUS_BANDWIDTH_NARROWBAND+(fast_rand()%3): + modes[j]==1?OPUS_BANDWIDTH_SUPERWIDEBAND+(fast_rand()&1): + OPUS_BANDWIDTH_NARROWBAND+(fast_rand()%5); + if(modes[j]==2&&bw==OPUS_BANDWIDTH_MEDIUMBAND)bw+=3; + if(opus_encoder_ctl(enc, OPUS_SET_BANDWIDTH(bw))!=OPUS_OK)test_failed(); + len = opus_encode(enc, &inbuf[i<<1], frame_size, packet, MAX_PACKET); + if(len<0 || len>MAX_PACKET)test_failed(); + if(opus_encoder_ctl(enc, OPUS_GET_FINAL_RANGE(&enc_final_range))!=OPUS_OK)test_failed(); + if((fast_rand()&3)==0) + { + if(opus_packet_pad(packet,len,len+1)!=OPUS_OK)test_failed(); + len++; + } + if((fast_rand()&7)==0) + { + if(opus_packet_pad(packet,len,len+256)!=OPUS_OK)test_failed(); + len+=256; + } + if((fast_rand()&3)==0) + { + len=opus_packet_unpad(packet,len); + if(len<1)test_failed(); + } + out_samples = opus_decode(dec, packet, len, &outbuf[i<<1], MAX_FRAME_SAMP, 0); + if(out_samples!=frame_size)test_failed(); + if(opus_decoder_ctl(dec, OPUS_GET_FINAL_RANGE(&dec_final_range))!=OPUS_OK)test_failed(); + if(enc_final_range!=dec_final_range)test_failed(); + /*LBRR decode*/ + out_samples = opus_decode(dec_err[0], packet, len, out2buf, frame_size, (fast_rand()&3)!=0); + if(out_samples!=frame_size)test_failed(); + out_samples = opus_decode(dec_err[1], packet, (fast_rand()&3)==0?0:len, out2buf, MAX_FRAME_SAMP, (fast_rand()&7)!=0); + if(out_samples<120)test_failed(); + i+=frame_size; + count++; + }while(i<(SSAMPLES-MAX_FRAME_SAMP)); + fprintf(stdout," Mode %s FB encode %s, %6d bps OK.\n",mstrings[modes[j]],rc==0?" VBR":rc==1?"CVBR":" CBR",rate); + } + } + + if(opus_encoder_ctl(enc, OPUS_SET_FORCE_MODE(OPUS_AUTO))!=OPUS_OK)test_failed(); + if(opus_encoder_ctl(enc, OPUS_SET_FORCE_CHANNELS(OPUS_AUTO))!=OPUS_OK)test_failed(); + if(opus_encoder_ctl(enc, OPUS_SET_INBAND_FEC(0))!=OPUS_OK)test_failed(); + if(opus_encoder_ctl(enc, OPUS_SET_DTX(0))!=OPUS_OK)test_failed(); + + for(rc=0;rc<3;rc++) + { + if(opus_multistream_encoder_ctl(MSenc, OPUS_SET_VBR(rc<2))!=OPUS_OK)test_failed(); + if(opus_multistream_encoder_ctl(MSenc, OPUS_SET_VBR_CONSTRAINT(rc==1))!=OPUS_OK)test_failed(); + if(opus_multistream_encoder_ctl(MSenc, OPUS_SET_VBR_CONSTRAINT(rc==1))!=OPUS_OK)test_failed(); + if(opus_multistream_encoder_ctl(MSenc, OPUS_SET_INBAND_FEC(rc==0))!=OPUS_OK)test_failed(); + for(j=0;j<16;j++) + { + int rate; + int modes[16]={0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2}; + int rates[16]={4000,12000,32000,8000,16000,32000,48000,88000,4000,12000,32000,8000,16000,32000,48000,88000}; + int frame[16]={160*1,160,80,160,160,80,40,20,160*1,160,80,160,160,80,40,20}; + if(opus_multistream_encoder_ctl(MSenc, OPUS_SET_INBAND_FEC(rc==0&&j==1))!=OPUS_OK)test_failed(); + if(opus_multistream_encoder_ctl(MSenc, OPUS_SET_FORCE_MODE(MODE_SILK_ONLY+modes[j]))!=OPUS_OK)test_failed(); + rate=rates[j]+fast_rand()%rates[j]; + if(opus_multistream_encoder_ctl(MSenc, OPUS_SET_DTX(fast_rand()&1))!=OPUS_OK)test_failed(); + if(opus_multistream_encoder_ctl(MSenc, OPUS_SET_BITRATE(rate))!=OPUS_OK)test_failed(); + count=i=0; + do { + int len,out_samples,frame_size,loss; + opus_int32 pred; + if(opus_multistream_encoder_ctl(MSenc, OPUS_GET_PREDICTION_DISABLED(&pred))!=OPUS_OK)test_failed(); + if(opus_multistream_encoder_ctl(MSenc, OPUS_SET_PREDICTION_DISABLED((int)(fast_rand()&15)<(pred?11:4)))!=OPUS_OK)test_failed(); + frame_size=frame[j]; + if(opus_multistream_encoder_ctl(MSenc, OPUS_SET_COMPLEXITY((count>>2)%11))!=OPUS_OK)test_failed(); + if(opus_multistream_encoder_ctl(MSenc, OPUS_SET_PACKET_LOSS_PERC((fast_rand()&15)&(fast_rand()%15)))!=OPUS_OK)test_failed(); + if((fast_rand()&255)==0) + { + if(opus_multistream_encoder_ctl(MSenc, OPUS_RESET_STATE)!=OPUS_OK)test_failed(); + if(opus_multistream_decoder_ctl(MSdec, OPUS_RESET_STATE)!=OPUS_OK)test_failed(); + if((fast_rand()&3)!=0) + { + if(opus_multistream_decoder_ctl(MSdec_err, OPUS_RESET_STATE)!=OPUS_OK)test_failed(); + } + } + if((fast_rand()&255)==0) + { + if(opus_multistream_decoder_ctl(MSdec_err, OPUS_RESET_STATE)!=OPUS_OK)test_failed(); + } + len = opus_multistream_encode(MSenc, &inbuf[i<<1], frame_size, packet, MAX_PACKET); + if(len<0 || len>MAX_PACKET)test_failed(); + if(opus_multistream_encoder_ctl(MSenc, OPUS_GET_FINAL_RANGE(&enc_final_range))!=OPUS_OK)test_failed(); + if((fast_rand()&3)==0) + { + if(opus_multistream_packet_pad(packet,len,len+1,2)!=OPUS_OK)test_failed(); + len++; + } + if((fast_rand()&7)==0) + { + if(opus_multistream_packet_pad(packet,len,len+256,2)!=OPUS_OK)test_failed(); + len+=256; + } + if((fast_rand()&3)==0) + { + len=opus_multistream_packet_unpad(packet,len,2); + if(len<1)test_failed(); + } + out_samples = opus_multistream_decode(MSdec, packet, len, out2buf, MAX_FRAME_SAMP, 0); + if(out_samples!=frame_size*6)test_failed(); + if(opus_multistream_decoder_ctl(MSdec, OPUS_GET_FINAL_RANGE(&dec_final_range))!=OPUS_OK)test_failed(); + if(enc_final_range!=dec_final_range)test_failed(); + /*LBRR decode*/ + loss=(fast_rand()&63)==0; + out_samples = opus_multistream_decode(MSdec_err, packet, loss?0:len, out2buf, frame_size*6, (fast_rand()&3)!=0); + if(out_samples!=(frame_size*6))test_failed(); + i+=frame_size; + count++; + }while(i<(SSAMPLES/12-MAX_FRAME_SAMP)); + fprintf(stdout," Mode %s NB dual-mono MS encode %s, %6d bps OK.\n",mstrings[modes[j]],rc==0?" VBR":rc==1?"CVBR":" CBR",rate); + } + } + + bitrate_bps=512000; + fsize=fast_rand()%31; + fswitch=100; + + debruijn2(6,db62); + count=i=0; + do { + unsigned char toc; + const unsigned char *frames[48]; + short size[48]; + int payload_offset; + opus_uint32 dec_final_range2; + int jj,dec2; + int len,out_samples; + int frame_size=fsizes[db62[fsize]]; + opus_int32 offset=i%(SAMPLES-MAX_FRAME_SAMP); + + opus_encoder_ctl(enc, OPUS_SET_BITRATE(bitrate_bps)); + + len = opus_encode(enc, &inbuf[offset<<1], frame_size, packet, MAX_PACKET); + if(len<0 || len>MAX_PACKET)test_failed(); + count++; + + opus_encoder_ctl(enc, OPUS_GET_FINAL_RANGE(&enc_final_range)); + + out_samples = opus_decode(dec, packet, len, &outbuf[offset<<1], MAX_FRAME_SAMP, 0); + if(out_samples!=frame_size)test_failed(); + + opus_decoder_ctl(dec, OPUS_GET_FINAL_RANGE(&dec_final_range)); + + /* compare final range encoder rng values of encoder and decoder */ + if(dec_final_range!=enc_final_range)test_failed(); + + /* We fuzz the packet, but take care not to only corrupt the payload + Corrupted headers are tested elsewhere and we need to actually run + the decoders in order to compare them. */ + if(opus_packet_parse(packet,len,&toc,frames,size,&payload_offset)<=0)test_failed(); + if((fast_rand()&1023)==0)len=0; + for(j=(opus_int32)(frames[0]-packet);j0?packet:NULL, len, out2buf, MAX_FRAME_SAMP, 0); + if(out_samples<0||out_samples>MAX_FRAME_SAMP)test_failed(); + if((len>0&&out_samples!=frame_size))test_failed(); /*FIXME use lastframe*/ + + opus_decoder_ctl(dec_err[0], OPUS_GET_FINAL_RANGE(&dec_final_range)); + + /*randomly select one of the decoders to compare with*/ + dec2=fast_rand()%9+1; + out_samples = opus_decode(dec_err[dec2], len>0?packet:NULL, len, out2buf, MAX_FRAME_SAMP, 0); + if(out_samples<0||out_samples>MAX_FRAME_SAMP)test_failed(); /*FIXME, use factor, lastframe for loss*/ + + opus_decoder_ctl(dec_err[dec2], OPUS_GET_FINAL_RANGE(&dec_final_range2)); + if(len>0&&dec_final_range!=dec_final_range2)test_failed(); + + fswitch--; + if(fswitch<1) + { + int new_size; + fsize=(fsize+1)%36; + new_size=fsizes[db62[fsize]]; + if(new_size==960||new_size==480)fswitch=2880/new_size*(fast_rand()%19+1); + else fswitch=(fast_rand()%(2880/new_size))+1; + } + bitrate_bps=((fast_rand()%508000+4000)+bitrate_bps)>>1; + i+=frame_size; + }while(i] [-fuzz ]\n",_argv[0]); +} + +int main(int _argc, char **_argv) +{ + int args=1; + char * strtol_str=NULL; + const char * oversion; + const char * env_seed; + int env_used; + int num_encoders_to_fuzz=5; + int num_setting_changes=40; + + env_used=0; + env_seed=getenv("SEED"); + if(_argc>1) + iseed=strtol(_argv[1], &strtol_str, 10); /* the first input argument might be the seed */ + if(strtol_str!=NULL && strtol_str[0]=='\0') /* iseed is a valid number */ + args++; + else if(env_seed) { + iseed=atoi(env_seed); + env_used=1; + } + else iseed=(opus_uint32)time(NULL)^(((opus_uint32)getpid()&65535)<<16); + Rw=Rz=iseed; + + while(args<_argc) + { + if(strcmp(_argv[args], "-fuzz")==0 && _argc==(args+3)) { + num_encoders_to_fuzz=strtol(_argv[args+1], &strtol_str, 10); + if(strtol_str[0]!='\0' || num_encoders_to_fuzz<=0) { + print_usage(_argv); + return EXIT_FAILURE; + } + num_setting_changes=strtol(_argv[args+2], &strtol_str, 10); + if(strtol_str[0]!='\0' || num_setting_changes<=0) { + print_usage(_argv); + return EXIT_FAILURE; + } + args+=3; + } + else { + print_usage(_argv); + return EXIT_FAILURE; + } + } + + oversion=opus_get_version_string(); + if(!oversion)test_failed(); + fprintf(stderr,"Testing %s encoder. Random seed: %u (%.4X)\n", oversion, iseed, fast_rand() % 65535); + if(env_used)fprintf(stderr," Random seed set from the environment (SEED=%s).\n", env_seed); + + regression_test(); + + /*Setting TEST_OPUS_NOFUZZ tells the tool not to send garbage data + into the decoders. This is helpful because garbage data + may cause the decoders to clip, which angers CLANG IOC.*/ + run_test1(getenv("TEST_OPUS_NOFUZZ")!=NULL); + + /* Fuzz encoder settings online */ + if(getenv("TEST_OPUS_NOFUZZ")==NULL) { + fprintf(stderr,"Running fuzz_encoder_settings with %d encoder(s) and %d setting change(s) each.\n", + num_encoders_to_fuzz, num_setting_changes); + fuzz_encoder_settings(num_encoders_to_fuzz, num_setting_changes); + } + + fprintf(stderr,"Tests completed successfully.\n"); + + return 0; +} diff --git a/extern/opus/tests/test_opus_padding.c b/extern/opus/tests/test_opus_padding.c new file mode 100644 index 0000000..c22e8f0 --- /dev/null +++ b/extern/opus/tests/test_opus_padding.c @@ -0,0 +1,93 @@ +/* Copyright (c) 2012 Xiph.Org Foundation + Written by Jüri Aedla and Ralph Giles */ +/* + 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. + + 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 OWNER + 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. +*/ + +/* Check for overflow in reading the padding length. + * http://lists.xiph.org/pipermail/opus/2012-November/001834.html + */ + +#include +#include +#include +#include "opus.h" +#include "test_opus_common.h" + +#define PACKETSIZE 16909318 +#define CHANNELS 2 +#define FRAMESIZE 5760 + +int test_overflow(void) +{ + OpusDecoder *decoder; + int result; + int error; + + unsigned char *in = malloc(PACKETSIZE); + opus_int16 *out = malloc(FRAMESIZE*CHANNELS*sizeof(*out)); + + fprintf(stderr, " Checking for padding overflow... "); + if (!in || !out) { + fprintf(stderr, "FAIL (out of memory)\n"); + return -1; + } + in[0] = 0xff; + in[1] = 0x41; + memset(in + 2, 0xff, PACKETSIZE - 3); + in[PACKETSIZE-1] = 0x0b; + + decoder = opus_decoder_create(48000, CHANNELS, &error); + result = opus_decode(decoder, in, PACKETSIZE, out, FRAMESIZE, 0); + opus_decoder_destroy(decoder); + + free(in); + free(out); + + if (result != OPUS_INVALID_PACKET) { + fprintf(stderr, "FAIL!\n"); + test_failed(); + } + + fprintf(stderr, "OK.\n"); + + return 1; +} + +int main(void) +{ + const char *oversion; + int tests = 0;; + + iseed = 0; + oversion = opus_get_version_string(); + if (!oversion) test_failed(); + fprintf(stderr, "Testing %s padding.\n", oversion); + + tests += test_overflow(); + + fprintf(stderr, "All padding tests passed.\n"); + + return 0; +} diff --git a/extern/opus/tests/test_opus_projection.c b/extern/opus/tests/test_opus_projection.c new file mode 100644 index 0000000..5f0d672 --- /dev/null +++ b/extern/opus/tests/test_opus_projection.c @@ -0,0 +1,394 @@ +/* Copyright (c) 2017 Google Inc. + Written by Andrew Allen */ +/* + 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. + + 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 OWNER + 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. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include +#include "float_cast.h" +#include "opus.h" +#include "test_opus_common.h" +#include "opus_projection.h" +#include "mathops.h" +#include "../src/mapping_matrix.h" +#include "mathops.h" + +#define BUFFER_SIZE 960 +#define MAX_DATA_BYTES 32768 +#define MAX_FRAME_SAMPLES 5760 +#define ERROR_TOLERANCE 1 + +#define SIMPLE_MATRIX_SIZE 12 +#define SIMPLE_MATRIX_FRAME_SIZE 10 +#define SIMPLE_MATRIX_INPUT_SIZE 30 +#define SIMPLE_MATRIX_OUTPUT_SIZE 40 + +int assert_is_equal( + const opus_val16 *a, const opus_int16 *b, int size, opus_int16 tolerance) +{ + int i; + for (i = 0; i < size; i++) + { +#ifdef FIXED_POINT + opus_int16 val = a[i]; +#else + opus_int16 val = FLOAT2INT16(a[i]); +#endif + if (abs(val - b[i]) > tolerance) + return 1; + } + return 0; +} + +int assert_is_equal_short( + const opus_int16 *a, const opus_int16 *b, int size, opus_int16 tolerance) +{ + int i; + for (i = 0; i < size; i++) + if (abs(a[i] - b[i]) > tolerance) + return 1; + return 0; +} + +void test_simple_matrix(void) +{ + const MappingMatrix simple_matrix_params = {4, 3, 0}; + const opus_int16 simple_matrix_data[SIMPLE_MATRIX_SIZE] = {0, 32767, 0, 0, 32767, 0, 0, 0, 0, 0, 0, 32767}; + const opus_int16 input_int16[SIMPLE_MATRIX_INPUT_SIZE] = { + 32767, 0, -32768, 29491, -3277, -29491, 26214, -6554, -26214, 22938, -9830, + -22938, 19661, -13107, -19661, 16384, -16384, -16384, 13107, -19661, -13107, + 9830, -22938, -9830, 6554, -26214, -6554, 3277, -29491, -3277}; + const opus_int16 expected_output_int16[SIMPLE_MATRIX_OUTPUT_SIZE] = { + 0, 32767, 0, -32768, -3277, 29491, 0, -29491, -6554, 26214, 0, -26214, + -9830, 22938, 0, -22938, -13107, 19661, 0, -19661, -16384, 16384, 0, -16384, + -19661, 13107, 0, -13107, -22938, 9830, 0, -9830, -26214, 6554, 0, -6554, + -29491, 3277, 0, -3277}; + + int i, ret; + opus_int32 simple_matrix_size; + opus_val16 *input_val16; + opus_val16 *output_val16; + opus_int16 *output_int16; + MappingMatrix *simple_matrix; + + /* Allocate input/output buffers. */ + input_val16 = (opus_val16 *)opus_alloc(sizeof(opus_val16) * SIMPLE_MATRIX_INPUT_SIZE); + output_int16 = (opus_int16 *)opus_alloc(sizeof(opus_int16) * SIMPLE_MATRIX_OUTPUT_SIZE); + output_val16 = (opus_val16 *)opus_alloc(sizeof(opus_val16) * SIMPLE_MATRIX_OUTPUT_SIZE); + + /* Initialize matrix */ + simple_matrix_size = mapping_matrix_get_size(simple_matrix_params.rows, + simple_matrix_params.cols); + if (!simple_matrix_size) + test_failed(); + + simple_matrix = (MappingMatrix *)opus_alloc(simple_matrix_size); + mapping_matrix_init(simple_matrix, simple_matrix_params.rows, + simple_matrix_params.cols, simple_matrix_params.gain, simple_matrix_data, + sizeof(simple_matrix_data)); + + /* Copy inputs. */ + for (i = 0; i < SIMPLE_MATRIX_INPUT_SIZE; i++) + { +#ifdef FIXED_POINT + input_val16[i] = input_int16[i]; +#else + input_val16[i] = (1/32768.f)*input_int16[i]; +#endif + } + + /* _in_short */ + for (i = 0; i < SIMPLE_MATRIX_OUTPUT_SIZE; i++) + output_val16[i] = 0; + for (i = 0; i < simple_matrix->rows; i++) + { + mapping_matrix_multiply_channel_in_short(simple_matrix, + input_int16, simple_matrix->cols, &output_val16[i], i, + simple_matrix->rows, SIMPLE_MATRIX_FRAME_SIZE); + } + ret = assert_is_equal(output_val16, expected_output_int16, SIMPLE_MATRIX_OUTPUT_SIZE, ERROR_TOLERANCE); + if (ret) + test_failed(); + + /* _out_short */ + for (i = 0; i < SIMPLE_MATRIX_OUTPUT_SIZE; i++) + output_int16[i] = 0; + for (i = 0; i < simple_matrix->cols; i++) + { + mapping_matrix_multiply_channel_out_short(simple_matrix, + &input_val16[i], i, simple_matrix->cols, output_int16, + simple_matrix->rows, SIMPLE_MATRIX_FRAME_SIZE); + } + ret = assert_is_equal_short(output_int16, expected_output_int16, SIMPLE_MATRIX_OUTPUT_SIZE, ERROR_TOLERANCE); + if (ret) + test_failed(); + +#if !defined(DISABLE_FLOAT_API) && !defined(FIXED_POINT) + /* _in_float */ + for (i = 0; i < SIMPLE_MATRIX_OUTPUT_SIZE; i++) + output_val16[i] = 0; + for (i = 0; i < simple_matrix->rows; i++) + { + mapping_matrix_multiply_channel_in_float(simple_matrix, + input_val16, simple_matrix->cols, &output_val16[i], i, + simple_matrix->rows, SIMPLE_MATRIX_FRAME_SIZE); + } + ret = assert_is_equal(output_val16, expected_output_int16, SIMPLE_MATRIX_OUTPUT_SIZE, ERROR_TOLERANCE); + if (ret) + test_failed(); + + /* _out_float */ + for (i = 0; i < SIMPLE_MATRIX_OUTPUT_SIZE; i++) + output_val16[i] = 0; + for (i = 0; i < simple_matrix->cols; i++) + { + mapping_matrix_multiply_channel_out_float(simple_matrix, + &input_val16[i], i, simple_matrix->cols, output_val16, + simple_matrix->rows, SIMPLE_MATRIX_FRAME_SIZE); + } + ret = assert_is_equal(output_val16, expected_output_int16, SIMPLE_MATRIX_OUTPUT_SIZE, ERROR_TOLERANCE); + if (ret) + test_failed(); +#endif + + opus_free(input_val16); + opus_free(output_int16); + opus_free(output_val16); + opus_free(simple_matrix); +} + +void test_creation_arguments(const int channels, const int mapping_family) +{ + int streams; + int coupled_streams; + int enc_error; + int dec_error; + int ret; + OpusProjectionEncoder *st_enc = NULL; + OpusProjectionDecoder *st_dec = NULL; + + const opus_int32 Fs = 48000; + const int application = OPUS_APPLICATION_AUDIO; + + int order_plus_one = (int)floor(sqrt((float)channels)); + int nondiegetic_channels = channels - order_plus_one * order_plus_one; + + int is_channels_valid = 0; + int is_projection_valid = 0; + + st_enc = opus_projection_ambisonics_encoder_create(Fs, channels, + mapping_family, &streams, &coupled_streams, application, &enc_error); + if (st_enc != NULL) + { + opus_int32 matrix_size; + unsigned char *matrix; + + ret = opus_projection_encoder_ctl(st_enc, + OPUS_PROJECTION_GET_DEMIXING_MATRIX_SIZE_REQUEST, &matrix_size); + if (ret != OPUS_OK || !matrix_size) + test_failed(); + + matrix = (unsigned char *)opus_alloc(matrix_size); + ret = opus_projection_encoder_ctl(st_enc, + OPUS_PROJECTION_GET_DEMIXING_MATRIX_REQUEST, matrix, matrix_size); + + opus_projection_encoder_destroy(st_enc); + + st_dec = opus_projection_decoder_create(Fs, channels, streams, + coupled_streams, matrix, matrix_size, &dec_error); + if (st_dec != NULL) + { + opus_projection_decoder_destroy(st_dec); + } + opus_free(matrix); + } + + is_channels_valid = (order_plus_one >= 2 && order_plus_one <= 4) && + (nondiegetic_channels == 0 || nondiegetic_channels == 2); + is_projection_valid = (enc_error == OPUS_OK && dec_error == OPUS_OK); + if (is_channels_valid ^ is_projection_valid) + { + fprintf(stderr, "Channels: %d, Family: %d\n", channels, mapping_family); + fprintf(stderr, "Order+1: %d, Non-diegetic Channels: %d\n", + order_plus_one, nondiegetic_channels); + fprintf(stderr, "Streams: %d, Coupled Streams: %d\n", + streams, coupled_streams); + test_failed(); + } +} + +void generate_music(short *buf, opus_int32 len, opus_int32 channels) +{ + opus_int32 i,j,k; + opus_int32 *a,*b,*c,*d; + a = (opus_int32 *)malloc(sizeof(opus_int32) * channels); + b = (opus_int32 *)malloc(sizeof(opus_int32) * channels); + c = (opus_int32 *)malloc(sizeof(opus_int32) * channels); + d = (opus_int32 *)malloc(sizeof(opus_int32) * channels); + memset(a, 0, sizeof(opus_int32) * channels); + memset(b, 0, sizeof(opus_int32) * channels); + memset(c, 0, sizeof(opus_int32) * channels); + memset(d, 0, sizeof(opus_int32) * channels); + j=0; + + for(i=0;i>12)^((j>>10|j>>12)&26&j>>7)))&128)+128)<<15; + r=fast_rand();v+=r&65535;v-=r>>16; + b[k]=v-a[k]+((b[k]*61+32)>>6);a[k]=v; + c[k]=(30*(c[k]+b[k]+d[k])+32)>>6;d[k]=b[k]; + v=(c[k]+128)>>8; + buf[i*channels+k]=v>32767?32767:(v<-32768?-32768:v); + if(i%6==0)j++; + } + } + + free(a); + free(b); + free(c); + free(d); +} + +void test_encode_decode(opus_int32 bitrate, opus_int32 channels, + const int mapping_family) +{ + const opus_int32 Fs = 48000; + const int application = OPUS_APPLICATION_AUDIO; + + OpusProjectionEncoder *st_enc; + OpusProjectionDecoder *st_dec; + int streams; + int coupled; + int error; + short *buffer_in; + short *buffer_out; + unsigned char data[MAX_DATA_BYTES] = { 0 }; + int len; + int out_samples; + opus_int32 matrix_size = 0; + unsigned char *matrix = NULL; + + buffer_in = (short *)malloc(sizeof(short) * BUFFER_SIZE * channels); + buffer_out = (short *)malloc(sizeof(short) * BUFFER_SIZE * channels); + + st_enc = opus_projection_ambisonics_encoder_create(Fs, channels, + mapping_family, &streams, &coupled, application, &error); + if (error != OPUS_OK) { + fprintf(stderr, + "Couldn\'t create encoder with %d channels and mapping family %d.\n", + channels, mapping_family); + free(buffer_in); + free(buffer_out); + test_failed(); + } + + error = opus_projection_encoder_ctl(st_enc, + OPUS_SET_BITRATE(bitrate * 1000 * (streams + coupled))); + if (error != OPUS_OK) + { + goto bad_cleanup; + } + + error = opus_projection_encoder_ctl(st_enc, + OPUS_PROJECTION_GET_DEMIXING_MATRIX_SIZE_REQUEST, &matrix_size); + if (error != OPUS_OK || !matrix_size) + { + goto bad_cleanup; + } + + matrix = (unsigned char *)opus_alloc(matrix_size); + error = opus_projection_encoder_ctl(st_enc, + OPUS_PROJECTION_GET_DEMIXING_MATRIX_REQUEST, matrix, matrix_size); + + st_dec = opus_projection_decoder_create(Fs, channels, streams, coupled, + matrix, matrix_size, &error); + opus_free(matrix); + + if (error != OPUS_OK) { + fprintf(stderr, + "Couldn\'t create decoder with %d channels, %d streams " + "and %d coupled streams.\n", channels, streams, coupled); + goto bad_cleanup; + } + + generate_music(buffer_in, BUFFER_SIZE, channels); + + len = opus_projection_encode( + st_enc, buffer_in, BUFFER_SIZE, data, MAX_DATA_BYTES); + if(len<0 || len>MAX_DATA_BYTES) { + fprintf(stderr,"opus_encode() returned %d\n", len); + goto bad_cleanup; + } + + out_samples = opus_projection_decode( + st_dec, data, len, buffer_out, MAX_FRAME_SAMPLES, 0); + if(out_samples!=BUFFER_SIZE) { + fprintf(stderr,"opus_decode() returned %d\n", out_samples); + goto bad_cleanup; + } + + opus_projection_decoder_destroy(st_dec); + opus_projection_encoder_destroy(st_enc); + free(buffer_in); + free(buffer_out); + return; +bad_cleanup: + free(buffer_in); + free(buffer_out); + test_failed(); +} + +int main(int _argc, char **_argv) +{ + unsigned int i; + + (void)_argc; + (void)_argv; + + /* Test simple matrix multiplication routines. */ + test_simple_matrix(); + + /* Test full range of channels in creation arguments. */ + for (i = 0; i < 255; i++) + test_creation_arguments(i, 3); + + /* Test encode/decode pipeline. */ + test_encode_decode(64 * 18, 18, 3); + + fprintf(stderr, "All projection tests passed.\n"); + return 0; +} + diff --git a/extern/opus/training/rnn_dump.py b/extern/opus/training/rnn_dump.py new file mode 100755 index 0000000..c312088 --- /dev/null +++ b/extern/opus/training/rnn_dump.py @@ -0,0 +1,66 @@ +#!/usr/bin/python + +from __future__ import print_function + +from keras.models import Sequential +from keras.models import Model +from keras.layers import Input +from keras.layers import Dense +from keras.layers import LSTM +from keras.layers import GRU +from keras.models import load_model +from keras import backend as K +import sys + +import numpy as np + +def printVector(f, vector, name): + v = np.reshape(vector, (-1)); + #print('static const float ', name, '[', len(v), '] = \n', file=f) + f.write('static const opus_int8 {}[{}] = {{\n '.format(name, len(v))) + for i in range(0, len(v)): + f.write('{}'.format(max(-128,min(127,int(round(128*v[i])))))) + if (i!=len(v)-1): + f.write(',') + else: + break; + if (i%8==7): + f.write("\n ") + else: + f.write(" ") + #print(v, file=f) + f.write('\n};\n\n') + return; + +def binary_crossentrop2(y_true, y_pred): + return K.mean(2*K.abs(y_true-0.5) * K.binary_crossentropy(y_pred, y_true), axis=-1) + + +#model = load_model(sys.argv[1], custom_objects={'binary_crossentrop2': binary_crossentrop2}) +main_input = Input(shape=(None, 25), name='main_input') +x = Dense(32, activation='tanh')(main_input) +x = GRU(24, activation='tanh', recurrent_activation='sigmoid', return_sequences=True)(x) +x = Dense(2, activation='sigmoid')(x) +model = Model(inputs=main_input, outputs=x) +model.load_weights(sys.argv[1]) + +weights = model.get_weights() + +f = open(sys.argv[2], 'w') + +f.write('/*This file is automatically generated from a Keras model*/\n\n') +f.write('#ifdef HAVE_CONFIG_H\n#include "config.h"\n#endif\n\n#include "mlp.h"\n\n') + +printVector(f, weights[0], 'layer0_weights') +printVector(f, weights[1], 'layer0_bias') +printVector(f, weights[2], 'layer1_weights') +printVector(f, weights[3], 'layer1_recur_weights') +printVector(f, weights[4], 'layer1_bias') +printVector(f, weights[5], 'layer2_weights') +printVector(f, weights[6], 'layer2_bias') + +f.write('const DenseLayer layer0 = {\n layer0_bias,\n layer0_weights,\n 25, 32, 0\n};\n\n') +f.write('const GRULayer layer1 = {\n layer1_bias,\n layer1_weights,\n layer1_recur_weights,\n 32, 24\n};\n\n') +f.write('const DenseLayer layer2 = {\n layer2_bias,\n layer2_weights,\n 24, 2, 1\n};\n\n') + +f.close() diff --git a/extern/opus/training/rnn_train.py b/extern/opus/training/rnn_train.py new file mode 100755 index 0000000..29bcb03 --- /dev/null +++ b/extern/opus/training/rnn_train.py @@ -0,0 +1,177 @@ +#!/usr/bin/python3 + +from __future__ import print_function + +from keras.models import Sequential +from keras.models import Model +from keras.layers import Input +from keras.layers import Dense +from keras.layers import LSTM +from keras.layers import GRU +from keras.layers import CuDNNGRU +from keras.layers import SimpleRNN +from keras.layers import Dropout +from keras import losses +import h5py +from keras.optimizers import Adam + +from keras.constraints import Constraint +from keras import backend as K +import numpy as np + +import tensorflow as tf +from keras.backend.tensorflow_backend import set_session +config = tf.ConfigProto() +config.gpu_options.per_process_gpu_memory_fraction = 0.44 +set_session(tf.Session(config=config)) + +def binary_crossentrop2(y_true, y_pred): + return K.mean(2*K.abs(y_true-0.5) * K.binary_crossentropy(y_true, y_pred), axis=-1) + +def binary_accuracy2(y_true, y_pred): + return K.mean(K.cast(K.equal(y_true, K.round(y_pred)), 'float32') + K.cast(K.equal(y_true, 0.5), 'float32'), axis=-1) + +def quant_model(model): + weights = model.get_weights() + for k in range(len(weights)): + weights[k] = np.maximum(-128, np.minimum(127, np.round(128*weights[k])*0.0078125)) + model.set_weights(weights) + +class WeightClip(Constraint): + '''Clips the weights incident to each hidden unit to be inside a range + ''' + def __init__(self, c=2): + self.c = c + + def __call__(self, p): + return K.clip(p, -self.c, self.c) + + def get_config(self): + return {'name': self.__class__.__name__, + 'c': self.c} + +reg = 0.000001 +constraint = WeightClip(.998) + +print('Build model...') + +main_input = Input(shape=(None, 25), name='main_input') +x = Dense(32, activation='tanh', kernel_constraint=constraint, bias_constraint=constraint)(main_input) +#x = CuDNNGRU(24, return_sequences=True, kernel_constraint=constraint, recurrent_constraint=constraint, bias_constraint=constraint)(x) +x = GRU(24, recurrent_activation='sigmoid', activation='tanh', return_sequences=True, kernel_constraint=constraint, recurrent_constraint=constraint, bias_constraint=constraint)(x) +x = Dense(2, activation='sigmoid', kernel_constraint=constraint, bias_constraint=constraint)(x) +model = Model(inputs=main_input, outputs=x) + +batch_size = 2048 + +print('Loading data...') +with h5py.File('features10b.h5', 'r') as hf: + all_data = hf['data'][:] +print('done.') + +window_size = 1500 + +nb_sequences = len(all_data)//window_size +print(nb_sequences, ' sequences') +x_train = all_data[:nb_sequences*window_size, :-2] +x_train = np.reshape(x_train, (nb_sequences, window_size, 25)) + +y_train = np.copy(all_data[:nb_sequences*window_size, -2:]) +y_train = np.reshape(y_train, (nb_sequences, window_size, 2)) + +print("Marking ignores") +for s in y_train: + for e in s: + if (e[1] >= 1): + break + e[0] = 0.5 + +all_data = 0; +x_train = x_train.astype('float32') +y_train = y_train.astype('float32') + +print(len(x_train), 'train sequences. x shape =', x_train.shape, 'y shape = ', y_train.shape) + +model.load_weights('newweights10a1b_ep206.hdf5') + +#weights = model.get_weights() +#for k in range(len(weights)): +# weights[k] = np.round(128*weights[k])*0.0078125 +#model.set_weights(weights) + +# try using different optimizers and different optimizer configs +model.compile(loss=binary_crossentrop2, + optimizer=Adam(0.0001), + metrics=[binary_accuracy2]) + +print('Train...') +quant_model(model) +model.fit(x_train, y_train, + batch_size=batch_size, + epochs=10, validation_data=(x_train, y_train)) +model.save("newweights10a1c_ep10.hdf5") + +quant_model(model) +model.fit(x_train, y_train, + batch_size=batch_size, + epochs=50, initial_epoch=10) +model.save("newweights10a1c_ep50.hdf5") + +model.compile(loss=binary_crossentrop2, + optimizer=Adam(0.0001), + metrics=[binary_accuracy2]) + +quant_model(model) +model.fit(x_train, y_train, + batch_size=batch_size, + epochs=100, initial_epoch=50) +model.save("newweights10a1c_ep100.hdf5") + +quant_model(model) +model.fit(x_train, y_train, + batch_size=batch_size, + epochs=150, initial_epoch=100) +model.save("newweights10a1c_ep150.hdf5") + +quant_model(model) +model.fit(x_train, y_train, + batch_size=batch_size, + epochs=200, initial_epoch=150) +model.save("newweights10a1c_ep200.hdf5") + +quant_model(model) +model.fit(x_train, y_train, + batch_size=batch_size, + epochs=201, initial_epoch=200) +model.save("newweights10a1c_ep201.hdf5") + +quant_model(model) +model.fit(x_train, y_train, + batch_size=batch_size, + epochs=202, initial_epoch=201, validation_data=(x_train, y_train)) +model.save("newweights10a1c_ep202.hdf5") + +quant_model(model) +model.fit(x_train, y_train, + batch_size=batch_size, + epochs=203, initial_epoch=202, validation_data=(x_train, y_train)) +model.save("newweights10a1c_ep203.hdf5") + +quant_model(model) +model.fit(x_train, y_train, + batch_size=batch_size, + epochs=204, initial_epoch=203, validation_data=(x_train, y_train)) +model.save("newweights10a1c_ep204.hdf5") + +quant_model(model) +model.fit(x_train, y_train, + batch_size=batch_size, + epochs=205, initial_epoch=204, validation_data=(x_train, y_train)) +model.save("newweights10a1c_ep205.hdf5") + +quant_model(model) +model.fit(x_train, y_train, + batch_size=batch_size, + epochs=206, initial_epoch=205, validation_data=(x_train, y_train)) +model.save("newweights10a1c_ep206.hdf5") + diff --git a/extern/opus/training/txt2hdf5.py b/extern/opus/training/txt2hdf5.py new file mode 100755 index 0000000..9c60287 --- /dev/null +++ b/extern/opus/training/txt2hdf5.py @@ -0,0 +1,12 @@ +#!/usr/bin/python + +from __future__ import print_function + +import numpy as np +import h5py +import sys + +data = np.loadtxt(sys.argv[1], dtype='float32') +h5f = h5py.File(sys.argv[2], 'w'); +h5f.create_dataset('data', data=data) +h5f.close() diff --git a/extern/opus/update_version b/extern/opus/update_version new file mode 100755 index 0000000..a999991 --- /dev/null +++ b/extern/opus/update_version @@ -0,0 +1,65 @@ +#!/bin/bash + +# Creates and updates the package_version information used by configure.ac +# (or other makefiles). When run inside a git repository it will use the +# version information that can be queried from it unless AUTO_UPDATE is set +# to 'no'. If no version is currently known it will be set to 'unknown'. +# +# If called with the argument 'release', the PACKAGE_VERSION will be updated +# even if AUTO_UPDATE=no, but the value of AUTO_UPDATE shall be preserved. +# This is used to force a version update whenever `make dist` is run. +# +# The exit status is 1 if package_version is not modified, else 0 is returned. +# +# This script should NOT be included in distributed tarballs, because if a +# parent directory contains a git repository we do not want to accidentally +# retrieve the version information from it instead. Tarballs should ship +# with only the package_version file. +# +# Ron , 2012. + +SRCDIR=$(dirname $0) + +if [ -e "$SRCDIR/package_version" ]; then + . "$SRCDIR/package_version" +fi + +if [ "$AUTO_UPDATE" = no ]; then + [ "$1" = release ] || exit 1 +else + AUTO_UPDATE=yes +fi + +# We run `git status` before describe here to ensure that we don't get a false +# -dirty from files that have been touched but are not actually altered in the +# working dir. +GIT_VERSION=$(cd "$SRCDIR" && git status > /dev/null 2>&1 \ + && git describe --tags --match 'v*' --dirty 2> /dev/null) +GIT_VERSION=${GIT_VERSION#v} + +if [ -n "$GIT_VERSION" ]; then + + [ "$GIT_VERSION" != "$PACKAGE_VERSION" ] || exit 1 + PACKAGE_VERSION="$GIT_VERSION" + +elif [ -z "$PACKAGE_VERSION" ]; then + # No current package_version and no git ... + # We really shouldn't ever get here, because this script should only be + # included in the git repository, and should usually be export-ignored. + PACKAGE_VERSION="unknown" +else + exit 1 +fi + +cat > "$SRCDIR/package_version" <<-EOF + # Automatically generated by update_version. + # This file may be sourced into a shell script or makefile. + + # Set this to 'no' if you do not wish the version information + # to be checked and updated for every build. Most people will + # never want to change this, it is an option for developers + # making frequent changes that they know will not be released. + AUTO_UPDATE=$AUTO_UPDATE + + PACKAGE_VERSION="$PACKAGE_VERSION" +EOF diff --git a/extern/opus/win32/.gitignore b/extern/opus/win32/.gitignore new file mode 100644 index 0000000..c17feab --- /dev/null +++ b/extern/opus/win32/.gitignore @@ -0,0 +1,26 @@ +# Visual Studio ignores +[Dd]ebug/ +[Dd]ebugDLL/ +[Dd]ebugDLL_fixed/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleaseDLL/ +[Rr]eleaseDLL_fixed/ +[Rr]eleases/ +*.manifest +*.lastbuildstate +*.lib +*.log +*.idb +*.ipdb +*.ilk +*.iobj +*.obj +*.opensdf +*.pdb +*.sdf +*.suo +*.tlog +*.vcxproj.user +*.vc.db +*.vc.opendb diff --git a/extern/opus/win32/VS2015/common.props b/extern/opus/win32/VS2015/common.props new file mode 100644 index 0000000..6c757d8 --- /dev/null +++ b/extern/opus/win32/VS2015/common.props @@ -0,0 +1,82 @@ + + + + + + $(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\$(ProjectName)\ + Unicode + + + true + true + false + + + false + false + true + + + + Level3 + false + false + ..\..;..\..\include;..\..\silk;..\..\celt;..\..\win32;%(AdditionalIncludeDirectories) + HAVE_CONFIG_H;WIN32;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + false + false + + + Console + + + true + Console + + + + + Guard + ProgramDatabase + NoExtensions + false + true + false + Disabled + false + false + Disabled + MultiThreadedDebug + MultiThreadedDebugDLL + true + false + + + true + + + + + false + None + true + true + false + Speed + Fast + Precise + true + true + true + MaxSpeed + MultiThreaded + MultiThreadedDLL + 16Bytes + + + false + + + + \ No newline at end of file diff --git a/extern/opus/win32/VS2015/opus.sln b/extern/opus/win32/VS2015/opus.sln new file mode 100644 index 0000000..7b678e7 --- /dev/null +++ b/extern/opus/win32/VS2015/opus.sln @@ -0,0 +1,168 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.25420.1 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "opus", "opus.vcxproj", "{219EC965-228A-1824-174D-96449D05F88A}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "opus_demo", "opus_demo.vcxproj", "{016C739D-6389-43BF-8D88-24B2BF6F620F}" + ProjectSection(ProjectDependencies) = postProject + {219EC965-228A-1824-174D-96449D05F88A} = {219EC965-228A-1824-174D-96449D05F88A} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_opus_api", "test_opus_api.vcxproj", "{1D257A17-D254-42E5-82D6-1C87A6EC775A}" + ProjectSection(ProjectDependencies) = postProject + {219EC965-228A-1824-174D-96449D05F88A} = {219EC965-228A-1824-174D-96449D05F88A} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_opus_decode", "test_opus_decode.vcxproj", "{8578322A-1883-486B-B6FA-E0094B65C9F2}" + ProjectSection(ProjectDependencies) = postProject + {219EC965-228A-1824-174D-96449D05F88A} = {219EC965-228A-1824-174D-96449D05F88A} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_opus_encode", "test_opus_encode.vcxproj", "{84DAA768-1A38-4312-BB61-4C78BB59E5B8}" + ProjectSection(ProjectDependencies) = postProject + {219EC965-228A-1824-174D-96449D05F88A} = {219EC965-228A-1824-174D-96449D05F88A} + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + DebugDLL_fixed|Win32 = DebugDLL_fixed|Win32 + DebugDLL_fixed|x64 = DebugDLL_fixed|x64 + DebugDLL|Win32 = DebugDLL|Win32 + DebugDLL|x64 = DebugDLL|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + ReleaseDLL_fixed|Win32 = ReleaseDLL_fixed|Win32 + ReleaseDLL_fixed|x64 = ReleaseDLL_fixed|x64 + ReleaseDLL|Win32 = ReleaseDLL|Win32 + ReleaseDLL|x64 = ReleaseDLL|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {219EC965-228A-1824-174D-96449D05F88A}.Debug|Win32.ActiveCfg = Debug|Win32 + {219EC965-228A-1824-174D-96449D05F88A}.Debug|Win32.Build.0 = Debug|Win32 + {219EC965-228A-1824-174D-96449D05F88A}.Debug|x64.ActiveCfg = Debug|x64 + {219EC965-228A-1824-174D-96449D05F88A}.Debug|x64.Build.0 = Debug|x64 + {219EC965-228A-1824-174D-96449D05F88A}.DebugDLL_fixed|Win32.ActiveCfg = DebugDLL_fixed|Win32 + {219EC965-228A-1824-174D-96449D05F88A}.DebugDLL_fixed|Win32.Build.0 = DebugDLL_fixed|Win32 + {219EC965-228A-1824-174D-96449D05F88A}.DebugDLL_fixed|x64.ActiveCfg = DebugDLL_fixed|x64 + {219EC965-228A-1824-174D-96449D05F88A}.DebugDLL_fixed|x64.Build.0 = DebugDLL_fixed|x64 + {219EC965-228A-1824-174D-96449D05F88A}.DebugDLL|Win32.ActiveCfg = DebugDLL|Win32 + {219EC965-228A-1824-174D-96449D05F88A}.DebugDLL|Win32.Build.0 = DebugDLL|Win32 + {219EC965-228A-1824-174D-96449D05F88A}.DebugDLL|x64.ActiveCfg = DebugDLL|x64 + {219EC965-228A-1824-174D-96449D05F88A}.DebugDLL|x64.Build.0 = DebugDLL|x64 + {219EC965-228A-1824-174D-96449D05F88A}.Release|Win32.ActiveCfg = Release|Win32 + {219EC965-228A-1824-174D-96449D05F88A}.Release|Win32.Build.0 = Release|Win32 + {219EC965-228A-1824-174D-96449D05F88A}.Release|x64.ActiveCfg = Release|x64 + {219EC965-228A-1824-174D-96449D05F88A}.Release|x64.Build.0 = Release|x64 + {219EC965-228A-1824-174D-96449D05F88A}.ReleaseDLL_fixed|Win32.ActiveCfg = ReleaseDLL_fixed|Win32 + {219EC965-228A-1824-174D-96449D05F88A}.ReleaseDLL_fixed|Win32.Build.0 = ReleaseDLL_fixed|Win32 + {219EC965-228A-1824-174D-96449D05F88A}.ReleaseDLL_fixed|x64.ActiveCfg = ReleaseDLL_fixed|x64 + {219EC965-228A-1824-174D-96449D05F88A}.ReleaseDLL_fixed|x64.Build.0 = ReleaseDLL_fixed|x64 + {219EC965-228A-1824-174D-96449D05F88A}.ReleaseDLL|Win32.ActiveCfg = ReleaseDLL|Win32 + {219EC965-228A-1824-174D-96449D05F88A}.ReleaseDLL|Win32.Build.0 = ReleaseDLL|Win32 + {219EC965-228A-1824-174D-96449D05F88A}.ReleaseDLL|x64.ActiveCfg = ReleaseDLL|x64 + {219EC965-228A-1824-174D-96449D05F88A}.ReleaseDLL|x64.Build.0 = ReleaseDLL|x64 + {016C739D-6389-43BF-8D88-24B2BF6F620F}.Debug|Win32.ActiveCfg = Debug|Win32 + {016C739D-6389-43BF-8D88-24B2BF6F620F}.Debug|Win32.Build.0 = Debug|Win32 + {016C739D-6389-43BF-8D88-24B2BF6F620F}.Debug|x64.ActiveCfg = Debug|x64 + {016C739D-6389-43BF-8D88-24B2BF6F620F}.Debug|x64.Build.0 = Debug|x64 + {016C739D-6389-43BF-8D88-24B2BF6F620F}.DebugDLL_fixed|Win32.ActiveCfg = DebugDLL_fixed|Win32 + {016C739D-6389-43BF-8D88-24B2BF6F620F}.DebugDLL_fixed|Win32.Build.0 = DebugDLL_fixed|Win32 + {016C739D-6389-43BF-8D88-24B2BF6F620F}.DebugDLL_fixed|x64.ActiveCfg = DebugDLL_fixed|x64 + {016C739D-6389-43BF-8D88-24B2BF6F620F}.DebugDLL_fixed|x64.Build.0 = DebugDLL_fixed|x64 + {016C739D-6389-43BF-8D88-24B2BF6F620F}.DebugDLL|Win32.ActiveCfg = DebugDLL|Win32 + {016C739D-6389-43BF-8D88-24B2BF6F620F}.DebugDLL|Win32.Build.0 = DebugDLL|Win32 + {016C739D-6389-43BF-8D88-24B2BF6F620F}.DebugDLL|x64.ActiveCfg = DebugDLL|x64 + {016C739D-6389-43BF-8D88-24B2BF6F620F}.DebugDLL|x64.Build.0 = DebugDLL|x64 + {016C739D-6389-43BF-8D88-24B2BF6F620F}.Release|Win32.ActiveCfg = Release|Win32 + {016C739D-6389-43BF-8D88-24B2BF6F620F}.Release|Win32.Build.0 = Release|Win32 + {016C739D-6389-43BF-8D88-24B2BF6F620F}.Release|x64.ActiveCfg = Release|x64 + {016C739D-6389-43BF-8D88-24B2BF6F620F}.Release|x64.Build.0 = Release|x64 + {016C739D-6389-43BF-8D88-24B2BF6F620F}.ReleaseDLL_fixed|Win32.ActiveCfg = ReleaseDLL_fixed|Win32 + {016C739D-6389-43BF-8D88-24B2BF6F620F}.ReleaseDLL_fixed|Win32.Build.0 = ReleaseDLL_fixed|Win32 + {016C739D-6389-43BF-8D88-24B2BF6F620F}.ReleaseDLL_fixed|x64.ActiveCfg = ReleaseDLL_fixed|x64 + {016C739D-6389-43BF-8D88-24B2BF6F620F}.ReleaseDLL_fixed|x64.Build.0 = ReleaseDLL_fixed|x64 + {016C739D-6389-43BF-8D88-24B2BF6F620F}.ReleaseDLL|Win32.ActiveCfg = ReleaseDLL|Win32 + {016C739D-6389-43BF-8D88-24B2BF6F620F}.ReleaseDLL|Win32.Build.0 = ReleaseDLL|Win32 + {016C739D-6389-43BF-8D88-24B2BF6F620F}.ReleaseDLL|x64.ActiveCfg = ReleaseDLL|x64 + {016C739D-6389-43BF-8D88-24B2BF6F620F}.ReleaseDLL|x64.Build.0 = ReleaseDLL|x64 + {1D257A17-D254-42E5-82D6-1C87A6EC775A}.Debug|Win32.ActiveCfg = Debug|Win32 + {1D257A17-D254-42E5-82D6-1C87A6EC775A}.Debug|Win32.Build.0 = Debug|Win32 + {1D257A17-D254-42E5-82D6-1C87A6EC775A}.Debug|x64.ActiveCfg = Debug|x64 + {1D257A17-D254-42E5-82D6-1C87A6EC775A}.Debug|x64.Build.0 = Debug|x64 + {1D257A17-D254-42E5-82D6-1C87A6EC775A}.DebugDLL_fixed|Win32.ActiveCfg = DebugDLL_fixed|Win32 + {1D257A17-D254-42E5-82D6-1C87A6EC775A}.DebugDLL_fixed|Win32.Build.0 = DebugDLL_fixed|Win32 + {1D257A17-D254-42E5-82D6-1C87A6EC775A}.DebugDLL_fixed|x64.ActiveCfg = DebugDLL_fixed|x64 + {1D257A17-D254-42E5-82D6-1C87A6EC775A}.DebugDLL_fixed|x64.Build.0 = DebugDLL_fixed|x64 + {1D257A17-D254-42E5-82D6-1C87A6EC775A}.DebugDLL|Win32.ActiveCfg = DebugDLL|Win32 + {1D257A17-D254-42E5-82D6-1C87A6EC775A}.DebugDLL|Win32.Build.0 = DebugDLL|Win32 + {1D257A17-D254-42E5-82D6-1C87A6EC775A}.DebugDLL|x64.ActiveCfg = DebugDLL|x64 + {1D257A17-D254-42E5-82D6-1C87A6EC775A}.DebugDLL|x64.Build.0 = DebugDLL|x64 + {1D257A17-D254-42E5-82D6-1C87A6EC775A}.Release|Win32.ActiveCfg = Release|Win32 + {1D257A17-D254-42E5-82D6-1C87A6EC775A}.Release|Win32.Build.0 = Release|Win32 + {1D257A17-D254-42E5-82D6-1C87A6EC775A}.Release|x64.ActiveCfg = Release|x64 + {1D257A17-D254-42E5-82D6-1C87A6EC775A}.Release|x64.Build.0 = Release|x64 + {1D257A17-D254-42E5-82D6-1C87A6EC775A}.ReleaseDLL_fixed|Win32.ActiveCfg = ReleaseDLL_fixed|Win32 + {1D257A17-D254-42E5-82D6-1C87A6EC775A}.ReleaseDLL_fixed|Win32.Build.0 = ReleaseDLL_fixed|Win32 + {1D257A17-D254-42E5-82D6-1C87A6EC775A}.ReleaseDLL_fixed|x64.ActiveCfg = ReleaseDLL_fixed|x64 + {1D257A17-D254-42E5-82D6-1C87A6EC775A}.ReleaseDLL_fixed|x64.Build.0 = ReleaseDLL_fixed|x64 + {1D257A17-D254-42E5-82D6-1C87A6EC775A}.ReleaseDLL|Win32.ActiveCfg = ReleaseDLL|Win32 + {1D257A17-D254-42E5-82D6-1C87A6EC775A}.ReleaseDLL|Win32.Build.0 = ReleaseDLL|Win32 + {1D257A17-D254-42E5-82D6-1C87A6EC775A}.ReleaseDLL|x64.ActiveCfg = ReleaseDLL|x64 + {1D257A17-D254-42E5-82D6-1C87A6EC775A}.ReleaseDLL|x64.Build.0 = ReleaseDLL|x64 + {8578322A-1883-486B-B6FA-E0094B65C9F2}.Debug|Win32.ActiveCfg = Debug|Win32 + {8578322A-1883-486B-B6FA-E0094B65C9F2}.Debug|Win32.Build.0 = Debug|Win32 + {8578322A-1883-486B-B6FA-E0094B65C9F2}.Debug|x64.ActiveCfg = Debug|x64 + {8578322A-1883-486B-B6FA-E0094B65C9F2}.Debug|x64.Build.0 = Debug|x64 + {8578322A-1883-486B-B6FA-E0094B65C9F2}.DebugDLL_fixed|Win32.ActiveCfg = DebugDLL_fixed|Win32 + {8578322A-1883-486B-B6FA-E0094B65C9F2}.DebugDLL_fixed|Win32.Build.0 = DebugDLL_fixed|Win32 + {8578322A-1883-486B-B6FA-E0094B65C9F2}.DebugDLL_fixed|x64.ActiveCfg = DebugDLL_fixed|x64 + {8578322A-1883-486B-B6FA-E0094B65C9F2}.DebugDLL_fixed|x64.Build.0 = DebugDLL_fixed|x64 + {8578322A-1883-486B-B6FA-E0094B65C9F2}.DebugDLL|Win32.ActiveCfg = DebugDLL|Win32 + {8578322A-1883-486B-B6FA-E0094B65C9F2}.DebugDLL|Win32.Build.0 = DebugDLL|Win32 + {8578322A-1883-486B-B6FA-E0094B65C9F2}.DebugDLL|x64.ActiveCfg = DebugDLL|x64 + {8578322A-1883-486B-B6FA-E0094B65C9F2}.DebugDLL|x64.Build.0 = DebugDLL|x64 + {8578322A-1883-486B-B6FA-E0094B65C9F2}.Release|Win32.ActiveCfg = Release|Win32 + {8578322A-1883-486B-B6FA-E0094B65C9F2}.Release|Win32.Build.0 = Release|Win32 + {8578322A-1883-486B-B6FA-E0094B65C9F2}.Release|x64.ActiveCfg = Release|x64 + {8578322A-1883-486B-B6FA-E0094B65C9F2}.Release|x64.Build.0 = Release|x64 + {8578322A-1883-486B-B6FA-E0094B65C9F2}.ReleaseDLL_fixed|Win32.ActiveCfg = ReleaseDLL_fixed|Win32 + {8578322A-1883-486B-B6FA-E0094B65C9F2}.ReleaseDLL_fixed|Win32.Build.0 = ReleaseDLL_fixed|Win32 + {8578322A-1883-486B-B6FA-E0094B65C9F2}.ReleaseDLL_fixed|x64.ActiveCfg = ReleaseDLL_fixed|x64 + {8578322A-1883-486B-B6FA-E0094B65C9F2}.ReleaseDLL_fixed|x64.Build.0 = ReleaseDLL_fixed|x64 + {8578322A-1883-486B-B6FA-E0094B65C9F2}.ReleaseDLL|Win32.ActiveCfg = ReleaseDLL|Win32 + {8578322A-1883-486B-B6FA-E0094B65C9F2}.ReleaseDLL|Win32.Build.0 = ReleaseDLL|Win32 + {8578322A-1883-486B-B6FA-E0094B65C9F2}.ReleaseDLL|x64.ActiveCfg = ReleaseDLL|x64 + {8578322A-1883-486B-B6FA-E0094B65C9F2}.ReleaseDLL|x64.Build.0 = ReleaseDLL|x64 + {84DAA768-1A38-4312-BB61-4C78BB59E5B8}.Debug|Win32.ActiveCfg = Debug|Win32 + {84DAA768-1A38-4312-BB61-4C78BB59E5B8}.Debug|Win32.Build.0 = Debug|Win32 + {84DAA768-1A38-4312-BB61-4C78BB59E5B8}.Debug|x64.ActiveCfg = Debug|x64 + {84DAA768-1A38-4312-BB61-4C78BB59E5B8}.Debug|x64.Build.0 = Debug|x64 + {84DAA768-1A38-4312-BB61-4C78BB59E5B8}.DebugDLL_fixed|Win32.ActiveCfg = DebugDLL_fixed|Win32 + {84DAA768-1A38-4312-BB61-4C78BB59E5B8}.DebugDLL_fixed|Win32.Build.0 = DebugDLL_fixed|Win32 + {84DAA768-1A38-4312-BB61-4C78BB59E5B8}.DebugDLL_fixed|x64.ActiveCfg = DebugDLL_fixed|x64 + {84DAA768-1A38-4312-BB61-4C78BB59E5B8}.DebugDLL_fixed|x64.Build.0 = DebugDLL_fixed|x64 + {84DAA768-1A38-4312-BB61-4C78BB59E5B8}.DebugDLL|Win32.ActiveCfg = DebugDLL|Win32 + {84DAA768-1A38-4312-BB61-4C78BB59E5B8}.DebugDLL|Win32.Build.0 = DebugDLL|Win32 + {84DAA768-1A38-4312-BB61-4C78BB59E5B8}.DebugDLL|x64.ActiveCfg = DebugDLL|x64 + {84DAA768-1A38-4312-BB61-4C78BB59E5B8}.DebugDLL|x64.Build.0 = DebugDLL|x64 + {84DAA768-1A38-4312-BB61-4C78BB59E5B8}.Release|Win32.ActiveCfg = Release|Win32 + {84DAA768-1A38-4312-BB61-4C78BB59E5B8}.Release|Win32.Build.0 = Release|Win32 + {84DAA768-1A38-4312-BB61-4C78BB59E5B8}.Release|x64.ActiveCfg = Release|x64 + {84DAA768-1A38-4312-BB61-4C78BB59E5B8}.Release|x64.Build.0 = Release|x64 + {84DAA768-1A38-4312-BB61-4C78BB59E5B8}.ReleaseDLL_fixed|Win32.ActiveCfg = ReleaseDLL_fixed|Win32 + {84DAA768-1A38-4312-BB61-4C78BB59E5B8}.ReleaseDLL_fixed|Win32.Build.0 = ReleaseDLL_fixed|Win32 + {84DAA768-1A38-4312-BB61-4C78BB59E5B8}.ReleaseDLL_fixed|x64.ActiveCfg = ReleaseDLL_fixed|x64 + {84DAA768-1A38-4312-BB61-4C78BB59E5B8}.ReleaseDLL_fixed|x64.Build.0 = ReleaseDLL_fixed|x64 + {84DAA768-1A38-4312-BB61-4C78BB59E5B8}.ReleaseDLL|Win32.ActiveCfg = ReleaseDLL|Win32 + {84DAA768-1A38-4312-BB61-4C78BB59E5B8}.ReleaseDLL|Win32.Build.0 = ReleaseDLL|Win32 + {84DAA768-1A38-4312-BB61-4C78BB59E5B8}.ReleaseDLL|x64.ActiveCfg = ReleaseDLL|x64 + {84DAA768-1A38-4312-BB61-4C78BB59E5B8}.ReleaseDLL|x64.Build.0 = ReleaseDLL|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/extern/opus/win32/VS2015/opus.vcxproj b/extern/opus/win32/VS2015/opus.vcxproj new file mode 100644 index 0000000..34b1233 --- /dev/null +++ b/extern/opus/win32/VS2015/opus.vcxproj @@ -0,0 +1,399 @@ + + + + + DebugDLL_fixed + Win32 + + + DebugDLL_fixed + x64 + + + DebugDLL + Win32 + + + DebugDLL + x64 + + + Debug + Win32 + + + Debug + x64 + + + ReleaseDLL_fixed + Win32 + + + ReleaseDLL_fixed + x64 + + + ReleaseDLL + Win32 + + + ReleaseDLL + x64 + + + Release + Win32 + + + Release + x64 + + + + Win32Proj + opus + {219EC965-228A-1824-174D-96449D05F88A} + + + + StaticLibrary + v140 + + + DynamicLibrary + v140 + + + DynamicLibrary + v140 + + + StaticLibrary + v140 + + + DynamicLibrary + v140 + + + DynamicLibrary + v140 + + + StaticLibrary + v140 + + + DynamicLibrary + v140 + + + DynamicLibrary + v140 + + + StaticLibrary + v140 + + + DynamicLibrary + v140 + + + DynamicLibrary + v140 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ..\..\silk\fixed;..\..\silk\float;%(AdditionalIncludeDirectories) + DLL_EXPORT;%(PreprocessorDefinitions) + FIXED_POINT;%(PreprocessorDefinitions) + /arch:IA32 %(AdditionalOptions) + + + /ignore:4221 %(AdditionalOptions) + + + "$(ProjectDir)..\..\win32\genversion.bat" "$(ProjectDir)..\..\win32\version.h" PACKAGE_VERSION + Generating version.h + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 4244;%(DisableSpecificWarnings) + + + + + + + + + + + + + + + false + + + false + + + true + + + + + + + true + + + true + + + false + + + + + + + + diff --git a/extern/opus/win32/VS2015/opus.vcxproj.filters b/extern/opus/win32/VS2015/opus.vcxproj.filters new file mode 100644 index 0000000..8c61d6a --- /dev/null +++ b/extern/opus/win32/VS2015/opus.vcxproj.filters @@ -0,0 +1,585 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + diff --git a/extern/opus/win32/VS2015/opus_demo.vcxproj b/extern/opus/win32/VS2015/opus_demo.vcxproj new file mode 100644 index 0000000..f4344e5 --- /dev/null +++ b/extern/opus/win32/VS2015/opus_demo.vcxproj @@ -0,0 +1,171 @@ + + + + + DebugDLL_fixed + Win32 + + + DebugDLL_fixed + x64 + + + DebugDLL + Win32 + + + DebugDLL + x64 + + + Debug + Win32 + + + Debug + x64 + + + ReleaseDLL_fixed + Win32 + + + ReleaseDLL_fixed + x64 + + + ReleaseDLL + Win32 + + + ReleaseDLL + x64 + + + Release + Win32 + + + Release + x64 + + + + + {219ec965-228a-1824-174d-96449d05f88a} + + + + + + + {016C739D-6389-43BF-8D88-24B2BF6F620F} + Win32Proj + opus_demo + + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/extern/opus/win32/VS2015/opus_demo.vcxproj.filters b/extern/opus/win32/VS2015/opus_demo.vcxproj.filters new file mode 100644 index 0000000..2eb113a --- /dev/null +++ b/extern/opus/win32/VS2015/opus_demo.vcxproj.filters @@ -0,0 +1,22 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + \ No newline at end of file diff --git a/extern/opus/win32/VS2015/test_opus_api.vcxproj b/extern/opus/win32/VS2015/test_opus_api.vcxproj new file mode 100644 index 0000000..7cae131 --- /dev/null +++ b/extern/opus/win32/VS2015/test_opus_api.vcxproj @@ -0,0 +1,171 @@ + + + + + DebugDLL_fixed + Win32 + + + DebugDLL_fixed + x64 + + + DebugDLL + Win32 + + + DebugDLL + x64 + + + Debug + Win32 + + + Debug + x64 + + + ReleaseDLL_fixed + Win32 + + + ReleaseDLL_fixed + x64 + + + ReleaseDLL + Win32 + + + ReleaseDLL + x64 + + + Release + Win32 + + + Release + x64 + + + + + + + + {219ec965-228a-1824-174d-96449d05f88a} + + + + {1D257A17-D254-42E5-82D6-1C87A6EC775A} + Win32Proj + test_opus_api + + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/extern/opus/win32/VS2015/test_opus_api.vcxproj.filters b/extern/opus/win32/VS2015/test_opus_api.vcxproj.filters new file mode 100644 index 0000000..383d19f --- /dev/null +++ b/extern/opus/win32/VS2015/test_opus_api.vcxproj.filters @@ -0,0 +1,14 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + + + Source Files + + + \ No newline at end of file diff --git a/extern/opus/win32/VS2015/test_opus_decode.vcxproj b/extern/opus/win32/VS2015/test_opus_decode.vcxproj new file mode 100644 index 0000000..df01dca --- /dev/null +++ b/extern/opus/win32/VS2015/test_opus_decode.vcxproj @@ -0,0 +1,171 @@ + + + + + DebugDLL_fixed + Win32 + + + DebugDLL_fixed + x64 + + + DebugDLL + Win32 + + + DebugDLL + x64 + + + Debug + Win32 + + + Debug + x64 + + + ReleaseDLL_fixed + Win32 + + + ReleaseDLL_fixed + x64 + + + ReleaseDLL + Win32 + + + ReleaseDLL + x64 + + + Release + Win32 + + + Release + x64 + + + + + + + + {219ec965-228a-1824-174d-96449d05f88a} + + + + {8578322A-1883-486B-B6FA-E0094B65C9F2} + Win32Proj + test_opus_api + + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/extern/opus/win32/VS2015/test_opus_decode.vcxproj.filters b/extern/opus/win32/VS2015/test_opus_decode.vcxproj.filters new file mode 100644 index 0000000..3036a4e --- /dev/null +++ b/extern/opus/win32/VS2015/test_opus_decode.vcxproj.filters @@ -0,0 +1,14 @@ + + + + + {4a0dd677-931f-4728-afe5-b761149fc7eb} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + + + Source Files + + + \ No newline at end of file diff --git a/extern/opus/win32/VS2015/test_opus_encode.vcxproj b/extern/opus/win32/VS2015/test_opus_encode.vcxproj new file mode 100644 index 0000000..405efee --- /dev/null +++ b/extern/opus/win32/VS2015/test_opus_encode.vcxproj @@ -0,0 +1,172 @@ + + + + + DebugDLL_fixed + Win32 + + + DebugDLL_fixed + x64 + + + DebugDLL + Win32 + + + DebugDLL + x64 + + + Debug + Win32 + + + Debug + x64 + + + ReleaseDLL_fixed + Win32 + + + ReleaseDLL_fixed + x64 + + + ReleaseDLL + Win32 + + + ReleaseDLL + x64 + + + Release + Win32 + + + Release + x64 + + + + + + + + + {219ec965-228a-1824-174d-96449d05f88a} + + + + {84DAA768-1A38-4312-BB61-4C78BB59E5B8} + Win32Proj + test_opus_api + + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + Application + v140 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/extern/opus/win32/VS2015/test_opus_encode.vcxproj.filters b/extern/opus/win32/VS2015/test_opus_encode.vcxproj.filters new file mode 100644 index 0000000..4ed3bb9 --- /dev/null +++ b/extern/opus/win32/VS2015/test_opus_encode.vcxproj.filters @@ -0,0 +1,17 @@ + + + + + {546c8d9a-103e-4f78-972b-b44e8d3c8aba} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + + + Source Files + + + Source Files + + + \ No newline at end of file diff --git a/extern/opus/win32/genversion.bat b/extern/opus/win32/genversion.bat new file mode 100644 index 0000000..1def746 --- /dev/null +++ b/extern/opus/win32/genversion.bat @@ -0,0 +1,37 @@ +@echo off + +setlocal enableextensions enabledelayedexpansion + +for /f %%v in ('cd "%~dp0.." ^&^& git status ^>NUL 2^>NUL ^&^& git describe --tags --match "v*" --dirty 2^>NUL') do set version=%%v + +if not "%version%"=="" set version=!version:~1! && goto :gotversion + +if exist "%~dp0..\package_version" goto :getversion + +echo Git cannot be found, nor can package_version. Generating unknown version. + +set version=unknown + +goto :gotversion + +:getversion + +for /f "delims== tokens=2" %%v in (%~dps0..\package_version) do set version=%%v +set version=!version:"=! + +:gotversion + +set version=!version: =! +set version_out=#define %~2 "%version%" + +echo %version_out%> "%~1_temp" + +echo n | comp "%~1_temp" "%~1" > NUL 2> NUL + +if not errorlevel 1 goto exit + +copy /y "%~1_temp" "%~1" + +:exit + +del "%~1_temp" diff --git a/extern/opusfile/.appveyor.yml b/extern/opusfile/.appveyor.yml new file mode 100644 index 0000000..33ed6bd --- /dev/null +++ b/extern/opusfile/.appveyor.yml @@ -0,0 +1,58 @@ +image: Visual Studio 2015 +configuration: +- Debug +- Release +- Release-NoHTTP + +platform: +- Win32 +- x64 + +environment: + opus_url: https://ci.appveyor.com/api/projects/$(APPVEYOR_ACCOUNT_NAME)/opus/artifacts/opus.zip + +install: +- cd %APPVEYOR_BUILD_FOLDER%\.. +- 'curl -LOG --data-urlencode "job=Configuration: %CONFIGURATION:-NoHTTP=%; Platform: %PLATFORM%" %OPUS_URL%' +- 7z x opus.zip -oopus-artifacts +- move /Y opus-artifacts opus +- git clone -q https://github.com/xiph/ogg.git ogg +- msbuild ogg\win32\VS2015\libogg_static.sln /p:Configuration=%CONFIGURATION:-NoHTTP=%;Platform=%PLATFORM% /m /v:minimal /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" +- if %CONFIGURATION:-NoHTTP=%==%CONFIGURATION% git clone -q --branch=OpenSSL_1_0_2-stable https://github.com/openssl/openssl.git openssl +- ps: >- + If ($env:Platform -Match "Win32") { + $env:VCVARS_PLATFORM="x86" + $env:OPENSSL_TARGET="VC-WIN32" + $env:DO="do_nasm" + } Else { + $env:VCVARS_PLATFORM="amd64" + $env:OPENSSL_TARGET="VC-WIN64A" + $env:DO="do_win64a" + } +- if %CONFIGURATION:-NoHTTP=%==%CONFIGURATION% chocolatey install -y nasm +- if %CONFIGURATION:-NoHTTP=%==%CONFIGURATION% set PATH=%PROGRAMFILES%\nasm;%PATH% +- if %CONFIGURATION:-NoHTTP=%==%CONFIGURATION% call "%VS140COMNTOOLS%\..\..\VC\vcvarsall.bat" %VCVARS_PLATFORM% +- if %CONFIGURATION:-NoHTTP=%==%CONFIGURATION% cd openssl +# without prefix, libs end up in out32 for both 32 and 64-bit +- if %CONFIGURATION:-NoHTTP=%==%CONFIGURATION% perl Configure %OPENSSL_TARGET% --prefix=%CD%\%PLATFORM%\Release +- if %CONFIGURATION:-NoHTTP=%==%CONFIGURATION% call ms\%DO% +- if %CONFIGURATION:-NoHTTP=%==%CONFIGURATION% nmake /f ms\nt.mak +- if %CONFIGURATION:-NoHTTP=%==%CONFIGURATION% nmake /f ms\nt.mak install +# prevents warning 4099 on linking +- if %CONFIGURATION:-NoHTTP=%==%CONFIGURATION% copy /B tmp32\lib.pdb %CD%\%PLATFORM%\Release\lib\lib.pdb +- cd %APPVEYOR_BUILD_FOLDER% + +build: + project: win32\VS2015\opusfile.sln + parallel: true + verbosity: minimal + +after_build: +- if %CONFIGURATION:-NoHTTP=%==%CONFIGURATION% copy /B %APPVEYOR_BUILD_FOLDER%\..\openssl\%PLATFORM%\Release\lib\* win32\VS2015\%PLATFORM%\%CONFIGURATION%\ +- if %CONFIGURATION:-NoHTTP=%==%CONFIGURATION% mkdir include\openssl +- if %CONFIGURATION:-NoHTTP=%==%CONFIGURATION% copy /B %APPVEYOR_BUILD_FOLDER%\..\openssl\inc32\openssl include\openssl\ +- 7z a opusfile.zip win32\VS2015\%PLATFORM%\%CONFIGURATION%\opusfile.??? include\ +- if %CONFIGURATION:-NoHTTP=%==%CONFIGURATION% 7z a opusfile.zip win32\VS2015\%PLATFORM%\%CONFIGURATION%\lib.pdb win32\VS2015\%PLATFORM%\%CONFIGURATION%\*.lib + +artifacts: +- path: opusfile.zip diff --git a/extern/opusfile/.gitattributes b/extern/opusfile/.gitattributes new file mode 100644 index 0000000..649c810 --- /dev/null +++ b/extern/opusfile/.gitattributes @@ -0,0 +1,10 @@ +.gitignore export-ignore +.gitattributes export-ignore + +update_version export-ignore + +*.bat eol=crlf +*.sln eol=crlf +*.vcxproj eol=crlf +*.vcxproj.filters eol=crlf +common.props eol=crlf diff --git a/extern/opusfile/.gitignore b/extern/opusfile/.gitignore new file mode 100644 index 0000000..574d0c0 --- /dev/null +++ b/extern/opusfile/.gitignore @@ -0,0 +1,49 @@ +*.a +*.exe +*.la +*.lo +*.o +*.sw* +*~ +.deps +.dirstamp +.libs +/Makefile +Makefile.in +aclocal.m4 +autom4te.cache/ +config.guess +config.log +config.status +config.sub +configure +config.h.in +config.h +compile +depcomp +doc/Doxyfile +doc/doxygen-build.stamp +doc/html +doc/latex +examples/opusfile_example +examples/seeking_example +install-sh +libopusfile-*.tar.* +libtool +ltmain.sh +m4/libtool.m4 +m4/ltoptions.m4 +m4/ltsugar.m4 +m4/ltversion.m4 +m4/lt~obsolete.m4 +missing +opusfile.pc +opusfile-uninstalled.pc +opusurl.pc +opusurl-uninstalled.pc +package_version +stamp-h1 +test-driver +unix/objs +unix/opusfile_example +unix/seeking_example diff --git a/extern/opusfile/.travis.yml b/extern/opusfile/.travis.yml new file mode 100644 index 0000000..e65ba45 --- /dev/null +++ b/extern/opusfile/.travis.yml @@ -0,0 +1,25 @@ +language: c + +compiler: + - gcc + - clang + +os: + - linux + - osx + +addons: + apt: + packages: + - libogg-dev + - libopus-dev + +env: PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/usr/local/opt/openssl/lib/pkgconfig + +install: if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update && brew bundle; fi + +script: + - ./autogen.sh + - ./configure + - make + - make distcheck diff --git a/extern/opusfile/AUTHORS b/extern/opusfile/AUTHORS new file mode 100644 index 0000000..d0ac09d --- /dev/null +++ b/extern/opusfile/AUTHORS @@ -0,0 +1,5 @@ +Timothy B. Terriberry +Ralph Giles +Christopher "Monty" Montgomery (original libvorbisfile) +Gregory Maxwell (noise shaping dithering) +nu774 (original winsock support) diff --git a/extern/opusfile/Brewfile b/extern/opusfile/Brewfile new file mode 100644 index 0000000..c5f3a82 --- /dev/null +++ b/extern/opusfile/Brewfile @@ -0,0 +1,7 @@ +brew 'opus' +brew 'libogg' +brew 'openssl' +brew 'autoconf' +brew 'automake' +brew 'libtool' +brew 'pkg-config' diff --git a/extern/opusfile/COPYING b/extern/opusfile/COPYING new file mode 100644 index 0000000..7b53d66 --- /dev/null +++ b/extern/opusfile/COPYING @@ -0,0 +1,28 @@ +Copyright (c) 1994-2013 Xiph.Org Foundation and contributors + +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 the Xiph.Org Foundation nor the names of its +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 FOUNDATION +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. diff --git a/extern/opusfile/Makefile.am b/extern/opusfile/Makefile.am new file mode 100644 index 0000000..a750a86 --- /dev/null +++ b/extern/opusfile/Makefile.am @@ -0,0 +1,143 @@ +ACLOCAL_AMFLAGS = -I m4 + +AM_CFLAGS = -I$(top_srcdir)/include $(DEPS_CFLAGS) + +dist_doc_DATA = COPYING AUTHORS README.md + +opusincludedir = ${includedir}/opus +opusinclude_HEADERS = include/opusfile.h + +lib_LTLIBRARIES = libopusfile.la libopusurl.la +libopusfile_la_SOURCES = \ + src/info.c \ + src/internal.c src/internal.h \ + src/opusfile.c src/stream.c +libopusfile_la_LIBADD = $(DEPS_LIBS) $(lrintf_lib) +libopusfile_la_LDFLAGS = -no-undefined \ + -version-info @OP_LT_CURRENT@:@OP_LT_REVISION@:@OP_LT_AGE@ + +libopusurl_la_SOURCES = src/http.c src/internal.c src/internal.h +libopusurl_la_CFLAGS = $(AM_CFLAGS) $(URL_DEPS_CFLAGS) +libopusurl_la_LIBADD = libopusfile.la $(URL_DEPS_LIBS) +libopusurl_la_LDFLAGS = -no-undefined \ + -version-info @OP_LT_CURRENT@:@OP_LT_REVISION@:@OP_LT_AGE@ + +if OP_ENABLE_EXAMPLES +noinst_PROGRAMS = examples/opusfile_example examples/seeking_example +endif + +examples_opusfile_example_SOURCES = examples/opusfile_example.c +examples_seeking_example_SOURCES = examples/seeking_example.c +examples_opusfile_example_LDADD = libopusurl.la libopusfile.la +examples_seeking_example_LDADD = libopusurl.la libopusfile.la + +if OP_WIN32 +if OP_ENABLE_HTTP +libopusurl_la_SOURCES += src/wincerts.c src/winerrno.h +libopusurl_la_LIBADD += -lws2_32 -lcrypt32 +endif +examples_opusfile_example_SOURCES += examples/win32utf8.c examples/win32utf8.h +examples_seeking_example_SOURCES += examples/win32utf8.c examples/win32utf8.h +endif + +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = opusfile.pc opusurl.pc + +debug: + $(MAKE) CFLAGS="${CFLAGS} -O0 -ggdb -DOP_ENABLE_ASSERTIONS" all + +EXTRA_DIST = \ + opusfile.pc.in \ + opusurl.pc.in \ + opusfile-uninstalled.pc.in \ + opusurl-uninstalled.pc.in \ + doc/Doxyfile.in \ + doc/opus_logo.svg \ + doc/Makefile \ + unix/Makefile \ + win32/VS2015/opusfile.sln \ + win32/VS2015/opusfile.vcxproj \ + win32/VS2015/opusfile.vcxproj.filters \ + win32/VS2015/opusfile_example.vcxproj \ + win32/VS2015/opusfile_example.vcxproj.filters \ + win32/VS2015/seeking_example.vcxproj \ + win32/VS2015/seeking_example.vcxproj.filters + +# Targets to build and install just the library without the docs +opusfile install-opusfile: NO_DOXYGEN = 1 + +opusfile: all +install-opusfile: install + +# Or just the docs +docs: doc/doxygen-build.stamp + +install-docs: + @if [ -z "$(NO_DOXYGEN)" ]; then \ + ( cd doc && \ + echo "Installing documentation in $(DESTDIR)$(docdir)"; \ + $(INSTALL) -d $(DESTDIR)$(docdir)/html/search; \ + for f in `find html -type f \! -name "installdox"` ; do \ + $(INSTALL_DATA) $$f $(DESTDIR)$(docdir)/$$f; \ + done ) \ + fi + +doc/doxygen-build.stamp: doc/Doxyfile $(top_srcdir)/doc/opus_logo.svg \ + $(top_srcdir)/include/*.h + @[ -n "$(NO_DOXYGEN)" ] || ( cd doc && doxygen && touch $(@F) ) + + +if HAVE_DOXYGEN + +# Or everything (by default) +all-local: docs + +install-data-local: install-docs + +clean-local: + $(RM) -r doc/html + $(RM) -r doc/latex + $(RM) doc/doxygen-build.stamp + +uninstall-local: + $(RM) -r $(DESTDIR)$(docdir)/html + +endif + +# We check this every time make is run, with configure.ac being touched to +# trigger an update of the build system files if update_version changes the +# current PACKAGE_VERSION (or if package_version was modified manually by a +# user with either AUTO_UPDATE=no or no update_version script present - the +# latter being the normal case for tarball releases). +# +# We can't just add the package_version file to CONFIGURE_DEPENDENCIES since +# simply running autoconf will not actually regenerate configure for us when +# the content of that file changes (due to autoconf dependency checking not +# knowing about that without us creating yet another file for it to include). +# +# The MAKECMDGOALS check is a gnu-make'ism, but will degrade 'gracefully' for +# makes that don't support it. The only loss of functionality is not forcing +# an update of package_version for `make dist` if AUTO_UPDATE=no, but that is +# unlikely to be a real problem for any real user. +$(top_srcdir)/configure.ac: force + @case "$(MAKECMDGOALS)" in \ + dist-hook) exit 0 ;; \ + dist-* | dist | distcheck | distclean) _arg=release ;; \ + esac; \ + if ! $(top_srcdir)/update_version $$_arg 2> /dev/null; then \ + if [ ! -e $(top_srcdir)/package_version ]; then \ + echo 'PACKAGE_VERSION="unknown"' > $(top_srcdir)/package_version; \ + fi; \ + . $(top_srcdir)/package_version || exit 1; \ + [ "$(PACKAGE_VERSION)" != "$$PACKAGE_VERSION" ] || exit 0; \ + fi; \ + touch $@ + +force: + +# Create a minimal package_version file when make dist is run. +dist-hook: + echo 'PACKAGE_VERSION="$(PACKAGE_VERSION)"' > $(top_distdir)/package_version + + +.PHONY: opusfile install-opusfile docs install-docs diff --git a/extern/opusfile/README.md b/extern/opusfile/README.md new file mode 100644 index 0000000..5671aec --- /dev/null +++ b/extern/opusfile/README.md @@ -0,0 +1,18 @@ +# Opusfile + +[![Travis Build Status](https://travis-ci.org/xiph/opusfile.svg?branch=master)](https://travis-ci.org/xiph/opusfile) +[![Jenkins Build Status](https://mf4.xiph.org/jenkins/buildStatus/icon?job=opusfile-autotools)](https://mf4.xiph.org/jenkins/view/opus/job/opusfile-autotools/) +[![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/github/xiph/opusfile?branch=master&svg=true)](https://ci.appveyor.com/project/rillian/opusfile) + +The opusfile and opusurl libraries provide a high-level API for +decoding and seeking within .opus files on disk or over http(s). + +opusfile depends on libopus and libogg. +opusurl depends on opusfile and openssl. + +The library is functional, but there are likely issues +we didn't find in our own testing. Please give feedback +in #opus on irc.freenode.net or at opus@xiph.org. + +Programming documentation is available in tree and online at +https://opus-codec.org/docs/ diff --git a/extern/opusfile/autogen.sh b/extern/opusfile/autogen.sh new file mode 100755 index 0000000..946f76a --- /dev/null +++ b/extern/opusfile/autogen.sh @@ -0,0 +1,10 @@ +#!/bin/sh +# Run this to set up the build system: configure, makefiles, etc. +set -e + +srcdir=`dirname $0` +test -n "$srcdir" && cd "$srcdir" + +echo "Updating build configuration files for opusfile, please wait...." + +autoreconf -isf diff --git a/extern/opusfile/ci/autotools.sh b/extern/opusfile/ci/autotools.sh new file mode 100755 index 0000000..79543e5 --- /dev/null +++ b/extern/opusfile/ci/autotools.sh @@ -0,0 +1,65 @@ +# Continuous integration build script for opusfile. +# This script is run by automated frameworks to verify commits +# see https://mf4.xiph.org/jenkins/job/opusfile-autotools/ + +# This is intended to be run from the top-level source directory. + +set -x + +# WARNING: clobbers outside the current tree! +rm -f ../opus +ln -s /srv/jenkins/jobs/opus/workspace ../opus +rm -f ../ogg +ln -s /srv/jenkins/jobs/libogg/workspace ../ogg + +# HACK: libtool can't link a dynamic library to a static +# library, and the 'unix' makefile build can't link to +# a libopus.la. As a work around, hack our own pkg-config +# file for the uninstalled opus library we want to build +# against. +cat < opus-uninstalled.pc +# Opus codec uninstalled pkg-config file +# hacked up for the opusfile autotools build. + +libdir=\${pcfiledir}/../opus +includedir=\${libdir}/include + +Name: opus uninstalled for opusfile +Description: Opus IETF audio codec (not installed) +Version: 1.0.1 +Requires: +Conflicts: +Libs: \${libdir}/libopus.la -lm +Cflags: -I\${includedir} +EOF + +cat < ogg-uninstalled.pc +# ogg uninstalled pkg-config file +# hacked up for the opusfile autotools build + +libdir=\${pcfiledir}/../ogg/src +includedir=\${pcfiledir}/../ogg/include + +Name: ogg uninstalled for opusfile +Description: ogg is a library for manipulating ogg bitstreams (not installed) +Version: 1.3.0 +Requires: +Conflicts: +Libs: \${libdir}/libogg.la +Cflags: -I\${includedir} +EOF + +PKG_CONFIG_PATH=$PWD + +# compile +./autogen.sh +./configure PKG_CONFIG_PATH=${PKG_CONFIG_PATH} +make clean +make + +# verify distribution target +make distcheck PKG_CONFIG_PATH=${PKG_CONFIG_PATH} + +# build the documentation +# currently fails on jenkins (debian stretch) +# make -C doc/latex diff --git a/extern/opusfile/ci/unix.sh b/extern/opusfile/ci/unix.sh new file mode 100755 index 0000000..8e7e7d1 --- /dev/null +++ b/extern/opusfile/ci/unix.sh @@ -0,0 +1,23 @@ +# Continuous integration build script for opusfile. +# This script is run by automated frameworks to verify commits +# see https://mf4.xiph.org/jenkins/job/opusfile-unix/ + +# This is intended to be run from the top-level source directory. + +set -x + +# WARNING: clobbers outside the current tree! +rm -f ../opus +ln -s /srv/jenkins/jobs/opus/workspace ../opus + +# compile +make -C unix PKG_CONFIG_PATH=$PWD/../opus clean +make -C unix PKG_CONFIG_PATH=$PWD/../opus + +# run any built-in tests +make -C unix PKG_CONFIG_PATH=$PWD/../opus check + +# build the documentation +make -C doc +# currently fails on jenkins (debian stretch) +# make -C doc/latex diff --git a/extern/opusfile/configure.ac b/extern/opusfile/configure.ac new file mode 100644 index 0000000..3f4a654 --- /dev/null +++ b/extern/opusfile/configure.ac @@ -0,0 +1,189 @@ +# autoconf source script for generating configure + +dnl The package_version file will be automatically synced to the git revision +dnl by the update_version script when configured in the repository, but will +dnl remain constant in tarball releases unless it is manually edited. +m4_define([CURRENT_VERSION], + m4_esyscmd([ ./update_version 2>/dev/null || true + if test -e package_version; then + . ./package_version + printf "$PACKAGE_VERSION" + else + printf "unknown" + fi ])) + +AC_INIT([opusfile],[CURRENT_VERSION],[opus@xiph.org]) +AC_CONFIG_SRCDIR([src/opusfile.c]) +AC_CONFIG_MACRO_DIR([m4]) + +AC_USE_SYSTEM_EXTENSIONS +AC_SYS_LARGEFILE + +AM_INIT_AUTOMAKE([1.11 foreign no-define dist-zip subdir-objects]) +AM_MAINTAINER_MODE([enable]) +LT_INIT + +m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) + +dnl Library versioning for libtool. +dnl Please update these for releases. +dnl CURRENT, REVISION, AGE +dnl - library source changed -> increment REVISION +dnl - interfaces added/removed/changed -> increment CURRENT, REVISION = 0 +dnl - interfaces added -> increment AGE +dnl - interfaces removed -> AGE = 0 + +OP_LT_CURRENT=4 +OP_LT_REVISION=4 +OP_LT_AGE=4 + +AC_SUBST(OP_LT_CURRENT) +AC_SUBST(OP_LT_REVISION) +AC_SUBST(OP_LT_AGE) + +CC_CHECK_CFLAGS_APPEND( + [-std=c89 -pedantic -Wall -Wextra -Wno-parentheses -Wno-long-long]) + +# Platform-specific tweaks +case $host in + *-mingw*) + # -std=c89 causes some warnings under mingw. + CC_CHECK_CFLAGS_APPEND([-U__STRICT_ANSI__]) + # We need WINNT>=0x501 (WindowsXP) for getaddrinfo/freeaddrinfo. + # It's okay to define this even when HTTP support is disabled, as it only + # affects header declarations, not linking (unless we actually use some + # XP-only functions). + AC_DEFINE_UNQUOTED(_WIN32_WINNT,0x501, + [We need at least WindowsXP for getaddrinfo/freeaddrinfo]) + host_mingw=true + ;; +esac +AM_CONDITIONAL(OP_WIN32, test "$host_mingw" = "true") + +AC_ARG_ENABLE([assertions], + AS_HELP_STRING([--enable-assertions], [Enable assertions in code]),, + enable_assertions=no) + +AS_IF([test "$enable_assertions" = "yes"], [ + AC_DEFINE([OP_ENABLE_ASSERTIONS], [1], [Enable assertions in code]) +]) + +AC_ARG_ENABLE([http], + AS_HELP_STRING([--disable-http], [Disable HTTP support]),, + enable_http=yes) + +AM_COND_IF(OP_WIN32, + AS_IF([test "$enable_http" != "no"], + AC_CHECK_HEADER([winsock2.h],, + AC_MSG_WARN([HTTP support requires a Winsock socket library.]) + enable_http=no + ) + ), + AS_IF([test "$enable_http" != "no"], + AC_CHECK_HEADER([sys/socket.h],, + AC_MSG_WARN([HTTP support requires a POSIX socket library.]) + enable_http=no + ) + ) +) +AC_SEARCH_LIBS(ftime, [compat], , [enable_http=no]) + +m4_ifndef([PKG_PROG_PKG_CONFIG], + [m4_fatal([Could not locate the pkg-config autoconf macros. +Please make sure pkg-config is installed and, if necessary, set the environment +variable ACLOCAL="aclocal -I/path/to/pkg.m4".])]) + +AS_IF([test "$enable_http" != "no"], [ + openssl="openssl" + AC_DEFINE([OP_ENABLE_HTTP], [1], [Enable HTTP support]) + PKG_CHECK_MODULES([URL_DEPS], [openssl]) +]) +AM_CONDITIONAL(OP_ENABLE_HTTP, [test "$enable_http" != "no"]) +AC_SUBST([openssl]) + +PKG_CHECK_MODULES([DEPS], [ogg >= 1.3 opus >= 1.0.1]) + +AC_ARG_ENABLE([fixed-point], + AS_HELP_STRING([--enable-fixed-point], [Enable fixed-point calculation]),, + enable_fixed_point=no) +AC_ARG_ENABLE([float], + AS_HELP_STRING([--disable-float], [Disable floating-point API]),, + enable_float=yes) + +AS_IF([test "$enable_float" = "no"], + [enable_fixed_point=yes + AC_DEFINE([OP_DISABLE_FLOAT_API], [1], [Disable floating-point API]) + ] +) + +AS_IF([test "$enable_fixed_point" = "yes"], + [AC_DEFINE([OP_FIXED_POINT], [1], [Enable fixed-point calculation])], + [dnl This only has to be tested for if float->fixed conversions are required + saved_LIBS="$LIBS" + AC_SEARCH_LIBS([lrintf], [m], [ + AC_DEFINE([OP_HAVE_LRINTF], [1], [Enable use of lrintf function]) + lrintf_notice=" + Library for lrintf() ......... ${ac_cv_search_lrintf}" + ]) + LIBS="$saved_LIBS" + ] +) + +AC_ARG_ENABLE([examples], + AS_HELP_STRING([--disable-examples], [Do not build example applications]),, + enable_examples=yes) +AM_CONDITIONAL([OP_ENABLE_EXAMPLES], [test "$enable_examples" = "yes"]) + +AS_CASE(["$ac_cv_search_lrintf"], + ["no"],[], + ["none required"],[], + [lrintf_lib="$ac_cv_search_lrintf"]) + +AC_SUBST([lrintf_lib]) + +CC_ATTRIBUTE_VISIBILITY([default], [ + CC_FLAG_VISIBILITY([CFLAGS="${CFLAGS} -fvisibility=hidden"]) +]) + +dnl Check for doxygen +AC_ARG_ENABLE([doc], + AS_HELP_STRING([--disable-doc], [Do not build API documentation]),, + [enable_doc=yes] +) + +AS_IF([test "$enable_doc" = "yes"], [ + AC_CHECK_PROG([HAVE_DOXYGEN], [doxygen], [yes], [no]) + AC_CHECK_PROG([HAVE_DOT], [dot], [yes], [no]) +],[ + HAVE_DOXYGEN=no +]) + +AM_CONDITIONAL([HAVE_DOXYGEN], [test "$HAVE_DOXYGEN" = "yes"]) + +AC_CONFIG_FILES([ + Makefile + opusfile.pc + opusurl.pc + opusfile-uninstalled.pc + opusurl-uninstalled.pc + doc/Doxyfile +]) +AC_CONFIG_HEADERS([config.h]) +AC_OUTPUT + +AC_MSG_NOTICE([ +------------------------------------------------------------------------ + $PACKAGE_NAME $PACKAGE_VERSION: Automatic configuration OK. + + Assertions ................... ${enable_assertions} + + HTTP support ................. ${enable_http} + Fixed-point .................. ${enable_fixed_point} + Floating-point API ........... ${enable_float}${lrintf_notice} + + Hidden visibility ............ ${cc_cv_flag_visibility} + + API code examples ............ ${enable_examples} + API documentation ............ ${enable_doc} +------------------------------------------------------------------------ +]) diff --git a/extern/opusfile/doc/Doxyfile.in b/extern/opusfile/doc/Doxyfile.in new file mode 100644 index 0000000..0fa3363 --- /dev/null +++ b/extern/opusfile/doc/Doxyfile.in @@ -0,0 +1,20 @@ +# Process with doxygen to generate API documentation + +PROJECT_NAME = @PACKAGE_NAME@ +PROJECT_NUMBER = @PACKAGE_VERSION@ +PROJECT_BRIEF = "Stand-alone decoder library for .opus files." +INPUT = @top_srcdir@/include/opusfile.h +OPTIMIZE_OUTPUT_FOR_C = YES + +QUIET = YES +WARNINGS = YES +WARN_IF_UNDOCUMENTED = YES +WARN_IF_DOC_ERROR = YES +WARN_NO_PARAMDOC = YES + +JAVADOC_AUTOBRIEF = YES +SORT_MEMBER_DOCS = NO + +HAVE_DOT = @HAVE_DOT@ + +PROJECT_LOGO = @top_srcdir@/doc/opus_logo.svg diff --git a/extern/opusfile/doc/opus_logo.svg b/extern/opusfile/doc/opus_logo.svg new file mode 100644 index 0000000..794dd1d --- /dev/null +++ b/extern/opusfile/doc/opus_logo.svg @@ -0,0 +1,157 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/extern/opusfile/doc/release.txt b/extern/opusfile/doc/release.txt new file mode 100644 index 0000000..8fe74d1 --- /dev/null +++ b/extern/opusfile/doc/release.txt @@ -0,0 +1,70 @@ += Release checklist = + +Source release: + +- Update OP_LT_* API versioning in configure.ac. +- Check for uncommitted changes to master. +- Tag the release commit with 'git tag -s vN.M'. + - Include release notes in the tag annotation. +- Verify 'make distcheck' produces a tarball with + the desired name. +- Push tag to public repo. +- Upload source package 'opusfile-${version}.tar.gz' + to website and verify file permissions. +- Update checksum files on website. +- Update links on . +- Add a copy of the documentation to + and update the links. + +Releases are commited to https://svn.xiph.org/releases/opus/ +which propagates to downloads.xiph.org, and copied manually +to https://archive.mozilla.org/pub/opus/ + +Release packages should also be manually attached to the corresponding +tag on the github mirror https://github.com/xiph/opusfile/releases + +Win32 binaries: + +- Assuming the mingw cross toolchain: +- run `make -C mingw` + - Downloads versions of libogg, opus, openssl. + - Compiles them. + - Compiles static opusfile and examples against the built deps. +- Compile dynamic opusfile with: + - ./configure --host=i686-w64-mingw32 --prefix=/path/to/builddir/mingw \ + PKG_CONFIG_PATH=/path/to/builddir/mingw/lib/pkgconfig + - make && make check && make -C doc/latex +- Add api docs to opus-codec.org. +- mkdir opusfile-${version}-win32 +- Copy AUTHORS COPYING README.md include/opusfile.h to the release dir. +- Merge changes between README.md and the version in the last + binary release. E.g. it's good to include versions of the dependencies, + release notes, etc. +- Convert README.md to DOS line endings. +- Copy .libs/libopusfile-0.dll to the release dir. +- Copy .libs/libopusfile.a to the release dir. +- Copy .libs/libopusfile.dll.a to the release dir. (May not be needed?) +- Copy ./lib/libopusurl-0.dll, etc. to the release dir. +- Copy ./bin/*.dll to the release dir for dependencies. +- Copy any other dependent dlls, e.g. on Fedora 23 I needed to copy + /usr/i686-w64-mingw32/sys-root/mingw/bin/libgcc_s_sjlj-1.dll + /usr/i686-w64-mingw32/sys-root/mingw/bin/libwinpthread-1.dll +- Copy doc/latex/refman.pdf to opusfile-${version}-win32/opusfile-${version}.pdf +- Copy examples/.libs/*.exe to the release dir. +- Strip *.dll *.a *.exe in the release dir. +- In the release dir, run: + sha256sum * > SHA256SUMS.txt + gpg --detach-sign --armor SHA256SUMS.txt +- In the parent directory, create the archive: + zip -r opusfile-${version}-win32.zip opusfile-${version}-win32/* +- Copy the archive to a clean system and verify the examples work + to make sure you've included all the necessary libraries. +- Upload the archive zipfile to websites. +- Verify file permissions and that it's available at the expected + URL. +- Update links on . +- Add doc/latex/refman as docs/opusfile_api-${version}.pdf on opus-codec.org +- Add doc/html as docs/opusfile_api-${version} on opus-codec.org + +Binary releases are copied manually to s3 to appear at +https://archive.mozilla.org/pub/mozilla.org/opus/win32/ diff --git a/extern/opusfile/examples/opusfile_example.c b/extern/opusfile/examples/opusfile_example.c new file mode 100644 index 0000000..190bbc9 --- /dev/null +++ b/extern/opusfile/examples/opusfile_example.c @@ -0,0 +1,389 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE libopusfile SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE libopusfile SOURCE CODE IS (C) COPYRIGHT 1994-2012 * + * by the Xiph.Org Foundation and contributors http://www.xiph.org/ * + * * + ********************************************************************/ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/*For fileno()*/ +#if !defined(_POSIX_SOURCE) +# define _POSIX_SOURCE 1 +#endif +#include +#include +#include +#include +#include +#if defined(_WIN32) +# include "win32utf8.h" +# undef fileno +# define fileno _fileno +#endif + +static void print_duration(FILE *_fp,ogg_int64_t _nsamples,int _frac){ + ogg_int64_t seconds; + ogg_int64_t minutes; + ogg_int64_t hours; + ogg_int64_t days; + ogg_int64_t weeks; + _nsamples+=_frac?24:24000; + seconds=_nsamples/48000; + _nsamples-=seconds*48000; + minutes=seconds/60; + seconds-=minutes*60; + hours=minutes/60; + minutes-=hours*60; + days=hours/24; + hours-=days*24; + weeks=days/7; + days-=weeks*7; + if(weeks)fprintf(_fp,"%liw",(long)weeks); + if(weeks||days)fprintf(_fp,"%id",(int)days); + if(weeks||days||hours){ + if(weeks||days)fprintf(_fp,"%02ih",(int)hours); + else fprintf(_fp,"%ih",(int)hours); + } + if(weeks||days||hours||minutes){ + if(weeks||days||hours)fprintf(_fp,"%02im",(int)minutes); + else fprintf(_fp,"%im",(int)minutes); + fprintf(_fp,"%02i",(int)seconds); + } + else fprintf(_fp,"%i",(int)seconds); + if(_frac)fprintf(_fp,".%03i",(int)(_nsamples/48)); + fprintf(_fp,"s"); +} + +static void print_size(FILE *_fp,opus_int64 _nbytes,int _metric, + const char *_spacer){ + static const char SUFFIXES[7]={' ','k','M','G','T','P','E'}; + opus_int64 val; + opus_int64 den; + opus_int64 round; + int base; + int shift; + base=_metric?1000:1024; + round=0; + den=1; + for(shift=0;shift<6;shift++){ + if(_nbytes>1; + } + val=(_nbytes+round)/den; + if(den>1&&val<10){ + if(den>=1000000000)val=(_nbytes+(round/100))/(den/100); + else val=(_nbytes*100+round)/den; + fprintf(_fp,"%li.%02i%s%c",(long)(val/100),(int)(val%100), + _spacer,SUFFIXES[shift]); + } + else if(den>1&&val<100){ + if(den>=1000000000)val=(_nbytes+(round/10))/(den/10); + else val=(_nbytes*10+round)/den; + fprintf(_fp,"%li.%i%s%c",(long)(val/10),(int)(val%10), + _spacer,SUFFIXES[shift]); + } + else fprintf(_fp,"%li%s%c",(long)val,_spacer,SUFFIXES[shift]); +} + +static void put_le32(unsigned char *_dst,opus_uint32 _x){ + _dst[0]=(unsigned char)(_x&0xFF); + _dst[1]=(unsigned char)(_x>>8&0xFF); + _dst[2]=(unsigned char)(_x>>16&0xFF); + _dst[3]=(unsigned char)(_x>>24&0xFF); +} + +/*Make a header for a 48 kHz, stereo, signed, 16-bit little-endian PCM WAV.*/ +static void make_wav_header(unsigned char _dst[44],ogg_int64_t _duration){ + /*The chunk sizes are set to 0x7FFFFFFF by default. + Many, though not all, programs will interpret this to mean the duration is + "undefined", and continue to read from the file so long as there is actual + data.*/ + static const unsigned char WAV_HEADER_TEMPLATE[44]={ + 'R','I','F','F',0xFF,0xFF,0xFF,0x7F, + 'W','A','V','E','f','m','t',' ', + 0x10,0x00,0x00,0x00,0x01,0x00,0x02,0x00, + 0x80,0xBB,0x00,0x00,0x00,0xEE,0x02,0x00, + 0x04,0x00,0x10,0x00,'d','a','t','a', + 0xFF,0xFF,0xFF,0x7F + }; + memcpy(_dst,WAV_HEADER_TEMPLATE,sizeof(WAV_HEADER_TEMPLATE)); + if(_duration>0){ + if(_duration>0x1FFFFFF6){ + fprintf(stderr,"WARNING: WAV output would be larger than 2 GB.\n"); + fprintf(stderr, + "Writing non-standard WAV header with invalid chunk sizes.\n"); + } + else{ + opus_uint32 audio_size; + audio_size=(opus_uint32)(_duration*4); + put_le32(_dst+4,audio_size+36); + put_le32(_dst+40,audio_size); + } + } +} + +int main(int _argc,const char **_argv){ + OggOpusFile *of; + ogg_int64_t duration; + unsigned char wav_header[44]; + int ret; + int is_ssl; + int output_seekable; +#if defined(_WIN32) + win32_utf8_setup(&_argc,&_argv); +#endif + if(_argc!=2){ + fprintf(stderr,"Usage: %s \n",_argv[0]); + return EXIT_FAILURE; + } + is_ssl=0; + if(strcmp(_argv[1],"-")==0){ + OpusFileCallbacks cb={NULL,NULL,NULL,NULL}; + of=op_open_callbacks(op_fdopen(&cb,fileno(stdin),"rb"),&cb,NULL,0,&ret); + } + else{ + OpusServerInfo info; + /*Try to treat the argument as a URL.*/ + of=op_open_url(_argv[1],&ret,OP_GET_SERVER_INFO(&info),NULL); +#if 0 + if(of==NULL){ + OpusFileCallbacks cb={NULL,NULL,NULL,NULL}; + void *fp; + /*For debugging: force a file to not be seekable.*/ + fp=op_fopen(&cb,_argv[1],"rb"); + cb.seek=NULL; + cb.tell=NULL; + of=op_open_callbacks(fp,&cb,NULL,0,NULL); + } +#else + if(of==NULL)of=op_open_file(_argv[1],&ret); +#endif + else{ + if(info.name!=NULL){ + fprintf(stderr,"Station name: %s\n",info.name); + } + if(info.description!=NULL){ + fprintf(stderr,"Station description: %s\n",info.description); + } + if(info.genre!=NULL){ + fprintf(stderr,"Station genre: %s\n",info.genre); + } + if(info.url!=NULL){ + fprintf(stderr,"Station homepage: %s\n",info.url); + } + if(info.bitrate_kbps>=0){ + fprintf(stderr,"Station bitrate: %u kbps\n", + (unsigned)info.bitrate_kbps); + } + if(info.is_public>=0){ + fprintf(stderr,"%s\n", + info.is_public?"Station is public.":"Station is private."); + } + if(info.server!=NULL){ + fprintf(stderr,"Server software: %s\n",info.server); + } + if(info.content_type!=NULL){ + fprintf(stderr,"Content-Type: %s\n",info.content_type); + } + is_ssl=info.is_ssl; + opus_server_info_clear(&info); + } + } + if(of==NULL){ + fprintf(stderr,"Failed to open file '%s': %i\n",_argv[1],ret); + return EXIT_FAILURE; + } + duration=0; + output_seekable=fseek(stdout,0,SEEK_CUR)!=-1; + if(op_seekable(of)){ + opus_int64 size; + fprintf(stderr,"Total number of links: %i\n",op_link_count(of)); + duration=op_pcm_total(of,-1); + fprintf(stderr,"Total duration: "); + print_duration(stderr,duration,3); + fprintf(stderr," (%li samples @ 48 kHz)\n",(long)duration); + size=op_raw_total(of,-1); + fprintf(stderr,"Total size: "); + print_size(stderr,size,0,""); + fprintf(stderr,"\n"); + } + else if(!output_seekable){ + fprintf(stderr,"WARNING: Neither input nor output are seekable.\n"); + fprintf(stderr, + "Writing non-standard WAV header with invalid chunk sizes.\n"); + } + make_wav_header(wav_header,duration); + if(!fwrite(wav_header,sizeof(wav_header),1,stdout)){ + fprintf(stderr,"Error writing WAV header: %s\n",strerror(errno)); + ret=EXIT_FAILURE; + } + else{ + ogg_int64_t pcm_offset; + ogg_int64_t pcm_print_offset; + ogg_int64_t nsamples; + opus_int32 bitrate; + int prev_li; + prev_li=-1; + nsamples=0; + pcm_offset=op_pcm_tell(of); + if(pcm_offset!=0){ + fprintf(stderr,"Non-zero starting PCM offset: %li\n",(long)pcm_offset); + } + pcm_print_offset=pcm_offset-48000; + bitrate=0; + for(;;){ + ogg_int64_t next_pcm_offset; + opus_int16 pcm[120*48*2]; + unsigned char out[120*48*2*2]; + int li; + int si; + /*Although we would generally prefer to use the float interface, WAV + files with signed, 16-bit little-endian samples are far more + universally supported, so that's what we output.*/ + ret=op_read_stereo(of,pcm,sizeof(pcm)/sizeof(*pcm)); + if(ret==OP_HOLE){ + fprintf(stderr,"\nHole detected! Corrupt file segment?\n"); + continue; + } + else if(ret<0){ + fprintf(stderr,"\nError decoding '%s': %i\n",_argv[1],ret); + if(is_ssl)fprintf(stderr,"Possible truncation attack?\n"); + ret=EXIT_FAILURE; + break; + } + li=op_current_link(of); + if(li!=prev_li){ + const OpusHead *head; + const OpusTags *tags; + int binary_suffix_len; + int ci; + /*We found a new link. + Print out some information.*/ + fprintf(stderr,"Decoding link %i: \n",li); + head=op_head(of,li); + fprintf(stderr," Channels: %i\n",head->channel_count); + if(op_seekable(of)){ + ogg_int64_t duration; + opus_int64 size; + duration=op_pcm_total(of,li); + fprintf(stderr," Duration: "); + print_duration(stderr,duration,3); + fprintf(stderr," (%li samples @ 48 kHz)\n",(long)duration); + size=op_raw_total(of,li); + fprintf(stderr," Size: "); + print_size(stderr,size,0,""); + fprintf(stderr,"\n"); + } + if(head->input_sample_rate){ + fprintf(stderr," Original sampling rate: %lu Hz\n", + (unsigned long)head->input_sample_rate); + } + tags=op_tags(of,li); + fprintf(stderr," Encoded by: %s\n",tags->vendor); + for(ci=0;cicomments;ci++){ + const char *comment; + comment=tags->user_comments[ci]; + if(opus_tagncompare("METADATA_BLOCK_PICTURE",22,comment)==0){ + OpusPictureTag pic; + int err; + err=opus_picture_tag_parse(&pic,comment); + fprintf(stderr," %.23s",comment); + if(err>=0){ + fprintf(stderr,"%u|%s|%s|%ux%ux%u",pic.type,pic.mime_type, + pic.description,pic.width,pic.height,pic.depth); + if(pic.colors!=0)fprintf(stderr,"/%u",pic.colors); + if(pic.format==OP_PIC_FORMAT_URL){ + fprintf(stderr,"|%s\n",pic.data); + } + else{ + fprintf(stderr,"|<%u bytes of image data>\n",pic.data_length); + } + opus_picture_tag_clear(&pic); + } + else fprintf(stderr,"\n"); + } + else fprintf(stderr," %s\n",tags->user_comments[ci]); + } + if(opus_tags_get_binary_suffix(tags,&binary_suffix_len)!=NULL){ + fprintf(stderr,"<%u bytes of unknown binary metadata>\n", + binary_suffix_len); + } + fprintf(stderr,"\n"); + if(!op_seekable(of)){ + pcm_offset=op_pcm_tell(of)-ret; + if(pcm_offset!=0){ + fprintf(stderr,"Non-zero starting PCM offset in link %i: %li\n", + li,(long)pcm_offset); + } + } + } + if(li!=prev_li||pcm_offset>=pcm_print_offset+48000){ + opus_int32 next_bitrate; + opus_int64 raw_offset; + next_bitrate=op_bitrate_instant(of); + if(next_bitrate>=0)bitrate=next_bitrate; + raw_offset=op_raw_tell(of); + fprintf(stderr,"\r "); + print_size(stderr,raw_offset,0,""); + fprintf(stderr," "); + print_duration(stderr,pcm_offset,0); + fprintf(stderr," ("); + print_size(stderr,bitrate,1," "); + fprintf(stderr,"bps) \r"); + pcm_print_offset=pcm_offset; + fflush(stderr); + } + next_pcm_offset=op_pcm_tell(of); + if(pcm_offset+ret!=next_pcm_offset){ + fprintf(stderr,"\nPCM offset gap! %li+%i!=%li\n", + (long)pcm_offset,ret,(long)next_pcm_offset); + } + pcm_offset=next_pcm_offset; + if(ret<=0){ + ret=EXIT_SUCCESS; + break; + } + /*Ensure the data is little-endian before writing it out.*/ + for(si=0;si<2*ret;si++){ + out[2*si+0]=(unsigned char)(pcm[si]&0xFF); + out[2*si+1]=(unsigned char)(pcm[si]>>8&0xFF); + } + if(!fwrite(out,sizeof(*out)*4*ret,1,stdout)){ + fprintf(stderr,"\nError writing decoded audio data: %s\n", + strerror(errno)); + ret=EXIT_FAILURE; + break; + } + nsamples+=ret; + prev_li=li; + } + if(ret==EXIT_SUCCESS){ + fprintf(stderr,"\nDone: played "); + print_duration(stderr,nsamples,3); + fprintf(stderr," (%li samples @ 48 kHz).\n",(long)nsamples); + } + if(op_seekable(of)&&nsamples!=duration){ + fprintf(stderr,"\nWARNING: " + "Number of output samples does not match declared file duration.\n"); + if(!output_seekable)fprintf(stderr,"Output WAV file will be corrupt.\n"); + } + if(output_seekable&&nsamples!=duration){ + make_wav_header(wav_header,nsamples); + if(fseek(stdout,0,SEEK_SET)|| + !fwrite(wav_header,sizeof(wav_header),1,stdout)){ + fprintf(stderr,"Error rewriting WAV header: %s\n",strerror(errno)); + ret=EXIT_FAILURE; + } + } + } + op_free(of); + return ret; +} diff --git a/extern/opusfile/examples/seeking_example.c b/extern/opusfile/examples/seeking_example.c new file mode 100644 index 0000000..43d6848 --- /dev/null +++ b/extern/opusfile/examples/seeking_example.c @@ -0,0 +1,464 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE libopusfile SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE libopusfile SOURCE CODE IS (C) COPYRIGHT 1994-2012 * + * by the Xiph.Org Foundation and contributors http://www.xiph.org/ * + * * + ********************************************************************/ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/*For fileno()*/ +#if !defined(_POSIX_SOURCE) +# define _POSIX_SOURCE 1 +#endif +#include +#include +#include +#include +#include +#include +#if defined(_WIN32) +# include "win32utf8.h" +# undef fileno +# define fileno _fileno +#endif + +/*Use shorts, they're smaller.*/ +#if !defined(OP_FIXED_POINT) +# define OP_FIXED_POINT (1) +#endif + +#if defined(OP_FIXED_POINT) + +typedef opus_int16 op_sample; + +# define op_read_native op_read + +/*TODO: The convergence after 80 ms of preroll is far from exact. + Our comparison is very rough. + Need to find some way to do this better.*/ +# define MATCH_TOL (16384) + +# define ABS(_x) ((_x)<0?-(_x):(_x)) + +# define MATCH(_a,_b) (ABS((_a)-(_b))_pcm_offset){ + fprintf(stderr,"\nPCM position out of tolerance: requested %li, " + "got %li.\n",(long)_pcm_offset,(long)pcm_offset); + nfailures++; + } + if(pcm_offset<0||pcm_offset>_pcm_length){ + fprintf(stderr,"\nPCM position out of bounds: got %li.\n", + (long)pcm_offset); + nfailures++; + } + nsamples=op_read_native(_of,buffer,sizeof(buffer)/sizeof(*buffer),&li); + if(nsamples<0){ + fprintf(stderr,"\nFailed to read PCM data after seek: %i\n",nsamples); + nfailures++; + li=op_current_link(_of); + } + for(lj=0;ljduration){ + fprintf(stderr,"\nPCM data after seek exceeded link duration: " + "limit %li, got %li.\n",(long)duration,(long)(pcm_offset+nsamples)); + nfailures++; + } + nchannels=op_channel_count(_of,li); + if(_bigassbuffer!=NULL){ + for(i=0;i\n",_argv[0]); + return EXIT_FAILURE; + } + memset(&cb,0,sizeof(cb)); + if(strcmp(_argv[1],"-")==0)fp=op_fdopen(&cb,fileno(stdin),"rb"); + else{ + /*Try to treat the argument as a URL.*/ + fp=op_url_stream_create(&cb,_argv[1], + OP_SSL_SKIP_CERTIFICATE_CHECK(1),NULL); + /*Fall back assuming it's a regular file name.*/ + if(fp==NULL)fp=op_fopen(&cb,_argv[1],"rb"); + } + if(cb.seek!=NULL){ + real_seek=cb.seek; + cb.seek=seek_stat_counter; + } + of=op_open_callbacks(fp,&cb,NULL,0,NULL); + if(of==NULL){ + fprintf(stderr,"Failed to open file '%s'.\n",_argv[1]); + return EXIT_FAILURE; + } + if(op_seekable(of)){ + op_sample *bigassbuffer; + ogg_int64_t size; + ogg_int64_t pcm_offset; + ogg_int64_t pcm_length; + ogg_int64_t nsamples; + long max_seeks; + int nlinks; + int ret; + int li; + int i; + /*Because we want to do sample-level verification that the seek does what + it claimed, decode the entire file into memory.*/ + nlinks=op_link_count(of); + fprintf(stderr,"Opened file containing %i links with %li seeks " + "(%0.3f per link).\n",nlinks,nreal_seeks,nreal_seeks/(double)nlinks); + /*Reset the seek counter.*/ + nreal_seeks=0; + nsamples=0; + for(li=0;li=pcm_print_offset+48000){ + next_bitrate=op_bitrate_instant(of); + if(next_bitrate>=0)bitrate=next_bitrate; + fprintf(stderr,"\r%s... [%li left] (%0.3f kbps) ", + bigassbuffer==NULL?"Scanning":"Loading",nsamples-si,bitrate/1000.0); + pcm_print_offset=pcm_offset; + } + } + ret=op_read_native(of,smallerbuffer,8,&li); + if(ret<0){ + fprintf(stderr,"Failed to read PCM data: %i\n",ret); + nfailures++; + } + if(ret>0){ + fprintf(stderr,"Read too much PCM data!\n"); + nfailures++; + } + } +#endif + pcm_length=op_pcm_total(of,-1); + size=op_raw_total(of,-1); + fprintf(stderr,"\rLoaded (%0.3f kbps average). \n", + op_bitrate(of,-1)/1000.0); + fprintf(stderr,"Testing raw seeking to random places in %li bytes...\n", + (long)size); + max_seeks=0; + for(i=0;imax_seeks?nseeks_tmp:max_seeks; + } + fprintf(stderr,"\rTotal seek operations: %li (%.3f per raw seek, %li maximum).\n", + nreal_seeks,nreal_seeks/(double)NSEEK_TESTS,max_seeks); + nreal_seeks=0; + fprintf(stderr,"Testing exact PCM seeking to random places in %li " + "samples (",(long)pcm_length); + print_duration(stderr,pcm_length); + fprintf(stderr,")...\n"); + max_seeks=0; + for(i=0;imax_seeks?nseeks_tmp:max_seeks; + } + fprintf(stderr,"\rTotal seek operations: %li (%.3f per exact seek, %li maximum).\n", + nreal_seeks,nreal_seeks/(double)NSEEK_TESTS,max_seeks); + nreal_seeks=0; + fprintf(stderr,"OK.\n"); + _ogg_free(bigassbuffer); + } + else{ + fprintf(stderr,"Input was not seekable.\n"); + exit(EXIT_FAILURE); + } + op_free(of); + if(nfailures>0){ + fprintf(stderr,"FAILED: %li failure conditions encountered.\n",nfailures); + } + return nfailures!=0?EXIT_FAILURE:EXIT_SUCCESS; +} diff --git a/extern/opusfile/examples/win32utf8.c b/extern/opusfile/examples/win32utf8.c new file mode 100644 index 0000000..dd3f3df --- /dev/null +++ b/extern/opusfile/examples/win32utf8.c @@ -0,0 +1,111 @@ +#if defined(_WIN32) +# include +# include +# include +/*We need the following two to set stdin/stdout to binary.*/ +# include +# include +# define WIN32_LEAN_AND_MEAN +# define WIN32_EXTRA_LEAN +# include +# include "win32utf8.h" + +static char *utf16_to_utf8(const wchar_t *_src){ + char *dst; + size_t len; + size_t si; + size_t di; + len=wcslen(_src); + dst=(char *)malloc(sizeof(*dst)*(3*len+1)); + if(dst==NULL)return dst; + for(di=si=0;si>6); + dst[di++]=(char)(0x80|c0&0x3F); + continue; + } + else if(c0>=0xD800&&c0<0xDC00){ + unsigned c1; + /*This is safe, because c0 was not 0 and _src is NUL-terminated.*/ + c1=_src[si+1]; + if(c1>=0xDC00&&c1<0xE000){ + unsigned w; + /*Surrogate pair.*/ + w=((c0&0x3FF)<<10|c1&0x3FF)+0x10000; + /*Can be represented by a 4-byte sequence.*/ + dst[di++]=(char)(0xF0|w>>18); + dst[di++]=(char)(0x80|w>>12&0x3F); + dst[di++]=(char)(0x80|w>>6&0x3F); + dst[di++]=(char)(0x80|w&0x3F); + si++; + continue; + } + } + /*Anything else is either a valid 3-byte sequence, an invalid surrogate + pair, or 'not a character'. + In the latter two cases, we just encode the value as a 3-byte + sequence anyway (producing technically invalid UTF-8). + Later error handling will detect the problem, with a better + chance of giving a useful error message.*/ + dst[di++]=(char)(0xE0|c0>>12); + dst[di++]=(char)(0x80|c0>>6&0x3F); + dst[di++]=(char)(0x80|c0&0x3F); + } + dst[di++]='\0'; + return dst; +} + +typedef LPWSTR *(APIENTRY *command_line_to_argv_w_func)(LPCWSTR cmd_line, + int *num_args); + +/*Make a best-effort attempt to support UTF-8 on Windows.*/ +void win32_utf8_setup(int *_argc,const char ***_argv){ + HMODULE hlib; + /*We need to set stdin/stdout to binary mode. + This is unrelated to UTF-8 support, but it's platform specific and we need + to do it in the same places.*/ + _setmode(_fileno(stdin),_O_BINARY); + _setmode(_fileno(stdout),_O_BINARY); + hlib=LoadLibraryA("shell32.dll"); + if(hlib!=NULL){ + command_line_to_argv_w_func command_line_to_argv_w; + /*This function is only available on Windows 2000 or later.*/ + command_line_to_argv_w=(command_line_to_argv_w_func)GetProcAddress(hlib, + "CommandLineToArgvW"); + if(command_line_to_argv_w!=NULL){ + wchar_t **argvw; + int argc; + argvw=(*command_line_to_argv_w)(GetCommandLineW(),&argc); + if(argvw!=NULL){ + int ai; + /*Really, I don't see why argc would ever differ from *_argc, but let's + be paranoid.*/ + if(argc>*_argc)argc=*_argc; + for(ai=0;ailibopusfile C API. + + The libopusfile package provides a convenient high-level API for + decoding and basic manipulation of all Ogg Opus audio streams. + libopusfile is implemented as a layer on top of Xiph.Org's + reference + libogg + and + libopus + libraries. + + libopusfile provides several sets of built-in routines for + file/stream access, and may also use custom stream I/O routines provided by + the embedded environment. + There are built-in I/O routines provided for ANSI-compliant + stdio (FILE *), memory buffers, and URLs + (including URLs, plus optionally and URLs). + + \section Organization + + The main API is divided into several sections: + - \ref stream_open_close + - \ref stream_info + - \ref stream_decoding + - \ref stream_seeking + + Several additional sections are not tied to the main API. + - \ref stream_callbacks + - \ref header_info + - \ref error_codes + + \section Overview + + The libopusfile API always decodes files to 48 kHz. + The original sample rate is not preserved by the lossy compression, though + it is stored in the header to allow you to resample to it after decoding + (the libopusfile API does not currently provide a resampler, + but the + the + Speex resampler is a good choice if you need one). + In general, if you are playing back the audio, you should leave it at + 48 kHz, provided your audio hardware supports it. + When decoding to a file, it may be worth resampling back to the original + sample rate, so as not to surprise users who might not expect the sample + rate to change after encoding to Opus and decoding. + + Opus files can contain anywhere from 1 to 255 channels of audio. + The channel mappings for up to 8 channels are the same as the + Vorbis + mappings. + A special stereo API can convert everything to 2 channels, making it simple + to support multichannel files in an application which only has stereo + output. + Although the libopusfile ABI provides support for the theoretical + maximum number of channels, the current implementation does not support + files with more than 8 channels, as they do not have well-defined channel + mappings. + + Like all Ogg files, Opus files may be "chained". + That is, multiple Opus files may be combined into a single, longer file just + by concatenating the original files. + This is commonly done in internet radio streaming, as it allows the title + and artist to be updated each time the song changes, since each link in the + chain includes its own set of metadata. + + libopusfile fully supports chained files. + It will decode the first Opus stream found in each link of a chained file + (ignoring any other streams that might be concurrently multiplexed with it, + such as a video stream). + + The channel count can also change between links. + If your application is not prepared to deal with this, it can use the stereo + API to ensure the audio from all links will always get decoded into a + common format. + Since libopusfile always decodes to 48 kHz, you do not have to + worry about the sample rate changing between links (as was possible with + Vorbis). + This makes application support for chained files with libopusfile + very easy.*/ + +# if defined(__cplusplus) +extern "C" { +# endif + +# include +# include +# include +# include + +/**@cond PRIVATE*/ + +/*Enable special features for gcc and gcc-compatible compilers.*/ +# if !defined(OP_GNUC_PREREQ) +# if defined(__GNUC__)&&defined(__GNUC_MINOR__) +# define OP_GNUC_PREREQ(_maj,_min) \ + ((__GNUC__<<16)+__GNUC_MINOR__>=((_maj)<<16)+(_min)) +# else +# define OP_GNUC_PREREQ(_maj,_min) 0 +# endif +# endif + +# if OP_GNUC_PREREQ(4,0) +# pragma GCC visibility push(default) +# endif + +typedef struct OpusHead OpusHead; +typedef struct OpusTags OpusTags; +typedef struct OpusPictureTag OpusPictureTag; +typedef struct OpusServerInfo OpusServerInfo; +typedef struct OpusFileCallbacks OpusFileCallbacks; +typedef struct OggOpusFile OggOpusFile; + +/*Warning attributes for libopusfile functions.*/ +# if OP_GNUC_PREREQ(3,4) +# define OP_WARN_UNUSED_RESULT __attribute__((__warn_unused_result__)) +# else +# define OP_WARN_UNUSED_RESULT +# endif +# if OP_GNUC_PREREQ(3,4) +# define OP_ARG_NONNULL(_x) __attribute__((__nonnull__(_x))) +# else +# define OP_ARG_NONNULL(_x) +# endif + +/**@endcond*/ + +/**\defgroup error_codes Error Codes*/ +/*@{*/ +/**\name List of possible error codes + Many of the functions in this library return a negative error code when a + function fails. + This list provides a brief explanation of the common errors. + See each individual function for more details on what a specific error code + means in that context.*/ +/*@{*/ + +/**A request did not succeed.*/ +#define OP_FALSE (-1) +/*Currently not used externally.*/ +#define OP_EOF (-2) +/**There was a hole in the page sequence numbers (e.g., a page was corrupt or + missing).*/ +#define OP_HOLE (-3) +/**An underlying read, seek, or tell operation failed when it should have + succeeded.*/ +#define OP_EREAD (-128) +/**A NULL pointer was passed where one was unexpected, or an + internal memory allocation failed, or an internal library error was + encountered.*/ +#define OP_EFAULT (-129) +/**The stream used a feature that is not implemented, such as an unsupported + channel family.*/ +#define OP_EIMPL (-130) +/**One or more parameters to a function were invalid.*/ +#define OP_EINVAL (-131) +/**A purported Ogg Opus stream did not begin with an Ogg page, a purported + header packet did not start with one of the required strings, "OpusHead" or + "OpusTags", or a link in a chained file was encountered that did not + contain any logical Opus streams.*/ +#define OP_ENOTFORMAT (-132) +/**A required header packet was not properly formatted, contained illegal + values, or was missing altogether.*/ +#define OP_EBADHEADER (-133) +/**The ID header contained an unrecognized version number.*/ +#define OP_EVERSION (-134) +/*Currently not used at all.*/ +#define OP_ENOTAUDIO (-135) +/**An audio packet failed to decode properly. + This is usually caused by a multistream Ogg packet where the durations of + the individual Opus packets contained in it are not all the same.*/ +#define OP_EBADPACKET (-136) +/**We failed to find data we had seen before, or the bitstream structure was + sufficiently malformed that seeking to the target destination was + impossible.*/ +#define OP_EBADLINK (-137) +/**An operation that requires seeking was requested on an unseekable stream.*/ +#define OP_ENOSEEK (-138) +/**The first or last granule position of a link failed basic validity checks.*/ +#define OP_EBADTIMESTAMP (-139) + +/*@}*/ +/*@}*/ + +/**\defgroup header_info Header Information*/ +/*@{*/ + +/**The maximum number of channels in an Ogg Opus stream.*/ +#define OPUS_CHANNEL_COUNT_MAX (255) + +/**Ogg Opus bitstream information. + This contains the basic playback parameters for a stream, and corresponds to + the initial ID header packet of an Ogg Opus stream.*/ +struct OpusHead{ + /**The Ogg Opus format version, in the range 0...255. + The top 4 bits represent a "major" version, and the bottom four bits + represent backwards-compatible "minor" revisions. + The current specification describes version 1. + This library will recognize versions up through 15 as backwards compatible + with the current specification. + An earlier draft of the specification described a version 0, but the only + difference between version 1 and version 0 is that version 0 did + not specify the semantics for handling the version field.*/ + int version; + /**The number of channels, in the range 1...255.*/ + int channel_count; + /**The number of samples that should be discarded from the beginning of the + stream.*/ + unsigned pre_skip; + /**The sampling rate of the original input. + All Opus audio is coded at 48 kHz, and should also be decoded at 48 kHz + for playback (unless the target hardware does not support this sampling + rate). + However, this field may be used to resample the audio back to the original + sampling rate, for example, when saving the output to a file.*/ + opus_uint32 input_sample_rate; + /**The gain to apply to the decoded output, in dB, as a Q8 value in the range + -32768...32767. + The libopusfile API will automatically apply this gain to the + decoded output before returning it, scaling it by + pow(10,output_gain/(20.0*256)). + You can adjust this behavior with op_set_gain_offset().*/ + int output_gain; + /**The channel mapping family, in the range 0...255. + Channel mapping family 0 covers mono or stereo in a single stream. + Channel mapping family 1 covers 1 to 8 channels in one or more streams, + using the Vorbis speaker assignments. + Channel mapping family 255 covers 1 to 255 channels in one or more + streams, but without any defined speaker assignment.*/ + int mapping_family; + /**The number of Opus streams in each Ogg packet, in the range 1...255.*/ + int stream_count; + /**The number of coupled Opus streams in each Ogg packet, in the range + 0...127. + This must satisfy 0 <= coupled_count <= stream_count and + coupled_count + stream_count <= 255. + The coupled streams appear first, before all uncoupled streams, in an Ogg + Opus packet.*/ + int coupled_count; + /**The mapping from coded stream channels to output channels. + Let index=mapping[k] be the value for channel k. + If index<2*coupled_count, then it refers to the left channel + from stream (index/2) if even, and the right channel from + stream (index/2) if odd. + Otherwise, it refers to the output of the uncoupled stream + (index-coupled_count).*/ + unsigned char mapping[OPUS_CHANNEL_COUNT_MAX]; +}; + +/**The metadata from an Ogg Opus stream. + + This structure holds the in-stream metadata corresponding to the 'comment' + header packet of an Ogg Opus stream. + The comment header is meant to be used much like someone jotting a quick + note on the label of a CD. + It should be a short, to the point text note that can be more than a couple + words, but not more than a short paragraph. + + The metadata is stored as a series of (tag, value) pairs, in length-encoded + string vectors, using the same format as Vorbis (without the final "framing + bit"), Theora, and Speex, except for the packet header. + The first occurrence of the '=' character delimits the tag and value. + A particular tag may occur more than once, and order is significant. + The character set encoding for the strings is always UTF-8, but the tag + names are limited to ASCII, and treated as case-insensitive. + See the Vorbis + comment header specification for details. + + In filling in this structure, libopusfile will null-terminate the + #user_comments strings for safety. + However, the bitstream format itself treats them as 8-bit clean vectors, + possibly containing NUL characters, so the #comment_lengths array should be + treated as their authoritative length. + + This structure is binary and source-compatible with a + vorbis_comment, and pointers to it may be freely cast to + vorbis_comment pointers, and vice versa. + It is provided as a separate type to avoid introducing a compile-time + dependency on the libvorbis headers.*/ +struct OpusTags{ + /**The array of comment string vectors.*/ + char **user_comments; + /**An array of the corresponding length of each vector, in bytes.*/ + int *comment_lengths; + /**The total number of comment streams.*/ + int comments; + /**The null-terminated vendor string. + This identifies the software used to encode the stream.*/ + char *vendor; +}; + +/**\name Picture tag image formats*/ +/*@{*/ + +/**The MIME type was not recognized, or the image data did not match the + declared MIME type.*/ +#define OP_PIC_FORMAT_UNKNOWN (-1) +/**The MIME type indicates the image data is really a URL.*/ +#define OP_PIC_FORMAT_URL (0) +/**The image is a JPEG.*/ +#define OP_PIC_FORMAT_JPEG (1) +/**The image is a PNG.*/ +#define OP_PIC_FORMAT_PNG (2) +/**The image is a GIF.*/ +#define OP_PIC_FORMAT_GIF (3) + +/*@}*/ + +/**The contents of a METADATA_BLOCK_PICTURE tag.*/ +struct OpusPictureTag{ + /**The picture type according to the ID3v2 APIC frame: +
      +
    1. Other
    2. +
    3. 32x32 pixels 'file icon' (PNG only)
    4. +
    5. Other file icon
    6. +
    7. Cover (front)
    8. +
    9. Cover (back)
    10. +
    11. Leaflet page
    12. +
    13. Media (e.g. label side of CD)
    14. +
    15. Lead artist/lead performer/soloist
    16. +
    17. Artist/performer
    18. +
    19. Conductor
    20. +
    21. Band/Orchestra
    22. +
    23. Composer
    24. +
    25. Lyricist/text writer
    26. +
    27. Recording Location
    28. +
    29. During recording
    30. +
    31. During performance
    32. +
    33. Movie/video screen capture
    34. +
    35. A bright colored fish
    36. +
    37. Illustration
    38. +
    39. Band/artist logotype
    40. +
    41. Publisher/Studio logotype
    42. +
    + Others are reserved and should not be used. + There may only be one each of picture type 1 and 2 in a file.*/ + opus_int32 type; + /**The MIME type of the picture, in printable ASCII characters 0x20-0x7E. + The MIME type may also be "-->" to signify that the data part + is a URL pointing to the picture instead of the picture data itself. + In this case, a terminating NUL is appended to the URL string in #data, + but #data_length is set to the length of the string excluding that + terminating NUL.*/ + char *mime_type; + /**The description of the picture, in UTF-8.*/ + char *description; + /**The width of the picture in pixels.*/ + opus_uint32 width; + /**The height of the picture in pixels.*/ + opus_uint32 height; + /**The color depth of the picture in bits-per-pixel (not + bits-per-channel).*/ + opus_uint32 depth; + /**For indexed-color pictures (e.g., GIF), the number of colors used, or 0 + for non-indexed pictures.*/ + opus_uint32 colors; + /**The length of the picture data in bytes.*/ + opus_uint32 data_length; + /**The binary picture data.*/ + unsigned char *data; + /**The format of the picture data, if known. + One of +
      +
    • #OP_PIC_FORMAT_UNKNOWN,
    • +
    • #OP_PIC_FORMAT_URL,
    • +
    • #OP_PIC_FORMAT_JPEG,
    • +
    • #OP_PIC_FORMAT_PNG, or
    • +
    • #OP_PIC_FORMAT_GIF.
    • +
    */ + int format; +}; + +/**\name Functions for manipulating header data + + These functions manipulate the #OpusHead and #OpusTags structures, + which describe the audio parameters and tag-value metadata, respectively. + These can be used to query the headers returned by libopusfile, or + to parse Opus headers from sources other than an Ogg Opus stream, provided + they use the same format.*/ +/*@{*/ + +/**Parses the contents of the ID header packet of an Ogg Opus stream. + \param[out] _head Returns the contents of the parsed packet. + The contents of this structure are untouched on error. + This may be NULL to merely test the header + for validity. + \param[in] _data The contents of the ID header packet. + \param _len The number of bytes of data in the ID header packet. + \return 0 on success or a negative value on error. + \retval #OP_ENOTFORMAT If the data does not start with the "OpusHead" + string. + \retval #OP_EVERSION If the version field signaled a version this library + does not know how to parse. + \retval #OP_EIMPL If the channel mapping family was 255, which general + purpose players should not attempt to play. + \retval #OP_EBADHEADER If the contents of the packet otherwise violate the + Ogg Opus specification: +
      +
    • Insufficient data,
    • +
    • Too much data for the known minor versions,
    • +
    • An unrecognized channel mapping family,
    • +
    • Zero channels or too many channels,
    • +
    • Zero coded streams,
    • +
    • Too many coupled streams, or
    • +
    • An invalid channel mapping index.
    • +
    */ +OP_WARN_UNUSED_RESULT int opus_head_parse(OpusHead *_head, + const unsigned char *_data,size_t _len) OP_ARG_NONNULL(2); + +/**Converts a granule position to a sample offset for a given Ogg Opus stream. + The sample offset is simply _gp-_head->pre_skip. + Granule position values smaller than OpusHead#pre_skip correspond to audio + that should never be played, and thus have no associated sample offset. + This function returns -1 for such values. + This function also correctly handles extremely large granule positions, + which may have wrapped around to a negative number when stored in a signed + ogg_int64_t value. + \param _head The #OpusHead information from the ID header of the stream. + \param _gp The granule position to convert. + \return The sample offset associated with the given granule position + (counting at a 48 kHz sampling rate), or the special value -1 on + error (i.e., the granule position was smaller than the pre-skip + amount).*/ +ogg_int64_t opus_granule_sample(const OpusHead *_head,ogg_int64_t _gp) + OP_ARG_NONNULL(1); + +/**Parses the contents of the 'comment' header packet of an Ogg Opus stream. + \param[out] _tags An uninitialized #OpusTags structure. + This returns the contents of the parsed packet. + The contents of this structure are untouched on error. + This may be NULL to merely test the header + for validity. + \param[in] _data The contents of the 'comment' header packet. + \param _len The number of bytes of data in the 'info' header packet. + \retval 0 Success. + \retval #OP_ENOTFORMAT If the data does not start with the "OpusTags" + string. + \retval #OP_EBADHEADER If the contents of the packet otherwise violate the + Ogg Opus specification. + \retval #OP_EFAULT If there wasn't enough memory to store the tags.*/ +OP_WARN_UNUSED_RESULT int opus_tags_parse(OpusTags *_tags, + const unsigned char *_data,size_t _len) OP_ARG_NONNULL(2); + +/**Performs a deep copy of an #OpusTags structure. + \param _dst The #OpusTags structure to copy into. + If this function fails, the contents of this structure remain + untouched. + \param _src The #OpusTags structure to copy from. + \retval 0 Success. + \retval #OP_EFAULT If there wasn't enough memory to copy the tags.*/ +int opus_tags_copy(OpusTags *_dst,const OpusTags *_src) OP_ARG_NONNULL(1); + +/**Initializes an #OpusTags structure. + This should be called on a freshly allocated #OpusTags structure before + attempting to use it. + \param _tags The #OpusTags structure to initialize.*/ +void opus_tags_init(OpusTags *_tags) OP_ARG_NONNULL(1); + +/**Add a (tag, value) pair to an initialized #OpusTags structure. + \note Neither opus_tags_add() nor opus_tags_add_comment() support values + containing embedded NULs, although the bitstream format does support them. + To add such tags, you will need to manipulate the #OpusTags structure + directly. + \param _tags The #OpusTags structure to add the (tag, value) pair to. + \param _tag A NUL-terminated, case-insensitive, ASCII string containing + the tag to add (without an '=' character). + \param _value A NUL-terminated UTF-8 containing the corresponding value. + \return 0 on success, or a negative value on failure. + \retval #OP_EFAULT An internal memory allocation failed.*/ +int opus_tags_add(OpusTags *_tags,const char *_tag,const char *_value) + OP_ARG_NONNULL(1) OP_ARG_NONNULL(2) OP_ARG_NONNULL(3); + +/**Add a comment to an initialized #OpusTags structure. + \note Neither opus_tags_add_comment() nor opus_tags_add() support comments + containing embedded NULs, although the bitstream format does support them. + To add such tags, you will need to manipulate the #OpusTags structure + directly. + \param _tags The #OpusTags structure to add the comment to. + \param _comment A NUL-terminated UTF-8 string containing the comment in + "TAG=value" form. + \return 0 on success, or a negative value on failure. + \retval #OP_EFAULT An internal memory allocation failed.*/ +int opus_tags_add_comment(OpusTags *_tags,const char *_comment) + OP_ARG_NONNULL(1) OP_ARG_NONNULL(2); + +/**Replace the binary suffix data at the end of the packet (if any). + \param _tags An initialized #OpusTags structure. + \param _data A buffer of binary data to append after the encoded user + comments. + The least significant bit of the first byte of this data must + be set (to ensure the data is preserved by other editors). + \param _len The number of bytes of binary data to append. + This may be zero to remove any existing binary suffix data. + \return 0 on success, or a negative value on error. + \retval #OP_EINVAL \a _len was negative, or \a _len was positive but + \a _data was NULL or the least significant + bit of the first byte was not set. + \retval #OP_EFAULT An internal memory allocation failed.*/ +int opus_tags_set_binary_suffix(OpusTags *_tags, + const unsigned char *_data,int _len) OP_ARG_NONNULL(1); + +/**Look up a comment value by its tag. + \param _tags An initialized #OpusTags structure. + \param _tag The tag to look up. + \param _count The instance of the tag. + The same tag can appear multiple times, each with a distinct + value, so an index is required to retrieve them all. + The order in which these values appear is significant and + should be preserved. + Use opus_tags_query_count() to get the legal range for the + \a _count parameter. + \return A pointer to the queried tag's value. + This points directly to data in the #OpusTags structure. + It should not be modified or freed by the application, and + modifications to the structure may invalidate the pointer. + \retval NULL If no matching tag is found.*/ +const char *opus_tags_query(const OpusTags *_tags,const char *_tag,int _count) + OP_ARG_NONNULL(1) OP_ARG_NONNULL(2); + +/**Look up the number of instances of a tag. + Call this first when querying for a specific tag and then iterate over the + number of instances with separate calls to opus_tags_query() to retrieve + all the values for that tag in order. + \param _tags An initialized #OpusTags structure. + \param _tag The tag to look up. + \return The number of instances of this particular tag.*/ +int opus_tags_query_count(const OpusTags *_tags,const char *_tag) + OP_ARG_NONNULL(1) OP_ARG_NONNULL(2); + +/**Retrieve the binary suffix data at the end of the packet (if any). + \param _tags An initialized #OpusTags structure. + \param[out] _len Returns the number of bytes of binary suffix data returned. + \return A pointer to the binary suffix data, or NULL if none + was present.*/ +const unsigned char *opus_tags_get_binary_suffix(const OpusTags *_tags, + int *_len) OP_ARG_NONNULL(1) OP_ARG_NONNULL(2); + +/**Get the album gain from an R128_ALBUM_GAIN tag, if one was specified. + This searches for the first R128_ALBUM_GAIN tag with a valid signed, + 16-bit decimal integer value and returns the value. + This routine is exposed merely for convenience for applications which wish + to do something special with the album gain (i.e., display it). + If you simply wish to apply the album gain instead of the header gain, you + can use op_set_gain_offset() with an #OP_ALBUM_GAIN type and no offset. + \param _tags An initialized #OpusTags structure. + \param[out] _gain_q8 The album gain, in 1/256ths of a dB. + This will lie in the range [-32768,32767], and should + be applied in addition to the header gain. + On error, no value is returned, and the previous + contents remain unchanged. + \return 0 on success, or a negative value on error. + \retval #OP_FALSE There was no album gain available in the given tags.*/ +int opus_tags_get_album_gain(const OpusTags *_tags,int *_gain_q8) + OP_ARG_NONNULL(1) OP_ARG_NONNULL(2); + +/**Get the track gain from an R128_TRACK_GAIN tag, if one was specified. + This searches for the first R128_TRACK_GAIN tag with a valid signed, + 16-bit decimal integer value and returns the value. + This routine is exposed merely for convenience for applications which wish + to do something special with the track gain (i.e., display it). + If you simply wish to apply the track gain instead of the header gain, you + can use op_set_gain_offset() with an #OP_TRACK_GAIN type and no offset. + \param _tags An initialized #OpusTags structure. + \param[out] _gain_q8 The track gain, in 1/256ths of a dB. + This will lie in the range [-32768,32767], and should + be applied in addition to the header gain. + On error, no value is returned, and the previous + contents remain unchanged. + \return 0 on success, or a negative value on error. + \retval #OP_FALSE There was no track gain available in the given tags.*/ +int opus_tags_get_track_gain(const OpusTags *_tags,int *_gain_q8) + OP_ARG_NONNULL(1) OP_ARG_NONNULL(2); + +/**Clears the #OpusTags structure. + This should be called on an #OpusTags structure after it is no longer + needed. + It will free all memory used by the structure members. + \param _tags The #OpusTags structure to clear.*/ +void opus_tags_clear(OpusTags *_tags) OP_ARG_NONNULL(1); + +/**Check if \a _comment is an instance of a \a _tag_name tag. + \see opus_tagncompare + \param _tag_name A NUL-terminated, case-insensitive, ASCII string containing + the name of the tag to check for (without the terminating + '=' character). + \param _comment The comment string to check. + \return An integer less than, equal to, or greater than zero if \a _comment + is found respectively, to be less than, to match, or be greater + than a "tag=value" string whose tag matches \a _tag_name.*/ +int opus_tagcompare(const char *_tag_name,const char *_comment); + +/**Check if \a _comment is an instance of a \a _tag_name tag. + This version is slightly more efficient than opus_tagcompare() if the length + of the tag name is already known (e.g., because it is a constant). + \see opus_tagcompare + \param _tag_name A case-insensitive ASCII string containing the name of the + tag to check for (without the terminating '=' character). + \param _tag_len The number of characters in the tag name. + This must be non-negative. + \param _comment The comment string to check. + \return An integer less than, equal to, or greater than zero if \a _comment + is found respectively, to be less than, to match, or be greater + than a "tag=value" string whose tag matches the first \a _tag_len + characters of \a _tag_name.*/ +int opus_tagncompare(const char *_tag_name,int _tag_len,const char *_comment); + +/**Parse a single METADATA_BLOCK_PICTURE tag. + This decodes the BASE64-encoded content of the tag and returns a structure + with the MIME type, description, image parameters (if known), and the + compressed image data. + If the MIME type indicates the presence of an image format we recognize + (JPEG, PNG, or GIF) and the actual image data contains the magic signature + associated with that format, then the OpusPictureTag::format field will be + set to the corresponding format. + This is provided as a convenience to avoid requiring applications to parse + the MIME type and/or do their own format detection for the commonly used + formats. + In this case, we also attempt to extract the image parameters directly from + the image data (overriding any that were present in the tag, which the + specification says applications are not meant to rely on). + The application must still provide its own support for actually decoding the + image data and, if applicable, retrieving that data from URLs. + \param[out] _pic Returns the parsed picture data. + No sanitation is done on the type, MIME type, or + description fields, so these might return invalid values. + The contents of this structure are left unmodified on + failure. + \param _tag The METADATA_BLOCK_PICTURE tag contents. + The leading "METADATA_BLOCK_PICTURE=" portion is optional, + to allow the function to be used on either directly on the + values in OpusTags::user_comments or on the return value + of opus_tags_query(). + \return 0 on success or a negative value on error. + \retval #OP_ENOTFORMAT The METADATA_BLOCK_PICTURE contents were not valid. + \retval #OP_EFAULT There was not enough memory to store the picture tag + contents.*/ +OP_WARN_UNUSED_RESULT int opus_picture_tag_parse(OpusPictureTag *_pic, + const char *_tag) OP_ARG_NONNULL(1) OP_ARG_NONNULL(2); + +/**Initializes an #OpusPictureTag structure. + This should be called on a freshly allocated #OpusPictureTag structure + before attempting to use it. + \param _pic The #OpusPictureTag structure to initialize.*/ +void opus_picture_tag_init(OpusPictureTag *_pic) OP_ARG_NONNULL(1); + +/**Clears the #OpusPictureTag structure. + This should be called on an #OpusPictureTag structure after it is no longer + needed. + It will free all memory used by the structure members. + \param _pic The #OpusPictureTag structure to clear.*/ +void opus_picture_tag_clear(OpusPictureTag *_pic) OP_ARG_NONNULL(1); + +/*@}*/ + +/*@}*/ + +/**\defgroup url_options URL Reading Options*/ +/*@{*/ +/**\name URL reading options + Options for op_url_stream_create() and associated functions. + These allow you to provide proxy configuration parameters, skip SSL + certificate checks, etc. + Options are processed in order, and if the same option is passed multiple + times, only the value specified by the last occurrence has an effect + (unless otherwise specified). + They may be expanded in the future.*/ +/*@{*/ + +/**@cond PRIVATE*/ + +/*These are the raw numbers used to define the request codes. + They should not be used directly.*/ +#define OP_SSL_SKIP_CERTIFICATE_CHECK_REQUEST (6464) +#define OP_HTTP_PROXY_HOST_REQUEST (6528) +#define OP_HTTP_PROXY_PORT_REQUEST (6592) +#define OP_HTTP_PROXY_USER_REQUEST (6656) +#define OP_HTTP_PROXY_PASS_REQUEST (6720) +#define OP_GET_SERVER_INFO_REQUEST (6784) + +#define OP_URL_OPT(_request) ((_request)+(char *)0) + +/*These macros trigger compilation errors or warnings if the wrong types are + provided to one of the URL options.*/ +#define OP_CHECK_INT(_x) ((void)((_x)==(opus_int32)0),(opus_int32)(_x)) +#define OP_CHECK_CONST_CHAR_PTR(_x) ((_x)+((_x)-(const char *)(_x))) +#define OP_CHECK_SERVER_INFO_PTR(_x) ((_x)+((_x)-(OpusServerInfo *)(_x))) + +/**@endcond*/ + +/**HTTP/Shoutcast/Icecast server information associated with a URL.*/ +struct OpusServerInfo{ + /**The name of the server (icy-name/ice-name). + This is NULL if there was no icy-name or + ice-name header.*/ + char *name; + /**A short description of the server (icy-description/ice-description). + This is NULL if there was no icy-description or + ice-description header.*/ + char *description; + /**The genre the server falls under (icy-genre/ice-genre). + This is NULL if there was no icy-genre or + ice-genre header.*/ + char *genre; + /**The homepage for the server (icy-url/ice-url). + This is NULL if there was no icy-url or + ice-url header.*/ + char *url; + /**The software used by the origin server (Server). + This is NULL if there was no Server header.*/ + char *server; + /**The media type of the entity sent to the recepient (Content-Type). + This is NULL if there was no Content-Type + header.*/ + char *content_type; + /**The nominal stream bitrate in kbps (icy-br/ice-bitrate). + This is -1 if there was no icy-br or + ice-bitrate header.*/ + opus_int32 bitrate_kbps; + /**Flag indicating whether the server is public (1) or not + (0) (icy-pub/ice-public). + This is -1 if there was no icy-pub or + ice-public header.*/ + int is_public; + /**Flag indicating whether the server is using HTTPS instead of HTTP. + This is 0 unless HTTPS is being used. + This may not match the protocol used in the original URL if there were + redirections.*/ + int is_ssl; +}; + +/**Initializes an #OpusServerInfo structure. + All fields are set as if the corresponding header was not available. + \param _info The #OpusServerInfo structure to initialize. + \note If you use this function, you must link against libopusurl.*/ +void opus_server_info_init(OpusServerInfo *_info) OP_ARG_NONNULL(1); + +/**Clears the #OpusServerInfo structure. + This should be called on an #OpusServerInfo structure after it is no longer + needed. + It will free all memory used by the structure members. + \param _info The #OpusServerInfo structure to clear. + \note If you use this function, you must link against libopusurl.*/ +void opus_server_info_clear(OpusServerInfo *_info) OP_ARG_NONNULL(1); + +/**Skip the certificate check when connecting via TLS/SSL (https). + \param _b opus_int32: Whether or not to skip the certificate + check. + The check will be skipped if \a _b is non-zero, and will not be + skipped if \a _b is zero. + \hideinitializer*/ +#define OP_SSL_SKIP_CERTIFICATE_CHECK(_b) \ + OP_URL_OPT(OP_SSL_SKIP_CERTIFICATE_CHECK_REQUEST),OP_CHECK_INT(_b) + +/**Proxy connections through the given host. + If no port is specified via #OP_HTTP_PROXY_PORT, the port number defaults + to 8080 (http-alt). + All proxy parameters are ignored for non-http and non-https URLs. + \param _host const char *: The proxy server hostname. + This may be NULL to disable the use of a proxy + server. + \hideinitializer*/ +#define OP_HTTP_PROXY_HOST(_host) \ + OP_URL_OPT(OP_HTTP_PROXY_HOST_REQUEST),OP_CHECK_CONST_CHAR_PTR(_host) + +/**Use the given port when proxying connections. + This option only has an effect if #OP_HTTP_PROXY_HOST is specified with a + non-NULL \a _host. + If this option is not provided, the proxy port number defaults to 8080 + (http-alt). + All proxy parameters are ignored for non-http and non-https URLs. + \param _port opus_int32: The proxy server port. + This must be in the range 0...65535 (inclusive), or the + URL function this is passed to will fail. + \hideinitializer*/ +#define OP_HTTP_PROXY_PORT(_port) \ + OP_URL_OPT(OP_HTTP_PROXY_PORT_REQUEST),OP_CHECK_INT(_port) + +/**Use the given user name for authentication when proxying connections. + All proxy parameters are ignored for non-http and non-https URLs. + \param _user const char *: The proxy server user name. + This may be NULL to disable proxy + authentication. + A non-NULL value only has an effect + if #OP_HTTP_PROXY_HOST and #OP_HTTP_PROXY_PASS + are also specified with non-NULL + arguments. + \hideinitializer*/ +#define OP_HTTP_PROXY_USER(_user) \ + OP_URL_OPT(OP_HTTP_PROXY_USER_REQUEST),OP_CHECK_CONST_CHAR_PTR(_user) + +/**Use the given password for authentication when proxying connections. + All proxy parameters are ignored for non-http and non-https URLs. + \param _pass const char *: The proxy server password. + This may be NULL to disable proxy + authentication. + A non-NULL value only has an effect + if #OP_HTTP_PROXY_HOST and #OP_HTTP_PROXY_USER + are also specified with non-NULL + arguments. + \hideinitializer*/ +#define OP_HTTP_PROXY_PASS(_pass) \ + OP_URL_OPT(OP_HTTP_PROXY_PASS_REQUEST),OP_CHECK_CONST_CHAR_PTR(_pass) + +/**Parse information about the streaming server (if any) and return it. + Very little validation is done. + In particular, OpusServerInfo::url may not be a valid URL, + OpusServerInfo::bitrate_kbps may not really be in kbps, and + OpusServerInfo::content_type may not be a valid MIME type. + The character set of the string fields is not specified anywhere, and should + not be assumed to be valid UTF-8. + \param _info OpusServerInfo *: Returns information about the server. + If there is any error opening the stream, the + contents of this structure remain + unmodified. + On success, fills in the structure with the + server information that was available, if + any. + After a successful return, the contents of + this structure should be freed by calling + opus_server_info_clear(). + \hideinitializer*/ +#define OP_GET_SERVER_INFO(_info) \ + OP_URL_OPT(OP_GET_SERVER_INFO_REQUEST),OP_CHECK_SERVER_INFO_PTR(_info) + +/*@}*/ +/*@}*/ + +/**\defgroup stream_callbacks Abstract Stream Reading Interface*/ +/*@{*/ +/**\name Functions for reading from streams + These functions define the interface used to read from and seek in a stream + of data. + A stream does not need to implement seeking, but the decoder will not be + able to seek if it does not do so. + These functions also include some convenience routines for working with + standard FILE pointers, complete streams stored in a single + block of memory, or URLs.*/ +/*@{*/ + +/**Reads up to \a _nbytes bytes of data from \a _stream. + \param _stream The stream to read from. + \param[out] _ptr The buffer to store the data in. + \param _nbytes The maximum number of bytes to read. + This function may return fewer, though it will not + return zero unless it reaches end-of-file. + \return The number of bytes successfully read, or a negative value on + error.*/ +typedef int (*op_read_func)(void *_stream,unsigned char *_ptr,int _nbytes); + +/**Sets the position indicator for \a _stream. + The new position, measured in bytes, is obtained by adding \a _offset + bytes to the position specified by \a _whence. + If \a _whence is set to SEEK_SET, SEEK_CUR, or + SEEK_END, the offset is relative to the start of the stream, + the current position indicator, or end-of-file, respectively. + \retval 0 Success. + \retval -1 Seeking is not supported or an error occurred. + errno need not be set.*/ +typedef int (*op_seek_func)(void *_stream,opus_int64 _offset,int _whence); + +/**Obtains the current value of the position indicator for \a _stream. + \return The current position indicator.*/ +typedef opus_int64 (*op_tell_func)(void *_stream); + +/**Closes the underlying stream. + \retval 0 Success. + \retval EOF An error occurred. + errno need not be set.*/ +typedef int (*op_close_func)(void *_stream); + +/**The callbacks used to access non-FILE stream resources. + The function prototypes are basically the same as for the stdio functions + fread(), fseek(), ftell(), and + fclose(). + The differences are that the FILE * arguments have been + replaced with a void *, which is to be used as a pointer to + whatever internal data these functions might need, that #seek and #tell + take and return 64-bit offsets, and that #seek must return -1 if + the stream is unseekable.*/ +struct OpusFileCallbacks{ + /**Used to read data from the stream. + This must not be NULL.*/ + op_read_func read; + /**Used to seek in the stream. + This may be NULL if seeking is not implemented.*/ + op_seek_func seek; + /**Used to return the current read position in the stream. + This may be NULL if seeking is not implemented.*/ + op_tell_func tell; + /**Used to close the stream when the decoder is freed. + This may be NULL to leave the stream open.*/ + op_close_func close; +}; + +/**Opens a stream with fopen() and fills in a set of callbacks + that can be used to access it. + This is useful to avoid writing your own portable 64-bit seeking wrappers, + and also avoids cross-module linking issues on Windows, where a + FILE * must be accessed by routines defined in the same module + that opened it. + \param[out] _cb The callbacks to use for this file. + If there is an error opening the file, nothing will be + filled in here. + \param _path The path to the file to open. + On Windows, this string must be UTF-8 (to allow access to + files whose names cannot be represented in the current + MBCS code page). + All other systems use the native character encoding. + \param _mode The mode to open the file in. + \return A stream handle to use with the callbacks, or NULL on + error.*/ +OP_WARN_UNUSED_RESULT void *op_fopen(OpusFileCallbacks *_cb, + const char *_path,const char *_mode) OP_ARG_NONNULL(1) OP_ARG_NONNULL(2) + OP_ARG_NONNULL(3); + +/**Opens a stream with fdopen() and fills in a set of callbacks + that can be used to access it. + This is useful to avoid writing your own portable 64-bit seeking wrappers, + and also avoids cross-module linking issues on Windows, where a + FILE * must be accessed by routines defined in the same module + that opened it. + \param[out] _cb The callbacks to use for this file. + If there is an error opening the file, nothing will be + filled in here. + \param _fd The file descriptor to open. + \param _mode The mode to open the file in. + \return A stream handle to use with the callbacks, or NULL on + error.*/ +OP_WARN_UNUSED_RESULT void *op_fdopen(OpusFileCallbacks *_cb, + int _fd,const char *_mode) OP_ARG_NONNULL(1) OP_ARG_NONNULL(3); + +/**Opens a stream with freopen() and fills in a set of callbacks + that can be used to access it. + This is useful to avoid writing your own portable 64-bit seeking wrappers, + and also avoids cross-module linking issues on Windows, where a + FILE * must be accessed by routines defined in the same module + that opened it. + \param[out] _cb The callbacks to use for this file. + If there is an error opening the file, nothing will be + filled in here. + \param _path The path to the file to open. + On Windows, this string must be UTF-8 (to allow access + to files whose names cannot be represented in the + current MBCS code page). + All other systems use the native character encoding. + \param _mode The mode to open the file in. + \param _stream A stream previously returned by op_fopen(), op_fdopen(), + or op_freopen(). + \return A stream handle to use with the callbacks, or NULL on + error.*/ +OP_WARN_UNUSED_RESULT void *op_freopen(OpusFileCallbacks *_cb, + const char *_path,const char *_mode,void *_stream) OP_ARG_NONNULL(1) + OP_ARG_NONNULL(2) OP_ARG_NONNULL(3) OP_ARG_NONNULL(4); + +/**Creates a stream that reads from the given block of memory. + This block of memory must contain the complete stream to decode. + This is useful for caching small streams (e.g., sound effects) in RAM. + \param[out] _cb The callbacks to use for this stream. + If there is an error creating the stream, nothing will be + filled in here. + \param _data The block of memory to read from. + \param _size The size of the block of memory. + \return A stream handle to use with the callbacks, or NULL on + error.*/ +OP_WARN_UNUSED_RESULT void *op_mem_stream_create(OpusFileCallbacks *_cb, + const unsigned char *_data,size_t _size) OP_ARG_NONNULL(1); + +/**Creates a stream that reads from the given URL. + This function behaves identically to op_url_stream_create(), except that it + takes a va_list instead of a variable number of arguments. + It does not call the va_end macro, and because it invokes the + va_arg macro, the value of \a _ap is undefined after the call. + \note If you use this function, you must link against libopusurl. + \param[out] _cb The callbacks to use for this stream. + If there is an error creating the stream, nothing will + be filled in here. + \param _url The URL to read from. + Currently only the , , and + schemes are supported. + Both and may be disabled at compile + time, in which case opening such URLs will always fail. + Currently this only supports URIs. + IRIs should be converted to UTF-8 and URL-escaped, with + internationalized domain names encoded in punycode, + before passing them to this function. + \param[in,out] _ap A list of the \ref url_options "optional flags" to use. + This is a variable-length list of options terminated + with NULL. + \return A stream handle to use with the callbacks, or NULL on + error.*/ +OP_WARN_UNUSED_RESULT void *op_url_stream_vcreate(OpusFileCallbacks *_cb, + const char *_url,va_list _ap) OP_ARG_NONNULL(1) OP_ARG_NONNULL(2); + +/**Creates a stream that reads from the given URL. + \note If you use this function, you must link against libopusurl. + \param[out] _cb The callbacks to use for this stream. + If there is an error creating the stream, nothing will be + filled in here. + \param _url The URL to read from. + Currently only the , , and schemes + are supported. + Both and may be disabled at compile time, + in which case opening such URLs will always fail. + Currently this only supports URIs. + IRIs should be converted to UTF-8 and URL-escaped, with + internationalized domain names encoded in punycode, before + passing them to this function. + \param ... The \ref url_options "optional flags" to use. + This is a variable-length list of options terminated with + NULL. + \return A stream handle to use with the callbacks, or NULL on + error.*/ +OP_WARN_UNUSED_RESULT void *op_url_stream_create(OpusFileCallbacks *_cb, + const char *_url,...) OP_ARG_NONNULL(1) OP_ARG_NONNULL(2); + +/*@}*/ +/*@}*/ + +/**\defgroup stream_open_close Opening and Closing*/ +/*@{*/ +/**\name Functions for opening and closing streams + + These functions allow you to test a stream to see if it is Opus, open it, + and close it. + Several flavors are provided for each of the built-in stream types, plus a + more general version which takes a set of application-provided callbacks.*/ +/*@{*/ + +/**Test to see if this is an Opus stream. + For good results, you will need at least 57 bytes (for a pure Opus-only + stream). + Something like 512 bytes will give more reliable results for multiplexed + streams. + This function is meant to be a quick-rejection filter. + Its purpose is not to guarantee that a stream is a valid Opus stream, but to + ensure that it looks enough like Opus that it isn't going to be recognized + as some other format (except possibly an Opus stream that is also + multiplexed with other codecs, such as video). + \param[out] _head The parsed ID header contents. + You may pass NULL if you do not need + this information. + If the function fails, the contents of this structure + remain untouched. + \param _initial_data An initial buffer of data from the start of the + stream. + \param _initial_bytes The number of bytes in \a _initial_data. + \return 0 if the data appears to be Opus, or a negative value on error. + \retval #OP_FALSE There was not enough data to tell if this was an Opus + stream or not. + \retval #OP_EFAULT An internal memory allocation failed. + \retval #OP_EIMPL The stream used a feature that is not implemented, + such as an unsupported channel family. + \retval #OP_ENOTFORMAT If the data did not contain a recognizable ID + header for an Opus stream. + \retval #OP_EVERSION If the version field signaled a version this library + does not know how to parse. + \retval #OP_EBADHEADER The ID header was not properly formatted or contained + illegal values.*/ +int op_test(OpusHead *_head, + const unsigned char *_initial_data,size_t _initial_bytes); + +/**Open a stream from the given file path. + \param _path The path to the file to open. + \param[out] _error Returns 0 on success, or a failure code on error. + You may pass in NULL if you don't want the + failure code. + The failure code will be #OP_EFAULT if the file could not + be opened, or one of the other failure codes from + op_open_callbacks() otherwise. + \return A freshly opened \c OggOpusFile, or NULL on error.*/ +OP_WARN_UNUSED_RESULT OggOpusFile *op_open_file(const char *_path,int *_error) + OP_ARG_NONNULL(1); + +/**Open a stream from a memory buffer. + \param _data The memory buffer to open. + \param _size The number of bytes in the buffer. + \param[out] _error Returns 0 on success, or a failure code on error. + You may pass in NULL if you don't want the + failure code. + See op_open_callbacks() for a full list of failure codes. + \return A freshly opened \c OggOpusFile, or NULL on error.*/ +OP_WARN_UNUSED_RESULT OggOpusFile *op_open_memory(const unsigned char *_data, + size_t _size,int *_error); + +/**Open a stream from a URL. + This function behaves identically to op_open_url(), except that it + takes a va_list instead of a variable number of arguments. + It does not call the va_end macro, and because it invokes the + va_arg macro, the value of \a _ap is undefined after the call. + \note If you use this function, you must link against libopusurl. + \param _url The URL to open. + Currently only the , , and + schemes are supported. + Both and may be disabled at compile + time, in which case opening such URLs will always + fail. + Currently this only supports URIs. + IRIs should be converted to UTF-8 and URL-escaped, + with internationalized domain names encoded in + punycode, before passing them to this function. + \param[out] _error Returns 0 on success, or a failure code on error. + You may pass in NULL if you don't want + the failure code. + See op_open_callbacks() for a full list of failure + codes. + \param[in,out] _ap A list of the \ref url_options "optional flags" to + use. + This is a variable-length list of options terminated + with NULL. + \return A freshly opened \c OggOpusFile, or NULL on error.*/ +OP_WARN_UNUSED_RESULT OggOpusFile *op_vopen_url(const char *_url, + int *_error,va_list _ap) OP_ARG_NONNULL(1); + +/**Open a stream from a URL. + \note If you use this function, you must link against libopusurl. + \param _url The URL to open. + Currently only the , , and schemes + are supported. + Both and may be disabled at compile + time, in which case opening such URLs will always fail. + Currently this only supports URIs. + IRIs should be converted to UTF-8 and URL-escaped, with + internationalized domain names encoded in punycode, + before passing them to this function. + \param[out] _error Returns 0 on success, or a failure code on error. + You may pass in NULL if you don't want the + failure code. + See op_open_callbacks() for a full list of failure codes. + \param ... The \ref url_options "optional flags" to use. + This is a variable-length list of options terminated with + NULL. + \return A freshly opened \c OggOpusFile, or NULL on error.*/ +OP_WARN_UNUSED_RESULT OggOpusFile *op_open_url(const char *_url, + int *_error,...) OP_ARG_NONNULL(1); + +/**Open a stream using the given set of callbacks to access it. + \param _stream The stream to read from (e.g., a FILE *). + This value will be passed verbatim as the first + argument to all of the callbacks. + \param _cb The callbacks with which to access the stream. + read() must + be implemented. + seek() and + tell() may + be NULL, or may always return -1 to + indicate a stream is unseekable, but if + seek() is + implemented and succeeds on a particular stream, then + tell() must + also. + close() may + be NULL, but if it is not, it will be + called when the \c OggOpusFile is destroyed by + op_free(). + It will not be called if op_open_callbacks() fails + with an error. + \param _initial_data An initial buffer of data from the start of the + stream. + Applications can read some number of bytes from the + start of the stream to help identify this as an Opus + stream, and then provide them here to allow the + stream to be opened, even if it is unseekable. + \param _initial_bytes The number of bytes in \a _initial_data. + If the stream is seekable, its current position (as + reported by + tell() + at the start of this function) must be equal to + \a _initial_bytes. + Otherwise, seeking to absolute positions will + generate inconsistent results. + \param[out] _error Returns 0 on success, or a failure code on error. + You may pass in NULL if you don't want + the failure code. + The failure code will be one of +
    +
    #OP_EREAD
    +
    An underlying read, seek, or tell operation + failed when it should have succeeded, or we failed + to find data in the stream we had seen before.
    +
    #OP_EFAULT
    +
    There was a memory allocation failure, or an + internal library error.
    +
    #OP_EIMPL
    +
    The stream used a feature that is not + implemented, such as an unsupported channel + family.
    +
    #OP_EINVAL
    +
    seek() + was implemented and succeeded on this source, but + tell() + did not, or the starting position indicator was + not equal to \a _initial_bytes.
    +
    #OP_ENOTFORMAT
    +
    The stream contained a link that did not have + any logical Opus streams in it.
    +
    #OP_EBADHEADER
    +
    A required header packet was not properly + formatted, contained illegal values, or was missing + altogether.
    +
    #OP_EVERSION
    +
    An ID header contained an unrecognized version + number.
    +
    #OP_EBADLINK
    +
    We failed to find data we had seen before after + seeking.
    +
    #OP_EBADTIMESTAMP
    +
    The first or last timestamp in a link failed + basic validity checks.
    +
    + \return A freshly opened \c OggOpusFile, or NULL on error. + libopusfile does not take ownership of the stream + if the call fails. + The calling application is responsible for closing the stream if + this call returns an error.*/ +OP_WARN_UNUSED_RESULT OggOpusFile *op_open_callbacks(void *_stream, + const OpusFileCallbacks *_cb,const unsigned char *_initial_data, + size_t _initial_bytes,int *_error) OP_ARG_NONNULL(2); + +/**Partially open a stream from the given file path. + \see op_test_callbacks + \param _path The path to the file to open. + \param[out] _error Returns 0 on success, or a failure code on error. + You may pass in NULL if you don't want the + failure code. + The failure code will be #OP_EFAULT if the file could not + be opened, or one of the other failure codes from + op_open_callbacks() otherwise. + \return A partially opened \c OggOpusFile, or NULL on error.*/ +OP_WARN_UNUSED_RESULT OggOpusFile *op_test_file(const char *_path,int *_error) + OP_ARG_NONNULL(1); + +/**Partially open a stream from a memory buffer. + \see op_test_callbacks + \param _data The memory buffer to open. + \param _size The number of bytes in the buffer. + \param[out] _error Returns 0 on success, or a failure code on error. + You may pass in NULL if you don't want the + failure code. + See op_open_callbacks() for a full list of failure codes. + \return A partially opened \c OggOpusFile, or NULL on error.*/ +OP_WARN_UNUSED_RESULT OggOpusFile *op_test_memory(const unsigned char *_data, + size_t _size,int *_error); + +/**Partially open a stream from a URL. + This function behaves identically to op_test_url(), except that it + takes a va_list instead of a variable number of arguments. + It does not call the va_end macro, and because it invokes the + va_arg macro, the value of \a _ap is undefined after the call. + \note If you use this function, you must link against libopusurl. + \see op_test_url + \see op_test_callbacks + \param _url The URL to open. + Currently only the , , and + schemes are supported. + Both and may be disabled at compile + time, in which case opening such URLs will always + fail. + Currently this only supports URIs. + IRIs should be converted to UTF-8 and URL-escaped, + with internationalized domain names encoded in + punycode, before passing them to this function. + \param[out] _error Returns 0 on success, or a failure code on error. + You may pass in NULL if you don't want + the failure code. + See op_open_callbacks() for a full list of failure + codes. + \param[in,out] _ap A list of the \ref url_options "optional flags" to + use. + This is a variable-length list of options terminated + with NULL. + \return A partially opened \c OggOpusFile, or NULL on error.*/ +OP_WARN_UNUSED_RESULT OggOpusFile *op_vtest_url(const char *_url, + int *_error,va_list _ap) OP_ARG_NONNULL(1); + +/**Partially open a stream from a URL. + \note If you use this function, you must link against libopusurl. + \see op_test_callbacks + \param _url The URL to open. + Currently only the , , and + schemes are supported. + Both and may be disabled at compile + time, in which case opening such URLs will always fail. + Currently this only supports URIs. + IRIs should be converted to UTF-8 and URL-escaped, with + internationalized domain names encoded in punycode, + before passing them to this function. + \param[out] _error Returns 0 on success, or a failure code on error. + You may pass in NULL if you don't want the + failure code. + See op_open_callbacks() for a full list of failure + codes. + \param ... The \ref url_options "optional flags" to use. + This is a variable-length list of options terminated + with NULL. + \return A partially opened \c OggOpusFile, or NULL on error.*/ +OP_WARN_UNUSED_RESULT OggOpusFile *op_test_url(const char *_url, + int *_error,...) OP_ARG_NONNULL(1); + +/**Partially open a stream using the given set of callbacks to access it. + This tests for Opusness and loads the headers for the first link. + It does not seek (although it tests for seekability). + You can query a partially open stream for the few pieces of basic + information returned by op_serialno(), op_channel_count(), op_head(), and + op_tags() (but only for the first link). + You may also determine if it is seekable via a call to op_seekable(). + You cannot read audio from the stream, seek, get the size or duration, + get information from links other than the first one, or even get the total + number of links until you finish opening the stream with op_test_open(). + If you do not need to do any of these things, you can dispose of it with + op_free() instead. + + This function is provided mostly to simplify porting existing code that used + libvorbisfile. + For new code, you are likely better off using op_test() instead, which + is less resource-intensive, requires less data to succeed, and imposes a + hard limit on the amount of data it examines (important for unseekable + streams, where all such data must be buffered until you are sure of the + stream type). + \param _stream The stream to read from (e.g., a FILE *). + This value will be passed verbatim as the first + argument to all of the callbacks. + \param _cb The callbacks with which to access the stream. + read() must + be implemented. + seek() and + tell() may + be NULL, or may always return -1 to + indicate a stream is unseekable, but if + seek() is + implemented and succeeds on a particular stream, then + tell() must + also. + close() may + be NULL, but if it is not, it will be + called when the \c OggOpusFile is destroyed by + op_free(). + It will not be called if op_open_callbacks() fails + with an error. + \param _initial_data An initial buffer of data from the start of the + stream. + Applications can read some number of bytes from the + start of the stream to help identify this as an Opus + stream, and then provide them here to allow the + stream to be tested more thoroughly, even if it is + unseekable. + \param _initial_bytes The number of bytes in \a _initial_data. + If the stream is seekable, its current position (as + reported by + tell() + at the start of this function) must be equal to + \a _initial_bytes. + Otherwise, seeking to absolute positions will + generate inconsistent results. + \param[out] _error Returns 0 on success, or a failure code on error. + You may pass in NULL if you don't want + the failure code. + See op_open_callbacks() for a full list of failure + codes. + \return A partially opened \c OggOpusFile, or NULL on error. + libopusfile does not take ownership of the stream + if the call fails. + The calling application is responsible for closing the stream if + this call returns an error.*/ +OP_WARN_UNUSED_RESULT OggOpusFile *op_test_callbacks(void *_stream, + const OpusFileCallbacks *_cb,const unsigned char *_initial_data, + size_t _initial_bytes,int *_error) OP_ARG_NONNULL(2); + +/**Finish opening a stream partially opened with op_test_callbacks() or one of + the associated convenience functions. + If this function fails, you are still responsible for freeing the + \c OggOpusFile with op_free(). + \param _of The \c OggOpusFile to finish opening. + \return 0 on success, or a negative value on error. + \retval #OP_EREAD An underlying read, seek, or tell operation failed + when it should have succeeded. + \retval #OP_EFAULT There was a memory allocation failure, or an + internal library error. + \retval #OP_EIMPL The stream used a feature that is not implemented, + such as an unsupported channel family. + \retval #OP_EINVAL The stream was not partially opened with + op_test_callbacks() or one of the associated + convenience functions. + \retval #OP_ENOTFORMAT The stream contained a link that did not have any + logical Opus streams in it. + \retval #OP_EBADHEADER A required header packet was not properly + formatted, contained illegal values, or was + missing altogether. + \retval #OP_EVERSION An ID header contained an unrecognized version + number. + \retval #OP_EBADLINK We failed to find data we had seen before after + seeking. + \retval #OP_EBADTIMESTAMP The first or last timestamp in a link failed basic + validity checks.*/ +int op_test_open(OggOpusFile *_of) OP_ARG_NONNULL(1); + +/**Release all memory used by an \c OggOpusFile. + \param _of The \c OggOpusFile to free.*/ +void op_free(OggOpusFile *_of); + +/*@}*/ +/*@}*/ + +/**\defgroup stream_info Stream Information*/ +/*@{*/ +/**\name Functions for obtaining information about streams + + These functions allow you to get basic information about a stream, including + seekability, the number of links (for chained streams), plus the size, + duration, bitrate, header parameters, and meta information for each link + (or, where available, the stream as a whole). + Some of these (size, duration) are only available for seekable streams. + You can also query the current stream position, link, and playback time, + and instantaneous bitrate during playback. + + Some of these functions may be used successfully on the partially open + streams returned by op_test_callbacks() or one of the associated + convenience functions. + Their documention will indicate so explicitly.*/ +/*@{*/ + +/**Returns whether or not the stream being read is seekable. + This is true if +
      +
    1. The seek() and + tell() callbacks are both + non-NULL,
    2. +
    3. The seek() callback was + successfully executed at least once, and
    4. +
    5. The tell() callback was + successfully able to report the position indicator afterwards.
    6. +
    + This function may be called on partially-opened streams. + \param _of The \c OggOpusFile whose seekable status is to be returned. + \return A non-zero value if seekable, and 0 if unseekable.*/ +int op_seekable(const OggOpusFile *_of) OP_ARG_NONNULL(1); + +/**Returns the number of links in this chained stream. + This function may be called on partially-opened streams, but it will always + return 1. + The actual number of links is not known until the stream is fully opened. + \param _of The \c OggOpusFile from which to retrieve the link count. + \return For fully-open seekable streams, this returns the total number of + links in the whole stream, which will be at least 1. + For partially-open or unseekable streams, this always returns 1.*/ +int op_link_count(const OggOpusFile *_of) OP_ARG_NONNULL(1); + +/**Get the serial number of the given link in a (possibly-chained) Ogg Opus + stream. + This function may be called on partially-opened streams, but it will always + return the serial number of the Opus stream in the first link. + \param _of The \c OggOpusFile from which to retrieve the serial number. + \param _li The index of the link whose serial number should be retrieved. + Use a negative number to get the serial number of the current + link. + \return The serial number of the given link. + If \a _li is greater than the total number of links, this returns + the serial number of the last link. + If the stream is not seekable, this always returns the serial number + of the current link.*/ +opus_uint32 op_serialno(const OggOpusFile *_of,int _li) OP_ARG_NONNULL(1); + +/**Get the channel count of the given link in a (possibly-chained) Ogg Opus + stream. + This is equivalent to op_head(_of,_li)->channel_count, but + is provided for convenience. + This function may be called on partially-opened streams, but it will always + return the channel count of the Opus stream in the first link. + \param _of The \c OggOpusFile from which to retrieve the channel count. + \param _li The index of the link whose channel count should be retrieved. + Use a negative number to get the channel count of the current + link. + \return The channel count of the given link. + If \a _li is greater than the total number of links, this returns + the channel count of the last link. + If the stream is not seekable, this always returns the channel count + of the current link.*/ +int op_channel_count(const OggOpusFile *_of,int _li) OP_ARG_NONNULL(1); + +/**Get the total (compressed) size of the stream, or of an individual link in + a (possibly-chained) Ogg Opus stream, including all headers and Ogg muxing + overhead. + \warning If the Opus stream (or link) is concurrently multiplexed with other + logical streams (e.g., video), this returns the size of the entire stream + (or link), not just the number of bytes in the first logical Opus stream. + Returning the latter would require scanning the entire file. + \param _of The \c OggOpusFile from which to retrieve the compressed size. + \param _li The index of the link whose compressed size should be computed. + Use a negative number to get the compressed size of the entire + stream. + \return The compressed size of the entire stream if \a _li is negative, the + compressed size of link \a _li if it is non-negative, or a negative + value on error. + The compressed size of the entire stream may be smaller than that + of the underlying stream if trailing garbage was detected in the + file. + \retval #OP_EINVAL The stream is not seekable (so we can't know the length), + \a _li wasn't less than the total number of links in + the stream, or the stream was only partially open.*/ +opus_int64 op_raw_total(const OggOpusFile *_of,int _li) OP_ARG_NONNULL(1); + +/**Get the total PCM length (number of samples at 48 kHz) of the stream, or of + an individual link in a (possibly-chained) Ogg Opus stream. + Users looking for op_time_total() should use op_pcm_total() + instead. + Because timestamps in Opus are fixed at 48 kHz, there is no need for a + separate function to convert this to seconds (and leaving it out avoids + introducing floating point to the API, for those that wish to avoid it). + \param _of The \c OggOpusFile from which to retrieve the PCM offset. + \param _li The index of the link whose PCM length should be computed. + Use a negative number to get the PCM length of the entire stream. + \return The PCM length of the entire stream if \a _li is negative, the PCM + length of link \a _li if it is non-negative, or a negative value on + error. + \retval #OP_EINVAL The stream is not seekable (so we can't know the length), + \a _li wasn't less than the total number of links in + the stream, or the stream was only partially open.*/ +ogg_int64_t op_pcm_total(const OggOpusFile *_of,int _li) OP_ARG_NONNULL(1); + +/**Get the ID header information for the given link in a (possibly chained) Ogg + Opus stream. + This function may be called on partially-opened streams, but it will always + return the ID header information of the Opus stream in the first link. + \param _of The \c OggOpusFile from which to retrieve the ID header + information. + \param _li The index of the link whose ID header information should be + retrieved. + Use a negative number to get the ID header information of the + current link. + For an unseekable stream, \a _li is ignored, and the ID header + information for the current link is always returned, if + available. + \return The contents of the ID header for the given link.*/ +const OpusHead *op_head(const OggOpusFile *_of,int _li) OP_ARG_NONNULL(1); + +/**Get the comment header information for the given link in a (possibly + chained) Ogg Opus stream. + This function may be called on partially-opened streams, but it will always + return the tags from the Opus stream in the first link. + \param _of The \c OggOpusFile from which to retrieve the comment header + information. + \param _li The index of the link whose comment header information should be + retrieved. + Use a negative number to get the comment header information of + the current link. + For an unseekable stream, \a _li is ignored, and the comment + header information for the current link is always returned, if + available. + \return The contents of the comment header for the given link, or + NULL if this is an unseekable stream that encountered + an invalid link.*/ +const OpusTags *op_tags(const OggOpusFile *_of,int _li) OP_ARG_NONNULL(1); + +/**Retrieve the index of the current link. + This is the link that produced the data most recently read by + op_read_float() or its associated functions, or, after a seek, the link + that the seek target landed in. + Reading more data may advance the link index (even on the first read after a + seek). + \param _of The \c OggOpusFile from which to retrieve the current link index. + \return The index of the current link on success, or a negative value on + failure. + For seekable streams, this is a number between 0 (inclusive) and the + value returned by op_link_count() (exclusive). + For unseekable streams, this value starts at 0 and increments by one + each time a new link is encountered (even though op_link_count() + always returns 1). + \retval #OP_EINVAL The stream was only partially open.*/ +int op_current_link(const OggOpusFile *_of) OP_ARG_NONNULL(1); + +/**Computes the bitrate of the stream, or of an individual link in a + (possibly-chained) Ogg Opus stream. + The stream must be seekable to compute the bitrate. + For unseekable streams, use op_bitrate_instant() to get periodic estimates. + \warning If the Opus stream (or link) is concurrently multiplexed with other + logical streams (e.g., video), this uses the size of the entire stream (or + link) to compute the bitrate, not just the number of bytes in the first + logical Opus stream. + Returning the latter requires scanning the entire file, but this may be done + by decoding the whole file and calling op_bitrate_instant() once at the + end. + Install a trivial decoding callback with op_set_decode_callback() if you + wish to skip actual decoding during this process. + \param _of The \c OggOpusFile from which to retrieve the bitrate. + \param _li The index of the link whose bitrate should be computed. + Use a negative number to get the bitrate of the whole stream. + \return The bitrate on success, or a negative value on error. + \retval #OP_EINVAL The stream was only partially open, the stream was not + seekable, or \a _li was larger than the number of + links.*/ +opus_int32 op_bitrate(const OggOpusFile *_of,int _li) OP_ARG_NONNULL(1); + +/**Compute the instantaneous bitrate, measured as the ratio of bits to playable + samples decoded since a) the last call to op_bitrate_instant(), b) the last + seek, or c) the start of playback, whichever was most recent. + This will spike somewhat after a seek or at the start/end of a chain + boundary, as pre-skip, pre-roll, and end-trimming causes samples to be + decoded but not played. + \param _of The \c OggOpusFile from which to retrieve the bitrate. + \return The bitrate, in bits per second, or a negative value on error. + \retval #OP_FALSE No data has been decoded since any of the events + described above. + \retval #OP_EINVAL The stream was only partially open.*/ +opus_int32 op_bitrate_instant(OggOpusFile *_of) OP_ARG_NONNULL(1); + +/**Obtain the current value of the position indicator for \a _of. + \param _of The \c OggOpusFile from which to retrieve the position indicator. + \return The byte position that is currently being read from. + \retval #OP_EINVAL The stream was only partially open.*/ +opus_int64 op_raw_tell(const OggOpusFile *_of) OP_ARG_NONNULL(1); + +/**Obtain the PCM offset of the next sample to be read. + If the stream is not properly timestamped, this might not increment by the + proper amount between reads, or even return monotonically increasing + values. + \param _of The \c OggOpusFile from which to retrieve the PCM offset. + \return The PCM offset of the next sample to be read. + \retval #OP_EINVAL The stream was only partially open.*/ +ogg_int64_t op_pcm_tell(const OggOpusFile *_of) OP_ARG_NONNULL(1); + +/*@}*/ +/*@}*/ + +/**\defgroup stream_seeking Seeking*/ +/*@{*/ +/**\name Functions for seeking in Opus streams + + These functions let you seek in Opus streams, if the underlying stream + support it. + Seeking is implemented for all built-in stream I/O routines, though some + individual streams may not be seekable (pipes, live HTTP streams, or HTTP + streams from a server that does not support Range requests). + + op_raw_seek() is the fastest: it is guaranteed to perform at most one + physical seek, but, since the target is a byte position, makes no guarantee + how close to a given time it will come. + op_pcm_seek() provides sample-accurate seeking. + The number of physical seeks it requires is still quite small (often 1 or + 2, even in highly variable bitrate streams). + + Seeking in Opus requires decoding some pre-roll amount before playback to + allow the internal state to converge (as if recovering from packet loss). + This is handled internally by libopusfile, but means there is + little extra overhead for decoding up to the exact position requested + (since it must decode some amount of audio anyway). + It also means that decoding after seeking may not return exactly the same + values as would be obtained by decoding the stream straight through. + However, such differences are expected to be smaller than the loss + introduced by Opus's lossy compression.*/ +/*@{*/ + +/**Seek to a byte offset relative to the compressed data. + This also scans packets to update the PCM cursor. + It will cross a logical bitstream boundary, but only if it can't get any + packets out of the tail of the link to which it seeks. + \param _of The \c OggOpusFile in which to seek. + \param _byte_offset The byte position to seek to. + This must be between 0 and #op_raw_total(\a _of,\c -1) + (inclusive). + \return 0 on success, or a negative error code on failure. + \retval #OP_EREAD The underlying seek operation failed. + \retval #OP_EINVAL The stream was only partially open, or the target was + outside the valid range for the stream. + \retval #OP_ENOSEEK This stream is not seekable. + \retval #OP_EBADLINK Failed to initialize a decoder for a stream for an + unknown reason.*/ +int op_raw_seek(OggOpusFile *_of,opus_int64 _byte_offset) OP_ARG_NONNULL(1); + +/**Seek to the specified PCM offset, such that decoding will begin at exactly + the requested position. + \param _of The \c OggOpusFile in which to seek. + \param _pcm_offset The PCM offset to seek to. + This is in samples at 48 kHz relative to the start of the + stream. + \return 0 on success, or a negative value on error. + \retval #OP_EREAD An underlying read or seek operation failed. + \retval #OP_EINVAL The stream was only partially open, or the target was + outside the valid range for the stream. + \retval #OP_ENOSEEK This stream is not seekable. + \retval #OP_EBADLINK We failed to find data we had seen before, or the + bitstream structure was sufficiently malformed that + seeking to the target destination was impossible.*/ +int op_pcm_seek(OggOpusFile *_of,ogg_int64_t _pcm_offset) OP_ARG_NONNULL(1); + +/*@}*/ +/*@}*/ + +/**\defgroup stream_decoding Decoding*/ +/*@{*/ +/**\name Functions for decoding audio data + + These functions retrieve actual decoded audio data from the stream. + The general functions, op_read() and op_read_float() return 16-bit or + floating-point output, both using native endian ordering. + The number of channels returned can change from link to link in a chained + stream. + There are special functions, op_read_stereo() and op_read_float_stereo(), + which always output two channels, to simplify applications which do not + wish to handle multichannel audio. + These downmix multichannel files to two channels, so they can always return + samples in the same format for every link in a chained file. + + If the rest of your audio processing chain can handle floating point, the + floating-point routines should be preferred, as they prevent clipping and + other issues which might be avoided entirely if, e.g., you scale down the + volume at some other stage. + However, if you intend to consume 16-bit samples directly, the conversion in + libopusfile provides noise-shaping dithering and, if compiled + against libopus 1.1 or later, soft-clipping prevention. + + libopusfile can also be configured at compile time to use the + fixed-point libopus API. + If so, libopusfile's floating-point API may also be disabled. + In that configuration, nothing in libopusfile will use any + floating-point operations, to simplify support on devices without an + adequate FPU. + + \warning HTTPS streams may be be vulnerable to truncation attacks if you do + not check the error return code from op_read_float() or its associated + functions. + If the remote peer does not close the connection gracefully (with a TLS + "close notify" message), these functions will return #OP_EREAD instead of 0 + when they reach the end of the file. + If you are reading from an URL (particularly if seeking is not + supported), you should make sure to check for this error and warn the user + appropriately.*/ +/*@{*/ + +/**Indicates that the decoding callback should produce signed 16-bit + native-endian output samples.*/ +#define OP_DEC_FORMAT_SHORT (7008) +/**Indicates that the decoding callback should produce 32-bit native-endian + float samples.*/ +#define OP_DEC_FORMAT_FLOAT (7040) + +/**Indicates that the decoding callback did not decode anything, and that + libopusfile should decode normally instead.*/ +#define OP_DEC_USE_DEFAULT (6720) + +/**Called to decode an Opus packet. + This should invoke the functional equivalent of opus_multistream_decode() or + opus_multistream_decode_float(), except that it returns 0 on success + instead of the number of decoded samples (which is known a priori). + \param _ctx The application-provided callback context. + \param _decoder The decoder to use to decode the packet. + \param[out] _pcm The buffer to decode into. + This will always have enough room for \a _nchannels of + \a _nsamples samples, which should be placed into this + buffer interleaved. + \param _op The packet to decode. + This will always have its granule position set to a valid + value. + \param _nsamples The number of samples expected from the packet. + \param _nchannels The number of channels expected from the packet. + \param _format The desired sample output format. + This is either #OP_DEC_FORMAT_SHORT or + #OP_DEC_FORMAT_FLOAT. + \param _li The index of the link from which this packet was decoded. + \return A non-negative value on success, or a negative value on error. + Any error codes should be the same as those returned by + opus_multistream_decode() or opus_multistream_decode_float(). + Success codes are as follows: + \retval 0 Decoding was successful. + The application has filled the buffer with + exactly \a _nsamples*\a + _nchannels samples in the requested + format. + \retval #OP_DEC_USE_DEFAULT No decoding was done. + libopusfile should do the decoding + by itself instead.*/ +typedef int (*op_decode_cb_func)(void *_ctx,OpusMSDecoder *_decoder,void *_pcm, + const ogg_packet *_op,int _nsamples,int _nchannels,int _format,int _li); + +/**Sets the packet decode callback function. + If set, this is called once for each packet that needs to be decoded. + This can be used by advanced applications to do additional processing on the + compressed or uncompressed data. + For example, an application might save the final entropy coder state for + debugging and testing purposes, or it might apply additional filters + before the downmixing, dithering, or soft-clipping performed by + libopusfile, so long as these filters do not introduce any + latency. + + A call to this function is no guarantee that the audio will eventually be + delivered to the application. + libopusfile may discard some or all of the decoded audio data + (i.e., at the beginning or end of a link, or after a seek), however the + callback is still required to provide all of it. + \param _of The \c OggOpusFile on which to set the decode callback. + \param _decode_cb The callback function to call. + This may be NULL to disable calling the + callback. + \param _ctx The application-provided context pointer to pass to the + callback on each call.*/ +void op_set_decode_callback(OggOpusFile *_of, + op_decode_cb_func _decode_cb,void *_ctx) OP_ARG_NONNULL(1); + +/**Gain offset type that indicates that the provided offset is relative to the + header gain. + This is the default.*/ +#define OP_HEADER_GAIN (0) + +/**Gain offset type that indicates that the provided offset is relative to the + R128_ALBUM_GAIN value (if any), in addition to the header gain.*/ +#define OP_ALBUM_GAIN (3007) + +/**Gain offset type that indicates that the provided offset is relative to the + R128_TRACK_GAIN value (if any), in addition to the header gain.*/ +#define OP_TRACK_GAIN (3008) + +/**Gain offset type that indicates that the provided offset should be used as + the gain directly, without applying any the header or track gains.*/ +#define OP_ABSOLUTE_GAIN (3009) + +/**Sets the gain to be used for decoded output. + By default, the gain in the header is applied with no additional offset. + The total gain (including header gain and/or track gain, if applicable, and + this offset), will be clamped to [-32768,32767]/256 dB. + This is more than enough to saturate or underflow 16-bit PCM. + \note The new gain will not be applied to any already buffered, decoded + output. + This means you cannot change it sample-by-sample, as at best it will be + updated packet-by-packet. + It is meant for setting a target volume level, rather than applying smooth + fades, etc. + \param _of The \c OggOpusFile on which to set the gain offset. + \param _gain_type One of #OP_HEADER_GAIN, #OP_ALBUM_GAIN, + #OP_TRACK_GAIN, or #OP_ABSOLUTE_GAIN. + \param _gain_offset_q8 The gain offset to apply, in 1/256ths of a dB. + \return 0 on success or a negative value on error. + \retval #OP_EINVAL The \a _gain_type was unrecognized.*/ +int op_set_gain_offset(OggOpusFile *_of, + int _gain_type,opus_int32 _gain_offset_q8) OP_ARG_NONNULL(1); + +/**Sets whether or not dithering is enabled for 16-bit decoding. + By default, when libopusfile is compiled to use floating-point + internally, calling op_read() or op_read_stereo() will first decode to + float, and then convert to fixed-point using noise-shaping dithering. + This flag can be used to disable that dithering. + When the application uses op_read_float() or op_read_float_stereo(), or when + the library has been compiled to decode directly to fixed point, this flag + has no effect. + \param _of The \c OggOpusFile on which to enable or disable dithering. + \param _enabled A non-zero value to enable dithering, or 0 to disable it.*/ +void op_set_dither_enabled(OggOpusFile *_of,int _enabled) OP_ARG_NONNULL(1); + +/**Reads more samples from the stream. + \note Although \a _buf_size must indicate the total number of values that + can be stored in \a _pcm, the return value is the number of samples + per channel. + This is done because +
      +
    1. The channel count cannot be known a priori (reading more samples might + advance us into the next link, with a different channel count), so + \a _buf_size cannot also be in units of samples per channel,
    2. +
    3. Returning the samples per channel matches the libopus API + as closely as we're able,
    4. +
    5. Returning the total number of values instead of samples per channel + would mean the caller would need a division to compute the samples per + channel, and might worry about the possibility of getting back samples + for some channels and not others, and
    6. +
    7. This approach is relatively fool-proof: if an application passes too + small a value to \a _buf_size, they will simply get fewer samples back, + and if they assume the return value is the total number of values, then + they will simply read too few (rather than reading too many and going + off the end of the buffer).
    8. +
    + \param _of The \c OggOpusFile from which to read. + \param[out] _pcm A buffer in which to store the output PCM samples, as + signed native-endian 16-bit values at 48 kHz + with a nominal range of [-32768,32767). + Multiple channels are interleaved using the + Vorbis + channel ordering. + This must have room for at least \a _buf_size values. + \param _buf_size The number of values that can be stored in \a _pcm. + It is recommended that this be large enough for at + least 120 ms of data at 48 kHz per channel (5760 + values per channel). + Smaller buffers will simply return less data, possibly + consuming more memory to buffer the data internally. + libopusfile may return less data than + requested. + If so, there is no guarantee that the remaining data + in \a _pcm will be unmodified. + \param[out] _li The index of the link this data was decoded from. + You may pass NULL if you do not need this + information. + If this function fails (returning a negative value), + this parameter is left unset. + \return The number of samples read per channel on success, or a negative + value on failure. + The channel count can be retrieved on success by calling + op_head(_of,*_li). + The number of samples returned may be 0 if the buffer was too small + to store even a single sample for all channels, or if end-of-file + was reached. + The list of possible failure codes follows. + Most of them can only be returned by unseekable, chained streams + that encounter a new link. + \retval #OP_HOLE There was a hole in the data, and some samples + may have been skipped. + Call this function again to continue decoding + past the hole. + \retval #OP_EREAD An underlying read operation failed. + This may signal a truncation attack from an + source. + \retval #OP_EFAULT An internal memory allocation failed. + \retval #OP_EIMPL An unseekable stream encountered a new link that + used a feature that is not implemented, such as + an unsupported channel family. + \retval #OP_EINVAL The stream was only partially open. + \retval #OP_ENOTFORMAT An unseekable stream encountered a new link that + did not have any logical Opus streams in it. + \retval #OP_EBADHEADER An unseekable stream encountered a new link with a + required header packet that was not properly + formatted, contained illegal values, or was + missing altogether. + \retval #OP_EVERSION An unseekable stream encountered a new link with + an ID header that contained an unrecognized + version number. + \retval #OP_EBADPACKET Failed to properly decode the next packet. + \retval #OP_EBADLINK We failed to find data we had seen before. + \retval #OP_EBADTIMESTAMP An unseekable stream encountered a new link with + a starting timestamp that failed basic validity + checks.*/ +OP_WARN_UNUSED_RESULT int op_read(OggOpusFile *_of, + opus_int16 *_pcm,int _buf_size,int *_li) OP_ARG_NONNULL(1); + +/**Reads more samples from the stream. + \note Although \a _buf_size must indicate the total number of values that + can be stored in \a _pcm, the return value is the number of samples + per channel. +
      +
    1. The channel count cannot be known a priori (reading more samples might + advance us into the next link, with a different channel count), so + \a _buf_size cannot also be in units of samples per channel,
    2. +
    3. Returning the samples per channel matches the libopus API + as closely as we're able,
    4. +
    5. Returning the total number of values instead of samples per channel + would mean the caller would need a division to compute the samples per + channel, and might worry about the possibility of getting back samples + for some channels and not others, and
    6. +
    7. This approach is relatively fool-proof: if an application passes too + small a value to \a _buf_size, they will simply get fewer samples back, + and if they assume the return value is the total number of values, then + they will simply read too few (rather than reading too many and going + off the end of the buffer).
    8. +
    + \param _of The \c OggOpusFile from which to read. + \param[out] _pcm A buffer in which to store the output PCM samples as + signed floats at 48 kHz with a nominal range of + [-1.0,1.0]. + Multiple channels are interleaved using the + Vorbis + channel ordering. + This must have room for at least \a _buf_size floats. + \param _buf_size The number of floats that can be stored in \a _pcm. + It is recommended that this be large enough for at + least 120 ms of data at 48 kHz per channel (5760 + samples per channel). + Smaller buffers will simply return less data, possibly + consuming more memory to buffer the data internally. + If less than \a _buf_size values are returned, + libopusfile makes no guarantee that the + remaining data in \a _pcm will be unmodified. + \param[out] _li The index of the link this data was decoded from. + You may pass NULL if you do not need this + information. + If this function fails (returning a negative value), + this parameter is left unset. + \return The number of samples read per channel on success, or a negative + value on failure. + The channel count can be retrieved on success by calling + op_head(_of,*_li). + The number of samples returned may be 0 if the buffer was too small + to store even a single sample for all channels, or if end-of-file + was reached. + The list of possible failure codes follows. + Most of them can only be returned by unseekable, chained streams + that encounter a new link. + \retval #OP_HOLE There was a hole in the data, and some samples + may have been skipped. + Call this function again to continue decoding + past the hole. + \retval #OP_EREAD An underlying read operation failed. + This may signal a truncation attack from an + source. + \retval #OP_EFAULT An internal memory allocation failed. + \retval #OP_EIMPL An unseekable stream encountered a new link that + used a feature that is not implemented, such as + an unsupported channel family. + \retval #OP_EINVAL The stream was only partially open. + \retval #OP_ENOTFORMAT An unseekable stream encountered a new link that + did not have any logical Opus streams in it. + \retval #OP_EBADHEADER An unseekable stream encountered a new link with a + required header packet that was not properly + formatted, contained illegal values, or was + missing altogether. + \retval #OP_EVERSION An unseekable stream encountered a new link with + an ID header that contained an unrecognized + version number. + \retval #OP_EBADPACKET Failed to properly decode the next packet. + \retval #OP_EBADLINK We failed to find data we had seen before. + \retval #OP_EBADTIMESTAMP An unseekable stream encountered a new link with + a starting timestamp that failed basic validity + checks.*/ +OP_WARN_UNUSED_RESULT int op_read_float(OggOpusFile *_of, + float *_pcm,int _buf_size,int *_li) OP_ARG_NONNULL(1); + +/**Reads more samples from the stream and downmixes to stereo, if necessary. + This function is intended for simple players that want a uniform output + format, even if the channel count changes between links in a chained + stream. + \note \a _buf_size indicates the total number of values that can be stored + in \a _pcm, while the return value is the number of samples per + channel, even though the channel count is known, for consistency with + op_read(). + \param _of The \c OggOpusFile from which to read. + \param[out] _pcm A buffer in which to store the output PCM samples, as + signed native-endian 16-bit values at 48 kHz + with a nominal range of [-32768,32767). + The left and right channels are interleaved in the + buffer. + This must have room for at least \a _buf_size values. + \param _buf_size The number of values that can be stored in \a _pcm. + It is recommended that this be large enough for at + least 120 ms of data at 48 kHz per channel (11520 + values total). + Smaller buffers will simply return less data, possibly + consuming more memory to buffer the data internally. + If less than \a _buf_size values are returned, + libopusfile makes no guarantee that the + remaining data in \a _pcm will be unmodified. + \return The number of samples read per channel on success, or a negative + value on failure. + The number of samples returned may be 0 if the buffer was too small + to store even a single sample for both channels, or if end-of-file + was reached. + The list of possible failure codes follows. + Most of them can only be returned by unseekable, chained streams + that encounter a new link. + \retval #OP_HOLE There was a hole in the data, and some samples + may have been skipped. + Call this function again to continue decoding + past the hole. + \retval #OP_EREAD An underlying read operation failed. + This may signal a truncation attack from an + source. + \retval #OP_EFAULT An internal memory allocation failed. + \retval #OP_EIMPL An unseekable stream encountered a new link that + used a feature that is not implemented, such as + an unsupported channel family. + \retval #OP_EINVAL The stream was only partially open. + \retval #OP_ENOTFORMAT An unseekable stream encountered a new link that + did not have any logical Opus streams in it. + \retval #OP_EBADHEADER An unseekable stream encountered a new link with a + required header packet that was not properly + formatted, contained illegal values, or was + missing altogether. + \retval #OP_EVERSION An unseekable stream encountered a new link with + an ID header that contained an unrecognized + version number. + \retval #OP_EBADPACKET Failed to properly decode the next packet. + \retval #OP_EBADLINK We failed to find data we had seen before. + \retval #OP_EBADTIMESTAMP An unseekable stream encountered a new link with + a starting timestamp that failed basic validity + checks.*/ +OP_WARN_UNUSED_RESULT int op_read_stereo(OggOpusFile *_of, + opus_int16 *_pcm,int _buf_size) OP_ARG_NONNULL(1); + +/**Reads more samples from the stream and downmixes to stereo, if necessary. + This function is intended for simple players that want a uniform output + format, even if the channel count changes between links in a chained + stream. + \note \a _buf_size indicates the total number of values that can be stored + in \a _pcm, while the return value is the number of samples per + channel, even though the channel count is known, for consistency with + op_read_float(). + \param _of The \c OggOpusFile from which to read. + \param[out] _pcm A buffer in which to store the output PCM samples, as + signed floats at 48 kHz with a nominal range of + [-1.0,1.0]. + The left and right channels are interleaved in the + buffer. + This must have room for at least \a _buf_size values. + \param _buf_size The number of values that can be stored in \a _pcm. + It is recommended that this be large enough for at + least 120 ms of data at 48 kHz per channel (11520 + values total). + Smaller buffers will simply return less data, possibly + consuming more memory to buffer the data internally. + If less than \a _buf_size values are returned, + libopusfile makes no guarantee that the + remaining data in \a _pcm will be unmodified. + \return The number of samples read per channel on success, or a negative + value on failure. + The number of samples returned may be 0 if the buffer was too small + to store even a single sample for both channels, or if end-of-file + was reached. + The list of possible failure codes follows. + Most of them can only be returned by unseekable, chained streams + that encounter a new link. + \retval #OP_HOLE There was a hole in the data, and some samples + may have been skipped. + Call this function again to continue decoding + past the hole. + \retval #OP_EREAD An underlying read operation failed. + This may signal a truncation attack from an + source. + \retval #OP_EFAULT An internal memory allocation failed. + \retval #OP_EIMPL An unseekable stream encountered a new link that + used a feature that is not implemented, such as + an unsupported channel family. + \retval #OP_EINVAL The stream was only partially open. + \retval #OP_ENOTFORMAT An unseekable stream encountered a new link that + that did not have any logical Opus streams in it. + \retval #OP_EBADHEADER An unseekable stream encountered a new link with a + required header packet that was not properly + formatted, contained illegal values, or was + missing altogether. + \retval #OP_EVERSION An unseekable stream encountered a new link with + an ID header that contained an unrecognized + version number. + \retval #OP_EBADPACKET Failed to properly decode the next packet. + \retval #OP_EBADLINK We failed to find data we had seen before. + \retval #OP_EBADTIMESTAMP An unseekable stream encountered a new link with + a starting timestamp that failed basic validity + checks.*/ +OP_WARN_UNUSED_RESULT int op_read_float_stereo(OggOpusFile *_of, + float *_pcm,int _buf_size) OP_ARG_NONNULL(1); + +/*@}*/ +/*@}*/ + +# if OP_GNUC_PREREQ(4,0) +# pragma GCC visibility pop +# endif + +# if defined(__cplusplus) +} +# endif + +#endif diff --git a/extern/opusfile/m4/attributes.m4 b/extern/opusfile/m4/attributes.m4 new file mode 100644 index 0000000..ebc7347 --- /dev/null +++ b/extern/opusfile/m4/attributes.m4 @@ -0,0 +1,321 @@ +dnl Macros to check the presence of generic (non-typed) symbols. +dnl Copyright (c) 2006-2007 Diego Pettenò +dnl Copyright (c) 2006-2007 xine project +dnl +dnl This program is free software; you can redistribute it and/or modify +dnl it under the terms of the GNU General Public License as published by +dnl the Free Software Foundation; either version 2, or (at your option) +dnl any later version. +dnl +dnl This program is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +dnl GNU General Public License for more details. +dnl +dnl You should have received a copy of the GNU General Public License +dnl along with this program; if not, write to the Free Software +dnl Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +dnl 02110-1301, USA. +dnl +dnl As a special exception, the copyright owners of the +dnl macro gives unlimited permission to copy, distribute and modify the +dnl configure scripts that are the output of Autoconf when processing the +dnl Macro. You need not follow the terms of the GNU General Public +dnl License when using or distributing such scripts, even though portions +dnl of the text of the Macro appear in them. The GNU General Public +dnl License (GPL) does govern all other use of the material that +dnl constitutes the Autoconf Macro. +dnl +dnl This special exception to the GPL applies to versions of the +dnl Autoconf Macro released by this project. When you make and +dnl distribute a modified version of the Autoconf Macro, you may extend +dnl this special exception to the GPL to apply to your modified version as +dnl well. + +dnl Check if the flag is supported by compiler +dnl CC_CHECK_CFLAGS_SILENT([FLAG], [ACTION-IF-FOUND],[ACTION-IF-NOT-FOUND]) + +AC_DEFUN([CC_CHECK_CFLAGS_SILENT], [ + AC_CACHE_VAL(AS_TR_SH([cc_cv_cflags_$1]), + [ac_save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $1" + AC_LINK_IFELSE([AC_LANG_SOURCE([int main() { return 0; }])], + [eval "AS_TR_SH([cc_cv_cflags_$1])='yes'"], + [eval "AS_TR_SH([cc_cv_cflags_$1])='no'"]) + CFLAGS="$ac_save_CFLAGS" + ]) + + AS_IF([eval test x$]AS_TR_SH([cc_cv_cflags_$1])[ = xyes], + [$2], [$3]) +]) + +dnl Check if the flag is supported by compiler (cacheable) +dnl CC_CHECK_CFLAGS([FLAG], [ACTION-IF-FOUND],[ACTION-IF-NOT-FOUND]) + +AC_DEFUN([CC_CHECK_CFLAGS], [ + AC_CACHE_CHECK([if $CC supports $1 flag], + AS_TR_SH([cc_cv_cflags_$1]), + CC_CHECK_CFLAGS_SILENT([$1]) dnl Don't execute actions here! + ) + + AS_IF([eval test x$]AS_TR_SH([cc_cv_cflags_$1])[ = xyes], + [$2], [$3]) +]) + +dnl CC_CHECK_CFLAG_APPEND(FLAG, [action-if-found], [action-if-not-found]) +dnl Check for CFLAG and appends them to CFLAGS if supported +AC_DEFUN([CC_CHECK_CFLAG_APPEND], [ + AC_CACHE_CHECK([if $CC supports $1 flag], + AS_TR_SH([cc_cv_cflags_$1]), + CC_CHECK_CFLAGS_SILENT([$1]) dnl Don't execute actions here! + ) + + AS_IF([eval test x$]AS_TR_SH([cc_cv_cflags_$1])[ = xyes], + [CFLAGS="$CFLAGS $1"; $2], [$3]) +]) + +dnl CC_CHECK_CFLAGS_APPEND([FLAG1 FLAG2], [action-if-found], [action-if-not]) +AC_DEFUN([CC_CHECK_CFLAGS_APPEND], [ + for flag in $1; do + CC_CHECK_CFLAG_APPEND($flag, [$2], [$3]) + done +]) + +dnl Check if the flag is supported by linker (cacheable) +dnl CC_CHECK_LDFLAGS([FLAG], [ACTION-IF-FOUND],[ACTION-IF-NOT-FOUND]) + +AC_DEFUN([CC_CHECK_LDFLAGS], [ + AC_CACHE_CHECK([if $CC supports $1 flag], + AS_TR_SH([cc_cv_ldflags_$1]), + [ac_save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS $1" + AC_LINK_IFELSE([AC_LANG_SOURCE([int main() { return 1; }])], + [eval "AS_TR_SH([cc_cv_ldflags_$1])='yes'"], + [eval "AS_TR_SH([cc_cv_ldflags_$1])="]) + LDFLAGS="$ac_save_LDFLAGS" + ]) + + AS_IF([eval test x$]AS_TR_SH([cc_cv_ldflags_$1])[ = xyes], + [$2], [$3]) +]) + +dnl define the LDFLAGS_NOUNDEFINED variable with the correct value for +dnl the current linker to avoid undefined references in a shared object. +AC_DEFUN([CC_NOUNDEFINED], [ + dnl We check $host for which systems to enable this for. + AC_REQUIRE([AC_CANONICAL_HOST]) + + case $host in + dnl FreeBSD (et al.) does not complete linking for shared objects when pthreads + dnl are requested, as different implementations are present; to avoid problems + dnl use -Wl,-z,defs only for those platform not behaving this way. + *-freebsd* | *-openbsd*) ;; + *) + dnl First of all check for the --no-undefined variant of GNU ld. This allows + dnl for a much more readable commandline, so that people can understand what + dnl it does without going to look for what the heck -z defs does. + for possible_flags in "-Wl,--no-undefined" "-Wl,-z,defs"; do + CC_CHECK_LDFLAGS([$possible_flags], [LDFLAGS_NOUNDEFINED="$possible_flags"]) + break + done + ;; + esac + + AC_SUBST([LDFLAGS_NOUNDEFINED]) +]) + +dnl Check for a -Werror flag or equivalent. -Werror is the GCC +dnl and ICC flag that tells the compiler to treat all the warnings +dnl as fatal. We usually need this option to make sure that some +dnl constructs (like attributes) are not simply ignored. +dnl +dnl Other compilers don't support -Werror per se, but they support +dnl an equivalent flag: +dnl - Sun Studio compiler supports -errwarn=%all +AC_DEFUN([CC_CHECK_WERROR], [ + AC_CACHE_CHECK( + [for $CC way to treat warnings as errors], + [cc_cv_werror], + [CC_CHECK_CFLAGS_SILENT([-Werror], [cc_cv_werror=-Werror], + [CC_CHECK_CFLAGS_SILENT([-errwarn=%all], [cc_cv_werror=-errwarn=%all])]) + ]) +]) + +AC_DEFUN([CC_CHECK_ATTRIBUTE], [ + AC_REQUIRE([CC_CHECK_WERROR]) + AC_CACHE_CHECK([if $CC supports __attribute__(( ifelse([$2], , [$1], [$2]) ))], + AS_TR_SH([cc_cv_attribute_$1]), + [ac_save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $cc_cv_werror" + AC_COMPILE_IFELSE([AC_LANG_SOURCE([$3])], + [eval "AS_TR_SH([cc_cv_attribute_$1])='yes'"], + [eval "AS_TR_SH([cc_cv_attribute_$1])='no'"]) + CFLAGS="$ac_save_CFLAGS" + ]) + + AS_IF([eval test x$]AS_TR_SH([cc_cv_attribute_$1])[ = xyes], + [AC_DEFINE( + AS_TR_CPP([SUPPORT_ATTRIBUTE_$1]), 1, + [Define this if the compiler supports __attribute__(( ifelse([$2], , [$1], [$2]) ))] + ) + $4], + [$5]) +]) + +AC_DEFUN([CC_ATTRIBUTE_CONSTRUCTOR], [ + CC_CHECK_ATTRIBUTE( + [constructor],, + [extern void foo(); + void __attribute__((constructor)) ctor() { foo(); }], + [$1], [$2]) +]) + +AC_DEFUN([CC_ATTRIBUTE_DESTRUCTOR], [ + CC_CHECK_ATTRIBUTE( + [destructor],, + [extern void foo(); + void __attribute__((destructor)) dtor() { foo(); }], + [$1], [$2]) +]) + +AC_DEFUN([CC_ATTRIBUTE_FORMAT], [ + CC_CHECK_ATTRIBUTE( + [format], [format(printf, n, n)], + [void __attribute__((format(printf, 1, 2))) printflike(const char *fmt, ...) { fmt = (void *)0; }], + [$1], [$2]) +]) + +AC_DEFUN([CC_ATTRIBUTE_FORMAT_ARG], [ + CC_CHECK_ATTRIBUTE( + [format_arg], [format_arg(printf)], + [char *__attribute__((format_arg(1))) gettextlike(const char *fmt) { fmt = (void *)0; }], + [$1], [$2]) +]) + +AC_DEFUN([CC_ATTRIBUTE_VISIBILITY], [ + CC_CHECK_ATTRIBUTE( + [visibility_$1], [visibility("$1")], + [void __attribute__((visibility("$1"))) $1_function() { }], + [$2], [$3]) +]) + +AC_DEFUN([CC_ATTRIBUTE_NONNULL], [ + CC_CHECK_ATTRIBUTE( + [nonnull], [nonnull()], + [void __attribute__((nonnull())) some_function(void *foo, void *bar) { foo = (void*)0; bar = (void*)0; }], + [$1], [$2]) +]) + +AC_DEFUN([CC_ATTRIBUTE_UNUSED], [ + CC_CHECK_ATTRIBUTE( + [unused], , + [void some_function(void *foo, __attribute__((unused)) void *bar);], + [$1], [$2]) +]) + +AC_DEFUN([CC_ATTRIBUTE_SENTINEL], [ + CC_CHECK_ATTRIBUTE( + [sentinel], , + [void some_function(void *foo, ...) __attribute__((sentinel));], + [$1], [$2]) +]) + +AC_DEFUN([CC_ATTRIBUTE_DEPRECATED], [ + CC_CHECK_ATTRIBUTE( + [deprecated], , + [void some_function(void *foo, ...) __attribute__((deprecated));], + [$1], [$2]) +]) + +AC_DEFUN([CC_ATTRIBUTE_ALIAS], [ + CC_CHECK_ATTRIBUTE( + [alias], [weak, alias], + [void other_function(void *foo) { } + void some_function(void *foo) __attribute__((weak, alias("other_function")));], + [$1], [$2]) +]) + +AC_DEFUN([CC_ATTRIBUTE_MALLOC], [ + CC_CHECK_ATTRIBUTE( + [malloc], , + [void * __attribute__((malloc)) my_alloc(int n);], + [$1], [$2]) +]) + +AC_DEFUN([CC_ATTRIBUTE_PACKED], [ + CC_CHECK_ATTRIBUTE( + [packed], , + [struct astructure { char a; int b; long c; void *d; } __attribute__((packed)); + char assert@<:@(sizeof(struct astructure) == (sizeof(char)+sizeof(int)+sizeof(long)+sizeof(void*)))-1@:>@;], + [$1], [$2]) +]) + +AC_DEFUN([CC_ATTRIBUTE_CONST], [ + CC_CHECK_ATTRIBUTE( + [const], , + [int __attribute__((const)) twopow(int n) { return 1 << n; } ], + [$1], [$2]) +]) + +AC_DEFUN([CC_FLAG_VISIBILITY], [ + AC_REQUIRE([CC_CHECK_WERROR]) + AC_CACHE_CHECK([if $CC supports -fvisibility=hidden], + [cc_cv_flag_visibility], + [cc_flag_visibility_save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $cc_cv_werror" + CC_CHECK_CFLAGS_SILENT([-fvisibility=hidden], + cc_cv_flag_visibility='yes', + cc_cv_flag_visibility='no') + CFLAGS="$cc_flag_visibility_save_CFLAGS"]) + + AS_IF([test "x$cc_cv_flag_visibility" = "xyes"], + [AC_DEFINE([SUPPORT_FLAG_VISIBILITY], 1, + [Define this if the compiler supports the -fvisibility flag]) + $1], + [$2]) +]) + +AC_DEFUN([CC_FUNC_EXPECT], [ + AC_REQUIRE([CC_CHECK_WERROR]) + AC_CACHE_CHECK([if compiler has __builtin_expect function], + [cc_cv_func_expect], + [ac_save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $cc_cv_werror" + AC_COMPILE_IFELSE([AC_LANG_SOURCE( + [int some_function() { + int a = 3; + return (int)__builtin_expect(a, 3); + }])], + [cc_cv_func_expect=yes], + [cc_cv_func_expect=no]) + CFLAGS="$ac_save_CFLAGS" + ]) + + AS_IF([test "x$cc_cv_func_expect" = "xyes"], + [AC_DEFINE([SUPPORT__BUILTIN_EXPECT], 1, + [Define this if the compiler supports __builtin_expect() function]) + $1], + [$2]) +]) + +AC_DEFUN([CC_ATTRIBUTE_ALIGNED], [ + AC_REQUIRE([CC_CHECK_WERROR]) + AC_CACHE_CHECK([highest __attribute__ ((aligned ())) supported], + [cc_cv_attribute_aligned], + [ac_save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $cc_cv_werror" + for cc_attribute_align_try in 64 32 16 8 4 2; do + AC_COMPILE_IFELSE([AC_LANG_SOURCE([ + int main() { + static char c __attribute__ ((aligned($cc_attribute_align_try))) = 0; + return c; + }])], [cc_cv_attribute_aligned=$cc_attribute_align_try; break]) + done + CFLAGS="$ac_save_CFLAGS" + ]) + + if test "x$cc_cv_attribute_aligned" != "x"; then + AC_DEFINE_UNQUOTED([ATTRIBUTE_ALIGNED_MAX], [$cc_cv_attribute_aligned], + [Define the highest alignment supported]) + fi +]) diff --git a/extern/opusfile/mingw/Dockerfile b/extern/opusfile/mingw/Dockerfile new file mode 100644 index 0000000..d85d665 --- /dev/null +++ b/extern/opusfile/mingw/Dockerfile @@ -0,0 +1,21 @@ +FROM fedora:28 +MAINTAINER opus@xiph.org + +# Linux build. +RUN dnf update -y --setopt=deltarpm=0 +RUN dnf install -y git gcc make wget xz +RUN dnf install -y autoconf automake libtool pkgconfig + +# mingw cross build. +RUN dnf install -y mingw32-gcc zip + +RUN dnf clean all + +RUN git clone https://git.xiph.org/opusfile.git + +WORKDIR opusfile +RUN git pull +COPY Makefile mingw/Makefile +RUN make -C mingw +RUN ./autogen.sh && ./configure --host=i686-w64-mingw32 --prefix=${PWD}/mingw PKG_CONFIG_PATH=${PWD}/mingw/lib/pkgconfig && make && make check && make install +RUN make -C mingw package diff --git a/extern/opusfile/mingw/README.mingw b/extern/opusfile/mingw/README.mingw new file mode 100644 index 0000000..8d5dc12 --- /dev/null +++ b/extern/opusfile/mingw/README.mingw @@ -0,0 +1,23 @@ += Cross-compiling under mingw = + +Just running 'make' in this directory should download +and build opusfile and its dependencies. Some mingw +libraries need to be compiled into the final package. + +== Generic instructions == + +To build opusfile under mingw, you need to first build: + +libogg +libopus +openssl + +For 'make check' to work, you may need wine installed. + +To build openssl, try: + + CROSS_COMPILE="i686-w64-mingw32-" ./Configure mingw no-asm no-shared --prefix=$PWD/mingw && make depend && make -j8 && make install + +To build opusfile, try: + + CC=i686-w64-mingw32-gcc PKG_CONFIG_PATH=$PWD/lib/pkgconfig RANLIB=i686-w64-mingw32-ranlib make -f ../unix/Makefile diff --git a/extern/opusfile/opusfile-uninstalled.pc.in b/extern/opusfile/opusfile-uninstalled.pc.in new file mode 100644 index 0000000..b5861a4 --- /dev/null +++ b/extern/opusfile/opusfile-uninstalled.pc.in @@ -0,0 +1,14 @@ +# opusfile uninstalled pkg-config file + +prefix= +exec_prefix= +libdir=${pcfiledir}/.libs +includedir=${pcfiledir}/@top_srcdir@/include + +Name: opusfile uninstalled +Description: High-level Opus decoding library (not installed) +Version: @PACKAGE_VERSION@ +Requires.private: ogg >= 1.3 opus >= 1.0.1 +Conflicts: +Libs: ${libdir}/libopusfile.la @lrintf_lib@ +Cflags: -I${includedir} diff --git a/extern/opusfile/opusfile.pc.in b/extern/opusfile/opusfile.pc.in new file mode 100644 index 0000000..9622591 --- /dev/null +++ b/extern/opusfile/opusfile.pc.in @@ -0,0 +1,15 @@ +# opusfile installed pkg-config file + +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: opusfile +Description: High-level Opus decoding library +Version: @PACKAGE_VERSION@ +Requires.private: ogg >= 1.3 opus >= 1.0.1 +Conflicts: +Libs: -L${libdir} -lopusfile +Libs.private: @lrintf_lib@ +Cflags: -I${includedir}/opus diff --git a/extern/opusfile/opusurl-uninstalled.pc.in b/extern/opusfile/opusurl-uninstalled.pc.in new file mode 100644 index 0000000..f47786a --- /dev/null +++ b/extern/opusfile/opusurl-uninstalled.pc.in @@ -0,0 +1,14 @@ +# opusurl uninstalled pkg-config file + +prefix= +exec_prefix= +libdir=${pcfiledir}/.libs +includedir=${pcfiledir}/@top_srcdir@/include + +Name: opusfile uninstalled +Description: High-level Opus decoding library, URL support (not installed) +Version: @PACKAGE_VERSION@ +Requires: opusfile +Requires.private: @openssl@ +Conflicts: +Libs: ${libdir}/libopusurl.la diff --git a/extern/opusfile/opusurl.pc.in b/extern/opusfile/opusurl.pc.in new file mode 100644 index 0000000..df63759 --- /dev/null +++ b/extern/opusfile/opusurl.pc.in @@ -0,0 +1,14 @@ +# opusurl installed pkg-config file + +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: opusurl +Description: High-level Opus decoding library, URL support +Version: @PACKAGE_VERSION@ +Requires: opusfile +Requires.private: @openssl@ +Conflicts: +Libs: -L${libdir} -lopusurl diff --git a/extern/opusfile/releases.sha2 b/extern/opusfile/releases.sha2 new file mode 100644 index 0000000..773e0d2 --- /dev/null +++ b/extern/opusfile/releases.sha2 @@ -0,0 +1,17 @@ +094b789ee975fbc5ac706b14e5c83f12b92448fa0a55c8a9f7d79afa7f962aae opusfile-0.1-win32.zip +33521cef2ef341a938b386439e9879d3e8e916638ffdd5a7d11e09172f307d35 opusfile-0.2-win32.zip +4248927f2c4e316ea5b84fb02bd100bfec8fa4624a6910d77f0af7f0c6cb8baa opusfile-0.3.tar.gz +9836ea11706c44f36de92c4c9b1248e03a4c521e7fb2cff18a0cb4f8b0e79140 opusfile-0.4.tar.gz +f187906b1b35f7f0d7de6a759b4aab512a9279d23adb35d8009e7e33bd6a922a opusfile-0.4.zip +ae23da5963295c6aa13c97becf50ae013e2317706f0e2a9472f2384aa70aaa43 opusfile-0.4-win32.zip +2ce52d006aeeec9f10260dbe3073c4636954a1ab19c82b8baafefe0180aa4a39 opusfile-0.5.tar.gz +b940d62beb15b5974764574b9f265481fe5b6ee16902fb705727546caf956261 opusfile-0.5.zip +93104cab67a2b038753d125028d63c0028a277e798f8ca88df73d4edbfb9a787 opusfile-0.5-win32.zip +2428717b356e139f18ed2fdb5ad990b5654a238907a0058200b39c46a7d03ea6 opusfile-0.6.tar.gz +753339225193df605372944889023b9b3c5378d672e8784d69fa241cd465278c opusfile-0.6.zip +5c461b6e037f3843b31295c1eefbaf785bf165442f47fc90267bbcbd939b6e1b opusfile-0.6-win32.zip +9e2bed13bc729058591a0f1cab2505e8cfd8e7ac460bf10a78bcc3b125e7c301 opusfile-0.7.tar.gz +346967d7989bb83b05949483b76bd0f69a12c59bd8b4457e864902b52bb0ac34 opusfile-0.7.zip +c4c4c57b6b4bc9780a08c1e6300cc35846671bee61d8487c277ea1e8041cfbf8 opusfile-0.7-win32.zip +2c231ed3cfaa1b3173f52d740e5bbd77d51b9dfecb87014b404917fba4b855a4 opusfile-0.8.tar.gz +89dff4342c3b789574cbea5c57f11b96d4ebe4d28ab90248c1783ea569b1e9e3 opusfile-0.8.zip diff --git a/extern/opusfile/src/http.c b/extern/opusfile/src/http.c new file mode 100644 index 0000000..8ba9b28 --- /dev/null +++ b/extern/opusfile/src/http.c @@ -0,0 +1,3550 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE libopusfile SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE libopusfile SOURCE CODE IS (C) COPYRIGHT 2012 * + * by the Xiph.Org Foundation and contributors http://www.xiph.org/ * + * * + ********************************************************************/ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "internal.h" +#include +#include +#include +#include + +/*RFCs referenced in this file: + RFC 761: DOD Standard Transmission Control Protocol + RFC 1535: A Security Problem and Proposed Correction With Widely Deployed DNS + Software + RFC 1738: Uniform Resource Locators (URL) + RFC 1945: Hypertext Transfer Protocol -- HTTP/1.0 + RFC 2068: Hypertext Transfer Protocol -- HTTP/1.1 + RFC 2145: Use and Interpretation of HTTP Version Numbers + RFC 2246: The TLS Protocol Version 1.0 + RFC 2459: Internet X.509 Public Key Infrastructure Certificate and + Certificate Revocation List (CRL) Profile + RFC 2616: Hypertext Transfer Protocol -- HTTP/1.1 + RFC 2617: HTTP Authentication: Basic and Digest Access Authentication + RFC 2817: Upgrading to TLS Within HTTP/1.1 + RFC 2818: HTTP Over TLS + RFC 3492: Punycode: A Bootstring encoding of Unicode for Internationalized + Domain Names in Applications (IDNA) + RFC 3986: Uniform Resource Identifier (URI): Generic Syntax + RFC 3987: Internationalized Resource Identifiers (IRIs) + RFC 4343: Domain Name System (DNS) Case Insensitivity Clarification + RFC 5894: Internationalized Domain Names for Applications (IDNA): + Background, Explanation, and Rationale + RFC 6066: Transport Layer Security (TLS) Extensions: Extension Definitions + RFC 6125: Representation and Verification of Domain-Based Application Service + Identity within Internet Public Key Infrastructure Using X.509 (PKIX) + Certificates in the Context of Transport Layer Security (TLS) + RFC 6555: Happy Eyeballs: Success with Dual-Stack Hosts*/ + +typedef struct OpusParsedURL OpusParsedURL; +typedef struct OpusStringBuf OpusStringBuf; +typedef struct OpusHTTPConn OpusHTTPConn; +typedef struct OpusHTTPStream OpusHTTPStream; + +static char *op_string_range_dup(const char *_start,const char *_end){ + size_t len; + char *ret; + OP_ASSERT(_start<=_end); + len=_end-_start; + /*This is to help avoid overflow elsewhere, later.*/ + if(OP_UNLIKELY(len>=INT_MAX))return NULL; + ret=(char *)_ogg_malloc(sizeof(*ret)*(len+1)); + if(OP_LIKELY(ret!=NULL)){ + ret=(char *)memcpy(ret,_start,sizeof(*ret)*(len)); + ret[len]='\0'; + } + return ret; +} + +static char *op_string_dup(const char *_s){ + return op_string_range_dup(_s,_s+strlen(_s)); +} + +static char *op_string_tolower(char *_s){ + int i; + for(i=0;_s[i]!='\0';i++){ + int c; + c=_s[i]; + if(c>='A'&&c<='Z')c+='a'-'A'; + _s[i]=(char)c; + } + return _s; +} + +/*URI character classes (from RFC 3986).*/ +#define OP_URL_ALPHA \ + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" +#define OP_URL_DIGIT "0123456789" +#define OP_URL_HEXDIGIT "0123456789ABCDEFabcdef" +/*Not a character class, but the characters allowed in .*/ +#define OP_URL_SCHEME OP_URL_ALPHA OP_URL_DIGIT "+-." +#define OP_URL_GEN_DELIMS "#/:?@[]" +#define OP_URL_SUB_DELIMS "!$&'()*+,;=" +#define OP_URL_RESERVED OP_URL_GEN_DELIMS OP_URL_SUB_DELIMS +#define OP_URL_UNRESERVED OP_URL_ALPHA OP_URL_DIGIT "-._~" +/*Not a character class, but the characters allowed in .*/ +#define OP_URL_PCT_ENCODED "%" +/*Not a character class or production rule, but for convenience.*/ +#define OP_URL_PCHAR_BASE \ + OP_URL_UNRESERVED OP_URL_PCT_ENCODED OP_URL_SUB_DELIMS +#define OP_URL_PCHAR OP_URL_PCHAR_BASE ":@" +/*Not a character class, but the characters allowed in and + .*/ +#define OP_URL_PCHAR_NA OP_URL_PCHAR_BASE ":" +/*Not a character class, but the characters allowed in .*/ +#define OP_URL_PCHAR_NC OP_URL_PCHAR_BASE "@" +/*Not a character clsss, but the characters allowed in .*/ +#define OP_URL_PATH OP_URL_PCHAR "/" +/*Not a character class, but the characters allowed in / .*/ +#define OP_URL_QUERY_FRAG OP_URL_PCHAR "/?" + +/*Check the <% HEXDIG HEXDIG> escapes of a URL for validity. + Return: 0 if valid, or a negative value on failure.*/ +static int op_validate_url_escapes(const char *_s){ + int i; + for(i=0;_s[i];i++){ + if(_s[i]=='%'){ + if(OP_UNLIKELY(!isxdigit(_s[i+1])) + ||OP_UNLIKELY(!isxdigit(_s[i+2])) + /*RFC 3986 says %00 "should be rejected if the application is not + expecting to receive raw data within a component."*/ + ||OP_UNLIKELY(_s[i+1]=='0'&&_s[i+2]=='0')){ + return OP_FALSE; + } + i+=2; + } + } + return 0; +} + +/*Convert a hex digit to its actual value. + _c: The hex digit to convert. + Presumed to be valid ('0'...'9', 'A'...'F', or 'a'...'f'). + Return: The value of the digit, in the range [0,15].*/ +static int op_hex_value(int _c){ + return _c>='a'?_c-'a'+10:_c>='A'?_c-'A'+10:_c-'0'; +} + +/*Unescape all the <% HEXDIG HEXDIG> sequences in a string in-place. + This does no validity checking.*/ +static char *op_unescape_url_component(char *_s){ + int i; + int j; + for(i=j=0;_s[i];i++,j++){ + if(_s[i]=='%'){ + _s[i]=(char)(op_hex_value(_s[i+1])<<4|op_hex_value(_s[i+2])); + i+=2; + } + } + return _s; +} + +/*Parse a file: URL. + This code is not meant to be fast: strspn() with large sets is likely to be + slow, but it is very convenient. + It is meant to be RFC 1738-compliant (as updated by RFC 3986).*/ +static const char *op_parse_file_url(const char *_src){ + const char *scheme_end; + const char *path; + const char *path_end; + scheme_end=_src+strspn(_src,OP_URL_SCHEME); + if(OP_UNLIKELY(*scheme_end!=':') + ||scheme_end-_src!=4||op_strncasecmp(_src,"file",4)!=0){ + /*Unsupported protocol.*/ + return NULL; + } + /*Make sure all escape sequences are valid to simplify unescaping later.*/ + if(OP_UNLIKELY(op_validate_url_escapes(scheme_end+1)<0))return NULL; + if(scheme_end[1]=='/'&&scheme_end[2]=='/'){ + const char *host; + /*file: URLs can have a host! + Yeah, I was surprised, too, but that's what RFC 1738 says. + It also says, "The file URL scheme is unusual in that it does not specify + an Internet protocol or access method for such files; as such, its + utility in network protocols between hosts is limited," which is a mild + understatement.*/ + host=scheme_end+3; + /*The empty host is what we expect.*/ + if(OP_LIKELY(*host=='/'))path=host; + else{ + const char *host_end; + char host_buf[28]; + /*RFC 1738 says localhost "is interpreted as `the machine from which the + URL is being interpreted,'" so let's check for it.*/ + host_end=host+strspn(host,OP_URL_PCHAR_BASE); + /*No allowed. + This also rejects IP-Literals.*/ + if(*host_end!='/')return NULL; + /*An escaped "localhost" can take at most 27 characters.*/ + if(OP_UNLIKELY(host_end-host>27))return NULL; + memcpy(host_buf,host,sizeof(*host_buf)*(host_end-host)); + host_buf[host_end-host]='\0'; + op_unescape_url_component(host_buf); + op_string_tolower(host_buf); + /*Some other host: give up.*/ + if(OP_UNLIKELY(strcmp(host_buf,"localhost")!=0))return NULL; + path=host_end; + } + } + else path=scheme_end+1; + path_end=path+strspn(path,OP_URL_PATH); + /*This will reject a or component, too. + I don't know what to do with queries, but a temporal fragment would at + least make sense. + RFC 1738 pretty clearly defines a that's equivalent to the + RFC 3986 component for other schemes, but not the file: scheme, + so I'm going to just reject it.*/ + if(*path_end!='\0')return NULL; + return path; +} + +#if defined(OP_ENABLE_HTTP) +# if defined(_WIN32) +# include +# include +# include +# include +# include "winerrno.h" + +typedef SOCKET op_sock; + +# define OP_INVALID_SOCKET (INVALID_SOCKET) + +/*Vista and later support WSAPoll(), but we don't want to rely on that. + Instead we re-implement it badly using select(). + Unfortunately, they define a conflicting struct pollfd, so we only define our + own if it looks like that one has not already been defined.*/ +# if !defined(POLLIN) +/*Equivalent to POLLIN.*/ +# define POLLRDNORM (0x0100) +/*Priority band data can be read.*/ +# define POLLRDBAND (0x0200) +/*There is data to read.*/ +# define POLLIN (POLLRDNORM|POLLRDBAND) +/*There is urgent data to read.*/ +# define POLLPRI (0x0400) +/*Equivalent to POLLOUT.*/ +# define POLLWRNORM (0x0010) +/*Writing now will not block.*/ +# define POLLOUT (POLLWRNORM) +/*Priority data may be written.*/ +# define POLLWRBAND (0x0020) +/*Error condition (output only).*/ +# define POLLERR (0x0001) +/*Hang up (output only).*/ +# define POLLHUP (0x0002) +/*Invalid request: fd not open (output only).*/ +# define POLLNVAL (0x0004) + +struct pollfd{ + /*File descriptor.*/ + op_sock fd; + /*Requested events.*/ + short events; + /*Returned events.*/ + short revents; +}; +# endif + +/*But Winsock never defines nfds_t (it's simply hard-coded to ULONG).*/ +typedef unsigned long nfds_t; + +/*The usage of FD_SET() below is O(N^2). + This is okay because select() is limited to 64 sockets in Winsock, anyway. + In practice, we only ever call it with one or two sockets.*/ +static int op_poll_win32(struct pollfd *_fds,nfds_t _nfds,int _timeout){ + struct timeval tv; + fd_set ifds; + fd_set ofds; + fd_set efds; + nfds_t i; + int ret; + FD_ZERO(&ifds); + FD_ZERO(&ofds); + FD_ZERO(&efds); + for(i=0;i<_nfds;i++){ + _fds[i].revents=0; + if(_fds[i].events&POLLIN)FD_SET(_fds[i].fd,&ifds); + if(_fds[i].events&POLLOUT)FD_SET(_fds[i].fd,&ofds); + FD_SET(_fds[i].fd,&efds); + } + if(_timeout>=0){ + tv.tv_sec=_timeout/1000; + tv.tv_usec=(_timeout%1000)*1000; + } + ret=select(-1,&ifds,&ofds,&efds,_timeout<0?NULL:&tv); + if(ret>0){ + for(i=0;i<_nfds;i++){ + if(FD_ISSET(_fds[i].fd,&ifds))_fds[i].revents|=POLLIN; + if(FD_ISSET(_fds[i].fd,&ofds))_fds[i].revents|=POLLOUT; + /*This isn't correct: there are several different things that might have + happened to a fd in efds, but I don't know a good way to distinguish + them without more context from the caller. + It's okay, because we don't actually check any of these bits, we just + need _some_ bit set.*/ + if(FD_ISSET(_fds[i].fd,&efds))_fds[i].revents|=POLLHUP; + } + } + return ret; +} + +/*We define op_errno() to make it clear that it's not an l-value like normal + errno is.*/ +# define op_errno() (WSAGetLastError()?WSAGetLastError()-WSABASEERR:0) +# define op_reset_errno() (WSASetLastError(0)) + +/*The remaining functions don't get an op_ prefix even though they only + operate on sockets, because we don't use non-socket I/O here, and this + minimizes the changes needed to deal with Winsock.*/ +# define close(_fd) closesocket(_fd) +/*This takes an int for the address length, even though the value is of type + socklen_t (defined as an unsigned integer type with at least 32 bits).*/ +# define connect(_fd,_addr,_addrlen) \ + (OP_UNLIKELY((_addrlen)>(socklen_t)INT_MAX)? \ + WSASetLastError(WSA_NOT_ENOUGH_MEMORY),-1: \ + connect(_fd,_addr,(int)(_addrlen))) +/*This relies on sizeof(u_long)==sizeof(int), which is always true on both + Win32 and Win64.*/ +# define ioctl(_fd,_req,_arg) ioctlsocket(_fd,_req,(u_long *)(_arg)) +# define getsockopt(_fd,_level,_name,_val,_len) \ + getsockopt(_fd,_level,_name,(char *)(_val),_len) +# define setsockopt(_fd,_level,_name,_val,_len) \ + setsockopt(_fd,_level,_name,(const char *)(_val),_len) +# define poll(_fds,_nfds,_timeout) op_poll_win32(_fds,_nfds,_timeout) + +# if defined(_MSC_VER) +typedef ptrdiff_t ssize_t; +# endif + +/*Load certificates from the built-in certificate store.*/ +int SSL_CTX_set_default_verify_paths_win32(SSL_CTX *_ssl_ctx); +# define SSL_CTX_set_default_verify_paths \ + SSL_CTX_set_default_verify_paths_win32 + +# else +/*Normal Berkeley sockets.*/ +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include + +typedef int op_sock; + +# define OP_INVALID_SOCKET (-1) + +# define op_errno() (errno) +# define op_reset_errno() (errno=0) + +# endif +# include +# include + +/*The maximum number of simultaneous connections. + RFC 2616 says this SHOULD NOT be more than 2, but everyone on the modern web + ignores that (e.g., IE 8 bumped theirs up from 2 to 6, Firefox uses 15). + If it makes you feel better, we'll only ever actively read from one of these + at a time. + The others are kept around mainly to avoid slow-starting a new connection + when seeking, and time out rapidly.*/ +# define OP_NCONNS_MAX (4) + +/*The amount of time before we attempt to re-resolve the host. + This is 10 minutes, as recommended in RFC 6555 for expiring cached connection + results for dual-stack hosts.*/ +# define OP_RESOLVE_CACHE_TIMEOUT_MS (10*60*(opus_int32)1000) + +/*The number of redirections at which we give up. + The value here is the current default in Firefox. + RFC 2068 mandated a maximum of 5, but RFC 2616 relaxed that to "a client + SHOULD detect infinite redirection loops." + Fortunately, 20 is less than infinity.*/ +# define OP_REDIRECT_LIMIT (20) + +/*The initial size of the buffer used to read a response message (before the + body).*/ +# define OP_RESPONSE_SIZE_MIN (510) +/*The maximum size of a response message (before the body). + Responses larger than this will be discarded. + I've seen a real server return 20 kB of data for a 302 Found response. + Increasing this beyond 32kB will cause problems on platforms with a 16-bit + int.*/ +# define OP_RESPONSE_SIZE_MAX (32766) + +/*The number of milliseconds we will allow a connection to sit idle before we + refuse to resurrect it. + Apache as of 2.2 has reduced its default timeout to 5 seconds (from 15), so + that's what we'll use here.*/ +# define OP_CONNECTION_IDLE_TIMEOUT_MS (5*1000) + +/*The number of milliseconds we will wait to send or receive data before giving + up.*/ +# define OP_POLL_TIMEOUT_MS (30*1000) + +/*We will always attempt to read ahead at least this much in preference to + opening a new connection.*/ +# define OP_READAHEAD_THRESH_MIN (32*(opus_int32)1024) + +/*The amount of data to request after a seek. + This is a trade-off between read throughput after a seek vs. the the ability + to quickly perform another seek with the same connection.*/ +# define OP_PIPELINE_CHUNK_SIZE (32*(opus_int32)1024) +/*Subsequent chunks are requested with larger and larger sizes until they pass + this threshold, after which we just ask for the rest of the resource.*/ +# define OP_PIPELINE_CHUNK_SIZE_MAX (1024*(opus_int32)1024) +/*This is the maximum number of requests we'll make with a single connection. + Many servers will simply disconnect after we attempt some number of requests, + possibly without sending a Connection: close header, meaning we won't + discover it until we try to read beyond the end of the current chunk. + We can reconnect when that happens, but this is slow. + Instead, we impose a limit ourselves (set to the default for Apache + installations and thus likely the most common value in use).*/ +# define OP_PIPELINE_MAX_REQUESTS (100) +/*This should be the number of requests, starting from a chunk size of + OP_PIPELINE_CHUNK_SIZE and doubling each time, until we exceed + OP_PIPELINE_CHUNK_SIZE_MAX and just request the rest of the file. + We won't reuse a connection when seeking unless it has at least this many + requests left, to reduce the chances we'll have to open a new connection + while reading forward afterwards.*/ +# define OP_PIPELINE_MIN_REQUESTS (7) + +/*Is this an https URL? + For now we can simply check the last letter of the scheme.*/ +# define OP_URL_IS_SSL(_url) ((_url)->scheme[4]=='s') + +/*Does this URL use the default port for its scheme?*/ +# define OP_URL_IS_DEFAULT_PORT(_url) \ + (!OP_URL_IS_SSL(_url)&&(_url)->port==80 \ + ||OP_URL_IS_SSL(_url)&&(_url)->port==443) + +struct OpusParsedURL{ + /*Either "http" or "https".*/ + char *scheme; + /*The user name from the component, or NULL.*/ + char *user; + /*The password from the component, or NULL.*/ + char *pass; + /*The component. + This may not be NULL.*/ + char *host; + /*The and components. + This may not be NULL.*/ + char *path; + /*The component. + This is set to the default port if the URL did not contain one.*/ + unsigned port; +}; + +/*Parse a URL. + This code is not meant to be fast: strspn() with large sets is likely to be + slow, but it is very convenient. + It is meant to be RFC 3986-compliant. + We currently do not support IRIs (Internationalized Resource Identifiers, + RFC 3987). + Callers should translate them to URIs first.*/ +static int op_parse_url_impl(OpusParsedURL *_dst,const char *_src){ + const char *scheme_end; + const char *authority; + const char *userinfo_end; + const char *user; + const char *user_end; + const char *pass; + const char *hostport; + const char *hostport_end; + const char *host_end; + const char *port; + opus_int32 port_num; + const char *port_end; + const char *path; + const char *path_end; + const char *uri_end; + scheme_end=_src+strspn(_src,OP_URL_SCHEME); + if(OP_UNLIKELY(*scheme_end!=':') + ||OP_UNLIKELY(scheme_end-_src<4)||OP_UNLIKELY(scheme_end-_src>5) + ||OP_UNLIKELY(op_strncasecmp(_src,"https",(int)(scheme_end-_src))!=0)){ + /*Unsupported protocol.*/ + return OP_EIMPL; + } + if(OP_UNLIKELY(scheme_end[1]!='/')||OP_UNLIKELY(scheme_end[2]!='/')){ + /*We require an component.*/ + return OP_EINVAL; + } + authority=scheme_end+3; + /*Make sure all escape sequences are valid to simplify unescaping later.*/ + if(OP_UNLIKELY(op_validate_url_escapes(authority)<0))return OP_EINVAL; + /*Look for a component.*/ + userinfo_end=authority+strspn(authority,OP_URL_PCHAR_NA); + if(*userinfo_end=='@'){ + /*Found one.*/ + user=authority; + /*Look for a password (yes, clear-text passwords are deprecated, I know, + but what else are people supposed to use? use SSL if you care).*/ + user_end=authority+strspn(authority,OP_URL_PCHAR_BASE); + if(*user_end==':')pass=user_end+1; + else pass=NULL; + hostport=userinfo_end+1; + } + else{ + /*We shouldn't have to initialize user_end, but gcc is too dumb to figure + out that user!=NULL below means we didn't take this else branch.*/ + user=user_end=NULL; + pass=NULL; + hostport=authority; + } + /*Try to figure out where the component ends.*/ + if(hostport[0]=='['){ + hostport++; + /*We have an , which can contain colons.*/ + hostport_end=host_end=hostport+strspn(hostport,OP_URL_PCHAR_NA); + if(OP_UNLIKELY(*hostport_end++!=']'))return OP_EINVAL; + } + /*Currently we don't support IDNA (RFC 5894), because I don't want to deal + with the policy about which domains should not be internationalized to + avoid confusing similarities. + Give this API Punycode (RFC 3492) domain names instead.*/ + else hostport_end=host_end=hostport+strspn(hostport,OP_URL_PCHAR_BASE); + /*TODO: Validate host.*/ + /*Is there a port number?*/ + port_num=-1; + if(*hostport_end==':'){ + int i; + port=hostport_end+1; + port_end=port+strspn(port,OP_URL_DIGIT); + path=port_end; + /*Not part of RFC 3986, but require port numbers in the range 0...65535.*/ + if(OP_LIKELY(port_end-port>0)){ + while(*port=='0')port++; + if(OP_UNLIKELY(port_end-port>5))return OP_EINVAL; + port_num=0; + for(i=0;i65535))return OP_EINVAL; + } + } + else path=hostport_end; + path_end=path+strspn(path,OP_URL_PATH); + /*If the path is not empty, it must begin with a '/'.*/ + if(OP_LIKELY(path_end>path)&&OP_UNLIKELY(path[0]!='/'))return OP_EINVAL; + /*Consume the component, if any (right now we don't split this out + from the component).*/ + if(*path_end=='?')path_end=path_end+strspn(path_end,OP_URL_QUERY_FRAG); + /*Discard the component, if any. + This doesn't get sent to the server. + Some day we should add support for Media Fragment URIs + .*/ + if(*path_end=='#')uri_end=path_end+1+strspn(path_end+1,OP_URL_QUERY_FRAG); + else uri_end=path_end; + /*If there's anything left, this was not a valid URL.*/ + if(OP_UNLIKELY(*uri_end!='\0'))return OP_EINVAL; + _dst->scheme=op_string_range_dup(_src,scheme_end); + if(OP_UNLIKELY(_dst->scheme==NULL))return OP_EFAULT; + op_string_tolower(_dst->scheme); + if(user!=NULL){ + _dst->user=op_string_range_dup(user,user_end); + if(OP_UNLIKELY(_dst->user==NULL))return OP_EFAULT; + op_unescape_url_component(_dst->user); + /*Unescaping might have created a ':' in the username. + That's not allowed by RFC 2617's Basic Authentication Scheme.*/ + if(OP_UNLIKELY(strchr(_dst->user,':')!=NULL))return OP_EINVAL; + } + else _dst->user=NULL; + if(pass!=NULL){ + _dst->pass=op_string_range_dup(pass,userinfo_end); + if(OP_UNLIKELY(_dst->pass==NULL))return OP_EFAULT; + op_unescape_url_component(_dst->pass); + } + else _dst->pass=NULL; + _dst->host=op_string_range_dup(hostport,host_end); + if(OP_UNLIKELY(_dst->host==NULL))return OP_EFAULT; + if(port_num<0){ + if(_src[4]=='s')port_num=443; + else port_num=80; + } + _dst->port=(unsigned)port_num; + /*RFC 2616 says an empty component is equivalent to "/", and we + MUST use the latter in the Request-URI. + Reserve space for the slash here.*/ + if(path==path_end||path[0]=='?')path--; + _dst->path=op_string_range_dup(path,path_end); + if(OP_UNLIKELY(_dst->path==NULL))return OP_EFAULT; + /*And force-set it here.*/ + _dst->path[0]='/'; + return 0; +} + +static void op_parsed_url_init(OpusParsedURL *_url){ + memset(_url,0,sizeof(*_url)); +} + +static void op_parsed_url_clear(OpusParsedURL *_url){ + _ogg_free(_url->scheme); + _ogg_free(_url->user); + _ogg_free(_url->pass); + _ogg_free(_url->host); + _ogg_free(_url->path); +} + +static int op_parse_url(OpusParsedURL *_dst,const char *_src){ + OpusParsedURL url; + int ret; + op_parsed_url_init(&url); + ret=op_parse_url_impl(&url,_src); + if(OP_UNLIKELY(ret<0))op_parsed_url_clear(&url); + else *_dst=*&url; + return ret; +} + +/*A buffer to hold growing strings. + The main purpose of this is to consolidate allocation checks and simplify + cleanup on a failed allocation.*/ +struct OpusStringBuf{ + char *buf; + int nbuf; + int cbuf; +}; + +static void op_sb_init(OpusStringBuf *_sb){ + _sb->buf=NULL; + _sb->nbuf=0; + _sb->cbuf=0; +} + +static void op_sb_clear(OpusStringBuf *_sb){ + _ogg_free(_sb->buf); +} + +/*Make sure we have room for at least _capacity characters (plus 1 more for the + terminating NUL).*/ +static int op_sb_ensure_capacity(OpusStringBuf *_sb,int _capacity){ + char *buf; + int cbuf; + buf=_sb->buf; + cbuf=_sb->cbuf; + if(_capacity>=cbuf-1){ + if(OP_UNLIKELY(cbuf>INT_MAX-1>>1))return OP_EFAULT; + if(OP_UNLIKELY(_capacity>=INT_MAX-1))return OP_EFAULT; + cbuf=OP_MAX(2*cbuf+1,_capacity+1); + buf=_ogg_realloc(buf,sizeof(*buf)*cbuf); + if(OP_UNLIKELY(buf==NULL))return OP_EFAULT; + _sb->buf=buf; + _sb->cbuf=cbuf; + } + return 0; +} + +/*Increase the capacity of the buffer, but not to more than _max_size + characters (plus 1 more for the terminating NUL).*/ +static int op_sb_grow(OpusStringBuf *_sb,int _max_size){ + char *buf; + int cbuf; + buf=_sb->buf; + cbuf=_sb->cbuf; + OP_ASSERT(_max_size<=INT_MAX-1); + cbuf=cbuf<=_max_size-1>>1?2*cbuf+1:_max_size+1; + buf=_ogg_realloc(buf,sizeof(*buf)*cbuf); + if(OP_UNLIKELY(buf==NULL))return OP_EFAULT; + _sb->buf=buf; + _sb->cbuf=cbuf; + return 0; +} + +static int op_sb_append(OpusStringBuf *_sb,const char *_s,int _len){ + char *buf; + int nbuf; + int ret; + nbuf=_sb->nbuf; + if(OP_UNLIKELY(nbuf>INT_MAX-_len))return OP_EFAULT; + ret=op_sb_ensure_capacity(_sb,nbuf+_len); + if(OP_UNLIKELY(ret<0))return ret; + buf=_sb->buf; + memcpy(buf+nbuf,_s,sizeof(*buf)*_len); + nbuf+=_len; + buf[nbuf]='\0'; + _sb->nbuf=nbuf; + return 0; +} + +static int op_sb_append_string(OpusStringBuf *_sb,const char *_s){ + size_t len; + len=strlen(_s); + if(OP_UNLIKELY(len>(size_t)INT_MAX))return OP_EFAULT; + return op_sb_append(_sb,_s,(int)len); +} + +static int op_sb_append_port(OpusStringBuf *_sb,unsigned _port){ + char port_buf[7]; + OP_ASSERT(_port<=65535U); + sprintf(port_buf,":%u",_port); + return op_sb_append_string(_sb,port_buf); +} + +static int op_sb_append_nonnegative_int64(OpusStringBuf *_sb,opus_int64 _i){ + char digit; + int nbuf_start; + int ret; + OP_ASSERT(_i>=0); + nbuf_start=_sb->nbuf; + ret=0; + do{ + digit='0'+_i%10; + ret|=op_sb_append(_sb,&digit,1); + _i/=10; + } + while(_i>0); + if(OP_LIKELY(ret>=0)){ + char *buf; + int nbuf_end; + buf=_sb->buf; + nbuf_end=_sb->nbuf-1; + /*We've added the digits backwards. + Reverse them.*/ + while(nbuf_startnext_pos=-1; + _conn->ssl_conn=NULL; + _conn->next=NULL; + _conn->fd=OP_INVALID_SOCKET; +} + +static void op_http_conn_clear(OpusHTTPConn *_conn){ + if(_conn->ssl_conn!=NULL)SSL_free(_conn->ssl_conn); + /*SSL frees the BIO for us.*/ + if(_conn->fd!=OP_INVALID_SOCKET)close(_conn->fd); +} + +/*The global stream state.*/ +struct OpusHTTPStream{ + /*The list of connections.*/ + OpusHTTPConn conns[OP_NCONNS_MAX]; + /*The context object used as a framework for TLS/SSL functions.*/ + SSL_CTX *ssl_ctx; + /*The cached session to reuse for future connections.*/ + SSL_SESSION *ssl_session; + /*The LRU list (ordered from MRU to LRU) of currently connected + connections.*/ + OpusHTTPConn *lru_head; + /*The free list.*/ + OpusHTTPConn *free_head; + /*The URL to connect to.*/ + OpusParsedURL url; + /*Information about the address we connected to.*/ + struct addrinfo addr_info; + /*The address we connected to.*/ + union{ + struct sockaddr s; + struct sockaddr_in v4; + struct sockaddr_in6 v6; + } addr; + /*The last time we re-resolved the host.*/ + struct timeb resolve_time; + /*A buffer used to build HTTP requests.*/ + OpusStringBuf request; + /*A buffer used to build proxy CONNECT requests.*/ + OpusStringBuf proxy_connect; + /*A buffer used to receive the response headers.*/ + OpusStringBuf response; + /*The Content-Length, if specified, or -1 otherwise. + This will always be specified for seekable streams.*/ + opus_int64 content_length; + /*The position indicator used when no connection is active.*/ + opus_int64 pos; + /*The host we actually connected to.*/ + char *connect_host; + /*The port we actually connected to.*/ + unsigned connect_port; + /*The connection we're currently reading from. + This can be -1 if no connection is active.*/ + int cur_conni; + /*Whether or not the server supports range requests.*/ + int seekable; + /*Whether or not the server supports HTTP/1.1 with persistent connections.*/ + int pipeline; + /*Whether or not we should skip certificate checks.*/ + int skip_certificate_check; + /*The offset of the tail of the request. + Only the offset in the Range: header appears after this, allowing us to + quickly edit the request to ask for a new range.*/ + int request_tail; + /*The estimated time required to open a new connection, in milliseconds.*/ + opus_int32 connect_rate; +}; + +static void op_http_stream_init(OpusHTTPStream *_stream){ + OpusHTTPConn **pnext; + int ci; + pnext=&_stream->free_head; + for(ci=0;ciconns+ci); + *pnext=_stream->conns+ci; + pnext=&_stream->conns[ci].next; + } + _stream->ssl_ctx=NULL; + _stream->ssl_session=NULL; + _stream->lru_head=NULL; + op_parsed_url_init(&_stream->url); + op_sb_init(&_stream->request); + op_sb_init(&_stream->proxy_connect); + op_sb_init(&_stream->response); + _stream->connect_host=NULL; + _stream->seekable=0; +} + +/*Close the connection and move it to the free list. + _stream: The stream containing the free list. + _conn: The connection to close. + _pnext: The linked-list pointer currently pointing to this connection. + _gracefully: Whether or not to shut down cleanly.*/ +static void op_http_conn_close(OpusHTTPStream *_stream,OpusHTTPConn *_conn, + OpusHTTPConn **_pnext,int _gracefully){ + /*If we don't shut down gracefully, the server MUST NOT re-use our session + according to RFC 2246, because it can't tell the difference between an + abrupt close and a truncation attack. + So we shut down gracefully if we can. + However, we will not wait if this would block (it's not worth the savings + from session resumption to do so). + Clients (that's us) MAY resume a TLS session that ended with an incomplete + close, according to RFC 2818, so there's no reason to make sure the server + shut things down gracefully.*/ + if(_gracefully&&_conn->ssl_conn!=NULL)SSL_shutdown(_conn->ssl_conn); + op_http_conn_clear(_conn); + _conn->next_pos=-1; + _conn->ssl_conn=NULL; + _conn->fd=OP_INVALID_SOCKET; + OP_ASSERT(*_pnext==_conn); + *_pnext=_conn->next; + _conn->next=_stream->free_head; + _stream->free_head=_conn; +} + +static void op_http_stream_clear(OpusHTTPStream *_stream){ + while(_stream->lru_head!=NULL){ + op_http_conn_close(_stream,_stream->lru_head,&_stream->lru_head,0); + } + if(_stream->ssl_session!=NULL)SSL_SESSION_free(_stream->ssl_session); + if(_stream->ssl_ctx!=NULL)SSL_CTX_free(_stream->ssl_ctx); + op_sb_clear(&_stream->response); + op_sb_clear(&_stream->proxy_connect); + op_sb_clear(&_stream->request); + if(_stream->connect_host!=_stream->url.host)_ogg_free(_stream->connect_host); + op_parsed_url_clear(&_stream->url); +} + +static int op_http_conn_write_fully(OpusHTTPConn *_conn, + const char *_buf,int _buf_size){ + struct pollfd fd; + SSL *ssl_conn; + fd.fd=_conn->fd; + ssl_conn=_conn->ssl_conn; + while(_buf_size>0){ + int err; + if(ssl_conn!=NULL){ + int ret; + ret=SSL_write(ssl_conn,_buf,_buf_size); + if(ret>0){ + /*Wrote some data.*/ + _buf+=ret; + _buf_size-=ret; + continue; + } + /*Connection closed.*/ + else if(ret==0)return OP_FALSE; + err=SSL_get_error(ssl_conn,ret); + /*Yes, renegotiations can cause SSL_write() to block for reading.*/ + if(err==SSL_ERROR_WANT_READ)fd.events=POLLIN; + else if(err==SSL_ERROR_WANT_WRITE)fd.events=POLLOUT; + else return OP_FALSE; + } + else{ + ssize_t ret; + op_reset_errno(); + ret=send(fd.fd,_buf,_buf_size,0); + if(ret>0){ + _buf+=ret; + OP_ASSERT(ret<=_buf_size); + _buf_size-=(int)ret; + continue; + } + err=op_errno(); + if(err!=EAGAIN&&err!=EWOULDBLOCK)return OP_FALSE; + fd.events=POLLOUT; + } + if(poll(&fd,1,OP_POLL_TIMEOUT_MS)<=0)return OP_FALSE; + } + return 0; +} + +static int op_http_conn_estimate_available(OpusHTTPConn *_conn){ + int available; + int ret; + ret=ioctl(_conn->fd,FIONREAD,&available); + if(ret<0)available=0; + /*This requires the SSL read_ahead flag to be unset to work. + We ignore partial records as well as the protocol overhead for any pending + bytes. + This means we might return somewhat less than can truly be read without + blocking (if there's a partial record). + This is okay, because we're using this value to estimate network transfer + time, and we _have_ already received those bytes. + We also might return slightly more (due to protocol overhead), but that's + small enough that it probably doesn't matter.*/ + if(_conn->ssl_conn!=NULL)available+=SSL_pending(_conn->ssl_conn); + return available; +} + +static opus_int32 op_time_diff_ms(const struct timeb *_end, + const struct timeb *_start){ + opus_int64 dtime; + dtime=_end->time-(opus_int64)_start->time; + OP_ASSERT(_end->millitm<1000); + OP_ASSERT(_start->millitm<1000); + if(OP_UNLIKELY(dtime>(OP_INT32_MAX-1000)/1000))return OP_INT32_MAX; + if(OP_UNLIKELY(dtime<(OP_INT32_MIN+1000)/1000))return OP_INT32_MIN; + return (opus_int32)dtime*1000+_end->millitm-_start->millitm; +} + +/*Update the read rate estimate for this connection.*/ +static void op_http_conn_read_rate_update(OpusHTTPConn *_conn){ + struct timeb read_time; + opus_int32 read_delta_ms; + opus_int64 read_delta_bytes; + opus_int64 read_rate; + read_delta_bytes=_conn->read_bytes; + if(read_delta_bytes<=0)return; + ftime(&read_time); + read_delta_ms=op_time_diff_ms(&read_time,&_conn->read_time); + read_rate=_conn->read_rate; + read_delta_ms=OP_MAX(read_delta_ms,1); + read_rate+=read_delta_bytes*1000/read_delta_ms-read_rate+4>>3; + *&_conn->read_time=*&read_time; + _conn->read_bytes=0; + _conn->read_rate=read_rate; +} + +/*Tries to read from the given connection. + [out] _buf: Returns the data read. + _buf_size: The size of the buffer. + _blocking: Whether or not to block until some data is retrieved. + Return: A positive number of bytes read on success. + 0: The read would block, or the connection was closed. + OP_EREAD: There was a fatal read error.*/ +static int op_http_conn_read(OpusHTTPConn *_conn, + char *_buf,int _buf_size,int _blocking){ + struct pollfd fd; + SSL *ssl_conn; + int nread; + int nread_unblocked; + fd.fd=_conn->fd; + ssl_conn=_conn->ssl_conn; + nread=nread_unblocked=0; + /*RFC 2818 says "client implementations MUST treat any premature closes as + errors and the data received as potentially truncated," so we make very + sure to report read errors upwards.*/ + do{ + int err; + if(ssl_conn!=NULL){ + int ret; + ret=SSL_read(ssl_conn,_buf+nread,_buf_size-nread); + OP_ASSERT(ret<=_buf_size-nread); + if(ret>0){ + /*Read some data. + Keep going to see if there's more.*/ + nread+=ret; + nread_unblocked+=ret; + continue; + } + /*If we already read some data, return it right now.*/ + if(nread>0)break; + err=SSL_get_error(ssl_conn,ret); + if(ret==0){ + /*Connection close. + Check for a clean shutdown to prevent truncation attacks. + This check always succeeds for SSLv2, as it has no "close notify" + message and thus can't verify an orderly shutdown.*/ + return err==SSL_ERROR_ZERO_RETURN?0:OP_EREAD; + } + if(err==SSL_ERROR_WANT_READ)fd.events=POLLIN; + /*Yes, renegotiations can cause SSL_read() to block for writing.*/ + else if(err==SSL_ERROR_WANT_WRITE)fd.events=POLLOUT; + /*Some other error.*/ + else return OP_EREAD; + } + else{ + ssize_t ret; + op_reset_errno(); + ret=recv(fd.fd,_buf+nread,_buf_size-nread,0); + OP_ASSERT(ret<=_buf_size-nread); + if(ret>0){ + /*Read some data. + Keep going to see if there's more.*/ + OP_ASSERT(ret<=_buf_size-nread); + nread+=(int)ret; + nread_unblocked+=(int)ret; + continue; + } + /*If we already read some data or the connection was closed, return + right now.*/ + if(ret==0||nread>0)break; + err=op_errno(); + if(err!=EAGAIN&&err!=EWOULDBLOCK)return OP_EREAD; + fd.events=POLLIN; + } + _conn->read_bytes+=nread_unblocked; + op_http_conn_read_rate_update(_conn); + nread_unblocked=0; + if(!_blocking)break; + /*Need to wait to get any data at all.*/ + if(poll(&fd,1,OP_POLL_TIMEOUT_MS)<=0)return OP_EREAD; + } + while(nread<_buf_size); + _conn->read_bytes+=nread_unblocked; + return nread; +} + +/*Tries to look at the pending data for a connection without consuming it. + [out] _buf: Returns the data at which we're peeking. + _buf_size: The size of the buffer.*/ +static int op_http_conn_peek(OpusHTTPConn *_conn,char *_buf,int _buf_size){ + struct pollfd fd; + SSL *ssl_conn; + int ret; + fd.fd=_conn->fd; + ssl_conn=_conn->ssl_conn; + for(;;){ + int err; + if(ssl_conn!=NULL){ + ret=SSL_peek(ssl_conn,_buf,_buf_size); + /*Either saw some data or the connection was closed.*/ + if(ret>=0)return ret; + err=SSL_get_error(ssl_conn,ret); + if(err==SSL_ERROR_WANT_READ)fd.events=POLLIN; + /*Yes, renegotiations can cause SSL_peek() to block for writing.*/ + else if(err==SSL_ERROR_WANT_WRITE)fd.events=POLLOUT; + else return 0; + } + else{ + op_reset_errno(); + ret=(int)recv(fd.fd,_buf,_buf_size,MSG_PEEK); + /*Either saw some data or the connection was closed.*/ + if(ret>=0)return ret; + err=op_errno(); + if(err!=EAGAIN&&err!=EWOULDBLOCK)return 0; + fd.events=POLLIN; + } + /*Need to wait to get any data at all.*/ + if(poll(&fd,1,OP_POLL_TIMEOUT_MS)<=0)return 0; + } +} + +/*When parsing response headers, RFC 2616 mandates that all lines end in CR LF. + However, even in the year 2012, I have seen broken servers use just a LF. + This is the evil that Postel's advice from RFC 761 breeds.*/ + +/*Reads the entirety of a response to an HTTP request into the response buffer. + Actual parsing and validation is done later. + Return: The number of bytes in the response on success, OP_EREAD if the + connection was closed before reading any data, or another negative + value on any other error.*/ +static int op_http_conn_read_response(OpusHTTPConn *_conn, + OpusStringBuf *_response){ + int ret; + _response->nbuf=0; + ret=op_sb_ensure_capacity(_response,OP_RESPONSE_SIZE_MIN); + if(OP_UNLIKELY(ret<0))return ret; + for(;;){ + char *buf; + int size; + int capacity; + int read_limit; + int terminated; + size=_response->nbuf; + capacity=_response->cbuf-1; + if(OP_UNLIKELY(size>=capacity)){ + ret=op_sb_grow(_response,OP_RESPONSE_SIZE_MAX); + if(OP_UNLIKELY(ret<0))return ret; + capacity=_response->cbuf-1; + /*The response was too large. + This prevents a bad server from running us out of memory.*/ + if(OP_UNLIKELY(size>=capacity))return OP_EIMPL; + } + buf=_response->buf; + ret=op_http_conn_peek(_conn,buf+size,capacity-size); + if(OP_UNLIKELY(ret<=0))return size<=0?OP_EREAD:OP_FALSE; + /*We read some data.*/ + /*Make sure the starting characters are "HTTP". + Otherwise we could wind up waiting for a response from something that is + not an HTTP server until we time out.*/ + if(size<4&&op_strncasecmp(buf,"HTTP",OP_MIN(size+ret,4))!=0){ + return OP_FALSE; + } + /*How far can we read without passing the "\r\n\r\n" terminator?*/ + buf[size+ret]='\0'; + terminated=0; + for(read_limit=OP_MAX(size-3,0);read_limitnbuf=size; + /*We found the terminator and read all the data up to and including it.*/ + if(terminated&&OP_LIKELY(size>=read_limit))return size; + } + return OP_EIMPL; +} + +# define OP_HTTP_DIGIT "0123456789" + +/*The Reason-Phrase is not allowed to contain control characters, except + horizontal tab (HT: \011).*/ +# define OP_HTTP_CREASON_PHRASE \ + "\001\002\003\004\005\006\007\010\012\013\014\015\016\017\020\021" \ + "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\177" + +# define OP_HTTP_CTLS \ + "\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020" \ + "\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037\177" + +/*This also includes '\t', but we get that from OP_HTTP_CTLS.*/ +# define OP_HTTP_SEPARATORS " \"(),/:;<=>?@[\\]{}" + +/*TEXT can also include LWS, but that has structure, so we parse it + separately.*/ +# define OP_HTTP_CTOKEN OP_HTTP_CTLS OP_HTTP_SEPARATORS + +/*Return: The amount of linear white space (LWS) at the start of _s.*/ +static int op_http_lwsspn(const char *_s){ + int i; + for(i=0;;){ + if(_s[0]=='\r'&&_s[1]=='\n'&&(_s[2]=='\t'||_s[2]==' '))i+=3; + /*This case is for broken servers.*/ + else if(_s[0]=='\n'&&(_s[1]=='\t'||_s[1]==' '))i+=2; + else if(_s[i]=='\t'||_s[i]==' ')i++; + else return i; + } +} + +static char *op_http_parse_status_line(int *_v1_1_compat, + char **_status_code,char *_response){ + char *next; + char *status_code; + int v1_1_compat; + size_t d; + /*RFC 2616 Section 6.1 does not say if the tokens in the Status-Line can be + separated by optional LWS, but since it specifically calls out where + spaces are to be placed and that CR and LF are not allowed except at the + end, we are assuming extra LWS is not allowed.*/ + /*We already validated that this starts with "HTTP"*/ + OP_ASSERT(op_strncasecmp(_response,"HTTP",4)==0); + next=_response+4; + if(OP_UNLIKELY(*next++!='/'))return NULL; + d=strspn(next,OP_HTTP_DIGIT); + /*"Leading zeros MUST be ignored by recipients."*/ + while(*next=='0'){ + next++; + OP_ASSERT(d>0); + d--; + } + /*We only support version 1.x*/ + if(OP_UNLIKELY(d!=1)||OP_UNLIKELY(*next++!='1'))return NULL; + if(OP_UNLIKELY(*next++!='.'))return NULL; + d=strspn(next,OP_HTTP_DIGIT); + if(OP_UNLIKELY(d<=0))return NULL; + /*"Leading zeros MUST be ignored by recipients."*/ + while(*next=='0'){ + next++; + OP_ASSERT(d>0); + d--; + } + /*We don't need to parse the version number. + Any non-zero digit means it's at least 1.*/ + v1_1_compat=d>0; + next+=d; + if(OP_UNLIKELY(*next++!=' '))return NULL; + status_code=next; + d=strspn(next,OP_HTTP_DIGIT); + if(OP_UNLIKELY(d!=3))return NULL; + next+=d; + /*The Reason-Phrase can be empty, but the space must be here.*/ + if(OP_UNLIKELY(*next++!=' '))return NULL; + next+=strcspn(next,OP_HTTP_CREASON_PHRASE); + /*We are not mandating this be present thanks to broken servers.*/ + if(OP_LIKELY(*next=='\r'))next++; + if(OP_UNLIKELY(*next++!='\n'))return NULL; + if(_v1_1_compat!=NULL)*_v1_1_compat=v1_1_compat; + *_status_code=status_code; + return next; +} + +/*Get the next response header. + [out] _header: The header token, NUL-terminated, with leading and trailing + whitespace stripped, and converted to lower case (to simplify + case-insensitive comparisons), or NULL if there are no more + response headers. + [out] _cdr: The remaining contents of the header, excluding the initial + colon (':') and the terminating CRLF ("\r\n"), + NUL-terminated, and with leading and trailing whitespace + stripped, or NULL if there are no more response headers. + [inout] _s: On input, this points to the start of the current line of the + response headers. + On output, it points to the start of the first line following + this header, or NULL if there are no more response headers. + Return: 0 on success, or a negative value on failure.*/ +static int op_http_get_next_header(char **_header,char **_cdr,char **_s){ + char *header; + char *header_end; + char *cdr; + char *cdr_end; + char *next; + size_t d; + next=*_s; + /*The second case is for broken servers.*/ + if(next[0]=='\r'&&next[1]=='\n'||OP_UNLIKELY(next[0]=='\n')){ + /*No more headers.*/ + *_header=NULL; + *_cdr=NULL; + *_s=NULL; + return 0; + } + header=next+op_http_lwsspn(next); + d=strcspn(header,OP_HTTP_CTOKEN); + if(OP_UNLIKELY(d<=0))return OP_FALSE; + header_end=header+d; + next=header_end+op_http_lwsspn(header_end); + if(OP_UNLIKELY(*next++!=':'))return OP_FALSE; + next+=op_http_lwsspn(next); + cdr=next; + do{ + cdr_end=next+strcspn(next,OP_HTTP_CTLS); + next=cdr_end+op_http_lwsspn(cdr_end); + } + while(next>cdr_end); + /*We are not mandating this be present thanks to broken servers.*/ + if(OP_LIKELY(*next=='\r'))next++; + if(OP_UNLIKELY(*next++!='\n'))return OP_FALSE; + *header_end='\0'; + *cdr_end='\0'; + /*Field names are case-insensitive.*/ + op_string_tolower(header); + *_header=header; + *_cdr=cdr; + *_s=next; + return 0; +} + +static opus_int64 op_http_parse_nonnegative_int64(const char **_next, + const char *_cdr){ + const char *next; + opus_int64 ret; + int i; + next=_cdr+strspn(_cdr,OP_HTTP_DIGIT); + *_next=next; + if(OP_UNLIKELY(next<=_cdr))return OP_FALSE; + while(*_cdr=='0')_cdr++; + if(OP_UNLIKELY(next-_cdr>19))return OP_EIMPL; + ret=0; + for(i=0;i(OP_INT64_MAX-9)/10+(digit<=7)))return OP_EIMPL; + ret=ret*10+digit; + } + return ret; +} + +static opus_int64 op_http_parse_content_length(const char *_cdr){ + const char *next; + opus_int64 content_length; + content_length=op_http_parse_nonnegative_int64(&next,_cdr); + if(OP_UNLIKELY(*next!='\0'))return OP_FALSE; + return content_length; +} + +static int op_http_parse_content_range(opus_int64 *_first,opus_int64 *_last, + opus_int64 *_length,const char *_cdr){ + opus_int64 first; + opus_int64 last; + opus_int64 length; + size_t d; + if(OP_UNLIKELY(op_strncasecmp(_cdr,"bytes",5)!=0))return OP_FALSE; + _cdr+=5; + d=op_http_lwsspn(_cdr); + if(OP_UNLIKELY(d<=0))return OP_FALSE; + _cdr+=d; + if(*_cdr!='*'){ + first=op_http_parse_nonnegative_int64(&_cdr,_cdr); + if(OP_UNLIKELY(first<0))return (int)first; + _cdr+=op_http_lwsspn(_cdr); + if(*_cdr++!='-')return OP_FALSE; + _cdr+=op_http_lwsspn(_cdr); + last=op_http_parse_nonnegative_int64(&_cdr,_cdr); + if(OP_UNLIKELY(last<0))return (int)last; + _cdr+=op_http_lwsspn(_cdr); + } + else{ + /*This is for a 416 response (Requested range not satisfiable).*/ + first=last=-1; + _cdr++; + } + if(OP_UNLIKELY(*_cdr++!='/'))return OP_FALSE; + if(*_cdr!='*'){ + length=op_http_parse_nonnegative_int64(&_cdr,_cdr); + if(OP_UNLIKELY(length<0))return (int)length; + } + else{ + /*The total length is unspecified.*/ + _cdr++; + length=-1; + } + if(OP_UNLIKELY(*_cdr!='\0'))return OP_FALSE; + if(OP_UNLIKELY(last=0&&OP_UNLIKELY(last>=length))return OP_FALSE; + *_first=first; + *_last=last; + *_length=length; + return 0; +} + +/*Parse the Connection response header and look for a "close" token. + Return: 1 if a "close" token is found, 0 if it's not found, and a negative + value on error.*/ +static int op_http_parse_connection(char *_cdr){ + size_t d; + int ret; + ret=0; + for(;;){ + d=strcspn(_cdr,OP_HTTP_CTOKEN); + if(OP_UNLIKELY(d<=0))return OP_FALSE; + if(op_strncasecmp(_cdr,"close",(int)d)==0)ret=1; + /*We're supposed to strip and ignore any headers mentioned in the + Connection header if this response is from an HTTP/1.0 server (to + work around forwarding of hop-by-hop headers by old proxies), but the + only hop-by-hop header we look at is Connection itself. + Everything else is a well-defined end-to-end header, and going back and + undoing the things we did based on already-examined headers would be + hard (since we only scan them once, in a destructive manner). + Therefore we just ignore all the other tokens.*/ + _cdr+=d; + d=op_http_lwsspn(_cdr); + if(d<=0)break; + _cdr+=d; + } + return OP_UNLIKELY(*_cdr!='\0')?OP_FALSE:ret; +} + +typedef int (*op_ssl_step_func)(SSL *_ssl_conn); + +/*Try to run an SSL function to completion (blocking if necessary).*/ +static int op_do_ssl_step(SSL *_ssl_conn,op_sock _fd,op_ssl_step_func _step){ + struct pollfd fd; + fd.fd=_fd; + for(;;){ + int ret; + int err; + ret=(*_step)(_ssl_conn); + if(ret>=0)return ret; + err=SSL_get_error(_ssl_conn,ret); + if(err==SSL_ERROR_WANT_READ)fd.events=POLLIN; + else if(err==SSL_ERROR_WANT_WRITE)fd.events=POLLOUT; + else return OP_FALSE; + if(poll(&fd,1,OP_POLL_TIMEOUT_MS)<=0)return OP_FALSE; + } +} + +/*Implement a BIO type that just indicates every operation should be retried. + We use this when initializing an SSL connection via a proxy to allow the + initial handshake to proceed all the way up to the first read attempt, and + then return. + This allows the TLS client hello message to be pipelined with the HTTP + CONNECT request.*/ + +static int op_bio_retry_write(BIO *_b,const char *_buf,int _num){ + (void)_buf; + (void)_num; + BIO_clear_retry_flags(_b); + BIO_set_retry_write(_b); + return -1; +} + +static int op_bio_retry_read(BIO *_b,char *_buf,int _num){ + (void)_buf; + (void)_num; + BIO_clear_retry_flags(_b); + BIO_set_retry_read(_b); + return -1; +} + +static int op_bio_retry_puts(BIO *_b,const char *_str){ + return op_bio_retry_write(_b,_str,0); +} + +static long op_bio_retry_ctrl(BIO *_b,int _cmd,long _num,void *_ptr){ + long ret; + (void)_b; + (void)_num; + (void)_ptr; + ret=0; + switch(_cmd){ + case BIO_CTRL_RESET: + case BIO_C_RESET_READ_REQUEST:{ + BIO_clear_retry_flags(_b); + } + /*Fall through.*/ + case BIO_CTRL_EOF: + case BIO_CTRL_SET: + case BIO_CTRL_SET_CLOSE: + case BIO_CTRL_FLUSH: + case BIO_CTRL_DUP:{ + ret=1; + }break; + } + return ret; +} + +# if OPENSSL_VERSION_NUMBER<0x10100000L +# define BIO_set_data(_b,_ptr) ((_b)->ptr=(_ptr)) +# define BIO_set_init(_b,_init) ((_b)->init=(_init)) +# define ASN1_STRING_get0_data ASN1_STRING_data +# endif + +static int op_bio_retry_new(BIO *_b){ + BIO_set_init(_b,1); +# if OPENSSL_VERSION_NUMBER<0x10100000L + _b->num=0; +# endif + BIO_set_data(_b,NULL); + return 1; +} + +static int op_bio_retry_free(BIO *_b){ + return _b!=NULL; +} + +# if OPENSSL_VERSION_NUMBER<0x10100000L +/*This is not const because OpenSSL doesn't allow it, even though it won't + write to it.*/ +static BIO_METHOD op_bio_retry_method={ + BIO_TYPE_NULL, + "retry", + op_bio_retry_write, + op_bio_retry_read, + op_bio_retry_puts, + NULL, + op_bio_retry_ctrl, + op_bio_retry_new, + op_bio_retry_free, + NULL +}; +# endif + +/*Establish a CONNECT tunnel and pipeline the start of the TLS handshake for + proxying https URL requests.*/ +static int op_http_conn_establish_tunnel(OpusHTTPStream *_stream, + OpusHTTPConn *_conn,op_sock _fd,SSL *_ssl_conn,BIO *_ssl_bio){ +# if OPENSSL_VERSION_NUMBER>=0x10100000L + BIO_METHOD *bio_retry_method; +# endif + BIO *retry_bio; + char *status_code; + char *next; + int ret; + _conn->ssl_conn=NULL; + _conn->fd=_fd; + OP_ASSERT(_stream->proxy_connect.nbuf>0); + ret=op_http_conn_write_fully(_conn, + _stream->proxy_connect.buf,_stream->proxy_connect.nbuf); + if(OP_UNLIKELY(ret<0))return ret; +# if OPENSSL_VERSION_NUMBER>=0x10100000L + bio_retry_method=BIO_meth_new(BIO_TYPE_NULL,"retry"); + if(bio_retry_method==NULL)return OP_EFAULT; + BIO_meth_set_write(bio_retry_method,op_bio_retry_write); + BIO_meth_set_read(bio_retry_method,op_bio_retry_read); + BIO_meth_set_puts(bio_retry_method,op_bio_retry_puts); + BIO_meth_set_ctrl(bio_retry_method,op_bio_retry_ctrl); + BIO_meth_set_create(bio_retry_method,op_bio_retry_new); + BIO_meth_set_destroy(bio_retry_method,op_bio_retry_free); + retry_bio=BIO_new(bio_retry_method); + if(OP_UNLIKELY(retry_bio==NULL)){ + BIO_meth_free(bio_retry_method); + return OP_EFAULT; + } +# else + retry_bio=BIO_new(&op_bio_retry_method); + if(OP_UNLIKELY(retry_bio==NULL))return OP_EFAULT; +# endif + SSL_set_bio(_ssl_conn,retry_bio,_ssl_bio); + SSL_set_connect_state(_ssl_conn); + /*This shouldn't succeed, since we can't read yet.*/ + OP_ALWAYS_TRUE(SSL_connect(_ssl_conn)<0); + SSL_set_bio(_ssl_conn,_ssl_bio,_ssl_bio); +# if OPENSSL_VERSION_NUMBER>=0x10100000L + BIO_meth_free(bio_retry_method); +# endif + /*Only now do we disable write coalescing, to allow the CONNECT + request and the start of the TLS handshake to be combined.*/ + op_sock_set_tcp_nodelay(_fd,1); + ret=op_http_conn_read_response(_conn,&_stream->response); + if(OP_UNLIKELY(ret<0))return ret; + next=op_http_parse_status_line(NULL,&status_code,_stream->response.buf); + /*According to RFC 2817, "Any successful (2xx) response to a + CONNECT request indicates that the proxy has established a + connection to the requested host and port."*/ + if(OP_UNLIKELY(next==NULL)||OP_UNLIKELY(status_code[0]!='2'))return OP_FALSE; + return 0; +} + +/*Convert a host to a numeric address, if possible. + Return: A struct addrinfo containing the address, if it was numeric, and NULL + otherwise.*/ +static struct addrinfo *op_inet_pton(const char *_host){ + struct addrinfo *addrs; + struct addrinfo hints; + memset(&hints,0,sizeof(hints)); + hints.ai_socktype=SOCK_STREAM; + hints.ai_flags=AI_NUMERICHOST; + if(!getaddrinfo(_host,NULL,&hints,&addrs))return addrs; + return NULL; +} + +# if OPENSSL_VERSION_NUMBER<0x10002000L +/*Match a host name against a host with a possible wildcard pattern according + to the rules of RFC 6125 Section 6.4.3. + Return: 0 if the pattern doesn't match, and a non-zero value if it does.*/ +static int op_http_hostname_match(const char *_host,size_t _host_len, + ASN1_STRING *_pattern){ + const char *pattern; + size_t host_label_len; + size_t host_suffix_len; + size_t pattern_len; + size_t pattern_label_len; + size_t pattern_prefix_len; + size_t pattern_suffix_len; + if(OP_UNLIKELY(_host_len>(size_t)INT_MAX))return 0; + pattern=(const char *)ASN1_STRING_get0_data(_pattern); + pattern_len=strlen(pattern); + /*Check the pattern for embedded NULs.*/ + if(OP_UNLIKELY(pattern_len!=(size_t)ASN1_STRING_length(_pattern)))return 0; + pattern_label_len=strcspn(pattern,"."); + OP_ASSERT(pattern_label_len<=pattern_len); + pattern_prefix_len=strcspn(pattern,"*"); + if(OP_UNLIKELY(pattern_prefix_len>(size_t)INT_MAX))return 0; + if(pattern_prefix_len>=pattern_label_len){ + /*"The client SHOULD NOT attempt to match a presented identifier in which + the wildcard character comprises a label other than the left-most label + (e.g., do not match bar.*.example.net)." [RFC 6125 Section 6.4.3]*/ + if(pattern_prefix_lenurl.host; + host_len=strlen(host); + peer_cert=SSL_get_peer_certificate(_ssl_conn); + /*We set VERIFY_PEER, so we shouldn't get here without a certificate.*/ + if(OP_UNLIKELY(peer_cert==NULL))return 0; + ret=0; + OP_ASSERT(host_lenai_family){ + case AF_INET:{ + struct sockaddr_in *s; + s=(struct sockaddr_in *)addr->ai_addr; + OP_ASSERT(addr->ai_addrlen>=sizeof(*s)); + ip=(unsigned char *)&s->sin_addr; + ip_len=sizeof(s->sin_addr); + /*RFC 6125 says, "In this case, the iPAddress subjectAltName must [sic] + be present in the certificate and must [sic] exactly match the IP in + the URI." + So don't allow falling back to a Common Name.*/ + check_cn=0; + }break; + case AF_INET6:{ + struct sockaddr_in6 *s; + s=(struct sockaddr_in6 *)addr->ai_addr; + OP_ASSERT(addr->ai_addrlen>=sizeof(*s)); + ip=(unsigned char *)&s->sin6_addr; + ip_len=sizeof(s->sin6_addr); + check_cn=0; + }break; + } + } + /*We can only verify IP addresses and "fully-qualified" domain names. + To quote RFC 6125: "The extracted data MUST include only information that + can be securely parsed out of the inputs (e.g., parsing the fully + qualified DNS domain name out of the "host" component (or its + equivalent) of a URI or deriving the application service type from the + scheme of a URI) ..." + We don't have a way to check (without relying on DNS records, which might + be subverted) if this address is fully-qualified. + This is particularly problematic when using a CONNECT tunnel, as it is + the server that does DNS lookup, not us. + However, we are certain that if the hostname has no '.', it is definitely + not a fully-qualified domain name (with the exception of crazy TLDs that + actually resolve, like "uz", but I am willing to ignore those). + RFC 1535 says "...in any event where a '.' exists in a specified name it + should be assumed to be a fully qualified domain name (FQDN) and SHOULD + be tried as a rooted name first." + That doesn't give us any security guarantees, of course (a subverted DNS + could fail the original query and our resolver might still retry with a + local domain appended).*/ + if(ip!=NULL||strchr(host,'.')!=NULL){ + STACK_OF(GENERAL_NAME) *san_names; + /*RFC 2818 says (after correcting for Eratta 1077): "If a subjectAltName + extension of type dNSName is present, that MUST be used as the identity. + Otherwise, the (most specific) Common Name field in the Subject field of + the certificate MUST be used. + Although the use of the Common Name is existing practice, it is + deprecated and Certification Authorities are encouraged to use the + dNSName instead." + "Matching is performed using the matching rules specified by RFC 2459. + If more than one identity of a given type is present in the certificate + (e.g., more than one dNSName name), a match in any one of the set is + considered acceptable. + Names may contain the wildcard character * which is condered to match any + single domain name component or component fragment. + E.g., *.a.com matches foo.a.com but not bar.foo.a.com. + f*.com matches foo.com but not bar.com." + "In some cases, the URI is specified as an IP address rather than a + hostname. + In this case, the iPAddress subjectAltName must be present in the + certificate and must exactly match the IP in the URI."*/ + san_names=X509_get_ext_d2i(peer_cert,NID_subject_alt_name,NULL,NULL); + if(san_names!=NULL){ + int nsan_names; + int sni; + /*RFC 2459 says there MUST be at least one, but we don't depend on it.*/ + nsan_names=sk_GENERAL_NAME_num(san_names); + for(sni=0;snitype==GEN_DNS){ + /*We have a subjectAltName extension of type dNSName, so don't fall + back to a Common Name. + https://marc.info/?l=openssl-dev&m=139617145216047&w=2 says that + subjectAltNames of other types do not trigger this restriction, + (e.g., if they are all IP addresses, we will still check a + non-IP hostname against a Common Name).*/ + check_cn=0; + if(op_http_hostname_match(host,host_len,name->d.dNSName)){ + ret=1; + break; + } + } + } + else if(name->type==GEN_IPADD){ + unsigned const char *cert_ip; + /*If we do have an IP address, compare it directly. + RFC 6125: "When the reference identity is an IP address, the + identity MUST be converted to the 'network byte order' octet + string representation. + For IP Version 4, as specified in RFC 791, the octet string will + contain exactly four octets. + For IP Version 6, as specified in RFC 2460, the octet string will + contain exactly sixteen octets. + This octet string is then compared against subjectAltName values of + type iPAddress. + A match occurs if the reference identity octet string and the value + octet strings are identical."*/ + cert_ip=ASN1_STRING_get0_data(name->d.iPAddress); + if(ip_len==ASN1_STRING_length(name->d.iPAddress) + &&memcmp(ip,cert_ip,ip_len)==0){ + ret=1; + break; + } + } + } + sk_GENERAL_NAME_pop_free(san_names,GENERAL_NAME_free); + } + /*If we're supposed to fall back to a Common Name, match against it here.*/ + if(check_cn){ + int last_cn_loc; + int cn_loc; + /*RFC 6125 says that at least one significant CA is known to issue certs + with multiple CNs, although it SHOULD NOT. + It also says: "The server's identity may also be verified by comparing + the reference identity to the Common Name (CN) value in the last + Relative Distinguished Name (RDN) of the subject field of the server's + certificate (where "last" refers to the DER-encoded order...)." + So find the last one and check it.*/ + cn_loc=-1; + do{ + last_cn_loc=cn_loc; + cn_loc=X509_NAME_get_index_by_NID(X509_get_subject_name(peer_cert), + NID_commonName,last_cn_loc); + } + while(cn_loc>=0); + ret=last_cn_loc>=0 + &&op_http_hostname_match(host,host_len, + X509_NAME_ENTRY_get_data( + X509_NAME_get_entry(X509_get_subject_name(peer_cert),last_cn_loc))); + } + } + if(addr!=NULL)freeaddrinfo(addr); + X509_free(peer_cert); + return ret; +} +# endif + +/*Perform the TLS handshake on a new connection.*/ +static int op_http_conn_start_tls(OpusHTTPStream *_stream,OpusHTTPConn *_conn, + op_sock _fd,SSL *_ssl_conn){ + SSL_SESSION *ssl_session; + BIO *ssl_bio; + int skip_certificate_check; + int ret; + /*This always takes an int, even though with Winsock op_sock is a SOCKET.*/ + ssl_bio=BIO_new_socket((int)_fd,BIO_NOCLOSE); + if(OP_LIKELY(ssl_bio==NULL))return OP_FALSE; +# if !defined(OPENSSL_NO_TLSEXT) + /*Support for RFC 6066 Server Name Indication.*/ + SSL_set_tlsext_host_name(_ssl_conn,_stream->url.host); +# endif + skip_certificate_check=_stream->skip_certificate_check; +# if OPENSSL_VERSION_NUMBER>=0x10002000L + /*As of version 1.0.2, OpenSSL can finally do hostname checks automatically. + Of course, they make it much more complicated than it needs to be.*/ + if(!skip_certificate_check){ + X509_VERIFY_PARAM *param; + struct addrinfo *addr; + char *host; + unsigned char *ip; + int ip_len; + param=SSL_get0_param(_ssl_conn); + OP_ASSERT(param!=NULL); + host=_stream->url.host; + ip=NULL; + ip_len=0; + /*Check to see if the host was specified as a simple IP address.*/ + addr=op_inet_pton(host); + if(addr!=NULL){ + switch(addr->ai_family){ + case AF_INET:{ + struct sockaddr_in *s; + s=(struct sockaddr_in *)addr->ai_addr; + OP_ASSERT(addr->ai_addrlen>=sizeof(*s)); + ip=(unsigned char *)&s->sin_addr; + ip_len=sizeof(s->sin_addr); + host=NULL; + }break; + case AF_INET6:{ + struct sockaddr_in6 *s; + s=(struct sockaddr_in6 *)addr->ai_addr; + OP_ASSERT(addr->ai_addrlen>=sizeof(*s)); + ip=(unsigned char *)&s->sin6_addr; + ip_len=sizeof(s->sin6_addr); + host=NULL; + }break; + } + } + /*Always set both host and ip to prevent matching against an old one. + One of the two will always be NULL, clearing that parameter.*/ + X509_VERIFY_PARAM_set1_host(param,host,0); + X509_VERIFY_PARAM_set1_ip(param,ip,ip_len); + if(addr!=NULL)freeaddrinfo(addr); + } +# endif + /*Resume a previous session if available.*/ + if(_stream->ssl_session!=NULL){ + SSL_set_session(_ssl_conn,_stream->ssl_session); + } + /*If we're proxying, establish the CONNECT tunnel.*/ + if(_stream->proxy_connect.nbuf>0){ + ret=op_http_conn_establish_tunnel(_stream,_conn, + _fd,_ssl_conn,ssl_bio); + if(OP_UNLIKELY(ret<0))return ret; + } + else{ + /*Otherwise, just use this socket directly.*/ + op_sock_set_tcp_nodelay(_fd,1); + SSL_set_bio(_ssl_conn,ssl_bio,ssl_bio); + SSL_set_connect_state(_ssl_conn); + } + ret=op_do_ssl_step(_ssl_conn,_fd,SSL_connect); + if(OP_UNLIKELY(ret<=0))return OP_FALSE; + ssl_session=_stream->ssl_session; + if(ssl_session==NULL +# if OPENSSL_VERSION_NUMBER<0x10002000L + ||!skip_certificate_check +# endif + ){ + ret=op_do_ssl_step(_ssl_conn,_fd,SSL_do_handshake); + if(OP_UNLIKELY(ret<=0))return OP_FALSE; +# if OPENSSL_VERSION_NUMBER<0x10002000L + /*OpenSSL before version 1.0.2 does not do automatic hostname verification, + despite the fact that we just passed it the hostname above in the call + to SSL_set_tlsext_host_name(). + Do it for them.*/ + if(!skip_certificate_check&&!op_http_verify_hostname(_stream,_ssl_conn)){ + return OP_FALSE; + } +# endif + if(ssl_session==NULL){ + /*Save the session for later resumption.*/ + _stream->ssl_session=SSL_get1_session(_ssl_conn); + } + } + _conn->ssl_conn=_ssl_conn; + _conn->fd=_fd; + _conn->nrequests_left=OP_PIPELINE_MAX_REQUESTS; + return 0; +} + +/*Try to start a connection to the next address in the given list of a given + type. + _fd: The socket to connect with. + [inout] _addr: A pointer to the list of addresses. + This will be advanced to the first one that matches the given + address family (possibly the current one). + _ai_family: The address family to connect to. + Return: 1 If the connection was successful. + 0 If the connection is in progress. + OP_FALSE If the connection failed and there were no more addresses + left to try. + *_addr will be set to NULL in this case.*/ +static int op_sock_connect_next(op_sock _fd, + struct addrinfo **_addr,int _ai_family){ + struct addrinfo *addr; + int err; + for(addr=*_addr;;addr=addr->ai_next){ + /*Move to the next address of the requested type.*/ + for(;addr!=NULL&&addr->ai_family!=_ai_family;addr=addr->ai_next); + *_addr=addr; + /*No more: failure.*/ + if(addr==NULL)return OP_FALSE; + if(connect(_fd,addr->ai_addr,addr->ai_addrlen)>=0)return 1; + err=op_errno(); + /*Winsock will set WSAEWOULDBLOCK.*/ + if(OP_LIKELY(err==EINPROGRESS||err==EWOULDBLOCK))return 0; + } +} + +/*The number of address families to try connecting to simultaneously.*/ +# define OP_NPROTOS (2) + +static int op_http_connect_impl(OpusHTTPStream *_stream,OpusHTTPConn *_conn, + struct addrinfo *_addrs,struct timeb *_start_time){ + struct addrinfo *addr; + struct addrinfo *addrs[OP_NPROTOS]; + struct pollfd fds[OP_NPROTOS]; + int ai_family; + int nprotos; + int ret; + int pi; + int pj; + for(pi=0;piai_next){ + if(addr->ai_family==AF_INET6||addr->ai_family==AF_INET){ + OP_ASSERT(addr->ai_addrlen<= + OP_MAX(sizeof(struct sockaddr_in6),sizeof(struct sockaddr_in))); + /*If we've seen this address family before, skip this address for now.*/ + for(pi=0;piai_family==addr->ai_family)break; + if(pifree_head==_conn); + _stream->free_head=_conn->next; + _conn->next=_stream->lru_head; + _stream->lru_head=_conn; + ftime(_start_time); + *&_conn->read_time=*_start_time; + _conn->read_bytes=0; + _conn->read_rate=0; + /*Try to start a connection to each protocol. + RFC 6555 says it is RECOMMENDED that connection attempts be paced + 150...250 ms apart "to balance human factors against network load", but + that "stateful algorithms" (that's us) "are expected to be more + aggressive". + We are definitely more aggressive: we don't pace at all.*/ + for(pi=0;piai_family; + fds[pi].fd=socket(ai_family,SOCK_STREAM,addrs[pi]->ai_protocol); + fds[pi].events=POLLOUT; + if(OP_LIKELY(fds[pi].fd!=OP_INVALID_SOCKET)){ + if(OP_LIKELY(op_sock_set_nonblocking(fds[pi].fd,1)>=0)){ + ret=op_sock_connect_next(fds[pi].fd,addrs+pi,ai_family); + if(OP_UNLIKELY(ret>0)){ + /*It succeeded right away (technically possible), so stop.*/ + nprotos=pi+1; + break; + } + /*Otherwise go on to the next protocol, and skip the clean-up below.*/ + else if(ret==0)continue; + /*Tried all the addresses for this protocol.*/ + } + /*Clean up the socket.*/ + close(fds[pi].fd); + } + /*Remove this protocol from the list.*/ + memmove(addrs+pi,addrs+pi+1,sizeof(*addrs)*(nprotos-pi-1)); + nprotos--; + pi--; + } + /*Wait for one of the connections to finish.*/ + while(pi>=nprotos&&nprotos>0&&poll(fds,nprotos,OP_POLL_TIMEOUT_MS)>0){ + for(pi=0;piai_family; + addrs[pi]=addrs[pi]->ai_next; + ret=op_sock_connect_next(fds[pi].fd,addrs+pi,ai_family); + /*It succeeded right away, so stop.*/ + if(ret>0)break; + /*Otherwise go on to the next protocol, and skip the clean-up below.*/ + else if(ret==0)continue; + /*Tried all the addresses for this protocol. + Remove it from the list.*/ + close(fds[pi].fd); + memmove(fds+pi,fds+pi+1,sizeof(*fds)*(nprotos-pi-1)); + memmove(addrs+pi,addrs+pi+1,sizeof(*addrs)*(nprotos-pi-1)); + nprotos--; + pi--; + } + } + /*Close all the other sockets.*/ + for(pj=0;pj=nprotos)return OP_FALSE; + /*Save this address for future connection attempts.*/ + if(addrs[pi]!=&_stream->addr_info){ + memcpy(&_stream->addr_info,addrs[pi],sizeof(_stream->addr_info)); + _stream->addr_info.ai_addr=&_stream->addr.s; + _stream->addr_info.ai_next=NULL; + memcpy(&_stream->addr,addrs[pi]->ai_addr,addrs[pi]->ai_addrlen); + } + if(OP_URL_IS_SSL(&_stream->url)){ + SSL *ssl_conn; + /*Start the SSL connection.*/ + OP_ASSERT(_stream->ssl_ctx!=NULL); + ssl_conn=SSL_new(_stream->ssl_ctx); + if(OP_LIKELY(ssl_conn!=NULL)){ + ret=op_http_conn_start_tls(_stream,_conn,fds[pi].fd,ssl_conn); + if(OP_LIKELY(ret>=0))return ret; + SSL_free(ssl_conn); + } + close(fds[pi].fd); + _conn->fd=OP_INVALID_SOCKET; + return OP_FALSE; + } + /*Just a normal non-SSL connection.*/ + _conn->ssl_conn=NULL; + _conn->fd=fds[pi].fd; + _conn->nrequests_left=OP_PIPELINE_MAX_REQUESTS; + /*Disable write coalescing. + We always send whole requests at once and always parse the response headers + before sending another one.*/ + op_sock_set_tcp_nodelay(fds[pi].fd,1); + return 0; +} + +static int op_http_connect(OpusHTTPStream *_stream,OpusHTTPConn *_conn, + struct addrinfo *_addrs,struct timeb *_start_time){ + struct timeb resolve_time; + struct addrinfo *new_addrs; + int ret; + /*Re-resolve the host if we need to (RFC 6555 says we MUST do so + occasionally).*/ + new_addrs=NULL; + ftime(&resolve_time); + if(_addrs!=&_stream->addr_info||op_time_diff_ms(&resolve_time, + &_stream->resolve_time)>=OP_RESOLVE_CACHE_TIMEOUT_MS){ + new_addrs=op_resolve(_stream->connect_host,_stream->connect_port); + if(OP_LIKELY(new_addrs!=NULL)){ + _addrs=new_addrs; + *&_stream->resolve_time=*&resolve_time; + } + else if(OP_LIKELY(_addrs==NULL))return OP_FALSE; + } + ret=op_http_connect_impl(_stream,_conn,_addrs,_start_time); + if(new_addrs!=NULL)freeaddrinfo(new_addrs); + return ret; +} + +# define OP_BASE64_LENGTH(_len) (((_len)+2)/3*4) + +static const char BASE64_TABLE[64]={ + 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P', + 'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f', + 'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v', + 'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/' +}; + +static char *op_base64_encode(char *_dst,const char *_src,int _len){ + unsigned s0; + unsigned s1; + unsigned s2; + int ngroups; + int i; + ngroups=_len/3; + for(i=0;i>2]; + _dst[4*i+1]=BASE64_TABLE[(s0&3)<<4|s1>>4]; + _dst[4*i+2]=BASE64_TABLE[(s1&15)<<2|s2>>6]; + _dst[4*i+3]=BASE64_TABLE[s2&63]; + } + _len-=3*i; + if(_len==1){ + s0=_src[3*i+0]; + _dst[4*i+0]=BASE64_TABLE[s0>>2]; + _dst[4*i+1]=BASE64_TABLE[(s0&3)<<4]; + _dst[4*i+2]='='; + _dst[4*i+3]='='; + i++; + } + else if(_len==2){ + s0=_src[3*i+0]; + s1=_src[3*i+1]; + _dst[4*i+0]=BASE64_TABLE[s0>>2]; + _dst[4*i+1]=BASE64_TABLE[(s0&3)<<4|s1>>4]; + _dst[4*i+2]=BASE64_TABLE[(s1&15)<<2]; + _dst[4*i+3]='='; + i++; + } + _dst[4*i]='\0'; + return _dst+4*i; +} + +/*Construct an HTTP authorization header using RFC 2617's Basic Authentication + Scheme and append it to the given string buffer.*/ +static int op_sb_append_basic_auth_header(OpusStringBuf *_sb, + const char *_header,const char *_user,const char *_pass){ + size_t user_len; + size_t pass_len; + int user_pass_len; + int base64_len; + int nbuf_total; + int ret; + ret=op_sb_append_string(_sb,_header); + ret|=op_sb_append(_sb,": Basic ",8); + user_len=strlen(_user); + pass_len=strlen(_pass); + if(OP_UNLIKELY(user_len>(size_t)INT_MAX))return OP_EFAULT; + if(OP_UNLIKELY(pass_len>INT_MAX-user_len))return OP_EFAULT; + if(OP_UNLIKELY((int)(user_len+pass_len)>(INT_MAX>>2)*3-3))return OP_EFAULT; + user_pass_len=(int)(user_len+pass_len)+1; + base64_len=OP_BASE64_LENGTH(user_pass_len); + /*Stick "user:pass" at the end of the buffer so we can Base64 encode it + in-place.*/ + nbuf_total=_sb->nbuf; + if(OP_UNLIKELY(base64_len>INT_MAX-nbuf_total))return OP_EFAULT; + nbuf_total+=base64_len; + ret|=op_sb_ensure_capacity(_sb,nbuf_total); + if(OP_UNLIKELY(ret<0))return ret; + _sb->nbuf=nbuf_total-user_pass_len; + OP_ALWAYS_TRUE(!op_sb_append(_sb,_user,(int)user_len)); + OP_ALWAYS_TRUE(!op_sb_append(_sb,":",1)); + OP_ALWAYS_TRUE(!op_sb_append(_sb,_pass,(int)pass_len)); + op_base64_encode(_sb->buf+nbuf_total-base64_len, + _sb->buf+nbuf_total-user_pass_len,user_pass_len); + return op_sb_append(_sb,"\r\n",2); +} + +static int op_http_allow_pipelining(const char *_server){ + /*Servers known to do bad things with pipelined requests. + This list is taken from Gecko's nsHttpConnection::SupportsPipelining() (in + netwerk/protocol/http/nsHttpConnection.cpp).*/ + static const char *BAD_SERVERS[]={ + "EFAServer/", + "Microsoft-IIS/4.", + "Microsoft-IIS/5.", + "Netscape-Enterprise/3.", + "Netscape-Enterprise/4.", + "Netscape-Enterprise/5.", + "Netscape-Enterprise/6.", + "WebLogic 3.", + "WebLogic 4.", + "WebLogic 5.", + "WebLogic 6.", + "Winstone Servlet Engine v0." + }; +# define NBAD_SERVERS ((int)(sizeof(BAD_SERVERS)/sizeof(*BAD_SERVERS))) + if(*_server>='E'&&*_server<='W'){ + int si; + for(si=0;siurl,_url); + if(OP_UNLIKELY(ret<0))return ret; + if(_proxy_host!=NULL){ + if(OP_UNLIKELY(_proxy_port>65535U))return OP_EINVAL; + _stream->connect_host=op_string_dup(_proxy_host); + _stream->connect_port=_proxy_port; + } + else{ + _stream->connect_host=_stream->url.host; + _stream->connect_port=_stream->url.port; + } + addrs=NULL; + for(nredirs=0;nredirsurl)&&_stream->ssl_ctx==NULL){ + SSL_CTX *ssl_ctx; +# if OPENSSL_VERSION_NUMBER<0x10100000L +# if !defined(OPENSSL_NO_LOCKING) + /*The documentation says SSL_library_init() is not reentrant. + We don't want to add our own depenencies on a threading library, and it + appears that it's safe to call OpenSSL's locking functions before the + library is initialized, so that's what we'll do (really OpenSSL should + do this for us). + This doesn't guarantee that _other_ threads in the application aren't + calling SSL_library_init() at the same time, but there's not much we + can do about that.*/ + CRYPTO_w_lock(CRYPTO_LOCK_SSL); +# endif + SSL_library_init(); + /*Needed to get SHA2 algorithms with old OpenSSL versions.*/ + OpenSSL_add_ssl_algorithms(); +# if !defined(OPENSSL_NO_LOCKING) + CRYPTO_w_unlock(CRYPTO_LOCK_SSL); +# endif +# else + /*Finally, OpenSSL does this for us, but as penance, it can now fail.*/ + if(!OPENSSL_init_ssl(0,NULL))return OP_EFAULT; +# endif + ssl_ctx=SSL_CTX_new(SSLv23_client_method()); + if(ssl_ctx==NULL)return OP_EFAULT; + if(!_skip_certificate_check){ + /*We don't do anything if this fails, since it just means we won't load + any certificates (and thus all checks will fail). + However, as that is probably the result of a system + mis-configuration, assert here to make it easier to identify.*/ + OP_ALWAYS_TRUE(SSL_CTX_set_default_verify_paths(ssl_ctx)); + SSL_CTX_set_verify(ssl_ctx,SSL_VERIFY_PEER,NULL); + } + _stream->ssl_ctx=ssl_ctx; + _stream->skip_certificate_check=_skip_certificate_check; + if(_proxy_host!=NULL){ + /*We need to establish a CONNECT tunnel to handle https proxying. + Build the request we'll send to do so.*/ + _stream->proxy_connect.nbuf=0; + ret=op_sb_append(&_stream->proxy_connect,"CONNECT ",8); + ret|=op_sb_append_string(&_stream->proxy_connect,_stream->url.host); + ret|=op_sb_append_port(&_stream->proxy_connect,_stream->url.port); + /*CONNECT requires at least HTTP 1.1.*/ + ret|=op_sb_append(&_stream->proxy_connect," HTTP/1.1\r\n",11); + ret|=op_sb_append(&_stream->proxy_connect,"Host: ",6); + ret|=op_sb_append_string(&_stream->proxy_connect,_stream->url.host); + /*The example in RFC 2817 Section 5.2 specifies an explicit port even + when connecting to the default port. + Given that the proxy doesn't know whether we're trying to connect to + an http or an https URL except by the port number, this seems like a + good idea.*/ + ret|=op_sb_append_port(&_stream->proxy_connect,_stream->url.port); + ret|=op_sb_append(&_stream->proxy_connect,"\r\n",2); + ret|=op_sb_append(&_stream->proxy_connect,"User-Agent: .\r\n",15); + if(_proxy_user!=NULL&&_proxy_pass!=NULL){ + ret|=op_sb_append_basic_auth_header(&_stream->proxy_connect, + "Proxy-Authorization",_proxy_user,_proxy_pass); + } + /*For backwards compatibility.*/ + ret|=op_sb_append(&_stream->proxy_connect, + "Proxy-Connection: keep-alive\r\n",30); + ret|=op_sb_append(&_stream->proxy_connect,"\r\n",2); + if(OP_UNLIKELY(ret<0))return ret; + } + } + /*Actually make the connection.*/ + ret=op_http_connect(_stream,_stream->conns+0,addrs,&start_time); + if(OP_UNLIKELY(ret<0))return ret; + /*Build the request to send.*/ + _stream->request.nbuf=0; + ret=op_sb_append(&_stream->request,"GET ",4); + ret|=op_sb_append_string(&_stream->request, + _proxy_host!=NULL?_url:_stream->url.path); + /*Send HTTP/1.0 by default for maximum compatibility (so we don't have to + re-try if HTTP/1.1 fails, though it shouldn't, even for a 1.0 server). + This means we aren't conditionally compliant with RFC 2145, because we + violate the requirement that "An HTTP client SHOULD send a request + version equal to the highest version for which the client is at least + conditionally compliant...". + According to RFC 2145, that means we can't claim any compliance with any + IETF HTTP specification.*/ + ret|=op_sb_append(&_stream->request," HTTP/1.0\r\n",11); + /*Remember where this is so we can upgrade to HTTP/1.1 if the server + supports it.*/ + minor_version_pos=_stream->request.nbuf-3; + ret|=op_sb_append(&_stream->request,"Host: ",6); + ret|=op_sb_append_string(&_stream->request,_stream->url.host); + if(!OP_URL_IS_DEFAULT_PORT(&_stream->url)){ + ret|=op_sb_append_port(&_stream->request,_stream->url.port); + } + ret|=op_sb_append(&_stream->request,"\r\n",2); + /*User-Agents have been a bad idea, so send as little as possible. + RFC 2616 requires at least one token in the User-Agent, which must have + at least one character.*/ + ret|=op_sb_append(&_stream->request,"User-Agent: .\r\n",15); + if(_proxy_host!=NULL&&!OP_URL_IS_SSL(&_stream->url) + &&_proxy_user!=NULL&&_proxy_pass!=NULL){ + ret|=op_sb_append_basic_auth_header(&_stream->request, + "Proxy-Authorization",_proxy_user,_proxy_pass); + } + if(_stream->url.user!=NULL&&_stream->url.pass!=NULL){ + ret|=op_sb_append_basic_auth_header(&_stream->request, + "Authorization",_stream->url.user,_stream->url.pass); + } + /*Always send a Referer [sic] header. + It's common to refuse to serve a resource unless one is present. + We just use the relative "/" URI to suggest we came from the same domain, + as this is the most common check. + This might violate RFC 2616's mandate that the field "MUST NOT be sent if + the Request-URI was obtained from a source that does not have its own + URI, such as input from the user keyboard," but we don't really have any + way to know.*/ + /*TODO: Should we update this on redirects?*/ + ret|=op_sb_append(&_stream->request,"Referer: /\r\n",12); + /*Always send a Range request header to find out if we're seekable. + This requires an HTTP/1.1 server to succeed, but we'll still get what we + want with an HTTP/1.0 server that ignores this request header.*/ + ret|=op_sb_append(&_stream->request,"Range: bytes=0-\r\n",17); + /*Remember where this is so we can append offsets to it later.*/ + _stream->request_tail=_stream->request.nbuf-4; + ret|=op_sb_append(&_stream->request,"\r\n",2); + if(OP_UNLIKELY(ret<0))return ret; + ret=op_http_conn_write_fully(_stream->conns+0, + _stream->request.buf,_stream->request.nbuf); + if(OP_UNLIKELY(ret<0))return ret; + ret=op_http_conn_read_response(_stream->conns+0,&_stream->response); + if(OP_UNLIKELY(ret<0))return ret; + ftime(&end_time); + next=op_http_parse_status_line(&v1_1_compat,&status_code, + _stream->response.buf); + if(OP_UNLIKELY(next==NULL))return OP_FALSE; + if(status_code[0]=='2'){ + opus_int64 content_length; + opus_int64 range_length; + int pipeline_supported; + int pipeline_disabled; + /*We only understand 20x codes.*/ + if(status_code[1]!='0')return OP_FALSE; + content_length=-1; + range_length=-1; + /*Pipelining must be explicitly enabled.*/ + pipeline_supported=0; + pipeline_disabled=0; + for(;;){ + char *header; + char *cdr; + ret=op_http_get_next_header(&header,&cdr,&next); + if(OP_UNLIKELY(ret<0))return ret; + if(header==NULL)break; + if(strcmp(header,"content-length")==0){ + /*Two Content-Length headers?*/ + if(OP_UNLIKELY(content_length>=0))return OP_FALSE; + content_length=op_http_parse_content_length(cdr); + if(OP_UNLIKELY(content_length<0))return (int)content_length; + /*Make sure the Content-Length and Content-Range headers match.*/ + if(range_length>=0&&OP_UNLIKELY(content_length!=range_length)){ + return OP_FALSE; + } + } + else if(strcmp(header,"content-range")==0){ + opus_int64 range_first; + opus_int64 range_last; + /*Two Content-Range headers?*/ + if(OP_UNLIKELY(range_length>=0))return OP_FALSE; + ret=op_http_parse_content_range(&range_first,&range_last, + &range_length,cdr); + if(OP_UNLIKELY(ret<0))return ret; + /*"A response with satus code 206 (Partial Content) MUST NOT + include a Content-Range field with a byte-range-resp-spec of + '*'."*/ + if(status_code[2]=='6' + &&(OP_UNLIKELY(range_first<0)||OP_UNLIKELY(range_last<0))){ + return OP_FALSE; + } + /*We asked for the entire resource.*/ + if(range_length>=0){ + /*Quit if we didn't get it.*/ + if(range_last>=0&&OP_UNLIKELY(range_last!=range_length-1)){ + return OP_FALSE; + } + } + /*If there was no length, use the end of the range.*/ + else if(range_last>=0)range_length=range_last+1; + /*Make sure the Content-Length and Content-Range headers match.*/ + if(content_length>=0&&OP_UNLIKELY(content_length!=range_length)){ + return OP_FALSE; + } + } + else if(strcmp(header,"connection")==0){ + /*According to RFC 2616, if an HTTP/1.1 application does not support + pipelining, it "MUST include the 'close' connection option in + every message." + Therefore, if we receive one in the initial response, disable + pipelining entirely. + The server still might support it (e.g., we might just have hit the + request limit for a temporary child process), but if it doesn't + and we assume it does, every time we cross a chunk boundary we'll + error out and reconnect, adding lots of latency.*/ + ret=op_http_parse_connection(cdr); + if(OP_UNLIKELY(ret<0))return ret; + pipeline_disabled|=ret; + } + else if(strcmp(header,"server")==0){ + /*If we got a Server response header, and it wasn't from a known-bad + server, enable pipelining, as long as it's at least HTTP/1.1. + According to RFC 2145, the server is supposed to respond with the + highest minor version number it supports unless it is known or + suspected that we incorrectly implement the HTTP specification. + So it should send back at least HTTP/1.1, despite our HTTP/1.0 + request.*/ + pipeline_supported=v1_1_compat; + if(v1_1_compat)pipeline_disabled|=!op_http_allow_pipelining(cdr); + if(_info!=NULL&&_info->server==NULL)_info->server=op_string_dup(cdr); + } + /*Collect station information headers if the caller requested it. + If there's more than one copy of a header, the first one wins.*/ + else if(_info!=NULL){ + if(strcmp(header,"content-type")==0){ + if(_info->content_type==NULL){ + _info->content_type=op_string_dup(cdr); + } + } + else if(header[0]=='i'&&header[1]=='c' + &&(header[2]=='e'||header[2]=='y')&&header[3]=='-'){ + if(strcmp(header+4,"name")==0){ + if(_info->name==NULL)_info->name=op_string_dup(cdr); + } + else if(strcmp(header+4,"description")==0){ + if(_info->description==NULL)_info->description=op_string_dup(cdr); + } + else if(strcmp(header+4,"genre")==0){ + if(_info->genre==NULL)_info->genre=op_string_dup(cdr); + } + else if(strcmp(header+4,"url")==0){ + if(_info->url==NULL)_info->url=op_string_dup(cdr); + } + else if(strcmp(header,"icy-br")==0 + ||strcmp(header,"ice-bitrate")==0){ + if(_info->bitrate_kbps<0){ + opus_int64 bitrate_kbps; + /*Just re-using this function to parse a random unsigned + integer field.*/ + bitrate_kbps=op_http_parse_content_length(cdr); + if(bitrate_kbps>=0&&bitrate_kbps<=OP_INT32_MAX){ + _info->bitrate_kbps=(opus_int32)bitrate_kbps; + } + } + } + else if(strcmp(header,"icy-pub")==0 + ||strcmp(header,"ice-public")==0){ + if(_info->is_public<0&&(cdr[0]=='0'||cdr[0]=='1')&&cdr[1]=='\0'){ + _info->is_public=cdr[0]-'0'; + } + } + } + } + } + switch(status_code[2]){ + /*200 OK*/ + case '0':break; + /*203 Non-Authoritative Information*/ + case '3':break; + /*204 No Content*/ + case '4':{ + if(content_length>=0&&OP_UNLIKELY(content_length!=0)){ + return OP_FALSE; + } + }break; + /*206 Partial Content*/ + case '6':{ + /*No Content-Range header.*/ + if(OP_UNLIKELY(range_length<0))return OP_FALSE; + content_length=range_length; + /*The server supports range requests for this resource. + We can seek.*/ + _stream->seekable=1; + }break; + /*201 Created: the response "SHOULD include an entity containing a list + of resource characteristics and location(s)," but not an Opus file. + 202 Accepted: the response "SHOULD include an indication of request's + current status and either a pointer to a status monitor or some + estimate of when the user can expect the request to be fulfilled," + but not an Opus file. + 205 Reset Content: this "MUST NOT include an entity," meaning no Opus + file. + 207...209 are not yet defined, so we don't know how to handle them.*/ + default:return OP_FALSE; + } + _stream->content_length=content_length; + _stream->pipeline=pipeline_supported&&!pipeline_disabled; + /*Pipelining requires HTTP/1.1 persistent connections.*/ + if(_stream->pipeline)_stream->request.buf[minor_version_pos]='1'; + _stream->conns[0].pos=0; + _stream->conns[0].end_pos=_stream->seekable?content_length:-1; + _stream->conns[0].chunk_size=-1; + _stream->cur_conni=0; + _stream->connect_rate=op_time_diff_ms(&end_time,&start_time); + _stream->connect_rate=OP_MAX(_stream->connect_rate,1); + if(_info!=NULL)_info->is_ssl=OP_URL_IS_SSL(&_stream->url); + /*The URL has been successfully opened.*/ + return 0; + } + /*Shouldn't get 1xx; 4xx and 5xx are both failures (and we don't retry). + Everything else is undefined.*/ + else if(status_code[0]!='3')return OP_FALSE; + /*We have some form of redirect request.*/ + /*We only understand 30x codes.*/ + if(status_code[1]!='0')return OP_FALSE; + switch(status_code[2]){ + /*300 Multiple Choices: "If the server has a preferred choice of + representation, it SHOULD include the specific URI for that + representation in the Location field," otherwise we'll fail.*/ + case '0': + /*301 Moved Permanently*/ + case '1': + /*302 Found*/ + case '2': + /*307 Temporary Redirect*/ + case '7': + /*308 Permanent Redirect (defined by draft-reschke-http-status-308-07).*/ + case '8':break; + /*305 Use Proxy: "The Location field gives the URI of the proxy." + TODO: This shouldn't actually be that hard to do.*/ + case '5':return OP_EIMPL; + /*303 See Other: "The new URI is not a substitute reference for the + originally requested resource." + 304 Not Modified: "The 304 response MUST NOT contain a message-body." + 306 (Unused) + 309 is not yet defined, so we don't know how to handle it.*/ + default:return OP_FALSE; + } + _url=NULL; + for(;;){ + char *header; + char *cdr; + ret=op_http_get_next_header(&header,&cdr,&next); + if(OP_UNLIKELY(ret<0))return ret; + if(header==NULL)break; + if(strcmp(header,"location")==0&&OP_LIKELY(_url==NULL))_url=cdr; + } + if(OP_UNLIKELY(_url==NULL))return OP_FALSE; + ret=op_parse_url(&next_url,_url); + if(OP_UNLIKELY(ret<0))return ret; + if(_proxy_host==NULL||_stream->ssl_session!=NULL){ + if(strcmp(_stream->url.host,next_url.host)==0 + &&_stream->url.port==next_url.port){ + /*Try to skip re-resolve when connecting to the same host.*/ + addrs=&_stream->addr_info; + } + else{ + if(_stream->ssl_session!=NULL){ + /*Forget any cached SSL session from the last host.*/ + SSL_SESSION_free(_stream->ssl_session); + _stream->ssl_session=NULL; + } + } + } + if(_proxy_host==NULL){ + OP_ASSERT(_stream->connect_host==_stream->url.host); + _stream->connect_host=next_url.host; + _stream->connect_port=next_url.port; + } + /*Always try to skip re-resolve for proxy connections.*/ + else addrs=&_stream->addr_info; + op_parsed_url_clear(&_stream->url); + *&_stream->url=*&next_url; + /*TODO: On servers/proxies that support pipelining, we might be able to + re-use this connection.*/ + op_http_conn_close(_stream,_stream->conns+0,&_stream->lru_head,1); + } + /*Redirection limit reached.*/ + return OP_FALSE; +} + +static int op_http_conn_send_request(OpusHTTPStream *_stream, + OpusHTTPConn *_conn,opus_int64 _pos,opus_int32 _chunk_size, + int _try_not_to_block){ + opus_int64 next_end; + int ret; + /*We shouldn't have another request outstanding.*/ + OP_ASSERT(_conn->next_pos<0); + /*Build the request to send.*/ + OP_ASSERT(_stream->request.nbuf>=_stream->request_tail); + _stream->request.nbuf=_stream->request_tail; + ret=op_sb_append_nonnegative_int64(&_stream->request,_pos); + ret|=op_sb_append(&_stream->request,"-",1); + if(_chunk_size>0&&OP_ADV_OFFSET(_pos,2*_chunk_size)<_stream->content_length){ + /*We shouldn't be pipelining requests with non-HTTP/1.1 servers.*/ + OP_ASSERT(_stream->pipeline); + next_end=_pos+_chunk_size; + ret|=op_sb_append_nonnegative_int64(&_stream->request,next_end-1); + /*Use a larger chunk size for our next request.*/ + _chunk_size<<=1; + /*But after a while, just request the rest of the resource.*/ + if(_chunk_size>OP_PIPELINE_CHUNK_SIZE_MAX)_chunk_size=-1; + } + else{ + /*Either this was a non-pipelined request or we were close enough to the + end to just ask for the rest.*/ + next_end=-1; + _chunk_size=-1; + } + ret|=op_sb_append(&_stream->request,"\r\n\r\n",4); + if(OP_UNLIKELY(ret<0))return ret; + /*If we don't want to block, check to see if there's enough space in the send + queue. + There's still a chance we might block, even if there is enough space, but + it's a much slimmer one. + Blocking at all is pretty unlikely, as we won't have any requests queued + when _try_not_to_block is set, so if FIONSPACE isn't available (e.g., on + Linux), just skip the test.*/ + if(_try_not_to_block){ +# if defined(FIONSPACE) + int available; + ret=ioctl(_conn->fd,FIONSPACE,&available); + if(ret<0||available<_stream->request.nbuf)return 1; +# endif + } + ret=op_http_conn_write_fully(_conn, + _stream->request.buf,_stream->request.nbuf); + if(OP_UNLIKELY(ret<0))return ret; + _conn->next_pos=_pos; + _conn->next_end=next_end; + /*Save the chunk size to use for the next request.*/ + _conn->chunk_size=_chunk_size; + _conn->nrequests_left--; + return ret; +} + +/*Handles the response to all requests after the first one. + Return: 1 if the connection was closed or timed out, 0 on success, or a + negative value on any other error.*/ +static int op_http_conn_handle_response(OpusHTTPStream *_stream, + OpusHTTPConn *_conn){ + char *next; + char *status_code; + opus_int64 range_length; + opus_int64 next_pos; + opus_int64 next_end; + int ret; + ret=op_http_conn_read_response(_conn,&_stream->response); + /*If the server just closed the connection on us, we may have just hit a + connection re-use limit, so we might want to retry.*/ + if(OP_UNLIKELY(ret<0))return ret==OP_EREAD?1:ret; + next=op_http_parse_status_line(NULL,&status_code,_stream->response.buf); + if(OP_UNLIKELY(next==NULL))return OP_FALSE; + /*We _need_ a 206 Partial Content response. + Nothing else will do.*/ + if(strncmp(status_code,"206",3)!=0){ + /*But on a 408 Request Timeout, we might want to re-try.*/ + return strncmp(status_code,"408",3)==0?1:OP_FALSE; + } + next_pos=_conn->next_pos; + next_end=_conn->next_end; + range_length=-1; + for(;;){ + char *header; + char *cdr; + ret=op_http_get_next_header(&header,&cdr,&next); + if(OP_UNLIKELY(ret<0))return ret; + if(header==NULL)break; + if(strcmp(header,"content-range")==0){ + opus_int64 range_first; + opus_int64 range_last; + /*Two Content-Range headers?*/ + if(OP_UNLIKELY(range_length>=0))return OP_FALSE; + ret=op_http_parse_content_range(&range_first,&range_last, + &range_length,cdr); + if(OP_UNLIKELY(ret<0))return ret; + /*"A response with satus code 206 (Partial Content) MUST NOT + include a Content-Range field with a byte-range-resp-spec of + '*'."*/ + if(OP_UNLIKELY(range_first<0)||OP_UNLIKELY(range_last<0))return OP_FALSE; + /*We also don't want range_last to overflow.*/ + if(OP_UNLIKELY(range_last>=OP_INT64_MAX))return OP_FALSE; + range_last++; + /*Quit if we didn't get the offset we asked for.*/ + if(range_first!=next_pos)return OP_FALSE; + if(next_end<0){ + /*We asked for the rest of the resource.*/ + if(range_length>=0){ + /*Quit if we didn't get it.*/ + if(OP_UNLIKELY(range_last!=range_length))return OP_FALSE; + } + /*If there was no length, use the end of the range.*/ + else range_length=range_last; + next_end=range_last; + } + else{ + if(range_last!=next_end)return OP_FALSE; + /*If there was no length, use the larger of the content length or the + end of this chunk.*/ + if(range_length<0){ + range_length=OP_MAX(range_last,_stream->content_length); + } + } + } + else if(strcmp(header,"content-length")==0){ + opus_int64 content_length; + /*Validate the Content-Length header, if present, against the request we + made.*/ + content_length=op_http_parse_content_length(cdr); + if(OP_UNLIKELY(content_length<0))return (int)content_length; + if(next_end<0){ + /*If we haven't seen the Content-Range header yet and we asked for the + rest of the resource, set next_end, so we can make sure they match + when we do find the Content-Range header.*/ + if(OP_UNLIKELY(next_pos>OP_INT64_MAX-content_length))return OP_FALSE; + next_end=next_pos+content_length; + } + /*Otherwise, make sure they match now.*/ + else if(OP_UNLIKELY(next_end-next_pos!=content_length))return OP_FALSE; + } + else if(strcmp(header,"connection")==0){ + ret=op_http_parse_connection(cdr); + if(OP_UNLIKELY(ret<0))return ret; + /*If the server told us it was going to close the connection, don't make + any more requests.*/ + if(OP_UNLIKELY(ret>0))_conn->nrequests_left=0; + } + } + /*No Content-Range header.*/ + if(OP_UNLIKELY(range_length<0))return OP_FALSE; + /*Update the content_length if necessary.*/ + _stream->content_length=range_length; + _conn->pos=next_pos; + _conn->end_pos=next_end; + _conn->next_pos=-1; + return 0; +} + +/*Open a new connection that will start reading at byte offset _pos. + _pos: The byte offset to start reading from. + _chunk_size: The number of bytes to ask for in the initial request, or -1 to + request the rest of the resource. + This may be more bytes than remain, in which case it will be + converted into a request for the rest.*/ +static int op_http_conn_open_pos(OpusHTTPStream *_stream, + OpusHTTPConn *_conn,opus_int64 _pos,opus_int32 _chunk_size){ + struct timeb start_time; + struct timeb end_time; + opus_int32 connect_rate; + opus_int32 connect_time; + int ret; + ret=op_http_connect(_stream,_conn,&_stream->addr_info,&start_time); + if(OP_UNLIKELY(ret<0))return ret; + ret=op_http_conn_send_request(_stream,_conn,_pos,_chunk_size,0); + if(OP_UNLIKELY(ret<0))return ret; + ret=op_http_conn_handle_response(_stream,_conn); + if(OP_UNLIKELY(ret!=0))return OP_FALSE; + ftime(&end_time); + _stream->cur_conni=(int)(_conn-_stream->conns); + OP_ASSERT(_stream->cur_conni>=0&&_stream->cur_conniconnect_rate; + connect_rate+=OP_MAX(connect_time,1)-connect_rate+8>>4; + _stream->connect_rate=connect_rate; + return 0; +} + +/*Read data from the current response body. + If we're pipelining and we get close to the end of this response, queue + another request. + If we've reached the end of this response body, parse the next response and + keep going. + [out] _buf: Returns the data read. + _buf_size: The size of the buffer. + Return: A positive number of bytes read on success. + 0: The connection was closed. + OP_EREAD: There was a fatal read error.*/ +static int op_http_conn_read_body(OpusHTTPStream *_stream, + OpusHTTPConn *_conn,unsigned char *_buf,int _buf_size){ + opus_int64 pos; + opus_int64 end_pos; + opus_int64 next_pos; + opus_int64 content_length; + int nread; + int pipeline; + int ret; + /*Currently this function can only be called on the LRU head. + Otherwise, we'd need a _pnext pointer if we needed to close the connection, + and re-opening it would re-organize the lists.*/ + OP_ASSERT(_stream->lru_head==_conn); + /*We should have filtered out empty reads by this point.*/ + OP_ASSERT(_buf_size>0); + pos=_conn->pos; + end_pos=_conn->end_pos; + next_pos=_conn->next_pos; + pipeline=_stream->pipeline; + content_length=_stream->content_length; + if(end_pos>=0){ + /*Have we reached the end of the current response body?*/ + if(pos>=end_pos){ + OP_ASSERT(content_length>=0); + /*If this was the end of the stream, we're done. + Also return early if a non-blocking read was requested (regardless of + whether we might be able to parse the next response without + blocking).*/ + if(content_length<=end_pos)return 0; + /*Otherwise, start on the next response.*/ + if(next_pos<0){ + /*We haven't issued another request yet.*/ + if(!pipeline||_conn->nrequests_left<=0){ + /*There are two ways to get here: either the server told us it was + going to close the connection after the last request, or we + thought we were reading the whole resource, but it grew while we + were reading it. + The only way the latter could have happened is if content_length + changed while seeking. + Open a new request to read the rest.*/ + OP_ASSERT(_stream->seekable); + /*Try to open a new connection to read another chunk.*/ + op_http_conn_close(_stream,_conn,&_stream->lru_head,1); + /*If we're not pipelining, we should be requesting the rest.*/ + OP_ASSERT(pipeline||_conn->chunk_size==-1); + ret=op_http_conn_open_pos(_stream,_conn,end_pos,_conn->chunk_size); + if(OP_UNLIKELY(ret<0))return OP_EREAD; + } + else{ + /*Issue the request now (better late than never).*/ + ret=op_http_conn_send_request(_stream,_conn,pos,_conn->chunk_size,0); + if(OP_UNLIKELY(ret<0))return OP_EREAD; + next_pos=_conn->next_pos; + OP_ASSERT(next_pos>=0); + } + } + if(next_pos>=0){ + /*We shouldn't be trying to read past the current request body if we're + seeking somewhere else.*/ + OP_ASSERT(next_pos==end_pos); + ret=op_http_conn_handle_response(_stream,_conn); + if(OP_UNLIKELY(ret<0))return OP_EREAD; + if(OP_UNLIKELY(ret>0)&&pipeline){ + opus_int64 next_end; + next_end=_conn->next_end; + /*Our request timed out or the server closed the connection. + Try re-connecting.*/ + op_http_conn_close(_stream,_conn,&_stream->lru_head,1); + /*Unless there's a bug, we should be able to convert + (next_pos,next_end) into valid (_pos,_chunk_size) parameters.*/ + OP_ASSERT(next_end<0 + ||next_end-next_pos>=0&&next_end-next_pos<=OP_INT32_MAX); + ret=op_http_conn_open_pos(_stream,_conn,next_pos, + next_end<0?-1:(opus_int32)(next_end-next_pos)); + if(OP_UNLIKELY(ret<0))return OP_EREAD; + } + else if(OP_UNLIKELY(ret!=0))return OP_EREAD; + } + pos=_conn->pos; + end_pos=_conn->end_pos; + content_length=_stream->content_length; + } + OP_ASSERT(end_pos>pos); + _buf_size=(int)OP_MIN(_buf_size,end_pos-pos); + } + nread=op_http_conn_read(_conn,(char *)_buf,_buf_size,1); + if(OP_UNLIKELY(nread<0))return nread; + pos+=nread; + _conn->pos=pos; + OP_ASSERT(end_pos<0||content_length>=0); + /*TODO: If nrequests_left<=0, we can't make a new request, and there will be + a big pause after we hit the end of the chunk while we open a new + connection. + It would be nice to be able to start that process now, but we have no way + to do it in the background without blocking (even if we could start it, we + have no guarantee the application will return control to us in a + sufficiently timely manner to allow us to complete it, and this is + uncommon enough that it's not worth using threads just for this).*/ + if(end_pos>=0&&end_posnrequests_left>0)){ + opus_int64 request_thresh; + opus_int32 chunk_size; + /*Are we getting close to the end of the current response body? + If so, we should request more data.*/ + request_thresh=_stream->connect_rate*_conn->read_rate>>12; + /*But don't commit ourselves too quickly.*/ + chunk_size=_conn->chunk_size; + if(chunk_size>=0)request_thresh=OP_MIN(chunk_size>>2,request_thresh); + if(end_pos-poschunk_size,1); + if(OP_UNLIKELY(ret<0))return OP_EREAD; + } + } + return nread; +} + +static int op_http_stream_read(void *_stream, + unsigned char *_ptr,int _buf_size){ + OpusHTTPStream *stream; + int nread; + opus_int64 size; + opus_int64 pos; + int ci; + stream=(OpusHTTPStream *)_stream; + /*Check for an empty read.*/ + if(_buf_size<=0)return 0; + ci=stream->cur_conni; + /*No current connection => EOF.*/ + if(ci<0)return 0; + pos=stream->conns[ci].pos; + size=stream->content_length; + /*Check for EOF.*/ + if(size>=0){ + if(pos>=size)return 0; + /*Check for a short read.*/ + if(_buf_size>size-pos)_buf_size=(int)(size-pos); + } + nread=op_http_conn_read_body(stream,stream->conns+ci,_ptr,_buf_size); + if(OP_UNLIKELY(nread<=0)){ + /*We hit an error or EOF. + Either way, we're done with this connection.*/ + op_http_conn_close(stream,stream->conns+ci,&stream->lru_head,1); + stream->cur_conni=-1; + stream->pos=pos; + } + return nread; +} + +/*Discard data until we reach the _target position. + This destroys the contents of _stream->response.buf, as we need somewhere to + read this data, and that is a convenient place. + _just_read_ahead: Whether or not this is a plain fast-forward. + If 0, we need to issue a new request for a chunk at _target + and discard all the data from our current request(s). + Otherwise, we should be able to reach _target without + issuing any new requests. + _target: The stream position to which to read ahead.*/ +static int op_http_conn_read_ahead(OpusHTTPStream *_stream, + OpusHTTPConn *_conn,int _just_read_ahead,opus_int64 _target){ + opus_int64 pos; + opus_int64 end_pos; + opus_int64 next_pos; + opus_int64 next_end; + ptrdiff_t nread; + int ret; + pos=_conn->pos; + end_pos=_conn->end_pos; + next_pos=_conn->next_pos; + next_end=_conn->next_end; + if(!_just_read_ahead){ + /*We need to issue a new pipelined request. + This is the only case where we allow more than one outstanding request + at a time, so we need to reset next_pos (we'll restore it below if we + did have an outstanding request).*/ + OP_ASSERT(_stream->pipeline); + _conn->next_pos=-1; + ret=op_http_conn_send_request(_stream,_conn,_target, + OP_PIPELINE_CHUNK_SIZE,0); + if(OP_UNLIKELY(ret<0))return ret; + } + /*We can reach the target position by reading forward in the current chunk.*/ + if(_just_read_ahead&&(end_pos<0||_target=0){ + opus_int64 next_next_pos; + opus_int64 next_next_end; + /*We already have a request outstanding. + Finish off the current chunk.*/ + while(posresponse.buf, + (int)OP_MIN(end_pos-pos,_stream->response.cbuf),1); + /*We failed to read ahead.*/ + if(nread<=0)return OP_FALSE; + pos+=nread; + } + OP_ASSERT(pos==end_pos); + if(_just_read_ahead){ + next_next_pos=next_next_end=-1; + end_pos=_target; + } + else{ + OP_ASSERT(_conn->next_pos==_target); + next_next_pos=_target; + next_next_end=_conn->next_end; + _conn->next_pos=next_pos; + _conn->next_end=next_end; + end_pos=next_end; + } + ret=op_http_conn_handle_response(_stream,_conn); + if(OP_UNLIKELY(ret!=0))return OP_FALSE; + _conn->next_pos=next_next_pos; + _conn->next_end=next_next_end; + } + while(posresponse.buf, + (int)OP_MIN(end_pos-pos,_stream->response.cbuf),1); + /*We failed to read ahead.*/ + if(nread<=0)return OP_FALSE; + pos+=nread; + } + OP_ASSERT(pos==end_pos); + if(!_just_read_ahead){ + ret=op_http_conn_handle_response(_stream,_conn); + if(OP_UNLIKELY(ret!=0))return OP_FALSE; + } + else _conn->pos=end_pos; + OP_ASSERT(_conn->pos==_target); + return 0; +} + +static int op_http_stream_seek(void *_stream,opus_int64 _offset,int _whence){ + struct timeb seek_time; + OpusHTTPStream *stream; + OpusHTTPConn *conn; + OpusHTTPConn **pnext; + OpusHTTPConn *close_conn; + OpusHTTPConn **close_pnext; + opus_int64 content_length; + opus_int64 pos; + int pipeline; + int ci; + int ret; + stream=(OpusHTTPStream *)_stream; + if(!stream->seekable)return -1; + content_length=stream->content_length; + /*If we're seekable, we should have gotten a Content-Length.*/ + OP_ASSERT(content_length>=0); + ci=stream->cur_conni; + pos=ci<0?content_length:stream->conns[ci].pos; + switch(_whence){ + case SEEK_SET:{ + /*Check for overflow:*/ + if(_offset<0)return -1; + pos=_offset; + }break; + case SEEK_CUR:{ + /*Check for overflow:*/ + if(_offset<-pos||_offset>OP_INT64_MAX-pos)return -1; + pos+=_offset; + }break; + case SEEK_END:{ + /*Check for overflow:*/ + if(_offset>content_length||_offset=0){ + op_http_conn_read_rate_update(stream->conns+ci); + *&seek_time=*&stream->conns[ci].read_time; + } + else ftime(&seek_time); + /*If we seeked past the end of the stream, just disable the active + connection.*/ + if(pos>=content_length){ + stream->cur_conni=-1; + stream->pos=pos; + return 0; + } + /*First try to find a connection we can use without waiting.*/ + pnext=&stream->lru_head; + conn=stream->lru_head; + while(conn!=NULL){ + opus_int64 conn_pos; + opus_int64 end_pos; + int available; + /*If this connection has been dormant too long or has made too many + requests, close it. + This is to prevent us from hitting server limits/firewall timeouts.*/ + if(op_time_diff_ms(&seek_time,&conn->read_time)> + OP_CONNECTION_IDLE_TIMEOUT_MS + ||conn->nrequests_leftpos; + end_pos=conn->end_pos; + if(conn->next_pos>=0){ + OP_ASSERT(end_pos>=0); + OP_ASSERT(conn->next_pos==end_pos); + end_pos=conn->next_end; + } + OP_ASSERT(end_pos<0||conn_pos<=end_pos); + /*Can we quickly read ahead without issuing a new request or waiting for + any more data? + If we have an oustanding request, we'll over-estimate the amount of data + it has available (because we'll count the response headers, too), but + that probably doesn't matter.*/ + if(conn_pos<=pos&&pos-conn_pos<=available&&(end_pos<0||posnext; + conn->next=stream->lru_head; + stream->lru_head=conn; + stream->cur_conni=(int)(conn-stream->conns); + OP_ASSERT(stream->cur_conni>=0&&stream->cur_conninext; + conn=conn->next; + } + /*Chances are that didn't work, so now try to find one we can use by reading + ahead a reasonable amount and/or by issuing a new request.*/ + close_pnext=NULL; + close_conn=NULL; + pnext=&stream->lru_head; + conn=stream->lru_head; + pipeline=stream->pipeline; + while(conn!=NULL){ + opus_int64 conn_pos; + opus_int64 end_pos; + opus_int64 read_ahead_thresh; + int available; + int just_read_ahead; + /*Dividing by 2048 instead of 1000 scales this by nearly 1/2, biasing away + from connection re-use (and roughly compensating for the lag required to + reopen the TCP window of a connection that's been idle). + There's no overflow checking here, because it's vanishingly unlikely, and + all it would do is cause us to make poor decisions.*/ + read_ahead_thresh=OP_MAX(OP_READAHEAD_THRESH_MIN, + stream->connect_rate*conn->read_rate>>11); + available=op_http_conn_estimate_available(conn); + conn_pos=conn->pos; + end_pos=conn->end_pos; + if(conn->next_pos>=0){ + OP_ASSERT(end_pos>=0); + OP_ASSERT(conn->next_pos==end_pos); + end_pos=conn->next_end; + } + OP_ASSERT(end_pos<0||conn_pos<=end_pos); + /*Can we quickly read ahead without issuing a new request?*/ + just_read_ahead=conn_pos<=pos&&pos-conn_pos-available<=read_ahead_thresh + &&(end_pos<0||pos=0 + &&end_pos-conn_pos-available<=read_ahead_thresh){ + /*Found a suitable connection to re-use.*/ + ret=op_http_conn_read_ahead(stream,conn,just_read_ahead,pos); + if(OP_UNLIKELY(ret<0)){ + /*The connection might have become stale, so close it and keep going.*/ + op_http_conn_close(stream,conn,pnext,1); + conn=*pnext; + continue; + } + /*Sucessfully resurrected this connection.*/ + *pnext=conn->next; + conn->next=stream->lru_head; + stream->lru_head=conn; + stream->cur_conni=(int)(conn-stream->conns); + OP_ASSERT(stream->cur_conni>=0&&stream->cur_conninext; + conn=conn->next; + } + /*No suitable connections. + Open a new one.*/ + if(stream->free_head==NULL){ + /*All connections in use. + Expire one of them (we should have already picked which one when scanning + the list).*/ + OP_ASSERT(close_conn!=NULL); + OP_ASSERT(close_pnext!=NULL); + op_http_conn_close(stream,close_conn,close_pnext,1); + } + OP_ASSERT(stream->free_head!=NULL); + conn=stream->free_head; + /*If we can pipeline, only request a chunk of data. + If we're seeking now, there's a good chance we will want to seek again + soon, and this avoids committing this connection to reading the rest of + the stream. + Particularly with SSL or proxies, issuing a new request on the same + connection can be substantially faster than opening a new one. + This also limits the amount of data the server will blast at us on this + connection if we later seek elsewhere and start reading from a different + connection.*/ + ret=op_http_conn_open_pos(stream,conn,pos, + pipeline?OP_PIPELINE_CHUNK_SIZE:-1); + if(OP_UNLIKELY(ret<0)){ + op_http_conn_close(stream,conn,&stream->lru_head,1); + return -1; + } + return 0; +} + +static opus_int64 op_http_stream_tell(void *_stream){ + OpusHTTPStream *stream; + int ci; + stream=(OpusHTTPStream *)_stream; + ci=stream->cur_conni; + return ci<0?stream->pos:stream->conns[ci].pos; +} + +static int op_http_stream_close(void *_stream){ + OpusHTTPStream *stream; + stream=(OpusHTTPStream *)_stream; + if(OP_LIKELY(stream!=NULL)){ + op_http_stream_clear(stream); + _ogg_free(stream); + } + return 0; +} + +static const OpusFileCallbacks OP_HTTP_CALLBACKS={ + op_http_stream_read, + op_http_stream_seek, + op_http_stream_tell, + op_http_stream_close +}; +#endif + +void opus_server_info_init(OpusServerInfo *_info){ + _info->name=NULL; + _info->description=NULL; + _info->genre=NULL; + _info->url=NULL; + _info->server=NULL; + _info->content_type=NULL; + _info->bitrate_kbps=-1; + _info->is_public=-1; + _info->is_ssl=0; +} + +void opus_server_info_clear(OpusServerInfo *_info){ + _ogg_free(_info->content_type); + _ogg_free(_info->server); + _ogg_free(_info->url); + _ogg_free(_info->genre); + _ogg_free(_info->description); + _ogg_free(_info->name); +} + +/*The actual URL stream creation function. + This one isn't extensible like the application-level interface, but because + it isn't public, we're free to change it in the future.*/ +static void *op_url_stream_create_impl(OpusFileCallbacks *_cb,const char *_url, + int _skip_certificate_check,const char *_proxy_host,unsigned _proxy_port, + const char *_proxy_user,const char *_proxy_pass,OpusServerInfo *_info){ + const char *path; + /*Check to see if this is a valid file: URL.*/ + path=op_parse_file_url(_url); + if(path!=NULL){ + char *unescaped_path; + void *ret; + unescaped_path=op_string_dup(path); + if(OP_UNLIKELY(unescaped_path==NULL))return NULL; + ret=op_fopen(_cb,op_unescape_url_component(unescaped_path),"rb"); + _ogg_free(unescaped_path); + return ret; + } +#if defined(OP_ENABLE_HTTP) + /*If not, try http/https.*/ + else{ + OpusHTTPStream *stream; + int ret; + stream=(OpusHTTPStream *)_ogg_malloc(sizeof(*stream)); + if(OP_UNLIKELY(stream==NULL))return NULL; + op_http_stream_init(stream); + ret=op_http_stream_open(stream,_url,_skip_certificate_check, + _proxy_host,_proxy_port,_proxy_user,_proxy_pass,_info); + if(OP_UNLIKELY(ret<0)){ + op_http_stream_clear(stream); + _ogg_free(stream); + return NULL; + } + *_cb=*&OP_HTTP_CALLBACKS; + return stream; + } +#else + (void)_skip_certificate_check; + (void)_proxy_host; + (void)_proxy_port; + (void)_proxy_user; + (void)_proxy_pass; + (void)_info; + return NULL; +#endif +} + +/*The actual implementation of op_url_stream_vcreate(). + We have to do a careful dance here to avoid potential memory leaks if + OpusServerInfo is requested, since this function is also used by + op_vopen_url() and op_vtest_url(). + Even if this function succeeds, those functions might ultimately fail. + If they do, they should return without having touched the OpusServerInfo + passed by the application. + Therefore, if this function succeeds and OpusServerInfo is requested, the + actual info will be stored in *_info and a pointer to the application's + storage will be placed in *_pinfo. + If this function fails or if the application did not request OpusServerInfo, + *_pinfo will be NULL. + Our caller is responsible for copying *_info to **_pinfo if it ultimately + succeeds, or for clearing *_info if it ultimately fails.*/ +static void *op_url_stream_vcreate_impl(OpusFileCallbacks *_cb, + const char *_url,OpusServerInfo *_info,OpusServerInfo **_pinfo,va_list _ap){ + int skip_certificate_check; + const char *proxy_host; + opus_int32 proxy_port; + const char *proxy_user; + const char *proxy_pass; + OpusServerInfo *pinfo; + skip_certificate_check=0; + proxy_host=NULL; + proxy_port=8080; + proxy_user=NULL; + proxy_pass=NULL; + pinfo=NULL; + *_pinfo=NULL; + for(;;){ + ptrdiff_t request; + request=va_arg(_ap,char *)-(char *)NULL; + /*If we hit NULL, we're done processing options.*/ + if(!request)break; + switch(request){ + case OP_SSL_SKIP_CERTIFICATE_CHECK_REQUEST:{ + skip_certificate_check=!!va_arg(_ap,opus_int32); + }break; + case OP_HTTP_PROXY_HOST_REQUEST:{ + proxy_host=va_arg(_ap,const char *); + }break; + case OP_HTTP_PROXY_PORT_REQUEST:{ + proxy_port=va_arg(_ap,opus_int32); + if(proxy_port<0||proxy_port>(opus_int32)65535)return NULL; + }break; + case OP_HTTP_PROXY_USER_REQUEST:{ + proxy_user=va_arg(_ap,const char *); + }break; + case OP_HTTP_PROXY_PASS_REQUEST:{ + proxy_pass=va_arg(_ap,const char *); + }break; + case OP_GET_SERVER_INFO_REQUEST:{ + pinfo=va_arg(_ap,OpusServerInfo *); + }break; + /*Some unknown option.*/ + default:return NULL; + } + } + /*If the caller has requested server information, proxy it to a local copy to + simplify error handling.*/ + if(pinfo!=NULL){ + void *ret; + opus_server_info_init(_info); + ret=op_url_stream_create_impl(_cb,_url,skip_certificate_check, + proxy_host,proxy_port,proxy_user,proxy_pass,_info); + if(ret!=NULL)*_pinfo=pinfo; + else opus_server_info_clear(_info); + return ret; + } + return op_url_stream_create_impl(_cb,_url,skip_certificate_check, + proxy_host,proxy_port,proxy_user,proxy_pass,NULL); +} + +void *op_url_stream_vcreate(OpusFileCallbacks *_cb, + const char *_url,va_list _ap){ + OpusServerInfo info; + OpusServerInfo *pinfo; + void *ret; + ret=op_url_stream_vcreate_impl(_cb,_url,&info,&pinfo,_ap); + if(pinfo!=NULL)*pinfo=*&info; + return ret; +} + +void *op_url_stream_create(OpusFileCallbacks *_cb, + const char *_url,...){ + va_list ap; + void *ret; + va_start(ap,_url); + ret=op_url_stream_vcreate(_cb,_url,ap); + va_end(ap); + return ret; +} + +/*Convenience routines to open/test URLs in a single step.*/ + +OggOpusFile *op_vopen_url(const char *_url,int *_error,va_list _ap){ + OpusFileCallbacks cb; + OggOpusFile *of; + OpusServerInfo info; + OpusServerInfo *pinfo; + void *source; + source=op_url_stream_vcreate_impl(&cb,_url,&info,&pinfo,_ap); + if(OP_UNLIKELY(source==NULL)){ + OP_ASSERT(pinfo==NULL); + if(_error!=NULL)*_error=OP_EFAULT; + return NULL; + } + of=op_open_callbacks(source,&cb,NULL,0,_error); + if(OP_UNLIKELY(of==NULL)){ + if(pinfo!=NULL)opus_server_info_clear(&info); + (*cb.close)(source); + } + else if(pinfo!=NULL)*pinfo=*&info; + return of; +} + +OggOpusFile *op_open_url(const char *_url,int *_error,...){ + OggOpusFile *ret; + va_list ap; + va_start(ap,_error); + ret=op_vopen_url(_url,_error,ap); + va_end(ap); + return ret; +} + +OggOpusFile *op_vtest_url(const char *_url,int *_error,va_list _ap){ + OpusFileCallbacks cb; + OggOpusFile *of; + OpusServerInfo info; + OpusServerInfo *pinfo; + void *source; + source=op_url_stream_vcreate_impl(&cb,_url,&info,&pinfo,_ap); + if(OP_UNLIKELY(source==NULL)){ + OP_ASSERT(pinfo==NULL); + if(_error!=NULL)*_error=OP_EFAULT; + return NULL; + } + of=op_test_callbacks(source,&cb,NULL,0,_error); + if(OP_UNLIKELY(of==NULL)){ + if(pinfo!=NULL)opus_server_info_clear(&info); + (*cb.close)(source); + } + else if(pinfo!=NULL)*pinfo=*&info; + return of; +} + +OggOpusFile *op_test_url(const char *_url,int *_error,...){ + OggOpusFile *ret; + va_list ap; + va_start(ap,_error); + ret=op_vtest_url(_url,_error,ap); + va_end(ap); + return ret; +} diff --git a/extern/opusfile/src/info.c b/extern/opusfile/src/info.c new file mode 100644 index 0000000..3a1a5bf --- /dev/null +++ b/extern/opusfile/src/info.c @@ -0,0 +1,771 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE libopusfile SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE libopusfile SOURCE CODE IS (C) COPYRIGHT 2012 * + * by the Xiph.Org Foundation and contributors http://www.xiph.org/ * + * * + ********************************************************************/ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "internal.h" +#include +#include + +static unsigned op_parse_uint16le(const unsigned char *_data){ + return _data[0]|_data[1]<<8; +} + +static int op_parse_int16le(const unsigned char *_data){ + int ret; + ret=_data[0]|_data[1]<<8; + return (ret^0x8000)-0x8000; +} + +static opus_uint32 op_parse_uint32le(const unsigned char *_data){ + return _data[0]|(opus_uint32)_data[1]<<8| + (opus_uint32)_data[2]<<16|(opus_uint32)_data[3]<<24; +} + +static opus_uint32 op_parse_uint32be(const unsigned char *_data){ + return _data[3]|(opus_uint32)_data[2]<<8| + (opus_uint32)_data[1]<<16|(opus_uint32)_data[0]<<24; +} + +int opus_head_parse(OpusHead *_head,const unsigned char *_data,size_t _len){ + OpusHead head; + if(_len<8)return OP_ENOTFORMAT; + if(memcmp(_data,"OpusHead",8)!=0)return OP_ENOTFORMAT; + if(_len<9)return OP_EBADHEADER; + head.version=_data[8]; + if(head.version>15)return OP_EVERSION; + if(_len<19)return OP_EBADHEADER; + head.channel_count=_data[9]; + head.pre_skip=op_parse_uint16le(_data+10); + head.input_sample_rate=op_parse_uint32le(_data+12); + head.output_gain=op_parse_int16le(_data+16); + head.mapping_family=_data[18]; + if(head.mapping_family==0){ + if(head.channel_count<1||head.channel_count>2)return OP_EBADHEADER; + if(head.version<=1&&_len>19)return OP_EBADHEADER; + head.stream_count=1; + head.coupled_count=head.channel_count-1; + if(_head!=NULL){ + _head->mapping[0]=0; + _head->mapping[1]=1; + } + } + else if(head.mapping_family==1){ + size_t size; + int ci; + if(head.channel_count<1||head.channel_count>8)return OP_EBADHEADER; + size=21+head.channel_count; + if(_lensize)return OP_EBADHEADER; + head.stream_count=_data[19]; + if(head.stream_count<1)return OP_EBADHEADER; + head.coupled_count=_data[20]; + if(head.coupled_count>head.stream_count)return OP_EBADHEADER; + for(ci=0;ci=head.stream_count+head.coupled_count + &&_data[21+ci]!=255){ + return OP_EBADHEADER; + } + } + if(_head!=NULL)memcpy(_head->mapping,_data+21,head.channel_count); + } + /*General purpose players should not attempt to play back content with + channel mapping family 255.*/ + else if(head.mapping_family==255)return OP_EIMPL; + /*No other channel mapping families are currently defined.*/ + else return OP_EBADHEADER; + if(_head!=NULL)memcpy(_head,&head,head.mapping-(unsigned char *)&head); + return 0; +} + +void opus_tags_init(OpusTags *_tags){ + memset(_tags,0,sizeof(*_tags)); +} + +void opus_tags_clear(OpusTags *_tags){ + int ncomments; + int ci; + ncomments=_tags->comments; + if(_tags->user_comments!=NULL)ncomments++; + for(ci=ncomments;ci-->0;)_ogg_free(_tags->user_comments[ci]); + _ogg_free(_tags->user_comments); + _ogg_free(_tags->comment_lengths); + _ogg_free(_tags->vendor); +} + +/*Ensure there's room for up to _ncomments comments.*/ +static int op_tags_ensure_capacity(OpusTags *_tags,size_t _ncomments){ + char **user_comments; + int *comment_lengths; + int cur_ncomments; + size_t size; + if(OP_UNLIKELY(_ncomments>=(size_t)INT_MAX))return OP_EFAULT; + size=sizeof(*_tags->comment_lengths)*(_ncomments+1); + if(size/sizeof(*_tags->comment_lengths)!=_ncomments+1)return OP_EFAULT; + cur_ncomments=_tags->comments; + /*We only support growing. + Trimming requires cleaning up the allocated strings in the old space, and + is best handled separately if it's ever needed.*/ + OP_ASSERT(_ncomments>=(size_t)cur_ncomments); + comment_lengths=(int *)_ogg_realloc(_tags->comment_lengths,size); + if(OP_UNLIKELY(comment_lengths==NULL))return OP_EFAULT; + if(_tags->comment_lengths==NULL){ + OP_ASSERT(cur_ncomments==0); + comment_lengths[cur_ncomments]=0; + } + comment_lengths[_ncomments]=comment_lengths[cur_ncomments]; + _tags->comment_lengths=comment_lengths; + size=sizeof(*_tags->user_comments)*(_ncomments+1); + if(size/sizeof(*_tags->user_comments)!=_ncomments+1)return OP_EFAULT; + user_comments=(char **)_ogg_realloc(_tags->user_comments,size); + if(OP_UNLIKELY(user_comments==NULL))return OP_EFAULT; + if(_tags->user_comments==NULL){ + OP_ASSERT(cur_ncomments==0); + user_comments[cur_ncomments]=NULL; + } + user_comments[_ncomments]=user_comments[cur_ncomments]; + _tags->user_comments=user_comments; + return 0; +} + +/*Duplicate a (possibly non-NUL terminated) string with a known length.*/ +static char *op_strdup_with_len(const char *_s,size_t _len){ + size_t size; + char *ret; + size=sizeof(*ret)*(_len+1); + if(OP_UNLIKELY(size<_len))return NULL; + ret=(char *)_ogg_malloc(size); + if(OP_LIKELY(ret!=NULL)){ + ret=(char *)memcpy(ret,_s,sizeof(*ret)*_len); + ret[_len]='\0'; + } + return ret; +} + +/*The actual implementation of opus_tags_parse(). + Unlike the public API, this function requires _tags to already be + initialized, modifies its contents before success is guaranteed, and assumes + the caller will clear it on error.*/ +static int opus_tags_parse_impl(OpusTags *_tags, + const unsigned char *_data,size_t _len){ + opus_uint32 count; + size_t len; + int ncomments; + int ci; + len=_len; + if(len<8)return OP_ENOTFORMAT; + if(memcmp(_data,"OpusTags",8)!=0)return OP_ENOTFORMAT; + if(len<16)return OP_EBADHEADER; + _data+=8; + len-=8; + count=op_parse_uint32le(_data); + _data+=4; + len-=4; + if(count>len)return OP_EBADHEADER; + if(_tags!=NULL){ + _tags->vendor=op_strdup_with_len((char *)_data,count); + if(_tags->vendor==NULL)return OP_EFAULT; + } + _data+=count; + len-=count; + if(len<4)return OP_EBADHEADER; + count=op_parse_uint32le(_data); + _data+=4; + len-=4; + /*Check to make sure there's minimally sufficient data left in the packet.*/ + if(count>len>>2)return OP_EBADHEADER; + /*Check for overflow (the API limits this to an int).*/ + if(count>(opus_uint32)INT_MAX-1)return OP_EFAULT; + if(_tags!=NULL){ + int ret; + ret=op_tags_ensure_capacity(_tags,count); + if(ret<0)return ret; + } + ncomments=(int)count; + for(ci=0;cilen>>2)return OP_EBADHEADER; + count=op_parse_uint32le(_data); + _data+=4; + len-=4; + if(count>len)return OP_EBADHEADER; + /*Check for overflow (the API limits this to an int).*/ + if(count>(opus_uint32)INT_MAX)return OP_EFAULT; + if(_tags!=NULL){ + _tags->user_comments[ci]=op_strdup_with_len((char *)_data,count); + if(_tags->user_comments[ci]==NULL)return OP_EFAULT; + _tags->comment_lengths[ci]=(int)count; + _tags->comments=ci+1; + /*Needed by opus_tags_clear() if we fail before parsing the (optional) + binary metadata.*/ + _tags->user_comments[ci+1]=NULL; + } + _data+=count; + len-=count; + } + if(len>0&&(_data[0]&1)){ + if(len>(opus_uint32)INT_MAX)return OP_EFAULT; + if(_tags!=NULL){ + _tags->user_comments[ncomments]=(char *)_ogg_malloc(len); + if(OP_UNLIKELY(_tags->user_comments[ncomments]==NULL))return OP_EFAULT; + memcpy(_tags->user_comments[ncomments],_data,len); + _tags->comment_lengths[ncomments]=(int)len; + } + } + return 0; +} + +int opus_tags_parse(OpusTags *_tags,const unsigned char *_data,size_t _len){ + if(_tags!=NULL){ + OpusTags tags; + int ret; + opus_tags_init(&tags); + ret=opus_tags_parse_impl(&tags,_data,_len); + if(ret<0)opus_tags_clear(&tags); + else *_tags=*&tags; + return ret; + } + else return opus_tags_parse_impl(NULL,_data,_len); +} + +/*The actual implementation of opus_tags_copy(). + Unlike the public API, this function requires _dst to already be + initialized, modifies its contents before success is guaranteed, and assumes + the caller will clear it on error.*/ +static int opus_tags_copy_impl(OpusTags *_dst,const OpusTags *_src){ + char *vendor; + int ncomments; + int ret; + int ci; + vendor=_src->vendor; + _dst->vendor=op_strdup_with_len(vendor,strlen(vendor)); + if(OP_UNLIKELY(_dst->vendor==NULL))return OP_EFAULT; + ncomments=_src->comments; + ret=op_tags_ensure_capacity(_dst,ncomments); + if(OP_UNLIKELY(ret<0))return ret; + for(ci=0;cicomment_lengths[ci]; + OP_ASSERT(len>=0); + _dst->user_comments[ci]=op_strdup_with_len(_src->user_comments[ci],len); + if(OP_UNLIKELY(_dst->user_comments[ci]==NULL))return OP_EFAULT; + _dst->comment_lengths[ci]=len; + _dst->comments=ci+1; + } + if(_src->comment_lengths!=NULL){ + int len; + len=_src->comment_lengths[ncomments]; + if(len>0){ + _dst->user_comments[ncomments]=(char *)_ogg_malloc(len); + if(OP_UNLIKELY(_dst->user_comments[ncomments]==NULL))return OP_EFAULT; + memcpy(_dst->user_comments[ncomments],_src->user_comments[ncomments],len); + _dst->comment_lengths[ncomments]=len; + } + } + return 0; +} + +int opus_tags_copy(OpusTags *_dst,const OpusTags *_src){ + OpusTags dst; + int ret; + opus_tags_init(&dst); + ret=opus_tags_copy_impl(&dst,_src); + if(OP_UNLIKELY(ret<0))opus_tags_clear(&dst); + else *_dst=*&dst; + return ret; +} + +int opus_tags_add(OpusTags *_tags,const char *_tag,const char *_value){ + char *comment; + size_t tag_len; + size_t value_len; + int ncomments; + int ret; + ncomments=_tags->comments; + ret=op_tags_ensure_capacity(_tags,ncomments+1); + if(OP_UNLIKELY(ret<0))return ret; + tag_len=strlen(_tag); + value_len=strlen(_value); + /*+2 for '=' and '\0'.*/ + if(tag_len+value_len(size_t)INT_MAX-2)return OP_EFAULT; + comment=(char *)_ogg_malloc(sizeof(*comment)*(tag_len+value_len+2)); + if(OP_UNLIKELY(comment==NULL))return OP_EFAULT; + memcpy(comment,_tag,sizeof(*comment)*tag_len); + comment[tag_len]='='; + memcpy(comment+tag_len+1,_value,sizeof(*comment)*(value_len+1)); + _tags->user_comments[ncomments]=comment; + _tags->comment_lengths[ncomments]=(int)(tag_len+value_len+1); + _tags->comments=ncomments+1; + return 0; +} + +int opus_tags_add_comment(OpusTags *_tags,const char *_comment){ + char *comment; + int comment_len; + int ncomments; + int ret; + ncomments=_tags->comments; + ret=op_tags_ensure_capacity(_tags,ncomments+1); + if(OP_UNLIKELY(ret<0))return ret; + comment_len=(int)strlen(_comment); + comment=op_strdup_with_len(_comment,comment_len); + if(OP_UNLIKELY(comment==NULL))return OP_EFAULT; + _tags->user_comments[ncomments]=comment; + _tags->comment_lengths[ncomments]=comment_len; + _tags->comments=ncomments+1; + return 0; +} + +int opus_tags_set_binary_suffix(OpusTags *_tags, + const unsigned char *_data,int _len){ + unsigned char *binary_suffix_data; + int ncomments; + int ret; + if(_len<0||_len>0&&(_data==NULL||!(_data[0]&1)))return OP_EINVAL; + ncomments=_tags->comments; + ret=op_tags_ensure_capacity(_tags,ncomments); + if(OP_UNLIKELY(ret<0))return ret; + binary_suffix_data= + (unsigned char *)_ogg_realloc(_tags->user_comments[ncomments],_len); + if(OP_UNLIKELY(binary_suffix_data==NULL))return OP_EFAULT; + memcpy(binary_suffix_data,_data,_len); + _tags->user_comments[ncomments]=(char *)binary_suffix_data; + _tags->comment_lengths[ncomments]=_len; + return 0; +} + +int opus_tagcompare(const char *_tag_name,const char *_comment){ + size_t tag_len; + tag_len=strlen(_tag_name); + if(OP_UNLIKELY(tag_len>(size_t)INT_MAX))return -1; + return opus_tagncompare(_tag_name,(int)tag_len,_comment); +} + +int opus_tagncompare(const char *_tag_name,int _tag_len,const char *_comment){ + int ret; + OP_ASSERT(_tag_len>=0); + ret=op_strncasecmp(_tag_name,_comment,_tag_len); + return ret?ret:'='-_comment[_tag_len]; +} + +const char *opus_tags_query(const OpusTags *_tags,const char *_tag,int _count){ + char **user_comments; + size_t tag_len; + int found; + int ncomments; + int ci; + tag_len=strlen(_tag); + if(OP_UNLIKELY(tag_len>(size_t)INT_MAX))return NULL; + ncomments=_tags->comments; + user_comments=_tags->user_comments; + found=0; + for(ci=0;ci(size_t)INT_MAX))return 0; + ncomments=_tags->comments; + user_comments=_tags->user_comments; + found=0; + for(ci=0;cicomments; + len=_tags->comment_lengths==NULL?0:_tags->comment_lengths[ncomments]; + *_len=len; + OP_ASSERT(len==0||_tags->user_comments!=NULL); + return len>0?(const unsigned char *)_tags->user_comments[ncomments]:NULL; +} + +static int opus_tags_get_gain(const OpusTags *_tags,int *_gain_q8, + const char *_tag_name,size_t _tag_len){ + char **comments; + int ncomments; + int ci; + comments=_tags->user_comments; + ncomments=_tags->comments; + /*Look for the first valid tag with the name _tag_name and use that.*/ + for(ci=0;ci='0'&&*p<='9'){ + gain_q8=10*gain_q8+*p-'0'; + if(gain_q8>32767-negative)break; + p++; + } + /*This didn't look like a signed 16-bit decimal integer. + Not a valid gain tag.*/ + if(*p!='\0')continue; + *_gain_q8=(int)(gain_q8+negative^negative); + return 0; + } + } + return OP_FALSE; +} + +int opus_tags_get_album_gain(const OpusTags *_tags,int *_gain_q8){ + return opus_tags_get_gain(_tags,_gain_q8,"R128_ALBUM_GAIN",15); +} + +int opus_tags_get_track_gain(const OpusTags *_tags,int *_gain_q8){ + return opus_tags_get_gain(_tags,_gain_q8,"R128_TRACK_GAIN",15); +} + +static int op_is_jpeg(const unsigned char *_buf,size_t _buf_sz){ + return _buf_sz>=3&&memcmp(_buf,"\xFF\xD8\xFF",3)==0; +} + +/*Tries to extract the width, height, bits per pixel, and palette size of a + JPEG. + On failure, simply leaves its outputs unmodified.*/ +static void op_extract_jpeg_params(const unsigned char *_buf,size_t _buf_sz, + opus_uint32 *_width,opus_uint32 *_height, + opus_uint32 *_depth,opus_uint32 *_colors,int *_has_palette){ + if(op_is_jpeg(_buf,_buf_sz)){ + size_t offs; + offs=2; + for(;;){ + size_t segment_len; + int marker; + while(offs<_buf_sz&&_buf[offs]!=0xFF)offs++; + while(offs<_buf_sz&&_buf[offs]==0xFF)offs++; + marker=_buf[offs]; + offs++; + /*If we hit EOI* (end of image), or another SOI* (start of image), + or SOS (start of scan), then stop now.*/ + if(offs>=_buf_sz||(marker>=0xD8&&marker<=0xDA))break; + /*RST* (restart markers): skip (no segment length).*/ + else if(marker>=0xD0&&marker<=0xD7)continue; + /*Read the length of the marker segment.*/ + if(_buf_sz-offs<2)break; + segment_len=_buf[offs]<<8|_buf[offs+1]; + if(segment_len<2||_buf_sz-offs0xC0&&marker<0xD0&&(marker&3)!=0)){ + /*Found a SOFn (start of frame) marker segment:*/ + if(segment_len>=8){ + *_height=_buf[offs+3]<<8|_buf[offs+4]; + *_width=_buf[offs+5]<<8|_buf[offs+6]; + *_depth=_buf[offs+2]*_buf[offs+7]; + *_colors=0; + *_has_palette=0; + } + break; + } + /*Other markers: skip the whole marker segment.*/ + offs+=segment_len; + } + } +} + +static int op_is_png(const unsigned char *_buf,size_t _buf_sz){ + return _buf_sz>=8&&memcmp(_buf,"\x89PNG\x0D\x0A\x1A\x0A",8)==0; +} + +/*Tries to extract the width, height, bits per pixel, and palette size of a + PNG. + On failure, simply leaves its outputs unmodified.*/ +static void op_extract_png_params(const unsigned char *_buf,size_t _buf_sz, + opus_uint32 *_width,opus_uint32 *_height, + opus_uint32 *_depth,opus_uint32 *_colors,int *_has_palette){ + if(op_is_png(_buf,_buf_sz)){ + size_t offs; + offs=8; + while(_buf_sz-offs>=12){ + ogg_uint32_t chunk_len; + chunk_len=op_parse_uint32be(_buf+offs); + if(chunk_len>_buf_sz-(offs+12))break; + else if(chunk_len==13&&memcmp(_buf+offs+4,"IHDR",4)==0){ + int color_type; + *_width=op_parse_uint32be(_buf+offs+8); + *_height=op_parse_uint32be(_buf+offs+12); + color_type=_buf[offs+17]; + if(color_type==3){ + *_depth=24; + *_has_palette=1; + } + else{ + int sample_depth; + sample_depth=_buf[offs+16]; + if(color_type==0)*_depth=sample_depth; + else if(color_type==2)*_depth=sample_depth*3; + else if(color_type==4)*_depth=sample_depth*2; + else if(color_type==6)*_depth=sample_depth*4; + *_colors=0; + *_has_palette=0; + break; + } + } + else if(*_has_palette>0&&memcmp(_buf+offs+4,"PLTE",4)==0){ + *_colors=chunk_len/3; + break; + } + offs+=12+chunk_len; + } + } +} + +static int op_is_gif(const unsigned char *_buf,size_t _buf_sz){ + return _buf_sz>=6&&(memcmp(_buf,"GIF87a",6)==0||memcmp(_buf,"GIF89a",6)==0); +} + +/*Tries to extract the width, height, bits per pixel, and palette size of a + GIF. + On failure, simply leaves its outputs unmodified.*/ +static void op_extract_gif_params(const unsigned char *_buf,size_t _buf_sz, + opus_uint32 *_width,opus_uint32 *_height, + opus_uint32 *_depth,opus_uint32 *_colors,int *_has_palette){ + if(op_is_gif(_buf,_buf_sz)&&_buf_sz>=14){ + *_width=_buf[6]|_buf[7]<<8; + *_height=_buf[8]|_buf[9]<<8; + /*libFLAC hard-codes the depth to 24.*/ + *_depth=24; + *_colors=1<<((_buf[10]&7)+1); + *_has_palette=1; + } +} + +/*The actual implementation of opus_picture_tag_parse(). + Unlike the public API, this function requires _pic to already be + initialized, modifies its contents before success is guaranteed, and assumes + the caller will clear it on error.*/ +static int opus_picture_tag_parse_impl(OpusPictureTag *_pic,const char *_tag, + unsigned char *_buf,size_t _buf_sz,size_t _base64_sz){ + opus_int32 picture_type; + opus_uint32 mime_type_length; + char *mime_type; + opus_uint32 description_length; + char *description; + opus_uint32 width; + opus_uint32 height; + opus_uint32 depth; + opus_uint32 colors; + opus_uint32 data_length; + opus_uint32 file_width; + opus_uint32 file_height; + opus_uint32 file_depth; + opus_uint32 file_colors; + int format; + int has_palette; + int colors_set; + size_t i; + /*Decode the BASE64 data.*/ + for(i=0;i<_base64_sz;i++){ + opus_uint32 value; + int j; + value=0; + for(j=0;j<4;j++){ + unsigned c; + unsigned d; + c=(unsigned char)_tag[4*i+j]; + if(c=='+')d=62; + else if(c=='/')d=63; + else if(c>='0'&&c<='9')d=52+c-'0'; + else if(c>='a'&&c<='z')d=26+c-'a'; + else if(c>='A'&&c<='Z')d=c-'A'; + else if(c=='='&&3*i+j>_buf_sz)d=0; + else return OP_ENOTFORMAT; + value=value<<6|d; + } + _buf[3*i]=(unsigned char)(value>>16); + if(3*i+1<_buf_sz){ + _buf[3*i+1]=(unsigned char)(value>>8); + if(3*i+2<_buf_sz)_buf[3*i+2]=(unsigned char)value; + } + } + i=0; + picture_type=op_parse_uint32be(_buf+i); + i+=4; + /*Extract the MIME type.*/ + mime_type_length=op_parse_uint32be(_buf+i); + i+=4; + if(mime_type_length>_buf_sz-32)return OP_ENOTFORMAT; + mime_type=(char *)_ogg_malloc(sizeof(*_pic->mime_type)*(mime_type_length+1)); + if(mime_type==NULL)return OP_EFAULT; + memcpy(mime_type,_buf+i,sizeof(*mime_type)*mime_type_length); + mime_type[mime_type_length]='\0'; + _pic->mime_type=mime_type; + i+=mime_type_length; + /*Extract the description string.*/ + description_length=op_parse_uint32be(_buf+i); + i+=4; + if(description_length>_buf_sz-mime_type_length-32)return OP_ENOTFORMAT; + description= + (char *)_ogg_malloc(sizeof(*_pic->mime_type)*(description_length+1)); + if(description==NULL)return OP_EFAULT; + memcpy(description,_buf+i,sizeof(*description)*description_length); + description[description_length]='\0'; + _pic->description=description; + i+=description_length; + /*Extract the remaining fields.*/ + width=op_parse_uint32be(_buf+i); + i+=4; + height=op_parse_uint32be(_buf+i); + i+=4; + depth=op_parse_uint32be(_buf+i); + i+=4; + colors=op_parse_uint32be(_buf+i); + i+=4; + /*If one of these is set, they all must be, but colors==0 is a valid value.*/ + colors_set=width!=0||height!=0||depth!=0||colors!=0; + if((width==0||height==0||depth==0)&&colors_set)return OP_ENOTFORMAT; + data_length=op_parse_uint32be(_buf+i); + i+=4; + if(data_length>_buf_sz-i)return OP_ENOTFORMAT; + /*Trim extraneous data so we don't copy it below.*/ + _buf_sz=i+data_length; + /*Attempt to determine the image format.*/ + format=OP_PIC_FORMAT_UNKNOWN; + if(mime_type_length==3&&strcmp(mime_type,"-->")==0){ + format=OP_PIC_FORMAT_URL; + /*Picture type 1 must be a 32x32 PNG.*/ + if(picture_type==1&&(width!=0||height!=0)&&(width!=32||height!=32)){ + return OP_ENOTFORMAT; + } + /*Append a terminating NUL for the convenience of our callers.*/ + _buf[_buf_sz++]='\0'; + } + else{ + if(mime_type_length==10 + &&op_strncasecmp(mime_type,"image/jpeg",mime_type_length)==0){ + if(op_is_jpeg(_buf+i,data_length))format=OP_PIC_FORMAT_JPEG; + } + else if(mime_type_length==9 + &&op_strncasecmp(mime_type,"image/png",mime_type_length)==0){ + if(op_is_png(_buf+i,data_length))format=OP_PIC_FORMAT_PNG; + } + else if(mime_type_length==9 + &&op_strncasecmp(mime_type,"image/gif",mime_type_length)==0){ + if(op_is_gif(_buf+i,data_length))format=OP_PIC_FORMAT_GIF; + } + else if(mime_type_length==0||(mime_type_length==6 + &&op_strncasecmp(mime_type,"image/",mime_type_length)==0)){ + if(op_is_jpeg(_buf+i,data_length))format=OP_PIC_FORMAT_JPEG; + else if(op_is_png(_buf+i,data_length))format=OP_PIC_FORMAT_PNG; + else if(op_is_gif(_buf+i,data_length))format=OP_PIC_FORMAT_GIF; + } + file_width=file_height=file_depth=file_colors=0; + has_palette=-1; + switch(format){ + case OP_PIC_FORMAT_JPEG:{ + op_extract_jpeg_params(_buf+i,data_length, + &file_width,&file_height,&file_depth,&file_colors,&has_palette); + }break; + case OP_PIC_FORMAT_PNG:{ + op_extract_png_params(_buf+i,data_length, + &file_width,&file_height,&file_depth,&file_colors,&has_palette); + }break; + case OP_PIC_FORMAT_GIF:{ + op_extract_gif_params(_buf+i,data_length, + &file_width,&file_height,&file_depth,&file_colors,&has_palette); + }break; + } + if(has_palette>=0){ + /*If we successfully extracted these parameters from the image, override + any declared values.*/ + width=file_width; + height=file_height; + depth=file_depth; + colors=file_colors; + } + /*Picture type 1 must be a 32x32 PNG.*/ + if(picture_type==1&&(format!=OP_PIC_FORMAT_PNG||width!=32||height!=32)){ + return OP_ENOTFORMAT; + } + } + /*Adjust _buf_sz instead of using data_length to capture the terminating NUL + for URLs.*/ + _buf_sz-=i; + memmove(_buf,_buf+i,sizeof(*_buf)*_buf_sz); + _buf=(unsigned char *)_ogg_realloc(_buf,_buf_sz); + if(_buf_sz>0&&_buf==NULL)return OP_EFAULT; + _pic->type=picture_type; + _pic->width=width; + _pic->height=height; + _pic->depth=depth; + _pic->colors=colors; + _pic->data_length=data_length; + _pic->data=_buf; + _pic->format=format; + return 0; +} + +int opus_picture_tag_parse(OpusPictureTag *_pic,const char *_tag){ + OpusPictureTag pic; + unsigned char *buf; + size_t base64_sz; + size_t buf_sz; + size_t tag_length; + int ret; + if(opus_tagncompare("METADATA_BLOCK_PICTURE",22,_tag)==0)_tag+=23; + /*Figure out how much BASE64-encoded data we have.*/ + tag_length=strlen(_tag); + if(tag_length&3)return OP_ENOTFORMAT; + base64_sz=tag_length>>2; + buf_sz=3*base64_sz; + if(buf_sz<32)return OP_ENOTFORMAT; + if(_tag[tag_length-1]=='=')buf_sz--; + if(_tag[tag_length-2]=='=')buf_sz--; + if(buf_sz<32)return OP_ENOTFORMAT; + /*Allocate an extra byte to allow appending a terminating NUL to URL data.*/ + buf=(unsigned char *)_ogg_malloc(sizeof(*buf)*(buf_sz+1)); + if(buf==NULL)return OP_EFAULT; + opus_picture_tag_init(&pic); + ret=opus_picture_tag_parse_impl(&pic,_tag,buf,buf_sz,base64_sz); + if(ret<0){ + opus_picture_tag_clear(&pic); + _ogg_free(buf); + } + else *_pic=*&pic; + return ret; +} + +void opus_picture_tag_init(OpusPictureTag *_pic){ + memset(_pic,0,sizeof(*_pic)); +} + +void opus_picture_tag_clear(OpusPictureTag *_pic){ + _ogg_free(_pic->description); + _ogg_free(_pic->mime_type); + _ogg_free(_pic->data); +} diff --git a/extern/opusfile/src/internal.c b/extern/opusfile/src/internal.c new file mode 100644 index 0000000..96c80de --- /dev/null +++ b/extern/opusfile/src/internal.c @@ -0,0 +1,42 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE libopusfile SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE libopusfile SOURCE CODE IS (C) COPYRIGHT 2012 * + * by the Xiph.Org Foundation and contributors http://www.xiph.org/ * + * * + ********************************************************************/ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "internal.h" + +#if defined(OP_ENABLE_ASSERTIONS) +void op_fatal_impl(const char *_str,const char *_file,int _line){ + fprintf(stderr,"Fatal (internal) error in %s, line %i: %s\n", + _file,_line,_str); + abort(); +} +#endif + +/*A version of strncasecmp() that is guaranteed to only ignore the case of + ASCII characters.*/ +int op_strncasecmp(const char *_a,const char *_b,int _n){ + int i; + for(i=0;i<_n;i++){ + int a; + int b; + int d; + a=_a[i]; + b=_b[i]; + if(a>='a'&&a<='z')a-='a'-'A'; + if(b>='a'&&b<='z')b-='a'-'A'; + d=a-b; + if(d)return d; + } + return 0; +} diff --git a/extern/opusfile/src/internal.h b/extern/opusfile/src/internal.h new file mode 100644 index 0000000..9ac17e0 --- /dev/null +++ b/extern/opusfile/src/internal.h @@ -0,0 +1,259 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE libopusfile SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE libopusfile SOURCE CODE IS (C) COPYRIGHT 2012 * + * by the Xiph.Org Foundation and contributors http://www.xiph.org/ * + * * + ********************************************************************/ +#if !defined(_opusfile_internal_h) +# define _opusfile_internal_h (1) + +# if !defined(_REENTRANT) +# define _REENTRANT +# endif +# if !defined(_GNU_SOURCE) +# define _GNU_SOURCE +# endif +# if !defined(_LARGEFILE_SOURCE) +# define _LARGEFILE_SOURCE +# endif +# if !defined(_LARGEFILE64_SOURCE) +# define _LARGEFILE64_SOURCE +# endif +# if !defined(_FILE_OFFSET_BITS) +# define _FILE_OFFSET_BITS 64 +# endif + +# include +# include + +typedef struct OggOpusLink OggOpusLink; + +# if defined(OP_FIXED_POINT) + +typedef opus_int16 op_sample; + +# else + +typedef float op_sample; + +/*We're using this define to test for libopus 1.1 or later until libopus + provides a better mechanism.*/ +# if defined(OPUS_GET_EXPERT_FRAME_DURATION_REQUEST) +/*Enable soft clipping prevention in 16-bit decodes.*/ +# define OP_SOFT_CLIP (1) +# endif + +# endif + +# if OP_GNUC_PREREQ(4,2) +/*Disable excessive warnings about the order of operations.*/ +# pragma GCC diagnostic ignored "-Wparentheses" +# elif defined(_MSC_VER) +/*Disable excessive warnings about the order of operations.*/ +# pragma warning(disable:4554) +/*Disable warnings about "deprecated" POSIX functions.*/ +# pragma warning(disable:4996) +# endif + +# if OP_GNUC_PREREQ(3,0) +/*Another alternative is + (__builtin_constant_p(_x)?!!(_x):__builtin_expect(!!(_x),1)) + but that evaluates _x multiple times, which may be bad.*/ +# define OP_LIKELY(_x) (__builtin_expect(!!(_x),1)) +# define OP_UNLIKELY(_x) (__builtin_expect(!!(_x),0)) +# else +# define OP_LIKELY(_x) (!!(_x)) +# define OP_UNLIKELY(_x) (!!(_x)) +# endif + +# if defined(OP_ENABLE_ASSERTIONS) +# if OP_GNUC_PREREQ(2,5)||__SUNPRO_C>=0x590 +__attribute__((noreturn)) +# endif +void op_fatal_impl(const char *_str,const char *_file,int _line); + +# define OP_FATAL(_str) (op_fatal_impl(_str,__FILE__,__LINE__)) + +# define OP_ASSERT(_cond) \ + do{ \ + if(OP_UNLIKELY(!(_cond)))OP_FATAL("assertion failed: " #_cond); \ + } \ + while(0) +# define OP_ALWAYS_TRUE(_cond) OP_ASSERT(_cond) + +# else +# define OP_FATAL(_str) abort() +# define OP_ASSERT(_cond) +# define OP_ALWAYS_TRUE(_cond) ((void)(_cond)) +# endif + +# define OP_INT64_MAX (2*(((ogg_int64_t)1<<62)-1)|1) +# define OP_INT64_MIN (-OP_INT64_MAX-1) +# define OP_INT32_MAX (2*(((ogg_int32_t)1<<30)-1)|1) +# define OP_INT32_MIN (-OP_INT32_MAX-1) + +# define OP_MIN(_a,_b) ((_a)<(_b)?(_a):(_b)) +# define OP_MAX(_a,_b) ((_a)>(_b)?(_a):(_b)) +# define OP_CLAMP(_lo,_x,_hi) (OP_MAX(_lo,OP_MIN(_x,_hi))) + +/*Advance a file offset by the given amount, clamping against OP_INT64_MAX. + This is used to advance a known offset by things like OP_CHUNK_SIZE or + OP_PAGE_SIZE_MAX, while making sure to avoid signed overflow. + It assumes that both _offset and _amount are non-negative.*/ +#define OP_ADV_OFFSET(_offset,_amount) \ + (OP_MIN(_offset,OP_INT64_MAX-(_amount))+(_amount)) + +/*The maximum channel count for any mapping we'll actually decode.*/ +# define OP_NCHANNELS_MAX (8) + +/*Initial state.*/ +# define OP_NOTOPEN (0) +/*We've found the first Opus stream in the first link.*/ +# define OP_PARTOPEN (1) +# define OP_OPENED (2) +/*We've found the first Opus stream in the current link.*/ +# define OP_STREAMSET (3) +/*We've initialized the decoder for the chosen Opus stream in the current + link.*/ +# define OP_INITSET (4) + +/*Information cached for a single link in a chained Ogg Opus file. + We choose the first Opus stream encountered in each link to play back (and + require at least one).*/ +struct OggOpusLink{ + /*The byte offset of the first header page in this link.*/ + opus_int64 offset; + /*The byte offset of the first data page from the chosen Opus stream in this + link (after the headers).*/ + opus_int64 data_offset; + /*The byte offset of the last page from the chosen Opus stream in this link. + This is used when seeking to ensure we find a page before the last one, so + that end-trimming calculations work properly. + This is only valid for seekable sources.*/ + opus_int64 end_offset; + /*The total duration of all prior links. + This is always zero for non-seekable sources.*/ + ogg_int64_t pcm_file_offset; + /*The granule position of the last sample. + This is only valid for seekable sources.*/ + ogg_int64_t pcm_end; + /*The granule position before the first sample.*/ + ogg_int64_t pcm_start; + /*The serial number.*/ + ogg_uint32_t serialno; + /*The contents of the info header.*/ + OpusHead head; + /*The contents of the comment header.*/ + OpusTags tags; +}; + +struct OggOpusFile{ + /*The callbacks used to access the stream.*/ + OpusFileCallbacks callbacks; + /*A FILE *, memory buffer, etc.*/ + void *stream; + /*Whether or not we can seek with this stream.*/ + int seekable; + /*The number of links in this chained Ogg Opus file.*/ + int nlinks; + /*The cached information from each link in a chained Ogg Opus file. + If stream isn't seekable (e.g., it's a pipe), only the current link + appears.*/ + OggOpusLink *links; + /*The number of serial numbers from a single link.*/ + int nserialnos; + /*The capacity of the list of serial numbers from a single link.*/ + int cserialnos; + /*Storage for the list of serial numbers from a single link. + This is a scratch buffer used when scanning the BOS pages at the start of + each link.*/ + ogg_uint32_t *serialnos; + /*This is the current offset of the data processed by the ogg_sync_state. + After a seek, this should be set to the target offset so that we can track + the byte offsets of subsequent pages. + After a call to op_get_next_page(), this will point to the first byte after + that page.*/ + opus_int64 offset; + /*The total size of this stream, or -1 if it's unseekable.*/ + opus_int64 end; + /*Used to locate pages in the stream.*/ + ogg_sync_state oy; + /*One of OP_NOTOPEN, OP_PARTOPEN, OP_OPENED, OP_STREAMSET, OP_INITSET.*/ + int ready_state; + /*The current link being played back.*/ + int cur_link; + /*The number of decoded samples to discard from the start of decoding.*/ + opus_int32 cur_discard_count; + /*The granule position of the previous packet (current packet start time).*/ + ogg_int64_t prev_packet_gp; + /*The stream offset of the most recent page with completed packets, or -1. + This is only needed to recover continued packet data in the seeking logic, + when we use the current position as one of our bounds, only to later + discover it was the correct starting point.*/ + opus_int64 prev_page_offset; + /*The number of bytes read since the last bitrate query, including framing.*/ + opus_int64 bytes_tracked; + /*The number of samples decoded since the last bitrate query.*/ + ogg_int64_t samples_tracked; + /*Takes physical pages and welds them into a logical stream of packets.*/ + ogg_stream_state os; + /*Re-timestamped packets from a single page. + Buffering these relies on the undocumented libogg behavior that ogg_packet + pointers remain valid until the next page is submitted to the + ogg_stream_state they came from.*/ + ogg_packet op[255]; + /*The index of the next packet to return.*/ + int op_pos; + /*The total number of packets available.*/ + int op_count; + /*Central working state for the packet-to-PCM decoder.*/ + OpusMSDecoder *od; + /*The application-provided packet decode callback.*/ + op_decode_cb_func decode_cb; + /*The application-provided packet decode callback context.*/ + void *decode_cb_ctx; + /*The stream count used to initialize the decoder.*/ + int od_stream_count; + /*The coupled stream count used to initialize the decoder.*/ + int od_coupled_count; + /*The channel count used to initialize the decoder.*/ + int od_channel_count; + /*The channel mapping used to initialize the decoder.*/ + unsigned char od_mapping[OP_NCHANNELS_MAX]; + /*The buffered data for one decoded packet.*/ + op_sample *od_buffer; + /*The current position in the decoded buffer.*/ + int od_buffer_pos; + /*The number of valid samples in the decoded buffer.*/ + int od_buffer_size; + /*The type of gain offset to apply. + One of OP_HEADER_GAIN, OP_ALBUM_GAIN, OP_TRACK_GAIN, or OP_ABSOLUTE_GAIN.*/ + int gain_type; + /*The offset to apply to the gain.*/ + opus_int32 gain_offset_q8; + /*Internal state for soft clipping and dithering float->short output.*/ +#if !defined(OP_FIXED_POINT) +# if defined(OP_SOFT_CLIP) + float clip_state[OP_NCHANNELS_MAX]; +# endif + float dither_a[OP_NCHANNELS_MAX*4]; + float dither_b[OP_NCHANNELS_MAX*4]; + opus_uint32 dither_seed; + int dither_mute; + int dither_disabled; + /*The number of channels represented by the internal state. + This gets set to 0 whenever anything that would prevent state propagation + occurs (switching between the float/short APIs, or between the + stereo/multistream APIs).*/ + int state_channel_count; +#endif +}; + +int op_strncasecmp(const char *_a,const char *_b,int _n); + +#endif diff --git a/extern/opusfile/src/opusfile.c b/extern/opusfile/src/opusfile.c new file mode 100644 index 0000000..8b000a2 --- /dev/null +++ b/extern/opusfile/src/opusfile.c @@ -0,0 +1,3326 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE libopusfile SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE libopusfile SOURCE CODE IS (C) COPYRIGHT 1994-2012 * + * by the Xiph.Org Foundation and contributors http://www.xiph.org/ * + * * + ******************************************************************** + + function: stdio-based convenience library for opening/seeking/decoding + last mod: $Id: vorbisfile.c 17573 2010-10-27 14:53:59Z xiphmont $ + + ********************************************************************/ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "internal.h" +#include +#include +#include +#include +#include +#include + +#include "opusfile.h" + +/*This implementation is largely based off of libvorbisfile. + All of the Ogg bits work roughly the same, though I have made some + "improvements" that have not been folded back there, yet.*/ + +/*A 'chained bitstream' is an Ogg Opus bitstream that contains more than one + logical bitstream arranged end to end (the only form of Ogg multiplexing + supported by this library. + Grouping (parallel multiplexing) is not supported, except to the extent that + if there are multiple logical Ogg streams in a single link of the chain, we + will ignore all but the first Opus stream we find.*/ + +/*An Ogg Opus file can be played beginning to end (streamed) without worrying + ahead of time about chaining (see opusdec from the opus-tools package). + If we have the whole file, however, and want random access + (seeking/scrubbing) or desire to know the total length/time of a file, we + need to account for the possibility of chaining.*/ + +/*We can handle things a number of ways. + We can determine the entire bitstream structure right off the bat, or find + pieces on demand. + This library determines and caches structure for the entire bitstream, but + builds a virtual decoder on the fly when moving between links in the chain.*/ + +/*There are also different ways to implement seeking. + Enough information exists in an Ogg bitstream to seek to sample-granularity + positions in the output. + Or, one can seek by picking some portion of the stream roughly in the desired + area if we only want coarse navigation through the stream. + We implement and expose both strategies.*/ + +/*The maximum number of bytes in a page (including the page headers).*/ +#define OP_PAGE_SIZE_MAX (65307) +/*The default amount to seek backwards per step when trying to find the + previous page. + This must be at least as large as the maximum size of a page.*/ +#define OP_CHUNK_SIZE (65536) +/*The maximum amount to seek backwards per step when trying to find the + previous page.*/ +#define OP_CHUNK_SIZE_MAX (1024*(opus_int32)1024) +/*A smaller read size is needed for low-rate streaming.*/ +#define OP_READ_SIZE (2048) + +int op_test(OpusHead *_head, + const unsigned char *_initial_data,size_t _initial_bytes){ + ogg_sync_state oy; + char *data; + int err; + /*The first page of a normal Opus file will be at most 57 bytes (27 Ogg + page header bytes + 1 lacing value + 21 Opus header bytes + 8 channel + mapping bytes). + It will be at least 47 bytes (27 Ogg page header bytes + 1 lacing value + + 19 Opus header bytes using channel mapping family 0). + If we don't have at least that much data, give up now.*/ + if(_initial_bytes<47)return OP_FALSE; + /*Only proceed if we start with the magic OggS string. + This is to prevent us spending a lot of time allocating memory and looking + for Ogg pages in non-Ogg files.*/ + if(memcmp(_initial_data,"OggS",4)!=0)return OP_ENOTFORMAT; + if(OP_UNLIKELY(_initial_bytes>(size_t)LONG_MAX))return OP_EFAULT; + ogg_sync_init(&oy); + data=ogg_sync_buffer(&oy,(long)_initial_bytes); + if(data!=NULL){ + ogg_stream_state os; + ogg_page og; + int ret; + memcpy(data,_initial_data,_initial_bytes); + ogg_sync_wrote(&oy,(long)_initial_bytes); + ogg_stream_init(&os,-1); + err=OP_FALSE; + do{ + ogg_packet op; + ret=ogg_sync_pageout(&oy,&og); + /*Ignore holes.*/ + if(ret<0)continue; + /*Stop if we run out of data.*/ + if(!ret)break; + ogg_stream_reset_serialno(&os,ogg_page_serialno(&og)); + ogg_stream_pagein(&os,&og); + /*Only process the first packet on this page (if it's a BOS packet, + it's required to be the only one).*/ + if(ogg_stream_packetout(&os,&op)==1){ + if(op.b_o_s){ + ret=opus_head_parse(_head,op.packet,op.bytes); + /*If this didn't look like Opus, keep going.*/ + if(ret==OP_ENOTFORMAT)continue; + /*Otherwise we're done, one way or another.*/ + err=ret; + } + /*We finished parsing the headers. + There is no Opus to be found.*/ + else err=OP_ENOTFORMAT; + } + } + while(err==OP_FALSE); + ogg_stream_clear(&os); + } + else err=OP_EFAULT; + ogg_sync_clear(&oy); + return err; +} + +/*Many, many internal helpers. + The intention is not to be confusing. + Rampant duplication and monolithic function implementation (though we do have + some large, omnibus functions still) would be harder to understand anyway. + The high level functions are last. + Begin grokking near the end of the file if you prefer to read things + top-down.*/ + +/*The read/seek functions track absolute position within the stream.*/ + +/*Read a little more data from the file/pipe into the ogg_sync framer. + _nbytes: The maximum number of bytes to read. + Return: A positive number of bytes read on success, 0 on end-of-file, or a + negative value on failure.*/ +static int op_get_data(OggOpusFile *_of,int _nbytes){ + unsigned char *buffer; + int nbytes; + OP_ASSERT(_nbytes>0); + buffer=(unsigned char *)ogg_sync_buffer(&_of->oy,_nbytes); + nbytes=(int)(*_of->callbacks.read)(_of->stream,buffer,_nbytes); + OP_ASSERT(nbytes<=_nbytes); + if(OP_LIKELY(nbytes>0))ogg_sync_wrote(&_of->oy,nbytes); + return nbytes; +} + +/*Save a tiny smidge of verbosity to make the code more readable.*/ +static int op_seek_helper(OggOpusFile *_of,opus_int64 _offset){ + if(_offset==_of->offset)return 0; + if(_of->callbacks.seek==NULL + ||(*_of->callbacks.seek)(_of->stream,_offset,SEEK_SET)){ + return OP_EREAD; + } + _of->offset=_offset; + ogg_sync_reset(&_of->oy); + return 0; +} + +/*Get the current position indicator of the underlying stream. + This should be the same as the value reported by tell().*/ +static opus_int64 op_position(const OggOpusFile *_of){ + /*The current position indicator is _not_ simply offset. + We may also have unprocessed, buffered data in the sync state.*/ + return _of->offset+_of->oy.fill-_of->oy.returned; +} + +/*From the head of the stream, get the next page. + _boundary specifies if the function is allowed to fetch more data from the + stream (and how much) or only use internally buffered data. + _boundary: -1: Unbounded search. + 0: Read no additional data. + Use only cached data. + n: Search for the start of a new page up to file position n. + Return: n>=0: Found a page at absolute offset n. + OP_FALSE: Hit the _boundary limit. + OP_EREAD: An underlying read operation failed. + OP_BADLINK: We hit end-of-file before reaching _boundary.*/ +static opus_int64 op_get_next_page(OggOpusFile *_of,ogg_page *_og, + opus_int64 _boundary){ + while(_boundary<=0||_of->offset<_boundary){ + int more; + more=ogg_sync_pageseek(&_of->oy,_og); + /*Skipped (-more) bytes.*/ + if(OP_UNLIKELY(more<0))_of->offset-=more; + else if(more==0){ + int read_nbytes; + int ret; + /*Send more paramedics.*/ + if(!_boundary)return OP_FALSE; + if(_boundary<0)read_nbytes=OP_READ_SIZE; + else{ + opus_int64 position; + position=op_position(_of); + if(position>=_boundary)return OP_FALSE; + read_nbytes=(int)OP_MIN(_boundary-position,OP_READ_SIZE); + } + ret=op_get_data(_of,read_nbytes); + if(OP_UNLIKELY(ret<0))return OP_EREAD; + if(OP_UNLIKELY(ret==0)){ + /*Only fail cleanly on EOF if we didn't have a known boundary. + Otherwise, we should have been able to reach that boundary, and this + is a fatal error.*/ + return OP_UNLIKELY(_boundary<0)?OP_FALSE:OP_EBADLINK; + } + } + else{ + /*Got a page. + Return the page start offset and advance the internal offset past the + page end.*/ + opus_int64 page_offset; + page_offset=_of->offset; + _of->offset+=more; + OP_ASSERT(page_offset>=0); + return page_offset; + } + } + return OP_FALSE; +} + +static int op_add_serialno(const ogg_page *_og, + ogg_uint32_t **_serialnos,int *_nserialnos,int *_cserialnos){ + ogg_uint32_t *serialnos; + int nserialnos; + int cserialnos; + ogg_uint32_t s; + s=ogg_page_serialno(_og); + serialnos=*_serialnos; + nserialnos=*_nserialnos; + cserialnos=*_cserialnos; + if(OP_UNLIKELY(nserialnos>=cserialnos)){ + if(OP_UNLIKELY(cserialnos>INT_MAX/(int)sizeof(*serialnos)-1>>1)){ + return OP_EFAULT; + } + cserialnos=2*cserialnos+1; + OP_ASSERT(nserialnos=OP_PAGE_SIZE_MAX); + begin=OP_MAX(begin-chunk_size,0); + ret=op_seek_helper(_of,begin); + if(OP_UNLIKELY(ret<0))return ret; + search_start=begin; + while(_of->offsetsearch_start=search_start; + _sr->offset=_offset=llret; + _sr->serialno=serialno; + OP_ASSERT(_of->offset-_offset>=0); + OP_ASSERT(_of->offset-_offset<=OP_PAGE_SIZE_MAX); + _sr->size=(opus_int32)(_of->offset-_offset); + _sr->gp=ogg_page_granulepos(&og); + /*If this page is from the stream we're looking for, remember it.*/ + if(serialno==_serialno){ + preferred_found=1; + *&preferred_sr=*_sr; + } + if(!op_lookup_serialno(serialno,_serialnos,_nserialnos)){ + /*We fell off the end of the link, which means we seeked back too far + and shouldn't have been looking in that link to begin with. + If we found the preferred serial number, forget that we saw it.*/ + preferred_found=0; + } + search_start=llret+1; + } + /*We started from the beginning of the stream and found nothing. + This should be impossible unless the contents of the stream changed out + from under us after we read from it.*/ + if(OP_UNLIKELY(!begin)&&OP_UNLIKELY(_offset<0))return OP_EBADLINK; + /*Bump up the chunk size. + This is mildly helpful when seeks are very expensive (http).*/ + chunk_size=OP_MIN(2*chunk_size,OP_CHUNK_SIZE_MAX); + /*Avoid quadratic complexity if we hit an invalid patch of the file.*/ + end=OP_MIN(begin+OP_PAGE_SIZE_MAX-1,original_end); + } + while(_offset<0); + if(preferred_found)*_sr=*&preferred_sr; + return 0; +} + +/*Find the last page beginning before _offset with the given serial number and + a valid granule position. + Unlike the above search, this continues until it finds such a page, but does + not stray outside the current link. + We could implement it (inefficiently) by calling op_get_prev_page_serial() + repeatedly until it returned a page that had both our preferred serial + number and a valid granule position, but doing it with a separate function + allows us to avoid repeatedly re-scanning valid pages from other streams as + we seek-back-and-read-forward. + [out] _gp: Returns the granule position of the page that was found on + success. + _offset: The _offset before which to find a page. + Any page returned will consist of data entirely before _offset. + _serialno: The target serial number. + _serialnos: The list of serial numbers in the link that contains the + preferred serial number. + _nserialnos: The number of serial numbers in the current link. + Return: The offset of the page on success, or a negative value on failure. + OP_EREAD: Failed to read more data (error or EOF). + OP_EBADLINK: We couldn't find a page even after seeking back past the + beginning of the link.*/ +static opus_int64 op_get_last_page(OggOpusFile *_of,ogg_int64_t *_gp, + opus_int64 _offset,ogg_uint32_t _serialno, + const ogg_uint32_t *_serialnos,int _nserialnos){ + ogg_page og; + ogg_int64_t gp; + opus_int64 begin; + opus_int64 end; + opus_int64 original_end; + opus_int32 chunk_size; + /*The target serial number must belong to the current link.*/ + OP_ASSERT(op_lookup_serialno(_serialno,_serialnos,_nserialnos)); + original_end=end=begin=_offset; + _offset=-1; + /*We shouldn't have to initialize gp, but gcc is too dumb to figure out that + ret>=0 implies we entered the if(page_gp!=-1) block at least once.*/ + gp=-1; + chunk_size=OP_CHUNK_SIZE; + do{ + int left_link; + int ret; + OP_ASSERT(chunk_size>=OP_PAGE_SIZE_MAX); + begin=OP_MAX(begin-chunk_size,0); + ret=op_seek_helper(_of,begin); + if(OP_UNLIKELY(ret<0))return ret; + left_link=0; + while(_of->offsetready_stateos,ogg_page_serialno(_og)); + ogg_stream_pagein(&_of->os,_og); + if(OP_LIKELY(ogg_stream_packetout(&_of->os,&op)>0)){ + ret=opus_head_parse(_head,op.packet,op.bytes); + /*Found a valid Opus header. + Continue setup.*/ + if(OP_LIKELY(ret>=0))_of->ready_state=OP_STREAMSET; + /*If it's just a stream type we don't recognize, ignore it. + Everything else is fatal.*/ + else if(ret!=OP_ENOTFORMAT)return ret; + } + /*TODO: Should a BOS page with no packets be an error?*/ + } + /*Get the next page. + No need to clamp the boundary offset against _of->end, as all errors + become OP_ENOTFORMAT or OP_EBADHEADER.*/ + if(OP_UNLIKELY(op_get_next_page(_of,_og, + OP_ADV_OFFSET(_of->offset,OP_CHUNK_SIZE))<0)){ + return _of->ready_stateready_state!=OP_STREAMSET))return OP_ENOTFORMAT; + /*If the first non-header page belonged to our Opus stream, submit it.*/ + if(_of->os.serialno==ogg_page_serialno(_og))ogg_stream_pagein(&_of->os,_og); + /*Loop getting packets.*/ + for(;;){ + switch(ogg_stream_packetout(&_of->os,&op)){ + case 0:{ + /*Loop getting pages.*/ + for(;;){ + /*No need to clamp the boundary offset against _of->end, as all + errors become OP_EBADHEADER.*/ + if(OP_UNLIKELY(op_get_next_page(_of,_og, + OP_ADV_OFFSET(_of->offset,OP_CHUNK_SIZE))<0)){ + return OP_EBADHEADER; + } + /*If this page belongs to the correct stream, go parse it.*/ + if(_of->os.serialno==ogg_page_serialno(_og)){ + ogg_stream_pagein(&_of->os,_og); + break; + } + /*If the link ends before we see the Opus comment header, abort.*/ + if(OP_UNLIKELY(ogg_page_bos(_og)))return OP_EBADHEADER; + /*Otherwise, keep looking.*/ + } + }break; + /*We shouldn't get a hole in the headers!*/ + case -1:return OP_EBADHEADER; + default:{ + /*Got a packet. + It should be the comment header.*/ + ret=opus_tags_parse(_tags,op.packet,op.bytes); + if(OP_UNLIKELY(ret<0))return ret; + /*Make sure the page terminated at the end of the comment header. + If there is another packet on the page, or part of a packet, then + reject the stream. + Otherwise seekable sources won't be able to seek back to the start + properly.*/ + ret=ogg_stream_packetout(&_of->os,&op); + if(OP_UNLIKELY(ret!=0) + ||OP_UNLIKELY(_og->header[_og->header_len-1]==255)){ + /*If we fail, the caller assumes our tags are uninitialized.*/ + opus_tags_clear(_tags); + return OP_EBADHEADER; + } + return 0; + } + } + } +} + +static int op_fetch_headers(OggOpusFile *_of,OpusHead *_head, + OpusTags *_tags,ogg_uint32_t **_serialnos,int *_nserialnos, + int *_cserialnos,ogg_page *_og){ + ogg_page og; + int ret; + if(!_og){ + /*No need to clamp the boundary offset against _of->end, as all errors + become OP_ENOTFORMAT.*/ + if(OP_UNLIKELY(op_get_next_page(_of,&og, + OP_ADV_OFFSET(_of->offset,OP_CHUNK_SIZE))<0)){ + return OP_ENOTFORMAT; + } + _og=&og; + } + _of->ready_state=OP_OPENED; + ret=op_fetch_headers_impl(_of,_head,_tags,_serialnos,_nserialnos, + _cserialnos,_og); + /*Revert back from OP_STREAMSET to OP_OPENED on failure, to prevent + double-free of the tags in an unseekable stream.*/ + if(OP_UNLIKELY(ret<0))_of->ready_state=OP_OPENED; + return ret; +} + +/*Granule position manipulation routines. + A granule position is defined to be an unsigned 64-bit integer, with the + special value -1 in two's complement indicating an unset or invalid granule + position. + We are not guaranteed to have an unsigned 64-bit type, so we construct the + following routines that + a) Properly order negative numbers as larger than positive numbers, and + b) Check for underflow or overflow past the special -1 value. + This lets us operate on the full, valid range of granule positions in a + consistent and safe manner. + This full range is organized into distinct regions: + [ -1 (invalid) ][ 0 ... OP_INT64_MAX ][ OP_INT64_MIN ... -2 ][-1 (invalid) ] + + No one should actually use granule positions so large that they're negative, + even if they are technically valid, as very little software handles them + correctly (including most of Xiph.Org's). + This library also refuses to support durations so large they won't fit in a + signed 64-bit integer (to avoid exposing this mess to the application, and + to simplify a good deal of internal arithmetic), so the only way to use them + successfully is if pcm_start is very large. + This means there isn't anything you can do with negative granule positions + that you couldn't have done with purely non-negative ones. + The main purpose of these routines is to allow us to think very explicitly + about the possible failure cases of all granule position manipulations.*/ + +/*Safely adds a small signed integer to a valid (not -1) granule position. + The result can use the full 64-bit range of values (both positive and + negative), but will fail on overflow (wrapping past -1; wrapping past + OP_INT64_MAX is explicitly okay). + [out] _dst_gp: The resulting granule position. + Only modified on success. + _src_gp: The granule position to add to. + This must not be -1. + _delta: The amount to add. + This is allowed to be up to 32 bits to support the maximum + duration of a single Ogg page (255 packets * 120 ms per + packet == 1,468,800 samples at 48 kHz). + Return: 0 on success, or OP_EINVAL if the result would wrap around past -1.*/ +static int op_granpos_add(ogg_int64_t *_dst_gp,ogg_int64_t _src_gp, + opus_int32 _delta){ + /*The code below handles this case correctly, but there's no reason we + should ever be called with these values, so make sure we aren't.*/ + OP_ASSERT(_src_gp!=-1); + if(_delta>0){ + /*Adding this amount to the granule position would overflow its 64-bit + range.*/ + if(OP_UNLIKELY(_src_gp<0)&&OP_UNLIKELY(_src_gp>=-1-_delta))return OP_EINVAL; + if(OP_UNLIKELY(_src_gp>OP_INT64_MAX-_delta)){ + /*Adding this amount to the granule position would overflow the positive + half of its 64-bit range. + Since signed overflow is undefined in C, do it in a way the compiler + isn't allowed to screw up.*/ + _delta-=(opus_int32)(OP_INT64_MAX-_src_gp)+1; + _src_gp=OP_INT64_MIN; + } + } + else if(_delta<0){ + /*Subtracting this amount from the granule position would underflow its + 64-bit range.*/ + if(_src_gp>=0&&OP_UNLIKELY(_src_gp<-_delta))return OP_EINVAL; + if(OP_UNLIKELY(_src_gp da < 0.*/ + da=(OP_INT64_MIN-_gp_a)-1; + /*_gp_b >= 0 => db >= 0.*/ + db=OP_INT64_MAX-_gp_b; + /*Step 2: Check for overflow.*/ + if(OP_UNLIKELY(OP_INT64_MAX+da= 0 => da <= 0*/ + da=_gp_a+OP_INT64_MIN; + /*_gp_b < 0 => db <= 0*/ + db=OP_INT64_MIN-_gp_b; + /*Step 2: Check for overflow.*/ + if(OP_UNLIKELY(da=0)return 1; + /*Else fall through.*/ + } + else if(OP_UNLIKELY(_gp_b<0))return -1; + /*No wrapping case.*/ + return (_gp_a>_gp_b)-(_gp_b>_gp_a); +} + +/*Returns the duration of the packet (in samples at 48 kHz), or a negative + value on error.*/ +static int op_get_packet_duration(const unsigned char *_data,int _len){ + int nframes; + int frame_size; + int nsamples; + nframes=opus_packet_get_nb_frames(_data,_len); + if(OP_UNLIKELY(nframes<0))return OP_EBADPACKET; + frame_size=opus_packet_get_samples_per_frame(_data,48000); + nsamples=nframes*frame_size; + if(OP_UNLIKELY(nsamples>120*48))return OP_EBADPACKET; + return nsamples; +} + +/*This function more properly belongs in info.c, but we define it here to allow + the static granule position manipulation functions to remain static.*/ +ogg_int64_t opus_granule_sample(const OpusHead *_head,ogg_int64_t _gp){ + opus_int32 pre_skip; + pre_skip=_head->pre_skip; + if(_gp!=-1&&op_granpos_add(&_gp,_gp,-pre_skip))_gp=-1; + return _gp; +} + +/*Grab all the packets currently in the stream state, and compute their + durations. + _of->op_count is set to the number of packets collected. + [out] _durations: Returns the durations of the individual packets. + Return: The total duration of all packets, or OP_HOLE if there was a hole.*/ +static opus_int32 op_collect_audio_packets(OggOpusFile *_of, + int _durations[255]){ + opus_int32 total_duration; + int op_count; + /*Count the durations of all packets in the page.*/ + op_count=0; + total_duration=0; + for(;;){ + int ret; + /*This takes advantage of undocumented libogg behavior that returned + ogg_packet buffers are valid at least until the next page is + submitted. + Relying on this is not too terrible, as _none_ of the Ogg memory + ownership/lifetime rules are well-documented. + But I can read its code and know this will work.*/ + ret=ogg_stream_packetout(&_of->os,_of->op+op_count); + if(!ret)break; + if(OP_UNLIKELY(ret<0)){ + /*We shouldn't get holes in the middle of pages.*/ + OP_ASSERT(op_count==0); + /*Set the return value and break out of the loop. + We want to make sure op_count gets set to 0, because we've ingested a + page, so any previously loaded packets are now invalid.*/ + total_duration=OP_HOLE; + break; + } + /*Unless libogg is broken, we can't get more than 255 packets from a + single page.*/ + OP_ASSERT(op_count<255); + _durations[op_count]=op_get_packet_duration(_of->op[op_count].packet, + _of->op[op_count].bytes); + if(OP_LIKELY(_durations[op_count]>0)){ + /*With at most 255 packets on a page, this can't overflow.*/ + total_duration+=_durations[op_count++]; + } + /*Ignore packets with an invalid TOC sequence.*/ + else if(op_count>0){ + /*But save the granule position, if there was one.*/ + _of->op[op_count-1].granulepos=_of->op[op_count].granulepos; + } + } + _of->op_pos=0; + _of->op_count=op_count; + return total_duration; +} + +/*Starting from current cursor position, get the initial PCM offset of the next + page. + This also validates the granule position on the first page with a completed + audio data packet, as required by the spec. + If this link is completely empty (no pages with completed packets), then this + function sets pcm_start=pcm_end=0 and returns the BOS page of the next link + (if any). + In the seekable case, we initialize pcm_end=-1 before calling this function, + so that later we can detect that the link was empty before calling + op_find_final_pcm_offset(). + [inout] _link: The link for which to find pcm_start. + [out] _og: Returns the BOS page of the next link if this link was empty. + In the unseekable case, we can then feed this to + op_fetch_headers() to start the next link. + The caller may pass NULL (e.g., for seekable streams), in + which case this page will be discarded. + Return: 0 on success, 1 if there is a buffered BOS page available, or a + negative value on unrecoverable error.*/ +static int op_find_initial_pcm_offset(OggOpusFile *_of, + OggOpusLink *_link,ogg_page *_og){ + ogg_page og; + opus_int64 page_offset; + ogg_int64_t pcm_start; + ogg_int64_t prev_packet_gp; + ogg_int64_t cur_page_gp; + ogg_uint32_t serialno; + opus_int32 total_duration; + int durations[255]; + int cur_page_eos; + int op_count; + int pi; + if(_og==NULL)_og=&og; + serialno=_of->os.serialno; + op_count=0; + /*We shouldn't have to initialize total_duration, but gcc is too dumb to + figure out that op_count>0 implies we've been through the whole loop at + least once.*/ + total_duration=0; + do{ + page_offset=op_get_next_page(_of,_og,_of->end); + /*We should get a page unless the file is truncated or mangled. + Otherwise there are no audio data packets in the whole logical stream.*/ + if(OP_UNLIKELY(page_offset<0)){ + /*Fail if there was a read error.*/ + if(page_offsethead.pre_skip>0)return OP_EBADTIMESTAMP; + _link->pcm_file_offset=0; + /*Set pcm_end and end_offset so we can skip the call to + op_find_final_pcm_offset().*/ + _link->pcm_start=_link->pcm_end=0; + _link->end_offset=_link->data_offset; + return 0; + } + /*Similarly, if we hit the next link in the chain, we've gone too far.*/ + if(OP_UNLIKELY(ogg_page_bos(_og))){ + if(_link->head.pre_skip>0)return OP_EBADTIMESTAMP; + /*Set pcm_end and end_offset so we can skip the call to + op_find_final_pcm_offset().*/ + _link->pcm_file_offset=0; + _link->pcm_start=_link->pcm_end=0; + _link->end_offset=_link->data_offset; + /*Tell the caller we've got a buffered page for them.*/ + return 1; + } + /*Ignore pages from other streams (not strictly necessary, because of the + checks in ogg_stream_pagein(), but saves some work).*/ + if(serialno!=(ogg_uint32_t)ogg_page_serialno(_og))continue; + ogg_stream_pagein(&_of->os,_og); + /*Bitrate tracking: add the header's bytes here. + The body bytes are counted when we consume the packets.*/ + _of->bytes_tracked+=_og->header_len; + /*Count the durations of all packets in the page.*/ + do total_duration=op_collect_audio_packets(_of,durations); + /*Ignore holes.*/ + while(OP_UNLIKELY(total_duration<0)); + op_count=_of->op_count; + } + while(op_count<=0); + /*We found the first page with a completed audio data packet: actually look + at the granule position. + RFC 3533 says, "A special value of -1 (in two's complement) indicates that + no packets finish on this page," which does not say that a granule + position that is NOT -1 indicates that some packets DO finish on that page + (even though this was the intention, libogg itself violated this intention + for years before we fixed it). + The Ogg Opus specification only imposes its start-time requirements + on the granule position of the first page with completed packets, + so we ignore any set granule positions until then.*/ + cur_page_gp=_of->op[op_count-1].granulepos; + /*But getting a packet without a valid granule position on the page is not + okay.*/ + if(cur_page_gp==-1)return OP_EBADTIMESTAMP; + cur_page_eos=_of->op[op_count-1].e_o_s; + if(OP_LIKELY(!cur_page_eos)){ + /*The EOS flag wasn't set. + Work backwards from the provided granule position to get the starting PCM + offset.*/ + if(OP_UNLIKELY(op_granpos_add(&pcm_start,cur_page_gp,-total_duration)<0)){ + /*The starting granule position MUST not be smaller than the amount of + audio on the first page with completed packets.*/ + return OP_EBADTIMESTAMP; + } + } + else{ + /*The first page with completed packets was also the last.*/ + if(OP_LIKELY(op_granpos_add(&pcm_start,cur_page_gp,-total_duration)<0)){ + /*If there's less audio on the page than indicated by the granule + position, then we're doing end-trimming, and the starting PCM offset + is zero by spec mandate.*/ + pcm_start=0; + /*However, the end-trimming MUST not ask us to trim more samples than + exist after applying the pre-skip.*/ + if(OP_UNLIKELY(op_granpos_cmp(cur_page_gp,_link->head.pre_skip)<0)){ + return OP_EBADTIMESTAMP; + } + } + } + /*Timestamp the individual packets.*/ + prev_packet_gp=pcm_start; + for(pi=0;pi0){ + /*If we trimmed the entire packet, stop (the spec says encoders + shouldn't do this, but we support it anyway).*/ + if(OP_UNLIKELY(diff>durations[pi]))break; + _of->op[pi].granulepos=prev_packet_gp=cur_page_gp; + /*Move the EOS flag to this packet, if necessary, so we'll trim the + samples.*/ + _of->op[pi].e_o_s=1; + continue; + } + } + /*Update the granule position as normal.*/ + OP_ALWAYS_TRUE(!op_granpos_add(&_of->op[pi].granulepos, + prev_packet_gp,durations[pi])); + prev_packet_gp=_of->op[pi].granulepos; + } + /*Update the packet count after end-trimming.*/ + _of->op_count=pi; + _of->cur_discard_count=_link->head.pre_skip; + _link->pcm_file_offset=0; + _of->prev_packet_gp=_link->pcm_start=pcm_start; + _of->prev_page_offset=page_offset; + return 0; +} + +/*Starting from current cursor position, get the final PCM offset of the + previous page. + This also validates the duration of the link, which, while not strictly + required by the spec, we need to ensure duration calculations don't + overflow. + This is only done for seekable sources. + We must validate that op_find_initial_pcm_offset() succeeded for this link + before calling this function, otherwise it will scan the entire stream + backwards until it reaches the start, and then fail.*/ +static int op_find_final_pcm_offset(OggOpusFile *_of, + const ogg_uint32_t *_serialnos,int _nserialnos,OggOpusLink *_link, + opus_int64 _offset,ogg_uint32_t _end_serialno,ogg_int64_t _end_gp, + ogg_int64_t *_total_duration){ + ogg_int64_t total_duration; + ogg_int64_t duration; + ogg_uint32_t cur_serialno; + /*For the time being, fetch end PCM offset the simple way.*/ + cur_serialno=_link->serialno; + if(_end_serialno!=cur_serialno||_end_gp==-1){ + _offset=op_get_last_page(_of,&_end_gp,_offset, + cur_serialno,_serialnos,_nserialnos); + if(OP_UNLIKELY(_offset<0))return (int)_offset; + } + /*At worst we should have found the first page with completed packets.*/ + if(OP_UNLIKELY(_offset<_link->data_offset))return OP_EBADLINK; + /*This implementation requires that the difference between the first and last + granule positions in each link be representable in a signed, 64-bit + number, and that each link also have at least as many samples as the + pre-skip requires.*/ + if(OP_UNLIKELY(op_granpos_diff(&duration,_end_gp,_link->pcm_start)<0) + ||OP_UNLIKELY(duration<_link->head.pre_skip)){ + return OP_EBADTIMESTAMP; + } + /*We also require that the total duration be representable in a signed, + 64-bit number.*/ + duration-=_link->head.pre_skip; + total_duration=*_total_duration; + if(OP_UNLIKELY(OP_INT64_MAX-durationpcm_end=_end_gp; + _link->end_offset=_offset; + return 0; +} + +/*Rescale the number _x from the range [0,_from] to [0,_to]. + _from and _to must be positive.*/ +static opus_int64 op_rescale64(opus_int64 _x,opus_int64 _from,opus_int64 _to){ + opus_int64 frac; + opus_int64 ret; + int i; + if(_x>=_from)return _to; + if(_x<=0)return 0; + frac=0; + for(i=0;i<63;i++){ + frac<<=1; + OP_ASSERT(_x<=_from); + if(_x>=_from>>1){ + _x-=_from-_x; + frac|=1; + } + else _x<<=1; + } + ret=0; + for(i=0;i<63;i++){ + if(frac&1)ret=(ret&_to&1)+(ret>>1)+(_to>>1); + else ret>>=1; + frac>>=1; + } + return ret; +} + +/*The minimum granule position spacing allowed for making predictions. + This corresponds to about 1 second of audio at 48 kHz for both Opus and + Vorbis, or one keyframe interval in Theora with the default keyframe spacing + of 256.*/ +#define OP_GP_SPACING_MIN (48000) + +/*Try to estimate the location of the next link using the current seek + records, assuming the initial granule position of any streams we've found is + 0.*/ +static opus_int64 op_predict_link_start(const OpusSeekRecord *_sr,int _nsr, + opus_int64 _searched,opus_int64 _end_searched,opus_int32 _bias){ + opus_int64 bisect; + int sri; + int srj; + /*Require that we be at least OP_CHUNK_SIZE from the end. + We don't require that we be at least OP_CHUNK_SIZE from the beginning, + because if we are we'll just scan forward without seeking.*/ + _end_searched-=OP_CHUNK_SIZE; + if(_searched>=_end_searched)return -1; + bisect=_end_searched; + for(sri=0;sri<_nsr;sri++){ + ogg_int64_t gp1; + ogg_int64_t gp2_min; + ogg_uint32_t serialno1; + opus_int64 offset1; + /*If the granule position is negative, either it's invalid or we'd cause + overflow.*/ + gp1=_sr[sri].gp; + if(gp1<0)continue; + /*We require some minimum distance between granule positions to make an + estimate. + We don't actually know what granule position scheme is being used, + because we have no idea what kind of stream these came from. + Therefore we require a minimum spacing between them, with the + expectation that while bitrates and granule position increments might + vary locally in quite complex ways, they are globally smooth.*/ + if(OP_UNLIKELY(op_granpos_add(&gp2_min,gp1,OP_GP_SPACING_MIN)<0)){ + /*No granule position would satisfy us.*/ + continue; + } + offset1=_sr[sri].offset; + serialno1=_sr[sri].serialno; + for(srj=sri;srj-->0;){ + ogg_int64_t gp2; + opus_int64 offset2; + opus_int64 num; + ogg_int64_t den; + ogg_int64_t ipart; + gp2=_sr[srj].gp; + if(gp20); + if(ipart>0&&(offset2-_searched)/ipart=_end_searched?-1:bisect; +} + +/*Finds each bitstream link, one at a time, using a bisection search. + This has to begin by knowing the offset of the first link's initial page.*/ +static int op_bisect_forward_serialno(OggOpusFile *_of, + opus_int64 _searched,OpusSeekRecord *_sr,int _csr, + ogg_uint32_t **_serialnos,int *_nserialnos,int *_cserialnos){ + ogg_page og; + OggOpusLink *links; + int nlinks; + int clinks; + ogg_uint32_t *serialnos; + int nserialnos; + ogg_int64_t total_duration; + int nsr; + int ret; + links=_of->links; + nlinks=clinks=_of->nlinks; + total_duration=0; + /*We start with one seek record, for the last page in the file. + We build up a list of records for places we seek to during link + enumeration. + This list is kept sorted in reverse order. + We only care about seek locations that were _not_ in the current link, + therefore we can add them one at a time to the end of the list as we + improve the lower bound on the location where the next link starts.*/ + nsr=1; + for(;;){ + opus_int64 end_searched; + opus_int64 bisect; + opus_int64 next; + opus_int64 last; + ogg_int64_t end_offset; + ogg_int64_t end_gp; + int sri; + serialnos=*_serialnos; + nserialnos=*_nserialnos; + if(OP_UNLIKELY(nlinks>=clinks)){ + if(OP_UNLIKELY(clinks>INT_MAX-1>>1))return OP_EFAULT; + clinks=2*clinks+1; + OP_ASSERT(nlinkslinks=links; + } + /*Invariants: + We have the headers and serial numbers for the link beginning at 'begin'. + We have the offset and granule position of the last page in the file + (potentially not a page we care about).*/ + /*Scan the seek records we already have to save us some bisection.*/ + for(sri=0;sri1){ + opus_int64 last_offset; + opus_int64 avg_link_size; + opus_int64 upper_limit; + last_offset=links[nlinks-1].offset; + avg_link_size=last_offset/(nlinks-1); + upper_limit=end_searched-OP_CHUNK_SIZE-avg_link_size; + if(OP_LIKELY(last_offset>_searched-avg_link_size) + &&OP_LIKELY(last_offset>1); + /*If we're within OP_CHUNK_SIZE of the start, scan forward.*/ + if(bisect-_searchedoffset-last>=0); + OP_ASSERT(_of->offset-last<=OP_PAGE_SIZE_MAX); + _sr[nsr].size=(opus_int32)(_of->offset-last); + _sr[nsr].serialno=serialno; + _sr[nsr].gp=gp; + nsr++; + } + } + else{ + _searched=_of->offset; + next_bias=OP_CHUNK_SIZE; + if(serialno==links[nlinks-1].serialno){ + /*This page was from the stream we want, remember it. + If it's the last such page in the link, we won't have to go back + looking for it later.*/ + end_gp=gp; + end_offset=last; + } + } + } + bisect=op_predict_link_start(_sr,nsr,_searched,end_searched,next_bias); + } + /*Bisection point found. + Get the final granule position of the previous link, assuming + op_find_initial_pcm_offset() didn't already determine the link was + empty.*/ + if(OP_LIKELY(links[nlinks-1].pcm_end==-1)){ + if(end_gp==-1){ + /*If we don't know where the end page is, we'll have to seek back and + look for it, starting from the end of the link.*/ + end_offset=next; + /*Also forget the last page we read. + It won't be available after the seek.*/ + last=-1; + } + ret=op_find_final_pcm_offset(_of,serialnos,nserialnos, + links+nlinks-1,end_offset,links[nlinks-1].serialno,end_gp, + &total_duration); + if(OP_UNLIKELY(ret<0))return ret; + } + if(last!=next){ + /*The last page we read was not the first page the next link. + Move the cursor position to the offset of that first page. + This only performs an actual seek if the first page of the next link + does not start at the end of the last page from the current Opus + stream with a valid granule position.*/ + ret=op_seek_helper(_of,next); + if(OP_UNLIKELY(ret<0))return ret; + } + ret=op_fetch_headers(_of,&links[nlinks].head,&links[nlinks].tags, + _serialnos,_nserialnos,_cserialnos,last!=next?NULL:&og); + if(OP_UNLIKELY(ret<0))return ret; + links[nlinks].offset=next; + links[nlinks].data_offset=_of->offset; + links[nlinks].serialno=_of->os.serialno; + links[nlinks].pcm_end=-1; + /*This might consume a page from the next link, however the next bisection + always starts with a seek.*/ + ret=op_find_initial_pcm_offset(_of,links+nlinks,NULL); + if(OP_UNLIKELY(ret<0))return ret; + links[nlinks].pcm_file_offset=total_duration; + _searched=_of->offset; + /*Mark the current link count so it can be cleaned up on error.*/ + _of->nlinks=++nlinks; + } + /*Last page is in the starting serialno list, so we've reached the last link. + Now find the last granule position for it (if we didn't the first time we + looked at the end of the stream, and if op_find_initial_pcm_offset() + didn't already determine the link was empty).*/ + if(OP_LIKELY(links[nlinks-1].pcm_end==-1)){ + ret=op_find_final_pcm_offset(_of,serialnos,nserialnos, + links+nlinks-1,_sr[0].offset,_sr[0].serialno,_sr[0].gp,&total_duration); + if(OP_UNLIKELY(ret<0))return ret; + } + /*Trim back the links array if necessary.*/ + links=(OggOpusLink *)_ogg_realloc(links,sizeof(*links)*nlinks); + if(OP_LIKELY(links!=NULL))_of->links=links; + /*We also don't need these anymore.*/ + _ogg_free(*_serialnos); + *_serialnos=NULL; + *_cserialnos=*_nserialnos=0; + return 0; +} + +static void op_update_gain(OggOpusFile *_of){ + OpusHead *head; + opus_int32 gain_q8; + int li; + /*If decode isn't ready, then we'll apply the gain when we initialize the + decoder.*/ + if(_of->ready_stategain_offset_q8; + li=_of->seekable?_of->cur_link:0; + head=&_of->links[li].head; + /*We don't have to worry about overflow here because the header gain and + track gain must lie in the range [-32768,32767], and the user-supplied + offset has been pre-clamped to [-98302,98303].*/ + switch(_of->gain_type){ + case OP_ALBUM_GAIN:{ + int album_gain_q8; + album_gain_q8=0; + opus_tags_get_album_gain(&_of->links[li].tags,&album_gain_q8); + gain_q8+=album_gain_q8; + gain_q8+=head->output_gain; + }break; + case OP_TRACK_GAIN:{ + int track_gain_q8; + track_gain_q8=0; + opus_tags_get_track_gain(&_of->links[li].tags,&track_gain_q8); + gain_q8+=track_gain_q8; + gain_q8+=head->output_gain; + }break; + case OP_HEADER_GAIN:gain_q8+=head->output_gain;break; + case OP_ABSOLUTE_GAIN:break; + default:OP_ASSERT(0); + } + gain_q8=OP_CLAMP(-32768,gain_q8,32767); + OP_ASSERT(_of->od!=NULL); +#if defined(OPUS_SET_GAIN) + opus_multistream_decoder_ctl(_of->od,OPUS_SET_GAIN(gain_q8)); +#else +/*A fallback that works with both float and fixed-point is a bunch of work, + so just force people to use a sufficiently new version. + This is deployed well enough at this point that this shouldn't be a burden.*/ +# error "libopus 1.0.1 or later required" +#endif +} + +static int op_make_decode_ready(OggOpusFile *_of){ + const OpusHead *head; + int li; + int stream_count; + int coupled_count; + int channel_count; + if(_of->ready_state>OP_STREAMSET)return 0; + if(OP_UNLIKELY(_of->ready_stateseekable?_of->cur_link:0; + head=&_of->links[li].head; + stream_count=head->stream_count; + coupled_count=head->coupled_count; + channel_count=head->channel_count; + /*Check to see if the current decoder is compatible with the current link.*/ + if(_of->od!=NULL&&_of->od_stream_count==stream_count + &&_of->od_coupled_count==coupled_count&&_of->od_channel_count==channel_count + &&memcmp(_of->od_mapping,head->mapping, + sizeof(*head->mapping)*channel_count)==0){ + opus_multistream_decoder_ctl(_of->od,OPUS_RESET_STATE); + } + else{ + int err; + opus_multistream_decoder_destroy(_of->od); + _of->od=opus_multistream_decoder_create(48000,channel_count, + stream_count,coupled_count,head->mapping,&err); + if(_of->od==NULL)return OP_EFAULT; + _of->od_stream_count=stream_count; + _of->od_coupled_count=coupled_count; + _of->od_channel_count=channel_count; + memcpy(_of->od_mapping,head->mapping,sizeof(*head->mapping)*channel_count); + } + _of->ready_state=OP_INITSET; + _of->bytes_tracked=0; + _of->samples_tracked=0; +#if !defined(OP_FIXED_POINT) + _of->state_channel_count=0; + /*Use the serial number for the PRNG seed to get repeatable output for + straight play-throughs.*/ + _of->dither_seed=_of->links[li].serialno; +#endif + op_update_gain(_of); + return 0; +} + +static int op_open_seekable2_impl(OggOpusFile *_of){ + /*64 seek records should be enough for anybody. + Actually, with a bisection search in a 63-bit range down to OP_CHUNK_SIZE + granularity, much more than enough.*/ + OpusSeekRecord sr[64]; + opus_int64 data_offset; + int ret; + /*We can seek, so set out learning all about this file.*/ + (*_of->callbacks.seek)(_of->stream,0,SEEK_END); + _of->offset=_of->end=(*_of->callbacks.tell)(_of->stream); + if(OP_UNLIKELY(_of->end<0))return OP_EREAD; + data_offset=_of->links[0].data_offset; + if(OP_UNLIKELY(_of->endend, + _of->links[0].serialno,_of->serialnos,_of->nserialnos); + if(OP_UNLIKELY(ret<0))return ret; + /*If there's any trailing junk, forget about it.*/ + _of->end=sr[0].offset+sr[0].size; + if(OP_UNLIKELY(_of->endserialnos,&_of->nserialnos,&_of->cserialnos); +} + +static int op_open_seekable2(OggOpusFile *_of){ + ogg_sync_state oy_start; + ogg_stream_state os_start; + ogg_packet *op_start; + opus_int64 prev_page_offset; + opus_int64 start_offset; + int start_op_count; + int ret; + /*We're partially open and have a first link header state in storage in _of. + Save off that stream state so we can come back to it. + It would be simpler to just dump all this state and seek back to + links[0].data_offset when we're done. + But we do the extra work to allow us to seek back to _exactly_ the same + stream position we're at now. + This allows, e.g., the HTTP backend to continue reading from the original + connection (if it's still available), instead of opening a new one. + This means we can open and start playing a normal Opus file with a single + link and reasonable packet sizes using only two HTTP requests.*/ + start_op_count=_of->op_count; + /*This is a bit too large to put on the stack unconditionally.*/ + op_start=(ogg_packet *)_ogg_malloc(sizeof(*op_start)*start_op_count); + if(op_start==NULL)return OP_EFAULT; + *&oy_start=_of->oy; + *&os_start=_of->os; + prev_page_offset=_of->prev_page_offset; + start_offset=_of->offset; + memcpy(op_start,_of->op,sizeof(*op_start)*start_op_count); + OP_ASSERT((*_of->callbacks.tell)(_of->stream)==op_position(_of)); + ogg_sync_init(&_of->oy); + ogg_stream_init(&_of->os,-1); + ret=op_open_seekable2_impl(_of); + /*Restore the old stream state.*/ + ogg_stream_clear(&_of->os); + ogg_sync_clear(&_of->oy); + *&_of->oy=*&oy_start; + *&_of->os=*&os_start; + _of->offset=start_offset; + _of->op_count=start_op_count; + memcpy(_of->op,op_start,sizeof(*_of->op)*start_op_count); + _ogg_free(op_start); + _of->prev_packet_gp=_of->links[0].pcm_start; + _of->prev_page_offset=prev_page_offset; + _of->cur_discard_count=_of->links[0].head.pre_skip; + if(OP_UNLIKELY(ret<0))return ret; + /*And restore the position indicator.*/ + ret=(*_of->callbacks.seek)(_of->stream,op_position(_of),SEEK_SET); + return OP_UNLIKELY(ret<0)?OP_EREAD:0; +} + +/*Clear out the current logical bitstream decoder.*/ +static void op_decode_clear(OggOpusFile *_of){ + /*We don't actually free the decoder. + We might be able to re-use it for the next link.*/ + _of->op_count=0; + _of->od_buffer_size=0; + _of->prev_packet_gp=-1; + _of->prev_page_offset=-1; + if(!_of->seekable){ + OP_ASSERT(_of->ready_state>=OP_INITSET); + opus_tags_clear(&_of->links[0].tags); + } + _of->ready_state=OP_OPENED; +} + +static void op_clear(OggOpusFile *_of){ + OggOpusLink *links; + _ogg_free(_of->od_buffer); + if(_of->od!=NULL)opus_multistream_decoder_destroy(_of->od); + links=_of->links; + if(!_of->seekable){ + if(_of->ready_state>OP_OPENED||_of->ready_state==OP_PARTOPEN){ + opus_tags_clear(&links[0].tags); + } + } + else if(OP_LIKELY(links!=NULL)){ + int nlinks; + int link; + nlinks=_of->nlinks; + for(link=0;linkserialnos); + ogg_stream_clear(&_of->os); + ogg_sync_clear(&_of->oy); + if(_of->callbacks.close!=NULL)(*_of->callbacks.close)(_of->stream); +} + +static int op_open1(OggOpusFile *_of, + void *_stream,const OpusFileCallbacks *_cb, + const unsigned char *_initial_data,size_t _initial_bytes){ + ogg_page og; + ogg_page *pog; + int seekable; + int ret; + memset(_of,0,sizeof(*_of)); + if(OP_UNLIKELY(_initial_bytes>(size_t)LONG_MAX))return OP_EFAULT; + _of->end=-1; + _of->stream=_stream; + *&_of->callbacks=*_cb; + /*At a minimum, we need to be able to read data.*/ + if(OP_UNLIKELY(_of->callbacks.read==NULL))return OP_EREAD; + /*Initialize the framing state.*/ + ogg_sync_init(&_of->oy); + /*Perhaps some data was previously read into a buffer for testing against + other stream types. + Allow initialization from this previously read data (especially as we may + be reading from a non-seekable stream). + This requires copying it into a buffer allocated by ogg_sync_buffer() and + doesn't support seeking, so this is not a good mechanism to use for + decoding entire files from RAM.*/ + if(_initial_bytes>0){ + char *buffer; + buffer=ogg_sync_buffer(&_of->oy,(long)_initial_bytes); + memcpy(buffer,_initial_data,_initial_bytes*sizeof(*buffer)); + ogg_sync_wrote(&_of->oy,(long)_initial_bytes); + } + /*Can we seek? + Stevens suggests the seek test is portable.*/ + seekable=_cb->seek!=NULL&&(*_cb->seek)(_stream,0,SEEK_CUR)!=-1; + /*If seek is implemented, tell must also be implemented.*/ + if(seekable){ + opus_int64 pos; + if(OP_UNLIKELY(_of->callbacks.tell==NULL))return OP_EINVAL; + pos=(*_of->callbacks.tell)(_of->stream); + /*If the current position is not equal to the initial bytes consumed, + absolute seeking will not work.*/ + if(OP_UNLIKELY(pos!=(opus_int64)_initial_bytes))return OP_EINVAL; + } + _of->seekable=seekable; + /*Don't seek yet. + Set up a 'single' (current) logical bitstream entry for partial open.*/ + _of->links=(OggOpusLink *)_ogg_malloc(sizeof(*_of->links)); + /*The serialno gets filled in later by op_fetch_headers().*/ + ogg_stream_init(&_of->os,-1); + pog=NULL; + for(;;){ + /*Fetch all BOS pages, store the Opus header and all seen serial numbers, + and load subsequent Opus setup headers.*/ + ret=op_fetch_headers(_of,&_of->links[0].head,&_of->links[0].tags, + &_of->serialnos,&_of->nserialnos,&_of->cserialnos,pog); + if(OP_UNLIKELY(ret<0))break; + _of->nlinks=1; + _of->links[0].offset=0; + _of->links[0].data_offset=_of->offset; + _of->links[0].pcm_end=-1; + _of->links[0].serialno=_of->os.serialno; + /*Fetch the initial PCM offset.*/ + ret=op_find_initial_pcm_offset(_of,_of->links,&og); + if(seekable||OP_LIKELY(ret<=0))break; + /*This link was empty, but we already have the BOS page for the next one in + og. + We can't seek, so start processing the next link right now.*/ + opus_tags_clear(&_of->links[0].tags); + _of->nlinks=0; + if(!seekable)_of->cur_link++; + pog=&og; + } + if(OP_LIKELY(ret>=0))_of->ready_state=OP_PARTOPEN; + return ret; +} + +static int op_open2(OggOpusFile *_of){ + int ret; + OP_ASSERT(_of->ready_state==OP_PARTOPEN); + if(_of->seekable){ + _of->ready_state=OP_OPENED; + ret=op_open_seekable2(_of); + } + else ret=0; + if(OP_LIKELY(ret>=0)){ + /*We have buffered packets from op_find_initial_pcm_offset(). + Move to OP_INITSET so we can use them.*/ + _of->ready_state=OP_STREAMSET; + ret=op_make_decode_ready(_of); + if(OP_LIKELY(ret>=0))return 0; + } + /*Don't auto-close the stream on failure.*/ + _of->callbacks.close=NULL; + op_clear(_of); + return ret; +} + +OggOpusFile *op_test_callbacks(void *_stream,const OpusFileCallbacks *_cb, + const unsigned char *_initial_data,size_t _initial_bytes,int *_error){ + OggOpusFile *of; + int ret; + of=(OggOpusFile *)_ogg_malloc(sizeof(*of)); + ret=OP_EFAULT; + if(OP_LIKELY(of!=NULL)){ + ret=op_open1(of,_stream,_cb,_initial_data,_initial_bytes); + if(OP_LIKELY(ret>=0)){ + if(_error!=NULL)*_error=0; + return of; + } + /*Don't auto-close the stream on failure.*/ + of->callbacks.close=NULL; + op_clear(of); + _ogg_free(of); + } + if(_error!=NULL)*_error=ret; + return NULL; +} + +OggOpusFile *op_open_callbacks(void *_stream,const OpusFileCallbacks *_cb, + const unsigned char *_initial_data,size_t _initial_bytes,int *_error){ + OggOpusFile *of; + of=op_test_callbacks(_stream,_cb,_initial_data,_initial_bytes,_error); + if(OP_LIKELY(of!=NULL)){ + int ret; + ret=op_open2(of); + if(OP_LIKELY(ret>=0))return of; + if(_error!=NULL)*_error=ret; + _ogg_free(of); + } + return NULL; +} + +/*Convenience routine to clean up from failure for the open functions that + create their own streams.*/ +static OggOpusFile *op_open_close_on_failure(void *_stream, + const OpusFileCallbacks *_cb,int *_error){ + OggOpusFile *of; + if(OP_UNLIKELY(_stream==NULL)){ + if(_error!=NULL)*_error=OP_EFAULT; + return NULL; + } + of=op_open_callbacks(_stream,_cb,NULL,0,_error); + if(OP_UNLIKELY(of==NULL))(*_cb->close)(_stream); + return of; +} + +OggOpusFile *op_open_file(const char *_path,int *_error){ + OpusFileCallbacks cb; + return op_open_close_on_failure(op_fopen(&cb,_path,"rb"),&cb,_error); +} + +OggOpusFile *op_open_memory(const unsigned char *_data,size_t _size, + int *_error){ + OpusFileCallbacks cb; + return op_open_close_on_failure(op_mem_stream_create(&cb,_data,_size),&cb, + _error); +} + +/*Convenience routine to clean up from failure for the open functions that + create their own streams.*/ +static OggOpusFile *op_test_close_on_failure(void *_stream, + const OpusFileCallbacks *_cb,int *_error){ + OggOpusFile *of; + if(OP_UNLIKELY(_stream==NULL)){ + if(_error!=NULL)*_error=OP_EFAULT; + return NULL; + } + of=op_test_callbacks(_stream,_cb,NULL,0,_error); + if(OP_UNLIKELY(of==NULL))(*_cb->close)(_stream); + return of; +} + +OggOpusFile *op_test_file(const char *_path,int *_error){ + OpusFileCallbacks cb; + return op_test_close_on_failure(op_fopen(&cb,_path,"rb"),&cb,_error); +} + +OggOpusFile *op_test_memory(const unsigned char *_data,size_t _size, + int *_error){ + OpusFileCallbacks cb; + return op_test_close_on_failure(op_mem_stream_create(&cb,_data,_size),&cb, + _error); +} + +int op_test_open(OggOpusFile *_of){ + int ret; + if(OP_UNLIKELY(_of->ready_state!=OP_PARTOPEN))return OP_EINVAL; + ret=op_open2(_of); + /*op_open2() will clear this structure on failure. + Reset its contents to prevent double-frees in op_free().*/ + if(OP_UNLIKELY(ret<0))memset(_of,0,sizeof(*_of)); + return ret; +} + +void op_free(OggOpusFile *_of){ + if(OP_LIKELY(_of!=NULL)){ + op_clear(_of); + _ogg_free(_of); + } +} + +int op_seekable(const OggOpusFile *_of){ + return _of->seekable; +} + +int op_link_count(const OggOpusFile *_of){ + return _of->nlinks; +} + +opus_uint32 op_serialno(const OggOpusFile *_of,int _li){ + if(OP_UNLIKELY(_li>=_of->nlinks))_li=_of->nlinks-1; + if(!_of->seekable)_li=0; + return _of->links[_li<0?_of->cur_link:_li].serialno; +} + +int op_channel_count(const OggOpusFile *_of,int _li){ + return op_head(_of,_li)->channel_count; +} + +opus_int64 op_raw_total(const OggOpusFile *_of,int _li){ + if(OP_UNLIKELY(_of->ready_stateseekable) + ||OP_UNLIKELY(_li>=_of->nlinks)){ + return OP_EINVAL; + } + if(_li<0)return _of->end; + return (_li+1>=_of->nlinks?_of->end:_of->links[_li+1].offset) + -(_li>0?_of->links[_li].offset:0); +} + +ogg_int64_t op_pcm_total(const OggOpusFile *_of,int _li){ + OggOpusLink *links; + ogg_int64_t pcm_total; + ogg_int64_t diff; + int nlinks; + nlinks=_of->nlinks; + if(OP_UNLIKELY(_of->ready_stateseekable) + ||OP_UNLIKELY(_li>=nlinks)){ + return OP_EINVAL; + } + links=_of->links; + /*We verify that the granule position differences are larger than the + pre-skip and that the total duration does not overflow during link + enumeration, so we don't have to check here.*/ + pcm_total=0; + if(_li<0){ + pcm_total=links[nlinks-1].pcm_file_offset; + _li=nlinks-1; + } + OP_ALWAYS_TRUE(!op_granpos_diff(&diff, + links[_li].pcm_end,links[_li].pcm_start)); + return pcm_total+diff-links[_li].head.pre_skip; +} + +const OpusHead *op_head(const OggOpusFile *_of,int _li){ + if(OP_UNLIKELY(_li>=_of->nlinks))_li=_of->nlinks-1; + if(!_of->seekable)_li=0; + return &_of->links[_li<0?_of->cur_link:_li].head; +} + +const OpusTags *op_tags(const OggOpusFile *_of,int _li){ + if(OP_UNLIKELY(_li>=_of->nlinks))_li=_of->nlinks-1; + if(!_of->seekable){ + if(_of->ready_stateready_state!=OP_PARTOPEN){ + return NULL; + } + _li=0; + } + else if(_li<0)_li=_of->ready_state>=OP_STREAMSET?_of->cur_link:0; + return &_of->links[_li].tags; +} + +int op_current_link(const OggOpusFile *_of){ + if(OP_UNLIKELY(_of->ready_statecur_link; +} + +/*Compute an average bitrate given a byte and sample count. + Return: The bitrate in bits per second.*/ +static opus_int32 op_calc_bitrate(opus_int64 _bytes,ogg_int64_t _samples){ + /*These rates are absurd, but let's handle them anyway.*/ + if(OP_UNLIKELY(_bytes>(OP_INT64_MAX-(_samples>>1))/(48000*8))){ + ogg_int64_t den; + if(OP_UNLIKELY(_bytes/(OP_INT32_MAX/(48000*8))>=_samples)){ + return OP_INT32_MAX; + } + den=_samples/(48000*8); + return (opus_int32)((_bytes+(den>>1))/den); + } + if(OP_UNLIKELY(_samples<=0))return OP_INT32_MAX; + /*This can't actually overflow in normal operation: even with a pre-skip of + 545 2.5 ms frames with 8 streams running at 1282*8+1 bytes per packet + (1275 byte frames + Opus framing overhead + Ogg lacing values), that all + produce a single sample of decoded output, we still don't top 45 Mbps. + The only way to get bitrates larger than that is with excessive Opus + padding, more encoded streams than output channels, or lots and lots of + Ogg pages with no packets on them.*/ + return (opus_int32)OP_MIN((_bytes*48000*8+(_samples>>1))/_samples, + OP_INT32_MAX); +} + +opus_int32 op_bitrate(const OggOpusFile *_of,int _li){ + if(OP_UNLIKELY(_of->ready_stateseekable) + ||OP_UNLIKELY(_li>=_of->nlinks)){ + return OP_EINVAL; + } + return op_calc_bitrate(op_raw_total(_of,_li),op_pcm_total(_of,_li)); +} + +opus_int32 op_bitrate_instant(OggOpusFile *_of){ + ogg_int64_t samples_tracked; + opus_int32 ret; + if(OP_UNLIKELY(_of->ready_statesamples_tracked; + if(OP_UNLIKELY(samples_tracked==0))return OP_FALSE; + ret=op_calc_bitrate(_of->bytes_tracked,samples_tracked); + _of->bytes_tracked=0; + _of->samples_tracked=0; + return ret; +} + +/*Given a serialno, find a link with a corresponding Opus stream, if it exists. + Return: The index of the link to which the page belongs, or a negative number + if it was not a desired Opus bitstream section.*/ +static int op_get_link_from_serialno(const OggOpusFile *_of,int _cur_link, + opus_int64 _page_offset,ogg_uint32_t _serialno){ + const OggOpusLink *links; + int nlinks; + int li_lo; + int li_hi; + OP_ASSERT(_of->seekable); + links=_of->links; + nlinks=_of->nlinks; + li_lo=0; + /*Start off by guessing we're just a multiplexed page in the current link.*/ + li_hi=_cur_link+1=links[_cur_link].offset)li_lo=_cur_link; + else li_hi=_cur_link; + _cur_link=li_lo+(li_hi-li_lo>>1); + } + while(li_hi-li_lo>1); + /*We've identified the link that should contain this page. + Make sure it's a page we care about.*/ + if(links[_cur_link].serialno!=_serialno)return OP_FALSE; + return _cur_link; +} + +/*Fetch and process a page. + This handles the case where we're at a bitstream boundary and dumps the + decoding machine. + If the decoding machine is unloaded, it loads it. + It also keeps prev_packet_gp up to date (seek and read both use this). + Return: <0) Error, OP_HOLE (lost packet), or OP_EOF. + 0) Got at least one audio data packet.*/ +static int op_fetch_and_process_page(OggOpusFile *_of, + ogg_page *_og,opus_int64 _page_offset,int _spanp,int _ignore_holes){ + OggOpusLink *links; + ogg_uint32_t cur_serialno; + int seekable; + int cur_link; + int ret; + /*We shouldn't get here if we have unprocessed packets.*/ + OP_ASSERT(_of->ready_stateop_pos>=_of->op_count); + seekable=_of->seekable; + links=_of->links; + cur_link=seekable?_of->cur_link:0; + cur_serialno=links[cur_link].serialno; + /*Handle one page.*/ + for(;;){ + ogg_page og; + OP_ASSERT(_of->ready_state>=OP_OPENED); + /*If we were given a page to use, use it.*/ + if(_og!=NULL){ + *&og=*_og; + _og=NULL; + } + /*Keep reading until we get a page with the correct serialno.*/ + else _page_offset=op_get_next_page(_of,&og,_of->end); + /*EOF: Leave uninitialized.*/ + if(_page_offset<0)return _page_offsetready_state>=OP_STREAMSET) + &&cur_serialno!=(ogg_uint32_t)ogg_page_serialno(&og)){ + /*Two possibilities: + 1) Another stream is multiplexed into this logical section, or*/ + if(OP_LIKELY(!ogg_page_bos(&og)))continue; + /* 2) Our decoding just traversed a bitstream boundary.*/ + if(!_spanp)return OP_EOF; + if(OP_LIKELY(_of->ready_state>=OP_INITSET))op_decode_clear(_of); + } + /*Bitrate tracking: add the header's bytes here. + The body bytes are counted when we consume the packets.*/ + else _of->bytes_tracked+=og.header_len; + /*Do we need to load a new machine before submitting the page? + This is different in the seekable and non-seekable cases. + In the seekable case, we already have all the header information loaded + and cached. + We just initialize the machine with it and continue on our merry way. + In the non-seekable (streaming) case, we'll only be at a boundary if we + just left the previous logical bitstream, and we're now nominally at the + header of the next bitstream.*/ + if(OP_UNLIKELY(_of->ready_state=0&&cur_link<_of->nlinks); + if(links[cur_link].serialno!=serialno){ + /*It wasn't a page from the current link. + Is it from the next one?*/ + if(OP_LIKELY(cur_link+1<_of->nlinks&&links[cur_link+1].serialno== + serialno)){ + cur_link++; + } + else{ + int new_link; + new_link= + op_get_link_from_serialno(_of,cur_link,_page_offset,serialno); + /*Not a desired Opus bitstream section. + Keep trying.*/ + if(new_link<0)continue; + cur_link=new_link; + } + } + cur_serialno=serialno; + _of->cur_link=cur_link; + ogg_stream_reset_serialno(&_of->os,serialno); + _of->ready_state=OP_STREAMSET; + /*If we're at the start of this link, initialize the granule position + and pre-skip tracking.*/ + if(_page_offset<=links[cur_link].data_offset){ + _of->prev_packet_gp=links[cur_link].pcm_start; + _of->prev_page_offset=-1; + _of->cur_discard_count=links[cur_link].head.pre_skip; + /*Ignore a hole at the start of a new link (this is common for + streams joined in the middle) or after seeking.*/ + _ignore_holes=1; + } + } + else{ + do{ + /*We're streaming. + Fetch the two header packets, build the info struct.*/ + ret=op_fetch_headers(_of,&links[0].head,&links[0].tags, + NULL,NULL,NULL,&og); + if(OP_UNLIKELY(ret<0))return ret; + /*op_find_initial_pcm_offset() will suppress any initial hole for us, + so no need to set _ignore_holes.*/ + ret=op_find_initial_pcm_offset(_of,links,&og); + if(OP_UNLIKELY(ret<0))return ret; + _of->links[0].serialno=cur_serialno=_of->os.serialno; + _of->cur_link++; + } + /*If the link was empty, keep going, because we already have the + BOS page of the next one in og.*/ + while(OP_UNLIKELY(ret>0)); + /*If we didn't get any packets out of op_find_initial_pcm_offset(), + keep going (this is possible if end-trimming trimmed them all).*/ + if(_of->op_count<=0)continue; + /*Otherwise, we're done. + TODO: This resets bytes_tracked, which misses the header bytes + already processed by op_find_initial_pcm_offset().*/ + ret=op_make_decode_ready(_of); + if(OP_UNLIKELY(ret<0))return ret; + return 0; + } + } + /*The buffered page is the data we want, and we're ready for it. + Add it to the stream state.*/ + if(OP_UNLIKELY(_of->ready_state==OP_STREAMSET)){ + ret=op_make_decode_ready(_of); + if(OP_UNLIKELY(ret<0))return ret; + } + /*Extract all the packets from the current page.*/ + ogg_stream_pagein(&_of->os,&og); + if(OP_LIKELY(_of->ready_state>=OP_INITSET)){ + opus_int32 total_duration; + int durations[255]; + int op_count; + int report_hole; + report_hole=0; + total_duration=op_collect_audio_packets(_of,durations); + if(OP_UNLIKELY(total_duration<0)){ + /*libogg reported a hole (a gap in the page sequence numbers). + Drain the packets from the page anyway. + If we don't, they'll still be there when we fetch the next page. + Then, when we go to pull out packets, we might get more than 255, + which would overrun our packet buffer.*/ + total_duration=op_collect_audio_packets(_of,durations); + OP_ASSERT(total_duration>=0); + if(!_ignore_holes){ + /*Report the hole to the caller after we finish timestamping the + packets.*/ + report_hole=1; + /*We had lost or damaged pages, so reset our granule position + tracking. + This makes holes behave the same as a small raw seek. + If the next page is the EOS page, we'll discard it (because we + can't perform end trimming properly), and we'll always discard at + least 80 ms of audio (to allow decoder state to re-converge). + We could try to fill in the gap with PLC by looking at timestamps + in the non-EOS case, but that's complicated and error prone and we + can't rely on the timestamps being valid.*/ + _of->prev_packet_gp=-1; + } + } + op_count=_of->op_count; + /*If we found at least one audio data packet, compute per-packet granule + positions for them.*/ + if(op_count>0){ + ogg_int64_t diff; + ogg_int64_t prev_packet_gp; + ogg_int64_t cur_packet_gp; + ogg_int64_t cur_page_gp; + int cur_page_eos; + int pi; + cur_page_gp=_of->op[op_count-1].granulepos; + cur_page_eos=_of->op[op_count-1].e_o_s; + prev_packet_gp=_of->prev_packet_gp; + if(OP_UNLIKELY(prev_packet_gp==-1)){ + opus_int32 cur_discard_count; + /*This is the first call after a raw seek. + Try to reconstruct prev_packet_gp from scratch.*/ + OP_ASSERT(seekable); + if(OP_UNLIKELY(cur_page_eos)){ + /*If the first page we hit after our seek was the EOS page, and + we didn't start from data_offset or before, we don't have + enough information to do end-trimming. + Proceed to the next link, rather than risk playing back some + samples that shouldn't have been played.*/ + _of->op_count=0; + if(report_hole)return OP_HOLE; + continue; + } + /*By default discard 80 ms of data after a seek, unless we seek + into the pre-skip region.*/ + cur_discard_count=80*48; + cur_page_gp=_of->op[op_count-1].granulepos; + /*Try to initialize prev_packet_gp. + If the current page had packets but didn't have a granule + position, or the granule position it had was too small (both + illegal), just use the starting granule position for the link.*/ + prev_packet_gp=links[cur_link].pcm_start; + if(OP_LIKELY(cur_page_gp!=-1)){ + op_granpos_add(&prev_packet_gp,cur_page_gp,-total_duration); + } + if(OP_LIKELY(!op_granpos_diff(&diff, + prev_packet_gp,links[cur_link].pcm_start))){ + opus_int32 pre_skip; + /*If we start at the beginning of the pre-skip region, or we're + at least 80 ms from the end of the pre-skip region, we discard + to the end of the pre-skip region. + Otherwise, we still use the 80 ms default, which will discard + past the end of the pre-skip region.*/ + pre_skip=links[cur_link].head.pre_skip; + if(diff>=0&&diff<=OP_MAX(0,pre_skip-80*48)){ + cur_discard_count=pre_skip-(int)diff; + } + } + _of->cur_discard_count=cur_discard_count; + } + if(OP_UNLIKELY(cur_page_gp==-1)){ + /*This page had completed packets but didn't have a valid granule + position. + This is illegal, but we'll try to handle it by continuing to count + forwards from the previous page.*/ + if(op_granpos_add(&cur_page_gp,prev_packet_gp,total_duration)<0){ + /*The timestamp for this page overflowed.*/ + cur_page_gp=links[cur_link].pcm_end; + } + } + /*If we hit the last page, handle end-trimming.*/ + if(OP_UNLIKELY(cur_page_eos) + &&OP_LIKELY(!op_granpos_diff(&diff,cur_page_gp,prev_packet_gp)) + &&OP_LIKELY(diff0){ + /*If we trimmed the entire packet, stop (the spec says encoders + shouldn't do this, but we support it anyway).*/ + if(OP_UNLIKELY(diff>durations[pi]))break; + cur_packet_gp=cur_page_gp; + /*Move the EOS flag to this packet, if necessary, so we'll trim + the samples during decode.*/ + _of->op[pi].e_o_s=1; + } + else{ + /*Update the granule position as normal.*/ + OP_ALWAYS_TRUE(!op_granpos_add(&cur_packet_gp, + cur_packet_gp,durations[pi])); + } + _of->op[pi].granulepos=cur_packet_gp; + OP_ALWAYS_TRUE(!op_granpos_diff(&diff,cur_page_gp,cur_packet_gp)); + } + } + else{ + /*Propagate timestamps to earlier packets. + op_granpos_add(&prev_packet_gp,prev_packet_gp,total_duration) + should succeed and give prev_packet_gp==cur_page_gp. + But we don't bother to check that, as there isn't much we can do + if it's not true, and it actually will not be true on the first + page after a seek, if there was a continued packet. + The only thing we guarantee is that the start and end granule + positions of the packets are valid, and that they are monotonic + within a page. + They might be completely out of range for this link (we'll check + that elsewhere), or non-monotonic between pages.*/ + if(OP_UNLIKELY(op_granpos_add(&prev_packet_gp, + cur_page_gp,-total_duration)<0)){ + /*The starting timestamp for the first packet on this page + underflowed. + This is illegal, but we ignore it.*/ + prev_packet_gp=0; + } + for(pi=0;pi=0); + OP_ALWAYS_TRUE(!op_granpos_add(&cur_packet_gp, + cur_packet_gp,durations[pi])); + _of->op[pi].granulepos=cur_packet_gp; + } + OP_ASSERT(total_duration==0); + } + _of->prev_packet_gp=prev_packet_gp; + _of->prev_page_offset=_page_offset; + _of->op_count=op_count=pi; + } + if(report_hole)return OP_HOLE; + /*If end-trimming didn't trim all the packets, we're done.*/ + if(op_count>0)return 0; + } + } +} + +int op_raw_seek(OggOpusFile *_of,opus_int64 _pos){ + int ret; + if(OP_UNLIKELY(_of->ready_stateseekable))return OP_ENOSEEK; + if(OP_UNLIKELY(_pos<0)||OP_UNLIKELY(_pos>_of->end))return OP_EINVAL; + /*Clear out any buffered, decoded data.*/ + op_decode_clear(_of); + _of->bytes_tracked=0; + _of->samples_tracked=0; + ret=op_seek_helper(_of,_pos); + if(OP_UNLIKELY(ret<0))return OP_EREAD; + ret=op_fetch_and_process_page(_of,NULL,-1,1,1); + /*If we hit EOF, op_fetch_and_process_page() leaves us uninitialized. + Instead, jump to the end.*/ + if(ret==OP_EOF){ + int cur_link; + op_decode_clear(_of); + cur_link=_of->nlinks-1; + _of->cur_link=cur_link; + _of->prev_packet_gp=_of->links[cur_link].pcm_end; + _of->cur_discard_count=0; + ret=0; + } + return ret; +} + +/*Convert a PCM offset relative to the start of the whole stream to a granule + position in an individual link.*/ +static ogg_int64_t op_get_granulepos(const OggOpusFile *_of, + ogg_int64_t _pcm_offset,int *_li){ + const OggOpusLink *links; + ogg_int64_t duration; + ogg_int64_t pcm_start; + opus_int32 pre_skip; + int nlinks; + int li_lo; + int li_hi; + OP_ASSERT(_pcm_offset>=0); + nlinks=_of->nlinks; + links=_of->links; + li_lo=0; + li_hi=nlinks; + do{ + int li; + li=li_lo+(li_hi-li_lo>>1); + if(links[li].pcm_file_offset<=_pcm_offset)li_lo=li; + else li_hi=li; + } + while(li_hi-li_lo>1); + _pcm_offset-=links[li_lo].pcm_file_offset; + pcm_start=links[li_lo].pcm_start; + pre_skip=links[li_lo].head.pre_skip; + OP_ALWAYS_TRUE(!op_granpos_diff(&duration,links[li_lo].pcm_end,pcm_start)); + duration-=pre_skip; + if(_pcm_offset>=duration)return -1; + _pcm_offset+=pre_skip; + if(OP_UNLIKELY(pcm_start>OP_INT64_MAX-_pcm_offset)){ + /*Adding this amount to the granule position would overflow the positive + half of its 64-bit range. + Since signed overflow is undefined in C, do it in a way the compiler + isn't allowed to screw up.*/ + _pcm_offset-=OP_INT64_MAX-pcm_start+1; + pcm_start=OP_INT64_MIN; + } + pcm_start+=_pcm_offset; + *_li=li_lo; + return pcm_start; +} + +/*A small helper to determine if an Ogg page contains data that continues onto + a subsequent page.*/ +static int op_page_continues(const ogg_page *_og){ + int nlacing; + OP_ASSERT(_og->header_len>=27); + nlacing=_og->header[26]; + OP_ASSERT(_og->header_len>=27+nlacing); + /*This also correctly handles the (unlikely) case of nlacing==0, because + 0!=255.*/ + return _og->header[27+nlacing-1]==255; +} + +/*A small helper to buffer the continued packet data from a page.*/ +static void op_buffer_continued_data(OggOpusFile *_of,ogg_page *_og){ + ogg_packet op; + ogg_stream_pagein(&_of->os,_og); + /*Drain any packets that did end on this page (and ignore holes). + We only care about the continued packet data.*/ + while(ogg_stream_packetout(&_of->os,&op)); +} + +/*This controls how close the target has to be to use the current stream + position to subdivide the initial range. + Two minutes seems to be a good default.*/ +#define OP_CUR_TIME_THRESH (120*48*(opus_int32)1000) + +/*Note: The OP_SMALL_FOOTPRINT #define doesn't (currently) save much code size, + but it's meant to serve as documentation for portions of the seeking + algorithm that are purely optional, to aid others learning from/porting this + code to other contexts.*/ +/*#define OP_SMALL_FOOTPRINT (1)*/ + +/*Search within link _li for the page with the highest granule position + preceding (or equal to) _target_gp. + There is a danger here: missing pages or incorrect frame number information + in the bitstream could make our task impossible. + Account for that (and report it as an error condition).*/ +static int op_pcm_seek_page(OggOpusFile *_of, + ogg_int64_t _target_gp,int _li){ + const OggOpusLink *link; + ogg_page og; + ogg_int64_t pcm_pre_skip; + ogg_int64_t pcm_start; + ogg_int64_t pcm_end; + ogg_int64_t best_gp; + ogg_int64_t diff; + ogg_uint32_t serialno; + opus_int32 pre_skip; + opus_int64 begin; + opus_int64 end; + opus_int64 boundary; + opus_int64 best; + opus_int64 best_start; + opus_int64 page_offset; + opus_int64 d0; + opus_int64 d1; + opus_int64 d2; + int force_bisect; + int buffering; + int ret; + _of->bytes_tracked=0; + _of->samples_tracked=0; + link=_of->links+_li; + best_gp=pcm_start=link->pcm_start; + pcm_end=link->pcm_end; + serialno=link->serialno; + best=best_start=begin=link->data_offset; + page_offset=-1; + buffering=0; + /*We discard the first 80 ms of data after a seek, so seek back that much + farther. + If we can't, simply seek to the beginning of the link.*/ + if(OP_UNLIKELY(op_granpos_add(&_target_gp,_target_gp,-80*48)<0) + ||OP_UNLIKELY(op_granpos_cmp(_target_gp,pcm_start)<0)){ + _target_gp=pcm_start; + } + /*Special case seeking to the start of the link.*/ + pre_skip=link->head.pre_skip; + OP_ALWAYS_TRUE(!op_granpos_add(&pcm_pre_skip,pcm_start,pre_skip)); + if(op_granpos_cmp(_target_gp,pcm_pre_skip)<0)end=boundary=begin; + else{ + end=boundary=link->end_offset; +#if !defined(OP_SMALL_FOOTPRINT) + /*If we were decoding from this link, we can narrow the range a bit.*/ + if(_li==_of->cur_link&&_of->ready_state>=OP_INITSET){ + opus_int64 offset; + int op_count; + op_count=_of->op_count; + /*The only way the offset can be invalid _and_ we can fail the granule + position checks below is if someone changed the contents of the last + page since we read it. + We'd be within our rights to just return OP_EBADLINK in that case, but + we'll simply ignore the current position instead.*/ + offset=_of->offset; + if(op_count>0&&OP_LIKELY(offset<=end)){ + ogg_int64_t gp; + /*Make sure the timestamp is valid. + The granule position might be -1 if we collected the packets from a + page without a granule position after reporting a hole.*/ + gp=_of->op[op_count-1].granulepos; + if(OP_LIKELY(gp!=-1)&&OP_LIKELY(op_granpos_cmp(pcm_start,gp)<0) + &&OP_LIKELY(op_granpos_cmp(pcm_end,gp)>0)){ + OP_ALWAYS_TRUE(!op_granpos_diff(&diff,gp,_target_gp)); + /*We only actually use the current time if either + a) We can cut off at least half the range, or + b) We're seeking sufficiently close to the current position that + it's likely to be informative. + Otherwise it appears using the whole link range to estimate the + first seek location gives better results, on average.*/ + if(diff<0){ + OP_ASSERT(offset>=begin); + if(offset-begin>=end-begin>>1||diff>-OP_CUR_TIME_THRESH){ + best=begin=offset; + best_gp=pcm_start=gp; + /*If we have buffered data from a continued packet, remember the + offset of the previous page's start, so that if we do wind up + having to seek back here later, we can prime the stream with + the continued packet data. + With no continued packet, we remember the end of the page.*/ + best_start=_of->os.body_returned<_of->os.body_fill? + _of->prev_page_offset:best; + /*If there's completed packets and data in the stream state, + prev_page_offset should always be set.*/ + OP_ASSERT(best_start>=0); + /*Buffer any continued packet data starting from here.*/ + buffering=1; + } + } + else{ + ogg_int64_t prev_page_gp; + /*We might get lucky and already have the packet with the target + buffered. + Worth checking. + For very small files (with all of the data in a single page, + generally 1 second or less), we can loop them continuously + without seeking at all.*/ + OP_ALWAYS_TRUE(!op_granpos_add(&prev_page_gp,_of->op[0].granulepos, + -op_get_packet_duration(_of->op[0].packet,_of->op[0].bytes))); + if(op_granpos_cmp(prev_page_gp,_target_gp)<=0){ + /*Don't call op_decode_clear(), because it will dump our + packets.*/ + _of->op_pos=0; + _of->od_buffer_size=0; + _of->prev_packet_gp=prev_page_gp; + /*_of->prev_page_offset already points to the right place.*/ + _of->ready_state=OP_STREAMSET; + return op_make_decode_ready(_of); + } + /*No such luck. + Check if we can cut off at least half the range, though.*/ + if(offset-begin<=end-begin>>1||diffos,serialno); + _of->cur_link=_li; + _of->ready_state=OP_STREAMSET; + /*Initialize the interval size history.*/ + d2=d1=d0=end-begin; + force_bisect=0; + while(begin>1; + d1=d2>>1; + d2=end-begin>>1; + if(force_bisect)bisect=begin+(end-begin>>1); + else{ + ogg_int64_t diff2; + OP_ALWAYS_TRUE(!op_granpos_diff(&diff,_target_gp,pcm_start)); + OP_ALWAYS_TRUE(!op_granpos_diff(&diff2,pcm_end,pcm_start)); + /*Take a (pretty decent) guess.*/ + bisect=begin+op_rescale64(diff,diff2,end-begin)-OP_CHUNK_SIZE; + } + if(bisect-OP_CHUNK_SIZEoffset){ + /*Discard any buffered continued packet data.*/ + if(buffering)ogg_stream_reset(&_of->os); + buffering=0; + page_offset=-1; + ret=op_seek_helper(_of,bisect); + if(OP_UNLIKELY(ret<0))return ret; + } + chunk_size=OP_CHUNK_SIZE; + next_boundary=boundary; + /*Now scan forward and figure out where we landed. + In the ideal case, we will see a page with a granule position at or + before our target, followed by a page with a granule position after our + target (or the end of the search interval). + Then we can just drop out and will have all of the data we need with no + additional seeking. + If we landed too far before, or after, we'll break out and do another + bisection.*/ + while(beginos); + buffering=0; + bisect=OP_MAX(bisect-chunk_size,begin); + ret=op_seek_helper(_of,bisect); + if(OP_UNLIKELY(ret<0))return ret; + /*Bump up the chunk size.*/ + chunk_size=OP_MIN(2*chunk_size,OP_CHUNK_SIZE_MAX); + /*If we did find a page from another stream or without a timestamp, + don't read past it.*/ + boundary=next_boundary; + } + } + else{ + ogg_int64_t gp; + int has_packets; + /*Save the offset of the first page we found after the seek, regardless + of the stream it came from or whether or not it has a timestamp.*/ + next_boundary=OP_MIN(page_offset,next_boundary); + if(serialno!=(ogg_uint32_t)ogg_page_serialno(&og))continue; + has_packets=ogg_page_packets(&og)>0; + /*Force the gp to -1 (as it should be per spec) if no packets end on + this page. + Otherwise we might get confused when we try to pull out a packet + with that timestamp and can't find it.*/ + gp=has_packets?ogg_page_granulepos(&og):-1; + if(gp==-1){ + if(buffering){ + if(OP_LIKELY(!has_packets))ogg_stream_pagein(&_of->os,&og); + else{ + /*If packets did end on this page, but we still didn't have a + valid granule position (in violation of the spec!), stop + buffering continued packet data. + Otherwise we might continue past the packet we actually + wanted.*/ + ogg_stream_reset(&_of->os); + buffering=0; + } + } + continue; + } + if(op_granpos_cmp(gp,_target_gp)<0){ + /*We found a page that ends before our target. + Advance to the raw offset of the next page.*/ + begin=_of->offset; + if(OP_UNLIKELY(op_granpos_cmp(pcm_start,gp)>0) + ||OP_UNLIKELY(op_granpos_cmp(pcm_end,gp)<0)){ + /*Don't let pcm_start get out of range! + That could happen with an invalid timestamp.*/ + break; + } + /*Save the byte offset of the end of the page with this granule + position.*/ + best=best_start=begin; + /*Buffer any data from a continued packet, if necessary. + This avoids the need to seek back here if the next timestamp we + encounter while scanning forward lies after our target.*/ + if(buffering)ogg_stream_reset(&_of->os); + if(op_page_continues(&og)){ + op_buffer_continued_data(_of,&og); + /*If we have a continued packet, remember the offset of this + page's start, so that if we do wind up having to seek back here + later, we can prime the stream with the continued packet data. + With no continued packet, we remember the end of the page.*/ + best_start=page_offset; + } + /*Then force buffering on, so that if a packet starts (but does not + end) on the next page, we still avoid the extra seek back.*/ + buffering=1; + best_gp=pcm_start=gp; + OP_ALWAYS_TRUE(!op_granpos_diff(&diff,_target_gp,pcm_start)); + /*If we're more than a second away from our target, break out and + do another bisection.*/ + if(diff>48000)break; + /*Otherwise, keep scanning forward (do NOT use begin+1).*/ + bisect=begin; + } + else{ + /*We found a page that ends after our target.*/ + /*If we scanned the whole interval before we found it, we're done.*/ + if(bisect<=begin+1)end=begin; + else{ + end=bisect; + /*In later iterations, don't read past the first page we found.*/ + boundary=next_boundary; + /*If we're not making much progress shrinking the interval size, + start forcing straight bisection to limit the worst case.*/ + force_bisect=end-begin>d0*2; + /*Don't let pcm_end get out of range! + That could happen with an invalid timestamp.*/ + if(OP_LIKELY(op_granpos_cmp(pcm_end,gp)>0) + &&OP_LIKELY(op_granpos_cmp(pcm_start,gp)<=0)){ + pcm_end=gp; + } + break; + } + } + } + } + } + /*Found our page.*/ + OP_ASSERT(op_granpos_cmp(best_gp,pcm_start)>=0); + /*Seek, if necessary. + If we were buffering data from a continued packet, we should be able to + continue to scan forward to get the rest of the data (even if + page_offset==-1). + Otherwise, we need to seek back to best_start.*/ + if(!buffering){ + if(best_start!=page_offset){ + page_offset=-1; + ret=op_seek_helper(_of,best_start); + if(OP_UNLIKELY(ret<0))return ret; + } + if(best_startend_offset); + if(OP_UNLIKELY(page_offsetprev_packet_gp=best_gp; + _of->prev_page_offset=best_start; + ret=op_fetch_and_process_page(_of,page_offset<0?NULL:&og,page_offset,0,1); + if(OP_UNLIKELY(ret<0))return OP_EBADLINK; + /*Verify result.*/ + if(OP_UNLIKELY(op_granpos_cmp(_of->prev_packet_gp,_target_gp)>0)){ + return OP_EBADLINK; + } + /*Our caller will set cur_discard_count to handle pre-roll.*/ + return 0; +} + +int op_pcm_seek(OggOpusFile *_of,ogg_int64_t _pcm_offset){ + const OggOpusLink *link; + ogg_int64_t pcm_start; + ogg_int64_t target_gp; + ogg_int64_t prev_packet_gp; + ogg_int64_t skip; + ogg_int64_t diff; + int op_count; + int op_pos; + int ret; + int li; + if(OP_UNLIKELY(_of->ready_stateseekable))return OP_ENOSEEK; + if(OP_UNLIKELY(_pcm_offset<0))return OP_EINVAL; + target_gp=op_get_granulepos(_of,_pcm_offset,&li); + if(OP_UNLIKELY(target_gp==-1))return OP_EINVAL; + link=_of->links+li; + pcm_start=link->pcm_start; + OP_ALWAYS_TRUE(!op_granpos_diff(&_pcm_offset,target_gp,pcm_start)); +#if !defined(OP_SMALL_FOOTPRINT) + /*For small (90 ms or less) forward seeks within the same link, just decode + forward. + This also optimizes the case of seeking to the current position.*/ + if(li==_of->cur_link&&_of->ready_state>=OP_INITSET){ + ogg_int64_t gp; + gp=_of->prev_packet_gp; + if(OP_LIKELY(gp!=-1)){ + ogg_int64_t discard_count; + int nbuffered; + nbuffered=OP_MAX(_of->od_buffer_size-_of->od_buffer_pos,0); + OP_ALWAYS_TRUE(!op_granpos_add(&gp,gp,-nbuffered)); + /*We do _not_ add cur_discard_count to gp. + Otherwise the total amount to discard could grow without bound, and it + would be better just to do a full seek.*/ + if(OP_LIKELY(!op_granpos_diff(&discard_count,target_gp,gp))){ + /*We use a threshold of 90 ms instead of 80, since 80 ms is the + _minimum_ we would have discarded after a full seek. + Assuming 20 ms frames (the default), we'd discard 90 ms on average.*/ + if(discard_count>=0&&OP_UNLIKELY(discard_count<90*48)){ + _of->cur_discard_count=(opus_int32)discard_count; + return 0; + } + } + } + } +#endif + ret=op_pcm_seek_page(_of,target_gp,li); + if(OP_UNLIKELY(ret<0))return ret; + /*Now skip samples until we actually get to our target.*/ + /*Figure out where we should skip to.*/ + if(_pcm_offset<=link->head.pre_skip)skip=0; + else skip=OP_MAX(_pcm_offset-80*48,0); + OP_ASSERT(_pcm_offset-skip>=0); + OP_ASSERT(_pcm_offset-skipop_count; + prev_packet_gp=_of->prev_packet_gp; + for(op_pos=_of->op_pos;op_posop[op_pos].granulepos; + if(OP_LIKELY(!op_granpos_diff(&diff,cur_packet_gp,pcm_start)) + &&diff>skip){ + break; + } + prev_packet_gp=cur_packet_gp; + } + _of->prev_packet_gp=prev_packet_gp; + _of->op_pos=op_pos; + if(op_posskip)return OP_EBADLINK; + OP_ASSERT(_pcm_offset-diffcur_discard_count=(opus_int32)(_pcm_offset-diff); + return 0; +} + +opus_int64 op_raw_tell(const OggOpusFile *_of){ + if(OP_UNLIKELY(_of->ready_stateoffset; +} + +/*Convert a granule position from a given link to a PCM offset relative to the + start of the whole stream. + For unseekable sources, this gets reset to 0 at the beginning of each link.*/ +static ogg_int64_t op_get_pcm_offset(const OggOpusFile *_of, + ogg_int64_t _gp,int _li){ + const OggOpusLink *links; + ogg_int64_t pcm_offset; + links=_of->links; + OP_ASSERT(_li>=0&&_li<_of->nlinks); + pcm_offset=links[_li].pcm_file_offset; + if(_of->seekable&&OP_UNLIKELY(op_granpos_cmp(_gp,links[_li].pcm_end)>0)){ + _gp=links[_li].pcm_end; + } + if(OP_LIKELY(op_granpos_cmp(_gp,links[_li].pcm_start)>0)){ + ogg_int64_t delta; + if(OP_UNLIKELY(op_granpos_diff(&delta,_gp,links[_li].pcm_start)<0)){ + /*This means an unseekable stream claimed to have a page from more than + 2 billion days after we joined.*/ + OP_ASSERT(!_of->seekable); + return OP_INT64_MAX; + } + if(deltaready_stateprev_packet_gp; + if(gp==-1)return 0; + nbuffered=OP_MAX(_of->od_buffer_size-_of->od_buffer_pos,0); + OP_ALWAYS_TRUE(!op_granpos_add(&gp,gp,-nbuffered)); + li=_of->seekable?_of->cur_link:0; + if(op_granpos_add(&gp,gp,_of->cur_discard_count)<0){ + gp=_of->links[li].pcm_end; + } + return op_get_pcm_offset(_of,gp,li); +} + +void op_set_decode_callback(OggOpusFile *_of, + op_decode_cb_func _decode_cb,void *_ctx){ + _of->decode_cb=_decode_cb; + _of->decode_cb_ctx=_ctx; +} + +int op_set_gain_offset(OggOpusFile *_of, + int _gain_type,opus_int32 _gain_offset_q8){ + if(_gain_type!=OP_HEADER_GAIN&&_gain_type!=OP_ALBUM_GAIN + &&_gain_type!=OP_TRACK_GAIN&&_gain_type!=OP_ABSOLUTE_GAIN){ + return OP_EINVAL; + } + _of->gain_type=_gain_type; + /*The sum of header gain and track gain lies in the range [-65536,65534]. + These bounds allow the offset to set the final value to anywhere in the + range [-32768,32767], which is what we'll clamp it to before applying.*/ + _of->gain_offset_q8=OP_CLAMP(-98302,_gain_offset_q8,98303); + op_update_gain(_of); + return 0; +} + +void op_set_dither_enabled(OggOpusFile *_of,int _enabled){ +#if !defined(OP_FIXED_POINT) + _of->dither_disabled=!_enabled; + if(!_enabled)_of->dither_mute=65; +#endif +} + +/*Allocate the decoder scratch buffer. + This is done lazily, since if the user provides large enough buffers, we'll + never need it.*/ +static int op_init_buffer(OggOpusFile *_of){ + int nchannels_max; + if(_of->seekable){ + const OggOpusLink *links; + int nlinks; + int li; + links=_of->links; + nlinks=_of->nlinks; + nchannels_max=1; + for(li=0;liod_buffer=(op_sample *)_ogg_malloc( + sizeof(*_of->od_buffer)*nchannels_max*120*48); + if(_of->od_buffer==NULL)return OP_EFAULT; + return 0; +} + +/*Decode a single packet into the target buffer.*/ +static int op_decode(OggOpusFile *_of,op_sample *_pcm, + const ogg_packet *_op,int _nsamples,int _nchannels){ + int ret; + /*First we try using the application-provided decode callback.*/ + if(_of->decode_cb!=NULL){ +#if defined(OP_FIXED_POINT) + ret=(*_of->decode_cb)(_of->decode_cb_ctx,_of->od,_pcm,_op, + _nsamples,_nchannels,OP_DEC_FORMAT_SHORT,_of->cur_link); +#else + ret=(*_of->decode_cb)(_of->decode_cb_ctx,_of->od,_pcm,_op, + _nsamples,_nchannels,OP_DEC_FORMAT_FLOAT,_of->cur_link); +#endif + } + else ret=OP_DEC_USE_DEFAULT; + /*If the application didn't want to handle decoding, do it ourselves.*/ + if(ret==OP_DEC_USE_DEFAULT){ +#if defined(OP_FIXED_POINT) + ret=opus_multistream_decode(_of->od, + _op->packet,_op->bytes,_pcm,_nsamples,0); +#else + ret=opus_multistream_decode_float(_of->od, + _op->packet,_op->bytes,_pcm,_nsamples,0); +#endif + OP_ASSERT(ret<0||ret==_nsamples); + } + /*If the application returned a positive value other than 0 or + OP_DEC_USE_DEFAULT, fail.*/ + else if(OP_UNLIKELY(ret>0))return OP_EBADPACKET; + if(OP_UNLIKELY(ret<0))return OP_EBADPACKET; + return ret; +} + +/*Read more samples from the stream, using the same API as op_read() or + op_read_float().*/ +static int op_read_native(OggOpusFile *_of, + op_sample *_pcm,int _buf_size,int *_li){ + if(OP_UNLIKELY(_of->ready_stateready_state>=OP_INITSET)){ + int nchannels; + int od_buffer_pos; + int nsamples; + int op_pos; + nchannels=_of->links[_of->seekable?_of->cur_link:0].head.channel_count; + od_buffer_pos=_of->od_buffer_pos; + nsamples=_of->od_buffer_size-od_buffer_pos; + /*If we have buffered samples, return them.*/ + if(nsamples>0){ + if(nsamples*nchannels>_buf_size)nsamples=_buf_size/nchannels; + memcpy(_pcm,_of->od_buffer+nchannels*od_buffer_pos, + sizeof(*_pcm)*nchannels*nsamples); + od_buffer_pos+=nsamples; + _of->od_buffer_pos=od_buffer_pos; + if(_li!=NULL)*_li=_of->cur_link; + return nsamples; + } + /*If we have buffered packets, decode one.*/ + op_pos=_of->op_pos; + if(OP_LIKELY(op_pos<_of->op_count)){ + const ogg_packet *pop; + ogg_int64_t diff; + opus_int32 cur_discard_count; + int duration; + int trimmed_duration; + pop=_of->op+op_pos++; + _of->op_pos=op_pos; + cur_discard_count=_of->cur_discard_count; + duration=op_get_packet_duration(pop->packet,pop->bytes); + /*We don't buffer packets with an invalid TOC sequence.*/ + OP_ASSERT(duration>0); + trimmed_duration=duration; + /*Perform end-trimming.*/ + if(OP_UNLIKELY(pop->e_o_s)){ + if(OP_UNLIKELY(op_granpos_cmp(pop->granulepos, + _of->prev_packet_gp)<=0)){ + trimmed_duration=0; + } + else if(OP_LIKELY(!op_granpos_diff(&diff, + pop->granulepos,_of->prev_packet_gp))){ + trimmed_duration=(int)OP_MIN(diff,trimmed_duration); + } + } + _of->prev_packet_gp=pop->granulepos; + if(OP_UNLIKELY(duration*nchannels>_buf_size)){ + op_sample *buf; + /*If the user's buffer is too small, decode into a scratch buffer.*/ + buf=_of->od_buffer; + if(OP_UNLIKELY(buf==NULL)){ + ret=op_init_buffer(_of); + if(OP_UNLIKELY(ret<0))return ret; + buf=_of->od_buffer; + } + ret=op_decode(_of,buf,pop,duration,nchannels); + if(OP_UNLIKELY(ret<0))return ret; + /*Perform pre-skip/pre-roll.*/ + od_buffer_pos=(int)OP_MIN(trimmed_duration,cur_discard_count); + cur_discard_count-=od_buffer_pos; + _of->cur_discard_count=cur_discard_count; + _of->od_buffer_pos=od_buffer_pos; + _of->od_buffer_size=trimmed_duration; + /*Update bitrate tracking based on the actual samples we used from + what was decoded.*/ + _of->bytes_tracked+=pop->bytes; + _of->samples_tracked+=trimmed_duration-od_buffer_pos; + } + else{ + /*Otherwise decode directly into the user's buffer.*/ + ret=op_decode(_of,_pcm,pop,duration,nchannels); + if(OP_UNLIKELY(ret<0))return ret; + if(OP_LIKELY(trimmed_duration>0)){ + /*Perform pre-skip/pre-roll.*/ + od_buffer_pos=(int)OP_MIN(trimmed_duration,cur_discard_count); + cur_discard_count-=od_buffer_pos; + _of->cur_discard_count=cur_discard_count; + trimmed_duration-=od_buffer_pos; + if(OP_LIKELY(trimmed_duration>0) + &&OP_UNLIKELY(od_buffer_pos>0)){ + memmove(_pcm,_pcm+od_buffer_pos*nchannels, + sizeof(*_pcm)*trimmed_duration*nchannels); + } + /*Update bitrate tracking based on the actual samples we used from + what was decoded.*/ + _of->bytes_tracked+=pop->bytes; + _of->samples_tracked+=trimmed_duration; + if(OP_LIKELY(trimmed_duration>0)){ + if(_li!=NULL)*_li=_of->cur_link; + return trimmed_duration; + } + } + } + /*Don't grab another page yet. + This one might have more packets, or might have buffered data now.*/ + continue; + } + } + /*Suck in another page.*/ + ret=op_fetch_and_process_page(_of,NULL,-1,1,0); + if(OP_UNLIKELY(ret==OP_EOF)){ + if(_li!=NULL)*_li=_of->cur_link; + return 0; + } + if(OP_UNLIKELY(ret<0))return ret; + } +} + +/*A generic filter to apply to the decoded audio data. + _src is non-const because we will destructively modify the contents of the + source buffer that we consume in some cases.*/ +typedef int (*op_read_filter_func)(OggOpusFile *_of,void *_dst,int _dst_sz, + op_sample *_src,int _nsamples,int _nchannels); + +/*Decode some samples and then apply a custom filter to them. + This is used to convert to different output formats.*/ +static int op_filter_read_native(OggOpusFile *_of,void *_dst,int _dst_sz, + op_read_filter_func _filter,int *_li){ + int ret; + /*Ensure we have some decoded samples in our buffer.*/ + ret=op_read_native(_of,NULL,0,_li); + /*Now apply the filter to them.*/ + if(OP_LIKELY(ret>=0)&&OP_LIKELY(_of->ready_state>=OP_INITSET)){ + int od_buffer_pos; + od_buffer_pos=_of->od_buffer_pos; + ret=_of->od_buffer_size-od_buffer_pos; + if(OP_LIKELY(ret>0)){ + int nchannels; + nchannels=_of->links[_of->seekable?_of->cur_link:0].head.channel_count; + ret=(*_filter)(_of,_dst,_dst_sz, + _of->od_buffer+nchannels*od_buffer_pos,ret,nchannels); + OP_ASSERT(ret>=0); + OP_ASSERT(ret<=_of->od_buffer_size-od_buffer_pos); + od_buffer_pos+=ret; + _of->od_buffer_pos=od_buffer_pos; + } + } + return ret; +} + +#if !defined(OP_FIXED_POINT)||!defined(OP_DISABLE_FLOAT_API) + +/*Matrices for downmixing from the supported channel counts to stereo. + The matrices with 5 or more channels are normalized to a total volume of 2.0, + since most mixes sound too quiet if normalized to 1.0 (as there is generally + little volume in the side/rear channels).*/ +static const float OP_STEREO_DOWNMIX[OP_NCHANNELS_MAX-2][OP_NCHANNELS_MAX][2]={ + /*3.0*/ + { + {0.5858F,0.0F},{0.4142F,0.4142F},{0.0F,0.5858F} + }, + /*quadrophonic*/ + { + {0.4226F,0.0F},{0.0F,0.4226F},{0.366F,0.2114F},{0.2114F,0.336F} + }, + /*5.0*/ + { + {0.651F,0.0F},{0.46F,0.46F},{0.0F,0.651F},{0.5636F,0.3254F}, + {0.3254F,0.5636F} + }, + /*5.1*/ + { + {0.529F,0.0F},{0.3741F,0.3741F},{0.0F,0.529F},{0.4582F,0.2645F}, + {0.2645F,0.4582F},{0.3741F,0.3741F} + }, + /*6.1*/ + { + {0.4553F,0.0F},{0.322F,0.322F},{0.0F,0.4553F},{0.3943F,0.2277F}, + {0.2277F,0.3943F},{0.2788F,0.2788F},{0.322F,0.322F} + }, + /*7.1*/ + { + {0.3886F,0.0F},{0.2748F,0.2748F},{0.0F,0.3886F},{0.3366F,0.1943F}, + {0.1943F,0.3366F},{0.3366F,0.1943F},{0.1943F,0.3366F},{0.2748F,0.2748F} + } +}; + +#endif + +#if defined(OP_FIXED_POINT) + +/*Matrices for downmixing from the supported channel counts to stereo. + The matrices with 5 or more channels are normalized to a total volume of 2.0, + since most mixes sound too quiet if normalized to 1.0 (as there is generally + little volume in the side/rear channels). + Hence we keep the coefficients in Q14, so the downmix values won't overflow a + 32-bit number.*/ +static const opus_int16 OP_STEREO_DOWNMIX_Q14 + [OP_NCHANNELS_MAX-2][OP_NCHANNELS_MAX][2]={ + /*3.0*/ + { + {9598,0},{6786,6786},{0,9598} + }, + /*quadrophonic*/ + { + {6924,0},{0,6924},{5996,3464},{3464,5996} + }, + /*5.0*/ + { + {10666,0},{7537,7537},{0,10666},{9234,5331},{5331,9234} + }, + /*5.1*/ + { + {8668,0},{6129,6129},{0,8668},{7507,4335},{4335,7507},{6129,6129} + }, + /*6.1*/ + { + {7459,0},{5275,5275},{0,7459},{6460,3731},{3731,6460},{4568,4568}, + {5275,5275} + }, + /*7.1*/ + { + {6368,0},{4502,4502},{0,6368},{5515,3183},{3183,5515},{5515,3183}, + {3183,5515},{4502,4502} + } +}; + +int op_read(OggOpusFile *_of,opus_int16 *_pcm,int _buf_size,int *_li){ + return op_read_native(_of,_pcm,_buf_size,_li); +} + +static int op_stereo_filter(OggOpusFile *_of,void *_dst,int _dst_sz, + op_sample *_src,int _nsamples,int _nchannels){ + (void)_of; + _nsamples=OP_MIN(_nsamples,_dst_sz>>1); + if(_nchannels==2)memcpy(_dst,_src,_nsamples*2*sizeof(*_src)); + else{ + opus_int16 *dst; + int i; + dst=(opus_int16 *)_dst; + if(_nchannels==1){ + for(i=0;i<_nsamples;i++)dst[2*i+0]=dst[2*i+1]=_src[i]; + } + else{ + for(i=0;i<_nsamples;i++){ + opus_int32 l; + opus_int32 r; + int ci; + l=r=0; + for(ci=0;ci<_nchannels;ci++){ + opus_int32 s; + s=_src[_nchannels*i+ci]; + l+=OP_STEREO_DOWNMIX_Q14[_nchannels-3][ci][0]*s; + r+=OP_STEREO_DOWNMIX_Q14[_nchannels-3][ci][1]*s; + } + /*TODO: For 5 or more channels, we should do soft clipping here.*/ + dst[2*i+0]=(opus_int16)OP_CLAMP(-32768,l+8192>>14,32767); + dst[2*i+1]=(opus_int16)OP_CLAMP(-32768,r+8192>>14,32767); + } + } + } + return _nsamples; +} + +int op_read_stereo(OggOpusFile *_of,opus_int16 *_pcm,int _buf_size){ + return op_filter_read_native(_of,_pcm,_buf_size,op_stereo_filter,NULL); +} + +# if !defined(OP_DISABLE_FLOAT_API) + +static int op_short2float_filter(OggOpusFile *_of,void *_dst,int _dst_sz, + op_sample *_src,int _nsamples,int _nchannels){ + float *dst; + int i; + (void)_of; + dst=(float *)_dst; + if(OP_UNLIKELY(_nsamples*_nchannels>_dst_sz))_nsamples=_dst_sz/_nchannels; + _dst_sz=_nsamples*_nchannels; + for(i=0;i<_dst_sz;i++)dst[i]=(1.0F/32768)*_src[i]; + return _nsamples; +} + +int op_read_float(OggOpusFile *_of,float *_pcm,int _buf_size,int *_li){ + return op_filter_read_native(_of,_pcm,_buf_size,op_short2float_filter,_li); +} + +static int op_short2float_stereo_filter(OggOpusFile *_of, + void *_dst,int _dst_sz,op_sample *_src,int _nsamples,int _nchannels){ + float *dst; + int i; + dst=(float *)_dst; + _nsamples=OP_MIN(_nsamples,_dst_sz>>1); + if(_nchannels==1){ + _nsamples=op_short2float_filter(_of,dst,_nsamples,_src,_nsamples,1); + for(i=_nsamples;i-->0;)dst[2*i+0]=dst[2*i+1]=dst[i]; + } + else if(_nchannels<5){ + /*For 3 or 4 channels, we can downmix in fixed point without risk of + clipping.*/ + if(_nchannels>2){ + _nsamples=op_stereo_filter(_of,_src,_nsamples*2, + _src,_nsamples,_nchannels); + } + return op_short2float_filter(_of,dst,_dst_sz,_src,_nsamples,2); + } + else{ + /*For 5 or more channels, we convert to floats and then downmix (so that we + don't risk clipping).*/ + for(i=0;i<_nsamples;i++){ + float l; + float r; + int ci; + l=r=0; + for(ci=0;ci<_nchannels;ci++){ + float s; + s=(1.0F/32768)*_src[_nchannels*i+ci]; + l+=OP_STEREO_DOWNMIX[_nchannels-3][ci][0]*s; + r+=OP_STEREO_DOWNMIX[_nchannels-3][ci][1]*s; + } + dst[2*i+0]=l; + dst[2*i+1]=r; + } + } + return _nsamples; +} + +int op_read_float_stereo(OggOpusFile *_of,float *_pcm,int _buf_size){ + return op_filter_read_native(_of,_pcm,_buf_size, + op_short2float_stereo_filter,NULL); +} + +# endif + +#else + +# if defined(OP_HAVE_LRINTF) +# include +# define op_float2int(_x) (lrintf(_x)) +# else +# define op_float2int(_x) ((int)((_x)+((_x)<0?-0.5F:0.5F))) +# endif + +/*The dithering code here is adapted from opusdec, part of opus-tools. + It was originally written by Greg Maxwell.*/ + +static opus_uint32 op_rand(opus_uint32 _seed){ + return _seed*96314165+907633515&0xFFFFFFFFU; +} + +/*This implements 16-bit quantization with full triangular dither and IIR noise + shaping. + The noise shaping filters were designed by Sebastian Gesemann, and are based + on the LAME ATH curves with flattening to limit their peak gain to 20 dB. + Everyone else's noise shaping filters are mildly crazy. + The 48 kHz version of this filter is just a warped version of the 44.1 kHz + filter and probably could be improved by shifting the HF shelf up in + frequency a little bit, since 48 kHz has a bit more room and being more + conservative against bat-ears is probably more important than more noise + suppression. + This process can increase the peak level of the signal (in theory by the peak + error of 1.5 +20 dB, though that is unobservably rare). + To avoid clipping, the signal is attenuated by a couple thousandths of a dB. + Initially, the approach taken here was to only attenuate by the 99.9th + percentile, making clipping rare but not impossible (like SoX), but the + limited gain of the filter means that the worst case was only two + thousandths of a dB more, so this just uses the worst case. + The attenuation is probably also helpful to prevent clipping in the DAC + reconstruction filters or downstream resampling, in any case.*/ + +# define OP_GAIN (32753.0F) + +# define OP_PRNG_GAIN (1.0F/0xFFFFFFFF) + +/*48 kHz noise shaping filter, sd=2.34.*/ + +static const float OP_FCOEF_B[4]={ + 2.2374F,-0.7339F,-0.1251F,-0.6033F +}; + +static const float OP_FCOEF_A[4]={ + 0.9030F,0.0116F,-0.5853F,-0.2571F +}; + +static int op_float2short_filter(OggOpusFile *_of,void *_dst,int _dst_sz, + float *_src,int _nsamples,int _nchannels){ + opus_int16 *dst; + int ci; + int i; + dst=(opus_int16 *)_dst; + if(OP_UNLIKELY(_nsamples*_nchannels>_dst_sz))_nsamples=_dst_sz/_nchannels; +# if defined(OP_SOFT_CLIP) + if(_of->state_channel_count!=_nchannels){ + for(ci=0;ci<_nchannels;ci++)_of->clip_state[ci]=0; + } + opus_pcm_soft_clip(_src,_nsamples,_nchannels,_of->clip_state); +# endif + if(_of->dither_disabled){ + for(i=0;i<_nchannels*_nsamples;i++){ + dst[i]=op_float2int(OP_CLAMP(-32768,32768.0F*_src[i],32767)); + } + } + else{ + opus_uint32 seed; + int mute; + seed=_of->dither_seed; + mute=_of->dither_mute; + if(_of->state_channel_count!=_nchannels)mute=65; + /*In order to avoid replacing digital silence with quiet dither noise, we + mute if the output has been silent for a while.*/ + if(mute>64)memset(_of->dither_a,0,sizeof(*_of->dither_a)*4*_nchannels); + for(i=0;i<_nsamples;i++){ + int silent; + silent=1; + for(ci=0;ci<_nchannels;ci++){ + float r; + float s; + float err; + int si; + int j; + s=_src[_nchannels*i+ci]; + silent&=s==0; + s*=OP_GAIN; + err=0; + for(j=0;j<4;j++){ + err+=OP_FCOEF_B[j]*_of->dither_b[ci*4+j] + -OP_FCOEF_A[j]*_of->dither_a[ci*4+j]; + } + for(j=3;j-->0;)_of->dither_a[ci*4+j+1]=_of->dither_a[ci*4+j]; + for(j=3;j-->0;)_of->dither_b[ci*4+j+1]=_of->dither_b[ci*4+j]; + _of->dither_a[ci*4]=err; + s-=err; + if(mute>16)r=0; + else{ + seed=op_rand(seed); + r=seed*OP_PRNG_GAIN; + seed=op_rand(seed); + r-=seed*OP_PRNG_GAIN; + } + /*Clamp in float out of paranoia that the input will be > 96 dBFS and + wrap if the integer is clamped.*/ + si=op_float2int(OP_CLAMP(-32768,s+r,32767)); + dst[_nchannels*i+ci]=(opus_int16)si; + /*Including clipping in the noise shaping is generally disastrous: the + futile effort to restore the clipped energy results in more clipping. + However, small amounts---at the level which could normally be created + by dither and rounding---are harmless and can even reduce clipping + somewhat due to the clipping sometimes reducing the dither + rounding + error.*/ + _of->dither_b[ci*4]=mute>16?0:OP_CLAMP(-1.5F,si-s,1.5F); + } + mute++; + if(!silent)mute=0; + } + _of->dither_mute=OP_MIN(mute,65); + _of->dither_seed=seed; + } + _of->state_channel_count=_nchannels; + return _nsamples; +} + +int op_read(OggOpusFile *_of,opus_int16 *_pcm,int _buf_size,int *_li){ + return op_filter_read_native(_of,_pcm,_buf_size,op_float2short_filter,_li); +} + +int op_read_float(OggOpusFile *_of,float *_pcm,int _buf_size,int *_li){ + _of->state_channel_count=0; + return op_read_native(_of,_pcm,_buf_size,_li); +} + +static int op_stereo_filter(OggOpusFile *_of,void *_dst,int _dst_sz, + op_sample *_src,int _nsamples,int _nchannels){ + (void)_of; + _nsamples=OP_MIN(_nsamples,_dst_sz>>1); + if(_nchannels==2)memcpy(_dst,_src,_nsamples*2*sizeof(*_src)); + else{ + float *dst; + int i; + dst=(float *)_dst; + if(_nchannels==1){ + for(i=0;i<_nsamples;i++)dst[2*i+0]=dst[2*i+1]=_src[i]; + } + else{ + for(i=0;i<_nsamples;i++){ + float l; + float r; + int ci; + l=r=0; + for(ci=0;ci<_nchannels;ci++){ + l+=OP_STEREO_DOWNMIX[_nchannels-3][ci][0]*_src[_nchannels*i+ci]; + r+=OP_STEREO_DOWNMIX[_nchannels-3][ci][1]*_src[_nchannels*i+ci]; + } + dst[2*i+0]=l; + dst[2*i+1]=r; + } + } + } + return _nsamples; +} + +static int op_float2short_stereo_filter(OggOpusFile *_of, + void *_dst,int _dst_sz,op_sample *_src,int _nsamples,int _nchannels){ + opus_int16 *dst; + dst=(opus_int16 *)_dst; + if(_nchannels==1){ + int i; + _nsamples=op_float2short_filter(_of,dst,_dst_sz>>1,_src,_nsamples,1); + for(i=_nsamples;i-->0;)dst[2*i+0]=dst[2*i+1]=dst[i]; + } + else{ + if(_nchannels>2){ + _nsamples=OP_MIN(_nsamples,_dst_sz>>1); + _nsamples=op_stereo_filter(_of,_src,_nsamples*2, + _src,_nsamples,_nchannels); + } + _nsamples=op_float2short_filter(_of,dst,_dst_sz,_src,_nsamples,2); + } + return _nsamples; +} + +int op_read_stereo(OggOpusFile *_of,opus_int16 *_pcm,int _buf_size){ + return op_filter_read_native(_of,_pcm,_buf_size, + op_float2short_stereo_filter,NULL); +} + +int op_read_float_stereo(OggOpusFile *_of,float *_pcm,int _buf_size){ + _of->state_channel_count=0; + return op_filter_read_native(_of,_pcm,_buf_size,op_stereo_filter,NULL); +} + +#endif diff --git a/extern/opusfile/src/stream.c b/extern/opusfile/src/stream.c new file mode 100644 index 0000000..6a85197 --- /dev/null +++ b/extern/opusfile/src/stream.c @@ -0,0 +1,364 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE libopusfile SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE libopusfile SOURCE CODE IS (C) COPYRIGHT 1994-2012 * + * by the Xiph.Org Foundation and contributors http://www.xiph.org/ * + * * + ******************************************************************** + + function: stdio-based convenience library for opening/seeking/decoding + last mod: $Id: vorbisfile.c 17573 2010-10-27 14:53:59Z xiphmont $ + + ********************************************************************/ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "internal.h" +#include +#include +#include +#include +#include +#if defined(_WIN32) +# include +#endif + +typedef struct OpusMemStream OpusMemStream; + +#define OP_MEM_SIZE_MAX (~(size_t)0>>1) +#define OP_MEM_DIFF_MAX ((ptrdiff_t)OP_MEM_SIZE_MAX) + +/*The context information needed to read from a block of memory as if it were a + file.*/ +struct OpusMemStream{ + /*The block of memory to read from.*/ + const unsigned char *data; + /*The total size of the block. + This must be at most OP_MEM_SIZE_MAX to prevent signed overflow while + seeking.*/ + ptrdiff_t size; + /*The current file position. + This is allowed to be set arbitrarily greater than size (i.e., past the end + of the block, though we will not read data past the end of the block), but + is not allowed to be negative (i.e., before the beginning of the block).*/ + ptrdiff_t pos; +}; + +static int op_fread(void *_stream,unsigned char *_ptr,int _buf_size){ + FILE *stream; + size_t ret; + /*Check for empty read.*/ + if(_buf_size<=0)return 0; + stream=(FILE *)_stream; + ret=fread(_ptr,1,_buf_size,stream); + OP_ASSERT(ret<=(size_t)_buf_size); + /*If ret==0 and !feof(stream), there was a read error.*/ + return ret>0||feof(stream)?(int)ret:OP_EREAD; +} + +static int op_fseek(void *_stream,opus_int64 _offset,int _whence){ +#if defined(_WIN32) + /*_fseeki64() is not exposed until MSCVCRT80. + This is the default starting with MSVC 2005 (_MSC_VER>=1400), but we want + to allow linking against older MSVCRT versions for compatibility back to + XP without installing extra runtime libraries. + i686-pc-mingw32 does not have fseeko() and requires + __MSVCRT_VERSION__>=0x800 for _fseeki64(), which screws up linking with + other libraries (that don't use MSVCRT80 from MSVC 2005 by default). + i686-w64-mingw32 does have fseeko() and respects _FILE_OFFSET_BITS, but I + don't know how to detect that at compile time. + We could just use fseeko64() (which is available in both), but its + implemented using fgetpos()/fsetpos() just like this code, except without + the overflow checking, so we prefer our version.*/ + opus_int64 pos; + /*We don't use fpos_t directly because it might be a struct if __STDC__ is + non-zero or _INTEGRAL_MAX_BITS < 64. + I'm not certain when the latter is true, but someone could in theory set + the former. + Either way, it should be binary compatible with a normal 64-bit int (this + assumption is not portable, but I believe it is true for MSVCRT).*/ + OP_ASSERT(sizeof(pos)==sizeof(fpos_t)); + /*Translate the seek to an absolute one.*/ + if(_whence==SEEK_CUR){ + int ret; + ret=fgetpos((FILE *)_stream,(fpos_t *)&pos); + if(ret)return ret; + } + else if(_whence==SEEK_END)pos=_filelengthi64(_fileno((FILE *)_stream)); + else if(_whence==SEEK_SET)pos=0; + else return -1; + /*Check for errors or overflow.*/ + if(pos<0||_offset<-pos||_offset>OP_INT64_MAX-pos)return -1; + pos+=_offset; + return fsetpos((FILE *)_stream,(fpos_t *)&pos); +#else + /*This function actually conforms to the SUSv2 and POSIX.1-2001, so we prefer + it except on Windows.*/ + return fseeko((FILE *)_stream,(off_t)_offset,_whence); +#endif +} + +static opus_int64 op_ftell(void *_stream){ +#if defined(_WIN32) + /*_ftelli64() is not exposed until MSCVCRT80, and ftello()/ftello64() have + the same problems as fseeko()/fseeko64() in MingW. + See above for a more detailed explanation.*/ + opus_int64 pos; + OP_ASSERT(sizeof(pos)==sizeof(fpos_t)); + return fgetpos((FILE *)_stream,(fpos_t *)&pos)?-1:pos; +#else + /*This function actually conforms to the SUSv2 and POSIX.1-2001, so we prefer + it except on Windows.*/ + return ftello((FILE *)_stream); +#endif +} + +static const OpusFileCallbacks OP_FILE_CALLBACKS={ + op_fread, + op_fseek, + op_ftell, + (op_close_func)fclose +}; + +#if defined(_WIN32) +# include +# include + +/*Windows doesn't accept UTF-8 by default, and we don't have a wchar_t API, + so if we just pass the path to fopen(), then there'd be no way for a user + of our API to open a Unicode filename. + Instead, we translate from UTF-8 to UTF-16 and use Windows' wchar_t API. + This makes this API more consistent with platforms where the character set + used by fopen is the same as used on disk, which is generally UTF-8, and + with our metadata API, which always uses UTF-8.*/ +static wchar_t *op_utf8_to_utf16(const char *_src){ + wchar_t *dst; + size_t len; + len=strlen(_src); + /*Worst-case output is 1 wide character per 1 input character.*/ + dst=(wchar_t *)_ogg_malloc(sizeof(*dst)*(len+1)); + if(dst!=NULL){ + size_t si; + size_t di; + for(di=si=0;si=0x80U){ + /*This is a 2-byte sequence that is not overlong.*/ + dst[di++]=w; + si++; + continue; + } + } + else{ + int c2; + /*This is safe, because c1 was not 0 and _src is NUL-terminated.*/ + c2=(unsigned char)_src[si+2]; + if((c2&0xC0)==0x80){ + /*Found at least two continuation bytes.*/ + if((c0&0xF0)==0xE0){ + wchar_t w; + /*Start byte says this is a 3-byte sequence.*/ + w=(c0&0xF)<<12|(c1&0x3F)<<6|c2&0x3F; + if(w>=0x800U&&(w<0xD800||w>=0xE000)&&w<0xFFFE){ + /*This is a 3-byte sequence that is not overlong, not a + UTF-16 surrogate pair value, and not a 'not a character' + value.*/ + dst[di++]=w; + si+=2; + continue; + } + } + else{ + int c3; + /*This is safe, because c2 was not 0 and _src is + NUL-terminated.*/ + c3=(unsigned char)_src[si+3]; + if((c3&0xC0)==0x80){ + /*Found at least three continuation bytes.*/ + if((c0&0xF8)==0xF0){ + opus_uint32 w; + /*Start byte says this is a 4-byte sequence.*/ + w=(c0&7)<<18|(c1&0x3F)<<12|(c2&0x3F)<<6&(c3&0x3F); + if(w>=0x10000U&&w<0x110000U){ + /*This is a 4-byte sequence that is not overlong and not + greater than the largest valid Unicode code point. + Convert it to a surrogate pair.*/ + w-=0x10000; + dst[di++]=(wchar_t)(0xD800+(w>>10)); + dst[di++]=(wchar_t)(0xDC00+(w&0x3FF)); + si+=3; + continue; + } + } + } + } + } + } + } + } + /*If we got here, we encountered an illegal UTF-8 sequence.*/ + _ogg_free(dst); + return NULL; + } + OP_ASSERT(di<=len); + dst[di]='\0'; + } + return dst; +} + +#endif + +void *op_fopen(OpusFileCallbacks *_cb,const char *_path,const char *_mode){ + FILE *fp; +#if !defined(_WIN32) + fp=fopen(_path,_mode); +#else + fp=NULL; + { + wchar_t *wpath; + wchar_t *wmode; + wpath=op_utf8_to_utf16(_path); + wmode=op_utf8_to_utf16(_mode); + if(wmode==NULL)errno=EINVAL; + else if(wpath==NULL)errno=ENOENT; + else fp=_wfopen(wpath,wmode); + _ogg_free(wmode); + _ogg_free(wpath); + } +#endif + if(fp!=NULL)*_cb=*&OP_FILE_CALLBACKS; + return fp; +} + +void *op_fdopen(OpusFileCallbacks *_cb,int _fd,const char *_mode){ + FILE *fp; + fp=fdopen(_fd,_mode); + if(fp!=NULL)*_cb=*&OP_FILE_CALLBACKS; + return fp; +} + +void *op_freopen(OpusFileCallbacks *_cb,const char *_path,const char *_mode, + void *_stream){ + FILE *fp; +#if !defined(_WIN32) + fp=freopen(_path,_mode,(FILE *)_stream); +#else + fp=NULL; + { + wchar_t *wpath; + wchar_t *wmode; + wpath=op_utf8_to_utf16(_path); + wmode=op_utf8_to_utf16(_mode); + if(wmode==NULL)errno=EINVAL; + else if(wpath==NULL)errno=ENOENT; + else fp=_wfreopen(wpath,wmode,(FILE *)_stream); + _ogg_free(wmode); + _ogg_free(wpath); + } +#endif + if(fp!=NULL)*_cb=*&OP_FILE_CALLBACKS; + return fp; +} + +static int op_mem_read(void *_stream,unsigned char *_ptr,int _buf_size){ + OpusMemStream *stream; + ptrdiff_t size; + ptrdiff_t pos; + stream=(OpusMemStream *)_stream; + /*Check for empty read.*/ + if(_buf_size<=0)return 0; + size=stream->size; + pos=stream->pos; + /*Check for EOF.*/ + if(pos>=size)return 0; + /*Check for a short read.*/ + _buf_size=(int)OP_MIN(size-pos,_buf_size); + memcpy(_ptr,stream->data+pos,_buf_size); + pos+=_buf_size; + stream->pos=pos; + return _buf_size; +} + +static int op_mem_seek(void *_stream,opus_int64 _offset,int _whence){ + OpusMemStream *stream; + ptrdiff_t pos; + stream=(OpusMemStream *)_stream; + pos=stream->pos; + OP_ASSERT(pos>=0); + switch(_whence){ + case SEEK_SET:{ + /*Check for overflow:*/ + if(_offset<0||_offset>OP_MEM_DIFF_MAX)return -1; + pos=(ptrdiff_t)_offset; + }break; + case SEEK_CUR:{ + /*Check for overflow:*/ + if(_offset<-pos||_offset>OP_MEM_DIFF_MAX-pos)return -1; + pos=(ptrdiff_t)(pos+_offset); + }break; + case SEEK_END:{ + ptrdiff_t size; + size=stream->size; + OP_ASSERT(size>=0); + /*Check for overflow:*/ + if(_offset>size||_offsetpos=pos; + return 0; +} + +static opus_int64 op_mem_tell(void *_stream){ + OpusMemStream *stream; + stream=(OpusMemStream *)_stream; + return (ogg_int64_t)stream->pos; +} + +static int op_mem_close(void *_stream){ + _ogg_free(_stream); + return 0; +} + +static const OpusFileCallbacks OP_MEM_CALLBACKS={ + op_mem_read, + op_mem_seek, + op_mem_tell, + op_mem_close +}; + +void *op_mem_stream_create(OpusFileCallbacks *_cb, + const unsigned char *_data,size_t _size){ + OpusMemStream *stream; + if(_size>OP_MEM_SIZE_MAX)return NULL; + stream=(OpusMemStream *)_ogg_malloc(sizeof(*stream)); + if(stream!=NULL){ + *_cb=*&OP_MEM_CALLBACKS; + stream->data=_data; + stream->size=_size; + stream->pos=0; + } + return stream; +} diff --git a/extern/opusfile/src/wincerts.c b/extern/opusfile/src/wincerts.c new file mode 100644 index 0000000..7f915bd --- /dev/null +++ b/extern/opusfile/src/wincerts.c @@ -0,0 +1,173 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE libopusfile SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE libopusfile SOURCE CODE IS (C) COPYRIGHT 2013 * + * by the Xiph.Org Foundation and contributors http://www.xiph.org/ * + * * + ********************************************************************/ + +/*This should really be part of OpenSSL, but there's been a patch [1] sitting + in their bugtracker for over two years that implements this, without any + action, so I'm giving up and re-implementing it locally. + + [1] */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "internal.h" +#if defined(OP_ENABLE_HTTP)&&defined(_WIN32) +/*You must include windows.h before wincrypt.h and x509.h.*/ +# define WIN32_LEAN_AND_MEAN +# define WIN32_EXTRA_LEAN +# include +/*You must include wincrypt.h before x509.h, too, or X509_NAME doesn't get + defined properly.*/ +# include +# include +# include +# include + +static int op_capi_new(X509_LOOKUP *_lu){ + HCERTSTORE h_store; + h_store=CertOpenStore(CERT_STORE_PROV_SYSTEM_A,0,0, + CERT_STORE_OPEN_EXISTING_FLAG|CERT_STORE_READONLY_FLAG| + CERT_SYSTEM_STORE_CURRENT_USER|CERT_STORE_SHARE_CONTEXT_FLAG,"ROOT"); + if(h_store!=NULL){ + _lu->method_data=(char *)h_store; + return 1; + } + return 0; +} + +static void op_capi_free(X509_LOOKUP *_lu){ + HCERTSTORE h_store; + h_store=(HCERTSTORE)_lu->method_data; +# if defined(OP_ENABLE_ASSERTIONS) + OP_ALWAYS_TRUE(CertCloseStore(h_store,CERT_CLOSE_STORE_CHECK_FLAG)); +# else + CertCloseStore(h_store,0); +# endif +} + +static int op_capi_retrieve_by_subject(X509_LOOKUP *_lu,int _type, + X509_NAME *_name,X509_OBJECT *_ret){ + X509_OBJECT *obj; + CRYPTO_w_lock(CRYPTO_LOCK_X509_STORE); + obj=X509_OBJECT_retrieve_by_subject(_lu->store_ctx->objs,_type,_name); + CRYPTO_w_unlock(CRYPTO_LOCK_X509_STORE); + if(obj!=NULL){ + _ret->type=obj->type; + memcpy(&_ret->data,&obj->data,sizeof(_ret->data)); + return 1; + } + return 0; +} + +static int op_capi_get_by_subject(X509_LOOKUP *_lu,int _type,X509_NAME *_name, + X509_OBJECT *_ret){ + HCERTSTORE h_store; + if(_name==NULL)return 0; + if(_name->bytes==NULL||_name->bytes->length<=0||_name->modified){ + if(i2d_X509_NAME(_name,NULL)<0)return 0; + OP_ASSERT(_name->bytes->length>0); + } + h_store=(HCERTSTORE)_lu->method_data; + switch(_type){ + case X509_LU_X509:{ + CERT_NAME_BLOB find_para; + PCCERT_CONTEXT cert; + X509 *x; + int ret; + /*Although X509_NAME contains a canon_enc field, that "canonical" [1] + encoding was just made up by OpenSSL. + It doesn't correspond to any actual standard, and since it drops the + initial sequence header, won't be recognized by the Crypto API. + The assumption here is that CertFindCertificateInStore() will allow any + appropriate variations in the encoding when it does its comparison. + This is, however, emphatically not true under Wine, which just compares + the encodings with memcmp(). + Most of the time things work anyway, though, and there isn't really + anything we can do to make the situation better. + + [1] A "canonical form" is defined as the one where, if you locked 10 + mathematicians in a room and asked them to come up with a + representation for something, it's the answer that 9 of them would + give you back. + I don't think OpenSSL's encoding qualifies.*/ + if(OP_UNLIKELY(_name->bytes->length>MAXDWORD))return 0; + find_para.cbData=(DWORD)_name->bytes->length; + find_para.pbData=(unsigned char *)_name->bytes->data; + cert=CertFindCertificateInStore(h_store,X509_ASN_ENCODING,0, + CERT_FIND_SUBJECT_NAME,&find_para,NULL); + if(cert==NULL)return 0; + x=d2i_X509(NULL,(const unsigned char **)&cert->pbCertEncoded, + cert->cbCertEncoded); + CertFreeCertificateContext(cert); + if(x==NULL)return 0; + ret=X509_STORE_add_cert(_lu->store_ctx,x); + X509_free(x); + if(ret)return op_capi_retrieve_by_subject(_lu,_type,_name,_ret); + }break; + case X509_LU_CRL:{ + CERT_INFO cert_info; + CERT_CONTEXT find_para; + PCCRL_CONTEXT crl; + X509_CRL *x; + int ret; + ret=op_capi_retrieve_by_subject(_lu,_type,_name,_ret); + if(ret>0)return ret; + memset(&cert_info,0,sizeof(cert_info)); + if(OP_UNLIKELY(_name->bytes->length>MAXDWORD))return 0; + cert_info.Issuer.cbData=(DWORD)_name->bytes->length; + cert_info.Issuer.pbData=(unsigned char *)_name->bytes->data; + memset(&find_para,0,sizeof(find_para)); + find_para.pCertInfo=&cert_info; + crl=CertFindCRLInStore(h_store,0,0,CRL_FIND_ISSUED_BY,&find_para,NULL); + if(crl==NULL)return 0; + x=d2i_X509_CRL(NULL,(const unsigned char **)&crl->pbCrlEncoded, + crl->cbCrlEncoded); + CertFreeCRLContext(crl); + if(x==NULL)return 0; + ret=X509_STORE_add_crl(_lu->store_ctx,x); + X509_CRL_free(x); + if(ret)return op_capi_retrieve_by_subject(_lu,_type,_name,_ret); + }break; + } + return 0; +} + +/*This is not const because OpenSSL doesn't allow it, even though it won't + write to it.*/ +static X509_LOOKUP_METHOD X509_LOOKUP_CAPI={ + "Load Crypto API store into cache", + op_capi_new, + op_capi_free, + NULL, + NULL, + NULL, + op_capi_get_by_subject, + NULL, + NULL, + NULL +}; + +int SSL_CTX_set_default_verify_paths_win32(SSL_CTX *_ssl_ctx){ + X509_STORE *store; + X509_LOOKUP *lu; + /*We intentionally do not add the normal default paths, as they are usually + wrong, and are just asking to be used as an exploit vector.*/ + store=SSL_CTX_get_cert_store(_ssl_ctx); + OP_ASSERT(store!=NULL); + lu=X509_STORE_add_lookup(store,&X509_LOOKUP_CAPI); + if(lu==NULL)return 0; + ERR_clear_error(); + return 1; +} + +#endif diff --git a/extern/opusfile/src/winerrno.h b/extern/opusfile/src/winerrno.h new file mode 100644 index 0000000..32a90b4 --- /dev/null +++ b/extern/opusfile/src/winerrno.h @@ -0,0 +1,90 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE libopusfile SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE libopusfile SOURCE CODE IS (C) COPYRIGHT 2012 * + * by the Xiph.Org Foundation and contributors http://www.xiph.org/ * + * * + ********************************************************************/ +#if !defined(_opusfile_winerrno_h) +# define _opusfile_winerrno_h (1) + +# include +# include + +/*These conflict with the MSVC errno.h definitions, but we don't need to use + the original ones in any file that deals with sockets. + We could map the WSA errors to the errno.h ones (most of which are only + available on sufficiently new versions of MSVC), but they aren't ordered the + same, and given how rarely we actually look at the values, I don't think + it's worth a lookup table.*/ +# undef EWOULDBLOCK +# undef EINPROGRESS +# undef EALREADY +# undef ENOTSOCK +# undef EDESTADDRREQ +# undef EMSGSIZE +# undef EPROTOTYPE +# undef ENOPROTOOPT +# undef EPROTONOSUPPORT +# undef EOPNOTSUPP +# undef EAFNOSUPPORT +# undef EADDRINUSE +# undef EADDRNOTAVAIL +# undef ENETDOWN +# undef ENETUNREACH +# undef ENETRESET +# undef ECONNABORTED +# undef ECONNRESET +# undef ENOBUFS +# undef EISCONN +# undef ENOTCONN +# undef ETIMEDOUT +# undef ECONNREFUSED +# undef ELOOP +# undef ENAMETOOLONG +# undef EHOSTUNREACH +# undef ENOTEMPTY + +# define EWOULDBLOCK (WSAEWOULDBLOCK-WSABASEERR) +# define EINPROGRESS (WSAEINPROGRESS-WSABASEERR) +# define EALREADY (WSAEALREADY-WSABASEERR) +# define ENOTSOCK (WSAENOTSOCK-WSABASEERR) +# define EDESTADDRREQ (WSAEDESTADDRREQ-WSABASEERR) +# define EMSGSIZE (WSAEMSGSIZE-WSABASEERR) +# define EPROTOTYPE (WSAEPROTOTYPE-WSABASEERR) +# define ENOPROTOOPT (WSAENOPROTOOPT-WSABASEERR) +# define EPROTONOSUPPORT (WSAEPROTONOSUPPORT-WSABASEERR) +# define ESOCKTNOSUPPORT (WSAESOCKTNOSUPPORT-WSABASEERR) +# define EOPNOTSUPP (WSAEOPNOTSUPP-WSABASEERR) +# define EPFNOSUPPORT (WSAEPFNOSUPPORT-WSABASEERR) +# define EAFNOSUPPORT (WSAEAFNOSUPPORT-WSABASEERR) +# define EADDRINUSE (WSAEADDRINUSE-WSABASEERR) +# define EADDRNOTAVAIL (WSAEADDRNOTAVAIL-WSABASEERR) +# define ENETDOWN (WSAENETDOWN-WSABASEERR) +# define ENETUNREACH (WSAENETUNREACH-WSABASEERR) +# define ENETRESET (WSAENETRESET-WSABASEERR) +# define ECONNABORTED (WSAECONNABORTED-WSABASEERR) +# define ECONNRESET (WSAECONNRESET-WSABASEERR) +# define ENOBUFS (WSAENOBUFS-WSABASEERR) +# define EISCONN (WSAEISCONN-WSABASEERR) +# define ENOTCONN (WSAENOTCONN-WSABASEERR) +# define ESHUTDOWN (WSAESHUTDOWN-WSABASEERR) +# define ETOOMANYREFS (WSAETOOMANYREFS-WSABASEERR) +# define ETIMEDOUT (WSAETIMEDOUT-WSABASEERR) +# define ECONNREFUSED (WSAECONNREFUSED-WSABASEERR) +# define ELOOP (WSAELOOP-WSABASEERR) +# define ENAMETOOLONG (WSAENAMETOOLONG-WSABASEERR) +# define EHOSTDOWN (WSAEHOSTDOWN-WSABASEERR) +# define EHOSTUNREACH (WSAEHOSTUNREACH-WSABASEERR) +# define ENOTEMPTY (WSAENOTEMPTY-WSABASEERR) +# define EPROCLIM (WSAEPROCLIM-WSABASEERR) +# define EUSERS (WSAEUSERS-WSABASEERR) +# define EDQUOT (WSAEDQUOT-WSABASEERR) +# define ESTALE (WSAESTALE-WSABASEERR) +# define EREMOTE (WSAEREMOTE-WSABASEERR) + +#endif diff --git a/extern/opusfile/update_version b/extern/opusfile/update_version new file mode 100755 index 0000000..a999991 --- /dev/null +++ b/extern/opusfile/update_version @@ -0,0 +1,65 @@ +#!/bin/bash + +# Creates and updates the package_version information used by configure.ac +# (or other makefiles). When run inside a git repository it will use the +# version information that can be queried from it unless AUTO_UPDATE is set +# to 'no'. If no version is currently known it will be set to 'unknown'. +# +# If called with the argument 'release', the PACKAGE_VERSION will be updated +# even if AUTO_UPDATE=no, but the value of AUTO_UPDATE shall be preserved. +# This is used to force a version update whenever `make dist` is run. +# +# The exit status is 1 if package_version is not modified, else 0 is returned. +# +# This script should NOT be included in distributed tarballs, because if a +# parent directory contains a git repository we do not want to accidentally +# retrieve the version information from it instead. Tarballs should ship +# with only the package_version file. +# +# Ron , 2012. + +SRCDIR=$(dirname $0) + +if [ -e "$SRCDIR/package_version" ]; then + . "$SRCDIR/package_version" +fi + +if [ "$AUTO_UPDATE" = no ]; then + [ "$1" = release ] || exit 1 +else + AUTO_UPDATE=yes +fi + +# We run `git status` before describe here to ensure that we don't get a false +# -dirty from files that have been touched but are not actually altered in the +# working dir. +GIT_VERSION=$(cd "$SRCDIR" && git status > /dev/null 2>&1 \ + && git describe --tags --match 'v*' --dirty 2> /dev/null) +GIT_VERSION=${GIT_VERSION#v} + +if [ -n "$GIT_VERSION" ]; then + + [ "$GIT_VERSION" != "$PACKAGE_VERSION" ] || exit 1 + PACKAGE_VERSION="$GIT_VERSION" + +elif [ -z "$PACKAGE_VERSION" ]; then + # No current package_version and no git ... + # We really shouldn't ever get here, because this script should only be + # included in the git repository, and should usually be export-ignored. + PACKAGE_VERSION="unknown" +else + exit 1 +fi + +cat > "$SRCDIR/package_version" <<-EOF + # Automatically generated by update_version. + # This file may be sourced into a shell script or makefile. + + # Set this to 'no' if you do not wish the version information + # to be checked and updated for every build. Most people will + # never want to change this, it is an option for developers + # making frequent changes that they know will not be released. + AUTO_UPDATE=$AUTO_UPDATE + + PACKAGE_VERSION="$PACKAGE_VERSION" +EOF diff --git a/extern/opusfile/win32/.gitignore b/extern/opusfile/win32/.gitignore new file mode 100644 index 0000000..4ef99ac --- /dev/null +++ b/extern/opusfile/win32/.gitignore @@ -0,0 +1,25 @@ +# Visual Studio ignores +[Dd]ebug/ +[Dd]ebugDLL/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleaseDLL/ +[Rr]elese-NoHTTP/ +[Rr]eleases/ +*.manifest +*.lastbuildstate +*.lib +*.log +*.idb +*.ipdb +*.ilk +*.iobj +*.obj +*.opensdf +*.pdb +*.sdf +*.suo +*.tlog +*.vcxproj.user +*.vc.db +*.vc.opendb diff --git a/extern/opusfile/win32/VS2015/opusfile.sln b/extern/opusfile/win32/VS2015/opusfile.sln new file mode 100644 index 0000000..c80d22f --- /dev/null +++ b/extern/opusfile/win32/VS2015/opusfile.sln @@ -0,0 +1,62 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.25420.1 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "opusfile", "opusfile.vcxproj", "{1A4B5203-52EB-4805-9511-84B1BD094FCA}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "opusfile_example", "opusfile_example.vcxproj", "{5B354509-E328-439E-B79D-D8DD7F7FF8E3}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "seeking_example", "seeking_example.vcxproj", "{4FF9E8FA-2B1F-46B9-950A-B38D72F67C4C}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + Release-NoHTTP|Win32 = Release-NoHTTP|Win32 + Release-NoHTTP|x64 = Release-NoHTTP|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {1A4B5203-52EB-4805-9511-84B1BD094FCA}.Debug|Win32.ActiveCfg = Debug|Win32 + {1A4B5203-52EB-4805-9511-84B1BD094FCA}.Debug|Win32.Build.0 = Debug|Win32 + {1A4B5203-52EB-4805-9511-84B1BD094FCA}.Debug|x64.ActiveCfg = Debug|x64 + {1A4B5203-52EB-4805-9511-84B1BD094FCA}.Debug|x64.Build.0 = Debug|x64 + {1A4B5203-52EB-4805-9511-84B1BD094FCA}.Release|Win32.ActiveCfg = Release|Win32 + {1A4B5203-52EB-4805-9511-84B1BD094FCA}.Release|Win32.Build.0 = Release|Win32 + {1A4B5203-52EB-4805-9511-84B1BD094FCA}.Release|x64.ActiveCfg = Release|x64 + {1A4B5203-52EB-4805-9511-84B1BD094FCA}.Release|x64.Build.0 = Release|x64 + {1A4B5203-52EB-4805-9511-84B1BD094FCA}.Release-NoHTTP|Win32.ActiveCfg = Release-NoHTTP|Win32 + {1A4B5203-52EB-4805-9511-84B1BD094FCA}.Release-NoHTTP|Win32.Build.0 = Release-NoHTTP|Win32 + {1A4B5203-52EB-4805-9511-84B1BD094FCA}.Release-NoHTTP|x64.ActiveCfg = Release-NoHTTP|x64 + {1A4B5203-52EB-4805-9511-84B1BD094FCA}.Release-NoHTTP|x64.Build.0 = Release-NoHTTP|x64 + {5B354509-E328-439E-B79D-D8DD7F7FF8E3}.Debug|Win32.ActiveCfg = Debug|Win32 + {5B354509-E328-439E-B79D-D8DD7F7FF8E3}.Debug|Win32.Build.0 = Debug|Win32 + {5B354509-E328-439E-B79D-D8DD7F7FF8E3}.Debug|x64.ActiveCfg = Debug|x64 + {5B354509-E328-439E-B79D-D8DD7F7FF8E3}.Debug|x64.Build.0 = Debug|x64 + {5B354509-E328-439E-B79D-D8DD7F7FF8E3}.Release|Win32.ActiveCfg = Release|Win32 + {5B354509-E328-439E-B79D-D8DD7F7FF8E3}.Release|Win32.Build.0 = Release|Win32 + {5B354509-E328-439E-B79D-D8DD7F7FF8E3}.Release|x64.ActiveCfg = Release|x64 + {5B354509-E328-439E-B79D-D8DD7F7FF8E3}.Release|x64.Build.0 = Release|x64 + {5B354509-E328-439E-B79D-D8DD7F7FF8E3}.Release-NoHTTP|Win32.ActiveCfg = Release-NoHTTP|Win32 + {5B354509-E328-439E-B79D-D8DD7F7FF8E3}.Release-NoHTTP|Win32.Build.0 = Release-NoHTTP|Win32 + {5B354509-E328-439E-B79D-D8DD7F7FF8E3}.Release-NoHTTP|x64.ActiveCfg = Release-NoHTTP|x64 + {5B354509-E328-439E-B79D-D8DD7F7FF8E3}.Release-NoHTTP|x64.Build.0 = Release-NoHTTP|x64 + {4FF9E8FA-2B1F-46B9-950A-B38D72F67C4C}.Debug|Win32.ActiveCfg = Debug|Win32 + {4FF9E8FA-2B1F-46B9-950A-B38D72F67C4C}.Debug|Win32.Build.0 = Debug|Win32 + {4FF9E8FA-2B1F-46B9-950A-B38D72F67C4C}.Debug|x64.ActiveCfg = Debug|x64 + {4FF9E8FA-2B1F-46B9-950A-B38D72F67C4C}.Debug|x64.Build.0 = Debug|x64 + {4FF9E8FA-2B1F-46B9-950A-B38D72F67C4C}.Release|Win32.ActiveCfg = Release|Win32 + {4FF9E8FA-2B1F-46B9-950A-B38D72F67C4C}.Release|Win32.Build.0 = Release|Win32 + {4FF9E8FA-2B1F-46B9-950A-B38D72F67C4C}.Release|x64.ActiveCfg = Release|x64 + {4FF9E8FA-2B1F-46B9-950A-B38D72F67C4C}.Release|x64.Build.0 = Release|x64 + {4FF9E8FA-2B1F-46B9-950A-B38D72F67C4C}.Release-NoHTTP|Win32.ActiveCfg = Release-NoHTTP|Win32 + {4FF9E8FA-2B1F-46B9-950A-B38D72F67C4C}.Release-NoHTTP|Win32.Build.0 = Release-NoHTTP|Win32 + {4FF9E8FA-2B1F-46B9-950A-B38D72F67C4C}.Release-NoHTTP|x64.ActiveCfg = Release-NoHTTP|x64 + {4FF9E8FA-2B1F-46B9-950A-B38D72F67C4C}.Release-NoHTTP|x64.Build.0 = Release-NoHTTP|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/extern/opusfile/win32/VS2015/opusfile.vcxproj b/extern/opusfile/win32/VS2015/opusfile.vcxproj new file mode 100644 index 0000000..413ab5f --- /dev/null +++ b/extern/opusfile/win32/VS2015/opusfile.vcxproj @@ -0,0 +1,258 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release-NoHTTP + Win32 + + + Release-NoHTTP + x64 + + + Release + Win32 + + + Release + x64 + + + + + + + + + + + + + + + + {1A4B5203-52EB-4805-9511-84B1BD094FCA} + Win32Proj + opusfile + + + + StaticLibrary + true + NotSet + v140 + + + StaticLibrary + true + NotSet + v140 + + + StaticLibrary + false + true + NotSet + v140 + + + StaticLibrary + false + true + NotSet + v140 + + + StaticLibrary + false + true + NotSet + v140 + + + StaticLibrary + false + true + NotSet + v140 + + + + + + + + + + + + + + + + + + + + + + + + + $(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\$(ProjectName)\ + ..\..\..\opus\include;..\..\..\ogg\include;..\..\..\openssl\inc32;..\..\..\openssl\$(Platform)\Release\include;..\..\include;$(IncludePath) + + + $(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\$(ProjectName)\ + ..\..\..\opus\include;..\..\..\ogg\include;..\..\..\openssl\inc32;..\..\..\openssl\$(Platform)\Release\include;..\..\include;$(IncludePath) + + + $(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\$(ProjectName)\ + ..\..\..\opus\include;..\..\..\ogg\include;..\..\..\openssl\inc32;..\..\..\openssl\$(Platform)\Release\include;..\..\include;$(IncludePath) + + + $(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\$(ProjectName)\ + ..\..\..\opus\include;..\..\..\ogg\include;..\..\include;$(IncludePath) + + + $(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\$(ProjectName)\ + ..\..\..\opus\include;..\..\..\ogg\include;..\..\..\openssl\inc32;..\..\..\openssl\$(Platform)\Release\include;..\..\include;$(IncludePath) + + + $(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\$(ProjectName)\ + ..\..\..\opus\include;..\..\..\ogg\include;..\..\include;$(IncludePath) + + + + + + Level3 + Disabled + WIN32;OP_ENABLE_HTTP;_DEBUG;_CRT_SECURE_NO_WARNINGS;_LIB;%(PreprocessorDefinitions) + MultiThreadedDebug + + + Windows + true + + + + + + + Level3 + Disabled + WIN32;OP_ENABLE_HTTP;WIN64;_DEBUG;_CRT_SECURE_NO_WARNINGS;_LIB;%(PreprocessorDefinitions) + MultiThreadedDebug + + + Windows + true + + + + + Level3 + + + MaxSpeed + true + true + WIN32;OP_ENABLE_HTTP;NDEBUG;_CRT_SECURE_NO_WARNINGS;_LIB;%(PreprocessorDefinitions) + MultiThreaded + AnySuitable + Speed + true + Fast + + + Windows + true + true + true + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CRT_SECURE_NO_WARNINGS;_LIB;%(PreprocessorDefinitions) + MultiThreaded + AnySuitable + Speed + true + Fast + + + Windows + true + true + true + + + + + Level3 + + + MaxSpeed + true + true + WIN32;OP_ENABLE_HTTP;WIN64;NDEBUG;_CRT_SECURE_NO_WARNINGS;_LIB;%(PreprocessorDefinitions) + MultiThreaded + AnySuitable + Speed + true + Fast + + + Windows + true + true + true + + + + + Level3 + + + MaxSpeed + true + true + WIN32;WIN64;NDEBUG;_CRT_SECURE_NO_WARNINGS;_LIB;%(PreprocessorDefinitions) + MultiThreaded + AnySuitable + Speed + true + Fast + + + Windows + true + true + true + + + + + + \ No newline at end of file diff --git a/extern/opusfile/win32/VS2015/opusfile.vcxproj.filters b/extern/opusfile/win32/VS2015/opusfile.vcxproj.filters new file mode 100644 index 0000000..35f826a --- /dev/null +++ b/extern/opusfile/win32/VS2015/opusfile.vcxproj.filters @@ -0,0 +1,45 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + \ No newline at end of file diff --git a/extern/opusfile/win32/VS2015/opusfile_example.vcxproj b/extern/opusfile/win32/VS2015/opusfile_example.vcxproj new file mode 100644 index 0000000..b054287 --- /dev/null +++ b/extern/opusfile/win32/VS2015/opusfile_example.vcxproj @@ -0,0 +1,263 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release-NoHTTP + Win32 + + + Release-NoHTTP + x64 + + + Release + Win32 + + + Release + x64 + + + + {5B354509-E328-439E-B79D-D8DD7F7FF8E3} + Win32Proj + opusfile_example + + + + Application + true + Unicode + v140 + + + Application + true + Unicode + v140 + + + Application + false + true + Unicode + v140 + + + Application + false + true + Unicode + v140 + + + Application + false + true + Unicode + v140 + + + Application + false + true + Unicode + v140 + + + + + + + + + + + + + + + + + + + + + + + + + ..\..\..\opus\win32\VS2015\$(Platform)\$(Configuration);..\..\..\ogg\win32\VS2015\$(Platform)\$(Configuration);..\..\..\openssl\$(Platform)\Release\lib;..\..\..\openssl\out32;$(LibraryPath) + $(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\$(ProjectName)\ + ..\..\..\opus\include;..\..\..\ogg\include;..\..\..\openssl\inc32;..\..\..\openssl\$(Platform)\Release\include;..\..\include;$(IncludePath) + + + ..\..\..\opus\win32\VS2015\$(Platform)\$(Configuration);..\..\..\ogg\win32\VS2015\$(Platform)\$(Configuration);..\..\..\openssl\$(Platform)\Release\lib;..\..\..\openssl\out32;$(LibraryPath) + $(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\$(ProjectName)\ + ..\..\..\opus\include;..\..\..\ogg\include;..\..\..\openssl\inc32;..\..\..\openssl\$(Platform)\Release\include;..\..\include;$(IncludePath) + + + false + ..\..\..\opus\win32\VS2015\$(Platform)\$(Configuration);..\..\..\ogg\win32\VS2015\$(Platform)\$(Configuration);..\..\..\openssl\$(Platform)\Release\lib;..\..\..\openssl\out32;$(LibraryPath) + $(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\$(ProjectName)\ + ..\..\..\opus\include;..\..\..\ogg\include;..\..\..\openssl\inc32;..\..\..\openssl\$(Platform)\Release\include;..\..\include;$(IncludePath) + + + false + ..\..\..\opus\win32\VS2015\$(Platform)\Release;..\..\..\ogg\win32\VS2015\$(Platform)\Release;$(LibraryPath) + $(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\$(ProjectName)\ + ..\..\..\opus\include;..\..\..\ogg\include;..\..\include;$(IncludePath) + + + false + ..\..\..\opus\win32\VS2015\$(Platform)\$(Configuration);..\..\..\ogg\win32\VS2015\$(Platform)\$(Configuration);..\..\..\openssl\$(Platform)\Release\lib;..\..\..\openssl\out32;$(LibraryPath) + $(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\$(ProjectName)\ + ..\..\..\opus\include;..\..\..\ogg\include;..\..\..\openssl\inc32;..\..\..\openssl\$(Platform)\Release\include;..\..\include;$(IncludePath) + + + false + ..\..\..\opus\win32\VS2015\$(Platform)\Release;..\..\..\ogg\win32\VS2015\$(Platform)\Release;$(LibraryPath) + $(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\$(ProjectName)\ + ..\..\..\opus\include;..\..\..\ogg\include;..\..\include;$(IncludePath) + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CRT_SECURE_NO_WARNINGS;_CONSOLE;%(PreprocessorDefinitions) + MultiThreadedDebug + + + Console + true + libogg_static.lib;opus.lib;libeay32.lib;ssleay32.lib;ws2_32.lib;crypt32.lib;%(AdditionalDependencies) + + + + + + + Level3 + Disabled + WIN32;WIN64;_DEBUG;_CRT_SECURE_NO_WARNINGS;_CONSOLE;%(PreprocessorDefinitions) + MultiThreadedDebug + + + Console + true + libogg_static.lib;opus.lib;libeay32.lib;ssleay32.lib;ws2_32.lib;crypt32.lib;%(AdditionalDependencies) + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CRT_SECURE_NO_WARNINGS;_CONSOLE;%(PreprocessorDefinitions) + MultiThreaded + AnySuitable + Speed + + + Console + true + true + true + libogg_static.lib;opus.lib;libeay32.lib;ssleay32.lib;ws2_32.lib;crypt32.lib;%(AdditionalDependencies) + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CRT_SECURE_NO_WARNINGS;_CONSOLE;%(PreprocessorDefinitions) + MultiThreaded + AnySuitable + Speed + + + Console + true + true + true + libogg_static.lib;opus.lib;%(AdditionalDependencies) + + + + + Level3 + + + MaxSpeed + true + true + WIN32;WIN64;NDEBUG;_CRT_SECURE_NO_WARNINGS;_CONSOLE;%(PreprocessorDefinitions) + MultiThreaded + AnySuitable + Speed + + + Console + true + true + true + libogg_static.lib;opus.lib;libeay32.lib;ssleay32.lib;ws2_32.lib;crypt32.lib;%(AdditionalDependencies) + + + + + Level3 + + + MaxSpeed + true + true + WIN32;WIN64;NDEBUG;_CRT_SECURE_NO_WARNINGS;_CONSOLE;%(PreprocessorDefinitions) + MultiThreaded + AnySuitable + Speed + + + Console + true + true + true + libogg_static.lib;opus.lib;%(AdditionalDependencies) + + + + + + + + + {1a4b5203-52eb-4805-9511-84b1bd094fca} + + + + + + \ No newline at end of file diff --git a/extern/opusfile/win32/VS2015/opusfile_example.vcxproj.filters b/extern/opusfile/win32/VS2015/opusfile_example.vcxproj.filters new file mode 100644 index 0000000..e78b530 --- /dev/null +++ b/extern/opusfile/win32/VS2015/opusfile_example.vcxproj.filters @@ -0,0 +1,25 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + Source Files + + + diff --git a/extern/opusfile/win32/VS2015/seeking_example.vcxproj b/extern/opusfile/win32/VS2015/seeking_example.vcxproj new file mode 100644 index 0000000..4b2dbcb --- /dev/null +++ b/extern/opusfile/win32/VS2015/seeking_example.vcxproj @@ -0,0 +1,255 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release-NoHTTP + Win32 + + + Release-NoHTTP + x64 + + + Release + Win32 + + + Release + x64 + + + + {4FF9E8FA-2B1F-46B9-950A-B38D72F67C4C} + Win32Proj + seeking_example + + + + Application + true + NotSet + v140 + + + Application + true + NotSet + v140 + + + Application + false + true + NotSet + v140 + + + Application + false + true + NotSet + v140 + + + Application + false + true + NotSet + v140 + + + Application + false + true + NotSet + v140 + + + + + + + + + + + + + + + + + + + + + + + + + ..\..\..\opus\win32\VS2015\$(Platform)\$(Configuration);..\..\..\ogg\win32\VS2015\$(Platform)\$(Configuration);..\..\..\openssl\$(Platform)\Release\lib;..\..\..\openssl\out32;$(LibraryPath) + $(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\$(ProjectName)\ + ..\..\..\opus\include;..\..\..\ogg\include;..\..\..\openssl\inc32;..\..\..\openssl\$(Platform)\Release\include;..\..\include;$(IncludePath) + + + ..\..\..\opus\win32\VS2015\$(Platform)\$(Configuration);..\..\..\ogg\win32\VS2015\$(Platform)\$(Configuration);..\..\..\openssl\$(Platform)\Release\lib;..\..\..\openssl\out32;$(LibraryPath) + $(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\$(ProjectName)\ + ..\..\..\opus\include;..\..\..\ogg\include;..\..\..\openssl\inc32;..\..\..\openssl\$(Platform)\Release\include;..\..\include;$(IncludePath) + + + false + ..\..\..\opus\win32\VS2015\$(Platform)\$(Configuration);..\..\..\ogg\win32\VS2015\$(Platform)\$(Configuration);..\..\..\openssl\$(Platform)\Release\lib;..\..\..\openssl\out32;$(LibraryPath) + $(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\$(ProjectName)\ + ..\..\..\opus\include;..\..\..\ogg\include;..\..\..\openssl\inc32;..\..\..\openssl\$(Platform)\Release\include;..\..\include;$(IncludePath) + + + false + ..\..\..\opus\win32\VS2015\$(Platform)\Release;..\..\..\ogg\win32\VS2015\$(Platform)\Release;$(LibraryPath) + $(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\$(ProjectName)\ + ..\..\..\opus\include;..\..\..\ogg\include;..\..\include;$(IncludePath) + + + false + ..\..\..\opus\win32\VS2015\$(Platform)\$(Configuration);..\..\..\ogg\win32\VS2015\$(Platform)\$(Configuration);..\..\..\openssl\$(Platform)\Release\lib;..\..\..\openssl\out32;$(LibraryPath) + $(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\$(ProjectName)\ + ..\..\..\opus\include;..\..\..\ogg\include;..\..\..\openssl\inc32;..\..\..\openssl\$(Platform)\Release\include;..\..\include;$(IncludePath) + + + false + ..\..\..\opus\win32\VS2015\$(Platform)\Release;..\..\..\ogg\win32\VS2015\$(Platform)\Release;$(LibraryPath) + $(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\$(ProjectName)\ + ..\..\..\opus\include;..\..\..\ogg\include;..\..\include;$(IncludePath) + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CRT_SECURE_NO_WARNINGS;_CONSOLE;%(PreprocessorDefinitions) + MultiThreadedDebug + + + Console + true + libogg_static.lib;opus.lib;libeay32.lib;ssleay32.lib;ws2_32.lib;crypt32.lib;%(AdditionalDependencies) + + + + + + + Level3 + Disabled + WIN32;WIN64;_DEBUG;_CRT_SECURE_NO_WARNINGS;_CONSOLE;%(PreprocessorDefinitions) + MultiThreadedDebug + + + Console + true + libogg_static.lib;opus.lib;libeay32.lib;ssleay32.lib;ws2_32.lib;crypt32.lib;%(AdditionalDependencies) + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CRT_SECURE_NO_WARNINGS;_CONSOLE;%(PreprocessorDefinitions) + MultiThreaded + + + Console + true + true + true + libogg_static.lib;opus.lib;libeay32.lib;ssleay32.lib;ws2_32.lib;crypt32.lib;%(AdditionalDependencies) + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CRT_SECURE_NO_WARNINGS;_CONSOLE;%(PreprocessorDefinitions) + MultiThreaded + + + Console + true + true + true + libogg_static.lib;opus.lib;%(AdditionalDependencies) + + + + + Level3 + + + MaxSpeed + true + true + WIN32;WIN64;NDEBUG;_CRT_SECURE_NO_WARNINGS;_CONSOLE;%(PreprocessorDefinitions) + MultiThreaded + + + Console + true + true + true + libogg_static.lib;opus.lib;libeay32.lib;ssleay32.lib;ws2_32.lib;crypt32.lib;%(AdditionalDependencies) + + + + + Level3 + + + MaxSpeed + true + true + WIN32;WIN64;NDEBUG;_CRT_SECURE_NO_WARNINGS;_CONSOLE;%(PreprocessorDefinitions) + MultiThreaded + + + Console + true + true + true + libogg_static.lib;opus.lib;%(AdditionalDependencies) + + + + + + + + + {1a4b5203-52eb-4805-9511-84b1bd094fca} + + + + + + \ No newline at end of file diff --git a/extern/opusfile/win32/VS2015/seeking_example.vcxproj.filters b/extern/opusfile/win32/VS2015/seeking_example.vcxproj.filters new file mode 100644 index 0000000..c921c4e --- /dev/null +++ b/extern/opusfile/win32/VS2015/seeking_example.vcxproj.filters @@ -0,0 +1,25 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + Source Files + + + diff --git a/extern/portaudio/.gitattributes b/extern/portaudio/.gitattributes new file mode 100644 index 0000000..95d5134 --- /dev/null +++ b/extern/portaudio/.gitattributes @@ -0,0 +1,43 @@ +# Set the default behavior, in case people don't have core.autocrlf set. +* text=auto + +# Explicitly declare text files you want to always be normalized and converted +# to native line endings on checkout. +*.c text +*.h text +*.cpp text +*.hpp text +*.fth text +*.java text +*.f text +*.txt text +*.dox text +*.m text + +# Declare files that will always have CRLF line endings on checkout. +*.sln text eol=crlf +*.def text eol=crlf +*.dsp text eol=crlf +*.dsw text eol=crlf +*.vcproj text eol=crlf +*.sln text eol=crlf +*.doc text eol=crlf +*.bat text eol=crlf + +# Denote all files that are truly binary and should not be modified. +*.dic binary +*.odt binary +*.pdf binary +*.png binary +*.jpg binary +*.wav binary +*.la binary +config.guess binary +config.status binary +config.sub binary +configure binary +depcomp binary +install-sh binary +libtool binary +missing binary + diff --git a/extern/portaudio/.gitignore b/extern/portaudio/.gitignore new file mode 100644 index 0000000..892ddfc --- /dev/null +++ b/extern/portaudio/.gitignore @@ -0,0 +1,42 @@ +# Compiled Object files +*.slo +*.lo +*.o +*.obj + +# annoying files +**/.DS_Store + +# Generated by configure and make +Makefile +bin-stamp +bin/* +config.log +config.status +lib-stamp +lib/* +libtool +portaudio-2.0.pc + +# Precompiled Headers +*.gch +*.pch + +# Compiled Dynamic libraries +*.so +*.dylib +*.dll + +# Fortran module files +*.mod + +# Compiled Static libraries +*.lai +*.la +*.a +*.lib + +# Executables +*.exe +*.out +*.app diff --git a/extern/portaudio/CMakeLists.txt b/extern/portaudio/CMakeLists.txt new file mode 100644 index 0000000..55e0536 --- /dev/null +++ b/extern/portaudio/CMakeLists.txt @@ -0,0 +1,481 @@ +# $Id: $ +# +# For a "How-To" please refer to the Portaudio documentation at: +# http://www.portaudio.com/trac/wiki/TutorialDir/Compile/CMake +# + +CMAKE_MINIMUM_REQUIRED(VERSION 2.8) + +# Check if the user is building PortAudio stand-alone or as part of a larger +# project. If this is part of a larger project (i.e. the CMakeLists.txt has +# been imported by some other CMakeLists.txt), we don't want to trump over +# the top of that project's global settings. +IF(${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_CURRENT_LIST_DIR}) + PROJECT(portaudio) + + # CMAKE_CONFIGURATION_TYPES only exists for multi-config generators (like + # Visual Studio or Xcode). For these projects, we won't define + # CMAKE_BUILD_TYPE as it does not make sense. + IF(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + MESSAGE(STATUS "Setting CMAKE_BUILD_TYPE type to 'Debug' as none was specified.") + SET(CMAKE_BUILD_TYPE Debug CACHE STRING "Choose the type of build." FORCE) + SET_PROPERTY(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release") + ENDIF() + + SET_PROPERTY(GLOBAL PROPERTY USE_FOLDERS ON) + + IF(WIN32 AND MSVC) + OPTION(PA_DLL_LINK_WITH_STATIC_RUNTIME "Link with static runtime libraries (minimizes runtime dependencies)" ON) + IF(PA_DLL_LINK_WITH_STATIC_RUNTIME) + FOREACH(flag_var + CMAKE_C_FLAGS CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE + CMAKE_C_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELWITHDEBINFO + CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE + CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO) + IF(${flag_var} MATCHES "/MD") + STRING(REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}") + ENDIF() + ENDFOREACH() + ENDIF() + ENDIF() +ENDIF() + +SET(PA_VERSION 19) +SET(PA_PKGCONFIG_VERSION ${PA_VERSION}) +SET(PA_SOVERSION "${PA_VERSION}.0") + +# Most of the code from this point onwards is related to populating the +# following variables: +# PA_PUBLIC_INCLUDES - This contains the list of public PortAudio header +# files. These files will be copied into /include paths on Unix'y +# systems when "make install" is invoked. +# PA_PRIVATE_INCLUDES - This contains the list of header files which +# are not part of PortAudio, but are required by the various hostapis. +# It is only used by CMake IDE generators (like Visual Studio) to +# provide quick-links to useful headers. It has no impact on build +# output. +# PA_PRIVATE_INCLUDE_PATHS - This contains the list of include paths which +# will be passed to the compiler while PortAudio is being built which +# are not required by applications using the PortAudio API. +# PA_PRIVATE_COMPILE_DEFINITIONS - This contains a list of preprocessor +# macro definitions which will be set when compiling PortAudio source +# files. +# PA_SOURCES - This contains the list of source files which will be built +# into the static and shared PortAudio libraries. +# PA_NON_UNICODE_SOURCES - This also contains a list of source files which +# will be build into the static and shared PortAudio libraries. However, +# these sources will not have any unicode compiler definitions added +# to them. This list should only contain external source dependencies. +# PA_EXTRA_SHARED_SOURCES - Contains a list of extra files which will be +# associated only with the shared PortAudio library. This only seems +# relevant for Windows shared libraries which require a list of export +# symbols. +# Where other PA_* variables are set, these are almost always only used to +# preserve the historic SOURCE_GROUP behavior (which again only has an impact +# on IDE-style generators for visual appearance) or store the output of +# find_library() calls. + +SET(PA_COMMON_INCLUDES + src/common/pa_allocation.h + src/common/pa_converters.h + src/common/pa_cpuload.h + src/common/pa_debugprint.h + src/common/pa_dither.h + src/common/pa_endianness.h + src/common/pa_hostapi.h + src/common/pa_memorybarrier.h + src/common/pa_process.h + src/common/pa_ringbuffer.h + src/common/pa_stream.h + src/common/pa_trace.h + src/common/pa_types.h + src/common/pa_util.h +) + +SET(PA_COMMON_SOURCES + src/common/pa_allocation.c + src/common/pa_converters.c + src/common/pa_cpuload.c + src/common/pa_debugprint.c + src/common/pa_dither.c + src/common/pa_front.c + src/common/pa_process.c + src/common/pa_ringbuffer.c + src/common/pa_stream.c + src/common/pa_trace.c +) + +SOURCE_GROUP("common" FILES ${PA_COMMON_INCLUDES} ${PA_COMMON_SOURCES}) + +SET(PA_PUBLIC_INCLUDES include/portaudio.h) + +SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake_support) + +SET(PA_SKELETON_SOURCES src/hostapi/skeleton/pa_hostapi_skeleton.c) +SOURCE_GROUP("hostapi\\skeleton" ${PA_SKELETON_SOURCES}) +SET(PA_SOURCES ${PA_COMMON_SOURCES} ${PA_SKELETON_SOURCES}) +SET(PA_PRIVATE_INCLUDE_PATHS src/common ${CMAKE_CURRENT_BINARY_DIR}) + +IF(WIN32) + SET(PA_PRIVATE_COMPILE_DEFINITIONS ${PA_PRIVATE_COMPILE_DEFINITIONS} _CRT_SECURE_NO_WARNINGS) + + SET(PA_PLATFORM_SOURCES + src/os/win/pa_win_hostapis.c + src/os/win/pa_win_util.c + src/os/win/pa_win_waveformat.c + src/os/win/pa_win_wdmks_utils.c + src/os/win/pa_win_coinitialize.c) + SET(PA_PLATFORM_INCLUDES + src/os/win/pa_win_coinitialize.h + src/os/win/pa_win_wdmks_utils.h) + + IF(MSVC) + SET(PA_PLATFORM_SOURCES ${PA_PLATFORM_SOURCES} src/os/win/pa_x86_plain_converters.c) + SET(PA_PLATFORM_INCLUDES ${PA_PLATFORM_INCLUDES} src/os/win/pa_x86_plain_converters.h) + ELSE() + SET(PA_PRIVATE_COMPILE_DEFINITIONS ${PA_PRIVATE_COMPILE_DEFINITIONS} _WIN32_WINNT=0x0501 WINVER=0x0501) + SET(DEF_EXCLUDE_X86_PLAIN_CONVERTERS ";") + ENDIF() + + SOURCE_GROUP("os\\win" FILES ${PA_PLATFORM_SOURCES} ${PA_PLATFORM_INCLUDES}) + SET(PA_SOURCES ${PA_SOURCES} ${PA_PLATFORM_SOURCES}) + SET(PA_PRIVATE_INCLUDES ${PA_PRIVATE_INCLUDES} ${PA_PLATFORM_INCLUDES}) + SET(PA_PRIVATE_INCLUDE_PATHS ${PA_PRIVATE_INCLUDE_PATHS} src/os/win) + + SET(PA_LIBRARY_DEPENDENCIES ${PA_LIBRARY_DEPENDENCIES} winmm) + + # Try to find ASIO SDK (assumes that portaudio and asiosdk folders are side-by-side, see + # http://www.portaudio.com/trac/wiki/TutorialDir/Compile/WindowsASIOMSVC) + FIND_PACKAGE(ASIOSDK) + IF(ASIOSDK_FOUND) + OPTION(PA_USE_ASIO "Enable support for ASIO" ON) + ELSE() + OPTION(PA_USE_ASIO "Enable support for ASIO" OFF) + ENDIF() + IF(PA_USE_ASIO) + SET(PA_PRIVATE_INCLUDE_PATHS ${PA_PRIVATE_INCLUDE_PATHS} ${ASIOSDK_ROOT_DIR}/common) + SET(PA_PRIVATE_INCLUDE_PATHS ${PA_PRIVATE_INCLUDE_PATHS} ${ASIOSDK_ROOT_DIR}/host) + SET(PA_PRIVATE_INCLUDE_PATHS ${PA_PRIVATE_INCLUDE_PATHS} ${ASIOSDK_ROOT_DIR}/host/pc) + SET(PA_ASIO_SOURCES src/hostapi/asio/pa_asio.cpp src/hostapi/asio/iasiothiscallresolver.cpp) + SET(PA_ASIOSDK_SOURCES ${ASIOSDK_ROOT_DIR}/common/asio.cpp ${ASIOSDK_ROOT_DIR}/host/pc/asiolist.cpp ${ASIOSDK_ROOT_DIR}/host/asiodrivers.cpp) + SOURCE_GROUP("hostapi\\ASIO" FILES ${PA_ASIO_SOURCES}) + SOURCE_GROUP("hostapi\\ASIO\\ASIOSDK" FILES ${PA_ASIOSDK_SOURCES}) + SET(PA_PUBLIC_INCLUDES ${PA_PUBLIC_INCLUDES} include/pa_asio.h) + SET(PA_SOURCES ${PA_SOURCES} ${PA_ASIO_SOURCES}) + SET(PA_NON_UNICODE_SOURCES ${PA_NON_UNICODE_SOURCES} ${PA_ASIOSDK_SOURCES}) + SET(PA_LIBRARY_DEPENDENCIES ${PA_LIBRARY_DEPENDENCIES} ole32 uuid) + ELSE() + # Set variables for DEF file expansion + SET(DEF_EXCLUDE_ASIO_SYMBOLS ";") + ENDIF() + + OPTION(PA_USE_DS "Enable support for DirectSound" ON) + IF(PA_USE_DS) + IF(MINGW) + MESSAGE(STATUS "DirectSound support will be built with DSound provided by MinGW.") + OPTION(PA_USE_DIRECTSOUNDFULLDUPLEXCREATE "Use DirectSound full duplex create" OFF) + ELSE(MINGW) + OPTION(PA_USE_DIRECTSOUNDFULLDUPLEXCREATE "Use DirectSound full duplex create" ON) + ENDIF(MINGW) + MARK_AS_ADVANCED(PA_USE_DIRECTSOUNDFULLDUPLEXCREATE) + IF(PA_USE_DIRECTSOUNDFULLDUPLEXCREATE) + SET(PA_PRIVATE_COMPILE_DEFINITIONS ${PA_PRIVATE_COMPILE_DEFINITIONS} PAWIN_USE_DIRECTSOUNDFULLDUPLEXCREATE) + ENDIF() + SET(PA_DS_INCLUDES src/hostapi/dsound/pa_win_ds_dynlink.h) + SET(PA_DS_SOURCES src/hostapi/dsound/pa_win_ds.c src/hostapi/dsound/pa_win_ds_dynlink.c) + SOURCE_GROUP("hostapi\\dsound" FILES ${PA_DS_INCLUDES} ${PA_DS_SOURCES}) + SET(PA_PUBLIC_INCLUDES ${PA_PUBLIC_INCLUDES} include/pa_win_ds.h include/pa_win_waveformat.h) + SET(PA_PRIVATE_INCLUDES ${PA_PRIVATE_INCLUDES} ${PA_DS_INCLUDES}) + SET(PA_SOURCES ${PA_SOURCES} ${PA_DS_SOURCES}) + SET(PA_LIBRARY_DEPENDENCIES ${PA_LIBRARY_DEPENDENCIES} dsound) + ENDIF(PA_USE_DS) + + OPTION(PA_USE_WMME "Enable support for MME" ON) + IF(PA_USE_WMME) + SET(PA_WMME_SOURCES src/hostapi/wmme/pa_win_wmme.c) + SOURCE_GROUP("hostapi\\wmme" FILES ${PA_WMME_SOURCES}) + SET(PA_PUBLIC_INCLUDES ${PA_PUBLIC_INCLUDES} include/pa_win_wmme.h include/pa_win_waveformat.h) + SET(PA_SOURCES ${PA_SOURCES} ${PA_WMME_SOURCES}) + SET(PA_LIBRARY_DEPENDENCIES ${PA_LIBRARY_DEPENDENCIES} ole32 uuid) + ENDIF() + + # MinGW versions below 4.93, especially non MinGW-w64 distributions may + # break in the wasapi build. If an older MinGW version is required, WASAPI- + # support needs to be disabled. + OPTION(PA_USE_WASAPI "Enable support for WASAPI" ON) + IF(PA_USE_WASAPI) + SET(PA_WASAPI_SOURCES src/hostapi/wasapi/pa_win_wasapi.c) + SOURCE_GROUP("hostapi\\wasapi" FILES ${PA_WASAPI_SOURCES}) + SET(PA_PUBLIC_INCLUDES ${PA_PUBLIC_INCLUDES} include/pa_win_wasapi.h include/pa_win_waveformat.h) + SET(PA_SOURCES ${PA_SOURCES} ${PA_WASAPI_SOURCES}) + SET(PA_LIBRARY_DEPENDENCIES ${PA_LIBRARY_DEPENDENCIES} ole32 uuid) + ELSE() + SET(DEF_EXCLUDE_WASAPI_SYMBOLS ";") + ENDIF() + + OPTION(PA_USE_WDMKS "Enable support for WDMKS" ON) + IF(PA_USE_WDMKS) + SET(PA_WDMKS_SOURCES src/hostapi/wdmks/pa_win_wdmks.c) + SOURCE_GROUP("hostapi\\wdmks" FILES ${PA_WDMKS_SOURCES}) + SET(PA_PUBLIC_INCLUDES ${PA_PUBLIC_INCLUDES} include/pa_win_wdmks.h) + SET(PA_SOURCES ${PA_SOURCES} ${PA_WDMKS_SOURCES}) + SET(PA_LIBRARY_DEPENDENCIES ${PA_LIBRARY_DEPENDENCIES} setupapi ole32 uuid) + ENDIF() + + OPTION(PA_USE_WDMKS_DEVICE_INFO "Use WDM/KS API for device info" ON) + MARK_AS_ADVANCED(PA_USE_WDMKS_DEVICE_INFO) + IF(PA_USE_WDMKS_DEVICE_INFO) + SET(PA_PRIVATE_COMPILE_DEFINITIONS ${PA_PRIVATE_COMPILE_DEFINITIONS} PAWIN_USE_WDMKS_DEVICE_INFO) + ENDIF() + + SET(GENERATED_MESSAGE "CMake generated file, do NOT edit! Use CMake-GUI to change configuration instead.") + CONFIGURE_FILE(cmake_support/template_portaudio.def ${CMAKE_CURRENT_BINARY_DIR}/portaudio_cmake.def @ONLY) + CONFIGURE_FILE(cmake_support/options_cmake.h.in ${CMAKE_CURRENT_BINARY_DIR}/options_cmake.h @ONLY) + SET(PA_PRIVATE_INCLUDES ${PA_PRIVATE_INCLUDES} ${CMAKE_CURRENT_BINARY_DIR}/options_cmake.h) + SET(PA_PRIVATE_COMPILE_DEFINITIONS ${PA_PRIVATE_COMPILE_DEFINITIONS} PORTAUDIO_CMAKE_GENERATED) + SOURCE_GROUP("cmake_generated" FILES ${CMAKE_CURRENT_BINARY_DIR}/portaudio_cmake.def ${CMAKE_CURRENT_BINARY_DIR}/options_cmake.h) + + SET(PA_EXTRA_SHARED_SOURCES ${CMAKE_CURRENT_BINARY_DIR}/portaudio_cmake.def) + +ELSE() + + SET(PA_PRIVATE_INCLUDE_PATHS ${PA_PRIVATE_INCLUDE_PATHS} src/os/unix) + SET(PA_PLATFORM_SOURCES src/os/unix/pa_unix_hostapis.c src/os/unix/pa_unix_util.c) + SOURCE_GROUP("os\\unix" FILES ${PA_PLATFORM_SOURCES}) + SET(PA_SOURCES ${PA_SOURCES} ${PA_PLATFORM_SOURCES}) + + IF(APPLE) + + SET(CMAKE_MACOSX_RPATH 1) + OPTION(PA_USE_COREAUDIO "Enable support for CoreAudio" ON) + IF(PA_USE_COREAUDIO) + SET(PA_COREAUDIO_SOURCES + src/hostapi/coreaudio/pa_mac_core.c + src/hostapi/coreaudio/pa_mac_core_blocking.c + src/hostapi/coreaudio/pa_mac_core_utilities.c) + SET(PA_COREAUDIO_INCLUDES + src/hostapi/coreaudio/pa_mac_core_blocking.h + src/hostapi/coreaudio/pa_mac_core_utilities.h) + SOURCE_GROUP("hostapi\\coreaudio" FILES ${PA_COREAUDIO_SOURCES} ${PA_COREAUDIO_INCLUDES}) + SET(PA_PUBLIC_INCLUDES ${PA_PUBLIC_INCLUDES} include/pa_mac_core.h) + SET(PA_PRIVATE_INCLUDES ${PA_PRIVATE_INCLUDES} ${PA_COREAUDIO_INCLUDES}) + SET(PA_SOURCES ${PA_SOURCES} ${PA_COREAUDIO_SOURCES}) + + FIND_LIBRARY(COREAUDIO_LIBRARY CoreAudio REQUIRED) + FIND_LIBRARY(AUDIOTOOLBOX_LIBRARY AudioToolbox REQUIRED) + FIND_LIBRARY(AUDIOUNIT_LIBRARY AudioUnit REQUIRED) + FIND_LIBRARY(CARBON_LIBRARY Carbon REQUIRED) + MARK_AS_ADVANCED(COREAUDIO_LIBRARY AUDIOTOOLBOX_LIBRARY AUDIOUNIT_LIBRARY CARBON_LIBRARY) + SET(PA_LIBRARY_DEPENDENCIES ${PA_LIBRARY_DEPENDENCIES} ${COREAUDIO_LIBRARY} ${AUDIOTOOLBOX_LIBRARY} ${AUDIOUNIT_LIBRARY} ${CARBON_LIBRARY}) + SET(PA_PRIVATE_COMPILE_DEFINITIONS ${PA_PRIVATE_COMPILE_DEFINITIONS} PA_USE_COREAUDIO) + SET(PA_PKGCONFIG_LDFLAGS "${PA_PKGCONFIG_LDFLAGS} -framework CoreAudio -framework AudioToolbox -framework AudioUnit -framework Carbon") + ENDIF() + + ELSEIF(UNIX) + + FIND_PACKAGE(Jack) + IF(JACK_FOUND) + OPTION(PA_USE_JACK "Enable support for Jack" ON) + ELSE() + OPTION(PA_USE_JACK "Enable support for Jack" OFF) + ENDIF() + IF(PA_USE_JACK) + SET(PA_PRIVATE_INCLUDE_PATHS ${PA_PRIVATE_INCLUDE_PATHS} ${JACK_INCLUDE_DIRS}) + SET(PA_JACK_SOURCES src/hostapi/jack/pa_jack.c) + SOURCE_GROUP("hostapi\\JACK" FILES ${PA_JACK_SOURCES}) + SET(PA_PUBLIC_INCLUDES ${PA_PUBLIC_INCLUDES} include/pa_jack.h) + SET(PA_SOURCES ${PA_SOURCES} ${PA_JACK_SOURCES}) + SET(PA_PRIVATE_COMPILE_DEFINITIONS ${PA_PRIVATE_COMPILE_DEFINITIONS} PA_USE_JACK) + SET(PA_LIBRARY_DEPENDENCIES ${PA_LIBRARY_DEPENDENCIES} ${JACK_LIBRARIES}) + SET(PA_PKGCONFIG_LDFLAGS "${PA_PKGCONFIG_LDFLAGS} -ljack") + ENDIF() + + FIND_PACKAGE(ALSA) + IF(ALSA_FOUND) + OPTION(PA_USE_ALSA "Enable support for ALSA" ON) + ELSE() + OPTION(PA_USE_ALSA "Enable support for ALSA" OFF) + ENDIF() + IF(PA_USE_ALSA) + SET(PA_PRIVATE_INCLUDE_PATHS ${PA_PRIVATE_INCLUDE_PATHS} ${ALSA_INCLUDE_DIRS}) + SET(PA_ALSA_SOURCES src/hostapi/alsa/pa_linux_alsa.c) + SOURCE_GROUP("hostapi\\ALSA" FILES ${PA_ALSA_SOURCES}) + SET(PA_PUBLIC_INCLUDES ${PA_PUBLIC_INCLUDES} include/pa_linux_alsa.h) + SET(PA_SOURCES ${PA_SOURCES} ${PA_ALSA_SOURCES}) + SET(PA_PRIVATE_COMPILE_DEFINITIONS ${PA_PRIVATE_COMPILE_DEFINITIONS} PA_USE_ALSA) + SET(PA_LIBRARY_DEPENDENCIES ${PA_LIBRARY_DEPENDENCIES} ${ALSA_LIBRARIES}) + SET(PA_PKGCONFIG_LDFLAGS "${PA_PKGCONFIG_LDFLAGS} -lasound") + ENDIF() + + ENDIF() + + SET(PA_PKGCONFIG_LDFLAGS "${PA_PKGCONFIG_LDFLAGS} -lm -lpthread") + SET(PA_LIBRARY_DEPENDENCIES ${PA_LIBRARY_DEPENDENCIES} m pthread) + +ENDIF() + +SOURCE_GROUP("include" FILES ${PA_PUBLIC_INCLUDES}) + +SET(PA_INCLUDES ${PA_PRIVATE_INCLUDES} ${PA_PUBLIC_INCLUDES}) + +IF(WIN32) + OPTION(PA_UNICODE_BUILD "Enable Portaudio Unicode build" ON) + IF(PA_UNICODE_BUILD) + SET_SOURCE_FILES_PROPERTIES(${PA_SOURCES} PROPERTIES COMPILE_DEFINITIONS "UNICODE;_UNICODE") + ENDIF() +ENDIF() + +OPTION(PA_ENABLE_DEBUG_OUTPUT "Enable debug output for Portaudio" OFF) +IF(PA_ENABLE_DEBUG_OUTPUT) + SET(PA_PRIVATE_COMPILE_DEFINITIONS ${PA_PRIVATE_COMPILE_DEFINITIONS} PA_ENABLE_DEBUG_OUTPUT) +ENDIF() + +if(NOT ENABLE_IOS) +INCLUDE(TestBigEndian) +TEST_BIG_ENDIAN(IS_BIG_ENDIAN) +endif() +IF(IS_BIG_ENDIAN) + SET(PA_PRIVATE_COMPILE_DEFINITIONS ${PA_PRIVATE_COMPILE_DEFINITIONS} PA_BIG_ENDIAN) +ELSE() + SET(PA_PRIVATE_COMPILE_DEFINITIONS ${PA_PRIVATE_COMPILE_DEFINITIONS} PA_LITTLE_ENDIAN) +ENDIF() + +OPTION(PA_BUILD_STATIC "Build static library" ON) +OPTION(PA_BUILD_SHARED "Build shared/dynamic library" ON) + +IF(MSVC) + OPTION(PA_LIBNAME_ADD_SUFFIX "Add suffix _static to static library name" ON) +ELSE() + OPTION(PA_LIBNAME_ADD_SUFFIX "Add suffix _static to static library name" OFF) +ENDIF() + +# MSVC: if PA_LIBNAME_ADD_SUFFIX is not used, and both static and shared libraries are +# built, one, of import- and static libraries, will overwrite the other. In +# embedded builds this is not an issue as they will only build the configuration +# used in the host application. +MARK_AS_ADVANCED(PA_LIBNAME_ADD_SUFFIX) +IF(MSVC AND PA_BUILD_STATIC AND PA_BUILD_SHARED AND NOT PA_LIBNAME_ADD_SUFFIX) + MESSAGE(WARNING "Building both shared and static libraries, and avoiding the suffix _static will lead to a name conflict") + SET(PA_LIBNAME_ADD_SUFFIX ON CACHE BOOL "Forcing use of suffix _static to avoid name conflict between static and import library" FORCE) + MESSAGE(WARNING "PA_LIBNAME_ADD_SUFFIX was set to ON") +ENDIF() + +SET(PA_TARGETS "") + +IF(PA_BUILD_SHARED) + LIST(APPEND PA_TARGETS portaudio) + ADD_LIBRARY(portaudio SHARED ${PA_INCLUDES} ${PA_COMMON_INCLUDES} ${PA_SOURCES} ${PA_NON_UNICODE_SOURCES} ${PA_EXTRA_SHARED_SOURCES}) + SET_PROPERTY(TARGET portaudio APPEND_STRING PROPERTY COMPILE_DEFINITIONS ${PA_PRIVATE_COMPILE_DEFINITIONS}) + TARGET_INCLUDE_DIRECTORIES(portaudio PRIVATE ${PA_PRIVATE_INCLUDE_PATHS}) + TARGET_INCLUDE_DIRECTORIES(portaudio PUBLIC "$") + TARGET_LINK_LIBRARIES(portaudio ${PA_LIBRARY_DEPENDENCIES}) +ENDIF() + +IF(PA_BUILD_STATIC) + LIST(APPEND PA_TARGETS portaudio_static) + ADD_LIBRARY(portaudio_static STATIC ${PA_INCLUDES} ${PA_COMMON_INCLUDES} ${PA_SOURCES} ${PA_NON_UNICODE_SOURCES}) + SET_PROPERTY(TARGET portaudio_static APPEND_STRING PROPERTY COMPILE_DEFINITIONS ${PA_PRIVATE_COMPILE_DEFINITIONS}) + TARGET_INCLUDE_DIRECTORIES(portaudio_static PRIVATE ${PA_PRIVATE_INCLUDE_PATHS}) + TARGET_INCLUDE_DIRECTORIES(portaudio_static PUBLIC "$") + TARGET_LINK_LIBRARIES(portaudio_static ${PA_LIBRARY_DEPENDENCIES}) + IF(NOT PA_LIBNAME_ADD_SUFFIX) + SET_PROPERTY(TARGET portaudio_static PROPERTY OUTPUT_NAME portaudio) + ENDIF() +ENDIF() + +IF(WIN32 AND MSVC) + OPTION(PA_CONFIG_LIB_OUTPUT_PATH "Make sure that output paths are kept neat" OFF) + IF(CMAKE_CL_64) + SET(TARGET_POSTFIX x64) + IF(PA_CONFIG_LIB_OUTPUT_PATH) + SET(LIBRARY_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR}/bin/x64) + ENDIF() + ELSE() + SET(TARGET_POSTFIX x86) + IF(PA_CONFIG_LIB_OUTPUT_PATH) + SET(LIBRARY_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR}/bin/Win32) + ENDIF() + ENDIF() + IF(PA_BUILD_SHARED) + IF(PA_LIBNAME_ADD_SUFFIX) + SET_TARGET_PROPERTIES(portaudio PROPERTIES OUTPUT_NAME portaudio_${TARGET_POSTFIX}) + ELSE() + SET_TARGET_PROPERTIES(portaudio PROPERTIES OUTPUT_NAME portaudio) + ENDIF() + ENDIF() + IF(PA_BUILD_STATIC) + IF(PA_LIBNAME_ADD_SUFFIX) + SET_TARGET_PROPERTIES(portaudio_static PROPERTIES OUTPUT_NAME portaudio_static_${TARGET_POSTFIX}) + ELSE() + SET_TARGET_PROPERTIES(portaudio_static PROPERTIES OUTPUT_NAME portaudio) + ENDIF() + ENDIF() +ELSE() + IF(APPLE AND CMAKE_VERSION VERSION_GREATER 3.4.2) + OPTION(PA_OUTPUT_OSX_FRAMEWORK "Generate an OS X framework instead of the simple library" OFF) + IF(PA_OUTPUT_OSX_FRAMEWORK) + SET_TARGET_PROPERTIES(portaudio PROPERTIES + FRAMEWORK TRUE + MACOSX_FRAMEWORK_IDENTIFIER com.portaudio + FRAMEWORK_VERSION A + PUBLIC_HEADER "${PA_PUBLIC_INCLUDES}" + VERSION ${PA_SOVERSION} + SOVERSION ${PA_SOVERSION}) + ENDIF() + ENDIF() +ENDIF() + +# At least on Windows in embedded builds, portaudio's install target should likely +# not be executed, as the library would usually already be installed as part of, and +# by means of the host application. +# The option below offers the option to avoid executing the portaudio install target +# for cases in which the host-application executes install, but no independent install +# of portaudio is wished. +OPTION(PA_DISABLE_INSTALL "Disable targets install and uninstall (for embedded builds)" OFF) + +IF(NOT PA_OUTPUT_OSX_FRAMEWORK AND NOT PA_DISABLE_INSTALL) + INCLUDE(CMakePackageConfigHelpers) + + CONFIGURE_PACKAGE_CONFIG_FILE(cmake_support/portaudioConfig.cmake.in ${CMAKE_BINARY_DIR}/cmake/portaudio/portaudioConfig.cmake + INSTALL_DESTINATION "lib/cmake/portaudio" + NO_CHECK_REQUIRED_COMPONENTS_MACRO) + WRITE_BASIC_PACKAGE_VERSION_FILE(${CMAKE_BINARY_DIR}/cmake/portaudio/portaudioConfigVersion.cmake + VERSION ${PA_VERSION} + COMPATIBILITY SameMajorVersion) + CONFIGURE_FILE(cmake_support/portaudio-2.0.pc.in ${CMAKE_CURRENT_BINARY_DIR}/portaudio-2.0.pc @ONLY) + INSTALL(FILES README.txt DESTINATION share/doc/portaudio) + INSTALL(FILES LICENSE.txt DESTINATION share/doc/portaudio) + INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/portaudio-2.0.pc DESTINATION lib/pkgconfig) + INSTALL(FILES ${PA_PUBLIC_INCLUDES} DESTINATION include) + INSTALL(TARGETS ${PA_TARGETS} + EXPORT portaudio-targets + RUNTIME DESTINATION bin + LIBRARY DESTINATION lib + ARCHIVE DESTINATION lib) + INSTALL(EXPORT portaudio-targets FILE "portaudioTargets.cmake" DESTINATION "lib/cmake/portaudio") + EXPORT(TARGETS ${PA_TARGETS} FILE "${PROJECT_BINARY_DIR}/cmake/portaudio/portaudioTargets.cmake") + INSTALL(FILES "${CMAKE_BINARY_DIR}/cmake/portaudio/portaudioConfig.cmake" + "${CMAKE_BINARY_DIR}/cmake/portaudio/portaudioConfigVersion.cmake" + DESTINATION "lib/cmake/portaudio") + + IF (NOT TARGET uninstall) + CONFIGURE_FILE( + "${CMAKE_CURRENT_SOURCE_DIR}/cmake_support/cmake_uninstall.cmake.in" + "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" + IMMEDIATE @ONLY) + ADD_CUSTOM_TARGET(uninstall + COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake) + ENDIF() +ENDIF() + +# Prepared for inclusion of test files +OPTION(PA_BUILD_TESTS "Include test projects" OFF) +IF(PA_BUILD_TESTS) + SUBDIRS(test) +ENDIF() + +# Prepared for inclusion of test files +OPTION(PA_BUILD_EXAMPLES "Include example projects" OFF) +IF(PA_BUILD_EXAMPLES) + SUBDIRS(examples) +ENDIF() diff --git a/extern/portaudio/Doxyfile b/extern/portaudio/Doxyfile new file mode 100644 index 0000000..1288182 --- /dev/null +++ b/extern/portaudio/Doxyfile @@ -0,0 +1,239 @@ +# Doxyfile 1.4.6 + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- +PROJECT_NAME = PortAudio +PROJECT_NUMBER = 2.0 +OUTPUT_DIRECTORY = ./doc/ +CREATE_SUBDIRS = NO +OUTPUT_LANGUAGE = English +USE_WINDOWS_ENCODING = NO +BRIEF_MEMBER_DESC = YES +REPEAT_BRIEF = YES +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the +ALWAYS_DETAILED_SEC = NO +INLINE_INHERITED_MEMB = NO +FULL_PATH_NAMES = NO +STRIP_FROM_PATH = +STRIP_FROM_INC_PATH = +SHORT_NAMES = NO +JAVADOC_AUTOBRIEF = NO +MULTILINE_CPP_IS_BRIEF = NO +DETAILS_AT_TOP = NO +INHERIT_DOCS = YES +SEPARATE_MEMBER_PAGES = NO +TAB_SIZE = 8 +ALIASES = +OPTIMIZE_OUTPUT_FOR_C = YES +OPTIMIZE_OUTPUT_JAVA = NO +BUILTIN_STL_SUPPORT = NO +DISTRIBUTE_GROUP_DOC = NO +SUBGROUPING = YES +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- +EXTRACT_ALL = NO +EXTRACT_PRIVATE = NO +EXTRACT_STATIC = NO +EXTRACT_LOCAL_CLASSES = YES +EXTRACT_LOCAL_METHODS = NO +HIDE_UNDOC_MEMBERS = NO +HIDE_UNDOC_CLASSES = NO +HIDE_FRIEND_COMPOUNDS = NO +HIDE_IN_BODY_DOCS = NO +INTERNAL_DOCS = NO +CASE_SENSE_NAMES = YES +HIDE_SCOPE_NAMES = NO +SHOW_INCLUDE_FILES = YES +INLINE_INFO = YES +SORT_MEMBER_DOCS = YES +SORT_BRIEF_DOCS = NO +SORT_BY_SCOPE_NAME = NO +GENERATE_TODOLIST = NO +GENERATE_TESTLIST = NO +GENERATE_BUGLIST = NO +GENERATE_DEPRECATEDLIST= YES +ENABLED_SECTIONS = +MAX_INITIALIZER_LINES = 30 +SHOW_USED_FILES = YES +SHOW_DIRECTORIES = YES +FILE_VERSION_FILTER = +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- +QUIET = NO +WARNINGS = YES +WARN_IF_UNDOCUMENTED = YES +WARN_IF_DOC_ERROR = YES +WARN_NO_PARAMDOC = NO +WARN_FORMAT = "$file:$line: $text" +WARN_LOGFILE = +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- +INPUT = doc/src \ + include \ + examples +FILE_PATTERNS = *.h \ + *.c \ + *.cpp \ + *.java \ + *.dox +RECURSIVE = YES +EXCLUDE = src/hostapi/wasapi/mingw-include +EXCLUDE_SYMLINKS = NO +EXCLUDE_PATTERNS = +EXAMPLE_PATH = +EXAMPLE_PATTERNS = +EXAMPLE_RECURSIVE = NO +IMAGE_PATH = doc/src/images +INPUT_FILTER = +FILTER_PATTERNS = +FILTER_SOURCE_FILES = NO +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- +SOURCE_BROWSER = YES +INLINE_SOURCES = NO +STRIP_CODE_COMMENTS = YES +REFERENCED_BY_RELATION = YES +REFERENCES_RELATION = YES +USE_HTAGS = NO +VERBATIM_HEADERS = YES +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- +ALPHABETICAL_INDEX = NO +COLS_IN_ALPHA_INDEX = 5 +IGNORE_PREFIX = +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- +GENERATE_HTML = YES +HTML_OUTPUT = html +HTML_FILE_EXTENSION = .html +HTML_HEADER = +HTML_FOOTER = +HTML_STYLESHEET = +HTML_ALIGN_MEMBERS = YES +GENERATE_HTMLHELP = NO +CHM_FILE = +HHC_LOCATION = +GENERATE_CHI = NO +BINARY_TOC = NO +TOC_EXPAND = NO +DISABLE_INDEX = NO +ENUM_VALUES_PER_LINE = 4 +GENERATE_TREEVIEW = NO +TREEVIEW_WIDTH = 250 +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- +GENERATE_LATEX = NO +LATEX_OUTPUT = latex +LATEX_CMD_NAME = latex +MAKEINDEX_CMD_NAME = makeindex +COMPACT_LATEX = NO +PAPER_TYPE = a4wide +EXTRA_PACKAGES = +LATEX_HEADER = +PDF_HYPERLINKS = NO +USE_PDFLATEX = NO +LATEX_BATCHMODE = NO +LATEX_HIDE_INDICES = NO +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- +GENERATE_RTF = NO +RTF_OUTPUT = rtf +COMPACT_RTF = NO +RTF_HYPERLINKS = NO +RTF_STYLESHEET_FILE = +RTF_EXTENSIONS_FILE = +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- +GENERATE_MAN = NO +MAN_OUTPUT = man +MAN_EXTENSION = .3 +MAN_LINKS = NO +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- +GENERATE_XML = NO +XML_OUTPUT = xml +XML_SCHEMA = +XML_DTD = +XML_PROGRAMLISTING = YES +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- +GENERATE_AUTOGEN_DEF = NO +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- +GENERATE_PERLMOD = NO +PERLMOD_LATEX = NO +PERLMOD_PRETTY = YES +PERLMOD_MAKEVAR_PREFIX = +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- +ENABLE_PREPROCESSING = YES +MACRO_EXPANSION = NO +EXPAND_ONLY_PREDEF = NO +SEARCH_INCLUDES = YES +INCLUDE_PATH = +INCLUDE_FILE_PATTERNS = +PREDEFINED = +EXPAND_AS_DEFINED = +SKIP_FUNCTION_MACROS = YES +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- +TAGFILES = +GENERATE_TAGFILE = +ALLEXTERNALS = NO +EXTERNAL_GROUPS = YES +PERL_PATH = /usr/bin/perl +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- +CLASS_DIAGRAMS = NO +HIDE_UNDOC_RELATIONS = NO +HAVE_DOT = NO +CLASS_GRAPH = YES +COLLABORATION_GRAPH = YES +GROUP_GRAPHS = YES +UML_LOOK = NO +TEMPLATE_RELATIONS = YES +INCLUDE_GRAPH = YES +INCLUDED_BY_GRAPH = YES +CALL_GRAPH = NO +GRAPHICAL_HIERARCHY = YES +DIRECTORY_GRAPH = YES +DOT_IMAGE_FORMAT = png +DOT_PATH = +DOTFILE_DIRS = +MAX_DOT_GRAPH_WIDTH = 1024 +MAX_DOT_GRAPH_HEIGHT = 1024 +MAX_DOT_GRAPH_DEPTH = 1000 +DOT_TRANSPARENT = NO +DOT_MULTI_TARGETS = NO +GENERATE_LEGEND = YES +DOT_CLEANUP = YES +#--------------------------------------------------------------------------- +# Configuration::additions related to the search engine +#--------------------------------------------------------------------------- +SEARCHENGINE = NO diff --git a/extern/portaudio/Doxyfile.developer b/extern/portaudio/Doxyfile.developer new file mode 100644 index 0000000..c444652 --- /dev/null +++ b/extern/portaudio/Doxyfile.developer @@ -0,0 +1,242 @@ +# Doxyfile 1.4.6 + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- +PROJECT_NAME = PortAudio +PROJECT_NUMBER = 2.0 +OUTPUT_DIRECTORY = ./doc/ +CREATE_SUBDIRS = NO +OUTPUT_LANGUAGE = English +USE_WINDOWS_ENCODING = NO +BRIEF_MEMBER_DESC = YES +REPEAT_BRIEF = YES +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the +ALWAYS_DETAILED_SEC = NO +INLINE_INHERITED_MEMB = NO +FULL_PATH_NAMES = NO +STRIP_FROM_PATH = +STRIP_FROM_INC_PATH = +SHORT_NAMES = NO +JAVADOC_AUTOBRIEF = NO +MULTILINE_CPP_IS_BRIEF = NO +DETAILS_AT_TOP = NO +INHERIT_DOCS = YES +SEPARATE_MEMBER_PAGES = NO +TAB_SIZE = 8 +ALIASES = +OPTIMIZE_OUTPUT_FOR_C = YES +OPTIMIZE_OUTPUT_JAVA = NO +BUILTIN_STL_SUPPORT = NO +DISTRIBUTE_GROUP_DOC = NO +SUBGROUPING = YES +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- +EXTRACT_ALL = YES +EXTRACT_PRIVATE = NO +EXTRACT_STATIC = NO +EXTRACT_LOCAL_CLASSES = YES +EXTRACT_LOCAL_METHODS = NO +HIDE_UNDOC_MEMBERS = NO +HIDE_UNDOC_CLASSES = NO +HIDE_FRIEND_COMPOUNDS = NO +HIDE_IN_BODY_DOCS = NO +INTERNAL_DOCS = YES +CASE_SENSE_NAMES = YES +HIDE_SCOPE_NAMES = NO +SHOW_INCLUDE_FILES = YES +INLINE_INFO = YES +SORT_MEMBER_DOCS = YES +SORT_BRIEF_DOCS = NO +SORT_BY_SCOPE_NAME = NO +GENERATE_TODOLIST = YES +GENERATE_TESTLIST = YES +GENERATE_BUGLIST = YES +GENERATE_DEPRECATEDLIST= YES +ENABLED_SECTIONS = INTERNAL +MAX_INITIALIZER_LINES = 30 +SHOW_USED_FILES = YES +SHOW_DIRECTORIES = YES +FILE_VERSION_FILTER = +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- +QUIET = NO +WARNINGS = YES +WARN_IF_UNDOCUMENTED = YES +WARN_IF_DOC_ERROR = YES +WARN_NO_PARAMDOC = NO +WARN_FORMAT = "$file:$line: $text" +WARN_LOGFILE = +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- +INPUT = doc/src \ + include \ + examples \ + src \ + test \ + qa +FILE_PATTERNS = *.h \ + *.c \ + *.cpp \ + *.java \ + *.dox +RECURSIVE = YES +EXCLUDE = src/hostapi/wasapi/mingw-include +EXCLUDE_SYMLINKS = NO +EXCLUDE_PATTERNS = +EXAMPLE_PATH = +EXAMPLE_PATTERNS = +EXAMPLE_RECURSIVE = NO +IMAGE_PATH = doc/src/images +INPUT_FILTER = +FILTER_PATTERNS = +FILTER_SOURCE_FILES = NO +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- +SOURCE_BROWSER = NO +INLINE_SOURCES = NO +STRIP_CODE_COMMENTS = YES +REFERENCED_BY_RELATION = YES +REFERENCES_RELATION = YES +USE_HTAGS = NO +VERBATIM_HEADERS = YES +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- +ALPHABETICAL_INDEX = NO +COLS_IN_ALPHA_INDEX = 5 +IGNORE_PREFIX = +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- +GENERATE_HTML = YES +HTML_OUTPUT = html +HTML_FILE_EXTENSION = .html +HTML_HEADER = +HTML_FOOTER = +HTML_STYLESHEET = +HTML_ALIGN_MEMBERS = YES +GENERATE_HTMLHELP = NO +CHM_FILE = +HHC_LOCATION = +GENERATE_CHI = NO +BINARY_TOC = NO +TOC_EXPAND = NO +DISABLE_INDEX = NO +ENUM_VALUES_PER_LINE = 4 +GENERATE_TREEVIEW = NO +TREEVIEW_WIDTH = 250 +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- +GENERATE_LATEX = NO +LATEX_OUTPUT = latex +LATEX_CMD_NAME = latex +MAKEINDEX_CMD_NAME = makeindex +COMPACT_LATEX = NO +PAPER_TYPE = a4wide +EXTRA_PACKAGES = +LATEX_HEADER = +PDF_HYPERLINKS = NO +USE_PDFLATEX = NO +LATEX_BATCHMODE = NO +LATEX_HIDE_INDICES = NO +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- +GENERATE_RTF = NO +RTF_OUTPUT = rtf +COMPACT_RTF = NO +RTF_HYPERLINKS = NO +RTF_STYLESHEET_FILE = +RTF_EXTENSIONS_FILE = +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- +GENERATE_MAN = NO +MAN_OUTPUT = man +MAN_EXTENSION = .3 +MAN_LINKS = NO +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- +GENERATE_XML = NO +XML_OUTPUT = xml +XML_SCHEMA = +XML_DTD = +XML_PROGRAMLISTING = YES +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- +GENERATE_AUTOGEN_DEF = NO +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- +GENERATE_PERLMOD = NO +PERLMOD_LATEX = NO +PERLMOD_PRETTY = YES +PERLMOD_MAKEVAR_PREFIX = +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- +ENABLE_PREPROCESSING = YES +MACRO_EXPANSION = NO +EXPAND_ONLY_PREDEF = NO +SEARCH_INCLUDES = YES +INCLUDE_PATH = +INCLUDE_FILE_PATTERNS = +PREDEFINED = +EXPAND_AS_DEFINED = +SKIP_FUNCTION_MACROS = YES +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- +TAGFILES = +GENERATE_TAGFILE = +ALLEXTERNALS = NO +EXTERNAL_GROUPS = YES +PERL_PATH = /usr/bin/perl +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- +CLASS_DIAGRAMS = NO +HIDE_UNDOC_RELATIONS = NO +HAVE_DOT = NO +CLASS_GRAPH = YES +COLLABORATION_GRAPH = YES +GROUP_GRAPHS = YES +UML_LOOK = NO +TEMPLATE_RELATIONS = YES +INCLUDE_GRAPH = YES +INCLUDED_BY_GRAPH = YES +CALL_GRAPH = NO +GRAPHICAL_HIERARCHY = YES +DIRECTORY_GRAPH = YES +DOT_IMAGE_FORMAT = png +DOT_PATH = +DOTFILE_DIRS = +MAX_DOT_GRAPH_WIDTH = 1024 +MAX_DOT_GRAPH_HEIGHT = 1024 +MAX_DOT_GRAPH_DEPTH = 1000 +DOT_TRANSPARENT = NO +DOT_MULTI_TARGETS = NO +GENERATE_LEGEND = YES +DOT_CLEANUP = YES +#--------------------------------------------------------------------------- +# Configuration::additions related to the search engine +#--------------------------------------------------------------------------- +SEARCHENGINE = NO diff --git a/extern/portaudio/LICENSE.txt b/extern/portaudio/LICENSE.txt new file mode 100644 index 0000000..e0ac4e8 --- /dev/null +++ b/extern/portaudio/LICENSE.txt @@ -0,0 +1,81 @@ +Portable header file to contain: +>>>>> +/* + * PortAudio Portable Real-Time Audio Library + * PortAudio API Header File + * Latest version available at: http://www.portaudio.com + * + * Copyright (c) 1999-2006 Ross Bencina and Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ +<<<<< + + +Implementation files to contain: +>>>>> +/* + * PortAudio Portable Real-Time Audio Library + * Latest version at: http://www.portaudio.com + * Implementation + * Copyright (c) 1999-2000 + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ +<<<<< \ No newline at end of file diff --git a/extern/portaudio/Makefile.in b/extern/portaudio/Makefile.in new file mode 100644 index 0000000..5e1a764 --- /dev/null +++ b/extern/portaudio/Makefile.in @@ -0,0 +1,257 @@ +# +# PortAudio V19 Makefile.in +# +# Dominic Mazzoni +# Modifications by Mikael Magnusson +# Modifications by Stelios Bounanos +# + +top_srcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ +top_builddir = . +PREFIX = @prefix@ +prefix = $(PREFIX) +exec_prefix = @exec_prefix@ +bindir = @bindir@ +libdir = @libdir@ +includedir = @includedir@ +CC = @CC@ +CXX = @CXX@ +CFLAGS = @CFLAGS@ @DEFS@ +LIBS = @LIBS@ +AR = @AR@ +RANLIB = @RANLIB@ +SHELL = @SHELL@ +LIBTOOL = @LIBTOOL@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +SHARED_FLAGS = @SHARED_FLAGS@ +LDFLAGS = @LDFLAGS@ +DLL_LIBS = @DLL_LIBS@ +CXXFLAGS = @CXXFLAGS@ +NASM = @NASM@ +NASMOPT = @NASMOPT@ +LN_S = @LN_S@ +LT_CURRENT=@LT_CURRENT@ +LT_REVISION=@LT_REVISION@ +LT_AGE=@LT_AGE@ + +OTHER_OBJS = @OTHER_OBJS@ +INCLUDES = @INCLUDES@ + +PALIB = libportaudio.la +PAINC = include/portaudio.h + +PA_LDFLAGS = $(LDFLAGS) $(SHARED_FLAGS) -rpath $(libdir) -no-undefined \ + -export-symbols-regex "(Pa|PaMacCore|PaJack|PaAlsa|PaAsio|PaOSS)_.*" \ + -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) + +COMMON_OBJS = \ + src/common/pa_allocation.o \ + src/common/pa_converters.o \ + src/common/pa_cpuload.o \ + src/common/pa_dither.o \ + src/common/pa_debugprint.o \ + src/common/pa_front.o \ + src/common/pa_process.o \ + src/common/pa_stream.o \ + src/common/pa_trace.o \ + src/hostapi/skeleton/pa_hostapi_skeleton.o + +LOOPBACK_OBJS = \ + qa/loopback/src/audio_analyzer.o \ + qa/loopback/src/biquad_filter.o \ + qa/loopback/src/paqa_tools.o \ + qa/loopback/src/test_audio_analyzer.o \ + qa/loopback/src/write_wav.o \ + qa/loopback/src/paqa.o + +EXAMPLES = \ + bin/pa_devs \ + bin/pa_fuzz \ + bin/paex_pink \ + bin/paex_read_write_wire \ + bin/paex_record \ + bin/paex_saw \ + bin/paex_sine \ + bin/paex_write_sine \ + bin/paex_write_sine_nonint + +SELFTESTS = \ + bin/paqa_devs \ + bin/paqa_errs \ + bin/paqa_latency + +TESTS = \ + bin/patest1 \ + bin/patest_buffer \ + bin/patest_callbackstop \ + bin/patest_clip \ + bin/patest_dither \ + bin/patest_hang \ + bin/patest_in_overflow \ + bin/patest_latency \ + bin/patest_leftright \ + bin/patest_longsine \ + bin/patest_many \ + bin/patest_maxsines \ + bin/patest_mono \ + bin/patest_multi_sine \ + bin/patest_out_underflow \ + bin/patest_prime \ + bin/patest_ringmix \ + bin/patest_sine8 \ + bin/patest_sine_channelmaps \ + bin/patest_sine_formats \ + bin/patest_sine_time \ + bin/patest_sine_srate \ + bin/patest_start_stop \ + bin/patest_stop \ + bin/patest_stop_playout \ + bin/patest_toomanysines \ + bin/patest_two_rates \ + bin/patest_underflow \ + bin/patest_wire \ + bin/pa_minlat + +# Most of these don't compile yet. Put them in TESTS, above, if +# you want to try to compile them... +ALL_TESTS = \ + $(TESTS) \ + bin/patest_sync \ + bin/debug_convert \ + bin/debug_dither_calc \ + bin/debug_dual \ + bin/debug_multi_in \ + bin/debug_multi_out \ + bin/debug_record \ + bin/debug_record_reuse \ + bin/debug_sine_amp \ + bin/debug_sine \ + bin/debug_sine_formats \ + bin/debug_srate \ + bin/debug_test1 + +OBJS := $(COMMON_OBJS) $(OTHER_OBJS) + +LTOBJS := $(OBJS:.o=.lo) + +SRC_DIRS = \ + src/common \ + src/hostapi/alsa \ + src/hostapi/asihpi \ + src/hostapi/asio \ + src/hostapi/coreaudio \ + src/hostapi/dsound \ + src/hostapi/jack \ + src/hostapi/oss \ + src/hostapi/wasapi \ + src/hostapi/wdmks \ + src/hostapi/wmme \ + src/os/unix \ + src/os/win + +SUBDIRS = +@ENABLE_CXX_TRUE@SUBDIRS += bindings/cpp + +all: lib/$(PALIB) all-recursive tests examples selftests + +tests: bin-stamp $(TESTS) + +examples: bin-stamp $(EXAMPLES) + +selftests: bin-stamp $(SELFTESTS) + +loopback: bin-stamp bin/paloopback + +# With ASIO enabled we must link libportaudio and all test programs with CXX +lib/$(PALIB): lib-stamp $(LTOBJS) $(MAKEFILE) $(PAINC) + @WITH_ASIO_FALSE@ $(LIBTOOL) --mode=link $(CC) $(PA_LDFLAGS) -o lib/$(PALIB) $(LTOBJS) $(DLL_LIBS) + @WITH_ASIO_TRUE@ $(LIBTOOL) --mode=link --tag=CXX $(CXX) $(PA_LDFLAGS) -o lib/$(PALIB) $(LTOBJS) $(DLL_LIBS) + +$(ALL_TESTS): bin/%: lib/$(PALIB) $(MAKEFILE) $(PAINC) test/%.c + @WITH_ASIO_FALSE@ $(LIBTOOL) --mode=link $(CC) -o $@ $(CFLAGS) $(top_srcdir)/test/$*.c lib/$(PALIB) $(LIBS) + @WITH_ASIO_TRUE@ $(LIBTOOL) --mode=link --tag=CXX $(CXX) -o $@ $(CXXFLAGS) $(top_srcdir)/test/$*.c lib/$(PALIB) $(LIBS) + +$(EXAMPLES): bin/%: lib/$(PALIB) $(MAKEFILE) $(PAINC) examples/%.c + @WITH_ASIO_FALSE@ $(LIBTOOL) --mode=link $(CC) -o $@ $(CFLAGS) $(top_srcdir)/examples/$*.c lib/$(PALIB) $(LIBS) + @WITH_ASIO_TRUE@ $(LIBTOOL) --mode=link --tag=CXX $(CXX) -o $@ $(CXXFLAGS) $(top_srcdir)/examples/$*.c lib/$(PALIB) $(LIBS) + +$(SELFTESTS): bin/%: lib/$(PALIB) $(MAKEFILE) $(PAINC) qa/%.c + @WITH_ASIO_FALSE@ $(LIBTOOL) --mode=link $(CC) -o $@ $(CFLAGS) $(top_srcdir)/qa/$*.c lib/$(PALIB) $(LIBS) + @WITH_ASIO_TRUE@ $(LIBTOOL) --mode=link --tag=CXX $(CXX) -o $@ $(CXXFLAGS) $(top_srcdir)/qa/$*.c lib/$(PALIB) $(LIBS) + +bin/paloopback: lib/$(PALIB) $(MAKEFILE) $(PAINC) $(LOOPBACK_OBJS) + @WITH_ASIO_FALSE@ $(LIBTOOL) --mode=link $(CC) -o $@ $(CFLAGS) $(LOOPBACK_OBJS) lib/$(PALIB) $(LIBS) + @WITH_ASIO_TRUE@ $(LIBTOOL) --mode=link --tag=CXX $(CXX) -o $@ $(CXXFLAGS) $(LOOPBACK_OBJS) lib/$(PALIB) $(LIBS) + +install: lib/$(PALIB) portaudio-2.0.pc + $(INSTALL) -d $(DESTDIR)$(libdir) + $(LIBTOOL) --mode=install $(INSTALL) lib/$(PALIB) $(DESTDIR)$(libdir) + $(INSTALL) -d $(DESTDIR)$(includedir) + for include in $(INCLUDES); do \ + $(INSTALL_DATA) -m 644 $(top_srcdir)/include/$$include $(DESTDIR)$(includedir)/$$include; \ + done + $(INSTALL) -d $(DESTDIR)$(libdir)/pkgconfig + $(INSTALL) -m 644 portaudio-2.0.pc $(DESTDIR)$(libdir)/pkgconfig/portaudio-2.0.pc + @echo "" + @echo "------------------------------------------------------------" + @echo "PortAudio was successfully installed." + @echo "" + @echo "On some systems (e.g. Linux) you should run 'ldconfig' now" + @echo "to make the shared object available. You may also need to" + @echo "modify your LD_LIBRARY_PATH environment variable to include" + @echo "the directory $(libdir)" + @echo "------------------------------------------------------------" + @echo "" + $(MAKE) install-recursive + +uninstall: + $(LIBTOOL) --mode=uninstall rm -f $(DESTDIR)$(libdir)/$(PALIB) + $(LIBTOOL) --mode=uninstall rm -f $(DESTDIR)$(includedir)/portaudio.h + $(MAKE) uninstall-recursive + +clean: + $(LIBTOOL) --mode=clean rm -f $(LTOBJS) $(LOOPBACK_OBJS) $(ALL_TESTS) lib/$(PALIB) + $(RM) bin-stamp lib-stamp + -$(RM) -r bin lib + +distclean: clean + $(RM) config.log config.status Makefile libtool portaudio-2.0.pc + +%.o: %.c $(MAKEFILE) $(PAINC) + $(CC) -c $(CFLAGS) $< -o $@ + +%.lo: %.c $(MAKEFILE) $(PAINC) + $(LIBTOOL) --mode=compile $(CC) -c $(CFLAGS) $< -o $@ + +%.lo: %.cpp $(MAKEFILE) $(PAINC) + $(LIBTOOL) --mode=compile --tag=CXX $(CXX) -c $(CXXFLAGS) $< -o $@ + +%.o: %.cpp $(MAKEFILE) $(PAINC) + $(CXX) -c $(CXXFLAGS) $< -o $@ + +%.o: %.asm + $(NASM) $(NASMOPT) -o $@ $< + +bin-stamp: + -mkdir bin + touch $@ + +lib-stamp: + -mkdir lib + -mkdir -p $(SRC_DIRS) + touch $@ + +Makefile: Makefile.in config.status + $(SHELL) config.status + +all-recursive: + if test -n "$(SUBDIRS)" ; then for dir in "$(SUBDIRS)"; do $(MAKE) -C $$dir all; done ; fi + +install-recursive: + if test -n "$(SUBDIRS)" ; then for dir in "$(SUBDIRS)"; do $(MAKE) -C $$dir install; done ; fi + +uninstall-recursive: + if test -n "$(SUBDIRS)" ; then for dir in "$(SUBDIRS)"; do $(MAKE) -C $$dir uninstall; done ; fi diff --git a/extern/portaudio/README.configure.txt b/extern/portaudio/README.configure.txt new file mode 100644 index 0000000..6417d65 --- /dev/null +++ b/extern/portaudio/README.configure.txt @@ -0,0 +1,32 @@ +PortAudio uses "autoconf" tools to generate Makefiles for Linux and Mac platforms. +The source for these are configure.in and Makefile.in +If you modify either of these files then please run this command before +testing and checking in your changes. I run this command on Linux. + + autoreconf -if + +If you do not have autoreconf then do: + sudo apt-get install autoconf + +If you get error like "possibly undefined macro: AC_LIBTOOL_WIN32_DLL" +then you try installing some more packages and then try again. + + sudo apt-get install build-essential + sudo apt-get install pkg-config + sudo apt-get install libtool + autoreconf -if + +Then test a build by doing: + + ./configure + make clean + make + +then check in the related files that are modified. +These might include files like: + + configure + config.guess + depcomp + install.sh + diff --git a/extern/portaudio/README.txt b/extern/portaudio/README.txt new file mode 100644 index 0000000..2113827 --- /dev/null +++ b/extern/portaudio/README.txt @@ -0,0 +1,98 @@ +README for PortAudio + +/* + * PortAudio Portable Real-Time Audio Library + * Latest Version at: http://www.portaudio.com + * + * Copyright (c) 1999-2008 Phil Burk and Ross Bencina + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + + +PortAudio is a portable audio I/O library designed for cross-platform +support of audio. It uses either a callback mechanism to request audio +processing, or blocking read/write calls to buffer data between the +native audio subsystem and the client. Audio can be processed in various +formats, including 32 bit floating point, and will be converted to the +native format internally. + +Documentation: + Documentation is available in "/doc/html/index.html" + Also see "src/common/portaudio.h" for API spec. + Also see http://www.portaudio.com/docs/ + And see the "test/" directory for many examples of usage + (we suggest "test/patest_saw.c" for an example) + +For information on compiling programs with PortAudio, please see the +tutorial at: + + http://portaudio.com/trac/wiki/TutorialDir/TutorialStart + +We have an active mailing list for user and developer discussions. +Please feel free to join. See http://www.portaudio.com for details. + + +Important Files and Folders: + include/portaudio.h = header file for PortAudio API. Specifies API. + src/common/ = platform independant code, host independant + code for all implementations. + src/os = os specific (but host api neutral) code + src/hostapi = implementations for different host apis + + +Host API Implementations: + src/hostapi/alsa = Advanced Linux Sound Architecture (ALSA) + src/hostapi/asihpi = AudioScience HPI + src/hostapi/asio = ASIO for Windows and Macintosh + src/hostapi/coreaudio = Macintosh Core Audio for OS X + src/hostapi/dsound = Windows Direct Sound + src/hostapi/jack = JACK Audio Connection Kit + src/hostapi/oss = Unix Open Sound System (OSS) + src/hostapi/wasapi = Windows Vista WASAPI + src/hostapi/wdmks = Windows WDM Kernel Streaming + src/hostapi/wmme = Windows MultiMedia Extensions (MME) + + +Test Programs: + test/pa_fuzz.c = guitar fuzz box + test/pa_devs.c = print a list of available devices + test/pa_minlat.c = determine minimum latency for your machine + test/paqa_devs.c = self test that opens all devices + test/paqa_errs.c = test error detection and reporting + test/patest_clip.c = hear a sine wave clipped and unclipped + test/patest_dither.c = hear effects of dithering (extremely subtle) + test/patest_pink.c = fun with pink noise + test/patest_record.c = record and playback some audio + test/patest_maxsines.c = how many sine waves can we play? Tests Pa_GetCPULoad(). + test/patest_sine.c = output a sine wave in a simple PA app + test/patest_sync.c = test syncronization of audio and video + test/patest_wire.c = pass input to output, wire simulator diff --git a/extern/portaudio/SConstruct b/extern/portaudio/SConstruct new file mode 100644 index 0000000..37e67ba --- /dev/null +++ b/extern/portaudio/SConstruct @@ -0,0 +1,197 @@ +import sys, os.path + +def rsplit(toSplit, sub, max=-1): + """ str.rsplit seems to have been introduced in 2.4 :( """ + l = [] + i = 0 + while i != max: + try: idx = toSplit.rindex(sub) + except ValueError: break + + toSplit, splitOff = toSplit[:idx], toSplit[idx + len(sub):] + l.insert(0, splitOff) + i += 1 + + l.insert(0, toSplit) + return l + +sconsDir = os.path.join("build", "scons") +SConscript(os.path.join(sconsDir, "SConscript_common")) +Import("Platform", "Posix", "ApiVer") + +# SConscript_opts exports PortAudio options +optsDict = SConscript(os.path.join(sconsDir, "SConscript_opts")) +optionsCache = os.path.join(sconsDir, "options.cache") # Save options between runs in this cache +options = Options(optionsCache, args=ARGUMENTS) +for k in ("Installation Dirs", "Build Targets", "Host APIs", "Build Parameters", "Bindings"): + options.AddOptions(*optsDict[k]) +# Propagate options into environment +env = Environment(options=options) +# Save options for next run +options.Save(optionsCache, env) +# Generate help text for options +env.Help(options.GenerateHelpText(env)) + +buildDir = os.path.join("#", sconsDir, env["PLATFORM"]) + +# Determine parameters to build tools +if Platform in Posix: + threadCFlags = '' + if Platform != 'darwin': + threadCFlags = "-pthread " + baseLinkFlags = threadCFlags + baseCxxFlags = baseCFlags = "-Wall -pedantic -pipe " + threadCFlags + debugCxxFlags = debugCFlags = "-g" + optCxxFlags = optCFlags = "-O2" +env.Append(CCFLAGS = baseCFlags) +env.Append(CXXFLAGS = baseCxxFlags) +env.Append(LINKFLAGS = baseLinkFlags) +if env["enableDebug"]: + env.AppendUnique(CCFLAGS=debugCFlags.split()) + env.AppendUnique(CXXFLAGS=debugCxxFlags.split()) +if env["enableOptimize"]: + env.AppendUnique(CCFLAGS=optCFlags.split()) + env.AppendUnique(CXXFLAGS=optCxxFlags.split()) +if not env["enableAsserts"]: + env.AppendUnique(CPPDEFINES=["-DNDEBUG"]) +if env["customCFlags"]: + env.Append(CCFLAGS=Split(env["customCFlags"])) +if env["customCxxFlags"]: + env.Append(CXXFLAGS=Split(env["customCxxFlags"])) +if env["customLinkFlags"]: + env.Append(LINKFLAGS=Split(env["customLinkFlags"])) + +env.Append(CPPPATH=[os.path.join("#", "include"), "common"]) + +# Store all signatures in one file, otherwise .sconsign files will get installed along with our own files +env.SConsignFile(os.path.join(sconsDir, ".sconsign")) + +env.SConscriptChdir(False) +sources, sharedLib, staticLib, tests, portEnv, hostApis = env.SConscript(os.path.join("src", "SConscript"), + build_dir=buildDir, duplicate=False, exports=["env"]) + +if Platform in Posix: + prefix = env["prefix"] + includeDir = os.path.join(prefix, "include") + libDir = os.path.join(prefix, "lib") + env.Alias("install", includeDir) + env.Alias("install", libDir) + + # pkg-config + + def installPkgconfig(env, target, source): + tgt = str(target[0]) + src = str(source[0]) + f = open(src) + try: txt = f.read() + finally: f.close() + txt = txt.replace("@prefix@", prefix) + txt = txt.replace("@exec_prefix@", prefix) + txt = txt.replace("@libdir@", libDir) + txt = txt.replace("@includedir@", includeDir) + txt = txt.replace("@LIBS@", " ".join(["-l%s" % l for l in portEnv["LIBS"]])) + txt = txt.replace("@THREAD_CFLAGS@", threadCFlags) + + f = open(tgt, "w") + try: f.write(txt) + finally: f.close() + + pkgconfigTgt = "portaudio-%d.0.pc" % int(ApiVer.split(".", 1)[0]) + env.Command(os.path.join(libDir, "pkgconfig", pkgconfigTgt), + os.path.join("#", pkgconfigTgt + ".in"), installPkgconfig) + +# Default to None, since if the user disables all targets and no Default is set, all targets +# are built by default +env.Default(None) +if env["enableTests"]: + env.Default(tests) +if env["enableShared"]: + env.Default(sharedLib) + + if Platform in Posix: + def symlink(env, target, source): + trgt = str(target[0]) + src = str(source[0]) + + if os.path.islink(trgt) or os.path.exists(trgt): + os.remove(trgt) + os.symlink(os.path.basename(src), trgt) + + major, minor, micro = [int(c) for c in ApiVer.split(".")] + + soFile = "%s.%s" % (os.path.basename(str(sharedLib[0])), ApiVer) + env.InstallAs(target=os.path.join(libDir, soFile), source=sharedLib) + # Install symlinks + symTrgt = os.path.join(libDir, soFile) + env.Command(os.path.join(libDir, "libportaudio.so.%d.%d" % (major, minor)), + symTrgt, symlink) + symTrgt = rsplit(symTrgt, ".", 1)[0] + env.Command(os.path.join(libDir, "libportaudio.so.%d" % major), symTrgt, symlink) + symTrgt = rsplit(symTrgt, ".", 1)[0] + env.Command(os.path.join(libDir, "libportaudio.so"), symTrgt, symlink) + +if env["enableStatic"]: + env.Default(staticLib) + env.Install(libDir, staticLib) + +env.Install(includeDir, os.path.join("include", "portaudio.h")) + + +if env["enableCxx"]: + env.SConscriptChdir(True) + cxxEnv = env.Copy() + sharedLibs, staticLibs, headers = env.SConscript(os.path.join("bindings", "cpp", "SConscript"), + exports={"env": cxxEnv, "buildDir": buildDir}, build_dir=os.path.join(buildDir, "portaudiocpp"), duplicate=False) + if env["enableStatic"]: + env.Default(staticLibs) + env.Install(libDir, staticLibs) + if env["enableShared"]: + env.Default(sharedLibs) + env.Install(libDir, sharedLibs) + env.Install(os.path.join(includeDir, "portaudiocpp"), headers) + +# Generate portaudio_config.h header with compile-time definitions of which PA +# back-ends are available, and which includes back-end extension headers + +# Host-specific headers +hostApiHeaders = {"ALSA": "pa_linux_alsa.h", + "ASIO": "pa_asio.h", + "COREAUDIO": "pa_mac_core.h", + "JACK": "pa_jack.h", + "WMME": "pa_winwmme.h", + } + +def buildConfigH(target, source, env): + """builder for portaudio_config.h""" + global hostApiHeaders, hostApis + out = "" + for hostApi in hostApis: + out += "#define PA_HAVE_%s\n" % hostApi + + hostApiSpecificHeader = hostApiHeaders.get(hostApi, None) + if hostApiSpecificHeader: + out += "#include \"%s\"\n" % hostApiSpecificHeader + + out += "\n" + # Strip the last newline + if out and out[-1] == "\n": + out = out[:-1] + + f = file(str(target[0]), 'w') + try: f.write(out) + finally: f.close() + return 0 + +# Define the builder for the config header +env.Append(BUILDERS={"portaudioConfig": env.Builder( + action=Action(buildConfigH), target_factory=env.fs.File)}) + +confH = env.portaudioConfig(File("portaudio_config.h", "include"), + File("portaudio.h", "include")) +env.Default(confH) +env.Install(os.path.join(includeDir, "portaudio"), confH) + +for api in hostApis: + if api in hostApiHeaders: + env.Install(os.path.join(includeDir, "portaudio"), + File(hostApiHeaders[api], "include")) diff --git a/extern/portaudio/aclocal.m4 b/extern/portaudio/aclocal.m4 new file mode 100644 index 0000000..85326be --- /dev/null +++ b/extern/portaudio/aclocal.m4 @@ -0,0 +1,8776 @@ +# generated automatically by aclocal 1.14.1 -*- Autoconf -*- + +# Copyright (C) 1996-2013 Free Software Foundation, Inc. + +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])]) +# libtool.m4 - Configure libtool for the host system. -*-Autoconf-*- +# +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, +# 2006, 2007, 2008, 2009, 2010, 2011 Free Software +# Foundation, Inc. +# Written by Gordon Matzigkeit, 1996 +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. + +m4_define([_LT_COPYING], [dnl +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, +# 2006, 2007, 2008, 2009, 2010, 2011 Free Software +# Foundation, Inc. +# Written by Gordon Matzigkeit, 1996 +# +# This file is part of GNU Libtool. +# +# GNU Libtool is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# As a special exception to the GNU General Public License, +# if you distribute this file as part of a program or library that +# is built using GNU Libtool, you may include this file under the +# same distribution terms that you use for the rest of that program. +# +# GNU Libtool is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Libtool; see the file COPYING. If not, a copy +# can be downloaded from http://www.gnu.org/licenses/gpl.html, or +# obtained by writing to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +]) + +# serial 57 LT_INIT + + +# LT_PREREQ(VERSION) +# ------------------ +# Complain and exit if this libtool version is less that VERSION. +m4_defun([LT_PREREQ], +[m4_if(m4_version_compare(m4_defn([LT_PACKAGE_VERSION]), [$1]), -1, + [m4_default([$3], + [m4_fatal([Libtool version $1 or higher is required], + 63)])], + [$2])]) + + +# _LT_CHECK_BUILDDIR +# ------------------ +# Complain if the absolute build directory name contains unusual characters +m4_defun([_LT_CHECK_BUILDDIR], +[case `pwd` in + *\ * | *\ *) + AC_MSG_WARN([Libtool does not cope well with whitespace in `pwd`]) ;; +esac +]) + + +# LT_INIT([OPTIONS]) +# ------------------ +AC_DEFUN([LT_INIT], +[AC_PREREQ([2.58])dnl We use AC_INCLUDES_DEFAULT +AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl +AC_BEFORE([$0], [LT_LANG])dnl +AC_BEFORE([$0], [LT_OUTPUT])dnl +AC_BEFORE([$0], [LTDL_INIT])dnl +m4_require([_LT_CHECK_BUILDDIR])dnl + +dnl Autoconf doesn't catch unexpanded LT_ macros by default: +m4_pattern_forbid([^_?LT_[A-Z_]+$])dnl +m4_pattern_allow([^(_LT_EOF|LT_DLGLOBAL|LT_DLLAZY_OR_NOW|LT_MULTI_MODULE)$])dnl +dnl aclocal doesn't pull ltoptions.m4, ltsugar.m4, or ltversion.m4 +dnl unless we require an AC_DEFUNed macro: +AC_REQUIRE([LTOPTIONS_VERSION])dnl +AC_REQUIRE([LTSUGAR_VERSION])dnl +AC_REQUIRE([LTVERSION_VERSION])dnl +AC_REQUIRE([LTOBSOLETE_VERSION])dnl +m4_require([_LT_PROG_LTMAIN])dnl + +_LT_SHELL_INIT([SHELL=${CONFIG_SHELL-/bin/sh}]) + +dnl Parse OPTIONS +_LT_SET_OPTIONS([$0], [$1]) + +# This can be used to rebuild libtool when needed +LIBTOOL_DEPS="$ltmain" + +# Always use our own libtool. +LIBTOOL='$(SHELL) $(top_builddir)/libtool' +AC_SUBST(LIBTOOL)dnl + +_LT_SETUP + +# Only expand once: +m4_define([LT_INIT]) +])# LT_INIT + +# Old names: +AU_ALIAS([AC_PROG_LIBTOOL], [LT_INIT]) +AU_ALIAS([AM_PROG_LIBTOOL], [LT_INIT]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_PROG_LIBTOOL], []) +dnl AC_DEFUN([AM_PROG_LIBTOOL], []) + + +# _LT_CC_BASENAME(CC) +# ------------------- +# Calculate cc_basename. Skip known compiler wrappers and cross-prefix. +m4_defun([_LT_CC_BASENAME], +[for cc_temp in $1""; do + case $cc_temp in + compile | *[[\\/]]compile | ccache | *[[\\/]]ccache ) ;; + distcc | *[[\\/]]distcc | purify | *[[\\/]]purify ) ;; + \-*) ;; + *) break;; + esac +done +cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` +]) + + +# _LT_FILEUTILS_DEFAULTS +# ---------------------- +# It is okay to use these file commands and assume they have been set +# sensibly after `m4_require([_LT_FILEUTILS_DEFAULTS])'. +m4_defun([_LT_FILEUTILS_DEFAULTS], +[: ${CP="cp -f"} +: ${MV="mv -f"} +: ${RM="rm -f"} +])# _LT_FILEUTILS_DEFAULTS + + +# _LT_SETUP +# --------- +m4_defun([_LT_SETUP], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_CANONICAL_BUILD])dnl +AC_REQUIRE([_LT_PREPARE_SED_QUOTE_VARS])dnl +AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])dnl + +_LT_DECL([], [PATH_SEPARATOR], [1], [The PATH separator for the build system])dnl +dnl +_LT_DECL([], [host_alias], [0], [The host system])dnl +_LT_DECL([], [host], [0])dnl +_LT_DECL([], [host_os], [0])dnl +dnl +_LT_DECL([], [build_alias], [0], [The build system])dnl +_LT_DECL([], [build], [0])dnl +_LT_DECL([], [build_os], [0])dnl +dnl +AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([LT_PATH_LD])dnl +AC_REQUIRE([LT_PATH_NM])dnl +dnl +AC_REQUIRE([AC_PROG_LN_S])dnl +test -z "$LN_S" && LN_S="ln -s" +_LT_DECL([], [LN_S], [1], [Whether we need soft or hard links])dnl +dnl +AC_REQUIRE([LT_CMD_MAX_LEN])dnl +_LT_DECL([objext], [ac_objext], [0], [Object file suffix (normally "o")])dnl +_LT_DECL([], [exeext], [0], [Executable file suffix (normally "")])dnl +dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_CHECK_SHELL_FEATURES])dnl +m4_require([_LT_PATH_CONVERSION_FUNCTIONS])dnl +m4_require([_LT_CMD_RELOAD])dnl +m4_require([_LT_CHECK_MAGIC_METHOD])dnl +m4_require([_LT_CHECK_SHAREDLIB_FROM_LINKLIB])dnl +m4_require([_LT_CMD_OLD_ARCHIVE])dnl +m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl +m4_require([_LT_WITH_SYSROOT])dnl + +_LT_CONFIG_LIBTOOL_INIT([ +# See if we are running on zsh, and set the options which allow our +# commands through without removal of \ escapes INIT. +if test -n "\${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST +fi +]) +if test -n "${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST +fi + +_LT_CHECK_OBJDIR + +m4_require([_LT_TAG_COMPILER])dnl + +case $host_os in +aix3*) + # AIX sometimes has problems with the GCC collect2 program. For some + # reason, if we set the COLLECT_NAMES environment variable, the problems + # vanish in a puff of smoke. + if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES + fi + ;; +esac + +# Global variables: +ofile=libtool +can_build_shared=yes + +# All known linkers require a `.a' archive for static linking (except MSVC, +# which needs '.lib'). +libext=a + +with_gnu_ld="$lt_cv_prog_gnu_ld" + +old_CC="$CC" +old_CFLAGS="$CFLAGS" + +# Set sane defaults for various variables +test -z "$CC" && CC=cc +test -z "$LTCC" && LTCC=$CC +test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS +test -z "$LD" && LD=ld +test -z "$ac_objext" && ac_objext=o + +_LT_CC_BASENAME([$compiler]) + +# Only perform the check for file, if the check method requires it +test -z "$MAGIC_CMD" && MAGIC_CMD=file +case $deplibs_check_method in +file_magic*) + if test "$file_magic_cmd" = '$MAGIC_CMD'; then + _LT_PATH_MAGIC + fi + ;; +esac + +# Use C for the default configuration in the libtool script +LT_SUPPORTED_TAG([CC]) +_LT_LANG_C_CONFIG +_LT_LANG_DEFAULT_CONFIG +_LT_CONFIG_COMMANDS +])# _LT_SETUP + + +# _LT_PREPARE_SED_QUOTE_VARS +# -------------------------- +# Define a few sed substitution that help us do robust quoting. +m4_defun([_LT_PREPARE_SED_QUOTE_VARS], +[# Backslashify metacharacters that are still active within +# double-quoted strings. +sed_quote_subst='s/\([["`$\\]]\)/\\\1/g' + +# Same as above, but do not quote variable references. +double_quote_subst='s/\([["`\\]]\)/\\\1/g' + +# Sed substitution to delay expansion of an escaped shell variable in a +# double_quote_subst'ed string. +delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' + +# Sed substitution to delay expansion of an escaped single quote. +delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g' + +# Sed substitution to avoid accidental globbing in evaled expressions +no_glob_subst='s/\*/\\\*/g' +]) + +# _LT_PROG_LTMAIN +# --------------- +# Note that this code is called both from `configure', and `config.status' +# now that we use AC_CONFIG_COMMANDS to generate libtool. Notably, +# `config.status' has no value for ac_aux_dir unless we are using Automake, +# so we pass a copy along to make sure it has a sensible value anyway. +m4_defun([_LT_PROG_LTMAIN], +[m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([ltmain.sh])])dnl +_LT_CONFIG_LIBTOOL_INIT([ac_aux_dir='$ac_aux_dir']) +ltmain="$ac_aux_dir/ltmain.sh" +])# _LT_PROG_LTMAIN + + + +# So that we can recreate a full libtool script including additional +# tags, we accumulate the chunks of code to send to AC_CONFIG_COMMANDS +# in macros and then make a single call at the end using the `libtool' +# label. + + +# _LT_CONFIG_LIBTOOL_INIT([INIT-COMMANDS]) +# ---------------------------------------- +# Register INIT-COMMANDS to be passed to AC_CONFIG_COMMANDS later. +m4_define([_LT_CONFIG_LIBTOOL_INIT], +[m4_ifval([$1], + [m4_append([_LT_OUTPUT_LIBTOOL_INIT], + [$1 +])])]) + +# Initialize. +m4_define([_LT_OUTPUT_LIBTOOL_INIT]) + + +# _LT_CONFIG_LIBTOOL([COMMANDS]) +# ------------------------------ +# Register COMMANDS to be passed to AC_CONFIG_COMMANDS later. +m4_define([_LT_CONFIG_LIBTOOL], +[m4_ifval([$1], + [m4_append([_LT_OUTPUT_LIBTOOL_COMMANDS], + [$1 +])])]) + +# Initialize. +m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS]) + + +# _LT_CONFIG_SAVE_COMMANDS([COMMANDS], [INIT_COMMANDS]) +# ----------------------------------------------------- +m4_defun([_LT_CONFIG_SAVE_COMMANDS], +[_LT_CONFIG_LIBTOOL([$1]) +_LT_CONFIG_LIBTOOL_INIT([$2]) +]) + + +# _LT_FORMAT_COMMENT([COMMENT]) +# ----------------------------- +# Add leading comment marks to the start of each line, and a trailing +# full-stop to the whole comment if one is not present already. +m4_define([_LT_FORMAT_COMMENT], +[m4_ifval([$1], [ +m4_bpatsubst([m4_bpatsubst([$1], [^ *], [# ])], + [['`$\]], [\\\&])]m4_bmatch([$1], [[!?.]$], [], [.]) +)]) + + + + + +# _LT_DECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION], [IS-TAGGED?]) +# ------------------------------------------------------------------- +# CONFIGNAME is the name given to the value in the libtool script. +# VARNAME is the (base) name used in the configure script. +# VALUE may be 0, 1 or 2 for a computed quote escaped value based on +# VARNAME. Any other value will be used directly. +m4_define([_LT_DECL], +[lt_if_append_uniq([lt_decl_varnames], [$2], [, ], + [lt_dict_add_subkey([lt_decl_dict], [$2], [libtool_name], + [m4_ifval([$1], [$1], [$2])]) + lt_dict_add_subkey([lt_decl_dict], [$2], [value], [$3]) + m4_ifval([$4], + [lt_dict_add_subkey([lt_decl_dict], [$2], [description], [$4])]) + lt_dict_add_subkey([lt_decl_dict], [$2], + [tagged?], [m4_ifval([$5], [yes], [no])])]) +]) + + +# _LT_TAGDECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION]) +# -------------------------------------------------------- +m4_define([_LT_TAGDECL], [_LT_DECL([$1], [$2], [$3], [$4], [yes])]) + + +# lt_decl_tag_varnames([SEPARATOR], [VARNAME1...]) +# ------------------------------------------------ +m4_define([lt_decl_tag_varnames], +[_lt_decl_filter([tagged?], [yes], $@)]) + + +# _lt_decl_filter(SUBKEY, VALUE, [SEPARATOR], [VARNAME1..]) +# --------------------------------------------------------- +m4_define([_lt_decl_filter], +[m4_case([$#], + [0], [m4_fatal([$0: too few arguments: $#])], + [1], [m4_fatal([$0: too few arguments: $#: $1])], + [2], [lt_dict_filter([lt_decl_dict], [$1], [$2], [], lt_decl_varnames)], + [3], [lt_dict_filter([lt_decl_dict], [$1], [$2], [$3], lt_decl_varnames)], + [lt_dict_filter([lt_decl_dict], $@)])[]dnl +]) + + +# lt_decl_quote_varnames([SEPARATOR], [VARNAME1...]) +# -------------------------------------------------- +m4_define([lt_decl_quote_varnames], +[_lt_decl_filter([value], [1], $@)]) + + +# lt_decl_dquote_varnames([SEPARATOR], [VARNAME1...]) +# --------------------------------------------------- +m4_define([lt_decl_dquote_varnames], +[_lt_decl_filter([value], [2], $@)]) + + +# lt_decl_varnames_tagged([SEPARATOR], [VARNAME1...]) +# --------------------------------------------------- +m4_define([lt_decl_varnames_tagged], +[m4_assert([$# <= 2])dnl +_$0(m4_quote(m4_default([$1], [[, ]])), + m4_ifval([$2], [[$2]], [m4_dquote(lt_decl_tag_varnames)]), + m4_split(m4_normalize(m4_quote(_LT_TAGS)), [ ]))]) +m4_define([_lt_decl_varnames_tagged], +[m4_ifval([$3], [lt_combine([$1], [$2], [_], $3)])]) + + +# lt_decl_all_varnames([SEPARATOR], [VARNAME1...]) +# ------------------------------------------------ +m4_define([lt_decl_all_varnames], +[_$0(m4_quote(m4_default([$1], [[, ]])), + m4_if([$2], [], + m4_quote(lt_decl_varnames), + m4_quote(m4_shift($@))))[]dnl +]) +m4_define([_lt_decl_all_varnames], +[lt_join($@, lt_decl_varnames_tagged([$1], + lt_decl_tag_varnames([[, ]], m4_shift($@))))dnl +]) + + +# _LT_CONFIG_STATUS_DECLARE([VARNAME]) +# ------------------------------------ +# Quote a variable value, and forward it to `config.status' so that its +# declaration there will have the same value as in `configure'. VARNAME +# must have a single quote delimited value for this to work. +m4_define([_LT_CONFIG_STATUS_DECLARE], +[$1='`$ECHO "$][$1" | $SED "$delay_single_quote_subst"`']) + + +# _LT_CONFIG_STATUS_DECLARATIONS +# ------------------------------ +# We delimit libtool config variables with single quotes, so when +# we write them to config.status, we have to be sure to quote all +# embedded single quotes properly. In configure, this macro expands +# each variable declared with _LT_DECL (and _LT_TAGDECL) into: +# +# ='`$ECHO "$" | $SED "$delay_single_quote_subst"`' +m4_defun([_LT_CONFIG_STATUS_DECLARATIONS], +[m4_foreach([_lt_var], m4_quote(lt_decl_all_varnames), + [m4_n([_LT_CONFIG_STATUS_DECLARE(_lt_var)])])]) + + +# _LT_LIBTOOL_TAGS +# ---------------- +# Output comment and list of tags supported by the script +m4_defun([_LT_LIBTOOL_TAGS], +[_LT_FORMAT_COMMENT([The names of the tagged configurations supported by this script])dnl +available_tags="_LT_TAGS"dnl +]) + + +# _LT_LIBTOOL_DECLARE(VARNAME, [TAG]) +# ----------------------------------- +# Extract the dictionary values for VARNAME (optionally with TAG) and +# expand to a commented shell variable setting: +# +# # Some comment about what VAR is for. +# visible_name=$lt_internal_name +m4_define([_LT_LIBTOOL_DECLARE], +[_LT_FORMAT_COMMENT(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], + [description])))[]dnl +m4_pushdef([_libtool_name], + m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [libtool_name])))[]dnl +m4_case(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [value])), + [0], [_libtool_name=[$]$1], + [1], [_libtool_name=$lt_[]$1], + [2], [_libtool_name=$lt_[]$1], + [_libtool_name=lt_dict_fetch([lt_decl_dict], [$1], [value])])[]dnl +m4_ifval([$2], [_$2])[]m4_popdef([_libtool_name])[]dnl +]) + + +# _LT_LIBTOOL_CONFIG_VARS +# ----------------------- +# Produce commented declarations of non-tagged libtool config variables +# suitable for insertion in the LIBTOOL CONFIG section of the `libtool' +# script. Tagged libtool config variables (even for the LIBTOOL CONFIG +# section) are produced by _LT_LIBTOOL_TAG_VARS. +m4_defun([_LT_LIBTOOL_CONFIG_VARS], +[m4_foreach([_lt_var], + m4_quote(_lt_decl_filter([tagged?], [no], [], lt_decl_varnames)), + [m4_n([_LT_LIBTOOL_DECLARE(_lt_var)])])]) + + +# _LT_LIBTOOL_TAG_VARS(TAG) +# ------------------------- +m4_define([_LT_LIBTOOL_TAG_VARS], +[m4_foreach([_lt_var], m4_quote(lt_decl_tag_varnames), + [m4_n([_LT_LIBTOOL_DECLARE(_lt_var, [$1])])])]) + + +# _LT_TAGVAR(VARNAME, [TAGNAME]) +# ------------------------------ +m4_define([_LT_TAGVAR], [m4_ifval([$2], [$1_$2], [$1])]) + + +# _LT_CONFIG_COMMANDS +# ------------------- +# Send accumulated output to $CONFIG_STATUS. Thanks to the lists of +# variables for single and double quote escaping we saved from calls +# to _LT_DECL, we can put quote escaped variables declarations +# into `config.status', and then the shell code to quote escape them in +# for loops in `config.status'. Finally, any additional code accumulated +# from calls to _LT_CONFIG_LIBTOOL_INIT is expanded. +m4_defun([_LT_CONFIG_COMMANDS], +[AC_PROVIDE_IFELSE([LT_OUTPUT], + dnl If the libtool generation code has been placed in $CONFIG_LT, + dnl instead of duplicating it all over again into config.status, + dnl then we will have config.status run $CONFIG_LT later, so it + dnl needs to know what name is stored there: + [AC_CONFIG_COMMANDS([libtool], + [$SHELL $CONFIG_LT || AS_EXIT(1)], [CONFIG_LT='$CONFIG_LT'])], + dnl If the libtool generation code is destined for config.status, + dnl expand the accumulated commands and init code now: + [AC_CONFIG_COMMANDS([libtool], + [_LT_OUTPUT_LIBTOOL_COMMANDS], [_LT_OUTPUT_LIBTOOL_COMMANDS_INIT])]) +])#_LT_CONFIG_COMMANDS + + +# Initialize. +m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS_INIT], +[ + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +sed_quote_subst='$sed_quote_subst' +double_quote_subst='$double_quote_subst' +delay_variable_subst='$delay_variable_subst' +_LT_CONFIG_STATUS_DECLARATIONS +LTCC='$LTCC' +LTCFLAGS='$LTCFLAGS' +compiler='$compiler_DEFAULT' + +# A function that is used when there is no print builtin or printf. +func_fallback_echo () +{ + eval 'cat <<_LTECHO_EOF +\$[]1 +_LTECHO_EOF' +} + +# Quote evaled strings. +for var in lt_decl_all_varnames([[ \ +]], lt_decl_quote_varnames); do + case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in + *[[\\\\\\\`\\"\\\$]]*) + eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" + ;; + *) + eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" + ;; + esac +done + +# Double-quote double-evaled strings. +for var in lt_decl_all_varnames([[ \ +]], lt_decl_dquote_varnames); do + case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in + *[[\\\\\\\`\\"\\\$]]*) + eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" + ;; + *) + eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" + ;; + esac +done + +_LT_OUTPUT_LIBTOOL_INIT +]) + +# _LT_GENERATED_FILE_INIT(FILE, [COMMENT]) +# ------------------------------------ +# Generate a child script FILE with all initialization necessary to +# reuse the environment learned by the parent script, and make the +# file executable. If COMMENT is supplied, it is inserted after the +# `#!' sequence but before initialization text begins. After this +# macro, additional text can be appended to FILE to form the body of +# the child script. The macro ends with non-zero status if the +# file could not be fully written (such as if the disk is full). +m4_ifdef([AS_INIT_GENERATED], +[m4_defun([_LT_GENERATED_FILE_INIT],[AS_INIT_GENERATED($@)])], +[m4_defun([_LT_GENERATED_FILE_INIT], +[m4_require([AS_PREPARE])]dnl +[m4_pushdef([AS_MESSAGE_LOG_FD])]dnl +[lt_write_fail=0 +cat >$1 <<_ASEOF || lt_write_fail=1 +#! $SHELL +# Generated by $as_me. +$2 +SHELL=\${CONFIG_SHELL-$SHELL} +export SHELL +_ASEOF +cat >>$1 <<\_ASEOF || lt_write_fail=1 +AS_SHELL_SANITIZE +_AS_PREPARE +exec AS_MESSAGE_FD>&1 +_ASEOF +test $lt_write_fail = 0 && chmod +x $1[]dnl +m4_popdef([AS_MESSAGE_LOG_FD])])])# _LT_GENERATED_FILE_INIT + +# LT_OUTPUT +# --------- +# This macro allows early generation of the libtool script (before +# AC_OUTPUT is called), incase it is used in configure for compilation +# tests. +AC_DEFUN([LT_OUTPUT], +[: ${CONFIG_LT=./config.lt} +AC_MSG_NOTICE([creating $CONFIG_LT]) +_LT_GENERATED_FILE_INIT(["$CONFIG_LT"], +[# Run this file to recreate a libtool stub with the current configuration.]) + +cat >>"$CONFIG_LT" <<\_LTEOF +lt_cl_silent=false +exec AS_MESSAGE_LOG_FD>>config.log +{ + echo + AS_BOX([Running $as_me.]) +} >&AS_MESSAGE_LOG_FD + +lt_cl_help="\ +\`$as_me' creates a local libtool stub from the current configuration, +for use in further configure time tests before the real libtool is +generated. + +Usage: $[0] [[OPTIONS]] + + -h, --help print this help, then exit + -V, --version print version number, then exit + -q, --quiet do not print progress messages + -d, --debug don't remove temporary files + +Report bugs to ." + +lt_cl_version="\ +m4_ifset([AC_PACKAGE_NAME], [AC_PACKAGE_NAME ])config.lt[]dnl +m4_ifset([AC_PACKAGE_VERSION], [ AC_PACKAGE_VERSION]) +configured by $[0], generated by m4_PACKAGE_STRING. + +Copyright (C) 2011 Free Software Foundation, Inc. +This config.lt script is free software; the Free Software Foundation +gives unlimited permision to copy, distribute and modify it." + +while test $[#] != 0 +do + case $[1] in + --version | --v* | -V ) + echo "$lt_cl_version"; exit 0 ;; + --help | --h* | -h ) + echo "$lt_cl_help"; exit 0 ;; + --debug | --d* | -d ) + debug=: ;; + --quiet | --q* | --silent | --s* | -q ) + lt_cl_silent=: ;; + + -*) AC_MSG_ERROR([unrecognized option: $[1] +Try \`$[0] --help' for more information.]) ;; + + *) AC_MSG_ERROR([unrecognized argument: $[1] +Try \`$[0] --help' for more information.]) ;; + esac + shift +done + +if $lt_cl_silent; then + exec AS_MESSAGE_FD>/dev/null +fi +_LTEOF + +cat >>"$CONFIG_LT" <<_LTEOF +_LT_OUTPUT_LIBTOOL_COMMANDS_INIT +_LTEOF + +cat >>"$CONFIG_LT" <<\_LTEOF +AC_MSG_NOTICE([creating $ofile]) +_LT_OUTPUT_LIBTOOL_COMMANDS +AS_EXIT(0) +_LTEOF +chmod +x "$CONFIG_LT" + +# configure is writing to config.log, but config.lt does its own redirection, +# appending to config.log, which fails on DOS, as config.log is still kept +# open by configure. Here we exec the FD to /dev/null, effectively closing +# config.log, so it can be properly (re)opened and appended to by config.lt. +lt_cl_success=: +test "$silent" = yes && + lt_config_lt_args="$lt_config_lt_args --quiet" +exec AS_MESSAGE_LOG_FD>/dev/null +$SHELL "$CONFIG_LT" $lt_config_lt_args || lt_cl_success=false +exec AS_MESSAGE_LOG_FD>>config.log +$lt_cl_success || AS_EXIT(1) +])# LT_OUTPUT + + +# _LT_CONFIG(TAG) +# --------------- +# If TAG is the built-in tag, create an initial libtool script with a +# default configuration from the untagged config vars. Otherwise add code +# to config.status for appending the configuration named by TAG from the +# matching tagged config vars. +m4_defun([_LT_CONFIG], +[m4_require([_LT_FILEUTILS_DEFAULTS])dnl +_LT_CONFIG_SAVE_COMMANDS([ + m4_define([_LT_TAG], m4_if([$1], [], [C], [$1]))dnl + m4_if(_LT_TAG, [C], [ + # See if we are running on zsh, and set the options which allow our + # commands through without removal of \ escapes. + if test -n "${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST + fi + + cfgfile="${ofile}T" + trap "$RM \"$cfgfile\"; exit 1" 1 2 15 + $RM "$cfgfile" + + cat <<_LT_EOF >> "$cfgfile" +#! $SHELL + +# `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services. +# Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION +# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: +# NOTE: Changes made to this file will be lost: look at ltmain.sh. +# +_LT_COPYING +_LT_LIBTOOL_TAGS + +# ### BEGIN LIBTOOL CONFIG +_LT_LIBTOOL_CONFIG_VARS +_LT_LIBTOOL_TAG_VARS +# ### END LIBTOOL CONFIG + +_LT_EOF + + case $host_os in + aix3*) + cat <<\_LT_EOF >> "$cfgfile" +# AIX sometimes has problems with the GCC collect2 program. For some +# reason, if we set the COLLECT_NAMES environment variable, the problems +# vanish in a puff of smoke. +if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES +fi +_LT_EOF + ;; + esac + + _LT_PROG_LTMAIN + + # We use sed instead of cat because bash on DJGPP gets confused if + # if finds mixed CR/LF and LF-only lines. Since sed operates in + # text mode, it properly converts lines to CR/LF. This bash problem + # is reportedly fixed, but why not run on old versions too? + sed '$q' "$ltmain" >> "$cfgfile" \ + || (rm -f "$cfgfile"; exit 1) + + _LT_PROG_REPLACE_SHELLFNS + + mv -f "$cfgfile" "$ofile" || + (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") + chmod +x "$ofile" +], +[cat <<_LT_EOF >> "$ofile" + +dnl Unfortunately we have to use $1 here, since _LT_TAG is not expanded +dnl in a comment (ie after a #). +# ### BEGIN LIBTOOL TAG CONFIG: $1 +_LT_LIBTOOL_TAG_VARS(_LT_TAG) +# ### END LIBTOOL TAG CONFIG: $1 +_LT_EOF +])dnl /m4_if +], +[m4_if([$1], [], [ + PACKAGE='$PACKAGE' + VERSION='$VERSION' + TIMESTAMP='$TIMESTAMP' + RM='$RM' + ofile='$ofile'], []) +])dnl /_LT_CONFIG_SAVE_COMMANDS +])# _LT_CONFIG + + +# LT_SUPPORTED_TAG(TAG) +# --------------------- +# Trace this macro to discover what tags are supported by the libtool +# --tag option, using: +# autoconf --trace 'LT_SUPPORTED_TAG:$1' +AC_DEFUN([LT_SUPPORTED_TAG], []) + + +# C support is built-in for now +m4_define([_LT_LANG_C_enabled], []) +m4_define([_LT_TAGS], []) + + +# LT_LANG(LANG) +# ------------- +# Enable libtool support for the given language if not already enabled. +AC_DEFUN([LT_LANG], +[AC_BEFORE([$0], [LT_OUTPUT])dnl +m4_case([$1], + [C], [_LT_LANG(C)], + [C++], [_LT_LANG(CXX)], + [Go], [_LT_LANG(GO)], + [Java], [_LT_LANG(GCJ)], + [Fortran 77], [_LT_LANG(F77)], + [Fortran], [_LT_LANG(FC)], + [Windows Resource], [_LT_LANG(RC)], + [m4_ifdef([_LT_LANG_]$1[_CONFIG], + [_LT_LANG($1)], + [m4_fatal([$0: unsupported language: "$1"])])])dnl +])# LT_LANG + + +# _LT_LANG(LANGNAME) +# ------------------ +m4_defun([_LT_LANG], +[m4_ifdef([_LT_LANG_]$1[_enabled], [], + [LT_SUPPORTED_TAG([$1])dnl + m4_append([_LT_TAGS], [$1 ])dnl + m4_define([_LT_LANG_]$1[_enabled], [])dnl + _LT_LANG_$1_CONFIG($1)])dnl +])# _LT_LANG + + +m4_ifndef([AC_PROG_GO], [ +# NOTE: This macro has been submitted for inclusion into # +# GNU Autoconf as AC_PROG_GO. When it is available in # +# a released version of Autoconf we should remove this # +# macro and use it instead. # +m4_defun([AC_PROG_GO], +[AC_LANG_PUSH(Go)dnl +AC_ARG_VAR([GOC], [Go compiler command])dnl +AC_ARG_VAR([GOFLAGS], [Go compiler flags])dnl +_AC_ARG_VAR_LDFLAGS()dnl +AC_CHECK_TOOL(GOC, gccgo) +if test -z "$GOC"; then + if test -n "$ac_tool_prefix"; then + AC_CHECK_PROG(GOC, [${ac_tool_prefix}gccgo], [${ac_tool_prefix}gccgo]) + fi +fi +if test -z "$GOC"; then + AC_CHECK_PROG(GOC, gccgo, gccgo, false) +fi +])#m4_defun +])#m4_ifndef + + +# _LT_LANG_DEFAULT_CONFIG +# ----------------------- +m4_defun([_LT_LANG_DEFAULT_CONFIG], +[AC_PROVIDE_IFELSE([AC_PROG_CXX], + [LT_LANG(CXX)], + [m4_define([AC_PROG_CXX], defn([AC_PROG_CXX])[LT_LANG(CXX)])]) + +AC_PROVIDE_IFELSE([AC_PROG_F77], + [LT_LANG(F77)], + [m4_define([AC_PROG_F77], defn([AC_PROG_F77])[LT_LANG(F77)])]) + +AC_PROVIDE_IFELSE([AC_PROG_FC], + [LT_LANG(FC)], + [m4_define([AC_PROG_FC], defn([AC_PROG_FC])[LT_LANG(FC)])]) + +dnl The call to [A][M_PROG_GCJ] is quoted like that to stop aclocal +dnl pulling things in needlessly. +AC_PROVIDE_IFELSE([AC_PROG_GCJ], + [LT_LANG(GCJ)], + [AC_PROVIDE_IFELSE([A][M_PROG_GCJ], + [LT_LANG(GCJ)], + [AC_PROVIDE_IFELSE([LT_PROG_GCJ], + [LT_LANG(GCJ)], + [m4_ifdef([AC_PROG_GCJ], + [m4_define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[LT_LANG(GCJ)])]) + m4_ifdef([A][M_PROG_GCJ], + [m4_define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[LT_LANG(GCJ)])]) + m4_ifdef([LT_PROG_GCJ], + [m4_define([LT_PROG_GCJ], defn([LT_PROG_GCJ])[LT_LANG(GCJ)])])])])]) + +AC_PROVIDE_IFELSE([AC_PROG_GO], + [LT_LANG(GO)], + [m4_define([AC_PROG_GO], defn([AC_PROG_GO])[LT_LANG(GO)])]) + +AC_PROVIDE_IFELSE([LT_PROG_RC], + [LT_LANG(RC)], + [m4_define([LT_PROG_RC], defn([LT_PROG_RC])[LT_LANG(RC)])]) +])# _LT_LANG_DEFAULT_CONFIG + +# Obsolete macros: +AU_DEFUN([AC_LIBTOOL_CXX], [LT_LANG(C++)]) +AU_DEFUN([AC_LIBTOOL_F77], [LT_LANG(Fortran 77)]) +AU_DEFUN([AC_LIBTOOL_FC], [LT_LANG(Fortran)]) +AU_DEFUN([AC_LIBTOOL_GCJ], [LT_LANG(Java)]) +AU_DEFUN([AC_LIBTOOL_RC], [LT_LANG(Windows Resource)]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_CXX], []) +dnl AC_DEFUN([AC_LIBTOOL_F77], []) +dnl AC_DEFUN([AC_LIBTOOL_FC], []) +dnl AC_DEFUN([AC_LIBTOOL_GCJ], []) +dnl AC_DEFUN([AC_LIBTOOL_RC], []) + + +# _LT_TAG_COMPILER +# ---------------- +m4_defun([_LT_TAG_COMPILER], +[AC_REQUIRE([AC_PROG_CC])dnl + +_LT_DECL([LTCC], [CC], [1], [A C compiler])dnl +_LT_DECL([LTCFLAGS], [CFLAGS], [1], [LTCC compiler flags])dnl +_LT_TAGDECL([CC], [compiler], [1], [A language specific compiler])dnl +_LT_TAGDECL([with_gcc], [GCC], [0], [Is the compiler the GNU compiler?])dnl + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# If no C compiler flags were specified, use CFLAGS. +LTCFLAGS=${LTCFLAGS-"$CFLAGS"} + +# Allow CC to be a program name with arguments. +compiler=$CC +])# _LT_TAG_COMPILER + + +# _LT_COMPILER_BOILERPLATE +# ------------------------ +# Check for compiler boilerplate output or warnings with +# the simple compiler test code. +m4_defun([_LT_COMPILER_BOILERPLATE], +[m4_require([_LT_DECL_SED])dnl +ac_outfile=conftest.$ac_objext +echo "$lt_simple_compile_test_code" >conftest.$ac_ext +eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_compiler_boilerplate=`cat conftest.err` +$RM conftest* +])# _LT_COMPILER_BOILERPLATE + + +# _LT_LINKER_BOILERPLATE +# ---------------------- +# Check for linker boilerplate output or warnings with +# the simple link test code. +m4_defun([_LT_LINKER_BOILERPLATE], +[m4_require([_LT_DECL_SED])dnl +ac_outfile=conftest.$ac_objext +echo "$lt_simple_link_test_code" >conftest.$ac_ext +eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_linker_boilerplate=`cat conftest.err` +$RM -r conftest* +])# _LT_LINKER_BOILERPLATE + +# _LT_REQUIRED_DARWIN_CHECKS +# ------------------------- +m4_defun_once([_LT_REQUIRED_DARWIN_CHECKS],[ + case $host_os in + rhapsody* | darwin*) + AC_CHECK_TOOL([DSYMUTIL], [dsymutil], [:]) + AC_CHECK_TOOL([NMEDIT], [nmedit], [:]) + AC_CHECK_TOOL([LIPO], [lipo], [:]) + AC_CHECK_TOOL([OTOOL], [otool], [:]) + AC_CHECK_TOOL([OTOOL64], [otool64], [:]) + _LT_DECL([], [DSYMUTIL], [1], + [Tool to manipulate archived DWARF debug symbol files on Mac OS X]) + _LT_DECL([], [NMEDIT], [1], + [Tool to change global to local symbols on Mac OS X]) + _LT_DECL([], [LIPO], [1], + [Tool to manipulate fat objects and archives on Mac OS X]) + _LT_DECL([], [OTOOL], [1], + [ldd/readelf like tool for Mach-O binaries on Mac OS X]) + _LT_DECL([], [OTOOL64], [1], + [ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4]) + + AC_CACHE_CHECK([for -single_module linker flag],[lt_cv_apple_cc_single_mod], + [lt_cv_apple_cc_single_mod=no + if test -z "${LT_MULTI_MODULE}"; then + # By default we will add the -single_module flag. You can override + # by either setting the environment variable LT_MULTI_MODULE + # non-empty at configure time, or by adding -multi_module to the + # link flags. + rm -rf libconftest.dylib* + echo "int foo(void){return 1;}" > conftest.c + echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ +-dynamiclib -Wl,-single_module conftest.c" >&AS_MESSAGE_LOG_FD + $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ + -dynamiclib -Wl,-single_module conftest.c 2>conftest.err + _lt_result=$? + # If there is a non-empty error log, and "single_module" + # appears in it, assume the flag caused a linker warning + if test -s conftest.err && $GREP single_module conftest.err; then + cat conftest.err >&AS_MESSAGE_LOG_FD + # Otherwise, if the output was created with a 0 exit code from + # the compiler, it worked. + elif test -f libconftest.dylib && test $_lt_result -eq 0; then + lt_cv_apple_cc_single_mod=yes + else + cat conftest.err >&AS_MESSAGE_LOG_FD + fi + rm -rf libconftest.dylib* + rm -f conftest.* + fi]) + + AC_CACHE_CHECK([for -exported_symbols_list linker flag], + [lt_cv_ld_exported_symbols_list], + [lt_cv_ld_exported_symbols_list=no + save_LDFLAGS=$LDFLAGS + echo "_main" > conftest.sym + LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym" + AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])], + [lt_cv_ld_exported_symbols_list=yes], + [lt_cv_ld_exported_symbols_list=no]) + LDFLAGS="$save_LDFLAGS" + ]) + + AC_CACHE_CHECK([for -force_load linker flag],[lt_cv_ld_force_load], + [lt_cv_ld_force_load=no + cat > conftest.c << _LT_EOF +int forced_loaded() { return 2;} +_LT_EOF + echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&AS_MESSAGE_LOG_FD + $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&AS_MESSAGE_LOG_FD + echo "$AR cru libconftest.a conftest.o" >&AS_MESSAGE_LOG_FD + $AR cru libconftest.a conftest.o 2>&AS_MESSAGE_LOG_FD + echo "$RANLIB libconftest.a" >&AS_MESSAGE_LOG_FD + $RANLIB libconftest.a 2>&AS_MESSAGE_LOG_FD + cat > conftest.c << _LT_EOF +int main() { return 0;} +_LT_EOF + echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&AS_MESSAGE_LOG_FD + $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err + _lt_result=$? + if test -s conftest.err && $GREP force_load conftest.err; then + cat conftest.err >&AS_MESSAGE_LOG_FD + elif test -f conftest && test $_lt_result -eq 0 && $GREP forced_load conftest >/dev/null 2>&1 ; then + lt_cv_ld_force_load=yes + else + cat conftest.err >&AS_MESSAGE_LOG_FD + fi + rm -f conftest.err libconftest.a conftest conftest.c + rm -rf conftest.dSYM + ]) + case $host_os in + rhapsody* | darwin1.[[012]]) + _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;; + darwin1.*) + _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; + darwin*) # darwin 5.x on + # if running on 10.5 or later, the deployment target defaults + # to the OS version, if on x86, and 10.4, the deployment + # target defaults to 10.4. Don't you love it? + case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in + 10.0,*86*-darwin8*|10.0,*-darwin[[91]]*) + _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; + 10.[[012]]*) + _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; + 10.*) + _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; + esac + ;; + esac + if test "$lt_cv_apple_cc_single_mod" = "yes"; then + _lt_dar_single_mod='$single_module' + fi + if test "$lt_cv_ld_exported_symbols_list" = "yes"; then + _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym' + else + _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}' + fi + if test "$DSYMUTIL" != ":" && test "$lt_cv_ld_force_load" = "no"; then + _lt_dsymutil='~$DSYMUTIL $lib || :' + else + _lt_dsymutil= + fi + ;; + esac +]) + + +# _LT_DARWIN_LINKER_FEATURES([TAG]) +# --------------------------------- +# Checks for linker and compiler features on darwin +m4_defun([_LT_DARWIN_LINKER_FEATURES], +[ + m4_require([_LT_REQUIRED_DARWIN_CHECKS]) + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_automatic, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported + if test "$lt_cv_ld_force_load" = "yes"; then + _LT_TAGVAR(whole_archive_flag_spec, $1)='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`' + m4_case([$1], [F77], [_LT_TAGVAR(compiler_needs_object, $1)=yes], + [FC], [_LT_TAGVAR(compiler_needs_object, $1)=yes]) + else + _LT_TAGVAR(whole_archive_flag_spec, $1)='' + fi + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(allow_undefined_flag, $1)="$_lt_dar_allow_undefined" + case $cc_basename in + ifort*) _lt_dar_can_shared=yes ;; + *) _lt_dar_can_shared=$GCC ;; + esac + if test "$_lt_dar_can_shared" = "yes"; then + output_verbose_link_cmd=func_echo_all + _LT_TAGVAR(archive_cmds, $1)="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" + _LT_TAGVAR(module_cmds, $1)="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" + _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" + _LT_TAGVAR(module_expsym_cmds, $1)="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" + m4_if([$1], [CXX], +[ if test "$lt_cv_apple_cc_single_mod" != "yes"; then + _LT_TAGVAR(archive_cmds, $1)="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}" + _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dar_export_syms}${_lt_dsymutil}" + fi +],[]) + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi +]) + +# _LT_SYS_MODULE_PATH_AIX([TAGNAME]) +# ---------------------------------- +# Links a minimal program and checks the executable +# for the system default hardcoded library path. In most cases, +# this is /usr/lib:/lib, but when the MPI compilers are used +# the location of the communication and MPI libs are included too. +# If we don't find anything, use the default library path according +# to the aix ld manual. +# Store the results from the different compilers for each TAGNAME. +# Allow to override them for all tags through lt_cv_aix_libpath. +m4_defun([_LT_SYS_MODULE_PATH_AIX], +[m4_require([_LT_DECL_SED])dnl +if test "${lt_cv_aix_libpath+set}" = set; then + aix_libpath=$lt_cv_aix_libpath +else + AC_CACHE_VAL([_LT_TAGVAR([lt_cv_aix_libpath_], [$1])], + [AC_LINK_IFELSE([AC_LANG_PROGRAM],[ + lt_aix_libpath_sed='[ + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\([^ ]*\) *$/\1/ + p + } + }]' + _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` + # Check for a 64-bit object if we didn't find anything. + if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then + _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` + fi],[]) + if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then + _LT_TAGVAR([lt_cv_aix_libpath_], [$1])="/usr/lib:/lib" + fi + ]) + aix_libpath=$_LT_TAGVAR([lt_cv_aix_libpath_], [$1]) +fi +])# _LT_SYS_MODULE_PATH_AIX + + +# _LT_SHELL_INIT(ARG) +# ------------------- +m4_define([_LT_SHELL_INIT], +[m4_divert_text([M4SH-INIT], [$1 +])])# _LT_SHELL_INIT + + + +# _LT_PROG_ECHO_BACKSLASH +# ----------------------- +# Find how we can fake an echo command that does not interpret backslash. +# In particular, with Autoconf 2.60 or later we add some code to the start +# of the generated configure script which will find a shell with a builtin +# printf (which we can use as an echo command). +m4_defun([_LT_PROG_ECHO_BACKSLASH], +[ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO +ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO + +AC_MSG_CHECKING([how to print strings]) +# Test print first, because it will be a builtin if present. +if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \ + test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then + ECHO='print -r --' +elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then + ECHO='printf %s\n' +else + # Use this function as a fallback that always works. + func_fallback_echo () + { + eval 'cat <<_LTECHO_EOF +$[]1 +_LTECHO_EOF' + } + ECHO='func_fallback_echo' +fi + +# func_echo_all arg... +# Invoke $ECHO with all args, space-separated. +func_echo_all () +{ + $ECHO "$*" +} + +case "$ECHO" in + printf*) AC_MSG_RESULT([printf]) ;; + print*) AC_MSG_RESULT([print -r]) ;; + *) AC_MSG_RESULT([cat]) ;; +esac + +m4_ifdef([_AS_DETECT_SUGGESTED], +[_AS_DETECT_SUGGESTED([ + test -n "${ZSH_VERSION+set}${BASH_VERSION+set}" || ( + ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' + ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO + ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO + PATH=/empty FPATH=/empty; export PATH FPATH + test "X`printf %s $ECHO`" = "X$ECHO" \ + || test "X`print -r -- $ECHO`" = "X$ECHO" )])]) + +_LT_DECL([], [SHELL], [1], [Shell to use when invoking shell scripts]) +_LT_DECL([], [ECHO], [1], [An echo program that protects backslashes]) +])# _LT_PROG_ECHO_BACKSLASH + + +# _LT_WITH_SYSROOT +# ---------------- +AC_DEFUN([_LT_WITH_SYSROOT], +[AC_MSG_CHECKING([for sysroot]) +AC_ARG_WITH([sysroot], +[ --with-sysroot[=DIR] Search for dependent libraries within DIR + (or the compiler's sysroot if not specified).], +[], [with_sysroot=no]) + +dnl lt_sysroot will always be passed unquoted. We quote it here +dnl in case the user passed a directory name. +lt_sysroot= +case ${with_sysroot} in #( + yes) + if test "$GCC" = yes; then + lt_sysroot=`$CC --print-sysroot 2>/dev/null` + fi + ;; #( + /*) + lt_sysroot=`echo "$with_sysroot" | sed -e "$sed_quote_subst"` + ;; #( + no|'') + ;; #( + *) + AC_MSG_RESULT([${with_sysroot}]) + AC_MSG_ERROR([The sysroot must be an absolute path.]) + ;; +esac + + AC_MSG_RESULT([${lt_sysroot:-no}]) +_LT_DECL([], [lt_sysroot], [0], [The root where to search for ]dnl +[dependent libraries, and in which our libraries should be installed.])]) + +# _LT_ENABLE_LOCK +# --------------- +m4_defun([_LT_ENABLE_LOCK], +[AC_ARG_ENABLE([libtool-lock], + [AS_HELP_STRING([--disable-libtool-lock], + [avoid locking (might break parallel builds)])]) +test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes + +# Some flags need to be propagated to the compiler or linker for good +# libtool support. +case $host in +ia64-*-hpux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case `/usr/bin/file conftest.$ac_objext` in + *ELF-32*) + HPUX_IA64_MODE="32" + ;; + *ELF-64*) + HPUX_IA64_MODE="64" + ;; + esac + fi + rm -rf conftest* + ;; +*-*-irix6*) + # Find out which ABI we are using. + echo '[#]line '$LINENO' "configure"' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + if test "$lt_cv_prog_gnu_ld" = yes; then + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -melf32bsmip" + ;; + *N32*) + LD="${LD-ld} -melf32bmipn32" + ;; + *64-bit*) + LD="${LD-ld} -melf64bmip" + ;; + esac + else + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -32" + ;; + *N32*) + LD="${LD-ld} -n32" + ;; + *64-bit*) + LD="${LD-ld} -64" + ;; + esac + fi + fi + rm -rf conftest* + ;; + +x86_64-*kfreebsd*-gnu|x86_64-*linux*|powerpc*-*linux*| \ +s390*-*linux*|s390*-*tpf*|sparc*-*linux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case `/usr/bin/file conftest.o` in + *32-bit*) + case $host in + x86_64-*kfreebsd*-gnu) + LD="${LD-ld} -m elf_i386_fbsd" + ;; + x86_64-*linux*) + case `/usr/bin/file conftest.o` in + *x86-64*) + LD="${LD-ld} -m elf32_x86_64" + ;; + *) + LD="${LD-ld} -m elf_i386" + ;; + esac + ;; + powerpc64le-*) + LD="${LD-ld} -m elf32lppclinux" + ;; + powerpc64-*) + LD="${LD-ld} -m elf32ppclinux" + ;; + s390x-*linux*) + LD="${LD-ld} -m elf_s390" + ;; + sparc64-*linux*) + LD="${LD-ld} -m elf32_sparc" + ;; + esac + ;; + *64-bit*) + case $host in + x86_64-*kfreebsd*-gnu) + LD="${LD-ld} -m elf_x86_64_fbsd" + ;; + x86_64-*linux*) + LD="${LD-ld} -m elf_x86_64" + ;; + powerpcle-*) + LD="${LD-ld} -m elf64lppc" + ;; + powerpc-*) + LD="${LD-ld} -m elf64ppc" + ;; + s390*-*linux*|s390*-*tpf*) + LD="${LD-ld} -m elf64_s390" + ;; + sparc*-*linux*) + LD="${LD-ld} -m elf64_sparc" + ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; + +*-*-sco3.2v5*) + # On SCO OpenServer 5, we need -belf to get full-featured binaries. + SAVE_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -belf" + AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf, + [AC_LANG_PUSH(C) + AC_LINK_IFELSE([AC_LANG_PROGRAM([[]],[[]])],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no]) + AC_LANG_POP]) + if test x"$lt_cv_cc_needs_belf" != x"yes"; then + # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf + CFLAGS="$SAVE_CFLAGS" + fi + ;; +*-*solaris*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case `/usr/bin/file conftest.o` in + *64-bit*) + case $lt_cv_prog_gnu_ld in + yes*) + case $host in + i?86-*-solaris*) + LD="${LD-ld} -m elf_x86_64" + ;; + sparc*-*-solaris*) + LD="${LD-ld} -m elf64_sparc" + ;; + esac + # GNU ld 2.21 introduced _sol2 emulations. Use them if available. + if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then + LD="${LD-ld}_sol2" + fi + ;; + *) + if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then + LD="${LD-ld} -64" + fi + ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; +esac + +need_locks="$enable_libtool_lock" +])# _LT_ENABLE_LOCK + + +# _LT_PROG_AR +# ----------- +m4_defun([_LT_PROG_AR], +[AC_CHECK_TOOLS(AR, [ar], false) +: ${AR=ar} +: ${AR_FLAGS=cru} +_LT_DECL([], [AR], [1], [The archiver]) +_LT_DECL([], [AR_FLAGS], [1], [Flags to create an archive]) + +AC_CACHE_CHECK([for archiver @FILE support], [lt_cv_ar_at_file], + [lt_cv_ar_at_file=no + AC_COMPILE_IFELSE([AC_LANG_PROGRAM], + [echo conftest.$ac_objext > conftest.lst + lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&AS_MESSAGE_LOG_FD' + AC_TRY_EVAL([lt_ar_try]) + if test "$ac_status" -eq 0; then + # Ensure the archiver fails upon bogus file names. + rm -f conftest.$ac_objext libconftest.a + AC_TRY_EVAL([lt_ar_try]) + if test "$ac_status" -ne 0; then + lt_cv_ar_at_file=@ + fi + fi + rm -f conftest.* libconftest.a + ]) + ]) + +if test "x$lt_cv_ar_at_file" = xno; then + archiver_list_spec= +else + archiver_list_spec=$lt_cv_ar_at_file +fi +_LT_DECL([], [archiver_list_spec], [1], + [How to feed a file listing to the archiver]) +])# _LT_PROG_AR + + +# _LT_CMD_OLD_ARCHIVE +# ------------------- +m4_defun([_LT_CMD_OLD_ARCHIVE], +[_LT_PROG_AR + +AC_CHECK_TOOL(STRIP, strip, :) +test -z "$STRIP" && STRIP=: +_LT_DECL([], [STRIP], [1], [A symbol stripping program]) + +AC_CHECK_TOOL(RANLIB, ranlib, :) +test -z "$RANLIB" && RANLIB=: +_LT_DECL([], [RANLIB], [1], + [Commands used to install an old-style archive]) + +# Determine commands to create old-style static archives. +old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs' +old_postinstall_cmds='chmod 644 $oldlib' +old_postuninstall_cmds= + +if test -n "$RANLIB"; then + case $host_os in + openbsd*) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib" + ;; + *) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib" + ;; + esac + old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib" +fi + +case $host_os in + darwin*) + lock_old_archive_extraction=yes ;; + *) + lock_old_archive_extraction=no ;; +esac +_LT_DECL([], [old_postinstall_cmds], [2]) +_LT_DECL([], [old_postuninstall_cmds], [2]) +_LT_TAGDECL([], [old_archive_cmds], [2], + [Commands used to build an old-style archive]) +_LT_DECL([], [lock_old_archive_extraction], [0], + [Whether to use a lock for old archive extraction]) +])# _LT_CMD_OLD_ARCHIVE + + +# _LT_COMPILER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, +# [OUTPUT-FILE], [ACTION-SUCCESS], [ACTION-FAILURE]) +# ---------------------------------------------------------------- +# Check whether the given compiler option works +AC_DEFUN([_LT_COMPILER_OPTION], +[m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_SED])dnl +AC_CACHE_CHECK([$1], [$2], + [$2=no + m4_if([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4]) + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="$3" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&AS_MESSAGE_LOG_FD + echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings other than the usual output. + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then + $2=yes + fi + fi + $RM conftest* +]) + +if test x"[$]$2" = xyes; then + m4_if([$5], , :, [$5]) +else + m4_if([$6], , :, [$6]) +fi +])# _LT_COMPILER_OPTION + +# Old name: +AU_ALIAS([AC_LIBTOOL_COMPILER_OPTION], [_LT_COMPILER_OPTION]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION], []) + + +# _LT_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, +# [ACTION-SUCCESS], [ACTION-FAILURE]) +# ---------------------------------------------------- +# Check whether the given linker option works +AC_DEFUN([_LT_LINKER_OPTION], +[m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_SED])dnl +AC_CACHE_CHECK([$1], [$2], + [$2=no + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS $3" + echo "$lt_simple_link_test_code" > conftest.$ac_ext + if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then + # The linker can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + # Append any errors to the config.log. + cat conftest.err 1>&AS_MESSAGE_LOG_FD + $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if diff conftest.exp conftest.er2 >/dev/null; then + $2=yes + fi + else + $2=yes + fi + fi + $RM -r conftest* + LDFLAGS="$save_LDFLAGS" +]) + +if test x"[$]$2" = xyes; then + m4_if([$4], , :, [$4]) +else + m4_if([$5], , :, [$5]) +fi +])# _LT_LINKER_OPTION + +# Old name: +AU_ALIAS([AC_LIBTOOL_LINKER_OPTION], [_LT_LINKER_OPTION]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_LINKER_OPTION], []) + + +# LT_CMD_MAX_LEN +#--------------- +AC_DEFUN([LT_CMD_MAX_LEN], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +# find the maximum length of command line arguments +AC_MSG_CHECKING([the maximum length of command line arguments]) +AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl + i=0 + teststring="ABCD" + + case $build_os in + msdosdjgpp*) + # On DJGPP, this test can blow up pretty badly due to problems in libc + # (any single argument exceeding 2000 bytes causes a buffer overrun + # during glob expansion). Even if it were fixed, the result of this + # check would be larger than it should be. + lt_cv_sys_max_cmd_len=12288; # 12K is about right + ;; + + gnu*) + # Under GNU Hurd, this test is not required because there is + # no limit to the length of command line arguments. + # Libtool will interpret -1 as no limit whatsoever + lt_cv_sys_max_cmd_len=-1; + ;; + + cygwin* | mingw* | cegcc*) + # On Win9x/ME, this test blows up -- it succeeds, but takes + # about 5 minutes as the teststring grows exponentially. + # Worse, since 9x/ME are not pre-emptively multitasking, + # you end up with a "frozen" computer, even though with patience + # the test eventually succeeds (with a max line length of 256k). + # Instead, let's just punt: use the minimum linelength reported by + # all of the supported platforms: 8192 (on NT/2K/XP). + lt_cv_sys_max_cmd_len=8192; + ;; + + mint*) + # On MiNT this can take a long time and run out of memory. + lt_cv_sys_max_cmd_len=8192; + ;; + + amigaos*) + # On AmigaOS with pdksh, this test takes hours, literally. + # So we just punt and use a minimum line length of 8192. + lt_cv_sys_max_cmd_len=8192; + ;; + + netbsd* | freebsd* | openbsd* | darwin* | dragonfly*) + # This has been around since 386BSD, at least. Likely further. + if test -x /sbin/sysctl; then + lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` + elif test -x /usr/sbin/sysctl; then + lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` + else + lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs + fi + # And add a safety zone + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` + ;; + + interix*) + # We know the value 262144 and hardcode it with a safety zone (like BSD) + lt_cv_sys_max_cmd_len=196608 + ;; + + os2*) + # The test takes a long time on OS/2. + lt_cv_sys_max_cmd_len=8192 + ;; + + osf*) + # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure + # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not + # nice to cause kernel panics so lets avoid the loop below. + # First set a reasonable default. + lt_cv_sys_max_cmd_len=16384 + # + if test -x /sbin/sysconfig; then + case `/sbin/sysconfig -q proc exec_disable_arg_limit` in + *1*) lt_cv_sys_max_cmd_len=-1 ;; + esac + fi + ;; + sco3.2v5*) + lt_cv_sys_max_cmd_len=102400 + ;; + sysv5* | sco5v6* | sysv4.2uw2*) + kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` + if test -n "$kargmax"; then + lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[[ ]]//'` + else + lt_cv_sys_max_cmd_len=32768 + fi + ;; + *) + lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null` + if test -n "$lt_cv_sys_max_cmd_len" && \ + test undefined != "$lt_cv_sys_max_cmd_len"; then + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` + else + # Make teststring a little bigger before we do anything with it. + # a 1K string should be a reasonable start. + for i in 1 2 3 4 5 6 7 8 ; do + teststring=$teststring$teststring + done + SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} + # If test is not a shell built-in, we'll probably end up computing a + # maximum length that is only half of the actual maximum length, but + # we can't tell. + while { test "X"`env echo "$teststring$teststring" 2>/dev/null` \ + = "X$teststring$teststring"; } >/dev/null 2>&1 && + test $i != 17 # 1/2 MB should be enough + do + i=`expr $i + 1` + teststring=$teststring$teststring + done + # Only check the string length outside the loop. + lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1` + teststring= + # Add a significant safety factor because C++ compilers can tack on + # massive amounts of additional arguments before passing them to the + # linker. It appears as though 1/2 is a usable value. + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` + fi + ;; + esac +]) +if test -n $lt_cv_sys_max_cmd_len ; then + AC_MSG_RESULT($lt_cv_sys_max_cmd_len) +else + AC_MSG_RESULT(none) +fi +max_cmd_len=$lt_cv_sys_max_cmd_len +_LT_DECL([], [max_cmd_len], [0], + [What is the maximum length of a command?]) +])# LT_CMD_MAX_LEN + +# Old name: +AU_ALIAS([AC_LIBTOOL_SYS_MAX_CMD_LEN], [LT_CMD_MAX_LEN]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN], []) + + +# _LT_HEADER_DLFCN +# ---------------- +m4_defun([_LT_HEADER_DLFCN], +[AC_CHECK_HEADERS([dlfcn.h], [], [], [AC_INCLUDES_DEFAULT])dnl +])# _LT_HEADER_DLFCN + + +# _LT_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE, +# ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING) +# ---------------------------------------------------------------- +m4_defun([_LT_TRY_DLOPEN_SELF], +[m4_require([_LT_HEADER_DLFCN])dnl +if test "$cross_compiling" = yes; then : + [$4] +else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<_LT_EOF +[#line $LINENO "configure" +#include "confdefs.h" + +#if HAVE_DLFCN_H +#include +#endif + +#include + +#ifdef RTLD_GLOBAL +# define LT_DLGLOBAL RTLD_GLOBAL +#else +# ifdef DL_GLOBAL +# define LT_DLGLOBAL DL_GLOBAL +# else +# define LT_DLGLOBAL 0 +# endif +#endif + +/* We may have to define LT_DLLAZY_OR_NOW in the command line if we + find out it does not work in some platform. */ +#ifndef LT_DLLAZY_OR_NOW +# ifdef RTLD_LAZY +# define LT_DLLAZY_OR_NOW RTLD_LAZY +# else +# ifdef DL_LAZY +# define LT_DLLAZY_OR_NOW DL_LAZY +# else +# ifdef RTLD_NOW +# define LT_DLLAZY_OR_NOW RTLD_NOW +# else +# ifdef DL_NOW +# define LT_DLLAZY_OR_NOW DL_NOW +# else +# define LT_DLLAZY_OR_NOW 0 +# endif +# endif +# endif +# endif +#endif + +/* When -fvisbility=hidden is used, assume the code has been annotated + correspondingly for the symbols needed. */ +#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) +int fnord () __attribute__((visibility("default"))); +#endif + +int fnord () { return 42; } +int main () +{ + void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); + int status = $lt_dlunknown; + + if (self) + { + if (dlsym (self,"fnord")) status = $lt_dlno_uscore; + else + { + if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; + else puts (dlerror ()); + } + /* dlclose (self); */ + } + else + puts (dlerror ()); + + return status; +}] +_LT_EOF + if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext} 2>/dev/null; then + (./conftest; exit; ) >&AS_MESSAGE_LOG_FD 2>/dev/null + lt_status=$? + case x$lt_status in + x$lt_dlno_uscore) $1 ;; + x$lt_dlneed_uscore) $2 ;; + x$lt_dlunknown|x*) $3 ;; + esac + else : + # compilation failed + $3 + fi +fi +rm -fr conftest* +])# _LT_TRY_DLOPEN_SELF + + +# LT_SYS_DLOPEN_SELF +# ------------------ +AC_DEFUN([LT_SYS_DLOPEN_SELF], +[m4_require([_LT_HEADER_DLFCN])dnl +if test "x$enable_dlopen" != xyes; then + enable_dlopen=unknown + enable_dlopen_self=unknown + enable_dlopen_self_static=unknown +else + lt_cv_dlopen=no + lt_cv_dlopen_libs= + + case $host_os in + beos*) + lt_cv_dlopen="load_add_on" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + ;; + + mingw* | pw32* | cegcc*) + lt_cv_dlopen="LoadLibrary" + lt_cv_dlopen_libs= + ;; + + cygwin*) + lt_cv_dlopen="dlopen" + lt_cv_dlopen_libs= + ;; + + darwin*) + # if libdl is installed we need to link against it + AC_CHECK_LIB([dl], [dlopen], + [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],[ + lt_cv_dlopen="dyld" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + ]) + ;; + + *) + AC_CHECK_FUNC([shl_load], + [lt_cv_dlopen="shl_load"], + [AC_CHECK_LIB([dld], [shl_load], + [lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld"], + [AC_CHECK_FUNC([dlopen], + [lt_cv_dlopen="dlopen"], + [AC_CHECK_LIB([dl], [dlopen], + [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"], + [AC_CHECK_LIB([svld], [dlopen], + [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"], + [AC_CHECK_LIB([dld], [dld_link], + [lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld"]) + ]) + ]) + ]) + ]) + ]) + ;; + esac + + if test "x$lt_cv_dlopen" != xno; then + enable_dlopen=yes + else + enable_dlopen=no + fi + + case $lt_cv_dlopen in + dlopen) + save_CPPFLAGS="$CPPFLAGS" + test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" + + save_LDFLAGS="$LDFLAGS" + wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" + + save_LIBS="$LIBS" + LIBS="$lt_cv_dlopen_libs $LIBS" + + AC_CACHE_CHECK([whether a program can dlopen itself], + lt_cv_dlopen_self, [dnl + _LT_TRY_DLOPEN_SELF( + lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes, + lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross) + ]) + + if test "x$lt_cv_dlopen_self" = xyes; then + wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" + AC_CACHE_CHECK([whether a statically linked program can dlopen itself], + lt_cv_dlopen_self_static, [dnl + _LT_TRY_DLOPEN_SELF( + lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes, + lt_cv_dlopen_self_static=no, lt_cv_dlopen_self_static=cross) + ]) + fi + + CPPFLAGS="$save_CPPFLAGS" + LDFLAGS="$save_LDFLAGS" + LIBS="$save_LIBS" + ;; + esac + + case $lt_cv_dlopen_self in + yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; + *) enable_dlopen_self=unknown ;; + esac + + case $lt_cv_dlopen_self_static in + yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; + *) enable_dlopen_self_static=unknown ;; + esac +fi +_LT_DECL([dlopen_support], [enable_dlopen], [0], + [Whether dlopen is supported]) +_LT_DECL([dlopen_self], [enable_dlopen_self], [0], + [Whether dlopen of programs is supported]) +_LT_DECL([dlopen_self_static], [enable_dlopen_self_static], [0], + [Whether dlopen of statically linked programs is supported]) +])# LT_SYS_DLOPEN_SELF + +# Old name: +AU_ALIAS([AC_LIBTOOL_DLOPEN_SELF], [LT_SYS_DLOPEN_SELF]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF], []) + + +# _LT_COMPILER_C_O([TAGNAME]) +# --------------------------- +# Check to see if options -c and -o are simultaneously supported by compiler. +# This macro does not hard code the compiler like AC_PROG_CC_C_O. +m4_defun([_LT_COMPILER_C_O], +[m4_require([_LT_DECL_SED])dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_TAG_COMPILER])dnl +AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext], + [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)], + [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=no + $RM -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&AS_MESSAGE_LOG_FD + echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp + $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 + if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then + _LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes + fi + fi + chmod u+w . 2>&AS_MESSAGE_LOG_FD + $RM conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files + $RM out/* && rmdir out + cd .. + $RM -r conftest + $RM conftest* +]) +_LT_TAGDECL([compiler_c_o], [lt_cv_prog_compiler_c_o], [1], + [Does compiler simultaneously support -c and -o options?]) +])# _LT_COMPILER_C_O + + +# _LT_COMPILER_FILE_LOCKS([TAGNAME]) +# ---------------------------------- +# Check to see if we can do hard links to lock some files if needed +m4_defun([_LT_COMPILER_FILE_LOCKS], +[m4_require([_LT_ENABLE_LOCK])dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +_LT_COMPILER_C_O([$1]) + +hard_links="nottested" +if test "$_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)" = no && test "$need_locks" != no; then + # do not overwrite the value of need_locks provided by the user + AC_MSG_CHECKING([if we can lock with hard links]) + hard_links=yes + $RM conftest* + ln conftest.a conftest.b 2>/dev/null && hard_links=no + touch conftest.a + ln conftest.a conftest.b 2>&5 || hard_links=no + ln conftest.a conftest.b 2>/dev/null && hard_links=no + AC_MSG_RESULT([$hard_links]) + if test "$hard_links" = no; then + AC_MSG_WARN([`$CC' does not support `-c -o', so `make -j' may be unsafe]) + need_locks=warn + fi +else + need_locks=no +fi +_LT_DECL([], [need_locks], [1], [Must we lock files when doing compilation?]) +])# _LT_COMPILER_FILE_LOCKS + + +# _LT_CHECK_OBJDIR +# ---------------- +m4_defun([_LT_CHECK_OBJDIR], +[AC_CACHE_CHECK([for objdir], [lt_cv_objdir], +[rm -f .libs 2>/dev/null +mkdir .libs 2>/dev/null +if test -d .libs; then + lt_cv_objdir=.libs +else + # MS-DOS does not allow filenames that begin with a dot. + lt_cv_objdir=_libs +fi +rmdir .libs 2>/dev/null]) +objdir=$lt_cv_objdir +_LT_DECL([], [objdir], [0], + [The name of the directory that contains temporary libtool files])dnl +m4_pattern_allow([LT_OBJDIR])dnl +AC_DEFINE_UNQUOTED(LT_OBJDIR, "$lt_cv_objdir/", + [Define to the sub-directory in which libtool stores uninstalled libraries.]) +])# _LT_CHECK_OBJDIR + + +# _LT_LINKER_HARDCODE_LIBPATH([TAGNAME]) +# -------------------------------------- +# Check hardcoding attributes. +m4_defun([_LT_LINKER_HARDCODE_LIBPATH], +[AC_MSG_CHECKING([how to hardcode library paths into programs]) +_LT_TAGVAR(hardcode_action, $1)= +if test -n "$_LT_TAGVAR(hardcode_libdir_flag_spec, $1)" || + test -n "$_LT_TAGVAR(runpath_var, $1)" || + test "X$_LT_TAGVAR(hardcode_automatic, $1)" = "Xyes" ; then + + # We can hardcode non-existent directories. + if test "$_LT_TAGVAR(hardcode_direct, $1)" != no && + # If the only mechanism to avoid hardcoding is shlibpath_var, we + # have to relink, otherwise we might link with an installed library + # when we should be linking with a yet-to-be-installed one + ## test "$_LT_TAGVAR(hardcode_shlibpath_var, $1)" != no && + test "$_LT_TAGVAR(hardcode_minus_L, $1)" != no; then + # Linking always hardcodes the temporary library directory. + _LT_TAGVAR(hardcode_action, $1)=relink + else + # We can link without hardcoding, and we can hardcode nonexisting dirs. + _LT_TAGVAR(hardcode_action, $1)=immediate + fi +else + # We cannot hardcode anything, or else we can only hardcode existing + # directories. + _LT_TAGVAR(hardcode_action, $1)=unsupported +fi +AC_MSG_RESULT([$_LT_TAGVAR(hardcode_action, $1)]) + +if test "$_LT_TAGVAR(hardcode_action, $1)" = relink || + test "$_LT_TAGVAR(inherit_rpath, $1)" = yes; then + # Fast installation is not supported + enable_fast_install=no +elif test "$shlibpath_overrides_runpath" = yes || + test "$enable_shared" = no; then + # Fast installation is not necessary + enable_fast_install=needless +fi +_LT_TAGDECL([], [hardcode_action], [0], + [How to hardcode a shared library path into an executable]) +])# _LT_LINKER_HARDCODE_LIBPATH + + +# _LT_CMD_STRIPLIB +# ---------------- +m4_defun([_LT_CMD_STRIPLIB], +[m4_require([_LT_DECL_EGREP]) +striplib= +old_striplib= +AC_MSG_CHECKING([whether stripping libraries is possible]) +if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then + test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" + test -z "$striplib" && striplib="$STRIP --strip-unneeded" + AC_MSG_RESULT([yes]) +else +# FIXME - insert some real tests, host_os isn't really good enough + case $host_os in + darwin*) + if test -n "$STRIP" ; then + striplib="$STRIP -x" + old_striplib="$STRIP -S" + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + fi + ;; + *) + AC_MSG_RESULT([no]) + ;; + esac +fi +_LT_DECL([], [old_striplib], [1], [Commands to strip libraries]) +_LT_DECL([], [striplib], [1]) +])# _LT_CMD_STRIPLIB + + +# _LT_SYS_DYNAMIC_LINKER([TAG]) +# ----------------------------- +# PORTME Fill in your ld.so characteristics +m4_defun([_LT_SYS_DYNAMIC_LINKER], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +m4_require([_LT_DECL_EGREP])dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_OBJDUMP])dnl +m4_require([_LT_DECL_SED])dnl +m4_require([_LT_CHECK_SHELL_FEATURES])dnl +AC_MSG_CHECKING([dynamic linker characteristics]) +m4_if([$1], + [], [ +if test "$GCC" = yes; then + case $host_os in + darwin*) lt_awk_arg="/^libraries:/,/LR/" ;; + *) lt_awk_arg="/^libraries:/" ;; + esac + case $host_os in + mingw* | cegcc*) lt_sed_strip_eq="s,=\([[A-Za-z]]:\),\1,g" ;; + *) lt_sed_strip_eq="s,=/,/,g" ;; + esac + lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq` + case $lt_search_path_spec in + *\;*) + # if the path contains ";" then we assume it to be the separator + # otherwise default to the standard path separator (i.e. ":") - it is + # assumed that no part of a normal pathname contains ";" but that should + # okay in the real world where ";" in dirpaths is itself problematic. + lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'` + ;; + *) + lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"` + ;; + esac + # Ok, now we have the path, separated by spaces, we can step through it + # and add multilib dir if necessary. + lt_tmp_lt_search_path_spec= + lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null` + for lt_sys_path in $lt_search_path_spec; do + if test -d "$lt_sys_path/$lt_multi_os_dir"; then + lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir" + else + test -d "$lt_sys_path" && \ + lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path" + fi + done + lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk ' +BEGIN {RS=" "; FS="/|\n";} { + lt_foo=""; + lt_count=0; + for (lt_i = NF; lt_i > 0; lt_i--) { + if ($lt_i != "" && $lt_i != ".") { + if ($lt_i == "..") { + lt_count++; + } else { + if (lt_count == 0) { + lt_foo="/" $lt_i lt_foo; + } else { + lt_count--; + } + } + } + } + if (lt_foo != "") { lt_freq[[lt_foo]]++; } + if (lt_freq[[lt_foo]] == 1) { print lt_foo; } +}'` + # AWK program above erroneously prepends '/' to C:/dos/paths + # for these hosts. + case $host_os in + mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\ + $SED 's,/\([[A-Za-z]]:\),\1,g'` ;; + esac + sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP` +else + sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" +fi]) +library_names_spec= +libname_spec='lib$name' +soname_spec= +shrext_cmds=".so" +postinstall_cmds= +postuninstall_cmds= +finish_cmds= +finish_eval= +shlibpath_var= +shlibpath_overrides_runpath=unknown +version_type=none +dynamic_linker="$host_os ld.so" +sys_lib_dlsearch_path_spec="/lib /usr/lib" +need_lib_prefix=unknown +hardcode_into_libs=no + +# when you set need_version to no, make sure it does not cause -set_version +# flags to be left without arguments +need_version=unknown + +case $host_os in +aix3*) + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' + shlibpath_var=LIBPATH + + # AIX 3 has no versioning support, so we append a major version to the name. + soname_spec='${libname}${release}${shared_ext}$major' + ;; + +aix[[4-9]]*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + hardcode_into_libs=yes + if test "$host_cpu" = ia64; then + # AIX 5 supports IA64 + library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + else + # With GCC up to 2.95.x, collect2 would create an import file + # for dependence libraries. The import file would start with + # the line `#! .'. This would cause the generated library to + # depend on `.', always an invalid library. This was fixed in + # development snapshots of GCC prior to 3.0. + case $host_os in + aix4 | aix4.[[01]] | aix4.[[01]].*) + if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' + echo ' yes ' + echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then + : + else + can_build_shared=no + fi + ;; + esac + # AIX (on Power*) has no versioning support, so currently we can not hardcode correct + # soname into executable. Probably we can add versioning support to + # collect2, so additional links can be useful in future. + if test "$aix_use_runtimelinking" = yes; then + # If using run time linking (on AIX 4.2 or later) use lib.so + # instead of lib.a to let people know that these are not + # typical AIX shared libraries. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + else + # We preserve .a as extension for shared libraries through AIX4.2 + # and later when we are not doing run time linking. + library_names_spec='${libname}${release}.a $libname.a' + soname_spec='${libname}${release}${shared_ext}$major' + fi + shlibpath_var=LIBPATH + fi + ;; + +amigaos*) + case $host_cpu in + powerpc) + # Since July 2007 AmigaOS4 officially supports .so libraries. + # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + ;; + m68k) + library_names_spec='$libname.ixlibrary $libname.a' + # Create ${libname}_ixlibrary.a entries in /sys/libs. + finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' + ;; + esac + ;; + +beos*) + library_names_spec='${libname}${shared_ext}' + dynamic_linker="$host_os ld.so" + shlibpath_var=LIBRARY_PATH + ;; + +bsdi[[45]]*) + version_type=linux # correct to gnu/linux during the next big refactor + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" + sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" + # the default ld.so.conf also contains /usr/contrib/lib and + # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow + # libtool to hard-code these into programs + ;; + +cygwin* | mingw* | pw32* | cegcc*) + version_type=windows + shrext_cmds=".dll" + need_version=no + need_lib_prefix=no + + case $GCC,$cc_basename in + yes,*) + # gcc + library_names_spec='$libname.dll.a' + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \${file}`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname~ + chmod a+x \$dldir/$dlname~ + if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then + eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; + fi' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $RM \$dlpath' + shlibpath_overrides_runpath=yes + + case $host_os in + cygwin*) + # Cygwin DLLs use 'cyg' prefix rather than 'lib' + soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' +m4_if([$1], [],[ + sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api"]) + ;; + mingw* | cegcc*) + # MinGW DLLs use traditional 'lib' prefix + soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' + ;; + pw32*) + # pw32 DLLs use 'pw' prefix rather than 'lib' + library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' + ;; + esac + dynamic_linker='Win32 ld.exe' + ;; + + *,cl*) + # Native MSVC + libname_spec='$name' + soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' + library_names_spec='${libname}.dll.lib' + + case $build_os in + mingw*) + sys_lib_search_path_spec= + lt_save_ifs=$IFS + IFS=';' + for lt_path in $LIB + do + IFS=$lt_save_ifs + # Let DOS variable expansion print the short 8.3 style file name. + lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"` + sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path" + done + IFS=$lt_save_ifs + # Convert to MSYS style. + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([[a-zA-Z]]\\):| /\\1|g' -e 's|^ ||'` + ;; + cygwin*) + # Convert to unix form, then to dos form, then back to unix form + # but this time dos style (no spaces!) so that the unix form looks + # like /cygdrive/c/PROGRA~1:/cygdr... + sys_lib_search_path_spec=`cygpath --path --unix "$LIB"` + sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null` + sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + ;; + *) + sys_lib_search_path_spec="$LIB" + if $ECHO "$sys_lib_search_path_spec" | [$GREP ';[c-zC-Z]:/' >/dev/null]; then + # It is most probably a Windows format PATH. + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` + else + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi + # FIXME: find the short name or the path components, as spaces are + # common. (e.g. "Program Files" -> "PROGRA~1") + ;; + esac + + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \${file}`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $RM \$dlpath' + shlibpath_overrides_runpath=yes + dynamic_linker='Win32 link.exe' + ;; + + *) + # Assume MSVC wrapper + library_names_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext} $libname.lib' + dynamic_linker='Win32 ld.exe' + ;; + esac + # FIXME: first we should search . and the directory the executable is in + shlibpath_var=PATH + ;; + +darwin* | rhapsody*) + dynamic_linker="$host_os dyld" + version_type=darwin + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext' + soname_spec='${libname}${release}${major}$shared_ext' + shlibpath_overrides_runpath=yes + shlibpath_var=DYLD_LIBRARY_PATH + shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' +m4_if([$1], [],[ + sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"]) + sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' + ;; + +dgux*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +freebsd* | dragonfly*) + # DragonFly does not have aout. When/if they implement a new + # versioning mechanism, adjust this. + if test -x /usr/bin/objformat; then + objformat=`/usr/bin/objformat` + else + case $host_os in + freebsd[[23]].*) objformat=aout ;; + *) objformat=elf ;; + esac + fi + version_type=freebsd-$objformat + case $version_type in + freebsd-elf*) + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + need_version=no + need_lib_prefix=no + ;; + freebsd-*) + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' + need_version=yes + ;; + esac + shlibpath_var=LD_LIBRARY_PATH + case $host_os in + freebsd2.*) + shlibpath_overrides_runpath=yes + ;; + freebsd3.[[01]]* | freebsdelf3.[[01]]*) + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + freebsd3.[[2-9]]* | freebsdelf3.[[2-9]]* | \ + freebsd4.[[0-5]] | freebsdelf4.[[0-5]] | freebsd4.1.1 | freebsdelf4.1.1) + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + *) # from 4.6 on, and DragonFly + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + esac + ;; + +haiku*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + dynamic_linker="$host_os runtime_loader" + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LIBRARY_PATH + shlibpath_overrides_runpath=yes + sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib' + hardcode_into_libs=yes + ;; + +hpux9* | hpux10* | hpux11*) + # Give a soname corresponding to the major version so that dld.sl refuses to + # link against other versions. + version_type=sunos + need_lib_prefix=no + need_version=no + case $host_cpu in + ia64*) + shrext_cmds='.so' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.so" + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + if test "X$HPUX_IA64_MODE" = X32; then + sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" + else + sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" + fi + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + hppa*64*) + shrext_cmds='.sl' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.sl" + shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + *) + shrext_cmds='.sl' + dynamic_linker="$host_os dld.sl" + shlibpath_var=SHLIB_PATH + shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + ;; + esac + # HP-UX runs *really* slowly unless shared libraries are mode 555, ... + postinstall_cmds='chmod 555 $lib' + # or fails outright, so override atomically: + install_override_mode=555 + ;; + +interix[[3-9]]*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +irix5* | irix6* | nonstopux*) + case $host_os in + nonstopux*) version_type=nonstopux ;; + *) + if test "$lt_cv_prog_gnu_ld" = yes; then + version_type=linux # correct to gnu/linux during the next big refactor + else + version_type=irix + fi ;; + esac + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' + case $host_os in + irix5* | nonstopux*) + libsuff= shlibsuff= + ;; + *) + case $LD in # libtool.m4 will add one of these switches to LD + *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") + libsuff= shlibsuff= libmagic=32-bit;; + *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") + libsuff=32 shlibsuff=N32 libmagic=N32;; + *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") + libsuff=64 shlibsuff=64 libmagic=64-bit;; + *) libsuff= shlibsuff= libmagic=never-match;; + esac + ;; + esac + shlibpath_var=LD_LIBRARY${shlibsuff}_PATH + shlibpath_overrides_runpath=no + sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" + sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" + hardcode_into_libs=yes + ;; + +# No shared lib support for Linux oldld, aout, or coff. +linux*oldld* | linux*aout* | linux*coff*) + dynamic_linker=no + ;; + +# This must be glibc/ELF. +linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + + # Some binutils ld are patched to set DT_RUNPATH + AC_CACHE_VAL([lt_cv_shlibpath_overrides_runpath], + [lt_cv_shlibpath_overrides_runpath=no + save_LDFLAGS=$LDFLAGS + save_libdir=$libdir + eval "libdir=/foo; wl=\"$_LT_TAGVAR(lt_prog_compiler_wl, $1)\"; \ + LDFLAGS=\"\$LDFLAGS $_LT_TAGVAR(hardcode_libdir_flag_spec, $1)\"" + AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])], + [AS_IF([ ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null], + [lt_cv_shlibpath_overrides_runpath=yes])]) + LDFLAGS=$save_LDFLAGS + libdir=$save_libdir + ]) + shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath + + # This implies no fast_install, which is unacceptable. + # Some rework will be needed to allow for fast_install + # before this can be enabled. + hardcode_into_libs=yes + + # Append ld.so.conf contents to the search path + if test -f /etc/ld.so.conf; then + lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \[$]2)); skip = 1; } { if (!skip) print \[$]0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '` + sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" + fi + + # We used to test for /lib/ld.so.1 and disable shared libraries on + # powerpc, because MkLinux only supported shared libraries with the + # GNU dynamic linker. Since this was broken with cross compilers, + # most powerpc-linux boxes support dynamic linking these days and + # people can always --disable-shared, the test was removed, and we + # assume the GNU/Linux dynamic linker is in use. + dynamic_linker='GNU/Linux ld.so' + ;; + +netbsdelf*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='NetBSD ld.elf_so' + ;; + +netbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + dynamic_linker='NetBSD (a.out) ld.so' + else + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='NetBSD ld.elf_so' + fi + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + +newsos6) + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +*nto* | *qnx*) + version_type=qnx + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='ldqnx.so' + ;; + +openbsd*) + version_type=sunos + sys_lib_dlsearch_path_spec="/usr/lib" + need_lib_prefix=no + # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. + case $host_os in + openbsd3.3 | openbsd3.3.*) need_version=yes ;; + *) need_version=no ;; + esac + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + shlibpath_var=LD_LIBRARY_PATH + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + case $host_os in + openbsd2.[[89]] | openbsd2.[[89]].*) + shlibpath_overrides_runpath=no + ;; + *) + shlibpath_overrides_runpath=yes + ;; + esac + else + shlibpath_overrides_runpath=yes + fi + ;; + +os2*) + libname_spec='$name' + shrext_cmds=".dll" + need_lib_prefix=no + library_names_spec='$libname${shared_ext} $libname.a' + dynamic_linker='OS/2 ld.exe' + shlibpath_var=LIBPATH + ;; + +osf3* | osf4* | osf5*) + version_type=osf + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" + sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" + ;; + +rdos*) + dynamic_linker=no + ;; + +solaris*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + # ldd complains unless libraries are executable + postinstall_cmds='chmod +x $lib' + ;; + +sunos4*) + version_type=sunos + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + if test "$with_gnu_ld" = yes; then + need_lib_prefix=no + fi + need_version=yes + ;; + +sysv4 | sysv4.3*) + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + case $host_vendor in + sni) + shlibpath_overrides_runpath=no + need_lib_prefix=no + runpath_var=LD_RUN_PATH + ;; + siemens) + need_lib_prefix=no + ;; + motorola) + need_lib_prefix=no + need_version=no + shlibpath_overrides_runpath=no + sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' + ;; + esac + ;; + +sysv4*MP*) + if test -d /usr/nec ;then + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' + soname_spec='$libname${shared_ext}.$major' + shlibpath_var=LD_LIBRARY_PATH + fi + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + version_type=freebsd-elf + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + if test "$with_gnu_ld" = yes; then + sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' + else + sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' + case $host_os in + sco3.2v5*) + sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" + ;; + esac + fi + sys_lib_dlsearch_path_spec='/usr/lib' + ;; + +tpf*) + # TPF is a cross-target only. Preferred cross-host = GNU/Linux. + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +uts4*) + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +*) + dynamic_linker=no + ;; +esac +AC_MSG_RESULT([$dynamic_linker]) +test "$dynamic_linker" = no && can_build_shared=no + +variables_saved_for_relink="PATH $shlibpath_var $runpath_var" +if test "$GCC" = yes; then + variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" +fi + +if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then + sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec" +fi +if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then + sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec" +fi + +_LT_DECL([], [variables_saved_for_relink], [1], + [Variables whose values should be saved in libtool wrapper scripts and + restored at link time]) +_LT_DECL([], [need_lib_prefix], [0], + [Do we need the "lib" prefix for modules?]) +_LT_DECL([], [need_version], [0], [Do we need a version for libraries?]) +_LT_DECL([], [version_type], [0], [Library versioning type]) +_LT_DECL([], [runpath_var], [0], [Shared library runtime path variable]) +_LT_DECL([], [shlibpath_var], [0],[Shared library path variable]) +_LT_DECL([], [shlibpath_overrides_runpath], [0], + [Is shlibpath searched before the hard-coded library search path?]) +_LT_DECL([], [libname_spec], [1], [Format of library name prefix]) +_LT_DECL([], [library_names_spec], [1], + [[List of archive names. First name is the real one, the rest are links. + The last name is the one that the linker finds with -lNAME]]) +_LT_DECL([], [soname_spec], [1], + [[The coded name of the library, if different from the real name]]) +_LT_DECL([], [install_override_mode], [1], + [Permission mode override for installation of shared libraries]) +_LT_DECL([], [postinstall_cmds], [2], + [Command to use after installation of a shared archive]) +_LT_DECL([], [postuninstall_cmds], [2], + [Command to use after uninstallation of a shared archive]) +_LT_DECL([], [finish_cmds], [2], + [Commands used to finish a libtool library installation in a directory]) +_LT_DECL([], [finish_eval], [1], + [[As "finish_cmds", except a single script fragment to be evaled but + not shown]]) +_LT_DECL([], [hardcode_into_libs], [0], + [Whether we should hardcode library paths into libraries]) +_LT_DECL([], [sys_lib_search_path_spec], [2], + [Compile-time system search path for libraries]) +_LT_DECL([], [sys_lib_dlsearch_path_spec], [2], + [Run-time system search path for libraries]) +])# _LT_SYS_DYNAMIC_LINKER + + +# _LT_PATH_TOOL_PREFIX(TOOL) +# -------------------------- +# find a file program which can recognize shared library +AC_DEFUN([_LT_PATH_TOOL_PREFIX], +[m4_require([_LT_DECL_EGREP])dnl +AC_MSG_CHECKING([for $1]) +AC_CACHE_VAL(lt_cv_path_MAGIC_CMD, +[case $MAGIC_CMD in +[[\\/*] | ?:[\\/]*]) + lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. + ;; +*) + lt_save_MAGIC_CMD="$MAGIC_CMD" + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR +dnl $ac_dummy forces splitting on constant user-supplied paths. +dnl POSIX.2 word splitting is done only on the output of word expansions, +dnl not every word. This closes a longstanding sh security hole. + ac_dummy="m4_if([$2], , $PATH, [$2])" + for ac_dir in $ac_dummy; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$1; then + lt_cv_path_MAGIC_CMD="$ac_dir/$1" + if test -n "$file_magic_test_file"; then + case $deplibs_check_method in + "file_magic "*) + file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` + MAGIC_CMD="$lt_cv_path_MAGIC_CMD" + if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | + $EGREP "$file_magic_regex" > /dev/null; then + : + else + cat <<_LT_EOF 1>&2 + +*** Warning: the command libtool uses to detect shared libraries, +*** $file_magic_cmd, produces output that libtool cannot recognize. +*** The result is that libtool may fail to recognize shared libraries +*** as such. This will affect the creation of libtool libraries that +*** depend on shared libraries, but programs linked with such libtool +*** libraries will work regardless of this problem. Nevertheless, you +*** may want to report the problem to your system manager and/or to +*** bug-libtool@gnu.org + +_LT_EOF + fi ;; + esac + fi + break + fi + done + IFS="$lt_save_ifs" + MAGIC_CMD="$lt_save_MAGIC_CMD" + ;; +esac]) +MAGIC_CMD="$lt_cv_path_MAGIC_CMD" +if test -n "$MAGIC_CMD"; then + AC_MSG_RESULT($MAGIC_CMD) +else + AC_MSG_RESULT(no) +fi +_LT_DECL([], [MAGIC_CMD], [0], + [Used to examine libraries when file_magic_cmd begins with "file"])dnl +])# _LT_PATH_TOOL_PREFIX + +# Old name: +AU_ALIAS([AC_PATH_TOOL_PREFIX], [_LT_PATH_TOOL_PREFIX]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_PATH_TOOL_PREFIX], []) + + +# _LT_PATH_MAGIC +# -------------- +# find a file program which can recognize a shared library +m4_defun([_LT_PATH_MAGIC], +[_LT_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH) +if test -z "$lt_cv_path_MAGIC_CMD"; then + if test -n "$ac_tool_prefix"; then + _LT_PATH_TOOL_PREFIX(file, /usr/bin$PATH_SEPARATOR$PATH) + else + MAGIC_CMD=: + fi +fi +])# _LT_PATH_MAGIC + + +# LT_PATH_LD +# ---------- +# find the pathname to the GNU or non-GNU linker +AC_DEFUN([LT_PATH_LD], +[AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_CANONICAL_BUILD])dnl +m4_require([_LT_DECL_SED])dnl +m4_require([_LT_DECL_EGREP])dnl +m4_require([_LT_PROG_ECHO_BACKSLASH])dnl + +AC_ARG_WITH([gnu-ld], + [AS_HELP_STRING([--with-gnu-ld], + [assume the C compiler uses GNU ld @<:@default=no@:>@])], + [test "$withval" = no || with_gnu_ld=yes], + [with_gnu_ld=no])dnl + +ac_prog=ld +if test "$GCC" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + AC_MSG_CHECKING([for ld used by $CC]) + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case $ac_prog in + # Accept absolute paths. + [[\\/]]* | ?:[[\\/]]*) + re_direlt='/[[^/]][[^/]]*/\.\./' + # Canonicalize the pathname of ld + ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` + while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do + ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` + done + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + AC_MSG_CHECKING([for GNU ld]) +else + AC_MSG_CHECKING([for non-GNU ld]) +fi +AC_CACHE_VAL(lt_cv_path_LD, +[if test -z "$LD"; then + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + lt_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some variants of GNU ld only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + case `"$lt_cv_path_LD" -v 2>&1 &1 /dev/null 2>&1; then + lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' + lt_cv_file_magic_cmd='func_win32_libid' + else + # Keep this pattern in sync with the one in func_win32_libid. + lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' + lt_cv_file_magic_cmd='$OBJDUMP -f' + fi + ;; + +cegcc*) + # use the weaker test based on 'objdump'. See mingw*. + lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?' + lt_cv_file_magic_cmd='$OBJDUMP -f' + ;; + +darwin* | rhapsody*) + lt_cv_deplibs_check_method=pass_all + ;; + +freebsd* | dragonfly*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then + case $host_cpu in + i*86 ) + # Not sure whether the presence of OpenBSD here was a mistake. + # Let's accept both of them until this is cleared up. + lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[[3-9]]86 (compact )?demand paged shared library' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` + ;; + esac + else + lt_cv_deplibs_check_method=pass_all + fi + ;; + +haiku*) + lt_cv_deplibs_check_method=pass_all + ;; + +hpux10.20* | hpux11*) + lt_cv_file_magic_cmd=/usr/bin/file + case $host_cpu in + ia64*) + lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64' + lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so + ;; + hppa*64*) + [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]'] + lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl + ;; + *) + lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]]\.[[0-9]]) shared library' + lt_cv_file_magic_test_file=/usr/lib/libc.sl + ;; + esac + ;; + +interix[[3-9]]*) + # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|\.a)$' + ;; + +irix5* | irix6* | nonstopux*) + case $LD in + *-32|*"-32 ") libmagic=32-bit;; + *-n32|*"-n32 ") libmagic=N32;; + *-64|*"-64 ") libmagic=64-bit;; + *) libmagic=never-match;; + esac + lt_cv_deplibs_check_method=pass_all + ;; + +# This must be glibc/ELF. +linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) + lt_cv_deplibs_check_method=pass_all + ;; + +netbsd* | netbsdelf*-gnu) + if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|_pic\.a)$' + fi + ;; + +newos6*) + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=/usr/lib/libnls.so + ;; + +*nto* | *qnx*) + lt_cv_deplibs_check_method=pass_all + ;; + +openbsd*) + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|\.so|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' + fi + ;; + +osf3* | osf4* | osf5*) + lt_cv_deplibs_check_method=pass_all + ;; + +rdos*) + lt_cv_deplibs_check_method=pass_all + ;; + +solaris*) + lt_cv_deplibs_check_method=pass_all + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + lt_cv_deplibs_check_method=pass_all + ;; + +sysv4 | sysv4.3*) + case $host_vendor in + motorola) + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]' + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` + ;; + ncr) + lt_cv_deplibs_check_method=pass_all + ;; + sequent) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )' + ;; + sni) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib" + lt_cv_file_magic_test_file=/lib/libc.so + ;; + siemens) + lt_cv_deplibs_check_method=pass_all + ;; + pc) + lt_cv_deplibs_check_method=pass_all + ;; + esac + ;; + +tpf*) + lt_cv_deplibs_check_method=pass_all + ;; +esac +]) + +file_magic_glob= +want_nocaseglob=no +if test "$build" = "$host"; then + case $host_os in + mingw* | pw32*) + if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then + want_nocaseglob=yes + else + file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[[\1]]\/[[\1]]\/g;/g"` + fi + ;; + esac +fi + +file_magic_cmd=$lt_cv_file_magic_cmd +deplibs_check_method=$lt_cv_deplibs_check_method +test -z "$deplibs_check_method" && deplibs_check_method=unknown + +_LT_DECL([], [deplibs_check_method], [1], + [Method to check whether dependent libraries are shared objects]) +_LT_DECL([], [file_magic_cmd], [1], + [Command to use when deplibs_check_method = "file_magic"]) +_LT_DECL([], [file_magic_glob], [1], + [How to find potential files when deplibs_check_method = "file_magic"]) +_LT_DECL([], [want_nocaseglob], [1], + [Find potential files using nocaseglob when deplibs_check_method = "file_magic"]) +])# _LT_CHECK_MAGIC_METHOD + + +# LT_PATH_NM +# ---------- +# find the pathname to a BSD- or MS-compatible name lister +AC_DEFUN([LT_PATH_NM], +[AC_REQUIRE([AC_PROG_CC])dnl +AC_CACHE_CHECK([for BSD- or MS-compatible name lister (nm)], lt_cv_path_NM, +[if test -n "$NM"; then + # Let the user override the test. + lt_cv_path_NM="$NM" +else + lt_nm_to_check="${ac_tool_prefix}nm" + if test -n "$ac_tool_prefix" && test "$build" = "$host"; then + lt_nm_to_check="$lt_nm_to_check nm" + fi + for lt_tmp_nm in $lt_nm_to_check; do + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + tmp_nm="$ac_dir/$lt_tmp_nm" + if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then + # Check to see if the nm accepts a BSD-compat flag. + # Adding the `sed 1q' prevents false positives on HP-UX, which says: + # nm: unknown option "B" ignored + # Tru64's nm complains that /dev/null is an invalid object file + case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in + */dev/null* | *'Invalid file or object type'*) + lt_cv_path_NM="$tmp_nm -B" + break + ;; + *) + case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in + */dev/null*) + lt_cv_path_NM="$tmp_nm -p" + break + ;; + *) + lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but + continue # so that we can try to find one that supports BSD flags + ;; + esac + ;; + esac + fi + done + IFS="$lt_save_ifs" + done + : ${lt_cv_path_NM=no} +fi]) +if test "$lt_cv_path_NM" != "no"; then + NM="$lt_cv_path_NM" +else + # Didn't find any BSD compatible name lister, look for dumpbin. + if test -n "$DUMPBIN"; then : + # Let the user override the test. + else + AC_CHECK_TOOLS(DUMPBIN, [dumpbin "link -dump"], :) + case `$DUMPBIN -symbols /dev/null 2>&1 | sed '1q'` in + *COFF*) + DUMPBIN="$DUMPBIN -symbols" + ;; + *) + DUMPBIN=: + ;; + esac + fi + AC_SUBST([DUMPBIN]) + if test "$DUMPBIN" != ":"; then + NM="$DUMPBIN" + fi +fi +test -z "$NM" && NM=nm +AC_SUBST([NM]) +_LT_DECL([], [NM], [1], [A BSD- or MS-compatible name lister])dnl + +AC_CACHE_CHECK([the name lister ($NM) interface], [lt_cv_nm_interface], + [lt_cv_nm_interface="BSD nm" + echo "int some_variable = 0;" > conftest.$ac_ext + (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&AS_MESSAGE_LOG_FD) + (eval "$ac_compile" 2>conftest.err) + cat conftest.err >&AS_MESSAGE_LOG_FD + (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&AS_MESSAGE_LOG_FD) + (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) + cat conftest.err >&AS_MESSAGE_LOG_FD + (eval echo "\"\$as_me:$LINENO: output\"" >&AS_MESSAGE_LOG_FD) + cat conftest.out >&AS_MESSAGE_LOG_FD + if $GREP 'External.*some_variable' conftest.out > /dev/null; then + lt_cv_nm_interface="MS dumpbin" + fi + rm -f conftest*]) +])# LT_PATH_NM + +# Old names: +AU_ALIAS([AM_PROG_NM], [LT_PATH_NM]) +AU_ALIAS([AC_PROG_NM], [LT_PATH_NM]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AM_PROG_NM], []) +dnl AC_DEFUN([AC_PROG_NM], []) + +# _LT_CHECK_SHAREDLIB_FROM_LINKLIB +# -------------------------------- +# how to determine the name of the shared library +# associated with a specific link library. +# -- PORTME fill in with the dynamic library characteristics +m4_defun([_LT_CHECK_SHAREDLIB_FROM_LINKLIB], +[m4_require([_LT_DECL_EGREP]) +m4_require([_LT_DECL_OBJDUMP]) +m4_require([_LT_DECL_DLLTOOL]) +AC_CACHE_CHECK([how to associate runtime and link libraries], +lt_cv_sharedlib_from_linklib_cmd, +[lt_cv_sharedlib_from_linklib_cmd='unknown' + +case $host_os in +cygwin* | mingw* | pw32* | cegcc*) + # two different shell functions defined in ltmain.sh + # decide which to use based on capabilities of $DLLTOOL + case `$DLLTOOL --help 2>&1` in + *--identify-strict*) + lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib + ;; + *) + lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback + ;; + esac + ;; +*) + # fallback: assume linklib IS sharedlib + lt_cv_sharedlib_from_linklib_cmd="$ECHO" + ;; +esac +]) +sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd +test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO + +_LT_DECL([], [sharedlib_from_linklib_cmd], [1], + [Command to associate shared and link libraries]) +])# _LT_CHECK_SHAREDLIB_FROM_LINKLIB + + +# _LT_PATH_MANIFEST_TOOL +# ---------------------- +# locate the manifest tool +m4_defun([_LT_PATH_MANIFEST_TOOL], +[AC_CHECK_TOOL(MANIFEST_TOOL, mt, :) +test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt +AC_CACHE_CHECK([if $MANIFEST_TOOL is a manifest tool], [lt_cv_path_mainfest_tool], + [lt_cv_path_mainfest_tool=no + echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&AS_MESSAGE_LOG_FD + $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out + cat conftest.err >&AS_MESSAGE_LOG_FD + if $GREP 'Manifest Tool' conftest.out > /dev/null; then + lt_cv_path_mainfest_tool=yes + fi + rm -f conftest*]) +if test "x$lt_cv_path_mainfest_tool" != xyes; then + MANIFEST_TOOL=: +fi +_LT_DECL([], [MANIFEST_TOOL], [1], [Manifest tool])dnl +])# _LT_PATH_MANIFEST_TOOL + + +# LT_LIB_M +# -------- +# check for math library +AC_DEFUN([LT_LIB_M], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +LIBM= +case $host in +*-*-beos* | *-*-cegcc* | *-*-cygwin* | *-*-haiku* | *-*-pw32* | *-*-darwin*) + # These system don't have libm, or don't need it + ;; +*-ncr-sysv4.3*) + AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM="-lmw") + AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm") + ;; +*) + AC_CHECK_LIB(m, cos, LIBM="-lm") + ;; +esac +AC_SUBST([LIBM]) +])# LT_LIB_M + +# Old name: +AU_ALIAS([AC_CHECK_LIBM], [LT_LIB_M]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_CHECK_LIBM], []) + + +# _LT_COMPILER_NO_RTTI([TAGNAME]) +# ------------------------------- +m4_defun([_LT_COMPILER_NO_RTTI], +[m4_require([_LT_TAG_COMPILER])dnl + +_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= + +if test "$GCC" = yes; then + case $cc_basename in + nvcc*) + _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -Xcompiler -fno-builtin' ;; + *) + _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' ;; + esac + + _LT_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions], + lt_cv_prog_compiler_rtti_exceptions, + [-fno-rtti -fno-exceptions], [], + [_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)="$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) -fno-rtti -fno-exceptions"]) +fi +_LT_TAGDECL([no_builtin_flag], [lt_prog_compiler_no_builtin_flag], [1], + [Compiler flag to turn off builtin functions]) +])# _LT_COMPILER_NO_RTTI + + +# _LT_CMD_GLOBAL_SYMBOLS +# ---------------------- +m4_defun([_LT_CMD_GLOBAL_SYMBOLS], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([AC_PROG_AWK])dnl +AC_REQUIRE([LT_PATH_NM])dnl +AC_REQUIRE([LT_PATH_LD])dnl +m4_require([_LT_DECL_SED])dnl +m4_require([_LT_DECL_EGREP])dnl +m4_require([_LT_TAG_COMPILER])dnl + +# Check for command to grab the raw symbol name followed by C symbol from nm. +AC_MSG_CHECKING([command to parse $NM output from $compiler object]) +AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe], +[ +# These are sane defaults that work on at least a few old systems. +# [They come from Ultrix. What could be older than Ultrix?!! ;)] + +# Character class describing NM global symbol codes. +symcode='[[BCDEGRST]]' + +# Regexp to match symbols that can be accessed directly from C. +sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)' + +# Define system-specific variables. +case $host_os in +aix*) + symcode='[[BCDT]]' + ;; +cygwin* | mingw* | pw32* | cegcc*) + symcode='[[ABCDGISTW]]' + ;; +hpux*) + if test "$host_cpu" = ia64; then + symcode='[[ABCDEGRST]]' + fi + ;; +irix* | nonstopux*) + symcode='[[BCDEGRST]]' + ;; +osf*) + symcode='[[BCDEGQRST]]' + ;; +solaris*) + symcode='[[BDRT]]' + ;; +sco3.2v5*) + symcode='[[DT]]' + ;; +sysv4.2uw2*) + symcode='[[DT]]' + ;; +sysv5* | sco5v6* | unixware* | OpenUNIX*) + symcode='[[ABDT]]' + ;; +sysv4) + symcode='[[DFNSTU]]' + ;; +esac + +# If we're using GNU nm, then use its standard symbol codes. +case `$NM -V 2>&1` in +*GNU* | *'with BFD'*) + symcode='[[ABCDGIRSTW]]' ;; +esac + +# Transform an extracted symbol line into a proper C declaration. +# Some systems (esp. on ia64) link data and code symbols differently, +# so use this general approach. +lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" + +# Transform an extracted symbol line into symbol name and symbol address +lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\)[[ ]]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (void *) \&\2},/p'" +lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([[^ ]]*\)[[ ]]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \(lib[[^ ]]*\)$/ {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"lib\2\", (void *) \&\2},/p'" + +# Handle CRLF in mingw tool chain +opt_cr= +case $build_os in +mingw*) + opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp + ;; +esac + +# Try without a prefix underscore, then with it. +for ac_symprfx in "" "_"; do + + # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. + symxfrm="\\1 $ac_symprfx\\2 \\2" + + # Write the raw and C identifiers. + if test "$lt_cv_nm_interface" = "MS dumpbin"; then + # Fake it for dumpbin and say T for any non-static function + # and D for any global variable. + # Also find C++ and __fastcall symbols from MSVC++, + # which start with @ or ?. + lt_cv_sys_global_symbol_pipe="$AWK ['"\ +" {last_section=section; section=\$ 3};"\ +" /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\ +" /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\ +" \$ 0!~/External *\|/{next};"\ +" / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ +" {if(hide[section]) next};"\ +" {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\ +" {split(\$ 0, a, /\||\r/); split(a[2], s)};"\ +" s[1]~/^[@?]/{print s[1], s[1]; next};"\ +" s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\ +" ' prfx=^$ac_symprfx]" + else + lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[ ]]\($symcode$symcode*\)[[ ]][[ ]]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" + fi + lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | sed '/ __gnu_lto/d'" + + # Check to see that the pipe works correctly. + pipe_works=no + + rm -f conftest* + cat > conftest.$ac_ext <<_LT_EOF +#ifdef __cplusplus +extern "C" { +#endif +char nm_test_var; +void nm_test_func(void); +void nm_test_func(void){} +#ifdef __cplusplus +} +#endif +int main(){nm_test_var='a';nm_test_func();return(0);} +_LT_EOF + + if AC_TRY_EVAL(ac_compile); then + # Now try to grab the symbols. + nlist=conftest.nm + if AC_TRY_EVAL(NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist) && test -s "$nlist"; then + # Try sorting and uniquifying the output. + if sort "$nlist" | uniq > "$nlist"T; then + mv -f "$nlist"T "$nlist" + else + rm -f "$nlist"T + fi + + # Make sure that we snagged all the symbols we need. + if $GREP ' nm_test_var$' "$nlist" >/dev/null; then + if $GREP ' nm_test_func$' "$nlist" >/dev/null; then + cat <<_LT_EOF > conftest.$ac_ext +/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ +#if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE) +/* DATA imports from DLLs on WIN32 con't be const, because runtime + relocations are performed -- see ld's documentation on pseudo-relocs. */ +# define LT@&t@_DLSYM_CONST +#elif defined(__osf__) +/* This system does not cope well with relocations in const data. */ +# define LT@&t@_DLSYM_CONST +#else +# define LT@&t@_DLSYM_CONST const +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +_LT_EOF + # Now generate the symbol file. + eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext' + + cat <<_LT_EOF >> conftest.$ac_ext + +/* The mapping between symbol names and symbols. */ +LT@&t@_DLSYM_CONST struct { + const char *name; + void *address; +} +lt__PROGRAM__LTX_preloaded_symbols[[]] = +{ + { "@PROGRAM@", (void *) 0 }, +_LT_EOF + $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext + cat <<\_LT_EOF >> conftest.$ac_ext + {0, (void *) 0} +}; + +/* This works around a problem in FreeBSD linker */ +#ifdef FREEBSD_WORKAROUND +static const void *lt_preloaded_setup() { + return lt__PROGRAM__LTX_preloaded_symbols; +} +#endif + +#ifdef __cplusplus +} +#endif +_LT_EOF + # Now try linking the two files. + mv conftest.$ac_objext conftstm.$ac_objext + lt_globsym_save_LIBS=$LIBS + lt_globsym_save_CFLAGS=$CFLAGS + LIBS="conftstm.$ac_objext" + CFLAGS="$CFLAGS$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)" + if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext}; then + pipe_works=yes + fi + LIBS=$lt_globsym_save_LIBS + CFLAGS=$lt_globsym_save_CFLAGS + else + echo "cannot find nm_test_func in $nlist" >&AS_MESSAGE_LOG_FD + fi + else + echo "cannot find nm_test_var in $nlist" >&AS_MESSAGE_LOG_FD + fi + else + echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD + fi + else + echo "$progname: failed program was:" >&AS_MESSAGE_LOG_FD + cat conftest.$ac_ext >&5 + fi + rm -rf conftest* conftst* + + # Do not use the global_symbol_pipe unless it works. + if test "$pipe_works" = yes; then + break + else + lt_cv_sys_global_symbol_pipe= + fi +done +]) +if test -z "$lt_cv_sys_global_symbol_pipe"; then + lt_cv_sys_global_symbol_to_cdecl= +fi +if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then + AC_MSG_RESULT(failed) +else + AC_MSG_RESULT(ok) +fi + +# Response file support. +if test "$lt_cv_nm_interface" = "MS dumpbin"; then + nm_file_list_spec='@' +elif $NM --help 2>/dev/null | grep '[[@]]FILE' >/dev/null; then + nm_file_list_spec='@' +fi + +_LT_DECL([global_symbol_pipe], [lt_cv_sys_global_symbol_pipe], [1], + [Take the output of nm and produce a listing of raw symbols and C names]) +_LT_DECL([global_symbol_to_cdecl], [lt_cv_sys_global_symbol_to_cdecl], [1], + [Transform the output of nm in a proper C declaration]) +_LT_DECL([global_symbol_to_c_name_address], + [lt_cv_sys_global_symbol_to_c_name_address], [1], + [Transform the output of nm in a C name address pair]) +_LT_DECL([global_symbol_to_c_name_address_lib_prefix], + [lt_cv_sys_global_symbol_to_c_name_address_lib_prefix], [1], + [Transform the output of nm in a C name address pair when lib prefix is needed]) +_LT_DECL([], [nm_file_list_spec], [1], + [Specify filename containing input files for $NM]) +]) # _LT_CMD_GLOBAL_SYMBOLS + + +# _LT_COMPILER_PIC([TAGNAME]) +# --------------------------- +m4_defun([_LT_COMPILER_PIC], +[m4_require([_LT_TAG_COMPILER])dnl +_LT_TAGVAR(lt_prog_compiler_wl, $1)= +_LT_TAGVAR(lt_prog_compiler_pic, $1)= +_LT_TAGVAR(lt_prog_compiler_static, $1)= + +m4_if([$1], [CXX], [ + # C++ specific cases for pic, static, wl, etc. + if test "$GXX" = yes; then + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + m68k) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' + ;; + esac + ;; + + beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + mingw* | cygwin* | os2* | pw32* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + # Although the cygwin gcc ignores -fPIC, still need this for old-style + # (--disable-auto-import) libraries + m4_if([$1], [GCJ], [], + [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) + ;; + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' + ;; + *djgpp*) + # DJGPP does not support shared libraries at all + _LT_TAGVAR(lt_prog_compiler_pic, $1)= + ;; + haiku*) + # PIC is the default for Haiku. + # The "-static" flag exists, but is broken. + _LT_TAGVAR(lt_prog_compiler_static, $1)= + ;; + interix[[3-9]]*) + # Interix 3.x gcc -fpic/-fPIC options generate broken code. + # Instead, we relocate shared libraries at runtime. + ;; + sysv4*MP*) + if test -d /usr/nec; then + _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic + fi + ;; + hpux*) + # PIC is the default for 64-bit PA HP-UX, but not for 32-bit + # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag + # sets the default TLS model and affects inlining. + case $host_cpu in + hppa*64*) + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + ;; + *qnx* | *nto*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + else + case $host_os in + aix[[4-9]]*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + else + _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' + fi + ;; + chorus*) + case $cc_basename in + cxch68*) + # Green Hills C++ Compiler + # _LT_TAGVAR(lt_prog_compiler_static, $1)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a" + ;; + esac + ;; + mingw* | cygwin* | os2* | pw32* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + m4_if([$1], [GCJ], [], + [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) + ;; + dgux*) + case $cc_basename in + ec++*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + ;; + ghcx*) + # Green Hills C++ Compiler + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + ;; + *) + ;; + esac + ;; + freebsd* | dragonfly*) + # FreeBSD uses GNU C++ + ;; + hpux9* | hpux10* | hpux11*) + case $cc_basename in + CC*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' + if test "$host_cpu" != ia64; then + _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' + fi + ;; + aCC*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' + ;; + esac + ;; + *) + ;; + esac + ;; + interix*) + # This is c89, which is MS Visual C++ (no shared libs) + # Anyone wants to do a port? + ;; + irix5* | irix6* | nonstopux*) + case $cc_basename in + CC*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + # CC pic flag -KPIC is the default. + ;; + *) + ;; + esac + ;; + linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) + case $cc_basename in + KCC*) + # KAI C++ Compiler + _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + ecpc* ) + # old Intel C++ for x86_64 which still supported -KPIC. + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + icpc* ) + # Intel C++, used to be incompatible with GCC. + # ICC 10 doesn't accept -KPIC any more. + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + pgCC* | pgcpp*) + # Portland Group C++ compiler + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + cxx*) + # Compaq C++ + # Make sure the PIC flag is empty. It appears that all Alpha + # Linux and Compaq Tru64 Unix objects are PIC. + _LT_TAGVAR(lt_prog_compiler_pic, $1)= + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + xlc* | xlC* | bgxl[[cC]]* | mpixl[[cC]]*) + # IBM XL 8.0, 9.0 on PPC and BlueGene + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink' + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C++ 5.9 + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' + ;; + esac + ;; + esac + ;; + lynxos*) + ;; + m88k*) + ;; + mvs*) + case $cc_basename in + cxx*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-W c,exportall' + ;; + *) + ;; + esac + ;; + netbsd* | netbsdelf*-gnu) + ;; + *qnx* | *nto*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' + ;; + osf3* | osf4* | osf5*) + case $cc_basename in + KCC*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' + ;; + RCC*) + # Rational C++ 2.4.1 + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + ;; + cxx*) + # Digital/Compaq C++ + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # Make sure the PIC flag is empty. It appears that all Alpha + # Linux and Compaq Tru64 Unix objects are PIC. + _LT_TAGVAR(lt_prog_compiler_pic, $1)= + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + *) + ;; + esac + ;; + psos*) + ;; + solaris*) + case $cc_basename in + CC* | sunCC*) + # Sun C++ 4.2, 5.x and Centerline C++ + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' + ;; + gcx*) + # Green Hills C++ Compiler + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' + ;; + *) + ;; + esac + ;; + sunos4*) + case $cc_basename in + CC*) + # Sun C++ 4.x + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + lcc*) + # Lucid + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + ;; + *) + ;; + esac + ;; + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + case $cc_basename in + CC*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + esac + ;; + tandem*) + case $cc_basename in + NCC*) + # NonStop-UX NCC 3.20 + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + ;; + *) + ;; + esac + ;; + vxworks*) + ;; + *) + _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + ;; + esac + fi +], +[ + if test "$GCC" = yes; then + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + m68k) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' + ;; + esac + ;; + + beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + + mingw* | cygwin* | pw32* | os2* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + # Although the cygwin gcc ignores -fPIC, still need this for old-style + # (--disable-auto-import) libraries + m4_if([$1], [GCJ], [], + [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) + ;; + + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' + ;; + + haiku*) + # PIC is the default for Haiku. + # The "-static" flag exists, but is broken. + _LT_TAGVAR(lt_prog_compiler_static, $1)= + ;; + + hpux*) + # PIC is the default for 64-bit PA HP-UX, but not for 32-bit + # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag + # sets the default TLS model and affects inlining. + case $host_cpu in + hppa*64*) + # +Z the default + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + ;; + + interix[[3-9]]*) + # Interix 3.x gcc -fpic/-fPIC options generate broken code. + # Instead, we relocate shared libraries at runtime. + ;; + + msdosdjgpp*) + # Just because we use GCC doesn't mean we suddenly get shared libraries + # on systems that don't support them. + _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + enable_shared=no + ;; + + *nto* | *qnx*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic + fi + ;; + + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + + case $cc_basename in + nvcc*) # Cuda Compiler Driver 2.2 + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Xlinker ' + if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then + _LT_TAGVAR(lt_prog_compiler_pic, $1)="-Xcompiler $_LT_TAGVAR(lt_prog_compiler_pic, $1)" + fi + ;; + esac + else + # PORTME Check for flag to pass linker flags through the system compiler. + case $host_os in + aix*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + else + _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' + fi + ;; + + mingw* | cygwin* | pw32* | os2* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + m4_if([$1], [GCJ], [], + [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) + ;; + + hpux9* | hpux10* | hpux11*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' + ;; + esac + # Is there a better lt_prog_compiler_static that works with the bundled CC? + _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' + ;; + + irix5* | irix6* | nonstopux*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # PIC (with -KPIC) is the default. + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + + linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) + case $cc_basename in + # old Intel for x86_64 which still supported -KPIC. + ecc*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + # icc used to be incompatible with GCC. + # ICC 10 doesn't accept -KPIC any more. + icc* | ifort*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + # Lahey Fortran 8.1. + lf95*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='--shared' + _LT_TAGVAR(lt_prog_compiler_static, $1)='--static' + ;; + nagfor*) + # NAG Fortran compiler + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,-Wl,,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*) + # Portland Group compilers (*not* the Pentium gcc compiler, + # which looks to be a dead project) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + ccc*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # All Alpha code is PIC. + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + xl* | bgxl* | bgf* | mpixl*) + # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink' + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [[1-7]].* | *Sun*Fortran*\ 8.[[0-3]]*) + # Sun Fortran 8.3 passes all unrecognized flags to the linker + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_TAGVAR(lt_prog_compiler_wl, $1)='' + ;; + *Sun\ F* | *Sun*Fortran*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' + ;; + *Sun\ C*) + # Sun C 5.9 + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + ;; + *Intel*\ [[CF]]*Compiler*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + *Portland\ Group*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + esac + ;; + esac + ;; + + newsos6) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + *nto* | *qnx*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' + ;; + + osf3* | osf4* | osf5*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # All OSF/1 code is PIC. + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + + rdos*) + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + + solaris*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + case $cc_basename in + f77* | f90* | f95* | sunf77* | sunf90* | sunf95*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ';; + *) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,';; + esac + ;; + + sunos4*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + sysv4 | sysv4.2uw2* | sysv4.3*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + sysv4*MP*) + if test -d /usr/nec ;then + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + ;; + + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + unicos*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + ;; + + uts4*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + *) + _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + ;; + esac + fi +]) +case $host_os in + # For platforms which do not support PIC, -DPIC is meaningless: + *djgpp*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)= + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])" + ;; +esac + +AC_CACHE_CHECK([for $compiler option to produce PIC], + [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)], + [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_prog_compiler_pic, $1)]) +_LT_TAGVAR(lt_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_cv_prog_compiler_pic, $1) + +# +# Check to make sure the PIC flag actually works. +# +if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then + _LT_COMPILER_OPTION([if $compiler PIC flag $_LT_TAGVAR(lt_prog_compiler_pic, $1) works], + [_LT_TAGVAR(lt_cv_prog_compiler_pic_works, $1)], + [$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])], [], + [case $_LT_TAGVAR(lt_prog_compiler_pic, $1) in + "" | " "*) ;; + *) _LT_TAGVAR(lt_prog_compiler_pic, $1)=" $_LT_TAGVAR(lt_prog_compiler_pic, $1)" ;; + esac], + [_LT_TAGVAR(lt_prog_compiler_pic, $1)= + _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no]) +fi +_LT_TAGDECL([pic_flag], [lt_prog_compiler_pic], [1], + [Additional compiler flags for building library objects]) + +_LT_TAGDECL([wl], [lt_prog_compiler_wl], [1], + [How to pass a linker flag through the compiler]) +# +# Check to make sure the static flag actually works. +# +wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) eval lt_tmp_static_flag=\"$_LT_TAGVAR(lt_prog_compiler_static, $1)\" +_LT_LINKER_OPTION([if $compiler static flag $lt_tmp_static_flag works], + _LT_TAGVAR(lt_cv_prog_compiler_static_works, $1), + $lt_tmp_static_flag, + [], + [_LT_TAGVAR(lt_prog_compiler_static, $1)=]) +_LT_TAGDECL([link_static_flag], [lt_prog_compiler_static], [1], + [Compiler flag to prevent dynamic linking]) +])# _LT_COMPILER_PIC + + +# _LT_LINKER_SHLIBS([TAGNAME]) +# ---------------------------- +# See if the linker supports building shared libraries. +m4_defun([_LT_LINKER_SHLIBS], +[AC_REQUIRE([LT_PATH_LD])dnl +AC_REQUIRE([LT_PATH_NM])dnl +m4_require([_LT_PATH_MANIFEST_TOOL])dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_EGREP])dnl +m4_require([_LT_DECL_SED])dnl +m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl +m4_require([_LT_TAG_COMPILER])dnl +AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) +m4_if([$1], [CXX], [ + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'] + case $host_os in + aix[[4-9]]*) + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to AIX nm, but means don't demangle with GNU nm + # Also, AIX nm treats weak defined symbols like other global defined + # symbols, whereas GNU nm marks them as "W". + if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then + _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + else + _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + fi + ;; + pw32*) + _LT_TAGVAR(export_symbols_cmds, $1)="$ltdll_cmds" + ;; + cygwin* | mingw* | cegcc*) + case $cc_basename in + cl*) + _LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' + ;; + *) + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols' + _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname'] + ;; + esac + ;; + linux* | k*bsd*-gnu | gnu*) + _LT_TAGVAR(link_all_deplibs, $1)=no + ;; + *) + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + ;; + esac +], [ + runpath_var= + _LT_TAGVAR(allow_undefined_flag, $1)= + _LT_TAGVAR(always_export_symbols, $1)=no + _LT_TAGVAR(archive_cmds, $1)= + _LT_TAGVAR(archive_expsym_cmds, $1)= + _LT_TAGVAR(compiler_needs_object, $1)=no + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no + _LT_TAGVAR(export_dynamic_flag_spec, $1)= + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + _LT_TAGVAR(hardcode_automatic, $1)=no + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_direct_absolute, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= + _LT_TAGVAR(hardcode_libdir_separator, $1)= + _LT_TAGVAR(hardcode_minus_L, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported + _LT_TAGVAR(inherit_rpath, $1)=no + _LT_TAGVAR(link_all_deplibs, $1)=unknown + _LT_TAGVAR(module_cmds, $1)= + _LT_TAGVAR(module_expsym_cmds, $1)= + _LT_TAGVAR(old_archive_from_new_cmds, $1)= + _LT_TAGVAR(old_archive_from_expsyms_cmds, $1)= + _LT_TAGVAR(thread_safe_flag_spec, $1)= + _LT_TAGVAR(whole_archive_flag_spec, $1)= + # include_expsyms should be a list of space-separated symbols to be *always* + # included in the symbol list + _LT_TAGVAR(include_expsyms, $1)= + # exclude_expsyms can be an extended regexp of symbols to exclude + # it will be wrapped by ` (' and `)$', so one must not match beginning or + # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', + # as well as any symbol that contains `d'. + _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'] + # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out + # platforms (ab)use it in PIC code, but their linkers get confused if + # the symbol is explicitly referenced. Since portable code cannot + # rely on this symbol name, it's probably fine to never include it in + # preloaded symbol tables. + # Exclude shared library initialization/finalization symbols. +dnl Note also adjust exclude_expsyms for C++ above. + extract_expsyms_cmds= + + case $host_os in + cygwin* | mingw* | pw32* | cegcc*) + # FIXME: the MSVC++ port hasn't been tested in a loooong time + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + if test "$GCC" != yes; then + with_gnu_ld=no + fi + ;; + interix*) + # we just hope/assume this is gcc and not c89 (= MSVC++) + with_gnu_ld=yes + ;; + openbsd*) + with_gnu_ld=no + ;; + linux* | k*bsd*-gnu | gnu*) + _LT_TAGVAR(link_all_deplibs, $1)=no + ;; + esac + + _LT_TAGVAR(ld_shlibs, $1)=yes + + # On some targets, GNU ld is compatible enough with the native linker + # that we're better off using the native interface for both. + lt_use_gnu_ld_interface=no + if test "$with_gnu_ld" = yes; then + case $host_os in + aix*) + # The AIX port of GNU ld has always aspired to compatibility + # with the native linker. However, as the warning in the GNU ld + # block says, versions before 2.19.5* couldn't really create working + # shared libraries, regardless of the interface used. + case `$LD -v 2>&1` in + *\ \(GNU\ Binutils\)\ 2.19.5*) ;; + *\ \(GNU\ Binutils\)\ 2.[[2-9]]*) ;; + *\ \(GNU\ Binutils\)\ [[3-9]]*) ;; + *) + lt_use_gnu_ld_interface=yes + ;; + esac + ;; + *) + lt_use_gnu_ld_interface=yes + ;; + esac + fi + + if test "$lt_use_gnu_ld_interface" = yes; then + # If archive_cmds runs LD, not CC, wlarc should be empty + wlarc='${wl}' + + # Set some defaults for GNU ld with shared library support. These + # are reset later if shared libraries are not supported. Putting them + # here allows them to be overridden if necessary. + runpath_var=LD_RUN_PATH + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + # ancient GNU ld didn't support --whole-archive et. al. + if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then + _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + _LT_TAGVAR(whole_archive_flag_spec, $1)= + fi + supports_anon_versioning=no + case `$LD -v 2>&1` in + *GNU\ gold*) supports_anon_versioning=yes ;; + *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11 + *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... + *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... + *\ 2.11.*) ;; # other 2.11 versions + *) supports_anon_versioning=yes ;; + esac + + # See if GNU ld supports shared libraries. + case $host_os in + aix[[3-9]]*) + # On AIX/PPC, the GNU linker is very broken + if test "$host_cpu" != ia64; then + _LT_TAGVAR(ld_shlibs, $1)=no + cat <<_LT_EOF 1>&2 + +*** Warning: the GNU linker, at least up to release 2.19, is reported +*** to be unable to reliably create shared libraries on AIX. +*** Therefore, libtool is disabling shared libraries support. If you +*** really care for shared libraries, you may want to install binutils +*** 2.20 or above, or modify your PATH so that a non-GNU linker is found. +*** You will then need to restart the configuration process. + +_LT_EOF + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='' + ;; + m68k) + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_minus_L, $1)=yes + ;; + esac + ;; + + beos*) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + # Joseph Beckenbach says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + cygwin* | mingw* | pw32* | cegcc*) + # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, + # as there is no search path for DLLs. + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-all-symbols' + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(always_export_symbols, $1)=no + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols' + _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname'] + + if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is; otherwise, prepend... + _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + haiku*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(link_all_deplibs, $1)=yes + ;; + + interix[[3-9]]*) + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. + # Instead, shared libraries are loaded at an image base (0x10000000 by + # default) and relocated if they conflict, which is a slow very memory + # consuming and fragmenting process. To avoid this, we pick a random, + # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link + # time. Moving up from 0x10000000 also allows more sbrk(2) space. + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + ;; + + gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu) + tmp_diet=no + if test "$host_os" = linux-dietlibc; then + case $cc_basename in + diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn) + esac + fi + if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \ + && test "$tmp_diet" = no + then + tmp_addflag=' $pic_flag' + tmp_sharedflag='-shared' + case $cc_basename,$host_cpu in + pgcc*) # Portland Group C compiler + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_addflag=' $pic_flag' + ;; + pgf77* | pgf90* | pgf95* | pgfortran*) + # Portland Group f77 and f90 compilers + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_addflag=' $pic_flag -Mnomain' ;; + ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 + tmp_addflag=' -i_dynamic' ;; + efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 + tmp_addflag=' -i_dynamic -nofor_main' ;; + ifc* | ifort*) # Intel Fortran compiler + tmp_addflag=' -nofor_main' ;; + lf95*) # Lahey Fortran 8.1 + _LT_TAGVAR(whole_archive_flag_spec, $1)= + tmp_sharedflag='--shared' ;; + xl[[cC]]* | bgxl[[cC]]* | mpixl[[cC]]*) # IBM XL C 8.0 on PPC (deal with xlf below) + tmp_sharedflag='-qmkshrobj' + tmp_addflag= ;; + nvcc*) # Cuda Compiler Driver 2.2 + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + _LT_TAGVAR(compiler_needs_object, $1)=yes + ;; + esac + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) # Sun C 5.9 + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + _LT_TAGVAR(compiler_needs_object, $1)=yes + tmp_sharedflag='-G' ;; + *Sun\ F*) # Sun Fortran 8.3 + tmp_sharedflag='-G' ;; + esac + _LT_TAGVAR(archive_cmds, $1)='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + + if test "x$supports_anon_versioning" = xyes; then + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' + fi + + case $cc_basename in + xlf* | bgf* | bgxlf* | mpixlf*) + # IBM XL Fortran 10.1 on PPC cannot create shared libs itself + _LT_TAGVAR(whole_archive_flag_spec, $1)='--whole-archive$convenience --no-whole-archive' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib' + if test "x$supports_anon_versioning" = xyes; then + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib' + fi + ;; + esac + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + netbsd* | netbsdelf*-gnu) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' + wlarc= + else + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + fi + ;; + + solaris*) + if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then + _LT_TAGVAR(ld_shlibs, $1)=no + cat <<_LT_EOF 1>&2 + +*** Warning: The releases 2.8.* of the GNU linker cannot reliably +*** create shared libraries on Solaris systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.9.1 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +_LT_EOF + elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) + case `$LD -v 2>&1` in + *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.1[[0-5]].*) + _LT_TAGVAR(ld_shlibs, $1)=no + cat <<_LT_EOF 1>&2 + +*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not +*** reliably create shared libraries on SCO systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.16.91.0.3 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +_LT_EOF + ;; + *) + # For security reasons, it is highly recommended that you always + # use absolute paths for naming shared libraries, and exclude the + # DT_RUNPATH tag from executables and libraries. But doing so + # requires that you compile everything twice, which is a pain. + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + + sunos4*) + _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' + wlarc= + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + *) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + + if test "$_LT_TAGVAR(ld_shlibs, $1)" = no; then + runpath_var= + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= + _LT_TAGVAR(export_dynamic_flag_spec, $1)= + _LT_TAGVAR(whole_archive_flag_spec, $1)= + fi + else + # PORTME fill in a description of your system's linker (not GNU ld) + case $host_os in + aix3*) + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(always_export_symbols, $1)=yes + _LT_TAGVAR(archive_expsym_cmds, $1)='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' + # Note: this linker hardcodes the directories in LIBPATH if there + # are no directories specified by -L. + _LT_TAGVAR(hardcode_minus_L, $1)=yes + if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then + # Neither direct hardcoding nor static linking is supported with a + # broken collect2. + _LT_TAGVAR(hardcode_direct, $1)=unsupported + fi + ;; + + aix[[4-9]]*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to AIX nm, but means don't demangle with GNU nm + # Also, AIX nm treats weak defined symbols like other global + # defined symbols, whereas GNU nm marks them as "W". + if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then + _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + else + _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + fi + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*) + for ld_flag in $LDFLAGS; do + if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then + aix_use_runtimelinking=yes + break + fi + done + ;; + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + _LT_TAGVAR(archive_cmds, $1)='' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(file_list_spec, $1)='${wl}-f,' + + if test "$GCC" = yes; then + case $host_os in aix4.[[012]]|aix4.[[012]].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && + strings "$collect2name" | $GREP resolve_lib_name >/dev/null + then + # We have reworked collect2 + : + else + # We have old collect2 + _LT_TAGVAR(hardcode_direct, $1)=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)= + fi + ;; + esac + shared_flag='-shared' + if test "$aix_use_runtimelinking" = yes; then + shared_flag="$shared_flag "'${wl}-G' + fi + _LT_TAGVAR(link_all_deplibs, $1)=no + else + # not using gcc + if test "$host_cpu" = ia64; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='${wl}-G' + else + shared_flag='${wl}-bM:SRE' + fi + fi + fi + + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall' + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to export. + _LT_TAGVAR(always_export_symbols, $1)=yes + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + _LT_TAGVAR(allow_undefined_flag, $1)='-berok' + # Determine the default libpath from the value encoded in an + # empty executable. + _LT_SYS_MODULE_PATH_AIX([$1]) + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' + _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs" + _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an + # empty executable. + _LT_SYS_MODULE_PATH_AIX([$1]) + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' + _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' + if test "$with_gnu_ld" = yes; then + # We only use this code for GNU lds that support --whole-archive. + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive' + else + # Exported symbols can be pulled into shared objects from archives + _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience' + fi + _LT_TAGVAR(archive_cmds_need_lc, $1)=yes + # This is similar to how AIX traditionally builds its shared libraries. + _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + fi + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='' + ;; + m68k) + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_minus_L, $1)=yes + ;; + esac + ;; + + bsdi[[45]]*) + _LT_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic + ;; + + cygwin* | mingw* | pw32* | cegcc*) + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + case $cc_basename in + cl*) + # Native MSVC + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(always_export_symbols, $1)=yes + _LT_TAGVAR(file_list_spec, $1)='@' + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=".dll" + # FIXME: Setting linknames here is a bad hack. + _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames=' + _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + sed -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp; + else + sed -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp; + fi~ + $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ + linknames=' + # The linker will not automatically build a static lib if we build a DLL. + # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + _LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1,DATA/'\'' | $SED -e '\''/^[[AITW]][[ ]]/s/.*[[ ]]//'\'' | sort | uniq > $export_symbols' + # Don't use ranlib + _LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib' + _LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~ + lt_tool_outputfile="@TOOL_OUTPUT@"~ + case $lt_outputfile in + *.exe|*.EXE) ;; + *) + lt_outputfile="$lt_outputfile.exe" + lt_tool_outputfile="$lt_tool_outputfile.exe" + ;; + esac~ + if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then + $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; + $RM "$lt_outputfile.manifest"; + fi' + ;; + *) + # Assume MSVC wrapper + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=".dll" + # FIXME: Setting linknames here is a bad hack. + _LT_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames=' + # The linker will automatically build a .lib file if we build a DLL. + _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' + # FIXME: Should let the user specify the lib program. + _LT_TAGVAR(old_archive_cmds, $1)='lib -OUT:$oldlib$oldobjs$old_deplibs' + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + ;; + esac + ;; + + darwin* | rhapsody*) + _LT_DARWIN_LINKER_FEATURES($1) + ;; + + dgux*) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor + # support. Future versions do this automatically, but an explicit c++rt0.o + # does not break anything, and helps significantly (at the cost of a little + # extra space). + freebsd2.2*) + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + # Unfortunately, older versions of FreeBSD 2 do not have this feature. + freebsd2.*) + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + # FreeBSD 3 and greater uses gcc -shared to do shared libraries. + freebsd* | dragonfly*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + hpux9*) + if test "$GCC" = yes; then + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + else + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + fi + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(hardcode_direct, $1)=yes + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + ;; + + hpux10*) + if test "$GCC" = yes && test "$with_gnu_ld" = no; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' + fi + if test "$with_gnu_ld" = no; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + _LT_TAGVAR(hardcode_minus_L, $1)=yes + fi + ;; + + hpux11*) + if test "$GCC" = yes && test "$with_gnu_ld" = no; then + case $host_cpu in + hppa*64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + else + case $host_cpu in + hppa*64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + m4_if($1, [], [ + # Older versions of the 11.00 compiler do not understand -b yet + # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does) + _LT_LINKER_OPTION([if $CC understands -b], + _LT_TAGVAR(lt_cv_prog_compiler__b, $1), [-b], + [_LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'], + [_LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'])], + [_LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags']) + ;; + esac + fi + if test "$with_gnu_ld" = no; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + case $host_cpu in + hppa*64*|ia64*) + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + *) + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + _LT_TAGVAR(hardcode_minus_L, $1)=yes + ;; + esac + fi + ;; + + irix5* | irix6* | nonstopux*) + if test "$GCC" = yes; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + # Try to use the -exported_symbol ld option, if it does not + # work, assume that -exports_file does not work either and + # implicitly export all symbols. + # This should be the same for all languages, so no per-tag cache variable. + AC_CACHE_CHECK([whether the $host_os linker accepts -exported_symbol], + [lt_cv_irix_exported_symbol], + [save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null" + AC_LINK_IFELSE( + [AC_LANG_SOURCE( + [AC_LANG_CASE([C], [[int foo (void) { return 0; }]], + [C++], [[int foo (void) { return 0; }]], + [Fortran 77], [[ + subroutine foo + end]], + [Fortran], [[ + subroutine foo + end]])])], + [lt_cv_irix_exported_symbol=yes], + [lt_cv_irix_exported_symbol=no]) + LDFLAGS="$save_LDFLAGS"]) + if test "$lt_cv_irix_exported_symbol" = yes; then + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib' + fi + else + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib' + fi + _LT_TAGVAR(archive_cmds_need_lc, $1)='no' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(inherit_rpath, $1)=yes + _LT_TAGVAR(link_all_deplibs, $1)=yes + ;; + + netbsd* | netbsdelf*-gnu) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out + else + _LT_TAGVAR(archive_cmds, $1)='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF + fi + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + newsos6) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + *nto* | *qnx*) + ;; + + openbsd*) + if test -f /usr/libexec/ld.so; then + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + else + case $host_os in + openbsd[[01]].* | openbsd2.[[0-7]] | openbsd2.[[0-7]].*) + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + ;; + esac + fi + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + os2*) + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~echo DATA >> $output_objdir/$libname.def~echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' + _LT_TAGVAR(old_archive_from_new_cmds, $1)='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' + ;; + + osf3*) + if test "$GCC" = yes; then + _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' + fi + _LT_TAGVAR(archive_cmds_need_lc, $1)='no' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + ;; + + osf4* | osf5*) # as osf3* with the addition of -msym flag + if test "$GCC" = yes; then + _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $pic_flag $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + else + _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~ + $CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp' + + # Both c and cxx compiler support -rpath directly + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' + fi + _LT_TAGVAR(archive_cmds_need_lc, $1)='no' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + ;; + + solaris*) + _LT_TAGVAR(no_undefined_flag, $1)=' -z defs' + if test "$GCC" = yes; then + wlarc='${wl}' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' + else + case `$CC -V 2>&1` in + *"Compilers 5.0"*) + wlarc='' + _LT_TAGVAR(archive_cmds, $1)='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp' + ;; + *) + wlarc='${wl}' + _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' + ;; + esac + fi + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + case $host_os in + solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; + *) + # The compiler driver will combine and reorder linker options, + # but understands `-z linker_flag'. GCC discards it without `$wl', + # but is careful enough not to reorder. + # Supported since Solaris 2.6 (maybe 2.5.1?) + if test "$GCC" = yes; then + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' + else + _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' + fi + ;; + esac + _LT_TAGVAR(link_all_deplibs, $1)=yes + ;; + + sunos4*) + if test "x$host_vendor" = xsequent; then + # Use $CC to link under sequent, because it throws in some extra .o + # files that make .init and .fini sections work. + _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' + fi + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + sysv4) + case $host_vendor in + sni) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_direct, $1)=yes # is this really true??? + ;; + siemens) + ## LD is ld it makes a PLAMLIB + ## CC just makes a GrossModule. + _LT_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(reload_cmds, $1)='$CC -r -o $output$reload_objs' + _LT_TAGVAR(hardcode_direct, $1)=no + ;; + motorola) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_direct, $1)=no #Motorola manual says yes, but my tests say they lie + ;; + esac + runpath_var='LD_RUN_PATH' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + sysv4.3*) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(export_dynamic_flag_spec, $1)='-Bexport' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + runpath_var=LD_RUN_PATH + hardcode_runpath_var=yes + _LT_TAGVAR(ld_shlibs, $1)=yes + fi + ;; + + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*) + _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + runpath_var='LD_RUN_PATH' + + if test "$GCC" = yes; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + sysv5* | sco3.2v5* | sco5v6*) + # Note: We can NOT use -z defs as we might desire, because we do not + # link with -lc, and that would cause any symbols used from libc to + # always be unresolved, which means just about no library would + # ever link correctly. If we're not using GNU ld we use -z text + # though, which does catch some bad symbols but isn't as heavy-handed + # as -z defs. + _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' + _LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs' + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport' + runpath_var='LD_RUN_PATH' + + if test "$GCC" = yes; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + uts4*) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + *) + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + + if test x$host_vendor = xsni; then + case $host in + sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Blargedynsym' + ;; + esac + fi + fi +]) +AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)]) +test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no + +_LT_TAGVAR(with_gnu_ld, $1)=$with_gnu_ld + +_LT_DECL([], [libext], [0], [Old archive suffix (normally "a")])dnl +_LT_DECL([], [shrext_cmds], [1], [Shared library suffix (normally ".so")])dnl +_LT_DECL([], [extract_expsyms_cmds], [2], + [The commands to extract the exported symbol list from a shared archive]) + +# +# Do we need to explicitly link libc? +# +case "x$_LT_TAGVAR(archive_cmds_need_lc, $1)" in +x|xyes) + # Assume -lc should be added + _LT_TAGVAR(archive_cmds_need_lc, $1)=yes + + if test "$enable_shared" = yes && test "$GCC" = yes; then + case $_LT_TAGVAR(archive_cmds, $1) in + *'~'*) + # FIXME: we may have to deal with multi-command sequences. + ;; + '$CC '*) + # Test whether the compiler implicitly links with -lc since on some + # systems, -lgcc has to come before -lc. If gcc already passes -lc + # to ld, don't add -lc before -lgcc. + AC_CACHE_CHECK([whether -lc should be explicitly linked in], + [lt_cv_]_LT_TAGVAR(archive_cmds_need_lc, $1), + [$RM conftest* + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + if AC_TRY_EVAL(ac_compile) 2>conftest.err; then + soname=conftest + lib=conftest + libobjs=conftest.$ac_objext + deplibs= + wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) + pic_flag=$_LT_TAGVAR(lt_prog_compiler_pic, $1) + compiler_flags=-v + linker_flags=-v + verstring= + output_objdir=. + libname=conftest + lt_save_allow_undefined_flag=$_LT_TAGVAR(allow_undefined_flag, $1) + _LT_TAGVAR(allow_undefined_flag, $1)= + if AC_TRY_EVAL(_LT_TAGVAR(archive_cmds, $1) 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) + then + lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=no + else + lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=yes + fi + _LT_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag + else + cat conftest.err 1>&5 + fi + $RM conftest* + ]) + _LT_TAGVAR(archive_cmds_need_lc, $1)=$lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1) + ;; + esac + fi + ;; +esac + +_LT_TAGDECL([build_libtool_need_lc], [archive_cmds_need_lc], [0], + [Whether or not to add -lc for building shared libraries]) +_LT_TAGDECL([allow_libtool_libs_with_static_runtimes], + [enable_shared_with_static_runtimes], [0], + [Whether or not to disallow shared libs when runtime libs are static]) +_LT_TAGDECL([], [export_dynamic_flag_spec], [1], + [Compiler flag to allow reflexive dlopens]) +_LT_TAGDECL([], [whole_archive_flag_spec], [1], + [Compiler flag to generate shared objects directly from archives]) +_LT_TAGDECL([], [compiler_needs_object], [1], + [Whether the compiler copes with passing no objects directly]) +_LT_TAGDECL([], [old_archive_from_new_cmds], [2], + [Create an old-style archive from a shared archive]) +_LT_TAGDECL([], [old_archive_from_expsyms_cmds], [2], + [Create a temporary old-style archive to link instead of a shared archive]) +_LT_TAGDECL([], [archive_cmds], [2], [Commands used to build a shared archive]) +_LT_TAGDECL([], [archive_expsym_cmds], [2]) +_LT_TAGDECL([], [module_cmds], [2], + [Commands used to build a loadable module if different from building + a shared archive.]) +_LT_TAGDECL([], [module_expsym_cmds], [2]) +_LT_TAGDECL([], [with_gnu_ld], [1], + [Whether we are building with GNU ld or not]) +_LT_TAGDECL([], [allow_undefined_flag], [1], + [Flag that allows shared libraries with undefined symbols to be built]) +_LT_TAGDECL([], [no_undefined_flag], [1], + [Flag that enforces no undefined symbols]) +_LT_TAGDECL([], [hardcode_libdir_flag_spec], [1], + [Flag to hardcode $libdir into a binary during linking. + This must work even if $libdir does not exist]) +_LT_TAGDECL([], [hardcode_libdir_separator], [1], + [Whether we need a single "-rpath" flag with a separated argument]) +_LT_TAGDECL([], [hardcode_direct], [0], + [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes + DIR into the resulting binary]) +_LT_TAGDECL([], [hardcode_direct_absolute], [0], + [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes + DIR into the resulting binary and the resulting library dependency is + "absolute", i.e impossible to change by setting ${shlibpath_var} if the + library is relocated]) +_LT_TAGDECL([], [hardcode_minus_L], [0], + [Set to "yes" if using the -LDIR flag during linking hardcodes DIR + into the resulting binary]) +_LT_TAGDECL([], [hardcode_shlibpath_var], [0], + [Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR + into the resulting binary]) +_LT_TAGDECL([], [hardcode_automatic], [0], + [Set to "yes" if building a shared library automatically hardcodes DIR + into the library and all subsequent libraries and executables linked + against it]) +_LT_TAGDECL([], [inherit_rpath], [0], + [Set to yes if linker adds runtime paths of dependent libraries + to runtime path list]) +_LT_TAGDECL([], [link_all_deplibs], [0], + [Whether libtool must link a program against all its dependency libraries]) +_LT_TAGDECL([], [always_export_symbols], [0], + [Set to "yes" if exported symbols are required]) +_LT_TAGDECL([], [export_symbols_cmds], [2], + [The commands to list exported symbols]) +_LT_TAGDECL([], [exclude_expsyms], [1], + [Symbols that should not be listed in the preloaded symbols]) +_LT_TAGDECL([], [include_expsyms], [1], + [Symbols that must always be exported]) +_LT_TAGDECL([], [prelink_cmds], [2], + [Commands necessary for linking programs (against libraries) with templates]) +_LT_TAGDECL([], [postlink_cmds], [2], + [Commands necessary for finishing linking programs]) +_LT_TAGDECL([], [file_list_spec], [1], + [Specify filename containing input files]) +dnl FIXME: Not yet implemented +dnl _LT_TAGDECL([], [thread_safe_flag_spec], [1], +dnl [Compiler flag to generate thread safe objects]) +])# _LT_LINKER_SHLIBS + + +# _LT_LANG_C_CONFIG([TAG]) +# ------------------------ +# Ensure that the configuration variables for a C compiler are suitably +# defined. These variables are subsequently used by _LT_CONFIG to write +# the compiler configuration to `libtool'. +m4_defun([_LT_LANG_C_CONFIG], +[m4_require([_LT_DECL_EGREP])dnl +lt_save_CC="$CC" +AC_LANG_PUSH(C) + +# Source file extension for C test sources. +ac_ext=c + +# Object file extension for compiled C test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="int some_variable = 0;" + +# Code to be used in simple link tests +lt_simple_link_test_code='int main(){return(0);}' + +_LT_TAG_COMPILER +# Save the default compiler, since it gets overwritten when the other +# tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP. +compiler_DEFAULT=$CC + +# save warnings/boilerplate of simple test code +_LT_COMPILER_BOILERPLATE +_LT_LINKER_BOILERPLATE + +if test -n "$compiler"; then + _LT_COMPILER_NO_RTTI($1) + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_SYS_DYNAMIC_LINKER($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + LT_SYS_DLOPEN_SELF + _LT_CMD_STRIPLIB + + # Report which library types will actually be built + AC_MSG_CHECKING([if libtool supports shared libraries]) + AC_MSG_RESULT([$can_build_shared]) + + AC_MSG_CHECKING([whether to build shared libraries]) + test "$can_build_shared" = "no" && enable_shared=no + + # On AIX, shared libraries and static libraries use the same namespace, and + # are all built from PIC. + case $host_os in + aix3*) + test "$enable_shared" = yes && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + + aix[[4-9]]*) + if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then + test "$enable_shared" = yes && enable_static=no + fi + ;; + esac + AC_MSG_RESULT([$enable_shared]) + + AC_MSG_CHECKING([whether to build static libraries]) + # Make sure either enable_shared or enable_static is yes. + test "$enable_shared" = yes || enable_static=yes + AC_MSG_RESULT([$enable_static]) + + _LT_CONFIG($1) +fi +AC_LANG_POP +CC="$lt_save_CC" +])# _LT_LANG_C_CONFIG + + +# _LT_LANG_CXX_CONFIG([TAG]) +# -------------------------- +# Ensure that the configuration variables for a C++ compiler are suitably +# defined. These variables are subsequently used by _LT_CONFIG to write +# the compiler configuration to `libtool'. +m4_defun([_LT_LANG_CXX_CONFIG], +[m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_EGREP])dnl +m4_require([_LT_PATH_MANIFEST_TOOL])dnl +if test -n "$CXX" && ( test "X$CXX" != "Xno" && + ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) || + (test "X$CXX" != "Xg++"))) ; then + AC_PROG_CXXCPP +else + _lt_caught_CXX_error=yes +fi + +AC_LANG_PUSH(C++) +_LT_TAGVAR(archive_cmds_need_lc, $1)=no +_LT_TAGVAR(allow_undefined_flag, $1)= +_LT_TAGVAR(always_export_symbols, $1)=no +_LT_TAGVAR(archive_expsym_cmds, $1)= +_LT_TAGVAR(compiler_needs_object, $1)=no +_LT_TAGVAR(export_dynamic_flag_spec, $1)= +_LT_TAGVAR(hardcode_direct, $1)=no +_LT_TAGVAR(hardcode_direct_absolute, $1)=no +_LT_TAGVAR(hardcode_libdir_flag_spec, $1)= +_LT_TAGVAR(hardcode_libdir_separator, $1)= +_LT_TAGVAR(hardcode_minus_L, $1)=no +_LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported +_LT_TAGVAR(hardcode_automatic, $1)=no +_LT_TAGVAR(inherit_rpath, $1)=no +_LT_TAGVAR(module_cmds, $1)= +_LT_TAGVAR(module_expsym_cmds, $1)= +_LT_TAGVAR(link_all_deplibs, $1)=unknown +_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_TAGVAR(reload_flag, $1)=$reload_flag +_LT_TAGVAR(reload_cmds, $1)=$reload_cmds +_LT_TAGVAR(no_undefined_flag, $1)= +_LT_TAGVAR(whole_archive_flag_spec, $1)= +_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no + +# Source file extension for C++ test sources. +ac_ext=cpp + +# Object file extension for compiled C++ test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# No sense in running all these tests if we already determined that +# the CXX compiler isn't working. Some variables (like enable_shared) +# are currently assumed to apply to all compilers on this platform, +# and will be corrupted by setting them based on a non-working compiler. +if test "$_lt_caught_CXX_error" != yes; then + # Code to be used in simple compile tests + lt_simple_compile_test_code="int some_variable = 0;" + + # Code to be used in simple link tests + lt_simple_link_test_code='int main(int, char *[[]]) { return(0); }' + + # ltmain only uses $CC for tagged configurations so make sure $CC is set. + _LT_TAG_COMPILER + + # save warnings/boilerplate of simple test code + _LT_COMPILER_BOILERPLATE + _LT_LINKER_BOILERPLATE + + # Allow CC to be a program name with arguments. + lt_save_CC=$CC + lt_save_CFLAGS=$CFLAGS + lt_save_LD=$LD + lt_save_GCC=$GCC + GCC=$GXX + lt_save_with_gnu_ld=$with_gnu_ld + lt_save_path_LD=$lt_cv_path_LD + if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then + lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx + else + $as_unset lt_cv_prog_gnu_ld + fi + if test -n "${lt_cv_path_LDCXX+set}"; then + lt_cv_path_LD=$lt_cv_path_LDCXX + else + $as_unset lt_cv_path_LD + fi + test -z "${LDCXX+set}" || LD=$LDCXX + CC=${CXX-"c++"} + CFLAGS=$CXXFLAGS + compiler=$CC + _LT_TAGVAR(compiler, $1)=$CC + _LT_CC_BASENAME([$compiler]) + + if test -n "$compiler"; then + # We don't want -fno-exception when compiling C++ code, so set the + # no_builtin_flag separately + if test "$GXX" = yes; then + _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' + else + _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= + fi + + if test "$GXX" = yes; then + # Set up default GNU C++ configuration + + LT_PATH_LD + + # Check if GNU C++ uses GNU ld as the underlying linker, since the + # archiving commands below assume that GNU ld is being used. + if test "$with_gnu_ld" = yes; then + _LT_TAGVAR(archive_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + + # If archive_cmds runs LD, not CC, wlarc should be empty + # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to + # investigate it a little bit more. (MM) + wlarc='${wl}' + + # ancient GNU ld didn't support --whole-archive et. al. + if eval "`$CC -print-prog-name=ld` --help 2>&1" | + $GREP 'no-whole-archive' > /dev/null; then + _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + _LT_TAGVAR(whole_archive_flag_spec, $1)= + fi + else + with_gnu_ld=no + wlarc= + + # A generic and very simple default shared library creation + # command for GNU C++ for the case where it uses the native + # linker, instead of GNU ld. If possible, this setting should + # overridden to take advantage of the native linker features on + # the platform it is being used on. + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' + fi + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' + + else + GXX=no + with_gnu_ld=no + wlarc= + fi + + # PORTME: fill in a description of your system's C++ link characteristics + AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) + _LT_TAGVAR(ld_shlibs, $1)=yes + case $host_os in + aix3*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + aix[[4-9]]*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*) + for ld_flag in $LDFLAGS; do + case $ld_flag in + *-brtl*) + aix_use_runtimelinking=yes + break + ;; + esac + done + ;; + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + _LT_TAGVAR(archive_cmds, $1)='' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(file_list_spec, $1)='${wl}-f,' + + if test "$GXX" = yes; then + case $host_os in aix4.[[012]]|aix4.[[012]].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && + strings "$collect2name" | $GREP resolve_lib_name >/dev/null + then + # We have reworked collect2 + : + else + # We have old collect2 + _LT_TAGVAR(hardcode_direct, $1)=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)= + fi + esac + shared_flag='-shared' + if test "$aix_use_runtimelinking" = yes; then + shared_flag="$shared_flag "'${wl}-G' + fi + else + # not using gcc + if test "$host_cpu" = ia64; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='${wl}-G' + else + shared_flag='${wl}-bM:SRE' + fi + fi + fi + + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall' + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to + # export. + _LT_TAGVAR(always_export_symbols, $1)=yes + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + _LT_TAGVAR(allow_undefined_flag, $1)='-berok' + # Determine the default libpath from the value encoded in an empty + # executable. + _LT_SYS_MODULE_PATH_AIX([$1]) + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' + _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs" + _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an + # empty executable. + _LT_SYS_MODULE_PATH_AIX([$1]) + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' + _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' + if test "$with_gnu_ld" = yes; then + # We only use this code for GNU lds that support --whole-archive. + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive' + else + # Exported symbols can be pulled into shared objects from archives + _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience' + fi + _LT_TAGVAR(archive_cmds_need_lc, $1)=yes + # This is similar to how AIX traditionally builds its shared + # libraries. + _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + fi + fi + ;; + + beos*) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + # Joseph Beckenbach says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + chorus*) + case $cc_basename in + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + cygwin* | mingw* | pw32* | cegcc*) + case $GXX,$cc_basename in + ,cl* | no,cl*) + # Native MSVC + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(always_export_symbols, $1)=yes + _LT_TAGVAR(file_list_spec, $1)='@' + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=".dll" + # FIXME: Setting linknames here is a bad hack. + _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames=' + _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + $SED -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp; + else + $SED -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp; + fi~ + $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ + linknames=' + # The linker will not automatically build a static lib if we build a DLL. + # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + # Don't use ranlib + _LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib' + _LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~ + lt_tool_outputfile="@TOOL_OUTPUT@"~ + case $lt_outputfile in + *.exe|*.EXE) ;; + *) + lt_outputfile="$lt_outputfile.exe" + lt_tool_outputfile="$lt_tool_outputfile.exe" + ;; + esac~ + func_to_tool_file "$lt_outputfile"~ + if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then + $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; + $RM "$lt_outputfile.manifest"; + fi' + ;; + *) + # g++ + # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, + # as there is no search path for DLLs. + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-all-symbols' + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(always_export_symbols, $1)=no + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + + if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is; otherwise, prepend... + _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + darwin* | rhapsody*) + _LT_DARWIN_LINKER_FEATURES($1) + ;; + + dgux*) + case $cc_basename in + ec++*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + ghcx*) + # Green Hills C++ Compiler + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + freebsd2.*) + # C++ shared libraries reported to be fairly broken before + # switch to ELF + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + freebsd-elf*) + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + ;; + + freebsd* | dragonfly*) + # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF + # conventions + _LT_TAGVAR(ld_shlibs, $1)=yes + ;; + + haiku*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(link_all_deplibs, $1)=yes + ;; + + hpux9*) + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, + # but as the default + # location of the library. + + case $cc_basename in + CC*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + aCC*) + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' + ;; + *) + if test "$GXX" = yes; then + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -nostdlib $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + else + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + + hpux10*|hpux11*) + if test $with_gnu_ld = no; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + case $host_cpu in + hppa*64*|ia64*) + ;; + *) + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + ;; + esac + fi + case $host_cpu in + hppa*64*|ia64*) + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + *) + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, + # but as the default + # location of the library. + ;; + esac + + case $cc_basename in + CC*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + aCC*) + case $host_cpu in + hppa*64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + ia64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + esac + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' + ;; + *) + if test "$GXX" = yes; then + if test $with_gnu_ld = no; then + case $host_cpu in + hppa*64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + ia64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + esac + fi + else + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + + interix[[3-9]]*) + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. + # Instead, shared libraries are loaded at an image base (0x10000000 by + # default) and relocated if they conflict, which is a slow very memory + # consuming and fragmenting process. To avoid this, we pick a random, + # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link + # time. Moving up from 0x10000000 also allows more sbrk(2) space. + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + ;; + irix5* | irix6*) + case $cc_basename in + CC*) + # SGI C++ + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' + + # Archives containing C++ object files must be created using + # "CC -ar", where "CC" is the IRIX C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + _LT_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs' + ;; + *) + if test "$GXX" = yes; then + if test "$with_gnu_ld" = no; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` -o $lib' + fi + fi + _LT_TAGVAR(link_all_deplibs, $1)=yes + ;; + esac + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(inherit_rpath, $1)=yes + ;; + + linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) + case $cc_basename in + KCC*) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib' + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + + # Archives containing C++ object files must be created using + # "CC -Bstatic", where "CC" is the KAI C++ compiler. + _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' + ;; + icpc* | ecpc* ) + # Intel C++ + with_gnu_ld=yes + # version 8.0 and above of icpc choke on multiply defined symbols + # if we add $predep_objects and $postdep_objects, however 7.1 and + # earlier do not add the objects themselves. + case `$CC -V 2>&1` in + *"Version 7."*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + ;; + *) # Version 8.0 or newer + tmp_idyn= + case $host_cpu in + ia64*) tmp_idyn=' -i_dynamic';; + esac + _LT_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + ;; + esac + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive' + ;; + pgCC* | pgcpp*) + # Portland Group C++ compiler + case `$CC -V` in + *pgCC\ [[1-5]].* | *pgcpp\ [[1-5]].*) + _LT_TAGVAR(prelink_cmds, $1)='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~ + compile_command="$compile_command `find $tpldir -name \*.o | sort | $NL2SP`"' + _LT_TAGVAR(old_archive_cmds, $1)='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~ + $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | sort | $NL2SP`~ + $RANLIB $oldlib' + _LT_TAGVAR(archive_cmds, $1)='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ + $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ + $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' + ;; + *) # Version 6 and above use weak symbols + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' + ;; + esac + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + ;; + cxx*) + # Compaq C++ + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib ${wl}-retain-symbols-file $wl$export_symbols' + + runpath_var=LD_RUN_PATH + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "X$list" | $Xsed' + ;; + xl* | mpixl* | bgxl*) + # IBM XL 8.0 on PPC, with GNU ld + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + _LT_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + if test "x$supports_anon_versioning" = xyes; then + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' + fi + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C++ 5.9 + _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs' + _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file ${wl}$export_symbols' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + _LT_TAGVAR(compiler_needs_object, $1)=yes + + # Not sure whether something based on + # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 + # would be better. + output_verbose_link_cmd='func_echo_all' + + # Archives containing C++ object files must be created using + # "CC -xar", where "CC" is the Sun C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' + ;; + esac + ;; + esac + ;; + + lynxos*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + m88k*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + mvs*) + case $cc_basename in + cxx*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags' + wlarc= + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + fi + # Workaround some broken pre-1.5 toolchains + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"' + ;; + + *nto* | *qnx*) + _LT_TAGVAR(ld_shlibs, $1)=yes + ;; + + openbsd2*) + # C++ shared libraries are fairly broken + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + openbsd*) + if test -f /usr/libexec/ld.so; then + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + fi + output_verbose_link_cmd=func_echo_all + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + osf3* | osf4* | osf5*) + case $cc_basename in + KCC*) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + # Archives containing C++ object files must be created using + # the KAI C++ compiler. + case $host in + osf3*) _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;; + *) _LT_TAGVAR(old_archive_cmds, $1)='$CC -o $oldlib $oldobjs' ;; + esac + ;; + RCC*) + # Rational C++ 2.4.1 + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + cxx*) + case $host in + osf3*) + _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && func_echo_all "${wl}-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + ;; + *) + _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~ + echo "-hidden">> $lib.exp~ + $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname ${wl}-input ${wl}$lib.exp `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~ + $RM $lib.exp' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' + ;; + esac + + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' + ;; + *) + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + case $host in + osf3*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + ;; + esac + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' + + else + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + + psos*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + sunos4*) + case $cc_basename in + CC*) + # Sun C++ 4.x + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + lcc*) + # Lucid + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + solaris*) + case $cc_basename in + CC* | sunCC*) + # Sun C++ 4.2, 5.x and Centerline C++ + _LT_TAGVAR(archive_cmds_need_lc,$1)=yes + _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs' + _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -G${allow_undefined_flag} ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + case $host_os in + solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; + *) + # The compiler driver will combine and reorder linker options, + # but understands `-z linker_flag'. + # Supported since Solaris 2.6 (maybe 2.5.1?) + _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' + ;; + esac + _LT_TAGVAR(link_all_deplibs, $1)=yes + + output_verbose_link_cmd='func_echo_all' + + # Archives containing C++ object files must be created using + # "CC -xar", where "CC" is the Sun C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' + ;; + gcx*) + # Green Hills C++ Compiler + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + + # The C++ compiler must be used to create the archive. + _LT_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs' + ;; + *) + # GNU C++ compiler with Solaris linker + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-z ${wl}defs' + if $CC --version | $GREP -v '^2\.7' > /dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -shared $pic_flag -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' + else + # g++ 2.7 appears to require `-G' NOT `-shared' on this + # platform. + _LT_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' + fi + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $wl$libdir' + case $host_os in + solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; + *) + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' + ;; + esac + fi + ;; + esac + ;; + + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*) + _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + runpath_var='LD_RUN_PATH' + + case $cc_basename in + CC*) + _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + ;; + + sysv5* | sco3.2v5* | sco5v6*) + # Note: We can NOT use -z defs as we might desire, because we do not + # link with -lc, and that would cause any symbols used from libc to + # always be unresolved, which means just about no library would + # ever link correctly. If we're not using GNU ld we use -z text + # though, which does catch some bad symbols but isn't as heavy-handed + # as -z defs. + _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' + _LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs' + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport' + runpath_var='LD_RUN_PATH' + + case $cc_basename in + CC*) + _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(old_archive_cmds, $1)='$CC -Tprelink_objects $oldobjs~ + '"$_LT_TAGVAR(old_archive_cmds, $1)" + _LT_TAGVAR(reload_cmds, $1)='$CC -Tprelink_objects $reload_objs~ + '"$_LT_TAGVAR(reload_cmds, $1)" + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + ;; + + tandem*) + case $cc_basename in + NCC*) + # NonStop-UX NCC 3.20 + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + vxworks*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + + AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)]) + test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no + + _LT_TAGVAR(GCC, $1)="$GXX" + _LT_TAGVAR(LD, $1)="$LD" + + ## CAVEAT EMPTOR: + ## There is no encapsulation within the following macros, do not change + ## the running order or otherwise move them around unless you know exactly + ## what you are doing... + _LT_SYS_HIDDEN_LIBDEPS($1) + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_SYS_DYNAMIC_LINKER($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + + _LT_CONFIG($1) + fi # test -n "$compiler" + + CC=$lt_save_CC + CFLAGS=$lt_save_CFLAGS + LDCXX=$LD + LD=$lt_save_LD + GCC=$lt_save_GCC + with_gnu_ld=$lt_save_with_gnu_ld + lt_cv_path_LDCXX=$lt_cv_path_LD + lt_cv_path_LD=$lt_save_path_LD + lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld + lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld +fi # test "$_lt_caught_CXX_error" != yes + +AC_LANG_POP +])# _LT_LANG_CXX_CONFIG + + +# _LT_FUNC_STRIPNAME_CNF +# ---------------------- +# func_stripname_cnf prefix suffix name +# strip PREFIX and SUFFIX off of NAME. +# PREFIX and SUFFIX must not contain globbing or regex special +# characters, hashes, percent signs, but SUFFIX may contain a leading +# dot (in which case that matches only a dot). +# +# This function is identical to the (non-XSI) version of func_stripname, +# except this one can be used by m4 code that may be executed by configure, +# rather than the libtool script. +m4_defun([_LT_FUNC_STRIPNAME_CNF],[dnl +AC_REQUIRE([_LT_DECL_SED]) +AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH]) +func_stripname_cnf () +{ + case ${2} in + .*) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;; + *) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%${2}\$%%"`;; + esac +} # func_stripname_cnf +])# _LT_FUNC_STRIPNAME_CNF + +# _LT_SYS_HIDDEN_LIBDEPS([TAGNAME]) +# --------------------------------- +# Figure out "hidden" library dependencies from verbose +# compiler output when linking a shared library. +# Parse the compiler output and extract the necessary +# objects, libraries and library flags. +m4_defun([_LT_SYS_HIDDEN_LIBDEPS], +[m4_require([_LT_FILEUTILS_DEFAULTS])dnl +AC_REQUIRE([_LT_FUNC_STRIPNAME_CNF])dnl +# Dependencies to place before and after the object being linked: +_LT_TAGVAR(predep_objects, $1)= +_LT_TAGVAR(postdep_objects, $1)= +_LT_TAGVAR(predeps, $1)= +_LT_TAGVAR(postdeps, $1)= +_LT_TAGVAR(compiler_lib_search_path, $1)= + +dnl we can't use the lt_simple_compile_test_code here, +dnl because it contains code intended for an executable, +dnl not a library. It's possible we should let each +dnl tag define a new lt_????_link_test_code variable, +dnl but it's only used here... +m4_if([$1], [], [cat > conftest.$ac_ext <<_LT_EOF +int a; +void foo (void) { a = 0; } +_LT_EOF +], [$1], [CXX], [cat > conftest.$ac_ext <<_LT_EOF +class Foo +{ +public: + Foo (void) { a = 0; } +private: + int a; +}; +_LT_EOF +], [$1], [F77], [cat > conftest.$ac_ext <<_LT_EOF + subroutine foo + implicit none + integer*4 a + a=0 + return + end +_LT_EOF +], [$1], [FC], [cat > conftest.$ac_ext <<_LT_EOF + subroutine foo + implicit none + integer a + a=0 + return + end +_LT_EOF +], [$1], [GCJ], [cat > conftest.$ac_ext <<_LT_EOF +public class foo { + private int a; + public void bar (void) { + a = 0; + } +}; +_LT_EOF +], [$1], [GO], [cat > conftest.$ac_ext <<_LT_EOF +package foo +func foo() { +} +_LT_EOF +]) + +_lt_libdeps_save_CFLAGS=$CFLAGS +case "$CC $CFLAGS " in #( +*\ -flto*\ *) CFLAGS="$CFLAGS -fno-lto" ;; +*\ -fwhopr*\ *) CFLAGS="$CFLAGS -fno-whopr" ;; +*\ -fuse-linker-plugin*\ *) CFLAGS="$CFLAGS -fno-use-linker-plugin" ;; +esac + +dnl Parse the compiler output and extract the necessary +dnl objects, libraries and library flags. +if AC_TRY_EVAL(ac_compile); then + # Parse the compiler output and extract the necessary + # objects, libraries and library flags. + + # Sentinel used to keep track of whether or not we are before + # the conftest object file. + pre_test_object_deps_done=no + + for p in `eval "$output_verbose_link_cmd"`; do + case ${prev}${p} in + + -L* | -R* | -l*) + # Some compilers place space between "-{L,R}" and the path. + # Remove the space. + if test $p = "-L" || + test $p = "-R"; then + prev=$p + continue + fi + + # Expand the sysroot to ease extracting the directories later. + if test -z "$prev"; then + case $p in + -L*) func_stripname_cnf '-L' '' "$p"; prev=-L; p=$func_stripname_result ;; + -R*) func_stripname_cnf '-R' '' "$p"; prev=-R; p=$func_stripname_result ;; + -l*) func_stripname_cnf '-l' '' "$p"; prev=-l; p=$func_stripname_result ;; + esac + fi + case $p in + =*) func_stripname_cnf '=' '' "$p"; p=$lt_sysroot$func_stripname_result ;; + esac + if test "$pre_test_object_deps_done" = no; then + case ${prev} in + -L | -R) + # Internal compiler library paths should come after those + # provided the user. The postdeps already come after the + # user supplied libs so there is no need to process them. + if test -z "$_LT_TAGVAR(compiler_lib_search_path, $1)"; then + _LT_TAGVAR(compiler_lib_search_path, $1)="${prev}${p}" + else + _LT_TAGVAR(compiler_lib_search_path, $1)="${_LT_TAGVAR(compiler_lib_search_path, $1)} ${prev}${p}" + fi + ;; + # The "-l" case would never come before the object being + # linked, so don't bother handling this case. + esac + else + if test -z "$_LT_TAGVAR(postdeps, $1)"; then + _LT_TAGVAR(postdeps, $1)="${prev}${p}" + else + _LT_TAGVAR(postdeps, $1)="${_LT_TAGVAR(postdeps, $1)} ${prev}${p}" + fi + fi + prev= + ;; + + *.lto.$objext) ;; # Ignore GCC LTO objects + *.$objext) + # This assumes that the test object file only shows up + # once in the compiler output. + if test "$p" = "conftest.$objext"; then + pre_test_object_deps_done=yes + continue + fi + + if test "$pre_test_object_deps_done" = no; then + if test -z "$_LT_TAGVAR(predep_objects, $1)"; then + _LT_TAGVAR(predep_objects, $1)="$p" + else + _LT_TAGVAR(predep_objects, $1)="$_LT_TAGVAR(predep_objects, $1) $p" + fi + else + if test -z "$_LT_TAGVAR(postdep_objects, $1)"; then + _LT_TAGVAR(postdep_objects, $1)="$p" + else + _LT_TAGVAR(postdep_objects, $1)="$_LT_TAGVAR(postdep_objects, $1) $p" + fi + fi + ;; + + *) ;; # Ignore the rest. + + esac + done + + # Clean up. + rm -f a.out a.exe +else + echo "libtool.m4: error: problem compiling $1 test program" +fi + +$RM -f confest.$objext +CFLAGS=$_lt_libdeps_save_CFLAGS + +# PORTME: override above test on systems where it is broken +m4_if([$1], [CXX], +[case $host_os in +interix[[3-9]]*) + # Interix 3.5 installs completely hosed .la files for C++, so rather than + # hack all around it, let's just trust "g++" to DTRT. + _LT_TAGVAR(predep_objects,$1)= + _LT_TAGVAR(postdep_objects,$1)= + _LT_TAGVAR(postdeps,$1)= + ;; + +linux*) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C++ 5.9 + + # The more standards-conforming stlport4 library is + # incompatible with the Cstd library. Avoid specifying + # it if it's in CXXFLAGS. Ignore libCrun as + # -library=stlport4 depends on it. + case " $CXX $CXXFLAGS " in + *" -library=stlport4 "*) + solaris_use_stlport4=yes + ;; + esac + + if test "$solaris_use_stlport4" != yes; then + _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun' + fi + ;; + esac + ;; + +solaris*) + case $cc_basename in + CC* | sunCC*) + # The more standards-conforming stlport4 library is + # incompatible with the Cstd library. Avoid specifying + # it if it's in CXXFLAGS. Ignore libCrun as + # -library=stlport4 depends on it. + case " $CXX $CXXFLAGS " in + *" -library=stlport4 "*) + solaris_use_stlport4=yes + ;; + esac + + # Adding this requires a known-good setup of shared libraries for + # Sun compiler versions before 5.6, else PIC objects from an old + # archive will be linked into the output, leading to subtle bugs. + if test "$solaris_use_stlport4" != yes; then + _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun' + fi + ;; + esac + ;; +esac +]) + +case " $_LT_TAGVAR(postdeps, $1) " in +*" -lc "*) _LT_TAGVAR(archive_cmds_need_lc, $1)=no ;; +esac + _LT_TAGVAR(compiler_lib_search_dirs, $1)= +if test -n "${_LT_TAGVAR(compiler_lib_search_path, $1)}"; then + _LT_TAGVAR(compiler_lib_search_dirs, $1)=`echo " ${_LT_TAGVAR(compiler_lib_search_path, $1)}" | ${SED} -e 's! -L! !g' -e 's!^ !!'` +fi +_LT_TAGDECL([], [compiler_lib_search_dirs], [1], + [The directories searched by this compiler when creating a shared library]) +_LT_TAGDECL([], [predep_objects], [1], + [Dependencies to place before and after the objects being linked to + create a shared library]) +_LT_TAGDECL([], [postdep_objects], [1]) +_LT_TAGDECL([], [predeps], [1]) +_LT_TAGDECL([], [postdeps], [1]) +_LT_TAGDECL([], [compiler_lib_search_path], [1], + [The library search path used internally by the compiler when linking + a shared library]) +])# _LT_SYS_HIDDEN_LIBDEPS + + +# _LT_LANG_F77_CONFIG([TAG]) +# -------------------------- +# Ensure that the configuration variables for a Fortran 77 compiler are +# suitably defined. These variables are subsequently used by _LT_CONFIG +# to write the compiler configuration to `libtool'. +m4_defun([_LT_LANG_F77_CONFIG], +[AC_LANG_PUSH(Fortran 77) +if test -z "$F77" || test "X$F77" = "Xno"; then + _lt_disable_F77=yes +fi + +_LT_TAGVAR(archive_cmds_need_lc, $1)=no +_LT_TAGVAR(allow_undefined_flag, $1)= +_LT_TAGVAR(always_export_symbols, $1)=no +_LT_TAGVAR(archive_expsym_cmds, $1)= +_LT_TAGVAR(export_dynamic_flag_spec, $1)= +_LT_TAGVAR(hardcode_direct, $1)=no +_LT_TAGVAR(hardcode_direct_absolute, $1)=no +_LT_TAGVAR(hardcode_libdir_flag_spec, $1)= +_LT_TAGVAR(hardcode_libdir_separator, $1)= +_LT_TAGVAR(hardcode_minus_L, $1)=no +_LT_TAGVAR(hardcode_automatic, $1)=no +_LT_TAGVAR(inherit_rpath, $1)=no +_LT_TAGVAR(module_cmds, $1)= +_LT_TAGVAR(module_expsym_cmds, $1)= +_LT_TAGVAR(link_all_deplibs, $1)=unknown +_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_TAGVAR(reload_flag, $1)=$reload_flag +_LT_TAGVAR(reload_cmds, $1)=$reload_cmds +_LT_TAGVAR(no_undefined_flag, $1)= +_LT_TAGVAR(whole_archive_flag_spec, $1)= +_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no + +# Source file extension for f77 test sources. +ac_ext=f + +# Object file extension for compiled f77 test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# No sense in running all these tests if we already determined that +# the F77 compiler isn't working. Some variables (like enable_shared) +# are currently assumed to apply to all compilers on this platform, +# and will be corrupted by setting them based on a non-working compiler. +if test "$_lt_disable_F77" != yes; then + # Code to be used in simple compile tests + lt_simple_compile_test_code="\ + subroutine t + return + end +" + + # Code to be used in simple link tests + lt_simple_link_test_code="\ + program t + end +" + + # ltmain only uses $CC for tagged configurations so make sure $CC is set. + _LT_TAG_COMPILER + + # save warnings/boilerplate of simple test code + _LT_COMPILER_BOILERPLATE + _LT_LINKER_BOILERPLATE + + # Allow CC to be a program name with arguments. + lt_save_CC="$CC" + lt_save_GCC=$GCC + lt_save_CFLAGS=$CFLAGS + CC=${F77-"f77"} + CFLAGS=$FFLAGS + compiler=$CC + _LT_TAGVAR(compiler, $1)=$CC + _LT_CC_BASENAME([$compiler]) + GCC=$G77 + if test -n "$compiler"; then + AC_MSG_CHECKING([if libtool supports shared libraries]) + AC_MSG_RESULT([$can_build_shared]) + + AC_MSG_CHECKING([whether to build shared libraries]) + test "$can_build_shared" = "no" && enable_shared=no + + # On AIX, shared libraries and static libraries use the same namespace, and + # are all built from PIC. + case $host_os in + aix3*) + test "$enable_shared" = yes && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + aix[[4-9]]*) + if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then + test "$enable_shared" = yes && enable_static=no + fi + ;; + esac + AC_MSG_RESULT([$enable_shared]) + + AC_MSG_CHECKING([whether to build static libraries]) + # Make sure either enable_shared or enable_static is yes. + test "$enable_shared" = yes || enable_static=yes + AC_MSG_RESULT([$enable_static]) + + _LT_TAGVAR(GCC, $1)="$G77" + _LT_TAGVAR(LD, $1)="$LD" + + ## CAVEAT EMPTOR: + ## There is no encapsulation within the following macros, do not change + ## the running order or otherwise move them around unless you know exactly + ## what you are doing... + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_SYS_DYNAMIC_LINKER($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + + _LT_CONFIG($1) + fi # test -n "$compiler" + + GCC=$lt_save_GCC + CC="$lt_save_CC" + CFLAGS="$lt_save_CFLAGS" +fi # test "$_lt_disable_F77" != yes + +AC_LANG_POP +])# _LT_LANG_F77_CONFIG + + +# _LT_LANG_FC_CONFIG([TAG]) +# ------------------------- +# Ensure that the configuration variables for a Fortran compiler are +# suitably defined. These variables are subsequently used by _LT_CONFIG +# to write the compiler configuration to `libtool'. +m4_defun([_LT_LANG_FC_CONFIG], +[AC_LANG_PUSH(Fortran) + +if test -z "$FC" || test "X$FC" = "Xno"; then + _lt_disable_FC=yes +fi + +_LT_TAGVAR(archive_cmds_need_lc, $1)=no +_LT_TAGVAR(allow_undefined_flag, $1)= +_LT_TAGVAR(always_export_symbols, $1)=no +_LT_TAGVAR(archive_expsym_cmds, $1)= +_LT_TAGVAR(export_dynamic_flag_spec, $1)= +_LT_TAGVAR(hardcode_direct, $1)=no +_LT_TAGVAR(hardcode_direct_absolute, $1)=no +_LT_TAGVAR(hardcode_libdir_flag_spec, $1)= +_LT_TAGVAR(hardcode_libdir_separator, $1)= +_LT_TAGVAR(hardcode_minus_L, $1)=no +_LT_TAGVAR(hardcode_automatic, $1)=no +_LT_TAGVAR(inherit_rpath, $1)=no +_LT_TAGVAR(module_cmds, $1)= +_LT_TAGVAR(module_expsym_cmds, $1)= +_LT_TAGVAR(link_all_deplibs, $1)=unknown +_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_TAGVAR(reload_flag, $1)=$reload_flag +_LT_TAGVAR(reload_cmds, $1)=$reload_cmds +_LT_TAGVAR(no_undefined_flag, $1)= +_LT_TAGVAR(whole_archive_flag_spec, $1)= +_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no + +# Source file extension for fc test sources. +ac_ext=${ac_fc_srcext-f} + +# Object file extension for compiled fc test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# No sense in running all these tests if we already determined that +# the FC compiler isn't working. Some variables (like enable_shared) +# are currently assumed to apply to all compilers on this platform, +# and will be corrupted by setting them based on a non-working compiler. +if test "$_lt_disable_FC" != yes; then + # Code to be used in simple compile tests + lt_simple_compile_test_code="\ + subroutine t + return + end +" + + # Code to be used in simple link tests + lt_simple_link_test_code="\ + program t + end +" + + # ltmain only uses $CC for tagged configurations so make sure $CC is set. + _LT_TAG_COMPILER + + # save warnings/boilerplate of simple test code + _LT_COMPILER_BOILERPLATE + _LT_LINKER_BOILERPLATE + + # Allow CC to be a program name with arguments. + lt_save_CC="$CC" + lt_save_GCC=$GCC + lt_save_CFLAGS=$CFLAGS + CC=${FC-"f95"} + CFLAGS=$FCFLAGS + compiler=$CC + GCC=$ac_cv_fc_compiler_gnu + + _LT_TAGVAR(compiler, $1)=$CC + _LT_CC_BASENAME([$compiler]) + + if test -n "$compiler"; then + AC_MSG_CHECKING([if libtool supports shared libraries]) + AC_MSG_RESULT([$can_build_shared]) + + AC_MSG_CHECKING([whether to build shared libraries]) + test "$can_build_shared" = "no" && enable_shared=no + + # On AIX, shared libraries and static libraries use the same namespace, and + # are all built from PIC. + case $host_os in + aix3*) + test "$enable_shared" = yes && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + aix[[4-9]]*) + if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then + test "$enable_shared" = yes && enable_static=no + fi + ;; + esac + AC_MSG_RESULT([$enable_shared]) + + AC_MSG_CHECKING([whether to build static libraries]) + # Make sure either enable_shared or enable_static is yes. + test "$enable_shared" = yes || enable_static=yes + AC_MSG_RESULT([$enable_static]) + + _LT_TAGVAR(GCC, $1)="$ac_cv_fc_compiler_gnu" + _LT_TAGVAR(LD, $1)="$LD" + + ## CAVEAT EMPTOR: + ## There is no encapsulation within the following macros, do not change + ## the running order or otherwise move them around unless you know exactly + ## what you are doing... + _LT_SYS_HIDDEN_LIBDEPS($1) + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_SYS_DYNAMIC_LINKER($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + + _LT_CONFIG($1) + fi # test -n "$compiler" + + GCC=$lt_save_GCC + CC=$lt_save_CC + CFLAGS=$lt_save_CFLAGS +fi # test "$_lt_disable_FC" != yes + +AC_LANG_POP +])# _LT_LANG_FC_CONFIG + + +# _LT_LANG_GCJ_CONFIG([TAG]) +# -------------------------- +# Ensure that the configuration variables for the GNU Java Compiler compiler +# are suitably defined. These variables are subsequently used by _LT_CONFIG +# to write the compiler configuration to `libtool'. +m4_defun([_LT_LANG_GCJ_CONFIG], +[AC_REQUIRE([LT_PROG_GCJ])dnl +AC_LANG_SAVE + +# Source file extension for Java test sources. +ac_ext=java + +# Object file extension for compiled Java test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="class foo {}" + +# Code to be used in simple link tests +lt_simple_link_test_code='public class conftest { public static void main(String[[]] argv) {}; }' + +# ltmain only uses $CC for tagged configurations so make sure $CC is set. +_LT_TAG_COMPILER + +# save warnings/boilerplate of simple test code +_LT_COMPILER_BOILERPLATE +_LT_LINKER_BOILERPLATE + +# Allow CC to be a program name with arguments. +lt_save_CC=$CC +lt_save_CFLAGS=$CFLAGS +lt_save_GCC=$GCC +GCC=yes +CC=${GCJ-"gcj"} +CFLAGS=$GCJFLAGS +compiler=$CC +_LT_TAGVAR(compiler, $1)=$CC +_LT_TAGVAR(LD, $1)="$LD" +_LT_CC_BASENAME([$compiler]) + +# GCJ did not exist at the time GCC didn't implicitly link libc in. +_LT_TAGVAR(archive_cmds_need_lc, $1)=no + +_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_TAGVAR(reload_flag, $1)=$reload_flag +_LT_TAGVAR(reload_cmds, $1)=$reload_cmds + +if test -n "$compiler"; then + _LT_COMPILER_NO_RTTI($1) + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + + _LT_CONFIG($1) +fi + +AC_LANG_RESTORE + +GCC=$lt_save_GCC +CC=$lt_save_CC +CFLAGS=$lt_save_CFLAGS +])# _LT_LANG_GCJ_CONFIG + + +# _LT_LANG_GO_CONFIG([TAG]) +# -------------------------- +# Ensure that the configuration variables for the GNU Go compiler +# are suitably defined. These variables are subsequently used by _LT_CONFIG +# to write the compiler configuration to `libtool'. +m4_defun([_LT_LANG_GO_CONFIG], +[AC_REQUIRE([LT_PROG_GO])dnl +AC_LANG_SAVE + +# Source file extension for Go test sources. +ac_ext=go + +# Object file extension for compiled Go test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="package main; func main() { }" + +# Code to be used in simple link tests +lt_simple_link_test_code='package main; func main() { }' + +# ltmain only uses $CC for tagged configurations so make sure $CC is set. +_LT_TAG_COMPILER + +# save warnings/boilerplate of simple test code +_LT_COMPILER_BOILERPLATE +_LT_LINKER_BOILERPLATE + +# Allow CC to be a program name with arguments. +lt_save_CC=$CC +lt_save_CFLAGS=$CFLAGS +lt_save_GCC=$GCC +GCC=yes +CC=${GOC-"gccgo"} +CFLAGS=$GOFLAGS +compiler=$CC +_LT_TAGVAR(compiler, $1)=$CC +_LT_TAGVAR(LD, $1)="$LD" +_LT_CC_BASENAME([$compiler]) + +# Go did not exist at the time GCC didn't implicitly link libc in. +_LT_TAGVAR(archive_cmds_need_lc, $1)=no + +_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_TAGVAR(reload_flag, $1)=$reload_flag +_LT_TAGVAR(reload_cmds, $1)=$reload_cmds + +if test -n "$compiler"; then + _LT_COMPILER_NO_RTTI($1) + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + + _LT_CONFIG($1) +fi + +AC_LANG_RESTORE + +GCC=$lt_save_GCC +CC=$lt_save_CC +CFLAGS=$lt_save_CFLAGS +])# _LT_LANG_GO_CONFIG + + +# _LT_LANG_RC_CONFIG([TAG]) +# ------------------------- +# Ensure that the configuration variables for the Windows resource compiler +# are suitably defined. These variables are subsequently used by _LT_CONFIG +# to write the compiler configuration to `libtool'. +m4_defun([_LT_LANG_RC_CONFIG], +[AC_REQUIRE([LT_PROG_RC])dnl +AC_LANG_SAVE + +# Source file extension for RC test sources. +ac_ext=rc + +# Object file extension for compiled RC test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code='sample MENU { MENUITEM "&Soup", 100, CHECKED }' + +# Code to be used in simple link tests +lt_simple_link_test_code="$lt_simple_compile_test_code" + +# ltmain only uses $CC for tagged configurations so make sure $CC is set. +_LT_TAG_COMPILER + +# save warnings/boilerplate of simple test code +_LT_COMPILER_BOILERPLATE +_LT_LINKER_BOILERPLATE + +# Allow CC to be a program name with arguments. +lt_save_CC="$CC" +lt_save_CFLAGS=$CFLAGS +lt_save_GCC=$GCC +GCC= +CC=${RC-"windres"} +CFLAGS= +compiler=$CC +_LT_TAGVAR(compiler, $1)=$CC +_LT_CC_BASENAME([$compiler]) +_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes + +if test -n "$compiler"; then + : + _LT_CONFIG($1) +fi + +GCC=$lt_save_GCC +AC_LANG_RESTORE +CC=$lt_save_CC +CFLAGS=$lt_save_CFLAGS +])# _LT_LANG_RC_CONFIG + + +# LT_PROG_GCJ +# ----------- +AC_DEFUN([LT_PROG_GCJ], +[m4_ifdef([AC_PROG_GCJ], [AC_PROG_GCJ], + [m4_ifdef([A][M_PROG_GCJ], [A][M_PROG_GCJ], + [AC_CHECK_TOOL(GCJ, gcj,) + test "x${GCJFLAGS+set}" = xset || GCJFLAGS="-g -O2" + AC_SUBST(GCJFLAGS)])])[]dnl +]) + +# Old name: +AU_ALIAS([LT_AC_PROG_GCJ], [LT_PROG_GCJ]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([LT_AC_PROG_GCJ], []) + + +# LT_PROG_GO +# ---------- +AC_DEFUN([LT_PROG_GO], +[AC_CHECK_TOOL(GOC, gccgo,) +]) + + +# LT_PROG_RC +# ---------- +AC_DEFUN([LT_PROG_RC], +[AC_CHECK_TOOL(RC, windres,) +]) + +# Old name: +AU_ALIAS([LT_AC_PROG_RC], [LT_PROG_RC]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([LT_AC_PROG_RC], []) + + +# _LT_DECL_EGREP +# -------------- +# If we don't have a new enough Autoconf to choose the best grep +# available, choose the one first in the user's PATH. +m4_defun([_LT_DECL_EGREP], +[AC_REQUIRE([AC_PROG_EGREP])dnl +AC_REQUIRE([AC_PROG_FGREP])dnl +test -z "$GREP" && GREP=grep +_LT_DECL([], [GREP], [1], [A grep program that handles long lines]) +_LT_DECL([], [EGREP], [1], [An ERE matcher]) +_LT_DECL([], [FGREP], [1], [A literal string matcher]) +dnl Non-bleeding-edge autoconf doesn't subst GREP, so do it here too +AC_SUBST([GREP]) +]) + + +# _LT_DECL_OBJDUMP +# -------------- +# If we don't have a new enough Autoconf to choose the best objdump +# available, choose the one first in the user's PATH. +m4_defun([_LT_DECL_OBJDUMP], +[AC_CHECK_TOOL(OBJDUMP, objdump, false) +test -z "$OBJDUMP" && OBJDUMP=objdump +_LT_DECL([], [OBJDUMP], [1], [An object symbol dumper]) +AC_SUBST([OBJDUMP]) +]) + +# _LT_DECL_DLLTOOL +# ---------------- +# Ensure DLLTOOL variable is set. +m4_defun([_LT_DECL_DLLTOOL], +[AC_CHECK_TOOL(DLLTOOL, dlltool, false) +test -z "$DLLTOOL" && DLLTOOL=dlltool +_LT_DECL([], [DLLTOOL], [1], [DLL creation program]) +AC_SUBST([DLLTOOL]) +]) + +# _LT_DECL_SED +# ------------ +# Check for a fully-functional sed program, that truncates +# as few characters as possible. Prefer GNU sed if found. +m4_defun([_LT_DECL_SED], +[AC_PROG_SED +test -z "$SED" && SED=sed +Xsed="$SED -e 1s/^X//" +_LT_DECL([], [SED], [1], [A sed program that does not truncate output]) +_LT_DECL([], [Xsed], ["\$SED -e 1s/^X//"], + [Sed that helps us avoid accidentally triggering echo(1) options like -n]) +])# _LT_DECL_SED + +m4_ifndef([AC_PROG_SED], [ +# NOTE: This macro has been submitted for inclusion into # +# GNU Autoconf as AC_PROG_SED. When it is available in # +# a released version of Autoconf we should remove this # +# macro and use it instead. # + +m4_defun([AC_PROG_SED], +[AC_MSG_CHECKING([for a sed that does not truncate output]) +AC_CACHE_VAL(lt_cv_path_SED, +[# Loop through the user's path and test for sed and gsed. +# Then use that list of sed's as ones to test for truncation. +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for lt_ac_prog in sed gsed; do + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then + lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext" + fi + done + done +done +IFS=$as_save_IFS +lt_ac_max=0 +lt_ac_count=0 +# Add /usr/xpg4/bin/sed as it is typically found on Solaris +# along with /bin/sed that truncates output. +for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do + test ! -f $lt_ac_sed && continue + cat /dev/null > conftest.in + lt_ac_count=0 + echo $ECHO_N "0123456789$ECHO_C" >conftest.in + # Check for GNU sed and select it if it is found. + if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then + lt_cv_path_SED=$lt_ac_sed + break + fi + while true; do + cat conftest.in conftest.in >conftest.tmp + mv conftest.tmp conftest.in + cp conftest.in conftest.nl + echo >>conftest.nl + $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break + cmp -s conftest.out conftest.nl || break + # 10000 chars as input seems more than enough + test $lt_ac_count -gt 10 && break + lt_ac_count=`expr $lt_ac_count + 1` + if test $lt_ac_count -gt $lt_ac_max; then + lt_ac_max=$lt_ac_count + lt_cv_path_SED=$lt_ac_sed + fi + done +done +]) +SED=$lt_cv_path_SED +AC_SUBST([SED]) +AC_MSG_RESULT([$SED]) +])#AC_PROG_SED +])#m4_ifndef + +# Old name: +AU_ALIAS([LT_AC_PROG_SED], [AC_PROG_SED]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([LT_AC_PROG_SED], []) + + +# _LT_CHECK_SHELL_FEATURES +# ------------------------ +# Find out whether the shell is Bourne or XSI compatible, +# or has some other useful features. +m4_defun([_LT_CHECK_SHELL_FEATURES], +[AC_MSG_CHECKING([whether the shell understands some XSI constructs]) +# Try some XSI features +xsi_shell=no +( _lt_dummy="a/b/c" + test "${_lt_dummy##*/},${_lt_dummy%/*},${_lt_dummy#??}"${_lt_dummy%"$_lt_dummy"}, \ + = c,a/b,b/c, \ + && eval 'test $(( 1 + 1 )) -eq 2 \ + && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \ + && xsi_shell=yes +AC_MSG_RESULT([$xsi_shell]) +_LT_CONFIG_LIBTOOL_INIT([xsi_shell='$xsi_shell']) + +AC_MSG_CHECKING([whether the shell understands "+="]) +lt_shell_append=no +( foo=bar; set foo baz; eval "$[1]+=\$[2]" && test "$foo" = barbaz ) \ + >/dev/null 2>&1 \ + && lt_shell_append=yes +AC_MSG_RESULT([$lt_shell_append]) +_LT_CONFIG_LIBTOOL_INIT([lt_shell_append='$lt_shell_append']) + +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + lt_unset=unset +else + lt_unset=false +fi +_LT_DECL([], [lt_unset], [0], [whether the shell understands "unset"])dnl + +# test EBCDIC or ASCII +case `echo X|tr X '\101'` in + A) # ASCII based system + # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr + lt_SP2NL='tr \040 \012' + lt_NL2SP='tr \015\012 \040\040' + ;; + *) # EBCDIC based system + lt_SP2NL='tr \100 \n' + lt_NL2SP='tr \r\n \100\100' + ;; +esac +_LT_DECL([SP2NL], [lt_SP2NL], [1], [turn spaces into newlines])dnl +_LT_DECL([NL2SP], [lt_NL2SP], [1], [turn newlines into spaces])dnl +])# _LT_CHECK_SHELL_FEATURES + + +# _LT_PROG_FUNCTION_REPLACE (FUNCNAME, REPLACEMENT-BODY) +# ------------------------------------------------------ +# In `$cfgfile', look for function FUNCNAME delimited by `^FUNCNAME ()$' and +# '^} FUNCNAME ', and replace its body with REPLACEMENT-BODY. +m4_defun([_LT_PROG_FUNCTION_REPLACE], +[dnl { +sed -e '/^$1 ()$/,/^} # $1 /c\ +$1 ()\ +{\ +m4_bpatsubsts([$2], [$], [\\], [^\([ ]\)], [\\\1]) +} # Extended-shell $1 implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: +]) + + +# _LT_PROG_REPLACE_SHELLFNS +# ------------------------- +# Replace existing portable implementations of several shell functions with +# equivalent extended shell implementations where those features are available.. +m4_defun([_LT_PROG_REPLACE_SHELLFNS], +[if test x"$xsi_shell" = xyes; then + _LT_PROG_FUNCTION_REPLACE([func_dirname], [dnl + case ${1} in + */*) func_dirname_result="${1%/*}${2}" ;; + * ) func_dirname_result="${3}" ;; + esac]) + + _LT_PROG_FUNCTION_REPLACE([func_basename], [dnl + func_basename_result="${1##*/}"]) + + _LT_PROG_FUNCTION_REPLACE([func_dirname_and_basename], [dnl + case ${1} in + */*) func_dirname_result="${1%/*}${2}" ;; + * ) func_dirname_result="${3}" ;; + esac + func_basename_result="${1##*/}"]) + + _LT_PROG_FUNCTION_REPLACE([func_stripname], [dnl + # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are + # positional parameters, so assign one to ordinary parameter first. + func_stripname_result=${3} + func_stripname_result=${func_stripname_result#"${1}"} + func_stripname_result=${func_stripname_result%"${2}"}]) + + _LT_PROG_FUNCTION_REPLACE([func_split_long_opt], [dnl + func_split_long_opt_name=${1%%=*} + func_split_long_opt_arg=${1#*=}]) + + _LT_PROG_FUNCTION_REPLACE([func_split_short_opt], [dnl + func_split_short_opt_arg=${1#??} + func_split_short_opt_name=${1%"$func_split_short_opt_arg"}]) + + _LT_PROG_FUNCTION_REPLACE([func_lo2o], [dnl + case ${1} in + *.lo) func_lo2o_result=${1%.lo}.${objext} ;; + *) func_lo2o_result=${1} ;; + esac]) + + _LT_PROG_FUNCTION_REPLACE([func_xform], [ func_xform_result=${1%.*}.lo]) + + _LT_PROG_FUNCTION_REPLACE([func_arith], [ func_arith_result=$(( $[*] ))]) + + _LT_PROG_FUNCTION_REPLACE([func_len], [ func_len_result=${#1}]) +fi + +if test x"$lt_shell_append" = xyes; then + _LT_PROG_FUNCTION_REPLACE([func_append], [ eval "${1}+=\\${2}"]) + + _LT_PROG_FUNCTION_REPLACE([func_append_quoted], [dnl + func_quote_for_eval "${2}" +dnl m4 expansion turns \\\\ into \\, and then the shell eval turns that into \ + eval "${1}+=\\\\ \\$func_quote_for_eval_result"]) + + # Save a `func_append' function call where possible by direct use of '+=' + sed -e 's%func_append \([[a-zA-Z_]]\{1,\}\) "%\1+="%g' $cfgfile > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") + test 0 -eq $? || _lt_function_replace_fail=: +else + # Save a `func_append' function call even when '+=' is not available + sed -e 's%func_append \([[a-zA-Z_]]\{1,\}\) "%\1="$\1%g' $cfgfile > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") + test 0 -eq $? || _lt_function_replace_fail=: +fi + +if test x"$_lt_function_replace_fail" = x":"; then + AC_MSG_WARN([Unable to substitute extended shell functions in $ofile]) +fi +]) + +# _LT_PATH_CONVERSION_FUNCTIONS +# ----------------------------- +# Determine which file name conversion functions should be used by +# func_to_host_file (and, implicitly, by func_to_host_path). These are needed +# for certain cross-compile configurations and native mingw. +m4_defun([_LT_PATH_CONVERSION_FUNCTIONS], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_CANONICAL_BUILD])dnl +AC_MSG_CHECKING([how to convert $build file names to $host format]) +AC_CACHE_VAL(lt_cv_to_host_file_cmd, +[case $host in + *-*-mingw* ) + case $build in + *-*-mingw* ) # actually msys + lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32 + ;; + *-*-cygwin* ) + lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32 + ;; + * ) # otherwise, assume *nix + lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32 + ;; + esac + ;; + *-*-cygwin* ) + case $build in + *-*-mingw* ) # actually msys + lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin + ;; + *-*-cygwin* ) + lt_cv_to_host_file_cmd=func_convert_file_noop + ;; + * ) # otherwise, assume *nix + lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin + ;; + esac + ;; + * ) # unhandled hosts (and "normal" native builds) + lt_cv_to_host_file_cmd=func_convert_file_noop + ;; +esac +]) +to_host_file_cmd=$lt_cv_to_host_file_cmd +AC_MSG_RESULT([$lt_cv_to_host_file_cmd]) +_LT_DECL([to_host_file_cmd], [lt_cv_to_host_file_cmd], + [0], [convert $build file names to $host format])dnl + +AC_MSG_CHECKING([how to convert $build file names to toolchain format]) +AC_CACHE_VAL(lt_cv_to_tool_file_cmd, +[#assume ordinary cross tools, or native build. +lt_cv_to_tool_file_cmd=func_convert_file_noop +case $host in + *-*-mingw* ) + case $build in + *-*-mingw* ) # actually msys + lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32 + ;; + esac + ;; +esac +]) +to_tool_file_cmd=$lt_cv_to_tool_file_cmd +AC_MSG_RESULT([$lt_cv_to_tool_file_cmd]) +_LT_DECL([to_tool_file_cmd], [lt_cv_to_tool_file_cmd], + [0], [convert $build files to toolchain format])dnl +])# _LT_PATH_CONVERSION_FUNCTIONS + +# Helper functions for option handling. -*- Autoconf -*- +# +# Copyright (C) 2004, 2005, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# Written by Gary V. Vaughan, 2004 +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. + +# serial 7 ltoptions.m4 + +# This is to help aclocal find these macros, as it can't see m4_define. +AC_DEFUN([LTOPTIONS_VERSION], [m4_if([1])]) + + +# _LT_MANGLE_OPTION(MACRO-NAME, OPTION-NAME) +# ------------------------------------------ +m4_define([_LT_MANGLE_OPTION], +[[_LT_OPTION_]m4_bpatsubst($1__$2, [[^a-zA-Z0-9_]], [_])]) + + +# _LT_SET_OPTION(MACRO-NAME, OPTION-NAME) +# --------------------------------------- +# Set option OPTION-NAME for macro MACRO-NAME, and if there is a +# matching handler defined, dispatch to it. Other OPTION-NAMEs are +# saved as a flag. +m4_define([_LT_SET_OPTION], +[m4_define(_LT_MANGLE_OPTION([$1], [$2]))dnl +m4_ifdef(_LT_MANGLE_DEFUN([$1], [$2]), + _LT_MANGLE_DEFUN([$1], [$2]), + [m4_warning([Unknown $1 option `$2'])])[]dnl +]) + + +# _LT_IF_OPTION(MACRO-NAME, OPTION-NAME, IF-SET, [IF-NOT-SET]) +# ------------------------------------------------------------ +# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. +m4_define([_LT_IF_OPTION], +[m4_ifdef(_LT_MANGLE_OPTION([$1], [$2]), [$3], [$4])]) + + +# _LT_UNLESS_OPTIONS(MACRO-NAME, OPTION-LIST, IF-NOT-SET) +# ------------------------------------------------------- +# Execute IF-NOT-SET unless all options in OPTION-LIST for MACRO-NAME +# are set. +m4_define([_LT_UNLESS_OPTIONS], +[m4_foreach([_LT_Option], m4_split(m4_normalize([$2])), + [m4_ifdef(_LT_MANGLE_OPTION([$1], _LT_Option), + [m4_define([$0_found])])])[]dnl +m4_ifdef([$0_found], [m4_undefine([$0_found])], [$3 +])[]dnl +]) + + +# _LT_SET_OPTIONS(MACRO-NAME, OPTION-LIST) +# ---------------------------------------- +# OPTION-LIST is a space-separated list of Libtool options associated +# with MACRO-NAME. If any OPTION has a matching handler declared with +# LT_OPTION_DEFINE, dispatch to that macro; otherwise complain about +# the unknown option and exit. +m4_defun([_LT_SET_OPTIONS], +[# Set options +m4_foreach([_LT_Option], m4_split(m4_normalize([$2])), + [_LT_SET_OPTION([$1], _LT_Option)]) + +m4_if([$1],[LT_INIT],[ + dnl + dnl Simply set some default values (i.e off) if boolean options were not + dnl specified: + _LT_UNLESS_OPTIONS([LT_INIT], [dlopen], [enable_dlopen=no + ]) + _LT_UNLESS_OPTIONS([LT_INIT], [win32-dll], [enable_win32_dll=no + ]) + dnl + dnl If no reference was made to various pairs of opposing options, then + dnl we run the default mode handler for the pair. For example, if neither + dnl `shared' nor `disable-shared' was passed, we enable building of shared + dnl archives by default: + _LT_UNLESS_OPTIONS([LT_INIT], [shared disable-shared], [_LT_ENABLE_SHARED]) + _LT_UNLESS_OPTIONS([LT_INIT], [static disable-static], [_LT_ENABLE_STATIC]) + _LT_UNLESS_OPTIONS([LT_INIT], [pic-only no-pic], [_LT_WITH_PIC]) + _LT_UNLESS_OPTIONS([LT_INIT], [fast-install disable-fast-install], + [_LT_ENABLE_FAST_INSTALL]) + ]) +])# _LT_SET_OPTIONS + + + +# _LT_MANGLE_DEFUN(MACRO-NAME, OPTION-NAME) +# ----------------------------------------- +m4_define([_LT_MANGLE_DEFUN], +[[_LT_OPTION_DEFUN_]m4_bpatsubst(m4_toupper([$1__$2]), [[^A-Z0-9_]], [_])]) + + +# LT_OPTION_DEFINE(MACRO-NAME, OPTION-NAME, CODE) +# ----------------------------------------------- +m4_define([LT_OPTION_DEFINE], +[m4_define(_LT_MANGLE_DEFUN([$1], [$2]), [$3])[]dnl +])# LT_OPTION_DEFINE + + +# dlopen +# ------ +LT_OPTION_DEFINE([LT_INIT], [dlopen], [enable_dlopen=yes +]) + +AU_DEFUN([AC_LIBTOOL_DLOPEN], +[_LT_SET_OPTION([LT_INIT], [dlopen]) +AC_DIAGNOSE([obsolete], +[$0: Remove this warning and the call to _LT_SET_OPTION when you +put the `dlopen' option into LT_INIT's first parameter.]) +]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_DLOPEN], []) + + +# win32-dll +# --------- +# Declare package support for building win32 dll's. +LT_OPTION_DEFINE([LT_INIT], [win32-dll], +[enable_win32_dll=yes + +case $host in +*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-cegcc*) + AC_CHECK_TOOL(AS, as, false) + AC_CHECK_TOOL(DLLTOOL, dlltool, false) + AC_CHECK_TOOL(OBJDUMP, objdump, false) + ;; +esac + +test -z "$AS" && AS=as +_LT_DECL([], [AS], [1], [Assembler program])dnl + +test -z "$DLLTOOL" && DLLTOOL=dlltool +_LT_DECL([], [DLLTOOL], [1], [DLL creation program])dnl + +test -z "$OBJDUMP" && OBJDUMP=objdump +_LT_DECL([], [OBJDUMP], [1], [Object dumper program])dnl +])# win32-dll + +AU_DEFUN([AC_LIBTOOL_WIN32_DLL], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +_LT_SET_OPTION([LT_INIT], [win32-dll]) +AC_DIAGNOSE([obsolete], +[$0: Remove this warning and the call to _LT_SET_OPTION when you +put the `win32-dll' option into LT_INIT's first parameter.]) +]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_WIN32_DLL], []) + + +# _LT_ENABLE_SHARED([DEFAULT]) +# ---------------------------- +# implement the --enable-shared flag, and supports the `shared' and +# `disable-shared' LT_INIT options. +# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. +m4_define([_LT_ENABLE_SHARED], +[m4_define([_LT_ENABLE_SHARED_DEFAULT], [m4_if($1, no, no, yes)])dnl +AC_ARG_ENABLE([shared], + [AS_HELP_STRING([--enable-shared@<:@=PKGS@:>@], + [build shared libraries @<:@default=]_LT_ENABLE_SHARED_DEFAULT[@:>@])], + [p=${PACKAGE-default} + case $enableval in + yes) enable_shared=yes ;; + no) enable_shared=no ;; + *) + enable_shared=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_shared=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac], + [enable_shared=]_LT_ENABLE_SHARED_DEFAULT) + + _LT_DECL([build_libtool_libs], [enable_shared], [0], + [Whether or not to build shared libraries]) +])# _LT_ENABLE_SHARED + +LT_OPTION_DEFINE([LT_INIT], [shared], [_LT_ENABLE_SHARED([yes])]) +LT_OPTION_DEFINE([LT_INIT], [disable-shared], [_LT_ENABLE_SHARED([no])]) + +# Old names: +AC_DEFUN([AC_ENABLE_SHARED], +[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[shared]) +]) + +AC_DEFUN([AC_DISABLE_SHARED], +[_LT_SET_OPTION([LT_INIT], [disable-shared]) +]) + +AU_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)]) +AU_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AM_ENABLE_SHARED], []) +dnl AC_DEFUN([AM_DISABLE_SHARED], []) + + + +# _LT_ENABLE_STATIC([DEFAULT]) +# ---------------------------- +# implement the --enable-static flag, and support the `static' and +# `disable-static' LT_INIT options. +# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. +m4_define([_LT_ENABLE_STATIC], +[m4_define([_LT_ENABLE_STATIC_DEFAULT], [m4_if($1, no, no, yes)])dnl +AC_ARG_ENABLE([static], + [AS_HELP_STRING([--enable-static@<:@=PKGS@:>@], + [build static libraries @<:@default=]_LT_ENABLE_STATIC_DEFAULT[@:>@])], + [p=${PACKAGE-default} + case $enableval in + yes) enable_static=yes ;; + no) enable_static=no ;; + *) + enable_static=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_static=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac], + [enable_static=]_LT_ENABLE_STATIC_DEFAULT) + + _LT_DECL([build_old_libs], [enable_static], [0], + [Whether or not to build static libraries]) +])# _LT_ENABLE_STATIC + +LT_OPTION_DEFINE([LT_INIT], [static], [_LT_ENABLE_STATIC([yes])]) +LT_OPTION_DEFINE([LT_INIT], [disable-static], [_LT_ENABLE_STATIC([no])]) + +# Old names: +AC_DEFUN([AC_ENABLE_STATIC], +[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[static]) +]) + +AC_DEFUN([AC_DISABLE_STATIC], +[_LT_SET_OPTION([LT_INIT], [disable-static]) +]) + +AU_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)]) +AU_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AM_ENABLE_STATIC], []) +dnl AC_DEFUN([AM_DISABLE_STATIC], []) + + + +# _LT_ENABLE_FAST_INSTALL([DEFAULT]) +# ---------------------------------- +# implement the --enable-fast-install flag, and support the `fast-install' +# and `disable-fast-install' LT_INIT options. +# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. +m4_define([_LT_ENABLE_FAST_INSTALL], +[m4_define([_LT_ENABLE_FAST_INSTALL_DEFAULT], [m4_if($1, no, no, yes)])dnl +AC_ARG_ENABLE([fast-install], + [AS_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@], + [optimize for fast installation @<:@default=]_LT_ENABLE_FAST_INSTALL_DEFAULT[@:>@])], + [p=${PACKAGE-default} + case $enableval in + yes) enable_fast_install=yes ;; + no) enable_fast_install=no ;; + *) + enable_fast_install=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_fast_install=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac], + [enable_fast_install=]_LT_ENABLE_FAST_INSTALL_DEFAULT) + +_LT_DECL([fast_install], [enable_fast_install], [0], + [Whether or not to optimize for fast installation])dnl +])# _LT_ENABLE_FAST_INSTALL + +LT_OPTION_DEFINE([LT_INIT], [fast-install], [_LT_ENABLE_FAST_INSTALL([yes])]) +LT_OPTION_DEFINE([LT_INIT], [disable-fast-install], [_LT_ENABLE_FAST_INSTALL([no])]) + +# Old names: +AU_DEFUN([AC_ENABLE_FAST_INSTALL], +[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[fast-install]) +AC_DIAGNOSE([obsolete], +[$0: Remove this warning and the call to _LT_SET_OPTION when you put +the `fast-install' option into LT_INIT's first parameter.]) +]) + +AU_DEFUN([AC_DISABLE_FAST_INSTALL], +[_LT_SET_OPTION([LT_INIT], [disable-fast-install]) +AC_DIAGNOSE([obsolete], +[$0: Remove this warning and the call to _LT_SET_OPTION when you put +the `disable-fast-install' option into LT_INIT's first parameter.]) +]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_ENABLE_FAST_INSTALL], []) +dnl AC_DEFUN([AM_DISABLE_FAST_INSTALL], []) + + +# _LT_WITH_PIC([MODE]) +# -------------------- +# implement the --with-pic flag, and support the `pic-only' and `no-pic' +# LT_INIT options. +# MODE is either `yes' or `no'. If omitted, it defaults to `both'. +m4_define([_LT_WITH_PIC], +[AC_ARG_WITH([pic], + [AS_HELP_STRING([--with-pic@<:@=PKGS@:>@], + [try to use only PIC/non-PIC objects @<:@default=use both@:>@])], + [lt_p=${PACKAGE-default} + case $withval in + yes|no) pic_mode=$withval ;; + *) + pic_mode=default + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for lt_pkg in $withval; do + IFS="$lt_save_ifs" + if test "X$lt_pkg" = "X$lt_p"; then + pic_mode=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac], + [pic_mode=default]) + +test -z "$pic_mode" && pic_mode=m4_default([$1], [default]) + +_LT_DECL([], [pic_mode], [0], [What type of objects to build])dnl +])# _LT_WITH_PIC + +LT_OPTION_DEFINE([LT_INIT], [pic-only], [_LT_WITH_PIC([yes])]) +LT_OPTION_DEFINE([LT_INIT], [no-pic], [_LT_WITH_PIC([no])]) + +# Old name: +AU_DEFUN([AC_LIBTOOL_PICMODE], +[_LT_SET_OPTION([LT_INIT], [pic-only]) +AC_DIAGNOSE([obsolete], +[$0: Remove this warning and the call to _LT_SET_OPTION when you +put the `pic-only' option into LT_INIT's first parameter.]) +]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_PICMODE], []) + + +m4_define([_LTDL_MODE], []) +LT_OPTION_DEFINE([LTDL_INIT], [nonrecursive], + [m4_define([_LTDL_MODE], [nonrecursive])]) +LT_OPTION_DEFINE([LTDL_INIT], [recursive], + [m4_define([_LTDL_MODE], [recursive])]) +LT_OPTION_DEFINE([LTDL_INIT], [subproject], + [m4_define([_LTDL_MODE], [subproject])]) + +m4_define([_LTDL_TYPE], []) +LT_OPTION_DEFINE([LTDL_INIT], [installable], + [m4_define([_LTDL_TYPE], [installable])]) +LT_OPTION_DEFINE([LTDL_INIT], [convenience], + [m4_define([_LTDL_TYPE], [convenience])]) + +# ltsugar.m4 -- libtool m4 base layer. -*-Autoconf-*- +# +# Copyright (C) 2004, 2005, 2007, 2008 Free Software Foundation, Inc. +# Written by Gary V. Vaughan, 2004 +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. + +# serial 6 ltsugar.m4 + +# This is to help aclocal find these macros, as it can't see m4_define. +AC_DEFUN([LTSUGAR_VERSION], [m4_if([0.1])]) + + +# lt_join(SEP, ARG1, [ARG2...]) +# ----------------------------- +# Produce ARG1SEPARG2...SEPARGn, omitting [] arguments and their +# associated separator. +# Needed until we can rely on m4_join from Autoconf 2.62, since all earlier +# versions in m4sugar had bugs. +m4_define([lt_join], +[m4_if([$#], [1], [], + [$#], [2], [[$2]], + [m4_if([$2], [], [], [[$2]_])$0([$1], m4_shift(m4_shift($@)))])]) +m4_define([_lt_join], +[m4_if([$#$2], [2], [], + [m4_if([$2], [], [], [[$1$2]])$0([$1], m4_shift(m4_shift($@)))])]) + + +# lt_car(LIST) +# lt_cdr(LIST) +# ------------ +# Manipulate m4 lists. +# These macros are necessary as long as will still need to support +# Autoconf-2.59 which quotes differently. +m4_define([lt_car], [[$1]]) +m4_define([lt_cdr], +[m4_if([$#], 0, [m4_fatal([$0: cannot be called without arguments])], + [$#], 1, [], + [m4_dquote(m4_shift($@))])]) +m4_define([lt_unquote], $1) + + +# lt_append(MACRO-NAME, STRING, [SEPARATOR]) +# ------------------------------------------ +# Redefine MACRO-NAME to hold its former content plus `SEPARATOR'`STRING'. +# Note that neither SEPARATOR nor STRING are expanded; they are appended +# to MACRO-NAME as is (leaving the expansion for when MACRO-NAME is invoked). +# No SEPARATOR is output if MACRO-NAME was previously undefined (different +# than defined and empty). +# +# This macro is needed until we can rely on Autoconf 2.62, since earlier +# versions of m4sugar mistakenly expanded SEPARATOR but not STRING. +m4_define([lt_append], +[m4_define([$1], + m4_ifdef([$1], [m4_defn([$1])[$3]])[$2])]) + + + +# lt_combine(SEP, PREFIX-LIST, INFIX, SUFFIX1, [SUFFIX2...]) +# ---------------------------------------------------------- +# Produce a SEP delimited list of all paired combinations of elements of +# PREFIX-LIST with SUFFIX1 through SUFFIXn. Each element of the list +# has the form PREFIXmINFIXSUFFIXn. +# Needed until we can rely on m4_combine added in Autoconf 2.62. +m4_define([lt_combine], +[m4_if(m4_eval([$# > 3]), [1], + [m4_pushdef([_Lt_sep], [m4_define([_Lt_sep], m4_defn([lt_car]))])]]dnl +[[m4_foreach([_Lt_prefix], [$2], + [m4_foreach([_Lt_suffix], + ]m4_dquote(m4_dquote(m4_shift(m4_shift(m4_shift($@)))))[, + [_Lt_sep([$1])[]m4_defn([_Lt_prefix])[$3]m4_defn([_Lt_suffix])])])])]) + + +# lt_if_append_uniq(MACRO-NAME, VARNAME, [SEPARATOR], [UNIQ], [NOT-UNIQ]) +# ----------------------------------------------------------------------- +# Iff MACRO-NAME does not yet contain VARNAME, then append it (delimited +# by SEPARATOR if supplied) and expand UNIQ, else NOT-UNIQ. +m4_define([lt_if_append_uniq], +[m4_ifdef([$1], + [m4_if(m4_index([$3]m4_defn([$1])[$3], [$3$2$3]), [-1], + [lt_append([$1], [$2], [$3])$4], + [$5])], + [lt_append([$1], [$2], [$3])$4])]) + + +# lt_dict_add(DICT, KEY, VALUE) +# ----------------------------- +m4_define([lt_dict_add], +[m4_define([$1($2)], [$3])]) + + +# lt_dict_add_subkey(DICT, KEY, SUBKEY, VALUE) +# -------------------------------------------- +m4_define([lt_dict_add_subkey], +[m4_define([$1($2:$3)], [$4])]) + + +# lt_dict_fetch(DICT, KEY, [SUBKEY]) +# ---------------------------------- +m4_define([lt_dict_fetch], +[m4_ifval([$3], + m4_ifdef([$1($2:$3)], [m4_defn([$1($2:$3)])]), + m4_ifdef([$1($2)], [m4_defn([$1($2)])]))]) + + +# lt_if_dict_fetch(DICT, KEY, [SUBKEY], VALUE, IF-TRUE, [IF-FALSE]) +# ----------------------------------------------------------------- +m4_define([lt_if_dict_fetch], +[m4_if(lt_dict_fetch([$1], [$2], [$3]), [$4], + [$5], + [$6])]) + + +# lt_dict_filter(DICT, [SUBKEY], VALUE, [SEPARATOR], KEY, [...]) +# -------------------------------------------------------------- +m4_define([lt_dict_filter], +[m4_if([$5], [], [], + [lt_join(m4_quote(m4_default([$4], [[, ]])), + lt_unquote(m4_split(m4_normalize(m4_foreach(_Lt_key, lt_car([m4_shiftn(4, $@)]), + [lt_if_dict_fetch([$1], _Lt_key, [$2], [$3], [_Lt_key ])])))))])[]dnl +]) + +# ltversion.m4 -- version numbers -*- Autoconf -*- +# +# Copyright (C) 2004 Free Software Foundation, Inc. +# Written by Scott James Remnant, 2004 +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. + +# @configure_input@ + +# serial 3337 ltversion.m4 +# This file is part of GNU Libtool + +m4_define([LT_PACKAGE_VERSION], [2.4.2]) +m4_define([LT_PACKAGE_REVISION], [1.3337]) + +AC_DEFUN([LTVERSION_VERSION], +[macro_version='2.4.2' +macro_revision='1.3337' +_LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?]) +_LT_DECL(, macro_revision, 0) +]) + +# lt~obsolete.m4 -- aclocal satisfying obsolete definitions. -*-Autoconf-*- +# +# Copyright (C) 2004, 2005, 2007, 2009 Free Software Foundation, Inc. +# Written by Scott James Remnant, 2004. +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. + +# serial 5 lt~obsolete.m4 + +# These exist entirely to fool aclocal when bootstrapping libtool. +# +# In the past libtool.m4 has provided macros via AC_DEFUN (or AU_DEFUN) +# which have later been changed to m4_define as they aren't part of the +# exported API, or moved to Autoconf or Automake where they belong. +# +# The trouble is, aclocal is a bit thick. It'll see the old AC_DEFUN +# in /usr/share/aclocal/libtool.m4 and remember it, then when it sees us +# using a macro with the same name in our local m4/libtool.m4 it'll +# pull the old libtool.m4 in (it doesn't see our shiny new m4_define +# and doesn't know about Autoconf macros at all.) +# +# So we provide this file, which has a silly filename so it's always +# included after everything else. This provides aclocal with the +# AC_DEFUNs it wants, but when m4 processes it, it doesn't do anything +# because those macros already exist, or will be overwritten later. +# We use AC_DEFUN over AU_DEFUN for compatibility with aclocal-1.6. +# +# Anytime we withdraw an AC_DEFUN or AU_DEFUN, remember to add it here. +# Yes, that means every name once taken will need to remain here until +# we give up compatibility with versions before 1.7, at which point +# we need to keep only those names which we still refer to. + +# This is to help aclocal find these macros, as it can't see m4_define. +AC_DEFUN([LTOBSOLETE_VERSION], [m4_if([1])]) + +m4_ifndef([AC_LIBTOOL_LINKER_OPTION], [AC_DEFUN([AC_LIBTOOL_LINKER_OPTION])]) +m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP])]) +m4_ifndef([_LT_AC_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH])]) +m4_ifndef([_LT_AC_SHELL_INIT], [AC_DEFUN([_LT_AC_SHELL_INIT])]) +m4_ifndef([_LT_AC_SYS_LIBPATH_AIX], [AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX])]) +m4_ifndef([_LT_PROG_LTMAIN], [AC_DEFUN([_LT_PROG_LTMAIN])]) +m4_ifndef([_LT_AC_TAGVAR], [AC_DEFUN([_LT_AC_TAGVAR])]) +m4_ifndef([AC_LTDL_ENABLE_INSTALL], [AC_DEFUN([AC_LTDL_ENABLE_INSTALL])]) +m4_ifndef([AC_LTDL_PREOPEN], [AC_DEFUN([AC_LTDL_PREOPEN])]) +m4_ifndef([_LT_AC_SYS_COMPILER], [AC_DEFUN([_LT_AC_SYS_COMPILER])]) +m4_ifndef([_LT_AC_LOCK], [AC_DEFUN([_LT_AC_LOCK])]) +m4_ifndef([AC_LIBTOOL_SYS_OLD_ARCHIVE], [AC_DEFUN([AC_LIBTOOL_SYS_OLD_ARCHIVE])]) +m4_ifndef([_LT_AC_TRY_DLOPEN_SELF], [AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF])]) +m4_ifndef([AC_LIBTOOL_PROG_CC_C_O], [AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O])]) +m4_ifndef([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], [AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS])]) +m4_ifndef([AC_LIBTOOL_OBJDIR], [AC_DEFUN([AC_LIBTOOL_OBJDIR])]) +m4_ifndef([AC_LTDL_OBJDIR], [AC_DEFUN([AC_LTDL_OBJDIR])]) +m4_ifndef([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], [AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH])]) +m4_ifndef([AC_LIBTOOL_SYS_LIB_STRIP], [AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP])]) +m4_ifndef([AC_PATH_MAGIC], [AC_DEFUN([AC_PATH_MAGIC])]) +m4_ifndef([AC_PROG_LD_GNU], [AC_DEFUN([AC_PROG_LD_GNU])]) +m4_ifndef([AC_PROG_LD_RELOAD_FLAG], [AC_DEFUN([AC_PROG_LD_RELOAD_FLAG])]) +m4_ifndef([AC_DEPLIBS_CHECK_METHOD], [AC_DEFUN([AC_DEPLIBS_CHECK_METHOD])]) +m4_ifndef([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI])]) +m4_ifndef([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], [AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])]) +m4_ifndef([AC_LIBTOOL_PROG_COMPILER_PIC], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC])]) +m4_ifndef([AC_LIBTOOL_PROG_LD_SHLIBS], [AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS])]) +m4_ifndef([AC_LIBTOOL_POSTDEP_PREDEP], [AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP])]) +m4_ifndef([LT_AC_PROG_EGREP], [AC_DEFUN([LT_AC_PROG_EGREP])]) +m4_ifndef([LT_AC_PROG_SED], [AC_DEFUN([LT_AC_PROG_SED])]) +m4_ifndef([_LT_CC_BASENAME], [AC_DEFUN([_LT_CC_BASENAME])]) +m4_ifndef([_LT_COMPILER_BOILERPLATE], [AC_DEFUN([_LT_COMPILER_BOILERPLATE])]) +m4_ifndef([_LT_LINKER_BOILERPLATE], [AC_DEFUN([_LT_LINKER_BOILERPLATE])]) +m4_ifndef([_AC_PROG_LIBTOOL], [AC_DEFUN([_AC_PROG_LIBTOOL])]) +m4_ifndef([AC_LIBTOOL_SETUP], [AC_DEFUN([AC_LIBTOOL_SETUP])]) +m4_ifndef([_LT_AC_CHECK_DLFCN], [AC_DEFUN([_LT_AC_CHECK_DLFCN])]) +m4_ifndef([AC_LIBTOOL_SYS_DYNAMIC_LINKER], [AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER])]) +m4_ifndef([_LT_AC_TAGCONFIG], [AC_DEFUN([_LT_AC_TAGCONFIG])]) +m4_ifndef([AC_DISABLE_FAST_INSTALL], [AC_DEFUN([AC_DISABLE_FAST_INSTALL])]) +m4_ifndef([_LT_AC_LANG_CXX], [AC_DEFUN([_LT_AC_LANG_CXX])]) +m4_ifndef([_LT_AC_LANG_F77], [AC_DEFUN([_LT_AC_LANG_F77])]) +m4_ifndef([_LT_AC_LANG_GCJ], [AC_DEFUN([_LT_AC_LANG_GCJ])]) +m4_ifndef([AC_LIBTOOL_LANG_C_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG])]) +m4_ifndef([_LT_AC_LANG_C_CONFIG], [AC_DEFUN([_LT_AC_LANG_C_CONFIG])]) +m4_ifndef([AC_LIBTOOL_LANG_CXX_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG])]) +m4_ifndef([_LT_AC_LANG_CXX_CONFIG], [AC_DEFUN([_LT_AC_LANG_CXX_CONFIG])]) +m4_ifndef([AC_LIBTOOL_LANG_F77_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG])]) +m4_ifndef([_LT_AC_LANG_F77_CONFIG], [AC_DEFUN([_LT_AC_LANG_F77_CONFIG])]) +m4_ifndef([AC_LIBTOOL_LANG_GCJ_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG])]) +m4_ifndef([_LT_AC_LANG_GCJ_CONFIG], [AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG])]) +m4_ifndef([AC_LIBTOOL_LANG_RC_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG])]) +m4_ifndef([_LT_AC_LANG_RC_CONFIG], [AC_DEFUN([_LT_AC_LANG_RC_CONFIG])]) +m4_ifndef([AC_LIBTOOL_CONFIG], [AC_DEFUN([AC_LIBTOOL_CONFIG])]) +m4_ifndef([_LT_AC_FILE_LTDLL_C], [AC_DEFUN([_LT_AC_FILE_LTDLL_C])]) +m4_ifndef([_LT_REQUIRED_DARWIN_CHECKS], [AC_DEFUN([_LT_REQUIRED_DARWIN_CHECKS])]) +m4_ifndef([_LT_AC_PROG_CXXCPP], [AC_DEFUN([_LT_AC_PROG_CXXCPP])]) +m4_ifndef([_LT_PREPARE_SED_QUOTE_VARS], [AC_DEFUN([_LT_PREPARE_SED_QUOTE_VARS])]) +m4_ifndef([_LT_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_PROG_ECHO_BACKSLASH])]) +m4_ifndef([_LT_PROG_F77], [AC_DEFUN([_LT_PROG_F77])]) +m4_ifndef([_LT_PROG_FC], [AC_DEFUN([_LT_PROG_FC])]) +m4_ifndef([_LT_PROG_CXX], [AC_DEFUN([_LT_PROG_CXX])]) + +# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*- +# serial 1 (pkg-config-0.24) +# +# Copyright © 2004 Scott James Remnant . +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# PKG_PROG_PKG_CONFIG([MIN-VERSION]) +# ---------------------------------- +AC_DEFUN([PKG_PROG_PKG_CONFIG], +[m4_pattern_forbid([^_?PKG_[A-Z_]+$]) +m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$]) +m4_pattern_allow([^PKG_CONFIG_(DISABLE_UNINSTALLED|TOP_BUILD_DIR|DEBUG_SPEW)$]) +AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility]) +AC_ARG_VAR([PKG_CONFIG_PATH], [directories to add to pkg-config's search path]) +AC_ARG_VAR([PKG_CONFIG_LIBDIR], [path overriding pkg-config's built-in search path]) + +if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then + AC_PATH_TOOL([PKG_CONFIG], [pkg-config]) +fi +if test -n "$PKG_CONFIG"; then + _pkg_min_version=m4_default([$1], [0.9.0]) + AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version]) + if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + PKG_CONFIG="" + fi +fi[]dnl +])# PKG_PROG_PKG_CONFIG + +# PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) +# +# Check to see whether a particular set of modules exists. Similar +# to PKG_CHECK_MODULES(), but does not set variables or print errors. +# +# Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG]) +# only at the first occurence in configure.ac, so if the first place +# it's called might be skipped (such as if it is within an "if", you +# have to call PKG_CHECK_EXISTS manually +# -------------------------------------------------------------- +AC_DEFUN([PKG_CHECK_EXISTS], +[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl +if test -n "$PKG_CONFIG" && \ + AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then + m4_default([$2], [:]) +m4_ifvaln([$3], [else + $3])dnl +fi]) + +# _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES]) +# --------------------------------------------- +m4_define([_PKG_CONFIG], +[if test -n "$$1"; then + pkg_cv_[]$1="$$1" + elif test -n "$PKG_CONFIG"; then + PKG_CHECK_EXISTS([$3], + [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes ], + [pkg_failed=yes]) + else + pkg_failed=untried +fi[]dnl +])# _PKG_CONFIG + +# _PKG_SHORT_ERRORS_SUPPORTED +# ----------------------------- +AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED], +[AC_REQUIRE([PKG_PROG_PKG_CONFIG]) +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi[]dnl +])# _PKG_SHORT_ERRORS_SUPPORTED + + +# PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], +# [ACTION-IF-NOT-FOUND]) +# +# +# Note that if there is a possibility the first call to +# PKG_CHECK_MODULES might not happen, you should be sure to include an +# explicit call to PKG_PROG_PKG_CONFIG in your configure.ac +# +# +# -------------------------------------------------------------- +AC_DEFUN([PKG_CHECK_MODULES], +[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl +AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl +AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl + +pkg_failed=no +AC_MSG_CHECKING([for $1]) + +_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2]) +_PKG_CONFIG([$1][_LIBS], [libs], [$2]) + +m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS +and $1[]_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details.]) + +if test $pkg_failed = yes; then + AC_MSG_RESULT([no]) + _PKG_SHORT_ERRORS_SUPPORTED + if test $_pkg_short_errors_supported = yes; then + $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1` + else + $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD + + m4_default([$4], [AC_MSG_ERROR( +[Package requirements ($2) were not met: + +$$1_PKG_ERRORS + +Consider adjusting the PKG_CONFIG_PATH environment variable if you +installed software in a non-standard prefix. + +_PKG_TEXT])[]dnl + ]) +elif test $pkg_failed = untried; then + AC_MSG_RESULT([no]) + m4_default([$4], [AC_MSG_FAILURE( +[The pkg-config script could not be found or is too old. Make sure it +is in your PATH or set the PKG_CONFIG environment variable to the full +path to pkg-config. + +_PKG_TEXT + +To get pkg-config, see .])[]dnl + ]) +else + $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS + $1[]_LIBS=$pkg_cv_[]$1[]_LIBS + AC_MSG_RESULT([yes]) + $3 +fi[]dnl +])# PKG_CHECK_MODULES + diff --git a/extern/portaudio/bindings/cpp/AUTHORS b/extern/portaudio/bindings/cpp/AUTHORS new file mode 100644 index 0000000..e69de29 diff --git a/extern/portaudio/bindings/cpp/COPYING b/extern/portaudio/bindings/cpp/COPYING new file mode 100644 index 0000000..c1c60a0 --- /dev/null +++ b/extern/portaudio/bindings/cpp/COPYING @@ -0,0 +1,31 @@ +PortAudio Portable Real-Time Audio Library +Copyright (c) 1999-2006 Ross Bencina and Phil Burk + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files +(the "Software"), to deal in the Software without restriction, +including without limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of the Software, +and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR +ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +The text above constitutes the entire PortAudio license; however, +the PortAudio community also makes the following non-binding requests: + +Any person wishing to distribute modifications to the Software is +requested to send the modifications to the original developer so that +they can be incorporated into the canonical version. It is also +requested that these non-binding requests be included along with the +license above. diff --git a/extern/portaudio/bindings/cpp/ChangeLog b/extern/portaudio/bindings/cpp/ChangeLog new file mode 100644 index 0000000..6b0b027 --- /dev/null +++ b/extern/portaudio/bindings/cpp/ChangeLog @@ -0,0 +1,178 @@ +Note: Because PortAudioCpp is now in the main PortAudio SVN repository, having these per-release changelogs probably doesn't make much sense anymore. Perhaps it's better to just note mayor changes by date from now on. + +PortAudioCpp v19 revision 16 06/05/22: + + mblaauw: + - Added up-to-date MSVC 6.0 projects created by David Moore. Besides MSVC 6.0 users, MSVC 7.0 users may use these projects and automatically convert them to MSVC 7.0 projects. + - Changed the code and projects (MSVC 7.1 only) to be up-to-date with PortAudio's new directory structure. + - Added equivalents of the PaAsio_GetInputChannelName() and PaAsio_GetOutputChannelName() functions to the AsioDeviceAdapter wrapper-class (missing functions pointed out by David Moore). + - Added code to PortAudio's main SVN repository. + +PortAudioCpp v19 revision 15 (unknown release date): + + mblaauw: + - Changed some exception handling code in HostApi's constructor. + - Added accessors to PortAudio PaStream from PortAudioCpp Stream (their absense being pointed out + by Tom Jordan). + - Fixed a bug/typo in MemFunToCallbackInterfaceAdapter::init() thanks to Fredrik Viklund. + - Fixed issue with concrete Stream classes possibly throwing an exception and fixed documentation w.r.t. this. + - Moved files to portaudio/binding/cpp/. Made new msvc 7.1 projects to reflect the change and removed msvc 6.0 + and 7.0 projects (because I can no longer maintain them myself). Gnu projects will probably need updating. + +PortAudioCpp v19 revision 14 03/10/24: + + mblaauw: + - Fixed some error handling bugs in Stream and System (pointed out by Tom Jordan). + - Updated documentation a little (main page). + - Fixed order of members so initializer list was in the right order in + StreamParameters (pointed out by Ludwig Schwardt). + - Added new lines at EOF's (as indicated by Ludwig Schwardt). + +PortAudioCpp v19 revision 13 03/10/19: + + lschwardt: + - Added build files for GNU/Linux. + - Fixed bug in Exception where the inherited what() member function (and destructor) had looser + exception specification (namely no exception specification, i.e. could throw anything) than + the std::exception base class's what() member function (which had throw(), i.e. no-throw guarantee). + - Changed the iterators so that they have a set of public typedefs instead of deriving the C++ standard + library std::iterator<> struct. G++ 2.95 doesn't support std::exception<> and composition-by-aggregation + is prefered over composition-by-inheritance in this case. + - Changed some minor things to avoid G++ warning messages. + + mblaauw: + - Renamed this file (/WHATSNEW.txt) to /CHANGELOG. + - Renamed /PA_ISSUES.txt to /PA_ISSUES. + - Added /INSTALL file with some build info for GNU/Linux and VC6. + - Added MSVC 6.0 projects for building PortAudioCpp as a staticly or dynamically linkable library. + - Moved build files to /build/(gnu/ or vc6/). + - Moved Doxygen configuration files to /doc/ and output to /doc/api_reference/. + - Added a /doc/README with some info how to generate Doxygen documentation. + +PortAudioCpp v19 revision 12 03/09/02: + + mblaauw: + - Updated code to reflect changes on V19-devel CVS branch. + - Fixed some typos in the documentation. + +PortAudioCpp v19 revision 11 03/07/31: + + mblaauw: + - Renamed SingleDirecionStreamParameters to DirectionSpecificStreamParameters. + - Implemented BlockingStream. + - Updated code to reflect recent changes to PortAudio V19-devel. + - Fixed a potential memory leak when an exception was thrown in the HostApi + constructor. + - Renamed ``Latency'' to ``BufferSize'' in AsioDeviceAdapter. + - Updated class documentation. + +PortAudioCpp v19 revision 10 03/07/18: + + mblaauw: + - SingleDirectionStreamParameters now has a (static) null() method. + - StreamParameters uses references for the direction-specific stream parameters + instead of pointers (use null() method (above) instead of NULL). + - StreamParameters and SingleDirectionStreamParameters must now be fully specified + and now default values are used (because this was not very useful in general and + only made things more complex). + - Updated documentation. + +PortAudioCpp v19 revision 09 03/06/25: + + mblaauw: + - Changed some things in SingleDirectionStreamParameters to ease it's usage. + - Placed all SingleDirectionStreamParameters stuff into a separate file. + + Totally redid the callback stuff, now it's less ackward and supports C++ functions. + +PortAudioCpp v19 revision 08 03/06/20: + + mblaauw: + - Made deconstructors for Device and HostApi private. + + Added a AsioDeviceWrapper host api specific device extension class. + - Refactored Exception into a Exception base class and PaException and PaCppException + derived classes. + - Added ASIO specific device info to the devs.cxx example. + - Fixed a bug in System::hostApiCount() and System::defaultHostApi(). + + Moved Device::null to System::nullDevice. + - Fixed some bugs in Device and System. + +PortAudioCpp v19 revision 07 03/06/08: + + mblaauw: + - Updated some doxy comments. + + Renamed CbXyz to CallbackXyz. + + Renamed all ``configurations'' to ``parameters''. + + Renamed HalfDuplexStreamConfiguration to SingleDirectionStreamConfiguration. + - Renamed SingleDirectionStreamParameters::streamParameters() to + SingleDirectionStreamParameters::paSteamParameters. + - Added a non-constant version of SingleDirectionStreamParameters::paStreamParameters(). + - A few improvements to SingleDirectionStreamParameters. + - Allowed AutoSystem to be created without initializing the System singleton + (using a ctor flag). + - Added a BlockingStream class (not implemented for now). + - Fixed many bugs in the implementation of the iterators. + - Fixed a bug in Device::operator==(). + + Added a C++ version of the patest_sine.c test/example. + - Added a ctor for StreamParameters for a default half-duplex stream. + - Added SingleDirectionStreamParameters::setDevice() and setNumChannels(). + - Renamed System::numHostApis() to System::hostApiCount(). + + Rewrote the iterators and related classes. They are now fully STL compliant. The System now + has a static array of all HostApis and all Devices. Only the System can create HostApis and + Devices and they are non-copyable now. All HostApis and Devices are now passed by-reference. + - Renamed (System::) getVersion() to version() and getVersionText() to versionText(). + - Renamed (Device::) numXyzChannels() to maxXyzChannels(). + - Changed some stuff in StreamParameters. + + Added a C++ version of the patest_devs.c test/example. + +PortAudioCpp v19 revision 06 03/06/04: + + mblaauw: + + Added this file to the project (roughly, a `+' denotes a major change, a `-' a minor change). + - Added System::deviceByIndex(), useful when a Device's index is stored for instance. + - Renamed System::hostApiFromTypeId() to System::hostApiByTypeId(). + - Updated and added some Doxygen documentation. + - Made Stream::usedIntputLatency(), Stream::usedOutputLatency() and + Stream::usedSampleRate() throw an paInternalError equivalent exception instead of paBadStreamPtr. + - Changed exception handling in Stream::open() functions. They now follow the PA error handling + mechanism better and a couple of bugs regarding ownership of objects were fixed. + - Renamed Device::isDefaultXyzDevice() to Device::isSystemDefaultXyzDevice(). + - Added Device::isHostApiDefaultXyzDevice(). + - Added StreamConfiguration::unsetFlag(). + - Removed CUSTOM from SampleDataFormat. + - System::hostApiByTypeId() now throws an paInternalError if the type id was out-of-range; this + is a temporary work-around (see comments). + - Changed CbInterface to use paCallbackFun() instead of operator()(). + - Renamed ``object'' to ``instance'' in CbMemFunAdapter.hxx. + - Added StreamConfiguration::setXyzHostApiSpecificSampleFormat(). + - Added StreamConfiguration::isXyzSampleFormatHostApiSpecific(). + - Changed error handling in System::terminate(), it can now throw an Exception. + - Added error handling in System::defaultHostApi(). + - Added error handling in System::hostApisEnd(). + - Changed some (but probably not all) C casts to C++ casts to avoid confusion with a + certain Python person. + - Renamed RaiiSystem to AutoSystem (class and file) as this is a come common convention. + - Renamed System::numDevices() to System::deviceCount() to be more compatible with PortAudio + (although PortAudio uses Pa_CountDevices() instead, see comment). + - Renamed HostApi::numDevices() to HostApi::deviceCount(). + - Changed INC_ to INCLUDED_ in the header multiple include guards. + - Changed the order of functions in the StreamConfiguration class' header. + - Written some more info in PortAudioCpp.hxx (Doxygen). + - Added CallbackStream.hxx and CallbackStream.cxx files. + + Refactored StreamConfiguration to remove the duplication which was there. There is now a + HalfDuplexStreamConfiguration class. Also made some improvements to these classes while + doing the refactoring. + + Moved all code files to source/portaudiocpp/ and changed includes. + + Moved all header files to include/portaudiocpp/ to easy a binary build if needed. The project + must be set to have .../include/ as a path to look for includes. + + Refactored the Stream class into a Stream base class and a CallbackStream derived class. + - Renamed Stream::usingXyz() to Stream::xyz(). + - Updated some doxy comments. + - Changed ``using namespace portaudio'' in .cxx files to ``namespace portaudio { ... }''. + +PortAudioCpp v19 revision 05 03/04/09: + + mblaauw: + - Initial release on the PortAudio mailinglist. + + + diff --git a/extern/portaudio/bindings/cpp/INSTALL b/extern/portaudio/bindings/cpp/INSTALL new file mode 100644 index 0000000..2099840 --- /dev/null +++ b/extern/portaudio/bindings/cpp/INSTALL @@ -0,0 +1,370 @@ +Installation Instructions +************************* + +Copyright (C) 1994-1996, 1999-2002, 2004-2013 Free Software Foundation, +Inc. + + Copying and distribution of this file, with or without modification, +are permitted in any medium without royalty provided the copyright +notice and this notice are preserved. This file is offered as-is, +without warranty of any kind. + +Basic Installation +================== + + Briefly, the shell command `./configure && make && make install' +should configure, build, and install this package. The following +more-detailed instructions are generic; see the `README' file for +instructions specific to this package. Some packages provide this +`INSTALL' file but do not implement all of the features documented +below. The lack of an optional feature in a given package is not +necessarily a bug. More recommendations for GNU packages can be found +in *note Makefile Conventions: (standards)Makefile Conventions. + + The `configure' shell script attempts to guess correct values for +various system-dependent variables used during compilation. It uses +those values to create a `Makefile' in each directory of the package. +It may also create one or more `.h' files containing system-dependent +definitions. Finally, it creates a shell script `config.status' that +you can run in the future to recreate the current configuration, and a +file `config.log' containing compiler output (useful mainly for +debugging `configure'). + + It can also use an optional file (typically called `config.cache' +and enabled with `--cache-file=config.cache' or simply `-C') that saves +the results of its tests to speed up reconfiguring. Caching is +disabled by default to prevent problems with accidental use of stale +cache files. + + If you need to do unusual things to compile the package, please try +to figure out how `configure' could check whether to do them, and mail +diffs or instructions to the address given in the `README' so they can +be considered for the next release. If you are using the cache, and at +some point `config.cache' contains results you don't want to keep, you +may remove or edit it. + + The file `configure.ac' (or `configure.in') is used to create +`configure' by a program called `autoconf'. You need `configure.ac' if +you want to change it or regenerate `configure' using a newer version +of `autoconf'. + + The simplest way to compile this package is: + + 1. `cd' to the directory containing the package's source code and type + `./configure' to configure the package for your system. + + Running `configure' might take a while. While running, it prints + some messages telling which features it is checking for. + + 2. Type `make' to compile the package. + + 3. Optionally, type `make check' to run any self-tests that come with + the package, generally using the just-built uninstalled binaries. + + 4. Type `make install' to install the programs and any data files and + documentation. When installing into a prefix owned by root, it is + recommended that the package be configured and built as a regular + user, and only the `make install' phase executed with root + privileges. + + 5. Optionally, type `make installcheck' to repeat any self-tests, but + this time using the binaries in their final installed location. + This target does not install anything. Running this target as a + regular user, particularly if the prior `make install' required + root privileges, verifies that the installation completed + correctly. + + 6. You can remove the program binaries and object files from the + source code directory by typing `make clean'. To also remove the + files that `configure' created (so you can compile the package for + a different kind of computer), type `make distclean'. There is + also a `make maintainer-clean' target, but that is intended mainly + for the package's developers. If you use it, you may have to get + all sorts of other programs in order to regenerate files that came + with the distribution. + + 7. Often, you can also type `make uninstall' to remove the installed + files again. In practice, not all packages have tested that + uninstallation works correctly, even though it is required by the + GNU Coding Standards. + + 8. Some packages, particularly those that use Automake, provide `make + distcheck', which can by used by developers to test that all other + targets like `make install' and `make uninstall' work correctly. + This target is generally not run by end users. + +Compilers and Options +===================== + + Some systems require unusual options for compilation or linking that +the `configure' script does not know about. Run `./configure --help' +for details on some of the pertinent environment variables. + + You can give `configure' initial values for configuration parameters +by setting variables in the command line or in the environment. Here +is an example: + + ./configure CC=c99 CFLAGS=-g LIBS=-lposix + + *Note Defining Variables::, for more details. + +Compiling For Multiple Architectures +==================================== + + You can compile the package for more than one kind of computer at the +same time, by placing the object files for each architecture in their +own directory. To do this, you can use GNU `make'. `cd' to the +directory where you want the object files and executables to go and run +the `configure' script. `configure' automatically checks for the +source code in the directory that `configure' is in and in `..'. This +is known as a "VPATH" build. + + With a non-GNU `make', it is safer to compile the package for one +architecture at a time in the source code directory. After you have +installed the package for one architecture, use `make distclean' before +reconfiguring for another architecture. + + On MacOS X 10.5 and later systems, you can create libraries and +executables that work on multiple system types--known as "fat" or +"universal" binaries--by specifying multiple `-arch' options to the +compiler but only a single `-arch' option to the preprocessor. Like +this: + + ./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ + CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ + CPP="gcc -E" CXXCPP="g++ -E" + + This is not guaranteed to produce working output in all cases, you +may have to build one architecture at a time and combine the results +using the `lipo' tool if you have problems. + +Installation Names +================== + + By default, `make install' installs the package's commands under +`/usr/local/bin', include files under `/usr/local/include', etc. You +can specify an installation prefix other than `/usr/local' by giving +`configure' the option `--prefix=PREFIX', where PREFIX must be an +absolute file name. + + You can specify separate installation prefixes for +architecture-specific files and architecture-independent files. If you +pass the option `--exec-prefix=PREFIX' to `configure', the package uses +PREFIX as the prefix for installing programs and libraries. +Documentation and other data files still use the regular prefix. + + In addition, if you use an unusual directory layout you can give +options like `--bindir=DIR' to specify different values for particular +kinds of files. Run `configure --help' for a list of the directories +you can set and what kinds of files go in them. In general, the +default for these options is expressed in terms of `${prefix}', so that +specifying just `--prefix' will affect all of the other directory +specifications that were not explicitly provided. + + The most portable way to affect installation locations is to pass the +correct locations to `configure'; however, many packages provide one or +both of the following shortcuts of passing variable assignments to the +`make install' command line to change installation locations without +having to reconfigure or recompile. + + The first method involves providing an override variable for each +affected directory. For example, `make install +prefix=/alternate/directory' will choose an alternate location for all +directory configuration variables that were expressed in terms of +`${prefix}'. Any directories that were specified during `configure', +but not in terms of `${prefix}', must each be overridden at install +time for the entire installation to be relocated. The approach of +makefile variable overrides for each directory variable is required by +the GNU Coding Standards, and ideally causes no recompilation. +However, some platforms have known limitations with the semantics of +shared libraries that end up requiring recompilation when using this +method, particularly noticeable in packages that use GNU Libtool. + + The second method involves providing the `DESTDIR' variable. For +example, `make install DESTDIR=/alternate/directory' will prepend +`/alternate/directory' before all installation names. The approach of +`DESTDIR' overrides is not required by the GNU Coding Standards, and +does not work on platforms that have drive letters. On the other hand, +it does better at avoiding recompilation issues, and works well even +when some directory options were not specified in terms of `${prefix}' +at `configure' time. + +Optional Features +================= + + If the package supports it, you can cause programs to be installed +with an extra prefix or suffix on their names by giving `configure' the +option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. + + Some packages pay attention to `--enable-FEATURE' options to +`configure', where FEATURE indicates an optional part of the package. +They may also pay attention to `--with-PACKAGE' options, where PACKAGE +is something like `gnu-as' or `x' (for the X Window System). The +`README' should mention any `--enable-' and `--with-' options that the +package recognizes. + + For packages that use the X Window System, `configure' can usually +find the X include and library files automatically, but if it doesn't, +you can use the `configure' options `--x-includes=DIR' and +`--x-libraries=DIR' to specify their locations. + + Some packages offer the ability to configure how verbose the +execution of `make' will be. For these packages, running `./configure +--enable-silent-rules' sets the default to minimal output, which can be +overridden with `make V=1'; while running `./configure +--disable-silent-rules' sets the default to verbose, which can be +overridden with `make V=0'. + +Particular systems +================== + + On HP-UX, the default C compiler is not ANSI C compatible. If GNU +CC is not installed, it is recommended to use the following options in +order to use an ANSI C compiler: + + ./configure CC="cc -Ae -D_XOPEN_SOURCE=500" + +and if that doesn't work, install pre-built binaries of GCC for HP-UX. + + HP-UX `make' updates targets which have the same time stamps as +their prerequisites, which makes it generally unusable when shipped +generated files such as `configure' are involved. Use GNU `make' +instead. + + On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot +parse its `' header file. The option `-nodtk' can be used as +a workaround. If GNU CC is not installed, it is therefore recommended +to try + + ./configure CC="cc" + +and if that doesn't work, try + + ./configure CC="cc -nodtk" + + On Solaris, don't put `/usr/ucb' early in your `PATH'. This +directory contains several dysfunctional programs; working variants of +these programs are available in `/usr/bin'. So, if you need `/usr/ucb' +in your `PATH', put it _after_ `/usr/bin'. + + On Haiku, software installed for all users goes in `/boot/common', +not `/usr/local'. It is recommended to use the following options: + + ./configure --prefix=/boot/common + +Specifying the System Type +========================== + + There may be some features `configure' cannot figure out +automatically, but needs to determine by the type of machine the package +will run on. Usually, assuming the package is built to be run on the +_same_ architectures, `configure' can figure that out, but if it prints +a message saying it cannot guess the machine type, give it the +`--build=TYPE' option. TYPE can either be a short name for the system +type, such as `sun4', or a canonical name which has the form: + + CPU-COMPANY-SYSTEM + +where SYSTEM can have one of these forms: + + OS + KERNEL-OS + + See the file `config.sub' for the possible values of each field. If +`config.sub' isn't included in this package, then this package doesn't +need to know the machine type. + + If you are _building_ compiler tools for cross-compiling, you should +use the option `--target=TYPE' to select the type of system they will +produce code for. + + If you want to _use_ a cross compiler, that generates code for a +platform different from the build platform, you should specify the +"host" platform (i.e., that on which the generated programs will +eventually be run) with `--host=TYPE'. + +Sharing Defaults +================ + + If you want to set default values for `configure' scripts to share, +you can create a site shell script called `config.site' that gives +default values for variables like `CC', `cache_file', and `prefix'. +`configure' looks for `PREFIX/share/config.site' if it exists, then +`PREFIX/etc/config.site' if it exists. Or, you can set the +`CONFIG_SITE' environment variable to the location of the site script. +A warning: not all `configure' scripts look for a site script. + +Defining Variables +================== + + Variables not defined in a site shell script can be set in the +environment passed to `configure'. However, some packages may run +configure again during the build, and the customized values of these +variables may be lost. In order to avoid this problem, you should set +them in the `configure' command line, using `VAR=value'. For example: + + ./configure CC=/usr/local2/bin/gcc + +causes the specified `gcc' to be used as the C compiler (unless it is +overridden in the site shell script). + +Unfortunately, this technique does not work for `CONFIG_SHELL' due to +an Autoconf limitation. Until the limitation is lifted, you can use +this workaround: + + CONFIG_SHELL=/bin/bash ./configure CONFIG_SHELL=/bin/bash + +`configure' Invocation +====================== + + `configure' recognizes the following options to control how it +operates. + +`--help' +`-h' + Print a summary of all of the options to `configure', and exit. + +`--help=short' +`--help=recursive' + Print a summary of the options unique to this package's + `configure', and exit. The `short' variant lists options used + only in the top level, while the `recursive' variant lists options + also present in any nested packages. + +`--version' +`-V' + Print the version of Autoconf used to generate the `configure' + script, and exit. + +`--cache-file=FILE' + Enable the cache: use and save the results of the tests in FILE, + traditionally `config.cache'. FILE defaults to `/dev/null' to + disable caching. + +`--config-cache' +`-C' + Alias for `--cache-file=config.cache'. + +`--quiet' +`--silent' +`-q' + Do not print messages saying which checks are being made. To + suppress all normal output, redirect it to `/dev/null' (any error + messages will still be shown). + +`--srcdir=DIR' + Look for the package's source code in directory DIR. Usually + `configure' can determine that directory automatically. + +`--prefix=DIR' + Use DIR as the installation prefix. *note Installation Names:: + for more details, including other options available for fine-tuning + the installation locations. + +`--no-create' +`-n' + Run the configure checks, but stop before creating any output + files. + +`configure' also accepts some other, not widely useful, options. Run +`configure --help' for more details. diff --git a/extern/portaudio/bindings/cpp/Makefile.am b/extern/portaudio/bindings/cpp/Makefile.am new file mode 100644 index 0000000..b10449c --- /dev/null +++ b/extern/portaudio/bindings/cpp/Makefile.am @@ -0,0 +1,7 @@ +SUBDIRS = lib include bin +#doc + +EXTRA_DIST = portaudiocpp.pc + +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = portaudiocpp.pc diff --git a/extern/portaudio/bindings/cpp/Makefile.in b/extern/portaudio/bindings/cpp/Makefile.in new file mode 100644 index 0000000..a397933 --- /dev/null +++ b/extern/portaudio/bindings/cpp/Makefile.in @@ -0,0 +1,848 @@ +# Makefile.in generated by automake 1.14.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2013 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = . +DIST_COMMON = INSTALL NEWS README AUTHORS ChangeLog \ + $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ + $(top_srcdir)/configure $(am__configure_deps) \ + $(srcdir)/portaudiocpp.pc.in COPYING \ + $(top_srcdir)/../../compile $(top_srcdir)/../../config.guess \ + $(top_srcdir)/../../config.sub $(top_srcdir)/../../install-sh \ + $(top_srcdir)/../../ltmain.sh $(top_srcdir)/../../missing +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ + configure.lineno config.status.lineno +mkinstalldirs = $(install_sh) -d +CONFIG_CLEAN_FILES = portaudiocpp.pc +CONFIG_CLEAN_VPATH_FILES = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +SOURCES = +DIST_SOURCES = +RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ + ctags-recursive dvi-recursive html-recursive info-recursive \ + install-data-recursive install-dvi-recursive \ + install-exec-recursive install-html-recursive \ + install-info-recursive install-pdf-recursive \ + install-ps-recursive install-recursive installcheck-recursive \ + installdirs-recursive pdf-recursive ps-recursive \ + tags-recursive uninstall-recursive +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__uninstall_files_from_dir = { \ + test -z "$$files" \ + || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ + || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ + $(am__cd) "$$dir" && rm -f $$files; }; \ + } +am__installdirs = "$(DESTDIR)$(pkgconfigdir)" +DATA = $(pkgconfig_DATA) +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +am__recursive_targets = \ + $(RECURSIVE_TARGETS) \ + $(RECURSIVE_CLEAN_TARGETS) \ + $(am__extra_recursive_targets) +AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ + cscope distdir dist dist-all distcheck +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +CSCOPE = cscope +DIST_SUBDIRS = $(SUBDIRS) +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +distdir = $(PACKAGE)-$(VERSION) +top_distdir = $(distdir) +am__remove_distdir = \ + if test -d "$(distdir)"; then \ + find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \ + && rm -rf "$(distdir)" \ + || { sleep 5 && rm -rf "$(distdir)"; }; \ + else :; fi +am__post_remove_distdir = $(am__remove_distdir) +am__relativize = \ + dir0=`pwd`; \ + sed_first='s,^\([^/]*\)/.*$$,\1,'; \ + sed_rest='s,^[^/]*/*,,'; \ + sed_last='s,^.*/\([^/]*\)$$,\1,'; \ + sed_butlast='s,/*[^/]*$$,,'; \ + while test -n "$$dir1"; do \ + first=`echo "$$dir1" | sed -e "$$sed_first"`; \ + if test "$$first" != "."; then \ + if test "$$first" = ".."; then \ + dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ + dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ + else \ + first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ + if test "$$first2" = "$$first"; then \ + dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ + else \ + dir2="../$$dir2"; \ + fi; \ + dir0="$$dir0"/"$$first"; \ + fi; \ + fi; \ + dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ + done; \ + reldir="$$dir2" +DIST_ARCHIVES = $(distdir).tar.gz +GZIP_ENV = --best +DIST_TARGETS = dist-gzip +distuninstallcheck_listfiles = find . -type f -print +am__distuninstallcheck_listfiles = $(distuninstallcheck_listfiles) \ + | sed 's|^\./|$(prefix)/|' | grep -v '$(infodir)/dir$$' +distcleancheck_listfiles = find . -type f -print +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFAULT_INCLUDES = @DEFAULT_INCLUDES@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_VERSION_INFO = @LT_VERSION_INFO@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PORTAUDIO_ROOT = @PORTAUDIO_ROOT@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +SUBDIRS = lib include bin +#doc +EXTRA_DIST = portaudiocpp.pc +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = portaudiocpp.pc +all: all-recursive + +.SUFFIXES: +am--refresh: Makefile + @: +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + echo ' cd $(srcdir) && $(AUTOMAKE) --gnu'; \ + $(am__cd) $(srcdir) && $(AUTOMAKE) --gnu \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + echo ' $(SHELL) ./config.status'; \ + $(SHELL) ./config.status;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + $(SHELL) ./config.status --recheck + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + $(am__cd) $(srcdir) && $(AUTOCONF) +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + $(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) +$(am__aclocal_m4_deps): +portaudiocpp.pc: $(top_builddir)/config.status $(srcdir)/portaudiocpp.pc.in + cd $(top_builddir) && $(SHELL) ./config.status $@ + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +distclean-libtool: + -rm -f libtool config.lt +install-pkgconfigDATA: $(pkgconfig_DATA) + @$(NORMAL_INSTALL) + @list='$(pkgconfig_DATA)'; test -n "$(pkgconfigdir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(pkgconfigdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(pkgconfigdir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgconfigdir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgconfigdir)" || exit $$?; \ + done + +uninstall-pkgconfigDATA: + @$(NORMAL_UNINSTALL) + @list='$(pkgconfig_DATA)'; test -n "$(pkgconfigdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + dir='$(DESTDIR)$(pkgconfigdir)'; $(am__uninstall_files_from_dir) + +# This directory's subdirectories are mostly independent; you can cd +# into them and run 'make' without going through this Makefile. +# To change the values of 'make' variables: instead of editing Makefiles, +# (1) if the variable is set in 'config.status', edit 'config.status' +# (which will cause the Makefiles to be regenerated when you run 'make'); +# (2) otherwise, pass the desired values on the 'make' command line. +$(am__recursive_targets): + @fail=; \ + if $(am__make_keepgoing); then \ + failcom='fail=yes'; \ + else \ + failcom='exit 1'; \ + fi; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-recursive +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-recursive + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscope: cscope.files + test ! -s cscope.files \ + || $(CSCOPE) -b -q $(AM_CSCOPEFLAGS) $(CSCOPEFLAGS) -i cscope.files $(CSCOPE_ARGS) +clean-cscope: + -rm -f cscope.files +cscope.files: clean-cscope cscopelist +cscopelist: cscopelist-recursive + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + -rm -f cscope.out cscope.in.out cscope.po.out cscope.files + +distdir: $(DISTFILES) + $(am__remove_distdir) + test -d "$(distdir)" || mkdir "$(distdir)" + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + $(am__make_dryrun) \ + || test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ + $(am__relativize); \ + new_distdir=$$reldir; \ + dir1=$$subdir; dir2="$(top_distdir)"; \ + $(am__relativize); \ + new_top_distdir=$$reldir; \ + echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ + echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ + ($(am__cd) $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$new_top_distdir" \ + distdir="$$new_distdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + am__skip_mode_fix=: \ + distdir) \ + || exit 1; \ + fi; \ + done + -test -n "$(am__skip_mode_fix)" \ + || find "$(distdir)" -type d ! -perm -755 \ + -exec chmod u+rwx,go+rx {} \; -o \ + ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ + ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ + ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \ + || chmod -R a+r "$(distdir)" +dist-gzip: distdir + tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz + $(am__post_remove_distdir) + +dist-bzip2: distdir + tardir=$(distdir) && $(am__tar) | BZIP2=$${BZIP2--9} bzip2 -c >$(distdir).tar.bz2 + $(am__post_remove_distdir) + +dist-lzip: distdir + tardir=$(distdir) && $(am__tar) | lzip -c $${LZIP_OPT--9} >$(distdir).tar.lz + $(am__post_remove_distdir) + +dist-xz: distdir + tardir=$(distdir) && $(am__tar) | XZ_OPT=$${XZ_OPT--e} xz -c >$(distdir).tar.xz + $(am__post_remove_distdir) + +dist-tarZ: distdir + @echo WARNING: "Support for shar distribution archives is" \ + "deprecated." >&2 + @echo WARNING: "It will be removed altogether in Automake 2.0" >&2 + tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z + $(am__post_remove_distdir) + +dist-shar: distdir + @echo WARNING: "Support for distribution archives compressed with" \ + "legacy program 'compress' is deprecated." >&2 + @echo WARNING: "It will be removed altogether in Automake 2.0" >&2 + shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz + $(am__post_remove_distdir) + +dist-zip: distdir + -rm -f $(distdir).zip + zip -rq $(distdir).zip $(distdir) + $(am__post_remove_distdir) + +dist dist-all: + $(MAKE) $(AM_MAKEFLAGS) $(DIST_TARGETS) am__post_remove_distdir='@:' + $(am__post_remove_distdir) + +# This target untars the dist file and tries a VPATH configuration. Then +# it guarantees that the distribution is self-contained by making another +# tarfile. +distcheck: dist + case '$(DIST_ARCHIVES)' in \ + *.tar.gz*) \ + GZIP=$(GZIP_ENV) gzip -dc $(distdir).tar.gz | $(am__untar) ;;\ + *.tar.bz2*) \ + bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\ + *.tar.lz*) \ + lzip -dc $(distdir).tar.lz | $(am__untar) ;;\ + *.tar.xz*) \ + xz -dc $(distdir).tar.xz | $(am__untar) ;;\ + *.tar.Z*) \ + uncompress -c $(distdir).tar.Z | $(am__untar) ;;\ + *.shar.gz*) \ + GZIP=$(GZIP_ENV) gzip -dc $(distdir).shar.gz | unshar ;;\ + *.zip*) \ + unzip $(distdir).zip ;;\ + esac + chmod -R a-w $(distdir) + chmod u+w $(distdir) + mkdir $(distdir)/_build $(distdir)/_inst + chmod a-w $(distdir) + test -d $(distdir)/_build || exit 0; \ + dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ + && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ + && am__cwd=`pwd` \ + && $(am__cd) $(distdir)/_build \ + && ../configure \ + $(AM_DISTCHECK_CONFIGURE_FLAGS) \ + $(DISTCHECK_CONFIGURE_FLAGS) \ + --srcdir=.. --prefix="$$dc_install_base" \ + && $(MAKE) $(AM_MAKEFLAGS) \ + && $(MAKE) $(AM_MAKEFLAGS) dvi \ + && $(MAKE) $(AM_MAKEFLAGS) check \ + && $(MAKE) $(AM_MAKEFLAGS) install \ + && $(MAKE) $(AM_MAKEFLAGS) installcheck \ + && $(MAKE) $(AM_MAKEFLAGS) uninstall \ + && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \ + distuninstallcheck \ + && chmod -R a-w "$$dc_install_base" \ + && ({ \ + (cd ../.. && umask 077 && mkdir "$$dc_destdir") \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \ + distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \ + } || { rm -rf "$$dc_destdir"; exit 1; }) \ + && rm -rf "$$dc_destdir" \ + && $(MAKE) $(AM_MAKEFLAGS) dist \ + && rm -rf $(DIST_ARCHIVES) \ + && $(MAKE) $(AM_MAKEFLAGS) distcleancheck \ + && cd "$$am__cwd" \ + || exit 1 + $(am__post_remove_distdir) + @(echo "$(distdir) archives ready for distribution: "; \ + list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \ + sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x' +distuninstallcheck: + @test -n '$(distuninstallcheck_dir)' || { \ + echo 'ERROR: trying to run $@ with an empty' \ + '$$(distuninstallcheck_dir)' >&2; \ + exit 1; \ + }; \ + $(am__cd) '$(distuninstallcheck_dir)' || { \ + echo 'ERROR: cannot chdir into $(distuninstallcheck_dir)' >&2; \ + exit 1; \ + }; \ + test `$(am__distuninstallcheck_listfiles) | wc -l` -eq 0 \ + || { echo "ERROR: files left after uninstall:" ; \ + if test -n "$(DESTDIR)"; then \ + echo " (check DESTDIR support)"; \ + fi ; \ + $(distuninstallcheck_listfiles) ; \ + exit 1; } >&2 +distcleancheck: distclean + @if test '$(srcdir)' = . ; then \ + echo "ERROR: distcleancheck can only run from a VPATH build" ; \ + exit 1 ; \ + fi + @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \ + || { echo "ERROR: files left in build directory after distclean:" ; \ + $(distcleancheck_listfiles) ; \ + exit 1; } >&2 +check-am: all-am +check: check-recursive +all-am: Makefile $(DATA) +installdirs: installdirs-recursive +installdirs-am: + for dir in "$(DESTDIR)$(pkgconfigdir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-recursive + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-recursive + -rm -f $(am__CONFIG_DISTCLEAN_FILES) + -rm -f Makefile +distclean-am: clean-am distclean-generic distclean-libtool \ + distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +html-am: + +info: info-recursive + +info-am: + +install-data-am: install-pkgconfigDATA + +install-dvi: install-dvi-recursive + +install-dvi-am: + +install-exec-am: + +install-html: install-html-recursive + +install-html-am: + +install-info: install-info-recursive + +install-info-am: + +install-man: + +install-pdf: install-pdf-recursive + +install-pdf-am: + +install-ps: install-ps-recursive + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -f $(am__CONFIG_DISTCLEAN_FILES) + -rm -rf $(top_srcdir)/autom4te.cache + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: uninstall-pkgconfigDATA + +.MAKE: $(am__recursive_targets) install-am install-strip + +.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am \ + am--refresh check check-am clean clean-cscope clean-generic \ + clean-libtool cscope cscopelist-am ctags ctags-am dist \ + dist-all dist-bzip2 dist-gzip dist-lzip dist-shar dist-tarZ \ + dist-xz dist-zip distcheck distclean distclean-generic \ + distclean-libtool distclean-tags distcleancheck distdir \ + distuninstallcheck dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-pkgconfigDATA install-ps \ + install-ps-am install-strip installcheck installcheck-am \ + installdirs installdirs-am maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \ + uninstall-am uninstall-pkgconfigDATA + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/extern/portaudio/bindings/cpp/NEWS b/extern/portaudio/bindings/cpp/NEWS new file mode 100644 index 0000000..e69de29 diff --git a/extern/portaudio/bindings/cpp/README b/extern/portaudio/bindings/cpp/README new file mode 100644 index 0000000..e69de29 diff --git a/extern/portaudio/bindings/cpp/SConscript b/extern/portaudio/bindings/cpp/SConscript new file mode 100644 index 0000000..e69b93a --- /dev/null +++ b/extern/portaudio/bindings/cpp/SConscript @@ -0,0 +1,65 @@ +import os.path + +Import("env", "buildDir") +env.Append(CPPPATH="include") + +ApiVer = "0.0.12" +Major, Minor, Micro = [int(c) for c in ApiVer.split(".")] + +sharedLibs = [] +staticLibs = [] +Import("Platform", "Posix") +if Platform in Posix: + env["SHLIBSUFFIX"] = ".so.%d.%d.%d" % (Major, Minor, Micro) + soFile = "libportaudiocpp.so" + if Platform != 'darwin': + env.AppendUnique(SHLINKFLAGS="-Wl,-soname=%s.%d" % (soFile, Major)) + + # Create symlinks + def symlink(env, target, source): + trgt = str(target[0]) + src = str(source[0]) + if os.path.islink(trgt) or os.path.exists(trgt): + os.remove(trgt) + os.symlink(os.path.basename(src), trgt) + lnk0 = env.Command(soFile + ".%d" % (Major), soFile + ".%d.%d.%d" % (Major, Minor, Micro), symlink) + lnk1 = env.Command(soFile, soFile + ".%d" % (Major), symlink) + sharedLibs.append(lnk0) + sharedLibs.append(lnk1) + +src = [os.path.join("source", "portaudiocpp", "%s.cxx" % f) for f in ("BlockingStream", "CallbackInterface", \ + "CallbackStream", "CFunCallbackStream","CppFunCallbackStream", "Device", + "DirectionSpecificStreamParameters", "Exception", "HostApi", "InterfaceCallbackStream", + "MemFunCallbackStream", "Stream", "StreamParameters", "System", "SystemDeviceIterator", + "SystemHostApiIterator")] +env.Append(LIBS="portaudio", LIBPATH=buildDir) +sharedLib = env.SharedLibrary("portaudiocpp", src, LIBS=["portaudio"]) +staticLib = env.Library("portaudiocpp", src, LIBS=["portaudio"]) +sharedLibs.append(sharedLib) +staticLibs.append(staticLib) + +headers = Split("""AutoSystem.hxx + BlockingStream.hxx + CallbackInterface.hxx + CallbackStream.hxx + CFunCallbackStream.hxx + CppFunCallbackStream.hxx + Device.hxx + DirectionSpecificStreamParameters.hxx + Exception.hxx + HostApi.hxx + InterfaceCallbackStream.hxx + MemFunCallbackStream.hxx + PortAudioCpp.hxx + SampleDataFormat.hxx + Stream.hxx + StreamParameters.hxx + SystemDeviceIterator.hxx + SystemHostApiIterator.hxx + System.hxx + """) +if env["PLATFORM"] == "win32": + headers.append("AsioDeviceAdapter.hxx") +headers = [File(os.path.join("include", "portaudiocpp", h)) for h in headers] + +Return("sharedLibs", "staticLibs", "headers") diff --git a/extern/portaudio/bindings/cpp/aclocal.m4 b/extern/portaudio/bindings/cpp/aclocal.m4 new file mode 100644 index 0000000..68c908f --- /dev/null +++ b/extern/portaudio/bindings/cpp/aclocal.m4 @@ -0,0 +1,9787 @@ +# generated automatically by aclocal 1.14.1 -*- Autoconf -*- + +# Copyright (C) 1996-2013 Free Software Foundation, Inc. + +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])]) +m4_ifndef([AC_AUTOCONF_VERSION], + [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl +m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.69],, +[m4_warning([this file was generated for autoconf 2.69. +You have another version of autoconf. It may work, but is not guaranteed to. +If you have problems, you may need to regenerate the build system entirely. +To do so, use the procedure documented by the package, typically 'autoreconf'.])]) + +# libtool.m4 - Configure libtool for the host system. -*-Autoconf-*- +# +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, +# 2006, 2007, 2008, 2009, 2010, 2011 Free Software +# Foundation, Inc. +# Written by Gordon Matzigkeit, 1996 +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. + +m4_define([_LT_COPYING], [dnl +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, +# 2006, 2007, 2008, 2009, 2010, 2011 Free Software +# Foundation, Inc. +# Written by Gordon Matzigkeit, 1996 +# +# This file is part of GNU Libtool. +# +# GNU Libtool is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# As a special exception to the GNU General Public License, +# if you distribute this file as part of a program or library that +# is built using GNU Libtool, you may include this file under the +# same distribution terms that you use for the rest of that program. +# +# GNU Libtool is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Libtool; see the file COPYING. If not, a copy +# can be downloaded from http://www.gnu.org/licenses/gpl.html, or +# obtained by writing to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +]) + +# serial 57 LT_INIT + + +# LT_PREREQ(VERSION) +# ------------------ +# Complain and exit if this libtool version is less that VERSION. +m4_defun([LT_PREREQ], +[m4_if(m4_version_compare(m4_defn([LT_PACKAGE_VERSION]), [$1]), -1, + [m4_default([$3], + [m4_fatal([Libtool version $1 or higher is required], + 63)])], + [$2])]) + + +# _LT_CHECK_BUILDDIR +# ------------------ +# Complain if the absolute build directory name contains unusual characters +m4_defun([_LT_CHECK_BUILDDIR], +[case `pwd` in + *\ * | *\ *) + AC_MSG_WARN([Libtool does not cope well with whitespace in `pwd`]) ;; +esac +]) + + +# LT_INIT([OPTIONS]) +# ------------------ +AC_DEFUN([LT_INIT], +[AC_PREREQ([2.58])dnl We use AC_INCLUDES_DEFAULT +AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl +AC_BEFORE([$0], [LT_LANG])dnl +AC_BEFORE([$0], [LT_OUTPUT])dnl +AC_BEFORE([$0], [LTDL_INIT])dnl +m4_require([_LT_CHECK_BUILDDIR])dnl + +dnl Autoconf doesn't catch unexpanded LT_ macros by default: +m4_pattern_forbid([^_?LT_[A-Z_]+$])dnl +m4_pattern_allow([^(_LT_EOF|LT_DLGLOBAL|LT_DLLAZY_OR_NOW|LT_MULTI_MODULE)$])dnl +dnl aclocal doesn't pull ltoptions.m4, ltsugar.m4, or ltversion.m4 +dnl unless we require an AC_DEFUNed macro: +AC_REQUIRE([LTOPTIONS_VERSION])dnl +AC_REQUIRE([LTSUGAR_VERSION])dnl +AC_REQUIRE([LTVERSION_VERSION])dnl +AC_REQUIRE([LTOBSOLETE_VERSION])dnl +m4_require([_LT_PROG_LTMAIN])dnl + +_LT_SHELL_INIT([SHELL=${CONFIG_SHELL-/bin/sh}]) + +dnl Parse OPTIONS +_LT_SET_OPTIONS([$0], [$1]) + +# This can be used to rebuild libtool when needed +LIBTOOL_DEPS="$ltmain" + +# Always use our own libtool. +LIBTOOL='$(SHELL) $(top_builddir)/libtool' +AC_SUBST(LIBTOOL)dnl + +_LT_SETUP + +# Only expand once: +m4_define([LT_INIT]) +])# LT_INIT + +# Old names: +AU_ALIAS([AC_PROG_LIBTOOL], [LT_INIT]) +AU_ALIAS([AM_PROG_LIBTOOL], [LT_INIT]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_PROG_LIBTOOL], []) +dnl AC_DEFUN([AM_PROG_LIBTOOL], []) + + +# _LT_CC_BASENAME(CC) +# ------------------- +# Calculate cc_basename. Skip known compiler wrappers and cross-prefix. +m4_defun([_LT_CC_BASENAME], +[for cc_temp in $1""; do + case $cc_temp in + compile | *[[\\/]]compile | ccache | *[[\\/]]ccache ) ;; + distcc | *[[\\/]]distcc | purify | *[[\\/]]purify ) ;; + \-*) ;; + *) break;; + esac +done +cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` +]) + + +# _LT_FILEUTILS_DEFAULTS +# ---------------------- +# It is okay to use these file commands and assume they have been set +# sensibly after `m4_require([_LT_FILEUTILS_DEFAULTS])'. +m4_defun([_LT_FILEUTILS_DEFAULTS], +[: ${CP="cp -f"} +: ${MV="mv -f"} +: ${RM="rm -f"} +])# _LT_FILEUTILS_DEFAULTS + + +# _LT_SETUP +# --------- +m4_defun([_LT_SETUP], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_CANONICAL_BUILD])dnl +AC_REQUIRE([_LT_PREPARE_SED_QUOTE_VARS])dnl +AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])dnl + +_LT_DECL([], [PATH_SEPARATOR], [1], [The PATH separator for the build system])dnl +dnl +_LT_DECL([], [host_alias], [0], [The host system])dnl +_LT_DECL([], [host], [0])dnl +_LT_DECL([], [host_os], [0])dnl +dnl +_LT_DECL([], [build_alias], [0], [The build system])dnl +_LT_DECL([], [build], [0])dnl +_LT_DECL([], [build_os], [0])dnl +dnl +AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([LT_PATH_LD])dnl +AC_REQUIRE([LT_PATH_NM])dnl +dnl +AC_REQUIRE([AC_PROG_LN_S])dnl +test -z "$LN_S" && LN_S="ln -s" +_LT_DECL([], [LN_S], [1], [Whether we need soft or hard links])dnl +dnl +AC_REQUIRE([LT_CMD_MAX_LEN])dnl +_LT_DECL([objext], [ac_objext], [0], [Object file suffix (normally "o")])dnl +_LT_DECL([], [exeext], [0], [Executable file suffix (normally "")])dnl +dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_CHECK_SHELL_FEATURES])dnl +m4_require([_LT_PATH_CONVERSION_FUNCTIONS])dnl +m4_require([_LT_CMD_RELOAD])dnl +m4_require([_LT_CHECK_MAGIC_METHOD])dnl +m4_require([_LT_CHECK_SHAREDLIB_FROM_LINKLIB])dnl +m4_require([_LT_CMD_OLD_ARCHIVE])dnl +m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl +m4_require([_LT_WITH_SYSROOT])dnl + +_LT_CONFIG_LIBTOOL_INIT([ +# See if we are running on zsh, and set the options which allow our +# commands through without removal of \ escapes INIT. +if test -n "\${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST +fi +]) +if test -n "${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST +fi + +_LT_CHECK_OBJDIR + +m4_require([_LT_TAG_COMPILER])dnl + +case $host_os in +aix3*) + # AIX sometimes has problems with the GCC collect2 program. For some + # reason, if we set the COLLECT_NAMES environment variable, the problems + # vanish in a puff of smoke. + if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES + fi + ;; +esac + +# Global variables: +ofile=libtool +can_build_shared=yes + +# All known linkers require a `.a' archive for static linking (except MSVC, +# which needs '.lib'). +libext=a + +with_gnu_ld="$lt_cv_prog_gnu_ld" + +old_CC="$CC" +old_CFLAGS="$CFLAGS" + +# Set sane defaults for various variables +test -z "$CC" && CC=cc +test -z "$LTCC" && LTCC=$CC +test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS +test -z "$LD" && LD=ld +test -z "$ac_objext" && ac_objext=o + +_LT_CC_BASENAME([$compiler]) + +# Only perform the check for file, if the check method requires it +test -z "$MAGIC_CMD" && MAGIC_CMD=file +case $deplibs_check_method in +file_magic*) + if test "$file_magic_cmd" = '$MAGIC_CMD'; then + _LT_PATH_MAGIC + fi + ;; +esac + +# Use C for the default configuration in the libtool script +LT_SUPPORTED_TAG([CC]) +_LT_LANG_C_CONFIG +_LT_LANG_DEFAULT_CONFIG +_LT_CONFIG_COMMANDS +])# _LT_SETUP + + +# _LT_PREPARE_SED_QUOTE_VARS +# -------------------------- +# Define a few sed substitution that help us do robust quoting. +m4_defun([_LT_PREPARE_SED_QUOTE_VARS], +[# Backslashify metacharacters that are still active within +# double-quoted strings. +sed_quote_subst='s/\([["`$\\]]\)/\\\1/g' + +# Same as above, but do not quote variable references. +double_quote_subst='s/\([["`\\]]\)/\\\1/g' + +# Sed substitution to delay expansion of an escaped shell variable in a +# double_quote_subst'ed string. +delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' + +# Sed substitution to delay expansion of an escaped single quote. +delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g' + +# Sed substitution to avoid accidental globbing in evaled expressions +no_glob_subst='s/\*/\\\*/g' +]) + +# _LT_PROG_LTMAIN +# --------------- +# Note that this code is called both from `configure', and `config.status' +# now that we use AC_CONFIG_COMMANDS to generate libtool. Notably, +# `config.status' has no value for ac_aux_dir unless we are using Automake, +# so we pass a copy along to make sure it has a sensible value anyway. +m4_defun([_LT_PROG_LTMAIN], +[m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([ltmain.sh])])dnl +_LT_CONFIG_LIBTOOL_INIT([ac_aux_dir='$ac_aux_dir']) +ltmain="$ac_aux_dir/ltmain.sh" +])# _LT_PROG_LTMAIN + + + +# So that we can recreate a full libtool script including additional +# tags, we accumulate the chunks of code to send to AC_CONFIG_COMMANDS +# in macros and then make a single call at the end using the `libtool' +# label. + + +# _LT_CONFIG_LIBTOOL_INIT([INIT-COMMANDS]) +# ---------------------------------------- +# Register INIT-COMMANDS to be passed to AC_CONFIG_COMMANDS later. +m4_define([_LT_CONFIG_LIBTOOL_INIT], +[m4_ifval([$1], + [m4_append([_LT_OUTPUT_LIBTOOL_INIT], + [$1 +])])]) + +# Initialize. +m4_define([_LT_OUTPUT_LIBTOOL_INIT]) + + +# _LT_CONFIG_LIBTOOL([COMMANDS]) +# ------------------------------ +# Register COMMANDS to be passed to AC_CONFIG_COMMANDS later. +m4_define([_LT_CONFIG_LIBTOOL], +[m4_ifval([$1], + [m4_append([_LT_OUTPUT_LIBTOOL_COMMANDS], + [$1 +])])]) + +# Initialize. +m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS]) + + +# _LT_CONFIG_SAVE_COMMANDS([COMMANDS], [INIT_COMMANDS]) +# ----------------------------------------------------- +m4_defun([_LT_CONFIG_SAVE_COMMANDS], +[_LT_CONFIG_LIBTOOL([$1]) +_LT_CONFIG_LIBTOOL_INIT([$2]) +]) + + +# _LT_FORMAT_COMMENT([COMMENT]) +# ----------------------------- +# Add leading comment marks to the start of each line, and a trailing +# full-stop to the whole comment if one is not present already. +m4_define([_LT_FORMAT_COMMENT], +[m4_ifval([$1], [ +m4_bpatsubst([m4_bpatsubst([$1], [^ *], [# ])], + [['`$\]], [\\\&])]m4_bmatch([$1], [[!?.]$], [], [.]) +)]) + + + + + +# _LT_DECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION], [IS-TAGGED?]) +# ------------------------------------------------------------------- +# CONFIGNAME is the name given to the value in the libtool script. +# VARNAME is the (base) name used in the configure script. +# VALUE may be 0, 1 or 2 for a computed quote escaped value based on +# VARNAME. Any other value will be used directly. +m4_define([_LT_DECL], +[lt_if_append_uniq([lt_decl_varnames], [$2], [, ], + [lt_dict_add_subkey([lt_decl_dict], [$2], [libtool_name], + [m4_ifval([$1], [$1], [$2])]) + lt_dict_add_subkey([lt_decl_dict], [$2], [value], [$3]) + m4_ifval([$4], + [lt_dict_add_subkey([lt_decl_dict], [$2], [description], [$4])]) + lt_dict_add_subkey([lt_decl_dict], [$2], + [tagged?], [m4_ifval([$5], [yes], [no])])]) +]) + + +# _LT_TAGDECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION]) +# -------------------------------------------------------- +m4_define([_LT_TAGDECL], [_LT_DECL([$1], [$2], [$3], [$4], [yes])]) + + +# lt_decl_tag_varnames([SEPARATOR], [VARNAME1...]) +# ------------------------------------------------ +m4_define([lt_decl_tag_varnames], +[_lt_decl_filter([tagged?], [yes], $@)]) + + +# _lt_decl_filter(SUBKEY, VALUE, [SEPARATOR], [VARNAME1..]) +# --------------------------------------------------------- +m4_define([_lt_decl_filter], +[m4_case([$#], + [0], [m4_fatal([$0: too few arguments: $#])], + [1], [m4_fatal([$0: too few arguments: $#: $1])], + [2], [lt_dict_filter([lt_decl_dict], [$1], [$2], [], lt_decl_varnames)], + [3], [lt_dict_filter([lt_decl_dict], [$1], [$2], [$3], lt_decl_varnames)], + [lt_dict_filter([lt_decl_dict], $@)])[]dnl +]) + + +# lt_decl_quote_varnames([SEPARATOR], [VARNAME1...]) +# -------------------------------------------------- +m4_define([lt_decl_quote_varnames], +[_lt_decl_filter([value], [1], $@)]) + + +# lt_decl_dquote_varnames([SEPARATOR], [VARNAME1...]) +# --------------------------------------------------- +m4_define([lt_decl_dquote_varnames], +[_lt_decl_filter([value], [2], $@)]) + + +# lt_decl_varnames_tagged([SEPARATOR], [VARNAME1...]) +# --------------------------------------------------- +m4_define([lt_decl_varnames_tagged], +[m4_assert([$# <= 2])dnl +_$0(m4_quote(m4_default([$1], [[, ]])), + m4_ifval([$2], [[$2]], [m4_dquote(lt_decl_tag_varnames)]), + m4_split(m4_normalize(m4_quote(_LT_TAGS)), [ ]))]) +m4_define([_lt_decl_varnames_tagged], +[m4_ifval([$3], [lt_combine([$1], [$2], [_], $3)])]) + + +# lt_decl_all_varnames([SEPARATOR], [VARNAME1...]) +# ------------------------------------------------ +m4_define([lt_decl_all_varnames], +[_$0(m4_quote(m4_default([$1], [[, ]])), + m4_if([$2], [], + m4_quote(lt_decl_varnames), + m4_quote(m4_shift($@))))[]dnl +]) +m4_define([_lt_decl_all_varnames], +[lt_join($@, lt_decl_varnames_tagged([$1], + lt_decl_tag_varnames([[, ]], m4_shift($@))))dnl +]) + + +# _LT_CONFIG_STATUS_DECLARE([VARNAME]) +# ------------------------------------ +# Quote a variable value, and forward it to `config.status' so that its +# declaration there will have the same value as in `configure'. VARNAME +# must have a single quote delimited value for this to work. +m4_define([_LT_CONFIG_STATUS_DECLARE], +[$1='`$ECHO "$][$1" | $SED "$delay_single_quote_subst"`']) + + +# _LT_CONFIG_STATUS_DECLARATIONS +# ------------------------------ +# We delimit libtool config variables with single quotes, so when +# we write them to config.status, we have to be sure to quote all +# embedded single quotes properly. In configure, this macro expands +# each variable declared with _LT_DECL (and _LT_TAGDECL) into: +# +# ='`$ECHO "$" | $SED "$delay_single_quote_subst"`' +m4_defun([_LT_CONFIG_STATUS_DECLARATIONS], +[m4_foreach([_lt_var], m4_quote(lt_decl_all_varnames), + [m4_n([_LT_CONFIG_STATUS_DECLARE(_lt_var)])])]) + + +# _LT_LIBTOOL_TAGS +# ---------------- +# Output comment and list of tags supported by the script +m4_defun([_LT_LIBTOOL_TAGS], +[_LT_FORMAT_COMMENT([The names of the tagged configurations supported by this script])dnl +available_tags="_LT_TAGS"dnl +]) + + +# _LT_LIBTOOL_DECLARE(VARNAME, [TAG]) +# ----------------------------------- +# Extract the dictionary values for VARNAME (optionally with TAG) and +# expand to a commented shell variable setting: +# +# # Some comment about what VAR is for. +# visible_name=$lt_internal_name +m4_define([_LT_LIBTOOL_DECLARE], +[_LT_FORMAT_COMMENT(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], + [description])))[]dnl +m4_pushdef([_libtool_name], + m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [libtool_name])))[]dnl +m4_case(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [value])), + [0], [_libtool_name=[$]$1], + [1], [_libtool_name=$lt_[]$1], + [2], [_libtool_name=$lt_[]$1], + [_libtool_name=lt_dict_fetch([lt_decl_dict], [$1], [value])])[]dnl +m4_ifval([$2], [_$2])[]m4_popdef([_libtool_name])[]dnl +]) + + +# _LT_LIBTOOL_CONFIG_VARS +# ----------------------- +# Produce commented declarations of non-tagged libtool config variables +# suitable for insertion in the LIBTOOL CONFIG section of the `libtool' +# script. Tagged libtool config variables (even for the LIBTOOL CONFIG +# section) are produced by _LT_LIBTOOL_TAG_VARS. +m4_defun([_LT_LIBTOOL_CONFIG_VARS], +[m4_foreach([_lt_var], + m4_quote(_lt_decl_filter([tagged?], [no], [], lt_decl_varnames)), + [m4_n([_LT_LIBTOOL_DECLARE(_lt_var)])])]) + + +# _LT_LIBTOOL_TAG_VARS(TAG) +# ------------------------- +m4_define([_LT_LIBTOOL_TAG_VARS], +[m4_foreach([_lt_var], m4_quote(lt_decl_tag_varnames), + [m4_n([_LT_LIBTOOL_DECLARE(_lt_var, [$1])])])]) + + +# _LT_TAGVAR(VARNAME, [TAGNAME]) +# ------------------------------ +m4_define([_LT_TAGVAR], [m4_ifval([$2], [$1_$2], [$1])]) + + +# _LT_CONFIG_COMMANDS +# ------------------- +# Send accumulated output to $CONFIG_STATUS. Thanks to the lists of +# variables for single and double quote escaping we saved from calls +# to _LT_DECL, we can put quote escaped variables declarations +# into `config.status', and then the shell code to quote escape them in +# for loops in `config.status'. Finally, any additional code accumulated +# from calls to _LT_CONFIG_LIBTOOL_INIT is expanded. +m4_defun([_LT_CONFIG_COMMANDS], +[AC_PROVIDE_IFELSE([LT_OUTPUT], + dnl If the libtool generation code has been placed in $CONFIG_LT, + dnl instead of duplicating it all over again into config.status, + dnl then we will have config.status run $CONFIG_LT later, so it + dnl needs to know what name is stored there: + [AC_CONFIG_COMMANDS([libtool], + [$SHELL $CONFIG_LT || AS_EXIT(1)], [CONFIG_LT='$CONFIG_LT'])], + dnl If the libtool generation code is destined for config.status, + dnl expand the accumulated commands and init code now: + [AC_CONFIG_COMMANDS([libtool], + [_LT_OUTPUT_LIBTOOL_COMMANDS], [_LT_OUTPUT_LIBTOOL_COMMANDS_INIT])]) +])#_LT_CONFIG_COMMANDS + + +# Initialize. +m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS_INIT], +[ + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +sed_quote_subst='$sed_quote_subst' +double_quote_subst='$double_quote_subst' +delay_variable_subst='$delay_variable_subst' +_LT_CONFIG_STATUS_DECLARATIONS +LTCC='$LTCC' +LTCFLAGS='$LTCFLAGS' +compiler='$compiler_DEFAULT' + +# A function that is used when there is no print builtin or printf. +func_fallback_echo () +{ + eval 'cat <<_LTECHO_EOF +\$[]1 +_LTECHO_EOF' +} + +# Quote evaled strings. +for var in lt_decl_all_varnames([[ \ +]], lt_decl_quote_varnames); do + case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in + *[[\\\\\\\`\\"\\\$]]*) + eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" + ;; + *) + eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" + ;; + esac +done + +# Double-quote double-evaled strings. +for var in lt_decl_all_varnames([[ \ +]], lt_decl_dquote_varnames); do + case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in + *[[\\\\\\\`\\"\\\$]]*) + eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" + ;; + *) + eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" + ;; + esac +done + +_LT_OUTPUT_LIBTOOL_INIT +]) + +# _LT_GENERATED_FILE_INIT(FILE, [COMMENT]) +# ------------------------------------ +# Generate a child script FILE with all initialization necessary to +# reuse the environment learned by the parent script, and make the +# file executable. If COMMENT is supplied, it is inserted after the +# `#!' sequence but before initialization text begins. After this +# macro, additional text can be appended to FILE to form the body of +# the child script. The macro ends with non-zero status if the +# file could not be fully written (such as if the disk is full). +m4_ifdef([AS_INIT_GENERATED], +[m4_defun([_LT_GENERATED_FILE_INIT],[AS_INIT_GENERATED($@)])], +[m4_defun([_LT_GENERATED_FILE_INIT], +[m4_require([AS_PREPARE])]dnl +[m4_pushdef([AS_MESSAGE_LOG_FD])]dnl +[lt_write_fail=0 +cat >$1 <<_ASEOF || lt_write_fail=1 +#! $SHELL +# Generated by $as_me. +$2 +SHELL=\${CONFIG_SHELL-$SHELL} +export SHELL +_ASEOF +cat >>$1 <<\_ASEOF || lt_write_fail=1 +AS_SHELL_SANITIZE +_AS_PREPARE +exec AS_MESSAGE_FD>&1 +_ASEOF +test $lt_write_fail = 0 && chmod +x $1[]dnl +m4_popdef([AS_MESSAGE_LOG_FD])])])# _LT_GENERATED_FILE_INIT + +# LT_OUTPUT +# --------- +# This macro allows early generation of the libtool script (before +# AC_OUTPUT is called), incase it is used in configure for compilation +# tests. +AC_DEFUN([LT_OUTPUT], +[: ${CONFIG_LT=./config.lt} +AC_MSG_NOTICE([creating $CONFIG_LT]) +_LT_GENERATED_FILE_INIT(["$CONFIG_LT"], +[# Run this file to recreate a libtool stub with the current configuration.]) + +cat >>"$CONFIG_LT" <<\_LTEOF +lt_cl_silent=false +exec AS_MESSAGE_LOG_FD>>config.log +{ + echo + AS_BOX([Running $as_me.]) +} >&AS_MESSAGE_LOG_FD + +lt_cl_help="\ +\`$as_me' creates a local libtool stub from the current configuration, +for use in further configure time tests before the real libtool is +generated. + +Usage: $[0] [[OPTIONS]] + + -h, --help print this help, then exit + -V, --version print version number, then exit + -q, --quiet do not print progress messages + -d, --debug don't remove temporary files + +Report bugs to ." + +lt_cl_version="\ +m4_ifset([AC_PACKAGE_NAME], [AC_PACKAGE_NAME ])config.lt[]dnl +m4_ifset([AC_PACKAGE_VERSION], [ AC_PACKAGE_VERSION]) +configured by $[0], generated by m4_PACKAGE_STRING. + +Copyright (C) 2011 Free Software Foundation, Inc. +This config.lt script is free software; the Free Software Foundation +gives unlimited permision to copy, distribute and modify it." + +while test $[#] != 0 +do + case $[1] in + --version | --v* | -V ) + echo "$lt_cl_version"; exit 0 ;; + --help | --h* | -h ) + echo "$lt_cl_help"; exit 0 ;; + --debug | --d* | -d ) + debug=: ;; + --quiet | --q* | --silent | --s* | -q ) + lt_cl_silent=: ;; + + -*) AC_MSG_ERROR([unrecognized option: $[1] +Try \`$[0] --help' for more information.]) ;; + + *) AC_MSG_ERROR([unrecognized argument: $[1] +Try \`$[0] --help' for more information.]) ;; + esac + shift +done + +if $lt_cl_silent; then + exec AS_MESSAGE_FD>/dev/null +fi +_LTEOF + +cat >>"$CONFIG_LT" <<_LTEOF +_LT_OUTPUT_LIBTOOL_COMMANDS_INIT +_LTEOF + +cat >>"$CONFIG_LT" <<\_LTEOF +AC_MSG_NOTICE([creating $ofile]) +_LT_OUTPUT_LIBTOOL_COMMANDS +AS_EXIT(0) +_LTEOF +chmod +x "$CONFIG_LT" + +# configure is writing to config.log, but config.lt does its own redirection, +# appending to config.log, which fails on DOS, as config.log is still kept +# open by configure. Here we exec the FD to /dev/null, effectively closing +# config.log, so it can be properly (re)opened and appended to by config.lt. +lt_cl_success=: +test "$silent" = yes && + lt_config_lt_args="$lt_config_lt_args --quiet" +exec AS_MESSAGE_LOG_FD>/dev/null +$SHELL "$CONFIG_LT" $lt_config_lt_args || lt_cl_success=false +exec AS_MESSAGE_LOG_FD>>config.log +$lt_cl_success || AS_EXIT(1) +])# LT_OUTPUT + + +# _LT_CONFIG(TAG) +# --------------- +# If TAG is the built-in tag, create an initial libtool script with a +# default configuration from the untagged config vars. Otherwise add code +# to config.status for appending the configuration named by TAG from the +# matching tagged config vars. +m4_defun([_LT_CONFIG], +[m4_require([_LT_FILEUTILS_DEFAULTS])dnl +_LT_CONFIG_SAVE_COMMANDS([ + m4_define([_LT_TAG], m4_if([$1], [], [C], [$1]))dnl + m4_if(_LT_TAG, [C], [ + # See if we are running on zsh, and set the options which allow our + # commands through without removal of \ escapes. + if test -n "${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST + fi + + cfgfile="${ofile}T" + trap "$RM \"$cfgfile\"; exit 1" 1 2 15 + $RM "$cfgfile" + + cat <<_LT_EOF >> "$cfgfile" +#! $SHELL + +# `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services. +# Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION +# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: +# NOTE: Changes made to this file will be lost: look at ltmain.sh. +# +_LT_COPYING +_LT_LIBTOOL_TAGS + +# ### BEGIN LIBTOOL CONFIG +_LT_LIBTOOL_CONFIG_VARS +_LT_LIBTOOL_TAG_VARS +# ### END LIBTOOL CONFIG + +_LT_EOF + + case $host_os in + aix3*) + cat <<\_LT_EOF >> "$cfgfile" +# AIX sometimes has problems with the GCC collect2 program. For some +# reason, if we set the COLLECT_NAMES environment variable, the problems +# vanish in a puff of smoke. +if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES +fi +_LT_EOF + ;; + esac + + _LT_PROG_LTMAIN + + # We use sed instead of cat because bash on DJGPP gets confused if + # if finds mixed CR/LF and LF-only lines. Since sed operates in + # text mode, it properly converts lines to CR/LF. This bash problem + # is reportedly fixed, but why not run on old versions too? + sed '$q' "$ltmain" >> "$cfgfile" \ + || (rm -f "$cfgfile"; exit 1) + + _LT_PROG_REPLACE_SHELLFNS + + mv -f "$cfgfile" "$ofile" || + (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") + chmod +x "$ofile" +], +[cat <<_LT_EOF >> "$ofile" + +dnl Unfortunately we have to use $1 here, since _LT_TAG is not expanded +dnl in a comment (ie after a #). +# ### BEGIN LIBTOOL TAG CONFIG: $1 +_LT_LIBTOOL_TAG_VARS(_LT_TAG) +# ### END LIBTOOL TAG CONFIG: $1 +_LT_EOF +])dnl /m4_if +], +[m4_if([$1], [], [ + PACKAGE='$PACKAGE' + VERSION='$VERSION' + TIMESTAMP='$TIMESTAMP' + RM='$RM' + ofile='$ofile'], []) +])dnl /_LT_CONFIG_SAVE_COMMANDS +])# _LT_CONFIG + + +# LT_SUPPORTED_TAG(TAG) +# --------------------- +# Trace this macro to discover what tags are supported by the libtool +# --tag option, using: +# autoconf --trace 'LT_SUPPORTED_TAG:$1' +AC_DEFUN([LT_SUPPORTED_TAG], []) + + +# C support is built-in for now +m4_define([_LT_LANG_C_enabled], []) +m4_define([_LT_TAGS], []) + + +# LT_LANG(LANG) +# ------------- +# Enable libtool support for the given language if not already enabled. +AC_DEFUN([LT_LANG], +[AC_BEFORE([$0], [LT_OUTPUT])dnl +m4_case([$1], + [C], [_LT_LANG(C)], + [C++], [_LT_LANG(CXX)], + [Go], [_LT_LANG(GO)], + [Java], [_LT_LANG(GCJ)], + [Fortran 77], [_LT_LANG(F77)], + [Fortran], [_LT_LANG(FC)], + [Windows Resource], [_LT_LANG(RC)], + [m4_ifdef([_LT_LANG_]$1[_CONFIG], + [_LT_LANG($1)], + [m4_fatal([$0: unsupported language: "$1"])])])dnl +])# LT_LANG + + +# _LT_LANG(LANGNAME) +# ------------------ +m4_defun([_LT_LANG], +[m4_ifdef([_LT_LANG_]$1[_enabled], [], + [LT_SUPPORTED_TAG([$1])dnl + m4_append([_LT_TAGS], [$1 ])dnl + m4_define([_LT_LANG_]$1[_enabled], [])dnl + _LT_LANG_$1_CONFIG($1)])dnl +])# _LT_LANG + + +m4_ifndef([AC_PROG_GO], [ +# NOTE: This macro has been submitted for inclusion into # +# GNU Autoconf as AC_PROG_GO. When it is available in # +# a released version of Autoconf we should remove this # +# macro and use it instead. # +m4_defun([AC_PROG_GO], +[AC_LANG_PUSH(Go)dnl +AC_ARG_VAR([GOC], [Go compiler command])dnl +AC_ARG_VAR([GOFLAGS], [Go compiler flags])dnl +_AC_ARG_VAR_LDFLAGS()dnl +AC_CHECK_TOOL(GOC, gccgo) +if test -z "$GOC"; then + if test -n "$ac_tool_prefix"; then + AC_CHECK_PROG(GOC, [${ac_tool_prefix}gccgo], [${ac_tool_prefix}gccgo]) + fi +fi +if test -z "$GOC"; then + AC_CHECK_PROG(GOC, gccgo, gccgo, false) +fi +])#m4_defun +])#m4_ifndef + + +# _LT_LANG_DEFAULT_CONFIG +# ----------------------- +m4_defun([_LT_LANG_DEFAULT_CONFIG], +[AC_PROVIDE_IFELSE([AC_PROG_CXX], + [LT_LANG(CXX)], + [m4_define([AC_PROG_CXX], defn([AC_PROG_CXX])[LT_LANG(CXX)])]) + +AC_PROVIDE_IFELSE([AC_PROG_F77], + [LT_LANG(F77)], + [m4_define([AC_PROG_F77], defn([AC_PROG_F77])[LT_LANG(F77)])]) + +AC_PROVIDE_IFELSE([AC_PROG_FC], + [LT_LANG(FC)], + [m4_define([AC_PROG_FC], defn([AC_PROG_FC])[LT_LANG(FC)])]) + +dnl The call to [A][M_PROG_GCJ] is quoted like that to stop aclocal +dnl pulling things in needlessly. +AC_PROVIDE_IFELSE([AC_PROG_GCJ], + [LT_LANG(GCJ)], + [AC_PROVIDE_IFELSE([A][M_PROG_GCJ], + [LT_LANG(GCJ)], + [AC_PROVIDE_IFELSE([LT_PROG_GCJ], + [LT_LANG(GCJ)], + [m4_ifdef([AC_PROG_GCJ], + [m4_define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[LT_LANG(GCJ)])]) + m4_ifdef([A][M_PROG_GCJ], + [m4_define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[LT_LANG(GCJ)])]) + m4_ifdef([LT_PROG_GCJ], + [m4_define([LT_PROG_GCJ], defn([LT_PROG_GCJ])[LT_LANG(GCJ)])])])])]) + +AC_PROVIDE_IFELSE([AC_PROG_GO], + [LT_LANG(GO)], + [m4_define([AC_PROG_GO], defn([AC_PROG_GO])[LT_LANG(GO)])]) + +AC_PROVIDE_IFELSE([LT_PROG_RC], + [LT_LANG(RC)], + [m4_define([LT_PROG_RC], defn([LT_PROG_RC])[LT_LANG(RC)])]) +])# _LT_LANG_DEFAULT_CONFIG + +# Obsolete macros: +AU_DEFUN([AC_LIBTOOL_CXX], [LT_LANG(C++)]) +AU_DEFUN([AC_LIBTOOL_F77], [LT_LANG(Fortran 77)]) +AU_DEFUN([AC_LIBTOOL_FC], [LT_LANG(Fortran)]) +AU_DEFUN([AC_LIBTOOL_GCJ], [LT_LANG(Java)]) +AU_DEFUN([AC_LIBTOOL_RC], [LT_LANG(Windows Resource)]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_CXX], []) +dnl AC_DEFUN([AC_LIBTOOL_F77], []) +dnl AC_DEFUN([AC_LIBTOOL_FC], []) +dnl AC_DEFUN([AC_LIBTOOL_GCJ], []) +dnl AC_DEFUN([AC_LIBTOOL_RC], []) + + +# _LT_TAG_COMPILER +# ---------------- +m4_defun([_LT_TAG_COMPILER], +[AC_REQUIRE([AC_PROG_CC])dnl + +_LT_DECL([LTCC], [CC], [1], [A C compiler])dnl +_LT_DECL([LTCFLAGS], [CFLAGS], [1], [LTCC compiler flags])dnl +_LT_TAGDECL([CC], [compiler], [1], [A language specific compiler])dnl +_LT_TAGDECL([with_gcc], [GCC], [0], [Is the compiler the GNU compiler?])dnl + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# If no C compiler flags were specified, use CFLAGS. +LTCFLAGS=${LTCFLAGS-"$CFLAGS"} + +# Allow CC to be a program name with arguments. +compiler=$CC +])# _LT_TAG_COMPILER + + +# _LT_COMPILER_BOILERPLATE +# ------------------------ +# Check for compiler boilerplate output or warnings with +# the simple compiler test code. +m4_defun([_LT_COMPILER_BOILERPLATE], +[m4_require([_LT_DECL_SED])dnl +ac_outfile=conftest.$ac_objext +echo "$lt_simple_compile_test_code" >conftest.$ac_ext +eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_compiler_boilerplate=`cat conftest.err` +$RM conftest* +])# _LT_COMPILER_BOILERPLATE + + +# _LT_LINKER_BOILERPLATE +# ---------------------- +# Check for linker boilerplate output or warnings with +# the simple link test code. +m4_defun([_LT_LINKER_BOILERPLATE], +[m4_require([_LT_DECL_SED])dnl +ac_outfile=conftest.$ac_objext +echo "$lt_simple_link_test_code" >conftest.$ac_ext +eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_linker_boilerplate=`cat conftest.err` +$RM -r conftest* +])# _LT_LINKER_BOILERPLATE + +# _LT_REQUIRED_DARWIN_CHECKS +# ------------------------- +m4_defun_once([_LT_REQUIRED_DARWIN_CHECKS],[ + case $host_os in + rhapsody* | darwin*) + AC_CHECK_TOOL([DSYMUTIL], [dsymutil], [:]) + AC_CHECK_TOOL([NMEDIT], [nmedit], [:]) + AC_CHECK_TOOL([LIPO], [lipo], [:]) + AC_CHECK_TOOL([OTOOL], [otool], [:]) + AC_CHECK_TOOL([OTOOL64], [otool64], [:]) + _LT_DECL([], [DSYMUTIL], [1], + [Tool to manipulate archived DWARF debug symbol files on Mac OS X]) + _LT_DECL([], [NMEDIT], [1], + [Tool to change global to local symbols on Mac OS X]) + _LT_DECL([], [LIPO], [1], + [Tool to manipulate fat objects and archives on Mac OS X]) + _LT_DECL([], [OTOOL], [1], + [ldd/readelf like tool for Mach-O binaries on Mac OS X]) + _LT_DECL([], [OTOOL64], [1], + [ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4]) + + AC_CACHE_CHECK([for -single_module linker flag],[lt_cv_apple_cc_single_mod], + [lt_cv_apple_cc_single_mod=no + if test -z "${LT_MULTI_MODULE}"; then + # By default we will add the -single_module flag. You can override + # by either setting the environment variable LT_MULTI_MODULE + # non-empty at configure time, or by adding -multi_module to the + # link flags. + rm -rf libconftest.dylib* + echo "int foo(void){return 1;}" > conftest.c + echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ +-dynamiclib -Wl,-single_module conftest.c" >&AS_MESSAGE_LOG_FD + $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ + -dynamiclib -Wl,-single_module conftest.c 2>conftest.err + _lt_result=$? + # If there is a non-empty error log, and "single_module" + # appears in it, assume the flag caused a linker warning + if test -s conftest.err && $GREP single_module conftest.err; then + cat conftest.err >&AS_MESSAGE_LOG_FD + # Otherwise, if the output was created with a 0 exit code from + # the compiler, it worked. + elif test -f libconftest.dylib && test $_lt_result -eq 0; then + lt_cv_apple_cc_single_mod=yes + else + cat conftest.err >&AS_MESSAGE_LOG_FD + fi + rm -rf libconftest.dylib* + rm -f conftest.* + fi]) + + AC_CACHE_CHECK([for -exported_symbols_list linker flag], + [lt_cv_ld_exported_symbols_list], + [lt_cv_ld_exported_symbols_list=no + save_LDFLAGS=$LDFLAGS + echo "_main" > conftest.sym + LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym" + AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])], + [lt_cv_ld_exported_symbols_list=yes], + [lt_cv_ld_exported_symbols_list=no]) + LDFLAGS="$save_LDFLAGS" + ]) + + AC_CACHE_CHECK([for -force_load linker flag],[lt_cv_ld_force_load], + [lt_cv_ld_force_load=no + cat > conftest.c << _LT_EOF +int forced_loaded() { return 2;} +_LT_EOF + echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&AS_MESSAGE_LOG_FD + $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&AS_MESSAGE_LOG_FD + echo "$AR cru libconftest.a conftest.o" >&AS_MESSAGE_LOG_FD + $AR cru libconftest.a conftest.o 2>&AS_MESSAGE_LOG_FD + echo "$RANLIB libconftest.a" >&AS_MESSAGE_LOG_FD + $RANLIB libconftest.a 2>&AS_MESSAGE_LOG_FD + cat > conftest.c << _LT_EOF +int main() { return 0;} +_LT_EOF + echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&AS_MESSAGE_LOG_FD + $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err + _lt_result=$? + if test -s conftest.err && $GREP force_load conftest.err; then + cat conftest.err >&AS_MESSAGE_LOG_FD + elif test -f conftest && test $_lt_result -eq 0 && $GREP forced_load conftest >/dev/null 2>&1 ; then + lt_cv_ld_force_load=yes + else + cat conftest.err >&AS_MESSAGE_LOG_FD + fi + rm -f conftest.err libconftest.a conftest conftest.c + rm -rf conftest.dSYM + ]) + case $host_os in + rhapsody* | darwin1.[[012]]) + _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;; + darwin1.*) + _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; + darwin*) # darwin 5.x on + # if running on 10.5 or later, the deployment target defaults + # to the OS version, if on x86, and 10.4, the deployment + # target defaults to 10.4. Don't you love it? + case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in + 10.0,*86*-darwin8*|10.0,*-darwin[[91]]*) + _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; + 10.[[012]]*) + _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; + 10.*) + _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; + esac + ;; + esac + if test "$lt_cv_apple_cc_single_mod" = "yes"; then + _lt_dar_single_mod='$single_module' + fi + if test "$lt_cv_ld_exported_symbols_list" = "yes"; then + _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym' + else + _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}' + fi + if test "$DSYMUTIL" != ":" && test "$lt_cv_ld_force_load" = "no"; then + _lt_dsymutil='~$DSYMUTIL $lib || :' + else + _lt_dsymutil= + fi + ;; + esac +]) + + +# _LT_DARWIN_LINKER_FEATURES([TAG]) +# --------------------------------- +# Checks for linker and compiler features on darwin +m4_defun([_LT_DARWIN_LINKER_FEATURES], +[ + m4_require([_LT_REQUIRED_DARWIN_CHECKS]) + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_automatic, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported + if test "$lt_cv_ld_force_load" = "yes"; then + _LT_TAGVAR(whole_archive_flag_spec, $1)='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`' + m4_case([$1], [F77], [_LT_TAGVAR(compiler_needs_object, $1)=yes], + [FC], [_LT_TAGVAR(compiler_needs_object, $1)=yes]) + else + _LT_TAGVAR(whole_archive_flag_spec, $1)='' + fi + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(allow_undefined_flag, $1)="$_lt_dar_allow_undefined" + case $cc_basename in + ifort*) _lt_dar_can_shared=yes ;; + *) _lt_dar_can_shared=$GCC ;; + esac + if test "$_lt_dar_can_shared" = "yes"; then + output_verbose_link_cmd=func_echo_all + _LT_TAGVAR(archive_cmds, $1)="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" + _LT_TAGVAR(module_cmds, $1)="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" + _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" + _LT_TAGVAR(module_expsym_cmds, $1)="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" + m4_if([$1], [CXX], +[ if test "$lt_cv_apple_cc_single_mod" != "yes"; then + _LT_TAGVAR(archive_cmds, $1)="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}" + _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dar_export_syms}${_lt_dsymutil}" + fi +],[]) + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi +]) + +# _LT_SYS_MODULE_PATH_AIX([TAGNAME]) +# ---------------------------------- +# Links a minimal program and checks the executable +# for the system default hardcoded library path. In most cases, +# this is /usr/lib:/lib, but when the MPI compilers are used +# the location of the communication and MPI libs are included too. +# If we don't find anything, use the default library path according +# to the aix ld manual. +# Store the results from the different compilers for each TAGNAME. +# Allow to override them for all tags through lt_cv_aix_libpath. +m4_defun([_LT_SYS_MODULE_PATH_AIX], +[m4_require([_LT_DECL_SED])dnl +if test "${lt_cv_aix_libpath+set}" = set; then + aix_libpath=$lt_cv_aix_libpath +else + AC_CACHE_VAL([_LT_TAGVAR([lt_cv_aix_libpath_], [$1])], + [AC_LINK_IFELSE([AC_LANG_PROGRAM],[ + lt_aix_libpath_sed='[ + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\([^ ]*\) *$/\1/ + p + } + }]' + _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` + # Check for a 64-bit object if we didn't find anything. + if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then + _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` + fi],[]) + if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then + _LT_TAGVAR([lt_cv_aix_libpath_], [$1])="/usr/lib:/lib" + fi + ]) + aix_libpath=$_LT_TAGVAR([lt_cv_aix_libpath_], [$1]) +fi +])# _LT_SYS_MODULE_PATH_AIX + + +# _LT_SHELL_INIT(ARG) +# ------------------- +m4_define([_LT_SHELL_INIT], +[m4_divert_text([M4SH-INIT], [$1 +])])# _LT_SHELL_INIT + + + +# _LT_PROG_ECHO_BACKSLASH +# ----------------------- +# Find how we can fake an echo command that does not interpret backslash. +# In particular, with Autoconf 2.60 or later we add some code to the start +# of the generated configure script which will find a shell with a builtin +# printf (which we can use as an echo command). +m4_defun([_LT_PROG_ECHO_BACKSLASH], +[ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO +ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO + +AC_MSG_CHECKING([how to print strings]) +# Test print first, because it will be a builtin if present. +if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \ + test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then + ECHO='print -r --' +elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then + ECHO='printf %s\n' +else + # Use this function as a fallback that always works. + func_fallback_echo () + { + eval 'cat <<_LTECHO_EOF +$[]1 +_LTECHO_EOF' + } + ECHO='func_fallback_echo' +fi + +# func_echo_all arg... +# Invoke $ECHO with all args, space-separated. +func_echo_all () +{ + $ECHO "$*" +} + +case "$ECHO" in + printf*) AC_MSG_RESULT([printf]) ;; + print*) AC_MSG_RESULT([print -r]) ;; + *) AC_MSG_RESULT([cat]) ;; +esac + +m4_ifdef([_AS_DETECT_SUGGESTED], +[_AS_DETECT_SUGGESTED([ + test -n "${ZSH_VERSION+set}${BASH_VERSION+set}" || ( + ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' + ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO + ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO + PATH=/empty FPATH=/empty; export PATH FPATH + test "X`printf %s $ECHO`" = "X$ECHO" \ + || test "X`print -r -- $ECHO`" = "X$ECHO" )])]) + +_LT_DECL([], [SHELL], [1], [Shell to use when invoking shell scripts]) +_LT_DECL([], [ECHO], [1], [An echo program that protects backslashes]) +])# _LT_PROG_ECHO_BACKSLASH + + +# _LT_WITH_SYSROOT +# ---------------- +AC_DEFUN([_LT_WITH_SYSROOT], +[AC_MSG_CHECKING([for sysroot]) +AC_ARG_WITH([sysroot], +[ --with-sysroot[=DIR] Search for dependent libraries within DIR + (or the compiler's sysroot if not specified).], +[], [with_sysroot=no]) + +dnl lt_sysroot will always be passed unquoted. We quote it here +dnl in case the user passed a directory name. +lt_sysroot= +case ${with_sysroot} in #( + yes) + if test "$GCC" = yes; then + lt_sysroot=`$CC --print-sysroot 2>/dev/null` + fi + ;; #( + /*) + lt_sysroot=`echo "$with_sysroot" | sed -e "$sed_quote_subst"` + ;; #( + no|'') + ;; #( + *) + AC_MSG_RESULT([${with_sysroot}]) + AC_MSG_ERROR([The sysroot must be an absolute path.]) + ;; +esac + + AC_MSG_RESULT([${lt_sysroot:-no}]) +_LT_DECL([], [lt_sysroot], [0], [The root where to search for ]dnl +[dependent libraries, and in which our libraries should be installed.])]) + +# _LT_ENABLE_LOCK +# --------------- +m4_defun([_LT_ENABLE_LOCK], +[AC_ARG_ENABLE([libtool-lock], + [AS_HELP_STRING([--disable-libtool-lock], + [avoid locking (might break parallel builds)])]) +test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes + +# Some flags need to be propagated to the compiler or linker for good +# libtool support. +case $host in +ia64-*-hpux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case `/usr/bin/file conftest.$ac_objext` in + *ELF-32*) + HPUX_IA64_MODE="32" + ;; + *ELF-64*) + HPUX_IA64_MODE="64" + ;; + esac + fi + rm -rf conftest* + ;; +*-*-irix6*) + # Find out which ABI we are using. + echo '[#]line '$LINENO' "configure"' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + if test "$lt_cv_prog_gnu_ld" = yes; then + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -melf32bsmip" + ;; + *N32*) + LD="${LD-ld} -melf32bmipn32" + ;; + *64-bit*) + LD="${LD-ld} -melf64bmip" + ;; + esac + else + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -32" + ;; + *N32*) + LD="${LD-ld} -n32" + ;; + *64-bit*) + LD="${LD-ld} -64" + ;; + esac + fi + fi + rm -rf conftest* + ;; + +x86_64-*kfreebsd*-gnu|x86_64-*linux*|powerpc*-*linux*| \ +s390*-*linux*|s390*-*tpf*|sparc*-*linux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case `/usr/bin/file conftest.o` in + *32-bit*) + case $host in + x86_64-*kfreebsd*-gnu) + LD="${LD-ld} -m elf_i386_fbsd" + ;; + x86_64-*linux*) + case `/usr/bin/file conftest.o` in + *x86-64*) + LD="${LD-ld} -m elf32_x86_64" + ;; + *) + LD="${LD-ld} -m elf_i386" + ;; + esac + ;; + powerpc64le-*) + LD="${LD-ld} -m elf32lppclinux" + ;; + powerpc64-*) + LD="${LD-ld} -m elf32ppclinux" + ;; + s390x-*linux*) + LD="${LD-ld} -m elf_s390" + ;; + sparc64-*linux*) + LD="${LD-ld} -m elf32_sparc" + ;; + esac + ;; + *64-bit*) + case $host in + x86_64-*kfreebsd*-gnu) + LD="${LD-ld} -m elf_x86_64_fbsd" + ;; + x86_64-*linux*) + LD="${LD-ld} -m elf_x86_64" + ;; + powerpcle-*) + LD="${LD-ld} -m elf64lppc" + ;; + powerpc-*) + LD="${LD-ld} -m elf64ppc" + ;; + s390*-*linux*|s390*-*tpf*) + LD="${LD-ld} -m elf64_s390" + ;; + sparc*-*linux*) + LD="${LD-ld} -m elf64_sparc" + ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; + +*-*-sco3.2v5*) + # On SCO OpenServer 5, we need -belf to get full-featured binaries. + SAVE_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -belf" + AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf, + [AC_LANG_PUSH(C) + AC_LINK_IFELSE([AC_LANG_PROGRAM([[]],[[]])],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no]) + AC_LANG_POP]) + if test x"$lt_cv_cc_needs_belf" != x"yes"; then + # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf + CFLAGS="$SAVE_CFLAGS" + fi + ;; +*-*solaris*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case `/usr/bin/file conftest.o` in + *64-bit*) + case $lt_cv_prog_gnu_ld in + yes*) + case $host in + i?86-*-solaris*) + LD="${LD-ld} -m elf_x86_64" + ;; + sparc*-*-solaris*) + LD="${LD-ld} -m elf64_sparc" + ;; + esac + # GNU ld 2.21 introduced _sol2 emulations. Use them if available. + if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then + LD="${LD-ld}_sol2" + fi + ;; + *) + if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then + LD="${LD-ld} -64" + fi + ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; +esac + +need_locks="$enable_libtool_lock" +])# _LT_ENABLE_LOCK + + +# _LT_PROG_AR +# ----------- +m4_defun([_LT_PROG_AR], +[AC_CHECK_TOOLS(AR, [ar], false) +: ${AR=ar} +: ${AR_FLAGS=cru} +_LT_DECL([], [AR], [1], [The archiver]) +_LT_DECL([], [AR_FLAGS], [1], [Flags to create an archive]) + +AC_CACHE_CHECK([for archiver @FILE support], [lt_cv_ar_at_file], + [lt_cv_ar_at_file=no + AC_COMPILE_IFELSE([AC_LANG_PROGRAM], + [echo conftest.$ac_objext > conftest.lst + lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&AS_MESSAGE_LOG_FD' + AC_TRY_EVAL([lt_ar_try]) + if test "$ac_status" -eq 0; then + # Ensure the archiver fails upon bogus file names. + rm -f conftest.$ac_objext libconftest.a + AC_TRY_EVAL([lt_ar_try]) + if test "$ac_status" -ne 0; then + lt_cv_ar_at_file=@ + fi + fi + rm -f conftest.* libconftest.a + ]) + ]) + +if test "x$lt_cv_ar_at_file" = xno; then + archiver_list_spec= +else + archiver_list_spec=$lt_cv_ar_at_file +fi +_LT_DECL([], [archiver_list_spec], [1], + [How to feed a file listing to the archiver]) +])# _LT_PROG_AR + + +# _LT_CMD_OLD_ARCHIVE +# ------------------- +m4_defun([_LT_CMD_OLD_ARCHIVE], +[_LT_PROG_AR + +AC_CHECK_TOOL(STRIP, strip, :) +test -z "$STRIP" && STRIP=: +_LT_DECL([], [STRIP], [1], [A symbol stripping program]) + +AC_CHECK_TOOL(RANLIB, ranlib, :) +test -z "$RANLIB" && RANLIB=: +_LT_DECL([], [RANLIB], [1], + [Commands used to install an old-style archive]) + +# Determine commands to create old-style static archives. +old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs' +old_postinstall_cmds='chmod 644 $oldlib' +old_postuninstall_cmds= + +if test -n "$RANLIB"; then + case $host_os in + openbsd*) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib" + ;; + *) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib" + ;; + esac + old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib" +fi + +case $host_os in + darwin*) + lock_old_archive_extraction=yes ;; + *) + lock_old_archive_extraction=no ;; +esac +_LT_DECL([], [old_postinstall_cmds], [2]) +_LT_DECL([], [old_postuninstall_cmds], [2]) +_LT_TAGDECL([], [old_archive_cmds], [2], + [Commands used to build an old-style archive]) +_LT_DECL([], [lock_old_archive_extraction], [0], + [Whether to use a lock for old archive extraction]) +])# _LT_CMD_OLD_ARCHIVE + + +# _LT_COMPILER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, +# [OUTPUT-FILE], [ACTION-SUCCESS], [ACTION-FAILURE]) +# ---------------------------------------------------------------- +# Check whether the given compiler option works +AC_DEFUN([_LT_COMPILER_OPTION], +[m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_SED])dnl +AC_CACHE_CHECK([$1], [$2], + [$2=no + m4_if([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4]) + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="$3" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&AS_MESSAGE_LOG_FD + echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings other than the usual output. + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then + $2=yes + fi + fi + $RM conftest* +]) + +if test x"[$]$2" = xyes; then + m4_if([$5], , :, [$5]) +else + m4_if([$6], , :, [$6]) +fi +])# _LT_COMPILER_OPTION + +# Old name: +AU_ALIAS([AC_LIBTOOL_COMPILER_OPTION], [_LT_COMPILER_OPTION]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION], []) + + +# _LT_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, +# [ACTION-SUCCESS], [ACTION-FAILURE]) +# ---------------------------------------------------- +# Check whether the given linker option works +AC_DEFUN([_LT_LINKER_OPTION], +[m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_SED])dnl +AC_CACHE_CHECK([$1], [$2], + [$2=no + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS $3" + echo "$lt_simple_link_test_code" > conftest.$ac_ext + if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then + # The linker can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + # Append any errors to the config.log. + cat conftest.err 1>&AS_MESSAGE_LOG_FD + $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if diff conftest.exp conftest.er2 >/dev/null; then + $2=yes + fi + else + $2=yes + fi + fi + $RM -r conftest* + LDFLAGS="$save_LDFLAGS" +]) + +if test x"[$]$2" = xyes; then + m4_if([$4], , :, [$4]) +else + m4_if([$5], , :, [$5]) +fi +])# _LT_LINKER_OPTION + +# Old name: +AU_ALIAS([AC_LIBTOOL_LINKER_OPTION], [_LT_LINKER_OPTION]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_LINKER_OPTION], []) + + +# LT_CMD_MAX_LEN +#--------------- +AC_DEFUN([LT_CMD_MAX_LEN], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +# find the maximum length of command line arguments +AC_MSG_CHECKING([the maximum length of command line arguments]) +AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl + i=0 + teststring="ABCD" + + case $build_os in + msdosdjgpp*) + # On DJGPP, this test can blow up pretty badly due to problems in libc + # (any single argument exceeding 2000 bytes causes a buffer overrun + # during glob expansion). Even if it were fixed, the result of this + # check would be larger than it should be. + lt_cv_sys_max_cmd_len=12288; # 12K is about right + ;; + + gnu*) + # Under GNU Hurd, this test is not required because there is + # no limit to the length of command line arguments. + # Libtool will interpret -1 as no limit whatsoever + lt_cv_sys_max_cmd_len=-1; + ;; + + cygwin* | mingw* | cegcc*) + # On Win9x/ME, this test blows up -- it succeeds, but takes + # about 5 minutes as the teststring grows exponentially. + # Worse, since 9x/ME are not pre-emptively multitasking, + # you end up with a "frozen" computer, even though with patience + # the test eventually succeeds (with a max line length of 256k). + # Instead, let's just punt: use the minimum linelength reported by + # all of the supported platforms: 8192 (on NT/2K/XP). + lt_cv_sys_max_cmd_len=8192; + ;; + + mint*) + # On MiNT this can take a long time and run out of memory. + lt_cv_sys_max_cmd_len=8192; + ;; + + amigaos*) + # On AmigaOS with pdksh, this test takes hours, literally. + # So we just punt and use a minimum line length of 8192. + lt_cv_sys_max_cmd_len=8192; + ;; + + netbsd* | freebsd* | openbsd* | darwin* | dragonfly*) + # This has been around since 386BSD, at least. Likely further. + if test -x /sbin/sysctl; then + lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` + elif test -x /usr/sbin/sysctl; then + lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` + else + lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs + fi + # And add a safety zone + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` + ;; + + interix*) + # We know the value 262144 and hardcode it with a safety zone (like BSD) + lt_cv_sys_max_cmd_len=196608 + ;; + + os2*) + # The test takes a long time on OS/2. + lt_cv_sys_max_cmd_len=8192 + ;; + + osf*) + # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure + # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not + # nice to cause kernel panics so lets avoid the loop below. + # First set a reasonable default. + lt_cv_sys_max_cmd_len=16384 + # + if test -x /sbin/sysconfig; then + case `/sbin/sysconfig -q proc exec_disable_arg_limit` in + *1*) lt_cv_sys_max_cmd_len=-1 ;; + esac + fi + ;; + sco3.2v5*) + lt_cv_sys_max_cmd_len=102400 + ;; + sysv5* | sco5v6* | sysv4.2uw2*) + kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` + if test -n "$kargmax"; then + lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[[ ]]//'` + else + lt_cv_sys_max_cmd_len=32768 + fi + ;; + *) + lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null` + if test -n "$lt_cv_sys_max_cmd_len" && \ + test undefined != "$lt_cv_sys_max_cmd_len"; then + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` + else + # Make teststring a little bigger before we do anything with it. + # a 1K string should be a reasonable start. + for i in 1 2 3 4 5 6 7 8 ; do + teststring=$teststring$teststring + done + SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} + # If test is not a shell built-in, we'll probably end up computing a + # maximum length that is only half of the actual maximum length, but + # we can't tell. + while { test "X"`env echo "$teststring$teststring" 2>/dev/null` \ + = "X$teststring$teststring"; } >/dev/null 2>&1 && + test $i != 17 # 1/2 MB should be enough + do + i=`expr $i + 1` + teststring=$teststring$teststring + done + # Only check the string length outside the loop. + lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1` + teststring= + # Add a significant safety factor because C++ compilers can tack on + # massive amounts of additional arguments before passing them to the + # linker. It appears as though 1/2 is a usable value. + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` + fi + ;; + esac +]) +if test -n $lt_cv_sys_max_cmd_len ; then + AC_MSG_RESULT($lt_cv_sys_max_cmd_len) +else + AC_MSG_RESULT(none) +fi +max_cmd_len=$lt_cv_sys_max_cmd_len +_LT_DECL([], [max_cmd_len], [0], + [What is the maximum length of a command?]) +])# LT_CMD_MAX_LEN + +# Old name: +AU_ALIAS([AC_LIBTOOL_SYS_MAX_CMD_LEN], [LT_CMD_MAX_LEN]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN], []) + + +# _LT_HEADER_DLFCN +# ---------------- +m4_defun([_LT_HEADER_DLFCN], +[AC_CHECK_HEADERS([dlfcn.h], [], [], [AC_INCLUDES_DEFAULT])dnl +])# _LT_HEADER_DLFCN + + +# _LT_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE, +# ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING) +# ---------------------------------------------------------------- +m4_defun([_LT_TRY_DLOPEN_SELF], +[m4_require([_LT_HEADER_DLFCN])dnl +if test "$cross_compiling" = yes; then : + [$4] +else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<_LT_EOF +[#line $LINENO "configure" +#include "confdefs.h" + +#if HAVE_DLFCN_H +#include +#endif + +#include + +#ifdef RTLD_GLOBAL +# define LT_DLGLOBAL RTLD_GLOBAL +#else +# ifdef DL_GLOBAL +# define LT_DLGLOBAL DL_GLOBAL +# else +# define LT_DLGLOBAL 0 +# endif +#endif + +/* We may have to define LT_DLLAZY_OR_NOW in the command line if we + find out it does not work in some platform. */ +#ifndef LT_DLLAZY_OR_NOW +# ifdef RTLD_LAZY +# define LT_DLLAZY_OR_NOW RTLD_LAZY +# else +# ifdef DL_LAZY +# define LT_DLLAZY_OR_NOW DL_LAZY +# else +# ifdef RTLD_NOW +# define LT_DLLAZY_OR_NOW RTLD_NOW +# else +# ifdef DL_NOW +# define LT_DLLAZY_OR_NOW DL_NOW +# else +# define LT_DLLAZY_OR_NOW 0 +# endif +# endif +# endif +# endif +#endif + +/* When -fvisbility=hidden is used, assume the code has been annotated + correspondingly for the symbols needed. */ +#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) +int fnord () __attribute__((visibility("default"))); +#endif + +int fnord () { return 42; } +int main () +{ + void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); + int status = $lt_dlunknown; + + if (self) + { + if (dlsym (self,"fnord")) status = $lt_dlno_uscore; + else + { + if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; + else puts (dlerror ()); + } + /* dlclose (self); */ + } + else + puts (dlerror ()); + + return status; +}] +_LT_EOF + if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext} 2>/dev/null; then + (./conftest; exit; ) >&AS_MESSAGE_LOG_FD 2>/dev/null + lt_status=$? + case x$lt_status in + x$lt_dlno_uscore) $1 ;; + x$lt_dlneed_uscore) $2 ;; + x$lt_dlunknown|x*) $3 ;; + esac + else : + # compilation failed + $3 + fi +fi +rm -fr conftest* +])# _LT_TRY_DLOPEN_SELF + + +# LT_SYS_DLOPEN_SELF +# ------------------ +AC_DEFUN([LT_SYS_DLOPEN_SELF], +[m4_require([_LT_HEADER_DLFCN])dnl +if test "x$enable_dlopen" != xyes; then + enable_dlopen=unknown + enable_dlopen_self=unknown + enable_dlopen_self_static=unknown +else + lt_cv_dlopen=no + lt_cv_dlopen_libs= + + case $host_os in + beos*) + lt_cv_dlopen="load_add_on" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + ;; + + mingw* | pw32* | cegcc*) + lt_cv_dlopen="LoadLibrary" + lt_cv_dlopen_libs= + ;; + + cygwin*) + lt_cv_dlopen="dlopen" + lt_cv_dlopen_libs= + ;; + + darwin*) + # if libdl is installed we need to link against it + AC_CHECK_LIB([dl], [dlopen], + [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],[ + lt_cv_dlopen="dyld" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + ]) + ;; + + *) + AC_CHECK_FUNC([shl_load], + [lt_cv_dlopen="shl_load"], + [AC_CHECK_LIB([dld], [shl_load], + [lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld"], + [AC_CHECK_FUNC([dlopen], + [lt_cv_dlopen="dlopen"], + [AC_CHECK_LIB([dl], [dlopen], + [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"], + [AC_CHECK_LIB([svld], [dlopen], + [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"], + [AC_CHECK_LIB([dld], [dld_link], + [lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld"]) + ]) + ]) + ]) + ]) + ]) + ;; + esac + + if test "x$lt_cv_dlopen" != xno; then + enable_dlopen=yes + else + enable_dlopen=no + fi + + case $lt_cv_dlopen in + dlopen) + save_CPPFLAGS="$CPPFLAGS" + test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" + + save_LDFLAGS="$LDFLAGS" + wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" + + save_LIBS="$LIBS" + LIBS="$lt_cv_dlopen_libs $LIBS" + + AC_CACHE_CHECK([whether a program can dlopen itself], + lt_cv_dlopen_self, [dnl + _LT_TRY_DLOPEN_SELF( + lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes, + lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross) + ]) + + if test "x$lt_cv_dlopen_self" = xyes; then + wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" + AC_CACHE_CHECK([whether a statically linked program can dlopen itself], + lt_cv_dlopen_self_static, [dnl + _LT_TRY_DLOPEN_SELF( + lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes, + lt_cv_dlopen_self_static=no, lt_cv_dlopen_self_static=cross) + ]) + fi + + CPPFLAGS="$save_CPPFLAGS" + LDFLAGS="$save_LDFLAGS" + LIBS="$save_LIBS" + ;; + esac + + case $lt_cv_dlopen_self in + yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; + *) enable_dlopen_self=unknown ;; + esac + + case $lt_cv_dlopen_self_static in + yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; + *) enable_dlopen_self_static=unknown ;; + esac +fi +_LT_DECL([dlopen_support], [enable_dlopen], [0], + [Whether dlopen is supported]) +_LT_DECL([dlopen_self], [enable_dlopen_self], [0], + [Whether dlopen of programs is supported]) +_LT_DECL([dlopen_self_static], [enable_dlopen_self_static], [0], + [Whether dlopen of statically linked programs is supported]) +])# LT_SYS_DLOPEN_SELF + +# Old name: +AU_ALIAS([AC_LIBTOOL_DLOPEN_SELF], [LT_SYS_DLOPEN_SELF]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF], []) + + +# _LT_COMPILER_C_O([TAGNAME]) +# --------------------------- +# Check to see if options -c and -o are simultaneously supported by compiler. +# This macro does not hard code the compiler like AC_PROG_CC_C_O. +m4_defun([_LT_COMPILER_C_O], +[m4_require([_LT_DECL_SED])dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_TAG_COMPILER])dnl +AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext], + [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)], + [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=no + $RM -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&AS_MESSAGE_LOG_FD + echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp + $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 + if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then + _LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes + fi + fi + chmod u+w . 2>&AS_MESSAGE_LOG_FD + $RM conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files + $RM out/* && rmdir out + cd .. + $RM -r conftest + $RM conftest* +]) +_LT_TAGDECL([compiler_c_o], [lt_cv_prog_compiler_c_o], [1], + [Does compiler simultaneously support -c and -o options?]) +])# _LT_COMPILER_C_O + + +# _LT_COMPILER_FILE_LOCKS([TAGNAME]) +# ---------------------------------- +# Check to see if we can do hard links to lock some files if needed +m4_defun([_LT_COMPILER_FILE_LOCKS], +[m4_require([_LT_ENABLE_LOCK])dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +_LT_COMPILER_C_O([$1]) + +hard_links="nottested" +if test "$_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)" = no && test "$need_locks" != no; then + # do not overwrite the value of need_locks provided by the user + AC_MSG_CHECKING([if we can lock with hard links]) + hard_links=yes + $RM conftest* + ln conftest.a conftest.b 2>/dev/null && hard_links=no + touch conftest.a + ln conftest.a conftest.b 2>&5 || hard_links=no + ln conftest.a conftest.b 2>/dev/null && hard_links=no + AC_MSG_RESULT([$hard_links]) + if test "$hard_links" = no; then + AC_MSG_WARN([`$CC' does not support `-c -o', so `make -j' may be unsafe]) + need_locks=warn + fi +else + need_locks=no +fi +_LT_DECL([], [need_locks], [1], [Must we lock files when doing compilation?]) +])# _LT_COMPILER_FILE_LOCKS + + +# _LT_CHECK_OBJDIR +# ---------------- +m4_defun([_LT_CHECK_OBJDIR], +[AC_CACHE_CHECK([for objdir], [lt_cv_objdir], +[rm -f .libs 2>/dev/null +mkdir .libs 2>/dev/null +if test -d .libs; then + lt_cv_objdir=.libs +else + # MS-DOS does not allow filenames that begin with a dot. + lt_cv_objdir=_libs +fi +rmdir .libs 2>/dev/null]) +objdir=$lt_cv_objdir +_LT_DECL([], [objdir], [0], + [The name of the directory that contains temporary libtool files])dnl +m4_pattern_allow([LT_OBJDIR])dnl +AC_DEFINE_UNQUOTED(LT_OBJDIR, "$lt_cv_objdir/", + [Define to the sub-directory in which libtool stores uninstalled libraries.]) +])# _LT_CHECK_OBJDIR + + +# _LT_LINKER_HARDCODE_LIBPATH([TAGNAME]) +# -------------------------------------- +# Check hardcoding attributes. +m4_defun([_LT_LINKER_HARDCODE_LIBPATH], +[AC_MSG_CHECKING([how to hardcode library paths into programs]) +_LT_TAGVAR(hardcode_action, $1)= +if test -n "$_LT_TAGVAR(hardcode_libdir_flag_spec, $1)" || + test -n "$_LT_TAGVAR(runpath_var, $1)" || + test "X$_LT_TAGVAR(hardcode_automatic, $1)" = "Xyes" ; then + + # We can hardcode non-existent directories. + if test "$_LT_TAGVAR(hardcode_direct, $1)" != no && + # If the only mechanism to avoid hardcoding is shlibpath_var, we + # have to relink, otherwise we might link with an installed library + # when we should be linking with a yet-to-be-installed one + ## test "$_LT_TAGVAR(hardcode_shlibpath_var, $1)" != no && + test "$_LT_TAGVAR(hardcode_minus_L, $1)" != no; then + # Linking always hardcodes the temporary library directory. + _LT_TAGVAR(hardcode_action, $1)=relink + else + # We can link without hardcoding, and we can hardcode nonexisting dirs. + _LT_TAGVAR(hardcode_action, $1)=immediate + fi +else + # We cannot hardcode anything, or else we can only hardcode existing + # directories. + _LT_TAGVAR(hardcode_action, $1)=unsupported +fi +AC_MSG_RESULT([$_LT_TAGVAR(hardcode_action, $1)]) + +if test "$_LT_TAGVAR(hardcode_action, $1)" = relink || + test "$_LT_TAGVAR(inherit_rpath, $1)" = yes; then + # Fast installation is not supported + enable_fast_install=no +elif test "$shlibpath_overrides_runpath" = yes || + test "$enable_shared" = no; then + # Fast installation is not necessary + enable_fast_install=needless +fi +_LT_TAGDECL([], [hardcode_action], [0], + [How to hardcode a shared library path into an executable]) +])# _LT_LINKER_HARDCODE_LIBPATH + + +# _LT_CMD_STRIPLIB +# ---------------- +m4_defun([_LT_CMD_STRIPLIB], +[m4_require([_LT_DECL_EGREP]) +striplib= +old_striplib= +AC_MSG_CHECKING([whether stripping libraries is possible]) +if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then + test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" + test -z "$striplib" && striplib="$STRIP --strip-unneeded" + AC_MSG_RESULT([yes]) +else +# FIXME - insert some real tests, host_os isn't really good enough + case $host_os in + darwin*) + if test -n "$STRIP" ; then + striplib="$STRIP -x" + old_striplib="$STRIP -S" + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + fi + ;; + *) + AC_MSG_RESULT([no]) + ;; + esac +fi +_LT_DECL([], [old_striplib], [1], [Commands to strip libraries]) +_LT_DECL([], [striplib], [1]) +])# _LT_CMD_STRIPLIB + + +# _LT_SYS_DYNAMIC_LINKER([TAG]) +# ----------------------------- +# PORTME Fill in your ld.so characteristics +m4_defun([_LT_SYS_DYNAMIC_LINKER], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +m4_require([_LT_DECL_EGREP])dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_OBJDUMP])dnl +m4_require([_LT_DECL_SED])dnl +m4_require([_LT_CHECK_SHELL_FEATURES])dnl +AC_MSG_CHECKING([dynamic linker characteristics]) +m4_if([$1], + [], [ +if test "$GCC" = yes; then + case $host_os in + darwin*) lt_awk_arg="/^libraries:/,/LR/" ;; + *) lt_awk_arg="/^libraries:/" ;; + esac + case $host_os in + mingw* | cegcc*) lt_sed_strip_eq="s,=\([[A-Za-z]]:\),\1,g" ;; + *) lt_sed_strip_eq="s,=/,/,g" ;; + esac + lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq` + case $lt_search_path_spec in + *\;*) + # if the path contains ";" then we assume it to be the separator + # otherwise default to the standard path separator (i.e. ":") - it is + # assumed that no part of a normal pathname contains ";" but that should + # okay in the real world where ";" in dirpaths is itself problematic. + lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'` + ;; + *) + lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"` + ;; + esac + # Ok, now we have the path, separated by spaces, we can step through it + # and add multilib dir if necessary. + lt_tmp_lt_search_path_spec= + lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null` + for lt_sys_path in $lt_search_path_spec; do + if test -d "$lt_sys_path/$lt_multi_os_dir"; then + lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir" + else + test -d "$lt_sys_path" && \ + lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path" + fi + done + lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk ' +BEGIN {RS=" "; FS="/|\n";} { + lt_foo=""; + lt_count=0; + for (lt_i = NF; lt_i > 0; lt_i--) { + if ($lt_i != "" && $lt_i != ".") { + if ($lt_i == "..") { + lt_count++; + } else { + if (lt_count == 0) { + lt_foo="/" $lt_i lt_foo; + } else { + lt_count--; + } + } + } + } + if (lt_foo != "") { lt_freq[[lt_foo]]++; } + if (lt_freq[[lt_foo]] == 1) { print lt_foo; } +}'` + # AWK program above erroneously prepends '/' to C:/dos/paths + # for these hosts. + case $host_os in + mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\ + $SED 's,/\([[A-Za-z]]:\),\1,g'` ;; + esac + sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP` +else + sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" +fi]) +library_names_spec= +libname_spec='lib$name' +soname_spec= +shrext_cmds=".so" +postinstall_cmds= +postuninstall_cmds= +finish_cmds= +finish_eval= +shlibpath_var= +shlibpath_overrides_runpath=unknown +version_type=none +dynamic_linker="$host_os ld.so" +sys_lib_dlsearch_path_spec="/lib /usr/lib" +need_lib_prefix=unknown +hardcode_into_libs=no + +# when you set need_version to no, make sure it does not cause -set_version +# flags to be left without arguments +need_version=unknown + +case $host_os in +aix3*) + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' + shlibpath_var=LIBPATH + + # AIX 3 has no versioning support, so we append a major version to the name. + soname_spec='${libname}${release}${shared_ext}$major' + ;; + +aix[[4-9]]*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + hardcode_into_libs=yes + if test "$host_cpu" = ia64; then + # AIX 5 supports IA64 + library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + else + # With GCC up to 2.95.x, collect2 would create an import file + # for dependence libraries. The import file would start with + # the line `#! .'. This would cause the generated library to + # depend on `.', always an invalid library. This was fixed in + # development snapshots of GCC prior to 3.0. + case $host_os in + aix4 | aix4.[[01]] | aix4.[[01]].*) + if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' + echo ' yes ' + echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then + : + else + can_build_shared=no + fi + ;; + esac + # AIX (on Power*) has no versioning support, so currently we can not hardcode correct + # soname into executable. Probably we can add versioning support to + # collect2, so additional links can be useful in future. + if test "$aix_use_runtimelinking" = yes; then + # If using run time linking (on AIX 4.2 or later) use lib.so + # instead of lib.a to let people know that these are not + # typical AIX shared libraries. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + else + # We preserve .a as extension for shared libraries through AIX4.2 + # and later when we are not doing run time linking. + library_names_spec='${libname}${release}.a $libname.a' + soname_spec='${libname}${release}${shared_ext}$major' + fi + shlibpath_var=LIBPATH + fi + ;; + +amigaos*) + case $host_cpu in + powerpc) + # Since July 2007 AmigaOS4 officially supports .so libraries. + # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + ;; + m68k) + library_names_spec='$libname.ixlibrary $libname.a' + # Create ${libname}_ixlibrary.a entries in /sys/libs. + finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' + ;; + esac + ;; + +beos*) + library_names_spec='${libname}${shared_ext}' + dynamic_linker="$host_os ld.so" + shlibpath_var=LIBRARY_PATH + ;; + +bsdi[[45]]*) + version_type=linux # correct to gnu/linux during the next big refactor + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" + sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" + # the default ld.so.conf also contains /usr/contrib/lib and + # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow + # libtool to hard-code these into programs + ;; + +cygwin* | mingw* | pw32* | cegcc*) + version_type=windows + shrext_cmds=".dll" + need_version=no + need_lib_prefix=no + + case $GCC,$cc_basename in + yes,*) + # gcc + library_names_spec='$libname.dll.a' + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \${file}`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname~ + chmod a+x \$dldir/$dlname~ + if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then + eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; + fi' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $RM \$dlpath' + shlibpath_overrides_runpath=yes + + case $host_os in + cygwin*) + # Cygwin DLLs use 'cyg' prefix rather than 'lib' + soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' +m4_if([$1], [],[ + sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api"]) + ;; + mingw* | cegcc*) + # MinGW DLLs use traditional 'lib' prefix + soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' + ;; + pw32*) + # pw32 DLLs use 'pw' prefix rather than 'lib' + library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' + ;; + esac + dynamic_linker='Win32 ld.exe' + ;; + + *,cl*) + # Native MSVC + libname_spec='$name' + soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' + library_names_spec='${libname}.dll.lib' + + case $build_os in + mingw*) + sys_lib_search_path_spec= + lt_save_ifs=$IFS + IFS=';' + for lt_path in $LIB + do + IFS=$lt_save_ifs + # Let DOS variable expansion print the short 8.3 style file name. + lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"` + sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path" + done + IFS=$lt_save_ifs + # Convert to MSYS style. + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([[a-zA-Z]]\\):| /\\1|g' -e 's|^ ||'` + ;; + cygwin*) + # Convert to unix form, then to dos form, then back to unix form + # but this time dos style (no spaces!) so that the unix form looks + # like /cygdrive/c/PROGRA~1:/cygdr... + sys_lib_search_path_spec=`cygpath --path --unix "$LIB"` + sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null` + sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + ;; + *) + sys_lib_search_path_spec="$LIB" + if $ECHO "$sys_lib_search_path_spec" | [$GREP ';[c-zC-Z]:/' >/dev/null]; then + # It is most probably a Windows format PATH. + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` + else + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi + # FIXME: find the short name or the path components, as spaces are + # common. (e.g. "Program Files" -> "PROGRA~1") + ;; + esac + + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \${file}`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $RM \$dlpath' + shlibpath_overrides_runpath=yes + dynamic_linker='Win32 link.exe' + ;; + + *) + # Assume MSVC wrapper + library_names_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext} $libname.lib' + dynamic_linker='Win32 ld.exe' + ;; + esac + # FIXME: first we should search . and the directory the executable is in + shlibpath_var=PATH + ;; + +darwin* | rhapsody*) + dynamic_linker="$host_os dyld" + version_type=darwin + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext' + soname_spec='${libname}${release}${major}$shared_ext' + shlibpath_overrides_runpath=yes + shlibpath_var=DYLD_LIBRARY_PATH + shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' +m4_if([$1], [],[ + sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"]) + sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' + ;; + +dgux*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +freebsd* | dragonfly*) + # DragonFly does not have aout. When/if they implement a new + # versioning mechanism, adjust this. + if test -x /usr/bin/objformat; then + objformat=`/usr/bin/objformat` + else + case $host_os in + freebsd[[23]].*) objformat=aout ;; + *) objformat=elf ;; + esac + fi + version_type=freebsd-$objformat + case $version_type in + freebsd-elf*) + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + need_version=no + need_lib_prefix=no + ;; + freebsd-*) + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' + need_version=yes + ;; + esac + shlibpath_var=LD_LIBRARY_PATH + case $host_os in + freebsd2.*) + shlibpath_overrides_runpath=yes + ;; + freebsd3.[[01]]* | freebsdelf3.[[01]]*) + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + freebsd3.[[2-9]]* | freebsdelf3.[[2-9]]* | \ + freebsd4.[[0-5]] | freebsdelf4.[[0-5]] | freebsd4.1.1 | freebsdelf4.1.1) + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + *) # from 4.6 on, and DragonFly + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + esac + ;; + +haiku*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + dynamic_linker="$host_os runtime_loader" + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LIBRARY_PATH + shlibpath_overrides_runpath=yes + sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib' + hardcode_into_libs=yes + ;; + +hpux9* | hpux10* | hpux11*) + # Give a soname corresponding to the major version so that dld.sl refuses to + # link against other versions. + version_type=sunos + need_lib_prefix=no + need_version=no + case $host_cpu in + ia64*) + shrext_cmds='.so' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.so" + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + if test "X$HPUX_IA64_MODE" = X32; then + sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" + else + sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" + fi + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + hppa*64*) + shrext_cmds='.sl' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.sl" + shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + *) + shrext_cmds='.sl' + dynamic_linker="$host_os dld.sl" + shlibpath_var=SHLIB_PATH + shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + ;; + esac + # HP-UX runs *really* slowly unless shared libraries are mode 555, ... + postinstall_cmds='chmod 555 $lib' + # or fails outright, so override atomically: + install_override_mode=555 + ;; + +interix[[3-9]]*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +irix5* | irix6* | nonstopux*) + case $host_os in + nonstopux*) version_type=nonstopux ;; + *) + if test "$lt_cv_prog_gnu_ld" = yes; then + version_type=linux # correct to gnu/linux during the next big refactor + else + version_type=irix + fi ;; + esac + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' + case $host_os in + irix5* | nonstopux*) + libsuff= shlibsuff= + ;; + *) + case $LD in # libtool.m4 will add one of these switches to LD + *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") + libsuff= shlibsuff= libmagic=32-bit;; + *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") + libsuff=32 shlibsuff=N32 libmagic=N32;; + *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") + libsuff=64 shlibsuff=64 libmagic=64-bit;; + *) libsuff= shlibsuff= libmagic=never-match;; + esac + ;; + esac + shlibpath_var=LD_LIBRARY${shlibsuff}_PATH + shlibpath_overrides_runpath=no + sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" + sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" + hardcode_into_libs=yes + ;; + +# No shared lib support for Linux oldld, aout, or coff. +linux*oldld* | linux*aout* | linux*coff*) + dynamic_linker=no + ;; + +# This must be glibc/ELF. +linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + + # Some binutils ld are patched to set DT_RUNPATH + AC_CACHE_VAL([lt_cv_shlibpath_overrides_runpath], + [lt_cv_shlibpath_overrides_runpath=no + save_LDFLAGS=$LDFLAGS + save_libdir=$libdir + eval "libdir=/foo; wl=\"$_LT_TAGVAR(lt_prog_compiler_wl, $1)\"; \ + LDFLAGS=\"\$LDFLAGS $_LT_TAGVAR(hardcode_libdir_flag_spec, $1)\"" + AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])], + [AS_IF([ ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null], + [lt_cv_shlibpath_overrides_runpath=yes])]) + LDFLAGS=$save_LDFLAGS + libdir=$save_libdir + ]) + shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath + + # This implies no fast_install, which is unacceptable. + # Some rework will be needed to allow for fast_install + # before this can be enabled. + hardcode_into_libs=yes + + # Append ld.so.conf contents to the search path + if test -f /etc/ld.so.conf; then + lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \[$]2)); skip = 1; } { if (!skip) print \[$]0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '` + sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" + fi + + # We used to test for /lib/ld.so.1 and disable shared libraries on + # powerpc, because MkLinux only supported shared libraries with the + # GNU dynamic linker. Since this was broken with cross compilers, + # most powerpc-linux boxes support dynamic linking these days and + # people can always --disable-shared, the test was removed, and we + # assume the GNU/Linux dynamic linker is in use. + dynamic_linker='GNU/Linux ld.so' + ;; + +netbsdelf*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='NetBSD ld.elf_so' + ;; + +netbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + dynamic_linker='NetBSD (a.out) ld.so' + else + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='NetBSD ld.elf_so' + fi + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + +newsos6) + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +*nto* | *qnx*) + version_type=qnx + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='ldqnx.so' + ;; + +openbsd*) + version_type=sunos + sys_lib_dlsearch_path_spec="/usr/lib" + need_lib_prefix=no + # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. + case $host_os in + openbsd3.3 | openbsd3.3.*) need_version=yes ;; + *) need_version=no ;; + esac + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + shlibpath_var=LD_LIBRARY_PATH + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + case $host_os in + openbsd2.[[89]] | openbsd2.[[89]].*) + shlibpath_overrides_runpath=no + ;; + *) + shlibpath_overrides_runpath=yes + ;; + esac + else + shlibpath_overrides_runpath=yes + fi + ;; + +os2*) + libname_spec='$name' + shrext_cmds=".dll" + need_lib_prefix=no + library_names_spec='$libname${shared_ext} $libname.a' + dynamic_linker='OS/2 ld.exe' + shlibpath_var=LIBPATH + ;; + +osf3* | osf4* | osf5*) + version_type=osf + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" + sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" + ;; + +rdos*) + dynamic_linker=no + ;; + +solaris*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + # ldd complains unless libraries are executable + postinstall_cmds='chmod +x $lib' + ;; + +sunos4*) + version_type=sunos + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + if test "$with_gnu_ld" = yes; then + need_lib_prefix=no + fi + need_version=yes + ;; + +sysv4 | sysv4.3*) + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + case $host_vendor in + sni) + shlibpath_overrides_runpath=no + need_lib_prefix=no + runpath_var=LD_RUN_PATH + ;; + siemens) + need_lib_prefix=no + ;; + motorola) + need_lib_prefix=no + need_version=no + shlibpath_overrides_runpath=no + sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' + ;; + esac + ;; + +sysv4*MP*) + if test -d /usr/nec ;then + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' + soname_spec='$libname${shared_ext}.$major' + shlibpath_var=LD_LIBRARY_PATH + fi + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + version_type=freebsd-elf + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + if test "$with_gnu_ld" = yes; then + sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' + else + sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' + case $host_os in + sco3.2v5*) + sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" + ;; + esac + fi + sys_lib_dlsearch_path_spec='/usr/lib' + ;; + +tpf*) + # TPF is a cross-target only. Preferred cross-host = GNU/Linux. + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +uts4*) + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +*) + dynamic_linker=no + ;; +esac +AC_MSG_RESULT([$dynamic_linker]) +test "$dynamic_linker" = no && can_build_shared=no + +variables_saved_for_relink="PATH $shlibpath_var $runpath_var" +if test "$GCC" = yes; then + variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" +fi + +if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then + sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec" +fi +if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then + sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec" +fi + +_LT_DECL([], [variables_saved_for_relink], [1], + [Variables whose values should be saved in libtool wrapper scripts and + restored at link time]) +_LT_DECL([], [need_lib_prefix], [0], + [Do we need the "lib" prefix for modules?]) +_LT_DECL([], [need_version], [0], [Do we need a version for libraries?]) +_LT_DECL([], [version_type], [0], [Library versioning type]) +_LT_DECL([], [runpath_var], [0], [Shared library runtime path variable]) +_LT_DECL([], [shlibpath_var], [0],[Shared library path variable]) +_LT_DECL([], [shlibpath_overrides_runpath], [0], + [Is shlibpath searched before the hard-coded library search path?]) +_LT_DECL([], [libname_spec], [1], [Format of library name prefix]) +_LT_DECL([], [library_names_spec], [1], + [[List of archive names. First name is the real one, the rest are links. + The last name is the one that the linker finds with -lNAME]]) +_LT_DECL([], [soname_spec], [1], + [[The coded name of the library, if different from the real name]]) +_LT_DECL([], [install_override_mode], [1], + [Permission mode override for installation of shared libraries]) +_LT_DECL([], [postinstall_cmds], [2], + [Command to use after installation of a shared archive]) +_LT_DECL([], [postuninstall_cmds], [2], + [Command to use after uninstallation of a shared archive]) +_LT_DECL([], [finish_cmds], [2], + [Commands used to finish a libtool library installation in a directory]) +_LT_DECL([], [finish_eval], [1], + [[As "finish_cmds", except a single script fragment to be evaled but + not shown]]) +_LT_DECL([], [hardcode_into_libs], [0], + [Whether we should hardcode library paths into libraries]) +_LT_DECL([], [sys_lib_search_path_spec], [2], + [Compile-time system search path for libraries]) +_LT_DECL([], [sys_lib_dlsearch_path_spec], [2], + [Run-time system search path for libraries]) +])# _LT_SYS_DYNAMIC_LINKER + + +# _LT_PATH_TOOL_PREFIX(TOOL) +# -------------------------- +# find a file program which can recognize shared library +AC_DEFUN([_LT_PATH_TOOL_PREFIX], +[m4_require([_LT_DECL_EGREP])dnl +AC_MSG_CHECKING([for $1]) +AC_CACHE_VAL(lt_cv_path_MAGIC_CMD, +[case $MAGIC_CMD in +[[\\/*] | ?:[\\/]*]) + lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. + ;; +*) + lt_save_MAGIC_CMD="$MAGIC_CMD" + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR +dnl $ac_dummy forces splitting on constant user-supplied paths. +dnl POSIX.2 word splitting is done only on the output of word expansions, +dnl not every word. This closes a longstanding sh security hole. + ac_dummy="m4_if([$2], , $PATH, [$2])" + for ac_dir in $ac_dummy; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$1; then + lt_cv_path_MAGIC_CMD="$ac_dir/$1" + if test -n "$file_magic_test_file"; then + case $deplibs_check_method in + "file_magic "*) + file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` + MAGIC_CMD="$lt_cv_path_MAGIC_CMD" + if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | + $EGREP "$file_magic_regex" > /dev/null; then + : + else + cat <<_LT_EOF 1>&2 + +*** Warning: the command libtool uses to detect shared libraries, +*** $file_magic_cmd, produces output that libtool cannot recognize. +*** The result is that libtool may fail to recognize shared libraries +*** as such. This will affect the creation of libtool libraries that +*** depend on shared libraries, but programs linked with such libtool +*** libraries will work regardless of this problem. Nevertheless, you +*** may want to report the problem to your system manager and/or to +*** bug-libtool@gnu.org + +_LT_EOF + fi ;; + esac + fi + break + fi + done + IFS="$lt_save_ifs" + MAGIC_CMD="$lt_save_MAGIC_CMD" + ;; +esac]) +MAGIC_CMD="$lt_cv_path_MAGIC_CMD" +if test -n "$MAGIC_CMD"; then + AC_MSG_RESULT($MAGIC_CMD) +else + AC_MSG_RESULT(no) +fi +_LT_DECL([], [MAGIC_CMD], [0], + [Used to examine libraries when file_magic_cmd begins with "file"])dnl +])# _LT_PATH_TOOL_PREFIX + +# Old name: +AU_ALIAS([AC_PATH_TOOL_PREFIX], [_LT_PATH_TOOL_PREFIX]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_PATH_TOOL_PREFIX], []) + + +# _LT_PATH_MAGIC +# -------------- +# find a file program which can recognize a shared library +m4_defun([_LT_PATH_MAGIC], +[_LT_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH) +if test -z "$lt_cv_path_MAGIC_CMD"; then + if test -n "$ac_tool_prefix"; then + _LT_PATH_TOOL_PREFIX(file, /usr/bin$PATH_SEPARATOR$PATH) + else + MAGIC_CMD=: + fi +fi +])# _LT_PATH_MAGIC + + +# LT_PATH_LD +# ---------- +# find the pathname to the GNU or non-GNU linker +AC_DEFUN([LT_PATH_LD], +[AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_CANONICAL_BUILD])dnl +m4_require([_LT_DECL_SED])dnl +m4_require([_LT_DECL_EGREP])dnl +m4_require([_LT_PROG_ECHO_BACKSLASH])dnl + +AC_ARG_WITH([gnu-ld], + [AS_HELP_STRING([--with-gnu-ld], + [assume the C compiler uses GNU ld @<:@default=no@:>@])], + [test "$withval" = no || with_gnu_ld=yes], + [with_gnu_ld=no])dnl + +ac_prog=ld +if test "$GCC" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + AC_MSG_CHECKING([for ld used by $CC]) + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case $ac_prog in + # Accept absolute paths. + [[\\/]]* | ?:[[\\/]]*) + re_direlt='/[[^/]][[^/]]*/\.\./' + # Canonicalize the pathname of ld + ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` + while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do + ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` + done + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + AC_MSG_CHECKING([for GNU ld]) +else + AC_MSG_CHECKING([for non-GNU ld]) +fi +AC_CACHE_VAL(lt_cv_path_LD, +[if test -z "$LD"; then + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + lt_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some variants of GNU ld only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + case `"$lt_cv_path_LD" -v 2>&1 &1 /dev/null 2>&1; then + lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' + lt_cv_file_magic_cmd='func_win32_libid' + else + # Keep this pattern in sync with the one in func_win32_libid. + lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' + lt_cv_file_magic_cmd='$OBJDUMP -f' + fi + ;; + +cegcc*) + # use the weaker test based on 'objdump'. See mingw*. + lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?' + lt_cv_file_magic_cmd='$OBJDUMP -f' + ;; + +darwin* | rhapsody*) + lt_cv_deplibs_check_method=pass_all + ;; + +freebsd* | dragonfly*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then + case $host_cpu in + i*86 ) + # Not sure whether the presence of OpenBSD here was a mistake. + # Let's accept both of them until this is cleared up. + lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[[3-9]]86 (compact )?demand paged shared library' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` + ;; + esac + else + lt_cv_deplibs_check_method=pass_all + fi + ;; + +haiku*) + lt_cv_deplibs_check_method=pass_all + ;; + +hpux10.20* | hpux11*) + lt_cv_file_magic_cmd=/usr/bin/file + case $host_cpu in + ia64*) + lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64' + lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so + ;; + hppa*64*) + [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]'] + lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl + ;; + *) + lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]]\.[[0-9]]) shared library' + lt_cv_file_magic_test_file=/usr/lib/libc.sl + ;; + esac + ;; + +interix[[3-9]]*) + # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|\.a)$' + ;; + +irix5* | irix6* | nonstopux*) + case $LD in + *-32|*"-32 ") libmagic=32-bit;; + *-n32|*"-n32 ") libmagic=N32;; + *-64|*"-64 ") libmagic=64-bit;; + *) libmagic=never-match;; + esac + lt_cv_deplibs_check_method=pass_all + ;; + +# This must be glibc/ELF. +linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) + lt_cv_deplibs_check_method=pass_all + ;; + +netbsd* | netbsdelf*-gnu) + if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|_pic\.a)$' + fi + ;; + +newos6*) + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=/usr/lib/libnls.so + ;; + +*nto* | *qnx*) + lt_cv_deplibs_check_method=pass_all + ;; + +openbsd*) + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|\.so|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' + fi + ;; + +osf3* | osf4* | osf5*) + lt_cv_deplibs_check_method=pass_all + ;; + +rdos*) + lt_cv_deplibs_check_method=pass_all + ;; + +solaris*) + lt_cv_deplibs_check_method=pass_all + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + lt_cv_deplibs_check_method=pass_all + ;; + +sysv4 | sysv4.3*) + case $host_vendor in + motorola) + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]' + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` + ;; + ncr) + lt_cv_deplibs_check_method=pass_all + ;; + sequent) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )' + ;; + sni) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib" + lt_cv_file_magic_test_file=/lib/libc.so + ;; + siemens) + lt_cv_deplibs_check_method=pass_all + ;; + pc) + lt_cv_deplibs_check_method=pass_all + ;; + esac + ;; + +tpf*) + lt_cv_deplibs_check_method=pass_all + ;; +esac +]) + +file_magic_glob= +want_nocaseglob=no +if test "$build" = "$host"; then + case $host_os in + mingw* | pw32*) + if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then + want_nocaseglob=yes + else + file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[[\1]]\/[[\1]]\/g;/g"` + fi + ;; + esac +fi + +file_magic_cmd=$lt_cv_file_magic_cmd +deplibs_check_method=$lt_cv_deplibs_check_method +test -z "$deplibs_check_method" && deplibs_check_method=unknown + +_LT_DECL([], [deplibs_check_method], [1], + [Method to check whether dependent libraries are shared objects]) +_LT_DECL([], [file_magic_cmd], [1], + [Command to use when deplibs_check_method = "file_magic"]) +_LT_DECL([], [file_magic_glob], [1], + [How to find potential files when deplibs_check_method = "file_magic"]) +_LT_DECL([], [want_nocaseglob], [1], + [Find potential files using nocaseglob when deplibs_check_method = "file_magic"]) +])# _LT_CHECK_MAGIC_METHOD + + +# LT_PATH_NM +# ---------- +# find the pathname to a BSD- or MS-compatible name lister +AC_DEFUN([LT_PATH_NM], +[AC_REQUIRE([AC_PROG_CC])dnl +AC_CACHE_CHECK([for BSD- or MS-compatible name lister (nm)], lt_cv_path_NM, +[if test -n "$NM"; then + # Let the user override the test. + lt_cv_path_NM="$NM" +else + lt_nm_to_check="${ac_tool_prefix}nm" + if test -n "$ac_tool_prefix" && test "$build" = "$host"; then + lt_nm_to_check="$lt_nm_to_check nm" + fi + for lt_tmp_nm in $lt_nm_to_check; do + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + tmp_nm="$ac_dir/$lt_tmp_nm" + if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then + # Check to see if the nm accepts a BSD-compat flag. + # Adding the `sed 1q' prevents false positives on HP-UX, which says: + # nm: unknown option "B" ignored + # Tru64's nm complains that /dev/null is an invalid object file + case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in + */dev/null* | *'Invalid file or object type'*) + lt_cv_path_NM="$tmp_nm -B" + break + ;; + *) + case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in + */dev/null*) + lt_cv_path_NM="$tmp_nm -p" + break + ;; + *) + lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but + continue # so that we can try to find one that supports BSD flags + ;; + esac + ;; + esac + fi + done + IFS="$lt_save_ifs" + done + : ${lt_cv_path_NM=no} +fi]) +if test "$lt_cv_path_NM" != "no"; then + NM="$lt_cv_path_NM" +else + # Didn't find any BSD compatible name lister, look for dumpbin. + if test -n "$DUMPBIN"; then : + # Let the user override the test. + else + AC_CHECK_TOOLS(DUMPBIN, [dumpbin "link -dump"], :) + case `$DUMPBIN -symbols /dev/null 2>&1 | sed '1q'` in + *COFF*) + DUMPBIN="$DUMPBIN -symbols" + ;; + *) + DUMPBIN=: + ;; + esac + fi + AC_SUBST([DUMPBIN]) + if test "$DUMPBIN" != ":"; then + NM="$DUMPBIN" + fi +fi +test -z "$NM" && NM=nm +AC_SUBST([NM]) +_LT_DECL([], [NM], [1], [A BSD- or MS-compatible name lister])dnl + +AC_CACHE_CHECK([the name lister ($NM) interface], [lt_cv_nm_interface], + [lt_cv_nm_interface="BSD nm" + echo "int some_variable = 0;" > conftest.$ac_ext + (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&AS_MESSAGE_LOG_FD) + (eval "$ac_compile" 2>conftest.err) + cat conftest.err >&AS_MESSAGE_LOG_FD + (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&AS_MESSAGE_LOG_FD) + (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) + cat conftest.err >&AS_MESSAGE_LOG_FD + (eval echo "\"\$as_me:$LINENO: output\"" >&AS_MESSAGE_LOG_FD) + cat conftest.out >&AS_MESSAGE_LOG_FD + if $GREP 'External.*some_variable' conftest.out > /dev/null; then + lt_cv_nm_interface="MS dumpbin" + fi + rm -f conftest*]) +])# LT_PATH_NM + +# Old names: +AU_ALIAS([AM_PROG_NM], [LT_PATH_NM]) +AU_ALIAS([AC_PROG_NM], [LT_PATH_NM]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AM_PROG_NM], []) +dnl AC_DEFUN([AC_PROG_NM], []) + +# _LT_CHECK_SHAREDLIB_FROM_LINKLIB +# -------------------------------- +# how to determine the name of the shared library +# associated with a specific link library. +# -- PORTME fill in with the dynamic library characteristics +m4_defun([_LT_CHECK_SHAREDLIB_FROM_LINKLIB], +[m4_require([_LT_DECL_EGREP]) +m4_require([_LT_DECL_OBJDUMP]) +m4_require([_LT_DECL_DLLTOOL]) +AC_CACHE_CHECK([how to associate runtime and link libraries], +lt_cv_sharedlib_from_linklib_cmd, +[lt_cv_sharedlib_from_linklib_cmd='unknown' + +case $host_os in +cygwin* | mingw* | pw32* | cegcc*) + # two different shell functions defined in ltmain.sh + # decide which to use based on capabilities of $DLLTOOL + case `$DLLTOOL --help 2>&1` in + *--identify-strict*) + lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib + ;; + *) + lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback + ;; + esac + ;; +*) + # fallback: assume linklib IS sharedlib + lt_cv_sharedlib_from_linklib_cmd="$ECHO" + ;; +esac +]) +sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd +test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO + +_LT_DECL([], [sharedlib_from_linklib_cmd], [1], + [Command to associate shared and link libraries]) +])# _LT_CHECK_SHAREDLIB_FROM_LINKLIB + + +# _LT_PATH_MANIFEST_TOOL +# ---------------------- +# locate the manifest tool +m4_defun([_LT_PATH_MANIFEST_TOOL], +[AC_CHECK_TOOL(MANIFEST_TOOL, mt, :) +test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt +AC_CACHE_CHECK([if $MANIFEST_TOOL is a manifest tool], [lt_cv_path_mainfest_tool], + [lt_cv_path_mainfest_tool=no + echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&AS_MESSAGE_LOG_FD + $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out + cat conftest.err >&AS_MESSAGE_LOG_FD + if $GREP 'Manifest Tool' conftest.out > /dev/null; then + lt_cv_path_mainfest_tool=yes + fi + rm -f conftest*]) +if test "x$lt_cv_path_mainfest_tool" != xyes; then + MANIFEST_TOOL=: +fi +_LT_DECL([], [MANIFEST_TOOL], [1], [Manifest tool])dnl +])# _LT_PATH_MANIFEST_TOOL + + +# LT_LIB_M +# -------- +# check for math library +AC_DEFUN([LT_LIB_M], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +LIBM= +case $host in +*-*-beos* | *-*-cegcc* | *-*-cygwin* | *-*-haiku* | *-*-pw32* | *-*-darwin*) + # These system don't have libm, or don't need it + ;; +*-ncr-sysv4.3*) + AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM="-lmw") + AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm") + ;; +*) + AC_CHECK_LIB(m, cos, LIBM="-lm") + ;; +esac +AC_SUBST([LIBM]) +])# LT_LIB_M + +# Old name: +AU_ALIAS([AC_CHECK_LIBM], [LT_LIB_M]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_CHECK_LIBM], []) + + +# _LT_COMPILER_NO_RTTI([TAGNAME]) +# ------------------------------- +m4_defun([_LT_COMPILER_NO_RTTI], +[m4_require([_LT_TAG_COMPILER])dnl + +_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= + +if test "$GCC" = yes; then + case $cc_basename in + nvcc*) + _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -Xcompiler -fno-builtin' ;; + *) + _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' ;; + esac + + _LT_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions], + lt_cv_prog_compiler_rtti_exceptions, + [-fno-rtti -fno-exceptions], [], + [_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)="$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) -fno-rtti -fno-exceptions"]) +fi +_LT_TAGDECL([no_builtin_flag], [lt_prog_compiler_no_builtin_flag], [1], + [Compiler flag to turn off builtin functions]) +])# _LT_COMPILER_NO_RTTI + + +# _LT_CMD_GLOBAL_SYMBOLS +# ---------------------- +m4_defun([_LT_CMD_GLOBAL_SYMBOLS], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([AC_PROG_AWK])dnl +AC_REQUIRE([LT_PATH_NM])dnl +AC_REQUIRE([LT_PATH_LD])dnl +m4_require([_LT_DECL_SED])dnl +m4_require([_LT_DECL_EGREP])dnl +m4_require([_LT_TAG_COMPILER])dnl + +# Check for command to grab the raw symbol name followed by C symbol from nm. +AC_MSG_CHECKING([command to parse $NM output from $compiler object]) +AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe], +[ +# These are sane defaults that work on at least a few old systems. +# [They come from Ultrix. What could be older than Ultrix?!! ;)] + +# Character class describing NM global symbol codes. +symcode='[[BCDEGRST]]' + +# Regexp to match symbols that can be accessed directly from C. +sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)' + +# Define system-specific variables. +case $host_os in +aix*) + symcode='[[BCDT]]' + ;; +cygwin* | mingw* | pw32* | cegcc*) + symcode='[[ABCDGISTW]]' + ;; +hpux*) + if test "$host_cpu" = ia64; then + symcode='[[ABCDEGRST]]' + fi + ;; +irix* | nonstopux*) + symcode='[[BCDEGRST]]' + ;; +osf*) + symcode='[[BCDEGQRST]]' + ;; +solaris*) + symcode='[[BDRT]]' + ;; +sco3.2v5*) + symcode='[[DT]]' + ;; +sysv4.2uw2*) + symcode='[[DT]]' + ;; +sysv5* | sco5v6* | unixware* | OpenUNIX*) + symcode='[[ABDT]]' + ;; +sysv4) + symcode='[[DFNSTU]]' + ;; +esac + +# If we're using GNU nm, then use its standard symbol codes. +case `$NM -V 2>&1` in +*GNU* | *'with BFD'*) + symcode='[[ABCDGIRSTW]]' ;; +esac + +# Transform an extracted symbol line into a proper C declaration. +# Some systems (esp. on ia64) link data and code symbols differently, +# so use this general approach. +lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" + +# Transform an extracted symbol line into symbol name and symbol address +lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\)[[ ]]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (void *) \&\2},/p'" +lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([[^ ]]*\)[[ ]]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \(lib[[^ ]]*\)$/ {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"lib\2\", (void *) \&\2},/p'" + +# Handle CRLF in mingw tool chain +opt_cr= +case $build_os in +mingw*) + opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp + ;; +esac + +# Try without a prefix underscore, then with it. +for ac_symprfx in "" "_"; do + + # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. + symxfrm="\\1 $ac_symprfx\\2 \\2" + + # Write the raw and C identifiers. + if test "$lt_cv_nm_interface" = "MS dumpbin"; then + # Fake it for dumpbin and say T for any non-static function + # and D for any global variable. + # Also find C++ and __fastcall symbols from MSVC++, + # which start with @ or ?. + lt_cv_sys_global_symbol_pipe="$AWK ['"\ +" {last_section=section; section=\$ 3};"\ +" /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\ +" /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\ +" \$ 0!~/External *\|/{next};"\ +" / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ +" {if(hide[section]) next};"\ +" {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\ +" {split(\$ 0, a, /\||\r/); split(a[2], s)};"\ +" s[1]~/^[@?]/{print s[1], s[1]; next};"\ +" s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\ +" ' prfx=^$ac_symprfx]" + else + lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[ ]]\($symcode$symcode*\)[[ ]][[ ]]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" + fi + lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | sed '/ __gnu_lto/d'" + + # Check to see that the pipe works correctly. + pipe_works=no + + rm -f conftest* + cat > conftest.$ac_ext <<_LT_EOF +#ifdef __cplusplus +extern "C" { +#endif +char nm_test_var; +void nm_test_func(void); +void nm_test_func(void){} +#ifdef __cplusplus +} +#endif +int main(){nm_test_var='a';nm_test_func();return(0);} +_LT_EOF + + if AC_TRY_EVAL(ac_compile); then + # Now try to grab the symbols. + nlist=conftest.nm + if AC_TRY_EVAL(NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist) && test -s "$nlist"; then + # Try sorting and uniquifying the output. + if sort "$nlist" | uniq > "$nlist"T; then + mv -f "$nlist"T "$nlist" + else + rm -f "$nlist"T + fi + + # Make sure that we snagged all the symbols we need. + if $GREP ' nm_test_var$' "$nlist" >/dev/null; then + if $GREP ' nm_test_func$' "$nlist" >/dev/null; then + cat <<_LT_EOF > conftest.$ac_ext +/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ +#if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE) +/* DATA imports from DLLs on WIN32 con't be const, because runtime + relocations are performed -- see ld's documentation on pseudo-relocs. */ +# define LT@&t@_DLSYM_CONST +#elif defined(__osf__) +/* This system does not cope well with relocations in const data. */ +# define LT@&t@_DLSYM_CONST +#else +# define LT@&t@_DLSYM_CONST const +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +_LT_EOF + # Now generate the symbol file. + eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext' + + cat <<_LT_EOF >> conftest.$ac_ext + +/* The mapping between symbol names and symbols. */ +LT@&t@_DLSYM_CONST struct { + const char *name; + void *address; +} +lt__PROGRAM__LTX_preloaded_symbols[[]] = +{ + { "@PROGRAM@", (void *) 0 }, +_LT_EOF + $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext + cat <<\_LT_EOF >> conftest.$ac_ext + {0, (void *) 0} +}; + +/* This works around a problem in FreeBSD linker */ +#ifdef FREEBSD_WORKAROUND +static const void *lt_preloaded_setup() { + return lt__PROGRAM__LTX_preloaded_symbols; +} +#endif + +#ifdef __cplusplus +} +#endif +_LT_EOF + # Now try linking the two files. + mv conftest.$ac_objext conftstm.$ac_objext + lt_globsym_save_LIBS=$LIBS + lt_globsym_save_CFLAGS=$CFLAGS + LIBS="conftstm.$ac_objext" + CFLAGS="$CFLAGS$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)" + if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext}; then + pipe_works=yes + fi + LIBS=$lt_globsym_save_LIBS + CFLAGS=$lt_globsym_save_CFLAGS + else + echo "cannot find nm_test_func in $nlist" >&AS_MESSAGE_LOG_FD + fi + else + echo "cannot find nm_test_var in $nlist" >&AS_MESSAGE_LOG_FD + fi + else + echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD + fi + else + echo "$progname: failed program was:" >&AS_MESSAGE_LOG_FD + cat conftest.$ac_ext >&5 + fi + rm -rf conftest* conftst* + + # Do not use the global_symbol_pipe unless it works. + if test "$pipe_works" = yes; then + break + else + lt_cv_sys_global_symbol_pipe= + fi +done +]) +if test -z "$lt_cv_sys_global_symbol_pipe"; then + lt_cv_sys_global_symbol_to_cdecl= +fi +if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then + AC_MSG_RESULT(failed) +else + AC_MSG_RESULT(ok) +fi + +# Response file support. +if test "$lt_cv_nm_interface" = "MS dumpbin"; then + nm_file_list_spec='@' +elif $NM --help 2>/dev/null | grep '[[@]]FILE' >/dev/null; then + nm_file_list_spec='@' +fi + +_LT_DECL([global_symbol_pipe], [lt_cv_sys_global_symbol_pipe], [1], + [Take the output of nm and produce a listing of raw symbols and C names]) +_LT_DECL([global_symbol_to_cdecl], [lt_cv_sys_global_symbol_to_cdecl], [1], + [Transform the output of nm in a proper C declaration]) +_LT_DECL([global_symbol_to_c_name_address], + [lt_cv_sys_global_symbol_to_c_name_address], [1], + [Transform the output of nm in a C name address pair]) +_LT_DECL([global_symbol_to_c_name_address_lib_prefix], + [lt_cv_sys_global_symbol_to_c_name_address_lib_prefix], [1], + [Transform the output of nm in a C name address pair when lib prefix is needed]) +_LT_DECL([], [nm_file_list_spec], [1], + [Specify filename containing input files for $NM]) +]) # _LT_CMD_GLOBAL_SYMBOLS + + +# _LT_COMPILER_PIC([TAGNAME]) +# --------------------------- +m4_defun([_LT_COMPILER_PIC], +[m4_require([_LT_TAG_COMPILER])dnl +_LT_TAGVAR(lt_prog_compiler_wl, $1)= +_LT_TAGVAR(lt_prog_compiler_pic, $1)= +_LT_TAGVAR(lt_prog_compiler_static, $1)= + +m4_if([$1], [CXX], [ + # C++ specific cases for pic, static, wl, etc. + if test "$GXX" = yes; then + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + m68k) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' + ;; + esac + ;; + + beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + mingw* | cygwin* | os2* | pw32* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + # Although the cygwin gcc ignores -fPIC, still need this for old-style + # (--disable-auto-import) libraries + m4_if([$1], [GCJ], [], + [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) + ;; + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' + ;; + *djgpp*) + # DJGPP does not support shared libraries at all + _LT_TAGVAR(lt_prog_compiler_pic, $1)= + ;; + haiku*) + # PIC is the default for Haiku. + # The "-static" flag exists, but is broken. + _LT_TAGVAR(lt_prog_compiler_static, $1)= + ;; + interix[[3-9]]*) + # Interix 3.x gcc -fpic/-fPIC options generate broken code. + # Instead, we relocate shared libraries at runtime. + ;; + sysv4*MP*) + if test -d /usr/nec; then + _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic + fi + ;; + hpux*) + # PIC is the default for 64-bit PA HP-UX, but not for 32-bit + # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag + # sets the default TLS model and affects inlining. + case $host_cpu in + hppa*64*) + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + ;; + *qnx* | *nto*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + else + case $host_os in + aix[[4-9]]*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + else + _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' + fi + ;; + chorus*) + case $cc_basename in + cxch68*) + # Green Hills C++ Compiler + # _LT_TAGVAR(lt_prog_compiler_static, $1)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a" + ;; + esac + ;; + mingw* | cygwin* | os2* | pw32* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + m4_if([$1], [GCJ], [], + [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) + ;; + dgux*) + case $cc_basename in + ec++*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + ;; + ghcx*) + # Green Hills C++ Compiler + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + ;; + *) + ;; + esac + ;; + freebsd* | dragonfly*) + # FreeBSD uses GNU C++ + ;; + hpux9* | hpux10* | hpux11*) + case $cc_basename in + CC*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' + if test "$host_cpu" != ia64; then + _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' + fi + ;; + aCC*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' + ;; + esac + ;; + *) + ;; + esac + ;; + interix*) + # This is c89, which is MS Visual C++ (no shared libs) + # Anyone wants to do a port? + ;; + irix5* | irix6* | nonstopux*) + case $cc_basename in + CC*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + # CC pic flag -KPIC is the default. + ;; + *) + ;; + esac + ;; + linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) + case $cc_basename in + KCC*) + # KAI C++ Compiler + _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + ecpc* ) + # old Intel C++ for x86_64 which still supported -KPIC. + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + icpc* ) + # Intel C++, used to be incompatible with GCC. + # ICC 10 doesn't accept -KPIC any more. + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + pgCC* | pgcpp*) + # Portland Group C++ compiler + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + cxx*) + # Compaq C++ + # Make sure the PIC flag is empty. It appears that all Alpha + # Linux and Compaq Tru64 Unix objects are PIC. + _LT_TAGVAR(lt_prog_compiler_pic, $1)= + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + xlc* | xlC* | bgxl[[cC]]* | mpixl[[cC]]*) + # IBM XL 8.0, 9.0 on PPC and BlueGene + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink' + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C++ 5.9 + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' + ;; + esac + ;; + esac + ;; + lynxos*) + ;; + m88k*) + ;; + mvs*) + case $cc_basename in + cxx*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-W c,exportall' + ;; + *) + ;; + esac + ;; + netbsd* | netbsdelf*-gnu) + ;; + *qnx* | *nto*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' + ;; + osf3* | osf4* | osf5*) + case $cc_basename in + KCC*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' + ;; + RCC*) + # Rational C++ 2.4.1 + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + ;; + cxx*) + # Digital/Compaq C++ + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # Make sure the PIC flag is empty. It appears that all Alpha + # Linux and Compaq Tru64 Unix objects are PIC. + _LT_TAGVAR(lt_prog_compiler_pic, $1)= + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + *) + ;; + esac + ;; + psos*) + ;; + solaris*) + case $cc_basename in + CC* | sunCC*) + # Sun C++ 4.2, 5.x and Centerline C++ + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' + ;; + gcx*) + # Green Hills C++ Compiler + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' + ;; + *) + ;; + esac + ;; + sunos4*) + case $cc_basename in + CC*) + # Sun C++ 4.x + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + lcc*) + # Lucid + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + ;; + *) + ;; + esac + ;; + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + case $cc_basename in + CC*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + esac + ;; + tandem*) + case $cc_basename in + NCC*) + # NonStop-UX NCC 3.20 + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + ;; + *) + ;; + esac + ;; + vxworks*) + ;; + *) + _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + ;; + esac + fi +], +[ + if test "$GCC" = yes; then + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + m68k) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' + ;; + esac + ;; + + beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + + mingw* | cygwin* | pw32* | os2* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + # Although the cygwin gcc ignores -fPIC, still need this for old-style + # (--disable-auto-import) libraries + m4_if([$1], [GCJ], [], + [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) + ;; + + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' + ;; + + haiku*) + # PIC is the default for Haiku. + # The "-static" flag exists, but is broken. + _LT_TAGVAR(lt_prog_compiler_static, $1)= + ;; + + hpux*) + # PIC is the default for 64-bit PA HP-UX, but not for 32-bit + # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag + # sets the default TLS model and affects inlining. + case $host_cpu in + hppa*64*) + # +Z the default + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + ;; + + interix[[3-9]]*) + # Interix 3.x gcc -fpic/-fPIC options generate broken code. + # Instead, we relocate shared libraries at runtime. + ;; + + msdosdjgpp*) + # Just because we use GCC doesn't mean we suddenly get shared libraries + # on systems that don't support them. + _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + enable_shared=no + ;; + + *nto* | *qnx*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic + fi + ;; + + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + + case $cc_basename in + nvcc*) # Cuda Compiler Driver 2.2 + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Xlinker ' + if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then + _LT_TAGVAR(lt_prog_compiler_pic, $1)="-Xcompiler $_LT_TAGVAR(lt_prog_compiler_pic, $1)" + fi + ;; + esac + else + # PORTME Check for flag to pass linker flags through the system compiler. + case $host_os in + aix*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + else + _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' + fi + ;; + + mingw* | cygwin* | pw32* | os2* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + m4_if([$1], [GCJ], [], + [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) + ;; + + hpux9* | hpux10* | hpux11*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' + ;; + esac + # Is there a better lt_prog_compiler_static that works with the bundled CC? + _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' + ;; + + irix5* | irix6* | nonstopux*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # PIC (with -KPIC) is the default. + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + + linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) + case $cc_basename in + # old Intel for x86_64 which still supported -KPIC. + ecc*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + # icc used to be incompatible with GCC. + # ICC 10 doesn't accept -KPIC any more. + icc* | ifort*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + # Lahey Fortran 8.1. + lf95*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='--shared' + _LT_TAGVAR(lt_prog_compiler_static, $1)='--static' + ;; + nagfor*) + # NAG Fortran compiler + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,-Wl,,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*) + # Portland Group compilers (*not* the Pentium gcc compiler, + # which looks to be a dead project) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + ccc*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # All Alpha code is PIC. + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + xl* | bgxl* | bgf* | mpixl*) + # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink' + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [[1-7]].* | *Sun*Fortran*\ 8.[[0-3]]*) + # Sun Fortran 8.3 passes all unrecognized flags to the linker + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_TAGVAR(lt_prog_compiler_wl, $1)='' + ;; + *Sun\ F* | *Sun*Fortran*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' + ;; + *Sun\ C*) + # Sun C 5.9 + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + ;; + *Intel*\ [[CF]]*Compiler*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + *Portland\ Group*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + esac + ;; + esac + ;; + + newsos6) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + *nto* | *qnx*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' + ;; + + osf3* | osf4* | osf5*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # All OSF/1 code is PIC. + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + + rdos*) + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + + solaris*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + case $cc_basename in + f77* | f90* | f95* | sunf77* | sunf90* | sunf95*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ';; + *) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,';; + esac + ;; + + sunos4*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + sysv4 | sysv4.2uw2* | sysv4.3*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + sysv4*MP*) + if test -d /usr/nec ;then + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + ;; + + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + unicos*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + ;; + + uts4*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + *) + _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + ;; + esac + fi +]) +case $host_os in + # For platforms which do not support PIC, -DPIC is meaningless: + *djgpp*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)= + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])" + ;; +esac + +AC_CACHE_CHECK([for $compiler option to produce PIC], + [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)], + [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_prog_compiler_pic, $1)]) +_LT_TAGVAR(lt_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_cv_prog_compiler_pic, $1) + +# +# Check to make sure the PIC flag actually works. +# +if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then + _LT_COMPILER_OPTION([if $compiler PIC flag $_LT_TAGVAR(lt_prog_compiler_pic, $1) works], + [_LT_TAGVAR(lt_cv_prog_compiler_pic_works, $1)], + [$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])], [], + [case $_LT_TAGVAR(lt_prog_compiler_pic, $1) in + "" | " "*) ;; + *) _LT_TAGVAR(lt_prog_compiler_pic, $1)=" $_LT_TAGVAR(lt_prog_compiler_pic, $1)" ;; + esac], + [_LT_TAGVAR(lt_prog_compiler_pic, $1)= + _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no]) +fi +_LT_TAGDECL([pic_flag], [lt_prog_compiler_pic], [1], + [Additional compiler flags for building library objects]) + +_LT_TAGDECL([wl], [lt_prog_compiler_wl], [1], + [How to pass a linker flag through the compiler]) +# +# Check to make sure the static flag actually works. +# +wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) eval lt_tmp_static_flag=\"$_LT_TAGVAR(lt_prog_compiler_static, $1)\" +_LT_LINKER_OPTION([if $compiler static flag $lt_tmp_static_flag works], + _LT_TAGVAR(lt_cv_prog_compiler_static_works, $1), + $lt_tmp_static_flag, + [], + [_LT_TAGVAR(lt_prog_compiler_static, $1)=]) +_LT_TAGDECL([link_static_flag], [lt_prog_compiler_static], [1], + [Compiler flag to prevent dynamic linking]) +])# _LT_COMPILER_PIC + + +# _LT_LINKER_SHLIBS([TAGNAME]) +# ---------------------------- +# See if the linker supports building shared libraries. +m4_defun([_LT_LINKER_SHLIBS], +[AC_REQUIRE([LT_PATH_LD])dnl +AC_REQUIRE([LT_PATH_NM])dnl +m4_require([_LT_PATH_MANIFEST_TOOL])dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_EGREP])dnl +m4_require([_LT_DECL_SED])dnl +m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl +m4_require([_LT_TAG_COMPILER])dnl +AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) +m4_if([$1], [CXX], [ + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'] + case $host_os in + aix[[4-9]]*) + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to AIX nm, but means don't demangle with GNU nm + # Also, AIX nm treats weak defined symbols like other global defined + # symbols, whereas GNU nm marks them as "W". + if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then + _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + else + _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + fi + ;; + pw32*) + _LT_TAGVAR(export_symbols_cmds, $1)="$ltdll_cmds" + ;; + cygwin* | mingw* | cegcc*) + case $cc_basename in + cl*) + _LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' + ;; + *) + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols' + _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname'] + ;; + esac + ;; + linux* | k*bsd*-gnu | gnu*) + _LT_TAGVAR(link_all_deplibs, $1)=no + ;; + *) + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + ;; + esac +], [ + runpath_var= + _LT_TAGVAR(allow_undefined_flag, $1)= + _LT_TAGVAR(always_export_symbols, $1)=no + _LT_TAGVAR(archive_cmds, $1)= + _LT_TAGVAR(archive_expsym_cmds, $1)= + _LT_TAGVAR(compiler_needs_object, $1)=no + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no + _LT_TAGVAR(export_dynamic_flag_spec, $1)= + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + _LT_TAGVAR(hardcode_automatic, $1)=no + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_direct_absolute, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= + _LT_TAGVAR(hardcode_libdir_separator, $1)= + _LT_TAGVAR(hardcode_minus_L, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported + _LT_TAGVAR(inherit_rpath, $1)=no + _LT_TAGVAR(link_all_deplibs, $1)=unknown + _LT_TAGVAR(module_cmds, $1)= + _LT_TAGVAR(module_expsym_cmds, $1)= + _LT_TAGVAR(old_archive_from_new_cmds, $1)= + _LT_TAGVAR(old_archive_from_expsyms_cmds, $1)= + _LT_TAGVAR(thread_safe_flag_spec, $1)= + _LT_TAGVAR(whole_archive_flag_spec, $1)= + # include_expsyms should be a list of space-separated symbols to be *always* + # included in the symbol list + _LT_TAGVAR(include_expsyms, $1)= + # exclude_expsyms can be an extended regexp of symbols to exclude + # it will be wrapped by ` (' and `)$', so one must not match beginning or + # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', + # as well as any symbol that contains `d'. + _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'] + # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out + # platforms (ab)use it in PIC code, but their linkers get confused if + # the symbol is explicitly referenced. Since portable code cannot + # rely on this symbol name, it's probably fine to never include it in + # preloaded symbol tables. + # Exclude shared library initialization/finalization symbols. +dnl Note also adjust exclude_expsyms for C++ above. + extract_expsyms_cmds= + + case $host_os in + cygwin* | mingw* | pw32* | cegcc*) + # FIXME: the MSVC++ port hasn't been tested in a loooong time + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + if test "$GCC" != yes; then + with_gnu_ld=no + fi + ;; + interix*) + # we just hope/assume this is gcc and not c89 (= MSVC++) + with_gnu_ld=yes + ;; + openbsd*) + with_gnu_ld=no + ;; + linux* | k*bsd*-gnu | gnu*) + _LT_TAGVAR(link_all_deplibs, $1)=no + ;; + esac + + _LT_TAGVAR(ld_shlibs, $1)=yes + + # On some targets, GNU ld is compatible enough with the native linker + # that we're better off using the native interface for both. + lt_use_gnu_ld_interface=no + if test "$with_gnu_ld" = yes; then + case $host_os in + aix*) + # The AIX port of GNU ld has always aspired to compatibility + # with the native linker. However, as the warning in the GNU ld + # block says, versions before 2.19.5* couldn't really create working + # shared libraries, regardless of the interface used. + case `$LD -v 2>&1` in + *\ \(GNU\ Binutils\)\ 2.19.5*) ;; + *\ \(GNU\ Binutils\)\ 2.[[2-9]]*) ;; + *\ \(GNU\ Binutils\)\ [[3-9]]*) ;; + *) + lt_use_gnu_ld_interface=yes + ;; + esac + ;; + *) + lt_use_gnu_ld_interface=yes + ;; + esac + fi + + if test "$lt_use_gnu_ld_interface" = yes; then + # If archive_cmds runs LD, not CC, wlarc should be empty + wlarc='${wl}' + + # Set some defaults for GNU ld with shared library support. These + # are reset later if shared libraries are not supported. Putting them + # here allows them to be overridden if necessary. + runpath_var=LD_RUN_PATH + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + # ancient GNU ld didn't support --whole-archive et. al. + if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then + _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + _LT_TAGVAR(whole_archive_flag_spec, $1)= + fi + supports_anon_versioning=no + case `$LD -v 2>&1` in + *GNU\ gold*) supports_anon_versioning=yes ;; + *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11 + *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... + *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... + *\ 2.11.*) ;; # other 2.11 versions + *) supports_anon_versioning=yes ;; + esac + + # See if GNU ld supports shared libraries. + case $host_os in + aix[[3-9]]*) + # On AIX/PPC, the GNU linker is very broken + if test "$host_cpu" != ia64; then + _LT_TAGVAR(ld_shlibs, $1)=no + cat <<_LT_EOF 1>&2 + +*** Warning: the GNU linker, at least up to release 2.19, is reported +*** to be unable to reliably create shared libraries on AIX. +*** Therefore, libtool is disabling shared libraries support. If you +*** really care for shared libraries, you may want to install binutils +*** 2.20 or above, or modify your PATH so that a non-GNU linker is found. +*** You will then need to restart the configuration process. + +_LT_EOF + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='' + ;; + m68k) + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_minus_L, $1)=yes + ;; + esac + ;; + + beos*) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + # Joseph Beckenbach says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + cygwin* | mingw* | pw32* | cegcc*) + # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, + # as there is no search path for DLLs. + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-all-symbols' + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(always_export_symbols, $1)=no + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols' + _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname'] + + if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is; otherwise, prepend... + _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + haiku*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(link_all_deplibs, $1)=yes + ;; + + interix[[3-9]]*) + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. + # Instead, shared libraries are loaded at an image base (0x10000000 by + # default) and relocated if they conflict, which is a slow very memory + # consuming and fragmenting process. To avoid this, we pick a random, + # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link + # time. Moving up from 0x10000000 also allows more sbrk(2) space. + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + ;; + + gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu) + tmp_diet=no + if test "$host_os" = linux-dietlibc; then + case $cc_basename in + diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn) + esac + fi + if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \ + && test "$tmp_diet" = no + then + tmp_addflag=' $pic_flag' + tmp_sharedflag='-shared' + case $cc_basename,$host_cpu in + pgcc*) # Portland Group C compiler + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_addflag=' $pic_flag' + ;; + pgf77* | pgf90* | pgf95* | pgfortran*) + # Portland Group f77 and f90 compilers + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_addflag=' $pic_flag -Mnomain' ;; + ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 + tmp_addflag=' -i_dynamic' ;; + efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 + tmp_addflag=' -i_dynamic -nofor_main' ;; + ifc* | ifort*) # Intel Fortran compiler + tmp_addflag=' -nofor_main' ;; + lf95*) # Lahey Fortran 8.1 + _LT_TAGVAR(whole_archive_flag_spec, $1)= + tmp_sharedflag='--shared' ;; + xl[[cC]]* | bgxl[[cC]]* | mpixl[[cC]]*) # IBM XL C 8.0 on PPC (deal with xlf below) + tmp_sharedflag='-qmkshrobj' + tmp_addflag= ;; + nvcc*) # Cuda Compiler Driver 2.2 + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + _LT_TAGVAR(compiler_needs_object, $1)=yes + ;; + esac + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) # Sun C 5.9 + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + _LT_TAGVAR(compiler_needs_object, $1)=yes + tmp_sharedflag='-G' ;; + *Sun\ F*) # Sun Fortran 8.3 + tmp_sharedflag='-G' ;; + esac + _LT_TAGVAR(archive_cmds, $1)='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + + if test "x$supports_anon_versioning" = xyes; then + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' + fi + + case $cc_basename in + xlf* | bgf* | bgxlf* | mpixlf*) + # IBM XL Fortran 10.1 on PPC cannot create shared libs itself + _LT_TAGVAR(whole_archive_flag_spec, $1)='--whole-archive$convenience --no-whole-archive' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib' + if test "x$supports_anon_versioning" = xyes; then + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib' + fi + ;; + esac + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + netbsd* | netbsdelf*-gnu) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' + wlarc= + else + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + fi + ;; + + solaris*) + if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then + _LT_TAGVAR(ld_shlibs, $1)=no + cat <<_LT_EOF 1>&2 + +*** Warning: The releases 2.8.* of the GNU linker cannot reliably +*** create shared libraries on Solaris systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.9.1 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +_LT_EOF + elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) + case `$LD -v 2>&1` in + *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.1[[0-5]].*) + _LT_TAGVAR(ld_shlibs, $1)=no + cat <<_LT_EOF 1>&2 + +*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not +*** reliably create shared libraries on SCO systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.16.91.0.3 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +_LT_EOF + ;; + *) + # For security reasons, it is highly recommended that you always + # use absolute paths for naming shared libraries, and exclude the + # DT_RUNPATH tag from executables and libraries. But doing so + # requires that you compile everything twice, which is a pain. + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + + sunos4*) + _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' + wlarc= + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + *) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + + if test "$_LT_TAGVAR(ld_shlibs, $1)" = no; then + runpath_var= + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= + _LT_TAGVAR(export_dynamic_flag_spec, $1)= + _LT_TAGVAR(whole_archive_flag_spec, $1)= + fi + else + # PORTME fill in a description of your system's linker (not GNU ld) + case $host_os in + aix3*) + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(always_export_symbols, $1)=yes + _LT_TAGVAR(archive_expsym_cmds, $1)='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' + # Note: this linker hardcodes the directories in LIBPATH if there + # are no directories specified by -L. + _LT_TAGVAR(hardcode_minus_L, $1)=yes + if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then + # Neither direct hardcoding nor static linking is supported with a + # broken collect2. + _LT_TAGVAR(hardcode_direct, $1)=unsupported + fi + ;; + + aix[[4-9]]*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to AIX nm, but means don't demangle with GNU nm + # Also, AIX nm treats weak defined symbols like other global + # defined symbols, whereas GNU nm marks them as "W". + if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then + _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + else + _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + fi + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*) + for ld_flag in $LDFLAGS; do + if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then + aix_use_runtimelinking=yes + break + fi + done + ;; + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + _LT_TAGVAR(archive_cmds, $1)='' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(file_list_spec, $1)='${wl}-f,' + + if test "$GCC" = yes; then + case $host_os in aix4.[[012]]|aix4.[[012]].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && + strings "$collect2name" | $GREP resolve_lib_name >/dev/null + then + # We have reworked collect2 + : + else + # We have old collect2 + _LT_TAGVAR(hardcode_direct, $1)=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)= + fi + ;; + esac + shared_flag='-shared' + if test "$aix_use_runtimelinking" = yes; then + shared_flag="$shared_flag "'${wl}-G' + fi + _LT_TAGVAR(link_all_deplibs, $1)=no + else + # not using gcc + if test "$host_cpu" = ia64; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='${wl}-G' + else + shared_flag='${wl}-bM:SRE' + fi + fi + fi + + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall' + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to export. + _LT_TAGVAR(always_export_symbols, $1)=yes + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + _LT_TAGVAR(allow_undefined_flag, $1)='-berok' + # Determine the default libpath from the value encoded in an + # empty executable. + _LT_SYS_MODULE_PATH_AIX([$1]) + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' + _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs" + _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an + # empty executable. + _LT_SYS_MODULE_PATH_AIX([$1]) + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' + _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' + if test "$with_gnu_ld" = yes; then + # We only use this code for GNU lds that support --whole-archive. + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive' + else + # Exported symbols can be pulled into shared objects from archives + _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience' + fi + _LT_TAGVAR(archive_cmds_need_lc, $1)=yes + # This is similar to how AIX traditionally builds its shared libraries. + _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + fi + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='' + ;; + m68k) + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_minus_L, $1)=yes + ;; + esac + ;; + + bsdi[[45]]*) + _LT_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic + ;; + + cygwin* | mingw* | pw32* | cegcc*) + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + case $cc_basename in + cl*) + # Native MSVC + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(always_export_symbols, $1)=yes + _LT_TAGVAR(file_list_spec, $1)='@' + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=".dll" + # FIXME: Setting linknames here is a bad hack. + _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames=' + _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + sed -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp; + else + sed -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp; + fi~ + $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ + linknames=' + # The linker will not automatically build a static lib if we build a DLL. + # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + _LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1,DATA/'\'' | $SED -e '\''/^[[AITW]][[ ]]/s/.*[[ ]]//'\'' | sort | uniq > $export_symbols' + # Don't use ranlib + _LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib' + _LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~ + lt_tool_outputfile="@TOOL_OUTPUT@"~ + case $lt_outputfile in + *.exe|*.EXE) ;; + *) + lt_outputfile="$lt_outputfile.exe" + lt_tool_outputfile="$lt_tool_outputfile.exe" + ;; + esac~ + if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then + $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; + $RM "$lt_outputfile.manifest"; + fi' + ;; + *) + # Assume MSVC wrapper + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=".dll" + # FIXME: Setting linknames here is a bad hack. + _LT_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames=' + # The linker will automatically build a .lib file if we build a DLL. + _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' + # FIXME: Should let the user specify the lib program. + _LT_TAGVAR(old_archive_cmds, $1)='lib -OUT:$oldlib$oldobjs$old_deplibs' + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + ;; + esac + ;; + + darwin* | rhapsody*) + _LT_DARWIN_LINKER_FEATURES($1) + ;; + + dgux*) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor + # support. Future versions do this automatically, but an explicit c++rt0.o + # does not break anything, and helps significantly (at the cost of a little + # extra space). + freebsd2.2*) + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + # Unfortunately, older versions of FreeBSD 2 do not have this feature. + freebsd2.*) + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + # FreeBSD 3 and greater uses gcc -shared to do shared libraries. + freebsd* | dragonfly*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + hpux9*) + if test "$GCC" = yes; then + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + else + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + fi + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(hardcode_direct, $1)=yes + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + ;; + + hpux10*) + if test "$GCC" = yes && test "$with_gnu_ld" = no; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' + fi + if test "$with_gnu_ld" = no; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + _LT_TAGVAR(hardcode_minus_L, $1)=yes + fi + ;; + + hpux11*) + if test "$GCC" = yes && test "$with_gnu_ld" = no; then + case $host_cpu in + hppa*64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + else + case $host_cpu in + hppa*64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + m4_if($1, [], [ + # Older versions of the 11.00 compiler do not understand -b yet + # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does) + _LT_LINKER_OPTION([if $CC understands -b], + _LT_TAGVAR(lt_cv_prog_compiler__b, $1), [-b], + [_LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'], + [_LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'])], + [_LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags']) + ;; + esac + fi + if test "$with_gnu_ld" = no; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + case $host_cpu in + hppa*64*|ia64*) + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + *) + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + _LT_TAGVAR(hardcode_minus_L, $1)=yes + ;; + esac + fi + ;; + + irix5* | irix6* | nonstopux*) + if test "$GCC" = yes; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + # Try to use the -exported_symbol ld option, if it does not + # work, assume that -exports_file does not work either and + # implicitly export all symbols. + # This should be the same for all languages, so no per-tag cache variable. + AC_CACHE_CHECK([whether the $host_os linker accepts -exported_symbol], + [lt_cv_irix_exported_symbol], + [save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null" + AC_LINK_IFELSE( + [AC_LANG_SOURCE( + [AC_LANG_CASE([C], [[int foo (void) { return 0; }]], + [C++], [[int foo (void) { return 0; }]], + [Fortran 77], [[ + subroutine foo + end]], + [Fortran], [[ + subroutine foo + end]])])], + [lt_cv_irix_exported_symbol=yes], + [lt_cv_irix_exported_symbol=no]) + LDFLAGS="$save_LDFLAGS"]) + if test "$lt_cv_irix_exported_symbol" = yes; then + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib' + fi + else + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib' + fi + _LT_TAGVAR(archive_cmds_need_lc, $1)='no' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(inherit_rpath, $1)=yes + _LT_TAGVAR(link_all_deplibs, $1)=yes + ;; + + netbsd* | netbsdelf*-gnu) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out + else + _LT_TAGVAR(archive_cmds, $1)='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF + fi + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + newsos6) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + *nto* | *qnx*) + ;; + + openbsd*) + if test -f /usr/libexec/ld.so; then + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + else + case $host_os in + openbsd[[01]].* | openbsd2.[[0-7]] | openbsd2.[[0-7]].*) + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + ;; + esac + fi + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + os2*) + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~echo DATA >> $output_objdir/$libname.def~echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' + _LT_TAGVAR(old_archive_from_new_cmds, $1)='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' + ;; + + osf3*) + if test "$GCC" = yes; then + _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' + fi + _LT_TAGVAR(archive_cmds_need_lc, $1)='no' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + ;; + + osf4* | osf5*) # as osf3* with the addition of -msym flag + if test "$GCC" = yes; then + _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $pic_flag $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + else + _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~ + $CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp' + + # Both c and cxx compiler support -rpath directly + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' + fi + _LT_TAGVAR(archive_cmds_need_lc, $1)='no' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + ;; + + solaris*) + _LT_TAGVAR(no_undefined_flag, $1)=' -z defs' + if test "$GCC" = yes; then + wlarc='${wl}' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' + else + case `$CC -V 2>&1` in + *"Compilers 5.0"*) + wlarc='' + _LT_TAGVAR(archive_cmds, $1)='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp' + ;; + *) + wlarc='${wl}' + _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' + ;; + esac + fi + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + case $host_os in + solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; + *) + # The compiler driver will combine and reorder linker options, + # but understands `-z linker_flag'. GCC discards it without `$wl', + # but is careful enough not to reorder. + # Supported since Solaris 2.6 (maybe 2.5.1?) + if test "$GCC" = yes; then + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' + else + _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' + fi + ;; + esac + _LT_TAGVAR(link_all_deplibs, $1)=yes + ;; + + sunos4*) + if test "x$host_vendor" = xsequent; then + # Use $CC to link under sequent, because it throws in some extra .o + # files that make .init and .fini sections work. + _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' + fi + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + sysv4) + case $host_vendor in + sni) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_direct, $1)=yes # is this really true??? + ;; + siemens) + ## LD is ld it makes a PLAMLIB + ## CC just makes a GrossModule. + _LT_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(reload_cmds, $1)='$CC -r -o $output$reload_objs' + _LT_TAGVAR(hardcode_direct, $1)=no + ;; + motorola) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_direct, $1)=no #Motorola manual says yes, but my tests say they lie + ;; + esac + runpath_var='LD_RUN_PATH' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + sysv4.3*) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(export_dynamic_flag_spec, $1)='-Bexport' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + runpath_var=LD_RUN_PATH + hardcode_runpath_var=yes + _LT_TAGVAR(ld_shlibs, $1)=yes + fi + ;; + + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*) + _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + runpath_var='LD_RUN_PATH' + + if test "$GCC" = yes; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + sysv5* | sco3.2v5* | sco5v6*) + # Note: We can NOT use -z defs as we might desire, because we do not + # link with -lc, and that would cause any symbols used from libc to + # always be unresolved, which means just about no library would + # ever link correctly. If we're not using GNU ld we use -z text + # though, which does catch some bad symbols but isn't as heavy-handed + # as -z defs. + _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' + _LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs' + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport' + runpath_var='LD_RUN_PATH' + + if test "$GCC" = yes; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + uts4*) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + *) + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + + if test x$host_vendor = xsni; then + case $host in + sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Blargedynsym' + ;; + esac + fi + fi +]) +AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)]) +test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no + +_LT_TAGVAR(with_gnu_ld, $1)=$with_gnu_ld + +_LT_DECL([], [libext], [0], [Old archive suffix (normally "a")])dnl +_LT_DECL([], [shrext_cmds], [1], [Shared library suffix (normally ".so")])dnl +_LT_DECL([], [extract_expsyms_cmds], [2], + [The commands to extract the exported symbol list from a shared archive]) + +# +# Do we need to explicitly link libc? +# +case "x$_LT_TAGVAR(archive_cmds_need_lc, $1)" in +x|xyes) + # Assume -lc should be added + _LT_TAGVAR(archive_cmds_need_lc, $1)=yes + + if test "$enable_shared" = yes && test "$GCC" = yes; then + case $_LT_TAGVAR(archive_cmds, $1) in + *'~'*) + # FIXME: we may have to deal with multi-command sequences. + ;; + '$CC '*) + # Test whether the compiler implicitly links with -lc since on some + # systems, -lgcc has to come before -lc. If gcc already passes -lc + # to ld, don't add -lc before -lgcc. + AC_CACHE_CHECK([whether -lc should be explicitly linked in], + [lt_cv_]_LT_TAGVAR(archive_cmds_need_lc, $1), + [$RM conftest* + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + if AC_TRY_EVAL(ac_compile) 2>conftest.err; then + soname=conftest + lib=conftest + libobjs=conftest.$ac_objext + deplibs= + wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) + pic_flag=$_LT_TAGVAR(lt_prog_compiler_pic, $1) + compiler_flags=-v + linker_flags=-v + verstring= + output_objdir=. + libname=conftest + lt_save_allow_undefined_flag=$_LT_TAGVAR(allow_undefined_flag, $1) + _LT_TAGVAR(allow_undefined_flag, $1)= + if AC_TRY_EVAL(_LT_TAGVAR(archive_cmds, $1) 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) + then + lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=no + else + lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=yes + fi + _LT_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag + else + cat conftest.err 1>&5 + fi + $RM conftest* + ]) + _LT_TAGVAR(archive_cmds_need_lc, $1)=$lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1) + ;; + esac + fi + ;; +esac + +_LT_TAGDECL([build_libtool_need_lc], [archive_cmds_need_lc], [0], + [Whether or not to add -lc for building shared libraries]) +_LT_TAGDECL([allow_libtool_libs_with_static_runtimes], + [enable_shared_with_static_runtimes], [0], + [Whether or not to disallow shared libs when runtime libs are static]) +_LT_TAGDECL([], [export_dynamic_flag_spec], [1], + [Compiler flag to allow reflexive dlopens]) +_LT_TAGDECL([], [whole_archive_flag_spec], [1], + [Compiler flag to generate shared objects directly from archives]) +_LT_TAGDECL([], [compiler_needs_object], [1], + [Whether the compiler copes with passing no objects directly]) +_LT_TAGDECL([], [old_archive_from_new_cmds], [2], + [Create an old-style archive from a shared archive]) +_LT_TAGDECL([], [old_archive_from_expsyms_cmds], [2], + [Create a temporary old-style archive to link instead of a shared archive]) +_LT_TAGDECL([], [archive_cmds], [2], [Commands used to build a shared archive]) +_LT_TAGDECL([], [archive_expsym_cmds], [2]) +_LT_TAGDECL([], [module_cmds], [2], + [Commands used to build a loadable module if different from building + a shared archive.]) +_LT_TAGDECL([], [module_expsym_cmds], [2]) +_LT_TAGDECL([], [with_gnu_ld], [1], + [Whether we are building with GNU ld or not]) +_LT_TAGDECL([], [allow_undefined_flag], [1], + [Flag that allows shared libraries with undefined symbols to be built]) +_LT_TAGDECL([], [no_undefined_flag], [1], + [Flag that enforces no undefined symbols]) +_LT_TAGDECL([], [hardcode_libdir_flag_spec], [1], + [Flag to hardcode $libdir into a binary during linking. + This must work even if $libdir does not exist]) +_LT_TAGDECL([], [hardcode_libdir_separator], [1], + [Whether we need a single "-rpath" flag with a separated argument]) +_LT_TAGDECL([], [hardcode_direct], [0], + [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes + DIR into the resulting binary]) +_LT_TAGDECL([], [hardcode_direct_absolute], [0], + [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes + DIR into the resulting binary and the resulting library dependency is + "absolute", i.e impossible to change by setting ${shlibpath_var} if the + library is relocated]) +_LT_TAGDECL([], [hardcode_minus_L], [0], + [Set to "yes" if using the -LDIR flag during linking hardcodes DIR + into the resulting binary]) +_LT_TAGDECL([], [hardcode_shlibpath_var], [0], + [Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR + into the resulting binary]) +_LT_TAGDECL([], [hardcode_automatic], [0], + [Set to "yes" if building a shared library automatically hardcodes DIR + into the library and all subsequent libraries and executables linked + against it]) +_LT_TAGDECL([], [inherit_rpath], [0], + [Set to yes if linker adds runtime paths of dependent libraries + to runtime path list]) +_LT_TAGDECL([], [link_all_deplibs], [0], + [Whether libtool must link a program against all its dependency libraries]) +_LT_TAGDECL([], [always_export_symbols], [0], + [Set to "yes" if exported symbols are required]) +_LT_TAGDECL([], [export_symbols_cmds], [2], + [The commands to list exported symbols]) +_LT_TAGDECL([], [exclude_expsyms], [1], + [Symbols that should not be listed in the preloaded symbols]) +_LT_TAGDECL([], [include_expsyms], [1], + [Symbols that must always be exported]) +_LT_TAGDECL([], [prelink_cmds], [2], + [Commands necessary for linking programs (against libraries) with templates]) +_LT_TAGDECL([], [postlink_cmds], [2], + [Commands necessary for finishing linking programs]) +_LT_TAGDECL([], [file_list_spec], [1], + [Specify filename containing input files]) +dnl FIXME: Not yet implemented +dnl _LT_TAGDECL([], [thread_safe_flag_spec], [1], +dnl [Compiler flag to generate thread safe objects]) +])# _LT_LINKER_SHLIBS + + +# _LT_LANG_C_CONFIG([TAG]) +# ------------------------ +# Ensure that the configuration variables for a C compiler are suitably +# defined. These variables are subsequently used by _LT_CONFIG to write +# the compiler configuration to `libtool'. +m4_defun([_LT_LANG_C_CONFIG], +[m4_require([_LT_DECL_EGREP])dnl +lt_save_CC="$CC" +AC_LANG_PUSH(C) + +# Source file extension for C test sources. +ac_ext=c + +# Object file extension for compiled C test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="int some_variable = 0;" + +# Code to be used in simple link tests +lt_simple_link_test_code='int main(){return(0);}' + +_LT_TAG_COMPILER +# Save the default compiler, since it gets overwritten when the other +# tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP. +compiler_DEFAULT=$CC + +# save warnings/boilerplate of simple test code +_LT_COMPILER_BOILERPLATE +_LT_LINKER_BOILERPLATE + +if test -n "$compiler"; then + _LT_COMPILER_NO_RTTI($1) + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_SYS_DYNAMIC_LINKER($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + LT_SYS_DLOPEN_SELF + _LT_CMD_STRIPLIB + + # Report which library types will actually be built + AC_MSG_CHECKING([if libtool supports shared libraries]) + AC_MSG_RESULT([$can_build_shared]) + + AC_MSG_CHECKING([whether to build shared libraries]) + test "$can_build_shared" = "no" && enable_shared=no + + # On AIX, shared libraries and static libraries use the same namespace, and + # are all built from PIC. + case $host_os in + aix3*) + test "$enable_shared" = yes && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + + aix[[4-9]]*) + if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then + test "$enable_shared" = yes && enable_static=no + fi + ;; + esac + AC_MSG_RESULT([$enable_shared]) + + AC_MSG_CHECKING([whether to build static libraries]) + # Make sure either enable_shared or enable_static is yes. + test "$enable_shared" = yes || enable_static=yes + AC_MSG_RESULT([$enable_static]) + + _LT_CONFIG($1) +fi +AC_LANG_POP +CC="$lt_save_CC" +])# _LT_LANG_C_CONFIG + + +# _LT_LANG_CXX_CONFIG([TAG]) +# -------------------------- +# Ensure that the configuration variables for a C++ compiler are suitably +# defined. These variables are subsequently used by _LT_CONFIG to write +# the compiler configuration to `libtool'. +m4_defun([_LT_LANG_CXX_CONFIG], +[m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_EGREP])dnl +m4_require([_LT_PATH_MANIFEST_TOOL])dnl +if test -n "$CXX" && ( test "X$CXX" != "Xno" && + ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) || + (test "X$CXX" != "Xg++"))) ; then + AC_PROG_CXXCPP +else + _lt_caught_CXX_error=yes +fi + +AC_LANG_PUSH(C++) +_LT_TAGVAR(archive_cmds_need_lc, $1)=no +_LT_TAGVAR(allow_undefined_flag, $1)= +_LT_TAGVAR(always_export_symbols, $1)=no +_LT_TAGVAR(archive_expsym_cmds, $1)= +_LT_TAGVAR(compiler_needs_object, $1)=no +_LT_TAGVAR(export_dynamic_flag_spec, $1)= +_LT_TAGVAR(hardcode_direct, $1)=no +_LT_TAGVAR(hardcode_direct_absolute, $1)=no +_LT_TAGVAR(hardcode_libdir_flag_spec, $1)= +_LT_TAGVAR(hardcode_libdir_separator, $1)= +_LT_TAGVAR(hardcode_minus_L, $1)=no +_LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported +_LT_TAGVAR(hardcode_automatic, $1)=no +_LT_TAGVAR(inherit_rpath, $1)=no +_LT_TAGVAR(module_cmds, $1)= +_LT_TAGVAR(module_expsym_cmds, $1)= +_LT_TAGVAR(link_all_deplibs, $1)=unknown +_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_TAGVAR(reload_flag, $1)=$reload_flag +_LT_TAGVAR(reload_cmds, $1)=$reload_cmds +_LT_TAGVAR(no_undefined_flag, $1)= +_LT_TAGVAR(whole_archive_flag_spec, $1)= +_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no + +# Source file extension for C++ test sources. +ac_ext=cpp + +# Object file extension for compiled C++ test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# No sense in running all these tests if we already determined that +# the CXX compiler isn't working. Some variables (like enable_shared) +# are currently assumed to apply to all compilers on this platform, +# and will be corrupted by setting them based on a non-working compiler. +if test "$_lt_caught_CXX_error" != yes; then + # Code to be used in simple compile tests + lt_simple_compile_test_code="int some_variable = 0;" + + # Code to be used in simple link tests + lt_simple_link_test_code='int main(int, char *[[]]) { return(0); }' + + # ltmain only uses $CC for tagged configurations so make sure $CC is set. + _LT_TAG_COMPILER + + # save warnings/boilerplate of simple test code + _LT_COMPILER_BOILERPLATE + _LT_LINKER_BOILERPLATE + + # Allow CC to be a program name with arguments. + lt_save_CC=$CC + lt_save_CFLAGS=$CFLAGS + lt_save_LD=$LD + lt_save_GCC=$GCC + GCC=$GXX + lt_save_with_gnu_ld=$with_gnu_ld + lt_save_path_LD=$lt_cv_path_LD + if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then + lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx + else + $as_unset lt_cv_prog_gnu_ld + fi + if test -n "${lt_cv_path_LDCXX+set}"; then + lt_cv_path_LD=$lt_cv_path_LDCXX + else + $as_unset lt_cv_path_LD + fi + test -z "${LDCXX+set}" || LD=$LDCXX + CC=${CXX-"c++"} + CFLAGS=$CXXFLAGS + compiler=$CC + _LT_TAGVAR(compiler, $1)=$CC + _LT_CC_BASENAME([$compiler]) + + if test -n "$compiler"; then + # We don't want -fno-exception when compiling C++ code, so set the + # no_builtin_flag separately + if test "$GXX" = yes; then + _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' + else + _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= + fi + + if test "$GXX" = yes; then + # Set up default GNU C++ configuration + + LT_PATH_LD + + # Check if GNU C++ uses GNU ld as the underlying linker, since the + # archiving commands below assume that GNU ld is being used. + if test "$with_gnu_ld" = yes; then + _LT_TAGVAR(archive_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + + # If archive_cmds runs LD, not CC, wlarc should be empty + # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to + # investigate it a little bit more. (MM) + wlarc='${wl}' + + # ancient GNU ld didn't support --whole-archive et. al. + if eval "`$CC -print-prog-name=ld` --help 2>&1" | + $GREP 'no-whole-archive' > /dev/null; then + _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + _LT_TAGVAR(whole_archive_flag_spec, $1)= + fi + else + with_gnu_ld=no + wlarc= + + # A generic and very simple default shared library creation + # command for GNU C++ for the case where it uses the native + # linker, instead of GNU ld. If possible, this setting should + # overridden to take advantage of the native linker features on + # the platform it is being used on. + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' + fi + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' + + else + GXX=no + with_gnu_ld=no + wlarc= + fi + + # PORTME: fill in a description of your system's C++ link characteristics + AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) + _LT_TAGVAR(ld_shlibs, $1)=yes + case $host_os in + aix3*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + aix[[4-9]]*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*) + for ld_flag in $LDFLAGS; do + case $ld_flag in + *-brtl*) + aix_use_runtimelinking=yes + break + ;; + esac + done + ;; + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + _LT_TAGVAR(archive_cmds, $1)='' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(file_list_spec, $1)='${wl}-f,' + + if test "$GXX" = yes; then + case $host_os in aix4.[[012]]|aix4.[[012]].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && + strings "$collect2name" | $GREP resolve_lib_name >/dev/null + then + # We have reworked collect2 + : + else + # We have old collect2 + _LT_TAGVAR(hardcode_direct, $1)=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)= + fi + esac + shared_flag='-shared' + if test "$aix_use_runtimelinking" = yes; then + shared_flag="$shared_flag "'${wl}-G' + fi + else + # not using gcc + if test "$host_cpu" = ia64; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='${wl}-G' + else + shared_flag='${wl}-bM:SRE' + fi + fi + fi + + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall' + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to + # export. + _LT_TAGVAR(always_export_symbols, $1)=yes + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + _LT_TAGVAR(allow_undefined_flag, $1)='-berok' + # Determine the default libpath from the value encoded in an empty + # executable. + _LT_SYS_MODULE_PATH_AIX([$1]) + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' + _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs" + _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an + # empty executable. + _LT_SYS_MODULE_PATH_AIX([$1]) + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' + _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' + if test "$with_gnu_ld" = yes; then + # We only use this code for GNU lds that support --whole-archive. + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive' + else + # Exported symbols can be pulled into shared objects from archives + _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience' + fi + _LT_TAGVAR(archive_cmds_need_lc, $1)=yes + # This is similar to how AIX traditionally builds its shared + # libraries. + _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + fi + fi + ;; + + beos*) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + # Joseph Beckenbach says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + chorus*) + case $cc_basename in + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + cygwin* | mingw* | pw32* | cegcc*) + case $GXX,$cc_basename in + ,cl* | no,cl*) + # Native MSVC + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(always_export_symbols, $1)=yes + _LT_TAGVAR(file_list_spec, $1)='@' + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=".dll" + # FIXME: Setting linknames here is a bad hack. + _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames=' + _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + $SED -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp; + else + $SED -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp; + fi~ + $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ + linknames=' + # The linker will not automatically build a static lib if we build a DLL. + # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + # Don't use ranlib + _LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib' + _LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~ + lt_tool_outputfile="@TOOL_OUTPUT@"~ + case $lt_outputfile in + *.exe|*.EXE) ;; + *) + lt_outputfile="$lt_outputfile.exe" + lt_tool_outputfile="$lt_tool_outputfile.exe" + ;; + esac~ + func_to_tool_file "$lt_outputfile"~ + if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then + $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; + $RM "$lt_outputfile.manifest"; + fi' + ;; + *) + # g++ + # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, + # as there is no search path for DLLs. + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-all-symbols' + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(always_export_symbols, $1)=no + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + + if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is; otherwise, prepend... + _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + darwin* | rhapsody*) + _LT_DARWIN_LINKER_FEATURES($1) + ;; + + dgux*) + case $cc_basename in + ec++*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + ghcx*) + # Green Hills C++ Compiler + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + freebsd2.*) + # C++ shared libraries reported to be fairly broken before + # switch to ELF + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + freebsd-elf*) + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + ;; + + freebsd* | dragonfly*) + # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF + # conventions + _LT_TAGVAR(ld_shlibs, $1)=yes + ;; + + haiku*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(link_all_deplibs, $1)=yes + ;; + + hpux9*) + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, + # but as the default + # location of the library. + + case $cc_basename in + CC*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + aCC*) + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' + ;; + *) + if test "$GXX" = yes; then + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -nostdlib $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + else + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + + hpux10*|hpux11*) + if test $with_gnu_ld = no; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + case $host_cpu in + hppa*64*|ia64*) + ;; + *) + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + ;; + esac + fi + case $host_cpu in + hppa*64*|ia64*) + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + *) + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, + # but as the default + # location of the library. + ;; + esac + + case $cc_basename in + CC*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + aCC*) + case $host_cpu in + hppa*64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + ia64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + esac + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' + ;; + *) + if test "$GXX" = yes; then + if test $with_gnu_ld = no; then + case $host_cpu in + hppa*64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + ia64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + esac + fi + else + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + + interix[[3-9]]*) + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. + # Instead, shared libraries are loaded at an image base (0x10000000 by + # default) and relocated if they conflict, which is a slow very memory + # consuming and fragmenting process. To avoid this, we pick a random, + # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link + # time. Moving up from 0x10000000 also allows more sbrk(2) space. + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + ;; + irix5* | irix6*) + case $cc_basename in + CC*) + # SGI C++ + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' + + # Archives containing C++ object files must be created using + # "CC -ar", where "CC" is the IRIX C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + _LT_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs' + ;; + *) + if test "$GXX" = yes; then + if test "$with_gnu_ld" = no; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` -o $lib' + fi + fi + _LT_TAGVAR(link_all_deplibs, $1)=yes + ;; + esac + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(inherit_rpath, $1)=yes + ;; + + linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) + case $cc_basename in + KCC*) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib' + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + + # Archives containing C++ object files must be created using + # "CC -Bstatic", where "CC" is the KAI C++ compiler. + _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' + ;; + icpc* | ecpc* ) + # Intel C++ + with_gnu_ld=yes + # version 8.0 and above of icpc choke on multiply defined symbols + # if we add $predep_objects and $postdep_objects, however 7.1 and + # earlier do not add the objects themselves. + case `$CC -V 2>&1` in + *"Version 7."*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + ;; + *) # Version 8.0 or newer + tmp_idyn= + case $host_cpu in + ia64*) tmp_idyn=' -i_dynamic';; + esac + _LT_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + ;; + esac + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive' + ;; + pgCC* | pgcpp*) + # Portland Group C++ compiler + case `$CC -V` in + *pgCC\ [[1-5]].* | *pgcpp\ [[1-5]].*) + _LT_TAGVAR(prelink_cmds, $1)='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~ + compile_command="$compile_command `find $tpldir -name \*.o | sort | $NL2SP`"' + _LT_TAGVAR(old_archive_cmds, $1)='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~ + $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | sort | $NL2SP`~ + $RANLIB $oldlib' + _LT_TAGVAR(archive_cmds, $1)='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ + $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ + $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' + ;; + *) # Version 6 and above use weak symbols + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' + ;; + esac + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + ;; + cxx*) + # Compaq C++ + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib ${wl}-retain-symbols-file $wl$export_symbols' + + runpath_var=LD_RUN_PATH + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "X$list" | $Xsed' + ;; + xl* | mpixl* | bgxl*) + # IBM XL 8.0 on PPC, with GNU ld + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + _LT_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + if test "x$supports_anon_versioning" = xyes; then + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' + fi + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C++ 5.9 + _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs' + _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file ${wl}$export_symbols' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + _LT_TAGVAR(compiler_needs_object, $1)=yes + + # Not sure whether something based on + # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 + # would be better. + output_verbose_link_cmd='func_echo_all' + + # Archives containing C++ object files must be created using + # "CC -xar", where "CC" is the Sun C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' + ;; + esac + ;; + esac + ;; + + lynxos*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + m88k*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + mvs*) + case $cc_basename in + cxx*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags' + wlarc= + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + fi + # Workaround some broken pre-1.5 toolchains + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"' + ;; + + *nto* | *qnx*) + _LT_TAGVAR(ld_shlibs, $1)=yes + ;; + + openbsd2*) + # C++ shared libraries are fairly broken + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + openbsd*) + if test -f /usr/libexec/ld.so; then + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + fi + output_verbose_link_cmd=func_echo_all + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + osf3* | osf4* | osf5*) + case $cc_basename in + KCC*) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + # Archives containing C++ object files must be created using + # the KAI C++ compiler. + case $host in + osf3*) _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;; + *) _LT_TAGVAR(old_archive_cmds, $1)='$CC -o $oldlib $oldobjs' ;; + esac + ;; + RCC*) + # Rational C++ 2.4.1 + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + cxx*) + case $host in + osf3*) + _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && func_echo_all "${wl}-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + ;; + *) + _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~ + echo "-hidden">> $lib.exp~ + $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname ${wl}-input ${wl}$lib.exp `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~ + $RM $lib.exp' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' + ;; + esac + + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' + ;; + *) + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + case $host in + osf3*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + ;; + esac + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' + + else + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + + psos*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + sunos4*) + case $cc_basename in + CC*) + # Sun C++ 4.x + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + lcc*) + # Lucid + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + solaris*) + case $cc_basename in + CC* | sunCC*) + # Sun C++ 4.2, 5.x and Centerline C++ + _LT_TAGVAR(archive_cmds_need_lc,$1)=yes + _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs' + _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -G${allow_undefined_flag} ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + case $host_os in + solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; + *) + # The compiler driver will combine and reorder linker options, + # but understands `-z linker_flag'. + # Supported since Solaris 2.6 (maybe 2.5.1?) + _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' + ;; + esac + _LT_TAGVAR(link_all_deplibs, $1)=yes + + output_verbose_link_cmd='func_echo_all' + + # Archives containing C++ object files must be created using + # "CC -xar", where "CC" is the Sun C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' + ;; + gcx*) + # Green Hills C++ Compiler + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + + # The C++ compiler must be used to create the archive. + _LT_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs' + ;; + *) + # GNU C++ compiler with Solaris linker + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-z ${wl}defs' + if $CC --version | $GREP -v '^2\.7' > /dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -shared $pic_flag -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' + else + # g++ 2.7 appears to require `-G' NOT `-shared' on this + # platform. + _LT_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' + fi + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $wl$libdir' + case $host_os in + solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; + *) + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' + ;; + esac + fi + ;; + esac + ;; + + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*) + _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + runpath_var='LD_RUN_PATH' + + case $cc_basename in + CC*) + _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + ;; + + sysv5* | sco3.2v5* | sco5v6*) + # Note: We can NOT use -z defs as we might desire, because we do not + # link with -lc, and that would cause any symbols used from libc to + # always be unresolved, which means just about no library would + # ever link correctly. If we're not using GNU ld we use -z text + # though, which does catch some bad symbols but isn't as heavy-handed + # as -z defs. + _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' + _LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs' + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport' + runpath_var='LD_RUN_PATH' + + case $cc_basename in + CC*) + _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(old_archive_cmds, $1)='$CC -Tprelink_objects $oldobjs~ + '"$_LT_TAGVAR(old_archive_cmds, $1)" + _LT_TAGVAR(reload_cmds, $1)='$CC -Tprelink_objects $reload_objs~ + '"$_LT_TAGVAR(reload_cmds, $1)" + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + ;; + + tandem*) + case $cc_basename in + NCC*) + # NonStop-UX NCC 3.20 + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + vxworks*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + + AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)]) + test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no + + _LT_TAGVAR(GCC, $1)="$GXX" + _LT_TAGVAR(LD, $1)="$LD" + + ## CAVEAT EMPTOR: + ## There is no encapsulation within the following macros, do not change + ## the running order or otherwise move them around unless you know exactly + ## what you are doing... + _LT_SYS_HIDDEN_LIBDEPS($1) + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_SYS_DYNAMIC_LINKER($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + + _LT_CONFIG($1) + fi # test -n "$compiler" + + CC=$lt_save_CC + CFLAGS=$lt_save_CFLAGS + LDCXX=$LD + LD=$lt_save_LD + GCC=$lt_save_GCC + with_gnu_ld=$lt_save_with_gnu_ld + lt_cv_path_LDCXX=$lt_cv_path_LD + lt_cv_path_LD=$lt_save_path_LD + lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld + lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld +fi # test "$_lt_caught_CXX_error" != yes + +AC_LANG_POP +])# _LT_LANG_CXX_CONFIG + + +# _LT_FUNC_STRIPNAME_CNF +# ---------------------- +# func_stripname_cnf prefix suffix name +# strip PREFIX and SUFFIX off of NAME. +# PREFIX and SUFFIX must not contain globbing or regex special +# characters, hashes, percent signs, but SUFFIX may contain a leading +# dot (in which case that matches only a dot). +# +# This function is identical to the (non-XSI) version of func_stripname, +# except this one can be used by m4 code that may be executed by configure, +# rather than the libtool script. +m4_defun([_LT_FUNC_STRIPNAME_CNF],[dnl +AC_REQUIRE([_LT_DECL_SED]) +AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH]) +func_stripname_cnf () +{ + case ${2} in + .*) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;; + *) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%${2}\$%%"`;; + esac +} # func_stripname_cnf +])# _LT_FUNC_STRIPNAME_CNF + +# _LT_SYS_HIDDEN_LIBDEPS([TAGNAME]) +# --------------------------------- +# Figure out "hidden" library dependencies from verbose +# compiler output when linking a shared library. +# Parse the compiler output and extract the necessary +# objects, libraries and library flags. +m4_defun([_LT_SYS_HIDDEN_LIBDEPS], +[m4_require([_LT_FILEUTILS_DEFAULTS])dnl +AC_REQUIRE([_LT_FUNC_STRIPNAME_CNF])dnl +# Dependencies to place before and after the object being linked: +_LT_TAGVAR(predep_objects, $1)= +_LT_TAGVAR(postdep_objects, $1)= +_LT_TAGVAR(predeps, $1)= +_LT_TAGVAR(postdeps, $1)= +_LT_TAGVAR(compiler_lib_search_path, $1)= + +dnl we can't use the lt_simple_compile_test_code here, +dnl because it contains code intended for an executable, +dnl not a library. It's possible we should let each +dnl tag define a new lt_????_link_test_code variable, +dnl but it's only used here... +m4_if([$1], [], [cat > conftest.$ac_ext <<_LT_EOF +int a; +void foo (void) { a = 0; } +_LT_EOF +], [$1], [CXX], [cat > conftest.$ac_ext <<_LT_EOF +class Foo +{ +public: + Foo (void) { a = 0; } +private: + int a; +}; +_LT_EOF +], [$1], [F77], [cat > conftest.$ac_ext <<_LT_EOF + subroutine foo + implicit none + integer*4 a + a=0 + return + end +_LT_EOF +], [$1], [FC], [cat > conftest.$ac_ext <<_LT_EOF + subroutine foo + implicit none + integer a + a=0 + return + end +_LT_EOF +], [$1], [GCJ], [cat > conftest.$ac_ext <<_LT_EOF +public class foo { + private int a; + public void bar (void) { + a = 0; + } +}; +_LT_EOF +], [$1], [GO], [cat > conftest.$ac_ext <<_LT_EOF +package foo +func foo() { +} +_LT_EOF +]) + +_lt_libdeps_save_CFLAGS=$CFLAGS +case "$CC $CFLAGS " in #( +*\ -flto*\ *) CFLAGS="$CFLAGS -fno-lto" ;; +*\ -fwhopr*\ *) CFLAGS="$CFLAGS -fno-whopr" ;; +*\ -fuse-linker-plugin*\ *) CFLAGS="$CFLAGS -fno-use-linker-plugin" ;; +esac + +dnl Parse the compiler output and extract the necessary +dnl objects, libraries and library flags. +if AC_TRY_EVAL(ac_compile); then + # Parse the compiler output and extract the necessary + # objects, libraries and library flags. + + # Sentinel used to keep track of whether or not we are before + # the conftest object file. + pre_test_object_deps_done=no + + for p in `eval "$output_verbose_link_cmd"`; do + case ${prev}${p} in + + -L* | -R* | -l*) + # Some compilers place space between "-{L,R}" and the path. + # Remove the space. + if test $p = "-L" || + test $p = "-R"; then + prev=$p + continue + fi + + # Expand the sysroot to ease extracting the directories later. + if test -z "$prev"; then + case $p in + -L*) func_stripname_cnf '-L' '' "$p"; prev=-L; p=$func_stripname_result ;; + -R*) func_stripname_cnf '-R' '' "$p"; prev=-R; p=$func_stripname_result ;; + -l*) func_stripname_cnf '-l' '' "$p"; prev=-l; p=$func_stripname_result ;; + esac + fi + case $p in + =*) func_stripname_cnf '=' '' "$p"; p=$lt_sysroot$func_stripname_result ;; + esac + if test "$pre_test_object_deps_done" = no; then + case ${prev} in + -L | -R) + # Internal compiler library paths should come after those + # provided the user. The postdeps already come after the + # user supplied libs so there is no need to process them. + if test -z "$_LT_TAGVAR(compiler_lib_search_path, $1)"; then + _LT_TAGVAR(compiler_lib_search_path, $1)="${prev}${p}" + else + _LT_TAGVAR(compiler_lib_search_path, $1)="${_LT_TAGVAR(compiler_lib_search_path, $1)} ${prev}${p}" + fi + ;; + # The "-l" case would never come before the object being + # linked, so don't bother handling this case. + esac + else + if test -z "$_LT_TAGVAR(postdeps, $1)"; then + _LT_TAGVAR(postdeps, $1)="${prev}${p}" + else + _LT_TAGVAR(postdeps, $1)="${_LT_TAGVAR(postdeps, $1)} ${prev}${p}" + fi + fi + prev= + ;; + + *.lto.$objext) ;; # Ignore GCC LTO objects + *.$objext) + # This assumes that the test object file only shows up + # once in the compiler output. + if test "$p" = "conftest.$objext"; then + pre_test_object_deps_done=yes + continue + fi + + if test "$pre_test_object_deps_done" = no; then + if test -z "$_LT_TAGVAR(predep_objects, $1)"; then + _LT_TAGVAR(predep_objects, $1)="$p" + else + _LT_TAGVAR(predep_objects, $1)="$_LT_TAGVAR(predep_objects, $1) $p" + fi + else + if test -z "$_LT_TAGVAR(postdep_objects, $1)"; then + _LT_TAGVAR(postdep_objects, $1)="$p" + else + _LT_TAGVAR(postdep_objects, $1)="$_LT_TAGVAR(postdep_objects, $1) $p" + fi + fi + ;; + + *) ;; # Ignore the rest. + + esac + done + + # Clean up. + rm -f a.out a.exe +else + echo "libtool.m4: error: problem compiling $1 test program" +fi + +$RM -f confest.$objext +CFLAGS=$_lt_libdeps_save_CFLAGS + +# PORTME: override above test on systems where it is broken +m4_if([$1], [CXX], +[case $host_os in +interix[[3-9]]*) + # Interix 3.5 installs completely hosed .la files for C++, so rather than + # hack all around it, let's just trust "g++" to DTRT. + _LT_TAGVAR(predep_objects,$1)= + _LT_TAGVAR(postdep_objects,$1)= + _LT_TAGVAR(postdeps,$1)= + ;; + +linux*) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C++ 5.9 + + # The more standards-conforming stlport4 library is + # incompatible with the Cstd library. Avoid specifying + # it if it's in CXXFLAGS. Ignore libCrun as + # -library=stlport4 depends on it. + case " $CXX $CXXFLAGS " in + *" -library=stlport4 "*) + solaris_use_stlport4=yes + ;; + esac + + if test "$solaris_use_stlport4" != yes; then + _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun' + fi + ;; + esac + ;; + +solaris*) + case $cc_basename in + CC* | sunCC*) + # The more standards-conforming stlport4 library is + # incompatible with the Cstd library. Avoid specifying + # it if it's in CXXFLAGS. Ignore libCrun as + # -library=stlport4 depends on it. + case " $CXX $CXXFLAGS " in + *" -library=stlport4 "*) + solaris_use_stlport4=yes + ;; + esac + + # Adding this requires a known-good setup of shared libraries for + # Sun compiler versions before 5.6, else PIC objects from an old + # archive will be linked into the output, leading to subtle bugs. + if test "$solaris_use_stlport4" != yes; then + _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun' + fi + ;; + esac + ;; +esac +]) + +case " $_LT_TAGVAR(postdeps, $1) " in +*" -lc "*) _LT_TAGVAR(archive_cmds_need_lc, $1)=no ;; +esac + _LT_TAGVAR(compiler_lib_search_dirs, $1)= +if test -n "${_LT_TAGVAR(compiler_lib_search_path, $1)}"; then + _LT_TAGVAR(compiler_lib_search_dirs, $1)=`echo " ${_LT_TAGVAR(compiler_lib_search_path, $1)}" | ${SED} -e 's! -L! !g' -e 's!^ !!'` +fi +_LT_TAGDECL([], [compiler_lib_search_dirs], [1], + [The directories searched by this compiler when creating a shared library]) +_LT_TAGDECL([], [predep_objects], [1], + [Dependencies to place before and after the objects being linked to + create a shared library]) +_LT_TAGDECL([], [postdep_objects], [1]) +_LT_TAGDECL([], [predeps], [1]) +_LT_TAGDECL([], [postdeps], [1]) +_LT_TAGDECL([], [compiler_lib_search_path], [1], + [The library search path used internally by the compiler when linking + a shared library]) +])# _LT_SYS_HIDDEN_LIBDEPS + + +# _LT_LANG_F77_CONFIG([TAG]) +# -------------------------- +# Ensure that the configuration variables for a Fortran 77 compiler are +# suitably defined. These variables are subsequently used by _LT_CONFIG +# to write the compiler configuration to `libtool'. +m4_defun([_LT_LANG_F77_CONFIG], +[AC_LANG_PUSH(Fortran 77) +if test -z "$F77" || test "X$F77" = "Xno"; then + _lt_disable_F77=yes +fi + +_LT_TAGVAR(archive_cmds_need_lc, $1)=no +_LT_TAGVAR(allow_undefined_flag, $1)= +_LT_TAGVAR(always_export_symbols, $1)=no +_LT_TAGVAR(archive_expsym_cmds, $1)= +_LT_TAGVAR(export_dynamic_flag_spec, $1)= +_LT_TAGVAR(hardcode_direct, $1)=no +_LT_TAGVAR(hardcode_direct_absolute, $1)=no +_LT_TAGVAR(hardcode_libdir_flag_spec, $1)= +_LT_TAGVAR(hardcode_libdir_separator, $1)= +_LT_TAGVAR(hardcode_minus_L, $1)=no +_LT_TAGVAR(hardcode_automatic, $1)=no +_LT_TAGVAR(inherit_rpath, $1)=no +_LT_TAGVAR(module_cmds, $1)= +_LT_TAGVAR(module_expsym_cmds, $1)= +_LT_TAGVAR(link_all_deplibs, $1)=unknown +_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_TAGVAR(reload_flag, $1)=$reload_flag +_LT_TAGVAR(reload_cmds, $1)=$reload_cmds +_LT_TAGVAR(no_undefined_flag, $1)= +_LT_TAGVAR(whole_archive_flag_spec, $1)= +_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no + +# Source file extension for f77 test sources. +ac_ext=f + +# Object file extension for compiled f77 test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# No sense in running all these tests if we already determined that +# the F77 compiler isn't working. Some variables (like enable_shared) +# are currently assumed to apply to all compilers on this platform, +# and will be corrupted by setting them based on a non-working compiler. +if test "$_lt_disable_F77" != yes; then + # Code to be used in simple compile tests + lt_simple_compile_test_code="\ + subroutine t + return + end +" + + # Code to be used in simple link tests + lt_simple_link_test_code="\ + program t + end +" + + # ltmain only uses $CC for tagged configurations so make sure $CC is set. + _LT_TAG_COMPILER + + # save warnings/boilerplate of simple test code + _LT_COMPILER_BOILERPLATE + _LT_LINKER_BOILERPLATE + + # Allow CC to be a program name with arguments. + lt_save_CC="$CC" + lt_save_GCC=$GCC + lt_save_CFLAGS=$CFLAGS + CC=${F77-"f77"} + CFLAGS=$FFLAGS + compiler=$CC + _LT_TAGVAR(compiler, $1)=$CC + _LT_CC_BASENAME([$compiler]) + GCC=$G77 + if test -n "$compiler"; then + AC_MSG_CHECKING([if libtool supports shared libraries]) + AC_MSG_RESULT([$can_build_shared]) + + AC_MSG_CHECKING([whether to build shared libraries]) + test "$can_build_shared" = "no" && enable_shared=no + + # On AIX, shared libraries and static libraries use the same namespace, and + # are all built from PIC. + case $host_os in + aix3*) + test "$enable_shared" = yes && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + aix[[4-9]]*) + if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then + test "$enable_shared" = yes && enable_static=no + fi + ;; + esac + AC_MSG_RESULT([$enable_shared]) + + AC_MSG_CHECKING([whether to build static libraries]) + # Make sure either enable_shared or enable_static is yes. + test "$enable_shared" = yes || enable_static=yes + AC_MSG_RESULT([$enable_static]) + + _LT_TAGVAR(GCC, $1)="$G77" + _LT_TAGVAR(LD, $1)="$LD" + + ## CAVEAT EMPTOR: + ## There is no encapsulation within the following macros, do not change + ## the running order or otherwise move them around unless you know exactly + ## what you are doing... + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_SYS_DYNAMIC_LINKER($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + + _LT_CONFIG($1) + fi # test -n "$compiler" + + GCC=$lt_save_GCC + CC="$lt_save_CC" + CFLAGS="$lt_save_CFLAGS" +fi # test "$_lt_disable_F77" != yes + +AC_LANG_POP +])# _LT_LANG_F77_CONFIG + + +# _LT_LANG_FC_CONFIG([TAG]) +# ------------------------- +# Ensure that the configuration variables for a Fortran compiler are +# suitably defined. These variables are subsequently used by _LT_CONFIG +# to write the compiler configuration to `libtool'. +m4_defun([_LT_LANG_FC_CONFIG], +[AC_LANG_PUSH(Fortran) + +if test -z "$FC" || test "X$FC" = "Xno"; then + _lt_disable_FC=yes +fi + +_LT_TAGVAR(archive_cmds_need_lc, $1)=no +_LT_TAGVAR(allow_undefined_flag, $1)= +_LT_TAGVAR(always_export_symbols, $1)=no +_LT_TAGVAR(archive_expsym_cmds, $1)= +_LT_TAGVAR(export_dynamic_flag_spec, $1)= +_LT_TAGVAR(hardcode_direct, $1)=no +_LT_TAGVAR(hardcode_direct_absolute, $1)=no +_LT_TAGVAR(hardcode_libdir_flag_spec, $1)= +_LT_TAGVAR(hardcode_libdir_separator, $1)= +_LT_TAGVAR(hardcode_minus_L, $1)=no +_LT_TAGVAR(hardcode_automatic, $1)=no +_LT_TAGVAR(inherit_rpath, $1)=no +_LT_TAGVAR(module_cmds, $1)= +_LT_TAGVAR(module_expsym_cmds, $1)= +_LT_TAGVAR(link_all_deplibs, $1)=unknown +_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_TAGVAR(reload_flag, $1)=$reload_flag +_LT_TAGVAR(reload_cmds, $1)=$reload_cmds +_LT_TAGVAR(no_undefined_flag, $1)= +_LT_TAGVAR(whole_archive_flag_spec, $1)= +_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no + +# Source file extension for fc test sources. +ac_ext=${ac_fc_srcext-f} + +# Object file extension for compiled fc test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# No sense in running all these tests if we already determined that +# the FC compiler isn't working. Some variables (like enable_shared) +# are currently assumed to apply to all compilers on this platform, +# and will be corrupted by setting them based on a non-working compiler. +if test "$_lt_disable_FC" != yes; then + # Code to be used in simple compile tests + lt_simple_compile_test_code="\ + subroutine t + return + end +" + + # Code to be used in simple link tests + lt_simple_link_test_code="\ + program t + end +" + + # ltmain only uses $CC for tagged configurations so make sure $CC is set. + _LT_TAG_COMPILER + + # save warnings/boilerplate of simple test code + _LT_COMPILER_BOILERPLATE + _LT_LINKER_BOILERPLATE + + # Allow CC to be a program name with arguments. + lt_save_CC="$CC" + lt_save_GCC=$GCC + lt_save_CFLAGS=$CFLAGS + CC=${FC-"f95"} + CFLAGS=$FCFLAGS + compiler=$CC + GCC=$ac_cv_fc_compiler_gnu + + _LT_TAGVAR(compiler, $1)=$CC + _LT_CC_BASENAME([$compiler]) + + if test -n "$compiler"; then + AC_MSG_CHECKING([if libtool supports shared libraries]) + AC_MSG_RESULT([$can_build_shared]) + + AC_MSG_CHECKING([whether to build shared libraries]) + test "$can_build_shared" = "no" && enable_shared=no + + # On AIX, shared libraries and static libraries use the same namespace, and + # are all built from PIC. + case $host_os in + aix3*) + test "$enable_shared" = yes && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + aix[[4-9]]*) + if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then + test "$enable_shared" = yes && enable_static=no + fi + ;; + esac + AC_MSG_RESULT([$enable_shared]) + + AC_MSG_CHECKING([whether to build static libraries]) + # Make sure either enable_shared or enable_static is yes. + test "$enable_shared" = yes || enable_static=yes + AC_MSG_RESULT([$enable_static]) + + _LT_TAGVAR(GCC, $1)="$ac_cv_fc_compiler_gnu" + _LT_TAGVAR(LD, $1)="$LD" + + ## CAVEAT EMPTOR: + ## There is no encapsulation within the following macros, do not change + ## the running order or otherwise move them around unless you know exactly + ## what you are doing... + _LT_SYS_HIDDEN_LIBDEPS($1) + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_SYS_DYNAMIC_LINKER($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + + _LT_CONFIG($1) + fi # test -n "$compiler" + + GCC=$lt_save_GCC + CC=$lt_save_CC + CFLAGS=$lt_save_CFLAGS +fi # test "$_lt_disable_FC" != yes + +AC_LANG_POP +])# _LT_LANG_FC_CONFIG + + +# _LT_LANG_GCJ_CONFIG([TAG]) +# -------------------------- +# Ensure that the configuration variables for the GNU Java Compiler compiler +# are suitably defined. These variables are subsequently used by _LT_CONFIG +# to write the compiler configuration to `libtool'. +m4_defun([_LT_LANG_GCJ_CONFIG], +[AC_REQUIRE([LT_PROG_GCJ])dnl +AC_LANG_SAVE + +# Source file extension for Java test sources. +ac_ext=java + +# Object file extension for compiled Java test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="class foo {}" + +# Code to be used in simple link tests +lt_simple_link_test_code='public class conftest { public static void main(String[[]] argv) {}; }' + +# ltmain only uses $CC for tagged configurations so make sure $CC is set. +_LT_TAG_COMPILER + +# save warnings/boilerplate of simple test code +_LT_COMPILER_BOILERPLATE +_LT_LINKER_BOILERPLATE + +# Allow CC to be a program name with arguments. +lt_save_CC=$CC +lt_save_CFLAGS=$CFLAGS +lt_save_GCC=$GCC +GCC=yes +CC=${GCJ-"gcj"} +CFLAGS=$GCJFLAGS +compiler=$CC +_LT_TAGVAR(compiler, $1)=$CC +_LT_TAGVAR(LD, $1)="$LD" +_LT_CC_BASENAME([$compiler]) + +# GCJ did not exist at the time GCC didn't implicitly link libc in. +_LT_TAGVAR(archive_cmds_need_lc, $1)=no + +_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_TAGVAR(reload_flag, $1)=$reload_flag +_LT_TAGVAR(reload_cmds, $1)=$reload_cmds + +if test -n "$compiler"; then + _LT_COMPILER_NO_RTTI($1) + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + + _LT_CONFIG($1) +fi + +AC_LANG_RESTORE + +GCC=$lt_save_GCC +CC=$lt_save_CC +CFLAGS=$lt_save_CFLAGS +])# _LT_LANG_GCJ_CONFIG + + +# _LT_LANG_GO_CONFIG([TAG]) +# -------------------------- +# Ensure that the configuration variables for the GNU Go compiler +# are suitably defined. These variables are subsequently used by _LT_CONFIG +# to write the compiler configuration to `libtool'. +m4_defun([_LT_LANG_GO_CONFIG], +[AC_REQUIRE([LT_PROG_GO])dnl +AC_LANG_SAVE + +# Source file extension for Go test sources. +ac_ext=go + +# Object file extension for compiled Go test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="package main; func main() { }" + +# Code to be used in simple link tests +lt_simple_link_test_code='package main; func main() { }' + +# ltmain only uses $CC for tagged configurations so make sure $CC is set. +_LT_TAG_COMPILER + +# save warnings/boilerplate of simple test code +_LT_COMPILER_BOILERPLATE +_LT_LINKER_BOILERPLATE + +# Allow CC to be a program name with arguments. +lt_save_CC=$CC +lt_save_CFLAGS=$CFLAGS +lt_save_GCC=$GCC +GCC=yes +CC=${GOC-"gccgo"} +CFLAGS=$GOFLAGS +compiler=$CC +_LT_TAGVAR(compiler, $1)=$CC +_LT_TAGVAR(LD, $1)="$LD" +_LT_CC_BASENAME([$compiler]) + +# Go did not exist at the time GCC didn't implicitly link libc in. +_LT_TAGVAR(archive_cmds_need_lc, $1)=no + +_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_TAGVAR(reload_flag, $1)=$reload_flag +_LT_TAGVAR(reload_cmds, $1)=$reload_cmds + +if test -n "$compiler"; then + _LT_COMPILER_NO_RTTI($1) + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + + _LT_CONFIG($1) +fi + +AC_LANG_RESTORE + +GCC=$lt_save_GCC +CC=$lt_save_CC +CFLAGS=$lt_save_CFLAGS +])# _LT_LANG_GO_CONFIG + + +# _LT_LANG_RC_CONFIG([TAG]) +# ------------------------- +# Ensure that the configuration variables for the Windows resource compiler +# are suitably defined. These variables are subsequently used by _LT_CONFIG +# to write the compiler configuration to `libtool'. +m4_defun([_LT_LANG_RC_CONFIG], +[AC_REQUIRE([LT_PROG_RC])dnl +AC_LANG_SAVE + +# Source file extension for RC test sources. +ac_ext=rc + +# Object file extension for compiled RC test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code='sample MENU { MENUITEM "&Soup", 100, CHECKED }' + +# Code to be used in simple link tests +lt_simple_link_test_code="$lt_simple_compile_test_code" + +# ltmain only uses $CC for tagged configurations so make sure $CC is set. +_LT_TAG_COMPILER + +# save warnings/boilerplate of simple test code +_LT_COMPILER_BOILERPLATE +_LT_LINKER_BOILERPLATE + +# Allow CC to be a program name with arguments. +lt_save_CC="$CC" +lt_save_CFLAGS=$CFLAGS +lt_save_GCC=$GCC +GCC= +CC=${RC-"windres"} +CFLAGS= +compiler=$CC +_LT_TAGVAR(compiler, $1)=$CC +_LT_CC_BASENAME([$compiler]) +_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes + +if test -n "$compiler"; then + : + _LT_CONFIG($1) +fi + +GCC=$lt_save_GCC +AC_LANG_RESTORE +CC=$lt_save_CC +CFLAGS=$lt_save_CFLAGS +])# _LT_LANG_RC_CONFIG + + +# LT_PROG_GCJ +# ----------- +AC_DEFUN([LT_PROG_GCJ], +[m4_ifdef([AC_PROG_GCJ], [AC_PROG_GCJ], + [m4_ifdef([A][M_PROG_GCJ], [A][M_PROG_GCJ], + [AC_CHECK_TOOL(GCJ, gcj,) + test "x${GCJFLAGS+set}" = xset || GCJFLAGS="-g -O2" + AC_SUBST(GCJFLAGS)])])[]dnl +]) + +# Old name: +AU_ALIAS([LT_AC_PROG_GCJ], [LT_PROG_GCJ]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([LT_AC_PROG_GCJ], []) + + +# LT_PROG_GO +# ---------- +AC_DEFUN([LT_PROG_GO], +[AC_CHECK_TOOL(GOC, gccgo,) +]) + + +# LT_PROG_RC +# ---------- +AC_DEFUN([LT_PROG_RC], +[AC_CHECK_TOOL(RC, windres,) +]) + +# Old name: +AU_ALIAS([LT_AC_PROG_RC], [LT_PROG_RC]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([LT_AC_PROG_RC], []) + + +# _LT_DECL_EGREP +# -------------- +# If we don't have a new enough Autoconf to choose the best grep +# available, choose the one first in the user's PATH. +m4_defun([_LT_DECL_EGREP], +[AC_REQUIRE([AC_PROG_EGREP])dnl +AC_REQUIRE([AC_PROG_FGREP])dnl +test -z "$GREP" && GREP=grep +_LT_DECL([], [GREP], [1], [A grep program that handles long lines]) +_LT_DECL([], [EGREP], [1], [An ERE matcher]) +_LT_DECL([], [FGREP], [1], [A literal string matcher]) +dnl Non-bleeding-edge autoconf doesn't subst GREP, so do it here too +AC_SUBST([GREP]) +]) + + +# _LT_DECL_OBJDUMP +# -------------- +# If we don't have a new enough Autoconf to choose the best objdump +# available, choose the one first in the user's PATH. +m4_defun([_LT_DECL_OBJDUMP], +[AC_CHECK_TOOL(OBJDUMP, objdump, false) +test -z "$OBJDUMP" && OBJDUMP=objdump +_LT_DECL([], [OBJDUMP], [1], [An object symbol dumper]) +AC_SUBST([OBJDUMP]) +]) + +# _LT_DECL_DLLTOOL +# ---------------- +# Ensure DLLTOOL variable is set. +m4_defun([_LT_DECL_DLLTOOL], +[AC_CHECK_TOOL(DLLTOOL, dlltool, false) +test -z "$DLLTOOL" && DLLTOOL=dlltool +_LT_DECL([], [DLLTOOL], [1], [DLL creation program]) +AC_SUBST([DLLTOOL]) +]) + +# _LT_DECL_SED +# ------------ +# Check for a fully-functional sed program, that truncates +# as few characters as possible. Prefer GNU sed if found. +m4_defun([_LT_DECL_SED], +[AC_PROG_SED +test -z "$SED" && SED=sed +Xsed="$SED -e 1s/^X//" +_LT_DECL([], [SED], [1], [A sed program that does not truncate output]) +_LT_DECL([], [Xsed], ["\$SED -e 1s/^X//"], + [Sed that helps us avoid accidentally triggering echo(1) options like -n]) +])# _LT_DECL_SED + +m4_ifndef([AC_PROG_SED], [ +# NOTE: This macro has been submitted for inclusion into # +# GNU Autoconf as AC_PROG_SED. When it is available in # +# a released version of Autoconf we should remove this # +# macro and use it instead. # + +m4_defun([AC_PROG_SED], +[AC_MSG_CHECKING([for a sed that does not truncate output]) +AC_CACHE_VAL(lt_cv_path_SED, +[# Loop through the user's path and test for sed and gsed. +# Then use that list of sed's as ones to test for truncation. +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for lt_ac_prog in sed gsed; do + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then + lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext" + fi + done + done +done +IFS=$as_save_IFS +lt_ac_max=0 +lt_ac_count=0 +# Add /usr/xpg4/bin/sed as it is typically found on Solaris +# along with /bin/sed that truncates output. +for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do + test ! -f $lt_ac_sed && continue + cat /dev/null > conftest.in + lt_ac_count=0 + echo $ECHO_N "0123456789$ECHO_C" >conftest.in + # Check for GNU sed and select it if it is found. + if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then + lt_cv_path_SED=$lt_ac_sed + break + fi + while true; do + cat conftest.in conftest.in >conftest.tmp + mv conftest.tmp conftest.in + cp conftest.in conftest.nl + echo >>conftest.nl + $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break + cmp -s conftest.out conftest.nl || break + # 10000 chars as input seems more than enough + test $lt_ac_count -gt 10 && break + lt_ac_count=`expr $lt_ac_count + 1` + if test $lt_ac_count -gt $lt_ac_max; then + lt_ac_max=$lt_ac_count + lt_cv_path_SED=$lt_ac_sed + fi + done +done +]) +SED=$lt_cv_path_SED +AC_SUBST([SED]) +AC_MSG_RESULT([$SED]) +])#AC_PROG_SED +])#m4_ifndef + +# Old name: +AU_ALIAS([LT_AC_PROG_SED], [AC_PROG_SED]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([LT_AC_PROG_SED], []) + + +# _LT_CHECK_SHELL_FEATURES +# ------------------------ +# Find out whether the shell is Bourne or XSI compatible, +# or has some other useful features. +m4_defun([_LT_CHECK_SHELL_FEATURES], +[AC_MSG_CHECKING([whether the shell understands some XSI constructs]) +# Try some XSI features +xsi_shell=no +( _lt_dummy="a/b/c" + test "${_lt_dummy##*/},${_lt_dummy%/*},${_lt_dummy#??}"${_lt_dummy%"$_lt_dummy"}, \ + = c,a/b,b/c, \ + && eval 'test $(( 1 + 1 )) -eq 2 \ + && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \ + && xsi_shell=yes +AC_MSG_RESULT([$xsi_shell]) +_LT_CONFIG_LIBTOOL_INIT([xsi_shell='$xsi_shell']) + +AC_MSG_CHECKING([whether the shell understands "+="]) +lt_shell_append=no +( foo=bar; set foo baz; eval "$[1]+=\$[2]" && test "$foo" = barbaz ) \ + >/dev/null 2>&1 \ + && lt_shell_append=yes +AC_MSG_RESULT([$lt_shell_append]) +_LT_CONFIG_LIBTOOL_INIT([lt_shell_append='$lt_shell_append']) + +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + lt_unset=unset +else + lt_unset=false +fi +_LT_DECL([], [lt_unset], [0], [whether the shell understands "unset"])dnl + +# test EBCDIC or ASCII +case `echo X|tr X '\101'` in + A) # ASCII based system + # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr + lt_SP2NL='tr \040 \012' + lt_NL2SP='tr \015\012 \040\040' + ;; + *) # EBCDIC based system + lt_SP2NL='tr \100 \n' + lt_NL2SP='tr \r\n \100\100' + ;; +esac +_LT_DECL([SP2NL], [lt_SP2NL], [1], [turn spaces into newlines])dnl +_LT_DECL([NL2SP], [lt_NL2SP], [1], [turn newlines into spaces])dnl +])# _LT_CHECK_SHELL_FEATURES + + +# _LT_PROG_FUNCTION_REPLACE (FUNCNAME, REPLACEMENT-BODY) +# ------------------------------------------------------ +# In `$cfgfile', look for function FUNCNAME delimited by `^FUNCNAME ()$' and +# '^} FUNCNAME ', and replace its body with REPLACEMENT-BODY. +m4_defun([_LT_PROG_FUNCTION_REPLACE], +[dnl { +sed -e '/^$1 ()$/,/^} # $1 /c\ +$1 ()\ +{\ +m4_bpatsubsts([$2], [$], [\\], [^\([ ]\)], [\\\1]) +} # Extended-shell $1 implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: +]) + + +# _LT_PROG_REPLACE_SHELLFNS +# ------------------------- +# Replace existing portable implementations of several shell functions with +# equivalent extended shell implementations where those features are available.. +m4_defun([_LT_PROG_REPLACE_SHELLFNS], +[if test x"$xsi_shell" = xyes; then + _LT_PROG_FUNCTION_REPLACE([func_dirname], [dnl + case ${1} in + */*) func_dirname_result="${1%/*}${2}" ;; + * ) func_dirname_result="${3}" ;; + esac]) + + _LT_PROG_FUNCTION_REPLACE([func_basename], [dnl + func_basename_result="${1##*/}"]) + + _LT_PROG_FUNCTION_REPLACE([func_dirname_and_basename], [dnl + case ${1} in + */*) func_dirname_result="${1%/*}${2}" ;; + * ) func_dirname_result="${3}" ;; + esac + func_basename_result="${1##*/}"]) + + _LT_PROG_FUNCTION_REPLACE([func_stripname], [dnl + # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are + # positional parameters, so assign one to ordinary parameter first. + func_stripname_result=${3} + func_stripname_result=${func_stripname_result#"${1}"} + func_stripname_result=${func_stripname_result%"${2}"}]) + + _LT_PROG_FUNCTION_REPLACE([func_split_long_opt], [dnl + func_split_long_opt_name=${1%%=*} + func_split_long_opt_arg=${1#*=}]) + + _LT_PROG_FUNCTION_REPLACE([func_split_short_opt], [dnl + func_split_short_opt_arg=${1#??} + func_split_short_opt_name=${1%"$func_split_short_opt_arg"}]) + + _LT_PROG_FUNCTION_REPLACE([func_lo2o], [dnl + case ${1} in + *.lo) func_lo2o_result=${1%.lo}.${objext} ;; + *) func_lo2o_result=${1} ;; + esac]) + + _LT_PROG_FUNCTION_REPLACE([func_xform], [ func_xform_result=${1%.*}.lo]) + + _LT_PROG_FUNCTION_REPLACE([func_arith], [ func_arith_result=$(( $[*] ))]) + + _LT_PROG_FUNCTION_REPLACE([func_len], [ func_len_result=${#1}]) +fi + +if test x"$lt_shell_append" = xyes; then + _LT_PROG_FUNCTION_REPLACE([func_append], [ eval "${1}+=\\${2}"]) + + _LT_PROG_FUNCTION_REPLACE([func_append_quoted], [dnl + func_quote_for_eval "${2}" +dnl m4 expansion turns \\\\ into \\, and then the shell eval turns that into \ + eval "${1}+=\\\\ \\$func_quote_for_eval_result"]) + + # Save a `func_append' function call where possible by direct use of '+=' + sed -e 's%func_append \([[a-zA-Z_]]\{1,\}\) "%\1+="%g' $cfgfile > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") + test 0 -eq $? || _lt_function_replace_fail=: +else + # Save a `func_append' function call even when '+=' is not available + sed -e 's%func_append \([[a-zA-Z_]]\{1,\}\) "%\1="$\1%g' $cfgfile > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") + test 0 -eq $? || _lt_function_replace_fail=: +fi + +if test x"$_lt_function_replace_fail" = x":"; then + AC_MSG_WARN([Unable to substitute extended shell functions in $ofile]) +fi +]) + +# _LT_PATH_CONVERSION_FUNCTIONS +# ----------------------------- +# Determine which file name conversion functions should be used by +# func_to_host_file (and, implicitly, by func_to_host_path). These are needed +# for certain cross-compile configurations and native mingw. +m4_defun([_LT_PATH_CONVERSION_FUNCTIONS], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_CANONICAL_BUILD])dnl +AC_MSG_CHECKING([how to convert $build file names to $host format]) +AC_CACHE_VAL(lt_cv_to_host_file_cmd, +[case $host in + *-*-mingw* ) + case $build in + *-*-mingw* ) # actually msys + lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32 + ;; + *-*-cygwin* ) + lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32 + ;; + * ) # otherwise, assume *nix + lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32 + ;; + esac + ;; + *-*-cygwin* ) + case $build in + *-*-mingw* ) # actually msys + lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin + ;; + *-*-cygwin* ) + lt_cv_to_host_file_cmd=func_convert_file_noop + ;; + * ) # otherwise, assume *nix + lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin + ;; + esac + ;; + * ) # unhandled hosts (and "normal" native builds) + lt_cv_to_host_file_cmd=func_convert_file_noop + ;; +esac +]) +to_host_file_cmd=$lt_cv_to_host_file_cmd +AC_MSG_RESULT([$lt_cv_to_host_file_cmd]) +_LT_DECL([to_host_file_cmd], [lt_cv_to_host_file_cmd], + [0], [convert $build file names to $host format])dnl + +AC_MSG_CHECKING([how to convert $build file names to toolchain format]) +AC_CACHE_VAL(lt_cv_to_tool_file_cmd, +[#assume ordinary cross tools, or native build. +lt_cv_to_tool_file_cmd=func_convert_file_noop +case $host in + *-*-mingw* ) + case $build in + *-*-mingw* ) # actually msys + lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32 + ;; + esac + ;; +esac +]) +to_tool_file_cmd=$lt_cv_to_tool_file_cmd +AC_MSG_RESULT([$lt_cv_to_tool_file_cmd]) +_LT_DECL([to_tool_file_cmd], [lt_cv_to_tool_file_cmd], + [0], [convert $build files to toolchain format])dnl +])# _LT_PATH_CONVERSION_FUNCTIONS + +# Helper functions for option handling. -*- Autoconf -*- +# +# Copyright (C) 2004, 2005, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# Written by Gary V. Vaughan, 2004 +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. + +# serial 7 ltoptions.m4 + +# This is to help aclocal find these macros, as it can't see m4_define. +AC_DEFUN([LTOPTIONS_VERSION], [m4_if([1])]) + + +# _LT_MANGLE_OPTION(MACRO-NAME, OPTION-NAME) +# ------------------------------------------ +m4_define([_LT_MANGLE_OPTION], +[[_LT_OPTION_]m4_bpatsubst($1__$2, [[^a-zA-Z0-9_]], [_])]) + + +# _LT_SET_OPTION(MACRO-NAME, OPTION-NAME) +# --------------------------------------- +# Set option OPTION-NAME for macro MACRO-NAME, and if there is a +# matching handler defined, dispatch to it. Other OPTION-NAMEs are +# saved as a flag. +m4_define([_LT_SET_OPTION], +[m4_define(_LT_MANGLE_OPTION([$1], [$2]))dnl +m4_ifdef(_LT_MANGLE_DEFUN([$1], [$2]), + _LT_MANGLE_DEFUN([$1], [$2]), + [m4_warning([Unknown $1 option `$2'])])[]dnl +]) + + +# _LT_IF_OPTION(MACRO-NAME, OPTION-NAME, IF-SET, [IF-NOT-SET]) +# ------------------------------------------------------------ +# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. +m4_define([_LT_IF_OPTION], +[m4_ifdef(_LT_MANGLE_OPTION([$1], [$2]), [$3], [$4])]) + + +# _LT_UNLESS_OPTIONS(MACRO-NAME, OPTION-LIST, IF-NOT-SET) +# ------------------------------------------------------- +# Execute IF-NOT-SET unless all options in OPTION-LIST for MACRO-NAME +# are set. +m4_define([_LT_UNLESS_OPTIONS], +[m4_foreach([_LT_Option], m4_split(m4_normalize([$2])), + [m4_ifdef(_LT_MANGLE_OPTION([$1], _LT_Option), + [m4_define([$0_found])])])[]dnl +m4_ifdef([$0_found], [m4_undefine([$0_found])], [$3 +])[]dnl +]) + + +# _LT_SET_OPTIONS(MACRO-NAME, OPTION-LIST) +# ---------------------------------------- +# OPTION-LIST is a space-separated list of Libtool options associated +# with MACRO-NAME. If any OPTION has a matching handler declared with +# LT_OPTION_DEFINE, dispatch to that macro; otherwise complain about +# the unknown option and exit. +m4_defun([_LT_SET_OPTIONS], +[# Set options +m4_foreach([_LT_Option], m4_split(m4_normalize([$2])), + [_LT_SET_OPTION([$1], _LT_Option)]) + +m4_if([$1],[LT_INIT],[ + dnl + dnl Simply set some default values (i.e off) if boolean options were not + dnl specified: + _LT_UNLESS_OPTIONS([LT_INIT], [dlopen], [enable_dlopen=no + ]) + _LT_UNLESS_OPTIONS([LT_INIT], [win32-dll], [enable_win32_dll=no + ]) + dnl + dnl If no reference was made to various pairs of opposing options, then + dnl we run the default mode handler for the pair. For example, if neither + dnl `shared' nor `disable-shared' was passed, we enable building of shared + dnl archives by default: + _LT_UNLESS_OPTIONS([LT_INIT], [shared disable-shared], [_LT_ENABLE_SHARED]) + _LT_UNLESS_OPTIONS([LT_INIT], [static disable-static], [_LT_ENABLE_STATIC]) + _LT_UNLESS_OPTIONS([LT_INIT], [pic-only no-pic], [_LT_WITH_PIC]) + _LT_UNLESS_OPTIONS([LT_INIT], [fast-install disable-fast-install], + [_LT_ENABLE_FAST_INSTALL]) + ]) +])# _LT_SET_OPTIONS + + + +# _LT_MANGLE_DEFUN(MACRO-NAME, OPTION-NAME) +# ----------------------------------------- +m4_define([_LT_MANGLE_DEFUN], +[[_LT_OPTION_DEFUN_]m4_bpatsubst(m4_toupper([$1__$2]), [[^A-Z0-9_]], [_])]) + + +# LT_OPTION_DEFINE(MACRO-NAME, OPTION-NAME, CODE) +# ----------------------------------------------- +m4_define([LT_OPTION_DEFINE], +[m4_define(_LT_MANGLE_DEFUN([$1], [$2]), [$3])[]dnl +])# LT_OPTION_DEFINE + + +# dlopen +# ------ +LT_OPTION_DEFINE([LT_INIT], [dlopen], [enable_dlopen=yes +]) + +AU_DEFUN([AC_LIBTOOL_DLOPEN], +[_LT_SET_OPTION([LT_INIT], [dlopen]) +AC_DIAGNOSE([obsolete], +[$0: Remove this warning and the call to _LT_SET_OPTION when you +put the `dlopen' option into LT_INIT's first parameter.]) +]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_DLOPEN], []) + + +# win32-dll +# --------- +# Declare package support for building win32 dll's. +LT_OPTION_DEFINE([LT_INIT], [win32-dll], +[enable_win32_dll=yes + +case $host in +*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-cegcc*) + AC_CHECK_TOOL(AS, as, false) + AC_CHECK_TOOL(DLLTOOL, dlltool, false) + AC_CHECK_TOOL(OBJDUMP, objdump, false) + ;; +esac + +test -z "$AS" && AS=as +_LT_DECL([], [AS], [1], [Assembler program])dnl + +test -z "$DLLTOOL" && DLLTOOL=dlltool +_LT_DECL([], [DLLTOOL], [1], [DLL creation program])dnl + +test -z "$OBJDUMP" && OBJDUMP=objdump +_LT_DECL([], [OBJDUMP], [1], [Object dumper program])dnl +])# win32-dll + +AU_DEFUN([AC_LIBTOOL_WIN32_DLL], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +_LT_SET_OPTION([LT_INIT], [win32-dll]) +AC_DIAGNOSE([obsolete], +[$0: Remove this warning and the call to _LT_SET_OPTION when you +put the `win32-dll' option into LT_INIT's first parameter.]) +]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_WIN32_DLL], []) + + +# _LT_ENABLE_SHARED([DEFAULT]) +# ---------------------------- +# implement the --enable-shared flag, and supports the `shared' and +# `disable-shared' LT_INIT options. +# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. +m4_define([_LT_ENABLE_SHARED], +[m4_define([_LT_ENABLE_SHARED_DEFAULT], [m4_if($1, no, no, yes)])dnl +AC_ARG_ENABLE([shared], + [AS_HELP_STRING([--enable-shared@<:@=PKGS@:>@], + [build shared libraries @<:@default=]_LT_ENABLE_SHARED_DEFAULT[@:>@])], + [p=${PACKAGE-default} + case $enableval in + yes) enable_shared=yes ;; + no) enable_shared=no ;; + *) + enable_shared=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_shared=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac], + [enable_shared=]_LT_ENABLE_SHARED_DEFAULT) + + _LT_DECL([build_libtool_libs], [enable_shared], [0], + [Whether or not to build shared libraries]) +])# _LT_ENABLE_SHARED + +LT_OPTION_DEFINE([LT_INIT], [shared], [_LT_ENABLE_SHARED([yes])]) +LT_OPTION_DEFINE([LT_INIT], [disable-shared], [_LT_ENABLE_SHARED([no])]) + +# Old names: +AC_DEFUN([AC_ENABLE_SHARED], +[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[shared]) +]) + +AC_DEFUN([AC_DISABLE_SHARED], +[_LT_SET_OPTION([LT_INIT], [disable-shared]) +]) + +AU_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)]) +AU_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AM_ENABLE_SHARED], []) +dnl AC_DEFUN([AM_DISABLE_SHARED], []) + + + +# _LT_ENABLE_STATIC([DEFAULT]) +# ---------------------------- +# implement the --enable-static flag, and support the `static' and +# `disable-static' LT_INIT options. +# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. +m4_define([_LT_ENABLE_STATIC], +[m4_define([_LT_ENABLE_STATIC_DEFAULT], [m4_if($1, no, no, yes)])dnl +AC_ARG_ENABLE([static], + [AS_HELP_STRING([--enable-static@<:@=PKGS@:>@], + [build static libraries @<:@default=]_LT_ENABLE_STATIC_DEFAULT[@:>@])], + [p=${PACKAGE-default} + case $enableval in + yes) enable_static=yes ;; + no) enable_static=no ;; + *) + enable_static=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_static=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac], + [enable_static=]_LT_ENABLE_STATIC_DEFAULT) + + _LT_DECL([build_old_libs], [enable_static], [0], + [Whether or not to build static libraries]) +])# _LT_ENABLE_STATIC + +LT_OPTION_DEFINE([LT_INIT], [static], [_LT_ENABLE_STATIC([yes])]) +LT_OPTION_DEFINE([LT_INIT], [disable-static], [_LT_ENABLE_STATIC([no])]) + +# Old names: +AC_DEFUN([AC_ENABLE_STATIC], +[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[static]) +]) + +AC_DEFUN([AC_DISABLE_STATIC], +[_LT_SET_OPTION([LT_INIT], [disable-static]) +]) + +AU_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)]) +AU_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AM_ENABLE_STATIC], []) +dnl AC_DEFUN([AM_DISABLE_STATIC], []) + + + +# _LT_ENABLE_FAST_INSTALL([DEFAULT]) +# ---------------------------------- +# implement the --enable-fast-install flag, and support the `fast-install' +# and `disable-fast-install' LT_INIT options. +# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. +m4_define([_LT_ENABLE_FAST_INSTALL], +[m4_define([_LT_ENABLE_FAST_INSTALL_DEFAULT], [m4_if($1, no, no, yes)])dnl +AC_ARG_ENABLE([fast-install], + [AS_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@], + [optimize for fast installation @<:@default=]_LT_ENABLE_FAST_INSTALL_DEFAULT[@:>@])], + [p=${PACKAGE-default} + case $enableval in + yes) enable_fast_install=yes ;; + no) enable_fast_install=no ;; + *) + enable_fast_install=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_fast_install=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac], + [enable_fast_install=]_LT_ENABLE_FAST_INSTALL_DEFAULT) + +_LT_DECL([fast_install], [enable_fast_install], [0], + [Whether or not to optimize for fast installation])dnl +])# _LT_ENABLE_FAST_INSTALL + +LT_OPTION_DEFINE([LT_INIT], [fast-install], [_LT_ENABLE_FAST_INSTALL([yes])]) +LT_OPTION_DEFINE([LT_INIT], [disable-fast-install], [_LT_ENABLE_FAST_INSTALL([no])]) + +# Old names: +AU_DEFUN([AC_ENABLE_FAST_INSTALL], +[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[fast-install]) +AC_DIAGNOSE([obsolete], +[$0: Remove this warning and the call to _LT_SET_OPTION when you put +the `fast-install' option into LT_INIT's first parameter.]) +]) + +AU_DEFUN([AC_DISABLE_FAST_INSTALL], +[_LT_SET_OPTION([LT_INIT], [disable-fast-install]) +AC_DIAGNOSE([obsolete], +[$0: Remove this warning and the call to _LT_SET_OPTION when you put +the `disable-fast-install' option into LT_INIT's first parameter.]) +]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_ENABLE_FAST_INSTALL], []) +dnl AC_DEFUN([AM_DISABLE_FAST_INSTALL], []) + + +# _LT_WITH_PIC([MODE]) +# -------------------- +# implement the --with-pic flag, and support the `pic-only' and `no-pic' +# LT_INIT options. +# MODE is either `yes' or `no'. If omitted, it defaults to `both'. +m4_define([_LT_WITH_PIC], +[AC_ARG_WITH([pic], + [AS_HELP_STRING([--with-pic@<:@=PKGS@:>@], + [try to use only PIC/non-PIC objects @<:@default=use both@:>@])], + [lt_p=${PACKAGE-default} + case $withval in + yes|no) pic_mode=$withval ;; + *) + pic_mode=default + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for lt_pkg in $withval; do + IFS="$lt_save_ifs" + if test "X$lt_pkg" = "X$lt_p"; then + pic_mode=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac], + [pic_mode=default]) + +test -z "$pic_mode" && pic_mode=m4_default([$1], [default]) + +_LT_DECL([], [pic_mode], [0], [What type of objects to build])dnl +])# _LT_WITH_PIC + +LT_OPTION_DEFINE([LT_INIT], [pic-only], [_LT_WITH_PIC([yes])]) +LT_OPTION_DEFINE([LT_INIT], [no-pic], [_LT_WITH_PIC([no])]) + +# Old name: +AU_DEFUN([AC_LIBTOOL_PICMODE], +[_LT_SET_OPTION([LT_INIT], [pic-only]) +AC_DIAGNOSE([obsolete], +[$0: Remove this warning and the call to _LT_SET_OPTION when you +put the `pic-only' option into LT_INIT's first parameter.]) +]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_PICMODE], []) + + +m4_define([_LTDL_MODE], []) +LT_OPTION_DEFINE([LTDL_INIT], [nonrecursive], + [m4_define([_LTDL_MODE], [nonrecursive])]) +LT_OPTION_DEFINE([LTDL_INIT], [recursive], + [m4_define([_LTDL_MODE], [recursive])]) +LT_OPTION_DEFINE([LTDL_INIT], [subproject], + [m4_define([_LTDL_MODE], [subproject])]) + +m4_define([_LTDL_TYPE], []) +LT_OPTION_DEFINE([LTDL_INIT], [installable], + [m4_define([_LTDL_TYPE], [installable])]) +LT_OPTION_DEFINE([LTDL_INIT], [convenience], + [m4_define([_LTDL_TYPE], [convenience])]) + +# ltsugar.m4 -- libtool m4 base layer. -*-Autoconf-*- +# +# Copyright (C) 2004, 2005, 2007, 2008 Free Software Foundation, Inc. +# Written by Gary V. Vaughan, 2004 +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. + +# serial 6 ltsugar.m4 + +# This is to help aclocal find these macros, as it can't see m4_define. +AC_DEFUN([LTSUGAR_VERSION], [m4_if([0.1])]) + + +# lt_join(SEP, ARG1, [ARG2...]) +# ----------------------------- +# Produce ARG1SEPARG2...SEPARGn, omitting [] arguments and their +# associated separator. +# Needed until we can rely on m4_join from Autoconf 2.62, since all earlier +# versions in m4sugar had bugs. +m4_define([lt_join], +[m4_if([$#], [1], [], + [$#], [2], [[$2]], + [m4_if([$2], [], [], [[$2]_])$0([$1], m4_shift(m4_shift($@)))])]) +m4_define([_lt_join], +[m4_if([$#$2], [2], [], + [m4_if([$2], [], [], [[$1$2]])$0([$1], m4_shift(m4_shift($@)))])]) + + +# lt_car(LIST) +# lt_cdr(LIST) +# ------------ +# Manipulate m4 lists. +# These macros are necessary as long as will still need to support +# Autoconf-2.59 which quotes differently. +m4_define([lt_car], [[$1]]) +m4_define([lt_cdr], +[m4_if([$#], 0, [m4_fatal([$0: cannot be called without arguments])], + [$#], 1, [], + [m4_dquote(m4_shift($@))])]) +m4_define([lt_unquote], $1) + + +# lt_append(MACRO-NAME, STRING, [SEPARATOR]) +# ------------------------------------------ +# Redefine MACRO-NAME to hold its former content plus `SEPARATOR'`STRING'. +# Note that neither SEPARATOR nor STRING are expanded; they are appended +# to MACRO-NAME as is (leaving the expansion for when MACRO-NAME is invoked). +# No SEPARATOR is output if MACRO-NAME was previously undefined (different +# than defined and empty). +# +# This macro is needed until we can rely on Autoconf 2.62, since earlier +# versions of m4sugar mistakenly expanded SEPARATOR but not STRING. +m4_define([lt_append], +[m4_define([$1], + m4_ifdef([$1], [m4_defn([$1])[$3]])[$2])]) + + + +# lt_combine(SEP, PREFIX-LIST, INFIX, SUFFIX1, [SUFFIX2...]) +# ---------------------------------------------------------- +# Produce a SEP delimited list of all paired combinations of elements of +# PREFIX-LIST with SUFFIX1 through SUFFIXn. Each element of the list +# has the form PREFIXmINFIXSUFFIXn. +# Needed until we can rely on m4_combine added in Autoconf 2.62. +m4_define([lt_combine], +[m4_if(m4_eval([$# > 3]), [1], + [m4_pushdef([_Lt_sep], [m4_define([_Lt_sep], m4_defn([lt_car]))])]]dnl +[[m4_foreach([_Lt_prefix], [$2], + [m4_foreach([_Lt_suffix], + ]m4_dquote(m4_dquote(m4_shift(m4_shift(m4_shift($@)))))[, + [_Lt_sep([$1])[]m4_defn([_Lt_prefix])[$3]m4_defn([_Lt_suffix])])])])]) + + +# lt_if_append_uniq(MACRO-NAME, VARNAME, [SEPARATOR], [UNIQ], [NOT-UNIQ]) +# ----------------------------------------------------------------------- +# Iff MACRO-NAME does not yet contain VARNAME, then append it (delimited +# by SEPARATOR if supplied) and expand UNIQ, else NOT-UNIQ. +m4_define([lt_if_append_uniq], +[m4_ifdef([$1], + [m4_if(m4_index([$3]m4_defn([$1])[$3], [$3$2$3]), [-1], + [lt_append([$1], [$2], [$3])$4], + [$5])], + [lt_append([$1], [$2], [$3])$4])]) + + +# lt_dict_add(DICT, KEY, VALUE) +# ----------------------------- +m4_define([lt_dict_add], +[m4_define([$1($2)], [$3])]) + + +# lt_dict_add_subkey(DICT, KEY, SUBKEY, VALUE) +# -------------------------------------------- +m4_define([lt_dict_add_subkey], +[m4_define([$1($2:$3)], [$4])]) + + +# lt_dict_fetch(DICT, KEY, [SUBKEY]) +# ---------------------------------- +m4_define([lt_dict_fetch], +[m4_ifval([$3], + m4_ifdef([$1($2:$3)], [m4_defn([$1($2:$3)])]), + m4_ifdef([$1($2)], [m4_defn([$1($2)])]))]) + + +# lt_if_dict_fetch(DICT, KEY, [SUBKEY], VALUE, IF-TRUE, [IF-FALSE]) +# ----------------------------------------------------------------- +m4_define([lt_if_dict_fetch], +[m4_if(lt_dict_fetch([$1], [$2], [$3]), [$4], + [$5], + [$6])]) + + +# lt_dict_filter(DICT, [SUBKEY], VALUE, [SEPARATOR], KEY, [...]) +# -------------------------------------------------------------- +m4_define([lt_dict_filter], +[m4_if([$5], [], [], + [lt_join(m4_quote(m4_default([$4], [[, ]])), + lt_unquote(m4_split(m4_normalize(m4_foreach(_Lt_key, lt_car([m4_shiftn(4, $@)]), + [lt_if_dict_fetch([$1], _Lt_key, [$2], [$3], [_Lt_key ])])))))])[]dnl +]) + +# ltversion.m4 -- version numbers -*- Autoconf -*- +# +# Copyright (C) 2004 Free Software Foundation, Inc. +# Written by Scott James Remnant, 2004 +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. + +# @configure_input@ + +# serial 3337 ltversion.m4 +# This file is part of GNU Libtool + +m4_define([LT_PACKAGE_VERSION], [2.4.2]) +m4_define([LT_PACKAGE_REVISION], [1.3337]) + +AC_DEFUN([LTVERSION_VERSION], +[macro_version='2.4.2' +macro_revision='1.3337' +_LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?]) +_LT_DECL(, macro_revision, 0) +]) + +# lt~obsolete.m4 -- aclocal satisfying obsolete definitions. -*-Autoconf-*- +# +# Copyright (C) 2004, 2005, 2007, 2009 Free Software Foundation, Inc. +# Written by Scott James Remnant, 2004. +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. + +# serial 5 lt~obsolete.m4 + +# These exist entirely to fool aclocal when bootstrapping libtool. +# +# In the past libtool.m4 has provided macros via AC_DEFUN (or AU_DEFUN) +# which have later been changed to m4_define as they aren't part of the +# exported API, or moved to Autoconf or Automake where they belong. +# +# The trouble is, aclocal is a bit thick. It'll see the old AC_DEFUN +# in /usr/share/aclocal/libtool.m4 and remember it, then when it sees us +# using a macro with the same name in our local m4/libtool.m4 it'll +# pull the old libtool.m4 in (it doesn't see our shiny new m4_define +# and doesn't know about Autoconf macros at all.) +# +# So we provide this file, which has a silly filename so it's always +# included after everything else. This provides aclocal with the +# AC_DEFUNs it wants, but when m4 processes it, it doesn't do anything +# because those macros already exist, or will be overwritten later. +# We use AC_DEFUN over AU_DEFUN for compatibility with aclocal-1.6. +# +# Anytime we withdraw an AC_DEFUN or AU_DEFUN, remember to add it here. +# Yes, that means every name once taken will need to remain here until +# we give up compatibility with versions before 1.7, at which point +# we need to keep only those names which we still refer to. + +# This is to help aclocal find these macros, as it can't see m4_define. +AC_DEFUN([LTOBSOLETE_VERSION], [m4_if([1])]) + +m4_ifndef([AC_LIBTOOL_LINKER_OPTION], [AC_DEFUN([AC_LIBTOOL_LINKER_OPTION])]) +m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP])]) +m4_ifndef([_LT_AC_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH])]) +m4_ifndef([_LT_AC_SHELL_INIT], [AC_DEFUN([_LT_AC_SHELL_INIT])]) +m4_ifndef([_LT_AC_SYS_LIBPATH_AIX], [AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX])]) +m4_ifndef([_LT_PROG_LTMAIN], [AC_DEFUN([_LT_PROG_LTMAIN])]) +m4_ifndef([_LT_AC_TAGVAR], [AC_DEFUN([_LT_AC_TAGVAR])]) +m4_ifndef([AC_LTDL_ENABLE_INSTALL], [AC_DEFUN([AC_LTDL_ENABLE_INSTALL])]) +m4_ifndef([AC_LTDL_PREOPEN], [AC_DEFUN([AC_LTDL_PREOPEN])]) +m4_ifndef([_LT_AC_SYS_COMPILER], [AC_DEFUN([_LT_AC_SYS_COMPILER])]) +m4_ifndef([_LT_AC_LOCK], [AC_DEFUN([_LT_AC_LOCK])]) +m4_ifndef([AC_LIBTOOL_SYS_OLD_ARCHIVE], [AC_DEFUN([AC_LIBTOOL_SYS_OLD_ARCHIVE])]) +m4_ifndef([_LT_AC_TRY_DLOPEN_SELF], [AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF])]) +m4_ifndef([AC_LIBTOOL_PROG_CC_C_O], [AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O])]) +m4_ifndef([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], [AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS])]) +m4_ifndef([AC_LIBTOOL_OBJDIR], [AC_DEFUN([AC_LIBTOOL_OBJDIR])]) +m4_ifndef([AC_LTDL_OBJDIR], [AC_DEFUN([AC_LTDL_OBJDIR])]) +m4_ifndef([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], [AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH])]) +m4_ifndef([AC_LIBTOOL_SYS_LIB_STRIP], [AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP])]) +m4_ifndef([AC_PATH_MAGIC], [AC_DEFUN([AC_PATH_MAGIC])]) +m4_ifndef([AC_PROG_LD_GNU], [AC_DEFUN([AC_PROG_LD_GNU])]) +m4_ifndef([AC_PROG_LD_RELOAD_FLAG], [AC_DEFUN([AC_PROG_LD_RELOAD_FLAG])]) +m4_ifndef([AC_DEPLIBS_CHECK_METHOD], [AC_DEFUN([AC_DEPLIBS_CHECK_METHOD])]) +m4_ifndef([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI])]) +m4_ifndef([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], [AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])]) +m4_ifndef([AC_LIBTOOL_PROG_COMPILER_PIC], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC])]) +m4_ifndef([AC_LIBTOOL_PROG_LD_SHLIBS], [AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS])]) +m4_ifndef([AC_LIBTOOL_POSTDEP_PREDEP], [AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP])]) +m4_ifndef([LT_AC_PROG_EGREP], [AC_DEFUN([LT_AC_PROG_EGREP])]) +m4_ifndef([LT_AC_PROG_SED], [AC_DEFUN([LT_AC_PROG_SED])]) +m4_ifndef([_LT_CC_BASENAME], [AC_DEFUN([_LT_CC_BASENAME])]) +m4_ifndef([_LT_COMPILER_BOILERPLATE], [AC_DEFUN([_LT_COMPILER_BOILERPLATE])]) +m4_ifndef([_LT_LINKER_BOILERPLATE], [AC_DEFUN([_LT_LINKER_BOILERPLATE])]) +m4_ifndef([_AC_PROG_LIBTOOL], [AC_DEFUN([_AC_PROG_LIBTOOL])]) +m4_ifndef([AC_LIBTOOL_SETUP], [AC_DEFUN([AC_LIBTOOL_SETUP])]) +m4_ifndef([_LT_AC_CHECK_DLFCN], [AC_DEFUN([_LT_AC_CHECK_DLFCN])]) +m4_ifndef([AC_LIBTOOL_SYS_DYNAMIC_LINKER], [AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER])]) +m4_ifndef([_LT_AC_TAGCONFIG], [AC_DEFUN([_LT_AC_TAGCONFIG])]) +m4_ifndef([AC_DISABLE_FAST_INSTALL], [AC_DEFUN([AC_DISABLE_FAST_INSTALL])]) +m4_ifndef([_LT_AC_LANG_CXX], [AC_DEFUN([_LT_AC_LANG_CXX])]) +m4_ifndef([_LT_AC_LANG_F77], [AC_DEFUN([_LT_AC_LANG_F77])]) +m4_ifndef([_LT_AC_LANG_GCJ], [AC_DEFUN([_LT_AC_LANG_GCJ])]) +m4_ifndef([AC_LIBTOOL_LANG_C_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG])]) +m4_ifndef([_LT_AC_LANG_C_CONFIG], [AC_DEFUN([_LT_AC_LANG_C_CONFIG])]) +m4_ifndef([AC_LIBTOOL_LANG_CXX_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG])]) +m4_ifndef([_LT_AC_LANG_CXX_CONFIG], [AC_DEFUN([_LT_AC_LANG_CXX_CONFIG])]) +m4_ifndef([AC_LIBTOOL_LANG_F77_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG])]) +m4_ifndef([_LT_AC_LANG_F77_CONFIG], [AC_DEFUN([_LT_AC_LANG_F77_CONFIG])]) +m4_ifndef([AC_LIBTOOL_LANG_GCJ_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG])]) +m4_ifndef([_LT_AC_LANG_GCJ_CONFIG], [AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG])]) +m4_ifndef([AC_LIBTOOL_LANG_RC_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG])]) +m4_ifndef([_LT_AC_LANG_RC_CONFIG], [AC_DEFUN([_LT_AC_LANG_RC_CONFIG])]) +m4_ifndef([AC_LIBTOOL_CONFIG], [AC_DEFUN([AC_LIBTOOL_CONFIG])]) +m4_ifndef([_LT_AC_FILE_LTDLL_C], [AC_DEFUN([_LT_AC_FILE_LTDLL_C])]) +m4_ifndef([_LT_REQUIRED_DARWIN_CHECKS], [AC_DEFUN([_LT_REQUIRED_DARWIN_CHECKS])]) +m4_ifndef([_LT_AC_PROG_CXXCPP], [AC_DEFUN([_LT_AC_PROG_CXXCPP])]) +m4_ifndef([_LT_PREPARE_SED_QUOTE_VARS], [AC_DEFUN([_LT_PREPARE_SED_QUOTE_VARS])]) +m4_ifndef([_LT_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_PROG_ECHO_BACKSLASH])]) +m4_ifndef([_LT_PROG_F77], [AC_DEFUN([_LT_PROG_F77])]) +m4_ifndef([_LT_PROG_FC], [AC_DEFUN([_LT_PROG_FC])]) +m4_ifndef([_LT_PROG_CXX], [AC_DEFUN([_LT_PROG_CXX])]) + +# Copyright (C) 2002-2013 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_AUTOMAKE_VERSION(VERSION) +# ---------------------------- +# Automake X.Y traces this macro to ensure aclocal.m4 has been +# generated from the m4 files accompanying Automake X.Y. +# (This private macro should not be called outside this file.) +AC_DEFUN([AM_AUTOMAKE_VERSION], +[am__api_version='1.14' +dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to +dnl require some minimum version. Point them to the right macro. +m4_if([$1], [1.14.1], [], + [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl +]) + +# _AM_AUTOCONF_VERSION(VERSION) +# ----------------------------- +# aclocal traces this macro to find the Autoconf version. +# This is a private macro too. Using m4_define simplifies +# the logic in aclocal, which can simply ignore this definition. +m4_define([_AM_AUTOCONF_VERSION], []) + +# AM_SET_CURRENT_AUTOMAKE_VERSION +# ------------------------------- +# Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. +# This function is AC_REQUIREd by AM_INIT_AUTOMAKE. +AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], +[AM_AUTOMAKE_VERSION([1.14.1])dnl +m4_ifndef([AC_AUTOCONF_VERSION], + [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl +_AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) + +# AM_AUX_DIR_EXPAND -*- Autoconf -*- + +# Copyright (C) 2001-2013 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets +# $ac_aux_dir to '$srcdir/foo'. In other projects, it is set to +# '$srcdir', '$srcdir/..', or '$srcdir/../..'. +# +# Of course, Automake must honor this variable whenever it calls a +# tool from the auxiliary directory. The problem is that $srcdir (and +# therefore $ac_aux_dir as well) can be either absolute or relative, +# depending on how configure is run. This is pretty annoying, since +# it makes $ac_aux_dir quite unusable in subdirectories: in the top +# source directory, any form will work fine, but in subdirectories a +# relative path needs to be adjusted first. +# +# $ac_aux_dir/missing +# fails when called from a subdirectory if $ac_aux_dir is relative +# $top_srcdir/$ac_aux_dir/missing +# fails if $ac_aux_dir is absolute, +# fails when called from a subdirectory in a VPATH build with +# a relative $ac_aux_dir +# +# The reason of the latter failure is that $top_srcdir and $ac_aux_dir +# are both prefixed by $srcdir. In an in-source build this is usually +# harmless because $srcdir is '.', but things will broke when you +# start a VPATH build or use an absolute $srcdir. +# +# So we could use something similar to $top_srcdir/$ac_aux_dir/missing, +# iff we strip the leading $srcdir from $ac_aux_dir. That would be: +# am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"` +# and then we would define $MISSING as +# MISSING="\${SHELL} $am_aux_dir/missing" +# This will work as long as MISSING is not called from configure, because +# unfortunately $(top_srcdir) has no meaning in configure. +# However there are other variables, like CC, which are often used in +# configure, and could therefore not use this "fixed" $ac_aux_dir. +# +# Another solution, used here, is to always expand $ac_aux_dir to an +# absolute PATH. The drawback is that using absolute paths prevent a +# configured tree to be moved without reconfiguration. + +AC_DEFUN([AM_AUX_DIR_EXPAND], +[dnl Rely on autoconf to set up CDPATH properly. +AC_PREREQ([2.50])dnl +# expand $ac_aux_dir to an absolute path +am_aux_dir=`cd $ac_aux_dir && pwd` +]) + +# AM_CONDITIONAL -*- Autoconf -*- + +# Copyright (C) 1997-2013 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_CONDITIONAL(NAME, SHELL-CONDITION) +# ------------------------------------- +# Define a conditional. +AC_DEFUN([AM_CONDITIONAL], +[AC_PREREQ([2.52])dnl + m4_if([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], + [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl +AC_SUBST([$1_TRUE])dnl +AC_SUBST([$1_FALSE])dnl +_AM_SUBST_NOTMAKE([$1_TRUE])dnl +_AM_SUBST_NOTMAKE([$1_FALSE])dnl +m4_define([_AM_COND_VALUE_$1], [$2])dnl +if $2; then + $1_TRUE= + $1_FALSE='#' +else + $1_TRUE='#' + $1_FALSE= +fi +AC_CONFIG_COMMANDS_PRE( +[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then + AC_MSG_ERROR([[conditional "$1" was never defined. +Usually this means the macro was only invoked conditionally.]]) +fi])]) + +# Copyright (C) 1999-2013 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + + +# There are a few dirty hacks below to avoid letting 'AC_PROG_CC' be +# written in clear, in which case automake, when reading aclocal.m4, +# will think it sees a *use*, and therefore will trigger all it's +# C support machinery. Also note that it means that autoscan, seeing +# CC etc. in the Makefile, will ask for an AC_PROG_CC use... + + +# _AM_DEPENDENCIES(NAME) +# ---------------------- +# See how the compiler implements dependency checking. +# NAME is "CC", "CXX", "OBJC", "OBJCXX", "UPC", or "GJC". +# We try a few techniques and use that to set a single cache variable. +# +# We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was +# modified to invoke _AM_DEPENDENCIES(CC); we would have a circular +# dependency, and given that the user is not expected to run this macro, +# just rely on AC_PROG_CC. +AC_DEFUN([_AM_DEPENDENCIES], +[AC_REQUIRE([AM_SET_DEPDIR])dnl +AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl +AC_REQUIRE([AM_MAKE_INCLUDE])dnl +AC_REQUIRE([AM_DEP_TRACK])dnl + +m4_if([$1], [CC], [depcc="$CC" am_compiler_list=], + [$1], [CXX], [depcc="$CXX" am_compiler_list=], + [$1], [OBJC], [depcc="$OBJC" am_compiler_list='gcc3 gcc'], + [$1], [OBJCXX], [depcc="$OBJCXX" am_compiler_list='gcc3 gcc'], + [$1], [UPC], [depcc="$UPC" am_compiler_list=], + [$1], [GCJ], [depcc="$GCJ" am_compiler_list='gcc3 gcc'], + [depcc="$$1" am_compiler_list=]) + +AC_CACHE_CHECK([dependency style of $depcc], + [am_cv_$1_dependencies_compiler_type], +[if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named 'D' -- because '-MD' means "put the output + # in D". + rm -rf conftest.dir + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_$1_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp` + fi + am__universal=false + m4_case([$1], [CC], + [case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac], + [CXX], + [case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac]) + + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with + # Solaris 10 /bin/sh. + echo '/* dummy */' > sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + # We check with '-c' and '-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle '-M -o', and we need to detect this. Also, some Intel + # versions had trouble with output in subdirs. + am__obj=sub/conftest.${OBJEXT-o} + am__minus_obj="-o $am__obj" + case $depmode in + gcc) + # This depmode causes a compiler race in universal mode. + test "$am__universal" = false || continue + ;; + nosideeffect) + # After this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested. + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + msvc7 | msvc7msys | msvisualcpp | msvcmsys) + # This compiler won't grok '-c -o', but also, the minuso test has + # not run yet. These depmodes are late enough in the game, and + # so weak that their functioning should not be impacted. + am__obj=conftest.${OBJEXT-o} + am__minus_obj= + ;; + none) break ;; + esac + if depmode=$depmode \ + source=sub/conftest.c object=$am__obj \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep $am__obj sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_$1_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_$1_dependencies_compiler_type=none +fi +]) +AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type]) +AM_CONDITIONAL([am__fastdep$1], [ + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_$1_dependencies_compiler_type" = gcc3]) +]) + + +# AM_SET_DEPDIR +# ------------- +# Choose a directory name for dependency files. +# This macro is AC_REQUIREd in _AM_DEPENDENCIES. +AC_DEFUN([AM_SET_DEPDIR], +[AC_REQUIRE([AM_SET_LEADING_DOT])dnl +AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl +]) + + +# AM_DEP_TRACK +# ------------ +AC_DEFUN([AM_DEP_TRACK], +[AC_ARG_ENABLE([dependency-tracking], [dnl +AS_HELP_STRING( + [--enable-dependency-tracking], + [do not reject slow dependency extractors]) +AS_HELP_STRING( + [--disable-dependency-tracking], + [speeds up one-time build])]) +if test "x$enable_dependency_tracking" != xno; then + am_depcomp="$ac_aux_dir/depcomp" + AMDEPBACKSLASH='\' + am__nodep='_no' +fi +AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) +AC_SUBST([AMDEPBACKSLASH])dnl +_AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl +AC_SUBST([am__nodep])dnl +_AM_SUBST_NOTMAKE([am__nodep])dnl +]) + +# Generate code to set up dependency tracking. -*- Autoconf -*- + +# Copyright (C) 1999-2013 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + + +# _AM_OUTPUT_DEPENDENCY_COMMANDS +# ------------------------------ +AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], +[{ + # Older Autoconf quotes --file arguments for eval, but not when files + # are listed without --file. Let's play safe and only enable the eval + # if we detect the quoting. + case $CONFIG_FILES in + *\'*) eval set x "$CONFIG_FILES" ;; + *) set x $CONFIG_FILES ;; + esac + shift + for mf + do + # Strip MF so we end up with the name of the file. + mf=`echo "$mf" | sed -e 's/:.*$//'` + # Check whether this is an Automake generated Makefile or not. + # We used to match only the files named 'Makefile.in', but + # some people rename them; so instead we look at the file content. + # Grep'ing the first line is not enough: some people post-process + # each Makefile.in and add a new line on top of each file to say so. + # Grep'ing the whole file is not good either: AIX grep has a line + # limit of 2048, but all sed's we know have understand at least 4000. + if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then + dirpart=`AS_DIRNAME("$mf")` + else + continue + fi + # Extract the definition of DEPDIR, am__include, and am__quote + # from the Makefile without running 'make'. + DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` + test -z "$DEPDIR" && continue + am__include=`sed -n 's/^am__include = //p' < "$mf"` + test -z "$am__include" && continue + am__quote=`sed -n 's/^am__quote = //p' < "$mf"` + # Find all dependency output files, they are included files with + # $(DEPDIR) in their names. We invoke sed twice because it is the + # simplest approach to changing $(DEPDIR) to its actual value in the + # expansion. + for file in `sed -n " + s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ + sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g'`; do + # Make sure the directory exists. + test -f "$dirpart/$file" && continue + fdir=`AS_DIRNAME(["$file"])` + AS_MKDIR_P([$dirpart/$fdir]) + # echo "creating $dirpart/$file" + echo '# dummy' > "$dirpart/$file" + done + done +} +])# _AM_OUTPUT_DEPENDENCY_COMMANDS + + +# AM_OUTPUT_DEPENDENCY_COMMANDS +# ----------------------------- +# This macro should only be invoked once -- use via AC_REQUIRE. +# +# This code is only required when automatic dependency tracking +# is enabled. FIXME. This creates each '.P' file that we will +# need in order to bootstrap the dependency handling code. +AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], +[AC_CONFIG_COMMANDS([depfiles], + [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS], + [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"]) +]) + +# Do all the work for Automake. -*- Autoconf -*- + +# Copyright (C) 1996-2013 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This macro actually does too much. Some checks are only needed if +# your package does certain things. But this isn't really a big deal. + +dnl Redefine AC_PROG_CC to automatically invoke _AM_PROG_CC_C_O. +m4_define([AC_PROG_CC], +m4_defn([AC_PROG_CC]) +[_AM_PROG_CC_C_O +]) + +# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) +# AM_INIT_AUTOMAKE([OPTIONS]) +# ----------------------------------------------- +# The call with PACKAGE and VERSION arguments is the old style +# call (pre autoconf-2.50), which is being phased out. PACKAGE +# and VERSION should now be passed to AC_INIT and removed from +# the call to AM_INIT_AUTOMAKE. +# We support both call styles for the transition. After +# the next Automake release, Autoconf can make the AC_INIT +# arguments mandatory, and then we can depend on a new Autoconf +# release and drop the old call support. +AC_DEFUN([AM_INIT_AUTOMAKE], +[AC_PREREQ([2.65])dnl +dnl Autoconf wants to disallow AM_ names. We explicitly allow +dnl the ones we care about. +m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl +AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl +AC_REQUIRE([AC_PROG_INSTALL])dnl +if test "`cd $srcdir && pwd`" != "`pwd`"; then + # Use -I$(srcdir) only when $(srcdir) != ., so that make's output + # is not polluted with repeated "-I." + AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl + # test to see if srcdir already configured + if test -f $srcdir/config.status; then + AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) + fi +fi + +# test whether we have cygpath +if test -z "$CYGPATH_W"; then + if (cygpath --version) >/dev/null 2>/dev/null; then + CYGPATH_W='cygpath -w' + else + CYGPATH_W=echo + fi +fi +AC_SUBST([CYGPATH_W]) + +# Define the identity of the package. +dnl Distinguish between old-style and new-style calls. +m4_ifval([$2], +[AC_DIAGNOSE([obsolete], + [$0: two- and three-arguments forms are deprecated.]) +m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl + AC_SUBST([PACKAGE], [$1])dnl + AC_SUBST([VERSION], [$2])], +[_AM_SET_OPTIONS([$1])dnl +dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT. +m4_if( + m4_ifdef([AC_PACKAGE_NAME], [ok]):m4_ifdef([AC_PACKAGE_VERSION], [ok]), + [ok:ok],, + [m4_fatal([AC_INIT should be called with package and version arguments])])dnl + AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl + AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl + +_AM_IF_OPTION([no-define],, +[AC_DEFINE_UNQUOTED([PACKAGE], ["$PACKAGE"], [Name of package]) + AC_DEFINE_UNQUOTED([VERSION], ["$VERSION"], [Version number of package])])dnl + +# Some tools Automake needs. +AC_REQUIRE([AM_SANITY_CHECK])dnl +AC_REQUIRE([AC_ARG_PROGRAM])dnl +AM_MISSING_PROG([ACLOCAL], [aclocal-${am__api_version}]) +AM_MISSING_PROG([AUTOCONF], [autoconf]) +AM_MISSING_PROG([AUTOMAKE], [automake-${am__api_version}]) +AM_MISSING_PROG([AUTOHEADER], [autoheader]) +AM_MISSING_PROG([MAKEINFO], [makeinfo]) +AC_REQUIRE([AM_PROG_INSTALL_SH])dnl +AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl +AC_REQUIRE([AC_PROG_MKDIR_P])dnl +# For better backward compatibility. To be removed once Automake 1.9.x +# dies out for good. For more background, see: +# +# +AC_SUBST([mkdir_p], ['$(MKDIR_P)']) +# We need awk for the "check" target. The system "awk" is bad on +# some platforms. +AC_REQUIRE([AC_PROG_AWK])dnl +AC_REQUIRE([AC_PROG_MAKE_SET])dnl +AC_REQUIRE([AM_SET_LEADING_DOT])dnl +_AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], + [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], + [_AM_PROG_TAR([v7])])]) +_AM_IF_OPTION([no-dependencies],, +[AC_PROVIDE_IFELSE([AC_PROG_CC], + [_AM_DEPENDENCIES([CC])], + [m4_define([AC_PROG_CC], + m4_defn([AC_PROG_CC])[_AM_DEPENDENCIES([CC])])])dnl +AC_PROVIDE_IFELSE([AC_PROG_CXX], + [_AM_DEPENDENCIES([CXX])], + [m4_define([AC_PROG_CXX], + m4_defn([AC_PROG_CXX])[_AM_DEPENDENCIES([CXX])])])dnl +AC_PROVIDE_IFELSE([AC_PROG_OBJC], + [_AM_DEPENDENCIES([OBJC])], + [m4_define([AC_PROG_OBJC], + m4_defn([AC_PROG_OBJC])[_AM_DEPENDENCIES([OBJC])])])dnl +AC_PROVIDE_IFELSE([AC_PROG_OBJCXX], + [_AM_DEPENDENCIES([OBJCXX])], + [m4_define([AC_PROG_OBJCXX], + m4_defn([AC_PROG_OBJCXX])[_AM_DEPENDENCIES([OBJCXX])])])dnl +]) +AC_REQUIRE([AM_SILENT_RULES])dnl +dnl The testsuite driver may need to know about EXEEXT, so add the +dnl 'am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This +dnl macro is hooked onto _AC_COMPILER_EXEEXT early, see below. +AC_CONFIG_COMMANDS_PRE(dnl +[m4_provide_if([_AM_COMPILER_EXEEXT], + [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl + +# POSIX will say in a future version that running "rm -f" with no argument +# is OK; and we want to be able to make that assumption in our Makefile +# recipes. So use an aggressive probe to check that the usage we want is +# actually supported "in the wild" to an acceptable degree. +# See automake bug#10828. +# To make any issue more visible, cause the running configure to be aborted +# by default if the 'rm' program in use doesn't match our expectations; the +# user can still override this though. +if rm -f && rm -fr && rm -rf; then : OK; else + cat >&2 <<'END' +Oops! + +Your 'rm' program seems unable to run without file operands specified +on the command line, even when the '-f' option is present. This is contrary +to the behaviour of most rm programs out there, and not conforming with +the upcoming POSIX standard: + +Please tell bug-automake@gnu.org about your system, including the value +of your $PATH and any error possibly output before this message. This +can help us improve future automake versions. + +END + if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then + echo 'Configuration will proceed anyway, since you have set the' >&2 + echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2 + echo >&2 + else + cat >&2 <<'END' +Aborting the configuration process, to ensure you take notice of the issue. + +You can download and install GNU coreutils to get an 'rm' implementation +that behaves properly: . + +If you want to complete the configuration process using your problematic +'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM +to "yes", and re-run configure. + +END + AC_MSG_ERROR([Your 'rm' program is bad, sorry.]) + fi +fi]) + +dnl Hook into '_AC_COMPILER_EXEEXT' early to learn its expansion. Do not +dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further +dnl mangled by Autoconf and run in a shell conditional statement. +m4_define([_AC_COMPILER_EXEEXT], +m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])]) + +# When config.status generates a header, we must update the stamp-h file. +# This file resides in the same directory as the config header +# that is generated. The stamp files are numbered to have different names. + +# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the +# loop where config.status creates the headers, so we can generate +# our stamp files there. +AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK], +[# Compute $1's index in $config_headers. +_am_arg=$1 +_am_stamp_count=1 +for _am_header in $config_headers :; do + case $_am_header in + $_am_arg | $_am_arg:* ) + break ;; + * ) + _am_stamp_count=`expr $_am_stamp_count + 1` ;; + esac +done +echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count]) + +# Copyright (C) 2001-2013 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_PROG_INSTALL_SH +# ------------------ +# Define $install_sh. +AC_DEFUN([AM_PROG_INSTALL_SH], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +if test x"${install_sh}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; + *) + install_sh="\${SHELL} $am_aux_dir/install-sh" + esac +fi +AC_SUBST([install_sh])]) + +# Copyright (C) 2003-2013 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# Check whether the underlying file-system supports filenames +# with a leading dot. For instance MS-DOS doesn't. +AC_DEFUN([AM_SET_LEADING_DOT], +[rm -rf .tst 2>/dev/null +mkdir .tst 2>/dev/null +if test -d .tst; then + am__leading_dot=. +else + am__leading_dot=_ +fi +rmdir .tst 2>/dev/null +AC_SUBST([am__leading_dot])]) + +# Add --enable-maintainer-mode option to configure. -*- Autoconf -*- +# From Jim Meyering + +# Copyright (C) 1996-2013 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_MAINTAINER_MODE([DEFAULT-MODE]) +# ---------------------------------- +# Control maintainer-specific portions of Makefiles. +# Default is to disable them, unless 'enable' is passed literally. +# For symmetry, 'disable' may be passed as well. Anyway, the user +# can override the default with the --enable/--disable switch. +AC_DEFUN([AM_MAINTAINER_MODE], +[m4_case(m4_default([$1], [disable]), + [enable], [m4_define([am_maintainer_other], [disable])], + [disable], [m4_define([am_maintainer_other], [enable])], + [m4_define([am_maintainer_other], [enable]) + m4_warn([syntax], [unexpected argument to AM@&t@_MAINTAINER_MODE: $1])]) +AC_MSG_CHECKING([whether to enable maintainer-specific portions of Makefiles]) + dnl maintainer-mode's default is 'disable' unless 'enable' is passed + AC_ARG_ENABLE([maintainer-mode], + [AS_HELP_STRING([--]am_maintainer_other[-maintainer-mode], + am_maintainer_other[ make rules and dependencies not useful + (and sometimes confusing) to the casual installer])], + [USE_MAINTAINER_MODE=$enableval], + [USE_MAINTAINER_MODE=]m4_if(am_maintainer_other, [enable], [no], [yes])) + AC_MSG_RESULT([$USE_MAINTAINER_MODE]) + AM_CONDITIONAL([MAINTAINER_MODE], [test $USE_MAINTAINER_MODE = yes]) + MAINT=$MAINTAINER_MODE_TRUE + AC_SUBST([MAINT])dnl +] +) + +# Check to see how 'make' treats includes. -*- Autoconf -*- + +# Copyright (C) 2001-2013 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_MAKE_INCLUDE() +# ----------------- +# Check to see how make treats includes. +AC_DEFUN([AM_MAKE_INCLUDE], +[am_make=${MAKE-make} +cat > confinc << 'END' +am__doit: + @echo this is the am__doit target +.PHONY: am__doit +END +# If we don't find an include directive, just comment out the code. +AC_MSG_CHECKING([for style of include used by $am_make]) +am__include="#" +am__quote= +_am_result=none +# First try GNU make style include. +echo "include confinc" > confmf +# Ignore all kinds of additional output from 'make'. +case `$am_make -s -f confmf 2> /dev/null` in #( +*the\ am__doit\ target*) + am__include=include + am__quote= + _am_result=GNU + ;; +esac +# Now try BSD make style include. +if test "$am__include" = "#"; then + echo '.include "confinc"' > confmf + case `$am_make -s -f confmf 2> /dev/null` in #( + *the\ am__doit\ target*) + am__include=.include + am__quote="\"" + _am_result=BSD + ;; + esac +fi +AC_SUBST([am__include]) +AC_SUBST([am__quote]) +AC_MSG_RESULT([$_am_result]) +rm -f confinc confmf +]) + +# Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- + +# Copyright (C) 1997-2013 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_MISSING_PROG(NAME, PROGRAM) +# ------------------------------ +AC_DEFUN([AM_MISSING_PROG], +[AC_REQUIRE([AM_MISSING_HAS_RUN]) +$1=${$1-"${am_missing_run}$2"} +AC_SUBST($1)]) + +# AM_MISSING_HAS_RUN +# ------------------ +# Define MISSING if not defined so far and test if it is modern enough. +# If it is, set am_missing_run to use it, otherwise, to nothing. +AC_DEFUN([AM_MISSING_HAS_RUN], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +AC_REQUIRE_AUX_FILE([missing])dnl +if test x"${MISSING+set}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; + *) + MISSING="\${SHELL} $am_aux_dir/missing" ;; + esac +fi +# Use eval to expand $SHELL +if eval "$MISSING --is-lightweight"; then + am_missing_run="$MISSING " +else + am_missing_run= + AC_MSG_WARN(['missing' script is too old or missing]) +fi +]) + +# Helper functions for option handling. -*- Autoconf -*- + +# Copyright (C) 2001-2013 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# _AM_MANGLE_OPTION(NAME) +# ----------------------- +AC_DEFUN([_AM_MANGLE_OPTION], +[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) + +# _AM_SET_OPTION(NAME) +# -------------------- +# Set option NAME. Presently that only means defining a flag for this option. +AC_DEFUN([_AM_SET_OPTION], +[m4_define(_AM_MANGLE_OPTION([$1]), [1])]) + +# _AM_SET_OPTIONS(OPTIONS) +# ------------------------ +# OPTIONS is a space-separated list of Automake options. +AC_DEFUN([_AM_SET_OPTIONS], +[m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) + +# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET]) +# ------------------------------------------- +# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. +AC_DEFUN([_AM_IF_OPTION], +[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) + +# Copyright (C) 1999-2013 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# _AM_PROG_CC_C_O +# --------------- +# Like AC_PROG_CC_C_O, but changed for automake. We rewrite AC_PROG_CC +# to automatically call this. +AC_DEFUN([_AM_PROG_CC_C_O], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +AC_REQUIRE_AUX_FILE([compile])dnl +AC_LANG_PUSH([C])dnl +AC_CACHE_CHECK( + [whether $CC understands -c and -o together], + [am_cv_prog_cc_c_o], + [AC_LANG_CONFTEST([AC_LANG_PROGRAM([])]) + # Make sure it works both with $CC and with simple cc. + # Following AC_PROG_CC_C_O, we do the test twice because some + # compilers refuse to overwrite an existing .o file with -o, + # though they will create one. + am_cv_prog_cc_c_o=yes + for am_i in 1 2; do + if AM_RUN_LOG([$CC -c conftest.$ac_ext -o conftest2.$ac_objext]) \ + && test -f conftest2.$ac_objext; then + : OK + else + am_cv_prog_cc_c_o=no + break + fi + done + rm -f core conftest* + unset am_i]) +if test "$am_cv_prog_cc_c_o" != yes; then + # Losing compiler, so override with the script. + # FIXME: It is wrong to rewrite CC. + # But if we don't then we get into trouble of one sort or another. + # A longer-term fix would be to have automake use am__CC in this case, + # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" + CC="$am_aux_dir/compile $CC" +fi +AC_LANG_POP([C])]) + +# For backward compatibility. +AC_DEFUN_ONCE([AM_PROG_CC_C_O], [AC_REQUIRE([AC_PROG_CC])]) + +# Copyright (C) 2001-2013 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_RUN_LOG(COMMAND) +# ------------------- +# Run COMMAND, save the exit status in ac_status, and log it. +# (This has been adapted from Autoconf's _AC_RUN_LOG macro.) +AC_DEFUN([AM_RUN_LOG], +[{ echo "$as_me:$LINENO: $1" >&AS_MESSAGE_LOG_FD + ($1) >&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD + (exit $ac_status); }]) + +# Check to make sure that the build environment is sane. -*- Autoconf -*- + +# Copyright (C) 1996-2013 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_SANITY_CHECK +# --------------- +AC_DEFUN([AM_SANITY_CHECK], +[AC_MSG_CHECKING([whether build environment is sane]) +# Reject unsafe characters in $srcdir or the absolute working directory +# name. Accept space and tab only in the latter. +am_lf=' +' +case `pwd` in + *[[\\\"\#\$\&\'\`$am_lf]]*) + AC_MSG_ERROR([unsafe absolute working directory name]);; +esac +case $srcdir in + *[[\\\"\#\$\&\'\`$am_lf\ \ ]]*) + AC_MSG_ERROR([unsafe srcdir value: '$srcdir']);; +esac + +# Do 'set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + am_has_slept=no + for am_try in 1 2; do + echo "timestamp, slept: $am_has_slept" > conftest.file + set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` + if test "$[*]" = "X"; then + # -L didn't work. + set X `ls -t "$srcdir/configure" conftest.file` + fi + if test "$[*]" != "X $srcdir/configure conftest.file" \ + && test "$[*]" != "X conftest.file $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken + alias in your environment]) + fi + if test "$[2]" = conftest.file || test $am_try -eq 2; then + break + fi + # Just in case. + sleep 1 + am_has_slept=yes + done + test "$[2]" = conftest.file + ) +then + # Ok. + : +else + AC_MSG_ERROR([newly created file is older than distributed files! +Check your system clock]) +fi +AC_MSG_RESULT([yes]) +# If we didn't sleep, we still need to ensure time stamps of config.status and +# generated files are strictly newer. +am_sleep_pid= +if grep 'slept: no' conftest.file >/dev/null 2>&1; then + ( sleep 1 ) & + am_sleep_pid=$! +fi +AC_CONFIG_COMMANDS_PRE( + [AC_MSG_CHECKING([that generated files are newer than configure]) + if test -n "$am_sleep_pid"; then + # Hide warnings about reused PIDs. + wait $am_sleep_pid 2>/dev/null + fi + AC_MSG_RESULT([done])]) +rm -f conftest.file +]) + +# Copyright (C) 2009-2013 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_SILENT_RULES([DEFAULT]) +# -------------------------- +# Enable less verbose build rules; with the default set to DEFAULT +# ("yes" being less verbose, "no" or empty being verbose). +AC_DEFUN([AM_SILENT_RULES], +[AC_ARG_ENABLE([silent-rules], [dnl +AS_HELP_STRING( + [--enable-silent-rules], + [less verbose build output (undo: "make V=1")]) +AS_HELP_STRING( + [--disable-silent-rules], + [verbose build output (undo: "make V=0")])dnl +]) +case $enable_silent_rules in @%:@ ((( + yes) AM_DEFAULT_VERBOSITY=0;; + no) AM_DEFAULT_VERBOSITY=1;; + *) AM_DEFAULT_VERBOSITY=m4_if([$1], [yes], [0], [1]);; +esac +dnl +dnl A few 'make' implementations (e.g., NonStop OS and NextStep) +dnl do not support nested variable expansions. +dnl See automake bug#9928 and bug#10237. +am_make=${MAKE-make} +AC_CACHE_CHECK([whether $am_make supports nested variables], + [am_cv_make_support_nested_variables], + [if AS_ECHO([['TRUE=$(BAR$(V)) +BAR0=false +BAR1=true +V=1 +am__doit: + @$(TRUE) +.PHONY: am__doit']]) | $am_make -f - >/dev/null 2>&1; then + am_cv_make_support_nested_variables=yes +else + am_cv_make_support_nested_variables=no +fi]) +if test $am_cv_make_support_nested_variables = yes; then + dnl Using '$V' instead of '$(V)' breaks IRIX make. + AM_V='$(V)' + AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' +else + AM_V=$AM_DEFAULT_VERBOSITY + AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY +fi +AC_SUBST([AM_V])dnl +AM_SUBST_NOTMAKE([AM_V])dnl +AC_SUBST([AM_DEFAULT_V])dnl +AM_SUBST_NOTMAKE([AM_DEFAULT_V])dnl +AC_SUBST([AM_DEFAULT_VERBOSITY])dnl +AM_BACKSLASH='\' +AC_SUBST([AM_BACKSLASH])dnl +_AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl +]) + +# Copyright (C) 2001-2013 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_PROG_INSTALL_STRIP +# --------------------- +# One issue with vendor 'install' (even GNU) is that you can't +# specify the program used to strip binaries. This is especially +# annoying in cross-compiling environments, where the build's strip +# is unlikely to handle the host's binaries. +# Fortunately install-sh will honor a STRIPPROG variable, so we +# always use install-sh in "make install-strip", and initialize +# STRIPPROG with the value of the STRIP variable (set by the user). +AC_DEFUN([AM_PROG_INSTALL_STRIP], +[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl +# Installed binaries are usually stripped using 'strip' when the user +# run "make install-strip". However 'strip' might not be the right +# tool to use in cross-compilation environments, therefore Automake +# will honor the 'STRIP' environment variable to overrule this program. +dnl Don't test for $cross_compiling = yes, because it might be 'maybe'. +if test "$cross_compiling" != no; then + AC_CHECK_TOOL([STRIP], [strip], :) +fi +INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" +AC_SUBST([INSTALL_STRIP_PROGRAM])]) + +# Copyright (C) 2006-2013 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# _AM_SUBST_NOTMAKE(VARIABLE) +# --------------------------- +# Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in. +# This macro is traced by Automake. +AC_DEFUN([_AM_SUBST_NOTMAKE]) + +# AM_SUBST_NOTMAKE(VARIABLE) +# -------------------------- +# Public sister of _AM_SUBST_NOTMAKE. +AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)]) + +# Check how to create a tarball. -*- Autoconf -*- + +# Copyright (C) 2004-2013 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# _AM_PROG_TAR(FORMAT) +# -------------------- +# Check how to create a tarball in format FORMAT. +# FORMAT should be one of 'v7', 'ustar', or 'pax'. +# +# Substitute a variable $(am__tar) that is a command +# writing to stdout a FORMAT-tarball containing the directory +# $tardir. +# tardir=directory && $(am__tar) > result.tar +# +# Substitute a variable $(am__untar) that extract such +# a tarball read from stdin. +# $(am__untar) < result.tar +# +AC_DEFUN([_AM_PROG_TAR], +[# Always define AMTAR for backward compatibility. Yes, it's still used +# in the wild :-( We should find a proper way to deprecate it ... +AC_SUBST([AMTAR], ['$${TAR-tar}']) + +# We'll loop over all known methods to create a tar archive until one works. +_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' + +m4_if([$1], [v7], + [am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'], + + [m4_case([$1], + [ustar], + [# The POSIX 1988 'ustar' format is defined with fixed-size fields. + # There is notably a 21 bits limit for the UID and the GID. In fact, + # the 'pax' utility can hang on bigger UID/GID (see automake bug#8343 + # and bug#13588). + am_max_uid=2097151 # 2^21 - 1 + am_max_gid=$am_max_uid + # The $UID and $GID variables are not portable, so we need to resort + # to the POSIX-mandated id(1) utility. Errors in the 'id' calls + # below are definitely unexpected, so allow the users to see them + # (that is, avoid stderr redirection). + am_uid=`id -u || echo unknown` + am_gid=`id -g || echo unknown` + AC_MSG_CHECKING([whether UID '$am_uid' is supported by ustar format]) + if test $am_uid -le $am_max_uid; then + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + _am_tools=none + fi + AC_MSG_CHECKING([whether GID '$am_gid' is supported by ustar format]) + if test $am_gid -le $am_max_gid; then + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + _am_tools=none + fi], + + [pax], + [], + + [m4_fatal([Unknown tar format])]) + + AC_MSG_CHECKING([how to create a $1 tar archive]) + + # Go ahead even if we have the value already cached. We do so because we + # need to set the values for the 'am__tar' and 'am__untar' variables. + _am_tools=${am_cv_prog_tar_$1-$_am_tools} + + for _am_tool in $_am_tools; do + case $_am_tool in + gnutar) + for _am_tar in tar gnutar gtar; do + AM_RUN_LOG([$_am_tar --version]) && break + done + am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"' + am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"' + am__untar="$_am_tar -xf -" + ;; + plaintar) + # Must skip GNU tar: if it does not support --format= it doesn't create + # ustar tarball either. + (tar --version) >/dev/null 2>&1 && continue + am__tar='tar chf - "$$tardir"' + am__tar_='tar chf - "$tardir"' + am__untar='tar xf -' + ;; + pax) + am__tar='pax -L -x $1 -w "$$tardir"' + am__tar_='pax -L -x $1 -w "$tardir"' + am__untar='pax -r' + ;; + cpio) + am__tar='find "$$tardir" -print | cpio -o -H $1 -L' + am__tar_='find "$tardir" -print | cpio -o -H $1 -L' + am__untar='cpio -i -H $1 -d' + ;; + none) + am__tar=false + am__tar_=false + am__untar=false + ;; + esac + + # If the value was cached, stop now. We just wanted to have am__tar + # and am__untar set. + test -n "${am_cv_prog_tar_$1}" && break + + # tar/untar a dummy directory, and stop if the command works. + rm -rf conftest.dir + mkdir conftest.dir + echo GrepMe > conftest.dir/file + AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar]) + rm -rf conftest.dir + if test -s conftest.tar; then + AM_RUN_LOG([$am__untar /dev/null 2>&1 && break + fi + done + rm -rf conftest.dir + + AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool]) + AC_MSG_RESULT([$am_cv_prog_tar_$1])]) + +AC_SUBST([am__tar]) +AC_SUBST([am__untar]) +]) # _AM_PROG_TAR + diff --git a/extern/portaudio/bindings/cpp/bin/Makefile.am b/extern/portaudio/bindings/cpp/bin/Makefile.am new file mode 100644 index 0000000..dcf3735 --- /dev/null +++ b/extern/portaudio/bindings/cpp/bin/Makefile.am @@ -0,0 +1,9 @@ +BINDIR = $(top_srcdir)/example +LIBDIR = $(top_builddir)/lib + +noinst_PROGRAMS = devs sine + +LDADD = $(LIBDIR)/libportaudiocpp.la $(top_builddir)/$(PORTAUDIO_ROOT)/lib/libportaudio.la + +devs_SOURCES = $(BINDIR)/devs.cxx +sine_SOURCES = $(BINDIR)/sine.cxx diff --git a/extern/portaudio/bindings/cpp/bin/Makefile.in b/extern/portaudio/bindings/cpp/bin/Makefile.in new file mode 100644 index 0000000..af20830 --- /dev/null +++ b/extern/portaudio/bindings/cpp/bin/Makefile.in @@ -0,0 +1,618 @@ +# Makefile.in generated by automake 1.14.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2013 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +noinst_PROGRAMS = devs$(EXEEXT) sine$(EXEEXT) +subdir = bin +DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ + $(top_srcdir)/../../depcomp +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +PROGRAMS = $(noinst_PROGRAMS) +am_devs_OBJECTS = devs.$(OBJEXT) +devs_OBJECTS = $(am_devs_OBJECTS) +devs_LDADD = $(LDADD) +devs_DEPENDENCIES = $(LIBDIR)/libportaudiocpp.la \ + $(top_builddir)/$(PORTAUDIO_ROOT)/lib/libportaudio.la +AM_V_lt = $(am__v_lt_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +am__v_lt_1 = +am_sine_OBJECTS = sine.$(OBJEXT) +sine_OBJECTS = $(am_sine_OBJECTS) +sine_LDADD = $(LDADD) +sine_DEPENDENCIES = $(LIBDIR)/libportaudiocpp.la \ + $(top_builddir)/$(PORTAUDIO_ROOT)/lib/libportaudio.la +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +depcomp = $(SHELL) $(top_srcdir)/../../depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CXXFLAGS) $(CXXFLAGS) +AM_V_CXX = $(am__v_CXX_@AM_V@) +am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@) +am__v_CXX_0 = @echo " CXX " $@; +am__v_CXX_1 = +CXXLD = $(CXX) +CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \ + $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CXXLD = $(am__v_CXXLD_@AM_V@) +am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@) +am__v_CXXLD_0 = @echo " CXXLD " $@; +am__v_CXXLD_1 = +SOURCES = $(devs_SOURCES) $(sine_SOURCES) +DIST_SOURCES = $(devs_SOURCES) $(sine_SOURCES) +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFAULT_INCLUDES = @DEFAULT_INCLUDES@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_VERSION_INFO = @LT_VERSION_INFO@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PORTAUDIO_ROOT = @PORTAUDIO_ROOT@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +BINDIR = $(top_srcdir)/example +LIBDIR = $(top_builddir)/lib +LDADD = $(LIBDIR)/libportaudiocpp.la $(top_builddir)/$(PORTAUDIO_ROOT)/lib/libportaudio.la +devs_SOURCES = $(BINDIR)/devs.cxx +sine_SOURCES = $(BINDIR)/sine.cxx +all: all-am + +.SUFFIXES: +.SUFFIXES: .cxx .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu bin/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu bin/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +clean-noinstPROGRAMS: + @list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list + +devs$(EXEEXT): $(devs_OBJECTS) $(devs_DEPENDENCIES) $(EXTRA_devs_DEPENDENCIES) + @rm -f devs$(EXEEXT) + $(AM_V_CXXLD)$(CXXLINK) $(devs_OBJECTS) $(devs_LDADD) $(LIBS) + +sine$(EXEEXT): $(sine_OBJECTS) $(sine_DEPENDENCIES) $(EXTRA_sine_DEPENDENCIES) + @rm -f sine$(EXEEXT) + $(AM_V_CXXLD)$(CXXLINK) $(sine_OBJECTS) $(sine_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/devs.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sine.Po@am__quote@ + +.cxx.o: +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $< + +.cxx.obj: +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.cxx.lo: +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LTCXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $< + +devs.o: $(BINDIR)/devs.cxx +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT devs.o -MD -MP -MF $(DEPDIR)/devs.Tpo -c -o devs.o `test -f '$(BINDIR)/devs.cxx' || echo '$(srcdir)/'`$(BINDIR)/devs.cxx +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/devs.Tpo $(DEPDIR)/devs.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$(BINDIR)/devs.cxx' object='devs.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o devs.o `test -f '$(BINDIR)/devs.cxx' || echo '$(srcdir)/'`$(BINDIR)/devs.cxx + +devs.obj: $(BINDIR)/devs.cxx +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT devs.obj -MD -MP -MF $(DEPDIR)/devs.Tpo -c -o devs.obj `if test -f '$(BINDIR)/devs.cxx'; then $(CYGPATH_W) '$(BINDIR)/devs.cxx'; else $(CYGPATH_W) '$(srcdir)/$(BINDIR)/devs.cxx'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/devs.Tpo $(DEPDIR)/devs.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$(BINDIR)/devs.cxx' object='devs.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o devs.obj `if test -f '$(BINDIR)/devs.cxx'; then $(CYGPATH_W) '$(BINDIR)/devs.cxx'; else $(CYGPATH_W) '$(srcdir)/$(BINDIR)/devs.cxx'; fi` + +sine.o: $(BINDIR)/sine.cxx +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT sine.o -MD -MP -MF $(DEPDIR)/sine.Tpo -c -o sine.o `test -f '$(BINDIR)/sine.cxx' || echo '$(srcdir)/'`$(BINDIR)/sine.cxx +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/sine.Tpo $(DEPDIR)/sine.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$(BINDIR)/sine.cxx' object='sine.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o sine.o `test -f '$(BINDIR)/sine.cxx' || echo '$(srcdir)/'`$(BINDIR)/sine.cxx + +sine.obj: $(BINDIR)/sine.cxx +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT sine.obj -MD -MP -MF $(DEPDIR)/sine.Tpo -c -o sine.obj `if test -f '$(BINDIR)/sine.cxx'; then $(CYGPATH_W) '$(BINDIR)/sine.cxx'; else $(CYGPATH_W) '$(srcdir)/$(BINDIR)/sine.cxx'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/sine.Tpo $(DEPDIR)/sine.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$(BINDIR)/sine.cxx' object='sine.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o sine.obj `if test -f '$(BINDIR)/sine.cxx'; then $(CYGPATH_W) '$(BINDIR)/sine.cxx'; else $(CYGPATH_W) '$(srcdir)/$(BINDIR)/sine.cxx'; fi` + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-am +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-am + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscopelist: cscopelist-am + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(PROGRAMS) +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-noinstPROGRAMS \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-noinstPROGRAMS cscopelist-am ctags \ + ctags-am distclean distclean-compile distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-man install-pdf install-pdf-am \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags tags-am uninstall uninstall-am + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/extern/portaudio/bindings/cpp/configure b/extern/portaudio/bindings/cpp/configure new file mode 100755 index 0000000..0186597 --- /dev/null +++ b/extern/portaudio/bindings/cpp/configure @@ -0,0 +1,17918 @@ +#! /bin/sh +# Guess values for system-dependent variables and create Makefiles. +# Generated by GNU Autoconf 2.69 for PortAudioCpp 12. +# +# +# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. +# +# +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +as_myself= +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +# Use a proper internal environment variable to ensure we don't fall + # into an infinite loop, continuously re-executing ourselves. + if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then + _as_can_reexec=no; export _as_can_reexec; + # We cannot yet assume a decent shell, so we have to provide a +# neutralization value for shells without unset; and this also +# works around shells that cannot unset nonexistent variables. +# Preserve -v and -x to the replacement shell. +BASH_ENV=/dev/null +ENV=/dev/null +(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV +case $- in # (((( + *v*x* | *x*v* ) as_opts=-vx ;; + *v* ) as_opts=-v ;; + *x* ) as_opts=-x ;; + * ) as_opts= ;; +esac +exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} +# Admittedly, this is quite paranoid, since all the known shells bail +# out after a failed `exec'. +$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 +as_fn_exit 255 + fi + # We don't want this to propagate to other subprocesses. + { _as_can_reexec=; unset _as_can_reexec;} +if test "x$CONFIG_SHELL" = x; then + as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which + # is contrary to our usage. Disable this feature. + alias -g '\${1+\"\$@\"}'='\"\$@\"' + setopt NO_GLOB_SUBST +else + case \`(set -o) 2>/dev/null\` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi +" + as_required="as_fn_return () { (exit \$1); } +as_fn_success () { as_fn_return 0; } +as_fn_failure () { as_fn_return 1; } +as_fn_ret_success () { return 0; } +as_fn_ret_failure () { return 1; } + +exitcode=0 +as_fn_success || { exitcode=1; echo as_fn_success failed.; } +as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } +as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } +as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } +if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : + +else + exitcode=1; echo positional parameters were not saved. +fi +test x\$exitcode = x0 || exit 1 +test -x / || exit 1" + as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO + as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO + eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && + test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 + + test -n \"\${ZSH_VERSION+set}\${BASH_VERSION+set}\" || ( + ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' + ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO + ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO + PATH=/empty FPATH=/empty; export PATH FPATH + test \"X\`printf %s \$ECHO\`\" = \"X\$ECHO\" \\ + || test \"X\`print -r -- \$ECHO\`\" = \"X\$ECHO\" ) || exit 1 +test \$(( 1 + 1 )) = 2 || exit 1" + if (eval "$as_required") 2>/dev/null; then : + as_have_required=yes +else + as_have_required=no +fi + if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : + +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_found=false +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + as_found=: + case $as_dir in #( + /*) + for as_base in sh bash ksh sh5; do + # Try only shells that exist, to save several forks. + as_shell=$as_dir/$as_base + if { test -f "$as_shell" || test -f "$as_shell.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : + CONFIG_SHELL=$as_shell as_have_required=yes + if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : + break 2 +fi +fi + done;; + esac + as_found=false +done +$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : + CONFIG_SHELL=$SHELL as_have_required=yes +fi; } +IFS=$as_save_IFS + + + if test "x$CONFIG_SHELL" != x; then : + export CONFIG_SHELL + # We cannot yet assume a decent shell, so we have to provide a +# neutralization value for shells without unset; and this also +# works around shells that cannot unset nonexistent variables. +# Preserve -v and -x to the replacement shell. +BASH_ENV=/dev/null +ENV=/dev/null +(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV +case $- in # (((( + *v*x* | *x*v* ) as_opts=-vx ;; + *v* ) as_opts=-v ;; + *x* ) as_opts=-x ;; + * ) as_opts= ;; +esac +exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} +# Admittedly, this is quite paranoid, since all the known shells bail +# out after a failed `exec'. +$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 +exit 255 +fi + + if test x$as_have_required = xno; then : + $as_echo "$0: This script requires a shell more modern than all" + $as_echo "$0: the shells that I found on your system." + if test x${ZSH_VERSION+set} = xset ; then + $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" + $as_echo "$0: be upgraded to zsh 4.3.4 or later." + else + $as_echo "$0: Please tell bug-autoconf@gnu.org about your system, +$0: including any error possibly output before this +$0: message. Then install a modern shell, or manually run +$0: the script under such a shell if you do have one." + fi + exit 1 +fi +fi +fi +SHELL=${CONFIG_SHELL-/bin/sh} +export SHELL +# Unset more variables known to interfere with behavior of common tools. +CLICOLOR_FORCE= GREP_OPTIONS= +unset CLICOLOR_FORCE GREP_OPTIONS + +## --------------------- ## +## M4sh Shell Functions. ## +## --------------------- ## +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" + + +} # as_fn_mkdir_p + +# as_fn_executable_p FILE +# ----------------------- +# Test if FILE is an executable regular file. +as_fn_executable_p () +{ + test -f "$1" && test -x "$1" +} # as_fn_executable_p +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with STATUS, using 1 if that was 0. +as_fn_error () +{ + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + fi + $as_echo "$as_me: error: $2" >&2 + as_fn_exit $as_status +} # as_fn_error + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + + + as_lineno_1=$LINENO as_lineno_1a=$LINENO + as_lineno_2=$LINENO as_lineno_2a=$LINENO + eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && + test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { + # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) + sed -n ' + p + /[$]LINENO/= + ' <$as_myself | + sed ' + s/[$]LINENO.*/&-/ + t lineno + b + :lineno + N + :loop + s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ + t loop + s/-\n.*// + ' >$as_me.lineno && + chmod +x "$as_me.lineno" || + { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } + + # If we had to re-execute with $CONFIG_SHELL, we're ensured to have + # already done that, so ensure we don't try to do so again and fall + # in an infinite loop. This has already happened in practice. + _as_can_reexec=no; export _as_can_reexec + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensitive to this). + . "./$as_me.lineno" + # Exit status is that of the last command. + exit +} + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -pR'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -pR' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -pR' + fi +else + as_ln_s='cp -pR' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +as_test_x='test -x' +as_executable_p=as_fn_executable_p + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + +SHELL=${CONFIG_SHELL-/bin/sh} + + +test -n "$DJDIR" || exec 7<&0 &1 + +# Name of the host. +# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, +# so uname gets run too. +ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` + +# +# Initializations. +# +ac_default_prefix=/usr/local +ac_clean_files= +ac_config_libobj_dir=. +LIBOBJS= +cross_compiling=no +subdirs= +MFLAGS= +MAKEFLAGS= + +# Identity of this package. +PACKAGE_NAME='PortAudioCpp' +PACKAGE_TARNAME='portaudiocpp' +PACKAGE_VERSION='12' +PACKAGE_STRING='PortAudioCpp 12' +PACKAGE_BUGREPORT='' +PACKAGE_URL='' + +ac_unique_file="include/portaudiocpp/PortAudioCpp.hxx" +# Factoring default headers for most tests. +ac_includes_default="\ +#include +#ifdef HAVE_SYS_TYPES_H +# include +#endif +#ifdef HAVE_SYS_STAT_H +# include +#endif +#ifdef STDC_HEADERS +# include +# include +#else +# ifdef HAVE_STDLIB_H +# include +# endif +#endif +#ifdef HAVE_STRING_H +# if !defined STDC_HEADERS && defined HAVE_MEMORY_H +# include +# endif +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif +#ifdef HAVE_INTTYPES_H +# include +#endif +#ifdef HAVE_STDINT_H +# include +#endif +#ifdef HAVE_UNISTD_H +# include +#endif" + +ac_subst_vars='am__EXEEXT_FALSE +am__EXEEXT_TRUE +LTLIBOBJS +LIBOBJS +LT_VERSION_INFO +PORTAUDIO_ROOT +DEFAULT_INCLUDES +CXXCPP +CPP +OTOOL64 +OTOOL +LIPO +NMEDIT +DSYMUTIL +MANIFEST_TOOL +RANLIB +ac_ct_AR +AR +LN_S +NM +ac_ct_DUMPBIN +DUMPBIN +LD +FGREP +EGREP +GREP +SED +LIBTOOL +OBJDUMP +DLLTOOL +AS +host_os +host_vendor +host_cpu +host +build_os +build_vendor +build_cpu +build +am__fastdepCXX_FALSE +am__fastdepCXX_TRUE +CXXDEPMODE +ac_ct_CXX +CXXFLAGS +CXX +am__fastdepCC_FALSE +am__fastdepCC_TRUE +CCDEPMODE +am__nodep +AMDEPBACKSLASH +AMDEP_FALSE +AMDEP_TRUE +am__quote +am__include +DEPDIR +OBJEXT +EXEEXT +ac_ct_CC +CPPFLAGS +LDFLAGS +CFLAGS +CC +MAINT +MAINTAINER_MODE_FALSE +MAINTAINER_MODE_TRUE +AM_BACKSLASH +AM_DEFAULT_VERBOSITY +AM_DEFAULT_V +AM_V +am__untar +am__tar +AMTAR +am__leading_dot +SET_MAKE +AWK +mkdir_p +MKDIR_P +INSTALL_STRIP_PROGRAM +STRIP +install_sh +MAKEINFO +AUTOHEADER +AUTOMAKE +AUTOCONF +ACLOCAL +VERSION +PACKAGE +CYGPATH_W +am__isrc +INSTALL_DATA +INSTALL_SCRIPT +INSTALL_PROGRAM +target_alias +host_alias +build_alias +LIBS +ECHO_T +ECHO_N +ECHO_C +DEFS +mandir +localedir +libdir +psdir +pdfdir +dvidir +htmldir +infodir +docdir +oldincludedir +includedir +localstatedir +sharedstatedir +sysconfdir +datadir +datarootdir +libexecdir +sbindir +bindir +program_transform_name +prefix +exec_prefix +PACKAGE_URL +PACKAGE_BUGREPORT +PACKAGE_STRING +PACKAGE_VERSION +PACKAGE_TARNAME +PACKAGE_NAME +PATH_SEPARATOR +SHELL' +ac_subst_files='' +ac_user_opts=' +enable_option_checking +enable_silent_rules +enable_maintainer_mode +enable_dependency_tracking +enable_shared +enable_static +with_pic +enable_fast_install +with_gnu_ld +with_sysroot +enable_libtool_lock +' + ac_precious_vars='build_alias +host_alias +target_alias +CC +CFLAGS +LDFLAGS +LIBS +CPPFLAGS +CXX +CXXFLAGS +CCC +CPP +CXXCPP' + + +# Initialize some variables set by options. +ac_init_help= +ac_init_version=false +ac_unrecognized_opts= +ac_unrecognized_sep= +# The variables have the same names as the options, with +# dashes changed to underlines. +cache_file=/dev/null +exec_prefix=NONE +no_create= +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +verbose= +x_includes=NONE +x_libraries=NONE + +# Installation directory options. +# These are left unexpanded so users can "make install exec_prefix=/foo" +# and all the variables that are supposed to be based on exec_prefix +# by default will actually change. +# Use braces instead of parens because sh, perl, etc. also accept them. +# (The list follows the same order as the GNU Coding Standards.) +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datarootdir='${prefix}/share' +datadir='${datarootdir}' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +includedir='${prefix}/include' +oldincludedir='/usr/include' +docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' +infodir='${datarootdir}/info' +htmldir='${docdir}' +dvidir='${docdir}' +pdfdir='${docdir}' +psdir='${docdir}' +libdir='${exec_prefix}/lib' +localedir='${datarootdir}/locale' +mandir='${datarootdir}/man' + +ac_prev= +ac_dashdash= +for ac_option +do + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval $ac_prev=\$ac_option + ac_prev= + continue + fi + + case $ac_option in + *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; + *=) ac_optarg= ;; + *) ac_optarg=yes ;; + esac + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case $ac_dashdash$ac_option in + --) + ac_dashdash=yes ;; + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir=$ac_optarg ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build_alias ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build_alias=$ac_optarg ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file=$ac_optarg ;; + + --config-cache | -C) + cache_file=config.cache ;; + + -datadir | --datadir | --datadi | --datad) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=*) + datadir=$ac_optarg ;; + + -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ + | --dataroo | --dataro | --datar) + ac_prev=datarootdir ;; + -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ + | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) + datarootdir=$ac_optarg ;; + + -disable-* | --disable-*) + ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid feature name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=no ;; + + -docdir | --docdir | --docdi | --doc | --do) + ac_prev=docdir ;; + -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) + docdir=$ac_optarg ;; + + -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) + ac_prev=dvidir ;; + -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) + dvidir=$ac_optarg ;; + + -enable-* | --enable-*) + ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid feature name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=\$ac_optarg ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix=$ac_optarg ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he | -h) + ac_init_help=long ;; + -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) + ac_init_help=recursive ;; + -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) + ac_init_help=short ;; + + -host | --host | --hos | --ho) + ac_prev=host_alias ;; + -host=* | --host=* | --hos=* | --ho=*) + host_alias=$ac_optarg ;; + + -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) + ac_prev=htmldir ;; + -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ + | --ht=*) + htmldir=$ac_optarg ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir=$ac_optarg ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir=$ac_optarg ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir=$ac_optarg ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir=$ac_optarg ;; + + -localedir | --localedir | --localedi | --localed | --locale) + ac_prev=localedir ;; + -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) + localedir=$ac_optarg ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst | --locals) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) + localstatedir=$ac_optarg ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir=$ac_optarg ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c | -n) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir=$ac_optarg ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix=$ac_optarg ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix=$ac_optarg ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix=$ac_optarg ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name=$ac_optarg ;; + + -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) + ac_prev=pdfdir ;; + -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) + pdfdir=$ac_optarg ;; + + -psdir | --psdir | --psdi | --psd | --ps) + ac_prev=psdir ;; + -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) + psdir=$ac_optarg ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir=$ac_optarg ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir=$ac_optarg ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site=$ac_optarg ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir=$ac_optarg ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir=$ac_optarg ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target_alias ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target_alias=$ac_optarg ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers | -V) + ac_init_version=: ;; + + -with-* | --with-*) + ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid package name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=\$ac_optarg ;; + + -without-* | --without-*) + ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid package name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=no ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes=$ac_optarg ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries=$ac_optarg ;; + + -*) as_fn_error $? "unrecognized option: \`$ac_option' +Try \`$0 --help' for more information" + ;; + + *=*) + ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` + # Reject names that are not valid shell variable names. + case $ac_envvar in #( + '' | [0-9]* | *[!_$as_cr_alnum]* ) + as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; + esac + eval $ac_envvar=\$ac_optarg + export $ac_envvar ;; + + *) + # FIXME: should be removed in autoconf 3.0. + $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 + expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && + $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 + : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" + ;; + + esac +done + +if test -n "$ac_prev"; then + ac_option=--`echo $ac_prev | sed 's/_/-/g'` + as_fn_error $? "missing argument to $ac_option" +fi + +if test -n "$ac_unrecognized_opts"; then + case $enable_option_checking in + no) ;; + fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; + *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; + esac +fi + +# Check all directory arguments for consistency. +for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ + datadir sysconfdir sharedstatedir localstatedir includedir \ + oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ + libdir localedir mandir +do + eval ac_val=\$$ac_var + # Remove trailing slashes. + case $ac_val in + */ ) + ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` + eval $ac_var=\$ac_val;; + esac + # Be sure to have absolute directory names. + case $ac_val in + [\\/$]* | ?:[\\/]* ) continue;; + NONE | '' ) case $ac_var in *prefix ) continue;; esac;; + esac + as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" +done + +# There might be people who depend on the old broken behavior: `$host' +# used to hold the argument of --host etc. +# FIXME: To remove some day. +build=$build_alias +host=$host_alias +target=$target_alias + +# FIXME: To remove some day. +if test "x$host_alias" != x; then + if test "x$build_alias" = x; then + cross_compiling=maybe + elif test "x$build_alias" != "x$host_alias"; then + cross_compiling=yes + fi +fi + +ac_tool_prefix= +test -n "$host_alias" && ac_tool_prefix=$host_alias- + +test "$silent" = yes && exec 6>/dev/null + + +ac_pwd=`pwd` && test -n "$ac_pwd" && +ac_ls_di=`ls -di .` && +ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || + as_fn_error $? "working directory cannot be determined" +test "X$ac_ls_di" = "X$ac_pwd_ls_di" || + as_fn_error $? "pwd does not report name of working directory" + + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then the parent directory. + ac_confdir=`$as_dirname -- "$as_myself" || +$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_myself" : 'X\(//\)[^/]' \| \ + X"$as_myself" : 'X\(//\)$' \| \ + X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_myself" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + srcdir=$ac_confdir + if test ! -r "$srcdir/$ac_unique_file"; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r "$srcdir/$ac_unique_file"; then + test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." + as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" +fi +ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" +ac_abs_confdir=`( + cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" + pwd)` +# When building in place, set srcdir=. +if test "$ac_abs_confdir" = "$ac_pwd"; then + srcdir=. +fi +# Remove unnecessary trailing slashes from srcdir. +# Double slashes in file names in object file debugging info +# mess up M-x gdb in Emacs. +case $srcdir in +*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; +esac +for ac_var in $ac_precious_vars; do + eval ac_env_${ac_var}_set=\${${ac_var}+set} + eval ac_env_${ac_var}_value=\$${ac_var} + eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} + eval ac_cv_env_${ac_var}_value=\$${ac_var} +done + +# +# Report the --help message. +# +if test "$ac_init_help" = "long"; then + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat <<_ACEOF +\`configure' configures PortAudioCpp 12 to adapt to many kinds of systems. + +Usage: $0 [OPTION]... [VAR=VALUE]... + +To assign environment variables (e.g., CC, CFLAGS...), specify them as +VAR=VALUE. See below for descriptions of some of the useful variables. + +Defaults for the options are specified in brackets. + +Configuration: + -h, --help display this help and exit + --help=short display options specific to this package + --help=recursive display the short help of all the included packages + -V, --version display version information and exit + -q, --quiet, --silent do not print \`checking ...' messages + --cache-file=FILE cache test results in FILE [disabled] + -C, --config-cache alias for \`--cache-file=config.cache' + -n, --no-create do not create output files + --srcdir=DIR find the sources in DIR [configure dir or \`..'] + +Installation directories: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [PREFIX] + +By default, \`make install' will install all the files in +\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify +an installation prefix other than \`$ac_default_prefix' using \`--prefix', +for instance \`--prefix=\$HOME'. + +For better control, use the options below. + +Fine tuning of the installation directories: + --bindir=DIR user executables [EPREFIX/bin] + --sbindir=DIR system admin executables [EPREFIX/sbin] + --libexecdir=DIR program executables [EPREFIX/libexec] + --sysconfdir=DIR read-only single-machine data [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] + --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --libdir=DIR object code libraries [EPREFIX/lib] + --includedir=DIR C header files [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc [/usr/include] + --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] + --datadir=DIR read-only architecture-independent data [DATAROOTDIR] + --infodir=DIR info documentation [DATAROOTDIR/info] + --localedir=DIR locale-dependent data [DATAROOTDIR/locale] + --mandir=DIR man documentation [DATAROOTDIR/man] + --docdir=DIR documentation root [DATAROOTDIR/doc/portaudiocpp] + --htmldir=DIR html documentation [DOCDIR] + --dvidir=DIR dvi documentation [DOCDIR] + --pdfdir=DIR pdf documentation [DOCDIR] + --psdir=DIR ps documentation [DOCDIR] +_ACEOF + + cat <<\_ACEOF + +Program names: + --program-prefix=PREFIX prepend PREFIX to installed program names + --program-suffix=SUFFIX append SUFFIX to installed program names + --program-transform-name=PROGRAM run sed PROGRAM on installed program names + +System types: + --build=BUILD configure for building on BUILD [guessed] + --host=HOST cross-compile to build programs to run on HOST [BUILD] +_ACEOF +fi + +if test -n "$ac_init_help"; then + case $ac_init_help in + short | recursive ) echo "Configuration of PortAudioCpp 12:";; + esac + cat <<\_ACEOF + +Optional Features: + --disable-option-checking ignore unrecognized --enable/--with options + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --enable-silent-rules less verbose build output (undo: "make V=1") + --disable-silent-rules verbose build output (undo: "make V=0") + --enable-maintainer-mode + enable make rules and dependencies not useful (and + sometimes confusing) to the casual installer + --enable-dependency-tracking + do not reject slow dependency extractors + --disable-dependency-tracking + speeds up one-time build + --enable-shared[=PKGS] build shared libraries [default=yes] + --enable-static[=PKGS] build static libraries [default=yes] + --enable-fast-install[=PKGS] + optimize for fast installation [default=yes] + --disable-libtool-lock avoid locking (might break parallel builds) + +Optional Packages: + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --with-pic[=PKGS] try to use only PIC/non-PIC objects [default=use + both] + --with-gnu-ld assume the C compiler uses GNU ld [default=no] + --with-sysroot=DIR Search for dependent libraries within DIR + (or the compiler's sysroot if not specified). + +Some influential environment variables: + CC C compiler command + CFLAGS C compiler flags + LDFLAGS linker flags, e.g. -L if you have libraries in a + nonstandard directory + LIBS libraries to pass to the linker, e.g. -l + CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if + you have headers in a nonstandard directory + CXX C++ compiler command + CXXFLAGS C++ compiler flags + CPP C preprocessor + CXXCPP C++ preprocessor + +Use these variables to override the choices made by `configure' or to help +it to find libraries and programs with nonstandard names/locations. + +Report bugs to the package provider. +_ACEOF +ac_status=$? +fi + +if test "$ac_init_help" = "recursive"; then + # If there are subdirs, report their specific --help. + for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue + test -d "$ac_dir" || + { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || + continue + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + cd "$ac_dir" || { ac_status=$?; continue; } + # Check for guested configure. + if test -f "$ac_srcdir/configure.gnu"; then + echo && + $SHELL "$ac_srcdir/configure.gnu" --help=recursive + elif test -f "$ac_srcdir/configure"; then + echo && + $SHELL "$ac_srcdir/configure" --help=recursive + else + $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 + fi || ac_status=$? + cd "$ac_pwd" || { ac_status=$?; break; } + done +fi + +test -n "$ac_init_help" && exit $ac_status +if $ac_init_version; then + cat <<\_ACEOF +PortAudioCpp configure 12 +generated by GNU Autoconf 2.69 + +Copyright (C) 2012 Free Software Foundation, Inc. +This configure script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it. +_ACEOF + exit +fi + +## ------------------------ ## +## Autoconf initialization. ## +## ------------------------ ## + +# ac_fn_c_try_compile LINENO +# -------------------------- +# Try to compile conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext + if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_compile + +# ac_fn_cxx_try_compile LINENO +# ---------------------------- +# Try to compile conftest.$ac_ext, and return whether this succeeded. +ac_fn_cxx_try_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext + if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_cxx_try_compile + +# ac_fn_c_try_link LINENO +# ----------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_link () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext conftest$ac_exeext + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + test -x conftest$ac_exeext + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information + # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would + # interfere with the next link command; also delete a directory that is + # left behind by Apple's compiler. We do this before executing the actions. + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_link + +# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES +# ------------------------------------------------------- +# Tests whether HEADER exists and can be compiled using the include files in +# INCLUDES, setting the cache variable VAR accordingly. +ac_fn_c_check_header_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +#include <$2> +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + eval "$3=yes" +else + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_header_compile + +# ac_fn_c_try_cpp LINENO +# ---------------------- +# Try to preprocess conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_cpp () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } > conftest.i && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_cpp + +# ac_fn_c_try_run LINENO +# ---------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes +# that executables *can* be run. +ac_fn_c_try_run () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then : + ac_retval=0 +else + $as_echo "$as_me: program exited with status $ac_status" >&5 + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=$ac_status +fi + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_run + +# ac_fn_c_check_func LINENO FUNC VAR +# ---------------------------------- +# Tests whether FUNC exists, setting the cache variable VAR accordingly +ac_fn_c_check_func () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +/* Define $2 to an innocuous variant, in case declares $2. + For example, HP-UX 11i declares gettimeofday. */ +#define $2 innocuous_$2 + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $2 (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $2 + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char $2 (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_$2 || defined __stub___$2 +choke me +#endif + +int +main () +{ +return $2 (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + eval "$3=yes" +else + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_func + +# ac_fn_cxx_try_cpp LINENO +# ------------------------ +# Try to preprocess conftest.$ac_ext, and return whether this succeeded. +ac_fn_cxx_try_cpp () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } > conftest.i && { + test -z "$ac_cxx_preproc_warn_flag$ac_cxx_werror_flag" || + test ! -s conftest.err + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_cxx_try_cpp + +# ac_fn_cxx_try_link LINENO +# ------------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. +ac_fn_cxx_try_link () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext conftest$ac_exeext + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + test -x conftest$ac_exeext + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information + # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would + # interfere with the next link command; also delete a directory that is + # left behind by Apple's compiler. We do this before executing the actions. + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_cxx_try_link +cat >config.log <<_ACEOF +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. + +It was created by PortAudioCpp $as_me 12, which was +generated by GNU Autoconf 2.69. Invocation command line was + + $ $0 $@ + +_ACEOF +exec 5>>config.log +{ +cat <<_ASUNAME +## --------- ## +## Platform. ## +## --------- ## + +hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` + +/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` +/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` +/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` +/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` + +_ASUNAME + +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + $as_echo "PATH: $as_dir" + done +IFS=$as_save_IFS + +} >&5 + +cat >&5 <<_ACEOF + + +## ----------- ## +## Core tests. ## +## ----------- ## + +_ACEOF + + +# Keep a trace of the command line. +# Strip out --no-create and --no-recursion so they do not pile up. +# Strip out --silent because we don't want to record it for future runs. +# Also quote any args containing shell meta-characters. +# Make two passes to allow for proper duplicate-argument suppression. +ac_configure_args= +ac_configure_args0= +ac_configure_args1= +ac_must_keep_next=false +for ac_pass in 1 2 +do + for ac_arg + do + case $ac_arg in + -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + continue ;; + *\'*) + ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + case $ac_pass in + 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; + 2) + as_fn_append ac_configure_args1 " '$ac_arg'" + if test $ac_must_keep_next = true; then + ac_must_keep_next=false # Got value, back to normal. + else + case $ac_arg in + *=* | --config-cache | -C | -disable-* | --disable-* \ + | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ + | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ + | -with-* | --with-* | -without-* | --without-* | --x) + case "$ac_configure_args0 " in + "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; + esac + ;; + -* ) ac_must_keep_next=true ;; + esac + fi + as_fn_append ac_configure_args " '$ac_arg'" + ;; + esac + done +done +{ ac_configure_args0=; unset ac_configure_args0;} +{ ac_configure_args1=; unset ac_configure_args1;} + +# When interrupted or exit'd, cleanup temporary files, and complete +# config.log. We remove comments because anyway the quotes in there +# would cause problems or look ugly. +# WARNING: Use '\'' to represent an apostrophe within the trap. +# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. +trap 'exit_status=$? + # Save into config.log some information that might help in debugging. + { + echo + + $as_echo "## ---------------- ## +## Cache variables. ## +## ---------------- ##" + echo + # The following way of writing the cache mishandles newlines in values, +( + for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done + (set) 2>&1 | + case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + sed -n \ + "s/'\''/'\''\\\\'\'''\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" + ;; #( + *) + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) + echo + + $as_echo "## ----------------- ## +## Output variables. ## +## ----------------- ##" + echo + for ac_var in $ac_subst_vars + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + + if test -n "$ac_subst_files"; then + $as_echo "## ------------------- ## +## File substitutions. ## +## ------------------- ##" + echo + for ac_var in $ac_subst_files + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + fi + + if test -s confdefs.h; then + $as_echo "## ----------- ## +## confdefs.h. ## +## ----------- ##" + echo + cat confdefs.h + echo + fi + test "$ac_signal" != 0 && + $as_echo "$as_me: caught signal $ac_signal" + $as_echo "$as_me: exit $exit_status" + } >&5 + rm -f core *.core core.conftest.* && + rm -f -r conftest* confdefs* conf$$* $ac_clean_files && + exit $exit_status +' 0 +for ac_signal in 1 2 13 15; do + trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal +done +ac_signal=0 + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -f -r conftest* confdefs.h + +$as_echo "/* confdefs.h */" > confdefs.h + +# Predefined preprocessor variables. + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_NAME "$PACKAGE_NAME" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_TARNAME "$PACKAGE_TARNAME" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_VERSION "$PACKAGE_VERSION" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_STRING "$PACKAGE_STRING" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_URL "$PACKAGE_URL" +_ACEOF + + +# Let the site file select an alternate cache file if it wants to. +# Prefer an explicitly selected file to automatically selected ones. +ac_site_file1=NONE +ac_site_file2=NONE +if test -n "$CONFIG_SITE"; then + # We do not want a PATH search for config.site. + case $CONFIG_SITE in #(( + -*) ac_site_file1=./$CONFIG_SITE;; + */*) ac_site_file1=$CONFIG_SITE;; + *) ac_site_file1=./$CONFIG_SITE;; + esac +elif test "x$prefix" != xNONE; then + ac_site_file1=$prefix/share/config.site + ac_site_file2=$prefix/etc/config.site +else + ac_site_file1=$ac_default_prefix/share/config.site + ac_site_file2=$ac_default_prefix/etc/config.site +fi +for ac_site_file in "$ac_site_file1" "$ac_site_file2" +do + test "x$ac_site_file" = xNONE && continue + if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 +$as_echo "$as_me: loading site script $ac_site_file" >&6;} + sed 's/^/| /' "$ac_site_file" >&5 + . "$ac_site_file" \ + || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "failed to load site script $ac_site_file +See \`config.log' for more details" "$LINENO" 5; } + fi +done + +if test -r "$cache_file"; then + # Some versions of bash will fail to source /dev/null (special files + # actually), so we avoid doing that. DJGPP emulates it as a regular file. + if test /dev/null != "$cache_file" && test -f "$cache_file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 +$as_echo "$as_me: loading cache $cache_file" >&6;} + case $cache_file in + [\\/]* | ?:[\\/]* ) . "$cache_file";; + *) . "./$cache_file";; + esac + fi +else + { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 +$as_echo "$as_me: creating cache $cache_file" >&6;} + >$cache_file +fi + +# Check that the precious variables saved in the cache have kept the same +# value. +ac_cache_corrupted=false +for ac_var in $ac_precious_vars; do + eval ac_old_set=\$ac_cv_env_${ac_var}_set + eval ac_new_set=\$ac_env_${ac_var}_set + eval ac_old_val=\$ac_cv_env_${ac_var}_value + eval ac_new_val=\$ac_env_${ac_var}_value + case $ac_old_set,$ac_new_set in + set,) + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,set) + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,);; + *) + if test "x$ac_old_val" != "x$ac_new_val"; then + # differences in whitespace do not lead to failure. + ac_old_val_w=`echo x $ac_old_val` + ac_new_val_w=`echo x $ac_new_val` + if test "$ac_old_val_w" != "$ac_new_val_w"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 +$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + ac_cache_corrupted=: + else + { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 +$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} + eval $ac_var=\$ac_old_val + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 +$as_echo "$as_me: former value: \`$ac_old_val'" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 +$as_echo "$as_me: current value: \`$ac_new_val'" >&2;} + fi;; + esac + # Pass precious variables to config.status. + if test "$ac_new_set" = set; then + case $ac_new_val in + *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; + *) ac_arg=$ac_var=$ac_new_val ;; + esac + case " $ac_configure_args " in + *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. + *) as_fn_append ac_configure_args " '$ac_arg'" ;; + esac + fi +done +if $ac_cache_corrupted; then + { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 +$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} + as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 +fi +## -------------------- ## +## Main body of script. ## +## -------------------- ## + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + +am__api_version='1.14' + +ac_aux_dir= +for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do + if test -f "$ac_dir/install-sh"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f "$ac_dir/install.sh"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + elif test -f "$ac_dir/shtool"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/shtool install -c" + break + fi +done +if test -z "$ac_aux_dir"; then + as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5 +fi + +# These three variables are undocumented and unsupported, +# and are intended to be withdrawn in a future Autoconf release. +# They can cause serious problems if a builder's source tree is in a directory +# whose full name contains unusual characters. +ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. +ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. +ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. + + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AmigaOS /C/install, which installs bootblocks on floppy discs +# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# OS/2's system install, which has a completely different semantic +# ./install, which can be erroneously created by make from ./install.sh. +# Reject install programs that cannot install multiple files. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 +$as_echo_n "checking for a BSD-compatible install... " >&6; } +if test -z "$INSTALL"; then +if ${ac_cv_path_install+:} false; then : + $as_echo_n "(cached) " >&6 +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + # Account for people who put trailing slashes in PATH elements. +case $as_dir/ in #(( + ./ | .// | /[cC]/* | \ + /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ + ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ + /usr/ucb/* ) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + # Don't use installbsd from OSF since it installs stuff as root + # by default. + for ac_prog in ginstall scoinst install; do + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then + if test $ac_prog = install && + grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + : + elif test $ac_prog = install && + grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # program-specific install script used by HP pwplus--don't use. + : + else + rm -rf conftest.one conftest.two conftest.dir + echo one > conftest.one + echo two > conftest.two + mkdir conftest.dir + if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && + test -s conftest.one && test -s conftest.two && + test -s conftest.dir/conftest.one && + test -s conftest.dir/conftest.two + then + ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" + break 3 + fi + fi + fi + done + done + ;; +esac + + done +IFS=$as_save_IFS + +rm -rf conftest.one conftest.two conftest.dir + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL=$ac_cv_path_install + else + # As a last resort, use the slow shell script. Don't cache a + # value for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the value is a relative name. + INSTALL=$ac_install_sh + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 +$as_echo "$INSTALL" >&6; } + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5 +$as_echo_n "checking whether build environment is sane... " >&6; } +# Reject unsafe characters in $srcdir or the absolute working directory +# name. Accept space and tab only in the latter. +am_lf=' +' +case `pwd` in + *[\\\"\#\$\&\'\`$am_lf]*) + as_fn_error $? "unsafe absolute working directory name" "$LINENO" 5;; +esac +case $srcdir in + *[\\\"\#\$\&\'\`$am_lf\ \ ]*) + as_fn_error $? "unsafe srcdir value: '$srcdir'" "$LINENO" 5;; +esac + +# Do 'set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + am_has_slept=no + for am_try in 1 2; do + echo "timestamp, slept: $am_has_slept" > conftest.file + set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` + if test "$*" = "X"; then + # -L didn't work. + set X `ls -t "$srcdir/configure" conftest.file` + fi + if test "$*" != "X $srcdir/configure conftest.file" \ + && test "$*" != "X conftest.file $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + as_fn_error $? "ls -t appears to fail. Make sure there is not a broken + alias in your environment" "$LINENO" 5 + fi + if test "$2" = conftest.file || test $am_try -eq 2; then + break + fi + # Just in case. + sleep 1 + am_has_slept=yes + done + test "$2" = conftest.file + ) +then + # Ok. + : +else + as_fn_error $? "newly created file is older than distributed files! +Check your system clock" "$LINENO" 5 +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +# If we didn't sleep, we still need to ensure time stamps of config.status and +# generated files are strictly newer. +am_sleep_pid= +if grep 'slept: no' conftest.file >/dev/null 2>&1; then + ( sleep 1 ) & + am_sleep_pid=$! +fi + +rm -f conftest.file + +test "$program_prefix" != NONE && + program_transform_name="s&^&$program_prefix&;$program_transform_name" +# Use a double $ so make ignores it. +test "$program_suffix" != NONE && + program_transform_name="s&\$&$program_suffix&;$program_transform_name" +# Double any \ or $. +# By default was `s,x,x', remove it if useless. +ac_script='s/[\\$]/&&/g;s/;s,x,x,$//' +program_transform_name=`$as_echo "$program_transform_name" | sed "$ac_script"` + +# expand $ac_aux_dir to an absolute path +am_aux_dir=`cd $ac_aux_dir && pwd` + +if test x"${MISSING+set}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; + *) + MISSING="\${SHELL} $am_aux_dir/missing" ;; + esac +fi +# Use eval to expand $SHELL +if eval "$MISSING --is-lightweight"; then + am_missing_run="$MISSING " +else + am_missing_run= + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: 'missing' script is too old or missing" >&5 +$as_echo "$as_me: WARNING: 'missing' script is too old or missing" >&2;} +fi + +if test x"${install_sh}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; + *) + install_sh="\${SHELL} $am_aux_dir/install-sh" + esac +fi + +# Installed binaries are usually stripped using 'strip' when the user +# run "make install-strip". However 'strip' might not be the right +# tool to use in cross-compilation environments, therefore Automake +# will honor the 'STRIP' environment variable to overrule this program. +if test "$cross_compiling" != no; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. +set dummy ${ac_tool_prefix}strip; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_STRIP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$STRIP"; then + ac_cv_prog_STRIP="$STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_STRIP="${ac_tool_prefix}strip" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +STRIP=$ac_cv_prog_STRIP +if test -n "$STRIP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 +$as_echo "$STRIP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_STRIP"; then + ac_ct_STRIP=$STRIP + # Extract the first word of "strip", so it can be a program name with args. +set dummy strip; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_STRIP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_STRIP"; then + ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_STRIP="strip" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP +if test -n "$ac_ct_STRIP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 +$as_echo "$ac_ct_STRIP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_STRIP" = x; then + STRIP=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + STRIP=$ac_ct_STRIP + fi +else + STRIP="$ac_cv_prog_STRIP" +fi + +fi +INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a thread-safe mkdir -p" >&5 +$as_echo_n "checking for a thread-safe mkdir -p... " >&6; } +if test -z "$MKDIR_P"; then + if ${ac_cv_path_mkdir+:} false; then : + $as_echo_n "(cached) " >&6 +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in mkdir gmkdir; do + for ac_exec_ext in '' $ac_executable_extensions; do + as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext" || continue + case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #( + 'mkdir (GNU coreutils) '* | \ + 'mkdir (coreutils) '* | \ + 'mkdir (fileutils) '4.1*) + ac_cv_path_mkdir=$as_dir/$ac_prog$ac_exec_ext + break 3;; + esac + done + done + done +IFS=$as_save_IFS + +fi + + test -d ./--version && rmdir ./--version + if test "${ac_cv_path_mkdir+set}" = set; then + MKDIR_P="$ac_cv_path_mkdir -p" + else + # As a last resort, use the slow shell script. Don't cache a + # value for MKDIR_P within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the value is a relative name. + MKDIR_P="$ac_install_sh -d" + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5 +$as_echo "$MKDIR_P" >&6; } + +for ac_prog in gawk mawk nawk awk +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_AWK+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$AWK"; then + ac_cv_prog_AWK="$AWK" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_AWK="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +AWK=$ac_cv_prog_AWK +if test -n "$AWK"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5 +$as_echo "$AWK" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$AWK" && break +done + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 +$as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } +set x ${MAKE-make} +ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` +if eval \${ac_cv_prog_make_${ac_make}_set+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat >conftest.make <<\_ACEOF +SHELL = /bin/sh +all: + @echo '@@@%%%=$(MAKE)=@@@%%%' +_ACEOF +# GNU make sometimes prints "make[1]: Entering ...", which would confuse us. +case `${MAKE-make} -f conftest.make 2>/dev/null` in + *@@@%%%=?*=@@@%%%*) + eval ac_cv_prog_make_${ac_make}_set=yes;; + *) + eval ac_cv_prog_make_${ac_make}_set=no;; +esac +rm -f conftest.make +fi +if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + SET_MAKE= +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + SET_MAKE="MAKE=${MAKE-make}" +fi + +rm -rf .tst 2>/dev/null +mkdir .tst 2>/dev/null +if test -d .tst; then + am__leading_dot=. +else + am__leading_dot=_ +fi +rmdir .tst 2>/dev/null + +# Check whether --enable-silent-rules was given. +if test "${enable_silent_rules+set}" = set; then : + enableval=$enable_silent_rules; +fi + +case $enable_silent_rules in # ((( + yes) AM_DEFAULT_VERBOSITY=0;; + no) AM_DEFAULT_VERBOSITY=1;; + *) AM_DEFAULT_VERBOSITY=1;; +esac +am_make=${MAKE-make} +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $am_make supports nested variables" >&5 +$as_echo_n "checking whether $am_make supports nested variables... " >&6; } +if ${am_cv_make_support_nested_variables+:} false; then : + $as_echo_n "(cached) " >&6 +else + if $as_echo 'TRUE=$(BAR$(V)) +BAR0=false +BAR1=true +V=1 +am__doit: + @$(TRUE) +.PHONY: am__doit' | $am_make -f - >/dev/null 2>&1; then + am_cv_make_support_nested_variables=yes +else + am_cv_make_support_nested_variables=no +fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_make_support_nested_variables" >&5 +$as_echo "$am_cv_make_support_nested_variables" >&6; } +if test $am_cv_make_support_nested_variables = yes; then + AM_V='$(V)' + AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' +else + AM_V=$AM_DEFAULT_VERBOSITY + AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY +fi +AM_BACKSLASH='\' + +if test "`cd $srcdir && pwd`" != "`pwd`"; then + # Use -I$(srcdir) only when $(srcdir) != ., so that make's output + # is not polluted with repeated "-I." + am__isrc=' -I$(srcdir)' + # test to see if srcdir already configured + if test -f $srcdir/config.status; then + as_fn_error $? "source directory already configured; run \"make distclean\" there first" "$LINENO" 5 + fi +fi + +# test whether we have cygpath +if test -z "$CYGPATH_W"; then + if (cygpath --version) >/dev/null 2>/dev/null; then + CYGPATH_W='cygpath -w' + else + CYGPATH_W=echo + fi +fi + + +# Define the identity of the package. + PACKAGE='portaudiocpp' + VERSION='12' + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE "$PACKAGE" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define VERSION "$VERSION" +_ACEOF + +# Some tools Automake needs. + +ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"} + + +AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"} + + +AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"} + + +AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"} + + +MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"} + +# For better backward compatibility. To be removed once Automake 1.9.x +# dies out for good. For more background, see: +# +# +mkdir_p='$(MKDIR_P)' + +# We need awk for the "check" target. The system "awk" is bad on +# some platforms. +# Always define AMTAR for backward compatibility. Yes, it's still used +# in the wild :-( We should find a proper way to deprecate it ... +AMTAR='$${TAR-tar}' + + +# We'll loop over all known methods to create a tar archive until one works. +_am_tools='gnutar pax cpio none' + +am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -' + + + + + + +# POSIX will say in a future version that running "rm -f" with no argument +# is OK; and we want to be able to make that assumption in our Makefile +# recipes. So use an aggressive probe to check that the usage we want is +# actually supported "in the wild" to an acceptable degree. +# See automake bug#10828. +# To make any issue more visible, cause the running configure to be aborted +# by default if the 'rm' program in use doesn't match our expectations; the +# user can still override this though. +if rm -f && rm -fr && rm -rf; then : OK; else + cat >&2 <<'END' +Oops! + +Your 'rm' program seems unable to run without file operands specified +on the command line, even when the '-f' option is present. This is contrary +to the behaviour of most rm programs out there, and not conforming with +the upcoming POSIX standard: + +Please tell bug-automake@gnu.org about your system, including the value +of your $PATH and any error possibly output before this message. This +can help us improve future automake versions. + +END + if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then + echo 'Configuration will proceed anyway, since you have set the' >&2 + echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2 + echo >&2 + else + cat >&2 <<'END' +Aborting the configuration process, to ensure you take notice of the issue. + +You can download and install GNU coreutils to get an 'rm' implementation +that behaves properly: . + +If you want to complete the configuration process using your problematic +'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM +to "yes", and re-run configure. + +END + as_fn_error $? "Your 'rm' program is bad, sorry." "$LINENO" 5 + fi +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable maintainer-specific portions of Makefiles" >&5 +$as_echo_n "checking whether to enable maintainer-specific portions of Makefiles... " >&6; } + # Check whether --enable-maintainer-mode was given. +if test "${enable_maintainer_mode+set}" = set; then : + enableval=$enable_maintainer_mode; USE_MAINTAINER_MODE=$enableval +else + USE_MAINTAINER_MODE=no +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $USE_MAINTAINER_MODE" >&5 +$as_echo "$USE_MAINTAINER_MODE" >&6; } + if test $USE_MAINTAINER_MODE = yes; then + MAINTAINER_MODE_TRUE= + MAINTAINER_MODE_FALSE='#' +else + MAINTAINER_MODE_TRUE='#' + MAINTAINER_MODE_FALSE= +fi + + MAINT=$MAINTAINER_MODE_TRUE + + + +###### Top-level directory of pacpp +###### This makes it easy to shuffle the build directories +###### Also edit AC_CONFIG_SRCDIR above (wouldn't accept this variable)! +PACPP_ROOT="\$(top_srcdir)" +PORTAUDIO_ROOT="../.." + +# Various other variables and flags +DEFAULT_INCLUDES="-I$PACPP_ROOT/include -I$PACPP_ROOT/$PORTAUDIO_ROOT/include" +CFLAGS=${CFLAGS-"-g -O2 -Wall -ansi -pedantic"} +CXXFLAGS=${CXXFLAGS-"${CFLAGS}"} + +LT_VERSION_INFO="0:12:0" + +# Checks for programs + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. +set dummy ${ac_tool_prefix}gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +else + CC="$ac_cv_prog_CC" +fi + +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. +set dummy ${ac_tool_prefix}cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + fi +fi +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + ac_prog_rejected=no +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# != 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" + fi +fi +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + for ac_prog in cl.exe + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$CC" && break + done +fi +if test -z "$CC"; then + ac_ct_CC=$CC + for ac_prog in cl.exe +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_CC" && break +done + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +fi + +fi + + +test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "no acceptable C compiler found in \$PATH +See \`config.log' for more details" "$LINENO" 5; } + +# Provide some information about the compiler. +$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 +set X $ac_compile +ac_compiler=$2 +for ac_option in --version -v -V -qversion; do + { { ac_try="$ac_compiler $ac_option >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compiler $ac_option >&5") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + sed '10a\ +... rest of stderr output deleted ... + 10q' conftest.err >conftest.er1 + cat conftest.er1 >&5 + fi + rm -f conftest.er1 conftest.err + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +done + +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" +# Try to create an executable without -o first, disregard a.out. +# It will help us diagnose broken compilers, and finding out an intuition +# of exeext. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 +$as_echo_n "checking whether the C compiler works... " >&6; } +ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` + +# The possible output files: +ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" + +ac_rmfiles= +for ac_file in $ac_files +do + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; + * ) ac_rmfiles="$ac_rmfiles $ac_file";; + esac +done +rm -f $ac_rmfiles + +if { { ac_try="$ac_link_default" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link_default") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. +# So ignore a value of `no', otherwise this would lead to `EXEEXT = no' +# in a Makefile. We should not override ac_cv_exeext if it was cached, +# so that the user can short-circuit this test for compilers unknown to +# Autoconf. +for ac_file in $ac_files '' +do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) + ;; + [ab].out ) + # We found the default executable, but exeext='' is most + # certainly right. + break;; + *.* ) + if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; + then :; else + ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + fi + # We set ac_cv_exeext here because the later test for it is not + # safe: cross compilers may not add the suffix if given an `-o' + # argument, so we may need to know it at that point already. + # Even if this section looks crufty: it has the advantage of + # actually working. + break;; + * ) + break;; + esac +done +test "$ac_cv_exeext" = no && ac_cv_exeext= + +else + ac_file='' +fi +if test -z "$ac_file"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +$as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error 77 "C compiler cannot create executables +See \`config.log' for more details" "$LINENO" 5; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 +$as_echo_n "checking for C compiler default output file name... " >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 +$as_echo "$ac_file" >&6; } +ac_exeext=$ac_cv_exeext + +rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out +ac_clean_files=$ac_clean_files_save +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 +$as_echo_n "checking for suffix of executables... " >&6; } +if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + # If both `conftest.exe' and `conftest' are `present' (well, observable) +# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will +# work properly (i.e., refer to `conftest.exe'), while it won't with +# `rm'. +for ac_file in conftest.exe conftest conftest.*; do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; + *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + break;; + * ) break;; + esac +done +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details" "$LINENO" 5; } +fi +rm -f conftest conftest$ac_cv_exeext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 +$as_echo "$ac_cv_exeext" >&6; } + +rm -f conftest.$ac_ext +EXEEXT=$ac_cv_exeext +ac_exeext=$EXEEXT +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +FILE *f = fopen ("conftest.out", "w"); + return ferror (f) || fclose (f) != 0; + + ; + return 0; +} +_ACEOF +ac_clean_files="$ac_clean_files conftest.out" +# Check that the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 +$as_echo_n "checking whether we are cross compiling... " >&6; } +if test "$cross_compiling" != yes; then + { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + if { ac_try='./conftest$ac_cv_exeext' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then + cross_compiling=no + else + if test "$cross_compiling" = maybe; then + cross_compiling=yes + else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details" "$LINENO" 5; } + fi + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 +$as_echo "$cross_compiling" >&6; } + +rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out +ac_clean_files=$ac_clean_files_save +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 +$as_echo_n "checking for suffix of object files... " >&6; } +if ${ac_cv_objext+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.o conftest.obj +if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + for ac_file in conftest.o conftest.obj conftest.*; do + test -f "$ac_file" || continue; + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; + *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` + break;; + esac +done +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot compute suffix of object files: cannot compile +See \`config.log' for more details" "$LINENO" 5; } +fi +rm -f conftest.$ac_cv_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 +$as_echo "$ac_cv_objext" >&6; } +OBJEXT=$ac_cv_objext +ac_objext=$OBJEXT +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 +$as_echo_n "checking whether we are using the GNU C compiler... " >&6; } +if ${ac_cv_c_compiler_gnu+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_compiler_gnu=yes +else + ac_compiler_gnu=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_c_compiler_gnu=$ac_compiler_gnu + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 +$as_echo "$ac_cv_c_compiler_gnu" >&6; } +if test $ac_compiler_gnu = yes; then + GCC=yes +else + GCC= +fi +ac_test_CFLAGS=${CFLAGS+set} +ac_save_CFLAGS=$CFLAGS +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 +$as_echo_n "checking whether $CC accepts -g... " >&6; } +if ${ac_cv_prog_cc_g+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_save_c_werror_flag=$ac_c_werror_flag + ac_c_werror_flag=yes + ac_cv_prog_cc_g=no + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +else + CFLAGS="" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +else + ac_c_werror_flag=$ac_save_c_werror_flag + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_c_werror_flag=$ac_save_c_werror_flag +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 +$as_echo "$ac_cv_prog_cc_g" >&6; } +if test "$ac_test_CFLAGS" = set; then + CFLAGS=$ac_save_CFLAGS +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 +$as_echo_n "checking for $CC option to accept ISO C89... " >&6; } +if ${ac_cv_prog_cc_c89+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_cv_prog_cc_c89=no +ac_save_CC=$CC +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +struct stat; +/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ +struct buf { int x; }; +FILE * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (p, i) + char **p; + int i; +{ + return p[i]; +} +static char *f (char * (*g) (char **, int), char **p, ...) +{ + char *s; + va_list v; + va_start (v,p); + s = g (p, va_arg (v,int)); + va_end (v); + return s; +} + +/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has + function prototypes and stuff, but not '\xHH' hex character constants. + These don't provoke an error unfortunately, instead are silently treated + as 'x'. The following induces an error, until -std is added to get + proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an + array size at least. It's necessary to write '\x00'==0 to get something + that's true only with -std. */ +int osf4_cc_array ['\x00' == 0 ? 1 : -1]; + +/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters + inside strings and character constants. */ +#define FOO(x) 'x' +int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; + +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); +int argc; +char **argv; +int +main () +{ +return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; + ; + return 0; +} +_ACEOF +for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ + -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +do + CC="$ac_save_CC $ac_arg" + if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_c89=$ac_arg +fi +rm -f core conftest.err conftest.$ac_objext + test "x$ac_cv_prog_cc_c89" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC + +fi +# AC_CACHE_VAL +case "x$ac_cv_prog_cc_c89" in + x) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +$as_echo "none needed" >&6; } ;; + xno) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +$as_echo "unsupported" >&6; } ;; + *) + CC="$CC $ac_cv_prog_cc_c89" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 +$as_echo "$ac_cv_prog_cc_c89" >&6; } ;; +esac +if test "x$ac_cv_prog_cc_c89" != xno; then : + +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC understands -c and -o together" >&5 +$as_echo_n "checking whether $CC understands -c and -o together... " >&6; } +if ${am_cv_prog_cc_c_o+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF + # Make sure it works both with $CC and with simple cc. + # Following AC_PROG_CC_C_O, we do the test twice because some + # compilers refuse to overwrite an existing .o file with -o, + # though they will create one. + am_cv_prog_cc_c_o=yes + for am_i in 1 2; do + if { echo "$as_me:$LINENO: $CC -c conftest.$ac_ext -o conftest2.$ac_objext" >&5 + ($CC -c conftest.$ac_ext -o conftest2.$ac_objext) >&5 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } \ + && test -f conftest2.$ac_objext; then + : OK + else + am_cv_prog_cc_c_o=no + break + fi + done + rm -f core conftest* + unset am_i +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_cc_c_o" >&5 +$as_echo "$am_cv_prog_cc_c_o" >&6; } +if test "$am_cv_prog_cc_c_o" != yes; then + # Losing compiler, so override with the script. + # FIXME: It is wrong to rewrite CC. + # But if we don't then we get into trouble of one sort or another. + # A longer-term fix would be to have automake use am__CC in this case, + # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" + CC="$am_aux_dir/compile $CC" +fi +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +DEPDIR="${am__leading_dot}deps" + +ac_config_commands="$ac_config_commands depfiles" + + +am_make=${MAKE-make} +cat > confinc << 'END' +am__doit: + @echo this is the am__doit target +.PHONY: am__doit +END +# If we don't find an include directive, just comment out the code. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for style of include used by $am_make" >&5 +$as_echo_n "checking for style of include used by $am_make... " >&6; } +am__include="#" +am__quote= +_am_result=none +# First try GNU make style include. +echo "include confinc" > confmf +# Ignore all kinds of additional output from 'make'. +case `$am_make -s -f confmf 2> /dev/null` in #( +*the\ am__doit\ target*) + am__include=include + am__quote= + _am_result=GNU + ;; +esac +# Now try BSD make style include. +if test "$am__include" = "#"; then + echo '.include "confinc"' > confmf + case `$am_make -s -f confmf 2> /dev/null` in #( + *the\ am__doit\ target*) + am__include=.include + am__quote="\"" + _am_result=BSD + ;; + esac +fi + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $_am_result" >&5 +$as_echo "$_am_result" >&6; } +rm -f confinc confmf + +# Check whether --enable-dependency-tracking was given. +if test "${enable_dependency_tracking+set}" = set; then : + enableval=$enable_dependency_tracking; +fi + +if test "x$enable_dependency_tracking" != xno; then + am_depcomp="$ac_aux_dir/depcomp" + AMDEPBACKSLASH='\' + am__nodep='_no' +fi + if test "x$enable_dependency_tracking" != xno; then + AMDEP_TRUE= + AMDEP_FALSE='#' +else + AMDEP_TRUE='#' + AMDEP_FALSE= +fi + + + +depcc="$CC" am_compiler_list= + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 +$as_echo_n "checking dependency style of $depcc... " >&6; } +if ${am_cv_CC_dependencies_compiler_type+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named 'D' -- because '-MD' means "put the output + # in D". + rm -rf conftest.dir + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_CC_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` + fi + am__universal=false + case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac + + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with + # Solaris 10 /bin/sh. + echo '/* dummy */' > sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + # We check with '-c' and '-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle '-M -o', and we need to detect this. Also, some Intel + # versions had trouble with output in subdirs. + am__obj=sub/conftest.${OBJEXT-o} + am__minus_obj="-o $am__obj" + case $depmode in + gcc) + # This depmode causes a compiler race in universal mode. + test "$am__universal" = false || continue + ;; + nosideeffect) + # After this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested. + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + msvc7 | msvc7msys | msvisualcpp | msvcmsys) + # This compiler won't grok '-c -o', but also, the minuso test has + # not run yet. These depmodes are late enough in the game, and + # so weak that their functioning should not be impacted. + am__obj=conftest.${OBJEXT-o} + am__minus_obj= + ;; + none) break ;; + esac + if depmode=$depmode \ + source=sub/conftest.c object=$am__obj \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep $am__obj sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_CC_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_CC_dependencies_compiler_type=none +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5 +$as_echo "$am_cv_CC_dependencies_compiler_type" >&6; } +CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type + + if + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then + am__fastdepCC_TRUE= + am__fastdepCC_FALSE='#' +else + am__fastdepCC_TRUE='#' + am__fastdepCC_FALSE= +fi + + +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu +if test -z "$CXX"; then + if test -n "$CCC"; then + CXX=$CCC + else + if test -n "$ac_tool_prefix"; then + for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CXX+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CXX"; then + ac_cv_prog_CXX="$CXX" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CXX="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CXX=$ac_cv_prog_CXX +if test -n "$CXX"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5 +$as_echo "$CXX" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$CXX" && break + done +fi +if test -z "$CXX"; then + ac_ct_CXX=$CXX + for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_CXX+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CXX"; then + ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CXX="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CXX=$ac_cv_prog_ac_ct_CXX +if test -n "$ac_ct_CXX"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CXX" >&5 +$as_echo "$ac_ct_CXX" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_CXX" && break +done + + if test "x$ac_ct_CXX" = x; then + CXX="g++" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CXX=$ac_ct_CXX + fi +fi + + fi +fi +# Provide some information about the compiler. +$as_echo "$as_me:${as_lineno-$LINENO}: checking for C++ compiler version" >&5 +set X $ac_compile +ac_compiler=$2 +for ac_option in --version -v -V -qversion; do + { { ac_try="$ac_compiler $ac_option >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compiler $ac_option >&5") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + sed '10a\ +... rest of stderr output deleted ... + 10q' conftest.err >conftest.er1 + cat conftest.er1 >&5 + fi + rm -f conftest.er1 conftest.err + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +done + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C++ compiler" >&5 +$as_echo_n "checking whether we are using the GNU C++ compiler... " >&6; } +if ${ac_cv_cxx_compiler_gnu+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_compiler_gnu=yes +else + ac_compiler_gnu=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_cxx_compiler_gnu=$ac_compiler_gnu + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_compiler_gnu" >&5 +$as_echo "$ac_cv_cxx_compiler_gnu" >&6; } +if test $ac_compiler_gnu = yes; then + GXX=yes +else + GXX= +fi +ac_test_CXXFLAGS=${CXXFLAGS+set} +ac_save_CXXFLAGS=$CXXFLAGS +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -g" >&5 +$as_echo_n "checking whether $CXX accepts -g... " >&6; } +if ${ac_cv_prog_cxx_g+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_save_cxx_werror_flag=$ac_cxx_werror_flag + ac_cxx_werror_flag=yes + ac_cv_prog_cxx_g=no + CXXFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_cv_prog_cxx_g=yes +else + CXXFLAGS="" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + +else + ac_cxx_werror_flag=$ac_save_cxx_werror_flag + CXXFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_cv_prog_cxx_g=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_cxx_werror_flag=$ac_save_cxx_werror_flag +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_g" >&5 +$as_echo "$ac_cv_prog_cxx_g" >&6; } +if test "$ac_test_CXXFLAGS" = set; then + CXXFLAGS=$ac_save_CXXFLAGS +elif test $ac_cv_prog_cxx_g = yes; then + if test "$GXX" = yes; then + CXXFLAGS="-g -O2" + else + CXXFLAGS="-g" + fi +else + if test "$GXX" = yes; then + CXXFLAGS="-O2" + else + CXXFLAGS= + fi +fi +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +depcc="$CXX" am_compiler_list= + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 +$as_echo_n "checking dependency style of $depcc... " >&6; } +if ${am_cv_CXX_dependencies_compiler_type+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named 'D' -- because '-MD' means "put the output + # in D". + rm -rf conftest.dir + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_CXX_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` + fi + am__universal=false + case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac + + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with + # Solaris 10 /bin/sh. + echo '/* dummy */' > sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + # We check with '-c' and '-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle '-M -o', and we need to detect this. Also, some Intel + # versions had trouble with output in subdirs. + am__obj=sub/conftest.${OBJEXT-o} + am__minus_obj="-o $am__obj" + case $depmode in + gcc) + # This depmode causes a compiler race in universal mode. + test "$am__universal" = false || continue + ;; + nosideeffect) + # After this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested. + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + msvc7 | msvc7msys | msvisualcpp | msvcmsys) + # This compiler won't grok '-c -o', but also, the minuso test has + # not run yet. These depmodes are late enough in the game, and + # so weak that their functioning should not be impacted. + am__obj=conftest.${OBJEXT-o} + am__minus_obj= + ;; + none) break ;; + esac + if depmode=$depmode \ + source=sub/conftest.c object=$am__obj \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep $am__obj sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_CXX_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_CXX_dependencies_compiler_type=none +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CXX_dependencies_compiler_type" >&5 +$as_echo "$am_cv_CXX_dependencies_compiler_type" >&6; } +CXXDEPMODE=depmode=$am_cv_CXX_dependencies_compiler_type + + if + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_CXX_dependencies_compiler_type" = gcc3; then + am__fastdepCXX_TRUE= + am__fastdepCXX_FALSE='#' +else + am__fastdepCXX_TRUE='#' + am__fastdepCXX_FALSE= +fi + + +# Make sure we can run config.sub. +$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || + as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5 + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 +$as_echo_n "checking build system type... " >&6; } +if ${ac_cv_build+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_build_alias=$build_alias +test "x$ac_build_alias" = x && + ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` +test "x$ac_build_alias" = x && + as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 +ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` || + as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5 + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 +$as_echo "$ac_cv_build" >&6; } +case $ac_cv_build in +*-*-*) ;; +*) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;; +esac +build=$ac_cv_build +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_build +shift +build_cpu=$1 +build_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +build_os=$* +IFS=$ac_save_IFS +case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 +$as_echo_n "checking host system type... " >&6; } +if ${ac_cv_host+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test "x$host_alias" = x; then + ac_cv_host=$ac_cv_build +else + ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || + as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5 +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 +$as_echo "$ac_cv_host" >&6; } +case $ac_cv_host in +*-*-*) ;; +*) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;; +esac +host=$ac_cv_host +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_host +shift +host_cpu=$1 +host_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +host_os=$* +IFS=$ac_save_IFS +case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac + + +enable_win32_dll=yes + +case $host in +*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-cegcc*) + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}as", so it can be a program name with args. +set dummy ${ac_tool_prefix}as; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_AS+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$AS"; then + ac_cv_prog_AS="$AS" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_AS="${ac_tool_prefix}as" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +AS=$ac_cv_prog_AS +if test -n "$AS"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AS" >&5 +$as_echo "$AS" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_AS"; then + ac_ct_AS=$AS + # Extract the first word of "as", so it can be a program name with args. +set dummy as; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_AS+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_AS"; then + ac_cv_prog_ac_ct_AS="$ac_ct_AS" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_AS="as" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_AS=$ac_cv_prog_ac_ct_AS +if test -n "$ac_ct_AS"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AS" >&5 +$as_echo "$ac_ct_AS" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_AS" = x; then + AS="false" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + AS=$ac_ct_AS + fi +else + AS="$ac_cv_prog_AS" +fi + + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}dlltool", so it can be a program name with args. +set dummy ${ac_tool_prefix}dlltool; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_DLLTOOL+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$DLLTOOL"; then + ac_cv_prog_DLLTOOL="$DLLTOOL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_DLLTOOL="${ac_tool_prefix}dlltool" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +DLLTOOL=$ac_cv_prog_DLLTOOL +if test -n "$DLLTOOL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DLLTOOL" >&5 +$as_echo "$DLLTOOL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_DLLTOOL"; then + ac_ct_DLLTOOL=$DLLTOOL + # Extract the first word of "dlltool", so it can be a program name with args. +set dummy dlltool; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_DLLTOOL+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_DLLTOOL"; then + ac_cv_prog_ac_ct_DLLTOOL="$ac_ct_DLLTOOL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_DLLTOOL="dlltool" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_DLLTOOL=$ac_cv_prog_ac_ct_DLLTOOL +if test -n "$ac_ct_DLLTOOL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DLLTOOL" >&5 +$as_echo "$ac_ct_DLLTOOL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_DLLTOOL" = x; then + DLLTOOL="false" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + DLLTOOL=$ac_ct_DLLTOOL + fi +else + DLLTOOL="$ac_cv_prog_DLLTOOL" +fi + + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}objdump", so it can be a program name with args. +set dummy ${ac_tool_prefix}objdump; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_OBJDUMP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$OBJDUMP"; then + ac_cv_prog_OBJDUMP="$OBJDUMP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_OBJDUMP="${ac_tool_prefix}objdump" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +OBJDUMP=$ac_cv_prog_OBJDUMP +if test -n "$OBJDUMP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OBJDUMP" >&5 +$as_echo "$OBJDUMP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_OBJDUMP"; then + ac_ct_OBJDUMP=$OBJDUMP + # Extract the first word of "objdump", so it can be a program name with args. +set dummy objdump; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_OBJDUMP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_OBJDUMP"; then + ac_cv_prog_ac_ct_OBJDUMP="$ac_ct_OBJDUMP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_OBJDUMP="objdump" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_OBJDUMP=$ac_cv_prog_ac_ct_OBJDUMP +if test -n "$ac_ct_OBJDUMP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OBJDUMP" >&5 +$as_echo "$ac_ct_OBJDUMP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_OBJDUMP" = x; then + OBJDUMP="false" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + OBJDUMP=$ac_ct_OBJDUMP + fi +else + OBJDUMP="$ac_cv_prog_OBJDUMP" +fi + + ;; +esac + +test -z "$AS" && AS=as + + + + + +test -z "$DLLTOOL" && DLLTOOL=dlltool + + + + + +test -z "$OBJDUMP" && OBJDUMP=objdump + + + + + + + +case `pwd` in + *\ * | *\ *) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&5 +$as_echo "$as_me: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&2;} ;; +esac + + + +macro_version='2.4.2' +macro_revision='1.3337' + + + + + + + + + + + + + +ltmain="$ac_aux_dir/ltmain.sh" + +# Backslashify metacharacters that are still active within +# double-quoted strings. +sed_quote_subst='s/\(["`$\\]\)/\\\1/g' + +# Same as above, but do not quote variable references. +double_quote_subst='s/\(["`\\]\)/\\\1/g' + +# Sed substitution to delay expansion of an escaped shell variable in a +# double_quote_subst'ed string. +delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' + +# Sed substitution to delay expansion of an escaped single quote. +delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g' + +# Sed substitution to avoid accidental globbing in evaled expressions +no_glob_subst='s/\*/\\\*/g' + +ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO +ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to print strings" >&5 +$as_echo_n "checking how to print strings... " >&6; } +# Test print first, because it will be a builtin if present. +if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \ + test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then + ECHO='print -r --' +elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then + ECHO='printf %s\n' +else + # Use this function as a fallback that always works. + func_fallback_echo () + { + eval 'cat <<_LTECHO_EOF +$1 +_LTECHO_EOF' + } + ECHO='func_fallback_echo' +fi + +# func_echo_all arg... +# Invoke $ECHO with all args, space-separated. +func_echo_all () +{ + $ECHO "" +} + +case "$ECHO" in + printf*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: printf" >&5 +$as_echo "printf" >&6; } ;; + print*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: print -r" >&5 +$as_echo "print -r" >&6; } ;; + *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: cat" >&5 +$as_echo "cat" >&6; } ;; +esac + + + + + + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5 +$as_echo_n "checking for a sed that does not truncate output... " >&6; } +if ${ac_cv_path_SED+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ + for ac_i in 1 2 3 4 5 6 7; do + ac_script="$ac_script$as_nl$ac_script" + done + echo "$ac_script" 2>/dev/null | sed 99q >conftest.sed + { ac_script=; unset ac_script;} + if test -z "$SED"; then + ac_path_SED_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in sed gsed; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_SED="$as_dir/$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_SED" || continue +# Check for GNU ac_path_SED and select it if it is found. + # Check for GNU $ac_path_SED +case `"$ac_path_SED" --version 2>&1` in +*GNU*) + ac_cv_path_SED="$ac_path_SED" ac_path_SED_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo '' >> "conftest.nl" + "$ac_path_SED" -f conftest.sed < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_SED_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_SED="$ac_path_SED" + ac_path_SED_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_SED_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_SED"; then + as_fn_error $? "no acceptable sed could be found in \$PATH" "$LINENO" 5 + fi +else + ac_cv_path_SED=$SED +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5 +$as_echo "$ac_cv_path_SED" >&6; } + SED="$ac_cv_path_SED" + rm -f conftest.sed + +test -z "$SED" && SED=sed +Xsed="$SED -e 1s/^X//" + + + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 +$as_echo_n "checking for grep that handles long lines and -e... " >&6; } +if ${ac_cv_path_GREP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$GREP"; then + ac_path_GREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in grep ggrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_GREP" || continue +# Check for GNU ac_path_GREP and select it if it is found. + # Check for GNU $ac_path_GREP +case `"$ac_path_GREP" --version 2>&1` in +*GNU*) + ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'GREP' >> "conftest.nl" + "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_GREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_GREP="$ac_path_GREP" + ac_path_GREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_GREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_GREP"; then + as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_GREP=$GREP +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 +$as_echo "$ac_cv_path_GREP" >&6; } + GREP="$ac_cv_path_GREP" + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 +$as_echo_n "checking for egrep... " >&6; } +if ${ac_cv_path_EGREP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 + then ac_cv_path_EGREP="$GREP -E" + else + if test -z "$EGREP"; then + ac_path_EGREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in egrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_EGREP" || continue +# Check for GNU ac_path_EGREP and select it if it is found. + # Check for GNU $ac_path_EGREP +case `"$ac_path_EGREP" --version 2>&1` in +*GNU*) + ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'EGREP' >> "conftest.nl" + "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_EGREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_EGREP="$ac_path_EGREP" + ac_path_EGREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_EGREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_EGREP"; then + as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_EGREP=$EGREP +fi + + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 +$as_echo "$ac_cv_path_EGREP" >&6; } + EGREP="$ac_cv_path_EGREP" + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for fgrep" >&5 +$as_echo_n "checking for fgrep... " >&6; } +if ${ac_cv_path_FGREP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if echo 'ab*c' | $GREP -F 'ab*c' >/dev/null 2>&1 + then ac_cv_path_FGREP="$GREP -F" + else + if test -z "$FGREP"; then + ac_path_FGREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in fgrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_FGREP="$as_dir/$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_FGREP" || continue +# Check for GNU ac_path_FGREP and select it if it is found. + # Check for GNU $ac_path_FGREP +case `"$ac_path_FGREP" --version 2>&1` in +*GNU*) + ac_cv_path_FGREP="$ac_path_FGREP" ac_path_FGREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'FGREP' >> "conftest.nl" + "$ac_path_FGREP" FGREP < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_FGREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_FGREP="$ac_path_FGREP" + ac_path_FGREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_FGREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_FGREP"; then + as_fn_error $? "no acceptable fgrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_FGREP=$FGREP +fi + + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_FGREP" >&5 +$as_echo "$ac_cv_path_FGREP" >&6; } + FGREP="$ac_cv_path_FGREP" + + +test -z "$GREP" && GREP=grep + + + + + + + + + + + + + + + + + + + +# Check whether --with-gnu-ld was given. +if test "${with_gnu_ld+set}" = set; then : + withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes +else + with_gnu_ld=no +fi + +ac_prog=ld +if test "$GCC" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5 +$as_echo_n "checking for ld used by $CC... " >&6; } + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case $ac_prog in + # Accept absolute paths. + [\\/]* | ?:[\\/]*) + re_direlt='/[^/][^/]*/\.\./' + # Canonicalize the pathname of ld + ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` + while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do + ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` + done + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5 +$as_echo_n "checking for GNU ld... " >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5 +$as_echo_n "checking for non-GNU ld... " >&6; } +fi +if ${lt_cv_path_LD+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$LD"; then + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + lt_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some variants of GNU ld only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + case `"$lt_cv_path_LD" -v 2>&1 &5 +$as_echo "$LD" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5 +$as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; } +if ${lt_cv_prog_gnu_ld+:} false; then : + $as_echo_n "(cached) " >&6 +else + # I'd rather use --version here, but apparently some GNU lds only accept -v. +case `$LD -v 2>&1 &5 +$as_echo "$lt_cv_prog_gnu_ld" >&6; } +with_gnu_ld=$lt_cv_prog_gnu_ld + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for BSD- or MS-compatible name lister (nm)" >&5 +$as_echo_n "checking for BSD- or MS-compatible name lister (nm)... " >&6; } +if ${lt_cv_path_NM+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$NM"; then + # Let the user override the test. + lt_cv_path_NM="$NM" +else + lt_nm_to_check="${ac_tool_prefix}nm" + if test -n "$ac_tool_prefix" && test "$build" = "$host"; then + lt_nm_to_check="$lt_nm_to_check nm" + fi + for lt_tmp_nm in $lt_nm_to_check; do + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + tmp_nm="$ac_dir/$lt_tmp_nm" + if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then + # Check to see if the nm accepts a BSD-compat flag. + # Adding the `sed 1q' prevents false positives on HP-UX, which says: + # nm: unknown option "B" ignored + # Tru64's nm complains that /dev/null is an invalid object file + case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in + */dev/null* | *'Invalid file or object type'*) + lt_cv_path_NM="$tmp_nm -B" + break + ;; + *) + case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in + */dev/null*) + lt_cv_path_NM="$tmp_nm -p" + break + ;; + *) + lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but + continue # so that we can try to find one that supports BSD flags + ;; + esac + ;; + esac + fi + done + IFS="$lt_save_ifs" + done + : ${lt_cv_path_NM=no} +fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_NM" >&5 +$as_echo "$lt_cv_path_NM" >&6; } +if test "$lt_cv_path_NM" != "no"; then + NM="$lt_cv_path_NM" +else + # Didn't find any BSD compatible name lister, look for dumpbin. + if test -n "$DUMPBIN"; then : + # Let the user override the test. + else + if test -n "$ac_tool_prefix"; then + for ac_prog in dumpbin "link -dump" + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_DUMPBIN+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$DUMPBIN"; then + ac_cv_prog_DUMPBIN="$DUMPBIN" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_DUMPBIN="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +DUMPBIN=$ac_cv_prog_DUMPBIN +if test -n "$DUMPBIN"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DUMPBIN" >&5 +$as_echo "$DUMPBIN" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$DUMPBIN" && break + done +fi +if test -z "$DUMPBIN"; then + ac_ct_DUMPBIN=$DUMPBIN + for ac_prog in dumpbin "link -dump" +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_DUMPBIN+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_DUMPBIN"; then + ac_cv_prog_ac_ct_DUMPBIN="$ac_ct_DUMPBIN" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_DUMPBIN="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_DUMPBIN=$ac_cv_prog_ac_ct_DUMPBIN +if test -n "$ac_ct_DUMPBIN"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DUMPBIN" >&5 +$as_echo "$ac_ct_DUMPBIN" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_DUMPBIN" && break +done + + if test "x$ac_ct_DUMPBIN" = x; then + DUMPBIN=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + DUMPBIN=$ac_ct_DUMPBIN + fi +fi + + case `$DUMPBIN -symbols /dev/null 2>&1 | sed '1q'` in + *COFF*) + DUMPBIN="$DUMPBIN -symbols" + ;; + *) + DUMPBIN=: + ;; + esac + fi + + if test "$DUMPBIN" != ":"; then + NM="$DUMPBIN" + fi +fi +test -z "$NM" && NM=nm + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the name lister ($NM) interface" >&5 +$as_echo_n "checking the name lister ($NM) interface... " >&6; } +if ${lt_cv_nm_interface+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_nm_interface="BSD nm" + echo "int some_variable = 0;" > conftest.$ac_ext + (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&5) + (eval "$ac_compile" 2>conftest.err) + cat conftest.err >&5 + (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&5) + (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) + cat conftest.err >&5 + (eval echo "\"\$as_me:$LINENO: output\"" >&5) + cat conftest.out >&5 + if $GREP 'External.*some_variable' conftest.out > /dev/null; then + lt_cv_nm_interface="MS dumpbin" + fi + rm -f conftest* +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_nm_interface" >&5 +$as_echo "$lt_cv_nm_interface" >&6; } + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5 +$as_echo_n "checking whether ln -s works... " >&6; } +LN_S=$as_ln_s +if test "$LN_S" = "ln -s"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5 +$as_echo "no, using $LN_S" >&6; } +fi + +# find the maximum length of command line arguments +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the maximum length of command line arguments" >&5 +$as_echo_n "checking the maximum length of command line arguments... " >&6; } +if ${lt_cv_sys_max_cmd_len+:} false; then : + $as_echo_n "(cached) " >&6 +else + i=0 + teststring="ABCD" + + case $build_os in + msdosdjgpp*) + # On DJGPP, this test can blow up pretty badly due to problems in libc + # (any single argument exceeding 2000 bytes causes a buffer overrun + # during glob expansion). Even if it were fixed, the result of this + # check would be larger than it should be. + lt_cv_sys_max_cmd_len=12288; # 12K is about right + ;; + + gnu*) + # Under GNU Hurd, this test is not required because there is + # no limit to the length of command line arguments. + # Libtool will interpret -1 as no limit whatsoever + lt_cv_sys_max_cmd_len=-1; + ;; + + cygwin* | mingw* | cegcc*) + # On Win9x/ME, this test blows up -- it succeeds, but takes + # about 5 minutes as the teststring grows exponentially. + # Worse, since 9x/ME are not pre-emptively multitasking, + # you end up with a "frozen" computer, even though with patience + # the test eventually succeeds (with a max line length of 256k). + # Instead, let's just punt: use the minimum linelength reported by + # all of the supported platforms: 8192 (on NT/2K/XP). + lt_cv_sys_max_cmd_len=8192; + ;; + + mint*) + # On MiNT this can take a long time and run out of memory. + lt_cv_sys_max_cmd_len=8192; + ;; + + amigaos*) + # On AmigaOS with pdksh, this test takes hours, literally. + # So we just punt and use a minimum line length of 8192. + lt_cv_sys_max_cmd_len=8192; + ;; + + netbsd* | freebsd* | openbsd* | darwin* | dragonfly*) + # This has been around since 386BSD, at least. Likely further. + if test -x /sbin/sysctl; then + lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` + elif test -x /usr/sbin/sysctl; then + lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` + else + lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs + fi + # And add a safety zone + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` + ;; + + interix*) + # We know the value 262144 and hardcode it with a safety zone (like BSD) + lt_cv_sys_max_cmd_len=196608 + ;; + + os2*) + # The test takes a long time on OS/2. + lt_cv_sys_max_cmd_len=8192 + ;; + + osf*) + # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure + # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not + # nice to cause kernel panics so lets avoid the loop below. + # First set a reasonable default. + lt_cv_sys_max_cmd_len=16384 + # + if test -x /sbin/sysconfig; then + case `/sbin/sysconfig -q proc exec_disable_arg_limit` in + *1*) lt_cv_sys_max_cmd_len=-1 ;; + esac + fi + ;; + sco3.2v5*) + lt_cv_sys_max_cmd_len=102400 + ;; + sysv5* | sco5v6* | sysv4.2uw2*) + kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` + if test -n "$kargmax"; then + lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[ ]//'` + else + lt_cv_sys_max_cmd_len=32768 + fi + ;; + *) + lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null` + if test -n "$lt_cv_sys_max_cmd_len" && \ + test undefined != "$lt_cv_sys_max_cmd_len"; then + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` + else + # Make teststring a little bigger before we do anything with it. + # a 1K string should be a reasonable start. + for i in 1 2 3 4 5 6 7 8 ; do + teststring=$teststring$teststring + done + SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} + # If test is not a shell built-in, we'll probably end up computing a + # maximum length that is only half of the actual maximum length, but + # we can't tell. + while { test "X"`env echo "$teststring$teststring" 2>/dev/null` \ + = "X$teststring$teststring"; } >/dev/null 2>&1 && + test $i != 17 # 1/2 MB should be enough + do + i=`expr $i + 1` + teststring=$teststring$teststring + done + # Only check the string length outside the loop. + lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1` + teststring= + # Add a significant safety factor because C++ compilers can tack on + # massive amounts of additional arguments before passing them to the + # linker. It appears as though 1/2 is a usable value. + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` + fi + ;; + esac + +fi + +if test -n $lt_cv_sys_max_cmd_len ; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sys_max_cmd_len" >&5 +$as_echo "$lt_cv_sys_max_cmd_len" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: none" >&5 +$as_echo "none" >&6; } +fi +max_cmd_len=$lt_cv_sys_max_cmd_len + + + + + + +: ${CP="cp -f"} +: ${MV="mv -f"} +: ${RM="rm -f"} + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands some XSI constructs" >&5 +$as_echo_n "checking whether the shell understands some XSI constructs... " >&6; } +# Try some XSI features +xsi_shell=no +( _lt_dummy="a/b/c" + test "${_lt_dummy##*/},${_lt_dummy%/*},${_lt_dummy#??}"${_lt_dummy%"$_lt_dummy"}, \ + = c,a/b,b/c, \ + && eval 'test $(( 1 + 1 )) -eq 2 \ + && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \ + && xsi_shell=yes +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $xsi_shell" >&5 +$as_echo "$xsi_shell" >&6; } + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands \"+=\"" >&5 +$as_echo_n "checking whether the shell understands \"+=\"... " >&6; } +lt_shell_append=no +( foo=bar; set foo baz; eval "$1+=\$2" && test "$foo" = barbaz ) \ + >/dev/null 2>&1 \ + && lt_shell_append=yes +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_shell_append" >&5 +$as_echo "$lt_shell_append" >&6; } + + +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + lt_unset=unset +else + lt_unset=false +fi + + + + + +# test EBCDIC or ASCII +case `echo X|tr X '\101'` in + A) # ASCII based system + # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr + lt_SP2NL='tr \040 \012' + lt_NL2SP='tr \015\012 \040\040' + ;; + *) # EBCDIC based system + lt_SP2NL='tr \100 \n' + lt_NL2SP='tr \r\n \100\100' + ;; +esac + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to $host format" >&5 +$as_echo_n "checking how to convert $build file names to $host format... " >&6; } +if ${lt_cv_to_host_file_cmd+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $host in + *-*-mingw* ) + case $build in + *-*-mingw* ) # actually msys + lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32 + ;; + *-*-cygwin* ) + lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32 + ;; + * ) # otherwise, assume *nix + lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32 + ;; + esac + ;; + *-*-cygwin* ) + case $build in + *-*-mingw* ) # actually msys + lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin + ;; + *-*-cygwin* ) + lt_cv_to_host_file_cmd=func_convert_file_noop + ;; + * ) # otherwise, assume *nix + lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin + ;; + esac + ;; + * ) # unhandled hosts (and "normal" native builds) + lt_cv_to_host_file_cmd=func_convert_file_noop + ;; +esac + +fi + +to_host_file_cmd=$lt_cv_to_host_file_cmd +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_host_file_cmd" >&5 +$as_echo "$lt_cv_to_host_file_cmd" >&6; } + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to toolchain format" >&5 +$as_echo_n "checking how to convert $build file names to toolchain format... " >&6; } +if ${lt_cv_to_tool_file_cmd+:} false; then : + $as_echo_n "(cached) " >&6 +else + #assume ordinary cross tools, or native build. +lt_cv_to_tool_file_cmd=func_convert_file_noop +case $host in + *-*-mingw* ) + case $build in + *-*-mingw* ) # actually msys + lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32 + ;; + esac + ;; +esac + +fi + +to_tool_file_cmd=$lt_cv_to_tool_file_cmd +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_tool_file_cmd" >&5 +$as_echo "$lt_cv_to_tool_file_cmd" >&6; } + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $LD option to reload object files" >&5 +$as_echo_n "checking for $LD option to reload object files... " >&6; } +if ${lt_cv_ld_reload_flag+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_ld_reload_flag='-r' +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_reload_flag" >&5 +$as_echo "$lt_cv_ld_reload_flag" >&6; } +reload_flag=$lt_cv_ld_reload_flag +case $reload_flag in +"" | " "*) ;; +*) reload_flag=" $reload_flag" ;; +esac +reload_cmds='$LD$reload_flag -o $output$reload_objs' +case $host_os in + cygwin* | mingw* | pw32* | cegcc*) + if test "$GCC" != yes; then + reload_cmds=false + fi + ;; + darwin*) + if test "$GCC" = yes; then + reload_cmds='$LTCC $LTCFLAGS -nostdlib ${wl}-r -o $output$reload_objs' + else + reload_cmds='$LD$reload_flag -o $output$reload_objs' + fi + ;; +esac + + + + + + + + + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}objdump", so it can be a program name with args. +set dummy ${ac_tool_prefix}objdump; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_OBJDUMP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$OBJDUMP"; then + ac_cv_prog_OBJDUMP="$OBJDUMP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_OBJDUMP="${ac_tool_prefix}objdump" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +OBJDUMP=$ac_cv_prog_OBJDUMP +if test -n "$OBJDUMP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OBJDUMP" >&5 +$as_echo "$OBJDUMP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_OBJDUMP"; then + ac_ct_OBJDUMP=$OBJDUMP + # Extract the first word of "objdump", so it can be a program name with args. +set dummy objdump; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_OBJDUMP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_OBJDUMP"; then + ac_cv_prog_ac_ct_OBJDUMP="$ac_ct_OBJDUMP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_OBJDUMP="objdump" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_OBJDUMP=$ac_cv_prog_ac_ct_OBJDUMP +if test -n "$ac_ct_OBJDUMP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OBJDUMP" >&5 +$as_echo "$ac_ct_OBJDUMP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_OBJDUMP" = x; then + OBJDUMP="false" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + OBJDUMP=$ac_ct_OBJDUMP + fi +else + OBJDUMP="$ac_cv_prog_OBJDUMP" +fi + +test -z "$OBJDUMP" && OBJDUMP=objdump + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to recognize dependent libraries" >&5 +$as_echo_n "checking how to recognize dependent libraries... " >&6; } +if ${lt_cv_deplibs_check_method+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_file_magic_cmd='$MAGIC_CMD' +lt_cv_file_magic_test_file= +lt_cv_deplibs_check_method='unknown' +# Need to set the preceding variable on all platforms that support +# interlibrary dependencies. +# 'none' -- dependencies not supported. +# `unknown' -- same as none, but documents that we really don't know. +# 'pass_all' -- all dependencies passed with no checks. +# 'test_compile' -- check by making test program. +# 'file_magic [[regex]]' -- check by looking for files in library path +# which responds to the $file_magic_cmd with a given extended regex. +# If you have `file' or equivalent on your system and you're not sure +# whether `pass_all' will *always* work, you probably want this one. + +case $host_os in +aix[4-9]*) + lt_cv_deplibs_check_method=pass_all + ;; + +beos*) + lt_cv_deplibs_check_method=pass_all + ;; + +bsdi[45]*) + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib)' + lt_cv_file_magic_cmd='/usr/bin/file -L' + lt_cv_file_magic_test_file=/shlib/libc.so + ;; + +cygwin*) + # func_win32_libid is a shell function defined in ltmain.sh + lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' + lt_cv_file_magic_cmd='func_win32_libid' + ;; + +mingw* | pw32*) + # Base MSYS/MinGW do not provide the 'file' command needed by + # func_win32_libid shell function, so use a weaker test based on 'objdump', + # unless we find 'file', for example because we are cross-compiling. + # func_win32_libid assumes BSD nm, so disallow it if using MS dumpbin. + if ( test "$lt_cv_nm_interface" = "BSD nm" && file / ) >/dev/null 2>&1; then + lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' + lt_cv_file_magic_cmd='func_win32_libid' + else + # Keep this pattern in sync with the one in func_win32_libid. + lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' + lt_cv_file_magic_cmd='$OBJDUMP -f' + fi + ;; + +cegcc*) + # use the weaker test based on 'objdump'. See mingw*. + lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?' + lt_cv_file_magic_cmd='$OBJDUMP -f' + ;; + +darwin* | rhapsody*) + lt_cv_deplibs_check_method=pass_all + ;; + +freebsd* | dragonfly*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then + case $host_cpu in + i*86 ) + # Not sure whether the presence of OpenBSD here was a mistake. + # Let's accept both of them until this is cleared up. + lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[3-9]86 (compact )?demand paged shared library' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` + ;; + esac + else + lt_cv_deplibs_check_method=pass_all + fi + ;; + +haiku*) + lt_cv_deplibs_check_method=pass_all + ;; + +hpux10.20* | hpux11*) + lt_cv_file_magic_cmd=/usr/bin/file + case $host_cpu in + ia64*) + lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - IA64' + lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so + ;; + hppa*64*) + lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]' + lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl + ;; + *) + lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|PA-RISC[0-9]\.[0-9]) shared library' + lt_cv_file_magic_test_file=/usr/lib/libc.sl + ;; + esac + ;; + +interix[3-9]*) + # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|\.a)$' + ;; + +irix5* | irix6* | nonstopux*) + case $LD in + *-32|*"-32 ") libmagic=32-bit;; + *-n32|*"-n32 ") libmagic=N32;; + *-64|*"-64 ") libmagic=64-bit;; + *) libmagic=never-match;; + esac + lt_cv_deplibs_check_method=pass_all + ;; + +# This must be glibc/ELF. +linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) + lt_cv_deplibs_check_method=pass_all + ;; + +netbsd* | netbsdelf*-gnu) + if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|_pic\.a)$' + fi + ;; + +newos6*) + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (executable|dynamic lib)' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=/usr/lib/libnls.so + ;; + +*nto* | *qnx*) + lt_cv_deplibs_check_method=pass_all + ;; + +openbsd*) + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|\.so|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' + fi + ;; + +osf3* | osf4* | osf5*) + lt_cv_deplibs_check_method=pass_all + ;; + +rdos*) + lt_cv_deplibs_check_method=pass_all + ;; + +solaris*) + lt_cv_deplibs_check_method=pass_all + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + lt_cv_deplibs_check_method=pass_all + ;; + +sysv4 | sysv4.3*) + case $host_vendor in + motorola) + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib) M[0-9][0-9]* Version [0-9]' + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` + ;; + ncr) + lt_cv_deplibs_check_method=pass_all + ;; + sequent) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )' + ;; + sni) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method="file_magic ELF [0-9][0-9]*-bit [LM]SB dynamic lib" + lt_cv_file_magic_test_file=/lib/libc.so + ;; + siemens) + lt_cv_deplibs_check_method=pass_all + ;; + pc) + lt_cv_deplibs_check_method=pass_all + ;; + esac + ;; + +tpf*) + lt_cv_deplibs_check_method=pass_all + ;; +esac + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_deplibs_check_method" >&5 +$as_echo "$lt_cv_deplibs_check_method" >&6; } + +file_magic_glob= +want_nocaseglob=no +if test "$build" = "$host"; then + case $host_os in + mingw* | pw32*) + if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then + want_nocaseglob=yes + else + file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[\1]\/[\1]\/g;/g"` + fi + ;; + esac +fi + +file_magic_cmd=$lt_cv_file_magic_cmd +deplibs_check_method=$lt_cv_deplibs_check_method +test -z "$deplibs_check_method" && deplibs_check_method=unknown + + + + + + + + + + + + + + + + + + + + + + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}dlltool", so it can be a program name with args. +set dummy ${ac_tool_prefix}dlltool; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_DLLTOOL+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$DLLTOOL"; then + ac_cv_prog_DLLTOOL="$DLLTOOL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_DLLTOOL="${ac_tool_prefix}dlltool" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +DLLTOOL=$ac_cv_prog_DLLTOOL +if test -n "$DLLTOOL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DLLTOOL" >&5 +$as_echo "$DLLTOOL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_DLLTOOL"; then + ac_ct_DLLTOOL=$DLLTOOL + # Extract the first word of "dlltool", so it can be a program name with args. +set dummy dlltool; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_DLLTOOL+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_DLLTOOL"; then + ac_cv_prog_ac_ct_DLLTOOL="$ac_ct_DLLTOOL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_DLLTOOL="dlltool" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_DLLTOOL=$ac_cv_prog_ac_ct_DLLTOOL +if test -n "$ac_ct_DLLTOOL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DLLTOOL" >&5 +$as_echo "$ac_ct_DLLTOOL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_DLLTOOL" = x; then + DLLTOOL="false" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + DLLTOOL=$ac_ct_DLLTOOL + fi +else + DLLTOOL="$ac_cv_prog_DLLTOOL" +fi + +test -z "$DLLTOOL" && DLLTOOL=dlltool + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to associate runtime and link libraries" >&5 +$as_echo_n "checking how to associate runtime and link libraries... " >&6; } +if ${lt_cv_sharedlib_from_linklib_cmd+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_sharedlib_from_linklib_cmd='unknown' + +case $host_os in +cygwin* | mingw* | pw32* | cegcc*) + # two different shell functions defined in ltmain.sh + # decide which to use based on capabilities of $DLLTOOL + case `$DLLTOOL --help 2>&1` in + *--identify-strict*) + lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib + ;; + *) + lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback + ;; + esac + ;; +*) + # fallback: assume linklib IS sharedlib + lt_cv_sharedlib_from_linklib_cmd="$ECHO" + ;; +esac + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sharedlib_from_linklib_cmd" >&5 +$as_echo "$lt_cv_sharedlib_from_linklib_cmd" >&6; } +sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd +test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO + + + + + + + + +if test -n "$ac_tool_prefix"; then + for ac_prog in ar + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_AR+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$AR"; then + ac_cv_prog_AR="$AR" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_AR="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +AR=$ac_cv_prog_AR +if test -n "$AR"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 +$as_echo "$AR" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$AR" && break + done +fi +if test -z "$AR"; then + ac_ct_AR=$AR + for ac_prog in ar +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_AR+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_AR"; then + ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_AR="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_AR=$ac_cv_prog_ac_ct_AR +if test -n "$ac_ct_AR"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 +$as_echo "$ac_ct_AR" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_AR" && break +done + + if test "x$ac_ct_AR" = x; then + AR="false" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + AR=$ac_ct_AR + fi +fi + +: ${AR=ar} +: ${AR_FLAGS=cru} + + + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for archiver @FILE support" >&5 +$as_echo_n "checking for archiver @FILE support... " >&6; } +if ${lt_cv_ar_at_file+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_ar_at_file=no + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + echo conftest.$ac_objext > conftest.lst + lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&5' + { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5 + (eval $lt_ar_try) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + if test "$ac_status" -eq 0; then + # Ensure the archiver fails upon bogus file names. + rm -f conftest.$ac_objext libconftest.a + { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5 + (eval $lt_ar_try) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + if test "$ac_status" -ne 0; then + lt_cv_ar_at_file=@ + fi + fi + rm -f conftest.* libconftest.a + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ar_at_file" >&5 +$as_echo "$lt_cv_ar_at_file" >&6; } + +if test "x$lt_cv_ar_at_file" = xno; then + archiver_list_spec= +else + archiver_list_spec=$lt_cv_ar_at_file +fi + + + + + + + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. +set dummy ${ac_tool_prefix}strip; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_STRIP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$STRIP"; then + ac_cv_prog_STRIP="$STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_STRIP="${ac_tool_prefix}strip" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +STRIP=$ac_cv_prog_STRIP +if test -n "$STRIP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 +$as_echo "$STRIP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_STRIP"; then + ac_ct_STRIP=$STRIP + # Extract the first word of "strip", so it can be a program name with args. +set dummy strip; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_STRIP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_STRIP"; then + ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_STRIP="strip" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP +if test -n "$ac_ct_STRIP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 +$as_echo "$ac_ct_STRIP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_STRIP" = x; then + STRIP=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + STRIP=$ac_ct_STRIP + fi +else + STRIP="$ac_cv_prog_STRIP" +fi + +test -z "$STRIP" && STRIP=: + + + + + + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. +set dummy ${ac_tool_prefix}ranlib; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_RANLIB+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$RANLIB"; then + ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +RANLIB=$ac_cv_prog_RANLIB +if test -n "$RANLIB"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 +$as_echo "$RANLIB" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_RANLIB"; then + ac_ct_RANLIB=$RANLIB + # Extract the first word of "ranlib", so it can be a program name with args. +set dummy ranlib; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_RANLIB+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_RANLIB"; then + ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_RANLIB="ranlib" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB +if test -n "$ac_ct_RANLIB"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 +$as_echo "$ac_ct_RANLIB" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_RANLIB" = x; then + RANLIB=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + RANLIB=$ac_ct_RANLIB + fi +else + RANLIB="$ac_cv_prog_RANLIB" +fi + +test -z "$RANLIB" && RANLIB=: + + + + + + +# Determine commands to create old-style static archives. +old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs' +old_postinstall_cmds='chmod 644 $oldlib' +old_postuninstall_cmds= + +if test -n "$RANLIB"; then + case $host_os in + openbsd*) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib" + ;; + *) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib" + ;; + esac + old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib" +fi + +case $host_os in + darwin*) + lock_old_archive_extraction=yes ;; + *) + lock_old_archive_extraction=no ;; +esac + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# If no C compiler flags were specified, use CFLAGS. +LTCFLAGS=${LTCFLAGS-"$CFLAGS"} + +# Allow CC to be a program name with arguments. +compiler=$CC + + +# Check for command to grab the raw symbol name followed by C symbol from nm. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking command to parse $NM output from $compiler object" >&5 +$as_echo_n "checking command to parse $NM output from $compiler object... " >&6; } +if ${lt_cv_sys_global_symbol_pipe+:} false; then : + $as_echo_n "(cached) " >&6 +else + +# These are sane defaults that work on at least a few old systems. +# [They come from Ultrix. What could be older than Ultrix?!! ;)] + +# Character class describing NM global symbol codes. +symcode='[BCDEGRST]' + +# Regexp to match symbols that can be accessed directly from C. +sympat='\([_A-Za-z][_A-Za-z0-9]*\)' + +# Define system-specific variables. +case $host_os in +aix*) + symcode='[BCDT]' + ;; +cygwin* | mingw* | pw32* | cegcc*) + symcode='[ABCDGISTW]' + ;; +hpux*) + if test "$host_cpu" = ia64; then + symcode='[ABCDEGRST]' + fi + ;; +irix* | nonstopux*) + symcode='[BCDEGRST]' + ;; +osf*) + symcode='[BCDEGQRST]' + ;; +solaris*) + symcode='[BDRT]' + ;; +sco3.2v5*) + symcode='[DT]' + ;; +sysv4.2uw2*) + symcode='[DT]' + ;; +sysv5* | sco5v6* | unixware* | OpenUNIX*) + symcode='[ABDT]' + ;; +sysv4) + symcode='[DFNSTU]' + ;; +esac + +# If we're using GNU nm, then use its standard symbol codes. +case `$NM -V 2>&1` in +*GNU* | *'with BFD'*) + symcode='[ABCDGIRSTW]' ;; +esac + +# Transform an extracted symbol line into a proper C declaration. +# Some systems (esp. on ia64) link data and code symbols differently, +# so use this general approach. +lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" + +# Transform an extracted symbol line into symbol name and symbol address +lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([^ ]*\)[ ]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"\2\", (void *) \&\2},/p'" +lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([^ ]*\)[ ]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \(lib[^ ]*\)$/ {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"lib\2\", (void *) \&\2},/p'" + +# Handle CRLF in mingw tool chain +opt_cr= +case $build_os in +mingw*) + opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp + ;; +esac + +# Try without a prefix underscore, then with it. +for ac_symprfx in "" "_"; do + + # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. + symxfrm="\\1 $ac_symprfx\\2 \\2" + + # Write the raw and C identifiers. + if test "$lt_cv_nm_interface" = "MS dumpbin"; then + # Fake it for dumpbin and say T for any non-static function + # and D for any global variable. + # Also find C++ and __fastcall symbols from MSVC++, + # which start with @ or ?. + lt_cv_sys_global_symbol_pipe="$AWK '"\ +" {last_section=section; section=\$ 3};"\ +" /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\ +" /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\ +" \$ 0!~/External *\|/{next};"\ +" / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ +" {if(hide[section]) next};"\ +" {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\ +" {split(\$ 0, a, /\||\r/); split(a[2], s)};"\ +" s[1]~/^[@?]/{print s[1], s[1]; next};"\ +" s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\ +" ' prfx=^$ac_symprfx" + else + lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[ ]\($symcode$symcode*\)[ ][ ]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" + fi + lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | sed '/ __gnu_lto/d'" + + # Check to see that the pipe works correctly. + pipe_works=no + + rm -f conftest* + cat > conftest.$ac_ext <<_LT_EOF +#ifdef __cplusplus +extern "C" { +#endif +char nm_test_var; +void nm_test_func(void); +void nm_test_func(void){} +#ifdef __cplusplus +} +#endif +int main(){nm_test_var='a';nm_test_func();return(0);} +_LT_EOF + + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + # Now try to grab the symbols. + nlist=conftest.nm + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist\""; } >&5 + (eval $NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && test -s "$nlist"; then + # Try sorting and uniquifying the output. + if sort "$nlist" | uniq > "$nlist"T; then + mv -f "$nlist"T "$nlist" + else + rm -f "$nlist"T + fi + + # Make sure that we snagged all the symbols we need. + if $GREP ' nm_test_var$' "$nlist" >/dev/null; then + if $GREP ' nm_test_func$' "$nlist" >/dev/null; then + cat <<_LT_EOF > conftest.$ac_ext +/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ +#if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE) +/* DATA imports from DLLs on WIN32 con't be const, because runtime + relocations are performed -- see ld's documentation on pseudo-relocs. */ +# define LT_DLSYM_CONST +#elif defined(__osf__) +/* This system does not cope well with relocations in const data. */ +# define LT_DLSYM_CONST +#else +# define LT_DLSYM_CONST const +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +_LT_EOF + # Now generate the symbol file. + eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext' + + cat <<_LT_EOF >> conftest.$ac_ext + +/* The mapping between symbol names and symbols. */ +LT_DLSYM_CONST struct { + const char *name; + void *address; +} +lt__PROGRAM__LTX_preloaded_symbols[] = +{ + { "@PROGRAM@", (void *) 0 }, +_LT_EOF + $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext + cat <<\_LT_EOF >> conftest.$ac_ext + {0, (void *) 0} +}; + +/* This works around a problem in FreeBSD linker */ +#ifdef FREEBSD_WORKAROUND +static const void *lt_preloaded_setup() { + return lt__PROGRAM__LTX_preloaded_symbols; +} +#endif + +#ifdef __cplusplus +} +#endif +_LT_EOF + # Now try linking the two files. + mv conftest.$ac_objext conftstm.$ac_objext + lt_globsym_save_LIBS=$LIBS + lt_globsym_save_CFLAGS=$CFLAGS + LIBS="conftstm.$ac_objext" + CFLAGS="$CFLAGS$lt_prog_compiler_no_builtin_flag" + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 + (eval $ac_link) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && test -s conftest${ac_exeext}; then + pipe_works=yes + fi + LIBS=$lt_globsym_save_LIBS + CFLAGS=$lt_globsym_save_CFLAGS + else + echo "cannot find nm_test_func in $nlist" >&5 + fi + else + echo "cannot find nm_test_var in $nlist" >&5 + fi + else + echo "cannot run $lt_cv_sys_global_symbol_pipe" >&5 + fi + else + echo "$progname: failed program was:" >&5 + cat conftest.$ac_ext >&5 + fi + rm -rf conftest* conftst* + + # Do not use the global_symbol_pipe unless it works. + if test "$pipe_works" = yes; then + break + else + lt_cv_sys_global_symbol_pipe= + fi +done + +fi + +if test -z "$lt_cv_sys_global_symbol_pipe"; then + lt_cv_sys_global_symbol_to_cdecl= +fi +if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: failed" >&5 +$as_echo "failed" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5 +$as_echo "ok" >&6; } +fi + +# Response file support. +if test "$lt_cv_nm_interface" = "MS dumpbin"; then + nm_file_list_spec='@' +elif $NM --help 2>/dev/null | grep '[@]FILE' >/dev/null; then + nm_file_list_spec='@' +fi + + + + + + + + + + + + + + + + + + + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for sysroot" >&5 +$as_echo_n "checking for sysroot... " >&6; } + +# Check whether --with-sysroot was given. +if test "${with_sysroot+set}" = set; then : + withval=$with_sysroot; +else + with_sysroot=no +fi + + +lt_sysroot= +case ${with_sysroot} in #( + yes) + if test "$GCC" = yes; then + lt_sysroot=`$CC --print-sysroot 2>/dev/null` + fi + ;; #( + /*) + lt_sysroot=`echo "$with_sysroot" | sed -e "$sed_quote_subst"` + ;; #( + no|'') + ;; #( + *) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${with_sysroot}" >&5 +$as_echo "${with_sysroot}" >&6; } + as_fn_error $? "The sysroot must be an absolute path." "$LINENO" 5 + ;; +esac + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${lt_sysroot:-no}" >&5 +$as_echo "${lt_sysroot:-no}" >&6; } + + + + + +# Check whether --enable-libtool-lock was given. +if test "${enable_libtool_lock+set}" = set; then : + enableval=$enable_libtool_lock; +fi + +test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes + +# Some flags need to be propagated to the compiler or linker for good +# libtool support. +case $host in +ia64-*-hpux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + case `/usr/bin/file conftest.$ac_objext` in + *ELF-32*) + HPUX_IA64_MODE="32" + ;; + *ELF-64*) + HPUX_IA64_MODE="64" + ;; + esac + fi + rm -rf conftest* + ;; +*-*-irix6*) + # Find out which ABI we are using. + echo '#line '$LINENO' "configure"' > conftest.$ac_ext + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + if test "$lt_cv_prog_gnu_ld" = yes; then + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -melf32bsmip" + ;; + *N32*) + LD="${LD-ld} -melf32bmipn32" + ;; + *64-bit*) + LD="${LD-ld} -melf64bmip" + ;; + esac + else + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -32" + ;; + *N32*) + LD="${LD-ld} -n32" + ;; + *64-bit*) + LD="${LD-ld} -64" + ;; + esac + fi + fi + rm -rf conftest* + ;; + +x86_64-*kfreebsd*-gnu|x86_64-*linux*|powerpc*-*linux*| \ +s390*-*linux*|s390*-*tpf*|sparc*-*linux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + case `/usr/bin/file conftest.o` in + *32-bit*) + case $host in + x86_64-*kfreebsd*-gnu) + LD="${LD-ld} -m elf_i386_fbsd" + ;; + x86_64-*linux*) + case `/usr/bin/file conftest.o` in + *x86-64*) + LD="${LD-ld} -m elf32_x86_64" + ;; + *) + LD="${LD-ld} -m elf_i386" + ;; + esac + ;; + powerpc64le-*) + LD="${LD-ld} -m elf32lppclinux" + ;; + powerpc64-*) + LD="${LD-ld} -m elf32ppclinux" + ;; + s390x-*linux*) + LD="${LD-ld} -m elf_s390" + ;; + sparc64-*linux*) + LD="${LD-ld} -m elf32_sparc" + ;; + esac + ;; + *64-bit*) + case $host in + x86_64-*kfreebsd*-gnu) + LD="${LD-ld} -m elf_x86_64_fbsd" + ;; + x86_64-*linux*) + LD="${LD-ld} -m elf_x86_64" + ;; + powerpcle-*) + LD="${LD-ld} -m elf64lppc" + ;; + powerpc-*) + LD="${LD-ld} -m elf64ppc" + ;; + s390*-*linux*|s390*-*tpf*) + LD="${LD-ld} -m elf64_s390" + ;; + sparc*-*linux*) + LD="${LD-ld} -m elf64_sparc" + ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; + +*-*-sco3.2v5*) + # On SCO OpenServer 5, we need -belf to get full-featured binaries. + SAVE_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -belf" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler needs -belf" >&5 +$as_echo_n "checking whether the C compiler needs -belf... " >&6; } +if ${lt_cv_cc_needs_belf+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + lt_cv_cc_needs_belf=yes +else + lt_cv_cc_needs_belf=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_cc_needs_belf" >&5 +$as_echo "$lt_cv_cc_needs_belf" >&6; } + if test x"$lt_cv_cc_needs_belf" != x"yes"; then + # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf + CFLAGS="$SAVE_CFLAGS" + fi + ;; +*-*solaris*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + case `/usr/bin/file conftest.o` in + *64-bit*) + case $lt_cv_prog_gnu_ld in + yes*) + case $host in + i?86-*-solaris*) + LD="${LD-ld} -m elf_x86_64" + ;; + sparc*-*-solaris*) + LD="${LD-ld} -m elf64_sparc" + ;; + esac + # GNU ld 2.21 introduced _sol2 emulations. Use them if available. + if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then + LD="${LD-ld}_sol2" + fi + ;; + *) + if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then + LD="${LD-ld} -64" + fi + ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; +esac + +need_locks="$enable_libtool_lock" + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}mt", so it can be a program name with args. +set dummy ${ac_tool_prefix}mt; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_MANIFEST_TOOL+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$MANIFEST_TOOL"; then + ac_cv_prog_MANIFEST_TOOL="$MANIFEST_TOOL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_MANIFEST_TOOL="${ac_tool_prefix}mt" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +MANIFEST_TOOL=$ac_cv_prog_MANIFEST_TOOL +if test -n "$MANIFEST_TOOL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MANIFEST_TOOL" >&5 +$as_echo "$MANIFEST_TOOL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_MANIFEST_TOOL"; then + ac_ct_MANIFEST_TOOL=$MANIFEST_TOOL + # Extract the first word of "mt", so it can be a program name with args. +set dummy mt; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_MANIFEST_TOOL+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_MANIFEST_TOOL"; then + ac_cv_prog_ac_ct_MANIFEST_TOOL="$ac_ct_MANIFEST_TOOL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_MANIFEST_TOOL="mt" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_MANIFEST_TOOL=$ac_cv_prog_ac_ct_MANIFEST_TOOL +if test -n "$ac_ct_MANIFEST_TOOL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_MANIFEST_TOOL" >&5 +$as_echo "$ac_ct_MANIFEST_TOOL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_MANIFEST_TOOL" = x; then + MANIFEST_TOOL=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + MANIFEST_TOOL=$ac_ct_MANIFEST_TOOL + fi +else + MANIFEST_TOOL="$ac_cv_prog_MANIFEST_TOOL" +fi + +test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $MANIFEST_TOOL is a manifest tool" >&5 +$as_echo_n "checking if $MANIFEST_TOOL is a manifest tool... " >&6; } +if ${lt_cv_path_mainfest_tool+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_path_mainfest_tool=no + echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&5 + $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out + cat conftest.err >&5 + if $GREP 'Manifest Tool' conftest.out > /dev/null; then + lt_cv_path_mainfest_tool=yes + fi + rm -f conftest* +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_mainfest_tool" >&5 +$as_echo "$lt_cv_path_mainfest_tool" >&6; } +if test "x$lt_cv_path_mainfest_tool" != xyes; then + MANIFEST_TOOL=: +fi + + + + + + + case $host_os in + rhapsody* | darwin*) + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}dsymutil", so it can be a program name with args. +set dummy ${ac_tool_prefix}dsymutil; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_DSYMUTIL+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$DSYMUTIL"; then + ac_cv_prog_DSYMUTIL="$DSYMUTIL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_DSYMUTIL="${ac_tool_prefix}dsymutil" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +DSYMUTIL=$ac_cv_prog_DSYMUTIL +if test -n "$DSYMUTIL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DSYMUTIL" >&5 +$as_echo "$DSYMUTIL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_DSYMUTIL"; then + ac_ct_DSYMUTIL=$DSYMUTIL + # Extract the first word of "dsymutil", so it can be a program name with args. +set dummy dsymutil; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_DSYMUTIL+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_DSYMUTIL"; then + ac_cv_prog_ac_ct_DSYMUTIL="$ac_ct_DSYMUTIL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_DSYMUTIL="dsymutil" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_DSYMUTIL=$ac_cv_prog_ac_ct_DSYMUTIL +if test -n "$ac_ct_DSYMUTIL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DSYMUTIL" >&5 +$as_echo "$ac_ct_DSYMUTIL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_DSYMUTIL" = x; then + DSYMUTIL=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + DSYMUTIL=$ac_ct_DSYMUTIL + fi +else + DSYMUTIL="$ac_cv_prog_DSYMUTIL" +fi + + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}nmedit", so it can be a program name with args. +set dummy ${ac_tool_prefix}nmedit; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_NMEDIT+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$NMEDIT"; then + ac_cv_prog_NMEDIT="$NMEDIT" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_NMEDIT="${ac_tool_prefix}nmedit" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +NMEDIT=$ac_cv_prog_NMEDIT +if test -n "$NMEDIT"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $NMEDIT" >&5 +$as_echo "$NMEDIT" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_NMEDIT"; then + ac_ct_NMEDIT=$NMEDIT + # Extract the first word of "nmedit", so it can be a program name with args. +set dummy nmedit; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_NMEDIT+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_NMEDIT"; then + ac_cv_prog_ac_ct_NMEDIT="$ac_ct_NMEDIT" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_NMEDIT="nmedit" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_NMEDIT=$ac_cv_prog_ac_ct_NMEDIT +if test -n "$ac_ct_NMEDIT"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_NMEDIT" >&5 +$as_echo "$ac_ct_NMEDIT" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_NMEDIT" = x; then + NMEDIT=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + NMEDIT=$ac_ct_NMEDIT + fi +else + NMEDIT="$ac_cv_prog_NMEDIT" +fi + + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}lipo", so it can be a program name with args. +set dummy ${ac_tool_prefix}lipo; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_LIPO+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$LIPO"; then + ac_cv_prog_LIPO="$LIPO" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_LIPO="${ac_tool_prefix}lipo" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +LIPO=$ac_cv_prog_LIPO +if test -n "$LIPO"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIPO" >&5 +$as_echo "$LIPO" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_LIPO"; then + ac_ct_LIPO=$LIPO + # Extract the first word of "lipo", so it can be a program name with args. +set dummy lipo; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_LIPO+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_LIPO"; then + ac_cv_prog_ac_ct_LIPO="$ac_ct_LIPO" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_LIPO="lipo" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_LIPO=$ac_cv_prog_ac_ct_LIPO +if test -n "$ac_ct_LIPO"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_LIPO" >&5 +$as_echo "$ac_ct_LIPO" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_LIPO" = x; then + LIPO=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + LIPO=$ac_ct_LIPO + fi +else + LIPO="$ac_cv_prog_LIPO" +fi + + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}otool", so it can be a program name with args. +set dummy ${ac_tool_prefix}otool; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_OTOOL+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$OTOOL"; then + ac_cv_prog_OTOOL="$OTOOL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_OTOOL="${ac_tool_prefix}otool" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +OTOOL=$ac_cv_prog_OTOOL +if test -n "$OTOOL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL" >&5 +$as_echo "$OTOOL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_OTOOL"; then + ac_ct_OTOOL=$OTOOL + # Extract the first word of "otool", so it can be a program name with args. +set dummy otool; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_OTOOL+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_OTOOL"; then + ac_cv_prog_ac_ct_OTOOL="$ac_ct_OTOOL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_OTOOL="otool" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_OTOOL=$ac_cv_prog_ac_ct_OTOOL +if test -n "$ac_ct_OTOOL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL" >&5 +$as_echo "$ac_ct_OTOOL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_OTOOL" = x; then + OTOOL=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + OTOOL=$ac_ct_OTOOL + fi +else + OTOOL="$ac_cv_prog_OTOOL" +fi + + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}otool64", so it can be a program name with args. +set dummy ${ac_tool_prefix}otool64; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_OTOOL64+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$OTOOL64"; then + ac_cv_prog_OTOOL64="$OTOOL64" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_OTOOL64="${ac_tool_prefix}otool64" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +OTOOL64=$ac_cv_prog_OTOOL64 +if test -n "$OTOOL64"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL64" >&5 +$as_echo "$OTOOL64" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_OTOOL64"; then + ac_ct_OTOOL64=$OTOOL64 + # Extract the first word of "otool64", so it can be a program name with args. +set dummy otool64; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_OTOOL64+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_OTOOL64"; then + ac_cv_prog_ac_ct_OTOOL64="$ac_ct_OTOOL64" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_OTOOL64="otool64" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_OTOOL64=$ac_cv_prog_ac_ct_OTOOL64 +if test -n "$ac_ct_OTOOL64"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL64" >&5 +$as_echo "$ac_ct_OTOOL64" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_OTOOL64" = x; then + OTOOL64=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + OTOOL64=$ac_ct_OTOOL64 + fi +else + OTOOL64="$ac_cv_prog_OTOOL64" +fi + + + + + + + + + + + + + + + + + + + + + + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -single_module linker flag" >&5 +$as_echo_n "checking for -single_module linker flag... " >&6; } +if ${lt_cv_apple_cc_single_mod+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_apple_cc_single_mod=no + if test -z "${LT_MULTI_MODULE}"; then + # By default we will add the -single_module flag. You can override + # by either setting the environment variable LT_MULTI_MODULE + # non-empty at configure time, or by adding -multi_module to the + # link flags. + rm -rf libconftest.dylib* + echo "int foo(void){return 1;}" > conftest.c + echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ +-dynamiclib -Wl,-single_module conftest.c" >&5 + $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ + -dynamiclib -Wl,-single_module conftest.c 2>conftest.err + _lt_result=$? + # If there is a non-empty error log, and "single_module" + # appears in it, assume the flag caused a linker warning + if test -s conftest.err && $GREP single_module conftest.err; then + cat conftest.err >&5 + # Otherwise, if the output was created with a 0 exit code from + # the compiler, it worked. + elif test -f libconftest.dylib && test $_lt_result -eq 0; then + lt_cv_apple_cc_single_mod=yes + else + cat conftest.err >&5 + fi + rm -rf libconftest.dylib* + rm -f conftest.* + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_apple_cc_single_mod" >&5 +$as_echo "$lt_cv_apple_cc_single_mod" >&6; } + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -exported_symbols_list linker flag" >&5 +$as_echo_n "checking for -exported_symbols_list linker flag... " >&6; } +if ${lt_cv_ld_exported_symbols_list+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_ld_exported_symbols_list=no + save_LDFLAGS=$LDFLAGS + echo "_main" > conftest.sym + LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + lt_cv_ld_exported_symbols_list=yes +else + lt_cv_ld_exported_symbols_list=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LDFLAGS="$save_LDFLAGS" + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_exported_symbols_list" >&5 +$as_echo "$lt_cv_ld_exported_symbols_list" >&6; } + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -force_load linker flag" >&5 +$as_echo_n "checking for -force_load linker flag... " >&6; } +if ${lt_cv_ld_force_load+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_ld_force_load=no + cat > conftest.c << _LT_EOF +int forced_loaded() { return 2;} +_LT_EOF + echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&5 + $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&5 + echo "$AR cru libconftest.a conftest.o" >&5 + $AR cru libconftest.a conftest.o 2>&5 + echo "$RANLIB libconftest.a" >&5 + $RANLIB libconftest.a 2>&5 + cat > conftest.c << _LT_EOF +int main() { return 0;} +_LT_EOF + echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&5 + $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err + _lt_result=$? + if test -s conftest.err && $GREP force_load conftest.err; then + cat conftest.err >&5 + elif test -f conftest && test $_lt_result -eq 0 && $GREP forced_load conftest >/dev/null 2>&1 ; then + lt_cv_ld_force_load=yes + else + cat conftest.err >&5 + fi + rm -f conftest.err libconftest.a conftest conftest.c + rm -rf conftest.dSYM + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_force_load" >&5 +$as_echo "$lt_cv_ld_force_load" >&6; } + case $host_os in + rhapsody* | darwin1.[012]) + _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;; + darwin1.*) + _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; + darwin*) # darwin 5.x on + # if running on 10.5 or later, the deployment target defaults + # to the OS version, if on x86, and 10.4, the deployment + # target defaults to 10.4. Don't you love it? + case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in + 10.0,*86*-darwin8*|10.0,*-darwin[91]*) + _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; + 10.[012]*) + _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; + 10.*) + _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; + esac + ;; + esac + if test "$lt_cv_apple_cc_single_mod" = "yes"; then + _lt_dar_single_mod='$single_module' + fi + if test "$lt_cv_ld_exported_symbols_list" = "yes"; then + _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym' + else + _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}' + fi + if test "$DSYMUTIL" != ":" && test "$lt_cv_ld_force_load" = "no"; then + _lt_dsymutil='~$DSYMUTIL $lib || :' + else + _lt_dsymutil= + fi + ;; + esac + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 +$as_echo_n "checking how to run the C preprocessor... " >&6; } +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then + if ${ac_cv_prog_CPP+:} false; then : + $as_echo_n "(cached) " >&6 +else + # Double quotes because CPP needs to be expanded + for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" + do + ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.i conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.i conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + break +fi + + done + ac_cv_prog_CPP=$CPP + +fi + CPP=$ac_cv_prog_CPP +else + ac_cv_prog_CPP=$CPP +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 +$as_echo "$CPP" >&6; } +ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.i conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.i conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details" "$LINENO" 5; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 +$as_echo_n "checking for ANSI C header files... " >&6; } +if ${ac_cv_header_stdc+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#include +#include + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_header_stdc=yes +else + ac_cv_header_stdc=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "memchr" >/dev/null 2>&1; then : + +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "free" >/dev/null 2>&1; then : + +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. + if test "$cross_compiling" = yes; then : + : +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#if ((' ' & 0x0FF) == 0x020) +# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#else +# define ISLOWER(c) \ + (('a' <= (c) && (c) <= 'i') \ + || ('j' <= (c) && (c) <= 'r') \ + || ('s' <= (c) && (c) <= 'z')) +# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) +#endif + +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int +main () +{ + int i; + for (i = 0; i < 256; i++) + if (XOR (islower (i), ISLOWER (i)) + || toupper (i) != TOUPPER (i)) + return 2; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + +else + ac_cv_header_stdc=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 +$as_echo "$ac_cv_header_stdc" >&6; } +if test $ac_cv_header_stdc = yes; then + +$as_echo "#define STDC_HEADERS 1" >>confdefs.h + +fi + +# On IRIX 5.3, sys/types and inttypes.h are conflicting. +for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ + inttypes.h stdint.h unistd.h +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default +" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + +for ac_header in dlfcn.h +do : + ac_fn_c_check_header_compile "$LINENO" "dlfcn.h" "ac_cv_header_dlfcn_h" "$ac_includes_default +" +if test "x$ac_cv_header_dlfcn_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_DLFCN_H 1 +_ACEOF + +fi + +done + + + + +func_stripname_cnf () +{ + case ${2} in + .*) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;; + *) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%${2}\$%%"`;; + esac +} # func_stripname_cnf + + + + + +# Set options + + + + enable_dlopen=no + + + + # Check whether --enable-shared was given. +if test "${enable_shared+set}" = set; then : + enableval=$enable_shared; p=${PACKAGE-default} + case $enableval in + yes) enable_shared=yes ;; + no) enable_shared=no ;; + *) + enable_shared=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_shared=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac +else + enable_shared=yes +fi + + + + + + + + + + # Check whether --enable-static was given. +if test "${enable_static+set}" = set; then : + enableval=$enable_static; p=${PACKAGE-default} + case $enableval in + yes) enable_static=yes ;; + no) enable_static=no ;; + *) + enable_static=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_static=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac +else + enable_static=yes +fi + + + + + + + + + + +# Check whether --with-pic was given. +if test "${with_pic+set}" = set; then : + withval=$with_pic; lt_p=${PACKAGE-default} + case $withval in + yes|no) pic_mode=$withval ;; + *) + pic_mode=default + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for lt_pkg in $withval; do + IFS="$lt_save_ifs" + if test "X$lt_pkg" = "X$lt_p"; then + pic_mode=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac +else + pic_mode=default +fi + + +test -z "$pic_mode" && pic_mode=default + + + + + + + + # Check whether --enable-fast-install was given. +if test "${enable_fast_install+set}" = set; then : + enableval=$enable_fast_install; p=${PACKAGE-default} + case $enableval in + yes) enable_fast_install=yes ;; + no) enable_fast_install=no ;; + *) + enable_fast_install=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_fast_install=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac +else + enable_fast_install=yes +fi + + + + + + + + + + + +# This can be used to rebuild libtool when needed +LIBTOOL_DEPS="$ltmain" + +# Always use our own libtool. +LIBTOOL='$(SHELL) $(top_builddir)/libtool' + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +test -z "$LN_S" && LN_S="ln -s" + + + + + + + + + + + + + + +if test -n "${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for objdir" >&5 +$as_echo_n "checking for objdir... " >&6; } +if ${lt_cv_objdir+:} false; then : + $as_echo_n "(cached) " >&6 +else + rm -f .libs 2>/dev/null +mkdir .libs 2>/dev/null +if test -d .libs; then + lt_cv_objdir=.libs +else + # MS-DOS does not allow filenames that begin with a dot. + lt_cv_objdir=_libs +fi +rmdir .libs 2>/dev/null +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_objdir" >&5 +$as_echo "$lt_cv_objdir" >&6; } +objdir=$lt_cv_objdir + + + + + +cat >>confdefs.h <<_ACEOF +#define LT_OBJDIR "$lt_cv_objdir/" +_ACEOF + + + + +case $host_os in +aix3*) + # AIX sometimes has problems with the GCC collect2 program. For some + # reason, if we set the COLLECT_NAMES environment variable, the problems + # vanish in a puff of smoke. + if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES + fi + ;; +esac + +# Global variables: +ofile=libtool +can_build_shared=yes + +# All known linkers require a `.a' archive for static linking (except MSVC, +# which needs '.lib'). +libext=a + +with_gnu_ld="$lt_cv_prog_gnu_ld" + +old_CC="$CC" +old_CFLAGS="$CFLAGS" + +# Set sane defaults for various variables +test -z "$CC" && CC=cc +test -z "$LTCC" && LTCC=$CC +test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS +test -z "$LD" && LD=ld +test -z "$ac_objext" && ac_objext=o + +for cc_temp in $compiler""; do + case $cc_temp in + compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; + distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; + \-*) ;; + *) break;; + esac +done +cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` + + +# Only perform the check for file, if the check method requires it +test -z "$MAGIC_CMD" && MAGIC_CMD=file +case $deplibs_check_method in +file_magic*) + if test "$file_magic_cmd" = '$MAGIC_CMD'; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${ac_tool_prefix}file" >&5 +$as_echo_n "checking for ${ac_tool_prefix}file... " >&6; } +if ${lt_cv_path_MAGIC_CMD+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $MAGIC_CMD in +[\\/*] | ?:[\\/]*) + lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. + ;; +*) + lt_save_MAGIC_CMD="$MAGIC_CMD" + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" + for ac_dir in $ac_dummy; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/${ac_tool_prefix}file; then + lt_cv_path_MAGIC_CMD="$ac_dir/${ac_tool_prefix}file" + if test -n "$file_magic_test_file"; then + case $deplibs_check_method in + "file_magic "*) + file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` + MAGIC_CMD="$lt_cv_path_MAGIC_CMD" + if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | + $EGREP "$file_magic_regex" > /dev/null; then + : + else + cat <<_LT_EOF 1>&2 + +*** Warning: the command libtool uses to detect shared libraries, +*** $file_magic_cmd, produces output that libtool cannot recognize. +*** The result is that libtool may fail to recognize shared libraries +*** as such. This will affect the creation of libtool libraries that +*** depend on shared libraries, but programs linked with such libtool +*** libraries will work regardless of this problem. Nevertheless, you +*** may want to report the problem to your system manager and/or to +*** bug-libtool@gnu.org + +_LT_EOF + fi ;; + esac + fi + break + fi + done + IFS="$lt_save_ifs" + MAGIC_CMD="$lt_save_MAGIC_CMD" + ;; +esac +fi + +MAGIC_CMD="$lt_cv_path_MAGIC_CMD" +if test -n "$MAGIC_CMD"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 +$as_echo "$MAGIC_CMD" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + + + +if test -z "$lt_cv_path_MAGIC_CMD"; then + if test -n "$ac_tool_prefix"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for file" >&5 +$as_echo_n "checking for file... " >&6; } +if ${lt_cv_path_MAGIC_CMD+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $MAGIC_CMD in +[\\/*] | ?:[\\/]*) + lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. + ;; +*) + lt_save_MAGIC_CMD="$MAGIC_CMD" + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" + for ac_dir in $ac_dummy; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/file; then + lt_cv_path_MAGIC_CMD="$ac_dir/file" + if test -n "$file_magic_test_file"; then + case $deplibs_check_method in + "file_magic "*) + file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` + MAGIC_CMD="$lt_cv_path_MAGIC_CMD" + if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | + $EGREP "$file_magic_regex" > /dev/null; then + : + else + cat <<_LT_EOF 1>&2 + +*** Warning: the command libtool uses to detect shared libraries, +*** $file_magic_cmd, produces output that libtool cannot recognize. +*** The result is that libtool may fail to recognize shared libraries +*** as such. This will affect the creation of libtool libraries that +*** depend on shared libraries, but programs linked with such libtool +*** libraries will work regardless of this problem. Nevertheless, you +*** may want to report the problem to your system manager and/or to +*** bug-libtool@gnu.org + +_LT_EOF + fi ;; + esac + fi + break + fi + done + IFS="$lt_save_ifs" + MAGIC_CMD="$lt_save_MAGIC_CMD" + ;; +esac +fi + +MAGIC_CMD="$lt_cv_path_MAGIC_CMD" +if test -n "$MAGIC_CMD"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 +$as_echo "$MAGIC_CMD" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + else + MAGIC_CMD=: + fi +fi + + fi + ;; +esac + +# Use C for the default configuration in the libtool script + +lt_save_CC="$CC" +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +# Source file extension for C test sources. +ac_ext=c + +# Object file extension for compiled C test sources. +objext=o +objext=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="int some_variable = 0;" + +# Code to be used in simple link tests +lt_simple_link_test_code='int main(){return(0);}' + + + + + + + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# If no C compiler flags were specified, use CFLAGS. +LTCFLAGS=${LTCFLAGS-"$CFLAGS"} + +# Allow CC to be a program name with arguments. +compiler=$CC + +# Save the default compiler, since it gets overwritten when the other +# tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP. +compiler_DEFAULT=$CC + +# save warnings/boilerplate of simple test code +ac_outfile=conftest.$ac_objext +echo "$lt_simple_compile_test_code" >conftest.$ac_ext +eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_compiler_boilerplate=`cat conftest.err` +$RM conftest* + +ac_outfile=conftest.$ac_objext +echo "$lt_simple_link_test_code" >conftest.$ac_ext +eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_linker_boilerplate=`cat conftest.err` +$RM -r conftest* + + +if test -n "$compiler"; then + +lt_prog_compiler_no_builtin_flag= + +if test "$GCC" = yes; then + case $cc_basename in + nvcc*) + lt_prog_compiler_no_builtin_flag=' -Xcompiler -fno-builtin' ;; + *) + lt_prog_compiler_no_builtin_flag=' -fno-builtin' ;; + esac + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -fno-rtti -fno-exceptions" >&5 +$as_echo_n "checking if $compiler supports -fno-rtti -fno-exceptions... " >&6; } +if ${lt_cv_prog_compiler_rtti_exceptions+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_rtti_exceptions=no + ac_outfile=conftest.$ac_objext + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="-fno-rtti -fno-exceptions" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings other than the usual output. + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler_rtti_exceptions=yes + fi + fi + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_rtti_exceptions" >&5 +$as_echo "$lt_cv_prog_compiler_rtti_exceptions" >&6; } + +if test x"$lt_cv_prog_compiler_rtti_exceptions" = xyes; then + lt_prog_compiler_no_builtin_flag="$lt_prog_compiler_no_builtin_flag -fno-rtti -fno-exceptions" +else + : +fi + +fi + + + + + + + lt_prog_compiler_wl= +lt_prog_compiler_pic= +lt_prog_compiler_static= + + + if test "$GCC" = yes; then + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_static='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static='-Bstatic' + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + lt_prog_compiler_pic='-fPIC' + ;; + m68k) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + lt_prog_compiler_pic='-m68020 -resident32 -malways-restore-a4' + ;; + esac + ;; + + beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + + mingw* | cygwin* | pw32* | os2* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + # Although the cygwin gcc ignores -fPIC, still need this for old-style + # (--disable-auto-import) libraries + lt_prog_compiler_pic='-DDLL_EXPORT' + ;; + + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + lt_prog_compiler_pic='-fno-common' + ;; + + haiku*) + # PIC is the default for Haiku. + # The "-static" flag exists, but is broken. + lt_prog_compiler_static= + ;; + + hpux*) + # PIC is the default for 64-bit PA HP-UX, but not for 32-bit + # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag + # sets the default TLS model and affects inlining. + case $host_cpu in + hppa*64*) + # +Z the default + ;; + *) + lt_prog_compiler_pic='-fPIC' + ;; + esac + ;; + + interix[3-9]*) + # Interix 3.x gcc -fpic/-fPIC options generate broken code. + # Instead, we relocate shared libraries at runtime. + ;; + + msdosdjgpp*) + # Just because we use GCC doesn't mean we suddenly get shared libraries + # on systems that don't support them. + lt_prog_compiler_can_build_shared=no + enable_shared=no + ;; + + *nto* | *qnx*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + lt_prog_compiler_pic='-fPIC -shared' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + lt_prog_compiler_pic=-Kconform_pic + fi + ;; + + *) + lt_prog_compiler_pic='-fPIC' + ;; + esac + + case $cc_basename in + nvcc*) # Cuda Compiler Driver 2.2 + lt_prog_compiler_wl='-Xlinker ' + if test -n "$lt_prog_compiler_pic"; then + lt_prog_compiler_pic="-Xcompiler $lt_prog_compiler_pic" + fi + ;; + esac + else + # PORTME Check for flag to pass linker flags through the system compiler. + case $host_os in + aix*) + lt_prog_compiler_wl='-Wl,' + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static='-Bstatic' + else + lt_prog_compiler_static='-bnso -bI:/lib/syscalls.exp' + fi + ;; + + mingw* | cygwin* | pw32* | os2* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + lt_prog_compiler_pic='-DDLL_EXPORT' + ;; + + hpux9* | hpux10* | hpux11*) + lt_prog_compiler_wl='-Wl,' + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + lt_prog_compiler_pic='+Z' + ;; + esac + # Is there a better lt_prog_compiler_static that works with the bundled CC? + lt_prog_compiler_static='${wl}-a ${wl}archive' + ;; + + irix5* | irix6* | nonstopux*) + lt_prog_compiler_wl='-Wl,' + # PIC (with -KPIC) is the default. + lt_prog_compiler_static='-non_shared' + ;; + + linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) + case $cc_basename in + # old Intel for x86_64 which still supported -KPIC. + ecc*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-static' + ;; + # icc used to be incompatible with GCC. + # ICC 10 doesn't accept -KPIC any more. + icc* | ifort*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-fPIC' + lt_prog_compiler_static='-static' + ;; + # Lahey Fortran 8.1. + lf95*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='--shared' + lt_prog_compiler_static='--static' + ;; + nagfor*) + # NAG Fortran compiler + lt_prog_compiler_wl='-Wl,-Wl,,' + lt_prog_compiler_pic='-PIC' + lt_prog_compiler_static='-Bstatic' + ;; + pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*) + # Portland Group compilers (*not* the Pentium gcc compiler, + # which looks to be a dead project) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-fpic' + lt_prog_compiler_static='-Bstatic' + ;; + ccc*) + lt_prog_compiler_wl='-Wl,' + # All Alpha code is PIC. + lt_prog_compiler_static='-non_shared' + ;; + xl* | bgxl* | bgf* | mpixl*) + # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-qpic' + lt_prog_compiler_static='-qstaticlink' + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [1-7].* | *Sun*Fortran*\ 8.[0-3]*) + # Sun Fortran 8.3 passes all unrecognized flags to the linker + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + lt_prog_compiler_wl='' + ;; + *Sun\ F* | *Sun*Fortran*) + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + lt_prog_compiler_wl='-Qoption ld ' + ;; + *Sun\ C*) + # Sun C 5.9 + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + lt_prog_compiler_wl='-Wl,' + ;; + *Intel*\ [CF]*Compiler*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-fPIC' + lt_prog_compiler_static='-static' + ;; + *Portland\ Group*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-fpic' + lt_prog_compiler_static='-Bstatic' + ;; + esac + ;; + esac + ;; + + newsos6) + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + ;; + + *nto* | *qnx*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + lt_prog_compiler_pic='-fPIC -shared' + ;; + + osf3* | osf4* | osf5*) + lt_prog_compiler_wl='-Wl,' + # All OSF/1 code is PIC. + lt_prog_compiler_static='-non_shared' + ;; + + rdos*) + lt_prog_compiler_static='-non_shared' + ;; + + solaris*) + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + case $cc_basename in + f77* | f90* | f95* | sunf77* | sunf90* | sunf95*) + lt_prog_compiler_wl='-Qoption ld ';; + *) + lt_prog_compiler_wl='-Wl,';; + esac + ;; + + sunos4*) + lt_prog_compiler_wl='-Qoption ld ' + lt_prog_compiler_pic='-PIC' + lt_prog_compiler_static='-Bstatic' + ;; + + sysv4 | sysv4.2uw2* | sysv4.3*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + ;; + + sysv4*MP*) + if test -d /usr/nec ;then + lt_prog_compiler_pic='-Kconform_pic' + lt_prog_compiler_static='-Bstatic' + fi + ;; + + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + ;; + + unicos*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_can_build_shared=no + ;; + + uts4*) + lt_prog_compiler_pic='-pic' + lt_prog_compiler_static='-Bstatic' + ;; + + *) + lt_prog_compiler_can_build_shared=no + ;; + esac + fi + +case $host_os in + # For platforms which do not support PIC, -DPIC is meaningless: + *djgpp*) + lt_prog_compiler_pic= + ;; + *) + lt_prog_compiler_pic="$lt_prog_compiler_pic -DPIC" + ;; +esac + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5 +$as_echo_n "checking for $compiler option to produce PIC... " >&6; } +if ${lt_cv_prog_compiler_pic+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_pic=$lt_prog_compiler_pic +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic" >&5 +$as_echo "$lt_cv_prog_compiler_pic" >&6; } +lt_prog_compiler_pic=$lt_cv_prog_compiler_pic + +# +# Check to make sure the PIC flag actually works. +# +if test -n "$lt_prog_compiler_pic"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic works" >&5 +$as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic works... " >&6; } +if ${lt_cv_prog_compiler_pic_works+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_pic_works=no + ac_outfile=conftest.$ac_objext + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="$lt_prog_compiler_pic -DPIC" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings other than the usual output. + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler_pic_works=yes + fi + fi + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works" >&5 +$as_echo "$lt_cv_prog_compiler_pic_works" >&6; } + +if test x"$lt_cv_prog_compiler_pic_works" = xyes; then + case $lt_prog_compiler_pic in + "" | " "*) ;; + *) lt_prog_compiler_pic=" $lt_prog_compiler_pic" ;; + esac +else + lt_prog_compiler_pic= + lt_prog_compiler_can_build_shared=no +fi + +fi + + + + + + + + + + + +# +# Check to make sure the static flag actually works. +# +wl=$lt_prog_compiler_wl eval lt_tmp_static_flag=\"$lt_prog_compiler_static\" +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5 +$as_echo_n "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; } +if ${lt_cv_prog_compiler_static_works+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_static_works=no + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS $lt_tmp_static_flag" + echo "$lt_simple_link_test_code" > conftest.$ac_ext + if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then + # The linker can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + # Append any errors to the config.log. + cat conftest.err 1>&5 + $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler_static_works=yes + fi + else + lt_cv_prog_compiler_static_works=yes + fi + fi + $RM -r conftest* + LDFLAGS="$save_LDFLAGS" + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works" >&5 +$as_echo "$lt_cv_prog_compiler_static_works" >&6; } + +if test x"$lt_cv_prog_compiler_static_works" = xyes; then + : +else + lt_prog_compiler_static= +fi + + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 +$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } +if ${lt_cv_prog_compiler_c_o+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_c_o=no + $RM -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp + $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 + if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then + lt_cv_prog_compiler_c_o=yes + fi + fi + chmod u+w . 2>&5 + $RM conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files + $RM out/* && rmdir out + cd .. + $RM -r conftest + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 +$as_echo "$lt_cv_prog_compiler_c_o" >&6; } + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 +$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } +if ${lt_cv_prog_compiler_c_o+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_c_o=no + $RM -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp + $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 + if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then + lt_cv_prog_compiler_c_o=yes + fi + fi + chmod u+w . 2>&5 + $RM conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files + $RM out/* && rmdir out + cd .. + $RM -r conftest + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 +$as_echo "$lt_cv_prog_compiler_c_o" >&6; } + + + + +hard_links="nottested" +if test "$lt_cv_prog_compiler_c_o" = no && test "$need_locks" != no; then + # do not overwrite the value of need_locks provided by the user + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5 +$as_echo_n "checking if we can lock with hard links... " >&6; } + hard_links=yes + $RM conftest* + ln conftest.a conftest.b 2>/dev/null && hard_links=no + touch conftest.a + ln conftest.a conftest.b 2>&5 || hard_links=no + ln conftest.a conftest.b 2>/dev/null && hard_links=no + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5 +$as_echo "$hard_links" >&6; } + if test "$hard_links" = no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5 +$as_echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;} + need_locks=warn + fi +else + need_locks=no +fi + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5 +$as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; } + + runpath_var= + allow_undefined_flag= + always_export_symbols=no + archive_cmds= + archive_expsym_cmds= + compiler_needs_object=no + enable_shared_with_static_runtimes=no + export_dynamic_flag_spec= + export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + hardcode_automatic=no + hardcode_direct=no + hardcode_direct_absolute=no + hardcode_libdir_flag_spec= + hardcode_libdir_separator= + hardcode_minus_L=no + hardcode_shlibpath_var=unsupported + inherit_rpath=no + link_all_deplibs=unknown + module_cmds= + module_expsym_cmds= + old_archive_from_new_cmds= + old_archive_from_expsyms_cmds= + thread_safe_flag_spec= + whole_archive_flag_spec= + # include_expsyms should be a list of space-separated symbols to be *always* + # included in the symbol list + include_expsyms= + # exclude_expsyms can be an extended regexp of symbols to exclude + # it will be wrapped by ` (' and `)$', so one must not match beginning or + # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', + # as well as any symbol that contains `d'. + exclude_expsyms='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*' + # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out + # platforms (ab)use it in PIC code, but their linkers get confused if + # the symbol is explicitly referenced. Since portable code cannot + # rely on this symbol name, it's probably fine to never include it in + # preloaded symbol tables. + # Exclude shared library initialization/finalization symbols. + extract_expsyms_cmds= + + case $host_os in + cygwin* | mingw* | pw32* | cegcc*) + # FIXME: the MSVC++ port hasn't been tested in a loooong time + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + if test "$GCC" != yes; then + with_gnu_ld=no + fi + ;; + interix*) + # we just hope/assume this is gcc and not c89 (= MSVC++) + with_gnu_ld=yes + ;; + openbsd*) + with_gnu_ld=no + ;; + linux* | k*bsd*-gnu | gnu*) + link_all_deplibs=no + ;; + esac + + ld_shlibs=yes + + # On some targets, GNU ld is compatible enough with the native linker + # that we're better off using the native interface for both. + lt_use_gnu_ld_interface=no + if test "$with_gnu_ld" = yes; then + case $host_os in + aix*) + # The AIX port of GNU ld has always aspired to compatibility + # with the native linker. However, as the warning in the GNU ld + # block says, versions before 2.19.5* couldn't really create working + # shared libraries, regardless of the interface used. + case `$LD -v 2>&1` in + *\ \(GNU\ Binutils\)\ 2.19.5*) ;; + *\ \(GNU\ Binutils\)\ 2.[2-9]*) ;; + *\ \(GNU\ Binutils\)\ [3-9]*) ;; + *) + lt_use_gnu_ld_interface=yes + ;; + esac + ;; + *) + lt_use_gnu_ld_interface=yes + ;; + esac + fi + + if test "$lt_use_gnu_ld_interface" = yes; then + # If archive_cmds runs LD, not CC, wlarc should be empty + wlarc='${wl}' + + # Set some defaults for GNU ld with shared library support. These + # are reset later if shared libraries are not supported. Putting them + # here allows them to be overridden if necessary. + runpath_var=LD_RUN_PATH + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + export_dynamic_flag_spec='${wl}--export-dynamic' + # ancient GNU ld didn't support --whole-archive et. al. + if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then + whole_archive_flag_spec="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + whole_archive_flag_spec= + fi + supports_anon_versioning=no + case `$LD -v 2>&1` in + *GNU\ gold*) supports_anon_versioning=yes ;; + *\ [01].* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11 + *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... + *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... + *\ 2.11.*) ;; # other 2.11 versions + *) supports_anon_versioning=yes ;; + esac + + # See if GNU ld supports shared libraries. + case $host_os in + aix[3-9]*) + # On AIX/PPC, the GNU linker is very broken + if test "$host_cpu" != ia64; then + ld_shlibs=no + cat <<_LT_EOF 1>&2 + +*** Warning: the GNU linker, at least up to release 2.19, is reported +*** to be unable to reliably create shared libraries on AIX. +*** Therefore, libtool is disabling shared libraries support. If you +*** really care for shared libraries, you may want to install binutils +*** 2.20 or above, or modify your PATH so that a non-GNU linker is found. +*** You will then need to restart the configuration process. + +_LT_EOF + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='' + ;; + m68k) + archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + ;; + esac + ;; + + beos*) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + allow_undefined_flag=unsupported + # Joseph Beckenbach says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + archive_cmds='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + else + ld_shlibs=no + fi + ;; + + cygwin* | mingw* | pw32* | cegcc*) + # _LT_TAGVAR(hardcode_libdir_flag_spec, ) is actually meaningless, + # as there is no search path for DLLs. + hardcode_libdir_flag_spec='-L$libdir' + export_dynamic_flag_spec='${wl}--export-all-symbols' + allow_undefined_flag=unsupported + always_export_symbols=no + enable_shared_with_static_runtimes=yes + export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/;s/^.*[ ]__nm__\([^ ]*\)[ ][^ ]*/\1 DATA/;/^I[ ]/d;/^[AITW][ ]/s/.* //'\'' | sort | uniq > $export_symbols' + exclude_expsyms='[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname' + + if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is; otherwise, prepend... + archive_expsym_cmds='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + else + ld_shlibs=no + fi + ;; + + haiku*) + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + link_all_deplibs=yes + ;; + + interix[3-9]*) + hardcode_direct=no + hardcode_shlibpath_var=no + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + export_dynamic_flag_spec='${wl}-E' + # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. + # Instead, shared libraries are loaded at an image base (0x10000000 by + # default) and relocated if they conflict, which is a slow very memory + # consuming and fragmenting process. To avoid this, we pick a random, + # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link + # time. Moving up from 0x10000000 also allows more sbrk(2) space. + archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + archive_expsym_cmds='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + ;; + + gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu) + tmp_diet=no + if test "$host_os" = linux-dietlibc; then + case $cc_basename in + diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn) + esac + fi + if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \ + && test "$tmp_diet" = no + then + tmp_addflag=' $pic_flag' + tmp_sharedflag='-shared' + case $cc_basename,$host_cpu in + pgcc*) # Portland Group C compiler + whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_addflag=' $pic_flag' + ;; + pgf77* | pgf90* | pgf95* | pgfortran*) + # Portland Group f77 and f90 compilers + whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_addflag=' $pic_flag -Mnomain' ;; + ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 + tmp_addflag=' -i_dynamic' ;; + efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 + tmp_addflag=' -i_dynamic -nofor_main' ;; + ifc* | ifort*) # Intel Fortran compiler + tmp_addflag=' -nofor_main' ;; + lf95*) # Lahey Fortran 8.1 + whole_archive_flag_spec= + tmp_sharedflag='--shared' ;; + xl[cC]* | bgxl[cC]* | mpixl[cC]*) # IBM XL C 8.0 on PPC (deal with xlf below) + tmp_sharedflag='-qmkshrobj' + tmp_addflag= ;; + nvcc*) # Cuda Compiler Driver 2.2 + whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + compiler_needs_object=yes + ;; + esac + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) # Sun C 5.9 + whole_archive_flag_spec='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + compiler_needs_object=yes + tmp_sharedflag='-G' ;; + *Sun\ F*) # Sun Fortran 8.3 + tmp_sharedflag='-G' ;; + esac + archive_cmds='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + + if test "x$supports_anon_versioning" = xyes; then + archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' + fi + + case $cc_basename in + xlf* | bgf* | bgxlf* | mpixlf*) + # IBM XL Fortran 10.1 on PPC cannot create shared libs itself + whole_archive_flag_spec='--whole-archive$convenience --no-whole-archive' + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + archive_cmds='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib' + if test "x$supports_anon_versioning" = xyes; then + archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib' + fi + ;; + esac + else + ld_shlibs=no + fi + ;; + + netbsd* | netbsdelf*-gnu) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' + wlarc= + else + archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + fi + ;; + + solaris*) + if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then + ld_shlibs=no + cat <<_LT_EOF 1>&2 + +*** Warning: The releases 2.8.* of the GNU linker cannot reliably +*** create shared libraries on Solaris systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.9.1 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +_LT_EOF + elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + ld_shlibs=no + fi + ;; + + sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) + case `$LD -v 2>&1` in + *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*) + ld_shlibs=no + cat <<_LT_EOF 1>&2 + +*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not +*** reliably create shared libraries on SCO systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.16.91.0.3 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +_LT_EOF + ;; + *) + # For security reasons, it is highly recommended that you always + # use absolute paths for naming shared libraries, and exclude the + # DT_RUNPATH tag from executables and libraries. But doing so + # requires that you compile everything twice, which is a pain. + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + ld_shlibs=no + fi + ;; + esac + ;; + + sunos4*) + archive_cmds='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' + wlarc= + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + *) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + ld_shlibs=no + fi + ;; + esac + + if test "$ld_shlibs" = no; then + runpath_var= + hardcode_libdir_flag_spec= + export_dynamic_flag_spec= + whole_archive_flag_spec= + fi + else + # PORTME fill in a description of your system's linker (not GNU ld) + case $host_os in + aix3*) + allow_undefined_flag=unsupported + always_export_symbols=yes + archive_expsym_cmds='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' + # Note: this linker hardcodes the directories in LIBPATH if there + # are no directories specified by -L. + hardcode_minus_L=yes + if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then + # Neither direct hardcoding nor static linking is supported with a + # broken collect2. + hardcode_direct=unsupported + fi + ;; + + aix[4-9]*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to AIX nm, but means don't demangle with GNU nm + # Also, AIX nm treats weak defined symbols like other global + # defined symbols, whereas GNU nm marks them as "W". + if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then + export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + else + export_symbols_cmds='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + fi + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*) + for ld_flag in $LDFLAGS; do + if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then + aix_use_runtimelinking=yes + break + fi + done + ;; + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + archive_cmds='' + hardcode_direct=yes + hardcode_direct_absolute=yes + hardcode_libdir_separator=':' + link_all_deplibs=yes + file_list_spec='${wl}-f,' + + if test "$GCC" = yes; then + case $host_os in aix4.[012]|aix4.[012].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && + strings "$collect2name" | $GREP resolve_lib_name >/dev/null + then + # We have reworked collect2 + : + else + # We have old collect2 + hardcode_direct=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + hardcode_minus_L=yes + hardcode_libdir_flag_spec='-L$libdir' + hardcode_libdir_separator= + fi + ;; + esac + shared_flag='-shared' + if test "$aix_use_runtimelinking" = yes; then + shared_flag="$shared_flag "'${wl}-G' + fi + link_all_deplibs=no + else + # not using gcc + if test "$host_cpu" = ia64; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='${wl}-G' + else + shared_flag='${wl}-bM:SRE' + fi + fi + fi + + export_dynamic_flag_spec='${wl}-bexpall' + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to export. + always_export_symbols=yes + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + allow_undefined_flag='-berok' + # Determine the default libpath from the value encoded in an + # empty executable. + if test "${lt_cv_aix_libpath+set}" = set; then + aix_libpath=$lt_cv_aix_libpath +else + if ${lt_cv_aix_libpath_+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + + lt_aix_libpath_sed=' + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\([^ ]*\) *$/\1/ + p + } + }' + lt_cv_aix_libpath_=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` + # Check for a 64-bit object if we didn't find anything. + if test -z "$lt_cv_aix_libpath_"; then + lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` + fi +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + if test -z "$lt_cv_aix_libpath_"; then + lt_cv_aix_libpath_="/usr/lib:/lib" + fi + +fi + + aix_libpath=$lt_cv_aix_libpath_ +fi + + hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" + archive_expsym_cmds='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib' + allow_undefined_flag="-z nodefs" + archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an + # empty executable. + if test "${lt_cv_aix_libpath+set}" = set; then + aix_libpath=$lt_cv_aix_libpath +else + if ${lt_cv_aix_libpath_+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + + lt_aix_libpath_sed=' + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\([^ ]*\) *$/\1/ + p + } + }' + lt_cv_aix_libpath_=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` + # Check for a 64-bit object if we didn't find anything. + if test -z "$lt_cv_aix_libpath_"; then + lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` + fi +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + if test -z "$lt_cv_aix_libpath_"; then + lt_cv_aix_libpath_="/usr/lib:/lib" + fi + +fi + + aix_libpath=$lt_cv_aix_libpath_ +fi + + hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + no_undefined_flag=' ${wl}-bernotok' + allow_undefined_flag=' ${wl}-berok' + if test "$with_gnu_ld" = yes; then + # We only use this code for GNU lds that support --whole-archive. + whole_archive_flag_spec='${wl}--whole-archive$convenience ${wl}--no-whole-archive' + else + # Exported symbols can be pulled into shared objects from archives + whole_archive_flag_spec='$convenience' + fi + archive_cmds_need_lc=yes + # This is similar to how AIX traditionally builds its shared libraries. + archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + fi + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='' + ;; + m68k) + archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + ;; + esac + ;; + + bsdi[45]*) + export_dynamic_flag_spec=-rdynamic + ;; + + cygwin* | mingw* | pw32* | cegcc*) + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + case $cc_basename in + cl*) + # Native MSVC + hardcode_libdir_flag_spec=' ' + allow_undefined_flag=unsupported + always_export_symbols=yes + file_list_spec='@' + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=".dll" + # FIXME: Setting linknames here is a bad hack. + archive_cmds='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames=' + archive_expsym_cmds='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + sed -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp; + else + sed -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp; + fi~ + $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ + linknames=' + # The linker will not automatically build a static lib if we build a DLL. + # _LT_TAGVAR(old_archive_from_new_cmds, )='true' + enable_shared_with_static_runtimes=yes + exclude_expsyms='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' + export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1,DATA/'\'' | $SED -e '\''/^[AITW][ ]/s/.*[ ]//'\'' | sort | uniq > $export_symbols' + # Don't use ranlib + old_postinstall_cmds='chmod 644 $oldlib' + postlink_cmds='lt_outputfile="@OUTPUT@"~ + lt_tool_outputfile="@TOOL_OUTPUT@"~ + case $lt_outputfile in + *.exe|*.EXE) ;; + *) + lt_outputfile="$lt_outputfile.exe" + lt_tool_outputfile="$lt_tool_outputfile.exe" + ;; + esac~ + if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then + $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; + $RM "$lt_outputfile.manifest"; + fi' + ;; + *) + # Assume MSVC wrapper + hardcode_libdir_flag_spec=' ' + allow_undefined_flag=unsupported + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=".dll" + # FIXME: Setting linknames here is a bad hack. + archive_cmds='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames=' + # The linker will automatically build a .lib file if we build a DLL. + old_archive_from_new_cmds='true' + # FIXME: Should let the user specify the lib program. + old_archive_cmds='lib -OUT:$oldlib$oldobjs$old_deplibs' + enable_shared_with_static_runtimes=yes + ;; + esac + ;; + + darwin* | rhapsody*) + + + archive_cmds_need_lc=no + hardcode_direct=no + hardcode_automatic=yes + hardcode_shlibpath_var=unsupported + if test "$lt_cv_ld_force_load" = "yes"; then + whole_archive_flag_spec='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`' + + else + whole_archive_flag_spec='' + fi + link_all_deplibs=yes + allow_undefined_flag="$_lt_dar_allow_undefined" + case $cc_basename in + ifort*) _lt_dar_can_shared=yes ;; + *) _lt_dar_can_shared=$GCC ;; + esac + if test "$_lt_dar_can_shared" = "yes"; then + output_verbose_link_cmd=func_echo_all + archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" + module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" + archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" + module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" + + else + ld_shlibs=no + fi + + ;; + + dgux*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_shlibpath_var=no + ;; + + # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor + # support. Future versions do this automatically, but an explicit c++rt0.o + # does not break anything, and helps significantly (at the cost of a little + # extra space). + freebsd2.2*) + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + # Unfortunately, older versions of FreeBSD 2 do not have this feature. + freebsd2.*) + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=yes + hardcode_minus_L=yes + hardcode_shlibpath_var=no + ;; + + # FreeBSD 3 and greater uses gcc -shared to do shared libraries. + freebsd* | dragonfly*) + archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + hpux9*) + if test "$GCC" = yes; then + archive_cmds='$RM $output_objdir/$soname~$CC -shared $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + else + archive_cmds='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + fi + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_separator=: + hardcode_direct=yes + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + export_dynamic_flag_spec='${wl}-E' + ;; + + hpux10*) + if test "$GCC" = yes && test "$with_gnu_ld" = no; then + archive_cmds='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' + fi + if test "$with_gnu_ld" = no; then + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_separator=: + hardcode_direct=yes + hardcode_direct_absolute=yes + export_dynamic_flag_spec='${wl}-E' + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + fi + ;; + + hpux11*) + if test "$GCC" = yes && test "$with_gnu_ld" = no; then + case $host_cpu in + hppa*64*) + archive_cmds='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + archive_cmds='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + archive_cmds='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + else + case $host_cpu in + hppa*64*) + archive_cmds='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + + # Older versions of the 11.00 compiler do not understand -b yet + # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does) + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC understands -b" >&5 +$as_echo_n "checking if $CC understands -b... " >&6; } +if ${lt_cv_prog_compiler__b+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler__b=no + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS -b" + echo "$lt_simple_link_test_code" > conftest.$ac_ext + if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then + # The linker can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + # Append any errors to the config.log. + cat conftest.err 1>&5 + $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler__b=yes + fi + else + lt_cv_prog_compiler__b=yes + fi + fi + $RM -r conftest* + LDFLAGS="$save_LDFLAGS" + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler__b" >&5 +$as_echo "$lt_cv_prog_compiler__b" >&6; } + +if test x"$lt_cv_prog_compiler__b" = xyes; then + archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' +else + archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' +fi + + ;; + esac + fi + if test "$with_gnu_ld" = no; then + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_separator=: + + case $host_cpu in + hppa*64*|ia64*) + hardcode_direct=no + hardcode_shlibpath_var=no + ;; + *) + hardcode_direct=yes + hardcode_direct_absolute=yes + export_dynamic_flag_spec='${wl}-E' + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + ;; + esac + fi + ;; + + irix5* | irix6* | nonstopux*) + if test "$GCC" = yes; then + archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + # Try to use the -exported_symbol ld option, if it does not + # work, assume that -exports_file does not work either and + # implicitly export all symbols. + # This should be the same for all languages, so no per-tag cache variable. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $host_os linker accepts -exported_symbol" >&5 +$as_echo_n "checking whether the $host_os linker accepts -exported_symbol... " >&6; } +if ${lt_cv_irix_exported_symbol+:} false; then : + $as_echo_n "(cached) " >&6 +else + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +int foo (void) { return 0; } +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + lt_cv_irix_exported_symbol=yes +else + lt_cv_irix_exported_symbol=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LDFLAGS="$save_LDFLAGS" +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_irix_exported_symbol" >&5 +$as_echo "$lt_cv_irix_exported_symbol" >&6; } + if test "$lt_cv_irix_exported_symbol" = yes; then + archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib' + fi + else + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib' + fi + archive_cmds_need_lc='no' + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + inherit_rpath=yes + link_all_deplibs=yes + ;; + + netbsd* | netbsdelf*-gnu) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out + else + archive_cmds='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF + fi + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + newsos6) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=yes + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + hardcode_shlibpath_var=no + ;; + + *nto* | *qnx*) + ;; + + openbsd*) + if test -f /usr/libexec/ld.so; then + hardcode_direct=yes + hardcode_shlibpath_var=no + hardcode_direct_absolute=yes + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols' + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + export_dynamic_flag_spec='${wl}-E' + else + case $host_os in + openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*) + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec='-R$libdir' + ;; + *) + archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + ;; + esac + fi + else + ld_shlibs=no + fi + ;; + + os2*) + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + allow_undefined_flag=unsupported + archive_cmds='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~echo DATA >> $output_objdir/$libname.def~echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' + old_archive_from_new_cmds='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' + ;; + + osf3*) + if test "$GCC" = yes; then + allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + allow_undefined_flag=' -expect_unresolved \*' + archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' + fi + archive_cmds_need_lc='no' + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + ;; + + osf4* | osf5*) # as osf3* with the addition of -msym flag + if test "$GCC" = yes; then + allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds='$CC -shared${allow_undefined_flag} $pic_flag $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + else + allow_undefined_flag=' -expect_unresolved \*' + archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' + archive_expsym_cmds='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~ + $CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp' + + # Both c and cxx compiler support -rpath directly + hardcode_libdir_flag_spec='-rpath $libdir' + fi + archive_cmds_need_lc='no' + hardcode_libdir_separator=: + ;; + + solaris*) + no_undefined_flag=' -z defs' + if test "$GCC" = yes; then + wlarc='${wl}' + archive_cmds='$CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' + else + case `$CC -V 2>&1` in + *"Compilers 5.0"*) + wlarc='' + archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' + archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp' + ;; + *) + wlarc='${wl}' + archive_cmds='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' + ;; + esac + fi + hardcode_libdir_flag_spec='-R$libdir' + hardcode_shlibpath_var=no + case $host_os in + solaris2.[0-5] | solaris2.[0-5].*) ;; + *) + # The compiler driver will combine and reorder linker options, + # but understands `-z linker_flag'. GCC discards it without `$wl', + # but is careful enough not to reorder. + # Supported since Solaris 2.6 (maybe 2.5.1?) + if test "$GCC" = yes; then + whole_archive_flag_spec='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' + else + whole_archive_flag_spec='-z allextract$convenience -z defaultextract' + fi + ;; + esac + link_all_deplibs=yes + ;; + + sunos4*) + if test "x$host_vendor" = xsequent; then + # Use $CC to link under sequent, because it throws in some extra .o + # files that make .init and .fini sections work. + archive_cmds='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' + fi + hardcode_libdir_flag_spec='-L$libdir' + hardcode_direct=yes + hardcode_minus_L=yes + hardcode_shlibpath_var=no + ;; + + sysv4) + case $host_vendor in + sni) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=yes # is this really true??? + ;; + siemens) + ## LD is ld it makes a PLAMLIB + ## CC just makes a GrossModule. + archive_cmds='$LD -G -o $lib $libobjs $deplibs $linker_flags' + reload_cmds='$CC -r -o $output$reload_objs' + hardcode_direct=no + ;; + motorola) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=no #Motorola manual says yes, but my tests say they lie + ;; + esac + runpath_var='LD_RUN_PATH' + hardcode_shlibpath_var=no + ;; + + sysv4.3*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_shlibpath_var=no + export_dynamic_flag_spec='-Bexport' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_shlibpath_var=no + runpath_var=LD_RUN_PATH + hardcode_runpath_var=yes + ld_shlibs=yes + fi + ;; + + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*) + no_undefined_flag='${wl}-z,text' + archive_cmds_need_lc=no + hardcode_shlibpath_var=no + runpath_var='LD_RUN_PATH' + + if test "$GCC" = yes; then + archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + sysv5* | sco3.2v5* | sco5v6*) + # Note: We can NOT use -z defs as we might desire, because we do not + # link with -lc, and that would cause any symbols used from libc to + # always be unresolved, which means just about no library would + # ever link correctly. If we're not using GNU ld we use -z text + # though, which does catch some bad symbols but isn't as heavy-handed + # as -z defs. + no_undefined_flag='${wl}-z,text' + allow_undefined_flag='${wl}-z,nodefs' + archive_cmds_need_lc=no + hardcode_shlibpath_var=no + hardcode_libdir_flag_spec='${wl}-R,$libdir' + hardcode_libdir_separator=':' + link_all_deplibs=yes + export_dynamic_flag_spec='${wl}-Bexport' + runpath_var='LD_RUN_PATH' + + if test "$GCC" = yes; then + archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + uts4*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_shlibpath_var=no + ;; + + *) + ld_shlibs=no + ;; + esac + + if test x$host_vendor = xsni; then + case $host in + sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) + export_dynamic_flag_spec='${wl}-Blargedynsym' + ;; + esac + fi + fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs" >&5 +$as_echo "$ld_shlibs" >&6; } +test "$ld_shlibs" = no && can_build_shared=no + +with_gnu_ld=$with_gnu_ld + + + + + + + + + + + + + + + +# +# Do we need to explicitly link libc? +# +case "x$archive_cmds_need_lc" in +x|xyes) + # Assume -lc should be added + archive_cmds_need_lc=yes + + if test "$enable_shared" = yes && test "$GCC" = yes; then + case $archive_cmds in + *'~'*) + # FIXME: we may have to deal with multi-command sequences. + ;; + '$CC '*) + # Test whether the compiler implicitly links with -lc since on some + # systems, -lgcc has to come before -lc. If gcc already passes -lc + # to ld, don't add -lc before -lgcc. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5 +$as_echo_n "checking whether -lc should be explicitly linked in... " >&6; } +if ${lt_cv_archive_cmds_need_lc+:} false; then : + $as_echo_n "(cached) " >&6 +else + $RM conftest* + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } 2>conftest.err; then + soname=conftest + lib=conftest + libobjs=conftest.$ac_objext + deplibs= + wl=$lt_prog_compiler_wl + pic_flag=$lt_prog_compiler_pic + compiler_flags=-v + linker_flags=-v + verstring= + output_objdir=. + libname=conftest + lt_save_allow_undefined_flag=$allow_undefined_flag + allow_undefined_flag= + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5 + (eval $archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + then + lt_cv_archive_cmds_need_lc=no + else + lt_cv_archive_cmds_need_lc=yes + fi + allow_undefined_flag=$lt_save_allow_undefined_flag + else + cat conftest.err 1>&5 + fi + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_archive_cmds_need_lc" >&5 +$as_echo "$lt_cv_archive_cmds_need_lc" >&6; } + archive_cmds_need_lc=$lt_cv_archive_cmds_need_lc + ;; + esac + fi + ;; +esac + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5 +$as_echo_n "checking dynamic linker characteristics... " >&6; } + +if test "$GCC" = yes; then + case $host_os in + darwin*) lt_awk_arg="/^libraries:/,/LR/" ;; + *) lt_awk_arg="/^libraries:/" ;; + esac + case $host_os in + mingw* | cegcc*) lt_sed_strip_eq="s,=\([A-Za-z]:\),\1,g" ;; + *) lt_sed_strip_eq="s,=/,/,g" ;; + esac + lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq` + case $lt_search_path_spec in + *\;*) + # if the path contains ";" then we assume it to be the separator + # otherwise default to the standard path separator (i.e. ":") - it is + # assumed that no part of a normal pathname contains ";" but that should + # okay in the real world where ";" in dirpaths is itself problematic. + lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'` + ;; + *) + lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"` + ;; + esac + # Ok, now we have the path, separated by spaces, we can step through it + # and add multilib dir if necessary. + lt_tmp_lt_search_path_spec= + lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null` + for lt_sys_path in $lt_search_path_spec; do + if test -d "$lt_sys_path/$lt_multi_os_dir"; then + lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir" + else + test -d "$lt_sys_path" && \ + lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path" + fi + done + lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk ' +BEGIN {RS=" "; FS="/|\n";} { + lt_foo=""; + lt_count=0; + for (lt_i = NF; lt_i > 0; lt_i--) { + if ($lt_i != "" && $lt_i != ".") { + if ($lt_i == "..") { + lt_count++; + } else { + if (lt_count == 0) { + lt_foo="/" $lt_i lt_foo; + } else { + lt_count--; + } + } + } + } + if (lt_foo != "") { lt_freq[lt_foo]++; } + if (lt_freq[lt_foo] == 1) { print lt_foo; } +}'` + # AWK program above erroneously prepends '/' to C:/dos/paths + # for these hosts. + case $host_os in + mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\ + $SED 's,/\([A-Za-z]:\),\1,g'` ;; + esac + sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP` +else + sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" +fi +library_names_spec= +libname_spec='lib$name' +soname_spec= +shrext_cmds=".so" +postinstall_cmds= +postuninstall_cmds= +finish_cmds= +finish_eval= +shlibpath_var= +shlibpath_overrides_runpath=unknown +version_type=none +dynamic_linker="$host_os ld.so" +sys_lib_dlsearch_path_spec="/lib /usr/lib" +need_lib_prefix=unknown +hardcode_into_libs=no + +# when you set need_version to no, make sure it does not cause -set_version +# flags to be left without arguments +need_version=unknown + +case $host_os in +aix3*) + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' + shlibpath_var=LIBPATH + + # AIX 3 has no versioning support, so we append a major version to the name. + soname_spec='${libname}${release}${shared_ext}$major' + ;; + +aix[4-9]*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + hardcode_into_libs=yes + if test "$host_cpu" = ia64; then + # AIX 5 supports IA64 + library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + else + # With GCC up to 2.95.x, collect2 would create an import file + # for dependence libraries. The import file would start with + # the line `#! .'. This would cause the generated library to + # depend on `.', always an invalid library. This was fixed in + # development snapshots of GCC prior to 3.0. + case $host_os in + aix4 | aix4.[01] | aix4.[01].*) + if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' + echo ' yes ' + echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then + : + else + can_build_shared=no + fi + ;; + esac + # AIX (on Power*) has no versioning support, so currently we can not hardcode correct + # soname into executable. Probably we can add versioning support to + # collect2, so additional links can be useful in future. + if test "$aix_use_runtimelinking" = yes; then + # If using run time linking (on AIX 4.2 or later) use lib.so + # instead of lib.a to let people know that these are not + # typical AIX shared libraries. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + else + # We preserve .a as extension for shared libraries through AIX4.2 + # and later when we are not doing run time linking. + library_names_spec='${libname}${release}.a $libname.a' + soname_spec='${libname}${release}${shared_ext}$major' + fi + shlibpath_var=LIBPATH + fi + ;; + +amigaos*) + case $host_cpu in + powerpc) + # Since July 2007 AmigaOS4 officially supports .so libraries. + # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + ;; + m68k) + library_names_spec='$libname.ixlibrary $libname.a' + # Create ${libname}_ixlibrary.a entries in /sys/libs. + finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' + ;; + esac + ;; + +beos*) + library_names_spec='${libname}${shared_ext}' + dynamic_linker="$host_os ld.so" + shlibpath_var=LIBRARY_PATH + ;; + +bsdi[45]*) + version_type=linux # correct to gnu/linux during the next big refactor + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" + sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" + # the default ld.so.conf also contains /usr/contrib/lib and + # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow + # libtool to hard-code these into programs + ;; + +cygwin* | mingw* | pw32* | cegcc*) + version_type=windows + shrext_cmds=".dll" + need_version=no + need_lib_prefix=no + + case $GCC,$cc_basename in + yes,*) + # gcc + library_names_spec='$libname.dll.a' + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \${file}`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname~ + chmod a+x \$dldir/$dlname~ + if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then + eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; + fi' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $RM \$dlpath' + shlibpath_overrides_runpath=yes + + case $host_os in + cygwin*) + # Cygwin DLLs use 'cyg' prefix rather than 'lib' + soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + + sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api" + ;; + mingw* | cegcc*) + # MinGW DLLs use traditional 'lib' prefix + soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + ;; + pw32*) + # pw32 DLLs use 'pw' prefix rather than 'lib' + library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + ;; + esac + dynamic_linker='Win32 ld.exe' + ;; + + *,cl*) + # Native MSVC + libname_spec='$name' + soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + library_names_spec='${libname}.dll.lib' + + case $build_os in + mingw*) + sys_lib_search_path_spec= + lt_save_ifs=$IFS + IFS=';' + for lt_path in $LIB + do + IFS=$lt_save_ifs + # Let DOS variable expansion print the short 8.3 style file name. + lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"` + sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path" + done + IFS=$lt_save_ifs + # Convert to MSYS style. + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([a-zA-Z]\\):| /\\1|g' -e 's|^ ||'` + ;; + cygwin*) + # Convert to unix form, then to dos form, then back to unix form + # but this time dos style (no spaces!) so that the unix form looks + # like /cygdrive/c/PROGRA~1:/cygdr... + sys_lib_search_path_spec=`cygpath --path --unix "$LIB"` + sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null` + sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + ;; + *) + sys_lib_search_path_spec="$LIB" + if $ECHO "$sys_lib_search_path_spec" | $GREP ';[c-zC-Z]:/' >/dev/null; then + # It is most probably a Windows format PATH. + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` + else + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi + # FIXME: find the short name or the path components, as spaces are + # common. (e.g. "Program Files" -> "PROGRA~1") + ;; + esac + + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \${file}`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $RM \$dlpath' + shlibpath_overrides_runpath=yes + dynamic_linker='Win32 link.exe' + ;; + + *) + # Assume MSVC wrapper + library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib' + dynamic_linker='Win32 ld.exe' + ;; + esac + # FIXME: first we should search . and the directory the executable is in + shlibpath_var=PATH + ;; + +darwin* | rhapsody*) + dynamic_linker="$host_os dyld" + version_type=darwin + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext' + soname_spec='${libname}${release}${major}$shared_ext' + shlibpath_overrides_runpath=yes + shlibpath_var=DYLD_LIBRARY_PATH + shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' + + sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib" + sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' + ;; + +dgux*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +freebsd* | dragonfly*) + # DragonFly does not have aout. When/if they implement a new + # versioning mechanism, adjust this. + if test -x /usr/bin/objformat; then + objformat=`/usr/bin/objformat` + else + case $host_os in + freebsd[23].*) objformat=aout ;; + *) objformat=elf ;; + esac + fi + version_type=freebsd-$objformat + case $version_type in + freebsd-elf*) + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + need_version=no + need_lib_prefix=no + ;; + freebsd-*) + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' + need_version=yes + ;; + esac + shlibpath_var=LD_LIBRARY_PATH + case $host_os in + freebsd2.*) + shlibpath_overrides_runpath=yes + ;; + freebsd3.[01]* | freebsdelf3.[01]*) + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + freebsd3.[2-9]* | freebsdelf3.[2-9]* | \ + freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1) + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + *) # from 4.6 on, and DragonFly + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + esac + ;; + +haiku*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + dynamic_linker="$host_os runtime_loader" + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LIBRARY_PATH + shlibpath_overrides_runpath=yes + sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib' + hardcode_into_libs=yes + ;; + +hpux9* | hpux10* | hpux11*) + # Give a soname corresponding to the major version so that dld.sl refuses to + # link against other versions. + version_type=sunos + need_lib_prefix=no + need_version=no + case $host_cpu in + ia64*) + shrext_cmds='.so' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.so" + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + if test "X$HPUX_IA64_MODE" = X32; then + sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" + else + sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" + fi + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + hppa*64*) + shrext_cmds='.sl' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.sl" + shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + *) + shrext_cmds='.sl' + dynamic_linker="$host_os dld.sl" + shlibpath_var=SHLIB_PATH + shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + ;; + esac + # HP-UX runs *really* slowly unless shared libraries are mode 555, ... + postinstall_cmds='chmod 555 $lib' + # or fails outright, so override atomically: + install_override_mode=555 + ;; + +interix[3-9]*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +irix5* | irix6* | nonstopux*) + case $host_os in + nonstopux*) version_type=nonstopux ;; + *) + if test "$lt_cv_prog_gnu_ld" = yes; then + version_type=linux # correct to gnu/linux during the next big refactor + else + version_type=irix + fi ;; + esac + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' + case $host_os in + irix5* | nonstopux*) + libsuff= shlibsuff= + ;; + *) + case $LD in # libtool.m4 will add one of these switches to LD + *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") + libsuff= shlibsuff= libmagic=32-bit;; + *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") + libsuff=32 shlibsuff=N32 libmagic=N32;; + *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") + libsuff=64 shlibsuff=64 libmagic=64-bit;; + *) libsuff= shlibsuff= libmagic=never-match;; + esac + ;; + esac + shlibpath_var=LD_LIBRARY${shlibsuff}_PATH + shlibpath_overrides_runpath=no + sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" + sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" + hardcode_into_libs=yes + ;; + +# No shared lib support for Linux oldld, aout, or coff. +linux*oldld* | linux*aout* | linux*coff*) + dynamic_linker=no + ;; + +# This must be glibc/ELF. +linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + + # Some binutils ld are patched to set DT_RUNPATH + if ${lt_cv_shlibpath_overrides_runpath+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_shlibpath_overrides_runpath=no + save_LDFLAGS=$LDFLAGS + save_libdir=$libdir + eval "libdir=/foo; wl=\"$lt_prog_compiler_wl\"; \ + LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec\"" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + if ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null; then : + lt_cv_shlibpath_overrides_runpath=yes +fi +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LDFLAGS=$save_LDFLAGS + libdir=$save_libdir + +fi + + shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath + + # This implies no fast_install, which is unacceptable. + # Some rework will be needed to allow for fast_install + # before this can be enabled. + hardcode_into_libs=yes + + # Append ld.so.conf contents to the search path + if test -f /etc/ld.so.conf; then + lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '` + sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" + fi + + # We used to test for /lib/ld.so.1 and disable shared libraries on + # powerpc, because MkLinux only supported shared libraries with the + # GNU dynamic linker. Since this was broken with cross compilers, + # most powerpc-linux boxes support dynamic linking these days and + # people can always --disable-shared, the test was removed, and we + # assume the GNU/Linux dynamic linker is in use. + dynamic_linker='GNU/Linux ld.so' + ;; + +netbsdelf*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='NetBSD ld.elf_so' + ;; + +netbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + dynamic_linker='NetBSD (a.out) ld.so' + else + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='NetBSD ld.elf_so' + fi + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + +newsos6) + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +*nto* | *qnx*) + version_type=qnx + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='ldqnx.so' + ;; + +openbsd*) + version_type=sunos + sys_lib_dlsearch_path_spec="/usr/lib" + need_lib_prefix=no + # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. + case $host_os in + openbsd3.3 | openbsd3.3.*) need_version=yes ;; + *) need_version=no ;; + esac + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + shlibpath_var=LD_LIBRARY_PATH + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + case $host_os in + openbsd2.[89] | openbsd2.[89].*) + shlibpath_overrides_runpath=no + ;; + *) + shlibpath_overrides_runpath=yes + ;; + esac + else + shlibpath_overrides_runpath=yes + fi + ;; + +os2*) + libname_spec='$name' + shrext_cmds=".dll" + need_lib_prefix=no + library_names_spec='$libname${shared_ext} $libname.a' + dynamic_linker='OS/2 ld.exe' + shlibpath_var=LIBPATH + ;; + +osf3* | osf4* | osf5*) + version_type=osf + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" + sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" + ;; + +rdos*) + dynamic_linker=no + ;; + +solaris*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + # ldd complains unless libraries are executable + postinstall_cmds='chmod +x $lib' + ;; + +sunos4*) + version_type=sunos + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + if test "$with_gnu_ld" = yes; then + need_lib_prefix=no + fi + need_version=yes + ;; + +sysv4 | sysv4.3*) + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + case $host_vendor in + sni) + shlibpath_overrides_runpath=no + need_lib_prefix=no + runpath_var=LD_RUN_PATH + ;; + siemens) + need_lib_prefix=no + ;; + motorola) + need_lib_prefix=no + need_version=no + shlibpath_overrides_runpath=no + sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' + ;; + esac + ;; + +sysv4*MP*) + if test -d /usr/nec ;then + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' + soname_spec='$libname${shared_ext}.$major' + shlibpath_var=LD_LIBRARY_PATH + fi + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + version_type=freebsd-elf + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + if test "$with_gnu_ld" = yes; then + sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' + else + sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' + case $host_os in + sco3.2v5*) + sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" + ;; + esac + fi + sys_lib_dlsearch_path_spec='/usr/lib' + ;; + +tpf*) + # TPF is a cross-target only. Preferred cross-host = GNU/Linux. + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +uts4*) + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +*) + dynamic_linker=no + ;; +esac +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5 +$as_echo "$dynamic_linker" >&6; } +test "$dynamic_linker" = no && can_build_shared=no + +variables_saved_for_relink="PATH $shlibpath_var $runpath_var" +if test "$GCC" = yes; then + variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" +fi + +if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then + sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec" +fi +if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then + sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec" +fi + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5 +$as_echo_n "checking how to hardcode library paths into programs... " >&6; } +hardcode_action= +if test -n "$hardcode_libdir_flag_spec" || + test -n "$runpath_var" || + test "X$hardcode_automatic" = "Xyes" ; then + + # We can hardcode non-existent directories. + if test "$hardcode_direct" != no && + # If the only mechanism to avoid hardcoding is shlibpath_var, we + # have to relink, otherwise we might link with an installed library + # when we should be linking with a yet-to-be-installed one + ## test "$_LT_TAGVAR(hardcode_shlibpath_var, )" != no && + test "$hardcode_minus_L" != no; then + # Linking always hardcodes the temporary library directory. + hardcode_action=relink + else + # We can link without hardcoding, and we can hardcode nonexisting dirs. + hardcode_action=immediate + fi +else + # We cannot hardcode anything, or else we can only hardcode existing + # directories. + hardcode_action=unsupported +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action" >&5 +$as_echo "$hardcode_action" >&6; } + +if test "$hardcode_action" = relink || + test "$inherit_rpath" = yes; then + # Fast installation is not supported + enable_fast_install=no +elif test "$shlibpath_overrides_runpath" = yes || + test "$enable_shared" = no; then + # Fast installation is not necessary + enable_fast_install=needless +fi + + + + + + + if test "x$enable_dlopen" != xyes; then + enable_dlopen=unknown + enable_dlopen_self=unknown + enable_dlopen_self_static=unknown +else + lt_cv_dlopen=no + lt_cv_dlopen_libs= + + case $host_os in + beos*) + lt_cv_dlopen="load_add_on" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + ;; + + mingw* | pw32* | cegcc*) + lt_cv_dlopen="LoadLibrary" + lt_cv_dlopen_libs= + ;; + + cygwin*) + lt_cv_dlopen="dlopen" + lt_cv_dlopen_libs= + ;; + + darwin*) + # if libdl is installed we need to link against it + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 +$as_echo_n "checking for dlopen in -ldl... " >&6; } +if ${ac_cv_lib_dl_dlopen+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldl $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dlopen (); +int +main () +{ +return dlopen (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_dl_dlopen=yes +else + ac_cv_lib_dl_dlopen=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 +$as_echo "$ac_cv_lib_dl_dlopen" >&6; } +if test "x$ac_cv_lib_dl_dlopen" = xyes; then : + lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" +else + + lt_cv_dlopen="dyld" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + +fi + + ;; + + *) + ac_fn_c_check_func "$LINENO" "shl_load" "ac_cv_func_shl_load" +if test "x$ac_cv_func_shl_load" = xyes; then : + lt_cv_dlopen="shl_load" +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5 +$as_echo_n "checking for shl_load in -ldld... " >&6; } +if ${ac_cv_lib_dld_shl_load+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldld $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char shl_load (); +int +main () +{ +return shl_load (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_dld_shl_load=yes +else + ac_cv_lib_dld_shl_load=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5 +$as_echo "$ac_cv_lib_dld_shl_load" >&6; } +if test "x$ac_cv_lib_dld_shl_load" = xyes; then : + lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld" +else + ac_fn_c_check_func "$LINENO" "dlopen" "ac_cv_func_dlopen" +if test "x$ac_cv_func_dlopen" = xyes; then : + lt_cv_dlopen="dlopen" +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 +$as_echo_n "checking for dlopen in -ldl... " >&6; } +if ${ac_cv_lib_dl_dlopen+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldl $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dlopen (); +int +main () +{ +return dlopen (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_dl_dlopen=yes +else + ac_cv_lib_dl_dlopen=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 +$as_echo "$ac_cv_lib_dl_dlopen" >&6; } +if test "x$ac_cv_lib_dl_dlopen" = xyes; then : + lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -lsvld" >&5 +$as_echo_n "checking for dlopen in -lsvld... " >&6; } +if ${ac_cv_lib_svld_dlopen+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lsvld $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dlopen (); +int +main () +{ +return dlopen (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_svld_dlopen=yes +else + ac_cv_lib_svld_dlopen=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_svld_dlopen" >&5 +$as_echo "$ac_cv_lib_svld_dlopen" >&6; } +if test "x$ac_cv_lib_svld_dlopen" = xyes; then : + lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld" +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dld_link in -ldld" >&5 +$as_echo_n "checking for dld_link in -ldld... " >&6; } +if ${ac_cv_lib_dld_dld_link+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldld $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dld_link (); +int +main () +{ +return dld_link (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_dld_dld_link=yes +else + ac_cv_lib_dld_dld_link=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_dld_link" >&5 +$as_echo "$ac_cv_lib_dld_dld_link" >&6; } +if test "x$ac_cv_lib_dld_dld_link" = xyes; then : + lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld" +fi + + +fi + + +fi + + +fi + + +fi + + +fi + + ;; + esac + + if test "x$lt_cv_dlopen" != xno; then + enable_dlopen=yes + else + enable_dlopen=no + fi + + case $lt_cv_dlopen in + dlopen) + save_CPPFLAGS="$CPPFLAGS" + test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" + + save_LDFLAGS="$LDFLAGS" + wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" + + save_LIBS="$LIBS" + LIBS="$lt_cv_dlopen_libs $LIBS" + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a program can dlopen itself" >&5 +$as_echo_n "checking whether a program can dlopen itself... " >&6; } +if ${lt_cv_dlopen_self+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test "$cross_compiling" = yes; then : + lt_cv_dlopen_self=cross +else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<_LT_EOF +#line $LINENO "configure" +#include "confdefs.h" + +#if HAVE_DLFCN_H +#include +#endif + +#include + +#ifdef RTLD_GLOBAL +# define LT_DLGLOBAL RTLD_GLOBAL +#else +# ifdef DL_GLOBAL +# define LT_DLGLOBAL DL_GLOBAL +# else +# define LT_DLGLOBAL 0 +# endif +#endif + +/* We may have to define LT_DLLAZY_OR_NOW in the command line if we + find out it does not work in some platform. */ +#ifndef LT_DLLAZY_OR_NOW +# ifdef RTLD_LAZY +# define LT_DLLAZY_OR_NOW RTLD_LAZY +# else +# ifdef DL_LAZY +# define LT_DLLAZY_OR_NOW DL_LAZY +# else +# ifdef RTLD_NOW +# define LT_DLLAZY_OR_NOW RTLD_NOW +# else +# ifdef DL_NOW +# define LT_DLLAZY_OR_NOW DL_NOW +# else +# define LT_DLLAZY_OR_NOW 0 +# endif +# endif +# endif +# endif +#endif + +/* When -fvisbility=hidden is used, assume the code has been annotated + correspondingly for the symbols needed. */ +#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) +int fnord () __attribute__((visibility("default"))); +#endif + +int fnord () { return 42; } +int main () +{ + void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); + int status = $lt_dlunknown; + + if (self) + { + if (dlsym (self,"fnord")) status = $lt_dlno_uscore; + else + { + if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; + else puts (dlerror ()); + } + /* dlclose (self); */ + } + else + puts (dlerror ()); + + return status; +} +_LT_EOF + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 + (eval $ac_link) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then + (./conftest; exit; ) >&5 2>/dev/null + lt_status=$? + case x$lt_status in + x$lt_dlno_uscore) lt_cv_dlopen_self=yes ;; + x$lt_dlneed_uscore) lt_cv_dlopen_self=yes ;; + x$lt_dlunknown|x*) lt_cv_dlopen_self=no ;; + esac + else : + # compilation failed + lt_cv_dlopen_self=no + fi +fi +rm -fr conftest* + + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self" >&5 +$as_echo "$lt_cv_dlopen_self" >&6; } + + if test "x$lt_cv_dlopen_self" = xyes; then + wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a statically linked program can dlopen itself" >&5 +$as_echo_n "checking whether a statically linked program can dlopen itself... " >&6; } +if ${lt_cv_dlopen_self_static+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test "$cross_compiling" = yes; then : + lt_cv_dlopen_self_static=cross +else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<_LT_EOF +#line $LINENO "configure" +#include "confdefs.h" + +#if HAVE_DLFCN_H +#include +#endif + +#include + +#ifdef RTLD_GLOBAL +# define LT_DLGLOBAL RTLD_GLOBAL +#else +# ifdef DL_GLOBAL +# define LT_DLGLOBAL DL_GLOBAL +# else +# define LT_DLGLOBAL 0 +# endif +#endif + +/* We may have to define LT_DLLAZY_OR_NOW in the command line if we + find out it does not work in some platform. */ +#ifndef LT_DLLAZY_OR_NOW +# ifdef RTLD_LAZY +# define LT_DLLAZY_OR_NOW RTLD_LAZY +# else +# ifdef DL_LAZY +# define LT_DLLAZY_OR_NOW DL_LAZY +# else +# ifdef RTLD_NOW +# define LT_DLLAZY_OR_NOW RTLD_NOW +# else +# ifdef DL_NOW +# define LT_DLLAZY_OR_NOW DL_NOW +# else +# define LT_DLLAZY_OR_NOW 0 +# endif +# endif +# endif +# endif +#endif + +/* When -fvisbility=hidden is used, assume the code has been annotated + correspondingly for the symbols needed. */ +#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) +int fnord () __attribute__((visibility("default"))); +#endif + +int fnord () { return 42; } +int main () +{ + void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); + int status = $lt_dlunknown; + + if (self) + { + if (dlsym (self,"fnord")) status = $lt_dlno_uscore; + else + { + if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; + else puts (dlerror ()); + } + /* dlclose (self); */ + } + else + puts (dlerror ()); + + return status; +} +_LT_EOF + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 + (eval $ac_link) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then + (./conftest; exit; ) >&5 2>/dev/null + lt_status=$? + case x$lt_status in + x$lt_dlno_uscore) lt_cv_dlopen_self_static=yes ;; + x$lt_dlneed_uscore) lt_cv_dlopen_self_static=yes ;; + x$lt_dlunknown|x*) lt_cv_dlopen_self_static=no ;; + esac + else : + # compilation failed + lt_cv_dlopen_self_static=no + fi +fi +rm -fr conftest* + + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self_static" >&5 +$as_echo "$lt_cv_dlopen_self_static" >&6; } + fi + + CPPFLAGS="$save_CPPFLAGS" + LDFLAGS="$save_LDFLAGS" + LIBS="$save_LIBS" + ;; + esac + + case $lt_cv_dlopen_self in + yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; + *) enable_dlopen_self=unknown ;; + esac + + case $lt_cv_dlopen_self_static in + yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; + *) enable_dlopen_self_static=unknown ;; + esac +fi + + + + + + + + + + + + + + + + + +striplib= +old_striplib= +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether stripping libraries is possible" >&5 +$as_echo_n "checking whether stripping libraries is possible... " >&6; } +if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then + test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" + test -z "$striplib" && striplib="$STRIP --strip-unneeded" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +else +# FIXME - insert some real tests, host_os isn't really good enough + case $host_os in + darwin*) + if test -n "$STRIP" ; then + striplib="$STRIP -x" + old_striplib="$STRIP -S" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + fi + ;; + *) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + ;; + esac +fi + + + + + + + + + + + + + # Report which library types will actually be built + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if libtool supports shared libraries" >&5 +$as_echo_n "checking if libtool supports shared libraries... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $can_build_shared" >&5 +$as_echo "$can_build_shared" >&6; } + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build shared libraries" >&5 +$as_echo_n "checking whether to build shared libraries... " >&6; } + test "$can_build_shared" = "no" && enable_shared=no + + # On AIX, shared libraries and static libraries use the same namespace, and + # are all built from PIC. + case $host_os in + aix3*) + test "$enable_shared" = yes && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + + aix[4-9]*) + if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then + test "$enable_shared" = yes && enable_static=no + fi + ;; + esac + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_shared" >&5 +$as_echo "$enable_shared" >&6; } + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build static libraries" >&5 +$as_echo_n "checking whether to build static libraries... " >&6; } + # Make sure either enable_shared or enable_static is yes. + test "$enable_shared" = yes || enable_static=yes + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_static" >&5 +$as_echo "$enable_static" >&6; } + + + + +fi +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +CC="$lt_save_CC" + + if test -n "$CXX" && ( test "X$CXX" != "Xno" && + ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) || + (test "X$CXX" != "Xg++"))) ; then + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C++ preprocessor" >&5 +$as_echo_n "checking how to run the C++ preprocessor... " >&6; } +if test -z "$CXXCPP"; then + if ${ac_cv_prog_CXXCPP+:} false; then : + $as_echo_n "(cached) " >&6 +else + # Double quotes because CXXCPP needs to be expanded + for CXXCPP in "$CXX -E" "/lib/cpp" + do + ac_preproc_ok=false +for ac_cxx_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if ac_fn_cxx_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.i conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +_ACEOF +if ac_fn_cxx_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.i conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + break +fi + + done + ac_cv_prog_CXXCPP=$CXXCPP + +fi + CXXCPP=$ac_cv_prog_CXXCPP +else + ac_cv_prog_CXXCPP=$CXXCPP +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXXCPP" >&5 +$as_echo "$CXXCPP" >&6; } +ac_preproc_ok=false +for ac_cxx_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if ac_fn_cxx_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.i conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +_ACEOF +if ac_fn_cxx_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.i conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "C++ preprocessor \"$CXXCPP\" fails sanity check +See \`config.log' for more details" "$LINENO" 5; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +else + _lt_caught_CXX_error=yes +fi + +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + +archive_cmds_need_lc_CXX=no +allow_undefined_flag_CXX= +always_export_symbols_CXX=no +archive_expsym_cmds_CXX= +compiler_needs_object_CXX=no +export_dynamic_flag_spec_CXX= +hardcode_direct_CXX=no +hardcode_direct_absolute_CXX=no +hardcode_libdir_flag_spec_CXX= +hardcode_libdir_separator_CXX= +hardcode_minus_L_CXX=no +hardcode_shlibpath_var_CXX=unsupported +hardcode_automatic_CXX=no +inherit_rpath_CXX=no +module_cmds_CXX= +module_expsym_cmds_CXX= +link_all_deplibs_CXX=unknown +old_archive_cmds_CXX=$old_archive_cmds +reload_flag_CXX=$reload_flag +reload_cmds_CXX=$reload_cmds +no_undefined_flag_CXX= +whole_archive_flag_spec_CXX= +enable_shared_with_static_runtimes_CXX=no + +# Source file extension for C++ test sources. +ac_ext=cpp + +# Object file extension for compiled C++ test sources. +objext=o +objext_CXX=$objext + +# No sense in running all these tests if we already determined that +# the CXX compiler isn't working. Some variables (like enable_shared) +# are currently assumed to apply to all compilers on this platform, +# and will be corrupted by setting them based on a non-working compiler. +if test "$_lt_caught_CXX_error" != yes; then + # Code to be used in simple compile tests + lt_simple_compile_test_code="int some_variable = 0;" + + # Code to be used in simple link tests + lt_simple_link_test_code='int main(int, char *[]) { return(0); }' + + # ltmain only uses $CC for tagged configurations so make sure $CC is set. + + + + + + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# If no C compiler flags were specified, use CFLAGS. +LTCFLAGS=${LTCFLAGS-"$CFLAGS"} + +# Allow CC to be a program name with arguments. +compiler=$CC + + + # save warnings/boilerplate of simple test code + ac_outfile=conftest.$ac_objext +echo "$lt_simple_compile_test_code" >conftest.$ac_ext +eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_compiler_boilerplate=`cat conftest.err` +$RM conftest* + + ac_outfile=conftest.$ac_objext +echo "$lt_simple_link_test_code" >conftest.$ac_ext +eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_linker_boilerplate=`cat conftest.err` +$RM -r conftest* + + + # Allow CC to be a program name with arguments. + lt_save_CC=$CC + lt_save_CFLAGS=$CFLAGS + lt_save_LD=$LD + lt_save_GCC=$GCC + GCC=$GXX + lt_save_with_gnu_ld=$with_gnu_ld + lt_save_path_LD=$lt_cv_path_LD + if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then + lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx + else + $as_unset lt_cv_prog_gnu_ld + fi + if test -n "${lt_cv_path_LDCXX+set}"; then + lt_cv_path_LD=$lt_cv_path_LDCXX + else + $as_unset lt_cv_path_LD + fi + test -z "${LDCXX+set}" || LD=$LDCXX + CC=${CXX-"c++"} + CFLAGS=$CXXFLAGS + compiler=$CC + compiler_CXX=$CC + for cc_temp in $compiler""; do + case $cc_temp in + compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; + distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; + \-*) ;; + *) break;; + esac +done +cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` + + + if test -n "$compiler"; then + # We don't want -fno-exception when compiling C++ code, so set the + # no_builtin_flag separately + if test "$GXX" = yes; then + lt_prog_compiler_no_builtin_flag_CXX=' -fno-builtin' + else + lt_prog_compiler_no_builtin_flag_CXX= + fi + + if test "$GXX" = yes; then + # Set up default GNU C++ configuration + + + +# Check whether --with-gnu-ld was given. +if test "${with_gnu_ld+set}" = set; then : + withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes +else + with_gnu_ld=no +fi + +ac_prog=ld +if test "$GCC" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5 +$as_echo_n "checking for ld used by $CC... " >&6; } + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case $ac_prog in + # Accept absolute paths. + [\\/]* | ?:[\\/]*) + re_direlt='/[^/][^/]*/\.\./' + # Canonicalize the pathname of ld + ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` + while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do + ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` + done + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5 +$as_echo_n "checking for GNU ld... " >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5 +$as_echo_n "checking for non-GNU ld... " >&6; } +fi +if ${lt_cv_path_LD+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$LD"; then + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + lt_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some variants of GNU ld only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + case `"$lt_cv_path_LD" -v 2>&1 &5 +$as_echo "$LD" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5 +$as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; } +if ${lt_cv_prog_gnu_ld+:} false; then : + $as_echo_n "(cached) " >&6 +else + # I'd rather use --version here, but apparently some GNU lds only accept -v. +case `$LD -v 2>&1 &5 +$as_echo "$lt_cv_prog_gnu_ld" >&6; } +with_gnu_ld=$lt_cv_prog_gnu_ld + + + + + + + + # Check if GNU C++ uses GNU ld as the underlying linker, since the + # archiving commands below assume that GNU ld is being used. + if test "$with_gnu_ld" = yes; then + archive_cmds_CXX='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds_CXX='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + + hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' + export_dynamic_flag_spec_CXX='${wl}--export-dynamic' + + # If archive_cmds runs LD, not CC, wlarc should be empty + # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to + # investigate it a little bit more. (MM) + wlarc='${wl}' + + # ancient GNU ld didn't support --whole-archive et. al. + if eval "`$CC -print-prog-name=ld` --help 2>&1" | + $GREP 'no-whole-archive' > /dev/null; then + whole_archive_flag_spec_CXX="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + whole_archive_flag_spec_CXX= + fi + else + with_gnu_ld=no + wlarc= + + # A generic and very simple default shared library creation + # command for GNU C++ for the case where it uses the native + # linker, instead of GNU ld. If possible, this setting should + # overridden to take advantage of the native linker features on + # the platform it is being used on. + archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' + fi + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' + + else + GXX=no + with_gnu_ld=no + wlarc= + fi + + # PORTME: fill in a description of your system's C++ link characteristics + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5 +$as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; } + ld_shlibs_CXX=yes + case $host_os in + aix3*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + aix[4-9]*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*) + for ld_flag in $LDFLAGS; do + case $ld_flag in + *-brtl*) + aix_use_runtimelinking=yes + break + ;; + esac + done + ;; + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + archive_cmds_CXX='' + hardcode_direct_CXX=yes + hardcode_direct_absolute_CXX=yes + hardcode_libdir_separator_CXX=':' + link_all_deplibs_CXX=yes + file_list_spec_CXX='${wl}-f,' + + if test "$GXX" = yes; then + case $host_os in aix4.[012]|aix4.[012].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && + strings "$collect2name" | $GREP resolve_lib_name >/dev/null + then + # We have reworked collect2 + : + else + # We have old collect2 + hardcode_direct_CXX=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + hardcode_minus_L_CXX=yes + hardcode_libdir_flag_spec_CXX='-L$libdir' + hardcode_libdir_separator_CXX= + fi + esac + shared_flag='-shared' + if test "$aix_use_runtimelinking" = yes; then + shared_flag="$shared_flag "'${wl}-G' + fi + else + # not using gcc + if test "$host_cpu" = ia64; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='${wl}-G' + else + shared_flag='${wl}-bM:SRE' + fi + fi + fi + + export_dynamic_flag_spec_CXX='${wl}-bexpall' + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to + # export. + always_export_symbols_CXX=yes + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + allow_undefined_flag_CXX='-berok' + # Determine the default libpath from the value encoded in an empty + # executable. + if test "${lt_cv_aix_libpath+set}" = set; then + aix_libpath=$lt_cv_aix_libpath +else + if ${lt_cv_aix_libpath__CXX+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + + lt_aix_libpath_sed=' + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\([^ ]*\) *$/\1/ + p + } + }' + lt_cv_aix_libpath__CXX=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` + # Check for a 64-bit object if we didn't find anything. + if test -z "$lt_cv_aix_libpath__CXX"; then + lt_cv_aix_libpath__CXX=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` + fi +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + if test -z "$lt_cv_aix_libpath__CXX"; then + lt_cv_aix_libpath__CXX="/usr/lib:/lib" + fi + +fi + + aix_libpath=$lt_cv_aix_libpath__CXX +fi + + hardcode_libdir_flag_spec_CXX='${wl}-blibpath:$libdir:'"$aix_libpath" + + archive_expsym_cmds_CXX='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + hardcode_libdir_flag_spec_CXX='${wl}-R $libdir:/usr/lib:/lib' + allow_undefined_flag_CXX="-z nodefs" + archive_expsym_cmds_CXX="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an + # empty executable. + if test "${lt_cv_aix_libpath+set}" = set; then + aix_libpath=$lt_cv_aix_libpath +else + if ${lt_cv_aix_libpath__CXX+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + + lt_aix_libpath_sed=' + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\([^ ]*\) *$/\1/ + p + } + }' + lt_cv_aix_libpath__CXX=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` + # Check for a 64-bit object if we didn't find anything. + if test -z "$lt_cv_aix_libpath__CXX"; then + lt_cv_aix_libpath__CXX=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` + fi +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + if test -z "$lt_cv_aix_libpath__CXX"; then + lt_cv_aix_libpath__CXX="/usr/lib:/lib" + fi + +fi + + aix_libpath=$lt_cv_aix_libpath__CXX +fi + + hardcode_libdir_flag_spec_CXX='${wl}-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + no_undefined_flag_CXX=' ${wl}-bernotok' + allow_undefined_flag_CXX=' ${wl}-berok' + if test "$with_gnu_ld" = yes; then + # We only use this code for GNU lds that support --whole-archive. + whole_archive_flag_spec_CXX='${wl}--whole-archive$convenience ${wl}--no-whole-archive' + else + # Exported symbols can be pulled into shared objects from archives + whole_archive_flag_spec_CXX='$convenience' + fi + archive_cmds_need_lc_CXX=yes + # This is similar to how AIX traditionally builds its shared + # libraries. + archive_expsym_cmds_CXX="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + fi + fi + ;; + + beos*) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + allow_undefined_flag_CXX=unsupported + # Joseph Beckenbach says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + archive_cmds_CXX='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + else + ld_shlibs_CXX=no + fi + ;; + + chorus*) + case $cc_basename in + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + esac + ;; + + cygwin* | mingw* | pw32* | cegcc*) + case $GXX,$cc_basename in + ,cl* | no,cl*) + # Native MSVC + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + hardcode_libdir_flag_spec_CXX=' ' + allow_undefined_flag_CXX=unsupported + always_export_symbols_CXX=yes + file_list_spec_CXX='@' + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=".dll" + # FIXME: Setting linknames here is a bad hack. + archive_cmds_CXX='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames=' + archive_expsym_cmds_CXX='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + $SED -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp; + else + $SED -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp; + fi~ + $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ + linknames=' + # The linker will not automatically build a static lib if we build a DLL. + # _LT_TAGVAR(old_archive_from_new_cmds, CXX)='true' + enable_shared_with_static_runtimes_CXX=yes + # Don't use ranlib + old_postinstall_cmds_CXX='chmod 644 $oldlib' + postlink_cmds_CXX='lt_outputfile="@OUTPUT@"~ + lt_tool_outputfile="@TOOL_OUTPUT@"~ + case $lt_outputfile in + *.exe|*.EXE) ;; + *) + lt_outputfile="$lt_outputfile.exe" + lt_tool_outputfile="$lt_tool_outputfile.exe" + ;; + esac~ + func_to_tool_file "$lt_outputfile"~ + if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then + $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; + $RM "$lt_outputfile.manifest"; + fi' + ;; + *) + # g++ + # _LT_TAGVAR(hardcode_libdir_flag_spec, CXX) is actually meaningless, + # as there is no search path for DLLs. + hardcode_libdir_flag_spec_CXX='-L$libdir' + export_dynamic_flag_spec_CXX='${wl}--export-all-symbols' + allow_undefined_flag_CXX=unsupported + always_export_symbols_CXX=no + enable_shared_with_static_runtimes_CXX=yes + + if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then + archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is; otherwise, prepend... + archive_expsym_cmds_CXX='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + else + ld_shlibs_CXX=no + fi + ;; + esac + ;; + darwin* | rhapsody*) + + + archive_cmds_need_lc_CXX=no + hardcode_direct_CXX=no + hardcode_automatic_CXX=yes + hardcode_shlibpath_var_CXX=unsupported + if test "$lt_cv_ld_force_load" = "yes"; then + whole_archive_flag_spec_CXX='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`' + + else + whole_archive_flag_spec_CXX='' + fi + link_all_deplibs_CXX=yes + allow_undefined_flag_CXX="$_lt_dar_allow_undefined" + case $cc_basename in + ifort*) _lt_dar_can_shared=yes ;; + *) _lt_dar_can_shared=$GCC ;; + esac + if test "$_lt_dar_can_shared" = "yes"; then + output_verbose_link_cmd=func_echo_all + archive_cmds_CXX="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" + module_cmds_CXX="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" + archive_expsym_cmds_CXX="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" + module_expsym_cmds_CXX="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" + if test "$lt_cv_apple_cc_single_mod" != "yes"; then + archive_cmds_CXX="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}" + archive_expsym_cmds_CXX="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dar_export_syms}${_lt_dsymutil}" + fi + + else + ld_shlibs_CXX=no + fi + + ;; + + dgux*) + case $cc_basename in + ec++*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + ghcx*) + # Green Hills C++ Compiler + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + esac + ;; + + freebsd2.*) + # C++ shared libraries reported to be fairly broken before + # switch to ELF + ld_shlibs_CXX=no + ;; + + freebsd-elf*) + archive_cmds_need_lc_CXX=no + ;; + + freebsd* | dragonfly*) + # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF + # conventions + ld_shlibs_CXX=yes + ;; + + haiku*) + archive_cmds_CXX='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + link_all_deplibs_CXX=yes + ;; + + hpux9*) + hardcode_libdir_flag_spec_CXX='${wl}+b ${wl}$libdir' + hardcode_libdir_separator_CXX=: + export_dynamic_flag_spec_CXX='${wl}-E' + hardcode_direct_CXX=yes + hardcode_minus_L_CXX=yes # Not in the search PATH, + # but as the default + # location of the library. + + case $cc_basename in + CC*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + aCC*) + archive_cmds_CXX='$RM $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' + ;; + *) + if test "$GXX" = yes; then + archive_cmds_CXX='$RM $output_objdir/$soname~$CC -shared -nostdlib $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + else + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + fi + ;; + esac + ;; + + hpux10*|hpux11*) + if test $with_gnu_ld = no; then + hardcode_libdir_flag_spec_CXX='${wl}+b ${wl}$libdir' + hardcode_libdir_separator_CXX=: + + case $host_cpu in + hppa*64*|ia64*) + ;; + *) + export_dynamic_flag_spec_CXX='${wl}-E' + ;; + esac + fi + case $host_cpu in + hppa*64*|ia64*) + hardcode_direct_CXX=no + hardcode_shlibpath_var_CXX=no + ;; + *) + hardcode_direct_CXX=yes + hardcode_direct_absolute_CXX=yes + hardcode_minus_L_CXX=yes # Not in the search PATH, + # but as the default + # location of the library. + ;; + esac + + case $cc_basename in + CC*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + aCC*) + case $host_cpu in + hppa*64*) + archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + ia64*) + archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + *) + archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + esac + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' + ;; + *) + if test "$GXX" = yes; then + if test $with_gnu_ld = no; then + case $host_cpu in + hppa*64*) + archive_cmds_CXX='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + ia64*) + archive_cmds_CXX='$CC -shared -nostdlib $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + *) + archive_cmds_CXX='$CC -shared -nostdlib $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + esac + fi + else + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + fi + ;; + esac + ;; + + interix[3-9]*) + hardcode_direct_CXX=no + hardcode_shlibpath_var_CXX=no + hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' + export_dynamic_flag_spec_CXX='${wl}-E' + # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. + # Instead, shared libraries are loaded at an image base (0x10000000 by + # default) and relocated if they conflict, which is a slow very memory + # consuming and fragmenting process. To avoid this, we pick a random, + # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link + # time. Moving up from 0x10000000 also allows more sbrk(2) space. + archive_cmds_CXX='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + archive_expsym_cmds_CXX='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + ;; + irix5* | irix6*) + case $cc_basename in + CC*) + # SGI C++ + archive_cmds_CXX='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' + + # Archives containing C++ object files must be created using + # "CC -ar", where "CC" is the IRIX C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + old_archive_cmds_CXX='$CC -ar -WR,-u -o $oldlib $oldobjs' + ;; + *) + if test "$GXX" = yes; then + if test "$with_gnu_ld" = no; then + archive_cmds_CXX='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + archive_cmds_CXX='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` -o $lib' + fi + fi + link_all_deplibs_CXX=yes + ;; + esac + hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator_CXX=: + inherit_rpath_CXX=yes + ;; + + linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) + case $cc_basename in + KCC*) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + archive_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + archive_expsym_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib' + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' + + hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' + export_dynamic_flag_spec_CXX='${wl}--export-dynamic' + + # Archives containing C++ object files must be created using + # "CC -Bstatic", where "CC" is the KAI C++ compiler. + old_archive_cmds_CXX='$CC -Bstatic -o $oldlib $oldobjs' + ;; + icpc* | ecpc* ) + # Intel C++ + with_gnu_ld=yes + # version 8.0 and above of icpc choke on multiply defined symbols + # if we add $predep_objects and $postdep_objects, however 7.1 and + # earlier do not add the objects themselves. + case `$CC -V 2>&1` in + *"Version 7."*) + archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + ;; + *) # Version 8.0 or newer + tmp_idyn= + case $host_cpu in + ia64*) tmp_idyn=' -i_dynamic';; + esac + archive_cmds_CXX='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds_CXX='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + ;; + esac + archive_cmds_need_lc_CXX=no + hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' + export_dynamic_flag_spec_CXX='${wl}--export-dynamic' + whole_archive_flag_spec_CXX='${wl}--whole-archive$convenience ${wl}--no-whole-archive' + ;; + pgCC* | pgcpp*) + # Portland Group C++ compiler + case `$CC -V` in + *pgCC\ [1-5].* | *pgcpp\ [1-5].*) + prelink_cmds_CXX='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~ + compile_command="$compile_command `find $tpldir -name \*.o | sort | $NL2SP`"' + old_archive_cmds_CXX='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~ + $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | sort | $NL2SP`~ + $RANLIB $oldlib' + archive_cmds_CXX='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ + $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' + archive_expsym_cmds_CXX='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ + $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' + ;; + *) # Version 6 and above use weak symbols + archive_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' + archive_expsym_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' + ;; + esac + + hardcode_libdir_flag_spec_CXX='${wl}--rpath ${wl}$libdir' + export_dynamic_flag_spec_CXX='${wl}--export-dynamic' + whole_archive_flag_spec_CXX='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + ;; + cxx*) + # Compaq C++ + archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib ${wl}-retain-symbols-file $wl$export_symbols' + + runpath_var=LD_RUN_PATH + hardcode_libdir_flag_spec_CXX='-rpath $libdir' + hardcode_libdir_separator_CXX=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "X$list" | $Xsed' + ;; + xl* | mpixl* | bgxl*) + # IBM XL 8.0 on PPC, with GNU ld + hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' + export_dynamic_flag_spec_CXX='${wl}--export-dynamic' + archive_cmds_CXX='$CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + if test "x$supports_anon_versioning" = xyes; then + archive_expsym_cmds_CXX='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' + fi + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C++ 5.9 + no_undefined_flag_CXX=' -zdefs' + archive_cmds_CXX='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + archive_expsym_cmds_CXX='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file ${wl}$export_symbols' + hardcode_libdir_flag_spec_CXX='-R$libdir' + whole_archive_flag_spec_CXX='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + compiler_needs_object_CXX=yes + + # Not sure whether something based on + # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 + # would be better. + output_verbose_link_cmd='func_echo_all' + + # Archives containing C++ object files must be created using + # "CC -xar", where "CC" is the Sun C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + old_archive_cmds_CXX='$CC -xar -o $oldlib $oldobjs' + ;; + esac + ;; + esac + ;; + + lynxos*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + + m88k*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + + mvs*) + case $cc_basename in + cxx*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + esac + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + archive_cmds_CXX='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags' + wlarc= + hardcode_libdir_flag_spec_CXX='-R$libdir' + hardcode_direct_CXX=yes + hardcode_shlibpath_var_CXX=no + fi + # Workaround some broken pre-1.5 toolchains + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"' + ;; + + *nto* | *qnx*) + ld_shlibs_CXX=yes + ;; + + openbsd2*) + # C++ shared libraries are fairly broken + ld_shlibs_CXX=no + ;; + + openbsd*) + if test -f /usr/libexec/ld.so; then + hardcode_direct_CXX=yes + hardcode_shlibpath_var_CXX=no + hardcode_direct_absolute_CXX=yes + archive_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' + hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + archive_expsym_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib' + export_dynamic_flag_spec_CXX='${wl}-E' + whole_archive_flag_spec_CXX="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + fi + output_verbose_link_cmd=func_echo_all + else + ld_shlibs_CXX=no + fi + ;; + + osf3* | osf4* | osf5*) + case $cc_basename in + KCC*) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + archive_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + + hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' + hardcode_libdir_separator_CXX=: + + # Archives containing C++ object files must be created using + # the KAI C++ compiler. + case $host in + osf3*) old_archive_cmds_CXX='$CC -Bstatic -o $oldlib $oldobjs' ;; + *) old_archive_cmds_CXX='$CC -o $oldlib $oldobjs' ;; + esac + ;; + RCC*) + # Rational C++ 2.4.1 + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + cxx*) + case $host in + osf3*) + allow_undefined_flag_CXX=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds_CXX='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && func_echo_all "${wl}-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' + hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' + ;; + *) + allow_undefined_flag_CXX=' -expect_unresolved \*' + archive_cmds_CXX='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' + archive_expsym_cmds_CXX='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~ + echo "-hidden">> $lib.exp~ + $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname ${wl}-input ${wl}$lib.exp `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~ + $RM $lib.exp' + hardcode_libdir_flag_spec_CXX='-rpath $libdir' + ;; + esac + + hardcode_libdir_separator_CXX=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' + ;; + *) + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + allow_undefined_flag_CXX=' ${wl}-expect_unresolved ${wl}\*' + case $host in + osf3*) + archive_cmds_CXX='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + ;; + *) + archive_cmds_CXX='$CC -shared $pic_flag -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + ;; + esac + + hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator_CXX=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' + + else + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + fi + ;; + esac + ;; + + psos*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + + sunos4*) + case $cc_basename in + CC*) + # Sun C++ 4.x + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + lcc*) + # Lucid + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + esac + ;; + + solaris*) + case $cc_basename in + CC* | sunCC*) + # Sun C++ 4.2, 5.x and Centerline C++ + archive_cmds_need_lc_CXX=yes + no_undefined_flag_CXX=' -zdefs' + archive_cmds_CXX='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + archive_expsym_cmds_CXX='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -G${allow_undefined_flag} ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' + + hardcode_libdir_flag_spec_CXX='-R$libdir' + hardcode_shlibpath_var_CXX=no + case $host_os in + solaris2.[0-5] | solaris2.[0-5].*) ;; + *) + # The compiler driver will combine and reorder linker options, + # but understands `-z linker_flag'. + # Supported since Solaris 2.6 (maybe 2.5.1?) + whole_archive_flag_spec_CXX='-z allextract$convenience -z defaultextract' + ;; + esac + link_all_deplibs_CXX=yes + + output_verbose_link_cmd='func_echo_all' + + # Archives containing C++ object files must be created using + # "CC -xar", where "CC" is the Sun C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + old_archive_cmds_CXX='$CC -xar -o $oldlib $oldobjs' + ;; + gcx*) + # Green Hills C++ Compiler + archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + + # The C++ compiler must be used to create the archive. + old_archive_cmds_CXX='$CC $LDFLAGS -archive -o $oldlib $oldobjs' + ;; + *) + # GNU C++ compiler with Solaris linker + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + no_undefined_flag_CXX=' ${wl}-z ${wl}defs' + if $CC --version | $GREP -v '^2\.7' > /dev/null; then + archive_cmds_CXX='$CC -shared $pic_flag -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + archive_expsym_cmds_CXX='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -shared $pic_flag -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' + else + # g++ 2.7 appears to require `-G' NOT `-shared' on this + # platform. + archive_cmds_CXX='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + archive_expsym_cmds_CXX='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' + fi + + hardcode_libdir_flag_spec_CXX='${wl}-R $wl$libdir' + case $host_os in + solaris2.[0-5] | solaris2.[0-5].*) ;; + *) + whole_archive_flag_spec_CXX='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' + ;; + esac + fi + ;; + esac + ;; + + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*) + no_undefined_flag_CXX='${wl}-z,text' + archive_cmds_need_lc_CXX=no + hardcode_shlibpath_var_CXX=no + runpath_var='LD_RUN_PATH' + + case $cc_basename in + CC*) + archive_cmds_CXX='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_CXX='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + archive_cmds_CXX='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_CXX='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + ;; + + sysv5* | sco3.2v5* | sco5v6*) + # Note: We can NOT use -z defs as we might desire, because we do not + # link with -lc, and that would cause any symbols used from libc to + # always be unresolved, which means just about no library would + # ever link correctly. If we're not using GNU ld we use -z text + # though, which does catch some bad symbols but isn't as heavy-handed + # as -z defs. + no_undefined_flag_CXX='${wl}-z,text' + allow_undefined_flag_CXX='${wl}-z,nodefs' + archive_cmds_need_lc_CXX=no + hardcode_shlibpath_var_CXX=no + hardcode_libdir_flag_spec_CXX='${wl}-R,$libdir' + hardcode_libdir_separator_CXX=':' + link_all_deplibs_CXX=yes + export_dynamic_flag_spec_CXX='${wl}-Bexport' + runpath_var='LD_RUN_PATH' + + case $cc_basename in + CC*) + archive_cmds_CXX='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_CXX='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + old_archive_cmds_CXX='$CC -Tprelink_objects $oldobjs~ + '"$old_archive_cmds_CXX" + reload_cmds_CXX='$CC -Tprelink_objects $reload_objs~ + '"$reload_cmds_CXX" + ;; + *) + archive_cmds_CXX='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_CXX='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + ;; + + tandem*) + case $cc_basename in + NCC*) + # NonStop-UX NCC 3.20 + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + esac + ;; + + vxworks*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + esac + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs_CXX" >&5 +$as_echo "$ld_shlibs_CXX" >&6; } + test "$ld_shlibs_CXX" = no && can_build_shared=no + + GCC_CXX="$GXX" + LD_CXX="$LD" + + ## CAVEAT EMPTOR: + ## There is no encapsulation within the following macros, do not change + ## the running order or otherwise move them around unless you know exactly + ## what you are doing... + # Dependencies to place before and after the object being linked: +predep_objects_CXX= +postdep_objects_CXX= +predeps_CXX= +postdeps_CXX= +compiler_lib_search_path_CXX= + +cat > conftest.$ac_ext <<_LT_EOF +class Foo +{ +public: + Foo (void) { a = 0; } +private: + int a; +}; +_LT_EOF + + +_lt_libdeps_save_CFLAGS=$CFLAGS +case "$CC $CFLAGS " in #( +*\ -flto*\ *) CFLAGS="$CFLAGS -fno-lto" ;; +*\ -fwhopr*\ *) CFLAGS="$CFLAGS -fno-whopr" ;; +*\ -fuse-linker-plugin*\ *) CFLAGS="$CFLAGS -fno-use-linker-plugin" ;; +esac + +if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + # Parse the compiler output and extract the necessary + # objects, libraries and library flags. + + # Sentinel used to keep track of whether or not we are before + # the conftest object file. + pre_test_object_deps_done=no + + for p in `eval "$output_verbose_link_cmd"`; do + case ${prev}${p} in + + -L* | -R* | -l*) + # Some compilers place space between "-{L,R}" and the path. + # Remove the space. + if test $p = "-L" || + test $p = "-R"; then + prev=$p + continue + fi + + # Expand the sysroot to ease extracting the directories later. + if test -z "$prev"; then + case $p in + -L*) func_stripname_cnf '-L' '' "$p"; prev=-L; p=$func_stripname_result ;; + -R*) func_stripname_cnf '-R' '' "$p"; prev=-R; p=$func_stripname_result ;; + -l*) func_stripname_cnf '-l' '' "$p"; prev=-l; p=$func_stripname_result ;; + esac + fi + case $p in + =*) func_stripname_cnf '=' '' "$p"; p=$lt_sysroot$func_stripname_result ;; + esac + if test "$pre_test_object_deps_done" = no; then + case ${prev} in + -L | -R) + # Internal compiler library paths should come after those + # provided the user. The postdeps already come after the + # user supplied libs so there is no need to process them. + if test -z "$compiler_lib_search_path_CXX"; then + compiler_lib_search_path_CXX="${prev}${p}" + else + compiler_lib_search_path_CXX="${compiler_lib_search_path_CXX} ${prev}${p}" + fi + ;; + # The "-l" case would never come before the object being + # linked, so don't bother handling this case. + esac + else + if test -z "$postdeps_CXX"; then + postdeps_CXX="${prev}${p}" + else + postdeps_CXX="${postdeps_CXX} ${prev}${p}" + fi + fi + prev= + ;; + + *.lto.$objext) ;; # Ignore GCC LTO objects + *.$objext) + # This assumes that the test object file only shows up + # once in the compiler output. + if test "$p" = "conftest.$objext"; then + pre_test_object_deps_done=yes + continue + fi + + if test "$pre_test_object_deps_done" = no; then + if test -z "$predep_objects_CXX"; then + predep_objects_CXX="$p" + else + predep_objects_CXX="$predep_objects_CXX $p" + fi + else + if test -z "$postdep_objects_CXX"; then + postdep_objects_CXX="$p" + else + postdep_objects_CXX="$postdep_objects_CXX $p" + fi + fi + ;; + + *) ;; # Ignore the rest. + + esac + done + + # Clean up. + rm -f a.out a.exe +else + echo "libtool.m4: error: problem compiling CXX test program" +fi + +$RM -f confest.$objext +CFLAGS=$_lt_libdeps_save_CFLAGS + +# PORTME: override above test on systems where it is broken +case $host_os in +interix[3-9]*) + # Interix 3.5 installs completely hosed .la files for C++, so rather than + # hack all around it, let's just trust "g++" to DTRT. + predep_objects_CXX= + postdep_objects_CXX= + postdeps_CXX= + ;; + +linux*) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C++ 5.9 + + # The more standards-conforming stlport4 library is + # incompatible with the Cstd library. Avoid specifying + # it if it's in CXXFLAGS. Ignore libCrun as + # -library=stlport4 depends on it. + case " $CXX $CXXFLAGS " in + *" -library=stlport4 "*) + solaris_use_stlport4=yes + ;; + esac + + if test "$solaris_use_stlport4" != yes; then + postdeps_CXX='-library=Cstd -library=Crun' + fi + ;; + esac + ;; + +solaris*) + case $cc_basename in + CC* | sunCC*) + # The more standards-conforming stlport4 library is + # incompatible with the Cstd library. Avoid specifying + # it if it's in CXXFLAGS. Ignore libCrun as + # -library=stlport4 depends on it. + case " $CXX $CXXFLAGS " in + *" -library=stlport4 "*) + solaris_use_stlport4=yes + ;; + esac + + # Adding this requires a known-good setup of shared libraries for + # Sun compiler versions before 5.6, else PIC objects from an old + # archive will be linked into the output, leading to subtle bugs. + if test "$solaris_use_stlport4" != yes; then + postdeps_CXX='-library=Cstd -library=Crun' + fi + ;; + esac + ;; +esac + + +case " $postdeps_CXX " in +*" -lc "*) archive_cmds_need_lc_CXX=no ;; +esac + compiler_lib_search_dirs_CXX= +if test -n "${compiler_lib_search_path_CXX}"; then + compiler_lib_search_dirs_CXX=`echo " ${compiler_lib_search_path_CXX}" | ${SED} -e 's! -L! !g' -e 's!^ !!'` +fi + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + lt_prog_compiler_wl_CXX= +lt_prog_compiler_pic_CXX= +lt_prog_compiler_static_CXX= + + + # C++ specific cases for pic, static, wl, etc. + if test "$GXX" = yes; then + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_static_CXX='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static_CXX='-Bstatic' + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + lt_prog_compiler_pic_CXX='-fPIC' + ;; + m68k) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + lt_prog_compiler_pic_CXX='-m68020 -resident32 -malways-restore-a4' + ;; + esac + ;; + + beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + mingw* | cygwin* | os2* | pw32* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + # Although the cygwin gcc ignores -fPIC, still need this for old-style + # (--disable-auto-import) libraries + lt_prog_compiler_pic_CXX='-DDLL_EXPORT' + ;; + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + lt_prog_compiler_pic_CXX='-fno-common' + ;; + *djgpp*) + # DJGPP does not support shared libraries at all + lt_prog_compiler_pic_CXX= + ;; + haiku*) + # PIC is the default for Haiku. + # The "-static" flag exists, but is broken. + lt_prog_compiler_static_CXX= + ;; + interix[3-9]*) + # Interix 3.x gcc -fpic/-fPIC options generate broken code. + # Instead, we relocate shared libraries at runtime. + ;; + sysv4*MP*) + if test -d /usr/nec; then + lt_prog_compiler_pic_CXX=-Kconform_pic + fi + ;; + hpux*) + # PIC is the default for 64-bit PA HP-UX, but not for 32-bit + # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag + # sets the default TLS model and affects inlining. + case $host_cpu in + hppa*64*) + ;; + *) + lt_prog_compiler_pic_CXX='-fPIC' + ;; + esac + ;; + *qnx* | *nto*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + lt_prog_compiler_pic_CXX='-fPIC -shared' + ;; + *) + lt_prog_compiler_pic_CXX='-fPIC' + ;; + esac + else + case $host_os in + aix[4-9]*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static_CXX='-Bstatic' + else + lt_prog_compiler_static_CXX='-bnso -bI:/lib/syscalls.exp' + fi + ;; + chorus*) + case $cc_basename in + cxch68*) + # Green Hills C++ Compiler + # _LT_TAGVAR(lt_prog_compiler_static, CXX)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a" + ;; + esac + ;; + mingw* | cygwin* | os2* | pw32* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + lt_prog_compiler_pic_CXX='-DDLL_EXPORT' + ;; + dgux*) + case $cc_basename in + ec++*) + lt_prog_compiler_pic_CXX='-KPIC' + ;; + ghcx*) + # Green Hills C++ Compiler + lt_prog_compiler_pic_CXX='-pic' + ;; + *) + ;; + esac + ;; + freebsd* | dragonfly*) + # FreeBSD uses GNU C++ + ;; + hpux9* | hpux10* | hpux11*) + case $cc_basename in + CC*) + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_static_CXX='${wl}-a ${wl}archive' + if test "$host_cpu" != ia64; then + lt_prog_compiler_pic_CXX='+Z' + fi + ;; + aCC*) + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_static_CXX='${wl}-a ${wl}archive' + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + lt_prog_compiler_pic_CXX='+Z' + ;; + esac + ;; + *) + ;; + esac + ;; + interix*) + # This is c89, which is MS Visual C++ (no shared libs) + # Anyone wants to do a port? + ;; + irix5* | irix6* | nonstopux*) + case $cc_basename in + CC*) + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_static_CXX='-non_shared' + # CC pic flag -KPIC is the default. + ;; + *) + ;; + esac + ;; + linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) + case $cc_basename in + KCC*) + # KAI C++ Compiler + lt_prog_compiler_wl_CXX='--backend -Wl,' + lt_prog_compiler_pic_CXX='-fPIC' + ;; + ecpc* ) + # old Intel C++ for x86_64 which still supported -KPIC. + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_pic_CXX='-KPIC' + lt_prog_compiler_static_CXX='-static' + ;; + icpc* ) + # Intel C++, used to be incompatible with GCC. + # ICC 10 doesn't accept -KPIC any more. + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_pic_CXX='-fPIC' + lt_prog_compiler_static_CXX='-static' + ;; + pgCC* | pgcpp*) + # Portland Group C++ compiler + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_pic_CXX='-fpic' + lt_prog_compiler_static_CXX='-Bstatic' + ;; + cxx*) + # Compaq C++ + # Make sure the PIC flag is empty. It appears that all Alpha + # Linux and Compaq Tru64 Unix objects are PIC. + lt_prog_compiler_pic_CXX= + lt_prog_compiler_static_CXX='-non_shared' + ;; + xlc* | xlC* | bgxl[cC]* | mpixl[cC]*) + # IBM XL 8.0, 9.0 on PPC and BlueGene + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_pic_CXX='-qpic' + lt_prog_compiler_static_CXX='-qstaticlink' + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C++ 5.9 + lt_prog_compiler_pic_CXX='-KPIC' + lt_prog_compiler_static_CXX='-Bstatic' + lt_prog_compiler_wl_CXX='-Qoption ld ' + ;; + esac + ;; + esac + ;; + lynxos*) + ;; + m88k*) + ;; + mvs*) + case $cc_basename in + cxx*) + lt_prog_compiler_pic_CXX='-W c,exportall' + ;; + *) + ;; + esac + ;; + netbsd* | netbsdelf*-gnu) + ;; + *qnx* | *nto*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + lt_prog_compiler_pic_CXX='-fPIC -shared' + ;; + osf3* | osf4* | osf5*) + case $cc_basename in + KCC*) + lt_prog_compiler_wl_CXX='--backend -Wl,' + ;; + RCC*) + # Rational C++ 2.4.1 + lt_prog_compiler_pic_CXX='-pic' + ;; + cxx*) + # Digital/Compaq C++ + lt_prog_compiler_wl_CXX='-Wl,' + # Make sure the PIC flag is empty. It appears that all Alpha + # Linux and Compaq Tru64 Unix objects are PIC. + lt_prog_compiler_pic_CXX= + lt_prog_compiler_static_CXX='-non_shared' + ;; + *) + ;; + esac + ;; + psos*) + ;; + solaris*) + case $cc_basename in + CC* | sunCC*) + # Sun C++ 4.2, 5.x and Centerline C++ + lt_prog_compiler_pic_CXX='-KPIC' + lt_prog_compiler_static_CXX='-Bstatic' + lt_prog_compiler_wl_CXX='-Qoption ld ' + ;; + gcx*) + # Green Hills C++ Compiler + lt_prog_compiler_pic_CXX='-PIC' + ;; + *) + ;; + esac + ;; + sunos4*) + case $cc_basename in + CC*) + # Sun C++ 4.x + lt_prog_compiler_pic_CXX='-pic' + lt_prog_compiler_static_CXX='-Bstatic' + ;; + lcc*) + # Lucid + lt_prog_compiler_pic_CXX='-pic' + ;; + *) + ;; + esac + ;; + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + case $cc_basename in + CC*) + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_pic_CXX='-KPIC' + lt_prog_compiler_static_CXX='-Bstatic' + ;; + esac + ;; + tandem*) + case $cc_basename in + NCC*) + # NonStop-UX NCC 3.20 + lt_prog_compiler_pic_CXX='-KPIC' + ;; + *) + ;; + esac + ;; + vxworks*) + ;; + *) + lt_prog_compiler_can_build_shared_CXX=no + ;; + esac + fi + +case $host_os in + # For platforms which do not support PIC, -DPIC is meaningless: + *djgpp*) + lt_prog_compiler_pic_CXX= + ;; + *) + lt_prog_compiler_pic_CXX="$lt_prog_compiler_pic_CXX -DPIC" + ;; +esac + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5 +$as_echo_n "checking for $compiler option to produce PIC... " >&6; } +if ${lt_cv_prog_compiler_pic_CXX+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_pic_CXX=$lt_prog_compiler_pic_CXX +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_CXX" >&5 +$as_echo "$lt_cv_prog_compiler_pic_CXX" >&6; } +lt_prog_compiler_pic_CXX=$lt_cv_prog_compiler_pic_CXX + +# +# Check to make sure the PIC flag actually works. +# +if test -n "$lt_prog_compiler_pic_CXX"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic_CXX works" >&5 +$as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic_CXX works... " >&6; } +if ${lt_cv_prog_compiler_pic_works_CXX+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_pic_works_CXX=no + ac_outfile=conftest.$ac_objext + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="$lt_prog_compiler_pic_CXX -DPIC" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings other than the usual output. + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler_pic_works_CXX=yes + fi + fi + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works_CXX" >&5 +$as_echo "$lt_cv_prog_compiler_pic_works_CXX" >&6; } + +if test x"$lt_cv_prog_compiler_pic_works_CXX" = xyes; then + case $lt_prog_compiler_pic_CXX in + "" | " "*) ;; + *) lt_prog_compiler_pic_CXX=" $lt_prog_compiler_pic_CXX" ;; + esac +else + lt_prog_compiler_pic_CXX= + lt_prog_compiler_can_build_shared_CXX=no +fi + +fi + + + + + +# +# Check to make sure the static flag actually works. +# +wl=$lt_prog_compiler_wl_CXX eval lt_tmp_static_flag=\"$lt_prog_compiler_static_CXX\" +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5 +$as_echo_n "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; } +if ${lt_cv_prog_compiler_static_works_CXX+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_static_works_CXX=no + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS $lt_tmp_static_flag" + echo "$lt_simple_link_test_code" > conftest.$ac_ext + if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then + # The linker can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + # Append any errors to the config.log. + cat conftest.err 1>&5 + $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler_static_works_CXX=yes + fi + else + lt_cv_prog_compiler_static_works_CXX=yes + fi + fi + $RM -r conftest* + LDFLAGS="$save_LDFLAGS" + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works_CXX" >&5 +$as_echo "$lt_cv_prog_compiler_static_works_CXX" >&6; } + +if test x"$lt_cv_prog_compiler_static_works_CXX" = xyes; then + : +else + lt_prog_compiler_static_CXX= +fi + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 +$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } +if ${lt_cv_prog_compiler_c_o_CXX+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_c_o_CXX=no + $RM -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp + $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 + if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then + lt_cv_prog_compiler_c_o_CXX=yes + fi + fi + chmod u+w . 2>&5 + $RM conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files + $RM out/* && rmdir out + cd .. + $RM -r conftest + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o_CXX" >&5 +$as_echo "$lt_cv_prog_compiler_c_o_CXX" >&6; } + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 +$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } +if ${lt_cv_prog_compiler_c_o_CXX+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_c_o_CXX=no + $RM -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp + $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 + if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then + lt_cv_prog_compiler_c_o_CXX=yes + fi + fi + chmod u+w . 2>&5 + $RM conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files + $RM out/* && rmdir out + cd .. + $RM -r conftest + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o_CXX" >&5 +$as_echo "$lt_cv_prog_compiler_c_o_CXX" >&6; } + + + + +hard_links="nottested" +if test "$lt_cv_prog_compiler_c_o_CXX" = no && test "$need_locks" != no; then + # do not overwrite the value of need_locks provided by the user + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5 +$as_echo_n "checking if we can lock with hard links... " >&6; } + hard_links=yes + $RM conftest* + ln conftest.a conftest.b 2>/dev/null && hard_links=no + touch conftest.a + ln conftest.a conftest.b 2>&5 || hard_links=no + ln conftest.a conftest.b 2>/dev/null && hard_links=no + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5 +$as_echo "$hard_links" >&6; } + if test "$hard_links" = no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5 +$as_echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;} + need_locks=warn + fi +else + need_locks=no +fi + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5 +$as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; } + + export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + exclude_expsyms_CXX='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*' + case $host_os in + aix[4-9]*) + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to AIX nm, but means don't demangle with GNU nm + # Also, AIX nm treats weak defined symbols like other global defined + # symbols, whereas GNU nm marks them as "W". + if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then + export_symbols_cmds_CXX='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + else + export_symbols_cmds_CXX='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + fi + ;; + pw32*) + export_symbols_cmds_CXX="$ltdll_cmds" + ;; + cygwin* | mingw* | cegcc*) + case $cc_basename in + cl*) + exclude_expsyms_CXX='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' + ;; + *) + export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/;s/^.*[ ]__nm__\([^ ]*\)[ ][^ ]*/\1 DATA/;/^I[ ]/d;/^[AITW][ ]/s/.* //'\'' | sort | uniq > $export_symbols' + exclude_expsyms_CXX='[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname' + ;; + esac + ;; + linux* | k*bsd*-gnu | gnu*) + link_all_deplibs_CXX=no + ;; + *) + export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + ;; + esac + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs_CXX" >&5 +$as_echo "$ld_shlibs_CXX" >&6; } +test "$ld_shlibs_CXX" = no && can_build_shared=no + +with_gnu_ld_CXX=$with_gnu_ld + + + + + + +# +# Do we need to explicitly link libc? +# +case "x$archive_cmds_need_lc_CXX" in +x|xyes) + # Assume -lc should be added + archive_cmds_need_lc_CXX=yes + + if test "$enable_shared" = yes && test "$GCC" = yes; then + case $archive_cmds_CXX in + *'~'*) + # FIXME: we may have to deal with multi-command sequences. + ;; + '$CC '*) + # Test whether the compiler implicitly links with -lc since on some + # systems, -lgcc has to come before -lc. If gcc already passes -lc + # to ld, don't add -lc before -lgcc. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5 +$as_echo_n "checking whether -lc should be explicitly linked in... " >&6; } +if ${lt_cv_archive_cmds_need_lc_CXX+:} false; then : + $as_echo_n "(cached) " >&6 +else + $RM conftest* + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } 2>conftest.err; then + soname=conftest + lib=conftest + libobjs=conftest.$ac_objext + deplibs= + wl=$lt_prog_compiler_wl_CXX + pic_flag=$lt_prog_compiler_pic_CXX + compiler_flags=-v + linker_flags=-v + verstring= + output_objdir=. + libname=conftest + lt_save_allow_undefined_flag=$allow_undefined_flag_CXX + allow_undefined_flag_CXX= + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds_CXX 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5 + (eval $archive_cmds_CXX 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + then + lt_cv_archive_cmds_need_lc_CXX=no + else + lt_cv_archive_cmds_need_lc_CXX=yes + fi + allow_undefined_flag_CXX=$lt_save_allow_undefined_flag + else + cat conftest.err 1>&5 + fi + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_archive_cmds_need_lc_CXX" >&5 +$as_echo "$lt_cv_archive_cmds_need_lc_CXX" >&6; } + archive_cmds_need_lc_CXX=$lt_cv_archive_cmds_need_lc_CXX + ;; + esac + fi + ;; +esac + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5 +$as_echo_n "checking dynamic linker characteristics... " >&6; } + +library_names_spec= +libname_spec='lib$name' +soname_spec= +shrext_cmds=".so" +postinstall_cmds= +postuninstall_cmds= +finish_cmds= +finish_eval= +shlibpath_var= +shlibpath_overrides_runpath=unknown +version_type=none +dynamic_linker="$host_os ld.so" +sys_lib_dlsearch_path_spec="/lib /usr/lib" +need_lib_prefix=unknown +hardcode_into_libs=no + +# when you set need_version to no, make sure it does not cause -set_version +# flags to be left without arguments +need_version=unknown + +case $host_os in +aix3*) + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' + shlibpath_var=LIBPATH + + # AIX 3 has no versioning support, so we append a major version to the name. + soname_spec='${libname}${release}${shared_ext}$major' + ;; + +aix[4-9]*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + hardcode_into_libs=yes + if test "$host_cpu" = ia64; then + # AIX 5 supports IA64 + library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + else + # With GCC up to 2.95.x, collect2 would create an import file + # for dependence libraries. The import file would start with + # the line `#! .'. This would cause the generated library to + # depend on `.', always an invalid library. This was fixed in + # development snapshots of GCC prior to 3.0. + case $host_os in + aix4 | aix4.[01] | aix4.[01].*) + if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' + echo ' yes ' + echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then + : + else + can_build_shared=no + fi + ;; + esac + # AIX (on Power*) has no versioning support, so currently we can not hardcode correct + # soname into executable. Probably we can add versioning support to + # collect2, so additional links can be useful in future. + if test "$aix_use_runtimelinking" = yes; then + # If using run time linking (on AIX 4.2 or later) use lib.so + # instead of lib.a to let people know that these are not + # typical AIX shared libraries. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + else + # We preserve .a as extension for shared libraries through AIX4.2 + # and later when we are not doing run time linking. + library_names_spec='${libname}${release}.a $libname.a' + soname_spec='${libname}${release}${shared_ext}$major' + fi + shlibpath_var=LIBPATH + fi + ;; + +amigaos*) + case $host_cpu in + powerpc) + # Since July 2007 AmigaOS4 officially supports .so libraries. + # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + ;; + m68k) + library_names_spec='$libname.ixlibrary $libname.a' + # Create ${libname}_ixlibrary.a entries in /sys/libs. + finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' + ;; + esac + ;; + +beos*) + library_names_spec='${libname}${shared_ext}' + dynamic_linker="$host_os ld.so" + shlibpath_var=LIBRARY_PATH + ;; + +bsdi[45]*) + version_type=linux # correct to gnu/linux during the next big refactor + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" + sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" + # the default ld.so.conf also contains /usr/contrib/lib and + # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow + # libtool to hard-code these into programs + ;; + +cygwin* | mingw* | pw32* | cegcc*) + version_type=windows + shrext_cmds=".dll" + need_version=no + need_lib_prefix=no + + case $GCC,$cc_basename in + yes,*) + # gcc + library_names_spec='$libname.dll.a' + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \${file}`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname~ + chmod a+x \$dldir/$dlname~ + if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then + eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; + fi' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $RM \$dlpath' + shlibpath_overrides_runpath=yes + + case $host_os in + cygwin*) + # Cygwin DLLs use 'cyg' prefix rather than 'lib' + soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + + ;; + mingw* | cegcc*) + # MinGW DLLs use traditional 'lib' prefix + soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + ;; + pw32*) + # pw32 DLLs use 'pw' prefix rather than 'lib' + library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + ;; + esac + dynamic_linker='Win32 ld.exe' + ;; + + *,cl*) + # Native MSVC + libname_spec='$name' + soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + library_names_spec='${libname}.dll.lib' + + case $build_os in + mingw*) + sys_lib_search_path_spec= + lt_save_ifs=$IFS + IFS=';' + for lt_path in $LIB + do + IFS=$lt_save_ifs + # Let DOS variable expansion print the short 8.3 style file name. + lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"` + sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path" + done + IFS=$lt_save_ifs + # Convert to MSYS style. + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([a-zA-Z]\\):| /\\1|g' -e 's|^ ||'` + ;; + cygwin*) + # Convert to unix form, then to dos form, then back to unix form + # but this time dos style (no spaces!) so that the unix form looks + # like /cygdrive/c/PROGRA~1:/cygdr... + sys_lib_search_path_spec=`cygpath --path --unix "$LIB"` + sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null` + sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + ;; + *) + sys_lib_search_path_spec="$LIB" + if $ECHO "$sys_lib_search_path_spec" | $GREP ';[c-zC-Z]:/' >/dev/null; then + # It is most probably a Windows format PATH. + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` + else + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi + # FIXME: find the short name or the path components, as spaces are + # common. (e.g. "Program Files" -> "PROGRA~1") + ;; + esac + + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \${file}`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $RM \$dlpath' + shlibpath_overrides_runpath=yes + dynamic_linker='Win32 link.exe' + ;; + + *) + # Assume MSVC wrapper + library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib' + dynamic_linker='Win32 ld.exe' + ;; + esac + # FIXME: first we should search . and the directory the executable is in + shlibpath_var=PATH + ;; + +darwin* | rhapsody*) + dynamic_linker="$host_os dyld" + version_type=darwin + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext' + soname_spec='${libname}${release}${major}$shared_ext' + shlibpath_overrides_runpath=yes + shlibpath_var=DYLD_LIBRARY_PATH + shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' + + sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' + ;; + +dgux*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +freebsd* | dragonfly*) + # DragonFly does not have aout. When/if they implement a new + # versioning mechanism, adjust this. + if test -x /usr/bin/objformat; then + objformat=`/usr/bin/objformat` + else + case $host_os in + freebsd[23].*) objformat=aout ;; + *) objformat=elf ;; + esac + fi + version_type=freebsd-$objformat + case $version_type in + freebsd-elf*) + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + need_version=no + need_lib_prefix=no + ;; + freebsd-*) + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' + need_version=yes + ;; + esac + shlibpath_var=LD_LIBRARY_PATH + case $host_os in + freebsd2.*) + shlibpath_overrides_runpath=yes + ;; + freebsd3.[01]* | freebsdelf3.[01]*) + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + freebsd3.[2-9]* | freebsdelf3.[2-9]* | \ + freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1) + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + *) # from 4.6 on, and DragonFly + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + esac + ;; + +haiku*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + dynamic_linker="$host_os runtime_loader" + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LIBRARY_PATH + shlibpath_overrides_runpath=yes + sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib' + hardcode_into_libs=yes + ;; + +hpux9* | hpux10* | hpux11*) + # Give a soname corresponding to the major version so that dld.sl refuses to + # link against other versions. + version_type=sunos + need_lib_prefix=no + need_version=no + case $host_cpu in + ia64*) + shrext_cmds='.so' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.so" + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + if test "X$HPUX_IA64_MODE" = X32; then + sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" + else + sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" + fi + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + hppa*64*) + shrext_cmds='.sl' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.sl" + shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + *) + shrext_cmds='.sl' + dynamic_linker="$host_os dld.sl" + shlibpath_var=SHLIB_PATH + shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + ;; + esac + # HP-UX runs *really* slowly unless shared libraries are mode 555, ... + postinstall_cmds='chmod 555 $lib' + # or fails outright, so override atomically: + install_override_mode=555 + ;; + +interix[3-9]*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +irix5* | irix6* | nonstopux*) + case $host_os in + nonstopux*) version_type=nonstopux ;; + *) + if test "$lt_cv_prog_gnu_ld" = yes; then + version_type=linux # correct to gnu/linux during the next big refactor + else + version_type=irix + fi ;; + esac + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' + case $host_os in + irix5* | nonstopux*) + libsuff= shlibsuff= + ;; + *) + case $LD in # libtool.m4 will add one of these switches to LD + *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") + libsuff= shlibsuff= libmagic=32-bit;; + *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") + libsuff=32 shlibsuff=N32 libmagic=N32;; + *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") + libsuff=64 shlibsuff=64 libmagic=64-bit;; + *) libsuff= shlibsuff= libmagic=never-match;; + esac + ;; + esac + shlibpath_var=LD_LIBRARY${shlibsuff}_PATH + shlibpath_overrides_runpath=no + sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" + sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" + hardcode_into_libs=yes + ;; + +# No shared lib support for Linux oldld, aout, or coff. +linux*oldld* | linux*aout* | linux*coff*) + dynamic_linker=no + ;; + +# This must be glibc/ELF. +linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + + # Some binutils ld are patched to set DT_RUNPATH + if ${lt_cv_shlibpath_overrides_runpath+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_shlibpath_overrides_runpath=no + save_LDFLAGS=$LDFLAGS + save_libdir=$libdir + eval "libdir=/foo; wl=\"$lt_prog_compiler_wl_CXX\"; \ + LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec_CXX\"" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + if ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null; then : + lt_cv_shlibpath_overrides_runpath=yes +fi +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LDFLAGS=$save_LDFLAGS + libdir=$save_libdir + +fi + + shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath + + # This implies no fast_install, which is unacceptable. + # Some rework will be needed to allow for fast_install + # before this can be enabled. + hardcode_into_libs=yes + + # Append ld.so.conf contents to the search path + if test -f /etc/ld.so.conf; then + lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '` + sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" + fi + + # We used to test for /lib/ld.so.1 and disable shared libraries on + # powerpc, because MkLinux only supported shared libraries with the + # GNU dynamic linker. Since this was broken with cross compilers, + # most powerpc-linux boxes support dynamic linking these days and + # people can always --disable-shared, the test was removed, and we + # assume the GNU/Linux dynamic linker is in use. + dynamic_linker='GNU/Linux ld.so' + ;; + +netbsdelf*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='NetBSD ld.elf_so' + ;; + +netbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + dynamic_linker='NetBSD (a.out) ld.so' + else + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='NetBSD ld.elf_so' + fi + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + +newsos6) + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +*nto* | *qnx*) + version_type=qnx + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='ldqnx.so' + ;; + +openbsd*) + version_type=sunos + sys_lib_dlsearch_path_spec="/usr/lib" + need_lib_prefix=no + # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. + case $host_os in + openbsd3.3 | openbsd3.3.*) need_version=yes ;; + *) need_version=no ;; + esac + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + shlibpath_var=LD_LIBRARY_PATH + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + case $host_os in + openbsd2.[89] | openbsd2.[89].*) + shlibpath_overrides_runpath=no + ;; + *) + shlibpath_overrides_runpath=yes + ;; + esac + else + shlibpath_overrides_runpath=yes + fi + ;; + +os2*) + libname_spec='$name' + shrext_cmds=".dll" + need_lib_prefix=no + library_names_spec='$libname${shared_ext} $libname.a' + dynamic_linker='OS/2 ld.exe' + shlibpath_var=LIBPATH + ;; + +osf3* | osf4* | osf5*) + version_type=osf + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" + sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" + ;; + +rdos*) + dynamic_linker=no + ;; + +solaris*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + # ldd complains unless libraries are executable + postinstall_cmds='chmod +x $lib' + ;; + +sunos4*) + version_type=sunos + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + if test "$with_gnu_ld" = yes; then + need_lib_prefix=no + fi + need_version=yes + ;; + +sysv4 | sysv4.3*) + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + case $host_vendor in + sni) + shlibpath_overrides_runpath=no + need_lib_prefix=no + runpath_var=LD_RUN_PATH + ;; + siemens) + need_lib_prefix=no + ;; + motorola) + need_lib_prefix=no + need_version=no + shlibpath_overrides_runpath=no + sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' + ;; + esac + ;; + +sysv4*MP*) + if test -d /usr/nec ;then + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' + soname_spec='$libname${shared_ext}.$major' + shlibpath_var=LD_LIBRARY_PATH + fi + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + version_type=freebsd-elf + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + if test "$with_gnu_ld" = yes; then + sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' + else + sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' + case $host_os in + sco3.2v5*) + sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" + ;; + esac + fi + sys_lib_dlsearch_path_spec='/usr/lib' + ;; + +tpf*) + # TPF is a cross-target only. Preferred cross-host = GNU/Linux. + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +uts4*) + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +*) + dynamic_linker=no + ;; +esac +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5 +$as_echo "$dynamic_linker" >&6; } +test "$dynamic_linker" = no && can_build_shared=no + +variables_saved_for_relink="PATH $shlibpath_var $runpath_var" +if test "$GCC" = yes; then + variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" +fi + +if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then + sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec" +fi +if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then + sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec" +fi + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5 +$as_echo_n "checking how to hardcode library paths into programs... " >&6; } +hardcode_action_CXX= +if test -n "$hardcode_libdir_flag_spec_CXX" || + test -n "$runpath_var_CXX" || + test "X$hardcode_automatic_CXX" = "Xyes" ; then + + # We can hardcode non-existent directories. + if test "$hardcode_direct_CXX" != no && + # If the only mechanism to avoid hardcoding is shlibpath_var, we + # have to relink, otherwise we might link with an installed library + # when we should be linking with a yet-to-be-installed one + ## test "$_LT_TAGVAR(hardcode_shlibpath_var, CXX)" != no && + test "$hardcode_minus_L_CXX" != no; then + # Linking always hardcodes the temporary library directory. + hardcode_action_CXX=relink + else + # We can link without hardcoding, and we can hardcode nonexisting dirs. + hardcode_action_CXX=immediate + fi +else + # We cannot hardcode anything, or else we can only hardcode existing + # directories. + hardcode_action_CXX=unsupported +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action_CXX" >&5 +$as_echo "$hardcode_action_CXX" >&6; } + +if test "$hardcode_action_CXX" = relink || + test "$inherit_rpath_CXX" = yes; then + # Fast installation is not supported + enable_fast_install=no +elif test "$shlibpath_overrides_runpath" = yes || + test "$enable_shared" = no; then + # Fast installation is not necessary + enable_fast_install=needless +fi + + + + + + + + fi # test -n "$compiler" + + CC=$lt_save_CC + CFLAGS=$lt_save_CFLAGS + LDCXX=$LD + LD=$lt_save_LD + GCC=$lt_save_GCC + with_gnu_ld=$lt_save_with_gnu_ld + lt_cv_path_LDCXX=$lt_cv_path_LD + lt_cv_path_LD=$lt_save_path_LD + lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld + lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld +fi # test "$_lt_caught_CXX_error" != yes + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + + + + + + + + + + + + + + ac_config_commands="$ac_config_commands libtool" + + + + +# Only expand once: + + + +# Transfer these variables to the Makefile + + + + + +ac_config_files="$ac_config_files Makefile lib/Makefile include/Makefile bin/Makefile doc/Makefile portaudiocpp.pc" + +cat >confcache <<\_ACEOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs, see configure's option --config-cache. +# It is not useful on other systems. If it contains results you don't +# want to keep, you may remove or edit it. +# +# config.status only pays attention to the cache file if you give it +# the --recheck option to rerun configure. +# +# `ac_cv_env_foo' variables (set or unset) will be overridden when +# loading this file, other *unset* `ac_cv_foo' will be assigned the +# following values. + +_ACEOF + +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, we kill variables containing newlines. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +( + for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done + + (set) 2>&1 | + case $as_nl`(ac_space=' '; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + # `set' does not quote correctly, so add quotes: double-quote + # substitution turns \\\\ into \\, and sed turns \\ into \. + sed -n \ + "s/'/'\\\\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" + ;; #( + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) | + sed ' + /^ac_cv_env_/b end + t clear + :clear + s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + t end + s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ + :end' >>confcache +if diff "$cache_file" confcache >/dev/null 2>&1; then :; else + if test -w "$cache_file"; then + if test "x$cache_file" != "x/dev/null"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 +$as_echo "$as_me: updating cache $cache_file" >&6;} + if test ! -f "$cache_file" || test -h "$cache_file"; then + cat confcache >"$cache_file" + else + case $cache_file in #( + */* | ?:*) + mv -f confcache "$cache_file"$$ && + mv -f "$cache_file"$$ "$cache_file" ;; #( + *) + mv -f confcache "$cache_file" ;; + esac + fi + fi + else + { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 +$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} + fi +fi +rm -f confcache + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +# Transform confdefs.h into DEFS. +# Protect against shell expansion while executing Makefile rules. +# Protect against Makefile macro expansion. +# +# If the first sed substitution is executed (which looks for macros that +# take arguments), then branch to the quote section. Otherwise, +# look for a macro that doesn't take arguments. +ac_script=' +:mline +/\\$/{ + N + s,\\\n,, + b mline +} +t clear +:clear +s/^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\)/-D\1=\2/g +t quote +s/^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)/-D\1=\2/g +t quote +b any +:quote +s/[ `~#$^&*(){}\\|;'\''"<>?]/\\&/g +s/\[/\\&/g +s/\]/\\&/g +s/\$/$$/g +H +:any +${ + g + s/^\n// + s/\n/ /g + p +} +' +DEFS=`sed -n "$ac_script" confdefs.h` + + +ac_libobjs= +ac_ltlibobjs= +U= +for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue + # 1. Remove the extension, and $U if already installed. + ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' + ac_i=`$as_echo "$ac_i" | sed "$ac_script"` + # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR + # will be set to the directory where LIBOBJS objects are built. + as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" + as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' +done +LIBOBJS=$ac_libobjs + +LTLIBOBJS=$ac_ltlibobjs + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking that generated files are newer than configure" >&5 +$as_echo_n "checking that generated files are newer than configure... " >&6; } + if test -n "$am_sleep_pid"; then + # Hide warnings about reused PIDs. + wait $am_sleep_pid 2>/dev/null + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: done" >&5 +$as_echo "done" >&6; } + if test -n "$EXEEXT"; then + am__EXEEXT_TRUE= + am__EXEEXT_FALSE='#' +else + am__EXEEXT_TRUE='#' + am__EXEEXT_FALSE= +fi + +if test -z "${MAINTAINER_MODE_TRUE}" && test -z "${MAINTAINER_MODE_FALSE}"; then + as_fn_error $? "conditional \"MAINTAINER_MODE\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then + as_fn_error $? "conditional \"AMDEP\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then + as_fn_error $? "conditional \"am__fastdepCC\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${am__fastdepCXX_TRUE}" && test -z "${am__fastdepCXX_FALSE}"; then + as_fn_error $? "conditional \"am__fastdepCXX\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi + +: "${CONFIG_STATUS=./config.status}" +ac_write_fail=0 +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files $CONFIG_STATUS" +{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 +$as_echo "$as_me: creating $CONFIG_STATUS" >&6;} +as_write_fail=0 +cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 +#! $SHELL +# Generated by $as_me. +# Run this file to recreate the current configuration. +# Compiler output produced by configure, useful for debugging +# configure, is in config.log if it exists. + +debug=false +ac_cs_recheck=false +ac_cs_silent=false + +SHELL=\${CONFIG_SHELL-$SHELL} +export SHELL +_ASEOF +cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +as_myself= +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + + +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with STATUS, using 1 if that was 0. +as_fn_error () +{ + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + fi + $as_echo "$as_me: error: $2" >&2 + as_fn_exit $as_status +} # as_fn_error + + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -pR'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -pR' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -pR' + fi +else + as_ln_s='cp -pR' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" + + +} # as_fn_mkdir_p +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + + +# as_fn_executable_p FILE +# ----------------------- +# Test if FILE is an executable regular file. +as_fn_executable_p () +{ + test -f "$1" && test -x "$1" +} # as_fn_executable_p +as_test_x='test -x' +as_executable_p=as_fn_executable_p + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +exec 6>&1 +## ----------------------------------- ## +## Main body of $CONFIG_STATUS script. ## +## ----------------------------------- ## +_ASEOF +test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# Save the log message, to keep $0 and so on meaningful, and to +# report actual input values of CONFIG_FILES etc. instead of their +# values after options handling. +ac_log=" +This file was extended by PortAudioCpp $as_me 12, which was +generated by GNU Autoconf 2.69. Invocation command line was + + CONFIG_FILES = $CONFIG_FILES + CONFIG_HEADERS = $CONFIG_HEADERS + CONFIG_LINKS = $CONFIG_LINKS + CONFIG_COMMANDS = $CONFIG_COMMANDS + $ $0 $@ + +on `(hostname || uname -n) 2>/dev/null | sed 1q` +" + +_ACEOF + +case $ac_config_files in *" +"*) set x $ac_config_files; shift; ac_config_files=$*;; +esac + + + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +# Files that config.status was made for. +config_files="$ac_config_files" +config_commands="$ac_config_commands" + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +ac_cs_usage="\ +\`$as_me' instantiates files and other configuration actions +from templates according to the current configuration. Unless the files +and actions are specified as TAGs, all are instantiated by default. + +Usage: $0 [OPTION]... [TAG]... + + -h, --help print this help, then exit + -V, --version print version number and configuration settings, then exit + --config print configuration, then exit + -q, --quiet, --silent + do not print progress messages + -d, --debug don't remove temporary files + --recheck update $as_me by reconfiguring in the same conditions + --file=FILE[:TEMPLATE] + instantiate the configuration file FILE + +Configuration files: +$config_files + +Configuration commands: +$config_commands + +Report bugs to the package provider." + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" +ac_cs_version="\\ +PortAudioCpp config.status 12 +configured by $0, generated by GNU Autoconf 2.69, + with options \\"\$ac_cs_config\\" + +Copyright (C) 2012 Free Software Foundation, Inc. +This config.status script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it." + +ac_pwd='$ac_pwd' +srcdir='$srcdir' +INSTALL='$INSTALL' +MKDIR_P='$MKDIR_P' +AWK='$AWK' +test -n "\$AWK" || AWK=awk +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# The default lists apply if the user does not specify any file. +ac_need_defaults=: +while test $# != 0 +do + case $1 in + --*=?*) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` + ac_shift=: + ;; + --*=) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg= + ac_shift=: + ;; + *) + ac_option=$1 + ac_optarg=$2 + ac_shift=shift + ;; + esac + + case $ac_option in + # Handling of the options. + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + ac_cs_recheck=: ;; + --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) + $as_echo "$ac_cs_version"; exit ;; + --config | --confi | --conf | --con | --co | --c ) + $as_echo "$ac_cs_config"; exit ;; + --debug | --debu | --deb | --de | --d | -d ) + debug=: ;; + --file | --fil | --fi | --f ) + $ac_shift + case $ac_optarg in + *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + '') as_fn_error $? "missing file argument" ;; + esac + as_fn_append CONFIG_FILES " '$ac_optarg'" + ac_need_defaults=false;; + --he | --h | --help | --hel | -h ) + $as_echo "$ac_cs_usage"; exit ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil | --si | --s) + ac_cs_silent=: ;; + + # This is an error. + -*) as_fn_error $? "unrecognized option: \`$1' +Try \`$0 --help' for more information." ;; + + *) as_fn_append ac_config_targets " $1" + ac_need_defaults=false ;; + + esac + shift +done + +ac_configure_extra_args= + +if $ac_cs_silent; then + exec 6>/dev/null + ac_configure_extra_args="$ac_configure_extra_args --silent" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +if \$ac_cs_recheck; then + set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion + shift + \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 + CONFIG_SHELL='$SHELL' + export CONFIG_SHELL + exec "\$@" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +exec 5>>config.log +{ + echo + sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX +## Running $as_me. ## +_ASBOX + $as_echo "$ac_log" +} >&5 + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +# +# INIT-COMMANDS +# +AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir" + + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +sed_quote_subst='$sed_quote_subst' +double_quote_subst='$double_quote_subst' +delay_variable_subst='$delay_variable_subst' +AS='`$ECHO "$AS" | $SED "$delay_single_quote_subst"`' +DLLTOOL='`$ECHO "$DLLTOOL" | $SED "$delay_single_quote_subst"`' +OBJDUMP='`$ECHO "$OBJDUMP" | $SED "$delay_single_quote_subst"`' +macro_version='`$ECHO "$macro_version" | $SED "$delay_single_quote_subst"`' +macro_revision='`$ECHO "$macro_revision" | $SED "$delay_single_quote_subst"`' +enable_shared='`$ECHO "$enable_shared" | $SED "$delay_single_quote_subst"`' +enable_static='`$ECHO "$enable_static" | $SED "$delay_single_quote_subst"`' +pic_mode='`$ECHO "$pic_mode" | $SED "$delay_single_quote_subst"`' +enable_fast_install='`$ECHO "$enable_fast_install" | $SED "$delay_single_quote_subst"`' +SHELL='`$ECHO "$SHELL" | $SED "$delay_single_quote_subst"`' +ECHO='`$ECHO "$ECHO" | $SED "$delay_single_quote_subst"`' +PATH_SEPARATOR='`$ECHO "$PATH_SEPARATOR" | $SED "$delay_single_quote_subst"`' +host_alias='`$ECHO "$host_alias" | $SED "$delay_single_quote_subst"`' +host='`$ECHO "$host" | $SED "$delay_single_quote_subst"`' +host_os='`$ECHO "$host_os" | $SED "$delay_single_quote_subst"`' +build_alias='`$ECHO "$build_alias" | $SED "$delay_single_quote_subst"`' +build='`$ECHO "$build" | $SED "$delay_single_quote_subst"`' +build_os='`$ECHO "$build_os" | $SED "$delay_single_quote_subst"`' +SED='`$ECHO "$SED" | $SED "$delay_single_quote_subst"`' +Xsed='`$ECHO "$Xsed" | $SED "$delay_single_quote_subst"`' +GREP='`$ECHO "$GREP" | $SED "$delay_single_quote_subst"`' +EGREP='`$ECHO "$EGREP" | $SED "$delay_single_quote_subst"`' +FGREP='`$ECHO "$FGREP" | $SED "$delay_single_quote_subst"`' +LD='`$ECHO "$LD" | $SED "$delay_single_quote_subst"`' +NM='`$ECHO "$NM" | $SED "$delay_single_quote_subst"`' +LN_S='`$ECHO "$LN_S" | $SED "$delay_single_quote_subst"`' +max_cmd_len='`$ECHO "$max_cmd_len" | $SED "$delay_single_quote_subst"`' +ac_objext='`$ECHO "$ac_objext" | $SED "$delay_single_quote_subst"`' +exeext='`$ECHO "$exeext" | $SED "$delay_single_quote_subst"`' +lt_unset='`$ECHO "$lt_unset" | $SED "$delay_single_quote_subst"`' +lt_SP2NL='`$ECHO "$lt_SP2NL" | $SED "$delay_single_quote_subst"`' +lt_NL2SP='`$ECHO "$lt_NL2SP" | $SED "$delay_single_quote_subst"`' +lt_cv_to_host_file_cmd='`$ECHO "$lt_cv_to_host_file_cmd" | $SED "$delay_single_quote_subst"`' +lt_cv_to_tool_file_cmd='`$ECHO "$lt_cv_to_tool_file_cmd" | $SED "$delay_single_quote_subst"`' +reload_flag='`$ECHO "$reload_flag" | $SED "$delay_single_quote_subst"`' +reload_cmds='`$ECHO "$reload_cmds" | $SED "$delay_single_quote_subst"`' +deplibs_check_method='`$ECHO "$deplibs_check_method" | $SED "$delay_single_quote_subst"`' +file_magic_cmd='`$ECHO "$file_magic_cmd" | $SED "$delay_single_quote_subst"`' +file_magic_glob='`$ECHO "$file_magic_glob" | $SED "$delay_single_quote_subst"`' +want_nocaseglob='`$ECHO "$want_nocaseglob" | $SED "$delay_single_quote_subst"`' +sharedlib_from_linklib_cmd='`$ECHO "$sharedlib_from_linklib_cmd" | $SED "$delay_single_quote_subst"`' +AR='`$ECHO "$AR" | $SED "$delay_single_quote_subst"`' +AR_FLAGS='`$ECHO "$AR_FLAGS" | $SED "$delay_single_quote_subst"`' +archiver_list_spec='`$ECHO "$archiver_list_spec" | $SED "$delay_single_quote_subst"`' +STRIP='`$ECHO "$STRIP" | $SED "$delay_single_quote_subst"`' +RANLIB='`$ECHO "$RANLIB" | $SED "$delay_single_quote_subst"`' +old_postinstall_cmds='`$ECHO "$old_postinstall_cmds" | $SED "$delay_single_quote_subst"`' +old_postuninstall_cmds='`$ECHO "$old_postuninstall_cmds" | $SED "$delay_single_quote_subst"`' +old_archive_cmds='`$ECHO "$old_archive_cmds" | $SED "$delay_single_quote_subst"`' +lock_old_archive_extraction='`$ECHO "$lock_old_archive_extraction" | $SED "$delay_single_quote_subst"`' +CC='`$ECHO "$CC" | $SED "$delay_single_quote_subst"`' +CFLAGS='`$ECHO "$CFLAGS" | $SED "$delay_single_quote_subst"`' +compiler='`$ECHO "$compiler" | $SED "$delay_single_quote_subst"`' +GCC='`$ECHO "$GCC" | $SED "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_pipe='`$ECHO "$lt_cv_sys_global_symbol_pipe" | $SED "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_to_cdecl='`$ECHO "$lt_cv_sys_global_symbol_to_cdecl" | $SED "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_to_c_name_address='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address" | $SED "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_to_c_name_address_lib_prefix='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address_lib_prefix" | $SED "$delay_single_quote_subst"`' +nm_file_list_spec='`$ECHO "$nm_file_list_spec" | $SED "$delay_single_quote_subst"`' +lt_sysroot='`$ECHO "$lt_sysroot" | $SED "$delay_single_quote_subst"`' +objdir='`$ECHO "$objdir" | $SED "$delay_single_quote_subst"`' +MAGIC_CMD='`$ECHO "$MAGIC_CMD" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_no_builtin_flag='`$ECHO "$lt_prog_compiler_no_builtin_flag" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_pic='`$ECHO "$lt_prog_compiler_pic" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_wl='`$ECHO "$lt_prog_compiler_wl" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_static='`$ECHO "$lt_prog_compiler_static" | $SED "$delay_single_quote_subst"`' +lt_cv_prog_compiler_c_o='`$ECHO "$lt_cv_prog_compiler_c_o" | $SED "$delay_single_quote_subst"`' +need_locks='`$ECHO "$need_locks" | $SED "$delay_single_quote_subst"`' +MANIFEST_TOOL='`$ECHO "$MANIFEST_TOOL" | $SED "$delay_single_quote_subst"`' +DSYMUTIL='`$ECHO "$DSYMUTIL" | $SED "$delay_single_quote_subst"`' +NMEDIT='`$ECHO "$NMEDIT" | $SED "$delay_single_quote_subst"`' +LIPO='`$ECHO "$LIPO" | $SED "$delay_single_quote_subst"`' +OTOOL='`$ECHO "$OTOOL" | $SED "$delay_single_quote_subst"`' +OTOOL64='`$ECHO "$OTOOL64" | $SED "$delay_single_quote_subst"`' +libext='`$ECHO "$libext" | $SED "$delay_single_quote_subst"`' +shrext_cmds='`$ECHO "$shrext_cmds" | $SED "$delay_single_quote_subst"`' +extract_expsyms_cmds='`$ECHO "$extract_expsyms_cmds" | $SED "$delay_single_quote_subst"`' +archive_cmds_need_lc='`$ECHO "$archive_cmds_need_lc" | $SED "$delay_single_quote_subst"`' +enable_shared_with_static_runtimes='`$ECHO "$enable_shared_with_static_runtimes" | $SED "$delay_single_quote_subst"`' +export_dynamic_flag_spec='`$ECHO "$export_dynamic_flag_spec" | $SED "$delay_single_quote_subst"`' +whole_archive_flag_spec='`$ECHO "$whole_archive_flag_spec" | $SED "$delay_single_quote_subst"`' +compiler_needs_object='`$ECHO "$compiler_needs_object" | $SED "$delay_single_quote_subst"`' +old_archive_from_new_cmds='`$ECHO "$old_archive_from_new_cmds" | $SED "$delay_single_quote_subst"`' +old_archive_from_expsyms_cmds='`$ECHO "$old_archive_from_expsyms_cmds" | $SED "$delay_single_quote_subst"`' +archive_cmds='`$ECHO "$archive_cmds" | $SED "$delay_single_quote_subst"`' +archive_expsym_cmds='`$ECHO "$archive_expsym_cmds" | $SED "$delay_single_quote_subst"`' +module_cmds='`$ECHO "$module_cmds" | $SED "$delay_single_quote_subst"`' +module_expsym_cmds='`$ECHO "$module_expsym_cmds" | $SED "$delay_single_quote_subst"`' +with_gnu_ld='`$ECHO "$with_gnu_ld" | $SED "$delay_single_quote_subst"`' +allow_undefined_flag='`$ECHO "$allow_undefined_flag" | $SED "$delay_single_quote_subst"`' +no_undefined_flag='`$ECHO "$no_undefined_flag" | $SED "$delay_single_quote_subst"`' +hardcode_libdir_flag_spec='`$ECHO "$hardcode_libdir_flag_spec" | $SED "$delay_single_quote_subst"`' +hardcode_libdir_separator='`$ECHO "$hardcode_libdir_separator" | $SED "$delay_single_quote_subst"`' +hardcode_direct='`$ECHO "$hardcode_direct" | $SED "$delay_single_quote_subst"`' +hardcode_direct_absolute='`$ECHO "$hardcode_direct_absolute" | $SED "$delay_single_quote_subst"`' +hardcode_minus_L='`$ECHO "$hardcode_minus_L" | $SED "$delay_single_quote_subst"`' +hardcode_shlibpath_var='`$ECHO "$hardcode_shlibpath_var" | $SED "$delay_single_quote_subst"`' +hardcode_automatic='`$ECHO "$hardcode_automatic" | $SED "$delay_single_quote_subst"`' +inherit_rpath='`$ECHO "$inherit_rpath" | $SED "$delay_single_quote_subst"`' +link_all_deplibs='`$ECHO "$link_all_deplibs" | $SED "$delay_single_quote_subst"`' +always_export_symbols='`$ECHO "$always_export_symbols" | $SED "$delay_single_quote_subst"`' +export_symbols_cmds='`$ECHO "$export_symbols_cmds" | $SED "$delay_single_quote_subst"`' +exclude_expsyms='`$ECHO "$exclude_expsyms" | $SED "$delay_single_quote_subst"`' +include_expsyms='`$ECHO "$include_expsyms" | $SED "$delay_single_quote_subst"`' +prelink_cmds='`$ECHO "$prelink_cmds" | $SED "$delay_single_quote_subst"`' +postlink_cmds='`$ECHO "$postlink_cmds" | $SED "$delay_single_quote_subst"`' +file_list_spec='`$ECHO "$file_list_spec" | $SED "$delay_single_quote_subst"`' +variables_saved_for_relink='`$ECHO "$variables_saved_for_relink" | $SED "$delay_single_quote_subst"`' +need_lib_prefix='`$ECHO "$need_lib_prefix" | $SED "$delay_single_quote_subst"`' +need_version='`$ECHO "$need_version" | $SED "$delay_single_quote_subst"`' +version_type='`$ECHO "$version_type" | $SED "$delay_single_quote_subst"`' +runpath_var='`$ECHO "$runpath_var" | $SED "$delay_single_quote_subst"`' +shlibpath_var='`$ECHO "$shlibpath_var" | $SED "$delay_single_quote_subst"`' +shlibpath_overrides_runpath='`$ECHO "$shlibpath_overrides_runpath" | $SED "$delay_single_quote_subst"`' +libname_spec='`$ECHO "$libname_spec" | $SED "$delay_single_quote_subst"`' +library_names_spec='`$ECHO "$library_names_spec" | $SED "$delay_single_quote_subst"`' +soname_spec='`$ECHO "$soname_spec" | $SED "$delay_single_quote_subst"`' +install_override_mode='`$ECHO "$install_override_mode" | $SED "$delay_single_quote_subst"`' +postinstall_cmds='`$ECHO "$postinstall_cmds" | $SED "$delay_single_quote_subst"`' +postuninstall_cmds='`$ECHO "$postuninstall_cmds" | $SED "$delay_single_quote_subst"`' +finish_cmds='`$ECHO "$finish_cmds" | $SED "$delay_single_quote_subst"`' +finish_eval='`$ECHO "$finish_eval" | $SED "$delay_single_quote_subst"`' +hardcode_into_libs='`$ECHO "$hardcode_into_libs" | $SED "$delay_single_quote_subst"`' +sys_lib_search_path_spec='`$ECHO "$sys_lib_search_path_spec" | $SED "$delay_single_quote_subst"`' +sys_lib_dlsearch_path_spec='`$ECHO "$sys_lib_dlsearch_path_spec" | $SED "$delay_single_quote_subst"`' +hardcode_action='`$ECHO "$hardcode_action" | $SED "$delay_single_quote_subst"`' +enable_dlopen='`$ECHO "$enable_dlopen" | $SED "$delay_single_quote_subst"`' +enable_dlopen_self='`$ECHO "$enable_dlopen_self" | $SED "$delay_single_quote_subst"`' +enable_dlopen_self_static='`$ECHO "$enable_dlopen_self_static" | $SED "$delay_single_quote_subst"`' +old_striplib='`$ECHO "$old_striplib" | $SED "$delay_single_quote_subst"`' +striplib='`$ECHO "$striplib" | $SED "$delay_single_quote_subst"`' +compiler_lib_search_dirs='`$ECHO "$compiler_lib_search_dirs" | $SED "$delay_single_quote_subst"`' +predep_objects='`$ECHO "$predep_objects" | $SED "$delay_single_quote_subst"`' +postdep_objects='`$ECHO "$postdep_objects" | $SED "$delay_single_quote_subst"`' +predeps='`$ECHO "$predeps" | $SED "$delay_single_quote_subst"`' +postdeps='`$ECHO "$postdeps" | $SED "$delay_single_quote_subst"`' +compiler_lib_search_path='`$ECHO "$compiler_lib_search_path" | $SED "$delay_single_quote_subst"`' +LD_CXX='`$ECHO "$LD_CXX" | $SED "$delay_single_quote_subst"`' +reload_flag_CXX='`$ECHO "$reload_flag_CXX" | $SED "$delay_single_quote_subst"`' +reload_cmds_CXX='`$ECHO "$reload_cmds_CXX" | $SED "$delay_single_quote_subst"`' +old_archive_cmds_CXX='`$ECHO "$old_archive_cmds_CXX" | $SED "$delay_single_quote_subst"`' +compiler_CXX='`$ECHO "$compiler_CXX" | $SED "$delay_single_quote_subst"`' +GCC_CXX='`$ECHO "$GCC_CXX" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_no_builtin_flag_CXX='`$ECHO "$lt_prog_compiler_no_builtin_flag_CXX" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_pic_CXX='`$ECHO "$lt_prog_compiler_pic_CXX" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_wl_CXX='`$ECHO "$lt_prog_compiler_wl_CXX" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_static_CXX='`$ECHO "$lt_prog_compiler_static_CXX" | $SED "$delay_single_quote_subst"`' +lt_cv_prog_compiler_c_o_CXX='`$ECHO "$lt_cv_prog_compiler_c_o_CXX" | $SED "$delay_single_quote_subst"`' +archive_cmds_need_lc_CXX='`$ECHO "$archive_cmds_need_lc_CXX" | $SED "$delay_single_quote_subst"`' +enable_shared_with_static_runtimes_CXX='`$ECHO "$enable_shared_with_static_runtimes_CXX" | $SED "$delay_single_quote_subst"`' +export_dynamic_flag_spec_CXX='`$ECHO "$export_dynamic_flag_spec_CXX" | $SED "$delay_single_quote_subst"`' +whole_archive_flag_spec_CXX='`$ECHO "$whole_archive_flag_spec_CXX" | $SED "$delay_single_quote_subst"`' +compiler_needs_object_CXX='`$ECHO "$compiler_needs_object_CXX" | $SED "$delay_single_quote_subst"`' +old_archive_from_new_cmds_CXX='`$ECHO "$old_archive_from_new_cmds_CXX" | $SED "$delay_single_quote_subst"`' +old_archive_from_expsyms_cmds_CXX='`$ECHO "$old_archive_from_expsyms_cmds_CXX" | $SED "$delay_single_quote_subst"`' +archive_cmds_CXX='`$ECHO "$archive_cmds_CXX" | $SED "$delay_single_quote_subst"`' +archive_expsym_cmds_CXX='`$ECHO "$archive_expsym_cmds_CXX" | $SED "$delay_single_quote_subst"`' +module_cmds_CXX='`$ECHO "$module_cmds_CXX" | $SED "$delay_single_quote_subst"`' +module_expsym_cmds_CXX='`$ECHO "$module_expsym_cmds_CXX" | $SED "$delay_single_quote_subst"`' +with_gnu_ld_CXX='`$ECHO "$with_gnu_ld_CXX" | $SED "$delay_single_quote_subst"`' +allow_undefined_flag_CXX='`$ECHO "$allow_undefined_flag_CXX" | $SED "$delay_single_quote_subst"`' +no_undefined_flag_CXX='`$ECHO "$no_undefined_flag_CXX" | $SED "$delay_single_quote_subst"`' +hardcode_libdir_flag_spec_CXX='`$ECHO "$hardcode_libdir_flag_spec_CXX" | $SED "$delay_single_quote_subst"`' +hardcode_libdir_separator_CXX='`$ECHO "$hardcode_libdir_separator_CXX" | $SED "$delay_single_quote_subst"`' +hardcode_direct_CXX='`$ECHO "$hardcode_direct_CXX" | $SED "$delay_single_quote_subst"`' +hardcode_direct_absolute_CXX='`$ECHO "$hardcode_direct_absolute_CXX" | $SED "$delay_single_quote_subst"`' +hardcode_minus_L_CXX='`$ECHO "$hardcode_minus_L_CXX" | $SED "$delay_single_quote_subst"`' +hardcode_shlibpath_var_CXX='`$ECHO "$hardcode_shlibpath_var_CXX" | $SED "$delay_single_quote_subst"`' +hardcode_automatic_CXX='`$ECHO "$hardcode_automatic_CXX" | $SED "$delay_single_quote_subst"`' +inherit_rpath_CXX='`$ECHO "$inherit_rpath_CXX" | $SED "$delay_single_quote_subst"`' +link_all_deplibs_CXX='`$ECHO "$link_all_deplibs_CXX" | $SED "$delay_single_quote_subst"`' +always_export_symbols_CXX='`$ECHO "$always_export_symbols_CXX" | $SED "$delay_single_quote_subst"`' +export_symbols_cmds_CXX='`$ECHO "$export_symbols_cmds_CXX" | $SED "$delay_single_quote_subst"`' +exclude_expsyms_CXX='`$ECHO "$exclude_expsyms_CXX" | $SED "$delay_single_quote_subst"`' +include_expsyms_CXX='`$ECHO "$include_expsyms_CXX" | $SED "$delay_single_quote_subst"`' +prelink_cmds_CXX='`$ECHO "$prelink_cmds_CXX" | $SED "$delay_single_quote_subst"`' +postlink_cmds_CXX='`$ECHO "$postlink_cmds_CXX" | $SED "$delay_single_quote_subst"`' +file_list_spec_CXX='`$ECHO "$file_list_spec_CXX" | $SED "$delay_single_quote_subst"`' +hardcode_action_CXX='`$ECHO "$hardcode_action_CXX" | $SED "$delay_single_quote_subst"`' +compiler_lib_search_dirs_CXX='`$ECHO "$compiler_lib_search_dirs_CXX" | $SED "$delay_single_quote_subst"`' +predep_objects_CXX='`$ECHO "$predep_objects_CXX" | $SED "$delay_single_quote_subst"`' +postdep_objects_CXX='`$ECHO "$postdep_objects_CXX" | $SED "$delay_single_quote_subst"`' +predeps_CXX='`$ECHO "$predeps_CXX" | $SED "$delay_single_quote_subst"`' +postdeps_CXX='`$ECHO "$postdeps_CXX" | $SED "$delay_single_quote_subst"`' +compiler_lib_search_path_CXX='`$ECHO "$compiler_lib_search_path_CXX" | $SED "$delay_single_quote_subst"`' + +LTCC='$LTCC' +LTCFLAGS='$LTCFLAGS' +compiler='$compiler_DEFAULT' + +# A function that is used when there is no print builtin or printf. +func_fallback_echo () +{ + eval 'cat <<_LTECHO_EOF +\$1 +_LTECHO_EOF' +} + +# Quote evaled strings. +for var in AS \ +DLLTOOL \ +OBJDUMP \ +SHELL \ +ECHO \ +PATH_SEPARATOR \ +SED \ +GREP \ +EGREP \ +FGREP \ +LD \ +NM \ +LN_S \ +lt_SP2NL \ +lt_NL2SP \ +reload_flag \ +deplibs_check_method \ +file_magic_cmd \ +file_magic_glob \ +want_nocaseglob \ +sharedlib_from_linklib_cmd \ +AR \ +AR_FLAGS \ +archiver_list_spec \ +STRIP \ +RANLIB \ +CC \ +CFLAGS \ +compiler \ +lt_cv_sys_global_symbol_pipe \ +lt_cv_sys_global_symbol_to_cdecl \ +lt_cv_sys_global_symbol_to_c_name_address \ +lt_cv_sys_global_symbol_to_c_name_address_lib_prefix \ +nm_file_list_spec \ +lt_prog_compiler_no_builtin_flag \ +lt_prog_compiler_pic \ +lt_prog_compiler_wl \ +lt_prog_compiler_static \ +lt_cv_prog_compiler_c_o \ +need_locks \ +MANIFEST_TOOL \ +DSYMUTIL \ +NMEDIT \ +LIPO \ +OTOOL \ +OTOOL64 \ +shrext_cmds \ +export_dynamic_flag_spec \ +whole_archive_flag_spec \ +compiler_needs_object \ +with_gnu_ld \ +allow_undefined_flag \ +no_undefined_flag \ +hardcode_libdir_flag_spec \ +hardcode_libdir_separator \ +exclude_expsyms \ +include_expsyms \ +file_list_spec \ +variables_saved_for_relink \ +libname_spec \ +library_names_spec \ +soname_spec \ +install_override_mode \ +finish_eval \ +old_striplib \ +striplib \ +compiler_lib_search_dirs \ +predep_objects \ +postdep_objects \ +predeps \ +postdeps \ +compiler_lib_search_path \ +LD_CXX \ +reload_flag_CXX \ +compiler_CXX \ +lt_prog_compiler_no_builtin_flag_CXX \ +lt_prog_compiler_pic_CXX \ +lt_prog_compiler_wl_CXX \ +lt_prog_compiler_static_CXX \ +lt_cv_prog_compiler_c_o_CXX \ +export_dynamic_flag_spec_CXX \ +whole_archive_flag_spec_CXX \ +compiler_needs_object_CXX \ +with_gnu_ld_CXX \ +allow_undefined_flag_CXX \ +no_undefined_flag_CXX \ +hardcode_libdir_flag_spec_CXX \ +hardcode_libdir_separator_CXX \ +exclude_expsyms_CXX \ +include_expsyms_CXX \ +file_list_spec_CXX \ +compiler_lib_search_dirs_CXX \ +predep_objects_CXX \ +postdep_objects_CXX \ +predeps_CXX \ +postdeps_CXX \ +compiler_lib_search_path_CXX; do + case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in + *[\\\\\\\`\\"\\\$]*) + eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" + ;; + *) + eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" + ;; + esac +done + +# Double-quote double-evaled strings. +for var in reload_cmds \ +old_postinstall_cmds \ +old_postuninstall_cmds \ +old_archive_cmds \ +extract_expsyms_cmds \ +old_archive_from_new_cmds \ +old_archive_from_expsyms_cmds \ +archive_cmds \ +archive_expsym_cmds \ +module_cmds \ +module_expsym_cmds \ +export_symbols_cmds \ +prelink_cmds \ +postlink_cmds \ +postinstall_cmds \ +postuninstall_cmds \ +finish_cmds \ +sys_lib_search_path_spec \ +sys_lib_dlsearch_path_spec \ +reload_cmds_CXX \ +old_archive_cmds_CXX \ +old_archive_from_new_cmds_CXX \ +old_archive_from_expsyms_cmds_CXX \ +archive_cmds_CXX \ +archive_expsym_cmds_CXX \ +module_cmds_CXX \ +module_expsym_cmds_CXX \ +export_symbols_cmds_CXX \ +prelink_cmds_CXX \ +postlink_cmds_CXX; do + case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in + *[\\\\\\\`\\"\\\$]*) + eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" + ;; + *) + eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" + ;; + esac +done + +ac_aux_dir='$ac_aux_dir' +xsi_shell='$xsi_shell' +lt_shell_append='$lt_shell_append' + +# See if we are running on zsh, and set the options which allow our +# commands through without removal of \ escapes INIT. +if test -n "\${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST +fi + + + PACKAGE='$PACKAGE' + VERSION='$VERSION' + TIMESTAMP='$TIMESTAMP' + RM='$RM' + ofile='$ofile' + + + + + + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 + +# Handling of arguments. +for ac_config_target in $ac_config_targets +do + case $ac_config_target in + "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;; + "libtool") CONFIG_COMMANDS="$CONFIG_COMMANDS libtool" ;; + "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; + "lib/Makefile") CONFIG_FILES="$CONFIG_FILES lib/Makefile" ;; + "include/Makefile") CONFIG_FILES="$CONFIG_FILES include/Makefile" ;; + "bin/Makefile") CONFIG_FILES="$CONFIG_FILES bin/Makefile" ;; + "doc/Makefile") CONFIG_FILES="$CONFIG_FILES doc/Makefile" ;; + "portaudiocpp.pc") CONFIG_FILES="$CONFIG_FILES portaudiocpp.pc" ;; + + *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; + esac +done + + +# If the user did not use the arguments to specify the items to instantiate, +# then the envvar interface is used. Set only those that are not. +# We use the long form for the default assignment because of an extremely +# bizarre bug on SunOS 4.1.3. +if $ac_need_defaults; then + test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files + test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands +fi + +# Have a temporary directory for convenience. Make it in the build tree +# simply because there is no reason against having it here, and in addition, +# creating and moving files from /tmp can sometimes cause problems. +# Hook for its removal unless debugging. +# Note that there is a small window in which the directory will not be cleaned: +# after its creation but before its name has been assigned to `$tmp'. +$debug || +{ + tmp= ac_tmp= + trap 'exit_status=$? + : "${ac_tmp:=$tmp}" + { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status +' 0 + trap 'as_fn_exit 1' 1 2 13 15 +} +# Create a (secure) tmp directory for tmp files. + +{ + tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && + test -d "$tmp" +} || +{ + tmp=./conf$$-$RANDOM + (umask 077 && mkdir "$tmp") +} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 +ac_tmp=$tmp + +# Set up the scripts for CONFIG_FILES section. +# No need to generate them if there are no CONFIG_FILES. +# This happens for instance with `./config.status config.h'. +if test -n "$CONFIG_FILES"; then + + +ac_cr=`echo X | tr X '\015'` +# On cygwin, bash can eat \r inside `` if the user requested igncr. +# But we know of no other shell where ac_cr would be empty at this +# point, so we can use a bashism as a fallback. +if test "x$ac_cr" = x; then + eval ac_cr=\$\'\\r\' +fi +ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` +if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then + ac_cs_awk_cr='\\r' +else + ac_cs_awk_cr=$ac_cr +fi + +echo 'BEGIN {' >"$ac_tmp/subs1.awk" && +_ACEOF + + +{ + echo "cat >conf$$subs.awk <<_ACEOF" && + echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && + echo "_ACEOF" +} >conf$$subs.sh || + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 +ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` +ac_delim='%!_!# ' +for ac_last_try in false false false false false :; do + . ./conf$$subs.sh || + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 + + ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` + if test $ac_delim_n = $ac_delim_num; then + break + elif $ac_last_try; then + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done +rm -f conf$$subs.sh + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && +_ACEOF +sed -n ' +h +s/^/S["/; s/!.*/"]=/ +p +g +s/^[^!]*!// +:repl +t repl +s/'"$ac_delim"'$// +t delim +:nl +h +s/\(.\{148\}\)..*/\1/ +t more1 +s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ +p +n +b repl +:more1 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t nl +:delim +h +s/\(.\{148\}\)..*/\1/ +t more2 +s/["\\]/\\&/g; s/^/"/; s/$/"/ +p +b +:more2 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t delim +' >$CONFIG_STATUS || ac_write_fail=1 +rm -f conf$$subs.awk +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +_ACAWK +cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && + for (key in S) S_is_set[key] = 1 + FS = "" + +} +{ + line = $ 0 + nfields = split(line, field, "@") + substed = 0 + len = length(field[1]) + for (i = 2; i < nfields; i++) { + key = field[i] + keylen = length(key) + if (S_is_set[key]) { + value = S[key] + line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) + len += length(value) + length(field[++i]) + substed = 1 + } else + len += 1 + keylen + } + + print line +} + +_ACAWK +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then + sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" +else + cat +fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ + || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 +_ACEOF + +# VPATH may cause trouble with some makes, so we remove sole $(srcdir), +# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and +# trailing colons and then remove the whole line if VPATH becomes empty +# (actually we leave an empty line to preserve line numbers). +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ +h +s/// +s/^/:/ +s/[ ]*$/:/ +s/:\$(srcdir):/:/g +s/:\${srcdir}:/:/g +s/:@srcdir@:/:/g +s/^:*// +s/:*$// +x +s/\(=[ ]*\).*/\1/ +G +s/\n// +s/^[^=]*=[ ]*$// +}' +fi + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +fi # test -n "$CONFIG_FILES" + + +eval set X " :F $CONFIG_FILES :C $CONFIG_COMMANDS" +shift +for ac_tag +do + case $ac_tag in + :[FHLC]) ac_mode=$ac_tag; continue;; + esac + case $ac_mode$ac_tag in + :[FHL]*:*);; + :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; + :[FH]-) ac_tag=-:-;; + :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; + esac + ac_save_IFS=$IFS + IFS=: + set x $ac_tag + IFS=$ac_save_IFS + shift + ac_file=$1 + shift + + case $ac_mode in + :L) ac_source=$1;; + :[FH]) + ac_file_inputs= + for ac_f + do + case $ac_f in + -) ac_f="$ac_tmp/stdin";; + *) # Look for the file first in the build tree, then in the source tree + # (if the path is not absolute). The absolute path cannot be DOS-style, + # because $ac_f cannot contain `:'. + test -f "$ac_f" || + case $ac_f in + [\\/$]*) false;; + *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; + esac || + as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; + esac + case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac + as_fn_append ac_file_inputs " '$ac_f'" + done + + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + configure_input='Generated from '` + $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' + `' by configure.' + if test x"$ac_file" != x-; then + configure_input="$ac_file. $configure_input" + { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 +$as_echo "$as_me: creating $ac_file" >&6;} + fi + # Neutralize special characters interpreted by sed in replacement strings. + case $configure_input in #( + *\&* | *\|* | *\\* ) + ac_sed_conf_input=`$as_echo "$configure_input" | + sed 's/[\\\\&|]/\\\\&/g'`;; #( + *) ac_sed_conf_input=$configure_input;; + esac + + case $ac_tag in + *:-:* | *:-) cat >"$ac_tmp/stdin" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; + esac + ;; + esac + + ac_dir=`$as_dirname -- "$ac_file" || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + as_dir="$ac_dir"; as_fn_mkdir_p + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + + case $ac_mode in + :F) + # + # CONFIG_FILE + # + + case $INSTALL in + [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; + *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; + esac + ac_MKDIR_P=$MKDIR_P + case $MKDIR_P in + [\\/$]* | ?:[\\/]* ) ;; + */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;; + esac +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# If the template does not know about datarootdir, expand it. +# FIXME: This hack should be removed a few years after 2.60. +ac_datarootdir_hack=; ac_datarootdir_seen= +ac_sed_dataroot=' +/datarootdir/ { + p + q +} +/@datadir@/p +/@docdir@/p +/@infodir@/p +/@localedir@/p +/@mandir@/p' +case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in +*datarootdir*) ac_datarootdir_seen=yes;; +*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 +$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 + ac_datarootdir_hack=' + s&@datadir@&$datadir&g + s&@docdir@&$docdir&g + s&@infodir@&$infodir&g + s&@localedir@&$localedir&g + s&@mandir@&$mandir&g + s&\\\${datarootdir}&$datarootdir&g' ;; +esac +_ACEOF + +# Neutralize VPATH when `$srcdir' = `.'. +# Shell code in configure.ac might set extrasub. +# FIXME: do we really want to maintain this feature? +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_sed_extra="$ac_vpsub +$extrasub +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +:t +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +s|@configure_input@|$ac_sed_conf_input|;t t +s&@top_builddir@&$ac_top_builddir_sub&;t t +s&@top_build_prefix@&$ac_top_build_prefix&;t t +s&@srcdir@&$ac_srcdir&;t t +s&@abs_srcdir@&$ac_abs_srcdir&;t t +s&@top_srcdir@&$ac_top_srcdir&;t t +s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t +s&@builddir@&$ac_builddir&;t t +s&@abs_builddir@&$ac_abs_builddir&;t t +s&@abs_top_builddir@&$ac_abs_top_builddir&;t t +s&@INSTALL@&$ac_INSTALL&;t t +s&@MKDIR_P@&$ac_MKDIR_P&;t t +$ac_datarootdir_hack +" +eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ + >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + +test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && + { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && + { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ + "$ac_tmp/out"`; test -z "$ac_out"; } && + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined" >&5 +$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined" >&2;} + + rm -f "$ac_tmp/stdin" + case $ac_file in + -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; + *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; + esac \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + ;; + + + :C) { $as_echo "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5 +$as_echo "$as_me: executing $ac_file commands" >&6;} + ;; + esac + + + case $ac_file$ac_mode in + "depfiles":C) test x"$AMDEP_TRUE" != x"" || { + # Older Autoconf quotes --file arguments for eval, but not when files + # are listed without --file. Let's play safe and only enable the eval + # if we detect the quoting. + case $CONFIG_FILES in + *\'*) eval set x "$CONFIG_FILES" ;; + *) set x $CONFIG_FILES ;; + esac + shift + for mf + do + # Strip MF so we end up with the name of the file. + mf=`echo "$mf" | sed -e 's/:.*$//'` + # Check whether this is an Automake generated Makefile or not. + # We used to match only the files named 'Makefile.in', but + # some people rename them; so instead we look at the file content. + # Grep'ing the first line is not enough: some people post-process + # each Makefile.in and add a new line on top of each file to say so. + # Grep'ing the whole file is not good either: AIX grep has a line + # limit of 2048, but all sed's we know have understand at least 4000. + if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then + dirpart=`$as_dirname -- "$mf" || +$as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$mf" : 'X\(//\)[^/]' \| \ + X"$mf" : 'X\(//\)$' \| \ + X"$mf" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$mf" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + else + continue + fi + # Extract the definition of DEPDIR, am__include, and am__quote + # from the Makefile without running 'make'. + DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` + test -z "$DEPDIR" && continue + am__include=`sed -n 's/^am__include = //p' < "$mf"` + test -z "$am__include" && continue + am__quote=`sed -n 's/^am__quote = //p' < "$mf"` + # Find all dependency output files, they are included files with + # $(DEPDIR) in their names. We invoke sed twice because it is the + # simplest approach to changing $(DEPDIR) to its actual value in the + # expansion. + for file in `sed -n " + s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ + sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g'`; do + # Make sure the directory exists. + test -f "$dirpart/$file" && continue + fdir=`$as_dirname -- "$file" || +$as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$file" : 'X\(//\)[^/]' \| \ + X"$file" : 'X\(//\)$' \| \ + X"$file" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + as_dir=$dirpart/$fdir; as_fn_mkdir_p + # echo "creating $dirpart/$file" + echo '# dummy' > "$dirpart/$file" + done + done +} + ;; + "libtool":C) + + # See if we are running on zsh, and set the options which allow our + # commands through without removal of \ escapes. + if test -n "${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST + fi + + cfgfile="${ofile}T" + trap "$RM \"$cfgfile\"; exit 1" 1 2 15 + $RM "$cfgfile" + + cat <<_LT_EOF >> "$cfgfile" +#! $SHELL + +# `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services. +# Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION +# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: +# NOTE: Changes made to this file will be lost: look at ltmain.sh. +# +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, +# 2006, 2007, 2008, 2009, 2010, 2011 Free Software +# Foundation, Inc. +# Written by Gordon Matzigkeit, 1996 +# +# This file is part of GNU Libtool. +# +# GNU Libtool is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# As a special exception to the GNU General Public License, +# if you distribute this file as part of a program or library that +# is built using GNU Libtool, you may include this file under the +# same distribution terms that you use for the rest of that program. +# +# GNU Libtool is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Libtool; see the file COPYING. If not, a copy +# can be downloaded from http://www.gnu.org/licenses/gpl.html, or +# obtained by writing to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + +# The names of the tagged configurations supported by this script. +available_tags="CXX " + +# ### BEGIN LIBTOOL CONFIG + +# Assembler program. +AS=$lt_AS + +# DLL creation program. +DLLTOOL=$lt_DLLTOOL + +# Object dumper program. +OBJDUMP=$lt_OBJDUMP + +# Which release of libtool.m4 was used? +macro_version=$macro_version +macro_revision=$macro_revision + +# Whether or not to build shared libraries. +build_libtool_libs=$enable_shared + +# Whether or not to build static libraries. +build_old_libs=$enable_static + +# What type of objects to build. +pic_mode=$pic_mode + +# Whether or not to optimize for fast installation. +fast_install=$enable_fast_install + +# Shell to use when invoking shell scripts. +SHELL=$lt_SHELL + +# An echo program that protects backslashes. +ECHO=$lt_ECHO + +# The PATH separator for the build system. +PATH_SEPARATOR=$lt_PATH_SEPARATOR + +# The host system. +host_alias=$host_alias +host=$host +host_os=$host_os + +# The build system. +build_alias=$build_alias +build=$build +build_os=$build_os + +# A sed program that does not truncate output. +SED=$lt_SED + +# Sed that helps us avoid accidentally triggering echo(1) options like -n. +Xsed="\$SED -e 1s/^X//" + +# A grep program that handles long lines. +GREP=$lt_GREP + +# An ERE matcher. +EGREP=$lt_EGREP + +# A literal string matcher. +FGREP=$lt_FGREP + +# A BSD- or MS-compatible name lister. +NM=$lt_NM + +# Whether we need soft or hard links. +LN_S=$lt_LN_S + +# What is the maximum length of a command? +max_cmd_len=$max_cmd_len + +# Object file suffix (normally "o"). +objext=$ac_objext + +# Executable file suffix (normally ""). +exeext=$exeext + +# whether the shell understands "unset". +lt_unset=$lt_unset + +# turn spaces into newlines. +SP2NL=$lt_lt_SP2NL + +# turn newlines into spaces. +NL2SP=$lt_lt_NL2SP + +# convert \$build file names to \$host format. +to_host_file_cmd=$lt_cv_to_host_file_cmd + +# convert \$build files to toolchain format. +to_tool_file_cmd=$lt_cv_to_tool_file_cmd + +# Method to check whether dependent libraries are shared objects. +deplibs_check_method=$lt_deplibs_check_method + +# Command to use when deplibs_check_method = "file_magic". +file_magic_cmd=$lt_file_magic_cmd + +# How to find potential files when deplibs_check_method = "file_magic". +file_magic_glob=$lt_file_magic_glob + +# Find potential files using nocaseglob when deplibs_check_method = "file_magic". +want_nocaseglob=$lt_want_nocaseglob + +# Command to associate shared and link libraries. +sharedlib_from_linklib_cmd=$lt_sharedlib_from_linklib_cmd + +# The archiver. +AR=$lt_AR + +# Flags to create an archive. +AR_FLAGS=$lt_AR_FLAGS + +# How to feed a file listing to the archiver. +archiver_list_spec=$lt_archiver_list_spec + +# A symbol stripping program. +STRIP=$lt_STRIP + +# Commands used to install an old-style archive. +RANLIB=$lt_RANLIB +old_postinstall_cmds=$lt_old_postinstall_cmds +old_postuninstall_cmds=$lt_old_postuninstall_cmds + +# Whether to use a lock for old archive extraction. +lock_old_archive_extraction=$lock_old_archive_extraction + +# A C compiler. +LTCC=$lt_CC + +# LTCC compiler flags. +LTCFLAGS=$lt_CFLAGS + +# Take the output of nm and produce a listing of raw symbols and C names. +global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe + +# Transform the output of nm in a proper C declaration. +global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl + +# Transform the output of nm in a C name address pair. +global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address + +# Transform the output of nm in a C name address pair when lib prefix is needed. +global_symbol_to_c_name_address_lib_prefix=$lt_lt_cv_sys_global_symbol_to_c_name_address_lib_prefix + +# Specify filename containing input files for \$NM. +nm_file_list_spec=$lt_nm_file_list_spec + +# The root where to search for dependent libraries,and in which our libraries should be installed. +lt_sysroot=$lt_sysroot + +# The name of the directory that contains temporary libtool files. +objdir=$objdir + +# Used to examine libraries when file_magic_cmd begins with "file". +MAGIC_CMD=$MAGIC_CMD + +# Must we lock files when doing compilation? +need_locks=$lt_need_locks + +# Manifest tool. +MANIFEST_TOOL=$lt_MANIFEST_TOOL + +# Tool to manipulate archived DWARF debug symbol files on Mac OS X. +DSYMUTIL=$lt_DSYMUTIL + +# Tool to change global to local symbols on Mac OS X. +NMEDIT=$lt_NMEDIT + +# Tool to manipulate fat objects and archives on Mac OS X. +LIPO=$lt_LIPO + +# ldd/readelf like tool for Mach-O binaries on Mac OS X. +OTOOL=$lt_OTOOL + +# ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4. +OTOOL64=$lt_OTOOL64 + +# Old archive suffix (normally "a"). +libext=$libext + +# Shared library suffix (normally ".so"). +shrext_cmds=$lt_shrext_cmds + +# The commands to extract the exported symbol list from a shared archive. +extract_expsyms_cmds=$lt_extract_expsyms_cmds + +# Variables whose values should be saved in libtool wrapper scripts and +# restored at link time. +variables_saved_for_relink=$lt_variables_saved_for_relink + +# Do we need the "lib" prefix for modules? +need_lib_prefix=$need_lib_prefix + +# Do we need a version for libraries? +need_version=$need_version + +# Library versioning type. +version_type=$version_type + +# Shared library runtime path variable. +runpath_var=$runpath_var + +# Shared library path variable. +shlibpath_var=$shlibpath_var + +# Is shlibpath searched before the hard-coded library search path? +shlibpath_overrides_runpath=$shlibpath_overrides_runpath + +# Format of library name prefix. +libname_spec=$lt_libname_spec + +# List of archive names. First name is the real one, the rest are links. +# The last name is the one that the linker finds with -lNAME +library_names_spec=$lt_library_names_spec + +# The coded name of the library, if different from the real name. +soname_spec=$lt_soname_spec + +# Permission mode override for installation of shared libraries. +install_override_mode=$lt_install_override_mode + +# Command to use after installation of a shared archive. +postinstall_cmds=$lt_postinstall_cmds + +# Command to use after uninstallation of a shared archive. +postuninstall_cmds=$lt_postuninstall_cmds + +# Commands used to finish a libtool library installation in a directory. +finish_cmds=$lt_finish_cmds + +# As "finish_cmds", except a single script fragment to be evaled but +# not shown. +finish_eval=$lt_finish_eval + +# Whether we should hardcode library paths into libraries. +hardcode_into_libs=$hardcode_into_libs + +# Compile-time system search path for libraries. +sys_lib_search_path_spec=$lt_sys_lib_search_path_spec + +# Run-time system search path for libraries. +sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec + +# Whether dlopen is supported. +dlopen_support=$enable_dlopen + +# Whether dlopen of programs is supported. +dlopen_self=$enable_dlopen_self + +# Whether dlopen of statically linked programs is supported. +dlopen_self_static=$enable_dlopen_self_static + +# Commands to strip libraries. +old_striplib=$lt_old_striplib +striplib=$lt_striplib + + +# The linker used to build libraries. +LD=$lt_LD + +# How to create reloadable object files. +reload_flag=$lt_reload_flag +reload_cmds=$lt_reload_cmds + +# Commands used to build an old-style archive. +old_archive_cmds=$lt_old_archive_cmds + +# A language specific compiler. +CC=$lt_compiler + +# Is the compiler the GNU compiler? +with_gcc=$GCC + +# Compiler flag to turn off builtin functions. +no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag + +# Additional compiler flags for building library objects. +pic_flag=$lt_lt_prog_compiler_pic + +# How to pass a linker flag through the compiler. +wl=$lt_lt_prog_compiler_wl + +# Compiler flag to prevent dynamic linking. +link_static_flag=$lt_lt_prog_compiler_static + +# Does compiler simultaneously support -c and -o options? +compiler_c_o=$lt_lt_cv_prog_compiler_c_o + +# Whether or not to add -lc for building shared libraries. +build_libtool_need_lc=$archive_cmds_need_lc + +# Whether or not to disallow shared libs when runtime libs are static. +allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes + +# Compiler flag to allow reflexive dlopens. +export_dynamic_flag_spec=$lt_export_dynamic_flag_spec + +# Compiler flag to generate shared objects directly from archives. +whole_archive_flag_spec=$lt_whole_archive_flag_spec + +# Whether the compiler copes with passing no objects directly. +compiler_needs_object=$lt_compiler_needs_object + +# Create an old-style archive from a shared archive. +old_archive_from_new_cmds=$lt_old_archive_from_new_cmds + +# Create a temporary old-style archive to link instead of a shared archive. +old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds + +# Commands used to build a shared archive. +archive_cmds=$lt_archive_cmds +archive_expsym_cmds=$lt_archive_expsym_cmds + +# Commands used to build a loadable module if different from building +# a shared archive. +module_cmds=$lt_module_cmds +module_expsym_cmds=$lt_module_expsym_cmds + +# Whether we are building with GNU ld or not. +with_gnu_ld=$lt_with_gnu_ld + +# Flag that allows shared libraries with undefined symbols to be built. +allow_undefined_flag=$lt_allow_undefined_flag + +# Flag that enforces no undefined symbols. +no_undefined_flag=$lt_no_undefined_flag + +# Flag to hardcode \$libdir into a binary during linking. +# This must work even if \$libdir does not exist +hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec + +# Whether we need a single "-rpath" flag with a separated argument. +hardcode_libdir_separator=$lt_hardcode_libdir_separator + +# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes +# DIR into the resulting binary. +hardcode_direct=$hardcode_direct + +# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes +# DIR into the resulting binary and the resulting library dependency is +# "absolute",i.e impossible to change by setting \${shlibpath_var} if the +# library is relocated. +hardcode_direct_absolute=$hardcode_direct_absolute + +# Set to "yes" if using the -LDIR flag during linking hardcodes DIR +# into the resulting binary. +hardcode_minus_L=$hardcode_minus_L + +# Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR +# into the resulting binary. +hardcode_shlibpath_var=$hardcode_shlibpath_var + +# Set to "yes" if building a shared library automatically hardcodes DIR +# into the library and all subsequent libraries and executables linked +# against it. +hardcode_automatic=$hardcode_automatic + +# Set to yes if linker adds runtime paths of dependent libraries +# to runtime path list. +inherit_rpath=$inherit_rpath + +# Whether libtool must link a program against all its dependency libraries. +link_all_deplibs=$link_all_deplibs + +# Set to "yes" if exported symbols are required. +always_export_symbols=$always_export_symbols + +# The commands to list exported symbols. +export_symbols_cmds=$lt_export_symbols_cmds + +# Symbols that should not be listed in the preloaded symbols. +exclude_expsyms=$lt_exclude_expsyms + +# Symbols that must always be exported. +include_expsyms=$lt_include_expsyms + +# Commands necessary for linking programs (against libraries) with templates. +prelink_cmds=$lt_prelink_cmds + +# Commands necessary for finishing linking programs. +postlink_cmds=$lt_postlink_cmds + +# Specify filename containing input files. +file_list_spec=$lt_file_list_spec + +# How to hardcode a shared library path into an executable. +hardcode_action=$hardcode_action + +# The directories searched by this compiler when creating a shared library. +compiler_lib_search_dirs=$lt_compiler_lib_search_dirs + +# Dependencies to place before and after the objects being linked to +# create a shared library. +predep_objects=$lt_predep_objects +postdep_objects=$lt_postdep_objects +predeps=$lt_predeps +postdeps=$lt_postdeps + +# The library search path used internally by the compiler when linking +# a shared library. +compiler_lib_search_path=$lt_compiler_lib_search_path + +# ### END LIBTOOL CONFIG + +_LT_EOF + + case $host_os in + aix3*) + cat <<\_LT_EOF >> "$cfgfile" +# AIX sometimes has problems with the GCC collect2 program. For some +# reason, if we set the COLLECT_NAMES environment variable, the problems +# vanish in a puff of smoke. +if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES +fi +_LT_EOF + ;; + esac + + +ltmain="$ac_aux_dir/ltmain.sh" + + + # We use sed instead of cat because bash on DJGPP gets confused if + # if finds mixed CR/LF and LF-only lines. Since sed operates in + # text mode, it properly converts lines to CR/LF. This bash problem + # is reportedly fixed, but why not run on old versions too? + sed '$q' "$ltmain" >> "$cfgfile" \ + || (rm -f "$cfgfile"; exit 1) + + if test x"$xsi_shell" = xyes; then + sed -e '/^func_dirname ()$/,/^} # func_dirname /c\ +func_dirname ()\ +{\ +\ case ${1} in\ +\ */*) func_dirname_result="${1%/*}${2}" ;;\ +\ * ) func_dirname_result="${3}" ;;\ +\ esac\ +} # Extended-shell func_dirname implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + sed -e '/^func_basename ()$/,/^} # func_basename /c\ +func_basename ()\ +{\ +\ func_basename_result="${1##*/}"\ +} # Extended-shell func_basename implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + sed -e '/^func_dirname_and_basename ()$/,/^} # func_dirname_and_basename /c\ +func_dirname_and_basename ()\ +{\ +\ case ${1} in\ +\ */*) func_dirname_result="${1%/*}${2}" ;;\ +\ * ) func_dirname_result="${3}" ;;\ +\ esac\ +\ func_basename_result="${1##*/}"\ +} # Extended-shell func_dirname_and_basename implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + sed -e '/^func_stripname ()$/,/^} # func_stripname /c\ +func_stripname ()\ +{\ +\ # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are\ +\ # positional parameters, so assign one to ordinary parameter first.\ +\ func_stripname_result=${3}\ +\ func_stripname_result=${func_stripname_result#"${1}"}\ +\ func_stripname_result=${func_stripname_result%"${2}"}\ +} # Extended-shell func_stripname implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + sed -e '/^func_split_long_opt ()$/,/^} # func_split_long_opt /c\ +func_split_long_opt ()\ +{\ +\ func_split_long_opt_name=${1%%=*}\ +\ func_split_long_opt_arg=${1#*=}\ +} # Extended-shell func_split_long_opt implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + sed -e '/^func_split_short_opt ()$/,/^} # func_split_short_opt /c\ +func_split_short_opt ()\ +{\ +\ func_split_short_opt_arg=${1#??}\ +\ func_split_short_opt_name=${1%"$func_split_short_opt_arg"}\ +} # Extended-shell func_split_short_opt implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + sed -e '/^func_lo2o ()$/,/^} # func_lo2o /c\ +func_lo2o ()\ +{\ +\ case ${1} in\ +\ *.lo) func_lo2o_result=${1%.lo}.${objext} ;;\ +\ *) func_lo2o_result=${1} ;;\ +\ esac\ +} # Extended-shell func_lo2o implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + sed -e '/^func_xform ()$/,/^} # func_xform /c\ +func_xform ()\ +{\ + func_xform_result=${1%.*}.lo\ +} # Extended-shell func_xform implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + sed -e '/^func_arith ()$/,/^} # func_arith /c\ +func_arith ()\ +{\ + func_arith_result=$(( $* ))\ +} # Extended-shell func_arith implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + sed -e '/^func_len ()$/,/^} # func_len /c\ +func_len ()\ +{\ + func_len_result=${#1}\ +} # Extended-shell func_len implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + +fi + +if test x"$lt_shell_append" = xyes; then + sed -e '/^func_append ()$/,/^} # func_append /c\ +func_append ()\ +{\ + eval "${1}+=\\${2}"\ +} # Extended-shell func_append implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + sed -e '/^func_append_quoted ()$/,/^} # func_append_quoted /c\ +func_append_quoted ()\ +{\ +\ func_quote_for_eval "${2}"\ +\ eval "${1}+=\\\\ \\$func_quote_for_eval_result"\ +} # Extended-shell func_append_quoted implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + # Save a `func_append' function call where possible by direct use of '+=' + sed -e 's%func_append \([a-zA-Z_]\{1,\}\) "%\1+="%g' $cfgfile > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") + test 0 -eq $? || _lt_function_replace_fail=: +else + # Save a `func_append' function call even when '+=' is not available + sed -e 's%func_append \([a-zA-Z_]\{1,\}\) "%\1="$\1%g' $cfgfile > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") + test 0 -eq $? || _lt_function_replace_fail=: +fi + +if test x"$_lt_function_replace_fail" = x":"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Unable to substitute extended shell functions in $ofile" >&5 +$as_echo "$as_me: WARNING: Unable to substitute extended shell functions in $ofile" >&2;} +fi + + + mv -f "$cfgfile" "$ofile" || + (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") + chmod +x "$ofile" + + + cat <<_LT_EOF >> "$ofile" + +# ### BEGIN LIBTOOL TAG CONFIG: CXX + +# The linker used to build libraries. +LD=$lt_LD_CXX + +# How to create reloadable object files. +reload_flag=$lt_reload_flag_CXX +reload_cmds=$lt_reload_cmds_CXX + +# Commands used to build an old-style archive. +old_archive_cmds=$lt_old_archive_cmds_CXX + +# A language specific compiler. +CC=$lt_compiler_CXX + +# Is the compiler the GNU compiler? +with_gcc=$GCC_CXX + +# Compiler flag to turn off builtin functions. +no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag_CXX + +# Additional compiler flags for building library objects. +pic_flag=$lt_lt_prog_compiler_pic_CXX + +# How to pass a linker flag through the compiler. +wl=$lt_lt_prog_compiler_wl_CXX + +# Compiler flag to prevent dynamic linking. +link_static_flag=$lt_lt_prog_compiler_static_CXX + +# Does compiler simultaneously support -c and -o options? +compiler_c_o=$lt_lt_cv_prog_compiler_c_o_CXX + +# Whether or not to add -lc for building shared libraries. +build_libtool_need_lc=$archive_cmds_need_lc_CXX + +# Whether or not to disallow shared libs when runtime libs are static. +allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes_CXX + +# Compiler flag to allow reflexive dlopens. +export_dynamic_flag_spec=$lt_export_dynamic_flag_spec_CXX + +# Compiler flag to generate shared objects directly from archives. +whole_archive_flag_spec=$lt_whole_archive_flag_spec_CXX + +# Whether the compiler copes with passing no objects directly. +compiler_needs_object=$lt_compiler_needs_object_CXX + +# Create an old-style archive from a shared archive. +old_archive_from_new_cmds=$lt_old_archive_from_new_cmds_CXX + +# Create a temporary old-style archive to link instead of a shared archive. +old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds_CXX + +# Commands used to build a shared archive. +archive_cmds=$lt_archive_cmds_CXX +archive_expsym_cmds=$lt_archive_expsym_cmds_CXX + +# Commands used to build a loadable module if different from building +# a shared archive. +module_cmds=$lt_module_cmds_CXX +module_expsym_cmds=$lt_module_expsym_cmds_CXX + +# Whether we are building with GNU ld or not. +with_gnu_ld=$lt_with_gnu_ld_CXX + +# Flag that allows shared libraries with undefined symbols to be built. +allow_undefined_flag=$lt_allow_undefined_flag_CXX + +# Flag that enforces no undefined symbols. +no_undefined_flag=$lt_no_undefined_flag_CXX + +# Flag to hardcode \$libdir into a binary during linking. +# This must work even if \$libdir does not exist +hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec_CXX + +# Whether we need a single "-rpath" flag with a separated argument. +hardcode_libdir_separator=$lt_hardcode_libdir_separator_CXX + +# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes +# DIR into the resulting binary. +hardcode_direct=$hardcode_direct_CXX + +# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes +# DIR into the resulting binary and the resulting library dependency is +# "absolute",i.e impossible to change by setting \${shlibpath_var} if the +# library is relocated. +hardcode_direct_absolute=$hardcode_direct_absolute_CXX + +# Set to "yes" if using the -LDIR flag during linking hardcodes DIR +# into the resulting binary. +hardcode_minus_L=$hardcode_minus_L_CXX + +# Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR +# into the resulting binary. +hardcode_shlibpath_var=$hardcode_shlibpath_var_CXX + +# Set to "yes" if building a shared library automatically hardcodes DIR +# into the library and all subsequent libraries and executables linked +# against it. +hardcode_automatic=$hardcode_automatic_CXX + +# Set to yes if linker adds runtime paths of dependent libraries +# to runtime path list. +inherit_rpath=$inherit_rpath_CXX + +# Whether libtool must link a program against all its dependency libraries. +link_all_deplibs=$link_all_deplibs_CXX + +# Set to "yes" if exported symbols are required. +always_export_symbols=$always_export_symbols_CXX + +# The commands to list exported symbols. +export_symbols_cmds=$lt_export_symbols_cmds_CXX + +# Symbols that should not be listed in the preloaded symbols. +exclude_expsyms=$lt_exclude_expsyms_CXX + +# Symbols that must always be exported. +include_expsyms=$lt_include_expsyms_CXX + +# Commands necessary for linking programs (against libraries) with templates. +prelink_cmds=$lt_prelink_cmds_CXX + +# Commands necessary for finishing linking programs. +postlink_cmds=$lt_postlink_cmds_CXX + +# Specify filename containing input files. +file_list_spec=$lt_file_list_spec_CXX + +# How to hardcode a shared library path into an executable. +hardcode_action=$hardcode_action_CXX + +# The directories searched by this compiler when creating a shared library. +compiler_lib_search_dirs=$lt_compiler_lib_search_dirs_CXX + +# Dependencies to place before and after the objects being linked to +# create a shared library. +predep_objects=$lt_predep_objects_CXX +postdep_objects=$lt_postdep_objects_CXX +predeps=$lt_predeps_CXX +postdeps=$lt_postdeps_CXX + +# The library search path used internally by the compiler when linking +# a shared library. +compiler_lib_search_path=$lt_compiler_lib_search_path_CXX + +# ### END LIBTOOL TAG CONFIG: CXX +_LT_EOF + + ;; + + esac +done # for ac_tag + + +as_fn_exit 0 +_ACEOF +ac_clean_files=$ac_clean_files_save + +test $ac_write_fail = 0 || + as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 + + +# configure is writing to config.log, and then calls config.status. +# config.status does its own redirection, appending to config.log. +# Unfortunately, on DOS this fails, as config.log is still kept open +# by configure, so config.status won't be able to write to it; its +# output is simply discarded. So we exec the FD to /dev/null, +# effectively closing config.log, so it can be properly (re)opened and +# appended to by config.status. When coming back to configure, we +# need to make the FD available again. +if test "$no_create" != yes; then + ac_cs_success=: + ac_config_status_args= + test "$silent" = yes && + ac_config_status_args="$ac_config_status_args --quiet" + exec 5>/dev/null + $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false + exec 5>>config.log + # Use ||, not &&, to avoid exiting from the if with $? = 1, which + # would make configure fail if this is the last instruction. + $ac_cs_success || as_fn_exit 1 +fi +if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 +$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} +fi + diff --git a/extern/portaudio/bindings/cpp/configure.ac b/extern/portaudio/bindings/cpp/configure.ac new file mode 100644 index 0000000..100656a --- /dev/null +++ b/extern/portaudio/bindings/cpp/configure.ac @@ -0,0 +1,54 @@ +# +# PortAudioCpp V19 autoconf input file +# Shamelessly ripped from the PortAudio one by Dominic Mazzoni +# Ludwig Schwardt +# Customized for automake by Mikael Magnusson +# + +# Require autoconf >= 2.13 +AC_PREREQ(2.13) + +m4_define([lt_current], [0]) +m4_define([lt_revision], [12]) +m4_define([lt_age], [0]) + +AC_INIT([PortAudioCpp], [12]) +AC_CONFIG_SRCDIR([include/portaudiocpp/PortAudioCpp.hxx]) +AM_INIT_AUTOMAKE +AM_MAINTAINER_MODE + +###### Top-level directory of pacpp +###### This makes it easy to shuffle the build directories +###### Also edit AC_CONFIG_SRCDIR above (wouldn't accept this variable)! +PACPP_ROOT="\$(top_srcdir)" +PORTAUDIO_ROOT="../.." + +# Various other variables and flags +DEFAULT_INCLUDES="-I$PACPP_ROOT/include -I$PACPP_ROOT/$PORTAUDIO_ROOT/include" +CFLAGS=${CFLAGS-"-g -O2 -Wall -ansi -pedantic"} +CXXFLAGS=${CXXFLAGS-"${CFLAGS}"} + +LT_VERSION_INFO="lt_current:lt_revision:lt_age" + +# Checks for programs + +AC_PROG_CC +AC_PROG_CXX +AC_LIBTOOL_WIN32_DLL +AC_PROG_LIBTOOL + +# Transfer these variables to the Makefile +AC_SUBST(DEFAULT_INCLUDES) +AC_SUBST(PORTAUDIO_ROOT) +AC_SUBST(CXXFLAGS) +AC_SUBST(LT_VERSION_INFO) + +AC_CONFIG_FILES([ + Makefile + lib/Makefile + include/Makefile + bin/Makefile + doc/Makefile + portaudiocpp.pc + ]) +AC_OUTPUT diff --git a/extern/portaudio/bindings/cpp/doc/Makefile.am b/extern/portaudio/bindings/cpp/doc/Makefile.am new file mode 100644 index 0000000..7eb81ba --- /dev/null +++ b/extern/portaudio/bindings/cpp/doc/Makefile.am @@ -0,0 +1,5 @@ +PACPP_ROOT = . +#INCLUDES = -I$(srcdir)/$(PACPP_ROOT)/include -I$(top_srcdir)/include + +docs: + doxygen $(srcdir)/config.doxy.linux diff --git a/extern/portaudio/bindings/cpp/doc/Makefile.in b/extern/portaudio/bindings/cpp/doc/Makefile.in new file mode 100644 index 0000000..f471ddc --- /dev/null +++ b/extern/portaudio/bindings/cpp/doc/Makefile.in @@ -0,0 +1,432 @@ +# Makefile.in generated by automake 1.14.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2013 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ +VPATH = @srcdir@ +am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = doc +DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am README +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +SOURCES = +DIST_SOURCES = +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFAULT_INCLUDES = @DEFAULT_INCLUDES@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_VERSION_INFO = @LT_VERSION_INFO@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PORTAUDIO_ROOT = @PORTAUDIO_ROOT@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +PACPP_ROOT = . +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu doc/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu doc/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +tags TAGS: + +ctags CTAGS: + +cscope cscopelist: + + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: all all-am check check-am clean clean-generic clean-libtool \ + cscopelist-am ctags-am distclean distclean-generic \ + distclean-libtool distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags-am uninstall uninstall-am + +#INCLUDES = -I$(srcdir)/$(PACPP_ROOT)/include -I$(top_srcdir)/include + +docs: + doxygen $(srcdir)/config.doxy.linux + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/extern/portaudio/bindings/cpp/doc/README b/extern/portaudio/bindings/cpp/doc/README new file mode 100644 index 0000000..efeaa72 --- /dev/null +++ b/extern/portaudio/bindings/cpp/doc/README @@ -0,0 +1,34 @@ +GNU/Linux: +---------- + +1) Download and install a recent version of Doxygen (preferably version 1.3.3 or +later). See http://www.doxygen.org/. +2) Download and install a recent version of GraphViz. See +http://www.research.att.com/sw/tools/graphviz/. +3) Run ``doxygen config.doxy.linux'' in this directory or load and generate the file +config.doxy.linux from the Doxywizard application. Or alternatively ``make docs'' can +be run from the build/gnu folder. + +The generated html documentation will be placed in /doc/api_reference/. To open +the main page of the documentation, open the file /doc/api_reference/index.html in +an html browser. + + +Windows: +-------- + +1) Download and install a recent Doxygen (preferably version 1.3.4 or later). See +http://www.doxygen.org/. +2) Download and install a recent version of GraphViz. See +http://www.research.att.com/sw/tools/graphviz/. +3) If needed, edit the config.doxy file in an ascii text editor so that +``DOT_PATH'' variable points to the folder where GraphViz is installed. +4) Run ``doxygen config.doxy'' in this directory or load and generate the file +config.doxy from the Doxywizard application. + +The generated html documentation will be placed in /doc/api_reference/. To open +the main page of the documentation, open the file /doc/api_reference/index.html in +an html browser. + + + diff --git a/extern/portaudio/bindings/cpp/doc/config.doxy b/extern/portaudio/bindings/cpp/doc/config.doxy new file mode 100644 index 0000000..0bfe9d3 --- /dev/null +++ b/extern/portaudio/bindings/cpp/doc/config.doxy @@ -0,0 +1,211 @@ +# Doxyfile 1.3.6 + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- +PROJECT_NAME = PortAudioCpp +PROJECT_NUMBER = 2.0 +OUTPUT_DIRECTORY = ./ +OUTPUT_LANGUAGE = English +USE_WINDOWS_ENCODING = YES +BRIEF_MEMBER_DESC = YES +REPEAT_BRIEF = YES +ABBREVIATE_BRIEF = +ALWAYS_DETAILED_SEC = YES +INLINE_INHERITED_MEMB = NO +FULL_PATH_NAMES = NO +STRIP_FROM_PATH = +SHORT_NAMES = YES +JAVADOC_AUTOBRIEF = NO +MULTILINE_CPP_IS_BRIEF = NO +DETAILS_AT_TOP = YES +INHERIT_DOCS = YES +DISTRIBUTE_GROUP_DOC = NO +TAB_SIZE = 4 +ALIASES = +OPTIMIZE_OUTPUT_FOR_C = NO +OPTIMIZE_OUTPUT_JAVA = NO +SUBGROUPING = YES +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- +EXTRACT_ALL = YES +EXTRACT_PRIVATE = YES +EXTRACT_STATIC = YES +EXTRACT_LOCAL_CLASSES = YES +HIDE_UNDOC_MEMBERS = NO +HIDE_UNDOC_CLASSES = NO +HIDE_FRIEND_COMPOUNDS = NO +HIDE_IN_BODY_DOCS = NO +INTERNAL_DOCS = NO +CASE_SENSE_NAMES = YES +HIDE_SCOPE_NAMES = NO +SHOW_INCLUDE_FILES = YES +INLINE_INFO = YES +SORT_MEMBER_DOCS = NO +SORT_BRIEF_DOCS = NO +SORT_BY_SCOPE_NAME = NO +GENERATE_TODOLIST = YES +GENERATE_TESTLIST = YES +GENERATE_BUGLIST = YES +GENERATE_DEPRECATEDLIST= YES +ENABLED_SECTIONS = +MAX_INITIALIZER_LINES = 30 +SHOW_USED_FILES = YES +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- +QUIET = NO +WARNINGS = YES +WARN_IF_UNDOCUMENTED = YES +WARN_IF_DOC_ERROR = YES +WARN_FORMAT = "$file:$line: $text" +WARN_LOGFILE = +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- +INPUT = ../source \ + ../include +FILE_PATTERNS = *.hxx \ + *.cxx +RECURSIVE = YES +EXCLUDE = +EXCLUDE_SYMLINKS = NO +EXCLUDE_PATTERNS = +EXAMPLE_PATH = +EXAMPLE_PATTERNS = +EXAMPLE_RECURSIVE = NO +IMAGE_PATH = +INPUT_FILTER = +FILTER_SOURCE_FILES = NO +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- +SOURCE_BROWSER = NO +INLINE_SOURCES = NO +STRIP_CODE_COMMENTS = YES +REFERENCED_BY_RELATION = YES +REFERENCES_RELATION = YES +VERBATIM_HEADERS = YES +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- +ALPHABETICAL_INDEX = YES +COLS_IN_ALPHA_INDEX = 2 +IGNORE_PREFIX = +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- +GENERATE_HTML = YES +HTML_OUTPUT = api_reference +HTML_FILE_EXTENSION = .html +HTML_HEADER = +HTML_FOOTER = +HTML_STYLESHEET = +HTML_ALIGN_MEMBERS = YES +GENERATE_HTMLHELP = NO +CHM_FILE = +HHC_LOCATION = +GENERATE_CHI = NO +BINARY_TOC = NO +TOC_EXPAND = NO +DISABLE_INDEX = NO +ENUM_VALUES_PER_LINE = 4 +GENERATE_TREEVIEW = NO +TREEVIEW_WIDTH = 250 +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- +GENERATE_LATEX = NO +LATEX_OUTPUT = latex +LATEX_CMD_NAME = latex +MAKEINDEX_CMD_NAME = makeindex +COMPACT_LATEX = NO +PAPER_TYPE = a4wide +EXTRA_PACKAGES = +LATEX_HEADER = +PDF_HYPERLINKS = NO +USE_PDFLATEX = NO +LATEX_BATCHMODE = NO +LATEX_HIDE_INDICES = NO +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- +GENERATE_RTF = NO +RTF_OUTPUT = rtf +COMPACT_RTF = NO +RTF_HYPERLINKS = NO +RTF_STYLESHEET_FILE = +RTF_EXTENSIONS_FILE = +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- +GENERATE_MAN = NO +MAN_OUTPUT = man +MAN_EXTENSION = .3 +MAN_LINKS = NO +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- +GENERATE_XML = NO +XML_OUTPUT = xml +XML_SCHEMA = +XML_DTD = +XML_PROGRAMLISTING = YES +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- +GENERATE_AUTOGEN_DEF = NO +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- +GENERATE_PERLMOD = NO +PERLMOD_LATEX = NO +PERLMOD_PRETTY = YES +PERLMOD_MAKEVAR_PREFIX = +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- +ENABLE_PREPROCESSING = YES +MACRO_EXPANSION = NO +EXPAND_ONLY_PREDEF = NO +SEARCH_INCLUDES = YES +INCLUDE_PATH = +INCLUDE_FILE_PATTERNS = +PREDEFINED = +EXPAND_AS_DEFINED = +SKIP_FUNCTION_MACROS = YES +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- +TAGFILES = +GENERATE_TAGFILE = +ALLEXTERNALS = NO +EXTERNAL_GROUPS = YES +PERL_PATH = /usr/bin/perl +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- +CLASS_DIAGRAMS = YES +HIDE_UNDOC_RELATIONS = YES +HAVE_DOT = YES +CLASS_GRAPH = YES +COLLABORATION_GRAPH = YES +UML_LOOK = YES +TEMPLATE_RELATIONS = YES +INCLUDE_GRAPH = YES +INCLUDED_BY_GRAPH = YES +CALL_GRAPH = NO +GRAPHICAL_HIERARCHY = YES +DOT_IMAGE_FORMAT = png +DOT_PATH = "c:/Program Files/ATT/Graphviz/bin/" +DOTFILE_DIRS = +MAX_DOT_GRAPH_WIDTH = 1024 +MAX_DOT_GRAPH_HEIGHT = 1024 +MAX_DOT_GRAPH_DEPTH = 0 +GENERATE_LEGEND = YES +DOT_CLEANUP = YES +#--------------------------------------------------------------------------- +# Configuration::additions related to the search engine +#--------------------------------------------------------------------------- +SEARCHENGINE = NO diff --git a/extern/portaudio/bindings/cpp/doc/config.doxy.linux b/extern/portaudio/bindings/cpp/doc/config.doxy.linux new file mode 100644 index 0000000..95a38ef --- /dev/null +++ b/extern/portaudio/bindings/cpp/doc/config.doxy.linux @@ -0,0 +1,210 @@ +# Doxyfile 1.3.3 + +#--------------------------------------------------------------------------- +# General configuration options +#--------------------------------------------------------------------------- +PROJECT_NAME = PortAudioCpp +PROJECT_NUMBER = 2.0 +OUTPUT_DIRECTORY = ./ +OUTPUT_LANGUAGE = English +USE_WINDOWS_ENCODING = YES +EXTRACT_ALL = YES +EXTRACT_PRIVATE = YES +EXTRACT_STATIC = YES +EXTRACT_LOCAL_CLASSES = YES +HIDE_UNDOC_MEMBERS = NO +HIDE_UNDOC_CLASSES = NO +HIDE_FRIEND_COMPOUNDS = NO +HIDE_IN_BODY_DOCS = NO +BRIEF_MEMBER_DESC = YES +REPEAT_BRIEF = YES +ALWAYS_DETAILED_SEC = YES +INLINE_INHERITED_MEMB = NO +FULL_PATH_NAMES = NO +STRIP_FROM_PATH = +INTERNAL_DOCS = NO +CASE_SENSE_NAMES = YES +SHORT_NAMES = YES +HIDE_SCOPE_NAMES = NO +SHOW_INCLUDE_FILES = YES +JAVADOC_AUTOBRIEF = NO +MULTILINE_CPP_IS_BRIEF = NO +DETAILS_AT_TOP = YES +INHERIT_DOCS = YES +INLINE_INFO = YES +SORT_MEMBER_DOCS = NO +DISTRIBUTE_GROUP_DOC = NO +TAB_SIZE = 4 +GENERATE_TODOLIST = YES +GENERATE_TESTLIST = YES +GENERATE_BUGLIST = YES +GENERATE_DEPRECATEDLIST= YES +ALIASES = +ENABLED_SECTIONS = +MAX_INITIALIZER_LINES = 30 +OPTIMIZE_OUTPUT_FOR_C = NO +OPTIMIZE_OUTPUT_JAVA = NO +SHOW_USED_FILES = YES +SUBGROUPING = YES +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- +QUIET = NO +WARNINGS = YES +WARN_IF_UNDOCUMENTED = YES +WARN_IF_DOC_ERROR = YES +WARN_FORMAT = "$file:$line: $text" +WARN_LOGFILE = +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- +INPUT = ../source \ + ../include +FILE_PATTERNS = *.hxx \ + *.cxx +RECURSIVE = YES +EXCLUDE = +EXCLUDE_SYMLINKS = NO +EXCLUDE_PATTERNS = +EXAMPLE_PATH = +EXAMPLE_PATTERNS = +EXAMPLE_RECURSIVE = NO +IMAGE_PATH = +INPUT_FILTER = +FILTER_SOURCE_FILES = NO +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- +SOURCE_BROWSER = NO +INLINE_SOURCES = NO +STRIP_CODE_COMMENTS = YES +REFERENCED_BY_RELATION = YES +REFERENCES_RELATION = YES +VERBATIM_HEADERS = YES +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- +ALPHABETICAL_INDEX = YES +COLS_IN_ALPHA_INDEX = 2 +IGNORE_PREFIX = +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- +GENERATE_HTML = YES +HTML_OUTPUT = api_reference +HTML_FILE_EXTENSION = .html +HTML_HEADER = +HTML_FOOTER = +HTML_STYLESHEET = +HTML_ALIGN_MEMBERS = YES +GENERATE_HTMLHELP = NO +CHM_FILE = +HHC_LOCATION = +GENERATE_CHI = NO +BINARY_TOC = NO +TOC_EXPAND = NO +DISABLE_INDEX = NO +ENUM_VALUES_PER_LINE = 4 +GENERATE_TREEVIEW = NO +TREEVIEW_WIDTH = 250 +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- +GENERATE_LATEX = NO +LATEX_OUTPUT = latex +LATEX_CMD_NAME = latex +MAKEINDEX_CMD_NAME = makeindex +COMPACT_LATEX = NO +PAPER_TYPE = a4wide +EXTRA_PACKAGES = +LATEX_HEADER = +PDF_HYPERLINKS = NO +USE_PDFLATEX = NO +LATEX_BATCHMODE = NO +LATEX_HIDE_INDICES = NO +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- +GENERATE_RTF = NO +RTF_OUTPUT = rtf +COMPACT_RTF = NO +RTF_HYPERLINKS = NO +RTF_STYLESHEET_FILE = +RTF_EXTENSIONS_FILE = +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- +GENERATE_MAN = NO +MAN_OUTPUT = man +MAN_EXTENSION = .3 +MAN_LINKS = NO +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- +GENERATE_XML = NO +XML_OUTPUT = xml +XML_SCHEMA = +XML_DTD = +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- +GENERATE_AUTOGEN_DEF = NO +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- +GENERATE_PERLMOD = NO +PERLMOD_LATEX = NO +PERLMOD_PRETTY = YES +PERLMOD_MAKEVAR_PREFIX = +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- +ENABLE_PREPROCESSING = YES +MACRO_EXPANSION = NO +EXPAND_ONLY_PREDEF = NO +SEARCH_INCLUDES = YES +INCLUDE_PATH = +INCLUDE_FILE_PATTERNS = +PREDEFINED = +EXPAND_AS_DEFINED = +SKIP_FUNCTION_MACROS = YES +#--------------------------------------------------------------------------- +# Configuration::addtions related to external references +#--------------------------------------------------------------------------- +TAGFILES = +GENERATE_TAGFILE = +ALLEXTERNALS = NO +EXTERNAL_GROUPS = YES +PERL_PATH = /usr/bin/perl +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- +CLASS_DIAGRAMS = YES +HIDE_UNDOC_RELATIONS = YES +HAVE_DOT = YES +CLASS_GRAPH = YES +COLLABORATION_GRAPH = YES +UML_LOOK = YES +TEMPLATE_RELATIONS = YES +INCLUDE_GRAPH = YES +INCLUDED_BY_GRAPH = YES +CALL_GRAPH = NO +GRAPHICAL_HIERARCHY = YES +DOT_IMAGE_FORMAT = png +DOT_PATH = "/usr/bin/dot" +DOTFILE_DIRS = +MAX_DOT_GRAPH_WIDTH = 1024 +MAX_DOT_GRAPH_HEIGHT = 1024 +MAX_DOT_GRAPH_DEPTH = 0 +GENERATE_LEGEND = YES +DOT_CLEANUP = YES +#--------------------------------------------------------------------------- +# Configuration::addtions related to the search engine +#--------------------------------------------------------------------------- +SEARCHENGINE = NO +CGI_NAME = search.cgi +CGI_URL = +DOC_URL = +DOC_ABSPATH = +BIN_ABSPATH = /usr/local/bin/ +EXT_DOC_PATHS = diff --git a/extern/portaudio/bindings/cpp/example/devs.cxx b/extern/portaudio/bindings/cpp/example/devs.cxx new file mode 100644 index 0000000..31a560f --- /dev/null +++ b/extern/portaudio/bindings/cpp/example/devs.cxx @@ -0,0 +1,177 @@ +#include +#include "portaudiocpp/PortAudioCpp.hxx" + +#ifdef WIN32 +#include "portaudiocpp/AsioDeviceAdapter.hxx" +#endif + +// --------------------------------------------------------------------------------------- + +void printSupportedStandardSampleRates( + const portaudio::DirectionSpecificStreamParameters &inputParameters, + const portaudio::DirectionSpecificStreamParameters &outputParameters) +{ + static double STANDARD_SAMPLE_RATES[] = { + 8000.0, 9600.0, 11025.0, 12000.0, 16000.0, 22050.0, 24000.0, 32000.0, + 44100.0, 48000.0, 88200.0, 96000.0, -1 }; // negative terminated list + + int printCount = 0; + + for (int i = 0; STANDARD_SAMPLE_RATES[i] > 0; ++i) + { + portaudio::StreamParameters tmp = portaudio::StreamParameters(inputParameters, outputParameters, STANDARD_SAMPLE_RATES[i], 0, paNoFlag); + + if (tmp.isSupported()) + { + if (printCount == 0) + { + std::cout << " " << STANDARD_SAMPLE_RATES[i]; // 8.2 + printCount = 1; + } + else if (printCount == 4) + { + std::cout << "," << std::endl; + std::cout << " " << STANDARD_SAMPLE_RATES[i]; // 8.2 + printCount = 1; + } + else + { + std::cout << ", " << STANDARD_SAMPLE_RATES[i]; // 8.2 + ++printCount; + } + } + } + + if (printCount == 0) + std::cout << "None" << std::endl; + else + std::cout << std::endl; +} + +// --------------------------------------------------------------------------------------- + +int main(int, char*[]); +int main(int, char*[]) +{ + try + { + portaudio::AutoSystem autoSys; + + portaudio::System &sys = portaudio::System::instance(); + + std::cout << "PortAudio version number = " << sys.version() << std::endl; + std::cout << "PortAudio version text = '" << sys.versionText() << "'" << std::endl; + + int numDevices = sys.deviceCount(); + std::cout << "Number of devices = " << numDevices << std::endl; + + for (portaudio::System::DeviceIterator i = sys.devicesBegin(); i != sys.devicesEnd(); ++i) + { + std::cout << "--------------------------------------- device #" << (*i).index() << std::endl; + + // Mark global and API specific default devices: + bool defaultDisplayed = false; + + if ((*i).isSystemDefaultInputDevice()) + { + std::cout << "[ Default Input"; + defaultDisplayed = true; + } + else if ((*i).isHostApiDefaultInputDevice()) + { + std::cout << "[ Default " << (*i).hostApi().name() << " Input"; + defaultDisplayed = true; + } + + if ((*i).isSystemDefaultOutputDevice()) + { + std::cout << (defaultDisplayed ? "," : "["); + std::cout << " Default Output"; + defaultDisplayed = true; + } + else if ((*i).isHostApiDefaultOutputDevice()) + { + std::cout << (defaultDisplayed ? "," : "["); + std::cout << " Default " << (*i).hostApi().name() << " Output"; + defaultDisplayed = true; + } + + if (defaultDisplayed) + std::cout << " ]" << std::endl; + + // Print device info: + std::cout << "Name = " << (*i).name() << std::endl; + std::cout << "Host API = " << (*i).hostApi().name() << std::endl; + std::cout << "Max inputs = " << (*i).maxInputChannels() << ", Max outputs = " << (*i).maxOutputChannels() << std::endl; + + std::cout << "Default low input latency = " << (*i).defaultLowInputLatency() << std::endl; // 8.3 + std::cout << "Default low output latency = " << (*i).defaultLowOutputLatency() << std::endl; // 8.3 + std::cout << "Default high input latency = " << (*i).defaultHighInputLatency() << std::endl; // 8.3 + std::cout << "Default high output latency = " << (*i).defaultHighOutputLatency() << std::endl; // 8.3 + +#ifdef WIN32 + // ASIO specific latency information: + if ((*i).hostApi().typeId() == paASIO) + { + portaudio::AsioDeviceAdapter asioDevice((*i)); + + std::cout << "ASIO minimum buffer size = " << asioDevice.minBufferSize() << std::endl; + std::cout << "ASIO maximum buffer size = " << asioDevice.maxBufferSize() << std::endl; + std::cout << "ASIO preferred buffer size = " << asioDevice.preferredBufferSize() << std::endl; + + if (asioDevice.granularity() == -1) + std::cout << "ASIO buffer granularity = power of 2" << std::endl; + else + std::cout << "ASIO buffer granularity = " << asioDevice.granularity() << std::endl; + } +#endif // WIN32 + + std::cout << "Default sample rate = " << (*i).defaultSampleRate() << std::endl; // 8.2 + + // Poll for standard sample rates: + portaudio::DirectionSpecificStreamParameters inputParameters((*i), (*i).maxInputChannels(), portaudio::INT16, true, 0.0, NULL); + portaudio::DirectionSpecificStreamParameters outputParameters((*i), (*i).maxOutputChannels(), portaudio::INT16, true, 0.0, NULL); + + if (inputParameters.numChannels() > 0) + { + std::cout << "Supported standard sample rates" << std::endl; + std::cout << " for half-duplex 16 bit " << inputParameters.numChannels() << " channel input = " << std::endl; + printSupportedStandardSampleRates(inputParameters, portaudio::DirectionSpecificStreamParameters::null()); + } + + if (outputParameters.numChannels() > 0) + { + std::cout << "Supported standard sample rates" << std::endl; + std::cout << " for half-duplex 16 bit " << outputParameters.numChannels() << " channel output = " << std::endl; + printSupportedStandardSampleRates(portaudio::DirectionSpecificStreamParameters::null(), outputParameters); + } + + if (inputParameters.numChannels() > 0 && outputParameters.numChannels() > 0) + { + std::cout << "Supported standard sample rates" << std::endl; + std::cout << " for full-duplex 16 bit " << inputParameters.numChannels() << " channel input, " << outputParameters.numChannels() << " channel output = " << std::endl; + printSupportedStandardSampleRates(inputParameters, outputParameters); + } + } + + std::cout << "----------------------------------------------" << std::endl; + } + catch (const portaudio::PaException &e) + { + std::cout << "A PortAudio error occured: " << e.paErrorText() << std::endl; + } + catch (const portaudio::PaCppException &e) + { + std::cout << "A PortAudioCpp error occured: " << e.what() << std::endl; + } + catch (const std::exception &e) + { + std::cout << "A generic exception occured: " << e.what() << std::endl; + } + catch (...) + { + std::cout << "An unknown exception occured." << std::endl; + } + + return 0; +} diff --git a/extern/portaudio/bindings/cpp/example/sine.cxx b/extern/portaudio/bindings/cpp/example/sine.cxx new file mode 100644 index 0000000..0676e3e --- /dev/null +++ b/extern/portaudio/bindings/cpp/example/sine.cxx @@ -0,0 +1,137 @@ +// --------------------------------------------------------------------------------------- + +#include +#include +#include +#include +#include "portaudiocpp/PortAudioCpp.hxx" + +// --------------------------------------------------------------------------------------- + +// Some constants: +const int NUM_SECONDS = 5; +const double SAMPLE_RATE = 44100.0; +const int FRAMES_PER_BUFFER = 64; +const int TABLE_SIZE = 200; + +// --------------------------------------------------------------------------------------- + +// SineGenerator class: +class SineGenerator +{ +public: + SineGenerator(int tableSize) : tableSize_(tableSize), leftPhase_(0), rightPhase_(0) + { + const double PI = 3.14159265; + table_ = new float[tableSize]; + for (int i = 0; i < tableSize; ++i) + { + table_[i] = 0.125f * (float)sin(((double)i/(double)tableSize)*PI*2.); + } + } + + ~SineGenerator() + { + delete[] table_; + } + + int generate(const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, + const PaStreamCallbackTimeInfo *timeInfo, PaStreamCallbackFlags statusFlags) + { + assert(outputBuffer != NULL); + + float **out = static_cast(outputBuffer); + + for (unsigned int i = 0; i < framesPerBuffer; ++i) + { + out[0][i] = table_[leftPhase_]; + out[1][i] = table_[rightPhase_]; + + leftPhase_ += 1; + if (leftPhase_ >= tableSize_) + leftPhase_ -= tableSize_; + + rightPhase_ += 3; + if (rightPhase_ >= tableSize_) + rightPhase_ -= tableSize_; + } + + return paContinue; + } + +private: + float *table_; + int tableSize_; + int leftPhase_; + int rightPhase_; +}; + +// --------------------------------------------------------------------------------------- + +// main: +int main(int, char *[]); +int main(int, char *[]) +{ + try + { + // Create a SineGenerator object: + SineGenerator sineGenerator(TABLE_SIZE); + + std::cout << "Setting up PortAudio..." << std::endl; + + // Set up the System: + portaudio::AutoSystem autoSys; + portaudio::System &sys = portaudio::System::instance(); + + // Set up the parameters required to open a (Callback)Stream: + portaudio::DirectionSpecificStreamParameters outParams(sys.defaultOutputDevice(), 2, portaudio::FLOAT32, false, sys.defaultOutputDevice().defaultLowOutputLatency(), NULL); + portaudio::StreamParameters params(portaudio::DirectionSpecificStreamParameters::null(), outParams, SAMPLE_RATE, FRAMES_PER_BUFFER, paClipOff); + + std::cout << "Opening stereo output stream..." << std::endl; + + // Create (and open) a new Stream, using the SineGenerator::generate function as a callback: + portaudio::MemFunCallbackStream stream(params, sineGenerator, &SineGenerator::generate); + + std::cout << "Starting playback for " << NUM_SECONDS << " seconds." << std::endl; + + // Start the Stream (audio playback starts): + stream.start(); + + // Wait for 5 seconds: + sys.sleep(NUM_SECONDS * 1000); + + std::cout << "Closing stream..." <&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = include +DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ + $(pkginclude_HEADERS) +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +SOURCES = +DIST_SOURCES = +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__uninstall_files_from_dir = { \ + test -z "$$files" \ + || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ + || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ + $(am__cd) "$$dir" && rm -f $$files; }; \ + } +am__installdirs = "$(DESTDIR)$(pkgincludedir)" +HEADERS = $(pkginclude_HEADERS) +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFAULT_INCLUDES = @DEFAULT_INCLUDES@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_VERSION_INFO = @LT_VERSION_INFO@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PORTAUDIO_ROOT = @PORTAUDIO_ROOT@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +pkginclude_HEADERS = \ + portaudiocpp/AutoSystem.hxx \ + portaudiocpp/BlockingStream.hxx \ + portaudiocpp/CallbackInterface.hxx \ + portaudiocpp/CallbackStream.hxx \ + portaudiocpp/CFunCallbackStream.hxx \ + portaudiocpp/CppFunCallbackStream.hxx \ + portaudiocpp/Device.hxx \ + portaudiocpp/DirectionSpecificStreamParameters.hxx \ + portaudiocpp/Exception.hxx \ + portaudiocpp/HostApi.hxx \ + portaudiocpp/InterfaceCallbackStream.hxx \ + portaudiocpp/MemFunCallbackStream.hxx \ + portaudiocpp/PortAudioCpp.hxx \ + portaudiocpp/SampleDataFormat.hxx \ + portaudiocpp/Stream.hxx \ + portaudiocpp/StreamParameters.hxx \ + portaudiocpp/SystemDeviceIterator.hxx \ + portaudiocpp/SystemHostApiIterator.hxx \ + portaudiocpp/System.hxx + +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu include/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu include/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +install-pkgincludeHEADERS: $(pkginclude_HEADERS) + @$(NORMAL_INSTALL) + @list='$(pkginclude_HEADERS)'; test -n "$(pkgincludedir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(pkgincludedir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(pkgincludedir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(pkgincludedir)'"; \ + $(INSTALL_HEADER) $$files "$(DESTDIR)$(pkgincludedir)" || exit $$?; \ + done + +uninstall-pkgincludeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(pkginclude_HEADERS)'; test -n "$(pkgincludedir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + dir='$(DESTDIR)$(pkgincludedir)'; $(am__uninstall_files_from_dir) + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-am +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-am + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscopelist: cscopelist-am + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(HEADERS) +installdirs: + for dir in "$(DESTDIR)$(pkgincludedir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-pkgincludeHEADERS + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-pkgincludeHEADERS + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ + clean-libtool cscopelist-am ctags ctags-am distclean \ + distclean-generic distclean-libtool distclean-tags distdir dvi \ + dvi-am html html-am info info-am install install-am \ + install-data install-data-am install-dvi install-dvi-am \ + install-exec install-exec-am install-html install-html-am \ + install-info install-info-am install-man install-pdf \ + install-pdf-am install-pkgincludeHEADERS install-ps \ + install-ps-am install-strip installcheck installcheck-am \ + installdirs maintainer-clean maintainer-clean-generic \ + mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \ + ps ps-am tags tags-am uninstall uninstall-am \ + uninstall-pkgincludeHEADERS + + +# portaudiocpp/AsioDeviceAdapter.hxx + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/extern/portaudio/bindings/cpp/include/portaudiocpp/AsioDeviceAdapter.hxx b/extern/portaudio/bindings/cpp/include/portaudiocpp/AsioDeviceAdapter.hxx new file mode 100644 index 0000000..26957c4 --- /dev/null +++ b/extern/portaudio/bindings/cpp/include/portaudiocpp/AsioDeviceAdapter.hxx @@ -0,0 +1,44 @@ +#ifndef INCLUDED_PORTAUDIO_ASIODEVICEADAPTER_HXX +#define INCLUDED_PORTAUDIO_ASIODEVICEADAPTER_HXX + +namespace portaudio +{ + + // Forward declaration(s): + class Device; + + // Declaration(s): + ////// + /// @brief Adapts the given Device to an ASIO specific extension. + /// + /// Deleting the AsioDeviceAdapter does not affect the underlaying + /// Device. + ////// + class AsioDeviceAdapter + { + public: + AsioDeviceAdapter(Device &device); + + Device &device(); + + long minBufferSize() const; + long maxBufferSize() const; + long preferredBufferSize() const; + long granularity() const; + + void showControlPanel(void *systemSpecific); + + const char *inputChannelName(int channelIndex) const; + const char *outputChannelName(int channelIndex) const; + + private: + Device *device_; + + long minBufferSize_; + long maxBufferSize_; + long preferredBufferSize_; + long granularity_; + }; +} + +#endif // INCLUDED_PORTAUDIO_ASIODEVICEADAPTER_HXX diff --git a/extern/portaudio/bindings/cpp/include/portaudiocpp/AutoSystem.hxx b/extern/portaudio/bindings/cpp/include/portaudiocpp/AutoSystem.hxx new file mode 100644 index 0000000..47e2ec1 --- /dev/null +++ b/extern/portaudio/bindings/cpp/include/portaudiocpp/AutoSystem.hxx @@ -0,0 +1,62 @@ +#ifndef INCLUDED_PORTAUDIO_AUTOSYSTEM_HXX +#define INCLUDED_PORTAUDIO_AUTOSYSTEM_HXX + +// --------------------------------------------------------------------------------------- + +#include "portaudiocpp/System.hxx" + +// --------------------------------------------------------------------------------------- + +namespace portaudio +{ + + + ////// + /// @brief A RAII idiom class to ensure automatic clean-up when an exception is + /// raised. + /// + /// A simple helper class which uses the 'Resource Acquisition is Initialization' + /// idiom (RAII). Use this class to initialize/terminate the System rather than + /// using System directly. AutoSystem must be created on stack and must be valid + /// throughout the time you wish to use PortAudioCpp. Your 'main' function might be + /// a good place for it. + /// + /// To avoid having to type portaudio::System::instance().xyz() all the time, it's usually + /// a good idea to make a reference to the System which can be accessed directly. + /// @verbatim + /// portaudio::AutoSys autoSys; + /// portaudio::System &sys = portaudio::System::instance(); + /// @endverbatim + ////// + class AutoSystem + { + public: + AutoSystem(bool initialize = true) + { + if (initialize) + System::initialize(); + } + + ~AutoSystem() + { + if (System::exists()) + System::terminate(); + } + + void initialize() + { + System::initialize(); + } + + void terminate() + { + System::terminate(); + } + }; + + +} // namespace portaudio + +// --------------------------------------------------------------------------------------- + +#endif // INCLUDED_PORTAUDIO_AUTOSYSTEM_HXX diff --git a/extern/portaudio/bindings/cpp/include/portaudiocpp/BlockingStream.hxx b/extern/portaudio/bindings/cpp/include/portaudiocpp/BlockingStream.hxx new file mode 100644 index 0000000..158dfa0 --- /dev/null +++ b/extern/portaudio/bindings/cpp/include/portaudiocpp/BlockingStream.hxx @@ -0,0 +1,45 @@ +#ifndef INCLUDED_PORTAUDIO_BLOCKINGSTREAM_HXX +#define INCLUDED_PORTAUDIO_BLOCKINGSTREAM_HXX + +// --------------------------------------------------------------------------------------- + +#include "portaudiocpp/Stream.hxx" + +// --------------------------------------------------------------------------------------- + +namespace portaudio +{ + + + + ////// + /// @brief Stream class for blocking read/write-style input and output. + ////// + class BlockingStream : public Stream + { + public: + BlockingStream(); + BlockingStream(const StreamParameters ¶meters); + ~BlockingStream(); + + void open(const StreamParameters ¶meters); + + void read(void *buffer, unsigned long numFrames); + void write(const void *buffer, unsigned long numFrames); + + signed long availableReadSize() const; + signed long availableWriteSize() const; + + private: + BlockingStream(const BlockingStream &); // non-copyable + BlockingStream &operator=(const BlockingStream &); // non-copyable + }; + + + +} // portaudio + +// --------------------------------------------------------------------------------------- + +#endif // INCLUDED_PORTAUDIO_BLOCKINGSTREAM_HXX + diff --git a/extern/portaudio/bindings/cpp/include/portaudiocpp/CFunCallbackStream.hxx b/extern/portaudio/bindings/cpp/include/portaudiocpp/CFunCallbackStream.hxx new file mode 100644 index 0000000..1c7faa8 --- /dev/null +++ b/extern/portaudio/bindings/cpp/include/portaudiocpp/CFunCallbackStream.hxx @@ -0,0 +1,49 @@ +#ifndef INCLUDED_PORTAUDIO_CFUNCALLBACKSTREAM_HXX +#define INCLUDED_PORTAUDIO_CFUNCALLBACKSTREAM_HXX + +// --------------------------------------------------------------------------------------- + +#include "portaudio.h" + +#include "portaudiocpp/CallbackStream.hxx" + +// --------------------------------------------------------------------------------------- + +// Forward declaration(s) +namespace portaudio +{ + class StreamParameters; +} + +// --------------------------------------------------------------------------------------- + +// Declaration(s): +namespace portaudio +{ + // ----------------------------------------------------------------------------------- + + ////// + /// @brief Callback stream using a free function with C linkage. It's important that the function + /// the passed function pointer points to is declared ``extern "C"''. + ////// + class CFunCallbackStream : public CallbackStream + { + public: + CFunCallbackStream(); + CFunCallbackStream(const StreamParameters ¶meters, PaStreamCallback *funPtr, void *userData); + ~CFunCallbackStream(); + + void open(const StreamParameters ¶meters, PaStreamCallback *funPtr, void *userData); + + private: + CFunCallbackStream(const CFunCallbackStream &); // non-copyable + CFunCallbackStream &operator=(const CFunCallbackStream &); // non-copyable + }; + + // ----------------------------------------------------------------------------------- +} // portaudio + +// --------------------------------------------------------------------------------------- + +#endif // INCLUDED_PORTAUDIO_MEMFUNCALLBACKSTREAM_HXX + diff --git a/extern/portaudio/bindings/cpp/include/portaudiocpp/CallbackInterface.hxx b/extern/portaudio/bindings/cpp/include/portaudiocpp/CallbackInterface.hxx new file mode 100644 index 0000000..b306148 --- /dev/null +++ b/extern/portaudio/bindings/cpp/include/portaudiocpp/CallbackInterface.hxx @@ -0,0 +1,45 @@ +#ifndef INCLUDED_PORTAUDIO_CALLBACKINTERFACE_HXX +#define INCLUDED_PORTAUDIO_CALLBACKINTERFACE_HXX + +// --------------------------------------------------------------------------------------- + +#include "portaudio.h" + +// --------------------------------------------------------------------------------------- + +namespace portaudio +{ + // ----------------------------------------------------------------------------------- + + ////// + /// @brief Interface for an object that's callable as a PortAudioCpp callback object (ie that implements the + /// paCallbackFun method). + ////// + class CallbackInterface + { + public: + virtual ~CallbackInterface() {} + + virtual int paCallbackFun(const void *inputBuffer, void *outputBuffer, unsigned long numFrames, + const PaStreamCallbackTimeInfo *timeInfo, PaStreamCallbackFlags statusFlags) = 0; + }; + + // ----------------------------------------------------------------------------------- + + namespace impl + { + extern "C" + { + int callbackInterfaceToPaCallbackAdapter(const void *inputBuffer, void *outputBuffer, unsigned long numFrames, + const PaStreamCallbackTimeInfo *timeInfo, PaStreamCallbackFlags statusFlags, + void *userData); + } // extern "C" + } + + // ----------------------------------------------------------------------------------- + +} // namespace portaudio + +// --------------------------------------------------------------------------------------- + +#endif // INCLUDED_PORTAUDIO_CALLBACKINTERFACE_HXX diff --git a/extern/portaudio/bindings/cpp/include/portaudiocpp/CallbackStream.hxx b/extern/portaudio/bindings/cpp/include/portaudiocpp/CallbackStream.hxx new file mode 100644 index 0000000..7268b14 --- /dev/null +++ b/extern/portaudio/bindings/cpp/include/portaudiocpp/CallbackStream.hxx @@ -0,0 +1,40 @@ +#ifndef INCLUDED_PORTAUDIO_CALLBACKSTREAM_HXX +#define INCLUDED_PORTAUDIO_CALLBACKSTREAM_HXX + +// --------------------------------------------------------------------------------------- + +#include "portaudio.h" + +#include "portaudiocpp/Stream.hxx" + +// --------------------------------------------------------------------------------------- + +// Declaration(s): +namespace portaudio +{ + + + ////// + /// @brief Base class for all Streams which use a callback-based mechanism. + ////// + class CallbackStream : public Stream + { + protected: + CallbackStream(); + virtual ~CallbackStream(); + + public: + // stream info (time-varying) + double cpuLoad() const; + + private: + CallbackStream(const CallbackStream &); // non-copyable + CallbackStream &operator=(const CallbackStream &); // non-copyable + }; + + +} // namespace portaudio + +// --------------------------------------------------------------------------------------- + +#endif // INCLUDED_PORTAUDIO_CALLBACKSTREAM_HXX diff --git a/extern/portaudio/bindings/cpp/include/portaudiocpp/CppFunCallbackStream.hxx b/extern/portaudio/bindings/cpp/include/portaudiocpp/CppFunCallbackStream.hxx new file mode 100644 index 0000000..3f219ee --- /dev/null +++ b/extern/portaudio/bindings/cpp/include/portaudiocpp/CppFunCallbackStream.hxx @@ -0,0 +1,86 @@ +#ifndef INCLUDED_PORTAUDIO_CPPFUNCALLBACKSTREAM_HXX +#define INCLUDED_PORTAUDIO_CPPFUNCALLBACKSTREAM_HXX + +// --------------------------------------------------------------------------------------- + +#include "portaudio.h" + +#include "portaudiocpp/CallbackStream.hxx" + +// --------------------------------------------------------------------------------------- + +// Forward declaration(s): +namespace portaudio +{ + class StreamParameters; +} + +// --------------------------------------------------------------------------------------- + +// Declaration(s): +namespace portaudio +{ + + + namespace impl + { + extern "C" + { + int cppCallbackToPaCallbackAdapter(const void *inputBuffer, void *outputBuffer, unsigned long numFrames, + const PaStreamCallbackTimeInfo *timeInfo, PaStreamCallbackFlags statusFlags, + void *userData); + } // extern "C" + } + + // ----------------------------------------------------------------------------------- + + ////// + /// @brief Callback stream using a C++ function (either a free function or a static function) + /// callback. + ////// + class FunCallbackStream : public CallbackStream + { + public: + typedef int (*CallbackFunPtr)(const void *inputBuffer, void *outputBuffer, unsigned long numFrames, + const PaStreamCallbackTimeInfo *timeInfo, PaStreamCallbackFlags statusFlags, + void *userData); + + // ------------------------------------------------------------------------------- + + ////// + /// @brief Simple structure containing a function pointer to the C++ callback function and a + /// (void) pointer to the user supplied data. + ////// + struct CppToCCallbackData + { + CppToCCallbackData(); + CppToCCallbackData(CallbackFunPtr funPtr, void *userData); + void init(CallbackFunPtr funPtr, void *userData); + + CallbackFunPtr funPtr; + void *userData; + }; + + // ------------------------------------------------------------------------------- + + FunCallbackStream(); + FunCallbackStream(const StreamParameters ¶meters, CallbackFunPtr funPtr, void *userData); + ~FunCallbackStream(); + + void open(const StreamParameters ¶meters, CallbackFunPtr funPtr, void *userData); + + private: + FunCallbackStream(const FunCallbackStream &); // non-copyable + FunCallbackStream &operator=(const FunCallbackStream &); // non-copyable + + CppToCCallbackData adapterData_; + + void open(const StreamParameters ¶meters); + }; + + +} // portaudio + +// --------------------------------------------------------------------------------------- + +#endif // INCLUDED_PORTAUDIO_CPPFUNCALLBACKSTREAM_HXX diff --git a/extern/portaudio/bindings/cpp/include/portaudiocpp/Device.hxx b/extern/portaudio/bindings/cpp/include/portaudiocpp/Device.hxx new file mode 100644 index 0000000..3c6c3c0 --- /dev/null +++ b/extern/portaudio/bindings/cpp/include/portaudiocpp/Device.hxx @@ -0,0 +1,91 @@ +#ifndef INCLUDED_PORTAUDIO_DEVICE_HXX +#define INCLUDED_PORTAUDIO_DEVICE_HXX + +// --------------------------------------------------------------------------------------- + +#include + +#include "portaudio.h" + +#include "portaudiocpp/SampleDataFormat.hxx" + +// --------------------------------------------------------------------------------------- + +// Forward declaration(s): +namespace portaudio +{ + class System; + class HostApi; +} + +// --------------------------------------------------------------------------------------- + +// Declaration(s): +namespace portaudio +{ + + ////// + /// @brief Class which represents a PortAudio device in the System. + /// + /// A single physical device in the system may have multiple PortAudio + /// Device representations using different HostApi 's though. A Device + /// can be half-duplex or full-duplex. A half-duplex Device can be used + /// to create a half-duplex Stream. A full-duplex Device can be used to + /// create a full-duplex Stream. If supported by the HostApi, two + /// half-duplex Devices can even be used to create a full-duplex Stream. + /// + /// Note that Device objects are very light-weight and can be passed around + /// by-value. + ////// + class Device + { + public: + // query info: name, max in channels, max out channels, + // default low/hight input/output latency, default sample rate + PaDeviceIndex index() const; + const char *name() const; + int maxInputChannels() const; + int maxOutputChannels() const; + PaTime defaultLowInputLatency() const; + PaTime defaultHighInputLatency() const; + PaTime defaultLowOutputLatency() const; + PaTime defaultHighOutputLatency() const; + double defaultSampleRate() const; + + bool isInputOnlyDevice() const; // extended + bool isOutputOnlyDevice() const; // extended + bool isFullDuplexDevice() const; // extended + bool isSystemDefaultInputDevice() const; // extended + bool isSystemDefaultOutputDevice() const; // extended + bool isHostApiDefaultInputDevice() const; // extended + bool isHostApiDefaultOutputDevice() const; // extended + + bool operator==(const Device &rhs) const; + bool operator!=(const Device &rhs) const; + + // host api reference + HostApi &hostApi(); + const HostApi &hostApi() const; + + private: + PaDeviceIndex index_; + const PaDeviceInfo *info_; + + private: + friend class System; + + explicit Device(PaDeviceIndex index); + ~Device(); + + Device(const Device &); // non-copyable + Device &operator=(const Device &); // non-copyable + }; + + // ----------------------------------------------------------------------------------- + +} // namespace portaudio + +// --------------------------------------------------------------------------------------- + +#endif // INCLUDED_PORTAUDIO_DEVICE_HXX + diff --git a/extern/portaudio/bindings/cpp/include/portaudiocpp/DirectionSpecificStreamParameters.hxx b/extern/portaudio/bindings/cpp/include/portaudiocpp/DirectionSpecificStreamParameters.hxx new file mode 100644 index 0000000..bc24742 --- /dev/null +++ b/extern/portaudio/bindings/cpp/include/portaudiocpp/DirectionSpecificStreamParameters.hxx @@ -0,0 +1,77 @@ +#ifndef INCLUDED_PORTAUDIO_SINGLEDIRECTIONSTREAMPARAMETERS_HXX +#define INCLUDED_PORTAUDIO_SINGLEDIRECTIONSTREAMPARAMETERS_HXX + +// --------------------------------------------------------------------------------------- + +#include + +#include "portaudio.h" + +#include "portaudiocpp/System.hxx" +#include "portaudiocpp/SampleDataFormat.hxx" + +// --------------------------------------------------------------------------------------- + +// Forward declaration(s): +namespace portaudio +{ + class Device; +} + +// --------------------------------------------------------------------------------------- + +// Declaration(s): +namespace portaudio +{ + + ////// + /// @brief All parameters for one direction (either in or out) of a Stream. Together with + /// parameters common to both directions, two DirectionSpecificStreamParameters can make up + /// a StreamParameters object which contains all parameters for a Stream. + ////// + class DirectionSpecificStreamParameters + { + public: + static DirectionSpecificStreamParameters null(); + + DirectionSpecificStreamParameters(); + DirectionSpecificStreamParameters(const Device &device, int numChannels, SampleDataFormat format, + bool interleaved, PaTime suggestedLatency, void *hostApiSpecificStreamInfo); + + // Set up methods: + void setDevice(const Device &device); + void setNumChannels(int numChannels); + + void setSampleFormat(SampleDataFormat format, bool interleaved = true); + void setHostApiSpecificSampleFormat(PaSampleFormat format, bool interleaved = true); + + void setSuggestedLatency(PaTime latency); + + void setHostApiSpecificStreamInfo(void *streamInfo); + + // Accessor methods: + PaStreamParameters *paStreamParameters(); + const PaStreamParameters *paStreamParameters() const; + + Device &device() const; + int numChannels() const; + + SampleDataFormat sampleFormat() const; + bool isSampleFormatInterleaved() const; + bool isSampleFormatHostApiSpecific() const; + PaSampleFormat hostApiSpecificSampleFormat() const; + + PaTime suggestedLatency() const; + + void *hostApiSpecificStreamInfo() const; + + private: + PaStreamParameters paStreamParameters_; + }; + + +} // namespace portaudio + +// --------------------------------------------------------------------------------------- + +#endif // INCLUDED_PORTAUDIO_SINGLEDIRECTIONSTREAMPARAMETERS_HXX diff --git a/extern/portaudio/bindings/cpp/include/portaudiocpp/Exception.hxx b/extern/portaudio/bindings/cpp/include/portaudiocpp/Exception.hxx new file mode 100644 index 0000000..f5249c9 --- /dev/null +++ b/extern/portaudio/bindings/cpp/include/portaudiocpp/Exception.hxx @@ -0,0 +1,108 @@ +#ifndef INCLUDED_PORTAUDIO_EXCEPTION_HXX +#define INCLUDED_PORTAUDIO_EXCEPTION_HXX + +// --------------------------------------------------------------------------------------- + +#include + +#include "portaudio.h" + +// --------------------------------------------------------------------------------------- + +namespace portaudio +{ + + ////// + /// @brief Base class for all exceptions PortAudioCpp can throw. + /// + /// Class is derived from std::exception. + ////// + class Exception : public std::exception + { + public: + virtual ~Exception() throw() {} + + virtual const char *what() const throw() = 0; + }; + + // ----------------------------------------------------------------------------------- + + ////// + /// @brief Wrapper for PortAudio error codes to C++ exceptions. + /// + /// It wraps up PortAudio's error handling mechanism using + /// C++ exceptions and is derived from std::exception for + /// easy exception handling and to ease integration with + /// other code. + /// + /// To know what exceptions each function may throw, look up + /// the errors that can occure in the PortAudio documentation + /// for the equivalent functions. + /// + /// Some functions are likely to throw an exception (such as + /// Stream::open(), etc) and these should always be called in + /// try{} catch{} blocks and the thrown exceptions should be + /// handled properly (ie. the application shouldn't just abort, + /// but merely display a warning dialog to the user or something). + /// However nearly all functions in PortAudioCpp are capable + /// of throwing exceptions. When a function like Stream::isStopped() + /// throws an exception, it's such an exceptional state that it's + /// not likely that it can be recovered. PaExceptions such as these + /// can ``safely'' be left to be handled by some outer catch-all-like + /// mechanism for unrecoverable errors. + ////// + class PaException : public Exception + { + public: + explicit PaException(PaError error); + + const char *what() const throw(); + + PaError paError() const; + const char *paErrorText() const; + + bool isHostApiError() const; // extended + long lastHostApiError() const; + const char *lastHostApiErrorText() const; + + bool operator==(const PaException &rhs) const; + bool operator!=(const PaException &rhs) const; + + private: + PaError error_; + }; + + // ----------------------------------------------------------------------------------- + + ////// + /// @brief Exceptions specific to PortAudioCpp (ie. exceptions which do not have an + /// equivalent PortAudio error code). + ////// + class PaCppException : public Exception + { + public: + enum ExceptionSpecifier + { + UNABLE_TO_ADAPT_DEVICE + }; + + PaCppException(ExceptionSpecifier specifier); + + const char *what() const throw(); + + ExceptionSpecifier specifier() const; + + bool operator==(const PaCppException &rhs) const; + bool operator!=(const PaCppException &rhs) const; + + private: + ExceptionSpecifier specifier_; + }; + + +} // namespace portaudio + +// --------------------------------------------------------------------------------------- + +#endif // INCLUDED_PORTAUDIO_EXCEPTION_HXX + diff --git a/extern/portaudio/bindings/cpp/include/portaudiocpp/HostApi.hxx b/extern/portaudio/bindings/cpp/include/portaudiocpp/HostApi.hxx new file mode 100644 index 0000000..ce397ca --- /dev/null +++ b/extern/portaudio/bindings/cpp/include/portaudiocpp/HostApi.hxx @@ -0,0 +1,76 @@ +#ifndef INCLUDED_PORTAUDIO_HOSTAPI_HXX +#define INCLUDED_PORTAUDIO_HOSTAPI_HXX + +// --------------------------------------------------------------------------------------- + +#include "portaudio.h" + +#include "portaudiocpp/System.hxx" + +// --------------------------------------------------------------------------------------- + +// Forward declaration(s): +namespace portaudio +{ + class Device; +} + +// --------------------------------------------------------------------------------------- + +// Declaration(s): +namespace portaudio +{ + + + ////// + /// @brief HostApi represents a host API (usually type of driver) in the System. + /// + /// A single System can support multiple HostApi's each one typically having + /// a set of Devices using that HostApi (usually driver type). All Devices in + /// the HostApi can be enumerated and the default input/output Device for this + /// HostApi can be retreived. + ////// + class HostApi + { + public: + typedef System::DeviceIterator DeviceIterator; + + // query info: id, name, numDevices + PaHostApiTypeId typeId() const; + PaHostApiIndex index() const; + const char *name() const; + int deviceCount() const; + + // iterate devices + DeviceIterator devicesBegin(); + DeviceIterator devicesEnd(); + + // default devices + Device &defaultInputDevice() const; + Device &defaultOutputDevice() const; + + // comparison operators + bool operator==(const HostApi &rhs) const; + bool operator!=(const HostApi &rhs) const; + + private: + const PaHostApiInfo *info_; + Device **devices_; + + private: + friend class System; + + explicit HostApi(PaHostApiIndex index); + ~HostApi(); + + HostApi(const HostApi &); // non-copyable + HostApi &operator=(const HostApi &); // non-copyable + }; + + +} + +// --------------------------------------------------------------------------------------- + +#endif // INCLUDED_PORTAUDIO_HOSTAPI_HXX + diff --git a/extern/portaudio/bindings/cpp/include/portaudiocpp/InterfaceCallbackStream.hxx b/extern/portaudio/bindings/cpp/include/portaudiocpp/InterfaceCallbackStream.hxx new file mode 100644 index 0000000..5aa49e7 --- /dev/null +++ b/extern/portaudio/bindings/cpp/include/portaudiocpp/InterfaceCallbackStream.hxx @@ -0,0 +1,49 @@ +#ifndef INCLUDED_PORTAUDIO_INTERFACECALLBACKSTREAM_HXX +#define INCLUDED_PORTAUDIO_INTERFACECALLBACKSTREAM_HXX + +// --------------------------------------------------------------------------------------- + +#include "portaudio.h" + +#include "portaudiocpp/CallbackStream.hxx" + +// --------------------------------------------------------------------------------------- + +// Forward declaration(s) +namespace portaudio +{ + class StreamParameters; + class CallbackInterface; +} + +// --------------------------------------------------------------------------------------- + +// Declaration(s): +namespace portaudio +{ + + + ////// + /// @brief Callback stream using an instance of an object that's derived from the CallbackInterface + /// interface. + ////// + class InterfaceCallbackStream : public CallbackStream + { + public: + InterfaceCallbackStream(); + InterfaceCallbackStream(const StreamParameters ¶meters, CallbackInterface &instance); + ~InterfaceCallbackStream(); + + void open(const StreamParameters ¶meters, CallbackInterface &instance); + + private: + InterfaceCallbackStream(const InterfaceCallbackStream &); // non-copyable + InterfaceCallbackStream &operator=(const InterfaceCallbackStream &); // non-copyable + }; + + +} // portaudio + +// --------------------------------------------------------------------------------------- + +#endif // INCLUDED_PORTAUDIO_INTERFACECALLBACKSTREAM_HXX diff --git a/extern/portaudio/bindings/cpp/include/portaudiocpp/MemFunCallbackStream.hxx b/extern/portaudio/bindings/cpp/include/portaudiocpp/MemFunCallbackStream.hxx new file mode 100644 index 0000000..01cf37b --- /dev/null +++ b/extern/portaudio/bindings/cpp/include/portaudiocpp/MemFunCallbackStream.hxx @@ -0,0 +1,107 @@ +#ifndef INCLUDED_PORTAUDIO_MEMFUNCALLBACKSTREAM_HXX +#define INCLUDED_PORTAUDIO_MEMFUNCALLBACKSTREAM_HXX + +// --------------------------------------------------------------------------------------- + +#include "portaudio.h" + +#include "portaudiocpp/CallbackStream.hxx" +#include "portaudiocpp/CallbackInterface.hxx" +#include "portaudiocpp/StreamParameters.hxx" +#include "portaudiocpp/Exception.hxx" +#include "portaudiocpp/InterfaceCallbackStream.hxx" + +// --------------------------------------------------------------------------------------- + +namespace portaudio +{ + + + ////// + /// @brief Callback stream using a class's member function as a callback. Template argument T is the type of the + /// class of which a member function is going to be used. + /// + /// Example usage: + /// @verbatim MemFunCallback stream = MemFunCallbackStream(parameters, *this, &MyClass::myCallbackFunction); @endverbatim + ////// + template + class MemFunCallbackStream : public CallbackStream + { + public: + typedef int (T::*CallbackFunPtr)(const void *, void *, unsigned long, const PaStreamCallbackTimeInfo *, + PaStreamCallbackFlags); + + // ------------------------------------------------------------------------------- + + MemFunCallbackStream() + { + } + + MemFunCallbackStream(const StreamParameters ¶meters, T &instance, CallbackFunPtr memFun) : adapter_(instance, memFun) + { + open(parameters); + } + + ~MemFunCallbackStream() + { + close(); + } + + void open(const StreamParameters ¶meters, T &instance, CallbackFunPtr memFun) + { + // XXX: need to check if already open? + + adapter_.init(instance, memFun); + open(parameters); + } + + private: + MemFunCallbackStream(const MemFunCallbackStream &); // non-copyable + MemFunCallbackStream &operator=(const MemFunCallbackStream &); // non-copyable + + ////// + /// @brief Inner class which adapts a member function callback to a CallbackInterface compliant + /// class (so it can be adapted using the paCallbackAdapter function). + ////// + class MemFunToCallbackInterfaceAdapter : public CallbackInterface + { + public: + MemFunToCallbackInterfaceAdapter() {} + MemFunToCallbackInterfaceAdapter(T &instance, CallbackFunPtr memFun) : instance_(&instance), memFun_(memFun) {} + + void init(T &instance, CallbackFunPtr memFun) + { + instance_ = &instance; + memFun_ = memFun; + } + + int paCallbackFun(const void *inputBuffer, void *outputBuffer, unsigned long numFrames, + const PaStreamCallbackTimeInfo *timeInfo, PaStreamCallbackFlags statusFlags) + { + return (instance_->*memFun_)(inputBuffer, outputBuffer, numFrames, timeInfo, statusFlags); + } + + private: + T *instance_; + CallbackFunPtr memFun_; + }; + + MemFunToCallbackInterfaceAdapter adapter_; + + void open(const StreamParameters ¶meters) + { + PaError err = Pa_OpenStream(&stream_, parameters.inputParameters().paStreamParameters(), parameters.outputParameters().paStreamParameters(), + parameters.sampleRate(), parameters.framesPerBuffer(), parameters.flags(), &impl::callbackInterfaceToPaCallbackAdapter, + static_cast(&adapter_)); + + if (err != paNoError) + throw PaException(err); + } + }; + + +} // portaudio + +// --------------------------------------------------------------------------------------- + +#endif // INCLUDED_PORTAUDIO_MEMFUNCALLBACKSTREAM_HXX diff --git a/extern/portaudio/bindings/cpp/include/portaudiocpp/PortAudioCpp.hxx b/extern/portaudio/bindings/cpp/include/portaudiocpp/PortAudioCpp.hxx new file mode 100644 index 0000000..96df96e --- /dev/null +++ b/extern/portaudio/bindings/cpp/include/portaudiocpp/PortAudioCpp.hxx @@ -0,0 +1,109 @@ +#ifndef INCLUDED_PORTAUDIO_PORTAUDIOCPP_HXX +#define INCLUDED_PORTAUDIO_PORTAUDIOCPP_HXX + +// --------------------------------------------------------------------------------------- + +////// +/// @mainpage PortAudioCpp +/// +///

    PortAudioCpp - A Native C++ Binding of PortAudio V19

    +///

    PortAudio

    +///

    +/// PortAudio is a portable and mature C API for accessing audio hardware. It offers both callback-based and blocking +/// style input and output, deals with sample data format conversions, dithering and much more. There are a large number +/// of implementations available for various platforms including Windows MME, Windows DirectX, Windows and MacOS (Classic) +/// ASIO, MacOS Classic SoundManager, MacOS X CoreAudio, OSS (Linux), Linux ALSA, JACK (MacOS X and Linux) and SGI Irix +/// AL. Note that, currently not all of these implementations are equally complete or up-to-date (as PortAudio V19 is +/// still in development). Because PortAudio has a C API, it can easily be called from a variety of other programming +/// languages. +///

    +///

    PortAudioCpp

    +///

    +/// Although, it is possible to use PortAudio's C API from within a C++ program, this is usually a little awkward +/// as procedural and object-oriented paradigms need to be mixed. PortAudioCpp aims to resolve this by encapsulating +/// PortAudio's C API to form an equivalent object-oriented C++ API. It provides a more natural integration of PortAudio +/// into C++ programs as well as a more structured interface. PortAudio's concepts were preserved as much as possible and +/// no additional features were added except for some `convenience methods'. +///

    +///

    +/// PortAudioCpp's main features are: +///

      +///
    • Structured object model.
    • +///
    • C++ exception handling instead of C-style error return codes.
    • +///
    • Handling of callbacks using free functions (C and C++), static functions, member functions or instances of classes +/// derived from a given interface.
    • +///
    • STL compliant iterators to host APIs and devices.
    • +///
    • Some additional convenience functions to more easily set up and use PortAudio.
    • +///
    +///

    +///

    +/// PortAudioCpp requires a recent version of the PortAudio V19 source code. This can be obtained from CVS or as a snapshot +/// from the website. The examples also require the ASIO 2 SDK which can be obtained from the Steinberg website. Alternatively, the +/// examples can easily be modified to compile without needing ASIO. +///

    +///

    +/// Supported platforms: +///

      +///
    • Microsoft Visual C++ 6.0, 7.0 (.NET 2002) and 7.1 (.NET 2003).
    • +///
    • GNU G++ 2.95 and G++ 3.3.
    • +///
    +/// Other platforms should be easily supported as PortAudioCpp is platform-independent and (reasonably) C++ standard compliant. +///

    +///

    +/// This documentation mainly provides information specific to PortAudioCpp. For a more complete explaination of all of the +/// concepts used, please consult the PortAudio documentation. +///

    +///

    +/// PortAudioCpp was developed by Merlijn Blaauw with many great suggestions and help from Ross Bencina. Ludwig Schwardt provided +/// GNU/Linux build files and checked G++ compatibility. PortAudioCpp may be used under the same licensing, conditions and +/// warranty as PortAudio. See the PortAudio license for more details. +///

    +///

    Links

    +///

    +/// Official PortAudio site.
    +///

    +////// + +// --------------------------------------------------------------------------------------- + +////// +/// @namespace portaudio +/// +/// To avoid name collision, everything in PortAudioCpp is in the portaudio +/// namespace. If this name is too long it's usually pretty safe to use an +/// alias like ``namespace pa = portaudio;''. +////// + +// --------------------------------------------------------------------------------------- + +////// +/// @file PortAudioCpp.hxx +/// An include-all header file (for lazy programmers and using pre-compiled headers). +////// + +// --------------------------------------------------------------------------------------- + +#include "portaudio.h" + +#include "portaudiocpp/AutoSystem.hxx" +#include "portaudiocpp/BlockingStream.hxx" +#include "portaudiocpp/CallbackInterface.hxx" +#include "portaudiocpp/CallbackStream.hxx" +#include "portaudiocpp/CFunCallbackStream.hxx" +#include "portaudiocpp/CppFunCallbackStream.hxx" +#include "portaudiocpp/Device.hxx" +#include "portaudiocpp/Exception.hxx" +#include "portaudiocpp/HostApi.hxx" +#include "portaudiocpp/InterfaceCallbackStream.hxx" +#include "portaudiocpp/MemFunCallbackStream.hxx" +#include "portaudiocpp/SampleDataFormat.hxx" +#include "portaudiocpp/DirectionSpecificStreamParameters.hxx" +#include "portaudiocpp/Stream.hxx" +#include "portaudiocpp/StreamParameters.hxx" +#include "portaudiocpp/System.hxx" +#include "portaudiocpp/SystemDeviceIterator.hxx" +#include "portaudiocpp/SystemHostApiIterator.hxx" + +// --------------------------------------------------------------------------------------- + +#endif // INCLUDED_PORTAUDIO_PORTAUDIOCPP_HXX diff --git a/extern/portaudio/bindings/cpp/include/portaudiocpp/SampleDataFormat.hxx b/extern/portaudio/bindings/cpp/include/portaudiocpp/SampleDataFormat.hxx new file mode 100644 index 0000000..1d3a1d9 --- /dev/null +++ b/extern/portaudio/bindings/cpp/include/portaudiocpp/SampleDataFormat.hxx @@ -0,0 +1,35 @@ +#ifndef INCLUDED_PORTAUDIO_SAMPLEDATAFORMAT_HXX +#define INCLUDED_PORTAUDIO_SAMPLEDATAFORMAT_HXX + +// --------------------------------------------------------------------------------------- + +#include "portaudio.h" + +// --------------------------------------------------------------------------------------- + +namespace portaudio +{ + + + ////// + /// @brief PortAudio sample data formats. + /// + /// Small helper enum to wrap the PortAudio defines. + ////// + enum SampleDataFormat + { + INVALID_FORMAT = 0, + FLOAT32 = paFloat32, + INT32 = paInt32, + INT24 = paInt24, + INT16 = paInt16, + INT8 = paInt8, + UINT8 = paUInt8 + }; + + +} // namespace portaudio + +// --------------------------------------------------------------------------------------- + +#endif // INCLUDED_PORTAUDIO_SAMPLEDATAFORMAT_HXX diff --git a/extern/portaudio/bindings/cpp/include/portaudiocpp/Stream.hxx b/extern/portaudio/bindings/cpp/include/portaudiocpp/Stream.hxx new file mode 100644 index 0000000..1aed747 --- /dev/null +++ b/extern/portaudio/bindings/cpp/include/portaudiocpp/Stream.hxx @@ -0,0 +1,82 @@ +#ifndef INCLUDED_PORTAUDIO_STREAM_HXX +#define INCLUDED_PORTAUDIO_STREAM_HXX + +#include "portaudio.h" + +// --------------------------------------------------------------------------------------- + +// Forward declaration(s): +namespace portaudio +{ + class StreamParameters; +} + +// --------------------------------------------------------------------------------------- + +// Declaration(s): +namespace portaudio +{ + + + ////// + /// @brief A Stream represents an active or inactive input and/or output data + /// stream in the System. + /// + /// Concrete Stream classes should ensure themselves being in a closed state at + /// destruction (i.e. by calling their own close() method in their deconstructor). + /// Following good C++ programming practices, care must be taken to ensure no + /// exceptions are thrown by the deconstructor of these classes. As a consequence, + /// clients need to explicitly call close() to ensure the stream closed successfully. + /// + /// The Stream object can be used to manipulate the Stream's state. Also, time-constant + /// and time-varying information about the Stream can be retreived. + ////// + class Stream + { + public: + // Opening/closing: + virtual ~Stream(); + + virtual void close(); + bool isOpen() const; + + // Additional set up: + void setStreamFinishedCallback(PaStreamFinishedCallback *callback); + + // State management: + void start(); + void stop(); + void abort(); + + bool isStopped() const; + bool isActive() const; + + // Stream info (time-constant, but might become time-variant soon): + PaTime inputLatency() const; + PaTime outputLatency() const; + double sampleRate() const; + + // Stream info (time-varying): + PaTime time() const; + + // Accessors for PortAudio PaStream, useful for interfacing + // with PortAudio add-ons (such as PortMixer) for instance: + const PaStream *paStream() const; + PaStream *paStream(); + + protected: + Stream(); // abstract class + + PaStream *stream_; + + private: + Stream(const Stream &); // non-copyable + Stream &operator=(const Stream &); // non-copyable + }; + + +} // namespace portaudio + + +#endif // INCLUDED_PORTAUDIO_STREAM_HXX + diff --git a/extern/portaudio/bindings/cpp/include/portaudiocpp/StreamParameters.hxx b/extern/portaudio/bindings/cpp/include/portaudiocpp/StreamParameters.hxx new file mode 100644 index 0000000..c0ec9a9 --- /dev/null +++ b/extern/portaudio/bindings/cpp/include/portaudiocpp/StreamParameters.hxx @@ -0,0 +1,77 @@ +#ifndef INCLUDED_PORTAUDIO_STREAMPARAMETERS_HXX +#define INCLUDED_PORTAUDIO_STREAMPARAMETERS_HXX + +// --------------------------------------------------------------------------------------- + +#include "portaudio.h" + +#include "portaudiocpp/DirectionSpecificStreamParameters.hxx" + +// --------------------------------------------------------------------------------------- + +// Declaration(s): +namespace portaudio +{ + + ////// + /// @brief The entire set of parameters needed to configure and open + /// a Stream. + /// + /// It contains parameters of input, output and shared parameters. + /// Using the isSupported() method, the StreamParameters can be + /// checked if opening a Stream using this StreamParameters would + /// succeed or not. Accessors are provided to higher-level parameters + /// aswell as the lower-level parameters which are mainly intended for + /// internal use. + ////// + class StreamParameters + { + public: + StreamParameters(); + StreamParameters(const DirectionSpecificStreamParameters &inputParameters, + const DirectionSpecificStreamParameters &outputParameters, double sampleRate, + unsigned long framesPerBuffer, PaStreamFlags flags); + + // Set up for direction-specific: + void setInputParameters(const DirectionSpecificStreamParameters ¶meters); + void setOutputParameters(const DirectionSpecificStreamParameters ¶meters); + + // Set up for common parameters: + void setSampleRate(double sampleRate); + void setFramesPerBuffer(unsigned long framesPerBuffer); + void setFlag(PaStreamFlags flag); + void unsetFlag(PaStreamFlags flag); + void clearFlags(); + + // Validation: + bool isSupported() const; + + // Accessors (direction-specific): + DirectionSpecificStreamParameters &inputParameters(); + const DirectionSpecificStreamParameters &inputParameters() const; + DirectionSpecificStreamParameters &outputParameters(); + const DirectionSpecificStreamParameters &outputParameters() const; + + // Accessors (common): + double sampleRate() const; + unsigned long framesPerBuffer() const; + PaStreamFlags flags() const; + bool isFlagSet(PaStreamFlags flag) const; + + private: + // Half-duplex specific parameters: + DirectionSpecificStreamParameters inputParameters_; + DirectionSpecificStreamParameters outputParameters_; + + // Common parameters: + double sampleRate_; + unsigned long framesPerBuffer_; + PaStreamFlags flags_; + }; + + +} // namespace portaudio + +// --------------------------------------------------------------------------------------- + +#endif // INCLUDED_PORTAUDIO_STREAMPARAMETERS_HXX diff --git a/extern/portaudio/bindings/cpp/include/portaudiocpp/System.hxx b/extern/portaudio/bindings/cpp/include/portaudiocpp/System.hxx new file mode 100644 index 0000000..d5ff9dd --- /dev/null +++ b/extern/portaudio/bindings/cpp/include/portaudiocpp/System.hxx @@ -0,0 +1,107 @@ +#ifndef INCLUDED_PORTAUDIO_SYSTEM_HXX +#define INCLUDED_PORTAUDIO_SYSTEM_HXX + +// --------------------------------------------------------------------------------------- + +#include "portaudio.h" + +// --------------------------------------------------------------------------------------- + +// Forward declaration(s): +namespace portaudio +{ + class Device; + class Stream; + class HostApi; +} + +// --------------------------------------------------------------------------------------- + +// Declaration(s): +namespace portaudio +{ + + + ////// + /// @brief System singleton which represents the PortAudio system. + /// + /// The System is used to initialize/terminate PortAudio and provide + /// a single acccess point to the PortAudio System (instance()). + /// It can be used to iterate through all HostApi 's in the System as + /// well as all devices in the System. It also provides some utility + /// functionality of PortAudio. + /// + /// Terminating the System will also abort and close the open streams. + /// The Stream objects will need to be deallocated by the client though + /// (it's usually a good idea to have them cleaned up automatically). + ////// + class System + { + public: + class HostApiIterator; // forward declaration + class DeviceIterator; // forward declaration + + // ------------------------------------------------------------------------------- + + static int version(); + static const char *versionText(); + + static void initialize(); + static void terminate(); + + static System &instance(); + static bool exists(); + + // ------------------------------------------------------------------------------- + + // host apis: + HostApiIterator hostApisBegin(); + HostApiIterator hostApisEnd(); + + HostApi &defaultHostApi(); + + HostApi &hostApiByTypeId(PaHostApiTypeId type); + HostApi &hostApiByIndex(PaHostApiIndex index); + + int hostApiCount(); + + // ------------------------------------------------------------------------------- + + // devices: + DeviceIterator devicesBegin(); + DeviceIterator devicesEnd(); + + Device &defaultInputDevice(); + Device &defaultOutputDevice(); + + Device &deviceByIndex(PaDeviceIndex index); + + int deviceCount(); + + static Device &nullDevice(); + + // ------------------------------------------------------------------------------- + + // misc: + void sleep(long msec); + int sizeOfSample(PaSampleFormat format); + + private: + System(); + ~System(); + + static System *instance_; + static int initCount_; + + static HostApi **hostApis_; + static Device **devices_; + + static Device *nullDevice_; + }; + + +} // namespace portaudio + + +#endif // INCLUDED_PORTAUDIO_SYSTEM_HXX + diff --git a/extern/portaudio/bindings/cpp/include/portaudiocpp/SystemDeviceIterator.hxx b/extern/portaudio/bindings/cpp/include/portaudiocpp/SystemDeviceIterator.hxx new file mode 100644 index 0000000..ffa195d --- /dev/null +++ b/extern/portaudio/bindings/cpp/include/portaudiocpp/SystemDeviceIterator.hxx @@ -0,0 +1,66 @@ +#ifndef INCLUDED_PORTAUDIO_SYSTEMDEVICEITERATOR_HXX +#define INCLUDED_PORTAUDIO_SYSTEMDEVICEITERATOR_HXX + +// --------------------------------------------------------------------------------------- + +#include +#include + +#include "portaudiocpp/System.hxx" + +// --------------------------------------------------------------------------------------- + +// Forward declaration(s): +namespace portaudio +{ + class Device; + class HostApi; +} + +// --------------------------------------------------------------------------------------- + +// Declaration(s): +namespace portaudio +{ + + + ////// + /// @brief Iterator class for iterating through all Devices in a System. + /// + /// Devices will be iterated by iterating all Devices in each + /// HostApi in the System. Compliant with the STL bidirectional + /// iterator concept. + ////// + class System::DeviceIterator + { + public: + typedef std::bidirectional_iterator_tag iterator_category; + typedef Device value_type; + typedef ptrdiff_t difference_type; + typedef Device * pointer; + typedef Device & reference; + + Device &operator*() const; + Device *operator->() const; + + DeviceIterator &operator++(); + DeviceIterator operator++(int); + DeviceIterator &operator--(); + DeviceIterator operator--(int); + + bool operator==(const DeviceIterator &rhs) const; + bool operator!=(const DeviceIterator &rhs) const; + + private: + friend class System; + friend class HostApi; + Device **ptr_; + }; + + +} // namespace portaudio + +// --------------------------------------------------------------------------------------- + +#endif // INCLUDED_PORTAUDIO_SYSTEMDEVICEITERATOR_HXX + diff --git a/extern/portaudio/bindings/cpp/include/portaudiocpp/SystemHostApiIterator.hxx b/extern/portaudio/bindings/cpp/include/portaudiocpp/SystemHostApiIterator.hxx new file mode 100644 index 0000000..3e6a978 --- /dev/null +++ b/extern/portaudio/bindings/cpp/include/portaudiocpp/SystemHostApiIterator.hxx @@ -0,0 +1,61 @@ +#ifndef INCLUDED_PORTAUDIO_SYSTEMHOSTAPIITERATOR_HXX +#define INCLUDED_PORTAUDIO_SYSTEMHOSTAPIITERATOR_HXX + +// --------------------------------------------------------------------------------------- + +#include +#include + +#include "portaudiocpp/System.hxx" + +// --------------------------------------------------------------------------------------- + +// Forward declaration(s): +namespace portaudio +{ + class HostApi; +} + +// --------------------------------------------------------------------------------------- + +// Declaration(s): +namespace portaudio +{ + + + ////// + /// @brief Iterator class for iterating through all HostApis in a System. + /// + /// Compliant with the STL bidirectional iterator concept. + ////// + class System::HostApiIterator + { + public: + typedef std::bidirectional_iterator_tag iterator_category; + typedef Device value_type; + typedef ptrdiff_t difference_type; + typedef HostApi * pointer; + typedef HostApi & reference; + + HostApi &operator*() const; + HostApi *operator->() const; + + HostApiIterator &operator++(); + HostApiIterator operator++(int); + HostApiIterator &operator--(); + HostApiIterator operator--(int); + + bool operator==(const HostApiIterator &rhs) const; + bool operator!=(const HostApiIterator &rhs) const; + + private: + friend class System; + HostApi **ptr_; + }; + + +} // namespace portaudio + +// --------------------------------------------------------------------------------------- + +#endif // INCLUDED_PORTAUDIO_SYSTEMHOSTAPIITERATOR_HXX diff --git a/extern/portaudio/bindings/cpp/lib/Makefile.am b/extern/portaudio/bindings/cpp/lib/Makefile.am new file mode 100644 index 0000000..a27f7c5 --- /dev/null +++ b/extern/portaudio/bindings/cpp/lib/Makefile.am @@ -0,0 +1,26 @@ +SRCDIR = $(top_srcdir)/source/portaudiocpp + +lib_LTLIBRARIES = libportaudiocpp.la + +LDADD = libportaudiocpp.la + +libportaudiocpp_la_LDFLAGS = -version-info $(LT_VERSION_INFO) -no-undefined + +libportaudiocpp_la_LIBADD = $(top_builddir)/$(PORTAUDIO_ROOT)/lib/libportaudio.la +libportaudiocpp_la_SOURCES = \ + $(SRCDIR)/BlockingStream.cxx \ + $(SRCDIR)/CallbackInterface.cxx \ + $(SRCDIR)/CallbackStream.cxx \ + $(SRCDIR)/CFunCallbackStream.cxx \ + $(SRCDIR)/CppFunCallbackStream.cxx \ + $(SRCDIR)/Device.cxx \ + $(SRCDIR)/DirectionSpecificStreamParameters.cxx \ + $(SRCDIR)/Exception.cxx \ + $(SRCDIR)/HostApi.cxx \ + $(SRCDIR)/InterfaceCallbackStream.cxx \ + $(SRCDIR)/MemFunCallbackStream.cxx \ + $(SRCDIR)/Stream.cxx \ + $(SRCDIR)/StreamParameters.cxx \ + $(SRCDIR)/System.cxx \ + $(SRCDIR)/SystemDeviceIterator.cxx \ + $(SRCDIR)/SystemHostApiIterator.cxx diff --git a/extern/portaudio/bindings/cpp/lib/Makefile.in b/extern/portaudio/bindings/cpp/lib/Makefile.in new file mode 100644 index 0000000..db0d614 --- /dev/null +++ b/extern/portaudio/bindings/cpp/lib/Makefile.in @@ -0,0 +1,789 @@ +# Makefile.in generated by automake 1.14.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2013 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = lib +DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ + $(top_srcdir)/../../depcomp +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__uninstall_files_from_dir = { \ + test -z "$$files" \ + || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ + || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ + $(am__cd) "$$dir" && rm -f $$files; }; \ + } +am__installdirs = "$(DESTDIR)$(libdir)" +LTLIBRARIES = $(lib_LTLIBRARIES) +libportaudiocpp_la_DEPENDENCIES = \ + $(top_builddir)/$(PORTAUDIO_ROOT)/lib/libportaudio.la +am_libportaudiocpp_la_OBJECTS = BlockingStream.lo CallbackInterface.lo \ + CallbackStream.lo CFunCallbackStream.lo \ + CppFunCallbackStream.lo Device.lo \ + DirectionSpecificStreamParameters.lo Exception.lo HostApi.lo \ + InterfaceCallbackStream.lo MemFunCallbackStream.lo Stream.lo \ + StreamParameters.lo System.lo SystemDeviceIterator.lo \ + SystemHostApiIterator.lo +libportaudiocpp_la_OBJECTS = $(am_libportaudiocpp_la_OBJECTS) +AM_V_lt = $(am__v_lt_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +am__v_lt_1 = +libportaudiocpp_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ + $(AM_CXXFLAGS) $(CXXFLAGS) $(libportaudiocpp_la_LDFLAGS) \ + $(LDFLAGS) -o $@ +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +depcomp = $(SHELL) $(top_srcdir)/../../depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CXXFLAGS) $(CXXFLAGS) +AM_V_CXX = $(am__v_CXX_@AM_V@) +am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@) +am__v_CXX_0 = @echo " CXX " $@; +am__v_CXX_1 = +CXXLD = $(CXX) +CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \ + $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CXXLD = $(am__v_CXXLD_@AM_V@) +am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@) +am__v_CXXLD_0 = @echo " CXXLD " $@; +am__v_CXXLD_1 = +SOURCES = $(libportaudiocpp_la_SOURCES) +DIST_SOURCES = $(libportaudiocpp_la_SOURCES) +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFAULT_INCLUDES = @DEFAULT_INCLUDES@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_VERSION_INFO = @LT_VERSION_INFO@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PORTAUDIO_ROOT = @PORTAUDIO_ROOT@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +SRCDIR = $(top_srcdir)/source/portaudiocpp +lib_LTLIBRARIES = libportaudiocpp.la +LDADD = libportaudiocpp.la +libportaudiocpp_la_LDFLAGS = -version-info $(LT_VERSION_INFO) -no-undefined +libportaudiocpp_la_LIBADD = $(top_builddir)/$(PORTAUDIO_ROOT)/lib/libportaudio.la +libportaudiocpp_la_SOURCES = \ + $(SRCDIR)/BlockingStream.cxx \ + $(SRCDIR)/CallbackInterface.cxx \ + $(SRCDIR)/CallbackStream.cxx \ + $(SRCDIR)/CFunCallbackStream.cxx \ + $(SRCDIR)/CppFunCallbackStream.cxx \ + $(SRCDIR)/Device.cxx \ + $(SRCDIR)/DirectionSpecificStreamParameters.cxx \ + $(SRCDIR)/Exception.cxx \ + $(SRCDIR)/HostApi.cxx \ + $(SRCDIR)/InterfaceCallbackStream.cxx \ + $(SRCDIR)/MemFunCallbackStream.cxx \ + $(SRCDIR)/Stream.cxx \ + $(SRCDIR)/StreamParameters.cxx \ + $(SRCDIR)/System.cxx \ + $(SRCDIR)/SystemDeviceIterator.cxx \ + $(SRCDIR)/SystemHostApiIterator.cxx + +all: all-am + +.SUFFIXES: +.SUFFIXES: .cxx .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu lib/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu lib/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +install-libLTLIBRARIES: $(lib_LTLIBRARIES) + @$(NORMAL_INSTALL) + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ + } + +uninstall-libLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ + done + +clean-libLTLIBRARIES: + -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) + @list='$(lib_LTLIBRARIES)'; \ + locs=`for p in $$list; do echo $$p; done | \ + sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ + sort -u`; \ + test -z "$$locs" || { \ + echo rm -f $${locs}; \ + rm -f $${locs}; \ + } + +libportaudiocpp.la: $(libportaudiocpp_la_OBJECTS) $(libportaudiocpp_la_DEPENDENCIES) $(EXTRA_libportaudiocpp_la_DEPENDENCIES) + $(AM_V_CXXLD)$(libportaudiocpp_la_LINK) -rpath $(libdir) $(libportaudiocpp_la_OBJECTS) $(libportaudiocpp_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BlockingStream.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CFunCallbackStream.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CallbackInterface.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CallbackStream.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CppFunCallbackStream.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Device.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DirectionSpecificStreamParameters.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Exception.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/HostApi.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/InterfaceCallbackStream.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/MemFunCallbackStream.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Stream.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/StreamParameters.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/System.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SystemDeviceIterator.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SystemHostApiIterator.Plo@am__quote@ + +.cxx.o: +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $< + +.cxx.obj: +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.cxx.lo: +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LTCXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $< + +BlockingStream.lo: $(SRCDIR)/BlockingStream.cxx +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT BlockingStream.lo -MD -MP -MF $(DEPDIR)/BlockingStream.Tpo -c -o BlockingStream.lo `test -f '$(SRCDIR)/BlockingStream.cxx' || echo '$(srcdir)/'`$(SRCDIR)/BlockingStream.cxx +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/BlockingStream.Tpo $(DEPDIR)/BlockingStream.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$(SRCDIR)/BlockingStream.cxx' object='BlockingStream.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o BlockingStream.lo `test -f '$(SRCDIR)/BlockingStream.cxx' || echo '$(srcdir)/'`$(SRCDIR)/BlockingStream.cxx + +CallbackInterface.lo: $(SRCDIR)/CallbackInterface.cxx +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT CallbackInterface.lo -MD -MP -MF $(DEPDIR)/CallbackInterface.Tpo -c -o CallbackInterface.lo `test -f '$(SRCDIR)/CallbackInterface.cxx' || echo '$(srcdir)/'`$(SRCDIR)/CallbackInterface.cxx +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/CallbackInterface.Tpo $(DEPDIR)/CallbackInterface.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$(SRCDIR)/CallbackInterface.cxx' object='CallbackInterface.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o CallbackInterface.lo `test -f '$(SRCDIR)/CallbackInterface.cxx' || echo '$(srcdir)/'`$(SRCDIR)/CallbackInterface.cxx + +CallbackStream.lo: $(SRCDIR)/CallbackStream.cxx +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT CallbackStream.lo -MD -MP -MF $(DEPDIR)/CallbackStream.Tpo -c -o CallbackStream.lo `test -f '$(SRCDIR)/CallbackStream.cxx' || echo '$(srcdir)/'`$(SRCDIR)/CallbackStream.cxx +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/CallbackStream.Tpo $(DEPDIR)/CallbackStream.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$(SRCDIR)/CallbackStream.cxx' object='CallbackStream.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o CallbackStream.lo `test -f '$(SRCDIR)/CallbackStream.cxx' || echo '$(srcdir)/'`$(SRCDIR)/CallbackStream.cxx + +CFunCallbackStream.lo: $(SRCDIR)/CFunCallbackStream.cxx +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT CFunCallbackStream.lo -MD -MP -MF $(DEPDIR)/CFunCallbackStream.Tpo -c -o CFunCallbackStream.lo `test -f '$(SRCDIR)/CFunCallbackStream.cxx' || echo '$(srcdir)/'`$(SRCDIR)/CFunCallbackStream.cxx +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/CFunCallbackStream.Tpo $(DEPDIR)/CFunCallbackStream.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$(SRCDIR)/CFunCallbackStream.cxx' object='CFunCallbackStream.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o CFunCallbackStream.lo `test -f '$(SRCDIR)/CFunCallbackStream.cxx' || echo '$(srcdir)/'`$(SRCDIR)/CFunCallbackStream.cxx + +CppFunCallbackStream.lo: $(SRCDIR)/CppFunCallbackStream.cxx +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT CppFunCallbackStream.lo -MD -MP -MF $(DEPDIR)/CppFunCallbackStream.Tpo -c -o CppFunCallbackStream.lo `test -f '$(SRCDIR)/CppFunCallbackStream.cxx' || echo '$(srcdir)/'`$(SRCDIR)/CppFunCallbackStream.cxx +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/CppFunCallbackStream.Tpo $(DEPDIR)/CppFunCallbackStream.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$(SRCDIR)/CppFunCallbackStream.cxx' object='CppFunCallbackStream.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o CppFunCallbackStream.lo `test -f '$(SRCDIR)/CppFunCallbackStream.cxx' || echo '$(srcdir)/'`$(SRCDIR)/CppFunCallbackStream.cxx + +Device.lo: $(SRCDIR)/Device.cxx +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT Device.lo -MD -MP -MF $(DEPDIR)/Device.Tpo -c -o Device.lo `test -f '$(SRCDIR)/Device.cxx' || echo '$(srcdir)/'`$(SRCDIR)/Device.cxx +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/Device.Tpo $(DEPDIR)/Device.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$(SRCDIR)/Device.cxx' object='Device.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o Device.lo `test -f '$(SRCDIR)/Device.cxx' || echo '$(srcdir)/'`$(SRCDIR)/Device.cxx + +DirectionSpecificStreamParameters.lo: $(SRCDIR)/DirectionSpecificStreamParameters.cxx +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT DirectionSpecificStreamParameters.lo -MD -MP -MF $(DEPDIR)/DirectionSpecificStreamParameters.Tpo -c -o DirectionSpecificStreamParameters.lo `test -f '$(SRCDIR)/DirectionSpecificStreamParameters.cxx' || echo '$(srcdir)/'`$(SRCDIR)/DirectionSpecificStreamParameters.cxx +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/DirectionSpecificStreamParameters.Tpo $(DEPDIR)/DirectionSpecificStreamParameters.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$(SRCDIR)/DirectionSpecificStreamParameters.cxx' object='DirectionSpecificStreamParameters.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o DirectionSpecificStreamParameters.lo `test -f '$(SRCDIR)/DirectionSpecificStreamParameters.cxx' || echo '$(srcdir)/'`$(SRCDIR)/DirectionSpecificStreamParameters.cxx + +Exception.lo: $(SRCDIR)/Exception.cxx +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT Exception.lo -MD -MP -MF $(DEPDIR)/Exception.Tpo -c -o Exception.lo `test -f '$(SRCDIR)/Exception.cxx' || echo '$(srcdir)/'`$(SRCDIR)/Exception.cxx +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/Exception.Tpo $(DEPDIR)/Exception.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$(SRCDIR)/Exception.cxx' object='Exception.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o Exception.lo `test -f '$(SRCDIR)/Exception.cxx' || echo '$(srcdir)/'`$(SRCDIR)/Exception.cxx + +HostApi.lo: $(SRCDIR)/HostApi.cxx +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT HostApi.lo -MD -MP -MF $(DEPDIR)/HostApi.Tpo -c -o HostApi.lo `test -f '$(SRCDIR)/HostApi.cxx' || echo '$(srcdir)/'`$(SRCDIR)/HostApi.cxx +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/HostApi.Tpo $(DEPDIR)/HostApi.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$(SRCDIR)/HostApi.cxx' object='HostApi.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o HostApi.lo `test -f '$(SRCDIR)/HostApi.cxx' || echo '$(srcdir)/'`$(SRCDIR)/HostApi.cxx + +InterfaceCallbackStream.lo: $(SRCDIR)/InterfaceCallbackStream.cxx +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT InterfaceCallbackStream.lo -MD -MP -MF $(DEPDIR)/InterfaceCallbackStream.Tpo -c -o InterfaceCallbackStream.lo `test -f '$(SRCDIR)/InterfaceCallbackStream.cxx' || echo '$(srcdir)/'`$(SRCDIR)/InterfaceCallbackStream.cxx +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/InterfaceCallbackStream.Tpo $(DEPDIR)/InterfaceCallbackStream.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$(SRCDIR)/InterfaceCallbackStream.cxx' object='InterfaceCallbackStream.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o InterfaceCallbackStream.lo `test -f '$(SRCDIR)/InterfaceCallbackStream.cxx' || echo '$(srcdir)/'`$(SRCDIR)/InterfaceCallbackStream.cxx + +MemFunCallbackStream.lo: $(SRCDIR)/MemFunCallbackStream.cxx +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT MemFunCallbackStream.lo -MD -MP -MF $(DEPDIR)/MemFunCallbackStream.Tpo -c -o MemFunCallbackStream.lo `test -f '$(SRCDIR)/MemFunCallbackStream.cxx' || echo '$(srcdir)/'`$(SRCDIR)/MemFunCallbackStream.cxx +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/MemFunCallbackStream.Tpo $(DEPDIR)/MemFunCallbackStream.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$(SRCDIR)/MemFunCallbackStream.cxx' object='MemFunCallbackStream.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o MemFunCallbackStream.lo `test -f '$(SRCDIR)/MemFunCallbackStream.cxx' || echo '$(srcdir)/'`$(SRCDIR)/MemFunCallbackStream.cxx + +Stream.lo: $(SRCDIR)/Stream.cxx +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT Stream.lo -MD -MP -MF $(DEPDIR)/Stream.Tpo -c -o Stream.lo `test -f '$(SRCDIR)/Stream.cxx' || echo '$(srcdir)/'`$(SRCDIR)/Stream.cxx +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/Stream.Tpo $(DEPDIR)/Stream.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$(SRCDIR)/Stream.cxx' object='Stream.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o Stream.lo `test -f '$(SRCDIR)/Stream.cxx' || echo '$(srcdir)/'`$(SRCDIR)/Stream.cxx + +StreamParameters.lo: $(SRCDIR)/StreamParameters.cxx +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT StreamParameters.lo -MD -MP -MF $(DEPDIR)/StreamParameters.Tpo -c -o StreamParameters.lo `test -f '$(SRCDIR)/StreamParameters.cxx' || echo '$(srcdir)/'`$(SRCDIR)/StreamParameters.cxx +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/StreamParameters.Tpo $(DEPDIR)/StreamParameters.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$(SRCDIR)/StreamParameters.cxx' object='StreamParameters.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o StreamParameters.lo `test -f '$(SRCDIR)/StreamParameters.cxx' || echo '$(srcdir)/'`$(SRCDIR)/StreamParameters.cxx + +System.lo: $(SRCDIR)/System.cxx +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT System.lo -MD -MP -MF $(DEPDIR)/System.Tpo -c -o System.lo `test -f '$(SRCDIR)/System.cxx' || echo '$(srcdir)/'`$(SRCDIR)/System.cxx +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/System.Tpo $(DEPDIR)/System.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$(SRCDIR)/System.cxx' object='System.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o System.lo `test -f '$(SRCDIR)/System.cxx' || echo '$(srcdir)/'`$(SRCDIR)/System.cxx + +SystemDeviceIterator.lo: $(SRCDIR)/SystemDeviceIterator.cxx +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT SystemDeviceIterator.lo -MD -MP -MF $(DEPDIR)/SystemDeviceIterator.Tpo -c -o SystemDeviceIterator.lo `test -f '$(SRCDIR)/SystemDeviceIterator.cxx' || echo '$(srcdir)/'`$(SRCDIR)/SystemDeviceIterator.cxx +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/SystemDeviceIterator.Tpo $(DEPDIR)/SystemDeviceIterator.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$(SRCDIR)/SystemDeviceIterator.cxx' object='SystemDeviceIterator.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o SystemDeviceIterator.lo `test -f '$(SRCDIR)/SystemDeviceIterator.cxx' || echo '$(srcdir)/'`$(SRCDIR)/SystemDeviceIterator.cxx + +SystemHostApiIterator.lo: $(SRCDIR)/SystemHostApiIterator.cxx +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT SystemHostApiIterator.lo -MD -MP -MF $(DEPDIR)/SystemHostApiIterator.Tpo -c -o SystemHostApiIterator.lo `test -f '$(SRCDIR)/SystemHostApiIterator.cxx' || echo '$(srcdir)/'`$(SRCDIR)/SystemHostApiIterator.cxx +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/SystemHostApiIterator.Tpo $(DEPDIR)/SystemHostApiIterator.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$(SRCDIR)/SystemHostApiIterator.cxx' object='SystemHostApiIterator.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o SystemHostApiIterator.lo `test -f '$(SRCDIR)/SystemHostApiIterator.cxx' || echo '$(srcdir)/'`$(SRCDIR)/SystemHostApiIterator.cxx + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-am +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-am + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscopelist: cscopelist-am + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) +installdirs: + for dir in "$(DESTDIR)$(libdir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: install-libLTLIBRARIES + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-libLTLIBRARIES + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ + clean-libLTLIBRARIES clean-libtool cscopelist-am ctags \ + ctags-am distclean distclean-compile distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-libLTLIBRARIES install-man install-pdf \ + install-pdf-am install-ps install-ps-am install-strip \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags tags-am uninstall uninstall-am uninstall-libLTLIBRARIES + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/extern/portaudio/bindings/cpp/portaudiocpp.pc.in b/extern/portaudio/bindings/cpp/portaudiocpp.pc.in new file mode 100644 index 0000000..8b126d1 --- /dev/null +++ b/extern/portaudio/bindings/cpp/portaudiocpp.pc.in @@ -0,0 +1,12 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: PortAudioCpp +Description: Portable audio I/O C++ bindings +Version: 12 +Requires: portaudio-2.0 + +Libs: -L${libdir} -lportaudiocpp +Cflags: -I${includedir} diff --git a/extern/portaudio/bindings/cpp/source/portaudiocpp/AsioDeviceAdapter.cxx b/extern/portaudio/bindings/cpp/source/portaudiocpp/AsioDeviceAdapter.cxx new file mode 100644 index 0000000..3efc100 --- /dev/null +++ b/extern/portaudio/bindings/cpp/source/portaudiocpp/AsioDeviceAdapter.cxx @@ -0,0 +1,83 @@ +#include "portaudiocpp/AsioDeviceAdapter.hxx" + +#include "portaudio.h" +#include "pa_asio.h" + +#include "portaudiocpp/Device.hxx" +#include "portaudiocpp/HostApi.hxx" +#include "portaudiocpp/Exception.hxx" + +namespace portaudio +{ + AsioDeviceAdapter::AsioDeviceAdapter(Device &device) + { + if (device.hostApi().typeId() != paASIO) + throw PaCppException(PaCppException::UNABLE_TO_ADAPT_DEVICE); + + device_ = &device; + + PaError err = PaAsio_GetAvailableLatencyValues(device_->index(), &minBufferSize_, &maxBufferSize_, + &preferredBufferSize_, &granularity_); + + if (err != paNoError) + throw PaException(err); + + } + + Device &AsioDeviceAdapter::device() + { + return *device_; + } + + long AsioDeviceAdapter::minBufferSize() const + { + return minBufferSize_; + } + + long AsioDeviceAdapter::maxBufferSize() const + { + return maxBufferSize_; + } + + long AsioDeviceAdapter::preferredBufferSize() const + { + return preferredBufferSize_; + } + + long AsioDeviceAdapter::granularity() const + { + return granularity_; + } + + void AsioDeviceAdapter::showControlPanel(void *systemSpecific) + { + PaError err = PaAsio_ShowControlPanel(device_->index(), systemSpecific); + + if (err != paNoError) + throw PaException(err); + } + + const char *AsioDeviceAdapter::inputChannelName(int channelIndex) const + { + const char *channelName; + PaError err = PaAsio_GetInputChannelName(device_->index(), channelIndex, &channelName); + + if (err != paNoError) + throw PaException(err); + + return channelName; + } + + const char *AsioDeviceAdapter::outputChannelName(int channelIndex) const + { + const char *channelName; + PaError err = PaAsio_GetOutputChannelName(device_->index(), channelIndex, &channelName); + + if (err != paNoError) + throw PaException(err); + + return channelName; + } +} + + diff --git a/extern/portaudio/bindings/cpp/source/portaudiocpp/BlockingStream.cxx b/extern/portaudio/bindings/cpp/source/portaudiocpp/BlockingStream.cxx new file mode 100644 index 0000000..b26b9e8 --- /dev/null +++ b/extern/portaudio/bindings/cpp/source/portaudiocpp/BlockingStream.cxx @@ -0,0 +1,100 @@ +#include "portaudiocpp/BlockingStream.hxx" + +#include "portaudio.h" + +#include "portaudiocpp/StreamParameters.hxx" +#include "portaudiocpp/Exception.hxx" + +namespace portaudio +{ + + // -------------------------------------------------------------------------------------- + + BlockingStream::BlockingStream() + { + } + + BlockingStream::BlockingStream(const StreamParameters ¶meters) + { + open(parameters); + } + + BlockingStream::~BlockingStream() + { + try + { + close(); + } + catch (...) + { + // ignore all errors + } + } + + // -------------------------------------------------------------------------------------- + + void BlockingStream::open(const StreamParameters ¶meters) + { + PaError err = Pa_OpenStream(&stream_, parameters.inputParameters().paStreamParameters(), parameters.outputParameters().paStreamParameters(), + parameters.sampleRate(), parameters.framesPerBuffer(), parameters.flags(), NULL, NULL); + + if (err != paNoError) + { + throw PaException(err); + } + } + + // -------------------------------------------------------------------------------------- + + void BlockingStream::read(void *buffer, unsigned long numFrames) + { + PaError err = Pa_ReadStream(stream_, buffer, numFrames); + + if (err != paNoError) + { + throw PaException(err); + } + } + + void BlockingStream::write(const void *buffer, unsigned long numFrames) + { + PaError err = Pa_WriteStream(stream_, buffer, numFrames); + + if (err != paNoError) + { + throw PaException(err); + } + } + + // -------------------------------------------------------------------------------------- + + signed long BlockingStream::availableReadSize() const + { + signed long avail = Pa_GetStreamReadAvailable(stream_); + + if (avail < 0) + { + throw PaException(avail); + } + + return avail; + } + + signed long BlockingStream::availableWriteSize() const + { + signed long avail = Pa_GetStreamWriteAvailable(stream_); + + if (avail < 0) + { + throw PaException(avail); + } + + return avail; + } + + // -------------------------------------------------------------------------------------- + +} // portaudio + + + diff --git a/extern/portaudio/bindings/cpp/source/portaudiocpp/CFunCallbackStream.cxx b/extern/portaudio/bindings/cpp/source/portaudiocpp/CFunCallbackStream.cxx new file mode 100644 index 0000000..9cceda9 --- /dev/null +++ b/extern/portaudio/bindings/cpp/source/portaudiocpp/CFunCallbackStream.cxx @@ -0,0 +1,41 @@ +#include "portaudiocpp/CFunCallbackStream.hxx" + +#include "portaudiocpp/StreamParameters.hxx" +#include "portaudiocpp/Exception.hxx" + +namespace portaudio +{ + CFunCallbackStream::CFunCallbackStream() + { + } + + CFunCallbackStream::CFunCallbackStream(const StreamParameters ¶meters, PaStreamCallback *funPtr, void *userData) + { + open(parameters, funPtr, userData); + } + + CFunCallbackStream::~CFunCallbackStream() + { + try + { + close(); + } + catch (...) + { + // ignore all errors + } + } + + // ---------------------------------------------------------------------------------== + + void CFunCallbackStream::open(const StreamParameters ¶meters, PaStreamCallback *funPtr, void *userData) + { + PaError err = Pa_OpenStream(&stream_, parameters.inputParameters().paStreamParameters(), parameters.outputParameters().paStreamParameters(), + parameters.sampleRate(), parameters.framesPerBuffer(), parameters.flags(), funPtr, userData); + + if (err != paNoError) + { + throw PaException(err); + } + } +} diff --git a/extern/portaudio/bindings/cpp/source/portaudiocpp/CallbackInterface.cxx b/extern/portaudio/bindings/cpp/source/portaudiocpp/CallbackInterface.cxx new file mode 100644 index 0000000..0137261 --- /dev/null +++ b/extern/portaudio/bindings/cpp/source/portaudiocpp/CallbackInterface.cxx @@ -0,0 +1,25 @@ +#include "portaudiocpp/CallbackInterface.hxx" + +namespace portaudio +{ + + namespace impl + { + + ////// + /// Adapts any CallbackInterface object to a C-callable function (ie this function). A + /// pointer to the object should be passed as ``userData'' when setting up the callback. + ////// + int callbackInterfaceToPaCallbackAdapter(const void *inputBuffer, void *outputBuffer, unsigned long numFrames, + const PaStreamCallbackTimeInfo *timeInfo, PaStreamCallbackFlags statusFlags, void *userData) + { + CallbackInterface *cb = static_cast(userData); + return cb->paCallbackFun(inputBuffer, outputBuffer, numFrames, timeInfo, statusFlags); + } + + + } // namespace impl + +} // namespace portaudio + + diff --git a/extern/portaudio/bindings/cpp/source/portaudiocpp/CallbackStream.cxx b/extern/portaudio/bindings/cpp/source/portaudiocpp/CallbackStream.cxx new file mode 100644 index 0000000..b6c8e1d --- /dev/null +++ b/extern/portaudio/bindings/cpp/source/portaudiocpp/CallbackStream.cxx @@ -0,0 +1,20 @@ +#include "portaudiocpp/CallbackStream.hxx" + +namespace portaudio +{ + CallbackStream::CallbackStream() + { + } + + CallbackStream::~CallbackStream() + { + } + + // ----------------------------------------------------------------------------------- + + double CallbackStream::cpuLoad() const + { + return Pa_GetStreamCpuLoad(stream_); + } + +} // namespace portaudio diff --git a/extern/portaudio/bindings/cpp/source/portaudiocpp/CppFunCallbackStream.cxx b/extern/portaudio/bindings/cpp/source/portaudiocpp/CppFunCallbackStream.cxx new file mode 100644 index 0000000..fe0b4ab --- /dev/null +++ b/extern/portaudio/bindings/cpp/source/portaudiocpp/CppFunCallbackStream.cxx @@ -0,0 +1,81 @@ +#include "portaudiocpp/CppFunCallbackStream.hxx" + +#include "portaudiocpp/StreamParameters.hxx" +#include "portaudiocpp/Exception.hxx" + +namespace portaudio +{ + namespace impl + { + ////// + /// Adapts any a C++ callback to a C-callable function (ie this function). A + /// pointer to a struct with the C++ function pointer and the actual user data should be + /// passed as the ``userData'' parameter when setting up the callback. + ////// + int cppCallbackToPaCallbackAdapter(const void *inputBuffer, void *outputBuffer, unsigned long numFrames, + const PaStreamCallbackTimeInfo *timeInfo, PaStreamCallbackFlags statusFlags, void *userData) + { + FunCallbackStream::CppToCCallbackData *data = static_cast(userData); + return data->funPtr(inputBuffer, outputBuffer, numFrames, timeInfo, statusFlags, data->userData); + } + } + + // ----------------------------------------------------------------------------------- + + FunCallbackStream::CppToCCallbackData::CppToCCallbackData() + { + } + + FunCallbackStream::CppToCCallbackData::CppToCCallbackData(CallbackFunPtr funPtr, void *userData) : funPtr(funPtr), userData(userData) + { + } + + void FunCallbackStream::CppToCCallbackData::init(CallbackFunPtr funPtr, void *userData) + { + this->funPtr = funPtr; + this->userData = userData; + } + + // ----------------------------------------------------------------------------------- + + FunCallbackStream::FunCallbackStream() + { + } + + FunCallbackStream::FunCallbackStream(const StreamParameters ¶meters, CallbackFunPtr funPtr, void *userData) : adapterData_(funPtr, userData) + { + open(parameters); + } + + FunCallbackStream::~FunCallbackStream() + { + try + { + close(); + } + catch (...) + { + // ignore all errors + } + } + + void FunCallbackStream::open(const StreamParameters ¶meters, CallbackFunPtr funPtr, void *userData) + { + adapterData_.init(funPtr, userData); + open(parameters); + } + + void FunCallbackStream::open(const StreamParameters ¶meters) + { + PaError err = Pa_OpenStream(&stream_, parameters.inputParameters().paStreamParameters(), parameters.outputParameters().paStreamParameters(), + parameters.sampleRate(), parameters.framesPerBuffer(), parameters.flags(), &impl::cppCallbackToPaCallbackAdapter, + static_cast(&adapterData_)); + + if (err != paNoError) + { + throw PaException(err); + } + } + + // ----------------------------------------------------------------------------------- +} diff --git a/extern/portaudio/bindings/cpp/source/portaudiocpp/Device.cxx b/extern/portaudio/bindings/cpp/source/portaudiocpp/Device.cxx new file mode 100644 index 0000000..7b21b03 --- /dev/null +++ b/extern/portaudio/bindings/cpp/source/portaudiocpp/Device.cxx @@ -0,0 +1,168 @@ +#include "portaudiocpp/Device.hxx" + +#include + +#include "portaudiocpp/HostApi.hxx" +#include "portaudiocpp/System.hxx" +#include "portaudiocpp/Exception.hxx" + +namespace portaudio +{ + + // ------------------------------------------------------------------------------- + + Device::Device(PaDeviceIndex index) : index_(index) + { + if (index == paNoDevice) + info_ = NULL; + else + info_ = Pa_GetDeviceInfo(index); + } + + Device::~Device() + { + } + + PaDeviceIndex Device::index() const + { + return index_; + } + + const char *Device::name() const + { + if (info_ == NULL) + return ""; + + return info_->name; + } + + int Device::maxInputChannels() const + { + if (info_ == NULL) + return 0; + + return info_->maxInputChannels; + } + + int Device::maxOutputChannels() const + { + if (info_ == NULL) + return 0; + + return info_->maxOutputChannels; + } + + PaTime Device::defaultLowInputLatency() const + { + if (info_ == NULL) + return static_cast(0.0); + + return info_->defaultLowInputLatency; + } + + PaTime Device::defaultHighInputLatency() const + { + if (info_ == NULL) + return static_cast(0.0); + + return info_->defaultHighInputLatency; + } + + PaTime Device::defaultLowOutputLatency() const + { + if (info_ == NULL) + return static_cast(0.0); + + return info_->defaultLowOutputLatency; + } + + PaTime Device::defaultHighOutputLatency() const + { + if (info_ == NULL) + return static_cast(0.0); + + return info_->defaultHighOutputLatency; + } + + double Device::defaultSampleRate() const + { + if (info_ == NULL) + return 0.0; + + return info_->defaultSampleRate; + } + + // ------------------------------------------------------------------------------- + + bool Device::isInputOnlyDevice() const + { + return (maxOutputChannels() == 0); + } + + bool Device::isOutputOnlyDevice() const + { + return (maxInputChannels() == 0); + } + + bool Device::isFullDuplexDevice() const + { + return (maxInputChannels() > 0 && maxOutputChannels() > 0); + } + + bool Device::isSystemDefaultInputDevice() const + { + return (System::instance().defaultInputDevice() == *this); + } + + bool Device::isSystemDefaultOutputDevice() const + { + return (System::instance().defaultOutputDevice() == *this); + } + + bool Device::isHostApiDefaultInputDevice() const + { + return (hostApi().defaultInputDevice() == *this); + } + + bool Device::isHostApiDefaultOutputDevice() const + { + return (hostApi().defaultOutputDevice() == *this); + } + + // ------------------------------------------------------------------------------- + + bool Device::operator==(const Device &rhs) const + { + return (index_ == rhs.index_); + } + + bool Device::operator!=(const Device &rhs) const + { + return !(*this == rhs); + } + + // ------------------------------------------------------------------------------- + + HostApi &Device::hostApi() + { + // NOTE: will cause an exception when called for the null device + if (info_ == NULL) + throw PaException(paInternalError); + + return System::instance().hostApiByIndex(info_->hostApi); + } + + const HostApi &Device::hostApi() const + { + // NOTE; will cause an exception when called for the null device + if (info_ == NULL) + throw PaException(paInternalError); + + return System::instance().hostApiByIndex(info_->hostApi); + } + + // ------------------------------------------------------------------------------- + +} // namespace portaudio + + diff --git a/extern/portaudio/bindings/cpp/source/portaudiocpp/DirectionSpecificStreamParameters.cxx b/extern/portaudio/bindings/cpp/source/portaudiocpp/DirectionSpecificStreamParameters.cxx new file mode 100644 index 0000000..68453d0 --- /dev/null +++ b/extern/portaudio/bindings/cpp/source/portaudiocpp/DirectionSpecificStreamParameters.cxx @@ -0,0 +1,163 @@ +#include "portaudiocpp/DirectionSpecificStreamParameters.hxx" + +#include "portaudiocpp/Device.hxx" + +namespace portaudio +{ + + // ----------------------------------------------------------------------------------- + + ////// + /// Returns a `nil' DirectionSpecificStreamParameters object. This can be used to + /// specify that one direction of a Stream is not required (i.e. when creating + /// a half-duplex Stream). All fields of the null DirectionSpecificStreamParameters + /// object are invalid except for the device and the number of channel, which are set + /// to paNoDevice and 0 respectively. + ////// + DirectionSpecificStreamParameters DirectionSpecificStreamParameters::null() + { + DirectionSpecificStreamParameters tmp; + tmp.paStreamParameters_.device = paNoDevice; + tmp.paStreamParameters_.channelCount = 0; + return tmp; + } + + // ----------------------------------------------------------------------------------- + + ////// + /// Default constructor -- all parameters will be uninitialized. + ////// + DirectionSpecificStreamParameters::DirectionSpecificStreamParameters() + { + } + + ////// + /// Constructor which sets all required fields. + ////// + DirectionSpecificStreamParameters::DirectionSpecificStreamParameters(const Device &device, int numChannels, + SampleDataFormat format, bool interleaved, PaTime suggestedLatency, void *hostApiSpecificStreamInfo) + { + setDevice(device); + setNumChannels(numChannels); + setSampleFormat(format, interleaved); + setSuggestedLatency(suggestedLatency); + setHostApiSpecificStreamInfo(hostApiSpecificStreamInfo); + } + + // ----------------------------------------------------------------------------------- + + void DirectionSpecificStreamParameters::setDevice(const Device &device) + { + paStreamParameters_.device = device.index(); + } + + void DirectionSpecificStreamParameters::setNumChannels(int numChannels) + { + paStreamParameters_.channelCount = numChannels; + } + + void DirectionSpecificStreamParameters::setSampleFormat(SampleDataFormat format, bool interleaved) + { + paStreamParameters_.sampleFormat = static_cast(format); + + if (!interleaved) + paStreamParameters_.sampleFormat |= paNonInterleaved; + } + + void DirectionSpecificStreamParameters::setHostApiSpecificSampleFormat(PaSampleFormat format, bool interleaved) + { + paStreamParameters_.sampleFormat = format; + + paStreamParameters_.sampleFormat |= paCustomFormat; + + if (!interleaved) + paStreamParameters_.sampleFormat |= paNonInterleaved; + } + + void DirectionSpecificStreamParameters::setSuggestedLatency(PaTime latency) + { + paStreamParameters_.suggestedLatency = latency; + } + + void DirectionSpecificStreamParameters::setHostApiSpecificStreamInfo(void *streamInfo) + { + paStreamParameters_.hostApiSpecificStreamInfo = streamInfo; + } + + // ----------------------------------------------------------------------------------- + + PaStreamParameters *DirectionSpecificStreamParameters::paStreamParameters() + { + if (paStreamParameters_.channelCount > 0 && paStreamParameters_.device != paNoDevice) + return &paStreamParameters_; + else + return NULL; + } + + const PaStreamParameters *DirectionSpecificStreamParameters::paStreamParameters() const + { + if (paStreamParameters_.channelCount > 0 && paStreamParameters_.device != paNoDevice) + return &paStreamParameters_; + else + return NULL; + } + + Device &DirectionSpecificStreamParameters::device() const + { + return System::instance().deviceByIndex(paStreamParameters_.device); + } + + int DirectionSpecificStreamParameters::numChannels() const + { + return paStreamParameters_.channelCount; + } + + ////// + /// Returns the (non host api-specific) sample format, without including + /// the paNonInterleaved flag. If the sample format is host api-spefific, + /// INVALID_FORMAT (0) will be returned. + ////// + SampleDataFormat DirectionSpecificStreamParameters::sampleFormat() const + { + if (isSampleFormatHostApiSpecific()) + return INVALID_FORMAT; + else + return static_cast(paStreamParameters_.sampleFormat & ~paNonInterleaved); + } + + bool DirectionSpecificStreamParameters::isSampleFormatInterleaved() const + { + return ((paStreamParameters_.sampleFormat & paNonInterleaved) == 0); + } + + bool DirectionSpecificStreamParameters::isSampleFormatHostApiSpecific() const + { + return ((paStreamParameters_.sampleFormat & paCustomFormat) == 0); + } + + ////// + /// Returns the host api-specific sample format, without including any + /// paCustomFormat or paNonInterleaved flags. Will return 0 if the sample format is + /// not host api-specific. + ////// + PaSampleFormat DirectionSpecificStreamParameters::hostApiSpecificSampleFormat() const + { + if (isSampleFormatHostApiSpecific()) + return paStreamParameters_.sampleFormat & ~paCustomFormat & ~paNonInterleaved; + else + return 0; + } + + PaTime DirectionSpecificStreamParameters::suggestedLatency() const + { + return paStreamParameters_.suggestedLatency; + } + + void *DirectionSpecificStreamParameters::hostApiSpecificStreamInfo() const + { + return paStreamParameters_.hostApiSpecificStreamInfo; + } + + // ----------------------------------------------------------------------------------- + +} // namespace portaudio diff --git a/extern/portaudio/bindings/cpp/source/portaudiocpp/Exception.cxx b/extern/portaudio/bindings/cpp/source/portaudiocpp/Exception.cxx new file mode 100644 index 0000000..98945c8 --- /dev/null +++ b/extern/portaudio/bindings/cpp/source/portaudiocpp/Exception.cxx @@ -0,0 +1,123 @@ +#include "portaudiocpp/Exception.hxx" + +namespace portaudio +{ + // ----------------------------------------------------------------------------------- + // PaException: + // ----------------------------------------------------------------------------------- + + ////// + /// Wraps a PortAudio error into a PortAudioCpp PaException. + ////// + PaException::PaException(PaError error) : error_(error) + { + } + + // ----------------------------------------------------------------------------------- + + ////// + /// Alias for paErrorText(), to have std::exception compliance. + ////// + const char *PaException::what() const throw() + { + return paErrorText(); + } + + // ----------------------------------------------------------------------------------- + + ////// + /// Returns the PortAudio error code (PaError). + ////// + PaError PaException::paError() const + { + return error_; + } + + ////// + /// Returns the error as a (zero-terminated) text string. + ////// + const char *PaException::paErrorText() const + { + return Pa_GetErrorText(error_); + } + + ////// + /// Returns true is the error is a HostApi error. + ////// + bool PaException::isHostApiError() const + { + return (error_ == paUnanticipatedHostError); + } + + ////// + /// Returns the last HostApi error (which is the current one if + /// isHostApiError() returns true) as an error code. + ////// + long PaException::lastHostApiError() const + { + return Pa_GetLastHostErrorInfo()->errorCode; + } + + ////// + /// Returns the last HostApi error (which is the current one if + /// isHostApiError() returns true) as a (zero-terminated) text + /// string, if it's available. + ////// + const char *PaException::lastHostApiErrorText() const + { + return Pa_GetLastHostErrorInfo()->errorText; + } + + // ----------------------------------------------------------------------------------- + + bool PaException::operator==(const PaException &rhs) const + { + return (error_ == rhs.error_); + } + + bool PaException::operator!=(const PaException &rhs) const + { + return !(*this == rhs); + } + + // ----------------------------------------------------------------------------------- + // PaCppException: + // ----------------------------------------------------------------------------------- + + PaCppException::PaCppException(ExceptionSpecifier specifier) : specifier_(specifier) + { + } + + const char *PaCppException::what() const throw() + { + switch (specifier_) + { + case UNABLE_TO_ADAPT_DEVICE: + { + return "Unable to adapt the given device to the specified host api specific device extension"; + } + } + + return "Unknown exception"; + } + + PaCppException::ExceptionSpecifier PaCppException::specifier() const + { + return specifier_; + } + + bool PaCppException::operator==(const PaCppException &rhs) const + { + return (specifier_ == rhs.specifier_); + } + + bool PaCppException::operator!=(const PaCppException &rhs) const + { + return !(*this == rhs); + } + + // ----------------------------------------------------------------------------------- + +} // namespace portaudio + + diff --git a/extern/portaudio/bindings/cpp/source/portaudiocpp/HostApi.cxx b/extern/portaudio/bindings/cpp/source/portaudiocpp/HostApi.cxx new file mode 100644 index 0000000..6a09670 --- /dev/null +++ b/extern/portaudio/bindings/cpp/source/portaudiocpp/HostApi.cxx @@ -0,0 +1,121 @@ +#include "portaudiocpp/HostApi.hxx" + +#include "portaudiocpp/System.hxx" +#include "portaudiocpp/Device.hxx" +#include "portaudiocpp/SystemDeviceIterator.hxx" +#include "portaudiocpp/Exception.hxx" + +namespace portaudio +{ + + // ----------------------------------------------------------------------------------- + + HostApi::HostApi(PaHostApiIndex index) : devices_(NULL) + { + try + { + info_ = Pa_GetHostApiInfo(index); + + // Create and populate devices array: + int numDevices = deviceCount(); + + devices_ = new Device*[numDevices]; + + for (int i = 0; i < numDevices; ++i) + { + PaDeviceIndex deviceIndex = Pa_HostApiDeviceIndexToDeviceIndex(index, i); + + if (deviceIndex < 0) + { + throw PaException(deviceIndex); + } + + devices_[i] = &System::instance().deviceByIndex(deviceIndex); + } + } + catch (const std::exception &e) + { + // Delete any (partially) constructed objects (deconstructor isn't called): + delete[] devices_; // devices_ is either NULL or valid + + // Re-throw exception: + throw e; + } + } + + HostApi::~HostApi() + { + // Destroy devices array: + delete[] devices_; + } + + // ----------------------------------------------------------------------------------- + + PaHostApiTypeId HostApi::typeId() const + { + return info_->type; + } + + PaHostApiIndex HostApi::index() const + { + PaHostApiIndex index = Pa_HostApiTypeIdToHostApiIndex(typeId()); + + if (index < 0) + throw PaException(index); + + return index; + } + + const char *HostApi::name() const + { + return info_->name; + } + + int HostApi::deviceCount() const + { + return info_->deviceCount; + } + + // ----------------------------------------------------------------------------------- + + HostApi::DeviceIterator HostApi::devicesBegin() + { + DeviceIterator tmp; + tmp.ptr_ = &devices_[0]; // begin (first element) + return tmp; + } + + HostApi::DeviceIterator HostApi::devicesEnd() + { + DeviceIterator tmp; + tmp.ptr_ = &devices_[deviceCount()]; // end (one past last element) + return tmp; + } + + // ----------------------------------------------------------------------------------- + + Device &HostApi::defaultInputDevice() const + { + return System::instance().deviceByIndex(info_->defaultInputDevice); + } + + Device &HostApi::defaultOutputDevice() const + { + return System::instance().deviceByIndex(info_->defaultOutputDevice); + } + + // ----------------------------------------------------------------------------------- + + bool HostApi::operator==(const HostApi &rhs) const + { + return (typeId() == rhs.typeId()); + } + + bool HostApi::operator!=(const HostApi &rhs) const + { + return !(*this == rhs); + } + + // ----------------------------------------------------------------------------------- + +} // namespace portaudio diff --git a/extern/portaudio/bindings/cpp/source/portaudiocpp/InterfaceCallbackStream.cxx b/extern/portaudio/bindings/cpp/source/portaudiocpp/InterfaceCallbackStream.cxx new file mode 100644 index 0000000..5433fa3 --- /dev/null +++ b/extern/portaudio/bindings/cpp/source/portaudiocpp/InterfaceCallbackStream.cxx @@ -0,0 +1,45 @@ +#include "portaudiocpp/InterfaceCallbackStream.hxx" + +#include "portaudiocpp/StreamParameters.hxx" +#include "portaudiocpp/Exception.hxx" +#include "portaudiocpp/CallbackInterface.hxx" + +namespace portaudio +{ + + // ---------------------------------------------------------------------------------== + + InterfaceCallbackStream::InterfaceCallbackStream() + { + } + + InterfaceCallbackStream::InterfaceCallbackStream(const StreamParameters ¶meters, CallbackInterface &instance) + { + open(parameters, instance); + } + + InterfaceCallbackStream::~InterfaceCallbackStream() + { + try + { + close(); + } + catch (...) + { + // ignore all errors + } + } + + // ---------------------------------------------------------------------------------== + + void InterfaceCallbackStream::open(const StreamParameters ¶meters, CallbackInterface &instance) + { + PaError err = Pa_OpenStream(&stream_, parameters.inputParameters().paStreamParameters(), parameters.outputParameters().paStreamParameters(), + parameters.sampleRate(), parameters.framesPerBuffer(), parameters.flags(), &impl::callbackInterfaceToPaCallbackAdapter, static_cast(&instance)); + + if (err != paNoError) + { + throw PaException(err); + } + } +} diff --git a/extern/portaudio/bindings/cpp/source/portaudiocpp/MemFunCallbackStream.cxx b/extern/portaudio/bindings/cpp/source/portaudiocpp/MemFunCallbackStream.cxx new file mode 100644 index 0000000..5141de2 --- /dev/null +++ b/extern/portaudio/bindings/cpp/source/portaudiocpp/MemFunCallbackStream.cxx @@ -0,0 +1,4 @@ +#include "portaudiocpp/MemFunCallbackStream.hxx" + +// (... template class ...) + diff --git a/extern/portaudio/bindings/cpp/source/portaudiocpp/Stream.cxx b/extern/portaudio/bindings/cpp/source/portaudiocpp/Stream.cxx new file mode 100644 index 0000000..ba16e03 --- /dev/null +++ b/extern/portaudio/bindings/cpp/source/portaudiocpp/Stream.cxx @@ -0,0 +1,195 @@ +#include "portaudiocpp/Stream.hxx" + +#include + +#include "portaudiocpp/Exception.hxx" +#include "portaudiocpp/System.hxx" + +namespace portaudio +{ + + // ----------------------------------------------------------------------------------- + + Stream::Stream() : stream_(NULL) + { + } + + Stream::~Stream() + { + // (can't call close here, + // the derived class should atleast call + // close() in it's deconstructor) + } + + // ----------------------------------------------------------------------------------- + + ////// + /// Closes the Stream if it's open, else does nothing. + ////// + void Stream::close() + { + if (isOpen() && System::exists()) + { + PaError err = Pa_CloseStream(stream_); + stream_ = NULL; + + if (err != paNoError) + throw PaException(err); + } + } + + ////// + /// Returns true if the Stream is open. + ////// + bool Stream::isOpen() const + { + return (stream_ != NULL); + } + + // ----------------------------------------------------------------------------------- + + void Stream::setStreamFinishedCallback(PaStreamFinishedCallback *callback) + { + PaError err = Pa_SetStreamFinishedCallback(stream_, callback); + + if (err != paNoError) + throw PaException(err); + } + + // ----------------------------------------------------------------------------------- + + void Stream::start() + { + PaError err = Pa_StartStream(stream_); + + if (err != paNoError) + throw PaException(err); + } + + void Stream::stop() + { + PaError err = Pa_StopStream(stream_); + + if (err != paNoError) + throw PaException(err); + } + + void Stream::abort() + { + PaError err = Pa_AbortStream(stream_); + + if (err != paNoError) + throw PaException(err); + } + + bool Stream::isStopped() const + { + PaError ret = Pa_IsStreamStopped(stream_); + + if (ret < 0) + throw PaException(ret); + + return (ret == 1); + } + + bool Stream::isActive() const + { + PaError ret = Pa_IsStreamActive(stream_); + + if (ret < 0) + throw PaException(ret); + + return (ret == 1); + } + + // ----------------------------------------------------------------------------------- + + ////// + /// Returns the best known input latency for the Stream. This value may differ from the + /// suggested input latency set in the StreamParameters. Includes all sources of + /// latency known to PortAudio such as internal buffering, and Host API reported latency. + /// Doesn't include any estimates of unknown latency. + ////// + PaTime Stream::inputLatency() const + { + const PaStreamInfo *info = Pa_GetStreamInfo(stream_); + if (info == NULL) + { + throw PaException(paInternalError); + return PaTime(0.0); + } + + return info->inputLatency; + } + + ////// + /// Returns the best known output latency for the Stream. This value may differ from the + /// suggested output latency set in the StreamParameters. Includes all sources of + /// latency known to PortAudio such as internal buffering, and Host API reported latency. + /// Doesn't include any estimates of unknown latency. + ////// + PaTime Stream::outputLatency() const + { + const PaStreamInfo *info = Pa_GetStreamInfo(stream_); + if (info == NULL) + { + throw PaException(paInternalError); + return PaTime(0.0); + } + + return info->outputLatency; + } + + ////// + /// Returns the sample rate of the Stream. Usually this will be the + /// best known estimate of the used sample rate. For instance when opening a + /// Stream setting 44100.0 Hz in the StreamParameters, the actual sample + /// rate might be something like 44103.2 Hz (due to imperfections in the + /// sound card hardware). + ////// + double Stream::sampleRate() const + { + const PaStreamInfo *info = Pa_GetStreamInfo(stream_); + if (info == NULL) + { + throw PaException(paInternalError); + return 0.0; + } + + return info->sampleRate; + } + + // ----------------------------------------------------------------------------------- + + PaTime Stream::time() const + { + return Pa_GetStreamTime(stream_); + } + + // ----------------------------------------------------------------------------------- + + ////// + /// Accessor (const) for PortAudio PaStream pointer, useful for interfacing with + /// PortAudio add-ons such as PortMixer for instance. Normally accessing this + /// pointer should not be needed as PortAudioCpp aims to provide all of PortAudio's + /// functionality. + ////// + const PaStream *Stream::paStream() const + { + return stream_; + } + + ////// + /// Accessor (non-const) for PortAudio PaStream pointer, useful for interfacing with + /// PortAudio add-ons such as PortMixer for instance. Normally accessing this + /// pointer should not be needed as PortAudioCpp aims to provide all of PortAudio's + /// functionality. + ////// + PaStream *Stream::paStream() + { + return stream_; + } + + // ----------------------------------------------------------------------------------- + +} // namespace portaudio diff --git a/extern/portaudio/bindings/cpp/source/portaudiocpp/StreamParameters.cxx b/extern/portaudio/bindings/cpp/source/portaudiocpp/StreamParameters.cxx new file mode 100644 index 0000000..5b9e897 --- /dev/null +++ b/extern/portaudio/bindings/cpp/source/portaudiocpp/StreamParameters.cxx @@ -0,0 +1,165 @@ +#include "portaudiocpp/StreamParameters.hxx" + +#include + +#include "portaudiocpp/Device.hxx" + +namespace portaudio +{ + // ----------------------------------------------------------------------------------- + + ////// + /// Default constructor; does nothing. + ////// + StreamParameters::StreamParameters() + { + } + + ////// + /// Sets up the all parameters needed to open either a half-duplex or full-duplex Stream. + /// + /// @param inputParameters The parameters for the input direction of the to-be opened + /// Stream or DirectionSpecificStreamParameters::null() for an output-only Stream. + /// @param outputParameters The parameters for the output direction of the to-be opened + /// Stream or DirectionSpecificStreamParameters::null() for an input-only Stream. + /// @param sampleRate The to-be opened Stream's sample rate in Hz. + /// @param framesPerBuffer The number of frames per buffer for a CallbackStream, or + /// the preferred buffer granularity for a BlockingStream. + /// @param flags The flags for the to-be opened Stream; default paNoFlag. + ////// + StreamParameters::StreamParameters(const DirectionSpecificStreamParameters &inputParameters, + const DirectionSpecificStreamParameters &outputParameters, double sampleRate, unsigned long framesPerBuffer, + PaStreamFlags flags) : inputParameters_(inputParameters), outputParameters_(outputParameters), + sampleRate_(sampleRate), framesPerBuffer_(framesPerBuffer), flags_(flags) + { + } + + // ----------------------------------------------------------------------------------- + + ////// + /// Sets the requested sample rate. If this sample rate isn't supported by the hardware, the + /// Stream will fail to open. The real-life sample rate used might differ slightly due to + /// imperfections in the sound card hardware; use Stream::sampleRate() to retreive the + /// best known estimate for this value. + ////// + void StreamParameters::setSampleRate(double sampleRate) + { + sampleRate_ = sampleRate; + } + + ////// + /// Either the number of frames per buffer for a CallbackStream, or + /// the preferred buffer granularity for a BlockingStream. See PortAudio + /// documentation. + ////// + void StreamParameters::setFramesPerBuffer(unsigned long framesPerBuffer) + { + framesPerBuffer_ = framesPerBuffer; + } + + ////// + /// Sets the specified flag or does nothing when the flag is already set. Doesn't + /// `unset' any previously existing flags (use clearFlags() for that). + ////// + void StreamParameters::setFlag(PaStreamFlags flag) + { + flags_ |= flag; + } + + ////// + /// Unsets the specified flag or does nothing if the flag isn't set. Doesn't affect + /// any other flags. + ////// + void StreamParameters::unsetFlag(PaStreamFlags flag) + { + flags_ &= ~flag; + } + + ////// + /// Clears or `unsets' all set flags. + ////// + void StreamParameters::clearFlags() + { + flags_ = paNoFlag; + } + + // ----------------------------------------------------------------------------------- + + void StreamParameters::setInputParameters(const DirectionSpecificStreamParameters ¶meters) + { + inputParameters_ = parameters; + } + + void StreamParameters::setOutputParameters(const DirectionSpecificStreamParameters ¶meters) + { + outputParameters_ = parameters; + } + + // ----------------------------------------------------------------------------------- + + bool StreamParameters::isSupported() const + { + return (Pa_IsFormatSupported(inputParameters_.paStreamParameters(), + outputParameters_.paStreamParameters(), sampleRate_) == paFormatIsSupported); + } + + // ----------------------------------------------------------------------------------- + + double StreamParameters::sampleRate() const + { + return sampleRate_; + } + + unsigned long StreamParameters::framesPerBuffer() const + { + return framesPerBuffer_; + } + + ////// + /// Returns all currently set flags as a binary combined + /// integer value (PaStreamFlags). Use isFlagSet() to + /// avoid dealing with the bitmasks. + ////// + PaStreamFlags StreamParameters::flags() const + { + return flags_; + } + + ////// + /// Returns true if the specified flag is currently set + /// or false if it isn't. + ////// + bool StreamParameters::isFlagSet(PaStreamFlags flag) const + { + return ((flags_ & flag) != 0); + } + + // ----------------------------------------------------------------------------------- + + DirectionSpecificStreamParameters &StreamParameters::inputParameters() + { + return inputParameters_; + } + + const DirectionSpecificStreamParameters &StreamParameters::inputParameters() const + { + return inputParameters_; + } + + DirectionSpecificStreamParameters &StreamParameters::outputParameters() + { + return outputParameters_; + } + + const DirectionSpecificStreamParameters &StreamParameters::outputParameters() const + { + return outputParameters_; + } + + // ----------------------------------------------------------------------------------- +} // namespace portaudio + + + + + diff --git a/extern/portaudio/bindings/cpp/source/portaudiocpp/System.cxx b/extern/portaudio/bindings/cpp/source/portaudiocpp/System.cxx new file mode 100644 index 0000000..acb419d --- /dev/null +++ b/extern/portaudio/bindings/cpp/source/portaudiocpp/System.cxx @@ -0,0 +1,308 @@ +#include "portaudiocpp/System.hxx" + +#include +#include + +#include "portaudiocpp/HostApi.hxx" +#include "portaudiocpp/Device.hxx" +#include "portaudiocpp/Stream.hxx" +#include "portaudiocpp/Exception.hxx" +#include "portaudiocpp/SystemHostApiIterator.hxx" +#include "portaudiocpp/SystemDeviceIterator.hxx" + +namespace portaudio +{ + // ----------------------------------------------------------------------------------- + + // Static members: + System *System::instance_ = NULL; + int System::initCount_ = 0; + HostApi **System::hostApis_ = NULL; + Device **System::devices_ = NULL; + Device *System::nullDevice_ = NULL; + + // ----------------------------------------------------------------------------------- + + int System::version() + { + return Pa_GetVersion(); + } + + const char *System::versionText() + { + return Pa_GetVersionText(); + } + + void System::initialize() + { + ++initCount_; + + if (initCount_ == 1) + { + // Create singleton: + assert(instance_ == NULL); + instance_ = new System(); + + // Initialize the PortAudio system: + { + PaError err = Pa_Initialize(); + + if (err != paNoError) + throw PaException(err); + } + + // Create and populate device array: + { + int numDevices = instance().deviceCount(); + + devices_ = new Device*[numDevices]; + + for (int i = 0; i < numDevices; ++i) + devices_[i] = new Device(i); + } + + // Create and populate host api array: + { + int numHostApis = instance().hostApiCount(); + + hostApis_ = new HostApi*[numHostApis]; + + for (int i = 0; i < numHostApis; ++i) + hostApis_[i] = new HostApi(i); + } + + // Create null device: + nullDevice_ = new Device(paNoDevice); + } + } + + void System::terminate() + { + PaError err = paNoError; + + if (initCount_ == 1) + { + // Destroy null device: + delete nullDevice_; + + // Destroy host api array: + { + if (hostApis_ != NULL) + { + int numHostApis = instance().hostApiCount(); + + for (int i = 0; i < numHostApis; ++i) + delete hostApis_[i]; + + delete[] hostApis_; + hostApis_ = NULL; + } + } + + // Destroy device array: + { + if (devices_ != NULL) + { + int numDevices = instance().deviceCount(); + + for (int i = 0; i < numDevices; ++i) + delete devices_[i]; + + delete[] devices_; + devices_ = NULL; + } + } + + // Terminate the PortAudio system: + assert(instance_ != NULL); + err = Pa_Terminate(); + + // Destroy singleton: + delete instance_; + instance_ = NULL; + } + + if (initCount_ > 0) + --initCount_; + + if (err != paNoError) + throw PaException(err); + } + + + System &System::instance() + { + assert(exists()); + + return *instance_; + } + + bool System::exists() + { + return (instance_ != NULL); + } + + // ----------------------------------------------------------------------------------- + + System::HostApiIterator System::hostApisBegin() + { + System::HostApiIterator tmp; + tmp.ptr_ = &hostApis_[0]; // begin (first element) + return tmp; + } + + System::HostApiIterator System::hostApisEnd() + { + int count = hostApiCount(); + + System::HostApiIterator tmp; + tmp.ptr_ = &hostApis_[count]; // end (one past last element) + return tmp; + } + + HostApi &System::defaultHostApi() + { + PaHostApiIndex defaultHostApi = Pa_GetDefaultHostApi(); + + if (defaultHostApi < 0) + throw PaException(defaultHostApi); + + return *hostApis_[defaultHostApi]; + } + + HostApi &System::hostApiByTypeId(PaHostApiTypeId type) + { + PaHostApiIndex index = Pa_HostApiTypeIdToHostApiIndex(type); + + if (index < 0) + throw PaException(index); + + return *hostApis_[index]; + } + + HostApi &System::hostApiByIndex(PaHostApiIndex index) + { + if (index < 0 || index >= hostApiCount()) + throw PaException(paInternalError); + + return *hostApis_[index]; + } + + int System::hostApiCount() + { + PaHostApiIndex count = Pa_GetHostApiCount(); + + if (count < 0) + throw PaException(count); + + return count; + } + + // ----------------------------------------------------------------------------------- + + System::DeviceIterator System::devicesBegin() + { + DeviceIterator tmp; + tmp.ptr_ = &devices_[0]; + + return tmp; + } + + System::DeviceIterator System::devicesEnd() + { + int count = deviceCount(); + + DeviceIterator tmp; + tmp.ptr_ = &devices_[count]; + + return tmp; + } + + ////// + /// Returns the System's default input Device, or the null Device if none + /// was available. + ////// + Device &System::defaultInputDevice() + { + PaDeviceIndex index = Pa_GetDefaultInputDevice(); + return deviceByIndex(index); + } + + ////// + /// Returns the System's default output Device, or the null Device if none + /// was available. + ////// + Device &System::defaultOutputDevice() + { + PaDeviceIndex index = Pa_GetDefaultOutputDevice(); + return deviceByIndex(index); + } + + ////// + /// Returns the Device for the given index. + /// Will throw a paInternalError equivalent PaException if the given index + /// is out of range. + ////// + Device &System::deviceByIndex(PaDeviceIndex index) + { + if (index < -1 || index >= deviceCount()) + { + throw PaException(paInternalError); + } + + if (index == -1) + return System::instance().nullDevice(); + + return *devices_[index]; + } + + int System::deviceCount() + { + PaDeviceIndex count = Pa_GetDeviceCount(); + + if (count < 0) + throw PaException(count); + + return count; + } + + Device &System::nullDevice() + { + return *nullDevice_; + } + + // ----------------------------------------------------------------------------------- + + void System::sleep(long msec) + { + Pa_Sleep(msec); + } + + int System::sizeOfSample(PaSampleFormat format) + { + PaError err = Pa_GetSampleSize(format); + if (err < 0) + { + throw PaException(err); + return 0; + } + + return err; + } + + // ----------------------------------------------------------------------------------- + + System::System() + { + // (left blank intentionally) + } + + System::~System() + { + // (left blank intentionally) + } + + // ----------------------------------------------------------------------------------- + +} // namespace portaudio + diff --git a/extern/portaudio/bindings/cpp/source/portaudiocpp/SystemDeviceIterator.cxx b/extern/portaudio/bindings/cpp/source/portaudiocpp/SystemDeviceIterator.cxx new file mode 100644 index 0000000..f94cf10 --- /dev/null +++ b/extern/portaudio/bindings/cpp/source/portaudiocpp/SystemDeviceIterator.cxx @@ -0,0 +1,60 @@ +#include "portaudiocpp/SystemDeviceIterator.hxx" + +namespace portaudio +{ + // ----------------------------------------------------------------------------------- + + Device &System::DeviceIterator::operator*() const + { + return **ptr_; + } + + Device *System::DeviceIterator::operator->() const + { + return &**this; + } + + // ----------------------------------------------------------------------------------- + + System::DeviceIterator &System::DeviceIterator::operator++() + { + ++ptr_; + return *this; + } + + System::DeviceIterator System::DeviceIterator::operator++(int) + { + System::DeviceIterator prev = *this; + ++*this; + return prev; + } + + System::DeviceIterator &System::DeviceIterator::operator--() + { + --ptr_; + return *this; + } + + System::DeviceIterator System::DeviceIterator::operator--(int) + { + System::DeviceIterator prev = *this; + --*this; + return prev; + } + + // ----------------------------------------------------------------------------------- + + bool System::DeviceIterator::operator==(const System::DeviceIterator &rhs) const + { + return (ptr_ == rhs.ptr_); + } + + bool System::DeviceIterator::operator!=(const System::DeviceIterator &rhs) const + { + return !(*this == rhs); + } + + // ----------------------------------------------------------------------------------- +} // namespace portaudio + + diff --git a/extern/portaudio/bindings/cpp/source/portaudiocpp/SystemHostApiIterator.cxx b/extern/portaudio/bindings/cpp/source/portaudiocpp/SystemHostApiIterator.cxx new file mode 100644 index 0000000..03f2d6e --- /dev/null +++ b/extern/portaudio/bindings/cpp/source/portaudiocpp/SystemHostApiIterator.cxx @@ -0,0 +1,59 @@ +#include "portaudiocpp/SystemHostApiIterator.hxx" + +namespace portaudio +{ + // ----------------------------------------------------------------------------------- + + HostApi &System::HostApiIterator::operator*() const + { + return **ptr_; + } + + HostApi *System::HostApiIterator::operator->() const + { + return &**this; + } + + // ----------------------------------------------------------------------------------- + + System::HostApiIterator &System::HostApiIterator::operator++() + { + ++ptr_; + return *this; + } + + System::HostApiIterator System::HostApiIterator::operator++(int) + { + System::HostApiIterator prev = *this; + ++*this; + return prev; + } + + System::HostApiIterator &System::HostApiIterator::operator--() + { + --ptr_; + return *this; + } + + System::HostApiIterator System::HostApiIterator::operator--(int) + { + System::HostApiIterator prev = *this; + --*this; + return prev; + } + + // ----------------------------------------------------------------------------------- + + bool System::HostApiIterator::operator==(const System::HostApiIterator &rhs) const + { + return (ptr_ == rhs.ptr_); + } + + bool System::HostApiIterator::operator!=(const System::HostApiIterator &rhs) const + { + return !(*this == rhs); + } + + // ----------------------------------------------------------------------------------- +} // namespace portaudio + diff --git a/extern/portaudio/bindings/java/c/src/com_portaudio_BlockingStream.c b/extern/portaudio/bindings/java/c/src/com_portaudio_BlockingStream.c new file mode 100644 index 0000000..64d8213 --- /dev/null +++ b/extern/portaudio/bindings/java/c/src/com_portaudio_BlockingStream.c @@ -0,0 +1,352 @@ +/* + * Portable Audio I/O Library + * Java Binding for PortAudio + * + * Based on the Open Source API proposed by Ross Bencina + * Copyright (c) 2008 Ross Bencina + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +#include "com_portaudio_BlockingStream.h" +#include "portaudio.h" +#include "jpa_tools.h" + +#ifndef FALSE +#define FALSE (0) +#endif +#ifndef TRUE +#define TRUE (!FALSE) +#endif + +/* + * Class: com_portaudio_BlockingStream + * Method: getReadAvailable + * Signature: ()I + */ +JNIEXPORT jint JNICALL Java_com_portaudio_BlockingStream_getReadAvailable + (JNIEnv *env, jobject blockingStream) +{ + PaStream *stream =jpa_GetStreamPointer( env, blockingStream ); + if( stream == NULL ) return 0; + return Pa_GetStreamReadAvailable( stream ); +} + +/* + * Class: com_portaudio_BlockingStream + * Method: getWriteAvailable + * Signature: ()I + */ +JNIEXPORT jint JNICALL Java_com_portaudio_BlockingStream_getWriteAvailable + (JNIEnv *env, jobject blockingStream) +{ + PaStream *stream =jpa_GetStreamPointer( env, blockingStream ); + if( stream == NULL ) return 0; + return Pa_GetStreamWriteAvailable( stream ); +} + + +/* + * Class: com_portaudio_BlockingStream + * Method: writeFloats + * Signature: ([FI)Z + */ +JNIEXPORT jboolean JNICALL Java_com_portaudio_BlockingStream_writeFloats + (JNIEnv *env, jobject blockingStream, jfloatArray buffer, jint numFrames) +{ + jfloat *carr; + jint err; + PaStream *stream =jpa_GetStreamPointer( env, blockingStream ); + if( buffer == NULL ) + { + (*env)->ThrowNew( env, (*env)->FindClass(env,"java/lang/RuntimeException"), + "null stream buffer"); + return FALSE; + } + carr = (*env)->GetFloatArrayElements(env, buffer, NULL); + if (carr == NULL) + { + (*env)->ThrowNew( env, (*env)->FindClass(env,"java/lang/RuntimeException"), + "invalid stream buffer"); + return FALSE; + } + err = Pa_WriteStream( stream, carr, numFrames ); + (*env)->ReleaseFloatArrayElements(env, buffer, carr, 0); + if( err == paOutputUnderflowed ) + { + return TRUE; + } + else + { + jpa_CheckError( env, err ); + return FALSE; + } +} + +/* + * Class: com_portaudio_BlockingStream + * Method: readFloats + * Signature: ([FI)Z + */ +JNIEXPORT jboolean JNICALL Java_com_portaudio_BlockingStream_readFloats + (JNIEnv *env, jobject blockingStream, jfloatArray buffer, jint numFrames) +{ + jfloat *carr; + jint err; + PaStream *stream =jpa_GetStreamPointer( env, blockingStream ); + if( buffer == NULL ) + { + (*env)->ThrowNew( env, (*env)->FindClass(env,"java/lang/RuntimeException"), + "null stream buffer"); + return FALSE; + } + carr = (*env)->GetFloatArrayElements(env, buffer, NULL); + if (carr == NULL) + { + (*env)->ThrowNew( env, (*env)->FindClass(env,"java/lang/RuntimeException"), + "invalid stream buffer"); + return FALSE; + } + err = Pa_ReadStream( stream, carr, numFrames ); + (*env)->ReleaseFloatArrayElements(env, buffer, carr, 0); + if( err == paInputOverflowed ) + { + return TRUE; + } + else + { + jpa_CheckError( env, err ); + return FALSE; + } +} + +/* + * Class: com_portaudio_BlockingStream + * Method: writeShorts + * Signature: ([SI)Z + */ +JNIEXPORT jboolean JNICALL Java_com_portaudio_BlockingStream_writeShorts + (JNIEnv *env, jobject blockingStream, jfloatArray buffer, jint numFrames) +{ + jshort *carr; + jint err; + PaStream *stream =jpa_GetStreamPointer( env, blockingStream ); + if( buffer == NULL ) + { + (*env)->ThrowNew( env, (*env)->FindClass(env,"java/lang/RuntimeException"), + "null stream buffer"); + return FALSE; + } + carr = (*env)->GetShortArrayElements(env, buffer, NULL); + if (carr == NULL) + { + (*env)->ThrowNew( env, (*env)->FindClass(env,"java/lang/RuntimeException"), + "invalid stream buffer"); + return FALSE; + } + err = Pa_WriteStream( stream, carr, numFrames ); + (*env)->ReleaseShortArrayElements(env, buffer, carr, 0); + if( err == paOutputUnderflowed ) + { + return TRUE; + } + else + { + jpa_CheckError( env, err ); + return FALSE; + } +} + +/* + * Class: com_portaudio_BlockingStream + * Method: readShorts + * Signature: ([SI)Z + */ +JNIEXPORT jboolean JNICALL Java_com_portaudio_BlockingStream_readShorts + (JNIEnv *env, jobject blockingStream, jfloatArray buffer, jint numFrames) +{ + jshort *carr; + jint err; + PaStream *stream =jpa_GetStreamPointer( env, blockingStream ); + if( buffer == NULL ) + { + (*env)->ThrowNew( env, (*env)->FindClass(env,"java/lang/RuntimeException"), + "null stream buffer"); + return FALSE; + } + carr = (*env)->GetShortArrayElements(env, buffer, NULL); + if (carr == NULL) + { + (*env)->ThrowNew( env, (*env)->FindClass(env,"java/lang/RuntimeException"), + "invalid stream buffer"); + return FALSE; + } + err = Pa_ReadStream( stream, carr, numFrames ); + (*env)->ReleaseShortArrayElements(env, buffer, carr, 0); + if( err == paInputOverflowed ) + { + return TRUE; + } + else + { + jpa_CheckError( env, err ); + return FALSE; + } +} + +/* + * Class: com_portaudio_BlockingStream + * Method: start + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_com_portaudio_BlockingStream_start + (JNIEnv *env, jobject blockingStream ) +{ + PaStream *stream = jpa_GetStreamPointer( env, blockingStream ); + int err = Pa_StartStream( stream ); + jpa_CheckError( env, err ); +} + +/* + * Class: com_portaudio_BlockingStream + * Method: stop + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_com_portaudio_BlockingStream_stop + (JNIEnv *env, jobject blockingStream ) +{ + PaStream *stream =jpa_GetStreamPointer( env, blockingStream ); + int err = Pa_StopStream( stream ); + jpa_CheckError( env, err ); +} +/* + * Class: com_portaudio_BlockingStream + * Method: abort + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_com_portaudio_BlockingStream_abort + (JNIEnv *env, jobject blockingStream ) +{ + PaStream *stream =jpa_GetStreamPointer( env, blockingStream ); + int err = Pa_AbortStream( stream ); + jpa_CheckError( env, err ); +} + +/* + * Class: com_portaudio_BlockingStream + * Method: close + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_com_portaudio_BlockingStream_close + (JNIEnv *env, jobject blockingStream ) +{ + jclass cls; + PaStream *stream =jpa_GetStreamPointer( env, blockingStream ); + if( stream != NULL ) + { + int err = Pa_CloseStream( stream ); + jpa_CheckError( env, err ); + cls = (*env)->GetObjectClass(env, blockingStream); + jpa_SetLongField( env, cls, blockingStream, "nativeStream", (jlong) 0 ); + } +} + +/* + * Class: com_portaudio_BlockingStream + * Method: isStopped + * Signature: ()V + */ +JNIEXPORT jboolean JNICALL Java_com_portaudio_BlockingStream_isStopped + (JNIEnv *env, jobject blockingStream ) +{ + int err; + PaStream *stream =jpa_GetStreamPointer( env, blockingStream ); + if( stream == NULL ) return 1; + err = Pa_IsStreamStopped( stream ); + return (jpa_CheckError( env, err ) > 0); +} +/* + * Class: com_portaudio_BlockingStream + * Method: isActive + * Signature: ()V + */ +JNIEXPORT jboolean JNICALL Java_com_portaudio_BlockingStream_isActive + (JNIEnv *env, jobject blockingStream ) +{ + int err; + PaStream *stream =jpa_GetStreamPointer( env, blockingStream ); + if( stream == NULL ) return 0; + err = Pa_IsStreamActive( stream ); + return (jpa_CheckError( env, err ) > 0); +} + + +/* + * Class: com_portaudio_BlockingStream + * Method: getTime + * Signature: ()D + */ +JNIEXPORT jdouble JNICALL Java_com_portaudio_BlockingStream_getTime + (JNIEnv *env, jobject blockingStream ) +{ + PaStream *stream =jpa_GetStreamPointer( env, blockingStream ); + if( stream == NULL ) return 0.0; + return Pa_GetStreamTime( stream ); +} + + +/* + * Class: com_portaudio_BlockingStream + * Method: getInfo + * Signature: ()Lcom/portaudio/StreamInfo; + */ +JNIEXPORT void JNICALL Java_com_portaudio_BlockingStream_getInfo + (JNIEnv *env, jobject blockingStream, jobject streamInfo) +{ + + PaStream *stream =jpa_GetStreamPointer( env, blockingStream ); + const PaStreamInfo *info = Pa_GetStreamInfo( stream ); + if( streamInfo == NULL ) + { + jpa_ThrowError( env, "Invalid stream." ); + } + else + { + /* Get a reference to obj's class */ + jclass cls = (*env)->GetObjectClass(env, streamInfo); + + jpa_SetIntField( env, cls, streamInfo, "structVersion", info->structVersion ); + jpa_SetDoubleField( env, cls, streamInfo, "inputLatency", info->inputLatency ); + jpa_SetDoubleField( env, cls, streamInfo, "outputLatency", info->outputLatency ); + jpa_SetDoubleField( env, cls, streamInfo, "sampleRate", info->sampleRate ); + } +} + diff --git a/extern/portaudio/bindings/java/c/src/com_portaudio_BlockingStream.h b/extern/portaudio/bindings/java/c/src/com_portaudio_BlockingStream.h new file mode 100644 index 0000000..e405fae --- /dev/null +++ b/extern/portaudio/bindings/java/c/src/com_portaudio_BlockingStream.h @@ -0,0 +1,130 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#if defined(__APPLE__) +#include +#else +#include +#endif + +/* Header for class com_portaudio_BlockingStream */ + +#ifndef _Included_com_portaudio_BlockingStream +#define _Included_com_portaudio_BlockingStream +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: com_portaudio_BlockingStream + * Method: getReadAvailable + * Signature: ()I + */ +JNIEXPORT jint JNICALL Java_com_portaudio_BlockingStream_getReadAvailable + (JNIEnv *, jobject); + +/* + * Class: com_portaudio_BlockingStream + * Method: getWriteAvailable + * Signature: ()I + */ +JNIEXPORT jint JNICALL Java_com_portaudio_BlockingStream_getWriteAvailable + (JNIEnv *, jobject); + +/* + * Class: com_portaudio_BlockingStream + * Method: readFloats + * Signature: ([FI)Z + */ +JNIEXPORT jboolean JNICALL Java_com_portaudio_BlockingStream_readFloats + (JNIEnv *, jobject, jfloatArray, jint); + +/* + * Class: com_portaudio_BlockingStream + * Method: writeFloats + * Signature: ([FI)Z + */ +JNIEXPORT jboolean JNICALL Java_com_portaudio_BlockingStream_writeFloats + (JNIEnv *, jobject, jfloatArray, jint); + +/* + * Class: com_portaudio_BlockingStream + * Method: readShorts + * Signature: ([SI)Z + */ +JNIEXPORT jboolean JNICALL Java_com_portaudio_BlockingStream_readShorts + (JNIEnv *, jobject, jshortArray, jint); + +/* + * Class: com_portaudio_BlockingStream + * Method: writeShorts + * Signature: ([SI)Z + */ +JNIEXPORT jboolean JNICALL Java_com_portaudio_BlockingStream_writeShorts + (JNIEnv *, jobject, jshortArray, jint); + +/* + * Class: com_portaudio_BlockingStream + * Method: start + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_com_portaudio_BlockingStream_start + (JNIEnv *, jobject); + +/* + * Class: com_portaudio_BlockingStream + * Method: stop + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_com_portaudio_BlockingStream_stop + (JNIEnv *, jobject); + +/* + * Class: com_portaudio_BlockingStream + * Method: abort + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_com_portaudio_BlockingStream_abort + (JNIEnv *, jobject); + +/* + * Class: com_portaudio_BlockingStream + * Method: close + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_com_portaudio_BlockingStream_close + (JNIEnv *, jobject); + +/* + * Class: com_portaudio_BlockingStream + * Method: isStopped + * Signature: ()Z + */ +JNIEXPORT jboolean JNICALL Java_com_portaudio_BlockingStream_isStopped + (JNIEnv *, jobject); + +/* + * Class: com_portaudio_BlockingStream + * Method: isActive + * Signature: ()Z + */ +JNIEXPORT jboolean JNICALL Java_com_portaudio_BlockingStream_isActive + (JNIEnv *, jobject); + +/* + * Class: com_portaudio_BlockingStream + * Method: getTime + * Signature: ()D + */ +JNIEXPORT jdouble JNICALL Java_com_portaudio_BlockingStream_getTime + (JNIEnv *, jobject); + +/* + * Class: com_portaudio_BlockingStream + * Method: getInfo + * Signature: (Lcom/portaudio/StreamInfo;)V + */ +JNIEXPORT void JNICALL Java_com_portaudio_BlockingStream_getInfo + (JNIEnv *, jobject, jobject); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/extern/portaudio/bindings/java/c/src/com_portaudio_PortAudio.c b/extern/portaudio/bindings/java/c/src/com_portaudio_PortAudio.c new file mode 100644 index 0000000..77c42eb --- /dev/null +++ b/extern/portaudio/bindings/java/c/src/com_portaudio_PortAudio.c @@ -0,0 +1,279 @@ +/* + * Portable Audio I/O Library + * Java Binding for PortAudio + * + * Based on the Open Source API proposed by Ross Bencina + * Copyright (c) 2008 Ross Bencina + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +#include "com_portaudio_PortAudio.h" +#include "portaudio.h" +#include "jpa_tools.h" + +/* + * Class: com_portaudio_PortAudio + * Method: getVersion + * Signature: ()I + */ +JNIEXPORT jint JNICALL Java_com_portaudio_PortAudio_getVersion + (JNIEnv *env, jclass clazz) +{ + return Pa_GetVersion(); +} + +/* + * Class: com_portaudio_PortAudio + * Method: getVersionText + * Signature: ()Ljava/lang/String; + */ +JNIEXPORT jstring JNICALL Java_com_portaudio_PortAudio_getVersionText + (JNIEnv *env, jclass clazz) +{ + return (*env)->NewStringUTF(env, Pa_GetVersionText() ); +} + +/* + * Class: com_portaudio_PortAudio + * Method: initialize + * Signature: ()I + */ +JNIEXPORT void JNICALL Java_com_portaudio_PortAudio_initialize + (JNIEnv *env, jclass clazz) +{ + PaError err = Pa_Initialize(); + jpa_CheckError( env, err ); +} + +/* + * Class: com_portaudio_PortAudio + * Method: terminate + * Signature: ()I + */ +JNIEXPORT void JNICALL Java_com_portaudio_PortAudio_terminate + (JNIEnv *env, jclass clazz) +{ + PaError err = Pa_Terminate(); + jpa_CheckError( env, err ); +} + +/* + * Class: com_portaudio_PortAudio + * Method: getDeviceCount + * Signature: ()I + */ +JNIEXPORT jint JNICALL Java_com_portaudio_PortAudio_getDeviceCount + (JNIEnv *env, jclass clazz) +{ + jint count = Pa_GetDeviceCount(); + return jpa_CheckError( env, count ); +} + +/* + * Class: com_portaudio_PortAudio + * Method: getDeviceInfo + * Signature: (ILcom/portaudio/DeviceInfo;)I + */ +JNIEXPORT void JNICALL Java_com_portaudio_PortAudio_getDeviceInfo + (JNIEnv *env, jclass clazz, jint index, jobject deviceInfo) +{ + const PaDeviceInfo *info; + /* Get a reference to obj's class */ + jclass cls = (*env)->GetObjectClass(env, deviceInfo); + + info = Pa_GetDeviceInfo( index ); + if( info == NULL ) + { + jpa_ThrowError( env, "Pa_GetDeviceInfo returned NULL." ); + } + else + { + jpa_SetStringField( env, cls, deviceInfo, "name", info->name ); + jpa_SetIntField( env, cls, deviceInfo, "maxInputChannels", info->maxInputChannels ); + jpa_SetIntField( env, cls, deviceInfo, "maxOutputChannels", info->maxOutputChannels ); + jpa_SetIntField( env, cls, deviceInfo, "hostApi", info->hostApi ); + jpa_SetDoubleField( env, cls, deviceInfo, "defaultSampleRate", info->defaultSampleRate ); + jpa_SetDoubleField( env, cls, deviceInfo, "defaultLowInputLatency", info->defaultLowInputLatency ); + jpa_SetDoubleField( env, cls, deviceInfo, "defaultLowInputLatency", info->defaultHighInputLatency ); + jpa_SetDoubleField( env, cls, deviceInfo, "defaultLowOutputLatency", info->defaultLowOutputLatency ); + jpa_SetDoubleField( env, cls, deviceInfo, "defaultHighOutputLatency", info->defaultHighOutputLatency ); + } +} + +/* + * Class: com_portaudio_PortAudio + * Method: geHostApiCount + * Signature: ()I + */ +JNIEXPORT jint JNICALL Java_com_portaudio_PortAudio_getHostApiCount + (JNIEnv *env, jclass clazz) +{ + jint count = Pa_GetHostApiCount(); + return jpa_CheckError( env, count ); +} + + +/* + * Class: com_portaudio_PortAudio + * Method: hostApiTypeIdToHostApiIndex + * Signature: (I)I + */ +JNIEXPORT jint JNICALL Java_com_portaudio_PortAudio_hostApiTypeIdToHostApiIndex + (JNIEnv *env, jclass clazz, jint hostApiType) +{ + return Pa_HostApiTypeIdToHostApiIndex( (PaHostApiTypeId) hostApiType ); +} + +/* + * Class: com_portaudio_PortAudio + * Method: hostApiDeviceIndexToDeviceIndex + * Signature: (II)I + */ +JNIEXPORT jint JNICALL Java_com_portaudio_PortAudio_hostApiDeviceIndexToDeviceIndex + (JNIEnv *env, jclass clazz, jint hostApiIndex, jint apiDeviceIndex) +{ + return Pa_HostApiDeviceIndexToDeviceIndex( hostApiIndex, apiDeviceIndex ); +} + + +/* + * Class: com_portaudio_PortAudio + * Method: getHostApiInfo + * Signature: (ILcom/portaudio/HostApiInfo;)I + */ +JNIEXPORT void JNICALL Java_com_portaudio_PortAudio_getHostApiInfo + (JNIEnv *env, jclass clazz, jint index, jobject hostApiInfo) +{ + const PaHostApiInfo *info; + /* Get a reference to obj's class */ + jclass cls = (*env)->GetObjectClass(env, hostApiInfo); + + info = Pa_GetHostApiInfo( index ); + if( info == NULL ) + { + jpa_ThrowError( env, "Pa_GetHostApiInfo returned NULL." ); + } + else + { + jpa_SetIntField( env, cls, hostApiInfo, "version", info->structVersion ); + jpa_SetIntField( env, cls, hostApiInfo, "type", info->type ); + jpa_SetStringField( env, cls, hostApiInfo, "name", info->name ); + jpa_SetIntField( env, cls, hostApiInfo, "deviceCount", info->deviceCount ); + jpa_SetIntField( env, cls, hostApiInfo, "defaultInputDevice", info->defaultInputDevice ); + jpa_SetIntField( env, cls, hostApiInfo, "defaultOutputDevice", info->defaultOutputDevice ); + } +} + +/* + * Class: com_portaudio_PortAudio + * Method: getDefaultInputDevice + * Signature: ()I + */ +JNIEXPORT jint JNICALL Java_com_portaudio_PortAudio_getDefaultInputDevice + (JNIEnv *env, jclass clazz) +{ + jint deviceId = Pa_GetDefaultInputDevice(); + return jpa_CheckError( env, deviceId ); +} + +/* + * Class: com_portaudio_PortAudio + * Method: getDefaultOutputDevice + * Signature: ()I + */ +JNIEXPORT jint JNICALL Java_com_portaudio_PortAudio_getDefaultOutputDevice + (JNIEnv *env, jclass clazz) +{ + jint deviceId = Pa_GetDefaultOutputDevice(); + return jpa_CheckError( env, deviceId ); +} + +/* + * Class: com_portaudio_PortAudio + * Method: getDefaultHostApi + * Signature: ()I + */ +JNIEXPORT jint JNICALL Java_com_portaudio_PortAudio_getDefaultHostApi + (JNIEnv *env, jclass clazz) +{ + jint deviceId = Pa_GetDefaultHostApi(); + return jpa_CheckError( env, deviceId ); +} + +/* + * Class: com_portaudio_PortAudio + * Method: isFormatSupported + * Signature: (Lcom/portaudio/StreamParameters;Lcom/portaudio/StreamParameters;I)I + */ +JNIEXPORT jint JNICALL Java_com_portaudio_PortAudio_isFormatSupported + (JNIEnv *env, jclass clazz, jobject inParams, jobject outParams, jint sampleRate ) +{ + PaStreamParameters myInParams, *paInParams; + PaStreamParameters myOutParams, *paOutParams; + + paInParams = jpa_FillStreamParameters( env, inParams, &myInParams ); + paOutParams = jpa_FillStreamParameters( env, outParams, &myOutParams ); + + return Pa_IsFormatSupported( paInParams, paOutParams, sampleRate ); + +} + +/* + * Class: com_portaudio_PortAudio + * Method: openStream + * Signature: (Lcom/portaudio/BlockingStream;Lcom/portaudio/StreamParameters;Lcom/portaudio/StreamParameters;III)I + */ +JNIEXPORT void JNICALL Java_com_portaudio_PortAudio_openStream + (JNIEnv *env, jclass clazz, jobject blockingStream, jobject inParams, jobject outParams, jint sampleRate, jint framesPerBuffer, jint flags ) +{ + int err; + PaStreamParameters myInParams, *paInParams; + PaStreamParameters myOutParams, *paOutParams; + PaStream *stream; + + paInParams = jpa_FillStreamParameters( env, inParams, &myInParams ); + paOutParams = jpa_FillStreamParameters( env, outParams, &myOutParams ); + err = Pa_OpenStream( &stream, paInParams, paOutParams, sampleRate, framesPerBuffer, flags, NULL, NULL ); + if( jpa_CheckError( env, err ) == 0 ) + { + jclass cls = (*env)->GetObjectClass(env, blockingStream); + jpa_SetLongField( env, cls, blockingStream, "nativeStream", (jlong) stream ); + if( paInParams != NULL ) + { + jpa_SetIntField( env, cls, blockingStream, "inputFormat", paInParams->sampleFormat ); + } + if( paOutParams != NULL ) + { + jpa_SetIntField( env, cls, blockingStream, "outputFormat", paOutParams->sampleFormat ); + } + } +} diff --git a/extern/portaudio/bindings/java/c/src/com_portaudio_PortAudio.h b/extern/portaudio/bindings/java/c/src/com_portaudio_PortAudio.h new file mode 100644 index 0000000..ed806ac --- /dev/null +++ b/extern/portaudio/bindings/java/c/src/com_portaudio_PortAudio.h @@ -0,0 +1,183 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#if defined(__APPLE__) +#include +#else +#include +#endif +/* Header for class com_portaudio_PortAudio */ + +#ifndef _Included_com_portaudio_PortAudio +#define _Included_com_portaudio_PortAudio +#ifdef __cplusplus +extern "C" { +#endif +#undef com_portaudio_PortAudio_FLAG_CLIP_OFF +#define com_portaudio_PortAudio_FLAG_CLIP_OFF 1L +#undef com_portaudio_PortAudio_FLAG_DITHER_OFF +#define com_portaudio_PortAudio_FLAG_DITHER_OFF 2L +#undef com_portaudio_PortAudio_FORMAT_FLOAT_32 +#define com_portaudio_PortAudio_FORMAT_FLOAT_32 1L +#undef com_portaudio_PortAudio_FORMAT_INT_32 +#define com_portaudio_PortAudio_FORMAT_INT_32 2L +#undef com_portaudio_PortAudio_FORMAT_INT_24 +#define com_portaudio_PortAudio_FORMAT_INT_24 4L +#undef com_portaudio_PortAudio_FORMAT_INT_16 +#define com_portaudio_PortAudio_FORMAT_INT_16 8L +#undef com_portaudio_PortAudio_FORMAT_INT_8 +#define com_portaudio_PortAudio_FORMAT_INT_8 16L +#undef com_portaudio_PortAudio_FORMAT_UINT_8 +#define com_portaudio_PortAudio_FORMAT_UINT_8 32L +#undef com_portaudio_PortAudio_HOST_API_TYPE_DEV +#define com_portaudio_PortAudio_HOST_API_TYPE_DEV 0L +#undef com_portaudio_PortAudio_HOST_API_TYPE_DIRECTSOUND +#define com_portaudio_PortAudio_HOST_API_TYPE_DIRECTSOUND 1L +#undef com_portaudio_PortAudio_HOST_API_TYPE_MME +#define com_portaudio_PortAudio_HOST_API_TYPE_MME 2L +#undef com_portaudio_PortAudio_HOST_API_TYPE_ASIO +#define com_portaudio_PortAudio_HOST_API_TYPE_ASIO 3L +#undef com_portaudio_PortAudio_HOST_API_TYPE_SOUNDMANAGER +#define com_portaudio_PortAudio_HOST_API_TYPE_SOUNDMANAGER 4L +#undef com_portaudio_PortAudio_HOST_API_TYPE_COREAUDIO +#define com_portaudio_PortAudio_HOST_API_TYPE_COREAUDIO 5L +#undef com_portaudio_PortAudio_HOST_API_TYPE_OSS +#define com_portaudio_PortAudio_HOST_API_TYPE_OSS 7L +#undef com_portaudio_PortAudio_HOST_API_TYPE_ALSA +#define com_portaudio_PortAudio_HOST_API_TYPE_ALSA 8L +#undef com_portaudio_PortAudio_HOST_API_TYPE_AL +#define com_portaudio_PortAudio_HOST_API_TYPE_AL 9L +#undef com_portaudio_PortAudio_HOST_API_TYPE_BEOS +#define com_portaudio_PortAudio_HOST_API_TYPE_BEOS 10L +#undef com_portaudio_PortAudio_HOST_API_TYPE_WDMKS +#define com_portaudio_PortAudio_HOST_API_TYPE_WDMKS 11L +#undef com_portaudio_PortAudio_HOST_API_TYPE_JACK +#define com_portaudio_PortAudio_HOST_API_TYPE_JACK 12L +#undef com_portaudio_PortAudio_HOST_API_TYPE_WASAPI +#define com_portaudio_PortAudio_HOST_API_TYPE_WASAPI 13L +#undef com_portaudio_PortAudio_HOST_API_TYPE_AUDIOSCIENCE +#define com_portaudio_PortAudio_HOST_API_TYPE_AUDIOSCIENCE 14L +#undef com_portaudio_PortAudio_HOST_API_TYPE_COUNT +#define com_portaudio_PortAudio_HOST_API_TYPE_COUNT 15L +/* + * Class: com_portaudio_PortAudio + * Method: getVersion + * Signature: ()I + */ +JNIEXPORT jint JNICALL Java_com_portaudio_PortAudio_getVersion + (JNIEnv *, jclass); + +/* + * Class: com_portaudio_PortAudio + * Method: getVersionText + * Signature: ()Ljava/lang/String; + */ +JNIEXPORT jstring JNICALL Java_com_portaudio_PortAudio_getVersionText + (JNIEnv *, jclass); + +/* + * Class: com_portaudio_PortAudio + * Method: initialize + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_com_portaudio_PortAudio_initialize + (JNIEnv *, jclass); + +/* + * Class: com_portaudio_PortAudio + * Method: terminate + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_com_portaudio_PortAudio_terminate + (JNIEnv *, jclass); + +/* + * Class: com_portaudio_PortAudio + * Method: getDeviceCount + * Signature: ()I + */ +JNIEXPORT jint JNICALL Java_com_portaudio_PortAudio_getDeviceCount + (JNIEnv *, jclass); + +/* + * Class: com_portaudio_PortAudio + * Method: getDeviceInfo + * Signature: (ILcom/portaudio/DeviceInfo;)V + */ +JNIEXPORT void JNICALL Java_com_portaudio_PortAudio_getDeviceInfo + (JNIEnv *, jclass, jint, jobject); + +/* + * Class: com_portaudio_PortAudio + * Method: getHostApiCount + * Signature: ()I + */ +JNIEXPORT jint JNICALL Java_com_portaudio_PortAudio_getHostApiCount + (JNIEnv *, jclass); + +/* + * Class: com_portaudio_PortAudio + * Method: getHostApiInfo + * Signature: (ILcom/portaudio/HostApiInfo;)V + */ +JNIEXPORT void JNICALL Java_com_portaudio_PortAudio_getHostApiInfo + (JNIEnv *, jclass, jint, jobject); + +/* + * Class: com_portaudio_PortAudio + * Method: hostApiTypeIdToHostApiIndex + * Signature: (I)I + */ +JNIEXPORT jint JNICALL Java_com_portaudio_PortAudio_hostApiTypeIdToHostApiIndex + (JNIEnv *, jclass, jint); + +/* + * Class: com_portaudio_PortAudio + * Method: hostApiDeviceIndexToDeviceIndex + * Signature: (II)I + */ +JNIEXPORT jint JNICALL Java_com_portaudio_PortAudio_hostApiDeviceIndexToDeviceIndex + (JNIEnv *, jclass, jint, jint); + +/* + * Class: com_portaudio_PortAudio + * Method: getDefaultInputDevice + * Signature: ()I + */ +JNIEXPORT jint JNICALL Java_com_portaudio_PortAudio_getDefaultInputDevice + (JNIEnv *, jclass); + +/* + * Class: com_portaudio_PortAudio + * Method: getDefaultOutputDevice + * Signature: ()I + */ +JNIEXPORT jint JNICALL Java_com_portaudio_PortAudio_getDefaultOutputDevice + (JNIEnv *, jclass); + +/* + * Class: com_portaudio_PortAudio + * Method: getDefaultHostApi + * Signature: ()I + */ +JNIEXPORT jint JNICALL Java_com_portaudio_PortAudio_getDefaultHostApi + (JNIEnv *, jclass); + +/* + * Class: com_portaudio_PortAudio + * Method: isFormatSupported + * Signature: (Lcom/portaudio/StreamParameters;Lcom/portaudio/StreamParameters;I)I + */ +JNIEXPORT jint JNICALL Java_com_portaudio_PortAudio_isFormatSupported + (JNIEnv *, jclass, jobject, jobject, jint); + +/* + * Class: com_portaudio_PortAudio + * Method: openStream + * Signature: (Lcom/portaudio/BlockingStream;Lcom/portaudio/StreamParameters;Lcom/portaudio/StreamParameters;III)V + */ +JNIEXPORT void JNICALL Java_com_portaudio_PortAudio_openStream + (JNIEnv *, jclass, jobject, jobject, jobject, jint, jint, jint); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/extern/portaudio/bindings/java/c/src/jpa_tools.c b/extern/portaudio/bindings/java/c/src/jpa_tools.c new file mode 100644 index 0000000..e3f903a --- /dev/null +++ b/extern/portaudio/bindings/java/c/src/jpa_tools.c @@ -0,0 +1,208 @@ +/* + * Portable Audio I/O Library + * Java Binding for PortAudio + * + * Based on the Open Source API proposed by Ross Bencina + * Copyright (c) 2008 Ross Bencina + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +#include "com_portaudio_PortAudio.h" +#include "portaudio.h" +#include "jpa_tools.h" + +jint jpa_GetIntField( JNIEnv *env, jclass cls, jobject obj, const char *fieldName ) +{ + /* Look for the instance field maxInputChannels in cls */ + jfieldID fid = (*env)->GetFieldID(env, cls, fieldName, "I"); + if (fid == NULL) + { + jpa_ThrowError( env, "Cannot find integer JNI field." ); + return 0; + } + else + { + return (*env)->GetIntField(env, obj, fid ); + } +} + +void jpa_SetIntField( JNIEnv *env, jclass cls, jobject obj, const char *fieldName, jint value ) +{ + /* Look for the instance field maxInputChannels in cls */ + jfieldID fid = (*env)->GetFieldID(env, cls, fieldName, "I"); + if (fid == NULL) + { + jpa_ThrowError( env, "Cannot find integer JNI field." ); + } + else + { + (*env)->SetIntField(env, obj, fid, value ); + } +} + +jlong jpa_GetLongField( JNIEnv *env, jclass cls, jobject obj, const char *fieldName ) +{ + /* Look for the instance field maxInputChannels in cls */ + jfieldID fid = (*env)->GetFieldID(env, cls, fieldName, "J"); + if (fid == NULL) + { + jpa_ThrowError( env, "Cannot find long JNI field." ); + return 0L; + } + else + { + return (*env)->GetLongField(env, obj, fid ); + } +} + +void jpa_SetLongField( JNIEnv *env, jclass cls, jobject obj, const char *fieldName, jlong value ) +{ + /* Look for the instance field maxInputChannels in cls */ + jfieldID fid = (*env)->GetFieldID(env, cls, fieldName, "J"); + if (fid == NULL) + { + jpa_ThrowError( env, "Cannot find long JNI field." ); + } + else + { + (*env)->SetLongField(env, obj, fid, value ); + } +} + + +void jpa_SetDoubleField( JNIEnv *env, jclass cls, jobject obj, const char *fieldName, jdouble value ) +{ + /* Look for the instance field maxInputChannels in cls */ + jfieldID fid = (*env)->GetFieldID(env, cls, fieldName, "D"); + if (fid == NULL) + { + jpa_ThrowError( env, "Cannot find double JNI field." ); + } + else + { + (*env)->SetDoubleField(env, obj, fid, value ); + } +} + + +jdouble jpa_GetDoubleField( JNIEnv *env, jclass cls, jobject obj, const char *fieldName ) +{ + /* Look for the instance field maxInputChannels in cls */ + jfieldID fid = (*env)->GetFieldID(env, cls, fieldName, "D"); + if (fid == NULL) + { + jpa_ThrowError( env, "Cannot find double JNI field." ); + return 0; + } + else + { + return (*env)->GetDoubleField(env, obj, fid ); + } +} + +void jpa_SetStringField( JNIEnv *env, jclass cls, jobject obj, const char *fieldName, const char *value ) +{ + /* Look for the instance field maxInputChannels in cls */ + jfieldID fid = (*env)->GetFieldID(env, cls, fieldName, "Ljava/lang/String;"); + if (fid == NULL) + { + jpa_ThrowError( env, "Cannot find String JNI field." ); + } + else + { + jstring jstr = (*env)->NewStringUTF(env, value); + if (jstr == NULL) + { + jpa_ThrowError( env, "Cannot create new String." ); + } + else + { + (*env)->SetObjectField(env, obj, fid, jstr ); + } + } +} + +PaStreamParameters *jpa_FillStreamParameters( JNIEnv *env, jobject jstreamParam, PaStreamParameters *myParams ) +{ + jclass cls; + + if( jstreamParam == NULL ) return NULL; // OK, not an error + + cls = (*env)->GetObjectClass(env, jstreamParam); + + myParams->channelCount = jpa_GetIntField( env, cls, jstreamParam, "channelCount" ); + myParams->device = jpa_GetIntField( env, cls, jstreamParam, "device" ); + myParams->sampleFormat = jpa_GetIntField( env, cls, jstreamParam, "sampleFormat" ); + myParams->suggestedLatency = jpa_GetDoubleField( env, cls, jstreamParam, "suggestedLatency" ); + myParams->hostApiSpecificStreamInfo = NULL; + + return myParams; +} + +// Create an exception that will be thrown when we return from the JNI call. +jint jpa_ThrowError( JNIEnv *env, const char *message ) +{ + return (*env)->ThrowNew(env, (*env)->FindClass( env, "java/lang/RuntimeException"), + message ); +} + +// Throw an exception on error. +jint jpa_CheckError( JNIEnv *env, PaError err ) +{ + if( err == -1 ) + { + return jpa_ThrowError( env, "-1, possibly no available default device" ); + } + else if( err < 0 ) + { + if( err == paUnanticipatedHostError ) + { + const PaHostErrorInfo *hostErrorInfo = Pa_GetLastHostErrorInfo(); + return jpa_ThrowError( env, hostErrorInfo->errorText ); + } + else + { + return jpa_ThrowError( env, Pa_GetErrorText( err ) ); + } + } + else + { + return err; + } +} + +// Get the stream pointer from a BlockingStream long field. +PaStream *jpa_GetStreamPointer( JNIEnv *env, jobject blockingStream ) +{ + jclass cls = (*env)->GetObjectClass(env, blockingStream); + return (PaStream *) jpa_GetLongField( env, cls, blockingStream, "nativeStream" ); +} diff --git a/extern/portaudio/bindings/java/c/src/jpa_tools.h b/extern/portaudio/bindings/java/c/src/jpa_tools.h new file mode 100644 index 0000000..11e724c --- /dev/null +++ b/extern/portaudio/bindings/java/c/src/jpa_tools.h @@ -0,0 +1,62 @@ +/* + * Portable Audio I/O Library + * Java Binding for PortAudio + * + * Based on the Open Source API proposed by Ross Bencina + * Copyright (c) 2008 Ross Bencina + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +#include "com_portaudio_PortAudio.h" +#include "portaudio.h" + +#ifndef JPA_TOOLS_H +#define JPA_TOOLS_H + +jint jpa_GetIntField( JNIEnv *env, jclass cls, jobject obj, const char *fieldName ); +void jpa_SetIntField( JNIEnv *env, jclass cls, jobject obj, const char *fieldName, jint value ); + +jlong jpa_GetLongField( JNIEnv *env, jclass cls, jobject obj, const char *fieldName ); +void jpa_SetLongField( JNIEnv *env, jclass cls, jobject obj, const char *fieldName, jlong value ); + +jdouble jpa_GetDoubleField( JNIEnv *env, jclass cls, jobject obj, const char *fieldName ); +void jpa_SetDoubleField( JNIEnv *env, jclass cls, jobject obj, const char *fieldName, jdouble value ); + +void jpa_SetStringField( JNIEnv *env, jclass cls, jobject obj, const char *fieldName, const char *value ); +PaStreamParameters *jpa_FillStreamParameters( JNIEnv *env, jobject jstreamParam, PaStreamParameters *myParams ); + +jint jpa_CheckError( JNIEnv *env, PaError err ); +jint jpa_ThrowError( JNIEnv *env, const char *message ); + +PaStream *jpa_GetStreamPointer( JNIEnv *env, jobject blockingStream ); + +#endif /* JPA_TOOLS_H */ diff --git a/extern/portaudio/bindings/java/jportaudio.dox b/extern/portaudio/bindings/java/jportaudio.dox new file mode 100644 index 0000000..f97b565 --- /dev/null +++ b/extern/portaudio/bindings/java/jportaudio.dox @@ -0,0 +1,65 @@ +/** +@page java_binding JPortAudio Java Binding +@ingroup jportaudio + +Note: this page has not been reviewed, and may contain errors. + +@section java_draft DRAFT - IN PROGRESS + +9/4/12 JPortAudio is very new and should be considered an "alpha" release. +The building of JPortAudio will eventually be integrated into the Makefile as an optional build. + +Currently JPortAudio is only supported for Windows and Macintosh. Please contact us if you want to help with porting Linux. + +For reference documentation of the JPortAudio API see: com.portaudio.PortAudio + +For an example see: PlaySine.java + +@section java_comp_windows Building JPortAudio on Windows + +Build the Java code using the Eclipse project in "jportaudio". Export as "jportaudio.jar". + +If you modify the JNI API then you will need to regenerate the JNI .h files using: + +@code +cd bindings/java/scripts +make_header.bat +@endcode + +Build the JNI DLL using the Visual Studio 2010 solution in "java/c/build/vs2010/PortAudioJNI". + +@section java_use_windows Using JPortAudio on Windows + +Put the "jportaudio.jar" in the classpath for your application. +Place the following libraries where they can be found, typically in the same folder as your application. + +- portaudio_x86.dll +- portaudio_x64.dll +- jportaudio_x86.dll +- jportaudio_x64.dll + +@section java_comp_max Building JPortAudio on Mac + +These are notes from building JPortAudio on a Mac with 10.6.8 and XCode 4. + +I created a target of type 'C' library. + +I added the regular PortAudio frameworks plus the JavaVM framework. + +I modified com_portaudio_PortAudio.h and com_portaudio_BlockingStream.h so that jni.h could found. + +@code +#if defined(__APPLE__) +#include +#else +#include +#endif +@endcode + +This is bad because those header files are autogenerated and will be overwritten. +We need a better solution for this. + +I had trouble finding the "libjportaudio.jnilib". So I added a Build Phase that copied the library to "/Users/phil/Library/Java/Extensions". + +On the Mac we can create a universal library for both 32 and 64-bit JVMs. So in the JAR file I will open "jportaudio" on Apple. ON WIndows I will continue to open "jportaudio_x64" and "jportaudio_x86". +*/ diff --git a/extern/portaudio/bindings/java/jportaudio/.classpath b/extern/portaudio/bindings/java/jportaudio/.classpath new file mode 100644 index 0000000..6bbd70c --- /dev/null +++ b/extern/portaudio/bindings/java/jportaudio/.classpath @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/extern/portaudio/bindings/java/jportaudio/.project b/extern/portaudio/bindings/java/jportaudio/.project new file mode 100644 index 0000000..8d2a750 --- /dev/null +++ b/extern/portaudio/bindings/java/jportaudio/.project @@ -0,0 +1,17 @@ + + + JPortAudio + + + + + + org.eclipse.jdt.core.javabuilder + + + + + + org.eclipse.jdt.core.javanature + + diff --git a/extern/portaudio/bindings/java/jportaudio/jtests/com/portaudio/PlaySine.java b/extern/portaudio/bindings/java/jportaudio/jtests/com/portaudio/PlaySine.java new file mode 100644 index 0000000..ec2cb97 --- /dev/null +++ b/extern/portaudio/bindings/java/jportaudio/jtests/com/portaudio/PlaySine.java @@ -0,0 +1,89 @@ + +/** @file + @ingroup bindings_java + + @brief Example that shows how to play sine waves using JPortAudio. +*/ +package com.portaudio; + +import com.portaudio.TestBasic.SineOscillator; + +public class PlaySine +{ + /** + * Write a sine wave to the stream. + * @param stream + * @param framesPerBuffer + * @param numFrames + * @param sampleRate + */ + private void writeSineData( BlockingStream stream, int framesPerBuffer, + int numFrames, int sampleRate ) + { + float[] buffer = new float[framesPerBuffer * 2]; + SineOscillator osc1 = new SineOscillator( 200.0, sampleRate ); + SineOscillator osc2 = new SineOscillator( 300.0, sampleRate ); + int framesLeft = numFrames; + while( framesLeft > 0 ) + { + int index = 0; + int framesToWrite = (framesLeft > framesPerBuffer) ? framesPerBuffer + : framesLeft; + for( int j = 0; j < framesToWrite; j++ ) + { + buffer[index++] = (float) osc1.next(); + buffer[index++] = (float) osc2.next(); + } + stream.write( buffer, framesToWrite ); + framesLeft -= framesToWrite; + } + } + + /** + * Create a stream on the default device then play sine waves. + */ + public void play() + { + PortAudio.initialize(); + + // Get the default device and setup the stream parameters. + int deviceId = PortAudio.getDefaultOutputDevice(); + DeviceInfo deviceInfo = PortAudio.getDeviceInfo( deviceId ); + double sampleRate = deviceInfo.defaultSampleRate; + System.out.println( " deviceId = " + deviceId ); + System.out.println( " sampleRate = " + sampleRate ); + System.out.println( " device name = " + deviceInfo.name ); + + StreamParameters streamParameters = new StreamParameters(); + streamParameters.channelCount = 2; + streamParameters.device = deviceId; + streamParameters.suggestedLatency = deviceInfo.defaultLowOutputLatency; + System.out.println( " suggestedLatency = " + + streamParameters.suggestedLatency ); + + int framesPerBuffer = 256; + int flags = 0; + + // Open a stream for output. + BlockingStream stream = PortAudio.openStream( null, streamParameters, + (int) sampleRate, framesPerBuffer, flags ); + + int numFrames = (int) (sampleRate * 4); // enough for 4 seconds + + stream.start(); + + writeSineData( stream, framesPerBuffer, numFrames, (int) sampleRate ); + + stream.stop(); + stream.close(); + + PortAudio.terminate(); + System.out.println( "JPortAudio test complete." ); + } + + public static void main( String[] args ) + { + PlaySine player = new PlaySine(); + player.play(); + } +} diff --git a/extern/portaudio/bindings/java/jportaudio/jtests/com/portaudio/TestBasic.java b/extern/portaudio/bindings/java/jportaudio/jtests/com/portaudio/TestBasic.java new file mode 100644 index 0000000..b05750d --- /dev/null +++ b/extern/portaudio/bindings/java/jportaudio/jtests/com/portaudio/TestBasic.java @@ -0,0 +1,523 @@ +/* + * Portable Audio I/O Library + * Java Binding for PortAudio + * + * Based on the Open Source API proposed by Ross Bencina + * Copyright (c) 2008 Ross Bencina + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +package com.portaudio; + +import junit.framework.TestCase; + +/** + * Test the Java bindings for PortAudio. + * + * @author Phil Burk + * + */ +public class TestBasic extends TestCase +{ + + public void testDeviceCount() + { + PortAudio.initialize(); + assertTrue( "version invalid", (PortAudio.getVersion() > 0) ); + System.out.println( "getVersion = " + PortAudio.getVersion() ); + System.out.println( "getVersionText = " + PortAudio.getVersionText() ); + System.out.println( "getDeviceCount = " + PortAudio.getDeviceCount() ); + assertTrue( "getDeviceCount", (PortAudio.getDeviceCount() > 0) ); + PortAudio.terminate(); + } + + public void testListDevices() + { + PortAudio.initialize(); + int count = PortAudio.getDeviceCount(); + assertTrue( "getDeviceCount", (count > 0) ); + for( int i = 0; i < count; i++ ) + { + DeviceInfo info = PortAudio.getDeviceInfo( i ); + System.out.println( "------------------ #" + i ); + System.out.println( " name = " + info.name ); + System.out.println( " hostApi = " + info.hostApi ); + System.out.println( " maxOutputChannels = " + + info.maxOutputChannels ); + System.out.println( " maxInputChannels = " + + info.maxInputChannels ); + System.out.println( " defaultSampleRate = " + + info.defaultSampleRate ); + System.out.printf( " defaultLowInputLatency = %3d msec\n", + ((int) (info.defaultLowInputLatency * 1000)) ); + System.out.printf( " defaultHighInputLatency = %3d msec\n", + ((int) (info.defaultHighInputLatency * 1000)) ); + System.out.printf( " defaultLowOutputLatency = %3d msec\n", + ((int) (info.defaultLowOutputLatency * 1000)) ); + System.out.printf( " defaultHighOutputLatency = %3d msec\n", + ((int) (info.defaultHighOutputLatency * 1000)) ); + + assertTrue( "some channels", + (info.maxOutputChannels + info.maxInputChannels) > 0 ); + assertTrue( "not too many channels", (info.maxInputChannels < 64) ); + assertTrue( "not too many channels", (info.maxOutputChannels < 64) ); + } + + System.out.println( "defaultInput = " + + PortAudio.getDefaultInputDevice() ); + System.out.println( "defaultOutput = " + + PortAudio.getDefaultOutputDevice() ); + + PortAudio.terminate(); + } + + public void testHostApis() + { + PortAudio.initialize(); + int validApiCount = 0; + for( int hostApiType = 0; hostApiType < PortAudio.HOST_API_TYPE_COUNT; hostApiType++ ) + { + int hostApiIndex = PortAudio + .hostApiTypeIdToHostApiIndex( hostApiType ); + if( hostApiIndex >= 0 ) + { + HostApiInfo info = PortAudio.getHostApiInfo( hostApiIndex ); + System.out.println( "Checking Host API: " + info.name ); + for( int apiDeviceIndex = 0; apiDeviceIndex < info.deviceCount; apiDeviceIndex++ ) + { + int deviceIndex = PortAudio + .hostApiDeviceIndexToDeviceIndex( hostApiIndex, + apiDeviceIndex ); + DeviceInfo deviceInfo = PortAudio + .getDeviceInfo( deviceIndex ); + assertEquals( "host api must match up", hostApiIndex, + deviceInfo.hostApi ); + } + validApiCount++; + } + } + + assertEquals( "host api counts", PortAudio.getHostApiCount(), + validApiCount ); + } + + public void testListHostApis() + { + PortAudio.initialize(); + int count = PortAudio.getHostApiCount(); + assertTrue( "getHostApiCount", (count > 0) ); + for( int i = 0; i < count; i++ ) + { + HostApiInfo info = PortAudio.getHostApiInfo( i ); + System.out.println( "------------------ #" + i ); + System.out.println( " version = " + info.version ); + System.out.println( " name = " + info.name ); + System.out.println( " type = " + info.type ); + System.out.println( " deviceCount = " + info.deviceCount ); + System.out.println( " defaultInputDevice = " + + info.defaultInputDevice ); + System.out.println( " defaultOutputDevice = " + + info.defaultOutputDevice ); + assertTrue( "some devices", info.deviceCount > 0 ); + } + + System.out.println( "------\ndefaultHostApi = " + + PortAudio.getDefaultHostApi() ); + PortAudio.terminate(); + } + + public void testCheckFormat() + { + PortAudio.initialize(); + StreamParameters streamParameters = new StreamParameters(); + streamParameters.device = PortAudio.getDefaultOutputDevice(); + int result = PortAudio + .isFormatSupported( null, streamParameters, 44100 ); + System.out.println( "isFormatSupported returns " + result ); + assertEquals( "default output format", 0, result ); + // Try crazy channelCount + streamParameters.channelCount = 8765; + result = PortAudio.isFormatSupported( null, streamParameters, 44100 ); + System.out.println( "crazy isFormatSupported returns " + result ); + assertTrue( "default output format", (result < 0) ); + PortAudio.terminate(); + } + + static class SineOscillator + { + double phase = 0.0; + double phaseIncrement = 0.01; + + SineOscillator(double freq, int sampleRate) + { + phaseIncrement = freq * Math.PI * 2.0 / sampleRate; + } + + double next() + { + double value = Math.sin( phase ); + phase += phaseIncrement; + if( phase > Math.PI ) + { + phase -= Math.PI * 2.0; + } + return value; + } + } + + public void testStreamError() + { + PortAudio.initialize(); + StreamParameters streamParameters = new StreamParameters(); + streamParameters.sampleFormat = PortAudio.FORMAT_FLOAT_32; + streamParameters.channelCount = 2; + streamParameters.device = PortAudio.getDefaultOutputDevice(); + int framesPerBuffer = 256; + int flags = 0; + BlockingStream stream = PortAudio.openStream( null, streamParameters, + 44100, framesPerBuffer, flags ); + + // Try to write data to a stopped stream. + Throwable caught = null; + try + { + float[] buffer = new float[framesPerBuffer + * streamParameters.channelCount]; + stream.write( buffer, framesPerBuffer ); + } catch( Throwable e ) + { + caught = e; + e.printStackTrace(); + } + + assertTrue( "caught no expection", (caught != null) ); + assertTrue( "exception should say stream is stopped", caught + .getMessage().contains( "stopped" ) ); + + // Try to write null data. + caught = null; + try + { + stream.write( (float[]) null, framesPerBuffer ); + } catch( Throwable e ) + { + caught = e; + e.printStackTrace(); + } + assertTrue( "caught no expection", (caught != null) ); + assertTrue( "exception should say stream is stopped", caught + .getMessage().contains( "null" ) ); + + // Try to write short data to a float stream. + stream.start(); + caught = null; + try + { + short[] buffer = new short[framesPerBuffer + * streamParameters.channelCount]; + stream.write( buffer, framesPerBuffer ); + } catch( Throwable e ) + { + caught = e; + e.printStackTrace(); + } + + assertTrue( "caught no expection", (caught != null) ); + assertTrue( "exception should say tried to", caught.getMessage() + .contains( "Tried to write short" ) ); + + stream.close(); + + PortAudio.terminate(); + } + + public void checkBlockingWriteFloat( int deviceId, double sampleRate ) + { + StreamParameters streamParameters = new StreamParameters(); + streamParameters.channelCount = 2; + streamParameters.device = deviceId; + streamParameters.suggestedLatency = PortAudio + .getDeviceInfo( streamParameters.device ).defaultLowOutputLatency; + System.out.println( "suggestedLatency = " + + streamParameters.suggestedLatency ); + + int framesPerBuffer = 256; + int flags = 0; + BlockingStream stream = PortAudio.openStream( null, streamParameters, + (int) sampleRate, framesPerBuffer, flags ); + assertTrue( "got default stream", stream != null ); + + assertEquals( "stream isStopped", true, stream.isStopped() ); + assertEquals( "stream isActive", false, stream.isActive() ); + + int numFrames = 80000; + double expected = ((double)numFrames) / sampleRate; + stream.start(); + long startTime = System.currentTimeMillis(); + double startStreamTime = stream.getTime(); + assertEquals( "stream isStopped", false, stream.isStopped() ); + assertEquals( "stream isActive", true, stream.isActive() ); + + writeSineData( stream, framesPerBuffer, numFrames, (int) sampleRate ); + + StreamInfo streamInfo = stream.getInfo(); + System.out.println( "inputLatency of a stream = "+ streamInfo.inputLatency ); + System.out.println( "outputLatency of a stream = "+streamInfo.outputLatency ); + System.out.println( "sampleRate of a stream = "+ streamInfo.sampleRate ); + + assertEquals( "inputLatency of a stream ", 0.0, streamInfo.inputLatency, 0.000001 ); + assertTrue( "outputLatency of a stream ",(streamInfo.outputLatency > 0) ); + assertEquals( "sampleRate of a stream ", sampleRate, streamInfo.sampleRate, 3 ); + + double endStreamTime = stream.getTime(); + stream.stop(); + long stopTime = System.currentTimeMillis(); + + System.out.println( "startStreamTime = " + startStreamTime ); + System.out.println( "endStreamTime = " + endStreamTime ); + double elapsedStreamTime = endStreamTime - startStreamTime; + System.out.println( "elapsedStreamTime = " + elapsedStreamTime ); + assertTrue( "elapsedStreamTime: " + elapsedStreamTime, + (elapsedStreamTime > 0.0) ); + assertEquals( "elapsedStreamTime: ", expected, elapsedStreamTime, 0.10 ); + + assertEquals( "stream isStopped", true, stream.isStopped() ); + assertEquals( "stream isActive", false, stream.isActive() ); + stream.close(); + + double elapsed = (stopTime - startTime) / 1000.0; + assertEquals( "elapsed time to play", expected, elapsed, 0.20 ); + } + + public void testBlockingWriteFloat() + { + PortAudio.initialize(); + checkBlockingWriteFloat( PortAudio.getDefaultOutputDevice(), 44100 ); + PortAudio.terminate(); + } + + public void ZtestWriteEachHostAPI() + { + PortAudio.initialize(); + for( int hostApiIndex = 0; hostApiIndex < PortAudio.getHostApiCount(); hostApiIndex++ ) + { + HostApiInfo hostInfo = PortAudio.getHostApiInfo( hostApiIndex ); + System.out.println( "-------------\nWriting using Host API: " + hostInfo.name ); + int deviceId = hostInfo.defaultOutputDevice; + System.out.println( " Device ID =" + deviceId ); + DeviceInfo deviceInfo = PortAudio.getDeviceInfo( deviceId ); + System.out.println( " sampleRate =" + deviceInfo.defaultSampleRate ); + checkBlockingWriteFloat( deviceId, + (int) deviceInfo.defaultSampleRate ); + System.out.println( "Finished with " + hostInfo.name ); + } + PortAudio.terminate(); + } + + private void writeSineData( BlockingStream stream, int framesPerBuffer, + int numFrames, int sampleRate ) + { + float[] buffer = new float[framesPerBuffer * 2]; + SineOscillator osc1 = new SineOscillator( 200.0, sampleRate ); + SineOscillator osc2 = new SineOscillator( 300.0, sampleRate ); + int framesLeft = numFrames; + while( framesLeft > 0 ) + { + int index = 0; + int framesToWrite = (framesLeft > framesPerBuffer) ? framesPerBuffer + : framesLeft; + for( int j = 0; j < framesToWrite; j++ ) + { + buffer[index++] = (float) osc1.next(); + buffer[index++] = (float) osc2.next(); + } + stream.write( buffer, framesToWrite ); + framesLeft -= framesToWrite; + } + } + + private void writeSineDataShort( BlockingStream stream, + int framesPerBuffer, int numFrames ) + { + short[] buffer = new short[framesPerBuffer * 2]; + SineOscillator osc1 = new SineOscillator( 200.0, 44100 ); + SineOscillator osc2 = new SineOscillator( 300.0, 44100 ); + int framesLeft = numFrames; + while( framesLeft > 0 ) + { + int index = 0; + int framesToWrite = (framesLeft > framesPerBuffer) ? framesPerBuffer + : framesLeft; + for( int j = 0; j < framesToWrite; j++ ) + { + buffer[index++] = (short) (osc1.next() * 32767); + buffer[index++] = (short) (osc2.next() * 32767); + } + stream.write( buffer, framesToWrite ); + framesLeft -= framesToWrite; + } + } + + public void testBlockingWriteShort() + { + PortAudio.initialize(); + + StreamParameters streamParameters = new StreamParameters(); + streamParameters.sampleFormat = PortAudio.FORMAT_INT_16; + streamParameters.channelCount = 2; + streamParameters.device = PortAudio.getDefaultOutputDevice(); + streamParameters.suggestedLatency = PortAudio + .getDeviceInfo( streamParameters.device ).defaultLowOutputLatency; + System.out.println( "suggestedLatency = " + + streamParameters.suggestedLatency ); + + int framesPerBuffer = 256; + int flags = 0; + BlockingStream stream = PortAudio.openStream( null, streamParameters, + 44100, framesPerBuffer, flags ); + assertTrue( "got default stream", stream != null ); + + int numFrames = 80000; + stream.start(); + long startTime = System.currentTimeMillis(); + writeSineDataShort( stream, framesPerBuffer, numFrames ); + stream.stop(); + long stopTime = System.currentTimeMillis(); + stream.close(); + + double elapsed = (stopTime - startTime) / 1000.0; + double expected = numFrames / 44100.0; + assertEquals( "elapsed time to play", expected, elapsed, 0.20 ); + PortAudio.terminate(); + } + + public void testRecordPlayFloat() throws InterruptedException + { + checkRecordPlay( PortAudio.FORMAT_FLOAT_32 ); + } + + public void testRecordPlayShort() throws InterruptedException + { + checkRecordPlay( PortAudio.FORMAT_INT_16 ); + } + + public void checkRecordPlay( int sampleFormat ) throws InterruptedException + { + int framesPerBuffer = 256; + int flags = 0; + int sampleRate = 44100; + int numFrames = sampleRate * 3; + float[] floatBuffer = null; + short[] shortBuffer = null; + + PortAudio.initialize(); + StreamParameters inParameters = new StreamParameters(); + inParameters.sampleFormat = sampleFormat; + inParameters.device = PortAudio.getDefaultInputDevice(); + + DeviceInfo info = PortAudio.getDeviceInfo( inParameters.device ); + inParameters.channelCount = (info.maxInputChannels > 2) ? 2 + : info.maxInputChannels; + System.out.println( "channelCount = " + inParameters.channelCount ); + inParameters.suggestedLatency = PortAudio + .getDeviceInfo( inParameters.device ).defaultLowInputLatency; + + if( sampleFormat == PortAudio.FORMAT_FLOAT_32 ) + { + floatBuffer = new float[numFrames * inParameters.channelCount]; + } + else if( sampleFormat == PortAudio.FORMAT_INT_16 ) + { + shortBuffer = new short[numFrames * inParameters.channelCount]; + } + // Record a few seconds of audio. + BlockingStream inStream = PortAudio.openStream( inParameters, null, + sampleRate, framesPerBuffer, flags ); + + System.out.println( "RECORDING - say something like testing 1,2,3..." ); + inStream.start(); + + if( sampleFormat == PortAudio.FORMAT_FLOAT_32 ) + { + inStream.read( floatBuffer, numFrames ); + } + else if( sampleFormat == PortAudio.FORMAT_INT_16 ) + { + inStream.read( shortBuffer, numFrames ); + } + Thread.sleep( 100 ); + int availableToRead = inStream.getReadAvailable(); + System.out.println( "availableToRead = " + availableToRead ); + assertTrue( "getReadAvailable ", availableToRead > 0 ); + + inStream.stop(); + inStream.close(); + System.out.println( "Finished recording. Begin Playback." ); + + // Play back what we recorded. + StreamParameters outParameters = new StreamParameters(); + outParameters.sampleFormat = sampleFormat; + outParameters.channelCount = inParameters.channelCount; + outParameters.device = PortAudio.getDefaultOutputDevice(); + outParameters.suggestedLatency = PortAudio + .getDeviceInfo( outParameters.device ).defaultLowOutputLatency; + + BlockingStream outStream = PortAudio.openStream( null, outParameters, + sampleRate, framesPerBuffer, flags ); + assertTrue( "got default stream", outStream != null ); + + assertEquals( "inStream isActive", false, inStream.isActive() ); + + outStream.start(); + Thread.sleep( 100 ); + int availableToWrite = outStream.getWriteAvailable(); + System.out.println( "availableToWrite = " + availableToWrite ); + assertTrue( "getWriteAvailable ", availableToWrite > 0 ); + + System.out.println( "inStream = " + inStream ); + System.out.println( "outStream = " + outStream ); + assertEquals( "inStream isActive", false, inStream.isActive() ); + assertEquals( "outStream isActive", true, outStream.isActive() ); + if( sampleFormat == PortAudio.FORMAT_FLOAT_32 ) + { + outStream.write( floatBuffer, numFrames ); + } + else if( sampleFormat == PortAudio.FORMAT_INT_16 ) + { + outStream.write( shortBuffer, numFrames ); + } + outStream.stop(); + + outStream.close(); + PortAudio.terminate(); + } +} diff --git a/extern/portaudio/bindings/java/jportaudio/src/com/portaudio/BlockingStream.java b/extern/portaudio/bindings/java/jportaudio/src/com/portaudio/BlockingStream.java new file mode 100644 index 0000000..4c249ab --- /dev/null +++ b/extern/portaudio/bindings/java/jportaudio/src/com/portaudio/BlockingStream.java @@ -0,0 +1,208 @@ +/* + * Portable Audio I/O Library + * Java Binding for PortAudio + * + * Based on the Open Source API proposed by Ross Bencina + * Copyright (c) 2008 Ross Bencina + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +/** @file + @ingroup bindings_java + + @brief A blocking read/write stream. +*/ +package com.portaudio; + +/** + * Represents a stream for blocking read/write I/O. + * + * This Java object contains the pointer to a PortAudio stream stored as a long. + * It is passed to PortAudio when calling stream related functions. + * + * To create one of these, call PortAudio.openStream(). + * + * @see PortAudio + * + * @author Phil Burk + * + */ +public class BlockingStream +{ + // nativeStream is only accessed by the native code. It contains a pointer + // to a PaStream. + private long nativeStream; + private int inputFormat = -1; + private int outputFormat = -1; + + protected BlockingStream() + { + } + + /** + * @return number of frames that can be read without blocking. + */ + public native int getReadAvailable(); + + /** + * @return number of frames that can be written without blocking. + */ + public native int getWriteAvailable(); + + private native boolean readFloats( float[] buffer, int numFrames ); + + private native boolean writeFloats( float[] buffer, int numFrames ); + + /** + * Read 32-bit floating point data from the stream into the array. + * + * @param buffer + * @param numFrames + * number of frames to read + * @return true if an input overflow occurred + */ + public boolean read( float[] buffer, int numFrames ) + { + if( inputFormat != PortAudio.FORMAT_FLOAT_32 ) + { + throw new RuntimeException( + "Tried to read float samples from a non float stream." ); + } + return readFloats( buffer, numFrames ); + } + + /** + * Write 32-bit floating point data to the stream from the array. The data + * should be in the range -1.0 to +1.0. + * + * @param buffer + * @param numFrames + * number of frames to write + * @return true if an output underflow occurred + */ + public boolean write( float[] buffer, int numFrames ) + { + if( outputFormat != PortAudio.FORMAT_FLOAT_32 ) + { + throw new RuntimeException( + "Tried to write float samples to a non float stream." ); + } + return writeFloats( buffer, numFrames ); + } + + private native boolean readShorts( short[] buffer, int numFrames ); + + private native boolean writeShorts( short[] buffer, int numFrames ); + + /** + * Read 16-bit integer data to the stream from the array. + * + * @param buffer + * @param numFrames + * number of frames to write + * @return true if an input overflow occurred + */ + public boolean read( short[] buffer, int numFrames ) + { + if( inputFormat != PortAudio.FORMAT_INT_16 ) + { + throw new RuntimeException( + "Tried to read short samples from a non short stream." ); + } + return readShorts( buffer, numFrames ); + } + + /** + * Write 16-bit integer data to the stream from the array. + * + * @param buffer + * @param numFrames + * number of frames to write + * @return true if an output underflow occurred + */ + public boolean write( short[] buffer, int numFrames ) + { + if( outputFormat != PortAudio.FORMAT_INT_16 ) + { + throw new RuntimeException( + "Tried to write short samples from a non short stream." ); + } + return writeShorts( buffer, numFrames ); + } + + /** + * Atart audio I/O. + */ + public native void start(); + + /** + * Wait for the stream to play all of the data that has been written then + * stop. + */ + public native void stop(); + + /** + * Stop immediately and lose any data that was written but not played. + */ + public native void abort(); + + /** + * Close the stream and zero out the pointer. Do not reference the stream + * after this. + */ + public native void close(); + + public native boolean isStopped(); + + public native boolean isActive(); + + public String toString() + { + return "BlockingStream: streamPtr = " + Long.toHexString( nativeStream ) + + ", inFormat = " + inputFormat + ", outFormat = " + + outputFormat; + } + + /** + * Get audio time related to this stream. Note that it may not start at 0.0. + */ + public native double getTime(); + + private native void getInfo( StreamInfo streamInfo ); + + public StreamInfo getInfo() + { + StreamInfo streamInfo = new StreamInfo(); + getInfo( streamInfo ); + return streamInfo; + } +} diff --git a/extern/portaudio/bindings/java/jportaudio/src/com/portaudio/DeviceInfo.java b/extern/portaudio/bindings/java/jportaudio/src/com/portaudio/DeviceInfo.java new file mode 100644 index 0000000..1c4682e --- /dev/null +++ b/extern/portaudio/bindings/java/jportaudio/src/com/portaudio/DeviceInfo.java @@ -0,0 +1,65 @@ +/* + * Portable Audio I/O Library + * Java Binding for PortAudio + * + * Based on the Open Source API proposed by Ross Bencina + * Copyright (c) 2008 Ross Bencina + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +/** @file + @ingroup bindings_java + + @brief Information about a JPortAudio device. +*/ +package com.portaudio; + +/** + * Equivalent to PaDeviceInfo + * @see PortAudio + * @see HostApiInfo + * @author Phil Burk + * + */ +public class DeviceInfo +{ + public int version; + public String name; + public int hostApi; + public int maxInputChannels; + public int maxOutputChannels; + public double defaultLowInputLatency; + public double defaultHighInputLatency; + public double defaultLowOutputLatency; + public double defaultHighOutputLatency; + public double defaultSampleRate; +} diff --git a/extern/portaudio/bindings/java/jportaudio/src/com/portaudio/HostApiInfo.java b/extern/portaudio/bindings/java/jportaudio/src/com/portaudio/HostApiInfo.java new file mode 100644 index 0000000..dc2cdce --- /dev/null +++ b/extern/portaudio/bindings/java/jportaudio/src/com/portaudio/HostApiInfo.java @@ -0,0 +1,61 @@ +/* + * Portable Audio I/O Library + * Java Binding for PortAudio + * + * Based on the Open Source API proposed by Ross Bencina + * Copyright (c) 2008 Ross Bencina + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +/** @file + @ingroup bindings_java + + @brief Information about a JPortAudio Host API. +*/ +package com.portaudio; + +/** + * Equivalent to PaHostApiInfo + * @see PortAudio + * @see DeviceInfo + * @author Phil Burk + * + */ +public class HostApiInfo +{ + public int version; + public int type; + public String name; + public int deviceCount; + public int defaultInputDevice; + public int defaultOutputDevice; +} diff --git a/extern/portaudio/bindings/java/jportaudio/src/com/portaudio/PortAudio.java b/extern/portaudio/bindings/java/jportaudio/src/com/portaudio/PortAudio.java new file mode 100644 index 0000000..41b3c67 --- /dev/null +++ b/extern/portaudio/bindings/java/jportaudio/src/com/portaudio/PortAudio.java @@ -0,0 +1,261 @@ +/* + * Portable Audio I/O Library + * Java Binding for PortAudio + * + * Based on the Open Source API proposed by Ross Bencina + * Copyright (c) 2008 Ross Bencina + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +/** @file + @ingroup bindings_java + + @brief Java wrapper for the PortAudio API. +*/ +package com.portaudio; + +/** + * Java methods that call PortAudio via JNI. This is a portable audio I/O + * library that can be used as an alternative to JavaSound. + * + * Please see the PortAudio documentation for a full explanation. + * + * http://portaudio.com/docs/ + * http://portaudio.com/docs/v19-doxydocs/portaudio_8h.html + * + * This Java binding does not support audio callbacks because an audio callback + * should never block. Calling into a Java virtual machine might block for + * garbage collection or synchronization. So only the blocking read/write mode + * is supported. + * + * @see BlockingStream + * @see DeviceInfo + * @see HostApiInfo + * @see StreamInfo + * @see StreamParameters + * + * @author Phil Burk + * + */ +public class PortAudio +{ + public final static int FLAG_CLIP_OFF = (1 << 0); + public final static int FLAG_DITHER_OFF = (1 << 1); + + /** Sample Formats */ + public final static int FORMAT_FLOAT_32 = (1 << 0); + public final static int FORMAT_INT_32 = (1 << 1); // not supported + public final static int FORMAT_INT_24 = (1 << 2); // not supported + public final static int FORMAT_INT_16 = (1 << 3); + public final static int FORMAT_INT_8 = (1 << 4); // not supported + public final static int FORMAT_UINT_8 = (1 << 5); // not supported + + /** These HOST_API_TYPES will not change in the future. */ + public final static int HOST_API_TYPE_DEV = 0; + public final static int HOST_API_TYPE_DIRECTSOUND = 1; + public final static int HOST_API_TYPE_MME = 2; + public final static int HOST_API_TYPE_ASIO = 3; + /** Apple Sound Manager. Obsolete. */ + public final static int HOST_API_TYPE_SOUNDMANAGER = 4; + public final static int HOST_API_TYPE_COREAUDIO = 5; + public final static int HOST_API_TYPE_OSS = 7; + public final static int HOST_API_TYPE_ALSA = 8; + public final static int HOST_API_TYPE_AL = 9; + public final static int HOST_API_TYPE_BEOS = 10; + public final static int HOST_API_TYPE_WDMKS = 11; + public final static int HOST_API_TYPE_JACK = 12; + public final static int HOST_API_TYPE_WASAPI = 13; + public final static int HOST_API_TYPE_AUDIOSCIENCE = 14; + public final static int HOST_API_TYPE_COUNT = 15; + + static + { + String os = System.getProperty( "os.name" ).toLowerCase(); + // On Windows we have separate libraries for 32 and 64-bit JVMs. + if( os.indexOf( "win" ) >= 0 ) + { + if( System.getProperty( "os.arch" ).contains( "64" ) ) + { + System.loadLibrary( "jportaudio_x64" ); + } + else + { + System.loadLibrary( "jportaudio_x86" ); + } + } + else + { + System.loadLibrary( "jportaudio" ); + } + System.out.println( "---- JPortAudio version " + getVersion() + ", " + + getVersionText() ); + } + + /** + * @return the release number of the currently running PortAudio build, eg + * 1900. + */ + public native static int getVersion(); + + /** + * @return a textual description of the current PortAudio build, eg + * "PortAudio V19-devel 13 October 2002". + */ + public native static String getVersionText(); + + /** + * Library initialization function - call this before using PortAudio. This + * function initializes internal data structures and prepares underlying + * host APIs for use. With the exception of getVersion(), getVersionText(), + * and getErrorText(), this function MUST be called before using any other + * PortAudio API functions. + */ + public native static void initialize(); + + /** + * Library termination function - call this when finished using PortAudio. + * This function deallocates all resources allocated by PortAudio since it + * was initialized by a call to initialize(). In cases where Pa_Initialise() + * has been called multiple times, each call must be matched with a + * corresponding call to terminate(). The final matching call to terminate() + * will automatically close any PortAudio streams that are still open. + */ + public native static void terminate(); + + /** + * @return the number of available devices. The number of available devices + * may be zero. + */ + public native static int getDeviceCount(); + + private native static void getDeviceInfo( int index, DeviceInfo deviceInfo ); + + /** + * @param index + * A valid device index in the range 0 to (getDeviceCount()-1) + * @return An DeviceInfo structure. + * @throws RuntimeException + * if the device parameter is out of range. + */ + public static DeviceInfo getDeviceInfo( int index ) + { + DeviceInfo deviceInfo = new DeviceInfo(); + getDeviceInfo( index, deviceInfo ); + return deviceInfo; + } + + /** + * @return the number of available host APIs. + */ + public native static int getHostApiCount(); + + private native static void getHostApiInfo( int index, + HostApiInfo hostApiInfo ); + + /** + * @param index + * @return information about the Host API + */ + public static HostApiInfo getHostApiInfo( int index ) + { + HostApiInfo hostApiInfo = new HostApiInfo(); + getHostApiInfo( index, hostApiInfo ); + return hostApiInfo; + } + + /** + * @param hostApiType + * A unique host API identifier, for example + * HOST_API_TYPE_COREAUDIO. + * @return a runtime host API index + */ + public native static int hostApiTypeIdToHostApiIndex( int hostApiType ); + + /** + * @param hostApiIndex + * A valid host API index ranging from 0 to (getHostApiCount()-1) + * @param apiDeviceIndex + * A valid per-host device index in the range 0 to + * (getHostApiInfo(hostApi).deviceCount-1) + * @return standard PortAudio device index + */ + public native static int hostApiDeviceIndexToDeviceIndex( int hostApiIndex, + int apiDeviceIndex ); + + public native static int getDefaultInputDevice(); + + public native static int getDefaultOutputDevice(); + + public native static int getDefaultHostApi(); + + /** + * @param inputStreamParameters + * input description, may be null + * @param outputStreamParameters + * output description, may be null + * @param sampleRate + * typically 44100 or 48000, or maybe 22050, 16000, 8000, 96000 + * @return 0 if supported or a negative error + */ + public native static int isFormatSupported( + StreamParameters inputStreamParameters, + StreamParameters outputStreamParameters, int sampleRate ); + + private native static void openStream( BlockingStream blockingStream, + StreamParameters inputStreamParameters, + StreamParameters outputStreamParameters, int sampleRate, + int framesPerBuffer, int flags ); + + /** + * + * @param inputStreamParameters + * input description, may be null + * @param outputStreamParameters + * output description, may be null + * @param sampleRate + * typically 44100 or 48000, or maybe 22050, 16000, 8000, 96000 + * @param framesPerBuffer + * @param flags + * @return + */ + public static BlockingStream openStream( + StreamParameters inputStreamParameters, + StreamParameters outputStreamParameters, int sampleRate, + int framesPerBuffer, int flags ) + { + BlockingStream blockingStream = new BlockingStream(); + openStream( blockingStream, inputStreamParameters, + outputStreamParameters, sampleRate, framesPerBuffer, flags ); + return blockingStream; + } + +} diff --git a/extern/portaudio/bindings/java/jportaudio/src/com/portaudio/StreamInfo.java b/extern/portaudio/bindings/java/jportaudio/src/com/portaudio/StreamInfo.java new file mode 100644 index 0000000..685f94d --- /dev/null +++ b/extern/portaudio/bindings/java/jportaudio/src/com/portaudio/StreamInfo.java @@ -0,0 +1,60 @@ +/* + * Portable Audio I/O Library + * Java Binding for PortAudio + * + * Based on the Open Source API proposed by Ross Bencina + * Copyright (c) 2008 Ross Bencina + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + + +/** @file + @ingroup bindings_java + + @brief Information about a JPortAudio Stream. +*/ + +package com.portaudio; + +/** + * Equivalent to PaStreamInfo + * @see PortAudio + * @author Phil Burk + * + */ +public class StreamInfo +{ + public int structVersion; + public double outputLatency; + public double inputLatency; + public double sampleRate; +} diff --git a/extern/portaudio/bindings/java/jportaudio/src/com/portaudio/StreamParameters.java b/extern/portaudio/bindings/java/jportaudio/src/com/portaudio/StreamParameters.java new file mode 100644 index 0000000..707dab5 --- /dev/null +++ b/extern/portaudio/bindings/java/jportaudio/src/com/portaudio/StreamParameters.java @@ -0,0 +1,57 @@ +/* + * Portable Audio I/O Library + * Java Binding for PortAudio + * + * Based on the Open Source API proposed by Ross Bencina + * Copyright (c) 2008 Ross Bencina + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +/** @file + @ingroup bindings_java + + @brief Options to use when opening a stream. +*/ +package com.portaudio; +/** + * Equivalent to PaStreamParameters + * @see PortAudio + * @author Phil Burk + * + */ +public class StreamParameters +{ + public int device = 0; + public int channelCount = 2; + public int sampleFormat = PortAudio.FORMAT_FLOAT_32; + public double suggestedLatency = 0.050; +} diff --git a/extern/portaudio/bindings/java/scripts/make_header.bat b/extern/portaudio/bindings/java/scripts/make_header.bat new file mode 100644 index 0000000..3c4f58a --- /dev/null +++ b/extern/portaudio/bindings/java/scripts/make_header.bat @@ -0,0 +1,4 @@ +REM Generate the JNI header file from the Java code for JPortAudio +REM by Phil Burk + +javah -classpath ../jportaudio/bin -d ../c/src com.portaudio.PortAudio com.portaudio.BlockingStream diff --git a/extern/portaudio/clear_gitrevision.sh b/extern/portaudio/clear_gitrevision.sh new file mode 100755 index 0000000..b1b087c --- /dev/null +++ b/extern/portaudio/clear_gitrevision.sh @@ -0,0 +1,12 @@ +#!/bin/bash +# +# Clear the Git commit SHA in the include file. +# This should be run before checking in code to Git. +# +revision_filename=src/common/pa_gitrevision.h + +# Update the include file with the current GIT revision. +echo "#define PA_GIT_REVISION unknown" > ${revision_filename} + +echo ${revision_filename} now contains +cat ${revision_filename} diff --git a/extern/portaudio/cmake_support/FindASIOSDK.cmake b/extern/portaudio/cmake_support/FindASIOSDK.cmake new file mode 100644 index 0000000..55ad33d --- /dev/null +++ b/extern/portaudio/cmake_support/FindASIOSDK.cmake @@ -0,0 +1,41 @@ +# $Id: $ +# +# - Try to find the ASIO SDK +# Once done this will define +# +# ASIOSDK_FOUND - system has ASIO SDK +# ASIOSDK_ROOT_DIR - path to the ASIO SDK base directory +# ASIOSDK_INCLUDE_DIR - the ASIO SDK include directory + +if(WIN32) +else(WIN32) + message(FATAL_ERROR "FindASIOSDK.cmake: Unsupported platform ${CMAKE_SYSTEM_NAME}" ) +endif(WIN32) + +file(GLOB results "${CMAKE_CURRENT_SOURCE_DIR}/../as*") +foreach(f ${results}) + if(IS_DIRECTORY ${f}) + set(ASIOSDK_PATH_HINT ${ASIOSDK_PATH_HINT} ${f}) + endif() +endforeach() + +find_path(ASIOSDK_ROOT_DIR + common/asio.h + HINTS + ${ASIOSDK_PATH_HINT} +) + +find_path(ASIOSDK_INCLUDE_DIR + asio.h + PATHS + ${ASIOSDK_ROOT_DIR}/common +) + +# handle the QUIETLY and REQUIRED arguments and set ASIOSDK_FOUND to TRUE if +# all listed variables are TRUE +INCLUDE(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(ASIOSDK DEFAULT_MSG ASIOSDK_ROOT_DIR ASIOSDK_INCLUDE_DIR) + +MARK_AS_ADVANCED( + ASIOSDK_ROOT_DIR ASIOSDK_INCLUDE_DIR +) diff --git a/extern/portaudio/cmake_support/FindJack.cmake b/extern/portaudio/cmake_support/FindJack.cmake new file mode 100644 index 0000000..96e0b50 --- /dev/null +++ b/extern/portaudio/cmake_support/FindJack.cmake @@ -0,0 +1,41 @@ +# - Try to find jack +# Once done this will define +# JACK_FOUND - System has jack +# JACK_INCLUDE_DIRS - The jack include directories +# JACK_LIBRARIES - The libraries needed to use jack +# JACK_DEFINITIONS - Compiler switches required for using jack + +if (JACK_LIBRARIES AND JACK_INCLUDE_DIRS) + + # in cache already + set(JACK_FOUND TRUE) + +else (JACK_LIBRARIES AND JACK_INCLUDE_DIRS) + + set(JACK_DEFINITIONS "") + + # Look for pkg-config and use it (if available) to find package + find_package(PkgConfig QUIET) + if (PKG_CONFIG_FOUND) + pkg_search_module(JACK QUIET jack) + endif (PKG_CONFIG_FOUND) + + if (NOT JACK_FOUND) + + find_path(JACK_INCLUDE_DIR jack/jack.h HINTS ${JACK_INCLUDEDIR} ${JACK_INCLUDE_DIRS} PATH_SUFFIXES jack) + find_library(JACK_LIBRARY NAMES jack HINTS ${JACK_LIBDIR} ${JACK_LIBRARY_DIRS}) + + set(JACK_LIBRARIES ${JACK_LIBRARY}) + set(JACK_INCLUDE_DIRS ${JACK_INCLUDE_DIR}) + + include(FindPackageHandleStandardArgs) + + # Set JACK_FOUND if the library and include paths were found + find_package_handle_standard_args(jack DEFAULT_MSG JACK_LIBRARY JACK_INCLUDE_DIR) + + # Don't show include/library paths in cmake GUI + mark_as_advanced(JACK_INCLUDE_DIR JACK_LIBRARY) + + endif (NOT JACK_FOUND) + +endif (JACK_LIBRARIES AND JACK_INCLUDE_DIRS) diff --git a/extern/portaudio/cmake_support/cmake_uninstall.cmake.in b/extern/portaudio/cmake_support/cmake_uninstall.cmake.in new file mode 100644 index 0000000..2037e36 --- /dev/null +++ b/extern/portaudio/cmake_support/cmake_uninstall.cmake.in @@ -0,0 +1,21 @@ +if(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") + message(FATAL_ERROR "Cannot find install manifest: @CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") +endif(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") + +file(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files) +string(REGEX REPLACE "\n" ";" files "${files}") +foreach(file ${files}) + message(STATUS "Uninstalling $ENV{DESTDIR}${file}") + if(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") + exec_program( + "@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\"" + OUTPUT_VARIABLE rm_out + RETURN_VALUE rm_retval + ) + if(NOT "${rm_retval}" STREQUAL 0) + message(FATAL_ERROR "Problem when removing $ENV{DESTDIR}${file}") + endif(NOT "${rm_retval}" STREQUAL 0) + else(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") + message(STATUS "File $ENV{DESTDIR}${file} does not exist.") + endif(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") +endforeach(file) diff --git a/extern/portaudio/cmake_support/options_cmake.h.in b/extern/portaudio/cmake_support/options_cmake.h.in new file mode 100644 index 0000000..cd07605 --- /dev/null +++ b/extern/portaudio/cmake_support/options_cmake.h.in @@ -0,0 +1,31 @@ +/* $Id: $ + + !!! @GENERATED_MESSAGE@ !!! + + Header file configured by CMake to convert CMake options/vars to macros. It is done this way because if set via + preprocessor options, MSVC f.i. has no way of knowing when an option (or var) changes as there is no dependency chain. + + The generated "options_cmake.h" should be included like so: + + #ifdef PORTAUDIO_CMAKE_GENERATED + #include "options_cmake.h" + #endif + + so that non-CMake build environments are left intact. + + Source template: cmake_support/options_cmake.h.in +*/ + +#ifdef _WIN32 +#if defined(PA_USE_ASIO) || defined(PA_USE_DS) || defined(PA_USE_WMME) || defined(PA_USE_WASAPI) || defined(PA_USE_WDMKS) +#error "This header needs to be included before pa_hostapi.h!!" +#endif + +#cmakedefine01 PA_USE_ASIO +#cmakedefine01 PA_USE_DS +#cmakedefine01 PA_USE_WMME +#cmakedefine01 PA_USE_WASAPI +#cmakedefine01 PA_USE_WDMKS +#else +#error "Platform currently not supported by CMake script" +#endif diff --git a/extern/portaudio/cmake_support/portaudio-2.0.pc.in b/extern/portaudio/cmake_support/portaudio-2.0.pc.in new file mode 100644 index 0000000..738803d --- /dev/null +++ b/extern/portaudio/cmake_support/portaudio-2.0.pc.in @@ -0,0 +1,12 @@ +prefix=@CMAKE_INSTALL_PREFIX@ +exec_prefix=${prefix} +libdir=${prefix}/lib +includedir=${prefix}/include + +Name: PortAudio +Description: Portable audio I/O +Requires: +Version: @PA_PKGCONFIG_VERSION@ + +Libs: -L${libdir} -lportaudio @PA_PKGCONFIG_LDFLAGS@ +Cflags: -I${includedir} @PA_PKGCONFIG_CFLAGS@ diff --git a/extern/portaudio/cmake_support/portaudioConfig.cmake.in b/extern/portaudio/cmake_support/portaudioConfig.cmake.in new file mode 100644 index 0000000..cacc476 --- /dev/null +++ b/extern/portaudio/cmake_support/portaudioConfig.cmake.in @@ -0,0 +1 @@ +include("${CMAKE_CURRENT_LIST_DIR}/portaudioTargets.cmake") diff --git a/extern/portaudio/cmake_support/template_portaudio.def b/extern/portaudio/cmake_support/template_portaudio.def new file mode 100644 index 0000000..d05da59 --- /dev/null +++ b/extern/portaudio/cmake_support/template_portaudio.def @@ -0,0 +1,53 @@ +; $Id: $ +; +; !!! @GENERATED_MESSAGE@ !!! +EXPORTS + +; +Pa_GetVersion @1 +Pa_GetVersionText @2 +Pa_GetErrorText @3 +Pa_Initialize @4 +Pa_Terminate @5 +Pa_GetHostApiCount @6 +Pa_GetDefaultHostApi @7 +Pa_GetHostApiInfo @8 +Pa_HostApiTypeIdToHostApiIndex @9 +Pa_HostApiDeviceIndexToDeviceIndex @10 +Pa_GetLastHostErrorInfo @11 +Pa_GetDeviceCount @12 +Pa_GetDefaultInputDevice @13 +Pa_GetDefaultOutputDevice @14 +Pa_GetDeviceInfo @15 +Pa_IsFormatSupported @16 +Pa_OpenStream @17 +Pa_OpenDefaultStream @18 +Pa_CloseStream @19 +Pa_SetStreamFinishedCallback @20 +Pa_StartStream @21 +Pa_StopStream @22 +Pa_AbortStream @23 +Pa_IsStreamStopped @24 +Pa_IsStreamActive @25 +Pa_GetStreamInfo @26 +Pa_GetStreamTime @27 +Pa_GetStreamCpuLoad @28 +Pa_ReadStream @29 +Pa_WriteStream @30 +Pa_GetStreamReadAvailable @31 +Pa_GetStreamWriteAvailable @32 +Pa_GetSampleSize @33 +Pa_Sleep @34 +@DEF_EXCLUDE_ASIO_SYMBOLS@PaAsio_GetAvailableBufferSizes @50 +@DEF_EXCLUDE_ASIO_SYMBOLS@PaAsio_ShowControlPanel @51 +@DEF_EXCLUDE_X86_PLAIN_CONVERTERS@PaUtil_InitializeX86PlainConverters @52 +@DEF_EXCLUDE_ASIO_SYMBOLS@PaAsio_GetInputChannelName @53 +@DEF_EXCLUDE_ASIO_SYMBOLS@PaAsio_GetOutputChannelName @54 +PaUtil_SetDebugPrintFunction @55 +@DEF_EXCLUDE_WASAPI_SYMBOLS@PaWasapi_GetDeviceDefaultFormat @56 +@DEF_EXCLUDE_WASAPI_SYMBOLS@PaWasapi_GetDeviceRole @57 +@DEF_EXCLUDE_WASAPI_SYMBOLS@PaWasapi_ThreadPriorityBoost @58 +@DEF_EXCLUDE_WASAPI_SYMBOLS@PaWasapi_ThreadPriorityRevert @59 +@DEF_EXCLUDE_WASAPI_SYMBOLS@PaWasapi_GetFramesPerHostBuffer @60 +@DEF_EXCLUDE_WASAPI_SYMBOLS@PaWasapi_GetJackDescription @61 +@DEF_EXCLUDE_WASAPI_SYMBOLS@PaWasapi_GetJackCount @62 diff --git a/extern/portaudio/config.guess b/extern/portaudio/config.guess new file mode 100755 index 0000000..b79252d --- /dev/null +++ b/extern/portaudio/config.guess @@ -0,0 +1,1558 @@ +#! /bin/sh +# Attempt to guess a canonical system name. +# Copyright 1992-2013 Free Software Foundation, Inc. + +timestamp='2013-06-10' + +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, see . +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that +# program. This Exception is an additional permission under section 7 +# of the GNU General Public License, version 3 ("GPLv3"). +# +# Originally written by Per Bothner. +# +# You can get the latest version of this script from: +# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD +# +# Please send patches with a ChangeLog entry to config-patches@gnu.org. + + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] + +Output the configuration name of the system \`$me' is run on. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.guess ($timestamp) + +Originally written by Per Bothner. +Copyright 1992-2013 Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" >&2 + exit 1 ;; + * ) + break ;; + esac +done + +if test $# != 0; then + echo "$me: too many arguments$help" >&2 + exit 1 +fi + +trap 'exit 1' 1 2 15 + +# CC_FOR_BUILD -- compiler used by this script. Note that the use of a +# compiler to aid in system detection is discouraged as it requires +# temporary files to be created and, as you can see below, it is a +# headache to deal with in a portable fashion. + +# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still +# use `HOST_CC' if defined, but it is deprecated. + +# Portable tmp directory creation inspired by the Autoconf team. + +set_cc_for_build=' +trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; +trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; +: ${TMPDIR=/tmp} ; + { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || + { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || + { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || + { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; +dummy=$tmp/dummy ; +tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; +case $CC_FOR_BUILD,$HOST_CC,$CC in + ,,) echo "int x;" > $dummy.c ; + for c in cc gcc c89 c99 ; do + if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then + CC_FOR_BUILD="$c"; break ; + fi ; + done ; + if test x"$CC_FOR_BUILD" = x ; then + CC_FOR_BUILD=no_compiler_found ; + fi + ;; + ,,*) CC_FOR_BUILD=$CC ;; + ,*,*) CC_FOR_BUILD=$HOST_CC ;; +esac ; set_cc_for_build= ;' + +# This is needed to find uname on a Pyramid OSx when run in the BSD universe. +# (ghazi@noc.rutgers.edu 1994-08-24) +if (test -f /.attbin/uname) >/dev/null 2>&1 ; then + PATH=$PATH:/.attbin ; export PATH +fi + +UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown +UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown +UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown +UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown + +case "${UNAME_SYSTEM}" in +Linux|GNU|GNU/*) + # If the system lacks a compiler, then just pick glibc. + # We could probably try harder. + LIBC=gnu + + eval $set_cc_for_build + cat <<-EOF > $dummy.c + #include + #if defined(__UCLIBC__) + LIBC=uclibc + #elif defined(__dietlibc__) + LIBC=dietlibc + #else + LIBC=gnu + #endif + EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'` + ;; +esac + +# Note: order is significant - the case branches are not exclusive. + +case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in + *:NetBSD:*:*) + # NetBSD (nbsd) targets should (where applicable) match one or + # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*, + # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently + # switched to ELF, *-*-netbsd* would select the old + # object file format. This provides both forward + # compatibility and a consistent mechanism for selecting the + # object file format. + # + # Note: NetBSD doesn't particularly care about the vendor + # portion of the name. We always set it to "unknown". + sysctl="sysctl -n hw.machine_arch" + UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ + /usr/sbin/$sysctl 2>/dev/null || echo unknown)` + case "${UNAME_MACHINE_ARCH}" in + armeb) machine=armeb-unknown ;; + arm*) machine=arm-unknown ;; + sh3el) machine=shl-unknown ;; + sh3eb) machine=sh-unknown ;; + sh5el) machine=sh5le-unknown ;; + *) machine=${UNAME_MACHINE_ARCH}-unknown ;; + esac + # The Operating System including object format, if it has switched + # to ELF recently, or will in the future. + case "${UNAME_MACHINE_ARCH}" in + arm*|i386|m68k|ns32k|sh3*|sparc|vax) + eval $set_cc_for_build + if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ELF__ + then + # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). + # Return netbsd for either. FIX? + os=netbsd + else + os=netbsdelf + fi + ;; + *) + os=netbsd + ;; + esac + # The OS release + # Debian GNU/NetBSD machines have a different userland, and + # thus, need a distinct triplet. However, they do not need + # kernel version information, so it can be replaced with a + # suitable tag, in the style of linux-gnu. + case "${UNAME_VERSION}" in + Debian*) + release='-gnu' + ;; + *) + release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + ;; + esac + # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: + # contains redundant information, the shorter form: + # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. + echo "${machine}-${os}${release}" + exit ;; + *:Bitrig:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'` + echo ${UNAME_MACHINE_ARCH}-unknown-bitrig${UNAME_RELEASE} + exit ;; + *:OpenBSD:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` + echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} + exit ;; + *:ekkoBSD:*:*) + echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} + exit ;; + *:SolidBSD:*:*) + echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} + exit ;; + macppc:MirBSD:*:*) + echo powerpc-unknown-mirbsd${UNAME_RELEASE} + exit ;; + *:MirBSD:*:*) + echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} + exit ;; + alpha:OSF1:*:*) + case $UNAME_RELEASE in + *4.0) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` + ;; + *5.*) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` + ;; + esac + # According to Compaq, /usr/sbin/psrinfo has been available on + # OSF/1 and Tru64 systems produced since 1995. I hope that + # covers most systems running today. This code pipes the CPU + # types through head -n 1, so we only detect the type of CPU 0. + ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` + case "$ALPHA_CPU_TYPE" in + "EV4 (21064)") + UNAME_MACHINE="alpha" ;; + "EV4.5 (21064)") + UNAME_MACHINE="alpha" ;; + "LCA4 (21066/21068)") + UNAME_MACHINE="alpha" ;; + "EV5 (21164)") + UNAME_MACHINE="alphaev5" ;; + "EV5.6 (21164A)") + UNAME_MACHINE="alphaev56" ;; + "EV5.6 (21164PC)") + UNAME_MACHINE="alphapca56" ;; + "EV5.7 (21164PC)") + UNAME_MACHINE="alphapca57" ;; + "EV6 (21264)") + UNAME_MACHINE="alphaev6" ;; + "EV6.7 (21264A)") + UNAME_MACHINE="alphaev67" ;; + "EV6.8CB (21264C)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8AL (21264B)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8CX (21264D)") + UNAME_MACHINE="alphaev68" ;; + "EV6.9A (21264/EV69A)") + UNAME_MACHINE="alphaev69" ;; + "EV7 (21364)") + UNAME_MACHINE="alphaev7" ;; + "EV7.9 (21364A)") + UNAME_MACHINE="alphaev79" ;; + esac + # A Pn.n version is a patched version. + # A Vn.n version is a released version. + # A Tn.n version is a released field test version. + # A Xn.n version is an unreleased experimental baselevel. + # 1.2 uses "1.2" for uname -r. + echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + # Reset EXIT trap before exiting to avoid spurious non-zero exit code. + exitcode=$? + trap '' 0 + exit $exitcode ;; + Alpha\ *:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # Should we change UNAME_MACHINE based on the output of uname instead + # of the specific Alpha model? + echo alpha-pc-interix + exit ;; + 21064:Windows_NT:50:3) + echo alpha-dec-winnt3.5 + exit ;; + Amiga*:UNIX_System_V:4.0:*) + echo m68k-unknown-sysv4 + exit ;; + *:[Aa]miga[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-amigaos + exit ;; + *:[Mm]orph[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-morphos + exit ;; + *:OS/390:*:*) + echo i370-ibm-openedition + exit ;; + *:z/VM:*:*) + echo s390-ibm-zvmoe + exit ;; + *:OS400:*:*) + echo powerpc-ibm-os400 + exit ;; + arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) + echo arm-acorn-riscix${UNAME_RELEASE} + exit ;; + arm*:riscos:*:*|arm*:RISCOS:*:*) + echo arm-unknown-riscos + exit ;; + SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) + echo hppa1.1-hitachi-hiuxmpp + exit ;; + Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) + # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. + if test "`(/bin/universe) 2>/dev/null`" = att ; then + echo pyramid-pyramid-sysv3 + else + echo pyramid-pyramid-bsd + fi + exit ;; + NILE*:*:*:dcosx) + echo pyramid-pyramid-svr4 + exit ;; + DRS?6000:unix:4.0:6*) + echo sparc-icl-nx6 + exit ;; + DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) + case `/usr/bin/uname -p` in + sparc) echo sparc-icl-nx7; exit ;; + esac ;; + s390x:SunOS:*:*) + echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4H:SunOS:5.*:*) + echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) + echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) + echo i386-pc-auroraux${UNAME_RELEASE} + exit ;; + i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) + eval $set_cc_for_build + SUN_ARCH="i386" + # If there is a compiler, see if it is configured for 64-bit objects. + # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. + # This test works for both compilers. + if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then + if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ + (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_64BIT_ARCH >/dev/null + then + SUN_ARCH="x86_64" + fi + fi + echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:6*:*) + # According to config.sub, this is the proper way to canonicalize + # SunOS6. Hard to guess exactly what SunOS6 will be like, but + # it's likely to be more like Solaris than SunOS4. + echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:*:*) + case "`/usr/bin/arch -k`" in + Series*|S4*) + UNAME_RELEASE=`uname -v` + ;; + esac + # Japanese Language versions have a version number like `4.1.3-JL'. + echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` + exit ;; + sun3*:SunOS:*:*) + echo m68k-sun-sunos${UNAME_RELEASE} + exit ;; + sun*:*:4.2BSD:*) + UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` + test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 + case "`/bin/arch`" in + sun3) + echo m68k-sun-sunos${UNAME_RELEASE} + ;; + sun4) + echo sparc-sun-sunos${UNAME_RELEASE} + ;; + esac + exit ;; + aushp:SunOS:*:*) + echo sparc-auspex-sunos${UNAME_RELEASE} + exit ;; + # The situation for MiNT is a little confusing. The machine name + # can be virtually everything (everything which is not + # "atarist" or "atariste" at least should have a processor + # > m68000). The system name ranges from "MiNT" over "FreeMiNT" + # to the lowercase version "mint" (or "freemint"). Finally + # the system name "TOS" denotes a system which is actually not + # MiNT. But MiNT is downward compatible to TOS, so this should + # be no problem. + atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) + echo m68k-milan-mint${UNAME_RELEASE} + exit ;; + hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) + echo m68k-hades-mint${UNAME_RELEASE} + exit ;; + *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) + echo m68k-unknown-mint${UNAME_RELEASE} + exit ;; + m68k:machten:*:*) + echo m68k-apple-machten${UNAME_RELEASE} + exit ;; + powerpc:machten:*:*) + echo powerpc-apple-machten${UNAME_RELEASE} + exit ;; + RISC*:Mach:*:*) + echo mips-dec-mach_bsd4.3 + exit ;; + RISC*:ULTRIX:*:*) + echo mips-dec-ultrix${UNAME_RELEASE} + exit ;; + VAX*:ULTRIX*:*:*) + echo vax-dec-ultrix${UNAME_RELEASE} + exit ;; + 2020:CLIX:*:* | 2430:CLIX:*:*) + echo clipper-intergraph-clix${UNAME_RELEASE} + exit ;; + mips:*:*:UMIPS | mips:*:*:RISCos) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c +#ifdef __cplusplus +#include /* for printf() prototype */ + int main (int argc, char *argv[]) { +#else + int main (argc, argv) int argc; char *argv[]; { +#endif + #if defined (host_mips) && defined (MIPSEB) + #if defined (SYSTYPE_SYSV) + printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_SVR4) + printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) + printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); + #endif + #endif + exit (-1); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && + dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && + SYSTEM_NAME=`$dummy $dummyarg` && + { echo "$SYSTEM_NAME"; exit; } + echo mips-mips-riscos${UNAME_RELEASE} + exit ;; + Motorola:PowerMAX_OS:*:*) + echo powerpc-motorola-powermax + exit ;; + Motorola:*:4.3:PL8-*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:Power_UNIX:*:*) + echo powerpc-harris-powerunix + exit ;; + m88k:CX/UX:7*:*) + echo m88k-harris-cxux7 + exit ;; + m88k:*:4*:R4*) + echo m88k-motorola-sysv4 + exit ;; + m88k:*:3*:R3*) + echo m88k-motorola-sysv3 + exit ;; + AViiON:dgux:*:*) + # DG/UX returns AViiON for all architectures + UNAME_PROCESSOR=`/usr/bin/uname -p` + if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] + then + if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ + [ ${TARGET_BINARY_INTERFACE}x = x ] + then + echo m88k-dg-dgux${UNAME_RELEASE} + else + echo m88k-dg-dguxbcs${UNAME_RELEASE} + fi + else + echo i586-dg-dgux${UNAME_RELEASE} + fi + exit ;; + M88*:DolphinOS:*:*) # DolphinOS (SVR3) + echo m88k-dolphin-sysv3 + exit ;; + M88*:*:R3*:*) + # Delta 88k system running SVR3 + echo m88k-motorola-sysv3 + exit ;; + XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) + echo m88k-tektronix-sysv3 + exit ;; + Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) + echo m68k-tektronix-bsd + exit ;; + *:IRIX*:*:*) + echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` + exit ;; + ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. + echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id + exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' + i*86:AIX:*:*) + echo i386-ibm-aix + exit ;; + ia64:AIX:*:*) + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} + exit ;; + *:AIX:2:3) + if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + + main() + { + if (!__power_pc()) + exit(1); + puts("powerpc-ibm-aix3.2.5"); + exit(0); + } +EOF + if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` + then + echo "$SYSTEM_NAME" + else + echo rs6000-ibm-aix3.2.5 + fi + elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then + echo rs6000-ibm-aix3.2.4 + else + echo rs6000-ibm-aix3.2 + fi + exit ;; + *:AIX:*:[4567]) + IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` + if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then + IBM_ARCH=rs6000 + else + IBM_ARCH=powerpc + fi + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${IBM_ARCH}-ibm-aix${IBM_REV} + exit ;; + *:AIX:*:*) + echo rs6000-ibm-aix + exit ;; + ibmrt:4.4BSD:*|romp-ibm:BSD:*) + echo romp-ibm-bsd4.4 + exit ;; + ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and + echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to + exit ;; # report: romp-ibm BSD 4.3 + *:BOSX:*:*) + echo rs6000-bull-bosx + exit ;; + DPX/2?00:B.O.S.:*:*) + echo m68k-bull-sysv3 + exit ;; + 9000/[34]??:4.3bsd:1.*:*) + echo m68k-hp-bsd + exit ;; + hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) + echo m68k-hp-bsd4.4 + exit ;; + 9000/[34678]??:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + case "${UNAME_MACHINE}" in + 9000/31? ) HP_ARCH=m68000 ;; + 9000/[34]?? ) HP_ARCH=m68k ;; + 9000/[678][0-9][0-9]) + if [ -x /usr/bin/getconf ]; then + sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` + sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` + case "${sc_cpu_version}" in + 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 + 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 + 532) # CPU_PA_RISC2_0 + case "${sc_kernel_bits}" in + 32) HP_ARCH="hppa2.0n" ;; + 64) HP_ARCH="hppa2.0w" ;; + '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 + esac ;; + esac + fi + if [ "${HP_ARCH}" = "" ]; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + + #define _HPUX_SOURCE + #include + #include + + int main () + { + #if defined(_SC_KERNEL_BITS) + long bits = sysconf(_SC_KERNEL_BITS); + #endif + long cpu = sysconf (_SC_CPU_VERSION); + + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1"); break; + case CPU_PA_RISC2_0: + #if defined(_SC_KERNEL_BITS) + switch (bits) + { + case 64: puts ("hppa2.0w"); break; + case 32: puts ("hppa2.0n"); break; + default: puts ("hppa2.0"); break; + } break; + #else /* !defined(_SC_KERNEL_BITS) */ + puts ("hppa2.0"); break; + #endif + default: puts ("hppa1.0"); break; + } + exit (0); + } +EOF + (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` + test -z "$HP_ARCH" && HP_ARCH=hppa + fi ;; + esac + if [ ${HP_ARCH} = "hppa2.0w" ] + then + eval $set_cc_for_build + + # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating + # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler + # generating 64-bit code. GNU and HP use different nomenclature: + # + # $ CC_FOR_BUILD=cc ./config.guess + # => hppa2.0w-hp-hpux11.23 + # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess + # => hppa64-hp-hpux11.23 + + if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | + grep -q __LP64__ + then + HP_ARCH="hppa2.0w" + else + HP_ARCH="hppa64" + fi + fi + echo ${HP_ARCH}-hp-hpux${HPUX_REV} + exit ;; + ia64:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + echo ia64-hp-hpux${HPUX_REV} + exit ;; + 3050*:HI-UX:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + int + main () + { + long cpu = sysconf (_SC_CPU_VERSION); + /* The order matters, because CPU_IS_HP_MC68K erroneously returns + true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct + results, however. */ + if (CPU_IS_PA_RISC (cpu)) + { + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; + case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; + default: puts ("hppa-hitachi-hiuxwe2"); break; + } + } + else if (CPU_IS_HP_MC68K (cpu)) + puts ("m68k-hitachi-hiuxwe2"); + else puts ("unknown-hitachi-hiuxwe2"); + exit (0); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && + { echo "$SYSTEM_NAME"; exit; } + echo unknown-hitachi-hiuxwe2 + exit ;; + 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) + echo hppa1.1-hp-bsd + exit ;; + 9000/8??:4.3bsd:*:*) + echo hppa1.0-hp-bsd + exit ;; + *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) + echo hppa1.0-hp-mpeix + exit ;; + hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) + echo hppa1.1-hp-osf + exit ;; + hp8??:OSF1:*:*) + echo hppa1.0-hp-osf + exit ;; + i*86:OSF1:*:*) + if [ -x /usr/sbin/sysversion ] ; then + echo ${UNAME_MACHINE}-unknown-osf1mk + else + echo ${UNAME_MACHINE}-unknown-osf1 + fi + exit ;; + parisc*:Lites*:*:*) + echo hppa1.1-hp-lites + exit ;; + C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) + echo c1-convex-bsd + exit ;; + C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit ;; + C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) + echo c34-convex-bsd + exit ;; + C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) + echo c38-convex-bsd + exit ;; + C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) + echo c4-convex-bsd + exit ;; + CRAY*Y-MP:*:*:*) + echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*[A-Z]90:*:*:*) + echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ + | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ + -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ + -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*TS:*:*:*) + echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*T3E:*:*:*) + echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*SV1:*:*:*) + echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + *:UNICOS/mp:*:*) + echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) + FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` + echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + 5000:UNIX_System_V:4.*:*) + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` + echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) + echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} + exit ;; + sparc*:BSD/OS:*:*) + echo sparc-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:BSD/OS:*:*) + echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:FreeBSD:*:*) + UNAME_PROCESSOR=`/usr/bin/uname -p` + case ${UNAME_PROCESSOR} in + amd64) + echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + *) + echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + esac + exit ;; + i*:CYGWIN*:*) + echo ${UNAME_MACHINE}-pc-cygwin + exit ;; + *:MINGW64*:*) + echo ${UNAME_MACHINE}-pc-mingw64 + exit ;; + *:MINGW*:*) + echo ${UNAME_MACHINE}-pc-mingw32 + exit ;; + i*:MSYS*:*) + echo ${UNAME_MACHINE}-pc-msys + exit ;; + i*:windows32*:*) + # uname -m includes "-pc" on this system. + echo ${UNAME_MACHINE}-mingw32 + exit ;; + i*:PW*:*) + echo ${UNAME_MACHINE}-pc-pw32 + exit ;; + *:Interix*:*) + case ${UNAME_MACHINE} in + x86) + echo i586-pc-interix${UNAME_RELEASE} + exit ;; + authenticamd | genuineintel | EM64T) + echo x86_64-unknown-interix${UNAME_RELEASE} + exit ;; + IA64) + echo ia64-unknown-interix${UNAME_RELEASE} + exit ;; + esac ;; + [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) + echo i${UNAME_MACHINE}-pc-mks + exit ;; + 8664:Windows_NT:*) + echo x86_64-pc-mks + exit ;; + i*:Windows_NT*:* | Pentium*:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we + # UNAME_MACHINE based on the output of uname instead of i386? + echo i586-pc-interix + exit ;; + i*:UWIN*:*) + echo ${UNAME_MACHINE}-pc-uwin + exit ;; + amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) + echo x86_64-unknown-cygwin + exit ;; + p*:CYGWIN*:*) + echo powerpcle-unknown-cygwin + exit ;; + prep*:SunOS:5.*:*) + echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + *:GNU:*:*) + # the GNU system + echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-${LIBC}`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` + exit ;; + *:GNU/*:*:*) + # other systems with GNU libc and userland + echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC} + exit ;; + i*86:Minix:*:*) + echo ${UNAME_MACHINE}-pc-minix + exit ;; + aarch64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + aarch64_be:Linux:*:*) + UNAME_MACHINE=aarch64_be + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + alpha:Linux:*:*) + case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in + EV5) UNAME_MACHINE=alphaev5 ;; + EV56) UNAME_MACHINE=alphaev56 ;; + PCA56) UNAME_MACHINE=alphapca56 ;; + PCA57) UNAME_MACHINE=alphapca56 ;; + EV6) UNAME_MACHINE=alphaev6 ;; + EV67) UNAME_MACHINE=alphaev67 ;; + EV68*) UNAME_MACHINE=alphaev68 ;; + esac + objdump --private-headers /bin/sh | grep -q ld.so.1 + if test "$?" = 0 ; then LIBC="gnulibc1" ; fi + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + arc:Linux:*:* | arceb:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + arm*:Linux:*:*) + eval $set_cc_for_build + if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ARM_EABI__ + then + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + else + if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ARM_PCS_VFP + then + echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabi + else + echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabihf + fi + fi + exit ;; + avr32*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + cris:Linux:*:*) + echo ${UNAME_MACHINE}-axis-linux-${LIBC} + exit ;; + crisv32:Linux:*:*) + echo ${UNAME_MACHINE}-axis-linux-${LIBC} + exit ;; + frv:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + hexagon:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + i*86:Linux:*:*) + echo ${UNAME_MACHINE}-pc-linux-${LIBC} + exit ;; + ia64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + m32r*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + m68*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + mips:Linux:*:* | mips64:Linux:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #undef CPU + #undef ${UNAME_MACHINE} + #undef ${UNAME_MACHINE}el + #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) + CPU=${UNAME_MACHINE}el + #else + #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) + CPU=${UNAME_MACHINE} + #else + CPU= + #endif + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'` + test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; } + ;; + or1k:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + or32:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + padre:Linux:*:*) + echo sparc-unknown-linux-${LIBC} + exit ;; + parisc64:Linux:*:* | hppa64:Linux:*:*) + echo hppa64-unknown-linux-${LIBC} + exit ;; + parisc:Linux:*:* | hppa:Linux:*:*) + # Look for CPU level + case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in + PA7*) echo hppa1.1-unknown-linux-${LIBC} ;; + PA8*) echo hppa2.0-unknown-linux-${LIBC} ;; + *) echo hppa-unknown-linux-${LIBC} ;; + esac + exit ;; + ppc64:Linux:*:*) + echo powerpc64-unknown-linux-${LIBC} + exit ;; + ppc:Linux:*:*) + echo powerpc-unknown-linux-${LIBC} + exit ;; + ppc64le:Linux:*:*) + echo powerpc64le-unknown-linux-${LIBC} + exit ;; + ppcle:Linux:*:*) + echo powerpcle-unknown-linux-${LIBC} + exit ;; + s390:Linux:*:* | s390x:Linux:*:*) + echo ${UNAME_MACHINE}-ibm-linux-${LIBC} + exit ;; + sh64*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + sh*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + sparc:Linux:*:* | sparc64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + tile*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + vax:Linux:*:*) + echo ${UNAME_MACHINE}-dec-linux-${LIBC} + exit ;; + x86_64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + xtensa*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + i*86:DYNIX/ptx:4*:*) + # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. + # earlier versions are messed up and put the nodename in both + # sysname and nodename. + echo i386-sequent-sysv4 + exit ;; + i*86:UNIX_SV:4.2MP:2.*) + # Unixware is an offshoot of SVR4, but it has its own version + # number series starting with 2... + # I am not positive that other SVR4 systems won't match this, + # I just have to hope. -- rms. + # Use sysv4.2uw... so that sysv4* matches it. + echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} + exit ;; + i*86:OS/2:*:*) + # If we were able to find `uname', then EMX Unix compatibility + # is probably installed. + echo ${UNAME_MACHINE}-pc-os2-emx + exit ;; + i*86:XTS-300:*:STOP) + echo ${UNAME_MACHINE}-unknown-stop + exit ;; + i*86:atheos:*:*) + echo ${UNAME_MACHINE}-unknown-atheos + exit ;; + i*86:syllable:*:*) + echo ${UNAME_MACHINE}-pc-syllable + exit ;; + i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) + echo i386-unknown-lynxos${UNAME_RELEASE} + exit ;; + i*86:*DOS:*:*) + echo ${UNAME_MACHINE}-pc-msdosdjgpp + exit ;; + i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) + UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` + if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then + echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} + else + echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} + fi + exit ;; + i*86:*:5:[678]*) + # UnixWare 7.x, OpenUNIX and OpenServer 6. + case `/bin/uname -X | grep "^Machine"` in + *486*) UNAME_MACHINE=i486 ;; + *Pentium) UNAME_MACHINE=i586 ;; + *Pent*|*Celeron) UNAME_MACHINE=i686 ;; + esac + echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} + exit ;; + i*86:*:3.2:*) + if test -f /usr/options/cb.name; then + UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then + UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` + (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 + (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ + && UNAME_MACHINE=i586 + (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ + && UNAME_MACHINE=i686 + (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ + && UNAME_MACHINE=i686 + echo ${UNAME_MACHINE}-pc-sco$UNAME_REL + else + echo ${UNAME_MACHINE}-pc-sysv32 + fi + exit ;; + pc:*:*:*) + # Left here for compatibility: + # uname -m prints for DJGPP always 'pc', but it prints nothing about + # the processor, so we play safe by assuming i586. + # Note: whatever this is, it MUST be the same as what config.sub + # prints for the "djgpp" host, or else GDB configury will decide that + # this is a cross-build. + echo i586-pc-msdosdjgpp + exit ;; + Intel:Mach:3*:*) + echo i386-pc-mach3 + exit ;; + paragon:*:*:*) + echo i860-intel-osf1 + exit ;; + i860:*:4.*:*) # i860-SVR4 + if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then + echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 + else # Add other i860-SVR4 vendors below as they are discovered. + echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 + fi + exit ;; + mini*:CTIX:SYS*5:*) + # "miniframe" + echo m68010-convergent-sysv + exit ;; + mc68k:UNIX:SYSTEM5:3.51m) + echo m68k-convergent-sysv + exit ;; + M680?0:D-NIX:5.3:*) + echo m68k-diab-dnix + exit ;; + M68*:*:R3V[5678]*:*) + test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; + 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) + OS_REL='' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; + 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4; exit; } ;; + NCR*:*:4.2:* | MPRAS*:*:4.2:*) + OS_REL='.3' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; + m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) + echo m68k-unknown-lynxos${UNAME_RELEASE} + exit ;; + mc68030:UNIX_System_V:4.*:*) + echo m68k-atari-sysv4 + exit ;; + TSUNAMI:LynxOS:2.*:*) + echo sparc-unknown-lynxos${UNAME_RELEASE} + exit ;; + rs6000:LynxOS:2.*:*) + echo rs6000-unknown-lynxos${UNAME_RELEASE} + exit ;; + PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) + echo powerpc-unknown-lynxos${UNAME_RELEASE} + exit ;; + SM[BE]S:UNIX_SV:*:*) + echo mips-dde-sysv${UNAME_RELEASE} + exit ;; + RM*:ReliantUNIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + RM*:SINIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + *:SINIX-*:*:*) + if uname -p 2>/dev/null >/dev/null ; then + UNAME_MACHINE=`(uname -p) 2>/dev/null` + echo ${UNAME_MACHINE}-sni-sysv4 + else + echo ns32k-sni-sysv + fi + exit ;; + PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort + # says + echo i586-unisys-sysv4 + exit ;; + *:UNIX_System_V:4*:FTX*) + # From Gerald Hewes . + # How about differentiating between stratus architectures? -djm + echo hppa1.1-stratus-sysv4 + exit ;; + *:*:*:FTX*) + # From seanf@swdc.stratus.com. + echo i860-stratus-sysv4 + exit ;; + i*86:VOS:*:*) + # From Paul.Green@stratus.com. + echo ${UNAME_MACHINE}-stratus-vos + exit ;; + *:VOS:*:*) + # From Paul.Green@stratus.com. + echo hppa1.1-stratus-vos + exit ;; + mc68*:A/UX:*:*) + echo m68k-apple-aux${UNAME_RELEASE} + exit ;; + news*:NEWS-OS:6*:*) + echo mips-sony-newsos6 + exit ;; + R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) + if [ -d /usr/nec ]; then + echo mips-nec-sysv${UNAME_RELEASE} + else + echo mips-unknown-sysv${UNAME_RELEASE} + fi + exit ;; + BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. + echo powerpc-be-beos + exit ;; + BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. + echo powerpc-apple-beos + exit ;; + BePC:BeOS:*:*) # BeOS running on Intel PC compatible. + echo i586-pc-beos + exit ;; + BePC:Haiku:*:*) # Haiku running on Intel PC compatible. + echo i586-pc-haiku + exit ;; + x86_64:Haiku:*:*) + echo x86_64-unknown-haiku + exit ;; + SX-4:SUPER-UX:*:*) + echo sx4-nec-superux${UNAME_RELEASE} + exit ;; + SX-5:SUPER-UX:*:*) + echo sx5-nec-superux${UNAME_RELEASE} + exit ;; + SX-6:SUPER-UX:*:*) + echo sx6-nec-superux${UNAME_RELEASE} + exit ;; + SX-7:SUPER-UX:*:*) + echo sx7-nec-superux${UNAME_RELEASE} + exit ;; + SX-8:SUPER-UX:*:*) + echo sx8-nec-superux${UNAME_RELEASE} + exit ;; + SX-8R:SUPER-UX:*:*) + echo sx8r-nec-superux${UNAME_RELEASE} + exit ;; + Power*:Rhapsody:*:*) + echo powerpc-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Rhapsody:*:*) + echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Darwin:*:*) + UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown + eval $set_cc_for_build + if test "$UNAME_PROCESSOR" = unknown ; then + UNAME_PROCESSOR=powerpc + fi + if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then + if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ + (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_64BIT_ARCH >/dev/null + then + case $UNAME_PROCESSOR in + i386) UNAME_PROCESSOR=x86_64 ;; + powerpc) UNAME_PROCESSOR=powerpc64 ;; + esac + fi + fi + echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} + exit ;; + *:procnto*:*:* | *:QNX:[0123456789]*:*) + UNAME_PROCESSOR=`uname -p` + if test "$UNAME_PROCESSOR" = "x86"; then + UNAME_PROCESSOR=i386 + UNAME_MACHINE=pc + fi + echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} + exit ;; + *:QNX:*:4*) + echo i386-pc-qnx + exit ;; + NEO-?:NONSTOP_KERNEL:*:*) + echo neo-tandem-nsk${UNAME_RELEASE} + exit ;; + NSE-*:NONSTOP_KERNEL:*:*) + echo nse-tandem-nsk${UNAME_RELEASE} + exit ;; + NSR-?:NONSTOP_KERNEL:*:*) + echo nsr-tandem-nsk${UNAME_RELEASE} + exit ;; + *:NonStop-UX:*:*) + echo mips-compaq-nonstopux + exit ;; + BS2000:POSIX*:*:*) + echo bs2000-siemens-sysv + exit ;; + DS/*:UNIX_System_V:*:*) + echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} + exit ;; + *:Plan9:*:*) + # "uname -m" is not consistent, so use $cputype instead. 386 + # is converted to i386 for consistency with other x86 + # operating systems. + if test "$cputype" = "386"; then + UNAME_MACHINE=i386 + else + UNAME_MACHINE="$cputype" + fi + echo ${UNAME_MACHINE}-unknown-plan9 + exit ;; + *:TOPS-10:*:*) + echo pdp10-unknown-tops10 + exit ;; + *:TENEX:*:*) + echo pdp10-unknown-tenex + exit ;; + KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) + echo pdp10-dec-tops20 + exit ;; + XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) + echo pdp10-xkl-tops20 + exit ;; + *:TOPS-20:*:*) + echo pdp10-unknown-tops20 + exit ;; + *:ITS:*:*) + echo pdp10-unknown-its + exit ;; + SEI:*:*:SEIUX) + echo mips-sei-seiux${UNAME_RELEASE} + exit ;; + *:DragonFly:*:*) + echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` + exit ;; + *:*VMS:*:*) + UNAME_MACHINE=`(uname -p) 2>/dev/null` + case "${UNAME_MACHINE}" in + A*) echo alpha-dec-vms ; exit ;; + I*) echo ia64-dec-vms ; exit ;; + V*) echo vax-dec-vms ; exit ;; + esac ;; + *:XENIX:*:SysV) + echo i386-pc-xenix + exit ;; + i*86:skyos:*:*) + echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' + exit ;; + i*86:rdos:*:*) + echo ${UNAME_MACHINE}-pc-rdos + exit ;; + i*86:AROS:*:*) + echo ${UNAME_MACHINE}-pc-aros + exit ;; + x86_64:VMkernel:*:*) + echo ${UNAME_MACHINE}-unknown-esx + exit ;; +esac + +eval $set_cc_for_build +cat >$dummy.c < +# include +#endif +main () +{ +#if defined (sony) +#if defined (MIPSEB) + /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, + I don't know.... */ + printf ("mips-sony-bsd\n"); exit (0); +#else +#include + printf ("m68k-sony-newsos%s\n", +#ifdef NEWSOS4 + "4" +#else + "" +#endif + ); exit (0); +#endif +#endif + +#if defined (__arm) && defined (__acorn) && defined (__unix) + printf ("arm-acorn-riscix\n"); exit (0); +#endif + +#if defined (hp300) && !defined (hpux) + printf ("m68k-hp-bsd\n"); exit (0); +#endif + +#if defined (NeXT) +#if !defined (__ARCHITECTURE__) +#define __ARCHITECTURE__ "m68k" +#endif + int version; + version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; + if (version < 4) + printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); + else + printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); + exit (0); +#endif + +#if defined (MULTIMAX) || defined (n16) +#if defined (UMAXV) + printf ("ns32k-encore-sysv\n"); exit (0); +#else +#if defined (CMU) + printf ("ns32k-encore-mach\n"); exit (0); +#else + printf ("ns32k-encore-bsd\n"); exit (0); +#endif +#endif +#endif + +#if defined (__386BSD__) + printf ("i386-pc-bsd\n"); exit (0); +#endif + +#if defined (sequent) +#if defined (i386) + printf ("i386-sequent-dynix\n"); exit (0); +#endif +#if defined (ns32000) + printf ("ns32k-sequent-dynix\n"); exit (0); +#endif +#endif + +#if defined (_SEQUENT_) + struct utsname un; + + uname(&un); + + if (strncmp(un.version, "V2", 2) == 0) { + printf ("i386-sequent-ptx2\n"); exit (0); + } + if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ + printf ("i386-sequent-ptx1\n"); exit (0); + } + printf ("i386-sequent-ptx\n"); exit (0); + +#endif + +#if defined (vax) +# if !defined (ultrix) +# include +# if defined (BSD) +# if BSD == 43 + printf ("vax-dec-bsd4.3\n"); exit (0); +# else +# if BSD == 199006 + printf ("vax-dec-bsd4.3reno\n"); exit (0); +# else + printf ("vax-dec-bsd\n"); exit (0); +# endif +# endif +# else + printf ("vax-dec-bsd\n"); exit (0); +# endif +# else + printf ("vax-dec-ultrix\n"); exit (0); +# endif +#endif + +#if defined (alliant) && defined (i860) + printf ("i860-alliant-bsd\n"); exit (0); +#endif + + exit (1); +} +EOF + +$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` && + { echo "$SYSTEM_NAME"; exit; } + +# Apollos put the system type in the environment. + +test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; } + +# Convex versions that predate uname can use getsysinfo(1) + +if [ -x /usr/convex/getsysinfo ] +then + case `getsysinfo -f cpu_type` in + c1*) + echo c1-convex-bsd + exit ;; + c2*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit ;; + c34*) + echo c34-convex-bsd + exit ;; + c38*) + echo c38-convex-bsd + exit ;; + c4*) + echo c4-convex-bsd + exit ;; + esac +fi + +cat >&2 < in order to provide the needed +information to handle your system. + +config.guess timestamp = $timestamp + +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null` + +hostinfo = `(hostinfo) 2>/dev/null` +/bin/universe = `(/bin/universe) 2>/dev/null` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` +/bin/arch = `(/bin/arch) 2>/dev/null` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` + +UNAME_MACHINE = ${UNAME_MACHINE} +UNAME_RELEASE = ${UNAME_RELEASE} +UNAME_SYSTEM = ${UNAME_SYSTEM} +UNAME_VERSION = ${UNAME_VERSION} +EOF + +exit 1 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/extern/portaudio/config.sub b/extern/portaudio/config.sub new file mode 100755 index 0000000..9633db7 --- /dev/null +++ b/extern/portaudio/config.sub @@ -0,0 +1,1791 @@ +#! /bin/sh +# Configuration validation subroutine script. +# Copyright 1992-2013 Free Software Foundation, Inc. + +timestamp='2013-08-10' + +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, see . +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that +# program. This Exception is an additional permission under section 7 +# of the GNU General Public License, version 3 ("GPLv3"). + + +# Please send patches with a ChangeLog entry to config-patches@gnu.org. +# +# Configuration subroutine to validate and canonicalize a configuration type. +# Supply the specified configuration type as an argument. +# If it is invalid, we print an error message on stderr and exit with code 1. +# Otherwise, we print the canonical config type on stdout and succeed. + +# You can get the latest version of this script from: +# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD + +# This file is supposed to be the same for all GNU packages +# and recognize all the CPU types, system types and aliases +# that are meaningful with *any* GNU software. +# Each package is responsible for reporting which valid configurations +# it does not support. The user should be able to distinguish +# a failure to support a valid configuration from a meaningless +# configuration. + +# The goal of this file is to map all the various variations of a given +# machine specification into a single specification in the form: +# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM +# or in some cases, the newer four-part form: +# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM +# It is wrong to echo any other type of specification. + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] CPU-MFR-OPSYS + $0 [OPTION] ALIAS + +Canonicalize a configuration name. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.sub ($timestamp) + +Copyright 1992-2013 Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" + exit 1 ;; + + *local*) + # First pass through any local machine types. + echo $1 + exit ;; + + * ) + break ;; + esac +done + +case $# in + 0) echo "$me: missing argument$help" >&2 + exit 1;; + 1) ;; + *) echo "$me: too many arguments$help" >&2 + exit 1;; +esac + +# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). +# Here we must recognize all the valid KERNEL-OS combinations. +maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` +case $maybe_os in + nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \ + linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \ + knetbsd*-gnu* | netbsd*-gnu* | \ + kopensolaris*-gnu* | \ + storm-chaos* | os2-emx* | rtmk-nova*) + os=-$maybe_os + basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` + ;; + android-linux) + os=-linux-android + basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown + ;; + *) + basic_machine=`echo $1 | sed 's/-[^-]*$//'` + if [ $basic_machine != $1 ] + then os=`echo $1 | sed 's/.*-/-/'` + else os=; fi + ;; +esac + +### Let's recognize common machines as not being operating systems so +### that things like config.sub decstation-3100 work. We also +### recognize some manufacturers as not being operating systems, so we +### can provide default operating systems below. +case $os in + -sun*os*) + # Prevent following clause from handling this invalid input. + ;; + -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ + -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ + -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ + -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ + -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ + -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ + -apple | -axis | -knuth | -cray | -microblaze*) + os= + basic_machine=$1 + ;; + -bluegene*) + os=-cnk + ;; + -sim | -cisco | -oki | -wec | -winbond) + os= + basic_machine=$1 + ;; + -scout) + ;; + -wrs) + os=-vxworks + basic_machine=$1 + ;; + -chorusos*) + os=-chorusos + basic_machine=$1 + ;; + -chorusrdb) + os=-chorusrdb + basic_machine=$1 + ;; + -hiux*) + os=-hiuxwe2 + ;; + -sco6) + os=-sco5v6 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco5) + os=-sco3.2v5 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco4) + os=-sco3.2v4 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2.[4-9]*) + os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2v[4-9]*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco5v6*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco*) + os=-sco3.2v2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -udk*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -isc) + os=-isc2.2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -clix*) + basic_machine=clipper-intergraph + ;; + -isc*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -lynx*178) + os=-lynxos178 + ;; + -lynx*5) + os=-lynxos5 + ;; + -lynx*) + os=-lynxos + ;; + -ptx*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` + ;; + -windowsnt*) + os=`echo $os | sed -e 's/windowsnt/winnt/'` + ;; + -psos*) + os=-psos + ;; + -mint | -mint[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; +esac + +# Decode aliases for certain CPU-COMPANY combinations. +case $basic_machine in + # Recognize the basic CPU types without company name. + # Some are omitted here because they have special meanings below. + 1750a | 580 \ + | a29k \ + | aarch64 | aarch64_be \ + | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ + | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ + | am33_2.0 \ + | arc | arceb \ + | arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \ + | avr | avr32 \ + | be32 | be64 \ + | bfin \ + | c4x | c8051 | clipper \ + | d10v | d30v | dlx | dsp16xx \ + | epiphany \ + | fido | fr30 | frv \ + | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ + | hexagon \ + | i370 | i860 | i960 | ia64 \ + | ip2k | iq2000 \ + | le32 | le64 \ + | lm32 \ + | m32c | m32r | m32rle | m68000 | m68k | m88k \ + | maxq | mb | microblaze | microblazeel | mcore | mep | metag \ + | mips | mipsbe | mipseb | mipsel | mipsle \ + | mips16 \ + | mips64 | mips64el \ + | mips64octeon | mips64octeonel \ + | mips64orion | mips64orionel \ + | mips64r5900 | mips64r5900el \ + | mips64vr | mips64vrel \ + | mips64vr4100 | mips64vr4100el \ + | mips64vr4300 | mips64vr4300el \ + | mips64vr5000 | mips64vr5000el \ + | mips64vr5900 | mips64vr5900el \ + | mipsisa32 | mipsisa32el \ + | mipsisa32r2 | mipsisa32r2el \ + | mipsisa64 | mipsisa64el \ + | mipsisa64r2 | mipsisa64r2el \ + | mipsisa64sb1 | mipsisa64sb1el \ + | mipsisa64sr71k | mipsisa64sr71kel \ + | mipsr5900 | mipsr5900el \ + | mipstx39 | mipstx39el \ + | mn10200 | mn10300 \ + | moxie \ + | mt \ + | msp430 \ + | nds32 | nds32le | nds32be \ + | nios | nios2 | nios2eb | nios2el \ + | ns16k | ns32k \ + | open8 \ + | or1k | or32 \ + | pdp10 | pdp11 | pj | pjl \ + | powerpc | powerpc64 | powerpc64le | powerpcle \ + | pyramid \ + | rl78 | rx \ + | score \ + | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ + | sh64 | sh64le \ + | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ + | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ + | spu \ + | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \ + | ubicom32 \ + | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \ + | we32k \ + | x86 | xc16x | xstormy16 | xtensa \ + | z8k | z80) + basic_machine=$basic_machine-unknown + ;; + c54x) + basic_machine=tic54x-unknown + ;; + c55x) + basic_machine=tic55x-unknown + ;; + c6x) + basic_machine=tic6x-unknown + ;; + m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | picochip) + basic_machine=$basic_machine-unknown + os=-none + ;; + m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) + ;; + ms1) + basic_machine=mt-unknown + ;; + + strongarm | thumb | xscale) + basic_machine=arm-unknown + ;; + xgate) + basic_machine=$basic_machine-unknown + os=-none + ;; + xscaleeb) + basic_machine=armeb-unknown + ;; + + xscaleel) + basic_machine=armel-unknown + ;; + + # We use `pc' rather than `unknown' + # because (1) that's what they normally are, and + # (2) the word "unknown" tends to confuse beginning users. + i*86 | x86_64) + basic_machine=$basic_machine-pc + ;; + # Object if more than one company name word. + *-*-*) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; + # Recognize the basic CPU types with company name. + 580-* \ + | a29k-* \ + | aarch64-* | aarch64_be-* \ + | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ + | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ + | alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \ + | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ + | avr-* | avr32-* \ + | be32-* | be64-* \ + | bfin-* | bs2000-* \ + | c[123]* | c30-* | [cjt]90-* | c4x-* \ + | c8051-* | clipper-* | craynv-* | cydra-* \ + | d10v-* | d30v-* | dlx-* \ + | elxsi-* \ + | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ + | h8300-* | h8500-* \ + | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ + | hexagon-* \ + | i*86-* | i860-* | i960-* | ia64-* \ + | ip2k-* | iq2000-* \ + | le32-* | le64-* \ + | lm32-* \ + | m32c-* | m32r-* | m32rle-* \ + | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ + | m88110-* | m88k-* | maxq-* | mcore-* | metag-* \ + | microblaze-* | microblazeel-* \ + | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ + | mips16-* \ + | mips64-* | mips64el-* \ + | mips64octeon-* | mips64octeonel-* \ + | mips64orion-* | mips64orionel-* \ + | mips64r5900-* | mips64r5900el-* \ + | mips64vr-* | mips64vrel-* \ + | mips64vr4100-* | mips64vr4100el-* \ + | mips64vr4300-* | mips64vr4300el-* \ + | mips64vr5000-* | mips64vr5000el-* \ + | mips64vr5900-* | mips64vr5900el-* \ + | mipsisa32-* | mipsisa32el-* \ + | mipsisa32r2-* | mipsisa32r2el-* \ + | mipsisa64-* | mipsisa64el-* \ + | mipsisa64r2-* | mipsisa64r2el-* \ + | mipsisa64sb1-* | mipsisa64sb1el-* \ + | mipsisa64sr71k-* | mipsisa64sr71kel-* \ + | mipsr5900-* | mipsr5900el-* \ + | mipstx39-* | mipstx39el-* \ + | mmix-* \ + | mt-* \ + | msp430-* \ + | nds32-* | nds32le-* | nds32be-* \ + | nios-* | nios2-* | nios2eb-* | nios2el-* \ + | none-* | np1-* | ns16k-* | ns32k-* \ + | open8-* \ + | orion-* \ + | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ + | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \ + | pyramid-* \ + | rl78-* | romp-* | rs6000-* | rx-* \ + | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ + | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ + | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ + | sparclite-* \ + | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx?-* \ + | tahoe-* \ + | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ + | tile*-* \ + | tron-* \ + | ubicom32-* \ + | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \ + | vax-* \ + | we32k-* \ + | x86-* | x86_64-* | xc16x-* | xps100-* \ + | xstormy16-* | xtensa*-* \ + | ymp-* \ + | z8k-* | z80-*) + ;; + # Recognize the basic CPU types without company name, with glob match. + xtensa*) + basic_machine=$basic_machine-unknown + ;; + # Recognize the various machine names and aliases which stand + # for a CPU type and a company and sometimes even an OS. + 386bsd) + basic_machine=i386-unknown + os=-bsd + ;; + 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) + basic_machine=m68000-att + ;; + 3b*) + basic_machine=we32k-att + ;; + a29khif) + basic_machine=a29k-amd + os=-udi + ;; + abacus) + basic_machine=abacus-unknown + ;; + adobe68k) + basic_machine=m68010-adobe + os=-scout + ;; + alliant | fx80) + basic_machine=fx80-alliant + ;; + altos | altos3068) + basic_machine=m68k-altos + ;; + am29k) + basic_machine=a29k-none + os=-bsd + ;; + amd64) + basic_machine=x86_64-pc + ;; + amd64-*) + basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + amdahl) + basic_machine=580-amdahl + os=-sysv + ;; + amiga | amiga-*) + basic_machine=m68k-unknown + ;; + amigaos | amigados) + basic_machine=m68k-unknown + os=-amigaos + ;; + amigaunix | amix) + basic_machine=m68k-unknown + os=-sysv4 + ;; + apollo68) + basic_machine=m68k-apollo + os=-sysv + ;; + apollo68bsd) + basic_machine=m68k-apollo + os=-bsd + ;; + aros) + basic_machine=i386-pc + os=-aros + ;; + aux) + basic_machine=m68k-apple + os=-aux + ;; + balance) + basic_machine=ns32k-sequent + os=-dynix + ;; + blackfin) + basic_machine=bfin-unknown + os=-linux + ;; + blackfin-*) + basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + bluegene*) + basic_machine=powerpc-ibm + os=-cnk + ;; + c54x-*) + basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + c55x-*) + basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + c6x-*) + basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + c90) + basic_machine=c90-cray + os=-unicos + ;; + cegcc) + basic_machine=arm-unknown + os=-cegcc + ;; + convex-c1) + basic_machine=c1-convex + os=-bsd + ;; + convex-c2) + basic_machine=c2-convex + os=-bsd + ;; + convex-c32) + basic_machine=c32-convex + os=-bsd + ;; + convex-c34) + basic_machine=c34-convex + os=-bsd + ;; + convex-c38) + basic_machine=c38-convex + os=-bsd + ;; + cray | j90) + basic_machine=j90-cray + os=-unicos + ;; + craynv) + basic_machine=craynv-cray + os=-unicosmp + ;; + cr16 | cr16-*) + basic_machine=cr16-unknown + os=-elf + ;; + crds | unos) + basic_machine=m68k-crds + ;; + crisv32 | crisv32-* | etraxfs*) + basic_machine=crisv32-axis + ;; + cris | cris-* | etrax*) + basic_machine=cris-axis + ;; + crx) + basic_machine=crx-unknown + os=-elf + ;; + da30 | da30-*) + basic_machine=m68k-da30 + ;; + decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) + basic_machine=mips-dec + ;; + decsystem10* | dec10*) + basic_machine=pdp10-dec + os=-tops10 + ;; + decsystem20* | dec20*) + basic_machine=pdp10-dec + os=-tops20 + ;; + delta | 3300 | motorola-3300 | motorola-delta \ + | 3300-motorola | delta-motorola) + basic_machine=m68k-motorola + ;; + delta88) + basic_machine=m88k-motorola + os=-sysv3 + ;; + dicos) + basic_machine=i686-pc + os=-dicos + ;; + djgpp) + basic_machine=i586-pc + os=-msdosdjgpp + ;; + dpx20 | dpx20-*) + basic_machine=rs6000-bull + os=-bosx + ;; + dpx2* | dpx2*-bull) + basic_machine=m68k-bull + os=-sysv3 + ;; + ebmon29k) + basic_machine=a29k-amd + os=-ebmon + ;; + elxsi) + basic_machine=elxsi-elxsi + os=-bsd + ;; + encore | umax | mmax) + basic_machine=ns32k-encore + ;; + es1800 | OSE68k | ose68k | ose | OSE) + basic_machine=m68k-ericsson + os=-ose + ;; + fx2800) + basic_machine=i860-alliant + ;; + genix) + basic_machine=ns32k-ns + ;; + gmicro) + basic_machine=tron-gmicro + os=-sysv + ;; + go32) + basic_machine=i386-pc + os=-go32 + ;; + h3050r* | hiux*) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + h8300hms) + basic_machine=h8300-hitachi + os=-hms + ;; + h8300xray) + basic_machine=h8300-hitachi + os=-xray + ;; + h8500hms) + basic_machine=h8500-hitachi + os=-hms + ;; + harris) + basic_machine=m88k-harris + os=-sysv3 + ;; + hp300-*) + basic_machine=m68k-hp + ;; + hp300bsd) + basic_machine=m68k-hp + os=-bsd + ;; + hp300hpux) + basic_machine=m68k-hp + os=-hpux + ;; + hp3k9[0-9][0-9] | hp9[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k2[0-9][0-9] | hp9k31[0-9]) + basic_machine=m68000-hp + ;; + hp9k3[2-9][0-9]) + basic_machine=m68k-hp + ;; + hp9k6[0-9][0-9] | hp6[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k7[0-79][0-9] | hp7[0-79][0-9]) + basic_machine=hppa1.1-hp + ;; + hp9k78[0-9] | hp78[0-9]) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][13679] | hp8[0-9][13679]) + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][0-9] | hp8[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hppa-next) + os=-nextstep3 + ;; + hppaosf) + basic_machine=hppa1.1-hp + os=-osf + ;; + hppro) + basic_machine=hppa1.1-hp + os=-proelf + ;; + i370-ibm* | ibm*) + basic_machine=i370-ibm + ;; + i*86v32) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv32 + ;; + i*86v4*) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv4 + ;; + i*86v) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv + ;; + i*86sol2) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-solaris2 + ;; + i386mach) + basic_machine=i386-mach + os=-mach + ;; + i386-vsta | vsta) + basic_machine=i386-unknown + os=-vsta + ;; + iris | iris4d) + basic_machine=mips-sgi + case $os in + -irix*) + ;; + *) + os=-irix4 + ;; + esac + ;; + isi68 | isi) + basic_machine=m68k-isi + os=-sysv + ;; + m68knommu) + basic_machine=m68k-unknown + os=-linux + ;; + m68knommu-*) + basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + m88k-omron*) + basic_machine=m88k-omron + ;; + magnum | m3230) + basic_machine=mips-mips + os=-sysv + ;; + merlin) + basic_machine=ns32k-utek + os=-sysv + ;; + microblaze*) + basic_machine=microblaze-xilinx + ;; + mingw64) + basic_machine=x86_64-pc + os=-mingw64 + ;; + mingw32) + basic_machine=i686-pc + os=-mingw32 + ;; + mingw32ce) + basic_machine=arm-unknown + os=-mingw32ce + ;; + miniframe) + basic_machine=m68000-convergent + ;; + *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; + mips3*-*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` + ;; + mips3*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown + ;; + monitor) + basic_machine=m68k-rom68k + os=-coff + ;; + morphos) + basic_machine=powerpc-unknown + os=-morphos + ;; + msdos) + basic_machine=i386-pc + os=-msdos + ;; + ms1-*) + basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` + ;; + msys) + basic_machine=i686-pc + os=-msys + ;; + mvs) + basic_machine=i370-ibm + os=-mvs + ;; + nacl) + basic_machine=le32-unknown + os=-nacl + ;; + ncr3000) + basic_machine=i486-ncr + os=-sysv4 + ;; + netbsd386) + basic_machine=i386-unknown + os=-netbsd + ;; + netwinder) + basic_machine=armv4l-rebel + os=-linux + ;; + news | news700 | news800 | news900) + basic_machine=m68k-sony + os=-newsos + ;; + news1000) + basic_machine=m68030-sony + os=-newsos + ;; + news-3600 | risc-news) + basic_machine=mips-sony + os=-newsos + ;; + necv70) + basic_machine=v70-nec + os=-sysv + ;; + next | m*-next ) + basic_machine=m68k-next + case $os in + -nextstep* ) + ;; + -ns2*) + os=-nextstep2 + ;; + *) + os=-nextstep3 + ;; + esac + ;; + nh3000) + basic_machine=m68k-harris + os=-cxux + ;; + nh[45]000) + basic_machine=m88k-harris + os=-cxux + ;; + nindy960) + basic_machine=i960-intel + os=-nindy + ;; + mon960) + basic_machine=i960-intel + os=-mon960 + ;; + nonstopux) + basic_machine=mips-compaq + os=-nonstopux + ;; + np1) + basic_machine=np1-gould + ;; + neo-tandem) + basic_machine=neo-tandem + ;; + nse-tandem) + basic_machine=nse-tandem + ;; + nsr-tandem) + basic_machine=nsr-tandem + ;; + op50n-* | op60c-*) + basic_machine=hppa1.1-oki + os=-proelf + ;; + openrisc | openrisc-*) + basic_machine=or32-unknown + ;; + os400) + basic_machine=powerpc-ibm + os=-os400 + ;; + OSE68000 | ose68000) + basic_machine=m68000-ericsson + os=-ose + ;; + os68k) + basic_machine=m68k-none + os=-os68k + ;; + pa-hitachi) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + paragon) + basic_machine=i860-intel + os=-osf + ;; + parisc) + basic_machine=hppa-unknown + os=-linux + ;; + parisc-*) + basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + pbd) + basic_machine=sparc-tti + ;; + pbb) + basic_machine=m68k-tti + ;; + pc532 | pc532-*) + basic_machine=ns32k-pc532 + ;; + pc98) + basic_machine=i386-pc + ;; + pc98-*) + basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentium | p5 | k5 | k6 | nexgen | viac3) + basic_machine=i586-pc + ;; + pentiumpro | p6 | 6x86 | athlon | athlon_*) + basic_machine=i686-pc + ;; + pentiumii | pentium2 | pentiumiii | pentium3) + basic_machine=i686-pc + ;; + pentium4) + basic_machine=i786-pc + ;; + pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) + basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumpro-* | p6-* | 6x86-* | athlon-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentium4-*) + basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pn) + basic_machine=pn-gould + ;; + power) basic_machine=power-ibm + ;; + ppc | ppcbe) basic_machine=powerpc-unknown + ;; + ppc-* | ppcbe-*) + basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppcle | powerpclittle | ppc-le | powerpc-little) + basic_machine=powerpcle-unknown + ;; + ppcle-* | powerpclittle-*) + basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64) basic_machine=powerpc64-unknown + ;; + ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64le | powerpc64little | ppc64-le | powerpc64-little) + basic_machine=powerpc64le-unknown + ;; + ppc64le-* | powerpc64little-*) + basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ps2) + basic_machine=i386-ibm + ;; + pw32) + basic_machine=i586-unknown + os=-pw32 + ;; + rdos | rdos64) + basic_machine=x86_64-pc + os=-rdos + ;; + rdos32) + basic_machine=i386-pc + os=-rdos + ;; + rom68k) + basic_machine=m68k-rom68k + os=-coff + ;; + rm[46]00) + basic_machine=mips-siemens + ;; + rtpc | rtpc-*) + basic_machine=romp-ibm + ;; + s390 | s390-*) + basic_machine=s390-ibm + ;; + s390x | s390x-*) + basic_machine=s390x-ibm + ;; + sa29200) + basic_machine=a29k-amd + os=-udi + ;; + sb1) + basic_machine=mipsisa64sb1-unknown + ;; + sb1el) + basic_machine=mipsisa64sb1el-unknown + ;; + sde) + basic_machine=mipsisa32-sde + os=-elf + ;; + sei) + basic_machine=mips-sei + os=-seiux + ;; + sequent) + basic_machine=i386-sequent + ;; + sh) + basic_machine=sh-hitachi + os=-hms + ;; + sh5el) + basic_machine=sh5le-unknown + ;; + sh64) + basic_machine=sh64-unknown + ;; + sparclite-wrs | simso-wrs) + basic_machine=sparclite-wrs + os=-vxworks + ;; + sps7) + basic_machine=m68k-bull + os=-sysv2 + ;; + spur) + basic_machine=spur-unknown + ;; + st2000) + basic_machine=m68k-tandem + ;; + stratus) + basic_machine=i860-stratus + os=-sysv4 + ;; + strongarm-* | thumb-*) + basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + sun2) + basic_machine=m68000-sun + ;; + sun2os3) + basic_machine=m68000-sun + os=-sunos3 + ;; + sun2os4) + basic_machine=m68000-sun + os=-sunos4 + ;; + sun3os3) + basic_machine=m68k-sun + os=-sunos3 + ;; + sun3os4) + basic_machine=m68k-sun + os=-sunos4 + ;; + sun4os3) + basic_machine=sparc-sun + os=-sunos3 + ;; + sun4os4) + basic_machine=sparc-sun + os=-sunos4 + ;; + sun4sol2) + basic_machine=sparc-sun + os=-solaris2 + ;; + sun3 | sun3-*) + basic_machine=m68k-sun + ;; + sun4) + basic_machine=sparc-sun + ;; + sun386 | sun386i | roadrunner) + basic_machine=i386-sun + ;; + sv1) + basic_machine=sv1-cray + os=-unicos + ;; + symmetry) + basic_machine=i386-sequent + os=-dynix + ;; + t3e) + basic_machine=alphaev5-cray + os=-unicos + ;; + t90) + basic_machine=t90-cray + os=-unicos + ;; + tile*) + basic_machine=$basic_machine-unknown + os=-linux-gnu + ;; + tx39) + basic_machine=mipstx39-unknown + ;; + tx39el) + basic_machine=mipstx39el-unknown + ;; + toad1) + basic_machine=pdp10-xkl + os=-tops20 + ;; + tower | tower-32) + basic_machine=m68k-ncr + ;; + tpf) + basic_machine=s390x-ibm + os=-tpf + ;; + udi29k) + basic_machine=a29k-amd + os=-udi + ;; + ultra3) + basic_machine=a29k-nyu + os=-sym1 + ;; + v810 | necv810) + basic_machine=v810-nec + os=-none + ;; + vaxv) + basic_machine=vax-dec + os=-sysv + ;; + vms) + basic_machine=vax-dec + os=-vms + ;; + vpp*|vx|vx-*) + basic_machine=f301-fujitsu + ;; + vxworks960) + basic_machine=i960-wrs + os=-vxworks + ;; + vxworks68) + basic_machine=m68k-wrs + os=-vxworks + ;; + vxworks29k) + basic_machine=a29k-wrs + os=-vxworks + ;; + w65*) + basic_machine=w65-wdc + os=-none + ;; + w89k-*) + basic_machine=hppa1.1-winbond + os=-proelf + ;; + xbox) + basic_machine=i686-pc + os=-mingw32 + ;; + xps | xps100) + basic_machine=xps100-honeywell + ;; + xscale-* | xscalee[bl]-*) + basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'` + ;; + ymp) + basic_machine=ymp-cray + os=-unicos + ;; + z8k-*-coff) + basic_machine=z8k-unknown + os=-sim + ;; + z80-*-coff) + basic_machine=z80-unknown + os=-sim + ;; + none) + basic_machine=none-none + os=-none + ;; + +# Here we handle the default manufacturer of certain CPU types. It is in +# some cases the only manufacturer, in others, it is the most popular. + w89k) + basic_machine=hppa1.1-winbond + ;; + op50n) + basic_machine=hppa1.1-oki + ;; + op60c) + basic_machine=hppa1.1-oki + ;; + romp) + basic_machine=romp-ibm + ;; + mmix) + basic_machine=mmix-knuth + ;; + rs6000) + basic_machine=rs6000-ibm + ;; + vax) + basic_machine=vax-dec + ;; + pdp10) + # there are many clones, so DEC is not a safe bet + basic_machine=pdp10-unknown + ;; + pdp11) + basic_machine=pdp11-dec + ;; + we32k) + basic_machine=we32k-att + ;; + sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele) + basic_machine=sh-unknown + ;; + sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v) + basic_machine=sparc-sun + ;; + cydra) + basic_machine=cydra-cydrome + ;; + orion) + basic_machine=orion-highlevel + ;; + orion105) + basic_machine=clipper-highlevel + ;; + mac | mpw | mac-mpw) + basic_machine=m68k-apple + ;; + pmac | pmac-mpw) + basic_machine=powerpc-apple + ;; + *-unknown) + # Make sure to match an already-canonicalized machine name. + ;; + *) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; +esac + +# Here we canonicalize certain aliases for manufacturers. +case $basic_machine in + *-digital*) + basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` + ;; + *-commodore*) + basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` + ;; + *) + ;; +esac + +# Decode manufacturer-specific aliases for certain operating systems. + +if [ x"$os" != x"" ] +then +case $os in + # First match some system type aliases + # that might get confused with valid system types. + # -solaris* is a basic system type, with this one exception. + -auroraux) + os=-auroraux + ;; + -solaris1 | -solaris1.*) + os=`echo $os | sed -e 's|solaris1|sunos4|'` + ;; + -solaris) + os=-solaris2 + ;; + -svr4*) + os=-sysv4 + ;; + -unixware*) + os=-sysv4.2uw + ;; + -gnu/linux*) + os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` + ;; + # First accept the basic system types. + # The portable systems comes first. + # Each alternative MUST END IN A *, to match a version number. + # -sysv* is not here because it comes later, after sysvr4. + -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ + | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\ + | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ + | -sym* | -kopensolaris* | -plan9* \ + | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ + | -aos* | -aros* \ + | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ + | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ + | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ + | -bitrig* | -openbsd* | -solidbsd* \ + | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ + | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ + | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ + | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ + | -chorusos* | -chorusrdb* | -cegcc* \ + | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ + | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \ + | -linux-newlib* | -linux-musl* | -linux-uclibc* \ + | -uxpv* | -beos* | -mpeix* | -udk* \ + | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ + | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ + | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ + | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ + | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ + | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ + | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es*) + # Remember, each alternative MUST END IN *, to match a version number. + ;; + -qnx*) + case $basic_machine in + x86-* | i*86-*) + ;; + *) + os=-nto$os + ;; + esac + ;; + -nto-qnx*) + ;; + -nto*) + os=`echo $os | sed -e 's|nto|nto-qnx|'` + ;; + -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ + | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \ + | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) + ;; + -mac*) + os=`echo $os | sed -e 's|mac|macos|'` + ;; + -linux-dietlibc) + os=-linux-dietlibc + ;; + -linux*) + os=`echo $os | sed -e 's|linux|linux-gnu|'` + ;; + -sunos5*) + os=`echo $os | sed -e 's|sunos5|solaris2|'` + ;; + -sunos6*) + os=`echo $os | sed -e 's|sunos6|solaris3|'` + ;; + -opened*) + os=-openedition + ;; + -os400*) + os=-os400 + ;; + -wince*) + os=-wince + ;; + -osfrose*) + os=-osfrose + ;; + -osf*) + os=-osf + ;; + -utek*) + os=-bsd + ;; + -dynix*) + os=-bsd + ;; + -acis*) + os=-aos + ;; + -atheos*) + os=-atheos + ;; + -syllable*) + os=-syllable + ;; + -386bsd) + os=-bsd + ;; + -ctix* | -uts*) + os=-sysv + ;; + -nova*) + os=-rtmk-nova + ;; + -ns2 ) + os=-nextstep2 + ;; + -nsk*) + os=-nsk + ;; + # Preserve the version number of sinix5. + -sinix5.*) + os=`echo $os | sed -e 's|sinix|sysv|'` + ;; + -sinix*) + os=-sysv4 + ;; + -tpf*) + os=-tpf + ;; + -triton*) + os=-sysv3 + ;; + -oss*) + os=-sysv3 + ;; + -svr4) + os=-sysv4 + ;; + -svr3) + os=-sysv3 + ;; + -sysvr4) + os=-sysv4 + ;; + # This must come after -sysvr4. + -sysv*) + ;; + -ose*) + os=-ose + ;; + -es1800*) + os=-ose + ;; + -xenix) + os=-xenix + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + os=-mint + ;; + -aros*) + os=-aros + ;; + -zvmoe) + os=-zvmoe + ;; + -dicos*) + os=-dicos + ;; + -nacl*) + ;; + -none) + ;; + *) + # Get rid of the `-' at the beginning of $os. + os=`echo $os | sed 's/[^-]*-//'` + echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 + exit 1 + ;; +esac +else + +# Here we handle the default operating systems that come with various machines. +# The value should be what the vendor currently ships out the door with their +# machine or put another way, the most popular os provided with the machine. + +# Note that if you're going to try to match "-MANUFACTURER" here (say, +# "-sun"), then you have to tell the case statement up towards the top +# that MANUFACTURER isn't an operating system. Otherwise, code above +# will signal an error saying that MANUFACTURER isn't an operating +# system, and we'll never get to this point. + +case $basic_machine in + score-*) + os=-elf + ;; + spu-*) + os=-elf + ;; + *-acorn) + os=-riscix1.2 + ;; + arm*-rebel) + os=-linux + ;; + arm*-semi) + os=-aout + ;; + c4x-* | tic4x-*) + os=-coff + ;; + c8051-*) + os=-elf + ;; + hexagon-*) + os=-elf + ;; + tic54x-*) + os=-coff + ;; + tic55x-*) + os=-coff + ;; + tic6x-*) + os=-coff + ;; + # This must come before the *-dec entry. + pdp10-*) + os=-tops20 + ;; + pdp11-*) + os=-none + ;; + *-dec | vax-*) + os=-ultrix4.2 + ;; + m68*-apollo) + os=-domain + ;; + i386-sun) + os=-sunos4.0.2 + ;; + m68000-sun) + os=-sunos3 + ;; + m68*-cisco) + os=-aout + ;; + mep-*) + os=-elf + ;; + mips*-cisco) + os=-elf + ;; + mips*-*) + os=-elf + ;; + or1k-*) + os=-elf + ;; + or32-*) + os=-coff + ;; + *-tti) # must be before sparc entry or we get the wrong os. + os=-sysv3 + ;; + sparc-* | *-sun) + os=-sunos4.1.1 + ;; + *-be) + os=-beos + ;; + *-haiku) + os=-haiku + ;; + *-ibm) + os=-aix + ;; + *-knuth) + os=-mmixware + ;; + *-wec) + os=-proelf + ;; + *-winbond) + os=-proelf + ;; + *-oki) + os=-proelf + ;; + *-hp) + os=-hpux + ;; + *-hitachi) + os=-hiux + ;; + i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) + os=-sysv + ;; + *-cbm) + os=-amigaos + ;; + *-dg) + os=-dgux + ;; + *-dolphin) + os=-sysv3 + ;; + m68k-ccur) + os=-rtu + ;; + m88k-omron*) + os=-luna + ;; + *-next ) + os=-nextstep + ;; + *-sequent) + os=-ptx + ;; + *-crds) + os=-unos + ;; + *-ns) + os=-genix + ;; + i370-*) + os=-mvs + ;; + *-next) + os=-nextstep3 + ;; + *-gould) + os=-sysv + ;; + *-highlevel) + os=-bsd + ;; + *-encore) + os=-bsd + ;; + *-sgi) + os=-irix + ;; + *-siemens) + os=-sysv4 + ;; + *-masscomp) + os=-rtu + ;; + f30[01]-fujitsu | f700-fujitsu) + os=-uxpv + ;; + *-rom68k) + os=-coff + ;; + *-*bug) + os=-coff + ;; + *-apple) + os=-macos + ;; + *-atari*) + os=-mint + ;; + *) + os=-none + ;; +esac +fi + +# Here we handle the case where we know the os, and the CPU type, but not the +# manufacturer. We pick the logical manufacturer. +vendor=unknown +case $basic_machine in + *-unknown) + case $os in + -riscix*) + vendor=acorn + ;; + -sunos*) + vendor=sun + ;; + -cnk*|-aix*) + vendor=ibm + ;; + -beos*) + vendor=be + ;; + -hpux*) + vendor=hp + ;; + -mpeix*) + vendor=hp + ;; + -hiux*) + vendor=hitachi + ;; + -unos*) + vendor=crds + ;; + -dgux*) + vendor=dg + ;; + -luna*) + vendor=omron + ;; + -genix*) + vendor=ns + ;; + -mvs* | -opened*) + vendor=ibm + ;; + -os400*) + vendor=ibm + ;; + -ptx*) + vendor=sequent + ;; + -tpf*) + vendor=ibm + ;; + -vxsim* | -vxworks* | -windiss*) + vendor=wrs + ;; + -aux*) + vendor=apple + ;; + -hms*) + vendor=hitachi + ;; + -mpw* | -macos*) + vendor=apple + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + vendor=atari + ;; + -vos*) + vendor=stratus + ;; + esac + basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` + ;; +esac + +echo $basic_machine$os +exit + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/extern/portaudio/configure b/extern/portaudio/configure new file mode 100755 index 0000000..e170327 --- /dev/null +++ b/extern/portaudio/configure @@ -0,0 +1,18830 @@ +#! /bin/sh +# Guess values for system-dependent variables and create Makefiles. +# Generated by GNU Autoconf 2.69. +# +# +# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. +# +# +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +as_myself= +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +# Use a proper internal environment variable to ensure we don't fall + # into an infinite loop, continuously re-executing ourselves. + if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then + _as_can_reexec=no; export _as_can_reexec; + # We cannot yet assume a decent shell, so we have to provide a +# neutralization value for shells without unset; and this also +# works around shells that cannot unset nonexistent variables. +# Preserve -v and -x to the replacement shell. +BASH_ENV=/dev/null +ENV=/dev/null +(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV +case $- in # (((( + *v*x* | *x*v* ) as_opts=-vx ;; + *v* ) as_opts=-v ;; + *x* ) as_opts=-x ;; + * ) as_opts= ;; +esac +exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} +# Admittedly, this is quite paranoid, since all the known shells bail +# out after a failed `exec'. +$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 +as_fn_exit 255 + fi + # We don't want this to propagate to other subprocesses. + { _as_can_reexec=; unset _as_can_reexec;} +if test "x$CONFIG_SHELL" = x; then + as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which + # is contrary to our usage. Disable this feature. + alias -g '\${1+\"\$@\"}'='\"\$@\"' + setopt NO_GLOB_SUBST +else + case \`(set -o) 2>/dev/null\` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi +" + as_required="as_fn_return () { (exit \$1); } +as_fn_success () { as_fn_return 0; } +as_fn_failure () { as_fn_return 1; } +as_fn_ret_success () { return 0; } +as_fn_ret_failure () { return 1; } + +exitcode=0 +as_fn_success || { exitcode=1; echo as_fn_success failed.; } +as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } +as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } +as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } +if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : + +else + exitcode=1; echo positional parameters were not saved. +fi +test x\$exitcode = x0 || exit 1 +test -x / || exit 1" + as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO + as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO + eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && + test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 + + test -n \"\${ZSH_VERSION+set}\${BASH_VERSION+set}\" || ( + ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' + ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO + ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO + PATH=/empty FPATH=/empty; export PATH FPATH + test \"X\`printf %s \$ECHO\`\" = \"X\$ECHO\" \\ + || test \"X\`print -r -- \$ECHO\`\" = \"X\$ECHO\" ) || exit 1 +test \$(( 1 + 1 )) = 2 || exit 1" + if (eval "$as_required") 2>/dev/null; then : + as_have_required=yes +else + as_have_required=no +fi + if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : + +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_found=false +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + as_found=: + case $as_dir in #( + /*) + for as_base in sh bash ksh sh5; do + # Try only shells that exist, to save several forks. + as_shell=$as_dir/$as_base + if { test -f "$as_shell" || test -f "$as_shell.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : + CONFIG_SHELL=$as_shell as_have_required=yes + if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : + break 2 +fi +fi + done;; + esac + as_found=false +done +$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : + CONFIG_SHELL=$SHELL as_have_required=yes +fi; } +IFS=$as_save_IFS + + + if test "x$CONFIG_SHELL" != x; then : + export CONFIG_SHELL + # We cannot yet assume a decent shell, so we have to provide a +# neutralization value for shells without unset; and this also +# works around shells that cannot unset nonexistent variables. +# Preserve -v and -x to the replacement shell. +BASH_ENV=/dev/null +ENV=/dev/null +(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV +case $- in # (((( + *v*x* | *x*v* ) as_opts=-vx ;; + *v* ) as_opts=-v ;; + *x* ) as_opts=-x ;; + * ) as_opts= ;; +esac +exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} +# Admittedly, this is quite paranoid, since all the known shells bail +# out after a failed `exec'. +$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 +exit 255 +fi + + if test x$as_have_required = xno; then : + $as_echo "$0: This script requires a shell more modern than all" + $as_echo "$0: the shells that I found on your system." + if test x${ZSH_VERSION+set} = xset ; then + $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" + $as_echo "$0: be upgraded to zsh 4.3.4 or later." + else + $as_echo "$0: Please tell bug-autoconf@gnu.org about your system, +$0: including any error possibly output before this +$0: message. Then install a modern shell, or manually run +$0: the script under such a shell if you do have one." + fi + exit 1 +fi +fi +fi +SHELL=${CONFIG_SHELL-/bin/sh} +export SHELL +# Unset more variables known to interfere with behavior of common tools. +CLICOLOR_FORCE= GREP_OPTIONS= +unset CLICOLOR_FORCE GREP_OPTIONS + +## --------------------- ## +## M4sh Shell Functions. ## +## --------------------- ## +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" + + +} # as_fn_mkdir_p + +# as_fn_executable_p FILE +# ----------------------- +# Test if FILE is an executable regular file. +as_fn_executable_p () +{ + test -f "$1" && test -x "$1" +} # as_fn_executable_p +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with STATUS, using 1 if that was 0. +as_fn_error () +{ + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + fi + $as_echo "$as_me: error: $2" >&2 + as_fn_exit $as_status +} # as_fn_error + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + + + as_lineno_1=$LINENO as_lineno_1a=$LINENO + as_lineno_2=$LINENO as_lineno_2a=$LINENO + eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && + test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { + # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) + sed -n ' + p + /[$]LINENO/= + ' <$as_myself | + sed ' + s/[$]LINENO.*/&-/ + t lineno + b + :lineno + N + :loop + s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ + t loop + s/-\n.*// + ' >$as_me.lineno && + chmod +x "$as_me.lineno" || + { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } + + # If we had to re-execute with $CONFIG_SHELL, we're ensured to have + # already done that, so ensure we don't try to do so again and fall + # in an infinite loop. This has already happened in practice. + _as_can_reexec=no; export _as_can_reexec + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensitive to this). + . "./$as_me.lineno" + # Exit status is that of the last command. + exit +} + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -pR'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -pR' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -pR' + fi +else + as_ln_s='cp -pR' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +as_test_x='test -x' +as_executable_p=as_fn_executable_p + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + +SHELL=${CONFIG_SHELL-/bin/sh} + + +test -n "$DJDIR" || exec 7<&0 &1 + +# Name of the host. +# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, +# so uname gets run too. +ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` + +# +# Initializations. +# +ac_default_prefix=/usr/local +ac_clean_files= +ac_config_libobj_dir=. +LIBOBJS= +cross_compiling=no +subdirs= +MFLAGS= +MAKEFLAGS= + +# Identity of this package. +PACKAGE_NAME= +PACKAGE_TARNAME= +PACKAGE_VERSION= +PACKAGE_STRING= +PACKAGE_BUGREPORT= +PACKAGE_URL= + +ac_unique_file="include/portaudio.h" +# Factoring default headers for most tests. +ac_includes_default="\ +#include +#ifdef HAVE_SYS_TYPES_H +# include +#endif +#ifdef HAVE_SYS_STAT_H +# include +#endif +#ifdef STDC_HEADERS +# include +# include +#else +# ifdef HAVE_STDLIB_H +# include +# endif +#endif +#ifdef HAVE_STRING_H +# if !defined STDC_HEADERS && defined HAVE_MEMORY_H +# include +# endif +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif +#ifdef HAVE_INTTYPES_H +# include +#endif +#ifdef HAVE_STDINT_H +# include +#endif +#ifdef HAVE_UNISTD_H +# include +#endif" + +enable_option_checking=no +ac_subst_vars='LTLIBOBJS +LIBOBJS +WITH_ASIO_FALSE +WITH_ASIO_TRUE +ENABLE_CXX_FALSE +ENABLE_CXX_TRUE +subdirs +INCLUDES +NASMOPT +NASM +DLL_LIBS +THREAD_CFLAGS +SHARED_FLAGS +PADLL +OTHER_OBJS +LT_AGE +LT_REVISION +LT_CURRENT +JACK_LIBS +JACK_CFLAGS +PKG_CONFIG_LIBDIR +PKG_CONFIG_PATH +PKG_CONFIG +INSTALL_DATA +INSTALL_SCRIPT +INSTALL_PROGRAM +CXXCPP +CPP +OTOOL64 +OTOOL +LIPO +NMEDIT +DSYMUTIL +MANIFEST_TOOL +AWK +RANLIB +STRIP +ac_ct_AR +AR +LN_S +NM +ac_ct_DUMPBIN +DUMPBIN +LD +FGREP +EGREP +GREP +SED +LIBTOOL +OBJDUMP +DLLTOOL +AS +ac_ct_CXX +CXXFLAGS +CXX +OBJEXT +EXEEXT +ac_ct_CC +CPPFLAGS +LDFLAGS +CFLAGS +CC +target_os +target_vendor +target_cpu +target +host_os +host_vendor +host_cpu +host +build_os +build_vendor +build_cpu +build +target_alias +host_alias +build_alias +LIBS +ECHO_T +ECHO_N +ECHO_C +DEFS +mandir +localedir +libdir +psdir +pdfdir +dvidir +htmldir +infodir +docdir +oldincludedir +includedir +localstatedir +sharedstatedir +sysconfdir +datadir +datarootdir +libexecdir +sbindir +bindir +program_transform_name +prefix +exec_prefix +PACKAGE_URL +PACKAGE_BUGREPORT +PACKAGE_STRING +PACKAGE_VERSION +PACKAGE_TARNAME +PACKAGE_NAME +PATH_SEPARATOR +SHELL' +ac_subst_files='' +ac_user_opts=' +enable_option_checking +with_alsa +with_jack +with_oss +with_asihpi +with_winapi +with_asiodir +with_dxdir +enable_debug_output +enable_cxx +enable_mac_debug +enable_mac_universal +with_host_os +enable_shared +enable_static +with_pic +enable_fast_install +with_gnu_ld +with_sysroot +enable_libtool_lock +' + ac_precious_vars='build_alias +host_alias +target_alias +CC +CFLAGS +LDFLAGS +LIBS +CPPFLAGS +CXX +CXXFLAGS +CCC +CPP +CXXCPP +PKG_CONFIG +PKG_CONFIG_PATH +PKG_CONFIG_LIBDIR +JACK_CFLAGS +JACK_LIBS' +ac_subdirs_all='bindings/cpp' + +# Initialize some variables set by options. +ac_init_help= +ac_init_version=false +ac_unrecognized_opts= +ac_unrecognized_sep= +# The variables have the same names as the options, with +# dashes changed to underlines. +cache_file=/dev/null +exec_prefix=NONE +no_create= +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +verbose= +x_includes=NONE +x_libraries=NONE + +# Installation directory options. +# These are left unexpanded so users can "make install exec_prefix=/foo" +# and all the variables that are supposed to be based on exec_prefix +# by default will actually change. +# Use braces instead of parens because sh, perl, etc. also accept them. +# (The list follows the same order as the GNU Coding Standards.) +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datarootdir='${prefix}/share' +datadir='${datarootdir}' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +includedir='${prefix}/include' +oldincludedir='/usr/include' +docdir='${datarootdir}/doc/${PACKAGE}' +infodir='${datarootdir}/info' +htmldir='${docdir}' +dvidir='${docdir}' +pdfdir='${docdir}' +psdir='${docdir}' +libdir='${exec_prefix}/lib' +localedir='${datarootdir}/locale' +mandir='${datarootdir}/man' + +ac_prev= +ac_dashdash= +for ac_option +do + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval $ac_prev=\$ac_option + ac_prev= + continue + fi + + case $ac_option in + *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; + *=) ac_optarg= ;; + *) ac_optarg=yes ;; + esac + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case $ac_dashdash$ac_option in + --) + ac_dashdash=yes ;; + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir=$ac_optarg ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build_alias ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build_alias=$ac_optarg ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file=$ac_optarg ;; + + --config-cache | -C) + cache_file=config.cache ;; + + -datadir | --datadir | --datadi | --datad) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=*) + datadir=$ac_optarg ;; + + -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ + | --dataroo | --dataro | --datar) + ac_prev=datarootdir ;; + -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ + | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) + datarootdir=$ac_optarg ;; + + -disable-* | --disable-*) + ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid feature name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=no ;; + + -docdir | --docdir | --docdi | --doc | --do) + ac_prev=docdir ;; + -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) + docdir=$ac_optarg ;; + + -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) + ac_prev=dvidir ;; + -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) + dvidir=$ac_optarg ;; + + -enable-* | --enable-*) + ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid feature name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=\$ac_optarg ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix=$ac_optarg ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he | -h) + ac_init_help=long ;; + -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) + ac_init_help=recursive ;; + -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) + ac_init_help=short ;; + + -host | --host | --hos | --ho) + ac_prev=host_alias ;; + -host=* | --host=* | --hos=* | --ho=*) + host_alias=$ac_optarg ;; + + -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) + ac_prev=htmldir ;; + -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ + | --ht=*) + htmldir=$ac_optarg ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir=$ac_optarg ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir=$ac_optarg ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir=$ac_optarg ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir=$ac_optarg ;; + + -localedir | --localedir | --localedi | --localed | --locale) + ac_prev=localedir ;; + -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) + localedir=$ac_optarg ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst | --locals) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) + localstatedir=$ac_optarg ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir=$ac_optarg ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c | -n) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir=$ac_optarg ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix=$ac_optarg ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix=$ac_optarg ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix=$ac_optarg ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name=$ac_optarg ;; + + -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) + ac_prev=pdfdir ;; + -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) + pdfdir=$ac_optarg ;; + + -psdir | --psdir | --psdi | --psd | --ps) + ac_prev=psdir ;; + -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) + psdir=$ac_optarg ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir=$ac_optarg ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir=$ac_optarg ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site=$ac_optarg ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir=$ac_optarg ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir=$ac_optarg ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target_alias ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target_alias=$ac_optarg ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers | -V) + ac_init_version=: ;; + + -with-* | --with-*) + ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid package name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=\$ac_optarg ;; + + -without-* | --without-*) + ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid package name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=no ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes=$ac_optarg ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries=$ac_optarg ;; + + -*) as_fn_error $? "unrecognized option: \`$ac_option' +Try \`$0 --help' for more information" + ;; + + *=*) + ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` + # Reject names that are not valid shell variable names. + case $ac_envvar in #( + '' | [0-9]* | *[!_$as_cr_alnum]* ) + as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; + esac + eval $ac_envvar=\$ac_optarg + export $ac_envvar ;; + + *) + # FIXME: should be removed in autoconf 3.0. + $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 + expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && + $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 + : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" + ;; + + esac +done + +if test -n "$ac_prev"; then + ac_option=--`echo $ac_prev | sed 's/_/-/g'` + as_fn_error $? "missing argument to $ac_option" +fi + +if test -n "$ac_unrecognized_opts"; then + case $enable_option_checking in + no) ;; + fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; + *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; + esac +fi + +# Check all directory arguments for consistency. +for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ + datadir sysconfdir sharedstatedir localstatedir includedir \ + oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ + libdir localedir mandir +do + eval ac_val=\$$ac_var + # Remove trailing slashes. + case $ac_val in + */ ) + ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` + eval $ac_var=\$ac_val;; + esac + # Be sure to have absolute directory names. + case $ac_val in + [\\/$]* | ?:[\\/]* ) continue;; + NONE | '' ) case $ac_var in *prefix ) continue;; esac;; + esac + as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" +done + +# There might be people who depend on the old broken behavior: `$host' +# used to hold the argument of --host etc. +# FIXME: To remove some day. +build=$build_alias +host=$host_alias +target=$target_alias + +# FIXME: To remove some day. +if test "x$host_alias" != x; then + if test "x$build_alias" = x; then + cross_compiling=maybe + elif test "x$build_alias" != "x$host_alias"; then + cross_compiling=yes + fi +fi + +ac_tool_prefix= +test -n "$host_alias" && ac_tool_prefix=$host_alias- + +test "$silent" = yes && exec 6>/dev/null + + +ac_pwd=`pwd` && test -n "$ac_pwd" && +ac_ls_di=`ls -di .` && +ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || + as_fn_error $? "working directory cannot be determined" +test "X$ac_ls_di" = "X$ac_pwd_ls_di" || + as_fn_error $? "pwd does not report name of working directory" + + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then the parent directory. + ac_confdir=`$as_dirname -- "$as_myself" || +$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_myself" : 'X\(//\)[^/]' \| \ + X"$as_myself" : 'X\(//\)$' \| \ + X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_myself" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + srcdir=$ac_confdir + if test ! -r "$srcdir/$ac_unique_file"; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r "$srcdir/$ac_unique_file"; then + test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." + as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" +fi +ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" +ac_abs_confdir=`( + cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" + pwd)` +# When building in place, set srcdir=. +if test "$ac_abs_confdir" = "$ac_pwd"; then + srcdir=. +fi +# Remove unnecessary trailing slashes from srcdir. +# Double slashes in file names in object file debugging info +# mess up M-x gdb in Emacs. +case $srcdir in +*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; +esac +for ac_var in $ac_precious_vars; do + eval ac_env_${ac_var}_set=\${${ac_var}+set} + eval ac_env_${ac_var}_value=\$${ac_var} + eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} + eval ac_cv_env_${ac_var}_value=\$${ac_var} +done + +# +# Report the --help message. +# +if test "$ac_init_help" = "long"; then + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat <<_ACEOF +\`configure' configures this package to adapt to many kinds of systems. + +Usage: $0 [OPTION]... [VAR=VALUE]... + +To assign environment variables (e.g., CC, CFLAGS...), specify them as +VAR=VALUE. See below for descriptions of some of the useful variables. + +Defaults for the options are specified in brackets. + +Configuration: + -h, --help display this help and exit + --help=short display options specific to this package + --help=recursive display the short help of all the included packages + -V, --version display version information and exit + -q, --quiet, --silent do not print \`checking ...' messages + --cache-file=FILE cache test results in FILE [disabled] + -C, --config-cache alias for \`--cache-file=config.cache' + -n, --no-create do not create output files + --srcdir=DIR find the sources in DIR [configure dir or \`..'] + +Installation directories: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [PREFIX] + +By default, \`make install' will install all the files in +\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify +an installation prefix other than \`$ac_default_prefix' using \`--prefix', +for instance \`--prefix=\$HOME'. + +For better control, use the options below. + +Fine tuning of the installation directories: + --bindir=DIR user executables [EPREFIX/bin] + --sbindir=DIR system admin executables [EPREFIX/sbin] + --libexecdir=DIR program executables [EPREFIX/libexec] + --sysconfdir=DIR read-only single-machine data [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] + --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --libdir=DIR object code libraries [EPREFIX/lib] + --includedir=DIR C header files [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc [/usr/include] + --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] + --datadir=DIR read-only architecture-independent data [DATAROOTDIR] + --infodir=DIR info documentation [DATAROOTDIR/info] + --localedir=DIR locale-dependent data [DATAROOTDIR/locale] + --mandir=DIR man documentation [DATAROOTDIR/man] + --docdir=DIR documentation root [DATAROOTDIR/doc/PACKAGE] + --htmldir=DIR html documentation [DOCDIR] + --dvidir=DIR dvi documentation [DOCDIR] + --pdfdir=DIR pdf documentation [DOCDIR] + --psdir=DIR ps documentation [DOCDIR] +_ACEOF + + cat <<\_ACEOF + +System types: + --build=BUILD configure for building on BUILD [guessed] + --host=HOST cross-compile to build programs to run on HOST [BUILD] + --target=TARGET configure for building compilers for TARGET [HOST] +_ACEOF +fi + +if test -n "$ac_init_help"; then + + cat <<\_ACEOF + +Optional Features: + --disable-option-checking ignore unrecognized --enable/--with options + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --enable-debug-output Enable debug output [no] + --enable-cxx Enable C++ bindings [no] + --enable-mac-debug Enable Mac debug [no] + --enable-mac-universal Build Mac universal binaries [yes] + --enable-shared[=PKGS] build shared libraries [default=yes] + --enable-static[=PKGS] build static libraries [default=yes] + --enable-fast-install[=PKGS] + optimize for fast installation [default=yes] + --disable-libtool-lock avoid locking (might break parallel builds) + +Optional Packages: + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --with-alsa Enable support for ALSA [autodetect] + --with-jack Enable support for JACK [autodetect] + --with-oss Enable support for OSS [autodetect] + --with-asihpi Enable support for ASIHPI [autodetect] + --with-winapi Select Windows API support + ([wmme|directx|asio|wasapi|wdmks][,...]) [wmme] + --with-asiodir ASIO directory [/usr/local/asiosdk2] + --with-dxdir DirectX directory [/usr/local/dx7sdk] + + --with-pic[=PKGS] try to use only PIC/non-PIC objects [default=use + both] + --with-gnu-ld assume the C compiler uses GNU ld [default=no] + --with-sysroot=DIR Search for dependent libraries within DIR + (or the compiler's sysroot if not specified). + +Some influential environment variables: + CC C compiler command + CFLAGS C compiler flags + LDFLAGS linker flags, e.g. -L if you have libraries in a + nonstandard directory + LIBS libraries to pass to the linker, e.g. -l + CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if + you have headers in a nonstandard directory + CXX C++ compiler command + CXXFLAGS C++ compiler flags + CPP C preprocessor + CXXCPP C++ preprocessor + PKG_CONFIG path to pkg-config utility + PKG_CONFIG_PATH + directories to add to pkg-config's search path + PKG_CONFIG_LIBDIR + path overriding pkg-config's built-in search path + JACK_CFLAGS C compiler flags for JACK, overriding pkg-config + JACK_LIBS linker flags for JACK, overriding pkg-config + +Use these variables to override the choices made by `configure' or to help +it to find libraries and programs with nonstandard names/locations. + +Report bugs to the package provider. +_ACEOF +ac_status=$? +fi + +if test "$ac_init_help" = "recursive"; then + # If there are subdirs, report their specific --help. + for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue + test -d "$ac_dir" || + { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || + continue + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + cd "$ac_dir" || { ac_status=$?; continue; } + # Check for guested configure. + if test -f "$ac_srcdir/configure.gnu"; then + echo && + $SHELL "$ac_srcdir/configure.gnu" --help=recursive + elif test -f "$ac_srcdir/configure"; then + echo && + $SHELL "$ac_srcdir/configure" --help=recursive + else + $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 + fi || ac_status=$? + cd "$ac_pwd" || { ac_status=$?; break; } + done +fi + +test -n "$ac_init_help" && exit $ac_status +if $ac_init_version; then + cat <<\_ACEOF +configure +generated by GNU Autoconf 2.69 + +Copyright (C) 2012 Free Software Foundation, Inc. +This configure script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it. +_ACEOF + exit +fi + +## ------------------------ ## +## Autoconf initialization. ## +## ------------------------ ## + +# ac_fn_c_try_compile LINENO +# -------------------------- +# Try to compile conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext + if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_compile + +# ac_fn_cxx_try_compile LINENO +# ---------------------------- +# Try to compile conftest.$ac_ext, and return whether this succeeded. +ac_fn_cxx_try_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext + if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_cxx_try_compile + +# ac_fn_c_try_link LINENO +# ----------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_link () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext conftest$ac_exeext + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + test -x conftest$ac_exeext + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information + # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would + # interfere with the next link command; also delete a directory that is + # left behind by Apple's compiler. We do this before executing the actions. + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_link + +# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES +# ------------------------------------------------------- +# Tests whether HEADER exists and can be compiled using the include files in +# INCLUDES, setting the cache variable VAR accordingly. +ac_fn_c_check_header_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +#include <$2> +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + eval "$3=yes" +else + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_header_compile + +# ac_fn_c_try_cpp LINENO +# ---------------------- +# Try to preprocess conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_cpp () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } > conftest.i && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_cpp + +# ac_fn_c_try_run LINENO +# ---------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes +# that executables *can* be run. +ac_fn_c_try_run () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then : + ac_retval=0 +else + $as_echo "$as_me: program exited with status $ac_status" >&5 + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=$ac_status +fi + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_run + +# ac_fn_c_check_func LINENO FUNC VAR +# ---------------------------------- +# Tests whether FUNC exists, setting the cache variable VAR accordingly +ac_fn_c_check_func () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +/* Define $2 to an innocuous variant, in case declares $2. + For example, HP-UX 11i declares gettimeofday. */ +#define $2 innocuous_$2 + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $2 (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $2 + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char $2 (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_$2 || defined __stub___$2 +choke me +#endif + +int +main () +{ +return $2 (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + eval "$3=yes" +else + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_func + +# ac_fn_cxx_try_cpp LINENO +# ------------------------ +# Try to preprocess conftest.$ac_ext, and return whether this succeeded. +ac_fn_cxx_try_cpp () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } > conftest.i && { + test -z "$ac_cxx_preproc_warn_flag$ac_cxx_werror_flag" || + test ! -s conftest.err + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_cxx_try_cpp + +# ac_fn_cxx_try_link LINENO +# ------------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. +ac_fn_cxx_try_link () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext conftest$ac_exeext + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + test -x conftest$ac_exeext + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information + # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would + # interfere with the next link command; also delete a directory that is + # left behind by Apple's compiler. We do this before executing the actions. + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_cxx_try_link + +# ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES +# ------------------------------------------------------- +# Tests whether HEADER exists, giving a warning if it cannot be compiled using +# the include files in INCLUDES and setting the cache variable VAR +# accordingly. +ac_fn_c_check_header_mongrel () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if eval \${$3+:} false; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +else + # Is the header compilable? +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 +$as_echo_n "checking $2 usability... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +#include <$2> +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_header_compiler=yes +else + ac_header_compiler=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 +$as_echo "$ac_header_compiler" >&6; } + +# Is the header present? +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 +$as_echo_n "checking $2 presence... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <$2> +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + ac_header_preproc=yes +else + ac_header_preproc=no +fi +rm -f conftest.err conftest.i conftest.$ac_ext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 +$as_echo "$ac_header_preproc" >&6; } + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #(( + yes:no: ) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 +$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 +$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} + ;; + no:yes:* ) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 +$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 +$as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 +$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 +$as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 +$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} + ;; +esac + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + eval "$3=\$ac_header_compiler" +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_header_mongrel + +# ac_fn_c_compute_int LINENO EXPR VAR INCLUDES +# -------------------------------------------- +# Tries to find the compile-time value of EXPR in a program that includes +# INCLUDES, setting VAR accordingly. Returns whether the value could be +# computed +ac_fn_c_compute_int () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if test "$cross_compiling" = yes; then + # Depending upon the size, compute the lo and hi bounds. +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +static int test_array [1 - 2 * !(($2) >= 0)]; +test_array [0] = 0; +return test_array [0]; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_lo=0 ac_mid=0 + while :; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +static int test_array [1 - 2 * !(($2) <= $ac_mid)]; +test_array [0] = 0; +return test_array [0]; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_hi=$ac_mid; break +else + as_fn_arith $ac_mid + 1 && ac_lo=$as_val + if test $ac_lo -le $ac_mid; then + ac_lo= ac_hi= + break + fi + as_fn_arith 2 '*' $ac_mid + 1 && ac_mid=$as_val +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + done +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +static int test_array [1 - 2 * !(($2) < 0)]; +test_array [0] = 0; +return test_array [0]; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_hi=-1 ac_mid=-1 + while :; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +static int test_array [1 - 2 * !(($2) >= $ac_mid)]; +test_array [0] = 0; +return test_array [0]; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_lo=$ac_mid; break +else + as_fn_arith '(' $ac_mid ')' - 1 && ac_hi=$as_val + if test $ac_mid -le $ac_hi; then + ac_lo= ac_hi= + break + fi + as_fn_arith 2 '*' $ac_mid && ac_mid=$as_val +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + done +else + ac_lo= ac_hi= +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +# Binary search between lo and hi bounds. +while test "x$ac_lo" != "x$ac_hi"; do + as_fn_arith '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo && ac_mid=$as_val + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +static int test_array [1 - 2 * !(($2) <= $ac_mid)]; +test_array [0] = 0; +return test_array [0]; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_hi=$ac_mid +else + as_fn_arith '(' $ac_mid ')' + 1 && ac_lo=$as_val +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +done +case $ac_lo in #(( +?*) eval "$3=\$ac_lo"; ac_retval=0 ;; +'') ac_retval=1 ;; +esac + else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +static long int longval () { return $2; } +static unsigned long int ulongval () { return $2; } +#include +#include +int +main () +{ + + FILE *f = fopen ("conftest.val", "w"); + if (! f) + return 1; + if (($2) < 0) + { + long int i = longval (); + if (i != ($2)) + return 1; + fprintf (f, "%ld", i); + } + else + { + unsigned long int i = ulongval (); + if (i != ($2)) + return 1; + fprintf (f, "%lu", i); + } + /* Do not output a trailing newline, as this causes \r\n confusion + on some platforms. */ + return ferror (f) || fclose (f) != 0; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + echo >>conftest.val; read $3 config.log <<_ACEOF +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. + +It was created by $as_me, which was +generated by GNU Autoconf 2.69. Invocation command line was + + $ $0 $@ + +_ACEOF +exec 5>>config.log +{ +cat <<_ASUNAME +## --------- ## +## Platform. ## +## --------- ## + +hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` + +/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` +/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` +/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` +/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` + +_ASUNAME + +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + $as_echo "PATH: $as_dir" + done +IFS=$as_save_IFS + +} >&5 + +cat >&5 <<_ACEOF + + +## ----------- ## +## Core tests. ## +## ----------- ## + +_ACEOF + + +# Keep a trace of the command line. +# Strip out --no-create and --no-recursion so they do not pile up. +# Strip out --silent because we don't want to record it for future runs. +# Also quote any args containing shell meta-characters. +# Make two passes to allow for proper duplicate-argument suppression. +ac_configure_args= +ac_configure_args0= +ac_configure_args1= +ac_must_keep_next=false +for ac_pass in 1 2 +do + for ac_arg + do + case $ac_arg in + -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + continue ;; + *\'*) + ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + case $ac_pass in + 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; + 2) + as_fn_append ac_configure_args1 " '$ac_arg'" + if test $ac_must_keep_next = true; then + ac_must_keep_next=false # Got value, back to normal. + else + case $ac_arg in + *=* | --config-cache | -C | -disable-* | --disable-* \ + | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ + | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ + | -with-* | --with-* | -without-* | --without-* | --x) + case "$ac_configure_args0 " in + "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; + esac + ;; + -* ) ac_must_keep_next=true ;; + esac + fi + as_fn_append ac_configure_args " '$ac_arg'" + ;; + esac + done +done +{ ac_configure_args0=; unset ac_configure_args0;} +{ ac_configure_args1=; unset ac_configure_args1;} + +# When interrupted or exit'd, cleanup temporary files, and complete +# config.log. We remove comments because anyway the quotes in there +# would cause problems or look ugly. +# WARNING: Use '\'' to represent an apostrophe within the trap. +# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. +trap 'exit_status=$? + # Save into config.log some information that might help in debugging. + { + echo + + $as_echo "## ---------------- ## +## Cache variables. ## +## ---------------- ##" + echo + # The following way of writing the cache mishandles newlines in values, +( + for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done + (set) 2>&1 | + case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + sed -n \ + "s/'\''/'\''\\\\'\'''\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" + ;; #( + *) + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) + echo + + $as_echo "## ----------------- ## +## Output variables. ## +## ----------------- ##" + echo + for ac_var in $ac_subst_vars + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + + if test -n "$ac_subst_files"; then + $as_echo "## ------------------- ## +## File substitutions. ## +## ------------------- ##" + echo + for ac_var in $ac_subst_files + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + fi + + if test -s confdefs.h; then + $as_echo "## ----------- ## +## confdefs.h. ## +## ----------- ##" + echo + cat confdefs.h + echo + fi + test "$ac_signal" != 0 && + $as_echo "$as_me: caught signal $ac_signal" + $as_echo "$as_me: exit $exit_status" + } >&5 + rm -f core *.core core.conftest.* && + rm -f -r conftest* confdefs* conf$$* $ac_clean_files && + exit $exit_status +' 0 +for ac_signal in 1 2 13 15; do + trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal +done +ac_signal=0 + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -f -r conftest* confdefs.h + +$as_echo "/* confdefs.h */" > confdefs.h + +# Predefined preprocessor variables. + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_NAME "$PACKAGE_NAME" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_TARNAME "$PACKAGE_TARNAME" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_VERSION "$PACKAGE_VERSION" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_STRING "$PACKAGE_STRING" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_URL "$PACKAGE_URL" +_ACEOF + + +# Let the site file select an alternate cache file if it wants to. +# Prefer an explicitly selected file to automatically selected ones. +ac_site_file1=NONE +ac_site_file2=NONE +if test -n "$CONFIG_SITE"; then + # We do not want a PATH search for config.site. + case $CONFIG_SITE in #(( + -*) ac_site_file1=./$CONFIG_SITE;; + */*) ac_site_file1=$CONFIG_SITE;; + *) ac_site_file1=./$CONFIG_SITE;; + esac +elif test "x$prefix" != xNONE; then + ac_site_file1=$prefix/share/config.site + ac_site_file2=$prefix/etc/config.site +else + ac_site_file1=$ac_default_prefix/share/config.site + ac_site_file2=$ac_default_prefix/etc/config.site +fi +for ac_site_file in "$ac_site_file1" "$ac_site_file2" +do + test "x$ac_site_file" = xNONE && continue + if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 +$as_echo "$as_me: loading site script $ac_site_file" >&6;} + sed 's/^/| /' "$ac_site_file" >&5 + . "$ac_site_file" \ + || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "failed to load site script $ac_site_file +See \`config.log' for more details" "$LINENO" 5; } + fi +done + +if test -r "$cache_file"; then + # Some versions of bash will fail to source /dev/null (special files + # actually), so we avoid doing that. DJGPP emulates it as a regular file. + if test /dev/null != "$cache_file" && test -f "$cache_file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 +$as_echo "$as_me: loading cache $cache_file" >&6;} + case $cache_file in + [\\/]* | ?:[\\/]* ) . "$cache_file";; + *) . "./$cache_file";; + esac + fi +else + { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 +$as_echo "$as_me: creating cache $cache_file" >&6;} + >$cache_file +fi + +# Check that the precious variables saved in the cache have kept the same +# value. +ac_cache_corrupted=false +for ac_var in $ac_precious_vars; do + eval ac_old_set=\$ac_cv_env_${ac_var}_set + eval ac_new_set=\$ac_env_${ac_var}_set + eval ac_old_val=\$ac_cv_env_${ac_var}_value + eval ac_new_val=\$ac_env_${ac_var}_value + case $ac_old_set,$ac_new_set in + set,) + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,set) + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,);; + *) + if test "x$ac_old_val" != "x$ac_new_val"; then + # differences in whitespace do not lead to failure. + ac_old_val_w=`echo x $ac_old_val` + ac_new_val_w=`echo x $ac_new_val` + if test "$ac_old_val_w" != "$ac_new_val_w"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 +$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + ac_cache_corrupted=: + else + { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 +$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} + eval $ac_var=\$ac_old_val + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 +$as_echo "$as_me: former value: \`$ac_old_val'" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 +$as_echo "$as_me: current value: \`$ac_new_val'" >&2;} + fi;; + esac + # Pass precious variables to config.status. + if test "$ac_new_set" = set; then + case $ac_new_val in + *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; + *) ac_arg=$ac_var=$ac_new_val ;; + esac + case " $ac_configure_args " in + *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. + *) as_fn_append ac_configure_args " '$ac_arg'" ;; + esac + fi +done +if $ac_cache_corrupted; then + { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 +$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} + as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 +fi +## -------------------- ## +## Main body of script. ## +## -------------------- ## + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + +ac_aux_dir= +for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do + if test -f "$ac_dir/install-sh"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f "$ac_dir/install.sh"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + elif test -f "$ac_dir/shtool"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/shtool install -c" + break + fi +done +if test -z "$ac_aux_dir"; then + as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5 +fi + +# These three variables are undocumented and unsupported, +# and are intended to be withdrawn in a future Autoconf release. +# They can cause serious problems if a builder's source tree is in a directory +# whose full name contains unusual characters. +ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. +ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. +ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. + + +# Make sure we can run config.sub. +$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || + as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5 + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 +$as_echo_n "checking build system type... " >&6; } +if ${ac_cv_build+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_build_alias=$build_alias +test "x$ac_build_alias" = x && + ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` +test "x$ac_build_alias" = x && + as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 +ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` || + as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5 + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 +$as_echo "$ac_cv_build" >&6; } +case $ac_cv_build in +*-*-*) ;; +*) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;; +esac +build=$ac_cv_build +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_build +shift +build_cpu=$1 +build_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +build_os=$* +IFS=$ac_save_IFS +case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 +$as_echo_n "checking host system type... " >&6; } +if ${ac_cv_host+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test "x$host_alias" = x; then + ac_cv_host=$ac_cv_build +else + ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || + as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5 +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 +$as_echo "$ac_cv_host" >&6; } +case $ac_cv_host in +*-*-*) ;; +*) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;; +esac +host=$ac_cv_host +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_host +shift +host_cpu=$1 +host_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +host_os=$* +IFS=$ac_save_IFS +case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking target system type" >&5 +$as_echo_n "checking target system type... " >&6; } +if ${ac_cv_target+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test "x$target_alias" = x; then + ac_cv_target=$ac_cv_host +else + ac_cv_target=`$SHELL "$ac_aux_dir/config.sub" $target_alias` || + as_fn_error $? "$SHELL $ac_aux_dir/config.sub $target_alias failed" "$LINENO" 5 +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_target" >&5 +$as_echo "$ac_cv_target" >&6; } +case $ac_cv_target in +*-*-*) ;; +*) as_fn_error $? "invalid value of canonical target" "$LINENO" 5;; +esac +target=$ac_cv_target +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_target +shift +target_cpu=$1 +target_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +target_os=$* +IFS=$ac_save_IFS +case $target_os in *\ *) target_os=`echo "$target_os" | sed 's/ /-/g'`;; esac + + +# The aliases save the names the user supplied, while $host etc. +# will get canonicalized. +test -n "$target_alias" && + test "$program_prefix$program_suffix$program_transform_name" = \ + NONENONEs,x,x, && + program_prefix=${target_alias}- + + + +# Check whether --with-alsa was given. +if test "${with_alsa+set}" = set; then : + withval=$with_alsa; with_alsa=$withval +fi + + + +# Check whether --with-jack was given. +if test "${with_jack+set}" = set; then : + withval=$with_jack; with_jack=$withval +fi + + + +# Check whether --with-oss was given. +if test "${with_oss+set}" = set; then : + withval=$with_oss; with_oss=$withval +fi + + + +# Check whether --with-asihpi was given. +if test "${with_asihpi+set}" = set; then : + withval=$with_asihpi; with_asihpi=$withval +fi + + + +# Check whether --with-winapi was given. +if test "${with_winapi+set}" = set; then : + withval=$with_winapi; with_winapi=$withval +else + with_winapi="wmme" +fi + +case "$target_os" in *mingw* | *cygwin*) + with_wmme=no + with_directx=no + with_asio=no + with_wasapi=no + with_wdmks=no + for api in $(echo $with_winapi | sed 's/,/ /g'); do + case "$api" in + wmme|directx|asio|wasapi|wdmks) + eval with_$api=yes + ;; + *) + as_fn_error $? "unknown Windows API \"$api\" (do you need --help?)" "$LINENO" 5 + ;; + esac + done + ;; +esac + + +# Check whether --with-asiodir was given. +if test "${with_asiodir+set}" = set; then : + withval=$with_asiodir; with_asiodir=$withval +else + with_asiodir="/usr/local/asiosdk2" +fi + + + +# Check whether --with-dxdir was given. +if test "${with_dxdir+set}" = set; then : + withval=$with_dxdir; with_dxdir=$withval +else + with_dxdir="/usr/local/dx7sdk" +fi + + +debug_output=no +# Check whether --enable-debug-output was given. +if test "${enable_debug_output+set}" = set; then : + enableval=$enable_debug_output; if test "x$enableval" != "xno" ; then + +$as_echo "#define PA_ENABLE_DEBUG_OUTPUT /**/" >>confdefs.h + + debug_output=yes + fi + +fi + + +# Check whether --enable-cxx was given. +if test "${enable_cxx+set}" = set; then : + enableval=$enable_cxx; enable_cxx=$enableval +else + enable_cxx="no" +fi + + +# Check whether --enable-mac-debug was given. +if test "${enable_mac_debug+set}" = set; then : + enableval=$enable_mac_debug; enable_mac_debug=$enableval +else + enable_mac_debug="no" +fi + + +# Check whether --enable-mac-universal was given. +if test "${enable_mac_universal+set}" = set; then : + enableval=$enable_mac_universal; enable_mac_universal=$enableval +else + enable_mac_universal="yes" +fi + + + +# Check whether --with-host_os was given. +if test "${with_host_os+set}" = set; then : + withval=$with_host_os; host_os=$withval +fi + + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. +set dummy ${ac_tool_prefix}gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +else + CC="$ac_cv_prog_CC" +fi + +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. +set dummy ${ac_tool_prefix}cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + fi +fi +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + ac_prog_rejected=no +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# != 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" + fi +fi +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + for ac_prog in cl.exe + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$CC" && break + done +fi +if test -z "$CC"; then + ac_ct_CC=$CC + for ac_prog in cl.exe +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_CC" && break +done + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +fi + +fi + + +test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "no acceptable C compiler found in \$PATH +See \`config.log' for more details" "$LINENO" 5; } + +# Provide some information about the compiler. +$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 +set X $ac_compile +ac_compiler=$2 +for ac_option in --version -v -V -qversion; do + { { ac_try="$ac_compiler $ac_option >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compiler $ac_option >&5") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + sed '10a\ +... rest of stderr output deleted ... + 10q' conftest.err >conftest.er1 + cat conftest.er1 >&5 + fi + rm -f conftest.er1 conftest.err + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +done + +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" +# Try to create an executable without -o first, disregard a.out. +# It will help us diagnose broken compilers, and finding out an intuition +# of exeext. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 +$as_echo_n "checking whether the C compiler works... " >&6; } +ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` + +# The possible output files: +ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" + +ac_rmfiles= +for ac_file in $ac_files +do + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; + * ) ac_rmfiles="$ac_rmfiles $ac_file";; + esac +done +rm -f $ac_rmfiles + +if { { ac_try="$ac_link_default" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link_default") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. +# So ignore a value of `no', otherwise this would lead to `EXEEXT = no' +# in a Makefile. We should not override ac_cv_exeext if it was cached, +# so that the user can short-circuit this test for compilers unknown to +# Autoconf. +for ac_file in $ac_files '' +do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) + ;; + [ab].out ) + # We found the default executable, but exeext='' is most + # certainly right. + break;; + *.* ) + if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; + then :; else + ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + fi + # We set ac_cv_exeext here because the later test for it is not + # safe: cross compilers may not add the suffix if given an `-o' + # argument, so we may need to know it at that point already. + # Even if this section looks crufty: it has the advantage of + # actually working. + break;; + * ) + break;; + esac +done +test "$ac_cv_exeext" = no && ac_cv_exeext= + +else + ac_file='' +fi +if test -z "$ac_file"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +$as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error 77 "C compiler cannot create executables +See \`config.log' for more details" "$LINENO" 5; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 +$as_echo_n "checking for C compiler default output file name... " >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 +$as_echo "$ac_file" >&6; } +ac_exeext=$ac_cv_exeext + +rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out +ac_clean_files=$ac_clean_files_save +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 +$as_echo_n "checking for suffix of executables... " >&6; } +if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + # If both `conftest.exe' and `conftest' are `present' (well, observable) +# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will +# work properly (i.e., refer to `conftest.exe'), while it won't with +# `rm'. +for ac_file in conftest.exe conftest conftest.*; do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; + *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + break;; + * ) break;; + esac +done +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details" "$LINENO" 5; } +fi +rm -f conftest conftest$ac_cv_exeext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 +$as_echo "$ac_cv_exeext" >&6; } + +rm -f conftest.$ac_ext +EXEEXT=$ac_cv_exeext +ac_exeext=$EXEEXT +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +FILE *f = fopen ("conftest.out", "w"); + return ferror (f) || fclose (f) != 0; + + ; + return 0; +} +_ACEOF +ac_clean_files="$ac_clean_files conftest.out" +# Check that the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 +$as_echo_n "checking whether we are cross compiling... " >&6; } +if test "$cross_compiling" != yes; then + { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + if { ac_try='./conftest$ac_cv_exeext' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then + cross_compiling=no + else + if test "$cross_compiling" = maybe; then + cross_compiling=yes + else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details" "$LINENO" 5; } + fi + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 +$as_echo "$cross_compiling" >&6; } + +rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out +ac_clean_files=$ac_clean_files_save +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 +$as_echo_n "checking for suffix of object files... " >&6; } +if ${ac_cv_objext+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.o conftest.obj +if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + for ac_file in conftest.o conftest.obj conftest.*; do + test -f "$ac_file" || continue; + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; + *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` + break;; + esac +done +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot compute suffix of object files: cannot compile +See \`config.log' for more details" "$LINENO" 5; } +fi +rm -f conftest.$ac_cv_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 +$as_echo "$ac_cv_objext" >&6; } +OBJEXT=$ac_cv_objext +ac_objext=$OBJEXT +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 +$as_echo_n "checking whether we are using the GNU C compiler... " >&6; } +if ${ac_cv_c_compiler_gnu+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_compiler_gnu=yes +else + ac_compiler_gnu=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_c_compiler_gnu=$ac_compiler_gnu + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 +$as_echo "$ac_cv_c_compiler_gnu" >&6; } +if test $ac_compiler_gnu = yes; then + GCC=yes +else + GCC= +fi +ac_test_CFLAGS=${CFLAGS+set} +ac_save_CFLAGS=$CFLAGS +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 +$as_echo_n "checking whether $CC accepts -g... " >&6; } +if ${ac_cv_prog_cc_g+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_save_c_werror_flag=$ac_c_werror_flag + ac_c_werror_flag=yes + ac_cv_prog_cc_g=no + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +else + CFLAGS="" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +else + ac_c_werror_flag=$ac_save_c_werror_flag + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_c_werror_flag=$ac_save_c_werror_flag +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 +$as_echo "$ac_cv_prog_cc_g" >&6; } +if test "$ac_test_CFLAGS" = set; then + CFLAGS=$ac_save_CFLAGS +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 +$as_echo_n "checking for $CC option to accept ISO C89... " >&6; } +if ${ac_cv_prog_cc_c89+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_cv_prog_cc_c89=no +ac_save_CC=$CC +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +struct stat; +/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ +struct buf { int x; }; +FILE * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (p, i) + char **p; + int i; +{ + return p[i]; +} +static char *f (char * (*g) (char **, int), char **p, ...) +{ + char *s; + va_list v; + va_start (v,p); + s = g (p, va_arg (v,int)); + va_end (v); + return s; +} + +/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has + function prototypes and stuff, but not '\xHH' hex character constants. + These don't provoke an error unfortunately, instead are silently treated + as 'x'. The following induces an error, until -std is added to get + proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an + array size at least. It's necessary to write '\x00'==0 to get something + that's true only with -std. */ +int osf4_cc_array ['\x00' == 0 ? 1 : -1]; + +/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters + inside strings and character constants. */ +#define FOO(x) 'x' +int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; + +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); +int argc; +char **argv; +int +main () +{ +return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; + ; + return 0; +} +_ACEOF +for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ + -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +do + CC="$ac_save_CC $ac_arg" + if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_c89=$ac_arg +fi +rm -f core conftest.err conftest.$ac_objext + test "x$ac_cv_prog_cc_c89" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC + +fi +# AC_CACHE_VAL +case "x$ac_cv_prog_cc_c89" in + x) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +$as_echo "none needed" >&6; } ;; + xno) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +$as_echo "unsupported" >&6; } ;; + *) + CC="$CC $ac_cv_prog_cc_c89" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 +$as_echo "$ac_cv_prog_cc_c89" >&6; } ;; +esac +if test "x$ac_cv_prog_cc_c89" != xno; then : + +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +if [ "$with_asio" = "yes" ] || [ "$enable_cxx" = "yes" ] ; then + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu +if test -z "$CXX"; then + if test -n "$CCC"; then + CXX=$CCC + else + if test -n "$ac_tool_prefix"; then + for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CXX+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CXX"; then + ac_cv_prog_CXX="$CXX" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CXX="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CXX=$ac_cv_prog_CXX +if test -n "$CXX"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5 +$as_echo "$CXX" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$CXX" && break + done +fi +if test -z "$CXX"; then + ac_ct_CXX=$CXX + for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_CXX+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CXX"; then + ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CXX="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CXX=$ac_cv_prog_ac_ct_CXX +if test -n "$ac_ct_CXX"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CXX" >&5 +$as_echo "$ac_ct_CXX" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_CXX" && break +done + + if test "x$ac_ct_CXX" = x; then + CXX="g++" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CXX=$ac_ct_CXX + fi +fi + + fi +fi +# Provide some information about the compiler. +$as_echo "$as_me:${as_lineno-$LINENO}: checking for C++ compiler version" >&5 +set X $ac_compile +ac_compiler=$2 +for ac_option in --version -v -V -qversion; do + { { ac_try="$ac_compiler $ac_option >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compiler $ac_option >&5") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + sed '10a\ +... rest of stderr output deleted ... + 10q' conftest.err >conftest.er1 + cat conftest.er1 >&5 + fi + rm -f conftest.er1 conftest.err + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +done + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C++ compiler" >&5 +$as_echo_n "checking whether we are using the GNU C++ compiler... " >&6; } +if ${ac_cv_cxx_compiler_gnu+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_compiler_gnu=yes +else + ac_compiler_gnu=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_cxx_compiler_gnu=$ac_compiler_gnu + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_compiler_gnu" >&5 +$as_echo "$ac_cv_cxx_compiler_gnu" >&6; } +if test $ac_compiler_gnu = yes; then + GXX=yes +else + GXX= +fi +ac_test_CXXFLAGS=${CXXFLAGS+set} +ac_save_CXXFLAGS=$CXXFLAGS +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -g" >&5 +$as_echo_n "checking whether $CXX accepts -g... " >&6; } +if ${ac_cv_prog_cxx_g+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_save_cxx_werror_flag=$ac_cxx_werror_flag + ac_cxx_werror_flag=yes + ac_cv_prog_cxx_g=no + CXXFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_cv_prog_cxx_g=yes +else + CXXFLAGS="" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + +else + ac_cxx_werror_flag=$ac_save_cxx_werror_flag + CXXFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_cv_prog_cxx_g=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_cxx_werror_flag=$ac_save_cxx_werror_flag +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_g" >&5 +$as_echo "$ac_cv_prog_cxx_g" >&6; } +if test "$ac_test_CXXFLAGS" = set; then + CXXFLAGS=$ac_save_CXXFLAGS +elif test $ac_cv_prog_cxx_g = yes; then + if test "$GXX" = yes; then + CXXFLAGS="-g -O2" + else + CXXFLAGS="-g" + fi +else + if test "$GXX" = yes; then + CXXFLAGS="-O2" + else + CXXFLAGS= + fi +fi +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +fi +enable_win32_dll=yes + +case $host in +*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-cegcc*) + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}as", so it can be a program name with args. +set dummy ${ac_tool_prefix}as; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_AS+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$AS"; then + ac_cv_prog_AS="$AS" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_AS="${ac_tool_prefix}as" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +AS=$ac_cv_prog_AS +if test -n "$AS"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AS" >&5 +$as_echo "$AS" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_AS"; then + ac_ct_AS=$AS + # Extract the first word of "as", so it can be a program name with args. +set dummy as; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_AS+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_AS"; then + ac_cv_prog_ac_ct_AS="$ac_ct_AS" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_AS="as" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_AS=$ac_cv_prog_ac_ct_AS +if test -n "$ac_ct_AS"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AS" >&5 +$as_echo "$ac_ct_AS" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_AS" = x; then + AS="false" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + AS=$ac_ct_AS + fi +else + AS="$ac_cv_prog_AS" +fi + + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}dlltool", so it can be a program name with args. +set dummy ${ac_tool_prefix}dlltool; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_DLLTOOL+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$DLLTOOL"; then + ac_cv_prog_DLLTOOL="$DLLTOOL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_DLLTOOL="${ac_tool_prefix}dlltool" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +DLLTOOL=$ac_cv_prog_DLLTOOL +if test -n "$DLLTOOL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DLLTOOL" >&5 +$as_echo "$DLLTOOL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_DLLTOOL"; then + ac_ct_DLLTOOL=$DLLTOOL + # Extract the first word of "dlltool", so it can be a program name with args. +set dummy dlltool; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_DLLTOOL+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_DLLTOOL"; then + ac_cv_prog_ac_ct_DLLTOOL="$ac_ct_DLLTOOL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_DLLTOOL="dlltool" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_DLLTOOL=$ac_cv_prog_ac_ct_DLLTOOL +if test -n "$ac_ct_DLLTOOL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DLLTOOL" >&5 +$as_echo "$ac_ct_DLLTOOL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_DLLTOOL" = x; then + DLLTOOL="false" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + DLLTOOL=$ac_ct_DLLTOOL + fi +else + DLLTOOL="$ac_cv_prog_DLLTOOL" +fi + + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}objdump", so it can be a program name with args. +set dummy ${ac_tool_prefix}objdump; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_OBJDUMP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$OBJDUMP"; then + ac_cv_prog_OBJDUMP="$OBJDUMP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_OBJDUMP="${ac_tool_prefix}objdump" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +OBJDUMP=$ac_cv_prog_OBJDUMP +if test -n "$OBJDUMP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OBJDUMP" >&5 +$as_echo "$OBJDUMP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_OBJDUMP"; then + ac_ct_OBJDUMP=$OBJDUMP + # Extract the first word of "objdump", so it can be a program name with args. +set dummy objdump; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_OBJDUMP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_OBJDUMP"; then + ac_cv_prog_ac_ct_OBJDUMP="$ac_ct_OBJDUMP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_OBJDUMP="objdump" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_OBJDUMP=$ac_cv_prog_ac_ct_OBJDUMP +if test -n "$ac_ct_OBJDUMP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OBJDUMP" >&5 +$as_echo "$ac_ct_OBJDUMP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_OBJDUMP" = x; then + OBJDUMP="false" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + OBJDUMP=$ac_ct_OBJDUMP + fi +else + OBJDUMP="$ac_cv_prog_OBJDUMP" +fi + + ;; +esac + +test -z "$AS" && AS=as + + + + + +test -z "$DLLTOOL" && DLLTOOL=dlltool + + + + + +test -z "$OBJDUMP" && OBJDUMP=objdump + + + + + + + +case `pwd` in + *\ * | *\ *) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&5 +$as_echo "$as_me: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&2;} ;; +esac + + + +macro_version='2.4.2' +macro_revision='1.3337' + + + + + + + + + + + + + +ltmain="$ac_aux_dir/ltmain.sh" + +# Backslashify metacharacters that are still active within +# double-quoted strings. +sed_quote_subst='s/\(["`$\\]\)/\\\1/g' + +# Same as above, but do not quote variable references. +double_quote_subst='s/\(["`\\]\)/\\\1/g' + +# Sed substitution to delay expansion of an escaped shell variable in a +# double_quote_subst'ed string. +delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' + +# Sed substitution to delay expansion of an escaped single quote. +delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g' + +# Sed substitution to avoid accidental globbing in evaled expressions +no_glob_subst='s/\*/\\\*/g' + +ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO +ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to print strings" >&5 +$as_echo_n "checking how to print strings... " >&6; } +# Test print first, because it will be a builtin if present. +if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \ + test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then + ECHO='print -r --' +elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then + ECHO='printf %s\n' +else + # Use this function as a fallback that always works. + func_fallback_echo () + { + eval 'cat <<_LTECHO_EOF +$1 +_LTECHO_EOF' + } + ECHO='func_fallback_echo' +fi + +# func_echo_all arg... +# Invoke $ECHO with all args, space-separated. +func_echo_all () +{ + $ECHO "" +} + +case "$ECHO" in + printf*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: printf" >&5 +$as_echo "printf" >&6; } ;; + print*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: print -r" >&5 +$as_echo "print -r" >&6; } ;; + *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: cat" >&5 +$as_echo "cat" >&6; } ;; +esac + + + + + + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5 +$as_echo_n "checking for a sed that does not truncate output... " >&6; } +if ${ac_cv_path_SED+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ + for ac_i in 1 2 3 4 5 6 7; do + ac_script="$ac_script$as_nl$ac_script" + done + echo "$ac_script" 2>/dev/null | sed 99q >conftest.sed + { ac_script=; unset ac_script;} + if test -z "$SED"; then + ac_path_SED_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in sed gsed; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_SED="$as_dir/$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_SED" || continue +# Check for GNU ac_path_SED and select it if it is found. + # Check for GNU $ac_path_SED +case `"$ac_path_SED" --version 2>&1` in +*GNU*) + ac_cv_path_SED="$ac_path_SED" ac_path_SED_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo '' >> "conftest.nl" + "$ac_path_SED" -f conftest.sed < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_SED_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_SED="$ac_path_SED" + ac_path_SED_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_SED_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_SED"; then + as_fn_error $? "no acceptable sed could be found in \$PATH" "$LINENO" 5 + fi +else + ac_cv_path_SED=$SED +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5 +$as_echo "$ac_cv_path_SED" >&6; } + SED="$ac_cv_path_SED" + rm -f conftest.sed + +test -z "$SED" && SED=sed +Xsed="$SED -e 1s/^X//" + + + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 +$as_echo_n "checking for grep that handles long lines and -e... " >&6; } +if ${ac_cv_path_GREP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$GREP"; then + ac_path_GREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in grep ggrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_GREP" || continue +# Check for GNU ac_path_GREP and select it if it is found. + # Check for GNU $ac_path_GREP +case `"$ac_path_GREP" --version 2>&1` in +*GNU*) + ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'GREP' >> "conftest.nl" + "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_GREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_GREP="$ac_path_GREP" + ac_path_GREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_GREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_GREP"; then + as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_GREP=$GREP +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 +$as_echo "$ac_cv_path_GREP" >&6; } + GREP="$ac_cv_path_GREP" + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 +$as_echo_n "checking for egrep... " >&6; } +if ${ac_cv_path_EGREP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 + then ac_cv_path_EGREP="$GREP -E" + else + if test -z "$EGREP"; then + ac_path_EGREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in egrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_EGREP" || continue +# Check for GNU ac_path_EGREP and select it if it is found. + # Check for GNU $ac_path_EGREP +case `"$ac_path_EGREP" --version 2>&1` in +*GNU*) + ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'EGREP' >> "conftest.nl" + "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_EGREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_EGREP="$ac_path_EGREP" + ac_path_EGREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_EGREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_EGREP"; then + as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_EGREP=$EGREP +fi + + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 +$as_echo "$ac_cv_path_EGREP" >&6; } + EGREP="$ac_cv_path_EGREP" + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for fgrep" >&5 +$as_echo_n "checking for fgrep... " >&6; } +if ${ac_cv_path_FGREP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if echo 'ab*c' | $GREP -F 'ab*c' >/dev/null 2>&1 + then ac_cv_path_FGREP="$GREP -F" + else + if test -z "$FGREP"; then + ac_path_FGREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in fgrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_FGREP="$as_dir/$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_FGREP" || continue +# Check for GNU ac_path_FGREP and select it if it is found. + # Check for GNU $ac_path_FGREP +case `"$ac_path_FGREP" --version 2>&1` in +*GNU*) + ac_cv_path_FGREP="$ac_path_FGREP" ac_path_FGREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'FGREP' >> "conftest.nl" + "$ac_path_FGREP" FGREP < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_FGREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_FGREP="$ac_path_FGREP" + ac_path_FGREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_FGREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_FGREP"; then + as_fn_error $? "no acceptable fgrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_FGREP=$FGREP +fi + + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_FGREP" >&5 +$as_echo "$ac_cv_path_FGREP" >&6; } + FGREP="$ac_cv_path_FGREP" + + +test -z "$GREP" && GREP=grep + + + + + + + + + + + + + + + + + + + +# Check whether --with-gnu-ld was given. +if test "${with_gnu_ld+set}" = set; then : + withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes +else + with_gnu_ld=no +fi + +ac_prog=ld +if test "$GCC" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5 +$as_echo_n "checking for ld used by $CC... " >&6; } + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case $ac_prog in + # Accept absolute paths. + [\\/]* | ?:[\\/]*) + re_direlt='/[^/][^/]*/\.\./' + # Canonicalize the pathname of ld + ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` + while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do + ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` + done + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5 +$as_echo_n "checking for GNU ld... " >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5 +$as_echo_n "checking for non-GNU ld... " >&6; } +fi +if ${lt_cv_path_LD+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$LD"; then + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + lt_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some variants of GNU ld only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + case `"$lt_cv_path_LD" -v 2>&1 &5 +$as_echo "$LD" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5 +$as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; } +if ${lt_cv_prog_gnu_ld+:} false; then : + $as_echo_n "(cached) " >&6 +else + # I'd rather use --version here, but apparently some GNU lds only accept -v. +case `$LD -v 2>&1 &5 +$as_echo "$lt_cv_prog_gnu_ld" >&6; } +with_gnu_ld=$lt_cv_prog_gnu_ld + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for BSD- or MS-compatible name lister (nm)" >&5 +$as_echo_n "checking for BSD- or MS-compatible name lister (nm)... " >&6; } +if ${lt_cv_path_NM+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$NM"; then + # Let the user override the test. + lt_cv_path_NM="$NM" +else + lt_nm_to_check="${ac_tool_prefix}nm" + if test -n "$ac_tool_prefix" && test "$build" = "$host"; then + lt_nm_to_check="$lt_nm_to_check nm" + fi + for lt_tmp_nm in $lt_nm_to_check; do + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + tmp_nm="$ac_dir/$lt_tmp_nm" + if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then + # Check to see if the nm accepts a BSD-compat flag. + # Adding the `sed 1q' prevents false positives on HP-UX, which says: + # nm: unknown option "B" ignored + # Tru64's nm complains that /dev/null is an invalid object file + case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in + */dev/null* | *'Invalid file or object type'*) + lt_cv_path_NM="$tmp_nm -B" + break + ;; + *) + case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in + */dev/null*) + lt_cv_path_NM="$tmp_nm -p" + break + ;; + *) + lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but + continue # so that we can try to find one that supports BSD flags + ;; + esac + ;; + esac + fi + done + IFS="$lt_save_ifs" + done + : ${lt_cv_path_NM=no} +fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_NM" >&5 +$as_echo "$lt_cv_path_NM" >&6; } +if test "$lt_cv_path_NM" != "no"; then + NM="$lt_cv_path_NM" +else + # Didn't find any BSD compatible name lister, look for dumpbin. + if test -n "$DUMPBIN"; then : + # Let the user override the test. + else + if test -n "$ac_tool_prefix"; then + for ac_prog in dumpbin "link -dump" + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_DUMPBIN+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$DUMPBIN"; then + ac_cv_prog_DUMPBIN="$DUMPBIN" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_DUMPBIN="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +DUMPBIN=$ac_cv_prog_DUMPBIN +if test -n "$DUMPBIN"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DUMPBIN" >&5 +$as_echo "$DUMPBIN" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$DUMPBIN" && break + done +fi +if test -z "$DUMPBIN"; then + ac_ct_DUMPBIN=$DUMPBIN + for ac_prog in dumpbin "link -dump" +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_DUMPBIN+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_DUMPBIN"; then + ac_cv_prog_ac_ct_DUMPBIN="$ac_ct_DUMPBIN" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_DUMPBIN="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_DUMPBIN=$ac_cv_prog_ac_ct_DUMPBIN +if test -n "$ac_ct_DUMPBIN"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DUMPBIN" >&5 +$as_echo "$ac_ct_DUMPBIN" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_DUMPBIN" && break +done + + if test "x$ac_ct_DUMPBIN" = x; then + DUMPBIN=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + DUMPBIN=$ac_ct_DUMPBIN + fi +fi + + case `$DUMPBIN -symbols /dev/null 2>&1 | sed '1q'` in + *COFF*) + DUMPBIN="$DUMPBIN -symbols" + ;; + *) + DUMPBIN=: + ;; + esac + fi + + if test "$DUMPBIN" != ":"; then + NM="$DUMPBIN" + fi +fi +test -z "$NM" && NM=nm + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the name lister ($NM) interface" >&5 +$as_echo_n "checking the name lister ($NM) interface... " >&6; } +if ${lt_cv_nm_interface+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_nm_interface="BSD nm" + echo "int some_variable = 0;" > conftest.$ac_ext + (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&5) + (eval "$ac_compile" 2>conftest.err) + cat conftest.err >&5 + (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&5) + (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) + cat conftest.err >&5 + (eval echo "\"\$as_me:$LINENO: output\"" >&5) + cat conftest.out >&5 + if $GREP 'External.*some_variable' conftest.out > /dev/null; then + lt_cv_nm_interface="MS dumpbin" + fi + rm -f conftest* +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_nm_interface" >&5 +$as_echo "$lt_cv_nm_interface" >&6; } + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5 +$as_echo_n "checking whether ln -s works... " >&6; } +LN_S=$as_ln_s +if test "$LN_S" = "ln -s"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5 +$as_echo "no, using $LN_S" >&6; } +fi + +# find the maximum length of command line arguments +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the maximum length of command line arguments" >&5 +$as_echo_n "checking the maximum length of command line arguments... " >&6; } +if ${lt_cv_sys_max_cmd_len+:} false; then : + $as_echo_n "(cached) " >&6 +else + i=0 + teststring="ABCD" + + case $build_os in + msdosdjgpp*) + # On DJGPP, this test can blow up pretty badly due to problems in libc + # (any single argument exceeding 2000 bytes causes a buffer overrun + # during glob expansion). Even if it were fixed, the result of this + # check would be larger than it should be. + lt_cv_sys_max_cmd_len=12288; # 12K is about right + ;; + + gnu*) + # Under GNU Hurd, this test is not required because there is + # no limit to the length of command line arguments. + # Libtool will interpret -1 as no limit whatsoever + lt_cv_sys_max_cmd_len=-1; + ;; + + cygwin* | mingw* | cegcc*) + # On Win9x/ME, this test blows up -- it succeeds, but takes + # about 5 minutes as the teststring grows exponentially. + # Worse, since 9x/ME are not pre-emptively multitasking, + # you end up with a "frozen" computer, even though with patience + # the test eventually succeeds (with a max line length of 256k). + # Instead, let's just punt: use the minimum linelength reported by + # all of the supported platforms: 8192 (on NT/2K/XP). + lt_cv_sys_max_cmd_len=8192; + ;; + + mint*) + # On MiNT this can take a long time and run out of memory. + lt_cv_sys_max_cmd_len=8192; + ;; + + amigaos*) + # On AmigaOS with pdksh, this test takes hours, literally. + # So we just punt and use a minimum line length of 8192. + lt_cv_sys_max_cmd_len=8192; + ;; + + netbsd* | freebsd* | openbsd* | darwin* | dragonfly*) + # This has been around since 386BSD, at least. Likely further. + if test -x /sbin/sysctl; then + lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` + elif test -x /usr/sbin/sysctl; then + lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` + else + lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs + fi + # And add a safety zone + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` + ;; + + interix*) + # We know the value 262144 and hardcode it with a safety zone (like BSD) + lt_cv_sys_max_cmd_len=196608 + ;; + + os2*) + # The test takes a long time on OS/2. + lt_cv_sys_max_cmd_len=8192 + ;; + + osf*) + # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure + # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not + # nice to cause kernel panics so lets avoid the loop below. + # First set a reasonable default. + lt_cv_sys_max_cmd_len=16384 + # + if test -x /sbin/sysconfig; then + case `/sbin/sysconfig -q proc exec_disable_arg_limit` in + *1*) lt_cv_sys_max_cmd_len=-1 ;; + esac + fi + ;; + sco3.2v5*) + lt_cv_sys_max_cmd_len=102400 + ;; + sysv5* | sco5v6* | sysv4.2uw2*) + kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` + if test -n "$kargmax"; then + lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[ ]//'` + else + lt_cv_sys_max_cmd_len=32768 + fi + ;; + *) + lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null` + if test -n "$lt_cv_sys_max_cmd_len" && \ + test undefined != "$lt_cv_sys_max_cmd_len"; then + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` + else + # Make teststring a little bigger before we do anything with it. + # a 1K string should be a reasonable start. + for i in 1 2 3 4 5 6 7 8 ; do + teststring=$teststring$teststring + done + SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} + # If test is not a shell built-in, we'll probably end up computing a + # maximum length that is only half of the actual maximum length, but + # we can't tell. + while { test "X"`env echo "$teststring$teststring" 2>/dev/null` \ + = "X$teststring$teststring"; } >/dev/null 2>&1 && + test $i != 17 # 1/2 MB should be enough + do + i=`expr $i + 1` + teststring=$teststring$teststring + done + # Only check the string length outside the loop. + lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1` + teststring= + # Add a significant safety factor because C++ compilers can tack on + # massive amounts of additional arguments before passing them to the + # linker. It appears as though 1/2 is a usable value. + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` + fi + ;; + esac + +fi + +if test -n $lt_cv_sys_max_cmd_len ; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sys_max_cmd_len" >&5 +$as_echo "$lt_cv_sys_max_cmd_len" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: none" >&5 +$as_echo "none" >&6; } +fi +max_cmd_len=$lt_cv_sys_max_cmd_len + + + + + + +: ${CP="cp -f"} +: ${MV="mv -f"} +: ${RM="rm -f"} + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands some XSI constructs" >&5 +$as_echo_n "checking whether the shell understands some XSI constructs... " >&6; } +# Try some XSI features +xsi_shell=no +( _lt_dummy="a/b/c" + test "${_lt_dummy##*/},${_lt_dummy%/*},${_lt_dummy#??}"${_lt_dummy%"$_lt_dummy"}, \ + = c,a/b,b/c, \ + && eval 'test $(( 1 + 1 )) -eq 2 \ + && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \ + && xsi_shell=yes +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $xsi_shell" >&5 +$as_echo "$xsi_shell" >&6; } + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands \"+=\"" >&5 +$as_echo_n "checking whether the shell understands \"+=\"... " >&6; } +lt_shell_append=no +( foo=bar; set foo baz; eval "$1+=\$2" && test "$foo" = barbaz ) \ + >/dev/null 2>&1 \ + && lt_shell_append=yes +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_shell_append" >&5 +$as_echo "$lt_shell_append" >&6; } + + +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + lt_unset=unset +else + lt_unset=false +fi + + + + + +# test EBCDIC or ASCII +case `echo X|tr X '\101'` in + A) # ASCII based system + # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr + lt_SP2NL='tr \040 \012' + lt_NL2SP='tr \015\012 \040\040' + ;; + *) # EBCDIC based system + lt_SP2NL='tr \100 \n' + lt_NL2SP='tr \r\n \100\100' + ;; +esac + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to $host format" >&5 +$as_echo_n "checking how to convert $build file names to $host format... " >&6; } +if ${lt_cv_to_host_file_cmd+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $host in + *-*-mingw* ) + case $build in + *-*-mingw* ) # actually msys + lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32 + ;; + *-*-cygwin* ) + lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32 + ;; + * ) # otherwise, assume *nix + lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32 + ;; + esac + ;; + *-*-cygwin* ) + case $build in + *-*-mingw* ) # actually msys + lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin + ;; + *-*-cygwin* ) + lt_cv_to_host_file_cmd=func_convert_file_noop + ;; + * ) # otherwise, assume *nix + lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin + ;; + esac + ;; + * ) # unhandled hosts (and "normal" native builds) + lt_cv_to_host_file_cmd=func_convert_file_noop + ;; +esac + +fi + +to_host_file_cmd=$lt_cv_to_host_file_cmd +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_host_file_cmd" >&5 +$as_echo "$lt_cv_to_host_file_cmd" >&6; } + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to toolchain format" >&5 +$as_echo_n "checking how to convert $build file names to toolchain format... " >&6; } +if ${lt_cv_to_tool_file_cmd+:} false; then : + $as_echo_n "(cached) " >&6 +else + #assume ordinary cross tools, or native build. +lt_cv_to_tool_file_cmd=func_convert_file_noop +case $host in + *-*-mingw* ) + case $build in + *-*-mingw* ) # actually msys + lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32 + ;; + esac + ;; +esac + +fi + +to_tool_file_cmd=$lt_cv_to_tool_file_cmd +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_tool_file_cmd" >&5 +$as_echo "$lt_cv_to_tool_file_cmd" >&6; } + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $LD option to reload object files" >&5 +$as_echo_n "checking for $LD option to reload object files... " >&6; } +if ${lt_cv_ld_reload_flag+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_ld_reload_flag='-r' +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_reload_flag" >&5 +$as_echo "$lt_cv_ld_reload_flag" >&6; } +reload_flag=$lt_cv_ld_reload_flag +case $reload_flag in +"" | " "*) ;; +*) reload_flag=" $reload_flag" ;; +esac +reload_cmds='$LD$reload_flag -o $output$reload_objs' +case $host_os in + cygwin* | mingw* | pw32* | cegcc*) + if test "$GCC" != yes; then + reload_cmds=false + fi + ;; + darwin*) + if test "$GCC" = yes; then + reload_cmds='$LTCC $LTCFLAGS -nostdlib ${wl}-r -o $output$reload_objs' + else + reload_cmds='$LD$reload_flag -o $output$reload_objs' + fi + ;; +esac + + + + + + + + + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}objdump", so it can be a program name with args. +set dummy ${ac_tool_prefix}objdump; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_OBJDUMP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$OBJDUMP"; then + ac_cv_prog_OBJDUMP="$OBJDUMP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_OBJDUMP="${ac_tool_prefix}objdump" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +OBJDUMP=$ac_cv_prog_OBJDUMP +if test -n "$OBJDUMP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OBJDUMP" >&5 +$as_echo "$OBJDUMP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_OBJDUMP"; then + ac_ct_OBJDUMP=$OBJDUMP + # Extract the first word of "objdump", so it can be a program name with args. +set dummy objdump; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_OBJDUMP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_OBJDUMP"; then + ac_cv_prog_ac_ct_OBJDUMP="$ac_ct_OBJDUMP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_OBJDUMP="objdump" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_OBJDUMP=$ac_cv_prog_ac_ct_OBJDUMP +if test -n "$ac_ct_OBJDUMP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OBJDUMP" >&5 +$as_echo "$ac_ct_OBJDUMP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_OBJDUMP" = x; then + OBJDUMP="false" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + OBJDUMP=$ac_ct_OBJDUMP + fi +else + OBJDUMP="$ac_cv_prog_OBJDUMP" +fi + +test -z "$OBJDUMP" && OBJDUMP=objdump + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to recognize dependent libraries" >&5 +$as_echo_n "checking how to recognize dependent libraries... " >&6; } +if ${lt_cv_deplibs_check_method+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_file_magic_cmd='$MAGIC_CMD' +lt_cv_file_magic_test_file= +lt_cv_deplibs_check_method='unknown' +# Need to set the preceding variable on all platforms that support +# interlibrary dependencies. +# 'none' -- dependencies not supported. +# `unknown' -- same as none, but documents that we really don't know. +# 'pass_all' -- all dependencies passed with no checks. +# 'test_compile' -- check by making test program. +# 'file_magic [[regex]]' -- check by looking for files in library path +# which responds to the $file_magic_cmd with a given extended regex. +# If you have `file' or equivalent on your system and you're not sure +# whether `pass_all' will *always* work, you probably want this one. + +case $host_os in +aix[4-9]*) + lt_cv_deplibs_check_method=pass_all + ;; + +beos*) + lt_cv_deplibs_check_method=pass_all + ;; + +bsdi[45]*) + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib)' + lt_cv_file_magic_cmd='/usr/bin/file -L' + lt_cv_file_magic_test_file=/shlib/libc.so + ;; + +cygwin*) + # func_win32_libid is a shell function defined in ltmain.sh + lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' + lt_cv_file_magic_cmd='func_win32_libid' + ;; + +mingw* | pw32*) + # Base MSYS/MinGW do not provide the 'file' command needed by + # func_win32_libid shell function, so use a weaker test based on 'objdump', + # unless we find 'file', for example because we are cross-compiling. + # func_win32_libid assumes BSD nm, so disallow it if using MS dumpbin. + if ( test "$lt_cv_nm_interface" = "BSD nm" && file / ) >/dev/null 2>&1; then + lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' + lt_cv_file_magic_cmd='func_win32_libid' + else + # Keep this pattern in sync with the one in func_win32_libid. + lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' + lt_cv_file_magic_cmd='$OBJDUMP -f' + fi + ;; + +cegcc*) + # use the weaker test based on 'objdump'. See mingw*. + lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?' + lt_cv_file_magic_cmd='$OBJDUMP -f' + ;; + +darwin* | rhapsody*) + lt_cv_deplibs_check_method=pass_all + ;; + +freebsd* | dragonfly*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then + case $host_cpu in + i*86 ) + # Not sure whether the presence of OpenBSD here was a mistake. + # Let's accept both of them until this is cleared up. + lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[3-9]86 (compact )?demand paged shared library' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` + ;; + esac + else + lt_cv_deplibs_check_method=pass_all + fi + ;; + +haiku*) + lt_cv_deplibs_check_method=pass_all + ;; + +hpux10.20* | hpux11*) + lt_cv_file_magic_cmd=/usr/bin/file + case $host_cpu in + ia64*) + lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - IA64' + lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so + ;; + hppa*64*) + lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]' + lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl + ;; + *) + lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|PA-RISC[0-9]\.[0-9]) shared library' + lt_cv_file_magic_test_file=/usr/lib/libc.sl + ;; + esac + ;; + +interix[3-9]*) + # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|\.a)$' + ;; + +irix5* | irix6* | nonstopux*) + case $LD in + *-32|*"-32 ") libmagic=32-bit;; + *-n32|*"-n32 ") libmagic=N32;; + *-64|*"-64 ") libmagic=64-bit;; + *) libmagic=never-match;; + esac + lt_cv_deplibs_check_method=pass_all + ;; + +# This must be glibc/ELF. +linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) + lt_cv_deplibs_check_method=pass_all + ;; + +netbsd* | netbsdelf*-gnu) + if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|_pic\.a)$' + fi + ;; + +newos6*) + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (executable|dynamic lib)' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=/usr/lib/libnls.so + ;; + +*nto* | *qnx*) + lt_cv_deplibs_check_method=pass_all + ;; + +openbsd*) + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|\.so|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' + fi + ;; + +osf3* | osf4* | osf5*) + lt_cv_deplibs_check_method=pass_all + ;; + +rdos*) + lt_cv_deplibs_check_method=pass_all + ;; + +solaris*) + lt_cv_deplibs_check_method=pass_all + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + lt_cv_deplibs_check_method=pass_all + ;; + +sysv4 | sysv4.3*) + case $host_vendor in + motorola) + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib) M[0-9][0-9]* Version [0-9]' + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` + ;; + ncr) + lt_cv_deplibs_check_method=pass_all + ;; + sequent) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )' + ;; + sni) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method="file_magic ELF [0-9][0-9]*-bit [LM]SB dynamic lib" + lt_cv_file_magic_test_file=/lib/libc.so + ;; + siemens) + lt_cv_deplibs_check_method=pass_all + ;; + pc) + lt_cv_deplibs_check_method=pass_all + ;; + esac + ;; + +tpf*) + lt_cv_deplibs_check_method=pass_all + ;; +esac + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_deplibs_check_method" >&5 +$as_echo "$lt_cv_deplibs_check_method" >&6; } + +file_magic_glob= +want_nocaseglob=no +if test "$build" = "$host"; then + case $host_os in + mingw* | pw32*) + if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then + want_nocaseglob=yes + else + file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[\1]\/[\1]\/g;/g"` + fi + ;; + esac +fi + +file_magic_cmd=$lt_cv_file_magic_cmd +deplibs_check_method=$lt_cv_deplibs_check_method +test -z "$deplibs_check_method" && deplibs_check_method=unknown + + + + + + + + + + + + + + + + + + + + + + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}dlltool", so it can be a program name with args. +set dummy ${ac_tool_prefix}dlltool; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_DLLTOOL+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$DLLTOOL"; then + ac_cv_prog_DLLTOOL="$DLLTOOL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_DLLTOOL="${ac_tool_prefix}dlltool" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +DLLTOOL=$ac_cv_prog_DLLTOOL +if test -n "$DLLTOOL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DLLTOOL" >&5 +$as_echo "$DLLTOOL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_DLLTOOL"; then + ac_ct_DLLTOOL=$DLLTOOL + # Extract the first word of "dlltool", so it can be a program name with args. +set dummy dlltool; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_DLLTOOL+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_DLLTOOL"; then + ac_cv_prog_ac_ct_DLLTOOL="$ac_ct_DLLTOOL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_DLLTOOL="dlltool" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_DLLTOOL=$ac_cv_prog_ac_ct_DLLTOOL +if test -n "$ac_ct_DLLTOOL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DLLTOOL" >&5 +$as_echo "$ac_ct_DLLTOOL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_DLLTOOL" = x; then + DLLTOOL="false" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + DLLTOOL=$ac_ct_DLLTOOL + fi +else + DLLTOOL="$ac_cv_prog_DLLTOOL" +fi + +test -z "$DLLTOOL" && DLLTOOL=dlltool + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to associate runtime and link libraries" >&5 +$as_echo_n "checking how to associate runtime and link libraries... " >&6; } +if ${lt_cv_sharedlib_from_linklib_cmd+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_sharedlib_from_linklib_cmd='unknown' + +case $host_os in +cygwin* | mingw* | pw32* | cegcc*) + # two different shell functions defined in ltmain.sh + # decide which to use based on capabilities of $DLLTOOL + case `$DLLTOOL --help 2>&1` in + *--identify-strict*) + lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib + ;; + *) + lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback + ;; + esac + ;; +*) + # fallback: assume linklib IS sharedlib + lt_cv_sharedlib_from_linklib_cmd="$ECHO" + ;; +esac + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sharedlib_from_linklib_cmd" >&5 +$as_echo "$lt_cv_sharedlib_from_linklib_cmd" >&6; } +sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd +test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO + + + + + + + + +if test -n "$ac_tool_prefix"; then + for ac_prog in ar + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_AR+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$AR"; then + ac_cv_prog_AR="$AR" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_AR="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +AR=$ac_cv_prog_AR +if test -n "$AR"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 +$as_echo "$AR" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$AR" && break + done +fi +if test -z "$AR"; then + ac_ct_AR=$AR + for ac_prog in ar +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_AR+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_AR"; then + ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_AR="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_AR=$ac_cv_prog_ac_ct_AR +if test -n "$ac_ct_AR"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 +$as_echo "$ac_ct_AR" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_AR" && break +done + + if test "x$ac_ct_AR" = x; then + AR="false" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + AR=$ac_ct_AR + fi +fi + +: ${AR=ar} +: ${AR_FLAGS=cru} + + + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for archiver @FILE support" >&5 +$as_echo_n "checking for archiver @FILE support... " >&6; } +if ${lt_cv_ar_at_file+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_ar_at_file=no + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + echo conftest.$ac_objext > conftest.lst + lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&5' + { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5 + (eval $lt_ar_try) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + if test "$ac_status" -eq 0; then + # Ensure the archiver fails upon bogus file names. + rm -f conftest.$ac_objext libconftest.a + { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5 + (eval $lt_ar_try) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + if test "$ac_status" -ne 0; then + lt_cv_ar_at_file=@ + fi + fi + rm -f conftest.* libconftest.a + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ar_at_file" >&5 +$as_echo "$lt_cv_ar_at_file" >&6; } + +if test "x$lt_cv_ar_at_file" = xno; then + archiver_list_spec= +else + archiver_list_spec=$lt_cv_ar_at_file +fi + + + + + + + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. +set dummy ${ac_tool_prefix}strip; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_STRIP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$STRIP"; then + ac_cv_prog_STRIP="$STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_STRIP="${ac_tool_prefix}strip" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +STRIP=$ac_cv_prog_STRIP +if test -n "$STRIP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 +$as_echo "$STRIP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_STRIP"; then + ac_ct_STRIP=$STRIP + # Extract the first word of "strip", so it can be a program name with args. +set dummy strip; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_STRIP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_STRIP"; then + ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_STRIP="strip" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP +if test -n "$ac_ct_STRIP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 +$as_echo "$ac_ct_STRIP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_STRIP" = x; then + STRIP=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + STRIP=$ac_ct_STRIP + fi +else + STRIP="$ac_cv_prog_STRIP" +fi + +test -z "$STRIP" && STRIP=: + + + + + + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. +set dummy ${ac_tool_prefix}ranlib; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_RANLIB+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$RANLIB"; then + ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +RANLIB=$ac_cv_prog_RANLIB +if test -n "$RANLIB"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 +$as_echo "$RANLIB" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_RANLIB"; then + ac_ct_RANLIB=$RANLIB + # Extract the first word of "ranlib", so it can be a program name with args. +set dummy ranlib; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_RANLIB+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_RANLIB"; then + ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_RANLIB="ranlib" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB +if test -n "$ac_ct_RANLIB"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 +$as_echo "$ac_ct_RANLIB" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_RANLIB" = x; then + RANLIB=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + RANLIB=$ac_ct_RANLIB + fi +else + RANLIB="$ac_cv_prog_RANLIB" +fi + +test -z "$RANLIB" && RANLIB=: + + + + + + +# Determine commands to create old-style static archives. +old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs' +old_postinstall_cmds='chmod 644 $oldlib' +old_postuninstall_cmds= + +if test -n "$RANLIB"; then + case $host_os in + openbsd*) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib" + ;; + *) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib" + ;; + esac + old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib" +fi + +case $host_os in + darwin*) + lock_old_archive_extraction=yes ;; + *) + lock_old_archive_extraction=no ;; +esac + + + + + + + + + + + + + + + + + + + + + +for ac_prog in gawk mawk nawk awk +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_AWK+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$AWK"; then + ac_cv_prog_AWK="$AWK" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_AWK="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +AWK=$ac_cv_prog_AWK +if test -n "$AWK"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5 +$as_echo "$AWK" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$AWK" && break +done + + + + + + + + + + + + + + + + + + + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# If no C compiler flags were specified, use CFLAGS. +LTCFLAGS=${LTCFLAGS-"$CFLAGS"} + +# Allow CC to be a program name with arguments. +compiler=$CC + + +# Check for command to grab the raw symbol name followed by C symbol from nm. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking command to parse $NM output from $compiler object" >&5 +$as_echo_n "checking command to parse $NM output from $compiler object... " >&6; } +if ${lt_cv_sys_global_symbol_pipe+:} false; then : + $as_echo_n "(cached) " >&6 +else + +# These are sane defaults that work on at least a few old systems. +# [They come from Ultrix. What could be older than Ultrix?!! ;)] + +# Character class describing NM global symbol codes. +symcode='[BCDEGRST]' + +# Regexp to match symbols that can be accessed directly from C. +sympat='\([_A-Za-z][_A-Za-z0-9]*\)' + +# Define system-specific variables. +case $host_os in +aix*) + symcode='[BCDT]' + ;; +cygwin* | mingw* | pw32* | cegcc*) + symcode='[ABCDGISTW]' + ;; +hpux*) + if test "$host_cpu" = ia64; then + symcode='[ABCDEGRST]' + fi + ;; +irix* | nonstopux*) + symcode='[BCDEGRST]' + ;; +osf*) + symcode='[BCDEGQRST]' + ;; +solaris*) + symcode='[BDRT]' + ;; +sco3.2v5*) + symcode='[DT]' + ;; +sysv4.2uw2*) + symcode='[DT]' + ;; +sysv5* | sco5v6* | unixware* | OpenUNIX*) + symcode='[ABDT]' + ;; +sysv4) + symcode='[DFNSTU]' + ;; +esac + +# If we're using GNU nm, then use its standard symbol codes. +case `$NM -V 2>&1` in +*GNU* | *'with BFD'*) + symcode='[ABCDGIRSTW]' ;; +esac + +# Transform an extracted symbol line into a proper C declaration. +# Some systems (esp. on ia64) link data and code symbols differently, +# so use this general approach. +lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" + +# Transform an extracted symbol line into symbol name and symbol address +lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([^ ]*\)[ ]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"\2\", (void *) \&\2},/p'" +lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([^ ]*\)[ ]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \(lib[^ ]*\)$/ {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"lib\2\", (void *) \&\2},/p'" + +# Handle CRLF in mingw tool chain +opt_cr= +case $build_os in +mingw*) + opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp + ;; +esac + +# Try without a prefix underscore, then with it. +for ac_symprfx in "" "_"; do + + # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. + symxfrm="\\1 $ac_symprfx\\2 \\2" + + # Write the raw and C identifiers. + if test "$lt_cv_nm_interface" = "MS dumpbin"; then + # Fake it for dumpbin and say T for any non-static function + # and D for any global variable. + # Also find C++ and __fastcall symbols from MSVC++, + # which start with @ or ?. + lt_cv_sys_global_symbol_pipe="$AWK '"\ +" {last_section=section; section=\$ 3};"\ +" /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\ +" /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\ +" \$ 0!~/External *\|/{next};"\ +" / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ +" {if(hide[section]) next};"\ +" {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\ +" {split(\$ 0, a, /\||\r/); split(a[2], s)};"\ +" s[1]~/^[@?]/{print s[1], s[1]; next};"\ +" s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\ +" ' prfx=^$ac_symprfx" + else + lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[ ]\($symcode$symcode*\)[ ][ ]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" + fi + lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | sed '/ __gnu_lto/d'" + + # Check to see that the pipe works correctly. + pipe_works=no + + rm -f conftest* + cat > conftest.$ac_ext <<_LT_EOF +#ifdef __cplusplus +extern "C" { +#endif +char nm_test_var; +void nm_test_func(void); +void nm_test_func(void){} +#ifdef __cplusplus +} +#endif +int main(){nm_test_var='a';nm_test_func();return(0);} +_LT_EOF + + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + # Now try to grab the symbols. + nlist=conftest.nm + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist\""; } >&5 + (eval $NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && test -s "$nlist"; then + # Try sorting and uniquifying the output. + if sort "$nlist" | uniq > "$nlist"T; then + mv -f "$nlist"T "$nlist" + else + rm -f "$nlist"T + fi + + # Make sure that we snagged all the symbols we need. + if $GREP ' nm_test_var$' "$nlist" >/dev/null; then + if $GREP ' nm_test_func$' "$nlist" >/dev/null; then + cat <<_LT_EOF > conftest.$ac_ext +/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ +#if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE) +/* DATA imports from DLLs on WIN32 con't be const, because runtime + relocations are performed -- see ld's documentation on pseudo-relocs. */ +# define LT_DLSYM_CONST +#elif defined(__osf__) +/* This system does not cope well with relocations in const data. */ +# define LT_DLSYM_CONST +#else +# define LT_DLSYM_CONST const +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +_LT_EOF + # Now generate the symbol file. + eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext' + + cat <<_LT_EOF >> conftest.$ac_ext + +/* The mapping between symbol names and symbols. */ +LT_DLSYM_CONST struct { + const char *name; + void *address; +} +lt__PROGRAM__LTX_preloaded_symbols[] = +{ + { "@PROGRAM@", (void *) 0 }, +_LT_EOF + $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext + cat <<\_LT_EOF >> conftest.$ac_ext + {0, (void *) 0} +}; + +/* This works around a problem in FreeBSD linker */ +#ifdef FREEBSD_WORKAROUND +static const void *lt_preloaded_setup() { + return lt__PROGRAM__LTX_preloaded_symbols; +} +#endif + +#ifdef __cplusplus +} +#endif +_LT_EOF + # Now try linking the two files. + mv conftest.$ac_objext conftstm.$ac_objext + lt_globsym_save_LIBS=$LIBS + lt_globsym_save_CFLAGS=$CFLAGS + LIBS="conftstm.$ac_objext" + CFLAGS="$CFLAGS$lt_prog_compiler_no_builtin_flag" + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 + (eval $ac_link) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && test -s conftest${ac_exeext}; then + pipe_works=yes + fi + LIBS=$lt_globsym_save_LIBS + CFLAGS=$lt_globsym_save_CFLAGS + else + echo "cannot find nm_test_func in $nlist" >&5 + fi + else + echo "cannot find nm_test_var in $nlist" >&5 + fi + else + echo "cannot run $lt_cv_sys_global_symbol_pipe" >&5 + fi + else + echo "$progname: failed program was:" >&5 + cat conftest.$ac_ext >&5 + fi + rm -rf conftest* conftst* + + # Do not use the global_symbol_pipe unless it works. + if test "$pipe_works" = yes; then + break + else + lt_cv_sys_global_symbol_pipe= + fi +done + +fi + +if test -z "$lt_cv_sys_global_symbol_pipe"; then + lt_cv_sys_global_symbol_to_cdecl= +fi +if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: failed" >&5 +$as_echo "failed" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5 +$as_echo "ok" >&6; } +fi + +# Response file support. +if test "$lt_cv_nm_interface" = "MS dumpbin"; then + nm_file_list_spec='@' +elif $NM --help 2>/dev/null | grep '[@]FILE' >/dev/null; then + nm_file_list_spec='@' +fi + + + + + + + + + + + + + + + + + + + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for sysroot" >&5 +$as_echo_n "checking for sysroot... " >&6; } + +# Check whether --with-sysroot was given. +if test "${with_sysroot+set}" = set; then : + withval=$with_sysroot; +else + with_sysroot=no +fi + + +lt_sysroot= +case ${with_sysroot} in #( + yes) + if test "$GCC" = yes; then + lt_sysroot=`$CC --print-sysroot 2>/dev/null` + fi + ;; #( + /*) + lt_sysroot=`echo "$with_sysroot" | sed -e "$sed_quote_subst"` + ;; #( + no|'') + ;; #( + *) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${with_sysroot}" >&5 +$as_echo "${with_sysroot}" >&6; } + as_fn_error $? "The sysroot must be an absolute path." "$LINENO" 5 + ;; +esac + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${lt_sysroot:-no}" >&5 +$as_echo "${lt_sysroot:-no}" >&6; } + + + + + +# Check whether --enable-libtool-lock was given. +if test "${enable_libtool_lock+set}" = set; then : + enableval=$enable_libtool_lock; +fi + +test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes + +# Some flags need to be propagated to the compiler or linker for good +# libtool support. +case $host in +ia64-*-hpux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + case `/usr/bin/file conftest.$ac_objext` in + *ELF-32*) + HPUX_IA64_MODE="32" + ;; + *ELF-64*) + HPUX_IA64_MODE="64" + ;; + esac + fi + rm -rf conftest* + ;; +*-*-irix6*) + # Find out which ABI we are using. + echo '#line '$LINENO' "configure"' > conftest.$ac_ext + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + if test "$lt_cv_prog_gnu_ld" = yes; then + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -melf32bsmip" + ;; + *N32*) + LD="${LD-ld} -melf32bmipn32" + ;; + *64-bit*) + LD="${LD-ld} -melf64bmip" + ;; + esac + else + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -32" + ;; + *N32*) + LD="${LD-ld} -n32" + ;; + *64-bit*) + LD="${LD-ld} -64" + ;; + esac + fi + fi + rm -rf conftest* + ;; + +x86_64-*kfreebsd*-gnu|x86_64-*linux*|powerpc*-*linux*| \ +s390*-*linux*|s390*-*tpf*|sparc*-*linux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + case `/usr/bin/file conftest.o` in + *32-bit*) + case $host in + x86_64-*kfreebsd*-gnu) + LD="${LD-ld} -m elf_i386_fbsd" + ;; + x86_64-*linux*) + case `/usr/bin/file conftest.o` in + *x86-64*) + LD="${LD-ld} -m elf32_x86_64" + ;; + *) + LD="${LD-ld} -m elf_i386" + ;; + esac + ;; + powerpc64le-*) + LD="${LD-ld} -m elf32lppclinux" + ;; + powerpc64-*) + LD="${LD-ld} -m elf32ppclinux" + ;; + s390x-*linux*) + LD="${LD-ld} -m elf_s390" + ;; + sparc64-*linux*) + LD="${LD-ld} -m elf32_sparc" + ;; + esac + ;; + *64-bit*) + case $host in + x86_64-*kfreebsd*-gnu) + LD="${LD-ld} -m elf_x86_64_fbsd" + ;; + x86_64-*linux*) + LD="${LD-ld} -m elf_x86_64" + ;; + powerpcle-*) + LD="${LD-ld} -m elf64lppc" + ;; + powerpc-*) + LD="${LD-ld} -m elf64ppc" + ;; + s390*-*linux*|s390*-*tpf*) + LD="${LD-ld} -m elf64_s390" + ;; + sparc*-*linux*) + LD="${LD-ld} -m elf64_sparc" + ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; + +*-*-sco3.2v5*) + # On SCO OpenServer 5, we need -belf to get full-featured binaries. + SAVE_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -belf" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler needs -belf" >&5 +$as_echo_n "checking whether the C compiler needs -belf... " >&6; } +if ${lt_cv_cc_needs_belf+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + lt_cv_cc_needs_belf=yes +else + lt_cv_cc_needs_belf=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_cc_needs_belf" >&5 +$as_echo "$lt_cv_cc_needs_belf" >&6; } + if test x"$lt_cv_cc_needs_belf" != x"yes"; then + # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf + CFLAGS="$SAVE_CFLAGS" + fi + ;; +*-*solaris*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + case `/usr/bin/file conftest.o` in + *64-bit*) + case $lt_cv_prog_gnu_ld in + yes*) + case $host in + i?86-*-solaris*) + LD="${LD-ld} -m elf_x86_64" + ;; + sparc*-*-solaris*) + LD="${LD-ld} -m elf64_sparc" + ;; + esac + # GNU ld 2.21 introduced _sol2 emulations. Use them if available. + if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then + LD="${LD-ld}_sol2" + fi + ;; + *) + if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then + LD="${LD-ld} -64" + fi + ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; +esac + +need_locks="$enable_libtool_lock" + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}mt", so it can be a program name with args. +set dummy ${ac_tool_prefix}mt; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_MANIFEST_TOOL+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$MANIFEST_TOOL"; then + ac_cv_prog_MANIFEST_TOOL="$MANIFEST_TOOL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_MANIFEST_TOOL="${ac_tool_prefix}mt" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +MANIFEST_TOOL=$ac_cv_prog_MANIFEST_TOOL +if test -n "$MANIFEST_TOOL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MANIFEST_TOOL" >&5 +$as_echo "$MANIFEST_TOOL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_MANIFEST_TOOL"; then + ac_ct_MANIFEST_TOOL=$MANIFEST_TOOL + # Extract the first word of "mt", so it can be a program name with args. +set dummy mt; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_MANIFEST_TOOL+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_MANIFEST_TOOL"; then + ac_cv_prog_ac_ct_MANIFEST_TOOL="$ac_ct_MANIFEST_TOOL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_MANIFEST_TOOL="mt" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_MANIFEST_TOOL=$ac_cv_prog_ac_ct_MANIFEST_TOOL +if test -n "$ac_ct_MANIFEST_TOOL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_MANIFEST_TOOL" >&5 +$as_echo "$ac_ct_MANIFEST_TOOL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_MANIFEST_TOOL" = x; then + MANIFEST_TOOL=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + MANIFEST_TOOL=$ac_ct_MANIFEST_TOOL + fi +else + MANIFEST_TOOL="$ac_cv_prog_MANIFEST_TOOL" +fi + +test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $MANIFEST_TOOL is a manifest tool" >&5 +$as_echo_n "checking if $MANIFEST_TOOL is a manifest tool... " >&6; } +if ${lt_cv_path_mainfest_tool+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_path_mainfest_tool=no + echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&5 + $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out + cat conftest.err >&5 + if $GREP 'Manifest Tool' conftest.out > /dev/null; then + lt_cv_path_mainfest_tool=yes + fi + rm -f conftest* +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_mainfest_tool" >&5 +$as_echo "$lt_cv_path_mainfest_tool" >&6; } +if test "x$lt_cv_path_mainfest_tool" != xyes; then + MANIFEST_TOOL=: +fi + + + + + + + case $host_os in + rhapsody* | darwin*) + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}dsymutil", so it can be a program name with args. +set dummy ${ac_tool_prefix}dsymutil; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_DSYMUTIL+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$DSYMUTIL"; then + ac_cv_prog_DSYMUTIL="$DSYMUTIL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_DSYMUTIL="${ac_tool_prefix}dsymutil" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +DSYMUTIL=$ac_cv_prog_DSYMUTIL +if test -n "$DSYMUTIL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DSYMUTIL" >&5 +$as_echo "$DSYMUTIL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_DSYMUTIL"; then + ac_ct_DSYMUTIL=$DSYMUTIL + # Extract the first word of "dsymutil", so it can be a program name with args. +set dummy dsymutil; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_DSYMUTIL+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_DSYMUTIL"; then + ac_cv_prog_ac_ct_DSYMUTIL="$ac_ct_DSYMUTIL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_DSYMUTIL="dsymutil" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_DSYMUTIL=$ac_cv_prog_ac_ct_DSYMUTIL +if test -n "$ac_ct_DSYMUTIL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DSYMUTIL" >&5 +$as_echo "$ac_ct_DSYMUTIL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_DSYMUTIL" = x; then + DSYMUTIL=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + DSYMUTIL=$ac_ct_DSYMUTIL + fi +else + DSYMUTIL="$ac_cv_prog_DSYMUTIL" +fi + + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}nmedit", so it can be a program name with args. +set dummy ${ac_tool_prefix}nmedit; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_NMEDIT+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$NMEDIT"; then + ac_cv_prog_NMEDIT="$NMEDIT" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_NMEDIT="${ac_tool_prefix}nmedit" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +NMEDIT=$ac_cv_prog_NMEDIT +if test -n "$NMEDIT"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $NMEDIT" >&5 +$as_echo "$NMEDIT" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_NMEDIT"; then + ac_ct_NMEDIT=$NMEDIT + # Extract the first word of "nmedit", so it can be a program name with args. +set dummy nmedit; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_NMEDIT+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_NMEDIT"; then + ac_cv_prog_ac_ct_NMEDIT="$ac_ct_NMEDIT" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_NMEDIT="nmedit" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_NMEDIT=$ac_cv_prog_ac_ct_NMEDIT +if test -n "$ac_ct_NMEDIT"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_NMEDIT" >&5 +$as_echo "$ac_ct_NMEDIT" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_NMEDIT" = x; then + NMEDIT=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + NMEDIT=$ac_ct_NMEDIT + fi +else + NMEDIT="$ac_cv_prog_NMEDIT" +fi + + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}lipo", so it can be a program name with args. +set dummy ${ac_tool_prefix}lipo; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_LIPO+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$LIPO"; then + ac_cv_prog_LIPO="$LIPO" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_LIPO="${ac_tool_prefix}lipo" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +LIPO=$ac_cv_prog_LIPO +if test -n "$LIPO"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIPO" >&5 +$as_echo "$LIPO" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_LIPO"; then + ac_ct_LIPO=$LIPO + # Extract the first word of "lipo", so it can be a program name with args. +set dummy lipo; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_LIPO+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_LIPO"; then + ac_cv_prog_ac_ct_LIPO="$ac_ct_LIPO" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_LIPO="lipo" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_LIPO=$ac_cv_prog_ac_ct_LIPO +if test -n "$ac_ct_LIPO"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_LIPO" >&5 +$as_echo "$ac_ct_LIPO" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_LIPO" = x; then + LIPO=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + LIPO=$ac_ct_LIPO + fi +else + LIPO="$ac_cv_prog_LIPO" +fi + + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}otool", so it can be a program name with args. +set dummy ${ac_tool_prefix}otool; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_OTOOL+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$OTOOL"; then + ac_cv_prog_OTOOL="$OTOOL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_OTOOL="${ac_tool_prefix}otool" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +OTOOL=$ac_cv_prog_OTOOL +if test -n "$OTOOL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL" >&5 +$as_echo "$OTOOL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_OTOOL"; then + ac_ct_OTOOL=$OTOOL + # Extract the first word of "otool", so it can be a program name with args. +set dummy otool; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_OTOOL+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_OTOOL"; then + ac_cv_prog_ac_ct_OTOOL="$ac_ct_OTOOL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_OTOOL="otool" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_OTOOL=$ac_cv_prog_ac_ct_OTOOL +if test -n "$ac_ct_OTOOL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL" >&5 +$as_echo "$ac_ct_OTOOL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_OTOOL" = x; then + OTOOL=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + OTOOL=$ac_ct_OTOOL + fi +else + OTOOL="$ac_cv_prog_OTOOL" +fi + + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}otool64", so it can be a program name with args. +set dummy ${ac_tool_prefix}otool64; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_OTOOL64+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$OTOOL64"; then + ac_cv_prog_OTOOL64="$OTOOL64" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_OTOOL64="${ac_tool_prefix}otool64" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +OTOOL64=$ac_cv_prog_OTOOL64 +if test -n "$OTOOL64"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL64" >&5 +$as_echo "$OTOOL64" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_OTOOL64"; then + ac_ct_OTOOL64=$OTOOL64 + # Extract the first word of "otool64", so it can be a program name with args. +set dummy otool64; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_OTOOL64+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_OTOOL64"; then + ac_cv_prog_ac_ct_OTOOL64="$ac_ct_OTOOL64" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_OTOOL64="otool64" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_OTOOL64=$ac_cv_prog_ac_ct_OTOOL64 +if test -n "$ac_ct_OTOOL64"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL64" >&5 +$as_echo "$ac_ct_OTOOL64" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_OTOOL64" = x; then + OTOOL64=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + OTOOL64=$ac_ct_OTOOL64 + fi +else + OTOOL64="$ac_cv_prog_OTOOL64" +fi + + + + + + + + + + + + + + + + + + + + + + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -single_module linker flag" >&5 +$as_echo_n "checking for -single_module linker flag... " >&6; } +if ${lt_cv_apple_cc_single_mod+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_apple_cc_single_mod=no + if test -z "${LT_MULTI_MODULE}"; then + # By default we will add the -single_module flag. You can override + # by either setting the environment variable LT_MULTI_MODULE + # non-empty at configure time, or by adding -multi_module to the + # link flags. + rm -rf libconftest.dylib* + echo "int foo(void){return 1;}" > conftest.c + echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ +-dynamiclib -Wl,-single_module conftest.c" >&5 + $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ + -dynamiclib -Wl,-single_module conftest.c 2>conftest.err + _lt_result=$? + # If there is a non-empty error log, and "single_module" + # appears in it, assume the flag caused a linker warning + if test -s conftest.err && $GREP single_module conftest.err; then + cat conftest.err >&5 + # Otherwise, if the output was created with a 0 exit code from + # the compiler, it worked. + elif test -f libconftest.dylib && test $_lt_result -eq 0; then + lt_cv_apple_cc_single_mod=yes + else + cat conftest.err >&5 + fi + rm -rf libconftest.dylib* + rm -f conftest.* + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_apple_cc_single_mod" >&5 +$as_echo "$lt_cv_apple_cc_single_mod" >&6; } + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -exported_symbols_list linker flag" >&5 +$as_echo_n "checking for -exported_symbols_list linker flag... " >&6; } +if ${lt_cv_ld_exported_symbols_list+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_ld_exported_symbols_list=no + save_LDFLAGS=$LDFLAGS + echo "_main" > conftest.sym + LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + lt_cv_ld_exported_symbols_list=yes +else + lt_cv_ld_exported_symbols_list=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LDFLAGS="$save_LDFLAGS" + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_exported_symbols_list" >&5 +$as_echo "$lt_cv_ld_exported_symbols_list" >&6; } + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -force_load linker flag" >&5 +$as_echo_n "checking for -force_load linker flag... " >&6; } +if ${lt_cv_ld_force_load+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_ld_force_load=no + cat > conftest.c << _LT_EOF +int forced_loaded() { return 2;} +_LT_EOF + echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&5 + $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&5 + echo "$AR cru libconftest.a conftest.o" >&5 + $AR cru libconftest.a conftest.o 2>&5 + echo "$RANLIB libconftest.a" >&5 + $RANLIB libconftest.a 2>&5 + cat > conftest.c << _LT_EOF +int main() { return 0;} +_LT_EOF + echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&5 + $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err + _lt_result=$? + if test -s conftest.err && $GREP force_load conftest.err; then + cat conftest.err >&5 + elif test -f conftest && test $_lt_result -eq 0 && $GREP forced_load conftest >/dev/null 2>&1 ; then + lt_cv_ld_force_load=yes + else + cat conftest.err >&5 + fi + rm -f conftest.err libconftest.a conftest conftest.c + rm -rf conftest.dSYM + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_force_load" >&5 +$as_echo "$lt_cv_ld_force_load" >&6; } + case $host_os in + rhapsody* | darwin1.[012]) + _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;; + darwin1.*) + _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; + darwin*) # darwin 5.x on + # if running on 10.5 or later, the deployment target defaults + # to the OS version, if on x86, and 10.4, the deployment + # target defaults to 10.4. Don't you love it? + case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in + 10.0,*86*-darwin8*|10.0,*-darwin[91]*) + _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; + 10.[012]*) + _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; + 10.*) + _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; + esac + ;; + esac + if test "$lt_cv_apple_cc_single_mod" = "yes"; then + _lt_dar_single_mod='$single_module' + fi + if test "$lt_cv_ld_exported_symbols_list" = "yes"; then + _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym' + else + _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}' + fi + if test "$DSYMUTIL" != ":" && test "$lt_cv_ld_force_load" = "no"; then + _lt_dsymutil='~$DSYMUTIL $lib || :' + else + _lt_dsymutil= + fi + ;; + esac + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 +$as_echo_n "checking how to run the C preprocessor... " >&6; } +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then + if ${ac_cv_prog_CPP+:} false; then : + $as_echo_n "(cached) " >&6 +else + # Double quotes because CPP needs to be expanded + for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" + do + ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.i conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.i conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + break +fi + + done + ac_cv_prog_CPP=$CPP + +fi + CPP=$ac_cv_prog_CPP +else + ac_cv_prog_CPP=$CPP +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 +$as_echo "$CPP" >&6; } +ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.i conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.i conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details" "$LINENO" 5; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 +$as_echo_n "checking for ANSI C header files... " >&6; } +if ${ac_cv_header_stdc+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#include +#include + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_header_stdc=yes +else + ac_cv_header_stdc=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "memchr" >/dev/null 2>&1; then : + +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "free" >/dev/null 2>&1; then : + +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. + if test "$cross_compiling" = yes; then : + : +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#if ((' ' & 0x0FF) == 0x020) +# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#else +# define ISLOWER(c) \ + (('a' <= (c) && (c) <= 'i') \ + || ('j' <= (c) && (c) <= 'r') \ + || ('s' <= (c) && (c) <= 'z')) +# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) +#endif + +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int +main () +{ + int i; + for (i = 0; i < 256; i++) + if (XOR (islower (i), ISLOWER (i)) + || toupper (i) != TOUPPER (i)) + return 2; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + +else + ac_cv_header_stdc=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 +$as_echo "$ac_cv_header_stdc" >&6; } +if test $ac_cv_header_stdc = yes; then + +$as_echo "#define STDC_HEADERS 1" >>confdefs.h + +fi + +# On IRIX 5.3, sys/types and inttypes.h are conflicting. +for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ + inttypes.h stdint.h unistd.h +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default +" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + +for ac_header in dlfcn.h +do : + ac_fn_c_check_header_compile "$LINENO" "dlfcn.h" "ac_cv_header_dlfcn_h" "$ac_includes_default +" +if test "x$ac_cv_header_dlfcn_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_DLFCN_H 1 +_ACEOF + +fi + +done + + + + +func_stripname_cnf () +{ + case ${2} in + .*) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;; + *) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%${2}\$%%"`;; + esac +} # func_stripname_cnf + + + + + +# Set options + + + + enable_dlopen=no + + + + # Check whether --enable-shared was given. +if test "${enable_shared+set}" = set; then : + enableval=$enable_shared; p=${PACKAGE-default} + case $enableval in + yes) enable_shared=yes ;; + no) enable_shared=no ;; + *) + enable_shared=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_shared=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac +else + enable_shared=yes +fi + + + + + + + + + + # Check whether --enable-static was given. +if test "${enable_static+set}" = set; then : + enableval=$enable_static; p=${PACKAGE-default} + case $enableval in + yes) enable_static=yes ;; + no) enable_static=no ;; + *) + enable_static=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_static=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac +else + enable_static=yes +fi + + + + + + + + + + +# Check whether --with-pic was given. +if test "${with_pic+set}" = set; then : + withval=$with_pic; lt_p=${PACKAGE-default} + case $withval in + yes|no) pic_mode=$withval ;; + *) + pic_mode=default + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for lt_pkg in $withval; do + IFS="$lt_save_ifs" + if test "X$lt_pkg" = "X$lt_p"; then + pic_mode=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac +else + pic_mode=default +fi + + +test -z "$pic_mode" && pic_mode=default + + + + + + + + # Check whether --enable-fast-install was given. +if test "${enable_fast_install+set}" = set; then : + enableval=$enable_fast_install; p=${PACKAGE-default} + case $enableval in + yes) enable_fast_install=yes ;; + no) enable_fast_install=no ;; + *) + enable_fast_install=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_fast_install=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac +else + enable_fast_install=yes +fi + + + + + + + + + + + +# This can be used to rebuild libtool when needed +LIBTOOL_DEPS="$ltmain" + +# Always use our own libtool. +LIBTOOL='$(SHELL) $(top_builddir)/libtool' + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +test -z "$LN_S" && LN_S="ln -s" + + + + + + + + + + + + + + +if test -n "${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for objdir" >&5 +$as_echo_n "checking for objdir... " >&6; } +if ${lt_cv_objdir+:} false; then : + $as_echo_n "(cached) " >&6 +else + rm -f .libs 2>/dev/null +mkdir .libs 2>/dev/null +if test -d .libs; then + lt_cv_objdir=.libs +else + # MS-DOS does not allow filenames that begin with a dot. + lt_cv_objdir=_libs +fi +rmdir .libs 2>/dev/null +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_objdir" >&5 +$as_echo "$lt_cv_objdir" >&6; } +objdir=$lt_cv_objdir + + + + + +cat >>confdefs.h <<_ACEOF +#define LT_OBJDIR "$lt_cv_objdir/" +_ACEOF + + + + +case $host_os in +aix3*) + # AIX sometimes has problems with the GCC collect2 program. For some + # reason, if we set the COLLECT_NAMES environment variable, the problems + # vanish in a puff of smoke. + if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES + fi + ;; +esac + +# Global variables: +ofile=libtool +can_build_shared=yes + +# All known linkers require a `.a' archive for static linking (except MSVC, +# which needs '.lib'). +libext=a + +with_gnu_ld="$lt_cv_prog_gnu_ld" + +old_CC="$CC" +old_CFLAGS="$CFLAGS" + +# Set sane defaults for various variables +test -z "$CC" && CC=cc +test -z "$LTCC" && LTCC=$CC +test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS +test -z "$LD" && LD=ld +test -z "$ac_objext" && ac_objext=o + +for cc_temp in $compiler""; do + case $cc_temp in + compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; + distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; + \-*) ;; + *) break;; + esac +done +cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` + + +# Only perform the check for file, if the check method requires it +test -z "$MAGIC_CMD" && MAGIC_CMD=file +case $deplibs_check_method in +file_magic*) + if test "$file_magic_cmd" = '$MAGIC_CMD'; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${ac_tool_prefix}file" >&5 +$as_echo_n "checking for ${ac_tool_prefix}file... " >&6; } +if ${lt_cv_path_MAGIC_CMD+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $MAGIC_CMD in +[\\/*] | ?:[\\/]*) + lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. + ;; +*) + lt_save_MAGIC_CMD="$MAGIC_CMD" + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" + for ac_dir in $ac_dummy; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/${ac_tool_prefix}file; then + lt_cv_path_MAGIC_CMD="$ac_dir/${ac_tool_prefix}file" + if test -n "$file_magic_test_file"; then + case $deplibs_check_method in + "file_magic "*) + file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` + MAGIC_CMD="$lt_cv_path_MAGIC_CMD" + if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | + $EGREP "$file_magic_regex" > /dev/null; then + : + else + cat <<_LT_EOF 1>&2 + +*** Warning: the command libtool uses to detect shared libraries, +*** $file_magic_cmd, produces output that libtool cannot recognize. +*** The result is that libtool may fail to recognize shared libraries +*** as such. This will affect the creation of libtool libraries that +*** depend on shared libraries, but programs linked with such libtool +*** libraries will work regardless of this problem. Nevertheless, you +*** may want to report the problem to your system manager and/or to +*** bug-libtool@gnu.org + +_LT_EOF + fi ;; + esac + fi + break + fi + done + IFS="$lt_save_ifs" + MAGIC_CMD="$lt_save_MAGIC_CMD" + ;; +esac +fi + +MAGIC_CMD="$lt_cv_path_MAGIC_CMD" +if test -n "$MAGIC_CMD"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 +$as_echo "$MAGIC_CMD" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + + + +if test -z "$lt_cv_path_MAGIC_CMD"; then + if test -n "$ac_tool_prefix"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for file" >&5 +$as_echo_n "checking for file... " >&6; } +if ${lt_cv_path_MAGIC_CMD+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $MAGIC_CMD in +[\\/*] | ?:[\\/]*) + lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. + ;; +*) + lt_save_MAGIC_CMD="$MAGIC_CMD" + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" + for ac_dir in $ac_dummy; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/file; then + lt_cv_path_MAGIC_CMD="$ac_dir/file" + if test -n "$file_magic_test_file"; then + case $deplibs_check_method in + "file_magic "*) + file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` + MAGIC_CMD="$lt_cv_path_MAGIC_CMD" + if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | + $EGREP "$file_magic_regex" > /dev/null; then + : + else + cat <<_LT_EOF 1>&2 + +*** Warning: the command libtool uses to detect shared libraries, +*** $file_magic_cmd, produces output that libtool cannot recognize. +*** The result is that libtool may fail to recognize shared libraries +*** as such. This will affect the creation of libtool libraries that +*** depend on shared libraries, but programs linked with such libtool +*** libraries will work regardless of this problem. Nevertheless, you +*** may want to report the problem to your system manager and/or to +*** bug-libtool@gnu.org + +_LT_EOF + fi ;; + esac + fi + break + fi + done + IFS="$lt_save_ifs" + MAGIC_CMD="$lt_save_MAGIC_CMD" + ;; +esac +fi + +MAGIC_CMD="$lt_cv_path_MAGIC_CMD" +if test -n "$MAGIC_CMD"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 +$as_echo "$MAGIC_CMD" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + else + MAGIC_CMD=: + fi +fi + + fi + ;; +esac + +# Use C for the default configuration in the libtool script + +lt_save_CC="$CC" +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +# Source file extension for C test sources. +ac_ext=c + +# Object file extension for compiled C test sources. +objext=o +objext=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="int some_variable = 0;" + +# Code to be used in simple link tests +lt_simple_link_test_code='int main(){return(0);}' + + + + + + + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# If no C compiler flags were specified, use CFLAGS. +LTCFLAGS=${LTCFLAGS-"$CFLAGS"} + +# Allow CC to be a program name with arguments. +compiler=$CC + +# Save the default compiler, since it gets overwritten when the other +# tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP. +compiler_DEFAULT=$CC + +# save warnings/boilerplate of simple test code +ac_outfile=conftest.$ac_objext +echo "$lt_simple_compile_test_code" >conftest.$ac_ext +eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_compiler_boilerplate=`cat conftest.err` +$RM conftest* + +ac_outfile=conftest.$ac_objext +echo "$lt_simple_link_test_code" >conftest.$ac_ext +eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_linker_boilerplate=`cat conftest.err` +$RM -r conftest* + + +if test -n "$compiler"; then + +lt_prog_compiler_no_builtin_flag= + +if test "$GCC" = yes; then + case $cc_basename in + nvcc*) + lt_prog_compiler_no_builtin_flag=' -Xcompiler -fno-builtin' ;; + *) + lt_prog_compiler_no_builtin_flag=' -fno-builtin' ;; + esac + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -fno-rtti -fno-exceptions" >&5 +$as_echo_n "checking if $compiler supports -fno-rtti -fno-exceptions... " >&6; } +if ${lt_cv_prog_compiler_rtti_exceptions+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_rtti_exceptions=no + ac_outfile=conftest.$ac_objext + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="-fno-rtti -fno-exceptions" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings other than the usual output. + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler_rtti_exceptions=yes + fi + fi + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_rtti_exceptions" >&5 +$as_echo "$lt_cv_prog_compiler_rtti_exceptions" >&6; } + +if test x"$lt_cv_prog_compiler_rtti_exceptions" = xyes; then + lt_prog_compiler_no_builtin_flag="$lt_prog_compiler_no_builtin_flag -fno-rtti -fno-exceptions" +else + : +fi + +fi + + + + + + + lt_prog_compiler_wl= +lt_prog_compiler_pic= +lt_prog_compiler_static= + + + if test "$GCC" = yes; then + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_static='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static='-Bstatic' + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + lt_prog_compiler_pic='-fPIC' + ;; + m68k) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + lt_prog_compiler_pic='-m68020 -resident32 -malways-restore-a4' + ;; + esac + ;; + + beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + + mingw* | cygwin* | pw32* | os2* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + # Although the cygwin gcc ignores -fPIC, still need this for old-style + # (--disable-auto-import) libraries + lt_prog_compiler_pic='-DDLL_EXPORT' + ;; + + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + lt_prog_compiler_pic='-fno-common' + ;; + + haiku*) + # PIC is the default for Haiku. + # The "-static" flag exists, but is broken. + lt_prog_compiler_static= + ;; + + hpux*) + # PIC is the default for 64-bit PA HP-UX, but not for 32-bit + # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag + # sets the default TLS model and affects inlining. + case $host_cpu in + hppa*64*) + # +Z the default + ;; + *) + lt_prog_compiler_pic='-fPIC' + ;; + esac + ;; + + interix[3-9]*) + # Interix 3.x gcc -fpic/-fPIC options generate broken code. + # Instead, we relocate shared libraries at runtime. + ;; + + msdosdjgpp*) + # Just because we use GCC doesn't mean we suddenly get shared libraries + # on systems that don't support them. + lt_prog_compiler_can_build_shared=no + enable_shared=no + ;; + + *nto* | *qnx*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + lt_prog_compiler_pic='-fPIC -shared' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + lt_prog_compiler_pic=-Kconform_pic + fi + ;; + + *) + lt_prog_compiler_pic='-fPIC' + ;; + esac + + case $cc_basename in + nvcc*) # Cuda Compiler Driver 2.2 + lt_prog_compiler_wl='-Xlinker ' + if test -n "$lt_prog_compiler_pic"; then + lt_prog_compiler_pic="-Xcompiler $lt_prog_compiler_pic" + fi + ;; + esac + else + # PORTME Check for flag to pass linker flags through the system compiler. + case $host_os in + aix*) + lt_prog_compiler_wl='-Wl,' + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static='-Bstatic' + else + lt_prog_compiler_static='-bnso -bI:/lib/syscalls.exp' + fi + ;; + + mingw* | cygwin* | pw32* | os2* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + lt_prog_compiler_pic='-DDLL_EXPORT' + ;; + + hpux9* | hpux10* | hpux11*) + lt_prog_compiler_wl='-Wl,' + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + lt_prog_compiler_pic='+Z' + ;; + esac + # Is there a better lt_prog_compiler_static that works with the bundled CC? + lt_prog_compiler_static='${wl}-a ${wl}archive' + ;; + + irix5* | irix6* | nonstopux*) + lt_prog_compiler_wl='-Wl,' + # PIC (with -KPIC) is the default. + lt_prog_compiler_static='-non_shared' + ;; + + linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) + case $cc_basename in + # old Intel for x86_64 which still supported -KPIC. + ecc*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-static' + ;; + # icc used to be incompatible with GCC. + # ICC 10 doesn't accept -KPIC any more. + icc* | ifort*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-fPIC' + lt_prog_compiler_static='-static' + ;; + # Lahey Fortran 8.1. + lf95*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='--shared' + lt_prog_compiler_static='--static' + ;; + nagfor*) + # NAG Fortran compiler + lt_prog_compiler_wl='-Wl,-Wl,,' + lt_prog_compiler_pic='-PIC' + lt_prog_compiler_static='-Bstatic' + ;; + pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*) + # Portland Group compilers (*not* the Pentium gcc compiler, + # which looks to be a dead project) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-fpic' + lt_prog_compiler_static='-Bstatic' + ;; + ccc*) + lt_prog_compiler_wl='-Wl,' + # All Alpha code is PIC. + lt_prog_compiler_static='-non_shared' + ;; + xl* | bgxl* | bgf* | mpixl*) + # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-qpic' + lt_prog_compiler_static='-qstaticlink' + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [1-7].* | *Sun*Fortran*\ 8.[0-3]*) + # Sun Fortran 8.3 passes all unrecognized flags to the linker + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + lt_prog_compiler_wl='' + ;; + *Sun\ F* | *Sun*Fortran*) + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + lt_prog_compiler_wl='-Qoption ld ' + ;; + *Sun\ C*) + # Sun C 5.9 + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + lt_prog_compiler_wl='-Wl,' + ;; + *Intel*\ [CF]*Compiler*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-fPIC' + lt_prog_compiler_static='-static' + ;; + *Portland\ Group*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-fpic' + lt_prog_compiler_static='-Bstatic' + ;; + esac + ;; + esac + ;; + + newsos6) + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + ;; + + *nto* | *qnx*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + lt_prog_compiler_pic='-fPIC -shared' + ;; + + osf3* | osf4* | osf5*) + lt_prog_compiler_wl='-Wl,' + # All OSF/1 code is PIC. + lt_prog_compiler_static='-non_shared' + ;; + + rdos*) + lt_prog_compiler_static='-non_shared' + ;; + + solaris*) + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + case $cc_basename in + f77* | f90* | f95* | sunf77* | sunf90* | sunf95*) + lt_prog_compiler_wl='-Qoption ld ';; + *) + lt_prog_compiler_wl='-Wl,';; + esac + ;; + + sunos4*) + lt_prog_compiler_wl='-Qoption ld ' + lt_prog_compiler_pic='-PIC' + lt_prog_compiler_static='-Bstatic' + ;; + + sysv4 | sysv4.2uw2* | sysv4.3*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + ;; + + sysv4*MP*) + if test -d /usr/nec ;then + lt_prog_compiler_pic='-Kconform_pic' + lt_prog_compiler_static='-Bstatic' + fi + ;; + + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + ;; + + unicos*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_can_build_shared=no + ;; + + uts4*) + lt_prog_compiler_pic='-pic' + lt_prog_compiler_static='-Bstatic' + ;; + + *) + lt_prog_compiler_can_build_shared=no + ;; + esac + fi + +case $host_os in + # For platforms which do not support PIC, -DPIC is meaningless: + *djgpp*) + lt_prog_compiler_pic= + ;; + *) + lt_prog_compiler_pic="$lt_prog_compiler_pic -DPIC" + ;; +esac + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5 +$as_echo_n "checking for $compiler option to produce PIC... " >&6; } +if ${lt_cv_prog_compiler_pic+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_pic=$lt_prog_compiler_pic +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic" >&5 +$as_echo "$lt_cv_prog_compiler_pic" >&6; } +lt_prog_compiler_pic=$lt_cv_prog_compiler_pic + +# +# Check to make sure the PIC flag actually works. +# +if test -n "$lt_prog_compiler_pic"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic works" >&5 +$as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic works... " >&6; } +if ${lt_cv_prog_compiler_pic_works+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_pic_works=no + ac_outfile=conftest.$ac_objext + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="$lt_prog_compiler_pic -DPIC" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings other than the usual output. + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler_pic_works=yes + fi + fi + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works" >&5 +$as_echo "$lt_cv_prog_compiler_pic_works" >&6; } + +if test x"$lt_cv_prog_compiler_pic_works" = xyes; then + case $lt_prog_compiler_pic in + "" | " "*) ;; + *) lt_prog_compiler_pic=" $lt_prog_compiler_pic" ;; + esac +else + lt_prog_compiler_pic= + lt_prog_compiler_can_build_shared=no +fi + +fi + + + + + + + + + + + +# +# Check to make sure the static flag actually works. +# +wl=$lt_prog_compiler_wl eval lt_tmp_static_flag=\"$lt_prog_compiler_static\" +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5 +$as_echo_n "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; } +if ${lt_cv_prog_compiler_static_works+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_static_works=no + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS $lt_tmp_static_flag" + echo "$lt_simple_link_test_code" > conftest.$ac_ext + if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then + # The linker can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + # Append any errors to the config.log. + cat conftest.err 1>&5 + $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler_static_works=yes + fi + else + lt_cv_prog_compiler_static_works=yes + fi + fi + $RM -r conftest* + LDFLAGS="$save_LDFLAGS" + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works" >&5 +$as_echo "$lt_cv_prog_compiler_static_works" >&6; } + +if test x"$lt_cv_prog_compiler_static_works" = xyes; then + : +else + lt_prog_compiler_static= +fi + + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 +$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } +if ${lt_cv_prog_compiler_c_o+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_c_o=no + $RM -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp + $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 + if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then + lt_cv_prog_compiler_c_o=yes + fi + fi + chmod u+w . 2>&5 + $RM conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files + $RM out/* && rmdir out + cd .. + $RM -r conftest + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 +$as_echo "$lt_cv_prog_compiler_c_o" >&6; } + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 +$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } +if ${lt_cv_prog_compiler_c_o+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_c_o=no + $RM -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp + $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 + if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then + lt_cv_prog_compiler_c_o=yes + fi + fi + chmod u+w . 2>&5 + $RM conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files + $RM out/* && rmdir out + cd .. + $RM -r conftest + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 +$as_echo "$lt_cv_prog_compiler_c_o" >&6; } + + + + +hard_links="nottested" +if test "$lt_cv_prog_compiler_c_o" = no && test "$need_locks" != no; then + # do not overwrite the value of need_locks provided by the user + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5 +$as_echo_n "checking if we can lock with hard links... " >&6; } + hard_links=yes + $RM conftest* + ln conftest.a conftest.b 2>/dev/null && hard_links=no + touch conftest.a + ln conftest.a conftest.b 2>&5 || hard_links=no + ln conftest.a conftest.b 2>/dev/null && hard_links=no + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5 +$as_echo "$hard_links" >&6; } + if test "$hard_links" = no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5 +$as_echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;} + need_locks=warn + fi +else + need_locks=no +fi + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5 +$as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; } + + runpath_var= + allow_undefined_flag= + always_export_symbols=no + archive_cmds= + archive_expsym_cmds= + compiler_needs_object=no + enable_shared_with_static_runtimes=no + export_dynamic_flag_spec= + export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + hardcode_automatic=no + hardcode_direct=no + hardcode_direct_absolute=no + hardcode_libdir_flag_spec= + hardcode_libdir_separator= + hardcode_minus_L=no + hardcode_shlibpath_var=unsupported + inherit_rpath=no + link_all_deplibs=unknown + module_cmds= + module_expsym_cmds= + old_archive_from_new_cmds= + old_archive_from_expsyms_cmds= + thread_safe_flag_spec= + whole_archive_flag_spec= + # include_expsyms should be a list of space-separated symbols to be *always* + # included in the symbol list + include_expsyms= + # exclude_expsyms can be an extended regexp of symbols to exclude + # it will be wrapped by ` (' and `)$', so one must not match beginning or + # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', + # as well as any symbol that contains `d'. + exclude_expsyms='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*' + # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out + # platforms (ab)use it in PIC code, but their linkers get confused if + # the symbol is explicitly referenced. Since portable code cannot + # rely on this symbol name, it's probably fine to never include it in + # preloaded symbol tables. + # Exclude shared library initialization/finalization symbols. + extract_expsyms_cmds= + + case $host_os in + cygwin* | mingw* | pw32* | cegcc*) + # FIXME: the MSVC++ port hasn't been tested in a loooong time + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + if test "$GCC" != yes; then + with_gnu_ld=no + fi + ;; + interix*) + # we just hope/assume this is gcc and not c89 (= MSVC++) + with_gnu_ld=yes + ;; + openbsd*) + with_gnu_ld=no + ;; + linux* | k*bsd*-gnu | gnu*) + link_all_deplibs=no + ;; + esac + + ld_shlibs=yes + + # On some targets, GNU ld is compatible enough with the native linker + # that we're better off using the native interface for both. + lt_use_gnu_ld_interface=no + if test "$with_gnu_ld" = yes; then + case $host_os in + aix*) + # The AIX port of GNU ld has always aspired to compatibility + # with the native linker. However, as the warning in the GNU ld + # block says, versions before 2.19.5* couldn't really create working + # shared libraries, regardless of the interface used. + case `$LD -v 2>&1` in + *\ \(GNU\ Binutils\)\ 2.19.5*) ;; + *\ \(GNU\ Binutils\)\ 2.[2-9]*) ;; + *\ \(GNU\ Binutils\)\ [3-9]*) ;; + *) + lt_use_gnu_ld_interface=yes + ;; + esac + ;; + *) + lt_use_gnu_ld_interface=yes + ;; + esac + fi + + if test "$lt_use_gnu_ld_interface" = yes; then + # If archive_cmds runs LD, not CC, wlarc should be empty + wlarc='${wl}' + + # Set some defaults for GNU ld with shared library support. These + # are reset later if shared libraries are not supported. Putting them + # here allows them to be overridden if necessary. + runpath_var=LD_RUN_PATH + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + export_dynamic_flag_spec='${wl}--export-dynamic' + # ancient GNU ld didn't support --whole-archive et. al. + if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then + whole_archive_flag_spec="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + whole_archive_flag_spec= + fi + supports_anon_versioning=no + case `$LD -v 2>&1` in + *GNU\ gold*) supports_anon_versioning=yes ;; + *\ [01].* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11 + *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... + *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... + *\ 2.11.*) ;; # other 2.11 versions + *) supports_anon_versioning=yes ;; + esac + + # See if GNU ld supports shared libraries. + case $host_os in + aix[3-9]*) + # On AIX/PPC, the GNU linker is very broken + if test "$host_cpu" != ia64; then + ld_shlibs=no + cat <<_LT_EOF 1>&2 + +*** Warning: the GNU linker, at least up to release 2.19, is reported +*** to be unable to reliably create shared libraries on AIX. +*** Therefore, libtool is disabling shared libraries support. If you +*** really care for shared libraries, you may want to install binutils +*** 2.20 or above, or modify your PATH so that a non-GNU linker is found. +*** You will then need to restart the configuration process. + +_LT_EOF + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='' + ;; + m68k) + archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + ;; + esac + ;; + + beos*) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + allow_undefined_flag=unsupported + # Joseph Beckenbach says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + archive_cmds='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + else + ld_shlibs=no + fi + ;; + + cygwin* | mingw* | pw32* | cegcc*) + # _LT_TAGVAR(hardcode_libdir_flag_spec, ) is actually meaningless, + # as there is no search path for DLLs. + hardcode_libdir_flag_spec='-L$libdir' + export_dynamic_flag_spec='${wl}--export-all-symbols' + allow_undefined_flag=unsupported + always_export_symbols=no + enable_shared_with_static_runtimes=yes + export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/;s/^.*[ ]__nm__\([^ ]*\)[ ][^ ]*/\1 DATA/;/^I[ ]/d;/^[AITW][ ]/s/.* //'\'' | sort | uniq > $export_symbols' + exclude_expsyms='[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname' + + if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is; otherwise, prepend... + archive_expsym_cmds='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + else + ld_shlibs=no + fi + ;; + + haiku*) + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + link_all_deplibs=yes + ;; + + interix[3-9]*) + hardcode_direct=no + hardcode_shlibpath_var=no + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + export_dynamic_flag_spec='${wl}-E' + # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. + # Instead, shared libraries are loaded at an image base (0x10000000 by + # default) and relocated if they conflict, which is a slow very memory + # consuming and fragmenting process. To avoid this, we pick a random, + # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link + # time. Moving up from 0x10000000 also allows more sbrk(2) space. + archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + archive_expsym_cmds='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + ;; + + gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu) + tmp_diet=no + if test "$host_os" = linux-dietlibc; then + case $cc_basename in + diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn) + esac + fi + if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \ + && test "$tmp_diet" = no + then + tmp_addflag=' $pic_flag' + tmp_sharedflag='-shared' + case $cc_basename,$host_cpu in + pgcc*) # Portland Group C compiler + whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_addflag=' $pic_flag' + ;; + pgf77* | pgf90* | pgf95* | pgfortran*) + # Portland Group f77 and f90 compilers + whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_addflag=' $pic_flag -Mnomain' ;; + ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 + tmp_addflag=' -i_dynamic' ;; + efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 + tmp_addflag=' -i_dynamic -nofor_main' ;; + ifc* | ifort*) # Intel Fortran compiler + tmp_addflag=' -nofor_main' ;; + lf95*) # Lahey Fortran 8.1 + whole_archive_flag_spec= + tmp_sharedflag='--shared' ;; + xl[cC]* | bgxl[cC]* | mpixl[cC]*) # IBM XL C 8.0 on PPC (deal with xlf below) + tmp_sharedflag='-qmkshrobj' + tmp_addflag= ;; + nvcc*) # Cuda Compiler Driver 2.2 + whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + compiler_needs_object=yes + ;; + esac + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) # Sun C 5.9 + whole_archive_flag_spec='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + compiler_needs_object=yes + tmp_sharedflag='-G' ;; + *Sun\ F*) # Sun Fortran 8.3 + tmp_sharedflag='-G' ;; + esac + archive_cmds='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + + if test "x$supports_anon_versioning" = xyes; then + archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' + fi + + case $cc_basename in + xlf* | bgf* | bgxlf* | mpixlf*) + # IBM XL Fortran 10.1 on PPC cannot create shared libs itself + whole_archive_flag_spec='--whole-archive$convenience --no-whole-archive' + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + archive_cmds='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib' + if test "x$supports_anon_versioning" = xyes; then + archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib' + fi + ;; + esac + else + ld_shlibs=no + fi + ;; + + netbsd* | netbsdelf*-gnu) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' + wlarc= + else + archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + fi + ;; + + solaris*) + if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then + ld_shlibs=no + cat <<_LT_EOF 1>&2 + +*** Warning: The releases 2.8.* of the GNU linker cannot reliably +*** create shared libraries on Solaris systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.9.1 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +_LT_EOF + elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + ld_shlibs=no + fi + ;; + + sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) + case `$LD -v 2>&1` in + *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*) + ld_shlibs=no + cat <<_LT_EOF 1>&2 + +*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not +*** reliably create shared libraries on SCO systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.16.91.0.3 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +_LT_EOF + ;; + *) + # For security reasons, it is highly recommended that you always + # use absolute paths for naming shared libraries, and exclude the + # DT_RUNPATH tag from executables and libraries. But doing so + # requires that you compile everything twice, which is a pain. + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + ld_shlibs=no + fi + ;; + esac + ;; + + sunos4*) + archive_cmds='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' + wlarc= + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + *) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + ld_shlibs=no + fi + ;; + esac + + if test "$ld_shlibs" = no; then + runpath_var= + hardcode_libdir_flag_spec= + export_dynamic_flag_spec= + whole_archive_flag_spec= + fi + else + # PORTME fill in a description of your system's linker (not GNU ld) + case $host_os in + aix3*) + allow_undefined_flag=unsupported + always_export_symbols=yes + archive_expsym_cmds='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' + # Note: this linker hardcodes the directories in LIBPATH if there + # are no directories specified by -L. + hardcode_minus_L=yes + if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then + # Neither direct hardcoding nor static linking is supported with a + # broken collect2. + hardcode_direct=unsupported + fi + ;; + + aix[4-9]*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to AIX nm, but means don't demangle with GNU nm + # Also, AIX nm treats weak defined symbols like other global + # defined symbols, whereas GNU nm marks them as "W". + if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then + export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + else + export_symbols_cmds='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + fi + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*) + for ld_flag in $LDFLAGS; do + if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then + aix_use_runtimelinking=yes + break + fi + done + ;; + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + archive_cmds='' + hardcode_direct=yes + hardcode_direct_absolute=yes + hardcode_libdir_separator=':' + link_all_deplibs=yes + file_list_spec='${wl}-f,' + + if test "$GCC" = yes; then + case $host_os in aix4.[012]|aix4.[012].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && + strings "$collect2name" | $GREP resolve_lib_name >/dev/null + then + # We have reworked collect2 + : + else + # We have old collect2 + hardcode_direct=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + hardcode_minus_L=yes + hardcode_libdir_flag_spec='-L$libdir' + hardcode_libdir_separator= + fi + ;; + esac + shared_flag='-shared' + if test "$aix_use_runtimelinking" = yes; then + shared_flag="$shared_flag "'${wl}-G' + fi + link_all_deplibs=no + else + # not using gcc + if test "$host_cpu" = ia64; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='${wl}-G' + else + shared_flag='${wl}-bM:SRE' + fi + fi + fi + + export_dynamic_flag_spec='${wl}-bexpall' + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to export. + always_export_symbols=yes + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + allow_undefined_flag='-berok' + # Determine the default libpath from the value encoded in an + # empty executable. + if test "${lt_cv_aix_libpath+set}" = set; then + aix_libpath=$lt_cv_aix_libpath +else + if ${lt_cv_aix_libpath_+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + + lt_aix_libpath_sed=' + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\([^ ]*\) *$/\1/ + p + } + }' + lt_cv_aix_libpath_=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` + # Check for a 64-bit object if we didn't find anything. + if test -z "$lt_cv_aix_libpath_"; then + lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` + fi +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + if test -z "$lt_cv_aix_libpath_"; then + lt_cv_aix_libpath_="/usr/lib:/lib" + fi + +fi + + aix_libpath=$lt_cv_aix_libpath_ +fi + + hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" + archive_expsym_cmds='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib' + allow_undefined_flag="-z nodefs" + archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an + # empty executable. + if test "${lt_cv_aix_libpath+set}" = set; then + aix_libpath=$lt_cv_aix_libpath +else + if ${lt_cv_aix_libpath_+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + + lt_aix_libpath_sed=' + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\([^ ]*\) *$/\1/ + p + } + }' + lt_cv_aix_libpath_=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` + # Check for a 64-bit object if we didn't find anything. + if test -z "$lt_cv_aix_libpath_"; then + lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` + fi +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + if test -z "$lt_cv_aix_libpath_"; then + lt_cv_aix_libpath_="/usr/lib:/lib" + fi + +fi + + aix_libpath=$lt_cv_aix_libpath_ +fi + + hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + no_undefined_flag=' ${wl}-bernotok' + allow_undefined_flag=' ${wl}-berok' + if test "$with_gnu_ld" = yes; then + # We only use this code for GNU lds that support --whole-archive. + whole_archive_flag_spec='${wl}--whole-archive$convenience ${wl}--no-whole-archive' + else + # Exported symbols can be pulled into shared objects from archives + whole_archive_flag_spec='$convenience' + fi + archive_cmds_need_lc=yes + # This is similar to how AIX traditionally builds its shared libraries. + archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + fi + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='' + ;; + m68k) + archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + ;; + esac + ;; + + bsdi[45]*) + export_dynamic_flag_spec=-rdynamic + ;; + + cygwin* | mingw* | pw32* | cegcc*) + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + case $cc_basename in + cl*) + # Native MSVC + hardcode_libdir_flag_spec=' ' + allow_undefined_flag=unsupported + always_export_symbols=yes + file_list_spec='@' + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=".dll" + # FIXME: Setting linknames here is a bad hack. + archive_cmds='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames=' + archive_expsym_cmds='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + sed -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp; + else + sed -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp; + fi~ + $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ + linknames=' + # The linker will not automatically build a static lib if we build a DLL. + # _LT_TAGVAR(old_archive_from_new_cmds, )='true' + enable_shared_with_static_runtimes=yes + exclude_expsyms='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' + export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1,DATA/'\'' | $SED -e '\''/^[AITW][ ]/s/.*[ ]//'\'' | sort | uniq > $export_symbols' + # Don't use ranlib + old_postinstall_cmds='chmod 644 $oldlib' + postlink_cmds='lt_outputfile="@OUTPUT@"~ + lt_tool_outputfile="@TOOL_OUTPUT@"~ + case $lt_outputfile in + *.exe|*.EXE) ;; + *) + lt_outputfile="$lt_outputfile.exe" + lt_tool_outputfile="$lt_tool_outputfile.exe" + ;; + esac~ + if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then + $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; + $RM "$lt_outputfile.manifest"; + fi' + ;; + *) + # Assume MSVC wrapper + hardcode_libdir_flag_spec=' ' + allow_undefined_flag=unsupported + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=".dll" + # FIXME: Setting linknames here is a bad hack. + archive_cmds='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames=' + # The linker will automatically build a .lib file if we build a DLL. + old_archive_from_new_cmds='true' + # FIXME: Should let the user specify the lib program. + old_archive_cmds='lib -OUT:$oldlib$oldobjs$old_deplibs' + enable_shared_with_static_runtimes=yes + ;; + esac + ;; + + darwin* | rhapsody*) + + + archive_cmds_need_lc=no + hardcode_direct=no + hardcode_automatic=yes + hardcode_shlibpath_var=unsupported + if test "$lt_cv_ld_force_load" = "yes"; then + whole_archive_flag_spec='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`' + + else + whole_archive_flag_spec='' + fi + link_all_deplibs=yes + allow_undefined_flag="$_lt_dar_allow_undefined" + case $cc_basename in + ifort*) _lt_dar_can_shared=yes ;; + *) _lt_dar_can_shared=$GCC ;; + esac + if test "$_lt_dar_can_shared" = "yes"; then + output_verbose_link_cmd=func_echo_all + archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" + module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" + archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" + module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" + + else + ld_shlibs=no + fi + + ;; + + dgux*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_shlibpath_var=no + ;; + + # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor + # support. Future versions do this automatically, but an explicit c++rt0.o + # does not break anything, and helps significantly (at the cost of a little + # extra space). + freebsd2.2*) + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + # Unfortunately, older versions of FreeBSD 2 do not have this feature. + freebsd2.*) + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=yes + hardcode_minus_L=yes + hardcode_shlibpath_var=no + ;; + + # FreeBSD 3 and greater uses gcc -shared to do shared libraries. + freebsd* | dragonfly*) + archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + hpux9*) + if test "$GCC" = yes; then + archive_cmds='$RM $output_objdir/$soname~$CC -shared $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + else + archive_cmds='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + fi + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_separator=: + hardcode_direct=yes + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + export_dynamic_flag_spec='${wl}-E' + ;; + + hpux10*) + if test "$GCC" = yes && test "$with_gnu_ld" = no; then + archive_cmds='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' + fi + if test "$with_gnu_ld" = no; then + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_separator=: + hardcode_direct=yes + hardcode_direct_absolute=yes + export_dynamic_flag_spec='${wl}-E' + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + fi + ;; + + hpux11*) + if test "$GCC" = yes && test "$with_gnu_ld" = no; then + case $host_cpu in + hppa*64*) + archive_cmds='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + archive_cmds='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + archive_cmds='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + else + case $host_cpu in + hppa*64*) + archive_cmds='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + + # Older versions of the 11.00 compiler do not understand -b yet + # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does) + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC understands -b" >&5 +$as_echo_n "checking if $CC understands -b... " >&6; } +if ${lt_cv_prog_compiler__b+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler__b=no + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS -b" + echo "$lt_simple_link_test_code" > conftest.$ac_ext + if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then + # The linker can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + # Append any errors to the config.log. + cat conftest.err 1>&5 + $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler__b=yes + fi + else + lt_cv_prog_compiler__b=yes + fi + fi + $RM -r conftest* + LDFLAGS="$save_LDFLAGS" + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler__b" >&5 +$as_echo "$lt_cv_prog_compiler__b" >&6; } + +if test x"$lt_cv_prog_compiler__b" = xyes; then + archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' +else + archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' +fi + + ;; + esac + fi + if test "$with_gnu_ld" = no; then + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_separator=: + + case $host_cpu in + hppa*64*|ia64*) + hardcode_direct=no + hardcode_shlibpath_var=no + ;; + *) + hardcode_direct=yes + hardcode_direct_absolute=yes + export_dynamic_flag_spec='${wl}-E' + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + ;; + esac + fi + ;; + + irix5* | irix6* | nonstopux*) + if test "$GCC" = yes; then + archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + # Try to use the -exported_symbol ld option, if it does not + # work, assume that -exports_file does not work either and + # implicitly export all symbols. + # This should be the same for all languages, so no per-tag cache variable. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $host_os linker accepts -exported_symbol" >&5 +$as_echo_n "checking whether the $host_os linker accepts -exported_symbol... " >&6; } +if ${lt_cv_irix_exported_symbol+:} false; then : + $as_echo_n "(cached) " >&6 +else + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +int foo (void) { return 0; } +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + lt_cv_irix_exported_symbol=yes +else + lt_cv_irix_exported_symbol=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LDFLAGS="$save_LDFLAGS" +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_irix_exported_symbol" >&5 +$as_echo "$lt_cv_irix_exported_symbol" >&6; } + if test "$lt_cv_irix_exported_symbol" = yes; then + archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib' + fi + else + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib' + fi + archive_cmds_need_lc='no' + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + inherit_rpath=yes + link_all_deplibs=yes + ;; + + netbsd* | netbsdelf*-gnu) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out + else + archive_cmds='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF + fi + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + newsos6) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=yes + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + hardcode_shlibpath_var=no + ;; + + *nto* | *qnx*) + ;; + + openbsd*) + if test -f /usr/libexec/ld.so; then + hardcode_direct=yes + hardcode_shlibpath_var=no + hardcode_direct_absolute=yes + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols' + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + export_dynamic_flag_spec='${wl}-E' + else + case $host_os in + openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*) + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec='-R$libdir' + ;; + *) + archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + ;; + esac + fi + else + ld_shlibs=no + fi + ;; + + os2*) + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + allow_undefined_flag=unsupported + archive_cmds='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~echo DATA >> $output_objdir/$libname.def~echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' + old_archive_from_new_cmds='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' + ;; + + osf3*) + if test "$GCC" = yes; then + allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + allow_undefined_flag=' -expect_unresolved \*' + archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' + fi + archive_cmds_need_lc='no' + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + ;; + + osf4* | osf5*) # as osf3* with the addition of -msym flag + if test "$GCC" = yes; then + allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds='$CC -shared${allow_undefined_flag} $pic_flag $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + else + allow_undefined_flag=' -expect_unresolved \*' + archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' + archive_expsym_cmds='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~ + $CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp' + + # Both c and cxx compiler support -rpath directly + hardcode_libdir_flag_spec='-rpath $libdir' + fi + archive_cmds_need_lc='no' + hardcode_libdir_separator=: + ;; + + solaris*) + no_undefined_flag=' -z defs' + if test "$GCC" = yes; then + wlarc='${wl}' + archive_cmds='$CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' + else + case `$CC -V 2>&1` in + *"Compilers 5.0"*) + wlarc='' + archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' + archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp' + ;; + *) + wlarc='${wl}' + archive_cmds='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' + ;; + esac + fi + hardcode_libdir_flag_spec='-R$libdir' + hardcode_shlibpath_var=no + case $host_os in + solaris2.[0-5] | solaris2.[0-5].*) ;; + *) + # The compiler driver will combine and reorder linker options, + # but understands `-z linker_flag'. GCC discards it without `$wl', + # but is careful enough not to reorder. + # Supported since Solaris 2.6 (maybe 2.5.1?) + if test "$GCC" = yes; then + whole_archive_flag_spec='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' + else + whole_archive_flag_spec='-z allextract$convenience -z defaultextract' + fi + ;; + esac + link_all_deplibs=yes + ;; + + sunos4*) + if test "x$host_vendor" = xsequent; then + # Use $CC to link under sequent, because it throws in some extra .o + # files that make .init and .fini sections work. + archive_cmds='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' + fi + hardcode_libdir_flag_spec='-L$libdir' + hardcode_direct=yes + hardcode_minus_L=yes + hardcode_shlibpath_var=no + ;; + + sysv4) + case $host_vendor in + sni) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=yes # is this really true??? + ;; + siemens) + ## LD is ld it makes a PLAMLIB + ## CC just makes a GrossModule. + archive_cmds='$LD -G -o $lib $libobjs $deplibs $linker_flags' + reload_cmds='$CC -r -o $output$reload_objs' + hardcode_direct=no + ;; + motorola) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=no #Motorola manual says yes, but my tests say they lie + ;; + esac + runpath_var='LD_RUN_PATH' + hardcode_shlibpath_var=no + ;; + + sysv4.3*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_shlibpath_var=no + export_dynamic_flag_spec='-Bexport' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_shlibpath_var=no + runpath_var=LD_RUN_PATH + hardcode_runpath_var=yes + ld_shlibs=yes + fi + ;; + + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*) + no_undefined_flag='${wl}-z,text' + archive_cmds_need_lc=no + hardcode_shlibpath_var=no + runpath_var='LD_RUN_PATH' + + if test "$GCC" = yes; then + archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + sysv5* | sco3.2v5* | sco5v6*) + # Note: We can NOT use -z defs as we might desire, because we do not + # link with -lc, and that would cause any symbols used from libc to + # always be unresolved, which means just about no library would + # ever link correctly. If we're not using GNU ld we use -z text + # though, which does catch some bad symbols but isn't as heavy-handed + # as -z defs. + no_undefined_flag='${wl}-z,text' + allow_undefined_flag='${wl}-z,nodefs' + archive_cmds_need_lc=no + hardcode_shlibpath_var=no + hardcode_libdir_flag_spec='${wl}-R,$libdir' + hardcode_libdir_separator=':' + link_all_deplibs=yes + export_dynamic_flag_spec='${wl}-Bexport' + runpath_var='LD_RUN_PATH' + + if test "$GCC" = yes; then + archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + uts4*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_shlibpath_var=no + ;; + + *) + ld_shlibs=no + ;; + esac + + if test x$host_vendor = xsni; then + case $host in + sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) + export_dynamic_flag_spec='${wl}-Blargedynsym' + ;; + esac + fi + fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs" >&5 +$as_echo "$ld_shlibs" >&6; } +test "$ld_shlibs" = no && can_build_shared=no + +with_gnu_ld=$with_gnu_ld + + + + + + + + + + + + + + + +# +# Do we need to explicitly link libc? +# +case "x$archive_cmds_need_lc" in +x|xyes) + # Assume -lc should be added + archive_cmds_need_lc=yes + + if test "$enable_shared" = yes && test "$GCC" = yes; then + case $archive_cmds in + *'~'*) + # FIXME: we may have to deal with multi-command sequences. + ;; + '$CC '*) + # Test whether the compiler implicitly links with -lc since on some + # systems, -lgcc has to come before -lc. If gcc already passes -lc + # to ld, don't add -lc before -lgcc. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5 +$as_echo_n "checking whether -lc should be explicitly linked in... " >&6; } +if ${lt_cv_archive_cmds_need_lc+:} false; then : + $as_echo_n "(cached) " >&6 +else + $RM conftest* + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } 2>conftest.err; then + soname=conftest + lib=conftest + libobjs=conftest.$ac_objext + deplibs= + wl=$lt_prog_compiler_wl + pic_flag=$lt_prog_compiler_pic + compiler_flags=-v + linker_flags=-v + verstring= + output_objdir=. + libname=conftest + lt_save_allow_undefined_flag=$allow_undefined_flag + allow_undefined_flag= + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5 + (eval $archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + then + lt_cv_archive_cmds_need_lc=no + else + lt_cv_archive_cmds_need_lc=yes + fi + allow_undefined_flag=$lt_save_allow_undefined_flag + else + cat conftest.err 1>&5 + fi + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_archive_cmds_need_lc" >&5 +$as_echo "$lt_cv_archive_cmds_need_lc" >&6; } + archive_cmds_need_lc=$lt_cv_archive_cmds_need_lc + ;; + esac + fi + ;; +esac + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5 +$as_echo_n "checking dynamic linker characteristics... " >&6; } + +if test "$GCC" = yes; then + case $host_os in + darwin*) lt_awk_arg="/^libraries:/,/LR/" ;; + *) lt_awk_arg="/^libraries:/" ;; + esac + case $host_os in + mingw* | cegcc*) lt_sed_strip_eq="s,=\([A-Za-z]:\),\1,g" ;; + *) lt_sed_strip_eq="s,=/,/,g" ;; + esac + lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq` + case $lt_search_path_spec in + *\;*) + # if the path contains ";" then we assume it to be the separator + # otherwise default to the standard path separator (i.e. ":") - it is + # assumed that no part of a normal pathname contains ";" but that should + # okay in the real world where ";" in dirpaths is itself problematic. + lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'` + ;; + *) + lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"` + ;; + esac + # Ok, now we have the path, separated by spaces, we can step through it + # and add multilib dir if necessary. + lt_tmp_lt_search_path_spec= + lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null` + for lt_sys_path in $lt_search_path_spec; do + if test -d "$lt_sys_path/$lt_multi_os_dir"; then + lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir" + else + test -d "$lt_sys_path" && \ + lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path" + fi + done + lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk ' +BEGIN {RS=" "; FS="/|\n";} { + lt_foo=""; + lt_count=0; + for (lt_i = NF; lt_i > 0; lt_i--) { + if ($lt_i != "" && $lt_i != ".") { + if ($lt_i == "..") { + lt_count++; + } else { + if (lt_count == 0) { + lt_foo="/" $lt_i lt_foo; + } else { + lt_count--; + } + } + } + } + if (lt_foo != "") { lt_freq[lt_foo]++; } + if (lt_freq[lt_foo] == 1) { print lt_foo; } +}'` + # AWK program above erroneously prepends '/' to C:/dos/paths + # for these hosts. + case $host_os in + mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\ + $SED 's,/\([A-Za-z]:\),\1,g'` ;; + esac + sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP` +else + sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" +fi +library_names_spec= +libname_spec='lib$name' +soname_spec= +shrext_cmds=".so" +postinstall_cmds= +postuninstall_cmds= +finish_cmds= +finish_eval= +shlibpath_var= +shlibpath_overrides_runpath=unknown +version_type=none +dynamic_linker="$host_os ld.so" +sys_lib_dlsearch_path_spec="/lib /usr/lib" +need_lib_prefix=unknown +hardcode_into_libs=no + +# when you set need_version to no, make sure it does not cause -set_version +# flags to be left without arguments +need_version=unknown + +case $host_os in +aix3*) + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' + shlibpath_var=LIBPATH + + # AIX 3 has no versioning support, so we append a major version to the name. + soname_spec='${libname}${release}${shared_ext}$major' + ;; + +aix[4-9]*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + hardcode_into_libs=yes + if test "$host_cpu" = ia64; then + # AIX 5 supports IA64 + library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + else + # With GCC up to 2.95.x, collect2 would create an import file + # for dependence libraries. The import file would start with + # the line `#! .'. This would cause the generated library to + # depend on `.', always an invalid library. This was fixed in + # development snapshots of GCC prior to 3.0. + case $host_os in + aix4 | aix4.[01] | aix4.[01].*) + if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' + echo ' yes ' + echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then + : + else + can_build_shared=no + fi + ;; + esac + # AIX (on Power*) has no versioning support, so currently we can not hardcode correct + # soname into executable. Probably we can add versioning support to + # collect2, so additional links can be useful in future. + if test "$aix_use_runtimelinking" = yes; then + # If using run time linking (on AIX 4.2 or later) use lib.so + # instead of lib.a to let people know that these are not + # typical AIX shared libraries. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + else + # We preserve .a as extension for shared libraries through AIX4.2 + # and later when we are not doing run time linking. + library_names_spec='${libname}${release}.a $libname.a' + soname_spec='${libname}${release}${shared_ext}$major' + fi + shlibpath_var=LIBPATH + fi + ;; + +amigaos*) + case $host_cpu in + powerpc) + # Since July 2007 AmigaOS4 officially supports .so libraries. + # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + ;; + m68k) + library_names_spec='$libname.ixlibrary $libname.a' + # Create ${libname}_ixlibrary.a entries in /sys/libs. + finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' + ;; + esac + ;; + +beos*) + library_names_spec='${libname}${shared_ext}' + dynamic_linker="$host_os ld.so" + shlibpath_var=LIBRARY_PATH + ;; + +bsdi[45]*) + version_type=linux # correct to gnu/linux during the next big refactor + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" + sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" + # the default ld.so.conf also contains /usr/contrib/lib and + # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow + # libtool to hard-code these into programs + ;; + +cygwin* | mingw* | pw32* | cegcc*) + version_type=windows + shrext_cmds=".dll" + need_version=no + need_lib_prefix=no + + case $GCC,$cc_basename in + yes,*) + # gcc + library_names_spec='$libname.dll.a' + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \${file}`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname~ + chmod a+x \$dldir/$dlname~ + if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then + eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; + fi' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $RM \$dlpath' + shlibpath_overrides_runpath=yes + + case $host_os in + cygwin*) + # Cygwin DLLs use 'cyg' prefix rather than 'lib' + soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + + sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api" + ;; + mingw* | cegcc*) + # MinGW DLLs use traditional 'lib' prefix + soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + ;; + pw32*) + # pw32 DLLs use 'pw' prefix rather than 'lib' + library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + ;; + esac + dynamic_linker='Win32 ld.exe' + ;; + + *,cl*) + # Native MSVC + libname_spec='$name' + soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + library_names_spec='${libname}.dll.lib' + + case $build_os in + mingw*) + sys_lib_search_path_spec= + lt_save_ifs=$IFS + IFS=';' + for lt_path in $LIB + do + IFS=$lt_save_ifs + # Let DOS variable expansion print the short 8.3 style file name. + lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"` + sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path" + done + IFS=$lt_save_ifs + # Convert to MSYS style. + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([a-zA-Z]\\):| /\\1|g' -e 's|^ ||'` + ;; + cygwin*) + # Convert to unix form, then to dos form, then back to unix form + # but this time dos style (no spaces!) so that the unix form looks + # like /cygdrive/c/PROGRA~1:/cygdr... + sys_lib_search_path_spec=`cygpath --path --unix "$LIB"` + sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null` + sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + ;; + *) + sys_lib_search_path_spec="$LIB" + if $ECHO "$sys_lib_search_path_spec" | $GREP ';[c-zC-Z]:/' >/dev/null; then + # It is most probably a Windows format PATH. + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` + else + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi + # FIXME: find the short name or the path components, as spaces are + # common. (e.g. "Program Files" -> "PROGRA~1") + ;; + esac + + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \${file}`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $RM \$dlpath' + shlibpath_overrides_runpath=yes + dynamic_linker='Win32 link.exe' + ;; + + *) + # Assume MSVC wrapper + library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib' + dynamic_linker='Win32 ld.exe' + ;; + esac + # FIXME: first we should search . and the directory the executable is in + shlibpath_var=PATH + ;; + +darwin* | rhapsody*) + dynamic_linker="$host_os dyld" + version_type=darwin + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext' + soname_spec='${libname}${release}${major}$shared_ext' + shlibpath_overrides_runpath=yes + shlibpath_var=DYLD_LIBRARY_PATH + shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' + + sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib" + sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' + ;; + +dgux*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +freebsd* | dragonfly*) + # DragonFly does not have aout. When/if they implement a new + # versioning mechanism, adjust this. + if test -x /usr/bin/objformat; then + objformat=`/usr/bin/objformat` + else + case $host_os in + freebsd[23].*) objformat=aout ;; + *) objformat=elf ;; + esac + fi + version_type=freebsd-$objformat + case $version_type in + freebsd-elf*) + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + need_version=no + need_lib_prefix=no + ;; + freebsd-*) + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' + need_version=yes + ;; + esac + shlibpath_var=LD_LIBRARY_PATH + case $host_os in + freebsd2.*) + shlibpath_overrides_runpath=yes + ;; + freebsd3.[01]* | freebsdelf3.[01]*) + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + freebsd3.[2-9]* | freebsdelf3.[2-9]* | \ + freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1) + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + *) # from 4.6 on, and DragonFly + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + esac + ;; + +haiku*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + dynamic_linker="$host_os runtime_loader" + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LIBRARY_PATH + shlibpath_overrides_runpath=yes + sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib' + hardcode_into_libs=yes + ;; + +hpux9* | hpux10* | hpux11*) + # Give a soname corresponding to the major version so that dld.sl refuses to + # link against other versions. + version_type=sunos + need_lib_prefix=no + need_version=no + case $host_cpu in + ia64*) + shrext_cmds='.so' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.so" + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + if test "X$HPUX_IA64_MODE" = X32; then + sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" + else + sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" + fi + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + hppa*64*) + shrext_cmds='.sl' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.sl" + shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + *) + shrext_cmds='.sl' + dynamic_linker="$host_os dld.sl" + shlibpath_var=SHLIB_PATH + shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + ;; + esac + # HP-UX runs *really* slowly unless shared libraries are mode 555, ... + postinstall_cmds='chmod 555 $lib' + # or fails outright, so override atomically: + install_override_mode=555 + ;; + +interix[3-9]*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +irix5* | irix6* | nonstopux*) + case $host_os in + nonstopux*) version_type=nonstopux ;; + *) + if test "$lt_cv_prog_gnu_ld" = yes; then + version_type=linux # correct to gnu/linux during the next big refactor + else + version_type=irix + fi ;; + esac + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' + case $host_os in + irix5* | nonstopux*) + libsuff= shlibsuff= + ;; + *) + case $LD in # libtool.m4 will add one of these switches to LD + *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") + libsuff= shlibsuff= libmagic=32-bit;; + *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") + libsuff=32 shlibsuff=N32 libmagic=N32;; + *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") + libsuff=64 shlibsuff=64 libmagic=64-bit;; + *) libsuff= shlibsuff= libmagic=never-match;; + esac + ;; + esac + shlibpath_var=LD_LIBRARY${shlibsuff}_PATH + shlibpath_overrides_runpath=no + sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" + sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" + hardcode_into_libs=yes + ;; + +# No shared lib support for Linux oldld, aout, or coff. +linux*oldld* | linux*aout* | linux*coff*) + dynamic_linker=no + ;; + +# This must be glibc/ELF. +linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + + # Some binutils ld are patched to set DT_RUNPATH + if ${lt_cv_shlibpath_overrides_runpath+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_shlibpath_overrides_runpath=no + save_LDFLAGS=$LDFLAGS + save_libdir=$libdir + eval "libdir=/foo; wl=\"$lt_prog_compiler_wl\"; \ + LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec\"" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + if ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null; then : + lt_cv_shlibpath_overrides_runpath=yes +fi +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LDFLAGS=$save_LDFLAGS + libdir=$save_libdir + +fi + + shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath + + # This implies no fast_install, which is unacceptable. + # Some rework will be needed to allow for fast_install + # before this can be enabled. + hardcode_into_libs=yes + + # Append ld.so.conf contents to the search path + if test -f /etc/ld.so.conf; then + lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '` + sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" + fi + + # We used to test for /lib/ld.so.1 and disable shared libraries on + # powerpc, because MkLinux only supported shared libraries with the + # GNU dynamic linker. Since this was broken with cross compilers, + # most powerpc-linux boxes support dynamic linking these days and + # people can always --disable-shared, the test was removed, and we + # assume the GNU/Linux dynamic linker is in use. + dynamic_linker='GNU/Linux ld.so' + ;; + +netbsdelf*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='NetBSD ld.elf_so' + ;; + +netbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + dynamic_linker='NetBSD (a.out) ld.so' + else + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='NetBSD ld.elf_so' + fi + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + +newsos6) + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +*nto* | *qnx*) + version_type=qnx + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='ldqnx.so' + ;; + +openbsd*) + version_type=sunos + sys_lib_dlsearch_path_spec="/usr/lib" + need_lib_prefix=no + # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. + case $host_os in + openbsd3.3 | openbsd3.3.*) need_version=yes ;; + *) need_version=no ;; + esac + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + shlibpath_var=LD_LIBRARY_PATH + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + case $host_os in + openbsd2.[89] | openbsd2.[89].*) + shlibpath_overrides_runpath=no + ;; + *) + shlibpath_overrides_runpath=yes + ;; + esac + else + shlibpath_overrides_runpath=yes + fi + ;; + +os2*) + libname_spec='$name' + shrext_cmds=".dll" + need_lib_prefix=no + library_names_spec='$libname${shared_ext} $libname.a' + dynamic_linker='OS/2 ld.exe' + shlibpath_var=LIBPATH + ;; + +osf3* | osf4* | osf5*) + version_type=osf + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" + sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" + ;; + +rdos*) + dynamic_linker=no + ;; + +solaris*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + # ldd complains unless libraries are executable + postinstall_cmds='chmod +x $lib' + ;; + +sunos4*) + version_type=sunos + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + if test "$with_gnu_ld" = yes; then + need_lib_prefix=no + fi + need_version=yes + ;; + +sysv4 | sysv4.3*) + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + case $host_vendor in + sni) + shlibpath_overrides_runpath=no + need_lib_prefix=no + runpath_var=LD_RUN_PATH + ;; + siemens) + need_lib_prefix=no + ;; + motorola) + need_lib_prefix=no + need_version=no + shlibpath_overrides_runpath=no + sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' + ;; + esac + ;; + +sysv4*MP*) + if test -d /usr/nec ;then + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' + soname_spec='$libname${shared_ext}.$major' + shlibpath_var=LD_LIBRARY_PATH + fi + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + version_type=freebsd-elf + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + if test "$with_gnu_ld" = yes; then + sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' + else + sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' + case $host_os in + sco3.2v5*) + sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" + ;; + esac + fi + sys_lib_dlsearch_path_spec='/usr/lib' + ;; + +tpf*) + # TPF is a cross-target only. Preferred cross-host = GNU/Linux. + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +uts4*) + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +*) + dynamic_linker=no + ;; +esac +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5 +$as_echo "$dynamic_linker" >&6; } +test "$dynamic_linker" = no && can_build_shared=no + +variables_saved_for_relink="PATH $shlibpath_var $runpath_var" +if test "$GCC" = yes; then + variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" +fi + +if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then + sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec" +fi +if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then + sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec" +fi + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5 +$as_echo_n "checking how to hardcode library paths into programs... " >&6; } +hardcode_action= +if test -n "$hardcode_libdir_flag_spec" || + test -n "$runpath_var" || + test "X$hardcode_automatic" = "Xyes" ; then + + # We can hardcode non-existent directories. + if test "$hardcode_direct" != no && + # If the only mechanism to avoid hardcoding is shlibpath_var, we + # have to relink, otherwise we might link with an installed library + # when we should be linking with a yet-to-be-installed one + ## test "$_LT_TAGVAR(hardcode_shlibpath_var, )" != no && + test "$hardcode_minus_L" != no; then + # Linking always hardcodes the temporary library directory. + hardcode_action=relink + else + # We can link without hardcoding, and we can hardcode nonexisting dirs. + hardcode_action=immediate + fi +else + # We cannot hardcode anything, or else we can only hardcode existing + # directories. + hardcode_action=unsupported +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action" >&5 +$as_echo "$hardcode_action" >&6; } + +if test "$hardcode_action" = relink || + test "$inherit_rpath" = yes; then + # Fast installation is not supported + enable_fast_install=no +elif test "$shlibpath_overrides_runpath" = yes || + test "$enable_shared" = no; then + # Fast installation is not necessary + enable_fast_install=needless +fi + + + + + + + if test "x$enable_dlopen" != xyes; then + enable_dlopen=unknown + enable_dlopen_self=unknown + enable_dlopen_self_static=unknown +else + lt_cv_dlopen=no + lt_cv_dlopen_libs= + + case $host_os in + beos*) + lt_cv_dlopen="load_add_on" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + ;; + + mingw* | pw32* | cegcc*) + lt_cv_dlopen="LoadLibrary" + lt_cv_dlopen_libs= + ;; + + cygwin*) + lt_cv_dlopen="dlopen" + lt_cv_dlopen_libs= + ;; + + darwin*) + # if libdl is installed we need to link against it + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 +$as_echo_n "checking for dlopen in -ldl... " >&6; } +if ${ac_cv_lib_dl_dlopen+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldl $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dlopen (); +int +main () +{ +return dlopen (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_dl_dlopen=yes +else + ac_cv_lib_dl_dlopen=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 +$as_echo "$ac_cv_lib_dl_dlopen" >&6; } +if test "x$ac_cv_lib_dl_dlopen" = xyes; then : + lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" +else + + lt_cv_dlopen="dyld" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + +fi + + ;; + + *) + ac_fn_c_check_func "$LINENO" "shl_load" "ac_cv_func_shl_load" +if test "x$ac_cv_func_shl_load" = xyes; then : + lt_cv_dlopen="shl_load" +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5 +$as_echo_n "checking for shl_load in -ldld... " >&6; } +if ${ac_cv_lib_dld_shl_load+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldld $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char shl_load (); +int +main () +{ +return shl_load (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_dld_shl_load=yes +else + ac_cv_lib_dld_shl_load=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5 +$as_echo "$ac_cv_lib_dld_shl_load" >&6; } +if test "x$ac_cv_lib_dld_shl_load" = xyes; then : + lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld" +else + ac_fn_c_check_func "$LINENO" "dlopen" "ac_cv_func_dlopen" +if test "x$ac_cv_func_dlopen" = xyes; then : + lt_cv_dlopen="dlopen" +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 +$as_echo_n "checking for dlopen in -ldl... " >&6; } +if ${ac_cv_lib_dl_dlopen+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldl $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dlopen (); +int +main () +{ +return dlopen (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_dl_dlopen=yes +else + ac_cv_lib_dl_dlopen=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 +$as_echo "$ac_cv_lib_dl_dlopen" >&6; } +if test "x$ac_cv_lib_dl_dlopen" = xyes; then : + lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -lsvld" >&5 +$as_echo_n "checking for dlopen in -lsvld... " >&6; } +if ${ac_cv_lib_svld_dlopen+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lsvld $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dlopen (); +int +main () +{ +return dlopen (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_svld_dlopen=yes +else + ac_cv_lib_svld_dlopen=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_svld_dlopen" >&5 +$as_echo "$ac_cv_lib_svld_dlopen" >&6; } +if test "x$ac_cv_lib_svld_dlopen" = xyes; then : + lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld" +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dld_link in -ldld" >&5 +$as_echo_n "checking for dld_link in -ldld... " >&6; } +if ${ac_cv_lib_dld_dld_link+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldld $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dld_link (); +int +main () +{ +return dld_link (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_dld_dld_link=yes +else + ac_cv_lib_dld_dld_link=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_dld_link" >&5 +$as_echo "$ac_cv_lib_dld_dld_link" >&6; } +if test "x$ac_cv_lib_dld_dld_link" = xyes; then : + lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld" +fi + + +fi + + +fi + + +fi + + +fi + + +fi + + ;; + esac + + if test "x$lt_cv_dlopen" != xno; then + enable_dlopen=yes + else + enable_dlopen=no + fi + + case $lt_cv_dlopen in + dlopen) + save_CPPFLAGS="$CPPFLAGS" + test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" + + save_LDFLAGS="$LDFLAGS" + wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" + + save_LIBS="$LIBS" + LIBS="$lt_cv_dlopen_libs $LIBS" + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a program can dlopen itself" >&5 +$as_echo_n "checking whether a program can dlopen itself... " >&6; } +if ${lt_cv_dlopen_self+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test "$cross_compiling" = yes; then : + lt_cv_dlopen_self=cross +else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<_LT_EOF +#line $LINENO "configure" +#include "confdefs.h" + +#if HAVE_DLFCN_H +#include +#endif + +#include + +#ifdef RTLD_GLOBAL +# define LT_DLGLOBAL RTLD_GLOBAL +#else +# ifdef DL_GLOBAL +# define LT_DLGLOBAL DL_GLOBAL +# else +# define LT_DLGLOBAL 0 +# endif +#endif + +/* We may have to define LT_DLLAZY_OR_NOW in the command line if we + find out it does not work in some platform. */ +#ifndef LT_DLLAZY_OR_NOW +# ifdef RTLD_LAZY +# define LT_DLLAZY_OR_NOW RTLD_LAZY +# else +# ifdef DL_LAZY +# define LT_DLLAZY_OR_NOW DL_LAZY +# else +# ifdef RTLD_NOW +# define LT_DLLAZY_OR_NOW RTLD_NOW +# else +# ifdef DL_NOW +# define LT_DLLAZY_OR_NOW DL_NOW +# else +# define LT_DLLAZY_OR_NOW 0 +# endif +# endif +# endif +# endif +#endif + +/* When -fvisbility=hidden is used, assume the code has been annotated + correspondingly for the symbols needed. */ +#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) +int fnord () __attribute__((visibility("default"))); +#endif + +int fnord () { return 42; } +int main () +{ + void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); + int status = $lt_dlunknown; + + if (self) + { + if (dlsym (self,"fnord")) status = $lt_dlno_uscore; + else + { + if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; + else puts (dlerror ()); + } + /* dlclose (self); */ + } + else + puts (dlerror ()); + + return status; +} +_LT_EOF + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 + (eval $ac_link) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then + (./conftest; exit; ) >&5 2>/dev/null + lt_status=$? + case x$lt_status in + x$lt_dlno_uscore) lt_cv_dlopen_self=yes ;; + x$lt_dlneed_uscore) lt_cv_dlopen_self=yes ;; + x$lt_dlunknown|x*) lt_cv_dlopen_self=no ;; + esac + else : + # compilation failed + lt_cv_dlopen_self=no + fi +fi +rm -fr conftest* + + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self" >&5 +$as_echo "$lt_cv_dlopen_self" >&6; } + + if test "x$lt_cv_dlopen_self" = xyes; then + wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a statically linked program can dlopen itself" >&5 +$as_echo_n "checking whether a statically linked program can dlopen itself... " >&6; } +if ${lt_cv_dlopen_self_static+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test "$cross_compiling" = yes; then : + lt_cv_dlopen_self_static=cross +else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<_LT_EOF +#line $LINENO "configure" +#include "confdefs.h" + +#if HAVE_DLFCN_H +#include +#endif + +#include + +#ifdef RTLD_GLOBAL +# define LT_DLGLOBAL RTLD_GLOBAL +#else +# ifdef DL_GLOBAL +# define LT_DLGLOBAL DL_GLOBAL +# else +# define LT_DLGLOBAL 0 +# endif +#endif + +/* We may have to define LT_DLLAZY_OR_NOW in the command line if we + find out it does not work in some platform. */ +#ifndef LT_DLLAZY_OR_NOW +# ifdef RTLD_LAZY +# define LT_DLLAZY_OR_NOW RTLD_LAZY +# else +# ifdef DL_LAZY +# define LT_DLLAZY_OR_NOW DL_LAZY +# else +# ifdef RTLD_NOW +# define LT_DLLAZY_OR_NOW RTLD_NOW +# else +# ifdef DL_NOW +# define LT_DLLAZY_OR_NOW DL_NOW +# else +# define LT_DLLAZY_OR_NOW 0 +# endif +# endif +# endif +# endif +#endif + +/* When -fvisbility=hidden is used, assume the code has been annotated + correspondingly for the symbols needed. */ +#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) +int fnord () __attribute__((visibility("default"))); +#endif + +int fnord () { return 42; } +int main () +{ + void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); + int status = $lt_dlunknown; + + if (self) + { + if (dlsym (self,"fnord")) status = $lt_dlno_uscore; + else + { + if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; + else puts (dlerror ()); + } + /* dlclose (self); */ + } + else + puts (dlerror ()); + + return status; +} +_LT_EOF + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 + (eval $ac_link) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then + (./conftest; exit; ) >&5 2>/dev/null + lt_status=$? + case x$lt_status in + x$lt_dlno_uscore) lt_cv_dlopen_self_static=yes ;; + x$lt_dlneed_uscore) lt_cv_dlopen_self_static=yes ;; + x$lt_dlunknown|x*) lt_cv_dlopen_self_static=no ;; + esac + else : + # compilation failed + lt_cv_dlopen_self_static=no + fi +fi +rm -fr conftest* + + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self_static" >&5 +$as_echo "$lt_cv_dlopen_self_static" >&6; } + fi + + CPPFLAGS="$save_CPPFLAGS" + LDFLAGS="$save_LDFLAGS" + LIBS="$save_LIBS" + ;; + esac + + case $lt_cv_dlopen_self in + yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; + *) enable_dlopen_self=unknown ;; + esac + + case $lt_cv_dlopen_self_static in + yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; + *) enable_dlopen_self_static=unknown ;; + esac +fi + + + + + + + + + + + + + + + + + +striplib= +old_striplib= +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether stripping libraries is possible" >&5 +$as_echo_n "checking whether stripping libraries is possible... " >&6; } +if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then + test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" + test -z "$striplib" && striplib="$STRIP --strip-unneeded" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +else +# FIXME - insert some real tests, host_os isn't really good enough + case $host_os in + darwin*) + if test -n "$STRIP" ; then + striplib="$STRIP -x" + old_striplib="$STRIP -S" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + fi + ;; + *) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + ;; + esac +fi + + + + + + + + + + + + + # Report which library types will actually be built + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if libtool supports shared libraries" >&5 +$as_echo_n "checking if libtool supports shared libraries... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $can_build_shared" >&5 +$as_echo "$can_build_shared" >&6; } + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build shared libraries" >&5 +$as_echo_n "checking whether to build shared libraries... " >&6; } + test "$can_build_shared" = "no" && enable_shared=no + + # On AIX, shared libraries and static libraries use the same namespace, and + # are all built from PIC. + case $host_os in + aix3*) + test "$enable_shared" = yes && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + + aix[4-9]*) + if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then + test "$enable_shared" = yes && enable_static=no + fi + ;; + esac + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_shared" >&5 +$as_echo "$enable_shared" >&6; } + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build static libraries" >&5 +$as_echo_n "checking whether to build static libraries... " >&6; } + # Make sure either enable_shared or enable_static is yes. + test "$enable_shared" = yes || enable_static=yes + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_static" >&5 +$as_echo "$enable_static" >&6; } + + + + +fi +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +CC="$lt_save_CC" + + if test -n "$CXX" && ( test "X$CXX" != "Xno" && + ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) || + (test "X$CXX" != "Xg++"))) ; then + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C++ preprocessor" >&5 +$as_echo_n "checking how to run the C++ preprocessor... " >&6; } +if test -z "$CXXCPP"; then + if ${ac_cv_prog_CXXCPP+:} false; then : + $as_echo_n "(cached) " >&6 +else + # Double quotes because CXXCPP needs to be expanded + for CXXCPP in "$CXX -E" "/lib/cpp" + do + ac_preproc_ok=false +for ac_cxx_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if ac_fn_cxx_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.i conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +_ACEOF +if ac_fn_cxx_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.i conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + break +fi + + done + ac_cv_prog_CXXCPP=$CXXCPP + +fi + CXXCPP=$ac_cv_prog_CXXCPP +else + ac_cv_prog_CXXCPP=$CXXCPP +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXXCPP" >&5 +$as_echo "$CXXCPP" >&6; } +ac_preproc_ok=false +for ac_cxx_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if ac_fn_cxx_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.i conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +_ACEOF +if ac_fn_cxx_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.i conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "C++ preprocessor \"$CXXCPP\" fails sanity check +See \`config.log' for more details" "$LINENO" 5; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +else + _lt_caught_CXX_error=yes +fi + +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + +archive_cmds_need_lc_CXX=no +allow_undefined_flag_CXX= +always_export_symbols_CXX=no +archive_expsym_cmds_CXX= +compiler_needs_object_CXX=no +export_dynamic_flag_spec_CXX= +hardcode_direct_CXX=no +hardcode_direct_absolute_CXX=no +hardcode_libdir_flag_spec_CXX= +hardcode_libdir_separator_CXX= +hardcode_minus_L_CXX=no +hardcode_shlibpath_var_CXX=unsupported +hardcode_automatic_CXX=no +inherit_rpath_CXX=no +module_cmds_CXX= +module_expsym_cmds_CXX= +link_all_deplibs_CXX=unknown +old_archive_cmds_CXX=$old_archive_cmds +reload_flag_CXX=$reload_flag +reload_cmds_CXX=$reload_cmds +no_undefined_flag_CXX= +whole_archive_flag_spec_CXX= +enable_shared_with_static_runtimes_CXX=no + +# Source file extension for C++ test sources. +ac_ext=cpp + +# Object file extension for compiled C++ test sources. +objext=o +objext_CXX=$objext + +# No sense in running all these tests if we already determined that +# the CXX compiler isn't working. Some variables (like enable_shared) +# are currently assumed to apply to all compilers on this platform, +# and will be corrupted by setting them based on a non-working compiler. +if test "$_lt_caught_CXX_error" != yes; then + # Code to be used in simple compile tests + lt_simple_compile_test_code="int some_variable = 0;" + + # Code to be used in simple link tests + lt_simple_link_test_code='int main(int, char *[]) { return(0); }' + + # ltmain only uses $CC for tagged configurations so make sure $CC is set. + + + + + + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# If no C compiler flags were specified, use CFLAGS. +LTCFLAGS=${LTCFLAGS-"$CFLAGS"} + +# Allow CC to be a program name with arguments. +compiler=$CC + + + # save warnings/boilerplate of simple test code + ac_outfile=conftest.$ac_objext +echo "$lt_simple_compile_test_code" >conftest.$ac_ext +eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_compiler_boilerplate=`cat conftest.err` +$RM conftest* + + ac_outfile=conftest.$ac_objext +echo "$lt_simple_link_test_code" >conftest.$ac_ext +eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_linker_boilerplate=`cat conftest.err` +$RM -r conftest* + + + # Allow CC to be a program name with arguments. + lt_save_CC=$CC + lt_save_CFLAGS=$CFLAGS + lt_save_LD=$LD + lt_save_GCC=$GCC + GCC=$GXX + lt_save_with_gnu_ld=$with_gnu_ld + lt_save_path_LD=$lt_cv_path_LD + if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then + lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx + else + $as_unset lt_cv_prog_gnu_ld + fi + if test -n "${lt_cv_path_LDCXX+set}"; then + lt_cv_path_LD=$lt_cv_path_LDCXX + else + $as_unset lt_cv_path_LD + fi + test -z "${LDCXX+set}" || LD=$LDCXX + CC=${CXX-"c++"} + CFLAGS=$CXXFLAGS + compiler=$CC + compiler_CXX=$CC + for cc_temp in $compiler""; do + case $cc_temp in + compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; + distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; + \-*) ;; + *) break;; + esac +done +cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` + + + if test -n "$compiler"; then + # We don't want -fno-exception when compiling C++ code, so set the + # no_builtin_flag separately + if test "$GXX" = yes; then + lt_prog_compiler_no_builtin_flag_CXX=' -fno-builtin' + else + lt_prog_compiler_no_builtin_flag_CXX= + fi + + if test "$GXX" = yes; then + # Set up default GNU C++ configuration + + + +# Check whether --with-gnu-ld was given. +if test "${with_gnu_ld+set}" = set; then : + withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes +else + with_gnu_ld=no +fi + +ac_prog=ld +if test "$GCC" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5 +$as_echo_n "checking for ld used by $CC... " >&6; } + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case $ac_prog in + # Accept absolute paths. + [\\/]* | ?:[\\/]*) + re_direlt='/[^/][^/]*/\.\./' + # Canonicalize the pathname of ld + ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` + while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do + ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` + done + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5 +$as_echo_n "checking for GNU ld... " >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5 +$as_echo_n "checking for non-GNU ld... " >&6; } +fi +if ${lt_cv_path_LD+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$LD"; then + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + lt_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some variants of GNU ld only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + case `"$lt_cv_path_LD" -v 2>&1 &5 +$as_echo "$LD" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5 +$as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; } +if ${lt_cv_prog_gnu_ld+:} false; then : + $as_echo_n "(cached) " >&6 +else + # I'd rather use --version here, but apparently some GNU lds only accept -v. +case `$LD -v 2>&1 &5 +$as_echo "$lt_cv_prog_gnu_ld" >&6; } +with_gnu_ld=$lt_cv_prog_gnu_ld + + + + + + + + # Check if GNU C++ uses GNU ld as the underlying linker, since the + # archiving commands below assume that GNU ld is being used. + if test "$with_gnu_ld" = yes; then + archive_cmds_CXX='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds_CXX='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + + hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' + export_dynamic_flag_spec_CXX='${wl}--export-dynamic' + + # If archive_cmds runs LD, not CC, wlarc should be empty + # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to + # investigate it a little bit more. (MM) + wlarc='${wl}' + + # ancient GNU ld didn't support --whole-archive et. al. + if eval "`$CC -print-prog-name=ld` --help 2>&1" | + $GREP 'no-whole-archive' > /dev/null; then + whole_archive_flag_spec_CXX="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + whole_archive_flag_spec_CXX= + fi + else + with_gnu_ld=no + wlarc= + + # A generic and very simple default shared library creation + # command for GNU C++ for the case where it uses the native + # linker, instead of GNU ld. If possible, this setting should + # overridden to take advantage of the native linker features on + # the platform it is being used on. + archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' + fi + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' + + else + GXX=no + with_gnu_ld=no + wlarc= + fi + + # PORTME: fill in a description of your system's C++ link characteristics + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5 +$as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; } + ld_shlibs_CXX=yes + case $host_os in + aix3*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + aix[4-9]*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*) + for ld_flag in $LDFLAGS; do + case $ld_flag in + *-brtl*) + aix_use_runtimelinking=yes + break + ;; + esac + done + ;; + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + archive_cmds_CXX='' + hardcode_direct_CXX=yes + hardcode_direct_absolute_CXX=yes + hardcode_libdir_separator_CXX=':' + link_all_deplibs_CXX=yes + file_list_spec_CXX='${wl}-f,' + + if test "$GXX" = yes; then + case $host_os in aix4.[012]|aix4.[012].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && + strings "$collect2name" | $GREP resolve_lib_name >/dev/null + then + # We have reworked collect2 + : + else + # We have old collect2 + hardcode_direct_CXX=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + hardcode_minus_L_CXX=yes + hardcode_libdir_flag_spec_CXX='-L$libdir' + hardcode_libdir_separator_CXX= + fi + esac + shared_flag='-shared' + if test "$aix_use_runtimelinking" = yes; then + shared_flag="$shared_flag "'${wl}-G' + fi + else + # not using gcc + if test "$host_cpu" = ia64; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='${wl}-G' + else + shared_flag='${wl}-bM:SRE' + fi + fi + fi + + export_dynamic_flag_spec_CXX='${wl}-bexpall' + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to + # export. + always_export_symbols_CXX=yes + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + allow_undefined_flag_CXX='-berok' + # Determine the default libpath from the value encoded in an empty + # executable. + if test "${lt_cv_aix_libpath+set}" = set; then + aix_libpath=$lt_cv_aix_libpath +else + if ${lt_cv_aix_libpath__CXX+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + + lt_aix_libpath_sed=' + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\([^ ]*\) *$/\1/ + p + } + }' + lt_cv_aix_libpath__CXX=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` + # Check for a 64-bit object if we didn't find anything. + if test -z "$lt_cv_aix_libpath__CXX"; then + lt_cv_aix_libpath__CXX=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` + fi +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + if test -z "$lt_cv_aix_libpath__CXX"; then + lt_cv_aix_libpath__CXX="/usr/lib:/lib" + fi + +fi + + aix_libpath=$lt_cv_aix_libpath__CXX +fi + + hardcode_libdir_flag_spec_CXX='${wl}-blibpath:$libdir:'"$aix_libpath" + + archive_expsym_cmds_CXX='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + hardcode_libdir_flag_spec_CXX='${wl}-R $libdir:/usr/lib:/lib' + allow_undefined_flag_CXX="-z nodefs" + archive_expsym_cmds_CXX="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an + # empty executable. + if test "${lt_cv_aix_libpath+set}" = set; then + aix_libpath=$lt_cv_aix_libpath +else + if ${lt_cv_aix_libpath__CXX+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + + lt_aix_libpath_sed=' + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\([^ ]*\) *$/\1/ + p + } + }' + lt_cv_aix_libpath__CXX=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` + # Check for a 64-bit object if we didn't find anything. + if test -z "$lt_cv_aix_libpath__CXX"; then + lt_cv_aix_libpath__CXX=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` + fi +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + if test -z "$lt_cv_aix_libpath__CXX"; then + lt_cv_aix_libpath__CXX="/usr/lib:/lib" + fi + +fi + + aix_libpath=$lt_cv_aix_libpath__CXX +fi + + hardcode_libdir_flag_spec_CXX='${wl}-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + no_undefined_flag_CXX=' ${wl}-bernotok' + allow_undefined_flag_CXX=' ${wl}-berok' + if test "$with_gnu_ld" = yes; then + # We only use this code for GNU lds that support --whole-archive. + whole_archive_flag_spec_CXX='${wl}--whole-archive$convenience ${wl}--no-whole-archive' + else + # Exported symbols can be pulled into shared objects from archives + whole_archive_flag_spec_CXX='$convenience' + fi + archive_cmds_need_lc_CXX=yes + # This is similar to how AIX traditionally builds its shared + # libraries. + archive_expsym_cmds_CXX="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + fi + fi + ;; + + beos*) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + allow_undefined_flag_CXX=unsupported + # Joseph Beckenbach says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + archive_cmds_CXX='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + else + ld_shlibs_CXX=no + fi + ;; + + chorus*) + case $cc_basename in + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + esac + ;; + + cygwin* | mingw* | pw32* | cegcc*) + case $GXX,$cc_basename in + ,cl* | no,cl*) + # Native MSVC + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + hardcode_libdir_flag_spec_CXX=' ' + allow_undefined_flag_CXX=unsupported + always_export_symbols_CXX=yes + file_list_spec_CXX='@' + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=".dll" + # FIXME: Setting linknames here is a bad hack. + archive_cmds_CXX='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames=' + archive_expsym_cmds_CXX='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + $SED -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp; + else + $SED -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp; + fi~ + $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ + linknames=' + # The linker will not automatically build a static lib if we build a DLL. + # _LT_TAGVAR(old_archive_from_new_cmds, CXX)='true' + enable_shared_with_static_runtimes_CXX=yes + # Don't use ranlib + old_postinstall_cmds_CXX='chmod 644 $oldlib' + postlink_cmds_CXX='lt_outputfile="@OUTPUT@"~ + lt_tool_outputfile="@TOOL_OUTPUT@"~ + case $lt_outputfile in + *.exe|*.EXE) ;; + *) + lt_outputfile="$lt_outputfile.exe" + lt_tool_outputfile="$lt_tool_outputfile.exe" + ;; + esac~ + func_to_tool_file "$lt_outputfile"~ + if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then + $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; + $RM "$lt_outputfile.manifest"; + fi' + ;; + *) + # g++ + # _LT_TAGVAR(hardcode_libdir_flag_spec, CXX) is actually meaningless, + # as there is no search path for DLLs. + hardcode_libdir_flag_spec_CXX='-L$libdir' + export_dynamic_flag_spec_CXX='${wl}--export-all-symbols' + allow_undefined_flag_CXX=unsupported + always_export_symbols_CXX=no + enable_shared_with_static_runtimes_CXX=yes + + if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then + archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is; otherwise, prepend... + archive_expsym_cmds_CXX='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + else + ld_shlibs_CXX=no + fi + ;; + esac + ;; + darwin* | rhapsody*) + + + archive_cmds_need_lc_CXX=no + hardcode_direct_CXX=no + hardcode_automatic_CXX=yes + hardcode_shlibpath_var_CXX=unsupported + if test "$lt_cv_ld_force_load" = "yes"; then + whole_archive_flag_spec_CXX='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`' + + else + whole_archive_flag_spec_CXX='' + fi + link_all_deplibs_CXX=yes + allow_undefined_flag_CXX="$_lt_dar_allow_undefined" + case $cc_basename in + ifort*) _lt_dar_can_shared=yes ;; + *) _lt_dar_can_shared=$GCC ;; + esac + if test "$_lt_dar_can_shared" = "yes"; then + output_verbose_link_cmd=func_echo_all + archive_cmds_CXX="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" + module_cmds_CXX="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" + archive_expsym_cmds_CXX="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" + module_expsym_cmds_CXX="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" + if test "$lt_cv_apple_cc_single_mod" != "yes"; then + archive_cmds_CXX="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}" + archive_expsym_cmds_CXX="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dar_export_syms}${_lt_dsymutil}" + fi + + else + ld_shlibs_CXX=no + fi + + ;; + + dgux*) + case $cc_basename in + ec++*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + ghcx*) + # Green Hills C++ Compiler + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + esac + ;; + + freebsd2.*) + # C++ shared libraries reported to be fairly broken before + # switch to ELF + ld_shlibs_CXX=no + ;; + + freebsd-elf*) + archive_cmds_need_lc_CXX=no + ;; + + freebsd* | dragonfly*) + # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF + # conventions + ld_shlibs_CXX=yes + ;; + + haiku*) + archive_cmds_CXX='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + link_all_deplibs_CXX=yes + ;; + + hpux9*) + hardcode_libdir_flag_spec_CXX='${wl}+b ${wl}$libdir' + hardcode_libdir_separator_CXX=: + export_dynamic_flag_spec_CXX='${wl}-E' + hardcode_direct_CXX=yes + hardcode_minus_L_CXX=yes # Not in the search PATH, + # but as the default + # location of the library. + + case $cc_basename in + CC*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + aCC*) + archive_cmds_CXX='$RM $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' + ;; + *) + if test "$GXX" = yes; then + archive_cmds_CXX='$RM $output_objdir/$soname~$CC -shared -nostdlib $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + else + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + fi + ;; + esac + ;; + + hpux10*|hpux11*) + if test $with_gnu_ld = no; then + hardcode_libdir_flag_spec_CXX='${wl}+b ${wl}$libdir' + hardcode_libdir_separator_CXX=: + + case $host_cpu in + hppa*64*|ia64*) + ;; + *) + export_dynamic_flag_spec_CXX='${wl}-E' + ;; + esac + fi + case $host_cpu in + hppa*64*|ia64*) + hardcode_direct_CXX=no + hardcode_shlibpath_var_CXX=no + ;; + *) + hardcode_direct_CXX=yes + hardcode_direct_absolute_CXX=yes + hardcode_minus_L_CXX=yes # Not in the search PATH, + # but as the default + # location of the library. + ;; + esac + + case $cc_basename in + CC*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + aCC*) + case $host_cpu in + hppa*64*) + archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + ia64*) + archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + *) + archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + esac + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' + ;; + *) + if test "$GXX" = yes; then + if test $with_gnu_ld = no; then + case $host_cpu in + hppa*64*) + archive_cmds_CXX='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + ia64*) + archive_cmds_CXX='$CC -shared -nostdlib $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + *) + archive_cmds_CXX='$CC -shared -nostdlib $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + esac + fi + else + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + fi + ;; + esac + ;; + + interix[3-9]*) + hardcode_direct_CXX=no + hardcode_shlibpath_var_CXX=no + hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' + export_dynamic_flag_spec_CXX='${wl}-E' + # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. + # Instead, shared libraries are loaded at an image base (0x10000000 by + # default) and relocated if they conflict, which is a slow very memory + # consuming and fragmenting process. To avoid this, we pick a random, + # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link + # time. Moving up from 0x10000000 also allows more sbrk(2) space. + archive_cmds_CXX='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + archive_expsym_cmds_CXX='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + ;; + irix5* | irix6*) + case $cc_basename in + CC*) + # SGI C++ + archive_cmds_CXX='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' + + # Archives containing C++ object files must be created using + # "CC -ar", where "CC" is the IRIX C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + old_archive_cmds_CXX='$CC -ar -WR,-u -o $oldlib $oldobjs' + ;; + *) + if test "$GXX" = yes; then + if test "$with_gnu_ld" = no; then + archive_cmds_CXX='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + archive_cmds_CXX='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` -o $lib' + fi + fi + link_all_deplibs_CXX=yes + ;; + esac + hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator_CXX=: + inherit_rpath_CXX=yes + ;; + + linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) + case $cc_basename in + KCC*) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + archive_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + archive_expsym_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib' + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' + + hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' + export_dynamic_flag_spec_CXX='${wl}--export-dynamic' + + # Archives containing C++ object files must be created using + # "CC -Bstatic", where "CC" is the KAI C++ compiler. + old_archive_cmds_CXX='$CC -Bstatic -o $oldlib $oldobjs' + ;; + icpc* | ecpc* ) + # Intel C++ + with_gnu_ld=yes + # version 8.0 and above of icpc choke on multiply defined symbols + # if we add $predep_objects and $postdep_objects, however 7.1 and + # earlier do not add the objects themselves. + case `$CC -V 2>&1` in + *"Version 7."*) + archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + ;; + *) # Version 8.0 or newer + tmp_idyn= + case $host_cpu in + ia64*) tmp_idyn=' -i_dynamic';; + esac + archive_cmds_CXX='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds_CXX='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + ;; + esac + archive_cmds_need_lc_CXX=no + hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' + export_dynamic_flag_spec_CXX='${wl}--export-dynamic' + whole_archive_flag_spec_CXX='${wl}--whole-archive$convenience ${wl}--no-whole-archive' + ;; + pgCC* | pgcpp*) + # Portland Group C++ compiler + case `$CC -V` in + *pgCC\ [1-5].* | *pgcpp\ [1-5].*) + prelink_cmds_CXX='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~ + compile_command="$compile_command `find $tpldir -name \*.o | sort | $NL2SP`"' + old_archive_cmds_CXX='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~ + $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | sort | $NL2SP`~ + $RANLIB $oldlib' + archive_cmds_CXX='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ + $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' + archive_expsym_cmds_CXX='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ + $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' + ;; + *) # Version 6 and above use weak symbols + archive_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' + archive_expsym_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' + ;; + esac + + hardcode_libdir_flag_spec_CXX='${wl}--rpath ${wl}$libdir' + export_dynamic_flag_spec_CXX='${wl}--export-dynamic' + whole_archive_flag_spec_CXX='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + ;; + cxx*) + # Compaq C++ + archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib ${wl}-retain-symbols-file $wl$export_symbols' + + runpath_var=LD_RUN_PATH + hardcode_libdir_flag_spec_CXX='-rpath $libdir' + hardcode_libdir_separator_CXX=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "X$list" | $Xsed' + ;; + xl* | mpixl* | bgxl*) + # IBM XL 8.0 on PPC, with GNU ld + hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' + export_dynamic_flag_spec_CXX='${wl}--export-dynamic' + archive_cmds_CXX='$CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + if test "x$supports_anon_versioning" = xyes; then + archive_expsym_cmds_CXX='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' + fi + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C++ 5.9 + no_undefined_flag_CXX=' -zdefs' + archive_cmds_CXX='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + archive_expsym_cmds_CXX='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file ${wl}$export_symbols' + hardcode_libdir_flag_spec_CXX='-R$libdir' + whole_archive_flag_spec_CXX='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + compiler_needs_object_CXX=yes + + # Not sure whether something based on + # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 + # would be better. + output_verbose_link_cmd='func_echo_all' + + # Archives containing C++ object files must be created using + # "CC -xar", where "CC" is the Sun C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + old_archive_cmds_CXX='$CC -xar -o $oldlib $oldobjs' + ;; + esac + ;; + esac + ;; + + lynxos*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + + m88k*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + + mvs*) + case $cc_basename in + cxx*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + esac + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + archive_cmds_CXX='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags' + wlarc= + hardcode_libdir_flag_spec_CXX='-R$libdir' + hardcode_direct_CXX=yes + hardcode_shlibpath_var_CXX=no + fi + # Workaround some broken pre-1.5 toolchains + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"' + ;; + + *nto* | *qnx*) + ld_shlibs_CXX=yes + ;; + + openbsd2*) + # C++ shared libraries are fairly broken + ld_shlibs_CXX=no + ;; + + openbsd*) + if test -f /usr/libexec/ld.so; then + hardcode_direct_CXX=yes + hardcode_shlibpath_var_CXX=no + hardcode_direct_absolute_CXX=yes + archive_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' + hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + archive_expsym_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib' + export_dynamic_flag_spec_CXX='${wl}-E' + whole_archive_flag_spec_CXX="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + fi + output_verbose_link_cmd=func_echo_all + else + ld_shlibs_CXX=no + fi + ;; + + osf3* | osf4* | osf5*) + case $cc_basename in + KCC*) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + archive_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + + hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' + hardcode_libdir_separator_CXX=: + + # Archives containing C++ object files must be created using + # the KAI C++ compiler. + case $host in + osf3*) old_archive_cmds_CXX='$CC -Bstatic -o $oldlib $oldobjs' ;; + *) old_archive_cmds_CXX='$CC -o $oldlib $oldobjs' ;; + esac + ;; + RCC*) + # Rational C++ 2.4.1 + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + cxx*) + case $host in + osf3*) + allow_undefined_flag_CXX=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds_CXX='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && func_echo_all "${wl}-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' + hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' + ;; + *) + allow_undefined_flag_CXX=' -expect_unresolved \*' + archive_cmds_CXX='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' + archive_expsym_cmds_CXX='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~ + echo "-hidden">> $lib.exp~ + $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname ${wl}-input ${wl}$lib.exp `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~ + $RM $lib.exp' + hardcode_libdir_flag_spec_CXX='-rpath $libdir' + ;; + esac + + hardcode_libdir_separator_CXX=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' + ;; + *) + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + allow_undefined_flag_CXX=' ${wl}-expect_unresolved ${wl}\*' + case $host in + osf3*) + archive_cmds_CXX='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + ;; + *) + archive_cmds_CXX='$CC -shared $pic_flag -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + ;; + esac + + hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator_CXX=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' + + else + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + fi + ;; + esac + ;; + + psos*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + + sunos4*) + case $cc_basename in + CC*) + # Sun C++ 4.x + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + lcc*) + # Lucid + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + esac + ;; + + solaris*) + case $cc_basename in + CC* | sunCC*) + # Sun C++ 4.2, 5.x and Centerline C++ + archive_cmds_need_lc_CXX=yes + no_undefined_flag_CXX=' -zdefs' + archive_cmds_CXX='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + archive_expsym_cmds_CXX='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -G${allow_undefined_flag} ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' + + hardcode_libdir_flag_spec_CXX='-R$libdir' + hardcode_shlibpath_var_CXX=no + case $host_os in + solaris2.[0-5] | solaris2.[0-5].*) ;; + *) + # The compiler driver will combine and reorder linker options, + # but understands `-z linker_flag'. + # Supported since Solaris 2.6 (maybe 2.5.1?) + whole_archive_flag_spec_CXX='-z allextract$convenience -z defaultextract' + ;; + esac + link_all_deplibs_CXX=yes + + output_verbose_link_cmd='func_echo_all' + + # Archives containing C++ object files must be created using + # "CC -xar", where "CC" is the Sun C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + old_archive_cmds_CXX='$CC -xar -o $oldlib $oldobjs' + ;; + gcx*) + # Green Hills C++ Compiler + archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + + # The C++ compiler must be used to create the archive. + old_archive_cmds_CXX='$CC $LDFLAGS -archive -o $oldlib $oldobjs' + ;; + *) + # GNU C++ compiler with Solaris linker + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + no_undefined_flag_CXX=' ${wl}-z ${wl}defs' + if $CC --version | $GREP -v '^2\.7' > /dev/null; then + archive_cmds_CXX='$CC -shared $pic_flag -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + archive_expsym_cmds_CXX='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -shared $pic_flag -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' + else + # g++ 2.7 appears to require `-G' NOT `-shared' on this + # platform. + archive_cmds_CXX='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + archive_expsym_cmds_CXX='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' + fi + + hardcode_libdir_flag_spec_CXX='${wl}-R $wl$libdir' + case $host_os in + solaris2.[0-5] | solaris2.[0-5].*) ;; + *) + whole_archive_flag_spec_CXX='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' + ;; + esac + fi + ;; + esac + ;; + + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*) + no_undefined_flag_CXX='${wl}-z,text' + archive_cmds_need_lc_CXX=no + hardcode_shlibpath_var_CXX=no + runpath_var='LD_RUN_PATH' + + case $cc_basename in + CC*) + archive_cmds_CXX='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_CXX='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + archive_cmds_CXX='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_CXX='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + ;; + + sysv5* | sco3.2v5* | sco5v6*) + # Note: We can NOT use -z defs as we might desire, because we do not + # link with -lc, and that would cause any symbols used from libc to + # always be unresolved, which means just about no library would + # ever link correctly. If we're not using GNU ld we use -z text + # though, which does catch some bad symbols but isn't as heavy-handed + # as -z defs. + no_undefined_flag_CXX='${wl}-z,text' + allow_undefined_flag_CXX='${wl}-z,nodefs' + archive_cmds_need_lc_CXX=no + hardcode_shlibpath_var_CXX=no + hardcode_libdir_flag_spec_CXX='${wl}-R,$libdir' + hardcode_libdir_separator_CXX=':' + link_all_deplibs_CXX=yes + export_dynamic_flag_spec_CXX='${wl}-Bexport' + runpath_var='LD_RUN_PATH' + + case $cc_basename in + CC*) + archive_cmds_CXX='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_CXX='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + old_archive_cmds_CXX='$CC -Tprelink_objects $oldobjs~ + '"$old_archive_cmds_CXX" + reload_cmds_CXX='$CC -Tprelink_objects $reload_objs~ + '"$reload_cmds_CXX" + ;; + *) + archive_cmds_CXX='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_CXX='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + ;; + + tandem*) + case $cc_basename in + NCC*) + # NonStop-UX NCC 3.20 + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + esac + ;; + + vxworks*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + esac + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs_CXX" >&5 +$as_echo "$ld_shlibs_CXX" >&6; } + test "$ld_shlibs_CXX" = no && can_build_shared=no + + GCC_CXX="$GXX" + LD_CXX="$LD" + + ## CAVEAT EMPTOR: + ## There is no encapsulation within the following macros, do not change + ## the running order or otherwise move them around unless you know exactly + ## what you are doing... + # Dependencies to place before and after the object being linked: +predep_objects_CXX= +postdep_objects_CXX= +predeps_CXX= +postdeps_CXX= +compiler_lib_search_path_CXX= + +cat > conftest.$ac_ext <<_LT_EOF +class Foo +{ +public: + Foo (void) { a = 0; } +private: + int a; +}; +_LT_EOF + + +_lt_libdeps_save_CFLAGS=$CFLAGS +case "$CC $CFLAGS " in #( +*\ -flto*\ *) CFLAGS="$CFLAGS -fno-lto" ;; +*\ -fwhopr*\ *) CFLAGS="$CFLAGS -fno-whopr" ;; +*\ -fuse-linker-plugin*\ *) CFLAGS="$CFLAGS -fno-use-linker-plugin" ;; +esac + +if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + # Parse the compiler output and extract the necessary + # objects, libraries and library flags. + + # Sentinel used to keep track of whether or not we are before + # the conftest object file. + pre_test_object_deps_done=no + + for p in `eval "$output_verbose_link_cmd"`; do + case ${prev}${p} in + + -L* | -R* | -l*) + # Some compilers place space between "-{L,R}" and the path. + # Remove the space. + if test $p = "-L" || + test $p = "-R"; then + prev=$p + continue + fi + + # Expand the sysroot to ease extracting the directories later. + if test -z "$prev"; then + case $p in + -L*) func_stripname_cnf '-L' '' "$p"; prev=-L; p=$func_stripname_result ;; + -R*) func_stripname_cnf '-R' '' "$p"; prev=-R; p=$func_stripname_result ;; + -l*) func_stripname_cnf '-l' '' "$p"; prev=-l; p=$func_stripname_result ;; + esac + fi + case $p in + =*) func_stripname_cnf '=' '' "$p"; p=$lt_sysroot$func_stripname_result ;; + esac + if test "$pre_test_object_deps_done" = no; then + case ${prev} in + -L | -R) + # Internal compiler library paths should come after those + # provided the user. The postdeps already come after the + # user supplied libs so there is no need to process them. + if test -z "$compiler_lib_search_path_CXX"; then + compiler_lib_search_path_CXX="${prev}${p}" + else + compiler_lib_search_path_CXX="${compiler_lib_search_path_CXX} ${prev}${p}" + fi + ;; + # The "-l" case would never come before the object being + # linked, so don't bother handling this case. + esac + else + if test -z "$postdeps_CXX"; then + postdeps_CXX="${prev}${p}" + else + postdeps_CXX="${postdeps_CXX} ${prev}${p}" + fi + fi + prev= + ;; + + *.lto.$objext) ;; # Ignore GCC LTO objects + *.$objext) + # This assumes that the test object file only shows up + # once in the compiler output. + if test "$p" = "conftest.$objext"; then + pre_test_object_deps_done=yes + continue + fi + + if test "$pre_test_object_deps_done" = no; then + if test -z "$predep_objects_CXX"; then + predep_objects_CXX="$p" + else + predep_objects_CXX="$predep_objects_CXX $p" + fi + else + if test -z "$postdep_objects_CXX"; then + postdep_objects_CXX="$p" + else + postdep_objects_CXX="$postdep_objects_CXX $p" + fi + fi + ;; + + *) ;; # Ignore the rest. + + esac + done + + # Clean up. + rm -f a.out a.exe +else + echo "libtool.m4: error: problem compiling CXX test program" +fi + +$RM -f confest.$objext +CFLAGS=$_lt_libdeps_save_CFLAGS + +# PORTME: override above test on systems where it is broken +case $host_os in +interix[3-9]*) + # Interix 3.5 installs completely hosed .la files for C++, so rather than + # hack all around it, let's just trust "g++" to DTRT. + predep_objects_CXX= + postdep_objects_CXX= + postdeps_CXX= + ;; + +linux*) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C++ 5.9 + + # The more standards-conforming stlport4 library is + # incompatible with the Cstd library. Avoid specifying + # it if it's in CXXFLAGS. Ignore libCrun as + # -library=stlport4 depends on it. + case " $CXX $CXXFLAGS " in + *" -library=stlport4 "*) + solaris_use_stlport4=yes + ;; + esac + + if test "$solaris_use_stlport4" != yes; then + postdeps_CXX='-library=Cstd -library=Crun' + fi + ;; + esac + ;; + +solaris*) + case $cc_basename in + CC* | sunCC*) + # The more standards-conforming stlport4 library is + # incompatible with the Cstd library. Avoid specifying + # it if it's in CXXFLAGS. Ignore libCrun as + # -library=stlport4 depends on it. + case " $CXX $CXXFLAGS " in + *" -library=stlport4 "*) + solaris_use_stlport4=yes + ;; + esac + + # Adding this requires a known-good setup of shared libraries for + # Sun compiler versions before 5.6, else PIC objects from an old + # archive will be linked into the output, leading to subtle bugs. + if test "$solaris_use_stlport4" != yes; then + postdeps_CXX='-library=Cstd -library=Crun' + fi + ;; + esac + ;; +esac + + +case " $postdeps_CXX " in +*" -lc "*) archive_cmds_need_lc_CXX=no ;; +esac + compiler_lib_search_dirs_CXX= +if test -n "${compiler_lib_search_path_CXX}"; then + compiler_lib_search_dirs_CXX=`echo " ${compiler_lib_search_path_CXX}" | ${SED} -e 's! -L! !g' -e 's!^ !!'` +fi + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + lt_prog_compiler_wl_CXX= +lt_prog_compiler_pic_CXX= +lt_prog_compiler_static_CXX= + + + # C++ specific cases for pic, static, wl, etc. + if test "$GXX" = yes; then + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_static_CXX='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static_CXX='-Bstatic' + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + lt_prog_compiler_pic_CXX='-fPIC' + ;; + m68k) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + lt_prog_compiler_pic_CXX='-m68020 -resident32 -malways-restore-a4' + ;; + esac + ;; + + beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + mingw* | cygwin* | os2* | pw32* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + # Although the cygwin gcc ignores -fPIC, still need this for old-style + # (--disable-auto-import) libraries + lt_prog_compiler_pic_CXX='-DDLL_EXPORT' + ;; + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + lt_prog_compiler_pic_CXX='-fno-common' + ;; + *djgpp*) + # DJGPP does not support shared libraries at all + lt_prog_compiler_pic_CXX= + ;; + haiku*) + # PIC is the default for Haiku. + # The "-static" flag exists, but is broken. + lt_prog_compiler_static_CXX= + ;; + interix[3-9]*) + # Interix 3.x gcc -fpic/-fPIC options generate broken code. + # Instead, we relocate shared libraries at runtime. + ;; + sysv4*MP*) + if test -d /usr/nec; then + lt_prog_compiler_pic_CXX=-Kconform_pic + fi + ;; + hpux*) + # PIC is the default for 64-bit PA HP-UX, but not for 32-bit + # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag + # sets the default TLS model and affects inlining. + case $host_cpu in + hppa*64*) + ;; + *) + lt_prog_compiler_pic_CXX='-fPIC' + ;; + esac + ;; + *qnx* | *nto*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + lt_prog_compiler_pic_CXX='-fPIC -shared' + ;; + *) + lt_prog_compiler_pic_CXX='-fPIC' + ;; + esac + else + case $host_os in + aix[4-9]*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static_CXX='-Bstatic' + else + lt_prog_compiler_static_CXX='-bnso -bI:/lib/syscalls.exp' + fi + ;; + chorus*) + case $cc_basename in + cxch68*) + # Green Hills C++ Compiler + # _LT_TAGVAR(lt_prog_compiler_static, CXX)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a" + ;; + esac + ;; + mingw* | cygwin* | os2* | pw32* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + lt_prog_compiler_pic_CXX='-DDLL_EXPORT' + ;; + dgux*) + case $cc_basename in + ec++*) + lt_prog_compiler_pic_CXX='-KPIC' + ;; + ghcx*) + # Green Hills C++ Compiler + lt_prog_compiler_pic_CXX='-pic' + ;; + *) + ;; + esac + ;; + freebsd* | dragonfly*) + # FreeBSD uses GNU C++ + ;; + hpux9* | hpux10* | hpux11*) + case $cc_basename in + CC*) + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_static_CXX='${wl}-a ${wl}archive' + if test "$host_cpu" != ia64; then + lt_prog_compiler_pic_CXX='+Z' + fi + ;; + aCC*) + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_static_CXX='${wl}-a ${wl}archive' + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + lt_prog_compiler_pic_CXX='+Z' + ;; + esac + ;; + *) + ;; + esac + ;; + interix*) + # This is c89, which is MS Visual C++ (no shared libs) + # Anyone wants to do a port? + ;; + irix5* | irix6* | nonstopux*) + case $cc_basename in + CC*) + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_static_CXX='-non_shared' + # CC pic flag -KPIC is the default. + ;; + *) + ;; + esac + ;; + linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) + case $cc_basename in + KCC*) + # KAI C++ Compiler + lt_prog_compiler_wl_CXX='--backend -Wl,' + lt_prog_compiler_pic_CXX='-fPIC' + ;; + ecpc* ) + # old Intel C++ for x86_64 which still supported -KPIC. + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_pic_CXX='-KPIC' + lt_prog_compiler_static_CXX='-static' + ;; + icpc* ) + # Intel C++, used to be incompatible with GCC. + # ICC 10 doesn't accept -KPIC any more. + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_pic_CXX='-fPIC' + lt_prog_compiler_static_CXX='-static' + ;; + pgCC* | pgcpp*) + # Portland Group C++ compiler + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_pic_CXX='-fpic' + lt_prog_compiler_static_CXX='-Bstatic' + ;; + cxx*) + # Compaq C++ + # Make sure the PIC flag is empty. It appears that all Alpha + # Linux and Compaq Tru64 Unix objects are PIC. + lt_prog_compiler_pic_CXX= + lt_prog_compiler_static_CXX='-non_shared' + ;; + xlc* | xlC* | bgxl[cC]* | mpixl[cC]*) + # IBM XL 8.0, 9.0 on PPC and BlueGene + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_pic_CXX='-qpic' + lt_prog_compiler_static_CXX='-qstaticlink' + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C++ 5.9 + lt_prog_compiler_pic_CXX='-KPIC' + lt_prog_compiler_static_CXX='-Bstatic' + lt_prog_compiler_wl_CXX='-Qoption ld ' + ;; + esac + ;; + esac + ;; + lynxos*) + ;; + m88k*) + ;; + mvs*) + case $cc_basename in + cxx*) + lt_prog_compiler_pic_CXX='-W c,exportall' + ;; + *) + ;; + esac + ;; + netbsd* | netbsdelf*-gnu) + ;; + *qnx* | *nto*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + lt_prog_compiler_pic_CXX='-fPIC -shared' + ;; + osf3* | osf4* | osf5*) + case $cc_basename in + KCC*) + lt_prog_compiler_wl_CXX='--backend -Wl,' + ;; + RCC*) + # Rational C++ 2.4.1 + lt_prog_compiler_pic_CXX='-pic' + ;; + cxx*) + # Digital/Compaq C++ + lt_prog_compiler_wl_CXX='-Wl,' + # Make sure the PIC flag is empty. It appears that all Alpha + # Linux and Compaq Tru64 Unix objects are PIC. + lt_prog_compiler_pic_CXX= + lt_prog_compiler_static_CXX='-non_shared' + ;; + *) + ;; + esac + ;; + psos*) + ;; + solaris*) + case $cc_basename in + CC* | sunCC*) + # Sun C++ 4.2, 5.x and Centerline C++ + lt_prog_compiler_pic_CXX='-KPIC' + lt_prog_compiler_static_CXX='-Bstatic' + lt_prog_compiler_wl_CXX='-Qoption ld ' + ;; + gcx*) + # Green Hills C++ Compiler + lt_prog_compiler_pic_CXX='-PIC' + ;; + *) + ;; + esac + ;; + sunos4*) + case $cc_basename in + CC*) + # Sun C++ 4.x + lt_prog_compiler_pic_CXX='-pic' + lt_prog_compiler_static_CXX='-Bstatic' + ;; + lcc*) + # Lucid + lt_prog_compiler_pic_CXX='-pic' + ;; + *) + ;; + esac + ;; + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + case $cc_basename in + CC*) + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_pic_CXX='-KPIC' + lt_prog_compiler_static_CXX='-Bstatic' + ;; + esac + ;; + tandem*) + case $cc_basename in + NCC*) + # NonStop-UX NCC 3.20 + lt_prog_compiler_pic_CXX='-KPIC' + ;; + *) + ;; + esac + ;; + vxworks*) + ;; + *) + lt_prog_compiler_can_build_shared_CXX=no + ;; + esac + fi + +case $host_os in + # For platforms which do not support PIC, -DPIC is meaningless: + *djgpp*) + lt_prog_compiler_pic_CXX= + ;; + *) + lt_prog_compiler_pic_CXX="$lt_prog_compiler_pic_CXX -DPIC" + ;; +esac + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5 +$as_echo_n "checking for $compiler option to produce PIC... " >&6; } +if ${lt_cv_prog_compiler_pic_CXX+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_pic_CXX=$lt_prog_compiler_pic_CXX +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_CXX" >&5 +$as_echo "$lt_cv_prog_compiler_pic_CXX" >&6; } +lt_prog_compiler_pic_CXX=$lt_cv_prog_compiler_pic_CXX + +# +# Check to make sure the PIC flag actually works. +# +if test -n "$lt_prog_compiler_pic_CXX"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic_CXX works" >&5 +$as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic_CXX works... " >&6; } +if ${lt_cv_prog_compiler_pic_works_CXX+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_pic_works_CXX=no + ac_outfile=conftest.$ac_objext + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="$lt_prog_compiler_pic_CXX -DPIC" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings other than the usual output. + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler_pic_works_CXX=yes + fi + fi + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works_CXX" >&5 +$as_echo "$lt_cv_prog_compiler_pic_works_CXX" >&6; } + +if test x"$lt_cv_prog_compiler_pic_works_CXX" = xyes; then + case $lt_prog_compiler_pic_CXX in + "" | " "*) ;; + *) lt_prog_compiler_pic_CXX=" $lt_prog_compiler_pic_CXX" ;; + esac +else + lt_prog_compiler_pic_CXX= + lt_prog_compiler_can_build_shared_CXX=no +fi + +fi + + + + + +# +# Check to make sure the static flag actually works. +# +wl=$lt_prog_compiler_wl_CXX eval lt_tmp_static_flag=\"$lt_prog_compiler_static_CXX\" +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5 +$as_echo_n "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; } +if ${lt_cv_prog_compiler_static_works_CXX+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_static_works_CXX=no + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS $lt_tmp_static_flag" + echo "$lt_simple_link_test_code" > conftest.$ac_ext + if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then + # The linker can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + # Append any errors to the config.log. + cat conftest.err 1>&5 + $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler_static_works_CXX=yes + fi + else + lt_cv_prog_compiler_static_works_CXX=yes + fi + fi + $RM -r conftest* + LDFLAGS="$save_LDFLAGS" + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works_CXX" >&5 +$as_echo "$lt_cv_prog_compiler_static_works_CXX" >&6; } + +if test x"$lt_cv_prog_compiler_static_works_CXX" = xyes; then + : +else + lt_prog_compiler_static_CXX= +fi + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 +$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } +if ${lt_cv_prog_compiler_c_o_CXX+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_c_o_CXX=no + $RM -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp + $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 + if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then + lt_cv_prog_compiler_c_o_CXX=yes + fi + fi + chmod u+w . 2>&5 + $RM conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files + $RM out/* && rmdir out + cd .. + $RM -r conftest + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o_CXX" >&5 +$as_echo "$lt_cv_prog_compiler_c_o_CXX" >&6; } + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 +$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } +if ${lt_cv_prog_compiler_c_o_CXX+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_c_o_CXX=no + $RM -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp + $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 + if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then + lt_cv_prog_compiler_c_o_CXX=yes + fi + fi + chmod u+w . 2>&5 + $RM conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files + $RM out/* && rmdir out + cd .. + $RM -r conftest + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o_CXX" >&5 +$as_echo "$lt_cv_prog_compiler_c_o_CXX" >&6; } + + + + +hard_links="nottested" +if test "$lt_cv_prog_compiler_c_o_CXX" = no && test "$need_locks" != no; then + # do not overwrite the value of need_locks provided by the user + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5 +$as_echo_n "checking if we can lock with hard links... " >&6; } + hard_links=yes + $RM conftest* + ln conftest.a conftest.b 2>/dev/null && hard_links=no + touch conftest.a + ln conftest.a conftest.b 2>&5 || hard_links=no + ln conftest.a conftest.b 2>/dev/null && hard_links=no + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5 +$as_echo "$hard_links" >&6; } + if test "$hard_links" = no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5 +$as_echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;} + need_locks=warn + fi +else + need_locks=no +fi + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5 +$as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; } + + export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + exclude_expsyms_CXX='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*' + case $host_os in + aix[4-9]*) + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to AIX nm, but means don't demangle with GNU nm + # Also, AIX nm treats weak defined symbols like other global defined + # symbols, whereas GNU nm marks them as "W". + if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then + export_symbols_cmds_CXX='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + else + export_symbols_cmds_CXX='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + fi + ;; + pw32*) + export_symbols_cmds_CXX="$ltdll_cmds" + ;; + cygwin* | mingw* | cegcc*) + case $cc_basename in + cl*) + exclude_expsyms_CXX='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' + ;; + *) + export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/;s/^.*[ ]__nm__\([^ ]*\)[ ][^ ]*/\1 DATA/;/^I[ ]/d;/^[AITW][ ]/s/.* //'\'' | sort | uniq > $export_symbols' + exclude_expsyms_CXX='[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname' + ;; + esac + ;; + linux* | k*bsd*-gnu | gnu*) + link_all_deplibs_CXX=no + ;; + *) + export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + ;; + esac + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs_CXX" >&5 +$as_echo "$ld_shlibs_CXX" >&6; } +test "$ld_shlibs_CXX" = no && can_build_shared=no + +with_gnu_ld_CXX=$with_gnu_ld + + + + + + +# +# Do we need to explicitly link libc? +# +case "x$archive_cmds_need_lc_CXX" in +x|xyes) + # Assume -lc should be added + archive_cmds_need_lc_CXX=yes + + if test "$enable_shared" = yes && test "$GCC" = yes; then + case $archive_cmds_CXX in + *'~'*) + # FIXME: we may have to deal with multi-command sequences. + ;; + '$CC '*) + # Test whether the compiler implicitly links with -lc since on some + # systems, -lgcc has to come before -lc. If gcc already passes -lc + # to ld, don't add -lc before -lgcc. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5 +$as_echo_n "checking whether -lc should be explicitly linked in... " >&6; } +if ${lt_cv_archive_cmds_need_lc_CXX+:} false; then : + $as_echo_n "(cached) " >&6 +else + $RM conftest* + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } 2>conftest.err; then + soname=conftest + lib=conftest + libobjs=conftest.$ac_objext + deplibs= + wl=$lt_prog_compiler_wl_CXX + pic_flag=$lt_prog_compiler_pic_CXX + compiler_flags=-v + linker_flags=-v + verstring= + output_objdir=. + libname=conftest + lt_save_allow_undefined_flag=$allow_undefined_flag_CXX + allow_undefined_flag_CXX= + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds_CXX 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5 + (eval $archive_cmds_CXX 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + then + lt_cv_archive_cmds_need_lc_CXX=no + else + lt_cv_archive_cmds_need_lc_CXX=yes + fi + allow_undefined_flag_CXX=$lt_save_allow_undefined_flag + else + cat conftest.err 1>&5 + fi + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_archive_cmds_need_lc_CXX" >&5 +$as_echo "$lt_cv_archive_cmds_need_lc_CXX" >&6; } + archive_cmds_need_lc_CXX=$lt_cv_archive_cmds_need_lc_CXX + ;; + esac + fi + ;; +esac + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5 +$as_echo_n "checking dynamic linker characteristics... " >&6; } + +library_names_spec= +libname_spec='lib$name' +soname_spec= +shrext_cmds=".so" +postinstall_cmds= +postuninstall_cmds= +finish_cmds= +finish_eval= +shlibpath_var= +shlibpath_overrides_runpath=unknown +version_type=none +dynamic_linker="$host_os ld.so" +sys_lib_dlsearch_path_spec="/lib /usr/lib" +need_lib_prefix=unknown +hardcode_into_libs=no + +# when you set need_version to no, make sure it does not cause -set_version +# flags to be left without arguments +need_version=unknown + +case $host_os in +aix3*) + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' + shlibpath_var=LIBPATH + + # AIX 3 has no versioning support, so we append a major version to the name. + soname_spec='${libname}${release}${shared_ext}$major' + ;; + +aix[4-9]*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + hardcode_into_libs=yes + if test "$host_cpu" = ia64; then + # AIX 5 supports IA64 + library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + else + # With GCC up to 2.95.x, collect2 would create an import file + # for dependence libraries. The import file would start with + # the line `#! .'. This would cause the generated library to + # depend on `.', always an invalid library. This was fixed in + # development snapshots of GCC prior to 3.0. + case $host_os in + aix4 | aix4.[01] | aix4.[01].*) + if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' + echo ' yes ' + echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then + : + else + can_build_shared=no + fi + ;; + esac + # AIX (on Power*) has no versioning support, so currently we can not hardcode correct + # soname into executable. Probably we can add versioning support to + # collect2, so additional links can be useful in future. + if test "$aix_use_runtimelinking" = yes; then + # If using run time linking (on AIX 4.2 or later) use lib.so + # instead of lib.a to let people know that these are not + # typical AIX shared libraries. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + else + # We preserve .a as extension for shared libraries through AIX4.2 + # and later when we are not doing run time linking. + library_names_spec='${libname}${release}.a $libname.a' + soname_spec='${libname}${release}${shared_ext}$major' + fi + shlibpath_var=LIBPATH + fi + ;; + +amigaos*) + case $host_cpu in + powerpc) + # Since July 2007 AmigaOS4 officially supports .so libraries. + # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + ;; + m68k) + library_names_spec='$libname.ixlibrary $libname.a' + # Create ${libname}_ixlibrary.a entries in /sys/libs. + finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' + ;; + esac + ;; + +beos*) + library_names_spec='${libname}${shared_ext}' + dynamic_linker="$host_os ld.so" + shlibpath_var=LIBRARY_PATH + ;; + +bsdi[45]*) + version_type=linux # correct to gnu/linux during the next big refactor + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" + sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" + # the default ld.so.conf also contains /usr/contrib/lib and + # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow + # libtool to hard-code these into programs + ;; + +cygwin* | mingw* | pw32* | cegcc*) + version_type=windows + shrext_cmds=".dll" + need_version=no + need_lib_prefix=no + + case $GCC,$cc_basename in + yes,*) + # gcc + library_names_spec='$libname.dll.a' + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \${file}`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname~ + chmod a+x \$dldir/$dlname~ + if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then + eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; + fi' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $RM \$dlpath' + shlibpath_overrides_runpath=yes + + case $host_os in + cygwin*) + # Cygwin DLLs use 'cyg' prefix rather than 'lib' + soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + + ;; + mingw* | cegcc*) + # MinGW DLLs use traditional 'lib' prefix + soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + ;; + pw32*) + # pw32 DLLs use 'pw' prefix rather than 'lib' + library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + ;; + esac + dynamic_linker='Win32 ld.exe' + ;; + + *,cl*) + # Native MSVC + libname_spec='$name' + soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + library_names_spec='${libname}.dll.lib' + + case $build_os in + mingw*) + sys_lib_search_path_spec= + lt_save_ifs=$IFS + IFS=';' + for lt_path in $LIB + do + IFS=$lt_save_ifs + # Let DOS variable expansion print the short 8.3 style file name. + lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"` + sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path" + done + IFS=$lt_save_ifs + # Convert to MSYS style. + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([a-zA-Z]\\):| /\\1|g' -e 's|^ ||'` + ;; + cygwin*) + # Convert to unix form, then to dos form, then back to unix form + # but this time dos style (no spaces!) so that the unix form looks + # like /cygdrive/c/PROGRA~1:/cygdr... + sys_lib_search_path_spec=`cygpath --path --unix "$LIB"` + sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null` + sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + ;; + *) + sys_lib_search_path_spec="$LIB" + if $ECHO "$sys_lib_search_path_spec" | $GREP ';[c-zC-Z]:/' >/dev/null; then + # It is most probably a Windows format PATH. + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` + else + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi + # FIXME: find the short name or the path components, as spaces are + # common. (e.g. "Program Files" -> "PROGRA~1") + ;; + esac + + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \${file}`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $RM \$dlpath' + shlibpath_overrides_runpath=yes + dynamic_linker='Win32 link.exe' + ;; + + *) + # Assume MSVC wrapper + library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib' + dynamic_linker='Win32 ld.exe' + ;; + esac + # FIXME: first we should search . and the directory the executable is in + shlibpath_var=PATH + ;; + +darwin* | rhapsody*) + dynamic_linker="$host_os dyld" + version_type=darwin + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext' + soname_spec='${libname}${release}${major}$shared_ext' + shlibpath_overrides_runpath=yes + shlibpath_var=DYLD_LIBRARY_PATH + shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' + + sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' + ;; + +dgux*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +freebsd* | dragonfly*) + # DragonFly does not have aout. When/if they implement a new + # versioning mechanism, adjust this. + if test -x /usr/bin/objformat; then + objformat=`/usr/bin/objformat` + else + case $host_os in + freebsd[23].*) objformat=aout ;; + *) objformat=elf ;; + esac + fi + version_type=freebsd-$objformat + case $version_type in + freebsd-elf*) + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + need_version=no + need_lib_prefix=no + ;; + freebsd-*) + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' + need_version=yes + ;; + esac + shlibpath_var=LD_LIBRARY_PATH + case $host_os in + freebsd2.*) + shlibpath_overrides_runpath=yes + ;; + freebsd3.[01]* | freebsdelf3.[01]*) + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + freebsd3.[2-9]* | freebsdelf3.[2-9]* | \ + freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1) + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + *) # from 4.6 on, and DragonFly + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + esac + ;; + +haiku*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + dynamic_linker="$host_os runtime_loader" + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LIBRARY_PATH + shlibpath_overrides_runpath=yes + sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib' + hardcode_into_libs=yes + ;; + +hpux9* | hpux10* | hpux11*) + # Give a soname corresponding to the major version so that dld.sl refuses to + # link against other versions. + version_type=sunos + need_lib_prefix=no + need_version=no + case $host_cpu in + ia64*) + shrext_cmds='.so' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.so" + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + if test "X$HPUX_IA64_MODE" = X32; then + sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" + else + sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" + fi + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + hppa*64*) + shrext_cmds='.sl' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.sl" + shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + *) + shrext_cmds='.sl' + dynamic_linker="$host_os dld.sl" + shlibpath_var=SHLIB_PATH + shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + ;; + esac + # HP-UX runs *really* slowly unless shared libraries are mode 555, ... + postinstall_cmds='chmod 555 $lib' + # or fails outright, so override atomically: + install_override_mode=555 + ;; + +interix[3-9]*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +irix5* | irix6* | nonstopux*) + case $host_os in + nonstopux*) version_type=nonstopux ;; + *) + if test "$lt_cv_prog_gnu_ld" = yes; then + version_type=linux # correct to gnu/linux during the next big refactor + else + version_type=irix + fi ;; + esac + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' + case $host_os in + irix5* | nonstopux*) + libsuff= shlibsuff= + ;; + *) + case $LD in # libtool.m4 will add one of these switches to LD + *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") + libsuff= shlibsuff= libmagic=32-bit;; + *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") + libsuff=32 shlibsuff=N32 libmagic=N32;; + *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") + libsuff=64 shlibsuff=64 libmagic=64-bit;; + *) libsuff= shlibsuff= libmagic=never-match;; + esac + ;; + esac + shlibpath_var=LD_LIBRARY${shlibsuff}_PATH + shlibpath_overrides_runpath=no + sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" + sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" + hardcode_into_libs=yes + ;; + +# No shared lib support for Linux oldld, aout, or coff. +linux*oldld* | linux*aout* | linux*coff*) + dynamic_linker=no + ;; + +# This must be glibc/ELF. +linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + + # Some binutils ld are patched to set DT_RUNPATH + if ${lt_cv_shlibpath_overrides_runpath+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_shlibpath_overrides_runpath=no + save_LDFLAGS=$LDFLAGS + save_libdir=$libdir + eval "libdir=/foo; wl=\"$lt_prog_compiler_wl_CXX\"; \ + LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec_CXX\"" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + if ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null; then : + lt_cv_shlibpath_overrides_runpath=yes +fi +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LDFLAGS=$save_LDFLAGS + libdir=$save_libdir + +fi + + shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath + + # This implies no fast_install, which is unacceptable. + # Some rework will be needed to allow for fast_install + # before this can be enabled. + hardcode_into_libs=yes + + # Append ld.so.conf contents to the search path + if test -f /etc/ld.so.conf; then + lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '` + sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" + fi + + # We used to test for /lib/ld.so.1 and disable shared libraries on + # powerpc, because MkLinux only supported shared libraries with the + # GNU dynamic linker. Since this was broken with cross compilers, + # most powerpc-linux boxes support dynamic linking these days and + # people can always --disable-shared, the test was removed, and we + # assume the GNU/Linux dynamic linker is in use. + dynamic_linker='GNU/Linux ld.so' + ;; + +netbsdelf*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='NetBSD ld.elf_so' + ;; + +netbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + dynamic_linker='NetBSD (a.out) ld.so' + else + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='NetBSD ld.elf_so' + fi + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + +newsos6) + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +*nto* | *qnx*) + version_type=qnx + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='ldqnx.so' + ;; + +openbsd*) + version_type=sunos + sys_lib_dlsearch_path_spec="/usr/lib" + need_lib_prefix=no + # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. + case $host_os in + openbsd3.3 | openbsd3.3.*) need_version=yes ;; + *) need_version=no ;; + esac + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + shlibpath_var=LD_LIBRARY_PATH + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + case $host_os in + openbsd2.[89] | openbsd2.[89].*) + shlibpath_overrides_runpath=no + ;; + *) + shlibpath_overrides_runpath=yes + ;; + esac + else + shlibpath_overrides_runpath=yes + fi + ;; + +os2*) + libname_spec='$name' + shrext_cmds=".dll" + need_lib_prefix=no + library_names_spec='$libname${shared_ext} $libname.a' + dynamic_linker='OS/2 ld.exe' + shlibpath_var=LIBPATH + ;; + +osf3* | osf4* | osf5*) + version_type=osf + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" + sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" + ;; + +rdos*) + dynamic_linker=no + ;; + +solaris*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + # ldd complains unless libraries are executable + postinstall_cmds='chmod +x $lib' + ;; + +sunos4*) + version_type=sunos + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + if test "$with_gnu_ld" = yes; then + need_lib_prefix=no + fi + need_version=yes + ;; + +sysv4 | sysv4.3*) + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + case $host_vendor in + sni) + shlibpath_overrides_runpath=no + need_lib_prefix=no + runpath_var=LD_RUN_PATH + ;; + siemens) + need_lib_prefix=no + ;; + motorola) + need_lib_prefix=no + need_version=no + shlibpath_overrides_runpath=no + sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' + ;; + esac + ;; + +sysv4*MP*) + if test -d /usr/nec ;then + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' + soname_spec='$libname${shared_ext}.$major' + shlibpath_var=LD_LIBRARY_PATH + fi + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + version_type=freebsd-elf + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + if test "$with_gnu_ld" = yes; then + sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' + else + sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' + case $host_os in + sco3.2v5*) + sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" + ;; + esac + fi + sys_lib_dlsearch_path_spec='/usr/lib' + ;; + +tpf*) + # TPF is a cross-target only. Preferred cross-host = GNU/Linux. + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +uts4*) + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +*) + dynamic_linker=no + ;; +esac +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5 +$as_echo "$dynamic_linker" >&6; } +test "$dynamic_linker" = no && can_build_shared=no + +variables_saved_for_relink="PATH $shlibpath_var $runpath_var" +if test "$GCC" = yes; then + variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" +fi + +if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then + sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec" +fi +if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then + sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec" +fi + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5 +$as_echo_n "checking how to hardcode library paths into programs... " >&6; } +hardcode_action_CXX= +if test -n "$hardcode_libdir_flag_spec_CXX" || + test -n "$runpath_var_CXX" || + test "X$hardcode_automatic_CXX" = "Xyes" ; then + + # We can hardcode non-existent directories. + if test "$hardcode_direct_CXX" != no && + # If the only mechanism to avoid hardcoding is shlibpath_var, we + # have to relink, otherwise we might link with an installed library + # when we should be linking with a yet-to-be-installed one + ## test "$_LT_TAGVAR(hardcode_shlibpath_var, CXX)" != no && + test "$hardcode_minus_L_CXX" != no; then + # Linking always hardcodes the temporary library directory. + hardcode_action_CXX=relink + else + # We can link without hardcoding, and we can hardcode nonexisting dirs. + hardcode_action_CXX=immediate + fi +else + # We cannot hardcode anything, or else we can only hardcode existing + # directories. + hardcode_action_CXX=unsupported +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action_CXX" >&5 +$as_echo "$hardcode_action_CXX" >&6; } + +if test "$hardcode_action_CXX" = relink || + test "$inherit_rpath_CXX" = yes; then + # Fast installation is not supported + enable_fast_install=no +elif test "$shlibpath_overrides_runpath" = yes || + test "$enable_shared" = no; then + # Fast installation is not necessary + enable_fast_install=needless +fi + + + + + + + + fi # test -n "$compiler" + + CC=$lt_save_CC + CFLAGS=$lt_save_CFLAGS + LDCXX=$LD + LD=$lt_save_LD + GCC=$lt_save_GCC + with_gnu_ld=$lt_save_with_gnu_ld + lt_cv_path_LDCXX=$lt_cv_path_LD + lt_cv_path_LD=$lt_save_path_LD + lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld + lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld +fi # test "$_lt_caught_CXX_error" != yes + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + + + + + + + + + + + + + + ac_config_commands="$ac_config_commands libtool" + + + + +# Only expand once: + + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AmigaOS /C/install, which installs bootblocks on floppy discs +# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# OS/2's system install, which has a completely different semantic +# ./install, which can be erroneously created by make from ./install.sh. +# Reject install programs that cannot install multiple files. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 +$as_echo_n "checking for a BSD-compatible install... " >&6; } +if test -z "$INSTALL"; then +if ${ac_cv_path_install+:} false; then : + $as_echo_n "(cached) " >&6 +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + # Account for people who put trailing slashes in PATH elements. +case $as_dir/ in #(( + ./ | .// | /[cC]/* | \ + /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ + ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ + /usr/ucb/* ) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + # Don't use installbsd from OSF since it installs stuff as root + # by default. + for ac_prog in ginstall scoinst install; do + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then + if test $ac_prog = install && + grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + : + elif test $ac_prog = install && + grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # program-specific install script used by HP pwplus--don't use. + : + else + rm -rf conftest.one conftest.two conftest.dir + echo one > conftest.one + echo two > conftest.two + mkdir conftest.dir + if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && + test -s conftest.one && test -s conftest.two && + test -s conftest.dir/conftest.one && + test -s conftest.dir/conftest.two + then + ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" + break 3 + fi + fi + fi + done + done + ;; +esac + + done +IFS=$as_save_IFS + +rm -rf conftest.one conftest.two conftest.dir + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL=$ac_cv_path_install + else + # As a last resort, use the slow shell script. Don't cache a + # value for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the value is a relative name. + INSTALL=$ac_install_sh + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 +$as_echo "$INSTALL" >&6; } + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5 +$as_echo_n "checking whether ln -s works... " >&6; } +LN_S=$as_ln_s +if test "$LN_S" = "ln -s"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5 +$as_echo "no, using $LN_S" >&6; } +fi + +# Extract the first word of "ar", so it can be a program name with args. +set dummy ar; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_AR+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $AR in + [\\/]* | ?:[\\/]*) + ac_cv_path_AR="$AR" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_AR="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + test -z "$ac_cv_path_AR" && ac_cv_path_AR="no" + ;; +esac +fi +AR=$ac_cv_path_AR +if test -n "$AR"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 +$as_echo "$AR" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +if [ $AR = "no" ] ; then + as_fn_error $? "\"Could not find ar - needed to create a library\"" "$LINENO" 5 +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether byte ordering is bigendian" >&5 +$as_echo_n "checking whether byte ordering is bigendian... " >&6; } +if ${ac_cv_c_bigendian+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_cv_c_bigendian=unknown + # See if we're dealing with a universal compiler. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifndef __APPLE_CC__ + not a universal capable compiler + #endif + typedef int dummy; + +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + + # Check for potential -arch flags. It is not universal unless + # there are at least two -arch flags with different values. + ac_arch= + ac_prev= + for ac_word in $CC $CFLAGS $CPPFLAGS $LDFLAGS; do + if test -n "$ac_prev"; then + case $ac_word in + i?86 | x86_64 | ppc | ppc64) + if test -z "$ac_arch" || test "$ac_arch" = "$ac_word"; then + ac_arch=$ac_word + else + ac_cv_c_bigendian=universal + break + fi + ;; + esac + ac_prev= + elif test "x$ac_word" = "x-arch"; then + ac_prev=arch + fi + done +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + if test $ac_cv_c_bigendian = unknown; then + # See if sys/param.h defines the BYTE_ORDER macro. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #include + +int +main () +{ +#if ! (defined BYTE_ORDER && defined BIG_ENDIAN \ + && defined LITTLE_ENDIAN && BYTE_ORDER && BIG_ENDIAN \ + && LITTLE_ENDIAN) + bogus endian macros + #endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + # It does; now see whether it defined to BIG_ENDIAN or not. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #include + +int +main () +{ +#if BYTE_ORDER != BIG_ENDIAN + not big endian + #endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_c_bigendian=yes +else + ac_cv_c_bigendian=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + fi + if test $ac_cv_c_bigendian = unknown; then + # See if defines _LITTLE_ENDIAN or _BIG_ENDIAN (e.g., Solaris). + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +int +main () +{ +#if ! (defined _LITTLE_ENDIAN || defined _BIG_ENDIAN) + bogus endian macros + #endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + # It does; now see whether it defined to _BIG_ENDIAN or not. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +int +main () +{ +#ifndef _BIG_ENDIAN + not big endian + #endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_c_bigendian=yes +else + ac_cv_c_bigendian=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + fi + if test $ac_cv_c_bigendian = unknown; then + # Compile a test program. + if test "$cross_compiling" = yes; then : + # Try to guess by grepping values from an object file. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +short int ascii_mm[] = + { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 }; + short int ascii_ii[] = + { 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 }; + int use_ascii (int i) { + return ascii_mm[i] + ascii_ii[i]; + } + short int ebcdic_ii[] = + { 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 }; + short int ebcdic_mm[] = + { 0xC2C9, 0xC785, 0x95C4, 0x8981, 0x95E2, 0xA8E2, 0 }; + int use_ebcdic (int i) { + return ebcdic_mm[i] + ebcdic_ii[i]; + } + extern int foo; + +int +main () +{ +return use_ascii (foo) == use_ebcdic (foo); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + if grep BIGenDianSyS conftest.$ac_objext >/dev/null; then + ac_cv_c_bigendian=yes + fi + if grep LiTTleEnDian conftest.$ac_objext >/dev/null ; then + if test "$ac_cv_c_bigendian" = unknown; then + ac_cv_c_bigendian=no + else + # finding both strings is unlikely to happen, but who knows? + ac_cv_c_bigendian=unknown + fi + fi +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ + + /* Are we little or big endian? From Harbison&Steele. */ + union + { + long int l; + char c[sizeof (long int)]; + } u; + u.l = 1; + return u.c[sizeof (long int) - 1] == 1; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + ac_cv_c_bigendian=no +else + ac_cv_c_bigendian=yes +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_bigendian" >&5 +$as_echo "$ac_cv_c_bigendian" >&6; } + case $ac_cv_c_bigendian in #( + yes) + $as_echo "#define WORDS_BIGENDIAN 1" >>confdefs.h +;; #( + no) + ;; #( + universal) + +$as_echo "#define AC_APPLE_UNIVERSAL_BUILD 1" >>confdefs.h + + ;; #( + *) + as_fn_error $? "unknown endianness + presetting ac_cv_c_bigendian=no (or yes) will help" "$LINENO" 5 ;; + esac + + + +have_alsa=no +if test "x$with_alsa" != "xno"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for snd_pcm_open in -lasound" >&5 +$as_echo_n "checking for snd_pcm_open in -lasound... " >&6; } +if ${ac_cv_lib_asound_snd_pcm_open+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lasound $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char snd_pcm_open (); +int +main () +{ +return snd_pcm_open (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_asound_snd_pcm_open=yes +else + ac_cv_lib_asound_snd_pcm_open=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_asound_snd_pcm_open" >&5 +$as_echo "$ac_cv_lib_asound_snd_pcm_open" >&6; } +if test "x$ac_cv_lib_asound_snd_pcm_open" = xyes; then : + have_alsa=yes +else + have_alsa=no +fi + +fi +have_asihpi=no +if test "x$with_asihpi" != "xno"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for HPI_SubSysCreate in -lhpi" >&5 +$as_echo_n "checking for HPI_SubSysCreate in -lhpi... " >&6; } +if ${ac_cv_lib_hpi_HPI_SubSysCreate+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lhpi -lm $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char HPI_SubSysCreate (); +int +main () +{ +return HPI_SubSysCreate (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_hpi_HPI_SubSysCreate=yes +else + ac_cv_lib_hpi_HPI_SubSysCreate=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_hpi_HPI_SubSysCreate" >&5 +$as_echo "$ac_cv_lib_hpi_HPI_SubSysCreate" >&6; } +if test "x$ac_cv_lib_hpi_HPI_SubSysCreate" = xyes; then : + have_asihpi=yes +else + have_asihpi=no +fi + +fi +have_libossaudio=no +have_oss=no +if test "x$with_oss" != "xno"; then + for ac_header in sys/soundcard.h linux/soundcard.h machine/soundcard.h +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + have_oss=yes +fi + +done + + if test "x$have_oss" = "xyes"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _oss_ioctl in -lossaudio" >&5 +$as_echo_n "checking for _oss_ioctl in -lossaudio... " >&6; } +if ${ac_cv_lib_ossaudio__oss_ioctl+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lossaudio $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char _oss_ioctl (); +int +main () +{ +return _oss_ioctl (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_ossaudio__oss_ioctl=yes +else + ac_cv_lib_ossaudio__oss_ioctl=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ossaudio__oss_ioctl" >&5 +$as_echo "$ac_cv_lib_ossaudio__oss_ioctl" >&6; } +if test "x$ac_cv_lib_ossaudio__oss_ioctl" = xyes; then : + have_libossaudio=yes +else + have_libossaudio=no +fi + + fi +fi +have_jack=no +if test "x$with_jack" != "xno"; then + + + + + + + +if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args. +set dummy ${ac_tool_prefix}pkg-config; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_PKG_CONFIG+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $PKG_CONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +PKG_CONFIG=$ac_cv_path_PKG_CONFIG +if test -n "$PKG_CONFIG"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5 +$as_echo "$PKG_CONFIG" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_path_PKG_CONFIG"; then + ac_pt_PKG_CONFIG=$PKG_CONFIG + # Extract the first word of "pkg-config", so it can be a program name with args. +set dummy pkg-config; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_ac_pt_PKG_CONFIG+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $ac_pt_PKG_CONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_ac_pt_PKG_CONFIG="$ac_pt_PKG_CONFIG" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_ac_pt_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +ac_pt_PKG_CONFIG=$ac_cv_path_ac_pt_PKG_CONFIG +if test -n "$ac_pt_PKG_CONFIG"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKG_CONFIG" >&5 +$as_echo "$ac_pt_PKG_CONFIG" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_pt_PKG_CONFIG" = x; then + PKG_CONFIG="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + PKG_CONFIG=$ac_pt_PKG_CONFIG + fi +else + PKG_CONFIG="$ac_cv_path_PKG_CONFIG" +fi + +fi +if test -n "$PKG_CONFIG"; then + _pkg_min_version=0.9.0 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking pkg-config is at least version $_pkg_min_version" >&5 +$as_echo_n "checking pkg-config is at least version $_pkg_min_version... " >&6; } + if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + PKG_CONFIG="" + fi +fi + +pkg_failed=no +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for JACK" >&5 +$as_echo_n "checking for JACK... " >&6; } + +if test -n "$JACK_CFLAGS"; then + pkg_cv_JACK_CFLAGS="$JACK_CFLAGS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"jack\""; } >&5 + ($PKG_CONFIG --exists --print-errors "jack") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_JACK_CFLAGS=`$PKG_CONFIG --cflags "jack" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi +if test -n "$JACK_LIBS"; then + pkg_cv_JACK_LIBS="$JACK_LIBS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"jack\""; } >&5 + ($PKG_CONFIG --exists --print-errors "jack") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_JACK_LIBS=`$PKG_CONFIG --libs "jack" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi + + + +if test $pkg_failed = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + JACK_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "jack" 2>&1` + else + JACK_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "jack" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$JACK_PKG_ERRORS" >&5 + + have_jack=no +elif test $pkg_failed = untried; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + have_jack=no +else + JACK_CFLAGS=$pkg_cv_JACK_CFLAGS + JACK_LIBS=$pkg_cv_JACK_LIBS + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + have_jack=yes +fi +fi + + + +# The cast to long int works around a bug in the HP C Compiler +# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects +# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. +# This bug is HP SR number 8606223364. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of short" >&5 +$as_echo_n "checking size of short... " >&6; } +if ${ac_cv_sizeof_short+:} false; then : + $as_echo_n "(cached) " >&6 +else + if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (short))" "ac_cv_sizeof_short" "$ac_includes_default"; then : + +else + if test "$ac_cv_type_short" = yes; then + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error 77 "cannot compute sizeof (short) +See \`config.log' for more details" "$LINENO" 5; } + else + ac_cv_sizeof_short=0 + fi +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_short" >&5 +$as_echo "$ac_cv_sizeof_short" >&6; } + + + +cat >>confdefs.h <<_ACEOF +#define SIZEOF_SHORT $ac_cv_sizeof_short +_ACEOF + + +# The cast to long int works around a bug in the HP C Compiler +# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects +# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. +# This bug is HP SR number 8606223364. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of int" >&5 +$as_echo_n "checking size of int... " >&6; } +if ${ac_cv_sizeof_int+:} false; then : + $as_echo_n "(cached) " >&6 +else + if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (int))" "ac_cv_sizeof_int" "$ac_includes_default"; then : + +else + if test "$ac_cv_type_int" = yes; then + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error 77 "cannot compute sizeof (int) +See \`config.log' for more details" "$LINENO" 5; } + else + ac_cv_sizeof_int=0 + fi +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_int" >&5 +$as_echo "$ac_cv_sizeof_int" >&6; } + + + +cat >>confdefs.h <<_ACEOF +#define SIZEOF_INT $ac_cv_sizeof_int +_ACEOF + + +# The cast to long int works around a bug in the HP C Compiler +# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects +# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. +# This bug is HP SR number 8606223364. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of long" >&5 +$as_echo_n "checking size of long... " >&6; } +if ${ac_cv_sizeof_long+:} false; then : + $as_echo_n "(cached) " >&6 +else + if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (long))" "ac_cv_sizeof_long" "$ac_includes_default"; then : + +else + if test "$ac_cv_type_long" = yes; then + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error 77 "cannot compute sizeof (long) +See \`config.log' for more details" "$LINENO" 5; } + else + ac_cv_sizeof_long=0 + fi +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_long" >&5 +$as_echo "$ac_cv_sizeof_long" >&6; } + + + +cat >>confdefs.h <<_ACEOF +#define SIZEOF_LONG $ac_cv_sizeof_long +_ACEOF + + + +save_LIBS="${LIBS}" +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for clock_gettime in -lrt" >&5 +$as_echo_n "checking for clock_gettime in -lrt... " >&6; } +if ${ac_cv_lib_rt_clock_gettime+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lrt $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char clock_gettime (); +int +main () +{ +return clock_gettime (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_rt_clock_gettime=yes +else + ac_cv_lib_rt_clock_gettime=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_rt_clock_gettime" >&5 +$as_echo "$ac_cv_lib_rt_clock_gettime" >&6; } +if test "x$ac_cv_lib_rt_clock_gettime" = xyes; then : + rt_libs=" -lrt" +fi + +LIBS="${LIBS}${rt_libs}" +DLL_LIBS="${DLL_LIBS}${rt_libs}" +for ac_func in clock_gettime nanosleep +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + +LIBS="${save_LIBS}" + +LT_CURRENT=2 +LT_REVISION=0 +LT_AGE=0 + + + + + + + + + + + + + + + +if ( echo "${host_os}" | grep ^darwin >> /dev/null ) && + [ "$enable_mac_universal" = "yes" ] && + [ "$enable_mac_debug" != "yes" ] ; then + CFLAGS="-O2 -Wall -pedantic -pipe -fPIC -DNDEBUG" +else + CFLAGS=${CFLAGS:-"-g -O2 -Wall -pedantic -pipe -fPIC"} +fi + +if [ $ac_cv_c_bigendian = "yes" ] ; then + CFLAGS="$CFLAGS -DPA_BIG_ENDIAN" +else + CFLAGS="$CFLAGS -DPA_LITTLE_ENDIAN" +fi + +add_objects() +{ + for o in $@; do + test "${OTHER_OBJS#*${o}*}" = "${OTHER_OBJS}" && OTHER_OBJS="$OTHER_OBJS $o" + done +} + +INCLUDES=portaudio.h + +CFLAGS="$CFLAGS -I\$(top_srcdir)/include -I\$(top_srcdir)/src/common" + +case "${host_os}" in + darwin* ) + + $as_echo "#define PA_USE_COREAUDIO 1" >>confdefs.h + + + CFLAGS="$CFLAGS -I\$(top_srcdir)/src/os/unix -Wno-deprecated -Werror" + LIBS="-framework CoreAudio -framework AudioToolbox -framework AudioUnit -framework Carbon" + + if test "x$enable_mac_universal" = "xyes" ; then + case `xcodebuild -version | sed -n 's/Xcode \(.*\)/\1/p'` in + + 12*|3.0|3.1) + if [ -d /Developer/SDKs/MacOSX10.5.sdk ] ; then + mac_version_min="-mmacosx-version-min=10.3" + mac_sysroot="-isysroot /Developer/SDKs/MacOSX10.5.sdk" + else + mac_version_min="-mmacosx-version-min=10.3" + mac_sysroot="-isysroot /Developer/SDKs/MacOSX10.4u.sdk" + fi + ;; + + *) + if xcodebuild -version -sdk macosx10.5 Path >/dev/null 2>&1 ; then + mac_version_min="-mmacosx-version-min=10.3" + mac_sysroot="-isysroot `xcodebuild -version -sdk macosx10.5 Path`" + elif xcodebuild -version -sdk macosx10.6 Path >/dev/null 2>&1 ; then + mac_version_min="-mmacosx-version-min=10.4" + mac_sysroot="-isysroot `xcodebuild -version -sdk macosx10.6 Path`" + elif xcodebuild -version -sdk macosx10.7 Path >/dev/null 2>&1 ; then + mac_version_min="-mmacosx-version-min=10.4" + mac_sysroot="-isysroot `xcodebuild -version -sdk macosx10.7 Path`" + elif xcodebuild -version -sdk macosx10.8 Path >/dev/null 2>&1 ; then + mac_version_min="-mmacosx-version-min=10.4" + mac_sysroot="-isysroot `xcodebuild -version -sdk macosx10.8 Path`" + elif xcodebuild -version -sdk macosx10.9 Path >/dev/null 2>&1 ; then + mac_version_min="-mmacosx-version-min=10.4" + mac_sysroot="-isysroot `xcodebuild -version -sdk macosx10.9 Path`" + elif xcodebuild -version -sdk macosx10.10 Path >/dev/null 2>&1 ; then + mac_version_min="-mmacosx-version-min=10.4" + mac_sysroot="-isysroot `xcodebuild -version -sdk macosx10.10 Path`" + elif xcodebuild -version -sdk macosx10.11 Path >/dev/null 2>&1 ; then + mac_version_min="-mmacosx-version-min=10.4" + mac_sysroot="-isysroot `xcodebuild -version -sdk macosx10.11 Path`" + elif xcodebuild -version -sdk macosx10.12 Path >/dev/null 2>&1 ; then + mac_version_min="-mmacosx-version-min=10.4" + mac_sysroot="-isysroot `xcodebuild -version -sdk macosx10.12 Path`" + elif xcodebuild -version -sdk macosx10.13 Path >/dev/null 2>&1 ; then + mac_version_min="-mmacosx-version-min=10.4" + mac_sysroot="-isysroot `xcodebuild -version -sdk macosx10.13 Path`" + else + as_fn_error $? "Could not find 10.5 to 10.13 SDK." "$LINENO" 5 + fi + esac + + mac_arches="" + for arch in i386 x86_64 ppc ppc64 + do + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -arch $arch" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + + if [ -z "$mac_arches" ] ; then + mac_arches="-arch $arch" + else + mac_arches="$mac_arches -arch $arch" + fi + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + CFLAGS="$save_CFLAGS" + done + else + mac_arches="" + mac_sysroot="" + mac_version="" + fi + SHARED_FLAGS="$LIBS -dynamiclib $mac_arches $mac_sysroot $mac_version_min" + CFLAGS="-std=c99 $CFLAGS $mac_arches $mac_sysroot $mac_version_min" + OTHER_OBJS="src/os/unix/pa_unix_hostapis.o src/os/unix/pa_unix_util.o src/hostapi/coreaudio/pa_mac_core.o src/hostapi/coreaudio/pa_mac_core_utilities.o src/hostapi/coreaudio/pa_mac_core_blocking.o src/common/pa_ringbuffer.o" + PADLL="libportaudio.dylib" + ;; + + mingw* ) + + PADLL="portaudio.dll" + THREAD_CFLAGS="-mthreads" + SHARED_FLAGS="-shared" + CFLAGS="$CFLAGS -I\$(top_srcdir)/src/os/win -DPA_USE_WMME=0 -DPA_USE_ASIO=0 -DPA_USE_WDMKS=0 -DPA_USE_DS=0 -DPA_USE_WASAPI=0" + + if [ "x$with_directx" = "xyes" ]; then + DXDIR="$with_dxdir" + add_objects src/hostapi/dsound/pa_win_ds.o src/hostapi/dsound/pa_win_ds_dynlink.o src/os/win/pa_win_hostapis.o src/os/win/pa_win_util.o src/os/win/pa_win_coinitialize.o src/os/win/pa_win_waveformat.o + LIBS="${LIBS} -lwinmm -lm -ldsound -lole32" + DLL_LIBS="${DLL_LIBS} -lwinmm -lm -L$DXDIR/lib -ldsound -lole32" + #VC98="\"/c/Program Files/Microsoft Visual Studio/VC98/Include\"" + #CFLAGS="$CFLAGS -I$VC98 -DPA_NO_WMME -DPA_NO_ASIO" + CFLAGS="$CFLAGS -I$DXDIR/include -UPA_USE_DS -DPA_USE_DS=1" + fi + + if [ "x$with_asio" = "xyes" ]; then + ASIODIR="$with_asiodir" + add_objects src/hostapi/asio/pa_asio.o src/common/pa_ringbuffer.o src/os/win/pa_win_hostapis.o src/os/win/pa_win_util.o src/os/win/pa_win_coinitialize.o src/hostapi/asio/iasiothiscallresolver.o $ASIODIR/common/asio.o $ASIODIR/host/asiodrivers.o $ASIODIR/host/pc/asiolist.o + LIBS="${LIBS} -lwinmm -lm -lole32 -luuid" + DLL_LIBS="${DLL_LIBS} -lwinmm -lm -lole32 -luuid" + CFLAGS="$CFLAGS -ffast-math -fomit-frame-pointer -I\$(top_srcdir)/src/hostapi/asio -I$ASIODIR/host/pc -I$ASIODIR/common -I$ASIODIR/host -UPA_USE_ASIO -DPA_USE_ASIO=1 -DWINDOWS" + + CFLAGS="$CFLAGS -D_WIN32_WINNT=0x0501 -DWINVER=0x0501" + + CXXFLAGS="$CFLAGS" + fi + + if [ "x$with_wdmks" = "xyes" ]; then + DXDIR="$with_dxdir" + add_objects src/hostapi/wdmks/pa_win_wdmks.o src/common/pa_ringbuffer.o src/os/win/pa_win_hostapis.o src/os/win/pa_win_util.o src/os/win/pa_win_wdmks_utils.o src/os/win/pa_win_waveformat.o + LIBS="${LIBS} -lwinmm -lm -luuid -lsetupapi -lole32" + DLL_LIBS="${DLL_LIBS} -lwinmm -lm -L$DXDIR/lib -luuid -lsetupapi -lole32" + #VC98="\"/c/Program Files/Microsoft Visual Studio/VC98/Include\"" + #CFLAGS="$CFLAGS -I$VC98 -DPA_NO_WMME -DPA_NO_ASIO" + CFLAGS="$CFLAGS -I$DXDIR/include -UPA_USE_WDMKS -DPA_USE_WDMKS=1" + fi + + if [ "x$with_wmme" = "xyes" ]; then + add_objects src/hostapi/wmme/pa_win_wmme.o src/os/win/pa_win_hostapis.o src/os/win/pa_win_util.o src/os/win/pa_win_waveformat.o + LIBS="${LIBS} -lwinmm -lm -lole32 -luuid" + DLL_LIBS="${DLL_LIBS} -lwinmm" + CFLAGS="$CFLAGS -UPA_USE_WMME -DPA_USE_WMME=1" + fi + + if [ "x$with_wasapi" = "xyes" ]; then + add_objects src/hostapi/wasapi/pa_win_wasapi.o src/common/pa_ringbuffer.o src/os/win/pa_win_hostapis.o src/os/win/pa_win_util.o src/os/win/pa_win_coinitialize.o src/os/win/pa_win_waveformat.o + LIBS="${LIBS} -lwinmm -lm -lole32 -luuid" + DLL_LIBS="${DLL_LIBS} -lwinmm -lole32" + CFLAGS="$CFLAGS -I\$(top_srcdir)/src/hostapi/wasapi/mingw-include -UPA_USE_WASAPI -DPA_USE_WASAPI=1" + fi + ;; + + cygwin* ) + + OTHER_OBJS="src/hostapi/wmme/pa_win_wmme.o src/os/win/pa_win_hostapis.o src/os/win/pa_win_util.o src/os/win/pa_win_waveformat.o" + CFLAGS="$CFLAGS -I\$(top_srcdir)/src/os/win -DPA_USE_DS=0 -DPA_USE_WDMKS=0 -DPA_USE_ASIO=0 -DPA_USE_WASAPI=0 -DPA_USE_WMME=1" + LIBS="-lwinmm -lm" + PADLL="portaudio.dll" + THREAD_CFLAGS="-mthreads" + SHARED_FLAGS="-shared" + DLL_LIBS="${DLL_LIBS} -lwinmm" + ;; + + irix* ) + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_create in -lpthread" >&5 +$as_echo_n "checking for pthread_create in -lpthread... " >&6; } +if ${ac_cv_lib_pthread_pthread_create+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lpthread $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char pthread_create (); +int +main () +{ +return pthread_create (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_pthread_pthread_create=yes +else + ac_cv_lib_pthread_pthread_create=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread_pthread_create" >&5 +$as_echo "$ac_cv_lib_pthread_pthread_create" >&6; } +if test "x$ac_cv_lib_pthread_pthread_create" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBPTHREAD 1 +_ACEOF + + LIBS="-lpthread $LIBS" + +else + as_fn_error $? "IRIX posix thread library not found!" "$LINENO" 5 +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for alOpenPort in -laudio" >&5 +$as_echo_n "checking for alOpenPort in -laudio... " >&6; } +if ${ac_cv_lib_audio_alOpenPort+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-laudio $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char alOpenPort (); +int +main () +{ +return alOpenPort (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_audio_alOpenPort=yes +else + ac_cv_lib_audio_alOpenPort=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_audio_alOpenPort" >&5 +$as_echo "$ac_cv_lib_audio_alOpenPort" >&6; } +if test "x$ac_cv_lib_audio_alOpenPort" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBAUDIO 1 +_ACEOF + + LIBS="-laudio $LIBS" + +else + as_fn_error $? "IRIX audio library not found!" "$LINENO" 5 +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dmGetUST in -ldmedia" >&5 +$as_echo_n "checking for dmGetUST in -ldmedia... " >&6; } +if ${ac_cv_lib_dmedia_dmGetUST+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldmedia $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dmGetUST (); +int +main () +{ +return dmGetUST (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_dmedia_dmGetUST=yes +else + ac_cv_lib_dmedia_dmGetUST=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dmedia_dmGetUST" >&5 +$as_echo "$ac_cv_lib_dmedia_dmGetUST" >&6; } +if test "x$ac_cv_lib_dmedia_dmGetUST" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBDMEDIA 1 +_ACEOF + + LIBS="-ldmedia $LIBS" + +else + as_fn_error $? "IRIX digital media library not found!" "$LINENO" 5 +fi + + + $as_echo "#define PA_USE_SGI 1" >>confdefs.h + + + CFLAGS="$CFLAGS -I\$(top_srcdir)/src/os/unix" + + THREAD_CFLAGS="-D_REENTRANT" + + OTHER_OBJS="pa_sgi/pa_sgi.o src/os/unix/pa_unix_hostapis.o src/os/unix/pa_unix_util.o" + + LIBS="-lm -ldmedia -laudio -lpthread" + PADLL="libportaudio.so" + SHARED_FLAGS="" + ;; + + *) + + CFLAGS="$CFLAGS -I\$(top_srcdir)/src/os/unix" + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_create in -lpthread" >&5 +$as_echo_n "checking for pthread_create in -lpthread... " >&6; } +if ${ac_cv_lib_pthread_pthread_create+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lpthread $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char pthread_create (); +int +main () +{ +return pthread_create (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_pthread_pthread_create=yes +else + ac_cv_lib_pthread_pthread_create=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread_pthread_create" >&5 +$as_echo "$ac_cv_lib_pthread_pthread_create" >&6; } +if test "x$ac_cv_lib_pthread_pthread_create" = xyes; then : + have_pthread="yes" +else + as_fn_error $? "libpthread not found!" "$LINENO" 5 +fi + + + if [ "$have_alsa" = "yes" ] && [ "$with_alsa" != "no" ] ; then + DLL_LIBS="$DLL_LIBS -lasound" + LIBS="$LIBS -lasound" + OTHER_OBJS="$OTHER_OBJS src/hostapi/alsa/pa_linux_alsa.o" + INCLUDES="$INCLUDES pa_linux_alsa.h" + $as_echo "#define PA_USE_ALSA 1" >>confdefs.h + + fi + + if [ "$have_jack" = "yes" ] && [ "$with_jack" != "no" ] ; then + DLL_LIBS="$DLL_LIBS $JACK_LIBS" + CFLAGS="$CFLAGS $JACK_CFLAGS" + OTHER_OBJS="$OTHER_OBJS src/hostapi/jack/pa_jack.o src/common/pa_ringbuffer.o" + INCLUDES="$INCLUDES pa_jack.h" + $as_echo "#define PA_USE_JACK 1" >>confdefs.h + + fi + + if [ "$with_oss" != "no" ] ; then + OTHER_OBJS="$OTHER_OBJS src/hostapi/oss/pa_unix_oss.o" + if [ "$have_libossaudio" = "yes" ] ; then + DLL_LIBS="$DLL_LIBS -lossaudio" + LIBS="$LIBS -lossaudio" + fi + $as_echo "#define PA_USE_OSS 1" >>confdefs.h + + fi + + if [ "$have_asihpi" = "yes" ] && [ "$with_asihpi" != "no" ] ; then + LIBS="$LIBS -lhpi" + DLL_LIBS="$DLL_LIBS -lhpi" + OTHER_OBJS="$OTHER_OBJS src/hostapi/asihpi/pa_linux_asihpi.o" + $as_echo "#define PA_USE_ASIHPI 1" >>confdefs.h + + fi + + DLL_LIBS="$DLL_LIBS -lm -lpthread" + LIBS="$LIBS -lm -lpthread" + PADLL="libportaudio.so" + + ## support sun cc compiler flags + case "${host_os}" in + solaris*) + SHARED_FLAGS="-G" + THREAD_CFLAGS="-mt" + ;; + *) + SHARED_FLAGS="-fPIC" + THREAD_CFLAGS="-pthread" + ;; + esac + + OTHER_OBJS="$OTHER_OBJS src/os/unix/pa_unix_hostapis.o src/os/unix/pa_unix_util.o" +esac +CFLAGS="$CFLAGS $THREAD_CFLAGS" + +test "$enable_shared" != "yes" && SHARED_FLAGS="" + +if test "$enable_cxx" = "yes"; then + + +subdirs="$subdirs bindings/cpp" + + ENABLE_CXX_TRUE="" + ENABLE_CXX_FALSE="#" +else + ENABLE_CXX_TRUE="#" + ENABLE_CXX_FALSE="" +fi + + + +if test "x$with_asio" = "xyes"; then + WITH_ASIO_TRUE="" + WITH_ASIO_FALSE="@ #" +else + WITH_ASIO_TRUE="@ #" + WITH_ASIO_FALSE="" +fi + + + +ac_config_files="$ac_config_files Makefile portaudio-2.0.pc" + +cat >confcache <<\_ACEOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs, see configure's option --config-cache. +# It is not useful on other systems. If it contains results you don't +# want to keep, you may remove or edit it. +# +# config.status only pays attention to the cache file if you give it +# the --recheck option to rerun configure. +# +# `ac_cv_env_foo' variables (set or unset) will be overridden when +# loading this file, other *unset* `ac_cv_foo' will be assigned the +# following values. + +_ACEOF + +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, we kill variables containing newlines. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +( + for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done + + (set) 2>&1 | + case $as_nl`(ac_space=' '; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + # `set' does not quote correctly, so add quotes: double-quote + # substitution turns \\\\ into \\, and sed turns \\ into \. + sed -n \ + "s/'/'\\\\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" + ;; #( + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) | + sed ' + /^ac_cv_env_/b end + t clear + :clear + s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + t end + s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ + :end' >>confcache +if diff "$cache_file" confcache >/dev/null 2>&1; then :; else + if test -w "$cache_file"; then + if test "x$cache_file" != "x/dev/null"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 +$as_echo "$as_me: updating cache $cache_file" >&6;} + if test ! -f "$cache_file" || test -h "$cache_file"; then + cat confcache >"$cache_file" + else + case $cache_file in #( + */* | ?:*) + mv -f confcache "$cache_file"$$ && + mv -f "$cache_file"$$ "$cache_file" ;; #( + *) + mv -f confcache "$cache_file" ;; + esac + fi + fi + else + { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 +$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} + fi +fi +rm -f confcache + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +# Transform confdefs.h into DEFS. +# Protect against shell expansion while executing Makefile rules. +# Protect against Makefile macro expansion. +# +# If the first sed substitution is executed (which looks for macros that +# take arguments), then branch to the quote section. Otherwise, +# look for a macro that doesn't take arguments. +ac_script=' +:mline +/\\$/{ + N + s,\\\n,, + b mline +} +t clear +:clear +s/^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\)/-D\1=\2/g +t quote +s/^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)/-D\1=\2/g +t quote +b any +:quote +s/[ `~#$^&*(){}\\|;'\''"<>?]/\\&/g +s/\[/\\&/g +s/\]/\\&/g +s/\$/$$/g +H +:any +${ + g + s/^\n// + s/\n/ /g + p +} +' +DEFS=`sed -n "$ac_script" confdefs.h` + + +ac_libobjs= +ac_ltlibobjs= +U= +for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue + # 1. Remove the extension, and $U if already installed. + ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' + ac_i=`$as_echo "$ac_i" | sed "$ac_script"` + # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR + # will be set to the directory where LIBOBJS objects are built. + as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" + as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' +done +LIBOBJS=$ac_libobjs + +LTLIBOBJS=$ac_ltlibobjs + + + + +: "${CONFIG_STATUS=./config.status}" +ac_write_fail=0 +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files $CONFIG_STATUS" +{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 +$as_echo "$as_me: creating $CONFIG_STATUS" >&6;} +as_write_fail=0 +cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 +#! $SHELL +# Generated by $as_me. +# Run this file to recreate the current configuration. +# Compiler output produced by configure, useful for debugging +# configure, is in config.log if it exists. + +debug=false +ac_cs_recheck=false +ac_cs_silent=false + +SHELL=\${CONFIG_SHELL-$SHELL} +export SHELL +_ASEOF +cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +as_myself= +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + + +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with STATUS, using 1 if that was 0. +as_fn_error () +{ + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + fi + $as_echo "$as_me: error: $2" >&2 + as_fn_exit $as_status +} # as_fn_error + + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -pR'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -pR' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -pR' + fi +else + as_ln_s='cp -pR' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" + + +} # as_fn_mkdir_p +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + + +# as_fn_executable_p FILE +# ----------------------- +# Test if FILE is an executable regular file. +as_fn_executable_p () +{ + test -f "$1" && test -x "$1" +} # as_fn_executable_p +as_test_x='test -x' +as_executable_p=as_fn_executable_p + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +exec 6>&1 +## ----------------------------------- ## +## Main body of $CONFIG_STATUS script. ## +## ----------------------------------- ## +_ASEOF +test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# Save the log message, to keep $0 and so on meaningful, and to +# report actual input values of CONFIG_FILES etc. instead of their +# values after options handling. +ac_log=" +This file was extended by $as_me, which was +generated by GNU Autoconf 2.69. Invocation command line was + + CONFIG_FILES = $CONFIG_FILES + CONFIG_HEADERS = $CONFIG_HEADERS + CONFIG_LINKS = $CONFIG_LINKS + CONFIG_COMMANDS = $CONFIG_COMMANDS + $ $0 $@ + +on `(hostname || uname -n) 2>/dev/null | sed 1q` +" + +_ACEOF + +case $ac_config_files in *" +"*) set x $ac_config_files; shift; ac_config_files=$*;; +esac + + + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +# Files that config.status was made for. +config_files="$ac_config_files" +config_commands="$ac_config_commands" + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +ac_cs_usage="\ +\`$as_me' instantiates files and other configuration actions +from templates according to the current configuration. Unless the files +and actions are specified as TAGs, all are instantiated by default. + +Usage: $0 [OPTION]... [TAG]... + + -h, --help print this help, then exit + -V, --version print version number and configuration settings, then exit + --config print configuration, then exit + -q, --quiet, --silent + do not print progress messages + -d, --debug don't remove temporary files + --recheck update $as_me by reconfiguring in the same conditions + --file=FILE[:TEMPLATE] + instantiate the configuration file FILE + +Configuration files: +$config_files + +Configuration commands: +$config_commands + +Report bugs to the package provider." + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" +ac_cs_version="\\ +config.status +configured by $0, generated by GNU Autoconf 2.69, + with options \\"\$ac_cs_config\\" + +Copyright (C) 2012 Free Software Foundation, Inc. +This config.status script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it." + +ac_pwd='$ac_pwd' +srcdir='$srcdir' +INSTALL='$INSTALL' +AWK='$AWK' +test -n "\$AWK" || AWK=awk +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# The default lists apply if the user does not specify any file. +ac_need_defaults=: +while test $# != 0 +do + case $1 in + --*=?*) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` + ac_shift=: + ;; + --*=) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg= + ac_shift=: + ;; + *) + ac_option=$1 + ac_optarg=$2 + ac_shift=shift + ;; + esac + + case $ac_option in + # Handling of the options. + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + ac_cs_recheck=: ;; + --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) + $as_echo "$ac_cs_version"; exit ;; + --config | --confi | --conf | --con | --co | --c ) + $as_echo "$ac_cs_config"; exit ;; + --debug | --debu | --deb | --de | --d | -d ) + debug=: ;; + --file | --fil | --fi | --f ) + $ac_shift + case $ac_optarg in + *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + '') as_fn_error $? "missing file argument" ;; + esac + as_fn_append CONFIG_FILES " '$ac_optarg'" + ac_need_defaults=false;; + --he | --h | --help | --hel | -h ) + $as_echo "$ac_cs_usage"; exit ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil | --si | --s) + ac_cs_silent=: ;; + + # This is an error. + -*) as_fn_error $? "unrecognized option: \`$1' +Try \`$0 --help' for more information." ;; + + *) as_fn_append ac_config_targets " $1" + ac_need_defaults=false ;; + + esac + shift +done + +ac_configure_extra_args= + +if $ac_cs_silent; then + exec 6>/dev/null + ac_configure_extra_args="$ac_configure_extra_args --silent" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +if \$ac_cs_recheck; then + set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion + shift + \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 + CONFIG_SHELL='$SHELL' + export CONFIG_SHELL + exec "\$@" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +exec 5>>config.log +{ + echo + sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX +## Running $as_me. ## +_ASBOX + $as_echo "$ac_log" +} >&5 + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +# +# INIT-COMMANDS +# + + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +sed_quote_subst='$sed_quote_subst' +double_quote_subst='$double_quote_subst' +delay_variable_subst='$delay_variable_subst' +AS='`$ECHO "$AS" | $SED "$delay_single_quote_subst"`' +DLLTOOL='`$ECHO "$DLLTOOL" | $SED "$delay_single_quote_subst"`' +OBJDUMP='`$ECHO "$OBJDUMP" | $SED "$delay_single_quote_subst"`' +macro_version='`$ECHO "$macro_version" | $SED "$delay_single_quote_subst"`' +macro_revision='`$ECHO "$macro_revision" | $SED "$delay_single_quote_subst"`' +enable_shared='`$ECHO "$enable_shared" | $SED "$delay_single_quote_subst"`' +enable_static='`$ECHO "$enable_static" | $SED "$delay_single_quote_subst"`' +pic_mode='`$ECHO "$pic_mode" | $SED "$delay_single_quote_subst"`' +enable_fast_install='`$ECHO "$enable_fast_install" | $SED "$delay_single_quote_subst"`' +SHELL='`$ECHO "$SHELL" | $SED "$delay_single_quote_subst"`' +ECHO='`$ECHO "$ECHO" | $SED "$delay_single_quote_subst"`' +PATH_SEPARATOR='`$ECHO "$PATH_SEPARATOR" | $SED "$delay_single_quote_subst"`' +host_alias='`$ECHO "$host_alias" | $SED "$delay_single_quote_subst"`' +host='`$ECHO "$host" | $SED "$delay_single_quote_subst"`' +host_os='`$ECHO "$host_os" | $SED "$delay_single_quote_subst"`' +build_alias='`$ECHO "$build_alias" | $SED "$delay_single_quote_subst"`' +build='`$ECHO "$build" | $SED "$delay_single_quote_subst"`' +build_os='`$ECHO "$build_os" | $SED "$delay_single_quote_subst"`' +SED='`$ECHO "$SED" | $SED "$delay_single_quote_subst"`' +Xsed='`$ECHO "$Xsed" | $SED "$delay_single_quote_subst"`' +GREP='`$ECHO "$GREP" | $SED "$delay_single_quote_subst"`' +EGREP='`$ECHO "$EGREP" | $SED "$delay_single_quote_subst"`' +FGREP='`$ECHO "$FGREP" | $SED "$delay_single_quote_subst"`' +LD='`$ECHO "$LD" | $SED "$delay_single_quote_subst"`' +NM='`$ECHO "$NM" | $SED "$delay_single_quote_subst"`' +LN_S='`$ECHO "$LN_S" | $SED "$delay_single_quote_subst"`' +max_cmd_len='`$ECHO "$max_cmd_len" | $SED "$delay_single_quote_subst"`' +ac_objext='`$ECHO "$ac_objext" | $SED "$delay_single_quote_subst"`' +exeext='`$ECHO "$exeext" | $SED "$delay_single_quote_subst"`' +lt_unset='`$ECHO "$lt_unset" | $SED "$delay_single_quote_subst"`' +lt_SP2NL='`$ECHO "$lt_SP2NL" | $SED "$delay_single_quote_subst"`' +lt_NL2SP='`$ECHO "$lt_NL2SP" | $SED "$delay_single_quote_subst"`' +lt_cv_to_host_file_cmd='`$ECHO "$lt_cv_to_host_file_cmd" | $SED "$delay_single_quote_subst"`' +lt_cv_to_tool_file_cmd='`$ECHO "$lt_cv_to_tool_file_cmd" | $SED "$delay_single_quote_subst"`' +reload_flag='`$ECHO "$reload_flag" | $SED "$delay_single_quote_subst"`' +reload_cmds='`$ECHO "$reload_cmds" | $SED "$delay_single_quote_subst"`' +deplibs_check_method='`$ECHO "$deplibs_check_method" | $SED "$delay_single_quote_subst"`' +file_magic_cmd='`$ECHO "$file_magic_cmd" | $SED "$delay_single_quote_subst"`' +file_magic_glob='`$ECHO "$file_magic_glob" | $SED "$delay_single_quote_subst"`' +want_nocaseglob='`$ECHO "$want_nocaseglob" | $SED "$delay_single_quote_subst"`' +sharedlib_from_linklib_cmd='`$ECHO "$sharedlib_from_linklib_cmd" | $SED "$delay_single_quote_subst"`' +AR='`$ECHO "$AR" | $SED "$delay_single_quote_subst"`' +AR_FLAGS='`$ECHO "$AR_FLAGS" | $SED "$delay_single_quote_subst"`' +archiver_list_spec='`$ECHO "$archiver_list_spec" | $SED "$delay_single_quote_subst"`' +STRIP='`$ECHO "$STRIP" | $SED "$delay_single_quote_subst"`' +RANLIB='`$ECHO "$RANLIB" | $SED "$delay_single_quote_subst"`' +old_postinstall_cmds='`$ECHO "$old_postinstall_cmds" | $SED "$delay_single_quote_subst"`' +old_postuninstall_cmds='`$ECHO "$old_postuninstall_cmds" | $SED "$delay_single_quote_subst"`' +old_archive_cmds='`$ECHO "$old_archive_cmds" | $SED "$delay_single_quote_subst"`' +lock_old_archive_extraction='`$ECHO "$lock_old_archive_extraction" | $SED "$delay_single_quote_subst"`' +CC='`$ECHO "$CC" | $SED "$delay_single_quote_subst"`' +CFLAGS='`$ECHO "$CFLAGS" | $SED "$delay_single_quote_subst"`' +compiler='`$ECHO "$compiler" | $SED "$delay_single_quote_subst"`' +GCC='`$ECHO "$GCC" | $SED "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_pipe='`$ECHO "$lt_cv_sys_global_symbol_pipe" | $SED "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_to_cdecl='`$ECHO "$lt_cv_sys_global_symbol_to_cdecl" | $SED "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_to_c_name_address='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address" | $SED "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_to_c_name_address_lib_prefix='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address_lib_prefix" | $SED "$delay_single_quote_subst"`' +nm_file_list_spec='`$ECHO "$nm_file_list_spec" | $SED "$delay_single_quote_subst"`' +lt_sysroot='`$ECHO "$lt_sysroot" | $SED "$delay_single_quote_subst"`' +objdir='`$ECHO "$objdir" | $SED "$delay_single_quote_subst"`' +MAGIC_CMD='`$ECHO "$MAGIC_CMD" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_no_builtin_flag='`$ECHO "$lt_prog_compiler_no_builtin_flag" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_pic='`$ECHO "$lt_prog_compiler_pic" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_wl='`$ECHO "$lt_prog_compiler_wl" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_static='`$ECHO "$lt_prog_compiler_static" | $SED "$delay_single_quote_subst"`' +lt_cv_prog_compiler_c_o='`$ECHO "$lt_cv_prog_compiler_c_o" | $SED "$delay_single_quote_subst"`' +need_locks='`$ECHO "$need_locks" | $SED "$delay_single_quote_subst"`' +MANIFEST_TOOL='`$ECHO "$MANIFEST_TOOL" | $SED "$delay_single_quote_subst"`' +DSYMUTIL='`$ECHO "$DSYMUTIL" | $SED "$delay_single_quote_subst"`' +NMEDIT='`$ECHO "$NMEDIT" | $SED "$delay_single_quote_subst"`' +LIPO='`$ECHO "$LIPO" | $SED "$delay_single_quote_subst"`' +OTOOL='`$ECHO "$OTOOL" | $SED "$delay_single_quote_subst"`' +OTOOL64='`$ECHO "$OTOOL64" | $SED "$delay_single_quote_subst"`' +libext='`$ECHO "$libext" | $SED "$delay_single_quote_subst"`' +shrext_cmds='`$ECHO "$shrext_cmds" | $SED "$delay_single_quote_subst"`' +extract_expsyms_cmds='`$ECHO "$extract_expsyms_cmds" | $SED "$delay_single_quote_subst"`' +archive_cmds_need_lc='`$ECHO "$archive_cmds_need_lc" | $SED "$delay_single_quote_subst"`' +enable_shared_with_static_runtimes='`$ECHO "$enable_shared_with_static_runtimes" | $SED "$delay_single_quote_subst"`' +export_dynamic_flag_spec='`$ECHO "$export_dynamic_flag_spec" | $SED "$delay_single_quote_subst"`' +whole_archive_flag_spec='`$ECHO "$whole_archive_flag_spec" | $SED "$delay_single_quote_subst"`' +compiler_needs_object='`$ECHO "$compiler_needs_object" | $SED "$delay_single_quote_subst"`' +old_archive_from_new_cmds='`$ECHO "$old_archive_from_new_cmds" | $SED "$delay_single_quote_subst"`' +old_archive_from_expsyms_cmds='`$ECHO "$old_archive_from_expsyms_cmds" | $SED "$delay_single_quote_subst"`' +archive_cmds='`$ECHO "$archive_cmds" | $SED "$delay_single_quote_subst"`' +archive_expsym_cmds='`$ECHO "$archive_expsym_cmds" | $SED "$delay_single_quote_subst"`' +module_cmds='`$ECHO "$module_cmds" | $SED "$delay_single_quote_subst"`' +module_expsym_cmds='`$ECHO "$module_expsym_cmds" | $SED "$delay_single_quote_subst"`' +with_gnu_ld='`$ECHO "$with_gnu_ld" | $SED "$delay_single_quote_subst"`' +allow_undefined_flag='`$ECHO "$allow_undefined_flag" | $SED "$delay_single_quote_subst"`' +no_undefined_flag='`$ECHO "$no_undefined_flag" | $SED "$delay_single_quote_subst"`' +hardcode_libdir_flag_spec='`$ECHO "$hardcode_libdir_flag_spec" | $SED "$delay_single_quote_subst"`' +hardcode_libdir_separator='`$ECHO "$hardcode_libdir_separator" | $SED "$delay_single_quote_subst"`' +hardcode_direct='`$ECHO "$hardcode_direct" | $SED "$delay_single_quote_subst"`' +hardcode_direct_absolute='`$ECHO "$hardcode_direct_absolute" | $SED "$delay_single_quote_subst"`' +hardcode_minus_L='`$ECHO "$hardcode_minus_L" | $SED "$delay_single_quote_subst"`' +hardcode_shlibpath_var='`$ECHO "$hardcode_shlibpath_var" | $SED "$delay_single_quote_subst"`' +hardcode_automatic='`$ECHO "$hardcode_automatic" | $SED "$delay_single_quote_subst"`' +inherit_rpath='`$ECHO "$inherit_rpath" | $SED "$delay_single_quote_subst"`' +link_all_deplibs='`$ECHO "$link_all_deplibs" | $SED "$delay_single_quote_subst"`' +always_export_symbols='`$ECHO "$always_export_symbols" | $SED "$delay_single_quote_subst"`' +export_symbols_cmds='`$ECHO "$export_symbols_cmds" | $SED "$delay_single_quote_subst"`' +exclude_expsyms='`$ECHO "$exclude_expsyms" | $SED "$delay_single_quote_subst"`' +include_expsyms='`$ECHO "$include_expsyms" | $SED "$delay_single_quote_subst"`' +prelink_cmds='`$ECHO "$prelink_cmds" | $SED "$delay_single_quote_subst"`' +postlink_cmds='`$ECHO "$postlink_cmds" | $SED "$delay_single_quote_subst"`' +file_list_spec='`$ECHO "$file_list_spec" | $SED "$delay_single_quote_subst"`' +variables_saved_for_relink='`$ECHO "$variables_saved_for_relink" | $SED "$delay_single_quote_subst"`' +need_lib_prefix='`$ECHO "$need_lib_prefix" | $SED "$delay_single_quote_subst"`' +need_version='`$ECHO "$need_version" | $SED "$delay_single_quote_subst"`' +version_type='`$ECHO "$version_type" | $SED "$delay_single_quote_subst"`' +runpath_var='`$ECHO "$runpath_var" | $SED "$delay_single_quote_subst"`' +shlibpath_var='`$ECHO "$shlibpath_var" | $SED "$delay_single_quote_subst"`' +shlibpath_overrides_runpath='`$ECHO "$shlibpath_overrides_runpath" | $SED "$delay_single_quote_subst"`' +libname_spec='`$ECHO "$libname_spec" | $SED "$delay_single_quote_subst"`' +library_names_spec='`$ECHO "$library_names_spec" | $SED "$delay_single_quote_subst"`' +soname_spec='`$ECHO "$soname_spec" | $SED "$delay_single_quote_subst"`' +install_override_mode='`$ECHO "$install_override_mode" | $SED "$delay_single_quote_subst"`' +postinstall_cmds='`$ECHO "$postinstall_cmds" | $SED "$delay_single_quote_subst"`' +postuninstall_cmds='`$ECHO "$postuninstall_cmds" | $SED "$delay_single_quote_subst"`' +finish_cmds='`$ECHO "$finish_cmds" | $SED "$delay_single_quote_subst"`' +finish_eval='`$ECHO "$finish_eval" | $SED "$delay_single_quote_subst"`' +hardcode_into_libs='`$ECHO "$hardcode_into_libs" | $SED "$delay_single_quote_subst"`' +sys_lib_search_path_spec='`$ECHO "$sys_lib_search_path_spec" | $SED "$delay_single_quote_subst"`' +sys_lib_dlsearch_path_spec='`$ECHO "$sys_lib_dlsearch_path_spec" | $SED "$delay_single_quote_subst"`' +hardcode_action='`$ECHO "$hardcode_action" | $SED "$delay_single_quote_subst"`' +enable_dlopen='`$ECHO "$enable_dlopen" | $SED "$delay_single_quote_subst"`' +enable_dlopen_self='`$ECHO "$enable_dlopen_self" | $SED "$delay_single_quote_subst"`' +enable_dlopen_self_static='`$ECHO "$enable_dlopen_self_static" | $SED "$delay_single_quote_subst"`' +old_striplib='`$ECHO "$old_striplib" | $SED "$delay_single_quote_subst"`' +striplib='`$ECHO "$striplib" | $SED "$delay_single_quote_subst"`' +compiler_lib_search_dirs='`$ECHO "$compiler_lib_search_dirs" | $SED "$delay_single_quote_subst"`' +predep_objects='`$ECHO "$predep_objects" | $SED "$delay_single_quote_subst"`' +postdep_objects='`$ECHO "$postdep_objects" | $SED "$delay_single_quote_subst"`' +predeps='`$ECHO "$predeps" | $SED "$delay_single_quote_subst"`' +postdeps='`$ECHO "$postdeps" | $SED "$delay_single_quote_subst"`' +compiler_lib_search_path='`$ECHO "$compiler_lib_search_path" | $SED "$delay_single_quote_subst"`' +LD_CXX='`$ECHO "$LD_CXX" | $SED "$delay_single_quote_subst"`' +reload_flag_CXX='`$ECHO "$reload_flag_CXX" | $SED "$delay_single_quote_subst"`' +reload_cmds_CXX='`$ECHO "$reload_cmds_CXX" | $SED "$delay_single_quote_subst"`' +old_archive_cmds_CXX='`$ECHO "$old_archive_cmds_CXX" | $SED "$delay_single_quote_subst"`' +compiler_CXX='`$ECHO "$compiler_CXX" | $SED "$delay_single_quote_subst"`' +GCC_CXX='`$ECHO "$GCC_CXX" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_no_builtin_flag_CXX='`$ECHO "$lt_prog_compiler_no_builtin_flag_CXX" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_pic_CXX='`$ECHO "$lt_prog_compiler_pic_CXX" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_wl_CXX='`$ECHO "$lt_prog_compiler_wl_CXX" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_static_CXX='`$ECHO "$lt_prog_compiler_static_CXX" | $SED "$delay_single_quote_subst"`' +lt_cv_prog_compiler_c_o_CXX='`$ECHO "$lt_cv_prog_compiler_c_o_CXX" | $SED "$delay_single_quote_subst"`' +archive_cmds_need_lc_CXX='`$ECHO "$archive_cmds_need_lc_CXX" | $SED "$delay_single_quote_subst"`' +enable_shared_with_static_runtimes_CXX='`$ECHO "$enable_shared_with_static_runtimes_CXX" | $SED "$delay_single_quote_subst"`' +export_dynamic_flag_spec_CXX='`$ECHO "$export_dynamic_flag_spec_CXX" | $SED "$delay_single_quote_subst"`' +whole_archive_flag_spec_CXX='`$ECHO "$whole_archive_flag_spec_CXX" | $SED "$delay_single_quote_subst"`' +compiler_needs_object_CXX='`$ECHO "$compiler_needs_object_CXX" | $SED "$delay_single_quote_subst"`' +old_archive_from_new_cmds_CXX='`$ECHO "$old_archive_from_new_cmds_CXX" | $SED "$delay_single_quote_subst"`' +old_archive_from_expsyms_cmds_CXX='`$ECHO "$old_archive_from_expsyms_cmds_CXX" | $SED "$delay_single_quote_subst"`' +archive_cmds_CXX='`$ECHO "$archive_cmds_CXX" | $SED "$delay_single_quote_subst"`' +archive_expsym_cmds_CXX='`$ECHO "$archive_expsym_cmds_CXX" | $SED "$delay_single_quote_subst"`' +module_cmds_CXX='`$ECHO "$module_cmds_CXX" | $SED "$delay_single_quote_subst"`' +module_expsym_cmds_CXX='`$ECHO "$module_expsym_cmds_CXX" | $SED "$delay_single_quote_subst"`' +with_gnu_ld_CXX='`$ECHO "$with_gnu_ld_CXX" | $SED "$delay_single_quote_subst"`' +allow_undefined_flag_CXX='`$ECHO "$allow_undefined_flag_CXX" | $SED "$delay_single_quote_subst"`' +no_undefined_flag_CXX='`$ECHO "$no_undefined_flag_CXX" | $SED "$delay_single_quote_subst"`' +hardcode_libdir_flag_spec_CXX='`$ECHO "$hardcode_libdir_flag_spec_CXX" | $SED "$delay_single_quote_subst"`' +hardcode_libdir_separator_CXX='`$ECHO "$hardcode_libdir_separator_CXX" | $SED "$delay_single_quote_subst"`' +hardcode_direct_CXX='`$ECHO "$hardcode_direct_CXX" | $SED "$delay_single_quote_subst"`' +hardcode_direct_absolute_CXX='`$ECHO "$hardcode_direct_absolute_CXX" | $SED "$delay_single_quote_subst"`' +hardcode_minus_L_CXX='`$ECHO "$hardcode_minus_L_CXX" | $SED "$delay_single_quote_subst"`' +hardcode_shlibpath_var_CXX='`$ECHO "$hardcode_shlibpath_var_CXX" | $SED "$delay_single_quote_subst"`' +hardcode_automatic_CXX='`$ECHO "$hardcode_automatic_CXX" | $SED "$delay_single_quote_subst"`' +inherit_rpath_CXX='`$ECHO "$inherit_rpath_CXX" | $SED "$delay_single_quote_subst"`' +link_all_deplibs_CXX='`$ECHO "$link_all_deplibs_CXX" | $SED "$delay_single_quote_subst"`' +always_export_symbols_CXX='`$ECHO "$always_export_symbols_CXX" | $SED "$delay_single_quote_subst"`' +export_symbols_cmds_CXX='`$ECHO "$export_symbols_cmds_CXX" | $SED "$delay_single_quote_subst"`' +exclude_expsyms_CXX='`$ECHO "$exclude_expsyms_CXX" | $SED "$delay_single_quote_subst"`' +include_expsyms_CXX='`$ECHO "$include_expsyms_CXX" | $SED "$delay_single_quote_subst"`' +prelink_cmds_CXX='`$ECHO "$prelink_cmds_CXX" | $SED "$delay_single_quote_subst"`' +postlink_cmds_CXX='`$ECHO "$postlink_cmds_CXX" | $SED "$delay_single_quote_subst"`' +file_list_spec_CXX='`$ECHO "$file_list_spec_CXX" | $SED "$delay_single_quote_subst"`' +hardcode_action_CXX='`$ECHO "$hardcode_action_CXX" | $SED "$delay_single_quote_subst"`' +compiler_lib_search_dirs_CXX='`$ECHO "$compiler_lib_search_dirs_CXX" | $SED "$delay_single_quote_subst"`' +predep_objects_CXX='`$ECHO "$predep_objects_CXX" | $SED "$delay_single_quote_subst"`' +postdep_objects_CXX='`$ECHO "$postdep_objects_CXX" | $SED "$delay_single_quote_subst"`' +predeps_CXX='`$ECHO "$predeps_CXX" | $SED "$delay_single_quote_subst"`' +postdeps_CXX='`$ECHO "$postdeps_CXX" | $SED "$delay_single_quote_subst"`' +compiler_lib_search_path_CXX='`$ECHO "$compiler_lib_search_path_CXX" | $SED "$delay_single_quote_subst"`' + +LTCC='$LTCC' +LTCFLAGS='$LTCFLAGS' +compiler='$compiler_DEFAULT' + +# A function that is used when there is no print builtin or printf. +func_fallback_echo () +{ + eval 'cat <<_LTECHO_EOF +\$1 +_LTECHO_EOF' +} + +# Quote evaled strings. +for var in AS \ +DLLTOOL \ +OBJDUMP \ +SHELL \ +ECHO \ +PATH_SEPARATOR \ +SED \ +GREP \ +EGREP \ +FGREP \ +LD \ +NM \ +LN_S \ +lt_SP2NL \ +lt_NL2SP \ +reload_flag \ +deplibs_check_method \ +file_magic_cmd \ +file_magic_glob \ +want_nocaseglob \ +sharedlib_from_linklib_cmd \ +AR \ +AR_FLAGS \ +archiver_list_spec \ +STRIP \ +RANLIB \ +CC \ +CFLAGS \ +compiler \ +lt_cv_sys_global_symbol_pipe \ +lt_cv_sys_global_symbol_to_cdecl \ +lt_cv_sys_global_symbol_to_c_name_address \ +lt_cv_sys_global_symbol_to_c_name_address_lib_prefix \ +nm_file_list_spec \ +lt_prog_compiler_no_builtin_flag \ +lt_prog_compiler_pic \ +lt_prog_compiler_wl \ +lt_prog_compiler_static \ +lt_cv_prog_compiler_c_o \ +need_locks \ +MANIFEST_TOOL \ +DSYMUTIL \ +NMEDIT \ +LIPO \ +OTOOL \ +OTOOL64 \ +shrext_cmds \ +export_dynamic_flag_spec \ +whole_archive_flag_spec \ +compiler_needs_object \ +with_gnu_ld \ +allow_undefined_flag \ +no_undefined_flag \ +hardcode_libdir_flag_spec \ +hardcode_libdir_separator \ +exclude_expsyms \ +include_expsyms \ +file_list_spec \ +variables_saved_for_relink \ +libname_spec \ +library_names_spec \ +soname_spec \ +install_override_mode \ +finish_eval \ +old_striplib \ +striplib \ +compiler_lib_search_dirs \ +predep_objects \ +postdep_objects \ +predeps \ +postdeps \ +compiler_lib_search_path \ +LD_CXX \ +reload_flag_CXX \ +compiler_CXX \ +lt_prog_compiler_no_builtin_flag_CXX \ +lt_prog_compiler_pic_CXX \ +lt_prog_compiler_wl_CXX \ +lt_prog_compiler_static_CXX \ +lt_cv_prog_compiler_c_o_CXX \ +export_dynamic_flag_spec_CXX \ +whole_archive_flag_spec_CXX \ +compiler_needs_object_CXX \ +with_gnu_ld_CXX \ +allow_undefined_flag_CXX \ +no_undefined_flag_CXX \ +hardcode_libdir_flag_spec_CXX \ +hardcode_libdir_separator_CXX \ +exclude_expsyms_CXX \ +include_expsyms_CXX \ +file_list_spec_CXX \ +compiler_lib_search_dirs_CXX \ +predep_objects_CXX \ +postdep_objects_CXX \ +predeps_CXX \ +postdeps_CXX \ +compiler_lib_search_path_CXX; do + case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in + *[\\\\\\\`\\"\\\$]*) + eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" + ;; + *) + eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" + ;; + esac +done + +# Double-quote double-evaled strings. +for var in reload_cmds \ +old_postinstall_cmds \ +old_postuninstall_cmds \ +old_archive_cmds \ +extract_expsyms_cmds \ +old_archive_from_new_cmds \ +old_archive_from_expsyms_cmds \ +archive_cmds \ +archive_expsym_cmds \ +module_cmds \ +module_expsym_cmds \ +export_symbols_cmds \ +prelink_cmds \ +postlink_cmds \ +postinstall_cmds \ +postuninstall_cmds \ +finish_cmds \ +sys_lib_search_path_spec \ +sys_lib_dlsearch_path_spec \ +reload_cmds_CXX \ +old_archive_cmds_CXX \ +old_archive_from_new_cmds_CXX \ +old_archive_from_expsyms_cmds_CXX \ +archive_cmds_CXX \ +archive_expsym_cmds_CXX \ +module_cmds_CXX \ +module_expsym_cmds_CXX \ +export_symbols_cmds_CXX \ +prelink_cmds_CXX \ +postlink_cmds_CXX; do + case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in + *[\\\\\\\`\\"\\\$]*) + eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" + ;; + *) + eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" + ;; + esac +done + +ac_aux_dir='$ac_aux_dir' +xsi_shell='$xsi_shell' +lt_shell_append='$lt_shell_append' + +# See if we are running on zsh, and set the options which allow our +# commands through without removal of \ escapes INIT. +if test -n "\${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST +fi + + + PACKAGE='$PACKAGE' + VERSION='$VERSION' + TIMESTAMP='$TIMESTAMP' + RM='$RM' + ofile='$ofile' + + + + + + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 + +# Handling of arguments. +for ac_config_target in $ac_config_targets +do + case $ac_config_target in + "libtool") CONFIG_COMMANDS="$CONFIG_COMMANDS libtool" ;; + "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; + "portaudio-2.0.pc") CONFIG_FILES="$CONFIG_FILES portaudio-2.0.pc" ;; + + *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; + esac +done + + +# If the user did not use the arguments to specify the items to instantiate, +# then the envvar interface is used. Set only those that are not. +# We use the long form for the default assignment because of an extremely +# bizarre bug on SunOS 4.1.3. +if $ac_need_defaults; then + test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files + test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands +fi + +# Have a temporary directory for convenience. Make it in the build tree +# simply because there is no reason against having it here, and in addition, +# creating and moving files from /tmp can sometimes cause problems. +# Hook for its removal unless debugging. +# Note that there is a small window in which the directory will not be cleaned: +# after its creation but before its name has been assigned to `$tmp'. +$debug || +{ + tmp= ac_tmp= + trap 'exit_status=$? + : "${ac_tmp:=$tmp}" + { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status +' 0 + trap 'as_fn_exit 1' 1 2 13 15 +} +# Create a (secure) tmp directory for tmp files. + +{ + tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && + test -d "$tmp" +} || +{ + tmp=./conf$$-$RANDOM + (umask 077 && mkdir "$tmp") +} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 +ac_tmp=$tmp + +# Set up the scripts for CONFIG_FILES section. +# No need to generate them if there are no CONFIG_FILES. +# This happens for instance with `./config.status config.h'. +if test -n "$CONFIG_FILES"; then + + +ac_cr=`echo X | tr X '\015'` +# On cygwin, bash can eat \r inside `` if the user requested igncr. +# But we know of no other shell where ac_cr would be empty at this +# point, so we can use a bashism as a fallback. +if test "x$ac_cr" = x; then + eval ac_cr=\$\'\\r\' +fi +ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` +if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then + ac_cs_awk_cr='\\r' +else + ac_cs_awk_cr=$ac_cr +fi + +echo 'BEGIN {' >"$ac_tmp/subs1.awk" && +_ACEOF + + +{ + echo "cat >conf$$subs.awk <<_ACEOF" && + echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && + echo "_ACEOF" +} >conf$$subs.sh || + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 +ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` +ac_delim='%!_!# ' +for ac_last_try in false false false false false :; do + . ./conf$$subs.sh || + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 + + ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` + if test $ac_delim_n = $ac_delim_num; then + break + elif $ac_last_try; then + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done +rm -f conf$$subs.sh + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && +_ACEOF +sed -n ' +h +s/^/S["/; s/!.*/"]=/ +p +g +s/^[^!]*!// +:repl +t repl +s/'"$ac_delim"'$// +t delim +:nl +h +s/\(.\{148\}\)..*/\1/ +t more1 +s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ +p +n +b repl +:more1 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t nl +:delim +h +s/\(.\{148\}\)..*/\1/ +t more2 +s/["\\]/\\&/g; s/^/"/; s/$/"/ +p +b +:more2 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t delim +' >$CONFIG_STATUS || ac_write_fail=1 +rm -f conf$$subs.awk +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +_ACAWK +cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && + for (key in S) S_is_set[key] = 1 + FS = "" + +} +{ + line = $ 0 + nfields = split(line, field, "@") + substed = 0 + len = length(field[1]) + for (i = 2; i < nfields; i++) { + key = field[i] + keylen = length(key) + if (S_is_set[key]) { + value = S[key] + line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) + len += length(value) + length(field[++i]) + substed = 1 + } else + len += 1 + keylen + } + + print line +} + +_ACAWK +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then + sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" +else + cat +fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ + || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 +_ACEOF + +# VPATH may cause trouble with some makes, so we remove sole $(srcdir), +# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and +# trailing colons and then remove the whole line if VPATH becomes empty +# (actually we leave an empty line to preserve line numbers). +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ +h +s/// +s/^/:/ +s/[ ]*$/:/ +s/:\$(srcdir):/:/g +s/:\${srcdir}:/:/g +s/:@srcdir@:/:/g +s/^:*// +s/:*$// +x +s/\(=[ ]*\).*/\1/ +G +s/\n// +s/^[^=]*=[ ]*$// +}' +fi + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +fi # test -n "$CONFIG_FILES" + + +eval set X " :F $CONFIG_FILES :C $CONFIG_COMMANDS" +shift +for ac_tag +do + case $ac_tag in + :[FHLC]) ac_mode=$ac_tag; continue;; + esac + case $ac_mode$ac_tag in + :[FHL]*:*);; + :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; + :[FH]-) ac_tag=-:-;; + :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; + esac + ac_save_IFS=$IFS + IFS=: + set x $ac_tag + IFS=$ac_save_IFS + shift + ac_file=$1 + shift + + case $ac_mode in + :L) ac_source=$1;; + :[FH]) + ac_file_inputs= + for ac_f + do + case $ac_f in + -) ac_f="$ac_tmp/stdin";; + *) # Look for the file first in the build tree, then in the source tree + # (if the path is not absolute). The absolute path cannot be DOS-style, + # because $ac_f cannot contain `:'. + test -f "$ac_f" || + case $ac_f in + [\\/$]*) false;; + *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; + esac || + as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; + esac + case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac + as_fn_append ac_file_inputs " '$ac_f'" + done + + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + configure_input='Generated from '` + $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' + `' by configure.' + if test x"$ac_file" != x-; then + configure_input="$ac_file. $configure_input" + { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 +$as_echo "$as_me: creating $ac_file" >&6;} + fi + # Neutralize special characters interpreted by sed in replacement strings. + case $configure_input in #( + *\&* | *\|* | *\\* ) + ac_sed_conf_input=`$as_echo "$configure_input" | + sed 's/[\\\\&|]/\\\\&/g'`;; #( + *) ac_sed_conf_input=$configure_input;; + esac + + case $ac_tag in + *:-:* | *:-) cat >"$ac_tmp/stdin" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; + esac + ;; + esac + + ac_dir=`$as_dirname -- "$ac_file" || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + as_dir="$ac_dir"; as_fn_mkdir_p + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + + case $ac_mode in + :F) + # + # CONFIG_FILE + # + + case $INSTALL in + [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; + *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; + esac +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# If the template does not know about datarootdir, expand it. +# FIXME: This hack should be removed a few years after 2.60. +ac_datarootdir_hack=; ac_datarootdir_seen= +ac_sed_dataroot=' +/datarootdir/ { + p + q +} +/@datadir@/p +/@docdir@/p +/@infodir@/p +/@localedir@/p +/@mandir@/p' +case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in +*datarootdir*) ac_datarootdir_seen=yes;; +*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 +$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 + ac_datarootdir_hack=' + s&@datadir@&$datadir&g + s&@docdir@&$docdir&g + s&@infodir@&$infodir&g + s&@localedir@&$localedir&g + s&@mandir@&$mandir&g + s&\\\${datarootdir}&$datarootdir&g' ;; +esac +_ACEOF + +# Neutralize VPATH when `$srcdir' = `.'. +# Shell code in configure.ac might set extrasub. +# FIXME: do we really want to maintain this feature? +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_sed_extra="$ac_vpsub +$extrasub +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +:t +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +s|@configure_input@|$ac_sed_conf_input|;t t +s&@top_builddir@&$ac_top_builddir_sub&;t t +s&@top_build_prefix@&$ac_top_build_prefix&;t t +s&@srcdir@&$ac_srcdir&;t t +s&@abs_srcdir@&$ac_abs_srcdir&;t t +s&@top_srcdir@&$ac_top_srcdir&;t t +s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t +s&@builddir@&$ac_builddir&;t t +s&@abs_builddir@&$ac_abs_builddir&;t t +s&@abs_top_builddir@&$ac_abs_top_builddir&;t t +s&@INSTALL@&$ac_INSTALL&;t t +$ac_datarootdir_hack +" +eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ + >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + +test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && + { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && + { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ + "$ac_tmp/out"`; test -z "$ac_out"; } && + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined" >&5 +$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined" >&2;} + + rm -f "$ac_tmp/stdin" + case $ac_file in + -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; + *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; + esac \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + ;; + + + :C) { $as_echo "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5 +$as_echo "$as_me: executing $ac_file commands" >&6;} + ;; + esac + + + case $ac_file$ac_mode in + "libtool":C) + + # See if we are running on zsh, and set the options which allow our + # commands through without removal of \ escapes. + if test -n "${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST + fi + + cfgfile="${ofile}T" + trap "$RM \"$cfgfile\"; exit 1" 1 2 15 + $RM "$cfgfile" + + cat <<_LT_EOF >> "$cfgfile" +#! $SHELL + +# `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services. +# Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION +# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: +# NOTE: Changes made to this file will be lost: look at ltmain.sh. +# +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, +# 2006, 2007, 2008, 2009, 2010, 2011 Free Software +# Foundation, Inc. +# Written by Gordon Matzigkeit, 1996 +# +# This file is part of GNU Libtool. +# +# GNU Libtool is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# As a special exception to the GNU General Public License, +# if you distribute this file as part of a program or library that +# is built using GNU Libtool, you may include this file under the +# same distribution terms that you use for the rest of that program. +# +# GNU Libtool is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Libtool; see the file COPYING. If not, a copy +# can be downloaded from http://www.gnu.org/licenses/gpl.html, or +# obtained by writing to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + +# The names of the tagged configurations supported by this script. +available_tags="CXX " + +# ### BEGIN LIBTOOL CONFIG + +# Assembler program. +AS=$lt_AS + +# DLL creation program. +DLLTOOL=$lt_DLLTOOL + +# Object dumper program. +OBJDUMP=$lt_OBJDUMP + +# Which release of libtool.m4 was used? +macro_version=$macro_version +macro_revision=$macro_revision + +# Whether or not to build shared libraries. +build_libtool_libs=$enable_shared + +# Whether or not to build static libraries. +build_old_libs=$enable_static + +# What type of objects to build. +pic_mode=$pic_mode + +# Whether or not to optimize for fast installation. +fast_install=$enable_fast_install + +# Shell to use when invoking shell scripts. +SHELL=$lt_SHELL + +# An echo program that protects backslashes. +ECHO=$lt_ECHO + +# The PATH separator for the build system. +PATH_SEPARATOR=$lt_PATH_SEPARATOR + +# The host system. +host_alias=$host_alias +host=$host +host_os=$host_os + +# The build system. +build_alias=$build_alias +build=$build +build_os=$build_os + +# A sed program that does not truncate output. +SED=$lt_SED + +# Sed that helps us avoid accidentally triggering echo(1) options like -n. +Xsed="\$SED -e 1s/^X//" + +# A grep program that handles long lines. +GREP=$lt_GREP + +# An ERE matcher. +EGREP=$lt_EGREP + +# A literal string matcher. +FGREP=$lt_FGREP + +# A BSD- or MS-compatible name lister. +NM=$lt_NM + +# Whether we need soft or hard links. +LN_S=$lt_LN_S + +# What is the maximum length of a command? +max_cmd_len=$max_cmd_len + +# Object file suffix (normally "o"). +objext=$ac_objext + +# Executable file suffix (normally ""). +exeext=$exeext + +# whether the shell understands "unset". +lt_unset=$lt_unset + +# turn spaces into newlines. +SP2NL=$lt_lt_SP2NL + +# turn newlines into spaces. +NL2SP=$lt_lt_NL2SP + +# convert \$build file names to \$host format. +to_host_file_cmd=$lt_cv_to_host_file_cmd + +# convert \$build files to toolchain format. +to_tool_file_cmd=$lt_cv_to_tool_file_cmd + +# Method to check whether dependent libraries are shared objects. +deplibs_check_method=$lt_deplibs_check_method + +# Command to use when deplibs_check_method = "file_magic". +file_magic_cmd=$lt_file_magic_cmd + +# How to find potential files when deplibs_check_method = "file_magic". +file_magic_glob=$lt_file_magic_glob + +# Find potential files using nocaseglob when deplibs_check_method = "file_magic". +want_nocaseglob=$lt_want_nocaseglob + +# Command to associate shared and link libraries. +sharedlib_from_linklib_cmd=$lt_sharedlib_from_linklib_cmd + +# The archiver. +AR=$lt_AR + +# Flags to create an archive. +AR_FLAGS=$lt_AR_FLAGS + +# How to feed a file listing to the archiver. +archiver_list_spec=$lt_archiver_list_spec + +# A symbol stripping program. +STRIP=$lt_STRIP + +# Commands used to install an old-style archive. +RANLIB=$lt_RANLIB +old_postinstall_cmds=$lt_old_postinstall_cmds +old_postuninstall_cmds=$lt_old_postuninstall_cmds + +# Whether to use a lock for old archive extraction. +lock_old_archive_extraction=$lock_old_archive_extraction + +# A C compiler. +LTCC=$lt_CC + +# LTCC compiler flags. +LTCFLAGS=$lt_CFLAGS + +# Take the output of nm and produce a listing of raw symbols and C names. +global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe + +# Transform the output of nm in a proper C declaration. +global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl + +# Transform the output of nm in a C name address pair. +global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address + +# Transform the output of nm in a C name address pair when lib prefix is needed. +global_symbol_to_c_name_address_lib_prefix=$lt_lt_cv_sys_global_symbol_to_c_name_address_lib_prefix + +# Specify filename containing input files for \$NM. +nm_file_list_spec=$lt_nm_file_list_spec + +# The root where to search for dependent libraries,and in which our libraries should be installed. +lt_sysroot=$lt_sysroot + +# The name of the directory that contains temporary libtool files. +objdir=$objdir + +# Used to examine libraries when file_magic_cmd begins with "file". +MAGIC_CMD=$MAGIC_CMD + +# Must we lock files when doing compilation? +need_locks=$lt_need_locks + +# Manifest tool. +MANIFEST_TOOL=$lt_MANIFEST_TOOL + +# Tool to manipulate archived DWARF debug symbol files on Mac OS X. +DSYMUTIL=$lt_DSYMUTIL + +# Tool to change global to local symbols on Mac OS X. +NMEDIT=$lt_NMEDIT + +# Tool to manipulate fat objects and archives on Mac OS X. +LIPO=$lt_LIPO + +# ldd/readelf like tool for Mach-O binaries on Mac OS X. +OTOOL=$lt_OTOOL + +# ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4. +OTOOL64=$lt_OTOOL64 + +# Old archive suffix (normally "a"). +libext=$libext + +# Shared library suffix (normally ".so"). +shrext_cmds=$lt_shrext_cmds + +# The commands to extract the exported symbol list from a shared archive. +extract_expsyms_cmds=$lt_extract_expsyms_cmds + +# Variables whose values should be saved in libtool wrapper scripts and +# restored at link time. +variables_saved_for_relink=$lt_variables_saved_for_relink + +# Do we need the "lib" prefix for modules? +need_lib_prefix=$need_lib_prefix + +# Do we need a version for libraries? +need_version=$need_version + +# Library versioning type. +version_type=$version_type + +# Shared library runtime path variable. +runpath_var=$runpath_var + +# Shared library path variable. +shlibpath_var=$shlibpath_var + +# Is shlibpath searched before the hard-coded library search path? +shlibpath_overrides_runpath=$shlibpath_overrides_runpath + +# Format of library name prefix. +libname_spec=$lt_libname_spec + +# List of archive names. First name is the real one, the rest are links. +# The last name is the one that the linker finds with -lNAME +library_names_spec=$lt_library_names_spec + +# The coded name of the library, if different from the real name. +soname_spec=$lt_soname_spec + +# Permission mode override for installation of shared libraries. +install_override_mode=$lt_install_override_mode + +# Command to use after installation of a shared archive. +postinstall_cmds=$lt_postinstall_cmds + +# Command to use after uninstallation of a shared archive. +postuninstall_cmds=$lt_postuninstall_cmds + +# Commands used to finish a libtool library installation in a directory. +finish_cmds=$lt_finish_cmds + +# As "finish_cmds", except a single script fragment to be evaled but +# not shown. +finish_eval=$lt_finish_eval + +# Whether we should hardcode library paths into libraries. +hardcode_into_libs=$hardcode_into_libs + +# Compile-time system search path for libraries. +sys_lib_search_path_spec=$lt_sys_lib_search_path_spec + +# Run-time system search path for libraries. +sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec + +# Whether dlopen is supported. +dlopen_support=$enable_dlopen + +# Whether dlopen of programs is supported. +dlopen_self=$enable_dlopen_self + +# Whether dlopen of statically linked programs is supported. +dlopen_self_static=$enable_dlopen_self_static + +# Commands to strip libraries. +old_striplib=$lt_old_striplib +striplib=$lt_striplib + + +# The linker used to build libraries. +LD=$lt_LD + +# How to create reloadable object files. +reload_flag=$lt_reload_flag +reload_cmds=$lt_reload_cmds + +# Commands used to build an old-style archive. +old_archive_cmds=$lt_old_archive_cmds + +# A language specific compiler. +CC=$lt_compiler + +# Is the compiler the GNU compiler? +with_gcc=$GCC + +# Compiler flag to turn off builtin functions. +no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag + +# Additional compiler flags for building library objects. +pic_flag=$lt_lt_prog_compiler_pic + +# How to pass a linker flag through the compiler. +wl=$lt_lt_prog_compiler_wl + +# Compiler flag to prevent dynamic linking. +link_static_flag=$lt_lt_prog_compiler_static + +# Does compiler simultaneously support -c and -o options? +compiler_c_o=$lt_lt_cv_prog_compiler_c_o + +# Whether or not to add -lc for building shared libraries. +build_libtool_need_lc=$archive_cmds_need_lc + +# Whether or not to disallow shared libs when runtime libs are static. +allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes + +# Compiler flag to allow reflexive dlopens. +export_dynamic_flag_spec=$lt_export_dynamic_flag_spec + +# Compiler flag to generate shared objects directly from archives. +whole_archive_flag_spec=$lt_whole_archive_flag_spec + +# Whether the compiler copes with passing no objects directly. +compiler_needs_object=$lt_compiler_needs_object + +# Create an old-style archive from a shared archive. +old_archive_from_new_cmds=$lt_old_archive_from_new_cmds + +# Create a temporary old-style archive to link instead of a shared archive. +old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds + +# Commands used to build a shared archive. +archive_cmds=$lt_archive_cmds +archive_expsym_cmds=$lt_archive_expsym_cmds + +# Commands used to build a loadable module if different from building +# a shared archive. +module_cmds=$lt_module_cmds +module_expsym_cmds=$lt_module_expsym_cmds + +# Whether we are building with GNU ld or not. +with_gnu_ld=$lt_with_gnu_ld + +# Flag that allows shared libraries with undefined symbols to be built. +allow_undefined_flag=$lt_allow_undefined_flag + +# Flag that enforces no undefined symbols. +no_undefined_flag=$lt_no_undefined_flag + +# Flag to hardcode \$libdir into a binary during linking. +# This must work even if \$libdir does not exist +hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec + +# Whether we need a single "-rpath" flag with a separated argument. +hardcode_libdir_separator=$lt_hardcode_libdir_separator + +# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes +# DIR into the resulting binary. +hardcode_direct=$hardcode_direct + +# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes +# DIR into the resulting binary and the resulting library dependency is +# "absolute",i.e impossible to change by setting \${shlibpath_var} if the +# library is relocated. +hardcode_direct_absolute=$hardcode_direct_absolute + +# Set to "yes" if using the -LDIR flag during linking hardcodes DIR +# into the resulting binary. +hardcode_minus_L=$hardcode_minus_L + +# Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR +# into the resulting binary. +hardcode_shlibpath_var=$hardcode_shlibpath_var + +# Set to "yes" if building a shared library automatically hardcodes DIR +# into the library and all subsequent libraries and executables linked +# against it. +hardcode_automatic=$hardcode_automatic + +# Set to yes if linker adds runtime paths of dependent libraries +# to runtime path list. +inherit_rpath=$inherit_rpath + +# Whether libtool must link a program against all its dependency libraries. +link_all_deplibs=$link_all_deplibs + +# Set to "yes" if exported symbols are required. +always_export_symbols=$always_export_symbols + +# The commands to list exported symbols. +export_symbols_cmds=$lt_export_symbols_cmds + +# Symbols that should not be listed in the preloaded symbols. +exclude_expsyms=$lt_exclude_expsyms + +# Symbols that must always be exported. +include_expsyms=$lt_include_expsyms + +# Commands necessary for linking programs (against libraries) with templates. +prelink_cmds=$lt_prelink_cmds + +# Commands necessary for finishing linking programs. +postlink_cmds=$lt_postlink_cmds + +# Specify filename containing input files. +file_list_spec=$lt_file_list_spec + +# How to hardcode a shared library path into an executable. +hardcode_action=$hardcode_action + +# The directories searched by this compiler when creating a shared library. +compiler_lib_search_dirs=$lt_compiler_lib_search_dirs + +# Dependencies to place before and after the objects being linked to +# create a shared library. +predep_objects=$lt_predep_objects +postdep_objects=$lt_postdep_objects +predeps=$lt_predeps +postdeps=$lt_postdeps + +# The library search path used internally by the compiler when linking +# a shared library. +compiler_lib_search_path=$lt_compiler_lib_search_path + +# ### END LIBTOOL CONFIG + +_LT_EOF + + case $host_os in + aix3*) + cat <<\_LT_EOF >> "$cfgfile" +# AIX sometimes has problems with the GCC collect2 program. For some +# reason, if we set the COLLECT_NAMES environment variable, the problems +# vanish in a puff of smoke. +if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES +fi +_LT_EOF + ;; + esac + + +ltmain="$ac_aux_dir/ltmain.sh" + + + # We use sed instead of cat because bash on DJGPP gets confused if + # if finds mixed CR/LF and LF-only lines. Since sed operates in + # text mode, it properly converts lines to CR/LF. This bash problem + # is reportedly fixed, but why not run on old versions too? + sed '$q' "$ltmain" >> "$cfgfile" \ + || (rm -f "$cfgfile"; exit 1) + + if test x"$xsi_shell" = xyes; then + sed -e '/^func_dirname ()$/,/^} # func_dirname /c\ +func_dirname ()\ +{\ +\ case ${1} in\ +\ */*) func_dirname_result="${1%/*}${2}" ;;\ +\ * ) func_dirname_result="${3}" ;;\ +\ esac\ +} # Extended-shell func_dirname implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + sed -e '/^func_basename ()$/,/^} # func_basename /c\ +func_basename ()\ +{\ +\ func_basename_result="${1##*/}"\ +} # Extended-shell func_basename implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + sed -e '/^func_dirname_and_basename ()$/,/^} # func_dirname_and_basename /c\ +func_dirname_and_basename ()\ +{\ +\ case ${1} in\ +\ */*) func_dirname_result="${1%/*}${2}" ;;\ +\ * ) func_dirname_result="${3}" ;;\ +\ esac\ +\ func_basename_result="${1##*/}"\ +} # Extended-shell func_dirname_and_basename implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + sed -e '/^func_stripname ()$/,/^} # func_stripname /c\ +func_stripname ()\ +{\ +\ # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are\ +\ # positional parameters, so assign one to ordinary parameter first.\ +\ func_stripname_result=${3}\ +\ func_stripname_result=${func_stripname_result#"${1}"}\ +\ func_stripname_result=${func_stripname_result%"${2}"}\ +} # Extended-shell func_stripname implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + sed -e '/^func_split_long_opt ()$/,/^} # func_split_long_opt /c\ +func_split_long_opt ()\ +{\ +\ func_split_long_opt_name=${1%%=*}\ +\ func_split_long_opt_arg=${1#*=}\ +} # Extended-shell func_split_long_opt implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + sed -e '/^func_split_short_opt ()$/,/^} # func_split_short_opt /c\ +func_split_short_opt ()\ +{\ +\ func_split_short_opt_arg=${1#??}\ +\ func_split_short_opt_name=${1%"$func_split_short_opt_arg"}\ +} # Extended-shell func_split_short_opt implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + sed -e '/^func_lo2o ()$/,/^} # func_lo2o /c\ +func_lo2o ()\ +{\ +\ case ${1} in\ +\ *.lo) func_lo2o_result=${1%.lo}.${objext} ;;\ +\ *) func_lo2o_result=${1} ;;\ +\ esac\ +} # Extended-shell func_lo2o implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + sed -e '/^func_xform ()$/,/^} # func_xform /c\ +func_xform ()\ +{\ + func_xform_result=${1%.*}.lo\ +} # Extended-shell func_xform implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + sed -e '/^func_arith ()$/,/^} # func_arith /c\ +func_arith ()\ +{\ + func_arith_result=$(( $* ))\ +} # Extended-shell func_arith implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + sed -e '/^func_len ()$/,/^} # func_len /c\ +func_len ()\ +{\ + func_len_result=${#1}\ +} # Extended-shell func_len implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + +fi + +if test x"$lt_shell_append" = xyes; then + sed -e '/^func_append ()$/,/^} # func_append /c\ +func_append ()\ +{\ + eval "${1}+=\\${2}"\ +} # Extended-shell func_append implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + sed -e '/^func_append_quoted ()$/,/^} # func_append_quoted /c\ +func_append_quoted ()\ +{\ +\ func_quote_for_eval "${2}"\ +\ eval "${1}+=\\\\ \\$func_quote_for_eval_result"\ +} # Extended-shell func_append_quoted implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + # Save a `func_append' function call where possible by direct use of '+=' + sed -e 's%func_append \([a-zA-Z_]\{1,\}\) "%\1+="%g' $cfgfile > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") + test 0 -eq $? || _lt_function_replace_fail=: +else + # Save a `func_append' function call even when '+=' is not available + sed -e 's%func_append \([a-zA-Z_]\{1,\}\) "%\1="$\1%g' $cfgfile > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") + test 0 -eq $? || _lt_function_replace_fail=: +fi + +if test x"$_lt_function_replace_fail" = x":"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Unable to substitute extended shell functions in $ofile" >&5 +$as_echo "$as_me: WARNING: Unable to substitute extended shell functions in $ofile" >&2;} +fi + + + mv -f "$cfgfile" "$ofile" || + (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") + chmod +x "$ofile" + + + cat <<_LT_EOF >> "$ofile" + +# ### BEGIN LIBTOOL TAG CONFIG: CXX + +# The linker used to build libraries. +LD=$lt_LD_CXX + +# How to create reloadable object files. +reload_flag=$lt_reload_flag_CXX +reload_cmds=$lt_reload_cmds_CXX + +# Commands used to build an old-style archive. +old_archive_cmds=$lt_old_archive_cmds_CXX + +# A language specific compiler. +CC=$lt_compiler_CXX + +# Is the compiler the GNU compiler? +with_gcc=$GCC_CXX + +# Compiler flag to turn off builtin functions. +no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag_CXX + +# Additional compiler flags for building library objects. +pic_flag=$lt_lt_prog_compiler_pic_CXX + +# How to pass a linker flag through the compiler. +wl=$lt_lt_prog_compiler_wl_CXX + +# Compiler flag to prevent dynamic linking. +link_static_flag=$lt_lt_prog_compiler_static_CXX + +# Does compiler simultaneously support -c and -o options? +compiler_c_o=$lt_lt_cv_prog_compiler_c_o_CXX + +# Whether or not to add -lc for building shared libraries. +build_libtool_need_lc=$archive_cmds_need_lc_CXX + +# Whether or not to disallow shared libs when runtime libs are static. +allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes_CXX + +# Compiler flag to allow reflexive dlopens. +export_dynamic_flag_spec=$lt_export_dynamic_flag_spec_CXX + +# Compiler flag to generate shared objects directly from archives. +whole_archive_flag_spec=$lt_whole_archive_flag_spec_CXX + +# Whether the compiler copes with passing no objects directly. +compiler_needs_object=$lt_compiler_needs_object_CXX + +# Create an old-style archive from a shared archive. +old_archive_from_new_cmds=$lt_old_archive_from_new_cmds_CXX + +# Create a temporary old-style archive to link instead of a shared archive. +old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds_CXX + +# Commands used to build a shared archive. +archive_cmds=$lt_archive_cmds_CXX +archive_expsym_cmds=$lt_archive_expsym_cmds_CXX + +# Commands used to build a loadable module if different from building +# a shared archive. +module_cmds=$lt_module_cmds_CXX +module_expsym_cmds=$lt_module_expsym_cmds_CXX + +# Whether we are building with GNU ld or not. +with_gnu_ld=$lt_with_gnu_ld_CXX + +# Flag that allows shared libraries with undefined symbols to be built. +allow_undefined_flag=$lt_allow_undefined_flag_CXX + +# Flag that enforces no undefined symbols. +no_undefined_flag=$lt_no_undefined_flag_CXX + +# Flag to hardcode \$libdir into a binary during linking. +# This must work even if \$libdir does not exist +hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec_CXX + +# Whether we need a single "-rpath" flag with a separated argument. +hardcode_libdir_separator=$lt_hardcode_libdir_separator_CXX + +# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes +# DIR into the resulting binary. +hardcode_direct=$hardcode_direct_CXX + +# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes +# DIR into the resulting binary and the resulting library dependency is +# "absolute",i.e impossible to change by setting \${shlibpath_var} if the +# library is relocated. +hardcode_direct_absolute=$hardcode_direct_absolute_CXX + +# Set to "yes" if using the -LDIR flag during linking hardcodes DIR +# into the resulting binary. +hardcode_minus_L=$hardcode_minus_L_CXX + +# Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR +# into the resulting binary. +hardcode_shlibpath_var=$hardcode_shlibpath_var_CXX + +# Set to "yes" if building a shared library automatically hardcodes DIR +# into the library and all subsequent libraries and executables linked +# against it. +hardcode_automatic=$hardcode_automatic_CXX + +# Set to yes if linker adds runtime paths of dependent libraries +# to runtime path list. +inherit_rpath=$inherit_rpath_CXX + +# Whether libtool must link a program against all its dependency libraries. +link_all_deplibs=$link_all_deplibs_CXX + +# Set to "yes" if exported symbols are required. +always_export_symbols=$always_export_symbols_CXX + +# The commands to list exported symbols. +export_symbols_cmds=$lt_export_symbols_cmds_CXX + +# Symbols that should not be listed in the preloaded symbols. +exclude_expsyms=$lt_exclude_expsyms_CXX + +# Symbols that must always be exported. +include_expsyms=$lt_include_expsyms_CXX + +# Commands necessary for linking programs (against libraries) with templates. +prelink_cmds=$lt_prelink_cmds_CXX + +# Commands necessary for finishing linking programs. +postlink_cmds=$lt_postlink_cmds_CXX + +# Specify filename containing input files. +file_list_spec=$lt_file_list_spec_CXX + +# How to hardcode a shared library path into an executable. +hardcode_action=$hardcode_action_CXX + +# The directories searched by this compiler when creating a shared library. +compiler_lib_search_dirs=$lt_compiler_lib_search_dirs_CXX + +# Dependencies to place before and after the objects being linked to +# create a shared library. +predep_objects=$lt_predep_objects_CXX +postdep_objects=$lt_postdep_objects_CXX +predeps=$lt_predeps_CXX +postdeps=$lt_postdeps_CXX + +# The library search path used internally by the compiler when linking +# a shared library. +compiler_lib_search_path=$lt_compiler_lib_search_path_CXX + +# ### END LIBTOOL TAG CONFIG: CXX +_LT_EOF + + ;; + + esac +done # for ac_tag + + +as_fn_exit 0 +_ACEOF +ac_clean_files=$ac_clean_files_save + +test $ac_write_fail = 0 || + as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 + + +# configure is writing to config.log, and then calls config.status. +# config.status does its own redirection, appending to config.log. +# Unfortunately, on DOS this fails, as config.log is still kept open +# by configure, so config.status won't be able to write to it; its +# output is simply discarded. So we exec the FD to /dev/null, +# effectively closing config.log, so it can be properly (re)opened and +# appended to by config.status. When coming back to configure, we +# need to make the FD available again. +if test "$no_create" != yes; then + ac_cs_success=: + ac_config_status_args= + test "$silent" = yes && + ac_config_status_args="$ac_config_status_args --quiet" + exec 5>/dev/null + $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false + exec 5>>config.log + # Use ||, not &&, to avoid exiting from the if with $? = 1, which + # would make configure fail if this is the last instruction. + $ac_cs_success || as_fn_exit 1 +fi + +# +# CONFIG_SUBDIRS section. +# +if test "$no_recursion" != yes; then + + # Remove --cache-file, --srcdir, and --disable-option-checking arguments + # so they do not pile up. + ac_sub_configure_args= + ac_prev= + eval "set x $ac_configure_args" + shift + for ac_arg + do + if test -n "$ac_prev"; then + ac_prev= + continue + fi + case $ac_arg in + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* \ + | --c=*) + ;; + --config-cache | -C) + ;; + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + ;; + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + ;; + --disable-option-checking) + ;; + *) + case $ac_arg in + *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + as_fn_append ac_sub_configure_args " '$ac_arg'" ;; + esac + done + + # Always prepend --prefix to ensure using the same prefix + # in subdir configurations. + ac_arg="--prefix=$prefix" + case $ac_arg in + *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + ac_sub_configure_args="'$ac_arg' $ac_sub_configure_args" + + # Pass --silent + if test "$silent" = yes; then + ac_sub_configure_args="--silent $ac_sub_configure_args" + fi + + # Always prepend --disable-option-checking to silence warnings, since + # different subdirs can have different --enable and --with options. + ac_sub_configure_args="--disable-option-checking $ac_sub_configure_args" + + ac_popdir=`pwd` + for ac_dir in : $subdirs; do test "x$ac_dir" = x: && continue + + # Do not complain, so a configure script can configure whichever + # parts of a large source tree are present. + test -d "$srcdir/$ac_dir" || continue + + ac_msg="=== configuring in $ac_dir (`pwd`/$ac_dir)" + $as_echo "$as_me:${as_lineno-$LINENO}: $ac_msg" >&5 + $as_echo "$ac_msg" >&6 + as_dir="$ac_dir"; as_fn_mkdir_p + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + + cd "$ac_dir" + + # Check for guested configure; otherwise get Cygnus style configure. + if test -f "$ac_srcdir/configure.gnu"; then + ac_sub_configure=$ac_srcdir/configure.gnu + elif test -f "$ac_srcdir/configure"; then + ac_sub_configure=$ac_srcdir/configure + elif test -f "$ac_srcdir/configure.in"; then + # This should be Cygnus configure. + ac_sub_configure=$ac_aux_dir/configure + else + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: no configuration information is in $ac_dir" >&5 +$as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2;} + ac_sub_configure= + fi + + # The recursion is here. + if test -n "$ac_sub_configure"; then + # Make the cache file name correct relative to the subdirectory. + case $cache_file in + [\\/]* | ?:[\\/]* ) ac_sub_cache_file=$cache_file ;; + *) # Relative name. + ac_sub_cache_file=$ac_top_build_prefix$cache_file ;; + esac + + { $as_echo "$as_me:${as_lineno-$LINENO}: running $SHELL $ac_sub_configure $ac_sub_configure_args --cache-file=$ac_sub_cache_file --srcdir=$ac_srcdir" >&5 +$as_echo "$as_me: running $SHELL $ac_sub_configure $ac_sub_configure_args --cache-file=$ac_sub_cache_file --srcdir=$ac_srcdir" >&6;} + # The eval makes quoting arguments work. + eval "\$SHELL \"\$ac_sub_configure\" $ac_sub_configure_args \ + --cache-file=\"\$ac_sub_cache_file\" --srcdir=\"\$ac_srcdir\"" || + as_fn_error $? "$ac_sub_configure failed for $ac_dir" "$LINENO" 5 + fi + + cd "$ac_popdir" + done +fi +if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 +$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} +fi + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: +Configuration summary: + + Target ...................... $target + C++ bindings ................ $enable_cxx + Debug output ................ $debug_output" >&5 +$as_echo " +Configuration summary: + + Target ...................... $target + C++ bindings ................ $enable_cxx + Debug output ................ $debug_output" >&6; } + +case "$target_os" in *linux*) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: + ALSA ........................ $have_alsa + ASIHPI ...................... $have_asihpi" >&5 +$as_echo " + ALSA ........................ $have_alsa + ASIHPI ...................... $have_asihpi" >&6; } + ;; +esac +case "$target_os" in + *mingw* | *cygwin*) + test "x$with_directx" = "xyes" && with_directx="$with_directx (${with_dxdir})" + test "x$with_wdmks" = "xyes" && with_wdmks="$with_wdmks (${with_dxdir})" + test "x$with_asio" = "xyes" && with_asio="$with_asio (${with_asiodir})" + test "x$with_wasapi" = "xyes" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: + WMME ........................ $with_wmme + DSound ...................... $with_directx + ASIO ........................ $with_asio + WASAPI ...................... $with_wasapi + WDMKS ....................... $with_wdmks +" >&5 +$as_echo " + WMME ........................ $with_wmme + DSound ...................... $with_directx + ASIO ........................ $with_asio + WASAPI ...................... $with_wasapi + WDMKS ....................... $with_wdmks +" >&6; } + ;; + *darwin*) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: + Mac debug flags ............. $enable_mac_debug +" >&5 +$as_echo " + Mac debug flags ............. $enable_mac_debug +" >&6; } + ;; + *) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: + OSS ......................... $have_oss + JACK ........................ $have_jack +" >&5 +$as_echo " + OSS ......................... $have_oss + JACK ........................ $have_jack +" >&6; } + ;; +esac diff --git a/extern/portaudio/configure.in b/extern/portaudio/configure.in new file mode 100644 index 0000000..b2129ba --- /dev/null +++ b/extern/portaudio/configure.in @@ -0,0 +1,519 @@ +dnl +dnl portaudio V19 configure.in script +dnl +dnl Dominic Mazzoni, Arve Knudsen, Stelios Bounanos +dnl + +dnl Require autoconf >= 2.13 +AC_PREREQ(2.13) + +dnl Init autoconf and make sure configure is being called +dnl from the right directory +AC_INIT([include/portaudio.h]) + +dnl Define build, build_cpu, build_vendor, build_os +AC_CANONICAL_BUILD +dnl Define host, host_cpu, host_vendor, host_os +AC_CANONICAL_HOST +dnl Define target, target_cpu, target_vendor, target_os +AC_CANONICAL_TARGET + +dnl Specify options + +AC_ARG_WITH(alsa, + AS_HELP_STRING([--with-alsa], [Enable support for ALSA @<:@autodetect@:>@]), + [with_alsa=$withval]) + +AC_ARG_WITH(jack, + AS_HELP_STRING([--with-jack], [Enable support for JACK @<:@autodetect@:>@]), + [with_jack=$withval]) + +AC_ARG_WITH(oss, + AS_HELP_STRING([--with-oss], [Enable support for OSS @<:@autodetect@:>@]), + [with_oss=$withval]) + +AC_ARG_WITH(asihpi, + AS_HELP_STRING([--with-asihpi], [Enable support for ASIHPI @<:@autodetect@:>@]), + [with_asihpi=$withval]) + +AC_ARG_WITH(winapi, + AS_HELP_STRING([--with-winapi], + [Select Windows API support (@<:@wmme|directx|asio|wasapi|wdmks@:>@@<:@,...@:>@) @<:@wmme@:>@]), + [with_winapi=$withval], [with_winapi="wmme"]) +case "$target_os" in *mingw* | *cygwin*) + with_wmme=no + with_directx=no + with_asio=no + with_wasapi=no + with_wdmks=no + for api in $(echo $with_winapi | sed 's/,/ /g'); do + case "$api" in + wmme|directx|asio|wasapi|wdmks) + eval with_$api=yes + ;; + *) + AC_MSG_ERROR([unknown Windows API \"$api\" (do you need --help?)]) + ;; + esac + done + ;; +esac + +AC_ARG_WITH(asiodir, + AS_HELP_STRING([--with-asiodir], [ASIO directory @<:@/usr/local/asiosdk2@:>@]), + with_asiodir=$withval, with_asiodir="/usr/local/asiosdk2") + +AC_ARG_WITH(dxdir, + AS_HELP_STRING([--with-dxdir], [DirectX directory @<:@/usr/local/dx7sdk@:>@]), + with_dxdir=$withval, with_dxdir="/usr/local/dx7sdk") + +debug_output=no +AC_ARG_ENABLE(debug-output, + AS_HELP_STRING([--enable-debug-output], [Enable debug output @<:@no@:>@]), + [if test "x$enableval" != "xno" ; then + AC_DEFINE(PA_ENABLE_DEBUG_OUTPUT,,[Enable debugging messages]) + debug_output=yes + fi + ]) + +AC_ARG_ENABLE(cxx, + AS_HELP_STRING([--enable-cxx], [Enable C++ bindings @<:@no@:>@]), + enable_cxx=$enableval, enable_cxx="no") + +AC_ARG_ENABLE(mac-debug, + AS_HELP_STRING([--enable-mac-debug], [Enable Mac debug @<:@no@:>@]), + enable_mac_debug=$enableval, enable_mac_debug="no") + +AC_ARG_ENABLE(mac-universal, + AS_HELP_STRING([--enable-mac-universal], [Build Mac universal binaries @<:@yes@:>@]), + enable_mac_universal=$enableval, enable_mac_universal="yes") + +dnl Continue to accept --host_os for compatibility but do not document +dnl it (the correct way to change host_os is with --host=...). Moved +dnl here because the empty help string generates a blank line which we +dnl can use to separate PA options from libtool options. +AC_ARG_WITH(host_os, [], host_os=$withval) + +dnl Checks for programs. + +AC_PROG_CC +dnl ASIO and CXX bindings need a C++ compiler +if [[ "$with_asio" = "yes" ] || [ "$enable_cxx" = "yes" ]] ; then + AC_PROG_CXX +fi +AC_LIBTOOL_WIN32_DLL +AC_PROG_LIBTOOL +AC_PROG_INSTALL +AC_PROG_LN_S +AC_PATH_PROG(AR, ar, no) +if [[ $AR = "no" ]] ; then + AC_MSG_ERROR("Could not find ar - needed to create a library") +fi + +dnl This must be one of the first tests we do or it will fail... +AC_C_BIGENDIAN + +dnl checks for various host APIs and arguments to configure that +dnl turn them on or off + +have_alsa=no +if test "x$with_alsa" != "xno"; then + AC_CHECK_LIB(asound, snd_pcm_open, have_alsa=yes, have_alsa=no) +fi +have_asihpi=no +if test "x$with_asihpi" != "xno"; then + AC_CHECK_LIB(hpi, HPI_SubSysCreate, have_asihpi=yes, have_asihpi=no, -lm) +fi +have_libossaudio=no +have_oss=no +if test "x$with_oss" != "xno"; then + AC_CHECK_HEADERS([sys/soundcard.h linux/soundcard.h machine/soundcard.h], [have_oss=yes]) + if test "x$have_oss" = "xyes"; then + AC_CHECK_LIB(ossaudio, _oss_ioctl, have_libossaudio=yes, have_libossaudio=no) + fi +fi +have_jack=no +if test "x$with_jack" != "xno"; then + PKG_CHECK_MODULES(JACK, jack, have_jack=yes, have_jack=no) +fi + + +dnl sizeof checks: we will need a 16-bit and a 32-bit type + +AC_CHECK_SIZEOF(short) +AC_CHECK_SIZEOF(int) +AC_CHECK_SIZEOF(long) + +save_LIBS="${LIBS}" +AC_CHECK_LIB(rt, clock_gettime, [rt_libs=" -lrt"]) +LIBS="${LIBS}${rt_libs}" +DLL_LIBS="${DLL_LIBS}${rt_libs}" +AC_CHECK_FUNCS([clock_gettime nanosleep]) +LIBS="${save_LIBS}" + +dnl LT_RELEASE=19 +LT_CURRENT=2 +LT_REVISION=0 +LT_AGE=0 + +AC_SUBST(LT_CURRENT) +AC_SUBST(LT_REVISION) +AC_SUBST(LT_AGE) + +dnl extra variables +AC_SUBST(OTHER_OBJS) +AC_SUBST(PADLL) +AC_SUBST(SHARED_FLAGS) +AC_SUBST(THREAD_CFLAGS) +AC_SUBST(DLL_LIBS) +AC_SUBST(CXXFLAGS) +AC_SUBST(NASM) +AC_SUBST(NASMOPT) +AC_SUBST(INCLUDES) + +dnl -g is optional on darwin +if ( echo "${host_os}" | grep ^darwin >> /dev/null ) && + [[ "$enable_mac_universal" = "yes" ] && + [ "$enable_mac_debug" != "yes" ]] ; then + CFLAGS="-O2 -Wall -pedantic -pipe -fPIC -DNDEBUG" +else + CFLAGS=${CFLAGS:-"-g -O2 -Wall -pedantic -pipe -fPIC"} +fi + +if [[ $ac_cv_c_bigendian = "yes" ]] ; then + CFLAGS="$CFLAGS -DPA_BIG_ENDIAN" +else + CFLAGS="$CFLAGS -DPA_LITTLE_ENDIAN" +fi + +add_objects() +{ + for o in $@; do + test "${OTHER_OBJS#*${o}*}" = "${OTHER_OBJS}" && OTHER_OBJS="$OTHER_OBJS $o" + done +} + +INCLUDES=portaudio.h + +dnl Include directories needed by all implementations +CFLAGS="$CFLAGS -I\$(top_srcdir)/include -I\$(top_srcdir)/src/common" + +case "${host_os}" in + darwin* ) + dnl Mac OS X configuration + + AC_DEFINE(PA_USE_COREAUDIO,1) + + CFLAGS="$CFLAGS -I\$(top_srcdir)/src/os/unix -Wno-deprecated -Werror" + LIBS="-framework CoreAudio -framework AudioToolbox -framework AudioUnit -framework Carbon" + + if test "x$enable_mac_universal" = "xyes" ; then + case `xcodebuild -version | sed -n 's/Xcode \(.*\)/\1/p'` in + + [12]*|3.0|3.1) + dnl In pre-3.2 versions of Xcode, xcodebuild doesn't + dnl support -sdk, so we can't use that to look for + dnl SDKs. However, in those versions of Xcode, the + dnl SDKs are under /Developer/SDKs, so we can just look + dnl there. Also, we assume they had no SDKs later + dnl than 10.5, as 3.2 was the version that came with + dnl 10.6, at least if the Wikipedia page for Xcode + dnl is to be believed. + if [[ -d /Developer/SDKs/MacOSX10.5.sdk ]] ; then + mac_version_min="-mmacosx-version-min=10.3" + mac_sysroot="-isysroot /Developer/SDKs/MacOSX10.5.sdk" + else + mac_version_min="-mmacosx-version-min=10.3" + mac_sysroot="-isysroot /Developer/SDKs/MacOSX10.4u.sdk" + fi + ;; + + *) + dnl In 3.2 and later, xcodebuild supports -sdk, and, in + dnl 4.3 and later, the SDKs aren't under /Developer/SDKs + dnl as there *is* no /Developer, so we use -sdk to check + dnl what SDKs are available and to get the full path of + dnl the SDKs. + if xcodebuild -version -sdk macosx10.5 Path >/dev/null 2>&1 ; then + mac_version_min="-mmacosx-version-min=10.3" + mac_sysroot="-isysroot `xcodebuild -version -sdk macosx10.5 Path`" + elif xcodebuild -version -sdk macosx10.6 Path >/dev/null 2>&1 ; then + mac_version_min="-mmacosx-version-min=10.4" + mac_sysroot="-isysroot `xcodebuild -version -sdk macosx10.6 Path`" + elif xcodebuild -version -sdk macosx10.7 Path >/dev/null 2>&1 ; then + mac_version_min="-mmacosx-version-min=10.4" + mac_sysroot="-isysroot `xcodebuild -version -sdk macosx10.7 Path`" + elif xcodebuild -version -sdk macosx10.8 Path >/dev/null 2>&1 ; then + mac_version_min="-mmacosx-version-min=10.4" + mac_sysroot="-isysroot `xcodebuild -version -sdk macosx10.8 Path`" + elif xcodebuild -version -sdk macosx10.9 Path >/dev/null 2>&1 ; then + mac_version_min="-mmacosx-version-min=10.4" + mac_sysroot="-isysroot `xcodebuild -version -sdk macosx10.9 Path`" + elif xcodebuild -version -sdk macosx10.10 Path >/dev/null 2>&1 ; then + mac_version_min="-mmacosx-version-min=10.4" + mac_sysroot="-isysroot `xcodebuild -version -sdk macosx10.10 Path`" + elif xcodebuild -version -sdk macosx10.11 Path >/dev/null 2>&1 ; then + mac_version_min="-mmacosx-version-min=10.4" + mac_sysroot="-isysroot `xcodebuild -version -sdk macosx10.11 Path`" + elif xcodebuild -version -sdk macosx10.12 Path >/dev/null 2>&1 ; then + mac_version_min="-mmacosx-version-min=10.4" + mac_sysroot="-isysroot `xcodebuild -version -sdk macosx10.12 Path`" + elif xcodebuild -version -sdk macosx10.13 Path >/dev/null 2>&1 ; then + mac_version_min="-mmacosx-version-min=10.4" + mac_sysroot="-isysroot `xcodebuild -version -sdk macosx10.13 Path`" + else + AC_MSG_ERROR([Could not find 10.5 to 10.13 SDK.]) + fi + esac + + dnl Pick which architectures to build for based on what + dnl the compiler supports. + mac_arches="" + for arch in i386 x86_64 ppc ppc64 + do + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -arch $arch" + AC_TRY_COMPILE([], [return 0;], + [ + if [[ -z "$mac_arches" ]] ; then + mac_arches="-arch $arch" + else + mac_arches="$mac_arches -arch $arch" + fi + ]) + CFLAGS="$save_CFLAGS" + done + else + mac_arches="" + mac_sysroot="" + mac_version="" + fi + SHARED_FLAGS="$LIBS -dynamiclib $mac_arches $mac_sysroot $mac_version_min" + CFLAGS="-std=c99 $CFLAGS $mac_arches $mac_sysroot $mac_version_min" + OTHER_OBJS="src/os/unix/pa_unix_hostapis.o src/os/unix/pa_unix_util.o src/hostapi/coreaudio/pa_mac_core.o src/hostapi/coreaudio/pa_mac_core_utilities.o src/hostapi/coreaudio/pa_mac_core_blocking.o src/common/pa_ringbuffer.o" + PADLL="libportaudio.dylib" + ;; + + mingw* ) + dnl MingW configuration + + PADLL="portaudio.dll" + THREAD_CFLAGS="-mthreads" + SHARED_FLAGS="-shared" + CFLAGS="$CFLAGS -I\$(top_srcdir)/src/os/win -DPA_USE_WMME=0 -DPA_USE_ASIO=0 -DPA_USE_WDMKS=0 -DPA_USE_DS=0 -DPA_USE_WASAPI=0" + + if [[ "x$with_directx" = "xyes" ]]; then + DXDIR="$with_dxdir" + add_objects src/hostapi/dsound/pa_win_ds.o src/hostapi/dsound/pa_win_ds_dynlink.o src/os/win/pa_win_hostapis.o src/os/win/pa_win_util.o src/os/win/pa_win_coinitialize.o src/os/win/pa_win_waveformat.o + LIBS="${LIBS} -lwinmm -lm -ldsound -lole32" + DLL_LIBS="${DLL_LIBS} -lwinmm -lm -L$DXDIR/lib -ldsound -lole32" + #VC98="\"/c/Program Files/Microsoft Visual Studio/VC98/Include\"" + #CFLAGS="$CFLAGS -I$VC98 -DPA_NO_WMME -DPA_NO_ASIO" + CFLAGS="$CFLAGS -I$DXDIR/include -UPA_USE_DS -DPA_USE_DS=1" + fi + + if [[ "x$with_asio" = "xyes" ]]; then + ASIODIR="$with_asiodir" + add_objects src/hostapi/asio/pa_asio.o src/common/pa_ringbuffer.o src/os/win/pa_win_hostapis.o src/os/win/pa_win_util.o src/os/win/pa_win_coinitialize.o src/hostapi/asio/iasiothiscallresolver.o $ASIODIR/common/asio.o $ASIODIR/host/asiodrivers.o $ASIODIR/host/pc/asiolist.o + LIBS="${LIBS} -lwinmm -lm -lole32 -luuid" + DLL_LIBS="${DLL_LIBS} -lwinmm -lm -lole32 -luuid" + CFLAGS="$CFLAGS -ffast-math -fomit-frame-pointer -I\$(top_srcdir)/src/hostapi/asio -I$ASIODIR/host/pc -I$ASIODIR/common -I$ASIODIR/host -UPA_USE_ASIO -DPA_USE_ASIO=1 -DWINDOWS" + + dnl Setting the windows version flags below resolves a conflict between Interlocked* + dnl definitions in mingw winbase.h and Interlocked* hacks in ASIO SDK combase.h + dnl combase.h is included by asiodrvr.h + dnl PortAudio does not actually require Win XP (winver 501) APIs + CFLAGS="$CFLAGS -D_WIN32_WINNT=0x0501 -DWINVER=0x0501" + + CXXFLAGS="$CFLAGS" + fi + + if [[ "x$with_wdmks" = "xyes" ]]; then + DXDIR="$with_dxdir" + add_objects src/hostapi/wdmks/pa_win_wdmks.o src/common/pa_ringbuffer.o src/os/win/pa_win_hostapis.o src/os/win/pa_win_util.o src/os/win/pa_win_wdmks_utils.o src/os/win/pa_win_waveformat.o + LIBS="${LIBS} -lwinmm -lm -luuid -lsetupapi -lole32" + DLL_LIBS="${DLL_LIBS} -lwinmm -lm -L$DXDIR/lib -luuid -lsetupapi -lole32" + #VC98="\"/c/Program Files/Microsoft Visual Studio/VC98/Include\"" + #CFLAGS="$CFLAGS -I$VC98 -DPA_NO_WMME -DPA_NO_ASIO" + CFLAGS="$CFLAGS -I$DXDIR/include -UPA_USE_WDMKS -DPA_USE_WDMKS=1" + fi + + if [[ "x$with_wmme" = "xyes" ]]; then + add_objects src/hostapi/wmme/pa_win_wmme.o src/os/win/pa_win_hostapis.o src/os/win/pa_win_util.o src/os/win/pa_win_waveformat.o + LIBS="${LIBS} -lwinmm -lm -lole32 -luuid" + DLL_LIBS="${DLL_LIBS} -lwinmm" + CFLAGS="$CFLAGS -UPA_USE_WMME -DPA_USE_WMME=1" + fi + + if [[ "x$with_wasapi" = "xyes" ]]; then + add_objects src/hostapi/wasapi/pa_win_wasapi.o src/common/pa_ringbuffer.o src/os/win/pa_win_hostapis.o src/os/win/pa_win_util.o src/os/win/pa_win_coinitialize.o src/os/win/pa_win_waveformat.o + LIBS="${LIBS} -lwinmm -lm -lole32 -luuid" + DLL_LIBS="${DLL_LIBS} -lwinmm -lole32" + CFLAGS="$CFLAGS -UPA_USE_WASAPI -DPA_USE_WASAPI=1" + fi + ;; + + cygwin* ) + dnl Cygwin configuration + + OTHER_OBJS="src/hostapi/wmme/pa_win_wmme.o src/os/win/pa_win_hostapis.o src/os/win/pa_win_util.o src/os/win/pa_win_waveformat.o" + CFLAGS="$CFLAGS -I\$(top_srcdir)/src/os/win -DPA_USE_DS=0 -DPA_USE_WDMKS=0 -DPA_USE_ASIO=0 -DPA_USE_WASAPI=0 -DPA_USE_WMME=1" + LIBS="-lwinmm -lm" + PADLL="portaudio.dll" + THREAD_CFLAGS="-mthreads" + SHARED_FLAGS="-shared" + DLL_LIBS="${DLL_LIBS} -lwinmm" + ;; + + irix* ) + dnl SGI IRIX audio library (AL) configuration (Pieter, oct 2-13, 2003). + dnl The 'dmedia' library is needed to read the Unadjusted System Time (UST). + dnl + AC_CHECK_LIB(pthread, pthread_create, , AC_MSG_ERROR([IRIX posix thread library not found!])) + AC_CHECK_LIB(audio, alOpenPort, , AC_MSG_ERROR([IRIX audio library not found!])) + AC_CHECK_LIB(dmedia, dmGetUST, , AC_MSG_ERROR([IRIX digital media library not found!])) + + dnl See the '#ifdef PA_USE_SGI' in file pa_unix/pa_unix_hostapis.c + dnl which selects the appropriate PaXXX_Initialize() function. + dnl + AC_DEFINE(PA_USE_SGI,1) + + CFLAGS="$CFLAGS -I\$(top_srcdir)/src/os/unix" + + dnl The _REENTRANT option for pthread safety. Perhaps not necessary but it 'll do no harm. + dnl + THREAD_CFLAGS="-D_REENTRANT" + + OTHER_OBJS="pa_sgi/pa_sgi.o src/os/unix/pa_unix_hostapis.o src/os/unix/pa_unix_util.o" + + dnl SGI books say -lpthread should be the last of the libs mentioned. + dnl + LIBS="-lm -ldmedia -laudio -lpthread" + PADLL="libportaudio.so" + SHARED_FLAGS="" + ;; + + *) + dnl Unix configuration + + CFLAGS="$CFLAGS -I\$(top_srcdir)/src/os/unix" + + AC_CHECK_LIB(pthread, pthread_create,[have_pthread="yes"], + AC_MSG_ERROR([libpthread not found!])) + + if [[ "$have_alsa" = "yes" ] && [ "$with_alsa" != "no" ]] ; then + DLL_LIBS="$DLL_LIBS -lasound" + LIBS="$LIBS -lasound" + OTHER_OBJS="$OTHER_OBJS src/hostapi/alsa/pa_linux_alsa.o" + INCLUDES="$INCLUDES pa_linux_alsa.h" + AC_DEFINE(PA_USE_ALSA,1) + fi + + if [[ "$have_jack" = "yes" ] && [ "$with_jack" != "no" ]] ; then + DLL_LIBS="$DLL_LIBS $JACK_LIBS" + CFLAGS="$CFLAGS $JACK_CFLAGS" + OTHER_OBJS="$OTHER_OBJS src/hostapi/jack/pa_jack.o src/common/pa_ringbuffer.o" + INCLUDES="$INCLUDES pa_jack.h" + AC_DEFINE(PA_USE_JACK,1) + fi + + if [[ "$with_oss" != "no" ]] ; then + OTHER_OBJS="$OTHER_OBJS src/hostapi/oss/pa_unix_oss.o" + if [[ "$have_libossaudio" = "yes" ]] ; then + DLL_LIBS="$DLL_LIBS -lossaudio" + LIBS="$LIBS -lossaudio" + fi + AC_DEFINE(PA_USE_OSS,1) + fi + + if [[ "$have_asihpi" = "yes" ] && [ "$with_asihpi" != "no" ]] ; then + LIBS="$LIBS -lhpi" + DLL_LIBS="$DLL_LIBS -lhpi" + OTHER_OBJS="$OTHER_OBJS src/hostapi/asihpi/pa_linux_asihpi.o" + AC_DEFINE(PA_USE_ASIHPI,1) + fi + + DLL_LIBS="$DLL_LIBS -lm -lpthread" + LIBS="$LIBS -lm -lpthread" + PADLL="libportaudio.so" + + ## support sun cc compiler flags + case "${host_os}" in + solaris*) + SHARED_FLAGS="-G" + THREAD_CFLAGS="-mt" + ;; + *) + SHARED_FLAGS="-fPIC" + THREAD_CFLAGS="-pthread" + ;; + esac + + OTHER_OBJS="$OTHER_OBJS src/os/unix/pa_unix_hostapis.o src/os/unix/pa_unix_util.o" +esac +CFLAGS="$CFLAGS $THREAD_CFLAGS" + +test "$enable_shared" != "yes" && SHARED_FLAGS="" + +if test "$enable_cxx" = "yes"; then + AC_CONFIG_SUBDIRS([bindings/cpp]) + ENABLE_CXX_TRUE="" + ENABLE_CXX_FALSE="#" +else + ENABLE_CXX_TRUE="#" + ENABLE_CXX_FALSE="" +fi +AC_SUBST(ENABLE_CXX_TRUE) +AC_SUBST(ENABLE_CXX_FALSE) + +if test "x$with_asio" = "xyes"; then + WITH_ASIO_TRUE="" + WITH_ASIO_FALSE="@ #" +else + WITH_ASIO_TRUE="@ #" + WITH_ASIO_FALSE="" +fi +AC_SUBST(WITH_ASIO_TRUE) +AC_SUBST(WITH_ASIO_FALSE) + +AC_OUTPUT([Makefile portaudio-2.0.pc]) + +AC_MSG_RESULT([ +Configuration summary: + + Target ...................... $target + C++ bindings ................ $enable_cxx + Debug output ................ $debug_output]) + +case "$target_os" in *linux*) + AC_MSG_RESULT([ + ALSA ........................ $have_alsa + ASIHPI ...................... $have_asihpi]) + ;; +esac +case "$target_os" in + *mingw* | *cygwin*) + test "x$with_directx" = "xyes" && with_directx="$with_directx (${with_dxdir})" + test "x$with_wdmks" = "xyes" && with_wdmks="$with_wdmks (${with_dxdir})" + test "x$with_asio" = "xyes" && with_asio="$with_asio (${with_asiodir})" + test "x$with_wasapi" = "xyes" + AC_MSG_RESULT([ + WMME ........................ $with_wmme + DSound ...................... $with_directx + ASIO ........................ $with_asio + WASAPI ...................... $with_wasapi + WDMKS ....................... $with_wdmks +]) + ;; + *darwin*) + AC_MSG_RESULT([ + Mac debug flags ............. $enable_mac_debug +]) + ;; + *) + AC_MSG_RESULT([ + OSS ......................... $have_oss + JACK ........................ $have_jack +]) + ;; +esac diff --git a/extern/portaudio/depcomp b/extern/portaudio/depcomp new file mode 100755 index 0000000..4ebd5b3 --- /dev/null +++ b/extern/portaudio/depcomp @@ -0,0 +1,791 @@ +#! /bin/sh +# depcomp - compile a program generating dependencies as side-effects + +scriptversion=2013-05-30.07; # UTC + +# Copyright (C) 1999-2013 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# Originally written by Alexandre Oliva . + +case $1 in + '') + echo "$0: No command. Try '$0 --help' for more information." 1>&2 + exit 1; + ;; + -h | --h*) + cat <<\EOF +Usage: depcomp [--help] [--version] PROGRAM [ARGS] + +Run PROGRAMS ARGS to compile a file, generating dependencies +as side-effects. + +Environment variables: + depmode Dependency tracking mode. + source Source file read by 'PROGRAMS ARGS'. + object Object file output by 'PROGRAMS ARGS'. + DEPDIR directory where to store dependencies. + depfile Dependency file to output. + tmpdepfile Temporary file to use when outputting dependencies. + libtool Whether libtool is used (yes/no). + +Report bugs to . +EOF + exit $? + ;; + -v | --v*) + echo "depcomp $scriptversion" + exit $? + ;; +esac + +# Get the directory component of the given path, and save it in the +# global variables '$dir'. Note that this directory component will +# be either empty or ending with a '/' character. This is deliberate. +set_dir_from () +{ + case $1 in + */*) dir=`echo "$1" | sed -e 's|/[^/]*$|/|'`;; + *) dir=;; + esac +} + +# Get the suffix-stripped basename of the given path, and save it the +# global variable '$base'. +set_base_from () +{ + base=`echo "$1" | sed -e 's|^.*/||' -e 's/\.[^.]*$//'` +} + +# If no dependency file was actually created by the compiler invocation, +# we still have to create a dummy depfile, to avoid errors with the +# Makefile "include basename.Plo" scheme. +make_dummy_depfile () +{ + echo "#dummy" > "$depfile" +} + +# Factor out some common post-processing of the generated depfile. +# Requires the auxiliary global variable '$tmpdepfile' to be set. +aix_post_process_depfile () +{ + # If the compiler actually managed to produce a dependency file, + # post-process it. + if test -f "$tmpdepfile"; then + # Each line is of the form 'foo.o: dependency.h'. + # Do two passes, one to just change these to + # $object: dependency.h + # and one to simply output + # dependency.h: + # which is needed to avoid the deleted-header problem. + { sed -e "s,^.*\.[$lower]*:,$object:," < "$tmpdepfile" + sed -e "s,^.*\.[$lower]*:[$tab ]*,," -e 's,$,:,' < "$tmpdepfile" + } > "$depfile" + rm -f "$tmpdepfile" + else + make_dummy_depfile + fi +} + +# A tabulation character. +tab=' ' +# A newline character. +nl=' +' +# Character ranges might be problematic outside the C locale. +# These definitions help. +upper=ABCDEFGHIJKLMNOPQRSTUVWXYZ +lower=abcdefghijklmnopqrstuvwxyz +digits=0123456789 +alpha=${upper}${lower} + +if test -z "$depmode" || test -z "$source" || test -z "$object"; then + echo "depcomp: Variables source, object and depmode must be set" 1>&2 + exit 1 +fi + +# Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po. +depfile=${depfile-`echo "$object" | + sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`} +tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`} + +rm -f "$tmpdepfile" + +# Avoid interferences from the environment. +gccflag= dashmflag= + +# Some modes work just like other modes, but use different flags. We +# parameterize here, but still list the modes in the big case below, +# to make depend.m4 easier to write. Note that we *cannot* use a case +# here, because this file can only contain one case statement. +if test "$depmode" = hp; then + # HP compiler uses -M and no extra arg. + gccflag=-M + depmode=gcc +fi + +if test "$depmode" = dashXmstdout; then + # This is just like dashmstdout with a different argument. + dashmflag=-xM + depmode=dashmstdout +fi + +cygpath_u="cygpath -u -f -" +if test "$depmode" = msvcmsys; then + # This is just like msvisualcpp but w/o cygpath translation. + # Just convert the backslash-escaped backslashes to single forward + # slashes to satisfy depend.m4 + cygpath_u='sed s,\\\\,/,g' + depmode=msvisualcpp +fi + +if test "$depmode" = msvc7msys; then + # This is just like msvc7 but w/o cygpath translation. + # Just convert the backslash-escaped backslashes to single forward + # slashes to satisfy depend.m4 + cygpath_u='sed s,\\\\,/,g' + depmode=msvc7 +fi + +if test "$depmode" = xlc; then + # IBM C/C++ Compilers xlc/xlC can output gcc-like dependency information. + gccflag=-qmakedep=gcc,-MF + depmode=gcc +fi + +case "$depmode" in +gcc3) +## gcc 3 implements dependency tracking that does exactly what +## we want. Yay! Note: for some reason libtool 1.4 doesn't like +## it if -MD -MP comes after the -MF stuff. Hmm. +## Unfortunately, FreeBSD c89 acceptance of flags depends upon +## the command line argument order; so add the flags where they +## appear in depend2.am. Note that the slowdown incurred here +## affects only configure: in makefiles, %FASTDEP% shortcuts this. + for arg + do + case $arg in + -c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;; + *) set fnord "$@" "$arg" ;; + esac + shift # fnord + shift # $arg + done + "$@" + stat=$? + if test $stat -ne 0; then + rm -f "$tmpdepfile" + exit $stat + fi + mv "$tmpdepfile" "$depfile" + ;; + +gcc) +## Note that this doesn't just cater to obsosete pre-3.x GCC compilers. +## but also to in-use compilers like IMB xlc/xlC and the HP C compiler. +## (see the conditional assignment to $gccflag above). +## There are various ways to get dependency output from gcc. Here's +## why we pick this rather obscure method: +## - Don't want to use -MD because we'd like the dependencies to end +## up in a subdir. Having to rename by hand is ugly. +## (We might end up doing this anyway to support other compilers.) +## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like +## -MM, not -M (despite what the docs say). Also, it might not be +## supported by the other compilers which use the 'gcc' depmode. +## - Using -M directly means running the compiler twice (even worse +## than renaming). + if test -z "$gccflag"; then + gccflag=-MD, + fi + "$@" -Wp,"$gccflag$tmpdepfile" + stat=$? + if test $stat -ne 0; then + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + echo "$object : \\" > "$depfile" + # The second -e expression handles DOS-style file names with drive + # letters. + sed -e 's/^[^:]*: / /' \ + -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile" +## This next piece of magic avoids the "deleted header file" problem. +## The problem is that when a header file which appears in a .P file +## is deleted, the dependency causes make to die (because there is +## typically no way to rebuild the header). We avoid this by adding +## dummy dependencies for each header file. Too bad gcc doesn't do +## this for us directly. +## Some versions of gcc put a space before the ':'. On the theory +## that the space means something, we add a space to the output as +## well. hp depmode also adds that space, but also prefixes the VPATH +## to the object. Take care to not repeat it in the output. +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + tr ' ' "$nl" < "$tmpdepfile" \ + | sed -e 's/^\\$//' -e '/^$/d' -e "s|.*$object$||" -e '/:$/d' \ + | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +hp) + # This case exists only to let depend.m4 do its work. It works by + # looking at the text of this script. This case will never be run, + # since it is checked for above. + exit 1 + ;; + +sgi) + if test "$libtool" = yes; then + "$@" "-Wp,-MDupdate,$tmpdepfile" + else + "$@" -MDupdate "$tmpdepfile" + fi + stat=$? + if test $stat -ne 0; then + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + + if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files + echo "$object : \\" > "$depfile" + # Clip off the initial element (the dependent). Don't try to be + # clever and replace this with sed code, as IRIX sed won't handle + # lines with more than a fixed number of characters (4096 in + # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines; + # the IRIX cc adds comments like '#:fec' to the end of the + # dependency line. + tr ' ' "$nl" < "$tmpdepfile" \ + | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' \ + | tr "$nl" ' ' >> "$depfile" + echo >> "$depfile" + # The second pass generates a dummy entry for each header file. + tr ' ' "$nl" < "$tmpdepfile" \ + | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \ + >> "$depfile" + else + make_dummy_depfile + fi + rm -f "$tmpdepfile" + ;; + +xlc) + # This case exists only to let depend.m4 do its work. It works by + # looking at the text of this script. This case will never be run, + # since it is checked for above. + exit 1 + ;; + +aix) + # The C for AIX Compiler uses -M and outputs the dependencies + # in a .u file. In older versions, this file always lives in the + # current directory. Also, the AIX compiler puts '$object:' at the + # start of each line; $object doesn't have directory information. + # Version 6 uses the directory in both cases. + set_dir_from "$object" + set_base_from "$object" + if test "$libtool" = yes; then + tmpdepfile1=$dir$base.u + tmpdepfile2=$base.u + tmpdepfile3=$dir.libs/$base.u + "$@" -Wc,-M + else + tmpdepfile1=$dir$base.u + tmpdepfile2=$dir$base.u + tmpdepfile3=$dir$base.u + "$@" -M + fi + stat=$? + if test $stat -ne 0; then + rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" + exit $stat + fi + + for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" + do + test -f "$tmpdepfile" && break + done + aix_post_process_depfile + ;; + +tcc) + # tcc (Tiny C Compiler) understand '-MD -MF file' since version 0.9.26 + # FIXME: That version still under development at the moment of writing. + # Make that this statement remains true also for stable, released + # versions. + # It will wrap lines (doesn't matter whether long or short) with a + # trailing '\', as in: + # + # foo.o : \ + # foo.c \ + # foo.h \ + # + # It will put a trailing '\' even on the last line, and will use leading + # spaces rather than leading tabs (at least since its commit 0394caf7 + # "Emit spaces for -MD"). + "$@" -MD -MF "$tmpdepfile" + stat=$? + if test $stat -ne 0; then + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + # Each non-empty line is of the form 'foo.o : \' or ' dep.h \'. + # We have to change lines of the first kind to '$object: \'. + sed -e "s|.*:|$object :|" < "$tmpdepfile" > "$depfile" + # And for each line of the second kind, we have to emit a 'dep.h:' + # dummy dependency, to avoid the deleted-header problem. + sed -n -e 's|^ *\(.*\) *\\$|\1:|p' < "$tmpdepfile" >> "$depfile" + rm -f "$tmpdepfile" + ;; + +## The order of this option in the case statement is important, since the +## shell code in configure will try each of these formats in the order +## listed in this file. A plain '-MD' option would be understood by many +## compilers, so we must ensure this comes after the gcc and icc options. +pgcc) + # Portland's C compiler understands '-MD'. + # Will always output deps to 'file.d' where file is the root name of the + # source file under compilation, even if file resides in a subdirectory. + # The object file name does not affect the name of the '.d' file. + # pgcc 10.2 will output + # foo.o: sub/foo.c sub/foo.h + # and will wrap long lines using '\' : + # foo.o: sub/foo.c ... \ + # sub/foo.h ... \ + # ... + set_dir_from "$object" + # Use the source, not the object, to determine the base name, since + # that's sadly what pgcc will do too. + set_base_from "$source" + tmpdepfile=$base.d + + # For projects that build the same source file twice into different object + # files, the pgcc approach of using the *source* file root name can cause + # problems in parallel builds. Use a locking strategy to avoid stomping on + # the same $tmpdepfile. + lockdir=$base.d-lock + trap " + echo '$0: caught signal, cleaning up...' >&2 + rmdir '$lockdir' + exit 1 + " 1 2 13 15 + numtries=100 + i=$numtries + while test $i -gt 0; do + # mkdir is a portable test-and-set. + if mkdir "$lockdir" 2>/dev/null; then + # This process acquired the lock. + "$@" -MD + stat=$? + # Release the lock. + rmdir "$lockdir" + break + else + # If the lock is being held by a different process, wait + # until the winning process is done or we timeout. + while test -d "$lockdir" && test $i -gt 0; do + sleep 1 + i=`expr $i - 1` + done + fi + i=`expr $i - 1` + done + trap - 1 2 13 15 + if test $i -le 0; then + echo "$0: failed to acquire lock after $numtries attempts" >&2 + echo "$0: check lockdir '$lockdir'" >&2 + exit 1 + fi + + if test $stat -ne 0; then + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + # Each line is of the form `foo.o: dependent.h', + # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'. + # Do two passes, one to just change these to + # `$object: dependent.h' and one to simply `dependent.h:'. + sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile" + # Some versions of the HPUX 10.20 sed can't process this invocation + # correctly. Breaking it into two sed invocations is a workaround. + sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" \ + | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +hp2) + # The "hp" stanza above does not work with aCC (C++) and HP's ia64 + # compilers, which have integrated preprocessors. The correct option + # to use with these is +Maked; it writes dependencies to a file named + # 'foo.d', which lands next to the object file, wherever that + # happens to be. + # Much of this is similar to the tru64 case; see comments there. + set_dir_from "$object" + set_base_from "$object" + if test "$libtool" = yes; then + tmpdepfile1=$dir$base.d + tmpdepfile2=$dir.libs/$base.d + "$@" -Wc,+Maked + else + tmpdepfile1=$dir$base.d + tmpdepfile2=$dir$base.d + "$@" +Maked + fi + stat=$? + if test $stat -ne 0; then + rm -f "$tmpdepfile1" "$tmpdepfile2" + exit $stat + fi + + for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" + do + test -f "$tmpdepfile" && break + done + if test -f "$tmpdepfile"; then + sed -e "s,^.*\.[$lower]*:,$object:," "$tmpdepfile" > "$depfile" + # Add 'dependent.h:' lines. + sed -ne '2,${ + s/^ *// + s/ \\*$// + s/$/:/ + p + }' "$tmpdepfile" >> "$depfile" + else + make_dummy_depfile + fi + rm -f "$tmpdepfile" "$tmpdepfile2" + ;; + +tru64) + # The Tru64 compiler uses -MD to generate dependencies as a side + # effect. 'cc -MD -o foo.o ...' puts the dependencies into 'foo.o.d'. + # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put + # dependencies in 'foo.d' instead, so we check for that too. + # Subdirectories are respected. + set_dir_from "$object" + set_base_from "$object" + + if test "$libtool" = yes; then + # Libtool generates 2 separate objects for the 2 libraries. These + # two compilations output dependencies in $dir.libs/$base.o.d and + # in $dir$base.o.d. We have to check for both files, because + # one of the two compilations can be disabled. We should prefer + # $dir$base.o.d over $dir.libs/$base.o.d because the latter is + # automatically cleaned when .libs/ is deleted, while ignoring + # the former would cause a distcleancheck panic. + tmpdepfile1=$dir$base.o.d # libtool 1.5 + tmpdepfile2=$dir.libs/$base.o.d # Likewise. + tmpdepfile3=$dir.libs/$base.d # Compaq CCC V6.2-504 + "$@" -Wc,-MD + else + tmpdepfile1=$dir$base.d + tmpdepfile2=$dir$base.d + tmpdepfile3=$dir$base.d + "$@" -MD + fi + + stat=$? + if test $stat -ne 0; then + rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" + exit $stat + fi + + for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" + do + test -f "$tmpdepfile" && break + done + # Same post-processing that is required for AIX mode. + aix_post_process_depfile + ;; + +msvc7) + if test "$libtool" = yes; then + showIncludes=-Wc,-showIncludes + else + showIncludes=-showIncludes + fi + "$@" $showIncludes > "$tmpdepfile" + stat=$? + grep -v '^Note: including file: ' "$tmpdepfile" + if test $stat -ne 0; then + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + echo "$object : \\" > "$depfile" + # The first sed program below extracts the file names and escapes + # backslashes for cygpath. The second sed program outputs the file + # name when reading, but also accumulates all include files in the + # hold buffer in order to output them again at the end. This only + # works with sed implementations that can handle large buffers. + sed < "$tmpdepfile" -n ' +/^Note: including file: *\(.*\)/ { + s//\1/ + s/\\/\\\\/g + p +}' | $cygpath_u | sort -u | sed -n ' +s/ /\\ /g +s/\(.*\)/'"$tab"'\1 \\/p +s/.\(.*\) \\/\1:/ +H +$ { + s/.*/'"$tab"'/ + G + p +}' >> "$depfile" + echo >> "$depfile" # make sure the fragment doesn't end with a backslash + rm -f "$tmpdepfile" + ;; + +msvc7msys) + # This case exists only to let depend.m4 do its work. It works by + # looking at the text of this script. This case will never be run, + # since it is checked for above. + exit 1 + ;; + +#nosideeffect) + # This comment above is used by automake to tell side-effect + # dependency tracking mechanisms from slower ones. + +dashmstdout) + # Important note: in order to support this mode, a compiler *must* + # always write the preprocessed file to stdout, regardless of -o. + "$@" || exit $? + + # Remove the call to Libtool. + if test "$libtool" = yes; then + while test "X$1" != 'X--mode=compile'; do + shift + done + shift + fi + + # Remove '-o $object'. + IFS=" " + for arg + do + case $arg in + -o) + shift + ;; + $object) + shift + ;; + *) + set fnord "$@" "$arg" + shift # fnord + shift # $arg + ;; + esac + done + + test -z "$dashmflag" && dashmflag=-M + # Require at least two characters before searching for ':' + # in the target name. This is to cope with DOS-style filenames: + # a dependency such as 'c:/foo/bar' could be seen as target 'c' otherwise. + "$@" $dashmflag | + sed "s|^[$tab ]*[^:$tab ][^:][^:]*:[$tab ]*|$object: |" > "$tmpdepfile" + rm -f "$depfile" + cat < "$tmpdepfile" > "$depfile" + # Some versions of the HPUX 10.20 sed can't process this sed invocation + # correctly. Breaking it into two sed invocations is a workaround. + tr ' ' "$nl" < "$tmpdepfile" \ + | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \ + | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +dashXmstdout) + # This case only exists to satisfy depend.m4. It is never actually + # run, as this mode is specially recognized in the preamble. + exit 1 + ;; + +makedepend) + "$@" || exit $? + # Remove any Libtool call + if test "$libtool" = yes; then + while test "X$1" != 'X--mode=compile'; do + shift + done + shift + fi + # X makedepend + shift + cleared=no eat=no + for arg + do + case $cleared in + no) + set ""; shift + cleared=yes ;; + esac + if test $eat = yes; then + eat=no + continue + fi + case "$arg" in + -D*|-I*) + set fnord "$@" "$arg"; shift ;; + # Strip any option that makedepend may not understand. Remove + # the object too, otherwise makedepend will parse it as a source file. + -arch) + eat=yes ;; + -*|$object) + ;; + *) + set fnord "$@" "$arg"; shift ;; + esac + done + obj_suffix=`echo "$object" | sed 's/^.*\././'` + touch "$tmpdepfile" + ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@" + rm -f "$depfile" + # makedepend may prepend the VPATH from the source file name to the object. + # No need to regex-escape $object, excess matching of '.' is harmless. + sed "s|^.*\($object *:\)|\1|" "$tmpdepfile" > "$depfile" + # Some versions of the HPUX 10.20 sed can't process the last invocation + # correctly. Breaking it into two sed invocations is a workaround. + sed '1,2d' "$tmpdepfile" \ + | tr ' ' "$nl" \ + | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \ + | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" "$tmpdepfile".bak + ;; + +cpp) + # Important note: in order to support this mode, a compiler *must* + # always write the preprocessed file to stdout. + "$@" || exit $? + + # Remove the call to Libtool. + if test "$libtool" = yes; then + while test "X$1" != 'X--mode=compile'; do + shift + done + shift + fi + + # Remove '-o $object'. + IFS=" " + for arg + do + case $arg in + -o) + shift + ;; + $object) + shift + ;; + *) + set fnord "$@" "$arg" + shift # fnord + shift # $arg + ;; + esac + done + + "$@" -E \ + | sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \ + -e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \ + | sed '$ s: \\$::' > "$tmpdepfile" + rm -f "$depfile" + echo "$object : \\" > "$depfile" + cat < "$tmpdepfile" >> "$depfile" + sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +msvisualcpp) + # Important note: in order to support this mode, a compiler *must* + # always write the preprocessed file to stdout. + "$@" || exit $? + + # Remove the call to Libtool. + if test "$libtool" = yes; then + while test "X$1" != 'X--mode=compile'; do + shift + done + shift + fi + + IFS=" " + for arg + do + case "$arg" in + -o) + shift + ;; + $object) + shift + ;; + "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI") + set fnord "$@" + shift + shift + ;; + *) + set fnord "$@" "$arg" + shift + shift + ;; + esac + done + "$@" -E 2>/dev/null | + sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile" + rm -f "$depfile" + echo "$object : \\" > "$depfile" + sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::'"$tab"'\1 \\:p' >> "$depfile" + echo "$tab" >> "$depfile" + sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +msvcmsys) + # This case exists only to let depend.m4 do its work. It works by + # looking at the text of this script. This case will never be run, + # since it is checked for above. + exit 1 + ;; + +none) + exec "$@" + ;; + +*) + echo "Unknown depmode $depmode" 1>&2 + exit 1 + ;; +esac + +exit 0 + +# Local Variables: +# mode: shell-script +# sh-indentation: 2 +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-time-zone: "UTC" +# time-stamp-end: "; # UTC" +# End: diff --git a/extern/portaudio/doc/src/api_overview.dox b/extern/portaudio/doc/src/api_overview.dox new file mode 100644 index 0000000..98a0dbd --- /dev/null +++ b/extern/portaudio/doc/src/api_overview.dox @@ -0,0 +1,162 @@ +/** @page api_overview PortAudio API Overview + +This page provides a top-down overview of the entire PortAudio API. It describes how all of the PortAudio data types and functions fit together. It provides links to the documentation for each function and data type. You can find all of the detailed documentation for each API function and data type on the portaudio.h page. + +@section introduction Introduction + +PortAudio provides a uniform application programming interface (API) across all supported platforms. You can think of the PortAudio library as a wrapper that converts calls to the PortAudio API into calls to platform-specific native audio APIs. Operating systems often offer more than one native audio API and some APIs (such as JACK) may be available on multiple target operating systems. PortAudio supports all the major native audio APIs on each supported platform. The diagram below illustrates the relationship between your application, PortAudio, and the supported native audio APIs: + +@image html portaudio-external-architecture-diagram.png + +PortAudio provides a uniform interface to native audio APIs. However, it doesn't always provide totally uniform functionality. There are cases where PortAudio is limited by the capabilities of the underlying native audio API. For example, PortAudio doesn't provide sample rate conversion if you request a sample rate that is not supported by the native audio API. Another example is that the ASIO SDK only allows one device to be open at a time, so PortAudio/ASIO doesn't currently support opening multiple ASIO devices simultaneously. + +@section key_abstractions Key abstractions: Host APIs, Devices and Streams + +The PortAudio processing model includes three main abstractions: Host APIs, audio Devices and audio Streams. + +Host APIs represent platform-specific native audio APIs. Some examples of Host APIs are Core Audio on Mac OS, WMME and DirectSound on Windows and OSS and ALSA on Linux. The diagram in the previous section shows many of the supported native APIs. Sometimes it's useful to know which Host APIs you're dealing with, but it is easy to use PortAudio without ever interacting directly with the Host API abstraction. + +Devices represent individual hardware audio interfaces or audio ports on the host platform. Devices have names and certain capabilities such as supported sample rates and the number of supported input and output channels. PortAudio provides functions to enumerate available Devices and to query for Device capabilities. + +Streams manage active audio input and output from and to Devices. Streams may be half duplex (input or output) or full duplex (simultaneous input and output). Streams operate at a specific sample rate with particular sample formats, buffer sizes and internal buffering latencies. You specify these parameters when you open the Stream. Audio data is communicated between a Stream and your application via a user provided asynchronous callback function or by invoking synchronous read and write functions. + +PortAudio supports audio input and output in a variety of sample formats: 8, 16, 24 and 32 bit integer formats and 32 bit floating point, irrespective of the formats supported by the native audio API. PortAudio also supports multichannel buffers in both interleaved and non-interleaved (separate buffer per channel) formats and automatically performs conversion when necessary. If requested, PortAudio can clamp out-of range samples and/or dither to a native format. + +The PortAudio API offers the following functionality: +- Initialize and terminate the library +- Enumerate available Host APIs +- Enumerate available Devices either globally, or within each Host API +- Discover default or recommended Devices and Device settings +- Discover Device capabilities such as supported audio data formats and sample rates +- Create and control audio Streams to acquire audio from and output audio to Devices +- Provide Stream timing information to support synchronising audio with other parts of your application +- Retrieve version and error information. + +These functions are described in more detail below. + + +@section top_level_functions Initialization, termination and utility functions + +The PortAudio library must be initialized before it can be used and terminated to clean up afterwards. You initialize PortAudio by calling Pa_Initialize() and clean up by calling Pa_Terminate(). + +You can query PortAudio for version information using Pa_GetVersion() to get a numeric version number and Pa_GetVersionText() to get a string. + +The size in bytes of the various sample formats represented by the @ref PaSampleFormat enumeration can be obtained using Pa_GetSampleSize(). + +Pa_Sleep() sleeps for a specified number of milliseconds. This isn't intended for use in production systems; it's provided only as a simple portable way to implement tests and examples where the main thread sleeps while audio is acquired or played by an asynchronous callback function. + +@section host_apis Host APIs + +A Host API acts as a top-level grouping for all of the Devices offered by a single native platform audio API. Each Host API has a unique type identifier, a name, zero or more Devices, and nominated default input and output Devices. + +Host APIs are usually referenced by index: an integer of type @ref PaHostApiIndex that ranges between zero and Pa_GetHostApiCount() - 1. You can enumerate all available Host APIs by counting across this range. + +You can retrieve the index of the default Host API by calling Pa_GetDefaultHostApi(). + +Information about a Host API, such as it's name and default devices, is stored in a @ref PaHostApiInfo structure. You can retrieve a pointer to a particular Host API's @ref PaHostApiInfo structure by calling Pa_GetHostApiInfo() with the Host API's index as a parameter. + +Most PortAudio functions reference Host APIs by @ref PaHostApiIndex indices. Each Host API also has a unique type identifier defined in the @ref PaHostApiTypeId enumeration. +You can call Pa_HostApiTypeIdToHostApiIndex() to retrieve the current @ref PaHostApiIndex for a particular @ref PaHostApiTypeId. + +@section devices Devices + +A Device represents an audio endpoint provided by a particular native audio API. This usually corresponds to a specific input or output port on a hardware audio interface, or to the interface as a whole. Each Host API operates independently, so a single physical audio port may be addressable via different Devices exposed by different Host APIs. + +A Device has a name, is associated with a Host API, and has a maximum number of supported input and output channels. PortAudio provides recommended default latency values and a default sample rate for each Device. To obtain more detailed information about device capabilities you can call Pa_IsFormatSupported() to query whether it is possible to open a Stream using particular Devices, parameters and sample rate. + +Although each Device conceptually belongs to a specific Host API, most PortAudio functions and data structures refer to Devices using a global, Host API-independent index of type @ref PaDeviceIndex – an integer of that ranges between zero and Pa_GetDeviceCount() - 1. The reasons for this are partly historical but it also makes it easy for applications to ignore the Host API abstraction and just work with Devices and Streams. + +If you want to enumerate Devices belonging to a particular Host API you can count between 0 and PaHostApiInfo::deviceCount - 1. You can convert this Host API-specific index value to a global @ref PaDeviceIndex value by calling Pa_HostApiDeviceIndexToDeviceIndex(). + +Information about a Device is stored in a @ref PaDeviceInfo structure. You can retrieve a pointer to a Devices's @ref PaDeviceInfo structure by calling Pa_GetDeviceInfo() with the Device's index as a parameter. + +You can retrieve the indices of the global default input and output devices using Pa_GetDefaultInputDevice() and Pa_GetDefaultOutputDevice(). Default Devices for each Host API are stored in the Host API's @ref PaHostApiInfo structures. + +For an example of enumerating devices and printing information about their capabilities see the pa_devs.c program in the test directory of the PortAudio distribution. + +@section streams Streams + +A Stream represents an active flow of audio data between your application and one or more audio Devices. A Stream operates at a specific sample rate with specific sample formats and buffer sizes. + +@subsection io_methods I/O Methods: callback and read/write + +PortAudio offers two methods for communicating audio data between an open Stream and your Application: (1) an asynchronous callback interface, where PortAudio calls a user defined callback function when new audio data is available or required, and (2) synchronous read and write functions which can be used in a blocking or non-blocking manner. You choose between the two methods when you open a Stream. The two methods are discussed in more detail below. + +@subsection opening_and_closing_streams Opening and Closing Streams + +You call Pa_OpenStream() to open a Stream, specifying the Device(s) to use, the number of input and output channels, sample formats, suggested latency values and flags that control dithering, clipping and overflow handling. You specify many of these parameters in two PaStreamParameters structures, one for input and one for output. If you're using the callback I/O method you also pass a callback buffer size, callback function pointer and user data pointer. + +Devices may be full duplex (supporting simultaneous input and output) or half duplex (supporting input or output) – usually this reflects the structure of the underlying native audio API. When opening a Stream you can specify one full duplex Device for both input and output, or two different Devices for input and output. Some Host APIs only support full-duplex operation with a full-duplex device (e.g. ASIO) but most are able to aggregate two half duplex devices into a full duplex Stream. PortAudio requires that all devices specified in a call to Pa_OpenStream() belong to the same Host API. + +A successful call to Pa_OpenStream() creates a pointer to a @ref PaStream – an opaque handle representing the open Stream. All PortAudio API functions that operate on open Streams take a pointer to a @ref PaStream as their first parameter. + +PortAudio also provides Pa_OpenDefaultStream() – a simpler alternative to Pa_OpenStream() which you can use when you want to open the default audio Device(s) with default latency parameters. + +You call Pa_CloseStream() to close a Stream when you've finished using it. + +@subsection starting_and_stopping_streams Starting and Stopping Streams + +Newly opened Streams are initially stopped. You call Pa_StartStream() to start a Stream. You can stop a running Stream using Pa_StopStream() or Pa_AbortStream() (the Stop function plays out all internally queued audio data, while Abort tries to stop as quickly as possible). An open Stream can be started and stopped multiple times. You can call Pa_IsStreamStopped() to query whether a Stream is running or stopped. + +By calling Pa_SetStreamFinishedCallback() it is possible to register a special @ref PaStreamFinishedCallback that will be called when the Stream has completed playing any internally queued buffers. This can be used in conjunction with the @ref paComplete stream callback return value (see below) to avoid blocking on a call to Pa_StopStream() while queued audio data is still playing. + +@subsection callback_io_method The Callback I/O Method + +So-called 'callback Streams' operate by periodically invoking a callback function you supply to Pa_OpenStream(). The callback function must implement the @ref PaStreamCallback signature. It gets called by PortAudio every time PortAudio needs your application to consume or produce audio data. The callback is passed pointers to buffers containing the audio to process. The format (interleave, sample data type) and size of these buffers is determined by the parameters passed to Pa_OpenStream() when the Stream was opened. + +Stream callbacks usually return @ref paContinue to indicate that PortAudio should keep the stream running. It is possible to deactivate a Stream from the stream callback by returning either @ref paComplete or @ref paAbort. In this case the Stream enters a deactivated state after the last buffer has finished playing (@ref paComplete) or as soon as possible (@ref paAbort). You can detect the deactivated state by calling Pa_IsStreamActive() or by using Pa_SetStreamFinishedCallback() to subscribe to a stream finished notification. Note that even if the stream callback returns @ref paComplete it's still necessary to call Pa_StopStream() or Pa_AbortStream() to enter the stopped state. + +Many of the tests in the /tests directory of the PortAudio distribution implement PortAudio stream callbacks. For example see: patest_sine.c (audio output), patest_record.c (audio input), patest_wire.c (audio pass-through) and pa_fuzz.c (simple audio effects processing). + +IMPORTANT: The stream callback function often needs to operate with very high or real-time priority. As a result there are strict requirements placed on the type of code that can be executed in a stream callback. In general this means avoiding any code that might block, including: acquiring locks, calling OS API functions including allocating memory. With the exception of Pa_GetStreamCpuLoad() you may not call PortAudio API functions from within the stream callback. + +@subsection read_write_io_method The Read/Write I/O Method + +As an alternative to the callback I/O method, PortAudio provides a synchronous read/write interface for acquiring and playing audio. This can be useful for applications that don't require the lowest possibly latency, or don't warrant the increased complexity of synchronising with an asynchronous callback funciton. This I/O method is also useful when calling PortAudio from programming languages that don't support asynchronous callbacks. + +To open a Stream in read/write mode you pass a NULL stream callback function pointer to Pa_OpenStream(). + +To write audio data to a Stream call Pa_WriteStream() and to read data call Pa_ReadStream(). These functions will block if the internal buffers are full, making them safe to call in a tight loop. If you want to avoid blocking you can query the amount of available read or write space using Pa_GetStreamReadAvailable() or Pa_GetStreamWriteAvailable() and use the returned values to limit the amount of data you read or write. + +For examples of the read/write I/O method see the following examples in the /tests directory of the PortAudio distribution: patest_read_record.c (audio input), patest_write_sine.c (audio output), patest_read_write_wire.c (audio pass-through). + +@subsection stream_info Retrieving Stream Information + +You can retrieve information about an open Stream by calling Pa_GetStreamInfo(). This returns a @ref PaStreamInfo structure containing the actual input and output latency and sample rate of the stream. It's possible for these values to be different from the suggested values passed to Pa_OpenStream(). + +When using a callback stream you can call Pa_GetStreamCpuLoad() to retrieve a rough estimate of the amount of CPU time your callback function is using. + +@subsection stream_timing Stream Timing Information + +When using the callback I/O method your stream callback function receives timing information via a pointer to a PaStreamCallbackTimeInfo structure. This structure contains the current time along with the estimated hardware capture and playback time of the first sample of the input and output buffers. All times are measured in seconds relative to a Stream-specific clock. The current Stream clock time can be retrieved using Pa_GetStreamTime(). + +You can use the stream callback @ref PaStreamCallbackTimeInfo times in conjunction with timestamps returned by Pa_GetStreamTime() to implement time synchronization schemes such as time aligning your GUI display with rendered audio, or maintaining synchronization between MIDI and audio playback. + +@section error_handling Error Handling + +Most PortAudio functions return error codes using values from the @ref PaError enumeration. All error codes are negative values. Some functions return values greater than or equal to zero for normal results and a negative error code in case of error. + +You can convert @ref PaError error codes to human readable text by calling Pa_GetErrorText(). + +PortAudio usually tries to translate error conditions into portable @ref PaError error codes. However if an unexpected error is encountered the @ref paUnanticipatedHostError code may be returned. In this case a further mechanism is provided to query for Host API-specific error information. If PortAudio returns @ref paUnanticipatedHostError you can call Pa_GetLastHostErrorInfo() to retrieve a pointer to a @ref PaHostErrorInfo structure that provides more information, including the Host API that encountered the error, a native API error code and error text. + +@section host_api_extensions Host API and Platform-specific Extensions + +The public PortAudio API only exposes functionality that can be provided across all target platforms. In some cases individual native audio APIs offer unique functionality. Some PortAudio Host APIs expose this functionality via Host API-specific extensions. Examples include access to low-level buffering and priority parameters, opening a Stream with only a subset of a Device's channels, or accessing channel metadata such as channel names. + +Host API-specific extensions are provided in the form of additional functions and data structures defined in Host API-specific header files found in the /include directory. + +The @ref PaStreamParameters structure passed to Pa_IsFormatSupported() and Pa_OpenStream() has a field named @ref PaStreamParameters::hostApiSpecificStreamInfo that is sometimes used to pass low level information when opening a Stream. + +See the documentation for the individual Host API-specific header files for details of the extended functionality they expose: + +- pa_asio.h +- pa_jack.h +- pa_linux_alsa.h +- pa_mac_core.h +- pa_win_ds.h +- pa_win_wasapi.h +- pa_win_wmme.h +- pa_win_waveformat.h + +*/ \ No newline at end of file diff --git a/extern/portaudio/doc/src/images/portaudio-external-architecture-diagram.png b/extern/portaudio/doc/src/images/portaudio-external-architecture-diagram.png new file mode 100644 index 0000000..64c0905 Binary files /dev/null and b/extern/portaudio/doc/src/images/portaudio-external-architecture-diagram.png differ diff --git a/extern/portaudio/doc/src/license.dox b/extern/portaudio/doc/src/license.dox new file mode 100644 index 0000000..8d0c51f --- /dev/null +++ b/extern/portaudio/doc/src/license.dox @@ -0,0 +1,38 @@ +/** @page License PortAudio License + +PortAudio Portable Real-Time Audio Library
    +Copyright (c) 1999-2011 Ross Bencina, Phil Burk + + + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files +(the "Software"), to deal in the Software without restriction, +including without limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of the Software, +and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR +ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +
    + +The text above constitutes the entire PortAudio license; however, +the PortAudio community also makes the following non-binding requests: + +Any person wishing to distribute modifications to the Software is +requested to send the modifications to the original developer so that +they can be incorporated into the canonical version. It is also +requested that these non-binding requests be included along with the +license above. + +*/ \ No newline at end of file diff --git a/extern/portaudio/doc/src/mainpage.dox b/extern/portaudio/doc/src/mainpage.dox new file mode 100644 index 0000000..7a54d32 --- /dev/null +++ b/extern/portaudio/doc/src/mainpage.dox @@ -0,0 +1,61 @@ +/* doxygen index page */ +/** @mainpage + +@section overview Overview + +PortAudio is a cross-platform, open-source C language library for real-time audio input and output. +The library provides functions that allow your software to acquire and output real-time audio streams from your computer's hardware audio interfaces. It is designed to simplify writing cross-platform audio applications, and also to simplify the development of audio software in general by hiding the complexities of dealing directly with each native audio API. PortAudio is used to implement sound recording, editing and mixing applications, software synthesizers, effects processors, music players, internet telephony applications, software defined radios and more. Supported platforms include MS Windows, Mac OS X and Linux. Third-party language bindings make it possible to call PortAudio from other programming languages including @ref java_binding "Java", C++, C#, Python, PureBasic, FreePascal and Lazarus. + +@section start_here Start here + +- @ref api_overview
    +A top-down view of the PortAudio API, its capabilities, functions and data structures + +- @ref tutorial_start
    +Get started writing code with PortAudio tutorials + +- @ref examples_src "Examples"
    +Simple example programs demonstrating PortAudio usage + +- @ref License
    +PortAudio is licenced under the MIT Expat open source licence. We make a non-binding request for you to contribute your changes back to the project. + + +@section reference API Reference + +- portaudio.h Portable API
    +Detailed documentation for each portable API function and data type + +- @ref public_header "Host API Specific Extensions"
    +Documentation for non-portable platform-specific host API extensions + + +@section resources Resources + +- The PortAudio website + +- Our mailing list for users and developers
    + +- The PortAudio wiki + +@section developer_resources Developer Resources + +@if INTERNAL +- @ref srcguide +@endif + +- Our wiki and issue tracking system + +- Developer guidelines + +- Implementation style guidelines + +If you're interested in helping out with PortAudio development we're more than happy for you to be involved. Just drop by the PortAudio mailing list and ask how you can help. Or check out the starter tickets. + + +@section older_api_versions Older API Versions + +This documentation covers the current API version: PortAudio V19, API version 2.0. API 2.0 differs in a number of ways from previous versions (most often encountered in PortAudio V18), please consult the enhancement proposals for details of what was added/changed for V19: +http://www.portaudio.com/docs/proposals/index.html + +*/ \ No newline at end of file diff --git a/extern/portaudio/doc/src/srcguide.dox b/extern/portaudio/doc/src/srcguide.dox new file mode 100644 index 0000000..26fd941 --- /dev/null +++ b/extern/portaudio/doc/src/srcguide.dox @@ -0,0 +1,55 @@ +/* + define all of the file groups used to structure the documentation. +*/ + +/** + @defgroup public_header Public API definitions for users of PortAudio +*/ + +/** + @internal + @defgroup common_src Source code common to all implementations +*/ + +/** + @internal + @defgroup win_src Source code common to all Windows implementations +*/ + +/** + @internal + @defgroup unix_src Source code common to all Unix implementations +*/ + +/** + @internal + @defgroup macosx_src Source code common to all Macintosh implementations +*/ + +/** + @internal + @defgroup hostapi_src Source code for specific Host APIs +*/ + +/** + @internal + @defgroup test_src Test programs +*/ + +/** + @defgroup examples_src Example programs demonstrating PortAudio usage +*/ + +/** + @internal + @page srcguide A guide to the PortAudio sources + + - \ref public_header + - \ref examples_src + - \ref common_src + - \ref win_src + - \ref unix_src + - \ref macosx_src + - \ref hostapi_src + - \ref test_src +*/ \ No newline at end of file diff --git a/extern/portaudio/doc/src/tutorial/blocking_read_write.dox b/extern/portaudio/doc/src/tutorial/blocking_read_write.dox new file mode 100644 index 0000000..8905ee3 --- /dev/null +++ b/extern/portaudio/doc/src/tutorial/blocking_read_write.dox @@ -0,0 +1,68 @@ +/** @page blocking_read_write Blocking Read/Write Functions +@ingroup tutorial + +PortAudio V19 adds a huge advance over previous versions with a feature called Blocking I/O. Although it may have lower performance that the callback method described earlier in this tutorial, blocking I/O is easier to understand and is, in some cases, more compatible with third party systems than the callback method. Most people starting audio programming also find Blocking I/O easier to learn. + +Blocking I/O works in much the same way as the callback method except that instead of providing a function to provide (or consume) audio data, you must feed data to (or consume data from) PortAudio at regular intervals, usually inside a loop. The example below, excepted from patest_read_write_wire.c, shows how to open the default device, and pass data from its input to its output for a set period of time. Note that we use the default high latency values to help avoid underruns since we are usually reading and writing audio data from a relatively low priority thread, and there is usually extra buffering required to make blocking I/O work. + +Note that not all API's implement Blocking I/O at this point, so for maximum portability or performance, you'll still want to use callbacks. + +@code + /* -- initialize PortAudio -- */ + err = Pa_Initialize(); + if( err != paNoError ) goto error; + + /* -- setup input and output -- */ + inputParameters.device = Pa_GetDefaultInputDevice(); /* default input device */ + inputParameters.channelCount = NUM_CHANNELS; + inputParameters.sampleFormat = PA_SAMPLE_TYPE; + inputParameters.suggestedLatency = Pa_GetDeviceInfo( inputParameters.device )->defaultHighInputLatency ; + inputParameters.hostApiSpecificStreamInfo = NULL; + + outputParameters.device = Pa_GetDefaultOutputDevice(); /* default output device */ + outputParameters.channelCount = NUM_CHANNELS; + outputParameters.sampleFormat = PA_SAMPLE_TYPE; + outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultHighOutputLatency; + outputParameters.hostApiSpecificStreamInfo = NULL; + + /* -- setup stream -- */ + err = Pa_OpenStream( + &stream, + &inputParameters, + &outputParameters, + SAMPLE_RATE, + FRAMES_PER_BUFFER, + paClipOff, /* we won't output out of range samples so don't bother clipping them */ + NULL, /* no callback, use blocking API */ + NULL ); /* no callback, so no callback userData */ + if( err != paNoError ) goto error; + + /* -- start stream -- */ + err = Pa_StartStream( stream ); + if( err != paNoError ) goto error; + printf("Wire on. Will run one minute.\n"); fflush(stdout); + + /* -- Here's the loop where we pass data from input to output -- */ + for( i=0; i<(60*SAMPLE_RATE)/FRAMES_PER_BUFFER; ++i ) + { + err = Pa_WriteStream( stream, sampleBlock, FRAMES_PER_BUFFER ); + if( err ) goto xrun; + err = Pa_ReadStream( stream, sampleBlock, FRAMES_PER_BUFFER ); + if( err ) goto xrun; + } + /* -- Now we stop the stream -- */ + err = Pa_StopStream( stream ); + if( err != paNoError ) goto error; + + /* -- don't forget to cleanup! -- */ + err = Pa_CloseStream( stream ); + if( err != paNoError ) goto error; + + Pa_Terminate(); + return 0; +@endcode + + +Previous: \ref querying_devices | Next: \ref exploring + +*/ \ No newline at end of file diff --git a/extern/portaudio/doc/src/tutorial/compile_cmake.dox b/extern/portaudio/doc/src/tutorial/compile_cmake.dox new file mode 100644 index 0000000..ab2a239 --- /dev/null +++ b/extern/portaudio/doc/src/tutorial/compile_cmake.dox @@ -0,0 +1,57 @@ +/** @page compile_cmake PortAudio on Windows, OS X or Linux via. CMake +@ingroup tutorial + +@section cmake_building Building PortAudio stand-alone on Windows, OS X or Linux + +CMake can be used to generate Visual Studio solutions on Windows, Makefiles (on Linux and OS X) and build metadata for other build systems for PortAudio. You should obtain a recent version of CMake from [http://www.cmake.org] if you do not have one already. If you are unfamiliar with CMake, this section will provide some information on using CMake to build PortAudio. + +On Linux, CMake serves a very similar purpose to an autotools "configure" script - except it can generate build metadata apart from Makefiles. The equivalent of the following on POSIX'y systems: + + build_path> {portaudio path}/configure --prefix=/install_location + build_path> make + build_path> make install + +Would be: + + build_path> cmake {portaudio path} -G "Unix Makefiles" -DCMAKE_INSTALL_PREFIX=/install_location + build_path> make + build_path> make install + +The "-G" option specifies the type of build metadata which will be generated. You can obtain a list of supported build metadata formats by invoking (on any platform): + + cmake -G + +"make install" should install the same set of files that are installed using the usual configure script included with PortAudio along with a few extra files (similar to pkg-config metadata files) which make it easier for other CMake projects to use the installed libraries. + +On Windows, you can use CMake to generate Visual Studio project files which can be used to create the PortAudio libraries. The following serves as an example (and should be done from a directory outside the PortAudio tree) which will create Visual Studio 2015 project files targetting a 64-bit build: + + C:\PABUILD> cmake {portaudio path} -G "Visual Studio 14 2015 Win64" + +After executing the above, you can either open the generated solution with Visual Studio or use CMake to invoke the build process. The following shows an example of how to build a release configuration (assuming the above command was executed previously in the same directory): + + C:\PABUILD> cmake --build . --config Release + +If you want ASIO support you need to obtain the ASIO2 SDK from Steinberg and place it according to \ref compile_windows_asio_msvc. Both ASIO and the DirectX SDK are automatically searched for by the CMake script - if they are found, they will be enabled by default. + +@section cmake_using Using PortAudio in your CMake project + +PortAudio defines the following CMake targets: + + - "portaudio_static" for a static library and + - "portaudio" for a dynamic library + +If you installed PortAudio as described above in \ref cmake_building and the install prefix you used (CMAKE_INSTALL_PREFIX) is in your system PATH or CMAKE_MODULE_PATH CMake variable, you should be able to use: + + find_package(portaudio) + +To define the "portaudio_static" and "portaudio" targets in your CMake project. + +If you do not want to install portaudio into your system but would rather just have it get built as part of your own project (which may be particularly convenient on Windows), you may also use: + + add_subdirectory("path to PortAudio location" "some binary directory" EXCLUDE_FROM_ALL) + +EXCLUDE_FROM_ALL is not strictly necessary, but will ensure that targets which you don't use in your project won't get built. + +Back to \ref tutorial_start + +*/ \ No newline at end of file diff --git a/extern/portaudio/doc/src/tutorial/compile_linux.dox b/extern/portaudio/doc/src/tutorial/compile_linux.dox new file mode 100644 index 0000000..e227d75 --- /dev/null +++ b/extern/portaudio/doc/src/tutorial/compile_linux.dox @@ -0,0 +1,83 @@ +/** @page compile_linux Building Portaudio for Linux +@ingroup tutorial + +Note: this page has not been reviewed, and may contain errors. + +@section comp_linux1 Installing ALSA Development Kit + +The OSS sound API is very old and not well supported. It is recommended that you use the ALSA sound API. +The PortAudio configure script will look for the ALSA SDK. You can install the ALSA SDK on Ubuntu using: + +@code +sudo apt-get install libasound-dev +@endcode + +You might need to use yum, or some other package manager, instead of apt-get on your machine. +If you do not install ALSA then you might get a message when testing that says you have no audio devices. + +You can find out more about ALSA here: http://www.alsa-project.org/ + +@section comp_linux2 Configuring and Compiling PortAudio + +You can build PortAudio in Linux Environments using the standard configure/make tools: + +@code +./configure && make +@endcode + +That will build PortAudio using Jack, ALSA and OSS in whatever combination they are found on your system. For example, if you have Jack and OSS but not ALSA, it will build using Jack and OSS but not ALSA. This step also builds a number of tests, which can be found in the bin directory of PortAudio. It's a good idea to run some of these tests to make sure PortAudio is working correctly. + +@section comp_linux3 Using PortAudio in your Projects + +To use PortAudio in your apps, you can simply install the .so files: + +@code +sudo make install +@endcode + +Projects built this way will expect PortAudio to be installed on target systems in order to run. If you want to build a more self-contained binary, you may use the libportaudio.a file: + +@code +cp lib/.libs/libportaudio.a /YOUR/PROJECT/DIR +@endcode + +On some systems you may need to use: + +@code +cp /usr/local/lib/libportaudio.a /YOUR/PROJECT/DIR +@endcode + +You may also need to copy portaudio.h, located in the include/ directory of PortAudio into your project. Note that you will usually need to link with the approriate libraries that you used, such as ALSA and JACK, as well as with librt and libpthread. For example: + +@code +gcc main.c libportaudio.a -lrt -lm -lasound -ljack -pthread -o YOUR_BINARY +@endcode + +@section comp_linux4 Linux Extensions + +Note that the ALSA PortAudio back-end adds a few extensions to the standard API that you may take advantage of. To use these functions be sure to include the pa_linux_alsa.h file found in the include file in the PortAudio folder. This file contains further documentation on the following functions: + + PaAlsaStreamInfo/PaAlsa_InitializeStreamInfo:: + Objects of the !PaAlsaStreamInfo type may be used for the !hostApiSpecificStreamInfo attribute of a !PaStreamParameters object, in order to specify the name of an ALSA device to open directly. Specify the device via !PaAlsaStreamInfo.deviceString, after initializing the object with PaAlsa_InitializeStreamInfo. + + PaAlsa_EnableRealtimeScheduling:: + PA ALSA supports real-time scheduling of the audio callback thread (using the FIFO pthread scheduling policy), via the extension PaAlsa_EnableRealtimeScheduling. Call this on the stream before starting it with the enableScheduling parameter set to true or false, to enable or disable this behaviour respectively. + + PaAlsa_GetStreamInputCard:: + Use this function to get the ALSA-lib card index of the stream's input device. + + PaAlsa_GetStreamOutputCard:: + Use this function to get the ALSA-lib card index of the stream's output device. + +Of particular importance is PaAlsa_EnableRealtimeScheduling, which allows ALSA to run at a high priority to prevent ordinary processes on the system from preempting audio playback. Without this, low latency audio playback will be irregular and will contain frequent drop-outs. + +@section comp_linux5 Linux Debugging + +Eliot Blennerhassett writes: + +On linux build, use e.g. "libtool gdb bin/patest_sine8" to debug that program. +This is because on linux bin/patest_sine8 is a libtool shell script that wraps +bin/.libs/patest_sine8 and allows it to find the appropriate libraries within +the build tree. + +*/ \ No newline at end of file diff --git a/extern/portaudio/doc/src/tutorial/compile_mac_coreaudio.dox b/extern/portaudio/doc/src/tutorial/compile_mac_coreaudio.dox new file mode 100644 index 0000000..e16ce33 --- /dev/null +++ b/extern/portaudio/doc/src/tutorial/compile_mac_coreaudio.dox @@ -0,0 +1,122 @@ +/** @page compile_mac_coreaudio Building Portaudio for Mac OS X +@ingroup tutorial + +@section comp_mac_ca_1 Requirements + +* OS X 10.4 or later. PortAudio v19 currently only compiles and runs on OS X version 10.4 or later. Because of its heavy reliance on memory barriers, it's not clear how easy it would be to back-port PortAudio to OS X version 10.3. Leopard support requires the 2007 snapshot or later. + +* Apple's Xcode and its related tools installed in the default location. There is no Xcode project for PortAudio. + +* Mac 10.4 SDK. Look for "/Developer/SDKs/MacOSX10.4u.sdk" folder on your system. It may be installed with XCode. If not then you can download it from Apple Developer Connection. http://connect.apple.com/ + +@section comp_mac_ca_2 Building + +To build PortAudio, simply use the Unix-style "./configure && make": + +@code + ./configure && make +@endcode + +You do not need to do "make install", and we don't recommend it; however, you may be using software that instructs you to do so, in which case you should follow those instructions. (Note from Phil: I had to do "sudo make install" after the command above, otherwise XCode complained that it could not find "/usr/local/lib/libportaudio.dylib" when I compiled an example.) + +The result of these steps will be a file named "libportaudio.dylib" in the directory "usr/local/lib/". + +By default, this will create universal binaries and therefore requires the Universal SDK from Apple, included with XCode 2.1 and higher. + +@section comp_mac_ca_3 Other Build Options + +There are a variety of other options for building PortAudio. The default described above is recommended as it is the most supported and tested; however, your needs may differ and require other options, which are described below. + +@subsection comp_mac_ca_3.1 Building Non-Universal Libraries + +By default, PortAudio is built as a universal binary. This includes 64-bit versions if you are compiling on 10.5, Leopard. If you want a "thin", or single architecture library, you have two options: + + * build a non-universal library using configure options. + * use lipo(1) on whatever part of the library you plan to use. + +Note that the first option may require an extremely recent version of PortAudio (February 5th '08 at least). + +@subsection comp_mac_ca_3.2 Building with --disable-mac-universal + +To build a non-universal library for the host architecture, simply use the --disable-mac-universal option with configure. + +@code + ./configure --disable-mac-universal && make +@endcode + +The --disable-mac-universal option may also be used in conjunction with environment variables to give you more control over the universal binary build process. For example, to build a universal binary for the i386 and ppc architectures using the 10.4u sdk (which is the default on 10.4, but not 10.5), you might specify this configure command line: + +@code + CFLAGS="-O2 -g -Wall -arch i386 -arch ppc -isysroot /Developer/SDKs/MacOSX10.4u.sdk -mmacosx-version-min=10.3" \ + LDFLAGS="-arch i386 -arch ppc -isysroot /Developer/SDKs/MacOSX10.4u.sdk -mmacosx-version-min=10.3" \ + ./configure --disable-mac-universal --disable-dependency-tracking +@endcode + +For more info, see Apple's documentation on the matter: + + * http://developer.apple.com/technotes/tn2005/tn2137.html + * http://developer.apple.com/documentation/Porting/Conceptual/PortingUnix/intro/chapter_1_section_1.html + +@subsection comp_mac_ca_3.3 Using lipo + +The second option is to build normally, and use lipo (1) to extract the architectures you want. For example, if you want a "thin", i386 library only: + +@code + lipo lib/.libs/libportaudio.a -thin i386 -output libportaudio.a +@endcode + +or if you want to extract a single architecture fat file: + +@code + lipo lib/.libs/libportaudio.a -extract i386 -output libportaudio.a +@endcode + +@subsection comp_mac_ca_3.4 Building With Debug Options + +By default, PortAudio on the mac is built without any debugging options. This is because asserts are generally inappropriate for a production environment and debugging information has been suspected, though not proven, to cause trouble with some interfaces. If you would like to compile with debugging, you must run configure with the appropriate flags. For example: + +@code + ./configure --enable-mac-debug && make +@endcode + +This will enable -g and disable -DNDEBUG which will effectively enable asserts. + +@section comp_mac_ca_4 Using the Library in XCode Projects + +If you are planning to follow the rest of the tutorial, several project types will work. You can create a "Standard Tool" under "Command Line Utility". If you are not following the rest of the tutorial, any type of project should work with PortAudio, but these instructions may not work perfectly. + +Once you've compiled PortAudio, the easiest and recommended way to use PortAudio in your XCode project is to add "/include/portaudio.h" and "/lib/.libs/libportaudio.a" to your project. Because "/lib/.libs/" is a hidden directory, you won't be able to navigate to it using the finder or the standard Mac OS file dialogs by clicking on files and folders. You can use command-shift-G in the finder to specify the exact path, or, from the shell, if you are in the portaudio directory, you can enter this command: + +@code + open lib/.libs +@endcode + +Then drag the "libportaudio.a" file into your XCode project and place it in the "External Frameworks and Libraries" group, if the project type has it. If not you can simply add it to the top level folder of the project. + +You will need to add the following frameworks to your XCode project: + + - CoreAudio.framework + - AudioToolbox.framework + - AudioUnit.framework + - CoreServices.framework + - Carbon.framework + +@section comp_mac_ca_5 Using the Library in Other Projects + +For gcc/Make style projects, include "include/portaudio.h" and link "libportaudio.a", and use the frameworks listed in the previous section. How you do so depends on your build. + +@section comp_mac_ca_6 Using Mac-only Extensions to PortAudio + +For additional, Mac-only extensions to the PortAudio interface, you may also want to grab "include/pa_mac_core.h". This file contains some special, mac-only features relating to sample-rate conversion, channel mapping, performance and device hogging. See "src/hostapi/coreaudio/notes.txt" for more details on these features. + +@section comp_mac_ca_7 What Happened to Makefile.darwin? + +Note, there used to be a special makefile just for darwin. This is no longer supported because you can build universal binaries from the standard configure routine. If you find this file in your directory structure it means you have an outdated version of PortAudio. + +@code + make -f Makefile.darwin +@endcode + +Back to the Tutorial: \ref tutorial_start + +*/ diff --git a/extern/portaudio/doc/src/tutorial/compile_windows.dox b/extern/portaudio/doc/src/tutorial/compile_windows.dox new file mode 100644 index 0000000..2258939 --- /dev/null +++ b/extern/portaudio/doc/src/tutorial/compile_windows.dox @@ -0,0 +1,108 @@ +/** @page compile_windows Building PortAudio for Windows using Microsoft Visual Studio +@ingroup tutorial + +Below is a list of steps to build PortAudio into a dll and lib file. The resulting dll file may contain all five current win32 PortAudio APIs: MME, DirectSound, WASAPI, WDM/KS and ASIO, depending on the preprocessor definitions set in step 9 below. + +PortAudio can be compiled using Visual C++ Express Edition which is available free from Microsoft. If you do not already have a C++ development environment, simply download and install. These instructions have been observed to succeed using Visual Studio 2010 as well. + +1) Building PortAudio with DirectSound support requires the files dsound.h and dsconf.h. Download and install the DirectX SDK from http://www.microsoft.com/downloads/details.aspx?displaylang=en&FamilyID=3021d52b-514e-41d3-ad02-438a3ba730ba to obtain these files. If you installed the DirectX SDK then the DirectSound libraries and header files should be found automatically by Visual Studio/Visual C++. If you get an error saying dsound.h or dsconf.h is missing, you will need to add an extra include path to the Visual Studio project file referencing the DirectX includes directory. + +2) For ASIO support, download the ASIO SDK from Steinberg at http://www.steinberg.net/en/company/developer.html . The SDK is free, but you will need to set up a developer account with Steinberg. To use the Visual Studio projects mentioned below, copy the entire ASIOSDK2 folder into src\\hostapi\\asio\\. Rename it from ASIOSDK2 to ASIOSDK. To build without ASIO (or other host API) see the "Building without ASIO support" section below. + +3) If you have Visual Studio 6.0, 7.0(VC.NET/2001) or 7.1(VC.2003), open portaudio.dsp and convert if needed. + +4) If you have Visual Studio 2005, Visual C++ 2008 Express Edition or Visual Studio 2010, open the portaudio.sln file located in build\\msvc\\. Doing so will open Visual Studio or Visual C++. Click "Finish" if a conversion wizard appears. The sln file contains four configurations: Win32 and Win64 in both Release and Debug variants. + +@section comp_win1 For Visual Studio 2005, Visual C++ 2008 Express Edition or Visual Studio 2010 + +The steps below describe settings for recent versions of Visual Studio. Similar settings can be set in earlier versions of Visual Studio. + +5) Open Project -> portaudio Properties and select "Configuration Properties" in the tree view. + +6) Select "all configurations" in the "Configurations" combo box above. Select "All Platforms" in the "Platforms" combo box. + +7) Now set a few options: + +Required: + +C/C++ -> Code Generation -> Runtime library = /MT + +Optional: + +C/C++ -> Optimization -> Omit frame pointers = Yes + +Optional: C/C++ -> Code Generation -> Floating point model = fast + +NOTE: When using PortAudio from C/C++ it is not usually necessary to explicitly set the structure member alignment; the default should work fine. However some languages require, for example, 4-byte alignment. If you are having problems with portaudio.h structure members not being properly read or written to, it may be necessary to explicitly set this value by going to C/C++ -> Code Generation -> Struct member alignment and setting it to an appropriate value (four is a common value). If your compiler is configurable, you should ensure that it is set to use the same structure member alignment value as used for the PortAudio build. + +Click "Ok" when you have finished setting these parameters. + +@section comp_win2 Preprocessor Definitions + +Since the preprocessor definitions are different for each configuration and platform, you'll need to edit these individually for each configuration/platform combination that you want to modify using the "Configurations" and "Platforms" combo boxes. + +8) To suppress PortAudio runtime debug console output, go to Project -> Properties -> Configuration Properties -> C/C++ -> Preprocessor. In the field 'Preprocessor Definitions', find PA_ENABLE_DEBUG_OUTPUT and remove it. The console will not output debug messages. + +9) Also in the preprocessor definitions you need to explicitly define the native audio APIs you wish to use. For Windows the available API definitions are: + +PA_USE_ASIO
    +PA_USE_DS (DirectSound)
    +PA_USE_WMME (MME)
    +PA_USE_WASAPI
    +PA_USE_WDMKS
    +PA_USE_SKELETON + +For each of these, the value of 0 indicates that support for this API should not be included. The value 1 indicates that support for this API should be included. (PA_USE_SKELETON is not usually used, it is a code sample for developers wanting to support a new API). + +@section comp_win3 Building + +As when setting Preprocessor definitions, building is a per-configuration per-platform process. Follow these instructions for each configuration/platform combination that you're interested in. + +10) From the Build menu click Build -> Build solution. For 32-bit compilations, the dll file created by this process (portaudio_x86.dll) can be found in the directory build\\msvc\\Win32\\Release. For 64-bit compilations, the dll file is called portaudio_x64.dll, and is found in the directory build\\msvc\\x64\\Release. + +11) Now, any project that requires portaudio can be linked with portaudio_x86.lib (or _x64) and include the relevant headers (portaudio.h, and/or pa_asio.h , pa_x86_plain_converters.h) You may want to add/remove some DLL entry points. At the time of writing the following 6 entries are not part of the official PortAudio API defined in portaudio.h: + +(from portaudio.def) +@code +... +PaAsio_GetAvailableLatencyValues @50 +PaAsio_ShowControlPanel @51 +PaUtil_InitializeX86PlainConverters @52 +PaAsio_GetInputChannelName @53 +PaAsio_GetOutputChannelName @54 +PaUtil_SetLogPrintFunction @55 +@endcode + +@section comp_win4 Building without ASIO support + +To build PortAudio without ASIO support you need to: + +1) Make sure your project doesn't try to build any ASIO SDK files. If you're using one of the shipped projects, remove the ASIO related files from the project. In the shipped projects you can find them in the project tree under portaudio > Source Files > hostapi > ASIO > ASIOSDK + +2) Make sure your project doesn't try to build the PortAudio ASIO implementation files: + +@code +src\\hostapi\\pa_asio.cpp +src\\hostapi\\iasiothiscallresolver.cpp +@endcode + +If you're using one of the shipped projects, remove them from the project. In the shipped projects you can find them in the project tree under portaudio > Source Files > hostapi > ASIO + +3) Define the preprocessor symbols in the project properties as described in step 9 above. In VS2005 this can be accomplished by selecting +Project Properties -> Configuration Properties -> C/C++ -> Preprocessor -> Preprocessor Definitions. Omitting PA_USE_ASIO or setting it to 0 stops src\\os\\win\\pa_win_hostapis.c from trying to initialize the PortAudio ASIO implementation. + +4) Remove PaAsio_* entry points from portaudio.def + + +----- +David Viens, davidv@plogue.com + +Updated by Chris on 5/26/2011 + +Improvements by John Clements on 12/15/2011 + +Edits by Ross on 1/20/2014 + +Back to the Tutorial: \ref tutorial_start + +*/ \ No newline at end of file diff --git a/extern/portaudio/doc/src/tutorial/compile_windows_asio_msvc.dox b/extern/portaudio/doc/src/tutorial/compile_windows_asio_msvc.dox new file mode 100644 index 0000000..cf3a0e5 --- /dev/null +++ b/extern/portaudio/doc/src/tutorial/compile_windows_asio_msvc.dox @@ -0,0 +1,97 @@ +/** @page compile_windows_asio_msvc Building Portaudio for Windows with ASIO support using MSVC +@ingroup tutorial + +@section comp_win_asiomsvc1 Portaudio Windows ASIO with MSVC + +This tutorial describes how to build PortAudio with ASIO support using MSVC *from scratch*, without an existing Visual Studio project. For instructions for building PortAudio (including ASIO support) using the bundled Visual Studio project file see the compiling instructions for \ref compile_windows. + +ASIO is a low latency audio API from Steinberg. To compile an ASIO +application, you must first download the ASIO SDK from Steinberg. You also +need to obtain ASIO drivers for your audio device. Download the ASIO SDK from Steinberg at http://www.steinberg.net/en/company/developer.html . The SDK is free but you will need to set up a developer account with Steinberg. + +This tutorial assumes that you have 3 directories set up at the same level (side by side), one containing PortAudio, one containing the ASIO SDK and one containing your Visual Studio project: + +@code +/ASIOSDK2 +/portaudio +/DirContainingYourVisualStudioProject (should directly contain the .sln, .vcproj or .vcprojx etc.) +@endcode + +First, make sure that the Steinberg SDK and the portaudio files are "side by side" in the same directory. + +Open Microsoft Visual C++ and create a new blank Console exe Project/Workspace in that same directory. + +For example, the paths for all three groups might read like this: + +@code +C:\Program Files\Microsoft Visual Studio\VC98\My Projects\ASIOSDK2 +C:\Program Files\Microsoft Visual Studio\VC98\My Projects\portaudio +C:\Program Files\Microsoft Visual Studio\VC98\My Projects\Sawtooth +@endcode + + +Next, add the following Steinberg ASIO SDK files to the project Source Files: + +@code +asio.cpp (ASIOSDK2\common) +asiodrivers.cpp (ASIOSDK2\host) +asiolist.cpp (ASIOSDK2\host\pc) +@endcode + + +Then, add the following PortAudio files to the project Source Files: + +@code +pa_asio.cpp (portaudio\src\hostapi\asio) +pa_allocation.c (portaudio\src\common) +pa_converters.c (portaudio\src\common) +pa_cpuload.c (portaudio\src\common) +pa_dither.c (portaudio\src\common) +pa_front.c (portaudio\src\common) +pa_process.c (portaudio\src\common) +pa_ringbuffer.c (portaudio\src\common) +pa_stream.c (portaudio\src\common) +pa_trace.c (portaudio\src\common) +pa_win_hostapis.c (portaudio\src\os\win) +pa_win_util.c (portaudio\src\os\win) +pa_win_coinitialize.c (portaudio\src\os\win) +pa_win_waveformat.c (portaudio\src\os\win) +pa_x86_plain_converters.c (portaudio\src\os\win) +paex_saw.c (portaudio\examples) (Or another file containing main() + for the console exe to be built.) +@endcode + + +Although not strictly necessary, you may also want to add the following files to the project Header Files: + +@code +portaudio.h (portaudio\include) +pa_asio.h (portaudio\include) +@endcode + +These header files define the interfaces to the PortAudio API. + + +Next, go to Project Settings > All Configurations > C/C++ > Preprocessor > Preprocessor Definitions and add +PA_USE_ASIO=1 to any entries that might be there. + +eg: WIN32;_CONSOLE;_MBCS changes to WIN32;_CONSOLE,_MBCS;PA_USE_ASIO=1 + +Then, on the same Project Settings tab, go down to Additional Include Directories (in VS2010 you'll find this setting under C/C++ > General) and enter the following relative include paths: + +@code +..\portaudio\include;..\portaudio\src\common;..\portaudio\src\os\win;..\asiosdk2\common;..\asiosdk2\host;..\asiosdk2\host\pc +@endcode + +You'll need to make sure the relative paths are correct for the particular directory layout you're using. The above should work fine if you use the side-by-side layout we recommended earlier. + +Some source code in the ASIO SDK is not compatible with the Win32 API UNICODE mode (The ASIO SDK expects the non-Unicode Win32 API). Therefore you need to make sure your project is set to not use Unicode. You do this by setting the project Character Set to "Use Multi-Byte Character Set" (NOT "Use Unicode Character Set"). In VS2010 the Character Set option can be found at Configuration Properties > General > Character Set. (An alternative to setting the project to non-Unicode is to patch asiolist.cpp to work when UNICODE is defined: put #undef UNICODE at the top of the file before windows.h is included.) + +You should now be able to build any of the test executables in the portaudio\\examples directory. +We suggest that you start with paex_saw.c because it's one of the simplest example files. + +--- Chris Share, Tom McCandless, Ross Bencina + +Back to the Tutorial: \ref tutorial_start + +*/ \ No newline at end of file diff --git a/extern/portaudio/doc/src/tutorial/compile_windows_mingw.dox b/extern/portaudio/doc/src/tutorial/compile_windows_mingw.dox new file mode 100644 index 0000000..d521b7b --- /dev/null +++ b/extern/portaudio/doc/src/tutorial/compile_windows_mingw.dox @@ -0,0 +1,53 @@ +/** @page compile_windows_mingw Building Portaudio for Windows with MinGW +@ingroup tutorial + +@section comp_mingw1 Portaudio for Windows With MinGW + +This document contains old or out-of-date information. Please see a draft of new MinGW information on our Wiki: PortAudio Wiki: Notes about building PortAudio with MinGW + += MinGW/MSYS = + +From the [http://www.mingw.org MinGW projectpage]: + +MinGW: A collection of freely available and freely distributable +Windows specific header files and import libraries, augmenting +the GNU Compiler Collection, (GCC), and its associated +tools, (GNU binutils). MinGW provides a complete Open Source +programming tool set which is suitable for the development of +native Windows programs that do not depend on any 3rd-party C +runtime DLLs. + +MSYS: A Minimal SYStem providing a POSIX compatible Bourne shell +environment, with a small collection of UNIX command line +tools. Primarily developed as a means to execute the configure +scripts and Makefiles used to build Open Source software, but +also useful as a general purpose command line interface to +replace Windows cmd.exe. + +MinGW provides a compiler/linker toolchain while MSYS is required +to actually run the PortAudio configure script. + +Once MinGW and MSYS are installed (see the [http://www.mingw.org/MinGWiki MinGW-Wiki]) open an MSYS shell and run the famous: + +@code +./configure +make +make install +@endcode + +The above should create a working version though you might want to +provide '--prefix=' to configure. + +'./configure --help' gives details as to what can be tinkered with. + +--- Mikael Magnusson + +To update your copy or check out a fresh copy of the source + +[wiki:UsingThePortAudioSvnRepository SVN instructions] + +--- Bob !McGwier + +Back to the Tutorial: \ref tutorial_start + +*/ \ No newline at end of file diff --git a/extern/portaudio/doc/src/tutorial/exploring.dox b/extern/portaudio/doc/src/tutorial/exploring.dox new file mode 100644 index 0000000..9dd0873 --- /dev/null +++ b/extern/portaudio/doc/src/tutorial/exploring.dox @@ -0,0 +1,15 @@ +/** @page exploring Exploring PortAudio +@ingroup tutorial + +Now that you have a good idea of how PortAudio works, you can try out the example programs. You'll find them in the examples/ directory in the PortAudio distribution. + +For an example of playing a sine wave, see examples/paex_sine.c. + +For an example of recording and playing back a sound, see examples/paex_record.c. + +I also encourage you to examine the source for the PortAudio libraries. If you have suggestions on ways to improve them, please let us know. If you want to implement PortAudio on a new platform, please let us know as well so we can coordinate people's efforts. + + +Previous: \ref blocking_read_write | Next: This is the end of the tutorial. + +*/ \ No newline at end of file diff --git a/extern/portaudio/doc/src/tutorial/initializing_portaudio.dox b/extern/portaudio/doc/src/tutorial/initializing_portaudio.dox new file mode 100644 index 0000000..9439c35 --- /dev/null +++ b/extern/portaudio/doc/src/tutorial/initializing_portaudio.dox @@ -0,0 +1,29 @@ +/** @page initializing_portaudio Initializing PortAudio +@ingroup tutorial + +@section tut_init1 Initializing PortAudio + +Before making any other calls to PortAudio, you 'must' call Pa_Initialize(). This will trigger a scan of available devices which can be queried later. Like most PA functions, it will return a result of type paError. If the result is not paNoError, then an error has occurred. +@code +err = Pa_Initialize(); +if( err != paNoError ) goto error; +@endcode + +You can get a text message that explains the error message by passing it to Pa_GetErrorText( err ). For Example: + +@code +printf( "PortAudio error: %s\n", Pa_GetErrorText( err ) ); +@endcode + +It is also important, when you are done with PortAudio, to Terminate it: + +@code +err = Pa_Terminate(); +if( err != paNoError ) + printf( "PortAudio error: %s\n", Pa_GetErrorText( err ) ); +@endcode + + +Previous: \ref writing_a_callback | Next: \ref open_default_stream + +*/ \ No newline at end of file diff --git a/extern/portaudio/doc/src/tutorial/open_default_stream.dox b/extern/portaudio/doc/src/tutorial/open_default_stream.dox new file mode 100644 index 0000000..7512d1e --- /dev/null +++ b/extern/portaudio/doc/src/tutorial/open_default_stream.dox @@ -0,0 +1,48 @@ +/** @page open_default_stream Opening a Stream Using Defaults +@ingroup tutorial + +The next step is to open a stream, which is similar to opening a file. You can specify whether you want audio input and/or output, how many channels, the data format, sample rate, etc. Opening a ''default'' stream means opening the default input and output devices, which saves you the trouble of getting a list of devices and choosing one from the list. (We'll see how to do that later.) +@code +#define SAMPLE_RATE (44100) +static paTestData data; + +..... + + PaStream *stream; + PaError err; + + /* Open an audio I/O stream. */ + err = Pa_OpenDefaultStream( &stream, + 0, /* no input channels */ + 2, /* stereo output */ + paFloat32, /* 32 bit floating point output */ + SAMPLE_RATE, + 256, /* frames per buffer, i.e. the number + of sample frames that PortAudio will + request from the callback. Many apps + may want to use + paFramesPerBufferUnspecified, which + tells PortAudio to pick the best, + possibly changing, buffer size.*/ + patestCallback, /* this is your callback function */ + &data ); /*This is a pointer that will be passed to + your callback*/ + if( err != paNoError ) goto error; +@endcode + +The data structure and callback are described in \ref writing_a_callback. + +The above example opens the stream for writing, which is sufficient for playback. It is also possible to open a stream for reading, to do recording, or both reading and writing, for simultaneous recording and playback or even real-time audio processing. If you plan to do playback and recording at the same time, open only one stream with valid input and output parameters. + +There are some caveats to note about simultaneous read/write: + + - Some platforms can only open a read/write stream using the same device. + - Although multiple streams can be opened, it is difficult to synchronize them. + - Some platforms don't support opening multiple streams on the same device. + - Using multiple streams may not be as well tested as other features. + - The PortAudio library calls must be made from the same thread or synchronized by the user. + + +Previous: \ref initializing_portaudio | Next: \ref start_stop_abort + +*/ \ No newline at end of file diff --git a/extern/portaudio/doc/src/tutorial/querying_devices.dox b/extern/portaudio/doc/src/tutorial/querying_devices.dox new file mode 100644 index 0000000..1eac41a --- /dev/null +++ b/extern/portaudio/doc/src/tutorial/querying_devices.dox @@ -0,0 +1,111 @@ +/** @page querying_devices Enumerating and Querying PortAudio Devices +@ingroup tutorial + +@section tut_query1 Querying Devices + +It is often fine to use the default device as we did previously in this tutorial, but there are times when you'll want to explicitly choose the device from a list of available devices on the system. To see a working example of this, check out pa_devs.c in the tests/ directory of the PortAudio source code. To do so, you'll need to first initialize PortAudio and Query for the number of Devices: + +@code + int numDevices; + + numDevices = Pa_GetDeviceCount(); + if( numDevices < 0 ) + { + printf( "ERROR: Pa_CountDevices returned 0x%x\n", numDevices ); + err = numDevices; + goto error; + } +@endcode + + +If you want to get information about each device, simply loop through as follows: + +@code + const PaDeviceInfo *deviceInfo; + + for( i=0; idefaultLowInputLatency ; + inputParameters.hostApiSpecificStreamInfo = NULL; //See you specific host's API docs for info on using this field + + + bzero( &outputParameters, sizeof( outputParameters ) ); //not necessary if you are filling in all the fields + outputParameters.channelCount = outChan; + outputParameters.device = outDevNum; + outputParameters.hostApiSpecificStreamInfo = NULL; + outputParameters.sampleFormat = paFloat32; + outputParameters.suggestedLatency = Pa_GetDeviceInfo(outDevNum)->defaultLowOutputLatency ; + outputParameters.hostApiSpecificStreamInfo = NULL; //See you specific host's API docs for info on using this field + + err = Pa_OpenStream( + &stream, + &inputParameters, + &outputParameters, + srate, + framesPerBuffer, + paNoFlag, //flags that can be used to define dither, clip settings and more + portAudioCallback, //your callback function + (void *)this ); //data to be passed to callback. In C++, it is frequently (void *)this + //don't forget to check errors! +@endcode + + +Previous: \ref utility_functions | Next: \ref blocking_read_write + +*/ \ No newline at end of file diff --git a/extern/portaudio/doc/src/tutorial/start_stop_abort.dox b/extern/portaudio/doc/src/tutorial/start_stop_abort.dox new file mode 100644 index 0000000..6d4f777 --- /dev/null +++ b/extern/portaudio/doc/src/tutorial/start_stop_abort.dox @@ -0,0 +1,35 @@ +/** @page start_stop_abort Starting, Stopping and Aborting a Stream +@ingroup tutorial + +@section tut_startstop1 Starting, Stopping and Aborting a Stream + +PortAudio will not start playing back audio until you start the stream. After calling Pa_StartStream(), PortAudio will start calling your callback function to perform the audio processing. + +@code + err = Pa_StartStream( stream ); + if( err != paNoError ) goto error; +@endcode + +You can communicate with your callback routine through the data structure you passed in on the open call, or through global variables, or using other interprocess communication techniques, but please be aware that your callback function may be called at interrupt time when your foreground process is least expecting it. So avoid sharing complex data structures that are easily corrupted like double linked lists, and avoid using locks such as mutexs as this may cause your callback function to block and therefore drop audio. Such techniques may even cause deadlock on some platforms. + +PortAudio will continue to call your callback and process audio until you stop the stream. This can be done in one of several ways, but, before we do so, we'll want to see that some of our audio gets processed by sleeping for a few seconds. This is easy to do with Pa_Sleep(), which is used by many of the examples in the patests/ directory for exactly this purpose. Note that, for a variety of reasons, you can not rely on this function for accurate scheduling, so your stream may not run for exactly the same amount of time as you expect, but it's good enough for our example. + +@code + /* Sleep for several seconds. */ + Pa_Sleep(NUM_SECONDS*1000); +@endcode + +Now we need to stop playback. There are several ways to do this, the simplest of which is to call Pa_StopStream(): + +@code + err = Pa_StopStream( stream ); + if( err != paNoError ) goto error; +@endcode + +Pa_StopStream() is designed to make sure that the buffers you've processed in your callback are all played, which may cause some delay. Alternatively, you could call Pa_AbortStream(). On some platforms, aborting the stream is much faster and may cause some data processed by your callback not to be played. + +Another way to stop the stream is to return either paComplete, or paAbort from your callback. paComplete ensures that the last buffer is played whereas paAbort stops the stream as soon as possible. If you stop the stream using this technique, you will need to call Pa_StopStream() before starting the stream again. + +Previous: \ref open_default_stream | Next: \ref terminating_portaudio + +*/ \ No newline at end of file diff --git a/extern/portaudio/doc/src/tutorial/terminating_portaudio.dox b/extern/portaudio/doc/src/tutorial/terminating_portaudio.dox new file mode 100644 index 0000000..67f74f6 --- /dev/null +++ b/extern/portaudio/doc/src/tutorial/terminating_portaudio.dox @@ -0,0 +1,20 @@ +/** @page terminating_portaudio Closing a Stream and Terminating PortAudio +@ingroup tutorial + +When you are done with a stream, you should close it to free up resources: + +@code + err = Pa_CloseStream( stream ); + if( err != paNoError ) goto error; +@endcode + +We've already mentioned this in \ref initializing_portaudio, but in case you forgot, be sure to terminate PortAudio when you are done: + +@code + err = Pa_Terminate( ); + if( err != paNoError ) goto error; +@endcode + +Previous: \ref start_stop_abort | Next: \ref utility_functions + +*/ \ No newline at end of file diff --git a/extern/portaudio/doc/src/tutorial/tutorial_start.dox b/extern/portaudio/doc/src/tutorial/tutorial_start.dox new file mode 100644 index 0000000..f920178 --- /dev/null +++ b/extern/portaudio/doc/src/tutorial/tutorial_start.dox @@ -0,0 +1,59 @@ +/** @page tutorial_start PortAudio Tutorials +@ingroup tutorial + +These tutorials takes you through a hands-on example of using PortAudio to make sound. If you'd prefer to start with a top-down overview of the PortAudio API, check out the @ref api_overview. + +@section tut_start1 Downloading + +First thing you need to do is download the PortAudio source code either as a tarball from the website, or from the Subversion Repository. + +@section tut_start2 Compiling + +Once you've downloaded PortAudio you'll need to compile it, which of course, depends on your environment: + + - Windows + - \ref compile_windows + - \ref compile_windows_mingw + - \ref compile_windows_asio_msvc + - Mac OS X + - \ref compile_mac_coreaudio + - POSIX + - \ref compile_linux + +You can also use CMake to generate project files for PortAudio on Windows, OS X or Linux or include PortAudio easily in your own CMake project. See \ref compile_cmake. + +Many platforms with GCC/make can use the simple ./configure && make combination and simply use the resulting libraries in their code. + +@section tut_start3 Programming with PortAudio + +Below are the steps to writing a PortAudio application using the callback technique: + + - Write a callback function that will be called by PortAudio when audio processing is needed. + - Initialize the PA library and open a stream for audio I/O. + - Start the stream. Your callback function will be now be called repeatedly by PA in the background. + - In your callback you can read audio data from the inputBuffer and/or write data to the outputBuffer. + - Stop the stream by returning 1 from your callback, or by calling a stop function. + - Close the stream and terminate the library. + +In addition to this "Callback" architecture, V19 also supports a "Blocking I/O" model which uses read and write calls which may be more familiar to non-audio programmers. Note that at this time, not all APIs support this functionality. + +In this tutorial, we'll show how to use the callback architecture to play a sawtooth wave. Much of the tutorial is taken from the file paex_saw.c, which is part of the PortAudio distribution. When you're done with this tutorial, you'll be armed with the basic knowledge you need to write an audio program. If you need more sample code, look in the "examples" and "test" directory of the PortAudio distribution. Another great source of info is the portaudio.h Doxygen page, which documents the entire V19 API. Also see the page for tips on programming PortAudio on the PortAudio wiki. + +@section tut_start4 Programming Tutorial Contents + +- \ref writing_a_callback +- \ref initializing_portaudio +- \ref open_default_stream +- \ref start_stop_abort +- \ref terminating_portaudio +- \ref utility_functions +- \ref querying_devices +- \ref blocking_read_write + +If you are upgrading from V18, you may want to look at the Proposed Enhancements to PortAudio, which describes the differences between V18 and V19. + +Once you have a basic understanding of how to use PortAudio, you might be interested in \ref exploring. + +Next: \ref writing_a_callback + +*/ \ No newline at end of file diff --git a/extern/portaudio/doc/src/tutorial/utility_functions.dox b/extern/portaudio/doc/src/tutorial/utility_functions.dox new file mode 100644 index 0000000..c06bf3b --- /dev/null +++ b/extern/portaudio/doc/src/tutorial/utility_functions.dox @@ -0,0 +1,69 @@ +/** @page utility_functions Utility Functions +@ingroup tutorial + +In addition to the functions described elsewhere in this tutorial, PortAudio provides a number of Utility functions that are useful in a variety of circumstances. +You'll want to read the portaudio.h reference, which documents the entire V19 API for details, but we'll try to cover the basics here. + +@section tut_util2 Version Information + +PortAudio offers two functions to determine the PortAudio Version. This is most useful when you are using PortAudio as a dynamic library, but it may also be useful at other times. + +@code +int Pa_GetVersion (void) +const char * Pa_GetVersionText (void) +@endcode + +@section tut_util3 Error Text + +PortAudio allows you to get error text from an error number. + +@code +const char * Pa_GetErrorText (PaError errorCode) +@endcode + +@section tut_util4 Stream State + +PortAudio Streams exist in 3 states: Active, Stopped, and Callback Stopped. If a stream is in callback stopped state, you'll need to stop it before you can start it again. If you need to query the state of a PortAudio stream, there are two functions for doing so: + +@code +PaError Pa_IsStreamStopped (PaStream *stream) +PaError Pa_IsStreamActive (PaStream *stream) +@endcode + +@section tut_util5 Stream Info + +If you need to retrieve info about a given stream, such as latency, and sample rate info, there's a function for that too: + +@code +const PaStreamInfo * Pa_GetStreamInfo (PaStream *stream) +@endcode + +@section tut_util6 Stream Time + +If you need to synchronise other activities such as display updates or MIDI output with the PortAudio callback you need to know the current time according to the same timebase used by the stream callback timestamps. + +@code +PaTime Pa_GetStreamTime (PaStream *stream) +@endcode + +@section tut_util6CPU Usage + +To determine how much CPU is being used by the callback, use these: + +@code +double Pa_GetStreamCpuLoad (PaStream *stream) +@endcode + +@section tut_util7 Other utilities + +These functions allow you to determine the size of a sample from its format and sleep for a given amount of time. The sleep function should not be used for precise timing or synchronization because it makes few guarantees about the exact length of time it waits. It is most useful for testing. + +@code +PaError Pa_GetSampleSize (PaSampleFormat format) +void Pa_Sleep (long msec) +@endcode + + +Previous: \ref terminating_portaudio | Next: \ref querying_devices + +*/ \ No newline at end of file diff --git a/extern/portaudio/doc/src/tutorial/writing_a_callback.dox b/extern/portaudio/doc/src/tutorial/writing_a_callback.dox new file mode 100644 index 0000000..7c2f8d3 --- /dev/null +++ b/extern/portaudio/doc/src/tutorial/writing_a_callback.dox @@ -0,0 +1,70 @@ +/** @page writing_a_callback Writing a Callback Function +@ingroup tutorial + +To write a program using PortAudio, you must include the "portaudio.h" include file. You may wish to read "portaudio.h" because it contains a complete description of the PortAudio functions and constants. Alternatively, you could browse the [http://www.portaudio.com/docs/v19-doxydocs/portaudio_8h.html "portaudio.h" Doxygen page] +@code +#include "portaudio.h" +@endcode +The next task is to write your own "callback" function. The "callback" is a function that is called by the PortAudio engine whenever it has captured audio data, or when it needs more audio data for output. + +Before we begin, it's important to realize that the callback is a delicate place. This is because some systems perform the callback in a special thread, or interrupt handler, and it is rarely treated the same as the rest of your code. +For most modern systems, you won't be able to cause crashes by making disallowed calls in the callback, but if you want your code to produce glitch-free audio, you will have to make sure you avoid function calls that may take an unbounded amount of time +to execute. Exactly what these are depend on your platform but almost certainly include the following: memory allocation/deallocation, I/O (including file I/O as well as console I/O, such as printf()), context switching (such as exec() or +yield()), mutex operations, or anything else that might rely on the OS. If you think short critical sections are safe please go read about priority inversion. Windows amd Mac OS schedulers have no real-time safe priority inversion prevention. Other platforms require special mutex flags. In addition, it is not safe to call any PortAudio API functions in the callback except as explicitly permitted in the documentation. + + +Your callback function must return an int and accept the exact parameters specified in this typedef: + +@code +typedef int PaStreamCallback( const void *input, + void *output, + unsigned long frameCount, + const PaStreamCallbackTimeInfo* timeInfo, + PaStreamCallbackFlags statusFlags, + void *userData ) ; +@endcode +Here is an example callback function from the test file "patests/patest_saw.c". It calculates a simple left and right sawtooth signal and writes it to the output buffer. Notice that in this example, the signals are of float data type. The signals must be between -1.0 and +1.0. You can also use 16 bit integers or other formats which are specified during setup, but floats are easiest to work with. You can pass a pointer to your data structure through PortAudio which will appear as userData. + +@code +typedef struct +{ + float left_phase; + float right_phase; +} +paTestData; + +/* This routine will be called by the PortAudio engine when audio is needed. +** It may called at interrupt level on some machines so don't do anything +** that could mess up the system like calling malloc() or free(). +*/ +static int patestCallback( const void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + const PaStreamCallbackTimeInfo* timeInfo, + PaStreamCallbackFlags statusFlags, + void *userData ) +{ + /* Cast data passed through stream to our structure. */ + paTestData *data = (paTestData*)userData; + float *out = (float*)outputBuffer; + unsigned int i; + (void) inputBuffer; /* Prevent unused variable warning. */ + + for( i=0; ileft_phase; /* left */ + *out++ = data->right_phase; /* right */ + /* Generate simple sawtooth phaser that ranges between -1.0 and 1.0. */ + data->left_phase += 0.01f; + /* When signal reaches top, drop back down. */ + if( data->left_phase >= 1.0f ) data->left_phase -= 2.0f; + /* higher pitch so we can distinguish left and right. */ + data->right_phase += 0.03f; + if( data->right_phase >= 1.0f ) data->right_phase -= 2.0f; + } + return 0; +} +@endcode + +Previous: \ref tutorial_start | Next: \ref initializing_portaudio + +*/ diff --git a/extern/portaudio/doc/utils/checkfiledocs.py b/extern/portaudio/doc/utils/checkfiledocs.py new file mode 100644 index 0000000..5d6b585 --- /dev/null +++ b/extern/portaudio/doc/utils/checkfiledocs.py @@ -0,0 +1,87 @@ +import os +import os.path +import string + +paRootDirectory = '../../' +paHtmlDocDirectory = os.path.join( paRootDirectory, "doc", "html" ) + +## Script to check documentation status +## this script assumes that html doxygen documentation has been generated +## +## it then walks the entire portaudio source tree and check that +## - every source file (.c,.h,.cpp) has a doxygen comment block containing +## - a @file directive +## - a @brief directive +## - a @ingroup directive +## - it also checks that a corresponding html documentation file has been generated. +## +## This can be used as a first-level check to make sure the documentation is in order. +## +## The idea is to get a list of which files are missing doxygen documentation. +## +## How to run: +## $ cd doc/utils +## $ python checkfiledocs.py + +def oneOf_a_in_b(a, b): + for x in a: + if x in b: + return True + return False + +# recurse from top and return a list of all with the given +# extensions. ignore .svn directories. return absolute paths +def recursiveFindFiles( top, extensions, dirBlacklist, includePaths ): + result = [] + for (dirpath, dirnames, filenames) in os.walk(top): + if not oneOf_a_in_b(dirBlacklist, dirpath): + for f in filenames: + if os.path.splitext(f)[1] in extensions: + if includePaths: + result.append( os.path.abspath( os.path.join( dirpath, f ) ) ) + else: + result.append( f ) + return result + +# generate the html file name that doxygen would use for +# a particular source file. this is a brittle conversion +# which i worked out by trial and error +def doxygenHtmlDocFileName( sourceFile ): + return sourceFile.replace( '_', '__' ).replace( '.', '_8' ) + '.html' + + +sourceFiles = recursiveFindFiles( os.path.join(paRootDirectory,'src'), [ '.c', '.h', '.cpp' ], ['.svn', 'mingw-include'], True ); +sourceFiles += recursiveFindFiles( os.path.join(paRootDirectory,'include'), [ '.c', '.h', '.cpp' ], ['.svn'], True ); +docFiles = recursiveFindFiles( paHtmlDocDirectory, [ '.html' ], ['.svn'], False ); + + + +currentFile = "" + +def printError( f, message ): + global currentFile + if f != currentFile: + currentFile = f + print f, ":" + print "\t!", message + + +for f in sourceFiles: + if not doxygenHtmlDocFileName( os.path.basename(f) ) in docFiles: + printError( f, "no doxygen generated doc page" ) + + s = file( f, 'rt' ).read() + + if not '/**' in s: + printError( f, "no doxygen /** block" ) + + if not '@file' in s: + printError( f, "no doxygen @file tag" ) + + if not '@brief' in s: + printError( f, "no doxygen @brief tag" ) + + if not '@ingroup' in s: + printError( f, "no doxygen @ingroup tag" ) + + diff --git a/extern/portaudio/examples/CMakeLists.txt b/extern/portaudio/examples/CMakeLists.txt new file mode 100644 index 0000000..f96b6ec --- /dev/null +++ b/extern/portaudio/examples/CMakeLists.txt @@ -0,0 +1,41 @@ +# Example projects + +MACRO(ADD_EXAMPLE appl_name) + ADD_EXECUTABLE(${appl_name} "${appl_name}.c") + TARGET_LINK_LIBRARIES(${appl_name} portaudio_static) + SET_TARGET_PROPERTIES(${appl_name} PROPERTIES FOLDER "Examples C") + IF(WIN32) + SET_PROPERTY(TARGET ${appl_name} APPEND_STRING PROPERTY COMPILE_DEFINITIONS _CRT_SECURE_NO_WARNINGS) + ENDIF() +ENDMACRO(ADD_EXAMPLE) + +MACRO(ADD_EXAMPLE_CPP appl_name) + ADD_EXECUTABLE(${appl_name} "${appl_name}.cpp") + TARGET_LINK_LIBRARIES(${appl_name} portaudio_static) + SET_TARGET_PROPERTIES(${appl_name} PROPERTIES FOLDER "Examples C++") + IF(WIN32) + SET_PROPERTY(TARGET ${appl_name} APPEND_STRING PROPERTY COMPILE_DEFINITIONS _CRT_SECURE_NO_WARNINGS) + ENDIF() +ENDMACRO(ADD_EXAMPLE_CPP) + +ADD_EXAMPLE(pa_devs) +ADD_EXAMPLE(pa_fuzz) +IF(PA_USE_ASIO AND WIN32) + ADD_EXAMPLE(paex_mono_asio_channel_select) +ENDIF() +ADD_EXAMPLE(paex_ocean_shore) +TARGET_INCLUDE_DIRECTORIES(paex_ocean_shore PRIVATE ../src/common) +ADD_EXAMPLE(paex_pink) +ADD_EXAMPLE(paex_read_write_wire) +ADD_EXAMPLE(paex_record) +ADD_EXAMPLE(paex_record_file) +TARGET_INCLUDE_DIRECTORIES(paex_record_file PRIVATE ../src/common) +ADD_EXAMPLE(paex_saw) +ADD_EXAMPLE(paex_sine) +ADD_EXAMPLE_CPP(paex_sine_c++) +IF(PA_USE_WMME AND WIN32) + ADD_EXAMPLE(paex_wmme_ac3) + ADD_EXAMPLE(paex_wmme_surround) +ENDIF() +ADD_EXAMPLE(paex_write_sine) +ADD_EXAMPLE(paex_write_sine_nonint) diff --git a/extern/portaudio/examples/pa_devs.c b/extern/portaudio/examples/pa_devs.c new file mode 100644 index 0000000..595a05d --- /dev/null +++ b/extern/portaudio/examples/pa_devs.c @@ -0,0 +1,252 @@ +/** @file pa_devs.c + @ingroup examples_src + @brief List available devices, including device information. + @author Phil Burk http://www.softsynth.com + + @note Define PA_USE_ASIO=0 to compile this code on Windows without + ASIO support. +*/ +/* + * $Id$ + * + * This program uses the PortAudio Portable Audio Library. + * For more information see: http://www.portaudio.com + * Copyright (c) 1999-2000 Ross Bencina and Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +#include +#include +#include "portaudio.h" + +#ifdef WIN32 +#include + +#if PA_USE_ASIO +#include "pa_asio.h" +#endif +#endif + +/*******************************************************************/ +static void PrintSupportedStandardSampleRates( + const PaStreamParameters *inputParameters, + const PaStreamParameters *outputParameters ) +{ + static double standardSampleRates[] = { + 8000.0, 9600.0, 11025.0, 12000.0, 16000.0, 22050.0, 24000.0, 32000.0, + 44100.0, 48000.0, 88200.0, 96000.0, 192000.0, -1 /* negative terminated list */ + }; + int i, printCount; + PaError err; + + printCount = 0; + for( i=0; standardSampleRates[i] > 0; i++ ) + { + err = Pa_IsFormatSupported( inputParameters, outputParameters, standardSampleRates[i] ); + if( err == paFormatIsSupported ) + { + if( printCount == 0 ) + { + printf( "\t%8.2f", standardSampleRates[i] ); + printCount = 1; + } + else if( printCount == 4 ) + { + printf( ",\n\t%8.2f", standardSampleRates[i] ); + printCount = 1; + } + else + { + printf( ", %8.2f", standardSampleRates[i] ); + ++printCount; + } + } + } + if( !printCount ) + printf( "None\n" ); + else + printf( "\n" ); +} + +/*******************************************************************/ +int main(void); +int main(void) +{ + int i, numDevices, defaultDisplayed; + const PaDeviceInfo *deviceInfo; + PaStreamParameters inputParameters, outputParameters; + PaError err; + + + err = Pa_Initialize(); + if( err != paNoError ) + { + printf( "ERROR: Pa_Initialize returned 0x%x\n", err ); + goto error; + } + + printf( "PortAudio version: 0x%08X\n", Pa_GetVersion()); + printf( "Version text: '%s'\n", Pa_GetVersionInfo()->versionText ); + + numDevices = Pa_GetDeviceCount(); + if( numDevices < 0 ) + { + printf( "ERROR: Pa_GetDeviceCount returned 0x%x\n", numDevices ); + err = numDevices; + goto error; + } + + printf( "Number of devices = %d\n", numDevices ); + for( i=0; ihostApi )->defaultInputDevice ) + { + const PaHostApiInfo *hostInfo = Pa_GetHostApiInfo( deviceInfo->hostApi ); + printf( "[ Default %s Input", hostInfo->name ); + defaultDisplayed = 1; + } + + if( i == Pa_GetDefaultOutputDevice() ) + { + printf( (defaultDisplayed ? "," : "[") ); + printf( " Default Output" ); + defaultDisplayed = 1; + } + else if( i == Pa_GetHostApiInfo( deviceInfo->hostApi )->defaultOutputDevice ) + { + const PaHostApiInfo *hostInfo = Pa_GetHostApiInfo( deviceInfo->hostApi ); + printf( (defaultDisplayed ? "," : "[") ); + printf( " Default %s Output", hostInfo->name ); + defaultDisplayed = 1; + } + + if( defaultDisplayed ) + printf( " ]\n" ); + + /* print device info fields */ +#ifdef WIN32 + { /* Use wide char on windows, so we can show UTF-8 encoded device names */ + wchar_t wideName[MAX_PATH]; + MultiByteToWideChar(CP_UTF8, 0, deviceInfo->name, -1, wideName, MAX_PATH-1); + wprintf( L"Name = %s\n", wideName ); + } +#else + printf( "Name = %s\n", deviceInfo->name ); +#endif + printf( "Host API = %s\n", Pa_GetHostApiInfo( deviceInfo->hostApi )->name ); + printf( "Max inputs = %d", deviceInfo->maxInputChannels ); + printf( ", Max outputs = %d\n", deviceInfo->maxOutputChannels ); + + printf( "Default low input latency = %8.4f\n", deviceInfo->defaultLowInputLatency ); + printf( "Default low output latency = %8.4f\n", deviceInfo->defaultLowOutputLatency ); + printf( "Default high input latency = %8.4f\n", deviceInfo->defaultHighInputLatency ); + printf( "Default high output latency = %8.4f\n", deviceInfo->defaultHighOutputLatency ); + +#ifdef WIN32 +#if PA_USE_ASIO +/* ASIO specific latency information */ + if( Pa_GetHostApiInfo( deviceInfo->hostApi )->type == paASIO ){ + long minLatency, maxLatency, preferredLatency, granularity; + + err = PaAsio_GetAvailableLatencyValues( i, + &minLatency, &maxLatency, &preferredLatency, &granularity ); + + printf( "ASIO minimum buffer size = %ld\n", minLatency ); + printf( "ASIO maximum buffer size = %ld\n", maxLatency ); + printf( "ASIO preferred buffer size = %ld\n", preferredLatency ); + + if( granularity == -1 ) + printf( "ASIO buffer granularity = power of 2\n" ); + else + printf( "ASIO buffer granularity = %ld\n", granularity ); + } +#endif /* PA_USE_ASIO */ +#endif /* WIN32 */ + + printf( "Default sample rate = %8.2f\n", deviceInfo->defaultSampleRate ); + + /* poll for standard sample rates */ + inputParameters.device = i; + inputParameters.channelCount = deviceInfo->maxInputChannels; + inputParameters.sampleFormat = paInt16; + inputParameters.suggestedLatency = 0; /* ignored by Pa_IsFormatSupported() */ + inputParameters.hostApiSpecificStreamInfo = NULL; + + outputParameters.device = i; + outputParameters.channelCount = deviceInfo->maxOutputChannels; + outputParameters.sampleFormat = paInt16; + outputParameters.suggestedLatency = 0; /* ignored by Pa_IsFormatSupported() */ + outputParameters.hostApiSpecificStreamInfo = NULL; + + if( inputParameters.channelCount > 0 ) + { + printf("Supported standard sample rates\n for half-duplex 16 bit %d channel input = \n", + inputParameters.channelCount ); + PrintSupportedStandardSampleRates( &inputParameters, NULL ); + } + + if( outputParameters.channelCount > 0 ) + { + printf("Supported standard sample rates\n for half-duplex 16 bit %d channel output = \n", + outputParameters.channelCount ); + PrintSupportedStandardSampleRates( NULL, &outputParameters ); + } + + if( inputParameters.channelCount > 0 && outputParameters.channelCount > 0 ) + { + printf("Supported standard sample rates\n for full-duplex 16 bit %d channel input, %d channel output = \n", + inputParameters.channelCount, outputParameters.channelCount ); + PrintSupportedStandardSampleRates( &inputParameters, &outputParameters ); + } + } + + Pa_Terminate(); + + printf("----------------------------------------------\n"); + return 0; + +error: + Pa_Terminate(); + fprintf( stderr, "Error number: %d\n", err ); + fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); + return err; +} diff --git a/extern/portaudio/examples/pa_fuzz.c b/extern/portaudio/examples/pa_fuzz.c new file mode 100644 index 0000000..d5f99ec --- /dev/null +++ b/extern/portaudio/examples/pa_fuzz.c @@ -0,0 +1,183 @@ +/** @file pa_fuzz.c + @ingroup examples_src + @brief Distort input like a fuzz box. + @author Phil Burk http://www.softsynth.com +*/ +/* + * $Id$ + * + * This program uses the PortAudio Portable Audio Library. + * For more information see: http://www.portaudio.com + * Copyright (c) 1999-2000 Ross Bencina and Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +#include +#include +#include "portaudio.h" +/* +** Note that many of the older ISA sound cards on PCs do NOT support +** full duplex audio (simultaneous record and playback). +** And some only support full duplex at lower sample rates. +*/ +#define SAMPLE_RATE (44100) +#define PA_SAMPLE_TYPE paFloat32 +#define FRAMES_PER_BUFFER (64) + +typedef float SAMPLE; + +float CubicAmplifier( float input ); +static int fuzzCallback( const void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + const PaStreamCallbackTimeInfo* timeInfo, + PaStreamCallbackFlags statusFlags, + void *userData ); + +/* Non-linear amplifier with soft distortion curve. */ +float CubicAmplifier( float input ) +{ + float output, temp; + if( input < 0.0 ) + { + temp = input + 1.0f; + output = (temp * temp * temp) - 1.0f; + } + else + { + temp = input - 1.0f; + output = (temp * temp * temp) + 1.0f; + } + + return output; +} +#define FUZZ(x) CubicAmplifier(CubicAmplifier(CubicAmplifier(CubicAmplifier(x)))) + +static int gNumNoInputs = 0; +/* This routine will be called by the PortAudio engine when audio is needed. +** It may be called at interrupt level on some machines so don't do anything +** that could mess up the system like calling malloc() or free(). +*/ +static int fuzzCallback( const void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + const PaStreamCallbackTimeInfo* timeInfo, + PaStreamCallbackFlags statusFlags, + void *userData ) +{ + SAMPLE *out = (SAMPLE*)outputBuffer; + const SAMPLE *in = (const SAMPLE*)inputBuffer; + unsigned int i; + (void) timeInfo; /* Prevent unused variable warnings. */ + (void) statusFlags; + (void) userData; + + if( inputBuffer == NULL ) + { + for( i=0; idefaultLowInputLatency; + inputParameters.hostApiSpecificStreamInfo = NULL; + + outputParameters.device = Pa_GetDefaultOutputDevice(); /* default output device */ + if (outputParameters.device == paNoDevice) { + fprintf(stderr,"Error: No default output device.\n"); + goto error; + } + outputParameters.channelCount = 2; /* stereo output */ + outputParameters.sampleFormat = PA_SAMPLE_TYPE; + outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultLowOutputLatency; + outputParameters.hostApiSpecificStreamInfo = NULL; + + err = Pa_OpenStream( + &stream, + &inputParameters, + &outputParameters, + SAMPLE_RATE, + FRAMES_PER_BUFFER, + 0, /* paClipOff, */ /* we won't output out of range samples so don't bother clipping them */ + fuzzCallback, + NULL ); + if( err != paNoError ) goto error; + + err = Pa_StartStream( stream ); + if( err != paNoError ) goto error; + + printf("Hit ENTER to stop program.\n"); + getchar(); + err = Pa_CloseStream( stream ); + if( err != paNoError ) goto error; + + printf("Finished. gNumNoInputs = %d\n", gNumNoInputs ); + Pa_Terminate(); + return 0; + +error: + Pa_Terminate(); + fprintf( stderr, "An error occured while using the portaudio stream\n" ); + fprintf( stderr, "Error number: %d\n", err ); + fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); + return -1; +} diff --git a/extern/portaudio/examples/paex_mono_asio_channel_select.c b/extern/portaudio/examples/paex_mono_asio_channel_select.c new file mode 100644 index 0000000..a141ac0 --- /dev/null +++ b/extern/portaudio/examples/paex_mono_asio_channel_select.c @@ -0,0 +1,167 @@ +/** @file paex_mono_asio_channel_select.c + @ingroup examples_src + @brief Play a monophonic sine wave on a specific ASIO channel. + @author Ross Bencina + @author Phil Burk +*/ +/* + * $Id$ + * + * Authors: + * Ross Bencina + * Phil Burk + * + * This program uses the PortAudio Portable Audio Library. + * For more information see: http://www.portaudio.com + * Copyright (c) 1999-2000 Ross Bencina and Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +#include +#include +#include "portaudio.h" +#include "pa_asio.h" + +#define NUM_SECONDS (10) +#define SAMPLE_RATE (44100) +#define AMPLITUDE (0.8) +#define FRAMES_PER_BUFFER (64) +#define OUTPUT_DEVICE Pa_GetDefaultOutputDevice() + +#ifndef M_PI +#define M_PI (3.14159265) +#endif + +#define TABLE_SIZE (200) +typedef struct +{ + float sine[TABLE_SIZE]; + int phase; +} +paTestData; + +/* This routine will be called by the PortAudio engine when audio is needed. +** It may called at interrupt level on some machines so don't do anything +** that could mess up the system like calling malloc() or free(). +*/ +static int patestCallback( const void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + const PaStreamCallbackTimeInfo* timeInfo, + PaStreamCallbackFlags statusFlags, + void *userData ) +{ + paTestData *data = (paTestData*)userData; + float *out = (float*)outputBuffer; + unsigned long i; + int finished = 0; + /* avoid unused variable warnings */ + (void) inputBuffer; + (void) timeInfo; + (void) statusFlags; + for( i=0; isine[data->phase]; /* left */ + data->phase += 1; + if( data->phase >= TABLE_SIZE ) data->phase -= TABLE_SIZE; + } + return finished; +} + +/*******************************************************************/ +int main(void); +int main(void) +{ + PaStreamParameters outputParameters; + PaAsioStreamInfo asioOutputInfo; + PaStream *stream; + PaError err; + paTestData data; + int outputChannelSelectors[1]; + int i; + printf("PortAudio Test: output MONO sine wave. SR = %d, BufSize = %d\n", SAMPLE_RATE, FRAMES_PER_BUFFER); + /* initialise sinusoidal wavetable */ + for( i=0; idefaultLowOutputLatency; + + /* Use an ASIO specific structure. WARNING - this is not portable. */ + asioOutputInfo.size = sizeof(PaAsioStreamInfo); + asioOutputInfo.hostApiType = paASIO; + asioOutputInfo.version = 1; + asioOutputInfo.flags = paAsioUseChannelSelectors; + outputChannelSelectors[0] = 1; /* skip channel 0 and use the second (right) ASIO device channel */ + asioOutputInfo.channelSelectors = outputChannelSelectors; + outputParameters.hostApiSpecificStreamInfo = &asioOutputInfo; + + err = Pa_OpenStream( + &stream, + NULL, /* no input */ + &outputParameters, + SAMPLE_RATE, + FRAMES_PER_BUFFER, + paClipOff, /* we won't output out of range samples so don't bother clipping them */ + patestCallback, + &data ); + if( err != paNoError ) goto error; + + err = Pa_StartStream( stream ); + if( err != paNoError ) goto error; + + printf("Play for %d seconds.\n", NUM_SECONDS ); fflush(stdout); + Pa_Sleep( NUM_SECONDS * 1000 ); + + err = Pa_StopStream( stream ); + if( err != paNoError ) goto error; + + err = Pa_CloseStream( stream ); + if( err != paNoError ) goto error; + + Pa_Terminate(); + printf("Test finished.\n"); + return err; +error: + Pa_Terminate(); + fprintf( stderr, "An error occured while using the portaudio stream\n" ); + fprintf( stderr, "Error number: %d\n", err ); + fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); + return err; +} diff --git a/extern/portaudio/examples/paex_ocean_shore.c b/extern/portaudio/examples/paex_ocean_shore.c new file mode 100644 index 0000000..7eb7f20 --- /dev/null +++ b/extern/portaudio/examples/paex_ocean_shore.c @@ -0,0 +1,533 @@ +/** @file paex_ocean_shore.c + @ingroup examples_src + @brief Generate Pink Noise using Gardner method, and make "waves". Provides an example of how to + post stuff to/from the audio callback using lock-free FIFOs implemented by the PA ringbuffer. + + Optimization suggested by James McCartney uses a tree + to select which random value to replace. +
    +	x x x x x x x x x x x x x x x x 
    +	x   x   x   x   x   x   x   x   
    +	x       x       x       x       
    +	 x               x               
    +	   x   
    +
    + Tree is generated by counting trailing zeros in an increasing index. + When the index is zero, no random number is selected. + + @author Phil Burk http://www.softsynth.com + Robert Bielik +*/ +/* + * $Id$ + * + * This program uses the PortAudio Portable Audio Library. + * For more information see: http://www.portaudio.com + * Copyright (c) 1999-2000 Ross Bencina and Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +#include +#include +#include +#include +#include + +#include "portaudio.h" +#include "pa_ringbuffer.h" +#include "pa_util.h" + +#define PINK_MAX_RANDOM_ROWS (30) +#define PINK_RANDOM_BITS (24) +#define PINK_RANDOM_SHIFT ((sizeof(long)*8)-PINK_RANDOM_BITS) + +typedef struct +{ + long pink_Rows[PINK_MAX_RANDOM_ROWS]; + long pink_RunningSum; /* Used to optimize summing of generators. */ + int pink_Index; /* Incremented each sample. */ + int pink_IndexMask; /* Index wrapped by ANDing with this mask. */ + float pink_Scalar; /* Used to scale within range of -1.0 to +1.0 */ +} +PinkNoise; + +typedef struct +{ + float bq_b0; + float bq_b1; + float bq_b2; + float bq_a1; + float bq_a2; +} BiQuad; + +typedef enum +{ + State_kAttack, + State_kPreDecay, + State_kDecay, + State_kCnt, +} EnvState; + +typedef struct +{ + PinkNoise wave_left; + PinkNoise wave_right; + + BiQuad wave_bq_coeffs; + float wave_bq_left[2]; + float wave_bq_right[2]; + + EnvState wave_envelope_state; + float wave_envelope_level; + float wave_envelope_max_level; + float wave_pan_left; + float wave_pan_right; + float wave_attack_incr; + float wave_decay_incr; + +} OceanWave; + +/* Prototypes */ +static unsigned long GenerateRandomNumber( void ); +void InitializePinkNoise( PinkNoise *pink, int numRows ); +float GeneratePinkNoise( PinkNoise *pink ); +unsigned GenerateWave( OceanWave* wave, float* output, unsigned noOfFrames); + +/************************************************************/ +/* Calculate pseudo-random 32 bit number based on linear congruential method. */ +static unsigned long GenerateRandomNumber( void ) +{ + /* Change this seed for different random sequences. */ + static unsigned long randSeed = 22222; + randSeed = (randSeed * 196314165) + 907633515; + return randSeed; +} + +/************************************************************/ +/* Setup PinkNoise structure for N rows of generators. */ +void InitializePinkNoise( PinkNoise *pink, int numRows ) +{ + int i; + long pmax; + pink->pink_Index = 0; + pink->pink_IndexMask = (1<pink_Scalar = 1.0f / pmax; + /* Initialize rows. */ + for( i=0; ipink_Rows[i] = 0; + pink->pink_RunningSum = 0; +} + +/* Generate Pink noise values between -1.0 and +1.0 */ +float GeneratePinkNoise( PinkNoise *pink ) +{ + long newRandom; + long sum; + float output; + /* Increment and mask index. */ + pink->pink_Index = (pink->pink_Index + 1) & pink->pink_IndexMask; + /* If index is zero, don't update any random values. */ + if( pink->pink_Index != 0 ) + { + /* Determine how many trailing zeros in PinkIndex. */ + /* This algorithm will hang if n==0 so test first. */ + int numZeros = 0; + int n = pink->pink_Index; + while( (n & 1) == 0 ) + { + n = n >> 1; + numZeros++; + } + /* Replace the indexed ROWS random value. + * Subtract and add back to RunningSum instead of adding all the random + * values together. Only one changes each time. + */ + pink->pink_RunningSum -= pink->pink_Rows[numZeros]; + newRandom = ((long)GenerateRandomNumber()) >> PINK_RANDOM_SHIFT; + pink->pink_RunningSum += newRandom; + pink->pink_Rows[numZeros] = newRandom; + } + + /* Add extra white noise value. */ + newRandom = ((long)GenerateRandomNumber()) >> PINK_RANDOM_SHIFT; + sum = pink->pink_RunningSum + newRandom; + /* Scale to range of -1.0 to 0.9999. */ + output = pink->pink_Scalar * sum; + return output; +} + +float ProcessBiquad(const BiQuad* coeffs, float* memory, float input) +{ + float w = input - coeffs->bq_a1 * memory[0] - coeffs->bq_a2 * memory[1]; + float out = coeffs->bq_b1 * memory[0] + coeffs->bq_b2 * memory[1] + coeffs->bq_b0 * w; + memory[1] = memory[0]; + memory[0] = w; + return out; +} + +static const float one_over_2Q_LP = 0.3f; +static const float one_over_2Q_HP = 1.0f; + +unsigned GenerateWave( OceanWave* wave, float* output, unsigned noOfFrames ) +{ + unsigned retval=0,i; + float targetLevel, levelIncr, currentLevel; + switch (wave->wave_envelope_state) + { + case State_kAttack: + targetLevel = noOfFrames * wave->wave_attack_incr + wave->wave_envelope_level; + if (targetLevel >= wave->wave_envelope_max_level) + { + /* Go to decay state */ + wave->wave_envelope_state = State_kPreDecay; + targetLevel = wave->wave_envelope_max_level; + } + /* Calculate lowpass biquad coeffs + + alpha = sin(w0)/(2*Q) + + b0 = (1 - cos(w0))/2 + b1 = 1 - cos(w0) + b2 = (1 - cos(w0))/2 + a0 = 1 + alpha + a1 = -2*cos(w0) + a2 = 1 - alpha + + w0 = [0 - pi[ + */ + { + const float w0 = 3.141592654f * targetLevel / wave->wave_envelope_max_level; + const float alpha = sinf(w0) * one_over_2Q_LP; + const float cosw0 = cosf(w0); + const float a0_fact = 1.0f / (1.0f + alpha); + wave->wave_bq_coeffs.bq_b1 = (1.0f - cosw0) * a0_fact; + wave->wave_bq_coeffs.bq_b0 = wave->wave_bq_coeffs.bq_b1 * 0.5f; + wave->wave_bq_coeffs.bq_b2 = wave->wave_bq_coeffs.bq_b0; + wave->wave_bq_coeffs.bq_a2 = (1.0f - alpha) * a0_fact; + wave->wave_bq_coeffs.bq_a1 = -2.0f * cosw0 * a0_fact; + } + break; + + case State_kPreDecay: + /* Reset biquad state */ + memset(wave->wave_bq_left, 0, 2 * sizeof(float)); + memset(wave->wave_bq_right, 0, 2 * sizeof(float)); + wave->wave_envelope_state = State_kDecay; + + /* Deliberate fall-through */ + + case State_kDecay: + targetLevel = noOfFrames * wave->wave_decay_incr + wave->wave_envelope_level; + if (targetLevel < 0.001f) + { + /* < -60 dB, we're done */ + wave->wave_envelope_state = 3; + retval = 1; + } + /* Calculate highpass biquad coeffs + + alpha = sin(w0)/(2*Q) + + b0 = (1 + cos(w0))/2 + b1 = -(1 + cos(w0)) + b2 = (1 + cos(w0))/2 + a0 = 1 + alpha + a1 = -2*cos(w0) + a2 = 1 - alpha + + w0 = [0 - pi/2[ + */ + { + const float v = targetLevel / wave->wave_envelope_max_level; + const float w0 = 1.5707963f * (1.0f - (v*v)); + const float alpha = sinf(w0) * one_over_2Q_HP; + const float cosw0 = cosf(w0); + const float a0_fact = 1.0f / (1.0f + alpha); + wave->wave_bq_coeffs.bq_b1 = (float)(- (1 + cosw0) * a0_fact); + wave->wave_bq_coeffs.bq_b0 = -wave->wave_bq_coeffs.bq_b1 * 0.5f; + wave->wave_bq_coeffs.bq_b2 = wave->wave_bq_coeffs.bq_b0; + wave->wave_bq_coeffs.bq_a2 = (float)((1.0 - alpha) * a0_fact); + wave->wave_bq_coeffs.bq_a1 = (float)(-2.0 * cosw0 * a0_fact); + } + break; + + default: + break; + } + + currentLevel = wave->wave_envelope_level; + wave->wave_envelope_level = targetLevel; + levelIncr = (targetLevel - currentLevel) / noOfFrames; + + for (i = 0; i < noOfFrames; ++i, currentLevel += levelIncr) + { + (*output++) += ProcessBiquad(&wave->wave_bq_coeffs, wave->wave_bq_left, (GeneratePinkNoise(&wave->wave_left))) * currentLevel * wave->wave_pan_left; + (*output++) += ProcessBiquad(&wave->wave_bq_coeffs, wave->wave_bq_right, (GeneratePinkNoise(&wave->wave_right))) * currentLevel * wave->wave_pan_right; + } + + return retval; +} + + +/*******************************************************************/ + +/* Context for callback routine. */ +typedef struct +{ + OceanWave* waves[16]; /* Maximum 16 waves */ + unsigned noOfActiveWaves; + + /* Ring buffer (FIFO) for "communicating" towards audio callback */ + PaUtilRingBuffer rBufToRT; + void* rBufToRTData; + + /* Ring buffer (FIFO) for "communicating" from audio callback */ + PaUtilRingBuffer rBufFromRT; + void* rBufFromRTData; +} +paTestData; + +/* This routine will be called by the PortAudio engine when audio is needed. +** It may called at interrupt level on some machines so don't do anything +** that could mess up the system like calling malloc() or free(). +*/ +static int patestCallback(const void* inputBuffer, + void* outputBuffer, + unsigned long framesPerBuffer, + const PaStreamCallbackTimeInfo* timeInfo, + PaStreamCallbackFlags statusFlags, + void* userData) +{ + int i; + paTestData *data = (paTestData*)userData; + float *out = (float*)outputBuffer; + (void) inputBuffer; /* Prevent "unused variable" warnings. */ + + /* Reset output data first */ + memset(out, 0, framesPerBuffer * 2 * sizeof(float)); + + for (i = 0; i < 16; ++i) + { + /* Consume the input queue */ + if (data->waves[i] == 0 && PaUtil_GetRingBufferReadAvailable(&data->rBufToRT)) + { + OceanWave* ptr = 0; + PaUtil_ReadRingBuffer(&data->rBufToRT, &ptr, 1); + data->waves[i] = ptr; + } + + if (data->waves[i] != 0) + { + if (GenerateWave(data->waves[i], out, framesPerBuffer)) + { + /* If wave is "done", post it back to the main thread for deletion */ + PaUtil_WriteRingBuffer(&data->rBufFromRT, &data->waves[i], 1); + data->waves[i] = 0; + } + } + } + return paContinue; +} + +#define NEW_ROW_SIZE (12 + (8*rand())/RAND_MAX) + +OceanWave* InitializeWave(double SR, float attackInSeconds, float maxLevel, float positionLeftRight) +{ + OceanWave* wave = NULL; + static unsigned lastNoOfRows = 12; + unsigned newNoOfRows; + + wave = (OceanWave*)PaUtil_AllocateMemory(sizeof(OceanWave)); + if (wave != NULL) + { + InitializePinkNoise(&wave->wave_left, lastNoOfRows); + while ((newNoOfRows = NEW_ROW_SIZE) == lastNoOfRows); + InitializePinkNoise(&wave->wave_right, newNoOfRows); + lastNoOfRows = newNoOfRows; + + wave->wave_envelope_state = State_kAttack; + wave->wave_envelope_level = 0.f; + wave->wave_envelope_max_level = maxLevel; + wave->wave_attack_incr = wave->wave_envelope_max_level / (attackInSeconds * (float)SR); + wave->wave_decay_incr = - wave->wave_envelope_max_level / (attackInSeconds * 4 * (float)SR); + + wave->wave_pan_left = sqrtf(1.0f - positionLeftRight); + wave->wave_pan_right = sqrtf(positionLeftRight); + } + return wave; +} + +static float GenerateFloatRandom(float minValue, float maxValue) +{ + return minValue + ((maxValue - minValue) * rand()) / RAND_MAX; +} + +/*******************************************************************/ +int main(void); +int main(void) +{ + PaStream* stream; + PaError err; + paTestData data = {0}; + PaStreamParameters outputParameters; + double tstamp; + double tstart; + double tdelta = 0; + static const double SR = 44100.0; + static const int FPB = 128; /* Frames per buffer: 2.9 ms buffers. */ + + /* Initialize communication buffers (queues) */ + data.rBufToRTData = PaUtil_AllocateMemory(sizeof(OceanWave*) * 256); + if (data.rBufToRTData == NULL) + { + return 1; + } + PaUtil_InitializeRingBuffer(&data.rBufToRT, sizeof(OceanWave*), 256, data.rBufToRTData); + + data.rBufFromRTData = PaUtil_AllocateMemory(sizeof(OceanWave*) * 256); + if (data.rBufFromRTData == NULL) + { + return 1; + } + PaUtil_InitializeRingBuffer(&data.rBufFromRT, sizeof(OceanWave*), 256, data.rBufFromRTData); + + err = Pa_Initialize(); + if( err != paNoError ) goto error; + + /* Open a stereo PortAudio stream so we can hear the result. */ + outputParameters.device = Pa_GetDefaultOutputDevice(); /* Take the default output device. */ + if (outputParameters.device == paNoDevice) { + fprintf(stderr,"Error: No default output device.\n"); + goto error; + } + outputParameters.channelCount = 2; /* Stereo output, most likely supported. */ + outputParameters.hostApiSpecificStreamInfo = NULL; + outputParameters.sampleFormat = paFloat32; /* 32 bit floating point output. */ + outputParameters.suggestedLatency = Pa_GetDeviceInfo(outputParameters.device)->defaultLowOutputLatency; + err = Pa_OpenStream(&stream, + NULL, /* No input. */ + &outputParameters, + SR, /* Sample rate. */ + FPB, /* Frames per buffer. */ + paDitherOff, /* Clip but don't dither */ + patestCallback, + &data); + if( err != paNoError ) goto error; + + err = Pa_StartStream( stream ); + if( err != paNoError ) goto error; + + printf("Stereo \"ocean waves\" for one minute...\n"); + + tstart = PaUtil_GetTime(); + tstamp = tstart; + srand( (unsigned)time(NULL) ); + + while( ( err = Pa_IsStreamActive( stream ) ) == 1 ) + { + const double tcurrent = PaUtil_GetTime(); + + /* Delete "waves" that the callback is finished with */ + while (PaUtil_GetRingBufferReadAvailable(&data.rBufFromRT) > 0) + { + OceanWave* ptr = 0; + PaUtil_ReadRingBuffer(&data.rBufFromRT, &ptr, 1); + if (ptr != 0) + { + printf("Wave is deleted...\n"); + PaUtil_FreeMemory(ptr); + --data.noOfActiveWaves; + } + } + + if (tcurrent - tstart < 60.0) /* Only start new "waves" during one minute */ + { + if (tcurrent >= tstamp) + { + double tdelta = GenerateFloatRandom(1.0f, 4.0f); + tstamp += tdelta; + + if (data.noOfActiveWaves<16) + { + const float attackTime = GenerateFloatRandom(2.0f, 6.0f); + const float level = GenerateFloatRandom(0.1f, 1.0f); + const float pos = GenerateFloatRandom(0.0f, 1.0f); + OceanWave* p = InitializeWave(SR, attackTime, level, pos); + if (p != NULL) + { + /* Post wave to audio callback */ + PaUtil_WriteRingBuffer(&data.rBufToRT, &p, 1); + ++data.noOfActiveWaves; + + printf("Starting wave at level = %.2f, attack = %.2lf, pos = %.2lf\n", level, attackTime, pos); + } + } + } + } + else + { + if (data.noOfActiveWaves == 0) + { + printf("All waves finished!\n"); + break; + } + } + + Pa_Sleep(100); + } + if( err < 0 ) goto error; + + err = Pa_CloseStream( stream ); + if( err != paNoError ) goto error; + + if (data.rBufToRTData) + { + PaUtil_FreeMemory(data.rBufToRTData); + } + if (data.rBufFromRTData) + { + PaUtil_FreeMemory(data.rBufFromRTData); + } + + Pa_Sleep(1000); + + Pa_Terminate(); + return 0; + +error: + Pa_Terminate(); + fprintf( stderr, "An error occured while using the portaudio stream\n" ); + fprintf( stderr, "Error number: %d\n", err ); + fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); + return 0; +} diff --git a/extern/portaudio/examples/paex_pink.c b/extern/portaudio/examples/paex_pink.c new file mode 100644 index 0000000..3714ba7 --- /dev/null +++ b/extern/portaudio/examples/paex_pink.c @@ -0,0 +1,280 @@ +/** @file paex_pink.c + @ingroup examples_src + @brief Generate Pink Noise using Gardner method. + + Optimization suggested by James McCartney uses a tree + to select which random value to replace. +
    +	x x x x x x x x x x x x x x x x 
    +	x   x   x   x   x   x   x   x   
    +	x       x       x       x       
    +	 x               x               
    +	   x   
    +
    + Tree is generated by counting trailing zeros in an increasing index. + When the index is zero, no random number is selected. + + @author Phil Burk http://www.softsynth.com +*/ +/* + * $Id$ + * + * This program uses the PortAudio Portable Audio Library. + * For more information see: http://www.portaudio.com + * Copyright (c) 1999-2000 Ross Bencina and Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +#include +#include +#include "portaudio.h" + +#define PINK_MAX_RANDOM_ROWS (30) +#define PINK_RANDOM_BITS (24) +#define PINK_RANDOM_SHIFT ((sizeof(long)*8)-PINK_RANDOM_BITS) + +typedef struct +{ + long pink_Rows[PINK_MAX_RANDOM_ROWS]; + long pink_RunningSum; /* Used to optimize summing of generators. */ + int pink_Index; /* Incremented each sample. */ + int pink_IndexMask; /* Index wrapped by ANDing with this mask. */ + float pink_Scalar; /* Used to scale within range of -1.0 to +1.0 */ +} +PinkNoise; + +/* Prototypes */ +static unsigned long GenerateRandomNumber( void ); +void InitializePinkNoise( PinkNoise *pink, int numRows ); +float GeneratePinkNoise( PinkNoise *pink ); + +/************************************************************/ +/* Calculate pseudo-random 32 bit number based on linear congruential method. */ +static unsigned long GenerateRandomNumber( void ) +{ + /* Change this seed for different random sequences. */ + static unsigned long randSeed = 22222; + randSeed = (randSeed * 196314165) + 907633515; + return randSeed; +} + +/************************************************************/ +/* Setup PinkNoise structure for N rows of generators. */ +void InitializePinkNoise( PinkNoise *pink, int numRows ) +{ + int i; + long pmax; + pink->pink_Index = 0; + pink->pink_IndexMask = (1<pink_Scalar = 1.0f / pmax; + /* Initialize rows. */ + for( i=0; ipink_Rows[i] = 0; + pink->pink_RunningSum = 0; +} + +#define PINK_MEASURE +#ifdef PINK_MEASURE +float pinkMax = -999.0; +float pinkMin = 999.0; +#endif + +/* Generate Pink noise values between -1.0 and +1.0 */ +float GeneratePinkNoise( PinkNoise *pink ) +{ + long newRandom; + long sum; + float output; + /* Increment and mask index. */ + pink->pink_Index = (pink->pink_Index + 1) & pink->pink_IndexMask; + /* If index is zero, don't update any random values. */ + if( pink->pink_Index != 0 ) + { + /* Determine how many trailing zeros in PinkIndex. */ + /* This algorithm will hang if n==0 so test first. */ + int numZeros = 0; + int n = pink->pink_Index; + while( (n & 1) == 0 ) + { + n = n >> 1; + numZeros++; + } + /* Replace the indexed ROWS random value. + * Subtract and add back to RunningSum instead of adding all the random + * values together. Only one changes each time. + */ + pink->pink_RunningSum -= pink->pink_Rows[numZeros]; + newRandom = ((long)GenerateRandomNumber()) >> PINK_RANDOM_SHIFT; + pink->pink_RunningSum += newRandom; + pink->pink_Rows[numZeros] = newRandom; + } + + /* Add extra white noise value. */ + newRandom = ((long)GenerateRandomNumber()) >> PINK_RANDOM_SHIFT; + sum = pink->pink_RunningSum + newRandom; + /* Scale to range of -1.0 to 0.9999. */ + output = pink->pink_Scalar * sum; +#ifdef PINK_MEASURE + /* Check Min/Max */ + if( output > pinkMax ) pinkMax = output; + else if( output < pinkMin ) pinkMin = output; +#endif + return output; +} + +/*******************************************************************/ +#define PINK_TEST +#ifdef PINK_TEST + +/* Context for callback routine. */ +typedef struct +{ + PinkNoise leftPink; + PinkNoise rightPink; + unsigned int sampsToGo; +} +paTestData; + +/* This routine will be called by the PortAudio engine when audio is needed. +** It may called at interrupt level on some machines so don't do anything +** that could mess up the system like calling malloc() or free(). +*/ +static int patestCallback(const void* inputBuffer, + void* outputBuffer, + unsigned long framesPerBuffer, + const PaStreamCallbackTimeInfo* timeInfo, + PaStreamCallbackFlags statusFlags, + void* userData) +{ + int finished; + int i; + int numFrames; + paTestData *data = (paTestData*)userData; + float *out = (float*)outputBuffer; + (void) inputBuffer; /* Prevent "unused variable" warnings. */ + + /* Are we almost at end. */ + if( data->sampsToGo < framesPerBuffer ) + { + numFrames = data->sampsToGo; + finished = 1; + } + else + { + numFrames = framesPerBuffer; + finished = 0; + } + for( i=0; ileftPink ); + *out++ = GeneratePinkNoise( &data->rightPink ); + } + data->sampsToGo -= numFrames; + return finished; +} + +/*******************************************************************/ +int main(void); +int main(void) +{ + PaStream* stream; + PaError err; + paTestData data; + PaStreamParameters outputParameters; + int totalSamps; + static const double SR = 44100.0; + static const int FPB = 2048; /* Frames per buffer: 46 ms buffers. */ + + /* Initialize two pink noise signals with different numbers of rows. */ + InitializePinkNoise( &data.leftPink, 12 ); + InitializePinkNoise( &data.rightPink, 16 ); + + /* Look at a few values. */ + { + int i; + float pink; + for( i=0; i<20; i++ ) + { + pink = GeneratePinkNoise( &data.leftPink ); + printf("Pink = %f\n", pink ); + } + } + + data.sampsToGo = totalSamps = (int)(60.0 * SR); /* Play a whole minute. */ + err = Pa_Initialize(); + if( err != paNoError ) goto error; + + /* Open a stereo PortAudio stream so we can hear the result. */ + outputParameters.device = Pa_GetDefaultOutputDevice(); /* Take the default output device. */ + if (outputParameters.device == paNoDevice) { + fprintf(stderr,"Error: No default output device.\n"); + goto error; + } + outputParameters.channelCount = 2; /* Stereo output, most likely supported. */ + outputParameters.hostApiSpecificStreamInfo = NULL; + outputParameters.sampleFormat = paFloat32; /* 32 bit floating point output. */ + outputParameters.suggestedLatency = + Pa_GetDeviceInfo(outputParameters.device)->defaultLowOutputLatency; + err = Pa_OpenStream(&stream, + NULL, /* No input. */ + &outputParameters, + SR, /* Sample rate. */ + FPB, /* Frames per buffer. */ + paClipOff, /* we won't output out of range samples so don't bother clipping them */ + patestCallback, + &data); + if( err != paNoError ) goto error; + + err = Pa_StartStream( stream ); + if( err != paNoError ) goto error; + + printf("Stereo pink noise for one minute...\n"); + + while( ( err = Pa_IsStreamActive( stream ) ) == 1 ) Pa_Sleep(100); + if( err < 0 ) goto error; + + err = Pa_CloseStream( stream ); + if( err != paNoError ) goto error; +#ifdef PINK_MEASURE + printf("Pink min = %f, max = %f\n", pinkMin, pinkMax ); +#endif + Pa_Terminate(); + return 0; +error: + Pa_Terminate(); + fprintf( stderr, "An error occured while using the portaudio stream\n" ); + fprintf( stderr, "Error number: %d\n", err ); + fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); + return 0; +} +#endif /* PINK_TEST */ diff --git a/extern/portaudio/examples/paex_read_write_wire.c b/extern/portaudio/examples/paex_read_write_wire.c new file mode 100644 index 0000000..4208a01 --- /dev/null +++ b/extern/portaudio/examples/paex_read_write_wire.c @@ -0,0 +1,205 @@ +/** @file paex_read_write_wire.c + @ingroup examples_src + @brief Tests full duplex blocking I/O by passing input straight to output. + @author Bjorn Roche. XO Audio LLC for Z-Systems Engineering. + @author based on code by: Phil Burk http://www.softsynth.com + @author based on code by: Ross Bencina rossb@audiomulch.com +*/ +/* + * $Id: patest_read_record.c 757 2004-02-13 07:48:10Z rossbencina $ + * + * This program uses the PortAudio Portable Audio Library. + * For more information see: http://www.portaudio.com + * Copyright (c) 1999-2000 Ross Bencina and Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +#include +#include +#include +#include "portaudio.h" + +/* #define SAMPLE_RATE (17932) // Test failure to open with this value. */ +#define SAMPLE_RATE (44100) +#define FRAMES_PER_BUFFER (512) +#define NUM_SECONDS (10) +/* #define DITHER_FLAG (paDitherOff) */ +#define DITHER_FLAG (0) + +/* Select sample format. */ +#if 1 +#define PA_SAMPLE_TYPE paFloat32 +#define SAMPLE_SIZE (4) +#define SAMPLE_SILENCE (0.0f) +#define PRINTF_S_FORMAT "%.8f" +#elif 0 +#define PA_SAMPLE_TYPE paInt16 +#define SAMPLE_SIZE (2) +#define SAMPLE_SILENCE (0) +#define PRINTF_S_FORMAT "%d" +#elif 0 +#define PA_SAMPLE_TYPE paInt24 +#define SAMPLE_SIZE (3) +#define SAMPLE_SILENCE (0) +#define PRINTF_S_FORMAT "%d" +#elif 0 +#define PA_SAMPLE_TYPE paInt8 +#define SAMPLE_SIZE (1) +#define SAMPLE_SILENCE (0) +#define PRINTF_S_FORMAT "%d" +#else +#define PA_SAMPLE_TYPE paUInt8 +#define SAMPLE_SIZE (1) +#define SAMPLE_SILENCE (128) +#define PRINTF_S_FORMAT "%d" +#endif + +/*******************************************************************/ +int main(void); +int main(void) +{ + PaStreamParameters inputParameters, outputParameters; + PaStream *stream = NULL; + PaError err; + const PaDeviceInfo* inputInfo; + const PaDeviceInfo* outputInfo; + char *sampleBlock = NULL; + int i; + int numBytes; + int numChannels; + + printf("patest_read_write_wire.c\n"); fflush(stdout); + printf("sizeof(int) = %lu\n", sizeof(int)); fflush(stdout); + printf("sizeof(long) = %lu\n", sizeof(long)); fflush(stdout); + + err = Pa_Initialize(); + if( err != paNoError ) goto error2; + + inputParameters.device = Pa_GetDefaultInputDevice(); /* default input device */ + printf( "Input device # %d.\n", inputParameters.device ); + inputInfo = Pa_GetDeviceInfo( inputParameters.device ); + printf( " Name: %s\n", inputInfo->name ); + printf( " LL: %g s\n", inputInfo->defaultLowInputLatency ); + printf( " HL: %g s\n", inputInfo->defaultHighInputLatency ); + + outputParameters.device = Pa_GetDefaultOutputDevice(); /* default output device */ + printf( "Output device # %d.\n", outputParameters.device ); + outputInfo = Pa_GetDeviceInfo( outputParameters.device ); + printf( " Name: %s\n", outputInfo->name ); + printf( " LL: %g s\n", outputInfo->defaultLowOutputLatency ); + printf( " HL: %g s\n", outputInfo->defaultHighOutputLatency ); + + numChannels = inputInfo->maxInputChannels < outputInfo->maxOutputChannels + ? inputInfo->maxInputChannels : outputInfo->maxOutputChannels; + printf( "Num channels = %d.\n", numChannels ); + + inputParameters.channelCount = numChannels; + inputParameters.sampleFormat = PA_SAMPLE_TYPE; + inputParameters.suggestedLatency = inputInfo->defaultHighInputLatency ; + inputParameters.hostApiSpecificStreamInfo = NULL; + + outputParameters.channelCount = numChannels; + outputParameters.sampleFormat = PA_SAMPLE_TYPE; + outputParameters.suggestedLatency = outputInfo->defaultHighOutputLatency; + outputParameters.hostApiSpecificStreamInfo = NULL; + + /* -- setup -- */ + + err = Pa_OpenStream( + &stream, + &inputParameters, + &outputParameters, + SAMPLE_RATE, + FRAMES_PER_BUFFER, + paClipOff, /* we won't output out of range samples so don't bother clipping them */ + NULL, /* no callback, use blocking API */ + NULL ); /* no callback, so no callback userData */ + if( err != paNoError ) goto error2; + + numBytes = FRAMES_PER_BUFFER * numChannels * SAMPLE_SIZE ; + sampleBlock = (char *) malloc( numBytes ); + if( sampleBlock == NULL ) + { + printf("Could not allocate record array.\n"); + goto error1; + } + memset( sampleBlock, SAMPLE_SILENCE, numBytes ); + + err = Pa_StartStream( stream ); + if( err != paNoError ) goto error1; + printf("Wire on. Will run %d seconds.\n", NUM_SECONDS); fflush(stdout); + + for( i=0; i<(NUM_SECONDS*SAMPLE_RATE)/FRAMES_PER_BUFFER; ++i ) + { + // You may get underruns or overruns if the output is not primed by PortAudio. + err = Pa_WriteStream( stream, sampleBlock, FRAMES_PER_BUFFER ); + if( err ) goto xrun; + err = Pa_ReadStream( stream, sampleBlock, FRAMES_PER_BUFFER ); + if( err ) goto xrun; + } + printf("Wire off.\n"); fflush(stdout); + + err = Pa_StopStream( stream ); + if( err != paNoError ) goto error1; + + free( sampleBlock ); + + Pa_Terminate(); + return 0; + +xrun: + printf("err = %d\n", err); fflush(stdout); + if( stream ) { + Pa_AbortStream( stream ); + Pa_CloseStream( stream ); + } + free( sampleBlock ); + Pa_Terminate(); + if( err & paInputOverflow ) + fprintf( stderr, "Input Overflow.\n" ); + if( err & paOutputUnderflow ) + fprintf( stderr, "Output Underflow.\n" ); + return -2; +error1: + free( sampleBlock ); +error2: + if( stream ) { + Pa_AbortStream( stream ); + Pa_CloseStream( stream ); + } + Pa_Terminate(); + fprintf( stderr, "An error occured while using the portaudio stream\n" ); + fprintf( stderr, "Error number: %d\n", err ); + fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); + return -1; +} + diff --git a/extern/portaudio/examples/paex_record.c b/extern/portaudio/examples/paex_record.c new file mode 100644 index 0000000..99226fc --- /dev/null +++ b/extern/portaudio/examples/paex_record.c @@ -0,0 +1,354 @@ +/** @file paex_record.c + @ingroup examples_src + @brief Record input into an array; Save array to a file; Playback recorded data. + @author Phil Burk http://www.softsynth.com +*/ +/* + * $Id$ + * + * This program uses the PortAudio Portable Audio Library. + * For more information see: http://www.portaudio.com + * Copyright (c) 1999-2000 Ross Bencina and Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +#include +#include +#include "portaudio.h" + +/* #define SAMPLE_RATE (17932) // Test failure to open with this value. */ +#define SAMPLE_RATE (44100) +#define FRAMES_PER_BUFFER (512) +#define NUM_SECONDS (5) +#define NUM_CHANNELS (2) +/* #define DITHER_FLAG (paDitherOff) */ +#define DITHER_FLAG (0) /**/ +/** Set to 1 if you want to capture the recording to a file. */ +#define WRITE_TO_FILE (0) + +/* Select sample format. */ +#if 1 +#define PA_SAMPLE_TYPE paFloat32 +typedef float SAMPLE; +#define SAMPLE_SILENCE (0.0f) +#define PRINTF_S_FORMAT "%.8f" +#elif 1 +#define PA_SAMPLE_TYPE paInt16 +typedef short SAMPLE; +#define SAMPLE_SILENCE (0) +#define PRINTF_S_FORMAT "%d" +#elif 0 +#define PA_SAMPLE_TYPE paInt8 +typedef char SAMPLE; +#define SAMPLE_SILENCE (0) +#define PRINTF_S_FORMAT "%d" +#else +#define PA_SAMPLE_TYPE paUInt8 +typedef unsigned char SAMPLE; +#define SAMPLE_SILENCE (128) +#define PRINTF_S_FORMAT "%d" +#endif + +typedef struct +{ + int frameIndex; /* Index into sample array. */ + int maxFrameIndex; + SAMPLE *recordedSamples; +} +paTestData; + +/* This routine will be called by the PortAudio engine when audio is needed. +** It may be called at interrupt level on some machines so don't do anything +** that could mess up the system like calling malloc() or free(). +*/ +static int recordCallback( const void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + const PaStreamCallbackTimeInfo* timeInfo, + PaStreamCallbackFlags statusFlags, + void *userData ) +{ + paTestData *data = (paTestData*)userData; + const SAMPLE *rptr = (const SAMPLE*)inputBuffer; + SAMPLE *wptr = &data->recordedSamples[data->frameIndex * NUM_CHANNELS]; + long framesToCalc; + long i; + int finished; + unsigned long framesLeft = data->maxFrameIndex - data->frameIndex; + + (void) outputBuffer; /* Prevent unused variable warnings. */ + (void) timeInfo; + (void) statusFlags; + (void) userData; + + if( framesLeft < framesPerBuffer ) + { + framesToCalc = framesLeft; + finished = paComplete; + } + else + { + framesToCalc = framesPerBuffer; + finished = paContinue; + } + + if( inputBuffer == NULL ) + { + for( i=0; iframeIndex += framesToCalc; + return finished; +} + +/* This routine will be called by the PortAudio engine when audio is needed. +** It may be called at interrupt level on some machines so don't do anything +** that could mess up the system like calling malloc() or free(). +*/ +static int playCallback( const void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + const PaStreamCallbackTimeInfo* timeInfo, + PaStreamCallbackFlags statusFlags, + void *userData ) +{ + paTestData *data = (paTestData*)userData; + SAMPLE *rptr = &data->recordedSamples[data->frameIndex * NUM_CHANNELS]; + SAMPLE *wptr = (SAMPLE*)outputBuffer; + unsigned int i; + int finished; + unsigned int framesLeft = data->maxFrameIndex - data->frameIndex; + + (void) inputBuffer; /* Prevent unused variable warnings. */ + (void) timeInfo; + (void) statusFlags; + (void) userData; + + if( framesLeft < framesPerBuffer ) + { + /* final buffer... */ + for( i=0; iframeIndex += framesLeft; + finished = paComplete; + } + else + { + for( i=0; iframeIndex += framesPerBuffer; + finished = paContinue; + } + return finished; +} + +/*******************************************************************/ +int main(void); +int main(void) +{ + PaStreamParameters inputParameters, + outputParameters; + PaStream* stream; + PaError err = paNoError; + paTestData data; + int i; + int totalFrames; + int numSamples; + int numBytes; + SAMPLE max, val; + double average; + + printf("patest_record.c\n"); fflush(stdout); + + data.maxFrameIndex = totalFrames = NUM_SECONDS * SAMPLE_RATE; /* Record for a few seconds. */ + data.frameIndex = 0; + numSamples = totalFrames * NUM_CHANNELS; + numBytes = numSamples * sizeof(SAMPLE); + data.recordedSamples = (SAMPLE *) malloc( numBytes ); /* From now on, recordedSamples is initialised. */ + if( data.recordedSamples == NULL ) + { + printf("Could not allocate record array.\n"); + goto done; + } + for( i=0; idefaultLowInputLatency; + inputParameters.hostApiSpecificStreamInfo = NULL; + + /* Record some audio. -------------------------------------------- */ + err = Pa_OpenStream( + &stream, + &inputParameters, + NULL, /* &outputParameters, */ + SAMPLE_RATE, + FRAMES_PER_BUFFER, + paClipOff, /* we won't output out of range samples so don't bother clipping them */ + recordCallback, + &data ); + if( err != paNoError ) goto done; + + err = Pa_StartStream( stream ); + if( err != paNoError ) goto done; + printf("\n=== Now recording!! Please speak into the microphone. ===\n"); fflush(stdout); + + while( ( err = Pa_IsStreamActive( stream ) ) == 1 ) + { + Pa_Sleep(1000); + printf("index = %d\n", data.frameIndex ); fflush(stdout); + } + if( err < 0 ) goto done; + + err = Pa_CloseStream( stream ); + if( err != paNoError ) goto done; + + /* Measure maximum peak amplitude. */ + max = 0; + average = 0.0; + for( i=0; i max ) + { + max = val; + } + average += val; + } + + average = average / (double)numSamples; + + printf("sample max amplitude = "PRINTF_S_FORMAT"\n", max ); + printf("sample average = %lf\n", average ); + + /* Write recorded data to a file. */ +#if WRITE_TO_FILE + { + FILE *fid; + fid = fopen("recorded.raw", "wb"); + if( fid == NULL ) + { + printf("Could not open file."); + } + else + { + fwrite( data.recordedSamples, NUM_CHANNELS * sizeof(SAMPLE), totalFrames, fid ); + fclose( fid ); + printf("Wrote data to 'recorded.raw'\n"); + } + } +#endif + + /* Playback recorded data. -------------------------------------------- */ + data.frameIndex = 0; + + outputParameters.device = Pa_GetDefaultOutputDevice(); /* default output device */ + if (outputParameters.device == paNoDevice) { + fprintf(stderr,"Error: No default output device.\n"); + goto done; + } + outputParameters.channelCount = 2; /* stereo output */ + outputParameters.sampleFormat = PA_SAMPLE_TYPE; + outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultLowOutputLatency; + outputParameters.hostApiSpecificStreamInfo = NULL; + + printf("\n=== Now playing back. ===\n"); fflush(stdout); + err = Pa_OpenStream( + &stream, + NULL, /* no input */ + &outputParameters, + SAMPLE_RATE, + FRAMES_PER_BUFFER, + paClipOff, /* we won't output out of range samples so don't bother clipping them */ + playCallback, + &data ); + if( err != paNoError ) goto done; + + if( stream ) + { + err = Pa_StartStream( stream ); + if( err != paNoError ) goto done; + + printf("Waiting for playback to finish.\n"); fflush(stdout); + + while( ( err = Pa_IsStreamActive( stream ) ) == 1 ) Pa_Sleep(100); + if( err < 0 ) goto done; + + err = Pa_CloseStream( stream ); + if( err != paNoError ) goto done; + + printf("Done.\n"); fflush(stdout); + } + +done: + Pa_Terminate(); + if( data.recordedSamples ) /* Sure it is NULL or valid. */ + free( data.recordedSamples ); + if( err != paNoError ) + { + fprintf( stderr, "An error occured while using the portaudio stream\n" ); + fprintf( stderr, "Error number: %d\n", err ); + fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); + err = 1; /* Always return 0 or 1, but no other return codes. */ + } + return err; +} + diff --git a/extern/portaudio/examples/paex_record_file.c b/extern/portaudio/examples/paex_record_file.c new file mode 100644 index 0000000..1f1211f --- /dev/null +++ b/extern/portaudio/examples/paex_record_file.c @@ -0,0 +1,458 @@ +/** @file paex_record_file.c + @ingroup examples_src + @brief Record input into a file, then playback recorded data from file (Windows only at the moment) + @author Robert Bielik +*/ +/* + * $Id: paex_record_file.c 1752 2011-09-08 03:21:55Z philburk $ + * + * This program uses the PortAudio Portable Audio Library. + * For more information see: http://www.portaudio.com + * Copyright (c) 1999-2000 Ross Bencina and Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +#include +#include +#include "portaudio.h" +#include "pa_ringbuffer.h" +#include "pa_util.h" + +#ifdef _WIN32 +#include +#include +#endif + +static ring_buffer_size_t rbs_min(ring_buffer_size_t a, ring_buffer_size_t b) +{ + return (a < b) ? a : b; +} + +/* #define SAMPLE_RATE (17932) // Test failure to open with this value. */ +#define FILE_NAME "audio_data.raw" +#define SAMPLE_RATE (44100) +#define FRAMES_PER_BUFFER (512) +#define NUM_SECONDS (10) +#define NUM_CHANNELS (2) +#define NUM_WRITES_PER_BUFFER (4) +/* #define DITHER_FLAG (paDitherOff) */ +#define DITHER_FLAG (0) /**/ + + +/* Select sample format. */ +#if 1 +#define PA_SAMPLE_TYPE paFloat32 +typedef float SAMPLE; +#define SAMPLE_SILENCE (0.0f) +#define PRINTF_S_FORMAT "%.8f" +#elif 1 +#define PA_SAMPLE_TYPE paInt16 +typedef short SAMPLE; +#define SAMPLE_SILENCE (0) +#define PRINTF_S_FORMAT "%d" +#elif 0 +#define PA_SAMPLE_TYPE paInt8 +typedef char SAMPLE; +#define SAMPLE_SILENCE (0) +#define PRINTF_S_FORMAT "%d" +#else +#define PA_SAMPLE_TYPE paUInt8 +typedef unsigned char SAMPLE; +#define SAMPLE_SILENCE (128) +#define PRINTF_S_FORMAT "%d" +#endif + +typedef struct +{ + unsigned frameIndex; + int threadSyncFlag; + SAMPLE *ringBufferData; + PaUtilRingBuffer ringBuffer; + FILE *file; + void *threadHandle; +} +paTestData; + +/* This routine is run in a separate thread to write data from the ring buffer into a file (during Recording) */ +static int threadFunctionWriteToRawFile(void* ptr) +{ + paTestData* pData = (paTestData*)ptr; + + /* Mark thread started */ + pData->threadSyncFlag = 0; + + while (1) + { + ring_buffer_size_t elementsInBuffer = PaUtil_GetRingBufferReadAvailable(&pData->ringBuffer); + if ( (elementsInBuffer >= pData->ringBuffer.bufferSize / NUM_WRITES_PER_BUFFER) || + pData->threadSyncFlag ) + { + void* ptr[2] = {0}; + ring_buffer_size_t sizes[2] = {0}; + + /* By using PaUtil_GetRingBufferReadRegions, we can read directly from the ring buffer */ + ring_buffer_size_t elementsRead = PaUtil_GetRingBufferReadRegions(&pData->ringBuffer, elementsInBuffer, ptr + 0, sizes + 0, ptr + 1, sizes + 1); + if (elementsRead > 0) + { + int i; + for (i = 0; i < 2 && ptr[i] != NULL; ++i) + { + fwrite(ptr[i], pData->ringBuffer.elementSizeBytes, sizes[i], pData->file); + } + PaUtil_AdvanceRingBufferReadIndex(&pData->ringBuffer, elementsRead); + } + + if (pData->threadSyncFlag) + { + break; + } + } + + /* Sleep a little while... */ + Pa_Sleep(20); + } + + pData->threadSyncFlag = 0; + + return 0; +} + +/* This routine is run in a separate thread to read data from file into the ring buffer (during Playback). When the file + has reached EOF, a flag is set so that the play PA callback can return paComplete */ +static int threadFunctionReadFromRawFile(void* ptr) +{ + paTestData* pData = (paTestData*)ptr; + + while (1) + { + ring_buffer_size_t elementsInBuffer = PaUtil_GetRingBufferWriteAvailable(&pData->ringBuffer); + + if (elementsInBuffer >= pData->ringBuffer.bufferSize / NUM_WRITES_PER_BUFFER) + { + void* ptr[2] = {0}; + ring_buffer_size_t sizes[2] = {0}; + + /* By using PaUtil_GetRingBufferWriteRegions, we can write directly into the ring buffer */ + PaUtil_GetRingBufferWriteRegions(&pData->ringBuffer, elementsInBuffer, ptr + 0, sizes + 0, ptr + 1, sizes + 1); + + if (!feof(pData->file)) + { + ring_buffer_size_t itemsReadFromFile = 0; + int i; + for (i = 0; i < 2 && ptr[i] != NULL; ++i) + { + itemsReadFromFile += (ring_buffer_size_t)fread(ptr[i], pData->ringBuffer.elementSizeBytes, sizes[i], pData->file); + } + PaUtil_AdvanceRingBufferWriteIndex(&pData->ringBuffer, itemsReadFromFile); + + /* Mark thread started here, that way we "prime" the ring buffer before playback */ + pData->threadSyncFlag = 0; + } + else + { + /* No more data to read */ + pData->threadSyncFlag = 1; + break; + } + } + + /* Sleep a little while... */ + Pa_Sleep(20); + } + + return 0; +} + +typedef int (*ThreadFunctionType)(void*); + +/* Start up a new thread in the given function, at the moment only Windows, but should be very easy to extend + to posix type OSs (Linux/Mac) */ +static PaError startThread( paTestData* pData, ThreadFunctionType fn ) +{ +#ifdef _WIN32 + typedef unsigned (__stdcall* WinThreadFunctionType)(void*); + pData->threadHandle = (void*)_beginthreadex(NULL, 0, (WinThreadFunctionType)fn, pData, CREATE_SUSPENDED, NULL); + if (pData->threadHandle == NULL) return paUnanticipatedHostError; + + /* Set file thread to a little higher prio than normal */ + SetThreadPriority(pData->threadHandle, THREAD_PRIORITY_ABOVE_NORMAL); + + /* Start it up */ + pData->threadSyncFlag = 1; + ResumeThread(pData->threadHandle); + +#endif + + /* Wait for thread to startup */ + while (pData->threadSyncFlag) { + Pa_Sleep(10); + } + + return paNoError; +} + +static int stopThread( paTestData* pData ) +{ + pData->threadSyncFlag = 1; + /* Wait for thread to stop */ + while (pData->threadSyncFlag) { + Pa_Sleep(10); + } +#ifdef _WIN32 + CloseHandle(pData->threadHandle); + pData->threadHandle = 0; +#endif + + return paNoError; +} + + +/* This routine will be called by the PortAudio engine when audio is needed. +** It may be called at interrupt level on some machines so don't do anything +** that could mess up the system like calling malloc() or free(). +*/ +static int recordCallback( const void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + const PaStreamCallbackTimeInfo* timeInfo, + PaStreamCallbackFlags statusFlags, + void *userData ) +{ + paTestData *data = (paTestData*)userData; + ring_buffer_size_t elementsWriteable = PaUtil_GetRingBufferWriteAvailable(&data->ringBuffer); + ring_buffer_size_t elementsToWrite = rbs_min(elementsWriteable, (ring_buffer_size_t)(framesPerBuffer * NUM_CHANNELS)); + const SAMPLE *rptr = (const SAMPLE*)inputBuffer; + + (void) outputBuffer; /* Prevent unused variable warnings. */ + (void) timeInfo; + (void) statusFlags; + (void) userData; + + data->frameIndex += PaUtil_WriteRingBuffer(&data->ringBuffer, rptr, elementsToWrite); + + return paContinue; +} + +/* This routine will be called by the PortAudio engine when audio is needed. +** It may be called at interrupt level on some machines so don't do anything +** that could mess up the system like calling malloc() or free(). +*/ +static int playCallback( const void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + const PaStreamCallbackTimeInfo* timeInfo, + PaStreamCallbackFlags statusFlags, + void *userData ) +{ + paTestData *data = (paTestData*)userData; + ring_buffer_size_t elementsToPlay = PaUtil_GetRingBufferReadAvailable(&data->ringBuffer); + ring_buffer_size_t elementsToRead = rbs_min(elementsToPlay, (ring_buffer_size_t)(framesPerBuffer * NUM_CHANNELS)); + SAMPLE* wptr = (SAMPLE*)outputBuffer; + + (void) inputBuffer; /* Prevent unused variable warnings. */ + (void) timeInfo; + (void) statusFlags; + (void) userData; + + data->frameIndex += PaUtil_ReadRingBuffer(&data->ringBuffer, wptr, elementsToRead); + + return data->threadSyncFlag ? paComplete : paContinue; +} + +static unsigned NextPowerOf2(unsigned val) +{ + val--; + val = (val >> 1) | val; + val = (val >> 2) | val; + val = (val >> 4) | val; + val = (val >> 8) | val; + val = (val >> 16) | val; + return ++val; +} + +/*******************************************************************/ +int main(void); +int main(void) +{ + PaStreamParameters inputParameters, + outputParameters; + PaStream* stream; + PaError err = paNoError; + paTestData data = {0}; + unsigned delayCntr; + unsigned numSamples; + unsigned numBytes; + + printf("patest_record.c\n"); fflush(stdout); + + /* We set the ring buffer size to about 500 ms */ + numSamples = NextPowerOf2((unsigned)(SAMPLE_RATE * 0.5 * NUM_CHANNELS)); + numBytes = numSamples * sizeof(SAMPLE); + data.ringBufferData = (SAMPLE *) PaUtil_AllocateMemory( numBytes ); + if( data.ringBufferData == NULL ) + { + printf("Could not allocate ring buffer data.\n"); + goto done; + } + + if (PaUtil_InitializeRingBuffer(&data.ringBuffer, sizeof(SAMPLE), numSamples, data.ringBufferData) < 0) + { + printf("Failed to initialize ring buffer. Size is not power of 2 ??\n"); + goto done; + } + + err = Pa_Initialize(); + if( err != paNoError ) goto done; + + inputParameters.device = Pa_GetDefaultInputDevice(); /* default input device */ + if (inputParameters.device == paNoDevice) { + fprintf(stderr,"Error: No default input device.\n"); + goto done; + } + inputParameters.channelCount = 2; /* stereo input */ + inputParameters.sampleFormat = PA_SAMPLE_TYPE; + inputParameters.suggestedLatency = Pa_GetDeviceInfo( inputParameters.device )->defaultLowInputLatency; + inputParameters.hostApiSpecificStreamInfo = NULL; + + /* Record some audio. -------------------------------------------- */ + err = Pa_OpenStream( + &stream, + &inputParameters, + NULL, /* &outputParameters, */ + SAMPLE_RATE, + FRAMES_PER_BUFFER, + paClipOff, /* we won't output out of range samples so don't bother clipping them */ + recordCallback, + &data ); + if( err != paNoError ) goto done; + + /* Open the raw audio 'cache' file... */ + data.file = fopen(FILE_NAME, "wb"); + if (data.file == 0) goto done; + + /* Start the file writing thread */ + err = startThread(&data, threadFunctionWriteToRawFile); + if( err != paNoError ) goto done; + + err = Pa_StartStream( stream ); + if( err != paNoError ) goto done; + printf("\n=== Now recording to '" FILE_NAME "' for %d seconds!! Please speak into the microphone. ===\n", NUM_SECONDS); fflush(stdout); + + /* Note that the RECORDING part is limited with TIME, not size of the file and/or buffer, so you can + increase NUM_SECONDS until you run out of disk */ + delayCntr = 0; + while( delayCntr++ < NUM_SECONDS ) + { + printf("index = %d\n", data.frameIndex ); fflush(stdout); + Pa_Sleep(1000); + } + if( err < 0 ) goto done; + + err = Pa_CloseStream( stream ); + if( err != paNoError ) goto done; + + /* Stop the thread */ + err = stopThread(&data); + if( err != paNoError ) goto done; + + /* Close file */ + fclose(data.file); + data.file = 0; + + /* Playback recorded data. -------------------------------------------- */ + data.frameIndex = 0; + + outputParameters.device = Pa_GetDefaultOutputDevice(); /* default output device */ + if (outputParameters.device == paNoDevice) { + fprintf(stderr,"Error: No default output device.\n"); + goto done; + } + outputParameters.channelCount = 2; /* stereo output */ + outputParameters.sampleFormat = PA_SAMPLE_TYPE; + outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultLowOutputLatency; + outputParameters.hostApiSpecificStreamInfo = NULL; + + printf("\n=== Now playing back from file '" FILE_NAME "' until end-of-file is reached ===\n"); fflush(stdout); + err = Pa_OpenStream( + &stream, + NULL, /* no input */ + &outputParameters, + SAMPLE_RATE, + FRAMES_PER_BUFFER, + paClipOff, /* we won't output out of range samples so don't bother clipping them */ + playCallback, + &data ); + if( err != paNoError ) goto done; + + if( stream ) + { + /* Open file again for reading */ + data.file = fopen(FILE_NAME, "rb"); + if (data.file != 0) + { + /* Start the file reading thread */ + err = startThread(&data, threadFunctionReadFromRawFile); + if( err != paNoError ) goto done; + + err = Pa_StartStream( stream ); + if( err != paNoError ) goto done; + + printf("Waiting for playback to finish.\n"); fflush(stdout); + + /* The playback will end when EOF is reached */ + while( ( err = Pa_IsStreamActive( stream ) ) == 1 ) { + printf("index = %d\n", data.frameIndex ); fflush(stdout); + Pa_Sleep(1000); + } + if( err < 0 ) goto done; + } + + err = Pa_CloseStream( stream ); + if( err != paNoError ) goto done; + + fclose(data.file); + + printf("Done.\n"); fflush(stdout); + } + +done: + Pa_Terminate(); + if( data.ringBufferData ) /* Sure it is NULL or valid. */ + PaUtil_FreeMemory( data.ringBufferData ); + if( err != paNoError ) + { + fprintf( stderr, "An error occured while using the portaudio stream\n" ); + fprintf( stderr, "Error number: %d\n", err ); + fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); + err = 1; /* Always return 0 or 1, but no other return codes. */ + } + return err; +} + diff --git a/extern/portaudio/examples/paex_saw.c b/extern/portaudio/examples/paex_saw.c new file mode 100644 index 0000000..235f247 --- /dev/null +++ b/extern/portaudio/examples/paex_saw.c @@ -0,0 +1,133 @@ +/** @file paex_saw.c + @ingroup examples_src + @brief Play a simple (aliasing) sawtooth wave. + @author Phil Burk http://www.softsynth.com +*/ +/* + * $Id$ + * + * This program uses the PortAudio Portable Audio Library. + * For more information see: http://www.portaudio.com + * Copyright (c) 1999-2000 Ross Bencina and Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +#include +#include +#include "portaudio.h" +#define NUM_SECONDS (4) +#define SAMPLE_RATE (44100) + +typedef struct +{ + float left_phase; + float right_phase; +} +paTestData; + +/* This routine will be called by the PortAudio engine when audio is needed. +** It may called at interrupt level on some machines so don't do anything +** that could mess up the system like calling malloc() or free(). +*/ +static int patestCallback( const void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + const PaStreamCallbackTimeInfo* timeInfo, + PaStreamCallbackFlags statusFlags, + void *userData ) +{ + /* Cast data passed through stream to our structure. */ + paTestData *data = (paTestData*)userData; + float *out = (float*)outputBuffer; + unsigned int i; + (void) inputBuffer; /* Prevent unused variable warning. */ + + for( i=0; ileft_phase; /* left */ + *out++ = data->right_phase; /* right */ + /* Generate simple sawtooth phaser that ranges between -1.0 and 1.0. */ + data->left_phase += 0.01f; + /* When signal reaches top, drop back down. */ + if( data->left_phase >= 1.0f ) data->left_phase -= 2.0f; + /* higher pitch so we can distinguish left and right. */ + data->right_phase += 0.03f; + if( data->right_phase >= 1.0f ) data->right_phase -= 2.0f; + } + return 0; +} + +/*******************************************************************/ +static paTestData data; +int main(void); +int main(void) +{ + PaStream *stream; + PaError err; + + printf("PortAudio Test: output sawtooth wave.\n"); + /* Initialize our data for use by callback. */ + data.left_phase = data.right_phase = 0.0; + /* Initialize library before making any other calls. */ + err = Pa_Initialize(); + if( err != paNoError ) goto error; + + /* Open an audio I/O stream. */ + err = Pa_OpenDefaultStream( &stream, + 0, /* no input channels */ + 2, /* stereo output */ + paFloat32, /* 32 bit floating point output */ + SAMPLE_RATE, + 256, /* frames per buffer */ + patestCallback, + &data ); + if( err != paNoError ) goto error; + + err = Pa_StartStream( stream ); + if( err != paNoError ) goto error; + + /* Sleep for several seconds. */ + Pa_Sleep(NUM_SECONDS*1000); + + err = Pa_StopStream( stream ); + if( err != paNoError ) goto error; + err = Pa_CloseStream( stream ); + if( err != paNoError ) goto error; + Pa_Terminate(); + printf("Test finished.\n"); + return err; +error: + Pa_Terminate(); + fprintf( stderr, "An error occured while using the portaudio stream\n" ); + fprintf( stderr, "Error number: %d\n", err ); + fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); + return err; +} diff --git a/extern/portaudio/examples/paex_sine.c b/extern/portaudio/examples/paex_sine.c new file mode 100644 index 0000000..bda290b --- /dev/null +++ b/extern/portaudio/examples/paex_sine.c @@ -0,0 +1,175 @@ +/** @file paex_sine.c + @ingroup examples_src + @brief Play a sine wave for several seconds. + @author Ross Bencina + @author Phil Burk +*/ +/* + * $Id$ + * + * This program uses the PortAudio Portable Audio Library. + * For more information see: http://www.portaudio.com/ + * Copyright (c) 1999-2000 Ross Bencina and Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ +#include +#include +#include "portaudio.h" + +#define NUM_SECONDS (5) +#define SAMPLE_RATE (44100) +#define FRAMES_PER_BUFFER (64) + +#ifndef M_PI +#define M_PI (3.14159265) +#endif + +#define TABLE_SIZE (200) +typedef struct +{ + float sine[TABLE_SIZE]; + int left_phase; + int right_phase; + char message[20]; +} +paTestData; + +/* This routine will be called by the PortAudio engine when audio is needed. +** It may called at interrupt level on some machines so don't do anything +** that could mess up the system like calling malloc() or free(). +*/ +static int patestCallback( const void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + const PaStreamCallbackTimeInfo* timeInfo, + PaStreamCallbackFlags statusFlags, + void *userData ) +{ + paTestData *data = (paTestData*)userData; + float *out = (float*)outputBuffer; + unsigned long i; + + (void) timeInfo; /* Prevent unused variable warnings. */ + (void) statusFlags; + (void) inputBuffer; + + for( i=0; isine[data->left_phase]; /* left */ + *out++ = data->sine[data->right_phase]; /* right */ + data->left_phase += 1; + if( data->left_phase >= TABLE_SIZE ) data->left_phase -= TABLE_SIZE; + data->right_phase += 3; /* higher pitch so we can distinguish left and right. */ + if( data->right_phase >= TABLE_SIZE ) data->right_phase -= TABLE_SIZE; + } + + return paContinue; +} + +/* + * This routine is called by portaudio when playback is done. + */ +static void StreamFinished( void* userData ) +{ + paTestData *data = (paTestData *) userData; + printf( "Stream Completed: %s\n", data->message ); +} + +/*******************************************************************/ +int main(void); +int main(void) +{ + PaStreamParameters outputParameters; + PaStream *stream; + PaError err; + paTestData data; + int i; + + printf("PortAudio Test: output sine wave. SR = %d, BufSize = %d\n", SAMPLE_RATE, FRAMES_PER_BUFFER); + + /* initialise sinusoidal wavetable */ + for( i=0; idefaultLowOutputLatency; + outputParameters.hostApiSpecificStreamInfo = NULL; + + err = Pa_OpenStream( + &stream, + NULL, /* no input */ + &outputParameters, + SAMPLE_RATE, + FRAMES_PER_BUFFER, + paClipOff, /* we won't output out of range samples so don't bother clipping them */ + patestCallback, + &data ); + if( err != paNoError ) goto error; + + sprintf( data.message, "No Message" ); + err = Pa_SetStreamFinishedCallback( stream, &StreamFinished ); + if( err != paNoError ) goto error; + + err = Pa_StartStream( stream ); + if( err != paNoError ) goto error; + + printf("Play for %d seconds.\n", NUM_SECONDS ); + Pa_Sleep( NUM_SECONDS * 1000 ); + + err = Pa_StopStream( stream ); + if( err != paNoError ) goto error; + + err = Pa_CloseStream( stream ); + if( err != paNoError ) goto error; + + Pa_Terminate(); + printf("Test finished.\n"); + + return err; +error: + Pa_Terminate(); + fprintf( stderr, "An error occured while using the portaudio stream\n" ); + fprintf( stderr, "Error number: %d\n", err ); + fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); + return err; +} diff --git a/extern/portaudio/examples/paex_sine_c++.cpp b/extern/portaudio/examples/paex_sine_c++.cpp new file mode 100644 index 0000000..2859a57 --- /dev/null +++ b/extern/portaudio/examples/paex_sine_c++.cpp @@ -0,0 +1,275 @@ +/** @file paex_sine.c + @ingroup examples_src + @brief Play a sine wave for several seconds. + @author Ross Bencina + @author Phil Burk +*/ +/* + * $Id: paex_sine.c 1752 2011-09-08 03:21:55Z philburk $ + * + * This program uses the PortAudio Portable Audio Library. + * For more information see: http://www.portaudio.com/ + * Copyright (c) 1999-2000 Ross Bencina and Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ +#include +#include +#include "portaudio.h" + +#define NUM_SECONDS (5) +#define SAMPLE_RATE (44100) +#define FRAMES_PER_BUFFER (64) + +#ifndef M_PI +#define M_PI (3.14159265) +#endif + +#define TABLE_SIZE (200) + +class Sine +{ +public: + Sine() : stream(0), left_phase(0), right_phase(0) + { + /* initialise sinusoidal wavetable */ + for( int i=0; iname); + } + + outputParameters.channelCount = 2; /* stereo output */ + outputParameters.sampleFormat = paFloat32; /* 32 bit floating point output */ + outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultLowOutputLatency; + outputParameters.hostApiSpecificStreamInfo = NULL; + + PaError err = Pa_OpenStream( + &stream, + NULL, /* no input */ + &outputParameters, + SAMPLE_RATE, + paFramesPerBufferUnspecified, + paClipOff, /* we won't output out of range samples so don't bother clipping them */ + &Sine::paCallback, + this /* Using 'this' for userData so we can cast to Sine* in paCallback method */ + ); + + if (err != paNoError) + { + /* Failed to open stream to device !!! */ + return false; + } + + err = Pa_SetStreamFinishedCallback( stream, &Sine::paStreamFinished ); + + if (err != paNoError) + { + Pa_CloseStream( stream ); + stream = 0; + + return false; + } + + return true; + } + + bool close() + { + if (stream == 0) + return false; + + PaError err = Pa_CloseStream( stream ); + stream = 0; + + return (err == paNoError); + } + + + bool start() + { + if (stream == 0) + return false; + + PaError err = Pa_StartStream( stream ); + + return (err == paNoError); + } + + bool stop() + { + if (stream == 0) + return false; + + PaError err = Pa_StopStream( stream ); + + return (err == paNoError); + } + +private: + /* The instance callback, where we have access to every method/variable in object of class Sine */ + int paCallbackMethod(const void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + const PaStreamCallbackTimeInfo* timeInfo, + PaStreamCallbackFlags statusFlags) + { + float *out = (float*)outputBuffer; + unsigned long i; + + (void) timeInfo; /* Prevent unused variable warnings. */ + (void) statusFlags; + (void) inputBuffer; + + for( i=0; i= TABLE_SIZE ) left_phase -= TABLE_SIZE; + right_phase += 3; /* higher pitch so we can distinguish left and right. */ + if( right_phase >= TABLE_SIZE ) right_phase -= TABLE_SIZE; + } + + return paContinue; + + } + + /* This routine will be called by the PortAudio engine when audio is needed. + ** It may called at interrupt level on some machines so don't do anything + ** that could mess up the system like calling malloc() or free(). + */ + static int paCallback( const void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + const PaStreamCallbackTimeInfo* timeInfo, + PaStreamCallbackFlags statusFlags, + void *userData ) + { + /* Here we cast userData to Sine* type so we can call the instance method paCallbackMethod, we can do that since + we called Pa_OpenStream with 'this' for userData */ + return ((Sine*)userData)->paCallbackMethod(inputBuffer, outputBuffer, + framesPerBuffer, + timeInfo, + statusFlags); + } + + + void paStreamFinishedMethod() + { + printf( "Stream Completed: %s\n", message ); + } + + /* + * This routine is called by portaudio when playback is done. + */ + static void paStreamFinished(void* userData) + { + return ((Sine*)userData)->paStreamFinishedMethod(); + } + + PaStream *stream; + float sine[TABLE_SIZE]; + int left_phase; + int right_phase; + char message[20]; +}; + +class ScopedPaHandler +{ +public: + ScopedPaHandler() + : _result(Pa_Initialize()) + { + } + ~ScopedPaHandler() + { + if (_result == paNoError) + { + Pa_Terminate(); + } + } + + PaError result() const { return _result; } + +private: + PaError _result; +}; + + +/*******************************************************************/ +int main(void); +int main(void) +{ + Sine sine; + + printf("PortAudio Test: output sine wave. SR = %d, BufSize = %d\n", SAMPLE_RATE, FRAMES_PER_BUFFER); + + ScopedPaHandler paInit; + if( paInit.result() != paNoError ) goto error; + + if (sine.open(Pa_GetDefaultOutputDevice())) + { + if (sine.start()) + { + printf("Play for %d seconds.\n", NUM_SECONDS ); + Pa_Sleep( NUM_SECONDS * 1000 ); + + sine.stop(); + } + + sine.close(); + } + + printf("Test finished.\n"); + return paNoError; + +error: + fprintf( stderr, "An error occured while using the portaudio stream\n" ); + fprintf( stderr, "Error number: %d\n", paInit.result() ); + fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( paInit.result() ) ); + return 1; +} diff --git a/extern/portaudio/examples/paex_wmme_ac3.c b/extern/portaudio/examples/paex_wmme_ac3.c new file mode 100644 index 0000000..e59c571 --- /dev/null +++ b/extern/portaudio/examples/paex_wmme_ac3.c @@ -0,0 +1,221 @@ +/** @file paex_wmme_ac3.c + @ingroup examples_src + @brief Use WMME-specific interface to send raw AC3 data to a S/PDIF output. + @author Ross Bencina +*/ +/* + * $Id: $ + * Portable Audio I/O Library + * Windows MME ac3 sound output test + * + * Copyright (c) 2009 Ross Bencina + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +#include +#include + +#include /* required when using pa_win_wmme.h */ +#include /* required when using pa_win_wmme.h */ + +#include "portaudio.h" +#include "pa_win_wmme.h" + +#define NUM_SECONDS (20) +#define SAMPLE_RATE (48000) +#define FRAMES_PER_BUFFER (64) + +#ifndef M_PI +#define M_PI (3.14159265) +#endif + +#define TABLE_SIZE (100) + +#define CHANNEL_COUNT (2) + + + +typedef struct +{ + short *buffer; + int bufferSampleCount; + int playbackIndex; +} +paTestData; + +/* This routine will be called by the PortAudio engine when audio is needed. +** It may called at interrupt level on some machines so don't do anything +** that could mess up the system like calling malloc() or free(). +*/ +static int patestCallback( const void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + const PaStreamCallbackTimeInfo* timeInfo, + PaStreamCallbackFlags statusFlags, + void *userData ) +{ + paTestData *data = (paTestData*)userData; + short *out = (short*)outputBuffer; + unsigned long i,j; + + (void) timeInfo; /* Prevent unused variable warnings. */ + (void) statusFlags; + (void) inputBuffer; + + /* stream out contents of data->buffer looping at end */ + + for( i=0; ibuffer[ data->playbackIndex++ ]; + + if( data->playbackIndex >= data->bufferSampleCount ) + data->playbackIndex = 0; /* loop at end of buffer */ + } + } + + return paContinue; +} + +/*******************************************************************/ +int main(int argc, char* argv[]) +{ + PaStreamParameters outputParameters; + PaWinMmeStreamInfo wmmeStreamInfo; + PaStream *stream; + PaError err; + paTestData data; + int deviceIndex; + FILE *fp; + const char *fileName = "c:\\test_48k.ac3.spdif"; + data.buffer = NULL; + + printf("usage: patest_wmme_ac3 fileName [paDeviceIndex]\n"); + printf("**IMPORTANT*** The provided file must include the spdif preamble at the start of every AC-3 frame. Using a normal ac3 file won't work.\n"); + printf("PortAudio Test: output a raw spdif ac3 stream. SR = %d, BufSize = %d, Chans = %d\n", + SAMPLE_RATE, FRAMES_PER_BUFFER, CHANNEL_COUNT); + + + if( argc >= 2 ) + fileName = argv[1]; + + printf( "reading spdif ac3 raw stream file %s\n", fileName ); + + fp = fopen( fileName, "rb" ); + if( !fp ){ + fprintf( stderr, "error opening spdif ac3 file.\n" ); + return -1; + } + /* get file size */ + fseek( fp, 0, SEEK_END ); + data.bufferSampleCount = ftell( fp ) / sizeof(short); + fseek( fp, 0, SEEK_SET ); + + /* allocate buffer, read the whole file into memory */ + data.buffer = (short*)malloc( data.bufferSampleCount * sizeof(short) ); + if( !data.buffer ){ + fprintf( stderr, "error allocating buffer.\n" ); + return -1; + } + + fread( data.buffer, sizeof(short), data.bufferSampleCount, fp ); + fclose( fp ); + + data.playbackIndex = 0; + + err = Pa_Initialize(); + if( err != paNoError ) goto error; + + deviceIndex = Pa_GetHostApiInfo( Pa_HostApiTypeIdToHostApiIndex( paMME ) )->defaultOutputDevice; + if( argc >= 3 ){ + sscanf( argv[1], "%d", &deviceIndex ); + } + + printf( "using device id %d (%s)\n", deviceIndex, Pa_GetDeviceInfo(deviceIndex)->name ); + + + outputParameters.device = deviceIndex; + outputParameters.channelCount = CHANNEL_COUNT; + outputParameters.sampleFormat = paInt16; /* IMPORTANT must use paInt16 for WMME AC3 */ + outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultLowOutputLatency; + outputParameters.hostApiSpecificStreamInfo = NULL; + + wmmeStreamInfo.size = sizeof(PaWinMmeStreamInfo); + wmmeStreamInfo.hostApiType = paMME; + wmmeStreamInfo.version = 1; + wmmeStreamInfo.flags = paWinMmeWaveFormatDolbyAc3Spdif; + outputParameters.hostApiSpecificStreamInfo = &wmmeStreamInfo; + + + if( Pa_IsFormatSupported( 0, &outputParameters, SAMPLE_RATE ) == paFormatIsSupported ){ + printf( "Pa_IsFormatSupported reports device will support %d channels.\n", CHANNEL_COUNT ); + }else{ + printf( "Pa_IsFormatSupported reports device will not support %d channels.\n", CHANNEL_COUNT ); + } + + err = Pa_OpenStream( + &stream, + NULL, /* no input */ + &outputParameters, + SAMPLE_RATE, + FRAMES_PER_BUFFER, + 0, + patestCallback, + &data ); + if( err != paNoError ) goto error; + + err = Pa_StartStream( stream ); + if( err != paNoError ) goto error; + + printf("Play for %d seconds.\n", NUM_SECONDS ); + Pa_Sleep( NUM_SECONDS * 1000 ); + + err = Pa_StopStream( stream ); + if( err != paNoError ) goto error; + + err = Pa_CloseStream( stream ); + if( err != paNoError ) goto error; + + Pa_Terminate(); + free( data.buffer ); + printf("Test finished.\n"); + + return err; +error: + Pa_Terminate(); + free( data.buffer ); + + fprintf( stderr, "An error occured while using the portaudio stream\n" ); + fprintf( stderr, "Error number: %d\n", err ); + fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); + return err; +} + diff --git a/extern/portaudio/examples/paex_wmme_surround.c b/extern/portaudio/examples/paex_wmme_surround.c new file mode 100644 index 0000000..ddab73d --- /dev/null +++ b/extern/portaudio/examples/paex_wmme_surround.c @@ -0,0 +1,211 @@ +/** @file paex_wmme_surround.c + @ingroup examples_src + @brief Use WMME-specific channelMask to request 5.1 surround sound output. + @author Ross Bencina +*/ +/* + * $Id: $ + * Portable Audio I/O Library + * Windows MME surround sound output test + * + * Copyright (c) 2007 Ross Bencina + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +#include +#include + +#include /* required when using pa_win_wmme.h */ +#include /* required when using pa_win_wmme.h */ + +#include "portaudio.h" +#include "pa_win_wmme.h" + +#define NUM_SECONDS (12) +#define SAMPLE_RATE (44100) +#define FRAMES_PER_BUFFER (64) + +#ifndef M_PI +#define M_PI (3.14159265) +#endif + +#define TABLE_SIZE (100) + +#define CHANNEL_COUNT (6) + + + +typedef struct +{ + float sine[TABLE_SIZE]; + int phase; + int currentChannel; + int cycleCount; +} +paTestData; + +/* This routine will be called by the PortAudio engine when audio is needed. +** It may called at interrupt level on some machines so don't do anything +** that could mess up the system like calling malloc() or free(). +*/ +static int patestCallback( const void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + const PaStreamCallbackTimeInfo* timeInfo, + PaStreamCallbackFlags statusFlags, + void *userData ) +{ + paTestData *data = (paTestData*)userData; + float *out = (float*)outputBuffer; + unsigned long i,j; + + (void) timeInfo; /* Prevent unused variable warnings. */ + (void) statusFlags; + (void) inputBuffer; + + for( i=0; icurrentChannel && data->cycleCount < 4410 ){ + *out++ = data->sine[data->phase]; + data->phase += 1 + j; // play each channel at a different pitch so they can be distinguished + if( data->phase >= TABLE_SIZE ){ + data->phase -= TABLE_SIZE; + } + }else{ + *out++ = 0; + } + } + + data->cycleCount++; + if( data->cycleCount > 44100 ){ + data->cycleCount = 0; + + ++data->currentChannel; + if( data->currentChannel >= CHANNEL_COUNT ) + data->currentChannel -= CHANNEL_COUNT; + } + } + + return paContinue; +} + +/*******************************************************************/ +int main(int argc, char* argv[]) +{ + PaStreamParameters outputParameters; + PaWinMmeStreamInfo wmmeStreamInfo; + PaStream *stream; + PaError err; + paTestData data; + int i; + int deviceIndex; + + printf("PortAudio Test: output a sine blip on each channel. SR = %d, BufSize = %d, Chans = %d\n", SAMPLE_RATE, FRAMES_PER_BUFFER, CHANNEL_COUNT); + + err = Pa_Initialize(); + if( err != paNoError ) goto error; + + deviceIndex = Pa_GetHostApiInfo( Pa_HostApiTypeIdToHostApiIndex( paMME ) )->defaultOutputDevice; + if( argc == 2 ){ + sscanf( argv[1], "%d", &deviceIndex ); + } + + printf( "using device id %d (%s)\n", deviceIndex, Pa_GetDeviceInfo(deviceIndex)->name ); + + /* initialise sinusoidal wavetable */ + for( i=0; idefaultLowOutputLatency; + outputParameters.hostApiSpecificStreamInfo = NULL; + + /* it's not strictly necessary to provide a channelMask for surround sound + output. But if you want to be sure which channel mask PortAudio will use + then you should supply one */ + wmmeStreamInfo.size = sizeof(PaWinMmeStreamInfo); + wmmeStreamInfo.hostApiType = paMME; + wmmeStreamInfo.version = 1; + wmmeStreamInfo.flags = paWinMmeUseChannelMask; + wmmeStreamInfo.channelMask = PAWIN_SPEAKER_5POINT1; /* request 5.1 output format */ + outputParameters.hostApiSpecificStreamInfo = &wmmeStreamInfo; + + + if( Pa_IsFormatSupported( 0, &outputParameters, SAMPLE_RATE ) == paFormatIsSupported ){ + printf( "Pa_IsFormatSupported reports device will support %d channels.\n", CHANNEL_COUNT ); + }else{ + printf( "Pa_IsFormatSupported reports device will not support %d channels.\n", CHANNEL_COUNT ); + } + + err = Pa_OpenStream( + &stream, + NULL, /* no input */ + &outputParameters, + SAMPLE_RATE, + FRAMES_PER_BUFFER, + paClipOff, /* we won't output out of range samples so don't bother clipping them */ + patestCallback, + &data ); + if( err != paNoError ) goto error; + + err = Pa_StartStream( stream ); + if( err != paNoError ) goto error; + + printf("Play for %d seconds.\n", NUM_SECONDS ); + Pa_Sleep( NUM_SECONDS * 1000 ); + + err = Pa_StopStream( stream ); + if( err != paNoError ) goto error; + + err = Pa_CloseStream( stream ); + if( err != paNoError ) goto error; + + Pa_Terminate(); + printf("Test finished.\n"); + + return err; +error: + Pa_Terminate(); + fprintf( stderr, "An error occured while using the portaudio stream\n" ); + fprintf( stderr, "Error number: %d\n", err ); + fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); + return err; +} + diff --git a/extern/portaudio/examples/paex_write_sine.c b/extern/portaudio/examples/paex_write_sine.c new file mode 100644 index 0000000..f5ead3f --- /dev/null +++ b/extern/portaudio/examples/paex_write_sine.c @@ -0,0 +1,166 @@ +/** @file paex_write_sine.c + @ingroup examples_src + @brief Play a sine wave for several seconds using the blocking API (Pa_WriteStream()) + @author Ross Bencina + @author Phil Burk +*/ +/* + * $Id$ + * + * This program uses the PortAudio Portable Audio Library. + * For more information see: http://www.portaudio.com/ + * Copyright (c) 1999-2000 Ross Bencina and Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +#include +#include +#include "portaudio.h" + +#define NUM_SECONDS (5) +#define SAMPLE_RATE (44100) +#define FRAMES_PER_BUFFER (1024) + +#ifndef M_PI +#define M_PI (3.14159265) +#endif + +#define TABLE_SIZE (200) + + +int main(void); +int main(void) +{ + PaStreamParameters outputParameters; + PaStream *stream; + PaError err; + float buffer[FRAMES_PER_BUFFER][2]; /* stereo output buffer */ + float sine[TABLE_SIZE]; /* sine wavetable */ + int left_phase = 0; + int right_phase = 0; + int left_inc = 1; + int right_inc = 3; /* higher pitch so we can distinguish left and right. */ + int i, j, k; + int bufferCount; + + printf("PortAudio Test: output sine wave. SR = %d, BufSize = %d\n", SAMPLE_RATE, FRAMES_PER_BUFFER); + + /* initialise sinusoidal wavetable */ + for( i=0; idefaultLowOutputLatency; + outputParameters.hostApiSpecificStreamInfo = NULL; + + err = Pa_OpenStream( + &stream, + NULL, /* no input */ + &outputParameters, + SAMPLE_RATE, + FRAMES_PER_BUFFER, + paClipOff, /* we won't output out of range samples so don't bother clipping them */ + NULL, /* no callback, use blocking API */ + NULL ); /* no callback, so no callback userData */ + if( err != paNoError ) goto error; + + + printf( "Play 3 times, higher each time.\n" ); + + for( k=0; k < 3; ++k ) + { + err = Pa_StartStream( stream ); + if( err != paNoError ) goto error; + + printf("Play for %d seconds.\n", NUM_SECONDS ); + + bufferCount = ((NUM_SECONDS * SAMPLE_RATE) / FRAMES_PER_BUFFER); + + for( i=0; i < bufferCount; i++ ) + { + for( j=0; j < FRAMES_PER_BUFFER; j++ ) + { + buffer[j][0] = sine[left_phase]; /* left */ + buffer[j][1] = sine[right_phase]; /* right */ + left_phase += left_inc; + if( left_phase >= TABLE_SIZE ) left_phase -= TABLE_SIZE; + right_phase += right_inc; + if( right_phase >= TABLE_SIZE ) right_phase -= TABLE_SIZE; + } + + err = Pa_WriteStream( stream, buffer, FRAMES_PER_BUFFER ); + if( err != paNoError ) goto error; + } + + err = Pa_StopStream( stream ); + if( err != paNoError ) goto error; + + ++left_inc; + ++right_inc; + + Pa_Sleep( 1000 ); + } + + err = Pa_CloseStream( stream ); + if( err != paNoError ) goto error; + + Pa_Terminate(); + printf("Test finished.\n"); + + return err; + +error: + fprintf( stderr, "An error occured while using the portaudio stream\n" ); + fprintf( stderr, "Error number: %d\n", err ); + fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); + // Print more information about the error. + if( err == paUnanticipatedHostError ) + { + const PaHostErrorInfo *hostErrorInfo = Pa_GetLastHostErrorInfo(); + fprintf( stderr, "Host API error = #%ld, hostApiType = %d\n", hostErrorInfo->errorCode, hostErrorInfo->hostApiType ); + fprintf( stderr, "Host API error = %s\n", hostErrorInfo->errorText ); + } + Pa_Terminate(); + return err; +} diff --git a/extern/portaudio/examples/paex_write_sine_nonint.c b/extern/portaudio/examples/paex_write_sine_nonint.c new file mode 100644 index 0000000..3a038e1 --- /dev/null +++ b/extern/portaudio/examples/paex_write_sine_nonint.c @@ -0,0 +1,167 @@ +/** @file paex_write_sine_nonint.c + @ingroup examples_src + @brief Play a non-interleaved sine wave using the blocking API (Pa_WriteStream()) + @author Ross Bencina + @author Phil Burk +*/ +/* + * $Id: patest_write_sine.c 1368 2008-03-01 00:38:27Z rossb $ + * + * This program uses the PortAudio Portable Audio Library. + * For more information see: http://www.portaudio.com/ + * Copyright (c) 1999-2000 Ross Bencina and Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +#include +#include +#include "portaudio.h" + +#define NUM_SECONDS (5) +#define SAMPLE_RATE (44100) +#define FRAMES_PER_BUFFER (1024) + +#ifndef M_PI +#define M_PI (3.14159265) +#endif + +#define TABLE_SIZE (200) + + +int main(void); +int main(void) +{ + PaStreamParameters outputParameters; + PaStream *stream; + PaError err; + + float leftBuffer[FRAMES_PER_BUFFER]; + float rightBuffer[FRAMES_PER_BUFFER]; + void *buffers[2]; /* points to both non-interleaved buffers. */ + + float sine[TABLE_SIZE]; /* sine wavetable */ + int left_phase = 0; + int right_phase = 0; + int left_inc = 1; + int right_inc = 3; /* higher pitch so we can distinguish left and right. */ + int i, j, k; + int bufferCount; + + + printf("PortAudio Test: output sine wave NON-INTERLEAVED. SR = %d, BufSize = %d\n", SAMPLE_RATE, FRAMES_PER_BUFFER); + + /* initialise sinusoidal wavetable */ + for( i=0; idefaultLowOutputLatency; + outputParameters.hostApiSpecificStreamInfo = NULL; + + err = Pa_OpenStream( + &stream, + NULL, /* no input */ + &outputParameters, + SAMPLE_RATE, + FRAMES_PER_BUFFER, + paClipOff, /* we won't output out of range samples so don't bother clipping them */ + NULL, /* no callback, use blocking API */ + NULL ); /* no callback, so no callback userData */ + if( err != paNoError ) goto error; + + + printf( "Play 3 times, higher each time.\n" ); + + /* Set up array of buffer pointers for Pa_WriteStream */ + buffers[0] = leftBuffer; + buffers[1] = rightBuffer; + + for( k=0; k < 3; ++k ) + { + err = Pa_StartStream( stream ); + if( err != paNoError ) goto error; + + printf("Play for %d seconds.\n", NUM_SECONDS ); + + bufferCount = ((NUM_SECONDS * SAMPLE_RATE) / FRAMES_PER_BUFFER); + + for( i=0; i < bufferCount; i++ ) + { + for( j=0; j < FRAMES_PER_BUFFER; j++ ) + { + leftBuffer[j] = sine[left_phase]; /* left */ + rightBuffer[j] = sine[right_phase]; /* right */ + left_phase += left_inc; + if( left_phase >= TABLE_SIZE ) left_phase -= TABLE_SIZE; + right_phase += right_inc; + if( right_phase >= TABLE_SIZE ) right_phase -= TABLE_SIZE; + } + + err = Pa_WriteStream( stream, buffers, FRAMES_PER_BUFFER ); + if( err != paNoError ) goto error; + } + + err = Pa_StopStream( stream ); + if( err != paNoError ) goto error; + + ++left_inc; + ++right_inc; + + Pa_Sleep( 1000 ); + } + + err = Pa_CloseStream( stream ); + if( err != paNoError ) goto error; + + Pa_Terminate(); + printf("Test finished.\n"); + + return err; +error: + Pa_Terminate(); + fprintf( stderr, "An error occured while using the portaudio stream\n" ); + fprintf( stderr, "Error number: %d\n", err ); + fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); + return err; +} diff --git a/extern/portaudio/fixdir.bat b/extern/portaudio/fixdir.bat new file mode 100755 index 0000000..92d6c74 --- /dev/null +++ b/extern/portaudio/fixdir.bat @@ -0,0 +1,19 @@ +rem Use Astyle to fix style in 'C' files +cd %1% + +fixlines -p *.c +fixlines -p *.cpp +fixlines -p *.cc + +astyle --style=ansi -c -o --convert-tabs --indent-preprocessor *.c +astyle --style=ansi -c -o --convert-tabs --indent-preprocessor *.cpp +astyle --style=ansi -c -o --convert-tabs --indent-preprocessor *.cc +del *.orig +@rem convert line terminators to Unix style LFs +fixlines -u *.c +fixlines -u *.cpp +fixlines -u *.cc +fixlines -u *.h +del *.bak + +cd ..\ diff --git a/extern/portaudio/fixfile.bat b/extern/portaudio/fixfile.bat new file mode 100755 index 0000000..48f6fbc --- /dev/null +++ b/extern/portaudio/fixfile.bat @@ -0,0 +1,7 @@ +rem Use Astyle to fix style in a file +fixlines -p %1% +astyle --style=ansi -c -o --convert-tabs --indent-preprocessor %1% +del %1%.orig +@rem convert line terminators to Unix style LFs +fixlines -u %1% +del %1%.bak diff --git a/extern/portaudio/include/pa_asio.h b/extern/portaudio/include/pa_asio.h new file mode 100644 index 0000000..9c606a9 --- /dev/null +++ b/extern/portaudio/include/pa_asio.h @@ -0,0 +1,150 @@ +#ifndef PA_ASIO_H +#define PA_ASIO_H +/* + * $Id$ + * PortAudio Portable Real-Time Audio Library + * ASIO specific extensions + * + * Copyright (c) 1999-2000 Ross Bencina and Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + + +/** @file + @ingroup public_header + @brief ASIO-specific PortAudio API extension header file. +*/ + +#include "portaudio.h" + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + +/** Retrieve legal native buffer sizes for the specificed device, in sample frames. + + @param device The global index of the device about which the query is being made. + @param minBufferSizeFrames A pointer to the location which will receive the minimum buffer size value. + @param maxBufferSizeFrames A pointer to the location which will receive the maximum buffer size value. + @param preferredBufferSizeFrames A pointer to the location which will receive the preferred buffer size value. + @param granularity A pointer to the location which will receive the "granularity". This value determines + the step size used to compute the legal values between minBufferSizeFrames and maxBufferSizeFrames. + If granularity is -1 then available buffer size values are powers of two. + + @see ASIOGetBufferSize in the ASIO SDK. + + @note: this function used to be called PaAsio_GetAvailableLatencyValues. There is a + #define that maps PaAsio_GetAvailableLatencyValues to this function for backwards compatibility. +*/ +PaError PaAsio_GetAvailableBufferSizes( PaDeviceIndex device, + long *minBufferSizeFrames, long *maxBufferSizeFrames, long *preferredBufferSizeFrames, long *granularity ); + + +/** Backwards compatibility alias for PaAsio_GetAvailableBufferSizes + + @see PaAsio_GetAvailableBufferSizes +*/ +#define PaAsio_GetAvailableLatencyValues PaAsio_GetAvailableBufferSizes + + +/** Display the ASIO control panel for the specified device. + + @param device The global index of the device whose control panel is to be displayed. + @param systemSpecific On Windows, the calling application's main window handle, + on Macintosh this value should be zero. +*/ +PaError PaAsio_ShowControlPanel( PaDeviceIndex device, void* systemSpecific ); + + + + +/** Retrieve a pointer to a string containing the name of the specified + input channel. The string is valid until Pa_Terminate is called. + + The string will be no longer than 32 characters including the null terminator. +*/ +PaError PaAsio_GetInputChannelName( PaDeviceIndex device, int channelIndex, + const char** channelName ); + + +/** Retrieve a pointer to a string containing the name of the specified + input channel. The string is valid until Pa_Terminate is called. + + The string will be no longer than 32 characters including the null terminator. +*/ +PaError PaAsio_GetOutputChannelName( PaDeviceIndex device, int channelIndex, + const char** channelName ); + + +/** Set the sample rate of an open paASIO stream. + + @param stream The stream to operate on. + @param sampleRate The new sample rate. + + Note that this function may fail if the stream is alredy running and the + ASIO driver does not support switching the sample rate of a running stream. + + Returns paIncompatibleStreamHostApi if stream is not a paASIO stream. +*/ +PaError PaAsio_SetStreamSampleRate( PaStream* stream, double sampleRate ); + + +#define paAsioUseChannelSelectors (0x01) + +typedef struct PaAsioStreamInfo{ + unsigned long size; /**< sizeof(PaAsioStreamInfo) */ + PaHostApiTypeId hostApiType; /**< paASIO */ + unsigned long version; /**< 1 */ + + unsigned long flags; + + /* Support for opening only specific channels of an ASIO device. + If the paAsioUseChannelSelectors flag is set, channelSelectors is a + pointer to an array of integers specifying the device channels to use. + When used, the length of the channelSelectors array must match the + corresponding channelCount parameter to Pa_OpenStream() otherwise a + crash may result. + The values in the selectors array must specify channels within the + range of supported channels for the device or paInvalidChannelCount will + result. + */ + int *channelSelectors; +}PaAsioStreamInfo; + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* PA_ASIO_H */ diff --git a/extern/portaudio/include/pa_jack.h b/extern/portaudio/include/pa_jack.h new file mode 100644 index 0000000..99ef833 --- /dev/null +++ b/extern/portaudio/include/pa_jack.h @@ -0,0 +1,77 @@ +#ifndef PA_JACK_H +#define PA_JACK_H + +/* + * $Id: + * PortAudio Portable Real-Time Audio Library + * JACK-specific extensions + * + * Copyright (c) 1999-2000 Ross Bencina and Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +/** @file + * @ingroup public_header + * @brief JACK-specific PortAudio API extension header file. + */ + +#include "portaudio.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** Set the JACK client name. + * + * During Pa_Initialize, When PA JACK connects as a client of the JACK server, it requests a certain + * name, which is for instance prepended to port names. By default this name is "PortAudio". The + * JACK server may append a suffix to the client name, in order to avoid clashes among clients that + * try to connect with the same name (e.g., different PA JACK clients). + * + * This function must be called before Pa_Initialize, otherwise it won't have any effect. Note that + * the string is not copied, but instead referenced directly, so it must not be freed for as long as + * PA might need it. + * @sa PaJack_GetClientName + */ +PaError PaJack_SetClientName( const char* name ); + +/** Get the JACK client name used by PA JACK. + * + * The caller is responsible for freeing the returned pointer. + */ +PaError PaJack_GetClientName(const char** clientName); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/extern/portaudio/include/pa_linux_alsa.h b/extern/portaudio/include/pa_linux_alsa.h new file mode 100644 index 0000000..7ac6736 --- /dev/null +++ b/extern/portaudio/include/pa_linux_alsa.h @@ -0,0 +1,107 @@ +#ifndef PA_LINUX_ALSA_H +#define PA_LINUX_ALSA_H + +/* + * $Id$ + * PortAudio Portable Real-Time Audio Library + * ALSA-specific extensions + * + * Copyright (c) 1999-2000 Ross Bencina and Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +/** @file + * @ingroup public_header + * @brief ALSA-specific PortAudio API extension header file. + */ + +#include "portaudio.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct PaAlsaStreamInfo +{ + unsigned long size; + PaHostApiTypeId hostApiType; + unsigned long version; + + const char *deviceString; +} +PaAlsaStreamInfo; + +/** Initialize host API specific structure, call this before setting relevant attributes. */ +void PaAlsa_InitializeStreamInfo( PaAlsaStreamInfo *info ); + +/** Instruct whether to enable real-time priority when starting the audio thread. + * + * If this is turned on by the stream is started, the audio callback thread will be created + * with the FIFO scheduling policy, which is suitable for realtime operation. + **/ +void PaAlsa_EnableRealtimeScheduling( PaStream *s, int enable ); + +#if 0 +void PaAlsa_EnableWatchdog( PaStream *s, int enable ); +#endif + +/** Get the ALSA-lib card index of this stream's input device. */ +PaError PaAlsa_GetStreamInputCard( PaStream *s, int *card ); + +/** Get the ALSA-lib card index of this stream's output device. */ +PaError PaAlsa_GetStreamOutputCard( PaStream *s, int *card ); + +/** Set the number of periods (buffer fragments) to configure devices with. + * + * By default the number of periods is 4, this is the lowest number of periods that works well on + * the author's soundcard. + * @param numPeriods The number of periods. + */ +PaError PaAlsa_SetNumPeriods( int numPeriods ); + +/** Set the maximum number of times to retry opening busy device (sleeping for a + * short interval inbetween). + */ +PaError PaAlsa_SetRetriesBusy( int retries ); + +/** Set the path and name of ALSA library file if PortAudio is configured to load it dynamically (see + * PA_ALSA_DYNAMIC). This setting will overwrite the default name set by PA_ALSA_PATHNAME define. + * @param pathName Full path with filename. Only filename can be used, but dlopen() will lookup default + * searchable directories (/usr/lib;/usr/local/lib) then. + */ +void PaAlsa_SetLibraryPathName( const char *pathName ); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/extern/portaudio/include/pa_mac_core.h b/extern/portaudio/include/pa_mac_core.h new file mode 100644 index 0000000..83e40a6 --- /dev/null +++ b/extern/portaudio/include/pa_mac_core.h @@ -0,0 +1,191 @@ +#ifndef PA_MAC_CORE_H +#define PA_MAC_CORE_H +/* + * PortAudio Portable Real-Time Audio Library + * Macintosh Core Audio specific extensions + * portaudio.h should be included before this file. + * + * Copyright (c) 2005-2006 Bjorn Roche + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +/** @file + * @ingroup public_header + * @brief CoreAudio-specific PortAudio API extension header file. + */ + +#include "portaudio.h" + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +/** + * A pointer to a paMacCoreStreamInfo may be passed as + * the hostApiSpecificStreamInfo in the PaStreamParameters struct + * when opening a stream or querying the format. Use NULL, for the + * defaults. Note that for duplex streams, flags for input and output + * should be the same or behaviour is undefined. + */ +typedef struct +{ + unsigned long size; /**size of whole structure including this header */ + PaHostApiTypeId hostApiType; /**host API for which this data is intended */ + unsigned long version; /**structure version */ + unsigned long flags; /** flags to modify behaviour */ + SInt32 const * channelMap; /** Channel map for HAL channel mapping , if not needed, use NULL;*/ + unsigned long channelMapSize; /** Channel map size for HAL channel mapping , if not needed, use 0;*/ +} PaMacCoreStreamInfo; + +/** + * Functions + */ + + +/** Use this function to initialize a paMacCoreStreamInfo struct + * using the requested flags. Note that channel mapping is turned + * off after a call to this function. + * @param data The datastructure to initialize + * @param flags The flags to initialize the datastructure with. +*/ +void PaMacCore_SetupStreamInfo( PaMacCoreStreamInfo *data, unsigned long flags ); + +/** call this after pa_SetupMacCoreStreamInfo to use channel mapping as described in notes.txt. + * @param data The stream info structure to assign a channel mapping to + * @param channelMap The channel map array, as described in notes.txt. This array pointer will be used directly (ie the underlying data will not be copied), so the caller should not free the array until after the stream has been opened. + * @param channelMapSize The size of the channel map array. + */ +void PaMacCore_SetupChannelMap( PaMacCoreStreamInfo *data, const SInt32 * const channelMap, unsigned long channelMapSize ); + +/** + * Retrieve the AudioDeviceID of the input device assigned to an open stream + * + * @param s The stream to query. + * + * @return A valid AudioDeviceID, or NULL if an error occurred. + */ +AudioDeviceID PaMacCore_GetStreamInputDevice( PaStream* s ); + +/** + * Retrieve the AudioDeviceID of the output device assigned to an open stream + * + * @param s The stream to query. + * + * @return A valid AudioDeviceID, or NULL if an error occurred. + */ +AudioDeviceID PaMacCore_GetStreamOutputDevice( PaStream* s ); + +/** + * Returns a statically allocated string with the device's name + * for the given channel. NULL will be returned on failure. + * + * This function's implemenation is not complete! + * + * @param device The PortAudio device index. + * @param channel The channel number who's name is requested. + * @return a statically allocated string with the name of the device. + * Because this string is statically allocated, it must be + * coppied if it is to be saved and used by the user after + * another call to this function. + * + */ +const char *PaMacCore_GetChannelName( int device, int channelIndex, bool input ); + + +/** Retrieve the range of legal native buffer sizes for the specificed device, in sample frames. + + @param device The global index of the PortAudio device about which the query is being made. + @param minBufferSizeFrames A pointer to the location which will receive the minimum buffer size value. + @param maxBufferSizeFrames A pointer to the location which will receive the maximum buffer size value. + + @see kAudioDevicePropertyBufferFrameSizeRange in the CoreAudio SDK. + */ +PaError PaMacCore_GetBufferSizeRange( PaDeviceIndex device, + long *minBufferSizeFrames, long *maxBufferSizeFrames ); + + +/** + * Flags + */ + +/** + * The following flags alter the behaviour of PA on the mac platform. + * they can be ORed together. These should work both for opening and + * checking a device. + */ + +/** Allows PortAudio to change things like the device's frame size, + * which allows for much lower latency, but might disrupt the device + * if other programs are using it, even when you are just Querying + * the device. */ +#define paMacCoreChangeDeviceParameters (0x01) + +/** In combination with the above flag, + * causes the stream opening to fail, unless the exact sample rates + * are supported by the device. */ +#define paMacCoreFailIfConversionRequired (0x02) + +/** These flags set the SR conversion quality, if required. The wierd ordering + * allows Maximum Quality to be the default.*/ +#define paMacCoreConversionQualityMin (0x0100) +#define paMacCoreConversionQualityMedium (0x0200) +#define paMacCoreConversionQualityLow (0x0300) +#define paMacCoreConversionQualityHigh (0x0400) +#define paMacCoreConversionQualityMax (0x0000) + +/** + * Here are some "preset" combinations of flags (above) to get to some + * common configurations. THIS IS OVERKILL, but if more flags are added + * it won't be. + */ + +/**This is the default setting: do as much sample rate conversion as possible + * and as little mucking with the device as possible. */ +#define paMacCorePlayNice (0x00) +/**This setting is tuned for pro audio apps. It allows SR conversion on input + and output, but it tries to set the appropriate SR on the device.*/ +#define paMacCorePro (0x01) +/**This is a setting to minimize CPU usage and still play nice.*/ +#define paMacCoreMinimizeCPUButPlayNice (0x0100) +/**This is a setting to minimize CPU usage, even if that means interrupting the device. */ +#define paMacCoreMinimizeCPU (0x0101) + + +#ifdef __cplusplus +} +#endif /** __cplusplus */ + +#endif /** PA_MAC_CORE_H */ diff --git a/extern/portaudio/include/pa_win_ds.h b/extern/portaudio/include/pa_win_ds.h new file mode 100644 index 0000000..5d38641 --- /dev/null +++ b/extern/portaudio/include/pa_win_ds.h @@ -0,0 +1,95 @@ +#ifndef PA_WIN_DS_H +#define PA_WIN_DS_H +/* + * $Id: $ + * PortAudio Portable Real-Time Audio Library + * DirectSound specific extensions + * + * Copyright (c) 1999-2007 Ross Bencina and Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +/** @file + @ingroup public_header + @brief DirectSound-specific PortAudio API extension header file. +*/ + +#include "portaudio.h" +#include "pa_win_waveformat.h" + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + +#define paWinDirectSoundUseLowLevelLatencyParameters (0x01) +#define paWinDirectSoundUseChannelMask (0x04) + + +typedef struct PaWinDirectSoundStreamInfo{ + unsigned long size; /**< sizeof(PaWinDirectSoundStreamInfo) */ + PaHostApiTypeId hostApiType; /**< paDirectSound */ + unsigned long version; /**< 2 */ + + unsigned long flags; /**< enable other features of this struct */ + + /** + low-level latency setting support + Sets the size of the DirectSound host buffer. + When flags contains the paWinDirectSoundUseLowLevelLatencyParameters + this size will be used instead of interpreting the generic latency + parameters to Pa_OpenStream(). If the flag is not set this value is ignored. + + If the stream is a full duplex stream the implementation requires that + the values of framesPerBuffer for input and output match (if both are specified). + */ + unsigned long framesPerBuffer; + + /** + support for WAVEFORMATEXTENSIBLE channel masks. If flags contains + paWinDirectSoundUseChannelMask this allows you to specify which speakers + to address in a multichannel stream. Constants for channelMask + are specified in pa_win_waveformat.h + + */ + PaWinWaveFormatChannelMask channelMask; + +}PaWinDirectSoundStreamInfo; + + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* PA_WIN_DS_H */ diff --git a/extern/portaudio/include/pa_win_wasapi.h b/extern/portaudio/include/pa_win_wasapi.h new file mode 100644 index 0000000..9b827d1 --- /dev/null +++ b/extern/portaudio/include/pa_win_wasapi.h @@ -0,0 +1,635 @@ +#ifndef PA_WIN_WASAPI_H +#define PA_WIN_WASAPI_H +/* + * $Id: $ + * PortAudio Portable Real-Time Audio Library + * WASAPI specific extensions + * + * Copyright (c) 1999-2018 Ross Bencina and Phil Burk + * Copyright (c) 2006-2010 David Viens + * Copyright (c) 2010-2018 Dmitry Kostjuchenko + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +/** @file + @ingroup public_header + @brief WASAPI-specific PortAudio API extension header file. +*/ + +#include "portaudio.h" +#include "pa_win_waveformat.h" + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + +/* Stream setup flags. */ +typedef enum PaWasapiFlags +{ + /* put WASAPI into exclusive mode */ + paWinWasapiExclusive = (1 << 0), + + /* allow to skip internal PA processing completely */ + paWinWasapiRedirectHostProcessor = (1 << 1), + + /* assign custom channel mask */ + paWinWasapiUseChannelMask = (1 << 2), + + /* select non-Event driven method of data read/write + Note: WASAPI Event driven core is capable of 2ms latency!!!, but Polling + method can only provide 15-20ms latency. */ + paWinWasapiPolling = (1 << 3), + + /* force custom thread priority setting, must be used if PaWasapiStreamInfo::threadPriority + is set to a custom value */ + paWinWasapiThreadPriority = (1 << 4), + + /* force explicit sample format and do not allow PA to select suitable working format, API will + fail if provided sample format is not supported by audio hardware in Exclusive mode + or system mixer in Shared mode */ + paWinWasapiExplicitSampleFormat = (1 << 5), + + /* allow API to insert system-level channel matrix mixer and sample rate converter to allow + playback formats that do not match the current configured system settings. + this is in particular required for streams not matching the system mixer sample rate. + only applies in Shared mode. */ + paWinWasapiAutoConvert = (1 << 6) +} +PaWasapiFlags; +#define paWinWasapiExclusive (paWinWasapiExclusive) +#define paWinWasapiRedirectHostProcessor (paWinWasapiRedirectHostProcessor) +#define paWinWasapiUseChannelMask (paWinWasapiUseChannelMask) +#define paWinWasapiPolling (paWinWasapiPolling) +#define paWinWasapiThreadPriority (paWinWasapiThreadPriority) +#define paWinWasapiExplicitSampleFormat (paWinWasapiExplicitSampleFormat) +#define paWinWasapiAutoConvert (paWinWasapiAutoConvert) + + +/* Stream state. + + @note Multiple states can be united into a bitmask. + @see PaWasapiStreamStateCallback, PaWasapi_SetStreamStateHandler +*/ +typedef enum PaWasapiStreamState +{ + /* state change was caused by the error: + + Example: + 1) If thread execution stopped due to AUDCLNT_E_RESOURCES_INVALIDATED then state + value will contain paWasapiStreamStateError|paWasapiStreamStateThreadStop. + */ + paWasapiStreamStateError = (1 << 0), + + /* processing thread is preparing to start execution */ + paWasapiStreamStateThreadPrepare = (1 << 1), + + /* processing thread started execution (enters its loop) */ + paWasapiStreamStateThreadStart = (1 << 2), + + /* processing thread stopped execution */ + paWasapiStreamStateThreadStop = (1 << 3) +} +PaWasapiStreamState; +#define paWasapiStreamStateError (paWasapiStreamStateError) +#define paWasapiStreamStateThreadPrepare (paWasapiStreamStateThreadPrepare) +#define paWasapiStreamStateThreadStart (paWasapiStreamStateThreadStart) +#define paWasapiStreamStateThreadStop (paWasapiStreamStateThreadStop) + + +/* Host processor. + + Allows to skip internal PA processing completely. paWinWasapiRedirectHostProcessor flag + must be set to the PaWasapiStreamInfo::flags member in order to have host processor + redirected to this callback. + + Use with caution! inputFrames and outputFrames depend solely on final device setup. + To query max values of inputFrames/outputFrames use PaWasapi_GetFramesPerHostBuffer. +*/ +typedef void (*PaWasapiHostProcessorCallback) (void *inputBuffer, long inputFrames, + void *outputBuffer, long outputFrames, void *userData); + + +/* Stream state handler. + + @param pStream Pointer to PaStream object. + @param stateFlags State flags, a collection of values from PaWasapiStreamState enum. + @param errorId Error id provided by system API (HRESULT). + @param userData Pointer to user data. + + @see PaWasapiStreamState +*/ +typedef void (*PaWasapiStreamStateCallback) (PaStream *pStream, unsigned int stateFlags, + unsigned int errorId, void *pUserData); + + +/* Device role. */ +typedef enum PaWasapiDeviceRole +{ + eRoleRemoteNetworkDevice = 0, + eRoleSpeakers, + eRoleLineLevel, + eRoleHeadphones, + eRoleMicrophone, + eRoleHeadset, + eRoleHandset, + eRoleUnknownDigitalPassthrough, + eRoleSPDIF, + eRoleHDMI, + eRoleUnknownFormFactor +} +PaWasapiDeviceRole; + + +/* Jack connection type. */ +typedef enum PaWasapiJackConnectionType +{ + eJackConnTypeUnknown, + eJackConnType3Point5mm, + eJackConnTypeQuarter, + eJackConnTypeAtapiInternal, + eJackConnTypeRCA, + eJackConnTypeOptical, + eJackConnTypeOtherDigital, + eJackConnTypeOtherAnalog, + eJackConnTypeMultichannelAnalogDIN, + eJackConnTypeXlrProfessional, + eJackConnTypeRJ11Modem, + eJackConnTypeCombination +} +PaWasapiJackConnectionType; + + +/* Jack geometric location. */ +typedef enum PaWasapiJackGeoLocation +{ + eJackGeoLocUnk = 0, + eJackGeoLocRear = 0x1, /* matches EPcxGeoLocation::eGeoLocRear */ + eJackGeoLocFront, + eJackGeoLocLeft, + eJackGeoLocRight, + eJackGeoLocTop, + eJackGeoLocBottom, + eJackGeoLocRearPanel, + eJackGeoLocRiser, + eJackGeoLocInsideMobileLid, + eJackGeoLocDrivebay, + eJackGeoLocHDMI, + eJackGeoLocOutsideMobileLid, + eJackGeoLocATAPI, + eJackGeoLocReserved5, + eJackGeoLocReserved6, +} +PaWasapiJackGeoLocation; + + +/* Jack general location. */ +typedef enum PaWasapiJackGenLocation +{ + eJackGenLocPrimaryBox = 0, + eJackGenLocInternal, + eJackGenLocSeparate, + eJackGenLocOther +} +PaWasapiJackGenLocation; + + +/* Jack's type of port. */ +typedef enum PaWasapiJackPortConnection +{ + eJackPortConnJack = 0, + eJackPortConnIntegratedDevice, + eJackPortConnBothIntegratedAndJack, + eJackPortConnUnknown +} +PaWasapiJackPortConnection; + + +/* Thread priority. */ +typedef enum PaWasapiThreadPriority +{ + eThreadPriorityNone = 0, + eThreadPriorityAudio, //!< Default for Shared mode. + eThreadPriorityCapture, + eThreadPriorityDistribution, + eThreadPriorityGames, + eThreadPriorityPlayback, + eThreadPriorityProAudio, //!< Default for Exclusive mode. + eThreadPriorityWindowManager +} +PaWasapiThreadPriority; + + +/* Stream descriptor. */ +typedef struct PaWasapiJackDescription +{ + unsigned long channelMapping; + unsigned long color; /* derived from macro: #define RGB(r,g,b) ((COLORREF)(((BYTE)(r)|((WORD)((BYTE)(g))<<8))|(((DWORD)(BYTE)(b))<<16))) */ + PaWasapiJackConnectionType connectionType; + PaWasapiJackGeoLocation geoLocation; + PaWasapiJackGenLocation genLocation; + PaWasapiJackPortConnection portConnection; + unsigned int isConnected; +} +PaWasapiJackDescription; + + +/** Stream category. + Note: + - values are equal to WASAPI AUDIO_STREAM_CATEGORY enum + - supported since Windows 8.0, noop on earler versions + - values 1,2 are deprecated on Windows 10 and not included into enumeration + + @version Available as of 19.6.0 +*/ +typedef enum PaWasapiStreamCategory +{ + eAudioCategoryOther = 0, + eAudioCategoryCommunications = 3, + eAudioCategoryAlerts = 4, + eAudioCategorySoundEffects = 5, + eAudioCategoryGameEffects = 6, + eAudioCategoryGameMedia = 7, + eAudioCategoryGameChat = 8, + eAudioCategorySpeech = 9, + eAudioCategoryMovie = 10, + eAudioCategoryMedia = 11 +} +PaWasapiStreamCategory; + + +/** Stream option. + Note: + - values are equal to WASAPI AUDCLNT_STREAMOPTIONS enum + - supported since Windows 8.1, noop on earler versions + + @version Available as of 19.6.0 +*/ +typedef enum PaWasapiStreamOption +{ + eStreamOptionNone = 0, //!< default + eStreamOptionRaw = 1, //!< bypass WASAPI Audio Engine DSP effects, supported since Windows 8.1 + eStreamOptionMatchFormat = 2 //!< force WASAPI Audio Engine into a stream format, supported since Windows 10 +} +PaWasapiStreamOption; + + +/* Stream descriptor. */ +typedef struct PaWasapiStreamInfo +{ + unsigned long size; /**< sizeof(PaWasapiStreamInfo) */ + PaHostApiTypeId hostApiType; /**< paWASAPI */ + unsigned long version; /**< 1 */ + + unsigned long flags; /**< collection of PaWasapiFlags */ + + /** Support for WAVEFORMATEXTENSIBLE channel masks. If flags contains + paWinWasapiUseChannelMask this allows you to specify which speakers + to address in a multichannel stream. Constants for channelMask + are specified in pa_win_waveformat.h. Will be used only if + paWinWasapiUseChannelMask flag is specified. + */ + PaWinWaveFormatChannelMask channelMask; + + /** Delivers raw data to callback obtained from GetBuffer() methods skipping + internal PortAudio processing inventory completely. userData parameter will + be the same that was passed to Pa_OpenStream method. Will be used only if + paWinWasapiRedirectHostProcessor flag is specified. + */ + PaWasapiHostProcessorCallback hostProcessorOutput; + PaWasapiHostProcessorCallback hostProcessorInput; + + /** Specifies thread priority explicitly. Will be used only if paWinWasapiThreadPriority flag + is specified. + + Please note, if Input/Output streams are opened simultaniously (Full-Duplex mode) + you shall specify same value for threadPriority or othervise one of the values will be used + to setup thread priority. + */ + PaWasapiThreadPriority threadPriority; + + /** Stream category. + @see PaWasapiStreamCategory + @version Available as of 19.6.0 + */ + PaWasapiStreamCategory streamCategory; + + /** Stream option. + @see PaWasapiStreamOption + @version Available as of 19.6.0 + */ + PaWasapiStreamOption streamOption; +} +PaWasapiStreamInfo; + + +/** Returns pointer to WASAPI's IAudioClient object of the stream. + + @param pStream Pointer to PaStream object. + @param pAudioClient Pointer to pointer of IAudioClient. + @param bOutput TRUE (1) for output stream, FALSE (0) for input stream. + + @return Error code indicating success or failure. +*/ +PaError PaWasapi_GetAudioClient( PaStream *pStream, void **pAudioClient, int bOutput ); + + +/** Update device list. + + This function is available if PA_WASAPI_MAX_CONST_DEVICE_COUNT is defined during compile time + with maximum constant WASAPI device count (recommended value - 32). + If PA_WASAPI_MAX_CONST_DEVICE_COUNT is set to 0 (or not defined) during compile time the implementation + will not define PaWasapi_UpdateDeviceList() and thus updating device list can only be possible by calling + Pa_Terminate() and then Pa_Initialize(). + + @return Error code indicating success or failure. +*/ +PaError PaWasapi_UpdateDeviceList(); + + +/** Get current audio format of the device assigned to the opened stream. + + Format is represented by PaWinWaveFormat or WAVEFORMATEXTENSIBLE structure. + Use this function to reconfirm format if PA's processor is overriden and + paWinWasapiRedirectHostProcessor flag is specified. + + @param pStream Pointer to PaStream object. + @param pFormat Pointer to PaWinWaveFormat or WAVEFORMATEXTENSIBLE structure. + @param formatSize Size of PaWinWaveFormat or WAVEFORMATEXTENSIBLE structure in bytes. + @param bOutput TRUE (1) for output stream, FALSE (0) for input stream. + + @return Non-negative value indicating the number of bytes copied into format decriptor + or, a PaErrorCode (which is always negative) if PortAudio is not initialized + or an error is encountered. +*/ +int PaWasapi_GetDeviceCurrentFormat( PaStream *pStream, void *pFormat, unsigned int formatSize, int bOutput ); + + +/** Get default audio format for the device in Shared Mode. + + Format is represented by PaWinWaveFormat or WAVEFORMATEXTENSIBLE structure and obtained + by getting the device property with a PKEY_AudioEngine_DeviceFormat key. + + @param pFormat Pointer to PaWinWaveFormat or WAVEFORMATEXTENSIBLE structure. + @param formatSize Size of PaWinWaveFormat or WAVEFORMATEXTENSIBLE structure in bytes. + @param device Device index. + + @return Non-negative value indicating the number of bytes copied into format decriptor + or, a PaErrorCode (which is always negative) if PortAudio is not initialized + or an error is encountered. +*/ +int PaWasapi_GetDeviceDefaultFormat( void *pFormat, unsigned int formatSize, PaDeviceIndex device ); + + +/** Get mix audio format for the device in Shared Mode. + + Format is represented by PaWinWaveFormat or WAVEFORMATEXTENSIBLE structureand obtained by + IAudioClient::GetMixFormat. + + @param pFormat Pointer to PaWinWaveFormat or WAVEFORMATEXTENSIBLE structure. + @param formatSize Size of PaWinWaveFormat or WAVEFORMATEXTENSIBLE structure in bytes. + @param device Device index. + + @return Non-negative value indicating the number of bytes copied into format decriptor + or, a PaErrorCode (which is always negative) if PortAudio is not initialized + or an error is encountered. +*/ +int PaWasapi_GetDeviceMixFormat( void *pFormat, unsigned int formatSize, PaDeviceIndex device ); + + +/** Get device role (PaWasapiDeviceRole enum). + + @param device Device index. + + @return Non-negative value indicating device role or, a PaErrorCode (which is always negative) + if PortAudio is not initialized or an error is encountered. +*/ +int/*PaWasapiDeviceRole*/ PaWasapi_GetDeviceRole( PaDeviceIndex device ); + + +/** Boost thread priority of calling thread (MMCSS). + + Use it for Blocking Interface only inside the thread which makes calls to Pa_WriteStream/Pa_ReadStream. + + @param pTask Handle to pointer to priority task. Must be used with PaWasapi_RevertThreadPriority + method to revert thread priority to initial state. + + @param priorityClass Id of thread priority of PaWasapiThreadPriority type. Specifying + eThreadPriorityNone does nothing. + + @return Error code indicating success or failure. + @see PaWasapi_RevertThreadPriority +*/ +PaError PaWasapi_ThreadPriorityBoost( void **pTask, PaWasapiThreadPriority priorityClass ); + + +/** Boost thread priority of calling thread (MMCSS). + + Use it for Blocking Interface only inside the thread which makes calls to Pa_WriteStream/Pa_ReadStream. + + @param pTask Task handle obtained by PaWasapi_BoostThreadPriority method. + + @return Error code indicating success or failure. + @see PaWasapi_BoostThreadPriority +*/ +PaError PaWasapi_ThreadPriorityRevert( void *pTask ); + + +/** Get number of frames per host buffer. + + It is max value of frames of WASAPI buffer which can be locked for operations. + Use this method as helper to findout max values of inputFrames/outputFrames + of PaWasapiHostProcessorCallback. + + @param pStream Pointer to PaStream object. + @param pInput Pointer to variable to receive number of input frames. Can be NULL. + @param pOutput Pointer to variable to receive number of output frames. Can be NULL. + + @return Error code indicating success or failure. + @see PaWasapiHostProcessorCallback +*/ +PaError PaWasapi_GetFramesPerHostBuffer( PaStream *pStream, unsigned int *pInput, unsigned int *pOutput ); + + +/** Get number of jacks associated with a WASAPI device. + + Use this method to determine if there are any jacks associated with the provided WASAPI device. + Not all audio devices will support this capability. This is valid for both input and output devices. + + @note Not available on UWP platform. + + @param device Device index. + @param pJackCount Pointer to variable to receive number of jacks. + + @return Error code indicating success or failure. + @see PaWasapi_GetJackDescription + */ +PaError PaWasapi_GetJackCount( PaDeviceIndex device, int *pJackCount ); + + +/** Get the jack description associated with a WASAPI device and jack number. + + Before this function is called, use PaWasapi_GetJackCount to determine the + number of jacks associated with device. If jcount is greater than zero, then + each jack from 0 to jcount can be queried with this function to get the jack + description. + + @note Not available on UWP platform. + + @param device Device index. + @param jackIndex Jack index. + @param pJackDescription Pointer to PaWasapiJackDescription. + + @return Error code indicating success or failure. + @see PaWasapi_GetJackCount + */ +PaError PaWasapi_GetJackDescription( PaDeviceIndex device, int jackIndex, PaWasapiJackDescription *pJackDescription ); + + +/** Set default interface Id. + + By default PA implementation will use DEVINTERFACE_AUDIO_RENDER and + DEVINTERFACE_AUDIO_CAPTURE if device Id is not provided explicitly. These default Ids + will not allow to use Exclusive mode on UWP platform and thus you must provide + device Id explicitly via this API before calling Pa_OpenStream(). + Device Ids on UWP platform are obtainable via + Windows::Media::Devices::MediaDevice::GetDefaultAudioRenderId() or + Windows::Media::Devices::MediaDevice::GetDefaultAudioCaptureId() API. + + @note UWP platform only. + + @param pId Interface Id, pointer to the 16-bit Unicode string (WCHAR). If NULL then device Id + will be reset to the default, e.g. DEVINTERFACE_AUDIO_RENDER or DEVINTERFACE_AUDIO_CAPTURE. + @param bOutput TRUE (1) for output (render), FALSE (0) for input (capture). + + @return Error code indicating success or failure. Will return paIncompatibleStreamHostApi if PA is not compiled + for UWP platform. If Id is longer than 4096 characters paBufferTooBig will be returned. +*/ +PaError PaWasapi_SetDefaultInterfaceId( unsigned short *pId, int bOutput ); + + +/** Set stream state handler. + + @param pStream Pointer to PaStream object. + @param fnStateHandler Pointer to state handling function. + @param pUserData Pointer to user data. + + @return Error code indicating success or failure. +*/ +PaError PaWasapi_SetStreamStateHandler( PaStream *pStream, PaWasapiStreamStateCallback fnStateHandler, void *pUserData ); + + +/* + IMPORTANT: + + WASAPI is implemented for Callback and Blocking interfaces. It supports Shared and Exclusive + share modes. + + Exclusive Mode: + + Exclusive mode allows to deliver audio data directly to hardware bypassing + software mixing. + Exclusive mode is specified by 'paWinWasapiExclusive' flag. + + Callback Interface: + + Provides best audio quality with low latency. Callback interface is implemented in + two versions: + + 1) Event-Driven: + This is the most powerful WASAPI implementation which provides glitch-free + audio at around 3ms latency in Exclusive mode. Lowest possible latency for this mode is + 3 ms for HD Audio class audio chips. For the Shared mode latency can not be + lower than 20 ms. + + 2) Poll-Driven: + Polling is another 2-nd method to operate with WASAPI. It is less efficient than Event-Driven + and provides latency at around 10-13ms. Polling must be used to overcome a system bug + under Windows Vista x64 when application is WOW64(32-bit) and Event-Driven method simply + times out (event handle is never signalled on buffer completion). Please note, such WOW64 bug + does not exist in Vista x86 or Windows 7. + Polling can be setup by speciying 'paWinWasapiPolling' flag. Our WASAPI implementation detects + WOW64 bug and sets 'paWinWasapiPolling' automatically. + + Thread priority: + + Normally thread priority is set automatically and does not require modification. Although + if user wants some tweaking thread priority can be modified by setting 'paWinWasapiThreadPriority' + flag and specifying 'PaWasapiStreamInfo::threadPriority' with value from PaWasapiThreadPriority + enum. + + Blocking Interface: + + Blocking interface is implemented but due to above described Poll-Driven method can not + deliver lowest possible latency. Specifying too low latency in Shared mode will result in + distorted audio although Exclusive mode adds stability. + + 8.24 format: + + If paCustomFormat is specified as sample format then the implementation will understand it + as valid 24-bits inside 32-bit container (e.g. wBitsPerSample = 32, Samples.wValidBitsPerSample = 24). + + By using paCustomFormat there will be small optimization when samples are be copied + with Copy_24_To_24 by PA processor instead of conversion from packed 3-byte (24-bit) data + with Int24_To_Int32. + + Pa_IsFormatSupported: + + To check format with correct Share Mode (Exclusive/Shared) you must supply PaWasapiStreamInfo + with flags paWinWasapiExclusive set through member of PaStreamParameters::hostApiSpecificStreamInfo + structure. + + If paWinWasapiExplicitSampleFormat flag is provided then implementation will not try to select + suitable close format and will return an error instead of paFormatIsSupported. By specifying + paWinWasapiExplicitSampleFormat flag it is possible to find out what sample formats are + supported by Exclusive or Shared modes. + + Pa_OpenStream: + + To set desired Share Mode (Exclusive/Shared) you must supply + PaWasapiStreamInfo with flags paWinWasapiExclusive set through member of + PaStreamParameters::hostApiSpecificStreamInfo structure. + + Coding style for parameters and structure members of the public API: + + 1) bXXX - boolean, [1 (TRUE), 0 (FALSE)] + 2) pXXX - pointer + 3) fnXXX - pointer to function + 4) structure members are never prefixed with a type distinguisher +*/ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* PA_WIN_WASAPI_H */ diff --git a/extern/portaudio/include/pa_win_waveformat.h b/extern/portaudio/include/pa_win_waveformat.h new file mode 100644 index 0000000..2c00267 --- /dev/null +++ b/extern/portaudio/include/pa_win_waveformat.h @@ -0,0 +1,199 @@ +#ifndef PA_WIN_WAVEFORMAT_H +#define PA_WIN_WAVEFORMAT_H + +/* + * PortAudio Portable Real-Time Audio Library + * Windows WAVEFORMAT* data structure utilities + * portaudio.h should be included before this file. + * + * Copyright (c) 2007 Ross Bencina + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +/** @file + @ingroup public_header + @brief Windows specific PortAudio API extension and utilities header file. +*/ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + The following #defines for speaker channel masks are the same + as those in ksmedia.h, except with PAWIN_ prepended, KSAUDIO_ removed + in some cases, and casts to PaWinWaveFormatChannelMask added. +*/ + +typedef unsigned long PaWinWaveFormatChannelMask; + +/* Speaker Positions: */ +#define PAWIN_SPEAKER_FRONT_LEFT ((PaWinWaveFormatChannelMask)0x1) +#define PAWIN_SPEAKER_FRONT_RIGHT ((PaWinWaveFormatChannelMask)0x2) +#define PAWIN_SPEAKER_FRONT_CENTER ((PaWinWaveFormatChannelMask)0x4) +#define PAWIN_SPEAKER_LOW_FREQUENCY ((PaWinWaveFormatChannelMask)0x8) +#define PAWIN_SPEAKER_BACK_LEFT ((PaWinWaveFormatChannelMask)0x10) +#define PAWIN_SPEAKER_BACK_RIGHT ((PaWinWaveFormatChannelMask)0x20) +#define PAWIN_SPEAKER_FRONT_LEFT_OF_CENTER ((PaWinWaveFormatChannelMask)0x40) +#define PAWIN_SPEAKER_FRONT_RIGHT_OF_CENTER ((PaWinWaveFormatChannelMask)0x80) +#define PAWIN_SPEAKER_BACK_CENTER ((PaWinWaveFormatChannelMask)0x100) +#define PAWIN_SPEAKER_SIDE_LEFT ((PaWinWaveFormatChannelMask)0x200) +#define PAWIN_SPEAKER_SIDE_RIGHT ((PaWinWaveFormatChannelMask)0x400) +#define PAWIN_SPEAKER_TOP_CENTER ((PaWinWaveFormatChannelMask)0x800) +#define PAWIN_SPEAKER_TOP_FRONT_LEFT ((PaWinWaveFormatChannelMask)0x1000) +#define PAWIN_SPEAKER_TOP_FRONT_CENTER ((PaWinWaveFormatChannelMask)0x2000) +#define PAWIN_SPEAKER_TOP_FRONT_RIGHT ((PaWinWaveFormatChannelMask)0x4000) +#define PAWIN_SPEAKER_TOP_BACK_LEFT ((PaWinWaveFormatChannelMask)0x8000) +#define PAWIN_SPEAKER_TOP_BACK_CENTER ((PaWinWaveFormatChannelMask)0x10000) +#define PAWIN_SPEAKER_TOP_BACK_RIGHT ((PaWinWaveFormatChannelMask)0x20000) + +/* Bit mask locations reserved for future use */ +#define PAWIN_SPEAKER_RESERVED ((PaWinWaveFormatChannelMask)0x7FFC0000) + +/* Used to specify that any possible permutation of speaker configurations */ +#define PAWIN_SPEAKER_ALL ((PaWinWaveFormatChannelMask)0x80000000) + +/* DirectSound Speaker Config */ +#define PAWIN_SPEAKER_DIRECTOUT 0 +#define PAWIN_SPEAKER_MONO (PAWIN_SPEAKER_FRONT_CENTER) +#define PAWIN_SPEAKER_STEREO (PAWIN_SPEAKER_FRONT_LEFT | PAWIN_SPEAKER_FRONT_RIGHT) +#define PAWIN_SPEAKER_QUAD (PAWIN_SPEAKER_FRONT_LEFT | PAWIN_SPEAKER_FRONT_RIGHT | \ + PAWIN_SPEAKER_BACK_LEFT | PAWIN_SPEAKER_BACK_RIGHT) +#define PAWIN_SPEAKER_SURROUND (PAWIN_SPEAKER_FRONT_LEFT | PAWIN_SPEAKER_FRONT_RIGHT | \ + PAWIN_SPEAKER_FRONT_CENTER | PAWIN_SPEAKER_BACK_CENTER) +#define PAWIN_SPEAKER_5POINT1 (PAWIN_SPEAKER_FRONT_LEFT | PAWIN_SPEAKER_FRONT_RIGHT | \ + PAWIN_SPEAKER_FRONT_CENTER | PAWIN_SPEAKER_LOW_FREQUENCY | \ + PAWIN_SPEAKER_BACK_LEFT | PAWIN_SPEAKER_BACK_RIGHT) +#define PAWIN_SPEAKER_7POINT1 (PAWIN_SPEAKER_FRONT_LEFT | PAWIN_SPEAKER_FRONT_RIGHT | \ + PAWIN_SPEAKER_FRONT_CENTER | PAWIN_SPEAKER_LOW_FREQUENCY | \ + PAWIN_SPEAKER_BACK_LEFT | PAWIN_SPEAKER_BACK_RIGHT | \ + PAWIN_SPEAKER_FRONT_LEFT_OF_CENTER | PAWIN_SPEAKER_FRONT_RIGHT_OF_CENTER) +#define PAWIN_SPEAKER_5POINT1_SURROUND (PAWIN_SPEAKER_FRONT_LEFT | PAWIN_SPEAKER_FRONT_RIGHT | \ + PAWIN_SPEAKER_FRONT_CENTER | PAWIN_SPEAKER_LOW_FREQUENCY | \ + PAWIN_SPEAKER_SIDE_LEFT | PAWIN_SPEAKER_SIDE_RIGHT) +#define PAWIN_SPEAKER_7POINT1_SURROUND (PAWIN_SPEAKER_FRONT_LEFT | PAWIN_SPEAKER_FRONT_RIGHT | \ + PAWIN_SPEAKER_FRONT_CENTER | PAWIN_SPEAKER_LOW_FREQUENCY | \ + PAWIN_SPEAKER_BACK_LEFT | PAWIN_SPEAKER_BACK_RIGHT | \ + PAWIN_SPEAKER_SIDE_LEFT | PAWIN_SPEAKER_SIDE_RIGHT) +/* + According to the Microsoft documentation: + The following are obsolete 5.1 and 7.1 settings (they lack side speakers). Note this means + that the default 5.1 and 7.1 settings (KSAUDIO_SPEAKER_5POINT1 and KSAUDIO_SPEAKER_7POINT1 are + similarly obsolete but are unchanged for compatibility reasons). +*/ +#define PAWIN_SPEAKER_5POINT1_BACK PAWIN_SPEAKER_5POINT1 +#define PAWIN_SPEAKER_7POINT1_WIDE PAWIN_SPEAKER_7POINT1 + +/* DVD Speaker Positions */ +#define PAWIN_SPEAKER_GROUND_FRONT_LEFT PAWIN_SPEAKER_FRONT_LEFT +#define PAWIN_SPEAKER_GROUND_FRONT_CENTER PAWIN_SPEAKER_FRONT_CENTER +#define PAWIN_SPEAKER_GROUND_FRONT_RIGHT PAWIN_SPEAKER_FRONT_RIGHT +#define PAWIN_SPEAKER_GROUND_REAR_LEFT PAWIN_SPEAKER_BACK_LEFT +#define PAWIN_SPEAKER_GROUND_REAR_RIGHT PAWIN_SPEAKER_BACK_RIGHT +#define PAWIN_SPEAKER_TOP_MIDDLE PAWIN_SPEAKER_TOP_CENTER +#define PAWIN_SPEAKER_SUPER_WOOFER PAWIN_SPEAKER_LOW_FREQUENCY + + +/* + PaWinWaveFormat is defined here to provide compatibility with + compilation environments which don't have headers defining + WAVEFORMATEXTENSIBLE (e.g. older versions of MSVC, Borland C++ etc. + + The fields for WAVEFORMATEX and WAVEFORMATEXTENSIBLE are declared as an + unsigned char array here to avoid clients who include this file having + a dependency on windows.h and mmsystem.h, and also to to avoid having + to write separate packing pragmas for each compiler. +*/ +#define PAWIN_SIZEOF_WAVEFORMATEX 18 +#define PAWIN_SIZEOF_WAVEFORMATEXTENSIBLE (PAWIN_SIZEOF_WAVEFORMATEX + 22) + +typedef struct{ + unsigned char fields[ PAWIN_SIZEOF_WAVEFORMATEXTENSIBLE ]; + unsigned long extraLongForAlignment; /* ensure that compiler aligns struct to DWORD */ +} PaWinWaveFormat; + +/* + WAVEFORMATEXTENSIBLE fields: + + union { + WORD wValidBitsPerSample; + WORD wSamplesPerBlock; + WORD wReserved; + } Samples; + DWORD dwChannelMask; + GUID SubFormat; +*/ + +#define PAWIN_INDEXOF_WVALIDBITSPERSAMPLE (PAWIN_SIZEOF_WAVEFORMATEX+0) +#define PAWIN_INDEXOF_DWCHANNELMASK (PAWIN_SIZEOF_WAVEFORMATEX+2) +#define PAWIN_INDEXOF_SUBFORMAT (PAWIN_SIZEOF_WAVEFORMATEX+6) + + +/* + Valid values to pass for the waveFormatTag PaWin_InitializeWaveFormatEx and + PaWin_InitializeWaveFormatExtensible functions below. These must match + the standard Windows WAVE_FORMAT_* values. +*/ +#define PAWIN_WAVE_FORMAT_PCM (1) +#define PAWIN_WAVE_FORMAT_IEEE_FLOAT (3) +#define PAWIN_WAVE_FORMAT_DOLBY_AC3_SPDIF (0x0092) +#define PAWIN_WAVE_FORMAT_WMA_SPDIF (0x0164) + + +/* + returns PAWIN_WAVE_FORMAT_PCM or PAWIN_WAVE_FORMAT_IEEE_FLOAT + depending on the sampleFormat parameter. +*/ +int PaWin_SampleFormatToLinearWaveFormatTag( PaSampleFormat sampleFormat ); + +/* + Use the following two functions to initialize the waveformat structure. +*/ + +void PaWin_InitializeWaveFormatEx( PaWinWaveFormat *waveFormat, + int numChannels, PaSampleFormat sampleFormat, int waveFormatTag, double sampleRate ); + + +void PaWin_InitializeWaveFormatExtensible( PaWinWaveFormat *waveFormat, + int numChannels, PaSampleFormat sampleFormat, int waveFormatTag, double sampleRate, + PaWinWaveFormatChannelMask channelMask ); + + +/* Map a channel count to a speaker channel mask */ +PaWinWaveFormatChannelMask PaWin_DefaultChannelMask( int numChannels ); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* PA_WIN_WAVEFORMAT_H */ \ No newline at end of file diff --git a/extern/portaudio/include/pa_win_wdmks.h b/extern/portaudio/include/pa_win_wdmks.h new file mode 100644 index 0000000..3592962 --- /dev/null +++ b/extern/portaudio/include/pa_win_wdmks.h @@ -0,0 +1,137 @@ +#ifndef PA_WIN_WDMKS_H +#define PA_WIN_WDMKS_H +/* + * $Id$ + * PortAudio Portable Real-Time Audio Library + * WDM/KS specific extensions + * + * Copyright (c) 1999-2007 Ross Bencina and Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +/** @file + @ingroup public_header + @brief WDM Kernel Streaming-specific PortAudio API extension header file. +*/ + + +#include "portaudio.h" + +#include + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + /** Flags to indicate valid fields in PaWinWDMKSInfo. + @see PaWinWDMKSInfo + @version Available as of 19.5.0. + */ + typedef enum PaWinWDMKSFlags + { + /** Makes WDMKS use the supplied latency figures instead of relying on the frame size reported + by the WaveCyclic device. Use at own risk! + */ + paWinWDMKSOverrideFramesize = (1 << 0), + + /** Makes WDMKS (output stream) use the given channelMask instead of the default. + @version Available as of 19.5.0. + */ + paWinWDMKSUseGivenChannelMask = (1 << 1), + + } PaWinWDMKSFlags; + + typedef struct PaWinWDMKSInfo{ + unsigned long size; /**< sizeof(PaWinWDMKSInfo) */ + PaHostApiTypeId hostApiType; /**< paWDMKS */ + unsigned long version; /**< 1 */ + + /** Flags indicate which fields are valid. + @see PaWinWDMKSFlags + @version Available as of 19.5.0. + */ + unsigned long flags; + + /** The number of packets to use for WaveCyclic devices, range is [2, 8]. Set to zero for default value of 2. */ + unsigned noOfPackets; + + /** If paWinWDMKSUseGivenChannelMask bit is set in flags, use this as channelMask instead of default. + @see PaWinWDMKSFlags + @version Available as of 19.5.0. + */ + unsigned channelMask; + } PaWinWDMKSInfo; + + typedef enum PaWDMKSType + { + Type_kNotUsed, + Type_kWaveCyclic, + Type_kWaveRT, + Type_kCnt, + } PaWDMKSType; + + typedef enum PaWDMKSSubType + { + SubType_kUnknown, + SubType_kNotification, + SubType_kPolled, + SubType_kCnt, + } PaWDMKSSubType; + + typedef struct PaWinWDMKSDeviceInfo { + wchar_t filterPath[MAX_PATH]; /**< KS filter path in Unicode! */ + wchar_t topologyPath[MAX_PATH]; /**< Topology filter path in Unicode! */ + PaWDMKSType streamingType; + GUID deviceProductGuid; /**< The product GUID of the device (if supported) */ + } PaWinWDMKSDeviceInfo; + + typedef struct PaWDMKSDirectionSpecificStreamInfo + { + PaDeviceIndex device; + unsigned channels; /**< No of channels the device is opened with */ + unsigned framesPerHostBuffer; /**< No of frames of the device buffer */ + int endpointPinId; /**< Endpoint pin ID (on topology filter if topologyName is not empty) */ + int muxNodeId; /**< Only valid for input */ + PaWDMKSSubType streamingSubType; /**< Not known until device is opened for streaming */ + } PaWDMKSDirectionSpecificStreamInfo; + + typedef struct PaWDMKSSpecificStreamInfo { + PaWDMKSDirectionSpecificStreamInfo input; + PaWDMKSDirectionSpecificStreamInfo output; + } PaWDMKSSpecificStreamInfo; + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* PA_WIN_DS_H */ diff --git a/extern/portaudio/include/pa_win_wmme.h b/extern/portaudio/include/pa_win_wmme.h new file mode 100644 index 0000000..f84b68b --- /dev/null +++ b/extern/portaudio/include/pa_win_wmme.h @@ -0,0 +1,185 @@ +#ifndef PA_WIN_WMME_H +#define PA_WIN_WMME_H +/* + * $Id$ + * PortAudio Portable Real-Time Audio Library + * MME specific extensions + * + * Copyright (c) 1999-2000 Ross Bencina and Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +/** @file + @ingroup public_header + @brief WMME-specific PortAudio API extension header file. +*/ + +#include "portaudio.h" +#include "pa_win_waveformat.h" + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + +/* The following are flags which can be set in + PaWinMmeStreamInfo's flags field. +*/ + +#define paWinMmeUseLowLevelLatencyParameters (0x01) +#define paWinMmeUseMultipleDevices (0x02) /* use mme specific multiple device feature */ +#define paWinMmeUseChannelMask (0x04) + +/* By default, the mme implementation drops the processing thread's priority + to THREAD_PRIORITY_NORMAL and sleeps the thread if the CPU load exceeds 100% + This flag disables any priority throttling. The processing thread will always + run at THREAD_PRIORITY_TIME_CRITICAL. +*/ +#define paWinMmeDontThrottleOverloadedProcessingThread (0x08) + +/* Flags for non-PCM spdif passthrough. +*/ +#define paWinMmeWaveFormatDolbyAc3Spdif (0x10) +#define paWinMmeWaveFormatWmaSpdif (0x20) + + +typedef struct PaWinMmeDeviceAndChannelCount{ + PaDeviceIndex device; + int channelCount; +}PaWinMmeDeviceAndChannelCount; + + +typedef struct PaWinMmeStreamInfo{ + unsigned long size; /**< sizeof(PaWinMmeStreamInfo) */ + PaHostApiTypeId hostApiType; /**< paMME */ + unsigned long version; /**< 1 */ + + unsigned long flags; + + /* low-level latency setting support + These settings control the number and size of host buffers in order + to set latency. They will be used instead of the generic parameters + to Pa_OpenStream() if flags contains the PaWinMmeUseLowLevelLatencyParameters + flag. + + If PaWinMmeStreamInfo structures with PaWinMmeUseLowLevelLatencyParameters + are supplied for both input and output in a full duplex stream, then the + input and output framesPerBuffer must be the same, or the larger of the + two must be a multiple of the smaller, otherwise a + paIncompatibleHostApiSpecificStreamInfo error will be returned from + Pa_OpenStream(). + */ + unsigned long framesPerBuffer; + unsigned long bufferCount; /* formerly numBuffers */ + + /* multiple devices per direction support + If flags contains the PaWinMmeUseMultipleDevices flag, + this functionality will be used, otherwise the device parameter to + Pa_OpenStream() will be used instead. + If devices are specified here, the corresponding device parameter + to Pa_OpenStream() should be set to paUseHostApiSpecificDeviceSpecification, + otherwise an paInvalidDevice error will result. + The total number of channels accross all specified devices + must agree with the corresponding channelCount parameter to + Pa_OpenStream() otherwise a paInvalidChannelCount error will result. + */ + PaWinMmeDeviceAndChannelCount *devices; + unsigned long deviceCount; + + /* + support for WAVEFORMATEXTENSIBLE channel masks. If flags contains + paWinMmeUseChannelMask this allows you to specify which speakers + to address in a multichannel stream. Constants for channelMask + are specified in pa_win_waveformat.h + + */ + PaWinWaveFormatChannelMask channelMask; + +}PaWinMmeStreamInfo; + + +/** Retrieve the number of wave in handles used by a PortAudio WinMME stream. + Returns zero if the stream is output only. + + @return A non-negative value indicating the number of wave in handles + or, a PaErrorCode (which are always negative) if PortAudio is not initialized + or an error is encountered. + + @see PaWinMME_GetStreamInputHandle +*/ +int PaWinMME_GetStreamInputHandleCount( PaStream* stream ); + + +/** Retrieve a wave in handle used by a PortAudio WinMME stream. + + @param stream The stream to query. + @param handleIndex The zero based index of the wave in handle to retrieve. This + should be in the range [0, PaWinMME_GetStreamInputHandleCount(stream)-1]. + + @return A valid wave in handle, or NULL if an error occurred. + + @see PaWinMME_GetStreamInputHandle +*/ +HWAVEIN PaWinMME_GetStreamInputHandle( PaStream* stream, int handleIndex ); + + +/** Retrieve the number of wave out handles used by a PortAudio WinMME stream. + Returns zero if the stream is input only. + + @return A non-negative value indicating the number of wave out handles + or, a PaErrorCode (which are always negative) if PortAudio is not initialized + or an error is encountered. + + @see PaWinMME_GetStreamOutputHandle +*/ +int PaWinMME_GetStreamOutputHandleCount( PaStream* stream ); + + +/** Retrieve a wave out handle used by a PortAudio WinMME stream. + + @param stream The stream to query. + @param handleIndex The zero based index of the wave out handle to retrieve. + This should be in the range [0, PaWinMME_GetStreamOutputHandleCount(stream)-1]. + + @return A valid wave out handle, or NULL if an error occurred. + + @see PaWinMME_GetStreamOutputHandleCount +*/ +HWAVEOUT PaWinMME_GetStreamOutputHandle( PaStream* stream, int handleIndex ); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* PA_WIN_WMME_H */ diff --git a/extern/portaudio/include/portaudio.h b/extern/portaudio/include/portaudio.h new file mode 100644 index 0000000..738080d --- /dev/null +++ b/extern/portaudio/include/portaudio.h @@ -0,0 +1,1225 @@ +#ifndef PORTAUDIO_H +#define PORTAUDIO_H +/* + * $Id$ + * PortAudio Portable Real-Time Audio Library + * PortAudio API Header File + * Latest version available at: http://www.portaudio.com/ + * + * Copyright (c) 1999-2002 Ross Bencina and Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +/** @file + @ingroup public_header + @brief The portable PortAudio API. +*/ + + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +/** Retrieve the release number of the currently running PortAudio build. + For example, for version "19.5.1" this will return 0x00130501. + + @see paMakeVersionNumber +*/ +int Pa_GetVersion( void ); + +/** Retrieve a textual description of the current PortAudio build, + e.g. "PortAudio V19.5.0-devel, revision 1952M". + The format of the text may change in the future. Do not try to parse the + returned string. + + @deprecated As of 19.5.0, use Pa_GetVersionInfo()->versionText instead. +*/ +const char* Pa_GetVersionText( void ); + +/** + Generate a packed integer version number in the same format used + by Pa_GetVersion(). Use this to compare a specified version number with + the currently running version. For example: + + @code + if( Pa_GetVersion() < paMakeVersionNumber(19,5,1) ) {} + @endcode + + @see Pa_GetVersion, Pa_GetVersionInfo + @version Available as of 19.5.0. +*/ +#define paMakeVersionNumber(major, minor, subminor) \ + (((major)&0xFF)<<16 | ((minor)&0xFF)<<8 | ((subminor)&0xFF)) + + +/** + A structure containing PortAudio API version information. + @see Pa_GetVersionInfo, paMakeVersionNumber + @version Available as of 19.5.0. +*/ +typedef struct PaVersionInfo { + int versionMajor; + int versionMinor; + int versionSubMinor; + /** + This is currently the Git revision hash but may change in the future. + The versionControlRevision is updated by running a script before compiling the library. + If the update does not occur, this value may refer to an earlier revision. + */ + const char *versionControlRevision; + /** Version as a string, for example "PortAudio V19.5.0-devel, revision 1952M" */ + const char *versionText; +} PaVersionInfo; + +/** Retrieve version information for the currently running PortAudio build. + @return A pointer to an immutable PaVersionInfo structure. + + @note This function can be called at any time. It does not require PortAudio + to be initialized. The structure pointed to is statically allocated. Do not + attempt to free it or modify it. + + @see PaVersionInfo, paMakeVersionNumber + @version Available as of 19.5.0. +*/ +const PaVersionInfo* Pa_GetVersionInfo( void ); + + +/** Error codes returned by PortAudio functions. + Note that with the exception of paNoError, all PaErrorCodes are negative. +*/ + +typedef int PaError; +typedef enum PaErrorCode +{ + paNoError = 0, + + paNotInitialized = -10000, + paUnanticipatedHostError, + paInvalidChannelCount, + paInvalidSampleRate, + paInvalidDevice, + paInvalidFlag, + paSampleFormatNotSupported, + paBadIODeviceCombination, + paInsufficientMemory, + paBufferTooBig, + paBufferTooSmall, + paNullCallback, + paBadStreamPtr, + paTimedOut, + paInternalError, + paDeviceUnavailable, + paIncompatibleHostApiSpecificStreamInfo, + paStreamIsStopped, + paStreamIsNotStopped, + paInputOverflowed, + paOutputUnderflowed, + paHostApiNotFound, + paInvalidHostApi, + paCanNotReadFromACallbackStream, + paCanNotWriteToACallbackStream, + paCanNotReadFromAnOutputOnlyStream, + paCanNotWriteToAnInputOnlyStream, + paIncompatibleStreamHostApi, + paBadBufferPtr +} PaErrorCode; + + +/** Translate the supplied PortAudio error code into a human readable + message. +*/ +const char *Pa_GetErrorText( PaError errorCode ); + + +/** Library initialization function - call this before using PortAudio. + This function initializes internal data structures and prepares underlying + host APIs for use. With the exception of Pa_GetVersion(), Pa_GetVersionText(), + and Pa_GetErrorText(), this function MUST be called before using any other + PortAudio API functions. + + If Pa_Initialize() is called multiple times, each successful + call must be matched with a corresponding call to Pa_Terminate(). + Pairs of calls to Pa_Initialize()/Pa_Terminate() may overlap, and are not + required to be fully nested. + + Note that if Pa_Initialize() returns an error code, Pa_Terminate() should + NOT be called. + + @return paNoError if successful, otherwise an error code indicating the cause + of failure. + + @see Pa_Terminate +*/ +PaError Pa_Initialize( void ); + + +/** Library termination function - call this when finished using PortAudio. + This function deallocates all resources allocated by PortAudio since it was + initialized by a call to Pa_Initialize(). In cases where Pa_Initialise() has + been called multiple times, each call must be matched with a corresponding call + to Pa_Terminate(). The final matching call to Pa_Terminate() will automatically + close any PortAudio streams that are still open. + + Pa_Terminate() MUST be called before exiting a program which uses PortAudio. + Failure to do so may result in serious resource leaks, such as audio devices + not being available until the next reboot. + + @return paNoError if successful, otherwise an error code indicating the cause + of failure. + + @see Pa_Initialize +*/ +PaError Pa_Terminate( void ); + + + +/** The type used to refer to audio devices. Values of this type usually + range from 0 to (Pa_GetDeviceCount()-1), and may also take on the PaNoDevice + and paUseHostApiSpecificDeviceSpecification values. + + @see Pa_GetDeviceCount, paNoDevice, paUseHostApiSpecificDeviceSpecification +*/ +typedef int PaDeviceIndex; + + +/** A special PaDeviceIndex value indicating that no device is available, + or should be used. + + @see PaDeviceIndex +*/ +#define paNoDevice ((PaDeviceIndex)-1) + + +/** A special PaDeviceIndex value indicating that the device(s) to be used + are specified in the host api specific stream info structure. + + @see PaDeviceIndex +*/ +#define paUseHostApiSpecificDeviceSpecification ((PaDeviceIndex)-2) + + +/* Host API enumeration mechanism */ + +/** The type used to enumerate to host APIs at runtime. Values of this type + range from 0 to (Pa_GetHostApiCount()-1). + + @see Pa_GetHostApiCount +*/ +typedef int PaHostApiIndex; + + +/** Retrieve the number of available host APIs. Even if a host API is + available it may have no devices available. + + @return A non-negative value indicating the number of available host APIs + or, a PaErrorCode (which are always negative) if PortAudio is not initialized + or an error is encountered. + + @see PaHostApiIndex +*/ +PaHostApiIndex Pa_GetHostApiCount( void ); + + +/** Retrieve the index of the default host API. The default host API will be + the lowest common denominator host API on the current platform and is + unlikely to provide the best performance. + + @return A non-negative value ranging from 0 to (Pa_GetHostApiCount()-1) + indicating the default host API index or, a PaErrorCode (which are always + negative) if PortAudio is not initialized or an error is encountered. +*/ +PaHostApiIndex Pa_GetDefaultHostApi( void ); + + +/** Unchanging unique identifiers for each supported host API. This type + is used in the PaHostApiInfo structure. The values are guaranteed to be + unique and to never change, thus allowing code to be written that + conditionally uses host API specific extensions. + + New type ids will be allocated when support for a host API reaches + "public alpha" status, prior to that developers should use the + paInDevelopment type id. + + @see PaHostApiInfo +*/ +typedef enum PaHostApiTypeId +{ + paInDevelopment=0, /* use while developing support for a new host API */ + paDirectSound=1, + paMME=2, + paASIO=3, + paSoundManager=4, + paCoreAudio=5, + paOSS=7, + paALSA=8, + paAL=9, + paBeOS=10, + paWDMKS=11, + paJACK=12, + paWASAPI=13, + paAudioScienceHPI=14 +} PaHostApiTypeId; + + +/** A structure containing information about a particular host API. */ + +typedef struct PaHostApiInfo +{ + /** this is struct version 1 */ + int structVersion; + /** The well known unique identifier of this host API @see PaHostApiTypeId */ + PaHostApiTypeId type; + /** A textual description of the host API for display on user interfaces. */ + const char *name; + + /** The number of devices belonging to this host API. This field may be + used in conjunction with Pa_HostApiDeviceIndexToDeviceIndex() to enumerate + all devices for this host API. + @see Pa_HostApiDeviceIndexToDeviceIndex + */ + int deviceCount; + + /** The default input device for this host API. The value will be a + device index ranging from 0 to (Pa_GetDeviceCount()-1), or paNoDevice + if no default input device is available. + */ + PaDeviceIndex defaultInputDevice; + + /** The default output device for this host API. The value will be a + device index ranging from 0 to (Pa_GetDeviceCount()-1), or paNoDevice + if no default output device is available. + */ + PaDeviceIndex defaultOutputDevice; + +} PaHostApiInfo; + + +/** Retrieve a pointer to a structure containing information about a specific + host Api. + + @param hostApi A valid host API index ranging from 0 to (Pa_GetHostApiCount()-1) + + @return A pointer to an immutable PaHostApiInfo structure describing + a specific host API. If the hostApi parameter is out of range or an error + is encountered, the function returns NULL. + + The returned structure is owned by the PortAudio implementation and must not + be manipulated or freed. The pointer is only guaranteed to be valid between + calls to Pa_Initialize() and Pa_Terminate(). +*/ +const PaHostApiInfo * Pa_GetHostApiInfo( PaHostApiIndex hostApi ); + + +/** Convert a static host API unique identifier, into a runtime + host API index. + + @param type A unique host API identifier belonging to the PaHostApiTypeId + enumeration. + + @return A valid PaHostApiIndex ranging from 0 to (Pa_GetHostApiCount()-1) or, + a PaErrorCode (which are always negative) if PortAudio is not initialized + or an error is encountered. + + The paHostApiNotFound error code indicates that the host API specified by the + type parameter is not available. + + @see PaHostApiTypeId +*/ +PaHostApiIndex Pa_HostApiTypeIdToHostApiIndex( PaHostApiTypeId type ); + + +/** Convert a host-API-specific device index to standard PortAudio device index. + This function may be used in conjunction with the deviceCount field of + PaHostApiInfo to enumerate all devices for the specified host API. + + @param hostApi A valid host API index ranging from 0 to (Pa_GetHostApiCount()-1) + + @param hostApiDeviceIndex A valid per-host device index in the range + 0 to (Pa_GetHostApiInfo(hostApi)->deviceCount-1) + + @return A non-negative PaDeviceIndex ranging from 0 to (Pa_GetDeviceCount()-1) + or, a PaErrorCode (which are always negative) if PortAudio is not initialized + or an error is encountered. + + A paInvalidHostApi error code indicates that the host API index specified by + the hostApi parameter is out of range. + + A paInvalidDevice error code indicates that the hostApiDeviceIndex parameter + is out of range. + + @see PaHostApiInfo +*/ +PaDeviceIndex Pa_HostApiDeviceIndexToDeviceIndex( PaHostApiIndex hostApi, + int hostApiDeviceIndex ); + + + +/** Structure used to return information about a host error condition. +*/ +typedef struct PaHostErrorInfo{ + PaHostApiTypeId hostApiType; /**< the host API which returned the error code */ + long errorCode; /**< the error code returned */ + const char *errorText; /**< a textual description of the error if available, otherwise a zero-length string */ +}PaHostErrorInfo; + + +/** Return information about the last host error encountered. The error + information returned by Pa_GetLastHostErrorInfo() will never be modified + asynchronously by errors occurring in other PortAudio owned threads + (such as the thread that manages the stream callback.) + + This function is provided as a last resort, primarily to enhance debugging + by providing clients with access to all available error information. + + @return A pointer to an immutable structure constraining information about + the host error. The values in this structure will only be valid if a + PortAudio function has previously returned the paUnanticipatedHostError + error code. +*/ +const PaHostErrorInfo* Pa_GetLastHostErrorInfo( void ); + + + +/* Device enumeration and capabilities */ + +/** Retrieve the number of available devices. The number of available devices + may be zero. + + @return A non-negative value indicating the number of available devices or, + a PaErrorCode (which are always negative) if PortAudio is not initialized + or an error is encountered. +*/ +PaDeviceIndex Pa_GetDeviceCount( void ); + + +/** Retrieve the index of the default input device. The result can be + used in the inputDevice parameter to Pa_OpenStream(). + + @return The default input device index for the default host API, or paNoDevice + if no default input device is available or an error was encountered. +*/ +PaDeviceIndex Pa_GetDefaultInputDevice( void ); + + +/** Retrieve the index of the default output device. The result can be + used in the outputDevice parameter to Pa_OpenStream(). + + @return The default output device index for the default host API, or paNoDevice + if no default output device is available or an error was encountered. + + @note + On the PC, the user can specify a default device by + setting an environment variable. For example, to use device #1. +
    + set PA_RECOMMENDED_OUTPUT_DEVICE=1
    +
    + The user should first determine the available device ids by using + the supplied application "pa_devs". +*/ +PaDeviceIndex Pa_GetDefaultOutputDevice( void ); + + +/** The type used to represent monotonic time in seconds. PaTime is + used for the fields of the PaStreamCallbackTimeInfo argument to the + PaStreamCallback and as the result of Pa_GetStreamTime(). + + PaTime values have unspecified origin. + + @see PaStreamCallback, PaStreamCallbackTimeInfo, Pa_GetStreamTime +*/ +typedef double PaTime; + + +/** A type used to specify one or more sample formats. Each value indicates + a possible format for sound data passed to and from the stream callback, + Pa_ReadStream and Pa_WriteStream. + + The standard formats paFloat32, paInt16, paInt32, paInt24, paInt8 + and aUInt8 are usually implemented by all implementations. + + The floating point representation (paFloat32) uses +1.0 and -1.0 as the + maximum and minimum respectively. + + paUInt8 is an unsigned 8 bit format where 128 is considered "ground" + + The paNonInterleaved flag indicates that audio data is passed as an array + of pointers to separate buffers, one buffer for each channel. Usually, + when this flag is not used, audio data is passed as a single buffer with + all channels interleaved. + + @see Pa_OpenStream, Pa_OpenDefaultStream, PaDeviceInfo + @see paFloat32, paInt16, paInt32, paInt24, paInt8 + @see paUInt8, paCustomFormat, paNonInterleaved +*/ +typedef unsigned long PaSampleFormat; + + +#define paFloat32 ((PaSampleFormat) 0x00000001) /**< @see PaSampleFormat */ +#define paInt32 ((PaSampleFormat) 0x00000002) /**< @see PaSampleFormat */ +#define paInt24 ((PaSampleFormat) 0x00000004) /**< Packed 24 bit format. @see PaSampleFormat */ +#define paInt16 ((PaSampleFormat) 0x00000008) /**< @see PaSampleFormat */ +#define paInt8 ((PaSampleFormat) 0x00000010) /**< @see PaSampleFormat */ +#define paUInt8 ((PaSampleFormat) 0x00000020) /**< @see PaSampleFormat */ +#define paCustomFormat ((PaSampleFormat) 0x00010000) /**< @see PaSampleFormat */ + +#define paNonInterleaved ((PaSampleFormat) 0x80000000) /**< @see PaSampleFormat */ + +/** A structure providing information and capabilities of PortAudio devices. + Devices may support input, output or both input and output. +*/ +typedef struct PaDeviceInfo +{ + int structVersion; /* this is struct version 2 */ + const char *name; + PaHostApiIndex hostApi; /**< note this is a host API index, not a type id*/ + + int maxInputChannels; + int maxOutputChannels; + + /** Default latency values for interactive performance. */ + PaTime defaultLowInputLatency; + PaTime defaultLowOutputLatency; + /** Default latency values for robust non-interactive applications (eg. playing sound files). */ + PaTime defaultHighInputLatency; + PaTime defaultHighOutputLatency; + + double defaultSampleRate; +} PaDeviceInfo; + + +/** Retrieve a pointer to a PaDeviceInfo structure containing information + about the specified device. + @return A pointer to an immutable PaDeviceInfo structure. If the device + parameter is out of range the function returns NULL. + + @param device A valid device index in the range 0 to (Pa_GetDeviceCount()-1) + + @note PortAudio manages the memory referenced by the returned pointer, + the client must not manipulate or free the memory. The pointer is only + guaranteed to be valid between calls to Pa_Initialize() and Pa_Terminate(). + + @see PaDeviceInfo, PaDeviceIndex +*/ +const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceIndex device ); + + +/** Parameters for one direction (input or output) of a stream. +*/ +typedef struct PaStreamParameters +{ + /** A valid device index in the range 0 to (Pa_GetDeviceCount()-1) + specifying the device to be used or the special constant + paUseHostApiSpecificDeviceSpecification which indicates that the actual + device(s) to use are specified in hostApiSpecificStreamInfo. + This field must not be set to paNoDevice. + */ + PaDeviceIndex device; + + /** The number of channels of sound to be delivered to the + stream callback or accessed by Pa_ReadStream() or Pa_WriteStream(). + It can range from 1 to the value of maxInputChannels in the + PaDeviceInfo record for the device specified by the device parameter. + */ + int channelCount; + + /** The sample format of the buffer provided to the stream callback, + a_ReadStream() or Pa_WriteStream(). It may be any of the formats described + by the PaSampleFormat enumeration. + */ + PaSampleFormat sampleFormat; + + /** The desired latency in seconds. Where practical, implementations should + configure their latency based on these parameters, otherwise they may + choose the closest viable latency instead. Unless the suggested latency + is greater than the absolute upper limit for the device implementations + should round the suggestedLatency up to the next practical value - ie to + provide an equal or higher latency than suggestedLatency wherever possible. + Actual latency values for an open stream may be retrieved using the + inputLatency and outputLatency fields of the PaStreamInfo structure + returned by Pa_GetStreamInfo(). + @see default*Latency in PaDeviceInfo, *Latency in PaStreamInfo + */ + PaTime suggestedLatency; + + /** An optional pointer to a host api specific data structure + containing additional information for device setup and/or stream processing. + hostApiSpecificStreamInfo is never required for correct operation, + if not used it should be set to NULL. + */ + void *hostApiSpecificStreamInfo; + +} PaStreamParameters; + + +/** Return code for Pa_IsFormatSupported indicating success. */ +#define paFormatIsSupported (0) + +/** Determine whether it would be possible to open a stream with the specified + parameters. + + @param inputParameters A structure that describes the input parameters used to + open a stream. The suggestedLatency field is ignored. See PaStreamParameters + for a description of these parameters. inputParameters must be NULL for + output-only streams. + + @param outputParameters A structure that describes the output parameters used + to open a stream. The suggestedLatency field is ignored. See PaStreamParameters + for a description of these parameters. outputParameters must be NULL for + input-only streams. + + @param sampleRate The required sampleRate. For full-duplex streams it is the + sample rate for both input and output + + @return Returns 0 if the format is supported, and an error code indicating why + the format is not supported otherwise. The constant paFormatIsSupported is + provided to compare with the return value for success. + + @see paFormatIsSupported, PaStreamParameters +*/ +PaError Pa_IsFormatSupported( const PaStreamParameters *inputParameters, + const PaStreamParameters *outputParameters, + double sampleRate ); + + + +/* Streaming types and functions */ + + +/** + A single PaStream can provide multiple channels of real-time + streaming audio input and output to a client application. A stream + provides access to audio hardware represented by one or more + PaDevices. Depending on the underlying Host API, it may be possible + to open multiple streams using the same device, however this behavior + is implementation defined. Portable applications should assume that + a PaDevice may be simultaneously used by at most one PaStream. + + Pointers to PaStream objects are passed between PortAudio functions that + operate on streams. + + @see Pa_OpenStream, Pa_OpenDefaultStream, Pa_OpenDefaultStream, Pa_CloseStream, + Pa_StartStream, Pa_StopStream, Pa_AbortStream, Pa_IsStreamActive, + Pa_GetStreamTime, Pa_GetStreamCpuLoad + +*/ +typedef void PaStream; + + +/** Can be passed as the framesPerBuffer parameter to Pa_OpenStream() + or Pa_OpenDefaultStream() to indicate that the stream callback will + accept buffers of any size. +*/ +#define paFramesPerBufferUnspecified (0) + + +/** Flags used to control the behavior of a stream. They are passed as + parameters to Pa_OpenStream or Pa_OpenDefaultStream. Multiple flags may be + ORed together. + + @see Pa_OpenStream, Pa_OpenDefaultStream + @see paNoFlag, paClipOff, paDitherOff, paNeverDropInput, + paPrimeOutputBuffersUsingStreamCallback, paPlatformSpecificFlags +*/ +typedef unsigned long PaStreamFlags; + +/** @see PaStreamFlags */ +#define paNoFlag ((PaStreamFlags) 0) + +/** Disable default clipping of out of range samples. + @see PaStreamFlags +*/ +#define paClipOff ((PaStreamFlags) 0x00000001) + +/** Disable default dithering. + @see PaStreamFlags +*/ +#define paDitherOff ((PaStreamFlags) 0x00000002) + +/** Flag requests that where possible a full duplex stream will not discard + overflowed input samples without calling the stream callback. This flag is + only valid for full duplex callback streams and only when used in combination + with the paFramesPerBufferUnspecified (0) framesPerBuffer parameter. Using + this flag incorrectly results in a paInvalidFlag error being returned from + Pa_OpenStream and Pa_OpenDefaultStream. + + @see PaStreamFlags, paFramesPerBufferUnspecified +*/ +#define paNeverDropInput ((PaStreamFlags) 0x00000004) + +/** Call the stream callback to fill initial output buffers, rather than the + default behavior of priming the buffers with zeros (silence). This flag has + no effect for input-only and blocking read/write streams. + + @see PaStreamFlags +*/ +#define paPrimeOutputBuffersUsingStreamCallback ((PaStreamFlags) 0x00000008) + +/** A mask specifying the platform specific bits. + @see PaStreamFlags +*/ +#define paPlatformSpecificFlags ((PaStreamFlags)0xFFFF0000) + +/** + Timing information for the buffers passed to the stream callback. + + Time values are expressed in seconds and are synchronised with the time base used by Pa_GetStreamTime() for the associated stream. + + @see PaStreamCallback, Pa_GetStreamTime +*/ +typedef struct PaStreamCallbackTimeInfo{ + PaTime inputBufferAdcTime; /**< The time when the first sample of the input buffer was captured at the ADC input */ + PaTime currentTime; /**< The time when the stream callback was invoked */ + PaTime outputBufferDacTime; /**< The time when the first sample of the output buffer will output the DAC */ +} PaStreamCallbackTimeInfo; + + +/** + Flag bit constants for the statusFlags to PaStreamCallback. + + @see paInputUnderflow, paInputOverflow, paOutputUnderflow, paOutputOverflow, + paPrimingOutput +*/ +typedef unsigned long PaStreamCallbackFlags; + +/** In a stream opened with paFramesPerBufferUnspecified, indicates that + input data is all silence (zeros) because no real data is available. In a + stream opened without paFramesPerBufferUnspecified, it indicates that one or + more zero samples have been inserted into the input buffer to compensate + for an input underflow. + @see PaStreamCallbackFlags +*/ +#define paInputUnderflow ((PaStreamCallbackFlags) 0x00000001) + +/** In a stream opened with paFramesPerBufferUnspecified, indicates that data + prior to the first sample of the input buffer was discarded due to an + overflow, possibly because the stream callback is using too much CPU time. + Otherwise indicates that data prior to one or more samples in the + input buffer was discarded. + @see PaStreamCallbackFlags +*/ +#define paInputOverflow ((PaStreamCallbackFlags) 0x00000002) + +/** Indicates that output data (or a gap) was inserted, possibly because the + stream callback is using too much CPU time. + @see PaStreamCallbackFlags +*/ +#define paOutputUnderflow ((PaStreamCallbackFlags) 0x00000004) + +/** Indicates that output data will be discarded because no room is available. + @see PaStreamCallbackFlags +*/ +#define paOutputOverflow ((PaStreamCallbackFlags) 0x00000008) + +/** Some of all of the output data will be used to prime the stream, input + data may be zero. + @see PaStreamCallbackFlags +*/ +#define paPrimingOutput ((PaStreamCallbackFlags) 0x00000010) + +/** + Allowable return values for the PaStreamCallback. + @see PaStreamCallback +*/ +typedef enum PaStreamCallbackResult +{ + paContinue=0, /**< Signal that the stream should continue invoking the callback and processing audio. */ + paComplete=1, /**< Signal that the stream should stop invoking the callback and finish once all output samples have played. */ + paAbort=2 /**< Signal that the stream should stop invoking the callback and finish as soon as possible. */ +} PaStreamCallbackResult; + + +/** + Functions of type PaStreamCallback are implemented by PortAudio clients. + They consume, process or generate audio in response to requests from an + active PortAudio stream. + + When a stream is running, PortAudio calls the stream callback periodically. + The callback function is responsible for processing buffers of audio samples + passed via the input and output parameters. + + The PortAudio stream callback runs at very high or real-time priority. + It is required to consistently meet its time deadlines. Do not allocate + memory, access the file system, call library functions or call other functions + from the stream callback that may block or take an unpredictable amount of + time to complete. + + In order for a stream to maintain glitch-free operation the callback + must consume and return audio data faster than it is recorded and/or + played. PortAudio anticipates that each callback invocation may execute for + a duration approaching the duration of frameCount audio frames at the stream + sample rate. It is reasonable to expect to be able to utilise 70% or more of + the available CPU time in the PortAudio callback. However, due to buffer size + adaption and other factors, not all host APIs are able to guarantee audio + stability under heavy CPU load with arbitrary fixed callback buffer sizes. + When high callback CPU utilisation is required the most robust behavior + can be achieved by using paFramesPerBufferUnspecified as the + Pa_OpenStream() framesPerBuffer parameter. + + @param input and @param output are either arrays of interleaved samples or; + if non-interleaved samples were requested using the paNonInterleaved sample + format flag, an array of buffer pointers, one non-interleaved buffer for + each channel. + + The format, packing and number of channels used by the buffers are + determined by parameters to Pa_OpenStream(). + + @param frameCount The number of sample frames to be processed by + the stream callback. + + @param timeInfo Timestamps indicating the ADC capture time of the first sample + in the input buffer, the DAC output time of the first sample in the output buffer + and the time the callback was invoked. + See PaStreamCallbackTimeInfo and Pa_GetStreamTime() + + @param statusFlags Flags indicating whether input and/or output buffers + have been inserted or will be dropped to overcome underflow or overflow + conditions. + + @param userData The value of a user supplied pointer passed to + Pa_OpenStream() intended for storing synthesis data etc. + + @return + The stream callback should return one of the values in the + ::PaStreamCallbackResult enumeration. To ensure that the callback continues + to be called, it should return paContinue (0). Either paComplete or paAbort + can be returned to finish stream processing, after either of these values is + returned the callback will not be called again. If paAbort is returned the + stream will finish as soon as possible. If paComplete is returned, the stream + will continue until all buffers generated by the callback have been played. + This may be useful in applications such as soundfile players where a specific + duration of output is required. However, it is not necessary to utilize this + mechanism as Pa_StopStream(), Pa_AbortStream() or Pa_CloseStream() can also + be used to stop the stream. The callback must always fill the entire output + buffer irrespective of its return value. + + @see Pa_OpenStream, Pa_OpenDefaultStream + + @note With the exception of Pa_GetStreamCpuLoad() it is not permissible to call + PortAudio API functions from within the stream callback. +*/ +typedef int PaStreamCallback( + const void *input, void *output, + unsigned long frameCount, + const PaStreamCallbackTimeInfo* timeInfo, + PaStreamCallbackFlags statusFlags, + void *userData ); + + +/** Opens a stream for either input, output or both. + + @param stream The address of a PaStream pointer which will receive + a pointer to the newly opened stream. + + @param inputParameters A structure that describes the input parameters used by + the opened stream. See PaStreamParameters for a description of these parameters. + inputParameters must be NULL for output-only streams. + + @param outputParameters A structure that describes the output parameters used by + the opened stream. See PaStreamParameters for a description of these parameters. + outputParameters must be NULL for input-only streams. + + @param sampleRate The desired sampleRate. For full-duplex streams it is the + sample rate for both input and output + + @param framesPerBuffer The number of frames passed to the stream callback + function, or the preferred block granularity for a blocking read/write stream. + The special value paFramesPerBufferUnspecified (0) may be used to request that + the stream callback will receive an optimal (and possibly varying) number of + frames based on host requirements and the requested latency settings. + Note: With some host APIs, the use of non-zero framesPerBuffer for a callback + stream may introduce an additional layer of buffering which could introduce + additional latency. PortAudio guarantees that the additional latency + will be kept to the theoretical minimum however, it is strongly recommended + that a non-zero framesPerBuffer value only be used when your algorithm + requires a fixed number of frames per stream callback. + + @param streamFlags Flags which modify the behavior of the streaming process. + This parameter may contain a combination of flags ORed together. Some flags may + only be relevant to certain buffer formats. + + @param streamCallback A pointer to a client supplied function that is responsible + for processing and filling input and output buffers. If this parameter is NULL + the stream will be opened in 'blocking read/write' mode. In blocking mode, + the client can receive sample data using Pa_ReadStream and write sample data + using Pa_WriteStream, the number of samples that may be read or written + without blocking is returned by Pa_GetStreamReadAvailable and + Pa_GetStreamWriteAvailable respectively. + + @param userData A client supplied pointer which is passed to the stream callback + function. It could for example, contain a pointer to instance data necessary + for processing the audio buffers. This parameter is ignored if streamCallback + is NULL. + + @return + Upon success Pa_OpenStream() returns paNoError and places a pointer to a + valid PaStream in the stream argument. The stream is inactive (stopped). + If a call to Pa_OpenStream() fails, a non-zero error code is returned (see + PaError for possible error codes) and the value of stream is invalid. + + @see PaStreamParameters, PaStreamCallback, Pa_ReadStream, Pa_WriteStream, + Pa_GetStreamReadAvailable, Pa_GetStreamWriteAvailable +*/ +PaError Pa_OpenStream( PaStream** stream, + const PaStreamParameters *inputParameters, + const PaStreamParameters *outputParameters, + double sampleRate, + unsigned long framesPerBuffer, + PaStreamFlags streamFlags, + PaStreamCallback *streamCallback, + void *userData ); + + +/** A simplified version of Pa_OpenStream() that opens the default input + and/or output devices. + + @param stream The address of a PaStream pointer which will receive + a pointer to the newly opened stream. + + @param numInputChannels The number of channels of sound that will be supplied + to the stream callback or returned by Pa_ReadStream. It can range from 1 to + the value of maxInputChannels in the PaDeviceInfo record for the default input + device. If 0 the stream is opened as an output-only stream. + + @param numOutputChannels The number of channels of sound to be delivered to the + stream callback or passed to Pa_WriteStream. It can range from 1 to the value + of maxOutputChannels in the PaDeviceInfo record for the default output device. + If 0 the stream is opened as an output-only stream. + + @param sampleFormat The sample format of both the input and output buffers + provided to the callback or passed to and from Pa_ReadStream and Pa_WriteStream. + sampleFormat may be any of the formats described by the PaSampleFormat + enumeration. + + @param sampleRate Same as Pa_OpenStream parameter of the same name. + @param framesPerBuffer Same as Pa_OpenStream parameter of the same name. + @param streamCallback Same as Pa_OpenStream parameter of the same name. + @param userData Same as Pa_OpenStream parameter of the same name. + + @return As for Pa_OpenStream + + @see Pa_OpenStream, PaStreamCallback +*/ +PaError Pa_OpenDefaultStream( PaStream** stream, + int numInputChannels, + int numOutputChannels, + PaSampleFormat sampleFormat, + double sampleRate, + unsigned long framesPerBuffer, + PaStreamCallback *streamCallback, + void *userData ); + + +/** Closes an audio stream. If the audio stream is active it + discards any pending buffers as if Pa_AbortStream() had been called. +*/ +PaError Pa_CloseStream( PaStream *stream ); + + +/** Functions of type PaStreamFinishedCallback are implemented by PortAudio + clients. They can be registered with a stream using the Pa_SetStreamFinishedCallback + function. Once registered they are called when the stream becomes inactive + (ie once a call to Pa_StopStream() will not block). + A stream will become inactive after the stream callback returns non-zero, + or when Pa_StopStream or Pa_AbortStream is called. For a stream providing audio + output, if the stream callback returns paComplete, or Pa_StopStream() is called, + the stream finished callback will not be called until all generated sample data + has been played. + + @param userData The userData parameter supplied to Pa_OpenStream() + + @see Pa_SetStreamFinishedCallback +*/ +typedef void PaStreamFinishedCallback( void *userData ); + + +/** Register a stream finished callback function which will be called when the + stream becomes inactive. See the description of PaStreamFinishedCallback for + further details about when the callback will be called. + + @param stream a pointer to a PaStream that is in the stopped state - if the + stream is not stopped, the stream's finished callback will remain unchanged + and an error code will be returned. + + @param streamFinishedCallback a pointer to a function with the same signature + as PaStreamFinishedCallback, that will be called when the stream becomes + inactive. Passing NULL for this parameter will un-register a previously + registered stream finished callback function. + + @return on success returns paNoError, otherwise an error code indicating the cause + of the error. + + @see PaStreamFinishedCallback +*/ +PaError Pa_SetStreamFinishedCallback( PaStream *stream, PaStreamFinishedCallback* streamFinishedCallback ); + + +/** Commences audio processing. +*/ +PaError Pa_StartStream( PaStream *stream ); + + +/** Terminates audio processing. It waits until all pending + audio buffers have been played before it returns. +*/ +PaError Pa_StopStream( PaStream *stream ); + + +/** Terminates audio processing immediately without waiting for pending + buffers to complete. +*/ +PaError Pa_AbortStream( PaStream *stream ); + + +/** Determine whether the stream is stopped. + A stream is considered to be stopped prior to a successful call to + Pa_StartStream and after a successful call to Pa_StopStream or Pa_AbortStream. + If a stream callback returns a value other than paContinue the stream is NOT + considered to be stopped. + + @return Returns one (1) when the stream is stopped, zero (0) when + the stream is running or, a PaErrorCode (which are always negative) if + PortAudio is not initialized or an error is encountered. + + @see Pa_StopStream, Pa_AbortStream, Pa_IsStreamActive +*/ +PaError Pa_IsStreamStopped( PaStream *stream ); + + +/** Determine whether the stream is active. + A stream is active after a successful call to Pa_StartStream(), until it + becomes inactive either as a result of a call to Pa_StopStream() or + Pa_AbortStream(), or as a result of a return value other than paContinue from + the stream callback. In the latter case, the stream is considered inactive + after the last buffer has finished playing. + + @return Returns one (1) when the stream is active (ie playing or recording + audio), zero (0) when not playing or, a PaErrorCode (which are always negative) + if PortAudio is not initialized or an error is encountered. + + @see Pa_StopStream, Pa_AbortStream, Pa_IsStreamStopped +*/ +PaError Pa_IsStreamActive( PaStream *stream ); + + + +/** A structure containing unchanging information about an open stream. + @see Pa_GetStreamInfo +*/ + +typedef struct PaStreamInfo +{ + /** this is struct version 1 */ + int structVersion; + + /** The input latency of the stream in seconds. This value provides the most + accurate estimate of input latency available to the implementation. It may + differ significantly from the suggestedLatency value passed to Pa_OpenStream(). + The value of this field will be zero (0.) for output-only streams. + @see PaTime + */ + PaTime inputLatency; + + /** The output latency of the stream in seconds. This value provides the most + accurate estimate of output latency available to the implementation. It may + differ significantly from the suggestedLatency value passed to Pa_OpenStream(). + The value of this field will be zero (0.) for input-only streams. + @see PaTime + */ + PaTime outputLatency; + + /** The sample rate of the stream in Hertz (samples per second). In cases + where the hardware sample rate is inaccurate and PortAudio is aware of it, + the value of this field may be different from the sampleRate parameter + passed to Pa_OpenStream(). If information about the actual hardware sample + rate is not available, this field will have the same value as the sampleRate + parameter passed to Pa_OpenStream(). + */ + double sampleRate; + +} PaStreamInfo; + + +/** Retrieve a pointer to a PaStreamInfo structure containing information + about the specified stream. + @return A pointer to an immutable PaStreamInfo structure. If the stream + parameter is invalid, or an error is encountered, the function returns NULL. + + @param stream A pointer to an open stream previously created with Pa_OpenStream. + + @note PortAudio manages the memory referenced by the returned pointer, + the client must not manipulate or free the memory. The pointer is only + guaranteed to be valid until the specified stream is closed. + + @see PaStreamInfo +*/ +const PaStreamInfo* Pa_GetStreamInfo( PaStream *stream ); + + +/** Returns the current time in seconds for a stream according to the same clock used + to generate callback PaStreamCallbackTimeInfo timestamps. The time values are + monotonically increasing and have unspecified origin. + + Pa_GetStreamTime returns valid time values for the entire life of the stream, + from when the stream is opened until it is closed. Starting and stopping the stream + does not affect the passage of time returned by Pa_GetStreamTime. + + This time may be used for synchronizing other events to the audio stream, for + example synchronizing audio to MIDI. + + @return The stream's current time in seconds, or 0 if an error occurred. + + @see PaTime, PaStreamCallback, PaStreamCallbackTimeInfo +*/ +PaTime Pa_GetStreamTime( PaStream *stream ); + + +/** Retrieve CPU usage information for the specified stream. + The "CPU Load" is a fraction of total CPU time consumed by a callback stream's + audio processing routines including, but not limited to the client supplied + stream callback. This function does not work with blocking read/write streams. + + This function may be called from the stream callback function or the + application. + + @return + A floating point value, typically between 0.0 and 1.0, where 1.0 indicates + that the stream callback is consuming the maximum number of CPU cycles possible + to maintain real-time operation. A value of 0.5 would imply that PortAudio and + the stream callback was consuming roughly 50% of the available CPU time. The + return value may exceed 1.0. A value of 0.0 will always be returned for a + blocking read/write stream, or if an error occurs. +*/ +double Pa_GetStreamCpuLoad( PaStream* stream ); + + +/** Read samples from an input stream. The function doesn't return until + the entire buffer has been filled - this may involve waiting for the operating + system to supply the data. + + @param stream A pointer to an open stream previously created with Pa_OpenStream. + + @param buffer A pointer to a buffer of sample frames. The buffer contains + samples in the format specified by the inputParameters->sampleFormat field + used to open the stream, and the number of channels specified by + inputParameters->numChannels. If non-interleaved samples were requested using + the paNonInterleaved sample format flag, buffer is a pointer to the first element + of an array of buffer pointers, one non-interleaved buffer for each channel. + + @param frames The number of frames to be read into buffer. This parameter + is not constrained to a specific range, however high performance applications + will want to match this parameter to the framesPerBuffer parameter used + when opening the stream. + + @return On success PaNoError will be returned, or PaInputOverflowed if input + data was discarded by PortAudio after the previous call and before this call. +*/ +PaError Pa_ReadStream( PaStream* stream, + void *buffer, + unsigned long frames ); + + +/** Write samples to an output stream. This function doesn't return until the + entire buffer has been written - this may involve waiting for the operating + system to consume the data. + + @param stream A pointer to an open stream previously created with Pa_OpenStream. + + @param buffer A pointer to a buffer of sample frames. The buffer contains + samples in the format specified by the outputParameters->sampleFormat field + used to open the stream, and the number of channels specified by + outputParameters->numChannels. If non-interleaved samples were requested using + the paNonInterleaved sample format flag, buffer is a pointer to the first element + of an array of buffer pointers, one non-interleaved buffer for each channel. + + @param frames The number of frames to be written from buffer. This parameter + is not constrained to a specific range, however high performance applications + will want to match this parameter to the framesPerBuffer parameter used + when opening the stream. + + @return On success PaNoError will be returned, or paOutputUnderflowed if + additional output data was inserted after the previous call and before this + call. +*/ +PaError Pa_WriteStream( PaStream* stream, + const void *buffer, + unsigned long frames ); + + +/** Retrieve the number of frames that can be read from the stream without + waiting. + + @return Returns a non-negative value representing the maximum number of frames + that can be read from the stream without blocking or busy waiting or, a + PaErrorCode (which are always negative) if PortAudio is not initialized or an + error is encountered. +*/ +signed long Pa_GetStreamReadAvailable( PaStream* stream ); + + +/** Retrieve the number of frames that can be written to the stream without + waiting. + + @return Returns a non-negative value representing the maximum number of frames + that can be written to the stream without blocking or busy waiting or, a + PaErrorCode (which are always negative) if PortAudio is not initialized or an + error is encountered. +*/ +signed long Pa_GetStreamWriteAvailable( PaStream* stream ); + + +/* Miscellaneous utilities */ + + +/** Retrieve the size of a given sample format in bytes. + + @return The size in bytes of a single sample in the specified format, + or paSampleFormatNotSupported if the format is not supported. +*/ +PaError Pa_GetSampleSize( PaSampleFormat format ); + + +/** Put the caller to sleep for at least 'msec' milliseconds. This function is + provided only as a convenience for authors of portable code (such as the tests + and examples in the PortAudio distribution.) + + The function may sleep longer than requested so don't rely on this for accurate + musical timing. +*/ +void Pa_Sleep( long msec ); + + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* PORTAUDIO_H */ diff --git a/extern/portaudio/index.html b/extern/portaudio/index.html new file mode 100644 index 0000000..55f9ed6 --- /dev/null +++ b/extern/portaudio/index.html @@ -0,0 +1,105 @@ + + + + + + + + + PortAudio Implementations for DirectSound + + +  +
    + + + +
    +
    +

    +PortAudio - Portable Audio Library

    +
    + +

    PortAudio is a cross platform, open-source, audio +I/O library proposed by Ross Bencina to the music-dsp +mailing list. It lets you write simple audio programs in 'C' that will +compile and run on Windows, Macintosh, Unix, BeOS. PortAudio is +intended to promote the exchange of audio synthesis software between developers +on different platforms. +

    For complete information on PortAudio and to download the latest releases, +please visit "http://www.portaudio.com". +
      +
      +

    +

    +Click here for Documentation

    + +

    +

    + +

    +Contacts and E-Mail List

    + +
      +
    • +If you are using or implementing PortAudio then please join the PortAudio +mail list .
    • + +
    • +If you find bugs in one of these implementations, or have suggestions, +please e-mail them to Phil Burk.
    • + +
    • +If you make improvements to the library, please send them to us so we can +incorporate the improvements.
    • +
    + +

    +License

    + + +
    +

    +PortAudio Portable Real-Time Audio Library +
    Copyright © 1999-2006 Ross Bencina and Phil Burk +

    +

    Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following conditions: +

    +

    +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. +

    +

    +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND ON INFRINGEMENT. +
    IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT +OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR +THE USE OR OTHER DEALINGS IN THE SOFTWARE. +

    + +

    +The text above constitutes the entire PortAudio license; however, +the PortAudio community also makes the following non-binding requests: +

    +

    +Any person wishing to distribute modifications to the Software is +requested to send the modifications to the original developer so that +they can be incorporated into the canonical version. It is also +requested that these non-binding requests be included along with the +license above. +

    + +
    + + + +
      + + diff --git a/extern/portaudio/install-sh b/extern/portaudio/install-sh new file mode 100755 index 0000000..377bb86 --- /dev/null +++ b/extern/portaudio/install-sh @@ -0,0 +1,527 @@ +#!/bin/sh +# install - install a program, script, or datafile + +scriptversion=2011-11-20.07; # UTC + +# This originates from X11R5 (mit/util/scripts/install.sh), which was +# later released in X11R6 (xc/config/util/install.sh) with the +# following copyright and license. +# +# Copyright (C) 1994 X Consortium +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to +# deal in the Software without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- +# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# Except as contained in this notice, the name of the X Consortium shall not +# be used in advertising or otherwise to promote the sale, use or other deal- +# ings in this Software without prior written authorization from the X Consor- +# tium. +# +# +# FSF changes to this file are in the public domain. +# +# Calling this script install-sh is preferred over install.sh, to prevent +# 'make' implicit rules from creating a file called install from it +# when there is no Makefile. +# +# This script is compatible with the BSD install script, but was written +# from scratch. + +nl=' +' +IFS=" "" $nl" + +# set DOITPROG to echo to test this script + +# Don't use :- since 4.3BSD and earlier shells don't like it. +doit=${DOITPROG-} +if test -z "$doit"; then + doit_exec=exec +else + doit_exec=$doit +fi + +# Put in absolute file names if you don't have them in your path; +# or use environment vars. + +chgrpprog=${CHGRPPROG-chgrp} +chmodprog=${CHMODPROG-chmod} +chownprog=${CHOWNPROG-chown} +cmpprog=${CMPPROG-cmp} +cpprog=${CPPROG-cp} +mkdirprog=${MKDIRPROG-mkdir} +mvprog=${MVPROG-mv} +rmprog=${RMPROG-rm} +stripprog=${STRIPPROG-strip} + +posix_glob='?' +initialize_posix_glob=' + test "$posix_glob" != "?" || { + if (set -f) 2>/dev/null; then + posix_glob= + else + posix_glob=: + fi + } +' + +posix_mkdir= + +# Desired mode of installed file. +mode=0755 + +chgrpcmd= +chmodcmd=$chmodprog +chowncmd= +mvcmd=$mvprog +rmcmd="$rmprog -f" +stripcmd= + +src= +dst= +dir_arg= +dst_arg= + +copy_on_change=false +no_target_directory= + +usage="\ +Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE + or: $0 [OPTION]... SRCFILES... DIRECTORY + or: $0 [OPTION]... -t DIRECTORY SRCFILES... + or: $0 [OPTION]... -d DIRECTORIES... + +In the 1st form, copy SRCFILE to DSTFILE. +In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. +In the 4th, create DIRECTORIES. + +Options: + --help display this help and exit. + --version display version info and exit. + + -c (ignored) + -C install only if different (preserve the last data modification time) + -d create directories instead of installing files. + -g GROUP $chgrpprog installed files to GROUP. + -m MODE $chmodprog installed files to MODE. + -o USER $chownprog installed files to USER. + -s $stripprog installed files. + -t DIRECTORY install into DIRECTORY. + -T report an error if DSTFILE is a directory. + +Environment variables override the default commands: + CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG + RMPROG STRIPPROG +" + +while test $# -ne 0; do + case $1 in + -c) ;; + + -C) copy_on_change=true;; + + -d) dir_arg=true;; + + -g) chgrpcmd="$chgrpprog $2" + shift;; + + --help) echo "$usage"; exit $?;; + + -m) mode=$2 + case $mode in + *' '* | *' '* | *' +'* | *'*'* | *'?'* | *'['*) + echo "$0: invalid mode: $mode" >&2 + exit 1;; + esac + shift;; + + -o) chowncmd="$chownprog $2" + shift;; + + -s) stripcmd=$stripprog;; + + -t) dst_arg=$2 + # Protect names problematic for 'test' and other utilities. + case $dst_arg in + -* | [=\(\)!]) dst_arg=./$dst_arg;; + esac + shift;; + + -T) no_target_directory=true;; + + --version) echo "$0 $scriptversion"; exit $?;; + + --) shift + break;; + + -*) echo "$0: invalid option: $1" >&2 + exit 1;; + + *) break;; + esac + shift +done + +if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then + # When -d is used, all remaining arguments are directories to create. + # When -t is used, the destination is already specified. + # Otherwise, the last argument is the destination. Remove it from $@. + for arg + do + if test -n "$dst_arg"; then + # $@ is not empty: it contains at least $arg. + set fnord "$@" "$dst_arg" + shift # fnord + fi + shift # arg + dst_arg=$arg + # Protect names problematic for 'test' and other utilities. + case $dst_arg in + -* | [=\(\)!]) dst_arg=./$dst_arg;; + esac + done +fi + +if test $# -eq 0; then + if test -z "$dir_arg"; then + echo "$0: no input file specified." >&2 + exit 1 + fi + # It's OK to call 'install-sh -d' without argument. + # This can happen when creating conditional directories. + exit 0 +fi + +if test -z "$dir_arg"; then + do_exit='(exit $ret); exit $ret' + trap "ret=129; $do_exit" 1 + trap "ret=130; $do_exit" 2 + trap "ret=141; $do_exit" 13 + trap "ret=143; $do_exit" 15 + + # Set umask so as not to create temps with too-generous modes. + # However, 'strip' requires both read and write access to temps. + case $mode in + # Optimize common cases. + *644) cp_umask=133;; + *755) cp_umask=22;; + + *[0-7]) + if test -z "$stripcmd"; then + u_plus_rw= + else + u_plus_rw='% 200' + fi + cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; + *) + if test -z "$stripcmd"; then + u_plus_rw= + else + u_plus_rw=,u+rw + fi + cp_umask=$mode$u_plus_rw;; + esac +fi + +for src +do + # Protect names problematic for 'test' and other utilities. + case $src in + -* | [=\(\)!]) src=./$src;; + esac + + if test -n "$dir_arg"; then + dst=$src + dstdir=$dst + test -d "$dstdir" + dstdir_status=$? + else + + # Waiting for this to be detected by the "$cpprog $src $dsttmp" command + # might cause directories to be created, which would be especially bad + # if $src (and thus $dsttmp) contains '*'. + if test ! -f "$src" && test ! -d "$src"; then + echo "$0: $src does not exist." >&2 + exit 1 + fi + + if test -z "$dst_arg"; then + echo "$0: no destination specified." >&2 + exit 1 + fi + dst=$dst_arg + + # If destination is a directory, append the input filename; won't work + # if double slashes aren't ignored. + if test -d "$dst"; then + if test -n "$no_target_directory"; then + echo "$0: $dst_arg: Is a directory" >&2 + exit 1 + fi + dstdir=$dst + dst=$dstdir/`basename "$src"` + dstdir_status=0 + else + # Prefer dirname, but fall back on a substitute if dirname fails. + dstdir=` + (dirname "$dst") 2>/dev/null || + expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$dst" : 'X\(//\)[^/]' \| \ + X"$dst" : 'X\(//\)$' \| \ + X"$dst" : 'X\(/\)' \| . 2>/dev/null || + echo X"$dst" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q' + ` + + test -d "$dstdir" + dstdir_status=$? + fi + fi + + obsolete_mkdir_used=false + + if test $dstdir_status != 0; then + case $posix_mkdir in + '') + # Create intermediate dirs using mode 755 as modified by the umask. + # This is like FreeBSD 'install' as of 1997-10-28. + umask=`umask` + case $stripcmd.$umask in + # Optimize common cases. + *[2367][2367]) mkdir_umask=$umask;; + .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; + + *[0-7]) + mkdir_umask=`expr $umask + 22 \ + - $umask % 100 % 40 + $umask % 20 \ + - $umask % 10 % 4 + $umask % 2 + `;; + *) mkdir_umask=$umask,go-w;; + esac + + # With -d, create the new directory with the user-specified mode. + # Otherwise, rely on $mkdir_umask. + if test -n "$dir_arg"; then + mkdir_mode=-m$mode + else + mkdir_mode= + fi + + posix_mkdir=false + case $umask in + *[123567][0-7][0-7]) + # POSIX mkdir -p sets u+wx bits regardless of umask, which + # is incompatible with FreeBSD 'install' when (umask & 300) != 0. + ;; + *) + tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ + trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0 + + if (umask $mkdir_umask && + exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1 + then + if test -z "$dir_arg" || { + # Check for POSIX incompatibilities with -m. + # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or + # other-writable bit of parent directory when it shouldn't. + # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. + ls_ld_tmpdir=`ls -ld "$tmpdir"` + case $ls_ld_tmpdir in + d????-?r-*) different_mode=700;; + d????-?--*) different_mode=755;; + *) false;; + esac && + $mkdirprog -m$different_mode -p -- "$tmpdir" && { + ls_ld_tmpdir_1=`ls -ld "$tmpdir"` + test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" + } + } + then posix_mkdir=: + fi + rmdir "$tmpdir/d" "$tmpdir" + else + # Remove any dirs left behind by ancient mkdir implementations. + rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null + fi + trap '' 0;; + esac;; + esac + + if + $posix_mkdir && ( + umask $mkdir_umask && + $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" + ) + then : + else + + # The umask is ridiculous, or mkdir does not conform to POSIX, + # or it failed possibly due to a race condition. Create the + # directory the slow way, step by step, checking for races as we go. + + case $dstdir in + /*) prefix='/';; + [-=\(\)!]*) prefix='./';; + *) prefix='';; + esac + + eval "$initialize_posix_glob" + + oIFS=$IFS + IFS=/ + $posix_glob set -f + set fnord $dstdir + shift + $posix_glob set +f + IFS=$oIFS + + prefixes= + + for d + do + test X"$d" = X && continue + + prefix=$prefix$d + if test -d "$prefix"; then + prefixes= + else + if $posix_mkdir; then + (umask=$mkdir_umask && + $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break + # Don't fail if two instances are running concurrently. + test -d "$prefix" || exit 1 + else + case $prefix in + *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; + *) qprefix=$prefix;; + esac + prefixes="$prefixes '$qprefix'" + fi + fi + prefix=$prefix/ + done + + if test -n "$prefixes"; then + # Don't fail if two instances are running concurrently. + (umask $mkdir_umask && + eval "\$doit_exec \$mkdirprog $prefixes") || + test -d "$dstdir" || exit 1 + obsolete_mkdir_used=true + fi + fi + fi + + if test -n "$dir_arg"; then + { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && + { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && + { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || + test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 + else + + # Make a couple of temp file names in the proper directory. + dsttmp=$dstdir/_inst.$$_ + rmtmp=$dstdir/_rm.$$_ + + # Trap to clean up those temp files at exit. + trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 + + # Copy the file name to the temp name. + (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") && + + # and set any options; do chmod last to preserve setuid bits. + # + # If any of these fail, we abort the whole thing. If we want to + # ignore errors from any of these, just make sure not to ignore + # errors from the above "$doit $cpprog $src $dsttmp" command. + # + { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && + { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && + { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && + { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && + + # If -C, don't bother to copy if it wouldn't change the file. + if $copy_on_change && + old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && + new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && + + eval "$initialize_posix_glob" && + $posix_glob set -f && + set X $old && old=:$2:$4:$5:$6 && + set X $new && new=:$2:$4:$5:$6 && + $posix_glob set +f && + + test "$old" = "$new" && + $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 + then + rm -f "$dsttmp" + else + # Rename the file to the real destination. + $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || + + # The rename failed, perhaps because mv can't rename something else + # to itself, or perhaps because mv is so ancient that it does not + # support -f. + { + # Now remove or move aside any old file at destination location. + # We try this two ways since rm can't unlink itself on some + # systems and the destination file might be busy for other + # reasons. In this case, the final cleanup might fail but the new + # file should still install successfully. + { + test ! -f "$dst" || + $doit $rmcmd -f "$dst" 2>/dev/null || + { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && + { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; } + } || + { echo "$0: cannot unlink or rename $dst" >&2 + (exit 1); exit 1 + } + } && + + # Now rename the file to the real destination. + $doit $mvcmd "$dsttmp" "$dst" + } + fi || exit 1 + + trap '' 0 + fi +done + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-time-zone: "UTC" +# time-stamp-end: "; # UTC" +# End: diff --git a/extern/portaudio/ltmain.sh b/extern/portaudio/ltmain.sh new file mode 100644 index 0000000..a356aca --- /dev/null +++ b/extern/portaudio/ltmain.sh @@ -0,0 +1,9661 @@ + +# libtool (GNU libtool) 2.4.2 +# Written by Gordon Matzigkeit , 1996 + +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006, +# 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc. +# This is free software; see the source for copying conditions. There is NO +# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +# GNU Libtool is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# As a special exception to the GNU General Public License, +# if you distribute this file as part of a program or library that +# is built using GNU Libtool, you may include this file under the +# same distribution terms that you use for the rest of that program. +# +# GNU Libtool is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Libtool; see the file COPYING. If not, a copy +# can be downloaded from http://www.gnu.org/licenses/gpl.html, +# or obtained by writing to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +# Usage: $progname [OPTION]... [MODE-ARG]... +# +# Provide generalized library-building support services. +# +# --config show all configuration variables +# --debug enable verbose shell tracing +# -n, --dry-run display commands without modifying any files +# --features display basic configuration information and exit +# --mode=MODE use operation mode MODE +# --preserve-dup-deps don't remove duplicate dependency libraries +# --quiet, --silent don't print informational messages +# --no-quiet, --no-silent +# print informational messages (default) +# --no-warn don't display warning messages +# --tag=TAG use configuration variables from tag TAG +# -v, --verbose print more informational messages than default +# --no-verbose don't print the extra informational messages +# --version print version information +# -h, --help, --help-all print short, long, or detailed help message +# +# MODE must be one of the following: +# +# clean remove files from the build directory +# compile compile a source file into a libtool object +# execute automatically set library path, then run a program +# finish complete the installation of libtool libraries +# install install libraries or executables +# link create a library or an executable +# uninstall remove libraries from an installed directory +# +# MODE-ARGS vary depending on the MODE. When passed as first option, +# `--mode=MODE' may be abbreviated as `MODE' or a unique abbreviation of that. +# Try `$progname --help --mode=MODE' for a more detailed description of MODE. +# +# When reporting a bug, please describe a test case to reproduce it and +# include the following information: +# +# host-triplet: $host +# shell: $SHELL +# compiler: $LTCC +# compiler flags: $LTCFLAGS +# linker: $LD (gnu? $with_gnu_ld) +# $progname: (GNU libtool) 2.4.2 Debian-2.4.2-1.7ubuntu1 +# automake: $automake_version +# autoconf: $autoconf_version +# +# Report bugs to . +# GNU libtool home page: . +# General help using GNU software: . + +PROGRAM=libtool +PACKAGE=libtool +VERSION="2.4.2 Debian-2.4.2-1.7ubuntu1" +TIMESTAMP="" +package_revision=1.3337 + +# Be Bourne compatible +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in *posix*) set -o posix;; esac +fi +BIN_SH=xpg4; export BIN_SH # for Tru64 +DUALCASE=1; export DUALCASE # for MKS sh + +# A function that is used when there is no print builtin or printf. +func_fallback_echo () +{ + eval 'cat <<_LTECHO_EOF +$1 +_LTECHO_EOF' +} + +# NLS nuisances: We save the old values to restore during execute mode. +lt_user_locale= +lt_safe_locale= +for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES +do + eval "if test \"\${$lt_var+set}\" = set; then + save_$lt_var=\$$lt_var + $lt_var=C + export $lt_var + lt_user_locale=\"$lt_var=\\\$save_\$lt_var; \$lt_user_locale\" + lt_safe_locale=\"$lt_var=C; \$lt_safe_locale\" + fi" +done +LC_ALL=C +LANGUAGE=C +export LANGUAGE LC_ALL + +$lt_unset CDPATH + + +# Work around backward compatibility issue on IRIX 6.5. On IRIX 6.4+, sh +# is ksh but when the shell is invoked as "sh" and the current value of +# the _XPG environment variable is not equal to 1 (one), the special +# positional parameter $0, within a function call, is the name of the +# function. +progpath="$0" + + + +: ${CP="cp -f"} +test "${ECHO+set}" = set || ECHO=${as_echo-'printf %s\n'} +: ${MAKE="make"} +: ${MKDIR="mkdir"} +: ${MV="mv -f"} +: ${RM="rm -f"} +: ${SHELL="${CONFIG_SHELL-/bin/sh}"} +: ${Xsed="$SED -e 1s/^X//"} + +# Global variables: +EXIT_SUCCESS=0 +EXIT_FAILURE=1 +EXIT_MISMATCH=63 # $? = 63 is used to indicate version mismatch to missing. +EXIT_SKIP=77 # $? = 77 is used to indicate a skipped test to automake. + +exit_status=$EXIT_SUCCESS + +# Make sure IFS has a sensible default +lt_nl=' +' +IFS=" $lt_nl" + +dirname="s,/[^/]*$,," +basename="s,^.*/,," + +# func_dirname file append nondir_replacement +# Compute the dirname of FILE. If nonempty, add APPEND to the result, +# otherwise set result to NONDIR_REPLACEMENT. +func_dirname () +{ + func_dirname_result=`$ECHO "${1}" | $SED "$dirname"` + if test "X$func_dirname_result" = "X${1}"; then + func_dirname_result="${3}" + else + func_dirname_result="$func_dirname_result${2}" + fi +} # func_dirname may be replaced by extended shell implementation + + +# func_basename file +func_basename () +{ + func_basename_result=`$ECHO "${1}" | $SED "$basename"` +} # func_basename may be replaced by extended shell implementation + + +# func_dirname_and_basename file append nondir_replacement +# perform func_basename and func_dirname in a single function +# call: +# dirname: Compute the dirname of FILE. If nonempty, +# add APPEND to the result, otherwise set result +# to NONDIR_REPLACEMENT. +# value returned in "$func_dirname_result" +# basename: Compute filename of FILE. +# value retuned in "$func_basename_result" +# Implementation must be kept synchronized with func_dirname +# and func_basename. For efficiency, we do not delegate to +# those functions but instead duplicate the functionality here. +func_dirname_and_basename () +{ + # Extract subdirectory from the argument. + func_dirname_result=`$ECHO "${1}" | $SED -e "$dirname"` + if test "X$func_dirname_result" = "X${1}"; then + func_dirname_result="${3}" + else + func_dirname_result="$func_dirname_result${2}" + fi + func_basename_result=`$ECHO "${1}" | $SED -e "$basename"` +} # func_dirname_and_basename may be replaced by extended shell implementation + + +# func_stripname prefix suffix name +# strip PREFIX and SUFFIX off of NAME. +# PREFIX and SUFFIX must not contain globbing or regex special +# characters, hashes, percent signs, but SUFFIX may contain a leading +# dot (in which case that matches only a dot). +# func_strip_suffix prefix name +func_stripname () +{ + case ${2} in + .*) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;; + *) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%${2}\$%%"`;; + esac +} # func_stripname may be replaced by extended shell implementation + + +# These SED scripts presuppose an absolute path with a trailing slash. +pathcar='s,^/\([^/]*\).*$,\1,' +pathcdr='s,^/[^/]*,,' +removedotparts=':dotsl + s@/\./@/@g + t dotsl + s,/\.$,/,' +collapseslashes='s@/\{1,\}@/@g' +finalslash='s,/*$,/,' + +# func_normal_abspath PATH +# Remove doubled-up and trailing slashes, "." path components, +# and cancel out any ".." path components in PATH after making +# it an absolute path. +# value returned in "$func_normal_abspath_result" +func_normal_abspath () +{ + # Start from root dir and reassemble the path. + func_normal_abspath_result= + func_normal_abspath_tpath=$1 + func_normal_abspath_altnamespace= + case $func_normal_abspath_tpath in + "") + # Empty path, that just means $cwd. + func_stripname '' '/' "`pwd`" + func_normal_abspath_result=$func_stripname_result + return + ;; + # The next three entries are used to spot a run of precisely + # two leading slashes without using negated character classes; + # we take advantage of case's first-match behaviour. + ///*) + # Unusual form of absolute path, do nothing. + ;; + //*) + # Not necessarily an ordinary path; POSIX reserves leading '//' + # and for example Cygwin uses it to access remote file shares + # over CIFS/SMB, so we conserve a leading double slash if found. + func_normal_abspath_altnamespace=/ + ;; + /*) + # Absolute path, do nothing. + ;; + *) + # Relative path, prepend $cwd. + func_normal_abspath_tpath=`pwd`/$func_normal_abspath_tpath + ;; + esac + # Cancel out all the simple stuff to save iterations. We also want + # the path to end with a slash for ease of parsing, so make sure + # there is one (and only one) here. + func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \ + -e "$removedotparts" -e "$collapseslashes" -e "$finalslash"` + while :; do + # Processed it all yet? + if test "$func_normal_abspath_tpath" = / ; then + # If we ascended to the root using ".." the result may be empty now. + if test -z "$func_normal_abspath_result" ; then + func_normal_abspath_result=/ + fi + break + fi + func_normal_abspath_tcomponent=`$ECHO "$func_normal_abspath_tpath" | $SED \ + -e "$pathcar"` + func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \ + -e "$pathcdr"` + # Figure out what to do with it + case $func_normal_abspath_tcomponent in + "") + # Trailing empty path component, ignore it. + ;; + ..) + # Parent dir; strip last assembled component from result. + func_dirname "$func_normal_abspath_result" + func_normal_abspath_result=$func_dirname_result + ;; + *) + # Actual path component, append it. + func_normal_abspath_result=$func_normal_abspath_result/$func_normal_abspath_tcomponent + ;; + esac + done + # Restore leading double-slash if one was found on entry. + func_normal_abspath_result=$func_normal_abspath_altnamespace$func_normal_abspath_result +} + +# func_relative_path SRCDIR DSTDIR +# generates a relative path from SRCDIR to DSTDIR, with a trailing +# slash if non-empty, suitable for immediately appending a filename +# without needing to append a separator. +# value returned in "$func_relative_path_result" +func_relative_path () +{ + func_relative_path_result= + func_normal_abspath "$1" + func_relative_path_tlibdir=$func_normal_abspath_result + func_normal_abspath "$2" + func_relative_path_tbindir=$func_normal_abspath_result + + # Ascend the tree starting from libdir + while :; do + # check if we have found a prefix of bindir + case $func_relative_path_tbindir in + $func_relative_path_tlibdir) + # found an exact match + func_relative_path_tcancelled= + break + ;; + $func_relative_path_tlibdir*) + # found a matching prefix + func_stripname "$func_relative_path_tlibdir" '' "$func_relative_path_tbindir" + func_relative_path_tcancelled=$func_stripname_result + if test -z "$func_relative_path_result"; then + func_relative_path_result=. + fi + break + ;; + *) + func_dirname $func_relative_path_tlibdir + func_relative_path_tlibdir=${func_dirname_result} + if test "x$func_relative_path_tlibdir" = x ; then + # Have to descend all the way to the root! + func_relative_path_result=../$func_relative_path_result + func_relative_path_tcancelled=$func_relative_path_tbindir + break + fi + func_relative_path_result=../$func_relative_path_result + ;; + esac + done + + # Now calculate path; take care to avoid doubling-up slashes. + func_stripname '' '/' "$func_relative_path_result" + func_relative_path_result=$func_stripname_result + func_stripname '/' '/' "$func_relative_path_tcancelled" + if test "x$func_stripname_result" != x ; then + func_relative_path_result=${func_relative_path_result}/${func_stripname_result} + fi + + # Normalisation. If bindir is libdir, return empty string, + # else relative path ending with a slash; either way, target + # file name can be directly appended. + if test ! -z "$func_relative_path_result"; then + func_stripname './' '' "$func_relative_path_result/" + func_relative_path_result=$func_stripname_result + fi +} + +# The name of this program: +func_dirname_and_basename "$progpath" +progname=$func_basename_result + +# Make sure we have an absolute path for reexecution: +case $progpath in + [\\/]*|[A-Za-z]:\\*) ;; + *[\\/]*) + progdir=$func_dirname_result + progdir=`cd "$progdir" && pwd` + progpath="$progdir/$progname" + ;; + *) + save_IFS="$IFS" + IFS=${PATH_SEPARATOR-:} + for progdir in $PATH; do + IFS="$save_IFS" + test -x "$progdir/$progname" && break + done + IFS="$save_IFS" + test -n "$progdir" || progdir=`pwd` + progpath="$progdir/$progname" + ;; +esac + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +Xsed="${SED}"' -e 1s/^X//' +sed_quote_subst='s/\([`"$\\]\)/\\\1/g' + +# Same as above, but do not quote variable references. +double_quote_subst='s/\(["`\\]\)/\\\1/g' + +# Sed substitution that turns a string into a regex matching for the +# string literally. +sed_make_literal_regex='s,[].[^$\\*\/],\\&,g' + +# Sed substitution that converts a w32 file name or path +# which contains forward slashes, into one that contains +# (escaped) backslashes. A very naive implementation. +lt_sed_naive_backslashify='s|\\\\*|\\|g;s|/|\\|g;s|\\|\\\\|g' + +# Re-`\' parameter expansions in output of double_quote_subst that were +# `\'-ed in input to the same. If an odd number of `\' preceded a '$' +# in input to double_quote_subst, that '$' was protected from expansion. +# Since each input `\' is now two `\'s, look for any number of runs of +# four `\'s followed by two `\'s and then a '$'. `\' that '$'. +bs='\\' +bs2='\\\\' +bs4='\\\\\\\\' +dollar='\$' +sed_double_backslash="\ + s/$bs4/&\\ +/g + s/^$bs2$dollar/$bs&/ + s/\\([^$bs]\\)$bs2$dollar/\\1$bs2$bs$dollar/g + s/\n//g" + +# Standard options: +opt_dry_run=false +opt_help=false +opt_quiet=false +opt_verbose=false +opt_warning=: + +# func_echo arg... +# Echo program name prefixed message, along with the current mode +# name if it has been set yet. +func_echo () +{ + $ECHO "$progname: ${opt_mode+$opt_mode: }$*" +} + +# func_verbose arg... +# Echo program name prefixed message in verbose mode only. +func_verbose () +{ + $opt_verbose && func_echo ${1+"$@"} + + # A bug in bash halts the script if the last line of a function + # fails when set -e is in force, so we need another command to + # work around that: + : +} + +# func_echo_all arg... +# Invoke $ECHO with all args, space-separated. +func_echo_all () +{ + $ECHO "$*" +} + +# func_error arg... +# Echo program name prefixed message to standard error. +func_error () +{ + $ECHO "$progname: ${opt_mode+$opt_mode: }"${1+"$@"} 1>&2 +} + +# func_warning arg... +# Echo program name prefixed warning message to standard error. +func_warning () +{ + $opt_warning && $ECHO "$progname: ${opt_mode+$opt_mode: }warning: "${1+"$@"} 1>&2 + + # bash bug again: + : +} + +# func_fatal_error arg... +# Echo program name prefixed message to standard error, and exit. +func_fatal_error () +{ + func_error ${1+"$@"} + exit $EXIT_FAILURE +} + +# func_fatal_help arg... +# Echo program name prefixed message to standard error, followed by +# a help hint, and exit. +func_fatal_help () +{ + func_error ${1+"$@"} + func_fatal_error "$help" +} +help="Try \`$progname --help' for more information." ## default + + +# func_grep expression filename +# Check whether EXPRESSION matches any line of FILENAME, without output. +func_grep () +{ + $GREP "$1" "$2" >/dev/null 2>&1 +} + + +# func_mkdir_p directory-path +# Make sure the entire path to DIRECTORY-PATH is available. +func_mkdir_p () +{ + my_directory_path="$1" + my_dir_list= + + if test -n "$my_directory_path" && test "$opt_dry_run" != ":"; then + + # Protect directory names starting with `-' + case $my_directory_path in + -*) my_directory_path="./$my_directory_path" ;; + esac + + # While some portion of DIR does not yet exist... + while test ! -d "$my_directory_path"; do + # ...make a list in topmost first order. Use a colon delimited + # list incase some portion of path contains whitespace. + my_dir_list="$my_directory_path:$my_dir_list" + + # If the last portion added has no slash in it, the list is done + case $my_directory_path in */*) ;; *) break ;; esac + + # ...otherwise throw away the child directory and loop + my_directory_path=`$ECHO "$my_directory_path" | $SED -e "$dirname"` + done + my_dir_list=`$ECHO "$my_dir_list" | $SED 's,:*$,,'` + + save_mkdir_p_IFS="$IFS"; IFS=':' + for my_dir in $my_dir_list; do + IFS="$save_mkdir_p_IFS" + # mkdir can fail with a `File exist' error if two processes + # try to create one of the directories concurrently. Don't + # stop in that case! + $MKDIR "$my_dir" 2>/dev/null || : + done + IFS="$save_mkdir_p_IFS" + + # Bail out if we (or some other process) failed to create a directory. + test -d "$my_directory_path" || \ + func_fatal_error "Failed to create \`$1'" + fi +} + + +# func_mktempdir [string] +# Make a temporary directory that won't clash with other running +# libtool processes, and avoids race conditions if possible. If +# given, STRING is the basename for that directory. +func_mktempdir () +{ + my_template="${TMPDIR-/tmp}/${1-$progname}" + + if test "$opt_dry_run" = ":"; then + # Return a directory name, but don't create it in dry-run mode + my_tmpdir="${my_template}-$$" + else + + # If mktemp works, use that first and foremost + my_tmpdir=`mktemp -d "${my_template}-XXXXXXXX" 2>/dev/null` + + if test ! -d "$my_tmpdir"; then + # Failing that, at least try and use $RANDOM to avoid a race + my_tmpdir="${my_template}-${RANDOM-0}$$" + + save_mktempdir_umask=`umask` + umask 0077 + $MKDIR "$my_tmpdir" + umask $save_mktempdir_umask + fi + + # If we're not in dry-run mode, bomb out on failure + test -d "$my_tmpdir" || \ + func_fatal_error "cannot create temporary directory \`$my_tmpdir'" + fi + + $ECHO "$my_tmpdir" +} + + +# func_quote_for_eval arg +# Aesthetically quote ARG to be evaled later. +# This function returns two values: FUNC_QUOTE_FOR_EVAL_RESULT +# is double-quoted, suitable for a subsequent eval, whereas +# FUNC_QUOTE_FOR_EVAL_UNQUOTED_RESULT has merely all characters +# which are still active within double quotes backslashified. +func_quote_for_eval () +{ + case $1 in + *[\\\`\"\$]*) + func_quote_for_eval_unquoted_result=`$ECHO "$1" | $SED "$sed_quote_subst"` ;; + *) + func_quote_for_eval_unquoted_result="$1" ;; + esac + + case $func_quote_for_eval_unquoted_result in + # Double-quote args containing shell metacharacters to delay + # word splitting, command substitution and and variable + # expansion for a subsequent eval. + # Many Bourne shells cannot handle close brackets correctly + # in scan sets, so we specify it separately. + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + func_quote_for_eval_result="\"$func_quote_for_eval_unquoted_result\"" + ;; + *) + func_quote_for_eval_result="$func_quote_for_eval_unquoted_result" + esac +} + + +# func_quote_for_expand arg +# Aesthetically quote ARG to be evaled later; same as above, +# but do not quote variable references. +func_quote_for_expand () +{ + case $1 in + *[\\\`\"]*) + my_arg=`$ECHO "$1" | $SED \ + -e "$double_quote_subst" -e "$sed_double_backslash"` ;; + *) + my_arg="$1" ;; + esac + + case $my_arg in + # Double-quote args containing shell metacharacters to delay + # word splitting and command substitution for a subsequent eval. + # Many Bourne shells cannot handle close brackets correctly + # in scan sets, so we specify it separately. + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + my_arg="\"$my_arg\"" + ;; + esac + + func_quote_for_expand_result="$my_arg" +} + + +# func_show_eval cmd [fail_exp] +# Unless opt_silent is true, then output CMD. Then, if opt_dryrun is +# not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP +# is given, then evaluate it. +func_show_eval () +{ + my_cmd="$1" + my_fail_exp="${2-:}" + + ${opt_silent-false} || { + func_quote_for_expand "$my_cmd" + eval "func_echo $func_quote_for_expand_result" + } + + if ${opt_dry_run-false}; then :; else + eval "$my_cmd" + my_status=$? + if test "$my_status" -eq 0; then :; else + eval "(exit $my_status); $my_fail_exp" + fi + fi +} + + +# func_show_eval_locale cmd [fail_exp] +# Unless opt_silent is true, then output CMD. Then, if opt_dryrun is +# not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP +# is given, then evaluate it. Use the saved locale for evaluation. +func_show_eval_locale () +{ + my_cmd="$1" + my_fail_exp="${2-:}" + + ${opt_silent-false} || { + func_quote_for_expand "$my_cmd" + eval "func_echo $func_quote_for_expand_result" + } + + if ${opt_dry_run-false}; then :; else + eval "$lt_user_locale + $my_cmd" + my_status=$? + eval "$lt_safe_locale" + if test "$my_status" -eq 0; then :; else + eval "(exit $my_status); $my_fail_exp" + fi + fi +} + +# func_tr_sh +# Turn $1 into a string suitable for a shell variable name. +# Result is stored in $func_tr_sh_result. All characters +# not in the set a-zA-Z0-9_ are replaced with '_'. Further, +# if $1 begins with a digit, a '_' is prepended as well. +func_tr_sh () +{ + case $1 in + [0-9]* | *[!a-zA-Z0-9_]*) + func_tr_sh_result=`$ECHO "$1" | $SED 's/^\([0-9]\)/_\1/; s/[^a-zA-Z0-9_]/_/g'` + ;; + * ) + func_tr_sh_result=$1 + ;; + esac +} + + +# func_version +# Echo version message to standard output and exit. +func_version () +{ + $opt_debug + + $SED -n '/(C)/!b go + :more + /\./!{ + N + s/\n# / / + b more + } + :go + /^# '$PROGRAM' (GNU /,/# warranty; / { + s/^# // + s/^# *$// + s/\((C)\)[ 0-9,-]*\( [1-9][0-9]*\)/\1\2/ + p + }' < "$progpath" + exit $? +} + +# func_usage +# Echo short help message to standard output and exit. +func_usage () +{ + $opt_debug + + $SED -n '/^# Usage:/,/^# *.*--help/ { + s/^# // + s/^# *$// + s/\$progname/'$progname'/ + p + }' < "$progpath" + echo + $ECHO "run \`$progname --help | more' for full usage" + exit $? +} + +# func_help [NOEXIT] +# Echo long help message to standard output and exit, +# unless 'noexit' is passed as argument. +func_help () +{ + $opt_debug + + $SED -n '/^# Usage:/,/# Report bugs to/ { + :print + s/^# // + s/^# *$// + s*\$progname*'$progname'* + s*\$host*'"$host"'* + s*\$SHELL*'"$SHELL"'* + s*\$LTCC*'"$LTCC"'* + s*\$LTCFLAGS*'"$LTCFLAGS"'* + s*\$LD*'"$LD"'* + s/\$with_gnu_ld/'"$with_gnu_ld"'/ + s/\$automake_version/'"`(${AUTOMAKE-automake} --version) 2>/dev/null |$SED 1q`"'/ + s/\$autoconf_version/'"`(${AUTOCONF-autoconf} --version) 2>/dev/null |$SED 1q`"'/ + p + d + } + /^# .* home page:/b print + /^# General help using/b print + ' < "$progpath" + ret=$? + if test -z "$1"; then + exit $ret + fi +} + +# func_missing_arg argname +# Echo program name prefixed message to standard error and set global +# exit_cmd. +func_missing_arg () +{ + $opt_debug + + func_error "missing argument for $1." + exit_cmd=exit +} + + +# func_split_short_opt shortopt +# Set func_split_short_opt_name and func_split_short_opt_arg shell +# variables after splitting SHORTOPT after the 2nd character. +func_split_short_opt () +{ + my_sed_short_opt='1s/^\(..\).*$/\1/;q' + my_sed_short_rest='1s/^..\(.*\)$/\1/;q' + + func_split_short_opt_name=`$ECHO "$1" | $SED "$my_sed_short_opt"` + func_split_short_opt_arg=`$ECHO "$1" | $SED "$my_sed_short_rest"` +} # func_split_short_opt may be replaced by extended shell implementation + + +# func_split_long_opt longopt +# Set func_split_long_opt_name and func_split_long_opt_arg shell +# variables after splitting LONGOPT at the `=' sign. +func_split_long_opt () +{ + my_sed_long_opt='1s/^\(--[^=]*\)=.*/\1/;q' + my_sed_long_arg='1s/^--[^=]*=//' + + func_split_long_opt_name=`$ECHO "$1" | $SED "$my_sed_long_opt"` + func_split_long_opt_arg=`$ECHO "$1" | $SED "$my_sed_long_arg"` +} # func_split_long_opt may be replaced by extended shell implementation + +exit_cmd=: + + + + + +magic="%%%MAGIC variable%%%" +magic_exe="%%%MAGIC EXE variable%%%" + +# Global variables. +nonopt= +preserve_args= +lo2o="s/\\.lo\$/.${objext}/" +o2lo="s/\\.${objext}\$/.lo/" +extracted_archives= +extracted_serial=0 + +# If this variable is set in any of the actions, the command in it +# will be execed at the end. This prevents here-documents from being +# left over by shells. +exec_cmd= + +# func_append var value +# Append VALUE to the end of shell variable VAR. +func_append () +{ + eval "${1}=\$${1}\${2}" +} # func_append may be replaced by extended shell implementation + +# func_append_quoted var value +# Quote VALUE and append to the end of shell variable VAR, separated +# by a space. +func_append_quoted () +{ + func_quote_for_eval "${2}" + eval "${1}=\$${1}\\ \$func_quote_for_eval_result" +} # func_append_quoted may be replaced by extended shell implementation + + +# func_arith arithmetic-term... +func_arith () +{ + func_arith_result=`expr "${@}"` +} # func_arith may be replaced by extended shell implementation + + +# func_len string +# STRING may not start with a hyphen. +func_len () +{ + func_len_result=`expr "${1}" : ".*" 2>/dev/null || echo $max_cmd_len` +} # func_len may be replaced by extended shell implementation + + +# func_lo2o object +func_lo2o () +{ + func_lo2o_result=`$ECHO "${1}" | $SED "$lo2o"` +} # func_lo2o may be replaced by extended shell implementation + + +# func_xform libobj-or-source +func_xform () +{ + func_xform_result=`$ECHO "${1}" | $SED 's/\.[^.]*$/.lo/'` +} # func_xform may be replaced by extended shell implementation + + +# func_fatal_configuration arg... +# Echo program name prefixed message to standard error, followed by +# a configuration failure hint, and exit. +func_fatal_configuration () +{ + func_error ${1+"$@"} + func_error "See the $PACKAGE documentation for more information." + func_fatal_error "Fatal configuration error." +} + + +# func_config +# Display the configuration for all the tags in this script. +func_config () +{ + re_begincf='^# ### BEGIN LIBTOOL' + re_endcf='^# ### END LIBTOOL' + + # Default configuration. + $SED "1,/$re_begincf CONFIG/d;/$re_endcf CONFIG/,\$d" < "$progpath" + + # Now print the configurations for the tags. + for tagname in $taglist; do + $SED -n "/$re_begincf TAG CONFIG: $tagname\$/,/$re_endcf TAG CONFIG: $tagname\$/p" < "$progpath" + done + + exit $? +} + +# func_features +# Display the features supported by this script. +func_features () +{ + echo "host: $host" + if test "$build_libtool_libs" = yes; then + echo "enable shared libraries" + else + echo "disable shared libraries" + fi + if test "$build_old_libs" = yes; then + echo "enable static libraries" + else + echo "disable static libraries" + fi + + exit $? +} + +# func_enable_tag tagname +# Verify that TAGNAME is valid, and either flag an error and exit, or +# enable the TAGNAME tag. We also add TAGNAME to the global $taglist +# variable here. +func_enable_tag () +{ + # Global variable: + tagname="$1" + + re_begincf="^# ### BEGIN LIBTOOL TAG CONFIG: $tagname\$" + re_endcf="^# ### END LIBTOOL TAG CONFIG: $tagname\$" + sed_extractcf="/$re_begincf/,/$re_endcf/p" + + # Validate tagname. + case $tagname in + *[!-_A-Za-z0-9,/]*) + func_fatal_error "invalid tag name: $tagname" + ;; + esac + + # Don't test for the "default" C tag, as we know it's + # there but not specially marked. + case $tagname in + CC) ;; + *) + if $GREP "$re_begincf" "$progpath" >/dev/null 2>&1; then + taglist="$taglist $tagname" + + # Evaluate the configuration. Be careful to quote the path + # and the sed script, to avoid splitting on whitespace, but + # also don't use non-portable quotes within backquotes within + # quotes we have to do it in 2 steps: + extractedcf=`$SED -n -e "$sed_extractcf" < "$progpath"` + eval "$extractedcf" + else + func_error "ignoring unknown tag $tagname" + fi + ;; + esac +} + +# func_check_version_match +# Ensure that we are using m4 macros, and libtool script from the same +# release of libtool. +func_check_version_match () +{ + if test "$package_revision" != "$macro_revision"; then + if test "$VERSION" != "$macro_version"; then + if test -z "$macro_version"; then + cat >&2 <<_LT_EOF +$progname: Version mismatch error. This is $PACKAGE $VERSION, but the +$progname: definition of this LT_INIT comes from an older release. +$progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION +$progname: and run autoconf again. +_LT_EOF + else + cat >&2 <<_LT_EOF +$progname: Version mismatch error. This is $PACKAGE $VERSION, but the +$progname: definition of this LT_INIT comes from $PACKAGE $macro_version. +$progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION +$progname: and run autoconf again. +_LT_EOF + fi + else + cat >&2 <<_LT_EOF +$progname: Version mismatch error. This is $PACKAGE $VERSION, revision $package_revision, +$progname: but the definition of this LT_INIT comes from revision $macro_revision. +$progname: You should recreate aclocal.m4 with macros from revision $package_revision +$progname: of $PACKAGE $VERSION and run autoconf again. +_LT_EOF + fi + + exit $EXIT_MISMATCH + fi +} + + +# Shorthand for --mode=foo, only valid as the first argument +case $1 in +clean|clea|cle|cl) + shift; set dummy --mode clean ${1+"$@"}; shift + ;; +compile|compil|compi|comp|com|co|c) + shift; set dummy --mode compile ${1+"$@"}; shift + ;; +execute|execut|execu|exec|exe|ex|e) + shift; set dummy --mode execute ${1+"$@"}; shift + ;; +finish|finis|fini|fin|fi|f) + shift; set dummy --mode finish ${1+"$@"}; shift + ;; +install|instal|insta|inst|ins|in|i) + shift; set dummy --mode install ${1+"$@"}; shift + ;; +link|lin|li|l) + shift; set dummy --mode link ${1+"$@"}; shift + ;; +uninstall|uninstal|uninsta|uninst|unins|unin|uni|un|u) + shift; set dummy --mode uninstall ${1+"$@"}; shift + ;; +esac + + + +# Option defaults: +opt_debug=: +opt_dry_run=false +opt_config=false +opt_preserve_dup_deps=false +opt_features=false +opt_finish=false +opt_help=false +opt_help_all=false +opt_silent=: +opt_warning=: +opt_verbose=: +opt_silent=false +opt_verbose=false + + +# Parse options once, thoroughly. This comes as soon as possible in the +# script to make things like `--version' happen as quickly as we can. +{ + # this just eases exit handling + while test $# -gt 0; do + opt="$1" + shift + case $opt in + --debug|-x) opt_debug='set -x' + func_echo "enabling shell trace mode" + $opt_debug + ;; + --dry-run|--dryrun|-n) + opt_dry_run=: + ;; + --config) + opt_config=: +func_config + ;; + --dlopen|-dlopen) + optarg="$1" + opt_dlopen="${opt_dlopen+$opt_dlopen +}$optarg" + shift + ;; + --preserve-dup-deps) + opt_preserve_dup_deps=: + ;; + --features) + opt_features=: +func_features + ;; + --finish) + opt_finish=: +set dummy --mode finish ${1+"$@"}; shift + ;; + --help) + opt_help=: + ;; + --help-all) + opt_help_all=: +opt_help=': help-all' + ;; + --mode) + test $# = 0 && func_missing_arg $opt && break + optarg="$1" + opt_mode="$optarg" +case $optarg in + # Valid mode arguments: + clean|compile|execute|finish|install|link|relink|uninstall) ;; + + # Catch anything else as an error + *) func_error "invalid argument for $opt" + exit_cmd=exit + break + ;; +esac + shift + ;; + --no-silent|--no-quiet) + opt_silent=false +func_append preserve_args " $opt" + ;; + --no-warning|--no-warn) + opt_warning=false +func_append preserve_args " $opt" + ;; + --no-verbose) + opt_verbose=false +func_append preserve_args " $opt" + ;; + --silent|--quiet) + opt_silent=: +func_append preserve_args " $opt" + opt_verbose=false + ;; + --verbose|-v) + opt_verbose=: +func_append preserve_args " $opt" +opt_silent=false + ;; + --tag) + test $# = 0 && func_missing_arg $opt && break + optarg="$1" + opt_tag="$optarg" +func_append preserve_args " $opt $optarg" +func_enable_tag "$optarg" + shift + ;; + + -\?|-h) func_usage ;; + --help) func_help ;; + --version) func_version ;; + + # Separate optargs to long options: + --*=*) + func_split_long_opt "$opt" + set dummy "$func_split_long_opt_name" "$func_split_long_opt_arg" ${1+"$@"} + shift + ;; + + # Separate non-argument short options: + -\?*|-h*|-n*|-v*) + func_split_short_opt "$opt" + set dummy "$func_split_short_opt_name" "-$func_split_short_opt_arg" ${1+"$@"} + shift + ;; + + --) break ;; + -*) func_fatal_help "unrecognized option \`$opt'" ;; + *) set dummy "$opt" ${1+"$@"}; shift; break ;; + esac + done + + # Validate options: + + # save first non-option argument + if test "$#" -gt 0; then + nonopt="$opt" + shift + fi + + # preserve --debug + test "$opt_debug" = : || func_append preserve_args " --debug" + + case $host in + *cygwin* | *mingw* | *pw32* | *cegcc*) + # don't eliminate duplications in $postdeps and $predeps + opt_duplicate_compiler_generated_deps=: + ;; + *) + opt_duplicate_compiler_generated_deps=$opt_preserve_dup_deps + ;; + esac + + $opt_help || { + # Sanity checks first: + func_check_version_match + + if test "$build_libtool_libs" != yes && test "$build_old_libs" != yes; then + func_fatal_configuration "not configured to build any kind of library" + fi + + # Darwin sucks + eval std_shrext=\"$shrext_cmds\" + + # Only execute mode is allowed to have -dlopen flags. + if test -n "$opt_dlopen" && test "$opt_mode" != execute; then + func_error "unrecognized option \`-dlopen'" + $ECHO "$help" 1>&2 + exit $EXIT_FAILURE + fi + + # Change the help message to a mode-specific one. + generic_help="$help" + help="Try \`$progname --help --mode=$opt_mode' for more information." + } + + + # Bail if the options were screwed + $exit_cmd $EXIT_FAILURE +} + + + + +## ----------- ## +## Main. ## +## ----------- ## + +# func_lalib_p file +# True iff FILE is a libtool `.la' library or `.lo' object file. +# This function is only a basic sanity check; it will hardly flush out +# determined imposters. +func_lalib_p () +{ + test -f "$1" && + $SED -e 4q "$1" 2>/dev/null \ + | $GREP "^# Generated by .*$PACKAGE" > /dev/null 2>&1 +} + +# func_lalib_unsafe_p file +# True iff FILE is a libtool `.la' library or `.lo' object file. +# This function implements the same check as func_lalib_p without +# resorting to external programs. To this end, it redirects stdin and +# closes it afterwards, without saving the original file descriptor. +# As a safety measure, use it only where a negative result would be +# fatal anyway. Works if `file' does not exist. +func_lalib_unsafe_p () +{ + lalib_p=no + if test -f "$1" && test -r "$1" && exec 5<&0 <"$1"; then + for lalib_p_l in 1 2 3 4 + do + read lalib_p_line + case "$lalib_p_line" in + \#\ Generated\ by\ *$PACKAGE* ) lalib_p=yes; break;; + esac + done + exec 0<&5 5<&- + fi + test "$lalib_p" = yes +} + +# func_ltwrapper_script_p file +# True iff FILE is a libtool wrapper script +# This function is only a basic sanity check; it will hardly flush out +# determined imposters. +func_ltwrapper_script_p () +{ + func_lalib_p "$1" +} + +# func_ltwrapper_executable_p file +# True iff FILE is a libtool wrapper executable +# This function is only a basic sanity check; it will hardly flush out +# determined imposters. +func_ltwrapper_executable_p () +{ + func_ltwrapper_exec_suffix= + case $1 in + *.exe) ;; + *) func_ltwrapper_exec_suffix=.exe ;; + esac + $GREP "$magic_exe" "$1$func_ltwrapper_exec_suffix" >/dev/null 2>&1 +} + +# func_ltwrapper_scriptname file +# Assumes file is an ltwrapper_executable +# uses $file to determine the appropriate filename for a +# temporary ltwrapper_script. +func_ltwrapper_scriptname () +{ + func_dirname_and_basename "$1" "" "." + func_stripname '' '.exe' "$func_basename_result" + func_ltwrapper_scriptname_result="$func_dirname_result/$objdir/${func_stripname_result}_ltshwrapper" +} + +# func_ltwrapper_p file +# True iff FILE is a libtool wrapper script or wrapper executable +# This function is only a basic sanity check; it will hardly flush out +# determined imposters. +func_ltwrapper_p () +{ + func_ltwrapper_script_p "$1" || func_ltwrapper_executable_p "$1" +} + + +# func_execute_cmds commands fail_cmd +# Execute tilde-delimited COMMANDS. +# If FAIL_CMD is given, eval that upon failure. +# FAIL_CMD may read-access the current command in variable CMD! +func_execute_cmds () +{ + $opt_debug + save_ifs=$IFS; IFS='~' + for cmd in $1; do + IFS=$save_ifs + eval cmd=\"$cmd\" + func_show_eval "$cmd" "${2-:}" + done + IFS=$save_ifs +} + + +# func_source file +# Source FILE, adding directory component if necessary. +# Note that it is not necessary on cygwin/mingw to append a dot to +# FILE even if both FILE and FILE.exe exist: automatic-append-.exe +# behavior happens only for exec(3), not for open(2)! Also, sourcing +# `FILE.' does not work on cygwin managed mounts. +func_source () +{ + $opt_debug + case $1 in + */* | *\\*) . "$1" ;; + *) . "./$1" ;; + esac +} + + +# func_resolve_sysroot PATH +# Replace a leading = in PATH with a sysroot. Store the result into +# func_resolve_sysroot_result +func_resolve_sysroot () +{ + func_resolve_sysroot_result=$1 + case $func_resolve_sysroot_result in + =*) + func_stripname '=' '' "$func_resolve_sysroot_result" + func_resolve_sysroot_result=$lt_sysroot$func_stripname_result + ;; + esac +} + +# func_replace_sysroot PATH +# If PATH begins with the sysroot, replace it with = and +# store the result into func_replace_sysroot_result. +func_replace_sysroot () +{ + case "$lt_sysroot:$1" in + ?*:"$lt_sysroot"*) + func_stripname "$lt_sysroot" '' "$1" + func_replace_sysroot_result="=$func_stripname_result" + ;; + *) + # Including no sysroot. + func_replace_sysroot_result=$1 + ;; + esac +} + +# func_infer_tag arg +# Infer tagged configuration to use if any are available and +# if one wasn't chosen via the "--tag" command line option. +# Only attempt this if the compiler in the base compile +# command doesn't match the default compiler. +# arg is usually of the form 'gcc ...' +func_infer_tag () +{ + $opt_debug + if test -n "$available_tags" && test -z "$tagname"; then + CC_quoted= + for arg in $CC; do + func_append_quoted CC_quoted "$arg" + done + CC_expanded=`func_echo_all $CC` + CC_quoted_expanded=`func_echo_all $CC_quoted` + case $@ in + # Blanks in the command may have been stripped by the calling shell, + # but not from the CC environment variable when configure was run. + " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \ + " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*) ;; + # Blanks at the start of $base_compile will cause this to fail + # if we don't check for them as well. + *) + for z in $available_tags; do + if $GREP "^# ### BEGIN LIBTOOL TAG CONFIG: $z$" < "$progpath" > /dev/null; then + # Evaluate the configuration. + eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^# ### END LIBTOOL TAG CONFIG: '$z'$/p' < $progpath`" + CC_quoted= + for arg in $CC; do + # Double-quote args containing other shell metacharacters. + func_append_quoted CC_quoted "$arg" + done + CC_expanded=`func_echo_all $CC` + CC_quoted_expanded=`func_echo_all $CC_quoted` + case "$@ " in + " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \ + " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*) + # The compiler in the base compile command matches + # the one in the tagged configuration. + # Assume this is the tagged configuration we want. + tagname=$z + break + ;; + esac + fi + done + # If $tagname still isn't set, then no tagged configuration + # was found and let the user know that the "--tag" command + # line option must be used. + if test -z "$tagname"; then + func_echo "unable to infer tagged configuration" + func_fatal_error "specify a tag with \`--tag'" +# else +# func_verbose "using $tagname tagged configuration" + fi + ;; + esac + fi +} + + + +# func_write_libtool_object output_name pic_name nonpic_name +# Create a libtool object file (analogous to a ".la" file), +# but don't create it if we're doing a dry run. +func_write_libtool_object () +{ + write_libobj=${1} + if test "$build_libtool_libs" = yes; then + write_lobj=\'${2}\' + else + write_lobj=none + fi + + if test "$build_old_libs" = yes; then + write_oldobj=\'${3}\' + else + write_oldobj=none + fi + + $opt_dry_run || { + cat >${write_libobj}T </dev/null` + if test "$?" -eq 0 && test -n "${func_convert_core_file_wine_to_w32_tmp}"; then + func_convert_core_file_wine_to_w32_result=`$ECHO "$func_convert_core_file_wine_to_w32_tmp" | + $SED -e "$lt_sed_naive_backslashify"` + else + func_convert_core_file_wine_to_w32_result= + fi + fi +} +# end: func_convert_core_file_wine_to_w32 + + +# func_convert_core_path_wine_to_w32 ARG +# Helper function used by path conversion functions when $build is *nix, and +# $host is mingw, cygwin, or some other w32 environment. Relies on a correctly +# configured wine environment available, with the winepath program in $build's +# $PATH. Assumes ARG has no leading or trailing path separator characters. +# +# ARG is path to be converted from $build format to win32. +# Result is available in $func_convert_core_path_wine_to_w32_result. +# Unconvertible file (directory) names in ARG are skipped; if no directory names +# are convertible, then the result may be empty. +func_convert_core_path_wine_to_w32 () +{ + $opt_debug + # unfortunately, winepath doesn't convert paths, only file names + func_convert_core_path_wine_to_w32_result="" + if test -n "$1"; then + oldIFS=$IFS + IFS=: + for func_convert_core_path_wine_to_w32_f in $1; do + IFS=$oldIFS + func_convert_core_file_wine_to_w32 "$func_convert_core_path_wine_to_w32_f" + if test -n "$func_convert_core_file_wine_to_w32_result" ; then + if test -z "$func_convert_core_path_wine_to_w32_result"; then + func_convert_core_path_wine_to_w32_result="$func_convert_core_file_wine_to_w32_result" + else + func_append func_convert_core_path_wine_to_w32_result ";$func_convert_core_file_wine_to_w32_result" + fi + fi + done + IFS=$oldIFS + fi +} +# end: func_convert_core_path_wine_to_w32 + + +# func_cygpath ARGS... +# Wrapper around calling the cygpath program via LT_CYGPATH. This is used when +# when (1) $build is *nix and Cygwin is hosted via a wine environment; or (2) +# $build is MSYS and $host is Cygwin, or (3) $build is Cygwin. In case (1) or +# (2), returns the Cygwin file name or path in func_cygpath_result (input +# file name or path is assumed to be in w32 format, as previously converted +# from $build's *nix or MSYS format). In case (3), returns the w32 file name +# or path in func_cygpath_result (input file name or path is assumed to be in +# Cygwin format). Returns an empty string on error. +# +# ARGS are passed to cygpath, with the last one being the file name or path to +# be converted. +# +# Specify the absolute *nix (or w32) name to cygpath in the LT_CYGPATH +# environment variable; do not put it in $PATH. +func_cygpath () +{ + $opt_debug + if test -n "$LT_CYGPATH" && test -f "$LT_CYGPATH"; then + func_cygpath_result=`$LT_CYGPATH "$@" 2>/dev/null` + if test "$?" -ne 0; then + # on failure, ensure result is empty + func_cygpath_result= + fi + else + func_cygpath_result= + func_error "LT_CYGPATH is empty or specifies non-existent file: \`$LT_CYGPATH'" + fi +} +#end: func_cygpath + + +# func_convert_core_msys_to_w32 ARG +# Convert file name or path ARG from MSYS format to w32 format. Return +# result in func_convert_core_msys_to_w32_result. +func_convert_core_msys_to_w32 () +{ + $opt_debug + # awkward: cmd appends spaces to result + func_convert_core_msys_to_w32_result=`( cmd //c echo "$1" ) 2>/dev/null | + $SED -e 's/[ ]*$//' -e "$lt_sed_naive_backslashify"` +} +#end: func_convert_core_msys_to_w32 + + +# func_convert_file_check ARG1 ARG2 +# Verify that ARG1 (a file name in $build format) was converted to $host +# format in ARG2. Otherwise, emit an error message, but continue (resetting +# func_to_host_file_result to ARG1). +func_convert_file_check () +{ + $opt_debug + if test -z "$2" && test -n "$1" ; then + func_error "Could not determine host file name corresponding to" + func_error " \`$1'" + func_error "Continuing, but uninstalled executables may not work." + # Fallback: + func_to_host_file_result="$1" + fi +} +# end func_convert_file_check + + +# func_convert_path_check FROM_PATHSEP TO_PATHSEP FROM_PATH TO_PATH +# Verify that FROM_PATH (a path in $build format) was converted to $host +# format in TO_PATH. Otherwise, emit an error message, but continue, resetting +# func_to_host_file_result to a simplistic fallback value (see below). +func_convert_path_check () +{ + $opt_debug + if test -z "$4" && test -n "$3"; then + func_error "Could not determine the host path corresponding to" + func_error " \`$3'" + func_error "Continuing, but uninstalled executables may not work." + # Fallback. This is a deliberately simplistic "conversion" and + # should not be "improved". See libtool.info. + if test "x$1" != "x$2"; then + lt_replace_pathsep_chars="s|$1|$2|g" + func_to_host_path_result=`echo "$3" | + $SED -e "$lt_replace_pathsep_chars"` + else + func_to_host_path_result="$3" + fi + fi +} +# end func_convert_path_check + + +# func_convert_path_front_back_pathsep FRONTPAT BACKPAT REPL ORIG +# Modifies func_to_host_path_result by prepending REPL if ORIG matches FRONTPAT +# and appending REPL if ORIG matches BACKPAT. +func_convert_path_front_back_pathsep () +{ + $opt_debug + case $4 in + $1 ) func_to_host_path_result="$3$func_to_host_path_result" + ;; + esac + case $4 in + $2 ) func_append func_to_host_path_result "$3" + ;; + esac +} +# end func_convert_path_front_back_pathsep + + +################################################## +# $build to $host FILE NAME CONVERSION FUNCTIONS # +################################################## +# invoked via `$to_host_file_cmd ARG' +# +# In each case, ARG is the path to be converted from $build to $host format. +# Result will be available in $func_to_host_file_result. + + +# func_to_host_file ARG +# Converts the file name ARG from $build format to $host format. Return result +# in func_to_host_file_result. +func_to_host_file () +{ + $opt_debug + $to_host_file_cmd "$1" +} +# end func_to_host_file + + +# func_to_tool_file ARG LAZY +# converts the file name ARG from $build format to toolchain format. Return +# result in func_to_tool_file_result. If the conversion in use is listed +# in (the comma separated) LAZY, no conversion takes place. +func_to_tool_file () +{ + $opt_debug + case ,$2, in + *,"$to_tool_file_cmd",*) + func_to_tool_file_result=$1 + ;; + *) + $to_tool_file_cmd "$1" + func_to_tool_file_result=$func_to_host_file_result + ;; + esac +} +# end func_to_tool_file + + +# func_convert_file_noop ARG +# Copy ARG to func_to_host_file_result. +func_convert_file_noop () +{ + func_to_host_file_result="$1" +} +# end func_convert_file_noop + + +# func_convert_file_msys_to_w32 ARG +# Convert file name ARG from (mingw) MSYS to (mingw) w32 format; automatic +# conversion to w32 is not available inside the cwrapper. Returns result in +# func_to_host_file_result. +func_convert_file_msys_to_w32 () +{ + $opt_debug + func_to_host_file_result="$1" + if test -n "$1"; then + func_convert_core_msys_to_w32 "$1" + func_to_host_file_result="$func_convert_core_msys_to_w32_result" + fi + func_convert_file_check "$1" "$func_to_host_file_result" +} +# end func_convert_file_msys_to_w32 + + +# func_convert_file_cygwin_to_w32 ARG +# Convert file name ARG from Cygwin to w32 format. Returns result in +# func_to_host_file_result. +func_convert_file_cygwin_to_w32 () +{ + $opt_debug + func_to_host_file_result="$1" + if test -n "$1"; then + # because $build is cygwin, we call "the" cygpath in $PATH; no need to use + # LT_CYGPATH in this case. + func_to_host_file_result=`cygpath -m "$1"` + fi + func_convert_file_check "$1" "$func_to_host_file_result" +} +# end func_convert_file_cygwin_to_w32 + + +# func_convert_file_nix_to_w32 ARG +# Convert file name ARG from *nix to w32 format. Requires a wine environment +# and a working winepath. Returns result in func_to_host_file_result. +func_convert_file_nix_to_w32 () +{ + $opt_debug + func_to_host_file_result="$1" + if test -n "$1"; then + func_convert_core_file_wine_to_w32 "$1" + func_to_host_file_result="$func_convert_core_file_wine_to_w32_result" + fi + func_convert_file_check "$1" "$func_to_host_file_result" +} +# end func_convert_file_nix_to_w32 + + +# func_convert_file_msys_to_cygwin ARG +# Convert file name ARG from MSYS to Cygwin format. Requires LT_CYGPATH set. +# Returns result in func_to_host_file_result. +func_convert_file_msys_to_cygwin () +{ + $opt_debug + func_to_host_file_result="$1" + if test -n "$1"; then + func_convert_core_msys_to_w32 "$1" + func_cygpath -u "$func_convert_core_msys_to_w32_result" + func_to_host_file_result="$func_cygpath_result" + fi + func_convert_file_check "$1" "$func_to_host_file_result" +} +# end func_convert_file_msys_to_cygwin + + +# func_convert_file_nix_to_cygwin ARG +# Convert file name ARG from *nix to Cygwin format. Requires Cygwin installed +# in a wine environment, working winepath, and LT_CYGPATH set. Returns result +# in func_to_host_file_result. +func_convert_file_nix_to_cygwin () +{ + $opt_debug + func_to_host_file_result="$1" + if test -n "$1"; then + # convert from *nix to w32, then use cygpath to convert from w32 to cygwin. + func_convert_core_file_wine_to_w32 "$1" + func_cygpath -u "$func_convert_core_file_wine_to_w32_result" + func_to_host_file_result="$func_cygpath_result" + fi + func_convert_file_check "$1" "$func_to_host_file_result" +} +# end func_convert_file_nix_to_cygwin + + +############################################# +# $build to $host PATH CONVERSION FUNCTIONS # +############################################# +# invoked via `$to_host_path_cmd ARG' +# +# In each case, ARG is the path to be converted from $build to $host format. +# The result will be available in $func_to_host_path_result. +# +# Path separators are also converted from $build format to $host format. If +# ARG begins or ends with a path separator character, it is preserved (but +# converted to $host format) on output. +# +# All path conversion functions are named using the following convention: +# file name conversion function : func_convert_file_X_to_Y () +# path conversion function : func_convert_path_X_to_Y () +# where, for any given $build/$host combination the 'X_to_Y' value is the +# same. If conversion functions are added for new $build/$host combinations, +# the two new functions must follow this pattern, or func_init_to_host_path_cmd +# will break. + + +# func_init_to_host_path_cmd +# Ensures that function "pointer" variable $to_host_path_cmd is set to the +# appropriate value, based on the value of $to_host_file_cmd. +to_host_path_cmd= +func_init_to_host_path_cmd () +{ + $opt_debug + if test -z "$to_host_path_cmd"; then + func_stripname 'func_convert_file_' '' "$to_host_file_cmd" + to_host_path_cmd="func_convert_path_${func_stripname_result}" + fi +} + + +# func_to_host_path ARG +# Converts the path ARG from $build format to $host format. Return result +# in func_to_host_path_result. +func_to_host_path () +{ + $opt_debug + func_init_to_host_path_cmd + $to_host_path_cmd "$1" +} +# end func_to_host_path + + +# func_convert_path_noop ARG +# Copy ARG to func_to_host_path_result. +func_convert_path_noop () +{ + func_to_host_path_result="$1" +} +# end func_convert_path_noop + + +# func_convert_path_msys_to_w32 ARG +# Convert path ARG from (mingw) MSYS to (mingw) w32 format; automatic +# conversion to w32 is not available inside the cwrapper. Returns result in +# func_to_host_path_result. +func_convert_path_msys_to_w32 () +{ + $opt_debug + func_to_host_path_result="$1" + if test -n "$1"; then + # Remove leading and trailing path separator characters from ARG. MSYS + # behavior is inconsistent here; cygpath turns them into '.;' and ';.'; + # and winepath ignores them completely. + func_stripname : : "$1" + func_to_host_path_tmp1=$func_stripname_result + func_convert_core_msys_to_w32 "$func_to_host_path_tmp1" + func_to_host_path_result="$func_convert_core_msys_to_w32_result" + func_convert_path_check : ";" \ + "$func_to_host_path_tmp1" "$func_to_host_path_result" + func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" + fi +} +# end func_convert_path_msys_to_w32 + + +# func_convert_path_cygwin_to_w32 ARG +# Convert path ARG from Cygwin to w32 format. Returns result in +# func_to_host_file_result. +func_convert_path_cygwin_to_w32 () +{ + $opt_debug + func_to_host_path_result="$1" + if test -n "$1"; then + # See func_convert_path_msys_to_w32: + func_stripname : : "$1" + func_to_host_path_tmp1=$func_stripname_result + func_to_host_path_result=`cygpath -m -p "$func_to_host_path_tmp1"` + func_convert_path_check : ";" \ + "$func_to_host_path_tmp1" "$func_to_host_path_result" + func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" + fi +} +# end func_convert_path_cygwin_to_w32 + + +# func_convert_path_nix_to_w32 ARG +# Convert path ARG from *nix to w32 format. Requires a wine environment and +# a working winepath. Returns result in func_to_host_file_result. +func_convert_path_nix_to_w32 () +{ + $opt_debug + func_to_host_path_result="$1" + if test -n "$1"; then + # See func_convert_path_msys_to_w32: + func_stripname : : "$1" + func_to_host_path_tmp1=$func_stripname_result + func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1" + func_to_host_path_result="$func_convert_core_path_wine_to_w32_result" + func_convert_path_check : ";" \ + "$func_to_host_path_tmp1" "$func_to_host_path_result" + func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" + fi +} +# end func_convert_path_nix_to_w32 + + +# func_convert_path_msys_to_cygwin ARG +# Convert path ARG from MSYS to Cygwin format. Requires LT_CYGPATH set. +# Returns result in func_to_host_file_result. +func_convert_path_msys_to_cygwin () +{ + $opt_debug + func_to_host_path_result="$1" + if test -n "$1"; then + # See func_convert_path_msys_to_w32: + func_stripname : : "$1" + func_to_host_path_tmp1=$func_stripname_result + func_convert_core_msys_to_w32 "$func_to_host_path_tmp1" + func_cygpath -u -p "$func_convert_core_msys_to_w32_result" + func_to_host_path_result="$func_cygpath_result" + func_convert_path_check : : \ + "$func_to_host_path_tmp1" "$func_to_host_path_result" + func_convert_path_front_back_pathsep ":*" "*:" : "$1" + fi +} +# end func_convert_path_msys_to_cygwin + + +# func_convert_path_nix_to_cygwin ARG +# Convert path ARG from *nix to Cygwin format. Requires Cygwin installed in a +# a wine environment, working winepath, and LT_CYGPATH set. Returns result in +# func_to_host_file_result. +func_convert_path_nix_to_cygwin () +{ + $opt_debug + func_to_host_path_result="$1" + if test -n "$1"; then + # Remove leading and trailing path separator characters from + # ARG. msys behavior is inconsistent here, cygpath turns them + # into '.;' and ';.', and winepath ignores them completely. + func_stripname : : "$1" + func_to_host_path_tmp1=$func_stripname_result + func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1" + func_cygpath -u -p "$func_convert_core_path_wine_to_w32_result" + func_to_host_path_result="$func_cygpath_result" + func_convert_path_check : : \ + "$func_to_host_path_tmp1" "$func_to_host_path_result" + func_convert_path_front_back_pathsep ":*" "*:" : "$1" + fi +} +# end func_convert_path_nix_to_cygwin + + +# func_mode_compile arg... +func_mode_compile () +{ + $opt_debug + # Get the compilation command and the source file. + base_compile= + srcfile="$nonopt" # always keep a non-empty value in "srcfile" + suppress_opt=yes + suppress_output= + arg_mode=normal + libobj= + later= + pie_flag= + + for arg + do + case $arg_mode in + arg ) + # do not "continue". Instead, add this to base_compile + lastarg="$arg" + arg_mode=normal + ;; + + target ) + libobj="$arg" + arg_mode=normal + continue + ;; + + normal ) + # Accept any command-line options. + case $arg in + -o) + test -n "$libobj" && \ + func_fatal_error "you cannot specify \`-o' more than once" + arg_mode=target + continue + ;; + + -pie | -fpie | -fPIE) + func_append pie_flag " $arg" + continue + ;; + + -shared | -static | -prefer-pic | -prefer-non-pic) + func_append later " $arg" + continue + ;; + + -no-suppress) + suppress_opt=no + continue + ;; + + -Xcompiler) + arg_mode=arg # the next one goes into the "base_compile" arg list + continue # The current "srcfile" will either be retained or + ;; # replaced later. I would guess that would be a bug. + + -Wc,*) + func_stripname '-Wc,' '' "$arg" + args=$func_stripname_result + lastarg= + save_ifs="$IFS"; IFS=',' + for arg in $args; do + IFS="$save_ifs" + func_append_quoted lastarg "$arg" + done + IFS="$save_ifs" + func_stripname ' ' '' "$lastarg" + lastarg=$func_stripname_result + + # Add the arguments to base_compile. + func_append base_compile " $lastarg" + continue + ;; + + *) + # Accept the current argument as the source file. + # The previous "srcfile" becomes the current argument. + # + lastarg="$srcfile" + srcfile="$arg" + ;; + esac # case $arg + ;; + esac # case $arg_mode + + # Aesthetically quote the previous argument. + func_append_quoted base_compile "$lastarg" + done # for arg + + case $arg_mode in + arg) + func_fatal_error "you must specify an argument for -Xcompile" + ;; + target) + func_fatal_error "you must specify a target with \`-o'" + ;; + *) + # Get the name of the library object. + test -z "$libobj" && { + func_basename "$srcfile" + libobj="$func_basename_result" + } + ;; + esac + + # Recognize several different file suffixes. + # If the user specifies -o file.o, it is replaced with file.lo + case $libobj in + *.[cCFSifmso] | \ + *.ada | *.adb | *.ads | *.asm | \ + *.c++ | *.cc | *.ii | *.class | *.cpp | *.cxx | \ + *.[fF][09]? | *.for | *.java | *.go | *.obj | *.sx | *.cu | *.cup) + func_xform "$libobj" + libobj=$func_xform_result + ;; + esac + + case $libobj in + *.lo) func_lo2o "$libobj"; obj=$func_lo2o_result ;; + *) + func_fatal_error "cannot determine name of library object from \`$libobj'" + ;; + esac + + func_infer_tag $base_compile + + for arg in $later; do + case $arg in + -shared) + test "$build_libtool_libs" != yes && \ + func_fatal_configuration "can not build a shared library" + build_old_libs=no + continue + ;; + + -static) + build_libtool_libs=no + build_old_libs=yes + continue + ;; + + -prefer-pic) + pic_mode=yes + continue + ;; + + -prefer-non-pic) + pic_mode=no + continue + ;; + esac + done + + func_quote_for_eval "$libobj" + test "X$libobj" != "X$func_quote_for_eval_result" \ + && $ECHO "X$libobj" | $GREP '[]~#^*{};<>?"'"'"' &()|`$[]' \ + && func_warning "libobj name \`$libobj' may not contain shell special characters." + func_dirname_and_basename "$obj" "/" "" + objname="$func_basename_result" + xdir="$func_dirname_result" + lobj=${xdir}$objdir/$objname + + test -z "$base_compile" && \ + func_fatal_help "you must specify a compilation command" + + # Delete any leftover library objects. + if test "$build_old_libs" = yes; then + removelist="$obj $lobj $libobj ${libobj}T" + else + removelist="$lobj $libobj ${libobj}T" + fi + + # On Cygwin there's no "real" PIC flag so we must build both object types + case $host_os in + cygwin* | mingw* | pw32* | os2* | cegcc*) + pic_mode=default + ;; + esac + if test "$pic_mode" = no && test "$deplibs_check_method" != pass_all; then + # non-PIC code in shared libraries is not supported + pic_mode=default + fi + + # Calculate the filename of the output object if compiler does + # not support -o with -c + if test "$compiler_c_o" = no; then + output_obj=`$ECHO "$srcfile" | $SED 's%^.*/%%; s%\.[^.]*$%%'`.${objext} + lockfile="$output_obj.lock" + else + output_obj= + need_locks=no + lockfile= + fi + + # Lock this critical section if it is needed + # We use this script file to make the link, it avoids creating a new file + if test "$need_locks" = yes; then + until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do + func_echo "Waiting for $lockfile to be removed" + sleep 2 + done + elif test "$need_locks" = warn; then + if test -f "$lockfile"; then + $ECHO "\ +*** ERROR, $lockfile exists and contains: +`cat $lockfile 2>/dev/null` + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support \`-c' and \`-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $opt_dry_run || $RM $removelist + exit $EXIT_FAILURE + fi + func_append removelist " $output_obj" + $ECHO "$srcfile" > "$lockfile" + fi + + $opt_dry_run || $RM $removelist + func_append removelist " $lockfile" + trap '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' 1 2 15 + + func_to_tool_file "$srcfile" func_convert_file_msys_to_w32 + srcfile=$func_to_tool_file_result + func_quote_for_eval "$srcfile" + qsrcfile=$func_quote_for_eval_result + + # Only build a PIC object if we are building libtool libraries. + if test "$build_libtool_libs" = yes; then + # Without this assignment, base_compile gets emptied. + fbsd_hideous_sh_bug=$base_compile + + if test "$pic_mode" != no; then + command="$base_compile $qsrcfile $pic_flag" + else + # Don't build PIC code + command="$base_compile $qsrcfile" + fi + + func_mkdir_p "$xdir$objdir" + + if test -z "$output_obj"; then + # Place PIC objects in $objdir + func_append command " -o $lobj" + fi + + func_show_eval_locale "$command" \ + 'test -n "$output_obj" && $RM $removelist; exit $EXIT_FAILURE' + + if test "$need_locks" = warn && + test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then + $ECHO "\ +*** ERROR, $lockfile contains: +`cat $lockfile 2>/dev/null` + +but it should contain: +$srcfile + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support \`-c' and \`-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $opt_dry_run || $RM $removelist + exit $EXIT_FAILURE + fi + + # Just move the object if needed, then go on to compile the next one + if test -n "$output_obj" && test "X$output_obj" != "X$lobj"; then + func_show_eval '$MV "$output_obj" "$lobj"' \ + 'error=$?; $opt_dry_run || $RM $removelist; exit $error' + fi + + # Allow error messages only from the first compilation. + if test "$suppress_opt" = yes; then + suppress_output=' >/dev/null 2>&1' + fi + fi + + # Only build a position-dependent object if we build old libraries. + if test "$build_old_libs" = yes; then + if test "$pic_mode" != yes; then + # Don't build PIC code + command="$base_compile $qsrcfile$pie_flag" + else + command="$base_compile $qsrcfile $pic_flag" + fi + if test "$compiler_c_o" = yes; then + func_append command " -o $obj" + fi + + # Suppress compiler output if we already did a PIC compilation. + func_append command "$suppress_output" + func_show_eval_locale "$command" \ + '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' + + if test "$need_locks" = warn && + test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then + $ECHO "\ +*** ERROR, $lockfile contains: +`cat $lockfile 2>/dev/null` + +but it should contain: +$srcfile + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support \`-c' and \`-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $opt_dry_run || $RM $removelist + exit $EXIT_FAILURE + fi + + # Just move the object if needed + if test -n "$output_obj" && test "X$output_obj" != "X$obj"; then + func_show_eval '$MV "$output_obj" "$obj"' \ + 'error=$?; $opt_dry_run || $RM $removelist; exit $error' + fi + fi + + $opt_dry_run || { + func_write_libtool_object "$libobj" "$objdir/$objname" "$objname" + + # Unlock the critical section if it was locked + if test "$need_locks" != no; then + removelist=$lockfile + $RM "$lockfile" + fi + } + + exit $EXIT_SUCCESS +} + +$opt_help || { + test "$opt_mode" = compile && func_mode_compile ${1+"$@"} +} + +func_mode_help () +{ + # We need to display help for each of the modes. + case $opt_mode in + "") + # Generic help is extracted from the usage comments + # at the start of this file. + func_help + ;; + + clean) + $ECHO \ +"Usage: $progname [OPTION]... --mode=clean RM [RM-OPTION]... FILE... + +Remove files from the build directory. + +RM is the name of the program to use to delete files associated with each FILE +(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed +to RM. + +If FILE is a libtool library, object or program, all the files associated +with it are deleted. Otherwise, only FILE itself is deleted using RM." + ;; + + compile) + $ECHO \ +"Usage: $progname [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE + +Compile a source file into a libtool library object. + +This mode accepts the following additional options: + + -o OUTPUT-FILE set the output file name to OUTPUT-FILE + -no-suppress do not suppress compiler output for multiple passes + -prefer-pic try to build PIC objects only + -prefer-non-pic try to build non-PIC objects only + -shared do not build a \`.o' file suitable for static linking + -static only build a \`.o' file suitable for static linking + -Wc,FLAG pass FLAG directly to the compiler + +COMPILE-COMMAND is a command to be used in creating a \`standard' object file +from the given SOURCEFILE. + +The output file name is determined by removing the directory component from +SOURCEFILE, then substituting the C source code suffix \`.c' with the +library object suffix, \`.lo'." + ;; + + execute) + $ECHO \ +"Usage: $progname [OPTION]... --mode=execute COMMAND [ARGS]... + +Automatically set library path, then run a program. + +This mode accepts the following additional options: + + -dlopen FILE add the directory containing FILE to the library path + +This mode sets the library path environment variable according to \`-dlopen' +flags. + +If any of the ARGS are libtool executable wrappers, then they are translated +into their corresponding uninstalled binary, and any of their required library +directories are added to the library path. + +Then, COMMAND is executed, with ARGS as arguments." + ;; + + finish) + $ECHO \ +"Usage: $progname [OPTION]... --mode=finish [LIBDIR]... + +Complete the installation of libtool libraries. + +Each LIBDIR is a directory that contains libtool libraries. + +The commands that this mode executes may require superuser privileges. Use +the \`--dry-run' option if you just want to see what would be executed." + ;; + + install) + $ECHO \ +"Usage: $progname [OPTION]... --mode=install INSTALL-COMMAND... + +Install executables or libraries. + +INSTALL-COMMAND is the installation command. The first component should be +either the \`install' or \`cp' program. + +The following components of INSTALL-COMMAND are treated specially: + + -inst-prefix-dir PREFIX-DIR Use PREFIX-DIR as a staging area for installation + +The rest of the components are interpreted as arguments to that command (only +BSD-compatible install options are recognized)." + ;; + + link) + $ECHO \ +"Usage: $progname [OPTION]... --mode=link LINK-COMMAND... + +Link object files or libraries together to form another library, or to +create an executable program. + +LINK-COMMAND is a command using the C compiler that you would use to create +a program from several object files. + +The following components of LINK-COMMAND are treated specially: + + -all-static do not do any dynamic linking at all + -avoid-version do not add a version suffix if possible + -bindir BINDIR specify path to binaries directory (for systems where + libraries must be found in the PATH setting at runtime) + -dlopen FILE \`-dlpreopen' FILE if it cannot be dlopened at runtime + -dlpreopen FILE link in FILE and add its symbols to lt_preloaded_symbols + -export-dynamic allow symbols from OUTPUT-FILE to be resolved with dlsym(3) + -export-symbols SYMFILE + try to export only the symbols listed in SYMFILE + -export-symbols-regex REGEX + try to export only the symbols matching REGEX + -LLIBDIR search LIBDIR for required installed libraries + -lNAME OUTPUT-FILE requires the installed library libNAME + -module build a library that can dlopened + -no-fast-install disable the fast-install mode + -no-install link a not-installable executable + -no-undefined declare that a library does not refer to external symbols + -o OUTPUT-FILE create OUTPUT-FILE from the specified objects + -objectlist FILE Use a list of object files found in FILE to specify objects + -precious-files-regex REGEX + don't remove output files matching REGEX + -release RELEASE specify package release information + -rpath LIBDIR the created library will eventually be installed in LIBDIR + -R[ ]LIBDIR add LIBDIR to the runtime path of programs and libraries + -shared only do dynamic linking of libtool libraries + -shrext SUFFIX override the standard shared library file extension + -static do not do any dynamic linking of uninstalled libtool libraries + -static-libtool-libs + do not do any dynamic linking of libtool libraries + -version-info CURRENT[:REVISION[:AGE]] + specify library version info [each variable defaults to 0] + -weak LIBNAME declare that the target provides the LIBNAME interface + -Wc,FLAG + -Xcompiler FLAG pass linker-specific FLAG directly to the compiler + -Wl,FLAG + -Xlinker FLAG pass linker-specific FLAG directly to the linker + -XCClinker FLAG pass link-specific FLAG to the compiler driver (CC) + +All other options (arguments beginning with \`-') are ignored. + +Every other argument is treated as a filename. Files ending in \`.la' are +treated as uninstalled libtool libraries, other files are standard or library +object files. + +If the OUTPUT-FILE ends in \`.la', then a libtool library is created, +only library objects (\`.lo' files) may be specified, and \`-rpath' is +required, except when creating a convenience library. + +If OUTPUT-FILE ends in \`.a' or \`.lib', then a standard library is created +using \`ar' and \`ranlib', or on Windows using \`lib'. + +If OUTPUT-FILE ends in \`.lo' or \`.${objext}', then a reloadable object file +is created, otherwise an executable program is created." + ;; + + uninstall) + $ECHO \ +"Usage: $progname [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE... + +Remove libraries from an installation directory. + +RM is the name of the program to use to delete files associated with each FILE +(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed +to RM. + +If FILE is a libtool library, all the files associated with it are deleted. +Otherwise, only FILE itself is deleted using RM." + ;; + + *) + func_fatal_help "invalid operation mode \`$opt_mode'" + ;; + esac + + echo + $ECHO "Try \`$progname --help' for more information about other modes." +} + +# Now that we've collected a possible --mode arg, show help if necessary +if $opt_help; then + if test "$opt_help" = :; then + func_mode_help + else + { + func_help noexit + for opt_mode in compile link execute install finish uninstall clean; do + func_mode_help + done + } | sed -n '1p; 2,$s/^Usage:/ or: /p' + { + func_help noexit + for opt_mode in compile link execute install finish uninstall clean; do + echo + func_mode_help + done + } | + sed '1d + /^When reporting/,/^Report/{ + H + d + } + $x + /information about other modes/d + /more detailed .*MODE/d + s/^Usage:.*--mode=\([^ ]*\) .*/Description of \1 mode:/' + fi + exit $? +fi + + +# func_mode_execute arg... +func_mode_execute () +{ + $opt_debug + # The first argument is the command name. + cmd="$nonopt" + test -z "$cmd" && \ + func_fatal_help "you must specify a COMMAND" + + # Handle -dlopen flags immediately. + for file in $opt_dlopen; do + test -f "$file" \ + || func_fatal_help "\`$file' is not a file" + + dir= + case $file in + *.la) + func_resolve_sysroot "$file" + file=$func_resolve_sysroot_result + + # Check to see that this really is a libtool archive. + func_lalib_unsafe_p "$file" \ + || func_fatal_help "\`$lib' is not a valid libtool archive" + + # Read the libtool library. + dlname= + library_names= + func_source "$file" + + # Skip this library if it cannot be dlopened. + if test -z "$dlname"; then + # Warn if it was a shared library. + test -n "$library_names" && \ + func_warning "\`$file' was not linked with \`-export-dynamic'" + continue + fi + + func_dirname "$file" "" "." + dir="$func_dirname_result" + + if test -f "$dir/$objdir/$dlname"; then + func_append dir "/$objdir" + else + if test ! -f "$dir/$dlname"; then + func_fatal_error "cannot find \`$dlname' in \`$dir' or \`$dir/$objdir'" + fi + fi + ;; + + *.lo) + # Just add the directory containing the .lo file. + func_dirname "$file" "" "." + dir="$func_dirname_result" + ;; + + *) + func_warning "\`-dlopen' is ignored for non-libtool libraries and objects" + continue + ;; + esac + + # Get the absolute pathname. + absdir=`cd "$dir" && pwd` + test -n "$absdir" && dir="$absdir" + + # Now add the directory to shlibpath_var. + if eval "test -z \"\$$shlibpath_var\""; then + eval "$shlibpath_var=\"\$dir\"" + else + eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\"" + fi + done + + # This variable tells wrapper scripts just to set shlibpath_var + # rather than running their programs. + libtool_execute_magic="$magic" + + # Check if any of the arguments is a wrapper script. + args= + for file + do + case $file in + -* | *.la | *.lo ) ;; + *) + # Do a test to see if this is really a libtool program. + if func_ltwrapper_script_p "$file"; then + func_source "$file" + # Transform arg to wrapped name. + file="$progdir/$program" + elif func_ltwrapper_executable_p "$file"; then + func_ltwrapper_scriptname "$file" + func_source "$func_ltwrapper_scriptname_result" + # Transform arg to wrapped name. + file="$progdir/$program" + fi + ;; + esac + # Quote arguments (to preserve shell metacharacters). + func_append_quoted args "$file" + done + + if test "X$opt_dry_run" = Xfalse; then + if test -n "$shlibpath_var"; then + # Export the shlibpath_var. + eval "export $shlibpath_var" + fi + + # Restore saved environment variables + for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES + do + eval "if test \"\${save_$lt_var+set}\" = set; then + $lt_var=\$save_$lt_var; export $lt_var + else + $lt_unset $lt_var + fi" + done + + # Now prepare to actually exec the command. + exec_cmd="\$cmd$args" + else + # Display what would be done. + if test -n "$shlibpath_var"; then + eval "\$ECHO \"\$shlibpath_var=\$$shlibpath_var\"" + echo "export $shlibpath_var" + fi + $ECHO "$cmd$args" + exit $EXIT_SUCCESS + fi +} + +test "$opt_mode" = execute && func_mode_execute ${1+"$@"} + + +# func_mode_finish arg... +func_mode_finish () +{ + $opt_debug + libs= + libdirs= + admincmds= + + for opt in "$nonopt" ${1+"$@"} + do + if test -d "$opt"; then + func_append libdirs " $opt" + + elif test -f "$opt"; then + if func_lalib_unsafe_p "$opt"; then + func_append libs " $opt" + else + func_warning "\`$opt' is not a valid libtool archive" + fi + + else + func_fatal_error "invalid argument \`$opt'" + fi + done + + if test -n "$libs"; then + if test -n "$lt_sysroot"; then + sysroot_regex=`$ECHO "$lt_sysroot" | $SED "$sed_make_literal_regex"` + sysroot_cmd="s/\([ ']\)$sysroot_regex/\1/g;" + else + sysroot_cmd= + fi + + # Remove sysroot references + if $opt_dry_run; then + for lib in $libs; do + echo "removing references to $lt_sysroot and \`=' prefixes from $lib" + done + else + tmpdir=`func_mktempdir` + for lib in $libs; do + sed -e "${sysroot_cmd} s/\([ ']-[LR]\)=/\1/g; s/\([ ']\)=/\1/g" $lib \ + > $tmpdir/tmp-la + mv -f $tmpdir/tmp-la $lib + done + ${RM}r "$tmpdir" + fi + fi + + if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then + for libdir in $libdirs; do + if test -n "$finish_cmds"; then + # Do each command in the finish commands. + func_execute_cmds "$finish_cmds" 'admincmds="$admincmds +'"$cmd"'"' + fi + if test -n "$finish_eval"; then + # Do the single finish_eval. + eval cmds=\"$finish_eval\" + $opt_dry_run || eval "$cmds" || func_append admincmds " + $cmds" + fi + done + fi + + # Exit here if they wanted silent mode. + $opt_silent && exit $EXIT_SUCCESS + + if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then + echo "----------------------------------------------------------------------" + echo "Libraries have been installed in:" + for libdir in $libdirs; do + $ECHO " $libdir" + done + echo + echo "If you ever happen to want to link against installed libraries" + echo "in a given directory, LIBDIR, you must either use libtool, and" + echo "specify the full pathname of the library, or use the \`-LLIBDIR'" + echo "flag during linking and do at least one of the following:" + if test -n "$shlibpath_var"; then + echo " - add LIBDIR to the \`$shlibpath_var' environment variable" + echo " during execution" + fi + if test -n "$runpath_var"; then + echo " - add LIBDIR to the \`$runpath_var' environment variable" + echo " during linking" + fi + if test -n "$hardcode_libdir_flag_spec"; then + libdir=LIBDIR + eval flag=\"$hardcode_libdir_flag_spec\" + + $ECHO " - use the \`$flag' linker flag" + fi + if test -n "$admincmds"; then + $ECHO " - have your system administrator run these commands:$admincmds" + fi + if test -f /etc/ld.so.conf; then + echo " - have your system administrator add LIBDIR to \`/etc/ld.so.conf'" + fi + echo + + echo "See any operating system documentation about shared libraries for" + case $host in + solaris2.[6789]|solaris2.1[0-9]) + echo "more information, such as the ld(1), crle(1) and ld.so(8) manual" + echo "pages." + ;; + *) + echo "more information, such as the ld(1) and ld.so(8) manual pages." + ;; + esac + echo "----------------------------------------------------------------------" + fi + exit $EXIT_SUCCESS +} + +test "$opt_mode" = finish && func_mode_finish ${1+"$@"} + + +# func_mode_install arg... +func_mode_install () +{ + $opt_debug + # There may be an optional sh(1) argument at the beginning of + # install_prog (especially on Windows NT). + if test "$nonopt" = "$SHELL" || test "$nonopt" = /bin/sh || + # Allow the use of GNU shtool's install command. + case $nonopt in *shtool*) :;; *) false;; esac; then + # Aesthetically quote it. + func_quote_for_eval "$nonopt" + install_prog="$func_quote_for_eval_result " + arg=$1 + shift + else + install_prog= + arg=$nonopt + fi + + # The real first argument should be the name of the installation program. + # Aesthetically quote it. + func_quote_for_eval "$arg" + func_append install_prog "$func_quote_for_eval_result" + install_shared_prog=$install_prog + case " $install_prog " in + *[\\\ /]cp\ *) install_cp=: ;; + *) install_cp=false ;; + esac + + # We need to accept at least all the BSD install flags. + dest= + files= + opts= + prev= + install_type= + isdir=no + stripme= + no_mode=: + for arg + do + arg2= + if test -n "$dest"; then + func_append files " $dest" + dest=$arg + continue + fi + + case $arg in + -d) isdir=yes ;; + -f) + if $install_cp; then :; else + prev=$arg + fi + ;; + -g | -m | -o) + prev=$arg + ;; + -s) + stripme=" -s" + continue + ;; + -*) + ;; + *) + # If the previous option needed an argument, then skip it. + if test -n "$prev"; then + if test "x$prev" = x-m && test -n "$install_override_mode"; then + arg2=$install_override_mode + no_mode=false + fi + prev= + else + dest=$arg + continue + fi + ;; + esac + + # Aesthetically quote the argument. + func_quote_for_eval "$arg" + func_append install_prog " $func_quote_for_eval_result" + if test -n "$arg2"; then + func_quote_for_eval "$arg2" + fi + func_append install_shared_prog " $func_quote_for_eval_result" + done + + test -z "$install_prog" && \ + func_fatal_help "you must specify an install program" + + test -n "$prev" && \ + func_fatal_help "the \`$prev' option requires an argument" + + if test -n "$install_override_mode" && $no_mode; then + if $install_cp; then :; else + func_quote_for_eval "$install_override_mode" + func_append install_shared_prog " -m $func_quote_for_eval_result" + fi + fi + + if test -z "$files"; then + if test -z "$dest"; then + func_fatal_help "no file or destination specified" + else + func_fatal_help "you must specify a destination" + fi + fi + + # Strip any trailing slash from the destination. + func_stripname '' '/' "$dest" + dest=$func_stripname_result + + # Check to see that the destination is a directory. + test -d "$dest" && isdir=yes + if test "$isdir" = yes; then + destdir="$dest" + destname= + else + func_dirname_and_basename "$dest" "" "." + destdir="$func_dirname_result" + destname="$func_basename_result" + + # Not a directory, so check to see that there is only one file specified. + set dummy $files; shift + test "$#" -gt 1 && \ + func_fatal_help "\`$dest' is not a directory" + fi + case $destdir in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + for file in $files; do + case $file in + *.lo) ;; + *) + func_fatal_help "\`$destdir' must be an absolute directory name" + ;; + esac + done + ;; + esac + + # This variable tells wrapper scripts just to set variables rather + # than running their programs. + libtool_install_magic="$magic" + + staticlibs= + future_libdirs= + current_libdirs= + for file in $files; do + + # Do each installation. + case $file in + *.$libext) + # Do the static libraries later. + func_append staticlibs " $file" + ;; + + *.la) + func_resolve_sysroot "$file" + file=$func_resolve_sysroot_result + + # Check to see that this really is a libtool archive. + func_lalib_unsafe_p "$file" \ + || func_fatal_help "\`$file' is not a valid libtool archive" + + library_names= + old_library= + relink_command= + func_source "$file" + + # Add the libdir to current_libdirs if it is the destination. + if test "X$destdir" = "X$libdir"; then + case "$current_libdirs " in + *" $libdir "*) ;; + *) func_append current_libdirs " $libdir" ;; + esac + else + # Note the libdir as a future libdir. + case "$future_libdirs " in + *" $libdir "*) ;; + *) func_append future_libdirs " $libdir" ;; + esac + fi + + func_dirname "$file" "/" "" + dir="$func_dirname_result" + func_append dir "$objdir" + + if test -n "$relink_command"; then + # Determine the prefix the user has applied to our future dir. + inst_prefix_dir=`$ECHO "$destdir" | $SED -e "s%$libdir\$%%"` + + # Don't allow the user to place us outside of our expected + # location b/c this prevents finding dependent libraries that + # are installed to the same prefix. + # At present, this check doesn't affect windows .dll's that + # are installed into $libdir/../bin (currently, that works fine) + # but it's something to keep an eye on. + test "$inst_prefix_dir" = "$destdir" && \ + func_fatal_error "error: cannot install \`$file' to a directory not ending in $libdir" + + if test -n "$inst_prefix_dir"; then + # Stick the inst_prefix_dir data into the link command. + relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%-inst-prefix-dir $inst_prefix_dir%"` + else + relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%%"` + fi + + func_warning "relinking \`$file'" + func_show_eval "$relink_command" \ + 'func_fatal_error "error: relink \`$file'\'' with the above command before installing it"' + fi + + # See the names of the shared library. + set dummy $library_names; shift + if test -n "$1"; then + realname="$1" + shift + + srcname="$realname" + test -n "$relink_command" && srcname="$realname"T + + # Install the shared library and build the symlinks. + func_show_eval "$install_shared_prog $dir/$srcname $destdir/$realname" \ + 'exit $?' + tstripme="$stripme" + case $host_os in + cygwin* | mingw* | pw32* | cegcc*) + case $realname in + *.dll.a) + tstripme="" + ;; + esac + ;; + esac + if test -n "$tstripme" && test -n "$striplib"; then + func_show_eval "$striplib $destdir/$realname" 'exit $?' + fi + + if test "$#" -gt 0; then + # Delete the old symlinks, and create new ones. + # Try `ln -sf' first, because the `ln' binary might depend on + # the symlink we replace! Solaris /bin/ln does not understand -f, + # so we also need to try rm && ln -s. + for linkname + do + test "$linkname" != "$realname" \ + && func_show_eval "(cd $destdir && { $LN_S -f $realname $linkname || { $RM $linkname && $LN_S $realname $linkname; }; })" + done + fi + + # Do each command in the postinstall commands. + lib="$destdir/$realname" + func_execute_cmds "$postinstall_cmds" 'exit $?' + fi + + # Install the pseudo-library for information purposes. + func_basename "$file" + name="$func_basename_result" + instname="$dir/$name"i + func_show_eval "$install_prog $instname $destdir/$name" 'exit $?' + + # Maybe install the static library, too. + test -n "$old_library" && func_append staticlibs " $dir/$old_library" + ;; + + *.lo) + # Install (i.e. copy) a libtool object. + + # Figure out destination file name, if it wasn't already specified. + if test -n "$destname"; then + destfile="$destdir/$destname" + else + func_basename "$file" + destfile="$func_basename_result" + destfile="$destdir/$destfile" + fi + + # Deduce the name of the destination old-style object file. + case $destfile in + *.lo) + func_lo2o "$destfile" + staticdest=$func_lo2o_result + ;; + *.$objext) + staticdest="$destfile" + destfile= + ;; + *) + func_fatal_help "cannot copy a libtool object to \`$destfile'" + ;; + esac + + # Install the libtool object if requested. + test -n "$destfile" && \ + func_show_eval "$install_prog $file $destfile" 'exit $?' + + # Install the old object if enabled. + if test "$build_old_libs" = yes; then + # Deduce the name of the old-style object file. + func_lo2o "$file" + staticobj=$func_lo2o_result + func_show_eval "$install_prog \$staticobj \$staticdest" 'exit $?' + fi + exit $EXIT_SUCCESS + ;; + + *) + # Figure out destination file name, if it wasn't already specified. + if test -n "$destname"; then + destfile="$destdir/$destname" + else + func_basename "$file" + destfile="$func_basename_result" + destfile="$destdir/$destfile" + fi + + # If the file is missing, and there is a .exe on the end, strip it + # because it is most likely a libtool script we actually want to + # install + stripped_ext="" + case $file in + *.exe) + if test ! -f "$file"; then + func_stripname '' '.exe' "$file" + file=$func_stripname_result + stripped_ext=".exe" + fi + ;; + esac + + # Do a test to see if this is really a libtool program. + case $host in + *cygwin* | *mingw*) + if func_ltwrapper_executable_p "$file"; then + func_ltwrapper_scriptname "$file" + wrapper=$func_ltwrapper_scriptname_result + else + func_stripname '' '.exe' "$file" + wrapper=$func_stripname_result + fi + ;; + *) + wrapper=$file + ;; + esac + if func_ltwrapper_script_p "$wrapper"; then + notinst_deplibs= + relink_command= + + func_source "$wrapper" + + # Check the variables that should have been set. + test -z "$generated_by_libtool_version" && \ + func_fatal_error "invalid libtool wrapper script \`$wrapper'" + + finalize=yes + for lib in $notinst_deplibs; do + # Check to see that each library is installed. + libdir= + if test -f "$lib"; then + func_source "$lib" + fi + libfile="$libdir/"`$ECHO "$lib" | $SED 's%^.*/%%g'` ### testsuite: skip nested quoting test + if test -n "$libdir" && test ! -f "$libfile"; then + func_warning "\`$lib' has not been installed in \`$libdir'" + finalize=no + fi + done + + relink_command= + func_source "$wrapper" + + outputname= + if test "$fast_install" = no && test -n "$relink_command"; then + $opt_dry_run || { + if test "$finalize" = yes; then + tmpdir=`func_mktempdir` + func_basename "$file$stripped_ext" + file="$func_basename_result" + outputname="$tmpdir/$file" + # Replace the output file specification. + relink_command=`$ECHO "$relink_command" | $SED 's%@OUTPUT@%'"$outputname"'%g'` + + $opt_silent || { + func_quote_for_expand "$relink_command" + eval "func_echo $func_quote_for_expand_result" + } + if eval "$relink_command"; then : + else + func_error "error: relink \`$file' with the above command before installing it" + $opt_dry_run || ${RM}r "$tmpdir" + continue + fi + file="$outputname" + else + func_warning "cannot relink \`$file'" + fi + } + else + # Install the binary that we compiled earlier. + file=`$ECHO "$file$stripped_ext" | $SED "s%\([^/]*\)$%$objdir/\1%"` + fi + fi + + # remove .exe since cygwin /usr/bin/install will append another + # one anyway + case $install_prog,$host in + */usr/bin/install*,*cygwin*) + case $file:$destfile in + *.exe:*.exe) + # this is ok + ;; + *.exe:*) + destfile=$destfile.exe + ;; + *:*.exe) + func_stripname '' '.exe' "$destfile" + destfile=$func_stripname_result + ;; + esac + ;; + esac + func_show_eval "$install_prog\$stripme \$file \$destfile" 'exit $?' + $opt_dry_run || if test -n "$outputname"; then + ${RM}r "$tmpdir" + fi + ;; + esac + done + + for file in $staticlibs; do + func_basename "$file" + name="$func_basename_result" + + # Set up the ranlib parameters. + oldlib="$destdir/$name" + func_to_tool_file "$oldlib" func_convert_file_msys_to_w32 + tool_oldlib=$func_to_tool_file_result + + func_show_eval "$install_prog \$file \$oldlib" 'exit $?' + + if test -n "$stripme" && test -n "$old_striplib"; then + func_show_eval "$old_striplib $tool_oldlib" 'exit $?' + fi + + # Do each command in the postinstall commands. + func_execute_cmds "$old_postinstall_cmds" 'exit $?' + done + + test -n "$future_libdirs" && \ + func_warning "remember to run \`$progname --finish$future_libdirs'" + + if test -n "$current_libdirs"; then + # Maybe just do a dry run. + $opt_dry_run && current_libdirs=" -n$current_libdirs" + exec_cmd='$SHELL $progpath $preserve_args --finish$current_libdirs' + else + exit $EXIT_SUCCESS + fi +} + +test "$opt_mode" = install && func_mode_install ${1+"$@"} + + +# func_generate_dlsyms outputname originator pic_p +# Extract symbols from dlprefiles and create ${outputname}S.o with +# a dlpreopen symbol table. +func_generate_dlsyms () +{ + $opt_debug + my_outputname="$1" + my_originator="$2" + my_pic_p="${3-no}" + my_prefix=`$ECHO "$my_originator" | sed 's%[^a-zA-Z0-9]%_%g'` + my_dlsyms= + + if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then + if test -n "$NM" && test -n "$global_symbol_pipe"; then + my_dlsyms="${my_outputname}S.c" + else + func_error "not configured to extract global symbols from dlpreopened files" + fi + fi + + if test -n "$my_dlsyms"; then + case $my_dlsyms in + "") ;; + *.c) + # Discover the nlist of each of the dlfiles. + nlist="$output_objdir/${my_outputname}.nm" + + func_show_eval "$RM $nlist ${nlist}S ${nlist}T" + + # Parse the name list into a source file. + func_verbose "creating $output_objdir/$my_dlsyms" + + $opt_dry_run || $ECHO > "$output_objdir/$my_dlsyms" "\ +/* $my_dlsyms - symbol resolution table for \`$my_outputname' dlsym emulation. */ +/* Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION */ + +#ifdef __cplusplus +extern \"C\" { +#endif + +#if defined(__GNUC__) && (((__GNUC__ == 4) && (__GNUC_MINOR__ >= 4)) || (__GNUC__ > 4)) +#pragma GCC diagnostic ignored \"-Wstrict-prototypes\" +#endif + +/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ +#if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE) +/* DATA imports from DLLs on WIN32 con't be const, because runtime + relocations are performed -- see ld's documentation on pseudo-relocs. */ +# define LT_DLSYM_CONST +#elif defined(__osf__) +/* This system does not cope well with relocations in const data. */ +# define LT_DLSYM_CONST +#else +# define LT_DLSYM_CONST const +#endif + +/* External symbol declarations for the compiler. */\ +" + + if test "$dlself" = yes; then + func_verbose "generating symbol list for \`$output'" + + $opt_dry_run || echo ': @PROGRAM@ ' > "$nlist" + + # Add our own program objects to the symbol list. + progfiles=`$ECHO "$objs$old_deplibs" | $SP2NL | $SED "$lo2o" | $NL2SP` + for progfile in $progfiles; do + func_to_tool_file "$progfile" func_convert_file_msys_to_w32 + func_verbose "extracting global C symbols from \`$func_to_tool_file_result'" + $opt_dry_run || eval "$NM $func_to_tool_file_result | $global_symbol_pipe >> '$nlist'" + done + + if test -n "$exclude_expsyms"; then + $opt_dry_run || { + eval '$EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T' + eval '$MV "$nlist"T "$nlist"' + } + fi + + if test -n "$export_symbols_regex"; then + $opt_dry_run || { + eval '$EGREP -e "$export_symbols_regex" "$nlist" > "$nlist"T' + eval '$MV "$nlist"T "$nlist"' + } + fi + + # Prepare the list of exported symbols + if test -z "$export_symbols"; then + export_symbols="$output_objdir/$outputname.exp" + $opt_dry_run || { + $RM $export_symbols + eval "${SED} -n -e '/^: @PROGRAM@ $/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"' + case $host in + *cygwin* | *mingw* | *cegcc* ) + eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' + eval 'cat "$export_symbols" >> "$output_objdir/$outputname.def"' + ;; + esac + } + else + $opt_dry_run || { + eval "${SED} -e 's/\([].[*^$]\)/\\\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$outputname.exp"' + eval '$GREP -f "$output_objdir/$outputname.exp" < "$nlist" > "$nlist"T' + eval '$MV "$nlist"T "$nlist"' + case $host in + *cygwin* | *mingw* | *cegcc* ) + eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' + eval 'cat "$nlist" >> "$output_objdir/$outputname.def"' + ;; + esac + } + fi + fi + + for dlprefile in $dlprefiles; do + func_verbose "extracting global C symbols from \`$dlprefile'" + func_basename "$dlprefile" + name="$func_basename_result" + case $host in + *cygwin* | *mingw* | *cegcc* ) + # if an import library, we need to obtain dlname + if func_win32_import_lib_p "$dlprefile"; then + func_tr_sh "$dlprefile" + eval "curr_lafile=\$libfile_$func_tr_sh_result" + dlprefile_dlbasename="" + if test -n "$curr_lafile" && func_lalib_p "$curr_lafile"; then + # Use subshell, to avoid clobbering current variable values + dlprefile_dlname=`source "$curr_lafile" && echo "$dlname"` + if test -n "$dlprefile_dlname" ; then + func_basename "$dlprefile_dlname" + dlprefile_dlbasename="$func_basename_result" + else + # no lafile. user explicitly requested -dlpreopen . + $sharedlib_from_linklib_cmd "$dlprefile" + dlprefile_dlbasename=$sharedlib_from_linklib_result + fi + fi + $opt_dry_run || { + if test -n "$dlprefile_dlbasename" ; then + eval '$ECHO ": $dlprefile_dlbasename" >> "$nlist"' + else + func_warning "Could not compute DLL name from $name" + eval '$ECHO ": $name " >> "$nlist"' + fi + func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 + eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe | + $SED -e '/I __imp/d' -e 's/I __nm_/D /;s/_nm__//' >> '$nlist'" + } + else # not an import lib + $opt_dry_run || { + eval '$ECHO ": $name " >> "$nlist"' + func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 + eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'" + } + fi + ;; + *) + $opt_dry_run || { + eval '$ECHO ": $name " >> "$nlist"' + func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 + eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'" + } + ;; + esac + done + + $opt_dry_run || { + # Make sure we have at least an empty file. + test -f "$nlist" || : > "$nlist" + + if test -n "$exclude_expsyms"; then + $EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T + $MV "$nlist"T "$nlist" + fi + + # Try sorting and uniquifying the output. + if $GREP -v "^: " < "$nlist" | + if sort -k 3 /dev/null 2>&1; then + sort -k 3 + else + sort +2 + fi | + uniq > "$nlist"S; then + : + else + $GREP -v "^: " < "$nlist" > "$nlist"S + fi + + if test -f "$nlist"S; then + eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$my_dlsyms"' + else + echo '/* NONE */' >> "$output_objdir/$my_dlsyms" + fi + + echo >> "$output_objdir/$my_dlsyms" "\ + +/* The mapping between symbol names and symbols. */ +typedef struct { + const char *name; + void *address; +} lt_dlsymlist; +extern LT_DLSYM_CONST lt_dlsymlist +lt_${my_prefix}_LTX_preloaded_symbols[]; +LT_DLSYM_CONST lt_dlsymlist +lt_${my_prefix}_LTX_preloaded_symbols[] = +{\ + { \"$my_originator\", (void *) 0 }," + + case $need_lib_prefix in + no) + eval "$global_symbol_to_c_name_address" < "$nlist" >> "$output_objdir/$my_dlsyms" + ;; + *) + eval "$global_symbol_to_c_name_address_lib_prefix" < "$nlist" >> "$output_objdir/$my_dlsyms" + ;; + esac + echo >> "$output_objdir/$my_dlsyms" "\ + {0, (void *) 0} +}; + +/* This works around a problem in FreeBSD linker */ +#ifdef FREEBSD_WORKAROUND +static const void *lt_preloaded_setup() { + return lt_${my_prefix}_LTX_preloaded_symbols; +} +#endif + +#ifdef __cplusplus +} +#endif\ +" + } # !$opt_dry_run + + pic_flag_for_symtable= + case "$compile_command " in + *" -static "*) ;; + *) + case $host in + # compiling the symbol table file with pic_flag works around + # a FreeBSD bug that causes programs to crash when -lm is + # linked before any other PIC object. But we must not use + # pic_flag when linking with -static. The problem exists in + # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1. + *-*-freebsd2.*|*-*-freebsd3.0*|*-*-freebsdelf3.0*) + pic_flag_for_symtable=" $pic_flag -DFREEBSD_WORKAROUND" ;; + *-*-hpux*) + pic_flag_for_symtable=" $pic_flag" ;; + *) + if test "X$my_pic_p" != Xno; then + pic_flag_for_symtable=" $pic_flag" + fi + ;; + esac + ;; + esac + symtab_cflags= + for arg in $LTCFLAGS; do + case $arg in + -pie | -fpie | -fPIE) ;; + *) func_append symtab_cflags " $arg" ;; + esac + done + + # Now compile the dynamic symbol file. + func_show_eval '(cd $output_objdir && $LTCC$symtab_cflags -c$no_builtin_flag$pic_flag_for_symtable "$my_dlsyms")' 'exit $?' + + # Clean up the generated files. + func_show_eval '$RM "$output_objdir/$my_dlsyms" "$nlist" "${nlist}S" "${nlist}T"' + + # Transform the symbol file into the correct name. + symfileobj="$output_objdir/${my_outputname}S.$objext" + case $host in + *cygwin* | *mingw* | *cegcc* ) + if test -f "$output_objdir/$my_outputname.def"; then + compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` + finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` + else + compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"` + finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"` + fi + ;; + *) + compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"` + finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"` + ;; + esac + ;; + *) + func_fatal_error "unknown suffix for \`$my_dlsyms'" + ;; + esac + else + # We keep going just in case the user didn't refer to + # lt_preloaded_symbols. The linker will fail if global_symbol_pipe + # really was required. + + # Nullify the symbol file. + compile_command=`$ECHO "$compile_command" | $SED "s% @SYMFILE@%%"` + finalize_command=`$ECHO "$finalize_command" | $SED "s% @SYMFILE@%%"` + fi +} + +# func_win32_libid arg +# return the library type of file 'arg' +# +# Need a lot of goo to handle *both* DLLs and import libs +# Has to be a shell function in order to 'eat' the argument +# that is supplied when $file_magic_command is called. +# Despite the name, also deal with 64 bit binaries. +func_win32_libid () +{ + $opt_debug + win32_libid_type="unknown" + win32_fileres=`file -L $1 2>/dev/null` + case $win32_fileres in + *ar\ archive\ import\ library*) # definitely import + win32_libid_type="x86 archive import" + ;; + *ar\ archive*) # could be an import, or static + # Keep the egrep pattern in sync with the one in _LT_CHECK_MAGIC_METHOD. + if eval $OBJDUMP -f $1 | $SED -e '10q' 2>/dev/null | + $EGREP 'file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' >/dev/null; then + func_to_tool_file "$1" func_convert_file_msys_to_w32 + win32_nmres=`eval $NM -f posix -A \"$func_to_tool_file_result\" | + $SED -n -e ' + 1,100{ + / I /{ + s,.*,import, + p + q + } + }'` + case $win32_nmres in + import*) win32_libid_type="x86 archive import";; + *) win32_libid_type="x86 archive static";; + esac + fi + ;; + *DLL*) + win32_libid_type="x86 DLL" + ;; + *executable*) # but shell scripts are "executable" too... + case $win32_fileres in + *MS\ Windows\ PE\ Intel*) + win32_libid_type="x86 DLL" + ;; + esac + ;; + esac + $ECHO "$win32_libid_type" +} + +# func_cygming_dll_for_implib ARG +# +# Platform-specific function to extract the +# name of the DLL associated with the specified +# import library ARG. +# Invoked by eval'ing the libtool variable +# $sharedlib_from_linklib_cmd +# Result is available in the variable +# $sharedlib_from_linklib_result +func_cygming_dll_for_implib () +{ + $opt_debug + sharedlib_from_linklib_result=`$DLLTOOL --identify-strict --identify "$1"` +} + +# func_cygming_dll_for_implib_fallback_core SECTION_NAME LIBNAMEs +# +# The is the core of a fallback implementation of a +# platform-specific function to extract the name of the +# DLL associated with the specified import library LIBNAME. +# +# SECTION_NAME is either .idata$6 or .idata$7, depending +# on the platform and compiler that created the implib. +# +# Echos the name of the DLL associated with the +# specified import library. +func_cygming_dll_for_implib_fallback_core () +{ + $opt_debug + match_literal=`$ECHO "$1" | $SED "$sed_make_literal_regex"` + $OBJDUMP -s --section "$1" "$2" 2>/dev/null | + $SED '/^Contents of section '"$match_literal"':/{ + # Place marker at beginning of archive member dllname section + s/.*/====MARK====/ + p + d + } + # These lines can sometimes be longer than 43 characters, but + # are always uninteresting + /:[ ]*file format pe[i]\{,1\}-/d + /^In archive [^:]*:/d + # Ensure marker is printed + /^====MARK====/p + # Remove all lines with less than 43 characters + /^.\{43\}/!d + # From remaining lines, remove first 43 characters + s/^.\{43\}//' | + $SED -n ' + # Join marker and all lines until next marker into a single line + /^====MARK====/ b para + H + $ b para + b + :para + x + s/\n//g + # Remove the marker + s/^====MARK====// + # Remove trailing dots and whitespace + s/[\. \t]*$// + # Print + /./p' | + # we now have a list, one entry per line, of the stringified + # contents of the appropriate section of all members of the + # archive which possess that section. Heuristic: eliminate + # all those which have a first or second character that is + # a '.' (that is, objdump's representation of an unprintable + # character.) This should work for all archives with less than + # 0x302f exports -- but will fail for DLLs whose name actually + # begins with a literal '.' or a single character followed by + # a '.'. + # + # Of those that remain, print the first one. + $SED -e '/^\./d;/^.\./d;q' +} + +# func_cygming_gnu_implib_p ARG +# This predicate returns with zero status (TRUE) if +# ARG is a GNU/binutils-style import library. Returns +# with nonzero status (FALSE) otherwise. +func_cygming_gnu_implib_p () +{ + $opt_debug + func_to_tool_file "$1" func_convert_file_msys_to_w32 + func_cygming_gnu_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $EGREP ' (_head_[A-Za-z0-9_]+_[ad]l*|[A-Za-z0-9_]+_[ad]l*_iname)$'` + test -n "$func_cygming_gnu_implib_tmp" +} + +# func_cygming_ms_implib_p ARG +# This predicate returns with zero status (TRUE) if +# ARG is an MS-style import library. Returns +# with nonzero status (FALSE) otherwise. +func_cygming_ms_implib_p () +{ + $opt_debug + func_to_tool_file "$1" func_convert_file_msys_to_w32 + func_cygming_ms_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $GREP '_NULL_IMPORT_DESCRIPTOR'` + test -n "$func_cygming_ms_implib_tmp" +} + +# func_cygming_dll_for_implib_fallback ARG +# Platform-specific function to extract the +# name of the DLL associated with the specified +# import library ARG. +# +# This fallback implementation is for use when $DLLTOOL +# does not support the --identify-strict option. +# Invoked by eval'ing the libtool variable +# $sharedlib_from_linklib_cmd +# Result is available in the variable +# $sharedlib_from_linklib_result +func_cygming_dll_for_implib_fallback () +{ + $opt_debug + if func_cygming_gnu_implib_p "$1" ; then + # binutils import library + sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$7' "$1"` + elif func_cygming_ms_implib_p "$1" ; then + # ms-generated import library + sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$6' "$1"` + else + # unknown + sharedlib_from_linklib_result="" + fi +} + + +# func_extract_an_archive dir oldlib +func_extract_an_archive () +{ + $opt_debug + f_ex_an_ar_dir="$1"; shift + f_ex_an_ar_oldlib="$1" + if test "$lock_old_archive_extraction" = yes; then + lockfile=$f_ex_an_ar_oldlib.lock + until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do + func_echo "Waiting for $lockfile to be removed" + sleep 2 + done + fi + func_show_eval "(cd \$f_ex_an_ar_dir && $AR x \"\$f_ex_an_ar_oldlib\")" \ + 'stat=$?; rm -f "$lockfile"; exit $stat' + if test "$lock_old_archive_extraction" = yes; then + $opt_dry_run || rm -f "$lockfile" + fi + if ($AR t "$f_ex_an_ar_oldlib" | sort | sort -uc >/dev/null 2>&1); then + : + else + func_fatal_error "object name conflicts in archive: $f_ex_an_ar_dir/$f_ex_an_ar_oldlib" + fi +} + + +# func_extract_archives gentop oldlib ... +func_extract_archives () +{ + $opt_debug + my_gentop="$1"; shift + my_oldlibs=${1+"$@"} + my_oldobjs="" + my_xlib="" + my_xabs="" + my_xdir="" + + for my_xlib in $my_oldlibs; do + # Extract the objects. + case $my_xlib in + [\\/]* | [A-Za-z]:[\\/]*) my_xabs="$my_xlib" ;; + *) my_xabs=`pwd`"/$my_xlib" ;; + esac + func_basename "$my_xlib" + my_xlib="$func_basename_result" + my_xlib_u=$my_xlib + while :; do + case " $extracted_archives " in + *" $my_xlib_u "*) + func_arith $extracted_serial + 1 + extracted_serial=$func_arith_result + my_xlib_u=lt$extracted_serial-$my_xlib ;; + *) break ;; + esac + done + extracted_archives="$extracted_archives $my_xlib_u" + my_xdir="$my_gentop/$my_xlib_u" + + func_mkdir_p "$my_xdir" + + case $host in + *-darwin*) + func_verbose "Extracting $my_xabs" + # Do not bother doing anything if just a dry run + $opt_dry_run || { + darwin_orig_dir=`pwd` + cd $my_xdir || exit $? + darwin_archive=$my_xabs + darwin_curdir=`pwd` + darwin_base_archive=`basename "$darwin_archive"` + darwin_arches=`$LIPO -info "$darwin_archive" 2>/dev/null | $GREP Architectures 2>/dev/null || true` + if test -n "$darwin_arches"; then + darwin_arches=`$ECHO "$darwin_arches" | $SED -e 's/.*are://'` + darwin_arch= + func_verbose "$darwin_base_archive has multiple architectures $darwin_arches" + for darwin_arch in $darwin_arches ; do + func_mkdir_p "unfat-$$/${darwin_base_archive}-${darwin_arch}" + $LIPO -thin $darwin_arch -output "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" "${darwin_archive}" + cd "unfat-$$/${darwin_base_archive}-${darwin_arch}" + func_extract_an_archive "`pwd`" "${darwin_base_archive}" + cd "$darwin_curdir" + $RM "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" + done # $darwin_arches + ## Okay now we've a bunch of thin objects, gotta fatten them up :) + darwin_filelist=`find unfat-$$ -type f -name \*.o -print -o -name \*.lo -print | $SED -e "$basename" | sort -u` + darwin_file= + darwin_files= + for darwin_file in $darwin_filelist; do + darwin_files=`find unfat-$$ -name $darwin_file -print | sort | $NL2SP` + $LIPO -create -output "$darwin_file" $darwin_files + done # $darwin_filelist + $RM -rf unfat-$$ + cd "$darwin_orig_dir" + else + cd $darwin_orig_dir + func_extract_an_archive "$my_xdir" "$my_xabs" + fi # $darwin_arches + } # !$opt_dry_run + ;; + *) + func_extract_an_archive "$my_xdir" "$my_xabs" + ;; + esac + my_oldobjs="$my_oldobjs "`find $my_xdir -name \*.$objext -print -o -name \*.lo -print | sort | $NL2SP` + done + + func_extract_archives_result="$my_oldobjs" +} + + +# func_emit_wrapper [arg=no] +# +# Emit a libtool wrapper script on stdout. +# Don't directly open a file because we may want to +# incorporate the script contents within a cygwin/mingw +# wrapper executable. Must ONLY be called from within +# func_mode_link because it depends on a number of variables +# set therein. +# +# ARG is the value that the WRAPPER_SCRIPT_BELONGS_IN_OBJDIR +# variable will take. If 'yes', then the emitted script +# will assume that the directory in which it is stored is +# the $objdir directory. This is a cygwin/mingw-specific +# behavior. +func_emit_wrapper () +{ + func_emit_wrapper_arg1=${1-no} + + $ECHO "\ +#! $SHELL + +# $output - temporary wrapper script for $objdir/$outputname +# Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION +# +# The $output program cannot be directly executed until all the libtool +# libraries that it depends on are installed. +# +# This wrapper script should never be moved out of the build directory. +# If it is, it will not operate correctly. + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +sed_quote_subst='$sed_quote_subst' + +# Be Bourne compatible +if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on \${1+\"\$@\"}, which + # is contrary to our usage. Disable this feature. + alias -g '\${1+\"\$@\"}'='\"\$@\"' + setopt NO_GLOB_SUBST +else + case \`(set -o) 2>/dev/null\` in *posix*) set -o posix;; esac +fi +BIN_SH=xpg4; export BIN_SH # for Tru64 +DUALCASE=1; export DUALCASE # for MKS sh + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +relink_command=\"$relink_command\" + +# This environment variable determines our operation mode. +if test \"\$libtool_install_magic\" = \"$magic\"; then + # install mode needs the following variables: + generated_by_libtool_version='$macro_version' + notinst_deplibs='$notinst_deplibs' +else + # When we are sourced in execute mode, \$file and \$ECHO are already set. + if test \"\$libtool_execute_magic\" != \"$magic\"; then + file=\"\$0\"" + + qECHO=`$ECHO "$ECHO" | $SED "$sed_quote_subst"` + $ECHO "\ + +# A function that is used when there is no print builtin or printf. +func_fallback_echo () +{ + eval 'cat <<_LTECHO_EOF +\$1 +_LTECHO_EOF' +} + ECHO=\"$qECHO\" + fi + +# Very basic option parsing. These options are (a) specific to +# the libtool wrapper, (b) are identical between the wrapper +# /script/ and the wrapper /executable/ which is used only on +# windows platforms, and (c) all begin with the string "--lt-" +# (application programs are unlikely to have options which match +# this pattern). +# +# There are only two supported options: --lt-debug and +# --lt-dump-script. There is, deliberately, no --lt-help. +# +# The first argument to this parsing function should be the +# script's $0 value, followed by "$@". +lt_option_debug= +func_parse_lt_options () +{ + lt_script_arg0=\$0 + shift + for lt_opt + do + case \"\$lt_opt\" in + --lt-debug) lt_option_debug=1 ;; + --lt-dump-script) + lt_dump_D=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%/[^/]*$%%'\` + test \"X\$lt_dump_D\" = \"X\$lt_script_arg0\" && lt_dump_D=. + lt_dump_F=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%^.*/%%'\` + cat \"\$lt_dump_D/\$lt_dump_F\" + exit 0 + ;; + --lt-*) + \$ECHO \"Unrecognized --lt- option: '\$lt_opt'\" 1>&2 + exit 1 + ;; + esac + done + + # Print the debug banner immediately: + if test -n \"\$lt_option_debug\"; then + echo \"${outputname}:${output}:\${LINENO}: libtool wrapper (GNU $PACKAGE$TIMESTAMP) $VERSION\" 1>&2 + fi +} + +# Used when --lt-debug. Prints its arguments to stdout +# (redirection is the responsibility of the caller) +func_lt_dump_args () +{ + lt_dump_args_N=1; + for lt_arg + do + \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[\$lt_dump_args_N]: \$lt_arg\" + lt_dump_args_N=\`expr \$lt_dump_args_N + 1\` + done +} + +# Core function for launching the target application +func_exec_program_core () +{ +" + case $host in + # Backslashes separate directories on plain windows + *-*-mingw | *-*-os2* | *-cegcc*) + $ECHO "\ + if test -n \"\$lt_option_debug\"; then + \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[0]: \$progdir\\\\\$program\" 1>&2 + func_lt_dump_args \${1+\"\$@\"} 1>&2 + fi + exec \"\$progdir\\\\\$program\" \${1+\"\$@\"} +" + ;; + + *) + $ECHO "\ + if test -n \"\$lt_option_debug\"; then + \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[0]: \$progdir/\$program\" 1>&2 + func_lt_dump_args \${1+\"\$@\"} 1>&2 + fi + exec \"\$progdir/\$program\" \${1+\"\$@\"} +" + ;; + esac + $ECHO "\ + \$ECHO \"\$0: cannot exec \$program \$*\" 1>&2 + exit 1 +} + +# A function to encapsulate launching the target application +# Strips options in the --lt-* namespace from \$@ and +# launches target application with the remaining arguments. +func_exec_program () +{ + case \" \$* \" in + *\\ --lt-*) + for lt_wr_arg + do + case \$lt_wr_arg in + --lt-*) ;; + *) set x \"\$@\" \"\$lt_wr_arg\"; shift;; + esac + shift + done ;; + esac + func_exec_program_core \${1+\"\$@\"} +} + + # Parse options + func_parse_lt_options \"\$0\" \${1+\"\$@\"} + + # Find the directory that this script lives in. + thisdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*$%%'\` + test \"x\$thisdir\" = \"x\$file\" && thisdir=. + + # Follow symbolic links until we get to the real thisdir. + file=\`ls -ld \"\$file\" | $SED -n 's/.*-> //p'\` + while test -n \"\$file\"; do + destdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*\$%%'\` + + # If there was a directory component, then change thisdir. + if test \"x\$destdir\" != \"x\$file\"; then + case \"\$destdir\" in + [\\\\/]* | [A-Za-z]:[\\\\/]*) thisdir=\"\$destdir\" ;; + *) thisdir=\"\$thisdir/\$destdir\" ;; + esac + fi + + file=\`\$ECHO \"\$file\" | $SED 's%^.*/%%'\` + file=\`ls -ld \"\$thisdir/\$file\" | $SED -n 's/.*-> //p'\` + done + + # Usually 'no', except on cygwin/mingw when embedded into + # the cwrapper. + WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=$func_emit_wrapper_arg1 + if test \"\$WRAPPER_SCRIPT_BELONGS_IN_OBJDIR\" = \"yes\"; then + # special case for '.' + if test \"\$thisdir\" = \".\"; then + thisdir=\`pwd\` + fi + # remove .libs from thisdir + case \"\$thisdir\" in + *[\\\\/]$objdir ) thisdir=\`\$ECHO \"\$thisdir\" | $SED 's%[\\\\/][^\\\\/]*$%%'\` ;; + $objdir ) thisdir=. ;; + esac + fi + + # Try to get the absolute directory name. + absdir=\`cd \"\$thisdir\" && pwd\` + test -n \"\$absdir\" && thisdir=\"\$absdir\" +" + + if test "$fast_install" = yes; then + $ECHO "\ + program=lt-'$outputname'$exeext + progdir=\"\$thisdir/$objdir\" + + if test ! -f \"\$progdir/\$program\" || + { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | ${SED} 1q\`; \\ + test \"X\$file\" != \"X\$progdir/\$program\"; }; then + + file=\"\$\$-\$program\" + + if test ! -d \"\$progdir\"; then + $MKDIR \"\$progdir\" + else + $RM \"\$progdir/\$file\" + fi" + + $ECHO "\ + + # relink executable if necessary + if test -n \"\$relink_command\"; then + if relink_command_output=\`eval \$relink_command 2>&1\`; then : + else + $ECHO \"\$relink_command_output\" >&2 + $RM \"\$progdir/\$file\" + exit 1 + fi + fi + + $MV \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null || + { $RM \"\$progdir/\$program\"; + $MV \"\$progdir/\$file\" \"\$progdir/\$program\"; } + $RM \"\$progdir/\$file\" + fi" + else + $ECHO "\ + program='$outputname' + progdir=\"\$thisdir/$objdir\" +" + fi + + $ECHO "\ + + if test -f \"\$progdir/\$program\"; then" + + # fixup the dll searchpath if we need to. + # + # Fix the DLL searchpath if we need to. Do this before prepending + # to shlibpath, because on Windows, both are PATH and uninstalled + # libraries must come first. + if test -n "$dllsearchpath"; then + $ECHO "\ + # Add the dll search path components to the executable PATH + PATH=$dllsearchpath:\$PATH +" + fi + + # Export our shlibpath_var if we have one. + if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then + $ECHO "\ + # Add our own library path to $shlibpath_var + $shlibpath_var=\"$temp_rpath\$$shlibpath_var\" + + # Some systems cannot cope with colon-terminated $shlibpath_var + # The second colon is a workaround for a bug in BeOS R4 sed + $shlibpath_var=\`\$ECHO \"\$$shlibpath_var\" | $SED 's/::*\$//'\` + + export $shlibpath_var +" + fi + + $ECHO "\ + if test \"\$libtool_execute_magic\" != \"$magic\"; then + # Run the actual program with our arguments. + func_exec_program \${1+\"\$@\"} + fi + else + # The program doesn't exist. + \$ECHO \"\$0: error: \\\`\$progdir/\$program' does not exist\" 1>&2 + \$ECHO \"This script is just a wrapper for \$program.\" 1>&2 + \$ECHO \"See the $PACKAGE documentation for more information.\" 1>&2 + exit 1 + fi +fi\ +" +} + + +# func_emit_cwrapperexe_src +# emit the source code for a wrapper executable on stdout +# Must ONLY be called from within func_mode_link because +# it depends on a number of variable set therein. +func_emit_cwrapperexe_src () +{ + cat < +#include +#ifdef _MSC_VER +# include +# include +# include +#else +# include +# include +# ifdef __CYGWIN__ +# include +# endif +#endif +#include +#include +#include +#include +#include +#include +#include +#include + +/* declarations of non-ANSI functions */ +#if defined(__MINGW32__) +# ifdef __STRICT_ANSI__ +int _putenv (const char *); +# endif +#elif defined(__CYGWIN__) +# ifdef __STRICT_ANSI__ +char *realpath (const char *, char *); +int putenv (char *); +int setenv (const char *, const char *, int); +# endif +/* #elif defined (other platforms) ... */ +#endif + +/* portability defines, excluding path handling macros */ +#if defined(_MSC_VER) +# define setmode _setmode +# define stat _stat +# define chmod _chmod +# define getcwd _getcwd +# define putenv _putenv +# define S_IXUSR _S_IEXEC +# ifndef _INTPTR_T_DEFINED +# define _INTPTR_T_DEFINED +# define intptr_t int +# endif +#elif defined(__MINGW32__) +# define setmode _setmode +# define stat _stat +# define chmod _chmod +# define getcwd _getcwd +# define putenv _putenv +#elif defined(__CYGWIN__) +# define HAVE_SETENV +# define FOPEN_WB "wb" +/* #elif defined (other platforms) ... */ +#endif + +#if defined(PATH_MAX) +# define LT_PATHMAX PATH_MAX +#elif defined(MAXPATHLEN) +# define LT_PATHMAX MAXPATHLEN +#else +# define LT_PATHMAX 1024 +#endif + +#ifndef S_IXOTH +# define S_IXOTH 0 +#endif +#ifndef S_IXGRP +# define S_IXGRP 0 +#endif + +/* path handling portability macros */ +#ifndef DIR_SEPARATOR +# define DIR_SEPARATOR '/' +# define PATH_SEPARATOR ':' +#endif + +#if defined (_WIN32) || defined (__MSDOS__) || defined (__DJGPP__) || \ + defined (__OS2__) +# define HAVE_DOS_BASED_FILE_SYSTEM +# define FOPEN_WB "wb" +# ifndef DIR_SEPARATOR_2 +# define DIR_SEPARATOR_2 '\\' +# endif +# ifndef PATH_SEPARATOR_2 +# define PATH_SEPARATOR_2 ';' +# endif +#endif + +#ifndef DIR_SEPARATOR_2 +# define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR) +#else /* DIR_SEPARATOR_2 */ +# define IS_DIR_SEPARATOR(ch) \ + (((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2)) +#endif /* DIR_SEPARATOR_2 */ + +#ifndef PATH_SEPARATOR_2 +# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR) +#else /* PATH_SEPARATOR_2 */ +# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR_2) +#endif /* PATH_SEPARATOR_2 */ + +#ifndef FOPEN_WB +# define FOPEN_WB "w" +#endif +#ifndef _O_BINARY +# define _O_BINARY 0 +#endif + +#define XMALLOC(type, num) ((type *) xmalloc ((num) * sizeof(type))) +#define XFREE(stale) do { \ + if (stale) { free ((void *) stale); stale = 0; } \ +} while (0) + +#if defined(LT_DEBUGWRAPPER) +static int lt_debug = 1; +#else +static int lt_debug = 0; +#endif + +const char *program_name = "libtool-wrapper"; /* in case xstrdup fails */ + +void *xmalloc (size_t num); +char *xstrdup (const char *string); +const char *base_name (const char *name); +char *find_executable (const char *wrapper); +char *chase_symlinks (const char *pathspec); +int make_executable (const char *path); +int check_executable (const char *path); +char *strendzap (char *str, const char *pat); +void lt_debugprintf (const char *file, int line, const char *fmt, ...); +void lt_fatal (const char *file, int line, const char *message, ...); +static const char *nonnull (const char *s); +static const char *nonempty (const char *s); +void lt_setenv (const char *name, const char *value); +char *lt_extend_str (const char *orig_value, const char *add, int to_end); +void lt_update_exe_path (const char *name, const char *value); +void lt_update_lib_path (const char *name, const char *value); +char **prepare_spawn (char **argv); +void lt_dump_script (FILE *f); +EOF + + cat <= 0) + && (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))) + return 1; + else + return 0; +} + +int +make_executable (const char *path) +{ + int rval = 0; + struct stat st; + + lt_debugprintf (__FILE__, __LINE__, "(make_executable): %s\n", + nonempty (path)); + if ((!path) || (!*path)) + return 0; + + if (stat (path, &st) >= 0) + { + rval = chmod (path, st.st_mode | S_IXOTH | S_IXGRP | S_IXUSR); + } + return rval; +} + +/* Searches for the full path of the wrapper. Returns + newly allocated full path name if found, NULL otherwise + Does not chase symlinks, even on platforms that support them. +*/ +char * +find_executable (const char *wrapper) +{ + int has_slash = 0; + const char *p; + const char *p_next; + /* static buffer for getcwd */ + char tmp[LT_PATHMAX + 1]; + int tmp_len; + char *concat_name; + + lt_debugprintf (__FILE__, __LINE__, "(find_executable): %s\n", + nonempty (wrapper)); + + if ((wrapper == NULL) || (*wrapper == '\0')) + return NULL; + + /* Absolute path? */ +#if defined (HAVE_DOS_BASED_FILE_SYSTEM) + if (isalpha ((unsigned char) wrapper[0]) && wrapper[1] == ':') + { + concat_name = xstrdup (wrapper); + if (check_executable (concat_name)) + return concat_name; + XFREE (concat_name); + } + else + { +#endif + if (IS_DIR_SEPARATOR (wrapper[0])) + { + concat_name = xstrdup (wrapper); + if (check_executable (concat_name)) + return concat_name; + XFREE (concat_name); + } +#if defined (HAVE_DOS_BASED_FILE_SYSTEM) + } +#endif + + for (p = wrapper; *p; p++) + if (*p == '/') + { + has_slash = 1; + break; + } + if (!has_slash) + { + /* no slashes; search PATH */ + const char *path = getenv ("PATH"); + if (path != NULL) + { + for (p = path; *p; p = p_next) + { + const char *q; + size_t p_len; + for (q = p; *q; q++) + if (IS_PATH_SEPARATOR (*q)) + break; + p_len = q - p; + p_next = (*q == '\0' ? q : q + 1); + if (p_len == 0) + { + /* empty path: current directory */ + if (getcwd (tmp, LT_PATHMAX) == NULL) + lt_fatal (__FILE__, __LINE__, "getcwd failed: %s", + nonnull (strerror (errno))); + tmp_len = strlen (tmp); + concat_name = + XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1); + memcpy (concat_name, tmp, tmp_len); + concat_name[tmp_len] = '/'; + strcpy (concat_name + tmp_len + 1, wrapper); + } + else + { + concat_name = + XMALLOC (char, p_len + 1 + strlen (wrapper) + 1); + memcpy (concat_name, p, p_len); + concat_name[p_len] = '/'; + strcpy (concat_name + p_len + 1, wrapper); + } + if (check_executable (concat_name)) + return concat_name; + XFREE (concat_name); + } + } + /* not found in PATH; assume curdir */ + } + /* Relative path | not found in path: prepend cwd */ + if (getcwd (tmp, LT_PATHMAX) == NULL) + lt_fatal (__FILE__, __LINE__, "getcwd failed: %s", + nonnull (strerror (errno))); + tmp_len = strlen (tmp); + concat_name = XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1); + memcpy (concat_name, tmp, tmp_len); + concat_name[tmp_len] = '/'; + strcpy (concat_name + tmp_len + 1, wrapper); + + if (check_executable (concat_name)) + return concat_name; + XFREE (concat_name); + return NULL; +} + +char * +chase_symlinks (const char *pathspec) +{ +#ifndef S_ISLNK + return xstrdup (pathspec); +#else + char buf[LT_PATHMAX]; + struct stat s; + char *tmp_pathspec = xstrdup (pathspec); + char *p; + int has_symlinks = 0; + while (strlen (tmp_pathspec) && !has_symlinks) + { + lt_debugprintf (__FILE__, __LINE__, + "checking path component for symlinks: %s\n", + tmp_pathspec); + if (lstat (tmp_pathspec, &s) == 0) + { + if (S_ISLNK (s.st_mode) != 0) + { + has_symlinks = 1; + break; + } + + /* search backwards for last DIR_SEPARATOR */ + p = tmp_pathspec + strlen (tmp_pathspec) - 1; + while ((p > tmp_pathspec) && (!IS_DIR_SEPARATOR (*p))) + p--; + if ((p == tmp_pathspec) && (!IS_DIR_SEPARATOR (*p))) + { + /* no more DIR_SEPARATORS left */ + break; + } + *p = '\0'; + } + else + { + lt_fatal (__FILE__, __LINE__, + "error accessing file \"%s\": %s", + tmp_pathspec, nonnull (strerror (errno))); + } + } + XFREE (tmp_pathspec); + + if (!has_symlinks) + { + return xstrdup (pathspec); + } + + tmp_pathspec = realpath (pathspec, buf); + if (tmp_pathspec == 0) + { + lt_fatal (__FILE__, __LINE__, + "could not follow symlinks for %s", pathspec); + } + return xstrdup (tmp_pathspec); +#endif +} + +char * +strendzap (char *str, const char *pat) +{ + size_t len, patlen; + + assert (str != NULL); + assert (pat != NULL); + + len = strlen (str); + patlen = strlen (pat); + + if (patlen <= len) + { + str += len - patlen; + if (strcmp (str, pat) == 0) + *str = '\0'; + } + return str; +} + +void +lt_debugprintf (const char *file, int line, const char *fmt, ...) +{ + va_list args; + if (lt_debug) + { + (void) fprintf (stderr, "%s:%s:%d: ", program_name, file, line); + va_start (args, fmt); + (void) vfprintf (stderr, fmt, args); + va_end (args); + } +} + +static void +lt_error_core (int exit_status, const char *file, + int line, const char *mode, + const char *message, va_list ap) +{ + fprintf (stderr, "%s:%s:%d: %s: ", program_name, file, line, mode); + vfprintf (stderr, message, ap); + fprintf (stderr, ".\n"); + + if (exit_status >= 0) + exit (exit_status); +} + +void +lt_fatal (const char *file, int line, const char *message, ...) +{ + va_list ap; + va_start (ap, message); + lt_error_core (EXIT_FAILURE, file, line, "FATAL", message, ap); + va_end (ap); +} + +static const char * +nonnull (const char *s) +{ + return s ? s : "(null)"; +} + +static const char * +nonempty (const char *s) +{ + return (s && !*s) ? "(empty)" : nonnull (s); +} + +void +lt_setenv (const char *name, const char *value) +{ + lt_debugprintf (__FILE__, __LINE__, + "(lt_setenv) setting '%s' to '%s'\n", + nonnull (name), nonnull (value)); + { +#ifdef HAVE_SETENV + /* always make a copy, for consistency with !HAVE_SETENV */ + char *str = xstrdup (value); + setenv (name, str, 1); +#else + int len = strlen (name) + 1 + strlen (value) + 1; + char *str = XMALLOC (char, len); + sprintf (str, "%s=%s", name, value); + if (putenv (str) != EXIT_SUCCESS) + { + XFREE (str); + } +#endif + } +} + +char * +lt_extend_str (const char *orig_value, const char *add, int to_end) +{ + char *new_value; + if (orig_value && *orig_value) + { + int orig_value_len = strlen (orig_value); + int add_len = strlen (add); + new_value = XMALLOC (char, add_len + orig_value_len + 1); + if (to_end) + { + strcpy (new_value, orig_value); + strcpy (new_value + orig_value_len, add); + } + else + { + strcpy (new_value, add); + strcpy (new_value + add_len, orig_value); + } + } + else + { + new_value = xstrdup (add); + } + return new_value; +} + +void +lt_update_exe_path (const char *name, const char *value) +{ + lt_debugprintf (__FILE__, __LINE__, + "(lt_update_exe_path) modifying '%s' by prepending '%s'\n", + nonnull (name), nonnull (value)); + + if (name && *name && value && *value) + { + char *new_value = lt_extend_str (getenv (name), value, 0); + /* some systems can't cope with a ':'-terminated path #' */ + int len = strlen (new_value); + while (((len = strlen (new_value)) > 0) && IS_PATH_SEPARATOR (new_value[len-1])) + { + new_value[len-1] = '\0'; + } + lt_setenv (name, new_value); + XFREE (new_value); + } +} + +void +lt_update_lib_path (const char *name, const char *value) +{ + lt_debugprintf (__FILE__, __LINE__, + "(lt_update_lib_path) modifying '%s' by prepending '%s'\n", + nonnull (name), nonnull (value)); + + if (name && *name && value && *value) + { + char *new_value = lt_extend_str (getenv (name), value, 0); + lt_setenv (name, new_value); + XFREE (new_value); + } +} + +EOF + case $host_os in + mingw*) + cat <<"EOF" + +/* Prepares an argument vector before calling spawn(). + Note that spawn() does not by itself call the command interpreter + (getenv ("COMSPEC") != NULL ? getenv ("COMSPEC") : + ({ OSVERSIONINFO v; v.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + GetVersionEx(&v); + v.dwPlatformId == VER_PLATFORM_WIN32_NT; + }) ? "cmd.exe" : "command.com"). + Instead it simply concatenates the arguments, separated by ' ', and calls + CreateProcess(). We must quote the arguments since Win32 CreateProcess() + interprets characters like ' ', '\t', '\\', '"' (but not '<' and '>') in a + special way: + - Space and tab are interpreted as delimiters. They are not treated as + delimiters if they are surrounded by double quotes: "...". + - Unescaped double quotes are removed from the input. Their only effect is + that within double quotes, space and tab are treated like normal + characters. + - Backslashes not followed by double quotes are not special. + - But 2*n+1 backslashes followed by a double quote become + n backslashes followed by a double quote (n >= 0): + \" -> " + \\\" -> \" + \\\\\" -> \\" + */ +#define SHELL_SPECIAL_CHARS "\"\\ \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037" +#define SHELL_SPACE_CHARS " \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037" +char ** +prepare_spawn (char **argv) +{ + size_t argc; + char **new_argv; + size_t i; + + /* Count number of arguments. */ + for (argc = 0; argv[argc] != NULL; argc++) + ; + + /* Allocate new argument vector. */ + new_argv = XMALLOC (char *, argc + 1); + + /* Put quoted arguments into the new argument vector. */ + for (i = 0; i < argc; i++) + { + const char *string = argv[i]; + + if (string[0] == '\0') + new_argv[i] = xstrdup ("\"\""); + else if (strpbrk (string, SHELL_SPECIAL_CHARS) != NULL) + { + int quote_around = (strpbrk (string, SHELL_SPACE_CHARS) != NULL); + size_t length; + unsigned int backslashes; + const char *s; + char *quoted_string; + char *p; + + length = 0; + backslashes = 0; + if (quote_around) + length++; + for (s = string; *s != '\0'; s++) + { + char c = *s; + if (c == '"') + length += backslashes + 1; + length++; + if (c == '\\') + backslashes++; + else + backslashes = 0; + } + if (quote_around) + length += backslashes + 1; + + quoted_string = XMALLOC (char, length + 1); + + p = quoted_string; + backslashes = 0; + if (quote_around) + *p++ = '"'; + for (s = string; *s != '\0'; s++) + { + char c = *s; + if (c == '"') + { + unsigned int j; + for (j = backslashes + 1; j > 0; j--) + *p++ = '\\'; + } + *p++ = c; + if (c == '\\') + backslashes++; + else + backslashes = 0; + } + if (quote_around) + { + unsigned int j; + for (j = backslashes; j > 0; j--) + *p++ = '\\'; + *p++ = '"'; + } + *p = '\0'; + + new_argv[i] = quoted_string; + } + else + new_argv[i] = (char *) string; + } + new_argv[argc] = NULL; + + return new_argv; +} +EOF + ;; + esac + + cat <<"EOF" +void lt_dump_script (FILE* f) +{ +EOF + func_emit_wrapper yes | + $SED -n -e ' +s/^\(.\{79\}\)\(..*\)/\1\ +\2/ +h +s/\([\\"]\)/\\\1/g +s/$/\\n/ +s/\([^\n]*\).*/ fputs ("\1", f);/p +g +D' + cat <<"EOF" +} +EOF +} +# end: func_emit_cwrapperexe_src + +# func_win32_import_lib_p ARG +# True if ARG is an import lib, as indicated by $file_magic_cmd +func_win32_import_lib_p () +{ + $opt_debug + case `eval $file_magic_cmd \"\$1\" 2>/dev/null | $SED -e 10q` in + *import*) : ;; + *) false ;; + esac +} + +# func_mode_link arg... +func_mode_link () +{ + $opt_debug + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) + # It is impossible to link a dll without this setting, and + # we shouldn't force the makefile maintainer to figure out + # which system we are compiling for in order to pass an extra + # flag for every libtool invocation. + # allow_undefined=no + + # FIXME: Unfortunately, there are problems with the above when trying + # to make a dll which has undefined symbols, in which case not + # even a static library is built. For now, we need to specify + # -no-undefined on the libtool link line when we can be certain + # that all symbols are satisfied, otherwise we get a static library. + allow_undefined=yes + ;; + *) + allow_undefined=yes + ;; + esac + libtool_args=$nonopt + base_compile="$nonopt $@" + compile_command=$nonopt + finalize_command=$nonopt + + compile_rpath= + finalize_rpath= + compile_shlibpath= + finalize_shlibpath= + convenience= + old_convenience= + deplibs= + old_deplibs= + compiler_flags= + linker_flags= + dllsearchpath= + lib_search_path=`pwd` + inst_prefix_dir= + new_inherited_linker_flags= + + avoid_version=no + bindir= + dlfiles= + dlprefiles= + dlself=no + export_dynamic=no + export_symbols= + export_symbols_regex= + generated= + libobjs= + ltlibs= + module=no + no_install=no + objs= + non_pic_objects= + precious_files_regex= + prefer_static_libs=no + preload=no + prev= + prevarg= + release= + rpath= + xrpath= + perm_rpath= + temp_rpath= + thread_safe=no + vinfo= + vinfo_number=no + weak_libs= + single_module="${wl}-single_module" + func_infer_tag $base_compile + + # We need to know -static, to get the right output filenames. + for arg + do + case $arg in + -shared) + test "$build_libtool_libs" != yes && \ + func_fatal_configuration "can not build a shared library" + build_old_libs=no + break + ;; + -all-static | -static | -static-libtool-libs) + case $arg in + -all-static) + if test "$build_libtool_libs" = yes && test -z "$link_static_flag"; then + func_warning "complete static linking is impossible in this configuration" + fi + if test -n "$link_static_flag"; then + dlopen_self=$dlopen_self_static + fi + prefer_static_libs=yes + ;; + -static) + if test -z "$pic_flag" && test -n "$link_static_flag"; then + dlopen_self=$dlopen_self_static + fi + prefer_static_libs=built + ;; + -static-libtool-libs) + if test -z "$pic_flag" && test -n "$link_static_flag"; then + dlopen_self=$dlopen_self_static + fi + prefer_static_libs=yes + ;; + esac + build_libtool_libs=no + build_old_libs=yes + break + ;; + esac + done + + # See if our shared archives depend on static archives. + test -n "$old_archive_from_new_cmds" && build_old_libs=yes + + # Go through the arguments, transforming them on the way. + while test "$#" -gt 0; do + arg="$1" + shift + func_quote_for_eval "$arg" + qarg=$func_quote_for_eval_unquoted_result + func_append libtool_args " $func_quote_for_eval_result" + + # If the previous option needs an argument, assign it. + if test -n "$prev"; then + case $prev in + output) + func_append compile_command " @OUTPUT@" + func_append finalize_command " @OUTPUT@" + ;; + esac + + case $prev in + bindir) + bindir="$arg" + prev= + continue + ;; + dlfiles|dlprefiles) + if test "$preload" = no; then + # Add the symbol object into the linking commands. + func_append compile_command " @SYMFILE@" + func_append finalize_command " @SYMFILE@" + preload=yes + fi + case $arg in + *.la | *.lo) ;; # We handle these cases below. + force) + if test "$dlself" = no; then + dlself=needless + export_dynamic=yes + fi + prev= + continue + ;; + self) + if test "$prev" = dlprefiles; then + dlself=yes + elif test "$prev" = dlfiles && test "$dlopen_self" != yes; then + dlself=yes + else + dlself=needless + export_dynamic=yes + fi + prev= + continue + ;; + *) + if test "$prev" = dlfiles; then + func_append dlfiles " $arg" + else + func_append dlprefiles " $arg" + fi + prev= + continue + ;; + esac + ;; + expsyms) + export_symbols="$arg" + test -f "$arg" \ + || func_fatal_error "symbol file \`$arg' does not exist" + prev= + continue + ;; + expsyms_regex) + export_symbols_regex="$arg" + prev= + continue + ;; + framework) + case $host in + *-*-darwin*) + case "$deplibs " in + *" $qarg.ltframework "*) ;; + *) func_append deplibs " $qarg.ltframework" # this is fixed later + ;; + esac + ;; + esac + prev= + continue + ;; + inst_prefix) + inst_prefix_dir="$arg" + prev= + continue + ;; + objectlist) + if test -f "$arg"; then + save_arg=$arg + moreargs= + for fil in `cat "$save_arg"` + do +# func_append moreargs " $fil" + arg=$fil + # A libtool-controlled object. + + # Check to see that this really is a libtool object. + if func_lalib_unsafe_p "$arg"; then + pic_object= + non_pic_object= + + # Read the .lo file + func_source "$arg" + + if test -z "$pic_object" || + test -z "$non_pic_object" || + test "$pic_object" = none && + test "$non_pic_object" = none; then + func_fatal_error "cannot find name of object for \`$arg'" + fi + + # Extract subdirectory from the argument. + func_dirname "$arg" "/" "" + xdir="$func_dirname_result" + + if test "$pic_object" != none; then + # Prepend the subdirectory the object is found in. + pic_object="$xdir$pic_object" + + if test "$prev" = dlfiles; then + if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then + func_append dlfiles " $pic_object" + prev= + continue + else + # If libtool objects are unsupported, then we need to preload. + prev=dlprefiles + fi + fi + + # CHECK ME: I think I busted this. -Ossama + if test "$prev" = dlprefiles; then + # Preload the old-style object. + func_append dlprefiles " $pic_object" + prev= + fi + + # A PIC object. + func_append libobjs " $pic_object" + arg="$pic_object" + fi + + # Non-PIC object. + if test "$non_pic_object" != none; then + # Prepend the subdirectory the object is found in. + non_pic_object="$xdir$non_pic_object" + + # A standard non-PIC object + func_append non_pic_objects " $non_pic_object" + if test -z "$pic_object" || test "$pic_object" = none ; then + arg="$non_pic_object" + fi + else + # If the PIC object exists, use it instead. + # $xdir was prepended to $pic_object above. + non_pic_object="$pic_object" + func_append non_pic_objects " $non_pic_object" + fi + else + # Only an error if not doing a dry-run. + if $opt_dry_run; then + # Extract subdirectory from the argument. + func_dirname "$arg" "/" "" + xdir="$func_dirname_result" + + func_lo2o "$arg" + pic_object=$xdir$objdir/$func_lo2o_result + non_pic_object=$xdir$func_lo2o_result + func_append libobjs " $pic_object" + func_append non_pic_objects " $non_pic_object" + else + func_fatal_error "\`$arg' is not a valid libtool object" + fi + fi + done + else + func_fatal_error "link input file \`$arg' does not exist" + fi + arg=$save_arg + prev= + continue + ;; + precious_regex) + precious_files_regex="$arg" + prev= + continue + ;; + release) + release="-$arg" + prev= + continue + ;; + rpath | xrpath) + # We need an absolute path. + case $arg in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + func_fatal_error "only absolute run-paths are allowed" + ;; + esac + if test "$prev" = rpath; then + case "$rpath " in + *" $arg "*) ;; + *) func_append rpath " $arg" ;; + esac + else + case "$xrpath " in + *" $arg "*) ;; + *) func_append xrpath " $arg" ;; + esac + fi + prev= + continue + ;; + shrext) + shrext_cmds="$arg" + prev= + continue + ;; + weak) + func_append weak_libs " $arg" + prev= + continue + ;; + xcclinker) + func_append linker_flags " $qarg" + func_append compiler_flags " $qarg" + prev= + func_append compile_command " $qarg" + func_append finalize_command " $qarg" + continue + ;; + xcompiler) + func_append compiler_flags " $qarg" + prev= + func_append compile_command " $qarg" + func_append finalize_command " $qarg" + continue + ;; + xlinker) + func_append linker_flags " $qarg" + func_append compiler_flags " $wl$qarg" + prev= + func_append compile_command " $wl$qarg" + func_append finalize_command " $wl$qarg" + continue + ;; + *) + eval "$prev=\"\$arg\"" + prev= + continue + ;; + esac + fi # test -n "$prev" + + prevarg="$arg" + + case $arg in + -all-static) + if test -n "$link_static_flag"; then + # See comment for -static flag below, for more details. + func_append compile_command " $link_static_flag" + func_append finalize_command " $link_static_flag" + fi + continue + ;; + + -allow-undefined) + # FIXME: remove this flag sometime in the future. + func_fatal_error "\`-allow-undefined' must not be used because it is the default" + ;; + + -avoid-version) + avoid_version=yes + continue + ;; + + -bindir) + prev=bindir + continue + ;; + + -dlopen) + prev=dlfiles + continue + ;; + + -dlpreopen) + prev=dlprefiles + continue + ;; + + -export-dynamic) + export_dynamic=yes + continue + ;; + + -export-symbols | -export-symbols-regex) + if test -n "$export_symbols" || test -n "$export_symbols_regex"; then + func_fatal_error "more than one -exported-symbols argument is not allowed" + fi + if test "X$arg" = "X-export-symbols"; then + prev=expsyms + else + prev=expsyms_regex + fi + continue + ;; + + -framework) + prev=framework + continue + ;; + + -inst-prefix-dir) + prev=inst_prefix + continue + ;; + + # The native IRIX linker understands -LANG:*, -LIST:* and -LNO:* + # so, if we see these flags be careful not to treat them like -L + -L[A-Z][A-Z]*:*) + case $with_gcc/$host in + no/*-*-irix* | /*-*-irix*) + func_append compile_command " $arg" + func_append finalize_command " $arg" + ;; + esac + continue + ;; + + -L*) + func_stripname "-L" '' "$arg" + if test -z "$func_stripname_result"; then + if test "$#" -gt 0; then + func_fatal_error "require no space between \`-L' and \`$1'" + else + func_fatal_error "need path for \`-L' option" + fi + fi + func_resolve_sysroot "$func_stripname_result" + dir=$func_resolve_sysroot_result + # We need an absolute path. + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + absdir=`cd "$dir" && pwd` + test -z "$absdir" && \ + func_fatal_error "cannot determine absolute directory name of \`$dir'" + dir="$absdir" + ;; + esac + case "$deplibs " in + *" -L$dir "* | *" $arg "*) + # Will only happen for absolute or sysroot arguments + ;; + *) + # Preserve sysroot, but never include relative directories + case $dir in + [\\/]* | [A-Za-z]:[\\/]* | =*) func_append deplibs " $arg" ;; + *) func_append deplibs " -L$dir" ;; + esac + func_append lib_search_path " $dir" + ;; + esac + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) + testbindir=`$ECHO "$dir" | $SED 's*/lib$*/bin*'` + case :$dllsearchpath: in + *":$dir:"*) ;; + ::) dllsearchpath=$dir;; + *) func_append dllsearchpath ":$dir";; + esac + case :$dllsearchpath: in + *":$testbindir:"*) ;; + ::) dllsearchpath=$testbindir;; + *) func_append dllsearchpath ":$testbindir";; + esac + ;; + esac + continue + ;; + + -l*) + if test "X$arg" = "X-lc" || test "X$arg" = "X-lm"; then + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-beos* | *-cegcc* | *-*-haiku*) + # These systems don't actually have a C or math library (as such) + continue + ;; + *-*-os2*) + # These systems don't actually have a C library (as such) + test "X$arg" = "X-lc" && continue + ;; + *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) + # Do not include libc due to us having libc/libc_r. + test "X$arg" = "X-lc" && continue + ;; + *-*-rhapsody* | *-*-darwin1.[012]) + # Rhapsody C and math libraries are in the System framework + func_append deplibs " System.ltframework" + continue + ;; + *-*-sco3.2v5* | *-*-sco5v6*) + # Causes problems with __ctype + test "X$arg" = "X-lc" && continue + ;; + *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) + # Compiler inserts libc in the correct place for threads to work + test "X$arg" = "X-lc" && continue + ;; + esac + elif test "X$arg" = "X-lc_r"; then + case $host in + *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) + # Do not include libc_r directly, use -pthread flag. + continue + ;; + esac + fi + func_append deplibs " $arg" + continue + ;; + + -module) + module=yes + continue + ;; + + # Tru64 UNIX uses -model [arg] to determine the layout of C++ + # classes, name mangling, and exception handling. + # Darwin uses the -arch flag to determine output architecture. + -model|-arch|-isysroot|--sysroot) + func_append compiler_flags " $arg" + func_append compile_command " $arg" + func_append finalize_command " $arg" + prev=xcompiler + continue + ;; + + -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe \ + |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*) + func_append compiler_flags " $arg" + func_append compile_command " $arg" + func_append finalize_command " $arg" + case "$new_inherited_linker_flags " in + *" $arg "*) ;; + * ) func_append new_inherited_linker_flags " $arg" ;; + esac + continue + ;; + + -multi_module) + single_module="${wl}-multi_module" + continue + ;; + + -no-fast-install) + fast_install=no + continue + ;; + + -no-install) + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-darwin* | *-cegcc*) + # The PATH hackery in wrapper scripts is required on Windows + # and Darwin in order for the loader to find any dlls it needs. + func_warning "\`-no-install' is ignored for $host" + func_warning "assuming \`-no-fast-install' instead" + fast_install=no + ;; + *) no_install=yes ;; + esac + continue + ;; + + -no-undefined) + allow_undefined=no + continue + ;; + + -objectlist) + prev=objectlist + continue + ;; + + -o) prev=output ;; + + -precious-files-regex) + prev=precious_regex + continue + ;; + + -release) + prev=release + continue + ;; + + -rpath) + prev=rpath + continue + ;; + + -R) + prev=xrpath + continue + ;; + + -R*) + func_stripname '-R' '' "$arg" + dir=$func_stripname_result + # We need an absolute path. + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) ;; + =*) + func_stripname '=' '' "$dir" + dir=$lt_sysroot$func_stripname_result + ;; + *) + func_fatal_error "only absolute run-paths are allowed" + ;; + esac + case "$xrpath " in + *" $dir "*) ;; + *) func_append xrpath " $dir" ;; + esac + continue + ;; + + -shared) + # The effects of -shared are defined in a previous loop. + continue + ;; + + -shrext) + prev=shrext + continue + ;; + + -static | -static-libtool-libs) + # The effects of -static are defined in a previous loop. + # We used to do the same as -all-static on platforms that + # didn't have a PIC flag, but the assumption that the effects + # would be equivalent was wrong. It would break on at least + # Digital Unix and AIX. + continue + ;; + + -thread-safe) + thread_safe=yes + continue + ;; + + -version-info) + prev=vinfo + continue + ;; + + -version-number) + prev=vinfo + vinfo_number=yes + continue + ;; + + -weak) + prev=weak + continue + ;; + + -Wc,*) + func_stripname '-Wc,' '' "$arg" + args=$func_stripname_result + arg= + save_ifs="$IFS"; IFS=',' + for flag in $args; do + IFS="$save_ifs" + func_quote_for_eval "$flag" + func_append arg " $func_quote_for_eval_result" + func_append compiler_flags " $func_quote_for_eval_result" + done + IFS="$save_ifs" + func_stripname ' ' '' "$arg" + arg=$func_stripname_result + ;; + + -Wl,*) + func_stripname '-Wl,' '' "$arg" + args=$func_stripname_result + arg= + save_ifs="$IFS"; IFS=',' + for flag in $args; do + IFS="$save_ifs" + func_quote_for_eval "$flag" + func_append arg " $wl$func_quote_for_eval_result" + func_append compiler_flags " $wl$func_quote_for_eval_result" + func_append linker_flags " $func_quote_for_eval_result" + done + IFS="$save_ifs" + func_stripname ' ' '' "$arg" + arg=$func_stripname_result + ;; + + -Xcompiler) + prev=xcompiler + continue + ;; + + -Xlinker) + prev=xlinker + continue + ;; + + -XCClinker) + prev=xcclinker + continue + ;; + + # -msg_* for osf cc + -msg_*) + func_quote_for_eval "$arg" + arg="$func_quote_for_eval_result" + ;; + + # Flags to be passed through unchanged, with rationale: + # -64, -mips[0-9] enable 64-bit mode for the SGI compiler + # -r[0-9][0-9]* specify processor for the SGI compiler + # -xarch=*, -xtarget=* enable 64-bit mode for the Sun compiler + # +DA*, +DD* enable 64-bit mode for the HP compiler + # -q* compiler args for the IBM compiler + # -m*, -t[45]*, -txscale* architecture-specific flags for GCC + # -F/path path to uninstalled frameworks, gcc on darwin + # -p, -pg, --coverage, -fprofile-* profiling flags for GCC + # @file GCC response files + # -tp=* Portland pgcc target processor selection + # --sysroot=* for sysroot support + # -O*, -flto*, -fwhopr*, -fuse-linker-plugin GCC link-time optimization + -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \ + -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*|--sysroot=*| \ + -O*|-flto*|-fwhopr*|-fuse-linker-plugin) + func_quote_for_eval "$arg" + arg="$func_quote_for_eval_result" + func_append compile_command " $arg" + func_append finalize_command " $arg" + func_append compiler_flags " $arg" + continue + ;; + + # Some other compiler flag. + -* | +*) + func_quote_for_eval "$arg" + arg="$func_quote_for_eval_result" + ;; + + *.$objext) + # A standard object. + func_append objs " $arg" + ;; + + *.lo) + # A libtool-controlled object. + + # Check to see that this really is a libtool object. + if func_lalib_unsafe_p "$arg"; then + pic_object= + non_pic_object= + + # Read the .lo file + func_source "$arg" + + if test -z "$pic_object" || + test -z "$non_pic_object" || + test "$pic_object" = none && + test "$non_pic_object" = none; then + func_fatal_error "cannot find name of object for \`$arg'" + fi + + # Extract subdirectory from the argument. + func_dirname "$arg" "/" "" + xdir="$func_dirname_result" + + if test "$pic_object" != none; then + # Prepend the subdirectory the object is found in. + pic_object="$xdir$pic_object" + + if test "$prev" = dlfiles; then + if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then + func_append dlfiles " $pic_object" + prev= + continue + else + # If libtool objects are unsupported, then we need to preload. + prev=dlprefiles + fi + fi + + # CHECK ME: I think I busted this. -Ossama + if test "$prev" = dlprefiles; then + # Preload the old-style object. + func_append dlprefiles " $pic_object" + prev= + fi + + # A PIC object. + func_append libobjs " $pic_object" + arg="$pic_object" + fi + + # Non-PIC object. + if test "$non_pic_object" != none; then + # Prepend the subdirectory the object is found in. + non_pic_object="$xdir$non_pic_object" + + # A standard non-PIC object + func_append non_pic_objects " $non_pic_object" + if test -z "$pic_object" || test "$pic_object" = none ; then + arg="$non_pic_object" + fi + else + # If the PIC object exists, use it instead. + # $xdir was prepended to $pic_object above. + non_pic_object="$pic_object" + func_append non_pic_objects " $non_pic_object" + fi + else + # Only an error if not doing a dry-run. + if $opt_dry_run; then + # Extract subdirectory from the argument. + func_dirname "$arg" "/" "" + xdir="$func_dirname_result" + + func_lo2o "$arg" + pic_object=$xdir$objdir/$func_lo2o_result + non_pic_object=$xdir$func_lo2o_result + func_append libobjs " $pic_object" + func_append non_pic_objects " $non_pic_object" + else + func_fatal_error "\`$arg' is not a valid libtool object" + fi + fi + ;; + + *.$libext) + # An archive. + func_append deplibs " $arg" + func_append old_deplibs " $arg" + continue + ;; + + *.la) + # A libtool-controlled library. + + func_resolve_sysroot "$arg" + if test "$prev" = dlfiles; then + # This library was specified with -dlopen. + func_append dlfiles " $func_resolve_sysroot_result" + prev= + elif test "$prev" = dlprefiles; then + # The library was specified with -dlpreopen. + func_append dlprefiles " $func_resolve_sysroot_result" + prev= + else + func_append deplibs " $func_resolve_sysroot_result" + fi + continue + ;; + + # Some other compiler argument. + *) + # Unknown arguments in both finalize_command and compile_command need + # to be aesthetically quoted because they are evaled later. + func_quote_for_eval "$arg" + arg="$func_quote_for_eval_result" + ;; + esac # arg + + # Now actually substitute the argument into the commands. + if test -n "$arg"; then + func_append compile_command " $arg" + func_append finalize_command " $arg" + fi + done # argument parsing loop + + test -n "$prev" && \ + func_fatal_help "the \`$prevarg' option requires an argument" + + if test "$export_dynamic" = yes && test -n "$export_dynamic_flag_spec"; then + eval arg=\"$export_dynamic_flag_spec\" + func_append compile_command " $arg" + func_append finalize_command " $arg" + fi + + oldlibs= + # calculate the name of the file, without its directory + func_basename "$output" + outputname="$func_basename_result" + libobjs_save="$libobjs" + + if test -n "$shlibpath_var"; then + # get the directories listed in $shlibpath_var + eval shlib_search_path=\`\$ECHO \"\${$shlibpath_var}\" \| \$SED \'s/:/ /g\'\` + else + shlib_search_path= + fi + eval sys_lib_search_path=\"$sys_lib_search_path_spec\" + eval sys_lib_dlsearch_path=\"$sys_lib_dlsearch_path_spec\" + + func_dirname "$output" "/" "" + output_objdir="$func_dirname_result$objdir" + func_to_tool_file "$output_objdir/" + tool_output_objdir=$func_to_tool_file_result + # Create the object directory. + func_mkdir_p "$output_objdir" + + # Determine the type of output + case $output in + "") + func_fatal_help "you must specify an output file" + ;; + *.$libext) linkmode=oldlib ;; + *.lo | *.$objext) linkmode=obj ;; + *.la) linkmode=lib ;; + *) linkmode=prog ;; # Anything else should be a program. + esac + + specialdeplibs= + + libs= + # Find all interdependent deplibs by searching for libraries + # that are linked more than once (e.g. -la -lb -la) + for deplib in $deplibs; do + if $opt_preserve_dup_deps ; then + case "$libs " in + *" $deplib "*) func_append specialdeplibs " $deplib" ;; + esac + fi + func_append libs " $deplib" + done + + if test "$linkmode" = lib; then + libs="$predeps $libs $compiler_lib_search_path $postdeps" + + # Compute libraries that are listed more than once in $predeps + # $postdeps and mark them as special (i.e., whose duplicates are + # not to be eliminated). + pre_post_deps= + if $opt_duplicate_compiler_generated_deps; then + for pre_post_dep in $predeps $postdeps; do + case "$pre_post_deps " in + *" $pre_post_dep "*) func_append specialdeplibs " $pre_post_deps" ;; + esac + func_append pre_post_deps " $pre_post_dep" + done + fi + pre_post_deps= + fi + + deplibs= + newdependency_libs= + newlib_search_path= + need_relink=no # whether we're linking any uninstalled libtool libraries + notinst_deplibs= # not-installed libtool libraries + notinst_path= # paths that contain not-installed libtool libraries + + case $linkmode in + lib) + passes="conv dlpreopen link" + for file in $dlfiles $dlprefiles; do + case $file in + *.la) ;; + *) + func_fatal_help "libraries can \`-dlopen' only libtool libraries: $file" + ;; + esac + done + ;; + prog) + compile_deplibs= + finalize_deplibs= + alldeplibs=no + newdlfiles= + newdlprefiles= + passes="conv scan dlopen dlpreopen link" + ;; + *) passes="conv" + ;; + esac + + for pass in $passes; do + # The preopen pass in lib mode reverses $deplibs; put it back here + # so that -L comes before libs that need it for instance... + if test "$linkmode,$pass" = "lib,link"; then + ## FIXME: Find the place where the list is rebuilt in the wrong + ## order, and fix it there properly + tmp_deplibs= + for deplib in $deplibs; do + tmp_deplibs="$deplib $tmp_deplibs" + done + deplibs="$tmp_deplibs" + fi + + if test "$linkmode,$pass" = "lib,link" || + test "$linkmode,$pass" = "prog,scan"; then + libs="$deplibs" + deplibs= + fi + if test "$linkmode" = prog; then + case $pass in + dlopen) libs="$dlfiles" ;; + dlpreopen) libs="$dlprefiles" ;; + link) + libs="$deplibs %DEPLIBS%" + test "X$link_all_deplibs" != Xno && libs="$libs $dependency_libs" + ;; + esac + fi + if test "$linkmode,$pass" = "lib,dlpreopen"; then + # Collect and forward deplibs of preopened libtool libs + for lib in $dlprefiles; do + # Ignore non-libtool-libs + dependency_libs= + func_resolve_sysroot "$lib" + case $lib in + *.la) func_source "$func_resolve_sysroot_result" ;; + esac + + # Collect preopened libtool deplibs, except any this library + # has declared as weak libs + for deplib in $dependency_libs; do + func_basename "$deplib" + deplib_base=$func_basename_result + case " $weak_libs " in + *" $deplib_base "*) ;; + *) func_append deplibs " $deplib" ;; + esac + done + done + libs="$dlprefiles" + fi + if test "$pass" = dlopen; then + # Collect dlpreopened libraries + save_deplibs="$deplibs" + deplibs= + fi + + for deplib in $libs; do + lib= + found=no + case $deplib in + -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe \ + |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*) + if test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + func_append compiler_flags " $deplib" + if test "$linkmode" = lib ; then + case "$new_inherited_linker_flags " in + *" $deplib "*) ;; + * ) func_append new_inherited_linker_flags " $deplib" ;; + esac + fi + fi + continue + ;; + -l*) + if test "$linkmode" != lib && test "$linkmode" != prog; then + func_warning "\`-l' is ignored for archives/objects" + continue + fi + func_stripname '-l' '' "$deplib" + name=$func_stripname_result + if test "$linkmode" = lib; then + searchdirs="$newlib_search_path $lib_search_path $compiler_lib_search_dirs $sys_lib_search_path $shlib_search_path" + else + searchdirs="$newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path" + fi + for searchdir in $searchdirs; do + for search_ext in .la $std_shrext .so .a; do + # Search the libtool library + lib="$searchdir/lib${name}${search_ext}" + if test -f "$lib"; then + if test "$search_ext" = ".la"; then + found=yes + else + found=no + fi + break 2 + fi + done + done + if test "$found" != yes; then + # deplib doesn't seem to be a libtool library + if test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + deplibs="$deplib $deplibs" + test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs" + fi + continue + else # deplib is a libtool library + # If $allow_libtool_libs_with_static_runtimes && $deplib is a stdlib, + # We need to do some special things here, and not later. + if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then + case " $predeps $postdeps " in + *" $deplib "*) + if func_lalib_p "$lib"; then + library_names= + old_library= + func_source "$lib" + for l in $old_library $library_names; do + ll="$l" + done + if test "X$ll" = "X$old_library" ; then # only static version available + found=no + func_dirname "$lib" "" "." + ladir="$func_dirname_result" + lib=$ladir/$old_library + if test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + deplibs="$deplib $deplibs" + test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs" + fi + continue + fi + fi + ;; + *) ;; + esac + fi + fi + ;; # -l + *.ltframework) + if test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + deplibs="$deplib $deplibs" + if test "$linkmode" = lib ; then + case "$new_inherited_linker_flags " in + *" $deplib "*) ;; + * ) func_append new_inherited_linker_flags " $deplib" ;; + esac + fi + fi + continue + ;; + -L*) + case $linkmode in + lib) + deplibs="$deplib $deplibs" + test "$pass" = conv && continue + newdependency_libs="$deplib $newdependency_libs" + func_stripname '-L' '' "$deplib" + func_resolve_sysroot "$func_stripname_result" + func_append newlib_search_path " $func_resolve_sysroot_result" + ;; + prog) + if test "$pass" = conv; then + deplibs="$deplib $deplibs" + continue + fi + if test "$pass" = scan; then + deplibs="$deplib $deplibs" + else + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + fi + func_stripname '-L' '' "$deplib" + func_resolve_sysroot "$func_stripname_result" + func_append newlib_search_path " $func_resolve_sysroot_result" + ;; + *) + func_warning "\`-L' is ignored for archives/objects" + ;; + esac # linkmode + continue + ;; # -L + -R*) + if test "$pass" = link; then + func_stripname '-R' '' "$deplib" + func_resolve_sysroot "$func_stripname_result" + dir=$func_resolve_sysroot_result + # Make sure the xrpath contains only unique directories. + case "$xrpath " in + *" $dir "*) ;; + *) func_append xrpath " $dir" ;; + esac + fi + deplibs="$deplib $deplibs" + continue + ;; + *.la) + func_resolve_sysroot "$deplib" + lib=$func_resolve_sysroot_result + ;; + *.$libext) + if test "$pass" = conv; then + deplibs="$deplib $deplibs" + continue + fi + case $linkmode in + lib) + # Linking convenience modules into shared libraries is allowed, + # but linking other static libraries is non-portable. + case " $dlpreconveniencelibs " in + *" $deplib "*) ;; + *) + valid_a_lib=no + case $deplibs_check_method in + match_pattern*) + set dummy $deplibs_check_method; shift + match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"` + if eval "\$ECHO \"$deplib\"" 2>/dev/null | $SED 10q \ + | $EGREP "$match_pattern_regex" > /dev/null; then + valid_a_lib=yes + fi + ;; + pass_all) + valid_a_lib=yes + ;; + esac + if test "$valid_a_lib" != yes; then + echo + $ECHO "*** Warning: Trying to link with static lib archive $deplib." + echo "*** I have the capability to make that library automatically link in when" + echo "*** you link to this library. But I can only do this if you have a" + echo "*** shared version of the library, which you do not appear to have" + echo "*** because the file extensions .$libext of this argument makes me believe" + echo "*** that it is just a static archive that I should not use here." + else + echo + $ECHO "*** Warning: Linking the shared library $output against the" + $ECHO "*** static library $deplib is not portable!" + deplibs="$deplib $deplibs" + fi + ;; + esac + continue + ;; + prog) + if test "$pass" != link; then + deplibs="$deplib $deplibs" + else + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + fi + continue + ;; + esac # linkmode + ;; # *.$libext + *.lo | *.$objext) + if test "$pass" = conv; then + deplibs="$deplib $deplibs" + elif test "$linkmode" = prog; then + if test "$pass" = dlpreopen || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then + # If there is no dlopen support or we're linking statically, + # we need to preload. + func_append newdlprefiles " $deplib" + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + func_append newdlfiles " $deplib" + fi + fi + continue + ;; + %DEPLIBS%) + alldeplibs=yes + continue + ;; + esac # case $deplib + + if test "$found" = yes || test -f "$lib"; then : + else + func_fatal_error "cannot find the library \`$lib' or unhandled argument \`$deplib'" + fi + + # Check to see that this really is a libtool archive. + func_lalib_unsafe_p "$lib" \ + || func_fatal_error "\`$lib' is not a valid libtool archive" + + func_dirname "$lib" "" "." + ladir="$func_dirname_result" + + dlname= + dlopen= + dlpreopen= + libdir= + library_names= + old_library= + inherited_linker_flags= + # If the library was installed with an old release of libtool, + # it will not redefine variables installed, or shouldnotlink + installed=yes + shouldnotlink=no + avoidtemprpath= + + + # Read the .la file + func_source "$lib" + + # Convert "-framework foo" to "foo.ltframework" + if test -n "$inherited_linker_flags"; then + tmp_inherited_linker_flags=`$ECHO "$inherited_linker_flags" | $SED 's/-framework \([^ $]*\)/\1.ltframework/g'` + for tmp_inherited_linker_flag in $tmp_inherited_linker_flags; do + case " $new_inherited_linker_flags " in + *" $tmp_inherited_linker_flag "*) ;; + *) func_append new_inherited_linker_flags " $tmp_inherited_linker_flag";; + esac + done + fi + dependency_libs=`$ECHO " $dependency_libs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + if test "$linkmode,$pass" = "lib,link" || + test "$linkmode,$pass" = "prog,scan" || + { test "$linkmode" != prog && test "$linkmode" != lib; }; then + test -n "$dlopen" && func_append dlfiles " $dlopen" + test -n "$dlpreopen" && func_append dlprefiles " $dlpreopen" + fi + + if test "$pass" = conv; then + # Only check for convenience libraries + deplibs="$lib $deplibs" + if test -z "$libdir"; then + if test -z "$old_library"; then + func_fatal_error "cannot find name of link library for \`$lib'" + fi + # It is a libtool convenience library, so add in its objects. + func_append convenience " $ladir/$objdir/$old_library" + func_append old_convenience " $ladir/$objdir/$old_library" + tmp_libs= + for deplib in $dependency_libs; do + deplibs="$deplib $deplibs" + if $opt_preserve_dup_deps ; then + case "$tmp_libs " in + *" $deplib "*) func_append specialdeplibs " $deplib" ;; + esac + fi + func_append tmp_libs " $deplib" + done + elif test "$linkmode" != prog && test "$linkmode" != lib; then + func_fatal_error "\`$lib' is not a convenience library" + fi + continue + fi # $pass = conv + + + # Get the name of the library we link against. + linklib= + if test -n "$old_library" && + { test "$prefer_static_libs" = yes || + test "$prefer_static_libs,$installed" = "built,no"; }; then + linklib=$old_library + else + for l in $old_library $library_names; do + linklib="$l" + done + fi + if test -z "$linklib"; then + func_fatal_error "cannot find name of link library for \`$lib'" + fi + + # This library was specified with -dlopen. + if test "$pass" = dlopen; then + if test -z "$libdir"; then + func_fatal_error "cannot -dlopen a convenience library: \`$lib'" + fi + if test -z "$dlname" || + test "$dlopen_support" != yes || + test "$build_libtool_libs" = no; then + # If there is no dlname, no dlopen support or we're linking + # statically, we need to preload. We also need to preload any + # dependent libraries so libltdl's deplib preloader doesn't + # bomb out in the load deplibs phase. + func_append dlprefiles " $lib $dependency_libs" + else + func_append newdlfiles " $lib" + fi + continue + fi # $pass = dlopen + + # We need an absolute path. + case $ladir in + [\\/]* | [A-Za-z]:[\\/]*) abs_ladir="$ladir" ;; + *) + abs_ladir=`cd "$ladir" && pwd` + if test -z "$abs_ladir"; then + func_warning "cannot determine absolute directory name of \`$ladir'" + func_warning "passing it literally to the linker, although it might fail" + abs_ladir="$ladir" + fi + ;; + esac + func_basename "$lib" + laname="$func_basename_result" + + # Find the relevant object directory and library name. + if test "X$installed" = Xyes; then + if test ! -f "$lt_sysroot$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then + func_warning "library \`$lib' was moved." + dir="$ladir" + absdir="$abs_ladir" + libdir="$abs_ladir" + else + dir="$lt_sysroot$libdir" + absdir="$lt_sysroot$libdir" + fi + test "X$hardcode_automatic" = Xyes && avoidtemprpath=yes + else + if test ! -f "$ladir/$objdir/$linklib" && test -f "$abs_ladir/$linklib"; then + dir="$ladir" + absdir="$abs_ladir" + # Remove this search path later + func_append notinst_path " $abs_ladir" + else + dir="$ladir/$objdir" + absdir="$abs_ladir/$objdir" + # Remove this search path later + func_append notinst_path " $abs_ladir" + fi + fi # $installed = yes + func_stripname 'lib' '.la' "$laname" + name=$func_stripname_result + + # This library was specified with -dlpreopen. + if test "$pass" = dlpreopen; then + if test -z "$libdir" && test "$linkmode" = prog; then + func_fatal_error "only libraries may -dlpreopen a convenience library: \`$lib'" + fi + case "$host" in + # special handling for platforms with PE-DLLs. + *cygwin* | *mingw* | *cegcc* ) + # Linker will automatically link against shared library if both + # static and shared are present. Therefore, ensure we extract + # symbols from the import library if a shared library is present + # (otherwise, the dlopen module name will be incorrect). We do + # this by putting the import library name into $newdlprefiles. + # We recover the dlopen module name by 'saving' the la file + # name in a special purpose variable, and (later) extracting the + # dlname from the la file. + if test -n "$dlname"; then + func_tr_sh "$dir/$linklib" + eval "libfile_$func_tr_sh_result=\$abs_ladir/\$laname" + func_append newdlprefiles " $dir/$linklib" + else + func_append newdlprefiles " $dir/$old_library" + # Keep a list of preopened convenience libraries to check + # that they are being used correctly in the link pass. + test -z "$libdir" && \ + func_append dlpreconveniencelibs " $dir/$old_library" + fi + ;; + * ) + # Prefer using a static library (so that no silly _DYNAMIC symbols + # are required to link). + if test -n "$old_library"; then + func_append newdlprefiles " $dir/$old_library" + # Keep a list of preopened convenience libraries to check + # that they are being used correctly in the link pass. + test -z "$libdir" && \ + func_append dlpreconveniencelibs " $dir/$old_library" + # Otherwise, use the dlname, so that lt_dlopen finds it. + elif test -n "$dlname"; then + func_append newdlprefiles " $dir/$dlname" + else + func_append newdlprefiles " $dir/$linklib" + fi + ;; + esac + fi # $pass = dlpreopen + + if test -z "$libdir"; then + # Link the convenience library + if test "$linkmode" = lib; then + deplibs="$dir/$old_library $deplibs" + elif test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$dir/$old_library $compile_deplibs" + finalize_deplibs="$dir/$old_library $finalize_deplibs" + else + deplibs="$lib $deplibs" # used for prog,scan pass + fi + continue + fi + + + if test "$linkmode" = prog && test "$pass" != link; then + func_append newlib_search_path " $ladir" + deplibs="$lib $deplibs" + + linkalldeplibs=no + if test "$link_all_deplibs" != no || test -z "$library_names" || + test "$build_libtool_libs" = no; then + linkalldeplibs=yes + fi + + tmp_libs= + for deplib in $dependency_libs; do + case $deplib in + -L*) func_stripname '-L' '' "$deplib" + func_resolve_sysroot "$func_stripname_result" + func_append newlib_search_path " $func_resolve_sysroot_result" + ;; + esac + # Need to link against all dependency_libs? + if test "$linkalldeplibs" = yes; then + deplibs="$deplib $deplibs" + else + # Need to hardcode shared library paths + # or/and link against static libraries + newdependency_libs="$deplib $newdependency_libs" + fi + if $opt_preserve_dup_deps ; then + case "$tmp_libs " in + *" $deplib "*) func_append specialdeplibs " $deplib" ;; + esac + fi + func_append tmp_libs " $deplib" + done # for deplib + continue + fi # $linkmode = prog... + + if test "$linkmode,$pass" = "prog,link"; then + if test -n "$library_names" && + { { test "$prefer_static_libs" = no || + test "$prefer_static_libs,$installed" = "built,yes"; } || + test -z "$old_library"; }; then + # We need to hardcode the library path + if test -n "$shlibpath_var" && test -z "$avoidtemprpath" ; then + # Make sure the rpath contains only unique directories. + case "$temp_rpath:" in + *"$absdir:"*) ;; + *) func_append temp_rpath "$absdir:" ;; + esac + fi + + # Hardcode the library path. + # Skip directories that are in the system default run-time + # search path. + case " $sys_lib_dlsearch_path " in + *" $absdir "*) ;; + *) + case "$compile_rpath " in + *" $absdir "*) ;; + *) func_append compile_rpath " $absdir" ;; + esac + ;; + esac + case " $sys_lib_dlsearch_path " in + *" $libdir "*) ;; + *) + case "$finalize_rpath " in + *" $libdir "*) ;; + *) func_append finalize_rpath " $libdir" ;; + esac + ;; + esac + fi # $linkmode,$pass = prog,link... + + if test "$alldeplibs" = yes && + { test "$deplibs_check_method" = pass_all || + { test "$build_libtool_libs" = yes && + test -n "$library_names"; }; }; then + # We only need to search for static libraries + continue + fi + fi + + link_static=no # Whether the deplib will be linked statically + use_static_libs=$prefer_static_libs + if test "$use_static_libs" = built && test "$installed" = yes; then + use_static_libs=no + fi + if test -n "$library_names" && + { test "$use_static_libs" = no || test -z "$old_library"; }; then + case $host in + *cygwin* | *mingw* | *cegcc*) + # No point in relinking DLLs because paths are not encoded + func_append notinst_deplibs " $lib" + need_relink=no + ;; + *) + if test "$installed" = no; then + func_append notinst_deplibs " $lib" + need_relink=yes + fi + ;; + esac + # This is a shared library + + # Warn about portability, can't link against -module's on some + # systems (darwin). Don't bleat about dlopened modules though! + dlopenmodule="" + for dlpremoduletest in $dlprefiles; do + if test "X$dlpremoduletest" = "X$lib"; then + dlopenmodule="$dlpremoduletest" + break + fi + done + if test -z "$dlopenmodule" && test "$shouldnotlink" = yes && test "$pass" = link; then + echo + if test "$linkmode" = prog; then + $ECHO "*** Warning: Linking the executable $output against the loadable module" + else + $ECHO "*** Warning: Linking the shared library $output against the loadable module" + fi + $ECHO "*** $linklib is not portable!" + fi + if test "$linkmode" = lib && + test "$hardcode_into_libs" = yes; then + # Hardcode the library path. + # Skip directories that are in the system default run-time + # search path. + case " $sys_lib_dlsearch_path " in + *" $absdir "*) ;; + *) + case "$compile_rpath " in + *" $absdir "*) ;; + *) func_append compile_rpath " $absdir" ;; + esac + ;; + esac + case " $sys_lib_dlsearch_path " in + *" $libdir "*) ;; + *) + case "$finalize_rpath " in + *" $libdir "*) ;; + *) func_append finalize_rpath " $libdir" ;; + esac + ;; + esac + fi + + if test -n "$old_archive_from_expsyms_cmds"; then + # figure out the soname + set dummy $library_names + shift + realname="$1" + shift + libname=`eval "\\$ECHO \"$libname_spec\""` + # use dlname if we got it. it's perfectly good, no? + if test -n "$dlname"; then + soname="$dlname" + elif test -n "$soname_spec"; then + # bleh windows + case $host in + *cygwin* | mingw* | *cegcc*) + func_arith $current - $age + major=$func_arith_result + versuffix="-$major" + ;; + esac + eval soname=\"$soname_spec\" + else + soname="$realname" + fi + + # Make a new name for the extract_expsyms_cmds to use + soroot="$soname" + func_basename "$soroot" + soname="$func_basename_result" + func_stripname 'lib' '.dll' "$soname" + newlib=libimp-$func_stripname_result.a + + # If the library has no export list, then create one now + if test -f "$output_objdir/$soname-def"; then : + else + func_verbose "extracting exported symbol list from \`$soname'" + func_execute_cmds "$extract_expsyms_cmds" 'exit $?' + fi + + # Create $newlib + if test -f "$output_objdir/$newlib"; then :; else + func_verbose "generating import library for \`$soname'" + func_execute_cmds "$old_archive_from_expsyms_cmds" 'exit $?' + fi + # make sure the library variables are pointing to the new library + dir=$output_objdir + linklib=$newlib + fi # test -n "$old_archive_from_expsyms_cmds" + + if test "$linkmode" = prog || test "$opt_mode" != relink; then + add_shlibpath= + add_dir= + add= + lib_linked=yes + case $hardcode_action in + immediate | unsupported) + if test "$hardcode_direct" = no; then + add="$dir/$linklib" + case $host in + *-*-sco3.2v5.0.[024]*) add_dir="-L$dir" ;; + *-*-sysv4*uw2*) add_dir="-L$dir" ;; + *-*-sysv5OpenUNIX* | *-*-sysv5UnixWare7.[01].[10]* | \ + *-*-unixware7*) add_dir="-L$dir" ;; + *-*-darwin* ) + # if the lib is a (non-dlopened) module then we can not + # link against it, someone is ignoring the earlier warnings + if /usr/bin/file -L $add 2> /dev/null | + $GREP ": [^:]* bundle" >/dev/null ; then + if test "X$dlopenmodule" != "X$lib"; then + $ECHO "*** Warning: lib $linklib is a module, not a shared library" + if test -z "$old_library" ; then + echo + echo "*** And there doesn't seem to be a static archive available" + echo "*** The link will probably fail, sorry" + else + add="$dir/$old_library" + fi + elif test -n "$old_library"; then + add="$dir/$old_library" + fi + fi + esac + elif test "$hardcode_minus_L" = no; then + case $host in + *-*-sunos*) add_shlibpath="$dir" ;; + esac + add_dir="-L$dir" + add="-l$name" + elif test "$hardcode_shlibpath_var" = no; then + add_shlibpath="$dir" + add="-l$name" + else + lib_linked=no + fi + ;; + relink) + if test "$hardcode_direct" = yes && + test "$hardcode_direct_absolute" = no; then + add="$dir/$linklib" + elif test "$hardcode_minus_L" = yes; then + add_dir="-L$absdir" + # Try looking first in the location we're being installed to. + if test -n "$inst_prefix_dir"; then + case $libdir in + [\\/]*) + func_append add_dir " -L$inst_prefix_dir$libdir" + ;; + esac + fi + add="-l$name" + elif test "$hardcode_shlibpath_var" = yes; then + add_shlibpath="$dir" + add="-l$name" + else + lib_linked=no + fi + ;; + *) lib_linked=no ;; + esac + + if test "$lib_linked" != yes; then + func_fatal_configuration "unsupported hardcode properties" + fi + + if test -n "$add_shlibpath"; then + case :$compile_shlibpath: in + *":$add_shlibpath:"*) ;; + *) func_append compile_shlibpath "$add_shlibpath:" ;; + esac + fi + if test "$linkmode" = prog; then + test -n "$add_dir" && compile_deplibs="$add_dir $compile_deplibs" + test -n "$add" && compile_deplibs="$add $compile_deplibs" + else + test -n "$add_dir" && deplibs="$add_dir $deplibs" + test -n "$add" && deplibs="$add $deplibs" + if test "$hardcode_direct" != yes && + test "$hardcode_minus_L" != yes && + test "$hardcode_shlibpath_var" = yes; then + case :$finalize_shlibpath: in + *":$libdir:"*) ;; + *) func_append finalize_shlibpath "$libdir:" ;; + esac + fi + fi + fi + + if test "$linkmode" = prog || test "$opt_mode" = relink; then + add_shlibpath= + add_dir= + add= + # Finalize command for both is simple: just hardcode it. + if test "$hardcode_direct" = yes && + test "$hardcode_direct_absolute" = no; then + add="$libdir/$linklib" + elif test "$hardcode_minus_L" = yes; then + add_dir="-L$libdir" + add="-l$name" + elif test "$hardcode_shlibpath_var" = yes; then + case :$finalize_shlibpath: in + *":$libdir:"*) ;; + *) func_append finalize_shlibpath "$libdir:" ;; + esac + add="-l$name" + elif test "$hardcode_automatic" = yes; then + if test -n "$inst_prefix_dir" && + test -f "$inst_prefix_dir$libdir/$linklib" ; then + add="$inst_prefix_dir$libdir/$linklib" + else + add="$libdir/$linklib" + fi + else + # We cannot seem to hardcode it, guess we'll fake it. + add_dir="-L$libdir" + # Try looking first in the location we're being installed to. + if test -n "$inst_prefix_dir"; then + case $libdir in + [\\/]*) + func_append add_dir " -L$inst_prefix_dir$libdir" + ;; + esac + fi + add="-l$name" + fi + + if test "$linkmode" = prog; then + test -n "$add_dir" && finalize_deplibs="$add_dir $finalize_deplibs" + test -n "$add" && finalize_deplibs="$add $finalize_deplibs" + else + test -n "$add_dir" && deplibs="$add_dir $deplibs" + test -n "$add" && deplibs="$add $deplibs" + fi + fi + elif test "$linkmode" = prog; then + # Here we assume that one of hardcode_direct or hardcode_minus_L + # is not unsupported. This is valid on all known static and + # shared platforms. + if test "$hardcode_direct" != unsupported; then + test -n "$old_library" && linklib="$old_library" + compile_deplibs="$dir/$linklib $compile_deplibs" + finalize_deplibs="$dir/$linklib $finalize_deplibs" + else + compile_deplibs="-l$name -L$dir $compile_deplibs" + finalize_deplibs="-l$name -L$dir $finalize_deplibs" + fi + elif test "$build_libtool_libs" = yes; then + # Not a shared library + if test "$deplibs_check_method" != pass_all; then + # We're trying link a shared library against a static one + # but the system doesn't support it. + + # Just print a warning and add the library to dependency_libs so + # that the program can be linked against the static library. + echo + $ECHO "*** Warning: This system can not link to static lib archive $lib." + echo "*** I have the capability to make that library automatically link in when" + echo "*** you link to this library. But I can only do this if you have a" + echo "*** shared version of the library, which you do not appear to have." + if test "$module" = yes; then + echo "*** But as you try to build a module library, libtool will still create " + echo "*** a static module, that should work as long as the dlopening application" + echo "*** is linked with the -dlopen flag to resolve symbols at runtime." + if test -z "$global_symbol_pipe"; then + echo + echo "*** However, this would only work if libtool was able to extract symbol" + echo "*** lists from a program, using \`nm' or equivalent, but libtool could" + echo "*** not find such a program. So, this module is probably useless." + echo "*** \`nm' from GNU binutils and a full rebuild may help." + fi + if test "$build_old_libs" = no; then + build_libtool_libs=module + build_old_libs=yes + else + build_libtool_libs=no + fi + fi + else + deplibs="$dir/$old_library $deplibs" + link_static=yes + fi + fi # link shared/static library? + + if test "$linkmode" = lib; then + if test -n "$dependency_libs" && + { test "$hardcode_into_libs" != yes || + test "$build_old_libs" = yes || + test "$link_static" = yes; }; then + # Extract -R from dependency_libs + temp_deplibs= + for libdir in $dependency_libs; do + case $libdir in + -R*) func_stripname '-R' '' "$libdir" + temp_xrpath=$func_stripname_result + case " $xrpath " in + *" $temp_xrpath "*) ;; + *) func_append xrpath " $temp_xrpath";; + esac;; + *) func_append temp_deplibs " $libdir";; + esac + done + dependency_libs="$temp_deplibs" + fi + + func_append newlib_search_path " $absdir" + # Link against this library + test "$link_static" = no && newdependency_libs="$abs_ladir/$laname $newdependency_libs" + # ... and its dependency_libs + tmp_libs= + for deplib in $dependency_libs; do + newdependency_libs="$deplib $newdependency_libs" + case $deplib in + -L*) func_stripname '-L' '' "$deplib" + func_resolve_sysroot "$func_stripname_result";; + *) func_resolve_sysroot "$deplib" ;; + esac + if $opt_preserve_dup_deps ; then + case "$tmp_libs " in + *" $func_resolve_sysroot_result "*) + func_append specialdeplibs " $func_resolve_sysroot_result" ;; + esac + fi + func_append tmp_libs " $func_resolve_sysroot_result" + done + + if test "$link_all_deplibs" != no; then + # Add the search paths of all dependency libraries + for deplib in $dependency_libs; do + path= + case $deplib in + -L*) path="$deplib" ;; + *.la) + func_resolve_sysroot "$deplib" + deplib=$func_resolve_sysroot_result + func_dirname "$deplib" "" "." + dir=$func_dirname_result + # We need an absolute path. + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) absdir="$dir" ;; + *) + absdir=`cd "$dir" && pwd` + if test -z "$absdir"; then + func_warning "cannot determine absolute directory name of \`$dir'" + absdir="$dir" + fi + ;; + esac + if $GREP "^installed=no" $deplib > /dev/null; then + case $host in + *-*-darwin*) + depdepl= + eval deplibrary_names=`${SED} -n -e 's/^library_names=\(.*\)$/\1/p' $deplib` + if test -n "$deplibrary_names" ; then + for tmp in $deplibrary_names ; do + depdepl=$tmp + done + if test -f "$absdir/$objdir/$depdepl" ; then + depdepl="$absdir/$objdir/$depdepl" + darwin_install_name=`${OTOOL} -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'` + if test -z "$darwin_install_name"; then + darwin_install_name=`${OTOOL64} -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'` + fi + func_append compiler_flags " ${wl}-dylib_file ${wl}${darwin_install_name}:${depdepl}" + func_append linker_flags " -dylib_file ${darwin_install_name}:${depdepl}" + path= + fi + fi + ;; + *) + path="-L$absdir/$objdir" + ;; + esac + else + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` + test -z "$libdir" && \ + func_fatal_error "\`$deplib' is not a valid libtool archive" + test "$absdir" != "$libdir" && \ + func_warning "\`$deplib' seems to be moved" + + path="-L$absdir" + fi + ;; + esac + case " $deplibs " in + *" $path "*) ;; + *) deplibs="$path $deplibs" ;; + esac + done + fi # link_all_deplibs != no + fi # linkmode = lib + done # for deplib in $libs + if test "$pass" = link; then + if test "$linkmode" = "prog"; then + compile_deplibs="$new_inherited_linker_flags $compile_deplibs" + finalize_deplibs="$new_inherited_linker_flags $finalize_deplibs" + else + compiler_flags="$compiler_flags "`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + fi + fi + dependency_libs="$newdependency_libs" + if test "$pass" = dlpreopen; then + # Link the dlpreopened libraries before other libraries + for deplib in $save_deplibs; do + deplibs="$deplib $deplibs" + done + fi + if test "$pass" != dlopen; then + if test "$pass" != conv; then + # Make sure lib_search_path contains only unique directories. + lib_search_path= + for dir in $newlib_search_path; do + case "$lib_search_path " in + *" $dir "*) ;; + *) func_append lib_search_path " $dir" ;; + esac + done + newlib_search_path= + fi + + if test "$linkmode,$pass" != "prog,link"; then + vars="deplibs" + else + vars="compile_deplibs finalize_deplibs" + fi + for var in $vars dependency_libs; do + # Add libraries to $var in reverse order + eval tmp_libs=\"\$$var\" + new_libs= + for deplib in $tmp_libs; do + # FIXME: Pedantically, this is the right thing to do, so + # that some nasty dependency loop isn't accidentally + # broken: + #new_libs="$deplib $new_libs" + # Pragmatically, this seems to cause very few problems in + # practice: + case $deplib in + -L*) new_libs="$deplib $new_libs" ;; + -R*) ;; + *) + # And here is the reason: when a library appears more + # than once as an explicit dependence of a library, or + # is implicitly linked in more than once by the + # compiler, it is considered special, and multiple + # occurrences thereof are not removed. Compare this + # with having the same library being listed as a + # dependency of multiple other libraries: in this case, + # we know (pedantically, we assume) the library does not + # need to be listed more than once, so we keep only the + # last copy. This is not always right, but it is rare + # enough that we require users that really mean to play + # such unportable linking tricks to link the library + # using -Wl,-lname, so that libtool does not consider it + # for duplicate removal. + case " $specialdeplibs " in + *" $deplib "*) new_libs="$deplib $new_libs" ;; + *) + case " $new_libs " in + *" $deplib "*) ;; + *) new_libs="$deplib $new_libs" ;; + esac + ;; + esac + ;; + esac + done + tmp_libs= + for deplib in $new_libs; do + case $deplib in + -L*) + case " $tmp_libs " in + *" $deplib "*) ;; + *) func_append tmp_libs " $deplib" ;; + esac + ;; + *) func_append tmp_libs " $deplib" ;; + esac + done + eval $var=\"$tmp_libs\" + done # for var + fi + # Last step: remove runtime libs from dependency_libs + # (they stay in deplibs) + tmp_libs= + for i in $dependency_libs ; do + case " $predeps $postdeps $compiler_lib_search_path " in + *" $i "*) + i="" + ;; + esac + if test -n "$i" ; then + func_append tmp_libs " $i" + fi + done + dependency_libs=$tmp_libs + done # for pass + if test "$linkmode" = prog; then + dlfiles="$newdlfiles" + fi + if test "$linkmode" = prog || test "$linkmode" = lib; then + dlprefiles="$newdlprefiles" + fi + + case $linkmode in + oldlib) + if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then + func_warning "\`-dlopen' is ignored for archives" + fi + + case " $deplibs" in + *\ -l* | *\ -L*) + func_warning "\`-l' and \`-L' are ignored for archives" ;; + esac + + test -n "$rpath" && \ + func_warning "\`-rpath' is ignored for archives" + + test -n "$xrpath" && \ + func_warning "\`-R' is ignored for archives" + + test -n "$vinfo" && \ + func_warning "\`-version-info/-version-number' is ignored for archives" + + test -n "$release" && \ + func_warning "\`-release' is ignored for archives" + + test -n "$export_symbols$export_symbols_regex" && \ + func_warning "\`-export-symbols' is ignored for archives" + + # Now set the variables for building old libraries. + build_libtool_libs=no + oldlibs="$output" + func_append objs "$old_deplibs" + ;; + + lib) + # Make sure we only generate libraries of the form `libNAME.la'. + case $outputname in + lib*) + func_stripname 'lib' '.la' "$outputname" + name=$func_stripname_result + eval shared_ext=\"$shrext_cmds\" + eval libname=\"$libname_spec\" + ;; + *) + test "$module" = no && \ + func_fatal_help "libtool library \`$output' must begin with \`lib'" + + if test "$need_lib_prefix" != no; then + # Add the "lib" prefix for modules if required + func_stripname '' '.la' "$outputname" + name=$func_stripname_result + eval shared_ext=\"$shrext_cmds\" + eval libname=\"$libname_spec\" + else + func_stripname '' '.la' "$outputname" + libname=$func_stripname_result + fi + ;; + esac + + if test -n "$objs"; then + if test "$deplibs_check_method" != pass_all; then + func_fatal_error "cannot build libtool library \`$output' from non-libtool objects on this host:$objs" + else + echo + $ECHO "*** Warning: Linking the shared library $output against the non-libtool" + $ECHO "*** objects $objs is not portable!" + func_append libobjs " $objs" + fi + fi + + test "$dlself" != no && \ + func_warning "\`-dlopen self' is ignored for libtool libraries" + + set dummy $rpath + shift + test "$#" -gt 1 && \ + func_warning "ignoring multiple \`-rpath's for a libtool library" + + install_libdir="$1" + + oldlibs= + if test -z "$rpath"; then + if test "$build_libtool_libs" = yes; then + # Building a libtool convenience library. + # Some compilers have problems with a `.al' extension so + # convenience libraries should have the same extension an + # archive normally would. + oldlibs="$output_objdir/$libname.$libext $oldlibs" + build_libtool_libs=convenience + build_old_libs=yes + fi + + test -n "$vinfo" && \ + func_warning "\`-version-info/-version-number' is ignored for convenience libraries" + + test -n "$release" && \ + func_warning "\`-release' is ignored for convenience libraries" + else + + # Parse the version information argument. + save_ifs="$IFS"; IFS=':' + set dummy $vinfo 0 0 0 + shift + IFS="$save_ifs" + + test -n "$7" && \ + func_fatal_help "too many parameters to \`-version-info'" + + # convert absolute version numbers to libtool ages + # this retains compatibility with .la files and attempts + # to make the code below a bit more comprehensible + + case $vinfo_number in + yes) + number_major="$1" + number_minor="$2" + number_revision="$3" + # + # There are really only two kinds -- those that + # use the current revision as the major version + # and those that subtract age and use age as + # a minor version. But, then there is irix + # which has an extra 1 added just for fun + # + case $version_type in + # correct linux to gnu/linux during the next big refactor + darwin|linux|osf|windows|none) + func_arith $number_major + $number_minor + current=$func_arith_result + age="$number_minor" + revision="$number_revision" + ;; + freebsd-aout|freebsd-elf|qnx|sunos) + current="$number_major" + revision="$number_minor" + age="0" + ;; + irix|nonstopux) + func_arith $number_major + $number_minor + current=$func_arith_result + age="$number_minor" + revision="$number_minor" + lt_irix_increment=no + ;; + *) + func_fatal_configuration "$modename: unknown library version type \`$version_type'" + ;; + esac + ;; + no) + current="$1" + revision="$2" + age="$3" + ;; + esac + + # Check that each of the things are valid numbers. + case $current in + 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; + *) + func_error "CURRENT \`$current' must be a nonnegative integer" + func_fatal_error "\`$vinfo' is not valid version information" + ;; + esac + + case $revision in + 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; + *) + func_error "REVISION \`$revision' must be a nonnegative integer" + func_fatal_error "\`$vinfo' is not valid version information" + ;; + esac + + case $age in + 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; + *) + func_error "AGE \`$age' must be a nonnegative integer" + func_fatal_error "\`$vinfo' is not valid version information" + ;; + esac + + if test "$age" -gt "$current"; then + func_error "AGE \`$age' is greater than the current interface number \`$current'" + func_fatal_error "\`$vinfo' is not valid version information" + fi + + # Calculate the version variables. + major= + versuffix= + verstring= + case $version_type in + none) ;; + + darwin) + # Like Linux, but with the current version available in + # verstring for coding it into the library header + func_arith $current - $age + major=.$func_arith_result + versuffix="$major.$age.$revision" + # Darwin ld doesn't like 0 for these options... + func_arith $current + 1 + minor_current=$func_arith_result + xlcverstring="${wl}-compatibility_version ${wl}$minor_current ${wl}-current_version ${wl}$minor_current.$revision" + verstring="-compatibility_version $minor_current -current_version $minor_current.$revision" + ;; + + freebsd-aout) + major=".$current" + versuffix=".$current.$revision"; + ;; + + freebsd-elf) + major=".$current" + versuffix=".$current" + ;; + + irix | nonstopux) + if test "X$lt_irix_increment" = "Xno"; then + func_arith $current - $age + else + func_arith $current - $age + 1 + fi + major=$func_arith_result + + case $version_type in + nonstopux) verstring_prefix=nonstopux ;; + *) verstring_prefix=sgi ;; + esac + verstring="$verstring_prefix$major.$revision" + + # Add in all the interfaces that we are compatible with. + loop=$revision + while test "$loop" -ne 0; do + func_arith $revision - $loop + iface=$func_arith_result + func_arith $loop - 1 + loop=$func_arith_result + verstring="$verstring_prefix$major.$iface:$verstring" + done + + # Before this point, $major must not contain `.'. + major=.$major + versuffix="$major.$revision" + ;; + + linux) # correct to gnu/linux during the next big refactor + func_arith $current - $age + major=.$func_arith_result + versuffix="$major.$age.$revision" + ;; + + osf) + func_arith $current - $age + major=.$func_arith_result + versuffix=".$current.$age.$revision" + verstring="$current.$age.$revision" + + # Add in all the interfaces that we are compatible with. + loop=$age + while test "$loop" -ne 0; do + func_arith $current - $loop + iface=$func_arith_result + func_arith $loop - 1 + loop=$func_arith_result + verstring="$verstring:${iface}.0" + done + + # Make executables depend on our current version. + func_append verstring ":${current}.0" + ;; + + qnx) + major=".$current" + versuffix=".$current" + ;; + + sunos) + major=".$current" + versuffix=".$current.$revision" + ;; + + windows) + # Use '-' rather than '.', since we only want one + # extension on DOS 8.3 filesystems. + func_arith $current - $age + major=$func_arith_result + versuffix="-$major" + ;; + + *) + func_fatal_configuration "unknown library version type \`$version_type'" + ;; + esac + + # Clear the version info if we defaulted, and they specified a release. + if test -z "$vinfo" && test -n "$release"; then + major= + case $version_type in + darwin) + # we can't check for "0.0" in archive_cmds due to quoting + # problems, so we reset it completely + verstring= + ;; + *) + verstring="0.0" + ;; + esac + if test "$need_version" = no; then + versuffix= + else + versuffix=".0.0" + fi + fi + + # Remove version info from name if versioning should be avoided + if test "$avoid_version" = yes && test "$need_version" = no; then + major= + versuffix= + verstring="" + fi + + # Check to see if the archive will have undefined symbols. + if test "$allow_undefined" = yes; then + if test "$allow_undefined_flag" = unsupported; then + func_warning "undefined symbols not allowed in $host shared libraries" + build_libtool_libs=no + build_old_libs=yes + fi + else + # Don't allow undefined symbols. + allow_undefined_flag="$no_undefined_flag" + fi + + fi + + func_generate_dlsyms "$libname" "$libname" "yes" + func_append libobjs " $symfileobj" + test "X$libobjs" = "X " && libobjs= + + if test "$opt_mode" != relink; then + # Remove our outputs, but don't remove object files since they + # may have been created when compiling PIC objects. + removelist= + tempremovelist=`$ECHO "$output_objdir/*"` + for p in $tempremovelist; do + case $p in + *.$objext | *.gcno) + ;; + $output_objdir/$outputname | $output_objdir/$libname.* | $output_objdir/${libname}${release}.*) + if test "X$precious_files_regex" != "X"; then + if $ECHO "$p" | $EGREP -e "$precious_files_regex" >/dev/null 2>&1 + then + continue + fi + fi + func_append removelist " $p" + ;; + *) ;; + esac + done + test -n "$removelist" && \ + func_show_eval "${RM}r \$removelist" + fi + + # Now set the variables for building old libraries. + if test "$build_old_libs" = yes && test "$build_libtool_libs" != convenience ; then + func_append oldlibs " $output_objdir/$libname.$libext" + + # Transform .lo files to .o files. + oldobjs="$objs "`$ECHO "$libobjs" | $SP2NL | $SED "/\.${libext}$/d; $lo2o" | $NL2SP` + fi + + # Eliminate all temporary directories. + #for path in $notinst_path; do + # lib_search_path=`$ECHO "$lib_search_path " | $SED "s% $path % %g"` + # deplibs=`$ECHO "$deplibs " | $SED "s% -L$path % %g"` + # dependency_libs=`$ECHO "$dependency_libs " | $SED "s% -L$path % %g"` + #done + + if test -n "$xrpath"; then + # If the user specified any rpath flags, then add them. + temp_xrpath= + for libdir in $xrpath; do + func_replace_sysroot "$libdir" + func_append temp_xrpath " -R$func_replace_sysroot_result" + case "$finalize_rpath " in + *" $libdir "*) ;; + *) func_append finalize_rpath " $libdir" ;; + esac + done + if test "$hardcode_into_libs" != yes || test "$build_old_libs" = yes; then + dependency_libs="$temp_xrpath $dependency_libs" + fi + fi + + # Make sure dlfiles contains only unique files that won't be dlpreopened + old_dlfiles="$dlfiles" + dlfiles= + for lib in $old_dlfiles; do + case " $dlprefiles $dlfiles " in + *" $lib "*) ;; + *) func_append dlfiles " $lib" ;; + esac + done + + # Make sure dlprefiles contains only unique files + old_dlprefiles="$dlprefiles" + dlprefiles= + for lib in $old_dlprefiles; do + case "$dlprefiles " in + *" $lib "*) ;; + *) func_append dlprefiles " $lib" ;; + esac + done + + if test "$build_libtool_libs" = yes; then + if test -n "$rpath"; then + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos* | *-cegcc* | *-*-haiku*) + # these systems don't actually have a c library (as such)! + ;; + *-*-rhapsody* | *-*-darwin1.[012]) + # Rhapsody C library is in the System framework + func_append deplibs " System.ltframework" + ;; + *-*-netbsd*) + # Don't link with libc until the a.out ld.so is fixed. + ;; + *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) + # Do not include libc due to us having libc/libc_r. + ;; + *-*-sco3.2v5* | *-*-sco5v6*) + # Causes problems with __ctype + ;; + *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) + # Compiler inserts libc in the correct place for threads to work + ;; + *) + # Add libc to deplibs on all other systems if necessary. + if test "$build_libtool_need_lc" = "yes"; then + func_append deplibs " -lc" + fi + ;; + esac + fi + + # Transform deplibs into only deplibs that can be linked in shared. + name_save=$name + libname_save=$libname + release_save=$release + versuffix_save=$versuffix + major_save=$major + # I'm not sure if I'm treating the release correctly. I think + # release should show up in the -l (ie -lgmp5) so we don't want to + # add it in twice. Is that correct? + release="" + versuffix="" + major="" + newdeplibs= + droppeddeps=no + case $deplibs_check_method in + pass_all) + # Don't check for shared/static. Everything works. + # This might be a little naive. We might want to check + # whether the library exists or not. But this is on + # osf3 & osf4 and I'm not really sure... Just + # implementing what was already the behavior. + newdeplibs=$deplibs + ;; + test_compile) + # This code stresses the "libraries are programs" paradigm to its + # limits. Maybe even breaks it. We compile a program, linking it + # against the deplibs as a proxy for the library. Then we can check + # whether they linked in statically or dynamically with ldd. + $opt_dry_run || $RM conftest.c + cat > conftest.c </dev/null` + $nocaseglob + else + potential_libs=`ls $i/$libnameglob[.-]* 2>/dev/null` + fi + for potent_lib in $potential_libs; do + # Follow soft links. + if ls -lLd "$potent_lib" 2>/dev/null | + $GREP " -> " >/dev/null; then + continue + fi + # The statement above tries to avoid entering an + # endless loop below, in case of cyclic links. + # We might still enter an endless loop, since a link + # loop can be closed while we follow links, + # but so what? + potlib="$potent_lib" + while test -h "$potlib" 2>/dev/null; do + potliblink=`ls -ld $potlib | ${SED} 's/.* -> //'` + case $potliblink in + [\\/]* | [A-Za-z]:[\\/]*) potlib="$potliblink";; + *) potlib=`$ECHO "$potlib" | $SED 's,[^/]*$,,'`"$potliblink";; + esac + done + if eval $file_magic_cmd \"\$potlib\" 2>/dev/null | + $SED -e 10q | + $EGREP "$file_magic_regex" > /dev/null; then + func_append newdeplibs " $a_deplib" + a_deplib="" + break 2 + fi + done + done + fi + if test -n "$a_deplib" ; then + droppeddeps=yes + echo + $ECHO "*** Warning: linker path does not have real file for library $a_deplib." + echo "*** I have the capability to make that library automatically link in when" + echo "*** you link to this library. But I can only do this if you have a" + echo "*** shared version of the library, which you do not appear to have" + echo "*** because I did check the linker path looking for a file starting" + if test -z "$potlib" ; then + $ECHO "*** with $libname but no candidates were found. (...for file magic test)" + else + $ECHO "*** with $libname and none of the candidates passed a file format test" + $ECHO "*** using a file magic. Last file checked: $potlib" + fi + fi + ;; + *) + # Add a -L argument. + func_append newdeplibs " $a_deplib" + ;; + esac + done # Gone through all deplibs. + ;; + match_pattern*) + set dummy $deplibs_check_method; shift + match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"` + for a_deplib in $deplibs; do + case $a_deplib in + -l*) + func_stripname -l '' "$a_deplib" + name=$func_stripname_result + if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then + case " $predeps $postdeps " in + *" $a_deplib "*) + func_append newdeplibs " $a_deplib" + a_deplib="" + ;; + esac + fi + if test -n "$a_deplib" ; then + libname=`eval "\\$ECHO \"$libname_spec\""` + for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do + potential_libs=`ls $i/$libname[.-]* 2>/dev/null` + for potent_lib in $potential_libs; do + potlib="$potent_lib" # see symlink-check above in file_magic test + if eval "\$ECHO \"$potent_lib\"" 2>/dev/null | $SED 10q | \ + $EGREP "$match_pattern_regex" > /dev/null; then + func_append newdeplibs " $a_deplib" + a_deplib="" + break 2 + fi + done + done + fi + if test -n "$a_deplib" ; then + droppeddeps=yes + echo + $ECHO "*** Warning: linker path does not have real file for library $a_deplib." + echo "*** I have the capability to make that library automatically link in when" + echo "*** you link to this library. But I can only do this if you have a" + echo "*** shared version of the library, which you do not appear to have" + echo "*** because I did check the linker path looking for a file starting" + if test -z "$potlib" ; then + $ECHO "*** with $libname but no candidates were found. (...for regex pattern test)" + else + $ECHO "*** with $libname and none of the candidates passed a file format test" + $ECHO "*** using a regex pattern. Last file checked: $potlib" + fi + fi + ;; + *) + # Add a -L argument. + func_append newdeplibs " $a_deplib" + ;; + esac + done # Gone through all deplibs. + ;; + none | unknown | *) + newdeplibs="" + tmp_deplibs=`$ECHO " $deplibs" | $SED 's/ -lc$//; s/ -[LR][^ ]*//g'` + if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then + for i in $predeps $postdeps ; do + # can't use Xsed below, because $i might contain '/' + tmp_deplibs=`$ECHO " $tmp_deplibs" | $SED "s,$i,,"` + done + fi + case $tmp_deplibs in + *[!\ \ ]*) + echo + if test "X$deplibs_check_method" = "Xnone"; then + echo "*** Warning: inter-library dependencies are not supported in this platform." + else + echo "*** Warning: inter-library dependencies are not known to be supported." + fi + echo "*** All declared inter-library dependencies are being dropped." + droppeddeps=yes + ;; + esac + ;; + esac + versuffix=$versuffix_save + major=$major_save + release=$release_save + libname=$libname_save + name=$name_save + + case $host in + *-*-rhapsody* | *-*-darwin1.[012]) + # On Rhapsody replace the C library with the System framework + newdeplibs=`$ECHO " $newdeplibs" | $SED 's/ -lc / System.ltframework /'` + ;; + esac + + if test "$droppeddeps" = yes; then + if test "$module" = yes; then + echo + echo "*** Warning: libtool could not satisfy all declared inter-library" + $ECHO "*** dependencies of module $libname. Therefore, libtool will create" + echo "*** a static module, that should work as long as the dlopening" + echo "*** application is linked with the -dlopen flag." + if test -z "$global_symbol_pipe"; then + echo + echo "*** However, this would only work if libtool was able to extract symbol" + echo "*** lists from a program, using \`nm' or equivalent, but libtool could" + echo "*** not find such a program. So, this module is probably useless." + echo "*** \`nm' from GNU binutils and a full rebuild may help." + fi + if test "$build_old_libs" = no; then + oldlibs="$output_objdir/$libname.$libext" + build_libtool_libs=module + build_old_libs=yes + else + build_libtool_libs=no + fi + else + echo "*** The inter-library dependencies that have been dropped here will be" + echo "*** automatically added whenever a program is linked with this library" + echo "*** or is declared to -dlopen it." + + if test "$allow_undefined" = no; then + echo + echo "*** Since this library must not contain undefined symbols," + echo "*** because either the platform does not support them or" + echo "*** it was explicitly requested with -no-undefined," + echo "*** libtool will only create a static version of it." + if test "$build_old_libs" = no; then + oldlibs="$output_objdir/$libname.$libext" + build_libtool_libs=module + build_old_libs=yes + else + build_libtool_libs=no + fi + fi + fi + fi + # Done checking deplibs! + deplibs=$newdeplibs + fi + # Time to change all our "foo.ltframework" stuff back to "-framework foo" + case $host in + *-*-darwin*) + newdeplibs=`$ECHO " $newdeplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + new_inherited_linker_flags=`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + deplibs=`$ECHO " $deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + ;; + esac + + # move library search paths that coincide with paths to not yet + # installed libraries to the beginning of the library search list + new_libs= + for path in $notinst_path; do + case " $new_libs " in + *" -L$path/$objdir "*) ;; + *) + case " $deplibs " in + *" -L$path/$objdir "*) + func_append new_libs " -L$path/$objdir" ;; + esac + ;; + esac + done + for deplib in $deplibs; do + case $deplib in + -L*) + case " $new_libs " in + *" $deplib "*) ;; + *) func_append new_libs " $deplib" ;; + esac + ;; + *) func_append new_libs " $deplib" ;; + esac + done + deplibs="$new_libs" + + # All the library-specific variables (install_libdir is set above). + library_names= + old_library= + dlname= + + # Test again, we may have decided not to build it any more + if test "$build_libtool_libs" = yes; then + # Remove ${wl} instances when linking with ld. + # FIXME: should test the right _cmds variable. + case $archive_cmds in + *\$LD\ *) wl= ;; + esac + if test "$hardcode_into_libs" = yes; then + # Hardcode the library paths + hardcode_libdirs= + dep_rpath= + rpath="$finalize_rpath" + test "$opt_mode" != relink && rpath="$compile_rpath$rpath" + for libdir in $rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + func_replace_sysroot "$libdir" + libdir=$func_replace_sysroot_result + if test -z "$hardcode_libdirs"; then + hardcode_libdirs="$libdir" + else + # Just accumulate the unique libdirs. + case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + func_append dep_rpath " $flag" + fi + elif test -n "$runpath_var"; then + case "$perm_rpath " in + *" $libdir "*) ;; + *) func_append perm_rpath " $libdir" ;; + esac + fi + done + # Substitute the hardcoded libdirs into the rpath. + if test -n "$hardcode_libdir_separator" && + test -n "$hardcode_libdirs"; then + libdir="$hardcode_libdirs" + eval "dep_rpath=\"$hardcode_libdir_flag_spec\"" + fi + if test -n "$runpath_var" && test -n "$perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $perm_rpath; do + func_append rpath "$dir:" + done + eval "$runpath_var='$rpath\$$runpath_var'; export $runpath_var" + fi + test -n "$dep_rpath" && deplibs="$dep_rpath $deplibs" + fi + + shlibpath="$finalize_shlibpath" + test "$opt_mode" != relink && shlibpath="$compile_shlibpath$shlibpath" + if test -n "$shlibpath"; then + eval "$shlibpath_var='$shlibpath\$$shlibpath_var'; export $shlibpath_var" + fi + + # Get the real and link names of the library. + eval shared_ext=\"$shrext_cmds\" + eval library_names=\"$library_names_spec\" + set dummy $library_names + shift + realname="$1" + shift + + if test -n "$soname_spec"; then + eval soname=\"$soname_spec\" + else + soname="$realname" + fi + if test -z "$dlname"; then + dlname=$soname + fi + + lib="$output_objdir/$realname" + linknames= + for link + do + func_append linknames " $link" + done + + # Use standard objects if they are pic + test -z "$pic_flag" && libobjs=`$ECHO "$libobjs" | $SP2NL | $SED "$lo2o" | $NL2SP` + test "X$libobjs" = "X " && libobjs= + + delfiles= + if test -n "$export_symbols" && test -n "$include_expsyms"; then + $opt_dry_run || cp "$export_symbols" "$output_objdir/$libname.uexp" + export_symbols="$output_objdir/$libname.uexp" + func_append delfiles " $export_symbols" + fi + + orig_export_symbols= + case $host_os in + cygwin* | mingw* | cegcc*) + if test -n "$export_symbols" && test -z "$export_symbols_regex"; then + # exporting using user supplied symfile + if test "x`$SED 1q $export_symbols`" != xEXPORTS; then + # and it's NOT already a .def file. Must figure out + # which of the given symbols are data symbols and tag + # them as such. So, trigger use of export_symbols_cmds. + # export_symbols gets reassigned inside the "prepare + # the list of exported symbols" if statement, so the + # include_expsyms logic still works. + orig_export_symbols="$export_symbols" + export_symbols= + always_export_symbols=yes + fi + fi + ;; + esac + + # Prepare the list of exported symbols + if test -z "$export_symbols"; then + if test "$always_export_symbols" = yes || test -n "$export_symbols_regex"; then + func_verbose "generating symbol list for \`$libname.la'" + export_symbols="$output_objdir/$libname.exp" + $opt_dry_run || $RM $export_symbols + cmds=$export_symbols_cmds + save_ifs="$IFS"; IFS='~' + for cmd1 in $cmds; do + IFS="$save_ifs" + # Take the normal branch if the nm_file_list_spec branch + # doesn't work or if tool conversion is not needed. + case $nm_file_list_spec~$to_tool_file_cmd in + *~func_convert_file_noop | *~func_convert_file_msys_to_w32 | ~*) + try_normal_branch=yes + eval cmd=\"$cmd1\" + func_len " $cmd" + len=$func_len_result + ;; + *) + try_normal_branch=no + ;; + esac + if test "$try_normal_branch" = yes \ + && { test "$len" -lt "$max_cmd_len" \ + || test "$max_cmd_len" -le -1; } + then + func_show_eval "$cmd" 'exit $?' + skipped_export=false + elif test -n "$nm_file_list_spec"; then + func_basename "$output" + output_la=$func_basename_result + save_libobjs=$libobjs + save_output=$output + output=${output_objdir}/${output_la}.nm + func_to_tool_file "$output" + libobjs=$nm_file_list_spec$func_to_tool_file_result + func_append delfiles " $output" + func_verbose "creating $NM input file list: $output" + for obj in $save_libobjs; do + func_to_tool_file "$obj" + $ECHO "$func_to_tool_file_result" + done > "$output" + eval cmd=\"$cmd1\" + func_show_eval "$cmd" 'exit $?' + output=$save_output + libobjs=$save_libobjs + skipped_export=false + else + # The command line is too long to execute in one step. + func_verbose "using reloadable object file for export list..." + skipped_export=: + # Break out early, otherwise skipped_export may be + # set to false by a later but shorter cmd. + break + fi + done + IFS="$save_ifs" + if test -n "$export_symbols_regex" && test "X$skipped_export" != "X:"; then + func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' + func_show_eval '$MV "${export_symbols}T" "$export_symbols"' + fi + fi + fi + + if test -n "$export_symbols" && test -n "$include_expsyms"; then + tmp_export_symbols="$export_symbols" + test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols" + $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"' + fi + + if test "X$skipped_export" != "X:" && test -n "$orig_export_symbols"; then + # The given exports_symbols file has to be filtered, so filter it. + func_verbose "filter symbol list for \`$libname.la' to tag DATA exports" + # FIXME: $output_objdir/$libname.filter potentially contains lots of + # 's' commands which not all seds can handle. GNU sed should be fine + # though. Also, the filter scales superlinearly with the number of + # global variables. join(1) would be nice here, but unfortunately + # isn't a blessed tool. + $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter + func_append delfiles " $export_symbols $output_objdir/$libname.filter" + export_symbols=$output_objdir/$libname.def + $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols + fi + + tmp_deplibs= + for test_deplib in $deplibs; do + case " $convenience " in + *" $test_deplib "*) ;; + *) + func_append tmp_deplibs " $test_deplib" + ;; + esac + done + deplibs="$tmp_deplibs" + + if test -n "$convenience"; then + if test -n "$whole_archive_flag_spec" && + test "$compiler_needs_object" = yes && + test -z "$libobjs"; then + # extract the archives, so we have objects to list. + # TODO: could optimize this to just extract one archive. + whole_archive_flag_spec= + fi + if test -n "$whole_archive_flag_spec"; then + save_libobjs=$libobjs + eval libobjs=\"\$libobjs $whole_archive_flag_spec\" + test "X$libobjs" = "X " && libobjs= + else + gentop="$output_objdir/${outputname}x" + func_append generated " $gentop" + + func_extract_archives $gentop $convenience + func_append libobjs " $func_extract_archives_result" + test "X$libobjs" = "X " && libobjs= + fi + fi + + if test "$thread_safe" = yes && test -n "$thread_safe_flag_spec"; then + eval flag=\"$thread_safe_flag_spec\" + func_append linker_flags " $flag" + fi + + # Make a backup of the uninstalled library when relinking + if test "$opt_mode" = relink; then + $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}U && $MV $realname ${realname}U)' || exit $? + fi + + # Do each of the archive commands. + if test "$module" = yes && test -n "$module_cmds" ; then + if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then + eval test_cmds=\"$module_expsym_cmds\" + cmds=$module_expsym_cmds + else + eval test_cmds=\"$module_cmds\" + cmds=$module_cmds + fi + else + if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then + eval test_cmds=\"$archive_expsym_cmds\" + cmds=$archive_expsym_cmds + else + eval test_cmds=\"$archive_cmds\" + cmds=$archive_cmds + fi + fi + + if test "X$skipped_export" != "X:" && + func_len " $test_cmds" && + len=$func_len_result && + test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then + : + else + # The command line is too long to link in one step, link piecewise + # or, if using GNU ld and skipped_export is not :, use a linker + # script. + + # Save the value of $output and $libobjs because we want to + # use them later. If we have whole_archive_flag_spec, we + # want to use save_libobjs as it was before + # whole_archive_flag_spec was expanded, because we can't + # assume the linker understands whole_archive_flag_spec. + # This may have to be revisited, in case too many + # convenience libraries get linked in and end up exceeding + # the spec. + if test -z "$convenience" || test -z "$whole_archive_flag_spec"; then + save_libobjs=$libobjs + fi + save_output=$output + func_basename "$output" + output_la=$func_basename_result + + # Clear the reloadable object creation command queue and + # initialize k to one. + test_cmds= + concat_cmds= + objlist= + last_robj= + k=1 + + if test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "$with_gnu_ld" = yes; then + output=${output_objdir}/${output_la}.lnkscript + func_verbose "creating GNU ld script: $output" + echo 'INPUT (' > $output + for obj in $save_libobjs + do + func_to_tool_file "$obj" + $ECHO "$func_to_tool_file_result" >> $output + done + echo ')' >> $output + func_append delfiles " $output" + func_to_tool_file "$output" + output=$func_to_tool_file_result + elif test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "X$file_list_spec" != X; then + output=${output_objdir}/${output_la}.lnk + func_verbose "creating linker input file list: $output" + : > $output + set x $save_libobjs + shift + firstobj= + if test "$compiler_needs_object" = yes; then + firstobj="$1 " + shift + fi + for obj + do + func_to_tool_file "$obj" + $ECHO "$func_to_tool_file_result" >> $output + done + func_append delfiles " $output" + func_to_tool_file "$output" + output=$firstobj\"$file_list_spec$func_to_tool_file_result\" + else + if test -n "$save_libobjs"; then + func_verbose "creating reloadable object files..." + output=$output_objdir/$output_la-${k}.$objext + eval test_cmds=\"$reload_cmds\" + func_len " $test_cmds" + len0=$func_len_result + len=$len0 + + # Loop over the list of objects to be linked. + for obj in $save_libobjs + do + func_len " $obj" + func_arith $len + $func_len_result + len=$func_arith_result + if test "X$objlist" = X || + test "$len" -lt "$max_cmd_len"; then + func_append objlist " $obj" + else + # The command $test_cmds is almost too long, add a + # command to the queue. + if test "$k" -eq 1 ; then + # The first file doesn't have a previous command to add. + reload_objs=$objlist + eval concat_cmds=\"$reload_cmds\" + else + # All subsequent reloadable object files will link in + # the last one created. + reload_objs="$objlist $last_robj" + eval concat_cmds=\"\$concat_cmds~$reload_cmds~\$RM $last_robj\" + fi + last_robj=$output_objdir/$output_la-${k}.$objext + func_arith $k + 1 + k=$func_arith_result + output=$output_objdir/$output_la-${k}.$objext + objlist=" $obj" + func_len " $last_robj" + func_arith $len0 + $func_len_result + len=$func_arith_result + fi + done + # Handle the remaining objects by creating one last + # reloadable object file. All subsequent reloadable object + # files will link in the last one created. + test -z "$concat_cmds" || concat_cmds=$concat_cmds~ + reload_objs="$objlist $last_robj" + eval concat_cmds=\"\${concat_cmds}$reload_cmds\" + if test -n "$last_robj"; then + eval concat_cmds=\"\${concat_cmds}~\$RM $last_robj\" + fi + func_append delfiles " $output" + + else + output= + fi + + if ${skipped_export-false}; then + func_verbose "generating symbol list for \`$libname.la'" + export_symbols="$output_objdir/$libname.exp" + $opt_dry_run || $RM $export_symbols + libobjs=$output + # Append the command to create the export file. + test -z "$concat_cmds" || concat_cmds=$concat_cmds~ + eval concat_cmds=\"\$concat_cmds$export_symbols_cmds\" + if test -n "$last_robj"; then + eval concat_cmds=\"\$concat_cmds~\$RM $last_robj\" + fi + fi + + test -n "$save_libobjs" && + func_verbose "creating a temporary reloadable object file: $output" + + # Loop through the commands generated above and execute them. + save_ifs="$IFS"; IFS='~' + for cmd in $concat_cmds; do + IFS="$save_ifs" + $opt_silent || { + func_quote_for_expand "$cmd" + eval "func_echo $func_quote_for_expand_result" + } + $opt_dry_run || eval "$cmd" || { + lt_exit=$? + + # Restore the uninstalled library and exit + if test "$opt_mode" = relink; then + ( cd "$output_objdir" && \ + $RM "${realname}T" && \ + $MV "${realname}U" "$realname" ) + fi + + exit $lt_exit + } + done + IFS="$save_ifs" + + if test -n "$export_symbols_regex" && ${skipped_export-false}; then + func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' + func_show_eval '$MV "${export_symbols}T" "$export_symbols"' + fi + fi + + if ${skipped_export-false}; then + if test -n "$export_symbols" && test -n "$include_expsyms"; then + tmp_export_symbols="$export_symbols" + test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols" + $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"' + fi + + if test -n "$orig_export_symbols"; then + # The given exports_symbols file has to be filtered, so filter it. + func_verbose "filter symbol list for \`$libname.la' to tag DATA exports" + # FIXME: $output_objdir/$libname.filter potentially contains lots of + # 's' commands which not all seds can handle. GNU sed should be fine + # though. Also, the filter scales superlinearly with the number of + # global variables. join(1) would be nice here, but unfortunately + # isn't a blessed tool. + $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter + func_append delfiles " $export_symbols $output_objdir/$libname.filter" + export_symbols=$output_objdir/$libname.def + $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols + fi + fi + + libobjs=$output + # Restore the value of output. + output=$save_output + + if test -n "$convenience" && test -n "$whole_archive_flag_spec"; then + eval libobjs=\"\$libobjs $whole_archive_flag_spec\" + test "X$libobjs" = "X " && libobjs= + fi + # Expand the library linking commands again to reset the + # value of $libobjs for piecewise linking. + + # Do each of the archive commands. + if test "$module" = yes && test -n "$module_cmds" ; then + if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then + cmds=$module_expsym_cmds + else + cmds=$module_cmds + fi + else + if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then + cmds=$archive_expsym_cmds + else + cmds=$archive_cmds + fi + fi + fi + + if test -n "$delfiles"; then + # Append the command to remove temporary files to $cmds. + eval cmds=\"\$cmds~\$RM $delfiles\" + fi + + # Add any objects from preloaded convenience libraries + if test -n "$dlprefiles"; then + gentop="$output_objdir/${outputname}x" + func_append generated " $gentop" + + func_extract_archives $gentop $dlprefiles + func_append libobjs " $func_extract_archives_result" + test "X$libobjs" = "X " && libobjs= + fi + + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $opt_silent || { + func_quote_for_expand "$cmd" + eval "func_echo $func_quote_for_expand_result" + } + $opt_dry_run || eval "$cmd" || { + lt_exit=$? + + # Restore the uninstalled library and exit + if test "$opt_mode" = relink; then + ( cd "$output_objdir" && \ + $RM "${realname}T" && \ + $MV "${realname}U" "$realname" ) + fi + + exit $lt_exit + } + done + IFS="$save_ifs" + + # Restore the uninstalled library and exit + if test "$opt_mode" = relink; then + $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}T && $MV $realname ${realname}T && $MV ${realname}U $realname)' || exit $? + + if test -n "$convenience"; then + if test -z "$whole_archive_flag_spec"; then + func_show_eval '${RM}r "$gentop"' + fi + fi + + exit $EXIT_SUCCESS + fi + + # Create links to the real library. + for linkname in $linknames; do + if test "$realname" != "$linkname"; then + func_show_eval '(cd "$output_objdir" && $RM "$linkname" && $LN_S "$realname" "$linkname")' 'exit $?' + fi + done + + # If -module or -export-dynamic was specified, set the dlname. + if test "$module" = yes || test "$export_dynamic" = yes; then + # On all known operating systems, these are identical. + dlname="$soname" + fi + fi + ;; + + obj) + if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then + func_warning "\`-dlopen' is ignored for objects" + fi + + case " $deplibs" in + *\ -l* | *\ -L*) + func_warning "\`-l' and \`-L' are ignored for objects" ;; + esac + + test -n "$rpath" && \ + func_warning "\`-rpath' is ignored for objects" + + test -n "$xrpath" && \ + func_warning "\`-R' is ignored for objects" + + test -n "$vinfo" && \ + func_warning "\`-version-info' is ignored for objects" + + test -n "$release" && \ + func_warning "\`-release' is ignored for objects" + + case $output in + *.lo) + test -n "$objs$old_deplibs" && \ + func_fatal_error "cannot build library object \`$output' from non-libtool objects" + + libobj=$output + func_lo2o "$libobj" + obj=$func_lo2o_result + ;; + *) + libobj= + obj="$output" + ;; + esac + + # Delete the old objects. + $opt_dry_run || $RM $obj $libobj + + # Objects from convenience libraries. This assumes + # single-version convenience libraries. Whenever we create + # different ones for PIC/non-PIC, this we'll have to duplicate + # the extraction. + reload_conv_objs= + gentop= + # reload_cmds runs $LD directly, so let us get rid of + # -Wl from whole_archive_flag_spec and hope we can get by with + # turning comma into space.. + wl= + + if test -n "$convenience"; then + if test -n "$whole_archive_flag_spec"; then + eval tmp_whole_archive_flags=\"$whole_archive_flag_spec\" + reload_conv_objs=$reload_objs\ `$ECHO "$tmp_whole_archive_flags" | $SED 's|,| |g'` + else + gentop="$output_objdir/${obj}x" + func_append generated " $gentop" + + func_extract_archives $gentop $convenience + reload_conv_objs="$reload_objs $func_extract_archives_result" + fi + fi + + # If we're not building shared, we need to use non_pic_objs + test "$build_libtool_libs" != yes && libobjs="$non_pic_objects" + + # Create the old-style object. + reload_objs="$objs$old_deplibs "`$ECHO "$libobjs" | $SP2NL | $SED "/\.${libext}$/d; /\.lib$/d; $lo2o" | $NL2SP`" $reload_conv_objs" ### testsuite: skip nested quoting test + + output="$obj" + func_execute_cmds "$reload_cmds" 'exit $?' + + # Exit if we aren't doing a library object file. + if test -z "$libobj"; then + if test -n "$gentop"; then + func_show_eval '${RM}r "$gentop"' + fi + + exit $EXIT_SUCCESS + fi + + if test "$build_libtool_libs" != yes; then + if test -n "$gentop"; then + func_show_eval '${RM}r "$gentop"' + fi + + # Create an invalid libtool object if no PIC, so that we don't + # accidentally link it into a program. + # $show "echo timestamp > $libobj" + # $opt_dry_run || eval "echo timestamp > $libobj" || exit $? + exit $EXIT_SUCCESS + fi + + if test -n "$pic_flag" || test "$pic_mode" != default; then + # Only do commands if we really have different PIC objects. + reload_objs="$libobjs $reload_conv_objs" + output="$libobj" + func_execute_cmds "$reload_cmds" 'exit $?' + fi + + if test -n "$gentop"; then + func_show_eval '${RM}r "$gentop"' + fi + + exit $EXIT_SUCCESS + ;; + + prog) + case $host in + *cygwin*) func_stripname '' '.exe' "$output" + output=$func_stripname_result.exe;; + esac + test -n "$vinfo" && \ + func_warning "\`-version-info' is ignored for programs" + + test -n "$release" && \ + func_warning "\`-release' is ignored for programs" + + test "$preload" = yes \ + && test "$dlopen_support" = unknown \ + && test "$dlopen_self" = unknown \ + && test "$dlopen_self_static" = unknown && \ + func_warning "\`LT_INIT([dlopen])' not used. Assuming no dlopen support." + + case $host in + *-*-rhapsody* | *-*-darwin1.[012]) + # On Rhapsody replace the C library is the System framework + compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's/ -lc / System.ltframework /'` + finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's/ -lc / System.ltframework /'` + ;; + esac + + case $host in + *-*-darwin*) + # Don't allow lazy linking, it breaks C++ global constructors + # But is supposedly fixed on 10.4 or later (yay!). + if test "$tagname" = CXX ; then + case ${MACOSX_DEPLOYMENT_TARGET-10.0} in + 10.[0123]) + func_append compile_command " ${wl}-bind_at_load" + func_append finalize_command " ${wl}-bind_at_load" + ;; + esac + fi + # Time to change all our "foo.ltframework" stuff back to "-framework foo" + compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + ;; + esac + + + # move library search paths that coincide with paths to not yet + # installed libraries to the beginning of the library search list + new_libs= + for path in $notinst_path; do + case " $new_libs " in + *" -L$path/$objdir "*) ;; + *) + case " $compile_deplibs " in + *" -L$path/$objdir "*) + func_append new_libs " -L$path/$objdir" ;; + esac + ;; + esac + done + for deplib in $compile_deplibs; do + case $deplib in + -L*) + case " $new_libs " in + *" $deplib "*) ;; + *) func_append new_libs " $deplib" ;; + esac + ;; + *) func_append new_libs " $deplib" ;; + esac + done + compile_deplibs="$new_libs" + + + func_append compile_command " $compile_deplibs" + func_append finalize_command " $finalize_deplibs" + + if test -n "$rpath$xrpath"; then + # If the user specified any rpath flags, then add them. + for libdir in $rpath $xrpath; do + # This is the magic to use -rpath. + case "$finalize_rpath " in + *" $libdir "*) ;; + *) func_append finalize_rpath " $libdir" ;; + esac + done + fi + + # Now hardcode the library paths + rpath= + hardcode_libdirs= + for libdir in $compile_rpath $finalize_rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + if test -z "$hardcode_libdirs"; then + hardcode_libdirs="$libdir" + else + # Just accumulate the unique libdirs. + case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + func_append rpath " $flag" + fi + elif test -n "$runpath_var"; then + case "$perm_rpath " in + *" $libdir "*) ;; + *) func_append perm_rpath " $libdir" ;; + esac + fi + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) + testbindir=`${ECHO} "$libdir" | ${SED} -e 's*/lib$*/bin*'` + case :$dllsearchpath: in + *":$libdir:"*) ;; + ::) dllsearchpath=$libdir;; + *) func_append dllsearchpath ":$libdir";; + esac + case :$dllsearchpath: in + *":$testbindir:"*) ;; + ::) dllsearchpath=$testbindir;; + *) func_append dllsearchpath ":$testbindir";; + esac + ;; + esac + done + # Substitute the hardcoded libdirs into the rpath. + if test -n "$hardcode_libdir_separator" && + test -n "$hardcode_libdirs"; then + libdir="$hardcode_libdirs" + eval rpath=\" $hardcode_libdir_flag_spec\" + fi + compile_rpath="$rpath" + + rpath= + hardcode_libdirs= + for libdir in $finalize_rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + if test -z "$hardcode_libdirs"; then + hardcode_libdirs="$libdir" + else + # Just accumulate the unique libdirs. + case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + func_append rpath " $flag" + fi + elif test -n "$runpath_var"; then + case "$finalize_perm_rpath " in + *" $libdir "*) ;; + *) func_append finalize_perm_rpath " $libdir" ;; + esac + fi + done + # Substitute the hardcoded libdirs into the rpath. + if test -n "$hardcode_libdir_separator" && + test -n "$hardcode_libdirs"; then + libdir="$hardcode_libdirs" + eval rpath=\" $hardcode_libdir_flag_spec\" + fi + finalize_rpath="$rpath" + + if test -n "$libobjs" && test "$build_old_libs" = yes; then + # Transform all the library objects into standard objects. + compile_command=`$ECHO "$compile_command" | $SP2NL | $SED "$lo2o" | $NL2SP` + finalize_command=`$ECHO "$finalize_command" | $SP2NL | $SED "$lo2o" | $NL2SP` + fi + + func_generate_dlsyms "$outputname" "@PROGRAM@" "no" + + # template prelinking step + if test -n "$prelink_cmds"; then + func_execute_cmds "$prelink_cmds" 'exit $?' + fi + + wrappers_required=yes + case $host in + *cegcc* | *mingw32ce*) + # Disable wrappers for cegcc and mingw32ce hosts, we are cross compiling anyway. + wrappers_required=no + ;; + *cygwin* | *mingw* ) + if test "$build_libtool_libs" != yes; then + wrappers_required=no + fi + ;; + *) + if test "$need_relink" = no || test "$build_libtool_libs" != yes; then + wrappers_required=no + fi + ;; + esac + if test "$wrappers_required" = no; then + # Replace the output file specification. + compile_command=`$ECHO "$compile_command" | $SED 's%@OUTPUT@%'"$output"'%g'` + link_command="$compile_command$compile_rpath" + + # We have no uninstalled library dependencies, so finalize right now. + exit_status=0 + func_show_eval "$link_command" 'exit_status=$?' + + if test -n "$postlink_cmds"; then + func_to_tool_file "$output" + postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` + func_execute_cmds "$postlink_cmds" 'exit $?' + fi + + # Delete the generated files. + if test -f "$output_objdir/${outputname}S.${objext}"; then + func_show_eval '$RM "$output_objdir/${outputname}S.${objext}"' + fi + + exit $exit_status + fi + + if test -n "$compile_shlibpath$finalize_shlibpath"; then + compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command" + fi + if test -n "$finalize_shlibpath"; then + finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command" + fi + + compile_var= + finalize_var= + if test -n "$runpath_var"; then + if test -n "$perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $perm_rpath; do + func_append rpath "$dir:" + done + compile_var="$runpath_var=\"$rpath\$$runpath_var\" " + fi + if test -n "$finalize_perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $finalize_perm_rpath; do + func_append rpath "$dir:" + done + finalize_var="$runpath_var=\"$rpath\$$runpath_var\" " + fi + fi + + if test "$no_install" = yes; then + # We don't need to create a wrapper script. + link_command="$compile_var$compile_command$compile_rpath" + # Replace the output file specification. + link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output"'%g'` + # Delete the old output file. + $opt_dry_run || $RM $output + # Link the executable and exit + func_show_eval "$link_command" 'exit $?' + + if test -n "$postlink_cmds"; then + func_to_tool_file "$output" + postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` + func_execute_cmds "$postlink_cmds" 'exit $?' + fi + + exit $EXIT_SUCCESS + fi + + if test "$hardcode_action" = relink; then + # Fast installation is not supported + link_command="$compile_var$compile_command$compile_rpath" + relink_command="$finalize_var$finalize_command$finalize_rpath" + + func_warning "this platform does not like uninstalled shared libraries" + func_warning "\`$output' will be relinked during installation" + else + if test "$fast_install" != no; then + link_command="$finalize_var$compile_command$finalize_rpath" + if test "$fast_install" = yes; then + relink_command=`$ECHO "$compile_var$compile_command$compile_rpath" | $SED 's%@OUTPUT@%\$progdir/\$file%g'` + else + # fast_install is set to needless + relink_command= + fi + else + link_command="$compile_var$compile_command$compile_rpath" + relink_command="$finalize_var$finalize_command$finalize_rpath" + fi + fi + + # Replace the output file specification. + link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'` + + # Delete the old output files. + $opt_dry_run || $RM $output $output_objdir/$outputname $output_objdir/lt-$outputname + + func_show_eval "$link_command" 'exit $?' + + if test -n "$postlink_cmds"; then + func_to_tool_file "$output_objdir/$outputname" + postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` + func_execute_cmds "$postlink_cmds" 'exit $?' + fi + + # Now create the wrapper script. + func_verbose "creating $output" + + # Quote the relink command for shipping. + if test -n "$relink_command"; then + # Preserve any variables that may affect compiler behavior + for var in $variables_saved_for_relink; do + if eval test -z \"\${$var+set}\"; then + relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command" + elif eval var_value=\$$var; test -z "$var_value"; then + relink_command="$var=; export $var; $relink_command" + else + func_quote_for_eval "$var_value" + relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command" + fi + done + relink_command="(cd `pwd`; $relink_command)" + relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"` + fi + + # Only actually do things if not in dry run mode. + $opt_dry_run || { + # win32 will think the script is a binary if it has + # a .exe suffix, so we strip it off here. + case $output in + *.exe) func_stripname '' '.exe' "$output" + output=$func_stripname_result ;; + esac + # test for cygwin because mv fails w/o .exe extensions + case $host in + *cygwin*) + exeext=.exe + func_stripname '' '.exe' "$outputname" + outputname=$func_stripname_result ;; + *) exeext= ;; + esac + case $host in + *cygwin* | *mingw* ) + func_dirname_and_basename "$output" "" "." + output_name=$func_basename_result + output_path=$func_dirname_result + cwrappersource="$output_path/$objdir/lt-$output_name.c" + cwrapper="$output_path/$output_name.exe" + $RM $cwrappersource $cwrapper + trap "$RM $cwrappersource $cwrapper; exit $EXIT_FAILURE" 1 2 15 + + func_emit_cwrapperexe_src > $cwrappersource + + # The wrapper executable is built using the $host compiler, + # because it contains $host paths and files. If cross- + # compiling, it, like the target executable, must be + # executed on the $host or under an emulation environment. + $opt_dry_run || { + $LTCC $LTCFLAGS -o $cwrapper $cwrappersource + $STRIP $cwrapper + } + + # Now, create the wrapper script for func_source use: + func_ltwrapper_scriptname $cwrapper + $RM $func_ltwrapper_scriptname_result + trap "$RM $func_ltwrapper_scriptname_result; exit $EXIT_FAILURE" 1 2 15 + $opt_dry_run || { + # note: this script will not be executed, so do not chmod. + if test "x$build" = "x$host" ; then + $cwrapper --lt-dump-script > $func_ltwrapper_scriptname_result + else + func_emit_wrapper no > $func_ltwrapper_scriptname_result + fi + } + ;; + * ) + $RM $output + trap "$RM $output; exit $EXIT_FAILURE" 1 2 15 + + func_emit_wrapper no > $output + chmod +x $output + ;; + esac + } + exit $EXIT_SUCCESS + ;; + esac + + # See if we need to build an old-fashioned archive. + for oldlib in $oldlibs; do + + if test "$build_libtool_libs" = convenience; then + oldobjs="$libobjs_save $symfileobj" + addlibs="$convenience" + build_libtool_libs=no + else + if test "$build_libtool_libs" = module; then + oldobjs="$libobjs_save" + build_libtool_libs=no + else + oldobjs="$old_deplibs $non_pic_objects" + if test "$preload" = yes && test -f "$symfileobj"; then + func_append oldobjs " $symfileobj" + fi + fi + addlibs="$old_convenience" + fi + + if test -n "$addlibs"; then + gentop="$output_objdir/${outputname}x" + func_append generated " $gentop" + + func_extract_archives $gentop $addlibs + func_append oldobjs " $func_extract_archives_result" + fi + + # Do each command in the archive commands. + if test -n "$old_archive_from_new_cmds" && test "$build_libtool_libs" = yes; then + cmds=$old_archive_from_new_cmds + else + + # Add any objects from preloaded convenience libraries + if test -n "$dlprefiles"; then + gentop="$output_objdir/${outputname}x" + func_append generated " $gentop" + + func_extract_archives $gentop $dlprefiles + func_append oldobjs " $func_extract_archives_result" + fi + + # POSIX demands no paths to be encoded in archives. We have + # to avoid creating archives with duplicate basenames if we + # might have to extract them afterwards, e.g., when creating a + # static archive out of a convenience library, or when linking + # the entirety of a libtool archive into another (currently + # not supported by libtool). + if (for obj in $oldobjs + do + func_basename "$obj" + $ECHO "$func_basename_result" + done | sort | sort -uc >/dev/null 2>&1); then + : + else + echo "copying selected object files to avoid basename conflicts..." + gentop="$output_objdir/${outputname}x" + func_append generated " $gentop" + func_mkdir_p "$gentop" + save_oldobjs=$oldobjs + oldobjs= + counter=1 + for obj in $save_oldobjs + do + func_basename "$obj" + objbase="$func_basename_result" + case " $oldobjs " in + " ") oldobjs=$obj ;; + *[\ /]"$objbase "*) + while :; do + # Make sure we don't pick an alternate name that also + # overlaps. + newobj=lt$counter-$objbase + func_arith $counter + 1 + counter=$func_arith_result + case " $oldobjs " in + *[\ /]"$newobj "*) ;; + *) if test ! -f "$gentop/$newobj"; then break; fi ;; + esac + done + func_show_eval "ln $obj $gentop/$newobj || cp $obj $gentop/$newobj" + func_append oldobjs " $gentop/$newobj" + ;; + *) func_append oldobjs " $obj" ;; + esac + done + fi + func_to_tool_file "$oldlib" func_convert_file_msys_to_w32 + tool_oldlib=$func_to_tool_file_result + eval cmds=\"$old_archive_cmds\" + + func_len " $cmds" + len=$func_len_result + if test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then + cmds=$old_archive_cmds + elif test -n "$archiver_list_spec"; then + func_verbose "using command file archive linking..." + for obj in $oldobjs + do + func_to_tool_file "$obj" + $ECHO "$func_to_tool_file_result" + done > $output_objdir/$libname.libcmd + func_to_tool_file "$output_objdir/$libname.libcmd" + oldobjs=" $archiver_list_spec$func_to_tool_file_result" + cmds=$old_archive_cmds + else + # the command line is too long to link in one step, link in parts + func_verbose "using piecewise archive linking..." + save_RANLIB=$RANLIB + RANLIB=: + objlist= + concat_cmds= + save_oldobjs=$oldobjs + oldobjs= + # Is there a better way of finding the last object in the list? + for obj in $save_oldobjs + do + last_oldobj=$obj + done + eval test_cmds=\"$old_archive_cmds\" + func_len " $test_cmds" + len0=$func_len_result + len=$len0 + for obj in $save_oldobjs + do + func_len " $obj" + func_arith $len + $func_len_result + len=$func_arith_result + func_append objlist " $obj" + if test "$len" -lt "$max_cmd_len"; then + : + else + # the above command should be used before it gets too long + oldobjs=$objlist + if test "$obj" = "$last_oldobj" ; then + RANLIB=$save_RANLIB + fi + test -z "$concat_cmds" || concat_cmds=$concat_cmds~ + eval concat_cmds=\"\${concat_cmds}$old_archive_cmds\" + objlist= + len=$len0 + fi + done + RANLIB=$save_RANLIB + oldobjs=$objlist + if test "X$oldobjs" = "X" ; then + eval cmds=\"\$concat_cmds\" + else + eval cmds=\"\$concat_cmds~\$old_archive_cmds\" + fi + fi + fi + func_execute_cmds "$cmds" 'exit $?' + done + + test -n "$generated" && \ + func_show_eval "${RM}r$generated" + + # Now create the libtool archive. + case $output in + *.la) + old_library= + test "$build_old_libs" = yes && old_library="$libname.$libext" + func_verbose "creating $output" + + # Preserve any variables that may affect compiler behavior + for var in $variables_saved_for_relink; do + if eval test -z \"\${$var+set}\"; then + relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command" + elif eval var_value=\$$var; test -z "$var_value"; then + relink_command="$var=; export $var; $relink_command" + else + func_quote_for_eval "$var_value" + relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command" + fi + done + # Quote the link command for shipping. + relink_command="(cd `pwd`; $SHELL $progpath $preserve_args --mode=relink $libtool_args @inst_prefix_dir@)" + relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"` + if test "$hardcode_automatic" = yes ; then + relink_command= + fi + + # Only create the output if not a dry run. + $opt_dry_run || { + for installed in no yes; do + if test "$installed" = yes; then + if test -z "$install_libdir"; then + break + fi + output="$output_objdir/$outputname"i + # Replace all uninstalled libtool libraries with the installed ones + newdependency_libs= + for deplib in $dependency_libs; do + case $deplib in + *.la) + func_basename "$deplib" + name="$func_basename_result" + func_resolve_sysroot "$deplib" + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $func_resolve_sysroot_result` + test -z "$libdir" && \ + func_fatal_error "\`$deplib' is not a valid libtool archive" + func_append newdependency_libs " ${lt_sysroot:+=}$libdir/$name" + ;; + -L*) + func_stripname -L '' "$deplib" + func_replace_sysroot "$func_stripname_result" + func_append newdependency_libs " -L$func_replace_sysroot_result" + ;; + -R*) + func_stripname -R '' "$deplib" + func_replace_sysroot "$func_stripname_result" + func_append newdependency_libs " -R$func_replace_sysroot_result" + ;; + *) func_append newdependency_libs " $deplib" ;; + esac + done + dependency_libs="$newdependency_libs" + newdlfiles= + + for lib in $dlfiles; do + case $lib in + *.la) + func_basename "$lib" + name="$func_basename_result" + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` + test -z "$libdir" && \ + func_fatal_error "\`$lib' is not a valid libtool archive" + func_append newdlfiles " ${lt_sysroot:+=}$libdir/$name" + ;; + *) func_append newdlfiles " $lib" ;; + esac + done + dlfiles="$newdlfiles" + newdlprefiles= + for lib in $dlprefiles; do + case $lib in + *.la) + # Only pass preopened files to the pseudo-archive (for + # eventual linking with the app. that links it) if we + # didn't already link the preopened objects directly into + # the library: + func_basename "$lib" + name="$func_basename_result" + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` + test -z "$libdir" && \ + func_fatal_error "\`$lib' is not a valid libtool archive" + func_append newdlprefiles " ${lt_sysroot:+=}$libdir/$name" + ;; + esac + done + dlprefiles="$newdlprefiles" + else + newdlfiles= + for lib in $dlfiles; do + case $lib in + [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;; + *) abs=`pwd`"/$lib" ;; + esac + func_append newdlfiles " $abs" + done + dlfiles="$newdlfiles" + newdlprefiles= + for lib in $dlprefiles; do + case $lib in + [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;; + *) abs=`pwd`"/$lib" ;; + esac + func_append newdlprefiles " $abs" + done + dlprefiles="$newdlprefiles" + fi + $RM $output + # place dlname in correct position for cygwin + # In fact, it would be nice if we could use this code for all target + # systems that can't hard-code library paths into their executables + # and that have no shared library path variable independent of PATH, + # but it turns out we can't easily determine that from inspecting + # libtool variables, so we have to hard-code the OSs to which it + # applies here; at the moment, that means platforms that use the PE + # object format with DLL files. See the long comment at the top of + # tests/bindir.at for full details. + tdlname=$dlname + case $host,$output,$installed,$module,$dlname in + *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll | *cegcc*,*lai,yes,no,*.dll) + # If a -bindir argument was supplied, place the dll there. + if test "x$bindir" != x ; + then + func_relative_path "$install_libdir" "$bindir" + tdlname=$func_relative_path_result$dlname + else + # Otherwise fall back on heuristic. + tdlname=../bin/$dlname + fi + ;; + esac + $ECHO > $output "\ +# $outputname - a libtool library file +# Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION +# +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# The name that we can dlopen(3). +dlname='$tdlname' + +# Names of this library. +library_names='$library_names' + +# The name of the static archive. +old_library='$old_library' + +# Linker flags that can not go in dependency_libs. +inherited_linker_flags='$new_inherited_linker_flags' + +# Libraries that this one depends upon. +dependency_libs='$dependency_libs' + +# Names of additional weak libraries provided by this library +weak_library_names='$weak_libs' + +# Version information for $libname. +current=$current +age=$age +revision=$revision + +# Is this an already installed library? +installed=$installed + +# Should we warn about portability when linking against -modules? +shouldnotlink=$module + +# Files to dlopen/dlpreopen +dlopen='$dlfiles' +dlpreopen='$dlprefiles' + +# Directory that this library needs to be installed in: +libdir='$install_libdir'" + if test "$installed" = no && test "$need_relink" = yes; then + $ECHO >> $output "\ +relink_command=\"$relink_command\"" + fi + done + } + + # Do a symbolic link so that the libtool archive can be found in + # LD_LIBRARY_PATH before the program is installed. + func_show_eval '( cd "$output_objdir" && $RM "$outputname" && $LN_S "../$outputname" "$outputname" )' 'exit $?' + ;; + esac + exit $EXIT_SUCCESS +} + +{ test "$opt_mode" = link || test "$opt_mode" = relink; } && + func_mode_link ${1+"$@"} + + +# func_mode_uninstall arg... +func_mode_uninstall () +{ + $opt_debug + RM="$nonopt" + files= + rmforce= + exit_status=0 + + # This variable tells wrapper scripts just to set variables rather + # than running their programs. + libtool_install_magic="$magic" + + for arg + do + case $arg in + -f) func_append RM " $arg"; rmforce=yes ;; + -*) func_append RM " $arg" ;; + *) func_append files " $arg" ;; + esac + done + + test -z "$RM" && \ + func_fatal_help "you must specify an RM program" + + rmdirs= + + for file in $files; do + func_dirname "$file" "" "." + dir="$func_dirname_result" + if test "X$dir" = X.; then + odir="$objdir" + else + odir="$dir/$objdir" + fi + func_basename "$file" + name="$func_basename_result" + test "$opt_mode" = uninstall && odir="$dir" + + # Remember odir for removal later, being careful to avoid duplicates + if test "$opt_mode" = clean; then + case " $rmdirs " in + *" $odir "*) ;; + *) func_append rmdirs " $odir" ;; + esac + fi + + # Don't error if the file doesn't exist and rm -f was used. + if { test -L "$file"; } >/dev/null 2>&1 || + { test -h "$file"; } >/dev/null 2>&1 || + test -f "$file"; then + : + elif test -d "$file"; then + exit_status=1 + continue + elif test "$rmforce" = yes; then + continue + fi + + rmfiles="$file" + + case $name in + *.la) + # Possibly a libtool archive, so verify it. + if func_lalib_p "$file"; then + func_source $dir/$name + + # Delete the libtool libraries and symlinks. + for n in $library_names; do + func_append rmfiles " $odir/$n" + done + test -n "$old_library" && func_append rmfiles " $odir/$old_library" + + case "$opt_mode" in + clean) + case " $library_names " in + *" $dlname "*) ;; + *) test -n "$dlname" && func_append rmfiles " $odir/$dlname" ;; + esac + test -n "$libdir" && func_append rmfiles " $odir/$name $odir/${name}i" + ;; + uninstall) + if test -n "$library_names"; then + # Do each command in the postuninstall commands. + func_execute_cmds "$postuninstall_cmds" 'test "$rmforce" = yes || exit_status=1' + fi + + if test -n "$old_library"; then + # Do each command in the old_postuninstall commands. + func_execute_cmds "$old_postuninstall_cmds" 'test "$rmforce" = yes || exit_status=1' + fi + # FIXME: should reinstall the best remaining shared library. + ;; + esac + fi + ;; + + *.lo) + # Possibly a libtool object, so verify it. + if func_lalib_p "$file"; then + + # Read the .lo file + func_source $dir/$name + + # Add PIC object to the list of files to remove. + if test -n "$pic_object" && + test "$pic_object" != none; then + func_append rmfiles " $dir/$pic_object" + fi + + # Add non-PIC object to the list of files to remove. + if test -n "$non_pic_object" && + test "$non_pic_object" != none; then + func_append rmfiles " $dir/$non_pic_object" + fi + fi + ;; + + *) + if test "$opt_mode" = clean ; then + noexename=$name + case $file in + *.exe) + func_stripname '' '.exe' "$file" + file=$func_stripname_result + func_stripname '' '.exe' "$name" + noexename=$func_stripname_result + # $file with .exe has already been added to rmfiles, + # add $file without .exe + func_append rmfiles " $file" + ;; + esac + # Do a test to see if this is a libtool program. + if func_ltwrapper_p "$file"; then + if func_ltwrapper_executable_p "$file"; then + func_ltwrapper_scriptname "$file" + relink_command= + func_source $func_ltwrapper_scriptname_result + func_append rmfiles " $func_ltwrapper_scriptname_result" + else + relink_command= + func_source $dir/$noexename + fi + + # note $name still contains .exe if it was in $file originally + # as does the version of $file that was added into $rmfiles + func_append rmfiles " $odir/$name $odir/${name}S.${objext}" + if test "$fast_install" = yes && test -n "$relink_command"; then + func_append rmfiles " $odir/lt-$name" + fi + if test "X$noexename" != "X$name" ; then + func_append rmfiles " $odir/lt-${noexename}.c" + fi + fi + fi + ;; + esac + func_show_eval "$RM $rmfiles" 'exit_status=1' + done + + # Try to remove the ${objdir}s in the directories where we deleted files + for dir in $rmdirs; do + if test -d "$dir"; then + func_show_eval "rmdir $dir >/dev/null 2>&1" + fi + done + + exit $exit_status +} + +{ test "$opt_mode" = uninstall || test "$opt_mode" = clean; } && + func_mode_uninstall ${1+"$@"} + +test -z "$opt_mode" && { + help="$generic_help" + func_fatal_help "you must specify a MODE" +} + +test -z "$exec_cmd" && \ + func_fatal_help "invalid operation mode \`$opt_mode'" + +if test -n "$exec_cmd"; then + eval exec "$exec_cmd" + exit $EXIT_FAILURE +fi + +exit $exit_status + + +# The TAGs below are defined such that we never get into a situation +# in which we disable both kinds of libraries. Given conflicting +# choices, we go for a static library, that is the most portable, +# since we can't tell whether shared libraries were disabled because +# the user asked for that or because the platform doesn't support +# them. This is particularly important on AIX, because we don't +# support having both static and shared libraries enabled at the same +# time on that platform, so we default to a shared-only configuration. +# If a disable-shared tag is given, we'll fallback to a static-only +# configuration. But we'll never go from static-only to shared-only. + +# ### BEGIN LIBTOOL TAG CONFIG: disable-shared +build_libtool_libs=no +build_old_libs=yes +# ### END LIBTOOL TAG CONFIG: disable-shared + +# ### BEGIN LIBTOOL TAG CONFIG: disable-static +build_old_libs=`case $build_libtool_libs in yes) echo no;; *) echo yes;; esac` +# ### END LIBTOOL TAG CONFIG: disable-static + +# Local Variables: +# mode:shell-script +# sh-indentation:2 +# End: +# vi:sw=2 + diff --git a/extern/portaudio/missing b/extern/portaudio/missing new file mode 100755 index 0000000..db98974 --- /dev/null +++ b/extern/portaudio/missing @@ -0,0 +1,215 @@ +#! /bin/sh +# Common wrapper for a few potentially missing GNU programs. + +scriptversion=2013-10-28.13; # UTC + +# Copyright (C) 1996-2013 Free Software Foundation, Inc. +# Originally written by Fran,cois Pinard , 1996. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +if test $# -eq 0; then + echo 1>&2 "Try '$0 --help' for more information" + exit 1 +fi + +case $1 in + + --is-lightweight) + # Used by our autoconf macros to check whether the available missing + # script is modern enough. + exit 0 + ;; + + --run) + # Back-compat with the calling convention used by older automake. + shift + ;; + + -h|--h|--he|--hel|--help) + echo "\ +$0 [OPTION]... PROGRAM [ARGUMENT]... + +Run 'PROGRAM [ARGUMENT]...', returning a proper advice when this fails due +to PROGRAM being missing or too old. + +Options: + -h, --help display this help and exit + -v, --version output version information and exit + +Supported PROGRAM values: + aclocal autoconf autoheader autom4te automake makeinfo + bison yacc flex lex help2man + +Version suffixes to PROGRAM as well as the prefixes 'gnu-', 'gnu', and +'g' are ignored when checking the name. + +Send bug reports to ." + exit $? + ;; + + -v|--v|--ve|--ver|--vers|--versi|--versio|--version) + echo "missing $scriptversion (GNU Automake)" + exit $? + ;; + + -*) + echo 1>&2 "$0: unknown '$1' option" + echo 1>&2 "Try '$0 --help' for more information" + exit 1 + ;; + +esac + +# Run the given program, remember its exit status. +"$@"; st=$? + +# If it succeeded, we are done. +test $st -eq 0 && exit 0 + +# Also exit now if we it failed (or wasn't found), and '--version' was +# passed; such an option is passed most likely to detect whether the +# program is present and works. +case $2 in --version|--help) exit $st;; esac + +# Exit code 63 means version mismatch. This often happens when the user +# tries to use an ancient version of a tool on a file that requires a +# minimum version. +if test $st -eq 63; then + msg="probably too old" +elif test $st -eq 127; then + # Program was missing. + msg="missing on your system" +else + # Program was found and executed, but failed. Give up. + exit $st +fi + +perl_URL=http://www.perl.org/ +flex_URL=http://flex.sourceforge.net/ +gnu_software_URL=http://www.gnu.org/software + +program_details () +{ + case $1 in + aclocal|automake) + echo "The '$1' program is part of the GNU Automake package:" + echo "<$gnu_software_URL/automake>" + echo "It also requires GNU Autoconf, GNU m4 and Perl in order to run:" + echo "<$gnu_software_URL/autoconf>" + echo "<$gnu_software_URL/m4/>" + echo "<$perl_URL>" + ;; + autoconf|autom4te|autoheader) + echo "The '$1' program is part of the GNU Autoconf package:" + echo "<$gnu_software_URL/autoconf/>" + echo "It also requires GNU m4 and Perl in order to run:" + echo "<$gnu_software_URL/m4/>" + echo "<$perl_URL>" + ;; + esac +} + +give_advice () +{ + # Normalize program name to check for. + normalized_program=`echo "$1" | sed ' + s/^gnu-//; t + s/^gnu//; t + s/^g//; t'` + + printf '%s\n' "'$1' is $msg." + + configure_deps="'configure.ac' or m4 files included by 'configure.ac'" + case $normalized_program in + autoconf*) + echo "You should only need it if you modified 'configure.ac'," + echo "or m4 files included by it." + program_details 'autoconf' + ;; + autoheader*) + echo "You should only need it if you modified 'acconfig.h' or" + echo "$configure_deps." + program_details 'autoheader' + ;; + automake*) + echo "You should only need it if you modified 'Makefile.am' or" + echo "$configure_deps." + program_details 'automake' + ;; + aclocal*) + echo "You should only need it if you modified 'acinclude.m4' or" + echo "$configure_deps." + program_details 'aclocal' + ;; + autom4te*) + echo "You might have modified some maintainer files that require" + echo "the 'autom4te' program to be rebuilt." + program_details 'autom4te' + ;; + bison*|yacc*) + echo "You should only need it if you modified a '.y' file." + echo "You may want to install the GNU Bison package:" + echo "<$gnu_software_URL/bison/>" + ;; + lex*|flex*) + echo "You should only need it if you modified a '.l' file." + echo "You may want to install the Fast Lexical Analyzer package:" + echo "<$flex_URL>" + ;; + help2man*) + echo "You should only need it if you modified a dependency" \ + "of a man page." + echo "You may want to install the GNU Help2man package:" + echo "<$gnu_software_URL/help2man/>" + ;; + makeinfo*) + echo "You should only need it if you modified a '.texi' file, or" + echo "any other file indirectly affecting the aspect of the manual." + echo "You might want to install the Texinfo package:" + echo "<$gnu_software_URL/texinfo/>" + echo "The spurious makeinfo call might also be the consequence of" + echo "using a buggy 'make' (AIX, DU, IRIX), in which case you might" + echo "want to install GNU make:" + echo "<$gnu_software_URL/make/>" + ;; + *) + echo "You might have modified some files without having the proper" + echo "tools for further handling them. Check the 'README' file, it" + echo "often tells you about the needed prerequisites for installing" + echo "this package. You may also peek at any GNU archive site, in" + echo "case some other package contains this missing '$1' program." + ;; + esac +} + +give_advice "$1" | sed -e '1s/^/WARNING: /' \ + -e '2,$s/^/ /' >&2 + +# Propagate the correct exit status (expected to be 127 for a program +# not found, 63 for a program that failed due to version mismatch). +exit $st + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-time-zone: "UTC" +# time-stamp-end: "; # UTC" +# End: diff --git a/extern/portaudio/pablio/README.txt b/extern/portaudio/pablio/README.txt new file mode 100644 index 0000000..84438bf --- /dev/null +++ b/extern/portaudio/pablio/README.txt @@ -0,0 +1,49 @@ +README for PABLIO +Portable Audio Blocking I/O Library +Author: Phil Burk + +PABLIO is a simplified interface to PortAudio that provides +read/write style blocking I/O. + +PABLIO is DEPRECATED. We recommend that people use the blocking I/O calls +that are now part of the PortAudio API. These are Pa_ReadStream() and +Pa_WriteStream(). + +http://portaudio.com/docs/v19-doxydocs/blocking_read_write.html + +/* + * More information on PortAudio at: http://www.portaudio.com + * Copyright (c) 1999-2000 Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + + diff --git a/extern/portaudio/pablio/pablio.c b/extern/portaudio/pablio/pablio.c new file mode 100644 index 0000000..2275250 --- /dev/null +++ b/extern/portaudio/pablio/pablio.c @@ -0,0 +1,314 @@ +/* + * $Id$ + * pablio.c + * Portable Audio Blocking Input/Output utility. + * + * Author: Phil Burk, http://www.softsynth.com + * + * This program uses the PortAudio Portable Audio Library. + * For more information see: http://www.portaudio.com + * Copyright (c) 1999-2000 Ross Bencina and Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +#include +#include +#include +#include "portaudio.h" +#include "pa_ringbuffer.h" +#include "pablio.h" +#include + +/************************************************************************/ +/******** Constants *****************************************************/ +/************************************************************************/ + +#define FRAMES_PER_BUFFER (256) + +/************************************************************************/ +/******** Prototypes ****************************************************/ +/************************************************************************/ + +static int blockingIOCallback( void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + PaTimestamp outTime, void *userData ); +static PaError PABLIO_InitFIFO( RingBuffer *rbuf, long numFrames, long bytesPerFrame ); +static PaError PABLIO_TermFIFO( RingBuffer *rbuf ); + +/************************************************************************/ +/******** Functions *****************************************************/ +/************************************************************************/ + +/* Called from PortAudio. + * Read and write data only if there is room in FIFOs. + */ +static int blockingIOCallback( void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + PaTimestamp outTime, void *userData ) +{ + PABLIO_Stream *data = (PABLIO_Stream*)userData; + long numBytes = data->bytesPerFrame * framesPerBuffer; + (void) outTime; + + /* This may get called with NULL inputBuffer during initial setup. */ + if( inputBuffer != NULL ) + { + PaUtil_WriteRingBuffer( &data->inFIFO, inputBuffer, numBytes ); + } + if( outputBuffer != NULL ) + { + int i; + int numRead = PaUtil_ReadRingBuffer( &data->outFIFO, outputBuffer, numBytes ); + /* Zero out remainder of buffer if we run out of data. */ + for( i=numRead; ibuffer ) free( rbuf->buffer ); + rbuf->buffer = NULL; + return paNoError; +} + +/************************************************************ + * Write data to ring buffer. + * Will not return until all the data has been written. + */ +long WriteAudioStream( PABLIO_Stream *aStream, void *data, long numFrames ) +{ + long bytesWritten; + char *p = (char *) data; + long numBytes = aStream->bytesPerFrame * numFrames; + while( numBytes > 0) + { + bytesWritten = PaUtil_WriteRingBuffer( &aStream->outFIFO, p, numBytes ); + numBytes -= bytesWritten; + p += bytesWritten; + if( numBytes > 0) Pa_Sleep(10); + } + return numFrames; +} + +/************************************************************ + * Read data from ring buffer. + * Will not return until all the data has been read. + */ +long ReadAudioStream( PABLIO_Stream *aStream, void *data, long numFrames ) +{ + long bytesRead; + char *p = (char *) data; + long numBytes = aStream->bytesPerFrame * numFrames; + while( numBytes > 0) + { + bytesRead = PaUtil_ReadRingBuffer( &aStream->inFIFO, p, numBytes ); + numBytes -= bytesRead; + p += bytesRead; + if( numBytes > 0) Pa_Sleep(10); + } + return numFrames; +} + +/************************************************************ + * Return the number of frames that could be written to the stream without + * having to wait. + */ +long GetAudioStreamWriteable( PABLIO_Stream *aStream ) +{ + int bytesEmpty = PaUtil_GetRingBufferWriteAvailable( &aStream->outFIFO ); + return bytesEmpty / aStream->bytesPerFrame; +} + +/************************************************************ + * Return the number of frames that are available to be read from the + * stream without having to wait. + */ +long GetAudioStreamReadable( PABLIO_Stream *aStream ) +{ + int bytesFull = PaUtil_GetRingBufferReadAvailable( &aStream->inFIFO ); + return bytesFull / aStream->bytesPerFrame; +} + +/************************************************************/ +static unsigned long RoundUpToNextPowerOf2( unsigned long n ) +{ + long numBits = 0; + if( ((n-1) & n) == 0) return n; /* Already Power of two. */ + while( n > 0 ) + { + n= n>>1; + numBits++; + } + return (1<samplesPerFrame = ((flags&PABLIO_MONO) != 0) ? 1 : 2; + aStream->bytesPerFrame = bytesPerSample * aStream->samplesPerFrame; + + /* Initialize PortAudio */ + err = Pa_Initialize(); + if( err != paNoError ) goto error; + + /* Warning: numFrames must be larger than amount of data processed per interrupt + * inside PA to prevent glitches. Just to be safe, adjust size upwards. + */ + minNumBuffers = 2 * Pa_GetMinNumBuffers( FRAMES_PER_BUFFER, sampleRate ); + numFrames = minNumBuffers * FRAMES_PER_BUFFER; + numFrames = RoundUpToNextPowerOf2( numFrames ); + + /* Initialize Ring Buffers */ + doRead = ((flags & PABLIO_READ) != 0); + doWrite = ((flags & PABLIO_WRITE) != 0); + if(doRead) + { + err = PABLIO_InitFIFO( &aStream->inFIFO, numFrames, aStream->bytesPerFrame ); + if( err != paNoError ) goto error; + } + if(doWrite) + { + long numBytes; + err = PABLIO_InitFIFO( &aStream->outFIFO, numFrames, aStream->bytesPerFrame ); + if( err != paNoError ) goto error; + /* Make Write FIFO appear full initially. */ + numBytes = PaUtil_GetRingBufferWriteAvailable( &aStream->outFIFO ); + PaUtil_AdvanceRingBufferWriteIndex( &aStream->outFIFO, numBytes ); + } + + /* Open a PortAudio stream that we will use to communicate with the underlying + * audio drivers. */ + err = Pa_OpenStream( + &aStream->stream, + (doRead ? Pa_GetDefaultInputDeviceID() : paNoDevice), + (doRead ? aStream->samplesPerFrame : 0 ), + format, + NULL, + (doWrite ? Pa_GetDefaultOutputDeviceID() : paNoDevice), + (doWrite ? aStream->samplesPerFrame : 0 ), + format, + NULL, + sampleRate, + FRAMES_PER_BUFFER, + minNumBuffers, + paClipOff, /* we won't output out of range samples so don't bother clipping them */ + blockingIOCallback, + aStream ); + if( err != paNoError ) goto error; + + err = Pa_StartStream( aStream->stream ); + if( err != paNoError ) goto error; + + *rwblPtr = aStream; + return paNoError; + +error: + CloseAudioStream( aStream ); + *rwblPtr = NULL; + return err; +} + +/************************************************************/ +PaError CloseAudioStream( PABLIO_Stream *aStream ) +{ + PaError err; + int bytesEmpty; + int byteSize = aStream->outFIFO.bufferSize; + + /* If we are writing data, make sure we play everything written. */ + if( byteSize > 0 ) + { + bytesEmpty = PaUtil_GetRingBufferWriteAvailable( &aStream->outFIFO ); + while( bytesEmpty < byteSize ) + { + Pa_Sleep( 10 ); + bytesEmpty = PaUtil_GetRingBufferWriteAvailable( &aStream->outFIFO ); + } + } + + err = Pa_StopStream( aStream->stream ); + if( err != paNoError ) goto error; + err = Pa_CloseStream( aStream->stream ); + if( err != paNoError ) goto error; + Pa_Terminate(); + +error: + PABLIO_TermFIFO( &aStream->inFIFO ); + PABLIO_TermFIFO( &aStream->outFIFO ); + free( aStream ); + return err; +} diff --git a/extern/portaudio/pablio/pablio.def b/extern/portaudio/pablio/pablio.def new file mode 100644 index 0000000..a10f952 --- /dev/null +++ b/extern/portaudio/pablio/pablio.def @@ -0,0 +1,35 @@ +LIBRARY PABLIO +DESCRIPTION 'PABLIO Portable Audio Blocking I/O' + +EXPORTS + ; Explicit exports can go here + Pa_Initialize @1 + Pa_Terminate @2 + Pa_GetHostError @3 + Pa_GetErrorText @4 + Pa_CountDevices @5 + Pa_GetDefaultInputDeviceID @6 + Pa_GetDefaultOutputDeviceID @7 + Pa_GetDeviceInfo @8 + Pa_OpenStream @9 + Pa_OpenDefaultStream @10 + Pa_CloseStream @11 + Pa_StartStream @12 + Pa_StopStream @13 + Pa_StreamActive @14 + Pa_StreamTime @15 + Pa_GetCPULoad @16 + Pa_GetMinNumBuffers @17 + Pa_Sleep @18 + + OpenAudioStream @19 + CloseAudioStream @20 + WriteAudioStream @21 + ReadAudioStream @22 + + Pa_GetSampleSize @23 + + ;123456789012345678901234567890123456 + ;000000000111111111122222222223333333 + + diff --git a/extern/portaudio/pablio/pablio.h b/extern/portaudio/pablio/pablio.h new file mode 100644 index 0000000..fbc3ef4 --- /dev/null +++ b/extern/portaudio/pablio/pablio.h @@ -0,0 +1,116 @@ +#ifndef _PABLIO_H +#define _PABLIO_H + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +/* + * $Id$ + * PABLIO.h + * Portable Audio Blocking read/write utility. + * + * Author: Phil Burk, http://www.softsynth.com/portaudio/ + * + * Include file for PABLIO, the Portable Audio Blocking I/O Library. + * PABLIO is built on top of PortAudio, the Portable Audio Library. + * For more information see: http://www.portaudio.com + * Copyright (c) 1999-2000 Ross Bencina and Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +#include +#include +#include +#include "portaudio.h" +#include "pa_ringbuffer.h" +#include + +typedef struct +{ + RingBuffer inFIFO; + RingBuffer outFIFO; + PortAudioStream *stream; + int bytesPerFrame; + int samplesPerFrame; +} +PABLIO_Stream; + +/* Values for flags for OpenAudioStream(). */ +#define PABLIO_READ (1<<0) +#define PABLIO_WRITE (1<<1) +#define PABLIO_READ_WRITE (PABLIO_READ|PABLIO_WRITE) +#define PABLIO_MONO (1<<2) +#define PABLIO_STEREO (1<<3) + +/************************************************************ + * Write data to ring buffer. + * Will not return until all the data has been written. + */ +long WriteAudioStream( PABLIO_Stream *aStream, void *data, long numFrames ); + +/************************************************************ + * Read data from ring buffer. + * Will not return until all the data has been read. + */ +long ReadAudioStream( PABLIO_Stream *aStream, void *data, long numFrames ); + +/************************************************************ + * Return the number of frames that could be written to the stream without + * having to wait. + */ +long GetAudioStreamWriteable( PABLIO_Stream *aStream ); + +/************************************************************ + * Return the number of frames that are available to be read from the + * stream without having to wait. + */ +long GetAudioStreamReadable( PABLIO_Stream *aStream ); + +/************************************************************ + * Opens a PortAudio stream with default characteristics. + * Allocates PABLIO_Stream structure. + * + * flags parameter can be an ORed combination of: + * PABLIO_READ, PABLIO_WRITE, or PABLIO_READ_WRITE, + * and either PABLIO_MONO or PABLIO_STEREO + */ +PaError OpenAudioStream( PABLIO_Stream **aStreamPtr, double sampleRate, + PaSampleFormat format, long flags ); + +PaError CloseAudioStream( PABLIO_Stream *aStream ); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* _PABLIO_H */ diff --git a/extern/portaudio/pablio/test_rw.c b/extern/portaudio/pablio/test_rw.c new file mode 100644 index 0000000..1388246 --- /dev/null +++ b/extern/portaudio/pablio/test_rw.c @@ -0,0 +1,105 @@ +/* + * $Id$ + * test_rw.c + * Read input from one stream and write it to another. + * + * Author: Phil Burk, http://www.softsynth.com/portaudio/ + * + * This program uses PABLIO, the Portable Audio Blocking I/O Library. + * PABLIO is built on top of PortAudio, the Portable Audio Library. + * For more information see: http://www.portaudio.com + * Copyright (c) 1999-2000 Ross Bencina and Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +#include +#include +#include "pablio.h" + +/* +** Note that many of the older ISA sound cards on PCs do NOT support +** full duplex audio (simultaneous record and playback). +** And some only support full duplex at lower sample rates. +*/ +#define SAMPLE_RATE (44100) +#define NUM_SECONDS (5) +#define SAMPLES_PER_FRAME (2) +#define FRAMES_PER_BLOCK (64) + +/* Select whether we will use floats or shorts. */ +#if 1 +#define SAMPLE_TYPE paFloat32 +typedef float SAMPLE; +#else +#define SAMPLE_TYPE paInt16 +typedef short SAMPLE; +#endif + +/*******************************************************************/ +int main(void); +int main(void) +{ + int i; + SAMPLE samples[SAMPLES_PER_FRAME * FRAMES_PER_BLOCK]; + PaError err; + PABLIO_Stream *aStream; + + printf("Full duplex sound test using PortAudio and RingBuffers\n"); + fflush(stdout); + + /* Open simplified blocking I/O layer on top of PortAudio. */ + err = OpenAudioStream( &aStream, SAMPLE_RATE, SAMPLE_TYPE, + (PABLIO_READ_WRITE | PABLIO_STEREO) ); + if( err != paNoError ) goto error; + + /* Process samples in the foreground. */ + for( i=0; i<(NUM_SECONDS * SAMPLE_RATE); i += FRAMES_PER_BLOCK ) + { + /* Read one block of data into sample array from audio input. */ + ReadAudioStream( aStream, samples, FRAMES_PER_BLOCK ); + /* Write that same block of data to output. */ + WriteAudioStream( aStream, samples, FRAMES_PER_BLOCK ); + } + + CloseAudioStream( aStream ); + + printf("Full duplex sound test complete.\n" ); + fflush(stdout); + return 0; + +error: + Pa_Terminate(); + fprintf( stderr, "An error occured while using the portaudio stream\n" ); + fprintf( stderr, "Error number: %d\n", err ); + fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); + return -1; +} diff --git a/extern/portaudio/pablio/test_rw_echo.c b/extern/portaudio/pablio/test_rw_echo.c new file mode 100644 index 0000000..470b4b0 --- /dev/null +++ b/extern/portaudio/pablio/test_rw_echo.c @@ -0,0 +1,129 @@ +/* + * $Id$ + * test_rw_echo.c + * Echo delayed input to output. + * + * Author: Phil Burk, http://www.softsynth.com/portaudio/ + * + * This program uses PABLIO, the Portable Audio Blocking I/O Library. + * PABLIO is built on top of PortAudio, the Portable Audio Library. + * + * Note that if you need low latency, you should not use PABLIO. + * Use the PA_OpenStream callback technique which is lower level + * than PABLIO. + * + * For more information see: http://www.portaudio.com + * Copyright (c) 1999-2000 Ross Bencina and Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +#include +#include +#include +#include "pablio.h" +#include + +/* +** Note that many of the older ISA sound cards on PCs do NOT support +** full duplex audio (simultaneous record and playback). +** And some only support full duplex at lower sample rates. +*/ +#define SAMPLE_RATE (22050) +#define NUM_SECONDS (20) +#define SAMPLES_PER_FRAME (2) + +/* Select whether we will use floats or shorts. */ +#if 1 +#define SAMPLE_TYPE paFloat32 +typedef float SAMPLE; +#else +#define SAMPLE_TYPE paInt16 +typedef short SAMPLE; +#endif + +#define NUM_ECHO_FRAMES (2*SAMPLE_RATE) +SAMPLE samples[NUM_ECHO_FRAMES][SAMPLES_PER_FRAME] = {0.0}; + +/*******************************************************************/ +int main(void); +int main(void) +{ + int i; + PaError err; + PABLIO_Stream *aInStream; + PABLIO_Stream *aOutStream; + int index; + + printf("Full duplex sound test using PABLIO\n"); + fflush(stdout); + + /* Open simplified blocking I/O layer on top of PortAudio. */ + /* Open input first so it can start to fill buffers. */ + err = OpenAudioStream( &aInStream, SAMPLE_RATE, SAMPLE_TYPE, + (PABLIO_READ | PABLIO_STEREO) ); + if( err != paNoError ) goto error; + /* printf("opened input\n"); fflush(stdout); /**/ + + err = OpenAudioStream( &aOutStream, SAMPLE_RATE, SAMPLE_TYPE, + (PABLIO_WRITE | PABLIO_STEREO) ); + if( err != paNoError ) goto error; + /* printf("opened output\n"); fflush(stdout); /**/ + + /* Process samples in the foreground. */ + index = 0; + for( i=0; i<(NUM_SECONDS * SAMPLE_RATE); i++ ) + { + /* Write old frame of data to output. */ + /* samples[index][1] = (i&256) * (1.0f/256.0f); /* sawtooth */ + WriteAudioStream( aOutStream, &samples[index][0], 1 ); + + /* Read one frame of data into sample array for later output. */ + ReadAudioStream( aInStream, &samples[index][0], 1 ); + index += 1; + if( index >= NUM_ECHO_FRAMES ) index = 0; + + if( (i & 0xFFFF) == 0 ) printf("i = %d\n", i ); fflush(stdout); /**/ + } + + CloseAudioStream( aOutStream ); + CloseAudioStream( aInStream ); + + printf("R/W echo sound test complete.\n" ); + fflush(stdout); + return 0; + +error: + fprintf( stderr, "An error occured while using PortAudio\n" ); + fprintf( stderr, "Error number: %d\n", err ); + fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); + return -1; +} diff --git a/extern/portaudio/pablio/test_w_saw.c b/extern/portaudio/pablio/test_w_saw.c new file mode 100644 index 0000000..39efe9e --- /dev/null +++ b/extern/portaudio/pablio/test_w_saw.c @@ -0,0 +1,114 @@ +/* + * $Id$ + * test_w_saw.c + * Generate stereo sawtooth waveforms. + * + * Author: Phil Burk, http://www.softsynth.com + * + * This program uses PABLIO, the Portable Audio Blocking I/O Library. + * PABLIO is built on top of PortAudio, the Portable Audio Library. + * + * For more information see: http://www.portaudio.com + * Copyright (c) 1999-2000 Ross Bencina and Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +#include +#include +#include +#include "pablio.h" +#include + +#define SAMPLE_RATE (44100) +#define NUM_SECONDS (6) +#define SAMPLES_PER_FRAME (2) + +#define FREQUENCY (220.0f) +#define PHASE_INCREMENT (2.0f * FREQUENCY / SAMPLE_RATE) +#define FRAMES_PER_BLOCK (100) + +float samples[FRAMES_PER_BLOCK][SAMPLES_PER_FRAME]; +float phases[SAMPLES_PER_FRAME]; + +/*******************************************************************/ +int main(void); +int main(void) +{ + int i,j; + PaError err; + PABLIO_Stream *aOutStream; + + printf("Generate sawtooth waves using PABLIO.\n"); + fflush(stdout); + + /* Open simplified blocking I/O layer on top of PortAudio. */ + err = OpenAudioStream( &aOutStream, SAMPLE_RATE, paFloat32, + (PABLIO_WRITE | PABLIO_STEREO) ); + if( err != paNoError ) goto error; + + /* Initialize oscillator phases. */ + phases[0] = 0.0; + phases[1] = 0.0; + + for( i=0; i<(NUM_SECONDS * SAMPLE_RATE); i += FRAMES_PER_BLOCK ) + { + /* Generate sawtooth waveforms in a block for efficiency. */ + for( j=0; j 1.0f ) phases[0] -= 2.0f; + samples[j][0] = phases[0]; + + /* On the second channel, generate a sawtooth wave a fifth higher. */ + phases[1] += PHASE_INCREMENT * (3.0f / 2.0f); + if( phases[1] > 1.0f ) phases[1] -= 2.0f; + samples[j][1] = phases[1]; + } + + /* Write samples to output. */ + WriteAudioStream( aOutStream, samples, FRAMES_PER_BLOCK ); + } + + CloseAudioStream( aOutStream ); + + printf("Sawtooth sound test complete.\n" ); + fflush(stdout); + return 0; + +error: + fprintf( stderr, "An error occured while using PABLIO\n" ); + fprintf( stderr, "Error number: %d\n", err ); + fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); + return -1; +} diff --git a/extern/portaudio/pablio/test_w_saw8.c b/extern/portaudio/pablio/test_w_saw8.c new file mode 100644 index 0000000..b62c820 --- /dev/null +++ b/extern/portaudio/pablio/test_w_saw8.c @@ -0,0 +1,112 @@ +/* + * $Id$ + * test_w_saw8.c + * Generate stereo 8 bit sawtooth waveforms. + * + * Author: Phil Burk, http://www.softsynth.com + * + * This program uses PABLIO, the Portable Audio Blocking I/O Library. + * PABLIO is built on top of PortAudio, the Portable Audio Library. + * + * For more information see: http://www.portaudio.com + * Copyright (c) 1999-2000 Ross Bencina and Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +#include +#include +#include +#include "pablio.h" +#include + +#define SAMPLE_RATE (22050) +#define NUM_SECONDS (6) +#define SAMPLES_PER_FRAME (2) + + +#define FRAMES_PER_BLOCK (100) + +unsigned char samples[FRAMES_PER_BLOCK][SAMPLES_PER_FRAME]; +unsigned char phases[SAMPLES_PER_FRAME]; + +/*******************************************************************/ +int main(void); +int main(void) +{ + int i,j; + PaError err; + PABLIO_Stream *aOutStream; + + printf("Generate unsigned 8 bit sawtooth waves using PABLIO.\n"); + fflush(stdout); + + /* Open simplified blocking I/O layer on top of PortAudio. */ + err = OpenAudioStream( &aOutStream, SAMPLE_RATE, paUInt8, + (PABLIO_WRITE | PABLIO_STEREO) ); + if( err != paNoError ) goto error; + + /* Initialize oscillator phases to "ground" level for paUInt8. */ + phases[0] = 128; + phases[1] = 128; + + for( i=0; i<(NUM_SECONDS * SAMPLE_RATE); i += FRAMES_PER_BLOCK ) + { + /* Generate sawtooth waveforms in a block for efficiency. */ + for( j=0; j +#include +#include +#include +#include +#include "qa_tools.h" +#include "audio_analyzer.h" +#include "write_wav.h" + +#define PAQA_POP_THRESHOLD (0.04) + +/*==========================================================================================*/ +double PaQa_GetNthFrequency( double baseFrequency, int index ) +{ + // Use 13 tone equal tempered scale because it does not generate harmonic ratios. + return baseFrequency * pow( 2.0, index / 13.0 ); +} + +/*==========================================================================================*/ +void PaQa_EraseBuffer( float *buffer, int numFrames, int samplesPerFrame ) +{ + int i; + int numSamples = numFrames * samplesPerFrame; + for( i=0; iphase = 0.0; + generator->amplitude = amplitude; + generator->frequency = frequency; + generator->phaseIncrement = 2.0 * frequency * MATH_PI / frameRate; +} + +/*==========================================================================================*/ +void PaQa_MixSine( PaQaSineGenerator *generator, float *buffer, int numSamples, int stride ) +{ + int i; + for( i=0; iphase ) * generator->amplitude; + *buffer += value; // Mix with existing value. + buffer += stride; + // Advance phase and wrap around. + generator->phase += generator->phaseIncrement; + if (generator->phase > MATH_TWO_PI) + { + generator->phase -= MATH_TWO_PI; + } + } +} + +/*==========================================================================================*/ +void PaQa_GenerateCrackDISABLED( float *buffer, int numSamples, int stride ) +{ + int i; + int offset = numSamples/2; + for( i=0; ibuffer = (float*)malloc(numBytes); + QA_ASSERT_TRUE( "Allocate recording buffer.", (recording->buffer != NULL) ); + recording->maxFrames = maxFrames; recording->sampleRate = frameRate; + recording->numFrames = 0; + return 0; +error: + return 1; +} + +/*==========================================================================================*/ +void PaQa_TerminateRecording( PaQaRecording *recording ) +{ + if (recording->buffer != NULL) + { + free( recording->buffer ); + recording->buffer = NULL; + } + recording->maxFrames = 0; +} + +/*==========================================================================================*/ +int PaQa_WriteRecording( PaQaRecording *recording, float *buffer, int numFrames, int stride ) +{ + int i; + int framesToWrite; + float *data = &recording->buffer[recording->numFrames]; + + framesToWrite = numFrames; + if ((framesToWrite + recording->numFrames) > recording->maxFrames) + { + framesToWrite = recording->maxFrames - recording->numFrames; + } + + for( i=0; inumFrames += framesToWrite; + return (recording->numFrames >= recording->maxFrames); +} + +/*==========================================================================================*/ +int PaQa_WriteSilence( PaQaRecording *recording, int numFrames ) +{ + int i; + int framesToRecord; + float *data = &recording->buffer[recording->numFrames]; + + framesToRecord = numFrames; + if ((framesToRecord + recording->numFrames) > recording->maxFrames) + { + framesToRecord = recording->maxFrames - recording->numFrames; + } + + for( i=0; inumFrames += framesToRecord; + return (recording->numFrames >= recording->maxFrames); +} + +/*==========================================================================================*/ +int PaQa_RecordFreeze( PaQaRecording *recording, int numFrames ) +{ + int i; + int framesToRecord; + float *data = &recording->buffer[recording->numFrames]; + + framesToRecord = numFrames; + if ((framesToRecord + recording->numFrames) > recording->maxFrames) + { + framesToRecord = recording->maxFrames - recording->numFrames; + } + + for( i=0; inumFrames += framesToRecord; + return (recording->numFrames >= recording->maxFrames); +} + +/*==========================================================================================*/ +/** + * Write recording to WAV file. + */ +int PaQa_SaveRecordingToWaveFile( PaQaRecording *recording, const char *filename ) +{ + WAV_Writer writer; + int result = 0; +#define NUM_SAMPLES (200) + short data[NUM_SAMPLES]; + const int samplesPerFrame = 1; + int numLeft = recording->numFrames; + float *buffer = &recording->buffer[0]; + + result = Audio_WAV_OpenWriter( &writer, filename, recording->sampleRate, samplesPerFrame ); + if( result < 0 ) goto error; + + while( numLeft > 0 ) + { + int i; + int numToSave = (numLeft > NUM_SAMPLES) ? NUM_SAMPLES : numLeft; + // Convert double samples to shorts. + for( i=0; i 32767 ) ival = 32767; + else if( ival < -32768 ) ival = -32768; + data[i] = ival; + } + result = Audio_WAV_WriteShorts( &writer, data, numToSave ); + if( result < 0 ) goto error; + numLeft -= numToSave; + } + + result = Audio_WAV_CloseWriter( &writer ); + if( result < 0 ) goto error; + + return 0; + +error: + printf("ERROR: result = %d\n", result ); + return result; +#undef NUM_SAMPLES +} + +/*==========================================================================================*/ + +double PaQa_MeasureCrossingSlope( float *buffer, int numFrames ) +{ + int i; + double slopeTotal = 0.0; + int slopeCount = 0; + float previous; + double averageSlope = 0.0; + + previous = buffer[0]; + for( i=1; i 0.0) && (previous < 0.0) ) + { + double delta = current - previous; + slopeTotal += delta; + slopeCount += 1; + } + previous = current; + } + if( slopeCount > 0 ) + { + averageSlope = slopeTotal / slopeCount; + } + return averageSlope; +} + +/*==========================================================================================*/ +/* + * We can't just measure the peaks cuz they may be clipped. + * But the zero crossing should be intact. + * The measured slope of a sine wave at zero should be: + * + * slope = sin( 2PI * frequency / sampleRate ) + * + */ +double PaQa_MeasureSineAmplitudeBySlope( PaQaRecording *recording, + double frequency, double frameRate, + int startFrame, int numFrames ) +{ + float *buffer = &recording->buffer[startFrame]; + double measuredSlope = PaQa_MeasureCrossingSlope( buffer, numFrames ); + double unitySlope = sin( MATH_TWO_PI * frequency / frameRate ); + double estimatedAmplitude = measuredSlope / unitySlope; + return estimatedAmplitude; +} + +/*==========================================================================================*/ +double PaQa_CorrelateSine( PaQaRecording *recording, double frequency, double frameRate, + int startFrame, int numFrames, double *phasePtr ) +{ + double magnitude = 0.0; + int numLeft = numFrames; + double phase = 0.0; + double phaseIncrement = 2.0 * MATH_PI * frequency / frameRate; + double sinAccumulator = 0.0; + double cosAccumulator = 0.0; + float *data = &recording->buffer[startFrame]; + + QA_ASSERT_TRUE( "startFrame out of bounds", (startFrame < recording->numFrames) ); + QA_ASSERT_TRUE( "numFrames out of bounds", ((startFrame+numFrames) <= recording->numFrames) ); + + while( numLeft > 0 ) + { + double sample = (double) *data++; + sinAccumulator += sample * sin( phase ); + cosAccumulator += sample * cos( phase ); + phase += phaseIncrement; + if (phase > MATH_TWO_PI) + { + phase -= MATH_TWO_PI; + } + numLeft -= 1; + } + sinAccumulator = sinAccumulator / numFrames; + cosAccumulator = cosAccumulator / numFrames; + // TODO Why do I have to multiply by 2.0? Need it to make result come out right. + magnitude = 2.0 * sqrt( (sinAccumulator * sinAccumulator) + (cosAccumulator * cosAccumulator )); + if( phasePtr != NULL ) + { + double phase = atan2( cosAccumulator, sinAccumulator ); + *phasePtr = phase; + } + return magnitude; +error: + return -1.0; +} + +/*==========================================================================================*/ +void PaQa_FilterRecording( PaQaRecording *input, PaQaRecording *output, BiquadFilter *filter ) +{ + int numToFilter = (input->numFrames > output->maxFrames) ? output->maxFrames : input->numFrames; + BiquadFilter_Filter( filter, &input->buffer[0], &output->buffer[0], numToFilter ); + output->numFrames = numToFilter; +} + +/*==========================================================================================*/ +/** Scan until we get a correlation of a single that goes over the tolerance level, + * peaks then drops to half the peak. + * Look for inverse correlation as well. + */ +double PaQa_FindFirstMatch( PaQaRecording *recording, float *buffer, int numFrames, double threshold ) +{ + int ic,is; + // How many buffers will fit in the recording? + int maxCorrelations = recording->numFrames - numFrames; + double maxSum = 0.0; + int peakIndex = -1; + double inverseMaxSum = 0.0; + int inversePeakIndex = -1; + double location = -1.0; + + QA_ASSERT_TRUE( "numFrames out of bounds", (numFrames < recording->numFrames) ); + + for( ic=0; icbuffer[ ic ]; + for( is=0; is maxSum) ) + { + maxSum = sum; + peakIndex = ic; + } + if( ((-sum) > inverseMaxSum) ) + { + inverseMaxSum = -sum; + inversePeakIndex = ic; + } + pastPeak = (maxSum > threshold) && (sum < 0.5*maxSum); + inversePastPeak = (inverseMaxSum > threshold) && ((-sum) < 0.5*inverseMaxSum); + //printf("PaQa_FindFirstMatch: ic = %4d, sum = %8f, maxSum = %8f, inverseMaxSum = %8f\n", ic, sum, maxSum, inverseMaxSum ); + if( pastPeak && inversePastPeak ) + { + if( maxSum > inverseMaxSum ) + { + location = peakIndex; + } + else + { + location = inversePeakIndex; + } + break; + } + + } + //printf("PaQa_FindFirstMatch: location = %4d\n", (int)location ); + return location; +error: + return -1.0; +} + +/*==========================================================================================*/ +// Measure the area under the curve by summing absolute value of each value. +double PaQa_MeasureArea( float *buffer, int numFrames, int stride ) +{ + int is; + double area = 0.0; + for( is=0; isnumFrames) ); + + { + double recordedArea = PaQa_MeasureArea( &recording->buffer[startAt], numFrames, 1 ); + double bufferArea = PaQa_MeasureArea( buffer, numFrames, 1 ); + if( bufferArea == 0.0 ) return 100000000.0; + return recordedArea / bufferArea; + } +error: + return -1.0; +} + + +/*==========================================================================================*/ +double PaQa_ComputePhaseDifference( double phase1, double phase2 ) +{ + double delta = phase1 - phase2; + while( delta > MATH_PI ) + { + delta -= MATH_TWO_PI; + } + while( delta < -MATH_PI ) + { + delta += MATH_TWO_PI; + } + return delta; +} + +/*==========================================================================================*/ +int PaQa_MeasureLatency( PaQaRecording *recording, PaQaTestTone *testTone, PaQaAnalysisResult *analysisResult ) +{ + double threshold; + PaQaSineGenerator generator; +#define MAX_BUFFER_SIZE 2048 + float buffer[MAX_BUFFER_SIZE]; + double period = testTone->sampleRate / testTone->frequency; + int cycleSize = (int) (period + 0.5); + //printf("PaQa_AnalyseRecording: frequency = %8f, frameRate = %8f, period = %8f, cycleSize = %8d\n", + // testTone->frequency, testTone->sampleRate, period, cycleSize ); + analysisResult->latency = -1; + analysisResult->valid = (0); + + // Set up generator to find matching first cycle. + QA_ASSERT_TRUE( "cycleSize out of bounds", (cycleSize < MAX_BUFFER_SIZE) ); + PaQa_SetupSineGenerator( &generator, testTone->frequency, testTone->amplitude, testTone->sampleRate ); + PaQa_EraseBuffer( buffer, cycleSize, testTone->samplesPerFrame ); + PaQa_MixSine( &generator, buffer, cycleSize, testTone->samplesPerFrame ); + + threshold = cycleSize * 0.02; + analysisResult->latency = PaQa_FindFirstMatch( recording, buffer, cycleSize, threshold ); + QA_ASSERT_TRUE( "Could not find the start of the signal.", (analysisResult->latency >= 0) ); + analysisResult->amplitudeRatio = PaQa_CompareAmplitudes( recording, analysisResult->latency, buffer, cycleSize ); + return 0; +error: + return -1; +} + +/*==========================================================================================*/ +// Apply cosine squared window. +void PaQa_FadeInRecording( PaQaRecording *recording, int startFrame, int count ) +{ + int is; + double phase = 0.5 * MATH_PI; + // Advance a quarter wave + double phaseIncrement = 0.25 * 2.0 * MATH_PI / count; + + assert( startFrame >= 0 ); + assert( count > 0 ); + + /* Zero out initial part of the recording. */ + for( is=0; isbuffer[ is ] = 0.0f; + } + /* Fade in where signal begins. */ + for( is=0; isbuffer[ is + startFrame ]; + float y = x * w; + //printf("FADE %d : w=%f, x=%f, y=%f\n", is, w, x, y ); + recording->buffer[ is + startFrame ] = y; + + phase += phaseIncrement; + } +} + + +/*==========================================================================================*/ +/** Apply notch filter and high pass filter then detect remaining energy. + */ +int PaQa_DetectPop( PaQaRecording *recording, PaQaTestTone *testTone, PaQaAnalysisResult *analysisResult ) +{ + int result = 0; + int i; + double maxAmplitude; + int maxPosition; + + PaQaRecording notchOutput = { 0 }; + BiquadFilter notchFilter; + + PaQaRecording hipassOutput = { 0 }; + BiquadFilter hipassFilter; + + int frameRate = (int) recording->sampleRate; + + analysisResult->popPosition = -1; + analysisResult->popAmplitude = 0.0; + + result = PaQa_InitializeRecording( ¬chOutput, recording->numFrames, frameRate ); + QA_ASSERT_EQUALS( "PaQa_InitializeRecording failed", 0, result ); + + result = PaQa_InitializeRecording( &hipassOutput, recording->numFrames, frameRate ); + QA_ASSERT_EQUALS( "PaQa_InitializeRecording failed", 0, result ); + + // Use notch filter to remove test tone. + BiquadFilter_SetupNotch( ¬chFilter, testTone->frequency / frameRate, 0.5 ); + PaQa_FilterRecording( recording, ¬chOutput, ¬chFilter ); + //result = PaQa_SaveRecordingToWaveFile( ¬chOutput, "notch_output.wav" ); + //QA_ASSERT_EQUALS( "PaQa_SaveRecordingToWaveFile failed", 0, result ); + + // Apply fade-in window. + PaQa_FadeInRecording( ¬chOutput, (int) analysisResult->latency, 500 ); + + // Use high pass to accentuate the edges of a pop. At higher frequency! + BiquadFilter_SetupHighPass( &hipassFilter, 2.0 * testTone->frequency / frameRate, 0.5 ); + PaQa_FilterRecording( ¬chOutput, &hipassOutput, &hipassFilter ); + //result = PaQa_SaveRecordingToWaveFile( &hipassOutput, "hipass_output.wav" ); + //QA_ASSERT_EQUALS( "PaQa_SaveRecordingToWaveFile failed", 0, result ); + + // Scan remaining signal looking for peak. + maxAmplitude = 0.0; + maxPosition = -1; + for( i=(int) analysisResult->latency; i maxAmplitude ) + { + maxAmplitude = mag; + maxPosition = i; + } + } + + if( maxAmplitude > PAQA_POP_THRESHOLD ) + { + analysisResult->popPosition = maxPosition; + analysisResult->popAmplitude = maxAmplitude; + } + + PaQa_TerminateRecording( ¬chOutput ); + PaQa_TerminateRecording( &hipassOutput ); + return 0; + +error: + PaQa_TerminateRecording( ¬chOutput ); + PaQa_TerminateRecording( &hipassOutput ); + return -1; +} + +/*==========================================================================================*/ +int PaQa_DetectPhaseError( PaQaRecording *recording, PaQaTestTone *testTone, PaQaAnalysisResult *analysisResult ) +{ + int i; + double period = testTone->sampleRate / testTone->frequency; + int cycleSize = (int) (period + 0.5); + + double maxAddedFrames = 0.0; + double maxDroppedFrames = 0.0; + + double previousPhase = 0.0; + double previousFrameError = 0; + int loopCount = 0; + int skip = cycleSize; + int windowSize = cycleSize; + + // Scan recording starting with first cycle, looking for phase errors. + analysisResult->numDroppedFrames = 0.0; + analysisResult->numAddedFrames = 0.0; + analysisResult->droppedFramesPosition = -1.0; + analysisResult->addedFramesPosition = -1.0; + + for( i=analysisResult->latency; i<(recording->numFrames - windowSize); i += skip ) + { + double expectedPhase = previousPhase + (skip * MATH_TWO_PI / period); + double expectedPhaseIncrement = PaQa_ComputePhaseDifference( expectedPhase, previousPhase ); + + double phase = 666.0; + double mag = PaQa_CorrelateSine( recording, testTone->frequency, testTone->sampleRate, i, windowSize, &phase ); + if( (loopCount > 1) && (mag > 0.0) ) + { + double phaseDelta = PaQa_ComputePhaseDifference( phase, previousPhase ); + double phaseError = PaQa_ComputePhaseDifference( phaseDelta, expectedPhaseIncrement ); + // Convert phaseError to equivalent number of frames. + double frameError = period * phaseError / MATH_TWO_PI; + double consecutiveFrameError = frameError + previousFrameError; +// if( fabs(frameError) > 0.01 ) +// { +// printf("FFFFFFFFFFFFF frameError = %f, at %d\n", frameError, i ); +// } + if( consecutiveFrameError > 0.8 ) + { + double droppedFrames = consecutiveFrameError; + if (droppedFrames > (maxDroppedFrames * 1.001)) + { + analysisResult->numDroppedFrames = droppedFrames; + analysisResult->droppedFramesPosition = i + (windowSize/2); + maxDroppedFrames = droppedFrames; + } + } + else if( consecutiveFrameError < -0.8 ) + { + double addedFrames = 0 - consecutiveFrameError; + if (addedFrames > (maxAddedFrames * 1.001)) + { + analysisResult->numAddedFrames = addedFrames; + analysisResult->addedFramesPosition = i + (windowSize/2); + maxAddedFrames = addedFrames; + } + } + previousFrameError = frameError; + + + //if( i<8000 ) + //{ + // printf("%d: phase = %8f, expected = %8f, delta = %8f, frameError = %8f\n", i, phase, expectedPhaseIncrement, phaseDelta, frameError ); + //} + } + previousPhase = phase; + loopCount += 1; + } + return 0; +} + +/*==========================================================================================*/ +int PaQa_AnalyseRecording( PaQaRecording *recording, PaQaTestTone *testTone, PaQaAnalysisResult *analysisResult ) +{ + int result = 0; + + memset( analysisResult, 0, sizeof(PaQaAnalysisResult) ); + result = PaQa_MeasureLatency( recording, testTone, analysisResult ); + QA_ASSERT_EQUALS( "latency measurement", 0, result ); + + if( (analysisResult->latency >= 0) && (analysisResult->amplitudeRatio > 0.1) ) + { + analysisResult->valid = (1); + + result = PaQa_DetectPop( recording, testTone, analysisResult ); + QA_ASSERT_EQUALS( "detect pop", 0, result ); + + result = PaQa_DetectPhaseError( recording, testTone, analysisResult ); + QA_ASSERT_EQUALS( "detect phase error", 0, result ); + } + return 0; +error: + return -1; +} + diff --git a/extern/portaudio/qa/loopback/src/audio_analyzer.h b/extern/portaudio/qa/loopback/src/audio_analyzer.h new file mode 100644 index 0000000..2a86798 --- /dev/null +++ b/extern/portaudio/qa/loopback/src/audio_analyzer.h @@ -0,0 +1,187 @@ + +/* + * PortAudio Portable Real-Time Audio Library + * Latest Version at: http://www.portaudio.com + * + * Copyright (c) 1999-2010 Phil Burk and Ross Bencina + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +#ifndef _AUDIO_ANALYZER_H +#define _AUDIO_ANALYZER_H + +#include "biquad_filter.h" + +#define MATH_PI (3.141592653589793238462643) +#define MATH_TWO_PI (2.0 * MATH_PI) + +typedef struct PaQaSineGenerator_s +{ + double phase; + double phaseIncrement; + double frequency; + double amplitude; +} PaQaSineGenerator; + +/** Container for a monophonic audio sample in memory. */ +typedef struct PaQaRecording_s +{ + /** Maximum number of frames that can fit in the allocated buffer. */ + int maxFrames; + float *buffer; + /** Actual number of valid frames in the buffer. */ + int numFrames; + int sampleRate; +} PaQaRecording; + +typedef struct PaQaTestTone_s +{ + int samplesPerFrame; + int startDelay; + double sampleRate; + double frequency; + double amplitude; +} PaQaTestTone; + +typedef struct PaQaAnalysisResult_s +{ + int valid; + /** Latency in samples from output to input. */ + double latency; + double amplitudeRatio; + double popAmplitude; + double popPosition; + double numDroppedFrames; + double droppedFramesPosition; + double numAddedFrames; + double addedFramesPosition; +} PaQaAnalysisResult; + + +/*================================================================*/ +/*================= General DSP Tools ============================*/ +/*================================================================*/ +/** + * Calculate Nth frequency of a series for use in testing multiple channels. + * Series should avoid harmonic overlap between channels. + */ +double PaQa_GetNthFrequency( double baseFrequency, int index ); + +void PaQa_EraseBuffer( float *buffer, int numFrames, int samplesPerFrame ); + +void PaQa_MixSine( PaQaSineGenerator *generator, float *buffer, int numSamples, int stride ); + +void PaQa_WriteSine( float *buffer, int numSamples, int stride, + double frequency, double amplitude ); + +/** + * Generate a signal with a sharp edge in the middle that can be recognized despite some phase shift. + */ +void PaQa_GenerateCrack( float *buffer, int numSamples, int stride ); + +double PaQa_ComputePhaseDifference( double phase1, double phase2 ); + +/** + * Measure the area under the curve by summing absolute value of each value. + */ +double PaQa_MeasureArea( float *buffer, int numFrames, int stride ); + +/** + * Measure slope of the positive zero crossings. + */ +double PaQa_MeasureCrossingSlope( float *buffer, int numFrames ); + + +/** + * Prepare an oscillator that can generate a sine tone for testing. + */ +void PaQa_SetupSineGenerator( PaQaSineGenerator *generator, double frequency, double amplitude, double frameRate ); + +/*================================================================*/ +/*================= Recordings ===================================*/ +/*================================================================*/ +/** + * Allocate memory for containg a mono audio signal. Set up recording for writing. + */ + int PaQa_InitializeRecording( PaQaRecording *recording, int maxSamples, int sampleRate ); + +/** +* Free memory allocated by PaQa_InitializeRecording. + */ + void PaQa_TerminateRecording( PaQaRecording *recording ); + +/** + * Apply a biquad filter to the audio from the input recording and write it to the output recording. + */ +void PaQa_FilterRecording( PaQaRecording *input, PaQaRecording *output, BiquadFilter *filter ); + + +int PaQa_SaveRecordingToWaveFile( PaQaRecording *recording, const char *filename ); + +/** + * @param stride is the spacing of samples to skip in the input buffer. To use every samples pass 1. To use every other sample pass 2. + */ +int PaQa_WriteRecording( PaQaRecording *recording, float *buffer, int numSamples, int stride ); + +/** Write zeros into a recording. */ +int PaQa_WriteSilence( PaQaRecording *recording, int numSamples ); + +int PaQa_RecordFreeze( PaQaRecording *recording, int numSamples ); + +double PaQa_CorrelateSine( PaQaRecording *recording, double frequency, double frameRate, + int startFrame, int numSamples, double *phasePtr ); + +double PaQa_FindFirstMatch( PaQaRecording *recording, float *buffer, int numSamples, double tolerance ); + +/** + * Estimate the original amplitude of a clipped sine wave by measuring + * its average slope at the zero crossings. + */ +double PaQa_MeasureSineAmplitudeBySlope( PaQaRecording *recording, + double frequency, double frameRate, + int startFrame, int numFrames ); + +double PaQa_MeasureRootMeanSquare( float *buffer, int numFrames ); + +/** + * Compare the amplitudes of these two signals. + * Return ratio of recorded signal over buffer signal. + */ +double PaQa_CompareAmplitudes( PaQaRecording *recording, int startAt, float *buffer, int numSamples ); + +/** + * Analyse a recording of a sine wave. + * Measure latency and look for dropped frames, etc. + */ +int PaQa_AnalyseRecording( PaQaRecording *recording, PaQaTestTone *testTone, PaQaAnalysisResult *analysisResult ); + +#endif /* _AUDIO_ANALYZER_H */ diff --git a/extern/portaudio/qa/loopback/src/biquad_filter.c b/extern/portaudio/qa/loopback/src/biquad_filter.c new file mode 100755 index 0000000..1bc4a23 --- /dev/null +++ b/extern/portaudio/qa/loopback/src/biquad_filter.c @@ -0,0 +1,122 @@ +#include +#include + +#include "biquad_filter.h" + +/** + * Unit_BiquadFilter implements a second order IIR filter. + Here is the equation that we use for this filter: + y(n) = a0*x(n) + a1*x(n-1) + a2*x(n-2) - b1*y(n-1) - b2*y(n-2) + * + * @author (C) 2002 Phil Burk, SoftSynth.com, All Rights Reserved + */ + +#define FILTER_PI (3.141592653589793238462643) +/*********************************************************** +** Calculate coefficients common to many parametric biquad filters. +*/ +static void BiquadFilter_CalculateCommon( BiquadFilter *filter, double ratio, double Q ) +{ + double omega; + + memset( filter, 0, sizeof(BiquadFilter) ); + +/* Don't let frequency get too close to Nyquist or filter will blow up. */ + if( ratio >= 0.499 ) ratio = 0.499; + omega = 2.0 * (double)FILTER_PI * ratio; + + filter->cos_omega = (double) cos( omega ); + filter->sin_omega = (double) sin( omega ); + filter->alpha = filter->sin_omega / (2.0 * Q); +} + +/********************************************************************************* + ** Calculate coefficients for Highpass filter. + */ +void BiquadFilter_SetupHighPass( BiquadFilter *filter, double ratio, double Q ) +{ + double scalar, opc; + + if( ratio < BIQUAD_MIN_RATIO ) ratio = BIQUAD_MIN_RATIO; + if( Q < BIQUAD_MIN_Q ) Q = BIQUAD_MIN_Q; + + BiquadFilter_CalculateCommon( filter, ratio, Q ); + + scalar = 1.0 / (1.0 + filter->alpha); + opc = (1.0 + filter->cos_omega); + + filter->a0 = opc * 0.5 * scalar; + filter->a1 = - opc * scalar; + filter->a2 = filter->a0; + filter->b1 = -2.0 * filter->cos_omega * scalar; + filter->b2 = (1.0 - filter->alpha) * scalar; +} + + +/********************************************************************************* + ** Calculate coefficients for Notch filter. + */ +void BiquadFilter_SetupNotch( BiquadFilter *filter, double ratio, double Q ) +{ + double scalar, opc; + + if( ratio < BIQUAD_MIN_RATIO ) ratio = BIQUAD_MIN_RATIO; + if( Q < BIQUAD_MIN_Q ) Q = BIQUAD_MIN_Q; + + BiquadFilter_CalculateCommon( filter, ratio, Q ); + + scalar = 1.0 / (1.0 + filter->alpha); + opc = (1.0 + filter->cos_omega); + + filter->a0 = scalar; + filter->a1 = -2.0 * filter->cos_omega * scalar; + filter->a2 = filter->a0; + filter->b1 = filter->a1; + filter->b2 = (1.0 - filter->alpha) * scalar; +} + +/***************************************************************** +** Perform core IIR filter calculation without permutation. +*/ +void BiquadFilter_Filter( BiquadFilter *filter, float *inputs, float *outputs, int numSamples ) +{ + int i; + double xn, yn; + // Pull values from structure to speed up the calculation. + double a0 = filter->a0; + double a1 = filter->a1; + double a2 = filter->a2; + double b1 = filter->b1; + double b2 = filter->b2; + double xn1 = filter->xn1; + double xn2 = filter->xn2; + double yn1 = filter->yn1; + double yn2 = filter->yn2; + + for( i=0; ixn1 = xn1; + filter->xn2 = xn2; + filter->yn1 = yn1; + filter->yn2 = yn2; +} diff --git a/extern/portaudio/qa/loopback/src/biquad_filter.h b/extern/portaudio/qa/loopback/src/biquad_filter.h new file mode 100755 index 0000000..cbac688 --- /dev/null +++ b/extern/portaudio/qa/loopback/src/biquad_filter.h @@ -0,0 +1,38 @@ +#ifndef _BIQUADFILTER_H +#define _BIQUADFILTER_H + + +/** + * Unit_BiquadFilter implements a second order IIR filter. + * + * @author (C) 2002 Phil Burk, SoftSynth.com, All Rights Reserved + */ + +#define BIQUAD_MIN_RATIO (0.000001) +#define BIQUAD_MIN_Q (0.00001) + +typedef struct BiquadFilter_s +{ + double xn1; // storage for delayed signals + double xn2; + double yn1; + double yn2; + + double a0; // coefficients + double a1; + double a2; + + double b1; + double b2; + + double cos_omega; + double sin_omega; + double alpha; +} BiquadFilter; + +void BiquadFilter_SetupHighPass( BiquadFilter *filter, double ratio, double Q ); +void BiquadFilter_SetupNotch( BiquadFilter *filter, double ratio, double Q ); + +void BiquadFilter_Filter( BiquadFilter *filter, float *inputs, float *outputs, int numSamples ); + +#endif diff --git a/extern/portaudio/qa/loopback/src/paqa.c b/extern/portaudio/qa/loopback/src/paqa.c new file mode 100644 index 0000000..cb7100d --- /dev/null +++ b/extern/portaudio/qa/loopback/src/paqa.c @@ -0,0 +1,1601 @@ + +/* + * PortAudio Portable Real-Time Audio Library + * Latest Version at: http://www.portaudio.com + * + * Copyright (c) 1999-2010 Phil Burk and Ross Bencina + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +#include +#include +#include +#include +#include + +#include "portaudio.h" + +#include "qa_tools.h" + +#include "paqa_tools.h" +#include "audio_analyzer.h" +#include "test_audio_analyzer.h" + +/** Accumulate counts for how many tests pass or fail. */ +int g_testsPassed = 0; +int g_testsFailed = 0; + +#define MAX_NUM_GENERATORS (8) +#define MAX_NUM_RECORDINGS (8) +#define MAX_BACKGROUND_NOISE_RMS (0.0004) +#define LOOPBACK_DETECTION_DURATION_SECONDS (0.8) +#define DEFAULT_FRAMES_PER_BUFFER (0) +#define PAQA_WAIT_STREAM_MSEC (100) +#define PAQA_TEST_DURATION (1.2) + +// Use two separate streams instead of one full duplex stream. +#define PAQA_FLAG_TWO_STREAMS (1<<0) +// Use bloching read/write for loopback. +#define PAQA_FLAG_USE_BLOCKING_IO (1<<1) + +const char * s_FlagOnNames[] = +{ + "Two Streams (Half Duplex)", + "Blocking Read/Write" +}; + +const char * s_FlagOffNames[] = +{ + "One Stream (Full Duplex)", + "Callback" +}; + + +/** Parameters that describe a single test run. */ +typedef struct TestParameters_s +{ + PaStreamParameters inputParameters; + PaStreamParameters outputParameters; + double sampleRate; + int samplesPerFrame; + int framesPerBuffer; + int maxFrames; + double baseFrequency; + double amplitude; + PaStreamFlags streamFlags; // paClipOff, etc + int flags; // PAQA_FLAG_TWO_STREAMS, PAQA_FLAG_USE_BLOCKING_IO +} TestParameters; + +typedef struct LoopbackContext_s +{ + // Generate a unique signal on each channel. + PaQaSineGenerator generators[MAX_NUM_GENERATORS]; + // Record each channel individually. + PaQaRecording recordings[MAX_NUM_RECORDINGS]; + + // Reported by the stream after it's opened + PaTime streamInfoInputLatency; + PaTime streamInfoOutputLatency; + + // Measured at runtime. + volatile int callbackCount; // incremented for each callback + volatile int inputBufferCount; // incremented if input buffer not NULL + int inputUnderflowCount; + int inputOverflowCount; + + volatile int outputBufferCount; // incremented if output buffer not NULL + int outputOverflowCount; + int outputUnderflowCount; + + // Measure whether input or output is lagging behind. + volatile int minInputOutputDelta; + volatile int maxInputOutputDelta; + + int minFramesPerBuffer; + int maxFramesPerBuffer; + int primingCount; + TestParameters *test; + volatile int done; +} LoopbackContext; + +typedef struct UserOptions_s +{ + int sampleRate; + int framesPerBuffer; + int inputLatency; + int outputLatency; + int saveBadWaves; + int verbose; + int waveFileCount; + const char *waveFilePath; + PaDeviceIndex inputDevice; + PaDeviceIndex outputDevice; +} UserOptions; + +#define BIG_BUFFER_SIZE (sizeof(float) * 2 * 2 * 1024) +static unsigned char g_ReadWriteBuffer[BIG_BUFFER_SIZE]; + +#define MAX_CONVERSION_SAMPLES (2 * 32 * 1024) +#define CONVERSION_BUFFER_SIZE (sizeof(float) * 2 * MAX_CONVERSION_SAMPLES) +static unsigned char g_ConversionBuffer[CONVERSION_BUFFER_SIZE]; + +/*******************************************************************/ +static int RecordAndPlaySinesCallback( const void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + const PaStreamCallbackTimeInfo* timeInfo, + PaStreamCallbackFlags statusFlags, + void *userData ) +{ + int i; + LoopbackContext *loopbackContext = (LoopbackContext *) userData; + + + loopbackContext->callbackCount += 1; + if( statusFlags & paInputUnderflow ) loopbackContext->inputUnderflowCount += 1; + if( statusFlags & paInputOverflow ) loopbackContext->inputOverflowCount += 1; + if( statusFlags & paOutputUnderflow ) loopbackContext->outputUnderflowCount += 1; + if( statusFlags & paOutputOverflow ) loopbackContext->outputOverflowCount += 1; + if( statusFlags & paPrimingOutput ) loopbackContext->primingCount += 1; + if( framesPerBuffer > loopbackContext->maxFramesPerBuffer ) + { + loopbackContext->maxFramesPerBuffer = framesPerBuffer; + } + if( framesPerBuffer < loopbackContext->minFramesPerBuffer ) + { + loopbackContext->minFramesPerBuffer = framesPerBuffer; + } + + /* This may get called with NULL inputBuffer during initial setup. + * We may also use the same callback with output only streams. + */ + if( inputBuffer != NULL) + { + int channelsPerFrame = loopbackContext->test->inputParameters.channelCount; + float *in = (float *)inputBuffer; + PaSampleFormat inFormat = loopbackContext->test->inputParameters.sampleFormat; + + loopbackContext->inputBufferCount += 1; + + if( inFormat != paFloat32 ) + { + int samplesToConvert = framesPerBuffer * channelsPerFrame; + in = (float *) g_ConversionBuffer; + if( samplesToConvert > MAX_CONVERSION_SAMPLES ) + { + // Hack to prevent buffer overflow. + // @todo Loop with small buffer instead of failing. + printf("Format conversion buffer too small!\n"); + return paComplete; + } + PaQa_ConvertToFloat( inputBuffer, samplesToConvert, inFormat, (float *) g_ConversionBuffer ); + } + + // Read each channel from the buffer. + for( i=0; idone |= PaQa_WriteRecording( &loopbackContext->recordings[i], + in + i, + framesPerBuffer, + channelsPerFrame ); + } + } + + if( outputBuffer != NULL ) + { + int channelsPerFrame = loopbackContext->test->outputParameters.channelCount; + float *out = (float *)outputBuffer; + PaSampleFormat outFormat = loopbackContext->test->outputParameters.sampleFormat; + + loopbackContext->outputBufferCount += 1; + + if( outFormat != paFloat32 ) + { + // If we need to convert then mix to the g_ConversionBuffer and then convert into the PA outputBuffer. + out = (float *) g_ConversionBuffer; + } + + PaQa_EraseBuffer( out, framesPerBuffer, channelsPerFrame ); + for( i=0; igenerators[i], + out + i, + framesPerBuffer, + channelsPerFrame ); + } + + if( outFormat != paFloat32 ) + { + int samplesToConvert = framesPerBuffer * channelsPerFrame; + if( samplesToConvert > MAX_CONVERSION_SAMPLES ) + { + printf("Format conversion buffer too small!\n"); + return paComplete; + } + PaQa_ConvertFromFloat( out, framesPerBuffer * channelsPerFrame, outFormat, outputBuffer ); + } + + } + + // Measure whether the input or output are lagging behind. + // Don't measure lag at end. + if( !loopbackContext->done ) + { + int inputOutputDelta = loopbackContext->inputBufferCount - loopbackContext->outputBufferCount; + if( loopbackContext->maxInputOutputDelta < inputOutputDelta ) + { + loopbackContext->maxInputOutputDelta = inputOutputDelta; + } + if( loopbackContext->minInputOutputDelta > inputOutputDelta ) + { + loopbackContext->minInputOutputDelta = inputOutputDelta; + } + } + + return loopbackContext->done ? paComplete : paContinue; +} + +static void CopyStreamInfoToLoopbackContext( LoopbackContext *loopbackContext, PaStream *inputStream, PaStream *outputStream ) +{ + const PaStreamInfo *inputStreamInfo = Pa_GetStreamInfo( inputStream ); + const PaStreamInfo *outputStreamInfo = Pa_GetStreamInfo( outputStream ); + + loopbackContext->streamInfoInputLatency = inputStreamInfo ? inputStreamInfo->inputLatency : -1; + loopbackContext->streamInfoOutputLatency = outputStreamInfo ? outputStreamInfo->outputLatency : -1; +} + +/*******************************************************************/ +/** + * Open a full duplex audio stream. + * Generate sine waves on the output channels and record the input channels. + * Then close the stream. + * @return 0 if OK or negative error. + */ +int PaQa_RunLoopbackFullDuplex( LoopbackContext *loopbackContext ) +{ + PaStream *stream = NULL; + PaError err = 0; + TestParameters *test = loopbackContext->test; + loopbackContext->done = 0; + // Use one full duplex stream. + err = Pa_OpenStream( + &stream, + &test->inputParameters, + &test->outputParameters, + test->sampleRate, + test->framesPerBuffer, + paClipOff, /* we won't output out of range samples so don't bother clipping them */ + RecordAndPlaySinesCallback, + loopbackContext ); + if( err != paNoError ) goto error; + + CopyStreamInfoToLoopbackContext( loopbackContext, stream, stream ); + + err = Pa_StartStream( stream ); + if( err != paNoError ) goto error; + + // Wait for stream to finish. + while( loopbackContext->done == 0 ) + { + Pa_Sleep(PAQA_WAIT_STREAM_MSEC); + } + + err = Pa_StopStream( stream ); + if( err != paNoError ) goto error; + + err = Pa_CloseStream( stream ); + if( err != paNoError ) goto error; + + return 0; + +error: + return err; +} + +/*******************************************************************/ +/** + * Open two audio streams, one for input and one for output. + * Generate sine waves on the output channels and record the input channels. + * Then close the stream. + * @return 0 if OK or paTimedOut. + */ + +int PaQa_WaitForStream( LoopbackContext *loopbackContext ) +{ + int timeoutMSec = 1000 * PAQA_TEST_DURATION * 2; + + // Wait for stream to finish or timeout. + while( (loopbackContext->done == 0) && (timeoutMSec > 0) ) + { + Pa_Sleep(PAQA_WAIT_STREAM_MSEC); + timeoutMSec -= PAQA_WAIT_STREAM_MSEC; + } + + if( loopbackContext->done == 0 ) + { + printf("ERROR - stream completion timed out!"); + return paTimedOut; + } + return 0; +} + +/*******************************************************************/ +/** + * Open two audio streams, one for input and one for output. + * Generate sine waves on the output channels and record the input channels. + * Then close the stream. + * @return 0 if OK or negative error. + */ +int PaQa_RunLoopbackHalfDuplex( LoopbackContext *loopbackContext ) +{ + PaStream *inStream = NULL; + PaStream *outStream = NULL; + PaError err = 0; + int timedOut = 0; + TestParameters *test = loopbackContext->test; + loopbackContext->done = 0; + + // Use two half duplex streams. + err = Pa_OpenStream( + &inStream, + &test->inputParameters, + NULL, + test->sampleRate, + test->framesPerBuffer, + test->streamFlags, + RecordAndPlaySinesCallback, + loopbackContext ); + if( err != paNoError ) goto error; + err = Pa_OpenStream( + &outStream, + NULL, + &test->outputParameters, + test->sampleRate, + test->framesPerBuffer, + test->streamFlags, + RecordAndPlaySinesCallback, + loopbackContext ); + if( err != paNoError ) goto error; + + CopyStreamInfoToLoopbackContext( loopbackContext, inStream, outStream ); + + err = Pa_StartStream( inStream ); + if( err != paNoError ) goto error; + + // Start output later so we catch the beginning of the waveform. + err = Pa_StartStream( outStream ); + if( err != paNoError ) goto error; + + timedOut = PaQa_WaitForStream( loopbackContext ); + + err = Pa_StopStream( inStream ); + if( err != paNoError ) goto error; + + err = Pa_StopStream( outStream ); + if( err != paNoError ) goto error; + + err = Pa_CloseStream( inStream ); + if( err != paNoError ) goto error; + + err = Pa_CloseStream( outStream ); + if( err != paNoError ) goto error; + + return timedOut; + +error: + return err; +} + + +/*******************************************************************/ +/** + * Open one audio streams, just for input. + * Record background level. + * Then close the stream. + * @return 0 if OK or negative error. + */ +int PaQa_RunInputOnly( LoopbackContext *loopbackContext ) +{ + PaStream *inStream = NULL; + PaError err = 0; + int timedOut = 0; + TestParameters *test = loopbackContext->test; + loopbackContext->done = 0; + + // Just open an input stream. + err = Pa_OpenStream( + &inStream, + &test->inputParameters, + NULL, + test->sampleRate, + test->framesPerBuffer, + paClipOff, /* We won't output out of range samples so don't bother clipping them. */ + RecordAndPlaySinesCallback, + loopbackContext ); + if( err != paNoError ) goto error; + + err = Pa_StartStream( inStream ); + if( err != paNoError ) goto error; + + timedOut = PaQa_WaitForStream( loopbackContext ); + + err = Pa_StopStream( inStream ); + if( err != paNoError ) goto error; + + err = Pa_CloseStream( inStream ); + if( err != paNoError ) goto error; + + return timedOut; + +error: + return err; +} + +/*******************************************************************/ +static int RecordAndPlayBlockingIO( PaStream *inStream, + PaStream *outStream, + LoopbackContext *loopbackContext + ) +{ + int i; + float *in = (float *)g_ReadWriteBuffer; + float *out = (float *)g_ReadWriteBuffer; + PaError err; + int done = 0; + long available; + const long maxPerBuffer = 64; + TestParameters *test = loopbackContext->test; + long framesPerBuffer = test->framesPerBuffer; + if( framesPerBuffer <= 0 ) + { + framesPerBuffer = maxPerBuffer; // bigger values might run past end of recording + } + + // Read in audio. + err = Pa_ReadStream( inStream, in, framesPerBuffer ); + // Ignore an overflow on the first read. + //if( !((loopbackContext->callbackCount == 0) && (err == paInputOverflowed)) ) + if( err != paInputOverflowed ) + { + QA_ASSERT_EQUALS( "Pa_ReadStream failed", paNoError, err ); + } + else + { + loopbackContext->inputOverflowCount += 1; + } + + + // Save in a recording. + for( i=0; itest->inputParameters.channelCount; i++ ) + { + done |= PaQa_WriteRecording( &loopbackContext->recordings[i], + in + i, + framesPerBuffer, + loopbackContext->test->inputParameters.channelCount ); + } + + // Synthesize audio. + available = Pa_GetStreamWriteAvailable( outStream ); + if( available > (2*framesPerBuffer) ) available = (2*framesPerBuffer); + PaQa_EraseBuffer( out, available, loopbackContext->test->outputParameters.channelCount ); + for( i=0; itest->outputParameters.channelCount; i++ ) + { + PaQa_MixSine( &loopbackContext->generators[i], + out + i, + available, + loopbackContext->test->outputParameters.channelCount ); + } + + // Write out audio. + err = Pa_WriteStream( outStream, out, available ); + // Ignore an underflow on the first write. + //if( !((loopbackContext->callbackCount == 0) && (err == paOutputUnderflowed)) ) + if( err != paOutputUnderflowed ) + { + QA_ASSERT_EQUALS( "Pa_WriteStream failed", paNoError, err ); + } + else + { + loopbackContext->outputUnderflowCount += 1; + } + + + loopbackContext->callbackCount += 1; + + return done; +error: + return err; +} + + +/*******************************************************************/ +/** + * Open two audio streams with non-blocking IO. + * Generate sine waves on the output channels and record the input channels. + * Then close the stream. + * @return 0 if OK or negative error. + */ +int PaQa_RunLoopbackHalfDuplexBlockingIO( LoopbackContext *loopbackContext ) +{ + PaStream *inStream = NULL; + PaStream *outStream = NULL; + PaError err = 0; + TestParameters *test = loopbackContext->test; + + // Use two half duplex streams. + err = Pa_OpenStream( + &inStream, + &test->inputParameters, + NULL, + test->sampleRate, + test->framesPerBuffer, + paClipOff, /* we won't output out of range samples so don't bother clipping them */ + NULL, // causes non-blocking IO + NULL ); + if( err != paNoError ) goto error1; + err = Pa_OpenStream( + &outStream, + NULL, + &test->outputParameters, + test->sampleRate, + test->framesPerBuffer, + paClipOff, /* we won't output out of range samples so don't bother clipping them */ + NULL, // causes non-blocking IO + NULL ); + if( err != paNoError ) goto error2; + + CopyStreamInfoToLoopbackContext( loopbackContext, inStream, outStream ); + + err = Pa_StartStream( outStream ); + if( err != paNoError ) goto error3; + + err = Pa_StartStream( inStream ); + if( err != paNoError ) goto error3; + + while( err == 0 ) + { + err = RecordAndPlayBlockingIO( inStream, outStream, loopbackContext ); + if( err < 0 ) goto error3; + } + + err = Pa_StopStream( inStream ); + if( err != paNoError ) goto error3; + + err = Pa_StopStream( outStream ); + if( err != paNoError ) goto error3; + + err = Pa_CloseStream( outStream ); + if( err != paNoError ) goto error2; + + err = Pa_CloseStream( inStream ); + if( err != paNoError ) goto error1; + + + return 0; + +error3: + Pa_CloseStream( outStream ); +error2: + Pa_CloseStream( inStream ); +error1: + return err; +} + + +/*******************************************************************/ +/** + * Open one audio stream with non-blocking IO. + * Generate sine waves on the output channels and record the input channels. + * Then close the stream. + * @return 0 if OK or negative error. + */ +int PaQa_RunLoopbackFullDuplexBlockingIO( LoopbackContext *loopbackContext ) +{ + PaStream *stream = NULL; + PaError err = 0; + TestParameters *test = loopbackContext->test; + + // Use one full duplex stream. + err = Pa_OpenStream( + &stream, + &test->inputParameters, + &test->outputParameters, + test->sampleRate, + test->framesPerBuffer, + paClipOff, /* we won't output out of range samples so don't bother clipping them */ + NULL, // causes non-blocking IO + NULL ); + if( err != paNoError ) goto error1; + + CopyStreamInfoToLoopbackContext( loopbackContext, stream, stream ); + + err = Pa_StartStream( stream ); + if( err != paNoError ) goto error2; + + while( err == 0 ) + { + err = RecordAndPlayBlockingIO( stream, stream, loopbackContext ); + if( err < 0 ) goto error2; + } + + err = Pa_StopStream( stream ); + if( err != paNoError ) goto error2; + + + err = Pa_CloseStream( stream ); + if( err != paNoError ) goto error1; + + + return 0; + +error2: + Pa_CloseStream( stream ); +error1: + return err; +} + + +/*******************************************************************/ +/** + * Run some kind of loopback test. + * @return 0 if OK or negative error. + */ +int PaQa_RunLoopback( LoopbackContext *loopbackContext ) +{ + PaError err = 0; + TestParameters *test = loopbackContext->test; + + + if( test->flags & PAQA_FLAG_TWO_STREAMS ) + { + if( test->flags & PAQA_FLAG_USE_BLOCKING_IO ) + { + err = PaQa_RunLoopbackHalfDuplexBlockingIO( loopbackContext ); + } + else + { + err = PaQa_RunLoopbackHalfDuplex( loopbackContext ); + } + } + else + { + if( test->flags & PAQA_FLAG_USE_BLOCKING_IO ) + { + err = PaQa_RunLoopbackFullDuplexBlockingIO( loopbackContext ); + } + else + { + err = PaQa_RunLoopbackFullDuplex( loopbackContext ); + } + } + + if( err != paNoError ) + { + printf("PortAudio error = %s\n", Pa_GetErrorText( err ) ); + } + return err; +} + +/*******************************************************************/ +static int PaQa_SaveTestResultToWaveFile( UserOptions *userOptions, PaQaRecording *recording ) +{ + if( userOptions->saveBadWaves ) + { + char filename[256]; +#ifdef WIN32 + _snprintf( filename, sizeof(filename), "%s\\paloopback_%d.wav", userOptions->waveFilePath, userOptions->waveFileCount++ ); +#else + snprintf( filename, sizeof(filename), "%s/paloopback_%d.wav", userOptions->waveFilePath, userOptions->waveFileCount++ ); +#endif + printf( "\"%s\", ", filename ); + return PaQa_SaveRecordingToWaveFile( recording, filename ); + } + return 0; +} + +/*******************************************************************/ +static int PaQa_SetupLoopbackContext( LoopbackContext *loopbackContextPtr, TestParameters *testParams ) +{ + int i; + // Setup loopback context. + memset( loopbackContextPtr, 0, sizeof(LoopbackContext) ); + loopbackContextPtr->test = testParams; + for( i=0; isamplesPerFrame; i++ ) + { + int err = PaQa_InitializeRecording( &loopbackContextPtr->recordings[i], testParams->maxFrames, testParams->sampleRate ); + QA_ASSERT_EQUALS( "PaQa_InitializeRecording failed", paNoError, err ); + } + for( i=0; isamplesPerFrame; i++ ) + { + PaQa_SetupSineGenerator( &loopbackContextPtr->generators[i], PaQa_GetNthFrequency( testParams->baseFrequency, i ), + testParams->amplitude, testParams->sampleRate ); + } + loopbackContextPtr->minFramesPerBuffer = 0x0FFFFFFF; + return 0; +error: + return -1; +} + +/*******************************************************************/ +static void PaQa_TeardownLoopbackContext( LoopbackContext *loopbackContextPtr ) +{ + int i; + if( loopbackContextPtr->test != NULL ) + { + for( i=0; itest->samplesPerFrame; i++ ) + { + PaQa_TerminateRecording( &loopbackContextPtr->recordings[i] ); + } + } +} + +/*******************************************************************/ +static void PaQa_PrintShortErrorReport( PaQaAnalysisResult *analysisResultPtr, int channel ) +{ + printf("channel %d ", channel); + if( analysisResultPtr->popPosition > 0 ) + { + printf("POP %0.3f at %d, ", (double)analysisResultPtr->popAmplitude, (int)analysisResultPtr->popPosition ); + } + else + { + if( analysisResultPtr->addedFramesPosition > 0 ) + { + printf("ADD %d at %d ", (int)analysisResultPtr->numAddedFrames, (int)analysisResultPtr->addedFramesPosition ); + } + + if( analysisResultPtr->droppedFramesPosition > 0 ) + { + printf("DROP %d at %d ", (int)analysisResultPtr->numDroppedFrames, (int)analysisResultPtr->droppedFramesPosition ); + } + } +} + +/*******************************************************************/ +static void PaQa_PrintFullErrorReport( PaQaAnalysisResult *analysisResultPtr, int channel ) +{ + printf("\n=== Loopback Analysis ===================\n"); + printf(" channel: %d\n", channel ); + printf(" latency: %10.3f\n", analysisResultPtr->latency ); + printf(" amplitudeRatio: %10.3f\n", (double)analysisResultPtr->amplitudeRatio ); + printf(" popPosition: %10.3f\n", (double)analysisResultPtr->popPosition ); + printf(" popAmplitude: %10.3f\n", (double)analysisResultPtr->popAmplitude ); + printf(" num added frames: %10.3f\n", analysisResultPtr->numAddedFrames ); + printf(" added frames at: %10.3f\n", analysisResultPtr->addedFramesPosition ); + printf(" num dropped frames: %10.3f\n", analysisResultPtr->numDroppedFrames ); + printf(" dropped frames at: %10.3f\n", analysisResultPtr->droppedFramesPosition ); +} + +/*******************************************************************/ +/** + * Test loopback connection using the given parameters. + * @return number of channels with glitches, or negative error. + */ +static int PaQa_SingleLoopBackTest( UserOptions *userOptions, TestParameters *testParams ) +{ + int i; + LoopbackContext loopbackContext; + PaError err = paNoError; + PaQaTestTone testTone; + PaQaAnalysisResult analysisResult; + int numBadChannels = 0; + + printf("| %5d | %6d | ", ((int)(testParams->sampleRate+0.5)), testParams->framesPerBuffer ); + fflush(stdout); + + testTone.samplesPerFrame = testParams->samplesPerFrame; + testTone.sampleRate = testParams->sampleRate; + testTone.amplitude = testParams->amplitude; + testTone.startDelay = 0; + + err = PaQa_SetupLoopbackContext( &loopbackContext, testParams ); + if( err ) return err; + + err = PaQa_RunLoopback( &loopbackContext ); + QA_ASSERT_TRUE("loopback did not run", (loopbackContext.callbackCount > 1) ); + + printf( "%7.2f %7.2f %7.2f | ", + loopbackContext.streamInfoInputLatency * 1000.0, + loopbackContext.streamInfoOutputLatency * 1000.0, + (loopbackContext.streamInfoInputLatency + loopbackContext.streamInfoOutputLatency) * 1000.0 + ); + + printf( "%4d/%4d/%4d, %4d/%4d/%4d | ", + loopbackContext.inputOverflowCount, + loopbackContext.inputUnderflowCount, + loopbackContext.inputBufferCount, + loopbackContext.outputOverflowCount, + loopbackContext.outputUnderflowCount, + loopbackContext.outputBufferCount + ); + + // Analyse recording to detect glitches. + for( i=0; isamplesPerFrame; i++ ) + { + double freq = PaQa_GetNthFrequency( testParams->baseFrequency, i ); + testTone.frequency = freq; + + PaQa_AnalyseRecording( &loopbackContext.recordings[i], &testTone, &analysisResult ); + + if( i==0 ) + { + double latencyMSec; + + printf( "%4d-%4d | ", + loopbackContext.minFramesPerBuffer, + loopbackContext.maxFramesPerBuffer + ); + + latencyMSec = 1000.0 * analysisResult.latency / testParams->sampleRate; + printf("%7.2f | ", latencyMSec ); + + } + + if( analysisResult.valid ) + { + int badChannel = ( (analysisResult.popPosition > 0) + || (analysisResult.addedFramesPosition > 0) + || (analysisResult.droppedFramesPosition > 0) ); + + if( badChannel ) + { + if( userOptions->verbose ) + { + PaQa_PrintFullErrorReport( &analysisResult, i ); + } + else + { + PaQa_PrintShortErrorReport( &analysisResult, i ); + } + PaQa_SaveTestResultToWaveFile( userOptions, &loopbackContext.recordings[i] ); + } + numBadChannels += badChannel; + } + else + { + printf( "[%d] No or low signal, ampRatio = %f", i, analysisResult.amplitudeRatio ); + numBadChannels += 1; + } + + } + if( numBadChannels == 0 ) + { + printf( "OK" ); + } + + // Print the # errors so far to make it easier to see where the error occured. + printf( " - #errs = %d\n", g_testsFailed ); + + PaQa_TeardownLoopbackContext( &loopbackContext ); + if( numBadChannels > 0 ) + { + g_testsFailed += 1; + } + return numBadChannels; + +error: + PaQa_TeardownLoopbackContext( &loopbackContext ); + printf( "\n" ); + g_testsFailed += 1; + return err; +} + +/*******************************************************************/ +static void PaQa_SetDefaultTestParameters( TestParameters *testParamsPtr, PaDeviceIndex inputDevice, PaDeviceIndex outputDevice ) +{ + memset( testParamsPtr, 0, sizeof(TestParameters) ); + + testParamsPtr->samplesPerFrame = 2; + testParamsPtr->amplitude = 0.5; + testParamsPtr->sampleRate = 44100; + testParamsPtr->maxFrames = (int) (PAQA_TEST_DURATION * testParamsPtr->sampleRate); + testParamsPtr->framesPerBuffer = DEFAULT_FRAMES_PER_BUFFER; + testParamsPtr->baseFrequency = 200.0; + testParamsPtr->flags = PAQA_FLAG_TWO_STREAMS; + testParamsPtr->streamFlags = paClipOff; /* we won't output out of range samples so don't bother clipping them */ + + testParamsPtr->inputParameters.device = inputDevice; + testParamsPtr->inputParameters.sampleFormat = paFloat32; + testParamsPtr->inputParameters.channelCount = testParamsPtr->samplesPerFrame; + testParamsPtr->inputParameters.suggestedLatency = Pa_GetDeviceInfo( inputDevice )->defaultLowInputLatency; + //testParamsPtr->inputParameters.suggestedLatency = Pa_GetDeviceInfo( inputDevice )->defaultHighInputLatency; + + testParamsPtr->outputParameters.device = outputDevice; + testParamsPtr->outputParameters.sampleFormat = paFloat32; + testParamsPtr->outputParameters.channelCount = testParamsPtr->samplesPerFrame; + testParamsPtr->outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputDevice )->defaultLowOutputLatency; + //testParamsPtr->outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputDevice )->defaultHighOutputLatency; +} + +/*******************************************************************/ +static void PaQa_OverrideTestParameters( TestParameters *testParamsPtr, UserOptions *userOptions ) +{ + // Check to see if a specific value was requested. + if( userOptions->sampleRate >= 0 ) + { + testParamsPtr->sampleRate = userOptions->sampleRate; + testParamsPtr->maxFrames = (int) (PAQA_TEST_DURATION * testParamsPtr->sampleRate); + } + if( userOptions->framesPerBuffer >= 0 ) + { + testParamsPtr->framesPerBuffer = userOptions->framesPerBuffer; + } + if( userOptions->inputLatency >= 0 ) + { + testParamsPtr->inputParameters.suggestedLatency = userOptions->inputLatency * 0.001; + } + if( userOptions->outputLatency >= 0 ) + { + testParamsPtr->outputParameters.suggestedLatency = userOptions->outputLatency * 0.001; + } + printf( " Running with suggested latency (msec): input = %5.2f, out = %5.2f\n", + (testParamsPtr->inputParameters.suggestedLatency * 1000.0), + (testParamsPtr->outputParameters.suggestedLatency * 1000.0) ); +} + +/*******************************************************************/ +/** + * Run a series of tests on this loopback connection. + * @return number of bad channel results + */ +static int PaQa_AnalyzeLoopbackConnection( UserOptions *userOptions, PaDeviceIndex inputDevice, PaDeviceIndex outputDevice ) +{ + int iFlags; + int iRate; + int iSize; + int iFormat; + int savedValue; + TestParameters testParams; + const PaDeviceInfo *inputDeviceInfo = Pa_GetDeviceInfo( inputDevice ); + const PaDeviceInfo *outputDeviceInfo = Pa_GetDeviceInfo( outputDevice ); + int totalBadChannels = 0; + + // test half duplex first because it is more likely to work. + int flagSettings[] = { PAQA_FLAG_TWO_STREAMS, 0 }; + int numFlagSettings = (sizeof(flagSettings)/sizeof(int)); + + double sampleRates[] = { 8000.0, 11025.0, 16000.0, 22050.0, 32000.0, 44100.0, 48000.0, 96000.0 }; + int numRates = (sizeof(sampleRates)/sizeof(double)); + + // framesPerBuffer==0 means PA decides on the buffer size. + int framesPerBuffers[] = { 0, 16, 32, 40, 64, 100, 128, 256, 512, 1024 }; + int numBufferSizes = (sizeof(framesPerBuffers)/sizeof(int)); + + PaSampleFormat sampleFormats[] = { paFloat32, paUInt8, paInt8, paInt16, paInt32 }; + const char *sampleFormatNames[] = { "paFloat32", "paUInt8", "paInt8", "paInt16", "paInt32" }; + int numSampleFormats = (sizeof(sampleFormats)/sizeof(PaSampleFormat)); + + printf( "=============== Analysing Loopback %d to %d =====================\n", outputDevice, inputDevice ); + printf( " Devices: %s => %s\n", outputDeviceInfo->name, inputDeviceInfo->name); + + PaQa_SetDefaultTestParameters( &testParams, inputDevice, outputDevice ); + + PaQa_OverrideTestParameters( &testParams, userOptions ); + + // Loop though combinations of audio parameters. + for( iFlags=0; iFlagssampleRate < 0 ) + { + savedValue = testParams.sampleRate; + for( iRate=0; iRateframesPerBuffer < 0 ) + { + savedValue = testParams.framesPerBuffer; + for( iSize=0; iSizetest; + + // Start in the middle assuming past latency. + int startFrame = testParamsPtr->maxFrames/2; + int numFrames = testParamsPtr->maxFrames/2; + + // Check to see if the signal is clipped. + double amplitudeLeft = PaQa_MeasureSineAmplitudeBySlope( &loopbackContextPtr->recordings[0], + testParamsPtr->baseFrequency, testParamsPtr->sampleRate, + startFrame, numFrames ); + double gainLeft = amplitudeLeft / testParamsPtr->amplitude; + double amplitudeRight = PaQa_MeasureSineAmplitudeBySlope( &loopbackContextPtr->recordings[1], + testParamsPtr->baseFrequency, testParamsPtr->sampleRate, + startFrame, numFrames ); + double gainRight = amplitudeLeft / testParamsPtr->amplitude; + printf(" Loop gain: left = %f, right = %f\n", gainLeft, gainRight ); + + if( (amplitudeLeft > 1.0 ) || (amplitudeRight > 1.0) ) + { + printf("ERROR - loop gain is too high. Should be around than 1.0. Please lower output level and/or input gain.\n" ); + clipped = 1; + } + return clipped; +} + +/*******************************************************************/ +int PaQa_MeasureBackgroundNoise( LoopbackContext *loopbackContextPtr, double *rmsPtr ) +{ + int result = 0; + *rmsPtr = 0.0; + // Rewind so we can record some input. + loopbackContextPtr->recordings[0].numFrames = 0; + loopbackContextPtr->recordings[1].numFrames = 0; + result = PaQa_RunInputOnly( loopbackContextPtr ); + if( result == 0 ) + { + double leftRMS = PaQa_MeasureRootMeanSquare( loopbackContextPtr->recordings[0].buffer, + loopbackContextPtr->recordings[0].numFrames ); + double rightRMS = PaQa_MeasureRootMeanSquare( loopbackContextPtr->recordings[1].buffer, + loopbackContextPtr->recordings[1].numFrames ); + *rmsPtr = (leftRMS + rightRMS) / 2.0; + } + return result; +} + +/*******************************************************************/ +/** + * Output a sine wave then try to detect it on input. + * + * @return 1 if loopback connected, 0 if not, or negative error. + */ +int PaQa_CheckForLoopBack( UserOptions *userOptions, PaDeviceIndex inputDevice, PaDeviceIndex outputDevice ) +{ + TestParameters testParams; + LoopbackContext loopbackContext; + const PaDeviceInfo *inputDeviceInfo; + const PaDeviceInfo *outputDeviceInfo; + PaError err = paNoError; + double minAmplitude; + int loopbackIsConnected; + int startFrame, numFrames; + double magLeft, magRight; + + inputDeviceInfo = Pa_GetDeviceInfo( inputDevice ); + if( inputDeviceInfo == NULL ) + { + printf("ERROR - Pa_GetDeviceInfo for input returned NULL.\n"); + return paInvalidDevice; + } + if( inputDeviceInfo->maxInputChannels < 2 ) + { + return 0; + } + + outputDeviceInfo = Pa_GetDeviceInfo( outputDevice ); + if( outputDeviceInfo == NULL ) + { + printf("ERROR - Pa_GetDeviceInfo for output returned NULL.\n"); + return paInvalidDevice; + } + if( outputDeviceInfo->maxOutputChannels < 2 ) + { + return 0; + } + + printf( "Look for loopback cable between \"%s\" => \"%s\"\n", outputDeviceInfo->name, inputDeviceInfo->name); + + printf( " Default suggested input latency (msec): low = %5.2f, high = %5.2f\n", + (inputDeviceInfo->defaultLowInputLatency * 1000.0), + (inputDeviceInfo->defaultHighInputLatency * 1000.0) ); + printf( " Default suggested output latency (msec): low = %5.2f, high = %5.2f\n", + (outputDeviceInfo->defaultLowOutputLatency * 1000.0), + (outputDeviceInfo->defaultHighOutputLatency * 1000.0) ); + + PaQa_SetDefaultTestParameters( &testParams, inputDevice, outputDevice ); + + PaQa_OverrideTestParameters( &testParams, userOptions ); + + testParams.maxFrames = (int) (LOOPBACK_DETECTION_DURATION_SECONDS * testParams.sampleRate); + minAmplitude = testParams.amplitude / 4.0; + + // Check to see if the selected formats are supported. + if( Pa_IsFormatSupported( &testParams.inputParameters, NULL, testParams.sampleRate ) != paFormatIsSupported ) + { + printf( "Input not supported for this format!\n" ); + return 0; + } + if( Pa_IsFormatSupported( NULL, &testParams.outputParameters, testParams.sampleRate ) != paFormatIsSupported ) + { + printf( "Output not supported for this format!\n" ); + return 0; + } + + PaQa_SetupLoopbackContext( &loopbackContext, &testParams ); + + if( inputDevice == outputDevice ) + { + // Use full duplex if checking for loopback on one device. + testParams.flags &= ~PAQA_FLAG_TWO_STREAMS; + } + else + { + // Use half duplex if checking for loopback on two different device. + testParams.flags = PAQA_FLAG_TWO_STREAMS; + } + err = PaQa_RunLoopback( &loopbackContext ); + QA_ASSERT_TRUE("loopback detection callback did not run", (loopbackContext.callbackCount > 1) ); + + // Analyse recording to see if we captured the output. + // Start in the middle assuming past latency. + startFrame = testParams.maxFrames/2; + numFrames = testParams.maxFrames/2; + magLeft = PaQa_CorrelateSine( &loopbackContext.recordings[0], + loopbackContext.generators[0].frequency, + testParams.sampleRate, + startFrame, numFrames, NULL ); + magRight = PaQa_CorrelateSine( &loopbackContext.recordings[1], + loopbackContext.generators[1].frequency, + testParams.sampleRate, + startFrame, numFrames, NULL ); + printf(" Amplitudes: left = %f, right = %f\n", magLeft, magRight ); + + // Check for backwards cable. + loopbackIsConnected = ((magLeft > minAmplitude) && (magRight > minAmplitude)); + + if( !loopbackIsConnected ) + { + double magLeftReverse = PaQa_CorrelateSine( &loopbackContext.recordings[0], + loopbackContext.generators[1].frequency, + testParams.sampleRate, + startFrame, numFrames, NULL ); + + double magRightReverse = PaQa_CorrelateSine( &loopbackContext.recordings[1], + loopbackContext.generators[0].frequency, + testParams.sampleRate, + startFrame, numFrames, NULL ); + + if ((magLeftReverse > minAmplitude) && (magRightReverse>minAmplitude)) + { + printf("ERROR - You seem to have the left and right channels swapped on the loopback cable!\n"); + } + } + else + { + double rms = 0.0; + if( PaQa_CheckForClippedLoopback( &loopbackContext ) ) + { + // Clipped so don't use this loopback. + loopbackIsConnected = 0; + } + + err = PaQa_MeasureBackgroundNoise( &loopbackContext, &rms ); + printf(" Background noise = %f\n", rms ); + if( err ) + { + printf("ERROR - Could not measure background noise on this input!\n"); + loopbackIsConnected = 0; + } + else if( rms > MAX_BACKGROUND_NOISE_RMS ) + { + printf("ERROR - There is too much background noise on this input!\n"); + loopbackIsConnected = 0; + } + } + + PaQa_TeardownLoopbackContext( &loopbackContext ); + return loopbackIsConnected; + +error: + PaQa_TeardownLoopbackContext( &loopbackContext ); + return err; +} + +/*******************************************************************/ +/** + * If there is a loopback connection then run the analysis. + */ +static int CheckLoopbackAndScan( UserOptions *userOptions, + PaDeviceIndex iIn, PaDeviceIndex iOut ) +{ + int loopbackConnected = PaQa_CheckForLoopBack( userOptions, iIn, iOut ); + if( loopbackConnected > 0 ) + { + PaQa_AnalyzeLoopbackConnection( userOptions, iIn, iOut ); + return 1; + } + return 0; +} + +/*******************************************************************/ +/** + * Scan every combination of output to input device. + * If a loopback is found the analyse the combination. + * The scan can be overriden using the -i and -o command line options. + */ +static int ScanForLoopback(UserOptions *userOptions) +{ + PaDeviceIndex iIn,iOut; + int numLoopbacks = 0; + int numDevices; + numDevices = Pa_GetDeviceCount(); + + // If both devices are specified then just use that combination. + if ((userOptions->inputDevice >= 0) && (userOptions->outputDevice >= 0)) + { + numLoopbacks += CheckLoopbackAndScan( userOptions, userOptions->inputDevice, userOptions->outputDevice ); + } + else if (userOptions->inputDevice >= 0) + { + // Just scan for output. + for( iOut=0; iOutinputDevice, iOut ); + } + } + else if (userOptions->outputDevice >= 0) + { + // Just scan for input. + for( iIn=0; iInoutputDevice ); + } + } + else + { + // Scan both. + for( iOut=0; iOut 0) ); + return numLoopbacks; + +error: + return -1; +} + +/*==========================================================================================*/ +int TestSampleFormatConversion( void ) +{ + int i; + const float floatInput[] = { 1.0, 0.5, -0.5, -1.0 }; + + const char charInput[] = { 127, 64, -64, -128 }; + const unsigned char ucharInput[] = { 255, 128+64, 64, 0 }; + const short shortInput[] = { 32767, 32768/2, -32768/2, -32768 }; + const int intInput[] = { 2147483647, 2147483647/2, -1073741824 /*-2147483648/2 doesn't work in msvc*/, -2147483648 }; + + float floatOutput[4]; + short shortOutput[4]; + int intOutput[4]; + unsigned char ucharOutput[4]; + char charOutput[4]; + + QA_ASSERT_EQUALS("int must be 32-bit", 4, (int) sizeof(int) ); + QA_ASSERT_EQUALS("short must be 16-bit", 2, (int) sizeof(short) ); + + // from Float ====== + PaQa_ConvertFromFloat( floatInput, 4, paUInt8, ucharOutput ); + for( i=0; i<4; i++ ) + { + QA_ASSERT_CLOSE_INT( "paFloat32 -> paUInt8 -> error", ucharInput[i], ucharOutput[i], 1 ); + } + + PaQa_ConvertFromFloat( floatInput, 4, paInt8, charOutput ); + for( i=0; i<4; i++ ) + { + QA_ASSERT_CLOSE_INT( "paFloat32 -> paInt8 -> error", charInput[i], charOutput[i], 1 ); + } + + PaQa_ConvertFromFloat( floatInput, 4, paInt16, shortOutput ); + for( i=0; i<4; i++ ) + { + QA_ASSERT_CLOSE_INT( "paFloat32 -> paInt16 error", shortInput[i], shortOutput[i], 1 ); + } + + PaQa_ConvertFromFloat( floatInput, 4, paInt32, intOutput ); + for( i=0; i<4; i++ ) + { + QA_ASSERT_CLOSE_INT( "paFloat32 -> paInt32 error", intInput[i], intOutput[i], 0x00010000 ); + } + + + // to Float ====== + memset( floatOutput, 0, sizeof(floatOutput) ); + PaQa_ConvertToFloat( ucharInput, 4, paUInt8, floatOutput ); + for( i=0; i<4; i++ ) + { + QA_ASSERT_CLOSE( "paUInt8 -> paFloat32 error", floatInput[i], floatOutput[i], 0.01 ); + } + + memset( floatOutput, 0, sizeof(floatOutput) ); + PaQa_ConvertToFloat( charInput, 4, paInt8, floatOutput ); + for( i=0; i<4; i++ ) + { + QA_ASSERT_CLOSE( "paInt8 -> paFloat32 error", floatInput[i], floatOutput[i], 0.01 ); + } + + memset( floatOutput, 0, sizeof(floatOutput) ); + PaQa_ConvertToFloat( shortInput, 4, paInt16, floatOutput ); + for( i=0; i<4; i++ ) + { + QA_ASSERT_CLOSE( "paInt16 -> paFloat32 error", floatInput[i], floatOutput[i], 0.001 ); + } + + memset( floatOutput, 0, sizeof(floatOutput) ); + PaQa_ConvertToFloat( intInput, 4, paInt32, floatOutput ); + for( i=0; i<4; i++ ) + { + QA_ASSERT_CLOSE( "paInt32 -> paFloat32 error", floatInput[i], floatOutput[i], 0.00001 ); + } + + return 0; + +error: + return -1; +} + + +/*******************************************************************/ +void usage( const char *name ) +{ + printf("%s [-i# -o# -l# -r# -s# -m -w -dDir]\n", name); + printf(" -i# - Input device ID. Will scan for loopback cable if not specified.\n"); + printf(" -o# - Output device ID. Will scan for loopback if not specified.\n"); + printf(" -l# - Latency for both input and output in milliseconds.\n"); + printf(" --inputLatency # Input latency in milliseconds.\n"); + printf(" --outputLatency # Output latency in milliseconds.\n"); + printf(" -r# - Sample Rate in Hz. Will use multiple common rates if not specified.\n"); + printf(" -s# - Size of callback buffer in frames, framesPerBuffer. Will use common values if not specified.\n"); + printf(" -w - Save bad recordings in a WAV file.\n"); + printf(" -dDir - Path for Directory for WAV files. Default is current directory.\n"); + printf(" -m - Just test the DSP Math code and not the audio devices.\n"); + printf(" -v - Verbose reports.\n"); +} + +/*******************************************************************/ +int main( int argc, char **argv ) +{ + int i; + UserOptions userOptions; + int result = 0; + int justMath = 0; + char *executableName = argv[0]; + + printf("PortAudio LoopBack Test built " __DATE__ " at " __TIME__ "\n"); + + if( argc > 1 ){ + printf("running with arguments:"); + for(i=1; i < argc; ++i ) + printf(" %s", argv[i] ); + printf("\n"); + }else{ + printf("running with no arguments\n"); + } + + memset(&userOptions, 0, sizeof(userOptions)); + userOptions.inputDevice = paNoDevice; + userOptions.outputDevice = paNoDevice; + userOptions.sampleRate = -1; + userOptions.framesPerBuffer = -1; + userOptions.inputLatency = -1; + userOptions.outputLatency = -1; + userOptions.waveFilePath = "."; + + // Process arguments. Skip name of executable. + i = 1; + while( imaxInputChannels ); + printf( ", %2d out", deviceInfo->maxOutputChannels ); + printf( ", %s", deviceInfo->name ); + printf( ", on %s\n", Pa_GetHostApiInfo( deviceInfo->hostApi )->name ); + } +} + +/*******************************************************************/ +void PaQa_ConvertToFloat( const void *input, int numSamples, PaSampleFormat inFormat, float *output ) +{ + int i; + switch( inFormat ) + { + case paUInt8: + { + unsigned char *data = (unsigned char *)input; + for( i=0; i> 8; + float fval = (float) (value / ((double) 0x00800000)); + *output++ = fval; + } + } + break; + } + +} + +/*******************************************************************/ +void PaQa_ConvertFromFloat( const float *input, int numSamples, PaSampleFormat outFormat, void *output ) +{ + int i; + switch( outFormat ) + { + case paUInt8: + { + unsigned char *data = (unsigned char *)output; + for( i=0; i +#include "portaudio.h" + +void PaQa_ListAudioDevices(void); + +void PaQa_ConvertToFloat( const void *input, int numSamples, PaSampleFormat inFormat, float *output ); + +void PaQa_ConvertFromFloat( const float *input, int numSamples, PaSampleFormat outFormat, void *output ); + +#endif /* _PAQA_TOOLS_H */ diff --git a/extern/portaudio/qa/loopback/src/qa_tools.h b/extern/portaudio/qa/loopback/src/qa_tools.h new file mode 100755 index 0000000..320236e --- /dev/null +++ b/extern/portaudio/qa/loopback/src/qa_tools.h @@ -0,0 +1,83 @@ + +/* + * PortAudio Portable Real-Time Audio Library + * Latest Version at: http://www.portaudio.com + * + * Copyright (c) 1999-2010 Phil Burk and Ross Bencina + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +#ifndef _QA_TOOLS_H +#define _QA_TOOLS_H + +extern int g_testsPassed; +extern int g_testsFailed; + +#define QA_ASSERT_TRUE( message, flag ) \ + if( !(flag) ) \ + { \ + printf( "%s:%d - ERROR - %s\n", __FILE__, __LINE__, message ); \ + g_testsFailed++; \ + goto error; \ + } \ + else g_testsPassed++; + + +#define QA_ASSERT_EQUALS( message, expected, actual ) \ + if( ((expected) != (actual)) ) \ + { \ + printf( "%s:%d - ERROR - %s, expected %d, got %d\n", __FILE__, __LINE__, message, expected, actual ); \ + g_testsFailed++; \ + goto error; \ + } \ + else g_testsPassed++; + +#define QA_ASSERT_CLOSE( message, expected, actual, tolerance ) \ + if (fabs((expected)-(actual))>(tolerance)) \ + { \ + printf( "%s:%d - ERROR - %s, expected %f, got %f, tol=%f\n", __FILE__, __LINE__, message, ((double)(expected)), ((double)(actual)), ((double)(tolerance)) ); \ + g_testsFailed++; \ + goto error; \ + } \ + else g_testsPassed++; + +#define QA_ASSERT_CLOSE_INT( message, expected, actual, tolerance ) \ + if (abs((expected)-(actual))>(tolerance)) \ + { \ + printf( "%s:%d - ERROR - %s, expected %d, got %d, tol=%d\n", __FILE__, __LINE__, message, ((int)(expected)), ((int)(actual)), ((int)(tolerance)) ); \ + g_testsFailed++; \ + goto error; \ + } \ + else g_testsPassed++; + + +#endif diff --git a/extern/portaudio/qa/loopback/src/test_audio_analyzer.c b/extern/portaudio/qa/loopback/src/test_audio_analyzer.c new file mode 100644 index 0000000..add57d4 --- /dev/null +++ b/extern/portaudio/qa/loopback/src/test_audio_analyzer.c @@ -0,0 +1,718 @@ + +/* + * PortAudio Portable Real-Time Audio Library + * Latest Version at: http://www.portaudio.com + * + * Copyright (c) 1999-2010 Phil Burk and Ross Bencina + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +#include +#include +#include +#include "qa_tools.h" +#include "audio_analyzer.h" +#include "test_audio_analyzer.h" +#include "write_wav.h" +#include "biquad_filter.h" + +#define FRAMES_PER_BLOCK (64) +#define PRINT_REPORTS 0 + +#define TEST_SAVED_WAVE (0) + +/*==========================================================================================*/ +/** + * Detect a single tone. + */ +static int TestSingleMonoTone( void ) +{ + int result = 0; + PaQaSineGenerator generator; + PaQaRecording recording; + float buffer[FRAMES_PER_BLOCK]; + double sampleRate = 44100.0; + int maxFrames = ((int)sampleRate) * 1; + int samplesPerFrame = 1; + int stride = 1; + int done = 0; + + double freq = 234.5; + double amp = 0.5; + + double mag1, mag2; + + // Setup a sine oscillator. + PaQa_SetupSineGenerator( &generator, freq, amp, sampleRate ); + + result = PaQa_InitializeRecording( &recording, maxFrames, (int) sampleRate ); + QA_ASSERT_EQUALS( "PaQa_InitializeRecording failed", 0, result ); + + done = 0; + while (!done) + { + PaQa_EraseBuffer( buffer, FRAMES_PER_BLOCK, samplesPerFrame ); + PaQa_MixSine( &generator, buffer, FRAMES_PER_BLOCK, stride ); + done = PaQa_WriteRecording( &recording, buffer, FRAMES_PER_BLOCK, samplesPerFrame ); + } + + mag1 = PaQa_CorrelateSine( &recording, freq, sampleRate, 0, recording.numFrames, NULL ); + QA_ASSERT_CLOSE( "exact frequency match", amp, mag1, 0.01 ); + + mag2 = PaQa_CorrelateSine( &recording, freq * 1.23, sampleRate, 0, recording.numFrames, NULL ); + QA_ASSERT_CLOSE( "wrong frequency", 0.0, mag2, 0.01 ); + + PaQa_TerminateRecording( &recording ); + return 0; + +error: + PaQa_TerminateRecording( &recording); + return 1; + +} + +/*==========================================================================================*/ +/** + * Mix multiple tones and then detect them. + */ + +static int TestMixedMonoTones( void ) +{ + int i; + int result = 0; +#define NUM_TONES (5) + PaQaSineGenerator generators[NUM_TONES]; + PaQaRecording recording; + float buffer[FRAMES_PER_BLOCK]; + double sampleRate = 44100.0; + int maxFrames = ((int)sampleRate) * 1; + int samplesPerFrame = 1; + + double baseFreq = 234.5; + double amp = 0.1; + + double mag2; + + int stride = samplesPerFrame; + int done = 0; + + // Setup a sine oscillator. + for( i=0; istartDelay; + + int stride = 1; + // Record some initial silence. + int done = PaQa_WriteSilence( recording, testTone->startDelay ); + + // Setup a sine oscillator. + PaQa_SetupSineGenerator( &generator, testTone->frequency, testTone->amplitude, testTone->sampleRate ); + + while (!done) + { + int framesThisLoop = BUFFER_SIZE; + + if( frameCounter == glitchPosition ) + { + if( framesToAdd > 0 ) + { + // Record some frozen data without advancing the sine generator. + done = PaQa_RecordFreeze( recording, framesToAdd ); + frameCounter += framesToAdd; + } + else if( framesToAdd < 0 ) + { + // Advance sine generator a few frames. + PaQa_MixSine( &generator, buffer, 0 - framesToAdd, stride ); + } + + } + else if( (frameCounter < glitchPosition) && ((frameCounter + framesThisLoop) > glitchPosition) ) + { + // Go right up to the glitchPosition. + framesThisLoop = glitchPosition - frameCounter; + } + + if( framesThisLoop > 0 ) + { + PaQa_EraseBuffer( buffer, framesThisLoop, testTone->samplesPerFrame ); + PaQa_MixSine( &generator, buffer, framesThisLoop, stride ); + done = PaQa_WriteRecording( recording, buffer, framesThisLoop, testTone->samplesPerFrame ); + } + frameCounter += framesThisLoop; + } +} + + +/*==========================================================================================*/ +/** + * Generate a clean recording. + */ + +static void MakeCleanRecording( PaQaRecording *recording, PaQaTestTone *testTone ) +{ + PaQaSineGenerator generator; +#define BUFFER_SIZE 512 + float buffer[BUFFER_SIZE]; + + int stride = 1; + // Record some initial silence. + int done = PaQa_WriteSilence( recording, testTone->startDelay ); + + // Setup a sine oscillator. + PaQa_SetupSineGenerator( &generator, testTone->frequency, testTone->amplitude, testTone->sampleRate ); + + // Generate recording with good phase. + while (!done) + { + PaQa_EraseBuffer( buffer, BUFFER_SIZE, testTone->samplesPerFrame ); + PaQa_MixSine( &generator, buffer, BUFFER_SIZE, stride ); + done = PaQa_WriteRecording( recording, buffer, BUFFER_SIZE, testTone->samplesPerFrame ); + } +} + +/*==========================================================================================*/ +/** + * Generate a recording with pop. + */ + +static void MakeRecordingWithPop( PaQaRecording *recording, PaQaTestTone *testTone, int popPosition, int popWidth, double popAmplitude ) +{ + int i; + + MakeCleanRecording( recording, testTone ); + + // Apply glitch to good recording. + if( (popPosition + popWidth) >= recording->numFrames ) + { + popWidth = (recording->numFrames - popPosition) - 1; + } + + for( i=0; ibuffer[i+popPosition]; + float bad = (good > 0.0) ? (good - popAmplitude) : (good + popAmplitude); + recording->buffer[i+popPosition] = bad; + } +} + +/*==========================================================================================*/ +/** + * Detect one phase error in a recording. + */ +static int TestDetectSinglePhaseError( double sampleRate, int cycleSize, int latencyFrames, int glitchPosition, int framesAdded ) +{ + int result = 0; + PaQaRecording recording; + PaQaTestTone testTone; + PaQaAnalysisResult analysisResult = { 0.0 }; + int framesDropped = 0; + int maxFrames = ((int)sampleRate) * 2; + + testTone.samplesPerFrame = 1; + testTone.sampleRate = sampleRate; + testTone.frequency = sampleRate / cycleSize; + testTone.amplitude = 0.5; + testTone.startDelay = latencyFrames; + + result = PaQa_InitializeRecording( &recording, maxFrames, (int) sampleRate ); + QA_ASSERT_EQUALS( "PaQa_InitializeRecording failed", 0, result ); + + MakeRecordingWithAddedFrames( &recording, &testTone, glitchPosition, framesAdded ); + + PaQa_AnalyseRecording( &recording, &testTone, &analysisResult ); + + if( framesAdded < 0 ) + { + framesDropped = -framesAdded; + framesAdded = 0; + } + +#if PRINT_REPORTS + printf("\n=== Dropped Frame Analysis ===================\n"); + printf(" expected actual\n"); + printf(" latency: %10.3f %10.3f\n", (double)latencyFrames, analysisResult.latency ); + printf(" num added frames: %10.3f %10.3f\n", (double)framesAdded, analysisResult.numAddedFrames ); + printf(" added frames at: %10.3f %10.3f\n", (double)glitchPosition, analysisResult.addedFramesPosition ); + printf(" num dropped frames: %10.3f %10.3f\n", (double)framesDropped, analysisResult.numDroppedFrames ); + printf(" dropped frames at: %10.3f %10.3f\n", (double)glitchPosition, analysisResult.droppedFramesPosition ); +#endif + + QA_ASSERT_CLOSE( "PaQa_AnalyseRecording latency", latencyFrames, analysisResult.latency, 0.5 ); + QA_ASSERT_CLOSE( "PaQa_AnalyseRecording framesAdded", framesAdded, analysisResult.numAddedFrames, 1.0 ); + QA_ASSERT_CLOSE( "PaQa_AnalyseRecording framesDropped", framesDropped, analysisResult.numDroppedFrames, 1.0 ); +// QA_ASSERT_CLOSE( "PaQa_AnalyseRecording glitchPosition", glitchPosition, analysisResult.glitchPosition, cycleSize ); + + PaQa_TerminateRecording( &recording ); + return 0; + +error: + PaQa_TerminateRecording( &recording); + return 1; +} + +/*==========================================================================================*/ +/** + * Test various dropped sample scenarios. + */ +static int TestDetectPhaseErrors( void ) +{ + int result; + + result = TestDetectSinglePhaseError( 44100, 200, 477, -1, 0 ); + if( result < 0 ) return result; +/* + result = TestDetectSinglePhaseError( 44100, 200, 77, -1, 0 ); + if( result < 0 ) return result; + + result = TestDetectSinglePhaseError( 44100, 200, 83, 3712, 9 ); + if( result < 0 ) return result; + + result = TestDetectSinglePhaseError( 44100, 280, 83, 3712, 27 ); + if( result < 0 ) return result; + + result = TestDetectSinglePhaseError( 44100, 200, 234, 3712, -9 ); + if( result < 0 ) return result; + + result = TestDetectSinglePhaseError( 44100, 200, 2091, 8923, -2 ); + if( result < 0 ) return result; + + result = TestDetectSinglePhaseError( 44100, 120, 1782, 5772, -18 ); + if( result < 0 ) return result; + + // Note that if the frequency is too high then it is hard to detect single dropped frames. + result = TestDetectSinglePhaseError( 44100, 200, 500, 4251, -1 ); + if( result < 0 ) return result; +*/ + return 0; +} + +/*==========================================================================================*/ +/** + * Detect one pop in a recording. + */ +static int TestDetectSinglePop( double sampleRate, int cycleSize, int latencyFrames, int popPosition, int popWidth, double popAmplitude ) +{ + int result = 0; + PaQaRecording recording; + PaQaTestTone testTone; + PaQaAnalysisResult analysisResult = { 0.0 }; + int maxFrames = ((int)sampleRate) * 2; + + testTone.samplesPerFrame = 1; + testTone.sampleRate = sampleRate; + testTone.frequency = sampleRate / cycleSize; + testTone.amplitude = 0.5; + testTone.startDelay = latencyFrames; + + result = PaQa_InitializeRecording( &recording, maxFrames, (int) sampleRate ); + QA_ASSERT_EQUALS( "PaQa_InitializeRecording failed", 0, result ); + + MakeRecordingWithPop( &recording, &testTone, popPosition, popWidth, popAmplitude ); + + PaQa_AnalyseRecording( &recording, &testTone, &analysisResult ); + +#if PRINT_REPORTS + printf("\n=== Pop Analysis ===================\n"); + printf(" expected actual\n"); + printf(" latency: %10.3f %10.3f\n", (double)latencyFrames, analysisResult.latency ); + printf(" popPosition: %10.3f %10.3f\n", (double)popPosition, analysisResult.popPosition ); + printf(" popAmplitude: %10.3f %10.3f\n", popAmplitude, analysisResult.popAmplitude ); + printf(" cycleSize: %6d\n", cycleSize ); + printf(" num added frames: %10.3f\n", analysisResult.numAddedFrames ); + printf(" added frames at: %10.3f\n", analysisResult.addedFramesPosition ); + printf(" num dropped frames: %10.3f\n", analysisResult.numDroppedFrames ); + printf(" dropped frames at: %10.3f\n", analysisResult.droppedFramesPosition ); +#endif + + QA_ASSERT_CLOSE( "PaQa_AnalyseRecording latency", latencyFrames, analysisResult.latency, 0.5 ); + QA_ASSERT_CLOSE( "PaQa_AnalyseRecording popPosition", popPosition, analysisResult.popPosition, 10 ); + if( popWidth > 0 ) + { + QA_ASSERT_CLOSE( "PaQa_AnalyseRecording popAmplitude", popAmplitude, analysisResult.popAmplitude, 0.1 * popAmplitude ); + } + + PaQa_TerminateRecording( &recording ); + return 0; + +error: + PaQa_SaveRecordingToWaveFile( &recording, "bad_recording.wav" ); + PaQa_TerminateRecording( &recording); + return 1; +} + +/*==========================================================================================*/ +/** + * Analyse recording with a DC offset. + */ +static int TestSingleInitialSpike( double sampleRate, int stepPosition, int cycleSize, int latencyFrames, double stepAmplitude ) +{ + int i; + int result = 0; + // Account for highpass filter offset. + int expectedLatency = latencyFrames + 1; + PaQaRecording recording; + + PaQaRecording hipassOutput = { 0 }; + BiquadFilter hipassFilter; + + PaQaTestTone testTone; + PaQaAnalysisResult analysisResult = { 0.0 }; + int maxFrames = ((int)sampleRate) * 2; + + testTone.samplesPerFrame = 1; + testTone.sampleRate = sampleRate; + testTone.frequency = sampleRate / cycleSize; + testTone.amplitude = -0.5; + testTone.startDelay = latencyFrames; + + result = PaQa_InitializeRecording( &recording, maxFrames, (int) sampleRate ); + QA_ASSERT_EQUALS( "PaQa_InitializeRecording failed", 0, result ); + + result = PaQa_InitializeRecording( &hipassOutput, maxFrames, (int) sampleRate ); + QA_ASSERT_EQUALS( "PaQa_InitializeRecording failed", 0, result ); + + MakeCleanRecording( &recording, &testTone ); + + // Apply DC step. + for( i=stepPosition; i +#include +#include "write_wav.h" + + +/* Write long word data to a little endian format byte array. */ +static void WriteLongLE( unsigned char **addrPtr, unsigned long data ) +{ + unsigned char *addr = *addrPtr; + *addr++ = (unsigned char) data; + *addr++ = (unsigned char) (data>>8); + *addr++ = (unsigned char) (data>>16); + *addr++ = (unsigned char) (data>>24); + *addrPtr = addr; +} + +/* Write short word data to a little endian format byte array. */ +static void WriteShortLE( unsigned char **addrPtr, unsigned short data ) +{ + unsigned char *addr = *addrPtr; + *addr++ = (unsigned char) data; + *addr++ = (unsigned char) (data>>8); + *addrPtr = addr; +} + +/* Write IFF ChunkType data to a byte array. */ +static void WriteChunkType( unsigned char **addrPtr, unsigned long cktyp ) +{ + unsigned char *addr = *addrPtr; + *addr++ = (unsigned char) (cktyp>>24); + *addr++ = (unsigned char) (cktyp>>16); + *addr++ = (unsigned char) (cktyp>>8); + *addr++ = (unsigned char) cktyp; + *addrPtr = addr; +} + +#define WAV_HEADER_SIZE (4 + 4 + 4 + /* RIFF+size+WAVE */ \ + 4 + 4 + 16 + /* fmt chunk */ \ + 4 + 4 ) /* data chunk */ + + +/********************************************************************************* + * Open named file and write WAV header to the file. + * The header includes the DATA chunk type and size. + * Returns number of bytes written to file or negative error code. + */ +long Audio_WAV_OpenWriter( WAV_Writer *writer, const char *fileName, int frameRate, int samplesPerFrame ) +{ + unsigned int bytesPerSecond; + unsigned char header[ WAV_HEADER_SIZE ]; + unsigned char *addr = header; + int numWritten; + + writer->dataSize = 0; + writer->dataSizeOffset = 0; + + writer->fid = fopen( fileName, "wb" ); + if( writer->fid == NULL ) + { + return -1; + } + +/* Write RIFF header. */ + WriteChunkType( &addr, RIFF_ID ); + +/* Write RIFF size as zero for now. Will patch later. */ + WriteLongLE( &addr, 0 ); + +/* Write WAVE form ID. */ + WriteChunkType( &addr, WAVE_ID ); + +/* Write format chunk based on AudioSample structure. */ + WriteChunkType( &addr, FMT_ID ); + WriteLongLE( &addr, 16 ); + WriteShortLE( &addr, WAVE_FORMAT_PCM ); + bytesPerSecond = frameRate * samplesPerFrame * sizeof( short); + WriteShortLE( &addr, (short) samplesPerFrame ); + WriteLongLE( &addr, frameRate ); + WriteLongLE( &addr, bytesPerSecond ); + WriteShortLE( &addr, (short) (samplesPerFrame * sizeof( short)) ); /* bytesPerBlock */ + WriteShortLE( &addr, (short) 16 ); /* bits per sample */ + +/* Write ID and size for 'data' chunk. */ + WriteChunkType( &addr, DATA_ID ); +/* Save offset so we can patch it later. */ + writer->dataSizeOffset = (int) (addr - header); + WriteLongLE( &addr, 0 ); + + numWritten = fwrite( header, 1, sizeof(header), writer->fid ); + if( numWritten != sizeof(header) ) return -1; + + return (int) numWritten; +} + +/********************************************************************************* + * Write to the data chunk portion of a WAV file. + * Returns bytes written or negative error code. + */ +long Audio_WAV_WriteShorts( WAV_Writer *writer, + short *samples, + int numSamples + ) +{ + unsigned char buffer[2]; + unsigned char *bufferPtr; + int i; + short *p = samples; + int numWritten; + int bytesWritten; + if( numSamples <= 0 ) + { + return -1; + } + + for( i=0; ifid ); + if( numWritten != sizeof(buffer) ) return -1; + } + bytesWritten = numSamples * sizeof(short); + writer->dataSize += bytesWritten; + return (int) bytesWritten; +} + +/********************************************************************************* + * Close WAV file. + * Update chunk sizes so it can be read by audio applications. + */ +long Audio_WAV_CloseWriter( WAV_Writer *writer ) +{ + unsigned char buffer[4]; + unsigned char *bufferPtr; + int numWritten; + int riffSize; + + /* Go back to beginning of file and update DATA size */ + int result = fseek( writer->fid, writer->dataSizeOffset, SEEK_SET ); + if( result < 0 ) return result; + + bufferPtr = buffer; + WriteLongLE( &bufferPtr, writer->dataSize ); + numWritten = fwrite( buffer, 1, sizeof( buffer), writer->fid ); + if( numWritten != sizeof(buffer) ) return -1; + + /* Update RIFF size */ + result = fseek( writer->fid, 4, SEEK_SET ); + if( result < 0 ) return result; + + riffSize = writer->dataSize + (WAV_HEADER_SIZE - 8); + bufferPtr = buffer; + WriteLongLE( &bufferPtr, riffSize ); + numWritten = fwrite( buffer, 1, sizeof( buffer), writer->fid ); + if( numWritten != sizeof(buffer) ) return -1; + + fclose( writer->fid ); + writer->fid = NULL; + return writer->dataSize; +} + +/********************************************************************************* + * Simple test that write a sawtooth waveform to a file. + */ +#if 0 +int main( void ) +{ + int i; + WAV_Writer writer; + int result; +#define NUM_SAMPLES (200) + short data[NUM_SAMPLES]; + short saw = 0; + + for( i=0; i +#include +#include "portaudio.h" +#include "pa_trace.h" + +/****************************************** Definitions ***********/ +#define MODE_INPUT (0) +#define MODE_OUTPUT (1) +#define MAX_TEST_CHANNELS 4 + +typedef struct PaQaData +{ + unsigned long framesLeft; + int numChannels; + int bytesPerSample; + int mode; + short sawPhase; + PaSampleFormat format; +} +PaQaData; + +/****************************************** Prototypes ***********/ +static void TestDevices( int mode ); +static void TestFormats( int mode, PaDeviceIndex deviceID, double sampleRate, + int numChannels ); +static int TestAdvance( int mode, PaDeviceIndex deviceID, double sampleRate, + int numChannels, PaSampleFormat format ); +static int QaCallback( const void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + const PaStreamCallbackTimeInfo* timeInfo, + PaStreamCallbackFlags statusFlags, + void *userData ); + +/****************************************** Globals ***********/ +static int gNumPassed = 0; +static int gNumFailed = 0; + +/****************************************** Macros ***********/ +/* Print ERROR if it fails. Tally success or failure. */ +/* Odd do-while wrapper seems to be needed for some compilers. */ +#define EXPECT(_exp) \ + do \ + { \ + if ((_exp)) {\ + /* printf("SUCCESS for %s\n", #_exp ); */ \ + gNumPassed++; \ + } \ + else { \ + printf("ERROR - 0x%x - %s for %s\n", result, \ + ((result == 0) ? "-" : Pa_GetErrorText(result)), \ + #_exp ); \ + gNumFailed++; \ + goto error; \ + } \ + } while(0) + +/*******************************************************************/ +/* This routine will be called by the PortAudio engine when audio is needed. +** It may be called at interrupt level on some machines so don't do anything +** that could mess up the system like calling malloc() or free(). +*/ +static int QaCallback( const void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + const PaStreamCallbackTimeInfo* timeInfo, + PaStreamCallbackFlags statusFlags, + void *userData ) +{ + unsigned long i; + short phase; + PaQaData *data = (PaQaData *) userData; + (void) inputBuffer; + + /* Play simple sawtooth wave. */ + if( data->mode == MODE_OUTPUT ) + { + phase = data->sawPhase; + switch( data->format ) + { + case paFloat32: + { + float *out = (float *) outputBuffer; + for( i=0; inumChannels == 2 ) + { + *out++ = (float) (phase * (1.0 / 32768.0)); + } + } + } + break; + + case paInt32: + { + int *out = (int *) outputBuffer; + for( i=0; inumChannels == 2 ) + { + *out++ = ((int) phase ) << 16; + } + } + } + break; + + case paInt16: + { + short *out = (short *) outputBuffer; + for( i=0; inumChannels == 2 ) + { + *out++ = phase; + } + } + } + break; + + default: + { + unsigned char *out = (unsigned char *) outputBuffer; + unsigned long numBytes = framesPerBuffer * data->numChannels * data->bytesPerSample; + for( i=0; isawPhase = phase; + } + /* Are we through yet? */ + if( data->framesLeft > framesPerBuffer ) + { + PaUtil_AddTraceMessage("QaCallback: running. framesLeft", data->framesLeft ); + data->framesLeft -= framesPerBuffer; + return 0; + } + else + { + PaUtil_AddTraceMessage("QaCallback: DONE! framesLeft", data->framesLeft ); + data->framesLeft = 0; + return 1; + } +} + +/*******************************************************************/ +int main(void); +int main(void) +{ + PaError result; + EXPECT( ((result=Pa_Initialize()) == 0) ); + printf("Test OUTPUT ---------------\n"); + TestDevices( MODE_OUTPUT ); + printf("Test INPUT ---------------\n"); + TestDevices( MODE_INPUT ); +error: + Pa_Terminate(); + printf("QA Report: %d passed, %d failed.\n", gNumPassed, gNumFailed ); + return (gNumFailed > 0) ? 1 : 0; +} + +/******************************************************************* +* Try each output device, through its full range of capabilities. */ +static void TestDevices( int mode ) +{ + int id, jc, i; + int maxChannels; + const PaDeviceInfo *pdi; + static double standardSampleRates[] = { 8000.0, 9600.0, 11025.0, 12000.0, + 16000.0, 22050.0, 24000.0, + 32000.0, 44100.0, 48000.0, + 88200.0, 96000.0, + -1.0 }; /* Negative terminated list. */ + int numDevices = Pa_GetDeviceCount(); + for( id=0; idmaxInputChannels : pdi->maxOutputChannels); + if( maxChannels > MAX_TEST_CHANNELS ) + maxChannels = MAX_TEST_CHANNELS; + + for( jc=1; jc<=maxChannels; jc++ ) + { + printf("\n========================================================================\n"); + printf(" Device = %s\n", pdi->name ); + printf("========================================================================\n"); + /* Try each standard sample rate. */ + for( i=0; standardSampleRates[i] > 0; i++ ) + { + TestFormats( mode, (PaDeviceIndex)id, standardSampleRates[i], jc ); + } + } + } +} + +/*******************************************************************/ +static void TestFormats( int mode, PaDeviceIndex deviceID, double sampleRate, + int numChannels ) +{ + TestAdvance( mode, deviceID, sampleRate, numChannels, paFloat32 ); + TestAdvance( mode, deviceID, sampleRate, numChannels, paInt16 ); + TestAdvance( mode, deviceID, sampleRate, numChannels, paInt32 ); + /* TestAdvance( mode, deviceID, sampleRate, numChannels, paInt24 ); */ +} + +/*******************************************************************/ +static int TestAdvance( int mode, PaDeviceIndex deviceID, double sampleRate, + int numChannels, PaSampleFormat format ) +{ + PaStreamParameters inputParameters, outputParameters, *ipp, *opp; + PaStream *stream = NULL; + PaError result = paNoError; + PaQaData myData; + #define FRAMES_PER_BUFFER (64) + const int kNumSeconds = 100; + + /* Setup data for synthesis thread. */ + myData.framesLeft = (unsigned long) (sampleRate * kNumSeconds); + myData.numChannels = numChannels; + myData.mode = mode; + myData.format = format; + switch( format ) + { + case paFloat32: + case paInt32: + case paInt24: + myData.bytesPerSample = 4; + break; +/* case paPackedInt24: + myData.bytesPerSample = 3; + break; */ + default: + myData.bytesPerSample = 2; + break; + } + + if( mode == MODE_INPUT ) + { + inputParameters.device = deviceID; + inputParameters.channelCount = numChannels; + inputParameters.sampleFormat = format; + inputParameters.suggestedLatency = Pa_GetDeviceInfo( inputParameters.device )->defaultLowInputLatency; + inputParameters.hostApiSpecificStreamInfo = NULL; + ipp = &inputParameters; + } + else + { + ipp = NULL; + } + + if( mode == MODE_OUTPUT ) + { + outputParameters.device = deviceID; + outputParameters.channelCount = numChannels; + outputParameters.sampleFormat = format; + outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultLowOutputLatency; + outputParameters.hostApiSpecificStreamInfo = NULL; + opp = &outputParameters; + } + else + { + opp = NULL; + } + + if(paFormatIsSupported == Pa_IsFormatSupported( ipp, opp, sampleRate )) + { + printf("------ TestAdvance: %s, device = %d, rate = %g, numChannels = %d, format = %lu -------\n", + ( mode == MODE_INPUT ) ? "INPUT" : "OUTPUT", + deviceID, sampleRate, numChannels, (unsigned long)format); + EXPECT( ((result = Pa_OpenStream( &stream, + ipp, + opp, + sampleRate, + FRAMES_PER_BUFFER, + paClipOff, /* we won't output out of range samples so don't bother clipping them */ + QaCallback, + &myData ) ) == 0) ); + if( stream ) + { + PaTime oldStamp, newStamp; + unsigned long oldFrames; + int minDelay = ( mode == MODE_INPUT ) ? 1000 : 400; + /* Was: + int minNumBuffers = Pa_GetMinNumBuffers( FRAMES_PER_BUFFER, sampleRate ); + int msec = (int) ((minNumBuffers * 3 * 1000.0 * FRAMES_PER_BUFFER) / sampleRate); + */ + int msec = (int)( 3.0 * + (( mode == MODE_INPUT ) ? inputParameters.suggestedLatency : outputParameters.suggestedLatency )); + if( msec < minDelay ) msec = minDelay; + printf("msec = %d\n", msec); /**/ + EXPECT( ((result=Pa_StartStream( stream )) == 0) ); + /* Check to make sure PortAudio is advancing timeStamp. */ + oldStamp = Pa_GetStreamTime(stream); + Pa_Sleep(msec); + newStamp = Pa_GetStreamTime(stream); + printf("oldStamp = %9.6f, newStamp = %9.6f\n", oldStamp, newStamp ); /**/ + EXPECT( (oldStamp < newStamp) ); + /* Check to make sure callback is decrementing framesLeft. */ + oldFrames = myData.framesLeft; + Pa_Sleep(msec); + printf("oldFrames = %lu, myData.framesLeft = %lu\n", oldFrames, myData.framesLeft ); /**/ + EXPECT( (oldFrames > myData.framesLeft) ); + EXPECT( ((result=Pa_CloseStream( stream )) == 0) ); + stream = NULL; + } + } + return 0; +error: + if( stream != NULL ) Pa_CloseStream( stream ); + return -1; +} diff --git a/extern/portaudio/qa/paqa_errs.c b/extern/portaudio/qa/paqa_errs.c new file mode 100644 index 0000000..8c1d06d --- /dev/null +++ b/extern/portaudio/qa/paqa_errs.c @@ -0,0 +1,403 @@ +/** @file paqa_errs.c + @ingroup qa_src + @brief Self Testing Quality Assurance app for PortAudio + Do lots of bad things to test error reporting. + @author Phil Burk http://www.softsynth.com + Pieter Suurmond adapted to V19 API. +*/ +/* + * $Id$ + * + * This program uses the PortAudio Portable Audio Library. + * For more information see: http://www.portaudio.com + * Copyright (c) 1999-2000 Ross Bencina and Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +#include +#include + +#include "portaudio.h" + +/*--------- Definitions ---------*/ +#define MODE_INPUT (0) +#define MODE_OUTPUT (1) +#define FRAMES_PER_BUFFER (64) +#define SAMPLE_RATE (44100.0) + +typedef struct PaQaData +{ + unsigned long framesLeft; + int numChannels; + int bytesPerSample; + int mode; +} +PaQaData; + +static int gNumPassed = 0; /* Two globals */ +static int gNumFailed = 0; + +/*------------------- Macros ------------------------------*/ +/* Print ERROR if it fails. Tally success or failure. Odd */ +/* do-while wrapper seems to be needed for some compilers. */ + +#define EXPECT(_exp) \ + do \ + { \ + if ((_exp)) {\ + gNumPassed++; \ + } \ + else { \ + printf("\nERROR - 0x%x - %s for %s\n", result, Pa_GetErrorText(result), #_exp ); \ + gNumFailed++; \ + goto error; \ + } \ + } while(0) + +#define HOPEFOR(_exp) \ + do \ + { \ + if ((_exp)) {\ + gNumPassed++; \ + } \ + else { \ + printf("\nERROR - 0x%x - %s for %s\n", result, Pa_GetErrorText(result), #_exp ); \ + gNumFailed++; \ + } \ + } while(0) + +/*-------------------------------------------------------------------------*/ +/* This routine will be called by the PortAudio engine when audio is needed. + It may be called at interrupt level on some machines so don't do anything + that could mess up the system like calling malloc() or free(). +*/ +static int QaCallback( const void* inputBuffer, + void* outputBuffer, + unsigned long framesPerBuffer, + const PaStreamCallbackTimeInfo* timeInfo, + PaStreamCallbackFlags statusFlags, + void* userData ) +{ + unsigned long i; + unsigned char* out = (unsigned char *) outputBuffer; + PaQaData* data = (PaQaData *) userData; + + (void)inputBuffer; /* Prevent "unused variable" warnings. */ + + /* Zero out buffer so we don't hear terrible noise. */ + if( data->mode == MODE_OUTPUT ) + { + unsigned long numBytes = framesPerBuffer * data->numChannels * data->bytesPerSample; + for( i=0; iframesLeft > framesPerBuffer ) + { + data->framesLeft -= framesPerBuffer; + return 0; + } + else + { + data->framesLeft = 0; + return 1; + } +} + +static PaDeviceIndex FindInputOnlyDevice(void) +{ + PaDeviceIndex result = Pa_GetDefaultInputDevice(); + if( result != paNoDevice && Pa_GetDeviceInfo(result)->maxOutputChannels == 0 ) + return result; + + for( result = 0; result < Pa_GetDeviceCount(); ++result ) + { + if( Pa_GetDeviceInfo(result)->maxOutputChannels == 0 ) + return result; + } + + return paNoDevice; +} + +static PaDeviceIndex FindOutputOnlyDevice(void) +{ + PaDeviceIndex result = Pa_GetDefaultOutputDevice(); + if( result != paNoDevice && Pa_GetDeviceInfo(result)->maxInputChannels == 0 ) + return result; + + for( result = 0; result < Pa_GetDeviceCount(); ++result ) + { + if( Pa_GetDeviceInfo(result)->maxInputChannels == 0 ) + return result; + } + + return paNoDevice; +} + +/*-------------------------------------------------------------------------------------------------*/ +static int TestBadOpens( void ) +{ + PaStream* stream = NULL; + PaError result; + PaQaData myData; + PaStreamParameters ipp, opp; + const PaDeviceInfo* info = NULL; + + + /* Setup data for synthesis thread. */ + myData.framesLeft = (unsigned long) (SAMPLE_RATE * 100); /* 100 seconds */ + myData.numChannels = 1; + myData.mode = MODE_OUTPUT; + + /*----------------------------- No devices specified: */ + ipp.device = opp.device = paNoDevice; + ipp.channelCount = opp.channelCount = 0; /* Also no channels. */ + ipp.hostApiSpecificStreamInfo = opp.hostApiSpecificStreamInfo = NULL; + ipp.sampleFormat = opp.sampleFormat = paFloat32; + /* Take the low latency of the default device for all subsequent tests. */ + info = Pa_GetDeviceInfo(Pa_GetDefaultInputDevice()); + ipp.suggestedLatency = info ? info->defaultLowInputLatency : 0.100; + info = Pa_GetDeviceInfo(Pa_GetDefaultOutputDevice()); + opp.suggestedLatency = info ? info->defaultLowOutputLatency : 0.100; + HOPEFOR(((result = Pa_OpenStream(&stream, &ipp, &opp, + SAMPLE_RATE, FRAMES_PER_BUFFER, + paClipOff, QaCallback, &myData )) == paInvalidDevice)); + + /*----------------------------- No devices specified #2: */ + HOPEFOR(((result = Pa_OpenStream(&stream, NULL, NULL, + SAMPLE_RATE, FRAMES_PER_BUFFER, + paClipOff, QaCallback, &myData )) == paInvalidDevice)); + + /*----------------------------- Out of range input device specified: */ + ipp.hostApiSpecificStreamInfo = opp.hostApiSpecificStreamInfo = NULL; + ipp.sampleFormat = opp.sampleFormat = paFloat32; + ipp.channelCount = 0; ipp.device = Pa_GetDeviceCount(); /* And no output device, and no channels. */ + opp.channelCount = 0; opp.device = paNoDevice; + HOPEFOR(((result = Pa_OpenStream(&stream, &ipp, NULL, + SAMPLE_RATE, FRAMES_PER_BUFFER, + paClipOff, QaCallback, &myData )) == paInvalidDevice)); + + /*----------------------------- Out of range output device specified: */ + ipp.hostApiSpecificStreamInfo = opp.hostApiSpecificStreamInfo = NULL; + ipp.sampleFormat = opp.sampleFormat = paFloat32; + ipp.channelCount = 0; ipp.device = paNoDevice; /* And no input device, and no channels. */ + opp.channelCount = 0; opp.device = Pa_GetDeviceCount(); + HOPEFOR(((result = Pa_OpenStream(&stream, NULL, &opp, + SAMPLE_RATE, FRAMES_PER_BUFFER, + paClipOff, QaCallback, &myData )) == paInvalidDevice)); + + if (Pa_GetDefaultInputDevice() != paNoDevice) { + /*----------------------------- Zero input channels: */ + ipp.hostApiSpecificStreamInfo = opp.hostApiSpecificStreamInfo = NULL; + ipp.sampleFormat = opp.sampleFormat = paFloat32; + ipp.channelCount = 0; ipp.device = Pa_GetDefaultInputDevice(); + opp.channelCount = 0; opp.device = paNoDevice; /* And no output device, and no output channels. */ + HOPEFOR(((result = Pa_OpenStream(&stream, &ipp, NULL, + SAMPLE_RATE, FRAMES_PER_BUFFER, + paClipOff, QaCallback, &myData )) == paInvalidChannelCount)); + } + + if (Pa_GetDefaultOutputDevice() != paNoDevice) { + /*----------------------------- Zero output channels: */ + ipp.hostApiSpecificStreamInfo = opp.hostApiSpecificStreamInfo = NULL; + ipp.sampleFormat = opp.sampleFormat = paFloat32; + ipp.channelCount = 0; ipp.device = paNoDevice; /* And no input device, and no input channels. */ + opp.channelCount = 0; opp.device = Pa_GetDefaultOutputDevice(); + HOPEFOR(((result = Pa_OpenStream(&stream, NULL, &opp, + SAMPLE_RATE, FRAMES_PER_BUFFER, + paClipOff, QaCallback, &myData )) == paInvalidChannelCount)); + } + /*----------------------------- Nonzero input and output channels but no output device: */ + ipp.hostApiSpecificStreamInfo = opp.hostApiSpecificStreamInfo = NULL; + ipp.sampleFormat = opp.sampleFormat = paFloat32; + ipp.channelCount = 2; ipp.device = Pa_GetDefaultInputDevice(); /* Both stereo. */ + opp.channelCount = 2; opp.device = paNoDevice; + HOPEFOR(((result = Pa_OpenStream(&stream, &ipp, &opp, + SAMPLE_RATE, FRAMES_PER_BUFFER, + paClipOff, QaCallback, &myData )) == paInvalidDevice)); + + /*----------------------------- Nonzero input and output channels but no input device: */ + ipp.hostApiSpecificStreamInfo = opp.hostApiSpecificStreamInfo = NULL; + ipp.sampleFormat = opp.sampleFormat = paFloat32; + ipp.channelCount = 2; ipp.device = paNoDevice; + opp.channelCount = 2; opp.device = Pa_GetDefaultOutputDevice(); + HOPEFOR(((result = Pa_OpenStream(&stream, &ipp, &opp, + SAMPLE_RATE, FRAMES_PER_BUFFER, + paClipOff, QaCallback, &myData )) == paInvalidDevice)); + + if (Pa_GetDefaultOutputDevice() != paNoDevice) { + /*----------------------------- NULL stream pointer: */ + ipp.hostApiSpecificStreamInfo = opp.hostApiSpecificStreamInfo = NULL; + ipp.sampleFormat = opp.sampleFormat = paFloat32; + ipp.channelCount = 0; ipp.device = paNoDevice; /* Output is more likely than input. */ + opp.channelCount = 2; opp.device = Pa_GetDefaultOutputDevice(); /* Only 2 output channels. */ + HOPEFOR(((result = Pa_OpenStream(NULL, &ipp, &opp, + SAMPLE_RATE, FRAMES_PER_BUFFER, + paClipOff, QaCallback, &myData )) == paBadStreamPtr)); + + /*----------------------------- Low sample rate: */ + ipp.hostApiSpecificStreamInfo = opp.hostApiSpecificStreamInfo = NULL; + ipp.sampleFormat = opp.sampleFormat = paFloat32; + ipp.channelCount = 0; ipp.device = paNoDevice; + opp.channelCount = 2; opp.device = Pa_GetDefaultOutputDevice(); + HOPEFOR(((result = Pa_OpenStream(&stream, NULL, &opp, + 1.0, FRAMES_PER_BUFFER, /* 1 cycle per second (1 Hz) is too low. */ + paClipOff, QaCallback, &myData )) == paInvalidSampleRate)); + + /*----------------------------- High sample rate: */ + ipp.hostApiSpecificStreamInfo = opp.hostApiSpecificStreamInfo = NULL; + ipp.sampleFormat = opp.sampleFormat = paFloat32; + ipp.channelCount = 0; ipp.device = paNoDevice; + opp.channelCount = 2; opp.device = Pa_GetDefaultOutputDevice(); + HOPEFOR(((result = Pa_OpenStream(&stream, NULL, &opp, + 10000000.0, FRAMES_PER_BUFFER, /* 10^6 cycles per second (10 MHz) is too high. */ + paClipOff, QaCallback, &myData )) == paInvalidSampleRate)); + + /*----------------------------- NULL callback: */ + /* NULL callback is valid in V19 -- it means use blocking read/write stream + + ipp.hostApiSpecificStreamInfo = opp.hostApiSpecificStreamInfo = NULL; + ipp.sampleFormat = opp.sampleFormat = paFloat32; + ipp.channelCount = 0; ipp.device = paNoDevice; + opp.channelCount = 2; opp.device = Pa_GetDefaultOutputDevice(); + HOPEFOR(((result = Pa_OpenStream(&stream, NULL, &opp, + SAMPLE_RATE, FRAMES_PER_BUFFER, + paClipOff, + NULL, + &myData )) == paNullCallback)); + */ + + /*----------------------------- Bad flag: */ + ipp.hostApiSpecificStreamInfo = opp.hostApiSpecificStreamInfo = NULL; + ipp.sampleFormat = opp.sampleFormat = paFloat32; + ipp.channelCount = 0; ipp.device = paNoDevice; + opp.channelCount = 2; opp.device = Pa_GetDefaultOutputDevice(); + HOPEFOR(((result = Pa_OpenStream(&stream, NULL, &opp, + SAMPLE_RATE, FRAMES_PER_BUFFER, + 255, /* Is 8 maybe legal V19 API? */ + QaCallback, &myData )) == paInvalidFlag)); + } + + /*----------------------------- using input device as output device: */ + if( FindInputOnlyDevice() != paNoDevice ) + { + ipp.hostApiSpecificStreamInfo = opp.hostApiSpecificStreamInfo = NULL; + ipp.sampleFormat = opp.sampleFormat = paFloat32; + ipp.channelCount = 0; ipp.device = paNoDevice; /* And no input device, and no channels. */ + opp.channelCount = 2; opp.device = FindInputOnlyDevice(); + HOPEFOR(((result = Pa_OpenStream(&stream, NULL, &opp, + SAMPLE_RATE, FRAMES_PER_BUFFER, + paClipOff, QaCallback, &myData )) == paInvalidChannelCount)); + } + + /*----------------------------- using output device as input device: */ + if( FindOutputOnlyDevice() != paNoDevice ) + { + ipp.hostApiSpecificStreamInfo = opp.hostApiSpecificStreamInfo = NULL; + ipp.sampleFormat = opp.sampleFormat = paFloat32; + ipp.channelCount = 2; ipp.device = FindOutputOnlyDevice(); + opp.channelCount = 0; opp.device = paNoDevice; /* And no output device, and no channels. */ + HOPEFOR(((result = Pa_OpenStream(&stream, &ipp, NULL, + SAMPLE_RATE, FRAMES_PER_BUFFER, + paClipOff, QaCallback, &myData )) == paInvalidChannelCount)); + + } + + if( stream != NULL ) Pa_CloseStream( stream ); + return result; +} + +/*-----------------------------------------------------------------------------------------*/ +static int TestBadActions( void ) +{ + PaStream* stream = NULL; + const PaDeviceInfo* deviceInfo = NULL; + PaError result = 0; + PaQaData myData; + PaStreamParameters opp; + const PaDeviceInfo* info = NULL; + + /* Setup data for synthesis thread. */ + myData.framesLeft = (unsigned long)(SAMPLE_RATE * 100); /* 100 seconds */ + myData.numChannels = 1; + myData.mode = MODE_OUTPUT; + + opp.device = Pa_GetDefaultOutputDevice(); /* Default output. */ + opp.channelCount = 2; /* Stereo output. */ + opp.hostApiSpecificStreamInfo = NULL; + opp.sampleFormat = paFloat32; + info = Pa_GetDeviceInfo(opp.device); + opp.suggestedLatency = info ? info->defaultLowOutputLatency : 0.100; + + if (opp.device != paNoDevice) { + HOPEFOR(((result = Pa_OpenStream(&stream, NULL, /* Take NULL as input parame- */ + &opp, /* ters, meaning try only output. */ + SAMPLE_RATE, FRAMES_PER_BUFFER, + paClipOff, QaCallback, &myData )) == paNoError)); + } + + HOPEFOR(((deviceInfo = Pa_GetDeviceInfo(paNoDevice)) == NULL)); + HOPEFOR(((deviceInfo = Pa_GetDeviceInfo(87654)) == NULL)); + HOPEFOR(((result = Pa_StartStream(NULL)) == paBadStreamPtr)); + HOPEFOR(((result = Pa_StopStream(NULL)) == paBadStreamPtr)); + HOPEFOR(((result = Pa_IsStreamStopped(NULL)) == paBadStreamPtr)); + HOPEFOR(((result = Pa_IsStreamActive(NULL)) == paBadStreamPtr)); + HOPEFOR(((result = Pa_CloseStream(NULL)) == paBadStreamPtr)); + HOPEFOR(((result = Pa_SetStreamFinishedCallback(NULL, NULL)) == paBadStreamPtr)); + HOPEFOR(((result = !Pa_GetStreamInfo(NULL)))); + HOPEFOR(((result = Pa_GetStreamTime(NULL)) == 0.0)); + HOPEFOR(((result = Pa_GetStreamCpuLoad(NULL)) == 0.0)); + HOPEFOR(((result = Pa_ReadStream(NULL, NULL, 0)) == paBadStreamPtr)); + HOPEFOR(((result = Pa_WriteStream(NULL, NULL, 0)) == paBadStreamPtr)); + + /** @todo test Pa_GetStreamReadAvailable and Pa_GetStreamWriteAvailable */ + + if (stream != NULL) Pa_CloseStream(stream); + return result; +} + +/*---------------------------------------------------------------------*/ +int main(void); +int main(void) +{ + PaError result; + + EXPECT(((result = Pa_Initialize()) == paNoError)); + TestBadOpens(); + TestBadActions(); +error: + Pa_Terminate(); + printf("QA Report: %d passed, %d failed.\n", gNumPassed, gNumFailed); + return 0; +} diff --git a/extern/portaudio/qa/paqa_latency.c b/extern/portaudio/qa/paqa_latency.c new file mode 100644 index 0000000..389c065 --- /dev/null +++ b/extern/portaudio/qa/paqa_latency.c @@ -0,0 +1,482 @@ +/** @file paqa_latency.c + @ingroup qa_src + @brief Test latency estimates. + @author Ross Bencina + @author Phil Burk +*/ +/* + * $Id: patest_sine.c 1368 2008-03-01 00:38:27Z rossb $ + * + * This program uses the PortAudio Portable Audio Library. + * For more information see: http://www.portaudio.com/ + * Copyright (c) 1999-2000 Ross Bencina and Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ +#include +#include +#include "portaudio.h" +#include "loopback/src/qa_tools.h" + +#define NUM_SECONDS (5) +#define SAMPLE_RATE (44100) +#define FRAMES_PER_BUFFER (64) + +#ifndef M_PI +#define M_PI (3.14159265) +#endif + +#define TABLE_SIZE (200) +typedef struct +{ + float sine[TABLE_SIZE]; + int left_phase; + int right_phase; + char message[20]; + int minFramesPerBuffer; + int maxFramesPerBuffer; + int callbackCount; + PaTime minDeltaDacTime; + PaTime maxDeltaDacTime; + PaStreamCallbackTimeInfo previousTimeInfo; +} +paTestData; + +/* Used to tally the results of the QA tests. */ +int g_testsPassed = 0; +int g_testsFailed = 0; + +/* This routine will be called by the PortAudio engine when audio is needed. +** It may called at interrupt level on some machines so don't do anything +** that could mess up the system like calling malloc() or free(). +*/ +static int patestCallback( const void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + const PaStreamCallbackTimeInfo* timeInfo, + PaStreamCallbackFlags statusFlags, + void *userData ) +{ + paTestData *data = (paTestData*)userData; + float *out = (float*)outputBuffer; + unsigned long i; + + (void) timeInfo; /* Prevent unused variable warnings. */ + (void) statusFlags; + (void) inputBuffer; + + if( data->minFramesPerBuffer > framesPerBuffer ) + { + data->minFramesPerBuffer = framesPerBuffer; + } + if( data->maxFramesPerBuffer < framesPerBuffer ) + { + data->maxFramesPerBuffer = framesPerBuffer; + } + + /* Measure min and max output time stamp delta. */ + if( data->callbackCount > 0 ) + { + PaTime delta = timeInfo->outputBufferDacTime - data->previousTimeInfo.outputBufferDacTime; + if( data->minDeltaDacTime > delta ) + { + data->minDeltaDacTime = delta; + } + if( data->maxDeltaDacTime < delta ) + { + data->maxDeltaDacTime = delta; + } + } + data->previousTimeInfo = *timeInfo; + + for( i=0; isine[data->left_phase]; /* left */ + *out++ = data->sine[data->right_phase]; /* right */ + data->left_phase += 1; + if( data->left_phase >= TABLE_SIZE ) data->left_phase -= TABLE_SIZE; + data->right_phase += 3; /* higher pitch so we can distinguish left and right. */ + if( data->right_phase >= TABLE_SIZE ) data->right_phase -= TABLE_SIZE; + } + + data->callbackCount += 1; + return paContinue; +} + +PaError paqaCheckLatency( PaStreamParameters *outputParamsPtr, + paTestData *dataPtr, double sampleRate, unsigned long framesPerBuffer ) +{ + PaError err; + PaStream *stream; + const PaStreamInfo* streamInfo; + + dataPtr->minFramesPerBuffer = 9999999; + dataPtr->maxFramesPerBuffer = 0; + dataPtr->minDeltaDacTime = 9999999.0; + dataPtr->maxDeltaDacTime = 0.0; + dataPtr->callbackCount = 0; + + printf("Stream parameter: suggestedOutputLatency = %g\n", outputParamsPtr->suggestedLatency ); + if( framesPerBuffer == paFramesPerBufferUnspecified ){ + printf("Stream parameter: user framesPerBuffer = paFramesPerBufferUnspecified\n" ); + }else{ + printf("Stream parameter: user framesPerBuffer = %lu\n", framesPerBuffer ); + } + err = Pa_OpenStream( + &stream, + NULL, /* no input */ + outputParamsPtr, + sampleRate, + framesPerBuffer, + paClipOff, /* we won't output out of range samples so don't bother clipping them */ + patestCallback, + dataPtr ); + if( err != paNoError ) goto error1; + + streamInfo = Pa_GetStreamInfo( stream ); + printf("Stream info: inputLatency = %g\n", streamInfo->inputLatency ); + printf("Stream info: outputLatency = %g\n", streamInfo->outputLatency ); + + err = Pa_StartStream( stream ); + if( err != paNoError ) goto error2; + + printf("Play for %d seconds.\n", NUM_SECONDS ); + Pa_Sleep( NUM_SECONDS * 1000 ); + + printf(" minFramesPerBuffer = %4d\n", dataPtr->minFramesPerBuffer ); + printf(" maxFramesPerBuffer = %4d\n", dataPtr->maxFramesPerBuffer ); + printf(" minDeltaDacTime = %f\n", dataPtr->minDeltaDacTime ); + printf(" maxDeltaDacTime = %f\n", dataPtr->maxDeltaDacTime ); + + err = Pa_StopStream( stream ); + if( err != paNoError ) goto error2; + + err = Pa_CloseStream( stream ); + Pa_Sleep( 1 * 1000 ); + + + printf("-------------------------------------\n"); + return err; +error2: + Pa_CloseStream( stream ); +error1: + printf("-------------------------------------\n"); + return err; +} + + +/*******************************************************************/ +static int paqaNoopCallback( const void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + const PaStreamCallbackTimeInfo* timeInfo, + PaStreamCallbackFlags statusFlags, + void *userData ) +{ + (void)inputBuffer; + (void)outputBuffer; + (void)framesPerBuffer; + (void)timeInfo; + (void)statusFlags; + (void)userData; + return paContinue; +} + +/*******************************************************************/ +static int paqaCheckMultipleSuggested( PaDeviceIndex deviceIndex, int isInput ) +{ + int i; + int numLoops = 10; + PaError err; + PaStream *stream; + PaStreamParameters streamParameters; + const PaStreamInfo* streamInfo; + double lowLatency; + double highLatency; + double finalLatency; + double sampleRate = SAMPLE_RATE; + const PaDeviceInfo *pdi = Pa_GetDeviceInfo( deviceIndex ); + double previousLatency = 0.0; + int numChannels = 1; + float toleranceRatio = 1.0; + + printf("------------------------ paqaCheckMultipleSuggested - %s\n", + (isInput ? "INPUT" : "OUTPUT") ); + if( isInput ) + { + lowLatency = pdi->defaultLowInputLatency; + highLatency = pdi->defaultHighInputLatency; + numChannels = (pdi->maxInputChannels < 2) ? 1 : 2; + } + else + { + lowLatency = pdi->defaultLowOutputLatency; + highLatency = pdi->defaultHighOutputLatency; + numChannels = (pdi->maxOutputChannels < 2) ? 1 : 2; + } + streamParameters.channelCount = numChannels; + streamParameters.device = deviceIndex; + streamParameters.hostApiSpecificStreamInfo = NULL; + streamParameters.sampleFormat = paFloat32; + sampleRate = pdi->defaultSampleRate; + + printf(" lowLatency = %g\n", lowLatency ); + printf(" highLatency = %g\n", highLatency ); + printf(" numChannels = %d\n", numChannels ); + printf(" sampleRate = %g\n", sampleRate ); + + if( (highLatency - lowLatency) < 0.001 ) + { + numLoops = 1; + } + + for( i=0; iinputLatency; + } + else + { + finalLatency = streamInfo->outputLatency; + } + printf(" finalLatency = %6.4f\n", finalLatency ); + /* For the default low & high latency values, expect quite close; for other requested + * values, at worst the next power-of-2 may result (eg 513 -> 1024) */ + toleranceRatio = ( (i == 0) || (i == ( numLoops - 1 )) ) ? 0.1 : 1.0; + QA_ASSERT_CLOSE( "final latency should be close to suggested latency", + streamParameters.suggestedLatency, finalLatency, (streamParameters.suggestedLatency * toleranceRatio) ); + if( i == 0 ) + { + previousLatency = finalLatency; + } + } + + if( numLoops > 1 ) + { + QA_ASSERT_TRUE( " final latency should increase with suggested latency", (finalLatency > previousLatency) ); + } + + return 0; +error: + return -1; +} + +/*******************************************************************/ +static int paqaVerifySuggestedLatency( void ) +{ + PaDeviceIndex id; + int result = 0; + const PaDeviceInfo *pdi; + int numDevices = Pa_GetDeviceCount(); + + printf("\n ------------------------ paqaVerifySuggestedLatency\n"); + for( id=0; idname, Pa_GetHostApiInfo(pdi->hostApi)->name); + if( pdi->maxOutputChannels > 0 ) + { + if( paqaCheckMultipleSuggested( id, 0 ) < 0 ) + { + printf("OUTPUT CHECK FAILED !!! #%d: '%s'\n", id, pdi->name); + result -= 1; + } + } + if( pdi->maxInputChannels > 0 ) + { + if( paqaCheckMultipleSuggested( id, 1 ) < 0 ) + { + printf("INPUT CHECK FAILED !!! #%d: '%s'\n", id, pdi->name); + result -= 1; + } + } + } + return result; +} + +/*******************************************************************/ +static int paqaVerifyDeviceInfoLatency( void ) +{ + PaDeviceIndex id; + const PaDeviceInfo *pdi; + int numDevices = Pa_GetDeviceCount(); + + printf("\n ------------------------ paqaVerifyDeviceInfoLatency\n"); + for( id=0; idname, Pa_GetHostApiInfo(pdi->hostApi)->name); + if( pdi->maxOutputChannels > 0 ) + { + printf(" Output defaultLowOutputLatency = %f seconds\n", pdi->defaultLowOutputLatency); + printf(" Output defaultHighOutputLatency = %f seconds\n", pdi->defaultHighOutputLatency); + QA_ASSERT_TRUE( "defaultLowOutputLatency should be > 0", (pdi->defaultLowOutputLatency > 0.0) ); + QA_ASSERT_TRUE( "defaultHighOutputLatency should be > 0", (pdi->defaultHighOutputLatency > 0.0) ); + QA_ASSERT_TRUE( "defaultHighOutputLatency should be >= Low", (pdi->defaultHighOutputLatency >= pdi->defaultLowOutputLatency) ); + } + if( pdi->maxInputChannels > 0 ) + { + printf(" Input defaultLowInputLatency = %f seconds\n", pdi->defaultLowInputLatency); + printf(" Input defaultHighInputLatency = %f seconds\n", pdi->defaultHighInputLatency); + QA_ASSERT_TRUE( "defaultLowInputLatency should be > 0", (pdi->defaultLowInputLatency > 0.0) ); + QA_ASSERT_TRUE( "defaultHighInputLatency should be > 0", (pdi->defaultHighInputLatency > 0.0) ); + QA_ASSERT_TRUE( "defaultHighInputLatency should be >= Low", (pdi->defaultHighInputLatency >= pdi->defaultLowInputLatency) ); + } + } + return 0; +error: + return -1; +} + + + +/*******************************************************************/ +int main(void); +int main(void) +{ + PaStreamParameters outputParameters; + PaError err; + paTestData data; + const PaDeviceInfo *deviceInfo; + int i; + int framesPerBuffer; + double sampleRate = SAMPLE_RATE; + + printf("\nPortAudio QA: investigate output latency.\n"); + + /* initialise sinusoidal wavetable */ + for( i=0; iname, Pa_GetHostApiInfo(deviceInfo->hostApi)->name); + printf("Device info: defaultLowOutputLatency = %f seconds\n", deviceInfo->defaultLowOutputLatency); + printf("Device info: defaultHighOutputLatency = %f seconds\n", deviceInfo->defaultHighOutputLatency); + sampleRate = deviceInfo->defaultSampleRate; + printf("Sample Rate for following tests: %g\n", sampleRate); + outputParameters.hostApiSpecificStreamInfo = NULL; + printf("-------------------------------------\n"); + + // Try to use a small buffer that is smaller than we think the device can handle. + // Try to force combining multiple user buffers into a host buffer. + printf("------------- Try a very small buffer.\n"); + framesPerBuffer = 9; + outputParameters.suggestedLatency = deviceInfo->defaultLowOutputLatency; + err = paqaCheckLatency( &outputParameters, &data, sampleRate, framesPerBuffer ); + if( err != paNoError ) goto error; + + printf("------------- 64 frame buffer with 1.1 * defaultLow latency.\n"); + framesPerBuffer = 64; + outputParameters.suggestedLatency = deviceInfo->defaultLowOutputLatency * 1.1; + err = paqaCheckLatency( &outputParameters, &data, sampleRate, framesPerBuffer ); + if( err != paNoError ) goto error; + + // Try to create a huge buffer that is bigger than the allowed device maximum. + printf("------------- Try a huge buffer.\n"); + framesPerBuffer = 16*1024; + outputParameters.suggestedLatency = ((double)framesPerBuffer) / sampleRate; // approximate + err = paqaCheckLatency( &outputParameters, &data, sampleRate, framesPerBuffer ); + if( err != paNoError ) goto error; + + printf("------------- Try suggestedLatency = 0.0\n"); + outputParameters.suggestedLatency = 0.0; + err = paqaCheckLatency( &outputParameters, &data, sampleRate, paFramesPerBufferUnspecified ); + if( err != paNoError ) goto error; + + printf("------------- Try suggestedLatency = defaultLowOutputLatency\n"); + outputParameters.suggestedLatency = deviceInfo->defaultLowOutputLatency; + err = paqaCheckLatency( &outputParameters, &data, sampleRate, paFramesPerBufferUnspecified ); + if( err != paNoError ) goto error; + + printf("------------- Try suggestedLatency = defaultHighOutputLatency\n"); + outputParameters.suggestedLatency = deviceInfo->defaultHighOutputLatency; + err = paqaCheckLatency( &outputParameters, &data, sampleRate, paFramesPerBufferUnspecified ); + if( err != paNoError ) goto error; + + printf("------------- Try suggestedLatency = defaultHighOutputLatency * 4\n"); + outputParameters.suggestedLatency = deviceInfo->defaultHighOutputLatency * 4; + err = paqaCheckLatency( &outputParameters, &data, sampleRate, paFramesPerBufferUnspecified ); + if( err != paNoError ) goto error; + + Pa_Terminate(); + printf("SUCCESS - test finished.\n"); + return err; + +error: + Pa_Terminate(); + fprintf( stderr, "ERROR - test failed.\n" ); + fprintf( stderr, "Error number: %d\n", err ); + fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); + return err; +} diff --git a/extern/portaudio/src/SConscript b/extern/portaudio/src/SConscript new file mode 100644 index 0000000..5cc9152 --- /dev/null +++ b/extern/portaudio/src/SConscript @@ -0,0 +1,220 @@ +import os.path, copy, sys + +def checkSymbol(conf, header, library=None, symbol=None, autoAdd=True, critical=False, pkgName=None): + """ Check for symbol in library, optionally look only for header. + @param conf: Configure instance. + @param header: The header file where the symbol is declared. + @param library: The library in which the symbol exists, if None it is taken to be the standard C library. + @param symbol: The symbol to look for, if None only the header will be looked up. + @param autoAdd: Automatically link with this library if check is positive. + @param critical: Raise on error? + @param pkgName: Optional name of pkg-config entry for library, to determine build parameters. + @return: True/False + """ + origEnv = conf.env.Copy() # Copy unmodified environment so we can restore it upon error + env = conf.env + if library is None: + library = "c" # Standard library + autoAdd = False + + if pkgName is not None: + origLibs = copy.copy(env.get("LIBS", None)) + + try: env.ParseConfig("pkg-config --silence-errors %s --cflags --libs" % pkgName) + except: pass + else: + # I see no other way of checking that the parsing succeeded, if it did add no more linking parameters + if env.get("LIBS", None) != origLibs: + autoAdd = False + + try: + if not conf.CheckCHeader(header, include_quotes="<>"): + raise ConfigurationError("missing header %s" % header) + if symbol is not None and not conf.CheckLib(library, symbol, language="C", autoadd=autoAdd): + raise ConfigurationError("missing symbol %s in library %s" % (symbol, library)) + except ConfigurationError: + conf.env = origEnv + if not critical: + return False + raise + + return True + +import SCons.Errors + +# Import common variables + +# Could use '#' to refer to top-level SConstruct directory, but looks like env.SConsignFile doesn't interpret this at least :( +sconsDir = os.path.abspath(os.path.join("build", "scons")) + +try: + Import("Platform", "Posix", "ConfigurationError", "ApiVer") +except SCons.Errors.UserError: + # The common objects must be exported first + SConscript(os.path.join(sconsDir, "SConscript_common")) + Import("Platform", "Posix", "ConfigurationError", "ApiVer") + +Import("env") + +# This will be manipulated +env = env.Copy() + +# We operate with a set of needed libraries and optional libraries, the latter stemming from host API implementations. +# For libraries of both types we record a set of values that is used to look for the library in question, during +# configuration. If the corresponding library for a host API implementation isn't found, the implementation is left out. +neededLibs = [] +optionalImpls = {} +if Platform in Posix: + env.Append(CPPPATH=os.path.join("os", "unix")) + neededLibs += [("pthread", "pthread.h", "pthread_create"), ("m", "math.h", "sin")] + if env["useALSA"]: + optionalImpls["ALSA"] = ("asound", "alsa/asoundlib.h", "snd_pcm_open") + if env["useJACK"]: + optionalImpls["JACK"] = ("jack", "jack/jack.h", "jack_client_new") + if env["useOSS"]: + # TODO: It looks like the prefix for soundcard.h depends on the platform + optionalImpls["OSS"] = ("oss", "sys/soundcard.h", None) + if Platform == 'netbsd': + optionalImpls["OSS"] = ("ossaudio", "sys/soundcard.h", "_oss_ioctl") + if env["useASIHPI"]: + optionalImpls["ASIHPI"] = ("hpi", "asihpi/hpi.h", "HPI_SubSysCreate") + if env["useCOREAUDIO"]: + optionalImpls["COREAUDIO"] = ("CoreAudio", "CoreAudio/CoreAudio.h", None) +else: + raise ConfigurationError("unknown platform %s" % Platform) + +if Platform == "darwin": + env.Append(LINKFLAGS="-framework CoreFoundation -framework CoreServices -framework CoreAudio -framework AudioToolBox -framework AudioUnit") +elif Platform == "cygwin": + env.Append(LIBS=["winmm"]) +elif Platform == "irix": + neededLibs += [("audio", "dmedia/audio.h", "alOpenPort"), ("dmedia", "dmedia/dmedia.h", "dmGetUST")] + env.Append(CPPDEFINES=["PA_USE_SGI"]) + +def CheckCTypeSize(context, tp): + """ Check size of C type. + @param context: A configuration context. + @param tp: The type to check. + @return: Size of type, in bytes. + """ + context.Message("Checking the size of C type %s..." % tp) + ret = context.TryRun(""" +#include + +int main() { + printf("%%d", sizeof(%s)); + return 0; +} +""" % tp, ".c") + if not ret[0]: + context.Result(" Couldn't obtain size of type %s!" % tp) + return None + + assert ret[1] + sz = int(ret[1]) + context.Result("%d" % sz) + return sz + +""" +if sys.byteorder == "little": + env.Append(CPPDEFINES=["PA_LITTLE_ENDIAN"]) +elif sys.byteorder == "big": + env.Append(CPPDEFINES=["PA_BIG_ENDIAN"]) +else: + raise ConfigurationError("unknown byte order: %s" % sys.byteorder) +""" +if env["enableDebugOutput"]: + env.Append(CPPDEFINES=["PA_ENABLE_DEBUG_OUTPUT"]) + +# Start configuration + +# Use an absolute path for conf_dir, otherwise it gets created both relative to current directory and build directory +conf = env.Configure(log_file=os.path.join(sconsDir, "sconf.log"), custom_tests={"CheckCTypeSize": CheckCTypeSize}, + conf_dir=os.path.join(sconsDir, ".sconf_temp")) +conf.env.Append(CPPDEFINES=["SIZEOF_SHORT=%d" % conf.CheckCTypeSize("short")]) +conf.env.Append(CPPDEFINES=["SIZEOF_INT=%d" % conf.CheckCTypeSize("int")]) +conf.env.Append(CPPDEFINES=["SIZEOF_LONG=%d" % conf.CheckCTypeSize("long")]) +if checkSymbol(conf, "time.h", "rt", "clock_gettime"): + conf.env.Append(CPPDEFINES=["HAVE_CLOCK_GETTIME"]) +if checkSymbol(conf, "time.h", symbol="nanosleep"): + conf.env.Append(CPPDEFINES=["HAVE_NANOSLEEP"]) +if conf.CheckCHeader("sys/soundcard.h"): + conf.env.Append(CPPDEFINES=["HAVE_SYS_SOUNDCARD_H"]) +if conf.CheckCHeader("linux/soundcard.h"): + conf.env.Append(CPPDEFINES=["HAVE_LINUX_SOUNDCARD_H"]) +if conf.CheckCHeader("machine/soundcard.h"): + conf.env.Append(CPPDEFINES=["HAVE_MACHINE_SOUNDCARD_H"]) + +# Look for needed libraries and link with them +for lib, hdr, sym in neededLibs: + checkSymbol(conf, hdr, lib, sym, critical=True) +# Look for host API libraries, if a library isn't found disable corresponding host API implementation. +for name, val in optionalImpls.items(): + lib, hdr, sym = val + if checkSymbol(conf, hdr, lib, sym, critical=False, pkgName=name.lower()): + conf.env.Append(CPPDEFINES=["PA_USE_%s=1" % name.upper()]) + else: + del optionalImpls[name] + +# Configuration finished +env = conf.Finish() + +# PA infrastructure +CommonSources = [os.path.join("common", f) for f in "pa_allocation.c pa_converters.c pa_cpuload.c pa_dither.c pa_front.c \ + pa_process.c pa_stream.c pa_trace.c pa_debugprint.c pa_ringbuffer.c".split()] +CommonSources.append(os.path.join("hostapi", "skeleton", "pa_hostapi_skeleton.c")) + +# Host APIs implementations +ImplSources = [] +if Platform in Posix: + ImplSources += [os.path.join("os", "unix", f) for f in "pa_unix_hostapis.c pa_unix_util.c".split()] + +if "ALSA" in optionalImpls: + ImplSources.append(os.path.join("hostapi", "alsa", "pa_linux_alsa.c")) +if "JACK" in optionalImpls: + ImplSources.append(os.path.join("hostapi", "jack", "pa_jack.c")) +if "OSS" in optionalImpls: + ImplSources.append(os.path.join("hostapi", "oss", "pa_unix_oss.c")) +if "ASIHPI" in optionalImpls: + ImplSources.append(os.path.join("hostapi", "asihpi", "pa_linux_asihpi.c")) +if "COREAUDIO" in optionalImpls: + ImplSources.append([os.path.join("hostapi", "coreaudio", f) for f in """ + pa_mac_core.c pa_mac_core_blocking.c pa_mac_core_utilities.c + """.split()]) + + +sources = CommonSources + ImplSources + +sharedLibEnv = env.Copy() +if Platform in Posix: + # Add soname to library, this is so a reference is made to the versioned library in programs linking against libportaudio.so + if Platform != 'darwin': + sharedLibEnv.AppendUnique(SHLINKFLAGS="-Wl,-soname=libportaudio.so.%d" % int(ApiVer.split(".")[0])) +sharedLib = sharedLibEnv.SharedLibrary(target="portaudio", source=sources) + +staticLib = env.StaticLibrary(target="portaudio", source=sources) + +if Platform in Posix: + prefix = env["prefix"] + includeDir = os.path.join(prefix, "include") + libDir = os.path.join(prefix, "lib") + +testNames = ["patest_sine", "paqa_devs", "paqa_errs", "patest1", "patest_buffer", "patest_callbackstop", "patest_clip", \ + "patest_dither", "patest_hang", "patest_in_overflow", "patest_latency", "patest_leftright", "patest_longsine", \ + "patest_many", "patest_maxsines", "patest_multi_sine", "patest_out_underflow", "patest_pink", "patest_prime", \ + "patest_read_record", "patest_record", "patest_ringmix", "patest_saw", "patest_sine8", "patest_sine", \ + "patest_sine_time", "patest_start_stop", "patest_stop", "patest_sync", "patest_toomanysines", \ + "patest_underflow", "patest_wire", "patest_write_sine", "pa_devs", "pa_fuzz", "pa_minlat", \ + "patest_sine_channelmaps",] + +# The test directory ("bin") should be in the top-level PA directory +tests = [env.Program(target=os.path.join("#", "bin", name), source=[os.path.join("#", "test", name + ".c"), + staticLib]) for name in testNames] + +# Detect host APIs +hostApis = [] +for cppdef in env["CPPDEFINES"]: + if cppdef.startswith("PA_USE_"): + hostApis.append(cppdef[7:-2]) + +Return("sources", "sharedLib", "staticLib", "tests", "env", "hostApis") diff --git a/extern/portaudio/src/common/pa_allocation.c b/extern/portaudio/src/common/pa_allocation.c new file mode 100644 index 0000000..51fe15a --- /dev/null +++ b/extern/portaudio/src/common/pa_allocation.c @@ -0,0 +1,243 @@ +/* + * $Id$ + * Portable Audio I/O Library allocation group implementation + * memory allocation group for tracking allocation groups + * + * Based on the Open Source API proposed by Ross Bencina + * Copyright (c) 1999-2002 Ross Bencina, Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +/** @file + @ingroup common_src + + @brief Allocation Group implementation. +*/ + + +#include "pa_allocation.h" +#include "pa_util.h" + + +/* + Maintain 3 singly linked lists... + linkBlocks: the buffers used to allocate the links + spareLinks: links available for use in the allocations list + allocations: the buffers currently allocated using PaUtil_ContextAllocateMemory() + + Link block size is doubled every time new links are allocated. +*/ + + +#define PA_INITIAL_LINK_COUNT_ 16 + +struct PaUtilAllocationGroupLink +{ + struct PaUtilAllocationGroupLink *next; + void *buffer; +}; + +/* + Allocate a block of links. The first link will have it's buffer member + pointing to the block, and it's next member set to . The remaining + links will have NULL buffer members, and each link will point to + the next link except the last, which will point to +*/ +static struct PaUtilAllocationGroupLink *AllocateLinks( long count, + struct PaUtilAllocationGroupLink *nextBlock, + struct PaUtilAllocationGroupLink *nextSpare ) +{ + struct PaUtilAllocationGroupLink *result; + int i; + + result = (struct PaUtilAllocationGroupLink *)PaUtil_AllocateMemory( + sizeof(struct PaUtilAllocationGroupLink) * count ); + if( result ) + { + /* the block link */ + result[0].buffer = result; + result[0].next = nextBlock; + + /* the spare links */ + for( i=1; ilinkCount = PA_INITIAL_LINK_COUNT_; + result->linkBlocks = &links[0]; + result->spareLinks = &links[1]; + result->allocations = 0; + } + else + { + PaUtil_FreeMemory( links ); + } + } + + return result; +} + + +void PaUtil_DestroyAllocationGroup( PaUtilAllocationGroup* group ) +{ + struct PaUtilAllocationGroupLink *current = group->linkBlocks; + struct PaUtilAllocationGroupLink *next; + + while( current ) + { + next = current->next; + PaUtil_FreeMemory( current->buffer ); + current = next; + } + + PaUtil_FreeMemory( group ); +} + + +void* PaUtil_GroupAllocateMemory( PaUtilAllocationGroup* group, long size ) +{ + struct PaUtilAllocationGroupLink *links, *link; + void *result = 0; + + /* allocate more links if necessary */ + if( !group->spareLinks ) + { + /* double the link count on each block allocation */ + links = AllocateLinks( group->linkCount, group->linkBlocks, group->spareLinks ); + if( links ) + { + group->linkCount += group->linkCount; + group->linkBlocks = &links[0]; + group->spareLinks = &links[1]; + } + } + + if( group->spareLinks ) + { + result = PaUtil_AllocateMemory( size ); + if( result ) + { + link = group->spareLinks; + group->spareLinks = link->next; + + link->buffer = result; + link->next = group->allocations; + + group->allocations = link; + } + } + + return result; +} + + +void PaUtil_GroupFreeMemory( PaUtilAllocationGroup* group, void *buffer ) +{ + struct PaUtilAllocationGroupLink *current = group->allocations; + struct PaUtilAllocationGroupLink *previous = 0; + + if( buffer == 0 ) + return; + + /* find the right link and remove it */ + while( current ) + { + if( current->buffer == buffer ) + { + if( previous ) + { + previous->next = current->next; + } + else + { + group->allocations = current->next; + } + + current->buffer = 0; + current->next = group->spareLinks; + group->spareLinks = current; + + break; + } + + previous = current; + current = current->next; + } + + PaUtil_FreeMemory( buffer ); /* free the memory whether we found it in the list or not */ +} + + +void PaUtil_FreeAllAllocations( PaUtilAllocationGroup* group ) +{ + struct PaUtilAllocationGroupLink *current = group->allocations; + struct PaUtilAllocationGroupLink *previous = 0; + + /* free all buffers in the allocations list */ + while( current ) + { + PaUtil_FreeMemory( current->buffer ); + current->buffer = 0; + + previous = current; + current = current->next; + } + + /* link the former allocations list onto the front of the spareLinks list */ + if( previous ) + { + previous->next = group->spareLinks; + group->spareLinks = group->allocations; + group->allocations = 0; + } +} + diff --git a/extern/portaudio/src/common/pa_allocation.h b/extern/portaudio/src/common/pa_allocation.h new file mode 100644 index 0000000..bd1f4b0 --- /dev/null +++ b/extern/portaudio/src/common/pa_allocation.h @@ -0,0 +1,104 @@ +#ifndef PA_ALLOCATION_H +#define PA_ALLOCATION_H +/* + * $Id$ + * Portable Audio I/O Library allocation context header + * memory allocation context for tracking allocation groups + * + * Based on the Open Source API proposed by Ross Bencina + * Copyright (c) 1999-2008 Ross Bencina, Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +/** @file + @ingroup common_src + + @brief Allocation Group prototypes. An Allocation Group makes it easy to + allocate multiple blocks of memory and free them all at once. + + An allocation group is useful for keeping track of multiple blocks + of memory which are allocated at the same time (such as during initialization) + and need to be deallocated at the same time. The allocation group maintains + a list of allocated blocks, and can free all allocations at once. This + can be usefull for cleaning up after a partially initialized object fails. + + The allocation group implementation is built on top of the lower + level allocation functions defined in pa_util.h +*/ + + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + +typedef struct +{ + long linkCount; + struct PaUtilAllocationGroupLink *linkBlocks; + struct PaUtilAllocationGroupLink *spareLinks; + struct PaUtilAllocationGroupLink *allocations; +}PaUtilAllocationGroup; + + + +/** Create an allocation group. +*/ +PaUtilAllocationGroup* PaUtil_CreateAllocationGroup( void ); + +/** Destroy an allocation group, but not the memory allocated through the group. +*/ +void PaUtil_DestroyAllocationGroup( PaUtilAllocationGroup* group ); + +/** Allocate a block of memory though an allocation group. +*/ +void* PaUtil_GroupAllocateMemory( PaUtilAllocationGroup* group, long size ); + +/** Free a block of memory that was previously allocated though an allocation + group. Calling this function is a relatively time consuming operation. + Under normal circumstances clients should call PaUtil_FreeAllAllocations to + free all allocated blocks simultaneously. + @see PaUtil_FreeAllAllocations +*/ +void PaUtil_GroupFreeMemory( PaUtilAllocationGroup* group, void *buffer ); + +/** Free all blocks of memory which have been allocated through the allocation + group. This function doesn't destroy the group itself. +*/ +void PaUtil_FreeAllAllocations( PaUtilAllocationGroup* group ); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* PA_ALLOCATION_H */ diff --git a/extern/portaudio/src/common/pa_converters.c b/extern/portaudio/src/common/pa_converters.c new file mode 100644 index 0000000..2107f5e --- /dev/null +++ b/extern/portaudio/src/common/pa_converters.c @@ -0,0 +1,1983 @@ +/* + * $Id$ + * Portable Audio I/O Library sample conversion mechanism + * + * Based on the Open Source API proposed by Ross Bencina + * Copyright (c) 1999-2002 Phil Burk, Ross Bencina + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +/** @file + @ingroup common_src + + @brief Conversion function implementations. + + If the C9x function lrintf() is available, define PA_USE_C99_LRINTF to use it + + @todo Consider whether functions which dither but don't clip should exist, + V18 automatically enabled clipping whenever dithering was selected. Perhaps + we should do the same. + see: "require clipping for dithering sample conversion functions?" + http://www.portaudio.com/trac/ticket/112 + + @todo implement the converters marked IMPLEMENT ME: Int32_To_Int24_Dither, + Int32_To_UInt8_Dither, Int24_To_Int16_Dither, Int24_To_Int8_Dither, + Int24_To_UInt8_Dither, Int16_To_Int8_Dither, Int16_To_UInt8_Dither + see: "some conversion functions are not implemented in pa_converters.c" + http://www.portaudio.com/trac/ticket/35 + + @todo review the converters marked REVIEW: Float32_To_Int32, + Float32_To_Int32_Dither, Float32_To_Int32_Clip, Float32_To_Int32_DitherClip, + Int32_To_Int16_Dither, Int32_To_Int8_Dither, Int16_To_Int32 +*/ + + +#include "pa_converters.h" +#include "pa_dither.h" +#include "pa_endianness.h" +#include "pa_types.h" + + +PaSampleFormat PaUtil_SelectClosestAvailableFormat( + PaSampleFormat availableFormats, PaSampleFormat format ) +{ + PaSampleFormat result; + + format &= ~paNonInterleaved; + availableFormats &= ~paNonInterleaved; + + if( (format & availableFormats) == 0 ) + { + /* NOTE: this code depends on the sample format constants being in + descending order of quality - ie best quality is 0 + FIXME: should write an assert which checks that all of the + known constants conform to that requirement. + */ + + if( format != 0x01 ) + { + /* scan for better formats */ + result = format; + do + { + result >>= 1; + } + while( (result & availableFormats) == 0 && result != 0 ); + } + else + { + result = 0; + } + + if( result == 0 ){ + /* scan for worse formats */ + result = format; + do + { + result <<= 1; + } + while( (result & availableFormats) == 0 && result != paCustomFormat ); + + if( (result & availableFormats) == 0 ) + result = paSampleFormatNotSupported; + } + + }else{ + result = format; + } + + return result; +} + +/* -------------------------------------------------------------------------- */ + +#define PA_SELECT_FORMAT_( format, float32, int32, int24, int16, int8, uint8 ) \ + switch( format & ~paNonInterleaved ){ \ + case paFloat32: \ + float32 \ + case paInt32: \ + int32 \ + case paInt24: \ + int24 \ + case paInt16: \ + int16 \ + case paInt8: \ + int8 \ + case paUInt8: \ + uint8 \ + default: return 0; \ + } + +/* -------------------------------------------------------------------------- */ + +#define PA_SELECT_CONVERTER_DITHER_CLIP_( flags, source, destination ) \ + if( flags & paClipOff ){ /* no clip */ \ + if( flags & paDitherOff ){ /* no dither */ \ + return paConverters. source ## _To_ ## destination; \ + }else{ /* dither */ \ + return paConverters. source ## _To_ ## destination ## _Dither; \ + } \ + }else{ /* clip */ \ + if( flags & paDitherOff ){ /* no dither */ \ + return paConverters. source ## _To_ ## destination ## _Clip; \ + }else{ /* dither */ \ + return paConverters. source ## _To_ ## destination ## _DitherClip; \ + } \ + } + +/* -------------------------------------------------------------------------- */ + +#define PA_SELECT_CONVERTER_DITHER_( flags, source, destination ) \ + if( flags & paDitherOff ){ /* no dither */ \ + return paConverters. source ## _To_ ## destination; \ + }else{ /* dither */ \ + return paConverters. source ## _To_ ## destination ## _Dither; \ + } + +/* -------------------------------------------------------------------------- */ + +#define PA_USE_CONVERTER_( source, destination )\ + return paConverters. source ## _To_ ## destination; + +/* -------------------------------------------------------------------------- */ + +#define PA_UNITY_CONVERSION_( wordlength )\ + return paConverters. Copy_ ## wordlength ## _To_ ## wordlength; + +/* -------------------------------------------------------------------------- */ + +PaUtilConverter* PaUtil_SelectConverter( PaSampleFormat sourceFormat, + PaSampleFormat destinationFormat, PaStreamFlags flags ) +{ + PA_SELECT_FORMAT_( sourceFormat, + /* paFloat32: */ + PA_SELECT_FORMAT_( destinationFormat, + /* paFloat32: */ PA_UNITY_CONVERSION_( 32 ), + /* paInt32: */ PA_SELECT_CONVERTER_DITHER_CLIP_( flags, Float32, Int32 ), + /* paInt24: */ PA_SELECT_CONVERTER_DITHER_CLIP_( flags, Float32, Int24 ), + /* paInt16: */ PA_SELECT_CONVERTER_DITHER_CLIP_( flags, Float32, Int16 ), + /* paInt8: */ PA_SELECT_CONVERTER_DITHER_CLIP_( flags, Float32, Int8 ), + /* paUInt8: */ PA_SELECT_CONVERTER_DITHER_CLIP_( flags, Float32, UInt8 ) + ), + /* paInt32: */ + PA_SELECT_FORMAT_( destinationFormat, + /* paFloat32: */ PA_USE_CONVERTER_( Int32, Float32 ), + /* paInt32: */ PA_UNITY_CONVERSION_( 32 ), + /* paInt24: */ PA_SELECT_CONVERTER_DITHER_( flags, Int32, Int24 ), + /* paInt16: */ PA_SELECT_CONVERTER_DITHER_( flags, Int32, Int16 ), + /* paInt8: */ PA_SELECT_CONVERTER_DITHER_( flags, Int32, Int8 ), + /* paUInt8: */ PA_SELECT_CONVERTER_DITHER_( flags, Int32, UInt8 ) + ), + /* paInt24: */ + PA_SELECT_FORMAT_( destinationFormat, + /* paFloat32: */ PA_USE_CONVERTER_( Int24, Float32 ), + /* paInt32: */ PA_USE_CONVERTER_( Int24, Int32 ), + /* paInt24: */ PA_UNITY_CONVERSION_( 24 ), + /* paInt16: */ PA_SELECT_CONVERTER_DITHER_( flags, Int24, Int16 ), + /* paInt8: */ PA_SELECT_CONVERTER_DITHER_( flags, Int24, Int8 ), + /* paUInt8: */ PA_SELECT_CONVERTER_DITHER_( flags, Int24, UInt8 ) + ), + /* paInt16: */ + PA_SELECT_FORMAT_( destinationFormat, + /* paFloat32: */ PA_USE_CONVERTER_( Int16, Float32 ), + /* paInt32: */ PA_USE_CONVERTER_( Int16, Int32 ), + /* paInt24: */ PA_USE_CONVERTER_( Int16, Int24 ), + /* paInt16: */ PA_UNITY_CONVERSION_( 16 ), + /* paInt8: */ PA_SELECT_CONVERTER_DITHER_( flags, Int16, Int8 ), + /* paUInt8: */ PA_SELECT_CONVERTER_DITHER_( flags, Int16, UInt8 ) + ), + /* paInt8: */ + PA_SELECT_FORMAT_( destinationFormat, + /* paFloat32: */ PA_USE_CONVERTER_( Int8, Float32 ), + /* paInt32: */ PA_USE_CONVERTER_( Int8, Int32 ), + /* paInt24: */ PA_USE_CONVERTER_( Int8, Int24 ), + /* paInt16: */ PA_USE_CONVERTER_( Int8, Int16 ), + /* paInt8: */ PA_UNITY_CONVERSION_( 8 ), + /* paUInt8: */ PA_USE_CONVERTER_( Int8, UInt8 ) + ), + /* paUInt8: */ + PA_SELECT_FORMAT_( destinationFormat, + /* paFloat32: */ PA_USE_CONVERTER_( UInt8, Float32 ), + /* paInt32: */ PA_USE_CONVERTER_( UInt8, Int32 ), + /* paInt24: */ PA_USE_CONVERTER_( UInt8, Int24 ), + /* paInt16: */ PA_USE_CONVERTER_( UInt8, Int16 ), + /* paInt8: */ PA_USE_CONVERTER_( UInt8, Int8 ), + /* paUInt8: */ PA_UNITY_CONVERSION_( 8 ) + ) + ) +} + +/* -------------------------------------------------------------------------- */ + +#ifdef PA_NO_STANDARD_CONVERTERS + +/* -------------------------------------------------------------------------- */ + +PaUtilConverterTable paConverters = { + 0, /* PaUtilConverter *Float32_To_Int32; */ + 0, /* PaUtilConverter *Float32_To_Int32_Dither; */ + 0, /* PaUtilConverter *Float32_To_Int32_Clip; */ + 0, /* PaUtilConverter *Float32_To_Int32_DitherClip; */ + + 0, /* PaUtilConverter *Float32_To_Int24; */ + 0, /* PaUtilConverter *Float32_To_Int24_Dither; */ + 0, /* PaUtilConverter *Float32_To_Int24_Clip; */ + 0, /* PaUtilConverter *Float32_To_Int24_DitherClip; */ + + 0, /* PaUtilConverter *Float32_To_Int16; */ + 0, /* PaUtilConverter *Float32_To_Int16_Dither; */ + 0, /* PaUtilConverter *Float32_To_Int16_Clip; */ + 0, /* PaUtilConverter *Float32_To_Int16_DitherClip; */ + + 0, /* PaUtilConverter *Float32_To_Int8; */ + 0, /* PaUtilConverter *Float32_To_Int8_Dither; */ + 0, /* PaUtilConverter *Float32_To_Int8_Clip; */ + 0, /* PaUtilConverter *Float32_To_Int8_DitherClip; */ + + 0, /* PaUtilConverter *Float32_To_UInt8; */ + 0, /* PaUtilConverter *Float32_To_UInt8_Dither; */ + 0, /* PaUtilConverter *Float32_To_UInt8_Clip; */ + 0, /* PaUtilConverter *Float32_To_UInt8_DitherClip; */ + + 0, /* PaUtilConverter *Int32_To_Float32; */ + 0, /* PaUtilConverter *Int32_To_Int24; */ + 0, /* PaUtilConverter *Int32_To_Int24_Dither; */ + 0, /* PaUtilConverter *Int32_To_Int16; */ + 0, /* PaUtilConverter *Int32_To_Int16_Dither; */ + 0, /* PaUtilConverter *Int32_To_Int8; */ + 0, /* PaUtilConverter *Int32_To_Int8_Dither; */ + 0, /* PaUtilConverter *Int32_To_UInt8; */ + 0, /* PaUtilConverter *Int32_To_UInt8_Dither; */ + + 0, /* PaUtilConverter *Int24_To_Float32; */ + 0, /* PaUtilConverter *Int24_To_Int32; */ + 0, /* PaUtilConverter *Int24_To_Int16; */ + 0, /* PaUtilConverter *Int24_To_Int16_Dither; */ + 0, /* PaUtilConverter *Int24_To_Int8; */ + 0, /* PaUtilConverter *Int24_To_Int8_Dither; */ + 0, /* PaUtilConverter *Int24_To_UInt8; */ + 0, /* PaUtilConverter *Int24_To_UInt8_Dither; */ + + 0, /* PaUtilConverter *Int16_To_Float32; */ + 0, /* PaUtilConverter *Int16_To_Int32; */ + 0, /* PaUtilConverter *Int16_To_Int24; */ + 0, /* PaUtilConverter *Int16_To_Int8; */ + 0, /* PaUtilConverter *Int16_To_Int8_Dither; */ + 0, /* PaUtilConverter *Int16_To_UInt8; */ + 0, /* PaUtilConverter *Int16_To_UInt8_Dither; */ + + 0, /* PaUtilConverter *Int8_To_Float32; */ + 0, /* PaUtilConverter *Int8_To_Int32; */ + 0, /* PaUtilConverter *Int8_To_Int24 */ + 0, /* PaUtilConverter *Int8_To_Int16; */ + 0, /* PaUtilConverter *Int8_To_UInt8; */ + + 0, /* PaUtilConverter *UInt8_To_Float32; */ + 0, /* PaUtilConverter *UInt8_To_Int32; */ + 0, /* PaUtilConverter *UInt8_To_Int24; */ + 0, /* PaUtilConverter *UInt8_To_Int16; */ + 0, /* PaUtilConverter *UInt8_To_Int8; */ + + 0, /* PaUtilConverter *Copy_8_To_8; */ + 0, /* PaUtilConverter *Copy_16_To_16; */ + 0, /* PaUtilConverter *Copy_24_To_24; */ + 0 /* PaUtilConverter *Copy_32_To_32; */ +}; + +/* -------------------------------------------------------------------------- */ + +#else /* PA_NO_STANDARD_CONVERTERS is not defined */ + +/* -------------------------------------------------------------------------- */ + +#define PA_CLIP_( val, min, max )\ + { val = ((val) < (min)) ? (min) : (((val) > (max)) ? (max) : (val)); } + + +static const float const_1_div_128_ = 1.0f / 128.0f; /* 8 bit multiplier */ + +static const float const_1_div_32768_ = 1.0f / 32768.f; /* 16 bit multiplier */ + +static const double const_1_div_2147483648_ = 1.0 / 2147483648.0; /* 32 bit multiplier */ + +/* -------------------------------------------------------------------------- */ + +static void Float32_To_Int32( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + float *src = (float*)sourceBuffer; + PaInt32 *dest = (PaInt32*)destinationBuffer; + (void)ditherGenerator; /* unused parameter */ + + while( count-- ) + { + /* REVIEW */ +#ifdef PA_USE_C99_LRINTF + float scaled = *src * 0x7FFFFFFF; + *dest = lrintf(scaled-0.5f); +#else + double scaled = *src * 0x7FFFFFFF; + *dest = (PaInt32) scaled; +#endif + + src += sourceStride; + dest += destinationStride; + } +} + +/* -------------------------------------------------------------------------- */ + +static void Float32_To_Int32_Dither( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + float *src = (float*)sourceBuffer; + PaInt32 *dest = (PaInt32*)destinationBuffer; + + while( count-- ) + { + /* REVIEW */ +#ifdef PA_USE_C99_LRINTF + float dither = PaUtil_GenerateFloatTriangularDither( ditherGenerator ); + /* use smaller scaler to prevent overflow when we add the dither */ + float dithered = ((float)*src * (2147483646.0f)) + dither; + *dest = lrintf(dithered - 0.5f); +#else + double dither = PaUtil_GenerateFloatTriangularDither( ditherGenerator ); + /* use smaller scaler to prevent overflow when we add the dither */ + double dithered = ((double)*src * (2147483646.0)) + dither; + *dest = (PaInt32) dithered; +#endif + src += sourceStride; + dest += destinationStride; + } +} + +/* -------------------------------------------------------------------------- */ + +static void Float32_To_Int32_Clip( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + float *src = (float*)sourceBuffer; + PaInt32 *dest = (PaInt32*)destinationBuffer; + (void) ditherGenerator; /* unused parameter */ + + while( count-- ) + { + /* REVIEW */ +#ifdef PA_USE_C99_LRINTF + float scaled = *src * 0x7FFFFFFF; + PA_CLIP_( scaled, -2147483648.f, 2147483647.f ); + *dest = lrintf(scaled-0.5f); +#else + double scaled = *src * 0x7FFFFFFF; + PA_CLIP_( scaled, -2147483648., 2147483647. ); + *dest = (PaInt32) scaled; +#endif + + src += sourceStride; + dest += destinationStride; + } +} + +/* -------------------------------------------------------------------------- */ + +static void Float32_To_Int32_DitherClip( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + float *src = (float*)sourceBuffer; + PaInt32 *dest = (PaInt32*)destinationBuffer; + + while( count-- ) + { + /* REVIEW */ +#ifdef PA_USE_C99_LRINTF + float dither = PaUtil_GenerateFloatTriangularDither( ditherGenerator ); + /* use smaller scaler to prevent overflow when we add the dither */ + float dithered = ((float)*src * (2147483646.0f)) + dither; + PA_CLIP_( dithered, -2147483648.f, 2147483647.f ); + *dest = lrintf(dithered-0.5f); +#else + double dither = PaUtil_GenerateFloatTriangularDither( ditherGenerator ); + /* use smaller scaler to prevent overflow when we add the dither */ + double dithered = ((double)*src * (2147483646.0)) + dither; + PA_CLIP_( dithered, -2147483648., 2147483647. ); + *dest = (PaInt32) dithered; +#endif + + src += sourceStride; + dest += destinationStride; + } +} + +/* -------------------------------------------------------------------------- */ + +static void Float32_To_Int24( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + float *src = (float*)sourceBuffer; + unsigned char *dest = (unsigned char*)destinationBuffer; + PaInt32 temp; + + (void) ditherGenerator; /* unused parameter */ + + while( count-- ) + { + /* convert to 32 bit and drop the low 8 bits */ + double scaled = (double)(*src) * 2147483647.0; + temp = (PaInt32) scaled; + +#if defined(PA_LITTLE_ENDIAN) + dest[0] = (unsigned char)(temp >> 8); + dest[1] = (unsigned char)(temp >> 16); + dest[2] = (unsigned char)(temp >> 24); +#elif defined(PA_BIG_ENDIAN) + dest[0] = (unsigned char)(temp >> 24); + dest[1] = (unsigned char)(temp >> 16); + dest[2] = (unsigned char)(temp >> 8); +#endif + + src += sourceStride; + dest += destinationStride * 3; + } +} + +/* -------------------------------------------------------------------------- */ + +static void Float32_To_Int24_Dither( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + float *src = (float*)sourceBuffer; + unsigned char *dest = (unsigned char*)destinationBuffer; + PaInt32 temp; + + while( count-- ) + { + /* convert to 32 bit and drop the low 8 bits */ + + double dither = PaUtil_GenerateFloatTriangularDither( ditherGenerator ); + /* use smaller scaler to prevent overflow when we add the dither */ + double dithered = ((double)*src * (2147483646.0)) + dither; + + temp = (PaInt32) dithered; + +#if defined(PA_LITTLE_ENDIAN) + dest[0] = (unsigned char)(temp >> 8); + dest[1] = (unsigned char)(temp >> 16); + dest[2] = (unsigned char)(temp >> 24); +#elif defined(PA_BIG_ENDIAN) + dest[0] = (unsigned char)(temp >> 24); + dest[1] = (unsigned char)(temp >> 16); + dest[2] = (unsigned char)(temp >> 8); +#endif + + src += sourceStride; + dest += destinationStride * 3; + } +} + +/* -------------------------------------------------------------------------- */ + +static void Float32_To_Int24_Clip( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + float *src = (float*)sourceBuffer; + unsigned char *dest = (unsigned char*)destinationBuffer; + PaInt32 temp; + + (void) ditherGenerator; /* unused parameter */ + + while( count-- ) + { + /* convert to 32 bit and drop the low 8 bits */ + double scaled = *src * 0x7FFFFFFF; + PA_CLIP_( scaled, -2147483648., 2147483647. ); + temp = (PaInt32) scaled; + +#if defined(PA_LITTLE_ENDIAN) + dest[0] = (unsigned char)(temp >> 8); + dest[1] = (unsigned char)(temp >> 16); + dest[2] = (unsigned char)(temp >> 24); +#elif defined(PA_BIG_ENDIAN) + dest[0] = (unsigned char)(temp >> 24); + dest[1] = (unsigned char)(temp >> 16); + dest[2] = (unsigned char)(temp >> 8); +#endif + + src += sourceStride; + dest += destinationStride * 3; + } +} + +/* -------------------------------------------------------------------------- */ + +static void Float32_To_Int24_DitherClip( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + float *src = (float*)sourceBuffer; + unsigned char *dest = (unsigned char*)destinationBuffer; + PaInt32 temp; + + while( count-- ) + { + /* convert to 32 bit and drop the low 8 bits */ + + double dither = PaUtil_GenerateFloatTriangularDither( ditherGenerator ); + /* use smaller scaler to prevent overflow when we add the dither */ + double dithered = ((double)*src * (2147483646.0)) + dither; + PA_CLIP_( dithered, -2147483648., 2147483647. ); + + temp = (PaInt32) dithered; + +#if defined(PA_LITTLE_ENDIAN) + dest[0] = (unsigned char)(temp >> 8); + dest[1] = (unsigned char)(temp >> 16); + dest[2] = (unsigned char)(temp >> 24); +#elif defined(PA_BIG_ENDIAN) + dest[0] = (unsigned char)(temp >> 24); + dest[1] = (unsigned char)(temp >> 16); + dest[2] = (unsigned char)(temp >> 8); +#endif + + src += sourceStride; + dest += destinationStride * 3; + } +} + +/* -------------------------------------------------------------------------- */ + +static void Float32_To_Int16( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + float *src = (float*)sourceBuffer; + PaInt16 *dest = (PaInt16*)destinationBuffer; + (void)ditherGenerator; /* unused parameter */ + + while( count-- ) + { +#ifdef PA_USE_C99_LRINTF + float tempf = (*src * (32767.0f)) ; + *dest = lrintf(tempf-0.5f); +#else + short samp = (short) (*src * (32767.0f)); + *dest = samp; +#endif + + src += sourceStride; + dest += destinationStride; + } +} + +/* -------------------------------------------------------------------------- */ + +static void Float32_To_Int16_Dither( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + float *src = (float*)sourceBuffer; + PaInt16 *dest = (PaInt16*)destinationBuffer; + + while( count-- ) + { + + float dither = PaUtil_GenerateFloatTriangularDither( ditherGenerator ); + /* use smaller scaler to prevent overflow when we add the dither */ + float dithered = (*src * (32766.0f)) + dither; + +#ifdef PA_USE_C99_LRINTF + *dest = lrintf(dithered-0.5f); +#else + *dest = (PaInt16) dithered; +#endif + + src += sourceStride; + dest += destinationStride; + } +} + +/* -------------------------------------------------------------------------- */ + +static void Float32_To_Int16_Clip( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + float *src = (float*)sourceBuffer; + PaInt16 *dest = (PaInt16*)destinationBuffer; + (void)ditherGenerator; /* unused parameter */ + + while( count-- ) + { +#ifdef PA_USE_C99_LRINTF + long samp = lrintf((*src * (32767.0f)) -0.5f); +#else + long samp = (PaInt32) (*src * (32767.0f)); +#endif + PA_CLIP_( samp, -0x8000, 0x7FFF ); + *dest = (PaInt16) samp; + + src += sourceStride; + dest += destinationStride; + } +} + +/* -------------------------------------------------------------------------- */ + +static void Float32_To_Int16_DitherClip( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + float *src = (float*)sourceBuffer; + PaInt16 *dest = (PaInt16*)destinationBuffer; + (void)ditherGenerator; /* unused parameter */ + + while( count-- ) + { + + float dither = PaUtil_GenerateFloatTriangularDither( ditherGenerator ); + /* use smaller scaler to prevent overflow when we add the dither */ + float dithered = (*src * (32766.0f)) + dither; + PaInt32 samp = (PaInt32) dithered; + PA_CLIP_( samp, -0x8000, 0x7FFF ); +#ifdef PA_USE_C99_LRINTF + *dest = lrintf(samp-0.5f); +#else + *dest = (PaInt16) samp; +#endif + + src += sourceStride; + dest += destinationStride; + } +} + +/* -------------------------------------------------------------------------- */ + +static void Float32_To_Int8( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + float *src = (float*)sourceBuffer; + signed char *dest = (signed char*)destinationBuffer; + (void)ditherGenerator; /* unused parameter */ + + while( count-- ) + { + signed char samp = (signed char) (*src * (127.0f)); + *dest = samp; + + src += sourceStride; + dest += destinationStride; + } +} + +/* -------------------------------------------------------------------------- */ + +static void Float32_To_Int8_Dither( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + float *src = (float*)sourceBuffer; + signed char *dest = (signed char*)destinationBuffer; + + while( count-- ) + { + float dither = PaUtil_GenerateFloatTriangularDither( ditherGenerator ); + /* use smaller scaler to prevent overflow when we add the dither */ + float dithered = (*src * (126.0f)) + dither; + PaInt32 samp = (PaInt32) dithered; + *dest = (signed char) samp; + + src += sourceStride; + dest += destinationStride; + } +} + +/* -------------------------------------------------------------------------- */ + +static void Float32_To_Int8_Clip( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + float *src = (float*)sourceBuffer; + signed char *dest = (signed char*)destinationBuffer; + (void)ditherGenerator; /* unused parameter */ + + while( count-- ) + { + PaInt32 samp = (PaInt32)(*src * (127.0f)); + PA_CLIP_( samp, -0x80, 0x7F ); + *dest = (signed char) samp; + + src += sourceStride; + dest += destinationStride; + } +} + +/* -------------------------------------------------------------------------- */ + +static void Float32_To_Int8_DitherClip( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + float *src = (float*)sourceBuffer; + signed char *dest = (signed char*)destinationBuffer; + (void)ditherGenerator; /* unused parameter */ + + while( count-- ) + { + float dither = PaUtil_GenerateFloatTriangularDither( ditherGenerator ); + /* use smaller scaler to prevent overflow when we add the dither */ + float dithered = (*src * (126.0f)) + dither; + PaInt32 samp = (PaInt32) dithered; + PA_CLIP_( samp, -0x80, 0x7F ); + *dest = (signed char) samp; + + src += sourceStride; + dest += destinationStride; + } +} + +/* -------------------------------------------------------------------------- */ + +static void Float32_To_UInt8( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + float *src = (float*)sourceBuffer; + unsigned char *dest = (unsigned char*)destinationBuffer; + (void)ditherGenerator; /* unused parameter */ + + while( count-- ) + { + unsigned char samp = (unsigned char)(128 + ((unsigned char) (*src * (127.0f)))); + *dest = samp; + + src += sourceStride; + dest += destinationStride; + } +} + +/* -------------------------------------------------------------------------- */ + +static void Float32_To_UInt8_Dither( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + float *src = (float*)sourceBuffer; + unsigned char *dest = (unsigned char*)destinationBuffer; + + while( count-- ) + { + float dither = PaUtil_GenerateFloatTriangularDither( ditherGenerator ); + /* use smaller scaler to prevent overflow when we add the dither */ + float dithered = (*src * (126.0f)) + dither; + PaInt32 samp = (PaInt32) dithered; + *dest = (unsigned char) (128 + samp); + + src += sourceStride; + dest += destinationStride; + } +} + +/* -------------------------------------------------------------------------- */ + +static void Float32_To_UInt8_Clip( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + float *src = (float*)sourceBuffer; + unsigned char *dest = (unsigned char*)destinationBuffer; + (void)ditherGenerator; /* unused parameter */ + + while( count-- ) + { + PaInt32 samp = 128 + (PaInt32)(*src * (127.0f)); + PA_CLIP_( samp, 0x0000, 0x00FF ); + *dest = (unsigned char) samp; + + src += sourceStride; + dest += destinationStride; + } +} + +/* -------------------------------------------------------------------------- */ + +static void Float32_To_UInt8_DitherClip( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + float *src = (float*)sourceBuffer; + unsigned char *dest = (unsigned char*)destinationBuffer; + (void)ditherGenerator; /* unused parameter */ + + while( count-- ) + { + float dither = PaUtil_GenerateFloatTriangularDither( ditherGenerator ); + /* use smaller scaler to prevent overflow when we add the dither */ + float dithered = (*src * (126.0f)) + dither; + PaInt32 samp = 128 + (PaInt32) dithered; + PA_CLIP_( samp, 0x0000, 0x00FF ); + *dest = (unsigned char) samp; + + src += sourceStride; + dest += destinationStride; + } +} + +/* -------------------------------------------------------------------------- */ + +static void Int32_To_Float32( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + PaInt32 *src = (PaInt32*)sourceBuffer; + float *dest = (float*)destinationBuffer; + (void)ditherGenerator; /* unused parameter */ + + while( count-- ) + { + *dest = (float) ((double)*src * const_1_div_2147483648_); + + src += sourceStride; + dest += destinationStride; + } +} + +/* -------------------------------------------------------------------------- */ + +static void Int32_To_Int24( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + PaInt32 *src = (PaInt32*)sourceBuffer; + unsigned char *dest = (unsigned char*)destinationBuffer; + (void) ditherGenerator; /* unused parameter */ + + while( count-- ) + { + /* REVIEW */ +#if defined(PA_LITTLE_ENDIAN) + dest[0] = (unsigned char)(*src >> 8); + dest[1] = (unsigned char)(*src >> 16); + dest[2] = (unsigned char)(*src >> 24); +#elif defined(PA_BIG_ENDIAN) + dest[0] = (unsigned char)(*src >> 24); + dest[1] = (unsigned char)(*src >> 16); + dest[2] = (unsigned char)(*src >> 8); +#endif + src += sourceStride; + dest += destinationStride * 3; + } +} + +/* -------------------------------------------------------------------------- */ + +static void Int32_To_Int24_Dither( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + (void) destinationBuffer; /* unused parameters */ + (void) destinationStride; /* unused parameters */ + (void) sourceBuffer; /* unused parameters */ + (void) sourceStride; /* unused parameters */ + (void) count; /* unused parameters */ + (void) ditherGenerator; /* unused parameters */ + /* IMPLEMENT ME */ +} + +/* -------------------------------------------------------------------------- */ + +static void Int32_To_Int16( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + PaInt32 *src = (PaInt32*)sourceBuffer; + PaInt16 *dest = (PaInt16*)destinationBuffer; + (void)ditherGenerator; /* unused parameter */ + + while( count-- ) + { + *dest = (PaInt16) ((*src) >> 16); + + src += sourceStride; + dest += destinationStride; + } +} + +/* -------------------------------------------------------------------------- */ + +static void Int32_To_Int16_Dither( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + PaInt32 *src = (PaInt32*)sourceBuffer; + PaInt16 *dest = (PaInt16*)destinationBuffer; + PaInt32 dither; + + while( count-- ) + { + /* REVIEW */ + dither = PaUtil_Generate16BitTriangularDither( ditherGenerator ); + *dest = (PaInt16) ((((*src)>>1) + dither) >> 15); + + src += sourceStride; + dest += destinationStride; + } +} + +/* -------------------------------------------------------------------------- */ + +static void Int32_To_Int8( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + PaInt32 *src = (PaInt32*)sourceBuffer; + signed char *dest = (signed char*)destinationBuffer; + (void)ditherGenerator; /* unused parameter */ + + while( count-- ) + { + *dest = (signed char) ((*src) >> 24); + + src += sourceStride; + dest += destinationStride; + } +} + +/* -------------------------------------------------------------------------- */ + +static void Int32_To_Int8_Dither( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + PaInt32 *src = (PaInt32*)sourceBuffer; + signed char *dest = (signed char*)destinationBuffer; + PaInt32 dither; + + while( count-- ) + { + /* REVIEW */ + dither = PaUtil_Generate16BitTriangularDither( ditherGenerator ); + *dest = (signed char) ((((*src)>>1) + dither) >> 23); + + src += sourceStride; + dest += destinationStride; + } +} + +/* -------------------------------------------------------------------------- */ + +static void Int32_To_UInt8( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + PaInt32 *src = (PaInt32*)sourceBuffer; + unsigned char *dest = (unsigned char*)destinationBuffer; + (void)ditherGenerator; /* unused parameter */ + + while( count-- ) + { + (*dest) = (unsigned char)(((*src) >> 24) + 128); + + src += sourceStride; + dest += destinationStride; + } +} + +/* -------------------------------------------------------------------------- */ + +static void Int32_To_UInt8_Dither( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + PaInt32 *src = (PaInt32*)sourceBuffer; + unsigned char *dest = (unsigned char*)destinationBuffer; + (void)ditherGenerator; /* unused parameter */ + + while( count-- ) + { + /* IMPLEMENT ME */ + + src += sourceStride; + dest += destinationStride; + } +} + +/* -------------------------------------------------------------------------- */ + +static void Int24_To_Float32( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + unsigned char *src = (unsigned char*)sourceBuffer; + float *dest = (float*)destinationBuffer; + PaInt32 temp; + + (void) ditherGenerator; /* unused parameter */ + + while( count-- ) + { + +#if defined(PA_LITTLE_ENDIAN) + temp = (((PaInt32)src[0]) << 8); + temp = temp | (((PaInt32)src[1]) << 16); + temp = temp | (((PaInt32)src[2]) << 24); +#elif defined(PA_BIG_ENDIAN) + temp = (((PaInt32)src[0]) << 24); + temp = temp | (((PaInt32)src[1]) << 16); + temp = temp | (((PaInt32)src[2]) << 8); +#endif + + *dest = (float) ((double)temp * const_1_div_2147483648_); + + src += sourceStride * 3; + dest += destinationStride; + } +} + +/* -------------------------------------------------------------------------- */ + +static void Int24_To_Int32( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + unsigned char *src = (unsigned char*)sourceBuffer; + PaInt32 *dest = (PaInt32*) destinationBuffer; + PaInt32 temp; + + (void) ditherGenerator; /* unused parameter */ + + while( count-- ) + { + +#if defined(PA_LITTLE_ENDIAN) + temp = (((PaInt32)src[0]) << 8); + temp = temp | (((PaInt32)src[1]) << 16); + temp = temp | (((PaInt32)src[2]) << 24); +#elif defined(PA_BIG_ENDIAN) + temp = (((PaInt32)src[0]) << 24); + temp = temp | (((PaInt32)src[1]) << 16); + temp = temp | (((PaInt32)src[2]) << 8); +#endif + + *dest = temp; + + src += sourceStride * 3; + dest += destinationStride; + } +} + +/* -------------------------------------------------------------------------- */ + +static void Int24_To_Int16( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + unsigned char *src = (unsigned char*)sourceBuffer; + PaInt16 *dest = (PaInt16*)destinationBuffer; + + PaInt16 temp; + + (void) ditherGenerator; /* unused parameter */ + + while( count-- ) + { + +#if defined(PA_LITTLE_ENDIAN) + /* src[0] is discarded */ + temp = (((PaInt16)src[1])); + temp = temp | (PaInt16)(((PaInt16)src[2]) << 8); +#elif defined(PA_BIG_ENDIAN) + /* src[2] is discarded */ + temp = (PaInt16)(((PaInt16)src[0]) << 8); + temp = temp | (((PaInt16)src[1])); +#endif + + *dest = temp; + + src += sourceStride * 3; + dest += destinationStride; + } +} + +/* -------------------------------------------------------------------------- */ + +static void Int24_To_Int16_Dither( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + unsigned char *src = (unsigned char*)sourceBuffer; + PaInt16 *dest = (PaInt16*)destinationBuffer; + + PaInt32 temp, dither; + + while( count-- ) + { + +#if defined(PA_LITTLE_ENDIAN) + temp = (((PaInt32)src[0]) << 8); + temp = temp | (((PaInt32)src[1]) << 16); + temp = temp | (((PaInt32)src[2]) << 24); +#elif defined(PA_BIG_ENDIAN) + temp = (((PaInt32)src[0]) << 24); + temp = temp | (((PaInt32)src[1]) << 16); + temp = temp | (((PaInt32)src[2]) << 8); +#endif + + /* REVIEW */ + dither = PaUtil_Generate16BitTriangularDither( ditherGenerator ); + *dest = (PaInt16) (((temp >> 1) + dither) >> 15); + + src += sourceStride * 3; + dest += destinationStride; + } +} + +/* -------------------------------------------------------------------------- */ + +static void Int24_To_Int8( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + unsigned char *src = (unsigned char*)sourceBuffer; + signed char *dest = (signed char*)destinationBuffer; + + (void) ditherGenerator; /* unused parameter */ + + while( count-- ) + { + +#if defined(PA_LITTLE_ENDIAN) + /* src[0] is discarded */ + /* src[1] is discarded */ + *dest = src[2]; +#elif defined(PA_BIG_ENDIAN) + /* src[2] is discarded */ + /* src[1] is discarded */ + *dest = src[0]; +#endif + + src += sourceStride * 3; + dest += destinationStride; + } +} + +/* -------------------------------------------------------------------------- */ + +static void Int24_To_Int8_Dither( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + unsigned char *src = (unsigned char*)sourceBuffer; + signed char *dest = (signed char*)destinationBuffer; + + PaInt32 temp, dither; + + while( count-- ) + { + +#if defined(PA_LITTLE_ENDIAN) + temp = (((PaInt32)src[0]) << 8); + temp = temp | (((PaInt32)src[1]) << 16); + temp = temp | (((PaInt32)src[2]) << 24); +#elif defined(PA_BIG_ENDIAN) + temp = (((PaInt32)src[0]) << 24); + temp = temp | (((PaInt32)src[1]) << 16); + temp = temp | (((PaInt32)src[2]) << 8); +#endif + + /* REVIEW */ + dither = PaUtil_Generate16BitTriangularDither( ditherGenerator ); + *dest = (signed char) (((temp >> 1) + dither) >> 23); + + src += sourceStride * 3; + dest += destinationStride; + } +} + +/* -------------------------------------------------------------------------- */ + +static void Int24_To_UInt8( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + unsigned char *src = (unsigned char*)sourceBuffer; + unsigned char *dest = (unsigned char*)destinationBuffer; + + (void) ditherGenerator; /* unused parameter */ + + while( count-- ) + { + +#if defined(PA_LITTLE_ENDIAN) + /* src[0] is discarded */ + /* src[1] is discarded */ + *dest = (unsigned char)(src[2] + 128); +#elif defined(PA_BIG_ENDIAN) + *dest = (unsigned char)(src[0] + 128); + /* src[1] is discarded */ + /* src[2] is discarded */ +#endif + + src += sourceStride * 3; + dest += destinationStride; + } +} + +/* -------------------------------------------------------------------------- */ + +static void Int24_To_UInt8_Dither( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + (void) destinationBuffer; /* unused parameters */ + (void) destinationStride; /* unused parameters */ + (void) sourceBuffer; /* unused parameters */ + (void) sourceStride; /* unused parameters */ + (void) count; /* unused parameters */ + (void) ditherGenerator; /* unused parameters */ + /* IMPLEMENT ME */ +} + +/* -------------------------------------------------------------------------- */ + +static void Int16_To_Float32( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + PaInt16 *src = (PaInt16*)sourceBuffer; + float *dest = (float*)destinationBuffer; + (void)ditherGenerator; /* unused parameter */ + + while( count-- ) + { + float samp = *src * const_1_div_32768_; /* FIXME: i'm concerned about this being asymetrical with float->int16 -rb */ + *dest = samp; + + src += sourceStride; + dest += destinationStride; + } +} + +/* -------------------------------------------------------------------------- */ + +static void Int16_To_Int32( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + PaInt16 *src = (PaInt16*)sourceBuffer; + PaInt32 *dest = (PaInt32*)destinationBuffer; + (void)ditherGenerator; /* unused parameter */ + + while( count-- ) + { + /* REVIEW: we should consider something like + (*src << 16) | (*src & 0xFFFF) + */ + + *dest = *src << 16; + + src += sourceStride; + dest += destinationStride; + } +} + +/* -------------------------------------------------------------------------- */ + +static void Int16_To_Int24( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + PaInt16 *src = (PaInt16*) sourceBuffer; + unsigned char *dest = (unsigned char*)destinationBuffer; + PaInt16 temp; + + (void) ditherGenerator; /* unused parameter */ + + while( count-- ) + { + temp = *src; + +#if defined(PA_LITTLE_ENDIAN) + dest[0] = 0; + dest[1] = (unsigned char)(temp); + dest[2] = (unsigned char)(temp >> 8); +#elif defined(PA_BIG_ENDIAN) + dest[0] = (unsigned char)(temp >> 8); + dest[1] = (unsigned char)(temp); + dest[2] = 0; +#endif + + src += sourceStride; + dest += destinationStride * 3; + } +} + +/* -------------------------------------------------------------------------- */ + +static void Int16_To_Int8( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + PaInt16 *src = (PaInt16*)sourceBuffer; + signed char *dest = (signed char*)destinationBuffer; + (void)ditherGenerator; /* unused parameter */ + + while( count-- ) + { + (*dest) = (signed char)((*src) >> 8); + + src += sourceStride; + dest += destinationStride; + } +} + +/* -------------------------------------------------------------------------- */ + +static void Int16_To_Int8_Dither( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + PaInt16 *src = (PaInt16*)sourceBuffer; + signed char *dest = (signed char*)destinationBuffer; + (void)ditherGenerator; /* unused parameter */ + + while( count-- ) + { + /* IMPLEMENT ME */ + + src += sourceStride; + dest += destinationStride; + } +} + +/* -------------------------------------------------------------------------- */ + +static void Int16_To_UInt8( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + PaInt16 *src = (PaInt16*)sourceBuffer; + unsigned char *dest = (unsigned char*)destinationBuffer; + (void)ditherGenerator; /* unused parameter */ + + while( count-- ) + { + (*dest) = (unsigned char)(((*src) >> 8) + 128); + + src += sourceStride; + dest += destinationStride; + } +} + +/* -------------------------------------------------------------------------- */ + +static void Int16_To_UInt8_Dither( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + PaInt16 *src = (PaInt16*)sourceBuffer; + unsigned char *dest = (unsigned char*)destinationBuffer; + (void)ditherGenerator; /* unused parameter */ + + while( count-- ) + { + /* IMPLEMENT ME */ + + src += sourceStride; + dest += destinationStride; + } +} + +/* -------------------------------------------------------------------------- */ + +static void Int8_To_Float32( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + signed char *src = (signed char*)sourceBuffer; + float *dest = (float*)destinationBuffer; + (void)ditherGenerator; /* unused parameter */ + + while( count-- ) + { + float samp = *src * const_1_div_128_; + *dest = samp; + + src += sourceStride; + dest += destinationStride; + } +} + +/* -------------------------------------------------------------------------- */ + +static void Int8_To_Int32( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + signed char *src = (signed char*)sourceBuffer; + PaInt32 *dest = (PaInt32*)destinationBuffer; + (void)ditherGenerator; /* unused parameter */ + + while( count-- ) + { + (*dest) = (*src) << 24; + + src += sourceStride; + dest += destinationStride; + } +} + +/* -------------------------------------------------------------------------- */ + +static void Int8_To_Int24( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + signed char *src = (signed char*)sourceBuffer; + unsigned char *dest = (unsigned char*)destinationBuffer; + (void)ditherGenerator; /* unused parameter */ + + while( count-- ) + { + +#if defined(PA_LITTLE_ENDIAN) + dest[0] = 0; + dest[1] = 0; + dest[2] = (*src); +#elif defined(PA_BIG_ENDIAN) + dest[0] = (*src); + dest[1] = 0; + dest[2] = 0; +#endif + + src += sourceStride; + dest += destinationStride * 3; + } +} + +/* -------------------------------------------------------------------------- */ + +static void Int8_To_Int16( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + signed char *src = (signed char*)sourceBuffer; + PaInt16 *dest = (PaInt16*)destinationBuffer; + (void)ditherGenerator; /* unused parameter */ + + while( count-- ) + { + (*dest) = (PaInt16)((*src) << 8); + + src += sourceStride; + dest += destinationStride; + } +} + +/* -------------------------------------------------------------------------- */ + +static void Int8_To_UInt8( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + signed char *src = (signed char*)sourceBuffer; + unsigned char *dest = (unsigned char*)destinationBuffer; + (void)ditherGenerator; /* unused parameter */ + + while( count-- ) + { + (*dest) = (unsigned char)(*src + 128); + + src += sourceStride; + dest += destinationStride; + } +} + +/* -------------------------------------------------------------------------- */ + +static void UInt8_To_Float32( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + unsigned char *src = (unsigned char*)sourceBuffer; + float *dest = (float*)destinationBuffer; + (void)ditherGenerator; /* unused parameter */ + + while( count-- ) + { + float samp = (*src - 128) * const_1_div_128_; + *dest = samp; + + src += sourceStride; + dest += destinationStride; + } +} + +/* -------------------------------------------------------------------------- */ + +static void UInt8_To_Int32( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + unsigned char *src = (unsigned char*)sourceBuffer; + PaInt32 *dest = (PaInt32*)destinationBuffer; + (void)ditherGenerator; /* unused parameter */ + + while( count-- ) + { + (*dest) = (*src - 128) << 24; + + src += sourceStride; + dest += destinationStride; + } +} + +/* -------------------------------------------------------------------------- */ + +static void UInt8_To_Int24( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + unsigned char *src = (unsigned char*)sourceBuffer; + unsigned char *dest = (unsigned char*)destinationBuffer; + (void) ditherGenerator; /* unused parameters */ + + while( count-- ) + { + +#if defined(PA_LITTLE_ENDIAN) + dest[0] = 0; + dest[1] = 0; + dest[2] = (unsigned char)(*src - 128); +#elif defined(PA_BIG_ENDIAN) + dest[0] = (unsigned char)(*src - 128); + dest[1] = 0; + dest[2] = 0; +#endif + + src += sourceStride; + dest += destinationStride * 3; + } +} + +/* -------------------------------------------------------------------------- */ + +static void UInt8_To_Int16( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + unsigned char *src = (unsigned char*)sourceBuffer; + PaInt16 *dest = (PaInt16*)destinationBuffer; + (void)ditherGenerator; /* unused parameter */ + + while( count-- ) + { + (*dest) = (PaInt16)((*src - 128) << 8); + + src += sourceStride; + dest += destinationStride; + } +} + +/* -------------------------------------------------------------------------- */ + +static void UInt8_To_Int8( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + unsigned char *src = (unsigned char*)sourceBuffer; + signed char *dest = (signed char*)destinationBuffer; + (void)ditherGenerator; /* unused parameter */ + + while( count-- ) + { + (*dest) = (signed char)(*src - 128); + + src += sourceStride; + dest += destinationStride; + } +} + +/* -------------------------------------------------------------------------- */ + +static void Copy_8_To_8( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + unsigned char *src = (unsigned char*)sourceBuffer; + unsigned char *dest = (unsigned char*)destinationBuffer; + + (void) ditherGenerator; /* unused parameter */ + + while( count-- ) + { + *dest = *src; + + src += sourceStride; + dest += destinationStride; + } +} + +/* -------------------------------------------------------------------------- */ + +static void Copy_16_To_16( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + PaUint16 *src = (PaUint16 *)sourceBuffer; + PaUint16 *dest = (PaUint16 *)destinationBuffer; + + (void) ditherGenerator; /* unused parameter */ + + while( count-- ) + { + *dest = *src; + + src += sourceStride; + dest += destinationStride; + } +} + +/* -------------------------------------------------------------------------- */ + +static void Copy_24_To_24( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + unsigned char *src = (unsigned char*)sourceBuffer; + unsigned char *dest = (unsigned char*)destinationBuffer; + + (void) ditherGenerator; /* unused parameter */ + + while( count-- ) + { + dest[0] = src[0]; + dest[1] = src[1]; + dest[2] = src[2]; + + src += sourceStride * 3; + dest += destinationStride * 3; + } +} + +/* -------------------------------------------------------------------------- */ + +static void Copy_32_To_32( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + PaUint32 *dest = (PaUint32 *)destinationBuffer; + PaUint32 *src = (PaUint32 *)sourceBuffer; + + (void) ditherGenerator; /* unused parameter */ + + while( count-- ) + { + *dest = *src; + + src += sourceStride; + dest += destinationStride; + } +} + +/* -------------------------------------------------------------------------- */ + +PaUtilConverterTable paConverters = { + Float32_To_Int32, /* PaUtilConverter *Float32_To_Int32; */ + Float32_To_Int32_Dither, /* PaUtilConverter *Float32_To_Int32_Dither; */ + Float32_To_Int32_Clip, /* PaUtilConverter *Float32_To_Int32_Clip; */ + Float32_To_Int32_DitherClip, /* PaUtilConverter *Float32_To_Int32_DitherClip; */ + + Float32_To_Int24, /* PaUtilConverter *Float32_To_Int24; */ + Float32_To_Int24_Dither, /* PaUtilConverter *Float32_To_Int24_Dither; */ + Float32_To_Int24_Clip, /* PaUtilConverter *Float32_To_Int24_Clip; */ + Float32_To_Int24_DitherClip, /* PaUtilConverter *Float32_To_Int24_DitherClip; */ + + Float32_To_Int16, /* PaUtilConverter *Float32_To_Int16; */ + Float32_To_Int16_Dither, /* PaUtilConverter *Float32_To_Int16_Dither; */ + Float32_To_Int16_Clip, /* PaUtilConverter *Float32_To_Int16_Clip; */ + Float32_To_Int16_DitherClip, /* PaUtilConverter *Float32_To_Int16_DitherClip; */ + + Float32_To_Int8, /* PaUtilConverter *Float32_To_Int8; */ + Float32_To_Int8_Dither, /* PaUtilConverter *Float32_To_Int8_Dither; */ + Float32_To_Int8_Clip, /* PaUtilConverter *Float32_To_Int8_Clip; */ + Float32_To_Int8_DitherClip, /* PaUtilConverter *Float32_To_Int8_DitherClip; */ + + Float32_To_UInt8, /* PaUtilConverter *Float32_To_UInt8; */ + Float32_To_UInt8_Dither, /* PaUtilConverter *Float32_To_UInt8_Dither; */ + Float32_To_UInt8_Clip, /* PaUtilConverter *Float32_To_UInt8_Clip; */ + Float32_To_UInt8_DitherClip, /* PaUtilConverter *Float32_To_UInt8_DitherClip; */ + + Int32_To_Float32, /* PaUtilConverter *Int32_To_Float32; */ + Int32_To_Int24, /* PaUtilConverter *Int32_To_Int24; */ + Int32_To_Int24_Dither, /* PaUtilConverter *Int32_To_Int24_Dither; */ + Int32_To_Int16, /* PaUtilConverter *Int32_To_Int16; */ + Int32_To_Int16_Dither, /* PaUtilConverter *Int32_To_Int16_Dither; */ + Int32_To_Int8, /* PaUtilConverter *Int32_To_Int8; */ + Int32_To_Int8_Dither, /* PaUtilConverter *Int32_To_Int8_Dither; */ + Int32_To_UInt8, /* PaUtilConverter *Int32_To_UInt8; */ + Int32_To_UInt8_Dither, /* PaUtilConverter *Int32_To_UInt8_Dither; */ + + Int24_To_Float32, /* PaUtilConverter *Int24_To_Float32; */ + Int24_To_Int32, /* PaUtilConverter *Int24_To_Int32; */ + Int24_To_Int16, /* PaUtilConverter *Int24_To_Int16; */ + Int24_To_Int16_Dither, /* PaUtilConverter *Int24_To_Int16_Dither; */ + Int24_To_Int8, /* PaUtilConverter *Int24_To_Int8; */ + Int24_To_Int8_Dither, /* PaUtilConverter *Int24_To_Int8_Dither; */ + Int24_To_UInt8, /* PaUtilConverter *Int24_To_UInt8; */ + Int24_To_UInt8_Dither, /* PaUtilConverter *Int24_To_UInt8_Dither; */ + + Int16_To_Float32, /* PaUtilConverter *Int16_To_Float32; */ + Int16_To_Int32, /* PaUtilConverter *Int16_To_Int32; */ + Int16_To_Int24, /* PaUtilConverter *Int16_To_Int24; */ + Int16_To_Int8, /* PaUtilConverter *Int16_To_Int8; */ + Int16_To_Int8_Dither, /* PaUtilConverter *Int16_To_Int8_Dither; */ + Int16_To_UInt8, /* PaUtilConverter *Int16_To_UInt8; */ + Int16_To_UInt8_Dither, /* PaUtilConverter *Int16_To_UInt8_Dither; */ + + Int8_To_Float32, /* PaUtilConverter *Int8_To_Float32; */ + Int8_To_Int32, /* PaUtilConverter *Int8_To_Int32; */ + Int8_To_Int24, /* PaUtilConverter *Int8_To_Int24 */ + Int8_To_Int16, /* PaUtilConverter *Int8_To_Int16; */ + Int8_To_UInt8, /* PaUtilConverter *Int8_To_UInt8; */ + + UInt8_To_Float32, /* PaUtilConverter *UInt8_To_Float32; */ + UInt8_To_Int32, /* PaUtilConverter *UInt8_To_Int32; */ + UInt8_To_Int24, /* PaUtilConverter *UInt8_To_Int24; */ + UInt8_To_Int16, /* PaUtilConverter *UInt8_To_Int16; */ + UInt8_To_Int8, /* PaUtilConverter *UInt8_To_Int8; */ + + Copy_8_To_8, /* PaUtilConverter *Copy_8_To_8; */ + Copy_16_To_16, /* PaUtilConverter *Copy_16_To_16; */ + Copy_24_To_24, /* PaUtilConverter *Copy_24_To_24; */ + Copy_32_To_32 /* PaUtilConverter *Copy_32_To_32; */ +}; + +/* -------------------------------------------------------------------------- */ + +#endif /* PA_NO_STANDARD_CONVERTERS */ + +/* -------------------------------------------------------------------------- */ + +PaUtilZeroer* PaUtil_SelectZeroer( PaSampleFormat destinationFormat ) +{ + switch( destinationFormat & ~paNonInterleaved ){ + case paFloat32: + return paZeroers.Zero32; + case paInt32: + return paZeroers.Zero32; + case paInt24: + return paZeroers.Zero24; + case paInt16: + return paZeroers.Zero16; + case paInt8: + return paZeroers.Zero8; + case paUInt8: + return paZeroers.ZeroU8; + default: return 0; + } +} + +/* -------------------------------------------------------------------------- */ + +#ifdef PA_NO_STANDARD_ZEROERS + +/* -------------------------------------------------------------------------- */ + +PaUtilZeroerTable paZeroers = { + 0, /* PaUtilZeroer *ZeroU8; */ + 0, /* PaUtilZeroer *Zero8; */ + 0, /* PaUtilZeroer *Zero16; */ + 0, /* PaUtilZeroer *Zero24; */ + 0, /* PaUtilZeroer *Zero32; */ +}; + +/* -------------------------------------------------------------------------- */ + +#else /* PA_NO_STANDARD_ZEROERS is not defined */ + +/* -------------------------------------------------------------------------- */ + +static void ZeroU8( void *destinationBuffer, signed int destinationStride, + unsigned int count ) +{ + unsigned char *dest = (unsigned char*)destinationBuffer; + + while( count-- ) + { + *dest = 128; + + dest += destinationStride; + } +} + +/* -------------------------------------------------------------------------- */ + +static void Zero8( void *destinationBuffer, signed int destinationStride, + unsigned int count ) +{ + unsigned char *dest = (unsigned char*)destinationBuffer; + + while( count-- ) + { + *dest = 0; + + dest += destinationStride; + } +} + +/* -------------------------------------------------------------------------- */ + +static void Zero16( void *destinationBuffer, signed int destinationStride, + unsigned int count ) +{ + PaUint16 *dest = (PaUint16 *)destinationBuffer; + + while( count-- ) + { + *dest = 0; + + dest += destinationStride; + } +} + +/* -------------------------------------------------------------------------- */ + +static void Zero24( void *destinationBuffer, signed int destinationStride, + unsigned int count ) +{ + unsigned char *dest = (unsigned char*)destinationBuffer; + + while( count-- ) + { + dest[0] = 0; + dest[1] = 0; + dest[2] = 0; + + dest += destinationStride * 3; + } +} + +/* -------------------------------------------------------------------------- */ + +static void Zero32( void *destinationBuffer, signed int destinationStride, + unsigned int count ) +{ + PaUint32 *dest = (PaUint32 *)destinationBuffer; + + while( count-- ) + { + *dest = 0; + + dest += destinationStride; + } +} + +/* -------------------------------------------------------------------------- */ + +PaUtilZeroerTable paZeroers = { + ZeroU8, /* PaUtilZeroer *ZeroU8; */ + Zero8, /* PaUtilZeroer *Zero8; */ + Zero16, /* PaUtilZeroer *Zero16; */ + Zero24, /* PaUtilZeroer *Zero24; */ + Zero32, /* PaUtilZeroer *Zero32; */ +}; + +/* -------------------------------------------------------------------------- */ + +#endif /* PA_NO_STANDARD_ZEROERS */ diff --git a/extern/portaudio/src/common/pa_converters.h b/extern/portaudio/src/common/pa_converters.h new file mode 100644 index 0000000..469f075 --- /dev/null +++ b/extern/portaudio/src/common/pa_converters.h @@ -0,0 +1,263 @@ +#ifndef PA_CONVERTERS_H +#define PA_CONVERTERS_H +/* + * $Id$ + * Portable Audio I/O Library sample conversion mechanism + * + * Based on the Open Source API proposed by Ross Bencina + * Copyright (c) 1999-2002 Phil Burk, Ross Bencina + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +/** @file + @ingroup common_src + + @brief Conversion functions used to convert buffers of samples from one + format to another. +*/ + + +#include "portaudio.h" /* for PaSampleFormat */ + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + +struct PaUtilTriangularDitherGenerator; + + +/** Choose an available sample format which is most appropriate for + representing the requested format. If the requested format is not available + higher quality formats are considered before lower quality formates. + @param availableFormats A variable containing the logical OR of all available + formats. + @param format The desired format. + @return The most appropriate available format for representing the requested + format. +*/ +PaSampleFormat PaUtil_SelectClosestAvailableFormat( + PaSampleFormat availableFormats, PaSampleFormat format ); + + +/* high level conversions functions for use by implementations */ + + +/** The generic sample converter prototype. Sample converters convert count + samples from sourceBuffer to destinationBuffer. The actual type of the data + pointed to by these parameters varys for different converter functions. + @param destinationBuffer A pointer to the first sample of the destination. + @param destinationStride An offset between successive destination samples + expressed in samples (not bytes.) It may be negative. + @param sourceBuffer A pointer to the first sample of the source. + @param sourceStride An offset between successive source samples + expressed in samples (not bytes.) It may be negative. + @param count The number of samples to convert. + @param ditherState State information used to calculate dither. Converters + that do not perform dithering will ignore this parameter, in which case + NULL or invalid dither state may be passed. +*/ +typedef void PaUtilConverter( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ); + + +/** Find a sample converter function for the given source and destinations + formats and flags (clip and dither.) + @return + A pointer to a PaUtilConverter which will perform the requested + conversion, or NULL if the given format conversion is not supported. + For conversions where clipping or dithering is not necessary, the + clip and dither flags are ignored and a non-clipping or dithering + version is returned. + If the source and destination formats are the same, a function which + copies data of the appropriate size will be returned. +*/ +PaUtilConverter* PaUtil_SelectConverter( PaSampleFormat sourceFormat, + PaSampleFormat destinationFormat, PaStreamFlags flags ); + + +/** The generic buffer zeroer prototype. Buffer zeroers copy count zeros to + destinationBuffer. The actual type of the data pointed to varys for + different zeroer functions. + @param destinationBuffer A pointer to the first sample of the destination. + @param destinationStride An offset between successive destination samples + expressed in samples (not bytes.) It may be negative. + @param count The number of samples to zero. +*/ +typedef void PaUtilZeroer( + void *destinationBuffer, signed int destinationStride, unsigned int count ); + + +/** Find a buffer zeroer function for the given destination format. + @return + A pointer to a PaUtilZeroer which will perform the requested + zeroing. +*/ +PaUtilZeroer* PaUtil_SelectZeroer( PaSampleFormat destinationFormat ); + +/*----------------------------------------------------------------------------*/ +/* low level functions and data structures which may be used for + substituting conversion functions */ + + +/** The type used to store all sample conversion functions. + @see paConverters; +*/ +typedef struct{ + PaUtilConverter *Float32_To_Int32; + PaUtilConverter *Float32_To_Int32_Dither; + PaUtilConverter *Float32_To_Int32_Clip; + PaUtilConverter *Float32_To_Int32_DitherClip; + + PaUtilConverter *Float32_To_Int24; + PaUtilConverter *Float32_To_Int24_Dither; + PaUtilConverter *Float32_To_Int24_Clip; + PaUtilConverter *Float32_To_Int24_DitherClip; + + PaUtilConverter *Float32_To_Int16; + PaUtilConverter *Float32_To_Int16_Dither; + PaUtilConverter *Float32_To_Int16_Clip; + PaUtilConverter *Float32_To_Int16_DitherClip; + + PaUtilConverter *Float32_To_Int8; + PaUtilConverter *Float32_To_Int8_Dither; + PaUtilConverter *Float32_To_Int8_Clip; + PaUtilConverter *Float32_To_Int8_DitherClip; + + PaUtilConverter *Float32_To_UInt8; + PaUtilConverter *Float32_To_UInt8_Dither; + PaUtilConverter *Float32_To_UInt8_Clip; + PaUtilConverter *Float32_To_UInt8_DitherClip; + + PaUtilConverter *Int32_To_Float32; + PaUtilConverter *Int32_To_Int24; + PaUtilConverter *Int32_To_Int24_Dither; + PaUtilConverter *Int32_To_Int16; + PaUtilConverter *Int32_To_Int16_Dither; + PaUtilConverter *Int32_To_Int8; + PaUtilConverter *Int32_To_Int8_Dither; + PaUtilConverter *Int32_To_UInt8; + PaUtilConverter *Int32_To_UInt8_Dither; + + PaUtilConverter *Int24_To_Float32; + PaUtilConverter *Int24_To_Int32; + PaUtilConverter *Int24_To_Int16; + PaUtilConverter *Int24_To_Int16_Dither; + PaUtilConverter *Int24_To_Int8; + PaUtilConverter *Int24_To_Int8_Dither; + PaUtilConverter *Int24_To_UInt8; + PaUtilConverter *Int24_To_UInt8_Dither; + + PaUtilConverter *Int16_To_Float32; + PaUtilConverter *Int16_To_Int32; + PaUtilConverter *Int16_To_Int24; + PaUtilConverter *Int16_To_Int8; + PaUtilConverter *Int16_To_Int8_Dither; + PaUtilConverter *Int16_To_UInt8; + PaUtilConverter *Int16_To_UInt8_Dither; + + PaUtilConverter *Int8_To_Float32; + PaUtilConverter *Int8_To_Int32; + PaUtilConverter *Int8_To_Int24; + PaUtilConverter *Int8_To_Int16; + PaUtilConverter *Int8_To_UInt8; + + PaUtilConverter *UInt8_To_Float32; + PaUtilConverter *UInt8_To_Int32; + PaUtilConverter *UInt8_To_Int24; + PaUtilConverter *UInt8_To_Int16; + PaUtilConverter *UInt8_To_Int8; + + PaUtilConverter *Copy_8_To_8; /* copy without any conversion */ + PaUtilConverter *Copy_16_To_16; /* copy without any conversion */ + PaUtilConverter *Copy_24_To_24; /* copy without any conversion */ + PaUtilConverter *Copy_32_To_32; /* copy without any conversion */ +} PaUtilConverterTable; + + +/** A table of pointers to all required converter functions. + PaUtil_SelectConverter() uses this table to lookup the appropriate + conversion functions. The fields of this structure are initialized + with default conversion functions. Fields may be NULL, indicating that + no conversion function is available. User code may substitue optimised + conversion functions by assigning different function pointers to + these fields. + + @note + If the PA_NO_STANDARD_CONVERTERS preprocessor variable is defined, + PortAudio's standard converters will not be compiled, and all fields + of this structure will be initialized to NULL. In such cases, users + should supply their own conversion functions if the require PortAudio + to open a stream that requires sample conversion. + + @see PaUtilConverterTable, PaUtilConverter, PaUtil_SelectConverter +*/ +extern PaUtilConverterTable paConverters; + + +/** The type used to store all buffer zeroing functions. + @see paZeroers; +*/ +typedef struct{ + PaUtilZeroer *ZeroU8; /* unsigned 8 bit, zero == 128 */ + PaUtilZeroer *Zero8; + PaUtilZeroer *Zero16; + PaUtilZeroer *Zero24; + PaUtilZeroer *Zero32; +} PaUtilZeroerTable; + + +/** A table of pointers to all required zeroer functions. + PaUtil_SelectZeroer() uses this table to lookup the appropriate + conversion functions. The fields of this structure are initialized + with default conversion functions. User code may substitue optimised + conversion functions by assigning different function pointers to + these fields. + + @note + If the PA_NO_STANDARD_ZEROERS preprocessor variable is defined, + PortAudio's standard zeroers will not be compiled, and all fields + of this structure will be initialized to NULL. In such cases, users + should supply their own zeroing functions for the sample sizes which + they intend to use. + + @see PaUtilZeroerTable, PaUtilZeroer, PaUtil_SelectZeroer +*/ +extern PaUtilZeroerTable paZeroers; + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* PA_CONVERTERS_H */ diff --git a/extern/portaudio/src/common/pa_cpuload.c b/extern/portaudio/src/common/pa_cpuload.c new file mode 100644 index 0000000..4adf21a --- /dev/null +++ b/extern/portaudio/src/common/pa_cpuload.c @@ -0,0 +1,105 @@ +/* + * $Id$ + * Portable Audio I/O Library CPU Load measurement functions + * Portable CPU load measurement facility. + * + * Based on the Open Source API proposed by Ross Bencina + * Copyright (c) 2002 Ross Bencina + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +/** @file + @ingroup common_src + + @brief Functions to assist in measuring the CPU utilization of a callback + stream. Used to implement the Pa_GetStreamCpuLoad() function. + + @todo Dynamically calculate the coefficients used to smooth the CPU Load + Measurements over time to provide a uniform characterisation of CPU Load + independent of rate at which PaUtil_BeginCpuLoadMeasurement / + PaUtil_EndCpuLoadMeasurement are called. see http://www.portaudio.com/trac/ticket/113 +*/ + + +#include "pa_cpuload.h" + +#include + +#include "pa_util.h" /* for PaUtil_GetTime() */ + + +void PaUtil_InitializeCpuLoadMeasurer( PaUtilCpuLoadMeasurer* measurer, double sampleRate ) +{ + assert( sampleRate > 0 ); + + measurer->samplingPeriod = 1. / sampleRate; + measurer->averageLoad = 0.; +} + +void PaUtil_ResetCpuLoadMeasurer( PaUtilCpuLoadMeasurer* measurer ) +{ + measurer->averageLoad = 0.; +} + +void PaUtil_BeginCpuLoadMeasurement( PaUtilCpuLoadMeasurer* measurer ) +{ + measurer->measurementStartTime = PaUtil_GetTime(); +} + + +void PaUtil_EndCpuLoadMeasurement( PaUtilCpuLoadMeasurer* measurer, unsigned long framesProcessed ) +{ + double measurementEndTime, secondsFor100Percent, measuredLoad; + + if( framesProcessed > 0 ){ + measurementEndTime = PaUtil_GetTime(); + + assert( framesProcessed > 0 ); + secondsFor100Percent = framesProcessed * measurer->samplingPeriod; + + measuredLoad = (measurementEndTime - measurer->measurementStartTime) / secondsFor100Percent; + + /* Low pass filter the calculated CPU load to reduce jitter using a simple IIR low pass filter. */ + /** FIXME @todo these coefficients shouldn't be hardwired see: http://www.portaudio.com/trac/ticket/113 */ +#define LOWPASS_COEFFICIENT_0 (0.9) +#define LOWPASS_COEFFICIENT_1 (0.99999 - LOWPASS_COEFFICIENT_0) + + measurer->averageLoad = (LOWPASS_COEFFICIENT_0 * measurer->averageLoad) + + (LOWPASS_COEFFICIENT_1 * measuredLoad); + } +} + + +double PaUtil_GetCpuLoad( PaUtilCpuLoadMeasurer* measurer ) +{ + return measurer->averageLoad; +} diff --git a/extern/portaudio/src/common/pa_cpuload.h b/extern/portaudio/src/common/pa_cpuload.h new file mode 100644 index 0000000..2a323aa --- /dev/null +++ b/extern/portaudio/src/common/pa_cpuload.h @@ -0,0 +1,72 @@ +#ifndef PA_CPULOAD_H +#define PA_CPULOAD_H +/* + * $Id$ + * Portable Audio I/O Library CPU Load measurement functions + * Portable CPU load measurement facility. + * + * Based on the Open Source API proposed by Ross Bencina + * Copyright (c) 2002 Ross Bencina + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +/** @file + @ingroup common_src + + @brief Functions to assist in measuring the CPU utilization of a callback + stream. Used to implement the Pa_GetStreamCpuLoad() function. +*/ + + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + +typedef struct { + double samplingPeriod; + double measurementStartTime; + double averageLoad; +} PaUtilCpuLoadMeasurer; /**< @todo need better name than measurer */ + +void PaUtil_InitializeCpuLoadMeasurer( PaUtilCpuLoadMeasurer* measurer, double sampleRate ); +void PaUtil_BeginCpuLoadMeasurement( PaUtilCpuLoadMeasurer* measurer ); +void PaUtil_EndCpuLoadMeasurement( PaUtilCpuLoadMeasurer* measurer, unsigned long framesProcessed ); +void PaUtil_ResetCpuLoadMeasurer( PaUtilCpuLoadMeasurer* measurer ); +double PaUtil_GetCpuLoad( PaUtilCpuLoadMeasurer* measurer ); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* PA_CPULOAD_H */ diff --git a/extern/portaudio/src/common/pa_debugprint.c b/extern/portaudio/src/common/pa_debugprint.c new file mode 100644 index 0000000..f34d4bb --- /dev/null +++ b/extern/portaudio/src/common/pa_debugprint.c @@ -0,0 +1,123 @@ +/* + * $Id: pa_log.c $ + * Portable Audio I/O Library Multi-Host API front end + * Validate function parameters and manage multiple host APIs. + * + * Based on the Open Source API proposed by Ross Bencina + * Copyright (c) 1999-2006 Ross Bencina, Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +/** @file + @ingroup common_src + + @brief Implements log function. + + PaUtil_SetLogPrintFunction can be user called to replace the provided + DefaultLogPrint function, which writes to stderr. + One can NOT pass var_args across compiler/dll boundaries as it is not + "byte code/abi portable". So the technique used here is to allocate a local + a static array, write in it, then callback the user with a pointer to its + start. +*/ + +#include +#include + +#include "pa_debugprint.h" + +// for OutputDebugStringA +#if defined(_MSC_VER) && defined(PA_ENABLE_MSVC_DEBUG_OUTPUT) + #define WIN32_LEAN_AND_MEAN // exclude rare headers + #include "windows.h" +#endif + +// User callback +static PaUtilLogCallback userCB = NULL; + +// Sets user callback +void PaUtil_SetDebugPrintFunction(PaUtilLogCallback cb) +{ + userCB = cb; +} + +/* + If your platform doesn’t have vsnprintf, you are stuck with a + VERY dangerous alternative, vsprintf (with no n) +*/ +#if _MSC_VER + /* Some Windows Mobile SDKs don't define vsnprintf but all define _vsnprintf (hopefully). + According to MSDN "vsnprintf is identical to _vsnprintf". So we use _vsnprintf with MSC. + */ + #define VSNPRINTF _vsnprintf +#else + #define VSNPRINTF vsnprintf +#endif + +#define PA_LOG_BUF_SIZE 2048 + +void PaUtil_DebugPrint( const char *format, ... ) +{ + // Optional logging into Output console of Visual Studio +#if defined(_MSC_VER) && defined(PA_ENABLE_MSVC_DEBUG_OUTPUT) + { + char buf[PA_LOG_BUF_SIZE]; + va_list ap; + va_start(ap, format); + VSNPRINTF(buf, sizeof(buf), format, ap); + buf[sizeof(buf)-1] = 0; + OutputDebugStringA(buf); + va_end(ap); + } +#endif + + // Output to User-Callback + if (userCB != NULL) + { + char strdump[PA_LOG_BUF_SIZE]; + va_list ap; + va_start(ap, format); + VSNPRINTF(strdump, sizeof(strdump), format, ap); + strdump[sizeof(strdump)-1] = 0; + userCB(strdump); + va_end(ap); + } + else + // Standard output to stderr + { + va_list ap; + va_start(ap, format); + vfprintf(stderr, format, ap); + va_end(ap); + fflush(stderr); + } +} diff --git a/extern/portaudio/src/common/pa_debugprint.h b/extern/portaudio/src/common/pa_debugprint.h new file mode 100644 index 0000000..5fba766 --- /dev/null +++ b/extern/portaudio/src/common/pa_debugprint.h @@ -0,0 +1,149 @@ +#ifndef PA_LOG_H +#define PA_LOG_H +/* + * Log file redirector function + * Copyright (c) 1999-2006 Ross Bencina, Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +/** @file + @ingroup common_src +*/ + + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + + +void PaUtil_DebugPrint( const char *format, ... ); + + +/* + The basic format for log messages is described below. If you need to + add any log messages, please follow this format. + + Function entry (void function): + + "FunctionName called.\n" + + Function entry (non void function): + + "FunctionName called:\n" + "\tParam1Type param1: param1Value\n" + "\tParam2Type param2: param2Value\n" (etc...) + + + Function exit (no return value): + + "FunctionName returned.\n" + + Function exit (simple return value): + + "FunctionName returned:\n" + "\tReturnType: returnValue\n" + + If the return type is an error code, the error text is displayed in () + + If the return type is not an error code, but has taken a special value + because an error occurred, then the reason for the error is shown in [] + + If the return type is a struct ptr, the struct is dumped. + + See the code below for examples +*/ + +/** PA_DEBUG() provides a simple debug message printing facility. The macro + passes it's argument to a printf-like function called PaUtil_DebugPrint() + which prints to stderr and always flushes the stream after printing. + Because preprocessor macros cannot directly accept variable length argument + lists, calls to the macro must include an additional set of parenthesis, eg: + PA_DEBUG(("errorno: %d", 1001 )); +*/ + + +#ifdef PA_ENABLE_DEBUG_OUTPUT +#define PA_DEBUG(x) PaUtil_DebugPrint x ; +#else +#define PA_DEBUG(x) +#endif + + +#ifdef PA_LOG_API_CALLS +#define PA_LOGAPI(x) PaUtil_DebugPrint x + +#define PA_LOGAPI_ENTER(functionName) PaUtil_DebugPrint( functionName " called.\n" ) + +#define PA_LOGAPI_ENTER_PARAMS(functionName) PaUtil_DebugPrint( functionName " called:\n" ) + +#define PA_LOGAPI_EXIT(functionName) PaUtil_DebugPrint( functionName " returned.\n" ) + +#define PA_LOGAPI_EXIT_PAERROR( functionName, result ) \ + PaUtil_DebugPrint( functionName " returned:\n" ); \ + PaUtil_DebugPrint("\tPaError: %d ( %s )\n", result, Pa_GetErrorText( result ) ) + +#define PA_LOGAPI_EXIT_T( functionName, resultFormatString, result ) \ + PaUtil_DebugPrint( functionName " returned:\n" ); \ + PaUtil_DebugPrint("\t" resultFormatString "\n", result ) + +#define PA_LOGAPI_EXIT_PAERROR_OR_T_RESULT( functionName, positiveResultFormatString, result ) \ + PaUtil_DebugPrint( functionName " returned:\n" ); \ + if( result > 0 ) \ + PaUtil_DebugPrint("\t" positiveResultFormatString "\n", result ); \ + else \ + PaUtil_DebugPrint("\tPaError: %d ( %s )\n", result, Pa_GetErrorText( result ) ) +#else +#define PA_LOGAPI(x) +#define PA_LOGAPI_ENTER(functionName) +#define PA_LOGAPI_ENTER_PARAMS(functionName) +#define PA_LOGAPI_EXIT(functionName) +#define PA_LOGAPI_EXIT_PAERROR( functionName, result ) +#define PA_LOGAPI_EXIT_T( functionName, resultFormatString, result ) +#define PA_LOGAPI_EXIT_PAERROR_OR_T_RESULT( functionName, positiveResultFormatString, result ) +#endif + + +typedef void (*PaUtilLogCallback ) (const char *log); + +/** + Install user provided log function +*/ +void PaUtil_SetDebugPrintFunction(PaUtilLogCallback cb); + + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* PA_LOG_H */ diff --git a/extern/portaudio/src/common/pa_dither.c b/extern/portaudio/src/common/pa_dither.c new file mode 100644 index 0000000..140e480 --- /dev/null +++ b/extern/portaudio/src/common/pa_dither.c @@ -0,0 +1,218 @@ +/* + * $Id$ + * Portable Audio I/O Library triangular dither generator + * + * Based on the Open Source API proposed by Ross Bencina + * Copyright (c) 1999-2002 Phil Burk, Ross Bencina + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +/** @file + @ingroup common_src + + @brief Functions for generating dither noise +*/ + +#include "pa_types.h" +#include "pa_dither.h" + + +/* Note that the linear congruential algorithm requires 32 bit integers + * because it uses arithmetic overflow. So use PaUint32 instead of + * unsigned long so it will work on 64 bit systems. + */ + +#define PA_DITHER_BITS_ (15) + + +void PaUtil_InitializeTriangularDitherState( PaUtilTriangularDitherGenerator *state ) +{ + state->previous = 0; + state->randSeed1 = 22222; + state->randSeed2 = 5555555; +} + + +PaInt32 PaUtil_Generate16BitTriangularDither( PaUtilTriangularDitherGenerator *state ) +{ + PaInt32 current, highPass; + + /* Generate two random numbers. */ + state->randSeed1 = (state->randSeed1 * 196314165) + 907633515; + state->randSeed2 = (state->randSeed2 * 196314165) + 907633515; + + /* Generate triangular distribution about 0. + * Shift before adding to prevent overflow which would skew the distribution. + * Also shift an extra bit for the high pass filter. + */ +#define DITHER_SHIFT_ ((sizeof(PaInt32)*8 - PA_DITHER_BITS_) + 1) + + current = (((PaInt32)state->randSeed1)>>DITHER_SHIFT_) + + (((PaInt32)state->randSeed2)>>DITHER_SHIFT_); + + /* High pass filter to reduce audibility. */ + highPass = current - state->previous; + state->previous = current; + return highPass; +} + + +/* Multiply by PA_FLOAT_DITHER_SCALE_ to get a float between -2.0 and +1.99999 */ +#define PA_FLOAT_DITHER_SCALE_ (1.0f / ((1<randSeed1 = (state->randSeed1 * 196314165) + 907633515; + state->randSeed2 = (state->randSeed2 * 196314165) + 907633515; + + /* Generate triangular distribution about 0. + * Shift before adding to prevent overflow which would skew the distribution. + * Also shift an extra bit for the high pass filter. + */ + current = (((PaInt32)state->randSeed1)>>DITHER_SHIFT_) + + (((PaInt32)state->randSeed2)>>DITHER_SHIFT_); + + /* High pass filter to reduce audibility. */ + highPass = current - state->previous; + state->previous = current; + return ((float)highPass) * const_float_dither_scale_; +} + + +/* +The following alternate dither algorithms (from musicdsp.org) could be +considered +*/ + +/*Noise shaped dither (March 2000) +------------------- + +This is a simple implementation of highpass triangular-PDF dither with +2nd-order noise shaping, for use when truncating floating point audio +data to fixed point. + +The noise shaping lowers the noise floor by 11dB below 5kHz (@ 44100Hz +sample rate) compared to triangular-PDF dither. The code below assumes +input data is in the range +1 to -1 and doesn't check for overloads! + +To save time when generating dither for multiple channels you can do +things like this: r3=(r1 & 0x7F)<<8; instead of calling rand() again. + + + + int r1, r2; //rectangular-PDF random numbers + float s1, s2; //error feedback buffers + float s = 0.5f; //set to 0.0f for no noise shaping + float w = pow(2.0,bits-1); //word length (usually bits=16) + float wi= 1.0f/w; + float d = wi / RAND_MAX; //dither amplitude (2 lsb) + float o = wi * 0.5f; //remove dc offset + float in, tmp; + int out; + + +//for each sample... + + r2=r1; //can make HP-TRI dither by + r1=rand(); //subtracting previous rand() + + in += s * (s1 + s1 - s2); //error feedback + tmp = in + o + d * (float)(r1 - r2); //dc offset and dither + + out = (int)(w * tmp); //truncate downwards + if(tmp<0.0f) out--; //this is faster than floor() + + s2 = s1; + s1 = in - wi * (float)out; //error + + + +-- +paul.kellett@maxim.abel.co.uk +http://www.maxim.abel.co.uk +*/ + + +/* +16-to-8-bit first-order dither + +Type : First order error feedforward dithering code +References : Posted by Jon Watte + +Notes : +This is about as simple a dithering algorithm as you can implement, but it's +likely to sound better than just truncating to N bits. + +Note that you might not want to carry forward the full difference for infinity. +It's probably likely that the worst performance hit comes from the saturation +conditionals, which can be avoided with appropriate instructions on many DSPs +and integer SIMD type instructions, or CMOV. + +Last, if sound quality is paramount (such as when going from > 16 bits to 16 +bits) you probably want to use a higher-order dither function found elsewhere +on this site. + + +Code : +// This code will down-convert and dither a 16-bit signed short +// mono signal into an 8-bit unsigned char signal, using a first +// order forward-feeding error term dither. + +#define uchar unsigned char + +void dither_one_channel_16_to_8( short * input, uchar * output, int count, int * memory ) +{ + int m = *memory; + while( count-- > 0 ) { + int i = *input++; + i += m; + int j = i + 32768 - 128; + uchar o; + if( j < 0 ) { + o = 0; + } + else if( j > 65535 ) { + o = 255; + } + else { + o = (uchar)((j>>8)&0xff); + } + m = ((j-32768+128)-i); + *output++ = o; + } + *memory = m; +} +*/ diff --git a/extern/portaudio/src/common/pa_dither.h b/extern/portaudio/src/common/pa_dither.h new file mode 100644 index 0000000..12ffc4f --- /dev/null +++ b/extern/portaudio/src/common/pa_dither.h @@ -0,0 +1,106 @@ +#ifndef PA_DITHER_H +#define PA_DITHER_H +/* + * $Id$ + * Portable Audio I/O Library triangular dither generator + * + * Based on the Open Source API proposed by Ross Bencina + * Copyright (c) 1999-2002 Phil Burk, Ross Bencina + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +/** @file + @ingroup common_src + + @brief Functions for generating dither noise +*/ + +#include "pa_types.h" + + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +/* Note that the linear congruential algorithm requires 32 bit integers + * because it uses arithmetic overflow. So use PaUint32 instead of + * unsigned long so it will work on 64 bit systems. + */ + +/** @brief State needed to generate a dither signal */ +typedef struct PaUtilTriangularDitherGenerator{ + PaUint32 previous; + PaUint32 randSeed1; + PaUint32 randSeed2; +} PaUtilTriangularDitherGenerator; + + +/** @brief Initialize dither state */ +void PaUtil_InitializeTriangularDitherState( PaUtilTriangularDitherGenerator *ditherState ); + + +/** + @brief Calculate 2 LSB dither signal with a triangular distribution. + Ranged for adding to a 1 bit right-shifted 32 bit integer + prior to >>15. eg: +
    +    signed long in = *
    +    signed long dither = PaUtil_Generate16BitTriangularDither( ditherState );
    +    signed short out = (signed short)(((in>>1) + dither) >> 15);
    +
    + @return + A signed 32-bit integer with a range of +32767 to -32768 +*/ +PaInt32 PaUtil_Generate16BitTriangularDither( PaUtilTriangularDitherGenerator *ditherState ); + + +/** + @brief Calculate 2 LSB dither signal with a triangular distribution. + Ranged for adding to a pre-scaled float. +
    +    float in = *
    +    float dither = PaUtil_GenerateFloatTriangularDither( ditherState );
    +    // use smaller scaler to prevent overflow when we add the dither
    +    signed short out = (signed short)(in*(32766.0f) + dither );
    +
    + @return + A float with a range of -2.0 to +1.99999. +*/ +float PaUtil_GenerateFloatTriangularDither( PaUtilTriangularDitherGenerator *ditherState ); + + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* PA_DITHER_H */ diff --git a/extern/portaudio/src/common/pa_endianness.h b/extern/portaudio/src/common/pa_endianness.h new file mode 100644 index 0000000..9e8e059 --- /dev/null +++ b/extern/portaudio/src/common/pa_endianness.h @@ -0,0 +1,145 @@ +#ifndef PA_ENDIANNESS_H +#define PA_ENDIANNESS_H +/* + * $Id$ + * Portable Audio I/O Library current platform endianness macros + * + * Based on the Open Source API proposed by Ross Bencina + * Copyright (c) 1999-2002 Phil Burk, Ross Bencina + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +/** @file + @ingroup common_src + + @brief Configure endianness symbols for the target processor. + + Arrange for either the PA_LITTLE_ENDIAN or PA_BIG_ENDIAN preprocessor symbols + to be defined. The one that is defined reflects the endianness of the target + platform and may be used to implement conditional compilation of byte-order + dependent code. + + If either PA_LITTLE_ENDIAN or PA_BIG_ENDIAN is defined already, then no attempt + is made to override that setting. This may be useful if you have a better way + of determining the platform's endianness. The autoconf mechanism uses this for + example. + + A PA_VALIDATE_ENDIANNESS macro is provided to compare the compile time + and runtime endiannes and raise an assertion if they don't match. +*/ + + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +/* If this is an apple, we need to do detect endianness this way */ +#if defined(__APPLE__) + /* we need to do some endian detection that is sensitive to harware arch */ + #if defined(__LITTLE_ENDIAN__) + #if !defined( PA_LITTLE_ENDIAN ) + #define PA_LITTLE_ENDIAN + #endif + #if defined( PA_BIG_ENDIAN ) + #undef PA_BIG_ENDIAN + #endif + #else + #if !defined( PA_BIG_ENDIAN ) + #define PA_BIG_ENDIAN + #endif + #if defined( PA_LITTLE_ENDIAN ) + #undef PA_LITTLE_ENDIAN + #endif + #endif +#else + /* this is not an apple, so first check the existing defines, and, failing that, + detect well-known architechtures. */ + + #if defined(PA_LITTLE_ENDIAN) || defined(PA_BIG_ENDIAN) + /* endianness define has been set externally, such as by autoconf */ + + #if defined(PA_LITTLE_ENDIAN) && defined(PA_BIG_ENDIAN) + #error both PA_LITTLE_ENDIAN and PA_BIG_ENDIAN have been defined externally to pa_endianness.h - only one endianness at a time please + #endif + + #else + /* endianness define has not been set externally */ + + /* set PA_LITTLE_ENDIAN or PA_BIG_ENDIAN by testing well known platform specific defines */ + + #if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__) || defined(LITTLE_ENDIAN) || defined(__i386) || defined(_M_IX86) || defined(__x86_64__) + #define PA_LITTLE_ENDIAN /* win32, assume intel byte order */ + #else + #define PA_BIG_ENDIAN + #endif + #endif + + #if !defined(PA_LITTLE_ENDIAN) && !defined(PA_BIG_ENDIAN) + /* + If the following error is raised, you either need to modify the code above + to automatically determine the endianness from other symbols defined on your + platform, or define either PA_LITTLE_ENDIAN or PA_BIG_ENDIAN externally. + */ + #error pa_endianness.h was unable to automatically determine the endianness of the target platform + #endif + +#endif + + +/* PA_VALIDATE_ENDIANNESS compares the compile time and runtime endianness, + and raises an assertion if they don't match. must be included in + the context in which this macro is used. +*/ +#if defined(NDEBUG) + #define PA_VALIDATE_ENDIANNESS +#else + #if defined(PA_LITTLE_ENDIAN) + #define PA_VALIDATE_ENDIANNESS \ + { \ + const long nativeOne = 1; \ + assert( "PortAudio: compile time and runtime endianness don't match" && (((char *)&nativeOne)[0]) == 1 ); \ + } + #elif defined(PA_BIG_ENDIAN) + #define PA_VALIDATE_ENDIANNESS \ + { \ + const long nativeOne = 1; \ + assert( "PortAudio: compile time and runtime endianness don't match" && (((char *)&nativeOne)[0]) == 0 ); \ + } + #endif +#endif + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* PA_ENDIANNESS_H */ diff --git a/extern/portaudio/src/common/pa_front.c b/extern/portaudio/src/common/pa_front.c new file mode 100644 index 0000000..9d30f48 --- /dev/null +++ b/extern/portaudio/src/common/pa_front.c @@ -0,0 +1,1811 @@ +/* + * $Id$ + * Portable Audio I/O Library Multi-Host API front end + * Validate function parameters and manage multiple host APIs. + * + * Based on the Open Source API proposed by Ross Bencina + * Copyright (c) 1999-2008 Ross Bencina, Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +/** @file + @ingroup common_src + + @brief Implements PortAudio API functions defined in portaudio.h, checks + some errors, delegates platform-specific behavior to host API implementations. + + Implements the functions defined in the PortAudio API (portaudio.h), + validates some parameters and checks for state inconsistencies before + forwarding API requests to specific Host API implementations (via the + interface declared in pa_hostapi.h), and Streams (via the interface + declared in pa_stream.h). + + This file manages initialization and termination of Host API + implementations via initializer functions stored in the paHostApiInitializers + global array (usually defined in an os-specific pa_[os]_hostapis.c file). + + This file maintains a list of all open streams and closes them at Pa_Terminate(). + + Some utility functions declared in pa_util.h are implemented in this file. + + All PortAudio API functions can be conditionally compiled with logging code. + To compile with logging, define the PA_LOG_API_CALLS precompiler symbol. +*/ + + +#include +#include +#include +#include /* needed for strtol() */ +#include /* needed by PA_VALIDATE_ENDIANNESS */ + +#include "portaudio.h" +#include "pa_util.h" +#include "pa_endianness.h" +#include "pa_types.h" +#include "pa_hostapi.h" +#include "pa_stream.h" +#include "pa_trace.h" /* still usefull?*/ +#include "pa_debugprint.h" + +#ifndef PA_GIT_REVISION +#include "pa_gitrevision.h" +#endif + +/** + * This is incremented if we make incompatible API changes. + * This version scheme is based loosely on http://semver.org/ + */ +#define paVersionMajor 19 + +/** + * This is incremented when we add functionality in a backwards-compatible manner. + * Or it is set to zero when paVersionMajor is incremented. + */ +#define paVersionMinor 6 + +/** + * This is incremented when we make backwards-compatible bug fixes. + * Or it is set to zero when paVersionMinor changes. + */ +#define paVersionSubMinor 0 + +/** + * This is a combination of paVersionMajor, paVersionMinor and paVersionSubMinor. + * It will always increase so that version numbers can be compared as integers to + * see which is later. + */ +#define paVersion paMakeVersionNumber(paVersionMajor, paVersionMinor, paVersionSubMinor) + +#define STRINGIFY(x) #x +#define TOSTRING(x) STRINGIFY(x) + +#define PA_VERSION_STRING_ TOSTRING(paVersionMajor) "." TOSTRING(paVersionMinor) "." TOSTRING(paVersionSubMinor) +#define PA_VERSION_TEXT_ "PortAudio V" PA_VERSION_STRING_ "-devel, revision " TOSTRING(PA_GIT_REVISION) + +int Pa_GetVersion( void ) +{ + return paVersion; +} + +const char* Pa_GetVersionText( void ) +{ + return PA_VERSION_TEXT_; +} + +static PaVersionInfo versionInfo_ = { + /*.versionMajor =*/ paVersionMajor, + /*.versionMinor =*/ paVersionMinor, + /*.versionSubMinor =*/ paVersionSubMinor, + /*.versionControlRevision =*/ TOSTRING(PA_GIT_REVISION), + /*.versionText =*/ PA_VERSION_TEXT_ +}; + +const PaVersionInfo* Pa_GetVersionInfo( void ) +{ + return &versionInfo_; +} + +#define PA_LAST_HOST_ERROR_TEXT_LENGTH_ 1024 + +static char lastHostErrorText_[ PA_LAST_HOST_ERROR_TEXT_LENGTH_ + 1 ] = {0}; + +static PaHostErrorInfo lastHostErrorInfo_ = { (PaHostApiTypeId)-1, 0, lastHostErrorText_ }; + + +void PaUtil_SetLastHostErrorInfo( PaHostApiTypeId hostApiType, long errorCode, + const char *errorText ) +{ + lastHostErrorInfo_.hostApiType = hostApiType; + lastHostErrorInfo_.errorCode = errorCode; + + strncpy( lastHostErrorText_, errorText, PA_LAST_HOST_ERROR_TEXT_LENGTH_ ); +} + + + +static PaUtilHostApiRepresentation **hostApis_ = 0; +static int hostApisCount_ = 0; +static int defaultHostApiIndex_ = 0; +static int initializationCount_ = 0; +static int deviceCount_ = 0; + +PaUtilStreamRepresentation *firstOpenStream_ = NULL; + + +#define PA_IS_INITIALISED_ (initializationCount_ != 0) + + +static int CountHostApiInitializers( void ) +{ + int result = 0; + + while( paHostApiInitializers[ result ] != 0 ) + ++result; + return result; +} + + +static void TerminateHostApis( void ) +{ + /* terminate in reverse order from initialization */ + PA_DEBUG(("TerminateHostApis in \n")); + + while( hostApisCount_ > 0 ) + { + --hostApisCount_; + hostApis_[hostApisCount_]->Terminate( hostApis_[hostApisCount_] ); + } + hostApisCount_ = 0; + defaultHostApiIndex_ = 0; + deviceCount_ = 0; + + if( hostApis_ != 0 ) + PaUtil_FreeMemory( hostApis_ ); + hostApis_ = 0; + + PA_DEBUG(("TerminateHostApis out\n")); +} + + +static PaError InitializeHostApis( void ) +{ + PaError result = paNoError; + int i, initializerCount, baseDeviceIndex; + + initializerCount = CountHostApiInitializers(); + + hostApis_ = (PaUtilHostApiRepresentation**)PaUtil_AllocateMemory( + sizeof(PaUtilHostApiRepresentation*) * initializerCount ); + if( !hostApis_ ) + { + result = paInsufficientMemory; + goto error; + } + + hostApisCount_ = 0; + defaultHostApiIndex_ = -1; /* indicates that we haven't determined the default host API yet */ + deviceCount_ = 0; + baseDeviceIndex = 0; + + for( i=0; i< initializerCount; ++i ) + { + hostApis_[hostApisCount_] = NULL; + + PA_DEBUG(( "before paHostApiInitializers[%d].\n",i)); + + result = paHostApiInitializers[i]( &hostApis_[hostApisCount_], hostApisCount_ ); + if( result != paNoError ) + goto error; + + PA_DEBUG(( "after paHostApiInitializers[%d].\n",i)); + + if( hostApis_[hostApisCount_] ) + { + PaUtilHostApiRepresentation* hostApi = hostApis_[hostApisCount_]; + assert( hostApi->info.defaultInputDevice < hostApi->info.deviceCount ); + assert( hostApi->info.defaultOutputDevice < hostApi->info.deviceCount ); + + /* the first successfully initialized host API with a default input *or* + output device is used as the default host API. + */ + if( (defaultHostApiIndex_ == -1) && + ( hostApi->info.defaultInputDevice != paNoDevice + || hostApi->info.defaultOutputDevice != paNoDevice ) ) + { + defaultHostApiIndex_ = hostApisCount_; + } + + hostApi->privatePaFrontInfo.baseDeviceIndex = baseDeviceIndex; + + if( hostApi->info.defaultInputDevice != paNoDevice ) + hostApi->info.defaultInputDevice += baseDeviceIndex; + + if( hostApi->info.defaultOutputDevice != paNoDevice ) + hostApi->info.defaultOutputDevice += baseDeviceIndex; + + baseDeviceIndex += hostApi->info.deviceCount; + deviceCount_ += hostApi->info.deviceCount; + + ++hostApisCount_; + } + } + + /* if no host APIs have devices, the default host API is the first initialized host API */ + if( defaultHostApiIndex_ == -1 ) + defaultHostApiIndex_ = 0; + + return result; + +error: + TerminateHostApis(); + return result; +} + + +/* + FindHostApi() finds the index of the host api to which + belongs and returns it. if is + non-null, the host specific device index is returned in it. + returns -1 if is out of range. + +*/ +static int FindHostApi( PaDeviceIndex device, int *hostSpecificDeviceIndex ) +{ + int i=0; + + if( !PA_IS_INITIALISED_ ) + return -1; + + if( device < 0 ) + return -1; + + while( i < hostApisCount_ + && device >= hostApis_[i]->info.deviceCount ) + { + + device -= hostApis_[i]->info.deviceCount; + ++i; + } + + if( i >= hostApisCount_ ) + return -1; + + if( hostSpecificDeviceIndex ) + *hostSpecificDeviceIndex = device; + + return i; +} + + +static void AddOpenStream( PaStream* stream ) +{ + ((PaUtilStreamRepresentation*)stream)->nextOpenStream = firstOpenStream_; + firstOpenStream_ = (PaUtilStreamRepresentation*)stream; +} + + +static void RemoveOpenStream( PaStream* stream ) +{ + PaUtilStreamRepresentation *previous = NULL; + PaUtilStreamRepresentation *current = firstOpenStream_; + + while( current != NULL ) + { + if( ((PaStream*)current) == stream ) + { + if( previous == NULL ) + { + firstOpenStream_ = current->nextOpenStream; + } + else + { + previous->nextOpenStream = current->nextOpenStream; + } + return; + } + else + { + previous = current; + current = current->nextOpenStream; + } + } +} + + +static void CloseOpenStreams( void ) +{ + /* we call Pa_CloseStream() here to ensure that the same destruction + logic is used for automatically closed streams */ + + while( firstOpenStream_ != NULL ) + Pa_CloseStream( firstOpenStream_ ); +} + + +PaError Pa_Initialize( void ) +{ + PaError result; + + PA_LOGAPI_ENTER( "Pa_Initialize" ); + + if( PA_IS_INITIALISED_ ) + { + ++initializationCount_; + result = paNoError; + } + else + { + PA_VALIDATE_TYPE_SIZES; + PA_VALIDATE_ENDIANNESS; + + PaUtil_InitializeClock(); + PaUtil_ResetTraceMessages(); + + result = InitializeHostApis(); + if( result == paNoError ) + ++initializationCount_; + } + + PA_LOGAPI_EXIT_PAERROR( "Pa_Initialize", result ); + + return result; +} + + +PaError Pa_Terminate( void ) +{ + PaError result; + + PA_LOGAPI_ENTER( "Pa_Terminate" ); + + if( PA_IS_INITIALISED_ ) + { + // leave initializationCount_>0 so that Pa_CloseStream() can execute + if( initializationCount_ == 1 ) + { + CloseOpenStreams(); + + TerminateHostApis(); + + PaUtil_DumpTraceMessages(); + } + --initializationCount_; + result = paNoError; + } + else + { + result= paNotInitialized; + } + + PA_LOGAPI_EXIT_PAERROR( "Pa_Terminate", result ); + + return result; +} + + +const PaHostErrorInfo* Pa_GetLastHostErrorInfo( void ) +{ + return &lastHostErrorInfo_; +} + + +const char *Pa_GetErrorText( PaError errorCode ) +{ + const char *result; + + switch( errorCode ) + { + case paNoError: result = "Success"; break; + case paNotInitialized: result = "PortAudio not initialized"; break; + /** @todo could catenate the last host error text to result in the case of paUnanticipatedHostError. see: http://www.portaudio.com/trac/ticket/114 */ + case paUnanticipatedHostError: result = "Unanticipated host error"; break; + case paInvalidChannelCount: result = "Invalid number of channels"; break; + case paInvalidSampleRate: result = "Invalid sample rate"; break; + case paInvalidDevice: result = "Invalid device"; break; + case paInvalidFlag: result = "Invalid flag"; break; + case paSampleFormatNotSupported: result = "Sample format not supported"; break; + case paBadIODeviceCombination: result = "Illegal combination of I/O devices"; break; + case paInsufficientMemory: result = "Insufficient memory"; break; + case paBufferTooBig: result = "Buffer too big"; break; + case paBufferTooSmall: result = "Buffer too small"; break; + case paNullCallback: result = "No callback routine specified"; break; + case paBadStreamPtr: result = "Invalid stream pointer"; break; + case paTimedOut: result = "Wait timed out"; break; + case paInternalError: result = "Internal PortAudio error"; break; + case paDeviceUnavailable: result = "Device unavailable"; break; + case paIncompatibleHostApiSpecificStreamInfo: result = "Incompatible host API specific stream info"; break; + case paStreamIsStopped: result = "Stream is stopped"; break; + case paStreamIsNotStopped: result = "Stream is not stopped"; break; + case paInputOverflowed: result = "Input overflowed"; break; + case paOutputUnderflowed: result = "Output underflowed"; break; + case paHostApiNotFound: result = "Host API not found"; break; + case paInvalidHostApi: result = "Invalid host API"; break; + case paCanNotReadFromACallbackStream: result = "Can't read from a callback stream"; break; + case paCanNotWriteToACallbackStream: result = "Can't write to a callback stream"; break; + case paCanNotReadFromAnOutputOnlyStream: result = "Can't read from an output only stream"; break; + case paCanNotWriteToAnInputOnlyStream: result = "Can't write to an input only stream"; break; + case paIncompatibleStreamHostApi: result = "Incompatible stream host API"; break; + case paBadBufferPtr: result = "Bad buffer pointer"; break; + default: + if( errorCode > 0 ) + result = "Invalid error code (value greater than zero)"; + else + result = "Invalid error code"; + break; + } + return result; +} + + +PaHostApiIndex Pa_HostApiTypeIdToHostApiIndex( PaHostApiTypeId type ) +{ + PaHostApiIndex result; + int i; + + PA_LOGAPI_ENTER_PARAMS( "Pa_HostApiTypeIdToHostApiIndex" ); + PA_LOGAPI(("\tPaHostApiTypeId type: %d\n", type )); + + if( !PA_IS_INITIALISED_ ) + { + result = paNotInitialized; + } + else + { + result = paHostApiNotFound; + + for( i=0; i < hostApisCount_; ++i ) + { + if( hostApis_[i]->info.type == type ) + { + result = i; + break; + } + } + } + + PA_LOGAPI_EXIT_PAERROR_OR_T_RESULT( "Pa_HostApiTypeIdToHostApiIndex", "PaHostApiIndex: %d", result ); + + return result; +} + + +PaError PaUtil_GetHostApiRepresentation( struct PaUtilHostApiRepresentation **hostApi, + PaHostApiTypeId type ) +{ + PaError result; + int i; + + if( !PA_IS_INITIALISED_ ) + { + result = paNotInitialized; + } + else + { + result = paHostApiNotFound; + + for( i=0; i < hostApisCount_; ++i ) + { + if( hostApis_[i]->info.type == type ) + { + *hostApi = hostApis_[i]; + result = paNoError; + break; + } + } + } + + return result; +} + + +PaError PaUtil_DeviceIndexToHostApiDeviceIndex( + PaDeviceIndex *hostApiDevice, PaDeviceIndex device, struct PaUtilHostApiRepresentation *hostApi ) +{ + PaError result; + PaDeviceIndex x; + + x = device - hostApi->privatePaFrontInfo.baseDeviceIndex; + + if( x < 0 || x >= hostApi->info.deviceCount ) + { + result = paInvalidDevice; + } + else + { + *hostApiDevice = x; + result = paNoError; + } + + return result; +} + + +PaHostApiIndex Pa_GetHostApiCount( void ) +{ + int result; + + PA_LOGAPI_ENTER( "Pa_GetHostApiCount" ); + + if( !PA_IS_INITIALISED_ ) + { + result = paNotInitialized; + } + else + { + result = hostApisCount_; + } + + PA_LOGAPI_EXIT_PAERROR_OR_T_RESULT( "Pa_GetHostApiCount", "PaHostApiIndex: %d", result ); + + return result; +} + + +PaHostApiIndex Pa_GetDefaultHostApi( void ) +{ + int result; + + PA_LOGAPI_ENTER( "Pa_GetDefaultHostApi" ); + + if( !PA_IS_INITIALISED_ ) + { + result = paNotInitialized; + } + else + { + result = defaultHostApiIndex_; + + /* internal consistency check: make sure that the default host api + index is within range */ + + if( result < 0 || result >= hostApisCount_ ) + { + result = paInternalError; + } + } + + PA_LOGAPI_EXIT_PAERROR_OR_T_RESULT( "Pa_GetDefaultHostApi", "PaHostApiIndex: %d", result ); + + return result; +} + + +const PaHostApiInfo* Pa_GetHostApiInfo( PaHostApiIndex hostApi ) +{ + PaHostApiInfo *info; + + PA_LOGAPI_ENTER_PARAMS( "Pa_GetHostApiInfo" ); + PA_LOGAPI(("\tPaHostApiIndex hostApi: %d\n", hostApi )); + + if( !PA_IS_INITIALISED_ ) + { + info = NULL; + + PA_LOGAPI(("Pa_GetHostApiInfo returned:\n" )); + PA_LOGAPI(("\tPaHostApiInfo*: NULL [ PortAudio not initialized ]\n" )); + + } + else if( hostApi < 0 || hostApi >= hostApisCount_ ) + { + info = NULL; + + PA_LOGAPI(("Pa_GetHostApiInfo returned:\n" )); + PA_LOGAPI(("\tPaHostApiInfo*: NULL [ hostApi out of range ]\n" )); + + } + else + { + info = &hostApis_[hostApi]->info; + + PA_LOGAPI(("Pa_GetHostApiInfo returned:\n" )); + PA_LOGAPI(("\tPaHostApiInfo*: 0x%p\n", info )); + PA_LOGAPI(("\t{\n" )); + PA_LOGAPI(("\t\tint structVersion: %d\n", info->structVersion )); + PA_LOGAPI(("\t\tPaHostApiTypeId type: %d\n", info->type )); + PA_LOGAPI(("\t\tconst char *name: %s\n", info->name )); + PA_LOGAPI(("\t}\n" )); + + } + + return info; +} + + +PaDeviceIndex Pa_HostApiDeviceIndexToDeviceIndex( PaHostApiIndex hostApi, int hostApiDeviceIndex ) +{ + PaDeviceIndex result; + + PA_LOGAPI_ENTER_PARAMS( "Pa_HostApiDeviceIndexToPaDeviceIndex" ); + PA_LOGAPI(("\tPaHostApiIndex hostApi: %d\n", hostApi )); + PA_LOGAPI(("\tint hostApiDeviceIndex: %d\n", hostApiDeviceIndex )); + + if( !PA_IS_INITIALISED_ ) + { + result = paNotInitialized; + } + else + { + if( hostApi < 0 || hostApi >= hostApisCount_ ) + { + result = paInvalidHostApi; + } + else + { + if( hostApiDeviceIndex < 0 || + hostApiDeviceIndex >= hostApis_[hostApi]->info.deviceCount ) + { + result = paInvalidDevice; + } + else + { + result = hostApis_[hostApi]->privatePaFrontInfo.baseDeviceIndex + hostApiDeviceIndex; + } + } + } + + PA_LOGAPI_EXIT_PAERROR_OR_T_RESULT( "Pa_HostApiDeviceIndexToPaDeviceIndex", "PaDeviceIndex: %d", result ); + + return result; +} + + +PaDeviceIndex Pa_GetDeviceCount( void ) +{ + PaDeviceIndex result; + + PA_LOGAPI_ENTER( "Pa_GetDeviceCount" ); + + if( !PA_IS_INITIALISED_ ) + { + result = paNotInitialized; + } + else + { + result = deviceCount_; + } + + PA_LOGAPI_EXIT_PAERROR_OR_T_RESULT( "Pa_GetDeviceCount", "PaDeviceIndex: %d", result ); + + return result; +} + + +PaDeviceIndex Pa_GetDefaultInputDevice( void ) +{ + PaHostApiIndex hostApi; + PaDeviceIndex result; + + PA_LOGAPI_ENTER( "Pa_GetDefaultInputDevice" ); + + hostApi = Pa_GetDefaultHostApi(); + if( hostApi < 0 ) + { + result = paNoDevice; + } + else + { + result = hostApis_[hostApi]->info.defaultInputDevice; + } + + PA_LOGAPI_EXIT_T( "Pa_GetDefaultInputDevice", "PaDeviceIndex: %d", result ); + + return result; +} + + +PaDeviceIndex Pa_GetDefaultOutputDevice( void ) +{ + PaHostApiIndex hostApi; + PaDeviceIndex result; + + PA_LOGAPI_ENTER( "Pa_GetDefaultOutputDevice" ); + + hostApi = Pa_GetDefaultHostApi(); + if( hostApi < 0 ) + { + result = paNoDevice; + } + else + { + result = hostApis_[hostApi]->info.defaultOutputDevice; + } + + PA_LOGAPI_EXIT_T( "Pa_GetDefaultOutputDevice", "PaDeviceIndex: %d", result ); + + return result; +} + + +const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceIndex device ) +{ + int hostSpecificDeviceIndex; + int hostApiIndex = FindHostApi( device, &hostSpecificDeviceIndex ); + PaDeviceInfo *result; + + + PA_LOGAPI_ENTER_PARAMS( "Pa_GetDeviceInfo" ); + PA_LOGAPI(("\tPaDeviceIndex device: %d\n", device )); + + if( hostApiIndex < 0 ) + { + result = NULL; + + PA_LOGAPI(("Pa_GetDeviceInfo returned:\n" )); + PA_LOGAPI(("\tPaDeviceInfo* NULL [ invalid device index ]\n" )); + + } + else + { + result = hostApis_[hostApiIndex]->deviceInfos[ hostSpecificDeviceIndex ]; + + PA_LOGAPI(("Pa_GetDeviceInfo returned:\n" )); + PA_LOGAPI(("\tPaDeviceInfo*: 0x%p:\n", result )); + PA_LOGAPI(("\t{\n" )); + + PA_LOGAPI(("\t\tint structVersion: %d\n", result->structVersion )); + PA_LOGAPI(("\t\tconst char *name: %s\n", result->name )); + PA_LOGAPI(("\t\tPaHostApiIndex hostApi: %d\n", result->hostApi )); + PA_LOGAPI(("\t\tint maxInputChannels: %d\n", result->maxInputChannels )); + PA_LOGAPI(("\t\tint maxOutputChannels: %d\n", result->maxOutputChannels )); + PA_LOGAPI(("\t}\n" )); + + } + + return result; +} + + +/* + SampleFormatIsValid() returns 1 if sampleFormat is a sample format + defined in portaudio.h, or 0 otherwise. +*/ +static int SampleFormatIsValid( PaSampleFormat format ) +{ + switch( format & ~paNonInterleaved ) + { + case paFloat32: return 1; + case paInt16: return 1; + case paInt32: return 1; + case paInt24: return 1; + case paInt8: return 1; + case paUInt8: return 1; + case paCustomFormat: return 1; + default: return 0; + } +} + +/* + NOTE: make sure this validation list is kept syncronised with the one in + pa_hostapi.h + + ValidateOpenStreamParameters() checks that parameters to Pa_OpenStream() + conform to the expected values as described below. This function is + also designed to be used with the proposed Pa_IsFormatSupported() function. + + There are basically two types of validation that could be performed: + Generic conformance validation, and device capability mismatch + validation. This function performs only generic conformance validation. + Validation that would require knowledge of device capabilities is + not performed because of potentially complex relationships between + combinations of parameters - for example, even if the sampleRate + seems ok, it might not be for a duplex stream - we have no way of + checking this in an API-neutral way, so we don't try. + + On success the function returns PaNoError and fills in hostApi, + hostApiInputDeviceID, and hostApiOutputDeviceID fields. On failure + the function returns an error code indicating the first encountered + parameter error. + + + If ValidateOpenStreamParameters() returns paNoError, the following + assertions are guaranteed to be true. + + - at least one of inputParameters & outputParmeters is valid (not NULL) + + - if inputParameters & outputParameters are both valid, that + inputParameters->device & outputParameters->device both use the same host api + + PaDeviceIndex inputParameters->device + - is within range (0 to Pa_GetDeviceCount-1) Or: + - is paUseHostApiSpecificDeviceSpecification and + inputParameters->hostApiSpecificStreamInfo is non-NULL and refers + to a valid host api + + int inputParameters->channelCount + - if inputParameters->device is not paUseHostApiSpecificDeviceSpecification, channelCount is > 0 + - upper bound is NOT validated against device capabilities + + PaSampleFormat inputParameters->sampleFormat + - is one of the sample formats defined in portaudio.h + + void *inputParameters->hostApiSpecificStreamInfo + - if supplied its hostApi field matches the input device's host Api + + PaDeviceIndex outputParmeters->device + - is within range (0 to Pa_GetDeviceCount-1) + + int outputParmeters->channelCount + - if inputDevice is valid, channelCount is > 0 + - upper bound is NOT validated against device capabilities + + PaSampleFormat outputParmeters->sampleFormat + - is one of the sample formats defined in portaudio.h + + void *outputParmeters->hostApiSpecificStreamInfo + - if supplied its hostApi field matches the output device's host Api + + double sampleRate + - is not an 'absurd' rate (less than 1000. or greater than 384000.) + - sampleRate is NOT validated against device capabilities + + PaStreamFlags streamFlags + - unused platform neutral flags are zero + - paNeverDropInput is only used for full-duplex callback streams with + variable buffer size (paFramesPerBufferUnspecified) +*/ +static PaError ValidateOpenStreamParameters( + const PaStreamParameters *inputParameters, + const PaStreamParameters *outputParameters, + double sampleRate, + unsigned long framesPerBuffer, + PaStreamFlags streamFlags, + PaStreamCallback *streamCallback, + PaUtilHostApiRepresentation **hostApi, + PaDeviceIndex *hostApiInputDevice, + PaDeviceIndex *hostApiOutputDevice ) +{ + int inputHostApiIndex = -1, /* Surpress uninitialised var warnings: compiler does */ + outputHostApiIndex = -1; /* not see that if inputParameters and outputParame- */ + /* ters are both nonzero, these indices are set. */ + + if( (inputParameters == NULL) && (outputParameters == NULL) ) + { + return paInvalidDevice; /** @todo should be a new error code "invalid device parameters" or something */ + } + else + { + if( inputParameters == NULL ) + { + *hostApiInputDevice = paNoDevice; + } + else if( inputParameters->device == paUseHostApiSpecificDeviceSpecification ) + { + if( inputParameters->hostApiSpecificStreamInfo ) + { + inputHostApiIndex = Pa_HostApiTypeIdToHostApiIndex( + ((PaUtilHostApiSpecificStreamInfoHeader*)inputParameters->hostApiSpecificStreamInfo)->hostApiType ); + + if( inputHostApiIndex != -1 ) + { + *hostApiInputDevice = paUseHostApiSpecificDeviceSpecification; + *hostApi = hostApis_[inputHostApiIndex]; + } + else + { + return paInvalidDevice; + } + } + else + { + return paInvalidDevice; + } + } + else + { + if( inputParameters->device < 0 || inputParameters->device >= deviceCount_ ) + return paInvalidDevice; + + inputHostApiIndex = FindHostApi( inputParameters->device, hostApiInputDevice ); + if( inputHostApiIndex < 0 ) + return paInternalError; + + *hostApi = hostApis_[inputHostApiIndex]; + + if( inputParameters->channelCount <= 0 ) + return paInvalidChannelCount; + + if( !SampleFormatIsValid( inputParameters->sampleFormat ) ) + return paSampleFormatNotSupported; + + if( inputParameters->hostApiSpecificStreamInfo != NULL ) + { + if( ((PaUtilHostApiSpecificStreamInfoHeader*)inputParameters->hostApiSpecificStreamInfo)->hostApiType + != (*hostApi)->info.type ) + return paIncompatibleHostApiSpecificStreamInfo; + } + } + + if( outputParameters == NULL ) + { + *hostApiOutputDevice = paNoDevice; + } + else if( outputParameters->device == paUseHostApiSpecificDeviceSpecification ) + { + if( outputParameters->hostApiSpecificStreamInfo ) + { + outputHostApiIndex = Pa_HostApiTypeIdToHostApiIndex( + ((PaUtilHostApiSpecificStreamInfoHeader*)outputParameters->hostApiSpecificStreamInfo)->hostApiType ); + + if( outputHostApiIndex != -1 ) + { + *hostApiOutputDevice = paUseHostApiSpecificDeviceSpecification; + *hostApi = hostApis_[outputHostApiIndex]; + } + else + { + return paInvalidDevice; + } + } + else + { + return paInvalidDevice; + } + } + else + { + if( outputParameters->device < 0 || outputParameters->device >= deviceCount_ ) + return paInvalidDevice; + + outputHostApiIndex = FindHostApi( outputParameters->device, hostApiOutputDevice ); + if( outputHostApiIndex < 0 ) + return paInternalError; + + *hostApi = hostApis_[outputHostApiIndex]; + + if( outputParameters->channelCount <= 0 ) + return paInvalidChannelCount; + + if( !SampleFormatIsValid( outputParameters->sampleFormat ) ) + return paSampleFormatNotSupported; + + if( outputParameters->hostApiSpecificStreamInfo != NULL ) + { + if( ((PaUtilHostApiSpecificStreamInfoHeader*)outputParameters->hostApiSpecificStreamInfo)->hostApiType + != (*hostApi)->info.type ) + return paIncompatibleHostApiSpecificStreamInfo; + } + } + + if( (inputParameters != NULL) && (outputParameters != NULL) ) + { + /* ensure that both devices use the same API */ + if( inputHostApiIndex != outputHostApiIndex ) + return paBadIODeviceCombination; + } + } + + + /* Check for absurd sample rates. */ + if( (sampleRate < 1000.0) || (sampleRate > 384000.0) ) + return paInvalidSampleRate; + + if( ((streamFlags & ~paPlatformSpecificFlags) & ~(paClipOff | paDitherOff | paNeverDropInput | paPrimeOutputBuffersUsingStreamCallback ) ) != 0 ) + return paInvalidFlag; + + if( streamFlags & paNeverDropInput ) + { + /* must be a callback stream */ + if( !streamCallback ) + return paInvalidFlag; + + /* must be a full duplex stream */ + if( (inputParameters == NULL) || (outputParameters == NULL) ) + return paInvalidFlag; + + /* must use paFramesPerBufferUnspecified */ + if( framesPerBuffer != paFramesPerBufferUnspecified ) + return paInvalidFlag; + } + + return paNoError; +} + + +PaError Pa_IsFormatSupported( const PaStreamParameters *inputParameters, + const PaStreamParameters *outputParameters, + double sampleRate ) +{ + PaError result; + PaUtilHostApiRepresentation *hostApi = 0; + PaDeviceIndex hostApiInputDevice = paNoDevice, hostApiOutputDevice = paNoDevice; + PaStreamParameters hostApiInputParameters, hostApiOutputParameters; + PaStreamParameters *hostApiInputParametersPtr, *hostApiOutputParametersPtr; + + +#ifdef PA_LOG_API_CALLS + PA_LOGAPI_ENTER_PARAMS( "Pa_IsFormatSupported" ); + + if( inputParameters == NULL ){ + PA_LOGAPI(("\tPaStreamParameters *inputParameters: NULL\n" )); + }else{ + PA_LOGAPI(("\tPaStreamParameters *inputParameters: 0x%p\n", inputParameters )); + PA_LOGAPI(("\tPaDeviceIndex inputParameters->device: %d\n", inputParameters->device )); + PA_LOGAPI(("\tint inputParameters->channelCount: %d\n", inputParameters->channelCount )); + PA_LOGAPI(("\tPaSampleFormat inputParameters->sampleFormat: %d\n", inputParameters->sampleFormat )); + PA_LOGAPI(("\tPaTime inputParameters->suggestedLatency: %f\n", inputParameters->suggestedLatency )); + PA_LOGAPI(("\tvoid *inputParameters->hostApiSpecificStreamInfo: 0x%p\n", inputParameters->hostApiSpecificStreamInfo )); + } + + if( outputParameters == NULL ){ + PA_LOGAPI(("\tPaStreamParameters *outputParameters: NULL\n" )); + }else{ + PA_LOGAPI(("\tPaStreamParameters *outputParameters: 0x%p\n", outputParameters )); + PA_LOGAPI(("\tPaDeviceIndex outputParameters->device: %d\n", outputParameters->device )); + PA_LOGAPI(("\tint outputParameters->channelCount: %d\n", outputParameters->channelCount )); + PA_LOGAPI(("\tPaSampleFormat outputParameters->sampleFormat: %d\n", outputParameters->sampleFormat )); + PA_LOGAPI(("\tPaTime outputParameters->suggestedLatency: %f\n", outputParameters->suggestedLatency )); + PA_LOGAPI(("\tvoid *outputParameters->hostApiSpecificStreamInfo: 0x%p\n", outputParameters->hostApiSpecificStreamInfo )); + } + + PA_LOGAPI(("\tdouble sampleRate: %g\n", sampleRate )); +#endif + + if( !PA_IS_INITIALISED_ ) + { + result = paNotInitialized; + + PA_LOGAPI_EXIT_PAERROR( "Pa_IsFormatSupported", result ); + return result; + } + + result = ValidateOpenStreamParameters( inputParameters, + outputParameters, + sampleRate, 0, paNoFlag, 0, + &hostApi, + &hostApiInputDevice, + &hostApiOutputDevice ); + if( result != paNoError ) + { + PA_LOGAPI_EXIT_PAERROR( "Pa_IsFormatSupported", result ); + return result; + } + + + if( inputParameters ) + { + hostApiInputParameters.device = hostApiInputDevice; + hostApiInputParameters.channelCount = inputParameters->channelCount; + hostApiInputParameters.sampleFormat = inputParameters->sampleFormat; + hostApiInputParameters.suggestedLatency = inputParameters->suggestedLatency; + hostApiInputParameters.hostApiSpecificStreamInfo = inputParameters->hostApiSpecificStreamInfo; + hostApiInputParametersPtr = &hostApiInputParameters; + } + else + { + hostApiInputParametersPtr = NULL; + } + + if( outputParameters ) + { + hostApiOutputParameters.device = hostApiOutputDevice; + hostApiOutputParameters.channelCount = outputParameters->channelCount; + hostApiOutputParameters.sampleFormat = outputParameters->sampleFormat; + hostApiOutputParameters.suggestedLatency = outputParameters->suggestedLatency; + hostApiOutputParameters.hostApiSpecificStreamInfo = outputParameters->hostApiSpecificStreamInfo; + hostApiOutputParametersPtr = &hostApiOutputParameters; + } + else + { + hostApiOutputParametersPtr = NULL; + } + + result = hostApi->IsFormatSupported( hostApi, + hostApiInputParametersPtr, hostApiOutputParametersPtr, + sampleRate ); + +#ifdef PA_LOG_API_CALLS + PA_LOGAPI(("Pa_OpenStream returned:\n" )); + if( result == paFormatIsSupported ) + PA_LOGAPI(("\tPaError: 0 [ paFormatIsSupported ]\n" )); + else + PA_LOGAPI(("\tPaError: %d ( %s )\n", result, Pa_GetErrorText( result ) )); +#endif + + return result; +} + + +PaError Pa_OpenStream( PaStream** stream, + const PaStreamParameters *inputParameters, + const PaStreamParameters *outputParameters, + double sampleRate, + unsigned long framesPerBuffer, + PaStreamFlags streamFlags, + PaStreamCallback *streamCallback, + void *userData ) +{ + PaError result; + PaUtilHostApiRepresentation *hostApi = 0; + PaDeviceIndex hostApiInputDevice = paNoDevice, hostApiOutputDevice = paNoDevice; + PaStreamParameters hostApiInputParameters, hostApiOutputParameters; + PaStreamParameters *hostApiInputParametersPtr, *hostApiOutputParametersPtr; + + +#ifdef PA_LOG_API_CALLS + PA_LOGAPI_ENTER_PARAMS( "Pa_OpenStream" ); + PA_LOGAPI(("\tPaStream** stream: 0x%p\n", stream )); + + if( inputParameters == NULL ){ + PA_LOGAPI(("\tPaStreamParameters *inputParameters: NULL\n" )); + }else{ + PA_LOGAPI(("\tPaStreamParameters *inputParameters: 0x%p\n", inputParameters )); + PA_LOGAPI(("\tPaDeviceIndex inputParameters->device: %d\n", inputParameters->device )); + PA_LOGAPI(("\tint inputParameters->channelCount: %d\n", inputParameters->channelCount )); + PA_LOGAPI(("\tPaSampleFormat inputParameters->sampleFormat: %d\n", inputParameters->sampleFormat )); + PA_LOGAPI(("\tPaTime inputParameters->suggestedLatency: %f\n", inputParameters->suggestedLatency )); + PA_LOGAPI(("\tvoid *inputParameters->hostApiSpecificStreamInfo: 0x%p\n", inputParameters->hostApiSpecificStreamInfo )); + } + + if( outputParameters == NULL ){ + PA_LOGAPI(("\tPaStreamParameters *outputParameters: NULL\n" )); + }else{ + PA_LOGAPI(("\tPaStreamParameters *outputParameters: 0x%p\n", outputParameters )); + PA_LOGAPI(("\tPaDeviceIndex outputParameters->device: %d\n", outputParameters->device )); + PA_LOGAPI(("\tint outputParameters->channelCount: %d\n", outputParameters->channelCount )); + PA_LOGAPI(("\tPaSampleFormat outputParameters->sampleFormat: %d\n", outputParameters->sampleFormat )); + PA_LOGAPI(("\tPaTime outputParameters->suggestedLatency: %f\n", outputParameters->suggestedLatency )); + PA_LOGAPI(("\tvoid *outputParameters->hostApiSpecificStreamInfo: 0x%p\n", outputParameters->hostApiSpecificStreamInfo )); + } + + PA_LOGAPI(("\tdouble sampleRate: %g\n", sampleRate )); + PA_LOGAPI(("\tunsigned long framesPerBuffer: %d\n", framesPerBuffer )); + PA_LOGAPI(("\tPaStreamFlags streamFlags: 0x%x\n", streamFlags )); + PA_LOGAPI(("\tPaStreamCallback *streamCallback: 0x%p\n", streamCallback )); + PA_LOGAPI(("\tvoid *userData: 0x%p\n", userData )); +#endif + + if( !PA_IS_INITIALISED_ ) + { + result = paNotInitialized; + + PA_LOGAPI(("Pa_OpenStream returned:\n" )); + PA_LOGAPI(("\t*(PaStream** stream): undefined\n" )); + PA_LOGAPI(("\tPaError: %d ( %s )\n", result, Pa_GetErrorText( result ) )); + return result; + } + + /* Check for parameter errors. + NOTE: make sure this validation list is kept syncronised with the one + in pa_hostapi.h + */ + + if( stream == NULL ) + { + result = paBadStreamPtr; + + PA_LOGAPI(("Pa_OpenStream returned:\n" )); + PA_LOGAPI(("\t*(PaStream** stream): undefined\n" )); + PA_LOGAPI(("\tPaError: %d ( %s )\n", result, Pa_GetErrorText( result ) )); + return result; + } + + result = ValidateOpenStreamParameters( inputParameters, + outputParameters, + sampleRate, framesPerBuffer, + streamFlags, streamCallback, + &hostApi, + &hostApiInputDevice, + &hostApiOutputDevice ); + if( result != paNoError ) + { + PA_LOGAPI(("Pa_OpenStream returned:\n" )); + PA_LOGAPI(("\t*(PaStream** stream): undefined\n" )); + PA_LOGAPI(("\tPaError: %d ( %s )\n", result, Pa_GetErrorText( result ) )); + return result; + } + + + if( inputParameters ) + { + hostApiInputParameters.device = hostApiInputDevice; + hostApiInputParameters.channelCount = inputParameters->channelCount; + hostApiInputParameters.sampleFormat = inputParameters->sampleFormat; + hostApiInputParameters.suggestedLatency = inputParameters->suggestedLatency; + hostApiInputParameters.hostApiSpecificStreamInfo = inputParameters->hostApiSpecificStreamInfo; + hostApiInputParametersPtr = &hostApiInputParameters; + } + else + { + hostApiInputParametersPtr = NULL; + } + + if( outputParameters ) + { + hostApiOutputParameters.device = hostApiOutputDevice; + hostApiOutputParameters.channelCount = outputParameters->channelCount; + hostApiOutputParameters.sampleFormat = outputParameters->sampleFormat; + hostApiOutputParameters.suggestedLatency = outputParameters->suggestedLatency; + hostApiOutputParameters.hostApiSpecificStreamInfo = outputParameters->hostApiSpecificStreamInfo; + hostApiOutputParametersPtr = &hostApiOutputParameters; + } + else + { + hostApiOutputParametersPtr = NULL; + } + + result = hostApi->OpenStream( hostApi, stream, + hostApiInputParametersPtr, hostApiOutputParametersPtr, + sampleRate, framesPerBuffer, streamFlags, streamCallback, userData ); + + if( result == paNoError ) + AddOpenStream( *stream ); + + + PA_LOGAPI(("Pa_OpenStream returned:\n" )); + PA_LOGAPI(("\t*(PaStream** stream): 0x%p\n", *stream )); + PA_LOGAPI(("\tPaError: %d ( %s )\n", result, Pa_GetErrorText( result ) )); + + return result; +} + + +PaError Pa_OpenDefaultStream( PaStream** stream, + int inputChannelCount, + int outputChannelCount, + PaSampleFormat sampleFormat, + double sampleRate, + unsigned long framesPerBuffer, + PaStreamCallback *streamCallback, + void *userData ) +{ + PaError result; + PaStreamParameters hostApiInputParameters, hostApiOutputParameters; + PaStreamParameters *hostApiInputParametersPtr, *hostApiOutputParametersPtr; + + PA_LOGAPI_ENTER_PARAMS( "Pa_OpenDefaultStream" ); + PA_LOGAPI(("\tPaStream** stream: 0x%p\n", stream )); + PA_LOGAPI(("\tint inputChannelCount: %d\n", inputChannelCount )); + PA_LOGAPI(("\tint outputChannelCount: %d\n", outputChannelCount )); + PA_LOGAPI(("\tPaSampleFormat sampleFormat: %d\n", sampleFormat )); + PA_LOGAPI(("\tdouble sampleRate: %g\n", sampleRate )); + PA_LOGAPI(("\tunsigned long framesPerBuffer: %d\n", framesPerBuffer )); + PA_LOGAPI(("\tPaStreamCallback *streamCallback: 0x%p\n", streamCallback )); + PA_LOGAPI(("\tvoid *userData: 0x%p\n", userData )); + + + if( inputChannelCount > 0 ) + { + hostApiInputParameters.device = Pa_GetDefaultInputDevice(); + if( hostApiInputParameters.device == paNoDevice ) + return paDeviceUnavailable; + + hostApiInputParameters.channelCount = inputChannelCount; + hostApiInputParameters.sampleFormat = sampleFormat; + /* defaultHighInputLatency is used below instead of + defaultLowInputLatency because it is more important for the default + stream to work reliably than it is for it to work with the lowest + latency. + */ + hostApiInputParameters.suggestedLatency = + Pa_GetDeviceInfo( hostApiInputParameters.device )->defaultHighInputLatency; + hostApiInputParameters.hostApiSpecificStreamInfo = NULL; + hostApiInputParametersPtr = &hostApiInputParameters; + } + else + { + hostApiInputParametersPtr = NULL; + } + + if( outputChannelCount > 0 ) + { + hostApiOutputParameters.device = Pa_GetDefaultOutputDevice(); + if( hostApiOutputParameters.device == paNoDevice ) + return paDeviceUnavailable; + + hostApiOutputParameters.channelCount = outputChannelCount; + hostApiOutputParameters.sampleFormat = sampleFormat; + /* defaultHighOutputLatency is used below instead of + defaultLowOutputLatency because it is more important for the default + stream to work reliably than it is for it to work with the lowest + latency. + */ + hostApiOutputParameters.suggestedLatency = + Pa_GetDeviceInfo( hostApiOutputParameters.device )->defaultHighOutputLatency; + hostApiOutputParameters.hostApiSpecificStreamInfo = NULL; + hostApiOutputParametersPtr = &hostApiOutputParameters; + } + else + { + hostApiOutputParametersPtr = NULL; + } + + + result = Pa_OpenStream( + stream, hostApiInputParametersPtr, hostApiOutputParametersPtr, + sampleRate, framesPerBuffer, paNoFlag, streamCallback, userData ); + + PA_LOGAPI(("Pa_OpenDefaultStream returned:\n" )); + PA_LOGAPI(("\t*(PaStream** stream): 0x%p", *stream )); + PA_LOGAPI(("\tPaError: %d ( %s )\n", result, Pa_GetErrorText( result ) )); + + return result; +} + + +PaError PaUtil_ValidateStreamPointer( PaStream* stream ) +{ + if( !PA_IS_INITIALISED_ ) return paNotInitialized; + + if( stream == NULL ) return paBadStreamPtr; + + if( ((PaUtilStreamRepresentation*)stream)->magic != PA_STREAM_MAGIC ) + return paBadStreamPtr; + + return paNoError; +} + + +PaError Pa_CloseStream( PaStream* stream ) +{ + PaUtilStreamInterface *interface; + PaError result = PaUtil_ValidateStreamPointer( stream ); + + PA_LOGAPI_ENTER_PARAMS( "Pa_CloseStream" ); + PA_LOGAPI(("\tPaStream* stream: 0x%p\n", stream )); + + /* always remove the open stream from our list, even if this function + eventually returns an error. Otherwise CloseOpenStreams() will + get stuck in an infinite loop */ + RemoveOpenStream( stream ); /* be sure to call this _before_ closing the stream */ + + if( result == paNoError ) + { + interface = PA_STREAM_INTERFACE(stream); + + /* abort the stream if it isn't stopped */ + result = interface->IsStopped( stream ); + if( result == 1 ) + result = paNoError; + else if( result == 0 ) + result = interface->Abort( stream ); + + if( result == paNoError ) /** @todo REVIEW: shouldn't we close anyway? see: http://www.portaudio.com/trac/ticket/115 */ + result = interface->Close( stream ); + } + + PA_LOGAPI_EXIT_PAERROR( "Pa_CloseStream", result ); + + return result; +} + + +PaError Pa_SetStreamFinishedCallback( PaStream *stream, PaStreamFinishedCallback* streamFinishedCallback ) +{ + PaError result = PaUtil_ValidateStreamPointer( stream ); + + PA_LOGAPI_ENTER_PARAMS( "Pa_SetStreamFinishedCallback" ); + PA_LOGAPI(("\tPaStream* stream: 0x%p\n", stream )); + PA_LOGAPI(("\tPaStreamFinishedCallback* streamFinishedCallback: 0x%p\n", streamFinishedCallback )); + + if( result == paNoError ) + { + result = PA_STREAM_INTERFACE(stream)->IsStopped( stream ); + if( result == 0 ) + { + result = paStreamIsNotStopped ; + } + if( result == 1 ) + { + PA_STREAM_REP( stream )->streamFinishedCallback = streamFinishedCallback; + result = paNoError; + } + } + + PA_LOGAPI_EXIT_PAERROR( "Pa_SetStreamFinishedCallback", result ); + + return result; + +} + + +PaError Pa_StartStream( PaStream *stream ) +{ + PaError result = PaUtil_ValidateStreamPointer( stream ); + + PA_LOGAPI_ENTER_PARAMS( "Pa_StartStream" ); + PA_LOGAPI(("\tPaStream* stream: 0x%p\n", stream )); + + if( result == paNoError ) + { + result = PA_STREAM_INTERFACE(stream)->IsStopped( stream ); + if( result == 0 ) + { + result = paStreamIsNotStopped ; + } + else if( result == 1 ) + { + result = PA_STREAM_INTERFACE(stream)->Start( stream ); + } + } + + PA_LOGAPI_EXIT_PAERROR( "Pa_StartStream", result ); + + return result; +} + + +PaError Pa_StopStream( PaStream *stream ) +{ + PaError result = PaUtil_ValidateStreamPointer( stream ); + + PA_LOGAPI_ENTER_PARAMS( "Pa_StopStream" ); + PA_LOGAPI(("\tPaStream* stream: 0x%p\n", stream )); + + if( result == paNoError ) + { + result = PA_STREAM_INTERFACE(stream)->IsStopped( stream ); + if( result == 0 ) + { + result = PA_STREAM_INTERFACE(stream)->Stop( stream ); + } + else if( result == 1 ) + { + result = paStreamIsStopped; + } + } + + PA_LOGAPI_EXIT_PAERROR( "Pa_StopStream", result ); + + return result; +} + + +PaError Pa_AbortStream( PaStream *stream ) +{ + PaError result = PaUtil_ValidateStreamPointer( stream ); + + PA_LOGAPI_ENTER_PARAMS( "Pa_AbortStream" ); + PA_LOGAPI(("\tPaStream* stream: 0x%p\n", stream )); + + if( result == paNoError ) + { + result = PA_STREAM_INTERFACE(stream)->IsStopped( stream ); + if( result == 0 ) + { + result = PA_STREAM_INTERFACE(stream)->Abort( stream ); + } + else if( result == 1 ) + { + result = paStreamIsStopped; + } + } + + PA_LOGAPI_EXIT_PAERROR( "Pa_AbortStream", result ); + + return result; +} + + +PaError Pa_IsStreamStopped( PaStream *stream ) +{ + PaError result = PaUtil_ValidateStreamPointer( stream ); + + PA_LOGAPI_ENTER_PARAMS( "Pa_IsStreamStopped" ); + PA_LOGAPI(("\tPaStream* stream: 0x%p\n", stream )); + + if( result == paNoError ) + result = PA_STREAM_INTERFACE(stream)->IsStopped( stream ); + + PA_LOGAPI_EXIT_PAERROR( "Pa_IsStreamStopped", result ); + + return result; +} + + +PaError Pa_IsStreamActive( PaStream *stream ) +{ + PaError result = PaUtil_ValidateStreamPointer( stream ); + + PA_LOGAPI_ENTER_PARAMS( "Pa_IsStreamActive" ); + PA_LOGAPI(("\tPaStream* stream: 0x%p\n", stream )); + + if( result == paNoError ) + result = PA_STREAM_INTERFACE(stream)->IsActive( stream ); + + + PA_LOGAPI_EXIT_PAERROR( "Pa_IsStreamActive", result ); + + return result; +} + + +const PaStreamInfo* Pa_GetStreamInfo( PaStream *stream ) +{ + PaError error = PaUtil_ValidateStreamPointer( stream ); + const PaStreamInfo *result; + + PA_LOGAPI_ENTER_PARAMS( "Pa_GetStreamInfo" ); + PA_LOGAPI(("\tPaStream* stream: 0x%p\n", stream )); + + if( error != paNoError ) + { + result = 0; + + PA_LOGAPI(("Pa_GetStreamInfo returned:\n" )); + PA_LOGAPI(("\tconst PaStreamInfo*: 0 [PaError error:%d ( %s )]\n", error, Pa_GetErrorText( error ) )); + + } + else + { + result = &PA_STREAM_REP( stream )->streamInfo; + + PA_LOGAPI(("Pa_GetStreamInfo returned:\n" )); + PA_LOGAPI(("\tconst PaStreamInfo*: 0x%p:\n", result )); + PA_LOGAPI(("\t{" )); + + PA_LOGAPI(("\t\tint structVersion: %d\n", result->structVersion )); + PA_LOGAPI(("\t\tPaTime inputLatency: %f\n", result->inputLatency )); + PA_LOGAPI(("\t\tPaTime outputLatency: %f\n", result->outputLatency )); + PA_LOGAPI(("\t\tdouble sampleRate: %f\n", result->sampleRate )); + PA_LOGAPI(("\t}\n" )); + + } + + return result; +} + + +PaTime Pa_GetStreamTime( PaStream *stream ) +{ + PaError error = PaUtil_ValidateStreamPointer( stream ); + PaTime result; + + PA_LOGAPI_ENTER_PARAMS( "Pa_GetStreamTime" ); + PA_LOGAPI(("\tPaStream* stream: 0x%p\n", stream )); + + if( error != paNoError ) + { + result = 0; + + PA_LOGAPI(("Pa_GetStreamTime returned:\n" )); + PA_LOGAPI(("\tPaTime: 0 [PaError error:%d ( %s )]\n", result, error, Pa_GetErrorText( error ) )); + + } + else + { + result = PA_STREAM_INTERFACE(stream)->GetTime( stream ); + + PA_LOGAPI(("Pa_GetStreamTime returned:\n" )); + PA_LOGAPI(("\tPaTime: %g\n", result )); + + } + + return result; +} + + +double Pa_GetStreamCpuLoad( PaStream* stream ) +{ + PaError error = PaUtil_ValidateStreamPointer( stream ); + double result; + + PA_LOGAPI_ENTER_PARAMS( "Pa_GetStreamCpuLoad" ); + PA_LOGAPI(("\tPaStream* stream: 0x%p\n", stream )); + + if( error != paNoError ) + { + + result = 0.0; + + PA_LOGAPI(("Pa_GetStreamCpuLoad returned:\n" )); + PA_LOGAPI(("\tdouble: 0.0 [PaError error: %d ( %s )]\n", error, Pa_GetErrorText( error ) )); + + } + else + { + result = PA_STREAM_INTERFACE(stream)->GetCpuLoad( stream ); + + PA_LOGAPI(("Pa_GetStreamCpuLoad returned:\n" )); + PA_LOGAPI(("\tdouble: %g\n", result )); + + } + + return result; +} + + +PaError Pa_ReadStream( PaStream* stream, + void *buffer, + unsigned long frames ) +{ + PaError result = PaUtil_ValidateStreamPointer( stream ); + + PA_LOGAPI_ENTER_PARAMS( "Pa_ReadStream" ); + PA_LOGAPI(("\tPaStream* stream: 0x%p\n", stream )); + + if( result == paNoError ) + { + if( frames == 0 ) + { + /* @todo Should we not allow the implementation to signal any overflow condition? see: http://www.portaudio.com/trac/ticket/116*/ + result = paNoError; + } + else if( buffer == 0 ) + { + result = paBadBufferPtr; + } + else + { + result = PA_STREAM_INTERFACE(stream)->IsStopped( stream ); + if( result == 0 ) + { + result = PA_STREAM_INTERFACE(stream)->Read( stream, buffer, frames ); + } + else if( result == 1 ) + { + result = paStreamIsStopped; + } + } + } + + PA_LOGAPI_EXIT_PAERROR( "Pa_ReadStream", result ); + + return result; +} + + +PaError Pa_WriteStream( PaStream* stream, + const void *buffer, + unsigned long frames ) +{ + PaError result = PaUtil_ValidateStreamPointer( stream ); + + PA_LOGAPI_ENTER_PARAMS( "Pa_WriteStream" ); + PA_LOGAPI(("\tPaStream* stream: 0x%p\n", stream )); + + if( result == paNoError ) + { + if( frames == 0 ) + { + /* @todo Should we not allow the implementation to signal any underflow condition? see: http://www.portaudio.com/trac/ticket/116*/ + result = paNoError; + } + else if( buffer == 0 ) + { + result = paBadBufferPtr; + } + else + { + result = PA_STREAM_INTERFACE(stream)->IsStopped( stream ); + if( result == 0 ) + { + result = PA_STREAM_INTERFACE(stream)->Write( stream, buffer, frames ); + } + else if( result == 1 ) + { + result = paStreamIsStopped; + } + } + } + + PA_LOGAPI_EXIT_PAERROR( "Pa_WriteStream", result ); + + return result; +} + +signed long Pa_GetStreamReadAvailable( PaStream* stream ) +{ + PaError error = PaUtil_ValidateStreamPointer( stream ); + signed long result; + + PA_LOGAPI_ENTER_PARAMS( "Pa_GetStreamReadAvailable" ); + PA_LOGAPI(("\tPaStream* stream: 0x%p\n", stream )); + + if( error != paNoError ) + { + result = 0; + + PA_LOGAPI(("Pa_GetStreamReadAvailable returned:\n" )); + PA_LOGAPI(("\tunsigned long: 0 [ PaError error: %d ( %s ) ]\n", error, Pa_GetErrorText( error ) )); + + } + else + { + result = PA_STREAM_INTERFACE(stream)->GetReadAvailable( stream ); + + PA_LOGAPI(("Pa_GetStreamReadAvailable returned:\n" )); + PA_LOGAPI(("\tPaError: %d ( %s )\n", result, Pa_GetErrorText( result ) )); + + } + + return result; +} + + +signed long Pa_GetStreamWriteAvailable( PaStream* stream ) +{ + PaError error = PaUtil_ValidateStreamPointer( stream ); + signed long result; + + PA_LOGAPI_ENTER_PARAMS( "Pa_GetStreamWriteAvailable" ); + PA_LOGAPI(("\tPaStream* stream: 0x%p\n", stream )); + + if( error != paNoError ) + { + result = 0; + + PA_LOGAPI(("Pa_GetStreamWriteAvailable returned:\n" )); + PA_LOGAPI(("\tunsigned long: 0 [ PaError error: %d ( %s ) ]\n", error, Pa_GetErrorText( error ) )); + + } + else + { + result = PA_STREAM_INTERFACE(stream)->GetWriteAvailable( stream ); + + PA_LOGAPI(("Pa_GetStreamWriteAvailable returned:\n" )); + PA_LOGAPI(("\tPaError: %d ( %s )\n", result, Pa_GetErrorText( result ) )); + + } + + return result; +} + + +PaError Pa_GetSampleSize( PaSampleFormat format ) +{ + int result; + + PA_LOGAPI_ENTER_PARAMS( "Pa_GetSampleSize" ); + PA_LOGAPI(("\tPaSampleFormat format: %d\n", format )); + + switch( format & ~paNonInterleaved ) + { + + case paUInt8: + case paInt8: + result = 1; + break; + + case paInt16: + result = 2; + break; + + case paInt24: + result = 3; + break; + + case paFloat32: + case paInt32: + result = 4; + break; + + default: + result = paSampleFormatNotSupported; + break; + } + + PA_LOGAPI_EXIT_PAERROR_OR_T_RESULT( "Pa_GetSampleSize", "int: %d", result ); + + return (PaError) result; +} + diff --git a/extern/portaudio/src/common/pa_gitrevision.h b/extern/portaudio/src/common/pa_gitrevision.h new file mode 100644 index 0000000..7d47425 --- /dev/null +++ b/extern/portaudio/src/common/pa_gitrevision.h @@ -0,0 +1 @@ +#define PA_GIT_REVISION unknown diff --git a/extern/portaudio/src/common/pa_hostapi.h b/extern/portaudio/src/common/pa_hostapi.h new file mode 100644 index 0000000..54b527e --- /dev/null +++ b/extern/portaudio/src/common/pa_hostapi.h @@ -0,0 +1,362 @@ +#ifndef PA_HOSTAPI_H +#define PA_HOSTAPI_H +/* + * $Id$ + * Portable Audio I/O Library + * host api representation + * + * Based on the Open Source API proposed by Ross Bencina + * Copyright (c) 1999-2008 Ross Bencina, Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +/** @file + @ingroup common_src + + @brief Interfaces and representation structures used by pa_front.c + to manage and communicate with host API implementations. +*/ + +#include "portaudio.h" + +/** +The PA_NO_* host API macros are now deprecated in favor of PA_USE_* macros. +PA_USE_* indicates whether a particular host API will be initialized by PortAudio. +An undefined or 0 value indicates that the host API will not be used. A value of 1 +indicates that the host API will be used. PA_USE_* macros should be left undefined +or defined to either 0 or 1. + +The code below ensures that PA_USE_* macros are always defined and have value +0 or 1. Undefined symbols are defaulted to 0. Symbols that are neither 0 nor 1 +are defaulted to 1. +*/ + +#ifndef PA_USE_SKELETON +#define PA_USE_SKELETON 0 +#elif (PA_USE_SKELETON != 0) && (PA_USE_SKELETON != 1) +#undef PA_USE_SKELETON +#define PA_USE_SKELETON 1 +#endif + +#if defined(PA_NO_ASIO) || defined(PA_NO_DS) || defined(PA_NO_WMME) || defined(PA_NO_WASAPI) || defined(PA_NO_WDMKS) +#error "Portaudio: PA_NO_ is no longer supported, please remove definition and use PA_USE_ instead" +#endif + +#ifndef PA_USE_ASIO +#define PA_USE_ASIO 0 +#elif (PA_USE_ASIO != 0) && (PA_USE_ASIO != 1) +#undef PA_USE_ASIO +#define PA_USE_ASIO 1 +#endif + +#ifndef PA_USE_DS +#define PA_USE_DS 0 +#elif (PA_USE_DS != 0) && (PA_USE_DS != 1) +#undef PA_USE_DS +#define PA_USE_DS 1 +#endif + +#ifndef PA_USE_WMME +#define PA_USE_WMME 0 +#elif (PA_USE_WMME != 0) && (PA_USE_WMME != 1) +#undef PA_USE_WMME +#define PA_USE_WMME 1 +#endif + +#ifndef PA_USE_WASAPI +#define PA_USE_WASAPI 0 +#elif (PA_USE_WASAPI != 0) && (PA_USE_WASAPI != 1) +#undef PA_USE_WASAPI +#define PA_USE_WASAPI 1 +#endif + +#ifndef PA_USE_WDMKS +#define PA_USE_WDMKS 0 +#elif (PA_USE_WDMKS != 0) && (PA_USE_WDMKS != 1) +#undef PA_USE_WDMKS +#define PA_USE_WDMKS 1 +#endif + +/* Set default values for Unix based APIs. */ +#if defined(PA_NO_OSS) || defined(PA_NO_ALSA) || defined(PA_NO_JACK) || defined(PA_NO_COREAUDIO) || defined(PA_NO_SGI) || defined(PA_NO_ASIHPI) +#error "Portaudio: PA_NO_ is no longer supported, please remove definition and use PA_USE_ instead" +#endif + +#ifndef PA_USE_OSS +#define PA_USE_OSS 0 +#elif (PA_USE_OSS != 0) && (PA_USE_OSS != 1) +#undef PA_USE_OSS +#define PA_USE_OSS 1 +#endif + +#ifndef PA_USE_ALSA +#define PA_USE_ALSA 0 +#elif (PA_USE_ALSA != 0) && (PA_USE_ALSA != 1) +#undef PA_USE_ALSA +#define PA_USE_ALSA 1 +#endif + +#ifndef PA_USE_JACK +#define PA_USE_JACK 0 +#elif (PA_USE_JACK != 0) && (PA_USE_JACK != 1) +#undef PA_USE_JACK +#define PA_USE_JACK 1 +#endif + +#ifndef PA_USE_SGI +#define PA_USE_SGI 0 +#elif (PA_USE_SGI != 0) && (PA_USE_SGI != 1) +#undef PA_USE_SGI +#define PA_USE_SGI 1 +#endif + +#ifndef PA_USE_COREAUDIO +#define PA_USE_COREAUDIO 0 +#elif (PA_USE_COREAUDIO != 0) && (PA_USE_COREAUDIO != 1) +#undef PA_USE_COREAUDIO +#define PA_USE_COREAUDIO 1 +#endif + +#ifndef PA_USE_ASIHPI +#define PA_USE_ASIHPI 0 +#elif (PA_USE_ASIHPI != 0) && (PA_USE_ASIHPI != 1) +#undef PA_USE_ASIHPI +#define PA_USE_ASIHPI 1 +#endif + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + +/** **FOR THE USE OF pa_front.c ONLY** + Do NOT use fields in this structure, they my change at any time. + Use functions defined in pa_util.h if you think you need functionality + which can be derived from here. +*/ +typedef struct PaUtilPrivatePaFrontHostApiInfo { + + + unsigned long baseDeviceIndex; +}PaUtilPrivatePaFrontHostApiInfo; + + +/** The common header for all data structures whose pointers are passed through + the hostApiSpecificStreamInfo field of the PaStreamParameters structure. + Note that in order to keep the public PortAudio interface clean, this structure + is not used explicitly when declaring hostApiSpecificStreamInfo data structures. + However, some code in pa_front depends on the first 3 members being equivalent + with this structure. + @see PaStreamParameters +*/ +typedef struct PaUtilHostApiSpecificStreamInfoHeader +{ + unsigned long size; /**< size of whole structure including this header */ + PaHostApiTypeId hostApiType; /**< host API for which this data is intended */ + unsigned long version; /**< structure version */ +} PaUtilHostApiSpecificStreamInfoHeader; + + + +/** A structure representing the interface to a host API. Contains both + concrete data and pointers to functions which implement the interface. +*/ +typedef struct PaUtilHostApiRepresentation { + PaUtilPrivatePaFrontHostApiInfo privatePaFrontInfo; + + /** The host api implementation should populate the info field. In the + case of info.defaultInputDevice and info.defaultOutputDevice the + values stored should be 0 based indices within the host api's own + device index range (0 to deviceCount). These values will be converted + to global device indices by pa_front after PaUtilHostApiInitializer() + returns. + */ + PaHostApiInfo info; + + PaDeviceInfo** deviceInfos; + + /** + (*Terminate)() is guaranteed to be called with a valid + parameter, which was previously returned from the same implementation's + initializer. + */ + void (*Terminate)( struct PaUtilHostApiRepresentation *hostApi ); + + /** + The inputParameters and outputParameters pointers should not be saved + as they will not remain valid after OpenStream is called. + + + The following guarantees are made about parameters to (*OpenStream)(): + + [NOTE: the following list up to *END PA FRONT VALIDATIONS* should be + kept in sync with the one for ValidateOpenStreamParameters and + Pa_OpenStream in pa_front.c] + + PaHostApiRepresentation *hostApi + - is valid for this implementation + + PaStream** stream + - is non-null + + - at least one of inputParameters & outputParmeters is valid (not NULL) + + - if inputParameters & outputParmeters are both valid, that + inputParameters->device & outputParmeters->device both use the same host api + + PaDeviceIndex inputParameters->device + - is within range (0 to Pa_CountDevices-1) Or: + - is paUseHostApiSpecificDeviceSpecification and + inputParameters->hostApiSpecificStreamInfo is non-NULL and refers + to a valid host api + + int inputParameters->numChannels + - if inputParameters->device is not paUseHostApiSpecificDeviceSpecification, numInputChannels is > 0 + - upper bound is NOT validated against device capabilities + + PaSampleFormat inputParameters->sampleFormat + - is one of the sample formats defined in portaudio.h + + void *inputParameters->hostApiSpecificStreamInfo + - if supplied its hostApi field matches the input device's host Api + + PaDeviceIndex outputParmeters->device + - is within range (0 to Pa_CountDevices-1) + + int outputParmeters->numChannels + - if inputDevice is valid, numInputChannels is > 0 + - upper bound is NOT validated against device capabilities + + PaSampleFormat outputParmeters->sampleFormat + - is one of the sample formats defined in portaudio.h + + void *outputParmeters->hostApiSpecificStreamInfo + - if supplied its hostApi field matches the output device's host Api + + double sampleRate + - is not an 'absurd' rate (less than 1000. or greater than 384000.) + - sampleRate is NOT validated against device capabilities + + PaStreamFlags streamFlags + - unused platform neutral flags are zero + - paNeverDropInput is only used for full-duplex callback streams + with variable buffer size (paFramesPerBufferUnspecified) + + [*END PA FRONT VALIDATIONS*] + + + The following validations MUST be performed by (*OpenStream)(): + + - check that input device can support numInputChannels + + - check that input device can support inputSampleFormat, or that + we have the capability to convert from outputSampleFormat to + a native format + + - if inputStreamInfo is supplied, validate its contents, + or return an error if no inputStreamInfo is expected + + - check that output device can support numOutputChannels + + - check that output device can support outputSampleFormat, or that + we have the capability to convert from outputSampleFormat to + a native format + + - if outputStreamInfo is supplied, validate its contents, + or return an error if no outputStreamInfo is expected + + - if a full duplex stream is requested, check that the combination + of input and output parameters is supported + + - check that the device supports sampleRate + + - alter sampleRate to a close allowable rate if necessary + + - validate inputLatency and outputLatency + + - validate any platform specific flags, if flags are supplied they + must be valid. + */ + PaError (*OpenStream)( struct PaUtilHostApiRepresentation *hostApi, + PaStream** stream, + const PaStreamParameters *inputParameters, + const PaStreamParameters *outputParameters, + double sampleRate, + unsigned long framesPerCallback, + PaStreamFlags streamFlags, + PaStreamCallback *streamCallback, + void *userData ); + + + PaError (*IsFormatSupported)( struct PaUtilHostApiRepresentation *hostApi, + const PaStreamParameters *inputParameters, + const PaStreamParameters *outputParameters, + double sampleRate ); +} PaUtilHostApiRepresentation; + + +/** Prototype for the initialization function which must be implemented by every + host API. + + This function should only return an error other than paNoError if it encounters + an unexpected and fatal error (memory allocation error for example). In general, + there may be conditions under which it returns a NULL interface pointer and also + returns paNoError. For example, if the ASIO implementation detects that ASIO is + not installed, it should return a NULL interface, and paNoError. + + @see paHostApiInitializers +*/ +typedef PaError PaUtilHostApiInitializer( PaUtilHostApiRepresentation**, PaHostApiIndex ); + + +/** paHostApiInitializers is a NULL-terminated array of host API initialization + functions. These functions are called by pa_front.c to initialize the host APIs + when the client calls Pa_Initialize(). + + The initialization functions are invoked in order. + + The first successfully initialized host API that has a default input *or* output + device is used as the default PortAudio host API. This is based on the logic that + there is only one default host API, and it must contain the default input and output + devices (if defined). + + There is a platform specific file that defines paHostApiInitializers for that + platform, pa_win/pa_win_hostapis.c contains the Win32 definitions for example. +*/ +extern PaUtilHostApiInitializer *paHostApiInitializers[]; + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* PA_HOSTAPI_H */ diff --git a/extern/portaudio/src/common/pa_memorybarrier.h b/extern/portaudio/src/common/pa_memorybarrier.h new file mode 100644 index 0000000..2879ce3 --- /dev/null +++ b/extern/portaudio/src/common/pa_memorybarrier.h @@ -0,0 +1,128 @@ +/* + * $Id: pa_memorybarrier.h 1240 2007-07-17 13:05:07Z bjornroche $ + * Portable Audio I/O Library + * Memory barrier utilities + * + * Author: Bjorn Roche, XO Audio, LLC + * + * This program uses the PortAudio Portable Audio Library. + * For more information see: http://www.portaudio.com + * Copyright (c) 1999-2000 Ross Bencina and Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +/** + @file pa_memorybarrier.h + @ingroup common_src +*/ + +/**************** + * Some memory barrier primitives based on the system. + * right now only OS X, FreeBSD, and Linux are supported. In addition to providing + * memory barriers, these functions should ensure that data cached in registers + * is written out to cache where it can be snooped by other CPUs. (ie, the volatile + * keyword should not be required) + * + * the primitives that must be defined are: + * + * PaUtil_FullMemoryBarrier() + * PaUtil_ReadMemoryBarrier() + * PaUtil_WriteMemoryBarrier() + * + ****************/ + +#if defined(__APPLE__) +# include + /* Here are the memory barrier functions. Mac OS X only provides + full memory barriers, so the three types of barriers are the same, + however, these barriers are superior to compiler-based ones. */ +# define PaUtil_FullMemoryBarrier() OSMemoryBarrier() +# define PaUtil_ReadMemoryBarrier() OSMemoryBarrier() +# define PaUtil_WriteMemoryBarrier() OSMemoryBarrier() +#elif defined(__GNUC__) + /* GCC >= 4.1 has built-in intrinsics. We'll use those */ +# if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) +# define PaUtil_FullMemoryBarrier() __sync_synchronize() +# define PaUtil_ReadMemoryBarrier() __sync_synchronize() +# define PaUtil_WriteMemoryBarrier() __sync_synchronize() + /* as a fallback, GCC understands volatile asm and "memory" to mean it + * should not reorder memory read/writes */ + /* Note that it is not clear that any compiler actually defines __PPC__, + * it can probably removed safely. */ +# elif defined( __ppc__ ) || defined( __powerpc__) || defined( __PPC__ ) +# define PaUtil_FullMemoryBarrier() asm volatile("sync":::"memory") +# define PaUtil_ReadMemoryBarrier() asm volatile("sync":::"memory") +# define PaUtil_WriteMemoryBarrier() asm volatile("sync":::"memory") +# elif defined( __i386__ ) || defined( __i486__ ) || defined( __i586__ ) || \ + defined( __i686__ ) || defined( __x86_64__ ) +# define PaUtil_FullMemoryBarrier() asm volatile("mfence":::"memory") +# define PaUtil_ReadMemoryBarrier() asm volatile("lfence":::"memory") +# define PaUtil_WriteMemoryBarrier() asm volatile("sfence":::"memory") +# else +# ifdef ALLOW_SMP_DANGERS +# warning Memory barriers not defined on this system or system unknown +# warning For SMP safety, you should fix this. +# define PaUtil_FullMemoryBarrier() +# define PaUtil_ReadMemoryBarrier() +# define PaUtil_WriteMemoryBarrier() +# else +# error Memory barriers are not defined on this system. You can still compile by defining ALLOW_SMP_DANGERS, but SMP safety will not be guaranteed. +# endif +# endif +#elif (_MSC_VER >= 1400) && !defined(_WIN32_WCE) +# include +# pragma intrinsic(_ReadWriteBarrier) +# pragma intrinsic(_ReadBarrier) +# pragma intrinsic(_WriteBarrier) +/* note that MSVC intrinsics _ReadWriteBarrier(), _ReadBarrier(), _WriteBarrier() are just compiler barriers *not* memory barriers */ +# define PaUtil_FullMemoryBarrier() _ReadWriteBarrier() +# define PaUtil_ReadMemoryBarrier() _ReadBarrier() +# define PaUtil_WriteMemoryBarrier() _WriteBarrier() +#elif defined(_WIN32_WCE) +# define PaUtil_FullMemoryBarrier() +# define PaUtil_ReadMemoryBarrier() +# define PaUtil_WriteMemoryBarrier() +#elif defined(_MSC_VER) || defined(__BORLANDC__) +# define PaUtil_FullMemoryBarrier() _asm { lock add [esp], 0 } +# define PaUtil_ReadMemoryBarrier() _asm { lock add [esp], 0 } +# define PaUtil_WriteMemoryBarrier() _asm { lock add [esp], 0 } +#else +# ifdef ALLOW_SMP_DANGERS +# warning Memory barriers not defined on this system or system unknown +# warning For SMP safety, you should fix this. +# define PaUtil_FullMemoryBarrier() +# define PaUtil_ReadMemoryBarrier() +# define PaUtil_WriteMemoryBarrier() +# else +# error Memory barriers are not defined on this system. You can still compile by defining ALLOW_SMP_DANGERS, but SMP safety will not be guaranteed. +# endif +#endif diff --git a/extern/portaudio/src/common/pa_process.c b/extern/portaudio/src/common/pa_process.c new file mode 100644 index 0000000..0faf841 --- /dev/null +++ b/extern/portaudio/src/common/pa_process.c @@ -0,0 +1,1831 @@ +/* + * $Id$ + * Portable Audio I/O Library + * streamCallback <-> host buffer processing adapter + * + * Based on the Open Source API proposed by Ross Bencina + * Copyright (c) 1999-2002 Ross Bencina, Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +/** @file + @ingroup common_src + + @brief Buffer Processor implementation. +*/ + + +#include +#include /* memset() */ + +#include "pa_process.h" +#include "pa_util.h" + + +#define PA_FRAMES_PER_TEMP_BUFFER_WHEN_HOST_BUFFER_SIZE_IS_UNKNOWN_ 1024 + +#define PA_MIN_( a, b ) ( ((a)<(b)) ? (a) : (b) ) + + +/* greatest common divisor - PGCD in French */ +static unsigned long GCD( unsigned long a, unsigned long b ) +{ + return (b==0) ? a : GCD( b, a%b); +} + +/* least common multiple - PPCM in French */ +static unsigned long LCM( unsigned long a, unsigned long b ) +{ + return (a*b) / GCD(a,b); +} + +#define PA_MAX_( a, b ) (((a) > (b)) ? (a) : (b)) + +static unsigned long CalculateFrameShift( unsigned long M, unsigned long N ) +{ + unsigned long result = 0; + unsigned long i; + unsigned long lcm; + + assert( M > 0 ); + assert( N > 0 ); + + lcm = LCM( M, N ); + for( i = M; i < lcm; i += M ) + result = PA_MAX_( result, i % N ); + + return result; +} + + +PaError PaUtil_InitializeBufferProcessor( PaUtilBufferProcessor* bp, + int inputChannelCount, PaSampleFormat userInputSampleFormat, + PaSampleFormat hostInputSampleFormat, + int outputChannelCount, PaSampleFormat userOutputSampleFormat, + PaSampleFormat hostOutputSampleFormat, + double sampleRate, + PaStreamFlags streamFlags, + unsigned long framesPerUserBuffer, + unsigned long framesPerHostBuffer, + PaUtilHostBufferSizeMode hostBufferSizeMode, + PaStreamCallback *streamCallback, void *userData ) +{ + PaError result = paNoError; + PaError bytesPerSample; + unsigned long tempInputBufferSize, tempOutputBufferSize; + PaStreamFlags tempInputStreamFlags; + + if( streamFlags & paNeverDropInput ) + { + /* paNeverDropInput is only valid for full-duplex callback streams, with an unspecified number of frames per buffer. */ + if( !streamCallback || !(inputChannelCount > 0 && outputChannelCount > 0) || + framesPerUserBuffer != paFramesPerBufferUnspecified ) + return paInvalidFlag; + } + + /* initialize buffer ptrs to zero so they can be freed if necessary in error */ + bp->tempInputBuffer = 0; + bp->tempInputBufferPtrs = 0; + bp->tempOutputBuffer = 0; + bp->tempOutputBufferPtrs = 0; + + bp->framesPerUserBuffer = framesPerUserBuffer; + bp->framesPerHostBuffer = framesPerHostBuffer; + + bp->inputChannelCount = inputChannelCount; + bp->outputChannelCount = outputChannelCount; + + bp->hostBufferSizeMode = hostBufferSizeMode; + + bp->hostInputChannels[0] = bp->hostInputChannels[1] = 0; + bp->hostOutputChannels[0] = bp->hostOutputChannels[1] = 0; + + if( framesPerUserBuffer == 0 ) /* streamCallback will accept any buffer size */ + { + bp->useNonAdaptingProcess = 1; + bp->initialFramesInTempInputBuffer = 0; + bp->initialFramesInTempOutputBuffer = 0; + + if( hostBufferSizeMode == paUtilFixedHostBufferSize + || hostBufferSizeMode == paUtilBoundedHostBufferSize ) + { + bp->framesPerTempBuffer = framesPerHostBuffer; + } + else /* unknown host buffer size */ + { + bp->framesPerTempBuffer = PA_FRAMES_PER_TEMP_BUFFER_WHEN_HOST_BUFFER_SIZE_IS_UNKNOWN_; + } + } + else + { + bp->framesPerTempBuffer = framesPerUserBuffer; + + if( hostBufferSizeMode == paUtilFixedHostBufferSize + && framesPerHostBuffer % framesPerUserBuffer == 0 ) + { + bp->useNonAdaptingProcess = 1; + bp->initialFramesInTempInputBuffer = 0; + bp->initialFramesInTempOutputBuffer = 0; + } + else + { + bp->useNonAdaptingProcess = 0; + + if( inputChannelCount > 0 && outputChannelCount > 0 ) + { + /* full duplex */ + if( hostBufferSizeMode == paUtilFixedHostBufferSize ) + { + unsigned long frameShift = + CalculateFrameShift( framesPerHostBuffer, framesPerUserBuffer ); + + if( framesPerUserBuffer > framesPerHostBuffer ) + { + bp->initialFramesInTempInputBuffer = frameShift; + bp->initialFramesInTempOutputBuffer = 0; + } + else + { + bp->initialFramesInTempInputBuffer = 0; + bp->initialFramesInTempOutputBuffer = frameShift; + } + } + else /* variable host buffer size, add framesPerUserBuffer latency */ + { + bp->initialFramesInTempInputBuffer = 0; + bp->initialFramesInTempOutputBuffer = framesPerUserBuffer; + } + } + else + { + /* half duplex */ + bp->initialFramesInTempInputBuffer = 0; + bp->initialFramesInTempOutputBuffer = 0; + } + } + } + + + bp->framesInTempInputBuffer = bp->initialFramesInTempInputBuffer; + bp->framesInTempOutputBuffer = bp->initialFramesInTempOutputBuffer; + + + if( inputChannelCount > 0 ) + { + bytesPerSample = Pa_GetSampleSize( hostInputSampleFormat ); + if( bytesPerSample > 0 ) + { + bp->bytesPerHostInputSample = bytesPerSample; + } + else + { + result = bytesPerSample; + goto error; + } + + bytesPerSample = Pa_GetSampleSize( userInputSampleFormat ); + if( bytesPerSample > 0 ) + { + bp->bytesPerUserInputSample = bytesPerSample; + } + else + { + result = bytesPerSample; + goto error; + } + + /* Under the assumption that no ADC in existence delivers better than 24bits resolution, + we disable dithering when host input format is paInt32 and user format is paInt24, + since the host samples will just be padded with zeros anyway. */ + + tempInputStreamFlags = streamFlags; + if( !(tempInputStreamFlags & paDitherOff) /* dither is on */ + && (hostInputSampleFormat & paInt32) /* host input format is int32 */ + && (userInputSampleFormat & paInt24) /* user requested format is int24 */ ){ + + tempInputStreamFlags = tempInputStreamFlags | paDitherOff; + } + + bp->inputConverter = + PaUtil_SelectConverter( hostInputSampleFormat, userInputSampleFormat, tempInputStreamFlags ); + + bp->inputZeroer = PaUtil_SelectZeroer( userInputSampleFormat ); + + bp->userInputIsInterleaved = (userInputSampleFormat & paNonInterleaved)?0:1; + + bp->hostInputIsInterleaved = (hostInputSampleFormat & paNonInterleaved)?0:1; + + bp->userInputSampleFormatIsEqualToHost = ((userInputSampleFormat & ~paNonInterleaved) == (hostInputSampleFormat & ~paNonInterleaved)); + + tempInputBufferSize = + bp->framesPerTempBuffer * bp->bytesPerUserInputSample * inputChannelCount; + + bp->tempInputBuffer = PaUtil_AllocateMemory( tempInputBufferSize ); + if( bp->tempInputBuffer == 0 ) + { + result = paInsufficientMemory; + goto error; + } + + if( bp->framesInTempInputBuffer > 0 ) + memset( bp->tempInputBuffer, 0, tempInputBufferSize ); + + if( userInputSampleFormat & paNonInterleaved ) + { + bp->tempInputBufferPtrs = + (void **)PaUtil_AllocateMemory( sizeof(void*)*inputChannelCount ); + if( bp->tempInputBufferPtrs == 0 ) + { + result = paInsufficientMemory; + goto error; + } + } + + bp->hostInputChannels[0] = (PaUtilChannelDescriptor*) + PaUtil_AllocateMemory( sizeof(PaUtilChannelDescriptor) * inputChannelCount * 2); + if( bp->hostInputChannels[0] == 0 ) + { + result = paInsufficientMemory; + goto error; + } + + bp->hostInputChannels[1] = &bp->hostInputChannels[0][inputChannelCount]; + } + + if( outputChannelCount > 0 ) + { + bytesPerSample = Pa_GetSampleSize( hostOutputSampleFormat ); + if( bytesPerSample > 0 ) + { + bp->bytesPerHostOutputSample = bytesPerSample; + } + else + { + result = bytesPerSample; + goto error; + } + + bytesPerSample = Pa_GetSampleSize( userOutputSampleFormat ); + if( bytesPerSample > 0 ) + { + bp->bytesPerUserOutputSample = bytesPerSample; + } + else + { + result = bytesPerSample; + goto error; + } + + bp->outputConverter = + PaUtil_SelectConverter( userOutputSampleFormat, hostOutputSampleFormat, streamFlags ); + + bp->outputZeroer = PaUtil_SelectZeroer( hostOutputSampleFormat ); + + bp->userOutputIsInterleaved = (userOutputSampleFormat & paNonInterleaved)?0:1; + + bp->hostOutputIsInterleaved = (hostOutputSampleFormat & paNonInterleaved)?0:1; + + bp->userOutputSampleFormatIsEqualToHost = ((userOutputSampleFormat & ~paNonInterleaved) == (hostOutputSampleFormat & ~paNonInterleaved)); + + tempOutputBufferSize = + bp->framesPerTempBuffer * bp->bytesPerUserOutputSample * outputChannelCount; + + bp->tempOutputBuffer = PaUtil_AllocateMemory( tempOutputBufferSize ); + if( bp->tempOutputBuffer == 0 ) + { + result = paInsufficientMemory; + goto error; + } + + if( bp->framesInTempOutputBuffer > 0 ) + memset( bp->tempOutputBuffer, 0, tempOutputBufferSize ); + + if( userOutputSampleFormat & paNonInterleaved ) + { + bp->tempOutputBufferPtrs = + (void **)PaUtil_AllocateMemory( sizeof(void*)*outputChannelCount ); + if( bp->tempOutputBufferPtrs == 0 ) + { + result = paInsufficientMemory; + goto error; + } + } + + bp->hostOutputChannels[0] = (PaUtilChannelDescriptor*) + PaUtil_AllocateMemory( sizeof(PaUtilChannelDescriptor)*outputChannelCount * 2 ); + if( bp->hostOutputChannels[0] == 0 ) + { + result = paInsufficientMemory; + goto error; + } + + bp->hostOutputChannels[1] = &bp->hostOutputChannels[0][outputChannelCount]; + } + + PaUtil_InitializeTriangularDitherState( &bp->ditherGenerator ); + + bp->samplePeriod = 1. / sampleRate; + + bp->streamCallback = streamCallback; + bp->userData = userData; + + return result; + +error: + if( bp->tempInputBuffer ) + PaUtil_FreeMemory( bp->tempInputBuffer ); + + if( bp->tempInputBufferPtrs ) + PaUtil_FreeMemory( bp->tempInputBufferPtrs ); + + if( bp->hostInputChannels[0] ) + PaUtil_FreeMemory( bp->hostInputChannels[0] ); + + if( bp->tempOutputBuffer ) + PaUtil_FreeMemory( bp->tempOutputBuffer ); + + if( bp->tempOutputBufferPtrs ) + PaUtil_FreeMemory( bp->tempOutputBufferPtrs ); + + if( bp->hostOutputChannels[0] ) + PaUtil_FreeMemory( bp->hostOutputChannels[0] ); + + return result; +} + + +void PaUtil_TerminateBufferProcessor( PaUtilBufferProcessor* bp ) +{ + if( bp->tempInputBuffer ) + PaUtil_FreeMemory( bp->tempInputBuffer ); + + if( bp->tempInputBufferPtrs ) + PaUtil_FreeMemory( bp->tempInputBufferPtrs ); + + if( bp->hostInputChannels[0] ) + PaUtil_FreeMemory( bp->hostInputChannels[0] ); + + if( bp->tempOutputBuffer ) + PaUtil_FreeMemory( bp->tempOutputBuffer ); + + if( bp->tempOutputBufferPtrs ) + PaUtil_FreeMemory( bp->tempOutputBufferPtrs ); + + if( bp->hostOutputChannels[0] ) + PaUtil_FreeMemory( bp->hostOutputChannels[0] ); +} + + +void PaUtil_ResetBufferProcessor( PaUtilBufferProcessor* bp ) +{ + unsigned long tempInputBufferSize, tempOutputBufferSize; + + bp->framesInTempInputBuffer = bp->initialFramesInTempInputBuffer; + bp->framesInTempOutputBuffer = bp->initialFramesInTempOutputBuffer; + + if( bp->framesInTempInputBuffer > 0 ) + { + tempInputBufferSize = + bp->framesPerTempBuffer * bp->bytesPerUserInputSample * bp->inputChannelCount; + memset( bp->tempInputBuffer, 0, tempInputBufferSize ); + } + + if( bp->framesInTempOutputBuffer > 0 ) + { + tempOutputBufferSize = + bp->framesPerTempBuffer * bp->bytesPerUserOutputSample * bp->outputChannelCount; + memset( bp->tempOutputBuffer, 0, tempOutputBufferSize ); + } +} + + +unsigned long PaUtil_GetBufferProcessorInputLatencyFrames( PaUtilBufferProcessor* bp ) +{ + return bp->initialFramesInTempInputBuffer; +} + + +unsigned long PaUtil_GetBufferProcessorOutputLatencyFrames( PaUtilBufferProcessor* bp ) +{ + return bp->initialFramesInTempOutputBuffer; +} + + +void PaUtil_SetInputFrameCount( PaUtilBufferProcessor* bp, + unsigned long frameCount ) +{ + if( frameCount == 0 ) + bp->hostInputFrameCount[0] = bp->framesPerHostBuffer; + else + bp->hostInputFrameCount[0] = frameCount; +} + + +void PaUtil_SetNoInput( PaUtilBufferProcessor* bp ) +{ + assert( bp->inputChannelCount > 0 ); + + bp->hostInputChannels[0][0].data = 0; +} + + +void PaUtil_SetInputChannel( PaUtilBufferProcessor* bp, + unsigned int channel, void *data, unsigned int stride ) +{ + assert( channel < bp->inputChannelCount ); + + bp->hostInputChannels[0][channel].data = data; + bp->hostInputChannels[0][channel].stride = stride; +} + + +void PaUtil_SetInterleavedInputChannels( PaUtilBufferProcessor* bp, + unsigned int firstChannel, void *data, unsigned int channelCount ) +{ + unsigned int i; + unsigned int channel = firstChannel; + unsigned char *p = (unsigned char*)data; + + if( channelCount == 0 ) + channelCount = bp->inputChannelCount; + + assert( firstChannel < bp->inputChannelCount ); + assert( firstChannel + channelCount <= bp->inputChannelCount ); + assert( bp->hostInputIsInterleaved ); + + for( i=0; i< channelCount; ++i ) + { + bp->hostInputChannels[0][channel+i].data = p; + p += bp->bytesPerHostInputSample; + bp->hostInputChannels[0][channel+i].stride = channelCount; + } +} + + +void PaUtil_SetNonInterleavedInputChannel( PaUtilBufferProcessor* bp, + unsigned int channel, void *data ) +{ + assert( channel < bp->inputChannelCount ); + assert( !bp->hostInputIsInterleaved ); + + bp->hostInputChannels[0][channel].data = data; + bp->hostInputChannels[0][channel].stride = 1; +} + + +void PaUtil_Set2ndInputFrameCount( PaUtilBufferProcessor* bp, + unsigned long frameCount ) +{ + bp->hostInputFrameCount[1] = frameCount; +} + + +void PaUtil_Set2ndInputChannel( PaUtilBufferProcessor* bp, + unsigned int channel, void *data, unsigned int stride ) +{ + assert( channel < bp->inputChannelCount ); + + bp->hostInputChannels[1][channel].data = data; + bp->hostInputChannels[1][channel].stride = stride; +} + + +void PaUtil_Set2ndInterleavedInputChannels( PaUtilBufferProcessor* bp, + unsigned int firstChannel, void *data, unsigned int channelCount ) +{ + unsigned int i; + unsigned int channel = firstChannel; + unsigned char *p = (unsigned char*)data; + + if( channelCount == 0 ) + channelCount = bp->inputChannelCount; + + assert( firstChannel < bp->inputChannelCount ); + assert( firstChannel + channelCount <= bp->inputChannelCount ); + assert( bp->hostInputIsInterleaved ); + + for( i=0; i< channelCount; ++i ) + { + bp->hostInputChannels[1][channel+i].data = p; + p += bp->bytesPerHostInputSample; + bp->hostInputChannels[1][channel+i].stride = channelCount; + } +} + + +void PaUtil_Set2ndNonInterleavedInputChannel( PaUtilBufferProcessor* bp, + unsigned int channel, void *data ) +{ + assert( channel < bp->inputChannelCount ); + assert( !bp->hostInputIsInterleaved ); + + bp->hostInputChannels[1][channel].data = data; + bp->hostInputChannels[1][channel].stride = 1; +} + + +void PaUtil_SetOutputFrameCount( PaUtilBufferProcessor* bp, + unsigned long frameCount ) +{ + if( frameCount == 0 ) + bp->hostOutputFrameCount[0] = bp->framesPerHostBuffer; + else + bp->hostOutputFrameCount[0] = frameCount; +} + + +void PaUtil_SetNoOutput( PaUtilBufferProcessor* bp ) +{ + assert( bp->outputChannelCount > 0 ); + + bp->hostOutputChannels[0][0].data = 0; + + /* note that only NonAdaptingProcess is able to deal with no output at this stage. not implemented for AdaptingProcess */ +} + + +void PaUtil_SetOutputChannel( PaUtilBufferProcessor* bp, + unsigned int channel, void *data, unsigned int stride ) +{ + assert( channel < bp->outputChannelCount ); + assert( data != NULL ); + + bp->hostOutputChannels[0][channel].data = data; + bp->hostOutputChannels[0][channel].stride = stride; +} + + +void PaUtil_SetInterleavedOutputChannels( PaUtilBufferProcessor* bp, + unsigned int firstChannel, void *data, unsigned int channelCount ) +{ + unsigned int i; + unsigned int channel = firstChannel; + unsigned char *p = (unsigned char*)data; + + if( channelCount == 0 ) + channelCount = bp->outputChannelCount; + + assert( firstChannel < bp->outputChannelCount ); + assert( firstChannel + channelCount <= bp->outputChannelCount ); + assert( bp->hostOutputIsInterleaved ); + + for( i=0; i< channelCount; ++i ) + { + PaUtil_SetOutputChannel( bp, channel + i, p, channelCount ); + p += bp->bytesPerHostOutputSample; + } +} + + +void PaUtil_SetNonInterleavedOutputChannel( PaUtilBufferProcessor* bp, + unsigned int channel, void *data ) +{ + assert( channel < bp->outputChannelCount ); + assert( !bp->hostOutputIsInterleaved ); + + PaUtil_SetOutputChannel( bp, channel, data, 1 ); +} + + +void PaUtil_Set2ndOutputFrameCount( PaUtilBufferProcessor* bp, + unsigned long frameCount ) +{ + bp->hostOutputFrameCount[1] = frameCount; +} + + +void PaUtil_Set2ndOutputChannel( PaUtilBufferProcessor* bp, + unsigned int channel, void *data, unsigned int stride ) +{ + assert( channel < bp->outputChannelCount ); + assert( data != NULL ); + + bp->hostOutputChannels[1][channel].data = data; + bp->hostOutputChannels[1][channel].stride = stride; +} + + +void PaUtil_Set2ndInterleavedOutputChannels( PaUtilBufferProcessor* bp, + unsigned int firstChannel, void *data, unsigned int channelCount ) +{ + unsigned int i; + unsigned int channel = firstChannel; + unsigned char *p = (unsigned char*)data; + + if( channelCount == 0 ) + channelCount = bp->outputChannelCount; + + assert( firstChannel < bp->outputChannelCount ); + assert( firstChannel + channelCount <= bp->outputChannelCount ); + assert( bp->hostOutputIsInterleaved ); + + for( i=0; i< channelCount; ++i ) + { + PaUtil_Set2ndOutputChannel( bp, channel + i, p, channelCount ); + p += bp->bytesPerHostOutputSample; + } +} + + +void PaUtil_Set2ndNonInterleavedOutputChannel( PaUtilBufferProcessor* bp, + unsigned int channel, void *data ) +{ + assert( channel < bp->outputChannelCount ); + assert( !bp->hostOutputIsInterleaved ); + + PaUtil_Set2ndOutputChannel( bp, channel, data, 1 ); +} + + +void PaUtil_BeginBufferProcessing( PaUtilBufferProcessor* bp, + PaStreamCallbackTimeInfo* timeInfo, PaStreamCallbackFlags callbackStatusFlags ) +{ + bp->timeInfo = timeInfo; + + /* the first streamCallback will be called to process samples which are + currently in the input buffer before the ones starting at the timeInfo time */ + + bp->timeInfo->inputBufferAdcTime -= bp->framesInTempInputBuffer * bp->samplePeriod; + + /* We just pass through timeInfo->currentTime provided by the caller. This is + not strictly conformant to the word of the spec, since the buffer processor + might call the callback multiple times, and we never refresh currentTime. */ + + /* the first streamCallback will be called to generate samples which will be + outputted after the frames currently in the output buffer have been + outputted. */ + bp->timeInfo->outputBufferDacTime += bp->framesInTempOutputBuffer * bp->samplePeriod; + + bp->callbackStatusFlags = callbackStatusFlags; + + bp->hostInputFrameCount[1] = 0; + bp->hostOutputFrameCount[1] = 0; +} + + +/* + NonAdaptingProcess() is a simple buffer copying adaptor that can handle + both full and half duplex copies. It processes framesToProcess frames, + broken into blocks bp->framesPerTempBuffer long. + This routine can be used when the streamCallback doesn't care what length + the buffers are, or when framesToProcess is an integer multiple of + bp->framesPerTempBuffer, in which case streamCallback will always be called + with bp->framesPerTempBuffer samples. +*/ +static unsigned long NonAdaptingProcess( PaUtilBufferProcessor *bp, + int *streamCallbackResult, + PaUtilChannelDescriptor *hostInputChannels, + PaUtilChannelDescriptor *hostOutputChannels, + unsigned long framesToProcess ) +{ + void *userInput, *userOutput; + unsigned char *srcBytePtr, *destBytePtr; + unsigned int srcSampleStrideSamples; /* stride from one sample to the next within a channel, in samples */ + unsigned int srcChannelStrideBytes; /* stride from one channel to the next, in bytes */ + unsigned int destSampleStrideSamples; /* stride from one sample to the next within a channel, in samples */ + unsigned int destChannelStrideBytes; /* stride from one channel to the next, in bytes */ + unsigned int i; + unsigned long frameCount; + unsigned long framesToGo = framesToProcess; + unsigned long framesProcessed = 0; + int skipOutputConvert = 0; + int skipInputConvert = 0; + + + if( *streamCallbackResult == paContinue ) + { + do + { + frameCount = PA_MIN_( bp->framesPerTempBuffer, framesToGo ); + + /* configure user input buffer and convert input data (host -> user) */ + if( bp->inputChannelCount == 0 ) + { + /* no input */ + userInput = 0; + } + else /* there are input channels */ + { + + destBytePtr = (unsigned char *)bp->tempInputBuffer; + + if( bp->userInputIsInterleaved ) + { + destSampleStrideSamples = bp->inputChannelCount; + destChannelStrideBytes = bp->bytesPerUserInputSample; + + /* process host buffer directly, or use temp buffer if formats differ or host buffer non-interleaved, + * or if num channels differs between the host (set in stride) and the user (eg with some Alsa hw:) */ + if( bp->userInputSampleFormatIsEqualToHost && bp->hostInputIsInterleaved + && bp->hostInputChannels[0][0].data && bp->inputChannelCount == hostInputChannels[0].stride ) + { + userInput = hostInputChannels[0].data; + destBytePtr = (unsigned char *)hostInputChannels[0].data; + skipInputConvert = 1; + } + else + { + userInput = bp->tempInputBuffer; + } + } + else /* user input is not interleaved */ + { + destSampleStrideSamples = 1; + destChannelStrideBytes = frameCount * bp->bytesPerUserInputSample; + + /* setup non-interleaved ptrs */ + if( bp->userInputSampleFormatIsEqualToHost && !bp->hostInputIsInterleaved && bp->hostInputChannels[0][0].data ) + { + for( i=0; iinputChannelCount; ++i ) + { + bp->tempInputBufferPtrs[i] = hostInputChannels[i].data; + } + skipInputConvert = 1; + } + else + { + for( i=0; iinputChannelCount; ++i ) + { + bp->tempInputBufferPtrs[i] = ((unsigned char*)bp->tempInputBuffer) + + i * bp->bytesPerUserInputSample * frameCount; + } + } + + userInput = bp->tempInputBufferPtrs; + } + + if( !bp->hostInputChannels[0][0].data ) + { + /* no input was supplied (see PaUtil_SetNoInput), so + zero the input buffer */ + + for( i=0; iinputChannelCount; ++i ) + { + bp->inputZeroer( destBytePtr, destSampleStrideSamples, frameCount ); + destBytePtr += destChannelStrideBytes; /* skip to next destination channel */ + } + } + else + { + if( skipInputConvert ) + { + for( i=0; iinputChannelCount; ++i ) + { + /* advance src ptr for next iteration */ + hostInputChannels[i].data = ((unsigned char*)hostInputChannels[i].data) + + frameCount * hostInputChannels[i].stride * bp->bytesPerHostInputSample; + } + } + else + { + for( i=0; iinputChannelCount; ++i ) + { + bp->inputConverter( destBytePtr, destSampleStrideSamples, + hostInputChannels[i].data, + hostInputChannels[i].stride, + frameCount, &bp->ditherGenerator ); + + destBytePtr += destChannelStrideBytes; /* skip to next destination channel */ + + /* advance src ptr for next iteration */ + hostInputChannels[i].data = ((unsigned char*)hostInputChannels[i].data) + + frameCount * hostInputChannels[i].stride * bp->bytesPerHostInputSample; + } + } + } + } + + /* configure user output buffer */ + if( bp->outputChannelCount == 0 ) + { + /* no output */ + userOutput = 0; + } + else /* there are output channels */ + { + if( bp->userOutputIsInterleaved ) + { + /* process host buffer directly, or use temp buffer if formats differ or host buffer non-interleaved, + * or if num channels differs between the host (set in stride) and the user (eg with some Alsa hw:) */ + if( bp->userOutputSampleFormatIsEqualToHost && bp->hostOutputIsInterleaved + && bp->outputChannelCount == hostOutputChannels[0].stride ) + { + userOutput = hostOutputChannels[0].data; + skipOutputConvert = 1; + } + else + { + userOutput = bp->tempOutputBuffer; + } + } + else /* user output is not interleaved */ + { + if( bp->userOutputSampleFormatIsEqualToHost && !bp->hostOutputIsInterleaved ) + { + for( i=0; ioutputChannelCount; ++i ) + { + bp->tempOutputBufferPtrs[i] = hostOutputChannels[i].data; + } + skipOutputConvert = 1; + } + else + { + for( i=0; ioutputChannelCount; ++i ) + { + bp->tempOutputBufferPtrs[i] = ((unsigned char*)bp->tempOutputBuffer) + + i * bp->bytesPerUserOutputSample * frameCount; + } + } + + userOutput = bp->tempOutputBufferPtrs; + } + } + + *streamCallbackResult = bp->streamCallback( userInput, userOutput, + frameCount, bp->timeInfo, bp->callbackStatusFlags, bp->userData ); + + if( *streamCallbackResult == paAbort ) + { + /* callback returned paAbort, don't advance framesProcessed + and framesToGo, they will be handled below */ + } + else + { + bp->timeInfo->inputBufferAdcTime += frameCount * bp->samplePeriod; + bp->timeInfo->outputBufferDacTime += frameCount * bp->samplePeriod; + + /* convert output data (user -> host) */ + + if( bp->outputChannelCount != 0 && bp->hostOutputChannels[0][0].data ) + { + if( skipOutputConvert ) + { + for( i=0; ioutputChannelCount; ++i ) + { + /* advance dest ptr for next iteration */ + hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) + + frameCount * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample; + } + } + else + { + + srcBytePtr = (unsigned char *)bp->tempOutputBuffer; + + if( bp->userOutputIsInterleaved ) + { + srcSampleStrideSamples = bp->outputChannelCount; + srcChannelStrideBytes = bp->bytesPerUserOutputSample; + } + else /* user output is not interleaved */ + { + srcSampleStrideSamples = 1; + srcChannelStrideBytes = frameCount * bp->bytesPerUserOutputSample; + } + + for( i=0; ioutputChannelCount; ++i ) + { + bp->outputConverter( hostOutputChannels[i].data, + hostOutputChannels[i].stride, + srcBytePtr, srcSampleStrideSamples, + frameCount, &bp->ditherGenerator ); + + srcBytePtr += srcChannelStrideBytes; /* skip to next source channel */ + + /* advance dest ptr for next iteration */ + hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) + + frameCount * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample; + } + } + } + + framesProcessed += frameCount; + + framesToGo -= frameCount; + } + } + while( framesToGo > 0 && *streamCallbackResult == paContinue ); + } + + if( framesToGo > 0 ) + { + /* zero any remaining frames output. There will only be remaining frames + if the callback has returned paComplete or paAbort */ + + frameCount = framesToGo; + + if( bp->outputChannelCount != 0 && bp->hostOutputChannels[0][0].data ) + { + for( i=0; ioutputChannelCount; ++i ) + { + bp->outputZeroer( hostOutputChannels[i].data, + hostOutputChannels[i].stride, + frameCount ); + + /* advance dest ptr for next iteration */ + hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) + + frameCount * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample; + } + } + + framesProcessed += frameCount; + } + + return framesProcessed; +} + + +/* + AdaptingInputOnlyProcess() is a half duplex input buffer processor. It + converts data from the input buffers into the temporary input buffer, + when the temporary input buffer is full, it calls the streamCallback. +*/ +static unsigned long AdaptingInputOnlyProcess( PaUtilBufferProcessor *bp, + int *streamCallbackResult, + PaUtilChannelDescriptor *hostInputChannels, + unsigned long framesToProcess ) +{ + void *userInput, *userOutput; + unsigned char *destBytePtr; + unsigned int destSampleStrideSamples; /* stride from one sample to the next within a channel, in samples */ + unsigned int destChannelStrideBytes; /* stride from one channel to the next, in bytes */ + unsigned int i; + unsigned long frameCount; + unsigned long framesToGo = framesToProcess; + unsigned long framesProcessed = 0; + + userOutput = 0; + + do + { + frameCount = ( bp->framesInTempInputBuffer + framesToGo > bp->framesPerUserBuffer ) + ? ( bp->framesPerUserBuffer - bp->framesInTempInputBuffer ) + : framesToGo; + + /* convert frameCount samples into temp buffer */ + + if( bp->userInputIsInterleaved ) + { + destBytePtr = ((unsigned char*)bp->tempInputBuffer) + + bp->bytesPerUserInputSample * bp->inputChannelCount * + bp->framesInTempInputBuffer; + + destSampleStrideSamples = bp->inputChannelCount; + destChannelStrideBytes = bp->bytesPerUserInputSample; + + userInput = bp->tempInputBuffer; + } + else /* user input is not interleaved */ + { + destBytePtr = ((unsigned char*)bp->tempInputBuffer) + + bp->bytesPerUserInputSample * bp->framesInTempInputBuffer; + + destSampleStrideSamples = 1; + destChannelStrideBytes = bp->framesPerUserBuffer * bp->bytesPerUserInputSample; + + /* setup non-interleaved ptrs */ + for( i=0; iinputChannelCount; ++i ) + { + bp->tempInputBufferPtrs[i] = ((unsigned char*)bp->tempInputBuffer) + + i * bp->bytesPerUserInputSample * bp->framesPerUserBuffer; + } + + userInput = bp->tempInputBufferPtrs; + } + + for( i=0; iinputChannelCount; ++i ) + { + bp->inputConverter( destBytePtr, destSampleStrideSamples, + hostInputChannels[i].data, + hostInputChannels[i].stride, + frameCount, &bp->ditherGenerator ); + + destBytePtr += destChannelStrideBytes; /* skip to next destination channel */ + + /* advance src ptr for next iteration */ + hostInputChannels[i].data = ((unsigned char*)hostInputChannels[i].data) + + frameCount * hostInputChannels[i].stride * bp->bytesPerHostInputSample; + } + + bp->framesInTempInputBuffer += frameCount; + + if( bp->framesInTempInputBuffer == bp->framesPerUserBuffer ) + { + /** + @todo (non-critical optimisation) + The conditional below implements the continue/complete/abort mechanism + simply by continuing on iterating through the input buffer, but not + passing the data to the callback. With care, the outer loop could be + terminated earlier, thus some unneeded conversion cycles would be + saved. + */ + if( *streamCallbackResult == paContinue ) + { + bp->timeInfo->outputBufferDacTime = 0; + + *streamCallbackResult = bp->streamCallback( userInput, userOutput, + bp->framesPerUserBuffer, bp->timeInfo, + bp->callbackStatusFlags, bp->userData ); + + bp->timeInfo->inputBufferAdcTime += bp->framesPerUserBuffer * bp->samplePeriod; + } + + bp->framesInTempInputBuffer = 0; + } + + framesProcessed += frameCount; + + framesToGo -= frameCount; + }while( framesToGo > 0 ); + + return framesProcessed; +} + + +/* + AdaptingOutputOnlyProcess() is a half duplex output buffer processor. + It converts data from the temporary output buffer, to the output buffers, + when the temporary output buffer is empty, it calls the streamCallback. +*/ +static unsigned long AdaptingOutputOnlyProcess( PaUtilBufferProcessor *bp, + int *streamCallbackResult, + PaUtilChannelDescriptor *hostOutputChannels, + unsigned long framesToProcess ) +{ + void *userInput, *userOutput; + unsigned char *srcBytePtr; + unsigned int srcSampleStrideSamples; /* stride from one sample to the next within a channel, in samples */ + unsigned int srcChannelStrideBytes; /* stride from one channel to the next, in bytes */ + unsigned int i; + unsigned long frameCount; + unsigned long framesToGo = framesToProcess; + unsigned long framesProcessed = 0; + + do + { + if( bp->framesInTempOutputBuffer == 0 && *streamCallbackResult == paContinue ) + { + userInput = 0; + + /* setup userOutput */ + if( bp->userOutputIsInterleaved ) + { + userOutput = bp->tempOutputBuffer; + } + else /* user output is not interleaved */ + { + for( i = 0; i < bp->outputChannelCount; ++i ) + { + bp->tempOutputBufferPtrs[i] = ((unsigned char*)bp->tempOutputBuffer) + + i * bp->framesPerUserBuffer * bp->bytesPerUserOutputSample; + } + + userOutput = bp->tempOutputBufferPtrs; + } + + bp->timeInfo->inputBufferAdcTime = 0; + + *streamCallbackResult = bp->streamCallback( userInput, userOutput, + bp->framesPerUserBuffer, bp->timeInfo, + bp->callbackStatusFlags, bp->userData ); + + if( *streamCallbackResult == paAbort ) + { + /* if the callback returned paAbort, we disregard its output */ + } + else + { + bp->timeInfo->outputBufferDacTime += bp->framesPerUserBuffer * bp->samplePeriod; + + bp->framesInTempOutputBuffer = bp->framesPerUserBuffer; + } + } + + if( bp->framesInTempOutputBuffer > 0 ) + { + /* convert frameCount frames from user buffer to host buffer */ + + frameCount = PA_MIN_( bp->framesInTempOutputBuffer, framesToGo ); + + if( bp->userOutputIsInterleaved ) + { + srcBytePtr = ((unsigned char*)bp->tempOutputBuffer) + + bp->bytesPerUserOutputSample * bp->outputChannelCount * + (bp->framesPerUserBuffer - bp->framesInTempOutputBuffer); + + srcSampleStrideSamples = bp->outputChannelCount; + srcChannelStrideBytes = bp->bytesPerUserOutputSample; + } + else /* user output is not interleaved */ + { + srcBytePtr = ((unsigned char*)bp->tempOutputBuffer) + + bp->bytesPerUserOutputSample * + (bp->framesPerUserBuffer - bp->framesInTempOutputBuffer); + + srcSampleStrideSamples = 1; + srcChannelStrideBytes = bp->framesPerUserBuffer * bp->bytesPerUserOutputSample; + } + + for( i=0; ioutputChannelCount; ++i ) + { + bp->outputConverter( hostOutputChannels[i].data, + hostOutputChannels[i].stride, + srcBytePtr, srcSampleStrideSamples, + frameCount, &bp->ditherGenerator ); + + srcBytePtr += srcChannelStrideBytes; /* skip to next source channel */ + + /* advance dest ptr for next iteration */ + hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) + + frameCount * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample; + } + + bp->framesInTempOutputBuffer -= frameCount; + } + else + { + /* no more user data is available because the callback has returned + paComplete or paAbort. Fill the remainder of the host buffer + with zeros. + */ + + frameCount = framesToGo; + + for( i=0; ioutputChannelCount; ++i ) + { + bp->outputZeroer( hostOutputChannels[i].data, + hostOutputChannels[i].stride, + frameCount ); + + /* advance dest ptr for next iteration */ + hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) + + frameCount * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample; + } + } + + framesProcessed += frameCount; + + framesToGo -= frameCount; + + }while( framesToGo > 0 ); + + return framesProcessed; +} + +/* CopyTempOutputBuffersToHostOutputBuffers is called from AdaptingProcess to copy frames from + tempOutputBuffer to hostOutputChannels. This includes data conversion + and interleaving. +*/ +static void CopyTempOutputBuffersToHostOutputBuffers( PaUtilBufferProcessor *bp) +{ + unsigned long maxFramesToCopy; + PaUtilChannelDescriptor *hostOutputChannels; + unsigned int frameCount; + unsigned char *srcBytePtr; + unsigned int srcSampleStrideSamples; /* stride from one sample to the next within a channel, in samples */ + unsigned int srcChannelStrideBytes; /* stride from one channel to the next, in bytes */ + unsigned int i; + + /* copy frames from user to host output buffers */ + while( bp->framesInTempOutputBuffer > 0 && + ((bp->hostOutputFrameCount[0] + bp->hostOutputFrameCount[1]) > 0) ) + { + maxFramesToCopy = bp->framesInTempOutputBuffer; + + /* select the output buffer set (1st or 2nd) */ + if( bp->hostOutputFrameCount[0] > 0 ) + { + hostOutputChannels = bp->hostOutputChannels[0]; + frameCount = PA_MIN_( bp->hostOutputFrameCount[0], maxFramesToCopy ); + } + else + { + hostOutputChannels = bp->hostOutputChannels[1]; + frameCount = PA_MIN_( bp->hostOutputFrameCount[1], maxFramesToCopy ); + } + + if( bp->userOutputIsInterleaved ) + { + srcBytePtr = ((unsigned char*)bp->tempOutputBuffer) + + bp->bytesPerUserOutputSample * bp->outputChannelCount * + (bp->framesPerUserBuffer - bp->framesInTempOutputBuffer); + + srcSampleStrideSamples = bp->outputChannelCount; + srcChannelStrideBytes = bp->bytesPerUserOutputSample; + } + else /* user output is not interleaved */ + { + srcBytePtr = ((unsigned char*)bp->tempOutputBuffer) + + bp->bytesPerUserOutputSample * + (bp->framesPerUserBuffer - bp->framesInTempOutputBuffer); + + srcSampleStrideSamples = 1; + srcChannelStrideBytes = bp->framesPerUserBuffer * bp->bytesPerUserOutputSample; + } + + for( i=0; ioutputChannelCount; ++i ) + { + assert( hostOutputChannels[i].data != NULL ); + bp->outputConverter( hostOutputChannels[i].data, + hostOutputChannels[i].stride, + srcBytePtr, srcSampleStrideSamples, + frameCount, &bp->ditherGenerator ); + + srcBytePtr += srcChannelStrideBytes; /* skip to next source channel */ + + /* advance dest ptr for next iteration */ + hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) + + frameCount * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample; + } + + if( bp->hostOutputFrameCount[0] > 0 ) + bp->hostOutputFrameCount[0] -= frameCount; + else + bp->hostOutputFrameCount[1] -= frameCount; + + bp->framesInTempOutputBuffer -= frameCount; + } +} + +/* + AdaptingProcess is a full duplex adapting buffer processor. It converts + data from the temporary output buffer into the host output buffers, then + from the host input buffers into the temporary input buffers. Calling the + streamCallback when necessary. + When processPartialUserBuffers is 0, all available input data will be + consumed and all available output space will be filled. When + processPartialUserBuffers is non-zero, as many full user buffers + as possible will be processed, but partial buffers will not be consumed. +*/ +static unsigned long AdaptingProcess( PaUtilBufferProcessor *bp, + int *streamCallbackResult, int processPartialUserBuffers ) +{ + void *userInput, *userOutput; + unsigned long framesProcessed = 0; + unsigned long framesAvailable; + unsigned long endProcessingMinFrameCount; + unsigned long maxFramesToCopy; + PaUtilChannelDescriptor *hostInputChannels, *hostOutputChannels; + unsigned int frameCount; + unsigned char *destBytePtr; + unsigned int destSampleStrideSamples; /* stride from one sample to the next within a channel, in samples */ + unsigned int destChannelStrideBytes; /* stride from one channel to the next, in bytes */ + unsigned int i, j; + + + framesAvailable = bp->hostInputFrameCount[0] + bp->hostInputFrameCount[1];/* this is assumed to be the same as the output buffer's frame count */ + + if( processPartialUserBuffers ) + endProcessingMinFrameCount = 0; + else + endProcessingMinFrameCount = (bp->framesPerUserBuffer - 1); + + /* Fill host output with remaining frames in user output (tempOutputBuffer) */ + CopyTempOutputBuffersToHostOutputBuffers( bp ); + + while( framesAvailable > endProcessingMinFrameCount ) + { + + if( bp->framesInTempOutputBuffer == 0 && *streamCallbackResult != paContinue ) + { + /* the callback will not be called any more, so zero what remains + of the host output buffers */ + + for( i=0; i<2; ++i ) + { + frameCount = bp->hostOutputFrameCount[i]; + if( frameCount > 0 ) + { + hostOutputChannels = bp->hostOutputChannels[i]; + + for( j=0; joutputChannelCount; ++j ) + { + bp->outputZeroer( hostOutputChannels[j].data, + hostOutputChannels[j].stride, + frameCount ); + + /* advance dest ptr for next iteration */ + hostOutputChannels[j].data = ((unsigned char*)hostOutputChannels[j].data) + + frameCount * hostOutputChannels[j].stride * bp->bytesPerHostOutputSample; + } + bp->hostOutputFrameCount[i] = 0; + } + } + } + + + /* copy frames from host to user input buffers */ + while( bp->framesInTempInputBuffer < bp->framesPerUserBuffer && + ((bp->hostInputFrameCount[0] + bp->hostInputFrameCount[1]) > 0) ) + { + maxFramesToCopy = bp->framesPerUserBuffer - bp->framesInTempInputBuffer; + + /* select the input buffer set (1st or 2nd) */ + if( bp->hostInputFrameCount[0] > 0 ) + { + hostInputChannels = bp->hostInputChannels[0]; + frameCount = PA_MIN_( bp->hostInputFrameCount[0], maxFramesToCopy ); + } + else + { + hostInputChannels = bp->hostInputChannels[1]; + frameCount = PA_MIN_( bp->hostInputFrameCount[1], maxFramesToCopy ); + } + + /* configure conversion destination pointers */ + if( bp->userInputIsInterleaved ) + { + destBytePtr = ((unsigned char*)bp->tempInputBuffer) + + bp->bytesPerUserInputSample * bp->inputChannelCount * + bp->framesInTempInputBuffer; + + destSampleStrideSamples = bp->inputChannelCount; + destChannelStrideBytes = bp->bytesPerUserInputSample; + } + else /* user input is not interleaved */ + { + destBytePtr = ((unsigned char*)bp->tempInputBuffer) + + bp->bytesPerUserInputSample * bp->framesInTempInputBuffer; + + destSampleStrideSamples = 1; + destChannelStrideBytes = bp->framesPerUserBuffer * bp->bytesPerUserInputSample; + } + + for( i=0; iinputChannelCount; ++i ) + { + bp->inputConverter( destBytePtr, destSampleStrideSamples, + hostInputChannels[i].data, + hostInputChannels[i].stride, + frameCount, &bp->ditherGenerator ); + + destBytePtr += destChannelStrideBytes; /* skip to next destination channel */ + + /* advance src ptr for next iteration */ + hostInputChannels[i].data = ((unsigned char*)hostInputChannels[i].data) + + frameCount * hostInputChannels[i].stride * bp->bytesPerHostInputSample; + } + + if( bp->hostInputFrameCount[0] > 0 ) + bp->hostInputFrameCount[0] -= frameCount; + else + bp->hostInputFrameCount[1] -= frameCount; + + bp->framesInTempInputBuffer += frameCount; + + /* update framesAvailable and framesProcessed based on input consumed + unless something is very wrong this will also correspond to the + amount of output generated */ + framesAvailable -= frameCount; + framesProcessed += frameCount; + } + + /* call streamCallback */ + if( bp->framesInTempInputBuffer == bp->framesPerUserBuffer && + bp->framesInTempOutputBuffer == 0 ) + { + if( *streamCallbackResult == paContinue ) + { + /* setup userInput */ + if( bp->userInputIsInterleaved ) + { + userInput = bp->tempInputBuffer; + } + else /* user input is not interleaved */ + { + for( i = 0; i < bp->inputChannelCount; ++i ) + { + bp->tempInputBufferPtrs[i] = ((unsigned char*)bp->tempInputBuffer) + + i * bp->framesPerUserBuffer * bp->bytesPerUserInputSample; + } + + userInput = bp->tempInputBufferPtrs; + } + + /* setup userOutput */ + if( bp->userOutputIsInterleaved ) + { + userOutput = bp->tempOutputBuffer; + } + else /* user output is not interleaved */ + { + for( i = 0; i < bp->outputChannelCount; ++i ) + { + bp->tempOutputBufferPtrs[i] = ((unsigned char*)bp->tempOutputBuffer) + + i * bp->framesPerUserBuffer * bp->bytesPerUserOutputSample; + } + + userOutput = bp->tempOutputBufferPtrs; + } + + /* call streamCallback */ + + *streamCallbackResult = bp->streamCallback( userInput, userOutput, + bp->framesPerUserBuffer, bp->timeInfo, + bp->callbackStatusFlags, bp->userData ); + + bp->timeInfo->inputBufferAdcTime += bp->framesPerUserBuffer * bp->samplePeriod; + bp->timeInfo->outputBufferDacTime += bp->framesPerUserBuffer * bp->samplePeriod; + + bp->framesInTempInputBuffer = 0; + + if( *streamCallbackResult == paAbort ) + bp->framesInTempOutputBuffer = 0; + else + bp->framesInTempOutputBuffer = bp->framesPerUserBuffer; + } + else + { + /* paComplete or paAbort has already been called. */ + + bp->framesInTempInputBuffer = 0; + } + } + + /* copy frames from user (tempOutputBuffer) to host output buffers (hostOutputChannels) + Means to process the user output provided by the callback. Has to be called after + each callback. */ + CopyTempOutputBuffersToHostOutputBuffers( bp ); + + } + + return framesProcessed; +} + + +unsigned long PaUtil_EndBufferProcessing( PaUtilBufferProcessor* bp, int *streamCallbackResult ) +{ + unsigned long framesToProcess, framesToGo; + unsigned long framesProcessed = 0; + + if( bp->inputChannelCount != 0 && bp->outputChannelCount != 0 + && bp->hostInputChannels[0][0].data /* input was supplied (see PaUtil_SetNoInput) */ + && bp->hostOutputChannels[0][0].data /* output was supplied (see PaUtil_SetNoOutput) */ ) + { + assert( (bp->hostInputFrameCount[0] + bp->hostInputFrameCount[1]) == + (bp->hostOutputFrameCount[0] + bp->hostOutputFrameCount[1]) ); + } + + assert( *streamCallbackResult == paContinue + || *streamCallbackResult == paComplete + || *streamCallbackResult == paAbort ); /* don't forget to pass in a valid callback result value */ + + if( bp->useNonAdaptingProcess ) + { + if( bp->inputChannelCount != 0 && bp->outputChannelCount != 0 ) + { + /* full duplex non-adapting process, splice buffers if they are + different lengths */ + + framesToGo = bp->hostOutputFrameCount[0] + bp->hostOutputFrameCount[1]; /* relies on assert above for input/output equivalence */ + + do{ + unsigned long noInputInputFrameCount; + unsigned long *hostInputFrameCount; + PaUtilChannelDescriptor *hostInputChannels; + unsigned long noOutputOutputFrameCount; + unsigned long *hostOutputFrameCount; + PaUtilChannelDescriptor *hostOutputChannels; + unsigned long framesProcessedThisIteration; + + if( !bp->hostInputChannels[0][0].data ) + { + /* no input was supplied (see PaUtil_SetNoInput) + NonAdaptingProcess knows how to deal with this + */ + noInputInputFrameCount = framesToGo; + hostInputFrameCount = &noInputInputFrameCount; + hostInputChannels = 0; + } + else if( bp->hostInputFrameCount[0] != 0 ) + { + hostInputFrameCount = &bp->hostInputFrameCount[0]; + hostInputChannels = bp->hostInputChannels[0]; + } + else + { + hostInputFrameCount = &bp->hostInputFrameCount[1]; + hostInputChannels = bp->hostInputChannels[1]; + } + + if( !bp->hostOutputChannels[0][0].data ) + { + /* no output was supplied (see PaUtil_SetNoOutput) + NonAdaptingProcess knows how to deal with this + */ + noOutputOutputFrameCount = framesToGo; + hostOutputFrameCount = &noOutputOutputFrameCount; + hostOutputChannels = 0; + } + if( bp->hostOutputFrameCount[0] != 0 ) + { + hostOutputFrameCount = &bp->hostOutputFrameCount[0]; + hostOutputChannels = bp->hostOutputChannels[0]; + } + else + { + hostOutputFrameCount = &bp->hostOutputFrameCount[1]; + hostOutputChannels = bp->hostOutputChannels[1]; + } + + framesToProcess = PA_MIN_( *hostInputFrameCount, + *hostOutputFrameCount ); + + assert( framesToProcess != 0 ); + + framesProcessedThisIteration = NonAdaptingProcess( bp, streamCallbackResult, + hostInputChannels, hostOutputChannels, + framesToProcess ); + + *hostInputFrameCount -= framesProcessedThisIteration; + *hostOutputFrameCount -= framesProcessedThisIteration; + + framesProcessed += framesProcessedThisIteration; + framesToGo -= framesProcessedThisIteration; + + }while( framesToGo > 0 ); + } + else + { + /* half duplex non-adapting process, just process 1st and 2nd buffer */ + /* process first buffer */ + + framesToProcess = (bp->inputChannelCount != 0) + ? bp->hostInputFrameCount[0] + : bp->hostOutputFrameCount[0]; + + framesProcessed = NonAdaptingProcess( bp, streamCallbackResult, + bp->hostInputChannels[0], bp->hostOutputChannels[0], + framesToProcess ); + + /* process second buffer if provided */ + + framesToProcess = (bp->inputChannelCount != 0) + ? bp->hostInputFrameCount[1] + : bp->hostOutputFrameCount[1]; + if( framesToProcess > 0 ) + { + framesProcessed += NonAdaptingProcess( bp, streamCallbackResult, + bp->hostInputChannels[1], bp->hostOutputChannels[1], + framesToProcess ); + } + } + } + else /* block adaption necessary*/ + { + + if( bp->inputChannelCount != 0 && bp->outputChannelCount != 0 ) + { + /* full duplex */ + + if( bp->hostBufferSizeMode == paUtilVariableHostBufferSizePartialUsageAllowed ) + { + framesProcessed = AdaptingProcess( bp, streamCallbackResult, + 0 /* dont process partial user buffers */ ); + } + else + { + framesProcessed = AdaptingProcess( bp, streamCallbackResult, + 1 /* process partial user buffers */ ); + } + } + else if( bp->inputChannelCount != 0 ) + { + /* input only */ + framesToProcess = bp->hostInputFrameCount[0]; + + framesProcessed = AdaptingInputOnlyProcess( bp, streamCallbackResult, + bp->hostInputChannels[0], framesToProcess ); + + framesToProcess = bp->hostInputFrameCount[1]; + if( framesToProcess > 0 ) + { + framesProcessed += AdaptingInputOnlyProcess( bp, streamCallbackResult, + bp->hostInputChannels[1], framesToProcess ); + } + } + else + { + /* output only */ + framesToProcess = bp->hostOutputFrameCount[0]; + + framesProcessed = AdaptingOutputOnlyProcess( bp, streamCallbackResult, + bp->hostOutputChannels[0], framesToProcess ); + + framesToProcess = bp->hostOutputFrameCount[1]; + if( framesToProcess > 0 ) + { + framesProcessed += AdaptingOutputOnlyProcess( bp, streamCallbackResult, + bp->hostOutputChannels[1], framesToProcess ); + } + } + } + + return framesProcessed; +} + + +int PaUtil_IsBufferProcessorOutputEmpty( PaUtilBufferProcessor* bp ) +{ + return (bp->framesInTempOutputBuffer) ? 0 : 1; +} + + +unsigned long PaUtil_CopyInput( PaUtilBufferProcessor* bp, + void **buffer, unsigned long frameCount ) +{ + PaUtilChannelDescriptor *hostInputChannels; + unsigned int framesToCopy; + unsigned char *destBytePtr; + void **nonInterleavedDestPtrs; + unsigned int destSampleStrideSamples; /* stride from one sample to the next within a channel, in samples */ + unsigned int destChannelStrideBytes; /* stride from one channel to the next, in bytes */ + unsigned int i; + + hostInputChannels = bp->hostInputChannels[0]; + framesToCopy = PA_MIN_( bp->hostInputFrameCount[0], frameCount ); + + if( bp->userInputIsInterleaved ) + { + destBytePtr = (unsigned char*)*buffer; + + destSampleStrideSamples = bp->inputChannelCount; + destChannelStrideBytes = bp->bytesPerUserInputSample; + + for( i=0; iinputChannelCount; ++i ) + { + bp->inputConverter( destBytePtr, destSampleStrideSamples, + hostInputChannels[i].data, + hostInputChannels[i].stride, + framesToCopy, &bp->ditherGenerator ); + + destBytePtr += destChannelStrideBytes; /* skip to next dest channel */ + + /* advance source ptr for next iteration */ + hostInputChannels[i].data = ((unsigned char*)hostInputChannels[i].data) + + framesToCopy * hostInputChannels[i].stride * bp->bytesPerHostInputSample; + } + + /* advance callers dest pointer (buffer) */ + *buffer = ((unsigned char *)*buffer) + + framesToCopy * bp->inputChannelCount * bp->bytesPerUserInputSample; + } + else + { + /* user input is not interleaved */ + + nonInterleavedDestPtrs = (void**)*buffer; + + destSampleStrideSamples = 1; + + for( i=0; iinputChannelCount; ++i ) + { + destBytePtr = (unsigned char*)nonInterleavedDestPtrs[i]; + + bp->inputConverter( destBytePtr, destSampleStrideSamples, + hostInputChannels[i].data, + hostInputChannels[i].stride, + framesToCopy, &bp->ditherGenerator ); + + /* advance callers dest pointer (nonInterleavedDestPtrs[i]) */ + destBytePtr += bp->bytesPerUserInputSample * framesToCopy; + nonInterleavedDestPtrs[i] = destBytePtr; + + /* advance source ptr for next iteration */ + hostInputChannels[i].data = ((unsigned char*)hostInputChannels[i].data) + + framesToCopy * hostInputChannels[i].stride * bp->bytesPerHostInputSample; + } + } + + bp->hostInputFrameCount[0] -= framesToCopy; + + return framesToCopy; +} + +unsigned long PaUtil_CopyOutput( PaUtilBufferProcessor* bp, + const void ** buffer, unsigned long frameCount ) +{ + PaUtilChannelDescriptor *hostOutputChannels; + unsigned int framesToCopy; + unsigned char *srcBytePtr; + void **nonInterleavedSrcPtrs; + unsigned int srcSampleStrideSamples; /* stride from one sample to the next within a channel, in samples */ + unsigned int srcChannelStrideBytes; /* stride from one channel to the next, in bytes */ + unsigned int i; + + hostOutputChannels = bp->hostOutputChannels[0]; + framesToCopy = PA_MIN_( bp->hostOutputFrameCount[0], frameCount ); + + if( bp->userOutputIsInterleaved ) + { + srcBytePtr = (unsigned char*)*buffer; + + srcSampleStrideSamples = bp->outputChannelCount; + srcChannelStrideBytes = bp->bytesPerUserOutputSample; + + for( i=0; ioutputChannelCount; ++i ) + { + bp->outputConverter( hostOutputChannels[i].data, + hostOutputChannels[i].stride, + srcBytePtr, srcSampleStrideSamples, + framesToCopy, &bp->ditherGenerator ); + + srcBytePtr += srcChannelStrideBytes; /* skip to next source channel */ + + /* advance dest ptr for next iteration */ + hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) + + framesToCopy * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample; + } + + /* advance callers source pointer (buffer) */ + *buffer = ((unsigned char *)*buffer) + + framesToCopy * bp->outputChannelCount * bp->bytesPerUserOutputSample; + + } + else + { + /* user output is not interleaved */ + + nonInterleavedSrcPtrs = (void**)*buffer; + + srcSampleStrideSamples = 1; + + for( i=0; ioutputChannelCount; ++i ) + { + srcBytePtr = (unsigned char*)nonInterleavedSrcPtrs[i]; + + bp->outputConverter( hostOutputChannels[i].data, + hostOutputChannels[i].stride, + srcBytePtr, srcSampleStrideSamples, + framesToCopy, &bp->ditherGenerator ); + + + /* advance callers source pointer (nonInterleavedSrcPtrs[i]) */ + srcBytePtr += bp->bytesPerUserOutputSample * framesToCopy; + nonInterleavedSrcPtrs[i] = srcBytePtr; + + /* advance dest ptr for next iteration */ + hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) + + framesToCopy * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample; + } + } + + bp->hostOutputFrameCount[0] += framesToCopy; + + return framesToCopy; +} + + +unsigned long PaUtil_ZeroOutput( PaUtilBufferProcessor* bp, unsigned long frameCount ) +{ + PaUtilChannelDescriptor *hostOutputChannels; + unsigned int framesToZero; + unsigned int i; + + hostOutputChannels = bp->hostOutputChannels[0]; + framesToZero = PA_MIN_( bp->hostOutputFrameCount[0], frameCount ); + + for( i=0; ioutputChannelCount; ++i ) + { + bp->outputZeroer( hostOutputChannels[i].data, + hostOutputChannels[i].stride, + framesToZero ); + + + /* advance dest ptr for next iteration */ + hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) + + framesToZero * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample; + } + + bp->hostOutputFrameCount[0] += framesToZero; + + return framesToZero; +} diff --git a/extern/portaudio/src/common/pa_process.h b/extern/portaudio/src/common/pa_process.h new file mode 100644 index 0000000..37b91d7 --- /dev/null +++ b/extern/portaudio/src/common/pa_process.h @@ -0,0 +1,754 @@ +#ifndef PA_PROCESS_H +#define PA_PROCESS_H +/* + * $Id$ + * Portable Audio I/O Library callback buffer processing adapters + * + * Based on the Open Source API proposed by Ross Bencina + * Copyright (c) 1999-2002 Phil Burk, Ross Bencina + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +/** @file + @ingroup common_src + + @brief Buffer Processor prototypes. A Buffer Processor performs buffer length + adaption, coordinates sample format conversion, and interleaves/deinterleaves + channels. + +

    Overview

    + + The "Buffer Processor" (PaUtilBufferProcessor) manages conversion of audio + data from host buffers to user buffers and back again. Where required, the + buffer processor takes care of converting between host and user sample formats, + interleaving and deinterleaving multichannel buffers, and adapting between host + and user buffers with different lengths. The buffer processor may be used with + full and half duplex streams, for both callback streams and blocking read/write + streams. + + One of the important capabilities provided by the buffer processor is + the ability to adapt between user and host buffer sizes of different lengths + with minimum latency. Although this task is relatively easy to perform when + the host buffer size is an integer multiple of the user buffer size, the + problem is more complicated when this is not the case - especially for + full-duplex callback streams. Where necessary the adaption is implemented by + internally buffering some input and/or output data. The buffer adation + algorithm used by the buffer processor was originally implemented by + Stephan Letz for the ASIO version of PortAudio, and is described in his + Callback_adaption_.pdf which is included in the distribution. + + The buffer processor performs sample conversion using the functions provided + by pa_converters.c. + + The following sections provide an overview of how to use the buffer processor. + Interested readers are advised to consult the host API implementations for + examples of buffer processor usage. + + +

    Initialization, resetting and termination

    + + When a stream is opened, the buffer processor should be initialized using + PaUtil_InitializeBufferProcessor. This function initializes internal state + and allocates temporary buffers as neccesary according to the supplied + configuration parameters. Some of the parameters correspond to those requested + by the user in their call to Pa_OpenStream(), others reflect the requirements + of the host API implementation - they indicate host buffer sizes, formats, + and the type of buffering which the Host API uses. The buffer processor should + be initialized for callback streams and blocking read/write streams. + + Call PaUtil_ResetBufferProcessor to clear any sample data which is present + in the buffer processor before starting to use it (for example when + Pa_StartStream is called). + + When the buffer processor is no longer used call + PaUtil_TerminateBufferProcessor. + + +

    Using the buffer processor for a callback stream

    + + The buffer processor's role in a callback stream is to take host input buffers + process them with the stream callback, and fill host output buffers. For a + full duplex stream, the buffer processor handles input and output simultaneously + due to the requirements of the minimum-latency buffer adation algorithm. + + When a host buffer becomes available, the implementation should call + the buffer processor to process the buffer. The buffer processor calls the + stream callback to consume and/or produce audio data as necessary. The buffer + processor will convert sample formats, interleave/deinterleave channels, + and slice or chunk the data to the appropriate buffer lengths according to + the requirements of the stream callback and the host API. + + To process a host buffer (or a pair of host buffers for a full-duplex stream) + use the following calling sequence: + + -# Call PaUtil_BeginBufferProcessing + -# For a stream which takes input: + - Call PaUtil_SetInputFrameCount with the number of frames in the host input + buffer. + - Call one of the following functions one or more times to tell the + buffer processor about the host input buffer(s): PaUtil_SetInputChannel, + PaUtil_SetInterleavedInputChannels, PaUtil_SetNonInterleavedInputChannel. + Which function you call will depend on whether the host buffer(s) are + interleaved or not. + - If the available host data is split accross two buffers (for example a + data range at the end of a circular buffer and another range at the + beginning of the circular buffer), also call + PaUtil_Set2ndInputFrameCount, PaUtil_Set2ndInputChannel, + PaUtil_Set2ndInterleavedInputChannels, + PaUtil_Set2ndNonInterleavedInputChannel as necessary to tell the buffer + processor about the second buffer. + -# For a stream which generates output: + - Call PaUtil_SetOutputFrameCount with the number of frames in the host + output buffer. + - Call one of the following functions one or more times to tell the + buffer processor about the host output buffer(s): PaUtil_SetOutputChannel, + PaUtil_SetInterleavedOutputChannels, PaUtil_SetNonInterleavedOutputChannel. + Which function you call will depend on whether the host buffer(s) are + interleaved or not. + - If the available host output buffer space is split accross two buffers + (for example a data range at the end of a circular buffer and another + range at the beginning of the circular buffer), call + PaUtil_Set2ndOutputFrameCount, PaUtil_Set2ndOutputChannel, + PaUtil_Set2ndInterleavedOutputChannels, + PaUtil_Set2ndNonInterleavedOutputChannel as necessary to tell the buffer + processor about the second buffer. + -# Call PaUtil_EndBufferProcessing, this function performs the actual data + conversion and processing. + + +

    Using the buffer processor for a blocking read/write stream

    + + Blocking read/write streams use the buffer processor to convert and copy user + output data to a host buffer, and to convert and copy host input data to + the user's buffer. The buffer processor does not perform any buffer adaption. + When using the buffer processor in a blocking read/write stream the input and + output conversion are performed separately by the PaUtil_CopyInput and + PaUtil_CopyOutput functions. + + To copy data from a host input buffer to the buffer(s) which the user supplies + to Pa_ReadStream, use the following calling sequence. + + - Repeat the following three steps until the user buffer(s) have been filled + with samples from the host input buffers: + -# Call PaUtil_SetInputFrameCount with the number of frames in the host + input buffer. + -# Call one of the following functions one or more times to tell the + buffer processor about the host input buffer(s): PaUtil_SetInputChannel, + PaUtil_SetInterleavedInputChannels, PaUtil_SetNonInterleavedInputChannel. + Which function you call will depend on whether the host buffer(s) are + interleaved or not. + -# Call PaUtil_CopyInput with the user buffer pointer (or a copy of the + array of buffer pointers for a non-interleaved stream) passed to + Pa_ReadStream, along with the number of frames in the user buffer(s). + Be careful to pass a copy of the user buffer pointers to + PaUtil_CopyInput because PaUtil_CopyInput advances the pointers to + the start of the next region to copy. + - PaUtil_CopyInput will not copy more data than is available in the + host buffer(s), so the above steps need to be repeated until the user + buffer(s) are full. + + + To copy data to the host output buffer from the user buffers(s) supplied + to Pa_WriteStream use the following calling sequence. + + - Repeat the following three steps until all frames from the user buffer(s) + have been copied to the host API: + -# Call PaUtil_SetOutputFrameCount with the number of frames in the host + output buffer. + -# Call one of the following functions one or more times to tell the + buffer processor about the host output buffer(s): PaUtil_SetOutputChannel, + PaUtil_SetInterleavedOutputChannels, PaUtil_SetNonInterleavedOutputChannel. + Which function you call will depend on whether the host buffer(s) are + interleaved or not. + -# Call PaUtil_CopyOutput with the user buffer pointer (or a copy of the + array of buffer pointers for a non-interleaved stream) passed to + Pa_WriteStream, along with the number of frames in the user buffer(s). + Be careful to pass a copy of the user buffer pointers to + PaUtil_CopyOutput because PaUtil_CopyOutput advances the pointers to + the start of the next region to copy. + - PaUtil_CopyOutput will not copy more data than fits in the host buffer(s), + so the above steps need to be repeated until all user data is copied. +*/ + + +#include "portaudio.h" +#include "pa_converters.h" +#include "pa_dither.h" + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + +/** @brief Mode flag passed to PaUtil_InitializeBufferProcessor indicating the type + of buffering that the host API uses. + + The mode used depends on whether the host API or the implementation manages + the buffers, and how these buffers are used (scatter gather, circular buffer). +*/ +typedef enum { +/** The host buffer size is a fixed known size. */ + paUtilFixedHostBufferSize, + +/** The host buffer size may vary, but has a known maximum size. */ + paUtilBoundedHostBufferSize, + +/** Nothing is known about the host buffer size. */ + paUtilUnknownHostBufferSize, + +/** The host buffer size varies, and the client does not require the buffer + processor to consume all of the input and fill all of the output buffer. This + is useful when the implementation has access to the host API's circular buffer + and only needs to consume/fill some of it, not necessarily all of it, with each + call to the buffer processor. This is the only mode where + PaUtil_EndBufferProcessing() may not consume the whole buffer. +*/ + paUtilVariableHostBufferSizePartialUsageAllowed +}PaUtilHostBufferSizeMode; + + +/** @brief An auxilliary data structure used internally by the buffer processor + to represent host input and output buffers. */ +typedef struct PaUtilChannelDescriptor{ + void *data; + unsigned int stride; /**< stride in samples, not bytes */ +}PaUtilChannelDescriptor; + + +/** @brief The main buffer processor data structure. + + Allocate one of these, initialize it with PaUtil_InitializeBufferProcessor + and terminate it with PaUtil_TerminateBufferProcessor. +*/ +typedef struct { + unsigned long framesPerUserBuffer; + unsigned long framesPerHostBuffer; + + PaUtilHostBufferSizeMode hostBufferSizeMode; + int useNonAdaptingProcess; + int userOutputSampleFormatIsEqualToHost; + int userInputSampleFormatIsEqualToHost; + unsigned long framesPerTempBuffer; + + unsigned int inputChannelCount; + unsigned int bytesPerHostInputSample; + unsigned int bytesPerUserInputSample; + int userInputIsInterleaved; + PaUtilConverter *inputConverter; + PaUtilZeroer *inputZeroer; + + unsigned int outputChannelCount; + unsigned int bytesPerHostOutputSample; + unsigned int bytesPerUserOutputSample; + int userOutputIsInterleaved; + PaUtilConverter *outputConverter; + PaUtilZeroer *outputZeroer; + + unsigned long initialFramesInTempInputBuffer; + unsigned long initialFramesInTempOutputBuffer; + + void *tempInputBuffer; /**< used for slips, block adaption, and conversion. */ + void **tempInputBufferPtrs; /**< storage for non-interleaved buffer pointers, NULL for interleaved user input */ + unsigned long framesInTempInputBuffer; /**< frames remaining in input buffer from previous adaption iteration */ + + void *tempOutputBuffer; /**< used for slips, block adaption, and conversion. */ + void **tempOutputBufferPtrs; /**< storage for non-interleaved buffer pointers, NULL for interleaved user output */ + unsigned long framesInTempOutputBuffer; /**< frames remaining in input buffer from previous adaption iteration */ + + PaStreamCallbackTimeInfo *timeInfo; + + PaStreamCallbackFlags callbackStatusFlags; + + int hostInputIsInterleaved; + unsigned long hostInputFrameCount[2]; + PaUtilChannelDescriptor *hostInputChannels[2]; /**< pointers to arrays of channel descriptors. + pointers are NULL for half-duplex output processing. + hostInputChannels[i].data is NULL when the caller + calls PaUtil_SetNoInput() + */ + int hostOutputIsInterleaved; + unsigned long hostOutputFrameCount[2]; + PaUtilChannelDescriptor *hostOutputChannels[2]; /**< pointers to arrays of channel descriptors. + pointers are NULL for half-duplex input processing. + hostOutputChannels[i].data is NULL when the caller + calls PaUtil_SetNoOutput() + */ + + PaUtilTriangularDitherGenerator ditherGenerator; + + double samplePeriod; + + PaStreamCallback *streamCallback; + void *userData; +} PaUtilBufferProcessor; + + +/** @name Initialization, termination, resetting and info */ +/*@{*/ + +/** Initialize a buffer processor's representation stored in a + PaUtilBufferProcessor structure. Be sure to call + PaUtil_TerminateBufferProcessor after finishing with a buffer processor. + + @param bufferProcessor The buffer processor structure to initialize. + + @param inputChannelCount The number of input channels as passed to + Pa_OpenStream or 0 for an output-only stream. + + @param userInputSampleFormat Format of user input samples, as passed to + Pa_OpenStream. This parameter is ignored for ouput-only streams. + + @param hostInputSampleFormat Format of host input samples. This parameter is + ignored for output-only streams. See note about host buffer interleave below. + + @param outputChannelCount The number of output channels as passed to + Pa_OpenStream or 0 for an input-only stream. + + @param userOutputSampleFormat Format of user output samples, as passed to + Pa_OpenStream. This parameter is ignored for input-only streams. + + @param hostOutputSampleFormat Format of host output samples. This parameter is + ignored for input-only streams. See note about host buffer interleave below. + + @param sampleRate Sample rate of the stream. The more accurate this is the + better - it is used for updating time stamps when adapting buffers. + + @param streamFlags Stream flags as passed to Pa_OpenStream, this parameter is + used for selecting special sample conversion options such as clipping and + dithering. + + @param framesPerUserBuffer Number of frames per user buffer, as requested + by the framesPerBuffer parameter to Pa_OpenStream. This parameter may be + zero to indicate that the user will accept any (and varying) buffer sizes. + + @param framesPerHostBuffer Specifies the number of frames per host buffer + for the fixed buffer size mode, and the maximum number of frames + per host buffer for the bounded host buffer size mode. It is ignored for + the other modes. + + @param hostBufferSizeMode A mode flag indicating the size variability of + host buffers that will be passed to the buffer processor. See + PaUtilHostBufferSizeMode for further details. + + @param streamCallback The user stream callback passed to Pa_OpenStream. + + @param userData The user data field passed to Pa_OpenStream. + + @note The interleave flag is ignored for host buffer formats. Host + interleave is determined by the use of different SetInput and SetOutput + functions. + + @return An error code indicating whether the initialization was successful. + If the error code is not PaNoError, the buffer processor was not initialized + and should not be used. + + @see Pa_OpenStream, PaUtilHostBufferSizeMode, PaUtil_TerminateBufferProcessor +*/ +PaError PaUtil_InitializeBufferProcessor( PaUtilBufferProcessor* bufferProcessor, + int inputChannelCount, PaSampleFormat userInputSampleFormat, + PaSampleFormat hostInputSampleFormat, + int outputChannelCount, PaSampleFormat userOutputSampleFormat, + PaSampleFormat hostOutputSampleFormat, + double sampleRate, + PaStreamFlags streamFlags, + unsigned long framesPerUserBuffer, /* 0 indicates don't care */ + unsigned long framesPerHostBuffer, + PaUtilHostBufferSizeMode hostBufferSizeMode, + PaStreamCallback *streamCallback, void *userData ); + + +/** Terminate a buffer processor's representation. Deallocates any temporary + buffers allocated by PaUtil_InitializeBufferProcessor. + + @param bufferProcessor The buffer processor structure to terminate. + + @see PaUtil_InitializeBufferProcessor. +*/ +void PaUtil_TerminateBufferProcessor( PaUtilBufferProcessor* bufferProcessor ); + + +/** Clear any internally buffered data. If you call + PaUtil_InitializeBufferProcessor in your OpenStream routine, make sure you + call PaUtil_ResetBufferProcessor in your StartStream call. + + @param bufferProcessor The buffer processor to reset. +*/ +void PaUtil_ResetBufferProcessor( PaUtilBufferProcessor* bufferProcessor ); + + +/** Retrieve the input latency of a buffer processor, in frames. + + @param bufferProcessor The buffer processor examine. + + @return The input latency introduced by the buffer processor, in frames. + + @see PaUtil_GetBufferProcessorOutputLatencyFrames +*/ +unsigned long PaUtil_GetBufferProcessorInputLatencyFrames( PaUtilBufferProcessor* bufferProcessor ); + +/** Retrieve the output latency of a buffer processor, in frames. + + @param bufferProcessor The buffer processor examine. + + @return The output latency introduced by the buffer processor, in frames. + + @see PaUtil_GetBufferProcessorInputLatencyFrames +*/ +unsigned long PaUtil_GetBufferProcessorOutputLatencyFrames( PaUtilBufferProcessor* bufferProcessor ); + +/*@}*/ + + +/** @name Host buffer pointer configuration + + Functions to set host input and output buffers, used by both callback streams + and blocking read/write streams. +*/ +/*@{*/ + + +/** Set the number of frames in the input host buffer(s) specified by the + PaUtil_Set*InputChannel functions. + + @param bufferProcessor The buffer processor. + + @param frameCount The number of host input frames. A 0 frameCount indicates to + use the framesPerHostBuffer value passed to PaUtil_InitializeBufferProcessor. + + @see PaUtil_SetNoInput, PaUtil_SetInputChannel, + PaUtil_SetInterleavedInputChannels, PaUtil_SetNonInterleavedInputChannel +*/ +void PaUtil_SetInputFrameCount( PaUtilBufferProcessor* bufferProcessor, + unsigned long frameCount ); + + +/** Indicate that no input is avalable. This function should be used when + priming the output of a full-duplex stream opened with the + paPrimeOutputBuffersUsingStreamCallback flag. Note that it is not necessary + to call this or any othe PaUtil_Set*Input* functions for ouput-only streams. + + @param bufferProcessor The buffer processor. +*/ +void PaUtil_SetNoInput( PaUtilBufferProcessor* bufferProcessor ); + + +/** Provide the buffer processor with a pointer to a host input channel. + + @param bufferProcessor The buffer processor. + @param channel The channel number. + @param data The buffer. + @param stride The stride from one sample to the next, in samples. For + interleaved host buffers, the stride will usually be the same as the number of + channels in the buffer. +*/ +void PaUtil_SetInputChannel( PaUtilBufferProcessor* bufferProcessor, + unsigned int channel, void *data, unsigned int stride ); + + +/** Provide the buffer processor with a pointer to an number of interleaved + host input channels. + + @param bufferProcessor The buffer processor. + @param firstChannel The first channel number. + @param data The buffer. + @param channelCount The number of interleaved channels in the buffer. If + channelCount is zero, the number of channels specified to + PaUtil_InitializeBufferProcessor will be used. +*/ +void PaUtil_SetInterleavedInputChannels( PaUtilBufferProcessor* bufferProcessor, + unsigned int firstChannel, void *data, unsigned int channelCount ); + + +/** Provide the buffer processor with a pointer to one non-interleaved host + output channel. + + @param bufferProcessor The buffer processor. + @param channel The channel number. + @param data The buffer. +*/ +void PaUtil_SetNonInterleavedInputChannel( PaUtilBufferProcessor* bufferProcessor, + unsigned int channel, void *data ); + + +/** Use for the second buffer half when the input buffer is split in two halves. + @see PaUtil_SetInputFrameCount +*/ +void PaUtil_Set2ndInputFrameCount( PaUtilBufferProcessor* bufferProcessor, + unsigned long frameCount ); + +/** Use for the second buffer half when the input buffer is split in two halves. + @see PaUtil_SetInputChannel +*/ +void PaUtil_Set2ndInputChannel( PaUtilBufferProcessor* bufferProcessor, + unsigned int channel, void *data, unsigned int stride ); + +/** Use for the second buffer half when the input buffer is split in two halves. + @see PaUtil_SetInterleavedInputChannels +*/ +void PaUtil_Set2ndInterleavedInputChannels( PaUtilBufferProcessor* bufferProcessor, + unsigned int firstChannel, void *data, unsigned int channelCount ); + +/** Use for the second buffer half when the input buffer is split in two halves. + @see PaUtil_SetNonInterleavedInputChannel +*/ +void PaUtil_Set2ndNonInterleavedInputChannel( PaUtilBufferProcessor* bufferProcessor, + unsigned int channel, void *data ); + + +/** Set the number of frames in the output host buffer(s) specified by the + PaUtil_Set*OutputChannel functions. + + @param bufferProcessor The buffer processor. + + @param frameCount The number of host output frames. A 0 frameCount indicates to + use the framesPerHostBuffer value passed to PaUtil_InitializeBufferProcessor. + + @see PaUtil_SetOutputChannel, PaUtil_SetInterleavedOutputChannels, + PaUtil_SetNonInterleavedOutputChannel +*/ +void PaUtil_SetOutputFrameCount( PaUtilBufferProcessor* bufferProcessor, + unsigned long frameCount ); + + +/** Indicate that the output will be discarded. This function should be used + when implementing the paNeverDropInput mode for full duplex streams. + + @param bufferProcessor The buffer processor. +*/ +void PaUtil_SetNoOutput( PaUtilBufferProcessor* bufferProcessor ); + + +/** Provide the buffer processor with a pointer to a host output channel. + + @param bufferProcessor The buffer processor. + @param channel The channel number. + @param data The buffer. + @param stride The stride from one sample to the next, in samples. For + interleaved host buffers, the stride will usually be the same as the number of + channels in the buffer. +*/ +void PaUtil_SetOutputChannel( PaUtilBufferProcessor* bufferProcessor, + unsigned int channel, void *data, unsigned int stride ); + + +/** Provide the buffer processor with a pointer to a number of interleaved + host output channels. + + @param bufferProcessor The buffer processor. + @param firstChannel The first channel number. + @param data The buffer. + @param channelCount The number of interleaved channels in the buffer. If + channelCount is zero, the number of channels specified to + PaUtil_InitializeBufferProcessor will be used. +*/ +void PaUtil_SetInterleavedOutputChannels( PaUtilBufferProcessor* bufferProcessor, + unsigned int firstChannel, void *data, unsigned int channelCount ); + + +/** Provide the buffer processor with a pointer to one non-interleaved host + output channel. + + @param bufferProcessor The buffer processor. + @param channel The channel number. + @param data The buffer. +*/ +void PaUtil_SetNonInterleavedOutputChannel( PaUtilBufferProcessor* bufferProcessor, + unsigned int channel, void *data ); + + +/** Use for the second buffer half when the output buffer is split in two halves. + @see PaUtil_SetOutputFrameCount +*/ +void PaUtil_Set2ndOutputFrameCount( PaUtilBufferProcessor* bufferProcessor, + unsigned long frameCount ); + +/** Use for the second buffer half when the output buffer is split in two halves. + @see PaUtil_SetOutputChannel +*/ +void PaUtil_Set2ndOutputChannel( PaUtilBufferProcessor* bufferProcessor, + unsigned int channel, void *data, unsigned int stride ); + +/** Use for the second buffer half when the output buffer is split in two halves. + @see PaUtil_SetInterleavedOutputChannels +*/ +void PaUtil_Set2ndInterleavedOutputChannels( PaUtilBufferProcessor* bufferProcessor, + unsigned int firstChannel, void *data, unsigned int channelCount ); + +/** Use for the second buffer half when the output buffer is split in two halves. + @see PaUtil_SetNonInterleavedOutputChannel +*/ +void PaUtil_Set2ndNonInterleavedOutputChannel( PaUtilBufferProcessor* bufferProcessor, + unsigned int channel, void *data ); + +/*@}*/ + + +/** @name Buffer processing functions for callback streams +*/ +/*@{*/ + +/** Commence processing a host buffer (or a pair of host buffers in the + full-duplex case) for a callback stream. + + @param bufferProcessor The buffer processor. + + @param timeInfo Timing information for the first sample of the host + buffer(s). This information may be adjusted when buffer adaption is being + performed. + + @param callbackStatusFlags Flags indicating whether underruns and overruns + have occurred since the last time the buffer processor was called. +*/ +void PaUtil_BeginBufferProcessing( PaUtilBufferProcessor* bufferProcessor, + PaStreamCallbackTimeInfo* timeInfo, PaStreamCallbackFlags callbackStatusFlags ); + + +/** Finish processing a host buffer (or a pair of host buffers in the + full-duplex case) for a callback stream. + + @param bufferProcessor The buffer processor. + + @param callbackResult On input, indicates a previous callback result, and on + exit, the result of the user stream callback, if it is called. + On entry callbackResult should contain one of { paContinue, paComplete, or + paAbort}. If paComplete is passed, the stream callback will not be called + but any audio that was generated by previous stream callbacks will be copied + to the output buffer(s). You can check whether the buffer processor's internal + buffer is empty by calling PaUtil_IsBufferProcessorOutputEmpty. + + If the stream callback is called its result is stored in *callbackResult. If + the stream callback returns paComplete or paAbort, all output buffers will be + full of valid data - some of which may be zeros to acount for data that + wasn't generated by the terminating callback. + + @return The number of frames processed. This usually corresponds to the + number of frames specified by the PaUtil_Set*FrameCount functions, exept in + the paUtilVariableHostBufferSizePartialUsageAllowed buffer size mode when a + smaller value may be returned. +*/ +unsigned long PaUtil_EndBufferProcessing( PaUtilBufferProcessor* bufferProcessor, + int *callbackResult ); + + +/** Determine whether any callback generated output remains in the bufffer + processor's internal buffers. This method may be used to determine when to + continue calling PaUtil_EndBufferProcessing() after the callback has returned + a callbackResult of paComplete. + + @param bufferProcessor The buffer processor. + + @return Returns non-zero when callback generated output remains in the internal + buffer and zero (0) when there internal buffer contains no callback generated + data. +*/ +int PaUtil_IsBufferProcessorOutputEmpty( PaUtilBufferProcessor* bufferProcessor ); + +/*@}*/ + + +/** @name Buffer processing functions for blocking read/write streams +*/ +/*@{*/ + +/** Copy samples from host input channels set up by the PaUtil_Set*InputChannels + functions to a user supplied buffer. This function is intended for use with + blocking read/write streams. Copies the minimum of the number of + user frames (specified by the frameCount parameter) and the number of available + host frames (specified in a previous call to SetInputFrameCount()). + + @param bufferProcessor The buffer processor. + + @param buffer A pointer to the user buffer pointer, or a pointer to a pointer + to an array of user buffer pointers for a non-interleaved stream. It is + important that this parameter points to a copy of the user buffer pointers, + not to the actual user buffer pointers, because this function updates the + pointers before returning. + + @param frameCount The number of frames of data in the buffer(s) pointed to by + the buffer parameter. + + @return The number of frames copied. The buffer pointer(s) pointed to by the + buffer parameter are advanced to point to the frame(s) following the last one + filled. +*/ +unsigned long PaUtil_CopyInput( PaUtilBufferProcessor* bufferProcessor, + void **buffer, unsigned long frameCount ); + + +/* Copy samples from a user supplied buffer to host output channels set up by + the PaUtil_Set*OutputChannels functions. This function is intended for use with + blocking read/write streams. Copies the minimum of the number of + user frames (specified by the frameCount parameter) and the number of + host frames (specified in a previous call to SetOutputFrameCount()). + + @param bufferProcessor The buffer processor. + + @param buffer A pointer to the user buffer pointer, or a pointer to a pointer + to an array of user buffer pointers for a non-interleaved stream. It is + important that this parameter points to a copy of the user buffer pointers, + not to the actual user buffer pointers, because this function updates the + pointers before returning. + + @param frameCount The number of frames of data in the buffer(s) pointed to by + the buffer parameter. + + @return The number of frames copied. The buffer pointer(s) pointed to by the + buffer parameter are advanced to point to the frame(s) following the last one + copied. +*/ +unsigned long PaUtil_CopyOutput( PaUtilBufferProcessor* bufferProcessor, + const void ** buffer, unsigned long frameCount ); + + +/* Zero samples in host output channels set up by the PaUtil_Set*OutputChannels + functions. This function is useful for flushing streams. + Zeros the minimum of frameCount and the number of host frames specified in a + previous call to SetOutputFrameCount(). + + @param bufferProcessor The buffer processor. + + @param frameCount The maximum number of frames to zero. + + @return The number of frames zeroed. +*/ +unsigned long PaUtil_ZeroOutput( PaUtilBufferProcessor* bufferProcessor, + unsigned long frameCount ); + + +/*@}*/ + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* PA_PROCESS_H */ diff --git a/extern/portaudio/src/common/pa_ringbuffer.c b/extern/portaudio/src/common/pa_ringbuffer.c new file mode 100644 index 0000000..93b3e43 --- /dev/null +++ b/extern/portaudio/src/common/pa_ringbuffer.c @@ -0,0 +1,237 @@ +/* + * $Id$ + * Portable Audio I/O Library + * Ring Buffer utility. + * + * Author: Phil Burk, http://www.softsynth.com + * modified for SMP safety on Mac OS X by Bjorn Roche + * modified for SMP safety on Linux by Leland Lucius + * also, allowed for const where possible + * modified for multiple-byte-sized data elements by Sven Fischer + * + * Note that this is safe only for a single-thread reader and a + * single-thread writer. + * + * This program uses the PortAudio Portable Audio Library. + * For more information see: http://www.portaudio.com + * Copyright (c) 1999-2000 Ross Bencina and Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +/** + @file + @ingroup common_src +*/ + +#include +#include +#include +#include "pa_ringbuffer.h" +#include +#include "pa_memorybarrier.h" + +/*************************************************************************** + * Initialize FIFO. + * elementCount must be power of 2, returns -1 if not. + */ +ring_buffer_size_t PaUtil_InitializeRingBuffer( PaUtilRingBuffer *rbuf, ring_buffer_size_t elementSizeBytes, ring_buffer_size_t elementCount, void *dataPtr ) +{ + if( ((elementCount-1) & elementCount) != 0) return -1; /* Not Power of two. */ + rbuf->bufferSize = elementCount; + rbuf->buffer = (char *)dataPtr; + PaUtil_FlushRingBuffer( rbuf ); + rbuf->bigMask = (elementCount*2)-1; + rbuf->smallMask = (elementCount)-1; + rbuf->elementSizeBytes = elementSizeBytes; + return 0; +} + +/*************************************************************************** +** Return number of elements available for reading. */ +ring_buffer_size_t PaUtil_GetRingBufferReadAvailable( const PaUtilRingBuffer *rbuf ) +{ + return ( (rbuf->writeIndex - rbuf->readIndex) & rbuf->bigMask ); +} +/*************************************************************************** +** Return number of elements available for writing. */ +ring_buffer_size_t PaUtil_GetRingBufferWriteAvailable( const PaUtilRingBuffer *rbuf ) +{ + return ( rbuf->bufferSize - PaUtil_GetRingBufferReadAvailable(rbuf)); +} + +/*************************************************************************** +** Clear buffer. Should only be called when buffer is NOT being read or written. */ +void PaUtil_FlushRingBuffer( PaUtilRingBuffer *rbuf ) +{ + rbuf->writeIndex = rbuf->readIndex = 0; +} + +/*************************************************************************** +** Get address of region(s) to which we can write data. +** If the region is contiguous, size2 will be zero. +** If non-contiguous, size2 will be the size of second region. +** Returns room available to be written or elementCount, whichever is smaller. +*/ +ring_buffer_size_t PaUtil_GetRingBufferWriteRegions( PaUtilRingBuffer *rbuf, ring_buffer_size_t elementCount, + void **dataPtr1, ring_buffer_size_t *sizePtr1, + void **dataPtr2, ring_buffer_size_t *sizePtr2 ) +{ + ring_buffer_size_t index; + ring_buffer_size_t available = PaUtil_GetRingBufferWriteAvailable( rbuf ); + if( elementCount > available ) elementCount = available; + /* Check to see if write is not contiguous. */ + index = rbuf->writeIndex & rbuf->smallMask; + if( (index + elementCount) > rbuf->bufferSize ) + { + /* Write data in two blocks that wrap the buffer. */ + ring_buffer_size_t firstHalf = rbuf->bufferSize - index; + *dataPtr1 = &rbuf->buffer[index*rbuf->elementSizeBytes]; + *sizePtr1 = firstHalf; + *dataPtr2 = &rbuf->buffer[0]; + *sizePtr2 = elementCount - firstHalf; + } + else + { + *dataPtr1 = &rbuf->buffer[index*rbuf->elementSizeBytes]; + *sizePtr1 = elementCount; + *dataPtr2 = NULL; + *sizePtr2 = 0; + } + + if( available ) + PaUtil_FullMemoryBarrier(); /* (write-after-read) => full barrier */ + + return elementCount; +} + + +/*************************************************************************** +*/ +ring_buffer_size_t PaUtil_AdvanceRingBufferWriteIndex( PaUtilRingBuffer *rbuf, ring_buffer_size_t elementCount ) +{ + /* ensure that previous writes are seen before we update the write index + (write after write) + */ + PaUtil_WriteMemoryBarrier(); + return rbuf->writeIndex = (rbuf->writeIndex + elementCount) & rbuf->bigMask; +} + +/*************************************************************************** +** Get address of region(s) from which we can read data. +** If the region is contiguous, size2 will be zero. +** If non-contiguous, size2 will be the size of second region. +** Returns room available to be read or elementCount, whichever is smaller. +*/ +ring_buffer_size_t PaUtil_GetRingBufferReadRegions( PaUtilRingBuffer *rbuf, ring_buffer_size_t elementCount, + void **dataPtr1, ring_buffer_size_t *sizePtr1, + void **dataPtr2, ring_buffer_size_t *sizePtr2 ) +{ + ring_buffer_size_t index; + ring_buffer_size_t available = PaUtil_GetRingBufferReadAvailable( rbuf ); /* doesn't use memory barrier */ + if( elementCount > available ) elementCount = available; + /* Check to see if read is not contiguous. */ + index = rbuf->readIndex & rbuf->smallMask; + if( (index + elementCount) > rbuf->bufferSize ) + { + /* Write data in two blocks that wrap the buffer. */ + ring_buffer_size_t firstHalf = rbuf->bufferSize - index; + *dataPtr1 = &rbuf->buffer[index*rbuf->elementSizeBytes]; + *sizePtr1 = firstHalf; + *dataPtr2 = &rbuf->buffer[0]; + *sizePtr2 = elementCount - firstHalf; + } + else + { + *dataPtr1 = &rbuf->buffer[index*rbuf->elementSizeBytes]; + *sizePtr1 = elementCount; + *dataPtr2 = NULL; + *sizePtr2 = 0; + } + + if( available ) + PaUtil_ReadMemoryBarrier(); /* (read-after-read) => read barrier */ + + return elementCount; +} +/*************************************************************************** +*/ +ring_buffer_size_t PaUtil_AdvanceRingBufferReadIndex( PaUtilRingBuffer *rbuf, ring_buffer_size_t elementCount ) +{ + /* ensure that previous reads (copies out of the ring buffer) are always completed before updating (writing) the read index. + (write-after-read) => full barrier + */ + PaUtil_FullMemoryBarrier(); + return rbuf->readIndex = (rbuf->readIndex + elementCount) & rbuf->bigMask; +} + +/*************************************************************************** +** Return elements written. */ +ring_buffer_size_t PaUtil_WriteRingBuffer( PaUtilRingBuffer *rbuf, const void *data, ring_buffer_size_t elementCount ) +{ + ring_buffer_size_t size1, size2, numWritten; + void *data1, *data2; + numWritten = PaUtil_GetRingBufferWriteRegions( rbuf, elementCount, &data1, &size1, &data2, &size2 ); + if( size2 > 0 ) + { + + memcpy( data1, data, size1*rbuf->elementSizeBytes ); + data = ((char *)data) + size1*rbuf->elementSizeBytes; + memcpy( data2, data, size2*rbuf->elementSizeBytes ); + } + else + { + memcpy( data1, data, size1*rbuf->elementSizeBytes ); + } + PaUtil_AdvanceRingBufferWriteIndex( rbuf, numWritten ); + return numWritten; +} + +/*************************************************************************** +** Return elements read. */ +ring_buffer_size_t PaUtil_ReadRingBuffer( PaUtilRingBuffer *rbuf, void *data, ring_buffer_size_t elementCount ) +{ + ring_buffer_size_t size1, size2, numRead; + void *data1, *data2; + numRead = PaUtil_GetRingBufferReadRegions( rbuf, elementCount, &data1, &size1, &data2, &size2 ); + if( size2 > 0 ) + { + memcpy( data, data1, size1*rbuf->elementSizeBytes ); + data = ((char *)data) + size1*rbuf->elementSizeBytes; + memcpy( data, data2, size2*rbuf->elementSizeBytes ); + } + else + { + memcpy( data, data1, size1*rbuf->elementSizeBytes ); + } + PaUtil_AdvanceRingBufferReadIndex( rbuf, numRead ); + return numRead; +} diff --git a/extern/portaudio/src/common/pa_ringbuffer.h b/extern/portaudio/src/common/pa_ringbuffer.h new file mode 100644 index 0000000..9edba0d --- /dev/null +++ b/extern/portaudio/src/common/pa_ringbuffer.h @@ -0,0 +1,236 @@ +#ifndef PA_RINGBUFFER_H +#define PA_RINGBUFFER_H +/* + * $Id$ + * Portable Audio I/O Library + * Ring Buffer utility. + * + * Author: Phil Burk, http://www.softsynth.com + * modified for SMP safety on OS X by Bjorn Roche. + * also allowed for const where possible. + * modified for multiple-byte-sized data elements by Sven Fischer + * + * Note that this is safe only for a single-thread reader + * and a single-thread writer. + * + * This program is distributed with the PortAudio Portable Audio Library. + * For more information see: http://www.portaudio.com + * Copyright (c) 1999-2000 Ross Bencina and Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +/** @file + @ingroup common_src + @brief Single-reader single-writer lock-free ring buffer + + PaUtilRingBuffer is a ring buffer used to transport samples between + different execution contexts (threads, OS callbacks, interrupt handlers) + without requiring the use of any locks. This only works when there is + a single reader and a single writer (ie. one thread or callback writes + to the ring buffer, another thread or callback reads from it). + + The PaUtilRingBuffer structure manages a ring buffer containing N + elements, where N must be a power of two. An element may be any size + (specified in bytes). + + The memory area used to store the buffer elements must be allocated by + the client prior to calling PaUtil_InitializeRingBuffer() and must outlive + the use of the ring buffer. + + @note The ring buffer functions are not normally exposed in the PortAudio libraries. + If you want to call them then you will need to add pa_ringbuffer.c to your application source code. +*/ + +#if defined(__APPLE__) +#include +typedef int32_t ring_buffer_size_t; +#elif defined( __GNUC__ ) +typedef long ring_buffer_size_t; +#elif (_MSC_VER >= 1400) +typedef long ring_buffer_size_t; +#elif defined(_MSC_VER) || defined(__BORLANDC__) +typedef long ring_buffer_size_t; +#else +typedef long ring_buffer_size_t; +#endif + + + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +typedef struct PaUtilRingBuffer +{ + ring_buffer_size_t bufferSize; /**< Number of elements in FIFO. Power of 2. Set by PaUtil_InitRingBuffer. */ + volatile ring_buffer_size_t writeIndex; /**< Index of next writable element. Set by PaUtil_AdvanceRingBufferWriteIndex. */ + volatile ring_buffer_size_t readIndex; /**< Index of next readable element. Set by PaUtil_AdvanceRingBufferReadIndex. */ + ring_buffer_size_t bigMask; /**< Used for wrapping indices with extra bit to distinguish full/empty. */ + ring_buffer_size_t smallMask; /**< Used for fitting indices to buffer. */ + ring_buffer_size_t elementSizeBytes; /**< Number of bytes per element. */ + char *buffer; /**< Pointer to the buffer containing the actual data. */ +}PaUtilRingBuffer; + +/** Initialize Ring Buffer to empty state ready to have elements written to it. + + @param rbuf The ring buffer. + + @param elementSizeBytes The size of a single data element in bytes. + + @param elementCount The number of elements in the buffer (must be a power of 2). + + @param dataPtr A pointer to a previously allocated area where the data + will be maintained. It must be elementCount*elementSizeBytes long. + + @return -1 if elementCount is not a power of 2, otherwise 0. +*/ +ring_buffer_size_t PaUtil_InitializeRingBuffer( PaUtilRingBuffer *rbuf, ring_buffer_size_t elementSizeBytes, ring_buffer_size_t elementCount, void *dataPtr ); + +/** Reset buffer to empty. Should only be called when buffer is NOT being read or written. + + @param rbuf The ring buffer. +*/ +void PaUtil_FlushRingBuffer( PaUtilRingBuffer *rbuf ); + +/** Retrieve the number of elements available in the ring buffer for writing. + + @param rbuf The ring buffer. + + @return The number of elements available for writing. +*/ +ring_buffer_size_t PaUtil_GetRingBufferWriteAvailable( const PaUtilRingBuffer *rbuf ); + +/** Retrieve the number of elements available in the ring buffer for reading. + + @param rbuf The ring buffer. + + @return The number of elements available for reading. +*/ +ring_buffer_size_t PaUtil_GetRingBufferReadAvailable( const PaUtilRingBuffer *rbuf ); + +/** Write data to the ring buffer. + + @param rbuf The ring buffer. + + @param data The address of new data to write to the buffer. + + @param elementCount The number of elements to be written. + + @return The number of elements written. +*/ +ring_buffer_size_t PaUtil_WriteRingBuffer( PaUtilRingBuffer *rbuf, const void *data, ring_buffer_size_t elementCount ); + +/** Read data from the ring buffer. + + @param rbuf The ring buffer. + + @param data The address where the data should be stored. + + @param elementCount The number of elements to be read. + + @return The number of elements read. +*/ +ring_buffer_size_t PaUtil_ReadRingBuffer( PaUtilRingBuffer *rbuf, void *data, ring_buffer_size_t elementCount ); + +/** Get address of region(s) to which we can write data. + + @param rbuf The ring buffer. + + @param elementCount The number of elements desired. + + @param dataPtr1 The address where the first (or only) region pointer will be + stored. + + @param sizePtr1 The address where the first (or only) region length will be + stored. + + @param dataPtr2 The address where the second region pointer will be stored if + the first region is too small to satisfy elementCount. + + @param sizePtr2 The address where the second region length will be stored if + the first region is too small to satisfy elementCount. + + @return The room available to be written or elementCount, whichever is smaller. +*/ +ring_buffer_size_t PaUtil_GetRingBufferWriteRegions( PaUtilRingBuffer *rbuf, ring_buffer_size_t elementCount, + void **dataPtr1, ring_buffer_size_t *sizePtr1, + void **dataPtr2, ring_buffer_size_t *sizePtr2 ); + +/** Advance the write index to the next location to be written. + + @param rbuf The ring buffer. + + @param elementCount The number of elements to advance. + + @return The new position. +*/ +ring_buffer_size_t PaUtil_AdvanceRingBufferWriteIndex( PaUtilRingBuffer *rbuf, ring_buffer_size_t elementCount ); + +/** Get address of region(s) from which we can read data. + + @param rbuf The ring buffer. + + @param elementCount The number of elements desired. + + @param dataPtr1 The address where the first (or only) region pointer will be + stored. + + @param sizePtr1 The address where the first (or only) region length will be + stored. + + @param dataPtr2 The address where the second region pointer will be stored if + the first region is too small to satisfy elementCount. + + @param sizePtr2 The address where the second region length will be stored if + the first region is too small to satisfy elementCount. + + @return The number of elements available for reading. +*/ +ring_buffer_size_t PaUtil_GetRingBufferReadRegions( PaUtilRingBuffer *rbuf, ring_buffer_size_t elementCount, + void **dataPtr1, ring_buffer_size_t *sizePtr1, + void **dataPtr2, ring_buffer_size_t *sizePtr2 ); + +/** Advance the read index to the next location to be read. + + @param rbuf The ring buffer. + + @param elementCount The number of elements to advance. + + @return The new position. +*/ +ring_buffer_size_t PaUtil_AdvanceRingBufferReadIndex( PaUtilRingBuffer *rbuf, ring_buffer_size_t elementCount ); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* PA_RINGBUFFER_H */ diff --git a/extern/portaudio/src/common/pa_stream.c b/extern/portaudio/src/common/pa_stream.c new file mode 100644 index 0000000..03a0ee6 --- /dev/null +++ b/extern/portaudio/src/common/pa_stream.c @@ -0,0 +1,150 @@ +/* + * $Id$ + * Portable Audio I/O Library + * stream interface + * + * Based on the Open Source API proposed by Ross Bencina + * Copyright (c) 2008 Ross Bencina + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +/** @file + @ingroup common_src + + @brief Stream interfaces, representation structures and helper functions + used to interface between pa_front.c host API implementations. +*/ + + +#include "pa_stream.h" + + +void PaUtil_InitializeStreamInterface( PaUtilStreamInterface *streamInterface, + PaError (*Close)( PaStream* ), + PaError (*Start)( PaStream* ), + PaError (*Stop)( PaStream* ), + PaError (*Abort)( PaStream* ), + PaError (*IsStopped)( PaStream* ), + PaError (*IsActive)( PaStream* ), + PaTime (*GetTime)( PaStream* ), + double (*GetCpuLoad)( PaStream* ), + PaError (*Read)( PaStream*, void *, unsigned long ), + PaError (*Write)( PaStream*, const void *, unsigned long ), + signed long (*GetReadAvailable)( PaStream* ), + signed long (*GetWriteAvailable)( PaStream* ) ) +{ + streamInterface->Close = Close; + streamInterface->Start = Start; + streamInterface->Stop = Stop; + streamInterface->Abort = Abort; + streamInterface->IsStopped = IsStopped; + streamInterface->IsActive = IsActive; + streamInterface->GetTime = GetTime; + streamInterface->GetCpuLoad = GetCpuLoad; + streamInterface->Read = Read; + streamInterface->Write = Write; + streamInterface->GetReadAvailable = GetReadAvailable; + streamInterface->GetWriteAvailable = GetWriteAvailable; +} + + +void PaUtil_InitializeStreamRepresentation( PaUtilStreamRepresentation *streamRepresentation, + PaUtilStreamInterface *streamInterface, + PaStreamCallback *streamCallback, + void *userData ) +{ + streamRepresentation->magic = PA_STREAM_MAGIC; + streamRepresentation->nextOpenStream = 0; + streamRepresentation->streamInterface = streamInterface; + streamRepresentation->streamCallback = streamCallback; + streamRepresentation->streamFinishedCallback = 0; + + streamRepresentation->userData = userData; + + streamRepresentation->streamInfo.inputLatency = 0.; + streamRepresentation->streamInfo.outputLatency = 0.; + streamRepresentation->streamInfo.sampleRate = 0.; +} + + +void PaUtil_TerminateStreamRepresentation( PaUtilStreamRepresentation *streamRepresentation ) +{ + streamRepresentation->magic = 0; +} + + +PaError PaUtil_DummyRead( PaStream* stream, + void *buffer, + unsigned long frames ) +{ + (void)stream; /* unused parameter */ + (void)buffer; /* unused parameter */ + (void)frames; /* unused parameter */ + + return paCanNotReadFromACallbackStream; +} + + +PaError PaUtil_DummyWrite( PaStream* stream, + const void *buffer, + unsigned long frames ) +{ + (void)stream; /* unused parameter */ + (void)buffer; /* unused parameter */ + (void)frames; /* unused parameter */ + + return paCanNotWriteToACallbackStream; +} + + +signed long PaUtil_DummyGetReadAvailable( PaStream* stream ) +{ + (void)stream; /* unused parameter */ + + return paCanNotReadFromACallbackStream; +} + + +signed long PaUtil_DummyGetWriteAvailable( PaStream* stream ) +{ + (void)stream; /* unused parameter */ + + return paCanNotWriteToACallbackStream; +} + + +double PaUtil_DummyGetCpuLoad( PaStream* stream ) +{ + (void)stream; /* unused parameter */ + + return 0.0; +} diff --git a/extern/portaudio/src/common/pa_stream.h b/extern/portaudio/src/common/pa_stream.h new file mode 100644 index 0000000..678e2ad --- /dev/null +++ b/extern/portaudio/src/common/pa_stream.h @@ -0,0 +1,205 @@ +#ifndef PA_STREAM_H +#define PA_STREAM_H +/* + * $Id$ + * Portable Audio I/O Library + * stream interface + * + * Based on the Open Source API proposed by Ross Bencina + * Copyright (c) 1999-2008 Ross Bencina, Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +/** @file + @ingroup common_src + + @brief Stream interfaces, representation structures and helper functions + used to interface between pa_front.c host API implementations. +*/ + + +#include "portaudio.h" + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + +#define PA_STREAM_MAGIC (0x18273645) + + +/** A structure representing an (abstract) interface to a host API. Contains + pointers to functions which implement the interface. + + All PaStreamInterface functions are guaranteed to be called with a non-null, + valid stream parameter. +*/ +typedef struct { + PaError (*Close)( PaStream* stream ); + PaError (*Start)( PaStream *stream ); + PaError (*Stop)( PaStream *stream ); + PaError (*Abort)( PaStream *stream ); + PaError (*IsStopped)( PaStream *stream ); + PaError (*IsActive)( PaStream *stream ); + PaTime (*GetTime)( PaStream *stream ); + double (*GetCpuLoad)( PaStream* stream ); + PaError (*Read)( PaStream* stream, void *buffer, unsigned long frames ); + PaError (*Write)( PaStream* stream, const void *buffer, unsigned long frames ); + signed long (*GetReadAvailable)( PaStream* stream ); + signed long (*GetWriteAvailable)( PaStream* stream ); +} PaUtilStreamInterface; + + +/** Initialize the fields of a PaUtilStreamInterface structure. +*/ +void PaUtil_InitializeStreamInterface( PaUtilStreamInterface *streamInterface, + PaError (*Close)( PaStream* ), + PaError (*Start)( PaStream* ), + PaError (*Stop)( PaStream* ), + PaError (*Abort)( PaStream* ), + PaError (*IsStopped)( PaStream* ), + PaError (*IsActive)( PaStream* ), + PaTime (*GetTime)( PaStream* ), + double (*GetCpuLoad)( PaStream* ), + PaError (*Read)( PaStream* stream, void *buffer, unsigned long frames ), + PaError (*Write)( PaStream* stream, const void *buffer, unsigned long frames ), + signed long (*GetReadAvailable)( PaStream* stream ), + signed long (*GetWriteAvailable)( PaStream* stream ) ); + + +/** Dummy Read function for use in interfaces to a callback based streams. + Pass to the Read parameter of PaUtil_InitializeStreamInterface. + @return An error code indicating that the function has no effect + because the stream is a callback stream. +*/ +PaError PaUtil_DummyRead( PaStream* stream, + void *buffer, + unsigned long frames ); + + +/** Dummy Write function for use in an interfaces to callback based streams. + Pass to the Write parameter of PaUtil_InitializeStreamInterface. + @return An error code indicating that the function has no effect + because the stream is a callback stream. +*/ +PaError PaUtil_DummyWrite( PaStream* stream, + const void *buffer, + unsigned long frames ); + + +/** Dummy GetReadAvailable function for use in interfaces to callback based + streams. Pass to the GetReadAvailable parameter of PaUtil_InitializeStreamInterface. + @return An error code indicating that the function has no effect + because the stream is a callback stream. +*/ +signed long PaUtil_DummyGetReadAvailable( PaStream* stream ); + + +/** Dummy GetWriteAvailable function for use in interfaces to callback based + streams. Pass to the GetWriteAvailable parameter of PaUtil_InitializeStreamInterface. + @return An error code indicating that the function has no effect + because the stream is a callback stream. +*/ +signed long PaUtil_DummyGetWriteAvailable( PaStream* stream ); + + + +/** Dummy GetCpuLoad function for use in an interface to a read/write stream. + Pass to the GetCpuLoad parameter of PaUtil_InitializeStreamInterface. + @return Returns 0. +*/ +double PaUtil_DummyGetCpuLoad( PaStream* stream ); + + +/** Non host specific data for a stream. This data is used by pa_front to + forward to the appropriate functions in the streamInterface structure. +*/ +typedef struct PaUtilStreamRepresentation { + unsigned long magic; /**< set to PA_STREAM_MAGIC */ + struct PaUtilStreamRepresentation *nextOpenStream; /**< field used by multi-api code */ + PaUtilStreamInterface *streamInterface; + PaStreamCallback *streamCallback; + PaStreamFinishedCallback *streamFinishedCallback; + void *userData; + PaStreamInfo streamInfo; +} PaUtilStreamRepresentation; + + +/** Initialize a PaUtilStreamRepresentation structure. + + @see PaUtil_InitializeStreamRepresentation +*/ +void PaUtil_InitializeStreamRepresentation( + PaUtilStreamRepresentation *streamRepresentation, + PaUtilStreamInterface *streamInterface, + PaStreamCallback *streamCallback, + void *userData ); + + +/** Clean up a PaUtilStreamRepresentation structure previously initialized + by a call to PaUtil_InitializeStreamRepresentation. + + @see PaUtil_InitializeStreamRepresentation +*/ +void PaUtil_TerminateStreamRepresentation( PaUtilStreamRepresentation *streamRepresentation ); + + +/** Check that the stream pointer is valid. + + @return Returns paNoError if the stream pointer appears to be OK, otherwise + returns an error indicating the cause of failure. +*/ +PaError PaUtil_ValidateStreamPointer( PaStream *stream ); + + +/** Cast an opaque stream pointer into a pointer to a PaUtilStreamRepresentation. + + @see PaUtilStreamRepresentation +*/ +#define PA_STREAM_REP( stream )\ + ((PaUtilStreamRepresentation*) (stream) ) + + +/** Cast an opaque stream pointer into a pointer to a PaUtilStreamInterface. + + @see PaUtilStreamRepresentation, PaUtilStreamInterface +*/ +#define PA_STREAM_INTERFACE( stream )\ + PA_STREAM_REP( (stream) )->streamInterface + + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* PA_STREAM_H */ diff --git a/extern/portaudio/src/common/pa_trace.c b/extern/portaudio/src/common/pa_trace.c new file mode 100644 index 0000000..818abff --- /dev/null +++ b/extern/portaudio/src/common/pa_trace.c @@ -0,0 +1,238 @@ +/* + * $Id$ + * Portable Audio I/O Library Trace Facility + * Store trace information in real-time for later printing. + * + * Based on the Open Source API proposed by Ross Bencina + * Copyright (c) 1999-2000 Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +/** @file + @ingroup common_src + + @brief Real-time safe event trace logging facility for debugging. +*/ + + +#include +#include +#include +#include +#include +#include "pa_trace.h" +#include "pa_util.h" +#include "pa_debugprint.h" + +#if PA_TRACE_REALTIME_EVENTS + +static char const *traceTextArray[PA_MAX_TRACE_RECORDS]; +static int traceIntArray[PA_MAX_TRACE_RECORDS]; +static int traceIndex = 0; +static int traceBlock = 0; + +/*********************************************************************/ +void PaUtil_ResetTraceMessages() +{ + traceIndex = 0; +} + +/*********************************************************************/ +void PaUtil_DumpTraceMessages() +{ + int i; + int messageCount = (traceIndex < PA_MAX_TRACE_RECORDS) ? traceIndex : PA_MAX_TRACE_RECORDS; + + printf("DumpTraceMessages: traceIndex = %d\n", traceIndex ); + for( i=0; idata = (char*)PaUtil_AllocateMemory(maxSizeInBytes); + if (pLog->data == 0) + { + PaUtil_FreeMemory(pLog); + return paInsufficientMemory; + } + pLog->magik = kMagik; + pLog->size = maxSizeInBytes; + pLog->refTime = PaUtil_GetTime(); + return paNoError; +} + +void PaUtil_ResetHighSpeedLogTimeRef( LogHandle hLog ) +{ + PaHighPerformanceLog* pLog = (PaHighPerformanceLog*)hLog; + assert(pLog->magik == kMagik); + pLog->refTime = PaUtil_GetTime(); +} + +typedef struct __PaLogEntryHeader +{ + int size; + double timeStamp; +} PaLogEntryHeader; + +#ifdef __APPLE__ +#define _vsnprintf vsnprintf +#define min(a,b) ((a)<(b)?(a):(b)) +#endif + + +int PaUtil_AddHighSpeedLogMessage( LogHandle hLog, const char* fmt, ... ) +{ + va_list l; + int n = 0; + PaHighPerformanceLog* pLog = (PaHighPerformanceLog*)hLog; + if (pLog != 0) + { + PaLogEntryHeader* pHeader; + char* p; + int maxN; + assert(pLog->magik == kMagik); + pHeader = (PaLogEntryHeader*)( pLog->data + pLog->writePtr ); + p = (char*)( pHeader + 1 ); + maxN = pLog->size - pLog->writePtr - 2 * sizeof(PaLogEntryHeader); + + pHeader->timeStamp = PaUtil_GetTime() - pLog->refTime; + if (maxN > 0) + { + if (maxN > 32) + { + va_start(l, fmt); + n = _vsnprintf(p, min(1024, maxN), fmt, l); + va_end(l); + } + else { + n = sprintf(p, "End of log..."); + } + n = ((n + sizeof(unsigned)) & ~(sizeof(unsigned)-1)) + sizeof(PaLogEntryHeader); + pHeader->size = n; +#if 0 + PaUtil_DebugPrint("%05u.%03u: %s\n", pHeader->timeStamp/1000, pHeader->timeStamp%1000, p); +#endif + pLog->writePtr += n; + } + } + return n; +} + +void PaUtil_DumpHighSpeedLog( LogHandle hLog, const char* fileName ) +{ + FILE* f = (fileName != NULL) ? fopen(fileName, "w") : stdout; + unsigned localWritePtr; + PaHighPerformanceLog* pLog = (PaHighPerformanceLog*)hLog; + assert(pLog->magik == kMagik); + localWritePtr = pLog->writePtr; + while (pLog->readPtr != localWritePtr) + { + const PaLogEntryHeader* pHeader = (const PaLogEntryHeader*)( pLog->data + pLog->readPtr ); + const char* p = (const char*)( pHeader + 1 ); + const PaUint64 ts = (const PaUint64)( pHeader->timeStamp * USEC_PER_SEC ); + assert(pHeader->size < (1024+sizeof(unsigned)+sizeof(PaLogEntryHeader))); + fprintf(f, "%05u.%03u: %s\n", (unsigned)(ts/1000), (unsigned)(ts%1000), p); + pLog->readPtr += pHeader->size; + } + if (f != stdout) + { + fclose(f); + } +} + +void PaUtil_DiscardHighSpeedLog( LogHandle hLog ) +{ + PaHighPerformanceLog* pLog = (PaHighPerformanceLog*)hLog; + assert(pLog->magik == kMagik); + PaUtil_FreeMemory(pLog->data); + PaUtil_FreeMemory(pLog); +} + +#else +/* This stub was added so that this file will generate a symbol. + * Otherwise linker/archiver programs will complain. + */ +int PaUtil_TraceStubToSatisfyLinker(void) +{ + return 0; +} +#endif /* TRACE_REALTIME_EVENTS */ diff --git a/extern/portaudio/src/common/pa_trace.h b/extern/portaudio/src/common/pa_trace.h new file mode 100644 index 0000000..6dfaeb7 --- /dev/null +++ b/extern/portaudio/src/common/pa_trace.h @@ -0,0 +1,117 @@ +#ifndef PA_TRACE_H +#define PA_TRACE_H +/* + * $Id$ + * Portable Audio I/O Library Trace Facility + * Store trace information in real-time for later printing. + * + * Based on the Open Source API proposed by Ross Bencina + * Copyright (c) 1999-2000 Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +/** @file + @ingroup common_src + + @brief Real-time safe event trace logging facility for debugging. + + Allows data to be logged to a fixed size trace buffer in a real-time + execution context (such as at interrupt time). Each log entry consists + of a message comprising a string pointer and an int. The trace buffer + may be dumped to stdout later. + + This facility is only active if PA_TRACE_REALTIME_EVENTS is set to 1, + otherwise the trace functions expand to no-ops. + + @fn PaUtil_ResetTraceMessages + @brief Clear the trace buffer. + + @fn PaUtil_AddTraceMessage + @brief Add a message to the trace buffer. A message consists of string and an int. + @param msg The string pointer must remain valid until PaUtil_DumpTraceMessages + is called. As a result, usually only string literals should be passed as + the msg parameter. + + @fn PaUtil_DumpTraceMessages + @brief Print all messages in the trace buffer to stdout and clear the trace buffer. +*/ + +#ifndef PA_TRACE_REALTIME_EVENTS +#define PA_TRACE_REALTIME_EVENTS (0) /**< Set to 1 to enable logging using the trace functions defined below */ +#endif + +#ifndef PA_MAX_TRACE_RECORDS +#define PA_MAX_TRACE_RECORDS (2048) /**< Maximum number of records stored in trace buffer */ +#endif + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + +#if PA_TRACE_REALTIME_EVENTS + +void PaUtil_ResetTraceMessages(); +void PaUtil_AddTraceMessage( const char *msg, int data ); +void PaUtil_DumpTraceMessages(); + +/* Alternative interface */ + +typedef void* LogHandle; + +int PaUtil_InitializeHighSpeedLog(LogHandle* phLog, unsigned maxSizeInBytes); +void PaUtil_ResetHighSpeedLogTimeRef(LogHandle hLog); +int PaUtil_AddHighSpeedLogMessage(LogHandle hLog, const char* fmt, ...); +void PaUtil_DumpHighSpeedLog(LogHandle hLog, const char* fileName); +void PaUtil_DiscardHighSpeedLog(LogHandle hLog); + +#else + +#define PaUtil_ResetTraceMessages() /* noop */ +#define PaUtil_AddTraceMessage(msg,data) /* noop */ +#define PaUtil_DumpTraceMessages() /* noop */ + +#define PaUtil_InitializeHighSpeedLog(phLog, maxSizeInBytes) (0) +#define PaUtil_ResetHighSpeedLogTimeRef(hLog) +#define PaUtil_AddHighSpeedLogMessage(...) (0) +#define PaUtil_DumpHighSpeedLog(hLog, fileName) +#define PaUtil_DiscardHighSpeedLog(hLog) + +#endif + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* PA_TRACE_H */ diff --git a/extern/portaudio/src/common/pa_types.h b/extern/portaudio/src/common/pa_types.h new file mode 100644 index 0000000..5b647d6 --- /dev/null +++ b/extern/portaudio/src/common/pa_types.h @@ -0,0 +1,107 @@ +#ifndef PA_TYPES_H +#define PA_TYPES_H + +/* + * Portable Audio I/O Library + * integer type definitions + * + * Based on the Open Source API proposed by Ross Bencina + * Copyright (c) 1999-2006 Ross Bencina, Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +/** @file + @ingroup common_src + + @brief Definition of 16 and 32 bit integer types (PaInt16, PaInt32 etc) + + SIZEOF_SHORT, SIZEOF_INT and SIZEOF_LONG are set by the configure script + when it is used. Otherwise we default to the common 32 bit values, if your + platform doesn't use configure, and doesn't use the default values below + you will need to explicitly define these symbols in your make file. + + A PA_VALIDATE_SIZES macro is provided to assert that the values set in this + file are correct. +*/ + +#ifndef SIZEOF_SHORT +#define SIZEOF_SHORT 2 +#endif + +#ifndef SIZEOF_INT +#define SIZEOF_INT 4 +#endif + +#ifndef SIZEOF_LONG +#define SIZEOF_LONG 4 +#endif + + +#if SIZEOF_SHORT == 2 +typedef signed short PaInt16; +typedef unsigned short PaUint16; +#elif SIZEOF_INT == 2 +typedef signed int PaInt16; +typedef unsigned int PaUint16; +#else +#error pa_types.h was unable to determine which type to use for 16bit integers on the target platform +#endif + +#if SIZEOF_SHORT == 4 +typedef signed short PaInt32; +typedef unsigned short PaUint32; +#elif SIZEOF_INT == 4 +typedef signed int PaInt32; +typedef unsigned int PaUint32; +#elif SIZEOF_LONG == 4 +typedef signed long PaInt32; +typedef unsigned long PaUint32; +#else +#error pa_types.h was unable to determine which type to use for 32bit integers on the target platform +#endif + + +/* PA_VALIDATE_TYPE_SIZES compares the size of the integer types at runtime to + ensure that PortAudio was configured correctly, and raises an assertion if + they don't match the expected values. must be included in the + context in which this macro is used. +*/ +#define PA_VALIDATE_TYPE_SIZES \ + { \ + assert( "PortAudio: type sizes are not correct in pa_types.h" && sizeof( PaUint16 ) == 2 ); \ + assert( "PortAudio: type sizes are not correct in pa_types.h" && sizeof( PaInt16 ) == 2 ); \ + assert( "PortAudio: type sizes are not correct in pa_types.h" && sizeof( PaUint32 ) == 4 ); \ + assert( "PortAudio: type sizes are not correct in pa_types.h" && sizeof( PaInt32 ) == 4 ); \ + } + + +#endif /* PA_TYPES_H */ diff --git a/extern/portaudio/src/common/pa_util.h b/extern/portaudio/src/common/pa_util.h new file mode 100644 index 0000000..ad5dac5 --- /dev/null +++ b/extern/portaudio/src/common/pa_util.h @@ -0,0 +1,159 @@ +#ifndef PA_UTIL_H +#define PA_UTIL_H +/* + * $Id$ + * Portable Audio I/O Library implementation utilities header + * common implementation utilities and interfaces + * + * Based on the Open Source API proposed by Ross Bencina + * Copyright (c) 1999-2008 Ross Bencina, Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +/** @file + @ingroup common_src + + @brief Prototypes for utility functions used by PortAudio implementations. + + Some functions declared here are defined in pa_front.c while others + are implemented separately for each platform. +*/ + + +#include "portaudio.h" + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + +struct PaUtilHostApiRepresentation; + + +/** Retrieve a specific host API representation. This function can be used + by implementations to retrieve a pointer to their representation in + host api specific extension functions which aren't passed a rep pointer + by pa_front.c. + + @param hostApi A pointer to a host API represenation pointer. Apon success + this will receive the requested representation pointer. + + @param type A valid host API type identifier. + + @returns An error code. If the result is PaNoError then a pointer to the + requested host API representation will be stored in *hostApi. If the host API + specified by type is not found, this function returns paHostApiNotFound. +*/ +PaError PaUtil_GetHostApiRepresentation( struct PaUtilHostApiRepresentation **hostApi, + PaHostApiTypeId type ); + + +/** Convert a PortAudio device index into a host API specific device index. + @param hostApiDevice Pointer to a device index, on success this will recieve the + converted device index value. + @param device The PortAudio device index to convert. + @param hostApi The host api which the index should be converted for. + + @returns On success returns PaNoError and places the converted index in the + hostApiDevice parameter. +*/ +PaError PaUtil_DeviceIndexToHostApiDeviceIndex( + PaDeviceIndex *hostApiDevice, PaDeviceIndex device, + struct PaUtilHostApiRepresentation *hostApi ); + + +/** Set the host error information returned by Pa_GetLastHostErrorInfo. This + function and the paUnanticipatedHostError error code should be used as a + last resort. Implementors should use existing PA error codes where possible, + or nominate new ones. Note that at it is always better to use + PaUtil_SetLastHostErrorInfo() and paUnanticipatedHostError than to return an + ambiguous or inaccurate PaError code. + + @param hostApiType The host API which encountered the error (ie of the caller) + + @param errorCode The error code returned by the native API function. + + @param errorText A string describing the error. PaUtil_SetLastHostErrorInfo + makes a copy of the string, so it is not necessary for the pointer to remain + valid after the call to PaUtil_SetLastHostErrorInfo() returns. + +*/ +void PaUtil_SetLastHostErrorInfo( PaHostApiTypeId hostApiType, long errorCode, + const char *errorText ); + + + +/* the following functions are implemented in a platform platform specific + .c file +*/ + +/** Allocate size bytes, guaranteed to be aligned to a FIXME byte boundary */ +void *PaUtil_AllocateMemory( long size ); + + +/** Realease block if non-NULL. block may be NULL */ +void PaUtil_FreeMemory( void *block ); + + +/** Return the number of currently allocated blocks. This function can be + used for detecting memory leaks. + + @note Allocations will only be tracked if PA_TRACK_MEMORY is #defined. If + it isn't, this function will always return 0. +*/ +int PaUtil_CountCurrentlyAllocatedBlocks( void ); + + +/** Initialize the clock used by PaUtil_GetTime(). Call this before calling + PaUtil_GetTime. + + @see PaUtil_GetTime +*/ +void PaUtil_InitializeClock( void ); + + +/** Return the system time in seconds. Used to implement CPU load functions + + @see PaUtil_InitializeClock +*/ +double PaUtil_GetTime( void ); + + +/* void Pa_Sleep( long msec ); must also be implemented in per-platform .c file */ + + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* PA_UTIL_H */ diff --git a/extern/portaudio/src/hostapi/alsa/pa_linux_alsa.c b/extern/portaudio/src/hostapi/alsa/pa_linux_alsa.c new file mode 100644 index 0000000..584cde8 --- /dev/null +++ b/extern/portaudio/src/hostapi/alsa/pa_linux_alsa.c @@ -0,0 +1,4639 @@ +/* + * $Id$ + * PortAudio Portable Real-Time Audio Library + * Latest Version at: http://www.portaudio.com + * ALSA implementation by Joshua Haberman and Arve Knudsen + * + * Copyright (c) 2002 Joshua Haberman + * Copyright (c) 2005-2009 Arve Knudsen + * Copyright (c) 2008 Kevin Kofler + * + * Based on the Open Source API proposed by Ross Bencina + * Copyright (c) 1999-2002 Ross Bencina, Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +/** + @file + @ingroup hostapi_src +*/ + +#define ALSA_PCM_NEW_HW_PARAMS_API +#define ALSA_PCM_NEW_SW_PARAMS_API +#include +#undef ALSA_PCM_NEW_HW_PARAMS_API +#undef ALSA_PCM_NEW_SW_PARAMS_API + +#include +#include /* strlen() */ +#include +#include +#include +#include +#include +#include +#include /* For sig_atomic_t */ +#ifdef PA_ALSA_DYNAMIC + #include /* For dlXXX functions */ +#endif + +#include "portaudio.h" +#include "pa_util.h" +#include "pa_unix_util.h" +#include "pa_allocation.h" +#include "pa_hostapi.h" +#include "pa_stream.h" +#include "pa_cpuload.h" +#include "pa_process.h" +#include "pa_endianness.h" +#include "pa_debugprint.h" + +#include "pa_linux_alsa.h" + +/* Add missing define (for compatibility with older ALSA versions) */ +#ifndef SND_PCM_TSTAMP_ENABLE + #define SND_PCM_TSTAMP_ENABLE SND_PCM_TSTAMP_MMAP +#endif + +/* Combine version elements into a single (unsigned) integer */ +#define ALSA_VERSION_INT(major, minor, subminor) ((major << 16) | (minor << 8) | subminor) + +/* The acceptable tolerance of sample rate set, to that requested (as a ratio, eg 50 is 2%, 100 is 1%) */ +#define RATE_MAX_DEVIATE_RATIO 100 + +/* Defines Alsa function types and pointers to these functions. */ +#define _PA_DEFINE_FUNC(x) typedef typeof(x) x##_ft; static x##_ft *alsa_##x = 0 + +/* Alloca helper. */ +#define __alsa_snd_alloca(ptr,type) do { size_t __alsa_alloca_size = alsa_##type##_sizeof(); (*ptr) = (type##_t *) alloca(__alsa_alloca_size); memset(*ptr, 0, __alsa_alloca_size); } while (0) + +_PA_DEFINE_FUNC(snd_pcm_open); +_PA_DEFINE_FUNC(snd_pcm_close); +_PA_DEFINE_FUNC(snd_pcm_nonblock); +_PA_DEFINE_FUNC(snd_pcm_frames_to_bytes); +_PA_DEFINE_FUNC(snd_pcm_prepare); +_PA_DEFINE_FUNC(snd_pcm_start); +_PA_DEFINE_FUNC(snd_pcm_resume); +_PA_DEFINE_FUNC(snd_pcm_wait); +_PA_DEFINE_FUNC(snd_pcm_state); +_PA_DEFINE_FUNC(snd_pcm_avail_update); +_PA_DEFINE_FUNC(snd_pcm_areas_silence); +_PA_DEFINE_FUNC(snd_pcm_mmap_begin); +_PA_DEFINE_FUNC(snd_pcm_mmap_commit); +_PA_DEFINE_FUNC(snd_pcm_readi); +_PA_DEFINE_FUNC(snd_pcm_readn); +_PA_DEFINE_FUNC(snd_pcm_writei); +_PA_DEFINE_FUNC(snd_pcm_writen); +_PA_DEFINE_FUNC(snd_pcm_drain); +_PA_DEFINE_FUNC(snd_pcm_recover); +_PA_DEFINE_FUNC(snd_pcm_drop); +_PA_DEFINE_FUNC(snd_pcm_area_copy); +_PA_DEFINE_FUNC(snd_pcm_poll_descriptors); +_PA_DEFINE_FUNC(snd_pcm_poll_descriptors_count); +_PA_DEFINE_FUNC(snd_pcm_poll_descriptors_revents); +_PA_DEFINE_FUNC(snd_pcm_format_size); +_PA_DEFINE_FUNC(snd_pcm_link); +_PA_DEFINE_FUNC(snd_pcm_delay); + +_PA_DEFINE_FUNC(snd_pcm_hw_params_sizeof); +_PA_DEFINE_FUNC(snd_pcm_hw_params_malloc); +_PA_DEFINE_FUNC(snd_pcm_hw_params_free); +_PA_DEFINE_FUNC(snd_pcm_hw_params_any); +_PA_DEFINE_FUNC(snd_pcm_hw_params_set_access); +_PA_DEFINE_FUNC(snd_pcm_hw_params_set_format); +_PA_DEFINE_FUNC(snd_pcm_hw_params_set_channels); +//_PA_DEFINE_FUNC(snd_pcm_hw_params_set_periods_near); +_PA_DEFINE_FUNC(snd_pcm_hw_params_set_rate_near); //!!! +_PA_DEFINE_FUNC(snd_pcm_hw_params_set_rate); +_PA_DEFINE_FUNC(snd_pcm_hw_params_set_rate_resample); +//_PA_DEFINE_FUNC(snd_pcm_hw_params_set_buffer_time_near); +_PA_DEFINE_FUNC(snd_pcm_hw_params_set_buffer_size); +_PA_DEFINE_FUNC(snd_pcm_hw_params_set_buffer_size_near); //!!! +_PA_DEFINE_FUNC(snd_pcm_hw_params_set_buffer_size_min); +//_PA_DEFINE_FUNC(snd_pcm_hw_params_set_period_time_near); +_PA_DEFINE_FUNC(snd_pcm_hw_params_set_period_size_near); +_PA_DEFINE_FUNC(snd_pcm_hw_params_set_periods_integer); +_PA_DEFINE_FUNC(snd_pcm_hw_params_set_periods_min); + +_PA_DEFINE_FUNC(snd_pcm_hw_params_get_buffer_size); +//_PA_DEFINE_FUNC(snd_pcm_hw_params_get_period_size); +//_PA_DEFINE_FUNC(snd_pcm_hw_params_get_access); +//_PA_DEFINE_FUNC(snd_pcm_hw_params_get_periods); +//_PA_DEFINE_FUNC(snd_pcm_hw_params_get_rate); +_PA_DEFINE_FUNC(snd_pcm_hw_params_get_channels_min); +_PA_DEFINE_FUNC(snd_pcm_hw_params_get_channels_max); + +_PA_DEFINE_FUNC(snd_pcm_hw_params_test_period_size); +_PA_DEFINE_FUNC(snd_pcm_hw_params_test_format); +_PA_DEFINE_FUNC(snd_pcm_hw_params_test_access); +_PA_DEFINE_FUNC(snd_pcm_hw_params_dump); +_PA_DEFINE_FUNC(snd_pcm_hw_params); + +_PA_DEFINE_FUNC(snd_pcm_hw_params_get_periods_min); +_PA_DEFINE_FUNC(snd_pcm_hw_params_get_periods_max); +_PA_DEFINE_FUNC(snd_pcm_hw_params_set_period_size); +_PA_DEFINE_FUNC(snd_pcm_hw_params_get_period_size_min); +_PA_DEFINE_FUNC(snd_pcm_hw_params_get_period_size_max); +_PA_DEFINE_FUNC(snd_pcm_hw_params_get_buffer_size_max); +_PA_DEFINE_FUNC(snd_pcm_hw_params_get_rate_min); +_PA_DEFINE_FUNC(snd_pcm_hw_params_get_rate_max); +_PA_DEFINE_FUNC(snd_pcm_hw_params_get_rate_numden); +#define alsa_snd_pcm_hw_params_alloca(ptr) __alsa_snd_alloca(ptr, snd_pcm_hw_params) + +_PA_DEFINE_FUNC(snd_pcm_sw_params_sizeof); +_PA_DEFINE_FUNC(snd_pcm_sw_params_malloc); +_PA_DEFINE_FUNC(snd_pcm_sw_params_current); +_PA_DEFINE_FUNC(snd_pcm_sw_params_set_avail_min); +_PA_DEFINE_FUNC(snd_pcm_sw_params); +_PA_DEFINE_FUNC(snd_pcm_sw_params_free); +_PA_DEFINE_FUNC(snd_pcm_sw_params_set_start_threshold); +_PA_DEFINE_FUNC(snd_pcm_sw_params_set_stop_threshold); +_PA_DEFINE_FUNC(snd_pcm_sw_params_get_boundary); +_PA_DEFINE_FUNC(snd_pcm_sw_params_set_silence_threshold); +_PA_DEFINE_FUNC(snd_pcm_sw_params_set_silence_size); +_PA_DEFINE_FUNC(snd_pcm_sw_params_set_xfer_align); +_PA_DEFINE_FUNC(snd_pcm_sw_params_set_tstamp_mode); +#define alsa_snd_pcm_sw_params_alloca(ptr) __alsa_snd_alloca(ptr, snd_pcm_sw_params) + +_PA_DEFINE_FUNC(snd_pcm_info); +_PA_DEFINE_FUNC(snd_pcm_info_sizeof); +_PA_DEFINE_FUNC(snd_pcm_info_malloc); +_PA_DEFINE_FUNC(snd_pcm_info_free); +_PA_DEFINE_FUNC(snd_pcm_info_set_device); +_PA_DEFINE_FUNC(snd_pcm_info_set_subdevice); +_PA_DEFINE_FUNC(snd_pcm_info_set_stream); +_PA_DEFINE_FUNC(snd_pcm_info_get_name); +_PA_DEFINE_FUNC(snd_pcm_info_get_card); +#define alsa_snd_pcm_info_alloca(ptr) __alsa_snd_alloca(ptr, snd_pcm_info) + +_PA_DEFINE_FUNC(snd_ctl_pcm_next_device); +_PA_DEFINE_FUNC(snd_ctl_pcm_info); +_PA_DEFINE_FUNC(snd_ctl_open); +_PA_DEFINE_FUNC(snd_ctl_close); +_PA_DEFINE_FUNC(snd_ctl_card_info_malloc); +_PA_DEFINE_FUNC(snd_ctl_card_info_free); +_PA_DEFINE_FUNC(snd_ctl_card_info); +_PA_DEFINE_FUNC(snd_ctl_card_info_sizeof); +_PA_DEFINE_FUNC(snd_ctl_card_info_get_name); +#define alsa_snd_ctl_card_info_alloca(ptr) __alsa_snd_alloca(ptr, snd_ctl_card_info) + +_PA_DEFINE_FUNC(snd_config); +_PA_DEFINE_FUNC(snd_config_update); +_PA_DEFINE_FUNC(snd_config_search); +_PA_DEFINE_FUNC(snd_config_iterator_entry); +_PA_DEFINE_FUNC(snd_config_iterator_first); +_PA_DEFINE_FUNC(snd_config_iterator_end); +_PA_DEFINE_FUNC(snd_config_iterator_next); +_PA_DEFINE_FUNC(snd_config_get_string); +_PA_DEFINE_FUNC(snd_config_get_id); +_PA_DEFINE_FUNC(snd_config_update_free_global); + +_PA_DEFINE_FUNC(snd_pcm_status); +_PA_DEFINE_FUNC(snd_pcm_status_sizeof); +_PA_DEFINE_FUNC(snd_pcm_status_get_tstamp); +_PA_DEFINE_FUNC(snd_pcm_status_get_state); +_PA_DEFINE_FUNC(snd_pcm_status_get_trigger_tstamp); +_PA_DEFINE_FUNC(snd_pcm_status_get_delay); +#define alsa_snd_pcm_status_alloca(ptr) __alsa_snd_alloca(ptr, snd_pcm_status) + +_PA_DEFINE_FUNC(snd_card_next); +_PA_DEFINE_FUNC(snd_asoundlib_version); +_PA_DEFINE_FUNC(snd_strerror); +_PA_DEFINE_FUNC(snd_output_stdio_attach); + +#define alsa_snd_config_for_each(pos, next, node)\ + for (pos = alsa_snd_config_iterator_first(node),\ + next = alsa_snd_config_iterator_next(pos);\ + pos != alsa_snd_config_iterator_end(node); pos = next, next = alsa_snd_config_iterator_next(pos)) + +#undef _PA_DEFINE_FUNC + +/* Redefine 'PA_ALSA_PATHNAME' to a different Alsa library name if desired. */ +#ifndef PA_ALSA_PATHNAME + #define PA_ALSA_PATHNAME "libasound.so" +#endif +static const char *g_AlsaLibName = PA_ALSA_PATHNAME; + +/* Handle to dynamically loaded library. */ +static void *g_AlsaLib = NULL; + +#ifdef PA_ALSA_DYNAMIC + +#define _PA_LOCAL_IMPL(x) __pa_local_##x + +int _PA_LOCAL_IMPL(snd_pcm_hw_params_set_rate_near) (snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir) +{ + int ret; + + if(( ret = alsa_snd_pcm_hw_params_set_rate(pcm, params, (*val), (*dir)) ) < 0 ) + return ret; + + return 0; +} + +int _PA_LOCAL_IMPL(snd_pcm_hw_params_set_buffer_size_near) (snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val) +{ + int ret; + + if(( ret = alsa_snd_pcm_hw_params_set_buffer_size(pcm, params, (*val)) ) < 0 ) + return ret; + + return 0; +} + +int _PA_LOCAL_IMPL(snd_pcm_hw_params_set_period_size_near) (snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val, int *dir) +{ + int ret; + + if(( ret = alsa_snd_pcm_hw_params_set_period_size(pcm, params, (*val), (*dir)) ) < 0 ) + return ret; + + return 0; +} + +int _PA_LOCAL_IMPL(snd_pcm_hw_params_get_channels_min) (const snd_pcm_hw_params_t *params, unsigned int *val) +{ + (*val) = 1; + return 0; +} + +int _PA_LOCAL_IMPL(snd_pcm_hw_params_get_channels_max) (const snd_pcm_hw_params_t *params, unsigned int *val) +{ + (*val) = 2; + return 0; +} + +int _PA_LOCAL_IMPL(snd_pcm_hw_params_get_periods_min) (const snd_pcm_hw_params_t *params, unsigned int *val, int *dir) +{ + (*val) = 2; + return 0; +} + +int _PA_LOCAL_IMPL(snd_pcm_hw_params_get_periods_max) (const snd_pcm_hw_params_t *params, unsigned int *val, int *dir) +{ + (*val) = 8; + return 0; +} + +int _PA_LOCAL_IMPL(snd_pcm_hw_params_get_period_size_min) (const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *frames, int *dir) +{ + (*frames) = 64; + return 0; +} + +int _PA_LOCAL_IMPL(snd_pcm_hw_params_get_period_size_max) (const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *frames, int *dir) +{ + (*frames) = 512; + return 0; +} + +int _PA_LOCAL_IMPL(snd_pcm_hw_params_get_buffer_size_max) (const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val) +{ + int ret; + int dir = 0; + snd_pcm_uframes_t pmax = 0; + unsigned int pcnt = 0; + + if(( ret = _PA_LOCAL_IMPL(snd_pcm_hw_params_get_period_size_max)(params, &pmax, &dir) ) < 0 ) + return ret; + if(( ret = _PA_LOCAL_IMPL(snd_pcm_hw_params_get_periods_max)(params, &pcnt, &dir) ) < 0 ) + return ret; + + (*val) = pmax * pcnt; + return 0; +} + +int _PA_LOCAL_IMPL(snd_pcm_hw_params_get_rate_min) (const snd_pcm_hw_params_t *params, unsigned int *val, int *dir) +{ + (*val) = 44100; + return 0; +} + +int _PA_LOCAL_IMPL(snd_pcm_hw_params_get_rate_max) (const snd_pcm_hw_params_t *params, unsigned int *val, int *dir) +{ + (*val) = 44100; + return 0; +} + +#endif // PA_ALSA_DYNAMIC + +/* Trying to load Alsa library dynamically if 'PA_ALSA_DYNAMIC' is defined, othervise + will link during compilation. +*/ +static int PaAlsa_LoadLibrary() +{ +#ifdef PA_ALSA_DYNAMIC + + PA_DEBUG(( "%s: loading ALSA library file - %s\n", __FUNCTION__, g_AlsaLibName )); + + dlerror(); + g_AlsaLib = dlopen(g_AlsaLibName, (RTLD_NOW|RTLD_GLOBAL) ); + if (g_AlsaLib == NULL) + { + PA_DEBUG(( "%s: failed dlopen() ALSA library file - %s, error: %s\n", __FUNCTION__, g_AlsaLibName, dlerror() )); + return 0; + } + + PA_DEBUG(( "%s: loading ALSA API\n", __FUNCTION__ )); + + #define _PA_LOAD_FUNC(x) do { \ + alsa_##x = dlsym( g_AlsaLib, #x ); \ + if( alsa_##x == NULL ) { \ + PA_DEBUG(( "%s: symbol [%s] not found in - %s, error: %s\n", __FUNCTION__, #x, g_AlsaLibName, dlerror() )); }\ + } while(0) + +#else + + #define _PA_LOAD_FUNC(x) alsa_##x = &x + +#endif + + _PA_LOAD_FUNC(snd_pcm_open); + _PA_LOAD_FUNC(snd_pcm_close); + _PA_LOAD_FUNC(snd_pcm_nonblock); + _PA_LOAD_FUNC(snd_pcm_frames_to_bytes); + _PA_LOAD_FUNC(snd_pcm_prepare); + _PA_LOAD_FUNC(snd_pcm_start); + _PA_LOAD_FUNC(snd_pcm_resume); + _PA_LOAD_FUNC(snd_pcm_wait); + _PA_LOAD_FUNC(snd_pcm_state); + _PA_LOAD_FUNC(snd_pcm_avail_update); + _PA_LOAD_FUNC(snd_pcm_areas_silence); + _PA_LOAD_FUNC(snd_pcm_mmap_begin); + _PA_LOAD_FUNC(snd_pcm_mmap_commit); + _PA_LOAD_FUNC(snd_pcm_readi); + _PA_LOAD_FUNC(snd_pcm_readn); + _PA_LOAD_FUNC(snd_pcm_writei); + _PA_LOAD_FUNC(snd_pcm_writen); + _PA_LOAD_FUNC(snd_pcm_drain); + _PA_LOAD_FUNC(snd_pcm_recover); + _PA_LOAD_FUNC(snd_pcm_drop); + _PA_LOAD_FUNC(snd_pcm_area_copy); + _PA_LOAD_FUNC(snd_pcm_poll_descriptors); + _PA_LOAD_FUNC(snd_pcm_poll_descriptors_count); + _PA_LOAD_FUNC(snd_pcm_poll_descriptors_revents); + _PA_LOAD_FUNC(snd_pcm_format_size); + _PA_LOAD_FUNC(snd_pcm_link); + _PA_LOAD_FUNC(snd_pcm_delay); + + _PA_LOAD_FUNC(snd_pcm_hw_params_sizeof); + _PA_LOAD_FUNC(snd_pcm_hw_params_malloc); + _PA_LOAD_FUNC(snd_pcm_hw_params_free); + _PA_LOAD_FUNC(snd_pcm_hw_params_any); + _PA_LOAD_FUNC(snd_pcm_hw_params_set_access); + _PA_LOAD_FUNC(snd_pcm_hw_params_set_format); + _PA_LOAD_FUNC(snd_pcm_hw_params_set_channels); +// _PA_LOAD_FUNC(snd_pcm_hw_params_set_periods_near); + _PA_LOAD_FUNC(snd_pcm_hw_params_set_rate_near); + _PA_LOAD_FUNC(snd_pcm_hw_params_set_rate); + _PA_LOAD_FUNC(snd_pcm_hw_params_set_rate_resample); +// _PA_LOAD_FUNC(snd_pcm_hw_params_set_buffer_time_near); + _PA_LOAD_FUNC(snd_pcm_hw_params_set_buffer_size); + _PA_LOAD_FUNC(snd_pcm_hw_params_set_buffer_size_near); + _PA_LOAD_FUNC(snd_pcm_hw_params_set_buffer_size_min); +// _PA_LOAD_FUNC(snd_pcm_hw_params_set_period_time_near); + _PA_LOAD_FUNC(snd_pcm_hw_params_set_period_size_near); + _PA_LOAD_FUNC(snd_pcm_hw_params_set_periods_integer); + _PA_LOAD_FUNC(snd_pcm_hw_params_set_periods_min); + + _PA_LOAD_FUNC(snd_pcm_hw_params_get_buffer_size); +// _PA_LOAD_FUNC(snd_pcm_hw_params_get_period_size); +// _PA_LOAD_FUNC(snd_pcm_hw_params_get_access); +// _PA_LOAD_FUNC(snd_pcm_hw_params_get_periods); +// _PA_LOAD_FUNC(snd_pcm_hw_params_get_rate); + _PA_LOAD_FUNC(snd_pcm_hw_params_get_channels_min); + _PA_LOAD_FUNC(snd_pcm_hw_params_get_channels_max); + + _PA_LOAD_FUNC(snd_pcm_hw_params_test_period_size); + _PA_LOAD_FUNC(snd_pcm_hw_params_test_format); + _PA_LOAD_FUNC(snd_pcm_hw_params_test_access); + _PA_LOAD_FUNC(snd_pcm_hw_params_dump); + _PA_LOAD_FUNC(snd_pcm_hw_params); + + _PA_LOAD_FUNC(snd_pcm_hw_params_get_periods_min); + _PA_LOAD_FUNC(snd_pcm_hw_params_get_periods_max); + _PA_LOAD_FUNC(snd_pcm_hw_params_set_period_size); + _PA_LOAD_FUNC(snd_pcm_hw_params_get_period_size_min); + _PA_LOAD_FUNC(snd_pcm_hw_params_get_period_size_max); + _PA_LOAD_FUNC(snd_pcm_hw_params_get_buffer_size_max); + _PA_LOAD_FUNC(snd_pcm_hw_params_get_rate_min); + _PA_LOAD_FUNC(snd_pcm_hw_params_get_rate_max); + _PA_LOAD_FUNC(snd_pcm_hw_params_get_rate_numden); + + _PA_LOAD_FUNC(snd_pcm_sw_params_sizeof); + _PA_LOAD_FUNC(snd_pcm_sw_params_malloc); + _PA_LOAD_FUNC(snd_pcm_sw_params_current); + _PA_LOAD_FUNC(snd_pcm_sw_params_set_avail_min); + _PA_LOAD_FUNC(snd_pcm_sw_params); + _PA_LOAD_FUNC(snd_pcm_sw_params_free); + _PA_LOAD_FUNC(snd_pcm_sw_params_set_start_threshold); + _PA_LOAD_FUNC(snd_pcm_sw_params_set_stop_threshold); + _PA_LOAD_FUNC(snd_pcm_sw_params_get_boundary); + _PA_LOAD_FUNC(snd_pcm_sw_params_set_silence_threshold); + _PA_LOAD_FUNC(snd_pcm_sw_params_set_silence_size); + _PA_LOAD_FUNC(snd_pcm_sw_params_set_xfer_align); + _PA_LOAD_FUNC(snd_pcm_sw_params_set_tstamp_mode); + + _PA_LOAD_FUNC(snd_pcm_info); + _PA_LOAD_FUNC(snd_pcm_info_sizeof); + _PA_LOAD_FUNC(snd_pcm_info_malloc); + _PA_LOAD_FUNC(snd_pcm_info_free); + _PA_LOAD_FUNC(snd_pcm_info_set_device); + _PA_LOAD_FUNC(snd_pcm_info_set_subdevice); + _PA_LOAD_FUNC(snd_pcm_info_set_stream); + _PA_LOAD_FUNC(snd_pcm_info_get_name); + _PA_LOAD_FUNC(snd_pcm_info_get_card); + + _PA_LOAD_FUNC(snd_ctl_pcm_next_device); + _PA_LOAD_FUNC(snd_ctl_pcm_info); + _PA_LOAD_FUNC(snd_ctl_open); + _PA_LOAD_FUNC(snd_ctl_close); + _PA_LOAD_FUNC(snd_ctl_card_info_malloc); + _PA_LOAD_FUNC(snd_ctl_card_info_free); + _PA_LOAD_FUNC(snd_ctl_card_info); + _PA_LOAD_FUNC(snd_ctl_card_info_sizeof); + _PA_LOAD_FUNC(snd_ctl_card_info_get_name); + + _PA_LOAD_FUNC(snd_config); + _PA_LOAD_FUNC(snd_config_update); + _PA_LOAD_FUNC(snd_config_search); + _PA_LOAD_FUNC(snd_config_iterator_entry); + _PA_LOAD_FUNC(snd_config_iterator_first); + _PA_LOAD_FUNC(snd_config_iterator_end); + _PA_LOAD_FUNC(snd_config_iterator_next); + _PA_LOAD_FUNC(snd_config_get_string); + _PA_LOAD_FUNC(snd_config_get_id); + _PA_LOAD_FUNC(snd_config_update_free_global); + + _PA_LOAD_FUNC(snd_pcm_status); + _PA_LOAD_FUNC(snd_pcm_status_sizeof); + _PA_LOAD_FUNC(snd_pcm_status_get_tstamp); + _PA_LOAD_FUNC(snd_pcm_status_get_state); + _PA_LOAD_FUNC(snd_pcm_status_get_trigger_tstamp); + _PA_LOAD_FUNC(snd_pcm_status_get_delay); + + _PA_LOAD_FUNC(snd_card_next); + _PA_LOAD_FUNC(snd_asoundlib_version); + _PA_LOAD_FUNC(snd_strerror); + _PA_LOAD_FUNC(snd_output_stdio_attach); +#undef _PA_LOAD_FUNC + +#ifdef PA_ALSA_DYNAMIC + PA_DEBUG(( "%s: loaded ALSA API - ok\n", __FUNCTION__ )); + +#define _PA_VALIDATE_LOAD_REPLACEMENT(x)\ + do {\ + if( alsa_##x == NULL )\ + {\ + alsa_##x = &_PA_LOCAL_IMPL(x);\ + PA_DEBUG(( "%s: replacing [%s] with local implementation\n", __FUNCTION__, #x ));\ + }\ + } while (0) + + _PA_VALIDATE_LOAD_REPLACEMENT(snd_pcm_hw_params_set_rate_near); + _PA_VALIDATE_LOAD_REPLACEMENT(snd_pcm_hw_params_set_buffer_size_near); + _PA_VALIDATE_LOAD_REPLACEMENT(snd_pcm_hw_params_set_period_size_near); + _PA_VALIDATE_LOAD_REPLACEMENT(snd_pcm_hw_params_get_channels_min); + _PA_VALIDATE_LOAD_REPLACEMENT(snd_pcm_hw_params_get_channels_max); + _PA_VALIDATE_LOAD_REPLACEMENT(snd_pcm_hw_params_get_periods_min); + _PA_VALIDATE_LOAD_REPLACEMENT(snd_pcm_hw_params_get_periods_max); + _PA_VALIDATE_LOAD_REPLACEMENT(snd_pcm_hw_params_get_period_size_min); + _PA_VALIDATE_LOAD_REPLACEMENT(snd_pcm_hw_params_get_period_size_max); + _PA_VALIDATE_LOAD_REPLACEMENT(snd_pcm_hw_params_get_buffer_size_max); + _PA_VALIDATE_LOAD_REPLACEMENT(snd_pcm_hw_params_get_rate_min); + _PA_VALIDATE_LOAD_REPLACEMENT(snd_pcm_hw_params_get_rate_max); + +#undef _PA_LOCAL_IMPL +#undef _PA_VALIDATE_LOAD_REPLACEMENT + +#endif // PA_ALSA_DYNAMIC + + return 1; +} + +void PaAlsa_SetLibraryPathName( const char *pathName ) +{ +#ifdef PA_ALSA_DYNAMIC + g_AlsaLibName = pathName; +#else + (void)pathName; +#endif +} + +/* Close handle to Alsa library. */ +static void PaAlsa_CloseLibrary() +{ +#ifdef PA_ALSA_DYNAMIC + dlclose(g_AlsaLib); + g_AlsaLib = NULL; +#endif +} + +/* Check return value of ALSA function, and map it to PaError */ +#define ENSURE_(expr, code) \ + do { \ + int __pa_unsure_error_id;\ + if( UNLIKELY( (__pa_unsure_error_id = (expr)) < 0 ) ) \ + { \ + /* PaUtil_SetLastHostErrorInfo should only be used in the main thread */ \ + if( (code) == paUnanticipatedHostError && pthread_equal( pthread_self(), paUnixMainThread) ) \ + { \ + PaUtil_SetLastHostErrorInfo( paALSA, __pa_unsure_error_id, alsa_snd_strerror( __pa_unsure_error_id ) ); \ + } \ + PaUtil_DebugPrint( "Expression '" #expr "' failed in '" __FILE__ "', line: " STRINGIZE( __LINE__ ) "\n" ); \ + if( (code) == paUnanticipatedHostError ) \ + PA_DEBUG(( "Host error description: %s\n", alsa_snd_strerror( __pa_unsure_error_id ) )); \ + result = (code); \ + goto error; \ + } \ + } while (0) + +#define ASSERT_CALL_(expr, success) \ + do {\ + int __pa_assert_error_id;\ + __pa_assert_error_id = (expr);\ + assert( success == __pa_assert_error_id );\ + } while (0) + +static int numPeriods_ = 4; +static int busyRetries_ = 100; + +int PaAlsa_SetNumPeriods( int numPeriods ) +{ + numPeriods_ = numPeriods; + return paNoError; +} + +typedef enum +{ + StreamDirection_In, + StreamDirection_Out +} StreamDirection; + +typedef struct +{ + PaSampleFormat hostSampleFormat; + int numUserChannels, numHostChannels; + int userInterleaved, hostInterleaved; + int canMmap; + void *nonMmapBuffer; + unsigned int nonMmapBufferSize; + PaDeviceIndex device; /* Keep the device index */ + int deviceIsPlug; /* Distinguish plug types from direct 'hw:' devices */ + int useReventFix; /* Alsa older than 1.0.16, plug devices need a fix */ + + snd_pcm_t *pcm; + snd_pcm_uframes_t framesPerPeriod, alsaBufferSize; + snd_pcm_format_t nativeFormat; + unsigned int nfds; + int ready; /* Marked ready from poll */ + void **userBuffers; + snd_pcm_uframes_t offset; + StreamDirection streamDir; + + snd_pcm_channel_area_t *channelAreas; /* Needed for channel adaption */ +} PaAlsaStreamComponent; + +/* Implementation specific stream structure */ +typedef struct PaAlsaStream +{ + PaUtilStreamRepresentation streamRepresentation; + PaUtilCpuLoadMeasurer cpuLoadMeasurer; + PaUtilBufferProcessor bufferProcessor; + PaUnixThread thread; + + unsigned long framesPerUserBuffer, maxFramesPerHostBuffer; + + int primeBuffers; + int callbackMode; /* bool: are we running in callback mode? */ + int pcmsSynced; /* Have we successfully synced pcms */ + int rtSched; + + /* the callback thread uses these to poll the sound device(s), waiting + * for data to be ready/available */ + struct pollfd* pfds; + int pollTimeout; + + /* Used in communication between threads */ + volatile sig_atomic_t callback_finished; /* bool: are we in the "callback finished" state? */ + volatile sig_atomic_t callbackAbort; /* Drop frames? */ + volatile sig_atomic_t isActive; /* Is stream in active state? (Between StartStream and StopStream || !paContinue) */ + PaUnixMutex stateMtx; /* Used to synchronize access to stream state */ + + int neverDropInput; + + PaTime underrun; + PaTime overrun; + + PaAlsaStreamComponent capture, playback; +} +PaAlsaStream; + +/* PaAlsaHostApiRepresentation - host api datastructure specific to this implementation */ + +typedef struct PaAlsaHostApiRepresentation +{ + PaUtilHostApiRepresentation baseHostApiRep; + PaUtilStreamInterface callbackStreamInterface; + PaUtilStreamInterface blockingStreamInterface; + + PaUtilAllocationGroup *allocations; + + PaHostApiIndex hostApiIndex; + PaUint32 alsaLibVersion; /* Retrieved from the library at run-time */ +} +PaAlsaHostApiRepresentation; + +typedef struct PaAlsaDeviceInfo +{ + PaDeviceInfo baseDeviceInfo; + char *alsaName; + int isPlug; + int minInputChannels; + int minOutputChannels; +} +PaAlsaDeviceInfo; + +/* prototypes for functions declared in this file */ + +static void Terminate( struct PaUtilHostApiRepresentation *hostApi ); +static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi, + const PaStreamParameters *inputParameters, + const PaStreamParameters *outputParameters, + double sampleRate ); +static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, + PaStream** s, + const PaStreamParameters *inputParameters, + const PaStreamParameters *outputParameters, + double sampleRate, + unsigned long framesPerBuffer, + PaStreamFlags streamFlags, + PaStreamCallback *callback, + void *userData ); +static PaError CloseStream( PaStream* stream ); +static PaError StartStream( PaStream *stream ); +static PaError StopStream( PaStream *stream ); +static PaError AbortStream( PaStream *stream ); +static PaError IsStreamStopped( PaStream *s ); +static PaError IsStreamActive( PaStream *stream ); +static PaTime GetStreamTime( PaStream *stream ); +static double GetStreamCpuLoad( PaStream* stream ); +static PaError BuildDeviceList( PaAlsaHostApiRepresentation *hostApi ); +static int SetApproximateSampleRate( snd_pcm_t *pcm, snd_pcm_hw_params_t *hwParams, double sampleRate ); +static int GetExactSampleRate( snd_pcm_hw_params_t *hwParams, double *sampleRate ); +static PaUint32 PaAlsaVersionNum(void); + +/* Callback prototypes */ +static void *CallbackThreadFunc( void *userData ); + +/* Blocking prototypes */ +static signed long GetStreamReadAvailable( PaStream* s ); +static signed long GetStreamWriteAvailable( PaStream* s ); +static PaError ReadStream( PaStream* stream, void *buffer, unsigned long frames ); +static PaError WriteStream( PaStream* stream, const void *buffer, unsigned long frames ); + + +static const PaAlsaDeviceInfo *GetDeviceInfo( const PaUtilHostApiRepresentation *hostApi, int device ) +{ + return (const PaAlsaDeviceInfo *)hostApi->deviceInfos[device]; +} + +/** Uncommented because AlsaErrorHandler is unused for anything good yet. If AlsaErrorHandler is + to be used, do not forget to register this callback in PaAlsa_Initialize, and unregister in Terminate. +*/ +/*static void AlsaErrorHandler(const char *file, int line, const char *function, int err, const char *fmt, ...) +{ +}*/ + +PaError PaAlsa_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex ) +{ + PaError result = paNoError; + PaAlsaHostApiRepresentation *alsaHostApi = NULL; + + /* Try loading Alsa library. */ + if (!PaAlsa_LoadLibrary()) + return paHostApiNotFound; + + PA_UNLESS( alsaHostApi = (PaAlsaHostApiRepresentation*) PaUtil_AllocateMemory( + sizeof(PaAlsaHostApiRepresentation) ), paInsufficientMemory ); + PA_UNLESS( alsaHostApi->allocations = PaUtil_CreateAllocationGroup(), paInsufficientMemory ); + alsaHostApi->hostApiIndex = hostApiIndex; + alsaHostApi->alsaLibVersion = PaAlsaVersionNum(); + + *hostApi = (PaUtilHostApiRepresentation*)alsaHostApi; + (*hostApi)->info.structVersion = 1; + (*hostApi)->info.type = paALSA; + (*hostApi)->info.name = "ALSA"; + + (*hostApi)->Terminate = Terminate; + (*hostApi)->OpenStream = OpenStream; + (*hostApi)->IsFormatSupported = IsFormatSupported; + + /** If AlsaErrorHandler is to be used, do not forget to unregister callback pointer in + Terminate function. + */ + /*ENSURE_( snd_lib_error_set_handler(AlsaErrorHandler), paUnanticipatedHostError );*/ + + PA_ENSURE( BuildDeviceList( alsaHostApi ) ); + + PaUtil_InitializeStreamInterface( &alsaHostApi->callbackStreamInterface, + CloseStream, StartStream, + StopStream, AbortStream, + IsStreamStopped, IsStreamActive, + GetStreamTime, GetStreamCpuLoad, + PaUtil_DummyRead, PaUtil_DummyWrite, + PaUtil_DummyGetReadAvailable, + PaUtil_DummyGetWriteAvailable ); + + PaUtil_InitializeStreamInterface( &alsaHostApi->blockingStreamInterface, + CloseStream, StartStream, + StopStream, AbortStream, + IsStreamStopped, IsStreamActive, + GetStreamTime, PaUtil_DummyGetCpuLoad, + ReadStream, WriteStream, + GetStreamReadAvailable, + GetStreamWriteAvailable ); + + PA_ENSURE( PaUnixThreading_Initialize() ); + + return result; + +error: + if( alsaHostApi ) + { + if( alsaHostApi->allocations ) + { + PaUtil_FreeAllAllocations( alsaHostApi->allocations ); + PaUtil_DestroyAllocationGroup( alsaHostApi->allocations ); + } + + PaUtil_FreeMemory( alsaHostApi ); + } + + return result; +} + +static void Terminate( struct PaUtilHostApiRepresentation *hostApi ) +{ + PaAlsaHostApiRepresentation *alsaHostApi = (PaAlsaHostApiRepresentation*)hostApi; + + assert( hostApi ); + + /** See AlsaErrorHandler and PaAlsa_Initialize for details. + */ + /*snd_lib_error_set_handler(NULL);*/ + + if( alsaHostApi->allocations ) + { + PaUtil_FreeAllAllocations( alsaHostApi->allocations ); + PaUtil_DestroyAllocationGroup( alsaHostApi->allocations ); + } + + PaUtil_FreeMemory( alsaHostApi ); + alsa_snd_config_update_free_global(); + + /* Close Alsa library. */ + PaAlsa_CloseLibrary(); +} + +/** Determine max channels and default latencies. + * + * This function provides functionality to grope an opened (might be opened for capture or playback) pcm device for + * traits like max channels, suitable default latencies and default sample rate. Upon error, max channels is set to zero, + * and a suitable result returned. The device is closed before returning. + */ +static PaError GropeDevice( snd_pcm_t* pcm, int isPlug, StreamDirection mode, int openBlocking, + PaAlsaDeviceInfo* devInfo ) +{ + PaError result = paNoError; + snd_pcm_hw_params_t *hwParams; + snd_pcm_uframes_t alsaBufferFrames, alsaPeriodFrames; + unsigned int minChans, maxChans; + int* minChannels, * maxChannels; + double * defaultLowLatency, * defaultHighLatency, * defaultSampleRate = + &devInfo->baseDeviceInfo.defaultSampleRate; + double defaultSr = *defaultSampleRate; + int dir; + + assert( pcm ); + + PA_DEBUG(( "%s: collecting info ..\n", __FUNCTION__ )); + + if( StreamDirection_In == mode ) + { + minChannels = &devInfo->minInputChannels; + maxChannels = &devInfo->baseDeviceInfo.maxInputChannels; + defaultLowLatency = &devInfo->baseDeviceInfo.defaultLowInputLatency; + defaultHighLatency = &devInfo->baseDeviceInfo.defaultHighInputLatency; + } + else + { + minChannels = &devInfo->minOutputChannels; + maxChannels = &devInfo->baseDeviceInfo.maxOutputChannels; + defaultLowLatency = &devInfo->baseDeviceInfo.defaultLowOutputLatency; + defaultHighLatency = &devInfo->baseDeviceInfo.defaultHighOutputLatency; + } + + ENSURE_( alsa_snd_pcm_nonblock( pcm, 0 ), paUnanticipatedHostError ); + + alsa_snd_pcm_hw_params_alloca( &hwParams ); + alsa_snd_pcm_hw_params_any( pcm, hwParams ); + + if( defaultSr >= 0 ) + { + /* Could be that the device opened in one mode supports samplerates that the other mode wont have, + * so try again .. */ + if( SetApproximateSampleRate( pcm, hwParams, defaultSr ) < 0 ) + { + defaultSr = -1.; + alsa_snd_pcm_hw_params_any( pcm, hwParams ); /* Clear any params (rate) that might have been set */ + PA_DEBUG(( "%s: Original default samplerate failed, trying again ..\n", __FUNCTION__ )); + } + } + + if( defaultSr < 0. ) /* Default sample rate not set */ + { + unsigned int sampleRate = 44100; /* Will contain approximate rate returned by alsa-lib */ + + /* Don't allow rate resampling when probing for the default rate (but ignore if this call fails) */ + alsa_snd_pcm_hw_params_set_rate_resample( pcm, hwParams, 0 ); + if( alsa_snd_pcm_hw_params_set_rate_near( pcm, hwParams, &sampleRate, NULL ) < 0 ) + { + result = paUnanticipatedHostError; + goto error; + } + ENSURE_( GetExactSampleRate( hwParams, &defaultSr ), paUnanticipatedHostError ); + } + + ENSURE_( alsa_snd_pcm_hw_params_get_channels_min( hwParams, &minChans ), paUnanticipatedHostError ); + ENSURE_( alsa_snd_pcm_hw_params_get_channels_max( hwParams, &maxChans ), paUnanticipatedHostError ); + assert( maxChans <= INT_MAX ); + assert( maxChans > 0 ); /* Weird linking issue could cause wrong version of ALSA symbols to be called, + resulting in zeroed values */ + + /* XXX: Limit to sensible number (ALSA plugins accept a crazy amount of channels)? */ + if( isPlug && maxChans > 128 ) + { + maxChans = 128; + PA_DEBUG(( "%s: Limiting number of plugin channels to %u\n", __FUNCTION__, maxChans )); + } + + /* TWEAKME: + * Giving values for default min and max latency is not straightforward. + * * for low latency, we want to give the lowest value that will work reliably. + * This varies based on the sound card, kernel, CPU, etc. Better to give + * sub-optimal latency than to give a number too low and cause dropouts. + * * for high latency we want to give a large enough value that dropouts are basically impossible. + * This doesn't really require as much tweaking, since providing too large a number will + * just cause us to select the nearest setting that will work at stream config time. + */ + /* Try low latency values, (sometimes the buffer & period that result are larger) */ + alsaBufferFrames = 512; + alsaPeriodFrames = 128; + ENSURE_( alsa_snd_pcm_hw_params_set_buffer_size_near( pcm, hwParams, &alsaBufferFrames ), paUnanticipatedHostError ); + ENSURE_( alsa_snd_pcm_hw_params_set_period_size_near( pcm, hwParams, &alsaPeriodFrames, &dir ), paUnanticipatedHostError ); + *defaultLowLatency = (double) (alsaBufferFrames - alsaPeriodFrames) / defaultSr; + + /* Base the high latency case on values four times larger */ + alsaBufferFrames = 2048; + alsaPeriodFrames = 512; + /* Have to reset hwParams, to set new buffer size; need to also set sample rate again */ + ENSURE_( alsa_snd_pcm_hw_params_any( pcm, hwParams ), paUnanticipatedHostError ); + ENSURE_( SetApproximateSampleRate( pcm, hwParams, defaultSr ), paUnanticipatedHostError ); + ENSURE_( alsa_snd_pcm_hw_params_set_buffer_size_near( pcm, hwParams, &alsaBufferFrames ), paUnanticipatedHostError ); + ENSURE_( alsa_snd_pcm_hw_params_set_period_size_near( pcm, hwParams, &alsaPeriodFrames, &dir ), paUnanticipatedHostError ); + *defaultHighLatency = (double) (alsaBufferFrames - alsaPeriodFrames) / defaultSr; + + *minChannels = (int)minChans; + *maxChannels = (int)maxChans; + *defaultSampleRate = defaultSr; + +end: + alsa_snd_pcm_close( pcm ); + return result; + +error: + goto end; +} + +/* Initialize device info with invalid values (maxInputChannels and maxOutputChannels are set to zero since these indicate + * whether input/output is available) */ +static void InitializeDeviceInfo( PaDeviceInfo *deviceInfo ) +{ + deviceInfo->structVersion = -1; + deviceInfo->name = NULL; + deviceInfo->hostApi = -1; + deviceInfo->maxInputChannels = 0; + deviceInfo->maxOutputChannels = 0; + deviceInfo->defaultLowInputLatency = -1.; + deviceInfo->defaultLowOutputLatency = -1.; + deviceInfo->defaultHighInputLatency = -1.; + deviceInfo->defaultHighOutputLatency = -1.; + deviceInfo->defaultSampleRate = -1.; +} + + +/* Retrieve the version of the runtime Alsa-lib, as a single number equivalent to + * SND_LIB_VERSION. Only a version string is available ("a.b.c") so this has to be converted. + * Assume 'a' and 'b' are single digits only. + */ +static PaUint32 PaAlsaVersionNum(void) +{ + char* verStr; + PaUint32 verNum; + + verStr = (char*) alsa_snd_asoundlib_version(); + verNum = ALSA_VERSION_INT( atoi(verStr), atoi(verStr + 2), atoi(verStr + 4) ); + PA_DEBUG(( "ALSA version (build): " SND_LIB_VERSION_STR "\nALSA version (runtime): %s\n", verStr )); + + return verNum; +} + + +/* Helper struct */ +typedef struct +{ + char *alsaName; + char *name; + int isPlug; + int hasPlayback; + int hasCapture; +} HwDevInfo; + + +HwDevInfo predefinedNames[] = { + { "center_lfe", NULL, 0, 1, 0 }, +/* { "default", NULL, 0, 1, 1 }, */ + { "dmix", NULL, 0, 1, 0 }, +/* { "dpl", NULL, 0, 1, 0 }, */ +/* { "dsnoop", NULL, 0, 0, 1 }, */ + { "front", NULL, 0, 1, 0 }, + { "iec958", NULL, 0, 1, 0 }, +/* { "modem", NULL, 0, 1, 0 }, */ + { "rear", NULL, 0, 1, 0 }, + { "side", NULL, 0, 1, 0 }, +/* { "spdif", NULL, 0, 0, 0 }, */ + { "surround40", NULL, 0, 1, 0 }, + { "surround41", NULL, 0, 1, 0 }, + { "surround50", NULL, 0, 1, 0 }, + { "surround51", NULL, 0, 1, 0 }, + { "surround71", NULL, 0, 1, 0 }, + + { "AndroidPlayback_Earpiece_normal", NULL, 0, 1, 0 }, + { "AndroidPlayback_Speaker_normal", NULL, 0, 1, 0 }, + { "AndroidPlayback_Bluetooth_normal", NULL, 0, 1, 0 }, + { "AndroidPlayback_Headset_normal", NULL, 0, 1, 0 }, + { "AndroidPlayback_Speaker_Headset_normal", NULL, 0, 1, 0 }, + { "AndroidPlayback_Bluetooth-A2DP_normal", NULL, 0, 1, 0 }, + { "AndroidPlayback_ExtraDockSpeaker_normal", NULL, 0, 1, 0 }, + { "AndroidPlayback_TvOut_normal", NULL, 0, 1, 0 }, + + { "AndroidRecord_Microphone", NULL, 0, 0, 1 }, + { "AndroidRecord_Earpiece_normal", NULL, 0, 0, 1 }, + { "AndroidRecord_Speaker_normal", NULL, 0, 0, 1 }, + { "AndroidRecord_Headset_normal", NULL, 0, 0, 1 }, + { "AndroidRecord_Bluetooth_normal", NULL, 0, 0, 1 }, + { "AndroidRecord_Speaker_Headset_normal", NULL, 0, 0, 1 }, + + { NULL, NULL, 0, 1, 0 } +}; + +static const HwDevInfo *FindDeviceName( const char *name ) +{ + int i; + + for( i = 0; predefinedNames[i].alsaName; i++ ) + { + if( strcmp( name, predefinedNames[i].alsaName ) == 0 ) + { + return &predefinedNames[i]; + } + } + + return NULL; +} + +static PaError PaAlsa_StrDup( PaAlsaHostApiRepresentation *alsaApi, + char **dst, + const char *src) +{ + PaError result = paNoError; + int len = strlen( src ) + 1; + + /* PA_DEBUG(("PaStrDup %s %d\n", src, len)); */ + + PA_UNLESS( *dst = (char *)PaUtil_GroupAllocateMemory( alsaApi->allocations, len ), + paInsufficientMemory ); + strncpy( *dst, src, len ); + +error: + return result; +} + +/* Disregard some standard plugins + */ +static int IgnorePlugin( const char *pluginId ) +{ + static const char *ignoredPlugins[] = {"hw", "plughw", "plug", "dsnoop", "tee", + "file", "null", "shm", "cards", "rate_convert", NULL}; + int i = 0; + while( ignoredPlugins[i] ) + { + if( !strcmp( pluginId, ignoredPlugins[i] ) ) + { + return 1; + } + ++i; + } + + return 0; +} + +/* Skip past parts at the beginning of a (pcm) info name that are already in the card name, to avoid duplication */ +static char *SkipCardDetailsInName( char *infoSkipName, char *cardRefName ) +{ + char *lastSpacePosn = infoSkipName; + + /* Skip matching chars; but only in chunks separated by ' ' (not part words etc), so track lastSpacePosn */ + while( *cardRefName ) + { + while( *infoSkipName && *cardRefName && *infoSkipName == *cardRefName) + { + infoSkipName++; + cardRefName++; + if( *infoSkipName == ' ' || *infoSkipName == '\0' ) + lastSpacePosn = infoSkipName; + } + infoSkipName = lastSpacePosn; + /* Look for another chunk; post-increment means ends pointing to next char */ + while( *cardRefName && ( *cardRefName++ != ' ' )); + } + if( *infoSkipName == '\0' ) + return "-"; /* The 2 names were identical; instead of a nul-string, return a marker string */ + + /* Now want to move to the first char after any spaces */ + while( *lastSpacePosn && *lastSpacePosn == ' ' ) + lastSpacePosn++; + /* Skip a single separator char if present in the remaining pcm name; (pa will add its own) */ + if(( *lastSpacePosn == '-' || *lastSpacePosn == ':' ) && *(lastSpacePosn + 1) == ' ' ) + lastSpacePosn += 2; + + return lastSpacePosn; +} + +/** Open PCM device. + * + * Wrapper around alsa_snd_pcm_open which may repeatedly retry opening a device if it is busy, for + * a certain time. This is because dmix may temporarily hold on to a device after it (dmix) + * has been opened and closed. + * @param mode: Open mode (e.g., SND_PCM_BLOCKING). + * @param waitOnBusy: Retry opening busy device for up to one second? + **/ +static int OpenPcm( snd_pcm_t **pcmp, const char *name, snd_pcm_stream_t stream, int mode, int waitOnBusy ) +{ + int ret, tries = 0, maxTries = waitOnBusy ? busyRetries_ : 0; + + ret = alsa_snd_pcm_open( pcmp, name, stream, mode ); + + for( tries = 0; tries < maxTries && -EBUSY == ret; ++tries ) + { + Pa_Sleep( 10 ); + ret = alsa_snd_pcm_open( pcmp, name, stream, mode ); + if( -EBUSY != ret ) + { + PA_DEBUG(( "%s: Successfully opened initially busy device after %d tries\n", __FUNCTION__, tries )); + } + } + if( -EBUSY == ret ) + { + PA_DEBUG(( "%s: Failed to open busy device '%s'\n", __FUNCTION__, name )); + } + else + { + if( ret < 0 ) + PA_DEBUG(( "%s: Opened device '%s' ptr[%p] - result: [%d:%s]\n", __FUNCTION__, name, *pcmp, ret, alsa_snd_strerror(ret) )); + } + + return ret; +} + +static PaError FillInDevInfo( PaAlsaHostApiRepresentation *alsaApi, HwDevInfo* deviceHwInfo, int blocking, + PaAlsaDeviceInfo* devInfo, int* devIdx ) +{ + PaError result = 0; + PaDeviceInfo *baseDeviceInfo = &devInfo->baseDeviceInfo; + snd_pcm_t *pcm = NULL; + PaUtilHostApiRepresentation *baseApi = &alsaApi->baseHostApiRep; + + PA_DEBUG(( "%s: Filling device info for: %s\n", __FUNCTION__, deviceHwInfo->name )); + + /* Zero fields */ + InitializeDeviceInfo( baseDeviceInfo ); + + /* To determine device capabilities, we must open the device and query the + * hardware parameter configuration space */ + + /* Query capture */ + if( deviceHwInfo->hasCapture && + OpenPcm( &pcm, deviceHwInfo->alsaName, SND_PCM_STREAM_CAPTURE, blocking, 0 ) >= 0 ) + { + if( GropeDevice( pcm, deviceHwInfo->isPlug, StreamDirection_In, blocking, devInfo ) != paNoError ) + { + /* Error */ + PA_DEBUG(( "%s: Failed groping %s for capture\n", __FUNCTION__, deviceHwInfo->alsaName )); + goto end; + } + } + + /* Query playback */ + if( deviceHwInfo->hasPlayback && + OpenPcm( &pcm, deviceHwInfo->alsaName, SND_PCM_STREAM_PLAYBACK, blocking, 0 ) >= 0 ) + { + if( GropeDevice( pcm, deviceHwInfo->isPlug, StreamDirection_Out, blocking, devInfo ) != paNoError ) + { + /* Error */ + PA_DEBUG(( "%s: Failed groping %s for playback\n", __FUNCTION__, deviceHwInfo->alsaName )); + goto end; + } + } + + baseDeviceInfo->structVersion = 2; + baseDeviceInfo->hostApi = alsaApi->hostApiIndex; + baseDeviceInfo->name = deviceHwInfo->name; + devInfo->alsaName = deviceHwInfo->alsaName; + devInfo->isPlug = deviceHwInfo->isPlug; + + /* A: Storing pointer to PaAlsaDeviceInfo object as pointer to PaDeviceInfo object. + * Should now be safe to add device info, unless the device supports neither capture nor playback + */ + if( baseDeviceInfo->maxInputChannels > 0 || baseDeviceInfo->maxOutputChannels > 0 ) + { + /* Make device default if there isn't already one or it is the ALSA "default" device */ + if( ( baseApi->info.defaultInputDevice == paNoDevice || + !strcmp( deviceHwInfo->alsaName, "default" ) ) && baseDeviceInfo->maxInputChannels > 0 ) + { + baseApi->info.defaultInputDevice = *devIdx; + PA_DEBUG(( "Default input device: %s\n", deviceHwInfo->name )); + } + if( ( baseApi->info.defaultOutputDevice == paNoDevice || + !strcmp( deviceHwInfo->alsaName, "default" ) ) && baseDeviceInfo->maxOutputChannels > 0 ) + { + baseApi->info.defaultOutputDevice = *devIdx; + PA_DEBUG(( "Default output device: %s\n", deviceHwInfo->name )); + } + PA_DEBUG(( "%s: Adding device %s: %d\n", __FUNCTION__, deviceHwInfo->name, *devIdx )); + baseApi->deviceInfos[*devIdx] = (PaDeviceInfo *) devInfo; + (*devIdx) += 1; + } + else + { + PA_DEBUG(( "%s: Skipped device: %s, all channels == 0\n", __FUNCTION__, deviceHwInfo->name )); + } + +end: + return result; +} + +/* Build PaDeviceInfo list, ignore devices for which we cannot determine capabilities (possibly busy, sigh) */ +static PaError BuildDeviceList( PaAlsaHostApiRepresentation *alsaApi ) +{ + PaUtilHostApiRepresentation *baseApi = &alsaApi->baseHostApiRep; + PaAlsaDeviceInfo *deviceInfoArray; + int cardIdx = -1, devIdx = 0; + snd_ctl_card_info_t *cardInfo; + PaError result = paNoError; + size_t numDeviceNames = 0, maxDeviceNames = 1, i; + HwDevInfo *hwDevInfos = NULL; + snd_config_t *topNode = NULL; + snd_pcm_info_t *pcmInfo; + int res; + int blocking = SND_PCM_NONBLOCK; + int usePlughw = 0; + char *hwPrefix = ""; + char alsaCardName[50]; +#ifdef PA_ENABLE_DEBUG_OUTPUT + PaTime startTime = PaUtil_GetTime(); +#endif + + if( getenv( "PA_ALSA_INITIALIZE_BLOCK" ) && atoi( getenv( "PA_ALSA_INITIALIZE_BLOCK" ) ) ) + blocking = 0; + + /* If PA_ALSA_PLUGHW is 1 (non-zero), use the plughw: pcm throughout instead of hw: */ + if( getenv( "PA_ALSA_PLUGHW" ) && atoi( getenv( "PA_ALSA_PLUGHW" ) ) ) + { + usePlughw = 1; + hwPrefix = "plug"; + PA_DEBUG(( "%s: Using Plughw\n", __FUNCTION__ )); + } + + /* These two will be set to the first working input and output device, respectively */ + baseApi->info.defaultInputDevice = paNoDevice; + baseApi->info.defaultOutputDevice = paNoDevice; + + /* Gather info about hw devices + + * alsa_snd_card_next() modifies the integer passed to it to be: + * the index of the first card if the parameter is -1 + * the index of the next card if the parameter is the index of a card + * -1 if there are no more cards + * + * The function itself returns 0 if it succeeded. */ + cardIdx = -1; + alsa_snd_ctl_card_info_alloca( &cardInfo ); + alsa_snd_pcm_info_alloca( &pcmInfo ); + while( alsa_snd_card_next( &cardIdx ) == 0 && cardIdx >= 0 ) + { + char *cardName; + int devIdx = -1; + snd_ctl_t *ctl; + char buf[50]; + + snprintf( alsaCardName, sizeof (alsaCardName), "hw:%d", cardIdx ); + + /* Acquire name of card */ + if( alsa_snd_ctl_open( &ctl, alsaCardName, 0 ) < 0 ) + { + /* Unable to open card :( */ + PA_DEBUG(( "%s: Unable to open device %s\n", __FUNCTION__, alsaCardName )); + continue; + } + alsa_snd_ctl_card_info( ctl, cardInfo ); + + PA_ENSURE( PaAlsa_StrDup( alsaApi, &cardName, alsa_snd_ctl_card_info_get_name( cardInfo )) ); + + while( alsa_snd_ctl_pcm_next_device( ctl, &devIdx ) == 0 && devIdx >= 0 ) + { + char *alsaDeviceName, *deviceName, *infoName; + size_t len; + int hasPlayback = 0, hasCapture = 0; + + snprintf( buf, sizeof (buf), "%s%s,%d", hwPrefix, alsaCardName, devIdx ); + + /* Obtain info about this particular device */ + alsa_snd_pcm_info_set_device( pcmInfo, devIdx ); + alsa_snd_pcm_info_set_subdevice( pcmInfo, 0 ); + alsa_snd_pcm_info_set_stream( pcmInfo, SND_PCM_STREAM_CAPTURE ); + if( alsa_snd_ctl_pcm_info( ctl, pcmInfo ) >= 0 ) + { + hasCapture = 1; + } + + alsa_snd_pcm_info_set_stream( pcmInfo, SND_PCM_STREAM_PLAYBACK ); + if( alsa_snd_ctl_pcm_info( ctl, pcmInfo ) >= 0 ) + { + hasPlayback = 1; + } + + if( !hasPlayback && !hasCapture ) + { + /* Error */ + continue; + } + + infoName = SkipCardDetailsInName( (char *)alsa_snd_pcm_info_get_name( pcmInfo ), cardName ); + + /* The length of the string written by snprintf plus terminating 0 */ + len = snprintf( NULL, 0, "%s: %s (%s)", cardName, infoName, buf ) + 1; + PA_UNLESS( deviceName = (char *)PaUtil_GroupAllocateMemory( alsaApi->allocations, len ), + paInsufficientMemory ); + snprintf( deviceName, len, "%s: %s (%s)", cardName, infoName, buf ); + + ++numDeviceNames; + if( !hwDevInfos || numDeviceNames > maxDeviceNames ) + { + maxDeviceNames *= 2; + PA_UNLESS( hwDevInfos = (HwDevInfo *) realloc( hwDevInfos, maxDeviceNames * sizeof (HwDevInfo) ), + paInsufficientMemory ); + } + + PA_ENSURE( PaAlsa_StrDup( alsaApi, &alsaDeviceName, buf ) ); + + hwDevInfos[ numDeviceNames - 1 ].alsaName = alsaDeviceName; + hwDevInfos[ numDeviceNames - 1 ].name = deviceName; + hwDevInfos[ numDeviceNames - 1 ].isPlug = usePlughw; + hwDevInfos[ numDeviceNames - 1 ].hasPlayback = hasPlayback; + hwDevInfos[ numDeviceNames - 1 ].hasCapture = hasCapture; + } + alsa_snd_ctl_close( ctl ); + } + + /* Iterate over plugin devices */ + if( NULL == (*alsa_snd_config) ) + { + /* alsa_snd_config_update is called implicitly by some functions, if this hasn't happened snd_config will be NULL (bleh) */ + ENSURE_( alsa_snd_config_update(), paUnanticipatedHostError ); + PA_DEBUG(( "Updating snd_config\n" )); + } + assert( *alsa_snd_config ); + if( ( res = alsa_snd_config_search( *alsa_snd_config, "pcm", &topNode ) ) >= 0 ) + { + snd_config_iterator_t i, next; + + alsa_snd_config_for_each( i, next, topNode ) + { + const char *tpStr = "unknown", *idStr = NULL; + int err = 0; + + char *alsaDeviceName, *deviceName; + const HwDevInfo *predefined = NULL; + snd_config_t *n = alsa_snd_config_iterator_entry( i ), * tp = NULL;; + + if( (err = alsa_snd_config_search( n, "type", &tp )) < 0 ) + { + if( -ENOENT != err ) + { + ENSURE_(err, paUnanticipatedHostError); + } + } + else + { + ENSURE_( alsa_snd_config_get_string( tp, &tpStr ), paUnanticipatedHostError ); + } + ENSURE_( alsa_snd_config_get_id( n, &idStr ), paUnanticipatedHostError ); + if( IgnorePlugin( idStr ) ) + { + PA_DEBUG(( "%s: Ignoring ALSA plugin device [%s] of type [%s]\n", __FUNCTION__, idStr, tpStr )); + continue; + } + PA_DEBUG(( "%s: Found plugin [%s] of type [%s]\n", __FUNCTION__, idStr, tpStr )); + + PA_UNLESS( alsaDeviceName = (char*)PaUtil_GroupAllocateMemory( alsaApi->allocations, + strlen(idStr) + 6 ), paInsufficientMemory ); + strcpy( alsaDeviceName, idStr ); + PA_UNLESS( deviceName = (char*)PaUtil_GroupAllocateMemory( alsaApi->allocations, + strlen(idStr) + 1 ), paInsufficientMemory ); + strcpy( deviceName, idStr ); + + ++numDeviceNames; + if( !hwDevInfos || numDeviceNames > maxDeviceNames ) + { + maxDeviceNames *= 2; + PA_UNLESS( hwDevInfos = (HwDevInfo *) realloc( hwDevInfos, maxDeviceNames * sizeof (HwDevInfo) ), + paInsufficientMemory ); + } + + predefined = FindDeviceName( alsaDeviceName ); + + hwDevInfos[numDeviceNames - 1].alsaName = alsaDeviceName; + hwDevInfos[numDeviceNames - 1].name = deviceName; + hwDevInfos[numDeviceNames - 1].isPlug = 1; + + if( predefined ) + { + hwDevInfos[numDeviceNames - 1].hasPlayback = predefined->hasPlayback; + hwDevInfos[numDeviceNames - 1].hasCapture = predefined->hasCapture; + } + else + { + hwDevInfos[numDeviceNames - 1].hasPlayback = 1; + hwDevInfos[numDeviceNames - 1].hasCapture = 1; + } + } + } + else + PA_DEBUG(( "%s: Iterating over ALSA plugins failed: %s\n", __FUNCTION__, alsa_snd_strerror( res ) )); + + /* allocate deviceInfo memory based on the number of devices */ + PA_UNLESS( baseApi->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory( + alsaApi->allocations, sizeof(PaDeviceInfo*) * (numDeviceNames) ), paInsufficientMemory ); + + /* allocate all device info structs in a contiguous block */ + PA_UNLESS( deviceInfoArray = (PaAlsaDeviceInfo*)PaUtil_GroupAllocateMemory( + alsaApi->allocations, sizeof(PaAlsaDeviceInfo) * numDeviceNames ), paInsufficientMemory ); + + /* Loop over list of cards, filling in info. If a device is deemed unavailable (can't get name), + * it's ignored. + * + * Note that we do this in two stages. This is a workaround owing to the fact that the 'dmix' + * plugin may cause the underlying hardware device to be busy for a short while even after it + * (dmix) is closed. The 'default' plugin may also point to the dmix plugin, so the same goes + * for this. + */ + PA_DEBUG(( "%s: Filling device info for %d devices\n", __FUNCTION__, numDeviceNames )); + for( i = 0, devIdx = 0; i < numDeviceNames; ++i ) + { + PaAlsaDeviceInfo* devInfo = &deviceInfoArray[i]; + HwDevInfo* hwInfo = &hwDevInfos[i]; + if( !strcmp( hwInfo->name, "dmix" ) || !strcmp( hwInfo->name, "default" ) ) + { + continue; + } + + PA_ENSURE( FillInDevInfo( alsaApi, hwInfo, blocking, devInfo, &devIdx ) ); + } + assert( devIdx < numDeviceNames ); + /* Now inspect 'dmix' and 'default' plugins */ + for( i = 0; i < numDeviceNames; ++i ) + { + PaAlsaDeviceInfo* devInfo = &deviceInfoArray[i]; + HwDevInfo* hwInfo = &hwDevInfos[i]; + if( strcmp( hwInfo->name, "dmix" ) && strcmp( hwInfo->name, "default" ) ) + { + continue; + } + + PA_ENSURE( FillInDevInfo( alsaApi, hwInfo, blocking, devInfo, &devIdx ) ); + } + free( hwDevInfos ); + + baseApi->info.deviceCount = devIdx; /* Number of successfully queried devices */ + +#ifdef PA_ENABLE_DEBUG_OUTPUT + PA_DEBUG(( "%s: Building device list took %f seconds\n", __FUNCTION__, PaUtil_GetTime() - startTime )); +#endif + +end: + return result; + +error: + /* No particular action */ + goto end; +} + +/* Check against known device capabilities */ +static PaError ValidateParameters( const PaStreamParameters *parameters, PaUtilHostApiRepresentation *hostApi, StreamDirection mode ) +{ + PaError result = paNoError; + int maxChans; + const PaAlsaDeviceInfo *deviceInfo = NULL; + assert( parameters ); + + if( parameters->device != paUseHostApiSpecificDeviceSpecification ) + { + assert( parameters->device < hostApi->info.deviceCount ); + PA_UNLESS( parameters->hostApiSpecificStreamInfo == NULL, paBadIODeviceCombination ); + deviceInfo = GetDeviceInfo( hostApi, parameters->device ); + } + else + { + const PaAlsaStreamInfo *streamInfo = parameters->hostApiSpecificStreamInfo; + + PA_UNLESS( parameters->device == paUseHostApiSpecificDeviceSpecification, paInvalidDevice ); + PA_UNLESS( streamInfo->size == sizeof (PaAlsaStreamInfo) && streamInfo->version == 1, + paIncompatibleHostApiSpecificStreamInfo ); + PA_UNLESS( streamInfo->deviceString != NULL, paInvalidDevice ); + + /* Skip further checking */ + return paNoError; + } + + assert( deviceInfo ); + assert( parameters->hostApiSpecificStreamInfo == NULL ); + maxChans = ( StreamDirection_In == mode ? deviceInfo->baseDeviceInfo.maxInputChannels : + deviceInfo->baseDeviceInfo.maxOutputChannels ); + PA_UNLESS( parameters->channelCount <= maxChans, paInvalidChannelCount ); + +error: + return result; +} + +/* Given an open stream, what sample formats are available? */ +static PaSampleFormat GetAvailableFormats( snd_pcm_t *pcm ) +{ + PaSampleFormat available = 0; + snd_pcm_hw_params_t *hwParams; + alsa_snd_pcm_hw_params_alloca( &hwParams ); + + alsa_snd_pcm_hw_params_any( pcm, hwParams ); + + if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_FLOAT ) >= 0) + available |= paFloat32; + + if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S32 ) >= 0) + available |= paInt32; + +#ifdef PA_LITTLE_ENDIAN + if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S24_3LE ) >= 0) + available |= paInt24; +#elif defined PA_BIG_ENDIAN + if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S24_3BE ) >= 0) + available |= paInt24; +#endif + + if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S16 ) >= 0) + available |= paInt16; + + if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_U8 ) >= 0) + available |= paUInt8; + + if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S8 ) >= 0) + available |= paInt8; + + return available; +} + +/* Output to console all formats supported by device */ +static void LogAllAvailableFormats( snd_pcm_t *pcm ) +{ + PaSampleFormat available = 0; + snd_pcm_hw_params_t *hwParams; + alsa_snd_pcm_hw_params_alloca( &hwParams ); + + alsa_snd_pcm_hw_params_any( pcm, hwParams ); + + PA_DEBUG(( " --- Supported Formats ---\n" )); + + if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S8 ) >= 0) + PA_DEBUG(( "SND_PCM_FORMAT_S8\n" )); + if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_U8 ) >= 0) + PA_DEBUG(( "SND_PCM_FORMAT_U8\n" )); + + if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S16_LE ) >= 0) + PA_DEBUG(( "SND_PCM_FORMAT_S16_LE\n" )); + if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S16_BE ) >= 0) + PA_DEBUG(( "SND_PCM_FORMAT_S16_BE\n" )); + + if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_U16_LE ) >= 0) + PA_DEBUG(( "SND_PCM_FORMAT_U16_LE\n" )); + if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_U16_BE ) >= 0) + PA_DEBUG(( "SND_PCM_FORMAT_U16_BE\n" )); + + if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S24_LE ) >= 0) + PA_DEBUG(( "SND_PCM_FORMAT_S24_LE\n" )); + if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S24_BE ) >= 0) + PA_DEBUG(( "SND_PCM_FORMAT_S24_BE\n" )); + + if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_U24_LE ) >= 0) + PA_DEBUG(( "SND_PCM_FORMAT_U24_LE\n" )); + if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_U24_BE ) >= 0) + PA_DEBUG(( "SND_PCM_FORMAT_U24_BE\n" )); + + if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_FLOAT_LE ) >= 0) + PA_DEBUG(( "SND_PCM_FORMAT_FLOAT_LE\n" )); + if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_FLOAT_BE ) >= 0) + PA_DEBUG(( "SND_PCM_FORMAT_FLOAT_BE\n" )); + + if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_FLOAT64_LE ) >= 0) + PA_DEBUG(( "SND_PCM_FORMAT_FLOAT64_LE\n" )); + if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_FLOAT64_BE ) >= 0) + PA_DEBUG(( "SND_PCM_FORMAT_FLOAT64_BE\n" )); + + if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_IEC958_SUBFRAME_LE ) >= 0) + PA_DEBUG(( "SND_PCM_FORMAT_IEC958_SUBFRAME_LE\n" )); + if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_IEC958_SUBFRAME_BE ) >= 0) + PA_DEBUG(( "SND_PCM_FORMAT_IEC958_SUBFRAME_BE\n" )); + + if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_MU_LAW ) >= 0) + PA_DEBUG(( "SND_PCM_FORMAT_MU_LAW\n" )); + if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_A_LAW ) >= 0) + PA_DEBUG(( "SND_PCM_FORMAT_A_LAW\n" )); + + if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_IMA_ADPCM ) >= 0) + PA_DEBUG(( "SND_PCM_FORMAT_IMA_ADPCM\n" )); + if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_MPEG ) >= 0) + PA_DEBUG(( "SND_PCM_FORMAT_MPEG\n" )); + + if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_GSM ) >= 0) + PA_DEBUG(( "SND_PCM_FORMAT_GSM\n" )); + if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_SPECIAL ) >= 0) + PA_DEBUG(( "SND_PCM_FORMAT_SPECIAL\n" )); + + if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S24_3LE ) >= 0) + PA_DEBUG(( "SND_PCM_FORMAT_S24_3LE\n" )); + if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S24_3BE ) >= 0) + PA_DEBUG(( "SND_PCM_FORMAT_S24_3BE\n" )); + + if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_U24_3LE ) >= 0) + PA_DEBUG(( "SND_PCM_FORMAT_U24_3LE\n" )); + if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_U24_3BE ) >= 0) + PA_DEBUG(( "SND_PCM_FORMAT_U24_3BE\n" )); + + if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S20_3LE ) >= 0) + PA_DEBUG(( "SND_PCM_FORMAT_S20_3LE\n" )); + if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S20_3BE ) >= 0) + PA_DEBUG(( "SND_PCM_FORMAT_S20_3BE\n" )); + + if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_U20_3LE ) >= 0) + PA_DEBUG(( "SND_PCM_FORMAT_U20_3LE\n" )); + if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_U20_3BE ) >= 0) + PA_DEBUG(( "SND_PCM_FORMAT_U20_3BE\n" )); + + if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S18_3LE ) >= 0) + PA_DEBUG(( "SND_PCM_FORMAT_S18_3LE\n" )); + if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S18_3BE ) >= 0) + PA_DEBUG(( "SND_PCM_FORMAT_S18_3BE\n" )); + + if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_U18_3LE ) >= 0) + PA_DEBUG(( "SND_PCM_FORMAT_U18_3LE\n" )); + if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_U18_3BE ) >= 0) + PA_DEBUG(( "SND_PCM_FORMAT_U18_3BE\n" )); + + if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S16 ) >= 0) + PA_DEBUG(( "SND_PCM_FORMAT_S16\n" )); + if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_U16 ) >= 0) + PA_DEBUG(( "SND_PCM_FORMAT_U16\n" )); + + if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S24 ) >= 0) + PA_DEBUG(( "SND_PCM_FORMAT_S24\n" )); + if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_U24 ) >= 0) + PA_DEBUG(( "SND_PCM_FORMAT_U24\n" )); + + if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S32 ) >= 0) + PA_DEBUG(( "SND_PCM_FORMAT_S32\n" )); + if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_U32 ) >= 0) + PA_DEBUG(( "SND_PCM_FORMAT_U32\n" )); + + if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_FLOAT ) >= 0) + PA_DEBUG(( "SND_PCM_FORMAT_FLOAT\n" )); + if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_FLOAT64 ) >= 0) + PA_DEBUG(( "SND_PCM_FORMAT_FLOAT64\n" )); + + if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_IEC958_SUBFRAME ) >= 0) + PA_DEBUG(( "SND_PCM_FORMAT_IEC958_SUBFRAME\n" )); + + PA_DEBUG(( " -------------------------\n" )); +} + +static snd_pcm_format_t Pa2AlsaFormat( PaSampleFormat paFormat ) +{ + switch( paFormat ) + { + case paFloat32: + return SND_PCM_FORMAT_FLOAT; + + case paInt16: + return SND_PCM_FORMAT_S16; + + case paInt24: +#ifdef PA_LITTLE_ENDIAN + return SND_PCM_FORMAT_S24_3LE; +#elif defined PA_BIG_ENDIAN + return SND_PCM_FORMAT_S24_3BE; +#endif + + case paInt32: + return SND_PCM_FORMAT_S32; + + case paInt8: + return SND_PCM_FORMAT_S8; + + case paUInt8: + return SND_PCM_FORMAT_U8; + + default: + return SND_PCM_FORMAT_UNKNOWN; + } +} + +/** Open an ALSA pcm handle. + * + * The device to be open can be specified by name in a custom PaAlsaStreamInfo struct, or it will be by + * the Portaudio device number supplied in the stream parameters. + */ +static PaError AlsaOpen( const PaUtilHostApiRepresentation *hostApi, const PaStreamParameters *params, StreamDirection + streamDir, snd_pcm_t **pcm ) +{ + PaError result = paNoError; + int ret; + const char* deviceName = ""; + const PaAlsaDeviceInfo *deviceInfo = NULL; + PaAlsaStreamInfo *streamInfo = (PaAlsaStreamInfo *)params->hostApiSpecificStreamInfo; + + if( !streamInfo ) + { + deviceInfo = GetDeviceInfo( hostApi, params->device ); + deviceName = deviceInfo->alsaName; + } + else + deviceName = streamInfo->deviceString; + + PA_DEBUG(( "%s: Opening device %s\n", __FUNCTION__, deviceName )); + if( (ret = OpenPcm( pcm, deviceName, streamDir == StreamDirection_In ? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK, + SND_PCM_NONBLOCK, 1 )) < 0 ) + { + /* Not to be closed */ + *pcm = NULL; + ENSURE_( ret, -EBUSY == ret ? paDeviceUnavailable : paBadIODeviceCombination ); + } + ENSURE_( alsa_snd_pcm_nonblock( *pcm, 0 ), paUnanticipatedHostError ); + +end: + return result; + +error: + goto end; +} + +static PaError TestParameters( const PaUtilHostApiRepresentation *hostApi, const PaStreamParameters *parameters, + double sampleRate, StreamDirection streamDir ) +{ + PaError result = paNoError; + snd_pcm_t *pcm = NULL; + PaSampleFormat availableFormats; + /* We are able to adapt to a number of channels less than what the device supports */ + unsigned int numHostChannels; + PaSampleFormat hostFormat; + snd_pcm_hw_params_t *hwParams; + alsa_snd_pcm_hw_params_alloca( &hwParams ); + + if( !parameters->hostApiSpecificStreamInfo ) + { + const PaAlsaDeviceInfo *devInfo = GetDeviceInfo( hostApi, parameters->device ); + numHostChannels = PA_MAX( parameters->channelCount, StreamDirection_In == streamDir ? + devInfo->minInputChannels : devInfo->minOutputChannels ); + } + else + numHostChannels = parameters->channelCount; + + PA_ENSURE( AlsaOpen( hostApi, parameters, streamDir, &pcm ) ); + + alsa_snd_pcm_hw_params_any( pcm, hwParams ); + + if( SetApproximateSampleRate( pcm, hwParams, sampleRate ) < 0 ) + { + result = paInvalidSampleRate; + goto error; + } + + if( alsa_snd_pcm_hw_params_set_channels( pcm, hwParams, numHostChannels ) < 0 ) + { + result = paInvalidChannelCount; + goto error; + } + + /* See if we can find a best possible match */ + availableFormats = GetAvailableFormats( pcm ); + PA_ENSURE( hostFormat = PaUtil_SelectClosestAvailableFormat( availableFormats, parameters->sampleFormat ) ); + + /* Some specific hardware (reported: Audio8 DJ) can fail with assertion during this step. */ + ENSURE_( alsa_snd_pcm_hw_params_set_format( pcm, hwParams, Pa2AlsaFormat( hostFormat ) ), paUnanticipatedHostError ); + + { + /* It happens that this call fails because the device is busy */ + int ret = 0; + if( ( ret = alsa_snd_pcm_hw_params( pcm, hwParams ) ) < 0 ) + { + if( -EINVAL == ret ) + { + /* Don't know what to return here */ + result = paBadIODeviceCombination; + goto error; + } + else if( -EBUSY == ret ) + { + result = paDeviceUnavailable; + PA_DEBUG(( "%s: Device is busy\n", __FUNCTION__ )); + } + else + { + result = paUnanticipatedHostError; + } + + ENSURE_( ret, result ); + } + } + +end: + if( pcm ) + { + alsa_snd_pcm_close( pcm ); + } + return result; + +error: + goto end; +} + +static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi, + const PaStreamParameters *inputParameters, + const PaStreamParameters *outputParameters, + double sampleRate ) +{ + int inputChannelCount = 0, outputChannelCount = 0; + PaSampleFormat inputSampleFormat, outputSampleFormat; + PaError result = paFormatIsSupported; + + if( inputParameters ) + { + PA_ENSURE( ValidateParameters( inputParameters, hostApi, StreamDirection_In ) ); + + inputChannelCount = inputParameters->channelCount; + inputSampleFormat = inputParameters->sampleFormat; + } + + if( outputParameters ) + { + PA_ENSURE( ValidateParameters( outputParameters, hostApi, StreamDirection_Out ) ); + + outputChannelCount = outputParameters->channelCount; + outputSampleFormat = outputParameters->sampleFormat; + } + + if( inputChannelCount ) + { + if( ( result = TestParameters( hostApi, inputParameters, sampleRate, StreamDirection_In ) ) + != paNoError ) + goto error; + } + if ( outputChannelCount ) + { + if( ( result = TestParameters( hostApi, outputParameters, sampleRate, StreamDirection_Out ) ) + != paNoError ) + goto error; + } + + return paFormatIsSupported; + +error: + return result; +} + + +static PaError PaAlsaStreamComponent_Initialize( PaAlsaStreamComponent *self, PaAlsaHostApiRepresentation *alsaApi, + const PaStreamParameters *params, StreamDirection streamDir, int callbackMode ) +{ + PaError result = paNoError; + PaSampleFormat userSampleFormat = params->sampleFormat, hostSampleFormat = paNoError; + assert( params->channelCount > 0 ); + + /* Make sure things have an initial value */ + memset( self, 0, sizeof (PaAlsaStreamComponent) ); + + if( NULL == params->hostApiSpecificStreamInfo ) + { + const PaAlsaDeviceInfo *devInfo = GetDeviceInfo( &alsaApi->baseHostApiRep, params->device ); + self->numHostChannels = PA_MAX( params->channelCount, StreamDirection_In == streamDir ? devInfo->minInputChannels + : devInfo->minOutputChannels ); + self->deviceIsPlug = devInfo->isPlug; + PA_DEBUG(( "%s: Host Chans %c %i\n", __FUNCTION__, streamDir == StreamDirection_In ? 'C' : 'P', self->numHostChannels )); + } + else + { + /* We're blissfully unaware of the minimum channelCount */ + self->numHostChannels = params->channelCount; + /* Check if device name does not start with hw: to determine if it is a 'plug' device */ + if( strncmp( "hw:", ((PaAlsaStreamInfo *)params->hostApiSpecificStreamInfo)->deviceString, 3 ) != 0 ) + self->deviceIsPlug = 1; /* An Alsa plug device, not a direct hw device */ + } + if( self->deviceIsPlug && alsaApi->alsaLibVersion < ALSA_VERSION_INT( 1, 0, 16 ) ) + self->useReventFix = 1; /* Prior to Alsa1.0.16, plug devices may stutter without this fix */ + + self->device = params->device; + + PA_ENSURE( AlsaOpen( &alsaApi->baseHostApiRep, params, streamDir, &self->pcm ) ); + self->nfds = alsa_snd_pcm_poll_descriptors_count( self->pcm ); + + PA_ENSURE( hostSampleFormat = PaUtil_SelectClosestAvailableFormat( GetAvailableFormats( self->pcm ), userSampleFormat ) ); + + self->hostSampleFormat = hostSampleFormat; + self->nativeFormat = Pa2AlsaFormat( hostSampleFormat ); + self->hostInterleaved = self->userInterleaved = !( userSampleFormat & paNonInterleaved ); + self->numUserChannels = params->channelCount; + self->streamDir = streamDir; + self->canMmap = 0; + self->nonMmapBuffer = NULL; + self->nonMmapBufferSize = 0; + + if( !callbackMode && !self->userInterleaved ) + { + /* Pre-allocate non-interleaved user provided buffers */ + PA_UNLESS( self->userBuffers = PaUtil_AllocateMemory( sizeof (void *) * self->numUserChannels ), + paInsufficientMemory ); + } + +error: + + /* Log all available formats. */ + if ( hostSampleFormat == paSampleFormatNotSupported ) + { + LogAllAvailableFormats( self->pcm ); + PA_DEBUG(( "%s: Please provide the log output to PortAudio developers, your hardware does not have any sample format implemented yet.\n", __FUNCTION__ )); + } + + return result; +} + +static void PaAlsaStreamComponent_Terminate( PaAlsaStreamComponent *self ) +{ + alsa_snd_pcm_close( self->pcm ); + PaUtil_FreeMemory( self->userBuffers ); /* (Ptr can be NULL; PaUtil_FreeMemory includes a NULL check) */ + PaUtil_FreeMemory( self->nonMmapBuffer ); +} + +/* +static int nearbyint_(float value) { + if( value - (int)value > .5 ) + return (int)ceil( value ); + return (int)floor( value ); +} +*/ + +/** Initiate configuration, preparing for determining a period size suitable for both capture and playback components. + * + */ +static PaError PaAlsaStreamComponent_InitialConfigure( PaAlsaStreamComponent *self, const PaStreamParameters *params, + int primeBuffers, snd_pcm_hw_params_t *hwParams, double *sampleRate ) +{ + /* Configuration consists of setting all of ALSA's parameters. + * These parameters come in two flavors: hardware parameters + * and software paramters. Hardware parameters will affect + * the way the device is initialized, software parameters + * affect the way ALSA interacts with me, the user-level client. + */ + + PaError result = paNoError; + snd_pcm_access_t accessMode, alternateAccessMode; + int dir = 0; + snd_pcm_t *pcm = self->pcm; + double sr = *sampleRate; + unsigned int minPeriods = 2; + + /* self->framesPerPeriod = framesPerHostBuffer; */ + + /* ... fill up the configuration space with all possibile + * combinations of parameters this device will accept */ + ENSURE_( alsa_snd_pcm_hw_params_any( pcm, hwParams ), paUnanticipatedHostError ); + + ENSURE_( alsa_snd_pcm_hw_params_set_periods_integer( pcm, hwParams ), paUnanticipatedHostError ); + /* I think there should be at least 2 periods (even though ALSA doesn't appear to enforce this) */ + dir = 0; + ENSURE_( alsa_snd_pcm_hw_params_set_periods_min( pcm, hwParams, &minPeriods, &dir ), paUnanticipatedHostError ); + + if( self->userInterleaved ) + { + accessMode = SND_PCM_ACCESS_MMAP_INTERLEAVED; + alternateAccessMode = SND_PCM_ACCESS_MMAP_NONINTERLEAVED; + + /* test if MMAP supported */ + self->canMmap = alsa_snd_pcm_hw_params_test_access( pcm, hwParams, accessMode ) >= 0 || + alsa_snd_pcm_hw_params_test_access( pcm, hwParams, alternateAccessMode ) >= 0; + + PA_DEBUG(( "%s: device MMAP SND_PCM_ACCESS_MMAP_INTERLEAVED: %s\n", __FUNCTION__, ( alsa_snd_pcm_hw_params_test_access( pcm, hwParams, accessMode ) >= 0 ? "YES" : "NO" ) )); + PA_DEBUG(( "%s: device MMAP SND_PCM_ACCESS_MMAP_NONINTERLEAVED: %s\n", __FUNCTION__, ( alsa_snd_pcm_hw_params_test_access( pcm, hwParams, alternateAccessMode ) >= 0 ? "YES" : "NO" ) )); + + if( !self->canMmap ) + { + accessMode = SND_PCM_ACCESS_RW_INTERLEAVED; + alternateAccessMode = SND_PCM_ACCESS_RW_NONINTERLEAVED; + } + } + else + { + accessMode = SND_PCM_ACCESS_MMAP_NONINTERLEAVED; + alternateAccessMode = SND_PCM_ACCESS_MMAP_INTERLEAVED; + + /* test if MMAP supported */ + self->canMmap = alsa_snd_pcm_hw_params_test_access( pcm, hwParams, accessMode ) >= 0 || + alsa_snd_pcm_hw_params_test_access( pcm, hwParams, alternateAccessMode ) >= 0; + + PA_DEBUG((" %s: device MMAP SND_PCM_ACCESS_MMAP_NONINTERLEAVED: %s\n", __FUNCTION__, ( alsa_snd_pcm_hw_params_test_access( pcm, hwParams, accessMode ) >= 0 ? "YES" : "NO" ) )); + PA_DEBUG(( "%s: device MMAP SND_PCM_ACCESS_MMAP_INTERLEAVED: %s\n", __FUNCTION__, ( alsa_snd_pcm_hw_params_test_access( pcm, hwParams, alternateAccessMode ) >= 0 ? "YES" : "NO" ) )); + + if( !self->canMmap ) + { + accessMode = SND_PCM_ACCESS_RW_NONINTERLEAVED; + alternateAccessMode = SND_PCM_ACCESS_RW_INTERLEAVED; + } + } + + PA_DEBUG(( "%s: device can MMAP: %s\n", __FUNCTION__, ( self->canMmap ? "YES" : "NO" ) )); + + /* If requested access mode fails, try alternate mode */ + if( alsa_snd_pcm_hw_params_set_access( pcm, hwParams, accessMode ) < 0 ) + { + int err = 0; + if( ( err = alsa_snd_pcm_hw_params_set_access( pcm, hwParams, alternateAccessMode )) < 0 ) + { + result = paUnanticipatedHostError; + PaUtil_SetLastHostErrorInfo( paALSA, err, alsa_snd_strerror( err ) ); + goto error; + } + /* Flip mode */ + self->hostInterleaved = !self->userInterleaved; + } + + /* Some specific hardware (reported: Audio8 DJ) can fail with assertion during this step. */ + ENSURE_( alsa_snd_pcm_hw_params_set_format( pcm, hwParams, self->nativeFormat ), paUnanticipatedHostError ); + + if( ( result = SetApproximateSampleRate( pcm, hwParams, sr )) != paUnanticipatedHostError ) + { + ENSURE_( GetExactSampleRate( hwParams, &sr ), paUnanticipatedHostError ); + if( result == paInvalidSampleRate ) /* From the SetApproximateSampleRate() call above */ + { /* The sample rate was returned as 'out of tolerance' of the one requested */ + PA_DEBUG(( "%s: Wanted %.3f, closest sample rate was %.3f\n", __FUNCTION__, sampleRate, sr )); + PA_ENSURE( paInvalidSampleRate ); + } + } + else + { + PA_ENSURE( paUnanticipatedHostError ); + } + + ENSURE_( alsa_snd_pcm_hw_params_set_channels( pcm, hwParams, self->numHostChannels ), paInvalidChannelCount ); + + *sampleRate = sr; + +end: + return result; + +error: + /* No particular action */ + goto end; +} + +/** Finish the configuration of the component's ALSA device. + * + * As part of this method, the component's alsaBufferSize attribute will be set. + * @param latency: The latency for this component. + */ +static PaError PaAlsaStreamComponent_FinishConfigure( PaAlsaStreamComponent *self, snd_pcm_hw_params_t* hwParams, + const PaStreamParameters *params, int primeBuffers, double sampleRate, PaTime* latency ) +{ + PaError result = paNoError; + snd_pcm_sw_params_t* swParams; + snd_pcm_uframes_t bufSz = 0; + *latency = -1.; + + alsa_snd_pcm_sw_params_alloca( &swParams ); + + bufSz = params->suggestedLatency * sampleRate + self->framesPerPeriod; + ENSURE_( alsa_snd_pcm_hw_params_set_buffer_size_near( self->pcm, hwParams, &bufSz ), paUnanticipatedHostError ); + + /* Set the parameters! */ + { + int r = alsa_snd_pcm_hw_params( self->pcm, hwParams ); +#ifdef PA_ENABLE_DEBUG_OUTPUT + if( r < 0 ) + { + snd_output_t *output = NULL; + alsa_snd_output_stdio_attach( &output, stderr, 0 ); + alsa_snd_pcm_hw_params_dump( hwParams, output ); + } +#endif + ENSURE_( r, paUnanticipatedHostError ); + } + if( alsa_snd_pcm_hw_params_get_buffer_size != NULL ) + { + ENSURE_( alsa_snd_pcm_hw_params_get_buffer_size( hwParams, &self->alsaBufferSize ), paUnanticipatedHostError ); + } + else + { + self->alsaBufferSize = bufSz; + } + + /* Latency in seconds */ + *latency = (self->alsaBufferSize - self->framesPerPeriod) / sampleRate; + + /* Now software parameters... */ + ENSURE_( alsa_snd_pcm_sw_params_current( self->pcm, swParams ), paUnanticipatedHostError ); + + ENSURE_( alsa_snd_pcm_sw_params_set_start_threshold( self->pcm, swParams, self->framesPerPeriod ), paUnanticipatedHostError ); + ENSURE_( alsa_snd_pcm_sw_params_set_stop_threshold( self->pcm, swParams, self->alsaBufferSize ), paUnanticipatedHostError ); + + /* Silence buffer in the case of underrun */ + if( !primeBuffers ) /* XXX: Make sense? */ + { + snd_pcm_uframes_t boundary; + ENSURE_( alsa_snd_pcm_sw_params_get_boundary( swParams, &boundary ), paUnanticipatedHostError ); + ENSURE_( alsa_snd_pcm_sw_params_set_silence_threshold( self->pcm, swParams, 0 ), paUnanticipatedHostError ); + ENSURE_( alsa_snd_pcm_sw_params_set_silence_size( self->pcm, swParams, boundary ), paUnanticipatedHostError ); + } + + ENSURE_( alsa_snd_pcm_sw_params_set_avail_min( self->pcm, swParams, self->framesPerPeriod ), paUnanticipatedHostError ); + ENSURE_( alsa_snd_pcm_sw_params_set_xfer_align( self->pcm, swParams, 1 ), paUnanticipatedHostError ); + ENSURE_( alsa_snd_pcm_sw_params_set_tstamp_mode( self->pcm, swParams, SND_PCM_TSTAMP_ENABLE ), paUnanticipatedHostError ); + + /* Set the parameters! */ + ENSURE_( alsa_snd_pcm_sw_params( self->pcm, swParams ), paUnanticipatedHostError ); + +error: + return result; +} + +static PaError PaAlsaStream_Initialize( PaAlsaStream *self, PaAlsaHostApiRepresentation *alsaApi, const PaStreamParameters *inParams, + const PaStreamParameters *outParams, double sampleRate, unsigned long framesPerUserBuffer, PaStreamCallback callback, + PaStreamFlags streamFlags, void *userData ) +{ + PaError result = paNoError; + assert( self ); + + memset( self, 0, sizeof( PaAlsaStream ) ); + + if( NULL != callback ) + { + PaUtil_InitializeStreamRepresentation( &self->streamRepresentation, + &alsaApi->callbackStreamInterface, + callback, userData ); + self->callbackMode = 1; + } + else + { + PaUtil_InitializeStreamRepresentation( &self->streamRepresentation, + &alsaApi->blockingStreamInterface, + NULL, userData ); + } + + self->framesPerUserBuffer = framesPerUserBuffer; + self->neverDropInput = streamFlags & paNeverDropInput; + /* XXX: Ignore paPrimeOutputBuffersUsingStreamCallback untill buffer priming is fully supported in pa_process.c */ + /* + if( outParams & streamFlags & paPrimeOutputBuffersUsingStreamCallback ) + self->primeBuffers = 1; + */ + memset( &self->capture, 0, sizeof (PaAlsaStreamComponent) ); + memset( &self->playback, 0, sizeof (PaAlsaStreamComponent) ); + if( inParams ) + { + PA_ENSURE( PaAlsaStreamComponent_Initialize( &self->capture, alsaApi, inParams, StreamDirection_In, NULL != callback ) ); + } + if( outParams ) + { + PA_ENSURE( PaAlsaStreamComponent_Initialize( &self->playback, alsaApi, outParams, StreamDirection_Out, NULL != callback ) ); + } + + assert( self->capture.nfds || self->playback.nfds ); + + PA_UNLESS( self->pfds = (struct pollfd*)PaUtil_AllocateMemory( ( self->capture.nfds + + self->playback.nfds ) * sizeof( struct pollfd ) ), paInsufficientMemory ); + + PaUtil_InitializeCpuLoadMeasurer( &self->cpuLoadMeasurer, sampleRate ); + ASSERT_CALL_( PaUnixMutex_Initialize( &self->stateMtx ), paNoError ); + +error: + return result; +} + +/** Free resources associated with stream, and eventually stream itself. + * + * Frees allocated memory, and terminates individual StreamComponents. + */ +static void PaAlsaStream_Terminate( PaAlsaStream *self ) +{ + assert( self ); + + if( self->capture.pcm ) + { + PaAlsaStreamComponent_Terminate( &self->capture ); + } + if( self->playback.pcm ) + { + PaAlsaStreamComponent_Terminate( &self->playback ); + } + + PaUtil_FreeMemory( self->pfds ); + ASSERT_CALL_( PaUnixMutex_Terminate( &self->stateMtx ), paNoError ); + + PaUtil_FreeMemory( self ); +} + +/** Calculate polling timeout + * + * @param frames Time to wait + * @return Polling timeout in milliseconds + */ +static int CalculatePollTimeout( const PaAlsaStream *stream, unsigned long frames ) +{ + assert( stream->streamRepresentation.streamInfo.sampleRate > 0.0 ); + /* Period in msecs, rounded up */ + return (int)ceil( 1000 * frames / stream->streamRepresentation.streamInfo.sampleRate ); +} + +/** Align value in backward direction. + * + * @param v: Value to align. + * @param align: Alignment. + */ +static unsigned long PaAlsa_AlignBackward(unsigned long v, unsigned long align) +{ + return ( v - ( align ? v % align : 0 ) ); +} + +/** Align value in forward direction. + * + * @param v: Value to align. + * @param align: Alignment. + */ +static unsigned long PaAlsa_AlignForward(unsigned long v, unsigned long align) +{ + unsigned long remainder = ( align ? ( v % align ) : 0); + return ( remainder != 0 ? v + ( align - remainder ) : v ); +} + +/** Get size of host buffer maintained from the number of user frames, sample rate and suggested latency. Minimum double buffering + * is maintained to allow 100% CPU usage inside user callback. + * + * @param userFramesPerBuffer: User buffer size in number of frames. + * @param suggestedLatency: User provided desired latency. + * @param sampleRate: Sample rate. + */ +static unsigned long PaAlsa_GetFramesPerHostBuffer(unsigned long userFramesPerBuffer, PaTime suggestedLatency, double sampleRate) +{ + unsigned long frames = userFramesPerBuffer + PA_MAX( userFramesPerBuffer, (unsigned long)( suggestedLatency * sampleRate ) ); + return frames; +} + +/** Determine size per host buffer. + * + * During this method call, the component's framesPerPeriod attribute gets computed, and the corresponding period size + * gets configured for the device. + * @param accurate: If the configured period size is non-integer, this will be set to 0. + */ +static PaError PaAlsaStreamComponent_DetermineFramesPerBuffer( PaAlsaStreamComponent* self, const PaStreamParameters* params, + unsigned long framesPerUserBuffer, double sampleRate, snd_pcm_hw_params_t* hwParams, int* accurate ) +{ + PaError result = paNoError; + unsigned long bufferSize, framesPerHostBuffer; + int dir = 0; + + /* Calculate host buffer size */ + bufferSize = PaAlsa_GetFramesPerHostBuffer(framesPerUserBuffer, params->suggestedLatency, sampleRate); + + /* Log */ + PA_DEBUG(( "%s: user-buffer (frames) = %lu\n", __FUNCTION__, framesPerUserBuffer )); + PA_DEBUG(( "%s: user-buffer (sec) = %f\n", __FUNCTION__, (double)(framesPerUserBuffer / sampleRate) )); + PA_DEBUG(( "%s: suggested latency (sec) = %f\n", __FUNCTION__, params->suggestedLatency )); + PA_DEBUG(( "%s: suggested host buffer (frames) = %lu\n", __FUNCTION__, bufferSize )); + PA_DEBUG(( "%s: suggested host buffer (sec) = %f\n", __FUNCTION__, (double)(bufferSize / sampleRate) )); + +#ifdef PA_ALSA_USE_OBSOLETE_HOST_BUFFER_CALC + + if( framesPerUserBuffer != paFramesPerBufferUnspecified ) + { + /* Preferably the host buffer size should be a multiple of the user buffer size */ + + if( bufferSize > framesPerUserBuffer ) + { + snd_pcm_uframes_t remainder = bufferSize % framesPerUserBuffer; + if( remainder > framesPerUserBuffer / 2. ) + bufferSize += framesPerUserBuffer - remainder; + else + bufferSize -= remainder; + + assert( bufferSize % framesPerUserBuffer == 0 ); + } + else if( framesPerUserBuffer % bufferSize != 0 ) + { + /* Find a good compromise between user specified latency and buffer size */ + if( bufferSize > framesPerUserBuffer * .75 ) + { + bufferSize = framesPerUserBuffer; + } + else + { + snd_pcm_uframes_t newSz = framesPerUserBuffer; + while( newSz / 2 >= bufferSize ) + { + if( framesPerUserBuffer % (newSz / 2) != 0 ) + { + /* No use dividing any further */ + break; + } + newSz /= 2; + } + bufferSize = newSz; + } + + assert( framesPerUserBuffer % bufferSize == 0 ); + } + } + +#endif + + { + unsigned numPeriods = numPeriods_, maxPeriods = 0, minPeriods = numPeriods_; + + /* It may be that the device only supports 2 periods for instance */ + dir = 0; + ENSURE_( alsa_snd_pcm_hw_params_get_periods_min( hwParams, &minPeriods, &dir ), paUnanticipatedHostError ); + ENSURE_( alsa_snd_pcm_hw_params_get_periods_max( hwParams, &maxPeriods, &dir ), paUnanticipatedHostError ); + assert( maxPeriods > 1 ); + + /* Clamp to min/max */ + numPeriods = PA_MIN(maxPeriods, PA_MAX(minPeriods, numPeriods)); + + PA_DEBUG(( "%s: periods min = %lu, max = %lu, req = %lu \n", __FUNCTION__, minPeriods, maxPeriods, numPeriods )); + +#ifndef PA_ALSA_USE_OBSOLETE_HOST_BUFFER_CALC + + /* Calculate period size */ + framesPerHostBuffer = (bufferSize / numPeriods); + + /* Align & test size */ + if( framesPerUserBuffer != paFramesPerBufferUnspecified ) + { + /* Align to user buffer size */ + framesPerHostBuffer = PaAlsa_AlignForward(framesPerHostBuffer, framesPerUserBuffer); + + /* Test (borrowed from older implementation) */ + if( framesPerHostBuffer < framesPerUserBuffer ) + { + assert( framesPerUserBuffer % framesPerHostBuffer == 0 ); + if( alsa_snd_pcm_hw_params_test_period_size( self->pcm, hwParams, framesPerHostBuffer, 0 ) < 0 ) + { + if( alsa_snd_pcm_hw_params_test_period_size( self->pcm, hwParams, framesPerHostBuffer * 2, 0 ) == 0 ) + framesPerHostBuffer *= 2; + else if( alsa_snd_pcm_hw_params_test_period_size( self->pcm, hwParams, framesPerHostBuffer / 2, 0 ) == 0 ) + framesPerHostBuffer /= 2; + } + } + else + { + assert( framesPerHostBuffer % framesPerUserBuffer == 0 ); + if( alsa_snd_pcm_hw_params_test_period_size( self->pcm, hwParams, framesPerHostBuffer, 0 ) < 0 ) + { + if( alsa_snd_pcm_hw_params_test_period_size( self->pcm, hwParams, framesPerHostBuffer + framesPerUserBuffer, 0 ) == 0 ) + framesPerHostBuffer += framesPerUserBuffer; + else if( alsa_snd_pcm_hw_params_test_period_size( self->pcm, hwParams, framesPerHostBuffer - framesPerUserBuffer, 0 ) == 0 ) + framesPerHostBuffer -= framesPerUserBuffer; + } + } + } +#endif + +#ifdef PA_ALSA_USE_OBSOLETE_HOST_BUFFER_CALC + + if( framesPerUserBuffer != paFramesPerBufferUnspecified ) + { + /* Try to get a power-of-two of the user buffer size. */ + framesPerHostBuffer = framesPerUserBuffer; + if( framesPerHostBuffer < bufferSize ) + { + while( bufferSize / framesPerHostBuffer > numPeriods ) + { + framesPerHostBuffer *= 2; + } + /* One extra period is preferrable to one less (should be more robust) */ + if( bufferSize / framesPerHostBuffer < numPeriods ) + { + framesPerHostBuffer /= 2; + } + } + else + { + while( bufferSize / framesPerHostBuffer < numPeriods ) + { + if( framesPerUserBuffer % ( framesPerHostBuffer / 2 ) != 0 ) + { + /* Can't be divided any further */ + break; + } + framesPerHostBuffer /= 2; + } + } + + if( framesPerHostBuffer < framesPerUserBuffer ) + { + assert( framesPerUserBuffer % framesPerHostBuffer == 0 ); + if( alsa_snd_pcm_hw_params_test_period_size( self->pcm, hwParams, framesPerHostBuffer, 0 ) < 0 ) + { + if( alsa_snd_pcm_hw_params_test_period_size( self->pcm, hwParams, framesPerHostBuffer * 2, 0 ) == 0 ) + framesPerHostBuffer *= 2; + else if( alsa_snd_pcm_hw_params_test_period_size( self->pcm, hwParams, framesPerHostBuffer / 2, 0 ) == 0 ) + framesPerHostBuffer /= 2; + } + } + else + { + assert( framesPerHostBuffer % framesPerUserBuffer == 0 ); + if( alsa_snd_pcm_hw_params_test_period_size( self->pcm, hwParams, framesPerHostBuffer, 0 ) < 0 ) + { + if( alsa_snd_pcm_hw_params_test_period_size( self->pcm, hwParams, framesPerHostBuffer + framesPerUserBuffer, 0 ) == 0 ) + framesPerHostBuffer += framesPerUserBuffer; + else if( alsa_snd_pcm_hw_params_test_period_size( self->pcm, hwParams, framesPerHostBuffer - framesPerUserBuffer, 0 ) == 0 ) + framesPerHostBuffer -= framesPerUserBuffer; + } + } + } + else + { + framesPerHostBuffer = bufferSize / numPeriods; + } + + /* non-mmap mode needs a reasonably-sized buffer or it'll stutter */ + if( !self->canMmap && framesPerHostBuffer < 2048 ) + framesPerHostBuffer = 2048; +#endif + PA_DEBUG(( "%s: suggested host buffer period = %lu \n", __FUNCTION__, framesPerHostBuffer )); + } + + { + /* Get min/max period sizes and adjust our chosen */ + snd_pcm_uframes_t min = 0, max = 0, minmax_diff; + ENSURE_( alsa_snd_pcm_hw_params_get_period_size_min( hwParams, &min, NULL ), paUnanticipatedHostError ); + ENSURE_( alsa_snd_pcm_hw_params_get_period_size_max( hwParams, &max, NULL ), paUnanticipatedHostError ); + minmax_diff = max - min; + + if( framesPerHostBuffer < min ) + { + PA_DEBUG(( "%s: The determined period size (%lu) is less than minimum (%lu)\n", __FUNCTION__, framesPerHostBuffer, min )); + framesPerHostBuffer = (( minmax_diff == 2 ) ? min + 1 : min ); + } + else if( framesPerHostBuffer > max ) + { + PA_DEBUG(( "%s: The determined period size (%lu) is greater than maximum (%lu)\n", __FUNCTION__, framesPerHostBuffer, max )); + framesPerHostBuffer = (( minmax_diff == 2 ) ? max - 1 : max ); + } + + PA_DEBUG(( "%s: device period minimum = %lu\n", __FUNCTION__, min )); + PA_DEBUG(( "%s: device period maximum = %lu\n", __FUNCTION__, max )); + PA_DEBUG(( "%s: host buffer period = %lu\n", __FUNCTION__, framesPerHostBuffer )); + PA_DEBUG(( "%s: host buffer period latency = %f\n", __FUNCTION__, (double)( framesPerHostBuffer / sampleRate ) )); + + /* Try setting period size */ + dir = 0; + ENSURE_( alsa_snd_pcm_hw_params_set_period_size_near( self->pcm, hwParams, &framesPerHostBuffer, &dir ), paUnanticipatedHostError ); + if( dir != 0 ) + { + PA_DEBUG(( "%s: The configured period size is non-integer.\n", __FUNCTION__, dir )); + *accurate = 0; + } + } + + /* Set result */ + self->framesPerPeriod = framesPerHostBuffer; + +error: + return result; +} + +/* We need to determine how many frames per host buffer (period) to use. Our + * goals are to provide the best possible performance, but also to + * honor the requested latency settings as closely as we can. Therefore this + * decision is based on: + * + * - the period sizes that playback and/or capture support. The + * host buffer size has to be one of these. + * - the number of periods that playback and/or capture support. + * + * We want to make period_size*(num_periods-1) to be as close as possible + * to latency*rate for both playback and capture. + * + * This method will determine suitable period sizes for capture and playback handles, and report the maximum number of + * frames per host buffer. The latter is relevant, in case we should be so unfortunate that the period size differs + * between capture and playback. If this should happen, the stream's hostBufferSizeMode attribute will be set to + * paUtilBoundedHostBufferSize, because the best we can do is limit the size of individual host buffers to the upper + * bound. The size of host buffers scheduled for processing should only matter if the user has specified a buffer size, + * but when he/she does we must strive for an optimal configuration. By default we'll opt for a fixed host buffer size, + * which should be fine if the period size is the same for capture and playback. In general, if there is a specified user + * buffer size, this method tries it best to determine a period size which is a multiple of the user buffer size. + * + * The framesPerPeriod attributes of the individual capture and playback components of the stream are set to corresponding + * values determined here. Since these should be reported as + * + * This is one of those blocks of code that will just take a lot of + * refinement to be any good. + * + * In the full-duplex case it is possible that the routine was unable + * to find a number of frames per buffer acceptable to both devices + * TODO: Implement an algorithm to find the value closest to acceptance + * by both devices, to minimize difference between period sizes? + * + * @param determinedFramesPerHostBuffer: The determined host buffer size. + */ +static PaError PaAlsaStream_DetermineFramesPerBuffer( PaAlsaStream* self, double sampleRate, const PaStreamParameters* inputParameters, + const PaStreamParameters* outputParameters, unsigned long framesPerUserBuffer, snd_pcm_hw_params_t* hwParamsCapture, + snd_pcm_hw_params_t* hwParamsPlayback, PaUtilHostBufferSizeMode* hostBufferSizeMode ) +{ + PaError result = paNoError; + unsigned long framesPerHostBuffer = 0; + int dir = 0; + int accurate = 1; + unsigned numPeriods = numPeriods_; + + if( self->capture.pcm && self->playback.pcm ) + { + if( framesPerUserBuffer == paFramesPerBufferUnspecified ) + { + /* Come up with a common desired latency */ + snd_pcm_uframes_t desiredBufSz, e, minPeriodSize, maxPeriodSize, optimalPeriodSize, periodSize, + minCapture, minPlayback, maxCapture, maxPlayback; + + dir = 0; + ENSURE_( alsa_snd_pcm_hw_params_get_period_size_min( hwParamsCapture, &minCapture, &dir ), paUnanticipatedHostError ); + dir = 0; + ENSURE_( alsa_snd_pcm_hw_params_get_period_size_min( hwParamsPlayback, &minPlayback, &dir ), paUnanticipatedHostError ); + dir = 0; + ENSURE_( alsa_snd_pcm_hw_params_get_period_size_max( hwParamsCapture, &maxCapture, &dir ), paUnanticipatedHostError ); + dir = 0; + ENSURE_( alsa_snd_pcm_hw_params_get_period_size_max( hwParamsPlayback, &maxPlayback, &dir ), paUnanticipatedHostError ); + minPeriodSize = PA_MAX( minPlayback, minCapture ); + maxPeriodSize = PA_MIN( maxPlayback, maxCapture ); + PA_UNLESS( minPeriodSize <= maxPeriodSize, paBadIODeviceCombination ); + + desiredBufSz = (snd_pcm_uframes_t)( PA_MIN( outputParameters->suggestedLatency, inputParameters->suggestedLatency ) + * sampleRate ); + /* Clamp desiredBufSz */ + { + snd_pcm_uframes_t maxBufferSize; + snd_pcm_uframes_t maxBufferSizeCapture, maxBufferSizePlayback; + ENSURE_( alsa_snd_pcm_hw_params_get_buffer_size_max( hwParamsCapture, &maxBufferSizeCapture ), paUnanticipatedHostError ); + ENSURE_( alsa_snd_pcm_hw_params_get_buffer_size_max( hwParamsPlayback, &maxBufferSizePlayback ), paUnanticipatedHostError ); + maxBufferSize = PA_MIN( maxBufferSizeCapture, maxBufferSizePlayback ); + + desiredBufSz = PA_MIN( desiredBufSz, maxBufferSize ); + } + + /* Find the closest power of 2 */ + e = ilogb( minPeriodSize ); + if( minPeriodSize & ( minPeriodSize - 1 ) ) + e += 1; + periodSize = (snd_pcm_uframes_t)pow( 2, e ); + + while( periodSize <= maxPeriodSize ) + { + if( alsa_snd_pcm_hw_params_test_period_size( self->playback.pcm, hwParamsPlayback, periodSize, 0 ) >= 0 && + alsa_snd_pcm_hw_params_test_period_size( self->capture.pcm, hwParamsCapture, periodSize, 0 ) >= 0 ) + { + /* OK! */ + break; + } + + periodSize *= 2; + } + + optimalPeriodSize = PA_MAX( desiredBufSz / numPeriods, minPeriodSize ); + optimalPeriodSize = PA_MIN( optimalPeriodSize, maxPeriodSize ); + + /* Find the closest power of 2 */ + e = ilogb( optimalPeriodSize ); + if( optimalPeriodSize & (optimalPeriodSize - 1) ) + e += 1; + optimalPeriodSize = (snd_pcm_uframes_t)pow( 2, e ); + + while( optimalPeriodSize >= periodSize ) + { + if( alsa_snd_pcm_hw_params_test_period_size( self->capture.pcm, hwParamsCapture, optimalPeriodSize, 0 ) + >= 0 && alsa_snd_pcm_hw_params_test_period_size( self->playback.pcm, hwParamsPlayback, + optimalPeriodSize, 0 ) >= 0 ) + { + break; + } + optimalPeriodSize /= 2; + } + + if( optimalPeriodSize > periodSize ) + periodSize = optimalPeriodSize; + + if( periodSize <= maxPeriodSize ) + { + /* Looks good, the periodSize _should_ be acceptable by both devices */ + ENSURE_( alsa_snd_pcm_hw_params_set_period_size( self->capture.pcm, hwParamsCapture, periodSize, 0 ), + paUnanticipatedHostError ); + ENSURE_( alsa_snd_pcm_hw_params_set_period_size( self->playback.pcm, hwParamsPlayback, periodSize, 0 ), + paUnanticipatedHostError ); + self->capture.framesPerPeriod = self->playback.framesPerPeriod = periodSize; + framesPerHostBuffer = periodSize; + } + else + { + /* Unable to find a common period size, oh well */ + optimalPeriodSize = PA_MAX( desiredBufSz / numPeriods, minPeriodSize ); + optimalPeriodSize = PA_MIN( optimalPeriodSize, maxPeriodSize ); + + self->capture.framesPerPeriod = optimalPeriodSize; + dir = 0; + ENSURE_( alsa_snd_pcm_hw_params_set_period_size_near( self->capture.pcm, hwParamsCapture, &self->capture.framesPerPeriod, &dir ), + paUnanticipatedHostError ); + self->playback.framesPerPeriod = optimalPeriodSize; + dir = 0; + ENSURE_( alsa_snd_pcm_hw_params_set_period_size_near( self->playback.pcm, hwParamsPlayback, &self->playback.framesPerPeriod, &dir ), + paUnanticipatedHostError ); + framesPerHostBuffer = PA_MAX( self->capture.framesPerPeriod, self->playback.framesPerPeriod ); + *hostBufferSizeMode = paUtilBoundedHostBufferSize; + } + } + else + { + /* We choose the simple route and determine a suitable number of frames per buffer for one component of + * the stream, then we hope that this will work for the other component too (it should!). + */ + + unsigned maxPeriods = 0; + PaAlsaStreamComponent* first = &self->capture, * second = &self->playback; + const PaStreamParameters* firstStreamParams = inputParameters; + snd_pcm_hw_params_t* firstHwParams = hwParamsCapture, * secondHwParams = hwParamsPlayback; + + dir = 0; + ENSURE_( alsa_snd_pcm_hw_params_get_periods_max( hwParamsPlayback, &maxPeriods, &dir ), paUnanticipatedHostError ); + if( maxPeriods < numPeriods ) + { + /* The playback component is trickier to get right, try that first */ + first = &self->playback; + second = &self->capture; + firstStreamParams = outputParameters; + firstHwParams = hwParamsPlayback; + secondHwParams = hwParamsCapture; + } + + PA_ENSURE( PaAlsaStreamComponent_DetermineFramesPerBuffer( first, firstStreamParams, framesPerUserBuffer, + sampleRate, firstHwParams, &accurate ) ); + + second->framesPerPeriod = first->framesPerPeriod; + dir = 0; + ENSURE_( alsa_snd_pcm_hw_params_set_period_size_near( second->pcm, secondHwParams, &second->framesPerPeriod, &dir ), + paUnanticipatedHostError ); + if( self->capture.framesPerPeriod == self->playback.framesPerPeriod ) + { + framesPerHostBuffer = self->capture.framesPerPeriod; + } + else + { + framesPerHostBuffer = PA_MAX( self->capture.framesPerPeriod, self->playback.framesPerPeriod ); + *hostBufferSizeMode = paUtilBoundedHostBufferSize; + } + } + } + else /* half-duplex is a slightly simpler case */ + { + if( self->capture.pcm ) + { + PA_ENSURE( PaAlsaStreamComponent_DetermineFramesPerBuffer( &self->capture, inputParameters, framesPerUserBuffer, + sampleRate, hwParamsCapture, &accurate) ); + framesPerHostBuffer = self->capture.framesPerPeriod; + } + else + { + assert( self->playback.pcm ); + PA_ENSURE( PaAlsaStreamComponent_DetermineFramesPerBuffer( &self->playback, outputParameters, framesPerUserBuffer, + sampleRate, hwParamsPlayback, &accurate ) ); + framesPerHostBuffer = self->playback.framesPerPeriod; + } + } + + PA_UNLESS( framesPerHostBuffer != 0, paInternalError ); + self->maxFramesPerHostBuffer = framesPerHostBuffer; + + if( !self->playback.canMmap || !accurate ) + { + /* Don't know the exact size per host buffer */ + *hostBufferSizeMode = paUtilBoundedHostBufferSize; + /* Raise upper bound */ + if( !accurate ) + ++self->maxFramesPerHostBuffer; + } + +error: + return result; +} + +/** Set up ALSA stream parameters. + * + */ +static PaError PaAlsaStream_Configure( PaAlsaStream *self, const PaStreamParameters *inParams, const PaStreamParameters* + outParams, double sampleRate, unsigned long framesPerUserBuffer, double* inputLatency, double* outputLatency, + PaUtilHostBufferSizeMode* hostBufferSizeMode ) +{ + PaError result = paNoError; + double realSr = sampleRate; + snd_pcm_hw_params_t* hwParamsCapture, * hwParamsPlayback; + + alsa_snd_pcm_hw_params_alloca( &hwParamsCapture ); + alsa_snd_pcm_hw_params_alloca( &hwParamsPlayback ); + + if( self->capture.pcm ) + PA_ENSURE( PaAlsaStreamComponent_InitialConfigure( &self->capture, inParams, self->primeBuffers, hwParamsCapture, + &realSr ) ); + if( self->playback.pcm ) + PA_ENSURE( PaAlsaStreamComponent_InitialConfigure( &self->playback, outParams, self->primeBuffers, hwParamsPlayback, + &realSr ) ); + + PA_ENSURE( PaAlsaStream_DetermineFramesPerBuffer( self, realSr, inParams, outParams, framesPerUserBuffer, + hwParamsCapture, hwParamsPlayback, hostBufferSizeMode ) ); + + if( self->capture.pcm ) + { + assert( self->capture.framesPerPeriod != 0 ); + PA_ENSURE( PaAlsaStreamComponent_FinishConfigure( &self->capture, hwParamsCapture, inParams, self->primeBuffers, realSr, + inputLatency ) ); + PA_DEBUG(( "%s: Capture period size: %lu, latency: %f\n", __FUNCTION__, self->capture.framesPerPeriod, *inputLatency )); + } + if( self->playback.pcm ) + { + assert( self->playback.framesPerPeriod != 0 ); + PA_ENSURE( PaAlsaStreamComponent_FinishConfigure( &self->playback, hwParamsPlayback, outParams, self->primeBuffers, realSr, + outputLatency ) ); + PA_DEBUG(( "%s: Playback period size: %lu, latency: %f\n", __FUNCTION__, self->playback.framesPerPeriod, *outputLatency )); + } + + /* Should be exact now */ + self->streamRepresentation.streamInfo.sampleRate = realSr; + + /* this will cause the two streams to automatically start/stop/prepare in sync. + * We only need to execute these operations on one of the pair. + * A: We don't want to do this on a blocking stream. + */ + if( self->callbackMode && self->capture.pcm && self->playback.pcm ) + { + int err = alsa_snd_pcm_link( self->capture.pcm, self->playback.pcm ); + if( err == 0 ) + self->pcmsSynced = 1; + else + PA_DEBUG(( "%s: Unable to sync pcms: %s\n", __FUNCTION__, alsa_snd_strerror( err ) )); + } + + { + unsigned long minFramesPerHostBuffer = PA_MIN( self->capture.pcm ? self->capture.framesPerPeriod : ULONG_MAX, + self->playback.pcm ? self->playback.framesPerPeriod : ULONG_MAX ); + self->pollTimeout = CalculatePollTimeout( self, minFramesPerHostBuffer ); /* Period in msecs, rounded up */ + + /* Time before watchdog unthrottles realtime thread == 1/4 of period time in msecs */ + /* self->threading.throttledSleepTime = (unsigned long) (minFramesPerHostBuffer / sampleRate / 4 * 1000); */ + } + + if( self->callbackMode ) + { + /* If the user expects a certain number of frames per callback we will either have to rely on block adaption + * (framesPerHostBuffer is not an integer multiple of framesPerPeriod) or we can simply align the number + * of host buffer frames with what the user specified */ + if( self->framesPerUserBuffer != paFramesPerBufferUnspecified ) + { + /* self->alignFrames = 1; */ + + /* Unless the ratio between number of host and user buffer frames is an integer we will have to rely + * on block adaption */ + /* + if( framesPerHostBuffer % framesPerPeriod != 0 || (self->capture.pcm && self->playback.pcm && + self->capture.framesPerPeriod != self->playback.framesPerPeriod) ) + self->useBlockAdaption = 1; + else + self->alignFrames = 1; + */ + } + } + +error: + return result; +} + +static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, + PaStream** s, + const PaStreamParameters *inputParameters, + const PaStreamParameters *outputParameters, + double sampleRate, + unsigned long framesPerBuffer, + PaStreamFlags streamFlags, + PaStreamCallback* callback, + void *userData ) +{ + PaError result = paNoError; + PaAlsaHostApiRepresentation *alsaHostApi = (PaAlsaHostApiRepresentation*)hostApi; + PaAlsaStream *stream = NULL; + PaSampleFormat hostInputSampleFormat = 0, hostOutputSampleFormat = 0; + PaSampleFormat inputSampleFormat = 0, outputSampleFormat = 0; + int numInputChannels = 0, numOutputChannels = 0; + PaTime inputLatency, outputLatency; + /* Operate with fixed host buffer size by default, since other modes will invariably lead to block adaption */ + /* XXX: Use Bounded by default? Output tends to get stuttery with Fixed ... */ + PaUtilHostBufferSizeMode hostBufferSizeMode = paUtilFixedHostBufferSize; + + if( ( streamFlags & paPlatformSpecificFlags ) != 0 ) + return paInvalidFlag; + + if( inputParameters ) + { + PA_ENSURE( ValidateParameters( inputParameters, hostApi, StreamDirection_In ) ); + + numInputChannels = inputParameters->channelCount; + inputSampleFormat = inputParameters->sampleFormat; + } + if( outputParameters ) + { + PA_ENSURE( ValidateParameters( outputParameters, hostApi, StreamDirection_Out ) ); + + numOutputChannels = outputParameters->channelCount; + outputSampleFormat = outputParameters->sampleFormat; + } + + /* XXX: Why do we support this anyway? */ + if( framesPerBuffer == paFramesPerBufferUnspecified && getenv( "PA_ALSA_PERIODSIZE" ) != NULL ) + { + PA_DEBUG(( "%s: Getting framesPerBuffer (Alsa period-size) from environment\n", __FUNCTION__ )); + framesPerBuffer = atoi( getenv("PA_ALSA_PERIODSIZE") ); + } + + PA_UNLESS( stream = (PaAlsaStream*)PaUtil_AllocateMemory( sizeof(PaAlsaStream) ), paInsufficientMemory ); + PA_ENSURE( PaAlsaStream_Initialize( stream, alsaHostApi, inputParameters, outputParameters, sampleRate, + framesPerBuffer, callback, streamFlags, userData ) ); + + PA_ENSURE( PaAlsaStream_Configure( stream, inputParameters, outputParameters, sampleRate, framesPerBuffer, + &inputLatency, &outputLatency, &hostBufferSizeMode ) ); + hostInputSampleFormat = stream->capture.hostSampleFormat | (!stream->capture.hostInterleaved ? paNonInterleaved : 0); + hostOutputSampleFormat = stream->playback.hostSampleFormat | (!stream->playback.hostInterleaved ? paNonInterleaved : 0); + + PA_ENSURE( PaUtil_InitializeBufferProcessor( &stream->bufferProcessor, + numInputChannels, inputSampleFormat, hostInputSampleFormat, + numOutputChannels, outputSampleFormat, hostOutputSampleFormat, + sampleRate, streamFlags, framesPerBuffer, stream->maxFramesPerHostBuffer, + hostBufferSizeMode, callback, userData ) ); + + /* Ok, buffer processor is initialized, now we can deduce it's latency */ + if( numInputChannels > 0 ) + stream->streamRepresentation.streamInfo.inputLatency = inputLatency + (PaTime)( + PaUtil_GetBufferProcessorInputLatencyFrames( &stream->bufferProcessor ) / sampleRate); + if( numOutputChannels > 0 ) + stream->streamRepresentation.streamInfo.outputLatency = outputLatency + (PaTime)( + PaUtil_GetBufferProcessorOutputLatencyFrames( &stream->bufferProcessor ) / sampleRate); + + PA_DEBUG(( "%s: Stream: framesPerBuffer = %lu, maxFramesPerHostBuffer = %lu, latency i=%f, o=%f\n", __FUNCTION__, framesPerBuffer, stream->maxFramesPerHostBuffer, stream->streamRepresentation.streamInfo.inputLatency, stream->streamRepresentation.streamInfo.outputLatency)); + + *s = (PaStream*)stream; + + return result; + +error: + if( stream ) + { + PA_DEBUG(( "%s: Stream in error, terminating\n", __FUNCTION__ )); + PaAlsaStream_Terminate( stream ); + } + + return result; +} + +static PaError CloseStream( PaStream* s ) +{ + PaError result = paNoError; + PaAlsaStream *stream = (PaAlsaStream*)s; + + PaUtil_TerminateBufferProcessor( &stream->bufferProcessor ); + PaUtil_TerminateStreamRepresentation( &stream->streamRepresentation ); + + PaAlsaStream_Terminate( stream ); + + return result; +} + +static void SilenceBuffer( PaAlsaStream *stream ) +{ + const snd_pcm_channel_area_t *areas; + snd_pcm_uframes_t frames = (snd_pcm_uframes_t)alsa_snd_pcm_avail_update( stream->playback.pcm ), offset; + + alsa_snd_pcm_mmap_begin( stream->playback.pcm, &areas, &offset, &frames ); + alsa_snd_pcm_areas_silence( areas, offset, stream->playback.numHostChannels, frames, stream->playback.nativeFormat ); + alsa_snd_pcm_mmap_commit( stream->playback.pcm, offset, frames ); +} + +/** Start/prepare pcm(s) for streaming. + * + * Depending on whether the stream is in callback or blocking mode, we will respectively start or simply + * prepare the playback pcm. If the buffer has _not_ been primed, we will in callback mode prepare and + * silence the buffer before starting playback. In blocking mode we simply prepare, as the playback will + * be started automatically as the user writes to output. + * + * The capture pcm, however, will simply be prepared and started. + */ +static PaError AlsaStart( PaAlsaStream *stream, int priming ) +{ + PaError result = paNoError; + + if( stream->playback.pcm ) + { + if( stream->callbackMode ) + { + if( !priming ) + { + /* Buffer isn't primed, so prepare and silence */ + ENSURE_( alsa_snd_pcm_prepare( stream->playback.pcm ), paUnanticipatedHostError ); + if( stream->playback.canMmap ) + SilenceBuffer( stream ); + } + if( stream->playback.canMmap ) + ENSURE_( alsa_snd_pcm_start( stream->playback.pcm ), paUnanticipatedHostError ); + } + else + ENSURE_( alsa_snd_pcm_prepare( stream->playback.pcm ), paUnanticipatedHostError ); + } + if( stream->capture.pcm && !stream->pcmsSynced ) + { + ENSURE_( alsa_snd_pcm_prepare( stream->capture.pcm ), paUnanticipatedHostError ); + /* For a blocking stream we want to start capture as well, since nothing will happen otherwise */ + ENSURE_( alsa_snd_pcm_start( stream->capture.pcm ), paUnanticipatedHostError ); + } + +end: + return result; +error: + goto end; +} + +/** Utility function for determining if pcms are in running state. + * + */ +#if 0 +static int IsRunning( PaAlsaStream *stream ) +{ + int result = 0; + + PA_ENSURE( PaUnixMutex_Lock( &stream->stateMtx ) ); + if( stream->capture.pcm ) + { + snd_pcm_state_t capture_state = alsa_snd_pcm_state( stream->capture.pcm ); + + if( capture_state == SND_PCM_STATE_RUNNING || capture_state == SND_PCM_STATE_XRUN + || capture_state == SND_PCM_STATE_DRAINING ) + { + result = 1; + goto end; + } + } + + if( stream->playback.pcm ) + { + snd_pcm_state_t playback_state = alsa_snd_pcm_state( stream->playback.pcm ); + + if( playback_state == SND_PCM_STATE_RUNNING || playback_state == SND_PCM_STATE_XRUN + || playback_state == SND_PCM_STATE_DRAINING ) + { + result = 1; + goto end; + } + } + +end: + ASSERT_CALL_( PaUnixMutex_Unlock( &stream->stateMtx ), paNoError ); + return result; +error: + goto error; +} +#endif + +static PaError StartStream( PaStream *s ) +{ + PaError result = paNoError; + PaAlsaStream* stream = (PaAlsaStream*)s; + int streamStarted = 0; /* So we can know whether we need to take the stream down */ + + /* Ready the processor */ + PaUtil_ResetBufferProcessor( &stream->bufferProcessor ); + + /* Set now, so we can test for activity further down */ + stream->isActive = 1; + + if( stream->callbackMode ) + { + PA_ENSURE( PaUnixThread_New( &stream->thread, &CallbackThreadFunc, stream, 1., stream->rtSched ) ); + } + else + { + PA_ENSURE( AlsaStart( stream, 0 ) ); + streamStarted = 1; + } + +end: + return result; +error: + if( streamStarted ) + { + AbortStream( stream ); + } + stream->isActive = 0; + + goto end; +} + +/** Stop PCM handle, either softly or abruptly. + */ +static PaError AlsaStop( PaAlsaStream *stream, int abort ) +{ + PaError result = paNoError; + /* XXX: alsa_snd_pcm_drain tends to lock up, avoid it until we find out more */ + abort = 1; + /* + if( stream->capture.pcm && !strcmp( Pa_GetDeviceInfo( stream->capture.device )->name, + "dmix" ) ) + { + abort = 1; + } + else if( stream->playback.pcm && !strcmp( Pa_GetDeviceInfo( stream->playback.device )->name, + "dmix" ) ) + { + abort = 1; + } + */ + + if( abort ) + { + if( stream->playback.pcm ) + { + ENSURE_( alsa_snd_pcm_drop( stream->playback.pcm ), paUnanticipatedHostError ); + } + if( stream->capture.pcm && !stream->pcmsSynced ) + { + ENSURE_( alsa_snd_pcm_drop( stream->capture.pcm ), paUnanticipatedHostError ); + } + + PA_DEBUG(( "%s: Dropped frames\n", __FUNCTION__ )); + } + else + { + if( stream->playback.pcm ) + { + ENSURE_( alsa_snd_pcm_nonblock( stream->playback.pcm, 0 ), paUnanticipatedHostError ); + if( alsa_snd_pcm_drain( stream->playback.pcm ) < 0 ) + { + PA_DEBUG(( "%s: Draining playback handle failed!\n", __FUNCTION__ )); + } + } + if( stream->capture.pcm && !stream->pcmsSynced ) + { + /* We don't need to retrieve any remaining frames */ + if( alsa_snd_pcm_drain( stream->capture.pcm ) < 0 ) + { + PA_DEBUG(( "%s: Draining capture handle failed!\n", __FUNCTION__ )); + } + } + } + +end: + return result; +error: + goto end; +} + +/** Stop or abort stream. + * + * If a stream is in callback mode we will have to inspect whether the background thread has + * finished, or we will have to take it out. In either case we join the thread before + * returning. In blocking mode, we simply tell ALSA to stop abruptly (abort) or finish + * buffers (drain) + * + * Stream will be considered inactive (!PaAlsaStream::isActive) after a call to this function + */ +static PaError RealStop( PaAlsaStream *stream, int abort ) +{ + PaError result = paNoError; + + /* First deal with the callback thread, cancelling and/or joining + * it if necessary + */ + if( stream->callbackMode ) + { + PaError threadRes; + stream->callbackAbort = abort; + + if( !abort ) + { + PA_DEBUG(( "Stopping callback\n" )); + } + PA_ENSURE( PaUnixThread_Terminate( &stream->thread, !abort, &threadRes ) ); + if( threadRes != paNoError ) + { + PA_DEBUG(( "Callback thread returned: %d\n", threadRes )); + } +#if 0 + if( watchdogRes != paNoError ) + PA_DEBUG(( "Watchdog thread returned: %d\n", watchdogRes )); +#endif + + stream->callback_finished = 0; + } + else + { + PA_ENSURE( AlsaStop( stream, abort ) ); + } + + stream->isActive = 0; + +end: + return result; + +error: + goto end; +} + +static PaError StopStream( PaStream *s ) +{ + return RealStop( (PaAlsaStream *) s, 0 ); +} + +static PaError AbortStream( PaStream *s ) +{ + return RealStop( (PaAlsaStream * ) s, 1 ); +} + +/** The stream is considered stopped before StartStream, or AFTER a call to Abort/StopStream (callback + * returning !paContinue is not considered) + * + */ +static PaError IsStreamStopped( PaStream *s ) +{ + PaAlsaStream *stream = (PaAlsaStream *)s; + + /* callback_finished indicates we need to join callback thread (ie. in Abort/StopStream) */ + return !IsStreamActive( s ) && !stream->callback_finished; +} + +static PaError IsStreamActive( PaStream *s ) +{ + PaAlsaStream *stream = (PaAlsaStream*)s; + return stream->isActive; +} + +static PaTime GetStreamTime( PaStream *s ) +{ + PaAlsaStream *stream = (PaAlsaStream*)s; + + snd_timestamp_t timestamp; + snd_pcm_status_t* status; + alsa_snd_pcm_status_alloca( &status ); + + /* TODO: what if we have both? does it really matter? */ + + /* TODO: if running in callback mode, this will mean + * libasound routines are being called from multiple threads. + * need to verify that libasound is thread-safe. */ + + if( stream->capture.pcm ) + { + alsa_snd_pcm_status( stream->capture.pcm, status ); + } + else if( stream->playback.pcm ) + { + alsa_snd_pcm_status( stream->playback.pcm, status ); + } + + alsa_snd_pcm_status_get_tstamp( status, ×tamp ); + return timestamp.tv_sec + (PaTime)timestamp.tv_usec / 1e6; +} + +static double GetStreamCpuLoad( PaStream* s ) +{ + PaAlsaStream *stream = (PaAlsaStream*)s; + + return PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer ); +} + +/* Set the stream sample rate to a nominal value requested; allow only a defined tolerance range */ +static int SetApproximateSampleRate( snd_pcm_t *pcm, snd_pcm_hw_params_t *hwParams, double sampleRate ) +{ + PaError result = paNoError; + unsigned int reqRate, setRate, deviation; + + assert( pcm && hwParams ); + + /* The Alsa sample rate is set by integer value; also the actual rate may differ */ + reqRate = setRate = (unsigned int) sampleRate; + + ENSURE_( alsa_snd_pcm_hw_params_set_rate_near( pcm, hwParams, &setRate, NULL ), paUnanticipatedHostError ); + /* The value actually set will be put in 'setRate' (may be way off); check the deviation as a proportion + * of the requested-rate with reference to the max-deviate-ratio (larger values allow less deviation) */ + deviation = abs( setRate - reqRate ); + if( deviation > 0 && deviation * RATE_MAX_DEVIATE_RATIO > reqRate ) + result = paInvalidSampleRate; + +end: + return result; + +error: + /* Log */ + { + unsigned int _min = 0, _max = 0; + int _dir = 0; + ENSURE_( alsa_snd_pcm_hw_params_get_rate_min( hwParams, &_min, &_dir ), paUnanticipatedHostError ); + ENSURE_( alsa_snd_pcm_hw_params_get_rate_max( hwParams, &_max, &_dir ), paUnanticipatedHostError ); + PA_DEBUG(( "%s: SR min = %u, max = %u, req = %u\n", __FUNCTION__, _min, _max, reqRate )); + } + goto end; +} + +/* Return exact sample rate in param sampleRate */ +static int GetExactSampleRate( snd_pcm_hw_params_t *hwParams, double *sampleRate ) +{ + unsigned int num, den = 1; + int err; + + assert( hwParams ); + + err = alsa_snd_pcm_hw_params_get_rate_numden( hwParams, &num, &den ); + *sampleRate = (double) num / den; + + return err; +} + +/* Utility functions for blocking/callback interfaces */ + +/* Atomic restart of stream (we don't want the intermediate state visible) */ +static PaError AlsaRestart( PaAlsaStream *stream ) +{ + PaError result = paNoError; + + PA_ENSURE( PaUnixMutex_Lock( &stream->stateMtx ) ); + PA_ENSURE( AlsaStop( stream, 0 ) ); + PA_ENSURE( AlsaStart( stream, 0 ) ); + + PA_DEBUG(( "%s: Restarted audio\n", __FUNCTION__ )); + +error: + PA_ENSURE( PaUnixMutex_Unlock( &stream->stateMtx ) ); + + return result; +} + +/** Recover from xrun state. + * + */ +static PaError PaAlsaStream_HandleXrun( PaAlsaStream *self ) +{ + PaError result = paNoError; + snd_pcm_status_t *st; + PaTime now = PaUtil_GetTime(); + snd_timestamp_t t; + int restartAlsa = 0; /* do not restart Alsa by default */ + + alsa_snd_pcm_status_alloca( &st ); + + if( self->playback.pcm ) + { + alsa_snd_pcm_status( self->playback.pcm, st ); + if( alsa_snd_pcm_status_get_state( st ) == SND_PCM_STATE_XRUN ) + { + alsa_snd_pcm_status_get_trigger_tstamp( st, &t ); + self->underrun = now * 1000 - ( (PaTime)t.tv_sec * 1000 + (PaTime)t.tv_usec / 1000 ); + + if( !self->playback.canMmap ) + { + if( alsa_snd_pcm_recover( self->playback.pcm, -EPIPE, 0 ) < 0 ) + { + PA_DEBUG(( "%s: [playback] non-MMAP-PCM failed recovering from XRUN, will restart Alsa\n", __FUNCTION__ )); + ++ restartAlsa; /* did not manage to recover */ + } + } + else + ++ restartAlsa; /* always restart MMAPed device */ + } + } + if( self->capture.pcm ) + { + alsa_snd_pcm_status( self->capture.pcm, st ); + if( alsa_snd_pcm_status_get_state( st ) == SND_PCM_STATE_XRUN ) + { + alsa_snd_pcm_status_get_trigger_tstamp( st, &t ); + self->overrun = now * 1000 - ((PaTime) t.tv_sec * 1000 + (PaTime) t.tv_usec / 1000); + + if (!self->capture.canMmap) + { + if (alsa_snd_pcm_recover( self->capture.pcm, -EPIPE, 0 ) < 0) + { + PA_DEBUG(( "%s: [capture] non-MMAP-PCM failed recovering from XRUN, will restart Alsa\n", __FUNCTION__ )); + ++ restartAlsa; /* did not manage to recover */ + } + } + else + ++ restartAlsa; /* always restart MMAPed device */ + } + } + + if( restartAlsa ) + { + PA_DEBUG(( "%s: restarting Alsa to recover from XRUN\n", __FUNCTION__ )); + PA_ENSURE( AlsaRestart( self ) ); + } + +end: + return result; +error: + goto end; +} + +/** Decide if we should continue polling for specified direction, eventually adjust the poll timeout. + * + */ +static PaError ContinuePoll( const PaAlsaStream *stream, StreamDirection streamDir, int *pollTimeout, int *continuePoll ) +{ + PaError result = paNoError; + snd_pcm_sframes_t delay, margin; + int err; + const PaAlsaStreamComponent *component = NULL, *otherComponent = NULL; + + *continuePoll = 1; + + if( StreamDirection_In == streamDir ) + { + component = &stream->capture; + otherComponent = &stream->playback; + } + else + { + component = &stream->playback; + otherComponent = &stream->capture; + } + + /* ALSA docs say that negative delay should indicate xrun, but in my experience alsa_snd_pcm_delay returns -EPIPE */ + if( ( err = alsa_snd_pcm_delay( otherComponent->pcm, &delay ) ) < 0 ) + { + if( err == -EPIPE ) + { + /* Xrun */ + *continuePoll = 0; + goto error; + } + + ENSURE_( err, paUnanticipatedHostError ); + } + + if( StreamDirection_Out == streamDir ) + { + /* Number of eligible frames before capture overrun */ + delay = otherComponent->alsaBufferSize - delay; + } + margin = delay - otherComponent->framesPerPeriod / 2; + + if( margin < 0 ) + { + PA_DEBUG(( "%s: Stopping poll for %s\n", __FUNCTION__, StreamDirection_In == streamDir ? "capture" : "playback" )); + *continuePoll = 0; + } + else if( margin < otherComponent->framesPerPeriod ) + { + *pollTimeout = CalculatePollTimeout( stream, margin ); + PA_DEBUG(( "%s: Trying to poll again for %s frames, pollTimeout: %d\n", + __FUNCTION__, StreamDirection_In == streamDir ? "capture" : "playback", *pollTimeout )); + } + +error: + return result; +} + +/* Callback interface */ + +static void OnExit( void *data ) +{ + PaAlsaStream *stream = (PaAlsaStream *) data; + + assert( data ); + + PaUtil_ResetCpuLoadMeasurer( &stream->cpuLoadMeasurer ); + + stream->callback_finished = 1; /* Let the outside world know stream was stopped in callback */ + PA_DEBUG(( "%s: Stopping ALSA handles\n", __FUNCTION__ )); + AlsaStop( stream, stream->callbackAbort ); + + PA_DEBUG(( "%s: Stoppage\n", __FUNCTION__ )); + + /* Eventually notify user all buffers have played */ + if( stream->streamRepresentation.streamFinishedCallback ) + { + stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData ); + } + stream->isActive = 0; +} + +static void CalculateTimeInfo( PaAlsaStream *stream, PaStreamCallbackTimeInfo *timeInfo ) +{ + snd_pcm_status_t *capture_status, *playback_status; + snd_timestamp_t capture_timestamp, playback_timestamp; + PaTime capture_time = 0., playback_time = 0.; + + alsa_snd_pcm_status_alloca( &capture_status ); + alsa_snd_pcm_status_alloca( &playback_status ); + + if( stream->capture.pcm ) + { + snd_pcm_sframes_t capture_delay; + + alsa_snd_pcm_status( stream->capture.pcm, capture_status ); + alsa_snd_pcm_status_get_tstamp( capture_status, &capture_timestamp ); + + capture_time = capture_timestamp.tv_sec + + ( (PaTime)capture_timestamp.tv_usec / 1000000.0 ); + timeInfo->currentTime = capture_time; + + capture_delay = alsa_snd_pcm_status_get_delay( capture_status ); + timeInfo->inputBufferAdcTime = timeInfo->currentTime - + (PaTime)capture_delay / stream->streamRepresentation.streamInfo.sampleRate; + } + if( stream->playback.pcm ) + { + snd_pcm_sframes_t playback_delay; + + alsa_snd_pcm_status( stream->playback.pcm, playback_status ); + alsa_snd_pcm_status_get_tstamp( playback_status, &playback_timestamp ); + + playback_time = playback_timestamp.tv_sec + + ((PaTime)playback_timestamp.tv_usec / 1000000.0); + + if( stream->capture.pcm ) /* Full duplex */ + { + /* Hmm, we have both a playback and a capture timestamp. + * Hopefully they are the same... */ + if( fabs( capture_time - playback_time ) > 0.01 ) + PA_DEBUG(( "Capture time and playback time differ by %f\n", fabs( capture_time-playback_time ) )); + } + else + timeInfo->currentTime = playback_time; + + playback_delay = alsa_snd_pcm_status_get_delay( playback_status ); + timeInfo->outputBufferDacTime = timeInfo->currentTime + + (PaTime)playback_delay / stream->streamRepresentation.streamInfo.sampleRate; + } +} + +/** Called after buffer processing is finished. + * + * A number of mmapped frames is committed, it is possible that an xrun has occurred in the meantime. + * + * @param numFrames The number of frames that has been processed + * @param xrun Return whether an xrun has occurred + */ +static PaError PaAlsaStreamComponent_EndProcessing( PaAlsaStreamComponent *self, unsigned long numFrames, int *xrun ) +{ + PaError result = paNoError; + int res = 0; + + /* @concern FullDuplex It is possible that only one direction is marked ready after polling, and processed + * afterwards + */ + if( !self->ready ) + goto end; + + if( !self->canMmap && StreamDirection_Out == self->streamDir ) + { + /* Play sound */ + if( self->hostInterleaved ) + res = alsa_snd_pcm_writei( self->pcm, self->nonMmapBuffer, numFrames ); + else + { + void *bufs[self->numHostChannels]; + int bufsize = alsa_snd_pcm_format_size( self->nativeFormat, self->framesPerPeriod + 1 ); + unsigned char *buffer = self->nonMmapBuffer; + int i; + for( i = 0; i < self->numHostChannels; ++i ) + { + bufs[i] = buffer; + buffer += bufsize; + } + res = alsa_snd_pcm_writen( self->pcm, bufs, numFrames ); + } + } + + if( self->canMmap ) + res = alsa_snd_pcm_mmap_commit( self->pcm, self->offset, numFrames ); + + if( res == -EPIPE || res == -ESTRPIPE ) + { + *xrun = 1; + } + else + { + ENSURE_( res, paUnanticipatedHostError ); + } + +end: +error: + return result; +} + +/* Extract buffer from channel area */ +static unsigned char *ExtractAddress( const snd_pcm_channel_area_t *area, snd_pcm_uframes_t offset ) +{ + return (unsigned char *) area->addr + ( area->first + offset * area->step ) / 8; +} + +/** Do necessary adaption between user and host channels. + * + @concern ChannelAdaption Adapting between user and host channels can involve silencing unused channels and + duplicating mono information if host outputs come in pairs. + */ +static PaError PaAlsaStreamComponent_DoChannelAdaption( PaAlsaStreamComponent *self, PaUtilBufferProcessor *bp, int numFrames ) +{ + PaError result = paNoError; + unsigned char *p; + int i; + int unusedChans = self->numHostChannels - self->numUserChannels; + unsigned char *src, *dst; + int convertMono = ( self->numHostChannels % 2 ) == 0 && ( self->numUserChannels % 2 ) != 0; + + assert( StreamDirection_Out == self->streamDir ); + + if( self->hostInterleaved ) + { + int swidth = alsa_snd_pcm_format_size( self->nativeFormat, 1 ); + unsigned char *buffer = self->canMmap ? ExtractAddress( self->channelAreas, self->offset ) : self->nonMmapBuffer; + + /* Start after the last user channel */ + p = buffer + self->numUserChannels * swidth; + + if( convertMono ) + { + /* Convert the last user channel into stereo pair */ + src = buffer + ( self->numUserChannels - 1 ) * swidth; + for( i = 0; i < numFrames; ++i ) + { + dst = src + swidth; + memcpy( dst, src, swidth ); + src += self->numHostChannels * swidth; + } + + /* Don't touch the channel we just wrote to */ + p += swidth; + --unusedChans; + } + + if( unusedChans > 0 ) + { + /* Silence unused output channels */ + for( i = 0; i < numFrames; ++i ) + { + memset( p, 0, swidth * unusedChans ); + p += self->numHostChannels * swidth; + } + } + } + else + { + /* We extract the last user channel */ + if( convertMono ) + { + ENSURE_( alsa_snd_pcm_area_copy( self->channelAreas + self->numUserChannels, self->offset, self->channelAreas + + ( self->numUserChannels - 1 ), self->offset, numFrames, self->nativeFormat ), paUnanticipatedHostError ); + --unusedChans; + } + if( unusedChans > 0 ) + { + alsa_snd_pcm_areas_silence( self->channelAreas + ( self->numHostChannels - unusedChans ), self->offset, unusedChans, numFrames, + self->nativeFormat ); + } + } + +error: + return result; +} + +static PaError PaAlsaStream_EndProcessing( PaAlsaStream *self, unsigned long numFrames, int *xrunOccurred ) +{ + PaError result = paNoError; + int xrun = 0; + + if( self->capture.pcm ) + { + PA_ENSURE( PaAlsaStreamComponent_EndProcessing( &self->capture, numFrames, &xrun ) ); + } + if( self->playback.pcm ) + { + if( self->playback.numHostChannels > self->playback.numUserChannels ) + { + PA_ENSURE( PaAlsaStreamComponent_DoChannelAdaption( &self->playback, &self->bufferProcessor, numFrames ) ); + } + PA_ENSURE( PaAlsaStreamComponent_EndProcessing( &self->playback, numFrames, &xrun ) ); + } + +error: + *xrunOccurred = xrun; + return result; +} + +/** Update the number of available frames. + * + */ +static PaError PaAlsaStreamComponent_GetAvailableFrames( PaAlsaStreamComponent *self, unsigned long *numFrames, int *xrunOccurred ) +{ + PaError result = paNoError; + snd_pcm_sframes_t framesAvail = alsa_snd_pcm_avail_update( self->pcm ); + *xrunOccurred = 0; + + if( -EPIPE == framesAvail ) + { + *xrunOccurred = 1; + framesAvail = 0; + } + else + { + ENSURE_( framesAvail, paUnanticipatedHostError ); + } + + *numFrames = framesAvail; + +error: + return result; +} + +/** Fill in pollfd objects. + */ +static PaError PaAlsaStreamComponent_BeginPolling( PaAlsaStreamComponent* self, struct pollfd* pfds ) +{ + PaError result = paNoError; + int ret = alsa_snd_pcm_poll_descriptors( self->pcm, pfds, self->nfds ); + (void)ret; /* Prevent unused variable warning if asserts are turned off */ + assert( ret == self->nfds ); + + self->ready = 0; + + return result; +} + +/** Examine results from poll(). + * + * @param pfds pollfds to inspect + * @param shouldPoll Should we continue to poll + * @param xrun Has an xrun occurred + */ +static PaError PaAlsaStreamComponent_EndPolling( PaAlsaStreamComponent* self, struct pollfd* pfds, int* shouldPoll, int* xrun ) +{ + PaError result = paNoError; + unsigned short revents; + + ENSURE_( alsa_snd_pcm_poll_descriptors_revents( self->pcm, pfds, self->nfds, &revents ), paUnanticipatedHostError ); + if( revents != 0 ) + { + if( revents & POLLERR ) + { + *xrun = 1; + } + else if( revents & POLLHUP ) + { + *xrun = 1; + PA_DEBUG(( "%s: revents has POLLHUP, processing as XRUN\n", __FUNCTION__ )); + } + else + self->ready = 1; + + *shouldPoll = 0; + } + else /* (A zero revent occurred) */ + /* Work around an issue with Alsa older than 1.0.16 using some plugins (eg default with plug + dmix) where + * POLLIN or POLLOUT are zeroed by Alsa-lib if _mmap_avail() is a few frames short of avail_min at period + * boundary, possibly due to erratic dma interrupts at period boundary? Treat as a valid event. + */ + if( self->useReventFix ) + { + self->ready = 1; + *shouldPoll = 0; + } + +error: + return result; +} + +/** Return the number of available frames for this stream. + * + * @concern FullDuplex The minimum available for the two directions is calculated, it might be desirable to ignore + * one direction however (not marked ready from poll), so this is controlled by queryCapture and queryPlayback. + * + * @param queryCapture Check available for capture + * @param queryPlayback Check available for playback + * @param available The returned number of frames + * @param xrunOccurred Return whether an xrun has occurred + */ +static PaError PaAlsaStream_GetAvailableFrames( PaAlsaStream *self, int queryCapture, int queryPlayback, unsigned long + *available, int *xrunOccurred ) +{ + PaError result = paNoError; + unsigned long captureFrames, playbackFrames; + *xrunOccurred = 0; + + assert( queryCapture || queryPlayback ); + + if( queryCapture ) + { + assert( self->capture.pcm ); + PA_ENSURE( PaAlsaStreamComponent_GetAvailableFrames( &self->capture, &captureFrames, xrunOccurred ) ); + if( *xrunOccurred ) + { + goto end; + } + } + if( queryPlayback ) + { + assert( self->playback.pcm ); + PA_ENSURE( PaAlsaStreamComponent_GetAvailableFrames( &self->playback, &playbackFrames, xrunOccurred ) ); + if( *xrunOccurred ) + { + goto end; + } + } + + if( queryCapture && queryPlayback ) + { + *available = PA_MIN( captureFrames, playbackFrames ); + /*PA_DEBUG(("capture: %lu, playback: %lu, combined: %lu\n", captureFrames, playbackFrames, *available));*/ + } + else if( queryCapture ) + { + *available = captureFrames; + } + else + { + *available = playbackFrames; + } + +end: +error: + return result; +} + +/** Wait for and report available buffer space from ALSA. + * + * Unless ALSA reports a minimum of frames available for I/O, we poll the ALSA filedescriptors for more. + * Both of these operations can uncover xrun conditions. + * + * @concern Xruns Both polling and querying available frames can report an xrun condition. + * + * @param framesAvail Return the number of available frames + * @param xrunOccurred Return whether an xrun has occurred + */ +static PaError PaAlsaStream_WaitForFrames( PaAlsaStream *self, unsigned long *framesAvail, int *xrunOccurred ) +{ + PaError result = paNoError; + int pollPlayback = self->playback.pcm != NULL, pollCapture = self->capture.pcm != NULL; + int pollTimeout = self->pollTimeout; + int xrun = 0, timeouts = 0; + int pollResults; + + assert( self ); + assert( framesAvail ); + + if( !self->callbackMode ) + { + /* In blocking mode we will only wait if necessary */ + PA_ENSURE( PaAlsaStream_GetAvailableFrames( self, self->capture.pcm != NULL, self->playback.pcm != NULL, + framesAvail, &xrun ) ); + if( xrun ) + { + goto end; + } + + if( *framesAvail > 0 ) + { + /* Mark pcms ready from poll */ + if( self->capture.pcm ) + self->capture.ready = 1; + if( self->playback.pcm ) + self->playback.ready = 1; + + goto end; + } + } + + while( pollPlayback || pollCapture ) + { + int totalFds = 0; + struct pollfd *capturePfds = NULL, *playbackPfds = NULL; + +#ifdef PTHREAD_CANCELED + pthread_testcancel(); +#endif + if( pollCapture ) + { + capturePfds = self->pfds; + PA_ENSURE( PaAlsaStreamComponent_BeginPolling( &self->capture, capturePfds ) ); + totalFds += self->capture.nfds; + } + if( pollPlayback ) + { + /* self->pfds is in effect an array of fds; if necessary, index past the capture fds */ + playbackPfds = self->pfds + (pollCapture ? self->capture.nfds : 0); + PA_ENSURE( PaAlsaStreamComponent_BeginPolling( &self->playback, playbackPfds ) ); + totalFds += self->playback.nfds; + } + +#ifdef PTHREAD_CANCELED + if( self->callbackMode ) + { + /* To allow 'Abort' to terminate the callback thread, enable cancelability just for poll() (& disable after) */ + pthread_setcancelstate( PTHREAD_CANCEL_ENABLE, NULL ); + } +#endif + + pollResults = poll( self->pfds, totalFds, pollTimeout ); + +#ifdef PTHREAD_CANCELED + if( self->callbackMode ) + { + pthread_setcancelstate( PTHREAD_CANCEL_DISABLE, NULL ); + } +#endif + + if( pollResults < 0 ) + { + /* XXX: Depend on preprocessor condition? */ + if( errno == EINTR ) + { + /* gdb */ + Pa_Sleep( 1 ); /* avoid hot loop */ + continue; + } + + /* TODO: Add macro for checking system calls */ + PA_ENSURE( paInternalError ); + } + else if( pollResults == 0 ) + { + /* Suspended, paused or failed device can provide 0 poll results. To avoid deadloop in such situation + * we simply run counter 'timeouts' which detects 0 poll result and accumulates. As soon as 2048 timouts (around 2 seconds) + * are achieved we simply fail function with paTimedOut to notify waiting methods that device is not capable + * of providing audio data anymore and needs some corresponding recovery action. + * Note that 'timeouts' is reset to 0 if poll() managed to return non 0 results. + */ + + /*PA_DEBUG(( "%s: poll == 0 results, timed out, %d times left\n", __FUNCTION__, 2048 - timeouts ));*/ + ++ timeouts; + if( timeouts > 1 ) /* sometimes device times out, but normally once, so we do not sleep any time */ + { + Pa_Sleep( 1 ); /* avoid hot loop */ + } + /* not else ! */ + if( timeouts >= 2048 ) /* audio device not working, shall return error to notify waiters */ + { + *framesAvail = 0; /* no frames available for processing */ + xrun = 1; /* try recovering device */ + + PA_DEBUG(( "%s: poll timed out\n", __FUNCTION__, timeouts )); + goto end;/*PA_ENSURE( paTimedOut );*/ + } + } + else if( pollResults > 0 ) + { + /* reset timouts counter */ + timeouts = 0; + + /* check the return status of our pfds */ + if( pollCapture ) + { + PA_ENSURE( PaAlsaStreamComponent_EndPolling( &self->capture, capturePfds, &pollCapture, &xrun ) ); + } + if( pollPlayback ) + { + PA_ENSURE( PaAlsaStreamComponent_EndPolling( &self->playback, playbackPfds, &pollPlayback, &xrun ) ); + } + if( xrun ) + { + break; + } + } + + /* @concern FullDuplex If only one of two pcms is ready we may want to compromise between the two. + * If there is less than half a period's worth of samples left of frames in the other pcm's buffer we will + * stop polling. + */ + if( self->capture.pcm && self->playback.pcm ) + { + if( pollCapture && !pollPlayback ) + { + PA_ENSURE( ContinuePoll( self, StreamDirection_In, &pollTimeout, &pollCapture ) ); + } + else if( pollPlayback && !pollCapture ) + { + PA_ENSURE( ContinuePoll( self, StreamDirection_Out, &pollTimeout, &pollPlayback ) ); + } + } + } + + if( !xrun ) + { + /* Get the number of available frames for the pcms that are marked ready. + * @concern FullDuplex If only one direction is marked ready (from poll), the number of frames available for + * the other direction is returned. Output is normally preferred over capture however, so capture frames may be + * discarded to avoid overrun unless paNeverDropInput is specified. + */ + int captureReady = self->capture.pcm ? self->capture.ready : 0, + playbackReady = self->playback.pcm ? self->playback.ready : 0; + PA_ENSURE( PaAlsaStream_GetAvailableFrames( self, captureReady, playbackReady, framesAvail, &xrun ) ); + + if( self->capture.pcm && self->playback.pcm ) + { + if( !self->playback.ready && !self->neverDropInput ) + { + /* Drop input, a period's worth */ + assert( self->capture.ready ); + PaAlsaStreamComponent_EndProcessing( &self->capture, PA_MIN( self->capture.framesPerPeriod, + *framesAvail ), &xrun ); + *framesAvail = 0; + self->capture.ready = 0; + } + } + else if( self->capture.pcm ) + assert( self->capture.ready ); + else + assert( self->playback.ready ); + } + +end: +error: + if( xrun ) + { + /* Recover from the xrun state */ + PA_ENSURE( PaAlsaStream_HandleXrun( self ) ); + *framesAvail = 0; + } + else + { + if( 0 != *framesAvail ) + { + /* If we're reporting frames eligible for processing, one of the handles better be ready */ + PA_UNLESS( self->capture.ready || self->playback.ready, paInternalError ); + } + } + *xrunOccurred = xrun; + + return result; +} + +/** Register per-channel ALSA buffer information with buffer processor. + * + * Mmapped buffer space is acquired from ALSA, and registered with the buffer processor. Differences between the + * number of host and user channels is taken into account. + * + * @param numFrames On entrance the number of requested frames, on exit the number of contiguously accessible frames. + */ +static PaError PaAlsaStreamComponent_RegisterChannels( PaAlsaStreamComponent* self, PaUtilBufferProcessor* bp, + unsigned long* numFrames, int* xrun ) +{ + PaError result = paNoError; + const snd_pcm_channel_area_t *areas, *area; + void (*setChannel)(PaUtilBufferProcessor *, unsigned int, void *, unsigned int) = + StreamDirection_In == self->streamDir ? PaUtil_SetInputChannel : PaUtil_SetOutputChannel; + unsigned char *buffer, *p; + int i; + unsigned long framesAvail; + + /* This _must_ be called before mmap_begin */ + PA_ENSURE( PaAlsaStreamComponent_GetAvailableFrames( self, &framesAvail, xrun ) ); + if( *xrun ) + { + *numFrames = 0; + goto end; + } + + if( self->canMmap ) + { + ENSURE_( alsa_snd_pcm_mmap_begin( self->pcm, &areas, &self->offset, numFrames ), paUnanticipatedHostError ); + /* @concern ChannelAdaption Buffer address is recorded so we can do some channel adaption later */ + self->channelAreas = (snd_pcm_channel_area_t *)areas; + } + else + { + unsigned int bufferSize = self->numHostChannels * alsa_snd_pcm_format_size( self->nativeFormat, *numFrames ); + if( bufferSize > self->nonMmapBufferSize ) + { + self->nonMmapBuffer = realloc( self->nonMmapBuffer, ( self->nonMmapBufferSize = bufferSize ) ); + if( !self->nonMmapBuffer ) + { + result = paInsufficientMemory; + goto error; + } + } + } + + if( self->hostInterleaved ) + { + int swidth = alsa_snd_pcm_format_size( self->nativeFormat, 1 ); + + p = buffer = self->canMmap ? ExtractAddress( areas, self->offset ) : self->nonMmapBuffer; + for( i = 0; i < self->numUserChannels; ++i ) + { + /* We're setting the channels up to userChannels, but the stride will be hostChannels samples */ + setChannel( bp, i, p, self->numHostChannels ); + p += swidth; + } + } + else + { + if( self->canMmap ) + { + for( i = 0; i < self->numUserChannels; ++i ) + { + area = areas + i; + buffer = ExtractAddress( area, self->offset ); + setChannel( bp, i, buffer, 1 ); + } + } + else + { + unsigned int buf_per_ch_size = self->nonMmapBufferSize / self->numHostChannels; + buffer = self->nonMmapBuffer; + for( i = 0; i < self->numUserChannels; ++i ) + { + setChannel( bp, i, buffer, 1 ); + buffer += buf_per_ch_size; + } + } + } + + if( !self->canMmap && StreamDirection_In == self->streamDir ) + { + /* Read sound */ + int res; + if( self->hostInterleaved ) + res = alsa_snd_pcm_readi( self->pcm, self->nonMmapBuffer, *numFrames ); + else + { + void *bufs[self->numHostChannels]; + unsigned int buf_per_ch_size = self->nonMmapBufferSize / self->numHostChannels; + unsigned char *buffer = self->nonMmapBuffer; + int i; + for( i = 0; i < self->numHostChannels; ++i ) + { + bufs[i] = buffer; + buffer += buf_per_ch_size; + } + res = alsa_snd_pcm_readn( self->pcm, bufs, *numFrames ); + } + if( res == -EPIPE || res == -ESTRPIPE ) + { + *xrun = 1; + *numFrames = 0; + } + } + +end: +error: + return result; +} + +/** Initiate buffer processing. + * + * ALSA buffers are registered with the PA buffer processor and the buffer size (in frames) set. + * + * @concern FullDuplex If both directions are being processed, the minimum amount of frames for the two directions is + * calculated. + * + * @param numFrames On entrance the number of available frames, on exit the number of received frames + * @param xrunOccurred Return whether an xrun has occurred + */ +static PaError PaAlsaStream_SetUpBuffers( PaAlsaStream* self, unsigned long* numFrames, int* xrunOccurred ) +{ + PaError result = paNoError; + unsigned long captureFrames = ULONG_MAX, playbackFrames = ULONG_MAX, commonFrames = 0; + int xrun = 0; + + if( *xrunOccurred ) + { + *numFrames = 0; + return result; + } + /* If we got here at least one of the pcm's should be marked ready */ + PA_UNLESS( self->capture.ready || self->playback.ready, paInternalError ); + + /* Extract per-channel ALSA buffer pointers and register them with the buffer processor. + * It is possible that a direction is not marked ready however, because it is out of sync with the other. + */ + if( self->capture.pcm && self->capture.ready ) + { + captureFrames = *numFrames; + PA_ENSURE( PaAlsaStreamComponent_RegisterChannels( &self->capture, &self->bufferProcessor, &captureFrames, + &xrun ) ); + } + if( self->playback.pcm && self->playback.ready ) + { + playbackFrames = *numFrames; + PA_ENSURE( PaAlsaStreamComponent_RegisterChannels( &self->playback, &self->bufferProcessor, &playbackFrames, + &xrun ) ); + } + if( xrun ) + { + /* Nothing more to do */ + assert( 0 == commonFrames ); + goto end; + } + + commonFrames = PA_MIN( captureFrames, playbackFrames ); + /* assert( commonFrames <= *numFrames ); */ + if( commonFrames > *numFrames ) + { + /* Hmmm ... how come there are more frames available than we requested!? Blah. */ + PA_DEBUG(( "%s: Common available frames are reported to be more than number requested: %lu, %lu, callbackMode: %d\n", __FUNCTION__, + commonFrames, *numFrames, self->callbackMode )); + if( self->capture.pcm ) + { + PA_DEBUG(( "%s: captureFrames: %lu, capture.ready: %d\n", __FUNCTION__, captureFrames, self->capture.ready )); + } + if( self->playback.pcm ) + { + PA_DEBUG(( "%s: playbackFrames: %lu, playback.ready: %d\n", __FUNCTION__, playbackFrames, self->playback.ready )); + } + + commonFrames = 0; + goto end; + } + + /* Inform PortAudio of the number of frames we got. + * @concern FullDuplex We might be experiencing underflow in either end; if its an input underflow, we go on + * with output. If its output underflow however, depending on the paNeverDropInput flag, we may want to simply + * discard the excess input or call the callback with paOutputOverflow flagged. + */ + if( self->capture.pcm ) + { + if( self->capture.ready ) + { + PaUtil_SetInputFrameCount( &self->bufferProcessor, commonFrames ); + } + else + { + /* We have input underflow */ + PaUtil_SetNoInput( &self->bufferProcessor ); + } + } + if( self->playback.pcm ) + { + if( self->playback.ready ) + { + PaUtil_SetOutputFrameCount( &self->bufferProcessor, commonFrames ); + } + else + { + /* We have output underflow, but keeping input data (paNeverDropInput) */ + assert( self->neverDropInput ); + assert( self->capture.pcm != NULL ); + PA_DEBUG(( "%s: Setting output buffers to NULL\n", __FUNCTION__ )); + PaUtil_SetNoOutput( &self->bufferProcessor ); + } + } + +end: + *numFrames = commonFrames; +error: + if( xrun ) + { + PA_ENSURE( PaAlsaStream_HandleXrun( self ) ); + *numFrames = 0; + } + *xrunOccurred = xrun; + + return result; +} + +/** Callback thread's function. + * + * Roughly, the workflow can be described in the following way: The number of available frames that can be processed + * directly is obtained from ALSA, we then request as much directly accessible memory as possible within this amount + * from ALSA. The buffer memory is registered with the PA buffer processor and processing is carried out with + * PaUtil_EndBufferProcessing. Finally, the number of processed frames is reported to ALSA. The processing can + * happen in several iterations untill we have consumed the known number of available frames (or an xrun is detected). + */ +static void *CallbackThreadFunc( void *userData ) +{ + PaError result = paNoError; + PaAlsaStream *stream = (PaAlsaStream*) userData; + PaStreamCallbackTimeInfo timeInfo = {0, 0, 0}; + snd_pcm_sframes_t startThreshold = 0; + int callbackResult = paContinue; + PaStreamCallbackFlags cbFlags = 0; /* We might want to keep state across iterations */ + int streamStarted = 0; + + assert( stream ); + /* Not implemented */ + assert( !stream->primeBuffers ); + + /* Execute OnExit when exiting */ + pthread_cleanup_push( &OnExit, stream ); +#ifdef PTHREAD_CANCELED + /* 'Abort' will use thread cancellation to terminate the callback thread, but the Alsa-lib functions + * are NOT cancel-safe, (and can end up in an inconsistent state). So, disable cancelability for + * the thread here, and just re-enable it for the poll() in PaAlsaStream_WaitForFrames(). */ + pthread_testcancel(); + pthread_setcancelstate( PTHREAD_CANCEL_DISABLE, NULL ); +#endif + + /* @concern StreamStart If the output is being primed the output pcm needs to be prepared, otherwise the + * stream is started immediately. The latter involves signaling the waiting main thread. + */ + if( stream->primeBuffers ) + { + snd_pcm_sframes_t avail; + + if( stream->playback.pcm ) + ENSURE_( alsa_snd_pcm_prepare( stream->playback.pcm ), paUnanticipatedHostError ); + if( stream->capture.pcm && !stream->pcmsSynced ) + ENSURE_( alsa_snd_pcm_prepare( stream->capture.pcm ), paUnanticipatedHostError ); + + /* We can't be certain that the whole ring buffer is available for priming, but there should be + * at least one period */ + avail = alsa_snd_pcm_avail_update( stream->playback.pcm ); + startThreshold = avail - (avail % stream->playback.framesPerPeriod); + assert( startThreshold >= stream->playback.framesPerPeriod ); + } + else + { + PA_ENSURE( PaUnixThread_PrepareNotify( &stream->thread ) ); + /* Buffer will be zeroed */ + PA_ENSURE( AlsaStart( stream, 0 ) ); + PA_ENSURE( PaUnixThread_NotifyParent( &stream->thread ) ); + + streamStarted = 1; + } + + while( 1 ) + { + unsigned long framesAvail, framesGot; + int xrun = 0; + +#ifdef PTHREAD_CANCELED + pthread_testcancel(); +#endif + + /* @concern StreamStop if the main thread has requested a stop and the stream has not been effectively + * stopped we signal this condition by modifying callbackResult (we'll want to flush buffered output). + */ + if( PaUnixThread_StopRequested( &stream->thread ) && paContinue == callbackResult ) + { + PA_DEBUG(( "Setting callbackResult to paComplete\n" )); + callbackResult = paComplete; + } + + if( paContinue != callbackResult ) + { + stream->callbackAbort = ( paAbort == callbackResult ); + if( stream->callbackAbort || + /** @concern BlockAdaption: Go on if adaption buffers are empty */ + PaUtil_IsBufferProcessorOutputEmpty( &stream->bufferProcessor ) ) + { + goto end; + } + + PA_DEBUG(( "%s: Flushing buffer processor\n", __FUNCTION__ )); + /* There is still buffered output that needs to be processed */ + } + + /* Wait for data to become available, this comes down to polling the ALSA file descriptors untill we have + * a number of available frames. + */ + PA_ENSURE( PaAlsaStream_WaitForFrames( stream, &framesAvail, &xrun ) ); + if( xrun ) + { + assert( 0 == framesAvail ); + continue; + + /* XXX: Report xruns to the user? A situation is conceivable where the callback is never invoked due + * to constant xruns, it might be desirable to notify the user of this. + */ + } + + /* Consume buffer space. Once we have a number of frames available for consumption we must retrieve the + * mmapped buffers from ALSA, this is contiguously accessible memory however, so we may receive smaller + * portions at a time than is available as a whole. Therefore we should be prepared to process several + * chunks successively. The buffers are passed to the PA buffer processor. + */ + while( framesAvail > 0 ) + { + xrun = 0; + + /** @concern Xruns Under/overflows are to be reported to the callback */ + if( stream->underrun > 0.0 ) + { + cbFlags |= paOutputUnderflow; + stream->underrun = 0.0; + } + if( stream->overrun > 0.0 ) + { + cbFlags |= paInputOverflow; + stream->overrun = 0.0; + } + if( stream->capture.pcm && stream->playback.pcm ) + { + /** @concern FullDuplex It's possible that only one direction is being processed to avoid an + * under- or overflow, this should be reported correspondingly */ + if( !stream->capture.ready ) + { + cbFlags |= paInputUnderflow; + PA_DEBUG(( "%s: Input underflow\n", __FUNCTION__ )); + } + else if( !stream->playback.ready ) + { + cbFlags |= paOutputOverflow; + PA_DEBUG(( "%s: Output overflow\n", __FUNCTION__ )); + } + } + +#if 0 + CallbackUpdate( &stream->threading ); +#endif + + CalculateTimeInfo( stream, &timeInfo ); + PaUtil_BeginBufferProcessing( &stream->bufferProcessor, &timeInfo, cbFlags ); + cbFlags = 0; + + /* CPU load measurement should include processing activity external to the stream callback */ + PaUtil_BeginCpuLoadMeasurement( &stream->cpuLoadMeasurer ); + + framesGot = framesAvail; + if( paUtilFixedHostBufferSize == stream->bufferProcessor.hostBufferSizeMode ) + { + /* We've committed to a fixed host buffer size, stick to that */ + framesGot = framesGot >= stream->maxFramesPerHostBuffer ? stream->maxFramesPerHostBuffer : 0; + } + else + { + /* We've committed to an upper bound on the size of host buffers */ + assert( paUtilBoundedHostBufferSize == stream->bufferProcessor.hostBufferSizeMode ); + framesGot = PA_MIN( framesGot, stream->maxFramesPerHostBuffer ); + } + PA_ENSURE( PaAlsaStream_SetUpBuffers( stream, &framesGot, &xrun ) ); + /* Check the host buffer size against the buffer processor configuration */ + framesAvail -= framesGot; + + if( framesGot > 0 ) + { + assert( !xrun ); + PaUtil_EndBufferProcessing( &stream->bufferProcessor, &callbackResult ); + PA_ENSURE( PaAlsaStream_EndProcessing( stream, framesGot, &xrun ) ); + } + PaUtil_EndCpuLoadMeasurement( &stream->cpuLoadMeasurer, framesGot ); + + if( 0 == framesGot ) + { + /* Go back to polling for more frames */ + break; + } + + if( paContinue != callbackResult ) + break; + } + } + +end: + ; /* Hack to fix "label at end of compound statement" error caused by pthread_cleanup_pop(1) macro. */ + /* Match pthread_cleanup_push */ + pthread_cleanup_pop( 1 ); + + PA_DEBUG(( "%s: Thread %d exiting\n ", __FUNCTION__, pthread_self() )); + PaUnixThreading_EXIT( result ); + +error: + PA_DEBUG(( "%s: Thread %d is canceled due to error %d\n ", __FUNCTION__, pthread_self(), result )); + goto end; +} + +/* Blocking interface */ + +static PaError ReadStream( PaStream* s, void *buffer, unsigned long frames ) +{ + PaError result = paNoError; + PaAlsaStream *stream = (PaAlsaStream*)s; + unsigned long framesGot, framesAvail; + void *userBuffer; + snd_pcm_t *save = stream->playback.pcm; + + assert( stream ); + + PA_UNLESS( stream->capture.pcm, paCanNotReadFromAnOutputOnlyStream ); + + /* Disregard playback */ + stream->playback.pcm = NULL; + + if( stream->overrun > 0. ) + { + result = paInputOverflowed; + stream->overrun = 0.0; + } + + if( stream->capture.userInterleaved ) + { + userBuffer = buffer; + } + else + { + /* Copy channels into local array */ + userBuffer = stream->capture.userBuffers; + memcpy( userBuffer, buffer, sizeof (void *) * stream->capture.numUserChannels ); + } + + /* Start stream if in prepared state */ + if( alsa_snd_pcm_state( stream->capture.pcm ) == SND_PCM_STATE_PREPARED ) + { + ENSURE_( alsa_snd_pcm_start( stream->capture.pcm ), paUnanticipatedHostError ); + } + + while( frames > 0 ) + { + int xrun = 0; + PA_ENSURE( PaAlsaStream_WaitForFrames( stream, &framesAvail, &xrun ) ); + framesGot = PA_MIN( framesAvail, frames ); + + PA_ENSURE( PaAlsaStream_SetUpBuffers( stream, &framesGot, &xrun ) ); + if( framesGot > 0 ) + { + framesGot = PaUtil_CopyInput( &stream->bufferProcessor, &userBuffer, framesGot ); + PA_ENSURE( PaAlsaStream_EndProcessing( stream, framesGot, &xrun ) ); + frames -= framesGot; + } + } + +end: + stream->playback.pcm = save; + return result; +error: + goto end; +} + +static PaError WriteStream( PaStream* s, const void *buffer, unsigned long frames ) +{ + PaError result = paNoError; + signed long err; + PaAlsaStream *stream = (PaAlsaStream*)s; + snd_pcm_uframes_t framesGot, framesAvail; + const void *userBuffer; + snd_pcm_t *save = stream->capture.pcm; + + assert( stream ); + + PA_UNLESS( stream->playback.pcm, paCanNotWriteToAnInputOnlyStream ); + + /* Disregard capture */ + stream->capture.pcm = NULL; + + if( stream->underrun > 0. ) + { + result = paOutputUnderflowed; + stream->underrun = 0.0; + } + + if( stream->playback.userInterleaved ) + userBuffer = buffer; + else /* Copy channels into local array */ + { + userBuffer = stream->playback.userBuffers; + memcpy( (void *)userBuffer, buffer, sizeof (void *) * stream->playback.numUserChannels ); + } + + while( frames > 0 ) + { + int xrun = 0; + snd_pcm_uframes_t hwAvail; + + PA_ENSURE( PaAlsaStream_WaitForFrames( stream, &framesAvail, &xrun ) ); + framesGot = PA_MIN( framesAvail, frames ); + + PA_ENSURE( PaAlsaStream_SetUpBuffers( stream, &framesGot, &xrun ) ); + if( framesGot > 0 ) + { + framesGot = PaUtil_CopyOutput( &stream->bufferProcessor, &userBuffer, framesGot ); + PA_ENSURE( PaAlsaStream_EndProcessing( stream, framesGot, &xrun ) ); + frames -= framesGot; + } + + /* Start stream after one period of samples worth */ + + /* Frames residing in buffer */ + PA_ENSURE( err = GetStreamWriteAvailable( stream ) ); + framesAvail = err; + hwAvail = stream->playback.alsaBufferSize - framesAvail; + + if( alsa_snd_pcm_state( stream->playback.pcm ) == SND_PCM_STATE_PREPARED && + hwAvail >= stream->playback.framesPerPeriod ) + { + ENSURE_( alsa_snd_pcm_start( stream->playback.pcm ), paUnanticipatedHostError ); + } + } + +end: + stream->capture.pcm = save; + return result; +error: + goto end; +} + +/* Return frames available for reading. In the event of an overflow, the capture pcm will be restarted */ +static signed long GetStreamReadAvailable( PaStream* s ) +{ + PaError result = paNoError; + PaAlsaStream *stream = (PaAlsaStream*)s; + unsigned long avail; + int xrun; + + PA_ENSURE( PaAlsaStreamComponent_GetAvailableFrames( &stream->capture, &avail, &xrun ) ); + if( xrun ) + { + PA_ENSURE( PaAlsaStream_HandleXrun( stream ) ); + PA_ENSURE( PaAlsaStreamComponent_GetAvailableFrames( &stream->capture, &avail, &xrun ) ); + if( xrun ) + PA_ENSURE( paInputOverflowed ); + } + + return (signed long)avail; + +error: + return result; +} + +static signed long GetStreamWriteAvailable( PaStream* s ) +{ + PaError result = paNoError; + PaAlsaStream *stream = (PaAlsaStream*)s; + unsigned long avail; + int xrun; + + PA_ENSURE( PaAlsaStreamComponent_GetAvailableFrames( &stream->playback, &avail, &xrun ) ); + if( xrun ) + { + snd_pcm_sframes_t savail; + + PA_ENSURE( PaAlsaStream_HandleXrun( stream ) ); + savail = alsa_snd_pcm_avail_update( stream->playback.pcm ); + + /* savail should not contain -EPIPE now, since PaAlsaStream_HandleXrun will only prepare the pcm */ + ENSURE_( savail, paUnanticipatedHostError ); + + avail = (unsigned long) savail; + } + + return (signed long)avail; + +error: + return result; +} + +/* Extensions */ + +void PaAlsa_InitializeStreamInfo( PaAlsaStreamInfo *info ) +{ + info->size = sizeof (PaAlsaStreamInfo); + info->hostApiType = paALSA; + info->version = 1; + info->deviceString = NULL; +} + +void PaAlsa_EnableRealtimeScheduling( PaStream *s, int enable ) +{ + PaAlsaStream *stream = (PaAlsaStream *) s; + stream->rtSched = enable; +} + +#if 0 +void PaAlsa_EnableWatchdog( PaStream *s, int enable ) +{ + PaAlsaStream *stream = (PaAlsaStream *) s; + stream->thread.useWatchdog = enable; +} +#endif + +static PaError GetAlsaStreamPointer( PaStream* s, PaAlsaStream** stream ) +{ + PaError result = paNoError; + PaUtilHostApiRepresentation* hostApi; + PaAlsaHostApiRepresentation* alsaHostApi; + + PA_ENSURE( PaUtil_ValidateStreamPointer( s ) ); + PA_ENSURE( PaUtil_GetHostApiRepresentation( &hostApi, paALSA ) ); + alsaHostApi = (PaAlsaHostApiRepresentation*)hostApi; + + PA_UNLESS( PA_STREAM_REP( s )->streamInterface == &alsaHostApi->callbackStreamInterface + || PA_STREAM_REP( s )->streamInterface == &alsaHostApi->blockingStreamInterface, + paIncompatibleStreamHostApi ); + + *stream = (PaAlsaStream*)s; +error: + return paNoError; +} + +PaError PaAlsa_GetStreamInputCard( PaStream* s, int* card ) +{ + PaAlsaStream *stream; + PaError result = paNoError; + snd_pcm_info_t* pcmInfo; + + PA_ENSURE( GetAlsaStreamPointer( s, &stream ) ); + + /* XXX: More descriptive error? */ + PA_UNLESS( stream->capture.pcm, paDeviceUnavailable ); + + alsa_snd_pcm_info_alloca( &pcmInfo ); + PA_ENSURE( alsa_snd_pcm_info( stream->capture.pcm, pcmInfo ) ); + *card = alsa_snd_pcm_info_get_card( pcmInfo ); + +error: + return result; +} + +PaError PaAlsa_GetStreamOutputCard( PaStream* s, int* card ) +{ + PaAlsaStream *stream; + PaError result = paNoError; + snd_pcm_info_t* pcmInfo; + + PA_ENSURE( GetAlsaStreamPointer( s, &stream ) ); + + /* XXX: More descriptive error? */ + PA_UNLESS( stream->playback.pcm, paDeviceUnavailable ); + + alsa_snd_pcm_info_alloca( &pcmInfo ); + PA_ENSURE( alsa_snd_pcm_info( stream->playback.pcm, pcmInfo ) ); + *card = alsa_snd_pcm_info_get_card( pcmInfo ); + +error: + return result; +} + +PaError PaAlsa_SetRetriesBusy( int retries ) +{ + busyRetries_ = retries; + return paNoError; +} diff --git a/extern/portaudio/src/hostapi/asihpi/pa_linux_asihpi.c b/extern/portaudio/src/hostapi/asihpi/pa_linux_asihpi.c new file mode 100644 index 0000000..f5a5290 --- /dev/null +++ b/extern/portaudio/src/hostapi/asihpi/pa_linux_asihpi.c @@ -0,0 +1,2893 @@ +/* + * $Id:$ + * PortAudio Portable Real-Time Audio Library + * Latest Version at: http://www.portaudio.com + * AudioScience HPI implementation by Fred Gleason, Ludwig Schwardt and + * Eliot Blennerhassett + * + * Copyright (c) 2003 Fred Gleason + * Copyright (c) 2005,2006 Ludwig Schwardt + * Copyright (c) 2011 Eliot Blennerhassett + * + * Based on the Open Source API proposed by Ross Bencina + * Copyright (c) 1999-2008 Ross Bencina, Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +/* + * Modification History + * 12/2003 - Initial version + * 09/2005 - v19 version [rewrite] + */ + +/** @file + @ingroup hostapi_src + @brief Host API implementation supporting AudioScience cards + via the Linux HPI interface. + +

    Overview

    + + This is a PortAudio implementation for the AudioScience HPI Audio API + on the Linux platform. AudioScience makes a range of audio adapters customised + for the broadcasting industry, with support for both Windows and Linux. + More information on their products can be found on their website: + + http://www.audioscience.com + + Documentation for the HPI API can be found at: + + http://www.audioscience.com/internet/download/sdk/hpi_usermanual_html/html/index.html + + The Linux HPI driver itself (a kernel module + library) can be downloaded from: + + http://www.audioscience.com/internet/download/linux_drivers.htm + +

    Implementation strategy

    + + *Note* Ideally, AudioScience cards should be handled by the PortAudio ALSA + implementation on Linux, as ALSA is the preferred Linux soundcard API. The existence + of this host API implementation might therefore seem a bit flawed. Unfortunately, at + the time of the creation of this implementation (June 2006), the PA ALSA implementation + could not make use of the existing AudioScience ALSA driver. PA ALSA uses the + "memory-mapped" (mmap) ALSA access mode to interact with the ALSA library, while the + AudioScience ALSA driver only supports the "read-write" access mode. The appropriate + solution to this problem is to add "read-write" support to PortAudio ALSA, thereby + extending the range of soundcards it supports (AudioScience cards are not the only + ones with this problem). Given the author's limited knowledge of ALSA and the + simplicity of the HPI API, the second-best solution was born... + + The following mapping between HPI and PA was followed: + HPI subsystem => PortAudio host API + HPI adapter => nothing specific + HPI stream => PortAudio device + + Each HPI stream is either input or output (not both), and can support + different channel counts, sampling rates and sample formats. It is therefore + a more natural fit to a PA device. A PA stream can therefore combine two + HPI streams (one input and one output) into a "full-duplex" stream. These + HPI streams can even be on different physical adapters. The two streams ought to be + sample-synchronised when they reside on the same adapter, as most AudioScience adapters + derive their ADC and DAC clocks from one master clock. When combining two adapters + into one full-duplex stream, however, the use of a word clock connection between the + adapters is strongly recommended. + + The HPI interface is inherently blocking, making use of read and write calls to + transfer data between user buffers and driver buffers. The callback interface therefore + requires a helper thread ("callback engine") which periodically transfers data (one thread + per PA stream, in fact). The current implementation explicitly sleeps via Pa_Sleep() until + enough samples can be transferred (select() or poll() would be better, but currently seems + impossible...). The thread implementation makes use of the Unix thread helper functions + and some pthread calls here and there. If a unified PA thread exists, this host API + implementation might also compile on Windows, as this is the only real Linux-specific + part of the code. + + There is no inherent fixed buffer size in the HPI interface, as in some other host APIs. + The PortAudio implementation contains a buffer that is allocated during OpenStream and + used to transfer data between the callback and the HPI driver buffer. The size of this + buffer is quite flexible and is derived from latency suggestions and matched to the + requested callback buffer size as far as possible. It can become quite huge, as the + AudioScience cards are typically geared towards higher-latency applications and contain + large hardware buffers. + + The HPI interface natively supports most common sample formats and sample rates (some + conversion is done on the adapter itself). + + Stream time is measured based on the number of processed frames, which is adjusted by the + number of frames currently buffered by the HPI driver. + + There is basic support for detecting overflow and underflow. The HPI interface does not + explicitly indicate this, so thresholds on buffer levels are used in combination with + stream state. Recovery from overflow and underflow is left to the PA client. + + Blocking streams are also implemented. It makes use of the same polling routines that + the callback interface uses, in order to prevent the allocation of variable-sized + buffers during reading and writing. The framesPerBuffer parameter is therefore still + relevant, and this can be increased in the blocking case to improve efficiency. + + The implementation contains extensive reporting macros (slightly modified PA_ENSURE and + PA_UNLESS versions) and a useful stream dump routine to provide debugging feedback. + + Output buffer priming via the user callback (i.e. paPrimeOutputBuffersUsingStreamCallback + and friends) is not implemented yet. All output is primed with silence. + */ + +#include +#include +#include +#include /* strlen() */ +#include /* pthreads and friends */ +#include /* assert */ +#include /* ceil, floor */ + +#include /* HPI API */ + +#include "portaudio.h" /* PortAudio API */ +#include "pa_util.h" /* PA_DEBUG, other small utilities */ +#include "pa_unix_util.h" /* Unix threading utilities */ +#include "pa_allocation.h" /* Group memory allocation */ +#include "pa_hostapi.h" /* Host API structs */ +#include "pa_stream.h" /* Stream interface structs */ +#include "pa_cpuload.h" /* CPU load measurer */ +#include "pa_process.h" /* Buffer processor */ +#include "pa_converters.h" /* PaUtilZeroer */ +#include "pa_debugprint.h" + +/* -------------------------------------------------------------------------- */ + +/* + * Defines + */ + +/* Error reporting and assertions */ + +/** Evaluate expression, and return on any PortAudio errors */ +#define PA_ENSURE_(expr) \ + do { \ + PaError paError = (expr); \ + if( UNLIKELY( paError < paNoError ) ) \ + { \ + PA_DEBUG(( "Expression '" #expr "' failed in '" __FILE__ "', line: " STRINGIZE( __LINE__ ) "\n" )); \ + result = paError; \ + goto error; \ + } \ + } while (0); + +/** Assert expression, else return the provided PaError */ +#define PA_UNLESS_(expr, paError) \ + do { \ + if( UNLIKELY( (expr) == 0 ) ) \ + { \ + PA_DEBUG(( "Expression '" #expr "' failed in '" __FILE__ "', line: " STRINGIZE( __LINE__ ) "\n" )); \ + result = (paError); \ + goto error; \ + } \ + } while( 0 ); + +/** Check return value of HPI function, and map it to PaError */ +#define PA_ASIHPI_UNLESS_(expr, paError) \ + do { \ + hpi_err_t hpiError = (expr); \ + /* If HPI error occurred */ \ + if( UNLIKELY( hpiError ) ) \ + { \ + char szError[256]; \ + HPI_GetErrorText( hpiError, szError ); \ + PA_DEBUG(( "HPI error %d occurred: %s\n", hpiError, szError )); \ + /* This message will always be displayed, even if debug info is disabled */ \ + PA_DEBUG(( "Expression '" #expr "' failed in '" __FILE__ "', line: " STRINGIZE( __LINE__ ) "\n" )); \ + if( (paError) == paUnanticipatedHostError ) \ + { \ + PA_DEBUG(( "Host error description: %s\n", szError )); \ + /* PaUtil_SetLastHostErrorInfo should only be used in the main thread */ \ + if( pthread_equal( pthread_self(), paUnixMainThread ) ) \ + { \ + PaUtil_SetLastHostErrorInfo( paInDevelopment, hpiError, szError ); \ + } \ + } \ + /* If paNoError is specified, continue as usual */ \ + /* (useful if you only want to print out the debug messages above) */ \ + if( (paError) < 0 ) \ + { \ + result = (paError); \ + goto error; \ + } \ + } \ + } while( 0 ); + +/** Report HPI error code and text */ +#define PA_ASIHPI_REPORT_ERROR_(hpiErrorCode) \ + do { \ + char szError[256]; \ + HPI_GetErrorText( hpiError, szError ); \ + PA_DEBUG(( "HPI error %d occurred: %s\n", hpiError, szError )); \ + /* PaUtil_SetLastHostErrorInfo should only be used in the main thread */ \ + if( pthread_equal( pthread_self(), paUnixMainThread ) ) \ + { \ + PaUtil_SetLastHostErrorInfo( paInDevelopment, (hpiErrorCode), szError ); \ + } \ + } while( 0 ); + +/* Defaults */ + +/** Sample formats available natively on AudioScience hardware */ +#define PA_ASIHPI_AVAILABLE_FORMATS_ (paFloat32 | paInt32 | paInt24 | paInt16 | paUInt8) +/** Enable background bus mastering (BBM) for buffer transfers, if available (see HPI docs) */ +#define PA_ASIHPI_USE_BBM_ 1 +/** Minimum number of frames in HPI buffer (for either data or available space). + If buffer contains less data/space, it indicates xrun or completion. */ +#define PA_ASIHPI_MIN_FRAMES_ 1152 +/** Minimum polling interval in milliseconds, which determines minimum host buffer size */ +#define PA_ASIHPI_MIN_POLLING_INTERVAL_ 10 + +/* -------------------------------------------------------------------------- */ + +/* + * Structures + */ + +/** Host API global data */ +typedef struct PaAsiHpiHostApiRepresentation +{ + /* PortAudio "base class" - keep the baseRep first! (C-style inheritance) */ + PaUtilHostApiRepresentation baseHostApiRep; + PaUtilStreamInterface callbackStreamInterface; + PaUtilStreamInterface blockingStreamInterface; + + PaUtilAllocationGroup *allocations; + + /* implementation specific data goes here */ + + PaHostApiIndex hostApiIndex; +} +PaAsiHpiHostApiRepresentation; + + +/** Device data */ +typedef struct PaAsiHpiDeviceInfo +{ + /* PortAudio "base class" - keep the baseRep first! (C-style inheritance) */ + /** Common PortAudio device information */ + PaDeviceInfo baseDeviceInfo; + + /* implementation specific data goes here */ + + /** Adapter index */ + uint16_t adapterIndex; + /** Adapter model number (hex) */ + uint16_t adapterType; + /** Adapter HW/SW version */ + uint16_t adapterVersion; + /** Adapter serial number */ + uint32_t adapterSerialNumber; + /** Stream number */ + uint16_t streamIndex; + /** 0=Input, 1=Output (HPI streams are either input or output but not both) */ + uint16_t streamIsOutput; +} +PaAsiHpiDeviceInfo; + + +/** Stream state as defined by PortAudio. + It seems that the host API implementation has to keep track of the PortAudio stream state. + Please note that this is NOT the same as the state of the underlying HPI stream. By separating + these two concepts, a lot of flexibility is gained. There is a rough match between the two, + of course, but forcing a precise match is difficult. For example, HPI_STATE_DRAINED can occur + during the Active state of PortAudio (due to underruns) and also during CallBackFinished in + the case of an output stream. Similarly, HPI_STATE_STOPPED mostly coincides with the Stopped + PortAudio state, by may also occur in the CallbackFinished state when recording is finished. + + Here is a rough match-up: + + PortAudio state => HPI state + --------------- --------- + Active => HPI_STATE_RECORDING, HPI_STATE_PLAYING, (HPI_STATE_DRAINED) + Stopped => HPI_STATE_STOPPED + CallbackFinished => HPI_STATE_STOPPED, HPI_STATE_DRAINED */ +typedef enum PaAsiHpiStreamState +{ + paAsiHpiStoppedState=0, + paAsiHpiActiveState=1, + paAsiHpiCallbackFinishedState=2 +} +PaAsiHpiStreamState; + + +/** Stream component data (associated with one direction, i.e. either input or output) */ +typedef struct PaAsiHpiStreamComponent +{ + /** Device information (HPI handles, etc) */ + PaAsiHpiDeviceInfo *hpiDevice; + /** Stream handle, as passed to HPI interface. */ + hpi_handle_t hpiStream; + /** Stream format, as passed to HPI interface */ + struct hpi_format hpiFormat; + /** Number of bytes per frame, derived from hpiFormat and saved for convenience */ + uint32_t bytesPerFrame; + /** Size of hardware (on-card) buffer of stream in bytes */ + uint32_t hardwareBufferSize; + /** Size of host (BBM) buffer of stream in bytes (if used) */ + uint32_t hostBufferSize; + /** Upper limit on the utilization of output stream buffer (both hardware and host). + This prevents large latencies in an output-only stream with a potentially huge buffer + and a fast data generator, which would otherwise keep the hardware buffer filled to + capacity. See also the "Hardware Buffering=off" option in the AudioScience WAV driver. */ + uint32_t outputBufferCap; + /** Sample buffer (halfway station between HPI and buffer processor) */ + uint8_t *tempBuffer; + /** Sample buffer size, in bytes */ + uint32_t tempBufferSize; +} +PaAsiHpiStreamComponent; + + +/** Stream data */ +typedef struct PaAsiHpiStream +{ + /* PortAudio "base class" - keep the baseRep first! (C-style inheritance) */ + PaUtilStreamRepresentation baseStreamRep; + PaUtilCpuLoadMeasurer cpuLoadMeasurer; + PaUtilBufferProcessor bufferProcessor; + + PaUtilAllocationGroup *allocations; + + /* implementation specific data goes here */ + + /** Separate structs for input and output sides of stream */ + PaAsiHpiStreamComponent *input, *output; + + /** Polling interval (in milliseconds) */ + uint32_t pollingInterval; + /** Are we running in callback mode? */ + int callbackMode; + /** Number of frames to transfer at a time to/from HPI */ + unsigned long maxFramesPerHostBuffer; + /** Indicates that the stream is in the paNeverDropInput mode */ + int neverDropInput; + /** Contains copy of user buffers, used by blocking interface to transfer non-interleaved data. + It went here instead of to each stream component, as the stream component buffer setup in + PaAsiHpi_SetupBuffers doesn't know the stream details such as callbackMode. + (Maybe a problem later if ReadStream and WriteStream happens concurrently on same stream.) */ + void **blockingUserBufferCopy; + + /* Thread-related variables */ + + /** Helper thread which will deliver data to user callback */ + PaUnixThread thread; + /** PortAudio stream state (Active/Stopped/CallbackFinished) */ + volatile sig_atomic_t state; + /** Hard abort, i.e. drop frames? */ + volatile sig_atomic_t callbackAbort; + /** True if stream stopped via exiting callback with paComplete/paAbort flag + (as opposed to explicit call to StopStream/AbortStream) */ + volatile sig_atomic_t callbackFinished; +} +PaAsiHpiStream; + + +/** Stream state information, collected together for convenience */ +typedef struct PaAsiHpiStreamInfo +{ + /** HPI stream state (HPI_STATE_STOPPED, HPI_STATE_PLAYING, etc.) */ + uint16_t state; + /** Size (in bytes) of recording/playback data buffer in HPI driver */ + uint32_t bufferSize; + /** Amount of data (in bytes) available in the buffer */ + uint32_t dataSize; + /** Number of frames played/recorded since last stream reset */ + uint32_t frameCounter; + /** Amount of data (in bytes) in hardware (on-card) buffer. + This differs from dataSize if bus mastering (BBM) is used, which introduces another + driver-level buffer to which dataSize/bufferSize then refers. */ + uint32_t auxDataSize; + /** Total number of data frames currently buffered by HPI driver (host + hw buffers) */ + uint32_t totalBufferedData; + /** Size of immediately available data (for input) or space (for output) in frames. + This only checks the first-level buffer (typically host buffer). This amount can be + transferred immediately. */ + uint32_t availableFrames; + /** Indicates that hardware buffer is getting too full */ + int overflow; + /** Indicates that hardware buffer is getting too empty */ + int underflow; +} +PaAsiHpiStreamInfo; + +/* -------------------------------------------------------------------------- */ + +/* + * Function prototypes + */ + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + /* The only exposed function in the entire host API implementation */ + PaError PaAsiHpi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index ); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +static void Terminate( struct PaUtilHostApiRepresentation *hostApi ); +static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi, + const PaStreamParameters *inputParameters, + const PaStreamParameters *outputParameters, + double sampleRate ); + +/* Stream prototypes */ +static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, + PaStream **s, + const PaStreamParameters *inputParameters, + const PaStreamParameters *outputParameters, + double sampleRate, + unsigned long framesPerBuffer, + PaStreamFlags streamFlags, + PaStreamCallback *streamCallback, + void *userData ); +static PaError CloseStream( PaStream *s ); +static PaError StartStream( PaStream *s ); +static PaError StopStream( PaStream *s ); +static PaError AbortStream( PaStream *s ); +static PaError IsStreamStopped( PaStream *s ); +static PaError IsStreamActive( PaStream *s ); +static PaTime GetStreamTime( PaStream *s ); +static double GetStreamCpuLoad( PaStream *s ); + +/* Blocking prototypes */ +static PaError ReadStream( PaStream *s, void *buffer, unsigned long frames ); +static PaError WriteStream( PaStream *s, const void *buffer, unsigned long frames ); +static signed long GetStreamReadAvailable( PaStream *s ); +static signed long GetStreamWriteAvailable( PaStream *s ); + +/* Callback prototypes */ +static void *CallbackThreadFunc( void *userData ); + +/* Functions specific to this API */ +static PaError PaAsiHpi_BuildDeviceList( PaAsiHpiHostApiRepresentation *hpiHostApi ); +static uint16_t PaAsiHpi_PaToHpiFormat( PaSampleFormat paFormat ); +static PaSampleFormat PaAsiHpi_HpiToPaFormat( uint16_t hpiFormat ); +static PaError PaAsiHpi_CreateFormat( struct PaUtilHostApiRepresentation *hostApi, + const PaStreamParameters *parameters, double sampleRate, + PaAsiHpiDeviceInfo **hpiDevice, struct hpi_format *hpiFormat ); +static PaError PaAsiHpi_OpenInput( struct PaUtilHostApiRepresentation *hostApi, + const PaAsiHpiDeviceInfo *hpiDevice, const struct hpi_format *hpiFormat, + hpi_handle_t *hpiStream ); +static PaError PaAsiHpi_OpenOutput( struct PaUtilHostApiRepresentation *hostApi, + const PaAsiHpiDeviceInfo *hpiDevice, const struct hpi_format *hpiFormat, + hpi_handle_t *hpiStream ); +static PaError PaAsiHpi_GetStreamInfo( PaAsiHpiStreamComponent *streamComp, PaAsiHpiStreamInfo *info ); +static void PaAsiHpi_StreamComponentDump( PaAsiHpiStreamComponent *streamComp, PaAsiHpiStream *stream ); +static void PaAsiHpi_StreamDump( PaAsiHpiStream *stream ); +static PaError PaAsiHpi_SetupBuffers( PaAsiHpiStreamComponent *streamComp, uint32_t pollingInterval, + unsigned long framesPerPaHostBuffer, PaTime suggestedLatency ); +static PaError PaAsiHpi_PrimeOutputWithSilence( PaAsiHpiStream *stream ); +static PaError PaAsiHpi_StartStream( PaAsiHpiStream *stream, int outputPrimed ); +static PaError PaAsiHpi_StopStream( PaAsiHpiStream *stream, int abort ); +static PaError PaAsiHpi_ExplicitStop( PaAsiHpiStream *stream, int abort ); +static void PaAsiHpi_OnThreadExit( void *userData ); +static PaError PaAsiHpi_WaitForFrames( PaAsiHpiStream *stream, unsigned long *framesAvail, + PaStreamCallbackFlags *cbFlags ); +static void PaAsiHpi_CalculateTimeInfo( PaAsiHpiStream *stream, PaStreamCallbackTimeInfo *timeInfo ); +static PaError PaAsiHpi_BeginProcessing( PaAsiHpiStream* stream, unsigned long* numFrames, + PaStreamCallbackFlags *cbFlags ); +static PaError PaAsiHpi_EndProcessing( PaAsiHpiStream *stream, unsigned long numFrames, + PaStreamCallbackFlags *cbFlags ); + +/* ========================================================================== + * ============================= IMPLEMENTATION ============================= + * ========================================================================== */ + +/* --------------------------- Host API Interface --------------------------- */ + +/** Enumerate all PA devices (= HPI streams). + This compiles a list of all HPI adapters, and registers a PA device for each input and + output stream it finds. Most errors are ignored, as missing or erroneous devices are + simply skipped. + + @param hpiHostApi Pointer to HPI host API struct + + @return PortAudio error code (only paInsufficientMemory in practice) + */ +static PaError PaAsiHpi_BuildDeviceList( PaAsiHpiHostApiRepresentation *hpiHostApi ) +{ + PaError result = paNoError; + PaUtilHostApiRepresentation *hostApi = &hpiHostApi->baseHostApiRep; + PaHostApiInfo *baseApiInfo = &hostApi->info; + PaAsiHpiDeviceInfo *hpiDeviceList; + int numAdapters; + hpi_err_t hpiError = 0; + int i, j, deviceCount = 0, deviceIndex = 0; + + assert( hpiHostApi ); + + /* Errors not considered critical here (subsystem may report 0 devices), but report them */ + /* in debug mode. */ + PA_ASIHPI_UNLESS_( HPI_SubSysGetNumAdapters( NULL, &numAdapters), paNoError ); + + for( i=0; i < numAdapters; ++i ) + { + uint16_t inStreams, outStreams; + uint16_t version; + uint32_t serial; + uint16_t type; + uint32_t idx; + + hpiError = HPI_SubSysGetAdapter(NULL, i, &idx, &type); + if (hpiError) + continue; + + /* Try to open adapter */ + hpiError = HPI_AdapterOpen( NULL, idx ); + /* Report error and skip to next device on failure */ + if( hpiError ) + { + PA_ASIHPI_REPORT_ERROR_( hpiError ); + continue; + } + hpiError = HPI_AdapterGetInfo( NULL, idx, &outStreams, &inStreams, + &version, &serial, &type ); + /* Skip to next device on failure */ + if( hpiError ) + { + PA_ASIHPI_REPORT_ERROR_( hpiError ); + continue; + } + else + { + /* Assign default devices if available and increment device count */ + if( (baseApiInfo->defaultInputDevice == paNoDevice) && (inStreams > 0) ) + baseApiInfo->defaultInputDevice = deviceCount; + deviceCount += inStreams; + if( (baseApiInfo->defaultOutputDevice == paNoDevice) && (outStreams > 0) ) + baseApiInfo->defaultOutputDevice = deviceCount; + deviceCount += outStreams; + } + } + + /* Register any discovered devices */ + if( deviceCount > 0 ) + { + /* Memory allocation */ + PA_UNLESS_( hostApi->deviceInfos = (PaDeviceInfo**) PaUtil_GroupAllocateMemory( + hpiHostApi->allocations, sizeof(PaDeviceInfo*) * deviceCount ), + paInsufficientMemory ); + /* Allocate all device info structs in a contiguous block */ + PA_UNLESS_( hpiDeviceList = (PaAsiHpiDeviceInfo*) PaUtil_GroupAllocateMemory( + hpiHostApi->allocations, sizeof(PaAsiHpiDeviceInfo) * deviceCount ), + paInsufficientMemory ); + + /* Now query devices again for information */ + for( i=0; i < numAdapters; ++i ) + { + uint16_t inStreams, outStreams; + uint16_t version; + uint32_t serial; + uint16_t type; + uint32_t idx; + + hpiError = HPI_SubSysGetAdapter( NULL, i, &idx, &type ); + if (hpiError) + continue; + + /* Assume adapter is still open from previous round */ + hpiError = HPI_AdapterGetInfo( NULL, idx, + &outStreams, &inStreams, &version, &serial, &type ); + /* Report error and skip to next device on failure */ + if( hpiError ) + { + PA_ASIHPI_REPORT_ERROR_( hpiError ); + continue; + } + else + { + PA_DEBUG(( "Found HPI Adapter ID=%4X Idx=%d #In=%d #Out=%d S/N=%d HWver=%c%d DSPver=%03d\n", + type, idx, inStreams, outStreams, serial, + ((version>>3)&0xf)+'A', /* Hw version major */ + version&0x7, /* Hw version minor */ + ((version>>13)*100)+((version>>7)&0x3f) /* DSP code version */ + )); + } + + /* First add all input streams as devices */ + for( j=0; j < inStreams; ++j ) + { + PaAsiHpiDeviceInfo *hpiDevice = &hpiDeviceList[deviceIndex]; + PaDeviceInfo *baseDeviceInfo = &hpiDevice->baseDeviceInfo; + char srcName[72]; + char *deviceName; + + memset( hpiDevice, 0, sizeof(PaAsiHpiDeviceInfo) ); + /* Set implementation-specific device details */ + hpiDevice->adapterIndex = idx; + hpiDevice->adapterType = type; + hpiDevice->adapterVersion = version; + hpiDevice->adapterSerialNumber = serial; + hpiDevice->streamIndex = j; + hpiDevice->streamIsOutput = 0; + /* Set common PortAudio device stats */ + baseDeviceInfo->structVersion = 2; + /* Make sure name string is owned by API info structure */ + sprintf( srcName, + "Adapter %d (%4X) - Input Stream %d", i+1, type, j+1 ); + PA_UNLESS_( deviceName = (char *) PaUtil_GroupAllocateMemory( + hpiHostApi->allocations, strlen(srcName) + 1 ), paInsufficientMemory ); + strcpy( deviceName, srcName ); + baseDeviceInfo->name = deviceName; + baseDeviceInfo->hostApi = hpiHostApi->hostApiIndex; + baseDeviceInfo->maxInputChannels = HPI_MAX_CHANNELS; + baseDeviceInfo->maxOutputChannels = 0; + /* Default latency values for interactive performance */ + baseDeviceInfo->defaultLowInputLatency = 0.01; + baseDeviceInfo->defaultLowOutputLatency = -1.0; + /* Default latency values for robust non-interactive applications (eg. playing sound files) */ + baseDeviceInfo->defaultHighInputLatency = 0.2; + baseDeviceInfo->defaultHighOutputLatency = -1.0; + /* HPI interface can actually handle any sampling rate to 1 Hz accuracy, + * so this default is as good as any */ + baseDeviceInfo->defaultSampleRate = 44100; + + /* Store device in global PortAudio list */ + hostApi->deviceInfos[deviceIndex++] = (PaDeviceInfo *) hpiDevice; + } + + /* Now add all output streams as devices (I know, the repetition is painful) */ + for( j=0; j < outStreams; ++j ) + { + PaAsiHpiDeviceInfo *hpiDevice = &hpiDeviceList[deviceIndex]; + PaDeviceInfo *baseDeviceInfo = &hpiDevice->baseDeviceInfo; + char srcName[72]; + char *deviceName; + + memset( hpiDevice, 0, sizeof(PaAsiHpiDeviceInfo) ); + /* Set implementation-specific device details */ + hpiDevice->adapterIndex = idx; + hpiDevice->adapterType = type; + hpiDevice->adapterVersion = version; + hpiDevice->adapterSerialNumber = serial; + hpiDevice->streamIndex = j; + hpiDevice->streamIsOutput = 1; + /* Set common PortAudio device stats */ + baseDeviceInfo->structVersion = 2; + /* Make sure name string is owned by API info structure */ + sprintf( srcName, + "Adapter %d (%4X) - Output Stream %d", i+1, type, j+1 ); + PA_UNLESS_( deviceName = (char *) PaUtil_GroupAllocateMemory( + hpiHostApi->allocations, strlen(srcName) + 1 ), paInsufficientMemory ); + strcpy( deviceName, srcName ); + baseDeviceInfo->name = deviceName; + baseDeviceInfo->hostApi = hpiHostApi->hostApiIndex; + baseDeviceInfo->maxInputChannels = 0; + baseDeviceInfo->maxOutputChannels = HPI_MAX_CHANNELS; + /* Default latency values for interactive performance. */ + baseDeviceInfo->defaultLowInputLatency = -1.0; + baseDeviceInfo->defaultLowOutputLatency = 0.01; + /* Default latency values for robust non-interactive applications (eg. playing sound files). */ + baseDeviceInfo->defaultHighInputLatency = -1.0; + baseDeviceInfo->defaultHighOutputLatency = 0.2; + /* HPI interface can actually handle any sampling rate to 1 Hz accuracy, + * so this default is as good as any */ + baseDeviceInfo->defaultSampleRate = 44100; + + /* Store device in global PortAudio list */ + hostApi->deviceInfos[deviceIndex++] = (PaDeviceInfo *) hpiDevice; + } + } + } + + /* Finally acknowledge checked devices */ + baseApiInfo->deviceCount = deviceIndex; + +error: + return result; +} + + +/** Initialize host API implementation. + This is the only function exported beyond this file. It is called by PortAudio to initialize + the host API. It stores API info, finds and registers all devices, and sets up callback and + blocking interfaces. + + @param hostApi Pointer to host API struct + + @param hostApiIndex Index of current (HPI) host API + + @return PortAudio error code + */ +PaError PaAsiHpi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex ) +{ + PaError result = paNoError; + PaAsiHpiHostApiRepresentation *hpiHostApi = NULL; + PaHostApiInfo *baseApiInfo; + + /* Try to initialize HPI subsystem */ + if (!HPI_SubSysCreate()) + { + /* the V19 development docs say that if an implementation + * detects that it cannot be used, it should return a NULL + * interface and paNoError */ + PA_DEBUG(( "Could not open HPI interface\n" )); + + *hostApi = NULL; + return paNoError; + } + else + { + uint32_t hpiVersion; + PA_ASIHPI_UNLESS_( HPI_SubSysGetVersionEx( NULL, &hpiVersion ), paUnanticipatedHostError ); + PA_DEBUG(( "HPI interface v%d.%02d.%02d\n", + hpiVersion >> 16, (hpiVersion >> 8) & 0x0F, (hpiVersion & 0x0F) )); + } + + /* Allocate host API structure */ + PA_UNLESS_( hpiHostApi = (PaAsiHpiHostApiRepresentation*) PaUtil_AllocateMemory( + sizeof(PaAsiHpiHostApiRepresentation) ), paInsufficientMemory ); + PA_UNLESS_( hpiHostApi->allocations = PaUtil_CreateAllocationGroup(), paInsufficientMemory ); + + hpiHostApi->hostApiIndex = hostApiIndex; + + *hostApi = &hpiHostApi->baseHostApiRep; + baseApiInfo = &((*hostApi)->info); + /* Fill in common API details */ + baseApiInfo->structVersion = 1; + baseApiInfo->type = paAudioScienceHPI; + baseApiInfo->name = "AudioScience HPI"; + baseApiInfo->deviceCount = 0; + baseApiInfo->defaultInputDevice = paNoDevice; + baseApiInfo->defaultOutputDevice = paNoDevice; + + PA_ENSURE_( PaAsiHpi_BuildDeviceList( hpiHostApi ) ); + + (*hostApi)->Terminate = Terminate; + (*hostApi)->OpenStream = OpenStream; + (*hostApi)->IsFormatSupported = IsFormatSupported; + + PaUtil_InitializeStreamInterface( &hpiHostApi->callbackStreamInterface, CloseStream, StartStream, + StopStream, AbortStream, IsStreamStopped, IsStreamActive, + GetStreamTime, GetStreamCpuLoad, + PaUtil_DummyRead, PaUtil_DummyWrite, + PaUtil_DummyGetReadAvailable, PaUtil_DummyGetWriteAvailable ); + + PaUtil_InitializeStreamInterface( &hpiHostApi->blockingStreamInterface, CloseStream, StartStream, + StopStream, AbortStream, IsStreamStopped, IsStreamActive, + GetStreamTime, PaUtil_DummyGetCpuLoad, + ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable ); + + /* Store identity of main thread */ + PA_ENSURE_( PaUnixThreading_Initialize() ); + + return result; +error: + if (hpiHostApi) + PaUtil_FreeMemory( hpiHostApi ); + return result; +} + + +/** Terminate host API implementation. + This closes all HPI adapters and frees the HPI subsystem. It also frees the host API struct + memory. It should be called once for every PaAsiHpi_Initialize call. + + @param Pointer to host API struct + */ +static void Terminate( struct PaUtilHostApiRepresentation *hostApi ) +{ + PaAsiHpiHostApiRepresentation *hpiHostApi = (PaAsiHpiHostApiRepresentation*)hostApi; + int i; + PaError result = paNoError; + + if( hpiHostApi ) + { + /* Get rid of HPI-specific structures */ + uint16_t lastAdapterIndex = HPI_MAX_ADAPTERS; + /* Iterate through device list and close adapters */ + for( i=0; i < hostApi->info.deviceCount; ++i ) + { + PaAsiHpiDeviceInfo *hpiDevice = (PaAsiHpiDeviceInfo *) hostApi->deviceInfos[ i ]; + /* Close adapter only if it differs from previous one */ + if( hpiDevice->adapterIndex != lastAdapterIndex ) + { + /* Ignore errors (report only during debugging) */ + PA_ASIHPI_UNLESS_( HPI_AdapterClose( NULL, + hpiDevice->adapterIndex ), paNoError ); + lastAdapterIndex = hpiDevice->adapterIndex; + } + } + /* Finally dismantle HPI subsystem */ + HPI_SubSysFree( NULL ); + + if( hpiHostApi->allocations ) + { + PaUtil_FreeAllAllocations( hpiHostApi->allocations ); + PaUtil_DestroyAllocationGroup( hpiHostApi->allocations ); + } + + PaUtil_FreeMemory( hpiHostApi ); + } +error: + return; +} + + +/** Converts PortAudio sample format to equivalent HPI format. + + @param paFormat PortAudio sample format + + @return HPI sample format + */ +static uint16_t PaAsiHpi_PaToHpiFormat( PaSampleFormat paFormat ) +{ + /* Ignore interleaving flag */ + switch( paFormat & ~paNonInterleaved ) + { + case paFloat32: + return HPI_FORMAT_PCM32_FLOAT; + + case paInt32: + return HPI_FORMAT_PCM32_SIGNED; + + case paInt24: + return HPI_FORMAT_PCM24_SIGNED; + + case paInt16: + return HPI_FORMAT_PCM16_SIGNED; + + case paUInt8: + return HPI_FORMAT_PCM8_UNSIGNED; + + /* Default is 16-bit signed */ + case paInt8: + default: + return HPI_FORMAT_PCM16_SIGNED; + } +} + + +/** Converts HPI sample format to equivalent PortAudio format. + + @param paFormat HPI sample format + + @return PortAudio sample format + */ +static PaSampleFormat PaAsiHpi_HpiToPaFormat( uint16_t hpiFormat ) +{ + switch( hpiFormat ) + { + case HPI_FORMAT_PCM32_FLOAT: + return paFloat32; + + case HPI_FORMAT_PCM32_SIGNED: + return paInt32; + + case HPI_FORMAT_PCM24_SIGNED: + return paInt24; + + case HPI_FORMAT_PCM16_SIGNED: + return paInt16; + + case HPI_FORMAT_PCM8_UNSIGNED: + return paUInt8; + + /* Default is custom format (e.g. for HPI MP3 format) */ + default: + return paCustomFormat; + } +} + + +/** Creates HPI format struct based on PortAudio parameters. + This also does some checks to see whether the desired format is valid, and whether + the device allows it. This only checks the format of one half (input or output) of the + PortAudio stream. + + @param hostApi Pointer to host API struct + + @param parameters Pointer to stream parameter struct + + @param sampleRate Desired sample rate + + @param hpiDevice Pointer to HPI device struct + + @param hpiFormat Resulting HPI format returned here + + @return PortAudio error code (typically indicating a problem with stream format) + */ +static PaError PaAsiHpi_CreateFormat( struct PaUtilHostApiRepresentation *hostApi, + const PaStreamParameters *parameters, double sampleRate, + PaAsiHpiDeviceInfo **hpiDevice, struct hpi_format *hpiFormat ) +{ + int maxChannelCount = 0; + PaSampleFormat hostSampleFormat = 0; + hpi_err_t hpiError = 0; + + /* Unless alternate device specification is supported, reject the use of + paUseHostApiSpecificDeviceSpecification */ + if( parameters->device == paUseHostApiSpecificDeviceSpecification ) + return paInvalidDevice; + else + { + assert( parameters->device < hostApi->info.deviceCount ); + *hpiDevice = (PaAsiHpiDeviceInfo*) hostApi->deviceInfos[ parameters->device ]; + } + + /* Validate streamInfo - this implementation doesn't use custom stream info */ + if( parameters->hostApiSpecificStreamInfo ) + return paIncompatibleHostApiSpecificStreamInfo; + + /* Check that device can support channel count */ + if( (*hpiDevice)->streamIsOutput ) + { + maxChannelCount = (*hpiDevice)->baseDeviceInfo.maxOutputChannels; + } + else + { + maxChannelCount = (*hpiDevice)->baseDeviceInfo.maxInputChannels; + } + if( (maxChannelCount == 0) || (parameters->channelCount > maxChannelCount) ) + return paInvalidChannelCount; + + /* All standard sample formats are supported by the buffer adapter, + and this implementation doesn't support any custom sample formats */ + if( parameters->sampleFormat & paCustomFormat ) + return paSampleFormatNotSupported; + + /* Switch to closest HPI native format */ + hostSampleFormat = PaUtil_SelectClosestAvailableFormat(PA_ASIHPI_AVAILABLE_FORMATS_, + parameters->sampleFormat ); + /* Setup format + info objects */ + hpiError = HPI_FormatCreate( hpiFormat, (uint16_t)parameters->channelCount, + PaAsiHpi_PaToHpiFormat( hostSampleFormat ), + (uint32_t)sampleRate, 0, 0 ); + if( hpiError ) + { + PA_ASIHPI_REPORT_ERROR_( hpiError ); + switch( hpiError ) + { + case HPI_ERROR_INVALID_FORMAT: + return paSampleFormatNotSupported; + + case HPI_ERROR_INVALID_SAMPLERATE: + case HPI_ERROR_INCOMPATIBLE_SAMPLERATE: + return paInvalidSampleRate; + + case HPI_ERROR_INVALID_CHANNELS: + return paInvalidChannelCount; + } + } + + return paNoError; +} + + +/** Open HPI input stream with given format. + This attempts to open HPI input stream with desired format. If the format is not supported + or the device is unavailable, the stream is closed and a PortAudio error code is returned. + + @param hostApi Pointer to host API struct + + @param hpiDevice Pointer to HPI device struct + + @param hpiFormat Pointer to HPI format struct + + @return PortAudio error code (typically indicating a problem with stream format or device) +*/ +static PaError PaAsiHpi_OpenInput( struct PaUtilHostApiRepresentation *hostApi, + const PaAsiHpiDeviceInfo *hpiDevice, const struct hpi_format *hpiFormat, + hpi_handle_t *hpiStream ) +{ + PaAsiHpiHostApiRepresentation *hpiHostApi = (PaAsiHpiHostApiRepresentation*)hostApi; + PaError result = paNoError; + hpi_err_t hpiError = 0; + + /* Catch misplaced output devices, as they typically have 0 input channels */ + PA_UNLESS_( !hpiDevice->streamIsOutput, paInvalidChannelCount ); + /* Try to open input stream */ + PA_ASIHPI_UNLESS_( HPI_InStreamOpen( NULL, hpiDevice->adapterIndex, + hpiDevice->streamIndex, hpiStream ), paDeviceUnavailable ); + /* Set input format (checking it in the process) */ + /* Could also use HPI_InStreamQueryFormat, but this economizes the process */ + hpiError = HPI_InStreamSetFormat( NULL, *hpiStream, (struct hpi_format*)hpiFormat ); + if( hpiError ) + { + PA_ASIHPI_REPORT_ERROR_( hpiError ); + PA_ASIHPI_UNLESS_( HPI_InStreamClose( NULL, *hpiStream ), paNoError ); + switch( hpiError ) + { + case HPI_ERROR_INVALID_FORMAT: + return paSampleFormatNotSupported; + + case HPI_ERROR_INVALID_SAMPLERATE: + case HPI_ERROR_INCOMPATIBLE_SAMPLERATE: + return paInvalidSampleRate; + + case HPI_ERROR_INVALID_CHANNELS: + return paInvalidChannelCount; + + default: + /* In case anything else went wrong */ + return paInvalidDevice; + } + } + +error: + return result; +} + + +/** Open HPI output stream with given format. + This attempts to open HPI output stream with desired format. If the format is not supported + or the device is unavailable, the stream is closed and a PortAudio error code is returned. + + @param hostApi Pointer to host API struct + + @param hpiDevice Pointer to HPI device struct + + @param hpiFormat Pointer to HPI format struct + + @return PortAudio error code (typically indicating a problem with stream format or device) +*/ +static PaError PaAsiHpi_OpenOutput( struct PaUtilHostApiRepresentation *hostApi, + const PaAsiHpiDeviceInfo *hpiDevice, const struct hpi_format *hpiFormat, + hpi_handle_t *hpiStream ) +{ + PaAsiHpiHostApiRepresentation *hpiHostApi = (PaAsiHpiHostApiRepresentation*)hostApi; + PaError result = paNoError; + hpi_err_t hpiError = 0; + + /* Catch misplaced input devices, as they typically have 0 output channels */ + PA_UNLESS_( hpiDevice->streamIsOutput, paInvalidChannelCount ); + /* Try to open output stream */ + PA_ASIHPI_UNLESS_( HPI_OutStreamOpen( NULL, hpiDevice->adapterIndex, + hpiDevice->streamIndex, hpiStream ), paDeviceUnavailable ); + + /* Check output format (format is set on first write to output stream) */ + hpiError = HPI_OutStreamQueryFormat( NULL, *hpiStream, (struct hpi_format*)hpiFormat ); + if( hpiError ) + { + PA_ASIHPI_REPORT_ERROR_( hpiError ); + PA_ASIHPI_UNLESS_( HPI_OutStreamClose( NULL, *hpiStream ), paNoError ); + switch( hpiError ) + { + case HPI_ERROR_INVALID_FORMAT: + return paSampleFormatNotSupported; + + case HPI_ERROR_INVALID_SAMPLERATE: + case HPI_ERROR_INCOMPATIBLE_SAMPLERATE: + return paInvalidSampleRate; + + case HPI_ERROR_INVALID_CHANNELS: + return paInvalidChannelCount; + + default: + /* In case anything else went wrong */ + return paInvalidDevice; + } + } + +error: + return result; +} + + +/** Checks whether the desired stream formats and devices are supported + (for both input and output). + This is done by actually opening the appropriate HPI streams and closing them again. + + @param hostApi Pointer to host API struct + + @param inputParameters Pointer to stream parameter struct for input side of stream + + @param outputParameters Pointer to stream parameter struct for output side of stream + + @param sampleRate Desired sample rate + + @return PortAudio error code (paFormatIsSupported on success) + */ +static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi, + const PaStreamParameters *inputParameters, + const PaStreamParameters *outputParameters, + double sampleRate ) +{ + PaError result = paFormatIsSupported; + PaAsiHpiHostApiRepresentation *hpiHostApi = (PaAsiHpiHostApiRepresentation*)hostApi; + PaAsiHpiDeviceInfo *hpiDevice = NULL; + struct hpi_format hpiFormat; + + /* Input stream */ + if( inputParameters ) + { + hpi_handle_t hpiStream; + PA_DEBUG(( "%s: Checking input params: dev=%d, sr=%d, chans=%d, fmt=%d\n", + __FUNCTION__, inputParameters->device, (int)sampleRate, + inputParameters->channelCount, inputParameters->sampleFormat )); + /* Create and validate format */ + PA_ENSURE_( PaAsiHpi_CreateFormat( hostApi, inputParameters, sampleRate, + &hpiDevice, &hpiFormat ) ); + /* Open stream to further check format */ + PA_ENSURE_( PaAsiHpi_OpenInput( hostApi, hpiDevice, &hpiFormat, &hpiStream ) ); + /* Close stream again */ + PA_ASIHPI_UNLESS_( HPI_InStreamClose( NULL, hpiStream ), paNoError ); + } + + /* Output stream */ + if( outputParameters ) + { + hpi_handle_t hpiStream; + PA_DEBUG(( "%s: Checking output params: dev=%d, sr=%d, chans=%d, fmt=%d\n", + __FUNCTION__, outputParameters->device, (int)sampleRate, + outputParameters->channelCount, outputParameters->sampleFormat )); + /* Create and validate format */ + PA_ENSURE_( PaAsiHpi_CreateFormat( hostApi, outputParameters, sampleRate, + &hpiDevice, &hpiFormat ) ); + /* Open stream to further check format */ + PA_ENSURE_( PaAsiHpi_OpenOutput( hostApi, hpiDevice, &hpiFormat, &hpiStream ) ); + /* Close stream again */ + PA_ASIHPI_UNLESS_( HPI_OutStreamClose( NULL, hpiStream ), paNoError ); + } + +error: + return result; +} + +/* ---------------------------- Stream Interface ---------------------------- */ + +/** Obtain HPI stream information. + This obtains info such as stream state and available data/space in buffers. It also + estimates whether an underflow or overflow occurred. + + @param streamComp Pointer to stream component (input or output) to query + + @param info Pointer to stream info struct that will contain result + + @return PortAudio error code (either paNoError, paDeviceUnavailable or paUnanticipatedHostError) + */ +static PaError PaAsiHpi_GetStreamInfo( PaAsiHpiStreamComponent *streamComp, PaAsiHpiStreamInfo *info ) +{ + PaError result = paDeviceUnavailable; + uint16_t state; + uint32_t bufferSize, dataSize, frameCounter, auxDataSize, threshold; + uint32_t hwBufferSize, hwDataSize; + + assert( streamComp ); + assert( info ); + + /* First blank the stream info struct, in case something goes wrong below. + This saves the caller from initializing the struct. */ + info->state = 0; + info->bufferSize = 0; + info->dataSize = 0; + info->frameCounter = 0; + info->auxDataSize = 0; + info->totalBufferedData = 0; + info->availableFrames = 0; + info->underflow = 0; + info->overflow = 0; + + if( streamComp->hpiDevice && streamComp->hpiStream ) + { + /* Obtain detailed stream info (either input or output) */ + if( streamComp->hpiDevice->streamIsOutput ) + { + PA_ASIHPI_UNLESS_( HPI_OutStreamGetInfoEx( NULL, + streamComp->hpiStream, + &state, &bufferSize, &dataSize, &frameCounter, + &auxDataSize ), paUnanticipatedHostError ); + } + else + { + PA_ASIHPI_UNLESS_( HPI_InStreamGetInfoEx( NULL, + streamComp->hpiStream, + &state, &bufferSize, &dataSize, &frameCounter, + &auxDataSize ), paUnanticipatedHostError ); + } + /* Load stream info */ + info->state = state; + info->bufferSize = bufferSize; + info->dataSize = dataSize; + info->frameCounter = frameCounter; + info->auxDataSize = auxDataSize; + /* Determine total buffered data */ + info->totalBufferedData = dataSize; + if( streamComp->hostBufferSize > 0 ) + info->totalBufferedData += auxDataSize; + info->totalBufferedData /= streamComp->bytesPerFrame; + /* Determine immediately available frames */ + info->availableFrames = streamComp->hpiDevice->streamIsOutput ? + bufferSize - dataSize : dataSize; + info->availableFrames /= streamComp->bytesPerFrame; + /* Minimum space/data required in buffers */ + threshold = PA_MIN( streamComp->tempBufferSize, + streamComp->bytesPerFrame * PA_ASIHPI_MIN_FRAMES_ ); + /* Obtain hardware buffer stats first, to simplify things */ + hwBufferSize = streamComp->hardwareBufferSize; + hwDataSize = streamComp->hostBufferSize > 0 ? auxDataSize : dataSize; + /* Underflow is a bit tricky */ + info->underflow = streamComp->hpiDevice->streamIsOutput ? + /* Stream seems to start in drained state sometimes, so ignore initial underflow */ + (frameCounter > 0) && ( (state == HPI_STATE_DRAINED) || (hwDataSize == 0) ) : + /* Input streams check the first-level (host) buffer for underflow */ + (state != HPI_STATE_STOPPED) && (dataSize < threshold); + /* Check for overflow in second-level (hardware) buffer for both input and output */ + info->overflow = (state != HPI_STATE_STOPPED) && (hwBufferSize - hwDataSize < threshold); + + return paNoError; + } + +error: + return result; +} + + +/** Display stream component information for debugging purposes. + + @param streamComp Pointer to stream component (input or output) to query + + @param stream Pointer to stream struct which contains the component above + */ +static void PaAsiHpi_StreamComponentDump( PaAsiHpiStreamComponent *streamComp, + PaAsiHpiStream *stream ) +{ + PaAsiHpiStreamInfo streamInfo; + + assert( streamComp ); + assert( stream ); + + /* Name of soundcard/device used by component */ + PA_DEBUG(( "device: %s\n", streamComp->hpiDevice->baseDeviceInfo.name )); + /* Unfortunately some overlap between input and output here */ + if( streamComp->hpiDevice->streamIsOutput ) + { + /* Settings on the user side (as experienced by user callback) */ + PA_DEBUG(( "user: %d-bit, %d ", + 8*stream->bufferProcessor.bytesPerUserOutputSample, + stream->bufferProcessor.outputChannelCount)); + if( stream->bufferProcessor.userOutputIsInterleaved ) + { + PA_DEBUG(( "interleaved channels, " )); + } + else + { + PA_DEBUG(( "non-interleaved channels, " )); + } + PA_DEBUG(( "%d frames/buffer, latency = %5.1f ms\n", + stream->bufferProcessor.framesPerUserBuffer, + 1000*stream->baseStreamRep.streamInfo.outputLatency )); + /* Settings on the host side (internal to PortAudio host API) */ + PA_DEBUG(( "host: %d-bit, %d interleaved channels, %d frames/buffer ", + 8*stream->bufferProcessor.bytesPerHostOutputSample, + stream->bufferProcessor.outputChannelCount, + stream->bufferProcessor.framesPerHostBuffer )); + } + else + { + /* Settings on the user side (as experienced by user callback) */ + PA_DEBUG(( "user: %d-bit, %d ", + 8*stream->bufferProcessor.bytesPerUserInputSample, + stream->bufferProcessor.inputChannelCount)); + if( stream->bufferProcessor.userInputIsInterleaved ) + { + PA_DEBUG(( "interleaved channels, " )); + } + else + { + PA_DEBUG(( "non-interleaved channels, " )); + } + PA_DEBUG(( "%d frames/buffer, latency = %5.1f ms\n", + stream->bufferProcessor.framesPerUserBuffer, + 1000*stream->baseStreamRep.streamInfo.inputLatency )); + /* Settings on the host side (internal to PortAudio host API) */ + PA_DEBUG(( "host: %d-bit, %d interleaved channels, %d frames/buffer ", + 8*stream->bufferProcessor.bytesPerHostInputSample, + stream->bufferProcessor.inputChannelCount, + stream->bufferProcessor.framesPerHostBuffer )); + } + switch( stream->bufferProcessor.hostBufferSizeMode ) + { + case paUtilFixedHostBufferSize: + PA_DEBUG(( "[fixed] " )); + break; + case paUtilBoundedHostBufferSize: + PA_DEBUG(( "[bounded] " )); + break; + case paUtilUnknownHostBufferSize: + PA_DEBUG(( "[unknown] " )); + break; + case paUtilVariableHostBufferSizePartialUsageAllowed: + PA_DEBUG(( "[variable] " )); + break; + } + PA_DEBUG(( "(%d max)\n", streamComp->tempBufferSize / streamComp->bytesPerFrame )); + /* HPI hardware settings */ + PA_DEBUG(( "HPI: adapter %d stream %d, %d-bit, %d-channel, %d Hz\n", + streamComp->hpiDevice->adapterIndex, streamComp->hpiDevice->streamIndex, + 8 * streamComp->bytesPerFrame / streamComp->hpiFormat.wChannels, + streamComp->hpiFormat.wChannels, + streamComp->hpiFormat.dwSampleRate )); + /* Stream state and buffer levels */ + PA_DEBUG(( "HPI: " )); + PaAsiHpi_GetStreamInfo( streamComp, &streamInfo ); + switch( streamInfo.state ) + { + case HPI_STATE_STOPPED: + PA_DEBUG(( "[STOPPED] " )); + break; + case HPI_STATE_PLAYING: + PA_DEBUG(( "[PLAYING] " )); + break; + case HPI_STATE_RECORDING: + PA_DEBUG(( "[RECORDING] " )); + break; + case HPI_STATE_DRAINED: + PA_DEBUG(( "[DRAINED] " )); + break; + default: + PA_DEBUG(( "[unknown state] " )); + break; + } + if( streamComp->hostBufferSize ) + { + PA_DEBUG(( "host = %d/%d B, ", streamInfo.dataSize, streamComp->hostBufferSize )); + PA_DEBUG(( "hw = %d/%d (%d) B, ", streamInfo.auxDataSize, + streamComp->hardwareBufferSize, streamComp->outputBufferCap )); + } + else + { + PA_DEBUG(( "hw = %d/%d B, ", streamInfo.dataSize, streamComp->hardwareBufferSize )); + } + PA_DEBUG(( "count = %d", streamInfo.frameCounter )); + if( streamInfo.overflow ) + { + PA_DEBUG(( " [overflow]" )); + } + else if( streamInfo.underflow ) + { + PA_DEBUG(( " [underflow]" )); + } + PA_DEBUG(( "\n" )); +} + + +/** Display stream information for debugging purposes. + + @param stream Pointer to stream to query + */ +static void PaAsiHpi_StreamDump( PaAsiHpiStream *stream ) +{ + assert( stream ); + + PA_DEBUG(( "\n------------------------- STREAM INFO FOR %p ---------------------------\n", stream )); + /* General stream info (input+output) */ + if( stream->baseStreamRep.streamCallback ) + { + PA_DEBUG(( "[callback] " )); + } + else + { + PA_DEBUG(( "[blocking] " )); + } + PA_DEBUG(( "sr=%d Hz, poll=%d ms, max %d frames/buf ", + (int)stream->baseStreamRep.streamInfo.sampleRate, + stream->pollingInterval, stream->maxFramesPerHostBuffer )); + switch( stream->state ) + { + case paAsiHpiStoppedState: + PA_DEBUG(( "[stopped]\n" )); + break; + case paAsiHpiActiveState: + PA_DEBUG(( "[active]\n" )); + break; + case paAsiHpiCallbackFinishedState: + PA_DEBUG(( "[cb fin]\n" )); + break; + default: + PA_DEBUG(( "[unknown state]\n" )); + break; + } + if( stream->callbackMode ) + { + PA_DEBUG(( "cb info: thread=%p, cbAbort=%d, cbFinished=%d\n", + stream->thread.thread, stream->callbackAbort, stream->callbackFinished )); + } + + PA_DEBUG(( "----------------------------------- Input ------------------------------------\n" )); + if( stream->input ) + { + PaAsiHpi_StreamComponentDump( stream->input, stream ); + } + else + { + PA_DEBUG(( "*none*\n" )); + } + + PA_DEBUG(( "----------------------------------- Output ------------------------------------\n" )); + if( stream->output ) + { + PaAsiHpi_StreamComponentDump( stream->output, stream ); + } + else + { + PA_DEBUG(( "*none*\n" )); + } + PA_DEBUG(( "-------------------------------------------------------------------------------\n\n" )); + +} + + +/** Determine buffer sizes and allocate appropriate stream buffers. + This attempts to allocate a BBM (host) buffer for the HPI stream component (either input + or output, as both have similar buffer needs). Not all AudioScience adapters support BBM, + in which case the hardware buffer has to suffice. The size of the HPI host buffer is chosen + as a multiple of framesPerPaHostBuffer, and also influenced by the suggested latency and the + estimated minimum polling interval. The HPI host and hardware buffer sizes are stored, and an + appropriate cap for the hardware buffer is also calculated. Finally, the temporary stream + buffer which serves as the PortAudio host buffer for this implementation is allocated. + This buffer contains an integer number of user buffers, to simplify buffer adaption in the + buffer processor. The function returns paBufferTooBig if the HPI interface cannot allocate + an HPI host buffer of the desired size. + + @param streamComp Pointer to stream component struct + + @param pollingInterval Polling interval for stream, in milliseconds + + @param framesPerPaHostBuffer Size of PortAudio host buffer, in frames + + @param suggestedLatency Suggested latency for stream component, in seconds + + @return PortAudio error code (possibly paBufferTooBig or paInsufficientMemory) + */ +static PaError PaAsiHpi_SetupBuffers( PaAsiHpiStreamComponent *streamComp, uint32_t pollingInterval, + unsigned long framesPerPaHostBuffer, PaTime suggestedLatency ) +{ + PaError result = paNoError; + PaAsiHpiStreamInfo streamInfo; + unsigned long hpiBufferSize = 0, paHostBufferSize = 0; + + assert( streamComp ); + assert( streamComp->hpiDevice ); + + /* Obtain size of hardware buffer of HPI stream, since we will be activating BBM shortly + and afterwards the buffer size will refer to the BBM (host-side) buffer. + This is necessary to enable reliable detection of xruns. */ + PA_ENSURE_( PaAsiHpi_GetStreamInfo( streamComp, &streamInfo ) ); + streamComp->hardwareBufferSize = streamInfo.bufferSize; + hpiBufferSize = streamInfo.bufferSize; + + /* Check if BBM (background bus mastering) is to be enabled */ + if( PA_ASIHPI_USE_BBM_ ) + { + uint32_t bbmBufferSize = 0, preLatencyBufferSize = 0; + hpi_err_t hpiError = 0; + PaTime pollingOverhead; + + /* Check overhead of Pa_Sleep() call (minimum sleep duration in ms -> OS dependent) */ + pollingOverhead = PaUtil_GetTime(); + Pa_Sleep( 0 ); + pollingOverhead = 1000*(PaUtil_GetTime() - pollingOverhead); + PA_DEBUG(( "polling overhead = %f ms (length of 0-second sleep)\n", pollingOverhead )); + /* Obtain minimum recommended size for host buffer (in bytes) */ + PA_ASIHPI_UNLESS_( HPI_StreamEstimateBufferSize( &streamComp->hpiFormat, + pollingInterval + (uint32_t)ceil( pollingOverhead ), + &bbmBufferSize ), paUnanticipatedHostError ); + /* BBM places more stringent requirements on buffer size (see description */ + /* of HPI_StreamEstimateBufferSize in HPI API document) */ + bbmBufferSize *= 3; + /* Make sure the BBM buffer contains multiple PA host buffers */ + if( bbmBufferSize < 3 * streamComp->bytesPerFrame * framesPerPaHostBuffer ) + bbmBufferSize = 3 * streamComp->bytesPerFrame * framesPerPaHostBuffer; + /* Try to honor latency suggested by user by growing buffer (no decrease possible) */ + if( suggestedLatency > 0.0 ) + { + PaTime bufferDuration = ((PaTime)bbmBufferSize) / streamComp->bytesPerFrame + / streamComp->hpiFormat.dwSampleRate; + /* Don't decrease buffer */ + if( bufferDuration < suggestedLatency ) + { + /* Save old buffer size, to be retried if new size proves too big */ + preLatencyBufferSize = bbmBufferSize; + bbmBufferSize = (uint32_t)ceil( suggestedLatency * streamComp->bytesPerFrame + * streamComp->hpiFormat.dwSampleRate ); + } + } + /* Choose closest memory block boundary (HPI API document states that + "a buffer size of Nx4096 - 20 makes the best use of memory" + (under the entry for HPI_StreamEstimateBufferSize)) */ + bbmBufferSize = ((uint32_t)ceil((bbmBufferSize + 20)/4096.0))*4096 - 20; + streamComp->hostBufferSize = bbmBufferSize; + /* Allocate BBM host buffer (this enables bus mastering transfers in background) */ + if( streamComp->hpiDevice->streamIsOutput ) + hpiError = HPI_OutStreamHostBufferAllocate( NULL, + streamComp->hpiStream, + bbmBufferSize ); + else + hpiError = HPI_InStreamHostBufferAllocate( NULL, + streamComp->hpiStream, + bbmBufferSize ); + if( hpiError ) + { + /* Indicate that BBM is disabled */ + streamComp->hostBufferSize = 0; + /* Retry with smaller buffer size (transfers will still work, but not via BBM) */ + if( hpiError == HPI_ERROR_INVALID_DATASIZE ) + { + /* Retry BBM allocation with smaller size if requested latency proved too big */ + if( preLatencyBufferSize > 0 ) + { + PA_DEBUG(( "Retrying BBM allocation with smaller size (%d vs. %d bytes)\n", + preLatencyBufferSize, bbmBufferSize )); + bbmBufferSize = preLatencyBufferSize; + if( streamComp->hpiDevice->streamIsOutput ) + hpiError = HPI_OutStreamHostBufferAllocate( NULL, + streamComp->hpiStream, + bbmBufferSize ); + else + hpiError = HPI_InStreamHostBufferAllocate( NULL, + streamComp->hpiStream, + bbmBufferSize ); + /* Another round of error checking */ + if( hpiError ) + { + PA_ASIHPI_REPORT_ERROR_( hpiError ); + /* No escapes this time */ + if( hpiError == HPI_ERROR_INVALID_DATASIZE ) + { + result = paBufferTooBig; + goto error; + } + else if( hpiError != HPI_ERROR_INVALID_OPERATION ) + { + result = paUnanticipatedHostError; + goto error; + } + } + else + { + streamComp->hostBufferSize = bbmBufferSize; + hpiBufferSize = bbmBufferSize; + } + } + else + { + result = paBufferTooBig; + goto error; + } + } + /* If BBM not supported, foreground transfers will be used, but not a show-stopper */ + /* Anything else is an error */ + else if (( hpiError != HPI_ERROR_INVALID_OPERATION ) && + ( hpiError != HPI_ERROR_INVALID_FUNC )) + { + PA_ASIHPI_REPORT_ERROR_( hpiError ); + result = paUnanticipatedHostError; + goto error; + } + } + else + { + hpiBufferSize = bbmBufferSize; + } + } + + /* Final check of buffer size */ + paHostBufferSize = streamComp->bytesPerFrame * framesPerPaHostBuffer; + if( hpiBufferSize < 3*paHostBufferSize ) + { + result = paBufferTooBig; + goto error; + } + /* Set cap on output buffer size, based on latency suggestions */ + if( streamComp->hpiDevice->streamIsOutput ) + { + PaTime latency = suggestedLatency > 0.0 ? suggestedLatency : + streamComp->hpiDevice->baseDeviceInfo.defaultHighOutputLatency; + streamComp->outputBufferCap = + (uint32_t)ceil( latency * streamComp->bytesPerFrame * streamComp->hpiFormat.dwSampleRate ); + /* The cap should not be too small, to prevent underflow */ + if( streamComp->outputBufferCap < 4*paHostBufferSize ) + streamComp->outputBufferCap = 4*paHostBufferSize; + } + else + { + streamComp->outputBufferCap = 0; + } + /* Temp buffer size should be multiple of PA host buffer size (or 1x, if using fixed blocks) */ + streamComp->tempBufferSize = paHostBufferSize; + /* Allocate temp buffer */ + PA_UNLESS_( streamComp->tempBuffer = (uint8_t *)PaUtil_AllocateMemory( streamComp->tempBufferSize ), + paInsufficientMemory ); +error: + return result; +} + + +/** Opens PortAudio stream. + This determines a suitable value for framesPerBuffer, if the user didn't specify it, + based on the suggested latency. It then opens each requested stream direction with the + appropriate stream format, and allocates the required stream buffers. It sets up the + various PortAudio structures dealing with streams, and estimates the stream latency. + + See pa_hostapi.h for a list of validity guarantees made about OpenStream parameters. + + @param hostApi Pointer to host API struct + + @param s List of open streams, where successfully opened stream will go + + @param inputParameters Pointer to stream parameter struct for input side of stream + + @param outputParameters Pointer to stream parameter struct for output side of stream + + @param sampleRate Desired sample rate + + @param framesPerBuffer Desired number of frames per buffer passed to user callback + (or chunk size for blocking stream) + + @param streamFlags Stream flags + + @param streamCallback Pointer to user callback function (zero for blocking interface) + + @param userData Pointer to user data that will be passed to callback function along with data + + @return PortAudio error code +*/ +static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, + PaStream **s, + const PaStreamParameters *inputParameters, + const PaStreamParameters *outputParameters, + double sampleRate, + unsigned long framesPerBuffer, + PaStreamFlags streamFlags, + PaStreamCallback *streamCallback, + void *userData ) +{ + PaError result = paNoError; + PaAsiHpiHostApiRepresentation *hpiHostApi = (PaAsiHpiHostApiRepresentation*)hostApi; + PaAsiHpiStream *stream = NULL; + unsigned long framesPerHostBuffer = framesPerBuffer; + int inputChannelCount = 0, outputChannelCount = 0; + PaSampleFormat inputSampleFormat = 0, outputSampleFormat = 0; + PaSampleFormat hostInputSampleFormat = 0, hostOutputSampleFormat = 0; + PaTime maxSuggestedLatency = 0.0; + + /* Validate platform-specific flags -> none expected for HPI */ + if( (streamFlags & paPlatformSpecificFlags) != 0 ) + return paInvalidFlag; /* unexpected platform-specific flag */ + + /* Create blank stream structure */ + PA_UNLESS_( stream = (PaAsiHpiStream *)PaUtil_AllocateMemory( sizeof(PaAsiHpiStream) ), + paInsufficientMemory ); + memset( stream, 0, sizeof(PaAsiHpiStream) ); + + /* If the number of frames per buffer is unspecified, we have to come up with one. */ + if( framesPerHostBuffer == paFramesPerBufferUnspecified ) + { + if( inputParameters ) + maxSuggestedLatency = inputParameters->suggestedLatency; + if( outputParameters && (outputParameters->suggestedLatency > maxSuggestedLatency) ) + maxSuggestedLatency = outputParameters->suggestedLatency; + /* Use suggested latency if available */ + if( maxSuggestedLatency > 0.0 ) + framesPerHostBuffer = (unsigned long)ceil( maxSuggestedLatency * sampleRate ); + else + /* AudioScience cards like BIG buffers by default */ + framesPerHostBuffer = 4096; + } + /* Lower bounds on host buffer size, due to polling and HPI constraints */ + if( 1000.0*framesPerHostBuffer/sampleRate < PA_ASIHPI_MIN_POLLING_INTERVAL_ ) + framesPerHostBuffer = (unsigned long)ceil( sampleRate * PA_ASIHPI_MIN_POLLING_INTERVAL_ / 1000.0 ); + /* if( framesPerHostBuffer < PA_ASIHPI_MIN_FRAMES_ ) + framesPerHostBuffer = PA_ASIHPI_MIN_FRAMES_; */ + /* Efficient if host buffer size is integer multiple of user buffer size */ + if( framesPerBuffer > 0 ) + framesPerHostBuffer = (unsigned long)ceil( (double)framesPerHostBuffer / framesPerBuffer ) * framesPerBuffer; + /* Buffer should always be a multiple of 4 bytes to facilitate 32-bit PCI transfers. + By keeping the frames a multiple of 4, this is ensured even for 8-bit mono sound. */ + framesPerHostBuffer = (framesPerHostBuffer / 4) * 4; + /* Polling is based on time length (in milliseconds) of user-requested block size */ + stream->pollingInterval = (uint32_t)ceil( 1000.0*framesPerHostBuffer/sampleRate ); + assert( framesPerHostBuffer > 0 ); + + /* Open underlying streams, check formats and allocate buffers */ + if( inputParameters ) + { + /* Create blank stream component structure */ + PA_UNLESS_( stream->input = (PaAsiHpiStreamComponent *)PaUtil_AllocateMemory( sizeof(PaAsiHpiStreamComponent) ), + paInsufficientMemory ); + memset( stream->input, 0, sizeof(PaAsiHpiStreamComponent) ); + /* Create/validate format */ + PA_ENSURE_( PaAsiHpi_CreateFormat( hostApi, inputParameters, sampleRate, + &stream->input->hpiDevice, &stream->input->hpiFormat ) ); + /* Open stream and set format */ + PA_ENSURE_( PaAsiHpi_OpenInput( hostApi, stream->input->hpiDevice, &stream->input->hpiFormat, + &stream->input->hpiStream ) ); + inputChannelCount = inputParameters->channelCount; + inputSampleFormat = inputParameters->sampleFormat; + hostInputSampleFormat = PaAsiHpi_HpiToPaFormat( stream->input->hpiFormat.wFormat ); + stream->input->bytesPerFrame = inputChannelCount * Pa_GetSampleSize( hostInputSampleFormat ); + assert( stream->input->bytesPerFrame > 0 ); + /* Allocate host and temp buffers of appropriate size */ + PA_ENSURE_( PaAsiHpi_SetupBuffers( stream->input, stream->pollingInterval, + framesPerHostBuffer, inputParameters->suggestedLatency ) ); + } + if( outputParameters ) + { + /* Create blank stream component structure */ + PA_UNLESS_( stream->output = (PaAsiHpiStreamComponent *)PaUtil_AllocateMemory( sizeof(PaAsiHpiStreamComponent) ), + paInsufficientMemory ); + memset( stream->output, 0, sizeof(PaAsiHpiStreamComponent) ); + /* Create/validate format */ + PA_ENSURE_( PaAsiHpi_CreateFormat( hostApi, outputParameters, sampleRate, + &stream->output->hpiDevice, &stream->output->hpiFormat ) ); + /* Open stream and check format */ + PA_ENSURE_( PaAsiHpi_OpenOutput( hostApi, stream->output->hpiDevice, + &stream->output->hpiFormat, + &stream->output->hpiStream ) ); + outputChannelCount = outputParameters->channelCount; + outputSampleFormat = outputParameters->sampleFormat; + hostOutputSampleFormat = PaAsiHpi_HpiToPaFormat( stream->output->hpiFormat.wFormat ); + stream->output->bytesPerFrame = outputChannelCount * Pa_GetSampleSize( hostOutputSampleFormat ); + /* Allocate host and temp buffers of appropriate size */ + PA_ENSURE_( PaAsiHpi_SetupBuffers( stream->output, stream->pollingInterval, + framesPerHostBuffer, outputParameters->suggestedLatency ) ); + } + + /* Determine maximum frames per host buffer (least common denominator of input/output) */ + if( inputParameters && outputParameters ) + { + stream->maxFramesPerHostBuffer = PA_MIN( stream->input->tempBufferSize / stream->input->bytesPerFrame, + stream->output->tempBufferSize / stream->output->bytesPerFrame ); + } + else + { + stream->maxFramesPerHostBuffer = inputParameters ? stream->input->tempBufferSize / stream->input->bytesPerFrame + : stream->output->tempBufferSize / stream->output->bytesPerFrame; + } + assert( stream->maxFramesPerHostBuffer > 0 ); + /* Initialize various other stream parameters */ + stream->neverDropInput = streamFlags & paNeverDropInput; + stream->state = paAsiHpiStoppedState; + + /* Initialize either callback or blocking interface */ + if( streamCallback ) + { + PaUtil_InitializeStreamRepresentation( &stream->baseStreamRep, + &hpiHostApi->callbackStreamInterface, + streamCallback, userData ); + stream->callbackMode = 1; + } + else + { + PaUtil_InitializeStreamRepresentation( &stream->baseStreamRep, + &hpiHostApi->blockingStreamInterface, + streamCallback, userData ); + /* Pre-allocate non-interleaved user buffer pointers for blocking interface */ + PA_UNLESS_( stream->blockingUserBufferCopy = + PaUtil_AllocateMemory( sizeof(void *) * PA_MAX( inputChannelCount, outputChannelCount ) ), + paInsufficientMemory ); + stream->callbackMode = 0; + } + PaUtil_InitializeCpuLoadMeasurer( &stream->cpuLoadMeasurer, sampleRate ); + + /* Following pa_linux_alsa's lead, we operate with fixed host buffer size by default, */ + /* since other modes will invariably lead to block adaption (maybe Bounded better?) */ + PA_ENSURE_( PaUtil_InitializeBufferProcessor( &stream->bufferProcessor, + inputChannelCount, inputSampleFormat, hostInputSampleFormat, + outputChannelCount, outputSampleFormat, hostOutputSampleFormat, + sampleRate, streamFlags, + framesPerBuffer, framesPerHostBuffer, paUtilFixedHostBufferSize, + streamCallback, userData ) ); + + stream->baseStreamRep.streamInfo.structVersion = 1; + stream->baseStreamRep.streamInfo.sampleRate = sampleRate; + /* Determine input latency from buffer processor and buffer sizes */ + if( stream->input ) + { + PaTime bufferDuration = ( stream->input->hostBufferSize + stream->input->hardwareBufferSize ) + / sampleRate / stream->input->bytesPerFrame; + stream->baseStreamRep.streamInfo.inputLatency = + bufferDuration + + ((PaTime)PaUtil_GetBufferProcessorInputLatencyFrames( &stream->bufferProcessor ) - + stream->maxFramesPerHostBuffer) / sampleRate; + assert( stream->baseStreamRep.streamInfo.inputLatency > 0.0 ); + } + /* Determine output latency from buffer processor and buffer sizes */ + if( stream->output ) + { + PaTime bufferDuration = ( stream->output->hostBufferSize + stream->output->hardwareBufferSize ) + / sampleRate / stream->output->bytesPerFrame; + /* Take buffer size cap into account (see PaAsiHpi_WaitForFrames) */ + if( !stream->input && (stream->output->outputBufferCap > 0) ) + { + bufferDuration = PA_MIN( bufferDuration, + stream->output->outputBufferCap / sampleRate / stream->output->bytesPerFrame ); + } + stream->baseStreamRep.streamInfo.outputLatency = + bufferDuration + + ((PaTime)PaUtil_GetBufferProcessorOutputLatencyFrames( &stream->bufferProcessor ) - + stream->maxFramesPerHostBuffer) / sampleRate; + assert( stream->baseStreamRep.streamInfo.outputLatency > 0.0 ); + } + + /* Report stream info, for debugging purposes */ + PaAsiHpi_StreamDump( stream ); + + /* Save initialized stream to PA stream list */ + *s = (PaStream*)stream; + return result; + +error: + CloseStream( (PaStream*)stream ); + return result; +} + + +/** Close PortAudio stream. + When CloseStream() is called, the multi-api layer ensures that the stream has already + been stopped or aborted. This closes the underlying HPI streams and deallocates stream + buffers and structs. + + @param s Pointer to PortAudio stream + + @return PortAudio error code +*/ +static PaError CloseStream( PaStream *s ) +{ + PaError result = paNoError; + PaAsiHpiStream *stream = (PaAsiHpiStream*)s; + + /* If stream is already gone, all is well */ + if( stream == NULL ) + return paNoError; + + /* Generic stream cleanup */ + PaUtil_TerminateBufferProcessor( &stream->bufferProcessor ); + PaUtil_TerminateStreamRepresentation( &stream->baseStreamRep ); + + /* Implementation-specific details - close internal streams */ + if( stream->input ) + { + /* Close HPI stream (freeing BBM host buffer in the process, if used) */ + if( stream->input->hpiStream ) + { + PA_ASIHPI_UNLESS_( HPI_InStreamClose( NULL, + stream->input->hpiStream ), paUnanticipatedHostError ); + } + /* Free temp buffer and stream component */ + PaUtil_FreeMemory( stream->input->tempBuffer ); + PaUtil_FreeMemory( stream->input ); + } + if( stream->output ) + { + /* Close HPI stream (freeing BBM host buffer in the process, if used) */ + if( stream->output->hpiStream ) + { + PA_ASIHPI_UNLESS_( HPI_OutStreamClose( NULL, + stream->output->hpiStream ), paUnanticipatedHostError ); + } + /* Free temp buffer and stream component */ + PaUtil_FreeMemory( stream->output->tempBuffer ); + PaUtil_FreeMemory( stream->output ); + } + + PaUtil_FreeMemory( stream->blockingUserBufferCopy ); + PaUtil_FreeMemory( stream ); + +error: + return result; +} + + +/** Prime HPI output stream with silence. + This resets the output stream and uses PortAudio helper routines to fill the + temp buffer with silence. It then writes two host buffers to the stream. This is supposed + to be called before the stream is started. It has no effect on input-only streams. + + @param stream Pointer to stream struct + + @return PortAudio error code + */ +static PaError PaAsiHpi_PrimeOutputWithSilence( PaAsiHpiStream *stream ) +{ + PaError result = paNoError; + PaAsiHpiStreamComponent *out; + PaUtilZeroer *zeroer; + PaSampleFormat outputFormat; + assert( stream ); + out = stream->output; + /* Only continue if stream has output channels */ + if( !out ) + return result; + assert( out->tempBuffer ); + + /* Clear all existing data in hardware playback buffer */ + PA_ASIHPI_UNLESS_( HPI_OutStreamReset( NULL, + out->hpiStream ), paUnanticipatedHostError ); + /* Fill temp buffer with silence */ + outputFormat = PaAsiHpi_HpiToPaFormat( out->hpiFormat.wFormat ); + zeroer = PaUtil_SelectZeroer( outputFormat ); + zeroer(out->tempBuffer, 1, out->tempBufferSize / Pa_GetSampleSize(outputFormat) ); + /* Write temp buffer to hardware fifo twice, to get started */ + PA_ASIHPI_UNLESS_( HPI_OutStreamWriteBuf( NULL, out->hpiStream, + out->tempBuffer, out->tempBufferSize, &out->hpiFormat), + paUnanticipatedHostError ); + PA_ASIHPI_UNLESS_( HPI_OutStreamWriteBuf( NULL, out->hpiStream, + out->tempBuffer, out->tempBufferSize, &out->hpiFormat), + paUnanticipatedHostError ); +error: + return result; +} + + +/** Start HPI streams (both input + output). + This starts all HPI streams in the PortAudio stream. Output streams are first primed with + silence, if required. After this call the PA stream is in the Active state. + + @todo Implement priming via the user callback + + @param stream Pointer to stream struct + + @param outputPrimed True if output is already primed (if false, silence will be loaded before starting) + + @return PortAudio error code + */ +static PaError PaAsiHpi_StartStream( PaAsiHpiStream *stream, int outputPrimed ) +{ + PaError result = paNoError; + + if( stream->input ) + { + PA_ASIHPI_UNLESS_( HPI_InStreamStart( NULL, + stream->input->hpiStream ), paUnanticipatedHostError ); + } + if( stream->output ) + { + if( !outputPrimed ) + { + /* Buffer isn't primed, so load stream with silence */ + PA_ENSURE_( PaAsiHpi_PrimeOutputWithSilence( stream ) ); + } + PA_ASIHPI_UNLESS_( HPI_OutStreamStart( NULL, + stream->output->hpiStream ), paUnanticipatedHostError ); + } + stream->state = paAsiHpiActiveState; + stream->callbackFinished = 0; + + /* Report stream info for debugging purposes */ + /* PaAsiHpi_StreamDump( stream ); */ + +error: + return result; +} + + +/** Start PortAudio stream. + If the stream has a callback interface, this starts a helper thread to feed the user callback. + The thread will then take care of starting the HPI streams, and this function will block + until the streams actually start. In the case of a blocking interface, the HPI streams + are simply started. + + @param s Pointer to PortAudio stream + + @return PortAudio error code +*/ +static PaError StartStream( PaStream *s ) +{ + PaError result = paNoError; + PaAsiHpiStream *stream = (PaAsiHpiStream*)s; + + assert( stream ); + + /* Ready the processor */ + PaUtil_ResetBufferProcessor( &stream->bufferProcessor ); + + if( stream->callbackMode ) + { + /* Create and start callback engine thread */ + /* Also waits 1 second for stream to be started by engine thread (otherwise aborts) */ + PA_ENSURE_( PaUnixThread_New( &stream->thread, &CallbackThreadFunc, stream, 1., 0 /*rtSched*/ ) ); + } + else + { + PA_ENSURE_( PaAsiHpi_StartStream( stream, 0 ) ); + } + +error: + return result; +} + + +/** Stop HPI streams (input + output), either softly or abruptly. + If abort is false, the function blocks until the output stream is drained, otherwise it + stops immediately and discards data in the stream hardware buffers. + + This function is safe to call from the callback engine thread as well as the main thread. + + @param stream Pointer to stream struct + + @param abort True if samples in output buffer should be discarded (otherwise blocks until stream is done) + + @return PortAudio error code + + */ +static PaError PaAsiHpi_StopStream( PaAsiHpiStream *stream, int abort ) +{ + PaError result = paNoError; + + assert( stream ); + + /* Input channels */ + if( stream->input ) + { + PA_ASIHPI_UNLESS_( HPI_InStreamReset( NULL, + stream->input->hpiStream ), paUnanticipatedHostError ); + } + /* Output channels */ + if( stream->output ) + { + if( !abort ) + { + /* Wait until HPI output stream is drained */ + while( 1 ) + { + PaAsiHpiStreamInfo streamInfo; + PaTime timeLeft; + + /* Obtain number of samples waiting to be played */ + PA_ENSURE_( PaAsiHpi_GetStreamInfo( stream->output, &streamInfo ) ); + /* Check if stream is drained */ + if( (streamInfo.state != HPI_STATE_PLAYING) && + (streamInfo.dataSize < stream->output->bytesPerFrame * PA_ASIHPI_MIN_FRAMES_) ) + break; + /* Sleep amount of time represented by remaining samples */ + timeLeft = 1000.0 * streamInfo.dataSize / stream->output->bytesPerFrame + / stream->baseStreamRep.streamInfo.sampleRate; + Pa_Sleep( (long)ceil( timeLeft ) ); + } + } + PA_ASIHPI_UNLESS_( HPI_OutStreamReset( NULL, + stream->output->hpiStream ), paUnanticipatedHostError ); + } + + /* Report stream info for debugging purposes */ + /* PaAsiHpi_StreamDump( stream ); */ + +error: + return result; +} + + +/** Stop or abort PortAudio stream. + + This function is used to explicitly stop the PortAudio stream (via StopStream/AbortStream), + as opposed to the situation when the callback finishes with a result other than paContinue. + If a stream is in callback mode we will have to inspect whether the background thread has + finished, or we will have to take it out. In either case we join the thread before returning. + In blocking mode, we simply tell HPI to stop abruptly (abort) or finish buffers (drain). + The PortAudio stream will be in the Stopped state after a call to this function. + + Don't call this from the callback engine thread! + + @param stream Pointer to stream struct + + @param abort True if samples in output buffer should be discarded (otherwise blocks until stream is done) + + @return PortAudio error code +*/ +static PaError PaAsiHpi_ExplicitStop( PaAsiHpiStream *stream, int abort ) +{ + PaError result = paNoError; + + /* First deal with the callback thread, cancelling and/or joining it if necessary */ + if( stream->callbackMode ) + { + PaError threadRes; + stream->callbackAbort = abort; + if( abort ) + { + PA_DEBUG(( "Aborting callback\n" )); + } + else + { + PA_DEBUG(( "Stopping callback\n" )); + } + PA_ENSURE_( PaUnixThread_Terminate( &stream->thread, !abort, &threadRes ) ); + if( threadRes != paNoError ) + { + PA_DEBUG(( "Callback thread returned: %d\n", threadRes )); + } + } + else + { + PA_ENSURE_( PaAsiHpi_StopStream( stream, abort ) ); + } + + stream->state = paAsiHpiStoppedState; + +error: + return result; +} + + +/** Stop PortAudio stream. + This blocks until the output buffers are drained. + + @param s Pointer to PortAudio stream + + @return PortAudio error code +*/ +static PaError StopStream( PaStream *s ) +{ + return PaAsiHpi_ExplicitStop( (PaAsiHpiStream *) s, 0 ); +} + + +/** Abort PortAudio stream. + This discards any existing data in output buffers and stops the stream immediately. + + @param s Pointer to PortAudio stream + + @return PortAudio error code +*/ +static PaError AbortStream( PaStream *s ) +{ + return PaAsiHpi_ExplicitStop( (PaAsiHpiStream * ) s, 1 ); +} + + +/** Determine whether the stream is stopped. + A stream is considered to be stopped prior to a successful call to StartStream and after + a successful call to StopStream or AbortStream. If a stream callback returns a value other + than paContinue the stream is NOT considered to be stopped (it is in CallbackFinished state). + + @param s Pointer to PortAudio stream + + @return Returns one (1) when the stream is stopped, zero (0) when the stream is running, or + a PaErrorCode (which are always negative) if PortAudio is not initialized or an + error is encountered. +*/ +static PaError IsStreamStopped( PaStream *s ) +{ + PaAsiHpiStream *stream = (PaAsiHpiStream*)s; + + assert( stream ); + return stream->state == paAsiHpiStoppedState ? 1 : 0; +} + + +/** Determine whether the stream is active. + A stream is active after a successful call to StartStream(), until it becomes inactive either + as a result of a call to StopStream() or AbortStream(), or as a result of a return value + other than paContinue from the stream callback. In the latter case, the stream is considered + inactive after the last buffer has finished playing. + + @param s Pointer to PortAudio stream + + @return Returns one (1) when the stream is active (i.e. playing or recording audio), + zero (0) when not playing, or a PaErrorCode (which are always negative) + if PortAudio is not initialized or an error is encountered. +*/ +static PaError IsStreamActive( PaStream *s ) +{ + PaAsiHpiStream *stream = (PaAsiHpiStream*)s; + + assert( stream ); + return stream->state == paAsiHpiActiveState ? 1 : 0; +} + + +/** Returns current stream time. + This corresponds to the system clock. The clock should run continuously while the stream + is open, i.e. between calls to OpenStream() and CloseStream(), therefore a frame counter + is not good enough. + + @param s Pointer to PortAudio stream + + @return Stream time, in seconds + */ +static PaTime GetStreamTime( PaStream *s ) +{ + return PaUtil_GetTime(); +} + + +/** Returns CPU load. + + @param s Pointer to PortAudio stream + + @return CPU load (0.0 if blocking interface is used) + */ +static double GetStreamCpuLoad( PaStream *s ) +{ + PaAsiHpiStream *stream = (PaAsiHpiStream*)s; + + return stream->callbackMode ? PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer ) : 0.0; +} + +/* --------------------------- Callback Interface --------------------------- */ + +/** Exit routine which is called when callback thread quits. + This takes care of stopping the HPI streams (either waiting for output to finish, or + abruptly). It also calls the user-supplied StreamFinished callback, and sets the + stream state to CallbackFinished if it was reached via a non-paContinue return from + the user callback function. + + @param userData A pointer to an open stream previously created with Pa_OpenStream + */ +static void PaAsiHpi_OnThreadExit( void *userData ) +{ + PaAsiHpiStream *stream = (PaAsiHpiStream *) userData; + + assert( stream ); + + PaUtil_ResetCpuLoadMeasurer( &stream->cpuLoadMeasurer ); + + PA_DEBUG(( "%s: Stopping HPI streams\n", __FUNCTION__ )); + PaAsiHpi_StopStream( stream, stream->callbackAbort ); + PA_DEBUG(( "%s: Stoppage\n", __FUNCTION__ )); + + /* Eventually notify user all buffers have played */ + if( stream->baseStreamRep.streamFinishedCallback ) + { + stream->baseStreamRep.streamFinishedCallback( stream->baseStreamRep.userData ); + } + + /* Unfortunately both explicit calls to Stop/AbortStream (leading to Stopped state) + and implicit stops via paComplete/paAbort (leading to CallbackFinished state) + end up here - need another flag to remind us which is the case */ + if( stream->callbackFinished ) + stream->state = paAsiHpiCallbackFinishedState; +} + + +/** Wait until there is enough frames to fill a host buffer. + The routine attempts to sleep until at least a full host buffer can be retrieved from the + input HPI stream and passed to the output HPI stream. It will first sleep until enough + output space is available, as this is usually easily achievable. If it is an output-only + stream, it will also sleep if the hardware buffer is too full, thereby throttling the + filling of the output buffer and reducing output latency. The routine then blocks until + enough input samples are available, unless this will cause an output underflow. In the + process, input overflows and output underflows are indicated. + + @param stream Pointer to stream struct + + @param framesAvail Returns the number of available frames + + @param cbFlags Overflows and underflows indicated in here + + @return PortAudio error code (only paUnanticipatedHostError expected) + */ +static PaError PaAsiHpi_WaitForFrames( PaAsiHpiStream *stream, unsigned long *framesAvail, + PaStreamCallbackFlags *cbFlags ) +{ + PaError result = paNoError; + double sampleRate; + unsigned long framesTarget; + uint32_t outputData = 0, outputSpace = 0, inputData = 0, framesLeft = 0; + + assert( stream ); + assert( stream->input || stream->output ); + + sampleRate = stream->baseStreamRep.streamInfo.sampleRate; + /* We have to come up with this much frames on both input and output */ + framesTarget = stream->bufferProcessor.framesPerHostBuffer; + assert( framesTarget > 0 ); + + while( 1 ) + { + PaAsiHpiStreamInfo info; + /* Check output first, as this takes priority in the default full-duplex mode */ + if( stream->output ) + { + PA_ENSURE_( PaAsiHpi_GetStreamInfo( stream->output, &info ) ); + /* Wait until enough space is available in output buffer to receive a full block */ + if( info.availableFrames < framesTarget ) + { + framesLeft = framesTarget - info.availableFrames; + Pa_Sleep( (long)ceil( 1000 * framesLeft / sampleRate ) ); + continue; + } + /* Wait until the data in hardware buffer has dropped to a sensible level. + Without this, the hardware buffer quickly fills up in the absence of an input + stream to regulate its data rate (if data generation is fast). This leads to + large latencies, as the AudioScience hardware buffers are humongous. + This is similar to the default "Hardware Buffering=off" option in the + AudioScience WAV driver. */ + if( !stream->input && (stream->output->outputBufferCap > 0) && + ( info.totalBufferedData > stream->output->outputBufferCap / stream->output->bytesPerFrame ) ) + { + framesLeft = info.totalBufferedData - stream->output->outputBufferCap / stream->output->bytesPerFrame; + Pa_Sleep( (long)ceil( 1000 * framesLeft / sampleRate ) ); + continue; + } + outputData = info.totalBufferedData; + outputSpace = info.availableFrames; + /* Report output underflow to callback */ + if( info.underflow ) + { + *cbFlags |= paOutputUnderflow; + } + } + + /* Now check input side */ + if( stream->input ) + { + PA_ENSURE_( PaAsiHpi_GetStreamInfo( stream->input, &info ) ); + /* If a full block of samples hasn't been recorded yet, wait for it if possible */ + if( info.availableFrames < framesTarget ) + { + framesLeft = framesTarget - info.availableFrames; + /* As long as output is not disrupted in the process, wait for a full + block of input samples */ + if( !stream->output || (outputData > framesLeft) ) + { + Pa_Sleep( (long)ceil( 1000 * framesLeft / sampleRate ) ); + continue; + } + } + inputData = info.availableFrames; + /** @todo The paInputOverflow flag should be set in the callback containing the + first input sample following the overflow. That means the block currently sitting + at the fore-front of recording, i.e. typically the one containing the newest (last) + sample in the HPI buffer system. This is most likely not the same as the current + block of data being passed to the callback. The current overflow should ideally + be noted in an overflow list of sorts, with an indication of when it should be + reported. The trouble starts if there are several separate overflow incidents, + given a big input buffer. Oh well, something to try out later... */ + if( info.overflow ) + { + *cbFlags |= paInputOverflow; + } + } + break; + } + /* Full-duplex stream */ + if( stream->input && stream->output ) + { + if( outputSpace >= framesTarget ) + *framesAvail = outputSpace; + /* If input didn't make the target, keep the output count instead (input underflow) */ + if( (inputData >= framesTarget) && (inputData < outputSpace) ) + *framesAvail = inputData; + } + else + { + *framesAvail = stream->input ? inputData : outputSpace; + } + +error: + return result; +} + + +/** Obtain recording, current and playback timestamps of stream. + The current time is determined by the system clock. This "now" timestamp occurs at the + forefront of recording (and playback in the full-duplex case), which happens later than the + input timestamp by an amount equal to the total number of recorded frames in the input buffer. + The output timestamp indicates when the next generated sample will actually be played. This + happens after all the samples currently in the output buffer are played. The output timestamp + therefore follows the current timestamp by an amount equal to the number of frames yet to be + played back in the output buffer. + + If the current timestamp is the present, the input timestamp is in the past and the output + timestamp is in the future. + + @param stream Pointer to stream struct + + @param timeInfo Pointer to timeInfo struct that will contain timestamps + */ +static void PaAsiHpi_CalculateTimeInfo( PaAsiHpiStream *stream, PaStreamCallbackTimeInfo *timeInfo ) +{ + PaAsiHpiStreamInfo streamInfo; + double sampleRate; + + assert( stream ); + assert( timeInfo ); + sampleRate = stream->baseStreamRep.streamInfo.sampleRate; + + /* The current time ("now") is at the forefront of both recording and playback */ + timeInfo->currentTime = GetStreamTime( (PaStream *)stream ); + /* The last sample in the input buffer was recorded just now, so the first sample + happened (number of recorded samples)/sampleRate ago */ + timeInfo->inputBufferAdcTime = timeInfo->currentTime; + if( stream->input ) + { + PaAsiHpi_GetStreamInfo( stream->input, &streamInfo ); + timeInfo->inputBufferAdcTime -= streamInfo.totalBufferedData / sampleRate; + } + /* The first of the outgoing samples will be played after all the samples in the output + buffer is done */ + timeInfo->outputBufferDacTime = timeInfo->currentTime; + if( stream->output ) + { + PaAsiHpi_GetStreamInfo( stream->output, &streamInfo ); + timeInfo->outputBufferDacTime += streamInfo.totalBufferedData / sampleRate; + } +} + + +/** Read from HPI input stream and register buffers. + This reads data from the HPI input stream (if it exists) and registers the temp stream + buffers of both input and output streams with the buffer processor. In the process it also + handles input underflows in the full-duplex case. + + @param stream Pointer to stream struct + + @param numFrames On entrance the number of available frames, on exit the number of + received frames + + @param cbFlags Indicates overflows and underflows + + @return PortAudio error code + */ +static PaError PaAsiHpi_BeginProcessing( PaAsiHpiStream *stream, unsigned long *numFrames, + PaStreamCallbackFlags *cbFlags ) +{ + PaError result = paNoError; + + assert( stream ); + if( *numFrames > stream->maxFramesPerHostBuffer ) + *numFrames = stream->maxFramesPerHostBuffer; + + if( stream->input ) + { + PaAsiHpiStreamInfo info; + + uint32_t framesToGet = *numFrames; + + /* Check for overflows and underflows yet again */ + PA_ENSURE_( PaAsiHpi_GetStreamInfo( stream->input, &info ) ); + if( info.overflow ) + { + *cbFlags |= paInputOverflow; + } + /* Input underflow if less than expected number of samples pitch up */ + if( framesToGet > info.availableFrames ) + { + PaUtilZeroer *zeroer; + PaSampleFormat inputFormat; + + /* Never call an input-only stream with InputUnderflow set */ + if( stream->output ) + *cbFlags |= paInputUnderflow; + framesToGet = info.availableFrames; + /* Fill temp buffer with silence (to make up for missing input samples) */ + inputFormat = PaAsiHpi_HpiToPaFormat( stream->input->hpiFormat.wFormat ); + zeroer = PaUtil_SelectZeroer( inputFormat ); + zeroer(stream->input->tempBuffer, 1, + stream->input->tempBufferSize / Pa_GetSampleSize(inputFormat) ); + } + + /* Read block of data into temp buffer */ + PA_ASIHPI_UNLESS_( HPI_InStreamReadBuf( NULL, + stream->input->hpiStream, + stream->input->tempBuffer, + framesToGet * stream->input->bytesPerFrame), + paUnanticipatedHostError ); + /* Register temp buffer with buffer processor (always FULL buffer) */ + PaUtil_SetInputFrameCount( &stream->bufferProcessor, *numFrames ); + /* HPI interface only allows interleaved channels */ + PaUtil_SetInterleavedInputChannels( &stream->bufferProcessor, + 0, stream->input->tempBuffer, + stream->input->hpiFormat.wChannels ); + } + if( stream->output ) + { + /* Register temp buffer with buffer processor */ + PaUtil_SetOutputFrameCount( &stream->bufferProcessor, *numFrames ); + /* HPI interface only allows interleaved channels */ + PaUtil_SetInterleavedOutputChannels( &stream->bufferProcessor, + 0, stream->output->tempBuffer, + stream->output->hpiFormat.wChannels ); + } + +error: + return result; +} + + +/** Flush output buffers to HPI output stream. + This completes the processing cycle by writing the temp buffer to the HPI interface. + Additional output underflows are caught before data is written to the stream, as this + action typically remedies the underflow and hides it in the process. + + @param stream Pointer to stream struct + + @param numFrames The number of frames to write to the output stream + + @param cbFlags Indicates overflows and underflows + */ +static PaError PaAsiHpi_EndProcessing( PaAsiHpiStream *stream, unsigned long numFrames, + PaStreamCallbackFlags *cbFlags ) +{ + PaError result = paNoError; + + assert( stream ); + + if( stream->output ) + { + PaAsiHpiStreamInfo info; + /* Check for underflows after the (potentially time-consuming) callback */ + PA_ENSURE_( PaAsiHpi_GetStreamInfo( stream->output, &info ) ); + if( info.underflow ) + { + *cbFlags |= paOutputUnderflow; + } + + /* Write temp buffer to HPI stream */ + PA_ASIHPI_UNLESS_( HPI_OutStreamWriteBuf( NULL, + stream->output->hpiStream, + stream->output->tempBuffer, + numFrames * stream->output->bytesPerFrame, + &stream->output->hpiFormat), + paUnanticipatedHostError ); + } + +error: + return result; +} + + +/** Main callback engine. + This function runs in a separate thread and does all the work of fetching audio data from + the AudioScience card via the HPI interface, feeding it to the user callback via the buffer + processor, and delivering the resulting output data back to the card via HPI calls. + It is started and terminated when the PortAudio stream is started and stopped, and starts + the HPI streams on startup. + + @param userData A pointer to an open stream previously created with Pa_OpenStream. +*/ +static void *CallbackThreadFunc( void *userData ) +{ + PaError result = paNoError; + PaAsiHpiStream *stream = (PaAsiHpiStream *) userData; + int callbackResult = paContinue; + + assert( stream ); + + /* Cleanup routine stops streams on thread exit */ + pthread_cleanup_push( &PaAsiHpi_OnThreadExit, stream ); + + /* Start HPI streams and notify parent when we're done */ + PA_ENSURE_( PaUnixThread_PrepareNotify( &stream->thread ) ); + /* Buffer will be primed with silence */ + PA_ENSURE_( PaAsiHpi_StartStream( stream, 0 ) ); + PA_ENSURE_( PaUnixThread_NotifyParent( &stream->thread ) ); + + /* MAIN LOOP */ + while( 1 ) + { + PaStreamCallbackFlags cbFlags = 0; + unsigned long framesAvail, framesGot; + + pthread_testcancel(); + + /** @concern StreamStop if the main thread has requested a stop and the stream has not + * been effectively stopped we signal this condition by modifying callbackResult + * (we'll want to flush buffered output). */ + if( PaUnixThread_StopRequested( &stream->thread ) && (callbackResult == paContinue) ) + { + PA_DEBUG(( "Setting callbackResult to paComplete\n" )); + callbackResult = paComplete; + } + + /* Start winding down thread if requested */ + if( callbackResult != paContinue ) + { + stream->callbackAbort = (callbackResult == paAbort); + if( stream->callbackAbort || + /** @concern BlockAdaption: Go on if adaption buffers are empty */ + PaUtil_IsBufferProcessorOutputEmpty( &stream->bufferProcessor ) ) + { + goto end; + } + PA_DEBUG(( "%s: Flushing buffer processor\n", __FUNCTION__ )); + /* There is still buffered output that needs to be processed */ + } + + /* SLEEP */ + /* Wait for data (or buffer space) to become available. This basically sleeps and + polls the HPI interface until a full block of frames can be moved. */ + PA_ENSURE_( PaAsiHpi_WaitForFrames( stream, &framesAvail, &cbFlags ) ); + + /* Consume buffer space. Once we have a number of frames available for consumption we + must retrieve the data from the HPI interface and pass it to the PA buffer processor. + We should be prepared to process several chunks successively. */ + while( framesAvail > 0 ) + { + PaStreamCallbackTimeInfo timeInfo = {0, 0, 0}; + + pthread_testcancel(); + + framesGot = framesAvail; + if( stream->bufferProcessor.hostBufferSizeMode == paUtilFixedHostBufferSize ) + { + /* We've committed to a fixed host buffer size, stick to that */ + framesGot = framesGot >= stream->maxFramesPerHostBuffer ? stream->maxFramesPerHostBuffer : 0; + } + else + { + /* We've committed to an upper bound on the size of host buffers */ + assert( stream->bufferProcessor.hostBufferSizeMode == paUtilBoundedHostBufferSize ); + framesGot = PA_MIN( framesGot, stream->maxFramesPerHostBuffer ); + } + + /* Obtain buffer timestamps */ + PaAsiHpi_CalculateTimeInfo( stream, &timeInfo ); + PaUtil_BeginBufferProcessing( &stream->bufferProcessor, &timeInfo, cbFlags ); + /* CPU load measurement should include processing activivity external to the stream callback */ + PaUtil_BeginCpuLoadMeasurement( &stream->cpuLoadMeasurer ); + if( framesGot > 0 ) + { + /* READ FROM HPI INPUT STREAM */ + PA_ENSURE_( PaAsiHpi_BeginProcessing( stream, &framesGot, &cbFlags ) ); + /* Input overflow in a full-duplex stream makes for interesting times */ + if( stream->input && stream->output && (cbFlags & paInputOverflow) ) + { + /* Special full-duplex paNeverDropInput mode */ + if( stream->neverDropInput ) + { + PaUtil_SetNoOutput( &stream->bufferProcessor ); + cbFlags |= paOutputOverflow; + } + } + /* CALL USER CALLBACK WITH INPUT DATA, AND OBTAIN OUTPUT DATA */ + PaUtil_EndBufferProcessing( &stream->bufferProcessor, &callbackResult ); + /* Clear overflow and underflow information (but PaAsiHpi_EndProcessing might + still show up output underflow that will carry over to next round) */ + cbFlags = 0; + /* WRITE TO HPI OUTPUT STREAM */ + PA_ENSURE_( PaAsiHpi_EndProcessing( stream, framesGot, &cbFlags ) ); + /* Advance frame counter */ + framesAvail -= framesGot; + } + PaUtil_EndCpuLoadMeasurement( &stream->cpuLoadMeasurer, framesGot ); + + if( framesGot == 0 ) + { + /* Go back to polling for more frames */ + break; + + } + if( callbackResult != paContinue ) + break; + } + } + + /* This code is unreachable, but important to include regardless because it + * is possibly a macro with a closing brace to match the opening brace in + * pthread_cleanup_push() above. The documentation states that they must + * always occur in pairs. */ + pthread_cleanup_pop( 1 ); + +end: + /* Indicates normal exit of callback, as opposed to the thread getting killed explicitly */ + stream->callbackFinished = 1; + PA_DEBUG(( "%s: Thread %d exiting (callbackResult = %d)\n ", + __FUNCTION__, pthread_self(), callbackResult )); + /* Exit from thread and report any PortAudio error in the process */ + PaUnixThreading_EXIT( result ); +error: + goto end; +} + +/* --------------------------- Blocking Interface --------------------------- */ + +/* As separate stream interfaces are used for blocking and callback streams, the following + functions can be guaranteed to only be called for blocking streams. */ + +/** Read data from input stream. + This reads the indicated number of frames into the supplied buffer from an input stream, + and blocks until this is done. + + @param s Pointer to PortAudio stream + + @param buffer Pointer to buffer that will receive interleaved data (or an array of pointers + to a buffer for each non-interleaved channel) + + @param frames Number of frames to read from stream + + @return PortAudio error code (also indicates overflow via paInputOverflowed) + */ +static PaError ReadStream( PaStream *s, + void *buffer, + unsigned long frames ) +{ + PaError result = paNoError; + PaAsiHpiStream *stream = (PaAsiHpiStream*)s; + PaAsiHpiStreamInfo info; + void *userBuffer; + + assert( stream ); + PA_UNLESS_( stream->input, paCanNotReadFromAnOutputOnlyStream ); + + /* Check for input overflow since previous call to ReadStream */ + PA_ENSURE_( PaAsiHpi_GetStreamInfo( stream->input, &info ) ); + if( info.overflow ) + { + result = paInputOverflowed; + } + + /* NB Make copy of user buffer pointers, since they are advanced by buffer processor */ + if( stream->bufferProcessor.userInputIsInterleaved ) + { + userBuffer = buffer; + } + else + { + /* Copy channels into local array */ + userBuffer = stream->blockingUserBufferCopy; + memcpy( userBuffer, buffer, sizeof (void *) * stream->input->hpiFormat.wChannels ); + } + + while( frames > 0 ) + { + unsigned long framesGot, framesAvail; + PaStreamCallbackFlags cbFlags = 0; + + PA_ENSURE_( PaAsiHpi_WaitForFrames( stream, &framesAvail, &cbFlags ) ); + framesGot = PA_MIN( framesAvail, frames ); + PA_ENSURE_( PaAsiHpi_BeginProcessing( stream, &framesGot, &cbFlags ) ); + + if( framesGot > 0 ) + { + framesGot = PaUtil_CopyInput( &stream->bufferProcessor, &userBuffer, framesGot ); + PA_ENSURE_( PaAsiHpi_EndProcessing( stream, framesGot, &cbFlags ) ); + /* Advance frame counter */ + frames -= framesGot; + } + } + +error: + return result; +} + + +/** Write data to output stream. + This writes the indicated number of frames from the supplied buffer to an output stream, + and blocks until this is done. + + @param s Pointer to PortAudio stream + + @param buffer Pointer to buffer that provides interleaved data (or an array of pointers + to a buffer for each non-interleaved channel) + + @param frames Number of frames to write to stream + + @return PortAudio error code (also indicates underflow via paOutputUnderflowed) + */ +static PaError WriteStream( PaStream *s, + const void *buffer, + unsigned long frames ) +{ + PaError result = paNoError; + PaAsiHpiStream *stream = (PaAsiHpiStream*)s; + PaAsiHpiStreamInfo info; + const void *userBuffer; + + assert( stream ); + PA_UNLESS_( stream->output, paCanNotWriteToAnInputOnlyStream ); + + /* Check for output underflow since previous call to WriteStream */ + PA_ENSURE_( PaAsiHpi_GetStreamInfo( stream->output, &info ) ); + if( info.underflow ) + { + result = paOutputUnderflowed; + } + + /* NB Make copy of user buffer pointers, since they are advanced by buffer processor */ + if( stream->bufferProcessor.userOutputIsInterleaved ) + { + userBuffer = buffer; + } + else + { + /* Copy channels into local array */ + userBuffer = stream->blockingUserBufferCopy; + memcpy( (void *)userBuffer, buffer, sizeof (void *) * stream->output->hpiFormat.wChannels ); + } + + while( frames > 0 ) + { + unsigned long framesGot, framesAvail; + PaStreamCallbackFlags cbFlags = 0; + + PA_ENSURE_( PaAsiHpi_WaitForFrames( stream, &framesAvail, &cbFlags ) ); + framesGot = PA_MIN( framesAvail, frames ); + PA_ENSURE_( PaAsiHpi_BeginProcessing( stream, &framesGot, &cbFlags ) ); + + if( framesGot > 0 ) + { + framesGot = PaUtil_CopyOutput( &stream->bufferProcessor, &userBuffer, framesGot ); + PA_ENSURE_( PaAsiHpi_EndProcessing( stream, framesGot, &cbFlags ) ); + /* Advance frame counter */ + frames -= framesGot; + } + } + +error: + return result; +} + + +/** Number of frames that can be read from input stream without blocking. + + @param s Pointer to PortAudio stream + + @return Number of frames, or PortAudio error code + */ +static signed long GetStreamReadAvailable( PaStream *s ) +{ + PaError result = paNoError; + PaAsiHpiStream *stream = (PaAsiHpiStream*)s; + PaAsiHpiStreamInfo info; + + assert( stream ); + PA_UNLESS_( stream->input, paCanNotReadFromAnOutputOnlyStream ); + + PA_ENSURE_( PaAsiHpi_GetStreamInfo( stream->input, &info ) ); + /* Round down to the nearest host buffer multiple */ + result = (info.availableFrames / stream->maxFramesPerHostBuffer) * stream->maxFramesPerHostBuffer; + if( info.overflow ) + { + result = paInputOverflowed; + } + +error: + return result; +} + + +/** Number of frames that can be written to output stream without blocking. + + @param s Pointer to PortAudio stream + + @return Number of frames, or PortAudio error code + */ +static signed long GetStreamWriteAvailable( PaStream *s ) +{ + PaError result = paNoError; + PaAsiHpiStream *stream = (PaAsiHpiStream*)s; + PaAsiHpiStreamInfo info; + + assert( stream ); + PA_UNLESS_( stream->output, paCanNotWriteToAnInputOnlyStream ); + + PA_ENSURE_( PaAsiHpi_GetStreamInfo( stream->output, &info ) ); + /* Round down to the nearest host buffer multiple */ + result = (info.availableFrames / stream->maxFramesPerHostBuffer) * stream->maxFramesPerHostBuffer; + if( info.underflow ) + { + result = paOutputUnderflowed; + } + +error: + return result; +} diff --git a/extern/portaudio/src/hostapi/asio/ASIO-README.txt b/extern/portaudio/src/hostapi/asio/ASIO-README.txt new file mode 100644 index 0000000..bc86caa --- /dev/null +++ b/extern/portaudio/src/hostapi/asio/ASIO-README.txt @@ -0,0 +1,147 @@ +ASIO-README.txt + +This document contains information to help you compile PortAudio with +ASIO support. If you find any omissions or errors in this document +please notify us on the PortAudio mailing list. + +NOTE: The Macintosh sections of this document are provided for historical +reference. They refer to pre-OS X Macintosh. PortAudio no longer +supports pre-OS X Macintosh. Steinberg does not support ASIO on Mac OS X. + + +Building PortAudio with ASIO support +------------------------------------ + +To build PortAudio with ASIO support you need to compile and link with +pa_asio.c, and files from the ASIO SDK (see below), along with the common +PortAudio files from src/common/ and platform specific files from +src/os/win/ (for Win32). + +If you are compiling with a non-Microsoft compiler on Windows, also +compile and link with iasiothiscallresolver.cpp (see below for +an explanation). + +For some platforms (MingW, Cygwin/MingW), you may simply +be able to type: + +./configure --with-host_os=mingw --with-winapi=asio [--with-asiodir=/usr/local/asiosdk2] +make + +and life will be good. Make sure you update the above with the correct local +path to the ASIO SDK. + + +For Microsoft Visual C++ there is an build tutorial here: +http://www.portaudio.com/trac/wiki/TutorialDir/Compile/WindowsASIOMSVC + + + +Obtaining the ASIO SDK +---------------------- + +In order to build PortAudio with ASIO support, you need to download +the ASIO SDK (version 2.0 or later) from Steinberg. Steinberg makes the ASIO +SDK available to anyone free of charge, however they do not permit its +source code to be distributed. + +NOTE: In some cases the ASIO SDK may require patching, see below +for further details. + +http://www.steinberg.net/en/company/developer.html + +If the above link is broken search Google for: +"download steinberg ASIO SDK" + + + +Building the ASIO SDK on Windows +-------------------------------- + +To build the ASIO SDK on Windows you need to compile and link with the +following files from the ASIO SDK: + +asio_sdk\common\asio.cpp +asio_sdk\host\asiodrivers.cpp +asio_sdk\host\pc\asiolist.cpp + +You may also need to adjust your include paths to support inclusion of +header files from the above directories. + +The ASIO SDK depends on the following COM API functions: +CoInitialize, CoUninitialize, CoCreateInstance, CLSIDFromString +For compilation with MinGW you will need to link with -lole32, for +Borland compilers link with Import32.lib. + + + +Non-Microsoft (MSVC) Compilers on Windows including Borland and GCC +------------------------------------------------------------------- + +Steinberg did not specify a calling convention in the IASIO interface +definition. This causes the Microsoft compiler to use the proprietary +thiscall convention which is not compatible with other compilers, such +as compilers from Borland (BCC and C++Builder) and GNU (gcc). +Steinberg's ASIO SDK will compile but crash on initialization if +compiled with a non-Microsoft compiler on Windows. + +PortAudio solves this problem using the iasiothiscallresolver library +which is included in the distribution. When building ASIO support for +non-Microsoft compilers, be sure to compile and link with +iasiothiscallresolver.cpp. Note that iasiothiscallresolver includes +conditional directives which cause it to have no effect if it is +compiled with a Microsoft compiler, or on the Macintosh. + +If you use configure and make (see above), this should be handled +automatically for you. + +For further information about the IASIO thiscall problem see this page: +http://www.rossbencina.com/code/iasio-thiscall-resolver + + + +Building the ASIO SDK on (Pre-OS X) Macintosh +--------------------------------------------- + +To build the ASIO SDK on Macintosh you need to compile and link with the +following files from the ASIO SDK: + +host/asiodrivers.cpp +host/mac/asioshlib.cpp +host/mac/codefragements.cpp + +You may also need to adjust your include paths to support inclusion of +header files from the above directories. + + + +(Pre-OS X) Macintosh ASIO SDK Bug Patch +--------------------------------------- + +There is a bug in the ASIO SDK that causes the Macintosh version to +often fail during initialization. Below is a patch that you can apply. + +In codefragments.cpp replace getFrontProcessDirectory function with +the following one (GetFrontProcess replaced by GetCurrentProcess). + + +bool CodeFragments::getFrontProcessDirectory(void *specs) +{ + FSSpec *fss = (FSSpec *)specs; + ProcessInfoRec pif; + ProcessSerialNumber psn; + + memset(&psn,0,(long)sizeof(ProcessSerialNumber)); + // if(GetFrontProcess(&psn) == noErr) // wrong !!! + if(GetCurrentProcess(&psn) == noErr) // correct !!! + { + pif.processName = 0; + pif.processAppSpec = fss; + pif.processInfoLength = sizeof(ProcessInfoRec); + if(GetProcessInformation(&psn, &pif) == noErr) + return true; + } + return false; +} + + +### diff --git a/extern/portaudio/src/hostapi/asio/Callback_adaptation_.pdf b/extern/portaudio/src/hostapi/asio/Callback_adaptation_.pdf new file mode 100644 index 0000000..76bf678 Binary files /dev/null and b/extern/portaudio/src/hostapi/asio/Callback_adaptation_.pdf differ diff --git a/extern/portaudio/src/hostapi/asio/Pa_ASIO.pdf b/extern/portaudio/src/hostapi/asio/Pa_ASIO.pdf new file mode 100644 index 0000000..ac5ecad Binary files /dev/null and b/extern/portaudio/src/hostapi/asio/Pa_ASIO.pdf differ diff --git a/extern/portaudio/src/hostapi/asio/iasiothiscallresolver.cpp b/extern/portaudio/src/hostapi/asio/iasiothiscallresolver.cpp new file mode 100644 index 0000000..08c55ea --- /dev/null +++ b/extern/portaudio/src/hostapi/asio/iasiothiscallresolver.cpp @@ -0,0 +1,572 @@ +/* + IASIOThiscallResolver.cpp see the comments in iasiothiscallresolver.h for + the top level description - this comment describes the technical details of + the implementation. + + The latest version of this file is available from: + http://www.audiomulch.com/~rossb/code/calliasio + + please email comments to Ross Bencina + + BACKGROUND + + The IASIO interface declared in the Steinberg ASIO 2 SDK declares + functions with no explicit calling convention. This causes MSVC++ to default + to using the thiscall convention, which is a proprietary convention not + implemented by some non-microsoft compilers - notably borland BCC, + C++Builder, and gcc. MSVC++ is the defacto standard compiler used by + Steinberg. As a result of this situation, the ASIO sdk will compile with + any compiler, however attempting to execute the compiled code will cause a + crash due to different default calling conventions on non-Microsoft + compilers. + + IASIOThiscallResolver solves the problem by providing an adapter class that + delegates to the IASIO interface using the correct calling convention + (thiscall). Due to the lack of support for thiscall in the Borland and GCC + compilers, the calls have been implemented in assembly language. + + A number of macros are defined for thiscall function calls with different + numbers of parameters, with and without return values - it may be possible + to modify the format of these macros to make them work with other inline + assemblers. + + + THISCALL DEFINITION + + A number of definitions of the thiscall calling convention are floating + around the internet. The following definition has been validated against + output from the MSVC++ compiler: + + For non-vararg functions, thiscall works as follows: the object (this) + pointer is passed in ECX. All arguments are passed on the stack in + right to left order. The return value is placed in EAX. The callee + clears the passed arguments from the stack. + + + FINDING FUNCTION POINTERS FROM AN IASIO POINTER + + The first field of a COM object is a pointer to its vtble. Thus a pointer + to an object implementing the IASIO interface also points to a pointer to + that object's vtbl. The vtble is a table of function pointers for all of + the virtual functions exposed by the implemented interfaces. + + If we consider a variable declared as a pointer to IASO: + + IASIO *theAsioDriver + + theAsioDriver points to: + + object implementing IASIO + { + IASIOvtbl *vtbl + other data + } + + in other words, theAsioDriver points to a pointer to an IASIOvtbl + + vtbl points to a table of function pointers: + + IASIOvtbl ( interface IASIO : public IUnknown ) + { + (IUnknown functions) + 0 virtual HRESULT STDMETHODCALLTYPE (*QueryInterface)(REFIID riid, void **ppv) = 0; + 4 virtual ULONG STDMETHODCALLTYPE (*AddRef)() = 0; + 8 virtual ULONG STDMETHODCALLTYPE (*Release)() = 0; + + (IASIO functions) + 12 virtual ASIOBool (*init)(void *sysHandle) = 0; + 16 virtual void (*getDriverName)(char *name) = 0; + 20 virtual long (*getDriverVersion)() = 0; + 24 virtual void (*getErrorMessage)(char *string) = 0; + 28 virtual ASIOError (*start)() = 0; + 32 virtual ASIOError (*stop)() = 0; + 36 virtual ASIOError (*getChannels)(long *numInputChannels, long *numOutputChannels) = 0; + 40 virtual ASIOError (*getLatencies)(long *inputLatency, long *outputLatency) = 0; + 44 virtual ASIOError (*getBufferSize)(long *minSize, long *maxSize, + long *preferredSize, long *granularity) = 0; + 48 virtual ASIOError (*canSampleRate)(ASIOSampleRate sampleRate) = 0; + 52 virtual ASIOError (*getSampleRate)(ASIOSampleRate *sampleRate) = 0; + 56 virtual ASIOError (*setSampleRate)(ASIOSampleRate sampleRate) = 0; + 60 virtual ASIOError (*getClockSources)(ASIOClockSource *clocks, long *numSources) = 0; + 64 virtual ASIOError (*setClockSource)(long reference) = 0; + 68 virtual ASIOError (*getSamplePosition)(ASIOSamples *sPos, ASIOTimeStamp *tStamp) = 0; + 72 virtual ASIOError (*getChannelInfo)(ASIOChannelInfo *info) = 0; + 76 virtual ASIOError (*createBuffers)(ASIOBufferInfo *bufferInfos, long numChannels, + long bufferSize, ASIOCallbacks *callbacks) = 0; + 80 virtual ASIOError (*disposeBuffers)() = 0; + 84 virtual ASIOError (*controlPanel)() = 0; + 88 virtual ASIOError (*future)(long selector,void *opt) = 0; + 92 virtual ASIOError (*outputReady)() = 0; + }; + + The numbers in the left column show the byte offset of each function ptr + from the beginning of the vtbl. These numbers are used in the code below + to select different functions. + + In order to find the address of a particular function, theAsioDriver + must first be dereferenced to find the value of the vtbl pointer: + + mov eax, theAsioDriver + mov edx, [theAsioDriver] // edx now points to vtbl[0] + + Then an offset must be added to the vtbl pointer to select a + particular function, for example vtbl+44 points to the slot containing + a pointer to the getBufferSize function. + + Finally vtbl+x must be dereferenced to obtain the value of the function + pointer stored in that address: + + call [edx+44] // call the function pointed to by + // the value in the getBufferSize field of the vtbl + + + SEE ALSO + + Martin Fay's OpenASIO DLL at http://www.martinfay.com solves the same + problem by providing a new COM interface which wraps IASIO with an + interface that uses portable calling conventions. OpenASIO must be compiled + with MSVC, and requires that you ship the OpenASIO DLL with your + application. + + + ACKNOWLEDGEMENTS + + Ross Bencina: worked out the thiscall details above, wrote the original + Borland asm macros, and a patch for asio.cpp (which is no longer needed). + Thanks to Martin Fay for introducing me to the issues discussed here, + and to Rene G. Ceballos for assisting with asm dumps from MSVC++. + + Antti Silvast: converted the original calliasio to work with gcc and NASM + by implementing the asm code in a separate file. + + Fraser Adams: modified the original calliasio containing the Borland inline + asm to add inline asm for gcc i.e. Intel syntax for Borland and AT&T syntax + for gcc. This seems a neater approach for gcc than to have a separate .asm + file and it means that we only need one version of the thiscall patch. + + Fraser Adams: rewrote the original calliasio patch in the form of the + IASIOThiscallResolver class in order to avoid modifications to files from + the Steinberg SDK, which may have had potential licence issues. + + Andrew Baldwin: contributed fixes for compatibility problems with more + recent versions of the gcc assembler. +*/ + + +// We only need IASIOThiscallResolver at all if we are on Win32. For other +// platforms we simply bypass the IASIOThiscallResolver definition to allow us +// to be safely #include'd whatever the platform to keep client code portable +#if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__)) && !defined(_WIN64) + + +// If microsoft compiler we can call IASIO directly so IASIOThiscallResolver +// is not used. +#if !defined(_MSC_VER) + + +#include +#include + +// We have a mechanism in iasiothiscallresolver.h to ensure that asio.h is +// #include'd before it in client code, we do NOT want to do this test here. +#define iasiothiscallresolver_sourcefile 1 +#include "iasiothiscallresolver.h" +#undef iasiothiscallresolver_sourcefile + +// iasiothiscallresolver.h redefines ASIOInit for clients, but we don't want +// this macro defined in this translation unit. +#undef ASIOInit + + +// theAsioDriver is a global pointer to the current IASIO instance which the +// ASIO SDK uses to perform all actions on the IASIO interface. We substitute +// our own forwarding interface into this pointer. +extern IASIO* theAsioDriver; + + +// The following macros define the inline assembler for BORLAND first then gcc + +#if defined(__BCPLUSPLUS__) || defined(__BORLANDC__) + + +#define CALL_THISCALL_0( resultName, thisPtr, funcOffset )\ + void *this_ = (thisPtr); \ + __asm { \ + mov ecx, this_ ; \ + mov eax, [ecx] ; \ + call [eax+funcOffset] ; \ + mov resultName, eax ; \ + } + + +#define CALL_VOID_THISCALL_1( thisPtr, funcOffset, param1 )\ + void *this_ = (thisPtr); \ + __asm { \ + mov eax, param1 ; \ + push eax ; \ + mov ecx, this_ ; \ + mov eax, [ecx] ; \ + call [eax+funcOffset] ; \ + } + + +#define CALL_THISCALL_1( resultName, thisPtr, funcOffset, param1 )\ + void *this_ = (thisPtr); \ + __asm { \ + mov eax, param1 ; \ + push eax ; \ + mov ecx, this_ ; \ + mov eax, [ecx] ; \ + call [eax+funcOffset] ; \ + mov resultName, eax ; \ + } + + +#define CALL_THISCALL_1_DOUBLE( resultName, thisPtr, funcOffset, param1 )\ + void *this_ = (thisPtr); \ + void *doubleParamPtr_ (¶m1); \ + __asm { \ + mov eax, doubleParamPtr_ ; \ + push [eax+4] ; \ + push [eax] ; \ + mov ecx, this_ ; \ + mov eax, [ecx] ; \ + call [eax+funcOffset] ; \ + mov resultName, eax ; \ + } + + +#define CALL_THISCALL_2( resultName, thisPtr, funcOffset, param1, param2 )\ + void *this_ = (thisPtr); \ + __asm { \ + mov eax, param2 ; \ + push eax ; \ + mov eax, param1 ; \ + push eax ; \ + mov ecx, this_ ; \ + mov eax, [ecx] ; \ + call [eax+funcOffset] ; \ + mov resultName, eax ; \ + } + + +#define CALL_THISCALL_4( resultName, thisPtr, funcOffset, param1, param2, param3, param4 )\ + void *this_ = (thisPtr); \ + __asm { \ + mov eax, param4 ; \ + push eax ; \ + mov eax, param3 ; \ + push eax ; \ + mov eax, param2 ; \ + push eax ; \ + mov eax, param1 ; \ + push eax ; \ + mov ecx, this_ ; \ + mov eax, [ecx] ; \ + call [eax+funcOffset] ; \ + mov resultName, eax ; \ + } + + +#elif defined(__GNUC__) + + +#define CALL_THISCALL_0( resultName, thisPtr, funcOffset ) \ + __asm__ __volatile__ ("movl (%1), %%edx\n\t" \ + "call *"#funcOffset"(%%edx)\n\t" \ + :"=a"(resultName) /* Output Operands */ \ + :"c"(thisPtr) /* Input Operands */ \ + : "%edx" /* Clobbered Registers */ \ + ); \ + + +#define CALL_VOID_THISCALL_1( thisPtr, funcOffset, param1 ) \ + __asm__ __volatile__ ("pushl %0\n\t" \ + "movl (%1), %%edx\n\t" \ + "call *"#funcOffset"(%%edx)\n\t" \ + : /* Output Operands */ \ + :"r"(param1), /* Input Operands */ \ + "c"(thisPtr) \ + : "%edx" /* Clobbered Registers */ \ + ); \ + + +#define CALL_THISCALL_1( resultName, thisPtr, funcOffset, param1 ) \ + __asm__ __volatile__ ("pushl %1\n\t" \ + "movl (%2), %%edx\n\t" \ + "call *"#funcOffset"(%%edx)\n\t" \ + :"=a"(resultName) /* Output Operands */ \ + :"r"(param1), /* Input Operands */ \ + "c"(thisPtr) \ + : "%edx" /* Clobbered Registers */ \ + ); \ + + +#define CALL_THISCALL_1_DOUBLE( resultName, thisPtr, funcOffset, param1 ) \ + do { \ + double param1f64 = param1; /* Cast explicitly to double */ \ + double *param1f64Ptr = ¶m1f64; /* Make pointer to address */ \ + __asm__ __volatile__ ("pushl 4(%1)\n\t" \ + "pushl (%1)\n\t" \ + "movl (%2), %%edx\n\t" \ + "call *"#funcOffset"(%%edx);\n\t" \ + : "=a"(resultName) /* Output Operands */ \ + : "r"(param1f64Ptr), /* Input Operands */ \ + "c"(thisPtr), \ + "m"(*param1f64Ptr) /* Using address */ \ + : "%edx" /* Clobbered Registers */ \ + ); \ + } while (0); \ + + +#define CALL_THISCALL_2( resultName, thisPtr, funcOffset, param1, param2 ) \ + __asm__ __volatile__ ("pushl %1\n\t" \ + "pushl %2\n\t" \ + "movl (%3), %%edx\n\t" \ + "call *"#funcOffset"(%%edx)\n\t" \ + :"=a"(resultName) /* Output Operands */ \ + :"r"(param2), /* Input Operands */ \ + "r"(param1), \ + "c"(thisPtr) \ + : "%edx" /* Clobbered Registers */ \ + ); \ + + +#define CALL_THISCALL_4( resultName, thisPtr, funcOffset, param1, param2, param3, param4 )\ + __asm__ __volatile__ ("pushl %1\n\t" \ + "pushl %2\n\t" \ + "pushl %3\n\t" \ + "pushl %4\n\t" \ + "movl (%5), %%edx\n\t" \ + "call *"#funcOffset"(%%edx)\n\t" \ + :"=a"(resultName) /* Output Operands */ \ + :"r"(param4), /* Input Operands */ \ + "r"(param3), \ + "r"(param2), \ + "r"(param1), \ + "c"(thisPtr) \ + : "%edx" /* Clobbered Registers */ \ + ); \ + +#endif + + + +// Our static singleton instance. +IASIOThiscallResolver IASIOThiscallResolver::instance; + +// Constructor called to initialize static Singleton instance above. Note that +// it is important not to clear that_ incase it has already been set by the call +// to placement new in ASIOInit(). +IASIOThiscallResolver::IASIOThiscallResolver() +{ +} + +// Constructor called from ASIOInit() below +IASIOThiscallResolver::IASIOThiscallResolver(IASIO* that) +: that_( that ) +{ +} + +// Implement IUnknown methods as assert(false). IASIOThiscallResolver is not +// really a COM object, just a wrapper which will work with the ASIO SDK. +// If you wanted to use ASIO without the SDK you might want to implement COM +// aggregation in these methods. +HRESULT STDMETHODCALLTYPE IASIOThiscallResolver::QueryInterface(REFIID riid, void **ppv) +{ + (void)riid; // suppress unused variable warning + + assert( false ); // this function should never be called by the ASIO SDK. + + *ppv = NULL; + return E_NOINTERFACE; +} + +ULONG STDMETHODCALLTYPE IASIOThiscallResolver::AddRef() +{ + assert( false ); // this function should never be called by the ASIO SDK. + + return 1; +} + +ULONG STDMETHODCALLTYPE IASIOThiscallResolver::Release() +{ + assert( false ); // this function should never be called by the ASIO SDK. + + return 1; +} + + +// Implement the IASIO interface methods by performing the vptr manipulation +// described above then delegating to the real implementation. +ASIOBool IASIOThiscallResolver::init(void *sysHandle) +{ + ASIOBool result; + CALL_THISCALL_1( result, that_, 12, sysHandle ); + return result; +} + +void IASIOThiscallResolver::getDriverName(char *name) +{ + CALL_VOID_THISCALL_1( that_, 16, name ); +} + +long IASIOThiscallResolver::getDriverVersion() +{ + ASIOBool result; + CALL_THISCALL_0( result, that_, 20 ); + return result; +} + +void IASIOThiscallResolver::getErrorMessage(char *string) +{ + CALL_VOID_THISCALL_1( that_, 24, string ); +} + +ASIOError IASIOThiscallResolver::start() +{ + ASIOBool result; + CALL_THISCALL_0( result, that_, 28 ); + return result; +} + +ASIOError IASIOThiscallResolver::stop() +{ + ASIOBool result; + CALL_THISCALL_0( result, that_, 32 ); + return result; +} + +ASIOError IASIOThiscallResolver::getChannels(long *numInputChannels, long *numOutputChannels) +{ + ASIOBool result; + CALL_THISCALL_2( result, that_, 36, numInputChannels, numOutputChannels ); + return result; +} + +ASIOError IASIOThiscallResolver::getLatencies(long *inputLatency, long *outputLatency) +{ + ASIOBool result; + CALL_THISCALL_2( result, that_, 40, inputLatency, outputLatency ); + return result; +} + +ASIOError IASIOThiscallResolver::getBufferSize(long *minSize, long *maxSize, + long *preferredSize, long *granularity) +{ + ASIOBool result; + CALL_THISCALL_4( result, that_, 44, minSize, maxSize, preferredSize, granularity ); + return result; +} + +ASIOError IASIOThiscallResolver::canSampleRate(ASIOSampleRate sampleRate) +{ + ASIOBool result; + CALL_THISCALL_1_DOUBLE( result, that_, 48, sampleRate ); + return result; +} + +ASIOError IASIOThiscallResolver::getSampleRate(ASIOSampleRate *sampleRate) +{ + ASIOBool result; + CALL_THISCALL_1( result, that_, 52, sampleRate ); + return result; +} + +ASIOError IASIOThiscallResolver::setSampleRate(ASIOSampleRate sampleRate) +{ + ASIOBool result; + CALL_THISCALL_1_DOUBLE( result, that_, 56, sampleRate ); + return result; +} + +ASIOError IASIOThiscallResolver::getClockSources(ASIOClockSource *clocks, long *numSources) +{ + ASIOBool result; + CALL_THISCALL_2( result, that_, 60, clocks, numSources ); + return result; +} + +ASIOError IASIOThiscallResolver::setClockSource(long reference) +{ + ASIOBool result; + CALL_THISCALL_1( result, that_, 64, reference ); + return result; +} + +ASIOError IASIOThiscallResolver::getSamplePosition(ASIOSamples *sPos, ASIOTimeStamp *tStamp) +{ + ASIOBool result; + CALL_THISCALL_2( result, that_, 68, sPos, tStamp ); + return result; +} + +ASIOError IASIOThiscallResolver::getChannelInfo(ASIOChannelInfo *info) +{ + ASIOBool result; + CALL_THISCALL_1( result, that_, 72, info ); + return result; +} + +ASIOError IASIOThiscallResolver::createBuffers(ASIOBufferInfo *bufferInfos, + long numChannels, long bufferSize, ASIOCallbacks *callbacks) +{ + ASIOBool result; + CALL_THISCALL_4( result, that_, 76, bufferInfos, numChannels, bufferSize, callbacks ); + return result; +} + +ASIOError IASIOThiscallResolver::disposeBuffers() +{ + ASIOBool result; + CALL_THISCALL_0( result, that_, 80 ); + return result; +} + +ASIOError IASIOThiscallResolver::controlPanel() +{ + ASIOBool result; + CALL_THISCALL_0( result, that_, 84 ); + return result; +} + +ASIOError IASIOThiscallResolver::future(long selector,void *opt) +{ + ASIOBool result; + CALL_THISCALL_2( result, that_, 88, selector, opt ); + return result; +} + +ASIOError IASIOThiscallResolver::outputReady() +{ + ASIOBool result; + CALL_THISCALL_0( result, that_, 92 ); + return result; +} + + +// Implement our substitute ASIOInit() method +ASIOError IASIOThiscallResolver::ASIOInit(ASIODriverInfo *info) +{ + // To ensure that our instance's vptr is correctly constructed, even if + // ASIOInit is called prior to main(), we explicitly call its constructor + // (potentially over the top of an existing instance). Note that this is + // pretty ugly, and is only safe because IASIOThiscallResolver has no + // destructor and contains no objects with destructors. + new((void*)&instance) IASIOThiscallResolver( theAsioDriver ); + + // Interpose between ASIO client code and the real driver. + theAsioDriver = &instance; + + // Note that we never need to switch theAsioDriver back to point to the + // real driver because theAsioDriver is reset to zero in ASIOExit(). + + // Delegate to the real ASIOInit + return ::ASIOInit(info); +} + + +#endif /* !defined(_MSC_VER) */ + +#endif /* Win32 */ + diff --git a/extern/portaudio/src/hostapi/asio/iasiothiscallresolver.h b/extern/portaudio/src/hostapi/asio/iasiothiscallresolver.h new file mode 100644 index 0000000..21d53b3 --- /dev/null +++ b/extern/portaudio/src/hostapi/asio/iasiothiscallresolver.h @@ -0,0 +1,197 @@ +// **************************************************************************** +// File: IASIOThiscallResolver.h +// Description: The IASIOThiscallResolver class implements the IASIO +// interface and acts as a proxy to the real IASIO interface by +// calling through its vptr table using the thiscall calling +// convention. To put it another way, we interpose +// IASIOThiscallResolver between ASIO SDK code and the driver. +// This is necessary because most non-Microsoft compilers don't +// implement the thiscall calling convention used by IASIO. +// +// iasiothiscallresolver.cpp contains the background of this +// problem plus a technical description of the vptr +// manipulations. +// +// In order to use this mechanism one simply has to add +// iasiothiscallresolver.cpp to the list of files to compile +// and #include +// +// Note that this #include must come after the other ASIO SDK +// #includes, for example: +// +// #include +// #include +// #include +// #include +// #include +// +// Actually the important thing is to #include +// after . We have +// incorporated a test to enforce this ordering. +// +// The code transparently takes care of the interposition by +// using macro substitution to intercept calls to ASIOInit() +// and ASIOExit(). We save the original ASIO global +// "theAsioDriver" in our "that" variable, and then set +// "theAsioDriver" to equal our IASIOThiscallResolver instance. +// +// Whilst this method of resolving the thiscall problem requires +// the addition of #include to client +// code it has the advantage that it does not break the terms +// of the ASIO licence by publishing it. We are NOT modifying +// any Steinberg code here, we are merely implementing the IASIO +// interface in the same way that we would need to do if we +// wished to provide an open source ASIO driver. +// +// For compilation with MinGW -lole32 needs to be added to the +// linker options. For BORLAND, linking with Import32.lib is +// sufficient. +// +// The dependencies are with: CoInitialize, CoUninitialize, +// CoCreateInstance, CLSIDFromString - used by asiolist.cpp +// and are required on Windows whether ThiscallResolver is used +// or not. +// +// Searching for the above strings in the root library path +// of your compiler should enable the correct libraries to be +// identified if they aren't immediately obvious. +// +// Note that the current implementation of IASIOThiscallResolver +// is not COM compliant - it does not correctly implement the +// IUnknown interface. Implementing it is not necessary because +// it is not called by parts of the ASIO SDK which call through +// theAsioDriver ptr. The IUnknown methods are implemented as +// assert(false) to ensure that the code fails if they are +// ever called. +// Restrictions: None. Public Domain & Open Source distribute freely +// You may use IASIOThiscallResolver commercially as well as +// privately. +// You the user assume the responsibility for the use of the +// files, binary or text, and there is no guarantee or warranty, +// expressed or implied, including but not limited to the +// implied warranties of merchantability and fitness for a +// particular purpose. You assume all responsibility and agree +// to hold no entity, copyright holder or distributors liable +// for any loss of data or inaccurate representations of data +// as a result of using IASIOThiscallResolver. +// Version: 1.4 Added separate macro CALL_THISCALL_1_DOUBLE from +// Andrew Baldwin, and volatile for whole gcc asm blocks, +// both for compatibility with newer gcc versions. Cleaned up +// Borland asm to use one less register. +// 1.3 Switched to including assert.h for better compatibility. +// Wrapped entire .h and .cpp contents with a check for +// _MSC_VER to provide better compatibility with MS compilers. +// Changed Singleton implementation to use static instance +// instead of freestore allocated instance. Removed ASIOExit +// macro as it is no longer needed. +// 1.2 Removed semicolons from ASIOInit and ASIOExit macros to +// allow them to be embedded in expressions (if statements). +// Cleaned up some comments. Removed combase.c dependency (it +// doesn't compile with BCB anyway) by stubbing IUnknown. +// 1.1 Incorporated comments from Ross Bencina including things +// such as changing name from ThiscallResolver to +// IASIOThiscallResolver, tidying up the constructor, fixing +// a bug in IASIOThiscallResolver::ASIOExit() and improving +// portability through the use of conditional compilation +// 1.0 Initial working version. +// Created: 6/09/2003 +// Authors: Fraser Adams +// Ross Bencina +// Rene G. Ceballos +// Martin Fay +// Antti Silvast +// Andrew Baldwin +// +// **************************************************************************** + + +#ifndef included_iasiothiscallresolver_h +#define included_iasiothiscallresolver_h + +// We only need IASIOThiscallResolver at all if we are on Win32. For other +// platforms we simply bypass the IASIOThiscallResolver definition to allow us +// to be safely #include'd whatever the platform to keep client code portable +#if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__)) && !defined(_WIN64) + + +// If microsoft compiler we can call IASIO directly so IASIOThiscallResolver +// is not used. +#if !defined(_MSC_VER) + + +// The following is in order to ensure that this header is only included after +// the other ASIO headers (except for the case of iasiothiscallresolver.cpp). +// We need to do this because IASIOThiscallResolver works by eclipsing the +// original definition of ASIOInit() with a macro (see below). +#if !defined(iasiothiscallresolver_sourcefile) + #if !defined(__ASIO_H) + #error iasiothiscallresolver.h must be included AFTER asio.h + #endif +#endif + +#include +#include /* From ASIO SDK */ + + +class IASIOThiscallResolver : public IASIO { +private: + IASIO* that_; // Points to the real IASIO + + static IASIOThiscallResolver instance; // Singleton instance + + // Constructors - declared private so construction is limited to + // our Singleton instance + IASIOThiscallResolver(); + IASIOThiscallResolver(IASIO* that); +public: + + // Methods from the IUnknown interface. We don't fully implement IUnknown + // because the ASIO SDK never calls these methods through theAsioDriver ptr. + // These methods are implemented as assert(false). + virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppv); + virtual ULONG STDMETHODCALLTYPE AddRef(); + virtual ULONG STDMETHODCALLTYPE Release(); + + // Methods from the IASIO interface, implemented as forwarning calls to that. + virtual ASIOBool init(void *sysHandle); + virtual void getDriverName(char *name); + virtual long getDriverVersion(); + virtual void getErrorMessage(char *string); + virtual ASIOError start(); + virtual ASIOError stop(); + virtual ASIOError getChannels(long *numInputChannels, long *numOutputChannels); + virtual ASIOError getLatencies(long *inputLatency, long *outputLatency); + virtual ASIOError getBufferSize(long *minSize, long *maxSize, long *preferredSize, long *granularity); + virtual ASIOError canSampleRate(ASIOSampleRate sampleRate); + virtual ASIOError getSampleRate(ASIOSampleRate *sampleRate); + virtual ASIOError setSampleRate(ASIOSampleRate sampleRate); + virtual ASIOError getClockSources(ASIOClockSource *clocks, long *numSources); + virtual ASIOError setClockSource(long reference); + virtual ASIOError getSamplePosition(ASIOSamples *sPos, ASIOTimeStamp *tStamp); + virtual ASIOError getChannelInfo(ASIOChannelInfo *info); + virtual ASIOError createBuffers(ASIOBufferInfo *bufferInfos, long numChannels, long bufferSize, ASIOCallbacks *callbacks); + virtual ASIOError disposeBuffers(); + virtual ASIOError controlPanel(); + virtual ASIOError future(long selector,void *opt); + virtual ASIOError outputReady(); + + // Class method, see ASIOInit() macro below. + static ASIOError ASIOInit(ASIODriverInfo *info); // Delegates to ::ASIOInit +}; + + +// Replace calls to ASIOInit with our interposing version. +// This macro enables us to perform thiscall resolution simply by #including +// after the asio #includes (this file _must_ be +// included _after_ the asio #includes) + +#define ASIOInit(name) IASIOThiscallResolver::ASIOInit((name)) + + +#endif /* !defined(_MSC_VER) */ + +#endif /* Win32 */ + +#endif /* included_iasiothiscallresolver_h */ + + diff --git a/extern/portaudio/src/hostapi/asio/pa_asio.cpp b/extern/portaudio/src/hostapi/asio/pa_asio.cpp new file mode 100644 index 0000000..f230d87 --- /dev/null +++ b/extern/portaudio/src/hostapi/asio/pa_asio.cpp @@ -0,0 +1,4251 @@ +/* + * $Id$ + * Portable Audio I/O Library for ASIO Drivers + * + * Author: Stephane Letz + * Based on the Open Source API proposed by Ross Bencina + * Copyright (c) 2000-2002 Stephane Letz, Phil Burk, Ross Bencina + * Blocking i/o implementation by Sven Fischer, Institute of Hearing + * Technology and Audiology (www.hoertechnik-audiologie.de) + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +/* Modification History + + 08-03-01 First version : Stephane Letz + 08-06-01 Tweaks for PC, use C++, buffer allocation, Float32 to Int32 conversion : Phil Burk + 08-20-01 More conversion, PA_StreamTime, Pa_GetHostError : Stephane Letz + 08-21-01 PaUInt8 bug correction, implementation of ASIOSTFloat32LSB and ASIOSTFloat32MSB native formats : Stephane Letz + 08-24-01 MAX_INT32_FP hack, another Uint8 fix : Stephane and Phil + 08-27-01 Implementation of hostBufferSize < userBufferSize case, better management of the ouput buffer when + the stream is stopped : Stephane Letz + 08-28-01 Check the stream pointer for null in bufferSwitchTimeInfo, correct bug in bufferSwitchTimeInfo when + the stream is stopped : Stephane Letz + 10-12-01 Correct the PaHost_CalcNumHostBuffers function: computes FramesPerHostBuffer to be the lowest that + respect requested FramesPerUserBuffer and userBuffersPerHostBuffer : Stephane Letz + 10-26-01 Management of hostBufferSize and userBufferSize of any size : Stephane Letz + 10-27-01 Improve calculus of hostBufferSize to be multiple or divisor of userBufferSize if possible : Stephane and Phil + 10-29-01 Change MAX_INT32_FP to (2147483520.0f) to prevent roundup to 0x80000000 : Phil Burk + 10-31-01 Clear the ouput buffer and user buffers in PaHost_StartOutput, correct bug in GetFirstMultiple : Stephane Letz + 11-06-01 Rename functions : Stephane Letz + 11-08-01 New Pa_ASIO_Adaptor_Init function to init Callback adpatation variables, cleanup of Pa_ASIO_Callback_Input: Stephane Letz + 11-29-01 Break apart device loading to debug random failure in Pa_ASIO_QueryDeviceInfo ; Phil Burk + 01-03-02 Desallocate all resources in PaHost_Term for cases where Pa_CloseStream is not called properly : Stephane Letz + 02-01-02 Cleanup, test of multiple-stream opening : Stephane Letz + 19-02-02 New Pa_ASIO_loadDriver that calls CoInitialize on each thread on Windows : Stephane Letz + 09-04-02 Correct error code management in PaHost_Term, removes various compiler warning : Stephane Letz + 12-04-02 Add Mac includes for and : Phil Burk + 13-04-02 Removes another compiler warning : Stephane Letz + 30-04-02 Pa_ASIO_QueryDeviceInfo bug correction, memory allocation checking, better error handling : D Viens, P Burk, S Letz + 12-06-02 Rehashed into new multi-api infrastructure, added support for all ASIO sample formats : Ross Bencina + 18-06-02 Added pa_asio.h, PaAsio_GetAvailableLatencyValues() : Ross B. + 21-06-02 Added SelectHostBufferSize() which selects host buffer size based on user latency parameters : Ross Bencina + ** NOTE maintanance history is now stored in CVS ** +*/ + +/** @file + @ingroup hostapi_src + + Note that specific support for paInputUnderflow, paOutputOverflow and + paNeverDropInput is not necessary or possible with this driver due to the + synchronous full duplex double-buffered architecture of ASIO. +*/ + + +#include +#include +#include +//#include +#include + +#include +#include + +#include "portaudio.h" +#include "pa_asio.h" +#include "pa_util.h" +#include "pa_allocation.h" +#include "pa_hostapi.h" +#include "pa_stream.h" +#include "pa_cpuload.h" +#include "pa_process.h" +#include "pa_debugprint.h" +#include "pa_ringbuffer.h" + +#include "pa_win_coinitialize.h" + +/* This version of pa_asio.cpp is currently only targetted at Win32, + It would require a few tweaks to work with pre-OS X Macintosh. + To make configuration easier, we define WIN32 here to make sure + that the ASIO SDK knows this is Win32. +*/ +#ifndef WIN32 +#define WIN32 +#endif + +#include "asiosys.h" +#include "asio.h" +#include "asiodrivers.h" +#include "iasiothiscallresolver.h" + +/* +#if MAC +#include +#include +#include +#else +*/ +/* +#include +#include +#include +*/ +/* +#endif +*/ + + +/* winmm.lib is needed for timeGetTime() (this is in winmm.a if you're using gcc) */ +#if (defined(WIN32) && (defined(_MSC_VER) && (_MSC_VER >= 1200))) /* MSC version 6 and above */ +#pragma comment(lib, "winmm.lib") +#endif + + +/* external reference to ASIO SDK's asioDrivers. + + This is a bit messy because we want to explicitly manage + allocation/deallocation of this structure, but some layers of the SDK + which we currently use (eg the implementation in asio.cpp) still + use this global version. + + For now we keep it in sync with our local instance in the host + API representation structure, but later we should be able to remove + all dependence on it. +*/ +extern AsioDrivers* asioDrivers; + + +/* We are trying to be compatible with CARBON but this has not been thoroughly tested. */ +/* not tested at all since new V19 code was introduced. */ +#define CARBON_COMPATIBLE (0) + + +/* prototypes for functions declared in this file */ + +extern "C" PaError PaAsio_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex ); +static void Terminate( struct PaUtilHostApiRepresentation *hostApi ); +static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, + PaStream** s, + const PaStreamParameters *inputParameters, + const PaStreamParameters *outputParameters, + double sampleRate, + unsigned long framesPerBuffer, + PaStreamFlags streamFlags, + PaStreamCallback *streamCallback, + void *userData ); +static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi, + const PaStreamParameters *inputParameters, + const PaStreamParameters *outputParameters, + double sampleRate ); +static PaError CloseStream( PaStream* stream ); +static PaError StartStream( PaStream *stream ); +static PaError StopStream( PaStream *stream ); +static PaError AbortStream( PaStream *stream ); +static PaError IsStreamStopped( PaStream *s ); +static PaError IsStreamActive( PaStream *stream ); +static PaTime GetStreamTime( PaStream *stream ); +static double GetStreamCpuLoad( PaStream* stream ); +static PaError ReadStream( PaStream* stream, void *buffer, unsigned long frames ); +static PaError WriteStream( PaStream* stream, const void *buffer, unsigned long frames ); +static signed long GetStreamReadAvailable( PaStream* stream ); +static signed long GetStreamWriteAvailable( PaStream* stream ); + +/* Blocking i/o callback function. */ +static int BlockingIoPaCallback(const void *inputBuffer , + void *outputBuffer , + unsigned long framesPerBuffer, + const PaStreamCallbackTimeInfo *timeInfo , + PaStreamCallbackFlags statusFlags , + void *userData ); + +/* our ASIO callback functions */ + +static void bufferSwitch(long index, ASIOBool processNow); +static ASIOTime *bufferSwitchTimeInfo(ASIOTime *timeInfo, long index, ASIOBool processNow); +static void sampleRateChanged(ASIOSampleRate sRate); +static long asioMessages(long selector, long value, void* message, double* opt); + +static ASIOCallbacks asioCallbacks_ = + { bufferSwitch, sampleRateChanged, asioMessages, bufferSwitchTimeInfo }; + + +#define PA_ASIO_SET_LAST_HOST_ERROR( errorCode, errorText ) \ + PaUtil_SetLastHostErrorInfo( paASIO, errorCode, errorText ) + + +static void PaAsio_SetLastSystemError( DWORD errorCode ) +{ + LPVOID lpMsgBuf; + FormatMessage( + FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, + NULL, + errorCode, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPTSTR) &lpMsgBuf, + 0, + NULL + ); + PaUtil_SetLastHostErrorInfo( paASIO, errorCode, (const char*)lpMsgBuf ); + LocalFree( lpMsgBuf ); +} + +#define PA_ASIO_SET_LAST_SYSTEM_ERROR( errorCode ) \ + PaAsio_SetLastSystemError( errorCode ) + + +static const char* PaAsio_GetAsioErrorText( ASIOError asioError ) +{ + const char *result; + + switch( asioError ){ + case ASE_OK: + case ASE_SUCCESS: result = "Success"; break; + case ASE_NotPresent: result = "Hardware input or output is not present or available"; break; + case ASE_HWMalfunction: result = "Hardware is malfunctioning"; break; + case ASE_InvalidParameter: result = "Input parameter invalid"; break; + case ASE_InvalidMode: result = "Hardware is in a bad mode or used in a bad mode"; break; + case ASE_SPNotAdvancing: result = "Hardware is not running when sample position is inquired"; break; + case ASE_NoClock: result = "Sample clock or rate cannot be determined or is not present"; break; + case ASE_NoMemory: result = "Not enough memory for completing the request"; break; + default: result = "Unknown ASIO error"; break; + } + + return result; +} + + +#define PA_ASIO_SET_LAST_ASIO_ERROR( asioError ) \ + PaUtil_SetLastHostErrorInfo( paASIO, asioError, PaAsio_GetAsioErrorText( asioError ) ) + + + + +// Atomic increment and decrement operations +#if MAC + /* need to be implemented on Mac */ + inline long PaAsio_AtomicIncrement(volatile long* v) {return ++(*const_cast(v));} + inline long PaAsio_AtomicDecrement(volatile long* v) {return --(*const_cast(v));} +#elif WINDOWS + inline long PaAsio_AtomicIncrement(volatile long* v) {return InterlockedIncrement(const_cast(v));} + inline long PaAsio_AtomicDecrement(volatile long* v) {return InterlockedDecrement(const_cast(v));} +#endif + + + +typedef struct PaAsioDriverInfo +{ + ASIODriverInfo asioDriverInfo; + long inputChannelCount, outputChannelCount; + long bufferMinSize, bufferMaxSize, bufferPreferredSize, bufferGranularity; + bool postOutput; +} +PaAsioDriverInfo; + + +/* PaAsioHostApiRepresentation - host api datastructure specific to this implementation */ + +typedef struct +{ + PaUtilHostApiRepresentation inheritedHostApiRep; + PaUtilStreamInterface callbackStreamInterface; + PaUtilStreamInterface blockingStreamInterface; + + PaUtilAllocationGroup *allocations; + + PaWinUtilComInitializationResult comInitializationResult; + + AsioDrivers *asioDrivers; + void *systemSpecific; + + /* the ASIO C API only allows one ASIO driver to be open at a time, + so we keep track of whether we have the driver open here, and + use this information to return errors from OpenStream if the + driver is already open. + + openAsioDeviceIndex will be PaNoDevice if there is no device open + and a valid pa_asio (not global) device index otherwise. + + openAsioDriverInfo is populated with the driver info for the + currently open device (if any) + */ + PaDeviceIndex openAsioDeviceIndex; + PaAsioDriverInfo openAsioDriverInfo; +} +PaAsioHostApiRepresentation; + + +/* + Retrieve driver names from ASIO, returned in a char** + allocated in . +*/ +static char **GetAsioDriverNames( PaAsioHostApiRepresentation *asioHostApi, PaUtilAllocationGroup *group, long driverCount ) +{ + char **result = 0; + int i; + + result =(char**)PaUtil_GroupAllocateMemory( + group, sizeof(char*) * driverCount ); + if( !result ) + goto error; + + result[0] = (char*)PaUtil_GroupAllocateMemory( + group, 32 * driverCount ); + if( !result[0] ) + goto error; + + for( i=0; iasioDrivers->getDriverNames( result, driverCount ); + +error: + return result; +} + + +static PaSampleFormat AsioSampleTypeToPaNativeSampleFormat(ASIOSampleType type) +{ + switch (type) { + case ASIOSTInt16MSB: + case ASIOSTInt16LSB: + return paInt16; + + case ASIOSTFloat32MSB: + case ASIOSTFloat32LSB: + case ASIOSTFloat64MSB: + case ASIOSTFloat64LSB: + return paFloat32; + + case ASIOSTInt32MSB: + case ASIOSTInt32LSB: + case ASIOSTInt32MSB16: + case ASIOSTInt32LSB16: + case ASIOSTInt32MSB18: + case ASIOSTInt32MSB20: + case ASIOSTInt32MSB24: + case ASIOSTInt32LSB18: + case ASIOSTInt32LSB20: + case ASIOSTInt32LSB24: + return paInt32; + + case ASIOSTInt24MSB: + case ASIOSTInt24LSB: + return paInt24; + + default: + return paCustomFormat; + } +} + +void AsioSampleTypeLOG(ASIOSampleType type) +{ + switch (type) { + case ASIOSTInt16MSB: PA_DEBUG(("ASIOSTInt16MSB\n")); break; + case ASIOSTInt16LSB: PA_DEBUG(("ASIOSTInt16LSB\n")); break; + case ASIOSTFloat32MSB:PA_DEBUG(("ASIOSTFloat32MSB\n"));break; + case ASIOSTFloat32LSB:PA_DEBUG(("ASIOSTFloat32LSB\n"));break; + case ASIOSTFloat64MSB:PA_DEBUG(("ASIOSTFloat64MSB\n"));break; + case ASIOSTFloat64LSB:PA_DEBUG(("ASIOSTFloat64LSB\n"));break; + case ASIOSTInt32MSB: PA_DEBUG(("ASIOSTInt32MSB\n")); break; + case ASIOSTInt32LSB: PA_DEBUG(("ASIOSTInt32LSB\n")); break; + case ASIOSTInt32MSB16:PA_DEBUG(("ASIOSTInt32MSB16\n"));break; + case ASIOSTInt32LSB16:PA_DEBUG(("ASIOSTInt32LSB16\n"));break; + case ASIOSTInt32MSB18:PA_DEBUG(("ASIOSTInt32MSB18\n"));break; + case ASIOSTInt32MSB20:PA_DEBUG(("ASIOSTInt32MSB20\n"));break; + case ASIOSTInt32MSB24:PA_DEBUG(("ASIOSTInt32MSB24\n"));break; + case ASIOSTInt32LSB18:PA_DEBUG(("ASIOSTInt32LSB18\n"));break; + case ASIOSTInt32LSB20:PA_DEBUG(("ASIOSTInt32LSB20\n"));break; + case ASIOSTInt32LSB24:PA_DEBUG(("ASIOSTInt32LSB24\n"));break; + case ASIOSTInt24MSB: PA_DEBUG(("ASIOSTInt24MSB\n")); break; + case ASIOSTInt24LSB: PA_DEBUG(("ASIOSTInt24LSB\n")); break; + default: PA_DEBUG(("Custom Format%d\n",type));break; + + } +} + +static int BytesPerAsioSample( ASIOSampleType sampleType ) +{ + switch (sampleType) { + case ASIOSTInt16MSB: + case ASIOSTInt16LSB: + return 2; + + case ASIOSTFloat64MSB: + case ASIOSTFloat64LSB: + return 8; + + case ASIOSTFloat32MSB: + case ASIOSTFloat32LSB: + case ASIOSTInt32MSB: + case ASIOSTInt32LSB: + case ASIOSTInt32MSB16: + case ASIOSTInt32LSB16: + case ASIOSTInt32MSB18: + case ASIOSTInt32MSB20: + case ASIOSTInt32MSB24: + case ASIOSTInt32LSB18: + case ASIOSTInt32LSB20: + case ASIOSTInt32LSB24: + return 4; + + case ASIOSTInt24MSB: + case ASIOSTInt24LSB: + return 3; + + default: + return 0; + } +} + + +static void Swap16( void *buffer, long shift, long count ) +{ + unsigned short *p = (unsigned short*)buffer; + unsigned short temp; + (void) shift; /* unused parameter */ + + while( count-- ) + { + temp = *p; + *p++ = (unsigned short)((temp<<8) | (temp>>8)); + } +} + +static void Swap24( void *buffer, long shift, long count ) +{ + unsigned char *p = (unsigned char*)buffer; + unsigned char temp; + (void) shift; /* unused parameter */ + + while( count-- ) + { + temp = *p; + *p = *(p+2); + *(p+2) = temp; + p += 3; + } +} + +#define PA_SWAP32_( x ) ((x>>24) | ((x>>8)&0xFF00) | ((x<<8)&0xFF0000) | (x<<24)); + +static void Swap32( void *buffer, long shift, long count ) +{ + unsigned long *p = (unsigned long*)buffer; + unsigned long temp; + (void) shift; /* unused parameter */ + + while( count-- ) + { + temp = *p; + *p++ = PA_SWAP32_( temp); + } +} + +static void SwapShiftLeft32( void *buffer, long shift, long count ) +{ + unsigned long *p = (unsigned long*)buffer; + unsigned long temp; + + while( count-- ) + { + temp = *p; + temp = PA_SWAP32_( temp); + *p++ = temp << shift; + } +} + +static void ShiftRightSwap32( void *buffer, long shift, long count ) +{ + unsigned long *p = (unsigned long*)buffer; + unsigned long temp; + + while( count-- ) + { + temp = *p >> shift; + *p++ = PA_SWAP32_( temp); + } +} + +static void ShiftLeft32( void *buffer, long shift, long count ) +{ + unsigned long *p = (unsigned long*)buffer; + unsigned long temp; + + while( count-- ) + { + temp = *p; + *p++ = temp << shift; + } +} + +static void ShiftRight32( void *buffer, long shift, long count ) +{ + unsigned long *p = (unsigned long*)buffer; + unsigned long temp; + + while( count-- ) + { + temp = *p; + *p++ = temp >> shift; + } +} + +#define PA_SWAP_( x, y ) temp=x; x = y; y = temp; + +static void Swap64ConvertFloat64ToFloat32( void *buffer, long shift, long count ) +{ + double *in = (double*)buffer; + float *out = (float*)buffer; + unsigned char *p; + unsigned char temp; + (void) shift; /* unused parameter */ + + while( count-- ) + { + p = (unsigned char*)in; + PA_SWAP_( p[0], p[7] ); + PA_SWAP_( p[1], p[6] ); + PA_SWAP_( p[2], p[5] ); + PA_SWAP_( p[3], p[4] ); + + *out++ = (float) (*in++); + } +} + +static void ConvertFloat64ToFloat32( void *buffer, long shift, long count ) +{ + double *in = (double*)buffer; + float *out = (float*)buffer; + (void) shift; /* unused parameter */ + + while( count-- ) + *out++ = (float) (*in++); +} + +static void ConvertFloat32ToFloat64Swap64( void *buffer, long shift, long count ) +{ + float *in = ((float*)buffer) + (count-1); + double *out = ((double*)buffer) + (count-1); + unsigned char *p; + unsigned char temp; + (void) shift; /* unused parameter */ + + while( count-- ) + { + *out = *in--; + + p = (unsigned char*)out; + PA_SWAP_( p[0], p[7] ); + PA_SWAP_( p[1], p[6] ); + PA_SWAP_( p[2], p[5] ); + PA_SWAP_( p[3], p[4] ); + + out--; + } +} + +static void ConvertFloat32ToFloat64( void *buffer, long shift, long count ) +{ + float *in = ((float*)buffer) + (count-1); + double *out = ((double*)buffer) + (count-1); + (void) shift; /* unused parameter */ + + while( count-- ) + *out-- = *in--; +} + +#ifdef MAC +#define PA_MSB_IS_NATIVE_ +#undef PA_LSB_IS_NATIVE_ +#endif + +#ifdef WINDOWS +#undef PA_MSB_IS_NATIVE_ +#define PA_LSB_IS_NATIVE_ +#endif + +typedef void PaAsioBufferConverter( void *, long, long ); + +static void SelectAsioToPaConverter( ASIOSampleType type, PaAsioBufferConverter **converter, long *shift ) +{ + *shift = 0; + *converter = 0; + + switch (type) { + case ASIOSTInt16MSB: + /* dest: paInt16, no conversion necessary, possible byte swap*/ + #ifdef PA_LSB_IS_NATIVE_ + *converter = Swap16; + #endif + break; + case ASIOSTInt16LSB: + /* dest: paInt16, no conversion necessary, possible byte swap*/ + #ifdef PA_MSB_IS_NATIVE_ + *converter = Swap16; + #endif + break; + case ASIOSTFloat32MSB: + /* dest: paFloat32, no conversion necessary, possible byte swap*/ + #ifdef PA_LSB_IS_NATIVE_ + *converter = Swap32; + #endif + break; + case ASIOSTFloat32LSB: + /* dest: paFloat32, no conversion necessary, possible byte swap*/ + #ifdef PA_MSB_IS_NATIVE_ + *converter = Swap32; + #endif + break; + case ASIOSTFloat64MSB: + /* dest: paFloat32, in-place conversion to/from float32, possible byte swap*/ + #ifdef PA_LSB_IS_NATIVE_ + *converter = Swap64ConvertFloat64ToFloat32; + #else + *converter = ConvertFloat64ToFloat32; + #endif + break; + case ASIOSTFloat64LSB: + /* dest: paFloat32, in-place conversion to/from float32, possible byte swap*/ + #ifdef PA_MSB_IS_NATIVE_ + *converter = Swap64ConvertFloat64ToFloat32; + #else + *converter = ConvertFloat64ToFloat32; + #endif + break; + case ASIOSTInt32MSB: + /* dest: paInt32, no conversion necessary, possible byte swap */ + #ifdef PA_LSB_IS_NATIVE_ + *converter = Swap32; + #endif + break; + case ASIOSTInt32LSB: + /* dest: paInt32, no conversion necessary, possible byte swap */ + #ifdef PA_MSB_IS_NATIVE_ + *converter = Swap32; + #endif + break; + case ASIOSTInt32MSB16: + /* dest: paInt32, 16 bit shift, possible byte swap */ + #ifdef PA_LSB_IS_NATIVE_ + *converter = SwapShiftLeft32; + #else + *converter = ShiftLeft32; + #endif + *shift = 16; + break; + case ASIOSTInt32MSB18: + /* dest: paInt32, 14 bit shift, possible byte swap */ + #ifdef PA_LSB_IS_NATIVE_ + *converter = SwapShiftLeft32; + #else + *converter = ShiftLeft32; + #endif + *shift = 14; + break; + case ASIOSTInt32MSB20: + /* dest: paInt32, 12 bit shift, possible byte swap */ + #ifdef PA_LSB_IS_NATIVE_ + *converter = SwapShiftLeft32; + #else + *converter = ShiftLeft32; + #endif + *shift = 12; + break; + case ASIOSTInt32MSB24: + /* dest: paInt32, 8 bit shift, possible byte swap */ + #ifdef PA_LSB_IS_NATIVE_ + *converter = SwapShiftLeft32; + #else + *converter = ShiftLeft32; + #endif + *shift = 8; + break; + case ASIOSTInt32LSB16: + /* dest: paInt32, 16 bit shift, possible byte swap */ + #ifdef PA_MSB_IS_NATIVE_ + *converter = SwapShiftLeft32; + #else + *converter = ShiftLeft32; + #endif + *shift = 16; + break; + case ASIOSTInt32LSB18: + /* dest: paInt32, 14 bit shift, possible byte swap */ + #ifdef PA_MSB_IS_NATIVE_ + *converter = SwapShiftLeft32; + #else + *converter = ShiftLeft32; + #endif + *shift = 14; + break; + case ASIOSTInt32LSB20: + /* dest: paInt32, 12 bit shift, possible byte swap */ + #ifdef PA_MSB_IS_NATIVE_ + *converter = SwapShiftLeft32; + #else + *converter = ShiftLeft32; + #endif + *shift = 12; + break; + case ASIOSTInt32LSB24: + /* dest: paInt32, 8 bit shift, possible byte swap */ + #ifdef PA_MSB_IS_NATIVE_ + *converter = SwapShiftLeft32; + #else + *converter = ShiftLeft32; + #endif + *shift = 8; + break; + case ASIOSTInt24MSB: + /* dest: paInt24, no conversion necessary, possible byte swap */ + #ifdef PA_LSB_IS_NATIVE_ + *converter = Swap24; + #endif + break; + case ASIOSTInt24LSB: + /* dest: paInt24, no conversion necessary, possible byte swap */ + #ifdef PA_MSB_IS_NATIVE_ + *converter = Swap24; + #endif + break; + } +} + + +static void SelectPaToAsioConverter( ASIOSampleType type, PaAsioBufferConverter **converter, long *shift ) +{ + *shift = 0; + *converter = 0; + + switch (type) { + case ASIOSTInt16MSB: + /* src: paInt16, no conversion necessary, possible byte swap*/ + #ifdef PA_LSB_IS_NATIVE_ + *converter = Swap16; + #endif + break; + case ASIOSTInt16LSB: + /* src: paInt16, no conversion necessary, possible byte swap*/ + #ifdef PA_MSB_IS_NATIVE_ + *converter = Swap16; + #endif + break; + case ASIOSTFloat32MSB: + /* src: paFloat32, no conversion necessary, possible byte swap*/ + #ifdef PA_LSB_IS_NATIVE_ + *converter = Swap32; + #endif + break; + case ASIOSTFloat32LSB: + /* src: paFloat32, no conversion necessary, possible byte swap*/ + #ifdef PA_MSB_IS_NATIVE_ + *converter = Swap32; + #endif + break; + case ASIOSTFloat64MSB: + /* src: paFloat32, in-place conversion to/from float32, possible byte swap*/ + #ifdef PA_LSB_IS_NATIVE_ + *converter = ConvertFloat32ToFloat64Swap64; + #else + *converter = ConvertFloat32ToFloat64; + #endif + break; + case ASIOSTFloat64LSB: + /* src: paFloat32, in-place conversion to/from float32, possible byte swap*/ + #ifdef PA_MSB_IS_NATIVE_ + *converter = ConvertFloat32ToFloat64Swap64; + #else + *converter = ConvertFloat32ToFloat64; + #endif + break; + case ASIOSTInt32MSB: + /* src: paInt32, no conversion necessary, possible byte swap */ + #ifdef PA_LSB_IS_NATIVE_ + *converter = Swap32; + #endif + break; + case ASIOSTInt32LSB: + /* src: paInt32, no conversion necessary, possible byte swap */ + #ifdef PA_MSB_IS_NATIVE_ + *converter = Swap32; + #endif + break; + case ASIOSTInt32MSB16: + /* src: paInt32, 16 bit shift, possible byte swap */ + #ifdef PA_LSB_IS_NATIVE_ + *converter = ShiftRightSwap32; + #else + *converter = ShiftRight32; + #endif + *shift = 16; + break; + case ASIOSTInt32MSB18: + /* src: paInt32, 14 bit shift, possible byte swap */ + #ifdef PA_LSB_IS_NATIVE_ + *converter = ShiftRightSwap32; + #else + *converter = ShiftRight32; + #endif + *shift = 14; + break; + case ASIOSTInt32MSB20: + /* src: paInt32, 12 bit shift, possible byte swap */ + #ifdef PA_LSB_IS_NATIVE_ + *converter = ShiftRightSwap32; + #else + *converter = ShiftRight32; + #endif + *shift = 12; + break; + case ASIOSTInt32MSB24: + /* src: paInt32, 8 bit shift, possible byte swap */ + #ifdef PA_LSB_IS_NATIVE_ + *converter = ShiftRightSwap32; + #else + *converter = ShiftRight32; + #endif + *shift = 8; + break; + case ASIOSTInt32LSB16: + /* src: paInt32, 16 bit shift, possible byte swap */ + #ifdef PA_MSB_IS_NATIVE_ + *converter = ShiftRightSwap32; + #else + *converter = ShiftRight32; + #endif + *shift = 16; + break; + case ASIOSTInt32LSB18: + /* src: paInt32, 14 bit shift, possible byte swap */ + #ifdef PA_MSB_IS_NATIVE_ + *converter = ShiftRightSwap32; + #else + *converter = ShiftRight32; + #endif + *shift = 14; + break; + case ASIOSTInt32LSB20: + /* src: paInt32, 12 bit shift, possible byte swap */ + #ifdef PA_MSB_IS_NATIVE_ + *converter = ShiftRightSwap32; + #else + *converter = ShiftRight32; + #endif + *shift = 12; + break; + case ASIOSTInt32LSB24: + /* src: paInt32, 8 bit shift, possible byte swap */ + #ifdef PA_MSB_IS_NATIVE_ + *converter = ShiftRightSwap32; + #else + *converter = ShiftRight32; + #endif + *shift = 8; + break; + case ASIOSTInt24MSB: + /* src: paInt24, no conversion necessary, possible byte swap */ + #ifdef PA_LSB_IS_NATIVE_ + *converter = Swap24; + #endif + break; + case ASIOSTInt24LSB: + /* src: paInt24, no conversion necessary, possible byte swap */ + #ifdef PA_MSB_IS_NATIVE_ + *converter = Swap24; + #endif + break; + } +} + + +typedef struct PaAsioDeviceInfo +{ + PaDeviceInfo commonDeviceInfo; + long minBufferSize; + long maxBufferSize; + long preferredBufferSize; + long bufferGranularity; + + ASIOChannelInfo *asioChannelInfos; +} +PaAsioDeviceInfo; + + +PaError PaAsio_GetAvailableBufferSizes( PaDeviceIndex device, + long *minBufferSizeFrames, long *maxBufferSizeFrames, long *preferredBufferSizeFrames, long *granularity ) +{ + PaError result; + PaUtilHostApiRepresentation *hostApi; + PaDeviceIndex hostApiDevice; + + result = PaUtil_GetHostApiRepresentation( &hostApi, paASIO ); + + if( result == paNoError ) + { + result = PaUtil_DeviceIndexToHostApiDeviceIndex( &hostApiDevice, device, hostApi ); + + if( result == paNoError ) + { + PaAsioDeviceInfo *asioDeviceInfo = + (PaAsioDeviceInfo*)hostApi->deviceInfos[hostApiDevice]; + + *minBufferSizeFrames = asioDeviceInfo->minBufferSize; + *maxBufferSizeFrames = asioDeviceInfo->maxBufferSize; + *preferredBufferSizeFrames = asioDeviceInfo->preferredBufferSize; + *granularity = asioDeviceInfo->bufferGranularity; + } + } + + return result; +} + +/* Unload whatever we loaded in LoadAsioDriver(). +*/ +static void UnloadAsioDriver( void ) +{ + ASIOExit(); +} + +/* + load the asio driver named by and return statistics about + the driver in info. If no error occurred, the driver will remain open + and must be closed by the called by calling UnloadAsioDriver() - if an error + is returned the driver will already be unloaded. +*/ +static PaError LoadAsioDriver( PaAsioHostApiRepresentation *asioHostApi, const char *driverName, + PaAsioDriverInfo *driverInfo, void *systemSpecific ) +{ + PaError result = paNoError; + ASIOError asioError; + int asioIsInitialized = 0; + + if( !asioHostApi->asioDrivers->loadDriver( const_cast(driverName) ) ) + { + result = paUnanticipatedHostError; + PA_ASIO_SET_LAST_HOST_ERROR( 0, "Failed to load ASIO driver" ); + goto error; + } + + memset( &driverInfo->asioDriverInfo, 0, sizeof(ASIODriverInfo) ); + driverInfo->asioDriverInfo.asioVersion = 2; + driverInfo->asioDriverInfo.sysRef = systemSpecific; + if( (asioError = ASIOInit( &driverInfo->asioDriverInfo )) != ASE_OK ) + { + result = paUnanticipatedHostError; + PA_ASIO_SET_LAST_ASIO_ERROR( asioError ); + goto error; + } + else + { + asioIsInitialized = 1; + } + + if( (asioError = ASIOGetChannels(&driverInfo->inputChannelCount, + &driverInfo->outputChannelCount)) != ASE_OK ) + { + result = paUnanticipatedHostError; + PA_ASIO_SET_LAST_ASIO_ERROR( asioError ); + goto error; + } + + if( (asioError = ASIOGetBufferSize(&driverInfo->bufferMinSize, + &driverInfo->bufferMaxSize, &driverInfo->bufferPreferredSize, + &driverInfo->bufferGranularity)) != ASE_OK ) + { + result = paUnanticipatedHostError; + PA_ASIO_SET_LAST_ASIO_ERROR( asioError ); + goto error; + } + + if( ASIOOutputReady() == ASE_OK ) + driverInfo->postOutput = true; + else + driverInfo->postOutput = false; + + return result; + +error: + if( asioIsInitialized ) + { + ASIOExit(); + } + + return result; +} + + +#define PA_DEFAULTSAMPLERATESEARCHORDER_COUNT_ 13 /* must be the same number of elements as in the array below */ +static ASIOSampleRate defaultSampleRateSearchOrder_[] + = {44100.0, 48000.0, 32000.0, 24000.0, 22050.0, 88200.0, 96000.0, + 192000.0, 16000.0, 12000.0, 11025.0, 9600.0, 8000.0 }; + + +static PaError InitPaDeviceInfoFromAsioDriver( PaAsioHostApiRepresentation *asioHostApi, + const char *driverName, int driverIndex, + PaDeviceInfo *deviceInfo, PaAsioDeviceInfo *asioDeviceInfo ) +{ + PaError result = paNoError; + + /* Due to the headless design of the ASIO API, drivers are free to write over data given to them (like M-Audio + drivers f.i.). This is an attempt to overcome that. */ + union _tag_local { + PaAsioDriverInfo info; + char _padding[4096]; + } paAsioDriver; + + asioDeviceInfo->asioChannelInfos = 0; /* we check this below to handle error cleanup */ + + result = LoadAsioDriver( asioHostApi, driverName, &paAsioDriver.info, asioHostApi->systemSpecific ); + if( result == paNoError ) + { + PA_DEBUG(("PaAsio_Initialize: drv:%d name = %s\n", driverIndex,deviceInfo->name)); + PA_DEBUG(("PaAsio_Initialize: drv:%d inputChannels = %d\n", driverIndex, paAsioDriver.info.inputChannelCount)); + PA_DEBUG(("PaAsio_Initialize: drv:%d outputChannels = %d\n", driverIndex, paAsioDriver.info.outputChannelCount)); + PA_DEBUG(("PaAsio_Initialize: drv:%d bufferMinSize = %d\n", driverIndex, paAsioDriver.info.bufferMinSize)); + PA_DEBUG(("PaAsio_Initialize: drv:%d bufferMaxSize = %d\n", driverIndex, paAsioDriver.info.bufferMaxSize)); + PA_DEBUG(("PaAsio_Initialize: drv:%d bufferPreferredSize = %d\n", driverIndex, paAsioDriver.info.bufferPreferredSize)); + PA_DEBUG(("PaAsio_Initialize: drv:%d bufferGranularity = %d\n", driverIndex, paAsioDriver.info.bufferGranularity)); + + deviceInfo->maxInputChannels = paAsioDriver.info.inputChannelCount; + deviceInfo->maxOutputChannels = paAsioDriver.info.outputChannelCount; + + deviceInfo->defaultSampleRate = 0.; + bool foundDefaultSampleRate = false; + for( int j=0; j < PA_DEFAULTSAMPLERATESEARCHORDER_COUNT_; ++j ) + { + ASIOError asioError = ASIOCanSampleRate( defaultSampleRateSearchOrder_[j] ); + if( asioError != ASE_NoClock && asioError != ASE_NotPresent ) + { + deviceInfo->defaultSampleRate = defaultSampleRateSearchOrder_[j]; + foundDefaultSampleRate = true; + break; + } + } + + PA_DEBUG(("PaAsio_Initialize: drv:%d defaultSampleRate = %f\n", driverIndex, deviceInfo->defaultSampleRate)); + + if( foundDefaultSampleRate ){ + + /* calculate default latency values from bufferPreferredSize + for default low latency, and bufferMaxSize + for default high latency. + use the default sample rate to convert from samples to + seconds. Without knowing what sample rate the user will + use this is the best we can do. + */ + + double defaultLowLatency = + paAsioDriver.info.bufferPreferredSize / deviceInfo->defaultSampleRate; + + deviceInfo->defaultLowInputLatency = defaultLowLatency; + deviceInfo->defaultLowOutputLatency = defaultLowLatency; + + double defaultHighLatency = + paAsioDriver.info.bufferMaxSize / deviceInfo->defaultSampleRate; + + if( defaultHighLatency < defaultLowLatency ) + defaultHighLatency = defaultLowLatency; /* just in case the driver returns something strange */ + + deviceInfo->defaultHighInputLatency = defaultHighLatency; + deviceInfo->defaultHighOutputLatency = defaultHighLatency; + + }else{ + + deviceInfo->defaultLowInputLatency = 0.; + deviceInfo->defaultLowOutputLatency = 0.; + deviceInfo->defaultHighInputLatency = 0.; + deviceInfo->defaultHighOutputLatency = 0.; + } + + PA_DEBUG(("PaAsio_Initialize: drv:%d defaultLowInputLatency = %f\n", driverIndex, deviceInfo->defaultLowInputLatency)); + PA_DEBUG(("PaAsio_Initialize: drv:%d defaultLowOutputLatency = %f\n", driverIndex, deviceInfo->defaultLowOutputLatency)); + PA_DEBUG(("PaAsio_Initialize: drv:%d defaultHighInputLatency = %f\n", driverIndex, deviceInfo->defaultHighInputLatency)); + PA_DEBUG(("PaAsio_Initialize: drv:%d defaultHighOutputLatency = %f\n", driverIndex, deviceInfo->defaultHighOutputLatency)); + + asioDeviceInfo->minBufferSize = paAsioDriver.info.bufferMinSize; + asioDeviceInfo->maxBufferSize = paAsioDriver.info.bufferMaxSize; + asioDeviceInfo->preferredBufferSize = paAsioDriver.info.bufferPreferredSize; + asioDeviceInfo->bufferGranularity = paAsioDriver.info.bufferGranularity; + + + asioDeviceInfo->asioChannelInfos = (ASIOChannelInfo*)PaUtil_GroupAllocateMemory( + asioHostApi->allocations, + sizeof(ASIOChannelInfo) * (deviceInfo->maxInputChannels + + deviceInfo->maxOutputChannels) ); + if( !asioDeviceInfo->asioChannelInfos ) + { + result = paInsufficientMemory; + goto error_unload; + } + + int a; + + for( a=0; a < deviceInfo->maxInputChannels; ++a ){ + asioDeviceInfo->asioChannelInfos[a].channel = a; + asioDeviceInfo->asioChannelInfos[a].isInput = ASIOTrue; + ASIOError asioError = ASIOGetChannelInfo( &asioDeviceInfo->asioChannelInfos[a] ); + if( asioError != ASE_OK ) + { + result = paUnanticipatedHostError; + PA_ASIO_SET_LAST_ASIO_ERROR( asioError ); + goto error_unload; + } + } + + for( a=0; a < deviceInfo->maxOutputChannels; ++a ){ + int b = deviceInfo->maxInputChannels + a; + asioDeviceInfo->asioChannelInfos[b].channel = a; + asioDeviceInfo->asioChannelInfos[b].isInput = ASIOFalse; + ASIOError asioError = ASIOGetChannelInfo( &asioDeviceInfo->asioChannelInfos[b] ); + if( asioError != ASE_OK ) + { + result = paUnanticipatedHostError; + PA_ASIO_SET_LAST_ASIO_ERROR( asioError ); + goto error_unload; + } + } + + /* unload the driver */ + UnloadAsioDriver(); + } + + return result; + +error_unload: + UnloadAsioDriver(); + + if( asioDeviceInfo->asioChannelInfos ){ + PaUtil_GroupFreeMemory( asioHostApi->allocations, asioDeviceInfo->asioChannelInfos ); + asioDeviceInfo->asioChannelInfos = 0; + } + + return result; +} + + +/* we look up IsDebuggerPresent at runtime incase it isn't present (on Win95 for example) */ +typedef BOOL (WINAPI *IsDebuggerPresentPtr)(VOID); +IsDebuggerPresentPtr IsDebuggerPresent_ = 0; +//FARPROC IsDebuggerPresent_ = 0; // this is the current way to do it apparently according to davidv + +PaError PaAsio_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex ) +{ + PaError result = paNoError; + int i, driverCount; + PaAsioHostApiRepresentation *asioHostApi; + PaAsioDeviceInfo *deviceInfoArray; + char **names; + asioHostApi = (PaAsioHostApiRepresentation*)PaUtil_AllocateMemory( sizeof(PaAsioHostApiRepresentation) ); + if( !asioHostApi ) + { + result = paInsufficientMemory; + goto error; + } + + memset( asioHostApi, 0, sizeof(PaAsioHostApiRepresentation) ); /* ensure all fields are zeroed. especially asioHostApi->allocations */ + + /* + We initialize COM ourselves here and uninitialize it in Terminate(). + This should be the only COM initialization needed in this module. + + The ASIO SDK may also initialize COM but since we want to reduce dependency + on the ASIO SDK we manage COM initialization ourselves. + + There used to be code that initialized COM in other situations + such as when creating a Stream. This made PA work when calling Pa_CreateStream + from a non-main thread. However we currently consider initialization + of COM in non-main threads to be the caller's responsibility. + */ + result = PaWinUtil_CoInitialize( paASIO, &asioHostApi->comInitializationResult ); + if( result != paNoError ) + { + goto error; + } + + asioHostApi->asioDrivers = 0; /* avoid surprises in our error handler below */ + + asioHostApi->allocations = PaUtil_CreateAllocationGroup(); + if( !asioHostApi->allocations ) + { + result = paInsufficientMemory; + goto error; + } + + /* Allocate the AsioDrivers() driver list (class from ASIO SDK) */ + try + { + asioHostApi->asioDrivers = new AsioDrivers(); /* invokes CoInitialize(0) in AsioDriverList::AsioDriverList */ + } + catch (std::bad_alloc) + { + asioHostApi->asioDrivers = 0; + } + /* some implementations of new (ie MSVC, see http://support.microsoft.com/?kbid=167733) + don't throw std::bad_alloc, so we also explicitly test for a null return. */ + if( asioHostApi->asioDrivers == 0 ) + { + result = paInsufficientMemory; + goto error; + } + + asioDrivers = asioHostApi->asioDrivers; /* keep SDK global in sync until we stop depending on it */ + + asioHostApi->systemSpecific = 0; + asioHostApi->openAsioDeviceIndex = paNoDevice; + + *hostApi = &asioHostApi->inheritedHostApiRep; + (*hostApi)->info.structVersion = 1; + + (*hostApi)->info.type = paASIO; + (*hostApi)->info.name = "ASIO"; + (*hostApi)->info.deviceCount = 0; + + #ifdef WINDOWS + /* use desktop window as system specific ptr */ + asioHostApi->systemSpecific = GetDesktopWindow(); + #endif + + /* driverCount is the number of installed drivers - not necessarily + the number of installed physical devices. */ + #if MAC + driverCount = asioHostApi->asioDrivers->getNumFragments(); + #elif WINDOWS + driverCount = asioHostApi->asioDrivers->asioGetNumDev(); + #endif + + if( driverCount > 0 ) + { + names = GetAsioDriverNames( asioHostApi, asioHostApi->allocations, driverCount ); + if( !names ) + { + result = paInsufficientMemory; + goto error; + } + + + /* allocate enough space for all drivers, even if some aren't installed */ + + (*hostApi)->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory( + asioHostApi->allocations, sizeof(PaDeviceInfo*) * driverCount ); + if( !(*hostApi)->deviceInfos ) + { + result = paInsufficientMemory; + goto error; + } + + /* allocate all device info structs in a contiguous block */ + deviceInfoArray = (PaAsioDeviceInfo*)PaUtil_GroupAllocateMemory( + asioHostApi->allocations, sizeof(PaAsioDeviceInfo) * driverCount ); + if( !deviceInfoArray ) + { + result = paInsufficientMemory; + goto error; + } + + IsDebuggerPresent_ = (IsDebuggerPresentPtr)GetProcAddress( LoadLibraryA( "Kernel32.dll" ), "IsDebuggerPresent" ); + + for( i=0; i < driverCount; ++i ) + { + PA_DEBUG(("ASIO names[%d]:%s\n",i,names[i])); + + // Since portaudio opens ALL ASIO drivers, and no one else does that, + // we face fact that some drivers were not meant for it, drivers which act + // like shells on top of REAL drivers, for instance. + // so we get duplicate handles, locks and other problems. + // so lets NOT try to load any such wrappers. + // The ones i [davidv] know of so far are: + + if ( strcmp (names[i],"ASIO DirectX Full Duplex Driver") == 0 + || strcmp (names[i],"ASIO Multimedia Driver") == 0 + || strncmp(names[i],"Premiere",8) == 0 //"Premiere Elements Windows Sound 1.0" + || strncmp(names[i],"Adobe",5) == 0 //"Adobe Default Windows Sound 1.5" + ) + { + PA_DEBUG(("BLACKLISTED!!!\n")); + continue; + } + + + if( IsDebuggerPresent_ && IsDebuggerPresent_() ) + { + /* ASIO Digidesign Driver uses PACE copy protection which quits out + if a debugger is running. So we don't load it if a debugger is running. */ + if( strcmp(names[i], "ASIO Digidesign Driver") == 0 ) + { + PA_DEBUG(("BLACKLISTED!!! ASIO Digidesign Driver would quit the debugger\n")); + continue; + } + } + + + /* Attempt to init device info from the asio driver... */ + { + PaAsioDeviceInfo *asioDeviceInfo = &deviceInfoArray[ (*hostApi)->info.deviceCount ]; + PaDeviceInfo *deviceInfo = &asioDeviceInfo->commonDeviceInfo; + + deviceInfo->structVersion = 2; + deviceInfo->hostApi = hostApiIndex; + + deviceInfo->name = names[i]; + + if( InitPaDeviceInfoFromAsioDriver( asioHostApi, names[i], i, deviceInfo, asioDeviceInfo ) == paNoError ) + { + (*hostApi)->deviceInfos[ (*hostApi)->info.deviceCount ] = deviceInfo; + ++(*hostApi)->info.deviceCount; + } + else + { + PA_DEBUG(("Skipping ASIO device:%s\n",names[i])); + continue; + } + } + } + } + + if( (*hostApi)->info.deviceCount > 0 ) + { + (*hostApi)->info.defaultInputDevice = 0; + (*hostApi)->info.defaultOutputDevice = 0; + } + else + { + (*hostApi)->info.defaultInputDevice = paNoDevice; + (*hostApi)->info.defaultOutputDevice = paNoDevice; + } + + + (*hostApi)->Terminate = Terminate; + (*hostApi)->OpenStream = OpenStream; + (*hostApi)->IsFormatSupported = IsFormatSupported; + + PaUtil_InitializeStreamInterface( &asioHostApi->callbackStreamInterface, CloseStream, StartStream, + StopStream, AbortStream, IsStreamStopped, IsStreamActive, + GetStreamTime, GetStreamCpuLoad, + PaUtil_DummyRead, PaUtil_DummyWrite, + PaUtil_DummyGetReadAvailable, PaUtil_DummyGetWriteAvailable ); + + PaUtil_InitializeStreamInterface( &asioHostApi->blockingStreamInterface, CloseStream, StartStream, + StopStream, AbortStream, IsStreamStopped, IsStreamActive, + GetStreamTime, PaUtil_DummyGetCpuLoad, + ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable ); + + return result; + +error: + if( asioHostApi ) + { + if( asioHostApi->allocations ) + { + PaUtil_FreeAllAllocations( asioHostApi->allocations ); + PaUtil_DestroyAllocationGroup( asioHostApi->allocations ); + } + + delete asioHostApi->asioDrivers; + asioDrivers = 0; /* keep SDK global in sync until we stop depending on it */ + + PaWinUtil_CoUninitialize( paASIO, &asioHostApi->comInitializationResult ); + + PaUtil_FreeMemory( asioHostApi ); + } + + return result; +} + + +static void Terminate( struct PaUtilHostApiRepresentation *hostApi ) +{ + PaAsioHostApiRepresentation *asioHostApi = (PaAsioHostApiRepresentation*)hostApi; + + /* + IMPLEMENT ME: + - clean up any resources not handled by the allocation group (need to review if there are any) + */ + + if( asioHostApi->allocations ) + { + PaUtil_FreeAllAllocations( asioHostApi->allocations ); + PaUtil_DestroyAllocationGroup( asioHostApi->allocations ); + } + + delete asioHostApi->asioDrivers; + asioDrivers = 0; /* keep SDK global in sync until we stop depending on it */ + + PaWinUtil_CoUninitialize( paASIO, &asioHostApi->comInitializationResult ); + + PaUtil_FreeMemory( asioHostApi ); +} + + +static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi, + const PaStreamParameters *inputParameters, + const PaStreamParameters *outputParameters, + double sampleRate ) +{ + PaError result = paNoError; + PaAsioHostApiRepresentation *asioHostApi = (PaAsioHostApiRepresentation*)hostApi; + PaAsioDriverInfo *driverInfo = &asioHostApi->openAsioDriverInfo; + int inputChannelCount, outputChannelCount; + PaSampleFormat inputSampleFormat, outputSampleFormat; + PaDeviceIndex asioDeviceIndex; + ASIOError asioError; + + if( inputParameters && outputParameters ) + { + /* full duplex ASIO stream must use the same device for input and output */ + + if( inputParameters->device != outputParameters->device ) + return paBadIODeviceCombination; + } + + if( inputParameters ) + { + inputChannelCount = inputParameters->channelCount; + inputSampleFormat = inputParameters->sampleFormat; + + /* all standard sample formats are supported by the buffer adapter, + this implementation doesn't support any custom sample formats */ + if( inputSampleFormat & paCustomFormat ) + return paSampleFormatNotSupported; + + /* unless alternate device specification is supported, reject the use of + paUseHostApiSpecificDeviceSpecification */ + + if( inputParameters->device == paUseHostApiSpecificDeviceSpecification ) + return paInvalidDevice; + + asioDeviceIndex = inputParameters->device; + + /* validate inputStreamInfo */ + /** @todo do more validation here */ + // if( inputParameters->hostApiSpecificStreamInfo ) + // return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */ + } + else + { + inputChannelCount = 0; + } + + if( outputParameters ) + { + outputChannelCount = outputParameters->channelCount; + outputSampleFormat = outputParameters->sampleFormat; + + /* all standard sample formats are supported by the buffer adapter, + this implementation doesn't support any custom sample formats */ + if( outputSampleFormat & paCustomFormat ) + return paSampleFormatNotSupported; + + /* unless alternate device specification is supported, reject the use of + paUseHostApiSpecificDeviceSpecification */ + + if( outputParameters->device == paUseHostApiSpecificDeviceSpecification ) + return paInvalidDevice; + + asioDeviceIndex = outputParameters->device; + + /* validate outputStreamInfo */ + /** @todo do more validation here */ + // if( outputParameters->hostApiSpecificStreamInfo ) + // return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */ + } + else + { + outputChannelCount = 0; + } + + + + /* if an ASIO device is open we can only get format information for the currently open device */ + + if( asioHostApi->openAsioDeviceIndex != paNoDevice + && asioHostApi->openAsioDeviceIndex != asioDeviceIndex ) + { + return paDeviceUnavailable; + } + + + /* NOTE: we load the driver and use its current settings + rather than the ones in our device info structure which may be stale */ + + /* open the device if it's not already open */ + if( asioHostApi->openAsioDeviceIndex == paNoDevice ) + { + result = LoadAsioDriver( asioHostApi, asioHostApi->inheritedHostApiRep.deviceInfos[ asioDeviceIndex ]->name, + driverInfo, asioHostApi->systemSpecific ); + if( result != paNoError ) + return result; + } + + /* check that input device can support inputChannelCount */ + if( inputChannelCount > 0 ) + { + if( inputChannelCount > driverInfo->inputChannelCount ) + { + result = paInvalidChannelCount; + goto done; + } + } + + /* check that output device can support outputChannelCount */ + if( outputChannelCount ) + { + if( outputChannelCount > driverInfo->outputChannelCount ) + { + result = paInvalidChannelCount; + goto done; + } + } + + /* query for sample rate support */ + asioError = ASIOCanSampleRate( sampleRate ); + if( asioError == ASE_NoClock || asioError == ASE_NotPresent ) + { + result = paInvalidSampleRate; + goto done; + } + +done: + /* close the device if it wasn't already open */ + if( asioHostApi->openAsioDeviceIndex == paNoDevice ) + { + UnloadAsioDriver(); /* not sure if we should check for errors here */ + } + + if( result == paNoError ) + return paFormatIsSupported; + else + return result; +} + + + +/** A data structure specifically for storing blocking i/o related data. */ +typedef struct PaAsioStreamBlockingState +{ + int stopFlag; /**< Flag indicating that block processing is to be stopped. */ + + unsigned long writeBuffersRequested; /**< The number of available output buffers, requested by the #WriteStream() function. */ + unsigned long readFramesRequested; /**< The number of available input frames, requested by the #ReadStream() function. */ + + int writeBuffersRequestedFlag; /**< Flag to indicate that #WriteStream() has requested more output buffers to be available. */ + int readFramesRequestedFlag; /**< Flag to indicate that #ReadStream() requires more input frames to be available. */ + + HANDLE writeBuffersReadyEvent; /**< Event to signal that requested output buffers are available. */ + HANDLE readFramesReadyEvent; /**< Event to signal that requested input frames are available. */ + + void *writeRingBufferData; /**< The actual ring buffer memory, used by the output ring buffer. */ + void *readRingBufferData; /**< The actual ring buffer memory, used by the input ring buffer. */ + + PaUtilRingBuffer writeRingBuffer; /**< Frame-aligned blocking i/o ring buffer to store output data (interleaved user format). */ + PaUtilRingBuffer readRingBuffer; /**< Frame-aligned blocking i/o ring buffer to store input data (interleaved user format). */ + + long writeRingBufferInitialFrames; /**< The initial number of silent frames within the output ring buffer. */ + + const void **writeStreamBuffer; /**< Temp buffer, used by #WriteStream() for handling non-interleaved data. */ + void **readStreamBuffer; /**< Temp buffer, used by #ReadStream() for handling non-interleaved data. */ + + PaUtilBufferProcessor bufferProcessor; /**< Buffer processor, used to handle the blocking i/o ring buffers. */ + + int outputUnderflowFlag; /**< Flag to signal an output underflow from within the callback function. */ + int inputOverflowFlag; /**< Flag to signal an input overflow from within the callback function. */ +} +PaAsioStreamBlockingState; + + + +/* PaAsioStream - a stream data structure specifically for this implementation */ + +typedef struct PaAsioStream +{ + PaUtilStreamRepresentation streamRepresentation; + PaUtilCpuLoadMeasurer cpuLoadMeasurer; + PaUtilBufferProcessor bufferProcessor; + + PaAsioHostApiRepresentation *asioHostApi; + unsigned long framesPerHostCallback; + + /* ASIO driver info - these may not be needed for the life of the stream, + but store them here until we work out how format conversion is going + to work. */ + + ASIOBufferInfo *asioBufferInfos; + ASIOChannelInfo *asioChannelInfos; + long asioInputLatencyFrames, asioOutputLatencyFrames; // actual latencies returned by asio + + long inputChannelCount, outputChannelCount; + bool postOutput; + + void **bufferPtrs; /* this is carved up for inputBufferPtrs and outputBufferPtrs */ + void **inputBufferPtrs[2]; + void **outputBufferPtrs[2]; + + PaAsioBufferConverter *inputBufferConverter; + long inputShift; + PaAsioBufferConverter *outputBufferConverter; + long outputShift; + + volatile bool stopProcessing; + int stopPlayoutCount; + HANDLE completedBuffersPlayedEvent; + + bool streamFinishedCallbackCalled; + int isStopped; + volatile int isActive; + volatile bool zeroOutput; /* all future calls to the callback will output silence */ + + volatile long reenterCount; + volatile long reenterError; + + PaStreamCallbackFlags callbackFlags; + + PaAsioStreamBlockingState *blockingState; /**< Blocking i/o data struct, or NULL when using callback interface. */ +} +PaAsioStream; + +static PaAsioStream *theAsioStream = 0; /* due to ASIO sdk limitations there can be only one stream */ + + +static void ZeroOutputBuffers( PaAsioStream *stream, long index ) +{ + int i; + + for( i=0; i < stream->outputChannelCount; ++i ) + { + void *buffer = stream->asioBufferInfos[ i + stream->inputChannelCount ].buffers[index]; + + int bytesPerSample = BytesPerAsioSample( stream->asioChannelInfos[ i + stream->inputChannelCount ].type ); + + memset( buffer, 0, stream->framesPerHostCallback * bytesPerSample ); + } +} + + +/* return the next power of two >= x. + Returns the input parameter if it is already a power of two. + http://stackoverflow.com/questions/364985/algorithm-for-finding-the-smallest-power-of-two-thats-greater-or-equal-to-a-giv +*/ +static unsigned long NextPowerOfTwo( unsigned long x ) +{ + --x; + x |= x >> 1; + x |= x >> 2; + x |= x >> 4; + x |= x >> 8; + x |= x >> 16; + /* If you needed to deal with numbers > 2^32 the following would be needed. + For latencies, we don't deal with values this large. + x |= x >> 16; + */ + + return x + 1; +} + + +static unsigned long SelectHostBufferSizeForUnspecifiedUserFramesPerBuffer( + unsigned long targetBufferingLatencyFrames, PaAsioDriverInfo *driverInfo ) +{ + /* Choose a host buffer size based only on targetBufferingLatencyFrames and the + device's supported buffer sizes. Always returns a valid value. + */ + + unsigned long result; + + if( targetBufferingLatencyFrames <= (unsigned long)driverInfo->bufferMinSize ) + { + result = driverInfo->bufferMinSize; + } + else if( targetBufferingLatencyFrames >= (unsigned long)driverInfo->bufferMaxSize ) + { + result = driverInfo->bufferMaxSize; + } + else + { + if( driverInfo->bufferGranularity == 0 ) /* single fixed host buffer size */ + { + /* The documentation states that bufferGranularity should be zero + when bufferMinSize, bufferMaxSize and bufferPreferredSize are the + same. We assume that is the case. + */ + + result = driverInfo->bufferPreferredSize; + } + else if( driverInfo->bufferGranularity == -1 ) /* power-of-two */ + { + /* We assume bufferMinSize and bufferMaxSize are powers of two. */ + + result = NextPowerOfTwo( targetBufferingLatencyFrames ); + + if( result < (unsigned long)driverInfo->bufferMinSize ) + result = driverInfo->bufferMinSize; + + if( result > (unsigned long)driverInfo->bufferMaxSize ) + result = driverInfo->bufferMaxSize; + } + else /* modulo bufferGranularity */ + { + /* round up to the next multiple of granularity */ + unsigned long n = (targetBufferingLatencyFrames + driverInfo->bufferGranularity - 1) + / driverInfo->bufferGranularity; + + result = n * driverInfo->bufferGranularity; + + if( result < (unsigned long)driverInfo->bufferMinSize ) + result = driverInfo->bufferMinSize; + + if( result > (unsigned long)driverInfo->bufferMaxSize ) + result = driverInfo->bufferMaxSize; + } + } + + return result; +} + + +static unsigned long SelectHostBufferSizeForSpecifiedUserFramesPerBuffer( + unsigned long targetBufferingLatencyFrames, unsigned long userFramesPerBuffer, + PaAsioDriverInfo *driverInfo ) +{ + /* Select a host buffer size conforming to targetBufferingLatencyFrames + and the device's supported buffer sizes. + The return value will always be a multiple of userFramesPerBuffer. + If a valid buffer size can not be found the function returns 0. + + The current implementation uses a simple iterative search for clarity. + Feel free to suggest a closed form solution. + */ + unsigned long result = 0; + + assert( userFramesPerBuffer != 0 ); + + if( driverInfo->bufferGranularity == 0 ) /* single fixed host buffer size */ + { + /* The documentation states that bufferGranularity should be zero + when bufferMinSize, bufferMaxSize and bufferPreferredSize are the + same. We assume that is the case. + */ + + if( (driverInfo->bufferPreferredSize % userFramesPerBuffer) == 0 ) + result = driverInfo->bufferPreferredSize; + } + else if( driverInfo->bufferGranularity == -1 ) /* power-of-two */ + { + /* We assume bufferMinSize and bufferMaxSize are powers of two. */ + + /* Search all powers of two in the range [bufferMinSize,bufferMaxSize] + for multiples of userFramesPerBuffer. We prefer the first multiple + that is equal or greater than targetBufferingLatencyFrames, or + failing that, the largest multiple less than + targetBufferingLatencyFrames. + */ + unsigned long x = (unsigned long)driverInfo->bufferMinSize; + do { + if( (x % userFramesPerBuffer) == 0 ) + { + /* any multiple of userFramesPerBuffer is acceptable */ + result = x; + if( result >= targetBufferingLatencyFrames ) + break; /* stop. a value >= to targetBufferingLatencyFrames is ideal. */ + } + + x *= 2; + } while( x <= (unsigned long)driverInfo->bufferMaxSize ); + } + else /* modulo granularity */ + { + /* We assume bufferMinSize is a multiple of bufferGranularity. */ + + /* Search all multiples of bufferGranularity in the range + [bufferMinSize,bufferMaxSize] for multiples of userFramesPerBuffer. + We prefer the first multiple that is equal or greater than + targetBufferingLatencyFrames, or failing that, the largest multiple + less than targetBufferingLatencyFrames. + */ + unsigned long x = (unsigned long)driverInfo->bufferMinSize; + do { + if( (x % userFramesPerBuffer) == 0 ) + { + /* any multiple of userFramesPerBuffer is acceptable */ + result = x; + if( result >= targetBufferingLatencyFrames ) + break; /* stop. a value >= to targetBufferingLatencyFrames is ideal. */ + } + + x += driverInfo->bufferGranularity; + } while( x <= (unsigned long)driverInfo->bufferMaxSize ); + } + + return result; +} + + +static unsigned long SelectHostBufferSize( + unsigned long targetBufferingLatencyFrames, + unsigned long userFramesPerBuffer, PaAsioDriverInfo *driverInfo ) +{ + unsigned long result = 0; + + /* We select a host buffer size based on the following requirements + (in priority order): + + 1. The host buffer size must be permissible according to the ASIO + driverInfo buffer size constraints (min, max, granularity or + powers-of-two). + + 2. If the user specifies a non-zero framesPerBuffer parameter + (userFramesPerBuffer here) the host buffer should be a multiple of + this (subject to the constraints in (1) above). + + [NOTE: Where no permissible host buffer size is a multiple of + userFramesPerBuffer, we choose a value as if userFramesPerBuffer were + zero (i.e. we ignore it). This strategy is open for review ~ perhaps + there are still "more optimal" buffer sizes related to + userFramesPerBuffer that we could use.] + + 3. The host buffer size should be greater than or equal to + targetBufferingLatencyFrames, subject to (1) and (2) above. Where it + is not possible to select a host buffer size equal or greater than + targetBufferingLatencyFrames, the highest buffer size conforming to + (1) and (2) should be chosen. + */ + + if( userFramesPerBuffer != 0 ) + { + /* userFramesPerBuffer is specified, try to find a buffer size that's + a multiple of it */ + result = SelectHostBufferSizeForSpecifiedUserFramesPerBuffer( + targetBufferingLatencyFrames, userFramesPerBuffer, driverInfo ); + } + + if( result == 0 ) + { + /* either userFramesPerBuffer was not specified, or we couldn't find a + host buffer size that is a multiple of it. Select a host buffer size + according to targetBufferingLatencyFrames and the ASIO driverInfo + buffer size constraints. + */ + result = SelectHostBufferSizeForUnspecifiedUserFramesPerBuffer( + targetBufferingLatencyFrames, driverInfo ); + } + + return result; +} + + +/* returns channelSelectors if present */ + +static PaError ValidateAsioSpecificStreamInfo( + const PaStreamParameters *streamParameters, + const PaAsioStreamInfo *streamInfo, + int deviceChannelCount, + int **channelSelectors ) +{ + if( streamInfo ) + { + if( streamInfo->size != sizeof( PaAsioStreamInfo ) + || streamInfo->version != 1 ) + { + return paIncompatibleHostApiSpecificStreamInfo; + } + + if( streamInfo->flags & paAsioUseChannelSelectors ) + *channelSelectors = streamInfo->channelSelectors; + + if( !(*channelSelectors) ) + return paIncompatibleHostApiSpecificStreamInfo; + + for( int i=0; i < streamParameters->channelCount; ++i ){ + if( (*channelSelectors)[i] < 0 + || (*channelSelectors)[i] >= deviceChannelCount ){ + return paInvalidChannelCount; + } + } + } + + return paNoError; +} + + +static bool IsUsingExternalClockSource() +{ + bool result = false; + ASIOError asioError; + ASIOClockSource clocks[32]; + long numSources=32; + + /* davidv: listing ASIO Clock sources. there is an ongoing investigation by + me about whether or not to call ASIOSetSampleRate if an external Clock is + used. A few drivers expected different things here */ + + asioError = ASIOGetClockSources(clocks, &numSources); + if( asioError != ASE_OK ){ + PA_DEBUG(("ERROR: ASIOGetClockSources: %s\n", PaAsio_GetAsioErrorText(asioError) )); + }else{ + PA_DEBUG(("INFO ASIOGetClockSources listing %d clocks\n", numSources )); + for (int i=0;iopenAsioDeviceIndex != paNoDevice ) + { + PA_DEBUG(("OpenStream paDeviceUnavailable\n")); + return paDeviceUnavailable; + } + + assert( theAsioStream == 0 ); + + if( inputParameters && outputParameters ) + { + /* full duplex ASIO stream must use the same device for input and output */ + + if( inputParameters->device != outputParameters->device ) + { + PA_DEBUG(("OpenStream paBadIODeviceCombination\n")); + return paBadIODeviceCombination; + } + } + + if( inputParameters ) + { + inputChannelCount = inputParameters->channelCount; + inputSampleFormat = inputParameters->sampleFormat; + suggestedInputLatencyFrames = (unsigned long)((inputParameters->suggestedLatency * sampleRate)+0.5f); + + /* unless alternate device specification is supported, reject the use of + paUseHostApiSpecificDeviceSpecification */ + if( inputParameters->device == paUseHostApiSpecificDeviceSpecification ) + return paInvalidDevice; + + asioDeviceIndex = inputParameters->device; + + PaAsioDeviceInfo *asioDeviceInfo = (PaAsioDeviceInfo*)hostApi->deviceInfos[asioDeviceIndex]; + + /* validate hostApiSpecificStreamInfo */ + inputStreamInfo = (PaAsioStreamInfo*)inputParameters->hostApiSpecificStreamInfo; + result = ValidateAsioSpecificStreamInfo( inputParameters, inputStreamInfo, + asioDeviceInfo->commonDeviceInfo.maxInputChannels, + &inputChannelSelectors + ); + if( result != paNoError ) return result; + } + else + { + inputChannelCount = 0; + inputSampleFormat = 0; + suggestedInputLatencyFrames = 0; + } + + if( outputParameters ) + { + outputChannelCount = outputParameters->channelCount; + outputSampleFormat = outputParameters->sampleFormat; + suggestedOutputLatencyFrames = (unsigned long)((outputParameters->suggestedLatency * sampleRate)+0.5f); + + /* unless alternate device specification is supported, reject the use of + paUseHostApiSpecificDeviceSpecification */ + if( outputParameters->device == paUseHostApiSpecificDeviceSpecification ) + return paInvalidDevice; + + asioDeviceIndex = outputParameters->device; + + PaAsioDeviceInfo *asioDeviceInfo = (PaAsioDeviceInfo*)hostApi->deviceInfos[asioDeviceIndex]; + + /* validate hostApiSpecificStreamInfo */ + outputStreamInfo = (PaAsioStreamInfo*)outputParameters->hostApiSpecificStreamInfo; + result = ValidateAsioSpecificStreamInfo( outputParameters, outputStreamInfo, + asioDeviceInfo->commonDeviceInfo.maxOutputChannels, + &outputChannelSelectors + ); + if( result != paNoError ) return result; + } + else + { + outputChannelCount = 0; + outputSampleFormat = 0; + suggestedOutputLatencyFrames = 0; + } + + driverInfo = &asioHostApi->openAsioDriverInfo; + + /* NOTE: we load the driver and use its current settings + rather than the ones in our device info structure which may be stale */ + + result = LoadAsioDriver( asioHostApi, asioHostApi->inheritedHostApiRep.deviceInfos[ asioDeviceIndex ]->name, + driverInfo, asioHostApi->systemSpecific ); + if( result == paNoError ) + asioIsInitialized = 1; + else{ + PA_DEBUG(("OpenStream ERROR1 - LoadAsioDriver returned %d\n", result)); + goto error; + } + + /* check that input device can support inputChannelCount */ + if( inputChannelCount > 0 ) + { + if( inputChannelCount > driverInfo->inputChannelCount ) + { + result = paInvalidChannelCount; + PA_DEBUG(("OpenStream ERROR2\n")); + goto error; + } + } + + /* check that output device can support outputChannelCount */ + if( outputChannelCount ) + { + if( outputChannelCount > driverInfo->outputChannelCount ) + { + result = paInvalidChannelCount; + PA_DEBUG(("OpenStream ERROR3\n")); + goto error; + } + } + + result = ValidateAndSetSampleRate( sampleRate ); + if( result != paNoError ) + goto error; + + /* + IMPLEMENT ME: + - if a full duplex stream is requested, check that the combination + of input and output parameters is supported + */ + + /* validate platform specific flags */ + if( (streamFlags & paPlatformSpecificFlags) != 0 ){ + PA_DEBUG(("OpenStream invalid flags!!\n")); + return paInvalidFlag; /* unexpected platform specific flag */ + } + + + stream = (PaAsioStream*)PaUtil_AllocateMemory( sizeof(PaAsioStream) ); + if( !stream ) + { + result = paInsufficientMemory; + PA_DEBUG(("OpenStream ERROR5\n")); + goto error; + } + stream->blockingState = NULL; /* Blocking i/o not initialized, yet. */ + + + stream->completedBuffersPlayedEvent = CreateEvent( NULL, TRUE, FALSE, NULL ); + if( stream->completedBuffersPlayedEvent == NULL ) + { + result = paUnanticipatedHostError; + PA_ASIO_SET_LAST_SYSTEM_ERROR( GetLastError() ); + PA_DEBUG(("OpenStream ERROR6\n")); + goto error; + } + completedBuffersPlayedEventInited = 1; + + + stream->asioBufferInfos = 0; /* for deallocation in error */ + stream->asioChannelInfos = 0; /* for deallocation in error */ + stream->bufferPtrs = 0; /* for deallocation in error */ + + /* Using blocking i/o interface... */ + if( usingBlockingIo ) + { + /* Blocking i/o is implemented by running callback mode, using a special blocking i/o callback. */ + streamCallback = BlockingIoPaCallback; /* Setup PA to use the ASIO blocking i/o callback. */ + userData = &theAsioStream; /* The callback user data will be the PA ASIO stream. */ + PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation, + &asioHostApi->blockingStreamInterface, streamCallback, userData ); + } + else /* Using callback interface... */ + { + PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation, + &asioHostApi->callbackStreamInterface, streamCallback, userData ); + } + + + PaUtil_InitializeCpuLoadMeasurer( &stream->cpuLoadMeasurer, sampleRate ); + + + stream->asioBufferInfos = (ASIOBufferInfo*)PaUtil_AllocateMemory( + sizeof(ASIOBufferInfo) * (inputChannelCount + outputChannelCount) ); + if( !stream->asioBufferInfos ) + { + result = paInsufficientMemory; + PA_DEBUG(("OpenStream ERROR7\n")); + goto error; + } + + + for( i=0; i < inputChannelCount; ++i ) + { + ASIOBufferInfo *info = &stream->asioBufferInfos[i]; + + info->isInput = ASIOTrue; + + if( inputChannelSelectors ){ + // inputChannelSelectors values have already been validated in + // ValidateAsioSpecificStreamInfo() above + info->channelNum = inputChannelSelectors[i]; + }else{ + info->channelNum = i; + } + + info->buffers[0] = info->buffers[1] = 0; + } + + for( i=0; i < outputChannelCount; ++i ){ + ASIOBufferInfo *info = &stream->asioBufferInfos[inputChannelCount+i]; + + info->isInput = ASIOFalse; + + if( outputChannelSelectors ){ + // outputChannelSelectors values have already been validated in + // ValidateAsioSpecificStreamInfo() above + info->channelNum = outputChannelSelectors[i]; + }else{ + info->channelNum = i; + } + + info->buffers[0] = info->buffers[1] = 0; + } + + + /* Using blocking i/o interface... */ + if( usingBlockingIo ) + { +/** @todo REVIEW selection of host buffer size for blocking i/o */ + + framesPerHostBuffer = SelectHostBufferSize( 0, framesPerBuffer, driverInfo ); + + } + else /* Using callback interface... */ + { + /* Select the host buffer size based on user framesPerBuffer and the + maximum of suggestedInputLatencyFrames and + suggestedOutputLatencyFrames. + + We should subtract any fixed known driver latency from + suggestedLatencyFrames before computing the host buffer size. + However, the ASIO API doesn't provide a method for determining fixed + latencies independent of the host buffer size. ASIOGetLatencies() + only returns latencies after the buffer size has been configured, so + we can't reliably use it to determine fixed latencies here. + + We could set the preferred buffer size and then subtract it from + the values returned from ASIOGetLatencies, but this would not be 100% + reliable, so we don't do it. + */ + + unsigned long targetBufferingLatencyFrames = + (( suggestedInputLatencyFrames > suggestedOutputLatencyFrames ) + ? suggestedInputLatencyFrames + : suggestedOutputLatencyFrames); + + framesPerHostBuffer = SelectHostBufferSize( targetBufferingLatencyFrames, + framesPerBuffer, driverInfo ); + } + + + PA_DEBUG(("PaAsioOpenStream: framesPerHostBuffer :%d\n", framesPerHostBuffer)); + + asioError = ASIOCreateBuffers( stream->asioBufferInfos, + inputChannelCount+outputChannelCount, + framesPerHostBuffer, &asioCallbacks_ ); + + if( asioError != ASE_OK + && framesPerHostBuffer != (unsigned long)driverInfo->bufferPreferredSize ) + { + PA_DEBUG(("ERROR: ASIOCreateBuffers: %s\n", PaAsio_GetAsioErrorText(asioError) )); + /* + Some buggy drivers (like the Hoontech DSP24) give incorrect + [min, preferred, max] values They should work with the preferred size + value, thus if Pa_ASIO_CreateBuffers fails with the hostBufferSize + computed in SelectHostBufferSize, we try again with the preferred size. + */ + + framesPerHostBuffer = driverInfo->bufferPreferredSize; + + PA_DEBUG(("PaAsioOpenStream: CORRECTED framesPerHostBuffer :%d\n", framesPerHostBuffer)); + + ASIOError asioError2 = ASIOCreateBuffers( stream->asioBufferInfos, + inputChannelCount+outputChannelCount, + framesPerHostBuffer, &asioCallbacks_ ); + if( asioError2 == ASE_OK ) + asioError = ASE_OK; + } + + if( asioError != ASE_OK ) + { + result = paUnanticipatedHostError; + PA_ASIO_SET_LAST_ASIO_ERROR( asioError ); + PA_DEBUG(("OpenStream ERROR9\n")); + goto error; + } + + asioBuffersCreated = 1; + + stream->asioChannelInfos = (ASIOChannelInfo*)PaUtil_AllocateMemory( + sizeof(ASIOChannelInfo) * (inputChannelCount + outputChannelCount) ); + if( !stream->asioChannelInfos ) + { + result = paInsufficientMemory; + PA_DEBUG(("OpenStream ERROR10\n")); + goto error; + } + + for( i=0; i < inputChannelCount + outputChannelCount; ++i ) + { + stream->asioChannelInfos[i].channel = stream->asioBufferInfos[i].channelNum; + stream->asioChannelInfos[i].isInput = stream->asioBufferInfos[i].isInput; + asioError = ASIOGetChannelInfo( &stream->asioChannelInfos[i] ); + if( asioError != ASE_OK ) + { + result = paUnanticipatedHostError; + PA_ASIO_SET_LAST_ASIO_ERROR( asioError ); + PA_DEBUG(("OpenStream ERROR11\n")); + goto error; + } + } + + stream->bufferPtrs = (void**)PaUtil_AllocateMemory( + 2 * sizeof(void*) * (inputChannelCount + outputChannelCount) ); + if( !stream->bufferPtrs ) + { + result = paInsufficientMemory; + PA_DEBUG(("OpenStream ERROR12\n")); + goto error; + } + + if( inputChannelCount > 0 ) + { + stream->inputBufferPtrs[0] = stream-> bufferPtrs; + stream->inputBufferPtrs[1] = &stream->bufferPtrs[inputChannelCount]; + + for( i=0; iinputBufferPtrs[0][i] = stream->asioBufferInfos[i].buffers[0]; + stream->inputBufferPtrs[1][i] = stream->asioBufferInfos[i].buffers[1]; + } + } + else + { + stream->inputBufferPtrs[0] = 0; + stream->inputBufferPtrs[1] = 0; + } + + if( outputChannelCount > 0 ) + { + stream->outputBufferPtrs[0] = &stream->bufferPtrs[inputChannelCount*2]; + stream->outputBufferPtrs[1] = &stream->bufferPtrs[inputChannelCount*2 + outputChannelCount]; + + for( i=0; ioutputBufferPtrs[0][i] = stream->asioBufferInfos[inputChannelCount+i].buffers[0]; + stream->outputBufferPtrs[1][i] = stream->asioBufferInfos[inputChannelCount+i].buffers[1]; + } + } + else + { + stream->outputBufferPtrs[0] = 0; + stream->outputBufferPtrs[1] = 0; + } + + if( inputChannelCount > 0 ) + { + /* FIXME: assume all channels use the same type for now + + see: "ASIO devices with multiple sample formats are unsupported" + http://www.portaudio.com/trac/ticket/106 + */ + ASIOSampleType inputType = stream->asioChannelInfos[0].type; + + PA_DEBUG(("ASIO Input type:%d",inputType)); + AsioSampleTypeLOG(inputType); + hostInputSampleFormat = AsioSampleTypeToPaNativeSampleFormat( inputType ); + + SelectAsioToPaConverter( inputType, &stream->inputBufferConverter, &stream->inputShift ); + } + else + { + hostInputSampleFormat = 0; + stream->inputBufferConverter = 0; + } + + if( outputChannelCount > 0 ) + { + /* FIXME: assume all channels use the same type for now + + see: "ASIO devices with multiple sample formats are unsupported" + http://www.portaudio.com/trac/ticket/106 + */ + ASIOSampleType outputType = stream->asioChannelInfos[inputChannelCount].type; + + PA_DEBUG(("ASIO Output type:%d",outputType)); + AsioSampleTypeLOG(outputType); + hostOutputSampleFormat = AsioSampleTypeToPaNativeSampleFormat( outputType ); + + SelectPaToAsioConverter( outputType, &stream->outputBufferConverter, &stream->outputShift ); + } + else + { + hostOutputSampleFormat = 0; + stream->outputBufferConverter = 0; + } + + /* Values returned by ASIOGetLatencies() include the latency introduced by + the ASIO double buffer. */ + ASIOGetLatencies( &stream->asioInputLatencyFrames, &stream->asioOutputLatencyFrames ); + + + /* Using blocking i/o interface... */ + if( usingBlockingIo ) + { + /* Allocate the blocking i/o input ring buffer memory. */ + stream->blockingState = (PaAsioStreamBlockingState*)PaUtil_AllocateMemory( sizeof(PaAsioStreamBlockingState) ); + if( !stream->blockingState ) + { + result = paInsufficientMemory; + PA_DEBUG(("ERROR! Blocking i/o interface struct allocation failed in OpenStream()\n")); + goto error; + } + + /* Initialize blocking i/o interface struct. */ + stream->blockingState->readFramesReadyEvent = NULL; /* Uninitialized, yet. */ + stream->blockingState->writeBuffersReadyEvent = NULL; /* Uninitialized, yet. */ + stream->blockingState->readRingBufferData = NULL; /* Uninitialized, yet. */ + stream->blockingState->writeRingBufferData = NULL; /* Uninitialized, yet. */ + stream->blockingState->readStreamBuffer = NULL; /* Uninitialized, yet. */ + stream->blockingState->writeStreamBuffer = NULL; /* Uninitialized, yet. */ + stream->blockingState->stopFlag = TRUE; /* Not started, yet. */ + + + /* If the user buffer is unspecified */ + if( framesPerBuffer == paFramesPerBufferUnspecified ) + { + /* Make the user buffer the same size as the host buffer. */ + framesPerBuffer = framesPerHostBuffer; + } + + + /* Initialize callback buffer processor. */ + result = PaUtil_InitializeBufferProcessor( &stream->bufferProcessor , + inputChannelCount , + inputSampleFormat & ~paNonInterleaved , /* Ring buffer. */ + (hostInputSampleFormat | paNonInterleaved), /* Host format. */ + outputChannelCount , + outputSampleFormat & ~paNonInterleaved, /* Ring buffer. */ + (hostOutputSampleFormat | paNonInterleaved), /* Host format. */ + sampleRate , + streamFlags , + framesPerBuffer , /* Frames per ring buffer block. */ + framesPerHostBuffer , /* Frames per asio buffer. */ + paUtilFixedHostBufferSize , + streamCallback , + userData ); + if( result != paNoError ){ + PA_DEBUG(("OpenStream ERROR13\n")); + goto error; + } + callbackBufferProcessorInited = TRUE; + + /* Initialize the blocking i/o buffer processor. */ + result = PaUtil_InitializeBufferProcessor(&stream->blockingState->bufferProcessor, + inputChannelCount , + inputSampleFormat , /* User format. */ + inputSampleFormat & ~paNonInterleaved , /* Ring buffer. */ + outputChannelCount , + outputSampleFormat , /* User format. */ + outputSampleFormat & ~paNonInterleaved, /* Ring buffer. */ + sampleRate , + paClipOff | paDitherOff , /* Don't use dither nor clipping. */ + framesPerBuffer , /* Frames per user buffer. */ + framesPerBuffer , /* Frames per ring buffer block. */ + paUtilBoundedHostBufferSize , + NULL, NULL );/* No callback! */ + if( result != paNoError ){ + PA_DEBUG(("ERROR! Blocking i/o buffer processor initialization failed in OpenStream()\n")); + goto error; + } + blockingBufferProcessorInited = TRUE; + + /* If input is requested. */ + if( inputChannelCount ) + { + /* Create the callback sync-event. */ + stream->blockingState->readFramesReadyEvent = CreateEvent( NULL, FALSE, FALSE, NULL ); + if( stream->blockingState->readFramesReadyEvent == NULL ) + { + result = paUnanticipatedHostError; + PA_ASIO_SET_LAST_SYSTEM_ERROR( GetLastError() ); + PA_DEBUG(("ERROR! Blocking i/o \"read frames ready\" event creation failed in OpenStream()\n")); + goto error; + } + blockingReadFramesReadyEventInitialized = 1; + + + /* Create pointer buffer to access non-interleaved data in ReadStream() */ + stream->blockingState->readStreamBuffer = (void**)PaUtil_AllocateMemory( sizeof(void*) * inputChannelCount ); + if( !stream->blockingState->readStreamBuffer ) + { + result = paInsufficientMemory; + PA_DEBUG(("ERROR! Blocking i/o read stream buffer allocation failed in OpenStream()\n")); + goto error; + } + + /* The ring buffer should store as many data blocks as needed + to achieve the requested latency. Whereas it must be large + enough to store at least two complete data blocks. + + 1) Determine the amount of latency to be added to the + prefered ASIO latency. + 2) Make sure we have at lest one additional latency frame. + 3) Divide the number of frames by the desired block size to + get the number (rounded up to pure integer) of blocks to + be stored in the buffer. + 4) Add one additional block for block processing and convert + to samples frames. + 5) Get the next larger (or equal) power-of-two buffer size. + */ + lBlockingBufferSize = suggestedInputLatencyFrames - stream->asioInputLatencyFrames; + lBlockingBufferSize = (lBlockingBufferSize > 0) ? lBlockingBufferSize : 1; + lBlockingBufferSize = (lBlockingBufferSize + framesPerBuffer - 1) / framesPerBuffer; + lBlockingBufferSize = (lBlockingBufferSize + 1) * framesPerBuffer; + + /* Get the next larger or equal power-of-two buffersize. */ + lBlockingBufferSizePow2 = 1; + while( lBlockingBufferSize > (lBlockingBufferSizePow2<<=1) ); + lBlockingBufferSize = lBlockingBufferSizePow2; + + /* Compute total intput latency in seconds */ + stream->streamRepresentation.streamInfo.inputLatency = + (double)( PaUtil_GetBufferProcessorInputLatencyFrames(&stream->bufferProcessor ) + + PaUtil_GetBufferProcessorInputLatencyFrames(&stream->blockingState->bufferProcessor) + + (lBlockingBufferSize / framesPerBuffer - 1) * framesPerBuffer + + stream->asioInputLatencyFrames ) + / sampleRate; + + /* The code below prints the ASIO latency which doesn't include + the buffer processor latency nor the blocking i/o latency. It + reports the added latency separately. + */ + PA_DEBUG(("PaAsio : ASIO InputLatency = %ld (%ld ms),\n added buffProc:%ld (%ld ms),\n added blocking:%ld (%ld ms)\n", + stream->asioInputLatencyFrames, + (long)( stream->asioInputLatencyFrames * (1000.0 / sampleRate) ), + PaUtil_GetBufferProcessorInputLatencyFrames(&stream->bufferProcessor), + (long)( PaUtil_GetBufferProcessorInputLatencyFrames(&stream->bufferProcessor) * (1000.0 / sampleRate) ), + PaUtil_GetBufferProcessorInputLatencyFrames(&stream->blockingState->bufferProcessor) + (lBlockingBufferSize / framesPerBuffer - 1) * framesPerBuffer, + (long)( (PaUtil_GetBufferProcessorInputLatencyFrames(&stream->blockingState->bufferProcessor) + (lBlockingBufferSize / framesPerBuffer - 1) * framesPerBuffer) * (1000.0 / sampleRate) ) + )); + + /* Determine the size of ring buffer in bytes. */ + lBytesPerFrame = inputChannelCount * Pa_GetSampleSize(inputSampleFormat ); + + /* Allocate the blocking i/o input ring buffer memory. */ + stream->blockingState->readRingBufferData = (void*)PaUtil_AllocateMemory( lBlockingBufferSize * lBytesPerFrame ); + if( !stream->blockingState->readRingBufferData ) + { + result = paInsufficientMemory; + PA_DEBUG(("ERROR! Blocking i/o input ring buffer allocation failed in OpenStream()\n")); + goto error; + } + + /* Initialize the input ring buffer struct. */ + PaUtil_InitializeRingBuffer( &stream->blockingState->readRingBuffer , + lBytesPerFrame , + lBlockingBufferSize , + stream->blockingState->readRingBufferData ); + } + + /* If output is requested. */ + if( outputChannelCount ) + { + stream->blockingState->writeBuffersReadyEvent = CreateEvent( NULL, FALSE, FALSE, NULL ); + if( stream->blockingState->writeBuffersReadyEvent == NULL ) + { + result = paUnanticipatedHostError; + PA_ASIO_SET_LAST_SYSTEM_ERROR( GetLastError() ); + PA_DEBUG(("ERROR! Blocking i/o \"write buffers ready\" event creation failed in OpenStream()\n")); + goto error; + } + blockingWriteBuffersReadyEventInitialized = 1; + + /* Create pointer buffer to access non-interleaved data in WriteStream() */ + stream->blockingState->writeStreamBuffer = (const void**)PaUtil_AllocateMemory( sizeof(const void*) * outputChannelCount ); + if( !stream->blockingState->writeStreamBuffer ) + { + result = paInsufficientMemory; + PA_DEBUG(("ERROR! Blocking i/o write stream buffer allocation failed in OpenStream()\n")); + goto error; + } + + /* The ring buffer should store as many data blocks as needed + to achieve the requested latency. Whereas it must be large + enough to store at least two complete data blocks. + + 1) Determine the amount of latency to be added to the + prefered ASIO latency. + 2) Make sure we have at lest one additional latency frame. + 3) Divide the number of frames by the desired block size to + get the number (rounded up to pure integer) of blocks to + be stored in the buffer. + 4) Add one additional block for block processing and convert + to samples frames. + 5) Get the next larger (or equal) power-of-two buffer size. + */ + lBlockingBufferSize = suggestedOutputLatencyFrames - stream->asioOutputLatencyFrames; + lBlockingBufferSize = (lBlockingBufferSize > 0) ? lBlockingBufferSize : 1; + lBlockingBufferSize = (lBlockingBufferSize + framesPerBuffer - 1) / framesPerBuffer; + lBlockingBufferSize = (lBlockingBufferSize + 1) * framesPerBuffer; + + /* The buffer size (without the additional block) corresponds + to the initial number of silent samples in the output ring + buffer. */ + stream->blockingState->writeRingBufferInitialFrames = lBlockingBufferSize - framesPerBuffer; + + /* Get the next larger or equal power-of-two buffersize. */ + lBlockingBufferSizePow2 = 1; + while( lBlockingBufferSize > (lBlockingBufferSizePow2<<=1) ); + lBlockingBufferSize = lBlockingBufferSizePow2; + + /* Compute total output latency in seconds */ + stream->streamRepresentation.streamInfo.outputLatency = + (double)( PaUtil_GetBufferProcessorOutputLatencyFrames(&stream->bufferProcessor) + + PaUtil_GetBufferProcessorOutputLatencyFrames(&stream->blockingState->bufferProcessor) + + (lBlockingBufferSize / framesPerBuffer - 1) * framesPerBuffer + + stream->asioOutputLatencyFrames ) + / sampleRate; + + /* The code below prints the ASIO latency which doesn't include + the buffer processor latency nor the blocking i/o latency. It + reports the added latency separately. + */ + PA_DEBUG(("PaAsio : ASIO OutputLatency = %ld (%ld ms),\n added buffProc:%ld (%ld ms),\n added blocking:%ld (%ld ms)\n", + stream->asioOutputLatencyFrames, + (long)( stream->asioOutputLatencyFrames * (1000.0 / sampleRate) ), + PaUtil_GetBufferProcessorOutputLatencyFrames(&stream->bufferProcessor), + (long)( PaUtil_GetBufferProcessorOutputLatencyFrames(&stream->bufferProcessor) * (1000.0 / sampleRate) ), + PaUtil_GetBufferProcessorOutputLatencyFrames(&stream->blockingState->bufferProcessor) + (lBlockingBufferSize / framesPerBuffer - 1) * framesPerBuffer, + (long)( (PaUtil_GetBufferProcessorOutputLatencyFrames(&stream->blockingState->bufferProcessor) + (lBlockingBufferSize / framesPerBuffer - 1) * framesPerBuffer) * (1000.0 / sampleRate) ) + )); + + /* Determine the size of ring buffer in bytes. */ + lBytesPerFrame = outputChannelCount * Pa_GetSampleSize(outputSampleFormat); + + /* Allocate the blocking i/o output ring buffer memory. */ + stream->blockingState->writeRingBufferData = (void*)PaUtil_AllocateMemory( lBlockingBufferSize * lBytesPerFrame ); + if( !stream->blockingState->writeRingBufferData ) + { + result = paInsufficientMemory; + PA_DEBUG(("ERROR! Blocking i/o output ring buffer allocation failed in OpenStream()\n")); + goto error; + } + + /* Initialize the output ring buffer struct. */ + PaUtil_InitializeRingBuffer( &stream->blockingState->writeRingBuffer , + lBytesPerFrame , + lBlockingBufferSize , + stream->blockingState->writeRingBufferData ); + } + + stream->streamRepresentation.streamInfo.sampleRate = sampleRate; + + + } + else /* Using callback interface... */ + { + result = PaUtil_InitializeBufferProcessor( &stream->bufferProcessor, + inputChannelCount, inputSampleFormat, (hostInputSampleFormat | paNonInterleaved), + outputChannelCount, outputSampleFormat, (hostOutputSampleFormat | paNonInterleaved), + sampleRate, streamFlags, framesPerBuffer, + framesPerHostBuffer, paUtilFixedHostBufferSize, + streamCallback, userData ); + if( result != paNoError ){ + PA_DEBUG(("OpenStream ERROR13\n")); + goto error; + } + callbackBufferProcessorInited = TRUE; + + stream->streamRepresentation.streamInfo.inputLatency = + (double)( PaUtil_GetBufferProcessorInputLatencyFrames(&stream->bufferProcessor) + + stream->asioInputLatencyFrames) / sampleRate; // seconds + stream->streamRepresentation.streamInfo.outputLatency = + (double)( PaUtil_GetBufferProcessorOutputLatencyFrames(&stream->bufferProcessor) + + stream->asioOutputLatencyFrames) / sampleRate; // seconds + stream->streamRepresentation.streamInfo.sampleRate = sampleRate; + + // the code below prints the ASIO latency which doesn't include the + // buffer processor latency. it reports the added latency separately + PA_DEBUG(("PaAsio : ASIO InputLatency = %ld (%ld ms), added buffProc:%ld (%ld ms)\n", + stream->asioInputLatencyFrames, + (long)((stream->asioInputLatencyFrames*1000)/ sampleRate), + PaUtil_GetBufferProcessorInputLatencyFrames(&stream->bufferProcessor), + (long)((PaUtil_GetBufferProcessorInputLatencyFrames(&stream->bufferProcessor)*1000)/ sampleRate) + )); + + PA_DEBUG(("PaAsio : ASIO OuputLatency = %ld (%ld ms), added buffProc:%ld (%ld ms)\n", + stream->asioOutputLatencyFrames, + (long)((stream->asioOutputLatencyFrames*1000)/ sampleRate), + PaUtil_GetBufferProcessorOutputLatencyFrames(&stream->bufferProcessor), + (long)((PaUtil_GetBufferProcessorOutputLatencyFrames(&stream->bufferProcessor)*1000)/ sampleRate) + )); + } + + stream->asioHostApi = asioHostApi; + stream->framesPerHostCallback = framesPerHostBuffer; + + stream->inputChannelCount = inputChannelCount; + stream->outputChannelCount = outputChannelCount; + stream->postOutput = driverInfo->postOutput; + stream->isStopped = 1; + stream->isActive = 0; + + asioHostApi->openAsioDeviceIndex = asioDeviceIndex; + + theAsioStream = stream; + *s = (PaStream*)stream; + + return result; + +error: + PA_DEBUG(("goto errored\n")); + if( stream ) + { + if( stream->blockingState ) + { + if( blockingBufferProcessorInited ) + PaUtil_TerminateBufferProcessor( &stream->blockingState->bufferProcessor ); + + if( stream->blockingState->writeRingBufferData ) + PaUtil_FreeMemory( stream->blockingState->writeRingBufferData ); + if( stream->blockingState->writeStreamBuffer ) + PaUtil_FreeMemory( stream->blockingState->writeStreamBuffer ); + if( blockingWriteBuffersReadyEventInitialized ) + CloseHandle( stream->blockingState->writeBuffersReadyEvent ); + + if( stream->blockingState->readRingBufferData ) + PaUtil_FreeMemory( stream->blockingState->readRingBufferData ); + if( stream->blockingState->readStreamBuffer ) + PaUtil_FreeMemory( stream->blockingState->readStreamBuffer ); + if( blockingReadFramesReadyEventInitialized ) + CloseHandle( stream->blockingState->readFramesReadyEvent ); + + PaUtil_FreeMemory( stream->blockingState ); + } + + if( callbackBufferProcessorInited ) + PaUtil_TerminateBufferProcessor( &stream->bufferProcessor ); + + if( completedBuffersPlayedEventInited ) + CloseHandle( stream->completedBuffersPlayedEvent ); + + if( stream->asioBufferInfos ) + PaUtil_FreeMemory( stream->asioBufferInfos ); + + if( stream->asioChannelInfos ) + PaUtil_FreeMemory( stream->asioChannelInfos ); + + if( stream->bufferPtrs ) + PaUtil_FreeMemory( stream->bufferPtrs ); + + PaUtil_FreeMemory( stream ); + } + + if( asioBuffersCreated ) + ASIODisposeBuffers(); + + if( asioIsInitialized ) + { + UnloadAsioDriver(); + } + return result; +} + + +/* + When CloseStream() is called, the multi-api layer ensures that + the stream has already been stopped or aborted. +*/ +static PaError CloseStream( PaStream* s ) +{ + PaError result = paNoError; + PaAsioStream *stream = (PaAsioStream*)s; + + /* + IMPLEMENT ME: + - additional stream closing + cleanup + */ + + PaUtil_TerminateBufferProcessor( &stream->bufferProcessor ); + PaUtil_TerminateStreamRepresentation( &stream->streamRepresentation ); + + stream->asioHostApi->openAsioDeviceIndex = paNoDevice; + + CloseHandle( stream->completedBuffersPlayedEvent ); + + /* Using blocking i/o interface... */ + if( stream->blockingState ) + { + PaUtil_TerminateBufferProcessor( &stream->blockingState->bufferProcessor ); + + if( stream->inputChannelCount ) { + PaUtil_FreeMemory( stream->blockingState->readRingBufferData ); + PaUtil_FreeMemory( stream->blockingState->readStreamBuffer ); + CloseHandle( stream->blockingState->readFramesReadyEvent ); + } + if( stream->outputChannelCount ) { + PaUtil_FreeMemory( stream->blockingState->writeRingBufferData ); + PaUtil_FreeMemory( stream->blockingState->writeStreamBuffer ); + CloseHandle( stream->blockingState->writeBuffersReadyEvent ); + } + + PaUtil_FreeMemory( stream->blockingState ); + } + + PaUtil_FreeMemory( stream->asioBufferInfos ); + PaUtil_FreeMemory( stream->asioChannelInfos ); + PaUtil_FreeMemory( stream->bufferPtrs ); + PaUtil_FreeMemory( stream ); + + ASIODisposeBuffers(); + UnloadAsioDriver(); + + theAsioStream = 0; + + return result; +} + + +static void bufferSwitch(long index, ASIOBool directProcess) +{ +//TAKEN FROM THE ASIO SDK + + // the actual processing callback. + // Beware that this is normally in a seperate thread, hence be sure that + // you take care about thread synchronization. This is omitted here for + // simplicity. + + // as this is a "back door" into the bufferSwitchTimeInfo a timeInfo needs + // to be created though it will only set the timeInfo.samplePosition and + // timeInfo.systemTime fields and the according flags + + ASIOTime timeInfo; + memset( &timeInfo, 0, sizeof (timeInfo) ); + + // get the time stamp of the buffer, not necessary if no + // synchronization to other media is required + if( ASIOGetSamplePosition(&timeInfo.timeInfo.samplePosition, &timeInfo.timeInfo.systemTime) == ASE_OK) + timeInfo.timeInfo.flags = kSystemTimeValid | kSamplePositionValid; + + // Call the real callback + bufferSwitchTimeInfo( &timeInfo, index, directProcess ); +} + + +// conversion from 64 bit ASIOSample/ASIOTimeStamp to double float +#if NATIVE_INT64 + #define ASIO64toDouble(a) (a) +#else + const double twoRaisedTo32 = 4294967296.; + #define ASIO64toDouble(a) ((a).lo + (a).hi * twoRaisedTo32) +#endif + +static ASIOTime *bufferSwitchTimeInfo( ASIOTime *timeInfo, long index, ASIOBool directProcess ) +{ + // the actual processing callback. + // Beware that this is normally in a seperate thread, hence be sure that + // you take care about thread synchronization. + + + /* The SDK says the following about the directProcess flag: + suggests to the host whether it should immediately start processing + (directProcess == ASIOTrue), or whether its process should be deferred + because the call comes from a very low level (for instance, a high level + priority interrupt), and direct processing would cause timing instabilities for + the rest of the system. If in doubt, directProcess should be set to ASIOFalse. + + We just ignore directProcess. This could cause incompatibilities with + drivers which really don't want the audio processing to occur in this + callback, but none have been identified yet. + */ + + (void) directProcess; /* suppress unused parameter warning */ + +#if 0 + // store the timeInfo for later use + asioDriverInfo.tInfo = *timeInfo; + + // get the time stamp of the buffer, not necessary if no + // synchronization to other media is required + + if (timeInfo->timeInfo.flags & kSystemTimeValid) + asioDriverInfo.nanoSeconds = ASIO64toDouble(timeInfo->timeInfo.systemTime); + else + asioDriverInfo.nanoSeconds = 0; + + if (timeInfo->timeInfo.flags & kSamplePositionValid) + asioDriverInfo.samples = ASIO64toDouble(timeInfo->timeInfo.samplePosition); + else + asioDriverInfo.samples = 0; + + if (timeInfo->timeCode.flags & kTcValid) + asioDriverInfo.tcSamples = ASIO64toDouble(timeInfo->timeCode.timeCodeSamples); + else + asioDriverInfo.tcSamples = 0; + + // get the system reference time + asioDriverInfo.sysRefTime = get_sys_reference_time(); +#endif + +#if 0 + // a few debug messages for the Windows device driver developer + // tells you the time when driver got its interrupt and the delay until the app receives + // the event notification. + static double last_samples = 0; + char tmp[128]; + sprintf (tmp, "diff: %d / %d ms / %d ms / %d samples \n", asioDriverInfo.sysRefTime - (long)(asioDriverInfo.nanoSeconds / 1000000.0), asioDriverInfo.sysRefTime, (long)(asioDriverInfo.nanoSeconds / 1000000.0), (long)(asioDriverInfo.samples - last_samples)); + OutputDebugString (tmp); + last_samples = asioDriverInfo.samples; +#endif + + + if( !theAsioStream ) + return 0L; + + // protect against reentrancy + if( PaAsio_AtomicIncrement(&theAsioStream->reenterCount) ) + { + theAsioStream->reenterError++; + //DBUG(("bufferSwitchTimeInfo : reentrancy detection = %d\n", asioDriverInfo.reenterError)); + return 0L; + } + + int buffersDone = 0; + + do + { + if( buffersDone > 0 ) + { + // this is a reentered buffer, we missed processing it on time + // set the input overflow and output underflow flags as appropriate + + if( theAsioStream->inputChannelCount > 0 ) + theAsioStream->callbackFlags |= paInputOverflow; + + if( theAsioStream->outputChannelCount > 0 ) + theAsioStream->callbackFlags |= paOutputUnderflow; + } + else + { + if( theAsioStream->zeroOutput ) + { + ZeroOutputBuffers( theAsioStream, index ); + + // Finally if the driver supports the ASIOOutputReady() optimization, + // do it here, all data are in place + if( theAsioStream->postOutput ) + ASIOOutputReady(); + + if( theAsioStream->stopProcessing ) + { + if( theAsioStream->stopPlayoutCount < 2 ) + { + ++theAsioStream->stopPlayoutCount; + if( theAsioStream->stopPlayoutCount == 2 ) + { + theAsioStream->isActive = 0; + if( theAsioStream->streamRepresentation.streamFinishedCallback != 0 ) + theAsioStream->streamRepresentation.streamFinishedCallback( theAsioStream->streamRepresentation.userData ); + theAsioStream->streamFinishedCallbackCalled = true; + SetEvent( theAsioStream->completedBuffersPlayedEvent ); + } + } + } + } + else + { + +#if 0 +/* + see: "ASIO callback underflow/overflow buffer slip detection doesn't work" + http://www.portaudio.com/trac/ticket/110 +*/ + +// test code to try to detect slip conditions... these may work on some systems +// but neither of them work on the RME Digi96 + +// check that sample delta matches buffer size (otherwise we must have skipped +// a buffer. +static double last_samples = -512; +double samples; +//if( timeInfo->timeCode.flags & kTcValid ) +// samples = ASIO64toDouble(timeInfo->timeCode.timeCodeSamples); +//else + samples = ASIO64toDouble(timeInfo->timeInfo.samplePosition); +int delta = samples - last_samples; +//printf( "%d\n", delta); +last_samples = samples; + +if( delta > theAsioStream->framesPerHostCallback ) +{ + if( theAsioStream->inputChannelCount > 0 ) + theAsioStream->callbackFlags |= paInputOverflow; + + if( theAsioStream->outputChannelCount > 0 ) + theAsioStream->callbackFlags |= paOutputUnderflow; +} + +// check that the buffer index is not the previous index (which would indicate +// that a buffer was skipped. +static int previousIndex = 1; +if( index == previousIndex ) +{ + if( theAsioStream->inputChannelCount > 0 ) + theAsioStream->callbackFlags |= paInputOverflow; + + if( theAsioStream->outputChannelCount > 0 ) + theAsioStream->callbackFlags |= paOutputUnderflow; +} +previousIndex = index; +#endif + + int i; + + PaUtil_BeginCpuLoadMeasurement( &theAsioStream->cpuLoadMeasurer ); + + PaStreamCallbackTimeInfo paTimeInfo; + + // asio systemTime is supposed to be measured according to the same + // clock as timeGetTime + paTimeInfo.currentTime = (ASIO64toDouble( timeInfo->timeInfo.systemTime ) * .000000001); + + /* patch from Paul Boege */ + paTimeInfo.inputBufferAdcTime = paTimeInfo.currentTime - + ((double)theAsioStream->asioInputLatencyFrames/theAsioStream->streamRepresentation.streamInfo.sampleRate); + + paTimeInfo.outputBufferDacTime = paTimeInfo.currentTime + + ((double)theAsioStream->asioOutputLatencyFrames/theAsioStream->streamRepresentation.streamInfo.sampleRate); + + /* old version is buggy because the buffer processor also adds in its latency to the time parameters + paTimeInfo.inputBufferAdcTime = paTimeInfo.currentTime - theAsioStream->streamRepresentation.streamInfo.inputLatency; + paTimeInfo.outputBufferDacTime = paTimeInfo.currentTime + theAsioStream->streamRepresentation.streamInfo.outputLatency; + */ + +/* Disabled! Stopping and re-starting the stream causes an input overflow / output underflow. S.Fischer */ +#if 0 +// detect underflows by checking inter-callback time > 2 buffer period +static double previousTime = -1; +if( previousTime > 0 ){ + + double delta = paTimeInfo.currentTime - previousTime; + + if( delta >= 2. * (theAsioStream->framesPerHostCallback / theAsioStream->streamRepresentation.streamInfo.sampleRate) ){ + if( theAsioStream->inputChannelCount > 0 ) + theAsioStream->callbackFlags |= paInputOverflow; + + if( theAsioStream->outputChannelCount > 0 ) + theAsioStream->callbackFlags |= paOutputUnderflow; + } +} +previousTime = paTimeInfo.currentTime; +#endif + + // note that the above input and output times do not need to be + // adjusted for the latency of the buffer processor -- the buffer + // processor handles that. + + if( theAsioStream->inputBufferConverter ) + { + for( i=0; iinputChannelCount; i++ ) + { + theAsioStream->inputBufferConverter( theAsioStream->inputBufferPtrs[index][i], + theAsioStream->inputShift, theAsioStream->framesPerHostCallback ); + } + } + + PaUtil_BeginBufferProcessing( &theAsioStream->bufferProcessor, &paTimeInfo, theAsioStream->callbackFlags ); + + /* reset status flags once they've been passed to the callback */ + theAsioStream->callbackFlags = 0; + + PaUtil_SetInputFrameCount( &theAsioStream->bufferProcessor, 0 /* default to host buffer size */ ); + for( i=0; iinputChannelCount; ++i ) + PaUtil_SetNonInterleavedInputChannel( &theAsioStream->bufferProcessor, i, theAsioStream->inputBufferPtrs[index][i] ); + + PaUtil_SetOutputFrameCount( &theAsioStream->bufferProcessor, 0 /* default to host buffer size */ ); + for( i=0; ioutputChannelCount; ++i ) + PaUtil_SetNonInterleavedOutputChannel( &theAsioStream->bufferProcessor, i, theAsioStream->outputBufferPtrs[index][i] ); + + int callbackResult; + if( theAsioStream->stopProcessing ) + callbackResult = paComplete; + else + callbackResult = paContinue; + unsigned long framesProcessed = PaUtil_EndBufferProcessing( &theAsioStream->bufferProcessor, &callbackResult ); + + if( theAsioStream->outputBufferConverter ) + { + for( i=0; ioutputChannelCount; i++ ) + { + theAsioStream->outputBufferConverter( theAsioStream->outputBufferPtrs[index][i], + theAsioStream->outputShift, theAsioStream->framesPerHostCallback ); + } + } + + PaUtil_EndCpuLoadMeasurement( &theAsioStream->cpuLoadMeasurer, framesProcessed ); + + // Finally if the driver supports the ASIOOutputReady() optimization, + // do it here, all data are in place + if( theAsioStream->postOutput ) + ASIOOutputReady(); + + if( callbackResult == paContinue ) + { + /* nothing special to do */ + } + else if( callbackResult == paAbort ) + { + /* finish playback immediately */ + theAsioStream->isActive = 0; + if( theAsioStream->streamRepresentation.streamFinishedCallback != 0 ) + theAsioStream->streamRepresentation.streamFinishedCallback( theAsioStream->streamRepresentation.userData ); + theAsioStream->streamFinishedCallbackCalled = true; + SetEvent( theAsioStream->completedBuffersPlayedEvent ); + theAsioStream->zeroOutput = true; + } + else /* paComplete or other non-zero value indicating complete */ + { + /* Finish playback once currently queued audio has completed. */ + theAsioStream->stopProcessing = true; + + if( PaUtil_IsBufferProcessorOutputEmpty( &theAsioStream->bufferProcessor ) ) + { + theAsioStream->zeroOutput = true; + theAsioStream->stopPlayoutCount = 0; + } + } + } + } + + ++buffersDone; + }while( PaAsio_AtomicDecrement(&theAsioStream->reenterCount) >= 0 ); + + return 0L; +} + + +static void sampleRateChanged(ASIOSampleRate sRate) +{ + // TAKEN FROM THE ASIO SDK + // do whatever you need to do if the sample rate changed + // usually this only happens during external sync. + // Audio processing is not stopped by the driver, actual sample rate + // might not have even changed, maybe only the sample rate status of an + // AES/EBU or S/PDIF digital input at the audio device. + // You might have to update time/sample related conversion routines, etc. + + (void) sRate; /* unused parameter */ + PA_DEBUG( ("sampleRateChanged : %d \n", sRate)); +} + +static long asioMessages(long selector, long value, void* message, double* opt) +{ +// TAKEN FROM THE ASIO SDK + // currently the parameters "value", "message" and "opt" are not used. + long ret = 0; + + (void) message; /* unused parameters */ + (void) opt; + + PA_DEBUG( ("asioMessages : %d , %d \n", selector, value)); + + switch(selector) + { + case kAsioSelectorSupported: + if(value == kAsioResetRequest + || value == kAsioEngineVersion + || value == kAsioResyncRequest + || value == kAsioLatenciesChanged + // the following three were added for ASIO 2.0, you don't necessarily have to support them + || value == kAsioSupportsTimeInfo + || value == kAsioSupportsTimeCode + || value == kAsioSupportsInputMonitor) + ret = 1L; + break; + + case kAsioBufferSizeChange: + //printf("kAsioBufferSizeChange \n"); + break; + + case kAsioResetRequest: + // defer the task and perform the reset of the driver during the next "safe" situation + // You cannot reset the driver right now, as this code is called from the driver. + // Reset the driver is done by completely destruct is. I.e. ASIOStop(), ASIODisposeBuffers(), Destruction + // Afterwards you initialize the driver again. + + /*FIXME: commented the next line out + + see: "PA/ASIO ignores some driver notifications it probably shouldn't" + http://www.portaudio.com/trac/ticket/108 + */ + //asioDriverInfo.stopped; // In this sample the processing will just stop + ret = 1L; + break; + + case kAsioResyncRequest: + // This informs the application, that the driver encountered some non fatal data loss. + // It is used for synchronization purposes of different media. + // Added mainly to work around the Win16Mutex problems in Windows 95/98 with the + // Windows Multimedia system, which could loose data because the Mutex was hold too long + // by another thread. + // However a driver can issue it in other situations, too. + ret = 1L; + break; + + case kAsioLatenciesChanged: + // This will inform the host application that the drivers were latencies changed. + // Beware, it this does not mean that the buffer sizes have changed! + // You might need to update internal delay data. + ret = 1L; + //printf("kAsioLatenciesChanged \n"); + break; + + case kAsioEngineVersion: + // return the supported ASIO version of the host application + // If a host applications does not implement this selector, ASIO 1.0 is assumed + // by the driver + ret = 2L; + break; + + case kAsioSupportsTimeInfo: + // informs the driver wether the asioCallbacks.bufferSwitchTimeInfo() callback + // is supported. + // For compatibility with ASIO 1.0 drivers the host application should always support + // the "old" bufferSwitch method, too. + ret = 1; + break; + + case kAsioSupportsTimeCode: + // informs the driver wether application is interested in time code info. + // If an application does not need to know about time code, the driver has less work + // to do. + ret = 0; + break; + } + return ret; +} + + +static PaError StartStream( PaStream *s ) +{ + PaError result = paNoError; + PaAsioStream *stream = (PaAsioStream*)s; + PaAsioStreamBlockingState *blockingState = stream->blockingState; + ASIOError asioError; + + if( stream->outputChannelCount > 0 ) + { + ZeroOutputBuffers( stream, 0 ); + ZeroOutputBuffers( stream, 1 ); + } + + PaUtil_ResetBufferProcessor( &stream->bufferProcessor ); + stream->stopProcessing = false; + stream->zeroOutput = false; + + /* Reentrancy counter initialisation */ + stream->reenterCount = -1; + stream->reenterError = 0; + + stream->callbackFlags = 0; + + if( ResetEvent( stream->completedBuffersPlayedEvent ) == 0 ) + { + result = paUnanticipatedHostError; + PA_ASIO_SET_LAST_SYSTEM_ERROR( GetLastError() ); + } + + + /* Using blocking i/o interface... */ + if( blockingState ) + { + /* Reset blocking i/o buffer processor. */ + PaUtil_ResetBufferProcessor( &blockingState->bufferProcessor ); + + /* If we're about to process some input data. */ + if( stream->inputChannelCount ) + { + /* Reset callback-ReadStream sync event. */ + if( ResetEvent( blockingState->readFramesReadyEvent ) == 0 ) + { + result = paUnanticipatedHostError; + PA_ASIO_SET_LAST_SYSTEM_ERROR( GetLastError() ); + } + + /* Flush blocking i/o ring buffer. */ + PaUtil_FlushRingBuffer( &blockingState->readRingBuffer ); + (*blockingState->bufferProcessor.inputZeroer)( blockingState->readRingBuffer.buffer, 1, blockingState->bufferProcessor.inputChannelCount * blockingState->readRingBuffer.bufferSize ); + } + + /* If we're about to process some output data. */ + if( stream->outputChannelCount ) + { + /* Reset callback-WriteStream sync event. */ + if( ResetEvent( blockingState->writeBuffersReadyEvent ) == 0 ) + { + result = paUnanticipatedHostError; + PA_ASIO_SET_LAST_SYSTEM_ERROR( GetLastError() ); + } + + /* Flush blocking i/o ring buffer. */ + PaUtil_FlushRingBuffer( &blockingState->writeRingBuffer ); + (*blockingState->bufferProcessor.outputZeroer)( blockingState->writeRingBuffer.buffer, 1, blockingState->bufferProcessor.outputChannelCount * blockingState->writeRingBuffer.bufferSize ); + + /* Initialize the output ring buffer to "silence". */ + PaUtil_AdvanceRingBufferWriteIndex( &blockingState->writeRingBuffer, blockingState->writeRingBufferInitialFrames ); + } + + /* Clear requested frames / buffers count. */ + blockingState->writeBuffersRequested = 0; + blockingState->readFramesRequested = 0; + blockingState->writeBuffersRequestedFlag = FALSE; + blockingState->readFramesRequestedFlag = FALSE; + blockingState->outputUnderflowFlag = FALSE; + blockingState->inputOverflowFlag = FALSE; + blockingState->stopFlag = FALSE; + } + + + if( result == paNoError ) + { + assert( theAsioStream == stream ); /* theAsioStream should be set correctly in OpenStream */ + + /* initialize these variables before the callback has a chance to be invoked */ + stream->isStopped = 0; + stream->isActive = 1; + stream->streamFinishedCallbackCalled = false; + + asioError = ASIOStart(); + if( asioError != ASE_OK ) + { + stream->isStopped = 1; + stream->isActive = 0; + + result = paUnanticipatedHostError; + PA_ASIO_SET_LAST_ASIO_ERROR( asioError ); + } + } + + return result; +} + +static void EnsureCallbackHasCompleted( PaAsioStream *stream ) +{ + // make sure that the callback is not still in-flight after ASIOStop() + // returns. This has been observed to happen on the Hoontech DSP24 for + // example. + int count = 2000; // only wait for 2 seconds, rather than hanging. + while( stream->reenterCount != -1 && count > 0 ) + { + Sleep(1); + --count; + } +} + +static PaError StopStream( PaStream *s ) +{ + PaError result = paNoError; + PaAsioStream *stream = (PaAsioStream*)s; + PaAsioStreamBlockingState *blockingState = stream->blockingState; + ASIOError asioError; + + if( stream->isActive ) + { + /* If blocking i/o output is in use */ + if( blockingState && stream->outputChannelCount ) + { + /* Request the whole output buffer to be available. */ + blockingState->writeBuffersRequested = blockingState->writeRingBuffer.bufferSize; + /* Signalize that additional buffers are need. */ + blockingState->writeBuffersRequestedFlag = TRUE; + /* Set flag to indicate the playback is to be stopped. */ + blockingState->stopFlag = TRUE; + + /* Wait until requested number of buffers has been freed. Time + out after twice the blocking i/o ouput buffer could have + been consumed. */ + DWORD timeout = (DWORD)( 2 * blockingState->writeRingBuffer.bufferSize * 1000 + / stream->streamRepresentation.streamInfo.sampleRate ); + DWORD waitResult = WaitForSingleObject( blockingState->writeBuffersReadyEvent, timeout ); + + /* If something seriously went wrong... */ + if( waitResult == WAIT_FAILED ) + { + PA_DEBUG(("WaitForSingleObject() failed in StopStream()\n")); + result = paUnanticipatedHostError; + PA_ASIO_SET_LAST_SYSTEM_ERROR( GetLastError() ); + } + else if( waitResult == WAIT_TIMEOUT ) + { + PA_DEBUG(("WaitForSingleObject() timed out in StopStream()\n")); + result = paTimedOut; + } + } + + stream->stopProcessing = true; + + /* wait for the stream to finish playing out enqueued buffers. + timeout after four times the stream latency. + + @todo should use a better time out value - if the user buffer + length is longer than the asio buffer size then that should + be taken into account. + */ + if( WaitForSingleObject( stream->completedBuffersPlayedEvent, + (DWORD)(stream->streamRepresentation.streamInfo.outputLatency * 1000. * 4.) ) + == WAIT_TIMEOUT ) + { + PA_DEBUG(("WaitForSingleObject() timed out in StopStream()\n" )); + } + } + + asioError = ASIOStop(); + if( asioError == ASE_OK ) + { + EnsureCallbackHasCompleted( stream ); + } + else + { + result = paUnanticipatedHostError; + PA_ASIO_SET_LAST_ASIO_ERROR( asioError ); + } + + stream->isStopped = 1; + stream->isActive = 0; + + if( !stream->streamFinishedCallbackCalled ) + { + if( stream->streamRepresentation.streamFinishedCallback != 0 ) + stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData ); + } + + return result; +} + +static PaError AbortStream( PaStream *s ) +{ + PaError result = paNoError; + PaAsioStream *stream = (PaAsioStream*)s; + ASIOError asioError; + + stream->zeroOutput = true; + + asioError = ASIOStop(); + if( asioError == ASE_OK ) + { + EnsureCallbackHasCompleted( stream ); + } + else + { + result = paUnanticipatedHostError; + PA_ASIO_SET_LAST_ASIO_ERROR( asioError ); + } + + stream->isStopped = 1; + stream->isActive = 0; + + if( !stream->streamFinishedCallbackCalled ) + { + if( stream->streamRepresentation.streamFinishedCallback != 0 ) + stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData ); + } + + return result; +} + + +static PaError IsStreamStopped( PaStream *s ) +{ + PaAsioStream *stream = (PaAsioStream*)s; + + return stream->isStopped; +} + + +static PaError IsStreamActive( PaStream *s ) +{ + PaAsioStream *stream = (PaAsioStream*)s; + + return stream->isActive; +} + + +static PaTime GetStreamTime( PaStream *s ) +{ + (void) s; /* unused parameter */ + + return (double)timeGetTime() * .001; +} + + +static double GetStreamCpuLoad( PaStream* s ) +{ + PaAsioStream *stream = (PaAsioStream*)s; + + return PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer ); +} + + +/* + As separate stream interfaces are used for blocking and callback + streams, the following functions can be guaranteed to only be called + for blocking streams. +*/ + +static PaError ReadStream( PaStream *s , + void *buffer, + unsigned long frames ) +{ + PaError result = paNoError; /* Initial return value. */ + PaAsioStream *stream = (PaAsioStream*)s; /* The PA ASIO stream. */ + + /* Pointer to the blocking i/o data struct. */ + PaAsioStreamBlockingState *blockingState = stream->blockingState; + + /* Get blocking i/o buffer processor and ring buffer pointers. */ + PaUtilBufferProcessor *pBp = &blockingState->bufferProcessor; + PaUtilRingBuffer *pRb = &blockingState->readRingBuffer; + + /* Ring buffer segment(s) used for writing. */ + void *pRingBufferData1st = NULL; /* First segment. (Mandatory) */ + void *pRingBufferData2nd = NULL; /* Second segment. (Optional) */ + + /* Number of frames per ring buffer segment. */ + long lRingBufferSize1st = 0; /* First segment. (Mandatory) */ + long lRingBufferSize2nd = 0; /* Second segment. (Optional) */ + + /* Get number of frames to be processed per data block. */ + unsigned long lFramesPerBlock = stream->bufferProcessor.framesPerUserBuffer; + /* Actual number of frames that has been copied into the ring buffer. */ + unsigned long lFramesCopied = 0; + /* The number of remaining unprocessed dtat frames. */ + unsigned long lFramesRemaining = frames; + + /* Copy the input argument to avoid pointer increment! */ + const void *userBuffer; + unsigned int i; /* Just a counter. */ + + /* About the time, needed to process 8 data blocks. */ + DWORD timeout = (DWORD)( 8 * lFramesPerBlock * 1000 / stream->streamRepresentation.streamInfo.sampleRate ); + DWORD waitResult = 0; + + + /* Check if the stream is still available ready to gather new data. */ + if( blockingState->stopFlag || !stream->isActive ) + { + PA_DEBUG(("Warning! Stream no longer available for reading in ReadStream()\n")); + result = paStreamIsStopped; + return result; + } + + /* If the stream is a input stream. */ + if( stream->inputChannelCount ) + { + /* Prepare buffer access. */ + if( !pBp->userOutputIsInterleaved ) + { + userBuffer = blockingState->readStreamBuffer; + for( i = 0; iinputChannelCount; ++i ) + { + ((void**)userBuffer)[i] = ((void**)buffer)[i]; + } + } /* Use the unchanged buffer. */ + else { userBuffer = buffer; } + + do /* Internal block processing for too large user data buffers. */ + { + /* Get the size of the current data block to be processed. */ + lFramesPerBlock =(lFramesPerBlock < lFramesRemaining) + ? lFramesPerBlock : lFramesRemaining; + /* Use predefined block size for as long there are enough + buffers available, thereafter reduce the processing block + size to match the number of remaining buffers. So the final + data block is processed although it may be incomplete. */ + + /* If the available amount of data frames is insufficient. */ + if( PaUtil_GetRingBufferReadAvailable(pRb) < (long) lFramesPerBlock ) + { + /* Make sure, the event isn't already set! */ + /* ResetEvent( blockingState->readFramesReadyEvent ); */ + + /* Set the number of requested buffers. */ + blockingState->readFramesRequested = lFramesPerBlock; + + /* Signalize that additional buffers are need. */ + blockingState->readFramesRequestedFlag = TRUE; + + /* Wait until requested number of buffers has been freed. */ + waitResult = WaitForSingleObject( blockingState->readFramesReadyEvent, timeout ); + + /* If something seriously went wrong... */ + if( waitResult == WAIT_FAILED ) + { + PA_DEBUG(("WaitForSingleObject() failed in ReadStream()\n")); + result = paUnanticipatedHostError; + PA_ASIO_SET_LAST_SYSTEM_ERROR( GetLastError() ); + return result; + } + else if( waitResult == WAIT_TIMEOUT ) + { + PA_DEBUG(("WaitForSingleObject() timed out in ReadStream()\n")); + + /* If block processing has stopped, abort! */ + if( blockingState->stopFlag ) { return result = paStreamIsStopped; } + + /* If a timeout is encountered, give up eventually. */ + return result = paTimedOut; + } + } + /* Now, the ring buffer contains the required amount of data + frames. + (Therefor we don't need to check the return argument of + PaUtil_GetRingBufferReadRegions(). ;-) ) + */ + + /* Retrieve pointer(s) to the ring buffer's current write + position(s). If the first buffer segment is too small to + store the requested number of bytes, an additional second + segment is returned. Otherwise, i.e. if the first segment + is large enough, the second segment's pointer will be NULL. + */ + PaUtil_GetRingBufferReadRegions(pRb , + lFramesPerBlock , + &pRingBufferData1st, + &lRingBufferSize1st, + &pRingBufferData2nd, + &lRingBufferSize2nd); + + /* Set number of frames to be copied from the ring buffer. */ + PaUtil_SetInputFrameCount( pBp, lRingBufferSize1st ); + /* Setup ring buffer access. */ + PaUtil_SetInterleavedInputChannels(pBp , /* Buffer processor. */ + 0 , /* The first channel's index. */ + pRingBufferData1st, /* First ring buffer segment. */ + 0 ); /* Use all available channels. */ + + /* If a second ring buffer segment is required. */ + if( lRingBufferSize2nd ) { + /* Set number of frames to be copied from the ring buffer. */ + PaUtil_Set2ndInputFrameCount( pBp, lRingBufferSize2nd ); + /* Setup ring buffer access. */ + PaUtil_Set2ndInterleavedInputChannels(pBp , /* Buffer processor. */ + 0 , /* The first channel's index. */ + pRingBufferData2nd, /* Second ring buffer segment. */ + 0 ); /* Use all available channels. */ + } + + /* Let the buffer processor handle "copy and conversion" and + update the ring buffer indices manually. */ + lFramesCopied = PaUtil_CopyInput( pBp, &buffer, lFramesPerBlock ); + PaUtil_AdvanceRingBufferReadIndex( pRb, lFramesCopied ); + + /* Decrease number of unprocessed frames. */ + lFramesRemaining -= lFramesCopied; + + } /* Continue with the next data chunk. */ + while( lFramesRemaining ); + + + /* If there has been an input overflow within the callback */ + if( blockingState->inputOverflowFlag ) + { + blockingState->inputOverflowFlag = FALSE; + + /* Return the corresponding error code. */ + result = paInputOverflowed; + } + + } /* If this is not an input stream. */ + else { + result = paCanNotReadFromAnOutputOnlyStream; + } + + return result; +} + +static PaError WriteStream( PaStream *s , + const void *buffer, + unsigned long frames ) +{ + PaError result = paNoError; /* Initial return value. */ + PaAsioStream *stream = (PaAsioStream*)s; /* The PA ASIO stream. */ + + /* Pointer to the blocking i/o data struct. */ + PaAsioStreamBlockingState *blockingState = stream->blockingState; + + /* Get blocking i/o buffer processor and ring buffer pointers. */ + PaUtilBufferProcessor *pBp = &blockingState->bufferProcessor; + PaUtilRingBuffer *pRb = &blockingState->writeRingBuffer; + + /* Ring buffer segment(s) used for writing. */ + void *pRingBufferData1st = NULL; /* First segment. (Mandatory) */ + void *pRingBufferData2nd = NULL; /* Second segment. (Optional) */ + + /* Number of frames per ring buffer segment. */ + long lRingBufferSize1st = 0; /* First segment. (Mandatory) */ + long lRingBufferSize2nd = 0; /* Second segment. (Optional) */ + + /* Get number of frames to be processed per data block. */ + unsigned long lFramesPerBlock = stream->bufferProcessor.framesPerUserBuffer; + /* Actual number of frames that has been copied into the ring buffer. */ + unsigned long lFramesCopied = 0; + /* The number of remaining unprocessed dtat frames. */ + unsigned long lFramesRemaining = frames; + + /* About the time, needed to process 8 data blocks. */ + DWORD timeout = (DWORD)( 8 * lFramesPerBlock * 1000 / stream->streamRepresentation.streamInfo.sampleRate ); + DWORD waitResult = 0; + + /* Copy the input argument to avoid pointer increment! */ + const void *userBuffer; + unsigned int i; /* Just a counter. */ + + + /* Check if the stream ist still available ready to recieve new data. */ + if( blockingState->stopFlag || !stream->isActive ) + { + PA_DEBUG(("Warning! Stream no longer available for writing in WriteStream()\n")); + result = paStreamIsStopped; + return result; + } + + /* If the stream is a output stream. */ + if( stream->outputChannelCount ) + { + /* Prepare buffer access. */ + if( !pBp->userOutputIsInterleaved ) + { + userBuffer = blockingState->writeStreamBuffer; + for( i = 0; ioutputChannelCount; ++i ) + { + ((const void**)userBuffer)[i] = ((const void**)buffer)[i]; + } + } /* Use the unchanged buffer. */ + else { userBuffer = buffer; } + + + do /* Internal block processing for too large user data buffers. */ + { + /* Get the size of the current data block to be processed. */ + lFramesPerBlock =(lFramesPerBlock < lFramesRemaining) + ? lFramesPerBlock : lFramesRemaining; + /* Use predefined block size for as long there are enough + frames available, thereafter reduce the processing block + size to match the number of remaining frames. So the final + data block is processed although it may be incomplete. */ + + /* If the available amount of buffers is insufficient. */ + if( PaUtil_GetRingBufferWriteAvailable(pRb) < (long) lFramesPerBlock ) + { + /* Make sure, the event isn't already set! */ + /* ResetEvent( blockingState->writeBuffersReadyEvent ); */ + + /* Set the number of requested buffers. */ + blockingState->writeBuffersRequested = lFramesPerBlock; + + /* Signalize that additional buffers are need. */ + blockingState->writeBuffersRequestedFlag = TRUE; + + /* Wait until requested number of buffers has been freed. */ + waitResult = WaitForSingleObject( blockingState->writeBuffersReadyEvent, timeout ); + + /* If something seriously went wrong... */ + if( waitResult == WAIT_FAILED ) + { + PA_DEBUG(("WaitForSingleObject() failed in WriteStream()\n")); + result = paUnanticipatedHostError; + PA_ASIO_SET_LAST_SYSTEM_ERROR( GetLastError() ); + return result; + } + else if( waitResult == WAIT_TIMEOUT ) + { + PA_DEBUG(("WaitForSingleObject() timed out in WriteStream()\n")); + + /* If block processing has stopped, abort! */ + if( blockingState->stopFlag ) { return result = paStreamIsStopped; } + + /* If a timeout is encountered, give up eventually. */ + return result = paTimedOut; + } + } + /* Now, the ring buffer contains the required amount of free + space to store the provided number of data frames. + (Therefor we don't need to check the return argument of + PaUtil_GetRingBufferWriteRegions(). ;-) ) + */ + + /* Retrieve pointer(s) to the ring buffer's current write + position(s). If the first buffer segment is too small to + store the requested number of bytes, an additional second + segment is returned. Otherwise, i.e. if the first segment + is large enough, the second segment's pointer will be NULL. + */ + PaUtil_GetRingBufferWriteRegions(pRb , + lFramesPerBlock , + &pRingBufferData1st, + &lRingBufferSize1st, + &pRingBufferData2nd, + &lRingBufferSize2nd); + + /* Set number of frames to be copied to the ring buffer. */ + PaUtil_SetOutputFrameCount( pBp, lRingBufferSize1st ); + /* Setup ring buffer access. */ + PaUtil_SetInterleavedOutputChannels(pBp , /* Buffer processor. */ + 0 , /* The first channel's index. */ + pRingBufferData1st, /* First ring buffer segment. */ + 0 ); /* Use all available channels. */ + + /* If a second ring buffer segment is required. */ + if( lRingBufferSize2nd ) { + /* Set number of frames to be copied to the ring buffer. */ + PaUtil_Set2ndOutputFrameCount( pBp, lRingBufferSize2nd ); + /* Setup ring buffer access. */ + PaUtil_Set2ndInterleavedOutputChannels(pBp , /* Buffer processor. */ + 0 , /* The first channel's index. */ + pRingBufferData2nd, /* Second ring buffer segment. */ + 0 ); /* Use all available channels. */ + } + + /* Let the buffer processor handle "copy and conversion" and + update the ring buffer indices manually. */ + lFramesCopied = PaUtil_CopyOutput( pBp, &userBuffer, lFramesPerBlock ); + PaUtil_AdvanceRingBufferWriteIndex( pRb, lFramesCopied ); + + /* Decrease number of unprocessed frames. */ + lFramesRemaining -= lFramesCopied; + + } /* Continue with the next data chunk. */ + while( lFramesRemaining ); + + + /* If there has been an output underflow within the callback */ + if( blockingState->outputUnderflowFlag ) + { + blockingState->outputUnderflowFlag = FALSE; + + /* Return the corresponding error code. */ + result = paOutputUnderflowed; + } + + } /* If this is not an output stream. */ + else + { + result = paCanNotWriteToAnInputOnlyStream; + } + + return result; +} + + +static signed long GetStreamReadAvailable( PaStream* s ) +{ + PaAsioStream *stream = (PaAsioStream*)s; + + /* Call buffer utility routine to get the number of available frames. */ + return PaUtil_GetRingBufferReadAvailable( &stream->blockingState->readRingBuffer ); +} + + +static signed long GetStreamWriteAvailable( PaStream* s ) +{ + PaAsioStream *stream = (PaAsioStream*)s; + + /* Call buffer utility routine to get the number of empty buffers. */ + return PaUtil_GetRingBufferWriteAvailable( &stream->blockingState->writeRingBuffer ); +} + + +/* This routine will be called by the PortAudio engine when audio is needed. +** It may called at interrupt level on some machines so don't do anything +** that could mess up the system like calling malloc() or free(). +*/ +static int BlockingIoPaCallback(const void *inputBuffer , + void *outputBuffer , + unsigned long framesPerBuffer, + const PaStreamCallbackTimeInfo *timeInfo , + PaStreamCallbackFlags statusFlags , + void *userData ) +{ + PaError result = paNoError; /* Initial return value. */ + PaAsioStream *stream = *(PaAsioStream**)userData; /* The PA ASIO stream. */ + PaAsioStreamBlockingState *blockingState = stream->blockingState; /* Persume blockingState is valid, otherwise the callback wouldn't be running. */ + + /* Get a pointer to the stream's blocking i/o buffer processor. */ + PaUtilBufferProcessor *pBp = &blockingState->bufferProcessor; + PaUtilRingBuffer *pRb = NULL; + + /* If output data has been requested. */ + if( stream->outputChannelCount ) + { + /* If the callback input argument signalizes a output underflow, + make sure the WriteStream() function knows about it, too! */ + if( statusFlags & paOutputUnderflowed ) { + blockingState->outputUnderflowFlag = TRUE; + } + + /* Access the corresponding ring buffer. */ + pRb = &blockingState->writeRingBuffer; + + /* If the blocking i/o buffer contains enough output data, */ + if( PaUtil_GetRingBufferReadAvailable(pRb) >= (long) framesPerBuffer ) + { + /* Extract the requested data from the ring buffer. */ + PaUtil_ReadRingBuffer( pRb, outputBuffer, framesPerBuffer ); + } + else /* If no output data is available :-( */ + { + /* Signalize a write-buffer underflow. */ + blockingState->outputUnderflowFlag = TRUE; + + /* Fill the output buffer with silence. */ + (*pBp->outputZeroer)( outputBuffer, 1, pBp->outputChannelCount * framesPerBuffer ); + + /* If playback is to be stopped */ + if( blockingState->stopFlag && PaUtil_GetRingBufferReadAvailable(pRb) < (long) framesPerBuffer ) + { + /* Extract all the remaining data from the ring buffer, + whether it is a complete data block or not. */ + PaUtil_ReadRingBuffer( pRb, outputBuffer, PaUtil_GetRingBufferReadAvailable(pRb) ); + } + } + + /* Set blocking i/o event? */ + if( blockingState->writeBuffersRequestedFlag && PaUtil_GetRingBufferWriteAvailable(pRb) >= (long) blockingState->writeBuffersRequested ) + { + /* Reset buffer request. */ + blockingState->writeBuffersRequestedFlag = FALSE; + blockingState->writeBuffersRequested = 0; + /* Signalize that requested buffers are ready. */ + SetEvent( blockingState->writeBuffersReadyEvent ); + /* What do we do if SetEvent() returns zero, i.e. the event + could not be set? How to return errors from within the + callback? - S.Fischer */ + } + } + + /* If input data has been supplied. */ + if( stream->inputChannelCount ) + { + /* If the callback input argument signalizes a input overflow, + make sure the ReadStream() function knows about it, too! */ + if( statusFlags & paInputOverflowed ) { + blockingState->inputOverflowFlag = TRUE; + } + + /* Access the corresponding ring buffer. */ + pRb = &blockingState->readRingBuffer; + + /* If the blocking i/o buffer contains not enough input buffers */ + if( PaUtil_GetRingBufferWriteAvailable(pRb) < (long) framesPerBuffer ) + { + /* Signalize a read-buffer overflow. */ + blockingState->inputOverflowFlag = TRUE; + + /* Remove some old data frames from the buffer. */ + PaUtil_AdvanceRingBufferReadIndex( pRb, framesPerBuffer ); + } + + /* Insert the current input data into the ring buffer. */ + PaUtil_WriteRingBuffer( pRb, inputBuffer, framesPerBuffer ); + + /* Set blocking i/o event? */ + if( blockingState->readFramesRequestedFlag && PaUtil_GetRingBufferReadAvailable(pRb) >= (long) blockingState->readFramesRequested ) + { + /* Reset buffer request. */ + blockingState->readFramesRequestedFlag = FALSE; + blockingState->readFramesRequested = 0; + /* Signalize that requested buffers are ready. */ + SetEvent( blockingState->readFramesReadyEvent ); + /* What do we do if SetEvent() returns zero, i.e. the event + could not be set? How to return errors from within the + callback? - S.Fischer */ + /** @todo report an error with PA_DEBUG */ + } + } + + return paContinue; +} + + +PaError PaAsio_ShowControlPanel( PaDeviceIndex device, void* systemSpecific ) +{ + PaError result = paNoError; + PaUtilHostApiRepresentation *hostApi; + PaDeviceIndex hostApiDevice; + ASIODriverInfo asioDriverInfo; + ASIOError asioError; + int asioIsInitialized = 0; + PaAsioHostApiRepresentation *asioHostApi; + PaAsioDeviceInfo *asioDeviceInfo; + PaWinUtilComInitializationResult comInitializationResult; + + /* initialize COM again here, we might be in another thread */ + result = PaWinUtil_CoInitialize( paASIO, &comInitializationResult ); + if( result != paNoError ) + return result; + + result = PaUtil_GetHostApiRepresentation( &hostApi, paASIO ); + if( result != paNoError ) + goto error; + + result = PaUtil_DeviceIndexToHostApiDeviceIndex( &hostApiDevice, device, hostApi ); + if( result != paNoError ) + goto error; + + /* + In theory we could proceed if the currently open device was the same + one for which the control panel was requested, however because the + window pointer is not available until this function is called we + currently need to call ASIOInit() again here, which of course can't be + done safely while a stream is open. + */ + + asioHostApi = (PaAsioHostApiRepresentation*)hostApi; + if( asioHostApi->openAsioDeviceIndex != paNoDevice ) + { + result = paDeviceUnavailable; + goto error; + } + + asioDeviceInfo = (PaAsioDeviceInfo*)hostApi->deviceInfos[hostApiDevice]; + + if( !asioHostApi->asioDrivers->loadDriver( const_cast(asioDeviceInfo->commonDeviceInfo.name) ) ) + { + result = paUnanticipatedHostError; + goto error; + } + + /* CRUCIAL!!! */ + memset( &asioDriverInfo, 0, sizeof(ASIODriverInfo) ); + asioDriverInfo.asioVersion = 2; + asioDriverInfo.sysRef = systemSpecific; + asioError = ASIOInit( &asioDriverInfo ); + if( asioError != ASE_OK ) + { + result = paUnanticipatedHostError; + PA_ASIO_SET_LAST_ASIO_ERROR( asioError ); + goto error; + } + else + { + asioIsInitialized = 1; + } + +PA_DEBUG(("PaAsio_ShowControlPanel: ASIOInit(): %s\n", PaAsio_GetAsioErrorText(asioError) )); +PA_DEBUG(("asioVersion: ASIOInit(): %ld\n", asioDriverInfo.asioVersion )); +PA_DEBUG(("driverVersion: ASIOInit(): %ld\n", asioDriverInfo.driverVersion )); +PA_DEBUG(("Name: ASIOInit(): %s\n", asioDriverInfo.name )); +PA_DEBUG(("ErrorMessage: ASIOInit(): %s\n", asioDriverInfo.errorMessage )); + + asioError = ASIOControlPanel(); + if( asioError != ASE_OK ) + { + PA_DEBUG(("PaAsio_ShowControlPanel: ASIOControlPanel(): %s\n", PaAsio_GetAsioErrorText(asioError) )); + result = paUnanticipatedHostError; + PA_ASIO_SET_LAST_ASIO_ERROR( asioError ); + goto error; + } + +PA_DEBUG(("PaAsio_ShowControlPanel: ASIOControlPanel(): %s\n", PaAsio_GetAsioErrorText(asioError) )); + + asioError = ASIOExit(); + if( asioError != ASE_OK ) + { + result = paUnanticipatedHostError; + PA_ASIO_SET_LAST_ASIO_ERROR( asioError ); + asioIsInitialized = 0; + goto error; + } + +PA_DEBUG(("PaAsio_ShowControlPanel: ASIOExit(): %s\n", PaAsio_GetAsioErrorText(asioError) )); + + return result; + +error: + if( asioIsInitialized ) + { + ASIOExit(); + } + + PaWinUtil_CoUninitialize( paASIO, &comInitializationResult ); + + return result; +} + + +PaError PaAsio_GetInputChannelName( PaDeviceIndex device, int channelIndex, + const char** channelName ) +{ + PaError result = paNoError; + PaUtilHostApiRepresentation *hostApi; + PaDeviceIndex hostApiDevice; + PaAsioDeviceInfo *asioDeviceInfo; + + + result = PaUtil_GetHostApiRepresentation( &hostApi, paASIO ); + if( result != paNoError ) + goto error; + + result = PaUtil_DeviceIndexToHostApiDeviceIndex( &hostApiDevice, device, hostApi ); + if( result != paNoError ) + goto error; + + asioDeviceInfo = (PaAsioDeviceInfo*)hostApi->deviceInfos[hostApiDevice]; + + if( channelIndex < 0 || channelIndex >= asioDeviceInfo->commonDeviceInfo.maxInputChannels ){ + result = paInvalidChannelCount; + goto error; + } + + *channelName = asioDeviceInfo->asioChannelInfos[channelIndex].name; + + return paNoError; + +error: + return result; +} + + +PaError PaAsio_GetOutputChannelName( PaDeviceIndex device, int channelIndex, + const char** channelName ) +{ + PaError result = paNoError; + PaUtilHostApiRepresentation *hostApi; + PaDeviceIndex hostApiDevice; + PaAsioDeviceInfo *asioDeviceInfo; + + + result = PaUtil_GetHostApiRepresentation( &hostApi, paASIO ); + if( result != paNoError ) + goto error; + + result = PaUtil_DeviceIndexToHostApiDeviceIndex( &hostApiDevice, device, hostApi ); + if( result != paNoError ) + goto error; + + asioDeviceInfo = (PaAsioDeviceInfo*)hostApi->deviceInfos[hostApiDevice]; + + if( channelIndex < 0 || channelIndex >= asioDeviceInfo->commonDeviceInfo.maxOutputChannels ){ + result = paInvalidChannelCount; + goto error; + } + + *channelName = asioDeviceInfo->asioChannelInfos[ + asioDeviceInfo->commonDeviceInfo.maxInputChannels + channelIndex].name; + + return paNoError; + +error: + return result; +} + + +/* NOTE: the following functions are ASIO-stream specific, and are called directly + by client code. We need to check for many more error conditions here because + we don't have the benefit of pa_front.c's parameter checking. +*/ + +static PaError GetAsioStreamPointer( PaAsioStream **stream, PaStream *s ) +{ + PaError result; + PaUtilHostApiRepresentation *hostApi; + PaAsioHostApiRepresentation *asioHostApi; + + result = PaUtil_ValidateStreamPointer( s ); + if( result != paNoError ) + return result; + + result = PaUtil_GetHostApiRepresentation( &hostApi, paASIO ); + if( result != paNoError ) + return result; + + asioHostApi = (PaAsioHostApiRepresentation*)hostApi; + + if( PA_STREAM_REP( s )->streamInterface == &asioHostApi->callbackStreamInterface + || PA_STREAM_REP( s )->streamInterface == &asioHostApi->blockingStreamInterface ) + { + /* s is an ASIO stream */ + *stream = (PaAsioStream *)s; + return paNoError; + } + else + { + return paIncompatibleStreamHostApi; + } +} + + +PaError PaAsio_SetStreamSampleRate( PaStream* s, double sampleRate ) +{ + PaAsioStream *stream; + PaError result = GetAsioStreamPointer( &stream, s ); + if( result != paNoError ) + return result; + + if( stream != theAsioStream ) + return paBadStreamPtr; + + return ValidateAndSetSampleRate( sampleRate ); +} + diff --git a/extern/portaudio/src/hostapi/coreaudio/notes.txt b/extern/portaudio/src/hostapi/coreaudio/notes.txt new file mode 100644 index 0000000..145afe1 --- /dev/null +++ b/extern/portaudio/src/hostapi/coreaudio/notes.txt @@ -0,0 +1,196 @@ +Notes on status of CoreAudio Implementation of PortAudio + +Document Last Updated December 9, 2005 + +There are currently two implementations of PortAudio for Mac Core Audio. + +The original is in pa_mac_core_old.c, and the newer, default implementation +is in pa_mac_core.c. +Only pa_mac_core.c is currently developed and supported as it uses apple's +current core audio technology. To select use the old implementation, replace +pa_mac_core.c with pa_mac_core_old.c (eg. "cp pa_mac_core_auhal.c +pa_mac_core.c"), then run configure and make as usual. + +------------------------------------------- + +Notes on Newer/Default AUHAL implementation: + +by Bjorn Roche + +Last Updated December 9, 2005 + +Principle of Operation: + +This implementation uses AUHAL for audio I/O. To some extent, it also +operates at the "HAL" Layer, though this behavior can be limited by +platform specific flags (see pa_mac_core.h for details). The default +settings should be reasonable: they don't change the SR of the device and +don't cause interruptions if other devices are using the device. + +Major Software Elements Used: Apple's HAL AUs provide output SR +conversion transparently, however, only on output, so this +implementation uses AudioConverters to convert the sample rate on input. +A PortAudio ring buffer is used to buffer input when sample rate +conversion is required or when separate audio units are used for duplex +IO. Finally, a PortAudio buffer processor is used to convert formats and +provide additional buffers if needed. Internally, interleaved floating +point data streams are used exclusively - the audio unit converts from +the audio hardware's native format to interleaved float PCM and +PortAudio's Buffer processor is used for conversion to user formats. + +Simplex Input: Simplex input uses a single callback. If sample rate +conversion is required, a ring buffer and AudioConverter are used as +well. + +Simplex output: Simplex output uses a single callback. No ring buffer or +audio converter is used because AUHAL does its own output SR conversion. + +Duplex, one device (no SR conversion): When one device is used, a single +callback is used. This achieves very low latency. + +Duplex, separate devices or SR conversion: When SR conversion is +required, data must be buffered before it is converted and data is not +always available at the same times on input and output, so SR conversion +requires the same treatment as separate devices. The input callback +reads data and puts it in the ring buffer. The output callback reads the +data off the ring buffer, into an audio converter and finally to the +buffer processor. + +Platform Specific Options: + +By using the flags in pa_mac_core.h, the user may specify several options. +For example, the user can specify the sample-rate conversion quality, and +the extent to which PA will attempt to "play nice" and to what extent it +will interrupt other apps to improve performance. For example, if 44100 Hz +sample rate is requested but the device is set at 48000 Hz, PA can either +change the device for optimal playback ("Pro" mode), which may interrupt +other programs playing back audio, or simple use a sample-rate coversion, +which allows for friendlier sharing of the device ("Play Nice" mode). + +Additionally, the user may define a "channel mapping" by calling +paSetupMacCoreChannelMap() on their stream info structure before opening +the stream with it. See below for creating a channel map. + +Known issues: + +- Buffering: No buffering beyond that provided by core audio is provided +except where absolutely needed for the implementation to work. This may cause +issues with large framesPerBuffer settings and it also means that no additional +latency will be provided even if a large latency setting is selected. + +- Latency: Latency settings are generally ignored. They may be used as a +hint for buffer size in paHostFramesPerBufferUnspecified, or the value may +be used in cases where additional buffering is needed, such as doing input and +output on seperate devices. Latency settings are always automatically bound +to "safe" values, however, so setting extreme values here should not be +an issue. + +- Buffer Size: paHostFramesPerBufferUnspecified and specific host buffer sizes +are supported. paHostFramesPerBufferUnspecified works best in "pro" mode, +where the buffer size and sample rate of the audio device is most likely +to match the expected values. In the case of paHostFramesPerBuffer, an +appropriate framesPerBuffer value will be used that guarantees minimum +requested latency if that's possible. + +- Timing info. It reports on stream time, but I'm probably doing something +wrong since patest_sine_time often reports negative latency numbers. Also, +there are currently issues with some devices whehn plugging/unplugging +devices. + +- xrun detection: The only xrun detection performed is when reading +and writing the ring buffer. There is probably more that can be done. + +- abort/stop issues: stopping a stream is always a complete operation, +but latency should be low enough to make the lack of a separate abort +unnecessary. Apple clarifies its AudioOutputUnitStop() call here: +http://lists.apple.com/archives/coreaudio-api/2005/Dec/msg00055.html + +- blocking interface: should work fine. + +- multichannel: It has been tested successfully on multichannel hardware +from MOTU: traveler and 896HD. Also Presonus firepod and others. It is +believed to work with all Core Audio devices, including virtual devices +such as soundflower. + +- sample rate conversion quality: By default, SR conversion is the maximum +available. This can be tweaked using flags pa_mac_core.h. Note that the AU +render quyality property is used to set the sample rate conversion quality +as "documented" here: +http://lists.apple.com/archives/coreaudio-api/2004/Jan/msg00141.html + +- x86/Universal Binary: Universal binaries can be build. + + + +Creating a channel map: + +How to create the map array - Text taken From AUHAL.rtfd : +[3] Channel Maps +Clients can tell the AUHAL units which channels of the device they are interested in. For example, the client may be processing stereo data, but outputting to a six-channel device. This is done by using the kAudioOutputUnitProperty_ChannelMap property. To use this property: + +For Output: +Create an array of SInt32 that is the size of the number of channels of the device (Get the Format of the AUHAL's output Element == 0) +Initialize each of the array's values to -1 (-1 indicates that that channel is NOT to be presented in the conversion.) + +Next, for each channel of your app's output, set: +channelMapArray[deviceOutputChannel] = desiredAppOutputChannel. + +For example: we have a 6 channel output device and our application has a stereo source it wants to provide to the device. Suppose we want that stereo source to go to the 3rd and 4th channels of the device. The channel map would look like this: { -1, -1, 0, 1, -1, -1 } + +Where the formats are: +Input Element == 0: 2 channels (- client format - settable) +Output Element == 0: 6 channels (- device format - NOT settable) + +So channel 2 (zero-based) of the device will take the first channel of output and channel 3 will take the second channel of output. (This translates to the 3rd and 4th plugs of the 6 output plugs of the device of course!) + +For Input: +Create an array of SInt32 that is the size of the number of channels of the format you require for input. Get (or Set in this case as needed) the AUHAL's output Element == 1. + +Next, for each channel of input you require, set: +channelMapArray[desiredAppInputChannel] = deviceOutputChannel; + +For example: we have a 6 channel input device from which we wish to receive stereo input from the 3rd and 4th channels. The channel map looks like this: { 2, 3 } + +Where the formats are: +Input Element == 0: 2 channels (- device format - NOT settable) +Output Element == 0: 6 channels (- client format - settable) + + + +---------------------------------------- + +Notes on Original implementation: + +by Phil Burk and Darren Gibbs + +Last updated March 20, 2002 + +WHAT WORKS + +Output with very low latency, <10 msec. +Half duplex input or output. +Full duplex on the same CoreAudio device. +The paFLoat32, paInt16, paInt8, paUInt8 sample formats. +Pa_GetCPULoad() +Pa_StreamTime() + +KNOWN BUGS OR LIMITATIONS + +We do not yet support simultaneous input and output on different +devices. Note that some CoreAudio devices like the Roland UH30 look +like one device but are actually two different CoreAudio devices. The +Built-In audio is typically one CoreAudio device. + +Mono doesn't work. + +DEVICE MAPPING + +CoreAudio devices can support both input and output. But the sample +rates supported may be different. So we have map one or two PortAudio +device to each CoreAudio device depending on whether it supports +input, output or both. + +When we query devices, we first get a list of CoreAudio devices. Then +we scan the list and add a PortAudio device for each CoreAudio device +that supports input. Then we make a scan for output devices. + diff --git a/extern/portaudio/src/hostapi/coreaudio/pa_mac_core.c b/extern/portaudio/src/hostapi/coreaudio/pa_mac_core.c new file mode 100644 index 0000000..257e9de --- /dev/null +++ b/extern/portaudio/src/hostapi/coreaudio/pa_mac_core.c @@ -0,0 +1,2836 @@ +/* + * Implementation of the PortAudio API for Apple AUHAL + * + * PortAudio Portable Real-Time Audio Library + * Latest Version at: http://www.portaudio.com + * + * Written by Bjorn Roche of XO Audio LLC, from PA skeleton code. + * Portions copied from code by Dominic Mazzoni (who wrote a HAL implementation) + * + * Dominic's code was based on code by Phil Burk, Darren Gibbs, + * Gord Peters, Stephane Letz, and Greg Pfiel. + * + * The following people also deserve acknowledgements: + * + * Olivier Tristan for feedback and testing + * Glenn Zelniker and Z-Systems engineering for sponsoring the Blocking I/O + * interface. + * + * + * Based on the Open Source API proposed by Ross Bencina + * Copyright (c) 1999-2002 Ross Bencina, Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +/** + @file pa_mac_core + @ingroup hostapi_src + @author Bjorn Roche + @brief AUHAL implementation of PortAudio +*/ + +/* FIXME: not all error conditions call PaUtil_SetLastHostErrorInfo() + * PaMacCore_SetError() will do this. + */ + +#include "pa_mac_core_internal.h" + +#include /* strlen(), memcmp() etc. */ +#include + +#include "pa_mac_core.h" +#include "pa_mac_core_utilities.h" +#include "pa_mac_core_blocking.h" + + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +/* This is a reasonable size for a small buffer based on experience. */ +#define PA_MAC_SMALL_BUFFER_SIZE (64) + +/* prototypes for functions declared in this file */ +PaError PaMacCore_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index ); + +/* + * Function declared in pa_mac_core.h. Sets up a PaMacCoreStreamInfoStruct + * with the requested flags and initializes channel map. + */ +void PaMacCore_SetupStreamInfo( PaMacCoreStreamInfo *data, const unsigned long flags ) +{ + bzero( data, sizeof( PaMacCoreStreamInfo ) ); + data->size = sizeof( PaMacCoreStreamInfo ); + data->hostApiType = paCoreAudio; + data->version = 0x01; + data->flags = flags; + data->channelMap = NULL; + data->channelMapSize = 0; +} + +/* + * Function declared in pa_mac_core.h. Adds channel mapping to a PaMacCoreStreamInfoStruct + */ +void PaMacCore_SetupChannelMap( PaMacCoreStreamInfo *data, const SInt32 * const channelMap, const unsigned long channelMapSize ) +{ + data->channelMap = channelMap; + data->channelMapSize = channelMapSize; +} +static char *channelName = NULL; +static int channelNameSize = 0; +static bool ensureChannelNameSize( int size ) +{ + if( size >= channelNameSize ) { + free( channelName ); + channelName = (char *) malloc( ( channelNameSize = size ) + 1 ); + if( !channelName ) { + channelNameSize = 0; + return false; + } + } + return true; +} +/* + * Function declared in pa_mac_core.h. retrives channel names. + */ +const char *PaMacCore_GetChannelName( int device, int channelIndex, bool input ) +{ + struct PaUtilHostApiRepresentation *hostApi; + PaError err; + OSStatus error; + err = PaUtil_GetHostApiRepresentation( &hostApi, paCoreAudio ); + assert(err == paNoError); + if( err != paNoError ) + return NULL; + PaMacAUHAL *macCoreHostApi = (PaMacAUHAL*)hostApi; + AudioDeviceID hostApiDevice = macCoreHostApi->devIds[device]; + CFStringRef nameRef; + + /* First try with CFString */ + UInt32 size = sizeof(nameRef); + error = AudioDeviceGetProperty( hostApiDevice, + channelIndex + 1, + input, + kAudioDevicePropertyChannelNameCFString, + &size, + &nameRef ); + if( error ) + { + /* try the C String */ + size = 0; + error = AudioDeviceGetPropertyInfo( hostApiDevice, + channelIndex + 1, + input, + kAudioDevicePropertyChannelName, + &size, + NULL); + if( !error ) + { + if( !ensureChannelNameSize( size ) ) + return NULL; + + error = AudioDeviceGetProperty( hostApiDevice, + channelIndex + 1, + input, + kAudioDevicePropertyChannelName, + &size, + channelName ); + + + if( !error ) + return channelName; + } + + /* as a last-ditch effort, we use the device name and append the channel number. */ + nameRef = CFStringCreateWithFormat( NULL, NULL, CFSTR( "%s: %d"), hostApi->deviceInfos[device]->name, channelIndex + 1 ); + + + size = CFStringGetMaximumSizeForEncoding(CFStringGetLength(nameRef), kCFStringEncodingUTF8);; + if( !ensureChannelNameSize( size ) ) + { + CFRelease( nameRef ); + return NULL; + } + CFStringGetCString( nameRef, channelName, size+1, kCFStringEncodingUTF8 ); + CFRelease( nameRef ); + } + else + { + size = CFStringGetMaximumSizeForEncoding(CFStringGetLength(nameRef), kCFStringEncodingUTF8);; + if( !ensureChannelNameSize( size ) ) + { + CFRelease( nameRef ); + return NULL; + } + CFStringGetCString( nameRef, channelName, size+1, kCFStringEncodingUTF8 ); + CFRelease( nameRef ); + } + + return channelName; +} + + +PaError PaMacCore_GetBufferSizeRange( PaDeviceIndex device, + long *minBufferSizeFrames, long *maxBufferSizeFrames ) +{ + PaError result; + PaUtilHostApiRepresentation *hostApi; + + result = PaUtil_GetHostApiRepresentation( &hostApi, paCoreAudio ); + + if( result == paNoError ) + { + PaDeviceIndex hostApiDeviceIndex; + result = PaUtil_DeviceIndexToHostApiDeviceIndex( &hostApiDeviceIndex, device, hostApi ); + if( result == paNoError ) + { + PaMacAUHAL *macCoreHostApi = (PaMacAUHAL*)hostApi; + AudioDeviceID macCoreDeviceId = macCoreHostApi->devIds[hostApiDeviceIndex]; + AudioValueRange audioRange; + UInt32 propSize = sizeof( audioRange ); + + // return the size range for the output scope unless we only have inputs + Boolean isInput = 0; + if( macCoreHostApi->inheritedHostApiRep.deviceInfos[hostApiDeviceIndex]->maxOutputChannels == 0 ) + isInput = 1; + + result = WARNING(AudioDeviceGetProperty( macCoreDeviceId, 0, isInput, kAudioDevicePropertyBufferFrameSizeRange, &propSize, &audioRange ) ); + + *minBufferSizeFrames = audioRange.mMinimum; + *maxBufferSizeFrames = audioRange.mMaximum; + } + } + + return result; +} + + +AudioDeviceID PaMacCore_GetStreamInputDevice( PaStream* s ) +{ + PaMacCoreStream *stream = (PaMacCoreStream*)s; + VVDBUG(("PaMacCore_GetStreamInputHandle()\n")); + + return ( stream->inputDevice ); +} + +AudioDeviceID PaMacCore_GetStreamOutputDevice( PaStream* s ) +{ + PaMacCoreStream *stream = (PaMacCoreStream*)s; + VVDBUG(("PaMacCore_GetStreamOutputHandle()\n")); + + return ( stream->outputDevice ); +} + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#define RING_BUFFER_ADVANCE_DENOMINATOR (4) + +static void Terminate( struct PaUtilHostApiRepresentation *hostApi ); +static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi, + const PaStreamParameters *inputParameters, + const PaStreamParameters *outputParameters, + double sampleRate ); +static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, + PaStream** s, + const PaStreamParameters *inputParameters, + const PaStreamParameters *outputParameters, + double sampleRate, + unsigned long framesPerBuffer, + PaStreamFlags streamFlags, + PaStreamCallback *streamCallback, + void *userData ); +static PaError CloseStream( PaStream* stream ); +static PaError StartStream( PaStream *stream ); +static PaError StopStream( PaStream *stream ); +static PaError AbortStream( PaStream *stream ); +static PaError IsStreamStopped( PaStream *s ); +static PaError IsStreamActive( PaStream *stream ); +static PaTime GetStreamTime( PaStream *stream ); +static OSStatus AudioIOProc( void *inRefCon, + AudioUnitRenderActionFlags *ioActionFlags, + const AudioTimeStamp *inTimeStamp, + UInt32 inBusNumber, + UInt32 inNumberFrames, + AudioBufferList *ioData ); +static double GetStreamCpuLoad( PaStream* stream ); + +static PaError GetChannelInfo( PaMacAUHAL *auhalHostApi, + PaDeviceInfo *deviceInfo, + AudioDeviceID macCoreDeviceId, + int isInput); + +static PaError OpenAndSetupOneAudioUnit( + const PaMacCoreStream *stream, + const PaStreamParameters *inStreamParams, + const PaStreamParameters *outStreamParams, + const UInt32 requestedFramesPerBuffer, + UInt32 *actualInputFramesPerBuffer, + UInt32 *actualOutputFramesPerBuffer, + const PaMacAUHAL *auhalHostApi, + AudioUnit *audioUnit, + AudioConverterRef *srConverter, + AudioDeviceID *audioDevice, + const double sampleRate, + void *refCon ); + +/* for setting errors. */ +#define PA_AUHAL_SET_LAST_HOST_ERROR( errorCode, errorText ) \ + PaUtil_SetLastHostErrorInfo( paCoreAudio, errorCode, errorText ) + +/* + * Callback called when starting or stopping a stream. + */ +static void startStopCallback( + void * inRefCon, + AudioUnit ci, + AudioUnitPropertyID inID, + AudioUnitScope inScope, + AudioUnitElement inElement ) +{ + PaMacCoreStream *stream = (PaMacCoreStream *) inRefCon; + UInt32 isRunning; + UInt32 size = sizeof( isRunning ); + OSStatus err; + err = AudioUnitGetProperty( ci, kAudioOutputUnitProperty_IsRunning, inScope, inElement, &isRunning, &size ); + assert( !err ); + if( err ) + isRunning = false; //it's very unclear what to do in case of error here. There's no real way to notify the user, and crashing seems unreasonable. + if( isRunning ) + return; //We are only interested in when we are stopping + // -- if we are using 2 I/O units, we only need one notification! + if( stream->inputUnit && stream->outputUnit && stream->inputUnit != stream->outputUnit && ci == stream->inputUnit ) + return; + PaStreamFinishedCallback *sfc = stream->streamRepresentation.streamFinishedCallback; + if( stream->state == STOPPING ) + stream->state = STOPPED ; + if( sfc ) + sfc( stream->streamRepresentation.userData ); +} + + +/*currently, this is only used in initialization, but it might be modified + to be used when the list of devices changes.*/ +static PaError gatherDeviceInfo(PaMacAUHAL *auhalHostApi) +{ + UInt32 size; + UInt32 propsize; + VVDBUG(("gatherDeviceInfo()\n")); + /* -- free any previous allocations -- */ + if( auhalHostApi->devIds ) + PaUtil_GroupFreeMemory(auhalHostApi->allocations, auhalHostApi->devIds); + auhalHostApi->devIds = NULL; + + /* -- figure out how many devices there are -- */ + AudioHardwareGetPropertyInfo( kAudioHardwarePropertyDevices, + &propsize, + NULL ); + auhalHostApi->devCount = propsize / sizeof( AudioDeviceID ); + + VDBUG( ( "Found %ld device(s).\n", auhalHostApi->devCount ) ); + + /* -- copy the device IDs -- */ + auhalHostApi->devIds = (AudioDeviceID *)PaUtil_GroupAllocateMemory( + auhalHostApi->allocations, + propsize ); + if( !auhalHostApi->devIds ) + return paInsufficientMemory; + AudioHardwareGetProperty( kAudioHardwarePropertyDevices, + &propsize, + auhalHostApi->devIds ); +#ifdef MAC_CORE_VERBOSE_DEBUG + { + int i; + for( i=0; idevCount; ++i ) + printf( "Device %d\t: %ld\n", i, auhalHostApi->devIds[i] ); + } +#endif + + size = sizeof(AudioDeviceID); + auhalHostApi->defaultIn = kAudioDeviceUnknown; + auhalHostApi->defaultOut = kAudioDeviceUnknown; + + /* determine the default device. */ + /* I am not sure how these calls to AudioHardwareGetProperty() + could fail, but in case they do, we use the first available + device as the default. */ + if( 0 != AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, + &size, + &auhalHostApi->defaultIn) ) { + int i; + auhalHostApi->defaultIn = kAudioDeviceUnknown; + VDBUG(("Failed to get default input device from OS.")); + VDBUG((" I will substitute the first available input Device.")); + for( i=0; idevCount; ++i ) { + PaDeviceInfo devInfo; + if( 0 != GetChannelInfo( auhalHostApi, &devInfo, + auhalHostApi->devIds[i], TRUE ) ) + if( devInfo.maxInputChannels ) { + auhalHostApi->defaultIn = auhalHostApi->devIds[i]; + break; + } + } + } + if( 0 != AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, + &size, + &auhalHostApi->defaultOut) ) { + int i; + auhalHostApi->defaultIn = kAudioDeviceUnknown; + VDBUG(("Failed to get default output device from OS.")); + VDBUG((" I will substitute the first available output Device.")); + for( i=0; idevCount; ++i ) { + PaDeviceInfo devInfo; + if( 0 != GetChannelInfo( auhalHostApi, &devInfo, + auhalHostApi->devIds[i], FALSE ) ) + if( devInfo.maxOutputChannels ) { + auhalHostApi->defaultOut = auhalHostApi->devIds[i]; + break; + } + } + } + + VDBUG( ( "Default in : %ld\n", auhalHostApi->defaultIn ) ); + VDBUG( ( "Default out: %ld\n", auhalHostApi->defaultOut ) ); + + return paNoError; +} + +/* =================================================================================================== */ +/** + * @internal + * @brief Clip the desired size against the allowed IO buffer size range for the device. + */ +static PaError ClipToDeviceBufferSize( AudioDeviceID macCoreDeviceId, + int isInput, UInt32 desiredSize, UInt32 *allowedSize ) +{ + UInt32 resultSize = desiredSize; + AudioValueRange audioRange; + UInt32 propSize = sizeof( audioRange ); + PaError err = WARNING(AudioDeviceGetProperty( macCoreDeviceId, 0, isInput, kAudioDevicePropertyBufferFrameSizeRange, &propSize, &audioRange ) ); + resultSize = MAX( resultSize, audioRange.mMinimum ); + resultSize = MIN( resultSize, audioRange.mMaximum ); + *allowedSize = resultSize; + return err; +} + +/* =================================================================================================== */ +#if 0 +static void DumpDeviceProperties( AudioDeviceID macCoreDeviceId, + int isInput ) +{ + PaError err; + int i; + UInt32 propSize; + UInt32 deviceLatency; + UInt32 streamLatency; + UInt32 bufferFrames; + UInt32 safetyOffset; + AudioStreamID streamIDs[128]; + + printf("\n======= latency query : macCoreDeviceId = %d, isInput %d =======\n", (int)macCoreDeviceId, isInput ); + + propSize = sizeof(UInt32); + err = WARNING(AudioDeviceGetProperty(macCoreDeviceId, 0, isInput, kAudioDevicePropertyBufferFrameSize, &propSize, &bufferFrames)); + printf("kAudioDevicePropertyBufferFrameSize: err = %d, propSize = %d, value = %d\n", err, propSize, bufferFrames ); + + propSize = sizeof(UInt32); + err = WARNING(AudioDeviceGetProperty(macCoreDeviceId, 0, isInput, kAudioDevicePropertySafetyOffset, &propSize, &safetyOffset)); + printf("kAudioDevicePropertySafetyOffset: err = %d, propSize = %d, value = %d\n", err, propSize, safetyOffset ); + + propSize = sizeof(UInt32); + err = WARNING(AudioDeviceGetProperty(macCoreDeviceId, 0, isInput, kAudioDevicePropertyLatency, &propSize, &deviceLatency)); + printf("kAudioDevicePropertyLatency: err = %d, propSize = %d, value = %d\n", err, propSize, deviceLatency ); + + AudioValueRange audioRange; + propSize = sizeof( audioRange ); + err = WARNING(AudioDeviceGetProperty( macCoreDeviceId, 0, isInput, kAudioDevicePropertyBufferFrameSizeRange, &propSize, &audioRange ) ); + printf("kAudioDevicePropertyBufferFrameSizeRange: err = %d, propSize = %u, minimum = %g\n", err, propSize, audioRange.mMinimum); + printf("kAudioDevicePropertyBufferFrameSizeRange: err = %d, propSize = %u, maximum = %g\n", err, propSize, audioRange.mMaximum ); + + /* Get the streams from the device and query their latency. */ + propSize = sizeof(streamIDs); + err = WARNING(AudioDeviceGetProperty(macCoreDeviceId, 0, isInput, kAudioDevicePropertyStreams, &propSize, &streamIDs[0])); + int numStreams = propSize / sizeof(AudioStreamID); + for( i=0; imNumberBuffers; ++i) + numChannels += buflist->mBuffers[i].mNumberChannels; + + if (isInput) + deviceInfo->maxInputChannels = numChannels; + else + deviceInfo->maxOutputChannels = numChannels; + + if (numChannels > 0) /* do not try to retrieve the latency if there are no channels. */ + { + /* Get the latency. Don't fail if we can't get this. */ + /* default to something reasonable */ + deviceInfo->defaultLowInputLatency = .01; + deviceInfo->defaultHighInputLatency = .10; + deviceInfo->defaultLowOutputLatency = .01; + deviceInfo->defaultHighOutputLatency = .10; + UInt32 lowLatencyFrames = 0; + UInt32 highLatencyFrames = 0; + err = CalculateDefaultDeviceLatencies( macCoreDeviceId, isInput, &lowLatencyFrames, &highLatencyFrames ); + if( err == 0 ) + { + + double lowLatencySeconds = lowLatencyFrames / deviceInfo->defaultSampleRate; + double highLatencySeconds = highLatencyFrames / deviceInfo->defaultSampleRate; + if (isInput) + { + deviceInfo->defaultLowInputLatency = lowLatencySeconds; + deviceInfo->defaultHighInputLatency = highLatencySeconds; + } + else + { + deviceInfo->defaultLowOutputLatency = lowLatencySeconds; + deviceInfo->defaultHighOutputLatency = highLatencySeconds; + } + } + } + PaUtil_FreeMemory( buflist ); + return paNoError; + error: + PaUtil_FreeMemory( buflist ); + return err; +} + +/* =================================================================================================== */ +static PaError InitializeDeviceInfo( PaMacAUHAL *auhalHostApi, + PaDeviceInfo *deviceInfo, + AudioDeviceID macCoreDeviceId, + PaHostApiIndex hostApiIndex ) +{ + Float64 sampleRate; + char *name; + PaError err = paNoError; + CFStringRef nameRef; + UInt32 propSize; + + VVDBUG(("InitializeDeviceInfo(): macCoreDeviceId=%ld\n", macCoreDeviceId)); + + memset(deviceInfo, 0, sizeof(PaDeviceInfo)); + + deviceInfo->structVersion = 2; + deviceInfo->hostApi = hostApiIndex; + + /* Get the device name using CFString */ + propSize = sizeof(nameRef); + err = ERR(AudioDeviceGetProperty(macCoreDeviceId, 0, 0, kAudioDevicePropertyDeviceNameCFString, &propSize, &nameRef)); + if (err) + { + /* Get the device name using c string. Fail if we can't get it. */ + err = ERR(AudioDeviceGetPropertyInfo(macCoreDeviceId, 0, 0, kAudioDevicePropertyDeviceName, &propSize, NULL)); + if (err) + return err; + + name = PaUtil_GroupAllocateMemory(auhalHostApi->allocations,propSize+1); + if ( !name ) + return paInsufficientMemory; + err = ERR(AudioDeviceGetProperty(macCoreDeviceId, 0, 0, kAudioDevicePropertyDeviceName, &propSize, name)); + if (err) + return err; + } + else + { + /* valid CFString so we just allocate a c string big enough to contain the data */ + propSize = CFStringGetMaximumSizeForEncoding(CFStringGetLength(nameRef), kCFStringEncodingUTF8); + name = PaUtil_GroupAllocateMemory(auhalHostApi->allocations, propSize+1); + if ( !name ) + { + CFRelease(nameRef); + return paInsufficientMemory; + } + CFStringGetCString(nameRef, name, propSize+1, kCFStringEncodingUTF8); + CFRelease(nameRef); + } + deviceInfo->name = name; + + /* Try to get the default sample rate. Don't fail if we can't get this. */ + propSize = sizeof(Float64); + err = ERR(AudioDeviceGetProperty(macCoreDeviceId, 0, 0, kAudioDevicePropertyNominalSampleRate, &propSize, &sampleRate)); + if (err) + deviceInfo->defaultSampleRate = 0.0; + else + deviceInfo->defaultSampleRate = sampleRate; + + /* Get the maximum number of input and output channels. Fail if we can't get this. */ + + err = GetChannelInfo(auhalHostApi, deviceInfo, macCoreDeviceId, 1); + if (err) + return err; + + err = GetChannelInfo(auhalHostApi, deviceInfo, macCoreDeviceId, 0); + if (err) + return err; + + return paNoError; +} + +PaError PaMacCore_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex ) +{ + PaError result = paNoError; + int i; + PaMacAUHAL *auhalHostApi = NULL; + PaDeviceInfo *deviceInfoArray; + int unixErr; + + VVDBUG(("PaMacCore_Initialize(): hostApiIndex=%d\n", hostApiIndex)); + + SInt32 major; + SInt32 minor; + Gestalt(gestaltSystemVersionMajor, &major); + Gestalt(gestaltSystemVersionMinor, &minor); + + // Starting with 10.6 systems, the HAL notification thread is created internally + if (major == 10 && minor >= 6) { + CFRunLoopRef theRunLoop = NULL; + AudioObjectPropertyAddress theAddress = { kAudioHardwarePropertyRunLoop, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster }; + OSStatus osErr = AudioObjectSetPropertyData (kAudioObjectSystemObject, &theAddress, 0, NULL, sizeof(CFRunLoopRef), &theRunLoop); + if (osErr != noErr) { + goto error; + } + } + + unixErr = initializeXRunListenerList(); + if( 0 != unixErr ) { + return UNIX_ERR(unixErr); + } + + auhalHostApi = (PaMacAUHAL*)PaUtil_AllocateMemory( sizeof(PaMacAUHAL) ); + if( !auhalHostApi ) + { + result = paInsufficientMemory; + goto error; + } + + auhalHostApi->allocations = PaUtil_CreateAllocationGroup(); + if( !auhalHostApi->allocations ) + { + result = paInsufficientMemory; + goto error; + } + + auhalHostApi->devIds = NULL; + auhalHostApi->devCount = 0; + + /* get the info we need about the devices */ + result = gatherDeviceInfo( auhalHostApi ); + if( result != paNoError ) + goto error; + + *hostApi = &auhalHostApi->inheritedHostApiRep; + (*hostApi)->info.structVersion = 1; + (*hostApi)->info.type = paCoreAudio; + (*hostApi)->info.name = "Core Audio"; + + (*hostApi)->info.defaultInputDevice = paNoDevice; + (*hostApi)->info.defaultOutputDevice = paNoDevice; + + (*hostApi)->info.deviceCount = 0; + + if( auhalHostApi->devCount > 0 ) + { + (*hostApi)->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory( + auhalHostApi->allocations, sizeof(PaDeviceInfo*) * auhalHostApi->devCount); + if( !(*hostApi)->deviceInfos ) + { + result = paInsufficientMemory; + goto error; + } + + /* allocate all device info structs in a contiguous block */ + deviceInfoArray = (PaDeviceInfo*)PaUtil_GroupAllocateMemory( + auhalHostApi->allocations, sizeof(PaDeviceInfo) * auhalHostApi->devCount ); + if( !deviceInfoArray ) + { + result = paInsufficientMemory; + goto error; + } + + for( i=0; i < auhalHostApi->devCount; ++i ) + { + int err; + err = InitializeDeviceInfo( auhalHostApi, &deviceInfoArray[i], + auhalHostApi->devIds[i], + hostApiIndex ); + if (err == paNoError) + { /* copy some info and set the defaults */ + (*hostApi)->deviceInfos[(*hostApi)->info.deviceCount] = &deviceInfoArray[i]; + if (auhalHostApi->devIds[i] == auhalHostApi->defaultIn) + (*hostApi)->info.defaultInputDevice = (*hostApi)->info.deviceCount; + if (auhalHostApi->devIds[i] == auhalHostApi->defaultOut) + (*hostApi)->info.defaultOutputDevice = (*hostApi)->info.deviceCount; + (*hostApi)->info.deviceCount++; + } + else + { /* there was an error. we need to shift the devices down, so we ignore this one */ + int j; + auhalHostApi->devCount--; + for( j=i; jdevCount; ++j ) + auhalHostApi->devIds[j] = auhalHostApi->devIds[j+1]; + i--; + } + } + } + + (*hostApi)->Terminate = Terminate; + (*hostApi)->OpenStream = OpenStream; + (*hostApi)->IsFormatSupported = IsFormatSupported; + + PaUtil_InitializeStreamInterface( &auhalHostApi->callbackStreamInterface, + CloseStream, StartStream, + StopStream, AbortStream, IsStreamStopped, + IsStreamActive, + GetStreamTime, GetStreamCpuLoad, + PaUtil_DummyRead, PaUtil_DummyWrite, + PaUtil_DummyGetReadAvailable, + PaUtil_DummyGetWriteAvailable ); + + PaUtil_InitializeStreamInterface( &auhalHostApi->blockingStreamInterface, + CloseStream, StartStream, + StopStream, AbortStream, IsStreamStopped, + IsStreamActive, + GetStreamTime, PaUtil_DummyGetCpuLoad, + ReadStream, WriteStream, + GetStreamReadAvailable, + GetStreamWriteAvailable ); + + return result; + +error: + if( auhalHostApi ) + { + if( auhalHostApi->allocations ) + { + PaUtil_FreeAllAllocations( auhalHostApi->allocations ); + PaUtil_DestroyAllocationGroup( auhalHostApi->allocations ); + } + + PaUtil_FreeMemory( auhalHostApi ); + } + return result; +} + + +static void Terminate( struct PaUtilHostApiRepresentation *hostApi ) +{ + int unixErr; + + PaMacAUHAL *auhalHostApi = (PaMacAUHAL*)hostApi; + + VVDBUG(("Terminate()\n")); + + unixErr = destroyXRunListenerList(); + if( 0 != unixErr ) + UNIX_ERR(unixErr); + + /* + IMPLEMENT ME: + - clean up any resources not handled by the allocation group + TODO: Double check that everything is handled by alloc group + */ + + if( auhalHostApi->allocations ) + { + PaUtil_FreeAllAllocations( auhalHostApi->allocations ); + PaUtil_DestroyAllocationGroup( auhalHostApi->allocations ); + } + + PaUtil_FreeMemory( auhalHostApi ); +} + + +static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi, + const PaStreamParameters *inputParameters, + const PaStreamParameters *outputParameters, + double sampleRate ) +{ + int inputChannelCount, outputChannelCount; + PaSampleFormat inputSampleFormat, outputSampleFormat; + + VVDBUG(("IsFormatSupported(): in chan=%d, in fmt=%ld, out chan=%d, out fmt=%ld sampleRate=%g\n", + inputParameters ? inputParameters->channelCount : -1, + inputParameters ? inputParameters->sampleFormat : -1, + outputParameters ? outputParameters->channelCount : -1, + outputParameters ? outputParameters->sampleFormat : -1, + (float) sampleRate )); + + /** These first checks are standard PA checks. We do some fancier checks + later. */ + if( inputParameters ) + { + inputChannelCount = inputParameters->channelCount; + inputSampleFormat = inputParameters->sampleFormat; + + /* all standard sample formats are supported by the buffer adapter, + this implementation doesn't support any custom sample formats */ + if( inputSampleFormat & paCustomFormat ) + return paSampleFormatNotSupported; + + /* unless alternate device specification is supported, reject the use of + paUseHostApiSpecificDeviceSpecification */ + + if( inputParameters->device == paUseHostApiSpecificDeviceSpecification ) + return paInvalidDevice; + + /* check that input device can support inputChannelCount */ + if( inputChannelCount > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels ) + return paInvalidChannelCount; + } + else + { + inputChannelCount = 0; + } + + if( outputParameters ) + { + outputChannelCount = outputParameters->channelCount; + outputSampleFormat = outputParameters->sampleFormat; + + /* all standard sample formats are supported by the buffer adapter, + this implementation doesn't support any custom sample formats */ + if( outputSampleFormat & paCustomFormat ) + return paSampleFormatNotSupported; + + /* unless alternate device specification is supported, reject the use of + paUseHostApiSpecificDeviceSpecification */ + + if( outputParameters->device == paUseHostApiSpecificDeviceSpecification ) + return paInvalidDevice; + + /* check that output device can support outputChannelCount */ + if( outputChannelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels ) + return paInvalidChannelCount; + + } + else + { + outputChannelCount = 0; + } + + /* FEEDBACK */ + /* I think the only way to check a given format SR combo is */ + /* to try opening it. This could be disruptive, is that Okay? */ + /* The alternative is to just read off available sample rates, */ + /* but this will not work %100 of the time (eg, a device that */ + /* supports N output at one rate but only N/2 at a higher rate.)*/ + + /* The following code opens the device with the requested parameters to + see if it works. */ + { + PaError err; + PaStream *s; + err = OpenStream( hostApi, &s, inputParameters, outputParameters, + sampleRate, 1024, 0, (PaStreamCallback *)1, NULL ); + if( err != paNoError && err != paInvalidSampleRate ) + DBUG( ( "OpenStream @ %g returned: %d: %s\n", + (float) sampleRate, err, Pa_GetErrorText( err ) ) ); + if( err ) + return err; + err = CloseStream( s ); + if( err ) { + /* FEEDBACK: is this more serious? should we assert? */ + DBUG( ( "WARNING: could not close Stream. %d: %s\n", + err, Pa_GetErrorText( err ) ) ); + } + } + + return paFormatIsSupported; +} + +/* ================================================================================= */ +static void InitializeDeviceProperties( PaMacCoreDeviceProperties *deviceProperties ) +{ + memset( deviceProperties, 0, sizeof(PaMacCoreDeviceProperties) ); + deviceProperties->sampleRate = 1.0; // Better than random. Overwritten by actual values later on. + deviceProperties->samplePeriod = 1.0 / deviceProperties->sampleRate; +} + +static Float64 CalculateSoftwareLatencyFromProperties( PaMacCoreStream *stream, PaMacCoreDeviceProperties *deviceProperties ) +{ + UInt32 latencyFrames = deviceProperties->bufferFrameSize + deviceProperties->deviceLatency + deviceProperties->safetyOffset; + return latencyFrames * deviceProperties->samplePeriod; // same as dividing by sampleRate but faster +} + +static Float64 CalculateHardwareLatencyFromProperties( PaMacCoreStream *stream, PaMacCoreDeviceProperties *deviceProperties ) +{ + return deviceProperties->deviceLatency * deviceProperties->samplePeriod; // same as dividing by sampleRate but faster +} + +/* Calculate values used to convert Apple timestamps into PA timestamps + * from the device properties. The final results of this calculation + * will be used in the audio callback function. + */ +static void UpdateTimeStampOffsets( PaMacCoreStream *stream ) +{ + Float64 inputSoftwareLatency = 0.0; + Float64 inputHardwareLatency = 0.0; + Float64 outputSoftwareLatency = 0.0; + Float64 outputHardwareLatency = 0.0; + + if( stream->inputUnit != NULL ) + { + inputSoftwareLatency = CalculateSoftwareLatencyFromProperties( stream, &stream->inputProperties ); + inputHardwareLatency = CalculateHardwareLatencyFromProperties( stream, &stream->inputProperties ); + } + if( stream->outputUnit != NULL ) + { + outputSoftwareLatency = CalculateSoftwareLatencyFromProperties( stream, &stream->outputProperties ); + outputHardwareLatency = CalculateHardwareLatencyFromProperties( stream, &stream->outputProperties ); + } + + /* We only need a mutex around setting these variables as a group. */ + pthread_mutex_lock( &stream->timingInformationMutex ); + stream->timestampOffsetCombined = inputSoftwareLatency + outputSoftwareLatency; + stream->timestampOffsetInputDevice = inputHardwareLatency; + stream->timestampOffsetOutputDevice = outputHardwareLatency; + pthread_mutex_unlock( &stream->timingInformationMutex ); +} + +/* ================================================================================= */ + +/* can be used to update from nominal or actual sample rate */ +static OSStatus UpdateSampleRateFromDeviceProperty( PaMacCoreStream *stream, AudioDeviceID deviceID, Boolean isInput, AudioDevicePropertyID sampleRatePropertyID ) +{ + PaMacCoreDeviceProperties * deviceProperties = isInput ? &stream->inputProperties : &stream->outputProperties; + + Float64 sampleRate = 0.0; + UInt32 propSize = sizeof(Float64); + OSStatus osErr = AudioDeviceGetProperty( deviceID, 0, isInput, sampleRatePropertyID, &propSize, &sampleRate); + if( (osErr == noErr) && (sampleRate > 1000.0) ) /* avoid divide by zero if there's an error */ + { + deviceProperties->sampleRate = sampleRate; + deviceProperties->samplePeriod = 1.0 / sampleRate; + } + return osErr; +} + +static OSStatus AudioDevicePropertyActualSampleRateListenerProc( AudioDeviceID inDevice, UInt32 inChannel, Boolean isInput, AudioDevicePropertyID inPropertyID, void *inClientData ) +{ + PaMacCoreStream *stream = (PaMacCoreStream*)inClientData; + + // Make sure the callback is operating on a stream that is still valid! + assert( stream->streamRepresentation.magic == PA_STREAM_MAGIC ); + + OSStatus osErr = UpdateSampleRateFromDeviceProperty( stream, inDevice, isInput, kAudioDevicePropertyActualSampleRate ); + if( osErr == noErr ) + { + UpdateTimeStampOffsets( stream ); + } + return osErr; +} + +/* ================================================================================= */ +static OSStatus QueryUInt32DeviceProperty( AudioDeviceID deviceID, Boolean isInput, AudioDevicePropertyID propertyID, UInt32 *outValue ) +{ + UInt32 propertyValue = 0; + UInt32 propertySize = sizeof(UInt32); + OSStatus osErr = AudioDeviceGetProperty( deviceID, 0, isInput, propertyID, &propertySize, &propertyValue); + if( osErr == noErr ) + { + *outValue = propertyValue; + } + return osErr; +} + +static OSStatus AudioDevicePropertyGenericListenerProc( AudioDeviceID inDevice, UInt32 inChannel, Boolean isInput, AudioDevicePropertyID inPropertyID, void *inClientData ) +{ + OSStatus osErr = noErr; + PaMacCoreStream *stream = (PaMacCoreStream*)inClientData; + + // Make sure the callback is operating on a stream that is still valid! + assert( stream->streamRepresentation.magic == PA_STREAM_MAGIC ); + + PaMacCoreDeviceProperties *deviceProperties = isInput ? &stream->inputProperties : &stream->outputProperties; + UInt32 *valuePtr = NULL; + switch( inPropertyID ) + { + case kAudioDevicePropertySafetyOffset: + valuePtr = &deviceProperties->safetyOffset; + break; + + case kAudioDevicePropertyLatency: + valuePtr = &deviceProperties->deviceLatency; + break; + + case kAudioDevicePropertyBufferFrameSize: + valuePtr = &deviceProperties->bufferFrameSize; + break; + } + if( valuePtr != NULL ) + { + osErr = QueryUInt32DeviceProperty( inDevice, isInput, inPropertyID, valuePtr ); + if( osErr == noErr ) + { + UpdateTimeStampOffsets( stream ); + } + } + return osErr; +} + +/* ================================================================================= */ +/* + * Setup listeners in case device properties change during the run. */ +static OSStatus SetupDevicePropertyListeners( PaMacCoreStream *stream, AudioDeviceID deviceID, Boolean isInput ) +{ + OSStatus osErr = noErr; + PaMacCoreDeviceProperties *deviceProperties = isInput ? &stream->inputProperties : &stream->outputProperties; + + if( (osErr = QueryUInt32DeviceProperty( deviceID, isInput, + kAudioDevicePropertyLatency, &deviceProperties->deviceLatency )) != noErr ) return osErr; + if( (osErr = QueryUInt32DeviceProperty( deviceID, isInput, + kAudioDevicePropertyBufferFrameSize, &deviceProperties->bufferFrameSize )) != noErr ) return osErr; + if( (osErr = QueryUInt32DeviceProperty( deviceID, isInput, + kAudioDevicePropertySafetyOffset, &deviceProperties->safetyOffset )) != noErr ) return osErr; + + AudioDeviceAddPropertyListener( deviceID, 0, isInput, kAudioDevicePropertyActualSampleRate, + AudioDevicePropertyActualSampleRateListenerProc, stream ); + + AudioDeviceAddPropertyListener( deviceID, 0, isInput, kAudioStreamPropertyLatency, + AudioDevicePropertyGenericListenerProc, stream ); + AudioDeviceAddPropertyListener( deviceID, 0, isInput, kAudioDevicePropertyBufferFrameSize, + AudioDevicePropertyGenericListenerProc, stream ); + AudioDeviceAddPropertyListener( deviceID, 0, isInput, kAudioDevicePropertySafetyOffset, + AudioDevicePropertyGenericListenerProc, stream ); + + return osErr; +} + +static void CleanupDevicePropertyListeners( PaMacCoreStream *stream, AudioDeviceID deviceID, Boolean isInput ) +{ + AudioDeviceRemovePropertyListener( deviceID, 0, isInput, kAudioDevicePropertyActualSampleRate, + AudioDevicePropertyActualSampleRateListenerProc ); + + AudioDeviceRemovePropertyListener( deviceID, 0, isInput, kAudioDevicePropertyLatency, + AudioDevicePropertyGenericListenerProc ); + AudioDeviceRemovePropertyListener( deviceID, 0, isInput, kAudioDevicePropertyBufferFrameSize, + AudioDevicePropertyGenericListenerProc ); + AudioDeviceRemovePropertyListener( deviceID, 0, isInput, kAudioDevicePropertySafetyOffset, + AudioDevicePropertyGenericListenerProc ); +} + +/* ================================================================================= */ +static PaError OpenAndSetupOneAudioUnit( + const PaMacCoreStream *stream, + const PaStreamParameters *inStreamParams, + const PaStreamParameters *outStreamParams, + const UInt32 requestedFramesPerBuffer, + UInt32 *actualInputFramesPerBuffer, + UInt32 *actualOutputFramesPerBuffer, + const PaMacAUHAL *auhalHostApi, + AudioUnit *audioUnit, + AudioConverterRef *srConverter, + AudioDeviceID *audioDevice, + const double sampleRate, + void *refCon ) +{ + ComponentDescription desc; + Component comp; + /*An Apple TN suggests using CAStreamBasicDescription, but that is C++*/ + AudioStreamBasicDescription desiredFormat; + OSStatus result = noErr; + PaError paResult = paNoError; + int line = 0; + UInt32 callbackKey; + AURenderCallbackStruct rcbs; + unsigned long macInputStreamFlags = paMacCorePlayNice; + unsigned long macOutputStreamFlags = paMacCorePlayNice; + SInt32 const *inChannelMap = NULL; + SInt32 const *outChannelMap = NULL; + unsigned long inChannelMapSize = 0; + unsigned long outChannelMapSize = 0; + + VVDBUG(("OpenAndSetupOneAudioUnit(): in chan=%d, in fmt=%ld, out chan=%d, out fmt=%ld, requestedFramesPerBuffer=%ld\n", + inStreamParams ? inStreamParams->channelCount : -1, + inStreamParams ? inStreamParams->sampleFormat : -1, + outStreamParams ? outStreamParams->channelCount : -1, + outStreamParams ? outStreamParams->sampleFormat : -1, + requestedFramesPerBuffer )); + + /* -- handle the degenerate case -- */ + if( !inStreamParams && !outStreamParams ) { + *audioUnit = NULL; + *audioDevice = kAudioDeviceUnknown; + return paNoError; + } + + /* -- get the user's api specific info, if they set any -- */ + if( inStreamParams && inStreamParams->hostApiSpecificStreamInfo ) + { + macInputStreamFlags= + ((PaMacCoreStreamInfo*)inStreamParams->hostApiSpecificStreamInfo) + ->flags; + inChannelMap = ((PaMacCoreStreamInfo*)inStreamParams->hostApiSpecificStreamInfo) + ->channelMap; + inChannelMapSize = ((PaMacCoreStreamInfo*)inStreamParams->hostApiSpecificStreamInfo) + ->channelMapSize; + } + if( outStreamParams && outStreamParams->hostApiSpecificStreamInfo ) + { + macOutputStreamFlags= + ((PaMacCoreStreamInfo*)outStreamParams->hostApiSpecificStreamInfo) + ->flags; + outChannelMap = ((PaMacCoreStreamInfo*)outStreamParams->hostApiSpecificStreamInfo) + ->channelMap; + outChannelMapSize = ((PaMacCoreStreamInfo*)outStreamParams->hostApiSpecificStreamInfo) + ->channelMapSize; + } + /* Override user's flags here, if desired for testing. */ + + /* + * The HAL AU is a Mac OS style "component". + * the first few steps deal with that. + * Later steps work on a combination of Mac OS + * components and the slightly lower level + * HAL. + */ + + /* -- describe the output type AudioUnit -- */ + /* Note: for the default AudioUnit, we could use the + * componentSubType value kAudioUnitSubType_DefaultOutput; + * but I don't think that's relevant here. + */ + desc.componentType = kAudioUnitType_Output; + desc.componentSubType = kAudioUnitSubType_HALOutput; + desc.componentManufacturer = kAudioUnitManufacturer_Apple; + desc.componentFlags = 0; + desc.componentFlagsMask = 0; + /* -- find the component -- */ + comp = FindNextComponent( NULL, &desc ); + if( !comp ) + { + DBUG( ( "AUHAL component not found." ) ); + *audioUnit = NULL; + *audioDevice = kAudioDeviceUnknown; + return paUnanticipatedHostError; + } + /* -- open it -- */ + result = OpenAComponent( comp, audioUnit ); + if( result ) + { + DBUG( ( "Failed to open AUHAL component." ) ); + *audioUnit = NULL; + *audioDevice = kAudioDeviceUnknown; + return ERR( result ); + } + /* -- prepare a little error handling logic / hackery -- */ +#define ERR_WRAP(mac_err) do { result = mac_err ; line = __LINE__ ; if ( result != noErr ) goto error ; } while(0) + + /* -- if there is input, we have to explicitly enable input -- */ + if( inStreamParams ) + { + UInt32 enableIO = 1; + ERR_WRAP( AudioUnitSetProperty( *audioUnit, + kAudioOutputUnitProperty_EnableIO, + kAudioUnitScope_Input, + INPUT_ELEMENT, + &enableIO, + sizeof(enableIO) ) ); + } + /* -- if there is no output, we must explicitly disable output -- */ + if( !outStreamParams ) + { + UInt32 enableIO = 0; + ERR_WRAP( AudioUnitSetProperty( *audioUnit, + kAudioOutputUnitProperty_EnableIO, + kAudioUnitScope_Output, + OUTPUT_ELEMENT, + &enableIO, + sizeof(enableIO) ) ); + } + + /* -- set the devices -- */ + /* make sure input and output are the same device if we are doing input and + output. */ + if( inStreamParams && outStreamParams ) + { + assert( outStreamParams->device == inStreamParams->device ); + } + if( inStreamParams ) + { + *audioDevice = auhalHostApi->devIds[inStreamParams->device] ; + ERR_WRAP( AudioUnitSetProperty( *audioUnit, + kAudioOutputUnitProperty_CurrentDevice, + kAudioUnitScope_Global, + INPUT_ELEMENT, + audioDevice, + sizeof(AudioDeviceID) ) ); + } + if( outStreamParams && outStreamParams != inStreamParams ) + { + *audioDevice = auhalHostApi->devIds[outStreamParams->device] ; + ERR_WRAP( AudioUnitSetProperty( *audioUnit, + kAudioOutputUnitProperty_CurrentDevice, + kAudioUnitScope_Global, + OUTPUT_ELEMENT, + audioDevice, + sizeof(AudioDeviceID) ) ); + } + /* -- add listener for dropouts -- */ + result = AudioDeviceAddPropertyListener( *audioDevice, + 0, + outStreamParams ? false : true, + kAudioDeviceProcessorOverload, + xrunCallback, + addToXRunListenerList( (void *)stream ) ) ; + if( result == kAudioHardwareIllegalOperationError ) { + // -- already registered, we're good + } else { + // -- not already registered, just check for errors + ERR_WRAP( result ); + } + /* -- listen for stream start and stop -- */ + ERR_WRAP( AudioUnitAddPropertyListener( *audioUnit, + kAudioOutputUnitProperty_IsRunning, + startStopCallback, + (void *)stream ) ); + + /* -- set format -- */ + bzero( &desiredFormat, sizeof(desiredFormat) ); + desiredFormat.mFormatID = kAudioFormatLinearPCM ; + desiredFormat.mFormatFlags = kAudioFormatFlagsNativeFloatPacked; + desiredFormat.mFramesPerPacket = 1; + desiredFormat.mBitsPerChannel = sizeof( float ) * 8; + + result = 0; + /* set device format first, but only touch the device if the user asked */ + if( inStreamParams ) { + /*The callback never calls back if we don't set the FPB */ + /*This seems wierd, because I would think setting anything on the device + would be disruptive.*/ + paResult = setBestFramesPerBuffer( *audioDevice, FALSE, + requestedFramesPerBuffer, + actualInputFramesPerBuffer ); + if( paResult ) goto error; + if( macInputStreamFlags & paMacCoreChangeDeviceParameters ) { + bool requireExact; + requireExact=macInputStreamFlags & paMacCoreFailIfConversionRequired; + paResult = setBestSampleRateForDevice( *audioDevice, FALSE, + requireExact, sampleRate ); + if( paResult ) goto error; + } + if( actualInputFramesPerBuffer && actualOutputFramesPerBuffer ) + *actualOutputFramesPerBuffer = *actualInputFramesPerBuffer ; + } + if( outStreamParams && !inStreamParams ) { + /*The callback never calls back if we don't set the FPB */ + /*This seems wierd, because I would think setting anything on the device + would be disruptive.*/ + paResult = setBestFramesPerBuffer( *audioDevice, TRUE, + requestedFramesPerBuffer, + actualOutputFramesPerBuffer ); + if( paResult ) goto error; + if( macOutputStreamFlags & paMacCoreChangeDeviceParameters ) { + bool requireExact; + requireExact=macOutputStreamFlags & paMacCoreFailIfConversionRequired; + paResult = setBestSampleRateForDevice( *audioDevice, TRUE, + requireExact, sampleRate ); + if( paResult ) goto error; + } + } + + /* -- set the quality of the output converter -- */ + if( outStreamParams ) { + UInt32 value = kAudioConverterQuality_Max; + switch( macOutputStreamFlags & 0x0700 ) { + case 0x0100: /*paMacCore_ConversionQualityMin:*/ + value=kRenderQuality_Min; + break; + case 0x0200: /*paMacCore_ConversionQualityLow:*/ + value=kRenderQuality_Low; + break; + case 0x0300: /*paMacCore_ConversionQualityMedium:*/ + value=kRenderQuality_Medium; + break; + case 0x0400: /*paMacCore_ConversionQualityHigh:*/ + value=kRenderQuality_High; + break; + } + ERR_WRAP( AudioUnitSetProperty( *audioUnit, + kAudioUnitProperty_RenderQuality, + kAudioUnitScope_Global, + OUTPUT_ELEMENT, + &value, + sizeof(value) ) ); + } + /* now set the format on the Audio Units. */ + if( outStreamParams ) + { + desiredFormat.mSampleRate =sampleRate; + desiredFormat.mBytesPerPacket=sizeof(float)*outStreamParams->channelCount; + desiredFormat.mBytesPerFrame =sizeof(float)*outStreamParams->channelCount; + desiredFormat.mChannelsPerFrame = outStreamParams->channelCount; + ERR_WRAP( AudioUnitSetProperty( *audioUnit, + kAudioUnitProperty_StreamFormat, + kAudioUnitScope_Input, + OUTPUT_ELEMENT, + &desiredFormat, + sizeof(AudioStreamBasicDescription) ) ); + } + if( inStreamParams ) + { + AudioStreamBasicDescription sourceFormat; + UInt32 size = sizeof( AudioStreamBasicDescription ); + + /* keep the sample rate of the device, or we confuse AUHAL */ + ERR_WRAP( AudioUnitGetProperty( *audioUnit, + kAudioUnitProperty_StreamFormat, + kAudioUnitScope_Input, + INPUT_ELEMENT, + &sourceFormat, + &size ) ); + desiredFormat.mSampleRate = sourceFormat.mSampleRate; + desiredFormat.mBytesPerPacket=sizeof(float)*inStreamParams->channelCount; + desiredFormat.mBytesPerFrame =sizeof(float)*inStreamParams->channelCount; + desiredFormat.mChannelsPerFrame = inStreamParams->channelCount; + ERR_WRAP( AudioUnitSetProperty( *audioUnit, + kAudioUnitProperty_StreamFormat, + kAudioUnitScope_Output, + INPUT_ELEMENT, + &desiredFormat, + sizeof(AudioStreamBasicDescription) ) ); + } + /* set the maximumFramesPerSlice */ + /* not doing this causes real problems + (eg. the callback might not be called). The idea of setting both this + and the frames per buffer on the device is that we'll be most likely + to actually get the frame size we requested in the callback with the + minimum latency. */ + if( outStreamParams ) { + UInt32 size = sizeof( *actualOutputFramesPerBuffer ); + ERR_WRAP( AudioUnitSetProperty( *audioUnit, + kAudioUnitProperty_MaximumFramesPerSlice, + kAudioUnitScope_Input, + OUTPUT_ELEMENT, + actualOutputFramesPerBuffer, + sizeof(*actualOutputFramesPerBuffer) ) ); + ERR_WRAP( AudioUnitGetProperty( *audioUnit, + kAudioUnitProperty_MaximumFramesPerSlice, + kAudioUnitScope_Global, + OUTPUT_ELEMENT, + actualOutputFramesPerBuffer, + &size ) ); + } + if( inStreamParams ) { + /*UInt32 size = sizeof( *actualInputFramesPerBuffer );*/ + ERR_WRAP( AudioUnitSetProperty( *audioUnit, + kAudioUnitProperty_MaximumFramesPerSlice, + kAudioUnitScope_Output, + INPUT_ELEMENT, + actualInputFramesPerBuffer, + sizeof(*actualInputFramesPerBuffer) ) ); +/* Don't know why this causes problems + ERR_WRAP( AudioUnitGetProperty( *audioUnit, + kAudioUnitProperty_MaximumFramesPerSlice, + kAudioUnitScope_Global, //Output, + INPUT_ELEMENT, + actualInputFramesPerBuffer, + &size ) ); +*/ + } + + /* -- if we have input, we may need to setup an SR converter -- */ + /* even if we got the sample rate we asked for, we need to do + the conversion in case another program changes the underlying SR. */ + /* FIXME: I think we need to monitor stream and change the converter if the incoming format changes. */ + if( inStreamParams ) { + AudioStreamBasicDescription desiredFormat; + AudioStreamBasicDescription sourceFormat; + UInt32 sourceSize = sizeof( sourceFormat ); + bzero( &desiredFormat, sizeof(desiredFormat) ); + desiredFormat.mSampleRate = sampleRate; + desiredFormat.mFormatID = kAudioFormatLinearPCM ; + desiredFormat.mFormatFlags = kAudioFormatFlagsNativeFloatPacked; + desiredFormat.mFramesPerPacket = 1; + desiredFormat.mBitsPerChannel = sizeof( float ) * 8; + desiredFormat.mBytesPerPacket=sizeof(float)*inStreamParams->channelCount; + desiredFormat.mBytesPerFrame =sizeof(float)*inStreamParams->channelCount; + desiredFormat.mChannelsPerFrame = inStreamParams->channelCount; + + /* get the source format */ + ERR_WRAP( AudioUnitGetProperty( + *audioUnit, + kAudioUnitProperty_StreamFormat, + kAudioUnitScope_Output, + INPUT_ELEMENT, + &sourceFormat, + &sourceSize ) ); + + if( desiredFormat.mSampleRate != sourceFormat.mSampleRate ) + { + UInt32 value = kAudioConverterQuality_Max; + switch( macInputStreamFlags & 0x0700 ) { + case 0x0100: /*paMacCore_ConversionQualityMin:*/ + value=kAudioConverterQuality_Min; + break; + case 0x0200: /*paMacCore_ConversionQualityLow:*/ + value=kAudioConverterQuality_Low; + break; + case 0x0300: /*paMacCore_ConversionQualityMedium:*/ + value=kAudioConverterQuality_Medium; + break; + case 0x0400: /*paMacCore_ConversionQualityHigh:*/ + value=kAudioConverterQuality_High; + break; + } + VDBUG(( "Creating sample rate converter for input" + " to convert from %g to %g\n", + (float)sourceFormat.mSampleRate, + (float)desiredFormat.mSampleRate ) ); + /* create our converter */ + ERR_WRAP( AudioConverterNew( + &sourceFormat, + &desiredFormat, + srConverter ) ); + /* Set quality */ + ERR_WRAP( AudioConverterSetProperty( + *srConverter, + kAudioConverterSampleRateConverterQuality, + sizeof( value ), + &value ) ); + } + } + /* -- set IOProc (callback) -- */ + callbackKey = outStreamParams ? kAudioUnitProperty_SetRenderCallback + : kAudioOutputUnitProperty_SetInputCallback ; + rcbs.inputProc = AudioIOProc; + rcbs.inputProcRefCon = refCon; + ERR_WRAP( AudioUnitSetProperty( + *audioUnit, + callbackKey, + kAudioUnitScope_Output, + outStreamParams ? OUTPUT_ELEMENT : INPUT_ELEMENT, + &rcbs, + sizeof(rcbs)) ); + + if( inStreamParams && outStreamParams && *srConverter ) + ERR_WRAP( AudioUnitSetProperty( + *audioUnit, + kAudioOutputUnitProperty_SetInputCallback, + kAudioUnitScope_Output, + INPUT_ELEMENT, + &rcbs, + sizeof(rcbs)) ); + + /* channel mapping. */ + if(inChannelMap) + { + UInt32 mapSize = inChannelMapSize *sizeof(SInt32); + + //for each channel of desired input, map the channel from + //the device's output channel. + ERR_WRAP( AudioUnitSetProperty(*audioUnit, + kAudioOutputUnitProperty_ChannelMap, + kAudioUnitScope_Output, + INPUT_ELEMENT, + inChannelMap, + mapSize)); + } + if(outChannelMap) + { + UInt32 mapSize = outChannelMapSize *sizeof(SInt32); + + //for each channel of desired output, map the channel from + //the device's output channel. + ERR_WRAP(AudioUnitSetProperty(*audioUnit, + kAudioOutputUnitProperty_ChannelMap, + kAudioUnitScope_Output, + OUTPUT_ELEMENT, + outChannelMap, + mapSize)); + } + /* initialize the audio unit */ + ERR_WRAP( AudioUnitInitialize(*audioUnit) ); + + if( inStreamParams && outStreamParams ) + { + VDBUG( ("Opened device %ld for input and output.\n", *audioDevice ) ); + } + else if( inStreamParams ) + { + VDBUG( ("Opened device %ld for input.\n", *audioDevice ) ); + } + else if( outStreamParams ) + { + VDBUG( ("Opened device %ld for output.\n", *audioDevice ) ); + } + return paNoError; +#undef ERR_WRAP + + error: + CloseComponent( *audioUnit ); + *audioUnit = NULL; + if( result ) + return PaMacCore_SetError( result, line, 1 ); + return paResult; +} + +/* =================================================================================================== */ + +static UInt32 CalculateOptimalBufferSize( PaMacAUHAL *auhalHostApi, + const PaStreamParameters *inputParameters, + const PaStreamParameters *outputParameters, + UInt32 fixedInputLatency, + UInt32 fixedOutputLatency, + double sampleRate, + UInt32 requestedFramesPerBuffer ) +{ + UInt32 resultBufferSizeFrames = 0; + // Use maximum of suggested input and output latencies. + if( inputParameters ) + { + UInt32 suggestedLatencyFrames = inputParameters->suggestedLatency * sampleRate; + // Calculate a buffer size assuming we are double buffered. + SInt32 variableLatencyFrames = suggestedLatencyFrames - fixedInputLatency; + // Prevent negative latency. + variableLatencyFrames = MAX( variableLatencyFrames, 0 ); + resultBufferSizeFrames = MAX( resultBufferSizeFrames, (UInt32) variableLatencyFrames ); + } + if( outputParameters ) + { + UInt32 suggestedLatencyFrames = outputParameters->suggestedLatency * sampleRate; + SInt32 variableLatencyFrames = suggestedLatencyFrames - fixedOutputLatency; + variableLatencyFrames = MAX( variableLatencyFrames, 0 ); + resultBufferSizeFrames = MAX( resultBufferSizeFrames, (UInt32) variableLatencyFrames ); + } + + // can't have zero frames. code to round up to next user buffer requires non-zero + resultBufferSizeFrames = MAX( resultBufferSizeFrames, 1 ); + + if( requestedFramesPerBuffer != paFramesPerBufferUnspecified ) + { + // make host buffer the next highest integer multiple of user frames per buffer + UInt32 n = (resultBufferSizeFrames + requestedFramesPerBuffer - 1) / requestedFramesPerBuffer; + resultBufferSizeFrames = n * requestedFramesPerBuffer; + + + // FIXME: really we should be searching for a multiple of requestedFramesPerBuffer + // that is >= suggested latency and also fits within device buffer min/max + + }else{ + VDBUG( ("Block Size unspecified. Based on Latency, the user wants a Block Size near: %ld.\n", + resultBufferSizeFrames ) ); + } + + // Clip to the capabilities of the device. + if( inputParameters ) + { + ClipToDeviceBufferSize( auhalHostApi->devIds[inputParameters->device], + true, // In the old code isInput was false! + resultBufferSizeFrames, &resultBufferSizeFrames ); + } + if( outputParameters ) + { + ClipToDeviceBufferSize( auhalHostApi->devIds[outputParameters->device], + false, resultBufferSizeFrames, &resultBufferSizeFrames ); + } + VDBUG(("After querying hardware, setting block size to %ld.\n", resultBufferSizeFrames)); + + return resultBufferSizeFrames; +} + +/* =================================================================================================== */ +/* see pa_hostapi.h for a list of validity guarantees made about OpenStream parameters */ +static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, + PaStream** s, + const PaStreamParameters *inputParameters, + const PaStreamParameters *outputParameters, + double sampleRate, + unsigned long requestedFramesPerBuffer, + PaStreamFlags streamFlags, + PaStreamCallback *streamCallback, + void *userData ) +{ + PaError result = paNoError; + PaMacAUHAL *auhalHostApi = (PaMacAUHAL*)hostApi; + PaMacCoreStream *stream = 0; + int inputChannelCount, outputChannelCount; + PaSampleFormat inputSampleFormat, outputSampleFormat; + PaSampleFormat hostInputSampleFormat, hostOutputSampleFormat; + UInt32 fixedInputLatency = 0; + UInt32 fixedOutputLatency = 0; + // Accumulate contributions to latency in these variables. + UInt32 inputLatencyFrames = 0; + UInt32 outputLatencyFrames = 0; + UInt32 suggestedLatencyFramesPerBuffer = requestedFramesPerBuffer; + + VVDBUG(("OpenStream(): in chan=%d, in fmt=%ld, out chan=%d, out fmt=%ld SR=%g, FPB=%ld\n", + inputParameters ? inputParameters->channelCount : -1, + inputParameters ? inputParameters->sampleFormat : -1, + outputParameters ? outputParameters->channelCount : -1, + outputParameters ? outputParameters->sampleFormat : -1, + (float) sampleRate, + requestedFramesPerBuffer )); + VDBUG( ("Opening Stream.\n") ); + + /* These first few bits of code are from paSkeleton with few modifications. */ + if( inputParameters ) + { + inputChannelCount = inputParameters->channelCount; + inputSampleFormat = inputParameters->sampleFormat; + + /* @todo Blocking read/write on Mac is not yet supported. */ + if( !streamCallback && inputSampleFormat & paNonInterleaved ) + { + return paSampleFormatNotSupported; + } + + /* unless alternate device specification is supported, reject the use of + paUseHostApiSpecificDeviceSpecification */ + + if( inputParameters->device == paUseHostApiSpecificDeviceSpecification ) + return paInvalidDevice; + + /* check that input device can support inputChannelCount */ + if( inputChannelCount > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels ) + return paInvalidChannelCount; + + /* Host supports interleaved float32 */ + hostInputSampleFormat = paFloat32; + } + else + { + inputChannelCount = 0; + inputSampleFormat = hostInputSampleFormat = paFloat32; /* Surpress 'uninitialised var' warnings. */ + } + + if( outputParameters ) + { + outputChannelCount = outputParameters->channelCount; + outputSampleFormat = outputParameters->sampleFormat; + + /* @todo Blocking read/write on Mac is not yet supported. */ + if( !streamCallback && outputSampleFormat & paNonInterleaved ) + { + return paSampleFormatNotSupported; + } + + /* unless alternate device specification is supported, reject the use of + paUseHostApiSpecificDeviceSpecification */ + + if( outputParameters->device == paUseHostApiSpecificDeviceSpecification ) + return paInvalidDevice; + + /* check that output device can support inputChannelCount */ + if( outputChannelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels ) + return paInvalidChannelCount; + + /* Host supports interleaved float32 */ + hostOutputSampleFormat = paFloat32; + } + else + { + outputChannelCount = 0; + outputSampleFormat = hostOutputSampleFormat = paFloat32; /* Surpress 'uninitialized var' warnings. */ + } + + /* validate platform specific flags */ + if( (streamFlags & paPlatformSpecificFlags) != 0 ) + return paInvalidFlag; /* unexpected platform specific flag */ + + stream = (PaMacCoreStream*)PaUtil_AllocateMemory( sizeof(PaMacCoreStream) ); + if( !stream ) + { + result = paInsufficientMemory; + goto error; + } + + /* If we fail after this point, we my be left in a bad state, with + some data structures setup and others not. So, first thing we + do is initialize everything so that if we fail, we know what hasn't + been touched. + */ + bzero( stream, sizeof( PaMacCoreStream ) ); + + /* + stream->blio.inputRingBuffer.buffer = NULL; + stream->blio.outputRingBuffer.buffer = NULL; + stream->blio.inputSampleFormat = inputParameters?inputParameters->sampleFormat:0; + stream->blio.inputSampleSize = computeSampleSizeFromFormat(stream->blio.inputSampleFormat); + stream->blio.outputSampleFormat=outputParameters?outputParameters->sampleFormat:0; + stream->blio.outputSampleSize = computeSampleSizeFromFormat(stream->blio.outputSampleFormat); + */ + + /* assert( streamCallback ) ; */ /* only callback mode is implemented */ + if( streamCallback ) + { + PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation, + &auhalHostApi->callbackStreamInterface, + streamCallback, userData ); + } + else + { + PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation, + &auhalHostApi->blockingStreamInterface, + BlioCallback, &stream->blio ); + } + + PaUtil_InitializeCpuLoadMeasurer( &stream->cpuLoadMeasurer, sampleRate ); + + + if( inputParameters ) + { + CalculateFixedDeviceLatency( auhalHostApi->devIds[inputParameters->device], true, &fixedInputLatency ); + inputLatencyFrames += fixedInputLatency; + } + if( outputParameters ) + { + CalculateFixedDeviceLatency( auhalHostApi->devIds[outputParameters->device], false, &fixedOutputLatency ); + outputLatencyFrames += fixedOutputLatency; + + } + + suggestedLatencyFramesPerBuffer = CalculateOptimalBufferSize( auhalHostApi, inputParameters, outputParameters, + fixedInputLatency, fixedOutputLatency, + sampleRate, requestedFramesPerBuffer ); + if( requestedFramesPerBuffer == paFramesPerBufferUnspecified ) + { + requestedFramesPerBuffer = suggestedLatencyFramesPerBuffer; + } + + /* -- Now we actually open and setup streams. -- */ + if( inputParameters && outputParameters && outputParameters->device == inputParameters->device ) + { /* full duplex. One device. */ + UInt32 inputFramesPerBuffer = (UInt32) stream->inputFramesPerBuffer; + UInt32 outputFramesPerBuffer = (UInt32) stream->outputFramesPerBuffer; + result = OpenAndSetupOneAudioUnit( stream, + inputParameters, + outputParameters, + suggestedLatencyFramesPerBuffer, + &inputFramesPerBuffer, + &outputFramesPerBuffer, + auhalHostApi, + &(stream->inputUnit), + &(stream->inputSRConverter), + &(stream->inputDevice), + sampleRate, + stream ); + stream->inputFramesPerBuffer = inputFramesPerBuffer; + stream->outputFramesPerBuffer = outputFramesPerBuffer; + stream->outputUnit = stream->inputUnit; + stream->outputDevice = stream->inputDevice; + if( result != paNoError ) + goto error; + } + else + { /* full duplex, different devices OR simplex */ + UInt32 outputFramesPerBuffer = (UInt32) stream->outputFramesPerBuffer; + UInt32 inputFramesPerBuffer = (UInt32) stream->inputFramesPerBuffer; + result = OpenAndSetupOneAudioUnit( stream, + NULL, + outputParameters, + suggestedLatencyFramesPerBuffer, + NULL, + &outputFramesPerBuffer, + auhalHostApi, + &(stream->outputUnit), + NULL, + &(stream->outputDevice), + sampleRate, + stream ); + if( result != paNoError ) + goto error; + result = OpenAndSetupOneAudioUnit( stream, + inputParameters, + NULL, + suggestedLatencyFramesPerBuffer, + &inputFramesPerBuffer, + NULL, + auhalHostApi, + &(stream->inputUnit), + &(stream->inputSRConverter), + &(stream->inputDevice), + sampleRate, + stream ); + if( result != paNoError ) + goto error; + stream->inputFramesPerBuffer = inputFramesPerBuffer; + stream->outputFramesPerBuffer = outputFramesPerBuffer; + } + + inputLatencyFrames += stream->inputFramesPerBuffer; + outputLatencyFrames += stream->outputFramesPerBuffer; + + if( stream->inputUnit ) { + const size_t szfl = sizeof(float); + /* setup the AudioBufferList used for input */ + bzero( &stream->inputAudioBufferList, sizeof( AudioBufferList ) ); + stream->inputAudioBufferList.mNumberBuffers = 1; + stream->inputAudioBufferList.mBuffers[0].mNumberChannels + = inputChannelCount; + stream->inputAudioBufferList.mBuffers[0].mDataByteSize + = stream->inputFramesPerBuffer*inputChannelCount*szfl; + stream->inputAudioBufferList.mBuffers[0].mData + = (float *) calloc( + stream->inputFramesPerBuffer*inputChannelCount, + szfl ); + if( !stream->inputAudioBufferList.mBuffers[0].mData ) + { + result = paInsufficientMemory; + goto error; + } + + /* + * If input and output devs are different or we are doing SR conversion, + * we also need a ring buffer to store input data while waiting for + * output data. + */ + if( (stream->outputUnit && (stream->inputUnit != stream->outputUnit)) + || stream->inputSRConverter ) + { + /* May want the ringSize or initial position in + ring buffer to depend somewhat on sample rate change */ + + void *data; + long ringSize; + + ringSize = computeRingBufferSize( inputParameters, + outputParameters, + stream->inputFramesPerBuffer, + stream->outputFramesPerBuffer, + sampleRate ); + /*ringSize <<= 4; *//*16x bigger, for testing */ + + + /*now, we need to allocate memory for the ring buffer*/ + data = calloc( ringSize, szfl*inputParameters->channelCount ); + if( !data ) + { + result = paInsufficientMemory; + goto error; + } + + /* now we can initialize the ring buffer */ + result = PaUtil_InitializeRingBuffer( &stream->inputRingBuffer, szfl*inputParameters->channelCount, ringSize, data ); + if( result != 0 ) + { + /* The only reason this should fail is if ringSize is not a power of 2, which we do not anticipate happening. */ + result = paUnanticipatedHostError; + free(data); + goto error; + } + + /* advance the read point a little, so we are reading from the + middle of the buffer */ + if( stream->outputUnit ) + PaUtil_AdvanceRingBufferWriteIndex( &stream->inputRingBuffer, ringSize / RING_BUFFER_ADVANCE_DENOMINATOR ); + + // Just adds to input latency between input device and PA full duplex callback. + inputLatencyFrames += ringSize; + } + } + + /* -- initialize Blio Buffer Processors -- */ + if( !streamCallback ) + { + long ringSize; + + ringSize = computeRingBufferSize( inputParameters, + outputParameters, + stream->inputFramesPerBuffer, + stream->outputFramesPerBuffer, + sampleRate ); + result = initializeBlioRingBuffers( &stream->blio, + inputParameters ? inputParameters->sampleFormat : 0, + outputParameters ? outputParameters->sampleFormat : 0, + ringSize, + inputParameters ? inputChannelCount : 0, + outputParameters ? outputChannelCount : 0 ) ; + if( result != paNoError ) + goto error; + + inputLatencyFrames += ringSize; + outputLatencyFrames += ringSize; + + } + + /* -- initialize Buffer Processor -- */ + { + unsigned long maxHostFrames = stream->inputFramesPerBuffer; + if( stream->outputFramesPerBuffer > maxHostFrames ) + maxHostFrames = stream->outputFramesPerBuffer; + result = PaUtil_InitializeBufferProcessor( &stream->bufferProcessor, + inputChannelCount, inputSampleFormat, + hostInputSampleFormat, + outputChannelCount, outputSampleFormat, + hostOutputSampleFormat, + sampleRate, + streamFlags, + requestedFramesPerBuffer, + /* If sample rate conversion takes place, the buffer size + will not be known. */ + maxHostFrames, + stream->inputSRConverter + ? paUtilUnknownHostBufferSize + : paUtilBoundedHostBufferSize, + streamCallback ? streamCallback : BlioCallback, + streamCallback ? userData : &stream->blio ); + if( result != paNoError ) + goto error; + } + stream->bufferProcessorIsInitialized = TRUE; + + // Calculate actual latency from the sum of individual latencies. + if( inputParameters ) + { + inputLatencyFrames += PaUtil_GetBufferProcessorInputLatencyFrames(&stream->bufferProcessor); + stream->streamRepresentation.streamInfo.inputLatency = inputLatencyFrames / sampleRate; + } + else + { + stream->streamRepresentation.streamInfo.inputLatency = 0.0; + } + + if( outputParameters ) + { + outputLatencyFrames += PaUtil_GetBufferProcessorOutputLatencyFrames(&stream->bufferProcessor); + stream->streamRepresentation.streamInfo.outputLatency = outputLatencyFrames / sampleRate; + } + else + { + stream->streamRepresentation.streamInfo.outputLatency = 0.0; + } + + stream->streamRepresentation.streamInfo.sampleRate = sampleRate; + + stream->sampleRate = sampleRate; + + stream->userInChan = inputChannelCount; + stream->userOutChan = outputChannelCount; + + // Setup property listeners for timestamp and latency calculations. + pthread_mutex_init( &stream->timingInformationMutex, NULL ); + stream->timingInformationMutexIsInitialized = 1; + InitializeDeviceProperties( &stream->inputProperties ); // zeros the struct. doesn't actually init it to useful values + InitializeDeviceProperties( &stream->outputProperties ); // zeros the struct. doesn't actually init it to useful values + if( stream->outputUnit ) + { + Boolean isInput = FALSE; + + // Start with the current values for the device properties. + // Init with nominal sample rate. Use actual sample rate where available + + result = ERR( UpdateSampleRateFromDeviceProperty( + stream, stream->outputDevice, isInput, kAudioDevicePropertyNominalSampleRate ) ); + if( result ) + goto error; /* fail if we can't even get a nominal device sample rate */ + + UpdateSampleRateFromDeviceProperty( stream, stream->outputDevice, isInput, kAudioDevicePropertyActualSampleRate ); + + SetupDevicePropertyListeners( stream, stream->outputDevice, isInput ); + } + if( stream->inputUnit ) + { + Boolean isInput = TRUE; + + // as above + result = ERR( UpdateSampleRateFromDeviceProperty( + stream, stream->inputDevice, isInput, kAudioDevicePropertyNominalSampleRate ) ); + if( result ) + goto error; + + UpdateSampleRateFromDeviceProperty( stream, stream->inputDevice, isInput, kAudioDevicePropertyActualSampleRate ); + + SetupDevicePropertyListeners( stream, stream->inputDevice, isInput ); + } + UpdateTimeStampOffsets( stream ); + // Setup timestamp copies to be used by audio callback. + stream->timestampOffsetCombined_ioProcCopy = stream->timestampOffsetCombined; + stream->timestampOffsetInputDevice_ioProcCopy = stream->timestampOffsetInputDevice; + stream->timestampOffsetOutputDevice_ioProcCopy = stream->timestampOffsetOutputDevice; + + stream->state = STOPPED; + stream->xrunFlags = 0; + + *s = (PaStream*)stream; + + return result; + +error: + CloseStream( stream ); + return result; +} + + +#define HOST_TIME_TO_PA_TIME( x ) ( AudioConvertHostTimeToNanos( (x) ) * 1.0E-09) /* convert to nanoseconds and then to seconds */ + +PaTime GetStreamTime( PaStream *s ) +{ + return HOST_TIME_TO_PA_TIME( AudioGetCurrentHostTime() ); +} + +#define RING_BUFFER_EMPTY (1000) + +static OSStatus ringBufferIOProc( AudioConverterRef inAudioConverter, + UInt32*ioDataSize, + void** outData, + void*inUserData ) +{ + void *dummyData; + ring_buffer_size_t dummySize; + PaUtilRingBuffer *rb = (PaUtilRingBuffer *) inUserData; + + VVDBUG(("ringBufferIOProc()\n")); + + if( PaUtil_GetRingBufferReadAvailable( rb ) == 0 ) { + *outData = NULL; + *ioDataSize = 0; + return RING_BUFFER_EMPTY; + } + assert(sizeof(UInt32) == sizeof(ring_buffer_size_t)); + assert( ( (*ioDataSize) / rb->elementSizeBytes ) * rb->elementSizeBytes == (*ioDataSize) ) ; + (*ioDataSize) /= rb->elementSizeBytes ; + PaUtil_GetRingBufferReadRegions( rb, *ioDataSize, + outData, (ring_buffer_size_t *)ioDataSize, + &dummyData, &dummySize ); + assert( *ioDataSize ); + PaUtil_AdvanceRingBufferReadIndex( rb, *ioDataSize ); + (*ioDataSize) *= rb->elementSizeBytes ; + + return noErr; +} + +/* + * Called by the AudioUnit API to process audio from the sound card. + * This is where the magic happens. + */ +/* FEEDBACK: there is a lot of redundant code here because of how all the cases differ. This makes it hard to maintain, so if there are suggestinos for cleaning it up, I'm all ears. */ +static OSStatus AudioIOProc( void *inRefCon, + AudioUnitRenderActionFlags *ioActionFlags, + const AudioTimeStamp *inTimeStamp, + UInt32 inBusNumber, + UInt32 inNumberFrames, + AudioBufferList *ioData ) +{ + unsigned long framesProcessed = 0; + PaStreamCallbackTimeInfo timeInfo = {0,0,0}; + PaMacCoreStream *stream = (PaMacCoreStream*)inRefCon; + const bool isRender = inBusNumber == OUTPUT_ELEMENT; + int callbackResult = paContinue ; + double hostTimeStampInPaTime = HOST_TIME_TO_PA_TIME(inTimeStamp->mHostTime); + + VVDBUG(("AudioIOProc()\n")); + + PaUtil_BeginCpuLoadMeasurement( &stream->cpuLoadMeasurer ); + + /* -----------------------------------------------------------------*\ + This output may be useful for debugging, + But printing durring the callback is a bad enough idea that + this is not enabled by enableing the usual debugging calls. + \* -----------------------------------------------------------------*/ + /* + static int renderCount = 0; + static int inputCount = 0; + printf( "------------------- starting reder/input\n" ); + if( isRender ) + printf("Render callback (%d):\t", ++renderCount); + else + printf("Input callback (%d):\t", ++inputCount); + printf( "Call totals: %d (input), %d (render)\n", inputCount, renderCount ); + + printf( "--- inBusNumber: %lu\n", inBusNumber ); + printf( "--- inNumberFrames: %lu\n", inNumberFrames ); + printf( "--- %x ioData\n", (unsigned) ioData ); + if( ioData ) + { + int i=0; + printf( "--- ioData.mNumBuffers %lu: \n", ioData->mNumberBuffers ); + for( i=0; imNumberBuffers; ++i ) + printf( "--- ioData buffer %d size: %lu.\n", i, ioData->mBuffers[i].mDataByteSize ); + } + ----------------------------------------------------------------- */ + + /* compute PaStreamCallbackTimeInfo */ + + if( pthread_mutex_trylock( &stream->timingInformationMutex ) == 0 ){ + /* snapshot the ioproc copy of timing information */ + stream->timestampOffsetCombined_ioProcCopy = stream->timestampOffsetCombined; + stream->timestampOffsetInputDevice_ioProcCopy = stream->timestampOffsetInputDevice; + stream->timestampOffsetOutputDevice_ioProcCopy = stream->timestampOffsetOutputDevice; + pthread_mutex_unlock( &stream->timingInformationMutex ); + } + + /* For timeInfo.currentTime we could calculate current time backwards from the HAL audio + output time to give a more accurate impression of the current timeslice but it doesn't + seem worth it at the moment since other PA host APIs don't do any better. + */ + timeInfo.currentTime = HOST_TIME_TO_PA_TIME( AudioGetCurrentHostTime() ); + + /* + For an input HAL AU, inTimeStamp is the time the samples are received from the hardware, + for an output HAL AU inTimeStamp is the time the samples are sent to the hardware. + PA expresses timestamps in terms of when the samples enter the ADC or leave the DAC + so we add or subtract kAudioDevicePropertyLatency below. + */ + + /* FIXME: not sure what to do below if the host timestamps aren't valid (kAudioTimeStampHostTimeValid isn't set) + Could ask on CA mailing list if it is possible for it not to be set. If so, could probably grab a now timestamp + at the top and compute from there (modulo scheduling jitter) or ask on mailing list for other options. */ + + if( isRender ) + { + if( stream->inputUnit ) /* full duplex */ + { + if( stream->inputUnit == stream->outputUnit ) /* full duplex AUHAL IOProc */ + { + // Ross and Phil agreed that the following calculation is correct based on an email from Jeff Moore: + // http://osdir.com/ml/coreaudio-api/2009-07/msg00140.html + // Basically the difference between the Apple output timestamp and the PA timestamp is kAudioDevicePropertyLatency. + timeInfo.inputBufferAdcTime = hostTimeStampInPaTime - + (stream->timestampOffsetCombined_ioProcCopy + stream->timestampOffsetInputDevice_ioProcCopy); + timeInfo.outputBufferDacTime = hostTimeStampInPaTime + stream->timestampOffsetOutputDevice_ioProcCopy; + } + else /* full duplex with ring-buffer from a separate input AUHAL ioproc */ + { + /* FIXME: take the ring buffer latency into account */ + timeInfo.inputBufferAdcTime = hostTimeStampInPaTime - + (stream->timestampOffsetCombined_ioProcCopy + stream->timestampOffsetInputDevice_ioProcCopy); + timeInfo.outputBufferDacTime = hostTimeStampInPaTime + stream->timestampOffsetOutputDevice_ioProcCopy; + } + } + else /* output only */ + { + timeInfo.inputBufferAdcTime = 0; + timeInfo.outputBufferDacTime = hostTimeStampInPaTime + stream->timestampOffsetOutputDevice_ioProcCopy; + } + } + else /* input only */ + { + timeInfo.inputBufferAdcTime = hostTimeStampInPaTime - stream->timestampOffsetInputDevice_ioProcCopy; + timeInfo.outputBufferDacTime = 0; + } + + //printf( "---%g, %g, %g\n", timeInfo.inputBufferAdcTime, timeInfo.currentTime, timeInfo.outputBufferDacTime ); + + if( isRender && stream->inputUnit == stream->outputUnit + && !stream->inputSRConverter ) + { + /* --------- Full Duplex, One Device, no SR Conversion ------- + * + * This is the lowest latency case, and also the simplest. + * Input data and output data are available at the same time. + * we do not use the input SR converter or the input ring buffer. + * + */ + OSStatus err = 0; + unsigned long frames; + long bytesPerFrame = sizeof( float ) * ioData->mBuffers[0].mNumberChannels; + + /* -- start processing -- */ + PaUtil_BeginBufferProcessing( &(stream->bufferProcessor), + &timeInfo, + stream->xrunFlags ); + stream->xrunFlags = 0; //FIXME: this flag also gets set outside by a callback, which calls the xrunCallback function. It should be in the same thread as the main audio callback, but the apple docs just use the word "usually" so it may be possible to loose an xrun notification, if that callback happens here. + + /* -- compute frames. do some checks -- */ + assert( ioData->mNumberBuffers == 1 ); + assert( ioData->mBuffers[0].mNumberChannels == stream->userOutChan ); + + frames = ioData->mBuffers[0].mDataByteSize / bytesPerFrame; + /* -- copy and process input data -- */ + err= AudioUnitRender(stream->inputUnit, + ioActionFlags, + inTimeStamp, + INPUT_ELEMENT, + inNumberFrames, + &stream->inputAudioBufferList ); + if(err != noErr) + { + goto stop_stream; + } + + PaUtil_SetInputFrameCount( &(stream->bufferProcessor), frames ); + PaUtil_SetInterleavedInputChannels( &(stream->bufferProcessor), + 0, + stream->inputAudioBufferList.mBuffers[0].mData, + stream->inputAudioBufferList.mBuffers[0].mNumberChannels); + /* -- Copy and process output data -- */ + PaUtil_SetOutputFrameCount( &(stream->bufferProcessor), frames ); + PaUtil_SetInterleavedOutputChannels( &(stream->bufferProcessor), + 0, + ioData->mBuffers[0].mData, + ioData->mBuffers[0].mNumberChannels); + /* -- complete processing -- */ + framesProcessed = + PaUtil_EndBufferProcessing( &(stream->bufferProcessor), + &callbackResult ); + } + else if( isRender ) + { + /* -------- Output Side of Full Duplex (Separate Devices or SR Conversion) + * -- OR Simplex Output + * + * This case handles output data as in the full duplex case, + * and, if there is input data, reads it off the ring buffer + * and into the PA buffer processor. If sample rate conversion + * is required on input, that is done here as well. + */ + unsigned long frames; + long bytesPerFrame = sizeof( float ) * ioData->mBuffers[0].mNumberChannels; + + /* Sometimes, when stopping a duplex stream we get erroneous + xrun flags, so if this is our last run, clear the flags. */ + int xrunFlags = stream->xrunFlags; +/* + if( xrunFlags & paInputUnderflow ) + printf( "input underflow.\n" ); + if( xrunFlags & paInputOverflow ) + printf( "input overflow.\n" ); +*/ + if( stream->state == STOPPING || stream->state == CALLBACK_STOPPED ) + xrunFlags = 0; + + /* -- start processing -- */ + PaUtil_BeginBufferProcessing( &(stream->bufferProcessor), + &timeInfo, + xrunFlags ); + stream->xrunFlags = 0; /* FEEDBACK: we only send flags to Buf Proc once */ + + /* -- Copy and process output data -- */ + assert( ioData->mNumberBuffers == 1 ); + frames = ioData->mBuffers[0].mDataByteSize / bytesPerFrame; + assert( ioData->mBuffers[0].mNumberChannels == stream->userOutChan ); + PaUtil_SetOutputFrameCount( &(stream->bufferProcessor), frames ); + PaUtil_SetInterleavedOutputChannels( &(stream->bufferProcessor), + 0, + ioData->mBuffers[0].mData, + ioData->mBuffers[0].mNumberChannels); + + /* -- copy and process input data, and complete processing -- */ + if( stream->inputUnit ) { + const int flsz = sizeof( float ); + /* Here, we read the data out of the ring buffer, through the + audio converter. */ + int inChan = stream->inputAudioBufferList.mBuffers[0].mNumberChannels; + long bytesPerFrame = flsz * inChan; + + if( stream->inputSRConverter ) + { + OSStatus err; + UInt32 size; + float data[ inChan * frames ]; + size = sizeof( data ); + err = AudioConverterFillBuffer( + stream->inputSRConverter, + ringBufferIOProc, + &stream->inputRingBuffer, + &size, + (void *)&data ); + if( err == RING_BUFFER_EMPTY ) + { /* the ring buffer callback underflowed */ + err = 0; + bzero( ((char *)data) + size, sizeof(data)-size ); + /* The ring buffer can underflow normally when the stream is stopping. + * So only report an error if the stream is active. */ + if( stream->state == ACTIVE ) + { + stream->xrunFlags |= paInputUnderflow; + } + } + ERR( err ); + if(err != noErr) + { + goto stop_stream; + } + + PaUtil_SetInputFrameCount( &(stream->bufferProcessor), frames ); + PaUtil_SetInterleavedInputChannels( &(stream->bufferProcessor), + 0, + data, + inChan ); + framesProcessed = + PaUtil_EndBufferProcessing( &(stream->bufferProcessor), + &callbackResult ); + } + else + { + /* Without the AudioConverter is actually a bit more complex + because we have to do a little buffer processing that the + AudioConverter would otherwise handle for us. */ + void *data1, *data2; + ring_buffer_size_t size1, size2; + ring_buffer_size_t framesReadable = PaUtil_GetRingBufferReadRegions( &stream->inputRingBuffer, + frames, + &data1, &size1, + &data2, &size2 ); + if( size1 == frames ) { + /* simplest case: all in first buffer */ + PaUtil_SetInputFrameCount( &(stream->bufferProcessor), frames ); + PaUtil_SetInterleavedInputChannels( &(stream->bufferProcessor), + 0, + data1, + inChan ); + framesProcessed = + PaUtil_EndBufferProcessing( &(stream->bufferProcessor), + &callbackResult ); + PaUtil_AdvanceRingBufferReadIndex(&stream->inputRingBuffer, size1 ); + } else if( framesReadable < frames ) { + + long sizeBytes1 = size1 * bytesPerFrame; + long sizeBytes2 = size2 * bytesPerFrame; + /*we underflowed. take what data we can, zero the rest.*/ + unsigned char data[ frames * bytesPerFrame ]; + if( size1 > 0 ) + { + memcpy( data, data1, sizeBytes1 ); + } + if( size2 > 0 ) + { + memcpy( data+sizeBytes1, data2, sizeBytes2 ); + } + bzero( data+sizeBytes1+sizeBytes2, (frames*bytesPerFrame) - sizeBytes1 - sizeBytes2 ); + + PaUtil_SetInputFrameCount( &(stream->bufferProcessor), frames ); + PaUtil_SetInterleavedInputChannels( &(stream->bufferProcessor), + 0, + data, + inChan ); + framesProcessed = + PaUtil_EndBufferProcessing( &(stream->bufferProcessor), + &callbackResult ); + PaUtil_AdvanceRingBufferReadIndex( &stream->inputRingBuffer, + framesReadable ); + /* flag underflow */ + stream->xrunFlags |= paInputUnderflow; + } else { + /*we got all the data, but split between buffers*/ + PaUtil_SetInputFrameCount( &(stream->bufferProcessor), size1 ); + PaUtil_SetInterleavedInputChannels( &(stream->bufferProcessor), + 0, + data1, + inChan ); + PaUtil_Set2ndInputFrameCount( &(stream->bufferProcessor), size2 ); + PaUtil_Set2ndInterleavedInputChannels( &(stream->bufferProcessor), + 0, + data2, + inChan ); + framesProcessed = + PaUtil_EndBufferProcessing( &(stream->bufferProcessor), + &callbackResult ); + PaUtil_AdvanceRingBufferReadIndex(&stream->inputRingBuffer, framesReadable ); + } + } + } else { + framesProcessed = + PaUtil_EndBufferProcessing( &(stream->bufferProcessor), + &callbackResult ); + } + + } + else + { + /* ------------------ Input + * + * First, we read off the audio data and put it in the ring buffer. + * if this is an input-only stream, we need to process it more, + * otherwise, we let the output case deal with it. + */ + OSStatus err = 0; + int chan = stream->inputAudioBufferList.mBuffers[0].mNumberChannels ; + /* FIXME: looping here may not actually be necessary, but it was something I tried in testing. */ + do { + err= AudioUnitRender(stream->inputUnit, + ioActionFlags, + inTimeStamp, + INPUT_ELEMENT, + inNumberFrames, + &stream->inputAudioBufferList ); + if( err == -10874 ) + inNumberFrames /= 2; + } while( err == -10874 && inNumberFrames > 1 ); + ERR( err ); + if(err != noErr) + { + goto stop_stream; + } + + if( stream->inputSRConverter || stream->outputUnit ) + { + /* If this is duplex or we use a converter, put the data + into the ring buffer. */ + ring_buffer_size_t framesWritten = PaUtil_WriteRingBuffer( &stream->inputRingBuffer, + stream->inputAudioBufferList.mBuffers[0].mData, + inNumberFrames ); + if( framesWritten != inNumberFrames ) + { + stream->xrunFlags |= paInputOverflow ; + } + } + else + { + /* for simplex input w/o SR conversion, + just pop the data into the buffer processor.*/ + PaUtil_BeginBufferProcessing( &(stream->bufferProcessor), + &timeInfo, + stream->xrunFlags ); + stream->xrunFlags = 0; + + PaUtil_SetInputFrameCount( &(stream->bufferProcessor), inNumberFrames); + PaUtil_SetInterleavedInputChannels( &(stream->bufferProcessor), + 0, + stream->inputAudioBufferList.mBuffers[0].mData, + chan ); + framesProcessed = + PaUtil_EndBufferProcessing( &(stream->bufferProcessor), + &callbackResult ); + } + if( !stream->outputUnit && stream->inputSRConverter ) + { + /* ------------------ Simplex Input w/ SR Conversion + * + * if this is a simplex input stream, we need to read off the buffer, + * do our sample rate conversion and pass the results to the buffer + * processor. + * The logic here is complicated somewhat by the fact that we don't + * know how much data is available, so we loop on reasonably sized + * chunks, and let the BufferProcessor deal with the rest. + * + */ + /* This might be too big or small depending on SR conversion. */ + float data[ chan * inNumberFrames ]; + OSStatus err; + do + { /* Run the buffer processor until we are out of data. */ + UInt32 size; + long f; + + size = sizeof( data ); + err = AudioConverterFillBuffer( + stream->inputSRConverter, + ringBufferIOProc, + &stream->inputRingBuffer, + &size, + (void *)data ); + if( err != RING_BUFFER_EMPTY ) + ERR( err ); + if( err != noErr && err != RING_BUFFER_EMPTY ) + { + goto stop_stream; + } + + + f = size / ( chan * sizeof(float) ); + PaUtil_SetInputFrameCount( &(stream->bufferProcessor), f ); + if( f ) + { + PaUtil_BeginBufferProcessing( &(stream->bufferProcessor), + &timeInfo, + stream->xrunFlags ); + stream->xrunFlags = 0; + + PaUtil_SetInterleavedInputChannels( &(stream->bufferProcessor), + 0, + data, + chan ); + framesProcessed = + PaUtil_EndBufferProcessing( &(stream->bufferProcessor), + &callbackResult ); + } + } while( callbackResult == paContinue && !err ); + } + } + + // Should we return successfully or fall through to stopping the stream? + if( callbackResult == paContinue ) + { + PaUtil_EndCpuLoadMeasurement( &stream->cpuLoadMeasurer, framesProcessed ); + return noErr; + } + +stop_stream: + stream->state = CALLBACK_STOPPED ; + if( stream->outputUnit ) + AudioOutputUnitStop(stream->outputUnit); + if( stream->inputUnit ) + AudioOutputUnitStop(stream->inputUnit); + + PaUtil_EndCpuLoadMeasurement( &stream->cpuLoadMeasurer, framesProcessed ); + return noErr; +} + +/* + When CloseStream() is called, the multi-api layer ensures that + the stream has already been stopped or aborted. +*/ +static PaError CloseStream( PaStream* s ) +{ + /* This may be called from a failed OpenStream. + Therefore, each piece of info is treated seperately. */ + PaError result = paNoError; + PaMacCoreStream *stream = (PaMacCoreStream*)s; + + VVDBUG(("CloseStream()\n")); + VDBUG( ( "Closing stream.\n" ) ); + + if( stream ) { + + if( stream->outputUnit ) + { + Boolean isInput = FALSE; + CleanupDevicePropertyListeners( stream, stream->outputDevice, isInput ); + } + + if( stream->inputUnit ) + { + Boolean isInput = TRUE; + CleanupDevicePropertyListeners( stream, stream->inputDevice, isInput ); + } + + if( stream->outputUnit ) { + int count = removeFromXRunListenerList( stream ); + if( count == 0 ) + AudioDeviceRemovePropertyListener( stream->outputDevice, + 0, + false, + kAudioDeviceProcessorOverload, + xrunCallback ); + } + if( stream->inputUnit && stream->outputUnit != stream->inputUnit ) { + int count = removeFromXRunListenerList( stream ); + if( count == 0 ) + AudioDeviceRemovePropertyListener( stream->inputDevice, + 0, + true, + kAudioDeviceProcessorOverload, + xrunCallback ); + } + if( stream->outputUnit && stream->outputUnit != stream->inputUnit ) { + AudioUnitUninitialize( stream->outputUnit ); + CloseComponent( stream->outputUnit ); + } + stream->outputUnit = NULL; + if( stream->inputUnit ) + { + AudioUnitUninitialize( stream->inputUnit ); + CloseComponent( stream->inputUnit ); + stream->inputUnit = NULL; + } + if( stream->inputRingBuffer.buffer ) + free( (void *) stream->inputRingBuffer.buffer ); + stream->inputRingBuffer.buffer = NULL; + /*TODO: is there more that needs to be done on error + from AudioConverterDispose?*/ + if( stream->inputSRConverter ) + ERR( AudioConverterDispose( stream->inputSRConverter ) ); + stream->inputSRConverter = NULL; + if( stream->inputAudioBufferList.mBuffers[0].mData ) + free( stream->inputAudioBufferList.mBuffers[0].mData ); + stream->inputAudioBufferList.mBuffers[0].mData = NULL; + + result = destroyBlioRingBuffers( &stream->blio ); + if( result ) + return result; + if( stream->bufferProcessorIsInitialized ) + PaUtil_TerminateBufferProcessor( &stream->bufferProcessor ); + + if( stream->timingInformationMutexIsInitialized ) + pthread_mutex_destroy( &stream->timingInformationMutex ); + + PaUtil_TerminateStreamRepresentation( &stream->streamRepresentation ); + PaUtil_FreeMemory( stream ); + } + + return result; +} + +static PaError StartStream( PaStream *s ) +{ + PaMacCoreStream *stream = (PaMacCoreStream*)s; + OSStatus result = noErr; + VVDBUG(("StartStream()\n")); + VDBUG( ( "Starting stream.\n" ) ); + +#define ERR_WRAP(mac_err) do { result = mac_err ; if ( result != noErr ) return ERR(result) ; } while(0) + + /*FIXME: maybe want to do this on close/abort for faster start? */ + PaUtil_ResetBufferProcessor( &stream->bufferProcessor ); + if( stream->inputSRConverter ) + ERR_WRAP( AudioConverterReset( stream->inputSRConverter ) ); + + /* -- start -- */ + stream->state = ACTIVE; + if( stream->inputUnit ) { + ERR_WRAP( AudioOutputUnitStart(stream->inputUnit) ); + } + if( stream->outputUnit && stream->outputUnit != stream->inputUnit ) { + ERR_WRAP( AudioOutputUnitStart(stream->outputUnit) ); + } + + return paNoError; +#undef ERR_WRAP +} + +// it's not clear from appl's docs that this really waits +// until all data is flushed. +static ComponentResult BlockWhileAudioUnitIsRunning( AudioUnit audioUnit, AudioUnitElement element ) +{ + Boolean isRunning = 1; + while( isRunning ) { + UInt32 s = sizeof( isRunning ); + ComponentResult err = AudioUnitGetProperty( audioUnit, kAudioOutputUnitProperty_IsRunning, kAudioUnitScope_Global, element, &isRunning, &s ); + if( err ) + return err; + Pa_Sleep( 100 ); + } + return noErr; +} + +static PaError FinishStoppingStream( PaMacCoreStream *stream ) +{ + OSStatus result = noErr; + PaError paErr; + +#define ERR_WRAP(mac_err) do { result = mac_err ; if ( result != noErr ) return ERR(result) ; } while(0) + /* -- stop and reset -- */ + if( stream->inputUnit == stream->outputUnit && stream->inputUnit ) + { + ERR_WRAP( AudioOutputUnitStop(stream->inputUnit) ); + ERR_WRAP( BlockWhileAudioUnitIsRunning(stream->inputUnit,0) ); + ERR_WRAP( BlockWhileAudioUnitIsRunning(stream->inputUnit,1) ); + ERR_WRAP( AudioUnitReset(stream->inputUnit, kAudioUnitScope_Global, 1) ); + ERR_WRAP( AudioUnitReset(stream->inputUnit, kAudioUnitScope_Global, 0) ); + } + else + { + if( stream->inputUnit ) + { + ERR_WRAP(AudioOutputUnitStop(stream->inputUnit) ); + ERR_WRAP( BlockWhileAudioUnitIsRunning(stream->inputUnit,1) ); + ERR_WRAP(AudioUnitReset(stream->inputUnit,kAudioUnitScope_Global,1)); + } + if( stream->outputUnit ) + { + ERR_WRAP(AudioOutputUnitStop(stream->outputUnit)); + ERR_WRAP( BlockWhileAudioUnitIsRunning(stream->outputUnit,0) ); + ERR_WRAP(AudioUnitReset(stream->outputUnit,kAudioUnitScope_Global,0)); + } + } + if( stream->inputRingBuffer.buffer ) { + PaUtil_FlushRingBuffer( &stream->inputRingBuffer ); + bzero( (void *)stream->inputRingBuffer.buffer, + stream->inputRingBuffer.bufferSize ); + /* advance the write point a little, so we are reading from the + middle of the buffer. We'll need extra at the end because + testing has shown that this helps. */ + if( stream->outputUnit ) + PaUtil_AdvanceRingBufferWriteIndex( &stream->inputRingBuffer, + stream->inputRingBuffer.bufferSize + / RING_BUFFER_ADVANCE_DENOMINATOR ); + } + + stream->xrunFlags = 0; + stream->state = STOPPED; + + paErr = resetBlioRingBuffers( &stream->blio ); + if( paErr ) + return paErr; + + VDBUG( ( "Stream Stopped.\n" ) ); + return paNoError; +#undef ERR_WRAP +} + +/* Block until buffer is empty then stop the stream. */ +static PaError StopStream( PaStream *s ) +{ + PaError paErr; + PaMacCoreStream *stream = (PaMacCoreStream*)s; + VVDBUG(("StopStream()\n")); + + /* Tell WriteStream to stop filling the buffer. */ + stream->state = STOPPING; + + if( stream->userOutChan > 0 ) /* Does this stream do output? */ + { + size_t maxHostFrames = MAX( stream->inputFramesPerBuffer, stream->outputFramesPerBuffer ); + VDBUG( ("Waiting for write buffer to be drained.\n") ); + paErr = waitUntilBlioWriteBufferIsEmpty( &stream->blio, stream->sampleRate, + maxHostFrames ); + VDBUG( ( "waitUntilBlioWriteBufferIsEmpty returned %d\n", paErr ) ); + } + return FinishStoppingStream( stream ); +} + +/* Immediately stop the stream. */ +static PaError AbortStream( PaStream *s ) +{ + PaMacCoreStream *stream = (PaMacCoreStream*)s; + VDBUG( ( "AbortStream()\n" ) ); + stream->state = STOPPING; + return FinishStoppingStream( stream ); +} + + +static PaError IsStreamStopped( PaStream *s ) +{ + PaMacCoreStream *stream = (PaMacCoreStream*)s; + VVDBUG(("IsStreamStopped()\n")); + + return stream->state == STOPPED ? 1 : 0; +} + + +static PaError IsStreamActive( PaStream *s ) +{ + PaMacCoreStream *stream = (PaMacCoreStream*)s; + VVDBUG(("IsStreamActive()\n")); + return ( stream->state == ACTIVE || stream->state == STOPPING ); +} + + +static double GetStreamCpuLoad( PaStream* s ) +{ + PaMacCoreStream *stream = (PaMacCoreStream*)s; + VVDBUG(("GetStreamCpuLoad()\n")); + + return PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer ); +} diff --git a/extern/portaudio/src/hostapi/coreaudio/pa_mac_core_blocking.c b/extern/portaudio/src/hostapi/coreaudio/pa_mac_core_blocking.c new file mode 100644 index 0000000..679c6ba --- /dev/null +++ b/extern/portaudio/src/hostapi/coreaudio/pa_mac_core_blocking.c @@ -0,0 +1,637 @@ +/* + * Implementation of the PortAudio API for Apple AUHAL + * + * PortAudio Portable Real-Time Audio Library + * Latest Version at: http://www.portaudio.com + * + * Written by Bjorn Roche of XO Audio LLC, from PA skeleton code. + * Portions copied from code by Dominic Mazzoni (who wrote a HAL implementation) + * + * Dominic's code was based on code by Phil Burk, Darren Gibbs, + * Gord Peters, Stephane Letz, and Greg Pfiel. + * + * The following people also deserve acknowledgements: + * + * Olivier Tristan for feedback and testing + * Glenn Zelniker and Z-Systems engineering for sponsoring the Blocking I/O + * interface. + * + * + * Based on the Open Source API proposed by Ross Bencina + * Copyright (c) 1999-2002 Ross Bencina, Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +/** + @file + @ingroup hostapi_src + + This file contains the implementation + required for blocking I/O. It is separated from pa_mac_core.c simply to ease + development. +*/ + +#include "pa_mac_core_blocking.h" +#include "pa_mac_core_internal.h" +#include +#ifdef MOSX_USE_NON_ATOMIC_FLAG_BITS +# define OSAtomicOr32( a, b ) ( (*(b)) |= (a) ) +# define OSAtomicAnd32( a, b ) ( (*(b)) &= (a) ) +#else +# include +#endif + +/* + * This function determines the size of a particular sample format. + * if the format is not recognized, this returns zero. + */ +static size_t computeSampleSizeFromFormat( PaSampleFormat format ) +{ + switch( format & (~paNonInterleaved) ) { + case paFloat32: return 4; + case paInt32: return 4; + case paInt24: return 3; + case paInt16: return 2; + case paInt8: case paUInt8: return 1; + default: return 0; + } +} +/* + * Same as computeSampleSizeFromFormat, except that if + * the size is not a power of two, it returns the next power of two up + */ +static size_t computeSampleSizeFromFormatPow2( PaSampleFormat format ) +{ + switch( format & (~paNonInterleaved) ) { + case paFloat32: return 4; + case paInt32: return 4; + case paInt24: return 4; + case paInt16: return 2; + case paInt8: case paUInt8: return 1; + default: return 0; + } +} + + + +/* + * Functions for initializing, resetting, and destroying BLIO structures. + * + */ + +/** + * This should be called with the relevant info when initializing a stream for callback. + * + * @param ringBufferSizeInFrames must be a power of 2 + */ +PaError initializeBlioRingBuffers( + PaMacBlio *blio, + PaSampleFormat inputSampleFormat, + PaSampleFormat outputSampleFormat, + long ringBufferSizeInFrames, + int inChan, + int outChan ) +{ + void *data; + int result; + OSStatus err; + + /* zeroify things */ + bzero( blio, sizeof( PaMacBlio ) ); + /* this is redundant, but the buffers are used to check + if the buffers have been initialized, so we do it explicitly. */ + blio->inputRingBuffer.buffer = NULL; + blio->outputRingBuffer.buffer = NULL; + + /* initialize simple data */ + blio->ringBufferFrames = ringBufferSizeInFrames; + blio->inputSampleFormat = inputSampleFormat; + blio->inputSampleSizeActual = computeSampleSizeFromFormat(inputSampleFormat); + blio->inputSampleSizePow2 = computeSampleSizeFromFormatPow2(inputSampleFormat); // FIXME: WHY? + blio->outputSampleFormat = outputSampleFormat; + blio->outputSampleSizeActual = computeSampleSizeFromFormat(outputSampleFormat); + blio->outputSampleSizePow2 = computeSampleSizeFromFormatPow2(outputSampleFormat); + + blio->inChan = inChan; + blio->outChan = outChan; + blio->statusFlags = 0; + blio->errors = paNoError; +#ifdef PA_MAC_BLIO_MUTEX + blio->isInputEmpty = false; + blio->isOutputFull = false; +#endif + + /* setup ring buffers */ +#ifdef PA_MAC_BLIO_MUTEX + result = PaMacCore_SetUnixError( pthread_mutex_init(&(blio->inputMutex),NULL), 0 ); + if( result ) + goto error; + result = UNIX_ERR( pthread_cond_init( &(blio->inputCond), NULL ) ); + if( result ) + goto error; + result = UNIX_ERR( pthread_mutex_init(&(blio->outputMutex),NULL) ); + if( result ) + goto error; + result = UNIX_ERR( pthread_cond_init( &(blio->outputCond), NULL ) ); +#endif + if( inChan ) { + data = calloc( ringBufferSizeInFrames, blio->inputSampleSizePow2 * inChan ); + if( !data ) + { + result = paInsufficientMemory; + goto error; + } + + err = PaUtil_InitializeRingBuffer( + &blio->inputRingBuffer, + blio->inputSampleSizePow2 * inChan, + ringBufferSizeInFrames, + data ); + assert( !err ); + } + if( outChan ) { + data = calloc( ringBufferSizeInFrames, blio->outputSampleSizePow2 * outChan ); + if( !data ) + { + result = paInsufficientMemory; + goto error; + } + + err = PaUtil_InitializeRingBuffer( + &blio->outputRingBuffer, + blio->outputSampleSizePow2 * outChan, + ringBufferSizeInFrames, + data ); + assert( !err ); + } + + result = resetBlioRingBuffers( blio ); + if( result ) + goto error; + + return 0; + + error: + destroyBlioRingBuffers( blio ); + return result; +} + +#ifdef PA_MAC_BLIO_MUTEX +PaError blioSetIsInputEmpty( PaMacBlio *blio, bool isEmpty ) +{ + PaError result = paNoError; + if( isEmpty == blio->isInputEmpty ) + goto done; + + /* we need to update the value. Here's what we do: + * - Lock the mutex, so noone else can write. + * - update the value. + * - unlock. + * - broadcast to all listeners. + */ + result = UNIX_ERR( pthread_mutex_lock( &blio->inputMutex ) ); + if( result ) + goto done; + blio->isInputEmpty = isEmpty; + result = UNIX_ERR( pthread_mutex_unlock( &blio->inputMutex ) ); + if( result ) + goto done; + result = UNIX_ERR( pthread_cond_broadcast( &blio->inputCond ) ); + if( result ) + goto done; + + done: + return result; +} +PaError blioSetIsOutputFull( PaMacBlio *blio, bool isFull ) +{ + PaError result = paNoError; + if( isFull == blio->isOutputFull ) + goto done; + + /* we need to update the value. Here's what we do: + * - Lock the mutex, so noone else can write. + * - update the value. + * - unlock. + * - broadcast to all listeners. + */ + result = UNIX_ERR( pthread_mutex_lock( &blio->outputMutex ) ); + if( result ) + goto done; + blio->isOutputFull = isFull; + result = UNIX_ERR( pthread_mutex_unlock( &blio->outputMutex ) ); + if( result ) + goto done; + result = UNIX_ERR( pthread_cond_broadcast( &blio->outputCond ) ); + if( result ) + goto done; + + done: + return result; +} +#endif + +/* This should be called after stopping or aborting the stream, so that on next + start, the buffers will be ready. */ +PaError resetBlioRingBuffers( PaMacBlio *blio ) +{ +#ifdef PA_MAC__BLIO_MUTEX + int result; +#endif + blio->statusFlags = 0; + if( blio->outputRingBuffer.buffer ) { + PaUtil_FlushRingBuffer( &blio->outputRingBuffer ); + /* Fill the buffer with zeros. */ + bzero( blio->outputRingBuffer.buffer, + blio->outputRingBuffer.bufferSize * blio->outputRingBuffer.elementSizeBytes ); + PaUtil_AdvanceRingBufferWriteIndex( &blio->outputRingBuffer, blio->ringBufferFrames ); + + /* Update isOutputFull. */ +#ifdef PA_MAC__BLIO_MUTEX + result = blioSetIsOutputFull( blio, toAdvance == blio->outputRingBuffer.bufferSize ); + if( result ) + goto error; +#endif +/* + printf( "------%d\n" , blio->outChan ); + printf( "------%d\n" , blio->outputSampleSize ); +*/ + } + if( blio->inputRingBuffer.buffer ) { + PaUtil_FlushRingBuffer( &blio->inputRingBuffer ); + bzero( blio->inputRingBuffer.buffer, + blio->inputRingBuffer.bufferSize * blio->inputRingBuffer.elementSizeBytes ); + /* Update isInputEmpty. */ +#ifdef PA_MAC__BLIO_MUTEX + result = blioSetIsInputEmpty( blio, true ); + if( result ) + goto error; +#endif + } + return paNoError; +#ifdef PA_MAC__BLIO_MUTEX + error: + return result; +#endif +} + +/*This should be called when you are done with the blio. It can safely be called + multiple times if there are no exceptions. */ +PaError destroyBlioRingBuffers( PaMacBlio *blio ) +{ + PaError result = paNoError; + if( blio->inputRingBuffer.buffer ) { + free( blio->inputRingBuffer.buffer ); +#ifdef PA_MAC__BLIO_MUTEX + result = UNIX_ERR( pthread_mutex_destroy( & blio->inputMutex ) ); + if( result ) return result; + result = UNIX_ERR( pthread_cond_destroy( & blio->inputCond ) ); + if( result ) return result; +#endif + } + blio->inputRingBuffer.buffer = NULL; + if( blio->outputRingBuffer.buffer ) { + free( blio->outputRingBuffer.buffer ); +#ifdef PA_MAC__BLIO_MUTEX + result = UNIX_ERR( pthread_mutex_destroy( & blio->outputMutex ) ); + if( result ) return result; + result = UNIX_ERR( pthread_cond_destroy( & blio->outputCond ) ); + if( result ) return result; +#endif + } + blio->outputRingBuffer.buffer = NULL; + + return result; +} + +/* + * this is the BlioCallback function. It expects to recieve a PaMacBlio Object + * pointer as userData. + * + */ +int BlioCallback( const void *input, void *output, unsigned long frameCount, + const PaStreamCallbackTimeInfo* timeInfo, + PaStreamCallbackFlags statusFlags, + void *userData ) +{ + PaMacBlio *blio = (PaMacBlio*)userData; + ring_buffer_size_t framesAvailable; + ring_buffer_size_t framesToTransfer; + ring_buffer_size_t framesTransferred; + + /* set flags returned by OS: */ + OSAtomicOr32( statusFlags, &blio->statusFlags ) ; + + /* --- Handle Input Buffer --- */ + if( blio->inChan ) { + framesAvailable = PaUtil_GetRingBufferWriteAvailable( &blio->inputRingBuffer ); + + /* check for underflow */ + if( framesAvailable < frameCount ) + { + OSAtomicOr32( paInputOverflow, &blio->statusFlags ); + framesToTransfer = framesAvailable; + } + else + { + framesToTransfer = (ring_buffer_size_t)frameCount; + } + + /* Copy the data from the audio input to the application ring buffer. */ + /*printf( "reading %d\n", toRead );*/ + framesTransferred = PaUtil_WriteRingBuffer( &blio->inputRingBuffer, input, framesToTransfer ); + assert( framesToTransfer == framesTransferred ); +#ifdef PA_MAC__BLIO_MUTEX + /* Priority inversion. See notes below. */ + blioSetIsInputEmpty( blio, false ); +#endif + } + + + /* --- Handle Output Buffer --- */ + if( blio->outChan ) { + framesAvailable = PaUtil_GetRingBufferReadAvailable( &blio->outputRingBuffer ); + + /* check for underflow */ + if( framesAvailable < frameCount ) + { + /* zero out the end of the output buffer that we do not have data for */ + framesToTransfer = framesAvailable; + + size_t bytesPerFrame = blio->outputSampleSizeActual * blio->outChan; + size_t offsetInBytes = framesToTransfer * bytesPerFrame; + size_t countInBytes = (frameCount - framesToTransfer) * bytesPerFrame; + bzero( ((char *)output) + offsetInBytes, countInBytes ); + + OSAtomicOr32( paOutputUnderflow, &blio->statusFlags ); + framesToTransfer = framesAvailable; + } + else + { + framesToTransfer = (ring_buffer_size_t)frameCount; + } + + /* copy the data */ + /*printf( "writing %d\n", toWrite );*/ + framesTransferred = PaUtil_ReadRingBuffer( &blio->outputRingBuffer, output, framesToTransfer ); + assert( framesToTransfer == framesTransferred ); +#ifdef PA_MAC__BLIO_MUTEX + /* We have a priority inversion here. However, we will only have to + wait if this was true and is now false, which means we've got + some room in the buffer. + Hopefully problems will be minimized. */ + blioSetIsOutputFull( blio, false ); +#endif + } + + return paContinue; +} + +PaError ReadStream( PaStream* stream, + void *buffer, + unsigned long framesRequested ) +{ + PaMacBlio *blio = & ((PaMacCoreStream*)stream) -> blio; + char *cbuf = (char *) buffer; + PaError ret = paNoError; + VVDBUG(("ReadStream()\n")); + + while( framesRequested > 0 ) { + ring_buffer_size_t framesAvailable; + ring_buffer_size_t framesToTransfer; + ring_buffer_size_t framesTransferred; + do { + framesAvailable = PaUtil_GetRingBufferReadAvailable( &blio->inputRingBuffer ); +/* + printf( "Read Buffer is %%%g full: %ld of %ld.\n", + 100 * (float)avail / (float) blio->inputRingBuffer.bufferSize, + framesAvailable, blio->inputRingBuffer.bufferSize ); +*/ + if( framesAvailable == 0 ) { +#ifdef PA_MAC_BLIO_MUTEX + /**block when empty*/ + ret = UNIX_ERR( pthread_mutex_lock( &blio->inputMutex ) ); + if( ret ) + return ret; + while( blio->isInputEmpty ) { + ret = UNIX_ERR( pthread_cond_wait( &blio->inputCond, &blio->inputMutex ) ); + if( ret ) + return ret; + } + ret = UNIX_ERR( pthread_mutex_unlock( &blio->inputMutex ) ); + if( ret ) + return ret; +#else + Pa_Sleep( PA_MAC_BLIO_BUSY_WAIT_SLEEP_INTERVAL ); +#endif + } + } while( framesAvailable == 0 ); + framesToTransfer = (ring_buffer_size_t) MIN( framesAvailable, framesRequested ); + framesTransferred = PaUtil_ReadRingBuffer( &blio->inputRingBuffer, (void *)cbuf, framesToTransfer ); + cbuf += framesTransferred * blio->inputSampleSizeActual * blio->inChan; + framesRequested -= framesTransferred; + + if( framesToTransfer == framesAvailable ) { +#ifdef PA_MAC_BLIO_MUTEX + /* we just emptied the buffer, so we need to mark it as empty. */ + ret = blioSetIsInputEmpty( blio, true ); + if( ret ) + return ret; + /* of course, in the meantime, the callback may have put some sats + in, so + so check for that, too, to avoid a race condition. */ + /* FIXME - this does not seem to fix any race condition. */ + if( PaUtil_GetRingBufferReadAvailable( &blio->inputRingBuffer ) ) { + blioSetIsInputEmpty( blio, false ); + /* FIXME - why check? ret has not been set? */ + if( ret ) + return ret; + } +#endif + } + } + + /* Report either paNoError or paInputOverflowed. */ + /* may also want to report other errors, but this is non-standard. */ + /* FIXME should not clobber ret, use if(blio->statusFlags & paInputOverflow) */ + ret = blio->statusFlags & paInputOverflow; + + /* report underflow only once: */ + if( ret ) { + OSAtomicAnd32( (uint32_t)(~paInputOverflow), &blio->statusFlags ); + ret = paInputOverflowed; + } + + return ret; +} + + +PaError WriteStream( PaStream* stream, + const void *buffer, + unsigned long framesRequested ) +{ + PaMacCoreStream *macStream = (PaMacCoreStream*)stream; + PaMacBlio *blio = &macStream->blio; + char *cbuf = (char *) buffer; + PaError ret = paNoError; + VVDBUG(("WriteStream()\n")); + + while( framesRequested > 0 && macStream->state != STOPPING ) { + ring_buffer_size_t framesAvailable; + ring_buffer_size_t framesToTransfer; + ring_buffer_size_t framesTransferred; + + do { + framesAvailable = PaUtil_GetRingBufferWriteAvailable( &blio->outputRingBuffer ); +/* + printf( "Write Buffer is %%%g full: %ld of %ld.\n", + 100 - 100 * (float)avail / (float) blio->outputRingBuffer.bufferSize, + framesAvailable, blio->outputRingBuffer.bufferSize ); +*/ + if( framesAvailable == 0 ) { +#ifdef PA_MAC_BLIO_MUTEX + /*block while full*/ + ret = UNIX_ERR( pthread_mutex_lock( &blio->outputMutex ) ); + if( ret ) + return ret; + while( blio->isOutputFull ) { + ret = UNIX_ERR( pthread_cond_wait( &blio->outputCond, &blio->outputMutex ) ); + if( ret ) + return ret; + } + ret = UNIX_ERR( pthread_mutex_unlock( &blio->outputMutex ) ); + if( ret ) + return ret; +#else + Pa_Sleep( PA_MAC_BLIO_BUSY_WAIT_SLEEP_INTERVAL ); +#endif + } + } while( framesAvailable == 0 && macStream->state != STOPPING ); + + if( macStream->state == STOPPING ) + { + break; + } + + framesToTransfer = MIN( framesAvailable, framesRequested ); + framesTransferred = PaUtil_WriteRingBuffer( &blio->outputRingBuffer, (void *)cbuf, framesToTransfer ); + cbuf += framesTransferred * blio->outputSampleSizeActual * blio->outChan; + framesRequested -= framesTransferred; + +#ifdef PA_MAC_BLIO_MUTEX + if( framesToTransfer == framesAvailable ) { + /* we just filled up the buffer, so we need to mark it as filled. */ + ret = blioSetIsOutputFull( blio, true ); + if( ret ) + return ret; + /* of course, in the meantime, we may have emptied the buffer, so + so check for that, too, to avoid a race condition. */ + if( PaUtil_GetRingBufferWriteAvailable( &blio->outputRingBuffer ) ) { + blioSetIsOutputFull( blio, false ); + /* FIXME remove or review this code, does not fix race, ret not set! */ + if( ret ) + return ret; + } + } +#endif + } + + if ( macStream->state == STOPPING ) + { + ret = paInternalError; + } + else if (ret == paNoError ) + { + /* Test for underflow. */ + ret = blio->statusFlags & paOutputUnderflow; + + /* report underflow only once: */ + if( ret ) + { + OSAtomicAnd32( (uint32_t)(~paOutputUnderflow), &blio->statusFlags ); + ret = paOutputUnderflowed; + } + } + + return ret; +} + +/* + * Wait until the data in the buffer has finished playing. + */ +PaError waitUntilBlioWriteBufferIsEmpty( PaMacBlio *blio, double sampleRate, + size_t framesPerBuffer ) +{ + PaError result = paNoError; + if( blio->outputRingBuffer.buffer ) { + ring_buffer_size_t framesLeft = PaUtil_GetRingBufferReadAvailable( &blio->outputRingBuffer ); + + /* Calculate when we should give up waiting. To be safe wait for two extra periods. */ + PaTime now = PaUtil_GetTime(); + PaTime startTime = now; + PaTime timeoutTime = startTime + (framesLeft + (2 * framesPerBuffer)) / sampleRate; + + long msecPerBuffer = 1 + (long)( 1000.0 * framesPerBuffer / sampleRate); + while( framesLeft > 0 && now < timeoutTime ) { + VDBUG(( "waitUntilBlioWriteBufferIsFlushed: framesLeft = %d, framesPerBuffer = %ld\n", + framesLeft, framesPerBuffer )); + Pa_Sleep( msecPerBuffer ); + framesLeft = PaUtil_GetRingBufferReadAvailable( &blio->outputRingBuffer ); + now = PaUtil_GetTime(); + } + + if( framesLeft > 0 ) + { + VDBUG(( "waitUntilBlioWriteBufferIsFlushed: TIMED OUT - framesLeft = %d\n", framesLeft )); + result = paTimedOut; + } + } + return result; +} + +signed long GetStreamReadAvailable( PaStream* stream ) +{ + PaMacBlio *blio = & ((PaMacCoreStream*)stream) -> blio; + VVDBUG(("GetStreamReadAvailable()\n")); + + return PaUtil_GetRingBufferReadAvailable( &blio->inputRingBuffer ); +} + + +signed long GetStreamWriteAvailable( PaStream* stream ) +{ + PaMacBlio *blio = & ((PaMacCoreStream*)stream) -> blio; + VVDBUG(("GetStreamWriteAvailable()\n")); + + return PaUtil_GetRingBufferWriteAvailable( &blio->outputRingBuffer ); +} + diff --git a/extern/portaudio/src/hostapi/coreaudio/pa_mac_core_blocking.h b/extern/portaudio/src/hostapi/coreaudio/pa_mac_core_blocking.h new file mode 100644 index 0000000..c994f09 --- /dev/null +++ b/extern/portaudio/src/hostapi/coreaudio/pa_mac_core_blocking.h @@ -0,0 +1,134 @@ +/* + * Internal blocking interfaces for PortAudio Apple AUHAL implementation + * + * PortAudio Portable Real-Time Audio Library + * Latest Version at: http://www.portaudio.com + * + * Written by Bjorn Roche of XO Audio LLC, from PA skeleton code. + * Portions copied from code by Dominic Mazzoni (who wrote a HAL implementation) + * + * Dominic's code was based on code by Phil Burk, Darren Gibbs, + * Gord Peters, Stephane Letz, and Greg Pfiel. + * + * The following people also deserve acknowledgements: + * + * Olivier Tristan for feedback and testing + * Glenn Zelniker and Z-Systems engineering for sponsoring the Blocking I/O + * interface. + * + * + * Based on the Open Source API proposed by Ross Bencina + * Copyright (c) 1999-2002 Ross Bencina, Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +/** + @file + @ingroup hostapi_src +*/ + +#ifndef PA_MAC_CORE_BLOCKING_H_ +#define PA_MAC_CORE_BLOCKING_H_ + +#include "pa_ringbuffer.h" +#include "portaudio.h" +#include "pa_mac_core_utilities.h" + +/* + * Number of milliseconds to busy wait while waiting for data in blocking calls. + */ +#define PA_MAC_BLIO_BUSY_WAIT_SLEEP_INTERVAL (5) +/* + * Define exactly one of these blocking methods + * PA_MAC_BLIO_MUTEX is not actively maintained. + */ +#define PA_MAC_BLIO_BUSY_WAIT +/* +#define PA_MAC_BLIO_MUTEX +*/ + +typedef struct { + PaUtilRingBuffer inputRingBuffer; + PaUtilRingBuffer outputRingBuffer; + ring_buffer_size_t ringBufferFrames; + PaSampleFormat inputSampleFormat; + size_t inputSampleSizeActual; + size_t inputSampleSizePow2; + PaSampleFormat outputSampleFormat; + size_t outputSampleSizeActual; + size_t outputSampleSizePow2; + + int inChan; + int outChan; + + //PaStreamCallbackFlags statusFlags; + uint32_t statusFlags; + PaError errors; + + /* Here we handle blocking, using condition variables. */ +#ifdef PA_MAC_BLIO_MUTEX + volatile bool isInputEmpty; + pthread_mutex_t inputMutex; + pthread_cond_t inputCond; + + volatile bool isOutputFull; + pthread_mutex_t outputMutex; + pthread_cond_t outputCond; +#endif +} +PaMacBlio; + +/* + * These functions operate on condition and related variables. + */ + +PaError initializeBlioRingBuffers( + PaMacBlio *blio, + PaSampleFormat inputSampleFormat, + PaSampleFormat outputSampleFormat, + long ringBufferSizeInFrames, + int inChan, + int outChan ); +PaError destroyBlioRingBuffers( PaMacBlio *blio ); +PaError resetBlioRingBuffers( PaMacBlio *blio ); + +int BlioCallback( + const void *input, void *output, + unsigned long frameCount, + const PaStreamCallbackTimeInfo* timeInfo, + PaStreamCallbackFlags statusFlags, + void *userData ); + +PaError waitUntilBlioWriteBufferIsEmpty( PaMacBlio *blio, double sampleRate, + size_t framesPerBuffer ); + +#endif /*PA_MAC_CORE_BLOCKING_H_*/ diff --git a/extern/portaudio/src/hostapi/coreaudio/pa_mac_core_internal.h b/extern/portaudio/src/hostapi/coreaudio/pa_mac_core_internal.h new file mode 100644 index 0000000..14e3d07 --- /dev/null +++ b/extern/portaudio/src/hostapi/coreaudio/pa_mac_core_internal.h @@ -0,0 +1,194 @@ +/* + * Internal interfaces for PortAudio Apple AUHAL implementation + * + * PortAudio Portable Real-Time Audio Library + * Latest Version at: http://www.portaudio.com + * + * Written by Bjorn Roche of XO Audio LLC, from PA skeleton code. + * Portions copied from code by Dominic Mazzoni (who wrote a HAL implementation) + * + * Dominic's code was based on code by Phil Burk, Darren Gibbs, + * Gord Peters, Stephane Letz, and Greg Pfiel. + * + * The following people also deserve acknowledgements: + * + * Olivier Tristan for feedback and testing + * Glenn Zelniker and Z-Systems engineering for sponsoring the Blocking I/O + * interface. + * + * + * Based on the Open Source API proposed by Ross Bencina + * Copyright (c) 1999-2002 Ross Bencina, Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +/** + @file pa_mac_core + @ingroup hostapi_src + @author Bjorn Roche + @brief AUHAL implementation of PortAudio +*/ + +#ifndef PA_MAC_CORE_INTERNAL_H__ +#define PA_MAC_CORE_INTERNAL_H__ + +#include +#include +#include +#include + +#include "portaudio.h" +#include "pa_util.h" +#include "pa_hostapi.h" +#include "pa_stream.h" +#include "pa_allocation.h" +#include "pa_cpuload.h" +#include "pa_process.h" +#include "pa_ringbuffer.h" + +#include "pa_mac_core_blocking.h" + +/* function prototypes */ + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +PaError PaMacCore_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index ); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#define RING_BUFFER_ADVANCE_DENOMINATOR (4) + +PaError ReadStream( PaStream* stream, void *buffer, unsigned long frames ); +PaError WriteStream( PaStream* stream, const void *buffer, unsigned long frames ); +signed long GetStreamReadAvailable( PaStream* stream ); +signed long GetStreamWriteAvailable( PaStream* stream ); +/* PaMacAUHAL - host api datastructure specific to this implementation */ +typedef struct +{ + PaUtilHostApiRepresentation inheritedHostApiRep; + PaUtilStreamInterface callbackStreamInterface; + PaUtilStreamInterface blockingStreamInterface; + + PaUtilAllocationGroup *allocations; + + /* implementation specific data goes here */ + long devCount; + AudioDeviceID *devIds; /*array of all audio devices*/ + AudioDeviceID defaultIn; + AudioDeviceID defaultOut; +} +PaMacAUHAL; + +typedef struct PaMacCoreDeviceProperties +{ + /* Values in Frames from property queries. */ + UInt32 safetyOffset; + UInt32 bufferFrameSize; + // UInt32 streamLatency; // Seems to be the same as deviceLatency!? + UInt32 deviceLatency; + /* Current device sample rate. May change! + These are initialized to the nominal device sample rate, + and updated with the actual sample rate, when/where available. + Note that these are the *device* sample rates, prior to any required + SR conversion. */ + Float64 sampleRate; + Float64 samplePeriod; // reciprocal +} +PaMacCoreDeviceProperties; + +/* stream data structure specifically for this implementation */ +typedef struct PaMacCoreStream +{ + PaUtilStreamRepresentation streamRepresentation; + PaUtilCpuLoadMeasurer cpuLoadMeasurer; + PaUtilBufferProcessor bufferProcessor; + + /* implementation specific data goes here */ + bool bufferProcessorIsInitialized; + AudioUnit inputUnit; + AudioUnit outputUnit; + AudioDeviceID inputDevice; + AudioDeviceID outputDevice; + size_t userInChan; + size_t userOutChan; + size_t inputFramesPerBuffer; + size_t outputFramesPerBuffer; + PaMacBlio blio; + /* We use this ring buffer when input and out devs are different. */ + PaUtilRingBuffer inputRingBuffer; + /* We may need to do SR conversion on input. */ + AudioConverterRef inputSRConverter; + /* We need to preallocate an inputBuffer for reading data. */ + AudioBufferList inputAudioBufferList; + AudioTimeStamp startTime; + /* FIXME: instead of volatile, these should be properly memory barriered */ + volatile uint32_t xrunFlags; /*PaStreamCallbackFlags*/ + volatile enum { + STOPPED = 0, /* playback is completely stopped, + and the user has called StopStream(). */ + CALLBACK_STOPPED = 1, /* callback has requested stop, + but user has not yet called StopStream(). */ + STOPPING = 2, /* The stream is in the process of closing + because the user has called StopStream. + This state is just used internally; + externally it is indistinguishable from + ACTIVE.*/ + ACTIVE = 3 /* The stream is active and running. */ + } state; + double sampleRate; + PaMacCoreDeviceProperties inputProperties; + PaMacCoreDeviceProperties outputProperties; + + /* data updated by main thread and notifications, protected by timingInformationMutex */ + int timingInformationMutexIsInitialized; + pthread_mutex_t timingInformationMutex; + + /* These are written by the PA thread or from CoreAudio callbacks. Protected by the mutex. */ + Float64 timestampOffsetCombined; + Float64 timestampOffsetInputDevice; + Float64 timestampOffsetOutputDevice; + + /* Offsets in seconds to be applied to Apple timestamps to convert them to PA timestamps. + * While the io proc is active, the following values are only accessed and manipulated by the ioproc */ + Float64 timestampOffsetCombined_ioProcCopy; + Float64 timestampOffsetInputDevice_ioProcCopy; + Float64 timestampOffsetOutputDevice_ioProcCopy; + +} +PaMacCoreStream; + +#endif /* PA_MAC_CORE_INTERNAL_H__ */ diff --git a/extern/portaudio/src/hostapi/coreaudio/pa_mac_core_old.c b/extern/portaudio/src/hostapi/coreaudio/pa_mac_core_old.c new file mode 100644 index 0000000..0e9b357 --- /dev/null +++ b/extern/portaudio/src/hostapi/coreaudio/pa_mac_core_old.c @@ -0,0 +1,913 @@ +/* + * $Id$ + * pa_mac_core.c + * Implementation of PortAudio for Mac OS X CoreAudio + * + * PortAudio Portable Real-Time Audio Library + * Latest Version at: http://www.portaudio.com + * + * Authors: Ross Bencina and Phil Burk + * Copyright (c) 1999-2000 Ross Bencina and Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +#include +#include +#include +#include +#include +#include + +#include "portaudio.h" +#include "pa_trace.h" +#include "pa_util.h" +#include "pa_allocation.h" +#include "pa_hostapi.h" +#include "pa_stream.h" +#include "pa_cpuload.h" +#include "pa_process.h" + +// ===== constants ===== + +// ===== structs ===== +#pragma mark structs + +// PaMacCoreHostApiRepresentation - host api datastructure specific to this implementation +typedef struct PaMacCore_HAR +{ + PaUtilHostApiRepresentation inheritedHostApiRep; + PaUtilStreamInterface callbackStreamInterface; + PaUtilStreamInterface blockingStreamInterface; + + PaUtilAllocationGroup *allocations; + AudioDeviceID *macCoreDeviceIds; +} +PaMacCoreHostApiRepresentation; + +typedef struct PaMacCore_DI +{ + PaDeviceInfo inheritedDeviceInfo; +} +PaMacCoreDeviceInfo; + +// PaMacCoreStream - a stream data structure specifically for this implementation +typedef struct PaMacCore_S +{ + PaUtilStreamRepresentation streamRepresentation; + PaUtilCpuLoadMeasurer cpuLoadMeasurer; + PaUtilBufferProcessor bufferProcessor; + + int primeStreamUsingCallback; + + AudioDeviceID inputDevice; + AudioDeviceID outputDevice; + + // Processing thread management -------------- +// HANDLE abortEvent; +// HANDLE processingThread; +// DWORD processingThreadId; + + char throttleProcessingThreadOnOverload; // 0 -> don't throtte, non-0 -> throttle + int processingThreadPriority; + int highThreadPriority; + int throttledThreadPriority; + unsigned long throttledSleepMsecs; + + int isStopped; + volatile int isActive; + volatile int stopProcessing; // stop thread once existing buffers have been returned + volatile int abortProcessing; // stop thread immediately + +// DWORD allBuffersDurationMs; // used to calculate timeouts +} +PaMacCoreStream; + +// Data needed by the CoreAudio callback functions +typedef struct PaMacCore_CD +{ + PaMacCoreStream *stream; + PaStreamCallback *callback; + void *userData; + PaUtilConverter *inputConverter; + PaUtilConverter *outputConverter; + void *inputBuffer; + void *outputBuffer; + int inputChannelCount; + int outputChannelCount; + PaSampleFormat inputSampleFormat; + PaSampleFormat outputSampleFormat; + PaUtilTriangularDitherGenerator *ditherGenerator; +} +PaMacClientData; + +// ===== CoreAudio-PortAudio bridge functions ===== +#pragma mark CoreAudio-PortAudio bridge functions + +// Maps CoreAudio OSStatus codes to PortAudio PaError codes +static PaError conv_err(OSStatus error) +{ + PaError result; + + switch (error) { + case kAudioHardwareNoError: + result = paNoError; break; + case kAudioHardwareNotRunningError: + result = paInternalError; break; + case kAudioHardwareUnspecifiedError: + result = paInternalError; break; + case kAudioHardwareUnknownPropertyError: + result = paInternalError; break; + case kAudioHardwareBadPropertySizeError: + result = paInternalError; break; + case kAudioHardwareIllegalOperationError: + result = paInternalError; break; + case kAudioHardwareBadDeviceError: + result = paInvalidDevice; break; + case kAudioHardwareBadStreamError: + result = paBadStreamPtr; break; + case kAudioHardwareUnsupportedOperationError: + result = paInternalError; break; + case kAudioDeviceUnsupportedFormatError: + result = paSampleFormatNotSupported; break; + case kAudioDevicePermissionsError: + result = paDeviceUnavailable; break; + default: + result = paInternalError; + } + + return result; +} + +/* This function is unused +static AudioStreamBasicDescription *InitializeStreamDescription(const PaStreamParameters *parameters, double sampleRate) +{ + struct AudioStreamBasicDescription *streamDescription = PaUtil_AllocateMemory(sizeof(AudioStreamBasicDescription)); + streamDescription->mSampleRate = sampleRate; + streamDescription->mFormatID = kAudioFormatLinearPCM; + streamDescription->mFormatFlags = 0; + streamDescription->mFramesPerPacket = 1; + + if (parameters->sampleFormat & paNonInterleaved) { + streamDescription->mFormatFlags |= kLinearPCMFormatFlagIsNonInterleaved; + streamDescription->mChannelsPerFrame = 1; + streamDescription->mBytesPerFrame = Pa_GetSampleSize(parameters->sampleFormat); + streamDescription->mBytesPerPacket = Pa_GetSampleSize(parameters->sampleFormat); + } + else { + streamDescription->mChannelsPerFrame = parameters->channelCount; + } + + streamDescription->mBytesPerFrame = Pa_GetSampleSize(parameters->sampleFormat) * streamDescription->mChannelsPerFrame; + streamDescription->mBytesPerPacket = streamDescription->mBytesPerFrame * streamDescription->mFramesPerPacket; + + if (parameters->sampleFormat & paFloat32) { + streamDescription->mFormatFlags |= kLinearPCMFormatFlagIsFloat; + streamDescription->mBitsPerChannel = 32; + } + else if (parameters->sampleFormat & paInt32) { + streamDescription->mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger; + streamDescription->mBitsPerChannel = 32; + } + else if (parameters->sampleFormat & paInt24) { + streamDescription->mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger; + streamDescription->mBitsPerChannel = 24; + } + else if (parameters->sampleFormat & paInt16) { + streamDescription->mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger; + streamDescription->mBitsPerChannel = 16; + } + else if (parameters->sampleFormat & paInt8) { + streamDescription->mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger; + streamDescription->mBitsPerChannel = 8; + } + else if (parameters->sampleFormat & paInt32) { + streamDescription->mBitsPerChannel = 8; + } + + return streamDescription; +} +*/ + +static PaStreamCallbackTimeInfo *InitializeTimeInfo(const AudioTimeStamp* now, const AudioTimeStamp* inputTime, const AudioTimeStamp* outputTime) +{ + PaStreamCallbackTimeInfo *timeInfo = PaUtil_AllocateMemory(sizeof(PaStreamCallbackTimeInfo)); + + timeInfo->inputBufferAdcTime = inputTime->mSampleTime; + timeInfo->currentTime = now->mSampleTime; + timeInfo->outputBufferDacTime = outputTime->mSampleTime; + + return timeInfo; +} + +// ===== support functions ===== +#pragma mark support functions + +static void CleanUp(PaMacCoreHostApiRepresentation *macCoreHostApi) +{ + if( macCoreHostApi->allocations ) + { + PaUtil_FreeAllAllocations( macCoreHostApi->allocations ); + PaUtil_DestroyAllocationGroup( macCoreHostApi->allocations ); + } + + PaUtil_FreeMemory( macCoreHostApi ); +} + +static PaError GetChannelInfo(PaDeviceInfo *deviceInfo, AudioDeviceID macCoreDeviceId, int isInput) +{ + UInt32 propSize; + PaError err = paNoError; + UInt32 i; + int numChannels = 0; + AudioBufferList *buflist; + + err = conv_err(AudioDeviceGetPropertyInfo(macCoreDeviceId, 0, isInput, kAudioDevicePropertyStreamConfiguration, &propSize, NULL)); + buflist = PaUtil_AllocateMemory(propSize); + err = conv_err(AudioDeviceGetProperty(macCoreDeviceId, 0, isInput, kAudioDevicePropertyStreamConfiguration, &propSize, buflist)); + if (!err) { + for (i = 0; i < buflist->mNumberBuffers; ++i) { + numChannels += buflist->mBuffers[i].mNumberChannels; + } + + if (isInput) + deviceInfo->maxInputChannels = numChannels; + else + deviceInfo->maxOutputChannels = numChannels; + + int frameLatency; + propSize = sizeof(UInt32); + err = conv_err(AudioDeviceGetProperty(macCoreDeviceId, 0, isInput, kAudioDevicePropertyLatency, &propSize, &frameLatency)); + if (!err) { + double secondLatency = frameLatency / deviceInfo->defaultSampleRate; + if (isInput) { + deviceInfo->defaultLowInputLatency = secondLatency; + deviceInfo->defaultHighInputLatency = secondLatency; + } + else { + deviceInfo->defaultLowOutputLatency = secondLatency; + deviceInfo->defaultHighOutputLatency = secondLatency; + } + } + } + PaUtil_FreeMemory(buflist); + + return err; +} + +static PaError InitializeDeviceInfo(PaMacCoreDeviceInfo *macCoreDeviceInfo, AudioDeviceID macCoreDeviceId, PaHostApiIndex hostApiIndex ) +{ + PaDeviceInfo *deviceInfo = &macCoreDeviceInfo->inheritedDeviceInfo; + deviceInfo->structVersion = 2; + deviceInfo->hostApi = hostApiIndex; + + PaError err = paNoError; + UInt32 propSize; + + err = conv_err(AudioDeviceGetPropertyInfo(macCoreDeviceId, 0, 0, kAudioDevicePropertyDeviceName, &propSize, NULL)); + // FIXME: this allocation should be part of the allocations group + char *name = PaUtil_AllocateMemory(propSize); + err = conv_err(AudioDeviceGetProperty(macCoreDeviceId, 0, 0, kAudioDevicePropertyDeviceName, &propSize, name)); + if (!err) { + deviceInfo->name = name; + } + + Float64 sampleRate; + propSize = sizeof(Float64); + err = conv_err(AudioDeviceGetProperty(macCoreDeviceId, 0, 0, kAudioDevicePropertyNominalSampleRate, &propSize, &sampleRate)); + if (!err) { + deviceInfo->defaultSampleRate = sampleRate; + } + + + // Get channel info + err = GetChannelInfo(deviceInfo, macCoreDeviceId, 1); + err = GetChannelInfo(deviceInfo, macCoreDeviceId, 0); + + return err; +} + +static PaError InitializeDeviceInfos( PaMacCoreHostApiRepresentation *macCoreHostApi, PaHostApiIndex hostApiIndex ) +{ + PaError result = paNoError; + PaUtilHostApiRepresentation *hostApi; + PaMacCoreDeviceInfo *deviceInfoArray; + + // initialise device counts and default devices under the assumption that there are no devices. These values are incremented below if and when devices are successfully initialized. + hostApi = &macCoreHostApi->inheritedHostApiRep; + hostApi->info.deviceCount = 0; + hostApi->info.defaultInputDevice = paNoDevice; + hostApi->info.defaultOutputDevice = paNoDevice; + + UInt32 propsize; + AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, &propsize, NULL); + int numDevices = propsize / sizeof(AudioDeviceID); + hostApi->info.deviceCount = numDevices; + if (numDevices > 0) { + hostApi->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory( + macCoreHostApi->allocations, sizeof(PaDeviceInfo*) * numDevices ); + if( !hostApi->deviceInfos ) + { + return paInsufficientMemory; + } + + // allocate all device info structs in a contiguous block + deviceInfoArray = (PaMacCoreDeviceInfo*)PaUtil_GroupAllocateMemory( + macCoreHostApi->allocations, sizeof(PaMacCoreDeviceInfo) * numDevices ); + if( !deviceInfoArray ) + { + return paInsufficientMemory; + } + + macCoreHostApi->macCoreDeviceIds = PaUtil_GroupAllocateMemory(macCoreHostApi->allocations, propsize); + AudioHardwareGetProperty(kAudioHardwarePropertyDevices, &propsize, macCoreHostApi->macCoreDeviceIds); + + AudioDeviceID defaultInputDevice, defaultOutputDevice; + propsize = sizeof(AudioDeviceID); + AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, &propsize, &defaultInputDevice); + AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &propsize, &defaultOutputDevice); + + UInt32 i; + for (i = 0; i < numDevices; ++i) { + if (macCoreHostApi->macCoreDeviceIds[i] == defaultInputDevice) { + hostApi->info.defaultInputDevice = i; + } + if (macCoreHostApi->macCoreDeviceIds[i] == defaultOutputDevice) { + hostApi->info.defaultOutputDevice = i; + } + InitializeDeviceInfo(&deviceInfoArray[i], macCoreHostApi->macCoreDeviceIds[i], hostApiIndex); + hostApi->deviceInfos[i] = &(deviceInfoArray[i].inheritedDeviceInfo); + } + } + + return result; +} + +static OSStatus CheckFormat(AudioDeviceID macCoreDeviceId, const PaStreamParameters *parameters, double sampleRate, int isInput) +{ + UInt32 propSize = sizeof(AudioStreamBasicDescription); + AudioStreamBasicDescription *streamDescription = PaUtil_AllocateMemory(propSize); + + streamDescription->mSampleRate = sampleRate; + streamDescription->mFormatID = 0; + streamDescription->mFormatFlags = 0; + streamDescription->mBytesPerPacket = 0; + streamDescription->mFramesPerPacket = 0; + streamDescription->mBytesPerFrame = 0; + streamDescription->mChannelsPerFrame = 0; + streamDescription->mBitsPerChannel = 0; + streamDescription->mReserved = 0; + + OSStatus result = AudioDeviceGetProperty(macCoreDeviceId, 0, isInput, kAudioDevicePropertyStreamFormatSupported, &propSize, streamDescription); + PaUtil_FreeMemory(streamDescription); + return result; +} + +static OSStatus CopyInputData(PaMacClientData* destination, const AudioBufferList *source, unsigned long frameCount) +{ + int frameSpacing, channelSpacing; + if (destination->inputSampleFormat & paNonInterleaved) { + frameSpacing = 1; + channelSpacing = destination->inputChannelCount; + } + else { + frameSpacing = destination->inputChannelCount; + channelSpacing = 1; + } + + AudioBuffer const *inputBuffer = &source->mBuffers[0]; + void *coreAudioBuffer = inputBuffer->mData; + void *portAudioBuffer = destination->inputBuffer; + UInt32 i, streamNumber, streamChannel; + for (i = streamNumber = streamChannel = 0; i < destination->inputChannelCount; ++i, ++streamChannel) { + if (streamChannel >= inputBuffer->mNumberChannels) { + ++streamNumber; + inputBuffer = &source->mBuffers[streamNumber]; + coreAudioBuffer = inputBuffer->mData; + streamChannel = 0; + } + destination->inputConverter(portAudioBuffer, frameSpacing, coreAudioBuffer, inputBuffer->mNumberChannels, frameCount, destination->ditherGenerator); + coreAudioBuffer += sizeof(Float32); + portAudioBuffer += Pa_GetSampleSize(destination->inputSampleFormat) * channelSpacing; + } + return noErr; +} + +static OSStatus CopyOutputData(AudioBufferList* destination, PaMacClientData *source, unsigned long frameCount) +{ + int frameSpacing, channelSpacing; + if (source->outputSampleFormat & paNonInterleaved) { + frameSpacing = 1; + channelSpacing = source->outputChannelCount; + } + else { + frameSpacing = source->outputChannelCount; + channelSpacing = 1; + } + + AudioBuffer *outputBuffer = &destination->mBuffers[0]; + void *coreAudioBuffer = outputBuffer->mData; + void *portAudioBuffer = source->outputBuffer; + UInt32 i, streamNumber, streamChannel; + for (i = streamNumber = streamChannel = 0; i < source->outputChannelCount; ++i, ++streamChannel) { + if (streamChannel >= outputBuffer->mNumberChannels) { + ++streamNumber; + outputBuffer = &destination->mBuffers[streamNumber]; + coreAudioBuffer = outputBuffer->mData; + streamChannel = 0; + } + source->outputConverter(coreAudioBuffer, outputBuffer->mNumberChannels, portAudioBuffer, frameSpacing, frameCount, NULL); + coreAudioBuffer += sizeof(Float32); + portAudioBuffer += Pa_GetSampleSize(source->outputSampleFormat) * channelSpacing; + } + return noErr; +} + +static OSStatus AudioIOProc( AudioDeviceID inDevice, + const AudioTimeStamp* inNow, + const AudioBufferList* inInputData, + const AudioTimeStamp* inInputTime, + AudioBufferList* outOutputData, + const AudioTimeStamp* inOutputTime, + void* inClientData) +{ + PaMacClientData *clientData = (PaMacClientData *)inClientData; + PaStreamCallbackTimeInfo *timeInfo = InitializeTimeInfo(inNow, inInputTime, inOutputTime); + + PaUtil_BeginCpuLoadMeasurement( &clientData->stream->cpuLoadMeasurer ); + + AudioBuffer *outputBuffer = &outOutputData->mBuffers[0]; + unsigned long frameCount = outputBuffer->mDataByteSize / (outputBuffer->mNumberChannels * sizeof(Float32)); + + if (clientData->inputBuffer) { + CopyInputData(clientData, inInputData, frameCount); + } + PaStreamCallbackResult result = clientData->callback(clientData->inputBuffer, clientData->outputBuffer, frameCount, timeInfo, paNoFlag, clientData->userData); + if (clientData->outputBuffer) { + CopyOutputData(outOutputData, clientData, frameCount); + } + + PaUtil_EndCpuLoadMeasurement( &clientData->stream->cpuLoadMeasurer, frameCount ); + + if (result == paComplete || result == paAbort) { + Pa_StopStream(clientData->stream); + } + + PaUtil_FreeMemory( timeInfo ); + return noErr; +} + +// This is not for input-only streams, this is for streams where the input device is different from the output device +static OSStatus AudioInputProc( AudioDeviceID inDevice, + const AudioTimeStamp* inNow, + const AudioBufferList* inInputData, + const AudioTimeStamp* inInputTime, + AudioBufferList* outOutputData, + const AudioTimeStamp* inOutputTime, + void* inClientData) +{ + PaMacClientData *clientData = (PaMacClientData *)inClientData; + PaStreamCallbackTimeInfo *timeInfo = InitializeTimeInfo(inNow, inInputTime, inOutputTime); + + PaUtil_BeginCpuLoadMeasurement( &clientData->stream->cpuLoadMeasurer ); + + AudioBuffer const *inputBuffer = &inInputData->mBuffers[0]; + unsigned long frameCount = inputBuffer->mDataByteSize / (inputBuffer->mNumberChannels * sizeof(Float32)); + + CopyInputData(clientData, inInputData, frameCount); + PaStreamCallbackResult result = clientData->callback(clientData->inputBuffer, clientData->outputBuffer, frameCount, timeInfo, paNoFlag, clientData->userData); + + PaUtil_EndCpuLoadMeasurement( &clientData->stream->cpuLoadMeasurer, frameCount ); + if( result == paComplete || result == paAbort ) + Pa_StopStream(clientData->stream); + PaUtil_FreeMemory( timeInfo ); + return noErr; +} + +// This is not for output-only streams, this is for streams where the input device is different from the output device +static OSStatus AudioOutputProc( AudioDeviceID inDevice, + const AudioTimeStamp* inNow, + const AudioBufferList* inInputData, + const AudioTimeStamp* inInputTime, + AudioBufferList* outOutputData, + const AudioTimeStamp* inOutputTime, + void* inClientData) +{ + PaMacClientData *clientData = (PaMacClientData *)inClientData; + //PaStreamCallbackTimeInfo *timeInfo = InitializeTimeInfo(inNow, inInputTime, inOutputTime); + + PaUtil_BeginCpuLoadMeasurement( &clientData->stream->cpuLoadMeasurer ); + + AudioBuffer *outputBuffer = &outOutputData->mBuffers[0]; + unsigned long frameCount = outputBuffer->mDataByteSize / (outputBuffer->mNumberChannels * sizeof(Float32)); + + //clientData->callback(NULL, clientData->outputBuffer, frameCount, timeInfo, paNoFlag, clientData->userData); + + CopyOutputData(outOutputData, clientData, frameCount); + + PaUtil_EndCpuLoadMeasurement( &clientData->stream->cpuLoadMeasurer, frameCount ); + return noErr; +} + +static PaError SetSampleRate(AudioDeviceID device, double sampleRate, int isInput) +{ + PaError result = paNoError; + + double actualSampleRate; + UInt32 propSize = sizeof(double); + result = conv_err(AudioDeviceSetProperty(device, NULL, 0, isInput, kAudioDevicePropertyNominalSampleRate, propSize, &sampleRate)); + + result = conv_err(AudioDeviceGetProperty(device, 0, isInput, kAudioDevicePropertyNominalSampleRate, &propSize, &actualSampleRate)); + + if (result == paNoError && actualSampleRate != sampleRate) { + result = paInvalidSampleRate; + } + + return result; +} + +static PaError SetFramesPerBuffer(AudioDeviceID device, unsigned long framesPerBuffer, int isInput) +{ + PaError result = paNoError; + UInt32 preferredFramesPerBuffer = framesPerBuffer; + // while (preferredFramesPerBuffer > UINT32_MAX) { + // preferredFramesPerBuffer /= 2; + // } + + UInt32 actualFramesPerBuffer; + UInt32 propSize = sizeof(UInt32); + result = conv_err(AudioDeviceSetProperty(device, NULL, 0, isInput, kAudioDevicePropertyBufferFrameSize, propSize, &preferredFramesPerBuffer)); + + result = conv_err(AudioDeviceGetProperty(device, 0, isInput, kAudioDevicePropertyBufferFrameSize, &propSize, &actualFramesPerBuffer)); + + if (result != paNoError) { + // do nothing + } + else if (actualFramesPerBuffer > framesPerBuffer) { + result = paBufferTooSmall; + } + else if (actualFramesPerBuffer < framesPerBuffer) { + result = paBufferTooBig; + } + + return result; +} + +static PaError SetUpUnidirectionalStream(AudioDeviceID device, double sampleRate, unsigned long framesPerBuffer, int isInput) +{ + PaError err = paNoError; + err = SetSampleRate(device, sampleRate, isInput); + if( err == paNoError ) + err = SetFramesPerBuffer(device, framesPerBuffer, isInput); + return err; +} + +// ===== PortAudio functions ===== +#pragma mark PortAudio functions + +#ifdef __cplusplus +extern "C" +{ +#endif // __cplusplus + + PaError PaMacCore_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index ); + +#ifdef __cplusplus +} +#endif // __cplusplus + +static void Terminate( struct PaUtilHostApiRepresentation *hostApi ) +{ + PaMacCoreHostApiRepresentation *macCoreHostApi = (PaMacCoreHostApiRepresentation*)hostApi; + + CleanUp(macCoreHostApi); +} + +static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi, + const PaStreamParameters *inputParameters, + const PaStreamParameters *outputParameters, + double sampleRate ) +{ + PaMacCoreHostApiRepresentation *macCoreHostApi = (PaMacCoreHostApiRepresentation*)hostApi; + PaDeviceInfo *deviceInfo; + + PaError result = paNoError; + if (inputParameters) { + deviceInfo = macCoreHostApi->inheritedHostApiRep.deviceInfos[inputParameters->device]; + if (inputParameters->channelCount > deviceInfo->maxInputChannels) + result = paInvalidChannelCount; + else if (CheckFormat(macCoreHostApi->macCoreDeviceIds[inputParameters->device], inputParameters, sampleRate, 1) != kAudioHardwareNoError) { + result = paInvalidSampleRate; + } + } + if (outputParameters && result == paNoError) { + deviceInfo = macCoreHostApi->inheritedHostApiRep.deviceInfos[outputParameters->device]; + if (outputParameters->channelCount > deviceInfo->maxOutputChannels) + result = paInvalidChannelCount; + else if (CheckFormat(macCoreHostApi->macCoreDeviceIds[outputParameters->device], outputParameters, sampleRate, 0) != kAudioHardwareNoError) { + result = paInvalidSampleRate; + } + } + + return result; +} + +static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, + PaStream** s, + const PaStreamParameters *inputParameters, + const PaStreamParameters *outputParameters, + double sampleRate, + unsigned long framesPerBuffer, + PaStreamFlags streamFlags, + PaStreamCallback *streamCallback, + void *userData ) +{ + PaError err = paNoError; + PaMacCoreHostApiRepresentation *macCoreHostApi = (PaMacCoreHostApiRepresentation *)hostApi; + PaMacCoreStream *stream = PaUtil_AllocateMemory(sizeof(PaMacCoreStream)); + stream->isActive = 0; + stream->isStopped = 1; + stream->inputDevice = kAudioDeviceUnknown; + stream->outputDevice = kAudioDeviceUnknown; + + PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation, + ( (streamCallback) + ? &macCoreHostApi->callbackStreamInterface + : &macCoreHostApi->blockingStreamInterface ), + streamCallback, userData ); + PaUtil_InitializeCpuLoadMeasurer( &stream->cpuLoadMeasurer, sampleRate ); + + *s = (PaStream*)stream; + PaMacClientData *clientData = PaUtil_AllocateMemory(sizeof(PaMacClientData)); + clientData->stream = stream; + clientData->callback = streamCallback; + clientData->userData = userData; + clientData->inputBuffer = 0; + clientData->outputBuffer = 0; + clientData->ditherGenerator = PaUtil_AllocateMemory(sizeof(PaUtilTriangularDitherGenerator)); + PaUtil_InitializeTriangularDitherState(clientData->ditherGenerator); + + if (inputParameters != NULL) { + stream->inputDevice = macCoreHostApi->macCoreDeviceIds[inputParameters->device]; + clientData->inputConverter = PaUtil_SelectConverter(paFloat32, inputParameters->sampleFormat, streamFlags); + clientData->inputBuffer = PaUtil_AllocateMemory(Pa_GetSampleSize(inputParameters->sampleFormat) * framesPerBuffer * inputParameters->channelCount); + clientData->inputChannelCount = inputParameters->channelCount; + clientData->inputSampleFormat = inputParameters->sampleFormat; + err = SetUpUnidirectionalStream(stream->inputDevice, sampleRate, framesPerBuffer, 1); + } + + if (err == paNoError && outputParameters != NULL) { + stream->outputDevice = macCoreHostApi->macCoreDeviceIds[outputParameters->device]; + clientData->outputConverter = PaUtil_SelectConverter(outputParameters->sampleFormat, paFloat32, streamFlags); + clientData->outputBuffer = PaUtil_AllocateMemory(Pa_GetSampleSize(outputParameters->sampleFormat) * framesPerBuffer * outputParameters->channelCount); + clientData->outputChannelCount = outputParameters->channelCount; + clientData->outputSampleFormat = outputParameters->sampleFormat; + err = SetUpUnidirectionalStream(stream->outputDevice, sampleRate, framesPerBuffer, 0); + } + + if (inputParameters == NULL || outputParameters == NULL || stream->inputDevice == stream->outputDevice) { + AudioDeviceID device = (inputParameters == NULL) ? stream->outputDevice : stream->inputDevice; + + AudioDeviceAddIOProc(device, AudioIOProc, clientData); + } + else { + // using different devices for input and output + AudioDeviceAddIOProc(stream->inputDevice, AudioInputProc, clientData); + AudioDeviceAddIOProc(stream->outputDevice, AudioOutputProc, clientData); + } + + return err; +} + +// Note: When CloseStream() is called, the multi-api layer ensures that the stream has already been stopped or aborted. +static PaError CloseStream( PaStream* s ) +{ + PaError err = paNoError; + PaMacCoreStream *stream = (PaMacCoreStream*)s; + + PaUtil_ResetCpuLoadMeasurer( &stream->cpuLoadMeasurer ); + + if (stream->inputDevice != kAudioDeviceUnknown) { + if (stream->outputDevice == kAudioDeviceUnknown || stream->outputDevice == stream->inputDevice) { + err = conv_err(AudioDeviceRemoveIOProc(stream->inputDevice, AudioIOProc)); + } + else { + err = conv_err(AudioDeviceRemoveIOProc(stream->inputDevice, AudioInputProc)); + err = conv_err(AudioDeviceRemoveIOProc(stream->outputDevice, AudioOutputProc)); + } + } + else { + err = conv_err(AudioDeviceRemoveIOProc(stream->outputDevice, AudioIOProc)); + } + + return err; +} + + +static PaError StartStream( PaStream *s ) +{ + PaError err = paNoError; + PaMacCoreStream *stream = (PaMacCoreStream*)s; + + if (stream->inputDevice != kAudioDeviceUnknown) { + if (stream->outputDevice == kAudioDeviceUnknown || stream->outputDevice == stream->inputDevice) { + err = conv_err(AudioDeviceStart(stream->inputDevice, AudioIOProc)); + } + else { + err = conv_err(AudioDeviceStart(stream->inputDevice, AudioInputProc)); + err = conv_err(AudioDeviceStart(stream->outputDevice, AudioOutputProc)); + } + } + else { + err = conv_err(AudioDeviceStart(stream->outputDevice, AudioIOProc)); + } + + stream->isActive = 1; + stream->isStopped = 0; + return err; +} + +static PaError AbortStream( PaStream *s ) +{ + PaError err = paNoError; + PaMacCoreStream *stream = (PaMacCoreStream*)s; + + if (stream->inputDevice != kAudioDeviceUnknown) { + if (stream->outputDevice == kAudioDeviceUnknown || stream->outputDevice == stream->inputDevice) { + err = conv_err(AudioDeviceStop(stream->inputDevice, AudioIOProc)); + } + else { + err = conv_err(AudioDeviceStop(stream->inputDevice, AudioInputProc)); + err = conv_err(AudioDeviceStop(stream->outputDevice, AudioOutputProc)); + } + } + else { + err = conv_err(AudioDeviceStop(stream->outputDevice, AudioIOProc)); + } + + stream->isActive = 0; + stream->isStopped = 1; + return err; +} + +static PaError StopStream( PaStream *s ) +{ + // TODO: this should be nicer than abort + return AbortStream(s); +} + +static PaError IsStreamStopped( PaStream *s ) +{ + PaMacCoreStream *stream = (PaMacCoreStream*)s; + + return stream->isStopped; +} + + +static PaError IsStreamActive( PaStream *s ) +{ + PaMacCoreStream *stream = (PaMacCoreStream*)s; + + return stream->isActive; +} + + +static PaTime GetStreamTime( PaStream *s ) +{ + OSStatus err; + PaTime result; + PaMacCoreStream *stream = (PaMacCoreStream*)s; + + AudioTimeStamp *timeStamp = PaUtil_AllocateMemory(sizeof(AudioTimeStamp)); + if (stream->inputDevice != kAudioDeviceUnknown) { + err = AudioDeviceGetCurrentTime(stream->inputDevice, timeStamp); + } + else { + err = AudioDeviceGetCurrentTime(stream->outputDevice, timeStamp); + } + + result = err ? 0 : timeStamp->mSampleTime; + PaUtil_FreeMemory(timeStamp); + + return result; +} + + +static double GetStreamCpuLoad( PaStream* s ) +{ + PaMacCoreStream *stream = (PaMacCoreStream*)s; + + return PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer ); +} + + +// As separate stream interfaces are used for blocking and callback streams, the following functions can be guaranteed to only be called for blocking streams. + +static PaError ReadStream( PaStream* s, + void *buffer, + unsigned long frames ) +{ + return paInternalError; +} + + +static PaError WriteStream( PaStream* s, + const void *buffer, + unsigned long frames ) +{ + return paInternalError; +} + + +static signed long GetStreamReadAvailable( PaStream* s ) +{ + return paInternalError; +} + + +static signed long GetStreamWriteAvailable( PaStream* s ) +{ + return paInternalError; +} + +// HostAPI-specific initialization function +PaError PaMacCore_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex ) +{ + PaError result = paNoError; + PaMacCoreHostApiRepresentation *macCoreHostApi = (PaMacCoreHostApiRepresentation *)PaUtil_AllocateMemory( sizeof(PaMacCoreHostApiRepresentation) ); + if( !macCoreHostApi ) + { + result = paInsufficientMemory; + goto error; + } + + macCoreHostApi->allocations = PaUtil_CreateAllocationGroup(); + if( !macCoreHostApi->allocations ) + { + result = paInsufficientMemory; + goto error; + } + + *hostApi = &macCoreHostApi->inheritedHostApiRep; + (*hostApi)->info.structVersion = 1; + (*hostApi)->info.type = paCoreAudio; + (*hostApi)->info.name = "CoreAudio"; + + result = InitializeDeviceInfos(macCoreHostApi, hostApiIndex); + if (result != paNoError) { + goto error; + } + + // Set up the proper callbacks to this HostApi's functions + (*hostApi)->Terminate = Terminate; + (*hostApi)->OpenStream = OpenStream; + (*hostApi)->IsFormatSupported = IsFormatSupported; + + PaUtil_InitializeStreamInterface( &macCoreHostApi->callbackStreamInterface, CloseStream, StartStream, + StopStream, AbortStream, IsStreamStopped, IsStreamActive, + GetStreamTime, GetStreamCpuLoad, + PaUtil_DummyRead, PaUtil_DummyWrite, + PaUtil_DummyGetReadAvailable, PaUtil_DummyGetWriteAvailable ); + + PaUtil_InitializeStreamInterface( &macCoreHostApi->blockingStreamInterface, CloseStream, StartStream, + StopStream, AbortStream, IsStreamStopped, IsStreamActive, + GetStreamTime, PaUtil_DummyGetCpuLoad, + ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable ); + + return result; + +error: + if( macCoreHostApi ) { + CleanUp(macCoreHostApi); + } + + return result; +} diff --git a/extern/portaudio/src/hostapi/coreaudio/pa_mac_core_utilities.c b/extern/portaudio/src/hostapi/coreaudio/pa_mac_core_utilities.c new file mode 100644 index 0000000..63e616f --- /dev/null +++ b/extern/portaudio/src/hostapi/coreaudio/pa_mac_core_utilities.c @@ -0,0 +1,701 @@ +/* + * Helper and utility functions for pa_mac_core.c (Apple AUHAL implementation) + * + * PortAudio Portable Real-Time Audio Library + * Latest Version at: http://www.portaudio.com + * + * Written by Bjorn Roche of XO Audio LLC, from PA skeleton code. + * Portions copied from code by Dominic Mazzoni (who wrote a HAL implementation) + * + * Dominic's code was based on code by Phil Burk, Darren Gibbs, + * Gord Peters, Stephane Letz, and Greg Pfiel. + * + * The following people also deserve acknowledgements: + * + * Olivier Tristan for feedback and testing + * Glenn Zelniker and Z-Systems engineering for sponsoring the Blocking I/O + * interface. + * + * + * Based on the Open Source API proposed by Ross Bencina + * Copyright (c) 1999-2002 Ross Bencina, Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +/** + @file + @ingroup hostapi_src +*/ + +#include "pa_mac_core_utilities.h" +#include "pa_mac_core_internal.h" +#include +#include +#include +#include + +PaError PaMacCore_SetUnixError( int err, int line ) +{ + PaError ret; + const char *errorText; + + if( err == 0 ) + { + return paNoError; + } + + ret = paNoError; + errorText = strerror( err ); + + /** Map Unix error to PaError. Pretty much the only one that maps + is ENOMEM. */ + if( err == ENOMEM ) + ret = paInsufficientMemory; + else + ret = paInternalError; + + DBUG(("%d on line %d: msg='%s'\n", err, line, errorText)); + PaUtil_SetLastHostErrorInfo( paCoreAudio, err, errorText ); + + return ret; +} + +/* + * Translates MacOS generated errors into PaErrors + */ +PaError PaMacCore_SetError(OSStatus error, int line, int isError) +{ + /*FIXME: still need to handle possible ComponentResult values.*/ + /* unfortunately, they don't seem to be documented anywhere.*/ + PaError result; + const char *errorType; + const char *errorText; + + switch (error) { + case kAudioHardwareNoError: + return paNoError; + case kAudioHardwareNotRunningError: + errorText = "Audio Hardware Not Running"; + result = paInternalError; break; + case kAudioHardwareUnspecifiedError: + errorText = "Unspecified Audio Hardware Error"; + result = paInternalError; break; + case kAudioHardwareUnknownPropertyError: + errorText = "Audio Hardware: Unknown Property"; + result = paInternalError; break; + case kAudioHardwareBadPropertySizeError: + errorText = "Audio Hardware: Bad Property Size"; + result = paInternalError; break; + case kAudioHardwareIllegalOperationError: + errorText = "Audio Hardware: Illegal Operation"; + result = paInternalError; break; + case kAudioHardwareBadDeviceError: + errorText = "Audio Hardware: Bad Device"; + result = paInvalidDevice; break; + case kAudioHardwareBadStreamError: + errorText = "Audio Hardware: BadStream"; + result = paBadStreamPtr; break; + case kAudioHardwareUnsupportedOperationError: + errorText = "Audio Hardware: Unsupported Operation"; + result = paInternalError; break; + case kAudioDeviceUnsupportedFormatError: + errorText = "Audio Device: Unsupported Format"; + result = paSampleFormatNotSupported; break; + case kAudioDevicePermissionsError: + errorText = "Audio Device: Permissions Error"; + result = paDeviceUnavailable; break; + /* Audio Unit Errors: http://developer.apple.com/documentation/MusicAudio/Reference/CoreAudio/audio_units/chapter_5_section_3.html */ + case kAudioUnitErr_InvalidProperty: + errorText = "Audio Unit: Invalid Property"; + result = paInternalError; break; + case kAudioUnitErr_InvalidParameter: + errorText = "Audio Unit: Invalid Parameter"; + result = paInternalError; break; + case kAudioUnitErr_NoConnection: + errorText = "Audio Unit: No Connection"; + result = paInternalError; break; + case kAudioUnitErr_FailedInitialization: + errorText = "Audio Unit: Initialization Failed"; + result = paInternalError; break; + case kAudioUnitErr_TooManyFramesToProcess: + errorText = "Audio Unit: Too Many Frames"; + result = paInternalError; break; + case kAudioUnitErr_IllegalInstrument: + errorText = "Audio Unit: Illegal Instrument"; + result = paInternalError; break; + case kAudioUnitErr_InstrumentTypeNotFound: + errorText = "Audio Unit: Instrument Type Not Found"; + result = paInternalError; break; + case kAudioUnitErr_InvalidFile: + errorText = "Audio Unit: Invalid File"; + result = paInternalError; break; + case kAudioUnitErr_UnknownFileType: + errorText = "Audio Unit: Unknown File Type"; + result = paInternalError; break; + case kAudioUnitErr_FileNotSpecified: + errorText = "Audio Unit: File Not Specified"; + result = paInternalError; break; + case kAudioUnitErr_FormatNotSupported: + errorText = "Audio Unit: Format Not Supported"; + result = paInternalError; break; + case kAudioUnitErr_Uninitialized: + errorText = "Audio Unit: Unitialized"; + result = paInternalError; break; + case kAudioUnitErr_InvalidScope: + errorText = "Audio Unit: Invalid Scope"; + result = paInternalError; break; + case kAudioUnitErr_PropertyNotWritable: + errorText = "Audio Unit: PropertyNotWritable"; + result = paInternalError; break; + case kAudioUnitErr_InvalidPropertyValue: + errorText = "Audio Unit: Invalid Property Value"; + result = paInternalError; break; + case kAudioUnitErr_PropertyNotInUse: + errorText = "Audio Unit: Property Not In Use"; + result = paInternalError; break; + case kAudioUnitErr_Initialized: + errorText = "Audio Unit: Initialized"; + result = paInternalError; break; + case kAudioUnitErr_InvalidOfflineRender: + errorText = "Audio Unit: Invalid Offline Render"; + result = paInternalError; break; + case kAudioUnitErr_Unauthorized: + errorText = "Audio Unit: Unauthorized"; + result = paInternalError; break; + case kAudioUnitErr_CannotDoInCurrentContext: + errorText = "Audio Unit: cannot do in current context"; + result = paInternalError; break; + default: + errorText = "Unknown Error"; + result = paInternalError; + } + + if (isError) + errorType = "Error"; + else + errorType = "Warning"; + + char str[20]; + // see if it appears to be a 4-char-code + *(UInt32 *)(str + 1) = CFSwapInt32HostToBig(error); + if (isprint(str[1]) && isprint(str[2]) && isprint(str[3]) && isprint(str[4])) + { + str[0] = str[5] = '\''; + str[6] = '\0'; + } else { + // no, format it as an integer + sprintf(str, "%d", (int)error); + } + + DBUG(("%s on line %d: err='%s', msg=%s\n", errorType, line, str, errorText)); + + PaUtil_SetLastHostErrorInfo( paCoreAudio, error, errorText ); + + return result; +} + +/* + * This function computes an appropriate ring buffer size given + * a requested latency (in seconds), sample rate and framesPerBuffer. + * + * The returned ringBufferSize is computed using the following + * constraints: + * - it must be at least 4. + * - it must be at least 3x framesPerBuffer. + * - it must be at least 2x the suggestedLatency. + * - it must be a power of 2. + * This function attempts to compute the minimum such size. + * + * FEEDBACK: too liberal/conservative/another way? + */ +long computeRingBufferSize( const PaStreamParameters *inputParameters, + const PaStreamParameters *outputParameters, + long inputFramesPerBuffer, + long outputFramesPerBuffer, + double sampleRate ) +{ + long ringSize; + int index; + int i; + double latency ; + long framesPerBuffer ; + + VVDBUG(( "computeRingBufferSize()\n" )); + + assert( inputParameters || outputParameters ); + + if( outputParameters && inputParameters ) + { + latency = MAX( inputParameters->suggestedLatency, outputParameters->suggestedLatency ); + framesPerBuffer = MAX( inputFramesPerBuffer, outputFramesPerBuffer ); + } + else if( outputParameters ) + { + latency = outputParameters->suggestedLatency; + framesPerBuffer = outputFramesPerBuffer ; + } + else /* we have inputParameters */ + { + latency = inputParameters->suggestedLatency; + framesPerBuffer = inputFramesPerBuffer ; + } + + ringSize = (long) ( latency * sampleRate * 2 + .5); + VDBUG( ( "suggested latency : %d\n", (int) (latency*sampleRate) ) ); + if( ringSize < framesPerBuffer * 3 ) + ringSize = framesPerBuffer * 3 ; + VDBUG(("framesPerBuffer:%d\n",(int)framesPerBuffer)); + VDBUG(("Ringbuffer size (1): %d\n", (int)ringSize )); + + /* make sure it's at least 4 */ + ringSize = MAX( ringSize, 4 ); + + /* round up to the next power of 2 */ + index = -1; + for( i=0; i> i & 0x01 ) + index = i; + assert( index > 0 ); + if( ringSize <= ( 0x01 << index ) ) + ringSize = 0x01 << index ; + else + ringSize = 0x01 << ( index + 1 ); + + VDBUG(( "Final Ringbuffer size (2): %d\n", (int)ringSize )); + return ringSize; +} + + +/* + * Durring testing of core audio, I found that serious crashes could occur + * if properties such as sample rate were changed multiple times in rapid + * succession. The function below could be used to with a condition variable. + * to prevent propertychanges from happening until the last property + * change is acknowledged. Instead, I implemented a busy-wait, which is simpler + * to implement b/c in second round of testing (nov '09) property changes occured + * quickly and so there was no real way to test the condition variable implementation. + * therefore, this function is not used, but it is aluded to in commented code below, + * since it represents a theoretically better implementation. + */ + +OSStatus propertyProc( + AudioDeviceID inDevice, + UInt32 inChannel, + Boolean isInput, + AudioDevicePropertyID inPropertyID, + void* inClientData ) +{ + // this is where we would set the condition variable + return noErr; +} + +/* sets the value of the given property and waits for the change to + be acknowledged, and returns the final value, which is not guaranteed + by this function to be the same as the desired value. Obviously, this + function can only be used for data whose input and output are the + same size and format, and their size and format are known in advance. + whether or not the call succeeds, if the data is successfully read, + it is returned in outPropertyData. If it is not read successfully, + outPropertyData is zeroed, which may or may not be useful in + determining if the property was read. */ +PaError AudioDeviceSetPropertyNowAndWaitForChange( + AudioDeviceID inDevice, + UInt32 inChannel, + Boolean isInput, + AudioDevicePropertyID inPropertyID, + UInt32 inPropertyDataSize, + const void *inPropertyData, + void *outPropertyData ) +{ + OSStatus macErr; + UInt32 outPropertyDataSize = inPropertyDataSize; + + /* First, see if it already has that value. If so, return. */ + macErr = AudioDeviceGetProperty( inDevice, inChannel, + isInput, inPropertyID, + &outPropertyDataSize, outPropertyData ); + if( macErr ) { + memset( outPropertyData, 0, inPropertyDataSize ); + goto failMac; + } + if( inPropertyDataSize!=outPropertyDataSize ) + return paInternalError; + if( 0==memcmp( outPropertyData, inPropertyData, outPropertyDataSize ) ) + return paNoError; + + /* Ideally, we'd use a condition variable to determine changes. + we could set that up here. */ + + /* If we were using a cond variable, we'd do something useful here, + but for now, this is just to make 10.6 happy. */ + macErr = AudioDeviceAddPropertyListener( inDevice, inChannel, isInput, + inPropertyID, propertyProc, + NULL ); + if( macErr ) + /* we couldn't add a listener. */ + goto failMac; + + /* set property */ + macErr = AudioDeviceSetProperty( inDevice, NULL, inChannel, + isInput, inPropertyID, + inPropertyDataSize, inPropertyData ); + if( macErr ) + goto failMac; + + /* busy-wait up to 30 seconds for the property to change */ + /* busy-wait is justified here only because the correct alternative (condition variable) + was hard to test, since most of the waiting ended up being for setting rather than + getting in OS X 10.5. This was not the case in earlier OS versions. */ + struct timeval tv1, tv2; + gettimeofday( &tv1, NULL ); + memcpy( &tv2, &tv1, sizeof( struct timeval ) ); + while( tv2.tv_sec - tv1.tv_sec < 30 ) { + /* now read the property back out */ + macErr = AudioDeviceGetProperty( inDevice, inChannel, + isInput, inPropertyID, + &outPropertyDataSize, outPropertyData ); + if( macErr ) { + memset( outPropertyData, 0, inPropertyDataSize ); + goto failMac; + } + /* and compare... */ + if( 0==memcmp( outPropertyData, inPropertyData, outPropertyDataSize ) ) { + AudioDeviceRemovePropertyListener( inDevice, inChannel, isInput, inPropertyID, propertyProc ); + return paNoError; + } + /* No match yet, so let's sleep and try again. */ + Pa_Sleep( 100 ); + gettimeofday( &tv2, NULL ); + } + DBUG( ("Timeout waiting for device setting.\n" ) ); + + AudioDeviceRemovePropertyListener( inDevice, inChannel, isInput, inPropertyID, propertyProc ); + return paNoError; + + failMac: + AudioDeviceRemovePropertyListener( inDevice, inChannel, isInput, inPropertyID, propertyProc ); + return ERR( macErr ); +} + +/* + * Sets the sample rate the HAL device. + * if requireExact: set the sample rate or fail. + * + * otherwise : set the exact sample rate. + * If that fails, check for available sample rates, and choose one + * higher than the requested rate. If there isn't a higher one, + * just use the highest available. + */ +PaError setBestSampleRateForDevice( const AudioDeviceID device, + const bool isOutput, + const bool requireExact, + const Float64 desiredSrate ) +{ + const bool isInput = isOutput ? 0 : 1; + Float64 srate; + UInt32 propsize = sizeof( Float64 ); + OSErr err; + AudioValueRange *ranges; + int i=0; + Float64 max = -1; /*the maximum rate available*/ + Float64 best = -1; /*the lowest sample rate still greater than desired rate*/ + VDBUG(("Setting sample rate for device %ld to %g.\n",device,(float)desiredSrate)); + + /* -- try setting the sample rate -- */ + srate = 0; + err = AudioDeviceSetPropertyNowAndWaitForChange( + device, 0, isInput, + kAudioDevicePropertyNominalSampleRate, + propsize, &desiredSrate, &srate ); + + /* -- if the rate agrees, and was changed, we are done -- */ + if( srate != 0 && srate == desiredSrate ) + return paNoError; + /* -- if the rate agrees, and we got no errors, we are done -- */ + if( !err && srate == desiredSrate ) + return paNoError; + /* -- we've failed if the rates disagree and we are setting input -- */ + if( requireExact ) + return paInvalidSampleRate; + + /* -- generate a list of available sample rates -- */ + err = AudioDeviceGetPropertyInfo( device, 0, isInput, + kAudioDevicePropertyAvailableNominalSampleRates, + &propsize, NULL ); + if( err ) + return ERR( err ); + ranges = (AudioValueRange *)calloc( 1, propsize ); + if( !ranges ) + return paInsufficientMemory; + err = AudioDeviceGetProperty( device, 0, isInput, + kAudioDevicePropertyAvailableNominalSampleRates, + &propsize, ranges ); + if( err ) + { + free( ranges ); + return ERR( err ); + } + VDBUG(("Requested sample rate of %g was not available.\n", (float)desiredSrate)); + VDBUG(("%lu Available Sample Rates are:\n",propsize/sizeof(AudioValueRange))); +#ifdef MAC_CORE_VERBOSE_DEBUG + for( i=0; i max ) max = ranges[i].mMaximum; + if( ranges[i].mMinimum > desiredSrate ) { + if( best < 0 ) + best = ranges[i].mMinimum; + else if( ranges[i].mMinimum < best ) + best = ranges[i].mMinimum; + } + } + if( best < 0 ) + best = max; + VDBUG( ("Maximum Rate %g. best is %g.\n", max, best ) ); + free( ranges ); + + /* -- set the sample rate -- */ + propsize = sizeof( best ); + srate = 0; + err = AudioDeviceSetPropertyNowAndWaitForChange( + device, 0, isInput, + kAudioDevicePropertyNominalSampleRate, + propsize, &best, &srate ); + + /* -- if the set rate matches, we are done -- */ + if( srate != 0 && srate == best ) + return paNoError; + + if( err ) + return ERR( err ); + + /* -- otherwise, something wierd happened: we didn't set the rate, and we got no errors. Just bail. */ + return paInternalError; +} + + +/* + Attempts to set the requestedFramesPerBuffer. If it can't set the exact + value, it settles for something smaller if available. If nothing smaller + is available, it uses the smallest available size. + actualFramesPerBuffer will be set to the actual value on successful return. + OK to pass NULL to actualFramesPerBuffer. + The logic is very simmilar too setBestSampleRate only failure here is + not usually catastrophic. +*/ +PaError setBestFramesPerBuffer( const AudioDeviceID device, + const bool isOutput, + UInt32 requestedFramesPerBuffer, + UInt32 *actualFramesPerBuffer ) +{ + UInt32 afpb; + const bool isInput = !isOutput; + UInt32 propsize = sizeof(UInt32); + OSErr err; + AudioValueRange range; + + if( actualFramesPerBuffer == NULL ) + { + actualFramesPerBuffer = &afpb; + } + + /* -- try and set exact FPB -- */ + err = AudioDeviceSetProperty( device, NULL, 0, isInput, + kAudioDevicePropertyBufferFrameSize, + propsize, &requestedFramesPerBuffer); + err = AudioDeviceGetProperty( device, 0, isInput, + kAudioDevicePropertyBufferFrameSize, + &propsize, actualFramesPerBuffer); + if( err ) + { + return ERR( err ); + } + // Did we get the size we asked for? + if( *actualFramesPerBuffer == requestedFramesPerBuffer ) + { + return paNoError; /* we are done */ + } + + // Clip requested value against legal range for the device. + propsize = sizeof(AudioValueRange); + err = AudioDeviceGetProperty( device, 0, isInput, + kAudioDevicePropertyBufferFrameSizeRange, + &propsize, &range ); + if( err ) + { + return ERR( err ); + } + if( requestedFramesPerBuffer < range.mMinimum ) + { + requestedFramesPerBuffer = range.mMinimum; + } + else if( requestedFramesPerBuffer > range.mMaximum ) + { + requestedFramesPerBuffer = range.mMaximum; + } + + /* --- set the buffer size (ignore errors) -- */ + propsize = sizeof( UInt32 ); + err = AudioDeviceSetProperty( device, NULL, 0, isInput, + kAudioDevicePropertyBufferFrameSize, + propsize, &requestedFramesPerBuffer ); + /* --- read the property to check that it was set -- */ + err = AudioDeviceGetProperty( device, 0, isInput, + kAudioDevicePropertyBufferFrameSize, + &propsize, actualFramesPerBuffer ); + + if( err ) + return ERR( err ); + + return paNoError; +} + +/********************** + * + * XRun stuff + * + **********************/ + +struct PaMacXRunListNode_s { + PaMacCoreStream *stream; + struct PaMacXRunListNode_s *next; +} ; + +typedef struct PaMacXRunListNode_s PaMacXRunListNode; + +/** Always empty, so that it can always be the one returned by + addToXRunListenerList. note that it's not a pointer. */ +static PaMacXRunListNode firstXRunListNode; +static int xRunListSize; +static pthread_mutex_t xrunMutex; + +OSStatus xrunCallback( + AudioDeviceID inDevice, + UInt32 inChannel, + Boolean isInput, + AudioDevicePropertyID inPropertyID, + void* inClientData) +{ + PaMacXRunListNode *node = (PaMacXRunListNode *) inClientData; + + int ret = pthread_mutex_trylock( &xrunMutex ) ; + + if( ret == 0 ) { + + node = node->next ; //skip the first node + + for( ; node; node=node->next ) { + PaMacCoreStream *stream = node->stream; + + if( stream->state != ACTIVE ) + continue; //if the stream isn't active, we don't care if the device is dropping + + if( isInput ) { + if( stream->inputDevice == inDevice ) + OSAtomicOr32( paInputOverflow, &stream->xrunFlags ); + } else { + if( stream->outputDevice == inDevice ) + OSAtomicOr32( paOutputUnderflow, &stream->xrunFlags ); + } + } + + pthread_mutex_unlock( &xrunMutex ); + } + + return 0; +} + +int initializeXRunListenerList() +{ + xRunListSize = 0; + bzero( (void *) &firstXRunListNode, sizeof(firstXRunListNode) ); + return pthread_mutex_init( &xrunMutex, NULL ); +} +int destroyXRunListenerList() +{ + PaMacXRunListNode *node; + node = firstXRunListNode.next; + while( node ) { + PaMacXRunListNode *tmp = node; + node = node->next; + free( tmp ); + } + xRunListSize = 0; + return pthread_mutex_destroy( &xrunMutex ); +} + +void *addToXRunListenerList( void *stream ) +{ + pthread_mutex_lock( &xrunMutex ); + PaMacXRunListNode *newNode; + // setup new node: + newNode = (PaMacXRunListNode *) malloc( sizeof( PaMacXRunListNode ) ); + newNode->stream = (PaMacCoreStream *) stream; + newNode->next = firstXRunListNode.next; + // insert: + firstXRunListNode.next = newNode; + pthread_mutex_unlock( &xrunMutex ); + + return &firstXRunListNode; +} + +int removeFromXRunListenerList( void *stream ) +{ + pthread_mutex_lock( &xrunMutex ); + PaMacXRunListNode *node, *prev; + prev = &firstXRunListNode; + node = firstXRunListNode.next; + while( node ) { + if( node->stream == stream ) { + //found it: + --xRunListSize; + prev->next = node->next; + free( node ); + pthread_mutex_unlock( &xrunMutex ); + return xRunListSize; + } + prev = prev->next; + node = node->next; + } + + pthread_mutex_unlock( &xrunMutex ); + // failure + return xRunListSize; +} + diff --git a/extern/portaudio/src/hostapi/coreaudio/pa_mac_core_utilities.h b/extern/portaudio/src/hostapi/coreaudio/pa_mac_core_utilities.h new file mode 100644 index 0000000..7c4afe5 --- /dev/null +++ b/extern/portaudio/src/hostapi/coreaudio/pa_mac_core_utilities.h @@ -0,0 +1,218 @@ +/* + * Helper and utility functions for pa_mac_core.c (Apple AUHAL implementation) + * + * PortAudio Portable Real-Time Audio Library + * Latest Version at: http://www.portaudio.com + * + * Written by Bjorn Roche of XO Audio LLC, from PA skeleton code. + * Portions copied from code by Dominic Mazzoni (who wrote a HAL implementation) + * + * Dominic's code was based on code by Phil Burk, Darren Gibbs, + * Gord Peters, Stephane Letz, and Greg Pfiel. + * + * The following people also deserve acknowledgements: + * + * Olivier Tristan for feedback and testing + * Glenn Zelniker and Z-Systems engineering for sponsoring the Blocking I/O + * interface. + * + * + * Based on the Open Source API proposed by Ross Bencina + * Copyright (c) 1999-2002 Ross Bencina, Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +/** + @file + @ingroup hostapi_src +*/ + +#ifndef PA_MAC_CORE_UTILITIES_H__ +#define PA_MAC_CORE_UTILITIES_H__ + +#include +#include "portaudio.h" +#include "pa_util.h" +#include +#include + +#ifndef MIN +#define MIN(a, b) (((a)<(b))?(a):(b)) +#endif + +#ifndef MAX +#define MAX(a, b) (((a)<(b))?(b):(a)) +#endif + +#define ERR(mac_error) PaMacCore_SetError(mac_error, __LINE__, 1 ) +#define WARNING(mac_error) PaMacCore_SetError(mac_error, __LINE__, 0 ) + + +/* Help keep track of AUHAL element numbers */ +#define INPUT_ELEMENT (1) +#define OUTPUT_ELEMENT (0) + +/* Normal level of debugging: fine for most apps that don't mind the occational warning being printf'ed */ +/* + */ +#define MAC_CORE_DEBUG +#ifdef MAC_CORE_DEBUG +# define DBUG(MSG) do { printf("||PaMacCore (AUHAL)|| "); printf MSG ; fflush(stdout); } while(0) +#else +# define DBUG(MSG) +#endif + +/* Verbose Debugging: useful for developement */ +/* +#define MAC_CORE_VERBOSE_DEBUG +*/ +#ifdef MAC_CORE_VERBOSE_DEBUG +# define VDBUG(MSG) do { printf("||PaMacCore (v )|| "); printf MSG ; fflush(stdout); } while(0) +#else +# define VDBUG(MSG) +#endif + +/* Very Verbose Debugging: Traces every call. */ +/* +#define MAC_CORE_VERY_VERBOSE_DEBUG + */ +#ifdef MAC_CORE_VERY_VERBOSE_DEBUG +# define VVDBUG(MSG) do { printf("||PaMacCore (vv)|| "); printf MSG ; fflush(stdout); } while(0) +#else +# define VVDBUG(MSG) +#endif + + + + + +#define UNIX_ERR(err) PaMacCore_SetUnixError( err, __LINE__ ) + +PaError PaMacCore_SetUnixError( int err, int line ); + +/* + * Translates MacOS generated errors into PaErrors + */ +PaError PaMacCore_SetError(OSStatus error, int line, int isError); + +/* + * This function computes an appropriate ring buffer size given + * a requested latency (in seconds), sample rate and framesPerBuffer. + * + * The returned ringBufferSize is computed using the following + * constraints: + * - it must be at least 4. + * - it must be at least 3x framesPerBuffer. + * - it must be at least 2x the suggestedLatency. + * - it must be a power of 2. + * This function attempts to compute the minimum such size. + * + */ +long computeRingBufferSize( const PaStreamParameters *inputParameters, + const PaStreamParameters *outputParameters, + long inputFramesPerBuffer, + long outputFramesPerBuffer, + double sampleRate ); + +OSStatus propertyProc( + AudioDeviceID inDevice, + UInt32 inChannel, + Boolean isInput, + AudioDevicePropertyID inPropertyID, + void* inClientData ); + +/* sets the value of the given property and waits for the change to + be acknowledged, and returns the final value, which is not guaranteed + by this function to be the same as the desired value. Obviously, this + function can only be used for data whose input and output are the + same size and format, and their size and format are known in advance.*/ +PaError AudioDeviceSetPropertyNowAndWaitForChange( + AudioDeviceID inDevice, + UInt32 inChannel, + Boolean isInput, + AudioDevicePropertyID inPropertyID, + UInt32 inPropertyDataSize, + const void *inPropertyData, + void *outPropertyData ); + +/* + * Sets the sample rate the HAL device. + * if requireExact: set the sample rate or fail. + * + * otherwise : set the exact sample rate. + * If that fails, check for available sample rates, and choose one + * higher than the requested rate. If there isn't a higher one, + * just use the highest available. + */ +PaError setBestSampleRateForDevice( const AudioDeviceID device, + const bool isOutput, + const bool requireExact, + const Float64 desiredSrate ); +/* + Attempts to set the requestedFramesPerBuffer. If it can't set the exact + value, it settles for something smaller if available. If nothing smaller + is available, it uses the smallest available size. + actualFramesPerBuffer will be set to the actual value on successful return. + OK to pass NULL to actualFramesPerBuffer. + The logic is very simmilar too setBestSampleRate only failure here is + not usually catastrophic. +*/ +PaError setBestFramesPerBuffer( const AudioDeviceID device, + const bool isOutput, + UInt32 requestedFramesPerBuffer, + UInt32 *actualFramesPerBuffer ); + + +/********************* + * + * xrun handling + * + *********************/ + +OSStatus xrunCallback( + AudioDeviceID inDevice, + UInt32 inChannel, + Boolean isInput, + AudioDevicePropertyID inPropertyID, + void* inClientData ) ; + +/** returns zero on success or a unix style error code. */ +int initializeXRunListenerList(); +/** returns zero on success or a unix style error code. */ +int destroyXRunListenerList(); + +/**Returns the list, so that it can be passed to CorAudio.*/ +void *addToXRunListenerList( void *stream ); +/**Returns the number of Listeners in the list remaining.*/ +int removeFromXRunListenerList( void *stream ); + +#endif /* PA_MAC_CORE_UTILITIES_H__*/ diff --git a/extern/portaudio/src/hostapi/dsound/pa_win_ds.c b/extern/portaudio/src/hostapi/dsound/pa_win_ds.c new file mode 100644 index 0000000..204004d --- /dev/null +++ b/extern/portaudio/src/hostapi/dsound/pa_win_ds.c @@ -0,0 +1,3271 @@ +/* + * $Id$ + * Portable Audio I/O Library DirectSound implementation + * + * Authors: Phil Burk, Robert Marsanyi & Ross Bencina + * Based on the Open Source API proposed by Ross Bencina + * Copyright (c) 1999-2007 Ross Bencina, Phil Burk, Robert Marsanyi + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +/** @file + @ingroup hostapi_src +*/ + +/* Until May 2011 PA/DS has used a multimedia timer to perform the callback. + We're replacing this with a new implementation using a thread and a different timer mechanim. + Defining PA_WIN_DS_USE_WMME_TIMER uses the old (pre-May 2011) behavior. +*/ +//#define PA_WIN_DS_USE_WMME_TIMER + +#include +#include +#include /* strlen() */ + +#define _WIN32_WINNT 0x0400 /* required to get waitable timer APIs */ +#include /* make sure ds guids get defined */ +#include +#include + + +/* + Use the earliest version of DX required, no need to polute the namespace +*/ +#ifdef PAWIN_USE_DIRECTSOUNDFULLDUPLEXCREATE +#define DIRECTSOUND_VERSION 0x0800 +#else +#define DIRECTSOUND_VERSION 0x0300 +#endif +#include +#ifdef PAWIN_USE_WDMKS_DEVICE_INFO +#include +#endif /* PAWIN_USE_WDMKS_DEVICE_INFO */ +#ifndef PA_WIN_DS_USE_WMME_TIMER +#ifndef UNDER_CE +#include +#endif +#endif + +#include "pa_util.h" +#include "pa_allocation.h" +#include "pa_hostapi.h" +#include "pa_stream.h" +#include "pa_cpuload.h" +#include "pa_process.h" +#include "pa_debugprint.h" + +#include "pa_win_ds.h" +#include "pa_win_ds_dynlink.h" +#include "pa_win_waveformat.h" +#include "pa_win_wdmks_utils.h" +#include "pa_win_coinitialize.h" + +#if (defined(WIN32) && (defined(_MSC_VER) && (_MSC_VER >= 1200))) /* MSC version 6 and above */ +#pragma comment( lib, "dsound.lib" ) +#pragma comment( lib, "winmm.lib" ) +#pragma comment( lib, "kernel32.lib" ) +#endif + +/* use CreateThread for CYGWIN, _beginthreadex for all others */ +#ifndef PA_WIN_DS_USE_WMME_TIMER + +#if !defined(__CYGWIN__) && !defined(UNDER_CE) +#define CREATE_THREAD (HANDLE)_beginthreadex +#undef CLOSE_THREAD_HANDLE /* as per documentation we don't call CloseHandle on a thread created with _beginthreadex */ +#define PA_THREAD_FUNC static unsigned WINAPI +#define PA_THREAD_ID unsigned +#else +#define CREATE_THREAD CreateThread +#define CLOSE_THREAD_HANDLE CloseHandle +#define PA_THREAD_FUNC static DWORD WINAPI +#define PA_THREAD_ID DWORD +#endif + +#if (defined(UNDER_CE)) +#pragma comment(lib, "Coredll.lib") +#elif (defined(WIN32) && (defined(_MSC_VER) && (_MSC_VER >= 1200))) /* MSC version 6 and above */ +#pragma comment(lib, "winmm.lib") +#endif + +PA_THREAD_FUNC ProcessingThreadProc( void *pArg ); + +#if !defined(UNDER_CE) +#define PA_WIN_DS_USE_WAITABLE_TIMER_OBJECT /* use waitable timer where possible, otherwise we use a WaitForSingleObject timeout */ +#endif + +#endif /* !PA_WIN_DS_USE_WMME_TIMER */ + + +/* + provided in newer platform sdks and x64 + */ +#ifndef DWORD_PTR + #if defined(_WIN64) + #define DWORD_PTR unsigned __int64 + #else + #define DWORD_PTR unsigned long + #endif +#endif + +#define PRINT(x) PA_DEBUG(x); +#define ERR_RPT(x) PRINT(x) +#define DBUG(x) PRINT(x) +#define DBUGX(x) PRINT(x) + +#define PA_USE_HIGH_LATENCY (0) +#if PA_USE_HIGH_LATENCY +#define PA_DS_WIN_9X_DEFAULT_LATENCY_ (.500) +#define PA_DS_WIN_NT_DEFAULT_LATENCY_ (.600) +#else +#define PA_DS_WIN_9X_DEFAULT_LATENCY_ (.140) +#define PA_DS_WIN_NT_DEFAULT_LATENCY_ (.280) +#endif + +#define PA_DS_WIN_WDM_DEFAULT_LATENCY_ (.120) + +/* we allow the polling period to range between 1 and 100ms. + prior to August 2011 we limited the minimum polling period to 10ms. +*/ +#define PA_DS_MINIMUM_POLLING_PERIOD_SECONDS (0.001) /* 1ms */ +#define PA_DS_MAXIMUM_POLLING_PERIOD_SECONDS (0.100) /* 100ms */ +#define PA_DS_POLLING_JITTER_SECONDS (0.001) /* 1ms */ + +#define SECONDS_PER_MSEC (0.001) +#define MSECS_PER_SECOND (1000) + +/* prototypes for functions declared in this file */ + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +PaError PaWinDs_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index ); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +static void Terminate( struct PaUtilHostApiRepresentation *hostApi ); +static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, + PaStream** s, + const PaStreamParameters *inputParameters, + const PaStreamParameters *outputParameters, + double sampleRate, + unsigned long framesPerBuffer, + PaStreamFlags streamFlags, + PaStreamCallback *streamCallback, + void *userData ); +static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi, + const PaStreamParameters *inputParameters, + const PaStreamParameters *outputParameters, + double sampleRate ); +static PaError CloseStream( PaStream* stream ); +static PaError StartStream( PaStream *stream ); +static PaError StopStream( PaStream *stream ); +static PaError AbortStream( PaStream *stream ); +static PaError IsStreamStopped( PaStream *s ); +static PaError IsStreamActive( PaStream *stream ); +static PaTime GetStreamTime( PaStream *stream ); +static double GetStreamCpuLoad( PaStream* stream ); +static PaError ReadStream( PaStream* stream, void *buffer, unsigned long frames ); +static PaError WriteStream( PaStream* stream, const void *buffer, unsigned long frames ); +static signed long GetStreamReadAvailable( PaStream* stream ); +static signed long GetStreamWriteAvailable( PaStream* stream ); + + +/* FIXME: should convert hr to a string */ +#define PA_DS_SET_LAST_DIRECTSOUND_ERROR( hr ) \ + PaUtil_SetLastHostErrorInfo( paDirectSound, hr, "DirectSound error" ) + +/************************************************* DX Prototypes **********/ +static BOOL CALLBACK CollectGUIDsProcW(LPGUID lpGUID, + LPCWSTR lpszDesc, + LPCWSTR lpszDrvName, + LPVOID lpContext ); + +/************************************************************************************/ +/********************** Structures **************************************************/ +/************************************************************************************/ +/* PaWinDsHostApiRepresentation - host api datastructure specific to this implementation */ + +typedef struct PaWinDsDeviceInfo +{ + PaDeviceInfo inheritedDeviceInfo; + GUID guid; + GUID *lpGUID; + double sampleRates[3]; + char deviceInputChannelCountIsKnown; /**<< if the system returns 0xFFFF then we don't really know the number of supported channels (1=>known, 0=>unknown)*/ + char deviceOutputChannelCountIsKnown; /**<< if the system returns 0xFFFF then we don't really know the number of supported channels (1=>known, 0=>unknown)*/ +} PaWinDsDeviceInfo; + +typedef struct +{ + PaUtilHostApiRepresentation inheritedHostApiRep; + PaUtilStreamInterface callbackStreamInterface; + PaUtilStreamInterface blockingStreamInterface; + + PaUtilAllocationGroup *allocations; + + /* implementation specific data goes here */ + + PaWinUtilComInitializationResult comInitializationResult; + +} PaWinDsHostApiRepresentation; + + +/* PaWinDsStream - a stream data structure specifically for this implementation */ + +typedef struct PaWinDsStream +{ + PaUtilStreamRepresentation streamRepresentation; + PaUtilCpuLoadMeasurer cpuLoadMeasurer; + PaUtilBufferProcessor bufferProcessor; + +/* DirectSound specific data. */ +#ifdef PAWIN_USE_DIRECTSOUNDFULLDUPLEXCREATE + LPDIRECTSOUNDFULLDUPLEX8 pDirectSoundFullDuplex8; +#endif + +/* Output */ + LPDIRECTSOUND pDirectSound; + LPDIRECTSOUNDBUFFER pDirectSoundPrimaryBuffer; + LPDIRECTSOUNDBUFFER pDirectSoundOutputBuffer; + DWORD outputBufferWriteOffsetBytes; /* last write position */ + INT outputBufferSizeBytes; + INT outputFrameSizeBytes; + /* Try to detect play buffer underflows. */ + LARGE_INTEGER perfCounterTicksPerBuffer; /* counter ticks it should take to play a full buffer */ + LARGE_INTEGER previousPlayTime; + DWORD previousPlayCursor; + UINT outputUnderflowCount; + BOOL outputIsRunning; + INT finalZeroBytesWritten; /* used to determine when we've flushed the whole buffer */ + +/* Input */ + LPDIRECTSOUNDCAPTURE pDirectSoundCapture; + LPDIRECTSOUNDCAPTUREBUFFER pDirectSoundInputBuffer; + INT inputFrameSizeBytes; + UINT readOffset; /* last read position */ + UINT inputBufferSizeBytes; + + + int hostBufferSizeFrames; /* input and output host ringbuffers have the same number of frames */ + double framesWritten; + double secondsPerHostByte; /* Used to optimize latency calculation for outTime */ + double pollingPeriodSeconds; + + PaStreamCallbackFlags callbackFlags; + + PaStreamFlags streamFlags; + int callbackResult; + HANDLE processingCompleted; + +/* FIXME - move all below to PaUtilStreamRepresentation */ + volatile int isStarted; + volatile int isActive; + volatile int stopProcessing; /* stop thread once existing buffers have been returned */ + volatile int abortProcessing; /* stop thread immediately */ + + UINT systemTimerResolutionPeriodMs; /* set to 0 if we were unable to set the timer period */ + +#ifdef PA_WIN_DS_USE_WMME_TIMER + MMRESULT timerID; +#else + +#ifdef PA_WIN_DS_USE_WAITABLE_TIMER_OBJECT + HANDLE waitableTimer; +#endif + HANDLE processingThread; + PA_THREAD_ID processingThreadId; + HANDLE processingThreadCompleted; +#endif + +} PaWinDsStream; + + +/* Set minimal latency based on the current OS version. + * NT has higher latency. + */ +static double PaWinDS_GetMinSystemLatencySeconds( void ) +{ +/* +NOTE: GetVersionEx() is deprecated as of Windows 8.1 and can not be used to reliably detect +versions of Windows higher than Windows 8 (due to manifest requirements for reporting higher versions). +Microsoft recommends switching to VerifyVersionInfo (available on Win 2k and later), however GetVersionEx +is is faster, for now we just disable the deprecation warning. +See: https://msdn.microsoft.com/en-us/library/windows/desktop/ms724451(v=vs.85).aspx +See: http://www.codeproject.com/Articles/678606/Part-Overcoming-Windows-s-deprecation-of-GetVe +*/ +#pragma warning (disable : 4996) /* use of GetVersionEx */ + + double minLatencySeconds; + /* Set minimal latency based on whether NT or other OS. + * NT has higher latency. + */ + + OSVERSIONINFO osvi; + osvi.dwOSVersionInfoSize = sizeof( osvi ); + GetVersionEx( &osvi ); + DBUG(("PA - PlatformId = 0x%x\n", osvi.dwPlatformId )); + DBUG(("PA - MajorVersion = 0x%x\n", osvi.dwMajorVersion )); + DBUG(("PA - MinorVersion = 0x%x\n", osvi.dwMinorVersion )); + /* Check for NT */ + if( (osvi.dwMajorVersion == 4) && (osvi.dwPlatformId == 2) ) + { + minLatencySeconds = PA_DS_WIN_NT_DEFAULT_LATENCY_; + } + else if(osvi.dwMajorVersion >= 5) + { + minLatencySeconds = PA_DS_WIN_WDM_DEFAULT_LATENCY_; + } + else + { + minLatencySeconds = PA_DS_WIN_9X_DEFAULT_LATENCY_; + } + return minLatencySeconds; + +#pragma warning (default : 4996) +} + + +/************************************************************************* +** Return minimum workable latency required for this host. This is returned +** As the default stream latency in PaDeviceInfo. +** Latency can be optionally set by user by setting an environment variable. +** For example, to set latency to 200 msec, put: +** +** set PA_MIN_LATENCY_MSEC=200 +** +** in the AUTOEXEC.BAT file and reboot. +** If the environment variable is not set, then the latency will be determined +** based on the OS. Windows NT has higher latency than Win95. +*/ +#define PA_LATENCY_ENV_NAME ("PA_MIN_LATENCY_MSEC") +#define PA_ENV_BUF_SIZE (32) + +static double PaWinDs_GetMinLatencySeconds( double sampleRate ) +{ + char envbuf[PA_ENV_BUF_SIZE]; + DWORD hresult; + double minLatencySeconds = 0; + + /* Let user determine minimal latency by setting environment variable. */ + hresult = GetEnvironmentVariableA( PA_LATENCY_ENV_NAME, envbuf, PA_ENV_BUF_SIZE ); + if( (hresult > 0) && (hresult < PA_ENV_BUF_SIZE) ) + { + minLatencySeconds = atoi( envbuf ) * SECONDS_PER_MSEC; + } + else + { + minLatencySeconds = PaWinDS_GetMinSystemLatencySeconds(); +#if PA_USE_HIGH_LATENCY + PRINT(("PA - Minimum Latency set to %f msec!\n", minLatencySeconds * MSECS_PER_SECOND )); +#endif + } + + return minLatencySeconds; +} + + +/************************************************************************************ +** Duplicate and convert the input string using the group allocations allocator. +** A NULL string is converted to a zero length string. +** If memory cannot be allocated, NULL is returned. +**/ +static char *DuplicateDeviceNameString( PaUtilAllocationGroup *allocations, const wchar_t* src ) +{ + char *result = 0; + + if( src != NULL ) + { +#if !defined(_UNICODE) && !defined(UNICODE) + size_t len = WideCharToMultiByte(CP_ACP, 0, src, -1, NULL, 0, NULL, NULL); + + result = (char*)PaUtil_GroupAllocateMemory( allocations, (long)(len + 1) ); + if( result ) { + if (WideCharToMultiByte(CP_ACP, 0, src, -1, result, (int)len, NULL, NULL) == 0) { + result = 0; + } + } +#else + size_t len = WideCharToMultiByte(CP_UTF8, 0, src, -1, NULL, 0, NULL, NULL); + + result = (char*)PaUtil_GroupAllocateMemory( allocations, (long)(len + 1) ); + if( result ) { + if (WideCharToMultiByte(CP_UTF8, 0, src, -1, result, (int)len, NULL, NULL) == 0) { + result = 0; + } + } +#endif + } + else + { + result = (char*)PaUtil_GroupAllocateMemory( allocations, 1 ); + if( result ) + result[0] = '\0'; + } + + return result; +} + +/************************************************************************************ +** DSDeviceNameAndGUID, DSDeviceNameAndGUIDVector used for collecting preliminary +** information during device enumeration. +*/ +typedef struct DSDeviceNameAndGUID{ + char *name; // allocated from parent's allocations, never deleted by this structure + GUID guid; + LPGUID lpGUID; + void *pnpInterface; // wchar_t* interface path, allocated using the DS host api's allocation group +} DSDeviceNameAndGUID; + +typedef struct DSDeviceNameAndGUIDVector{ + PaUtilAllocationGroup *allocations; + PaError enumerationError; + + int count; + int free; + DSDeviceNameAndGUID *items; // Allocated using LocalAlloc() +} DSDeviceNameAndGUIDVector; + +typedef struct DSDeviceNamesAndGUIDs{ + PaWinDsHostApiRepresentation *winDsHostApi; + DSDeviceNameAndGUIDVector inputNamesAndGUIDs; + DSDeviceNameAndGUIDVector outputNamesAndGUIDs; +} DSDeviceNamesAndGUIDs; + +static PaError InitializeDSDeviceNameAndGUIDVector( + DSDeviceNameAndGUIDVector *guidVector, PaUtilAllocationGroup *allocations ) +{ + PaError result = paNoError; + + guidVector->allocations = allocations; + guidVector->enumerationError = paNoError; + + guidVector->count = 0; + guidVector->free = 8; + guidVector->items = (DSDeviceNameAndGUID*)LocalAlloc( LMEM_FIXED, sizeof(DSDeviceNameAndGUID) * guidVector->free ); + if( guidVector->items == NULL ) + result = paInsufficientMemory; + + return result; +} + +static PaError ExpandDSDeviceNameAndGUIDVector( DSDeviceNameAndGUIDVector *guidVector ) +{ + PaError result = paNoError; + DSDeviceNameAndGUID *newItems; + int i; + + /* double size of vector */ + int size = guidVector->count + guidVector->free; + guidVector->free += size; + + newItems = (DSDeviceNameAndGUID*)LocalAlloc( LMEM_FIXED, sizeof(DSDeviceNameAndGUID) * size * 2 ); + if( newItems == NULL ) + { + result = paInsufficientMemory; + } + else + { + for( i=0; i < guidVector->count; ++i ) + { + newItems[i].name = guidVector->items[i].name; + if( guidVector->items[i].lpGUID == NULL ) + { + newItems[i].lpGUID = NULL; + } + else + { + newItems[i].lpGUID = &newItems[i].guid; + memcpy( &newItems[i].guid, guidVector->items[i].lpGUID, sizeof(GUID) ); + } + newItems[i].pnpInterface = guidVector->items[i].pnpInterface; + } + + LocalFree( guidVector->items ); + guidVector->items = newItems; + } + + return result; +} + +/* + it's safe to call DSDeviceNameAndGUIDVector multiple times +*/ +static PaError TerminateDSDeviceNameAndGUIDVector( DSDeviceNameAndGUIDVector *guidVector ) +{ + PaError result = paNoError; + + if( guidVector->items != NULL ) + { + if( LocalFree( guidVector->items ) != NULL ) + result = paInsufficientMemory; /** @todo this isn't the correct error to return from a deallocation failure */ + + guidVector->items = NULL; + } + + return result; +} + +/************************************************************************************ +** Collect preliminary device information during DirectSound enumeration +*/ +static BOOL CALLBACK CollectGUIDsProcW(LPGUID lpGUID, + LPCWSTR lpszDesc, + LPCWSTR lpszDrvName, + LPVOID lpContext ) +{ + DSDeviceNameAndGUIDVector *namesAndGUIDs = (DSDeviceNameAndGUIDVector*)lpContext; + PaError error; + + (void) lpszDrvName; /* unused variable */ + + if( namesAndGUIDs->free == 0 ) + { + error = ExpandDSDeviceNameAndGUIDVector( namesAndGUIDs ); + if( error != paNoError ) + { + namesAndGUIDs->enumerationError = error; + return FALSE; + } + } + + /* Set GUID pointer, copy GUID to storage in DSDeviceNameAndGUIDVector. */ + if( lpGUID == NULL ) + { + namesAndGUIDs->items[namesAndGUIDs->count].lpGUID = NULL; + } + else + { + namesAndGUIDs->items[namesAndGUIDs->count].lpGUID = + &namesAndGUIDs->items[namesAndGUIDs->count].guid; + + memcpy( &namesAndGUIDs->items[namesAndGUIDs->count].guid, lpGUID, sizeof(GUID) ); + } + + namesAndGUIDs->items[namesAndGUIDs->count].name = + DuplicateDeviceNameString( namesAndGUIDs->allocations, lpszDesc ); + if( namesAndGUIDs->items[namesAndGUIDs->count].name == NULL ) + { + namesAndGUIDs->enumerationError = paInsufficientMemory; + return FALSE; + } + + namesAndGUIDs->items[namesAndGUIDs->count].pnpInterface = 0; + + ++namesAndGUIDs->count; + --namesAndGUIDs->free; + + return TRUE; +} + + +#ifdef PAWIN_USE_WDMKS_DEVICE_INFO + +static void *DuplicateWCharString( PaUtilAllocationGroup *allocations, wchar_t *source ) +{ + size_t len; + wchar_t *result; + + len = wcslen( source ); + result = (wchar_t*)PaUtil_GroupAllocateMemory( allocations, (long) ((len+1) * sizeof(wchar_t)) ); + wcscpy( result, source ); + return result; +} + +static BOOL CALLBACK KsPropertySetEnumerateCallback( PDSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_W_DATA data, LPVOID context ) +{ + int i; + DSDeviceNamesAndGUIDs *deviceNamesAndGUIDs = (DSDeviceNamesAndGUIDs*)context; + + /* + Apparently data->Interface can be NULL in some cases. + Possibly virtual devices without hardware. + So we check for NULLs now. See mailing list message November 10, 2012: + "[Portaudio] portaudio initialization crash in KsPropertySetEnumerateCallback(pa_win_ds.c)" + */ + if( data->Interface ) + { + if( data->DataFlow == DIRECTSOUNDDEVICE_DATAFLOW_RENDER ) + { + for( i=0; i < deviceNamesAndGUIDs->outputNamesAndGUIDs.count; ++i ) + { + if( deviceNamesAndGUIDs->outputNamesAndGUIDs.items[i].lpGUID + && memcmp( &data->DeviceId, deviceNamesAndGUIDs->outputNamesAndGUIDs.items[i].lpGUID, sizeof(GUID) ) == 0 ) + { + deviceNamesAndGUIDs->outputNamesAndGUIDs.items[i].pnpInterface = + (char*)DuplicateWCharString( deviceNamesAndGUIDs->winDsHostApi->allocations, data->Interface ); + break; + } + } + } + else if( data->DataFlow == DIRECTSOUNDDEVICE_DATAFLOW_CAPTURE ) + { + for( i=0; i < deviceNamesAndGUIDs->inputNamesAndGUIDs.count; ++i ) + { + if( deviceNamesAndGUIDs->inputNamesAndGUIDs.items[i].lpGUID + && memcmp( &data->DeviceId, deviceNamesAndGUIDs->inputNamesAndGUIDs.items[i].lpGUID, sizeof(GUID) ) == 0 ) + { + deviceNamesAndGUIDs->inputNamesAndGUIDs.items[i].pnpInterface = + (char*)DuplicateWCharString( deviceNamesAndGUIDs->winDsHostApi->allocations, data->Interface ); + break; + } + } + } + } + + return TRUE; +} + + +static GUID pawin_CLSID_DirectSoundPrivate = +{ 0x11ab3ec0, 0x25ec, 0x11d1, 0xa4, 0xd8, 0x00, 0xc0, 0x4f, 0xc2, 0x8a, 0xca }; + +static GUID pawin_DSPROPSETID_DirectSoundDevice = +{ 0x84624f82, 0x25ec, 0x11d1, 0xa4, 0xd8, 0x00, 0xc0, 0x4f, 0xc2, 0x8a, 0xca }; + +static GUID pawin_IID_IKsPropertySet = +{ 0x31efac30, 0x515c, 0x11d0, 0xa9, 0xaa, 0x00, 0xaa, 0x00, 0x61, 0xbe, 0x93 }; + + +/* + FindDevicePnpInterfaces fills in the pnpInterface fields in deviceNamesAndGUIDs + with UNICODE file paths to the devices. The DS documentation mentions + at least two techniques by which these Interface paths can be found using IKsPropertySet on + the DirectSound class object. One is using the DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION + property, and the other is using DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE. + I tried both methods and only the second worked. I found two postings on the + net from people who had the same problem with the first method, so I think the method used here is + more common/likely to work. The probem is that IKsPropertySet_Get returns S_OK + but the fields of the device description are not filled in. + + The mechanism we use works by registering an enumeration callback which is called for + every DSound device. Our callback searches for a device in our deviceNamesAndGUIDs list + with the matching GUID and copies the pointer to the Interface path. + Note that we could have used this enumeration callback to perform the original + device enumeration, however we choose not to so we can disable this step easily. + + Apparently the IKsPropertySet mechanism was added in DirectSound 9c 2004 + http://www.tech-archive.net/Archive/Development/microsoft.public.win32.programmer.mmedia/2004-12/0099.html + + -- rossb +*/ +static void FindDevicePnpInterfaces( DSDeviceNamesAndGUIDs *deviceNamesAndGUIDs ) +{ + IClassFactory *pClassFactory; + + if( paWinDsDSoundEntryPoints.DllGetClassObject(&pawin_CLSID_DirectSoundPrivate, &IID_IClassFactory, (PVOID *) &pClassFactory) == S_OK ){ + IKsPropertySet *pPropertySet; + if( pClassFactory->lpVtbl->CreateInstance( pClassFactory, NULL, &pawin_IID_IKsPropertySet, (PVOID *) &pPropertySet) == S_OK ){ + + DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_W_DATA data; + ULONG bytesReturned; + + data.Callback = KsPropertySetEnumerateCallback; + data.Context = deviceNamesAndGUIDs; + + IKsPropertySet_Get( pPropertySet, + &pawin_DSPROPSETID_DirectSoundDevice, + DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_W, + NULL, + 0, + &data, + sizeof(data), + &bytesReturned + ); + + IKsPropertySet_Release( pPropertySet ); + } + pClassFactory->lpVtbl->Release( pClassFactory ); + } + + /* + The following code fragment, which I chose not to use, queries for the + device interface for a device with a specific GUID: + + ULONG BytesReturned; + DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_W_DATA Property; + + memset (&Property, 0, sizeof(Property)); + Property.DataFlow = DIRECTSOUNDDEVICE_DATAFLOW_RENDER; + Property.DeviceId = *lpGUID; + + hr = IKsPropertySet_Get( pPropertySet, + &pawin_DSPROPSETID_DirectSoundDevice, + DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_W, + NULL, + 0, + &Property, + sizeof(Property), + &BytesReturned + ); + + if( hr == S_OK ) + { + //pnpInterface = Property.Interface; + } + */ +} +#endif /* PAWIN_USE_WDMKS_DEVICE_INFO */ + + +/* + GUIDs for emulated devices which we blacklist below. + are there more than two of them?? +*/ + +GUID IID_IRolandVSCEmulated1 = {0xc2ad1800, 0xb243, 0x11ce, 0xa8, 0xa4, 0x00, 0xaa, 0x00, 0x6c, 0x45, 0x01}; +GUID IID_IRolandVSCEmulated2 = {0xc2ad1800, 0xb243, 0x11ce, 0xa8, 0xa4, 0x00, 0xaa, 0x00, 0x6c, 0x45, 0x02}; + + +#define PA_DEFAULTSAMPLERATESEARCHORDER_COUNT_ (13) /* must match array length below */ +static double defaultSampleRateSearchOrder_[] = + { 44100.0, 48000.0, 32000.0, 24000.0, 22050.0, 88200.0, 96000.0, 192000.0, + 16000.0, 12000.0, 11025.0, 9600.0, 8000.0 }; + +/************************************************************************************ +** Extract capabilities from an output device, and add it to the device info list +** if successful. This function assumes that there is enough room in the +** device info list to accomodate all entries. +** +** The device will not be added to the device list if any errors are encountered. +*/ +static PaError AddOutputDeviceInfoFromDirectSound( + PaWinDsHostApiRepresentation *winDsHostApi, char *name, LPGUID lpGUID, char *pnpInterface ) +{ + PaUtilHostApiRepresentation *hostApi = &winDsHostApi->inheritedHostApiRep; + PaWinDsDeviceInfo *winDsDeviceInfo = (PaWinDsDeviceInfo*) hostApi->deviceInfos[hostApi->info.deviceCount]; + PaDeviceInfo *deviceInfo = &winDsDeviceInfo->inheritedDeviceInfo; + HRESULT hr; + LPDIRECTSOUND lpDirectSound; + DSCAPS caps; + int deviceOK = TRUE; + PaError result = paNoError; + int i; + + /* Copy GUID to the device info structure. Set pointer. */ + if( lpGUID == NULL ) + { + winDsDeviceInfo->lpGUID = NULL; + } + else + { + memcpy( &winDsDeviceInfo->guid, lpGUID, sizeof(GUID) ); + winDsDeviceInfo->lpGUID = &winDsDeviceInfo->guid; + } + + if( lpGUID ) + { + if (IsEqualGUID (&IID_IRolandVSCEmulated1,lpGUID) || + IsEqualGUID (&IID_IRolandVSCEmulated2,lpGUID) ) + { + PA_DEBUG(("BLACKLISTED: %s \n",name)); + return paNoError; + } + } + + /* Create a DirectSound object for the specified GUID + Note that using CoCreateInstance doesn't work on windows CE. + */ + hr = paWinDsDSoundEntryPoints.DirectSoundCreate( lpGUID, &lpDirectSound, NULL ); + + /** try using CoCreateInstance because DirectSoundCreate was hanging under + some circumstances - note this was probably related to the + #define BOOL short bug which has now been fixed + @todo delete this comment and the following code once we've ensured + there is no bug. + */ + /* + hr = CoCreateInstance( &CLSID_DirectSound, NULL, CLSCTX_INPROC_SERVER, + &IID_IDirectSound, (void**)&lpDirectSound ); + + if( hr == S_OK ) + { + hr = IDirectSound_Initialize( lpDirectSound, lpGUID ); + } + */ + + if( hr != DS_OK ) + { + if (hr == DSERR_ALLOCATED) + PA_DEBUG(("AddOutputDeviceInfoFromDirectSound %s DSERR_ALLOCATED\n",name)); + DBUG(("Cannot create DirectSound for %s. Result = 0x%x\n", name, hr )); + if (lpGUID) + DBUG(("%s's GUID: {0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x, 0x%x} \n", + name, + lpGUID->Data1, + lpGUID->Data2, + lpGUID->Data3, + lpGUID->Data4[0], + lpGUID->Data4[1], + lpGUID->Data4[2], + lpGUID->Data4[3], + lpGUID->Data4[4], + lpGUID->Data4[5], + lpGUID->Data4[6], + lpGUID->Data4[7])); + + deviceOK = FALSE; + } + else + { + /* Query device characteristics. */ + memset( &caps, 0, sizeof(caps) ); + caps.dwSize = sizeof(caps); + hr = IDirectSound_GetCaps( lpDirectSound, &caps ); + if( hr != DS_OK ) + { + DBUG(("Cannot GetCaps() for DirectSound device %s. Result = 0x%x\n", name, hr )); + deviceOK = FALSE; + } + else + { + +#if PA_USE_WMME + if( caps.dwFlags & DSCAPS_EMULDRIVER ) + { + /* If WMME supported, then reject Emulated drivers because they are lousy. */ + deviceOK = FALSE; + } +#endif + + if( deviceOK ) + { + deviceInfo->maxInputChannels = 0; + winDsDeviceInfo->deviceInputChannelCountIsKnown = 1; + + /* DS output capabilities only indicate supported number of channels + using two flags which indicate mono and/or stereo. + We assume that stereo devices may support more than 2 channels + (as is the case with 5.1 devices for example) and so + set deviceOutputChannelCountIsKnown to 0 (unknown). + In this case OpenStream will try to open the device + when the user requests more than 2 channels, rather than + returning an error. + */ + if( caps.dwFlags & DSCAPS_PRIMARYSTEREO ) + { + deviceInfo->maxOutputChannels = 2; + winDsDeviceInfo->deviceOutputChannelCountIsKnown = 0; + } + else + { + deviceInfo->maxOutputChannels = 1; + winDsDeviceInfo->deviceOutputChannelCountIsKnown = 1; + } + + /* Guess channels count from speaker configuration. We do it only when + pnpInterface is NULL or when PAWIN_USE_WDMKS_DEVICE_INFO is undefined. + */ +#ifdef PAWIN_USE_WDMKS_DEVICE_INFO + if( !pnpInterface ) +#endif + { + DWORD spkrcfg; + if( SUCCEEDED(IDirectSound_GetSpeakerConfig( lpDirectSound, &spkrcfg )) ) + { + int count = 0; + switch (DSSPEAKER_CONFIG(spkrcfg)) + { + case DSSPEAKER_HEADPHONE: count = 2; break; + case DSSPEAKER_MONO: count = 1; break; + case DSSPEAKER_QUAD: count = 4; break; + case DSSPEAKER_STEREO: count = 2; break; + case DSSPEAKER_SURROUND: count = 4; break; + case DSSPEAKER_5POINT1: count = 6; break; +#ifndef DSSPEAKER_7POINT1 +#define DSSPEAKER_7POINT1 0x00000007 +#endif + case DSSPEAKER_7POINT1: count = 8; break; +#ifndef DSSPEAKER_7POINT1_SURROUND +#define DSSPEAKER_7POINT1_SURROUND 0x00000008 +#endif + case DSSPEAKER_7POINT1_SURROUND: count = 8; break; +#ifndef DSSPEAKER_5POINT1_SURROUND +#define DSSPEAKER_5POINT1_SURROUND 0x00000009 +#endif + case DSSPEAKER_5POINT1_SURROUND: count = 6; break; + } + if( count ) + { + deviceInfo->maxOutputChannels = count; + winDsDeviceInfo->deviceOutputChannelCountIsKnown = 1; + } + } + } + +#ifdef PAWIN_USE_WDMKS_DEVICE_INFO + if( pnpInterface ) + { + int count = PaWin_WDMKS_QueryFilterMaximumChannelCount( pnpInterface, /* isInput= */ 0 ); + if( count > 0 ) + { + deviceInfo->maxOutputChannels = count; + winDsDeviceInfo->deviceOutputChannelCountIsKnown = 1; + } + } +#endif /* PAWIN_USE_WDMKS_DEVICE_INFO */ + + /* initialize defaultSampleRate */ + + if( caps.dwFlags & DSCAPS_CONTINUOUSRATE ) + { + /* initialize to caps.dwMaxSecondarySampleRate incase none of the standard rates match */ + deviceInfo->defaultSampleRate = caps.dwMaxSecondarySampleRate; + + for( i = 0; i < PA_DEFAULTSAMPLERATESEARCHORDER_COUNT_; ++i ) + { + if( defaultSampleRateSearchOrder_[i] >= caps.dwMinSecondarySampleRate + && defaultSampleRateSearchOrder_[i] <= caps.dwMaxSecondarySampleRate ) + { + deviceInfo->defaultSampleRate = defaultSampleRateSearchOrder_[i]; + break; + } + } + } + else if( caps.dwMinSecondarySampleRate == caps.dwMaxSecondarySampleRate ) + { + if( caps.dwMinSecondarySampleRate == 0 ) + { + /* + ** On my Thinkpad 380Z, DirectSoundV6 returns min-max=0 !! + ** But it supports continuous sampling. + ** So fake range of rates, and hope it really supports it. + */ + deviceInfo->defaultSampleRate = 48000.0f; /* assume 48000 as the default */ + + DBUG(("PA - Reported rates both zero. Setting to fake values for device #%s\n", name )); + } + else + { + deviceInfo->defaultSampleRate = caps.dwMaxSecondarySampleRate; + } + } + else if( (caps.dwMinSecondarySampleRate < 1000.0) && (caps.dwMaxSecondarySampleRate > 50000.0) ) + { + /* The EWS88MT drivers lie, lie, lie. The say they only support two rates, 100 & 100000. + ** But we know that they really support a range of rates! + ** So when we see a ridiculous set of rates, assume it is a range. + */ + deviceInfo->defaultSampleRate = 48000.0f; /* assume 48000 as the default */ + DBUG(("PA - Sample rate range used instead of two odd values for device #%s\n", name )); + } + else deviceInfo->defaultSampleRate = caps.dwMaxSecondarySampleRate; + + //printf( "min %d max %d\n", caps.dwMinSecondarySampleRate, caps.dwMaxSecondarySampleRate ); + // dwFlags | DSCAPS_CONTINUOUSRATE + + deviceInfo->defaultLowInputLatency = 0.; + deviceInfo->defaultHighInputLatency = 0.; + + deviceInfo->defaultLowOutputLatency = PaWinDs_GetMinLatencySeconds( deviceInfo->defaultSampleRate ); + deviceInfo->defaultHighOutputLatency = deviceInfo->defaultLowOutputLatency * 2; + } + } + + IDirectSound_Release( lpDirectSound ); + } + + if( deviceOK ) + { + deviceInfo->name = name; + + if( lpGUID == NULL ) + hostApi->info.defaultOutputDevice = hostApi->info.deviceCount; + + hostApi->info.deviceCount++; + } + + return result; +} + + +/************************************************************************************ +** Extract capabilities from an input device, and add it to the device info list +** if successful. This function assumes that there is enough room in the +** device info list to accomodate all entries. +** +** The device will not be added to the device list if any errors are encountered. +*/ +static PaError AddInputDeviceInfoFromDirectSoundCapture( + PaWinDsHostApiRepresentation *winDsHostApi, char *name, LPGUID lpGUID, char *pnpInterface ) +{ + PaUtilHostApiRepresentation *hostApi = &winDsHostApi->inheritedHostApiRep; + PaWinDsDeviceInfo *winDsDeviceInfo = (PaWinDsDeviceInfo*) hostApi->deviceInfos[hostApi->info.deviceCount]; + PaDeviceInfo *deviceInfo = &winDsDeviceInfo->inheritedDeviceInfo; + HRESULT hr; + LPDIRECTSOUNDCAPTURE lpDirectSoundCapture; + DSCCAPS caps; + int deviceOK = TRUE; + PaError result = paNoError; + + /* Copy GUID to the device info structure. Set pointer. */ + if( lpGUID == NULL ) + { + winDsDeviceInfo->lpGUID = NULL; + } + else + { + winDsDeviceInfo->lpGUID = &winDsDeviceInfo->guid; + memcpy( &winDsDeviceInfo->guid, lpGUID, sizeof(GUID) ); + } + + hr = paWinDsDSoundEntryPoints.DirectSoundCaptureCreate( lpGUID, &lpDirectSoundCapture, NULL ); + + /** try using CoCreateInstance because DirectSoundCreate was hanging under + some circumstances - note this was probably related to the + #define BOOL short bug which has now been fixed + @todo delete this comment and the following code once we've ensured + there is no bug. + */ + /* + hr = CoCreateInstance( &CLSID_DirectSoundCapture, NULL, CLSCTX_INPROC_SERVER, + &IID_IDirectSoundCapture, (void**)&lpDirectSoundCapture ); + */ + if( hr != DS_OK ) + { + DBUG(("Cannot create Capture for %s. Result = 0x%x\n", name, hr )); + deviceOK = FALSE; + } + else + { + /* Query device characteristics. */ + memset( &caps, 0, sizeof(caps) ); + caps.dwSize = sizeof(caps); + hr = IDirectSoundCapture_GetCaps( lpDirectSoundCapture, &caps ); + if( hr != DS_OK ) + { + DBUG(("Cannot GetCaps() for Capture device %s. Result = 0x%x\n", name, hr )); + deviceOK = FALSE; + } + else + { +#if PA_USE_WMME + if( caps.dwFlags & DSCAPS_EMULDRIVER ) + { + /* If WMME supported, then reject Emulated drivers because they are lousy. */ + deviceOK = FALSE; + } +#endif + + if( deviceOK ) + { + deviceInfo->maxInputChannels = caps.dwChannels; + winDsDeviceInfo->deviceInputChannelCountIsKnown = 1; + + deviceInfo->maxOutputChannels = 0; + winDsDeviceInfo->deviceOutputChannelCountIsKnown = 1; + +#ifdef PAWIN_USE_WDMKS_DEVICE_INFO + if( pnpInterface ) + { + int count = PaWin_WDMKS_QueryFilterMaximumChannelCount( pnpInterface, /* isInput= */ 1 ); + if( count > 0 ) + { + deviceInfo->maxInputChannels = count; + winDsDeviceInfo->deviceInputChannelCountIsKnown = 1; + } + } +#endif /* PAWIN_USE_WDMKS_DEVICE_INFO */ + +/* constants from a WINE patch by Francois Gouget, see: + http://www.winehq.com/hypermail/wine-patches/2003/01/0290.html + + --- + Date: Fri, 14 May 2004 10:38:12 +0200 (CEST) + From: Francois Gouget + To: Ross Bencina + Subject: Re: Permission to use wine 48/96 wave patch in BSD licensed library + + [snip] + + I give you permission to use the patch below under the BSD license. + http://www.winehq.com/hypermail/wine-patches/2003/01/0290.html + + [snip] +*/ +#ifndef WAVE_FORMAT_48M08 +#define WAVE_FORMAT_48M08 0x00001000 /* 48 kHz, Mono, 8-bit */ +#define WAVE_FORMAT_48S08 0x00002000 /* 48 kHz, Stereo, 8-bit */ +#define WAVE_FORMAT_48M16 0x00004000 /* 48 kHz, Mono, 16-bit */ +#define WAVE_FORMAT_48S16 0x00008000 /* 48 kHz, Stereo, 16-bit */ +#define WAVE_FORMAT_96M08 0x00010000 /* 96 kHz, Mono, 8-bit */ +#define WAVE_FORMAT_96S08 0x00020000 /* 96 kHz, Stereo, 8-bit */ +#define WAVE_FORMAT_96M16 0x00040000 /* 96 kHz, Mono, 16-bit */ +#define WAVE_FORMAT_96S16 0x00080000 /* 96 kHz, Stereo, 16-bit */ +#endif + + /* defaultSampleRate */ + if( caps.dwChannels == 2 ) + { + if( caps.dwFormats & WAVE_FORMAT_4S16 ) + deviceInfo->defaultSampleRate = 44100.0; + else if( caps.dwFormats & WAVE_FORMAT_48S16 ) + deviceInfo->defaultSampleRate = 48000.0; + else if( caps.dwFormats & WAVE_FORMAT_2S16 ) + deviceInfo->defaultSampleRate = 22050.0; + else if( caps.dwFormats & WAVE_FORMAT_1S16 ) + deviceInfo->defaultSampleRate = 11025.0; + else if( caps.dwFormats & WAVE_FORMAT_96S16 ) + deviceInfo->defaultSampleRate = 96000.0; + else + deviceInfo->defaultSampleRate = 48000.0; /* assume 48000 as the default */ + } + else if( caps.dwChannels == 1 ) + { + if( caps.dwFormats & WAVE_FORMAT_4M16 ) + deviceInfo->defaultSampleRate = 44100.0; + else if( caps.dwFormats & WAVE_FORMAT_48M16 ) + deviceInfo->defaultSampleRate = 48000.0; + else if( caps.dwFormats & WAVE_FORMAT_2M16 ) + deviceInfo->defaultSampleRate = 22050.0; + else if( caps.dwFormats & WAVE_FORMAT_1M16 ) + deviceInfo->defaultSampleRate = 11025.0; + else if( caps.dwFormats & WAVE_FORMAT_96M16 ) + deviceInfo->defaultSampleRate = 96000.0; + else + deviceInfo->defaultSampleRate = 48000.0; /* assume 48000 as the default */ + } + else deviceInfo->defaultSampleRate = 48000.0; /* assume 48000 as the default */ + + deviceInfo->defaultLowInputLatency = PaWinDs_GetMinLatencySeconds( deviceInfo->defaultSampleRate ); + deviceInfo->defaultHighInputLatency = deviceInfo->defaultLowInputLatency * 2; + + deviceInfo->defaultLowOutputLatency = 0.; + deviceInfo->defaultHighOutputLatency = 0.; + } + } + + IDirectSoundCapture_Release( lpDirectSoundCapture ); + } + + if( deviceOK ) + { + deviceInfo->name = name; + + if( lpGUID == NULL ) + hostApi->info.defaultInputDevice = hostApi->info.deviceCount; + + hostApi->info.deviceCount++; + } + + return result; +} + + +/***********************************************************************************/ +PaError PaWinDs_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex ) +{ + PaError result = paNoError; + int i, deviceCount; + PaWinDsHostApiRepresentation *winDsHostApi; + DSDeviceNamesAndGUIDs deviceNamesAndGUIDs; + PaWinDsDeviceInfo *deviceInfoArray; + + PaWinDs_InitializeDSoundEntryPoints(); + + /* initialise guid vectors so they can be safely deleted on error */ + deviceNamesAndGUIDs.winDsHostApi = NULL; + deviceNamesAndGUIDs.inputNamesAndGUIDs.items = NULL; + deviceNamesAndGUIDs.outputNamesAndGUIDs.items = NULL; + + winDsHostApi = (PaWinDsHostApiRepresentation*)PaUtil_AllocateMemory( sizeof(PaWinDsHostApiRepresentation) ); + if( !winDsHostApi ) + { + result = paInsufficientMemory; + goto error; + } + + memset( winDsHostApi, 0, sizeof(PaWinDsHostApiRepresentation) ); /* ensure all fields are zeroed. especially winDsHostApi->allocations */ + + result = PaWinUtil_CoInitialize( paDirectSound, &winDsHostApi->comInitializationResult ); + if( result != paNoError ) + { + goto error; + } + + winDsHostApi->allocations = PaUtil_CreateAllocationGroup(); + if( !winDsHostApi->allocations ) + { + result = paInsufficientMemory; + goto error; + } + + *hostApi = &winDsHostApi->inheritedHostApiRep; + (*hostApi)->info.structVersion = 1; + (*hostApi)->info.type = paDirectSound; + (*hostApi)->info.name = "Windows DirectSound"; + + (*hostApi)->info.deviceCount = 0; + (*hostApi)->info.defaultInputDevice = paNoDevice; + (*hostApi)->info.defaultOutputDevice = paNoDevice; + + +/* DSound - enumerate devices to count them and to gather their GUIDs */ + + result = InitializeDSDeviceNameAndGUIDVector( &deviceNamesAndGUIDs.inputNamesAndGUIDs, winDsHostApi->allocations ); + if( result != paNoError ) + goto error; + + result = InitializeDSDeviceNameAndGUIDVector( &deviceNamesAndGUIDs.outputNamesAndGUIDs, winDsHostApi->allocations ); + if( result != paNoError ) + goto error; + + paWinDsDSoundEntryPoints.DirectSoundCaptureEnumerateW( (LPDSENUMCALLBACKW)CollectGUIDsProcW, (void *)&deviceNamesAndGUIDs.inputNamesAndGUIDs ); + + paWinDsDSoundEntryPoints.DirectSoundEnumerateW( (LPDSENUMCALLBACKW)CollectGUIDsProcW, (void *)&deviceNamesAndGUIDs.outputNamesAndGUIDs ); + + if( deviceNamesAndGUIDs.inputNamesAndGUIDs.enumerationError != paNoError ) + { + result = deviceNamesAndGUIDs.inputNamesAndGUIDs.enumerationError; + goto error; + } + + if( deviceNamesAndGUIDs.outputNamesAndGUIDs.enumerationError != paNoError ) + { + result = deviceNamesAndGUIDs.outputNamesAndGUIDs.enumerationError; + goto error; + } + + deviceCount = deviceNamesAndGUIDs.inputNamesAndGUIDs.count + deviceNamesAndGUIDs.outputNamesAndGUIDs.count; + +#ifdef PAWIN_USE_WDMKS_DEVICE_INFO + if( deviceCount > 0 ) + { + deviceNamesAndGUIDs.winDsHostApi = winDsHostApi; + FindDevicePnpInterfaces( &deviceNamesAndGUIDs ); + } +#endif /* PAWIN_USE_WDMKS_DEVICE_INFO */ + + if( deviceCount > 0 ) + { + /* allocate array for pointers to PaDeviceInfo structs */ + (*hostApi)->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory( + winDsHostApi->allocations, sizeof(PaDeviceInfo*) * deviceCount ); + if( !(*hostApi)->deviceInfos ) + { + result = paInsufficientMemory; + goto error; + } + + /* allocate all PaDeviceInfo structs in a contiguous block */ + deviceInfoArray = (PaWinDsDeviceInfo*)PaUtil_GroupAllocateMemory( + winDsHostApi->allocations, sizeof(PaWinDsDeviceInfo) * deviceCount ); + if( !deviceInfoArray ) + { + result = paInsufficientMemory; + goto error; + } + + for( i=0; i < deviceCount; ++i ) + { + PaDeviceInfo *deviceInfo = &deviceInfoArray[i].inheritedDeviceInfo; + deviceInfo->structVersion = 2; + deviceInfo->hostApi = hostApiIndex; + deviceInfo->name = 0; + (*hostApi)->deviceInfos[i] = deviceInfo; + } + + for( i=0; i < deviceNamesAndGUIDs.inputNamesAndGUIDs.count; ++i ) + { + result = AddInputDeviceInfoFromDirectSoundCapture( winDsHostApi, + deviceNamesAndGUIDs.inputNamesAndGUIDs.items[i].name, + deviceNamesAndGUIDs.inputNamesAndGUIDs.items[i].lpGUID, + deviceNamesAndGUIDs.inputNamesAndGUIDs.items[i].pnpInterface ); + if( result != paNoError ) + goto error; + } + + for( i=0; i < deviceNamesAndGUIDs.outputNamesAndGUIDs.count; ++i ) + { + result = AddOutputDeviceInfoFromDirectSound( winDsHostApi, + deviceNamesAndGUIDs.outputNamesAndGUIDs.items[i].name, + deviceNamesAndGUIDs.outputNamesAndGUIDs.items[i].lpGUID, + deviceNamesAndGUIDs.outputNamesAndGUIDs.items[i].pnpInterface ); + if( result != paNoError ) + goto error; + } + } + + result = TerminateDSDeviceNameAndGUIDVector( &deviceNamesAndGUIDs.inputNamesAndGUIDs ); + if( result != paNoError ) + goto error; + + result = TerminateDSDeviceNameAndGUIDVector( &deviceNamesAndGUIDs.outputNamesAndGUIDs ); + if( result != paNoError ) + goto error; + + + (*hostApi)->Terminate = Terminate; + (*hostApi)->OpenStream = OpenStream; + (*hostApi)->IsFormatSupported = IsFormatSupported; + + PaUtil_InitializeStreamInterface( &winDsHostApi->callbackStreamInterface, CloseStream, StartStream, + StopStream, AbortStream, IsStreamStopped, IsStreamActive, + GetStreamTime, GetStreamCpuLoad, + PaUtil_DummyRead, PaUtil_DummyWrite, + PaUtil_DummyGetReadAvailable, PaUtil_DummyGetWriteAvailable ); + + PaUtil_InitializeStreamInterface( &winDsHostApi->blockingStreamInterface, CloseStream, StartStream, + StopStream, AbortStream, IsStreamStopped, IsStreamActive, + GetStreamTime, PaUtil_DummyGetCpuLoad, + ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable ); + + return result; + +error: + TerminateDSDeviceNameAndGUIDVector( &deviceNamesAndGUIDs.inputNamesAndGUIDs ); + TerminateDSDeviceNameAndGUIDVector( &deviceNamesAndGUIDs.outputNamesAndGUIDs ); + + Terminate( (struct PaUtilHostApiRepresentation *)winDsHostApi ); + + return result; +} + + +/***********************************************************************************/ +static void Terminate( struct PaUtilHostApiRepresentation *hostApi ) +{ + PaWinDsHostApiRepresentation *winDsHostApi = (PaWinDsHostApiRepresentation*)hostApi; + + if( winDsHostApi ){ + if( winDsHostApi->allocations ) + { + PaUtil_FreeAllAllocations( winDsHostApi->allocations ); + PaUtil_DestroyAllocationGroup( winDsHostApi->allocations ); + } + + PaWinUtil_CoUninitialize( paDirectSound, &winDsHostApi->comInitializationResult ); + + PaUtil_FreeMemory( winDsHostApi ); + } + + PaWinDs_TerminateDSoundEntryPoints(); +} + +static PaError ValidateWinDirectSoundSpecificStreamInfo( + const PaStreamParameters *streamParameters, + const PaWinDirectSoundStreamInfo *streamInfo ) +{ + if( streamInfo ) + { + if( streamInfo->size != sizeof( PaWinDirectSoundStreamInfo ) + || streamInfo->version != 2 ) + { + return paIncompatibleHostApiSpecificStreamInfo; + } + + if( streamInfo->flags & paWinDirectSoundUseLowLevelLatencyParameters ) + { + if( streamInfo->framesPerBuffer <= 0 ) + return paIncompatibleHostApiSpecificStreamInfo; + + } + } + + return paNoError; +} + +/***********************************************************************************/ +static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi, + const PaStreamParameters *inputParameters, + const PaStreamParameters *outputParameters, + double sampleRate ) +{ + PaError result; + PaWinDsDeviceInfo *inputWinDsDeviceInfo, *outputWinDsDeviceInfo; + PaDeviceInfo *inputDeviceInfo, *outputDeviceInfo; + int inputChannelCount, outputChannelCount; + PaSampleFormat inputSampleFormat, outputSampleFormat; + PaWinDirectSoundStreamInfo *inputStreamInfo, *outputStreamInfo; + + if( inputParameters ) + { + inputWinDsDeviceInfo = (PaWinDsDeviceInfo*) hostApi->deviceInfos[ inputParameters->device ]; + inputDeviceInfo = &inputWinDsDeviceInfo->inheritedDeviceInfo; + + inputChannelCount = inputParameters->channelCount; + inputSampleFormat = inputParameters->sampleFormat; + + /* unless alternate device specification is supported, reject the use of + paUseHostApiSpecificDeviceSpecification */ + + if( inputParameters->device == paUseHostApiSpecificDeviceSpecification ) + return paInvalidDevice; + + /* check that input device can support inputChannelCount */ + if( inputWinDsDeviceInfo->deviceInputChannelCountIsKnown + && inputChannelCount > inputDeviceInfo->maxInputChannels ) + return paInvalidChannelCount; + + /* validate inputStreamInfo */ + inputStreamInfo = (PaWinDirectSoundStreamInfo*)inputParameters->hostApiSpecificStreamInfo; + result = ValidateWinDirectSoundSpecificStreamInfo( inputParameters, inputStreamInfo ); + if( result != paNoError ) return result; + } + else + { + inputChannelCount = 0; + } + + if( outputParameters ) + { + outputWinDsDeviceInfo = (PaWinDsDeviceInfo*) hostApi->deviceInfos[ outputParameters->device ]; + outputDeviceInfo = &outputWinDsDeviceInfo->inheritedDeviceInfo; + + outputChannelCount = outputParameters->channelCount; + outputSampleFormat = outputParameters->sampleFormat; + + /* unless alternate device specification is supported, reject the use of + paUseHostApiSpecificDeviceSpecification */ + + if( outputParameters->device == paUseHostApiSpecificDeviceSpecification ) + return paInvalidDevice; + + /* check that output device can support inputChannelCount */ + if( outputWinDsDeviceInfo->deviceOutputChannelCountIsKnown + && outputChannelCount > outputDeviceInfo->maxOutputChannels ) + return paInvalidChannelCount; + + /* validate outputStreamInfo */ + outputStreamInfo = (PaWinDirectSoundStreamInfo*)outputParameters->hostApiSpecificStreamInfo; + result = ValidateWinDirectSoundSpecificStreamInfo( outputParameters, outputStreamInfo ); + if( result != paNoError ) return result; + } + else + { + outputChannelCount = 0; + } + + /* + IMPLEMENT ME: + + - if a full duplex stream is requested, check that the combination + of input and output parameters is supported if necessary + + - check that the device supports sampleRate + + Because the buffer adapter handles conversion between all standard + sample formats, the following checks are only required if paCustomFormat + is implemented, or under some other unusual conditions. + + - check that input device can support inputSampleFormat, or that + we have the capability to convert from outputSampleFormat to + a native format + + - check that output device can support outputSampleFormat, or that + we have the capability to convert from outputSampleFormat to + a native format + */ + + return paFormatIsSupported; +} + + +#ifdef PAWIN_USE_DIRECTSOUNDFULLDUPLEXCREATE +static HRESULT InitFullDuplexInputOutputBuffers( PaWinDsStream *stream, + PaWinDsDeviceInfo *inputDevice, + PaSampleFormat hostInputSampleFormat, + WORD inputChannelCount, + int bytesPerInputBuffer, + PaWinWaveFormatChannelMask inputChannelMask, + PaWinDsDeviceInfo *outputDevice, + PaSampleFormat hostOutputSampleFormat, + WORD outputChannelCount, + int bytesPerOutputBuffer, + PaWinWaveFormatChannelMask outputChannelMask, + unsigned long nFrameRate + ) +{ + HRESULT hr; + DSCBUFFERDESC captureDesc; + PaWinWaveFormat captureWaveFormat; + DSBUFFERDESC secondaryRenderDesc; + PaWinWaveFormat renderWaveFormat; + LPDIRECTSOUNDBUFFER8 pRenderBuffer8; + LPDIRECTSOUNDCAPTUREBUFFER8 pCaptureBuffer8; + + // capture buffer description + + // only try wave format extensible. assume it's available on all ds 8 systems + PaWin_InitializeWaveFormatExtensible( &captureWaveFormat, inputChannelCount, + hostInputSampleFormat, PaWin_SampleFormatToLinearWaveFormatTag( hostInputSampleFormat ), + nFrameRate, inputChannelMask ); + + ZeroMemory(&captureDesc, sizeof(DSCBUFFERDESC)); + captureDesc.dwSize = sizeof(DSCBUFFERDESC); + captureDesc.dwFlags = 0; + captureDesc.dwBufferBytes = bytesPerInputBuffer; + captureDesc.lpwfxFormat = (WAVEFORMATEX*)&captureWaveFormat; + + // render buffer description + + PaWin_InitializeWaveFormatExtensible( &renderWaveFormat, outputChannelCount, + hostOutputSampleFormat, PaWin_SampleFormatToLinearWaveFormatTag( hostOutputSampleFormat ), + nFrameRate, outputChannelMask ); + + ZeroMemory(&secondaryRenderDesc, sizeof(DSBUFFERDESC)); + secondaryRenderDesc.dwSize = sizeof(DSBUFFERDESC); + secondaryRenderDesc.dwFlags = DSBCAPS_GLOBALFOCUS | DSBCAPS_GETCURRENTPOSITION2; + secondaryRenderDesc.dwBufferBytes = bytesPerOutputBuffer; + secondaryRenderDesc.lpwfxFormat = (WAVEFORMATEX*)&renderWaveFormat; + + /* note that we don't create a primary buffer here at all */ + + hr = paWinDsDSoundEntryPoints.DirectSoundFullDuplexCreate8( + inputDevice->lpGUID, outputDevice->lpGUID, + &captureDesc, &secondaryRenderDesc, + GetDesktopWindow(), /* see InitOutputBuffer() for a discussion of whether this is a good idea */ + DSSCL_EXCLUSIVE, + &stream->pDirectSoundFullDuplex8, + &pCaptureBuffer8, + &pRenderBuffer8, + NULL /* pUnkOuter must be NULL */ + ); + + if( hr == DS_OK ) + { + PA_DEBUG(("DirectSoundFullDuplexCreate succeeded!\n")); + + /* retrieve the pre ds 8 buffer interfaces which are used by the rest of the code */ + + hr = IUnknown_QueryInterface( pCaptureBuffer8, &IID_IDirectSoundCaptureBuffer, (LPVOID *)&stream->pDirectSoundInputBuffer ); + + if( hr == DS_OK ) + hr = IUnknown_QueryInterface( pRenderBuffer8, &IID_IDirectSoundBuffer, (LPVOID *)&stream->pDirectSoundOutputBuffer ); + + /* release the ds 8 interfaces, we don't need them */ + IUnknown_Release( pCaptureBuffer8 ); + IUnknown_Release( pRenderBuffer8 ); + + if( !stream->pDirectSoundInputBuffer || !stream->pDirectSoundOutputBuffer ){ + /* couldn't get pre ds 8 interfaces for some reason. clean up. */ + if( stream->pDirectSoundInputBuffer ) + { + IUnknown_Release( stream->pDirectSoundInputBuffer ); + stream->pDirectSoundInputBuffer = NULL; + } + + if( stream->pDirectSoundOutputBuffer ) + { + IUnknown_Release( stream->pDirectSoundOutputBuffer ); + stream->pDirectSoundOutputBuffer = NULL; + } + + IUnknown_Release( stream->pDirectSoundFullDuplex8 ); + stream->pDirectSoundFullDuplex8 = NULL; + } + } + else + { + PA_DEBUG(("DirectSoundFullDuplexCreate failed. hr=%d\n", hr)); + } + + return hr; +} +#endif /* PAWIN_USE_DIRECTSOUNDFULLDUPLEXCREATE */ + + +static HRESULT InitInputBuffer( PaWinDsStream *stream, + PaWinDsDeviceInfo *device, + PaSampleFormat sampleFormat, + unsigned long nFrameRate, + WORD nChannels, + int bytesPerBuffer, + PaWinWaveFormatChannelMask channelMask ) +{ + DSCBUFFERDESC captureDesc; + PaWinWaveFormat waveFormat; + HRESULT result; + + if( (result = paWinDsDSoundEntryPoints.DirectSoundCaptureCreate( + device->lpGUID, &stream->pDirectSoundCapture, NULL) ) != DS_OK ){ + ERR_RPT(("PortAudio: DirectSoundCaptureCreate() failed!\n")); + return result; + } + + // Setup the secondary buffer description + ZeroMemory(&captureDesc, sizeof(DSCBUFFERDESC)); + captureDesc.dwSize = sizeof(DSCBUFFERDESC); + captureDesc.dwFlags = 0; + captureDesc.dwBufferBytes = bytesPerBuffer; + captureDesc.lpwfxFormat = (WAVEFORMATEX*)&waveFormat; + + // Create the capture buffer + + // first try WAVEFORMATEXTENSIBLE. if this fails, fall back to WAVEFORMATEX + PaWin_InitializeWaveFormatExtensible( &waveFormat, nChannels, + sampleFormat, PaWin_SampleFormatToLinearWaveFormatTag( sampleFormat ), + nFrameRate, channelMask ); + + if( IDirectSoundCapture_CreateCaptureBuffer( stream->pDirectSoundCapture, + &captureDesc, &stream->pDirectSoundInputBuffer, NULL) != DS_OK ) + { + PaWin_InitializeWaveFormatEx( &waveFormat, nChannels, sampleFormat, + PaWin_SampleFormatToLinearWaveFormatTag( sampleFormat ), nFrameRate ); + + if ((result = IDirectSoundCapture_CreateCaptureBuffer( stream->pDirectSoundCapture, + &captureDesc, &stream->pDirectSoundInputBuffer, NULL)) != DS_OK) return result; + } + + stream->readOffset = 0; // reset last read position to start of buffer + return DS_OK; +} + + +static HRESULT InitOutputBuffer( PaWinDsStream *stream, PaWinDsDeviceInfo *device, + PaSampleFormat sampleFormat, unsigned long nFrameRate, + WORD nChannels, int bytesPerBuffer, + PaWinWaveFormatChannelMask channelMask ) +{ + HRESULT result; + HWND hWnd; + HRESULT hr; + PaWinWaveFormat waveFormat; + DSBUFFERDESC primaryDesc; + DSBUFFERDESC secondaryDesc; + + if( (hr = paWinDsDSoundEntryPoints.DirectSoundCreate( + device->lpGUID, &stream->pDirectSound, NULL )) != DS_OK ){ + ERR_RPT(("PortAudio: DirectSoundCreate() failed!\n")); + return hr; + } + + // We were using getForegroundWindow() but sometimes the ForegroundWindow may not be the + // applications's window. Also if that window is closed before the Buffer is closed + // then DirectSound can crash. (Thanks for Scott Patterson for reporting this.) + // So we will use GetDesktopWindow() which was suggested by Miller Puckette. + // hWnd = GetForegroundWindow(); + // + // FIXME: The example code I have on the net creates a hidden window that + // is managed by our code - I think we should do that - one hidden + // window for the whole of Pa_DS + // + hWnd = GetDesktopWindow(); + + // Set cooperative level to DSSCL_EXCLUSIVE so that we can get 16 bit output, 44.1 KHz. + // exclusive also prevents unexpected sounds from other apps during a performance. + if ((hr = IDirectSound_SetCooperativeLevel( stream->pDirectSound, + hWnd, DSSCL_EXCLUSIVE)) != DS_OK) + { + return hr; + } + + // ----------------------------------------------------------------------- + // Create primary buffer and set format just so we can specify our custom format. + // Otherwise we would be stuck with the default which might be 8 bit or 22050 Hz. + // Setup the primary buffer description + ZeroMemory(&primaryDesc, sizeof(DSBUFFERDESC)); + primaryDesc.dwSize = sizeof(DSBUFFERDESC); + primaryDesc.dwFlags = DSBCAPS_PRIMARYBUFFER; // all panning, mixing, etc done by synth + primaryDesc.dwBufferBytes = 0; + primaryDesc.lpwfxFormat = NULL; + // Create the buffer + if ((result = IDirectSound_CreateSoundBuffer( stream->pDirectSound, + &primaryDesc, &stream->pDirectSoundPrimaryBuffer, NULL)) != DS_OK) + goto error; + + // Set the primary buffer's format + + // first try WAVEFORMATEXTENSIBLE. if this fails, fall back to WAVEFORMATEX + PaWin_InitializeWaveFormatExtensible( &waveFormat, nChannels, + sampleFormat, PaWin_SampleFormatToLinearWaveFormatTag( sampleFormat ), + nFrameRate, channelMask ); + + if( IDirectSoundBuffer_SetFormat( stream->pDirectSoundPrimaryBuffer, (WAVEFORMATEX*)&waveFormat) != DS_OK ) + { + PaWin_InitializeWaveFormatEx( &waveFormat, nChannels, sampleFormat, + PaWin_SampleFormatToLinearWaveFormatTag( sampleFormat ), nFrameRate ); + + if((result = IDirectSoundBuffer_SetFormat( stream->pDirectSoundPrimaryBuffer, (WAVEFORMATEX*)&waveFormat)) != DS_OK) + goto error; + } + + // ---------------------------------------------------------------------- + // Setup the secondary buffer description + ZeroMemory(&secondaryDesc, sizeof(DSBUFFERDESC)); + secondaryDesc.dwSize = sizeof(DSBUFFERDESC); + secondaryDesc.dwFlags = DSBCAPS_GLOBALFOCUS | DSBCAPS_GETCURRENTPOSITION2; + secondaryDesc.dwBufferBytes = bytesPerBuffer; + secondaryDesc.lpwfxFormat = (WAVEFORMATEX*)&waveFormat; /* waveFormat contains whatever format was negotiated for the primary buffer above */ + // Create the secondary buffer + if ((result = IDirectSound_CreateSoundBuffer( stream->pDirectSound, + &secondaryDesc, &stream->pDirectSoundOutputBuffer, NULL)) != DS_OK) + goto error; + + return DS_OK; + +error: + + if( stream->pDirectSoundPrimaryBuffer ) + { + IDirectSoundBuffer_Release( stream->pDirectSoundPrimaryBuffer ); + stream->pDirectSoundPrimaryBuffer = NULL; + } + + return result; +} + + +static void CalculateBufferSettings( unsigned long *hostBufferSizeFrames, + unsigned long *pollingPeriodFrames, + int isFullDuplex, + unsigned long suggestedInputLatencyFrames, + unsigned long suggestedOutputLatencyFrames, + double sampleRate, unsigned long userFramesPerBuffer ) +{ + unsigned long minimumPollingPeriodFrames = (unsigned long)(sampleRate * PA_DS_MINIMUM_POLLING_PERIOD_SECONDS); + unsigned long maximumPollingPeriodFrames = (unsigned long)(sampleRate * PA_DS_MAXIMUM_POLLING_PERIOD_SECONDS); + unsigned long pollingJitterFrames = (unsigned long)(sampleRate * PA_DS_POLLING_JITTER_SECONDS); + + if( userFramesPerBuffer == paFramesPerBufferUnspecified ) + { + unsigned long targetBufferingLatencyFrames = max( suggestedInputLatencyFrames, suggestedOutputLatencyFrames ); + + *pollingPeriodFrames = targetBufferingLatencyFrames / 4; + if( *pollingPeriodFrames < minimumPollingPeriodFrames ) + { + *pollingPeriodFrames = minimumPollingPeriodFrames; + } + else if( *pollingPeriodFrames > maximumPollingPeriodFrames ) + { + *pollingPeriodFrames = maximumPollingPeriodFrames; + } + + *hostBufferSizeFrames = *pollingPeriodFrames + + max( *pollingPeriodFrames + pollingJitterFrames, targetBufferingLatencyFrames); + } + else + { + unsigned long targetBufferingLatencyFrames = suggestedInputLatencyFrames; + if( isFullDuplex ) + { + /* In full duplex streams we know that the buffer adapter adds userFramesPerBuffer + extra fixed latency. so we subtract it here as a fixed latency before computing + the buffer size. being careful not to produce an unrepresentable negative result. + + Note: this only works as expected if output latency is greater than input latency. + Otherwise we use input latency anyway since we do max(in,out). + */ + + if( userFramesPerBuffer < suggestedOutputLatencyFrames ) + { + unsigned long adjustedSuggestedOutputLatencyFrames = + suggestedOutputLatencyFrames - userFramesPerBuffer; + + /* maximum of input and adjusted output suggested latency */ + if( adjustedSuggestedOutputLatencyFrames > targetBufferingLatencyFrames ) + targetBufferingLatencyFrames = adjustedSuggestedOutputLatencyFrames; + } + } + else + { + /* maximum of input and output suggested latency */ + if( suggestedOutputLatencyFrames > suggestedInputLatencyFrames ) + targetBufferingLatencyFrames = suggestedOutputLatencyFrames; + } + + *hostBufferSizeFrames = userFramesPerBuffer + + max( userFramesPerBuffer + pollingJitterFrames, targetBufferingLatencyFrames); + + *pollingPeriodFrames = max( max(1, userFramesPerBuffer / 4), targetBufferingLatencyFrames / 16 ); + + if( *pollingPeriodFrames > maximumPollingPeriodFrames ) + { + *pollingPeriodFrames = maximumPollingPeriodFrames; + } + } +} + + +static void CalculatePollingPeriodFrames( unsigned long hostBufferSizeFrames, + unsigned long *pollingPeriodFrames, + double sampleRate, unsigned long userFramesPerBuffer ) +{ + unsigned long minimumPollingPeriodFrames = (unsigned long)(sampleRate * PA_DS_MINIMUM_POLLING_PERIOD_SECONDS); + unsigned long maximumPollingPeriodFrames = (unsigned long)(sampleRate * PA_DS_MAXIMUM_POLLING_PERIOD_SECONDS); + unsigned long pollingJitterFrames = (unsigned long)(sampleRate * PA_DS_POLLING_JITTER_SECONDS); + + *pollingPeriodFrames = max( max(1, userFramesPerBuffer / 4), hostBufferSizeFrames / 16 ); + + if( *pollingPeriodFrames > maximumPollingPeriodFrames ) + { + *pollingPeriodFrames = maximumPollingPeriodFrames; + } +} + + +static void SetStreamInfoLatencies( PaWinDsStream *stream, + unsigned long userFramesPerBuffer, + unsigned long pollingPeriodFrames, + double sampleRate ) +{ + /* compute the stream info actual latencies based on framesPerBuffer, polling period, hostBufferSizeFrames, + and the configuration of the buffer processor */ + + unsigned long effectiveFramesPerBuffer = (userFramesPerBuffer == paFramesPerBufferUnspecified) + ? pollingPeriodFrames + : userFramesPerBuffer; + + if( stream->bufferProcessor.inputChannelCount > 0 ) + { + /* stream info input latency is the minimum buffering latency + (unlike suggested and default which are *maximums*) */ + stream->streamRepresentation.streamInfo.inputLatency = + (double)(PaUtil_GetBufferProcessorInputLatencyFrames(&stream->bufferProcessor) + + effectiveFramesPerBuffer) / sampleRate; + } + else + { + stream->streamRepresentation.streamInfo.inputLatency = 0; + } + + if( stream->bufferProcessor.outputChannelCount > 0 ) + { + stream->streamRepresentation.streamInfo.outputLatency = + (double)(PaUtil_GetBufferProcessorOutputLatencyFrames(&stream->bufferProcessor) + + (stream->hostBufferSizeFrames - effectiveFramesPerBuffer)) / sampleRate; + } + else + { + stream->streamRepresentation.streamInfo.outputLatency = 0; + } +} + + +/***********************************************************************************/ +/* see pa_hostapi.h for a list of validity guarantees made about OpenStream parameters */ + +static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, + PaStream** s, + const PaStreamParameters *inputParameters, + const PaStreamParameters *outputParameters, + double sampleRate, + unsigned long framesPerBuffer, + PaStreamFlags streamFlags, + PaStreamCallback *streamCallback, + void *userData ) +{ + PaError result = paNoError; + PaWinDsHostApiRepresentation *winDsHostApi = (PaWinDsHostApiRepresentation*)hostApi; + PaWinDsStream *stream = 0; + int bufferProcessorIsInitialized = 0; + int streamRepresentationIsInitialized = 0; + PaWinDsDeviceInfo *inputWinDsDeviceInfo, *outputWinDsDeviceInfo; + PaDeviceInfo *inputDeviceInfo, *outputDeviceInfo; + int inputChannelCount, outputChannelCount; + PaSampleFormat inputSampleFormat, outputSampleFormat; + PaSampleFormat hostInputSampleFormat, hostOutputSampleFormat; + int userRequestedHostInputBufferSizeFrames = 0; + int userRequestedHostOutputBufferSizeFrames = 0; + unsigned long suggestedInputLatencyFrames, suggestedOutputLatencyFrames; + PaWinDirectSoundStreamInfo *inputStreamInfo, *outputStreamInfo; + PaWinWaveFormatChannelMask inputChannelMask, outputChannelMask; + unsigned long pollingPeriodFrames = 0; + + if( inputParameters ) + { + inputWinDsDeviceInfo = (PaWinDsDeviceInfo*) hostApi->deviceInfos[ inputParameters->device ]; + inputDeviceInfo = &inputWinDsDeviceInfo->inheritedDeviceInfo; + + inputChannelCount = inputParameters->channelCount; + inputSampleFormat = inputParameters->sampleFormat; + suggestedInputLatencyFrames = (unsigned long)(inputParameters->suggestedLatency * sampleRate); + + /* IDEA: the following 3 checks could be performed by default by pa_front + unless some flag indicated otherwise */ + + /* unless alternate device specification is supported, reject the use of + paUseHostApiSpecificDeviceSpecification */ + if( inputParameters->device == paUseHostApiSpecificDeviceSpecification ) + return paInvalidDevice; + + /* check that input device can support inputChannelCount */ + if( inputWinDsDeviceInfo->deviceInputChannelCountIsKnown + && inputChannelCount > inputDeviceInfo->maxInputChannels ) + return paInvalidChannelCount; + + /* validate hostApiSpecificStreamInfo */ + inputStreamInfo = (PaWinDirectSoundStreamInfo*)inputParameters->hostApiSpecificStreamInfo; + result = ValidateWinDirectSoundSpecificStreamInfo( inputParameters, inputStreamInfo ); + if( result != paNoError ) return result; + + if( inputStreamInfo && inputStreamInfo->flags & paWinDirectSoundUseLowLevelLatencyParameters ) + userRequestedHostInputBufferSizeFrames = inputStreamInfo->framesPerBuffer; + + if( inputStreamInfo && inputStreamInfo->flags & paWinDirectSoundUseChannelMask ) + inputChannelMask = inputStreamInfo->channelMask; + else + inputChannelMask = PaWin_DefaultChannelMask( inputChannelCount ); + } + else + { + inputChannelCount = 0; + inputSampleFormat = 0; + suggestedInputLatencyFrames = 0; + } + + + if( outputParameters ) + { + outputWinDsDeviceInfo = (PaWinDsDeviceInfo*) hostApi->deviceInfos[ outputParameters->device ]; + outputDeviceInfo = &outputWinDsDeviceInfo->inheritedDeviceInfo; + + outputChannelCount = outputParameters->channelCount; + outputSampleFormat = outputParameters->sampleFormat; + suggestedOutputLatencyFrames = (unsigned long)(outputParameters->suggestedLatency * sampleRate); + + /* unless alternate device specification is supported, reject the use of + paUseHostApiSpecificDeviceSpecification */ + if( outputParameters->device == paUseHostApiSpecificDeviceSpecification ) + return paInvalidDevice; + + /* check that output device can support outputChannelCount */ + if( outputWinDsDeviceInfo->deviceOutputChannelCountIsKnown + && outputChannelCount > outputDeviceInfo->maxOutputChannels ) + return paInvalidChannelCount; + + /* validate hostApiSpecificStreamInfo */ + outputStreamInfo = (PaWinDirectSoundStreamInfo*)outputParameters->hostApiSpecificStreamInfo; + result = ValidateWinDirectSoundSpecificStreamInfo( outputParameters, outputStreamInfo ); + if( result != paNoError ) return result; + + if( outputStreamInfo && outputStreamInfo->flags & paWinDirectSoundUseLowLevelLatencyParameters ) + userRequestedHostOutputBufferSizeFrames = outputStreamInfo->framesPerBuffer; + + if( outputStreamInfo && outputStreamInfo->flags & paWinDirectSoundUseChannelMask ) + outputChannelMask = outputStreamInfo->channelMask; + else + outputChannelMask = PaWin_DefaultChannelMask( outputChannelCount ); + } + else + { + outputChannelCount = 0; + outputSampleFormat = 0; + suggestedOutputLatencyFrames = 0; + } + + /* + If low level host buffer size is specified for both input and output + the current code requires the sizes to match. + */ + + if( (userRequestedHostInputBufferSizeFrames > 0 && userRequestedHostOutputBufferSizeFrames > 0) + && userRequestedHostInputBufferSizeFrames != userRequestedHostOutputBufferSizeFrames ) + return paIncompatibleHostApiSpecificStreamInfo; + + + + /* + IMPLEMENT ME: + + ( the following two checks are taken care of by PaUtil_InitializeBufferProcessor() ) + + - check that input device can support inputSampleFormat, or that + we have the capability to convert from outputSampleFormat to + a native format + + - check that output device can support outputSampleFormat, or that + we have the capability to convert from outputSampleFormat to + a native format + + - if a full duplex stream is requested, check that the combination + of input and output parameters is supported + + - check that the device supports sampleRate + + - alter sampleRate to a close allowable rate if possible / necessary + + - validate suggestedInputLatency and suggestedOutputLatency parameters, + use default values where necessary + */ + + + /* validate platform specific flags */ + if( (streamFlags & paPlatformSpecificFlags) != 0 ) + return paInvalidFlag; /* unexpected platform specific flag */ + + + stream = (PaWinDsStream*)PaUtil_AllocateMemory( sizeof(PaWinDsStream) ); + if( !stream ) + { + result = paInsufficientMemory; + goto error; + } + + memset( stream, 0, sizeof(PaWinDsStream) ); /* initialize all stream variables to 0 */ + + if( streamCallback ) + { + PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation, + &winDsHostApi->callbackStreamInterface, streamCallback, userData ); + } + else + { + PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation, + &winDsHostApi->blockingStreamInterface, streamCallback, userData ); + } + + streamRepresentationIsInitialized = 1; + + stream->streamFlags = streamFlags; + + PaUtil_InitializeCpuLoadMeasurer( &stream->cpuLoadMeasurer, sampleRate ); + + + if( inputParameters ) + { + /* IMPLEMENT ME - establish which host formats are available */ + PaSampleFormat nativeInputFormats = paInt16; + /* PaSampleFormat nativeFormats = paUInt8 | paInt16 | paInt24 | paInt32 | paFloat32; */ + + hostInputSampleFormat = + PaUtil_SelectClosestAvailableFormat( nativeInputFormats, inputParameters->sampleFormat ); + } + else + { + hostInputSampleFormat = 0; + } + + if( outputParameters ) + { + /* IMPLEMENT ME - establish which host formats are available */ + PaSampleFormat nativeOutputFormats = paInt16; + /* PaSampleFormat nativeOutputFormats = paUInt8 | paInt16 | paInt24 | paInt32 | paFloat32; */ + + hostOutputSampleFormat = + PaUtil_SelectClosestAvailableFormat( nativeOutputFormats, outputParameters->sampleFormat ); + } + else + { + hostOutputSampleFormat = 0; + } + + result = PaUtil_InitializeBufferProcessor( &stream->bufferProcessor, + inputChannelCount, inputSampleFormat, hostInputSampleFormat, + outputChannelCount, outputSampleFormat, hostOutputSampleFormat, + sampleRate, streamFlags, framesPerBuffer, + 0, /* ignored in paUtilVariableHostBufferSizePartialUsageAllowed mode. */ + /* This next mode is required because DS can split the host buffer when it wraps around. */ + paUtilVariableHostBufferSizePartialUsageAllowed, + streamCallback, userData ); + if( result != paNoError ) + goto error; + + bufferProcessorIsInitialized = 1; + + +/* DirectSound specific initialization */ + { + HRESULT hr; + unsigned long integerSampleRate = (unsigned long) (sampleRate + 0.5); + + stream->processingCompleted = CreateEvent( NULL, /* bManualReset = */ TRUE, /* bInitialState = */ FALSE, NULL ); + if( stream->processingCompleted == NULL ) + { + result = paInsufficientMemory; + goto error; + } + +#ifdef PA_WIN_DS_USE_WMME_TIMER + stream->timerID = 0; +#endif + +#ifdef PA_WIN_DS_USE_WAITABLE_TIMER_OBJECT + stream->waitableTimer = (HANDLE)CreateWaitableTimer( 0, FALSE, NULL ); + if( stream->waitableTimer == NULL ) + { + result = paUnanticipatedHostError; + PA_DS_SET_LAST_DIRECTSOUND_ERROR( GetLastError() ); + goto error; + } +#endif + +#ifndef PA_WIN_DS_USE_WMME_TIMER + stream->processingThreadCompleted = CreateEvent( NULL, /* bManualReset = */ TRUE, /* bInitialState = */ FALSE, NULL ); + if( stream->processingThreadCompleted == NULL ) + { + result = paUnanticipatedHostError; + PA_DS_SET_LAST_DIRECTSOUND_ERROR( GetLastError() ); + goto error; + } +#endif + + /* set up i/o parameters */ + + if( userRequestedHostInputBufferSizeFrames > 0 || userRequestedHostOutputBufferSizeFrames > 0 ) + { + /* use low level parameters */ + + /* since we use the same host buffer size for input and output + we choose the highest user specified value. + */ + stream->hostBufferSizeFrames = max( userRequestedHostInputBufferSizeFrames, userRequestedHostOutputBufferSizeFrames ); + + CalculatePollingPeriodFrames( + stream->hostBufferSizeFrames, &pollingPeriodFrames, + sampleRate, framesPerBuffer ); + } + else + { + CalculateBufferSettings( (unsigned long*)&stream->hostBufferSizeFrames, &pollingPeriodFrames, + /* isFullDuplex = */ (inputParameters && outputParameters), + suggestedInputLatencyFrames, + suggestedOutputLatencyFrames, + sampleRate, framesPerBuffer ); + } + + stream->pollingPeriodSeconds = pollingPeriodFrames / sampleRate; + + DBUG(("DirectSound host buffer size frames: %d, polling period seconds: %f, @ sr: %f\n", + stream->hostBufferSizeFrames, stream->pollingPeriodSeconds, sampleRate )); + + + /* ------------------ OUTPUT */ + if( outputParameters ) + { + LARGE_INTEGER counterFrequency; + + /* + PaDeviceInfo *deviceInfo = hostApi->deviceInfos[ outputParameters->device ]; + DBUG(("PaHost_OpenStream: deviceID = 0x%x\n", outputParameters->device)); + */ + + int sampleSizeBytes = Pa_GetSampleSize(hostOutputSampleFormat); + stream->outputFrameSizeBytes = outputParameters->channelCount * sampleSizeBytes; + + stream->outputBufferSizeBytes = stream->hostBufferSizeFrames * stream->outputFrameSizeBytes; + if( stream->outputBufferSizeBytes < DSBSIZE_MIN ) + { + result = paBufferTooSmall; + goto error; + } + else if( stream->outputBufferSizeBytes > DSBSIZE_MAX ) + { + result = paBufferTooBig; + goto error; + } + + /* Calculate value used in latency calculation to avoid real-time divides. */ + stream->secondsPerHostByte = 1.0 / + (stream->bufferProcessor.bytesPerHostOutputSample * + outputChannelCount * sampleRate); + + stream->outputIsRunning = FALSE; + stream->outputUnderflowCount = 0; + + /* perfCounterTicksPerBuffer is used by QueryOutputSpace for overflow detection */ + if( QueryPerformanceFrequency( &counterFrequency ) ) + { + stream->perfCounterTicksPerBuffer.QuadPart = (counterFrequency.QuadPart * stream->hostBufferSizeFrames) / integerSampleRate; + } + else + { + stream->perfCounterTicksPerBuffer.QuadPart = 0; + } + } + + /* ------------------ INPUT */ + if( inputParameters ) + { + /* + PaDeviceInfo *deviceInfo = hostApi->deviceInfos[ inputParameters->device ]; + DBUG(("PaHost_OpenStream: deviceID = 0x%x\n", inputParameters->device)); + */ + + int sampleSizeBytes = Pa_GetSampleSize(hostInputSampleFormat); + stream->inputFrameSizeBytes = inputParameters->channelCount * sampleSizeBytes; + + stream->inputBufferSizeBytes = stream->hostBufferSizeFrames * stream->inputFrameSizeBytes; + if( stream->inputBufferSizeBytes < DSBSIZE_MIN ) + { + result = paBufferTooSmall; + goto error; + } + else if( stream->inputBufferSizeBytes > DSBSIZE_MAX ) + { + result = paBufferTooBig; + goto error; + } + } + + /* open/create the DirectSound buffers */ + + /* interface ptrs should be zeroed when stream is zeroed. */ + assert( stream->pDirectSoundCapture == NULL ); + assert( stream->pDirectSoundInputBuffer == NULL ); + assert( stream->pDirectSound == NULL ); + assert( stream->pDirectSoundPrimaryBuffer == NULL ); + assert( stream->pDirectSoundOutputBuffer == NULL ); + + + if( inputParameters && outputParameters ) + { +#ifdef PAWIN_USE_DIRECTSOUNDFULLDUPLEXCREATE + /* try to use the full-duplex DX8 API to create the buffers. + if that fails we fall back to the half-duplex API below */ + + hr = InitFullDuplexInputOutputBuffers( stream, + (PaWinDsDeviceInfo*)hostApi->deviceInfos[inputParameters->device], + hostInputSampleFormat, + (WORD)inputParameters->channelCount, stream->inputBufferSizeBytes, + inputChannelMask, + (PaWinDsDeviceInfo*)hostApi->deviceInfos[outputParameters->device], + hostOutputSampleFormat, + (WORD)outputParameters->channelCount, stream->outputBufferSizeBytes, + outputChannelMask, + integerSampleRate + ); + DBUG(("InitFullDuplexInputOutputBuffers() returns %x\n", hr)); + /* ignore any error returned by InitFullDuplexInputOutputBuffers. + we retry opening the buffers below */ +#endif /* PAWIN_USE_DIRECTSOUNDFULLDUPLEXCREATE */ + } + + /* create half duplex buffers. also used for full-duplex streams which didn't + succeed when using the full duplex API. that could happen because + DX8 or greater isnt installed, the i/o devices aren't the same + physical device. etc. + */ + + if( outputParameters && !stream->pDirectSoundOutputBuffer ) + { + hr = InitOutputBuffer( stream, + (PaWinDsDeviceInfo*)hostApi->deviceInfos[outputParameters->device], + hostOutputSampleFormat, + integerSampleRate, + (WORD)outputParameters->channelCount, stream->outputBufferSizeBytes, + outputChannelMask ); + DBUG(("InitOutputBuffer() returns %x\n", hr)); + if( hr != DS_OK ) + { + result = paUnanticipatedHostError; + PA_DS_SET_LAST_DIRECTSOUND_ERROR( hr ); + goto error; + } + } + + if( inputParameters && !stream->pDirectSoundInputBuffer ) + { + hr = InitInputBuffer( stream, + (PaWinDsDeviceInfo*)hostApi->deviceInfos[inputParameters->device], + hostInputSampleFormat, + integerSampleRate, + (WORD)inputParameters->channelCount, stream->inputBufferSizeBytes, + inputChannelMask ); + DBUG(("InitInputBuffer() returns %x\n", hr)); + if( hr != DS_OK ) + { + ERR_RPT(("PortAudio: DSW_InitInputBuffer() returns %x\n", hr)); + result = paUnanticipatedHostError; + PA_DS_SET_LAST_DIRECTSOUND_ERROR( hr ); + goto error; + } + } + } + + SetStreamInfoLatencies( stream, framesPerBuffer, pollingPeriodFrames, sampleRate ); + + stream->streamRepresentation.streamInfo.sampleRate = sampleRate; + + *s = (PaStream*)stream; + + return result; + +error: + if( stream ) + { + if( stream->processingCompleted != NULL ) + CloseHandle( stream->processingCompleted ); + +#ifdef PA_WIN_DS_USE_WAITABLE_TIMER_OBJECT + if( stream->waitableTimer != NULL ) + CloseHandle( stream->waitableTimer ); +#endif + +#ifndef PA_WIN_DS_USE_WMME_TIMER + if( stream->processingThreadCompleted != NULL ) + CloseHandle( stream->processingThreadCompleted ); +#endif + + if( stream->pDirectSoundOutputBuffer ) + { + IDirectSoundBuffer_Stop( stream->pDirectSoundOutputBuffer ); + IDirectSoundBuffer_Release( stream->pDirectSoundOutputBuffer ); + stream->pDirectSoundOutputBuffer = NULL; + } + + if( stream->pDirectSoundPrimaryBuffer ) + { + IDirectSoundBuffer_Release( stream->pDirectSoundPrimaryBuffer ); + stream->pDirectSoundPrimaryBuffer = NULL; + } + + if( stream->pDirectSoundInputBuffer ) + { + IDirectSoundCaptureBuffer_Stop( stream->pDirectSoundInputBuffer ); + IDirectSoundCaptureBuffer_Release( stream->pDirectSoundInputBuffer ); + stream->pDirectSoundInputBuffer = NULL; + } + + if( stream->pDirectSoundCapture ) + { + IDirectSoundCapture_Release( stream->pDirectSoundCapture ); + stream->pDirectSoundCapture = NULL; + } + + if( stream->pDirectSound ) + { + IDirectSound_Release( stream->pDirectSound ); + stream->pDirectSound = NULL; + } + +#ifdef PAWIN_USE_DIRECTSOUNDFULLDUPLEXCREATE + if( stream->pDirectSoundFullDuplex8 ) + { + IDirectSoundFullDuplex_Release( stream->pDirectSoundFullDuplex8 ); + stream->pDirectSoundFullDuplex8 = NULL; + } +#endif + if( bufferProcessorIsInitialized ) + PaUtil_TerminateBufferProcessor( &stream->bufferProcessor ); + + if( streamRepresentationIsInitialized ) + PaUtil_TerminateStreamRepresentation( &stream->streamRepresentation ); + + PaUtil_FreeMemory( stream ); + } + + return result; +} + + +/************************************************************************************ + * Determine how much space can be safely written to in DS buffer. + * Detect underflows and overflows. + * Does not allow writing into safety gap maintained by DirectSound. + */ +static HRESULT QueryOutputSpace( PaWinDsStream *stream, long *bytesEmpty ) +{ + HRESULT hr; + DWORD playCursor; + DWORD writeCursor; + long numBytesEmpty; + long playWriteGap; + // Query to see how much room is in buffer. + hr = IDirectSoundBuffer_GetCurrentPosition( stream->pDirectSoundOutputBuffer, + &playCursor, &writeCursor ); + if( hr != DS_OK ) + { + return hr; + } + + // Determine size of gap between playIndex and WriteIndex that we cannot write into. + playWriteGap = writeCursor - playCursor; + if( playWriteGap < 0 ) playWriteGap += stream->outputBufferSizeBytes; // unwrap + + /* DirectSound doesn't have a large enough playCursor so we cannot detect wrap-around. */ + /* Attempt to detect playCursor wrap-around and correct it. */ + if( stream->outputIsRunning && (stream->perfCounterTicksPerBuffer.QuadPart != 0) ) + { + /* How much time has elapsed since last check. */ + LARGE_INTEGER currentTime; + LARGE_INTEGER elapsedTime; + long bytesPlayed; + long bytesExpected; + long buffersWrapped; + + QueryPerformanceCounter( ¤tTime ); + elapsedTime.QuadPart = currentTime.QuadPart - stream->previousPlayTime.QuadPart; + stream->previousPlayTime = currentTime; + + /* How many bytes does DirectSound say have been played. */ + bytesPlayed = playCursor - stream->previousPlayCursor; + if( bytesPlayed < 0 ) bytesPlayed += stream->outputBufferSizeBytes; // unwrap + stream->previousPlayCursor = playCursor; + + /* Calculate how many bytes we would have expected to been played by now. */ + bytesExpected = (long) ((elapsedTime.QuadPart * stream->outputBufferSizeBytes) / stream->perfCounterTicksPerBuffer.QuadPart); + buffersWrapped = (bytesExpected - bytesPlayed) / stream->outputBufferSizeBytes; + if( buffersWrapped > 0 ) + { + playCursor += (buffersWrapped * stream->outputBufferSizeBytes); + bytesPlayed += (buffersWrapped * stream->outputBufferSizeBytes); + } + } + numBytesEmpty = playCursor - stream->outputBufferWriteOffsetBytes; + if( numBytesEmpty < 0 ) numBytesEmpty += stream->outputBufferSizeBytes; // unwrap offset + + /* Have we underflowed? */ + if( numBytesEmpty > (stream->outputBufferSizeBytes - playWriteGap) ) + { + if( stream->outputIsRunning ) + { + stream->outputUnderflowCount += 1; + } + + /* + From MSDN: + The write cursor indicates the position at which it is safe + to write new data to the buffer. The write cursor always leads the + play cursor, typically by about 15 milliseconds' worth of audio + data. + It is always safe to change data that is behind the position + indicated by the lpdwCurrentPlayCursor parameter. + */ + + stream->outputBufferWriteOffsetBytes = writeCursor; + numBytesEmpty = stream->outputBufferSizeBytes - playWriteGap; + } + *bytesEmpty = numBytesEmpty; + return hr; +} + +/***********************************************************************************/ +static int TimeSlice( PaWinDsStream *stream ) +{ + long numFrames = 0; + long bytesEmpty = 0; + long bytesFilled = 0; + long bytesToXfer = 0; + long framesToXfer = 0; /* the number of frames we'll process this tick */ + long numInFramesReady = 0; + long numOutFramesReady = 0; + long bytesProcessed; + HRESULT hresult; + double outputLatency = 0; + double inputLatency = 0; + PaStreamCallbackTimeInfo timeInfo = {0,0,0}; + +/* Input */ + LPBYTE lpInBuf1 = NULL; + LPBYTE lpInBuf2 = NULL; + DWORD dwInSize1 = 0; + DWORD dwInSize2 = 0; +/* Output */ + LPBYTE lpOutBuf1 = NULL; + LPBYTE lpOutBuf2 = NULL; + DWORD dwOutSize1 = 0; + DWORD dwOutSize2 = 0; + + /* How much input data is available? */ + if( stream->bufferProcessor.inputChannelCount > 0 ) + { + HRESULT hr; + DWORD capturePos; + DWORD readPos; + long filled = 0; + // Query to see how much data is in buffer. + // We don't need the capture position but sometimes DirectSound doesn't handle NULLS correctly + // so let's pass a pointer just to be safe. + hr = IDirectSoundCaptureBuffer_GetCurrentPosition( stream->pDirectSoundInputBuffer, &capturePos, &readPos ); + if( hr == DS_OK ) + { + filled = readPos - stream->readOffset; + if( filled < 0 ) filled += stream->inputBufferSizeBytes; // unwrap offset + bytesFilled = filled; + + inputLatency = ((double)bytesFilled) * stream->secondsPerHostByte; + } + // FIXME: what happens if IDirectSoundCaptureBuffer_GetCurrentPosition fails? + + framesToXfer = numInFramesReady = bytesFilled / stream->inputFrameSizeBytes; + + /** @todo Check for overflow */ + } + + /* How much output room is available? */ + if( stream->bufferProcessor.outputChannelCount > 0 ) + { + UINT previousUnderflowCount = stream->outputUnderflowCount; + QueryOutputSpace( stream, &bytesEmpty ); + framesToXfer = numOutFramesReady = bytesEmpty / stream->outputFrameSizeBytes; + + /* Check for underflow */ + /* FIXME QueryOutputSpace should not adjust underflow count as a side effect. + A query function should be a const operator on the stream and return a flag on underflow. */ + if( stream->outputUnderflowCount != previousUnderflowCount ) + stream->callbackFlags |= paOutputUnderflow; + + /* We are about to compute audio into the first byte of empty space in the output buffer. + This audio will reach the DAC after all of the current (non-empty) audio + in the buffer has played. Therefore the output time is the current time + plus the time it takes to play the non-empty bytes in the buffer, + computed here: + */ + outputLatency = ((double)(stream->outputBufferSizeBytes - bytesEmpty)) * stream->secondsPerHostByte; + } + + /* if it's a full duplex stream, set framesToXfer to the minimum of input and output frames ready */ + if( stream->bufferProcessor.inputChannelCount > 0 && stream->bufferProcessor.outputChannelCount > 0 ) + { + framesToXfer = (numOutFramesReady < numInFramesReady) ? numOutFramesReady : numInFramesReady; + } + + if( framesToXfer > 0 ) + { + PaUtil_BeginCpuLoadMeasurement( &stream->cpuLoadMeasurer ); + + /* The outputBufferDacTime parameter should indicates the time at which + the first sample of the output buffer is heard at the DACs. */ + timeInfo.currentTime = PaUtil_GetTime(); + + PaUtil_BeginBufferProcessing( &stream->bufferProcessor, &timeInfo, stream->callbackFlags ); + stream->callbackFlags = 0; + + /* Input */ + if( stream->bufferProcessor.inputChannelCount > 0 ) + { + timeInfo.inputBufferAdcTime = timeInfo.currentTime - inputLatency; + + bytesToXfer = framesToXfer * stream->inputFrameSizeBytes; + hresult = IDirectSoundCaptureBuffer_Lock ( stream->pDirectSoundInputBuffer, + stream->readOffset, bytesToXfer, + (void **) &lpInBuf1, &dwInSize1, + (void **) &lpInBuf2, &dwInSize2, 0); + if (hresult != DS_OK) + { + ERR_RPT(("DirectSound IDirectSoundCaptureBuffer_Lock failed, hresult = 0x%x\n",hresult)); + /* PA_DS_SET_LAST_DIRECTSOUND_ERROR( hresult ); */ + PaUtil_ResetBufferProcessor( &stream->bufferProcessor ); /* flush the buffer processor */ + stream->callbackResult = paComplete; + goto error2; + } + + numFrames = dwInSize1 / stream->inputFrameSizeBytes; + PaUtil_SetInputFrameCount( &stream->bufferProcessor, numFrames ); + PaUtil_SetInterleavedInputChannels( &stream->bufferProcessor, 0, lpInBuf1, 0 ); + /* Is input split into two regions. */ + if( dwInSize2 > 0 ) + { + numFrames = dwInSize2 / stream->inputFrameSizeBytes; + PaUtil_Set2ndInputFrameCount( &stream->bufferProcessor, numFrames ); + PaUtil_Set2ndInterleavedInputChannels( &stream->bufferProcessor, 0, lpInBuf2, 0 ); + } + } + + /* Output */ + if( stream->bufferProcessor.outputChannelCount > 0 ) + { + /* + We don't currently add outputLatency here because it appears to produce worse + results than not adding it. Need to do more testing to verify this. + */ + /* timeInfo.outputBufferDacTime = timeInfo.currentTime + outputLatency; */ + timeInfo.outputBufferDacTime = timeInfo.currentTime; + + bytesToXfer = framesToXfer * stream->outputFrameSizeBytes; + hresult = IDirectSoundBuffer_Lock ( stream->pDirectSoundOutputBuffer, + stream->outputBufferWriteOffsetBytes, bytesToXfer, + (void **) &lpOutBuf1, &dwOutSize1, + (void **) &lpOutBuf2, &dwOutSize2, 0); + if (hresult != DS_OK) + { + ERR_RPT(("DirectSound IDirectSoundBuffer_Lock failed, hresult = 0x%x\n",hresult)); + /* PA_DS_SET_LAST_DIRECTSOUND_ERROR( hresult ); */ + PaUtil_ResetBufferProcessor( &stream->bufferProcessor ); /* flush the buffer processor */ + stream->callbackResult = paComplete; + goto error1; + } + + numFrames = dwOutSize1 / stream->outputFrameSizeBytes; + PaUtil_SetOutputFrameCount( &stream->bufferProcessor, numFrames ); + PaUtil_SetInterleavedOutputChannels( &stream->bufferProcessor, 0, lpOutBuf1, 0 ); + + /* Is output split into two regions. */ + if( dwOutSize2 > 0 ) + { + numFrames = dwOutSize2 / stream->outputFrameSizeBytes; + PaUtil_Set2ndOutputFrameCount( &stream->bufferProcessor, numFrames ); + PaUtil_Set2ndInterleavedOutputChannels( &stream->bufferProcessor, 0, lpOutBuf2, 0 ); + } + } + + numFrames = PaUtil_EndBufferProcessing( &stream->bufferProcessor, &stream->callbackResult ); + stream->framesWritten += numFrames; + + if( stream->bufferProcessor.outputChannelCount > 0 ) + { + /* FIXME: an underflow could happen here */ + + /* Update our buffer offset and unlock sound buffer */ + bytesProcessed = numFrames * stream->outputFrameSizeBytes; + stream->outputBufferWriteOffsetBytes = (stream->outputBufferWriteOffsetBytes + bytesProcessed) % stream->outputBufferSizeBytes; + IDirectSoundBuffer_Unlock( stream->pDirectSoundOutputBuffer, lpOutBuf1, dwOutSize1, lpOutBuf2, dwOutSize2); + } + +error1: + if( stream->bufferProcessor.inputChannelCount > 0 ) + { + /* FIXME: an overflow could happen here */ + + /* Update our buffer offset and unlock sound buffer */ + bytesProcessed = numFrames * stream->inputFrameSizeBytes; + stream->readOffset = (stream->readOffset + bytesProcessed) % stream->inputBufferSizeBytes; + IDirectSoundCaptureBuffer_Unlock( stream->pDirectSoundInputBuffer, lpInBuf1, dwInSize1, lpInBuf2, dwInSize2); + } +error2: + + PaUtil_EndCpuLoadMeasurement( &stream->cpuLoadMeasurer, numFrames ); + } + + if( stream->callbackResult == paComplete && !PaUtil_IsBufferProcessorOutputEmpty( &stream->bufferProcessor ) ) + { + /* don't return completed until the buffer processor has been drained */ + return paContinue; + } + else + { + return stream->callbackResult; + } +} +/*******************************************************************/ + +static HRESULT ZeroAvailableOutputSpace( PaWinDsStream *stream ) +{ + HRESULT hr; + LPBYTE lpbuf1 = NULL; + LPBYTE lpbuf2 = NULL; + DWORD dwsize1 = 0; + DWORD dwsize2 = 0; + long bytesEmpty; + hr = QueryOutputSpace( stream, &bytesEmpty ); + if (hr != DS_OK) return hr; + if( bytesEmpty == 0 ) return DS_OK; + // Lock free space in the DS + hr = IDirectSoundBuffer_Lock( stream->pDirectSoundOutputBuffer, stream->outputBufferWriteOffsetBytes, + bytesEmpty, (void **) &lpbuf1, &dwsize1, + (void **) &lpbuf2, &dwsize2, 0); + if (hr == DS_OK) + { + // Copy the buffer into the DS + ZeroMemory(lpbuf1, dwsize1); + if(lpbuf2 != NULL) + { + ZeroMemory(lpbuf2, dwsize2); + } + // Update our buffer offset and unlock sound buffer + stream->outputBufferWriteOffsetBytes = (stream->outputBufferWriteOffsetBytes + dwsize1 + dwsize2) % stream->outputBufferSizeBytes; + IDirectSoundBuffer_Unlock( stream->pDirectSoundOutputBuffer, lpbuf1, dwsize1, lpbuf2, dwsize2); + + stream->finalZeroBytesWritten += dwsize1 + dwsize2; + } + return hr; +} + + +static void CALLBACK TimerCallback(UINT uID, UINT uMsg, DWORD_PTR dwUser, DWORD dw1, DWORD dw2) +{ + PaWinDsStream *stream; + int isFinished = 0; + + /* suppress unused variable warnings */ + (void) uID; + (void) uMsg; + (void) dw1; + (void) dw2; + + stream = (PaWinDsStream *) dwUser; + if( stream == NULL ) return; + + if( stream->isActive ) + { + if( stream->abortProcessing ) + { + isFinished = 1; + } + else if( stream->stopProcessing ) + { + if( stream->bufferProcessor.outputChannelCount > 0 ) + { + ZeroAvailableOutputSpace( stream ); + if( stream->finalZeroBytesWritten >= stream->outputBufferSizeBytes ) + { + /* once we've flushed the whole output buffer with zeros we know all data has been played */ + isFinished = 1; + } + } + else + { + isFinished = 1; + } + } + else + { + int callbackResult = TimeSlice( stream ); + if( callbackResult != paContinue ) + { + /* FIXME implement handling of paComplete and paAbort if possible + At the moment this should behave as if paComplete was called and + flush the buffer. + */ + + stream->stopProcessing = 1; + } + } + + if( isFinished ) + { + if( stream->streamRepresentation.streamFinishedCallback != 0 ) + stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData ); + + stream->isActive = 0; /* don't set this until the stream really is inactive */ + SetEvent( stream->processingCompleted ); + } + } +} + +#ifndef PA_WIN_DS_USE_WMME_TIMER + +#ifdef PA_WIN_DS_USE_WAITABLE_TIMER_OBJECT + +static void CALLBACK WaitableTimerAPCProc( + LPVOID lpArg, // Data value + DWORD dwTimerLowValue, // Timer low value + DWORD dwTimerHighValue ) // Timer high value + +{ + (void)dwTimerLowValue; + (void)dwTimerHighValue; + + TimerCallback( 0, 0, (DWORD_PTR)lpArg, 0, 0 ); +} + +#endif /* PA_WIN_DS_USE_WAITABLE_TIMER_OBJECT */ + + +PA_THREAD_FUNC ProcessingThreadProc( void *pArg ) +{ + PaWinDsStream *stream = (PaWinDsStream *)pArg; + LARGE_INTEGER dueTime; + int timerPeriodMs; + + timerPeriodMs = (int)(stream->pollingPeriodSeconds * MSECS_PER_SECOND); + if( timerPeriodMs < 1 ) + timerPeriodMs = 1; + +#ifdef PA_WIN_DS_USE_WAITABLE_TIMER_OBJECT + assert( stream->waitableTimer != NULL ); + + /* invoke first timeout immediately */ + dueTime.LowPart = timerPeriodMs * 1000 * 10; + dueTime.HighPart = 0; + + /* tick using waitable timer */ + if( SetWaitableTimer( stream->waitableTimer, &dueTime, timerPeriodMs, WaitableTimerAPCProc, pArg, FALSE ) != 0 ) + { + DWORD wfsoResult = 0; + do + { + /* wait for processingCompleted to be signaled or our timer APC to be called */ + wfsoResult = WaitForSingleObjectEx( stream->processingCompleted, timerPeriodMs * 10, /* alertable = */ TRUE ); + + }while( wfsoResult == WAIT_TIMEOUT || wfsoResult == WAIT_IO_COMPLETION ); + } + + CancelWaitableTimer( stream->waitableTimer ); + +#else + + /* tick using WaitForSingleObject timout */ + while ( WaitForSingleObject( stream->processingCompleted, timerPeriodMs ) == WAIT_TIMEOUT ) + { + TimerCallback( 0, 0, (DWORD_PTR)pArg, 0, 0 ); + } +#endif /* PA_WIN_DS_USE_WAITABLE_TIMER_OBJECT */ + + SetEvent( stream->processingThreadCompleted ); + + return 0; +} + +#endif /* !PA_WIN_DS_USE_WMME_TIMER */ + +/*********************************************************************************** + When CloseStream() is called, the multi-api layer ensures that + the stream has already been stopped or aborted. +*/ +static PaError CloseStream( PaStream* s ) +{ + PaError result = paNoError; + PaWinDsStream *stream = (PaWinDsStream*)s; + + CloseHandle( stream->processingCompleted ); + +#ifdef PA_WIN_DS_USE_WAITABLE_TIMER_OBJECT + if( stream->waitableTimer != NULL ) + CloseHandle( stream->waitableTimer ); +#endif + +#ifndef PA_WIN_DS_USE_WMME_TIMER + CloseHandle( stream->processingThreadCompleted ); +#endif + + // Cleanup the sound buffers + if( stream->pDirectSoundOutputBuffer ) + { + IDirectSoundBuffer_Stop( stream->pDirectSoundOutputBuffer ); + IDirectSoundBuffer_Release( stream->pDirectSoundOutputBuffer ); + stream->pDirectSoundOutputBuffer = NULL; + } + + if( stream->pDirectSoundPrimaryBuffer ) + { + IDirectSoundBuffer_Release( stream->pDirectSoundPrimaryBuffer ); + stream->pDirectSoundPrimaryBuffer = NULL; + } + + if( stream->pDirectSoundInputBuffer ) + { + IDirectSoundCaptureBuffer_Stop( stream->pDirectSoundInputBuffer ); + IDirectSoundCaptureBuffer_Release( stream->pDirectSoundInputBuffer ); + stream->pDirectSoundInputBuffer = NULL; + } + + if( stream->pDirectSoundCapture ) + { + IDirectSoundCapture_Release( stream->pDirectSoundCapture ); + stream->pDirectSoundCapture = NULL; + } + + if( stream->pDirectSound ) + { + IDirectSound_Release( stream->pDirectSound ); + stream->pDirectSound = NULL; + } + +#ifdef PAWIN_USE_DIRECTSOUNDFULLDUPLEXCREATE + if( stream->pDirectSoundFullDuplex8 ) + { + IDirectSoundFullDuplex_Release( stream->pDirectSoundFullDuplex8 ); + stream->pDirectSoundFullDuplex8 = NULL; + } +#endif + + PaUtil_TerminateBufferProcessor( &stream->bufferProcessor ); + PaUtil_TerminateStreamRepresentation( &stream->streamRepresentation ); + PaUtil_FreeMemory( stream ); + + return result; +} + +/***********************************************************************************/ +static HRESULT ClearOutputBuffer( PaWinDsStream *stream ) +{ + PaError result = paNoError; + unsigned char* pDSBuffData; + DWORD dwDataLen; + HRESULT hr; + + hr = IDirectSoundBuffer_SetCurrentPosition( stream->pDirectSoundOutputBuffer, 0 ); + DBUG(("PaHost_ClearOutputBuffer: IDirectSoundBuffer_SetCurrentPosition returned = 0x%X.\n", hr)); + if( hr != DS_OK ) + return hr; + + // Lock the DS buffer + if ((hr = IDirectSoundBuffer_Lock( stream->pDirectSoundOutputBuffer, 0, stream->outputBufferSizeBytes, (LPVOID*)&pDSBuffData, + &dwDataLen, NULL, 0, 0)) != DS_OK ) + return hr; + + // Zero the DS buffer + ZeroMemory(pDSBuffData, dwDataLen); + // Unlock the DS buffer + if ((hr = IDirectSoundBuffer_Unlock( stream->pDirectSoundOutputBuffer, pDSBuffData, dwDataLen, NULL, 0)) != DS_OK) + return hr; + + // Let DSound set the starting write position because if we set it to zero, it looks like the + // buffer is full to begin with. This causes a long pause before sound starts when using large buffers. + if ((hr = IDirectSoundBuffer_GetCurrentPosition( stream->pDirectSoundOutputBuffer, + &stream->previousPlayCursor, &stream->outputBufferWriteOffsetBytes )) != DS_OK) + return hr; + + /* printf("DSW_InitOutputBuffer: playCursor = %d, writeCursor = %d\n", playCursor, dsw->dsw_WriteOffset ); */ + + return DS_OK; +} + +static PaError StartStream( PaStream *s ) +{ + PaError result = paNoError; + PaWinDsStream *stream = (PaWinDsStream*)s; + HRESULT hr; + + stream->callbackResult = paContinue; + PaUtil_ResetBufferProcessor( &stream->bufferProcessor ); + + ResetEvent( stream->processingCompleted ); + +#ifndef PA_WIN_DS_USE_WMME_TIMER + ResetEvent( stream->processingThreadCompleted ); +#endif + + if( stream->bufferProcessor.inputChannelCount > 0 ) + { + // Start the buffer capture + if( stream->pDirectSoundInputBuffer != NULL ) // FIXME: not sure this check is necessary + { + hr = IDirectSoundCaptureBuffer_Start( stream->pDirectSoundInputBuffer, DSCBSTART_LOOPING ); + } + + DBUG(("StartStream: DSW_StartInput returned = 0x%X.\n", hr)); + if( hr != DS_OK ) + { + result = paUnanticipatedHostError; + PA_DS_SET_LAST_DIRECTSOUND_ERROR( hr ); + goto error; + } + } + + stream->framesWritten = 0; + stream->callbackFlags = 0; + + stream->abortProcessing = 0; + stream->stopProcessing = 0; + + if( stream->bufferProcessor.outputChannelCount > 0 ) + { + QueryPerformanceCounter( &stream->previousPlayTime ); + stream->finalZeroBytesWritten = 0; + + hr = ClearOutputBuffer( stream ); + if( hr != DS_OK ) + { + result = paUnanticipatedHostError; + PA_DS_SET_LAST_DIRECTSOUND_ERROR( hr ); + goto error; + } + + if( stream->streamRepresentation.streamCallback && (stream->streamFlags & paPrimeOutputBuffersUsingStreamCallback) ) + { + stream->callbackFlags = paPrimingOutput; + + TimeSlice( stream ); + /* we ignore the return value from TimeSlice here and start the stream as usual. + The first timer callback will detect if the callback has completed. */ + + stream->callbackFlags = 0; + } + + // Start the buffer playback in a loop. + if( stream->pDirectSoundOutputBuffer != NULL ) // FIXME: not sure this needs to be checked here + { + hr = IDirectSoundBuffer_Play( stream->pDirectSoundOutputBuffer, 0, 0, DSBPLAY_LOOPING ); + DBUG(("PaHost_StartOutput: IDirectSoundBuffer_Play returned = 0x%X.\n", hr)); + if( hr != DS_OK ) + { + result = paUnanticipatedHostError; + PA_DS_SET_LAST_DIRECTSOUND_ERROR( hr ); + goto error; + } + stream->outputIsRunning = TRUE; + } + } + + if( stream->streamRepresentation.streamCallback ) + { + TIMECAPS timecaps; + int timerPeriodMs = (int)(stream->pollingPeriodSeconds * MSECS_PER_SECOND); + if( timerPeriodMs < 1 ) + timerPeriodMs = 1; + + /* set windows scheduler granularity only as fine as needed, no finer */ + /* Although this is not fully documented by MS, it appears that + timeBeginPeriod() affects the scheduling granulatity of all timers + including Waitable Timer Objects. So we always call timeBeginPeriod, whether + we're using an MM timer callback via timeSetEvent or not. + */ + assert( stream->systemTimerResolutionPeriodMs == 0 ); + if( timeGetDevCaps( &timecaps, sizeof(TIMECAPS) ) == MMSYSERR_NOERROR && timecaps.wPeriodMin > 0 ) + { + /* aim for resolution 4 times higher than polling rate */ + stream->systemTimerResolutionPeriodMs = (UINT)((stream->pollingPeriodSeconds * MSECS_PER_SECOND) * .25); + if( stream->systemTimerResolutionPeriodMs < timecaps.wPeriodMin ) + stream->systemTimerResolutionPeriodMs = timecaps.wPeriodMin; + if( stream->systemTimerResolutionPeriodMs > timecaps.wPeriodMax ) + stream->systemTimerResolutionPeriodMs = timecaps.wPeriodMax; + + if( timeBeginPeriod( stream->systemTimerResolutionPeriodMs ) != MMSYSERR_NOERROR ) + stream->systemTimerResolutionPeriodMs = 0; /* timeBeginPeriod failed, so we don't need to call timeEndPeriod() later */ + } + + +#ifdef PA_WIN_DS_USE_WMME_TIMER + /* Create timer that will wake us up so we can fill the DSound buffer. */ + /* We have deprecated timeSetEvent because all MM timer callbacks + are serialised onto a single thread. Which creates problems with multiple + PA streams, or when also using timers for other time critical tasks + */ + stream->timerID = timeSetEvent( timerPeriodMs, stream->systemTimerResolutionPeriodMs, (LPTIMECALLBACK) TimerCallback, + (DWORD_PTR) stream, TIME_PERIODIC | TIME_KILL_SYNCHRONOUS ); + + if( stream->timerID == 0 ) + { + stream->isActive = 0; + result = paUnanticipatedHostError; + PA_DS_SET_LAST_DIRECTSOUND_ERROR( GetLastError() ); + goto error; + } +#else + /* Create processing thread which calls TimerCallback */ + + stream->processingThread = CREATE_THREAD( 0, 0, ProcessingThreadProc, stream, 0, &stream->processingThreadId ); + if( !stream->processingThread ) + { + result = paUnanticipatedHostError; + PA_DS_SET_LAST_DIRECTSOUND_ERROR( GetLastError() ); + goto error; + } + + if( !SetThreadPriority( stream->processingThread, THREAD_PRIORITY_TIME_CRITICAL ) ) + { + result = paUnanticipatedHostError; + PA_DS_SET_LAST_DIRECTSOUND_ERROR( GetLastError() ); + goto error; + } +#endif + } + + stream->isActive = 1; + stream->isStarted = 1; + + assert( result == paNoError ); + return result; + +error: + + if( stream->pDirectSoundOutputBuffer != NULL && stream->outputIsRunning ) + IDirectSoundBuffer_Stop( stream->pDirectSoundOutputBuffer ); + stream->outputIsRunning = FALSE; + +#ifndef PA_WIN_DS_USE_WMME_TIMER + if( stream->processingThread ) + { +#ifdef CLOSE_THREAD_HANDLE + CLOSE_THREAD_HANDLE( stream->processingThread ); /* Delete thread. */ +#endif + stream->processingThread = NULL; + } +#endif + + return result; +} + + +/***********************************************************************************/ +static PaError StopStream( PaStream *s ) +{ + PaError result = paNoError; + PaWinDsStream *stream = (PaWinDsStream*)s; + HRESULT hr; + int timeoutMsec; + + if( stream->streamRepresentation.streamCallback ) + { + stream->stopProcessing = 1; + + /* Set timeout at 4 times maximum time we might wait. */ + timeoutMsec = (int) (4 * MSECS_PER_SECOND * (stream->hostBufferSizeFrames / stream->streamRepresentation.streamInfo.sampleRate)); + + WaitForSingleObject( stream->processingCompleted, timeoutMsec ); + } + +#ifdef PA_WIN_DS_USE_WMME_TIMER + if( stream->timerID != 0 ) + { + timeKillEvent(stream->timerID); /* Stop callback timer. */ + stream->timerID = 0; + } +#else + if( stream->processingThread ) + { + if( WaitForSingleObject( stream->processingThreadCompleted, 30*100 ) == WAIT_TIMEOUT ) + return paUnanticipatedHostError; + +#ifdef CLOSE_THREAD_HANDLE + CloseHandle( stream->processingThread ); /* Delete thread. */ + stream->processingThread = NULL; +#endif + + } +#endif + + if( stream->systemTimerResolutionPeriodMs > 0 ){ + timeEndPeriod( stream->systemTimerResolutionPeriodMs ); + stream->systemTimerResolutionPeriodMs = 0; + } + + if( stream->bufferProcessor.outputChannelCount > 0 ) + { + // Stop the buffer playback + if( stream->pDirectSoundOutputBuffer != NULL ) + { + stream->outputIsRunning = FALSE; + // FIXME: what happens if IDirectSoundBuffer_Stop returns an error? + hr = IDirectSoundBuffer_Stop( stream->pDirectSoundOutputBuffer ); + + if( stream->pDirectSoundPrimaryBuffer ) + IDirectSoundBuffer_Stop( stream->pDirectSoundPrimaryBuffer ); /* FIXME we never started the primary buffer so I'm not sure we need to stop it */ + } + } + + if( stream->bufferProcessor.inputChannelCount > 0 ) + { + // Stop the buffer capture + if( stream->pDirectSoundInputBuffer != NULL ) + { + // FIXME: what happens if IDirectSoundCaptureBuffer_Stop returns an error? + hr = IDirectSoundCaptureBuffer_Stop( stream->pDirectSoundInputBuffer ); + } + } + + stream->isStarted = 0; + + return result; +} + + +/***********************************************************************************/ +static PaError AbortStream( PaStream *s ) +{ + PaWinDsStream *stream = (PaWinDsStream*)s; + + stream->abortProcessing = 1; + return StopStream( s ); +} + + +/***********************************************************************************/ +static PaError IsStreamStopped( PaStream *s ) +{ + PaWinDsStream *stream = (PaWinDsStream*)s; + + return !stream->isStarted; +} + + +/***********************************************************************************/ +static PaError IsStreamActive( PaStream *s ) +{ + PaWinDsStream *stream = (PaWinDsStream*)s; + + return stream->isActive; +} + +/***********************************************************************************/ +static PaTime GetStreamTime( PaStream *s ) +{ + /* suppress unused variable warnings */ + (void) s; + + return PaUtil_GetTime(); +} + + +/***********************************************************************************/ +static double GetStreamCpuLoad( PaStream* s ) +{ + PaWinDsStream *stream = (PaWinDsStream*)s; + + return PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer ); +} + + +/*********************************************************************************** + As separate stream interfaces are used for blocking and callback + streams, the following functions can be guaranteed to only be called + for blocking streams. +*/ + +static PaError ReadStream( PaStream* s, + void *buffer, + unsigned long frames ) +{ + PaWinDsStream *stream = (PaWinDsStream*)s; + + /* suppress unused variable warnings */ + (void) buffer; + (void) frames; + (void) stream; + + /* IMPLEMENT ME, see portaudio.h for required behavior*/ + + return paNoError; +} + + +/***********************************************************************************/ +static PaError WriteStream( PaStream* s, + const void *buffer, + unsigned long frames ) +{ + PaWinDsStream *stream = (PaWinDsStream*)s; + + /* suppress unused variable warnings */ + (void) buffer; + (void) frames; + (void) stream; + + /* IMPLEMENT ME, see portaudio.h for required behavior*/ + + return paNoError; +} + + +/***********************************************************************************/ +static signed long GetStreamReadAvailable( PaStream* s ) +{ + PaWinDsStream *stream = (PaWinDsStream*)s; + + /* suppress unused variable warnings */ + (void) stream; + + /* IMPLEMENT ME, see portaudio.h for required behavior*/ + + return 0; +} + + +/***********************************************************************************/ +static signed long GetStreamWriteAvailable( PaStream* s ) +{ + PaWinDsStream *stream = (PaWinDsStream*)s; + + /* suppress unused variable warnings */ + (void) stream; + + /* IMPLEMENT ME, see portaudio.h for required behavior*/ + + return 0; +} + diff --git a/extern/portaudio/src/hostapi/dsound/pa_win_ds_dynlink.c b/extern/portaudio/src/hostapi/dsound/pa_win_ds_dynlink.c new file mode 100644 index 0000000..c4e3c4e --- /dev/null +++ b/extern/portaudio/src/hostapi/dsound/pa_win_ds_dynlink.c @@ -0,0 +1,224 @@ +/* + * Interface for dynamically loading directsound and providing a dummy + * implementation if it isn't present. + * + * Author: Ross Bencina (some portions Phil Burk & Robert Marsanyi) + * + * For PortAudio Portable Real-Time Audio Library + * For more information see: http://www.portaudio.com + * Copyright (c) 1999-2006 Phil Burk, Robert Marsanyi and Ross Bencina + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +/** + @file + @ingroup hostapi_src +*/ + +#include "pa_win_ds_dynlink.h" +#include "pa_debugprint.h" + +PaWinDsDSoundEntryPoints paWinDsDSoundEntryPoints = { 0, 0, 0, 0, 0, 0, 0 }; + + +static HRESULT WINAPI DummyDllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv) +{ + (void)rclsid; /* unused parameter */ + (void)riid; /* unused parameter */ + (void)ppv; /* unused parameter */ + return CLASS_E_CLASSNOTAVAILABLE; +} + +static HRESULT WINAPI DummyDirectSoundCreate(LPGUID lpcGuidDevice, LPDIRECTSOUND *ppDS, LPUNKNOWN pUnkOuter) +{ + (void)lpcGuidDevice; /* unused parameter */ + (void)ppDS; /* unused parameter */ + (void)pUnkOuter; /* unused parameter */ + return E_NOTIMPL; +} + +static HRESULT WINAPI DummyDirectSoundEnumerateW(LPDSENUMCALLBACKW lpDSEnumCallback, LPVOID lpContext) +{ + (void)lpDSEnumCallback; /* unused parameter */ + (void)lpContext; /* unused parameter */ + return E_NOTIMPL; +} + +static HRESULT WINAPI DummyDirectSoundEnumerateA(LPDSENUMCALLBACKA lpDSEnumCallback, LPVOID lpContext) +{ + (void)lpDSEnumCallback; /* unused parameter */ + (void)lpContext; /* unused parameter */ + return E_NOTIMPL; +} + +static HRESULT WINAPI DummyDirectSoundCaptureCreate(LPGUID lpcGUID, LPDIRECTSOUNDCAPTURE *lplpDSC, LPUNKNOWN pUnkOuter) +{ + (void)lpcGUID; /* unused parameter */ + (void)lplpDSC; /* unused parameter */ + (void)pUnkOuter; /* unused parameter */ + return E_NOTIMPL; +} + +static HRESULT WINAPI DummyDirectSoundCaptureEnumerateW(LPDSENUMCALLBACKW lpDSCEnumCallback, LPVOID lpContext) +{ + (void)lpDSCEnumCallback; /* unused parameter */ + (void)lpContext; /* unused parameter */ + return E_NOTIMPL; +} + +static HRESULT WINAPI DummyDirectSoundCaptureEnumerateA(LPDSENUMCALLBACKA lpDSCEnumCallback, LPVOID lpContext) +{ + (void)lpDSCEnumCallback; /* unused parameter */ + (void)lpContext; /* unused parameter */ + return E_NOTIMPL; +} + +#ifdef PAWIN_USE_DIRECTSOUNDFULLDUPLEXCREATE +static HRESULT WINAPI DummyDirectSoundFullDuplexCreate8( + LPCGUID pcGuidCaptureDevice, + LPCGUID pcGuidRenderDevice, + LPCDSCBUFFERDESC pcDSCBufferDesc, + LPCDSBUFFERDESC pcDSBufferDesc, + HWND hWnd, + DWORD dwLevel, + LPDIRECTSOUNDFULLDUPLEX * ppDSFD, + LPDIRECTSOUNDCAPTUREBUFFER8 * ppDSCBuffer8, + LPDIRECTSOUNDBUFFER8 * ppDSBuffer8, + LPUNKNOWN pUnkOuter) +{ + (void)pcGuidCaptureDevice; /* unused parameter */ + (void)pcGuidRenderDevice; /* unused parameter */ + (void)pcDSCBufferDesc; /* unused parameter */ + (void)pcDSBufferDesc; /* unused parameter */ + (void)hWnd; /* unused parameter */ + (void)dwLevel; /* unused parameter */ + (void)ppDSFD; /* unused parameter */ + (void)ppDSCBuffer8; /* unused parameter */ + (void)ppDSBuffer8; /* unused parameter */ + (void)pUnkOuter; /* unused parameter */ + + return E_NOTIMPL; +} +#endif /* PAWIN_USE_DIRECTSOUNDFULLDUPLEXCREATE */ + +void PaWinDs_InitializeDSoundEntryPoints(void) +{ + paWinDsDSoundEntryPoints.hInstance_ = LoadLibraryA("dsound.dll"); + if( paWinDsDSoundEntryPoints.hInstance_ != NULL ) + { + paWinDsDSoundEntryPoints.DllGetClassObject = + (HRESULT (WINAPI *)(REFCLSID, REFIID , LPVOID *)) + GetProcAddress( paWinDsDSoundEntryPoints.hInstance_, "DllGetClassObject" ); + if( paWinDsDSoundEntryPoints.DllGetClassObject == NULL ) + paWinDsDSoundEntryPoints.DllGetClassObject = DummyDllGetClassObject; + + paWinDsDSoundEntryPoints.DirectSoundCreate = + (HRESULT (WINAPI *)(LPGUID, LPDIRECTSOUND *, LPUNKNOWN)) + GetProcAddress( paWinDsDSoundEntryPoints.hInstance_, "DirectSoundCreate" ); + if( paWinDsDSoundEntryPoints.DirectSoundCreate == NULL ) + paWinDsDSoundEntryPoints.DirectSoundCreate = DummyDirectSoundCreate; + + paWinDsDSoundEntryPoints.DirectSoundEnumerateW = + (HRESULT (WINAPI *)(LPDSENUMCALLBACKW, LPVOID)) + GetProcAddress( paWinDsDSoundEntryPoints.hInstance_, "DirectSoundEnumerateW" ); + if( paWinDsDSoundEntryPoints.DirectSoundEnumerateW == NULL ) + paWinDsDSoundEntryPoints.DirectSoundEnumerateW = DummyDirectSoundEnumerateW; + + paWinDsDSoundEntryPoints.DirectSoundEnumerateA = + (HRESULT (WINAPI *)(LPDSENUMCALLBACKA, LPVOID)) + GetProcAddress( paWinDsDSoundEntryPoints.hInstance_, "DirectSoundEnumerateA" ); + if( paWinDsDSoundEntryPoints.DirectSoundEnumerateA == NULL ) + paWinDsDSoundEntryPoints.DirectSoundEnumerateA = DummyDirectSoundEnumerateA; + + paWinDsDSoundEntryPoints.DirectSoundCaptureCreate = + (HRESULT (WINAPI *)(LPGUID, LPDIRECTSOUNDCAPTURE *, LPUNKNOWN)) + GetProcAddress( paWinDsDSoundEntryPoints.hInstance_, "DirectSoundCaptureCreate" ); + if( paWinDsDSoundEntryPoints.DirectSoundCaptureCreate == NULL ) + paWinDsDSoundEntryPoints.DirectSoundCaptureCreate = DummyDirectSoundCaptureCreate; + + paWinDsDSoundEntryPoints.DirectSoundCaptureEnumerateW = + (HRESULT (WINAPI *)(LPDSENUMCALLBACKW, LPVOID)) + GetProcAddress( paWinDsDSoundEntryPoints.hInstance_, "DirectSoundCaptureEnumerateW" ); + if( paWinDsDSoundEntryPoints.DirectSoundCaptureEnumerateW == NULL ) + paWinDsDSoundEntryPoints.DirectSoundCaptureEnumerateW = DummyDirectSoundCaptureEnumerateW; + + paWinDsDSoundEntryPoints.DirectSoundCaptureEnumerateA = + (HRESULT (WINAPI *)(LPDSENUMCALLBACKA, LPVOID)) + GetProcAddress( paWinDsDSoundEntryPoints.hInstance_, "DirectSoundCaptureEnumerateA" ); + if( paWinDsDSoundEntryPoints.DirectSoundCaptureEnumerateA == NULL ) + paWinDsDSoundEntryPoints.DirectSoundCaptureEnumerateA = DummyDirectSoundCaptureEnumerateA; + +#ifdef PAWIN_USE_DIRECTSOUNDFULLDUPLEXCREATE + paWinDsDSoundEntryPoints.DirectSoundFullDuplexCreate8 = + (HRESULT (WINAPI *)(LPCGUID, LPCGUID, LPCDSCBUFFERDESC, LPCDSBUFFERDESC, + HWND, DWORD, LPDIRECTSOUNDFULLDUPLEX *, LPDIRECTSOUNDCAPTUREBUFFER8 *, + LPDIRECTSOUNDBUFFER8 *, LPUNKNOWN)) + GetProcAddress( paWinDsDSoundEntryPoints.hInstance_, "DirectSoundFullDuplexCreate" ); + if( paWinDsDSoundEntryPoints.DirectSoundFullDuplexCreate8 == NULL ) + paWinDsDSoundEntryPoints.DirectSoundFullDuplexCreate8 = DummyDirectSoundFullDuplexCreate8; +#endif + } + else + { + DWORD errorCode = GetLastError(); // 126 (0x7E) == ERROR_MOD_NOT_FOUND + PA_DEBUG(("Couldn't load dsound.dll error code: %d \n",errorCode)); + + /* initialize with dummy entry points to make live easy when ds isn't present */ + paWinDsDSoundEntryPoints.DirectSoundCreate = DummyDirectSoundCreate; + paWinDsDSoundEntryPoints.DirectSoundEnumerateW = DummyDirectSoundEnumerateW; + paWinDsDSoundEntryPoints.DirectSoundEnumerateA = DummyDirectSoundEnumerateA; + paWinDsDSoundEntryPoints.DirectSoundCaptureCreate = DummyDirectSoundCaptureCreate; + paWinDsDSoundEntryPoints.DirectSoundCaptureEnumerateW = DummyDirectSoundCaptureEnumerateW; + paWinDsDSoundEntryPoints.DirectSoundCaptureEnumerateA = DummyDirectSoundCaptureEnumerateA; +#ifdef PAWIN_USE_DIRECTSOUNDFULLDUPLEXCREATE + paWinDsDSoundEntryPoints.DirectSoundFullDuplexCreate8 = DummyDirectSoundFullDuplexCreate8; +#endif + } +} + + +void PaWinDs_TerminateDSoundEntryPoints(void) +{ + if( paWinDsDSoundEntryPoints.hInstance_ != NULL ) + { + /* ensure that we crash reliably if the entry points arent initialised */ + paWinDsDSoundEntryPoints.DirectSoundCreate = 0; + paWinDsDSoundEntryPoints.DirectSoundEnumerateW = 0; + paWinDsDSoundEntryPoints.DirectSoundEnumerateA = 0; + paWinDsDSoundEntryPoints.DirectSoundCaptureCreate = 0; + paWinDsDSoundEntryPoints.DirectSoundCaptureEnumerateW = 0; + paWinDsDSoundEntryPoints.DirectSoundCaptureEnumerateA = 0; + + FreeLibrary( paWinDsDSoundEntryPoints.hInstance_ ); + paWinDsDSoundEntryPoints.hInstance_ = NULL; + } +} \ No newline at end of file diff --git a/extern/portaudio/src/hostapi/dsound/pa_win_ds_dynlink.h b/extern/portaudio/src/hostapi/dsound/pa_win_ds_dynlink.h new file mode 100644 index 0000000..fd6d8fe --- /dev/null +++ b/extern/portaudio/src/hostapi/dsound/pa_win_ds_dynlink.h @@ -0,0 +1,106 @@ +/* + * Interface for dynamically loading directsound and providing a dummy + * implementation if it isn't present. + * + * Author: Ross Bencina (some portions Phil Burk & Robert Marsanyi) + * + * For PortAudio Portable Real-Time Audio Library + * For more information see: http://www.portaudio.com + * Copyright (c) 1999-2006 Phil Burk, Robert Marsanyi and Ross Bencina + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +/** + @file + @ingroup hostapi_src +*/ + +#ifndef INCLUDED_PA_DSOUND_DYNLINK_H +#define INCLUDED_PA_DSOUND_DYNLINK_H + +/* on Borland compilers, WIN32 doesn't seem to be defined by default, which + breaks dsound.h. Adding the define here fixes the problem. - rossb. */ +#ifdef __BORLANDC__ +#if !defined(WIN32) +#define WIN32 +#endif +#endif + +/* + Use the earliest version of DX required, no need to polute the namespace +*/ +#ifdef PAWIN_USE_DIRECTSOUNDFULLDUPLEXCREATE +#define DIRECTSOUND_VERSION 0x0800 +#else +#define DIRECTSOUND_VERSION 0x0300 +#endif +#include + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + +typedef struct +{ + HINSTANCE hInstance_; + + HRESULT (WINAPI *DllGetClassObject)(REFCLSID , REFIID , LPVOID *); + + HRESULT (WINAPI *DirectSoundCreate)(LPGUID, LPDIRECTSOUND *, LPUNKNOWN); + HRESULT (WINAPI *DirectSoundEnumerateW)(LPDSENUMCALLBACKW, LPVOID); + HRESULT (WINAPI *DirectSoundEnumerateA)(LPDSENUMCALLBACKA, LPVOID); + + HRESULT (WINAPI *DirectSoundCaptureCreate)(LPGUID, LPDIRECTSOUNDCAPTURE *, LPUNKNOWN); + HRESULT (WINAPI *DirectSoundCaptureEnumerateW)(LPDSENUMCALLBACKW, LPVOID); + HRESULT (WINAPI *DirectSoundCaptureEnumerateA)(LPDSENUMCALLBACKA, LPVOID); + +#ifdef PAWIN_USE_DIRECTSOUNDFULLDUPLEXCREATE + HRESULT (WINAPI *DirectSoundFullDuplexCreate8)( + LPCGUID, LPCGUID, LPCDSCBUFFERDESC, LPCDSBUFFERDESC, + HWND, DWORD, LPDIRECTSOUNDFULLDUPLEX *, LPDIRECTSOUNDCAPTUREBUFFER8 *, + LPDIRECTSOUNDBUFFER8 *, LPUNKNOWN ); +#endif +}PaWinDsDSoundEntryPoints; + +extern PaWinDsDSoundEntryPoints paWinDsDSoundEntryPoints; + +void PaWinDs_InitializeDSoundEntryPoints(void); +void PaWinDs_TerminateDSoundEntryPoints(void); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* INCLUDED_PA_DSOUND_DYNLINK_H */ diff --git a/extern/portaudio/src/hostapi/jack/pa_jack.c b/extern/portaudio/src/hostapi/jack/pa_jack.c new file mode 100644 index 0000000..a800f8e --- /dev/null +++ b/extern/portaudio/src/hostapi/jack/pa_jack.c @@ -0,0 +1,1769 @@ +/* + * $Id$ + * PortAudio Portable Real-Time Audio Library + * Latest Version at: http://www.portaudio.com + * JACK Implementation by Joshua Haberman + * + * Copyright (c) 2004 Stefan Westerfeld + * Copyright (c) 2004 Arve Knudsen + * Copyright (c) 2002 Joshua Haberman + * + * Based on the Open Source API proposed by Ross Bencina + * Copyright (c) 1999-2002 Ross Bencina, Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +/** + @file + @ingroup hostapi_src +*/ + +#include +#include +#include +#include +#include +#include +#include +#include /* EBUSY */ +#include /* sig_atomic_t */ +#include +#include + +#include +#include + +#include "pa_util.h" +#include "pa_hostapi.h" +#include "pa_stream.h" +#include "pa_process.h" +#include "pa_allocation.h" +#include "pa_cpuload.h" +#include "pa_ringbuffer.h" +#include "pa_debugprint.h" + +static pthread_t mainThread_; +static char *jackErr_ = NULL; +static const char* clientName_ = "PortAudio"; + +#define STRINGIZE_HELPER(expr) #expr +#define STRINGIZE(expr) STRINGIZE_HELPER(expr) + +/* Check PaError */ +#define ENSURE_PA(expr) \ + do { \ + PaError paErr; \ + if( (paErr = (expr)) < paNoError ) \ + { \ + if( (paErr) == paUnanticipatedHostError && pthread_self() == mainThread_ ) \ + { \ + const char *err = jackErr_; \ + if (! err ) err = "unknown error"; \ + PaUtil_SetLastHostErrorInfo( paJACK, -1, err ); \ + } \ + PaUtil_DebugPrint(( "Expression '" #expr "' failed in '" __FILE__ "', line: " STRINGIZE( __LINE__ ) "\n" )); \ + result = paErr; \ + goto error; \ + } \ + } while( 0 ) + +#define UNLESS(expr, code) \ + do { \ + if( (expr) == 0 ) \ + { \ + if( (code) == paUnanticipatedHostError && pthread_self() == mainThread_ ) \ + { \ + const char *err = jackErr_; \ + if (!err) err = "unknown error"; \ + PaUtil_SetLastHostErrorInfo( paJACK, -1, err ); \ + } \ + PaUtil_DebugPrint(( "Expression '" #expr "' failed in '" __FILE__ "', line: " STRINGIZE( __LINE__ ) "\n" )); \ + result = (code); \ + goto error; \ + } \ + } while( 0 ) + +#define ASSERT_CALL(expr, success) \ + do { \ + int err = (expr); \ + assert( err == success ); \ + } while( 0 ) + +/* + * Functions that directly map to the PortAudio stream interface + */ + +static void Terminate( struct PaUtilHostApiRepresentation *hostApi ); +static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi, + const PaStreamParameters *inputParameters, + const PaStreamParameters *outputParameters, + double sampleRate ); +static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, + PaStream** s, + const PaStreamParameters *inputParameters, + const PaStreamParameters *outputParameters, + double sampleRate, + unsigned long framesPerBuffer, + PaStreamFlags streamFlags, + PaStreamCallback *streamCallback, + void *userData ); +static PaError CloseStream( PaStream* stream ); +static PaError StartStream( PaStream *stream ); +static PaError StopStream( PaStream *stream ); +static PaError AbortStream( PaStream *stream ); +static PaError IsStreamStopped( PaStream *s ); +static PaError IsStreamActive( PaStream *stream ); +/*static PaTime GetStreamInputLatency( PaStream *stream );*/ +/*static PaTime GetStreamOutputLatency( PaStream *stream );*/ +static PaTime GetStreamTime( PaStream *stream ); +static double GetStreamCpuLoad( PaStream* stream ); + + +/* + * Data specific to this API + */ + +struct PaJackStream; + +typedef struct +{ + PaUtilHostApiRepresentation commonHostApiRep; + PaUtilStreamInterface callbackStreamInterface; + PaUtilStreamInterface blockingStreamInterface; + + PaUtilAllocationGroup *deviceInfoMemory; + + jack_client_t *jack_client; + int jack_buffer_size; + PaHostApiIndex hostApiIndex; + + pthread_mutex_t mtx; + pthread_cond_t cond; + unsigned long inputBase, outputBase; + + /* For dealing with the process thread */ + volatile int xrun; /* Received xrun notification from JACK? */ + struct PaJackStream * volatile toAdd, * volatile toRemove; + struct PaJackStream *processQueue; + volatile sig_atomic_t jackIsDown; +} +PaJackHostApiRepresentation; + +/* PaJackStream - a stream data structure specifically for this implementation */ + +typedef struct PaJackStream +{ + PaUtilStreamRepresentation streamRepresentation; + PaUtilBufferProcessor bufferProcessor; + PaUtilCpuLoadMeasurer cpuLoadMeasurer; + PaJackHostApiRepresentation *hostApi; + + /* our input and output ports */ + jack_port_t **local_input_ports; + jack_port_t **local_output_ports; + + /* the input and output ports of the client we are connecting to */ + jack_port_t **remote_input_ports; + jack_port_t **remote_output_ports; + + int num_incoming_connections; + int num_outgoing_connections; + + jack_client_t *jack_client; + + /* The stream is running if it's still producing samples. + * The stream is active if samples it produced are still being heard. + */ + volatile sig_atomic_t is_running; + volatile sig_atomic_t is_active; + /* Used to signal processing thread that stream should start or stop, respectively */ + volatile sig_atomic_t doStart, doStop, doAbort; + + jack_nframes_t t0; + + PaUtilAllocationGroup *stream_memory; + + /* These are useful in the process callback */ + + int callbackResult; + int isSilenced; + int xrun; + + /* These are useful for the blocking API */ + + int isBlockingStream; + PaUtilRingBuffer inFIFO; + PaUtilRingBuffer outFIFO; + volatile sig_atomic_t data_available; + sem_t data_semaphore; + int bytesPerFrame; + int samplesPerFrame; + + struct PaJackStream *next; +} +PaJackStream; + +/* In calls to jack_get_ports() this filter expression is used instead of "" + * to prevent any other types (eg Midi ports etc) being listed */ +#define JACK_PORT_TYPE_FILTER "audio" + +#define TRUE 1 +#define FALSE 0 + +/* + * Functions specific to this API + */ + +static int JackCallback( jack_nframes_t frames, void *userData ); + + +/* + * + * Implementation + * + */ + +/* ---- blocking emulation layer ---- */ + +/* Allocate buffer. */ +static PaError BlockingInitFIFO( PaUtilRingBuffer *rbuf, long numFrames, long bytesPerFrame ) +{ + long numBytes = numFrames * bytesPerFrame; + char *buffer = (char *) malloc( numBytes ); + if( buffer == NULL ) return paInsufficientMemory; + memset( buffer, 0, numBytes ); + return (PaError) PaUtil_InitializeRingBuffer( rbuf, 1, numBytes, buffer ); +} + +/* Free buffer. */ +static PaError BlockingTermFIFO( PaUtilRingBuffer *rbuf ) +{ + if( rbuf->buffer ) free( rbuf->buffer ); + rbuf->buffer = NULL; + return paNoError; +} + +static int +BlockingCallback( const void *inputBuffer, + void *outputBuffer, + unsigned long framesPerBuffer, + const PaStreamCallbackTimeInfo* timeInfo, + PaStreamCallbackFlags statusFlags, + void *userData ) +{ + struct PaJackStream *stream = (PaJackStream *)userData; + long numBytes = stream->bytesPerFrame * framesPerBuffer; + + /* This may get called with NULL inputBuffer during initial setup. */ + if( inputBuffer != NULL ) + { + PaUtil_WriteRingBuffer( &stream->inFIFO, inputBuffer, numBytes ); + } + if( outputBuffer != NULL ) + { + int numRead = PaUtil_ReadRingBuffer( &stream->outFIFO, outputBuffer, numBytes ); + /* Zero out remainder of buffer if we run out of data. */ + memset( (char *)outputBuffer + numRead, 0, numBytes - numRead ); + } + + if( !stream->data_available ) + { + stream->data_available = 1; + sem_post( &stream->data_semaphore ); + } + return paContinue; +} + +static PaError +BlockingBegin( PaJackStream *stream, int minimum_buffer_size ) +{ + long doRead = 0; + long doWrite = 0; + PaError result = paNoError; + long numFrames; + + doRead = stream->local_input_ports != NULL; + doWrite = stream->local_output_ports != NULL; + /* */ + stream->samplesPerFrame = 2; + stream->bytesPerFrame = sizeof(float) * stream->samplesPerFrame; + /* */ + numFrames = 32; + while (numFrames < minimum_buffer_size) + numFrames *= 2; + + if( doRead ) + { + ENSURE_PA( BlockingInitFIFO( &stream->inFIFO, numFrames, stream->bytesPerFrame ) ); + } + if( doWrite ) + { + long numBytes; + + ENSURE_PA( BlockingInitFIFO( &stream->outFIFO, numFrames, stream->bytesPerFrame ) ); + + /* Make Write FIFO appear full initially. */ + numBytes = PaUtil_GetRingBufferWriteAvailable( &stream->outFIFO ); + PaUtil_AdvanceRingBufferWriteIndex( &stream->outFIFO, numBytes ); + } + + stream->data_available = 0; + sem_init( &stream->data_semaphore, 0, 0 ); + +error: + return result; +} + +static void +BlockingEnd( PaJackStream *stream ) +{ + BlockingTermFIFO( &stream->inFIFO ); + BlockingTermFIFO( &stream->outFIFO ); + + sem_destroy( &stream->data_semaphore ); +} + +static PaError BlockingReadStream( PaStream* s, void *data, unsigned long numFrames ) +{ + PaError result = paNoError; + PaJackStream *stream = (PaJackStream *)s; + + long bytesRead; + char *p = (char *) data; + long numBytes = stream->bytesPerFrame * numFrames; + while( numBytes > 0 ) + { + bytesRead = PaUtil_ReadRingBuffer( &stream->inFIFO, p, numBytes ); + numBytes -= bytesRead; + p += bytesRead; + if( numBytes > 0 ) + { + /* see write for an explanation */ + if( stream->data_available ) + stream->data_available = 0; + else + sem_wait( &stream->data_semaphore ); + } + } + + return result; +} + +static PaError BlockingWriteStream( PaStream* s, const void *data, unsigned long numFrames ) +{ + PaError result = paNoError; + PaJackStream *stream = (PaJackStream *)s; + long bytesWritten; + char *p = (char *) data; + long numBytes = stream->bytesPerFrame * numFrames; + while( numBytes > 0 ) + { + bytesWritten = PaUtil_WriteRingBuffer( &stream->outFIFO, p, numBytes ); + numBytes -= bytesWritten; + p += bytesWritten; + if( numBytes > 0 ) + { + /* we use the following algorithm: + * (1) write data + * (2) if some data didn't fit into the ringbuffer, set data_available to 0 + * to indicate to the audio that if space becomes available, we want to know + * (3) retry to write data (because it might be that between (1) and (2) + * new space in the buffer became available) + * (4) if this failed, we are sure that the buffer is really empty and + * we will definitely receive a notification when it becomes available + * thus we can safely sleep + * + * if the algorithm bailed out in step (3) before, it leaks a count of 1 + * on the semaphore; however, it doesn't matter, because if we block in (4), + * we also do it in a loop + */ + if( stream->data_available ) + stream->data_available = 0; + else + sem_wait( &stream->data_semaphore ); + } + } + + return result; +} + +static signed long +BlockingGetStreamReadAvailable( PaStream* s ) +{ + PaJackStream *stream = (PaJackStream *)s; + + int bytesFull = PaUtil_GetRingBufferReadAvailable( &stream->inFIFO ); + return bytesFull / stream->bytesPerFrame; +} + +static signed long +BlockingGetStreamWriteAvailable( PaStream* s ) +{ + PaJackStream *stream = (PaJackStream *)s; + + int bytesEmpty = PaUtil_GetRingBufferWriteAvailable( &stream->outFIFO ); + return bytesEmpty / stream->bytesPerFrame; +} + +static PaError +BlockingWaitEmpty( PaStream *s ) +{ + PaJackStream *stream = (PaJackStream *)s; + + while( PaUtil_GetRingBufferReadAvailable( &stream->outFIFO ) > 0 ) + { + stream->data_available = 0; + sem_wait( &stream->data_semaphore ); + } + return 0; +} + +/* ---- jack driver ---- */ + +/* BuildDeviceList(): + * + * The process of determining a list of PortAudio "devices" from + * JACK's client/port system is fairly involved, so it is separated + * into its own routine. + */ + +static PaError BuildDeviceList( PaJackHostApiRepresentation *jackApi ) +{ + /* Utility macros for the repetitive process of allocating memory */ + + /* JACK has no concept of a device. To JACK, there are clients + * which have an arbitrary number of ports. To make this + * intelligible to PortAudio clients, we will group each JACK client + * into a device, and make each port of that client a channel */ + + PaError result = paNoError; + PaUtilHostApiRepresentation *commonApi = &jackApi->commonHostApiRep; + + const char **jack_ports = NULL; + char **client_names = NULL; + char *regex_pattern = NULL; + int port_index, client_index, i; + double globalSampleRate; + regex_t port_regex; + unsigned long numClients = 0, numPorts = 0; + char *tmp_client_name = NULL; + + commonApi->info.defaultInputDevice = paNoDevice; + commonApi->info.defaultOutputDevice = paNoDevice; + commonApi->info.deviceCount = 0; + + /* Parse the list of ports, using a regex to grab the client names */ + ASSERT_CALL( regcomp( &port_regex, "^[^:]*", REG_EXTENDED ), 0 ); + + /* since we are rebuilding the list of devices, free all memory + * associated with the previous list */ + PaUtil_FreeAllAllocations( jackApi->deviceInfoMemory ); + + regex_pattern = PaUtil_GroupAllocateMemory( jackApi->deviceInfoMemory, jack_client_name_size() + 3 ); + tmp_client_name = PaUtil_GroupAllocateMemory( jackApi->deviceInfoMemory, jack_client_name_size() ); + + /* We can only retrieve the list of clients indirectly, by first + * asking for a list of all ports, then parsing the port names + * according to the client_name:port_name convention (which is + * enforced by jackd) + * A: If jack_get_ports returns NULL, there's nothing for us to do */ + UNLESS( (jack_ports = jack_get_ports( jackApi->jack_client, "", JACK_PORT_TYPE_FILTER, 0 )) && jack_ports[0], paNoError ); + /* Find number of ports */ + while( jack_ports[numPorts] ) + ++numPorts; + /* At least there will be one port per client :) */ + UNLESS( client_names = PaUtil_GroupAllocateMemory( jackApi->deviceInfoMemory, numPorts * + sizeof (char *) ), paInsufficientMemory ); + + /* Build a list of clients from the list of ports */ + for( numClients = 0, port_index = 0; jack_ports[port_index] != NULL; port_index++ ) + { + int client_seen = FALSE; + regmatch_t match_info; + const char *port = jack_ports[port_index]; + + /* extract the client name from the port name, using a regex + * that parses the clientname:portname syntax */ + UNLESS( !regexec( &port_regex, port, 1, &match_info, 0 ), paInternalError ); + assert(match_info.rm_eo - match_info.rm_so < jack_client_name_size()); + memcpy( tmp_client_name, port + match_info.rm_so, + match_info.rm_eo - match_info.rm_so ); + tmp_client_name[match_info.rm_eo - match_info.rm_so] = '\0'; + + /* do we know about this port's client yet? */ + for( i = 0; i < numClients; i++ ) + { + if( strcmp( tmp_client_name, client_names[i] ) == 0 ) + client_seen = TRUE; + } + + if (client_seen) + continue; /* A: Nothing to see here, move along */ + + UNLESS( client_names[numClients] = (char*)PaUtil_GroupAllocateMemory( jackApi->deviceInfoMemory, + strlen(tmp_client_name) + 1), paInsufficientMemory ); + + /* The alsa_pcm client should go in spot 0. If this + * is the alsa_pcm client AND we are NOT about to put + * it in spot 0 put it in spot 0 and move whatever + * was already in spot 0 to the end. */ + if( strcmp( "alsa_pcm", tmp_client_name ) == 0 && numClients > 0 ) + { + /* alsa_pcm goes in spot 0 */ + strcpy( client_names[ numClients ], client_names[0] ); + strcpy( client_names[0], tmp_client_name ); + } + else + { + /* put the new client at the end of the client list */ + strcpy( client_names[ numClients ], tmp_client_name ); + } + ++numClients; + } + + /* Now we have a list of clients, which will become the list of + * PortAudio devices. */ + + /* there is one global sample rate all clients must conform to */ + + globalSampleRate = jack_get_sample_rate( jackApi->jack_client ); + UNLESS( commonApi->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory( jackApi->deviceInfoMemory, + sizeof(PaDeviceInfo*) * numClients ), paInsufficientMemory ); + + assert( commonApi->info.deviceCount == 0 ); + + /* Create a PaDeviceInfo structure for every client */ + for( client_index = 0; client_index < numClients; client_index++ ) + { + PaDeviceInfo *curDevInfo; + const char **clientPorts = NULL; + + UNLESS( curDevInfo = (PaDeviceInfo*)PaUtil_GroupAllocateMemory( jackApi->deviceInfoMemory, + sizeof(PaDeviceInfo) ), paInsufficientMemory ); + UNLESS( curDevInfo->name = (char*)PaUtil_GroupAllocateMemory( jackApi->deviceInfoMemory, + strlen(client_names[client_index]) + 1 ), paInsufficientMemory ); + strcpy( (char *)curDevInfo->name, client_names[client_index] ); + + curDevInfo->structVersion = 2; + curDevInfo->hostApi = jackApi->hostApiIndex; + + /* JACK is very inflexible: there is one sample rate the whole + * system must run at, and all clients must speak IEEE float. */ + curDevInfo->defaultSampleRate = globalSampleRate; + + /* To determine how many input and output channels are available, + * we re-query jackd with more specific parameters. */ + + sprintf( regex_pattern, "%s:.*", client_names[client_index] ); + + /* ... what are your output ports (that we could input from)? */ + clientPorts = jack_get_ports( jackApi->jack_client, regex_pattern, + JACK_PORT_TYPE_FILTER, JackPortIsOutput); + curDevInfo->maxInputChannels = 0; + curDevInfo->defaultLowInputLatency = 0.; + curDevInfo->defaultHighInputLatency = 0.; + if( clientPorts ) + { + jack_port_t *p = jack_port_by_name( jackApi->jack_client, clientPorts[0] ); + curDevInfo->defaultLowInputLatency = curDevInfo->defaultHighInputLatency = + jack_port_get_latency( p ) / globalSampleRate; + + for( i = 0; clientPorts[i] != NULL; i++) + { + /* The number of ports returned is the number of output channels. + * We don't care what they are, we just care how many */ + curDevInfo->maxInputChannels++; + } + free(clientPorts); + } + + /* ... what are your input ports (that we could output to)? */ + clientPorts = jack_get_ports( jackApi->jack_client, regex_pattern, + JACK_PORT_TYPE_FILTER, JackPortIsInput); + curDevInfo->maxOutputChannels = 0; + curDevInfo->defaultLowOutputLatency = 0.; + curDevInfo->defaultHighOutputLatency = 0.; + if( clientPorts ) + { + jack_port_t *p = jack_port_by_name( jackApi->jack_client, clientPorts[0] ); + curDevInfo->defaultLowOutputLatency = curDevInfo->defaultHighOutputLatency = + jack_port_get_latency( p ) / globalSampleRate; + + for( i = 0; clientPorts[i] != NULL; i++) + { + /* The number of ports returned is the number of input channels. + * We don't care what they are, we just care how many */ + curDevInfo->maxOutputChannels++; + } + free(clientPorts); + } + + /* Add this client to the list of devices */ + commonApi->deviceInfos[client_index] = curDevInfo; + ++commonApi->info.deviceCount; + if( commonApi->info.defaultInputDevice == paNoDevice && curDevInfo->maxInputChannels > 0 ) + commonApi->info.defaultInputDevice = client_index; + if( commonApi->info.defaultOutputDevice == paNoDevice && curDevInfo->maxOutputChannels > 0 ) + commonApi->info.defaultOutputDevice = client_index; + } + +error: + regfree( &port_regex ); + free( jack_ports ); + return result; +} + +static void UpdateSampleRate( PaJackStream *stream, double sampleRate ) +{ + /* XXX: Maybe not the cleanest way of going about this? */ + stream->cpuLoadMeasurer.samplingPeriod = stream->bufferProcessor.samplePeriod = 1. / sampleRate; + stream->streamRepresentation.streamInfo.sampleRate = sampleRate; +} + +static void JackErrorCallback( const char *msg ) +{ + if( pthread_self() == mainThread_ ) + { + assert( msg ); + jackErr_ = realloc( jackErr_, strlen( msg ) + 1 ); + strcpy( jackErr_, msg ); + } +} + +static void JackOnShutdown( void *arg ) +{ + PaJackHostApiRepresentation *jackApi = (PaJackHostApiRepresentation *)arg; + PaJackStream *stream = jackApi->processQueue; + + PA_DEBUG(( "%s: JACK server is shutting down\n", __FUNCTION__ )); + for( ; stream; stream = stream->next ) + { + stream->is_active = 0; + } + + /* Make sure that the main thread doesn't get stuck waiting on the condition */ + ASSERT_CALL( pthread_mutex_lock( &jackApi->mtx ), 0 ); + jackApi->jackIsDown = 1; + ASSERT_CALL( pthread_cond_signal( &jackApi->cond ), 0 ); + ASSERT_CALL( pthread_mutex_unlock( &jackApi->mtx ), 0 ); + +} + +static int JackSrCb( jack_nframes_t nframes, void *arg ) +{ + PaJackHostApiRepresentation *jackApi = (PaJackHostApiRepresentation *)arg; + double sampleRate = (double)nframes; + PaJackStream *stream = jackApi->processQueue; + + /* Update all streams in process queue */ + PA_DEBUG(( "%s: Acting on change in JACK samplerate: %f\n", __FUNCTION__, sampleRate )); + for( ; stream; stream = stream->next ) + { + if( stream->streamRepresentation.streamInfo.sampleRate != sampleRate ) + { + PA_DEBUG(( "%s: Updating samplerate\n", __FUNCTION__ )); + UpdateSampleRate( stream, sampleRate ); + } + } + + return 0; +} + +static int JackXRunCb(void *arg) { + PaJackHostApiRepresentation *hostApi = (PaJackHostApiRepresentation *)arg; + assert( hostApi ); + hostApi->xrun = TRUE; + PA_DEBUG(( "%s: JACK signalled xrun\n", __FUNCTION__ )); + return 0; +} + +PaError PaJack_Initialize( PaUtilHostApiRepresentation **hostApi, + PaHostApiIndex hostApiIndex ) +{ + PaError result = paNoError; + PaJackHostApiRepresentation *jackHostApi; + int activated = 0; + jack_status_t jackStatus = 0; + *hostApi = NULL; /* Initialize to NULL */ + + UNLESS( jackHostApi = (PaJackHostApiRepresentation*) + PaUtil_AllocateMemory( sizeof(PaJackHostApiRepresentation) ), paInsufficientMemory ); + UNLESS( jackHostApi->deviceInfoMemory = PaUtil_CreateAllocationGroup(), paInsufficientMemory ); + + mainThread_ = pthread_self(); + ASSERT_CALL( pthread_mutex_init( &jackHostApi->mtx, NULL ), 0 ); + ASSERT_CALL( pthread_cond_init( &jackHostApi->cond, NULL ), 0 ); + + /* Try to become a client of the JACK server. If we cannot do + * this, then this API cannot be used. + * + * Without the JackNoStartServer option, the jackd server is started + * automatically which we do not want. + */ + + jackHostApi->jack_client = jack_client_open( clientName_, JackNoStartServer, &jackStatus ); + if( !jackHostApi->jack_client ) + { + /* the V19 development docs say that if an implementation + * detects that it cannot be used, it should return a NULL + * interface and paNoError */ + PA_DEBUG(( "%s: Couldn't connect to JACK, status: %d\n", __FUNCTION__, jackStatus )); + result = paNoError; + goto error; + } + + jackHostApi->hostApiIndex = hostApiIndex; + + *hostApi = &jackHostApi->commonHostApiRep; + (*hostApi)->info.structVersion = 1; + (*hostApi)->info.type = paJACK; + (*hostApi)->info.name = "JACK Audio Connection Kit"; + + /* Build a device list by querying the JACK server */ + ENSURE_PA( BuildDeviceList( jackHostApi ) ); + + /* Register functions */ + + (*hostApi)->Terminate = Terminate; + (*hostApi)->OpenStream = OpenStream; + (*hostApi)->IsFormatSupported = IsFormatSupported; + + PaUtil_InitializeStreamInterface( &jackHostApi->callbackStreamInterface, + CloseStream, StartStream, + StopStream, AbortStream, + IsStreamStopped, IsStreamActive, + GetStreamTime, GetStreamCpuLoad, + PaUtil_DummyRead, PaUtil_DummyWrite, + PaUtil_DummyGetReadAvailable, + PaUtil_DummyGetWriteAvailable ); + + PaUtil_InitializeStreamInterface( &jackHostApi->blockingStreamInterface, CloseStream, StartStream, + StopStream, AbortStream, IsStreamStopped, IsStreamActive, + GetStreamTime, PaUtil_DummyGetCpuLoad, + BlockingReadStream, BlockingWriteStream, + BlockingGetStreamReadAvailable, BlockingGetStreamWriteAvailable ); + + jackHostApi->inputBase = jackHostApi->outputBase = 0; + jackHostApi->xrun = 0; + jackHostApi->toAdd = jackHostApi->toRemove = NULL; + jackHostApi->processQueue = NULL; + jackHostApi->jackIsDown = 0; + + jack_on_shutdown( jackHostApi->jack_client, JackOnShutdown, jackHostApi ); + jack_set_error_function( JackErrorCallback ); + jackHostApi->jack_buffer_size = jack_get_buffer_size ( jackHostApi->jack_client ); + /* Don't check for error, may not be supported (deprecated in at least jackdmp) */ + jack_set_sample_rate_callback( jackHostApi->jack_client, JackSrCb, jackHostApi ); + UNLESS( !jack_set_xrun_callback( jackHostApi->jack_client, JackXRunCb, jackHostApi ), paUnanticipatedHostError ); + UNLESS( !jack_set_process_callback( jackHostApi->jack_client, JackCallback, jackHostApi ), paUnanticipatedHostError ); + UNLESS( !jack_activate( jackHostApi->jack_client ), paUnanticipatedHostError ); + activated = 1; + + return result; + +error: + if( activated ) + ASSERT_CALL( jack_deactivate( jackHostApi->jack_client ), 0 ); + + if( jackHostApi ) + { + if( jackHostApi->jack_client ) + ASSERT_CALL( jack_client_close( jackHostApi->jack_client ), 0 ); + + if( jackHostApi->deviceInfoMemory ) + { + PaUtil_FreeAllAllocations( jackHostApi->deviceInfoMemory ); + PaUtil_DestroyAllocationGroup( jackHostApi->deviceInfoMemory ); + } + + PaUtil_FreeMemory( jackHostApi ); + } + return result; +} + + +static void Terminate( struct PaUtilHostApiRepresentation *hostApi ) +{ + PaJackHostApiRepresentation *jackHostApi = (PaJackHostApiRepresentation*)hostApi; + + /* note: this automatically disconnects all ports, since a deactivated + * client is not allowed to have any ports connected */ + ASSERT_CALL( jack_deactivate( jackHostApi->jack_client ), 0 ); + + ASSERT_CALL( pthread_mutex_destroy( &jackHostApi->mtx ), 0 ); + ASSERT_CALL( pthread_cond_destroy( &jackHostApi->cond ), 0 ); + + ASSERT_CALL( jack_client_close( jackHostApi->jack_client ), 0 ); + + if( jackHostApi->deviceInfoMemory ) + { + PaUtil_FreeAllAllocations( jackHostApi->deviceInfoMemory ); + PaUtil_DestroyAllocationGroup( jackHostApi->deviceInfoMemory ); + } + + PaUtil_FreeMemory( jackHostApi ); + + free( jackErr_ ); + jackErr_ = NULL; +} + +static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi, + const PaStreamParameters *inputParameters, + const PaStreamParameters *outputParameters, + double sampleRate ) +{ + int inputChannelCount = 0, outputChannelCount = 0; + PaSampleFormat inputSampleFormat, outputSampleFormat; + + if( inputParameters ) + { + inputChannelCount = inputParameters->channelCount; + inputSampleFormat = inputParameters->sampleFormat; + + /* unless alternate device specification is supported, reject the use of + paUseHostApiSpecificDeviceSpecification */ + + if( inputParameters->device == paUseHostApiSpecificDeviceSpecification ) + return paInvalidDevice; + + /* check that input device can support inputChannelCount */ + if( inputChannelCount > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels ) + return paInvalidChannelCount; + + /* validate inputStreamInfo */ + if( inputParameters->hostApiSpecificStreamInfo ) + return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */ + } + else + { + inputChannelCount = 0; + } + + if( outputParameters ) + { + outputChannelCount = outputParameters->channelCount; + outputSampleFormat = outputParameters->sampleFormat; + + /* unless alternate device specification is supported, reject the use of + paUseHostApiSpecificDeviceSpecification */ + + if( outputParameters->device == paUseHostApiSpecificDeviceSpecification ) + return paInvalidDevice; + + /* check that output device can support inputChannelCount */ + if( outputChannelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels ) + return paInvalidChannelCount; + + /* validate outputStreamInfo */ + if( outputParameters->hostApiSpecificStreamInfo ) + return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */ + } + else + { + outputChannelCount = 0; + } + + /* + The following check is not necessary for JACK. + + - if a full duplex stream is requested, check that the combination + of input and output parameters is supported + + + Because the buffer adapter handles conversion between all standard + sample formats, the following checks are only required if paCustomFormat + is implemented, or under some other unusual conditions. + + - check that input device can support inputSampleFormat, or that + we have the capability to convert from outputSampleFormat to + a native format + + - check that output device can support outputSampleFormat, or that + we have the capability to convert from outputSampleFormat to + a native format + */ + + /* check that the device supports sampleRate */ + +#define ABS(x) ( (x) > 0 ? (x) : -(x) ) + if( ABS(sampleRate - jack_get_sample_rate(((PaJackHostApiRepresentation *) hostApi)->jack_client )) > 1 ) + return paInvalidSampleRate; +#undef ABS + + return paFormatIsSupported; +} + +/* Basic stream initialization */ +static PaError InitializeStream( PaJackStream *stream, PaJackHostApiRepresentation *hostApi, int numInputChannels, + int numOutputChannels ) +{ + PaError result = paNoError; + assert( stream ); + + memset( stream, 0, sizeof (PaJackStream) ); + UNLESS( stream->stream_memory = PaUtil_CreateAllocationGroup(), paInsufficientMemory ); + stream->jack_client = hostApi->jack_client; + stream->hostApi = hostApi; + + if( numInputChannels > 0 ) + { + UNLESS( stream->local_input_ports = + (jack_port_t**) PaUtil_GroupAllocateMemory( stream->stream_memory, sizeof(jack_port_t*) * numInputChannels ), + paInsufficientMemory ); + memset( stream->local_input_ports, 0, sizeof(jack_port_t*) * numInputChannels ); + UNLESS( stream->remote_output_ports = + (jack_port_t**) PaUtil_GroupAllocateMemory( stream->stream_memory, sizeof(jack_port_t*) * numInputChannels ), + paInsufficientMemory ); + memset( stream->remote_output_ports, 0, sizeof(jack_port_t*) * numInputChannels ); + } + if( numOutputChannels > 0 ) + { + UNLESS( stream->local_output_ports = + (jack_port_t**) PaUtil_GroupAllocateMemory( stream->stream_memory, sizeof(jack_port_t*) * numOutputChannels ), + paInsufficientMemory ); + memset( stream->local_output_ports, 0, sizeof(jack_port_t*) * numOutputChannels ); + UNLESS( stream->remote_input_ports = + (jack_port_t**) PaUtil_GroupAllocateMemory( stream->stream_memory, sizeof(jack_port_t*) * numOutputChannels ), + paInsufficientMemory ); + memset( stream->remote_input_ports, 0, sizeof(jack_port_t*) * numOutputChannels ); + } + + stream->num_incoming_connections = numInputChannels; + stream->num_outgoing_connections = numOutputChannels; + +error: + return result; +} + +/*! + * Free resources associated with stream, and eventually stream itself. + * + * Frees allocated memory, and closes opened pcms. + */ +static void CleanUpStream( PaJackStream *stream, int terminateStreamRepresentation, int terminateBufferProcessor ) +{ + int i; + assert( stream ); + + if( stream->isBlockingStream ) + BlockingEnd( stream ); + + for( i = 0; i < stream->num_incoming_connections; ++i ) + { + if( stream->local_input_ports[i] ) + ASSERT_CALL( jack_port_unregister( stream->jack_client, stream->local_input_ports[i] ), 0 ); + } + for( i = 0; i < stream->num_outgoing_connections; ++i ) + { + if( stream->local_output_ports[i] ) + ASSERT_CALL( jack_port_unregister( stream->jack_client, stream->local_output_ports[i] ), 0 ); + } + + if( terminateStreamRepresentation ) + PaUtil_TerminateStreamRepresentation( &stream->streamRepresentation ); + if( terminateBufferProcessor ) + PaUtil_TerminateBufferProcessor( &stream->bufferProcessor ); + + if( stream->stream_memory ) + { + PaUtil_FreeAllAllocations( stream->stream_memory ); + PaUtil_DestroyAllocationGroup( stream->stream_memory ); + } + PaUtil_FreeMemory( stream ); +} + +static PaError WaitCondition( PaJackHostApiRepresentation *hostApi ) +{ + PaError result = paNoError; + int err = 0; + PaTime pt = PaUtil_GetTime(); + struct timespec ts; + + ts.tv_sec = (time_t) floor( pt + 10 * 60 /* 10 minutes */ ); + ts.tv_nsec = (long) ((pt - floor( pt )) * 1000000000); + /* XXX: Best enclose in loop, in case of spurious wakeups? */ + err = pthread_cond_timedwait( &hostApi->cond, &hostApi->mtx, &ts ); + + /* Make sure we didn't time out */ + UNLESS( err != ETIMEDOUT, paTimedOut ); + UNLESS( !err, paInternalError ); + +error: + return result; +} + +static PaError AddStream( PaJackStream *stream ) +{ + PaError result = paNoError; + PaJackHostApiRepresentation *hostApi = stream->hostApi; + /* Add to queue of streams that should be processed */ + ASSERT_CALL( pthread_mutex_lock( &hostApi->mtx ), 0 ); + if( !hostApi->jackIsDown ) + { + hostApi->toAdd = stream; + /* Unlock mutex and await signal from processing thread */ + result = WaitCondition( stream->hostApi ); + } + ASSERT_CALL( pthread_mutex_unlock( &hostApi->mtx ), 0 ); + ENSURE_PA( result ); + + UNLESS( !hostApi->jackIsDown, paDeviceUnavailable ); + +error: + return result; +} + +/* Remove stream from processing queue */ +static PaError RemoveStream( PaJackStream *stream ) +{ + PaError result = paNoError; + PaJackHostApiRepresentation *hostApi = stream->hostApi; + + /* Add to queue over streams that should be processed */ + ASSERT_CALL( pthread_mutex_lock( &hostApi->mtx ), 0 ); + if( !hostApi->jackIsDown ) + { + hostApi->toRemove = stream; + /* Unlock mutex and await signal from processing thread */ + result = WaitCondition( stream->hostApi ); + } + ASSERT_CALL( pthread_mutex_unlock( &hostApi->mtx ), 0 ); + ENSURE_PA( result ); + +error: + return result; +} + +/* Add stream to JACK callback processing queue */ +static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, + PaStream** s, + const PaStreamParameters *inputParameters, + const PaStreamParameters *outputParameters, + double sampleRate, + unsigned long framesPerBuffer, + PaStreamFlags streamFlags, + PaStreamCallback *streamCallback, + void *userData ) +{ + PaError result = paNoError; + PaJackHostApiRepresentation *jackHostApi = (PaJackHostApiRepresentation*)hostApi; + PaJackStream *stream = NULL; + char *port_string = PaUtil_GroupAllocateMemory( jackHostApi->deviceInfoMemory, jack_port_name_size() ); + unsigned long regexSz = jack_client_name_size() + 3; + char *regex_pattern = PaUtil_GroupAllocateMemory( jackHostApi->deviceInfoMemory, regexSz ); + const char **jack_ports = NULL; + /* int jack_max_buffer_size = jack_get_buffer_size( jackHostApi->jack_client ); */ + int i; + int inputChannelCount, outputChannelCount; + const double jackSr = jack_get_sample_rate( jackHostApi->jack_client ); + PaSampleFormat inputSampleFormat = 0, outputSampleFormat = 0; + int bpInitialized = 0, srInitialized = 0; /* Initialized buffer processor and stream representation? */ + unsigned long ofs; + + /* validate platform specific flags */ + if( (streamFlags & paPlatformSpecificFlags) != 0 ) + return paInvalidFlag; /* unexpected platform specific flag */ + if( (streamFlags & paPrimeOutputBuffersUsingStreamCallback) != 0 ) + { + streamFlags &= ~paPrimeOutputBuffersUsingStreamCallback; + /*return paInvalidFlag;*/ /* This implementation does not support buffer priming */ + } + + if( framesPerBuffer != paFramesPerBufferUnspecified ) + { + /* Jack operates with power of two buffers, and we don't support non-integer buffer adaption (yet) */ + /*UNLESS( !(framesPerBuffer & (framesPerBuffer - 1)), paBufferTooBig );*/ /* TODO: Add descriptive error code? */ + } + + /* Preliminary checks */ + + if( inputParameters ) + { + inputChannelCount = inputParameters->channelCount; + inputSampleFormat = inputParameters->sampleFormat; + + /* unless alternate device specification is supported, reject the use of + paUseHostApiSpecificDeviceSpecification */ + + if( inputParameters->device == paUseHostApiSpecificDeviceSpecification ) + return paInvalidDevice; + + /* check that input device can support inputChannelCount */ + if( inputChannelCount > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels ) + return paInvalidChannelCount; + + /* validate inputStreamInfo */ + if( inputParameters->hostApiSpecificStreamInfo ) + return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */ + } + else + { + inputChannelCount = 0; + } + + if( outputParameters ) + { + outputChannelCount = outputParameters->channelCount; + outputSampleFormat = outputParameters->sampleFormat; + + /* unless alternate device specification is supported, reject the use of + paUseHostApiSpecificDeviceSpecification */ + + if( outputParameters->device == paUseHostApiSpecificDeviceSpecification ) + return paInvalidDevice; + + /* check that output device can support inputChannelCount */ + if( outputChannelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels ) + return paInvalidChannelCount; + + /* validate outputStreamInfo */ + if( outputParameters->hostApiSpecificStreamInfo ) + return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */ + } + else + { + outputChannelCount = 0; + } + + /* ... check that the sample rate exactly matches the ONE acceptable rate + * A: This rate isn't necessarily constant though? */ + +#define ABS(x) ( (x) > 0 ? (x) : -(x) ) + if( ABS(sampleRate - jackSr) > 1 ) + return paInvalidSampleRate; +#undef ABS + + UNLESS( stream = (PaJackStream*)PaUtil_AllocateMemory( sizeof(PaJackStream) ), paInsufficientMemory ); + ENSURE_PA( InitializeStream( stream, jackHostApi, inputChannelCount, outputChannelCount ) ); + + /* the blocking emulation, if necessary */ + stream->isBlockingStream = !streamCallback; + if( stream->isBlockingStream ) + { + float latency = 0.001; /* 1ms is the absolute minimum we support */ + int minimum_buffer_frames = 0; + + if( inputParameters && inputParameters->suggestedLatency > latency ) + latency = inputParameters->suggestedLatency; + else if( outputParameters && outputParameters->suggestedLatency > latency ) + latency = outputParameters->suggestedLatency; + + /* the latency the user asked for indicates the minimum buffer size in frames */ + minimum_buffer_frames = (int) (latency * jack_get_sample_rate( jackHostApi->jack_client )); + + /* we also need to be able to store at least three full jack buffers to avoid dropouts */ + if( jackHostApi->jack_buffer_size * 3 > minimum_buffer_frames ) + minimum_buffer_frames = jackHostApi->jack_buffer_size * 3; + + /* setup blocking API data structures (FIXME: can fail) */ + BlockingBegin( stream, minimum_buffer_frames ); + + /* install our own callback for the blocking API */ + streamCallback = BlockingCallback; + userData = stream; + + PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation, + &jackHostApi->blockingStreamInterface, streamCallback, userData ); + } + else + { + PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation, + &jackHostApi->callbackStreamInterface, streamCallback, userData ); + } + srInitialized = 1; + PaUtil_InitializeCpuLoadMeasurer( &stream->cpuLoadMeasurer, jackSr ); + + /* create the JACK ports. We cannot connect them until audio + * processing begins */ + + /* Register a unique set of ports for this stream + * TODO: Robust allocation of new port names */ + + ofs = jackHostApi->inputBase; + for( i = 0; i < inputChannelCount; i++ ) + { + snprintf( port_string, jack_port_name_size(), "in_%lu", ofs + i ); + UNLESS( stream->local_input_ports[i] = jack_port_register( + jackHostApi->jack_client, port_string, + JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0 ), paInsufficientMemory ); + } + jackHostApi->inputBase += inputChannelCount; + + ofs = jackHostApi->outputBase; + for( i = 0; i < outputChannelCount; i++ ) + { + snprintf( port_string, jack_port_name_size(), "out_%lu", ofs + i ); + UNLESS( stream->local_output_ports[i] = jack_port_register( + jackHostApi->jack_client, port_string, + JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0 ), paInsufficientMemory ); + } + jackHostApi->outputBase += outputChannelCount; + + /* look up the jack_port_t's for the remote ports. We could do + * this at stream start time, but doing it here ensures the + * name lookup only happens once. */ + + if( inputChannelCount > 0 ) + { + int err = 0; + + /* Get output ports of our capture device */ + snprintf( regex_pattern, regexSz, "%s:.*", hostApi->deviceInfos[ inputParameters->device ]->name ); + UNLESS( jack_ports = jack_get_ports( jackHostApi->jack_client, regex_pattern, + JACK_PORT_TYPE_FILTER, JackPortIsOutput ), paUnanticipatedHostError ); + for( i = 0; i < inputChannelCount && jack_ports[i]; i++ ) + { + if( (stream->remote_output_ports[i] = jack_port_by_name( + jackHostApi->jack_client, jack_ports[i] )) == NULL ) + { + err = 1; + break; + } + } + free( jack_ports ); + UNLESS( !err, paInsufficientMemory ); + + /* Fewer ports than expected? */ + UNLESS( i == inputChannelCount, paInternalError ); + } + + if( outputChannelCount > 0 ) + { + int err = 0; + + /* Get input ports of our playback device */ + snprintf( regex_pattern, regexSz, "%s:.*", hostApi->deviceInfos[ outputParameters->device ]->name ); + UNLESS( jack_ports = jack_get_ports( jackHostApi->jack_client, regex_pattern, + JACK_PORT_TYPE_FILTER, JackPortIsInput ), paUnanticipatedHostError ); + for( i = 0; i < outputChannelCount && jack_ports[i]; i++ ) + { + if( (stream->remote_input_ports[i] = jack_port_by_name( + jackHostApi->jack_client, jack_ports[i] )) == 0 ) + { + err = 1; + break; + } + } + free( jack_ports ); + UNLESS( !err , paInsufficientMemory ); + + /* Fewer ports than expected? */ + UNLESS( i == outputChannelCount, paInternalError ); + } + + ENSURE_PA( PaUtil_InitializeBufferProcessor( + &stream->bufferProcessor, + inputChannelCount, + inputSampleFormat, + paFloat32 | paNonInterleaved, /* hostInputSampleFormat */ + outputChannelCount, + outputSampleFormat, + paFloat32 | paNonInterleaved, /* hostOutputSampleFormat */ + jackSr, + streamFlags, + framesPerBuffer, + 0, /* Ignored */ + paUtilUnknownHostBufferSize, /* Buffer size may vary on JACK's discretion */ + streamCallback, + userData ) ); + bpInitialized = 1; + + if( stream->num_incoming_connections > 0 ) + stream->streamRepresentation.streamInfo.inputLatency = (jack_port_get_latency( stream->remote_output_ports[0] ) + - jack_get_buffer_size( jackHostApi->jack_client ) /* One buffer is not counted as latency */ + + PaUtil_GetBufferProcessorInputLatencyFrames( &stream->bufferProcessor )) / sampleRate; + if( stream->num_outgoing_connections > 0 ) + stream->streamRepresentation.streamInfo.outputLatency = (jack_port_get_latency( stream->remote_input_ports[0] ) + - jack_get_buffer_size( jackHostApi->jack_client ) /* One buffer is not counted as latency */ + + PaUtil_GetBufferProcessorOutputLatencyFrames( &stream->bufferProcessor )) / sampleRate; + + stream->streamRepresentation.streamInfo.sampleRate = jackSr; + stream->t0 = jack_frame_time( jackHostApi->jack_client ); /* A: Time should run from Pa_OpenStream */ + + /* Add to queue of opened streams */ + ENSURE_PA( AddStream( stream ) ); + + *s = (PaStream*)stream; + + return result; + +error: + if( stream ) + CleanUpStream( stream, srInitialized, bpInitialized ); + + return result; +} + +/* + When CloseStream() is called, the multi-api layer ensures that + the stream has already been stopped or aborted. +*/ +static PaError CloseStream( PaStream* s ) +{ + PaError result = paNoError; + PaJackStream *stream = (PaJackStream*)s; + + /* Remove this stream from the processing queue */ + ENSURE_PA( RemoveStream( stream ) ); + +error: + CleanUpStream( stream, 1, 1 ); + return result; +} + +static PaError RealProcess( PaJackStream *stream, jack_nframes_t frames ) +{ + PaError result = paNoError; + PaStreamCallbackTimeInfo timeInfo = {0,0,0}; + int chn; + int framesProcessed; + const double sr = jack_get_sample_rate( stream->jack_client ); /* Shouldn't change during the process callback */ + PaStreamCallbackFlags cbFlags = 0; + + /* If the user has returned !paContinue from the callback we'll want to flush the internal buffers, + * when these are empty we can finally mark the stream as inactive */ + if( stream->callbackResult != paContinue && + PaUtil_IsBufferProcessorOutputEmpty( &stream->bufferProcessor ) ) + { + stream->is_active = 0; + if( stream->streamRepresentation.streamFinishedCallback ) + stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData ); + PA_DEBUG(( "%s: Callback finished\n", __FUNCTION__ )); + + goto end; + } + + timeInfo.currentTime = (jack_frame_time( stream->jack_client ) - stream->t0) / sr; + if( stream->num_incoming_connections > 0 ) + timeInfo.inputBufferAdcTime = timeInfo.currentTime - jack_port_get_latency( stream->remote_output_ports[0] ) + / sr; + if( stream->num_outgoing_connections > 0 ) + timeInfo.outputBufferDacTime = timeInfo.currentTime + jack_port_get_latency( stream->remote_input_ports[0] ) + / sr; + + PaUtil_BeginCpuLoadMeasurement( &stream->cpuLoadMeasurer ); + + if( stream->xrun ) + { + /* XXX: Any way to tell which of these occurred? */ + cbFlags = paOutputUnderflow | paInputOverflow; + stream->xrun = FALSE; + } + PaUtil_BeginBufferProcessing( &stream->bufferProcessor, &timeInfo, + cbFlags ); + + if( stream->num_incoming_connections > 0 ) + PaUtil_SetInputFrameCount( &stream->bufferProcessor, frames ); + if( stream->num_outgoing_connections > 0 ) + PaUtil_SetOutputFrameCount( &stream->bufferProcessor, frames ); + + for( chn = 0; chn < stream->num_incoming_connections; chn++ ) + { + jack_default_audio_sample_t *channel_buf = (jack_default_audio_sample_t*) + jack_port_get_buffer( stream->local_input_ports[chn], + frames ); + + PaUtil_SetNonInterleavedInputChannel( &stream->bufferProcessor, + chn, + channel_buf ); + } + + for( chn = 0; chn < stream->num_outgoing_connections; chn++ ) + { + jack_default_audio_sample_t *channel_buf = (jack_default_audio_sample_t*) + jack_port_get_buffer( stream->local_output_ports[chn], + frames ); + + PaUtil_SetNonInterleavedOutputChannel( &stream->bufferProcessor, + chn, + channel_buf ); + } + + framesProcessed = PaUtil_EndBufferProcessing( &stream->bufferProcessor, + &stream->callbackResult ); + /* We've specified a host buffer size mode where every frame should be consumed by the buffer processor */ + assert( framesProcessed == frames ); + + PaUtil_EndCpuLoadMeasurement( &stream->cpuLoadMeasurer, framesProcessed ); + +end: + return result; +} + +/* Update the JACK callback's stream processing queue. */ +static PaError UpdateQueue( PaJackHostApiRepresentation *hostApi ) +{ + PaError result = paNoError; + int queueModified = 0; + const double jackSr = jack_get_sample_rate( hostApi->jack_client ); + int err; + + if( (err = pthread_mutex_trylock( &hostApi->mtx )) != 0 ) + { + assert( err == EBUSY ); + return paNoError; + } + + if( hostApi->toAdd ) + { + if( hostApi->processQueue ) + { + PaJackStream *node = hostApi->processQueue; + /* Advance to end of queue */ + while( node->next ) + node = node->next; + + node->next = hostApi->toAdd; + } + else + { + /* The only queue entry. */ + hostApi->processQueue = (PaJackStream *)hostApi->toAdd; + } + + /* If necessary, update stream state */ + if( hostApi->toAdd->streamRepresentation.streamInfo.sampleRate != jackSr ) + UpdateSampleRate( hostApi->toAdd, jackSr ); + + hostApi->toAdd = NULL; + queueModified = 1; + } + if( hostApi->toRemove ) + { + int removed = 0; + PaJackStream *node = hostApi->processQueue, *prev = NULL; + assert( hostApi->processQueue ); + + while( node ) + { + if( node == hostApi->toRemove ) + { + if( prev ) + prev->next = node->next; + else + hostApi->processQueue = (PaJackStream *)node->next; + + removed = 1; + break; + } + + prev = node; + node = node->next; + } + UNLESS( removed, paInternalError ); + hostApi->toRemove = NULL; + PA_DEBUG(( "%s: Removed stream from processing queue\n", __FUNCTION__ )); + queueModified = 1; + } + + if( queueModified ) + { + /* Signal that we've done what was asked of us */ + ASSERT_CALL( pthread_cond_signal( &hostApi->cond ), 0 ); + } + +error: + ASSERT_CALL( pthread_mutex_unlock( &hostApi->mtx ), 0 ); + + return result; +} + +/* Audio processing callback invoked periodically from JACK. */ +static int JackCallback( jack_nframes_t frames, void *userData ) +{ + PaError result = paNoError; + PaJackHostApiRepresentation *hostApi = (PaJackHostApiRepresentation *)userData; + PaJackStream *stream = NULL; + int xrun = hostApi->xrun; + hostApi->xrun = 0; + + assert( hostApi ); + + ENSURE_PA( UpdateQueue( hostApi ) ); + + /* Process each stream */ + stream = hostApi->processQueue; + for( ; stream; stream = stream->next ) + { + if( xrun ) /* Don't override if already set */ + stream->xrun = 1; + + /* See if this stream is to be started */ + if( stream->doStart ) + { + /* If we can't obtain a lock, we'll try next time */ + int err = pthread_mutex_trylock( &stream->hostApi->mtx ); + if( !err ) + { + if( stream->doStart ) /* Could potentially change before obtaining the lock */ + { + stream->is_active = 1; + stream->doStart = 0; + PA_DEBUG(( "%s: Starting stream\n", __FUNCTION__ )); + ASSERT_CALL( pthread_cond_signal( &stream->hostApi->cond ), 0 ); + stream->callbackResult = paContinue; + stream->isSilenced = 0; + } + + ASSERT_CALL( pthread_mutex_unlock( &stream->hostApi->mtx ), 0 ); + } + else + assert( err == EBUSY ); + } + else if( stream->doStop || stream->doAbort ) /* Should we stop/abort stream? */ + { + if( stream->callbackResult == paContinue ) /* Ok, make it stop */ + { + PA_DEBUG(( "%s: Stopping stream\n", __FUNCTION__ )); + stream->callbackResult = stream->doStop ? paComplete : paAbort; + } + } + + if( stream->is_active ) + ENSURE_PA( RealProcess( stream, frames ) ); + /* If we have just entered inactive state, silence output */ + if( !stream->is_active && !stream->isSilenced ) + { + int i; + + /* Silence buffer after entering inactive state */ + PA_DEBUG(( "Silencing the output\n" )); + for( i = 0; i < stream->num_outgoing_connections; ++i ) + { + jack_default_audio_sample_t *buffer = jack_port_get_buffer( stream->local_output_ports[i], frames ); + memset( buffer, 0, sizeof (jack_default_audio_sample_t) * frames ); + } + + stream->isSilenced = 1; + } + + if( stream->doStop || stream->doAbort ) + { + /* See if RealProcess has acted on the request */ + if( !stream->is_active ) /* Ok, signal to the main thread that we've carried out the operation */ + { + /* If we can't obtain a lock, we'll try next time */ + int err = pthread_mutex_trylock( &stream->hostApi->mtx ); + if( !err ) + { + stream->doStop = stream->doAbort = 0; + ASSERT_CALL( pthread_cond_signal( &stream->hostApi->cond ), 0 ); + ASSERT_CALL( pthread_mutex_unlock( &stream->hostApi->mtx ), 0 ); + } + else + assert( err == EBUSY ); + } + } + } + + return 0; +error: + return -1; +} + +static PaError StartStream( PaStream *s ) +{ + PaError result = paNoError; + PaJackStream *stream = (PaJackStream*)s; + int i; + + /* Ready the processor */ + PaUtil_ResetBufferProcessor( &stream->bufferProcessor ); + + /* Connect the ports. Note that the ports may already have been connected by someone else in + * the meantime, in which case JACK returns EEXIST. */ + + if( stream->num_incoming_connections > 0 ) + { + for( i = 0; i < stream->num_incoming_connections; i++ ) + { + int r = jack_connect( stream->jack_client, jack_port_name( stream->remote_output_ports[i] ), + jack_port_name( stream->local_input_ports[i] ) ); + UNLESS( 0 == r || EEXIST == r, paUnanticipatedHostError ); + } + } + + if( stream->num_outgoing_connections > 0 ) + { + for( i = 0; i < stream->num_outgoing_connections; i++ ) + { + int r = jack_connect( stream->jack_client, jack_port_name( stream->local_output_ports[i] ), + jack_port_name( stream->remote_input_ports[i] ) ); + UNLESS( 0 == r || EEXIST == r, paUnanticipatedHostError ); + } + } + + stream->xrun = FALSE; + + /* Enable processing */ + + ASSERT_CALL( pthread_mutex_lock( &stream->hostApi->mtx ), 0 ); + stream->doStart = 1; + + /* Wait for stream to be started */ + result = WaitCondition( stream->hostApi ); + /* + do + { + err = pthread_cond_timedwait( &stream->hostApi->cond, &stream->hostApi->mtx, &ts ); + } while( !stream->is_active && !err ); + */ + if( result != paNoError ) /* Something went wrong, call off the stream start */ + { + stream->doStart = 0; + stream->is_active = 0; /* Cancel any processing */ + } + ASSERT_CALL( pthread_mutex_unlock( &stream->hostApi->mtx ), 0 ); + + ENSURE_PA( result ); + + stream->is_running = TRUE; + PA_DEBUG(( "%s: Stream started\n", __FUNCTION__ )); + +error: + return result; +} + +static PaError RealStop( PaJackStream *stream, int abort ) +{ + PaError result = paNoError; + int i; + + if( stream->isBlockingStream ) + BlockingWaitEmpty ( stream ); + + ASSERT_CALL( pthread_mutex_lock( &stream->hostApi->mtx ), 0 ); + if( abort ) + stream->doAbort = 1; + else + stream->doStop = 1; + + /* Wait for stream to be stopped */ + result = WaitCondition( stream->hostApi ); + ASSERT_CALL( pthread_mutex_unlock( &stream->hostApi->mtx ), 0 ); + ENSURE_PA( result ); + + UNLESS( !stream->is_active, paInternalError ); + + PA_DEBUG(( "%s: Stream stopped\n", __FUNCTION__ )); + +error: + stream->is_running = FALSE; + + /* Disconnect ports belonging to this stream */ + + if( !stream->hostApi->jackIsDown ) /* XXX: Well? */ + { + for( i = 0; i < stream->num_incoming_connections; i++ ) + { + if( jack_port_connected( stream->local_input_ports[i] ) ) + { + UNLESS( !jack_port_disconnect( stream->jack_client, stream->local_input_ports[i] ), + paUnanticipatedHostError ); + } + } + for( i = 0; i < stream->num_outgoing_connections; i++ ) + { + if( jack_port_connected( stream->local_output_ports[i] ) ) + { + UNLESS( !jack_port_disconnect( stream->jack_client, stream->local_output_ports[i] ), + paUnanticipatedHostError ); + } + } + } + + return result; +} + +static PaError StopStream( PaStream *s ) +{ + assert(s); + return RealStop( (PaJackStream *)s, 0 ); +} + +static PaError AbortStream( PaStream *s ) +{ + assert(s); + return RealStop( (PaJackStream *)s, 1 ); +} + +static PaError IsStreamStopped( PaStream *s ) +{ + PaJackStream *stream = (PaJackStream*)s; + return !stream->is_running; +} + + +static PaError IsStreamActive( PaStream *s ) +{ + PaJackStream *stream = (PaJackStream*)s; + return stream->is_active; +} + + +static PaTime GetStreamTime( PaStream *s ) +{ + PaJackStream *stream = (PaJackStream*)s; + + /* A: Is this relevant?? --> TODO: what if we're recording-only? */ + return (jack_frame_time( stream->jack_client ) - stream->t0) / (PaTime)jack_get_sample_rate( stream->jack_client ); +} + + +static double GetStreamCpuLoad( PaStream* s ) +{ + PaJackStream *stream = (PaJackStream*)s; + return PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer ); +} + +PaError PaJack_SetClientName( const char* name ) +{ + if( strlen( name ) > jack_client_name_size() ) + { + /* OK, I don't know any better error code */ + return paInvalidFlag; + } + clientName_ = name; + return paNoError; +} + +PaError PaJack_GetClientName(const char** clientName) +{ + PaError result = paNoError; + PaJackHostApiRepresentation* jackHostApi = NULL; + PaJackHostApiRepresentation** ref = &jackHostApi; + ENSURE_PA( PaUtil_GetHostApiRepresentation( (PaUtilHostApiRepresentation**)ref, paJACK ) ); + *clientName = jack_get_client_name( jackHostApi->jack_client ); + +error: + return result; +} diff --git a/extern/portaudio/src/hostapi/oss/low_latency_tip.txt b/extern/portaudio/src/hostapi/oss/low_latency_tip.txt new file mode 100644 index 0000000..2d982b7 Binary files /dev/null and b/extern/portaudio/src/hostapi/oss/low_latency_tip.txt differ diff --git a/extern/portaudio/src/hostapi/oss/pa_unix_oss.c b/extern/portaudio/src/hostapi/oss/pa_unix_oss.c new file mode 100644 index 0000000..51e9630 --- /dev/null +++ b/extern/portaudio/src/hostapi/oss/pa_unix_oss.c @@ -0,0 +1,2045 @@ +/* + * $Id$ + * PortAudio Portable Real-Time Audio Library + * Latest Version at: http://www.portaudio.com + * OSS implementation by: + * Douglas Repetto + * Phil Burk + * Dominic Mazzoni + * Arve Knudsen + * + * Based on the Open Source API proposed by Ross Bencina + * Copyright (c) 1999-2002 Ross Bencina, Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +/** + @file + @ingroup hostapi_src +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_SYS_SOUNDCARD_H +# include +# ifdef __NetBSD__ +# define DEVICE_NAME_BASE "/dev/audio" +# else +# define DEVICE_NAME_BASE "/dev/dsp" +# endif +#elif defined(HAVE_LINUX_SOUNDCARD_H) +# include +# define DEVICE_NAME_BASE "/dev/dsp" +#elif defined(HAVE_MACHINE_SOUNDCARD_H) +# include /* JH20010905 */ +# define DEVICE_NAME_BASE "/dev/audio" +#else +# error No sound card header file +#endif + +#include "portaudio.h" +#include "pa_util.h" +#include "pa_allocation.h" +#include "pa_hostapi.h" +#include "pa_stream.h" +#include "pa_cpuload.h" +#include "pa_process.h" +#include "pa_unix_util.h" +#include "pa_debugprint.h" + +static int sysErr_; +static pthread_t mainThread_; + +/* Check return value of system call, and map it to PaError */ +#define ENSURE_(expr, code) \ + do { \ + if( UNLIKELY( (sysErr_ = (expr)) < 0 ) ) \ + { \ + /* PaUtil_SetLastHostErrorInfo should only be used in the main thread */ \ + if( (code) == paUnanticipatedHostError && pthread_self() == mainThread_ ) \ + { \ + PaUtil_SetLastHostErrorInfo( paOSS, sysErr_, strerror( errno ) ); \ + } \ + \ + PaUtil_DebugPrint(( "Expression '" #expr "' failed in '" __FILE__ "', line: " STRINGIZE( __LINE__ ) "\n" )); \ + result = (code); \ + goto error; \ + } \ + } while( 0 ); + +#ifndef AFMT_S16_NE +#define AFMT_S16_NE Get_AFMT_S16_NE() +/********************************************************************* + * Some versions of OSS do not define AFMT_S16_NE. So check CPU. + * PowerPC is Big Endian. X86 is Little Endian. + */ +static int Get_AFMT_S16_NE( void ) +{ + long testData = 1; + char *ptr = (char *) &testData; + int isLittle = ( *ptr == 1 ); /* Does address point to least significant byte? */ + return isLittle ? AFMT_S16_LE : AFMT_S16_BE; +} +#endif + +/* PaOSSHostApiRepresentation - host api datastructure specific to this implementation */ + +typedef struct +{ + PaUtilHostApiRepresentation inheritedHostApiRep; + PaUtilStreamInterface callbackStreamInterface; + PaUtilStreamInterface blockingStreamInterface; + + PaUtilAllocationGroup *allocations; + + PaHostApiIndex hostApiIndex; +} +PaOSSHostApiRepresentation; + +/** Per-direction structure for PaOssStream. + * + * Aspect StreamChannels: In case the user requests to open the same device for both capture and playback, + * but with different number of channels we will have to adapt between the number of user and host + * channels for at least one direction, since the configuration space is the same for both directions + * of an OSS device. + */ +typedef struct +{ + int fd; + const char *devName; + int userChannelCount, hostChannelCount; + int userInterleaved; + void *buffer; + PaSampleFormat userFormat, hostFormat; + double latency; + unsigned long hostFrames, numBufs; + void **userBuffers; /* For non-interleaved blocking */ +} PaOssStreamComponent; + +/** Implementation specific representation of a PaStream. + * + */ +typedef struct PaOssStream +{ + PaUtilStreamRepresentation streamRepresentation; + PaUtilCpuLoadMeasurer cpuLoadMeasurer; + PaUtilBufferProcessor bufferProcessor; + + PaUtilThreading threading; + + int sharedDevice; + unsigned long framesPerHostBuffer; + int triggered; /* Have the devices been triggered yet (first start) */ + + int isActive; + int isStopped; + + int lastPosPtr; + double lastStreamBytes; + + int framesProcessed; + + double sampleRate; + + int callbackMode; + volatile int callbackStop, callbackAbort; + + PaOssStreamComponent *capture, *playback; + unsigned long pollTimeout; + sem_t semaphore; +} +PaOssStream; + +typedef enum { + StreamMode_In, + StreamMode_Out +} StreamMode; + +/* prototypes for functions declared in this file */ + +static void Terminate( struct PaUtilHostApiRepresentation *hostApi ); +static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi, + const PaStreamParameters *inputParameters, + const PaStreamParameters *outputParameters, + double sampleRate ); +static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, + PaStream** s, + const PaStreamParameters *inputParameters, + const PaStreamParameters *outputParameters, + double sampleRate, + unsigned long framesPerBuffer, + PaStreamFlags streamFlags, + PaStreamCallback *streamCallback, + void *userData ); +static PaError CloseStream( PaStream* stream ); +static PaError StartStream( PaStream *stream ); +static PaError StopStream( PaStream *stream ); +static PaError AbortStream( PaStream *stream ); +static PaError IsStreamStopped( PaStream *s ); +static PaError IsStreamActive( PaStream *stream ); +static PaTime GetStreamTime( PaStream *stream ); +static double GetStreamCpuLoad( PaStream* stream ); +static PaError ReadStream( PaStream* stream, void *buffer, unsigned long frames ); +static PaError WriteStream( PaStream* stream, const void *buffer, unsigned long frames ); +static signed long GetStreamReadAvailable( PaStream* stream ); +static signed long GetStreamWriteAvailable( PaStream* stream ); +static PaError BuildDeviceList( PaOSSHostApiRepresentation *hostApi ); + + +/** Initialize the OSS API implementation. + * + * This function will initialize host API datastructures and query host devices for information. + * + * Aspect DeviceCapabilities: Enumeration of host API devices is initiated from here + * + * Aspect FreeResources: If an error is encountered under way we have to free each resource allocated in this function, + * this happens with the usual "error" label. + */ +PaError PaOSS_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex ) +{ + PaError result = paNoError; + PaOSSHostApiRepresentation *ossHostApi = NULL; + + PA_UNLESS( ossHostApi = (PaOSSHostApiRepresentation*)PaUtil_AllocateMemory( sizeof(PaOSSHostApiRepresentation) ), + paInsufficientMemory ); + PA_UNLESS( ossHostApi->allocations = PaUtil_CreateAllocationGroup(), paInsufficientMemory ); + ossHostApi->hostApiIndex = hostApiIndex; + + /* Initialize host API structure */ + *hostApi = &ossHostApi->inheritedHostApiRep; + (*hostApi)->info.structVersion = 1; + (*hostApi)->info.type = paOSS; + (*hostApi)->info.name = "OSS"; + (*hostApi)->Terminate = Terminate; + (*hostApi)->OpenStream = OpenStream; + (*hostApi)->IsFormatSupported = IsFormatSupported; + + PA_ENSURE( BuildDeviceList( ossHostApi ) ); + + PaUtil_InitializeStreamInterface( &ossHostApi->callbackStreamInterface, CloseStream, StartStream, + StopStream, AbortStream, IsStreamStopped, IsStreamActive, + GetStreamTime, GetStreamCpuLoad, + PaUtil_DummyRead, PaUtil_DummyWrite, + PaUtil_DummyGetReadAvailable, + PaUtil_DummyGetWriteAvailable ); + + PaUtil_InitializeStreamInterface( &ossHostApi->blockingStreamInterface, CloseStream, StartStream, + StopStream, AbortStream, IsStreamStopped, IsStreamActive, + GetStreamTime, PaUtil_DummyGetCpuLoad, + ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable ); + + mainThread_ = pthread_self(); + + return result; + +error: + if( ossHostApi ) + { + if( ossHostApi->allocations ) + { + PaUtil_FreeAllAllocations( ossHostApi->allocations ); + PaUtil_DestroyAllocationGroup( ossHostApi->allocations ); + } + + PaUtil_FreeMemory( ossHostApi ); + } + return result; +} + +PaError PaUtil_InitializeDeviceInfo( PaDeviceInfo *deviceInfo, const char *name, PaHostApiIndex hostApiIndex, int maxInputChannels, + int maxOutputChannels, PaTime defaultLowInputLatency, PaTime defaultLowOutputLatency, PaTime defaultHighInputLatency, + PaTime defaultHighOutputLatency, double defaultSampleRate, PaUtilAllocationGroup *allocations ) +{ + PaError result = paNoError; + + deviceInfo->structVersion = 2; + if( allocations ) + { + size_t len = strlen( name ) + 1; + PA_UNLESS( deviceInfo->name = PaUtil_GroupAllocateMemory( allocations, len ), paInsufficientMemory ); + strncpy( (char *)deviceInfo->name, name, len ); + } + else + deviceInfo->name = name; + + deviceInfo->hostApi = hostApiIndex; + deviceInfo->maxInputChannels = maxInputChannels; + deviceInfo->maxOutputChannels = maxOutputChannels; + deviceInfo->defaultLowInputLatency = defaultLowInputLatency; + deviceInfo->defaultLowOutputLatency = defaultLowOutputLatency; + deviceInfo->defaultHighInputLatency = defaultHighInputLatency; + deviceInfo->defaultHighOutputLatency = defaultHighOutputLatency; + deviceInfo->defaultSampleRate = defaultSampleRate; + +error: + return result; +} + +static int CalcHigherLogTwo( int n ) +{ + int log2 = 0; + while( (1<= 2 ) + break; + } + else + { + /* ioctl() worked but bail out if it does not support numChannels. + * We don't want to leave gaps in the numChannels supported. + */ + if( (numChannels > 2) && (temp != numChannels) ) + break; + if( temp > maxNumChannels ) + maxNumChannels = temp; /* Save maximum. */ + } + } + /* A: We're able to open a device for capture if it's busy playing back and vice versa, + * but we can't configure anything */ + if( 0 == maxNumChannels && busy ) + { + result = paDeviceUnavailable; + goto error; + } + + /* The above negotiation may fail for an old driver so try this older technique. */ + if( maxNumChannels < 1 ) + { + int stereo = 1; + if( ioctl( devHandle, SNDCTL_DSP_STEREO, &stereo ) < 0 ) + { + maxNumChannels = 1; + } + else + { + maxNumChannels = (stereo) ? 2 : 1; + } + PA_DEBUG(( "%s: use SNDCTL_DSP_STEREO, maxNumChannels = %d\n", __FUNCTION__, maxNumChannels )); + } + + /* During channel negotiation, the last ioctl() may have failed. This can + * also cause sample rate negotiation to fail. Hence the following, to return + * to a supported number of channels. SG20011005 */ + { + /* use most reasonable default value */ + numChannels = PA_MIN( maxNumChannels, 2 ); + ENSURE_( ioctl( devHandle, SNDCTL_DSP_CHANNELS, &numChannels ), paUnanticipatedHostError ); + } + + /* Get supported sample rate closest to 44100 Hz */ + if( *defaultSampleRate < 0 ) + { + sr = 44100; + ENSURE_( ioctl( devHandle, SNDCTL_DSP_SPEED, &sr ), paUnanticipatedHostError ); + + *defaultSampleRate = sr; + } + + *maxChannelCount = maxNumChannels; + + /* Attempt to set low latency with 4 frags-per-buffer, 128 frames-per-frag (total buffer 512 frames) + * since the ioctl sets bytes, multiply by numChannels, and base on 2 bytes-per-sample, */ + fragFrames = 128; + frgmt = (4 << 16) + (CalcHigherLogTwo( fragFrames * numChannels * 2 ) & 0xffff); + ENSURE_( ioctl( devHandle, SNDCTL_DSP_SETFRAGMENT, &frgmt ), paUnanticipatedHostError ); + + /* Use the value set by the ioctl to give the latency achieved */ + fragFrames = pow( 2, frgmt & 0xffff ) / (numChannels * 2); + *defaultLowLatency = ((frgmt >> 16) - 1) * fragFrames / *defaultSampleRate; + + /* Cannot now try setting a high latency (device would need closing and opening again). Make + * high-latency 4 times the low unless the fragFrames are significantly more than requested 128 */ + temp = (fragFrames < 256) ? 4 : (fragFrames < 512) ? 2 : 1; + *defaultHighLatency = temp * *defaultLowLatency; + +error: + if( devHandle >= 0 ) + close( devHandle ); + + return result; +} + +/** Query OSS device. + * + * This is where PaDeviceInfo objects are constructed and filled in with relevant information. + * + * Aspect DeviceCapabilities: The inferred device capabilities are recorded in a PaDeviceInfo object that is constructed + * in place. + */ +static PaError QueryDevice( char *deviceName, PaOSSHostApiRepresentation *ossApi, PaDeviceInfo **deviceInfo ) +{ + PaError result = paNoError; + double sampleRate = -1.; + int maxInputChannels, maxOutputChannels; + PaTime defaultLowInputLatency, defaultLowOutputLatency, defaultHighInputLatency, defaultHighOutputLatency; + PaError tmpRes = paNoError; + int busy = 0; + *deviceInfo = NULL; + + /* douglas: + we have to do this querying in a slightly different order. apparently + some sound cards will give you different info based on their settins. + e.g. a card might give you stereo at 22kHz but only mono at 44kHz. + the correct order for OSS is: format, channels, sample rate + */ + + /* Aspect StreamChannels: The number of channels supported for a device may depend on the mode it is + * opened in, it may have more channels available for capture than playback and vice versa. Therefore + * we will open the device in both read- and write-only mode to determine the supported number. + */ + if( (tmpRes = QueryDirection( deviceName, StreamMode_In, &sampleRate, &maxInputChannels, &defaultLowInputLatency, + &defaultHighInputLatency )) != paNoError ) + { + if( tmpRes != paDeviceUnavailable ) + { + PA_DEBUG(( "%s: Querying device %s for capture failed!\n", __FUNCTION__, deviceName )); + /* PA_ENSURE( tmpRes ); */ + } + ++busy; + } + if( (tmpRes = QueryDirection( deviceName, StreamMode_Out, &sampleRate, &maxOutputChannels, &defaultLowOutputLatency, + &defaultHighOutputLatency )) != paNoError ) + { + if( tmpRes != paDeviceUnavailable ) + { + PA_DEBUG(( "%s: Querying device %s for playback failed!\n", __FUNCTION__, deviceName )); + /* PA_ENSURE( tmpRes ); */ + } + ++busy; + } + assert( 0 <= busy && busy <= 2 ); + if( 2 == busy ) /* Both directions are unavailable to us */ + { + result = paDeviceUnavailable; + goto error; + } + + PA_UNLESS( *deviceInfo = PaUtil_GroupAllocateMemory( ossApi->allocations, sizeof (PaDeviceInfo) ), paInsufficientMemory ); + PA_ENSURE( PaUtil_InitializeDeviceInfo( *deviceInfo, deviceName, ossApi->hostApiIndex, maxInputChannels, maxOutputChannels, + defaultLowInputLatency, defaultLowOutputLatency, defaultHighInputLatency, defaultHighOutputLatency, sampleRate, + ossApi->allocations ) ); + +error: + return result; +} + +/** Query host devices. + * + * Loop over host devices and query their capabilitiesu + * + * Aspect DeviceCapabilities: This function calls QueryDevice on each device entry and receives a filled in PaDeviceInfo object + * per device, these are placed in the host api representation's deviceInfos array. + */ +static PaError BuildDeviceList( PaOSSHostApiRepresentation *ossApi ) +{ + PaError result = paNoError; + PaUtilHostApiRepresentation *commonApi = &ossApi->inheritedHostApiRep; + int i; + int numDevices = 0, maxDeviceInfos = 1; + PaDeviceInfo **deviceInfos = NULL; + + /* These two will be set to the first working input and output device, respectively */ + commonApi->info.defaultInputDevice = paNoDevice; + commonApi->info.defaultOutputDevice = paNoDevice; + + /* Find devices by calling QueryDevice on each + * potential device names. When we find a valid one, + * add it to a linked list. + * A: Set an arbitrary of 100 devices, should probably be a smarter way. */ + + for( i = 0; i < 100; i++ ) + { + char deviceName[32]; + PaDeviceInfo *deviceInfo; + int testResult; + + if( i == 0 ) + snprintf(deviceName, sizeof (deviceName), "%s", DEVICE_NAME_BASE); + else + snprintf(deviceName, sizeof (deviceName), "%s%d", DEVICE_NAME_BASE, i); + + /* PA_DEBUG(("%s: trying device %s\n", __FUNCTION__, deviceName )); */ + if( (testResult = QueryDevice( deviceName, ossApi, &deviceInfo )) != paNoError ) + { + if( testResult != paDeviceUnavailable ) + PA_ENSURE( testResult ); + + continue; + } + + ++numDevices; + if( !deviceInfos || numDevices > maxDeviceInfos ) + { + maxDeviceInfos *= 2; + PA_UNLESS( deviceInfos = (PaDeviceInfo **) realloc( deviceInfos, maxDeviceInfos * sizeof (PaDeviceInfo *) ), + paInsufficientMemory ); + } + { + int devIdx = numDevices - 1; + deviceInfos[devIdx] = deviceInfo; + + if( commonApi->info.defaultInputDevice == paNoDevice && deviceInfo->maxInputChannels > 0 ) + commonApi->info.defaultInputDevice = devIdx; + if( commonApi->info.defaultOutputDevice == paNoDevice && deviceInfo->maxOutputChannels > 0 ) + commonApi->info.defaultOutputDevice = devIdx; + } + } + + /* Make an array of PaDeviceInfo pointers out of the linked list */ + + PA_DEBUG(("PaOSS %s: Total number of devices found: %d\n", __FUNCTION__, numDevices)); + + commonApi->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory( + ossApi->allocations, sizeof(PaDeviceInfo*) * numDevices ); + memcpy( commonApi->deviceInfos, deviceInfos, numDevices * sizeof (PaDeviceInfo *) ); + + commonApi->info.deviceCount = numDevices; + +error: + free( deviceInfos ); + + return result; +} + +static void Terminate( struct PaUtilHostApiRepresentation *hostApi ) +{ + PaOSSHostApiRepresentation *ossHostApi = (PaOSSHostApiRepresentation*)hostApi; + + if( ossHostApi->allocations ) + { + PaUtil_FreeAllAllocations( ossHostApi->allocations ); + PaUtil_DestroyAllocationGroup( ossHostApi->allocations ); + } + + PaUtil_FreeMemory( ossHostApi ); +} + +static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi, + const PaStreamParameters *inputParameters, + const PaStreamParameters *outputParameters, + double sampleRate ) +{ + PaError result = paNoError; + PaDeviceIndex device; + PaDeviceInfo *deviceInfo; + char *deviceName; + int inputChannelCount, outputChannelCount; + int tempDevHandle = -1; + int flags; + PaSampleFormat inputSampleFormat, outputSampleFormat; + + if( inputParameters ) + { + inputChannelCount = inputParameters->channelCount; + inputSampleFormat = inputParameters->sampleFormat; + + /* unless alternate device specification is supported, reject the use of + paUseHostApiSpecificDeviceSpecification */ + + if( inputParameters->device == paUseHostApiSpecificDeviceSpecification ) + return paInvalidDevice; + + /* check that input device can support inputChannelCount */ + if( inputChannelCount > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels ) + return paInvalidChannelCount; + + /* validate inputStreamInfo */ + if( inputParameters->hostApiSpecificStreamInfo ) + return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */ + } + else + { + inputChannelCount = 0; + } + + if( outputParameters ) + { + outputChannelCount = outputParameters->channelCount; + outputSampleFormat = outputParameters->sampleFormat; + + /* unless alternate device specification is supported, reject the use of + paUseHostApiSpecificDeviceSpecification */ + + if( outputParameters->device == paUseHostApiSpecificDeviceSpecification ) + return paInvalidDevice; + + /* check that output device can support inputChannelCount */ + if( outputChannelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels ) + return paInvalidChannelCount; + + /* validate outputStreamInfo */ + if( outputParameters->hostApiSpecificStreamInfo ) + return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */ + } + else + { + outputChannelCount = 0; + } + + if (inputChannelCount == 0 && outputChannelCount == 0) + return paInvalidChannelCount; + + /* if full duplex, make sure that they're the same device */ + + if (inputChannelCount > 0 && outputChannelCount > 0 && + inputParameters->device != outputParameters->device) + return paInvalidDevice; + + /* if full duplex, also make sure that they're the same number of channels */ + + if (inputChannelCount > 0 && outputChannelCount > 0 && + inputChannelCount != outputChannelCount) + return paInvalidChannelCount; + + /* open the device so we can do more tests */ + + if( inputChannelCount > 0 ) + { + result = PaUtil_DeviceIndexToHostApiDeviceIndex(&device, inputParameters->device, hostApi); + if (result != paNoError) + return result; + } + else + { + result = PaUtil_DeviceIndexToHostApiDeviceIndex(&device, outputParameters->device, hostApi); + if (result != paNoError) + return result; + } + + deviceInfo = hostApi->deviceInfos[device]; + deviceName = (char *)deviceInfo->name; + + flags = O_NONBLOCK; + if (inputChannelCount > 0 && outputChannelCount > 0) + flags |= O_RDWR; + else if (inputChannelCount > 0) + flags |= O_RDONLY; + else + flags |= O_WRONLY; + + ENSURE_( tempDevHandle = open( deviceInfo->name, flags ), paDeviceUnavailable ); + + /* PaOssStream_Configure will do the rest of the checking for us */ + /* PA_ENSURE( PaOssStream_Configure( tempDevHandle, deviceName, outputChannelCount, &sampleRate ) ); */ + + /* everything succeeded! */ + + error: + if( tempDevHandle >= 0 ) + close( tempDevHandle ); + + return result; +} + +/** Validate stream parameters. + * + * Aspect StreamChannels: We verify that the number of channels is within the allowed range for the device + */ +static PaError ValidateParameters( const PaStreamParameters *parameters, const PaDeviceInfo *deviceInfo, StreamMode mode ) +{ + int maxChans; + + assert( parameters ); + + if( parameters->device == paUseHostApiSpecificDeviceSpecification ) + { + return paInvalidDevice; + } + + maxChans = (mode == StreamMode_In ? deviceInfo->maxInputChannels : + deviceInfo->maxOutputChannels); + if( parameters->channelCount > maxChans ) + { + return paInvalidChannelCount; + } + + return paNoError; +} + +static PaError PaOssStreamComponent_Initialize( PaOssStreamComponent *component, const PaStreamParameters *parameters, + int callbackMode, int fd, const char *deviceName ) +{ + PaError result = paNoError; + assert( component ); + + memset( component, 0, sizeof (PaOssStreamComponent) ); + + component->fd = fd; + component->devName = deviceName; + component->userChannelCount = parameters->channelCount; + component->userFormat = parameters->sampleFormat; + component->latency = parameters->suggestedLatency; + component->userInterleaved = !(parameters->sampleFormat & paNonInterleaved); + + if( !callbackMode && !component->userInterleaved ) + { + /* Pre-allocate non-interleaved user provided buffers */ + PA_UNLESS( component->userBuffers = PaUtil_AllocateMemory( sizeof (void *) * component->userChannelCount ), + paInsufficientMemory ); + } + +error: + return result; +} + +static void PaOssStreamComponent_Terminate( PaOssStreamComponent *component ) +{ + assert( component ); + + if( component->fd >= 0 ) + close( component->fd ); + if( component->buffer ) + PaUtil_FreeMemory( component->buffer ); + + if( component->userBuffers ) + PaUtil_FreeMemory( component->userBuffers ); + + PaUtil_FreeMemory( component ); +} + +static PaError ModifyBlocking( int fd, int blocking ) +{ + PaError result = paNoError; + int fflags; + + ENSURE_( fflags = fcntl( fd, F_GETFL ), paUnanticipatedHostError ); + + if( blocking ) + fflags &= ~O_NONBLOCK; + else + fflags |= O_NONBLOCK; + + ENSURE_( fcntl( fd, F_SETFL, fflags ), paUnanticipatedHostError ); + +error: + return result; +} + +/** Open input and output devices. + * + * @param idev: Returned input device file descriptor. + * @param odev: Returned output device file descriptor. + */ +static PaError OpenDevices( const char *idevName, const char *odevName, int *idev, int *odev ) +{ + PaError result = paNoError; + int flags = O_NONBLOCK, duplex = 0; + *idev = *odev = -1; + + if( idevName && odevName ) + { + duplex = 1; + flags |= O_RDWR; + } + else if( idevName ) + flags |= O_RDONLY; + else + flags |= O_WRONLY; + + /* open first in nonblocking mode, in case it's busy... + * A: then unset the non-blocking attribute */ + assert( flags & O_NONBLOCK ); + if( idevName ) + { + ENSURE_( *idev = open( idevName, flags ), paDeviceUnavailable ); + PA_ENSURE( ModifyBlocking( *idev, 1 ) ); /* Blocking */ + } + if( odevName ) + { + if( !idevName ) + { + ENSURE_( *odev = open( odevName, flags ), paDeviceUnavailable ); + PA_ENSURE( ModifyBlocking( *odev, 1 ) ); /* Blocking */ + } + else + { + ENSURE_( *odev = dup( *idev ), paUnanticipatedHostError ); + } + } + +error: + return result; +} + +static PaError PaOssStream_Initialize( PaOssStream *stream, const PaStreamParameters *inputParameters, const PaStreamParameters *outputParameters, + PaStreamCallback callback, void *userData, PaStreamFlags streamFlags, + PaOSSHostApiRepresentation *ossApi ) +{ + PaError result = paNoError; + int idev, odev; + PaUtilHostApiRepresentation *hostApi = &ossApi->inheritedHostApiRep; + const char *idevName = NULL, *odevName = NULL; + + assert( stream ); + + memset( stream, 0, sizeof (PaOssStream) ); + stream->isStopped = 1; + + PA_ENSURE( PaUtil_InitializeThreading( &stream->threading ) ); + + if( inputParameters && outputParameters ) + { + if( inputParameters->device == outputParameters->device ) + stream->sharedDevice = 1; + } + + if( inputParameters ) + idevName = hostApi->deviceInfos[inputParameters->device]->name; + if( outputParameters ) + odevName = hostApi->deviceInfos[outputParameters->device]->name; + PA_ENSURE( OpenDevices( idevName, odevName, &idev, &odev ) ); + if( inputParameters ) + { + PA_UNLESS( stream->capture = PaUtil_AllocateMemory( sizeof (PaOssStreamComponent) ), paInsufficientMemory ); + PA_ENSURE( PaOssStreamComponent_Initialize( stream->capture, inputParameters, callback != NULL, idev, idevName ) ); + } + if( outputParameters ) + { + PA_UNLESS( stream->playback = PaUtil_AllocateMemory( sizeof (PaOssStreamComponent) ), paInsufficientMemory ); + PA_ENSURE( PaOssStreamComponent_Initialize( stream->playback, outputParameters, callback != NULL, odev, odevName ) ); + } + + if( callback != NULL ) + { + PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation, + &ossApi->callbackStreamInterface, callback, userData ); + stream->callbackMode = 1; + } + else + { + PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation, + &ossApi->blockingStreamInterface, callback, userData ); + } + + ENSURE_( sem_init( &stream->semaphore, 0, 0 ), paInternalError ); + +error: + return result; +} + +static void PaOssStream_Terminate( PaOssStream *stream ) +{ + assert( stream ); + + PaUtil_TerminateStreamRepresentation( &stream->streamRepresentation ); + PaUtil_TerminateThreading( &stream->threading ); + + if( stream->capture ) + PaOssStreamComponent_Terminate( stream->capture ); + if( stream->playback ) + PaOssStreamComponent_Terminate( stream->playback ); + + sem_destroy( &stream->semaphore ); + + PaUtil_FreeMemory( stream ); +} + +/** Translate from PA format to OSS native. + * + */ +static PaError Pa2OssFormat( PaSampleFormat paFormat, int *ossFormat ) +{ + switch( paFormat ) + { + case paUInt8: + *ossFormat = AFMT_U8; + break; + case paInt8: + *ossFormat = AFMT_S8; + break; + case paInt16: + *ossFormat = AFMT_S16_NE; + break; + default: + return paInternalError; /* This shouldn't happen */ + } + + return paNoError; +} + +/** Return the PA-compatible formats that this device can support. + * + */ +static PaError GetAvailableFormats( PaOssStreamComponent *component, PaSampleFormat *availableFormats ) +{ + PaError result = paNoError; + int mask = 0; + PaSampleFormat frmts = 0; + + ENSURE_( ioctl( component->fd, SNDCTL_DSP_GETFMTS, &mask ), paUnanticipatedHostError ); + if( mask & AFMT_U8 ) + frmts |= paUInt8; + if( mask & AFMT_S8 ) + frmts |= paInt8; + if( mask & AFMT_S16_NE ) + frmts |= paInt16; + else + result = paSampleFormatNotSupported; + + *availableFormats = frmts; + +error: + return result; +} + +static unsigned int PaOssStreamComponent_FrameSize( PaOssStreamComponent *component ) +{ + return Pa_GetSampleSize( component->hostFormat ) * component->hostChannelCount; +} + +/** Buffer size in bytes. + * + */ +static unsigned long PaOssStreamComponent_BufferSize( PaOssStreamComponent *component ) +{ + return PaOssStreamComponent_FrameSize( component ) * component->hostFrames * component->numBufs; +} + +/** Configure stream component device parameters. + */ +static PaError PaOssStreamComponent_Configure( PaOssStreamComponent *component, double sampleRate, unsigned long + framesPerBuffer, StreamMode streamMode, PaOssStreamComponent *master ) +{ + PaError result = paNoError; + int temp, nativeFormat; + int sr = (int)sampleRate; + PaSampleFormat availableFormats = 0, hostFormat = 0; + int chans = component->userChannelCount; + int frgmt; + int numBufs; + int bytesPerBuf; + unsigned long bufSz; + unsigned long fragSz; + audio_buf_info bufInfo; + + /* We may have a situation where only one component (the master) is configured, if both point to the same device. + * In that case, the second component will copy settings from the other */ + if( !master ) + { + /* Aspect BufferSettings: If framesPerBuffer is unspecified we have to infer a suitable fragment size. + * The hardware need not respect the requested fragment size, so we may have to adapt. + */ + if( framesPerBuffer == paFramesPerBufferUnspecified ) + { + /* Aim for 4 fragments in the complete buffer; the latency comes from 3 of these */ + fragSz = (unsigned long)(component->latency * sampleRate / 3); + bufSz = fragSz * 4; + } + else + { + fragSz = framesPerBuffer; + bufSz = (unsigned long)(component->latency * sampleRate) + fragSz; /* Latency + 1 buffer */ + } + + PA_ENSURE( GetAvailableFormats( component, &availableFormats ) ); + hostFormat = PaUtil_SelectClosestAvailableFormat( availableFormats, component->userFormat ); + + /* OSS demands at least 2 buffers, and 16 bytes per buffer */ + numBufs = (int)PA_MAX( bufSz / fragSz, 2 ); + bytesPerBuf = PA_MAX( fragSz * Pa_GetSampleSize( hostFormat ) * chans, 16 ); + + /* The fragment parameters are encoded like this: + * Most significant byte: number of fragments + * Least significant byte: exponent of fragment size (i.e., for 256, 8) + */ + frgmt = (numBufs << 16) + (CalcHigherLogTwo( bytesPerBuf ) & 0xffff); + ENSURE_( ioctl( component->fd, SNDCTL_DSP_SETFRAGMENT, &frgmt ), paUnanticipatedHostError ); + + /* A: according to the OSS programmer's guide parameters should be set in this order: + * format, channels, rate */ + + /* This format should be deemed good before we get this far */ + PA_ENSURE( Pa2OssFormat( hostFormat, &temp ) ); + nativeFormat = temp; + ENSURE_( ioctl( component->fd, SNDCTL_DSP_SETFMT, &temp ), paUnanticipatedHostError ); + PA_UNLESS( temp == nativeFormat, paInternalError ); + + /* try to set the number of channels */ + ENSURE_( ioctl( component->fd, SNDCTL_DSP_CHANNELS, &chans ), paSampleFormatNotSupported ); /* XXX: Should be paInvalidChannelCount? */ + /* It's possible that the minimum number of host channels is greater than what the user requested */ + PA_UNLESS( chans >= component->userChannelCount, paInvalidChannelCount ); + + /* try to set the sample rate */ + ENSURE_( ioctl( component->fd, SNDCTL_DSP_SPEED, &sr ), paInvalidSampleRate ); + + /* reject if there's no sample rate within 1% of the one requested */ + if( (fabs( sampleRate - sr ) / sampleRate) > 0.01 ) + { + PA_DEBUG(("%s: Wanted %f, closest sample rate was %d\n", __FUNCTION__, sampleRate, sr )); + PA_ENSURE( paInvalidSampleRate ); + } + + ENSURE_( ioctl( component->fd, streamMode == StreamMode_In ? SNDCTL_DSP_GETISPACE : SNDCTL_DSP_GETOSPACE, &bufInfo ), + paUnanticipatedHostError ); + component->numBufs = bufInfo.fragstotal; + + /* This needs to be the last ioctl call before the first read/write, according to the OSS programmer's guide */ + ENSURE_( ioctl( component->fd, SNDCTL_DSP_GETBLKSIZE, &bytesPerBuf ), paUnanticipatedHostError ); + + component->hostFrames = bytesPerBuf / Pa_GetSampleSize( hostFormat ) / chans; + component->hostChannelCount = chans; + component->hostFormat = hostFormat; + } + else + { + component->hostFormat = master->hostFormat; + component->hostFrames = master->hostFrames; + component->hostChannelCount = master->hostChannelCount; + component->numBufs = master->numBufs; + } + + PA_UNLESS( component->buffer = PaUtil_AllocateMemory( PaOssStreamComponent_BufferSize( component ) ), + paInsufficientMemory ); + +error: + return result; +} + +static PaError PaOssStreamComponent_Read( PaOssStreamComponent *component, unsigned long *frames ) +{ + PaError result = paNoError; + size_t len = *frames * PaOssStreamComponent_FrameSize( component ); + ssize_t bytesRead; + + ENSURE_( bytesRead = read( component->fd, component->buffer, len ), paUnanticipatedHostError ); + *frames = bytesRead / PaOssStreamComponent_FrameSize( component ); + /* TODO: Handle condition where number of frames read doesn't equal number of frames requested */ + +error: + return result; +} + +static PaError PaOssStreamComponent_Write( PaOssStreamComponent *component, unsigned long *frames ) +{ + PaError result = paNoError; + size_t len = *frames * PaOssStreamComponent_FrameSize( component ); + ssize_t bytesWritten; + + ENSURE_( bytesWritten = write( component->fd, component->buffer, len ), paUnanticipatedHostError ); + *frames = bytesWritten / PaOssStreamComponent_FrameSize( component ); + /* TODO: Handle condition where number of frames written doesn't equal number of frames requested */ + +error: + return result; +} + +/** Configure the stream according to input/output parameters. + * + * Aspect StreamChannels: The minimum number of channels supported by the device may exceed that requested by + * the user, if so we'll record the actual number of host channels and adapt later. + */ +static PaError PaOssStream_Configure( PaOssStream *stream, double sampleRate, unsigned long framesPerBuffer, + double *inputLatency, double *outputLatency ) +{ + PaError result = paNoError; + int duplex = stream->capture && stream->playback; + unsigned long framesPerHostBuffer = 0; + + /* We should request full duplex first thing after opening the device */ + if( duplex && stream->sharedDevice ) + ENSURE_( ioctl( stream->capture->fd, SNDCTL_DSP_SETDUPLEX, 0 ), paUnanticipatedHostError ); + + if( stream->capture ) + { + PaOssStreamComponent *component = stream->capture; + PA_ENSURE( PaOssStreamComponent_Configure( component, sampleRate, framesPerBuffer, StreamMode_In, + NULL ) ); + + assert( component->hostChannelCount > 0 ); + assert( component->hostFrames > 0 ); + + *inputLatency = (component->hostFrames * (component->numBufs - 1)) / sampleRate; + } + if( stream->playback ) + { + PaOssStreamComponent *component = stream->playback, *master = stream->sharedDevice ? stream->capture : NULL; + PA_ENSURE( PaOssStreamComponent_Configure( component, sampleRate, framesPerBuffer, StreamMode_Out, + master ) ); + + assert( component->hostChannelCount > 0 ); + assert( component->hostFrames > 0 ); + + *outputLatency = (component->hostFrames * (component->numBufs - 1)) / sampleRate; + } + + if( duplex ) + framesPerHostBuffer = PA_MIN( stream->capture->hostFrames, stream->playback->hostFrames ); + else if( stream->capture ) + framesPerHostBuffer = stream->capture->hostFrames; + else if( stream->playback ) + framesPerHostBuffer = stream->playback->hostFrames; + + stream->framesPerHostBuffer = framesPerHostBuffer; + stream->pollTimeout = (int) ceil( 1e6 * framesPerHostBuffer / sampleRate ); /* Period in usecs, rounded up */ + + stream->sampleRate = stream->streamRepresentation.streamInfo.sampleRate = sampleRate; + +error: + return result; +} + +/* see pa_hostapi.h for a list of validity guarantees made about OpenStream parameters */ + +/** Open a PA OSS stream. + * + * Aspect StreamChannels: The number of channels is specified per direction (in/out), and can differ between the + * two. However, OSS doesn't support separate configuration spaces for capture and playback so if both + * directions are the same device we will demand the same number of channels. The number of channels can range + * from 1 to the maximum supported by the device. + * + * Aspect BufferSettings: If framesPerBuffer != paFramesPerBufferUnspecified the number of frames per callback + * must reflect this, in addition the host latency per device should approximate the corresponding + * suggestedLatency. Based on these constraints we need to determine a number of frames per host buffer that + * both capture and playback can agree on (they can be different devices), the buffer processor can adapt + * between host and user buffer size, but the ratio should preferably be integral. + */ +static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, + PaStream** s, + const PaStreamParameters *inputParameters, + const PaStreamParameters *outputParameters, + double sampleRate, + unsigned long framesPerBuffer, + PaStreamFlags streamFlags, + PaStreamCallback *streamCallback, + void *userData ) +{ + PaError result = paNoError; + PaOSSHostApiRepresentation *ossHostApi = (PaOSSHostApiRepresentation*)hostApi; + PaOssStream *stream = NULL; + int inputChannelCount = 0, outputChannelCount = 0; + PaSampleFormat inputSampleFormat = 0, outputSampleFormat = 0, inputHostFormat = 0, outputHostFormat = 0; + const PaDeviceInfo *inputDeviceInfo = 0, *outputDeviceInfo = 0; + int bpInitialized = 0; + double inLatency = 0., outLatency = 0.; + int i = 0; + + /* validate platform specific flags */ + if( (streamFlags & paPlatformSpecificFlags) != 0 ) + return paInvalidFlag; /* unexpected platform specific flag */ + + if( inputParameters ) + { + /* unless alternate device specification is supported, reject the use of + paUseHostApiSpecificDeviceSpecification */ + inputDeviceInfo = hostApi->deviceInfos[inputParameters->device]; + PA_ENSURE( ValidateParameters( inputParameters, inputDeviceInfo, StreamMode_In ) ); + + inputChannelCount = inputParameters->channelCount; + inputSampleFormat = inputParameters->sampleFormat; + } + if( outputParameters ) + { + outputDeviceInfo = hostApi->deviceInfos[outputParameters->device]; + PA_ENSURE( ValidateParameters( outputParameters, outputDeviceInfo, StreamMode_Out ) ); + + outputChannelCount = outputParameters->channelCount; + outputSampleFormat = outputParameters->sampleFormat; + } + + /* Aspect StreamChannels: We currently demand that number of input and output channels are the same, if the same + * device is opened for both directions + */ + if( inputChannelCount > 0 && outputChannelCount > 0 ) + { + if( inputParameters->device == outputParameters->device ) + { + if( inputParameters->channelCount != outputParameters->channelCount ) + return paInvalidChannelCount; + } + } + + /* Round framesPerBuffer to the next power-of-two to make OSS happy. */ + if( framesPerBuffer != paFramesPerBufferUnspecified ) + { + framesPerBuffer &= INT_MAX; + for (i = 1; framesPerBuffer > i; i <<= 1) ; + framesPerBuffer = i; + } + + /* allocate and do basic initialization of the stream structure */ + PA_UNLESS( stream = (PaOssStream*)PaUtil_AllocateMemory( sizeof(PaOssStream) ), paInsufficientMemory ); + PA_ENSURE( PaOssStream_Initialize( stream, inputParameters, outputParameters, streamCallback, userData, streamFlags, ossHostApi ) ); + + PA_ENSURE( PaOssStream_Configure( stream, sampleRate, framesPerBuffer, &inLatency, &outLatency ) ); + + PaUtil_InitializeCpuLoadMeasurer( &stream->cpuLoadMeasurer, sampleRate ); + + if( inputParameters ) + { + inputHostFormat = stream->capture->hostFormat; + stream->streamRepresentation.streamInfo.inputLatency = inLatency + + PaUtil_GetBufferProcessorInputLatencyFrames( &stream->bufferProcessor ) / sampleRate; + } + if( outputParameters ) + { + outputHostFormat = stream->playback->hostFormat; + stream->streamRepresentation.streamInfo.outputLatency = outLatency + + PaUtil_GetBufferProcessorOutputLatencyFrames( &stream->bufferProcessor ) / sampleRate; + } + + /* Initialize buffer processor with fixed host buffer size. + * Aspect StreamSampleFormat: Here we commit the user and host sample formats, PA infrastructure will + * convert between the two. + */ + PA_ENSURE( PaUtil_InitializeBufferProcessor( &stream->bufferProcessor, + inputChannelCount, inputSampleFormat, inputHostFormat, outputChannelCount, outputSampleFormat, + outputHostFormat, sampleRate, streamFlags, framesPerBuffer, stream->framesPerHostBuffer, + paUtilFixedHostBufferSize, streamCallback, userData ) ); + bpInitialized = 1; + + *s = (PaStream*)stream; + + return result; + +error: + if( bpInitialized ) + PaUtil_TerminateBufferProcessor( &stream->bufferProcessor ); + if( stream ) + PaOssStream_Terminate( stream ); + + return result; +} + +/*! Poll on I/O filedescriptors. + + Poll till we've determined there's data for read or write. In the full-duplex case, + we don't want to hang around forever waiting for either input or output frames, so + whenever we have a timed out filedescriptor we check if we're nearing under/overrun + for the other direction (critical limit set at one buffer). If so, we exit the waiting + state, and go on with what we got. We align the number of frames on a host buffer + boundary because it is possible that the buffer size differs for the two directions and + the host buffer size is a compromise between the two. + */ +static PaError PaOssStream_WaitForFrames( PaOssStream *stream, unsigned long *frames ) +{ + PaError result = paNoError; + int pollPlayback = 0, pollCapture = 0; + int captureAvail = INT_MAX, playbackAvail = INT_MAX, commonAvail; + audio_buf_info bufInfo; + /* int ofs = 0, nfds = stream->nfds; */ + fd_set readFds, writeFds; + int nfds = 0; + struct timeval selectTimeval = {0, 0}; + unsigned long timeout = stream->pollTimeout; /* In usecs */ + int captureFd = -1, playbackFd = -1; + + assert( stream ); + assert( frames ); + + if( stream->capture ) + { + pollCapture = 1; + captureFd = stream->capture->fd; + /* stream->capture->pfd->events = POLLIN; */ + } + if( stream->playback ) + { + pollPlayback = 1; + playbackFd = stream->playback->fd; + /* stream->playback->pfd->events = POLLOUT; */ + } + + FD_ZERO( &readFds ); + FD_ZERO( &writeFds ); + + while( pollPlayback || pollCapture ) + { +#ifdef PTHREAD_CANCELED + pthread_testcancel(); +#else + /* avoid indefinite waiting on thread not supporting cancelation */ + if( stream->callbackStop || stream->callbackAbort ) + { + PA_DEBUG(( "Cancelling PaOssStream_WaitForFrames\n" )); + (*frames) = 0; + return paNoError; + } +#endif + + /* select may modify the timeout parameter */ + selectTimeval.tv_usec = timeout; + nfds = 0; + + if( pollCapture ) + { + FD_SET( captureFd, &readFds ); + nfds = captureFd + 1; + } + if( pollPlayback ) + { + FD_SET( playbackFd, &writeFds ); + nfds = PA_MAX( nfds, playbackFd + 1 ); + } + ENSURE_( select( nfds, &readFds, &writeFds, NULL, &selectTimeval ), paUnanticipatedHostError ); + /* + if( poll( stream->pfds + ofs, nfds, stream->pollTimeout ) < 0 ) + { + + ENSURE_( -1, paUnanticipatedHostError ); + } + */ +#ifdef PTHREAD_CANCELED + pthread_testcancel(); +#else + /* avoid indefinite waiting on thread not supporting cancelation */ + if( stream->callbackStop || stream->callbackAbort ) + { + PA_DEBUG(( "Cancelling PaOssStream_WaitForFrames\n" )); + (*frames) = 0; + return paNoError; + } +#endif + if( pollCapture ) + { + if( FD_ISSET( captureFd, &readFds ) ) + { + FD_CLR( captureFd, &readFds ); + pollCapture = 0; + } + /* + if( stream->capture->pfd->revents & POLLIN ) + { + --nfds; + ++ofs; + pollCapture = 0; + } + */ + else if( stream->playback ) /* Timed out, go on with playback? */ + { + /*PA_DEBUG(( "%s: Trying to poll again for capture frames, pollTimeout: %d\n", + __FUNCTION__, stream->pollTimeout ));*/ + } + } + if( pollPlayback ) + { + if( FD_ISSET( playbackFd, &writeFds ) ) + { + FD_CLR( playbackFd, &writeFds ); + pollPlayback = 0; + } + /* + if( stream->playback->pfd->revents & POLLOUT ) + { + --nfds; + pollPlayback = 0; + } + */ + else if( stream->capture ) /* Timed out, go on with capture? */ + { + /*PA_DEBUG(( "%s: Trying to poll again for playback frames, pollTimeout: %d\n\n", + __FUNCTION__, stream->pollTimeout ));*/ + } + } + } + + if( stream->capture ) + { + ENSURE_( ioctl( captureFd, SNDCTL_DSP_GETISPACE, &bufInfo ), paUnanticipatedHostError ); + captureAvail = bufInfo.fragments * stream->capture->hostFrames; + if( !captureAvail ) + PA_DEBUG(( "%s: captureAvail: 0\n", __FUNCTION__ )); + + captureAvail = captureAvail == 0 ? INT_MAX : captureAvail; /* Disregard if zero */ + } + if( stream->playback ) + { + ENSURE_( ioctl( playbackFd, SNDCTL_DSP_GETOSPACE, &bufInfo ), paUnanticipatedHostError ); + playbackAvail = bufInfo.fragments * stream->playback->hostFrames; + if( !playbackAvail ) + { + PA_DEBUG(( "%s: playbackAvail: 0\n", __FUNCTION__ )); + } + + playbackAvail = playbackAvail == 0 ? INT_MAX : playbackAvail; /* Disregard if zero */ + } + + commonAvail = PA_MIN( captureAvail, playbackAvail ); + if( commonAvail == INT_MAX ) + commonAvail = 0; + commonAvail -= commonAvail % stream->framesPerHostBuffer; + + assert( commonAvail != INT_MAX ); + assert( commonAvail >= 0 ); + *frames = commonAvail; + +error: + return result; +} + +/** Prepare stream for capture/playback. + * + * In order to synchronize capture and playback properly we use the SETTRIGGER command. + */ +static PaError PaOssStream_Prepare( PaOssStream *stream ) +{ + PaError result = paNoError; + int enableBits = 0; + + if( stream->triggered ) + return result; + + /* The OSS reference instructs us to clear direction bits before setting them.*/ + if( stream->playback ) + ENSURE_( ioctl( stream->playback->fd, SNDCTL_DSP_SETTRIGGER, &enableBits ), paUnanticipatedHostError ); + if( stream->capture ) + ENSURE_( ioctl( stream->capture->fd, SNDCTL_DSP_SETTRIGGER, &enableBits ), paUnanticipatedHostError ); + + if( stream->playback ) + { + size_t bufSz = PaOssStreamComponent_BufferSize( stream->playback ); + memset( stream->playback->buffer, 0, bufSz ); + + /* Looks like we have to turn off blocking before we try this, but if we don't fill the buffer + * OSS will complain. */ + PA_ENSURE( ModifyBlocking( stream->playback->fd, 0 ) ); + while (1) + { + if( write( stream->playback->fd, stream->playback->buffer, bufSz ) < 0 ) + break; + } + PA_ENSURE( ModifyBlocking( stream->playback->fd, 1 ) ); + } + + if( stream->sharedDevice ) + { + enableBits = PCM_ENABLE_INPUT | PCM_ENABLE_OUTPUT; + ENSURE_( ioctl( stream->capture->fd, SNDCTL_DSP_SETTRIGGER, &enableBits ), paUnanticipatedHostError ); + } + else + { + if( stream->capture ) + { + enableBits = PCM_ENABLE_INPUT; + ENSURE_( ioctl( stream->capture->fd, SNDCTL_DSP_SETTRIGGER, &enableBits ), paUnanticipatedHostError ); + } + if( stream->playback ) + { + enableBits = PCM_ENABLE_OUTPUT; + ENSURE_( ioctl( stream->playback->fd, SNDCTL_DSP_SETTRIGGER, &enableBits ), paUnanticipatedHostError ); + } + } + + /* Ok, we have triggered the stream */ + stream->triggered = 1; + +error: + return result; +} + +/** Stop audio processing + * + */ +static PaError PaOssStream_Stop( PaOssStream *stream, int abort ) +{ + PaError result = paNoError; + + /* Looks like the only safe way to stop audio without reopening the device is SNDCTL_DSP_POST. + * Also disable capture/playback till the stream is started again. + */ + int captureErr = 0, playbackErr = 0; + if( stream->capture ) + { + if( (captureErr = ioctl( stream->capture->fd, SNDCTL_DSP_POST, 0 )) < 0 ) + { + PA_DEBUG(( "%s: Failed to stop capture device, error: %d\n", __FUNCTION__, captureErr )); + } + } + if( stream->playback && !stream->sharedDevice ) + { + if( (playbackErr = ioctl( stream->playback->fd, SNDCTL_DSP_POST, 0 )) < 0 ) + { + PA_DEBUG(( "%s: Failed to stop playback device, error: %d\n", __FUNCTION__, playbackErr )); + } + } + + if( captureErr || playbackErr ) + { + result = paUnanticipatedHostError; + } + + return result; +} + +/** Clean up after thread exit. + * + * Aspect StreamState: If the user has registered a streamFinishedCallback it will be called here + */ +static void OnExit( void *data ) +{ + PaOssStream *stream = (PaOssStream *) data; + assert( data ); + + PaUtil_ResetCpuLoadMeasurer( &stream->cpuLoadMeasurer ); + + PaOssStream_Stop( stream, stream->callbackAbort ); + + PA_DEBUG(( "OnExit: Stoppage\n" )); + + /* Eventually notify user all buffers have played */ + if( stream->streamRepresentation.streamFinishedCallback ) + stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData ); + + stream->callbackAbort = 0; /* Clear state */ + stream->isActive = 0; +} + +static PaError SetUpBuffers( PaOssStream *stream, unsigned long framesAvail ) +{ + PaError result = paNoError; + + if( stream->capture ) + { + PaUtil_SetInterleavedInputChannels( &stream->bufferProcessor, 0, stream->capture->buffer, + stream->capture->hostChannelCount ); + PaUtil_SetInputFrameCount( &stream->bufferProcessor, framesAvail ); + } + if( stream->playback ) + { + PaUtil_SetInterleavedOutputChannels( &stream->bufferProcessor, 0, stream->playback->buffer, + stream->playback->hostChannelCount ); + PaUtil_SetOutputFrameCount( &stream->bufferProcessor, framesAvail ); + } + + return result; +} + +/** Thread procedure for callback processing. + * + * Aspect StreamState: StartStream will wait on this to initiate audio processing, useful in case the + * callback should be used for buffer priming. When the stream is cancelled a separate function will + * take care of the transition to the Callback Finished state (the stream isn't considered Stopped + * before StopStream() or AbortStream() are called). + */ +static void *PaOSS_AudioThreadProc( void *userData ) +{ + PaError result = paNoError; + PaOssStream *stream = (PaOssStream*)userData; + unsigned long framesAvail = 0, framesProcessed = 0; + int callbackResult = paContinue; + int triggered = stream->triggered; /* See if SNDCTL_DSP_TRIGGER has been issued already */ + int initiateProcessing = triggered; /* Already triggered? */ + PaStreamCallbackFlags cbFlags = 0; /* We might want to keep state across iterations */ + PaStreamCallbackTimeInfo timeInfo = {0,0,0}; /* TODO: IMPLEMENT ME */ + + /* +#if ( SOUND_VERSION > 0x030904 ) + audio_errinfo errinfo; +#endif +*/ + + assert( stream ); + + pthread_cleanup_push( &OnExit, stream ); /* Execute OnExit when exiting */ + + /* The first time the stream is started we use SNDCTL_DSP_TRIGGER to accurately start capture and + * playback in sync, when the stream is restarted after being stopped we simply start by reading/ + * writing. + */ + PA_ENSURE( PaOssStream_Prepare( stream ) ); + + /* If we are to initiate processing implicitly by reading/writing data, we start off in blocking mode */ + if( initiateProcessing ) + { + /* Make sure devices are in blocking mode */ + if( stream->capture ) + ModifyBlocking( stream->capture->fd, 1 ); + if( stream->playback ) + ModifyBlocking( stream->playback->fd, 1 ); + } + + while( 1 ) + { +#ifdef PTHREAD_CANCELED + pthread_testcancel(); +#else + if( stream->callbackAbort ) /* avoid indefinite waiting on thread not supporting cancelation */ + { + PA_DEBUG(( "Aborting callback thread\n" )); + break; + } +#endif + if( stream->callbackStop && callbackResult == paContinue ) + { + PA_DEBUG(( "Setting callbackResult to paComplete\n" )); + callbackResult = paComplete; + } + + /* Aspect StreamState: Because of the messy OSS scheme we can't explicitly trigger device start unless + * the stream has been recently started, we will have to go right ahead and read/write in blocking + * fashion to trigger operation. Therefore we begin with processing one host buffer before we switch + * to non-blocking mode. + */ + if( !initiateProcessing ) + { + /* Wait on available frames */ + PA_ENSURE( PaOssStream_WaitForFrames( stream, &framesAvail ) ); + assert( framesAvail % stream->framesPerHostBuffer == 0 ); + } + else + { + framesAvail = stream->framesPerHostBuffer; + } + + while( framesAvail > 0 ) + { + unsigned long frames = framesAvail; + +#ifdef PTHREAD_CANCELED + pthread_testcancel(); +#else + if( stream->callbackStop ) + { + PA_DEBUG(( "Setting callbackResult to paComplete\n" )); + callbackResult = paComplete; + } + + if( stream->callbackAbort ) /* avoid indefinite waiting on thread not supporting cancelation */ + { + PA_DEBUG(( "Aborting callback thread\n" )); + break; + } +#endif + PaUtil_BeginCpuLoadMeasurement( &stream->cpuLoadMeasurer ); + + /* Read data */ + if ( stream->capture ) + { + PA_ENSURE( PaOssStreamComponent_Read( stream->capture, &frames ) ); + if( frames < framesAvail ) + { + PA_DEBUG(( "Read %lu less frames than requested\n", framesAvail - frames )); + framesAvail = frames; + } + } + +#if ( SOUND_VERSION >= 0x030904 ) + /* + Check with OSS to see if there have been any under/overruns + since last time we checked. + */ + /* + if( ioctl( stream->deviceHandle, SNDCTL_DSP_GETERROR, &errinfo ) >= 0 ) + { + if( errinfo.play_underruns ) + cbFlags |= paOutputUnderflow ; + if( errinfo.record_underruns ) + cbFlags |= paInputUnderflow ; + } + else + PA_DEBUG(( "SNDCTL_DSP_GETERROR command failed: %s\n", strerror( errno ) )); + */ +#endif + + PaUtil_BeginBufferProcessing( &stream->bufferProcessor, &timeInfo, + cbFlags ); + cbFlags = 0; + PA_ENSURE( SetUpBuffers( stream, framesAvail ) ); + + framesProcessed = PaUtil_EndBufferProcessing( &stream->bufferProcessor, + &callbackResult ); + assert( framesProcessed == framesAvail ); + PaUtil_EndCpuLoadMeasurement( &stream->cpuLoadMeasurer, framesProcessed ); + + if ( stream->playback ) + { + frames = framesAvail; + + PA_ENSURE( PaOssStreamComponent_Write( stream->playback, &frames ) ); + if( frames < framesAvail ) + { + /* TODO: handle bytesWritten != bytesRequested (slippage?) */ + PA_DEBUG(( "Wrote %lu less frames than requested\n", framesAvail - frames )); + } + } + + framesAvail -= framesProcessed; + stream->framesProcessed += framesProcessed; + + if( callbackResult != paContinue ) + break; + } + + if( initiateProcessing || !triggered ) + { + /* Non-blocking */ + if( stream->capture ) + PA_ENSURE( ModifyBlocking( stream->capture->fd, 0 ) ); + if( stream->playback && !stream->sharedDevice ) + PA_ENSURE( ModifyBlocking( stream->playback->fd, 0 ) ); + + initiateProcessing = 0; + sem_post( &stream->semaphore ); + } + + if( callbackResult != paContinue ) + { + stream->callbackAbort = callbackResult == paAbort; + if( stream->callbackAbort || PaUtil_IsBufferProcessorOutputEmpty( &stream->bufferProcessor ) ) + break; + } + } + + pthread_cleanup_pop( 1 ); + +error: + pthread_exit( NULL ); +} + +/** Close the stream. + * + */ +static PaError CloseStream( PaStream* s ) +{ + PaError result = paNoError; + PaOssStream *stream = (PaOssStream*)s; + + assert( stream ); + + PaUtil_TerminateBufferProcessor( &stream->bufferProcessor ); + PaOssStream_Terminate( stream ); + + return result; +} + +/** Start the stream. + * + * Aspect StreamState: After returning, the stream shall be in the Active state, implying that an eventual + * callback will be repeatedly called in a separate thread. If a separate thread is started this function + * will block untill it has started processing audio, otherwise audio processing is started directly. + */ +static PaError StartStream( PaStream *s ) +{ + PaError result = paNoError; + PaOssStream *stream = (PaOssStream*)s; + + stream->isActive = 1; + stream->isStopped = 0; + stream->lastPosPtr = 0; + stream->lastStreamBytes = 0; + stream->framesProcessed = 0; + + /* only use the thread for callback streams */ + if( stream->bufferProcessor.streamCallback ) + { + PA_ENSURE( PaUtil_StartThreading( &stream->threading, &PaOSS_AudioThreadProc, stream ) ); + sem_wait( &stream->semaphore ); + } + else + PA_ENSURE( PaOssStream_Prepare( stream ) ); + +error: + return result; +} + +static PaError RealStop( PaOssStream *stream, int abort ) +{ + PaError result = paNoError; + + if( stream->callbackMode ) + { + if( abort ) + stream->callbackAbort = 1; + else + stream->callbackStop = 1; + + PA_ENSURE( PaUtil_CancelThreading( &stream->threading, !abort, NULL ) ); + + stream->callbackStop = stream->callbackAbort = 0; + } + else + PA_ENSURE( PaOssStream_Stop( stream, abort ) ); + + stream->isStopped = 1; + +error: + return result; +} + +/** Stop the stream. + * + * Aspect StreamState: This will cause the stream to transition to the Stopped state, playing all enqueued + * buffers. + */ +static PaError StopStream( PaStream *s ) +{ + return RealStop( (PaOssStream *)s, 0 ); +} + +/** Abort the stream. + * + * Aspect StreamState: This will cause the stream to transition to the Stopped state, discarding all enqueued + * buffers. Note that the buffers are not currently correctly discarded, this is difficult without closing + * the OSS device. + */ +static PaError AbortStream( PaStream *s ) +{ + return RealStop( (PaOssStream *)s, 1 ); +} + +/** Is the stream in the Stopped state. + * + */ +static PaError IsStreamStopped( PaStream *s ) +{ + PaOssStream *stream = (PaOssStream*)s; + + return (stream->isStopped); +} + +/** Is the stream in the Active state. + * + */ +static PaError IsStreamActive( PaStream *s ) +{ + PaOssStream *stream = (PaOssStream*)s; + + return (stream->isActive); +} + +static PaTime GetStreamTime( PaStream *s ) +{ + PaOssStream *stream = (PaOssStream*)s; + count_info info; + int delta; + + if( stream->playback ) { + if( ioctl( stream->playback->fd, SNDCTL_DSP_GETOPTR, &info) == 0 ) { + delta = ( info.bytes - stream->lastPosPtr ) /* & 0x000FFFFF*/; + return (float)(stream->lastStreamBytes + delta) / PaOssStreamComponent_FrameSize( stream->playback ) / stream->sampleRate; + } + } + else { + if (ioctl( stream->capture->fd, SNDCTL_DSP_GETIPTR, &info) == 0) { + delta = (info.bytes - stream->lastPosPtr) /*& 0x000FFFFF*/; + return (float)(stream->lastStreamBytes + delta) / PaOssStreamComponent_FrameSize( stream->capture ) / stream->sampleRate; + } + } + + /* the ioctl failed, but we can still give a coarse estimate */ + + return stream->framesProcessed / stream->sampleRate; +} + + +static double GetStreamCpuLoad( PaStream* s ) +{ + PaOssStream *stream = (PaOssStream*)s; + + return PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer ); +} + + +/* + As separate stream interfaces are used for blocking and callback + streams, the following functions can be guaranteed to only be called + for blocking streams. +*/ + + +static PaError ReadStream( PaStream* s, + void *buffer, + unsigned long frames ) +{ + PaError result = paNoError; + PaOssStream *stream = (PaOssStream*)s; + int bytesRequested, bytesRead; + unsigned long framesRequested; + void *userBuffer; + + /* If user input is non-interleaved, PaUtil_CopyInput will manipulate the channel pointers, + * so we copy the user provided pointers */ + if( stream->bufferProcessor.userInputIsInterleaved ) + userBuffer = buffer; + else /* Copy channels into local array */ + { + userBuffer = stream->capture->userBuffers; + memcpy( (void *)userBuffer, buffer, sizeof (void *) * stream->capture->userChannelCount ); + } + + while( frames ) + { + framesRequested = PA_MIN( frames, stream->capture->hostFrames ); + + bytesRequested = framesRequested * PaOssStreamComponent_FrameSize( stream->capture ); + ENSURE_( (bytesRead = read( stream->capture->fd, stream->capture->buffer, bytesRequested )), + paUnanticipatedHostError ); + if ( bytesRequested != bytesRead ) + { + PA_DEBUG(( "Requested %d bytes, read %d\n", bytesRequested, bytesRead )); + return paUnanticipatedHostError; + } + + PaUtil_SetInputFrameCount( &stream->bufferProcessor, stream->capture->hostFrames ); + PaUtil_SetInterleavedInputChannels( &stream->bufferProcessor, 0, stream->capture->buffer, stream->capture->hostChannelCount ); + PaUtil_CopyInput( &stream->bufferProcessor, &userBuffer, framesRequested ); + frames -= framesRequested; + } + +error: + return result; +} + + +static PaError WriteStream( PaStream *s, const void *buffer, unsigned long frames ) +{ + PaError result = paNoError; + PaOssStream *stream = (PaOssStream*)s; + int bytesRequested, bytesWritten; + unsigned long framesConverted; + const void *userBuffer; + + /* If user output is non-interleaved, PaUtil_CopyOutput will manipulate the channel pointers, + * so we copy the user provided pointers */ + if( stream->bufferProcessor.userOutputIsInterleaved ) + userBuffer = buffer; + else + { + /* Copy channels into local array */ + userBuffer = stream->playback->userBuffers; + memcpy( (void *)userBuffer, buffer, sizeof (void *) * stream->playback->userChannelCount ); + } + + while( frames ) + { + PaUtil_SetOutputFrameCount( &stream->bufferProcessor, stream->playback->hostFrames ); + PaUtil_SetInterleavedOutputChannels( &stream->bufferProcessor, 0, stream->playback->buffer, stream->playback->hostChannelCount ); + + framesConverted = PaUtil_CopyOutput( &stream->bufferProcessor, &userBuffer, frames ); + frames -= framesConverted; + + bytesRequested = framesConverted * PaOssStreamComponent_FrameSize( stream->playback ); + ENSURE_( (bytesWritten = write( stream->playback->fd, stream->playback->buffer, bytesRequested )), + paUnanticipatedHostError ); + + if ( bytesRequested != bytesWritten ) + { + PA_DEBUG(( "Requested %d bytes, wrote %d\n", bytesRequested, bytesWritten )); + return paUnanticipatedHostError; + } + } + +error: + return result; +} + + +static signed long GetStreamReadAvailable( PaStream* s ) +{ + PaError result = paNoError; + PaOssStream *stream = (PaOssStream*)s; + audio_buf_info info; + + ENSURE_( ioctl( stream->capture->fd, SNDCTL_DSP_GETISPACE, &info ), paUnanticipatedHostError ); + return info.fragments * stream->capture->hostFrames; + +error: + return result; +} + + +/* TODO: Compute number of allocated bytes somewhere else, can we use ODELAY with capture */ +static signed long GetStreamWriteAvailable( PaStream* s ) +{ + PaError result = paNoError; + PaOssStream *stream = (PaOssStream*)s; + int delay = 0; +#ifdef SNDCTL_DSP_GETODELAY + ENSURE_( ioctl( stream->playback->fd, SNDCTL_DSP_GETODELAY, &delay ), paUnanticipatedHostError ); +#endif + return (PaOssStreamComponent_BufferSize( stream->playback ) - delay) / PaOssStreamComponent_FrameSize( stream->playback ); + +/* Conditionally compile this to avoid warning about unused label */ +#ifdef SNDCTL_DSP_GETODELAY +error: + return result; +#endif +} + diff --git a/extern/portaudio/src/hostapi/oss/recplay.c b/extern/portaudio/src/hostapi/oss/recplay.c new file mode 100644 index 0000000..9d4c78c --- /dev/null +++ b/extern/portaudio/src/hostapi/oss/recplay.c @@ -0,0 +1,114 @@ +/* + * recplay.c + * Phil Burk + * Minimal record and playback test. + * + */ +#include +#include +#include +#ifndef __STDC__ +/* #include */ +#endif /* __STDC__ */ +#include +#ifdef __STDC__ +#include +#else /* __STDC__ */ +#include +#endif /* __STDC__ */ +#include + +#define NUM_BYTES (64*1024) +#define BLOCK_SIZE (4*1024) + +#define AUDIO "/dev/dsp" + +char buffer[NUM_BYTES]; + +int audioDev = 0; + +main (int argc, char *argv[]) +{ + int numLeft; + char *ptr; + int num; + int samplesize; + + /********** RECORD ********************/ + /* Open audio device. */ + audioDev = open (AUDIO, O_RDONLY, 0); + if (audioDev == -1) + { + perror (AUDIO); + exit (-1); + } + + /* Set to 16 bit samples. */ + samplesize = 16; + ioctl(audioDev, SNDCTL_DSP_SAMPLESIZE, &samplesize); + if (samplesize != 16) + { + perror("Unable to set the sample size."); + exit(-1); + } + + /* Record in blocks */ + printf("Begin recording.\n"); + numLeft = NUM_BYTES; + ptr = buffer; + while( numLeft >= BLOCK_SIZE ) + { + if ( (num = read (audioDev, ptr, BLOCK_SIZE)) < 0 ) + { + perror (AUDIO); + exit (-1); + } + else + { + printf("Read %d bytes\n", num); + ptr += num; + numLeft -= num; + } + } + + close( audioDev ); + + /********** PLAYBACK ********************/ + /* Open audio device for writing. */ + audioDev = open (AUDIO, O_WRONLY, 0); + if (audioDev == -1) + { + perror (AUDIO); + exit (-1); + } + + /* Set to 16 bit samples. */ + samplesize = 16; + ioctl(audioDev, SNDCTL_DSP_SAMPLESIZE, &samplesize); + if (samplesize != 16) + { + perror("Unable to set the sample size."); + exit(-1); + } + + /* Play in blocks */ + printf("Begin playing.\n"); + numLeft = NUM_BYTES; + ptr = buffer; + while( numLeft >= BLOCK_SIZE ) + { + if ( (num = write (audioDev, ptr, BLOCK_SIZE)) < 0 ) + { + perror (AUDIO); + exit (-1); + } + else + { + printf("Wrote %d bytes\n", num); + ptr += num; + numLeft -= num; + } + } + + close( audioDev ); +} diff --git a/extern/portaudio/src/hostapi/skeleton/README.txt b/extern/portaudio/src/hostapi/skeleton/README.txt new file mode 100644 index 0000000..39d4c8d --- /dev/null +++ b/extern/portaudio/src/hostapi/skeleton/README.txt @@ -0,0 +1 @@ +pa_hostapi_skeleton.c provides a starting point for implementing support for a new host API with PortAudio. The idea is that you copy it to a new directory inside /hostapi and start editing. \ No newline at end of file diff --git a/extern/portaudio/src/hostapi/skeleton/pa_hostapi_skeleton.c b/extern/portaudio/src/hostapi/skeleton/pa_hostapi_skeleton.c new file mode 100644 index 0000000..6edc22c --- /dev/null +++ b/extern/portaudio/src/hostapi/skeleton/pa_hostapi_skeleton.c @@ -0,0 +1,818 @@ +/* + * $Id$ + * Portable Audio I/O Library skeleton implementation + * demonstrates how to use the common functions to implement support + * for a host API + * + * Based on the Open Source API proposed by Ross Bencina + * Copyright (c) 1999-2002 Ross Bencina, Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +/** @file + @ingroup common_src + + @brief Skeleton implementation of support for a host API. + + This file is provided as a starting point for implementing support for + a new host API. It provides examples of how the common code can be used. + + @note IMPLEMENT ME comments are used to indicate functionality + which much be customised for each implementation. +*/ + + +#include /* strlen() */ + +#include "pa_util.h" +#include "pa_allocation.h" +#include "pa_hostapi.h" +#include "pa_stream.h" +#include "pa_cpuload.h" +#include "pa_process.h" + + +/* prototypes for functions declared in this file */ + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +PaError PaSkeleton_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index ); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +static void Terminate( struct PaUtilHostApiRepresentation *hostApi ); +static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi, + const PaStreamParameters *inputParameters, + const PaStreamParameters *outputParameters, + double sampleRate ); +static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, + PaStream** s, + const PaStreamParameters *inputParameters, + const PaStreamParameters *outputParameters, + double sampleRate, + unsigned long framesPerBuffer, + PaStreamFlags streamFlags, + PaStreamCallback *streamCallback, + void *userData ); +static PaError CloseStream( PaStream* stream ); +static PaError StartStream( PaStream *stream ); +static PaError StopStream( PaStream *stream ); +static PaError AbortStream( PaStream *stream ); +static PaError IsStreamStopped( PaStream *s ); +static PaError IsStreamActive( PaStream *stream ); +static PaTime GetStreamTime( PaStream *stream ); +static double GetStreamCpuLoad( PaStream* stream ); +static PaError ReadStream( PaStream* stream, void *buffer, unsigned long frames ); +static PaError WriteStream( PaStream* stream, const void *buffer, unsigned long frames ); +static signed long GetStreamReadAvailable( PaStream* stream ); +static signed long GetStreamWriteAvailable( PaStream* stream ); + + +/* IMPLEMENT ME: a macro like the following one should be used for reporting + host errors */ +#define PA_SKELETON_SET_LAST_HOST_ERROR( errorCode, errorText ) \ + PaUtil_SetLastHostErrorInfo( paInDevelopment, errorCode, errorText ) + +/* PaSkeletonHostApiRepresentation - host api datastructure specific to this implementation */ + +typedef struct +{ + PaUtilHostApiRepresentation inheritedHostApiRep; + PaUtilStreamInterface callbackStreamInterface; + PaUtilStreamInterface blockingStreamInterface; + + PaUtilAllocationGroup *allocations; + + /* implementation specific data goes here */ +} +PaSkeletonHostApiRepresentation; /* IMPLEMENT ME: rename this */ + + +PaError PaSkeleton_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex ) +{ + PaError result = paNoError; + int i, deviceCount; + PaSkeletonHostApiRepresentation *skeletonHostApi; + PaDeviceInfo *deviceInfoArray; + + skeletonHostApi = (PaSkeletonHostApiRepresentation*)PaUtil_AllocateMemory( sizeof(PaSkeletonHostApiRepresentation) ); + if( !skeletonHostApi ) + { + result = paInsufficientMemory; + goto error; + } + + skeletonHostApi->allocations = PaUtil_CreateAllocationGroup(); + if( !skeletonHostApi->allocations ) + { + result = paInsufficientMemory; + goto error; + } + + *hostApi = &skeletonHostApi->inheritedHostApiRep; + (*hostApi)->info.structVersion = 1; + (*hostApi)->info.type = paInDevelopment; /* IMPLEMENT ME: change to correct type id */ + (*hostApi)->info.name = "skeleton implementation"; /* IMPLEMENT ME: change to correct name */ + + (*hostApi)->info.defaultInputDevice = paNoDevice; /* IMPLEMENT ME */ + (*hostApi)->info.defaultOutputDevice = paNoDevice; /* IMPLEMENT ME */ + + (*hostApi)->info.deviceCount = 0; + + deviceCount = 0; /* IMPLEMENT ME */ + + if( deviceCount > 0 ) + { + (*hostApi)->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory( + skeletonHostApi->allocations, sizeof(PaDeviceInfo*) * deviceCount ); + if( !(*hostApi)->deviceInfos ) + { + result = paInsufficientMemory; + goto error; + } + + /* allocate all device info structs in a contiguous block */ + deviceInfoArray = (PaDeviceInfo*)PaUtil_GroupAllocateMemory( + skeletonHostApi->allocations, sizeof(PaDeviceInfo) * deviceCount ); + if( !deviceInfoArray ) + { + result = paInsufficientMemory; + goto error; + } + + for( i=0; i < deviceCount; ++i ) + { + PaDeviceInfo *deviceInfo = &deviceInfoArray[i]; + deviceInfo->structVersion = 2; + deviceInfo->hostApi = hostApiIndex; + deviceInfo->name = 0; /* IMPLEMENT ME: allocate block and copy name eg: + deviceName = (char*)PaUtil_GroupAllocateMemory( skeletonHostApi->allocations, strlen(srcName) + 1 ); + if( !deviceName ) + { + result = paInsufficientMemory; + goto error; + } + strcpy( deviceName, srcName ); + deviceInfo->name = deviceName; + */ + + deviceInfo->maxInputChannels = 0; /* IMPLEMENT ME */ + deviceInfo->maxOutputChannels = 0; /* IMPLEMENT ME */ + + deviceInfo->defaultLowInputLatency = 0.; /* IMPLEMENT ME */ + deviceInfo->defaultLowOutputLatency = 0.; /* IMPLEMENT ME */ + deviceInfo->defaultHighInputLatency = 0.; /* IMPLEMENT ME */ + deviceInfo->defaultHighOutputLatency = 0.; /* IMPLEMENT ME */ + + deviceInfo->defaultSampleRate = 0.; /* IMPLEMENT ME */ + + (*hostApi)->deviceInfos[i] = deviceInfo; + ++(*hostApi)->info.deviceCount; + } + } + + (*hostApi)->Terminate = Terminate; + (*hostApi)->OpenStream = OpenStream; + (*hostApi)->IsFormatSupported = IsFormatSupported; + + PaUtil_InitializeStreamInterface( &skeletonHostApi->callbackStreamInterface, CloseStream, StartStream, + StopStream, AbortStream, IsStreamStopped, IsStreamActive, + GetStreamTime, GetStreamCpuLoad, + PaUtil_DummyRead, PaUtil_DummyWrite, + PaUtil_DummyGetReadAvailable, PaUtil_DummyGetWriteAvailable ); + + PaUtil_InitializeStreamInterface( &skeletonHostApi->blockingStreamInterface, CloseStream, StartStream, + StopStream, AbortStream, IsStreamStopped, IsStreamActive, + GetStreamTime, PaUtil_DummyGetCpuLoad, + ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable ); + + return result; + +error: + if( skeletonHostApi ) + { + if( skeletonHostApi->allocations ) + { + PaUtil_FreeAllAllocations( skeletonHostApi->allocations ); + PaUtil_DestroyAllocationGroup( skeletonHostApi->allocations ); + } + + PaUtil_FreeMemory( skeletonHostApi ); + } + return result; +} + + +static void Terminate( struct PaUtilHostApiRepresentation *hostApi ) +{ + PaSkeletonHostApiRepresentation *skeletonHostApi = (PaSkeletonHostApiRepresentation*)hostApi; + + /* + IMPLEMENT ME: + - clean up any resources not handled by the allocation group + */ + + if( skeletonHostApi->allocations ) + { + PaUtil_FreeAllAllocations( skeletonHostApi->allocations ); + PaUtil_DestroyAllocationGroup( skeletonHostApi->allocations ); + } + + PaUtil_FreeMemory( skeletonHostApi ); +} + + +static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi, + const PaStreamParameters *inputParameters, + const PaStreamParameters *outputParameters, + double sampleRate ) +{ + int inputChannelCount, outputChannelCount; + PaSampleFormat inputSampleFormat, outputSampleFormat; + + if( inputParameters ) + { + inputChannelCount = inputParameters->channelCount; + inputSampleFormat = inputParameters->sampleFormat; + + /* all standard sample formats are supported by the buffer adapter, + this implementation doesn't support any custom sample formats */ + if( inputSampleFormat & paCustomFormat ) + return paSampleFormatNotSupported; + + /* unless alternate device specification is supported, reject the use of + paUseHostApiSpecificDeviceSpecification */ + + if( inputParameters->device == paUseHostApiSpecificDeviceSpecification ) + return paInvalidDevice; + + /* check that input device can support inputChannelCount */ + if( inputChannelCount > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels ) + return paInvalidChannelCount; + + /* validate inputStreamInfo */ + if( inputParameters->hostApiSpecificStreamInfo ) + return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */ + } + else + { + inputChannelCount = 0; + } + + if( outputParameters ) + { + outputChannelCount = outputParameters->channelCount; + outputSampleFormat = outputParameters->sampleFormat; + + /* all standard sample formats are supported by the buffer adapter, + this implementation doesn't support any custom sample formats */ + if( outputSampleFormat & paCustomFormat ) + return paSampleFormatNotSupported; + + /* unless alternate device specification is supported, reject the use of + paUseHostApiSpecificDeviceSpecification */ + + if( outputParameters->device == paUseHostApiSpecificDeviceSpecification ) + return paInvalidDevice; + + /* check that output device can support outputChannelCount */ + if( outputChannelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels ) + return paInvalidChannelCount; + + /* validate outputStreamInfo */ + if( outputParameters->hostApiSpecificStreamInfo ) + return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */ + } + else + { + outputChannelCount = 0; + } + + /* + IMPLEMENT ME: + + - if a full duplex stream is requested, check that the combination + of input and output parameters is supported if necessary + + - check that the device supports sampleRate + + Because the buffer adapter handles conversion between all standard + sample formats, the following checks are only required if paCustomFormat + is implemented, or under some other unusual conditions. + + - check that input device can support inputSampleFormat, or that + we have the capability to convert from inputSampleFormat to + a native format + + - check that output device can support outputSampleFormat, or that + we have the capability to convert from outputSampleFormat to + a native format + */ + + + /* suppress unused variable warnings */ + (void) sampleRate; + + return paFormatIsSupported; +} + +/* PaSkeletonStream - a stream data structure specifically for this implementation */ + +typedef struct PaSkeletonStream +{ /* IMPLEMENT ME: rename this */ + PaUtilStreamRepresentation streamRepresentation; + PaUtilCpuLoadMeasurer cpuLoadMeasurer; + PaUtilBufferProcessor bufferProcessor; + + /* IMPLEMENT ME: + - implementation specific data goes here + */ + unsigned long framesPerHostCallback; /* just an example */ +} +PaSkeletonStream; + +/* see pa_hostapi.h for a list of validity guarantees made about OpenStream parameters */ + +static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, + PaStream** s, + const PaStreamParameters *inputParameters, + const PaStreamParameters *outputParameters, + double sampleRate, + unsigned long framesPerBuffer, + PaStreamFlags streamFlags, + PaStreamCallback *streamCallback, + void *userData ) +{ + PaError result = paNoError; + PaSkeletonHostApiRepresentation *skeletonHostApi = (PaSkeletonHostApiRepresentation*)hostApi; + PaSkeletonStream *stream = 0; + unsigned long framesPerHostBuffer = framesPerBuffer; /* these may not be equivalent for all implementations */ + int inputChannelCount, outputChannelCount; + PaSampleFormat inputSampleFormat, outputSampleFormat; + PaSampleFormat hostInputSampleFormat, hostOutputSampleFormat; + + + if( inputParameters ) + { + inputChannelCount = inputParameters->channelCount; + inputSampleFormat = inputParameters->sampleFormat; + + /* unless alternate device specification is supported, reject the use of + paUseHostApiSpecificDeviceSpecification */ + + if( inputParameters->device == paUseHostApiSpecificDeviceSpecification ) + return paInvalidDevice; + + /* check that input device can support inputChannelCount */ + if( inputChannelCount > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels ) + return paInvalidChannelCount; + + /* validate inputStreamInfo */ + if( inputParameters->hostApiSpecificStreamInfo ) + return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */ + + /* IMPLEMENT ME - establish which host formats are available */ + hostInputSampleFormat = + PaUtil_SelectClosestAvailableFormat( paInt16 /* native formats */, inputSampleFormat ); + } + else + { + inputChannelCount = 0; + inputSampleFormat = hostInputSampleFormat = paInt16; /* Surpress 'uninitialised var' warnings. */ + } + + if( outputParameters ) + { + outputChannelCount = outputParameters->channelCount; + outputSampleFormat = outputParameters->sampleFormat; + + /* unless alternate device specification is supported, reject the use of + paUseHostApiSpecificDeviceSpecification */ + + if( outputParameters->device == paUseHostApiSpecificDeviceSpecification ) + return paInvalidDevice; + + /* check that output device can support inputChannelCount */ + if( outputChannelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels ) + return paInvalidChannelCount; + + /* validate outputStreamInfo */ + if( outputParameters->hostApiSpecificStreamInfo ) + return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */ + + /* IMPLEMENT ME - establish which host formats are available */ + hostOutputSampleFormat = + PaUtil_SelectClosestAvailableFormat( paInt16 /* native formats */, outputSampleFormat ); + } + else + { + outputChannelCount = 0; + outputSampleFormat = hostOutputSampleFormat = paInt16; /* Surpress 'uninitialized var' warnings. */ + } + + /* + IMPLEMENT ME: + + ( the following two checks are taken care of by PaUtil_InitializeBufferProcessor() FIXME - checks needed? ) + + - check that input device can support inputSampleFormat, or that + we have the capability to convert from outputSampleFormat to + a native format + + - check that output device can support outputSampleFormat, or that + we have the capability to convert from outputSampleFormat to + a native format + + - if a full duplex stream is requested, check that the combination + of input and output parameters is supported + + - check that the device supports sampleRate + + - alter sampleRate to a close allowable rate if possible / necessary + + - validate suggestedInputLatency and suggestedOutputLatency parameters, + use default values where necessary + */ + + + + + /* validate platform specific flags */ + if( (streamFlags & paPlatformSpecificFlags) != 0 ) + return paInvalidFlag; /* unexpected platform specific flag */ + + + stream = (PaSkeletonStream*)PaUtil_AllocateMemory( sizeof(PaSkeletonStream) ); + if( !stream ) + { + result = paInsufficientMemory; + goto error; + } + + if( streamCallback ) + { + PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation, + &skeletonHostApi->callbackStreamInterface, streamCallback, userData ); + } + else + { + PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation, + &skeletonHostApi->blockingStreamInterface, streamCallback, userData ); + } + + PaUtil_InitializeCpuLoadMeasurer( &stream->cpuLoadMeasurer, sampleRate ); + + + /* we assume a fixed host buffer size in this example, but the buffer processor + can also support bounded and unknown host buffer sizes by passing + paUtilBoundedHostBufferSize or paUtilUnknownHostBufferSize instead of + paUtilFixedHostBufferSize below. */ + + result = PaUtil_InitializeBufferProcessor( &stream->bufferProcessor, + inputChannelCount, inputSampleFormat, hostInputSampleFormat, + outputChannelCount, outputSampleFormat, hostOutputSampleFormat, + sampleRate, streamFlags, framesPerBuffer, + framesPerHostBuffer, paUtilFixedHostBufferSize, + streamCallback, userData ); + if( result != paNoError ) + goto error; + + + /* + IMPLEMENT ME: initialise the following fields with estimated or actual + values. + */ + stream->streamRepresentation.streamInfo.inputLatency = + (PaTime)PaUtil_GetBufferProcessorInputLatencyFrames(&stream->bufferProcessor) / sampleRate; /* inputLatency is specified in _seconds_ */ + stream->streamRepresentation.streamInfo.outputLatency = + (PaTime)PaUtil_GetBufferProcessorOutputLatencyFrames(&stream->bufferProcessor) / sampleRate; /* outputLatency is specified in _seconds_ */ + stream->streamRepresentation.streamInfo.sampleRate = sampleRate; + + + /* + IMPLEMENT ME: + - additional stream setup + opening + */ + + stream->framesPerHostCallback = framesPerHostBuffer; + + *s = (PaStream*)stream; + + return result; + +error: + if( stream ) + PaUtil_FreeMemory( stream ); + + return result; +} + +/* + ExampleHostProcessingLoop() illustrates the kind of processing which may + occur in a host implementation. + +*/ +static void ExampleHostProcessingLoop( void *inputBuffer, void *outputBuffer, void *userData ) +{ + PaSkeletonStream *stream = (PaSkeletonStream*)userData; + PaStreamCallbackTimeInfo timeInfo = {0,0,0}; /* IMPLEMENT ME */ + int callbackResult; + unsigned long framesProcessed; + + PaUtil_BeginCpuLoadMeasurement( &stream->cpuLoadMeasurer ); + + /* + IMPLEMENT ME: + - generate timing information + - handle buffer slips + */ + + /* + If you need to byte swap or shift inputBuffer to convert it into a + portaudio format, do it here. + */ + + + + PaUtil_BeginBufferProcessing( &stream->bufferProcessor, &timeInfo, 0 /* IMPLEMENT ME: pass underflow/overflow flags when necessary */ ); + + /* + depending on whether the host buffers are interleaved, non-interleaved + or a mixture, you will want to call PaUtil_SetInterleaved*Channels(), + PaUtil_SetNonInterleaved*Channel() or PaUtil_Set*Channel() here. + */ + + PaUtil_SetInputFrameCount( &stream->bufferProcessor, 0 /* default to host buffer size */ ); + PaUtil_SetInterleavedInputChannels( &stream->bufferProcessor, + 0, /* first channel of inputBuffer is channel 0 */ + inputBuffer, + 0 ); /* 0 - use inputChannelCount passed to init buffer processor */ + + PaUtil_SetOutputFrameCount( &stream->bufferProcessor, 0 /* default to host buffer size */ ); + PaUtil_SetInterleavedOutputChannels( &stream->bufferProcessor, + 0, /* first channel of outputBuffer is channel 0 */ + outputBuffer, + 0 ); /* 0 - use outputChannelCount passed to init buffer processor */ + + /* you must pass a valid value of callback result to PaUtil_EndBufferProcessing() + in general you would pass paContinue for normal operation, and + paComplete to drain the buffer processor's internal output buffer. + You can check whether the buffer processor's output buffer is empty + using PaUtil_IsBufferProcessorOuputEmpty( bufferProcessor ) + */ + callbackResult = paContinue; + framesProcessed = PaUtil_EndBufferProcessing( &stream->bufferProcessor, &callbackResult ); + + + /* + If you need to byte swap or shift outputBuffer to convert it to + host format, do it here. + */ + + PaUtil_EndCpuLoadMeasurement( &stream->cpuLoadMeasurer, framesProcessed ); + + + if( callbackResult == paContinue ) + { + /* nothing special to do */ + } + else if( callbackResult == paAbort ) + { + /* IMPLEMENT ME - finish playback immediately */ + + /* once finished, call the finished callback */ + if( stream->streamRepresentation.streamFinishedCallback != 0 ) + stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData ); + } + else + { + /* User callback has asked us to stop with paComplete or other non-zero value */ + + /* IMPLEMENT ME - finish playback once currently queued audio has completed */ + + /* once finished, call the finished callback */ + if( stream->streamRepresentation.streamFinishedCallback != 0 ) + stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData ); + } +} + + +/* + When CloseStream() is called, the multi-api layer ensures that + the stream has already been stopped or aborted. +*/ +static PaError CloseStream( PaStream* s ) +{ + PaError result = paNoError; + PaSkeletonStream *stream = (PaSkeletonStream*)s; + + /* + IMPLEMENT ME: + - additional stream closing + cleanup + */ + + PaUtil_TerminateBufferProcessor( &stream->bufferProcessor ); + PaUtil_TerminateStreamRepresentation( &stream->streamRepresentation ); + PaUtil_FreeMemory( stream ); + + return result; +} + + +static PaError StartStream( PaStream *s ) +{ + PaError result = paNoError; + PaSkeletonStream *stream = (PaSkeletonStream*)s; + + PaUtil_ResetBufferProcessor( &stream->bufferProcessor ); + + /* IMPLEMENT ME, see portaudio.h for required behavior */ + + /* suppress unused function warning. the code in ExampleHostProcessingLoop or + something similar should be implemented to feed samples to and from the + host after StartStream() is called. + */ + (void) ExampleHostProcessingLoop; + + return result; +} + + +static PaError StopStream( PaStream *s ) +{ + PaError result = paNoError; + PaSkeletonStream *stream = (PaSkeletonStream*)s; + + /* suppress unused variable warnings */ + (void) stream; + + /* IMPLEMENT ME, see portaudio.h for required behavior */ + + return result; +} + + +static PaError AbortStream( PaStream *s ) +{ + PaError result = paNoError; + PaSkeletonStream *stream = (PaSkeletonStream*)s; + + /* suppress unused variable warnings */ + (void) stream; + + /* IMPLEMENT ME, see portaudio.h for required behavior */ + + return result; +} + + +static PaError IsStreamStopped( PaStream *s ) +{ + PaSkeletonStream *stream = (PaSkeletonStream*)s; + + /* suppress unused variable warnings */ + (void) stream; + + /* IMPLEMENT ME, see portaudio.h for required behavior */ + + return 0; +} + + +static PaError IsStreamActive( PaStream *s ) +{ + PaSkeletonStream *stream = (PaSkeletonStream*)s; + + /* suppress unused variable warnings */ + (void) stream; + + /* IMPLEMENT ME, see portaudio.h for required behavior */ + + return 0; +} + + +static PaTime GetStreamTime( PaStream *s ) +{ + PaSkeletonStream *stream = (PaSkeletonStream*)s; + + /* suppress unused variable warnings */ + (void) stream; + + /* IMPLEMENT ME, see portaudio.h for required behavior*/ + + return 0; +} + + +static double GetStreamCpuLoad( PaStream* s ) +{ + PaSkeletonStream *stream = (PaSkeletonStream*)s; + + return PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer ); +} + + +/* + As separate stream interfaces are used for blocking and callback + streams, the following functions can be guaranteed to only be called + for blocking streams. +*/ + +static PaError ReadStream( PaStream* s, + void *buffer, + unsigned long frames ) +{ + PaSkeletonStream *stream = (PaSkeletonStream*)s; + + /* suppress unused variable warnings */ + (void) buffer; + (void) frames; + (void) stream; + + /* IMPLEMENT ME, see portaudio.h for required behavior*/ + + return paNoError; +} + + +static PaError WriteStream( PaStream* s, + const void *buffer, + unsigned long frames ) +{ + PaSkeletonStream *stream = (PaSkeletonStream*)s; + + /* suppress unused variable warnings */ + (void) buffer; + (void) frames; + (void) stream; + + /* IMPLEMENT ME, see portaudio.h for required behavior*/ + + return paNoError; +} + + +static signed long GetStreamReadAvailable( PaStream* s ) +{ + PaSkeletonStream *stream = (PaSkeletonStream*)s; + + /* suppress unused variable warnings */ + (void) stream; + + /* IMPLEMENT ME, see portaudio.h for required behavior*/ + + return 0; +} + + +static signed long GetStreamWriteAvailable( PaStream* s ) +{ + PaSkeletonStream *stream = (PaSkeletonStream*)s; + + /* suppress unused variable warnings */ + (void) stream; + + /* IMPLEMENT ME, see portaudio.h for required behavior*/ + + return 0; +} + + + + diff --git a/extern/portaudio/src/hostapi/wasapi/mingw-include/audioclient.h b/extern/portaudio/src/hostapi/wasapi/mingw-include/audioclient.h new file mode 100644 index 0000000..bf77baf --- /dev/null +++ b/extern/portaudio/src/hostapi/wasapi/mingw-include/audioclient.h @@ -0,0 +1,1177 @@ + + +/* this ALWAYS GENERATED file contains the definitions for the interfaces */ + + + /* File created by MIDL compiler version 7.00.0499 */ +/* Compiler settings for audioclient.idl: + Oicf, W1, Zp8, env=Win32 (32b run) + protocol : dce , ms_ext, c_ext, robust + error checks: allocation ref bounds_check enum stub_data + VC __declspec() decoration level: + __declspec(uuid()), __declspec(selectany), __declspec(novtable) + DECLSPEC_UUID(), MIDL_INTERFACE() +*/ +//@@MIDL_FILE_HEADING( ) + +#pragma warning( disable: 4049 ) /* more than 64k source lines */ + + +/* verify that the version is high enough to compile this file*/ +#ifndef __REQUIRED_RPCNDR_H_VERSION__ +#define __REQUIRED_RPCNDR_H_VERSION__ 500 +#endif + +/* verify that the version is high enough to compile this file*/ +#ifndef __REQUIRED_RPCSAL_H_VERSION__ +#define __REQUIRED_RPCSAL_H_VERSION__ 100 +#endif + +#include "rpc.h" +#include "rpcndr.h" + +#ifndef __RPCNDR_H_VERSION__ +#error this stub requires an updated version of +#endif // __RPCNDR_H_VERSION__ + +#ifndef COM_NO_WINDOWS_H +#include "windows.h" +#include "ole2.h" +#endif /*COM_NO_WINDOWS_H*/ + +#ifndef __audioclient_h__ +#define __audioclient_h__ + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +/* Forward Declarations */ + +#ifndef __IAudioClient_FWD_DEFINED__ +#define __IAudioClient_FWD_DEFINED__ +typedef interface IAudioClient IAudioClient; +#endif /* __IAudioClient_FWD_DEFINED__ */ + + +#ifndef __IAudioRenderClient_FWD_DEFINED__ +#define __IAudioRenderClient_FWD_DEFINED__ +typedef interface IAudioRenderClient IAudioRenderClient; +#endif /* __IAudioRenderClient_FWD_DEFINED__ */ + + +#ifndef __IAudioCaptureClient_FWD_DEFINED__ +#define __IAudioCaptureClient_FWD_DEFINED__ +typedef interface IAudioCaptureClient IAudioCaptureClient; +#endif /* __IAudioCaptureClient_FWD_DEFINED__ */ + + +#ifndef __IAudioClock_FWD_DEFINED__ +#define __IAudioClock_FWD_DEFINED__ +typedef interface IAudioClock IAudioClock; +#endif /* __IAudioClock_FWD_DEFINED__ */ + + +#ifndef __ISimpleAudioVolume_FWD_DEFINED__ +#define __ISimpleAudioVolume_FWD_DEFINED__ +typedef interface ISimpleAudioVolume ISimpleAudioVolume; +#endif /* __ISimpleAudioVolume_FWD_DEFINED__ */ + + +#ifndef __IAudioStreamVolume_FWD_DEFINED__ +#define __IAudioStreamVolume_FWD_DEFINED__ +typedef interface IAudioStreamVolume IAudioStreamVolume; +#endif /* __IAudioStreamVolume_FWD_DEFINED__ */ + + +#ifndef __IChannelAudioVolume_FWD_DEFINED__ +#define __IChannelAudioVolume_FWD_DEFINED__ +typedef interface IChannelAudioVolume IChannelAudioVolume; +#endif /* __IChannelAudioVolume_FWD_DEFINED__ */ + + +/* header files for imported files */ +#include "wtypes.h" +#include "unknwn.h" +#include "AudioSessionTypes.h" + +#ifdef __cplusplus +extern "C"{ +#endif + + +/* interface __MIDL_itf_audioclient_0000_0000 */ +/* [local] */ + +#if 0 +typedef /* [hidden][restricted] */ struct WAVEFORMATEX + { + WORD wFormatTag; + WORD nChannels; + DWORD nSamplesPerSec; + DWORD nAvgBytesPerSec; + WORD nBlockAlign; + WORD wBitsPerSample; + WORD cbSize; + } WAVEFORMATEX; + +#else +#include +#endif +#if 0 +typedef /* [hidden][restricted] */ LONGLONG REFERENCE_TIME; + +#else +#define _IKsControl_ +#include +#include +#endif + +enum _AUDCLNT_BUFFERFLAGS + { AUDCLNT_BUFFERFLAGS_DATA_DISCONTINUITY = 0x1, + AUDCLNT_BUFFERFLAGS_SILENT = 0x2, + AUDCLNT_BUFFERFLAGS_TIMESTAMP_ERROR = 0x4 + } ; + + +extern RPC_IF_HANDLE __MIDL_itf_audioclient_0000_0000_v0_0_c_ifspec; +extern RPC_IF_HANDLE __MIDL_itf_audioclient_0000_0000_v0_0_s_ifspec; + +#ifndef __IAudioClient_INTERFACE_DEFINED__ +#define __IAudioClient_INTERFACE_DEFINED__ + +/* interface IAudioClient */ +/* [local][unique][uuid][object] */ + + +EXTERN_C const IID IID_IAudioClient; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("1CB9AD4C-DBFA-4c32-B178-C2F568A703B2") + IAudioClient : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE Initialize( + /* [in] */ + __in AUDCLNT_SHAREMODE ShareMode, + /* [in] */ + __in DWORD StreamFlags, + /* [in] */ + __in REFERENCE_TIME hnsBufferDuration, + /* [in] */ + __in REFERENCE_TIME hnsPeriodicity, + /* [in] */ + __in const WAVEFORMATEX *pFormat, + /* [in] */ + __in_opt LPCGUID AudioSessionGuid) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetBufferSize( + /* [out] */ + __out UINT32 *pNumBufferFrames) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetStreamLatency( + /* [out] */ + __out REFERENCE_TIME *phnsLatency) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetCurrentPadding( + /* [out] */ + __out UINT32 *pNumPaddingFrames) = 0; + + virtual HRESULT STDMETHODCALLTYPE IsFormatSupported( + /* [in] */ + __in AUDCLNT_SHAREMODE ShareMode, + /* [in] */ + __in const WAVEFORMATEX *pFormat, + /* [unique][out] */ + __out_opt WAVEFORMATEX **ppClosestMatch) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetMixFormat( + /* [out] */ + __out WAVEFORMATEX **ppDeviceFormat) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetDevicePeriod( + /* [out] */ + __out_opt REFERENCE_TIME *phnsDefaultDevicePeriod, + /* [out] */ + __out_opt REFERENCE_TIME *phnsMinimumDevicePeriod) = 0; + + virtual HRESULT STDMETHODCALLTYPE Start( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE Stop( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE Reset( void) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetEventHandle( + /* [in] */ HANDLE eventHandle) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetService( + /* [in] */ + __in REFIID riid, + /* [iid_is][out] */ + __out void **ppv) = 0; + + }; + +#else /* C style interface */ + + typedef struct IAudioClientVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IAudioClient * This, + /* [in] */ REFIID riid, + /* [iid_is][out] */ + __RPC__deref_out void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IAudioClient * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IAudioClient * This); + + HRESULT ( STDMETHODCALLTYPE *Initialize )( + IAudioClient * This, + /* [in] */ + __in AUDCLNT_SHAREMODE ShareMode, + /* [in] */ + __in DWORD StreamFlags, + /* [in] */ + __in REFERENCE_TIME hnsBufferDuration, + /* [in] */ + __in REFERENCE_TIME hnsPeriodicity, + /* [in] */ + __in const WAVEFORMATEX *pFormat, + /* [in] */ + __in_opt LPCGUID AudioSessionGuid); + + HRESULT ( STDMETHODCALLTYPE *GetBufferSize )( + IAudioClient * This, + /* [out] */ + __out UINT32 *pNumBufferFrames); + + HRESULT ( STDMETHODCALLTYPE *GetStreamLatency )( + IAudioClient * This, + /* [out] */ + __out REFERENCE_TIME *phnsLatency); + + HRESULT ( STDMETHODCALLTYPE *GetCurrentPadding )( + IAudioClient * This, + /* [out] */ + __out UINT32 *pNumPaddingFrames); + + HRESULT ( STDMETHODCALLTYPE *IsFormatSupported )( + IAudioClient * This, + /* [in] */ + __in AUDCLNT_SHAREMODE ShareMode, + /* [in] */ + __in const WAVEFORMATEX *pFormat, + /* [unique][out] */ + __out_opt WAVEFORMATEX **ppClosestMatch); + + HRESULT ( STDMETHODCALLTYPE *GetMixFormat )( + IAudioClient * This, + /* [out] */ + __out WAVEFORMATEX **ppDeviceFormat); + + HRESULT ( STDMETHODCALLTYPE *GetDevicePeriod )( + IAudioClient * This, + /* [out] */ + __out_opt REFERENCE_TIME *phnsDefaultDevicePeriod, + /* [out] */ + __out_opt REFERENCE_TIME *phnsMinimumDevicePeriod); + + HRESULT ( STDMETHODCALLTYPE *Start )( + IAudioClient * This); + + HRESULT ( STDMETHODCALLTYPE *Stop )( + IAudioClient * This); + + HRESULT ( STDMETHODCALLTYPE *Reset )( + IAudioClient * This); + + HRESULT ( STDMETHODCALLTYPE *SetEventHandle )( + IAudioClient * This, + /* [in] */ HANDLE eventHandle); + + HRESULT ( STDMETHODCALLTYPE *GetService )( + IAudioClient * This, + /* [in] */ + __in REFIID riid, + /* [iid_is][out] */ + __out void **ppv); + + END_INTERFACE + } IAudioClientVtbl; + + interface IAudioClient + { + CONST_VTBL struct IAudioClientVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IAudioClient_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IAudioClient_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IAudioClient_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IAudioClient_Initialize(This,ShareMode,StreamFlags,hnsBufferDuration,hnsPeriodicity,pFormat,AudioSessionGuid) \ + ( (This)->lpVtbl -> Initialize(This,ShareMode,StreamFlags,hnsBufferDuration,hnsPeriodicity,pFormat,AudioSessionGuid) ) + +#define IAudioClient_GetBufferSize(This,pNumBufferFrames) \ + ( (This)->lpVtbl -> GetBufferSize(This,pNumBufferFrames) ) + +#define IAudioClient_GetStreamLatency(This,phnsLatency) \ + ( (This)->lpVtbl -> GetStreamLatency(This,phnsLatency) ) + +#define IAudioClient_GetCurrentPadding(This,pNumPaddingFrames) \ + ( (This)->lpVtbl -> GetCurrentPadding(This,pNumPaddingFrames) ) + +#define IAudioClient_IsFormatSupported(This,ShareMode,pFormat,ppClosestMatch) \ + ( (This)->lpVtbl -> IsFormatSupported(This,ShareMode,pFormat,ppClosestMatch) ) + +#define IAudioClient_GetMixFormat(This,ppDeviceFormat) \ + ( (This)->lpVtbl -> GetMixFormat(This,ppDeviceFormat) ) + +#define IAudioClient_GetDevicePeriod(This,phnsDefaultDevicePeriod,phnsMinimumDevicePeriod) \ + ( (This)->lpVtbl -> GetDevicePeriod(This,phnsDefaultDevicePeriod,phnsMinimumDevicePeriod) ) + +#define IAudioClient_Start(This) \ + ( (This)->lpVtbl -> Start(This) ) + +#define IAudioClient_Stop(This) \ + ( (This)->lpVtbl -> Stop(This) ) + +#define IAudioClient_Reset(This) \ + ( (This)->lpVtbl -> Reset(This) ) + +#define IAudioClient_SetEventHandle(This,eventHandle) \ + ( (This)->lpVtbl -> SetEventHandle(This,eventHandle) ) + +#define IAudioClient_GetService(This,riid,ppv) \ + ( (This)->lpVtbl -> GetService(This,riid,ppv) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IAudioClient_INTERFACE_DEFINED__ */ + + +#ifndef __IAudioRenderClient_INTERFACE_DEFINED__ +#define __IAudioRenderClient_INTERFACE_DEFINED__ + +/* interface IAudioRenderClient */ +/* [local][unique][helpstring][uuid][object] */ + + +EXTERN_C const IID IID_IAudioRenderClient; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("F294ACFC-3146-4483-A7BF-ADDCA7C260E2") + IAudioRenderClient : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE GetBuffer( + /* [in] */ + __in UINT32 NumFramesRequested, + /* [out] */ + __out BYTE **ppData) = 0; + + virtual HRESULT STDMETHODCALLTYPE ReleaseBuffer( + /* [in] */ + __in UINT32 NumFramesWritten, + /* [in] */ + __in DWORD dwFlags) = 0; + + }; + +#else /* C style interface */ + + typedef struct IAudioRenderClientVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IAudioRenderClient * This, + /* [in] */ REFIID riid, + /* [iid_is][out] */ + __RPC__deref_out void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IAudioRenderClient * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IAudioRenderClient * This); + + HRESULT ( STDMETHODCALLTYPE *GetBuffer )( + IAudioRenderClient * This, + /* [in] */ + __in UINT32 NumFramesRequested, + /* [out] */ + __out BYTE **ppData); + + HRESULT ( STDMETHODCALLTYPE *ReleaseBuffer )( + IAudioRenderClient * This, + /* [in] */ + __in UINT32 NumFramesWritten, + /* [in] */ + __in DWORD dwFlags); + + END_INTERFACE + } IAudioRenderClientVtbl; + + interface IAudioRenderClient + { + CONST_VTBL struct IAudioRenderClientVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IAudioRenderClient_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IAudioRenderClient_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IAudioRenderClient_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IAudioRenderClient_GetBuffer(This,NumFramesRequested,ppData) \ + ( (This)->lpVtbl -> GetBuffer(This,NumFramesRequested,ppData) ) + +#define IAudioRenderClient_ReleaseBuffer(This,NumFramesWritten,dwFlags) \ + ( (This)->lpVtbl -> ReleaseBuffer(This,NumFramesWritten,dwFlags) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IAudioRenderClient_INTERFACE_DEFINED__ */ + + +#ifndef __IAudioCaptureClient_INTERFACE_DEFINED__ +#define __IAudioCaptureClient_INTERFACE_DEFINED__ + +/* interface IAudioCaptureClient */ +/* [local][unique][helpstring][uuid][object] */ + + +EXTERN_C const IID IID_IAudioCaptureClient; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("C8ADBD64-E71E-48a0-A4DE-185C395CD317") + IAudioCaptureClient : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE GetBuffer( + /* [out] */ + __out BYTE **ppData, + /* [out] */ + __out UINT32 *pNumFramesToRead, + /* [out] */ + __out DWORD *pdwFlags, + /* [unique][out] */ + __out_opt UINT64 *pu64DevicePosition, + /* [unique][out] */ + __out_opt UINT64 *pu64QPCPosition) = 0; + + virtual HRESULT STDMETHODCALLTYPE ReleaseBuffer( + /* [in] */ + __in UINT32 NumFramesRead) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetNextPacketSize( + /* [out] */ + __out UINT32 *pNumFramesInNextPacket) = 0; + + }; + +#else /* C style interface */ + + typedef struct IAudioCaptureClientVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IAudioCaptureClient * This, + /* [in] */ REFIID riid, + /* [iid_is][out] */ + __RPC__deref_out void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IAudioCaptureClient * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IAudioCaptureClient * This); + + HRESULT ( STDMETHODCALLTYPE *GetBuffer )( + IAudioCaptureClient * This, + /* [out] */ + __out BYTE **ppData, + /* [out] */ + __out UINT32 *pNumFramesToRead, + /* [out] */ + __out DWORD *pdwFlags, + /* [unique][out] */ + __out_opt UINT64 *pu64DevicePosition, + /* [unique][out] */ + __out_opt UINT64 *pu64QPCPosition); + + HRESULT ( STDMETHODCALLTYPE *ReleaseBuffer )( + IAudioCaptureClient * This, + /* [in] */ + __in UINT32 NumFramesRead); + + HRESULT ( STDMETHODCALLTYPE *GetNextPacketSize )( + IAudioCaptureClient * This, + /* [out] */ + __out UINT32 *pNumFramesInNextPacket); + + END_INTERFACE + } IAudioCaptureClientVtbl; + + interface IAudioCaptureClient + { + CONST_VTBL struct IAudioCaptureClientVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IAudioCaptureClient_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IAudioCaptureClient_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IAudioCaptureClient_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IAudioCaptureClient_GetBuffer(This,ppData,pNumFramesToRead,pdwFlags,pu64DevicePosition,pu64QPCPosition) \ + ( (This)->lpVtbl -> GetBuffer(This,ppData,pNumFramesToRead,pdwFlags,pu64DevicePosition,pu64QPCPosition) ) + +#define IAudioCaptureClient_ReleaseBuffer(This,NumFramesRead) \ + ( (This)->lpVtbl -> ReleaseBuffer(This,NumFramesRead) ) + +#define IAudioCaptureClient_GetNextPacketSize(This,pNumFramesInNextPacket) \ + ( (This)->lpVtbl -> GetNextPacketSize(This,pNumFramesInNextPacket) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IAudioCaptureClient_INTERFACE_DEFINED__ */ + + +/* interface __MIDL_itf_audioclient_0000_0003 */ +/* [local] */ + +#define AUDIOCLOCK_CHARACTERISTIC_FIXED_FREQ 0x00000001 + + +extern RPC_IF_HANDLE __MIDL_itf_audioclient_0000_0003_v0_0_c_ifspec; +extern RPC_IF_HANDLE __MIDL_itf_audioclient_0000_0003_v0_0_s_ifspec; + +#ifndef __IAudioClock_INTERFACE_DEFINED__ +#define __IAudioClock_INTERFACE_DEFINED__ + +/* interface IAudioClock */ +/* [local][unique][uuid][object] */ + + +EXTERN_C const IID IID_IAudioClock; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("CD63314F-3FBA-4a1b-812C-EF96358728E7") + IAudioClock : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE GetFrequency( + /* [out] */ + __out UINT64 *pu64Frequency) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetPosition( + /* [out] */ + __out UINT64 *pu64Position, + /* [unique][out] */ + __out_opt UINT64 *pu64QPCPosition) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetCharacteristics( + /* [out] */ + __out DWORD *pdwCharacteristics) = 0; + + }; + +#else /* C style interface */ + + typedef struct IAudioClockVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IAudioClock * This, + /* [in] */ REFIID riid, + /* [iid_is][out] */ + __RPC__deref_out void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IAudioClock * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IAudioClock * This); + + HRESULT ( STDMETHODCALLTYPE *GetFrequency )( + IAudioClock * This, + /* [out] */ + __out UINT64 *pu64Frequency); + + HRESULT ( STDMETHODCALLTYPE *GetPosition )( + IAudioClock * This, + /* [out] */ + __out UINT64 *pu64Position, + /* [unique][out] */ + __out_opt UINT64 *pu64QPCPosition); + + HRESULT ( STDMETHODCALLTYPE *GetCharacteristics )( + IAudioClock * This, + /* [out] */ + __out DWORD *pdwCharacteristics); + + END_INTERFACE + } IAudioClockVtbl; + + interface IAudioClock + { + CONST_VTBL struct IAudioClockVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IAudioClock_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IAudioClock_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IAudioClock_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IAudioClock_GetFrequency(This,pu64Frequency) \ + ( (This)->lpVtbl -> GetFrequency(This,pu64Frequency) ) + +#define IAudioClock_GetPosition(This,pu64Position,pu64QPCPosition) \ + ( (This)->lpVtbl -> GetPosition(This,pu64Position,pu64QPCPosition) ) + +#define IAudioClock_GetCharacteristics(This,pdwCharacteristics) \ + ( (This)->lpVtbl -> GetCharacteristics(This,pdwCharacteristics) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IAudioClock_INTERFACE_DEFINED__ */ + + +#ifndef __ISimpleAudioVolume_INTERFACE_DEFINED__ +#define __ISimpleAudioVolume_INTERFACE_DEFINED__ + +/* interface ISimpleAudioVolume */ +/* [local][unique][uuid][object] */ + + +EXTERN_C const IID IID_ISimpleAudioVolume; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("87CE5498-68D6-44E5-9215-6DA47EF883D8") + ISimpleAudioVolume : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE SetMasterVolume( + /* [in] */ + __in float fLevel, + /* [unique][in] */ LPCGUID EventContext) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetMasterVolume( + /* [out] */ + __out float *pfLevel) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetMute( + /* [in] */ + __in const BOOL bMute, + /* [unique][in] */ LPCGUID EventContext) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetMute( + /* [out] */ + __out BOOL *pbMute) = 0; + + }; + +#else /* C style interface */ + + typedef struct ISimpleAudioVolumeVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ISimpleAudioVolume * This, + /* [in] */ REFIID riid, + /* [iid_is][out] */ + __RPC__deref_out void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ISimpleAudioVolume * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ISimpleAudioVolume * This); + + HRESULT ( STDMETHODCALLTYPE *SetMasterVolume )( + ISimpleAudioVolume * This, + /* [in] */ + __in float fLevel, + /* [unique][in] */ LPCGUID EventContext); + + HRESULT ( STDMETHODCALLTYPE *GetMasterVolume )( + ISimpleAudioVolume * This, + /* [out] */ + __out float *pfLevel); + + HRESULT ( STDMETHODCALLTYPE *SetMute )( + ISimpleAudioVolume * This, + /* [in] */ + __in const BOOL bMute, + /* [unique][in] */ LPCGUID EventContext); + + HRESULT ( STDMETHODCALLTYPE *GetMute )( + ISimpleAudioVolume * This, + /* [out] */ + __out BOOL *pbMute); + + END_INTERFACE + } ISimpleAudioVolumeVtbl; + + interface ISimpleAudioVolume + { + CONST_VTBL struct ISimpleAudioVolumeVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ISimpleAudioVolume_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ISimpleAudioVolume_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ISimpleAudioVolume_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ISimpleAudioVolume_SetMasterVolume(This,fLevel,EventContext) \ + ( (This)->lpVtbl -> SetMasterVolume(This,fLevel,EventContext) ) + +#define ISimpleAudioVolume_GetMasterVolume(This,pfLevel) \ + ( (This)->lpVtbl -> GetMasterVolume(This,pfLevel) ) + +#define ISimpleAudioVolume_SetMute(This,bMute,EventContext) \ + ( (This)->lpVtbl -> SetMute(This,bMute,EventContext) ) + +#define ISimpleAudioVolume_GetMute(This,pbMute) \ + ( (This)->lpVtbl -> GetMute(This,pbMute) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ISimpleAudioVolume_INTERFACE_DEFINED__ */ + + +#ifndef __IAudioStreamVolume_INTERFACE_DEFINED__ +#define __IAudioStreamVolume_INTERFACE_DEFINED__ + +/* interface IAudioStreamVolume */ +/* [local][unique][uuid][object] */ + + +EXTERN_C const IID IID_IAudioStreamVolume; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("93014887-242D-4068-8A15-CF5E93B90FE3") + IAudioStreamVolume : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE GetChannelCount( + /* [out] */ + __out UINT32 *pdwCount) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetChannelVolume( + /* [in] */ + __in UINT32 dwIndex, + /* [in] */ + __in const float fLevel) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetChannelVolume( + /* [in] */ + __in UINT32 dwIndex, + /* [out] */ + __out float *pfLevel) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetAllVolumes( + /* [in] */ + __in UINT32 dwCount, + /* [size_is][in] */ + __in_ecount(dwCount) const float *pfVolumes) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetAllVolumes( + /* [in] */ + __in UINT32 dwCount, + /* [size_is][out] */ + __out_ecount(dwCount) float *pfVolumes) = 0; + + }; + +#else /* C style interface */ + + typedef struct IAudioStreamVolumeVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IAudioStreamVolume * This, + /* [in] */ REFIID riid, + /* [iid_is][out] */ + __RPC__deref_out void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IAudioStreamVolume * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IAudioStreamVolume * This); + + HRESULT ( STDMETHODCALLTYPE *GetChannelCount )( + IAudioStreamVolume * This, + /* [out] */ + __out UINT32 *pdwCount); + + HRESULT ( STDMETHODCALLTYPE *SetChannelVolume )( + IAudioStreamVolume * This, + /* [in] */ + __in UINT32 dwIndex, + /* [in] */ + __in const float fLevel); + + HRESULT ( STDMETHODCALLTYPE *GetChannelVolume )( + IAudioStreamVolume * This, + /* [in] */ + __in UINT32 dwIndex, + /* [out] */ + __out float *pfLevel); + + HRESULT ( STDMETHODCALLTYPE *SetAllVolumes )( + IAudioStreamVolume * This, + /* [in] */ + __in UINT32 dwCount, + /* [size_is][in] */ + __in_ecount(dwCount) const float *pfVolumes); + + HRESULT ( STDMETHODCALLTYPE *GetAllVolumes )( + IAudioStreamVolume * This, + /* [in] */ + __in UINT32 dwCount, + /* [size_is][out] */ + __out_ecount(dwCount) float *pfVolumes); + + END_INTERFACE + } IAudioStreamVolumeVtbl; + + interface IAudioStreamVolume + { + CONST_VTBL struct IAudioStreamVolumeVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IAudioStreamVolume_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IAudioStreamVolume_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IAudioStreamVolume_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IAudioStreamVolume_GetChannelCount(This,pdwCount) \ + ( (This)->lpVtbl -> GetChannelCount(This,pdwCount) ) + +#define IAudioStreamVolume_SetChannelVolume(This,dwIndex,fLevel) \ + ( (This)->lpVtbl -> SetChannelVolume(This,dwIndex,fLevel) ) + +#define IAudioStreamVolume_GetChannelVolume(This,dwIndex,pfLevel) \ + ( (This)->lpVtbl -> GetChannelVolume(This,dwIndex,pfLevel) ) + +#define IAudioStreamVolume_SetAllVolumes(This,dwCount,pfVolumes) \ + ( (This)->lpVtbl -> SetAllVolumes(This,dwCount,pfVolumes) ) + +#define IAudioStreamVolume_GetAllVolumes(This,dwCount,pfVolumes) \ + ( (This)->lpVtbl -> GetAllVolumes(This,dwCount,pfVolumes) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IAudioStreamVolume_INTERFACE_DEFINED__ */ + + +#ifndef __IChannelAudioVolume_INTERFACE_DEFINED__ +#define __IChannelAudioVolume_INTERFACE_DEFINED__ + +/* interface IChannelAudioVolume */ +/* [local][unique][uuid][object] */ + + +EXTERN_C const IID IID_IChannelAudioVolume; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("1C158861-B533-4B30-B1CF-E853E51C59B8") + IChannelAudioVolume : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE GetChannelCount( + /* [out] */ + __out UINT32 *pdwCount) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetChannelVolume( + /* [in] */ + __in UINT32 dwIndex, + /* [in] */ + __in const float fLevel, + /* [unique][in] */ LPCGUID EventContext) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetChannelVolume( + /* [in] */ + __in UINT32 dwIndex, + /* [out] */ + __out float *pfLevel) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetAllVolumes( + /* [in] */ + __in UINT32 dwCount, + /* [size_is][in] */ + __in_ecount(dwCount) const float *pfVolumes, + /* [unique][in] */ LPCGUID EventContext) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetAllVolumes( + /* [in] */ + __in UINT32 dwCount, + /* [size_is][out] */ + __out_ecount(dwCount) float *pfVolumes) = 0; + + }; + +#else /* C style interface */ + + typedef struct IChannelAudioVolumeVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IChannelAudioVolume * This, + /* [in] */ REFIID riid, + /* [iid_is][out] */ + __RPC__deref_out void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IChannelAudioVolume * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IChannelAudioVolume * This); + + HRESULT ( STDMETHODCALLTYPE *GetChannelCount )( + IChannelAudioVolume * This, + /* [out] */ + __out UINT32 *pdwCount); + + HRESULT ( STDMETHODCALLTYPE *SetChannelVolume )( + IChannelAudioVolume * This, + /* [in] */ + __in UINT32 dwIndex, + /* [in] */ + __in const float fLevel, + /* [unique][in] */ LPCGUID EventContext); + + HRESULT ( STDMETHODCALLTYPE *GetChannelVolume )( + IChannelAudioVolume * This, + /* [in] */ + __in UINT32 dwIndex, + /* [out] */ + __out float *pfLevel); + + HRESULT ( STDMETHODCALLTYPE *SetAllVolumes )( + IChannelAudioVolume * This, + /* [in] */ + __in UINT32 dwCount, + /* [size_is][in] */ + __in_ecount(dwCount) const float *pfVolumes, + /* [unique][in] */ LPCGUID EventContext); + + HRESULT ( STDMETHODCALLTYPE *GetAllVolumes )( + IChannelAudioVolume * This, + /* [in] */ + __in UINT32 dwCount, + /* [size_is][out] */ + __out_ecount(dwCount) float *pfVolumes); + + END_INTERFACE + } IChannelAudioVolumeVtbl; + + interface IChannelAudioVolume + { + CONST_VTBL struct IChannelAudioVolumeVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IChannelAudioVolume_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IChannelAudioVolume_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IChannelAudioVolume_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IChannelAudioVolume_GetChannelCount(This,pdwCount) \ + ( (This)->lpVtbl -> GetChannelCount(This,pdwCount) ) + +#define IChannelAudioVolume_SetChannelVolume(This,dwIndex,fLevel,EventContext) \ + ( (This)->lpVtbl -> SetChannelVolume(This,dwIndex,fLevel,EventContext) ) + +#define IChannelAudioVolume_GetChannelVolume(This,dwIndex,pfLevel) \ + ( (This)->lpVtbl -> GetChannelVolume(This,dwIndex,pfLevel) ) + +#define IChannelAudioVolume_SetAllVolumes(This,dwCount,pfVolumes,EventContext) \ + ( (This)->lpVtbl -> SetAllVolumes(This,dwCount,pfVolumes,EventContext) ) + +#define IChannelAudioVolume_GetAllVolumes(This,dwCount,pfVolumes) \ + ( (This)->lpVtbl -> GetAllVolumes(This,dwCount,pfVolumes) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IChannelAudioVolume_INTERFACE_DEFINED__ */ + + +/* interface __MIDL_itf_audioclient_0000_0007 */ +/* [local] */ + +#define FACILITY_AUDCLNT 0x889 +#define AUDCLNT_ERR(n) MAKE_HRESULT(SEVERITY_ERROR, FACILITY_AUDCLNT, n) +#define AUDCLNT_SUCCESS(n) MAKE_SCODE(SEVERITY_SUCCESS, FACILITY_AUDCLNT, n) +#define AUDCLNT_E_NOT_INITIALIZED AUDCLNT_ERR(0x001) +#define AUDCLNT_E_ALREADY_INITIALIZED AUDCLNT_ERR(0x002) +#define AUDCLNT_E_WRONG_ENDPOINT_TYPE AUDCLNT_ERR(0x003) +#define AUDCLNT_E_DEVICE_INVALIDATED AUDCLNT_ERR(0x004) +#define AUDCLNT_E_NOT_STOPPED AUDCLNT_ERR(0x005) +#define AUDCLNT_E_BUFFER_TOO_LARGE AUDCLNT_ERR(0x006) +#define AUDCLNT_E_OUT_OF_ORDER AUDCLNT_ERR(0x007) +#define AUDCLNT_E_UNSUPPORTED_FORMAT AUDCLNT_ERR(0x008) +#define AUDCLNT_E_INVALID_SIZE AUDCLNT_ERR(0x009) +#define AUDCLNT_E_DEVICE_IN_USE AUDCLNT_ERR(0x00a) +#define AUDCLNT_E_BUFFER_OPERATION_PENDING AUDCLNT_ERR(0x00b) +#define AUDCLNT_E_THREAD_NOT_REGISTERED AUDCLNT_ERR(0x00c) +#define AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED AUDCLNT_ERR(0x00e) +#define AUDCLNT_E_ENDPOINT_CREATE_FAILED AUDCLNT_ERR(0x00f) +#define AUDCLNT_E_SERVICE_NOT_RUNNING AUDCLNT_ERR(0x010) +#define AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED AUDCLNT_ERR(0x011) +#define AUDCLNT_E_EXCLUSIVE_MODE_ONLY AUDCLNT_ERR(0x012) +#define AUDCLNT_E_BUFDURATION_PERIOD_NOT_EQUAL AUDCLNT_ERR(0x013) +#define AUDCLNT_E_EVENTHANDLE_NOT_SET AUDCLNT_ERR(0x014) +#define AUDCLNT_E_INCORRECT_BUFFER_SIZE AUDCLNT_ERR(0x015) +#define AUDCLNT_E_BUFFER_SIZE_ERROR AUDCLNT_ERR(0x016) +#define AUDCLNT_E_CPUUSAGE_EXCEEDED AUDCLNT_ERR(0x017) +#define AUDCLNT_S_BUFFER_EMPTY AUDCLNT_SUCCESS(0x001) +#define AUDCLNT_S_THREAD_ALREADY_REGISTERED AUDCLNT_SUCCESS(0x002) +#define AUDCLNT_S_POSITION_STALLED AUDCLNT_SUCCESS(0x003) + + +extern RPC_IF_HANDLE __MIDL_itf_audioclient_0000_0007_v0_0_c_ifspec; +extern RPC_IF_HANDLE __MIDL_itf_audioclient_0000_0007_v0_0_s_ifspec; + +/* Additional Prototypes for ALL interfaces */ + +/* end of Additional Prototypes */ + +#ifdef __cplusplus +} +#endif + +#endif + + + diff --git a/extern/portaudio/src/hostapi/wasapi/mingw-include/devicetopology.h b/extern/portaudio/src/hostapi/wasapi/mingw-include/devicetopology.h new file mode 100644 index 0000000..7a1f75c --- /dev/null +++ b/extern/portaudio/src/hostapi/wasapi/mingw-include/devicetopology.h @@ -0,0 +1,3275 @@ + + +/* this ALWAYS GENERATED file contains the definitions for the interfaces */ + + + /* File created by MIDL compiler version 7.00.0499 */ +/* Compiler settings for devicetopology.idl: + Oicf, W1, Zp8, env=Win32 (32b run) + protocol : dce , ms_ext, c_ext, robust + error checks: allocation ref bounds_check enum stub_data + VC __declspec() decoration level: + __declspec(uuid()), __declspec(selectany), __declspec(novtable) + DECLSPEC_UUID(), MIDL_INTERFACE() +*/ +//@@MIDL_FILE_HEADING( ) + +#pragma warning( disable: 4049 ) /* more than 64k source lines */ + + +/* verify that the version is high enough to compile this file*/ +#ifndef __REQUIRED_RPCNDR_H_VERSION__ +#define __REQUIRED_RPCNDR_H_VERSION__ 500 +#endif + +/* verify that the version is high enough to compile this file*/ +#ifndef __REQUIRED_RPCSAL_H_VERSION__ +#define __REQUIRED_RPCSAL_H_VERSION__ 100 +#endif + +#include "rpc.h" +#include "rpcndr.h" + +#ifndef __RPCNDR_H_VERSION__ +#error this stub requires an updated version of +#endif // __RPCNDR_H_VERSION__ + +#ifndef COM_NO_WINDOWS_H +#include "windows.h" +#include "ole2.h" +#endif /*COM_NO_WINDOWS_H*/ + +#ifndef __devicetopology_h__ +#define __devicetopology_h__ + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +/* Forward Declarations */ + +#ifndef __IKsControl_FWD_DEFINED__ +#define __IKsControl_FWD_DEFINED__ +typedef interface IKsControl IKsControl; +#endif /* __IKsControl_FWD_DEFINED__ */ + + +#ifndef __IPerChannelDbLevel_FWD_DEFINED__ +#define __IPerChannelDbLevel_FWD_DEFINED__ +typedef interface IPerChannelDbLevel IPerChannelDbLevel; +#endif /* __IPerChannelDbLevel_FWD_DEFINED__ */ + + +#ifndef __IAudioVolumeLevel_FWD_DEFINED__ +#define __IAudioVolumeLevel_FWD_DEFINED__ +typedef interface IAudioVolumeLevel IAudioVolumeLevel; +#endif /* __IAudioVolumeLevel_FWD_DEFINED__ */ + + +#ifndef __IAudioChannelConfig_FWD_DEFINED__ +#define __IAudioChannelConfig_FWD_DEFINED__ +typedef interface IAudioChannelConfig IAudioChannelConfig; +#endif /* __IAudioChannelConfig_FWD_DEFINED__ */ + + +#ifndef __IAudioLoudness_FWD_DEFINED__ +#define __IAudioLoudness_FWD_DEFINED__ +typedef interface IAudioLoudness IAudioLoudness; +#endif /* __IAudioLoudness_FWD_DEFINED__ */ + + +#ifndef __IAudioInputSelector_FWD_DEFINED__ +#define __IAudioInputSelector_FWD_DEFINED__ +typedef interface IAudioInputSelector IAudioInputSelector; +#endif /* __IAudioInputSelector_FWD_DEFINED__ */ + + +#ifndef __IAudioOutputSelector_FWD_DEFINED__ +#define __IAudioOutputSelector_FWD_DEFINED__ +typedef interface IAudioOutputSelector IAudioOutputSelector; +#endif /* __IAudioOutputSelector_FWD_DEFINED__ */ + + +#ifndef __IAudioMute_FWD_DEFINED__ +#define __IAudioMute_FWD_DEFINED__ +typedef interface IAudioMute IAudioMute; +#endif /* __IAudioMute_FWD_DEFINED__ */ + + +#ifndef __IAudioBass_FWD_DEFINED__ +#define __IAudioBass_FWD_DEFINED__ +typedef interface IAudioBass IAudioBass; +#endif /* __IAudioBass_FWD_DEFINED__ */ + + +#ifndef __IAudioMidrange_FWD_DEFINED__ +#define __IAudioMidrange_FWD_DEFINED__ +typedef interface IAudioMidrange IAudioMidrange; +#endif /* __IAudioMidrange_FWD_DEFINED__ */ + + +#ifndef __IAudioTreble_FWD_DEFINED__ +#define __IAudioTreble_FWD_DEFINED__ +typedef interface IAudioTreble IAudioTreble; +#endif /* __IAudioTreble_FWD_DEFINED__ */ + + +#ifndef __IAudioAutoGainControl_FWD_DEFINED__ +#define __IAudioAutoGainControl_FWD_DEFINED__ +typedef interface IAudioAutoGainControl IAudioAutoGainControl; +#endif /* __IAudioAutoGainControl_FWD_DEFINED__ */ + + +#ifndef __IAudioPeakMeter_FWD_DEFINED__ +#define __IAudioPeakMeter_FWD_DEFINED__ +typedef interface IAudioPeakMeter IAudioPeakMeter; +#endif /* __IAudioPeakMeter_FWD_DEFINED__ */ + + +#ifndef __IDeviceSpecificProperty_FWD_DEFINED__ +#define __IDeviceSpecificProperty_FWD_DEFINED__ +typedef interface IDeviceSpecificProperty IDeviceSpecificProperty; +#endif /* __IDeviceSpecificProperty_FWD_DEFINED__ */ + + +#ifndef __IKsFormatSupport_FWD_DEFINED__ +#define __IKsFormatSupport_FWD_DEFINED__ +typedef interface IKsFormatSupport IKsFormatSupport; +#endif /* __IKsFormatSupport_FWD_DEFINED__ */ + + +#ifndef __IKsJackDescription_FWD_DEFINED__ +#define __IKsJackDescription_FWD_DEFINED__ +typedef interface IKsJackDescription IKsJackDescription; +#endif /* __IKsJackDescription_FWD_DEFINED__ */ + + +#ifndef __IPartsList_FWD_DEFINED__ +#define __IPartsList_FWD_DEFINED__ +typedef interface IPartsList IPartsList; +#endif /* __IPartsList_FWD_DEFINED__ */ + + +#ifndef __IPart_FWD_DEFINED__ +#define __IPart_FWD_DEFINED__ +typedef interface IPart IPart; +#endif /* __IPart_FWD_DEFINED__ */ + + +#ifndef __IConnector_FWD_DEFINED__ +#define __IConnector_FWD_DEFINED__ +typedef interface IConnector IConnector; +#endif /* __IConnector_FWD_DEFINED__ */ + + +#ifndef __ISubunit_FWD_DEFINED__ +#define __ISubunit_FWD_DEFINED__ +typedef interface ISubunit ISubunit; +#endif /* __ISubunit_FWD_DEFINED__ */ + + +#ifndef __IControlInterface_FWD_DEFINED__ +#define __IControlInterface_FWD_DEFINED__ +typedef interface IControlInterface IControlInterface; +#endif /* __IControlInterface_FWD_DEFINED__ */ + + +#ifndef __IControlChangeNotify_FWD_DEFINED__ +#define __IControlChangeNotify_FWD_DEFINED__ +typedef interface IControlChangeNotify IControlChangeNotify; +#endif /* __IControlChangeNotify_FWD_DEFINED__ */ + + +#ifndef __IDeviceTopology_FWD_DEFINED__ +#define __IDeviceTopology_FWD_DEFINED__ +typedef interface IDeviceTopology IDeviceTopology; +#endif /* __IDeviceTopology_FWD_DEFINED__ */ + + +#ifndef __DeviceTopology_FWD_DEFINED__ +#define __DeviceTopology_FWD_DEFINED__ + +#ifdef __cplusplus +typedef class DeviceTopology DeviceTopology; +#else +typedef struct DeviceTopology DeviceTopology; +#endif /* __cplusplus */ + +#endif /* __DeviceTopology_FWD_DEFINED__ */ + + +#ifndef __IPartsList_FWD_DEFINED__ +#define __IPartsList_FWD_DEFINED__ +typedef interface IPartsList IPartsList; +#endif /* __IPartsList_FWD_DEFINED__ */ + + +#ifndef __IPerChannelDbLevel_FWD_DEFINED__ +#define __IPerChannelDbLevel_FWD_DEFINED__ +typedef interface IPerChannelDbLevel IPerChannelDbLevel; +#endif /* __IPerChannelDbLevel_FWD_DEFINED__ */ + + +#ifndef __IAudioVolumeLevel_FWD_DEFINED__ +#define __IAudioVolumeLevel_FWD_DEFINED__ +typedef interface IAudioVolumeLevel IAudioVolumeLevel; +#endif /* __IAudioVolumeLevel_FWD_DEFINED__ */ + + +#ifndef __IAudioLoudness_FWD_DEFINED__ +#define __IAudioLoudness_FWD_DEFINED__ +typedef interface IAudioLoudness IAudioLoudness; +#endif /* __IAudioLoudness_FWD_DEFINED__ */ + + +#ifndef __IAudioInputSelector_FWD_DEFINED__ +#define __IAudioInputSelector_FWD_DEFINED__ +typedef interface IAudioInputSelector IAudioInputSelector; +#endif /* __IAudioInputSelector_FWD_DEFINED__ */ + + +#ifndef __IAudioMute_FWD_DEFINED__ +#define __IAudioMute_FWD_DEFINED__ +typedef interface IAudioMute IAudioMute; +#endif /* __IAudioMute_FWD_DEFINED__ */ + + +#ifndef __IAudioBass_FWD_DEFINED__ +#define __IAudioBass_FWD_DEFINED__ +typedef interface IAudioBass IAudioBass; +#endif /* __IAudioBass_FWD_DEFINED__ */ + + +#ifndef __IAudioMidrange_FWD_DEFINED__ +#define __IAudioMidrange_FWD_DEFINED__ +typedef interface IAudioMidrange IAudioMidrange; +#endif /* __IAudioMidrange_FWD_DEFINED__ */ + + +#ifndef __IAudioTreble_FWD_DEFINED__ +#define __IAudioTreble_FWD_DEFINED__ +typedef interface IAudioTreble IAudioTreble; +#endif /* __IAudioTreble_FWD_DEFINED__ */ + + +#ifndef __IAudioAutoGainControl_FWD_DEFINED__ +#define __IAudioAutoGainControl_FWD_DEFINED__ +typedef interface IAudioAutoGainControl IAudioAutoGainControl; +#endif /* __IAudioAutoGainControl_FWD_DEFINED__ */ + + +#ifndef __IAudioOutputSelector_FWD_DEFINED__ +#define __IAudioOutputSelector_FWD_DEFINED__ +typedef interface IAudioOutputSelector IAudioOutputSelector; +#endif /* __IAudioOutputSelector_FWD_DEFINED__ */ + + +#ifndef __IAudioPeakMeter_FWD_DEFINED__ +#define __IAudioPeakMeter_FWD_DEFINED__ +typedef interface IAudioPeakMeter IAudioPeakMeter; +#endif /* __IAudioPeakMeter_FWD_DEFINED__ */ + + +#ifndef __IDeviceSpecificProperty_FWD_DEFINED__ +#define __IDeviceSpecificProperty_FWD_DEFINED__ +typedef interface IDeviceSpecificProperty IDeviceSpecificProperty; +#endif /* __IDeviceSpecificProperty_FWD_DEFINED__ */ + + +#ifndef __IKsFormatSupport_FWD_DEFINED__ +#define __IKsFormatSupport_FWD_DEFINED__ +typedef interface IKsFormatSupport IKsFormatSupport; +#endif /* __IKsFormatSupport_FWD_DEFINED__ */ + + +/* header files for imported files */ +#include "oaidl.h" +#include "ocidl.h" +#include "propidl.h" + +#ifdef __cplusplus +extern "C"{ +#endif + + +/* interface __MIDL_itf_devicetopology_0000_0000 */ +/* [local] */ + +#define E_NOTFOUND HRESULT_FROM_WIN32(ERROR_NOT_FOUND) +// +// Flag for clients of IControlChangeNotify::OnNotify to allow those clients to identify hardware initiated notifications +// +#define DEVTOPO_HARDWARE_INITIATED_EVENTCONTEXT 'draH' +/* E2C2E9DE-09B1-4B04-84E5-07931225EE04 */ +DEFINE_GUID(EVENTCONTEXT_VOLUMESLIDER, 0xE2C2E9DE,0x09B1,0x4B04,0x84, 0xE5, 0x07, 0x93, 0x12, 0x25, 0xEE, 0x04); +#define _IKsControl_ +#include "ks.h" +#include "ksmedia.h" +#ifndef _KS_ +typedef /* [public] */ struct __MIDL___MIDL_itf_devicetopology_0000_0000_0001 + { + ULONG FormatSize; + ULONG Flags; + ULONG SampleSize; + ULONG Reserved; + GUID MajorFormat; + GUID SubFormat; + GUID Specifier; + } KSDATAFORMAT; + +typedef struct __MIDL___MIDL_itf_devicetopology_0000_0000_0001 *PKSDATAFORMAT; + +typedef /* [public][public][public][public][public][public][public][public][public][public] */ struct __MIDL___MIDL_itf_devicetopology_0000_0000_0002 + { + union + { + struct + { + GUID Set; + ULONG Id; + ULONG Flags; + } ; + LONGLONG Alignment; + } ; + } KSIDENTIFIER; + +typedef struct __MIDL___MIDL_itf_devicetopology_0000_0000_0002 *PKSIDENTIFIER; + +typedef /* [public][public][public][public] */ +enum __MIDL___MIDL_itf_devicetopology_0000_0000_0005 + { ePcxChanMap_FL_FR = 0, + ePcxChanMap_FC_LFE = ( ePcxChanMap_FL_FR + 1 ) , + ePcxChanMap_BL_BR = ( ePcxChanMap_FC_LFE + 1 ) , + ePcxChanMap_FLC_FRC = ( ePcxChanMap_BL_BR + 1 ) , + ePcxChanMap_SL_SR = ( ePcxChanMap_FLC_FRC + 1 ) , + ePcxChanMap_Unknown = ( ePcxChanMap_SL_SR + 1 ) + } EChannelMapping; + +typedef /* [public][public][public][public] */ +enum __MIDL___MIDL_itf_devicetopology_0000_0000_0006 + { eConnTypeUnknown = 0, + eConnTypeEighth = ( eConnTypeUnknown + 1 ) , + eConnTypeQuarter = ( eConnTypeEighth + 1 ) , + eConnTypeAtapiInternal = ( eConnTypeQuarter + 1 ) , + eConnTypeRCA = ( eConnTypeAtapiInternal + 1 ) , + eConnTypeOptical = ( eConnTypeRCA + 1 ) , + eConnTypeOtherDigital = ( eConnTypeOptical + 1 ) , + eConnTypeOtherAnalog = ( eConnTypeOtherDigital + 1 ) , + eConnTypeMultichannelAnalogDIN = ( eConnTypeOtherAnalog + 1 ) , + eConnTypeXlrProfessional = ( eConnTypeMultichannelAnalogDIN + 1 ) , + eConnTypeRJ11Modem = ( eConnTypeXlrProfessional + 1 ) , + eConnTypeCombination = ( eConnTypeRJ11Modem + 1 ) + } EPcxConnectionType; + +typedef /* [public][public][public][public] */ +enum __MIDL___MIDL_itf_devicetopology_0000_0000_0007 + { eGeoLocRear = 0x1, + eGeoLocFront = ( eGeoLocRear + 1 ) , + eGeoLocLeft = ( eGeoLocFront + 1 ) , + eGeoLocRight = ( eGeoLocLeft + 1 ) , + eGeoLocTop = ( eGeoLocRight + 1 ) , + eGeoLocBottom = ( eGeoLocTop + 1 ) , + eGeoLocRearOPanel = ( eGeoLocBottom + 1 ) , + eGeoLocRiser = ( eGeoLocRearOPanel + 1 ) , + eGeoLocInsideMobileLid = ( eGeoLocRiser + 1 ) , + eGeoLocDrivebay = ( eGeoLocInsideMobileLid + 1 ) , + eGeoLocHDMI = ( eGeoLocDrivebay + 1 ) , + eGeoLocOutsideMobileLid = ( eGeoLocHDMI + 1 ) , + eGeoLocATAPI = ( eGeoLocOutsideMobileLid + 1 ) , + eGeoLocReserved5 = ( eGeoLocATAPI + 1 ) , + eGeoLocReserved6 = ( eGeoLocReserved5 + 1 ) + } EPcxGeoLocation; + +typedef /* [public][public][public][public] */ +enum __MIDL___MIDL_itf_devicetopology_0000_0000_0008 + { eGenLocPrimaryBox = 0, + eGenLocInternal = ( eGenLocPrimaryBox + 1 ) , + eGenLocSeperate = ( eGenLocInternal + 1 ) , + eGenLocOther = ( eGenLocSeperate + 1 ) + } EPcxGenLocation; + +typedef /* [public][public][public][public] */ +enum __MIDL___MIDL_itf_devicetopology_0000_0000_0009 + { ePortConnJack = 0, + ePortConnIntegratedDevice = ( ePortConnJack + 1 ) , + ePortConnBothIntegratedAndJack = ( ePortConnIntegratedDevice + 1 ) , + ePortConnUnknown = ( ePortConnBothIntegratedAndJack + 1 ) + } EPxcPortConnection; + +typedef /* [public][public] */ struct __MIDL___MIDL_itf_devicetopology_0000_0000_0010 + { + EChannelMapping ChannelMapping; + COLORREF Color; + EPcxConnectionType ConnectionType; + EPcxGeoLocation GeoLocation; + EPcxGenLocation GenLocation; + EPxcPortConnection PortConnection; + BOOL IsConnected; + } KSJACK_DESCRIPTION; + +typedef struct __MIDL___MIDL_itf_devicetopology_0000_0000_0010 *PKSJACK_DESCRIPTION; + +typedef KSIDENTIFIER KSPROPERTY; + +typedef KSIDENTIFIER *PKSPROPERTY; + +typedef KSIDENTIFIER KSMETHOD; + +typedef KSIDENTIFIER *PKSMETHOD; + +typedef KSIDENTIFIER KSEVENT; + +typedef KSIDENTIFIER *PKSEVENT; + +#endif + + + + + + + + +typedef /* [public][public] */ +enum __MIDL___MIDL_itf_devicetopology_0000_0000_0011 + { In = 0, + Out = ( In + 1 ) + } DataFlow; + +typedef /* [public][public] */ +enum __MIDL___MIDL_itf_devicetopology_0000_0000_0012 + { Connector = 0, + Subunit = ( Connector + 1 ) + } PartType; + +#define PARTTYPE_FLAG_CONNECTOR 0x00010000 +#define PARTTYPE_FLAG_SUBUNIT 0x00020000 +#define PARTTYPE_MASK 0x00030000 +#define PARTID_MASK 0x0000ffff +typedef /* [public][public] */ +enum __MIDL___MIDL_itf_devicetopology_0000_0000_0013 + { Unknown_Connector = 0, + Physical_Internal = ( Unknown_Connector + 1 ) , + Physical_External = ( Physical_Internal + 1 ) , + Software_IO = ( Physical_External + 1 ) , + Software_Fixed = ( Software_IO + 1 ) , + Network = ( Software_Fixed + 1 ) + } ConnectorType; + + + +extern RPC_IF_HANDLE __MIDL_itf_devicetopology_0000_0000_v0_0_c_ifspec; +extern RPC_IF_HANDLE __MIDL_itf_devicetopology_0000_0000_v0_0_s_ifspec; + +#ifndef __IKsControl_INTERFACE_DEFINED__ +#define __IKsControl_INTERFACE_DEFINED__ + +/* interface IKsControl */ +/* [unique][helpstring][nonextensible][uuid][local][object] */ + + +EXTERN_C const IID IID_IKsControl; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("28F54685-06FD-11D2-B27A-00A0C9223196") + IKsControl : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE KsProperty( + /* [in] */ PKSPROPERTY Property, + /* [in] */ ULONG PropertyLength, + /* [out][in] */ void *PropertyData, + /* [in] */ ULONG DataLength, + /* [out] */ ULONG *BytesReturned) = 0; + + virtual HRESULT STDMETHODCALLTYPE KsMethod( + /* [in] */ PKSMETHOD Method, + /* [in] */ ULONG MethodLength, + /* [out][in] */ void *MethodData, + /* [in] */ ULONG DataLength, + /* [out] */ ULONG *BytesReturned) = 0; + + virtual HRESULT STDMETHODCALLTYPE KsEvent( + /* [in] */ PKSEVENT Event, + /* [in] */ ULONG EventLength, + /* [out][in] */ void *EventData, + /* [in] */ ULONG DataLength, + /* [out] */ ULONG *BytesReturned) = 0; + + }; + +#else /* C style interface */ + + typedef struct IKsControlVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IKsControl * This, + /* [in] */ REFIID riid, + /* [iid_is][out] */ + __RPC__deref_out void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IKsControl * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IKsControl * This); + + HRESULT ( STDMETHODCALLTYPE *KsProperty )( + IKsControl * This, + /* [in] */ PKSPROPERTY Property, + /* [in] */ ULONG PropertyLength, + /* [out][in] */ void *PropertyData, + /* [in] */ ULONG DataLength, + /* [out] */ ULONG *BytesReturned); + + HRESULT ( STDMETHODCALLTYPE *KsMethod )( + IKsControl * This, + /* [in] */ PKSMETHOD Method, + /* [in] */ ULONG MethodLength, + /* [out][in] */ void *MethodData, + /* [in] */ ULONG DataLength, + /* [out] */ ULONG *BytesReturned); + + HRESULT ( STDMETHODCALLTYPE *KsEvent )( + IKsControl * This, + /* [in] */ PKSEVENT Event, + /* [in] */ ULONG EventLength, + /* [out][in] */ void *EventData, + /* [in] */ ULONG DataLength, + /* [out] */ ULONG *BytesReturned); + + END_INTERFACE + } IKsControlVtbl; + + interface IKsControl + { + CONST_VTBL struct IKsControlVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IKsControl_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IKsControl_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IKsControl_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IKsControl_KsProperty(This,Property,PropertyLength,PropertyData,DataLength,BytesReturned) \ + ( (This)->lpVtbl -> KsProperty(This,Property,PropertyLength,PropertyData,DataLength,BytesReturned) ) + +#define IKsControl_KsMethod(This,Method,MethodLength,MethodData,DataLength,BytesReturned) \ + ( (This)->lpVtbl -> KsMethod(This,Method,MethodLength,MethodData,DataLength,BytesReturned) ) + +#define IKsControl_KsEvent(This,Event,EventLength,EventData,DataLength,BytesReturned) \ + ( (This)->lpVtbl -> KsEvent(This,Event,EventLength,EventData,DataLength,BytesReturned) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IKsControl_INTERFACE_DEFINED__ */ + + +#ifndef __IPerChannelDbLevel_INTERFACE_DEFINED__ +#define __IPerChannelDbLevel_INTERFACE_DEFINED__ + +/* interface IPerChannelDbLevel */ +/* [unique][helpstring][nonextensible][uuid][local][object] */ + + +EXTERN_C const IID IID_IPerChannelDbLevel; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("C2F8E001-F205-4BC9-99BC-C13B1E048CCB") + IPerChannelDbLevel : public IUnknown + { + public: + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE GetChannelCount( + /* [out] */ + __out UINT *pcChannels) = 0; + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE GetLevelRange( + /* [in] */ + __in UINT nChannel, + /* [out] */ + __out float *pfMinLevelDB, + /* [out] */ + __out float *pfMaxLevelDB, + /* [out] */ + __out float *pfStepping) = 0; + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE GetLevel( + /* [in] */ + __in UINT nChannel, + /* [out] */ + __out float *pfLevelDB) = 0; + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE SetLevel( + /* [in] */ + __in UINT nChannel, + /* [in] */ + __in float fLevelDB, + /* [unique][in] */ + __in_opt LPCGUID pguidEventContext) = 0; + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE SetLevelUniform( + /* [in] */ + __in float fLevelDB, + /* [unique][in] */ + __in_opt LPCGUID pguidEventContext) = 0; + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE SetLevelAllChannels( + /* [size_is][in] */ + __in_ecount(cChannels) float aLevelsDB[ ], + /* [in] */ + __in ULONG cChannels, + /* [unique][in] */ + __in_opt LPCGUID pguidEventContext) = 0; + + }; + +#else /* C style interface */ + + typedef struct IPerChannelDbLevelVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IPerChannelDbLevel * This, + /* [in] */ REFIID riid, + /* [iid_is][out] */ + __RPC__deref_out void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IPerChannelDbLevel * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IPerChannelDbLevel * This); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *GetChannelCount )( + IPerChannelDbLevel * This, + /* [out] */ + __out UINT *pcChannels); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *GetLevelRange )( + IPerChannelDbLevel * This, + /* [in] */ + __in UINT nChannel, + /* [out] */ + __out float *pfMinLevelDB, + /* [out] */ + __out float *pfMaxLevelDB, + /* [out] */ + __out float *pfStepping); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *GetLevel )( + IPerChannelDbLevel * This, + /* [in] */ + __in UINT nChannel, + /* [out] */ + __out float *pfLevelDB); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *SetLevel )( + IPerChannelDbLevel * This, + /* [in] */ + __in UINT nChannel, + /* [in] */ + __in float fLevelDB, + /* [unique][in] */ + __in_opt LPCGUID pguidEventContext); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *SetLevelUniform )( + IPerChannelDbLevel * This, + /* [in] */ + __in float fLevelDB, + /* [unique][in] */ + __in_opt LPCGUID pguidEventContext); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *SetLevelAllChannels )( + IPerChannelDbLevel * This, + /* [size_is][in] */ + __in_ecount(cChannels) float aLevelsDB[ ], + /* [in] */ + __in ULONG cChannels, + /* [unique][in] */ + __in_opt LPCGUID pguidEventContext); + + END_INTERFACE + } IPerChannelDbLevelVtbl; + + interface IPerChannelDbLevel + { + CONST_VTBL struct IPerChannelDbLevelVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IPerChannelDbLevel_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IPerChannelDbLevel_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IPerChannelDbLevel_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IPerChannelDbLevel_GetChannelCount(This,pcChannels) \ + ( (This)->lpVtbl -> GetChannelCount(This,pcChannels) ) + +#define IPerChannelDbLevel_GetLevelRange(This,nChannel,pfMinLevelDB,pfMaxLevelDB,pfStepping) \ + ( (This)->lpVtbl -> GetLevelRange(This,nChannel,pfMinLevelDB,pfMaxLevelDB,pfStepping) ) + +#define IPerChannelDbLevel_GetLevel(This,nChannel,pfLevelDB) \ + ( (This)->lpVtbl -> GetLevel(This,nChannel,pfLevelDB) ) + +#define IPerChannelDbLevel_SetLevel(This,nChannel,fLevelDB,pguidEventContext) \ + ( (This)->lpVtbl -> SetLevel(This,nChannel,fLevelDB,pguidEventContext) ) + +#define IPerChannelDbLevel_SetLevelUniform(This,fLevelDB,pguidEventContext) \ + ( (This)->lpVtbl -> SetLevelUniform(This,fLevelDB,pguidEventContext) ) + +#define IPerChannelDbLevel_SetLevelAllChannels(This,aLevelsDB,cChannels,pguidEventContext) \ + ( (This)->lpVtbl -> SetLevelAllChannels(This,aLevelsDB,cChannels,pguidEventContext) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IPerChannelDbLevel_INTERFACE_DEFINED__ */ + + +#ifndef __IAudioVolumeLevel_INTERFACE_DEFINED__ +#define __IAudioVolumeLevel_INTERFACE_DEFINED__ + +/* interface IAudioVolumeLevel */ +/* [unique][helpstring][nonextensible][uuid][local][object] */ + + +EXTERN_C const IID IID_IAudioVolumeLevel; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("7FB7B48F-531D-44A2-BCB3-5AD5A134B3DC") + IAudioVolumeLevel : public IPerChannelDbLevel + { + public: + }; + +#else /* C style interface */ + + typedef struct IAudioVolumeLevelVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IAudioVolumeLevel * This, + /* [in] */ REFIID riid, + /* [iid_is][out] */ + __RPC__deref_out void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IAudioVolumeLevel * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IAudioVolumeLevel * This); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *GetChannelCount )( + IAudioVolumeLevel * This, + /* [out] */ + __out UINT *pcChannels); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *GetLevelRange )( + IAudioVolumeLevel * This, + /* [in] */ + __in UINT nChannel, + /* [out] */ + __out float *pfMinLevelDB, + /* [out] */ + __out float *pfMaxLevelDB, + /* [out] */ + __out float *pfStepping); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *GetLevel )( + IAudioVolumeLevel * This, + /* [in] */ + __in UINT nChannel, + /* [out] */ + __out float *pfLevelDB); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *SetLevel )( + IAudioVolumeLevel * This, + /* [in] */ + __in UINT nChannel, + /* [in] */ + __in float fLevelDB, + /* [unique][in] */ + __in_opt LPCGUID pguidEventContext); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *SetLevelUniform )( + IAudioVolumeLevel * This, + /* [in] */ + __in float fLevelDB, + /* [unique][in] */ + __in_opt LPCGUID pguidEventContext); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *SetLevelAllChannels )( + IAudioVolumeLevel * This, + /* [size_is][in] */ + __in_ecount(cChannels) float aLevelsDB[ ], + /* [in] */ + __in ULONG cChannels, + /* [unique][in] */ + __in_opt LPCGUID pguidEventContext); + + END_INTERFACE + } IAudioVolumeLevelVtbl; + + interface IAudioVolumeLevel + { + CONST_VTBL struct IAudioVolumeLevelVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IAudioVolumeLevel_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IAudioVolumeLevel_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IAudioVolumeLevel_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IAudioVolumeLevel_GetChannelCount(This,pcChannels) \ + ( (This)->lpVtbl -> GetChannelCount(This,pcChannels) ) + +#define IAudioVolumeLevel_GetLevelRange(This,nChannel,pfMinLevelDB,pfMaxLevelDB,pfStepping) \ + ( (This)->lpVtbl -> GetLevelRange(This,nChannel,pfMinLevelDB,pfMaxLevelDB,pfStepping) ) + +#define IAudioVolumeLevel_GetLevel(This,nChannel,pfLevelDB) \ + ( (This)->lpVtbl -> GetLevel(This,nChannel,pfLevelDB) ) + +#define IAudioVolumeLevel_SetLevel(This,nChannel,fLevelDB,pguidEventContext) \ + ( (This)->lpVtbl -> SetLevel(This,nChannel,fLevelDB,pguidEventContext) ) + +#define IAudioVolumeLevel_SetLevelUniform(This,fLevelDB,pguidEventContext) \ + ( (This)->lpVtbl -> SetLevelUniform(This,fLevelDB,pguidEventContext) ) + +#define IAudioVolumeLevel_SetLevelAllChannels(This,aLevelsDB,cChannels,pguidEventContext) \ + ( (This)->lpVtbl -> SetLevelAllChannels(This,aLevelsDB,cChannels,pguidEventContext) ) + + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IAudioVolumeLevel_INTERFACE_DEFINED__ */ + + +#ifndef __IAudioChannelConfig_INTERFACE_DEFINED__ +#define __IAudioChannelConfig_INTERFACE_DEFINED__ + +/* interface IAudioChannelConfig */ +/* [unique][helpstring][nonextensible][uuid][local][object] */ + + +EXTERN_C const IID IID_IAudioChannelConfig; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("BB11C46F-EC28-493C-B88A-5DB88062CE98") + IAudioChannelConfig : public IUnknown + { + public: + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE SetChannelConfig( + /* [in] */ DWORD dwConfig, + /* [unique][in] */ + __in_opt LPCGUID pguidEventContext) = 0; + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE GetChannelConfig( + /* [retval][out] */ DWORD *pdwConfig) = 0; + + }; + +#else /* C style interface */ + + typedef struct IAudioChannelConfigVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IAudioChannelConfig * This, + /* [in] */ REFIID riid, + /* [iid_is][out] */ + __RPC__deref_out void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IAudioChannelConfig * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IAudioChannelConfig * This); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *SetChannelConfig )( + IAudioChannelConfig * This, + /* [in] */ DWORD dwConfig, + /* [unique][in] */ + __in_opt LPCGUID pguidEventContext); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *GetChannelConfig )( + IAudioChannelConfig * This, + /* [retval][out] */ DWORD *pdwConfig); + + END_INTERFACE + } IAudioChannelConfigVtbl; + + interface IAudioChannelConfig + { + CONST_VTBL struct IAudioChannelConfigVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IAudioChannelConfig_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IAudioChannelConfig_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IAudioChannelConfig_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IAudioChannelConfig_SetChannelConfig(This,dwConfig,pguidEventContext) \ + ( (This)->lpVtbl -> SetChannelConfig(This,dwConfig,pguidEventContext) ) + +#define IAudioChannelConfig_GetChannelConfig(This,pdwConfig) \ + ( (This)->lpVtbl -> GetChannelConfig(This,pdwConfig) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IAudioChannelConfig_INTERFACE_DEFINED__ */ + + +#ifndef __IAudioLoudness_INTERFACE_DEFINED__ +#define __IAudioLoudness_INTERFACE_DEFINED__ + +/* interface IAudioLoudness */ +/* [unique][helpstring][nonextensible][uuid][local][object] */ + + +EXTERN_C const IID IID_IAudioLoudness; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("7D8B1437-DD53-4350-9C1B-1EE2890BD938") + IAudioLoudness : public IUnknown + { + public: + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE GetEnabled( + /* [out] */ + __out BOOL *pbEnabled) = 0; + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE SetEnabled( + /* [in] */ + __in BOOL bEnable, + /* [unique][in] */ + __in_opt LPCGUID pguidEventContext) = 0; + + }; + +#else /* C style interface */ + + typedef struct IAudioLoudnessVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IAudioLoudness * This, + /* [in] */ REFIID riid, + /* [iid_is][out] */ + __RPC__deref_out void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IAudioLoudness * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IAudioLoudness * This); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *GetEnabled )( + IAudioLoudness * This, + /* [out] */ + __out BOOL *pbEnabled); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *SetEnabled )( + IAudioLoudness * This, + /* [in] */ + __in BOOL bEnable, + /* [unique][in] */ + __in_opt LPCGUID pguidEventContext); + + END_INTERFACE + } IAudioLoudnessVtbl; + + interface IAudioLoudness + { + CONST_VTBL struct IAudioLoudnessVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IAudioLoudness_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IAudioLoudness_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IAudioLoudness_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IAudioLoudness_GetEnabled(This,pbEnabled) \ + ( (This)->lpVtbl -> GetEnabled(This,pbEnabled) ) + +#define IAudioLoudness_SetEnabled(This,bEnable,pguidEventContext) \ + ( (This)->lpVtbl -> SetEnabled(This,bEnable,pguidEventContext) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IAudioLoudness_INTERFACE_DEFINED__ */ + + +#ifndef __IAudioInputSelector_INTERFACE_DEFINED__ +#define __IAudioInputSelector_INTERFACE_DEFINED__ + +/* interface IAudioInputSelector */ +/* [unique][helpstring][nonextensible][uuid][local][object] */ + + +EXTERN_C const IID IID_IAudioInputSelector; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("4F03DC02-5E6E-4653-8F72-A030C123D598") + IAudioInputSelector : public IUnknown + { + public: + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE GetSelection( + /* [out] */ + __out UINT *pnIdSelected) = 0; + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE SetSelection( + /* [in] */ + __in UINT nIdSelect, + /* [unique][in] */ + __in_opt LPCGUID pguidEventContext) = 0; + + }; + +#else /* C style interface */ + + typedef struct IAudioInputSelectorVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IAudioInputSelector * This, + /* [in] */ REFIID riid, + /* [iid_is][out] */ + __RPC__deref_out void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IAudioInputSelector * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IAudioInputSelector * This); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *GetSelection )( + IAudioInputSelector * This, + /* [out] */ + __out UINT *pnIdSelected); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *SetSelection )( + IAudioInputSelector * This, + /* [in] */ + __in UINT nIdSelect, + /* [unique][in] */ + __in_opt LPCGUID pguidEventContext); + + END_INTERFACE + } IAudioInputSelectorVtbl; + + interface IAudioInputSelector + { + CONST_VTBL struct IAudioInputSelectorVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IAudioInputSelector_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IAudioInputSelector_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IAudioInputSelector_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IAudioInputSelector_GetSelection(This,pnIdSelected) \ + ( (This)->lpVtbl -> GetSelection(This,pnIdSelected) ) + +#define IAudioInputSelector_SetSelection(This,nIdSelect,pguidEventContext) \ + ( (This)->lpVtbl -> SetSelection(This,nIdSelect,pguidEventContext) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IAudioInputSelector_INTERFACE_DEFINED__ */ + + +#ifndef __IAudioOutputSelector_INTERFACE_DEFINED__ +#define __IAudioOutputSelector_INTERFACE_DEFINED__ + +/* interface IAudioOutputSelector */ +/* [unique][helpstring][nonextensible][uuid][local][object] */ + + +EXTERN_C const IID IID_IAudioOutputSelector; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("BB515F69-94A7-429e-8B9C-271B3F11A3AB") + IAudioOutputSelector : public IUnknown + { + public: + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE GetSelection( + /* [out] */ + __out UINT *pnIdSelected) = 0; + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE SetSelection( + /* [in] */ + __in UINT nIdSelect, + /* [unique][in] */ + __in_opt LPCGUID pguidEventContext) = 0; + + }; + +#else /* C style interface */ + + typedef struct IAudioOutputSelectorVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IAudioOutputSelector * This, + /* [in] */ REFIID riid, + /* [iid_is][out] */ + __RPC__deref_out void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IAudioOutputSelector * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IAudioOutputSelector * This); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *GetSelection )( + IAudioOutputSelector * This, + /* [out] */ + __out UINT *pnIdSelected); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *SetSelection )( + IAudioOutputSelector * This, + /* [in] */ + __in UINT nIdSelect, + /* [unique][in] */ + __in_opt LPCGUID pguidEventContext); + + END_INTERFACE + } IAudioOutputSelectorVtbl; + + interface IAudioOutputSelector + { + CONST_VTBL struct IAudioOutputSelectorVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IAudioOutputSelector_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IAudioOutputSelector_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IAudioOutputSelector_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IAudioOutputSelector_GetSelection(This,pnIdSelected) \ + ( (This)->lpVtbl -> GetSelection(This,pnIdSelected) ) + +#define IAudioOutputSelector_SetSelection(This,nIdSelect,pguidEventContext) \ + ( (This)->lpVtbl -> SetSelection(This,nIdSelect,pguidEventContext) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IAudioOutputSelector_INTERFACE_DEFINED__ */ + + +#ifndef __IAudioMute_INTERFACE_DEFINED__ +#define __IAudioMute_INTERFACE_DEFINED__ + +/* interface IAudioMute */ +/* [unique][helpstring][nonextensible][uuid][local][object] */ + + +EXTERN_C const IID IID_IAudioMute; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("DF45AEEA-B74A-4B6B-AFAD-2366B6AA012E") + IAudioMute : public IUnknown + { + public: + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE SetMute( + /* [in] */ + __in BOOL bMuted, + /* [unique][in] */ + __in_opt LPCGUID pguidEventContext) = 0; + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE GetMute( + /* [out] */ + __out BOOL *pbMuted) = 0; + + }; + +#else /* C style interface */ + + typedef struct IAudioMuteVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IAudioMute * This, + /* [in] */ REFIID riid, + /* [iid_is][out] */ + __RPC__deref_out void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IAudioMute * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IAudioMute * This); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *SetMute )( + IAudioMute * This, + /* [in] */ + __in BOOL bMuted, + /* [unique][in] */ + __in_opt LPCGUID pguidEventContext); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *GetMute )( + IAudioMute * This, + /* [out] */ + __out BOOL *pbMuted); + + END_INTERFACE + } IAudioMuteVtbl; + + interface IAudioMute + { + CONST_VTBL struct IAudioMuteVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IAudioMute_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IAudioMute_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IAudioMute_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IAudioMute_SetMute(This,bMuted,pguidEventContext) \ + ( (This)->lpVtbl -> SetMute(This,bMuted,pguidEventContext) ) + +#define IAudioMute_GetMute(This,pbMuted) \ + ( (This)->lpVtbl -> GetMute(This,pbMuted) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IAudioMute_INTERFACE_DEFINED__ */ + + +#ifndef __IAudioBass_INTERFACE_DEFINED__ +#define __IAudioBass_INTERFACE_DEFINED__ + +/* interface IAudioBass */ +/* [unique][helpstring][nonextensible][uuid][local][object] */ + + +EXTERN_C const IID IID_IAudioBass; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("A2B1A1D9-4DB3-425D-A2B2-BD335CB3E2E5") + IAudioBass : public IPerChannelDbLevel + { + public: + }; + +#else /* C style interface */ + + typedef struct IAudioBassVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IAudioBass * This, + /* [in] */ REFIID riid, + /* [iid_is][out] */ + __RPC__deref_out void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IAudioBass * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IAudioBass * This); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *GetChannelCount )( + IAudioBass * This, + /* [out] */ + __out UINT *pcChannels); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *GetLevelRange )( + IAudioBass * This, + /* [in] */ + __in UINT nChannel, + /* [out] */ + __out float *pfMinLevelDB, + /* [out] */ + __out float *pfMaxLevelDB, + /* [out] */ + __out float *pfStepping); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *GetLevel )( + IAudioBass * This, + /* [in] */ + __in UINT nChannel, + /* [out] */ + __out float *pfLevelDB); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *SetLevel )( + IAudioBass * This, + /* [in] */ + __in UINT nChannel, + /* [in] */ + __in float fLevelDB, + /* [unique][in] */ + __in_opt LPCGUID pguidEventContext); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *SetLevelUniform )( + IAudioBass * This, + /* [in] */ + __in float fLevelDB, + /* [unique][in] */ + __in_opt LPCGUID pguidEventContext); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *SetLevelAllChannels )( + IAudioBass * This, + /* [size_is][in] */ + __in_ecount(cChannels) float aLevelsDB[ ], + /* [in] */ + __in ULONG cChannels, + /* [unique][in] */ + __in_opt LPCGUID pguidEventContext); + + END_INTERFACE + } IAudioBassVtbl; + + interface IAudioBass + { + CONST_VTBL struct IAudioBassVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IAudioBass_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IAudioBass_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IAudioBass_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IAudioBass_GetChannelCount(This,pcChannels) \ + ( (This)->lpVtbl -> GetChannelCount(This,pcChannels) ) + +#define IAudioBass_GetLevelRange(This,nChannel,pfMinLevelDB,pfMaxLevelDB,pfStepping) \ + ( (This)->lpVtbl -> GetLevelRange(This,nChannel,pfMinLevelDB,pfMaxLevelDB,pfStepping) ) + +#define IAudioBass_GetLevel(This,nChannel,pfLevelDB) \ + ( (This)->lpVtbl -> GetLevel(This,nChannel,pfLevelDB) ) + +#define IAudioBass_SetLevel(This,nChannel,fLevelDB,pguidEventContext) \ + ( (This)->lpVtbl -> SetLevel(This,nChannel,fLevelDB,pguidEventContext) ) + +#define IAudioBass_SetLevelUniform(This,fLevelDB,pguidEventContext) \ + ( (This)->lpVtbl -> SetLevelUniform(This,fLevelDB,pguidEventContext) ) + +#define IAudioBass_SetLevelAllChannels(This,aLevelsDB,cChannels,pguidEventContext) \ + ( (This)->lpVtbl -> SetLevelAllChannels(This,aLevelsDB,cChannels,pguidEventContext) ) + + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IAudioBass_INTERFACE_DEFINED__ */ + + +#ifndef __IAudioMidrange_INTERFACE_DEFINED__ +#define __IAudioMidrange_INTERFACE_DEFINED__ + +/* interface IAudioMidrange */ +/* [unique][helpstring][nonextensible][uuid][local][object] */ + + +EXTERN_C const IID IID_IAudioMidrange; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("5E54B6D7-B44B-40D9-9A9E-E691D9CE6EDF") + IAudioMidrange : public IPerChannelDbLevel + { + public: + }; + +#else /* C style interface */ + + typedef struct IAudioMidrangeVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IAudioMidrange * This, + /* [in] */ REFIID riid, + /* [iid_is][out] */ + __RPC__deref_out void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IAudioMidrange * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IAudioMidrange * This); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *GetChannelCount )( + IAudioMidrange * This, + /* [out] */ + __out UINT *pcChannels); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *GetLevelRange )( + IAudioMidrange * This, + /* [in] */ + __in UINT nChannel, + /* [out] */ + __out float *pfMinLevelDB, + /* [out] */ + __out float *pfMaxLevelDB, + /* [out] */ + __out float *pfStepping); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *GetLevel )( + IAudioMidrange * This, + /* [in] */ + __in UINT nChannel, + /* [out] */ + __out float *pfLevelDB); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *SetLevel )( + IAudioMidrange * This, + /* [in] */ + __in UINT nChannel, + /* [in] */ + __in float fLevelDB, + /* [unique][in] */ + __in_opt LPCGUID pguidEventContext); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *SetLevelUniform )( + IAudioMidrange * This, + /* [in] */ + __in float fLevelDB, + /* [unique][in] */ + __in_opt LPCGUID pguidEventContext); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *SetLevelAllChannels )( + IAudioMidrange * This, + /* [size_is][in] */ + __in_ecount(cChannels) float aLevelsDB[ ], + /* [in] */ + __in ULONG cChannels, + /* [unique][in] */ + __in_opt LPCGUID pguidEventContext); + + END_INTERFACE + } IAudioMidrangeVtbl; + + interface IAudioMidrange + { + CONST_VTBL struct IAudioMidrangeVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IAudioMidrange_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IAudioMidrange_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IAudioMidrange_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IAudioMidrange_GetChannelCount(This,pcChannels) \ + ( (This)->lpVtbl -> GetChannelCount(This,pcChannels) ) + +#define IAudioMidrange_GetLevelRange(This,nChannel,pfMinLevelDB,pfMaxLevelDB,pfStepping) \ + ( (This)->lpVtbl -> GetLevelRange(This,nChannel,pfMinLevelDB,pfMaxLevelDB,pfStepping) ) + +#define IAudioMidrange_GetLevel(This,nChannel,pfLevelDB) \ + ( (This)->lpVtbl -> GetLevel(This,nChannel,pfLevelDB) ) + +#define IAudioMidrange_SetLevel(This,nChannel,fLevelDB,pguidEventContext) \ + ( (This)->lpVtbl -> SetLevel(This,nChannel,fLevelDB,pguidEventContext) ) + +#define IAudioMidrange_SetLevelUniform(This,fLevelDB,pguidEventContext) \ + ( (This)->lpVtbl -> SetLevelUniform(This,fLevelDB,pguidEventContext) ) + +#define IAudioMidrange_SetLevelAllChannels(This,aLevelsDB,cChannels,pguidEventContext) \ + ( (This)->lpVtbl -> SetLevelAllChannels(This,aLevelsDB,cChannels,pguidEventContext) ) + + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IAudioMidrange_INTERFACE_DEFINED__ */ + + +#ifndef __IAudioTreble_INTERFACE_DEFINED__ +#define __IAudioTreble_INTERFACE_DEFINED__ + +/* interface IAudioTreble */ +/* [unique][helpstring][nonextensible][uuid][local][object] */ + + +EXTERN_C const IID IID_IAudioTreble; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("0A717812-694E-4907-B74B-BAFA5CFDCA7B") + IAudioTreble : public IPerChannelDbLevel + { + public: + }; + +#else /* C style interface */ + + typedef struct IAudioTrebleVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IAudioTreble * This, + /* [in] */ REFIID riid, + /* [iid_is][out] */ + __RPC__deref_out void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IAudioTreble * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IAudioTreble * This); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *GetChannelCount )( + IAudioTreble * This, + /* [out] */ + __out UINT *pcChannels); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *GetLevelRange )( + IAudioTreble * This, + /* [in] */ + __in UINT nChannel, + /* [out] */ + __out float *pfMinLevelDB, + /* [out] */ + __out float *pfMaxLevelDB, + /* [out] */ + __out float *pfStepping); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *GetLevel )( + IAudioTreble * This, + /* [in] */ + __in UINT nChannel, + /* [out] */ + __out float *pfLevelDB); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *SetLevel )( + IAudioTreble * This, + /* [in] */ + __in UINT nChannel, + /* [in] */ + __in float fLevelDB, + /* [unique][in] */ + __in_opt LPCGUID pguidEventContext); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *SetLevelUniform )( + IAudioTreble * This, + /* [in] */ + __in float fLevelDB, + /* [unique][in] */ + __in_opt LPCGUID pguidEventContext); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *SetLevelAllChannels )( + IAudioTreble * This, + /* [size_is][in] */ + __in_ecount(cChannels) float aLevelsDB[ ], + /* [in] */ + __in ULONG cChannels, + /* [unique][in] */ + __in_opt LPCGUID pguidEventContext); + + END_INTERFACE + } IAudioTrebleVtbl; + + interface IAudioTreble + { + CONST_VTBL struct IAudioTrebleVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IAudioTreble_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IAudioTreble_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IAudioTreble_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IAudioTreble_GetChannelCount(This,pcChannels) \ + ( (This)->lpVtbl -> GetChannelCount(This,pcChannels) ) + +#define IAudioTreble_GetLevelRange(This,nChannel,pfMinLevelDB,pfMaxLevelDB,pfStepping) \ + ( (This)->lpVtbl -> GetLevelRange(This,nChannel,pfMinLevelDB,pfMaxLevelDB,pfStepping) ) + +#define IAudioTreble_GetLevel(This,nChannel,pfLevelDB) \ + ( (This)->lpVtbl -> GetLevel(This,nChannel,pfLevelDB) ) + +#define IAudioTreble_SetLevel(This,nChannel,fLevelDB,pguidEventContext) \ + ( (This)->lpVtbl -> SetLevel(This,nChannel,fLevelDB,pguidEventContext) ) + +#define IAudioTreble_SetLevelUniform(This,fLevelDB,pguidEventContext) \ + ( (This)->lpVtbl -> SetLevelUniform(This,fLevelDB,pguidEventContext) ) + +#define IAudioTreble_SetLevelAllChannels(This,aLevelsDB,cChannels,pguidEventContext) \ + ( (This)->lpVtbl -> SetLevelAllChannels(This,aLevelsDB,cChannels,pguidEventContext) ) + + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IAudioTreble_INTERFACE_DEFINED__ */ + + +#ifndef __IAudioAutoGainControl_INTERFACE_DEFINED__ +#define __IAudioAutoGainControl_INTERFACE_DEFINED__ + +/* interface IAudioAutoGainControl */ +/* [unique][helpstring][nonextensible][uuid][local][object] */ + + +EXTERN_C const IID IID_IAudioAutoGainControl; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("85401FD4-6DE4-4b9d-9869-2D6753A82F3C") + IAudioAutoGainControl : public IUnknown + { + public: + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE GetEnabled( + /* [out] */ + __out BOOL *pbEnabled) = 0; + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE SetEnabled( + /* [in] */ + __in BOOL bEnable, + /* [unique][in] */ + __in_opt LPCGUID pguidEventContext) = 0; + + }; + +#else /* C style interface */ + + typedef struct IAudioAutoGainControlVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IAudioAutoGainControl * This, + /* [in] */ REFIID riid, + /* [iid_is][out] */ + __RPC__deref_out void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IAudioAutoGainControl * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IAudioAutoGainControl * This); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *GetEnabled )( + IAudioAutoGainControl * This, + /* [out] */ + __out BOOL *pbEnabled); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *SetEnabled )( + IAudioAutoGainControl * This, + /* [in] */ + __in BOOL bEnable, + /* [unique][in] */ + __in_opt LPCGUID pguidEventContext); + + END_INTERFACE + } IAudioAutoGainControlVtbl; + + interface IAudioAutoGainControl + { + CONST_VTBL struct IAudioAutoGainControlVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IAudioAutoGainControl_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IAudioAutoGainControl_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IAudioAutoGainControl_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IAudioAutoGainControl_GetEnabled(This,pbEnabled) \ + ( (This)->lpVtbl -> GetEnabled(This,pbEnabled) ) + +#define IAudioAutoGainControl_SetEnabled(This,bEnable,pguidEventContext) \ + ( (This)->lpVtbl -> SetEnabled(This,bEnable,pguidEventContext) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IAudioAutoGainControl_INTERFACE_DEFINED__ */ + + +#ifndef __IAudioPeakMeter_INTERFACE_DEFINED__ +#define __IAudioPeakMeter_INTERFACE_DEFINED__ + +/* interface IAudioPeakMeter */ +/* [unique][helpstring][nonextensible][uuid][local][object] */ + + +EXTERN_C const IID IID_IAudioPeakMeter; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("DD79923C-0599-45e0-B8B6-C8DF7DB6E796") + IAudioPeakMeter : public IUnknown + { + public: + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE GetChannelCount( + /* [out] */ + __out UINT *pcChannels) = 0; + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE GetLevel( + /* [in] */ + __in UINT nChannel, + /* [out] */ + __out float *pfLevel) = 0; + + }; + +#else /* C style interface */ + + typedef struct IAudioPeakMeterVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IAudioPeakMeter * This, + /* [in] */ REFIID riid, + /* [iid_is][out] */ + __RPC__deref_out void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IAudioPeakMeter * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IAudioPeakMeter * This); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *GetChannelCount )( + IAudioPeakMeter * This, + /* [out] */ + __out UINT *pcChannels); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *GetLevel )( + IAudioPeakMeter * This, + /* [in] */ + __in UINT nChannel, + /* [out] */ + __out float *pfLevel); + + END_INTERFACE + } IAudioPeakMeterVtbl; + + interface IAudioPeakMeter + { + CONST_VTBL struct IAudioPeakMeterVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IAudioPeakMeter_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IAudioPeakMeter_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IAudioPeakMeter_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IAudioPeakMeter_GetChannelCount(This,pcChannels) \ + ( (This)->lpVtbl -> GetChannelCount(This,pcChannels) ) + +#define IAudioPeakMeter_GetLevel(This,nChannel,pfLevel) \ + ( (This)->lpVtbl -> GetLevel(This,nChannel,pfLevel) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IAudioPeakMeter_INTERFACE_DEFINED__ */ + + +#ifndef __IDeviceSpecificProperty_INTERFACE_DEFINED__ +#define __IDeviceSpecificProperty_INTERFACE_DEFINED__ + +/* interface IDeviceSpecificProperty */ +/* [unique][helpstring][nonextensible][uuid][local][object] */ + + +EXTERN_C const IID IID_IDeviceSpecificProperty; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("3B22BCBF-2586-4af0-8583-205D391B807C") + IDeviceSpecificProperty : public IUnknown + { + public: + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE GetType( + /* [out] */ + __deref_out VARTYPE *pVType) = 0; + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE GetValue( + /* [out] */ + __out void *pvValue, + /* [out][in] */ + __inout DWORD *pcbValue) = 0; + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE SetValue( + /* [in] */ + __in void *pvValue, + /* [in] */ DWORD cbValue, + /* [unique][in] */ + __in_opt LPCGUID pguidEventContext) = 0; + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE Get4BRange( + /* [out] */ + __deref_out LONG *plMin, + /* [out] */ + __deref_out LONG *plMax, + /* [out] */ + __deref_out LONG *plStepping) = 0; + + }; + +#else /* C style interface */ + + typedef struct IDeviceSpecificPropertyVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeviceSpecificProperty * This, + /* [in] */ REFIID riid, + /* [iid_is][out] */ + __RPC__deref_out void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeviceSpecificProperty * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeviceSpecificProperty * This); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *GetType )( + IDeviceSpecificProperty * This, + /* [out] */ + __deref_out VARTYPE *pVType); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *GetValue )( + IDeviceSpecificProperty * This, + /* [out] */ + __out void *pvValue, + /* [out][in] */ + __inout DWORD *pcbValue); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *SetValue )( + IDeviceSpecificProperty * This, + /* [in] */ + __in void *pvValue, + /* [in] */ DWORD cbValue, + /* [unique][in] */ + __in_opt LPCGUID pguidEventContext); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *Get4BRange )( + IDeviceSpecificProperty * This, + /* [out] */ + __deref_out LONG *plMin, + /* [out] */ + __deref_out LONG *plMax, + /* [out] */ + __deref_out LONG *plStepping); + + END_INTERFACE + } IDeviceSpecificPropertyVtbl; + + interface IDeviceSpecificProperty + { + CONST_VTBL struct IDeviceSpecificPropertyVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeviceSpecificProperty_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeviceSpecificProperty_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeviceSpecificProperty_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeviceSpecificProperty_GetType(This,pVType) \ + ( (This)->lpVtbl -> GetType(This,pVType) ) + +#define IDeviceSpecificProperty_GetValue(This,pvValue,pcbValue) \ + ( (This)->lpVtbl -> GetValue(This,pvValue,pcbValue) ) + +#define IDeviceSpecificProperty_SetValue(This,pvValue,cbValue,pguidEventContext) \ + ( (This)->lpVtbl -> SetValue(This,pvValue,cbValue,pguidEventContext) ) + +#define IDeviceSpecificProperty_Get4BRange(This,plMin,plMax,plStepping) \ + ( (This)->lpVtbl -> Get4BRange(This,plMin,plMax,plStepping) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeviceSpecificProperty_INTERFACE_DEFINED__ */ + + +#ifndef __IKsFormatSupport_INTERFACE_DEFINED__ +#define __IKsFormatSupport_INTERFACE_DEFINED__ + +/* interface IKsFormatSupport */ +/* [unique][helpstring][nonextensible][uuid][local][object] */ + + +EXTERN_C const IID IID_IKsFormatSupport; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("3CB4A69D-BB6F-4D2B-95B7-452D2C155DB5") + IKsFormatSupport : public IUnknown + { + public: + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE IsFormatSupported( + /* [size_is][in] */ PKSDATAFORMAT pKsFormat, + /* [in] */ + __in DWORD cbFormat, + /* [out] */ + __out BOOL *pbSupported) = 0; + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE GetDevicePreferredFormat( + /* [out] */ PKSDATAFORMAT *ppKsFormat) = 0; + + }; + +#else /* C style interface */ + + typedef struct IKsFormatSupportVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IKsFormatSupport * This, + /* [in] */ REFIID riid, + /* [iid_is][out] */ + __RPC__deref_out void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IKsFormatSupport * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IKsFormatSupport * This); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *IsFormatSupported )( + IKsFormatSupport * This, + /* [size_is][in] */ PKSDATAFORMAT pKsFormat, + /* [in] */ + __in DWORD cbFormat, + /* [out] */ + __out BOOL *pbSupported); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *GetDevicePreferredFormat )( + IKsFormatSupport * This, + /* [out] */ PKSDATAFORMAT *ppKsFormat); + + END_INTERFACE + } IKsFormatSupportVtbl; + + interface IKsFormatSupport + { + CONST_VTBL struct IKsFormatSupportVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IKsFormatSupport_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IKsFormatSupport_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IKsFormatSupport_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IKsFormatSupport_IsFormatSupported(This,pKsFormat,cbFormat,pbSupported) \ + ( (This)->lpVtbl -> IsFormatSupported(This,pKsFormat,cbFormat,pbSupported) ) + +#define IKsFormatSupport_GetDevicePreferredFormat(This,ppKsFormat) \ + ( (This)->lpVtbl -> GetDevicePreferredFormat(This,ppKsFormat) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IKsFormatSupport_INTERFACE_DEFINED__ */ + + +#ifndef __IKsJackDescription_INTERFACE_DEFINED__ +#define __IKsJackDescription_INTERFACE_DEFINED__ + +/* interface IKsJackDescription */ +/* [unique][helpstring][nonextensible][uuid][local][object] */ + + +EXTERN_C const IID IID_IKsJackDescription; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("4509F757-2D46-4637-8E62-CE7DB944F57B") + IKsJackDescription : public IUnknown + { + public: + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE GetJackCount( + /* [out] */ + __out UINT *pcJacks) = 0; + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE GetJackDescription( + /* [in] */ UINT nJack, + /* [out] */ + __out KSJACK_DESCRIPTION *pDescription) = 0; + + }; + +#else /* C style interface */ + + typedef struct IKsJackDescriptionVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IKsJackDescription * This, + /* [in] */ REFIID riid, + /* [iid_is][out] */ + __RPC__deref_out void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IKsJackDescription * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IKsJackDescription * This); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *GetJackCount )( + IKsJackDescription * This, + /* [out] */ + __out UINT *pcJacks); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *GetJackDescription )( + IKsJackDescription * This, + /* [in] */ UINT nJack, + /* [out] */ + __out KSJACK_DESCRIPTION *pDescription); + + END_INTERFACE + } IKsJackDescriptionVtbl; + + interface IKsJackDescription + { + CONST_VTBL struct IKsJackDescriptionVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IKsJackDescription_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IKsJackDescription_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IKsJackDescription_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IKsJackDescription_GetJackCount(This,pcJacks) \ + ( (This)->lpVtbl -> GetJackCount(This,pcJacks) ) + +#define IKsJackDescription_GetJackDescription(This,nJack,pDescription) \ + ( (This)->lpVtbl -> GetJackDescription(This,nJack,pDescription) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IKsJackDescription_INTERFACE_DEFINED__ */ + + +#ifndef __IPartsList_INTERFACE_DEFINED__ +#define __IPartsList_INTERFACE_DEFINED__ + +/* interface IPartsList */ +/* [object][unique][helpstring][uuid][local] */ + + +EXTERN_C const IID IID_IPartsList; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("6DAA848C-5EB0-45CC-AEA5-998A2CDA1FFB") + IPartsList : public IUnknown + { + public: + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE GetCount( + /* [out] */ + __out UINT *pCount) = 0; + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE GetPart( + /* [in] */ + __in UINT nIndex, + /* [out] */ + __out IPart **ppPart) = 0; + + }; + +#else /* C style interface */ + + typedef struct IPartsListVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IPartsList * This, + /* [in] */ REFIID riid, + /* [iid_is][out] */ + __RPC__deref_out void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IPartsList * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IPartsList * This); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *GetCount )( + IPartsList * This, + /* [out] */ + __out UINT *pCount); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *GetPart )( + IPartsList * This, + /* [in] */ + __in UINT nIndex, + /* [out] */ + __out IPart **ppPart); + + END_INTERFACE + } IPartsListVtbl; + + interface IPartsList + { + CONST_VTBL struct IPartsListVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IPartsList_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IPartsList_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IPartsList_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IPartsList_GetCount(This,pCount) \ + ( (This)->lpVtbl -> GetCount(This,pCount) ) + +#define IPartsList_GetPart(This,nIndex,ppPart) \ + ( (This)->lpVtbl -> GetPart(This,nIndex,ppPart) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IPartsList_INTERFACE_DEFINED__ */ + + +#ifndef __IPart_INTERFACE_DEFINED__ +#define __IPart_INTERFACE_DEFINED__ + +/* interface IPart */ +/* [object][unique][helpstring][uuid][local] */ + + +EXTERN_C const IID IID_IPart; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("AE2DE0E4-5BCA-4F2D-AA46-5D13F8FDB3A9") + IPart : public IUnknown + { + public: + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE GetName( + /* [out] */ + __deref_out LPWSTR *ppwstrName) = 0; + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE GetLocalId( + /* [out] */ + __out UINT *pnId) = 0; + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE GetGlobalId( + /* [out] */ + __deref_out LPWSTR *ppwstrGlobalId) = 0; + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE GetPartType( + /* [out] */ + __out PartType *pPartType) = 0; + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE GetSubType( + /* [out] */ GUID *pSubType) = 0; + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE GetControlInterfaceCount( + /* [out] */ + __out UINT *pCount) = 0; + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE GetControlInterface( + /* [in] */ + __in UINT nIndex, + /* [out] */ + __out IControlInterface **ppInterfaceDesc) = 0; + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE EnumPartsIncoming( + /* [out] */ + __out IPartsList **ppParts) = 0; + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE EnumPartsOutgoing( + /* [out] */ + __out IPartsList **ppParts) = 0; + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE GetTopologyObject( + /* [out] */ + __out IDeviceTopology **ppTopology) = 0; + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE Activate( + /* [in] */ + __in DWORD dwClsContext, + /* [in] */ + __in REFIID refiid, + /* [iid_is][out] */ + __out_opt void **ppvObject) = 0; + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE RegisterControlChangeCallback( + /* [in] */ + __in REFGUID riid, + /* [in] */ + __in IControlChangeNotify *pNotify) = 0; + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE UnregisterControlChangeCallback( + /* [in] */ + __in IControlChangeNotify *pNotify) = 0; + + }; + +#else /* C style interface */ + + typedef struct IPartVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IPart * This, + /* [in] */ REFIID riid, + /* [iid_is][out] */ + __RPC__deref_out void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IPart * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IPart * This); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *GetName )( + IPart * This, + /* [out] */ + __deref_out LPWSTR *ppwstrName); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *GetLocalId )( + IPart * This, + /* [out] */ + __out UINT *pnId); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *GetGlobalId )( + IPart * This, + /* [out] */ + __deref_out LPWSTR *ppwstrGlobalId); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *GetPartType )( + IPart * This, + /* [out] */ + __out PartType *pPartType); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *GetSubType )( + IPart * This, + /* [out] */ GUID *pSubType); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *GetControlInterfaceCount )( + IPart * This, + /* [out] */ + __out UINT *pCount); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *GetControlInterface )( + IPart * This, + /* [in] */ + __in UINT nIndex, + /* [out] */ + __out IControlInterface **ppInterfaceDesc); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *EnumPartsIncoming )( + IPart * This, + /* [out] */ + __out IPartsList **ppParts); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *EnumPartsOutgoing )( + IPart * This, + /* [out] */ + __out IPartsList **ppParts); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *GetTopologyObject )( + IPart * This, + /* [out] */ + __out IDeviceTopology **ppTopology); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *Activate )( + IPart * This, + /* [in] */ + __in DWORD dwClsContext, + /* [in] */ + __in REFIID refiid, + /* [iid_is][out] */ + __out_opt void **ppvObject); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *RegisterControlChangeCallback )( + IPart * This, + /* [in] */ + __in REFGUID riid, + /* [in] */ + __in IControlChangeNotify *pNotify); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *UnregisterControlChangeCallback )( + IPart * This, + /* [in] */ + __in IControlChangeNotify *pNotify); + + END_INTERFACE + } IPartVtbl; + + interface IPart + { + CONST_VTBL struct IPartVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IPart_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IPart_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IPart_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IPart_GetName(This,ppwstrName) \ + ( (This)->lpVtbl -> GetName(This,ppwstrName) ) + +#define IPart_GetLocalId(This,pnId) \ + ( (This)->lpVtbl -> GetLocalId(This,pnId) ) + +#define IPart_GetGlobalId(This,ppwstrGlobalId) \ + ( (This)->lpVtbl -> GetGlobalId(This,ppwstrGlobalId) ) + +#define IPart_GetPartType(This,pPartType) \ + ( (This)->lpVtbl -> GetPartType(This,pPartType) ) + +#define IPart_GetSubType(This,pSubType) \ + ( (This)->lpVtbl -> GetSubType(This,pSubType) ) + +#define IPart_GetControlInterfaceCount(This,pCount) \ + ( (This)->lpVtbl -> GetControlInterfaceCount(This,pCount) ) + +#define IPart_GetControlInterface(This,nIndex,ppInterfaceDesc) \ + ( (This)->lpVtbl -> GetControlInterface(This,nIndex,ppInterfaceDesc) ) + +#define IPart_EnumPartsIncoming(This,ppParts) \ + ( (This)->lpVtbl -> EnumPartsIncoming(This,ppParts) ) + +#define IPart_EnumPartsOutgoing(This,ppParts) \ + ( (This)->lpVtbl -> EnumPartsOutgoing(This,ppParts) ) + +#define IPart_GetTopologyObject(This,ppTopology) \ + ( (This)->lpVtbl -> GetTopologyObject(This,ppTopology) ) + +#define IPart_Activate(This,dwClsContext,refiid,ppvObject) \ + ( (This)->lpVtbl -> Activate(This,dwClsContext,refiid,ppvObject) ) + +#define IPart_RegisterControlChangeCallback(This,riid,pNotify) \ + ( (This)->lpVtbl -> RegisterControlChangeCallback(This,riid,pNotify) ) + +#define IPart_UnregisterControlChangeCallback(This,pNotify) \ + ( (This)->lpVtbl -> UnregisterControlChangeCallback(This,pNotify) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IPart_INTERFACE_DEFINED__ */ + + +#ifndef __IConnector_INTERFACE_DEFINED__ +#define __IConnector_INTERFACE_DEFINED__ + +/* interface IConnector */ +/* [object][unique][helpstring][uuid][local] */ + + +EXTERN_C const IID IID_IConnector; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("9c2c4058-23f5-41de-877a-df3af236a09e") + IConnector : public IUnknown + { + public: + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE GetType( + /* [out] */ + __out ConnectorType *pType) = 0; + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE GetDataFlow( + /* [out] */ + __out DataFlow *pFlow) = 0; + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE ConnectTo( + /* [in] */ + __in IConnector *pConnectTo) = 0; + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE Disconnect( void) = 0; + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE IsConnected( + /* [out] */ + __out BOOL *pbConnected) = 0; + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE GetConnectedTo( + /* [out] */ + __out IConnector **ppConTo) = 0; + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE GetConnectorIdConnectedTo( + /* [out] */ + __deref_out LPWSTR *ppwstrConnectorId) = 0; + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE GetDeviceIdConnectedTo( + /* [out] */ + __deref_out LPWSTR *ppwstrDeviceId) = 0; + + }; + +#else /* C style interface */ + + typedef struct IConnectorVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IConnector * This, + /* [in] */ REFIID riid, + /* [iid_is][out] */ + __RPC__deref_out void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IConnector * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IConnector * This); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *GetType )( + IConnector * This, + /* [out] */ + __out ConnectorType *pType); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *GetDataFlow )( + IConnector * This, + /* [out] */ + __out DataFlow *pFlow); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *ConnectTo )( + IConnector * This, + /* [in] */ + __in IConnector *pConnectTo); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *Disconnect )( + IConnector * This); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *IsConnected )( + IConnector * This, + /* [out] */ + __out BOOL *pbConnected); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *GetConnectedTo )( + IConnector * This, + /* [out] */ + __out IConnector **ppConTo); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *GetConnectorIdConnectedTo )( + IConnector * This, + /* [out] */ + __deref_out LPWSTR *ppwstrConnectorId); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *GetDeviceIdConnectedTo )( + IConnector * This, + /* [out] */ + __deref_out LPWSTR *ppwstrDeviceId); + + END_INTERFACE + } IConnectorVtbl; + + interface IConnector + { + CONST_VTBL struct IConnectorVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IConnector_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IConnector_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IConnector_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IConnector_GetType(This,pType) \ + ( (This)->lpVtbl -> GetType(This,pType) ) + +#define IConnector_GetDataFlow(This,pFlow) \ + ( (This)->lpVtbl -> GetDataFlow(This,pFlow) ) + +#define IConnector_ConnectTo(This,pConnectTo) \ + ( (This)->lpVtbl -> ConnectTo(This,pConnectTo) ) + +#define IConnector_Disconnect(This) \ + ( (This)->lpVtbl -> Disconnect(This) ) + +#define IConnector_IsConnected(This,pbConnected) \ + ( (This)->lpVtbl -> IsConnected(This,pbConnected) ) + +#define IConnector_GetConnectedTo(This,ppConTo) \ + ( (This)->lpVtbl -> GetConnectedTo(This,ppConTo) ) + +#define IConnector_GetConnectorIdConnectedTo(This,ppwstrConnectorId) \ + ( (This)->lpVtbl -> GetConnectorIdConnectedTo(This,ppwstrConnectorId) ) + +#define IConnector_GetDeviceIdConnectedTo(This,ppwstrDeviceId) \ + ( (This)->lpVtbl -> GetDeviceIdConnectedTo(This,ppwstrDeviceId) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IConnector_INTERFACE_DEFINED__ */ + + +#ifndef __ISubunit_INTERFACE_DEFINED__ +#define __ISubunit_INTERFACE_DEFINED__ + +/* interface ISubunit */ +/* [object][unique][helpstring][uuid][local] */ + + +EXTERN_C const IID IID_ISubunit; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("82149A85-DBA6-4487-86BB-EA8F7FEFCC71") + ISubunit : public IUnknown + { + public: + }; + +#else /* C style interface */ + + typedef struct ISubunitVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ISubunit * This, + /* [in] */ REFIID riid, + /* [iid_is][out] */ + __RPC__deref_out void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ISubunit * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ISubunit * This); + + END_INTERFACE + } ISubunitVtbl; + + interface ISubunit + { + CONST_VTBL struct ISubunitVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ISubunit_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ISubunit_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ISubunit_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ISubunit_INTERFACE_DEFINED__ */ + + +#ifndef __IControlInterface_INTERFACE_DEFINED__ +#define __IControlInterface_INTERFACE_DEFINED__ + +/* interface IControlInterface */ +/* [object][unique][helpstring][uuid][local] */ + + +EXTERN_C const IID IID_IControlInterface; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("45d37c3f-5140-444a-ae24-400789f3cbf3") + IControlInterface : public IUnknown + { + public: + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE GetName( + /* [out] */ + __deref_out LPWSTR *ppwstrName) = 0; + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE GetIID( + /* [out] */ + __out GUID *pIID) = 0; + + }; + +#else /* C style interface */ + + typedef struct IControlInterfaceVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IControlInterface * This, + /* [in] */ REFIID riid, + /* [iid_is][out] */ + __RPC__deref_out void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IControlInterface * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IControlInterface * This); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *GetName )( + IControlInterface * This, + /* [out] */ + __deref_out LPWSTR *ppwstrName); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *GetIID )( + IControlInterface * This, + /* [out] */ + __out GUID *pIID); + + END_INTERFACE + } IControlInterfaceVtbl; + + interface IControlInterface + { + CONST_VTBL struct IControlInterfaceVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IControlInterface_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IControlInterface_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IControlInterface_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IControlInterface_GetName(This,ppwstrName) \ + ( (This)->lpVtbl -> GetName(This,ppwstrName) ) + +#define IControlInterface_GetIID(This,pIID) \ + ( (This)->lpVtbl -> GetIID(This,pIID) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IControlInterface_INTERFACE_DEFINED__ */ + + +#ifndef __IControlChangeNotify_INTERFACE_DEFINED__ +#define __IControlChangeNotify_INTERFACE_DEFINED__ + +/* interface IControlChangeNotify */ +/* [unique][helpstring][nonextensible][uuid][local][object] */ + + +EXTERN_C const IID IID_IControlChangeNotify; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("A09513ED-C709-4d21-BD7B-5F34C47F3947") + IControlChangeNotify : public IUnknown + { + public: + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE OnNotify( + /* [in] */ + __in DWORD dwSenderProcessId, + /* [unique][in] */ + __in_opt LPCGUID pguidEventContext) = 0; + + }; + +#else /* C style interface */ + + typedef struct IControlChangeNotifyVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IControlChangeNotify * This, + /* [in] */ REFIID riid, + /* [iid_is][out] */ + __RPC__deref_out void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IControlChangeNotify * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IControlChangeNotify * This); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *OnNotify )( + IControlChangeNotify * This, + /* [in] */ + __in DWORD dwSenderProcessId, + /* [unique][in] */ + __in_opt LPCGUID pguidEventContext); + + END_INTERFACE + } IControlChangeNotifyVtbl; + + interface IControlChangeNotify + { + CONST_VTBL struct IControlChangeNotifyVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IControlChangeNotify_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IControlChangeNotify_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IControlChangeNotify_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IControlChangeNotify_OnNotify(This,dwSenderProcessId,pguidEventContext) \ + ( (This)->lpVtbl -> OnNotify(This,dwSenderProcessId,pguidEventContext) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IControlChangeNotify_INTERFACE_DEFINED__ */ + + +#ifndef __IDeviceTopology_INTERFACE_DEFINED__ +#define __IDeviceTopology_INTERFACE_DEFINED__ + +/* interface IDeviceTopology */ +/* [unique][helpstring][nonextensible][uuid][local][object] */ + + +EXTERN_C const IID IID_IDeviceTopology; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("2A07407E-6497-4A18-9787-32F79BD0D98F") + IDeviceTopology : public IUnknown + { + public: + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE GetConnectorCount( + /* [out] */ + __out UINT *pCount) = 0; + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE GetConnector( + /* [in] */ + __in UINT nIndex, + /* [out] */ + __out IConnector **ppConnector) = 0; + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE GetSubunitCount( + /* [out] */ + __out UINT *pCount) = 0; + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE GetSubunit( + /* [in] */ + __in UINT nIndex, + /* [out] */ + __deref_out ISubunit **ppSubunit) = 0; + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE GetPartById( + /* [in] */ + __in UINT nId, + /* [out] */ + __deref_out IPart **ppPart) = 0; + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE GetDeviceId( + /* [out] */ + __deref_out LPWSTR *ppwstrDeviceId) = 0; + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE GetSignalPath( + /* [in] */ + __in IPart *pIPartFrom, + /* [in] */ + __in IPart *pIPartTo, + /* [in] */ + __in BOOL bRejectMixedPaths, + /* [out] */ + __deref_out IPartsList **ppParts) = 0; + + }; + +#else /* C style interface */ + + typedef struct IDeviceTopologyVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDeviceTopology * This, + /* [in] */ REFIID riid, + /* [iid_is][out] */ + __RPC__deref_out void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDeviceTopology * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDeviceTopology * This); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *GetConnectorCount )( + IDeviceTopology * This, + /* [out] */ + __out UINT *pCount); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *GetConnector )( + IDeviceTopology * This, + /* [in] */ + __in UINT nIndex, + /* [out] */ + __out IConnector **ppConnector); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *GetSubunitCount )( + IDeviceTopology * This, + /* [out] */ + __out UINT *pCount); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *GetSubunit )( + IDeviceTopology * This, + /* [in] */ + __in UINT nIndex, + /* [out] */ + __deref_out ISubunit **ppSubunit); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *GetPartById )( + IDeviceTopology * This, + /* [in] */ + __in UINT nId, + /* [out] */ + __deref_out IPart **ppPart); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *GetDeviceId )( + IDeviceTopology * This, + /* [out] */ + __deref_out LPWSTR *ppwstrDeviceId); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *GetSignalPath )( + IDeviceTopology * This, + /* [in] */ + __in IPart *pIPartFrom, + /* [in] */ + __in IPart *pIPartTo, + /* [in] */ + __in BOOL bRejectMixedPaths, + /* [out] */ + __deref_out IPartsList **ppParts); + + END_INTERFACE + } IDeviceTopologyVtbl; + + interface IDeviceTopology + { + CONST_VTBL struct IDeviceTopologyVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDeviceTopology_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDeviceTopology_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDeviceTopology_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDeviceTopology_GetConnectorCount(This,pCount) \ + ( (This)->lpVtbl -> GetConnectorCount(This,pCount) ) + +#define IDeviceTopology_GetConnector(This,nIndex,ppConnector) \ + ( (This)->lpVtbl -> GetConnector(This,nIndex,ppConnector) ) + +#define IDeviceTopology_GetSubunitCount(This,pCount) \ + ( (This)->lpVtbl -> GetSubunitCount(This,pCount) ) + +#define IDeviceTopology_GetSubunit(This,nIndex,ppSubunit) \ + ( (This)->lpVtbl -> GetSubunit(This,nIndex,ppSubunit) ) + +#define IDeviceTopology_GetPartById(This,nId,ppPart) \ + ( (This)->lpVtbl -> GetPartById(This,nId,ppPart) ) + +#define IDeviceTopology_GetDeviceId(This,ppwstrDeviceId) \ + ( (This)->lpVtbl -> GetDeviceId(This,ppwstrDeviceId) ) + +#define IDeviceTopology_GetSignalPath(This,pIPartFrom,pIPartTo,bRejectMixedPaths,ppParts) \ + ( (This)->lpVtbl -> GetSignalPath(This,pIPartFrom,pIPartTo,bRejectMixedPaths,ppParts) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDeviceTopology_INTERFACE_DEFINED__ */ + + + +#ifndef __DevTopologyLib_LIBRARY_DEFINED__ +#define __DevTopologyLib_LIBRARY_DEFINED__ + +/* library DevTopologyLib */ +/* [helpstring][version][uuid] */ + + + + + + + + + + + + + + + + +EXTERN_C const IID LIBID_DevTopologyLib; + +EXTERN_C const CLSID CLSID_DeviceTopology; + +#ifdef __cplusplus + +class DECLSPEC_UUID("1DF639D0-5EC1-47AA-9379-828DC1AA8C59") +DeviceTopology; +#endif +#endif /* __DevTopologyLib_LIBRARY_DEFINED__ */ + +/* Additional Prototypes for ALL interfaces */ + +/* end of Additional Prototypes */ + +#ifdef __cplusplus +} +#endif + +#endif + + + diff --git a/extern/portaudio/src/hostapi/wasapi/mingw-include/endpointvolume.h b/extern/portaudio/src/hostapi/wasapi/mingw-include/endpointvolume.h new file mode 100644 index 0000000..81155d7 --- /dev/null +++ b/extern/portaudio/src/hostapi/wasapi/mingw-include/endpointvolume.h @@ -0,0 +1,620 @@ + + +/* this ALWAYS GENERATED file contains the definitions for the interfaces */ + + + /* File created by MIDL compiler version 7.00.0499 */ +/* Compiler settings for endpointvolume.idl: + Oicf, W1, Zp8, env=Win32 (32b run) + protocol : dce , ms_ext, c_ext, robust + error checks: allocation ref bounds_check enum stub_data + VC __declspec() decoration level: + __declspec(uuid()), __declspec(selectany), __declspec(novtable) + DECLSPEC_UUID(), MIDL_INTERFACE() +*/ +//@@MIDL_FILE_HEADING( ) + +#pragma warning( disable: 4049 ) /* more than 64k source lines */ + + +/* verify that the version is high enough to compile this file*/ +#ifndef __REQUIRED_RPCNDR_H_VERSION__ +#define __REQUIRED_RPCNDR_H_VERSION__ 500 +#endif + +/* verify that the version is high enough to compile this file*/ +#ifndef __REQUIRED_RPCSAL_H_VERSION__ +#define __REQUIRED_RPCSAL_H_VERSION__ 100 +#endif + +#include "rpc.h" +#include "rpcndr.h" + +#ifndef __RPCNDR_H_VERSION__ +#error this stub requires an updated version of +#endif // __RPCNDR_H_VERSION__ + +#ifndef COM_NO_WINDOWS_H +#include "windows.h" +#include "ole2.h" +#endif /*COM_NO_WINDOWS_H*/ + +#ifndef __endpointvolume_h__ +#define __endpointvolume_h__ + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +/* Forward Declarations */ + +#ifndef __IAudioEndpointVolumeCallback_FWD_DEFINED__ +#define __IAudioEndpointVolumeCallback_FWD_DEFINED__ +typedef interface IAudioEndpointVolumeCallback IAudioEndpointVolumeCallback; +#endif /* __IAudioEndpointVolumeCallback_FWD_DEFINED__ */ + + +#ifndef __IAudioEndpointVolume_FWD_DEFINED__ +#define __IAudioEndpointVolume_FWD_DEFINED__ +typedef interface IAudioEndpointVolume IAudioEndpointVolume; +#endif /* __IAudioEndpointVolume_FWD_DEFINED__ */ + + +#ifndef __IAudioMeterInformation_FWD_DEFINED__ +#define __IAudioMeterInformation_FWD_DEFINED__ +typedef interface IAudioMeterInformation IAudioMeterInformation; +#endif /* __IAudioMeterInformation_FWD_DEFINED__ */ + + +/* header files for imported files */ +#include "unknwn.h" +#include "devicetopology.h" + +#ifdef __cplusplus +extern "C"{ +#endif + + +/* interface __MIDL_itf_endpointvolume_0000_0000 */ +/* [local] */ + +typedef struct AUDIO_VOLUME_NOTIFICATION_DATA + { + GUID guidEventContext; + BOOL bMuted; + float fMasterVolume; + UINT nChannels; + float afChannelVolumes[ 1 ]; + } AUDIO_VOLUME_NOTIFICATION_DATA; + +typedef struct AUDIO_VOLUME_NOTIFICATION_DATA *PAUDIO_VOLUME_NOTIFICATION_DATA; + +#define ENDPOINT_HARDWARE_SUPPORT_VOLUME 0x00000001 +#define ENDPOINT_HARDWARE_SUPPORT_MUTE 0x00000002 +#define ENDPOINT_HARDWARE_SUPPORT_METER 0x00000004 + + +extern RPC_IF_HANDLE __MIDL_itf_endpointvolume_0000_0000_v0_0_c_ifspec; +extern RPC_IF_HANDLE __MIDL_itf_endpointvolume_0000_0000_v0_0_s_ifspec; + +#ifndef __IAudioEndpointVolumeCallback_INTERFACE_DEFINED__ +#define __IAudioEndpointVolumeCallback_INTERFACE_DEFINED__ + +/* interface IAudioEndpointVolumeCallback */ +/* [unique][helpstring][nonextensible][uuid][local][object] */ + + +EXTERN_C const IID IID_IAudioEndpointVolumeCallback; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("657804FA-D6AD-4496-8A60-352752AF4F89") + IAudioEndpointVolumeCallback : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE OnNotify( + PAUDIO_VOLUME_NOTIFICATION_DATA pNotify) = 0; + + }; + +#else /* C style interface */ + + typedef struct IAudioEndpointVolumeCallbackVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IAudioEndpointVolumeCallback * This, + /* [in] */ REFIID riid, + /* [iid_is][out] */ + __RPC__deref_out void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IAudioEndpointVolumeCallback * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IAudioEndpointVolumeCallback * This); + + HRESULT ( STDMETHODCALLTYPE *OnNotify )( + IAudioEndpointVolumeCallback * This, + PAUDIO_VOLUME_NOTIFICATION_DATA pNotify); + + END_INTERFACE + } IAudioEndpointVolumeCallbackVtbl; + + interface IAudioEndpointVolumeCallback + { + CONST_VTBL struct IAudioEndpointVolumeCallbackVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IAudioEndpointVolumeCallback_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IAudioEndpointVolumeCallback_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IAudioEndpointVolumeCallback_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IAudioEndpointVolumeCallback_OnNotify(This,pNotify) \ + ( (This)->lpVtbl -> OnNotify(This,pNotify) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IAudioEndpointVolumeCallback_INTERFACE_DEFINED__ */ + + +#ifndef __IAudioEndpointVolume_INTERFACE_DEFINED__ +#define __IAudioEndpointVolume_INTERFACE_DEFINED__ + +/* interface IAudioEndpointVolume */ +/* [unique][helpstring][nonextensible][uuid][local][object] */ + + +EXTERN_C const IID IID_IAudioEndpointVolume; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("5CDF2C82-841E-4546-9722-0CF74078229A") + IAudioEndpointVolume : public IUnknown + { + public: + virtual /* [helpstring] */ HRESULT STDMETHODCALLTYPE RegisterControlChangeNotify( + /* [in] */ + __in IAudioEndpointVolumeCallback *pNotify) = 0; + + virtual /* [helpstring] */ HRESULT STDMETHODCALLTYPE UnregisterControlChangeNotify( + /* [in] */ + __in IAudioEndpointVolumeCallback *pNotify) = 0; + + virtual /* [helpstring] */ HRESULT STDMETHODCALLTYPE GetChannelCount( + /* [out] */ + __out UINT *pnChannelCount) = 0; + + virtual /* [helpstring] */ HRESULT STDMETHODCALLTYPE SetMasterVolumeLevel( + /* [in] */ + __in float fLevelDB, + /* [unique][in] */ LPCGUID pguidEventContext) = 0; + + virtual /* [helpstring] */ HRESULT STDMETHODCALLTYPE SetMasterVolumeLevelScalar( + /* [in] */ + __in float fLevel, + /* [unique][in] */ LPCGUID pguidEventContext) = 0; + + virtual /* [helpstring] */ HRESULT STDMETHODCALLTYPE GetMasterVolumeLevel( + /* [out] */ + __out float *pfLevelDB) = 0; + + virtual /* [helpstring] */ HRESULT STDMETHODCALLTYPE GetMasterVolumeLevelScalar( + /* [out] */ + __out float *pfLevel) = 0; + + virtual /* [helpstring] */ HRESULT STDMETHODCALLTYPE SetChannelVolumeLevel( + /* [in] */ + __in UINT nChannel, + float fLevelDB, + /* [unique][in] */ LPCGUID pguidEventContext) = 0; + + virtual /* [helpstring] */ HRESULT STDMETHODCALLTYPE SetChannelVolumeLevelScalar( + /* [in] */ + __in UINT nChannel, + float fLevel, + /* [unique][in] */ LPCGUID pguidEventContext) = 0; + + virtual /* [helpstring] */ HRESULT STDMETHODCALLTYPE GetChannelVolumeLevel( + /* [in] */ + __in UINT nChannel, + /* [out] */ + __out float *pfLevelDB) = 0; + + virtual /* [helpstring] */ HRESULT STDMETHODCALLTYPE GetChannelVolumeLevelScalar( + /* [in] */ + __in UINT nChannel, + /* [out] */ + __out float *pfLevel) = 0; + + virtual /* [helpstring] */ HRESULT STDMETHODCALLTYPE SetMute( + /* [in] */ + __in BOOL bMute, + /* [unique][in] */ LPCGUID pguidEventContext) = 0; + + virtual /* [helpstring] */ HRESULT STDMETHODCALLTYPE GetMute( + /* [out] */ + __out BOOL *pbMute) = 0; + + virtual /* [helpstring] */ HRESULT STDMETHODCALLTYPE GetVolumeStepInfo( + /* [out] */ + __out UINT *pnStep, + /* [out] */ + __out UINT *pnStepCount) = 0; + + virtual /* [helpstring] */ HRESULT STDMETHODCALLTYPE VolumeStepUp( + /* [unique][in] */ LPCGUID pguidEventContext) = 0; + + virtual /* [helpstring] */ HRESULT STDMETHODCALLTYPE VolumeStepDown( + /* [unique][in] */ LPCGUID pguidEventContext) = 0; + + virtual /* [helpstring] */ HRESULT STDMETHODCALLTYPE QueryHardwareSupport( + /* [out] */ + __out DWORD *pdwHardwareSupportMask) = 0; + + virtual /* [helpstring] */ HRESULT STDMETHODCALLTYPE GetVolumeRange( + /* [out] */ + __out float *pflVolumeMindB, + /* [out] */ + __out float *pflVolumeMaxdB, + /* [out] */ + __out float *pflVolumeIncrementdB) = 0; + + }; + +#else /* C style interface */ + + typedef struct IAudioEndpointVolumeVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IAudioEndpointVolume * This, + /* [in] */ REFIID riid, + /* [iid_is][out] */ + __RPC__deref_out void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IAudioEndpointVolume * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IAudioEndpointVolume * This); + + /* [helpstring] */ HRESULT ( STDMETHODCALLTYPE *RegisterControlChangeNotify )( + IAudioEndpointVolume * This, + /* [in] */ + __in IAudioEndpointVolumeCallback *pNotify); + + /* [helpstring] */ HRESULT ( STDMETHODCALLTYPE *UnregisterControlChangeNotify )( + IAudioEndpointVolume * This, + /* [in] */ + __in IAudioEndpointVolumeCallback *pNotify); + + /* [helpstring] */ HRESULT ( STDMETHODCALLTYPE *GetChannelCount )( + IAudioEndpointVolume * This, + /* [out] */ + __out UINT *pnChannelCount); + + /* [helpstring] */ HRESULT ( STDMETHODCALLTYPE *SetMasterVolumeLevel )( + IAudioEndpointVolume * This, + /* [in] */ + __in float fLevelDB, + /* [unique][in] */ LPCGUID pguidEventContext); + + /* [helpstring] */ HRESULT ( STDMETHODCALLTYPE *SetMasterVolumeLevelScalar )( + IAudioEndpointVolume * This, + /* [in] */ + __in float fLevel, + /* [unique][in] */ LPCGUID pguidEventContext); + + /* [helpstring] */ HRESULT ( STDMETHODCALLTYPE *GetMasterVolumeLevel )( + IAudioEndpointVolume * This, + /* [out] */ + __out float *pfLevelDB); + + /* [helpstring] */ HRESULT ( STDMETHODCALLTYPE *GetMasterVolumeLevelScalar )( + IAudioEndpointVolume * This, + /* [out] */ + __out float *pfLevel); + + /* [helpstring] */ HRESULT ( STDMETHODCALLTYPE *SetChannelVolumeLevel )( + IAudioEndpointVolume * This, + /* [in] */ + __in UINT nChannel, + float fLevelDB, + /* [unique][in] */ LPCGUID pguidEventContext); + + /* [helpstring] */ HRESULT ( STDMETHODCALLTYPE *SetChannelVolumeLevelScalar )( + IAudioEndpointVolume * This, + /* [in] */ + __in UINT nChannel, + float fLevel, + /* [unique][in] */ LPCGUID pguidEventContext); + + /* [helpstring] */ HRESULT ( STDMETHODCALLTYPE *GetChannelVolumeLevel )( + IAudioEndpointVolume * This, + /* [in] */ + __in UINT nChannel, + /* [out] */ + __out float *pfLevelDB); + + /* [helpstring] */ HRESULT ( STDMETHODCALLTYPE *GetChannelVolumeLevelScalar )( + IAudioEndpointVolume * This, + /* [in] */ + __in UINT nChannel, + /* [out] */ + __out float *pfLevel); + + /* [helpstring] */ HRESULT ( STDMETHODCALLTYPE *SetMute )( + IAudioEndpointVolume * This, + /* [in] */ + __in BOOL bMute, + /* [unique][in] */ LPCGUID pguidEventContext); + + /* [helpstring] */ HRESULT ( STDMETHODCALLTYPE *GetMute )( + IAudioEndpointVolume * This, + /* [out] */ + __out BOOL *pbMute); + + /* [helpstring] */ HRESULT ( STDMETHODCALLTYPE *GetVolumeStepInfo )( + IAudioEndpointVolume * This, + /* [out] */ + __out UINT *pnStep, + /* [out] */ + __out UINT *pnStepCount); + + /* [helpstring] */ HRESULT ( STDMETHODCALLTYPE *VolumeStepUp )( + IAudioEndpointVolume * This, + /* [unique][in] */ LPCGUID pguidEventContext); + + /* [helpstring] */ HRESULT ( STDMETHODCALLTYPE *VolumeStepDown )( + IAudioEndpointVolume * This, + /* [unique][in] */ LPCGUID pguidEventContext); + + /* [helpstring] */ HRESULT ( STDMETHODCALLTYPE *QueryHardwareSupport )( + IAudioEndpointVolume * This, + /* [out] */ + __out DWORD *pdwHardwareSupportMask); + + /* [helpstring] */ HRESULT ( STDMETHODCALLTYPE *GetVolumeRange )( + IAudioEndpointVolume * This, + /* [out] */ + __out float *pflVolumeMindB, + /* [out] */ + __out float *pflVolumeMaxdB, + /* [out] */ + __out float *pflVolumeIncrementdB); + + END_INTERFACE + } IAudioEndpointVolumeVtbl; + + interface IAudioEndpointVolume + { + CONST_VTBL struct IAudioEndpointVolumeVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IAudioEndpointVolume_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IAudioEndpointVolume_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IAudioEndpointVolume_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IAudioEndpointVolume_RegisterControlChangeNotify(This,pNotify) \ + ( (This)->lpVtbl -> RegisterControlChangeNotify(This,pNotify) ) + +#define IAudioEndpointVolume_UnregisterControlChangeNotify(This,pNotify) \ + ( (This)->lpVtbl -> UnregisterControlChangeNotify(This,pNotify) ) + +#define IAudioEndpointVolume_GetChannelCount(This,pnChannelCount) \ + ( (This)->lpVtbl -> GetChannelCount(This,pnChannelCount) ) + +#define IAudioEndpointVolume_SetMasterVolumeLevel(This,fLevelDB,pguidEventContext) \ + ( (This)->lpVtbl -> SetMasterVolumeLevel(This,fLevelDB,pguidEventContext) ) + +#define IAudioEndpointVolume_SetMasterVolumeLevelScalar(This,fLevel,pguidEventContext) \ + ( (This)->lpVtbl -> SetMasterVolumeLevelScalar(This,fLevel,pguidEventContext) ) + +#define IAudioEndpointVolume_GetMasterVolumeLevel(This,pfLevelDB) \ + ( (This)->lpVtbl -> GetMasterVolumeLevel(This,pfLevelDB) ) + +#define IAudioEndpointVolume_GetMasterVolumeLevelScalar(This,pfLevel) \ + ( (This)->lpVtbl -> GetMasterVolumeLevelScalar(This,pfLevel) ) + +#define IAudioEndpointVolume_SetChannelVolumeLevel(This,nChannel,fLevelDB,pguidEventContext) \ + ( (This)->lpVtbl -> SetChannelVolumeLevel(This,nChannel,fLevelDB,pguidEventContext) ) + +#define IAudioEndpointVolume_SetChannelVolumeLevelScalar(This,nChannel,fLevel,pguidEventContext) \ + ( (This)->lpVtbl -> SetChannelVolumeLevelScalar(This,nChannel,fLevel,pguidEventContext) ) + +#define IAudioEndpointVolume_GetChannelVolumeLevel(This,nChannel,pfLevelDB) \ + ( (This)->lpVtbl -> GetChannelVolumeLevel(This,nChannel,pfLevelDB) ) + +#define IAudioEndpointVolume_GetChannelVolumeLevelScalar(This,nChannel,pfLevel) \ + ( (This)->lpVtbl -> GetChannelVolumeLevelScalar(This,nChannel,pfLevel) ) + +#define IAudioEndpointVolume_SetMute(This,bMute,pguidEventContext) \ + ( (This)->lpVtbl -> SetMute(This,bMute,pguidEventContext) ) + +#define IAudioEndpointVolume_GetMute(This,pbMute) \ + ( (This)->lpVtbl -> GetMute(This,pbMute) ) + +#define IAudioEndpointVolume_GetVolumeStepInfo(This,pnStep,pnStepCount) \ + ( (This)->lpVtbl -> GetVolumeStepInfo(This,pnStep,pnStepCount) ) + +#define IAudioEndpointVolume_VolumeStepUp(This,pguidEventContext) \ + ( (This)->lpVtbl -> VolumeStepUp(This,pguidEventContext) ) + +#define IAudioEndpointVolume_VolumeStepDown(This,pguidEventContext) \ + ( (This)->lpVtbl -> VolumeStepDown(This,pguidEventContext) ) + +#define IAudioEndpointVolume_QueryHardwareSupport(This,pdwHardwareSupportMask) \ + ( (This)->lpVtbl -> QueryHardwareSupport(This,pdwHardwareSupportMask) ) + +#define IAudioEndpointVolume_GetVolumeRange(This,pflVolumeMindB,pflVolumeMaxdB,pflVolumeIncrementdB) \ + ( (This)->lpVtbl -> GetVolumeRange(This,pflVolumeMindB,pflVolumeMaxdB,pflVolumeIncrementdB) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IAudioEndpointVolume_INTERFACE_DEFINED__ */ + + +#ifndef __IAudioMeterInformation_INTERFACE_DEFINED__ +#define __IAudioMeterInformation_INTERFACE_DEFINED__ + +/* interface IAudioMeterInformation */ +/* [unique][helpstring][nonextensible][uuid][local][object] */ + + +EXTERN_C const IID IID_IAudioMeterInformation; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("C02216F6-8C67-4B5B-9D00-D008E73E0064") + IAudioMeterInformation : public IUnknown + { + public: + virtual /* [helpstring] */ HRESULT STDMETHODCALLTYPE GetPeakValue( + /* [out] */ float *pfPeak) = 0; + + virtual /* [helpstring] */ HRESULT STDMETHODCALLTYPE GetMeteringChannelCount( + /* [out] */ + __out UINT *pnChannelCount) = 0; + + virtual /* [helpstring] */ HRESULT STDMETHODCALLTYPE GetChannelsPeakValues( + /* [in] */ UINT32 u32ChannelCount, + /* [size_is][out] */ float *afPeakValues) = 0; + + virtual /* [helpstring] */ HRESULT STDMETHODCALLTYPE QueryHardwareSupport( + /* [out] */ + __out DWORD *pdwHardwareSupportMask) = 0; + + }; + +#else /* C style interface */ + + typedef struct IAudioMeterInformationVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IAudioMeterInformation * This, + /* [in] */ REFIID riid, + /* [iid_is][out] */ + __RPC__deref_out void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IAudioMeterInformation * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IAudioMeterInformation * This); + + /* [helpstring] */ HRESULT ( STDMETHODCALLTYPE *GetPeakValue )( + IAudioMeterInformation * This, + /* [out] */ float *pfPeak); + + /* [helpstring] */ HRESULT ( STDMETHODCALLTYPE *GetMeteringChannelCount )( + IAudioMeterInformation * This, + /* [out] */ + __out UINT *pnChannelCount); + + /* [helpstring] */ HRESULT ( STDMETHODCALLTYPE *GetChannelsPeakValues )( + IAudioMeterInformation * This, + /* [in] */ UINT32 u32ChannelCount, + /* [size_is][out] */ float *afPeakValues); + + /* [helpstring] */ HRESULT ( STDMETHODCALLTYPE *QueryHardwareSupport )( + IAudioMeterInformation * This, + /* [out] */ + __out DWORD *pdwHardwareSupportMask); + + END_INTERFACE + } IAudioMeterInformationVtbl; + + interface IAudioMeterInformation + { + CONST_VTBL struct IAudioMeterInformationVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IAudioMeterInformation_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IAudioMeterInformation_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IAudioMeterInformation_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IAudioMeterInformation_GetPeakValue(This,pfPeak) \ + ( (This)->lpVtbl -> GetPeakValue(This,pfPeak) ) + +#define IAudioMeterInformation_GetMeteringChannelCount(This,pnChannelCount) \ + ( (This)->lpVtbl -> GetMeteringChannelCount(This,pnChannelCount) ) + +#define IAudioMeterInformation_GetChannelsPeakValues(This,u32ChannelCount,afPeakValues) \ + ( (This)->lpVtbl -> GetChannelsPeakValues(This,u32ChannelCount,afPeakValues) ) + +#define IAudioMeterInformation_QueryHardwareSupport(This,pdwHardwareSupportMask) \ + ( (This)->lpVtbl -> QueryHardwareSupport(This,pdwHardwareSupportMask) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IAudioMeterInformation_INTERFACE_DEFINED__ */ + + +/* Additional Prototypes for ALL interfaces */ + +/* end of Additional Prototypes */ + +#ifdef __cplusplus +} +#endif + +#endif + + + diff --git a/extern/portaudio/src/hostapi/wasapi/mingw-include/functiondiscoverykeys.h b/extern/portaudio/src/hostapi/wasapi/mingw-include/functiondiscoverykeys.h new file mode 100644 index 0000000..7e07292 --- /dev/null +++ b/extern/portaudio/src/hostapi/wasapi/mingw-include/functiondiscoverykeys.h @@ -0,0 +1,255 @@ +#pragma once + +#if __GNUC__ >=3 +#pragma GCC system_header +#endif + +#ifndef DEFINE_API_PKEY +#include +#endif + +#include + +// FMTID_FD = {904b03a2-471d-423c-a584-f3483238a146} +DEFINE_GUID(FMTID_FD, 0x904b03a2, 0x471d, 0x423c, 0xa5, 0x84, 0xf3, 0x48, 0x32, 0x38, 0xa1, 0x46); +DEFINE_API_PKEY(PKEY_FD_Visibility, VisibilityFlags, 0x904b03a2, 0x471d, 0x423c, 0xa5, 0x84, 0xf3, 0x48, 0x32, 0x38, 0xa1, 0x46, 0x00000001); // VT_UINT +#define FD_Visibility_Default 0 +#define FD_Visibility_Hidden 1 + +// FMTID_Device = {78C34FC8-104A-4aca-9EA4-524D52996E57} +DEFINE_GUID(FMTID_Device, 0x78c34fc8, 0x104a, 0x4aca, 0x9e, 0xa4, 0x52, 0x4d, 0x52, 0x99, 0x6e, 0x57); + +DEFINE_API_PKEY(PKEY_Device_NotPresent, DeviceNotPresent , 0x904b03a2, 0x471d, 0x423c, 0xa5, 0x84, 0xf3, 0x48, 0x32, 0x38, 0xa1, 0x46, 0x00000002); // VT_UINT +DEFINE_API_PKEY(PKEY_Device_QueueSize, DeviceQueueSize , 0x78c34fc8, 0x104a, 0x4aca, 0x9e, 0xa4, 0x52, 0x4d, 0x52, 0x99, 0x6e, 0x57, 0x00000024); // VT_UI4 +DEFINE_API_PKEY(PKEY_Device_Status, DeviceStatus , 0x78c34fc8, 0x104a, 0x4aca, 0x9e, 0xa4, 0x52, 0x4d, 0x52, 0x99, 0x6e, 0x57, 0x00000025); // VT_LPWSTR +DEFINE_API_PKEY(PKEY_Device_Comment, DeviceComment , 0x78c34fc8, 0x104a, 0x4aca, 0x9e, 0xa4, 0x52, 0x4d, 0x52, 0x99, 0x6e, 0x57, 0x00000026); // VT_LPWSTR +DEFINE_API_PKEY(PKEY_Device_Model, DeviceModel , 0x78c34fc8, 0x104a, 0x4aca, 0x9e, 0xa4, 0x52, 0x4d, 0x52, 0x99, 0x6e, 0x57, 0x00000027); // VT_LPWSTR + +// Name: System.Device.BIOSVersion -- PKEY_Device_BIOSVersion +// Type: String -- VT_LPWSTR (For variants: VT_BSTR) Legacy code may treat this as VT_BSTR. +// FormatID: EAEE7F1D-6A33-44D1-9441-5F46DEF23198, 9 +DEFINE_PROPERTYKEY(PKEY_Device_BIOSVersion, 0xEAEE7F1D, 0x6A33, 0x44D1, 0x94, 0x41, 0x5F, 0x46, 0xDE, 0xF2, 0x31, 0x98, 9); + +DEFINE_API_PKEY(PKEY_Write_Time, WriteTime , 0xf53b7e1c, 0x77e0, 0x4450, 0x8c, 0x5f, 0xa7, 0x6c, 0xc7, 0xfd, 0xe0, 0x58, 0x00000100); // VT_FILETIME + +#ifdef FD_XP +DEFINE_API_PKEY(PKEY_Device_InstanceId, DeviceInstanceId , 0x78c34fc8, 0x104a, 0x4aca, 0x9e, 0xa4, 0x52, 0x4d, 0x52, 0x99, 0x6e, 0x57, 0x00000100); // VT_LPWSTR +#endif +DEFINE_API_PKEY(PKEY_Device_Interface, DeviceInterface , 0x78c34fc8, 0x104a, 0x4aca, 0x9e, 0xa4, 0x52, 0x4d, 0x52, 0x99, 0x6e, 0x57, 0x00000101); // VT_CLSID + +DEFINE_API_PKEY(PKEY_ExposedIIDs, ExposedIIDs , 0x78c34fc8, 0x104a, 0x4aca, 0x9e, 0xa4, 0x52, 0x4d, 0x52, 0x99, 0x6e, 0x57, 0x00003002); // VT_VECTOR | VT_CLSID +DEFINE_API_PKEY(PKEY_ExposedCLSIDs, ExposedCLSIDs , 0x78c34fc8, 0x104a, 0x4aca, 0x9e, 0xa4, 0x52, 0x4d, 0x52, 0x99, 0x6e, 0x57, 0x00003003); // VT_VECTOR | VT_CLSID +DEFINE_API_PKEY(PKEY_InstanceValidatorClsid,InstanceValidator , 0x78c34fc8, 0x104a, 0x4aca, 0x9e, 0xa4, 0x52, 0x4d, 0x52, 0x99, 0x6e, 0x57, 0x00003004); // VT_CLSID + +// FMTID_WSD = {92506491-FF95-4724-A05A-5B81885A7C92} +DEFINE_GUID(FMTID_WSD, 0x92506491, 0xFF95, 0x4724, 0xA0, 0x5A, 0x5B, 0x81, 0x88, 0x5A, 0x7C, 0x92); + +DEFINE_API_PKEY(PKEY_WSD_AddressURI, WSD_AddressURI, 0x92506491, 0xFF95, 0x4724, 0xA0, 0x5A, 0x5B, 0x81, 0x88, 0x5A, 0x7C, 0x92, 0x00001000); // VT_LPWSTR +DEFINE_API_PKEY(PKEY_WSD_Types, WSD_Types, 0x92506491, 0xFF95, 0x4724, 0xA0, 0x5A, 0x5B, 0x81, 0x88, 0x5A, 0x7C, 0x92, 0x00001001); // VT_LPWSTR +DEFINE_API_PKEY(PKEY_WSD_Scopes, WSD_Scopes, 0x92506491, 0xFF95, 0x4724, 0xA0, 0x5A, 0x5B, 0x81, 0x88, 0x5A, 0x7C, 0x92, 0x00001002); // VT_LPWSTR +DEFINE_API_PKEY(PKEY_WSD_MetadataVersion, WSD_MetadataVersion, 0x92506491, 0xFF95, 0x4724, 0xA0, 0x5A, 0x5B, 0x81, 0x88, 0x5A, 0x7C, 0x92, 0x00001003); //VT_UI8 +DEFINE_API_PKEY(PKEY_WSD_AppSeqInstanceID, WSD_AppSeqInstanceID, 0x92506491, 0xFF95, 0x4724, 0xA0, 0x5A, 0x5B, 0x81, 0x88, 0x5A, 0x7C, 0x92, 0x00001004); // VT_UI8 +DEFINE_API_PKEY(PKEY_WSD_AppSeqSessionID, WSD_AppSeqSessionID, 0x92506491, 0xFF95, 0x4724, 0xA0, 0x5A, 0x5B, 0x81, 0x88, 0x5A, 0x7C, 0x92, 0x00001005); // VT_LPWSTR +DEFINE_API_PKEY(PKEY_WSD_AppSeqMessageNumber, WSD_AppSeqMessageNumber, 0x92506491, 0xFF95, 0x4724, 0xA0, 0x5A, 0x5B, 0x81, 0x88, 0x5A, 0x7C, 0x92, 0x00001006); // VT_UI8 +DEFINE_API_PKEY(PKEY_WSD_XAddrs, WSD_XAddrs, 0x92506491, 0xFF95, 0x4724, 0xA0, 0x5A, 0x5B, 0x81, 0x88, 0x5A, 0x7C, 0x92, 0x00002000); // VT_LPWSTR or VT_VECTOR | VT_LPWSTR + +DEFINE_API_PKEY(PKEY_WSD_MetadataClean, WSD_MetadataClean, 0x92506491, 0xFF95, 0x4724, 0xA0, 0x5A, 0x5B, 0x81, 0x88, 0x5A, 0x7C, 0x92, 0x00000001); // VT_BOOL +DEFINE_API_PKEY(PKEY_WSD_ServiceInfo, WSD_ServiceInfo, 0x92506491, 0xFF95, 0x4724, 0xA0, 0x5A, 0x5B, 0x81, 0x88, 0x5A, 0x7C, 0x92, 0x00000002); // VT_VECTOR|VT_VARIANT (variants are VT_UNKNOWN) + +DEFINE_API_PKEY(PKEY_PUBSVCS_TYPE, PUBSVCS_TYPE, 0xF1B88AD3, 0x109C, 0x4FD2, 0xBA, 0x3F, 0x53, 0x5A, 0x76, 0x5F, 0x82, 0xF4, 0x00005001); // VT_LPWSTR +DEFINE_API_PKEY(PKEY_PUBSVCS_SCOPE, PUBSVCS_SCOPE, 0x2AE2B567, 0xEECB, 0x4A3E, 0xB7, 0x53, 0x54, 0xC7, 0x25, 0x49, 0x43, 0x66, 0x00005002); // VT_LPWSTR | VT_VECTOR +DEFINE_API_PKEY(PKEY_PUBSVCS_METADATA, PUBSVCS_METADATA, 0x63C6D5B8, 0xF73A, 0x4ACA, 0x96, 0x7E, 0x0C, 0xC7, 0x87, 0xE0, 0xB5, 0x59, 0x00005003); // VT_LPWSTR +DEFINE_API_PKEY(PKEY_PUBSVCS_METADATA_VERSION, PUBSVCS_METADATA_VERSION, 0xC0C96C15, 0x1823, 0x4E5B, 0x93, 0x48, 0xE8, 0x25, 0x19, 0x92, 0x3F, 0x04, 0x00005004); // VT_UI8 +DEFINE_API_PKEY(PKEY_PUBSVCS_NETWORK_PROFILES_ALLOWED, PUBSVCS_NETWORK_PROFILES_ALLOWED, 0x63C6D5B8, 0xF73A, 0x4ACA, 0x96, 0x7E, 0x0C, 0xC7, 0x87, 0xE0, 0xB5, 0x59, 0x00005005); // VT_VECTOR | VT_LPWSTR +DEFINE_API_PKEY(PKEY_PUBSVCS_NETWORK_PROFILES_DENIED, PUBSVCS_NETWORK_PROFILES_DENIED, 0x63C6D5B8, 0xF73A, 0x4ACA, 0x96, 0x7E, 0x0C, 0xC7, 0x87, 0xE0, 0xB5, 0x59, 0x00005006); // VT_VECTOR | VT_LPWSTR +DEFINE_API_PKEY(PKEY_PUBSVCS_NETWORK_PROFILES_DEFAULT, PUBSVCS_NETWORK_PROFILES_DEFAULT, 0x63C6D5B8, 0xF73A, 0x4ACA, 0x96, 0x7E, 0x0C, 0xC7, 0x87, 0xE0, 0xB5, 0x59, 0x00005007); // VT_BOOL + +// FMTID_PNPX = {656A3BB3-ECC0-43FD-8477-4AE0404A96CD} +DEFINE_GUID(FMTID_PNPX, 0x656A3BB3, 0xECC0, 0x43FD, 0x84, 0x77, 0x4A, 0xE0, 0x40, 0x4A, 0x96, 0xCD); + // from Discovery messages +DEFINE_PROPERTYKEY(PKEY_PNPX_GlobalIdentity, 0x656A3BB3, 0xECC0, 0x43FD, 0x84, 0x77, 0x4A, 0xE0, 0x40, 0x4A, 0x96, 0xCD, 0x00001000); // VT_LPWSTR +DEFINE_PROPERTYKEY(PKEY_PNPX_Types, 0x656A3BB3, 0xECC0, 0x43FD, 0x84, 0x77, 0x4A, 0xE0, 0x40, 0x4A, 0x96, 0xCD, 0x00001001); // VT_LPWSTR | VT_VECTOR +DEFINE_PROPERTYKEY(PKEY_PNPX_Scopes, 0x656A3BB3, 0xECC0, 0x43FD, 0x84, 0x77, 0x4A, 0xE0, 0x40, 0x4A, 0x96, 0xCD, 0x00001002); // VT_LPWSTR | VT_VECTOR +DEFINE_PROPERTYKEY(PKEY_PNPX_XAddrs, 0x656A3BB3, 0xECC0, 0x43FD, 0x84, 0x77, 0x4A, 0xE0, 0x40, 0x4A, 0x96, 0xCD, 0x00001003); // VT_LPWSTR | VT_VECTOR +DEFINE_PROPERTYKEY(PKEY_PNPX_MetadataVersion, 0x656A3BB3, 0xECC0, 0x43FD, 0x84, 0x77, 0x4A, 0xE0, 0x40, 0x4A, 0x96, 0xCD, 0x00001004); // VT_UI8 +DEFINE_PROPERTYKEY(PKEY_PNPX_ID, 0x656A3BB3, 0xECC0, 0x43FD, 0x84, 0x77, 0x4A, 0xE0, 0x40, 0x4A, 0x96, 0xCD, 0x00001005); // VT_LPWSTR +DEFINE_PROPERTYKEY(PKEY_PNPX_RootProxy, 0x656A3BB3, 0xECC0, 0x43FD, 0x84, 0x77, 0x4A, 0xE0, 0x40, 0x4A, 0x96, 0xCD, 0x00001006); // VT_BOOL + + // for Directed Discovery +DEFINE_PROPERTYKEY(PKEY_PNPX_RemoteAddress, 0x656A3BB3, 0xECC0, 0x43FD, 0x84, 0x77, 0x4A, 0xE0, 0x40, 0x4A, 0x96, 0xCD, 0x00001006); // VT_LPWSTR + + // from ThisModel metadata +DEFINE_PROPERTYKEY(PKEY_PNPX_Manufacturer, 0x656A3BB3, 0xECC0, 0x43FD, 0x84, 0x77, 0x4A, 0xE0, 0x40, 0x4A, 0x96, 0xCD, 0x00002000); // VT_LPWSTR (localizable) +DEFINE_PROPERTYKEY(PKEY_PNPX_ManufacturerUrl, 0x656A3BB3, 0xECC0, 0x43FD, 0x84, 0x77, 0x4A, 0xE0, 0x40, 0x4A, 0x96, 0xCD, 0x00002001); // VT_LPWSTR +DEFINE_PROPERTYKEY(PKEY_PNPX_ModelName, 0x656A3BB3, 0xECC0, 0x43FD, 0x84, 0x77, 0x4A, 0xE0, 0x40, 0x4A, 0x96, 0xCD, 0x00002002); // VT_LPWSTR (localizable) +DEFINE_PROPERTYKEY(PKEY_PNPX_ModelNumber, 0x656A3BB3, 0xECC0, 0x43FD, 0x84, 0x77, 0x4A, 0xE0, 0x40, 0x4A, 0x96, 0xCD, 0x00002003); // VT_LPWSTR +DEFINE_PROPERTYKEY(PKEY_PNPX_ModelUrl, 0x656A3BB3, 0xECC0, 0x43FD, 0x84, 0x77, 0x4A, 0xE0, 0x40, 0x4A, 0x96, 0xCD, 0x00002004); // VT_LPWSTR +DEFINE_PROPERTYKEY(PKEY_PNPX_Upc, 0x656A3BB3, 0xECC0, 0x43FD, 0x84, 0x77, 0x4A, 0xE0, 0x40, 0x4A, 0x96, 0xCD, 0x00002005); // VT_LPWSTR +DEFINE_PROPERTYKEY(PKEY_PNPX_PresentationUrl, 0x656A3BB3, 0xECC0, 0x43FD, 0x84, 0x77, 0x4A, 0xE0, 0x40, 0x4A, 0x96, 0xCD, 0x00002006); // VT_LPWSTR + // from ThisDevice metadata +DEFINE_PROPERTYKEY(PKEY_PNPX_FriendlyName, 0x656A3BB3, 0xECC0, 0x43FD, 0x84, 0x77, 0x4A, 0xE0, 0x40, 0x4A, 0x96, 0xCD, 0x00003000); // VT_LPWSTR (localizable) +DEFINE_PROPERTYKEY(PKEY_PNPX_FirmwareVersion, 0x656A3BB3, 0xECC0, 0x43FD, 0x84, 0x77, 0x4A, 0xE0, 0x40, 0x4A, 0x96, 0xCD, 0x00003001); // VT_LPWSTR +DEFINE_PROPERTYKEY(PKEY_PNPX_SerialNumber, 0x656A3BB3, 0xECC0, 0x43FD, 0x84, 0x77, 0x4A, 0xE0, 0x40, 0x4A, 0x96, 0xCD, 0x00003002); // VT_LPWSTR +DEFINE_PROPERTYKEY(PKEY_PNPX_DeviceCategory, 0x656A3BB3, 0xECC0, 0x43FD, 0x84, 0x77, 0x4A, 0xE0, 0x40, 0x4A, 0x96, 0xCD, 0x00003004); // VT_LPWSTR | VT_VECTOR + // DeviceCategory values +#define PNPX_DEVICECATEGORY_COMPUTER L"Computers" +#define PNPX_DEVICECATEGORY_INPUTDEVICE L"Input" +#define PNPX_DEVICECATEGORY_PRINTER L"Printers" +#define PNPX_DEVICECATEGORY_SCANNER L"Scanners" +#define PNPX_DEVICECATEGORY_FAX L"FAX" +#define PNPX_DEVICECATEGORY_MFP L"MFP" +#define PNPX_DEVICECATEGORY_CAMERA L"Cameras" +#define PNPX_DEVICECATEGORY_STORAGE L"Storage" +#define PNPX_DEVICECATEGORY_NETWORK_INFRASTRUCTURE L"NetworkInfrastructure" +#define PNPX_DEVICECATEGORY_DISPLAYS L"Displays" +#define PNPX_DEVICECATEGORY_MULTIMEDIA_DEVICE L"MediaDevices" +#define PNPX_DEVICECATEGORY_GAMING_DEVICE L"Gaming" +#define PNPX_DEVICECATEGORY_TELEPHONE L"Phones" +#define PNPX_DEVICECATEGORY_HOME_AUTOMATION_SYSTEM L"HomeAutomation" +#define PNPX_DEVICECATEGORY_HOME_SECURITY_SYSTEM L"HomeSecurity" +#define PNPX_DEVICECATEGORY_OTHER L"Other" +DEFINE_PROPERTYKEY(PKEY_PNPX_DeviceCategory_Desc, 0x656A3BB3, 0xECC0, 0x43FD, 0x84, 0x77, 0x4A, 0xE0, 0x40, 0x4A, 0x96, 0xCD, 0x00003005); // VT_LPWSTR | VT_VECTOR + +DEFINE_PROPERTYKEY(PKEY_PNPX_PhysicalAddress, 0x656A3BB3, 0xECC0, 0x43FD, 0x84, 0x77, 0x4A, 0xE0, 0x40, 0x4A, 0x96, 0xCD, 0x00003006); // VT_UI1 | VT_VECTOR +DEFINE_PROPERTYKEY(PKEY_PNPX_NetworkInterfaceLuid, 0x656A3BB3, 0xECC0, 0x43FD, 0x84, 0x77, 0x4A, 0xE0, 0x40, 0x4A, 0x96, 0xCD, 0x00003007); // VT_UI8 +DEFINE_PROPERTYKEY(PKEY_PNPX_NetworkInterfaceGuid, 0x656A3BB3, 0xECC0, 0x43FD, 0x84, 0x77, 0x4A, 0xE0, 0x40, 0x4A, 0x96, 0xCD, 0x00003008); // VT_LPWSTR +DEFINE_PROPERTYKEY(PKEY_PNPX_IpAddress, 0x656A3BB3, 0xECC0, 0x43FD, 0x84, 0x77, 0x4A, 0xE0, 0x40, 0x4A, 0x96, 0xCD, 0x00003009); // VT_LPWSTR | VT_VECTOR + // from Relationship metadata +DEFINE_PROPERTYKEY(PKEY_PNPX_ServiceAddress, 0x656A3BB3, 0xECC0, 0x43FD, 0x84, 0x77, 0x4A, 0xE0, 0x40, 0x4A, 0x96, 0xCD, 0x00004000); // VT_LPWSTR | VT_VECTOR +DEFINE_PROPERTYKEY(PKEY_PNPX_ServiceId, 0x656A3BB3, 0xECC0, 0x43FD, 0x84, 0x77, 0x4A, 0xE0, 0x40, 0x4A, 0x96, 0xCD, 0x00004001); // VT_LPWSTR +DEFINE_PROPERTYKEY(PKEY_PNPX_ServiceTypes, 0x656A3BB3, 0xECC0, 0x43FD, 0x84, 0x77, 0x4A, 0xE0, 0x40, 0x4A, 0x96, 0xCD, 0x00004002); // VT_LPWSTR | VT_VECTOR + // Association DB PKEYs +DEFINE_API_PKEY(PKEY_PNPX_Devnode, PnPXDevNode, 0x656A3BB3, 0xECC0, 0x43FD, 0x84, 0x77, 0x4A, 0xE0, 0x40, 0x4A, 0x96, 0xCD, 0x00000001); // VT_BOOL +DEFINE_API_PKEY(PKEY_PNPX_AssociationState, AssociationState, 0x656A3BB3, 0xECC0, 0x43FD, 0x84, 0x77, 0x4A, 0xE0, 0x40, 0x4A, 0x96, 0xCD, 0x00000002); // VT_UINT +DEFINE_API_PKEY(PKEY_PNPX_AssociatedInstanceId, AssociatedInstanceId, 0x656A3BB3, 0xECC0, 0x43FD, 0x84, 0x77, 0x4A, 0xE0, 0x40, 0x4A, 0x96, 0xCD, 0x00000003); // VT_LPWSTR + // for Computer Discovery +DEFINE_PROPERTYKEY(PKEY_PNPX_DomainName, 0x656A3BB3, 0xECC0, 0x43FD, 0x84, 0x77, 0x4A, 0xE0, 0x40, 0x4A, 0x96, 0xCD, 0x00005000); // VT_LPWSTR +// Use PKEY_ComputerName (propkey.h) DEFINE_PROPERTYKEY(PKEY_PNPX_MachineName, 0x656A3BB3, 0xECC0, 0x43FD, 0x84, 0x77, 0x4A, 0xE0, 0x40, 0x4A, 0x96, 0xCD, 0x00005001); // VT_LPWSTR +DEFINE_PROPERTYKEY(PKEY_PNPX_ShareName, 0x656A3BB3, 0xECC0, 0x43FD, 0x84, 0x77, 0x4A, 0xE0, 0x40, 0x4A, 0x96, 0xCD, 0x00005002); // VT_LPWSTR + + // SSDP Provider custom properties +DEFINE_PROPERTYKEY(PKEY_SSDP_AltLocationInfo, 0x656A3BB3, 0xECC0, 0x43FD, 0x84, 0x77, 0x4A, 0xE0, 0x40, 0x4A, 0x96, 0xCD, 0x00006000); // VT_LPWSTR +DEFINE_PROPERTYKEY(PKEY_SSDP_DevLifeTime, 0x656A3BB3, 0xECC0, 0x43FD, 0x84, 0x77, 0x4A, 0xE0, 0x40, 0x4A, 0x96, 0xCD, 0x00006001); // VT_UI4 +DEFINE_PROPERTYKEY(PKEY_SSDP_NetworkInterface, 0x656A3BB3, 0xECC0, 0x43FD, 0x84, 0x77, 0x4A, 0xE0, 0x40, 0x4A, 0x96, 0xCD, 0x00006002); // VT_BOOL + +// FMTID_PNPXDynamicProperty = {4FC5077E-B686-44BE-93E3-86CAFE368CCD} +DEFINE_GUID(FMTID_PNPXDynamicProperty, 0x4FC5077E, 0xB686, 0x44BE, 0x93, 0xE3, 0x86, 0xCA, 0xFE, 0x36, 0x8C, 0xCD); + +DEFINE_PROPERTYKEY(PKEY_PNPX_Installable, 0x4FC5077E, 0xB686, 0x44BE, 0x93, 0xE3, 0x86, 0xCA, 0xFE, 0x36, 0x8C, 0xCD, 0x00000001); // VT_BOOL +DEFINE_PROPERTYKEY(PKEY_PNPX_Associated, 0x4FC5077E, 0xB686, 0x44BE, 0x93, 0xE3, 0x86, 0xCA, 0xFE, 0x36, 0x8C, 0xCD, 0x00000002); // VT_BOOL +// PKEY_PNPX_Installed to be deprecated in Longhorn Server timeframe +// this PKEY really represents Associated state +#define PKEY_PNPX_Installed PKEY_PNPX_Associated // Deprecated! Please use PKEY_PNPX_Associated +DEFINE_PROPERTYKEY(PKEY_PNPX_CompatibleTypes, 0x4FC5077E, 0xB686, 0x44BE, 0x93, 0xE3, 0x86, 0xCA, 0xFE, 0x36, 0x8C, 0xCD, 0x00000003); // VT_LPWSTR | VT_VECTOR + + // WNET Provider properties +DEFINE_PROPERTYKEY(PKEY_WNET_Scope, 0xdebda43a, 0x37b3, 0x4383, 0x91, 0xE7, 0x44, 0x98, 0xda, 0x29, 0x95, 0xab, 0x00000001); // VT_UINT +DEFINE_PROPERTYKEY(PKEY_WNET_Type, 0xdebda43a, 0x37b3, 0x4383, 0x91, 0xE7, 0x44, 0x98, 0xda, 0x29, 0x95, 0xab, 0x00000002); // VT_UINT +DEFINE_PROPERTYKEY(PKEY_WNET_DisplayType, 0xdebda43a, 0x37b3, 0x4383, 0x91, 0xE7, 0x44, 0x98, 0xda, 0x29, 0x95, 0xab, 0x00000003); // VT_UINT +DEFINE_PROPERTYKEY(PKEY_WNET_Usage, 0xdebda43a, 0x37b3, 0x4383, 0x91, 0xE7, 0x44, 0x98, 0xda, 0x29, 0x95, 0xab, 0x00000004); // VT_UINT +DEFINE_PROPERTYKEY(PKEY_WNET_LocalName, 0xdebda43a, 0x37b3, 0x4383, 0x91, 0xE7, 0x44, 0x98, 0xda, 0x29, 0x95, 0xab, 0x00000005); // VT_LPWSTR +DEFINE_PROPERTYKEY(PKEY_WNET_RemoteName, 0xdebda43a, 0x37b3, 0x4383, 0x91, 0xE7, 0x44, 0x98, 0xda, 0x29, 0x95, 0xab, 0x00000006); // VT_LPWSTR +DEFINE_PROPERTYKEY(PKEY_WNET_Comment, 0xdebda43a, 0x37b3, 0x4383, 0x91, 0xE7, 0x44, 0x98, 0xda, 0x29, 0x95, 0xab, 0x00000007); // VT_LPWSTR +DEFINE_PROPERTYKEY(PKEY_WNET_Provider, 0xdebda43a, 0x37b3, 0x4383, 0x91, 0xE7, 0x44, 0x98, 0xda, 0x29, 0x95, 0xab, 0x00000008); // VT_LPWSTR + + + // WCN Provider properties + +DEFINE_PROPERTYKEY(PKEY_WCN_Version, 0x88190b80, 0x4684, 0x11da, 0xa2, 0x6a, 0x00, 0x02, 0xb3, 0x98, 0x8e, 0x81, 0x00000001); // VT_UI1 +DEFINE_PROPERTYKEY(PKEY_WCN_RequestType, 0x88190b81, 0x4684, 0x11da, 0xa2, 0x6a, 0x00, 0x02, 0xb3, 0x98, 0x8e, 0x81, 0x00000002); // VT_INT +DEFINE_PROPERTYKEY(PKEY_WCN_AuthType, 0x88190b82, 0x4684, 0x11da, 0xa2, 0x6a, 0x00, 0x02, 0xb3, 0x98, 0x8e, 0x81, 0x00000003); // VT_INT +DEFINE_PROPERTYKEY(PKEY_WCN_EncryptType, 0x88190b83, 0x4684, 0x11da, 0xa2, 0x6a, 0x00, 0x02, 0xb3, 0x98, 0x8e, 0x81, 0x00000004); // VT_INT +DEFINE_PROPERTYKEY(PKEY_WCN_ConnType, 0x88190b84, 0x4684, 0x11da, 0xa2, 0x6a, 0x00, 0x02, 0xb3, 0x98, 0x8e, 0x81, 0x00000005); // VT_INT +DEFINE_PROPERTYKEY(PKEY_WCN_ConfigMethods, 0x88190b85, 0x4684, 0x11da, 0xa2, 0x6a, 0x00, 0x02, 0xb3, 0x98, 0x8e, 0x81, 0x00000006); // VT_INT +// map WCN DeviceType to PKEY_PNPX_DeviceCategory +//DEFINE_PROPERTYKEY(PKEY_WCN_DeviceType, 0x88190b86, 0x4684, 0x11da, 0xa2, 0x6a, 0x00, 0x02, 0xb3, 0x98, 0x8e, 0x81, 0x00000007); // VT_INT +DEFINE_PROPERTYKEY(PKEY_WCN_RfBand, 0x88190b87, 0x4684, 0x11da, 0xa2, 0x6a, 0x00, 0x02, 0xb3, 0x98, 0x8e, 0x81, 0x00000008); // VT_INT +DEFINE_PROPERTYKEY(PKEY_WCN_AssocState, 0x88190b88, 0x4684, 0x11da, 0xa2, 0x6a, 0x00, 0x02, 0xb3, 0x98, 0x8e, 0x81, 0x00000009); // VT_INT +DEFINE_PROPERTYKEY(PKEY_WCN_ConfigError, 0x88190b89, 0x4684, 0x11da, 0xa2, 0x6a, 0x00, 0x02, 0xb3, 0x98, 0x8e, 0x81, 0x0000000a); // VT_INT +DEFINE_PROPERTYKEY(PKEY_WCN_ConfigState, 0x88190b89, 0x4684, 0x11da, 0xa2, 0x6a, 0x00, 0x02, 0xb3, 0x98, 0x8e, 0x81, 0x0000000b); // VT_UI1 +DEFINE_PROPERTYKEY(PKEY_WCN_DevicePasswordId, 0x88190b89, 0x4684, 0x11da, 0xa2, 0x6a, 0x00, 0x02, 0xb3, 0x98, 0x8e, 0x81, 0x0000000c); // VT_INT +DEFINE_PROPERTYKEY(PKEY_WCN_OSVersion, 0x88190b89, 0x4684, 0x11da, 0xa2, 0x6a, 0x00, 0x02, 0xb3, 0x98, 0x8e, 0x81, 0x0000000d); // VT_UINT +DEFINE_PROPERTYKEY(PKEY_WCN_VendorExtension, 0x88190b8a, 0x4684, 0x11da, 0xa2, 0x6a, 0x00, 0x02, 0xb3, 0x98, 0x8e, 0x81, 0x0000000e); // VT_UI1 | VT_VECTOR +DEFINE_PROPERTYKEY(PKEY_WCN_RegistrarType, 0x88190b8b, 0x4684, 0x11da, 0xa2, 0x6a, 0x00, 0x02, 0xb3, 0x98, 0x8e, 0x81, 0x0000000f); // VT_INT + +//----------------------------------------------------------------------------- +// DriverPackage properties + +#define PKEY_DriverPackage_Model PKEY_DrvPkg_Model +#define PKEY_DriverPackage_VendorWebSite PKEY_DrvPkg_VendorWebSite +#define PKEY_DriverPackage_DetailedDescription PKEY_DrvPkg_DetailedDescription +#define PKEY_DriverPackage_DocumentationLink PKEY_DrvPkg_DocumentationLink +#define PKEY_DriverPackage_Icon PKEY_DrvPkg_Icon +#define PKEY_DriverPackage_BrandingIcon PKEY_DrvPkg_BrandingIcon + +//----------------------------------------------------------------------------- +// Hardware properties + +DEFINE_PROPERTYKEY(PKEY_Hardware_Devinst, 0x5EAF3EF2, 0xE0CA, 0x4598, 0xBF, 0x06, 0x71, 0xED, 0x1D, 0x9D, 0xD9, 0x53, 4097); + +// Name: System.Hardware.DisplayAttribute -- PKEY_Hardware_DisplayAttribute +// Type: Unspecified -- VT_NULL +// FormatID: 5EAF3EF2-E0CA-4598-BF06-71ED1D9DD953, 5 +DEFINE_PROPERTYKEY(PKEY_Hardware_DisplayAttribute, 0x5EAF3EF2, 0xE0CA, 0x4598, 0xBF, 0x06, 0x71, 0xED, 0x1D, 0x9D, 0xD9, 0x53, 5); + +// Name: System.Hardware.DriverDate -- PKEY_Hardware_DriverDate +// Type: Unspecified -- VT_NULL +// FormatID: 5EAF3EF2-E0CA-4598-BF06-71ED1D9DD953, 11 +DEFINE_PROPERTYKEY(PKEY_Hardware_DriverDate, 0x5EAF3EF2, 0xE0CA, 0x4598, 0xBF, 0x06, 0x71, 0xED, 0x1D, 0x9D, 0xD9, 0x53, 11); + +// Name: System.Hardware.DriverProvider -- PKEY_Hardware_DriverProvider +// Type: Unspecified -- VT_NULL +// FormatID: 5EAF3EF2-E0CA-4598-BF06-71ED1D9DD953, 10 +DEFINE_PROPERTYKEY(PKEY_Hardware_DriverProvider, 0x5EAF3EF2, 0xE0CA, 0x4598, 0xBF, 0x06, 0x71, 0xED, 0x1D, 0x9D, 0xD9, 0x53, 10); + +// Name: System.Hardware.DriverVersion -- PKEY_Hardware_DriverVersion +// Type: Unspecified -- VT_NULL +// FormatID: 5EAF3EF2-E0CA-4598-BF06-71ED1D9DD953, 9 +DEFINE_PROPERTYKEY(PKEY_Hardware_DriverVersion, 0x5EAF3EF2, 0xE0CA, 0x4598, 0xBF, 0x06, 0x71, 0xED, 0x1D, 0x9D, 0xD9, 0x53, 9); + +// Name: System.Hardware.Function -- PKEY_Hardware_Function +// Type: Unspecified -- VT_NULL +// FormatID: 5EAF3EF2-E0CA-4598-BF06-71ED1D9DD953, 4099 +DEFINE_PROPERTYKEY(PKEY_Hardware_Function, 0x5EAF3EF2, 0xE0CA, 0x4598, 0xBF, 0x06, 0x71, 0xED, 0x1D, 0x9D, 0xD9, 0x53, 4099); + +// Name: System.Hardware.Icon -- PKEY_Hardware_Icon +// Type: Unspecified -- VT_NULL +// FormatID: 5EAF3EF2-E0CA-4598-BF06-71ED1D9DD953, 3 +DEFINE_PROPERTYKEY(PKEY_Hardware_Icon, 0x5EAF3EF2, 0xE0CA, 0x4598, 0xBF, 0x06, 0x71, 0xED, 0x1D, 0x9D, 0xD9, 0x53, 3); + +// Name: System.Hardware.Image -- PKEY_Hardware_Image +// Type: Unspecified -- VT_NULL +// FormatID: 5EAF3EF2-E0CA-4598-BF06-71ED1D9DD953, 4098 +DEFINE_PROPERTYKEY(PKEY_Hardware_Image, 0x5EAF3EF2, 0xE0CA, 0x4598, 0xBF, 0x06, 0x71, 0xED, 0x1D, 0x9D, 0xD9, 0x53, 4098); + +// Name: System.Hardware.Manufacturer -- PKEY_Hardware_Manufacturer +// Type: Unspecified -- VT_NULL +// FormatID: 5EAF3EF2-E0CA-4598-BF06-71ED1D9DD953, 6 +DEFINE_PROPERTYKEY(PKEY_Hardware_Manufacturer, 0x5EAF3EF2, 0xE0CA, 0x4598, 0xBF, 0x06, 0x71, 0xED, 0x1D, 0x9D, 0xD9, 0x53, 6); + +// Name: System.Hardware.Model -- PKEY_Hardware_Model +// Type: Unspecified -- VT_NULL +// FormatID: 5EAF3EF2-E0CA-4598-BF06-71ED1D9DD953, 7 +DEFINE_PROPERTYKEY(PKEY_Hardware_Model, 0x5EAF3EF2, 0xE0CA, 0x4598, 0xBF, 0x06, 0x71, 0xED, 0x1D, 0x9D, 0xD9, 0x53, 7); + +// Name: System.Hardware.Name -- PKEY_Hardware_Name +// Type: String -- VT_LPWSTR (For variants: VT_BSTR) +// FormatID: 5EAF3EF2-E0CA-4598-BF06-71ED1D9DD953, 2 +DEFINE_PROPERTYKEY(PKEY_Hardware_Name, 0x5EAF3EF2, 0xE0CA, 0x4598, 0xBF, 0x06, 0x71, 0xED, 0x1D, 0x9D, 0xD9, 0x53, 2); + +// Name: System.Hardware.SerialNumber -- PKEY_Hardware_SerialNumber +// Type: Unspecified -- VT_NULL +// FormatID: 5EAF3EF2-E0CA-4598-BF06-71ED1D9DD953, 8 +DEFINE_PROPERTYKEY(PKEY_Hardware_SerialNumber, 0x5EAF3EF2, 0xE0CA, 0x4598, 0xBF, 0x06, 0x71, 0xED, 0x1D, 0x9D, 0xD9, 0x53, 8); + +// Name: System.Hardware.ShellAttributes -- PKEY_Hardware_ShellAttributes +// Type: Unspecified -- VT_NULL +// FormatID: 5EAF3EF2-E0CA-4598-BF06-71ED1D9DD953, 4100 +DEFINE_PROPERTYKEY(PKEY_Hardware_ShellAttributes, 0x5EAF3EF2, 0xE0CA, 0x4598, 0xBF, 0x06, 0x71, 0xED, 0x1D, 0x9D, 0xD9, 0x53, 4100); + +// Name: System.Hardware.Status -- PKEY_Hardware_Status +// Type: Unspecified -- VT_NULL +// FormatID: 5EAF3EF2-E0CA-4598-BF06-71ED1D9DD953, 4096 +DEFINE_PROPERTYKEY(PKEY_Hardware_Status, 0x5EAF3EF2, 0xE0CA, 0x4598, 0xBF, 0x06, 0x71, 0xED, 0x1D, 0x9D, 0xD9, 0x53, 4096); + + diff --git a/extern/portaudio/src/hostapi/wasapi/mingw-include/ks.h b/extern/portaudio/src/hostapi/wasapi/mingw-include/ks.h new file mode 100644 index 0000000..2261e6c --- /dev/null +++ b/extern/portaudio/src/hostapi/wasapi/mingw-include/ks.h @@ -0,0 +1,3666 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER.PD within this package. + */ +#ifndef _KS_ +#define _KS_ + +#if __GNUC__ >= 3 +#pragma GCC system_header +#endif + +#ifndef __MINGW_EXTENSION +#if defined(__GNUC__) || defined(__GNUG__) +#define __MINGW_EXTENSION __extension__ +#else +#define __MINGW_EXTENSION +#endif +#endif + +#ifdef __TCS__ +#define _KS_NO_ANONYMOUS_STRUCTURES_ 1 +#endif + +#ifdef _KS_NO_ANONYMOUS_STRUCTURES_ +#define _KS_ANON_STRUCT(X) struct X +#else +#define _KS_ANON_STRUCT(X) __MINGW_EXTENSION struct +#endif + +#ifndef _NTRTL_ +#ifndef DEFINE_GUIDEX +#define DEFINE_GUIDEX(name) EXTERN_C const CDECL GUID name +#endif +#ifndef STATICGUIDOF +#define STATICGUIDOF(guid) STATIC_##guid +#endif +#endif /* _NTRTL_ */ + +#ifndef SIZEOF_ARRAY +#define SIZEOF_ARRAY(ar) (sizeof(ar)/sizeof((ar)[0])) +#endif + +#define DEFINE_GUIDSTRUCT(g,n) DEFINE_GUIDEX(n) +#define DEFINE_GUIDNAMED(n) n + +#define STATIC_GUID_NULL \ + 0x00000000L,0x0000,0x0000,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 + +DEFINE_GUIDSTRUCT("00000000-0000-0000-0000-000000000000",GUID_NULL); +#define GUID_NULL DEFINE_GUIDNAMED(GUID_NULL) + +#define IOCTL_KS_PROPERTY CTL_CODE(FILE_DEVICE_KS,0x000,METHOD_NEITHER,FILE_ANY_ACCESS) +#define IOCTL_KS_ENABLE_EVENT CTL_CODE(FILE_DEVICE_KS,0x001,METHOD_NEITHER,FILE_ANY_ACCESS) +#define IOCTL_KS_DISABLE_EVENT CTL_CODE(FILE_DEVICE_KS,0x002,METHOD_NEITHER,FILE_ANY_ACCESS) +#define IOCTL_KS_METHOD CTL_CODE(FILE_DEVICE_KS,0x003,METHOD_NEITHER,FILE_ANY_ACCESS) +#define IOCTL_KS_WRITE_STREAM CTL_CODE(FILE_DEVICE_KS,0x004,METHOD_NEITHER,FILE_WRITE_ACCESS) +#define IOCTL_KS_READ_STREAM CTL_CODE(FILE_DEVICE_KS,0x005,METHOD_NEITHER,FILE_READ_ACCESS) +#define IOCTL_KS_RESET_STATE CTL_CODE(FILE_DEVICE_KS,0x006,METHOD_NEITHER,FILE_ANY_ACCESS) + +typedef enum { + KSRESET_BEGIN, + KSRESET_END +} KSRESET; + +typedef enum { + KSSTATE_STOP, + KSSTATE_ACQUIRE, + KSSTATE_PAUSE, + KSSTATE_RUN +} KSSTATE,*PKSSTATE; + +#define KSPRIORITY_LOW 0x00000001 +#define KSPRIORITY_NORMAL 0x40000000 +#define KSPRIORITY_HIGH 0x80000000 +#define KSPRIORITY_EXCLUSIVE 0xFFFFFFFF + +typedef struct { + ULONG PriorityClass; + ULONG PrioritySubClass; +} KSPRIORITY,*PKSPRIORITY; + +typedef struct { + __MINGW_EXTENSION union { + _KS_ANON_STRUCT(_IDENTIFIER) + { + GUID Set; + ULONG Id; + ULONG Flags; + }; + LONGLONG Alignment; + }; +} KSIDENTIFIER,*PKSIDENTIFIER; + +typedef KSIDENTIFIER KSPROPERTY,*PKSPROPERTY,KSMETHOD,*PKSMETHOD,KSEVENT,*PKSEVENT; + +#define KSMETHOD_TYPE_NONE 0x00000000 +#define KSMETHOD_TYPE_READ 0x00000001 +#define KSMETHOD_TYPE_WRITE 0x00000002 +#define KSMETHOD_TYPE_MODIFY 0x00000003 +#define KSMETHOD_TYPE_SOURCE 0x00000004 + +#define KSMETHOD_TYPE_SEND 0x00000001 +#define KSMETHOD_TYPE_SETSUPPORT 0x00000100 +#define KSMETHOD_TYPE_BASICSUPPORT 0x00000200 + +#define KSMETHOD_TYPE_TOPOLOGY 0x10000000 + +#define KSPROPERTY_TYPE_GET 0x00000001 +#define KSPROPERTY_TYPE_SET 0x00000002 +#define KSPROPERTY_TYPE_SETSUPPORT 0x00000100 +#define KSPROPERTY_TYPE_BASICSUPPORT 0x00000200 +#define KSPROPERTY_TYPE_RELATIONS 0x00000400 +#define KSPROPERTY_TYPE_SERIALIZESET 0x00000800 +#define KSPROPERTY_TYPE_UNSERIALIZESET 0x00001000 +#define KSPROPERTY_TYPE_SERIALIZERAW 0x00002000 +#define KSPROPERTY_TYPE_UNSERIALIZERAW 0x00004000 +#define KSPROPERTY_TYPE_SERIALIZESIZE 0x00008000 +#define KSPROPERTY_TYPE_DEFAULTVALUES 0x00010000 + +#define KSPROPERTY_TYPE_TOPOLOGY 0x10000000 + +typedef struct { + KSPROPERTY Property; + ULONG NodeId; + ULONG Reserved; +} KSP_NODE,*PKSP_NODE; + +typedef struct { + KSMETHOD Method; + ULONG NodeId; + ULONG Reserved; +} KSM_NODE,*PKSM_NODE; + +typedef struct { + KSEVENT Event; + ULONG NodeId; + ULONG Reserved; +} KSE_NODE,*PKSE_NODE; + +#define STATIC_KSPROPTYPESETID_General \ + 0x97E99BA0L,0xBDEA,0x11CF,0xA5,0xD6,0x28,0xDB,0x04,0xC1,0x00,0x00 +DEFINE_GUIDSTRUCT("97E99BA0-BDEA-11CF-A5D6-28DB04C10000",KSPROPTYPESETID_General); +#define KSPROPTYPESETID_General DEFINE_GUIDNAMED(KSPROPTYPESETID_General) + +typedef struct { + ULONG Size; + ULONG Count; +} KSMULTIPLE_ITEM,*PKSMULTIPLE_ITEM; + +typedef struct { + ULONG AccessFlags; + ULONG DescriptionSize; + KSIDENTIFIER PropTypeSet; + ULONG MembersListCount; + ULONG Reserved; +} KSPROPERTY_DESCRIPTION,*PKSPROPERTY_DESCRIPTION; + +#define KSPROPERTY_MEMBER_RANGES 0x00000001 +#define KSPROPERTY_MEMBER_STEPPEDRANGES 0x00000002 +#define KSPROPERTY_MEMBER_VALUES 0x00000003 + +#define KSPROPERTY_MEMBER_FLAG_DEFAULT 0x00000001 +#define KSPROPERTY_MEMBER_FLAG_BASICSUPPORT_MULTICHANNEL 0x00000002 +#define KSPROPERTY_MEMBER_FLAG_BASICSUPPORT_UNIFORM 0x00000004 + +typedef struct { + ULONG MembersFlags; + ULONG MembersSize; + ULONG MembersCount; + ULONG Flags; +} KSPROPERTY_MEMBERSHEADER,*PKSPROPERTY_MEMBERSHEADER; + +typedef union { + _KS_ANON_STRUCT(_SIGNED) + { + LONG SignedMinimum; + LONG SignedMaximum; + }; + _KS_ANON_STRUCT(_UNSIGNED) + { + ULONG UnsignedMinimum; + ULONG UnsignedMaximum; + }; +} KSPROPERTY_BOUNDS_LONG,*PKSPROPERTY_BOUNDS_LONG; + +typedef union { + _KS_ANON_STRUCT(_SIGNED64) + { + LONGLONG SignedMinimum; + LONGLONG SignedMaximum; + }; + _KS_ANON_STRUCT(_UNSIGNED64) + { + DWORDLONG UnsignedMinimum; + DWORDLONG UnsignedMaximum; + }; +} KSPROPERTY_BOUNDS_LONGLONG,*PKSPROPERTY_BOUNDS_LONGLONG; + +typedef struct { + ULONG SteppingDelta; + ULONG Reserved; + KSPROPERTY_BOUNDS_LONG Bounds; +} KSPROPERTY_STEPPING_LONG,*PKSPROPERTY_STEPPING_LONG; + +typedef struct { + DWORDLONG SteppingDelta; + KSPROPERTY_BOUNDS_LONGLONG Bounds; +} KSPROPERTY_STEPPING_LONGLONG,*PKSPROPERTY_STEPPING_LONGLONG; + +#if defined(_NTDDK_) +typedef struct _KSDEVICE_DESCRIPTOR KSDEVICE_DESCRIPTOR, *PKSDEVICE_DESCRIPTOR; +typedef struct _KSDEVICE_DISPATCH KSDEVICE_DISPATCH, *PKSDEVICE_DISPATCH; +typedef struct _KSDEVICE KSDEVICE, *PKSDEVICE; +typedef struct _KSFILTERFACTORY KSFILTERFACTORY, *PKSFILTERFACTORY; +typedef struct _KSFILTER_DESCRIPTOR KSFILTER_DESCRIPTOR, *PKSFILTER_DESCRIPTOR; +typedef struct _KSFILTER_DISPATCH KSFILTER_DISPATCH, *PKSFILTER_DISPATCH; +typedef struct _KSFILTER KSFILTER, *PKSFILTER; +typedef struct _KSPIN_DESCRIPTOR_EX KSPIN_DESCRIPTOR_EX, *PKSPIN_DESCRIPTOR_EX; +typedef struct _KSPIN_DISPATCH KSPIN_DISPATCH, *PKSPIN_DISPATCH; +typedef struct _KSCLOCK_DISPATCH KSCLOCK_DISPATCH, *PKSCLOCK_DISPATCH; +typedef struct _KSALLOCATOR_DISPATCH KSALLOCATOR_DISPATCH, *PKSALLOCATOR_DISPATCH; +typedef struct _KSPIN KSPIN, *PKSPIN; +typedef struct _KSNODE_DESCRIPTOR KSNODE_DESCRIPTOR, *PKSNODE_DESCRIPTOR; +typedef struct _KSSTREAM_POINTER_OFFSET KSSTREAM_POINTER_OFFSET, *PKSSTREAM_POINTER_OFFSET; +typedef struct _KSSTREAM_POINTER KSSTREAM_POINTER, *PKSSTREAM_POINTER; +typedef struct _KSMAPPING KSMAPPING, *PKSMAPPING; +typedef struct _KSPROCESSPIN KSPROCESSPIN, *PKSPROCESSPIN; +typedef struct _KSPROCESSPIN_INDEXENTRY KSPROCESSPIN_INDEXENTRY, *PKSPROCESSPIN_INDEXENTRY; +#endif /* _NTDDK_ */ + +typedef PVOID PKSWORKER; + + +typedef struct { + ULONG NotificationType; + __MINGW_EXTENSION union { + struct { + HANDLE Event; + ULONG_PTR Reserved[2]; + } EventHandle; + struct { + HANDLE Semaphore; + ULONG Reserved; + LONG Adjustment; + } SemaphoreHandle; +#if defined(_NTDDK_) + struct { + PVOID Event; + KPRIORITY Increment; + ULONG_PTR Reserved; + } EventObject; + struct { + PVOID Semaphore; + KPRIORITY Increment; + LONG Adjustment; + } SemaphoreObject; + struct { + PKDPC Dpc; + ULONG ReferenceCount; + ULONG_PTR Reserved; + } Dpc; + struct { + PWORK_QUEUE_ITEM WorkQueueItem; + WORK_QUEUE_TYPE WorkQueueType; + ULONG_PTR Reserved; + } WorkItem; + struct { + PWORK_QUEUE_ITEM WorkQueueItem; + PKSWORKER KsWorkerObject; + ULONG_PTR Reserved; + } KsWorkItem; +#endif /* _NTDDK_ */ + struct { + PVOID Unused; + LONG_PTR Alignment[2]; + } Alignment; + }; +} KSEVENTDATA,*PKSEVENTDATA; + +#define KSEVENTF_EVENT_HANDLE 0x00000001 +#define KSEVENTF_SEMAPHORE_HANDLE 0x00000002 +#if defined(_NTDDK_) +#define KSEVENTF_EVENT_OBJECT 0x00000004 +#define KSEVENTF_SEMAPHORE_OBJECT 0x00000008 +#define KSEVENTF_DPC 0x00000010 +#define KSEVENTF_WORKITEM 0x00000020 +#define KSEVENTF_KSWORKITEM 0x00000080 +#endif /* _NTDDK_ */ + +#define KSEVENT_TYPE_ENABLE 0x00000001 +#define KSEVENT_TYPE_ONESHOT 0x00000002 +#define KSEVENT_TYPE_ENABLEBUFFERED 0x00000004 +#define KSEVENT_TYPE_SETSUPPORT 0x00000100 +#define KSEVENT_TYPE_BASICSUPPORT 0x00000200 +#define KSEVENT_TYPE_QUERYBUFFER 0x00000400 + +#define KSEVENT_TYPE_TOPOLOGY 0x10000000 + +typedef struct { + KSEVENT Event; + PKSEVENTDATA EventData; + PVOID Reserved; +} KSQUERYBUFFER,*PKSQUERYBUFFER; + +typedef struct { + ULONG Size; + ULONG Flags; + __MINGW_EXTENSION union { + HANDLE ObjectHandle; + PVOID ObjectPointer; + }; + PVOID Reserved; + KSEVENT Event; + KSEVENTDATA EventData; +} KSRELATIVEEVENT; + +#define KSRELATIVEEVENT_FLAG_HANDLE 0x00000001 +#define KSRELATIVEEVENT_FLAG_POINTER 0x00000002 + +typedef struct { + KSEVENTDATA EventData; + LONGLONG MarkTime; +} KSEVENT_TIME_MARK,*PKSEVENT_TIME_MARK; + +typedef struct { + KSEVENTDATA EventData; + LONGLONG TimeBase; + LONGLONG Interval; +} KSEVENT_TIME_INTERVAL,*PKSEVENT_TIME_INTERVAL; + +typedef struct { + LONGLONG TimeBase; + LONGLONG Interval; +} KSINTERVAL,*PKSINTERVAL; + +#define STATIC_KSPROPSETID_General \ + 0x1464EDA5L,0x6A8F,0x11D1,0x9A,0xA7,0x00,0xA0,0xC9,0x22,0x31,0x96 +DEFINE_GUIDSTRUCT("1464EDA5-6A8F-11D1-9AA7-00A0C9223196",KSPROPSETID_General); +#define KSPROPSETID_General DEFINE_GUIDNAMED(KSPROPSETID_General) + +typedef enum { + KSPROPERTY_GENERAL_COMPONENTID +} KSPROPERTY_GENERAL; + +typedef struct { + GUID Manufacturer; + GUID Product; + GUID Component; + GUID Name; + ULONG Version; + ULONG Revision; +} KSCOMPONENTID,*PKSCOMPONENTID; + +#define DEFINE_KSPROPERTY_ITEM_GENERAL_COMPONENTID(Handler) \ + DEFINE_KSPROPERTY_ITEM( \ + KSPROPERTY_GENERAL_COMPONENTID, \ + (Handler), \ + sizeof(KSPROPERTY), \ + sizeof(KSCOMPONENTID), \ + NULL, NULL, 0, NULL, NULL, 0) + +#define STATIC_KSMETHODSETID_StreamIo \ + 0x65D003CAL,0x1523,0x11D2,0xB2,0x7A,0x00,0xA0,0xC9,0x22,0x31,0x96 +DEFINE_GUIDSTRUCT("65D003CA-1523-11D2-B27A-00A0C9223196",KSMETHODSETID_StreamIo); +#define KSMETHODSETID_StreamIo DEFINE_GUIDNAMED(KSMETHODSETID_StreamIo) + +typedef enum { + KSMETHOD_STREAMIO_READ, + KSMETHOD_STREAMIO_WRITE +} KSMETHOD_STREAMIO; + +#define DEFINE_KSMETHOD_ITEM_STREAMIO_READ(Handler) \ + DEFINE_KSMETHOD_ITEM( \ + KSMETHOD_STREAMIO_READ, \ + KSMETHOD_TYPE_WRITE, \ + (Handler), \ + sizeof(KSMETHOD), \ + 0, \ + NULL) + +#define DEFINE_KSMETHOD_ITEM_STREAMIO_WRITE(Handler) \ + DEFINE_KSMETHOD_ITEM( \ + KSMETHOD_STREAMIO_WRITE, \ + KSMETHOD_TYPE_READ, \ + (Handler), \ + sizeof(KSMETHOD), \ + 0, \ + NULL) + +#define STATIC_KSPROPSETID_MediaSeeking \ + 0xEE904F0CL,0xD09B,0x11D0,0xAB,0xE9,0x00,0xA0,0xC9,0x22,0x31,0x96 +DEFINE_GUIDSTRUCT("EE904F0C-D09B-11D0-ABE9-00A0C9223196",KSPROPSETID_MediaSeeking); +#define KSPROPSETID_MediaSeeking DEFINE_GUIDNAMED(KSPROPSETID_MediaSeeking) + +typedef enum { + KSPROPERTY_MEDIASEEKING_CAPABILITIES, + KSPROPERTY_MEDIASEEKING_FORMATS, + KSPROPERTY_MEDIASEEKING_TIMEFORMAT, + KSPROPERTY_MEDIASEEKING_POSITION, + KSPROPERTY_MEDIASEEKING_STOPPOSITION, + KSPROPERTY_MEDIASEEKING_POSITIONS, + KSPROPERTY_MEDIASEEKING_DURATION, + KSPROPERTY_MEDIASEEKING_AVAILABLE, + KSPROPERTY_MEDIASEEKING_PREROLL, + KSPROPERTY_MEDIASEEKING_CONVERTTIMEFORMAT +} KSPROPERTY_MEDIASEEKING; + +typedef enum { + KS_SEEKING_NoPositioning, + KS_SEEKING_AbsolutePositioning, + KS_SEEKING_RelativePositioning, + KS_SEEKING_IncrementalPositioning, + KS_SEEKING_PositioningBitsMask = 0x3, + KS_SEEKING_SeekToKeyFrame, + KS_SEEKING_ReturnTime = 0x8 +} KS_SEEKING_FLAGS; + +typedef enum { + KS_SEEKING_CanSeekAbsolute = 0x1, + KS_SEEKING_CanSeekForwards = 0x2, + KS_SEEKING_CanSeekBackwards = 0x4, + KS_SEEKING_CanGetCurrentPos = 0x8, + KS_SEEKING_CanGetStopPos = 0x10, + KS_SEEKING_CanGetDuration = 0x20, + KS_SEEKING_CanPlayBackwards = 0x40 +} KS_SEEKING_CAPABILITIES; + +typedef struct { + LONGLONG Current; + LONGLONG Stop; + KS_SEEKING_FLAGS CurrentFlags; + KS_SEEKING_FLAGS StopFlags; +} KSPROPERTY_POSITIONS,*PKSPROPERTY_POSITIONS; + +typedef struct { + LONGLONG Earliest; + LONGLONG Latest; +} KSPROPERTY_MEDIAAVAILABLE,*PKSPROPERTY_MEDIAAVAILABLE; + +typedef struct { + KSPROPERTY Property; + GUID SourceFormat; + GUID TargetFormat; + LONGLONG Time; +} KSP_TIMEFORMAT,*PKSP_TIMEFORMAT; + +#define DEFINE_KSPROPERTY_ITEM_MEDIASEEKING_CAPABILITIES(Handler) \ + DEFINE_KSPROPERTY_ITEM( \ + KSPROPERTY_MEDIASEEKING_CAPABILITIES, \ + (Handler), \ + sizeof(KSPROPERTY), \ + sizeof(KS_SEEKING_CAPABILITIES), \ + NULL, NULL, 0, NULL, NULL, 0) + +#define DEFINE_KSPROPERTY_ITEM_MEDIASEEKING_FORMATS(Handler) \ + DEFINE_KSPROPERTY_ITEM( \ + KSPROPERTY_MEDIASEEKING_FORMATS, \ + (Handler), \ + sizeof(KSPROPERTY), \ + 0, \ + NULL, NULL, 0, NULL, NULL, 0) + +#define DEFINE_KSPROPERTY_ITEM_MEDIASEEKING_TIMEFORMAT(GetHandler,SetHandler) \ + DEFINE_KSPROPERTY_ITEM( \ + KSPROPERTY_MEDIASEEKING_TIMEFORMAT, \ + (GetHandler), \ + sizeof(KSPROPERTY), \ + sizeof(GUID), \ + (SetHandler), \ + NULL, 0, NULL, NULL, 0) + +#define DEFINE_KSPROPERTY_ITEM_MEDIASEEKING_POSITION(Handler) \ + DEFINE_KSPROPERTY_ITEM( \ + KSPROPERTY_MEDIASEEKING_POSITION, \ + (Handler), \ + sizeof(KSPROPERTY), \ + sizeof(LONGLONG), \ + NULL, NULL, 0, NULL, NULL, 0) + +#define DEFINE_KSPROPERTY_ITEM_MEDIASEEKING_STOPPOSITION(Handler) \ + DEFINE_KSPROPERTY_ITEM( \ + KSPROPERTY_MEDIASEEKING_STOPPOSITION, \ + (Handler), \ + sizeof(KSPROPERTY), \ + sizeof(LONGLONG), \ + NULL, NULL, 0, NULL, NULL, 0) + +#define DEFINE_KSPROPERTY_ITEM_MEDIASEEKING_POSITIONS(Handler) \ + DEFINE_KSPROPERTY_ITEM( \ + KSPROPERTY_MEDIASEEKING_POSITIONS, \ + NULL, \ + sizeof(KSPROPERTY), \ + sizeof(KSPROPERTY_POSITIONS), \ + (Handler), \ + NULL, 0, NULL, NULL, 0) + +#define DEFINE_KSPROPERTY_ITEM_MEDIASEEKING_DURATION(Handler) \ + DEFINE_KSPROPERTY_ITEM( \ + KSPROPERTY_MEDIASEEKING_DURATION, \ + (Handler), \ + sizeof(KSPROPERTY), \ + sizeof(LONGLONG), \ + NULL, NULL, 0, NULL, NULL, 0) + +#define DEFINE_KSPROPERTY_ITEM_MEDIASEEKING_AVAILABLE(Handler) \ + DEFINE_KSPROPERTY_ITEM( \ + KSPROPERTY_MEDIASEEKING_AVAILABLE, \ + (Handler), \ + sizeof(KSPROPERTY), \ + sizeof(KSPROPERTY_MEDIAAVAILABLE), \ + NULL, NULL, 0, NULL, NULL, 0) + +#define DEFINE_KSPROPERTY_ITEM_MEDIASEEKING_PREROLL(Handler) \ + DEFINE_KSPROPERTY_ITEM( \ + KSPROPERTY_MEDIASEEKING_PREROLL, \ + (Handler), \ + sizeof(KSPROPERTY), \ + sizeof(LONGLONG), \ + NULL, NULL, 0, NULL, NULL, 0) + +#define DEFINE_KSPROPERTY_ITEM_MEDIASEEKING_CONVERTTIMEFORMAT(Handler) \ + DEFINE_KSPROPERTY_ITEM( \ + KSPROPERTY_MEDIASEEKING_CONVERTTIMEFORMAT, \ + (Handler), \ + sizeof(KSP_TIMEFORMAT), \ + sizeof(LONGLONG), \ + NULL, NULL, 0, NULL, NULL, 0) + +#define STATIC_KSPROPSETID_Topology \ + 0x720D4AC0L,0x7533,0x11D0,0xA5,0xD6,0x28,0xDB,0x04,0xC1,0x00,0x00 +DEFINE_GUIDSTRUCT("720D4AC0-7533-11D0-A5D6-28DB04C10000",KSPROPSETID_Topology); +#define KSPROPSETID_Topology DEFINE_GUIDNAMED(KSPROPSETID_Topology) + +typedef enum { + KSPROPERTY_TOPOLOGY_CATEGORIES, + KSPROPERTY_TOPOLOGY_NODES, + KSPROPERTY_TOPOLOGY_CONNECTIONS, + KSPROPERTY_TOPOLOGY_NAME +} KSPROPERTY_TOPOLOGY; + +#define DEFINE_KSPROPERTY_ITEM_TOPOLOGY_CATEGORIES(Handler) \ + DEFINE_KSPROPERTY_ITEM( \ + KSPROPERTY_TOPOLOGY_CATEGORIES, \ + (Handler), \ + sizeof(KSPROPERTY), \ + 0, \ + NULL, NULL, 0,NULL, NULL, 0) + +#define DEFINE_KSPROPERTY_ITEM_TOPOLOGY_NODES(Handler) \ + DEFINE_KSPROPERTY_ITEM( \ + KSPROPERTY_TOPOLOGY_NODES, \ + (Handler), \ + sizeof(KSPROPERTY), \ + 0, \ + NULL, NULL, 0, NULL, NULL, 0) + +#define DEFINE_KSPROPERTY_ITEM_TOPOLOGY_CONNECTIONS(Handler) \ + DEFINE_KSPROPERTY_ITEM( \ + KSPROPERTY_TOPOLOGY_CONNECTIONS, \ + (Handler), \ + sizeof(KSPROPERTY), \ + 0, \ + NULL, NULL, 0, NULL, NULL, 0) + +#define DEFINE_KSPROPERTY_ITEM_TOPOLOGY_NAME(Handler) \ + DEFINE_KSPROPERTY_ITEM( \ + KSPROPERTY_TOPOLOGY_NAME, \ + (Handler), \ + sizeof(KSP_NODE), \ + 0, \ + NULL, NULL, 0, NULL, NULL, 0) + +#define DEFINE_KSPROPERTY_TOPOLOGYSET(TopologySet,Handler) \ +DEFINE_KSPROPERTY_TABLE(TopologySet) { \ + DEFINE_KSPROPERTY_ITEM_TOPOLOGY_CATEGORIES(Handler), \ + DEFINE_KSPROPERTY_ITEM_TOPOLOGY_NODES(Handler), \ + DEFINE_KSPROPERTY_ITEM_TOPOLOGY_CONNECTIONS(Handler), \ + DEFINE_KSPROPERTY_ITEM_TOPOLOGY_NAME(Handler) \ +} + +#define STATIC_KSCATEGORY_BRIDGE \ + 0x085AFF00L,0x62CE,0x11CF,0xA5,0xD6,0x28,0xDB,0x04,0xC1,0x00,0x00 +DEFINE_GUIDSTRUCT("085AFF00-62CE-11CF-A5D6-28DB04C10000",KSCATEGORY_BRIDGE); +#define KSCATEGORY_BRIDGE DEFINE_GUIDNAMED(KSCATEGORY_BRIDGE) + +#define STATIC_KSCATEGORY_CAPTURE \ + 0x65E8773DL,0x8F56,0x11D0,0xA3,0xB9,0x00,0xA0,0xC9,0x22,0x31,0x96 +DEFINE_GUIDSTRUCT("65E8773D-8F56-11D0-A3B9-00A0C9223196",KSCATEGORY_CAPTURE); +#define KSCATEGORY_CAPTURE DEFINE_GUIDNAMED(KSCATEGORY_CAPTURE) + +#define STATIC_KSCATEGORY_RENDER \ + 0x65E8773EL,0x8F56,0x11D0,0xA3,0xB9,0x00,0xA0,0xC9,0x22,0x31,0x96 +DEFINE_GUIDSTRUCT("65E8773E-8F56-11D0-A3B9-00A0C9223196",KSCATEGORY_RENDER); +#define KSCATEGORY_RENDER DEFINE_GUIDNAMED(KSCATEGORY_RENDER) + +#define STATIC_KSCATEGORY_MIXER \ + 0xAD809C00L,0x7B88,0x11D0,0xA5,0xD6,0x28,0xDB,0x04,0xC1,0x00,0x00 +DEFINE_GUIDSTRUCT("AD809C00-7B88-11D0-A5D6-28DB04C10000",KSCATEGORY_MIXER); +#define KSCATEGORY_MIXER DEFINE_GUIDNAMED(KSCATEGORY_MIXER) + +#define STATIC_KSCATEGORY_SPLITTER \ + 0x0A4252A0L,0x7E70,0x11D0,0xA5,0xD6,0x28,0xDB,0x04,0xC1,0x00,0x00 +DEFINE_GUIDSTRUCT("0A4252A0-7E70-11D0-A5D6-28DB04C10000",KSCATEGORY_SPLITTER); +#define KSCATEGORY_SPLITTER DEFINE_GUIDNAMED(KSCATEGORY_SPLITTER) + +#define STATIC_KSCATEGORY_DATACOMPRESSOR \ + 0x1E84C900L,0x7E70,0x11D0,0xA5,0xD6,0x28,0xDB,0x04,0xC1,0x00,0x00 +DEFINE_GUIDSTRUCT("1E84C900-7E70-11D0-A5D6-28DB04C10000",KSCATEGORY_DATACOMPRESSOR); +#define KSCATEGORY_DATACOMPRESSOR DEFINE_GUIDNAMED(KSCATEGORY_DATACOMPRESSOR) + +#define STATIC_KSCATEGORY_DATADECOMPRESSOR \ + 0x2721AE20L,0x7E70,0x11D0,0xA5,0xD6,0x28,0xDB,0x04,0xC1,0x00,0x00 +DEFINE_GUIDSTRUCT("2721AE20-7E70-11D0-A5D6-28DB04C10000",KSCATEGORY_DATADECOMPRESSOR); +#define KSCATEGORY_DATADECOMPRESSOR DEFINE_GUIDNAMED(KSCATEGORY_DATADECOMPRESSOR) + +#define STATIC_KSCATEGORY_DATATRANSFORM \ + 0x2EB07EA0L,0x7E70,0x11D0,0xA5,0xD6,0x28,0xDB,0x04,0xC1,0x00,0x00 +DEFINE_GUIDSTRUCT("2EB07EA0-7E70-11D0-A5D6-28DB04C10000",KSCATEGORY_DATATRANSFORM); +#define KSCATEGORY_DATATRANSFORM DEFINE_GUIDNAMED(KSCATEGORY_DATATRANSFORM) + +#define STATIC_KSCATEGORY_COMMUNICATIONSTRANSFORM \ + 0xCF1DDA2CL,0x9743,0x11D0,0xA3,0xEE,0x00,0xA0,0xC9,0x22,0x31,0x96 +DEFINE_GUIDSTRUCT("CF1DDA2C-9743-11D0-A3EE-00A0C9223196",KSCATEGORY_COMMUNICATIONSTRANSFORM); +#define KSCATEGORY_COMMUNICATIONSTRANSFORM DEFINE_GUIDNAMED(KSCATEGORY_COMMUNICATIONSTRANSFORM) + +#define STATIC_KSCATEGORY_INTERFACETRANSFORM \ + 0xCF1DDA2DL,0x9743,0x11D0,0xA3,0xEE,0x00,0xA0,0xC9,0x22,0x31,0x96 +DEFINE_GUIDSTRUCT("CF1DDA2D-9743-11D0-A3EE-00A0C9223196",KSCATEGORY_INTERFACETRANSFORM); +#define KSCATEGORY_INTERFACETRANSFORM DEFINE_GUIDNAMED(KSCATEGORY_INTERFACETRANSFORM) + +#define STATIC_KSCATEGORY_MEDIUMTRANSFORM \ + 0xCF1DDA2EL,0x9743,0x11D0,0xA3,0xEE,0x00,0xA0,0xC9,0x22,0x31,0x96 +DEFINE_GUIDSTRUCT("CF1DDA2E-9743-11D0-A3EE-00A0C9223196",KSCATEGORY_MEDIUMTRANSFORM); +#define KSCATEGORY_MEDIUMTRANSFORM DEFINE_GUIDNAMED(KSCATEGORY_MEDIUMTRANSFORM) + +#define STATIC_KSCATEGORY_FILESYSTEM \ + 0x760FED5EL,0x9357,0x11D0,0xA3,0xCC,0x00,0xA0,0xC9,0x22,0x31,0x96 +DEFINE_GUIDSTRUCT("760FED5E-9357-11D0-A3CC-00A0C9223196",KSCATEGORY_FILESYSTEM); +#define KSCATEGORY_FILESYSTEM DEFINE_GUIDNAMED(KSCATEGORY_FILESYSTEM) + +#define STATIC_KSCATEGORY_CLOCK \ + 0x53172480L,0x4791,0x11D0,0xA5,0xD6,0x28,0xDB,0x04,0xC1,0x00,0x00 +DEFINE_GUIDSTRUCT("53172480-4791-11D0-A5D6-28DB04C10000",KSCATEGORY_CLOCK); +#define KSCATEGORY_CLOCK DEFINE_GUIDNAMED(KSCATEGORY_CLOCK) + +#define STATIC_KSCATEGORY_PROXY \ + 0x97EBAACAL,0x95BD,0x11D0,0xA3,0xEA,0x00,0xA0,0xC9,0x22,0x31,0x96 +DEFINE_GUIDSTRUCT("97EBAACA-95BD-11D0-A3EA-00A0C9223196",KSCATEGORY_PROXY); +#define KSCATEGORY_PROXY DEFINE_GUIDNAMED(KSCATEGORY_PROXY) + +#define STATIC_KSCATEGORY_QUALITY \ + 0x97EBAACBL,0x95BD,0x11D0,0xA3,0xEA,0x00,0xA0,0xC9,0x22,0x31,0x96 +DEFINE_GUIDSTRUCT("97EBAACB-95BD-11D0-A3EA-00A0C9223196",KSCATEGORY_QUALITY); +#define KSCATEGORY_QUALITY DEFINE_GUIDNAMED(KSCATEGORY_QUALITY) + +typedef struct { + ULONG FromNode; + ULONG FromNodePin; + ULONG ToNode; + ULONG ToNodePin; +} KSTOPOLOGY_CONNECTION,*PKSTOPOLOGY_CONNECTION; + +typedef struct { + ULONG CategoriesCount; + const GUID *Categories; + ULONG TopologyNodesCount; + const GUID *TopologyNodes; + ULONG TopologyConnectionsCount; + const KSTOPOLOGY_CONNECTION *TopologyConnections; + const GUID *TopologyNodesNames; + ULONG Reserved; +} KSTOPOLOGY,*PKSTOPOLOGY; + +#define KSFILTER_NODE ((ULONG)-1) +#define KSALL_NODES ((ULONG)-1) + +typedef struct { + ULONG CreateFlags; + ULONG Node; +} KSNODE_CREATE,*PKSNODE_CREATE; + +#define STATIC_KSTIME_FORMAT_NONE STATIC_GUID_NULL +#define KSTIME_FORMAT_NONE GUID_NULL + +#define STATIC_KSTIME_FORMAT_FRAME \ + 0x7b785570L,0x8c82,0x11cf,0xbc,0x0c,0x00,0xaa,0x00,0xac,0x74,0xf6 +DEFINE_GUIDSTRUCT("7b785570-8c82-11cf-bc0c-00aa00ac74f6",KSTIME_FORMAT_FRAME); +#define KSTIME_FORMAT_FRAME DEFINE_GUIDNAMED(KSTIME_FORMAT_FRAME) + +#define STATIC_KSTIME_FORMAT_BYTE \ + 0x7b785571L,0x8c82,0x11cf,0xbc,0x0c,0x00,0xaa,0x00,0xac,0x74,0xf6 +DEFINE_GUIDSTRUCT("7b785571-8c82-11cf-bc0c-00aa00ac74f6",KSTIME_FORMAT_BYTE); +#define KSTIME_FORMAT_BYTE DEFINE_GUIDNAMED(KSTIME_FORMAT_BYTE) + +#define STATIC_KSTIME_FORMAT_SAMPLE \ + 0x7b785572L,0x8c82,0x11cf,0xbc,0x0c,0x00,0xaa,0x00,0xac,0x74,0xf6 +DEFINE_GUIDSTRUCT("7b785572-8c82-11cf-bc0c-00aa00ac74f6",KSTIME_FORMAT_SAMPLE); +#define KSTIME_FORMAT_SAMPLE DEFINE_GUIDNAMED(KSTIME_FORMAT_SAMPLE) + +#define STATIC_KSTIME_FORMAT_FIELD \ + 0x7b785573L,0x8c82,0x11cf,0xbc,0x0c,0x00,0xaa,0x00,0xac,0x74,0xf6 +DEFINE_GUIDSTRUCT("7b785573-8c82-11cf-bc0c-00aa00ac74f6",KSTIME_FORMAT_FIELD); +#define KSTIME_FORMAT_FIELD DEFINE_GUIDNAMED(KSTIME_FORMAT_FIELD) + +#define STATIC_KSTIME_FORMAT_MEDIA_TIME \ + 0x7b785574L,0x8c82,0x11cf,0xbc,0x0c,0x00,0xaa,0x00,0xac,0x74,0xf6 +DEFINE_GUIDSTRUCT("7b785574-8c82-11cf-bc0c-00aa00ac74f6",KSTIME_FORMAT_MEDIA_TIME); +#define KSTIME_FORMAT_MEDIA_TIME DEFINE_GUIDNAMED(KSTIME_FORMAT_MEDIA_TIME) + +typedef KSIDENTIFIER KSPIN_INTERFACE,*PKSPIN_INTERFACE; + +#define STATIC_KSINTERFACESETID_Standard \ + 0x1A8766A0L,0x62CE,0x11CF,0xA5,0xD6,0x28,0xDB,0x04,0xC1,0x00,0x00 +DEFINE_GUIDSTRUCT("1A8766A0-62CE-11CF-A5D6-28DB04C10000",KSINTERFACESETID_Standard); +#define KSINTERFACESETID_Standard DEFINE_GUIDNAMED(KSINTERFACESETID_Standard) + +typedef enum { + KSINTERFACE_STANDARD_STREAMING, + KSINTERFACE_STANDARD_LOOPED_STREAMING, + KSINTERFACE_STANDARD_CONTROL +} KSINTERFACE_STANDARD; + +#define STATIC_KSINTERFACESETID_FileIo \ + 0x8C6F932CL,0xE771,0x11D0,0xB8,0xFF,0x00,0xA0,0xC9,0x22,0x31,0x96 +DEFINE_GUIDSTRUCT("8C6F932C-E771-11D0-B8FF-00A0C9223196",KSINTERFACESETID_FileIo); +#define KSINTERFACESETID_FileIo DEFINE_GUIDNAMED(KSINTERFACESETID_FileIo) + +typedef enum { + KSINTERFACE_FILEIO_STREAMING +} KSINTERFACE_FILEIO; + +#define KSMEDIUM_TYPE_ANYINSTANCE 0 + +#define STATIC_KSMEDIUMSETID_Standard \ + 0x4747B320L,0x62CE,0x11CF,0xA5,0xD6,0x28,0xDB,0x04,0xC1,0x00,0x00 +DEFINE_GUIDSTRUCT("4747B320-62CE-11CF-A5D6-28DB04C10000",KSMEDIUMSETID_Standard); +#define KSMEDIUMSETID_Standard DEFINE_GUIDNAMED(KSMEDIUMSETID_Standard) + +#define KSMEDIUM_STANDARD_DEVIO KSMEDIUM_TYPE_ANYINSTANCE + +#define STATIC_KSPROPSETID_Pin \ + 0x8C134960L,0x51AD,0x11CF,0x87,0x8A,0x94,0xF8,0x01,0xC1,0x00,0x00 +DEFINE_GUIDSTRUCT("8C134960-51AD-11CF-878A-94F801C10000",KSPROPSETID_Pin); +#define KSPROPSETID_Pin DEFINE_GUIDNAMED(KSPROPSETID_Pin) + +typedef enum { + KSPROPERTY_PIN_CINSTANCES, + KSPROPERTY_PIN_CTYPES, + KSPROPERTY_PIN_DATAFLOW, + KSPROPERTY_PIN_DATARANGES, + KSPROPERTY_PIN_DATAINTERSECTION, + KSPROPERTY_PIN_INTERFACES, + KSPROPERTY_PIN_MEDIUMS, + KSPROPERTY_PIN_COMMUNICATION, + KSPROPERTY_PIN_GLOBALCINSTANCES, + KSPROPERTY_PIN_NECESSARYINSTANCES, + KSPROPERTY_PIN_PHYSICALCONNECTION, + KSPROPERTY_PIN_CATEGORY, + KSPROPERTY_PIN_NAME, + KSPROPERTY_PIN_CONSTRAINEDDATARANGES, + KSPROPERTY_PIN_PROPOSEDATAFORMAT +} KSPROPERTY_PIN; + +typedef struct { + KSPROPERTY Property; + ULONG PinId; + ULONG Reserved; +} KSP_PIN,*PKSP_PIN; + +#define KSINSTANCE_INDETERMINATE ((ULONG)-1) + +typedef struct { + ULONG PossibleCount; + ULONG CurrentCount; +} KSPIN_CINSTANCES,*PKSPIN_CINSTANCES; + +typedef enum { + KSPIN_DATAFLOW_IN = 1, + KSPIN_DATAFLOW_OUT +} KSPIN_DATAFLOW,*PKSPIN_DATAFLOW; + +#define KSDATAFORMAT_BIT_TEMPORAL_COMPRESSION 0 +#define KSDATAFORMAT_TEMPORAL_COMPRESSION (1 << KSDATAFORMAT_BIT_TEMPORAL_COMPRESSION) +#define KSDATAFORMAT_BIT_ATTRIBUTES 1 +#define KSDATAFORMAT_ATTRIBUTES (1 << KSDATAFORMAT_BIT_ATTRIBUTES) + +#define KSDATARANGE_BIT_ATTRIBUTES 1 +#define KSDATARANGE_ATTRIBUTES (1 << KSDATARANGE_BIT_ATTRIBUTES) +#define KSDATARANGE_BIT_REQUIRED_ATTRIBUTES 2 +#define KSDATARANGE_REQUIRED_ATTRIBUTES (1 << KSDATARANGE_BIT_REQUIRED_ATTRIBUTES) + +typedef union { + __MINGW_EXTENSION struct { + ULONG FormatSize; + ULONG Flags; + ULONG SampleSize; + ULONG Reserved; + GUID MajorFormat; + GUID SubFormat; + GUID Specifier; + }; + LONGLONG Alignment; +} KSDATAFORMAT,*PKSDATAFORMAT,KSDATARANGE,*PKSDATARANGE; + +#define KSATTRIBUTE_REQUIRED 0x00000001 + +typedef struct { + ULONG Size; + ULONG Flags; + GUID Attribute; +} KSATTRIBUTE,*PKSATTRIBUTE; + +#if defined(_NTDDK_) +typedef struct { + ULONG Count; + PKSATTRIBUTE *Attributes; +} KSATTRIBUTE_LIST,*PKSATTRIBUTE_LIST; +#endif /* _NTDDK_ */ + +typedef enum { + KSPIN_COMMUNICATION_NONE, + KSPIN_COMMUNICATION_SINK, + KSPIN_COMMUNICATION_SOURCE, + KSPIN_COMMUNICATION_BOTH, + KSPIN_COMMUNICATION_BRIDGE +} KSPIN_COMMUNICATION,*PKSPIN_COMMUNICATION; + +typedef KSIDENTIFIER KSPIN_MEDIUM,*PKSPIN_MEDIUM; + +typedef struct { + KSPIN_INTERFACE Interface; + KSPIN_MEDIUM Medium; + ULONG PinId; + HANDLE PinToHandle; + KSPRIORITY Priority; +} KSPIN_CONNECT,*PKSPIN_CONNECT; + +typedef struct { + ULONG Size; + ULONG Pin; + WCHAR SymbolicLinkName[1]; +} KSPIN_PHYSICALCONNECTION,*PKSPIN_PHYSICALCONNECTION; + +#if defined(_NTDDK_) +typedef NTSTATUS (*PFNKSINTERSECTHANDLER) ( PIRP Irp, PKSP_PIN Pin, + PKSDATARANGE DataRange, + PVOID Data); +typedef NTSTATUS (*PFNKSINTERSECTHANDLEREX)(PVOID Context, PIRP Irp, + PKSP_PIN Pin, + PKSDATARANGE DataRange, + PKSDATARANGE MatchingDataRange, + ULONG DataBufferSize, + PVOID Data, + PULONG DataSize); +#endif /* _NTDDK_ */ + +#define DEFINE_KSPIN_INTERFACE_TABLE(tablename) \ + const KSPIN_INTERFACE tablename[] = + +#define DEFINE_KSPIN_INTERFACE_ITEM(guid,_interFace) \ + { \ + STATICGUIDOF(guid), \ + (_interFace), \ + 0 \ + } + +#define DEFINE_KSPIN_MEDIUM_TABLE(tablename) \ + const KSPIN_MEDIUM tablename[] = + +#define DEFINE_KSPIN_MEDIUM_ITEM(guid,medium) \ + DEFINE_KSPIN_INTERFACE_ITEM(guid,medium) + +#define DEFINE_KSPROPERTY_ITEM_PIN_CINSTANCES(Handler) \ + DEFINE_KSPROPERTY_ITEM( \ + KSPROPERTY_PIN_CINSTANCES, \ + (Handler), \ + sizeof(KSP_PIN), \ + sizeof(KSPIN_CINSTANCES), \ + NULL, NULL, 0, NULL, NULL, 0) + +#define DEFINE_KSPROPERTY_ITEM_PIN_CTYPES(Handler) \ + DEFINE_KSPROPERTY_ITEM( \ + KSPROPERTY_PIN_CTYPES, \ + (Handler), \ + sizeof(KSPROPERTY), \ + sizeof(ULONG), \ + NULL, NULL, 0, NULL, NULL, 0) + +#define DEFINE_KSPROPERTY_ITEM_PIN_DATAFLOW(Handler) \ + DEFINE_KSPROPERTY_ITEM( \ + KSPROPERTY_PIN_DATAFLOW, \ + (Handler), \ + sizeof(KSP_PIN), \ + sizeof(KSPIN_DATAFLOW), \ + NULL, NULL, 0, NULL, NULL, 0) + +#define DEFINE_KSPROPERTY_ITEM_PIN_DATARANGES(Handler) \ + DEFINE_KSPROPERTY_ITEM( \ + KSPROPERTY_PIN_DATARANGES, \ + (Handler), \ + sizeof(KSP_PIN), \ + 0, \ + NULL, NULL, 0, NULL, NULL, 0) + +#define DEFINE_KSPROPERTY_ITEM_PIN_DATAINTERSECTION(Handler) \ + DEFINE_KSPROPERTY_ITEM( \ + KSPROPERTY_PIN_DATAINTERSECTION, \ + (Handler), \ + sizeof(KSP_PIN) + sizeof(KSMULTIPLE_ITEM),\ + 0, \ + NULL, NULL, 0, NULL, NULL, 0) + +#define DEFINE_KSPROPERTY_ITEM_PIN_INTERFACES(Handler) \ + DEFINE_KSPROPERTY_ITEM( \ + KSPROPERTY_PIN_INTERFACES, \ + (Handler), \ + sizeof(KSP_PIN), \ + 0, \ + NULL, NULL, 0, NULL, NULL, 0) + +#define DEFINE_KSPROPERTY_ITEM_PIN_MEDIUMS(Handler) \ + DEFINE_KSPROPERTY_ITEM( \ + KSPROPERTY_PIN_MEDIUMS, \ + (Handler), \ + sizeof(KSP_PIN), \ + 0, \ + NULL, NULL, 0, NULL, NULL, 0) + +#define DEFINE_KSPROPERTY_ITEM_PIN_COMMUNICATION(Handler) \ + DEFINE_KSPROPERTY_ITEM( \ + KSPROPERTY_PIN_COMMUNICATION, \ + (Handler), \ + sizeof(KSP_PIN), \ + sizeof(KSPIN_COMMUNICATION), \ + NULL, NULL, 0, NULL, NULL, 0) + +#define DEFINE_KSPROPERTY_ITEM_PIN_GLOBALCINSTANCES(Handler) \ + DEFINE_KSPROPERTY_ITEM( \ + KSPROPERTY_PIN_GLOBALCINSTANCES, \ + (Handler), \ + sizeof(KSP_PIN), \ + sizeof(KSPIN_CINSTANCES), \ + NULL, NULL, 0, NULL, NULL, 0) + +#define DEFINE_KSPROPERTY_ITEM_PIN_NECESSARYINSTANCES(Handler) \ + DEFINE_KSPROPERTY_ITEM( \ + KSPROPERTY_PIN_NECESSARYINSTANCES, \ + (Handler), \ + sizeof(KSP_PIN), \ + sizeof(ULONG), \ + NULL, NULL, 0, NULL, NULL, 0) + +#define DEFINE_KSPROPERTY_ITEM_PIN_PHYSICALCONNECTION(Handler) \ + DEFINE_KSPROPERTY_ITEM( \ + KSPROPERTY_PIN_PHYSICALCONNECTION, \ + (Handler), \ + sizeof(KSP_PIN), \ + 0, \ + NULL, NULL, 0, NULL, NULL, 0) + +#define DEFINE_KSPROPERTY_ITEM_PIN_CATEGORY(Handler) \ + DEFINE_KSPROPERTY_ITEM( \ + KSPROPERTY_PIN_CATEGORY, \ + (Handler), \ + sizeof(KSP_PIN), \ + sizeof(GUID), \ + NULL, NULL, 0, NULL, NULL, 0) + +#define DEFINE_KSPROPERTY_ITEM_PIN_NAME(Handler) \ + DEFINE_KSPROPERTY_ITEM( \ + KSPROPERTY_PIN_NAME, \ + (Handler), \ + sizeof(KSP_PIN), \ + 0, \ + NULL, NULL, 0, NULL, NULL, 0) + +#define DEFINE_KSPROPERTY_ITEM_PIN_CONSTRAINEDDATARANGES(Handler) \ + DEFINE_KSPROPERTY_ITEM( \ + KSPROPERTY_PIN_CONSTRAINEDDATARANGES, \ + (Handler), \ + sizeof(KSP_PIN), \ + 0, \ + NULL, NULL, 0, NULL, NULL, 0) + +#define DEFINE_KSPROPERTY_ITEM_PIN_PROPOSEDATAFORMAT(Handler) \ + DEFINE_KSPROPERTY_ITEM( \ + KSPROPERTY_PIN_PROPOSEDATAFORMAT, \ + NULL, \ + sizeof(KSP_PIN), \ + sizeof(KSDATAFORMAT), \ + (Handler), NULL, 0, NULL, NULL, 0) + +#define DEFINE_KSPROPERTY_PINSET(PinSet,PropGeneral,PropInstances,PropIntersection) \ +DEFINE_KSPROPERTY_TABLE(PinSet) { \ + DEFINE_KSPROPERTY_ITEM_PIN_CINSTANCES(PropInstances), \ + DEFINE_KSPROPERTY_ITEM_PIN_CTYPES(PropGeneral), \ + DEFINE_KSPROPERTY_ITEM_PIN_DATAFLOW(PropGeneral), \ + DEFINE_KSPROPERTY_ITEM_PIN_DATARANGES(PropGeneral), \ + DEFINE_KSPROPERTY_ITEM_PIN_DATAINTERSECTION(PropIntersection), \ + DEFINE_KSPROPERTY_ITEM_PIN_INTERFACES(PropGeneral), \ + DEFINE_KSPROPERTY_ITEM_PIN_MEDIUMS(PropGeneral), \ + DEFINE_KSPROPERTY_ITEM_PIN_COMMUNICATION(PropGeneral), \ + DEFINE_KSPROPERTY_ITEM_PIN_CATEGORY(PropGeneral), \ + DEFINE_KSPROPERTY_ITEM_PIN_NAME(PropGeneral) \ +} + +#define DEFINE_KSPROPERTY_PINSETCONSTRAINED(PinSet,PropGeneral,PropInstances,PropIntersection) \ +DEFINE_KSPROPERTY_TABLE(PinSet) { \ + DEFINE_KSPROPERTY_ITEM_PIN_CINSTANCES(PropInstances), \ + DEFINE_KSPROPERTY_ITEM_PIN_CTYPES(PropGeneral), \ + DEFINE_KSPROPERTY_ITEM_PIN_DATAFLOW(PropGeneral), \ + DEFINE_KSPROPERTY_ITEM_PIN_DATARANGES(PropGeneral), \ + DEFINE_KSPROPERTY_ITEM_PIN_DATAINTERSECTION(PropIntersection), \ + DEFINE_KSPROPERTY_ITEM_PIN_INTERFACES(PropGeneral), \ + DEFINE_KSPROPERTY_ITEM_PIN_MEDIUMS(PropGeneral), \ + DEFINE_KSPROPERTY_ITEM_PIN_COMMUNICATION(PropGeneral), \ + DEFINE_KSPROPERTY_ITEM_PIN_CATEGORY(PropGeneral), \ + DEFINE_KSPROPERTY_ITEM_PIN_NAME(PropGeneral), \ + DEFINE_KSPROPERTY_ITEM_PIN_CONSTRAINEDDATARANGES(PropGeneral) \ +} + +#define STATIC_KSNAME_Filter \ + 0x9b365890L,0x165f,0x11d0,0xa1,0x95,0x00,0x20,0xaf,0xd1,0x56,0xe4 +DEFINE_GUIDSTRUCT("9b365890-165f-11d0-a195-0020afd156e4",KSNAME_Filter); +#define KSNAME_Filter DEFINE_GUIDNAMED(KSNAME_Filter) + +#define KSSTRING_Filter L"{9B365890-165F-11D0-A195-0020AFD156E4}" + +#define STATIC_KSNAME_Pin \ + 0x146F1A80L,0x4791,0x11D0,0xA5,0xD6,0x28,0xDB,0x04,0xC1,0x00,0x00 +DEFINE_GUIDSTRUCT("146F1A80-4791-11D0-A5D6-28DB04C10000",KSNAME_Pin); +#define KSNAME_Pin DEFINE_GUIDNAMED(KSNAME_Pin) + +#define KSSTRING_Pin L"{146F1A80-4791-11D0-A5D6-28DB04C10000}" + +#define STATIC_KSNAME_Clock \ + 0x53172480L,0x4791,0x11D0,0xA5,0xD6,0x28,0xDB,0x04,0xC1,0x00,0x00 +DEFINE_GUIDSTRUCT("53172480-4791-11D0-A5D6-28DB04C10000",KSNAME_Clock); +#define KSNAME_Clock DEFINE_GUIDNAMED(KSNAME_Clock) + +#define KSSTRING_Clock L"{53172480-4791-11D0-A5D6-28DB04C10000}" + +#define STATIC_KSNAME_Allocator \ + 0x642F5D00L,0x4791,0x11D0,0xA5,0xD6,0x28,0xDB,0x04,0xC1,0x00,0x00 +DEFINE_GUIDSTRUCT("642F5D00-4791-11D0-A5D6-28DB04C10000",KSNAME_Allocator); +#define KSNAME_Allocator DEFINE_GUIDNAMED(KSNAME_Allocator) + +#define KSSTRING_Allocator L"{642F5D00-4791-11D0-A5D6-28DB04C10000}" + +#define KSSTRING_AllocatorEx L"{091BB63B-603F-11D1-B067-00A0C9062802}" + +#define STATIC_KSNAME_TopologyNode \ + 0x0621061AL,0xEE75,0x11D0,0xB9,0x15,0x00,0xA0,0xC9,0x22,0x31,0x96 +DEFINE_GUIDSTRUCT("0621061A-EE75-11D0-B915-00A0C9223196",KSNAME_TopologyNode); +#define KSNAME_TopologyNode DEFINE_GUIDNAMED(KSNAME_TopologyNode) + +#define KSSTRING_TopologyNode L"{0621061A-EE75-11D0-B915-00A0C9223196}" + +#if defined(_NTDDK_) +typedef struct { + ULONG InterfacesCount; + const KSPIN_INTERFACE *Interfaces; + ULONG MediumsCount; + const KSPIN_MEDIUM *Mediums; + ULONG DataRangesCount; + const PKSDATARANGE *DataRanges; + KSPIN_DATAFLOW DataFlow; + KSPIN_COMMUNICATION Communication; + const GUID *Category; + const GUID *Name; + __MINGW_EXTENSION union { + LONGLONG Reserved; + __MINGW_EXTENSION struct { + ULONG ConstrainedDataRangesCount; + PKSDATARANGE *ConstrainedDataRanges; + }; + }; +} KSPIN_DESCRIPTOR, *PKSPIN_DESCRIPTOR; +typedef const KSPIN_DESCRIPTOR *PCKSPIN_DESCRIPTOR; + +#define DEFINE_KSPIN_DESCRIPTOR_TABLE(tablename) \ + const KSPIN_DESCRIPTOR tablename[] = + +#define DEFINE_KSPIN_DESCRIPTOR_ITEM(InterfacesCount,Interfaces,MediumsCount, Mediums,DataRangesCount,DataRanges,DataFlow,Communication)\ +{ \ + InterfacesCount, Interfaces, MediumsCount, Mediums, \ + DataRangesCount, DataRanges, DataFlow, Communication, \ + NULL, NULL, 0 \ +} + +#define DEFINE_KSPIN_DESCRIPTOR_ITEMEX(InterfacesCount,Interfaces,MediumsCount,Mediums,DataRangesCount,DataRanges,DataFlow,Communication,Category,Name)\ +{ \ + InterfacesCount, Interfaces, MediumsCount, Mediums, \ + DataRangesCount, DataRanges, DataFlow, Communication, \ + Category, Name, 0 \ +} +#endif /* _NTDDK_ */ + +#define STATIC_KSDATAFORMAT_TYPE_WILDCARD STATIC_GUID_NULL +#define KSDATAFORMAT_TYPE_WILDCARD GUID_NULL + +#define STATIC_KSDATAFORMAT_SUBTYPE_WILDCARD STATIC_GUID_NULL +#define KSDATAFORMAT_SUBTYPE_WILDCARD GUID_NULL + +#define STATIC_KSDATAFORMAT_TYPE_STREAM \ + 0xE436EB83L,0x524F,0x11CE,0x9F,0x53,0x00,0x20,0xAF,0x0B,0xA7,0x70 +DEFINE_GUIDSTRUCT("E436EB83-524F-11CE-9F53-0020AF0BA770",KSDATAFORMAT_TYPE_STREAM); +#define KSDATAFORMAT_TYPE_STREAM DEFINE_GUIDNAMED(KSDATAFORMAT_TYPE_STREAM) + +#define STATIC_KSDATAFORMAT_SUBTYPE_NONE \ + 0xE436EB8EL,0x524F,0x11CE,0x9F,0x53,0x00,0x20,0xAF,0x0B,0xA7,0x70 +DEFINE_GUIDSTRUCT("E436EB8E-524F-11CE-9F53-0020AF0BA770",KSDATAFORMAT_SUBTYPE_NONE); +#define KSDATAFORMAT_SUBTYPE_NONE DEFINE_GUIDNAMED(KSDATAFORMAT_SUBTYPE_NONE) + +#define STATIC_KSDATAFORMAT_SPECIFIER_WILDCARD STATIC_GUID_NULL +#define KSDATAFORMAT_SPECIFIER_WILDCARD GUID_NULL + +#define STATIC_KSDATAFORMAT_SPECIFIER_FILENAME \ + 0xAA797B40L,0xE974,0x11CF,0xA5,0xD6,0x28,0xDB,0x04,0xC1,0x00,0x00 +DEFINE_GUIDSTRUCT("AA797B40-E974-11CF-A5D6-28DB04C10000",KSDATAFORMAT_SPECIFIER_FILENAME); +#define KSDATAFORMAT_SPECIFIER_FILENAME DEFINE_GUIDNAMED(KSDATAFORMAT_SPECIFIER_FILENAME) + +#define STATIC_KSDATAFORMAT_SPECIFIER_FILEHANDLE \ + 0x65E8773CL,0x8F56,0x11D0,0xA3,0xB9,0x00,0xA0,0xC9,0x22,0x31,0x96 +DEFINE_GUIDSTRUCT("65E8773C-8F56-11D0-A3B9-00A0C9223196",KSDATAFORMAT_SPECIFIER_FILEHANDLE); +#define KSDATAFORMAT_SPECIFIER_FILEHANDLE DEFINE_GUIDNAMED(KSDATAFORMAT_SPECIFIER_FILEHANDLE) + +#define STATIC_KSDATAFORMAT_SPECIFIER_NONE \ + 0x0F6417D6L,0xC318,0x11D0,0xA4,0x3F,0x00,0xA0,0xC9,0x22,0x31,0x96 +DEFINE_GUIDSTRUCT("0F6417D6-C318-11D0-A43F-00A0C9223196",KSDATAFORMAT_SPECIFIER_NONE); +#define KSDATAFORMAT_SPECIFIER_NONE DEFINE_GUIDNAMED(KSDATAFORMAT_SPECIFIER_NONE) + +#define STATIC_KSPROPSETID_Quality \ + 0xD16AD380L,0xAC1A,0x11CF,0xA5,0xD6,0x28,0xDB,0x04,0xC1,0x00,0x00 +DEFINE_GUIDSTRUCT("D16AD380-AC1A-11CF-A5D6-28DB04C10000",KSPROPSETID_Quality); +#define KSPROPSETID_Quality DEFINE_GUIDNAMED(KSPROPSETID_Quality) + +typedef enum { + KSPROPERTY_QUALITY_REPORT, + KSPROPERTY_QUALITY_ERROR +} KSPROPERTY_QUALITY; + +#define DEFINE_KSPROPERTY_ITEM_QUALITY_REPORT(GetHandler,SetHandler) \ + DEFINE_KSPROPERTY_ITEM( \ + KSPROPERTY_QUALITY_REPORT, \ + (GetHandler), \ + sizeof(KSPROPERTY), \ + sizeof(KSQUALITY), \ + (SetHandler), \ + NULL, 0, NULL, NULL, 0) + +#define DEFINE_KSPROPERTY_ITEM_QUALITY_ERROR(GetHandler,SetHandler) \ + DEFINE_KSPROPERTY_ITEM( \ + KSPROPERTY_QUALITY_ERROR, \ + (GetHandler), \ + sizeof(KSPROPERTY), \ + sizeof(KSERROR), \ + (SetHandler), \ + NULL, 0, NULL, NULL, 0) + +#define STATIC_KSPROPSETID_Connection \ + 0x1D58C920L,0xAC9B,0x11CF,0xA5,0xD6,0x28,0xDB,0x04,0xC1,0x00,0x00 +DEFINE_GUIDSTRUCT("1D58C920-AC9B-11CF-A5D6-28DB04C10000",KSPROPSETID_Connection); +#define KSPROPSETID_Connection DEFINE_GUIDNAMED(KSPROPSETID_Connection) + +typedef enum { + KSPROPERTY_CONNECTION_STATE, + KSPROPERTY_CONNECTION_PRIORITY, + KSPROPERTY_CONNECTION_DATAFORMAT, + KSPROPERTY_CONNECTION_ALLOCATORFRAMING, + KSPROPERTY_CONNECTION_PROPOSEDATAFORMAT, + KSPROPERTY_CONNECTION_ACQUIREORDERING, + KSPROPERTY_CONNECTION_ALLOCATORFRAMING_EX, + KSPROPERTY_CONNECTION_STARTAT +} KSPROPERTY_CONNECTION; + +#define DEFINE_KSPROPERTY_ITEM_CONNECTION_STATE(GetHandler,SetHandler) \ + DEFINE_KSPROPERTY_ITEM( \ + KSPROPERTY_CONNECTION_STATE, \ + (GetHandler), \ + sizeof(KSPROPERTY), \ + sizeof(KSSTATE), \ + (SetHandler), \ + NULL, 0, NULL, NULL, 0) + +#define DEFINE_KSPROPERTY_ITEM_CONNECTION_PRIORITY(GetHandler,SetHandler) \ + DEFINE_KSPROPERTY_ITEM( \ + KSPROPERTY_CONNECTION_PRIORITY, \ + (GetHandler), \ + sizeof(KSPROPERTY), \ + sizeof(KSPRIORITY), \ + (SetHandler), \ + NULL, 0, NULL, NULL, 0) + +#define DEFINE_KSPROPERTY_ITEM_CONNECTION_DATAFORMAT(GetHandler,SetHandler)\ + DEFINE_KSPROPERTY_ITEM( \ + KSPROPERTY_CONNECTION_DATAFORMAT, \ + (GetHandler), \ + sizeof(KSPROPERTY), \ + 0, \ + (SetHandler), \ + NULL, 0, NULL, NULL, 0) + +#define DEFINE_KSPROPERTY_ITEM_CONNECTION_ALLOCATORFRAMING(Handler) \ + DEFINE_KSPROPERTY_ITEM( \ + KSPROPERTY_CONNECTION_ALLOCATORFRAMING, \ + (Handler), \ + sizeof(KSPROPERTY), \ + sizeof(KSALLOCATOR_FRAMING), \ + NULL, NULL, 0, NULL, NULL, 0) + +#define DEFINE_KSPROPERTY_ITEM_CONNECTION_ALLOCATORFRAMING_EX(Handler) \ + DEFINE_KSPROPERTY_ITEM( \ + KSPROPERTY_CONNECTION_ALLOCATORFRAMING_EX,\ + (Handler), \ + sizeof(KSPROPERTY), \ + 0, \ + NULL, NULL, 0, NULL, NULL, 0) + +#define DEFINE_KSPROPERTY_ITEM_CONNECTION_PROPOSEDATAFORMAT(Handler) \ + DEFINE_KSPROPERTY_ITEM( \ + KSPROPERTY_CONNECTION_PROPOSEDATAFORMAT,\ + NULL, \ + sizeof(KSPROPERTY), \ + sizeof(KSDATAFORMAT), \ + (Handler), \ + NULL, 0, NULL, NULL, 0) + +#define DEFINE_KSPROPERTY_ITEM_CONNECTION_ACQUIREORDERING(Handler) \ + DEFINE_KSPROPERTY_ITEM( \ + KSPROPERTY_CONNECTION_ACQUIREORDERING, \ + (Handler), \ + sizeof(KSPROPERTY), \ + sizeof(int), \ + NULL, NULL, 0, NULL, NULL, 0) + +#define DEFINE_KSPROPERTY_ITEM_CONNECTION_STARTAT(Handler) \ + DEFINE_KSPROPERTY_ITEM( \ + KSPROPERTY_CONNECTION_STARTAT, \ + NULL, \ + sizeof(KSPROPERTY), \ + sizeof(KSRELATIVEEVENT), \ + (Handler), \ + NULL, 0, NULL, NULL, 0) + +#define KSALLOCATOR_REQUIREMENTF_INPLACE_MODIFIER 0x00000001 +#define KSALLOCATOR_REQUIREMENTF_SYSTEM_MEMORY 0x00000002 +#define KSALLOCATOR_REQUIREMENTF_FRAME_INTEGRITY 0x00000004 +#define KSALLOCATOR_REQUIREMENTF_MUST_ALLOCATE 0x00000008 +#define KSALLOCATOR_REQUIREMENTF_PREFERENCES_ONLY 0x80000000 + +#define KSALLOCATOR_OPTIONF_COMPATIBLE 0x00000001 +#define KSALLOCATOR_OPTIONF_SYSTEM_MEMORY 0x00000002 +#define KSALLOCATOR_OPTIONF_VALID 0x00000003 + +#define KSALLOCATOR_FLAG_PARTIAL_READ_SUPPORT 0x00000010 +#define KSALLOCATOR_FLAG_DEVICE_SPECIFIC 0x00000020 +#define KSALLOCATOR_FLAG_CAN_ALLOCATE 0x00000040 +#define KSALLOCATOR_FLAG_INSIST_ON_FRAMESIZE_RATIO 0x00000080 +#define KSALLOCATOR_FLAG_NO_FRAME_INTEGRITY 0x00000100 +#define KSALLOCATOR_FLAG_MULTIPLE_OUTPUT 0x00000200 +#define KSALLOCATOR_FLAG_CYCLE 0x00000400 +#define KSALLOCATOR_FLAG_ALLOCATOR_EXISTS 0x00000800 +#define KSALLOCATOR_FLAG_INDEPENDENT_RANGES 0x00001000 +#define KSALLOCATOR_FLAG_ATTENTION_STEPPING 0x00002000 + +typedef struct { + __MINGW_EXTENSION union { + ULONG OptionsFlags; + ULONG RequirementsFlags; + }; +#if defined(_NTDDK_) + POOL_TYPE PoolType; +#else + ULONG PoolType; +#endif /* _NTDDK_ */ + ULONG Frames; + ULONG FrameSize; + ULONG FileAlignment; + ULONG Reserved; +} KSALLOCATOR_FRAMING,*PKSALLOCATOR_FRAMING; + +#if defined(_NTDDK_) +typedef PVOID (*PFNKSDEFAULTALLOCATE)(PVOID Context); +typedef VOID (*PFNKSDEFAULTFREE)(PVOID Context, PVOID Buffer); +typedef NTSTATUS (*PFNKSINITIALIZEALLOCATOR)(PVOID InitialContext, + PKSALLOCATOR_FRAMING AllocatorFraming, + PVOID* Context); +typedef VOID (*PFNKSDELETEALLOCATOR) (PVOID Context); +#endif /* _NTDDK_ */ + +typedef struct { + ULONG MinFrameSize; + ULONG MaxFrameSize; + ULONG Stepping; +} KS_FRAMING_RANGE,*PKS_FRAMING_RANGE; + +typedef struct { + KS_FRAMING_RANGE Range; + ULONG InPlaceWeight; + ULONG NotInPlaceWeight; +} KS_FRAMING_RANGE_WEIGHTED,*PKS_FRAMING_RANGE_WEIGHTED; + +typedef struct { + ULONG RatioNumerator; + ULONG RatioDenominator; + ULONG RatioConstantMargin; +} KS_COMPRESSION,*PKS_COMPRESSION; + +typedef struct { + GUID MemoryType; + GUID BusType; + ULONG MemoryFlags; + ULONG BusFlags; + ULONG Flags; + ULONG Frames; + ULONG FileAlignment; + ULONG MemoryTypeWeight; + KS_FRAMING_RANGE PhysicalRange; + KS_FRAMING_RANGE_WEIGHTED FramingRange; +} KS_FRAMING_ITEM,*PKS_FRAMING_ITEM; + +typedef struct { + ULONG CountItems; + ULONG PinFlags; + KS_COMPRESSION OutputCompression; + ULONG PinWeight; + KS_FRAMING_ITEM FramingItem[1]; +} KSALLOCATOR_FRAMING_EX,*PKSALLOCATOR_FRAMING_EX; + +#define KSMEMORY_TYPE_WILDCARD GUID_NULL +#define STATIC_KSMEMORY_TYPE_WILDCARD STATIC_GUID_NULL + +#define KSMEMORY_TYPE_DONT_CARE GUID_NULL +#define STATIC_KSMEMORY_TYPE_DONT_CARE STATIC_GUID_NULL + +#define KS_TYPE_DONT_CARE GUID_NULL +#define STATIC_KS_TYPE_DONT_CARE STATIC_GUID_NULL + +#define STATIC_KSMEMORY_TYPE_SYSTEM \ + 0x091bb638L,0x603f,0x11d1,0xb0,0x67,0x00,0xa0,0xc9,0x06,0x28,0x02 +DEFINE_GUIDSTRUCT("091bb638-603f-11d1-b067-00a0c9062802",KSMEMORY_TYPE_SYSTEM); +#define KSMEMORY_TYPE_SYSTEM DEFINE_GUIDNAMED(KSMEMORY_TYPE_SYSTEM) + +#define STATIC_KSMEMORY_TYPE_USER \ + 0x8cb0fc28L,0x7893,0x11d1,0xb0,0x69,0x00,0xa0,0xc9,0x06,0x28,0x02 +DEFINE_GUIDSTRUCT("8cb0fc28-7893-11d1-b069-00a0c9062802",KSMEMORY_TYPE_USER); +#define KSMEMORY_TYPE_USER DEFINE_GUIDNAMED(KSMEMORY_TYPE_USER) + +#define STATIC_KSMEMORY_TYPE_KERNEL_PAGED \ + 0xd833f8f8L,0x7894,0x11d1,0xb0,0x69,0x00,0xa0,0xc9,0x06,0x28,0x02 +DEFINE_GUIDSTRUCT("d833f8f8-7894-11d1-b069-00a0c9062802",KSMEMORY_TYPE_KERNEL_PAGED); +#define KSMEMORY_TYPE_KERNEL_PAGED DEFINE_GUIDNAMED(KSMEMORY_TYPE_KERNEL_PAGED) + +#define STATIC_KSMEMORY_TYPE_KERNEL_NONPAGED \ + 0x4a6d5fc4L,0x7895,0x11d1,0xb0,0x69,0x00,0xa0,0xc9,0x06,0x28,0x02 +DEFINE_GUIDSTRUCT("4a6d5fc4-7895-11d1-b069-00a0c9062802",KSMEMORY_TYPE_KERNEL_NONPAGED); +#define KSMEMORY_TYPE_KERNEL_NONPAGED DEFINE_GUIDNAMED(KSMEMORY_TYPE_KERNEL_NONPAGED) + +#define STATIC_KSMEMORY_TYPE_DEVICE_UNKNOWN \ + 0x091bb639L,0x603f,0x11d1,0xb0,0x67,0x00,0xa0,0xc9,0x06,0x28,0x02 +DEFINE_GUIDSTRUCT("091bb639-603f-11d1-b067-00a0c9062802",KSMEMORY_TYPE_DEVICE_UNKNOWN); +#define KSMEMORY_TYPE_DEVICE_UNKNOWN DEFINE_GUIDNAMED(KSMEMORY_TYPE_DEVICE_UNKNOWN) + +#define DECLARE_SIMPLE_FRAMING_EX(FramingExName,MemoryType,Flags,Frames,Alignment,MinFrameSize,MaxFrameSize) \ +const KSALLOCATOR_FRAMING_EX FramingExName = \ +{ \ + 1, \ + 0, \ + { \ + 1, \ + 1, \ + 0 \ + }, \ + 0, \ + { \ + { \ + MemoryType, \ + STATIC_KS_TYPE_DONT_CARE, \ + 0, \ + 0, \ + Flags, \ + Frames, \ + Alignment, \ + 0, \ + { \ + 0, \ + (ULONG)-1, \ + 1 \ + }, \ + { \ + { \ + MinFrameSize, \ + MaxFrameSize, \ + 1 \ + }, \ + 0, \ + 0 \ + } \ + } \ + } \ +} + +#define SetDefaultKsCompression(KsCompressionPointer) \ +{ \ + KsCompressionPointer->RatioNumerator = 1; \ + KsCompressionPointer->RatioDenominator = 1; \ + KsCompressionPointer->RatioConstantMargin = 0; \ +} + +#define SetDontCareKsFramingRange(KsFramingRangePointer) \ +{ \ + KsFramingRangePointer->MinFrameSize = 0; \ + KsFramingRangePointer->MaxFrameSize = (ULONG) -1; \ + KsFramingRangePointer->Stepping = 1; \ +} + +#define SetKsFramingRange(KsFramingRangePointer,P_MinFrameSize,P_MaxFrameSize) \ +{ \ + KsFramingRangePointer->MinFrameSize = P_MinFrameSize; \ + KsFramingRangePointer->MaxFrameSize = P_MaxFrameSize; \ + KsFramingRangePointer->Stepping = 1; \ +} + +#define SetKsFramingRangeWeighted(KsFramingRangeWeightedPointer,P_MinFrameSize,P_MaxFrameSize) \ +{ \ + KS_FRAMING_RANGE *KsFramingRange = \ + &KsFramingRangeWeightedPointer->Range; \ + SetKsFramingRange(KsFramingRange,P_MinFrameSize,P_MaxFrameSize);\ + KsFramingRangeWeightedPointer->InPlaceWeight = 0; \ + KsFramingRangeWeightedPointer->NotInPlaceWeight = 0; \ +} + +#define INITIALIZE_SIMPLE_FRAMING_EX(FramingExPointer,P_MemoryType,P_Flags,P_Frames,P_Alignment,P_MinFrameSize,P_MaxFrameSize) \ +{ \ + KS_COMPRESSION *KsCompression = \ + &FramingExPointer->OutputCompression; \ + KS_FRAMING_RANGE *KsFramingRange = \ + &FramingExPointer->FramingItem[0].PhysicalRange;\ + KS_FRAMING_RANGE_WEIGHTED *KsFramingRangeWeighted = \ + &FramingExPointer->FramingItem[0].FramingRange; \ + FramingExPointer->CountItems = 1; \ + FramingExPointer->PinFlags = 0; \ + SetDefaultKsCompression(KsCompression); \ + FramingExPointer->PinWeight = 0; \ + FramingExPointer->FramingItem[0].MemoryType = P_MemoryType; \ + FramingExPointer->FramingItem[0].BusType = KS_TYPE_DONT_CARE; \ + FramingExPointer->FramingItem[0].MemoryFlags = 0; \ + FramingExPointer->FramingItem[0].BusFlags = 0; \ + FramingExPointer->FramingItem[0].Flags = P_Flags; \ + FramingExPointer->FramingItem[0].Frames = P_Frames; \ + FramingExPointer->FramingItem[0].FileAlignment = P_Alignment; \ + FramingExPointer->FramingItem[0].MemoryTypeWeight = 0; \ + SetDontCareKsFramingRange(KsFramingRange); \ + SetKsFramingRangeWeighted(KsFramingRangeWeighted, \ + P_MinFrameSize,P_MaxFrameSize); \ +} + +#define STATIC_KSEVENTSETID_StreamAllocator \ + 0x75d95571L,0x073c,0x11d0,0xa1,0x61,0x00,0x20,0xaf,0xd1,0x56,0xe4 +DEFINE_GUIDSTRUCT("75d95571-073c-11d0-a161-0020afd156e4",KSEVENTSETID_StreamAllocator); +#define KSEVENTSETID_StreamAllocator DEFINE_GUIDNAMED(KSEVENTSETID_StreamAllocator) + +typedef enum { + KSEVENT_STREAMALLOCATOR_INTERNAL_FREEFRAME, + KSEVENT_STREAMALLOCATOR_FREEFRAME +} KSEVENT_STREAMALLOCATOR; + +#define STATIC_KSMETHODSETID_StreamAllocator \ + 0xcf6e4341L,0xec87,0x11cf,0xa1,0x30,0x00,0x20,0xaf,0xd1,0x56,0xe4 +DEFINE_GUIDSTRUCT("cf6e4341-ec87-11cf-a130-0020afd156e4",KSMETHODSETID_StreamAllocator); +#define KSMETHODSETID_StreamAllocator DEFINE_GUIDNAMED(KSMETHODSETID_StreamAllocator) + +typedef enum { + KSMETHOD_STREAMALLOCATOR_ALLOC, + KSMETHOD_STREAMALLOCATOR_FREE +} KSMETHOD_STREAMALLOCATOR; + +#define DEFINE_KSMETHOD_ITEM_STREAMALLOCATOR_ALLOC(Handler) \ + DEFINE_KSMETHOD_ITEM( \ + KSMETHOD_STREAMALLOCATOR_ALLOC, \ + KSMETHOD_TYPE_WRITE, \ + (Handler), \ + sizeof(KSMETHOD), \ + sizeof(PVOID), \ + NULL) + +#define DEFINE_KSMETHOD_ITEM_STREAMALLOCATOR_FREE(Handler) \ + DEFINE_KSMETHOD_ITEM( \ + KSMETHOD_STREAMALLOCATOR_FREE, \ + KSMETHOD_TYPE_READ, \ + (Handler), \ + sizeof(KSMETHOD), \ + sizeof(PVOID), \ + NULL) + +#define DEFINE_KSMETHOD_ALLOCATORSET(AllocatorSet,MethodAlloc,MethodFree)\ +DEFINE_KSMETHOD_TABLE(AllocatorSet) { \ + DEFINE_KSMETHOD_ITEM_STREAMALLOCATOR_ALLOC(MethodAlloc), \ + DEFINE_KSMETHOD_ITEM_STREAMALLOCATOR_FREE(MethodFree) \ +} + +#define STATIC_KSPROPSETID_StreamAllocator \ + 0xcf6e4342L,0xec87,0x11cf,0xa1,0x30,0x00,0x20,0xaf,0xd1,0x56,0xe4 +DEFINE_GUIDSTRUCT("cf6e4342-ec87-11cf-a130-0020afd156e4",KSPROPSETID_StreamAllocator); +#define KSPROPSETID_StreamAllocator DEFINE_GUIDNAMED(KSPROPSETID_StreamAllocator) + +#if defined(_NTDDK_) +typedef enum { + KSPROPERTY_STREAMALLOCATOR_FUNCTIONTABLE, + KSPROPERTY_STREAMALLOCATOR_STATUS +} KSPROPERTY_STREAMALLOCATOR; + +#define DEFINE_KSPROPERTY_ITEM_STREAMALLOCATOR_FUNCTIONTABLE(Handler) \ + DEFINE_KSPROPERTY_ITEM( \ + KSPROPERTY_STREAMALLOCATOR_FUNCTIONTABLE,\ + (Handler), \ + sizeof(KSPROPERTY), \ + sizeof(KSSTREAMALLOCATOR_FUNCTIONTABLE),\ + NULL, NULL, 0, NULL, NULL, 0) + +#define DEFINE_KSPROPERTY_ITEM_STREAMALLOCATOR_STATUS(Handler) \ + DEFINE_KSPROPERTY_ITEM( \ + KSPROPERTY_STREAMALLOCATOR_STATUS, \ + (Handler), \ + sizeof(KSPROPERTY), \ + sizeof(KSSTREAMALLOCATOR_STATUS), \ + NULL, NULL, 0, NULL, NULL, 0) + +#define DEFINE_KSPROPERTY_ALLOCATORSET(AllocatorSet,PropFunctionTable,PropStatus)\ +DEFINE_KSPROPERTY_TABLE(AllocatorSet) { \ + DEFINE_KSPROPERTY_ITEM_STREAMALLOCATOR_STATUS(PropStatus), \ + DEFINE_KSPROPERTY_ITEM_STREAMALLOCATOR_FUNCTIONTABLE(PropFunctionTable)\ +} + +typedef NTSTATUS (*PFNALLOCATOR_ALLOCATEFRAME) (PFILE_OBJECT FileObject, + PVOID *Frame); +typedef VOID (*PFNALLOCATOR_FREEFRAME) (PFILE_OBJECT FileObject, PVOID Frame); + +typedef struct { + PFNALLOCATOR_ALLOCATEFRAME AllocateFrame; + PFNALLOCATOR_FREEFRAME FreeFrame; +} KSSTREAMALLOCATOR_FUNCTIONTABLE, *PKSSTREAMALLOCATOR_FUNCTIONTABLE; +#endif /* _NTDDK_ */ + +typedef struct { + KSALLOCATOR_FRAMING Framing; + ULONG AllocatedFrames; + ULONG Reserved; +} KSSTREAMALLOCATOR_STATUS,*PKSSTREAMALLOCATOR_STATUS; + +typedef struct { + KSALLOCATOR_FRAMING_EX Framing; + ULONG AllocatedFrames; + ULONG Reserved; +} KSSTREAMALLOCATOR_STATUS_EX,*PKSSTREAMALLOCATOR_STATUS_EX; + +#define KSSTREAM_HEADER_OPTIONSF_SPLICEPOINT 0x00000001 +#define KSSTREAM_HEADER_OPTIONSF_PREROLL 0x00000002 +#define KSSTREAM_HEADER_OPTIONSF_DATADISCONTINUITY 0x00000004 +#define KSSTREAM_HEADER_OPTIONSF_TYPECHANGED 0x00000008 +#define KSSTREAM_HEADER_OPTIONSF_TIMEVALID 0x00000010 +#define KSSTREAM_HEADER_OPTIONSF_TIMEDISCONTINUITY 0x00000040 +#define KSSTREAM_HEADER_OPTIONSF_FLUSHONPAUSE 0x00000080 +#define KSSTREAM_HEADER_OPTIONSF_DURATIONVALID 0x00000100 +#define KSSTREAM_HEADER_OPTIONSF_ENDOFSTREAM 0x00000200 +#define KSSTREAM_HEADER_OPTIONSF_LOOPEDDATA 0x80000000 + +typedef struct { + LONGLONG Time; + ULONG Numerator; + ULONG Denominator; +} KSTIME,*PKSTIME; + +typedef struct { + ULONG Size; + ULONG TypeSpecificFlags; + KSTIME PresentationTime; + LONGLONG Duration; + ULONG FrameExtent; + ULONG DataUsed; + PVOID Data; + ULONG OptionsFlags; +#ifdef _WIN64 + ULONG Reserved; +#endif +} KSSTREAM_HEADER,*PKSSTREAM_HEADER; + +#define STATIC_KSPROPSETID_StreamInterface \ + 0x1fdd8ee1L,0x9cd3,0x11d0,0x82,0xaa,0x00,0x00,0xf8,0x22,0xfe,0x8a +DEFINE_GUIDSTRUCT("1fdd8ee1-9cd3-11d0-82aa-0000f822fe8a",KSPROPSETID_StreamInterface); +#define KSPROPSETID_StreamInterface DEFINE_GUIDNAMED(KSPROPSETID_StreamInterface) + +typedef enum { + KSPROPERTY_STREAMINTERFACE_HEADERSIZE +} KSPROPERTY_STREAMINTERFACE; + +#define DEFINE_KSPROPERTY_ITEM_STREAMINTERFACE_HEADERSIZE(GetHandler) \ + DEFINE_KSPROPERTY_ITEM( \ + KSPROPERTY_STREAMINTERFACE_HEADERSIZE, \ + (GetHandler), \ + sizeof(KSPROPERTY), \ + sizeof(ULONG), \ + NULL,NULL,0,NULL,NULL,0) + +#define DEFINE_KSPROPERTY_STREAMINTERFACESET(StreamInterfaceSet,HeaderSizeHandler) \ +DEFINE_KSPROPERTY_TABLE(StreamInterfaceSet) { \ + DEFINE_KSPROPERTY_ITEM_STREAMINTERFACE_HEADERSIZE(HeaderSizeHandler)\ +} + +#define STATIC_KSPROPSETID_Stream \ + 0x65aaba60L,0x98ae,0x11cf,0xa1,0x0d,0x00,0x20,0xaf,0xd1,0x56,0xe4 +DEFINE_GUIDSTRUCT("65aaba60-98ae-11cf-a10d-0020afd156e4",KSPROPSETID_Stream); +#define KSPROPSETID_Stream DEFINE_GUIDNAMED(KSPROPSETID_Stream) + +typedef enum { + KSPROPERTY_STREAM_ALLOCATOR, + KSPROPERTY_STREAM_QUALITY, + KSPROPERTY_STREAM_DEGRADATION, + KSPROPERTY_STREAM_MASTERCLOCK, + KSPROPERTY_STREAM_TIMEFORMAT, + KSPROPERTY_STREAM_PRESENTATIONTIME, + KSPROPERTY_STREAM_PRESENTATIONEXTENT, + KSPROPERTY_STREAM_FRAMETIME, + KSPROPERTY_STREAM_RATECAPABILITY, + KSPROPERTY_STREAM_RATE, + KSPROPERTY_STREAM_PIPE_ID +} KSPROPERTY_STREAM; + +#define DEFINE_KSPROPERTY_ITEM_STREAM_ALLOCATOR(GetHandler,SetHandler) \ + DEFINE_KSPROPERTY_ITEM( \ + KSPROPERTY_STREAM_ALLOCATOR, \ + (GetHandler), \ + sizeof(KSPROPERTY), \ + sizeof(HANDLE), \ + (SetHandler), \ + NULL, 0, NULL, NULL, 0) + +#define DEFINE_KSPROPERTY_ITEM_STREAM_QUALITY(Handler) \ + DEFINE_KSPROPERTY_ITEM( \ + KSPROPERTY_STREAM_QUALITY, \ + (Handler), \ + sizeof(KSPROPERTY), \ + sizeof(KSQUALITY_MANAGER), \ + NULL, NULL, 0, NULL, NULL, 0) + +#define DEFINE_KSPROPERTY_ITEM_STREAM_DEGRADATION(GetHandler,SetHandler)\ + DEFINE_KSPROPERTY_ITEM( \ + KSPROPERTY_STREAM_DEGRADATION, \ + (GetHandler), \ + sizeof(KSPROPERTY), \ + 0, \ + (SetHandler), \ + NULL, 0, NULL, NULL, 0) + +#define DEFINE_KSPROPERTY_ITEM_STREAM_MASTERCLOCK(GetHandler,SetHandler)\ + DEFINE_KSPROPERTY_ITEM( \ + KSPROPERTY_STREAM_MASTERCLOCK, \ + (GetHandler), \ + sizeof(KSPROPERTY), \ + sizeof(HANDLE), \ + (SetHandler), \ + NULL, 0, NULL, NULL, 0) + +#define DEFINE_KSPROPERTY_ITEM_STREAM_TIMEFORMAT(Handler) \ + DEFINE_KSPROPERTY_ITEM( \ + KSPROPERTY_STREAM_TIMEFORMAT, \ + (Handler), \ + sizeof(KSPROPERTY), \ + sizeof(GUID), \ + NULL, NULL, 0, NULL, NULL, 0) + +#define DEFINE_KSPROPERTY_ITEM_STREAM_PRESENTATIONTIME(GetHandler,SetHandler)\ + DEFINE_KSPROPERTY_ITEM( \ + KSPROPERTY_STREAM_PRESENTATIONTIME, \ + (GetHandler), \ + sizeof(KSPROPERTY), \ + sizeof(KSTIME), \ + (SetHandler), \ + NULL, 0, NULL, NULL, 0) + +#define DEFINE_KSPROPERTY_ITEM_STREAM_PRESENTATIONEXTENT(Handler) \ + DEFINE_KSPROPERTY_ITEM( \ + KSPROPERTY_STREAM_PRESENTATIONEXTENT, \ + (Handler), \ + sizeof(KSPROPERTY), \ + sizeof(LONGLONG), \ + NULL, NULL, 0, NULL, NULL, 0) + +#define DEFINE_KSPROPERTY_ITEM_STREAM_FRAMETIME(Handler) \ + DEFINE_KSPROPERTY_ITEM( \ + KSPROPERTY_STREAM_FRAMETIME, \ + (Handler), \ + sizeof(KSPROPERTY), \ + sizeof(KSFRAMETIME), \ + NULL, NULL, 0, NULL, NULL, 0) + +#define DEFINE_KSPROPERTY_ITEM_STREAM_RATECAPABILITY(Handler) \ + DEFINE_KSPROPERTY_ITEM( \ + KSPROPERTY_STREAM_RATECAPABILITY, \ + (Handler), \ + sizeof(KSRATE_CAPABILITY), \ + sizeof(KSRATE), \ + NULL, NULL, 0, NULL, NULL, 0) + +#define DEFINE_KSPROPERTY_ITEM_STREAM_RATE(GetHandler,SetHandler) \ + DEFINE_KSPROPERTY_ITEM( \ + KSPROPERTY_STREAM_RATE, \ + (GetHandler), \ + sizeof(KSPROPERTY), \ + sizeof(KSRATE), \ + (SetHandler), \ + NULL, 0, NULL, NULL, 0) + +#define DEFINE_KSPROPERTY_ITEM_STREAM_PIPE_ID(GetHandler,SetHandler) \ + DEFINE_KSPROPERTY_ITEM( \ + KSPROPERTY_STREAM_PIPE_ID, \ + (GetHandler), \ + sizeof(KSPROPERTY), \ + sizeof(HANDLE), \ + (SetHandler), \ + NULL, 0, NULL, NULL, 0) + +typedef struct { + HANDLE QualityManager; + PVOID Context; +} KSQUALITY_MANAGER,*PKSQUALITY_MANAGER; + +typedef struct { + LONGLONG Duration; + ULONG FrameFlags; + ULONG Reserved; +} KSFRAMETIME,*PKSFRAMETIME; + +#define KSFRAMETIME_VARIABLESIZE 0x00000001 + +typedef struct { + LONGLONG PresentationStart; + LONGLONG Duration; + KSPIN_INTERFACE Interface; + LONG Rate; + ULONG Flags; +} KSRATE,*PKSRATE; + +#define KSRATE_NOPRESENTATIONSTART 0x00000001 +#define KSRATE_NOPRESENTATIONDURATION 0x00000002 + +typedef struct { + KSPROPERTY Property; + KSRATE Rate; +} KSRATE_CAPABILITY,*PKSRATE_CAPABILITY; + +#define STATIC_KSPROPSETID_Clock \ + 0xDF12A4C0L,0xAC17,0x11CF,0xA5,0xD6,0x28,0xDB,0x04,0xC1,0x00,0x00 +DEFINE_GUIDSTRUCT("DF12A4C0-AC17-11CF-A5D6-28DB04C10000",KSPROPSETID_Clock); +#define KSPROPSETID_Clock DEFINE_GUIDNAMED(KSPROPSETID_Clock) + +#define NANOSECONDS 10000000 +#define KSCONVERT_PERFORMANCE_TIME(Frequency,PerformanceTime) \ + ((((ULONGLONG)(ULONG)(PerformanceTime).HighPart *NANOSECONDS / (Frequency)) << 32) + \ + ((((((ULONGLONG)(ULONG)(PerformanceTime).HighPart *NANOSECONDS) % (Frequency)) << 32) +\ + ((ULONGLONG)(PerformanceTime).LowPart *NANOSECONDS)) / (Frequency))) + +typedef struct { + ULONG CreateFlags; +} KSCLOCK_CREATE,*PKSCLOCK_CREATE; + +typedef struct { + LONGLONG Time; + LONGLONG SystemTime; +} KSCORRELATED_TIME,*PKSCORRELATED_TIME; + +typedef struct { + LONGLONG Granularity; + LONGLONG Error; +} KSRESOLUTION,*PKSRESOLUTION; + +typedef enum { + KSPROPERTY_CLOCK_TIME, + KSPROPERTY_CLOCK_PHYSICALTIME, + KSPROPERTY_CLOCK_CORRELATEDTIME, + KSPROPERTY_CLOCK_CORRELATEDPHYSICALTIME, + KSPROPERTY_CLOCK_RESOLUTION, + KSPROPERTY_CLOCK_STATE, +#if defined(_NTDDK_) + KSPROPERTY_CLOCK_FUNCTIONTABLE +#endif /* _NTDDK_ */ +} KSPROPERTY_CLOCK; + +#if defined(_NTDDK_) +typedef LONGLONG (FASTCALL *PFNKSCLOCK_GETTIME)(PFILE_OBJECT FileObject); +typedef LONGLONG (FASTCALL *PFNKSCLOCK_CORRELATEDTIME)(PFILE_OBJECT FileObject, + PLONGLONG SystemTime); + +typedef struct { + PFNKSCLOCK_GETTIME GetTime; + PFNKSCLOCK_GETTIME GetPhysicalTime; + PFNKSCLOCK_CORRELATEDTIME GetCorrelatedTime; + PFNKSCLOCK_CORRELATEDTIME GetCorrelatedPhysicalTime; +} KSCLOCK_FUNCTIONTABLE, *PKSCLOCK_FUNCTIONTABLE; + +typedef BOOLEAN (*PFNKSSETTIMER)(PVOID Context, PKTIMER Timer, + LARGE_INTEGER DueTime, PKDPC Dpc); +typedef BOOLEAN (*PFNKSCANCELTIMER) (PVOID Context, PKTIMER Timer); +typedef LONGLONG (FASTCALL *PFNKSCORRELATEDTIME)(PVOID Context, + PLONGLONG SystemTime); + +typedef PVOID PKSDEFAULTCLOCK; + +#define DEFINE_KSPROPERTY_ITEM_CLOCK_TIME(Handler) \ + DEFINE_KSPROPERTY_ITEM( \ + KSPROPERTY_CLOCK_TIME, \ + (Handler), \ + sizeof(KSPROPERTY), sizeof(LONGLONG), \ + NULL, NULL, 0, NULL, NULL, 0) + +#define DEFINE_KSPROPERTY_ITEM_CLOCK_PHYSICALTIME(Handler) \ + DEFINE_KSPROPERTY_ITEM( \ + KSPROPERTY_CLOCK_PHYSICALTIME, \ + (Handler), \ + sizeof(KSPROPERTY), sizeof(LONGLONG), \ + NULL, NULL, 0, NULL, NULL, 0) + +#define DEFINE_KSPROPERTY_ITEM_CLOCK_CORRELATEDTIME(Handler) \ + DEFINE_KSPROPERTY_ITEM( \ + KSPROPERTY_CLOCK_CORRELATEDTIME, \ + (Handler), \ + sizeof(KSPROPERTY), \ + sizeof(KSCORRELATED_TIME), \ + NULL, NULL, 0, NULL, NULL, 0) + +#define DEFINE_KSPROPERTY_ITEM_CLOCK_CORRELATEDPHYSICALTIME(Handler) \ + DEFINE_KSPROPERTY_ITEM( \ + KSPROPERTY_CLOCK_CORRELATEDPHYSICALTIME,\ + (Handler), \ + sizeof(KSPROPERTY), \ + sizeof(KSCORRELATED_TIME), \ + NULL, NULL, 0, NULL, NULL, 0) + +#define DEFINE_KSPROPERTY_ITEM_CLOCK_RESOLUTION(Handler) \ + DEFINE_KSPROPERTY_ITEM( \ + KSPROPERTY_CLOCK_RESOLUTION, \ + (Handler), \ + sizeof(KSPROPERTY),sizeof(KSRESOLUTION),\ + NULL, NULL, 0, NULL, NULL, 0) + +#define DEFINE_KSPROPERTY_ITEM_CLOCK_STATE(Handler) \ + DEFINE_KSPROPERTY_ITEM( \ + KSPROPERTY_CLOCK_STATE, \ + (Handler), \ + sizeof(KSPROPERTY), sizeof(KSSTATE), \ + NULL, NULL, 0, NULL, NULL, 0) + +#define DEFINE_KSPROPERTY_ITEM_CLOCK_FUNCTIONTABLE(Handler) \ + DEFINE_KSPROPERTY_ITEM( \ + KSPROPERTY_CLOCK_FUNCTIONTABLE, \ + (Handler), \ + sizeof(KSPROPERTY), \ + sizeof(KSCLOCK_FUNCTIONTABLE), \ + NULL, NULL, 0, NULL, NULL, 0) + +#define DEFINE_KSPROPERTY_CLOCKSET(ClockSet,PropTime,PropPhysicalTime,PropCorrelatedTime,PropCorrelatedPhysicalTime,PropResolution,PropState,PropFunctionTable)\ +DEFINE_KSPROPERTY_TABLE(ClockSet) { \ + DEFINE_KSPROPERTY_ITEM_CLOCK_TIME(PropTime), \ + DEFINE_KSPROPERTY_ITEM_CLOCK_PHYSICALTIME(PropPhysicalTime), \ + DEFINE_KSPROPERTY_ITEM_CLOCK_CORRELATEDTIME(PropCorrelatedTime),\ + DEFINE_KSPROPERTY_ITEM_CLOCK_CORRELATEDPHYSICALTIME(PropCorrelatedPhysicalTime),\ + DEFINE_KSPROPERTY_ITEM_CLOCK_RESOLUTION(PropResolution), \ + DEFINE_KSPROPERTY_ITEM_CLOCK_STATE(PropState), \ + DEFINE_KSPROPERTY_ITEM_CLOCK_FUNCTIONTABLE(PropFunctionTable), \ +} +#endif /* _NTDDK_ */ + +#define STATIC_KSEVENTSETID_Clock \ + 0x364D8E20L,0x62C7,0x11CF,0xA5,0xD6,0x28,0xDB,0x04,0xC1,0x00,0x00 +DEFINE_GUIDSTRUCT("364D8E20-62C7-11CF-A5D6-28DB04C10000",KSEVENTSETID_Clock); +#define KSEVENTSETID_Clock DEFINE_GUIDNAMED(KSEVENTSETID_Clock) + +typedef enum { + KSEVENT_CLOCK_INTERVAL_MARK, + KSEVENT_CLOCK_POSITION_MARK +} KSEVENT_CLOCK_POSITION; + +#define STATIC_KSEVENTSETID_Connection \ + 0x7f4bcbe0L,0x9ea5,0x11cf,0xa5,0xd6,0x28,0xdb,0x04,0xc1,0x00,0x00 +DEFINE_GUIDSTRUCT("7f4bcbe0-9ea5-11cf-a5d6-28db04c10000",KSEVENTSETID_Connection); +#define KSEVENTSETID_Connection DEFINE_GUIDNAMED(KSEVENTSETID_Connection) + +typedef enum { + KSEVENT_CONNECTION_POSITIONUPDATE, + KSEVENT_CONNECTION_DATADISCONTINUITY, + KSEVENT_CONNECTION_TIMEDISCONTINUITY, + KSEVENT_CONNECTION_PRIORITY, + KSEVENT_CONNECTION_ENDOFSTREAM +} KSEVENT_CONNECTION; + +typedef struct { + PVOID Context; + ULONG Proportion; + LONGLONG DeltaTime; +} KSQUALITY,*PKSQUALITY; + +typedef struct { + PVOID Context; + ULONG Status; +} KSERROR,*PKSERROR; + +typedef KSIDENTIFIER KSDEGRADE,*PKSDEGRADE; + +#define STATIC_KSDEGRADESETID_Standard \ + 0x9F564180L,0x704C,0x11D0,0xA5,0xD6,0x28,0xDB,0x04,0xC1,0x00,0x00 +DEFINE_GUIDSTRUCT("9F564180-704C-11D0-A5D6-28DB04C10000",KSDEGRADESETID_Standard); +#define KSDEGRADESETID_Standard DEFINE_GUIDNAMED(KSDEGRADESETID_Standard) + +typedef enum { + KSDEGRADE_STANDARD_SAMPLE, + KSDEGRADE_STANDARD_QUALITY, + KSDEGRADE_STANDARD_COMPUTATION, + KSDEGRADE_STANDARD_SKIP +} KSDEGRADE_STANDARD; + +#if defined(_NTDDK_) + +#define KSPROBE_STREAMREAD 0x00000000 +#define KSPROBE_STREAMWRITE 0x00000001 +#define KSPROBE_ALLOCATEMDL 0x00000010 +#define KSPROBE_PROBEANDLOCK 0x00000020 +#define KSPROBE_SYSTEMADDRESS 0x00000040 +#define KSPROBE_MODIFY 0x00000200 +#define KSPROBE_STREAMWRITEMODIFY (KSPROBE_MODIFY | KSPROBE_STREAMWRITE) +#define KSPROBE_ALLOWFORMATCHANGE 0x00000080 +#define KSSTREAM_READ KSPROBE_STREAMREAD +#define KSSTREAM_WRITE KSPROBE_STREAMWRITE +#define KSSTREAM_PAGED_DATA 0x00000000 +#define KSSTREAM_NONPAGED_DATA 0x00000100 +#define KSSTREAM_SYNCHRONOUS 0x00001000 +#define KSSTREAM_FAILUREEXCEPTION 0x00002000 + +typedef NTSTATUS (*PFNKSCONTEXT_DISPATCH)(PVOID Context, PIRP Irp); +typedef NTSTATUS (*PFNKSHANDLER)(PIRP Irp, PKSIDENTIFIER Request, PVOID Data); +typedef BOOLEAN (*PFNKSFASTHANDLER)(PFILE_OBJECT FileObject, + PKSIDENTIFIER Request, + ULONG RequestLength, PVOID Data, + ULONG DataLength, + PIO_STATUS_BLOCK IoStatus); +typedef NTSTATUS (*PFNKSALLOCATOR) (PIRP Irp, ULONG BufferSize, + BOOLEAN InputOperation); + +typedef struct { + KSPROPERTY_MEMBERSHEADER MembersHeader; + const VOID *Members; +} KSPROPERTY_MEMBERSLIST, *PKSPROPERTY_MEMBERSLIST; + +typedef struct { + KSIDENTIFIER PropTypeSet; + ULONG MembersListCount; + const KSPROPERTY_MEMBERSLIST *MembersList; +} KSPROPERTY_VALUES, *PKSPROPERTY_VALUES; + +#define DEFINE_KSPROPERTY_TABLE(tablename) \ + const KSPROPERTY_ITEM tablename[] = + +#define DEFINE_KSPROPERTY_ITEM(PropertyId,GetHandler,MinProperty,MinData,SetHandler,Values,RelationsCount,Relations,SupportHandler,SerializedSize)\ +{ \ + PropertyId, (PFNKSHANDLER)GetHandler, \ + MinProperty, MinData, \ + (PFNKSHANDLER)SetHandler, \ + (PKSPROPERTY_VALUES)Values, RelationsCount, \ + (PKSPROPERTY)Relations, \ + (PFNKSHANDLER)SupportHandler, \ + (ULONG)SerializedSize \ +} + +typedef struct { + ULONG PropertyId; + __MINGW_EXTENSION union { + PFNKSHANDLER GetPropertyHandler; + BOOLEAN GetSupported; + }; + ULONG MinProperty; + ULONG MinData; + __MINGW_EXTENSION union { + PFNKSHANDLER SetPropertyHandler; + BOOLEAN SetSupported; + }; + const KSPROPERTY_VALUES *Values; + ULONG RelationsCount; + const KSPROPERTY *Relations; + PFNKSHANDLER SupportHandler; + ULONG SerializedSize; +} KSPROPERTY_ITEM, *PKSPROPERTY_ITEM; + +#define DEFINE_KSFASTPROPERTY_ITEM(PropertyId, GetHandler, SetHandler) \ +{ \ + PropertyId, (PFNKSFASTHANDLER)GetHandler, \ + (PFNKSFASTHANDLER)SetHandler, 0 \ +} + +typedef struct { + ULONG PropertyId; + __MINGW_EXTENSION union { + PFNKSFASTHANDLER GetPropertyHandler; + BOOLEAN GetSupported; + }; + __MINGW_EXTENSION union { + PFNKSFASTHANDLER SetPropertyHandler; + BOOLEAN SetSupported; + }; + ULONG Reserved; +} KSFASTPROPERTY_ITEM, *PKSFASTPROPERTY_ITEM; + +#define DEFINE_KSPROPERTY_SET(Set,PropertiesCount,PropertyItem,FastIoCount,FastIoTable)\ +{ \ + Set, \ + PropertiesCount, PropertyItem, \ + FastIoCount, FastIoTable \ +} + +#define DEFINE_KSPROPERTY_SET_TABLE(tablename) \ + const KSPROPERTY_SET tablename[] = + +typedef struct { + const GUID *Set; + ULONG PropertiesCount; + const KSPROPERTY_ITEM *PropertyItem; + ULONG FastIoCount; + const KSFASTPROPERTY_ITEM *FastIoTable; +} KSPROPERTY_SET, *PKSPROPERTY_SET; + +#define DEFINE_KSMETHOD_TABLE(tablename) \ + const KSMETHOD_ITEM tablename[] = + +#define DEFINE_KSMETHOD_ITEM(MethodId,Flags,MethodHandler,MinMethod,MinData,SupportHandler)\ +{ \ + MethodId, (PFNKSHANDLER)MethodHandler, \ + MinMethod, MinData, \ + SupportHandler, Flags \ +} + +typedef struct { + ULONG MethodId; + __MINGW_EXTENSION union { + PFNKSHANDLER MethodHandler; + BOOLEAN MethodSupported; + }; + ULONG MinMethod; + ULONG MinData; + PFNKSHANDLER SupportHandler; + ULONG Flags; +} KSMETHOD_ITEM, *PKSMETHOD_ITEM; + +#define DEFINE_KSFASTMETHOD_ITEM(MethodId,MethodHandler) \ +{ \ + MethodId, (PFNKSFASTHANDLER)MethodHandler \ +} + +typedef struct { + ULONG MethodId; + __MINGW_EXTENSION union { + PFNKSFASTHANDLER MethodHandler; + BOOLEAN MethodSupported; + }; +} KSFASTMETHOD_ITEM, *PKSFASTMETHOD_ITEM; + +#define DEFINE_KSMETHOD_SET(Set,MethodsCount,MethodItem,FastIoCount,FastIoTable)\ +{ \ + Set, \ + MethodsCount, MethodItem, \ + FastIoCount, FastIoTable \ +} + +#define DEFINE_KSMETHOD_SET_TABLE(tablename) \ + const KSMETHOD_SET tablename[] = + +typedef struct { + const GUID *Set; + ULONG MethodsCount; + const KSMETHOD_ITEM *MethodItem; + ULONG FastIoCount; + const KSFASTMETHOD_ITEM *FastIoTable; +} KSMETHOD_SET, *PKSMETHOD_SET; + +typedef struct _KSEVENT_ENTRY KSEVENT_ENTRY, *PKSEVENT_ENTRY; +typedef NTSTATUS (*PFNKSADDEVENT)(PIRP Irp, PKSEVENTDATA EventData, + struct _KSEVENT_ENTRY* EventEntry); +typedef VOID (*PFNKSREMOVEEVENT)(PFILE_OBJECT FileObject, + struct _KSEVENT_ENTRY* EventEntry); + +#define DEFINE_KSEVENT_TABLE(tablename) \ + const KSEVENT_ITEM tablename[] = + +#define DEFINE_KSEVENT_ITEM(EventId,DataInput,ExtraEntryData,AddHandler,RemoveHandler,SupportHandler)\ +{ \ + EventId, DataInput, ExtraEntryData, \ + AddHandler, RemoveHandler, SupportHandler \ +} + +typedef struct { + ULONG EventId; + ULONG DataInput; + ULONG ExtraEntryData; + PFNKSADDEVENT AddHandler; + PFNKSREMOVEEVENT RemoveHandler; + PFNKSHANDLER SupportHandler; +} KSEVENT_ITEM, *PKSEVENT_ITEM; + +#define DEFINE_KSEVENT_SET(Set,EventsCount,EventItem) \ +{ \ + Set, EventsCount, EventItem \ +} + +#define DEFINE_KSEVENT_SET_TABLE(tablename) \ + const KSEVENT_SET tablename[] = + +typedef struct { + const GUID *Set; + ULONG EventsCount; + const KSEVENT_ITEM *EventItem; +} KSEVENT_SET, *PKSEVENT_SET; + +typedef struct { + KDPC Dpc; + ULONG ReferenceCount; + KSPIN_LOCK AccessLock; +} KSDPC_ITEM, *PKSDPC_ITEM; + +typedef struct { + KSDPC_ITEM DpcItem; + LIST_ENTRY BufferList; +} KSBUFFER_ITEM, *PKSBUFFER_ITEM; + + +#define KSEVENT_ENTRY_DELETED 1 +#define KSEVENT_ENTRY_ONESHOT 2 +#define KSEVENT_ENTRY_BUFFERED 4 + +struct _KSEVENT_ENTRY { + LIST_ENTRY ListEntry; + PVOID Object; + __MINGW_EXTENSION union { + PKSDPC_ITEM DpcItem; + PKSBUFFER_ITEM BufferItem; + }; + PKSEVENTDATA EventData; + ULONG NotificationType; + const KSEVENT_SET *EventSet; + const KSEVENT_ITEM *EventItem; + PFILE_OBJECT FileObject; + ULONG SemaphoreAdjustment; + ULONG Reserved; + ULONG Flags; +}; + +typedef enum { + KSEVENTS_NONE, + KSEVENTS_SPINLOCK, + KSEVENTS_MUTEX, + KSEVENTS_FMUTEX, + KSEVENTS_FMUTEXUNSAFE, + KSEVENTS_INTERRUPT, + KSEVENTS_ERESOURCE +} KSEVENTS_LOCKTYPE; + +#define KSDISPATCH_FASTIO 0x80000000 + +typedef struct { + PDRIVER_DISPATCH Create; + PVOID Context; + UNICODE_STRING ObjectClass; + PSECURITY_DESCRIPTOR SecurityDescriptor; + ULONG Flags; +} KSOBJECT_CREATE_ITEM, *PKSOBJECT_CREATE_ITEM; + +typedef VOID (*PFNKSITEMFREECALLBACK)(PKSOBJECT_CREATE_ITEM CreateItem); + +#define KSCREATE_ITEM_SECURITYCHANGED 0x00000001 +#define KSCREATE_ITEM_WILDCARD 0x00000002 +#define KSCREATE_ITEM_NOPARAMETERS 0x00000004 +#define KSCREATE_ITEM_FREEONSTOP 0x00000008 + +#define DEFINE_KSCREATE_DISPATCH_TABLE( tablename ) \ + KSOBJECT_CREATE_ITEM tablename[] = + +#define DEFINE_KSCREATE_ITEM(DispatchCreate,TypeName,Context) \ +{ \ + (DispatchCreate), (PVOID)(Context), \ + { \ + sizeof(TypeName) - sizeof(UNICODE_NULL),\ + sizeof(TypeName), \ + (PWCHAR)(TypeName) \ + }, \ + NULL, 0 \ +} + +#define DEFINE_KSCREATE_ITEMEX(DispatchCreate,TypeName,Context,Flags) \ +{ \ + (DispatchCreate), \ + (PVOID)(Context), \ + { \ + sizeof(TypeName) - sizeof(UNICODE_NULL),\ + sizeof(TypeName), \ + (PWCHAR)(TypeName) \ + }, \ + NULL, (Flags) \ +} + +#define DEFINE_KSCREATE_ITEMNULL(DispatchCreate,Context) \ +{ \ + DispatchCreate, Context, \ + { \ + 0, 0, NULL, \ + }, \ + NULL, 0 \ +} + +typedef struct { + ULONG CreateItemsCount; + PKSOBJECT_CREATE_ITEM CreateItemsList; +} KSOBJECT_CREATE, *PKSOBJECT_CREATE; + +typedef struct { + PDRIVER_DISPATCH DeviceIoControl; + PDRIVER_DISPATCH Read; + PDRIVER_DISPATCH Write; + PDRIVER_DISPATCH Flush; + PDRIVER_DISPATCH Close; + PDRIVER_DISPATCH QuerySecurity; + PDRIVER_DISPATCH SetSecurity; + PFAST_IO_DEVICE_CONTROL FastDeviceIoControl; + PFAST_IO_READ FastRead; + PFAST_IO_WRITE FastWrite; +} KSDISPATCH_TABLE, *PKSDISPATCH_TABLE; + +#define DEFINE_KSDISPATCH_TABLE(tablename,DeviceIoControl,Read,Write,Flush,Close,QuerySecurity,SetSecurity,FastDeviceIoControl,FastRead,FastWrite)\ + const KSDISPATCH_TABLE tablename = \ + { \ + DeviceIoControl, \ + Read, \ + Write, \ + Flush, \ + Close, \ + QuerySecurity, \ + SetSecurity, \ + FastDeviceIoControl, \ + FastRead, \ + FastWrite, \ + } + +#define KSCREATE_ITEM_IRP_STORAGE(Irp) \ + (*(PKSOBJECT_CREATE_ITEM *)&(Irp)->Tail.Overlay.DriverContext[0]) +#define KSEVENT_SET_IRP_STORAGE(Irp) \ + (*(const KSEVENT_SET **)&(Irp)->Tail.Overlay.DriverContext[0]) +#define KSEVENT_ITEM_IRP_STORAGE(Irp) \ + (*(const KSEVENT_ITEM **)&(Irp)->Tail.Overlay.DriverContext[3]) +#define KSEVENT_ENTRY_IRP_STORAGE(Irp) \ + (*(PKSEVENT_ENTRY *)&(Irp)->Tail.Overlay.DriverContext[0]) +#define KSMETHOD_SET_IRP_STORAGE(Irp) \ + (*(const KSMETHOD_SET **)&(Irp)->Tail.Overlay.DriverContext[0]) +#define KSMETHOD_ITEM_IRP_STORAGE(Irp) \ + (*(const KSMETHOD_ITEM **)&(Irp)->Tail.Overlay.DriverContext[3]) +#define KSMETHOD_TYPE_IRP_STORAGE(Irp) \ + (*(ULONG_PTR *)(&(Irp)->Tail.Overlay.DriverContext[2])) +#define KSQUEUE_SPINLOCK_IRP_STORAGE(Irp) \ + (*(PKSPIN_LOCK *)&(Irp)->Tail.Overlay.DriverContext[1]) +#define KSPROPERTY_SET_IRP_STORAGE(Irp) \ + (*(const KSPROPERTY_SET **)&(Irp)->Tail.Overlay.DriverContext[0]) +#define KSPROPERTY_ITEM_IRP_STORAGE(Irp) \ + (*(const KSPROPERTY_ITEM **)&(Irp)->Tail.Overlay.DriverContext[3]) +#define KSPROPERTY_ATTRIBUTES_IRP_STORAGE(Irp) \ + (*(PKSATTRIBUTE_LIST *)&(Irp)->Tail.Overlay.DriverContext[2]) + +typedef PVOID KSDEVICE_HEADER, KSOBJECT_HEADER; + +typedef enum { + KsInvokeOnSuccess = 1, + KsInvokeOnError = 2, + KsInvokeOnCancel = 4 +} KSCOMPLETION_INVOCATION; + +typedef enum { + KsListEntryTail, + KsListEntryHead +} KSLIST_ENTRY_LOCATION; + +typedef enum { + KsAcquireOnly, + KsAcquireAndRemove, + KsAcquireOnlySingleItem, + KsAcquireAndRemoveOnlySingleItem +} KSIRP_REMOVAL_OPERATION; + +typedef enum { + KsStackCopyToNewLocation, + KsStackReuseCurrentLocation, + KsStackUseNewLocation +} KSSTACK_USE; + +typedef enum { + KSTARGET_STATE_DISABLED, + KSTARGET_STATE_ENABLED +} KSTARGET_STATE; + +typedef NTSTATUS (*PFNKSIRPLISTCALLBACK)(PIRP Irp, PVOID Context); +typedef VOID (*PFNREFERENCEDEVICEOBJECT)(PVOID Context); +typedef VOID (*PFNDEREFERENCEDEVICEOBJECT)(PVOID Context); +typedef NTSTATUS (*PFNQUERYREFERENCESTRING)(PVOID Context, PWCHAR *String); + +#define BUS_INTERFACE_REFERENCE_VERSION 0x100 + +typedef struct { + INTERFACE Interface; + + PFNREFERENCEDEVICEOBJECT ReferenceDeviceObject; + PFNDEREFERENCEDEVICEOBJECT DereferenceDeviceObject; + PFNQUERYREFERENCESTRING QueryReferenceString; +} BUS_INTERFACE_REFERENCE, *PBUS_INTERFACE_REFERENCE; + +#define STATIC_REFERENCE_BUS_INTERFACE STATIC_KSMEDIUMSETID_Standard +#define REFERENCE_BUS_INTERFACE KSMEDIUMSETID_Standard + +#endif /* _NTDDK_ */ + +#ifndef PACK_PRAGMAS_NOT_SUPPORTED +#include +#endif + +typedef struct { + GUID PropertySet; + ULONG Count; +} KSPROPERTY_SERIALHDR,*PKSPROPERTY_SERIALHDR; + +#ifndef PACK_PRAGMAS_NOT_SUPPORTED +#include +#endif + +typedef struct { + KSIDENTIFIER PropTypeSet; + ULONG Id; + ULONG PropertyLength; +} KSPROPERTY_SERIAL,*PKSPROPERTY_SERIAL; + + +#if defined(_NTDDK_) + +#define IOCTL_KS_HANDSHAKE \ + CTL_CODE(FILE_DEVICE_KS, 0x007, METHOD_NEITHER, FILE_ANY_ACCESS) + +typedef struct { + GUID ProtocolId; + PVOID Argument1; + PVOID Argument2; +} KSHANDSHAKE, *PKSHANDSHAKE; + +typedef struct _KSGATE KSGATE, *PKSGATE; + +struct _KSGATE { + LONG Count; + PKSGATE NextGate; +}; + +typedef PVOID KSOBJECT_BAG; + + +typedef BOOLEAN (*PFNKSGENERATEEVENTCALLBACK)(PVOID Context, + PKSEVENT_ENTRY EventEntry); + +typedef NTSTATUS (*PFNKSDEVICECREATE)(PKSDEVICE Device); + +typedef NTSTATUS (*PFNKSDEVICEPNPSTART)(PKSDEVICE Device,PIRP Irp, + PCM_RESOURCE_LIST TranslatedResourceList, + PCM_RESOURCE_LIST UntranslatedResourceList); + +typedef NTSTATUS (*PFNKSDEVICE)(PKSDEVICE Device); + +typedef NTSTATUS (*PFNKSDEVICEIRP)(PKSDEVICE Device,PIRP Irp); + +typedef void (*PFNKSDEVICEIRPVOID)(PKSDEVICE Device,PIRP Irp); + +typedef NTSTATUS (*PFNKSDEVICEQUERYCAPABILITIES)(PKSDEVICE Device,PIRP Irp, + PDEVICE_CAPABILITIES Capabilities); + +typedef NTSTATUS (*PFNKSDEVICEQUERYPOWER)(PKSDEVICE Device,PIRP Irp, + DEVICE_POWER_STATE DeviceTo, + DEVICE_POWER_STATE DeviceFrom, + SYSTEM_POWER_STATE SystemTo, + SYSTEM_POWER_STATE SystemFrom, + POWER_ACTION Action); + +typedef void (*PFNKSDEVICESETPOWER)(PKSDEVICE Device,PIRP Irp, + DEVICE_POWER_STATE To, + DEVICE_POWER_STATE From); + +typedef NTSTATUS (*PFNKSFILTERFACTORYVOID)(PKSFILTERFACTORY FilterFactory); + +typedef void (*PFNKSFILTERFACTORYPOWER)(PKSFILTERFACTORY FilterFactory, + DEVICE_POWER_STATE State); + +typedef NTSTATUS (*PFNKSFILTERIRP)(PKSFILTER Filter,PIRP Irp); + +typedef NTSTATUS (*PFNKSFILTERPROCESS)(PKSFILTER Filter, + PKSPROCESSPIN_INDEXENTRY Index); + +typedef NTSTATUS (*PFNKSFILTERVOID)(PKSFILTER Filter); + +typedef void (*PFNKSFILTERPOWER)(PKSFILTER Filter,DEVICE_POWER_STATE State); + +typedef NTSTATUS (*PFNKSPINIRP)(PKSPIN Pin,PIRP Irp); + +typedef NTSTATUS (*PFNKSPINSETDEVICESTATE)(PKSPIN Pin,KSSTATE ToState, + KSSTATE FromState); + +typedef NTSTATUS (*PFNKSPINSETDATAFORMAT)(PKSPIN Pin,PKSDATAFORMAT OldFormat, + PKSMULTIPLE_ITEM OldAttributeList, + const KSDATARANGE *DataRange, + const KSATTRIBUTE_LIST *AttributeRange); + +typedef NTSTATUS (*PFNKSPINHANDSHAKE)(PKSPIN Pin,PKSHANDSHAKE In, + PKSHANDSHAKE Out); + +typedef NTSTATUS (*PFNKSPIN)(PKSPIN Pin); + +typedef void (*PFNKSPINVOID)(PKSPIN Pin); + +typedef void (*PFNKSPINPOWER)(PKSPIN Pin,DEVICE_POWER_STATE State); + +typedef BOOLEAN (*PFNKSPINSETTIMER)(PKSPIN Pin,PKTIMER Timer, + LARGE_INTEGER DueTime,PKDPC Dpc); + +typedef BOOLEAN (*PFNKSPINCANCELTIMER)(PKSPIN Pin,PKTIMER Timer); + +typedef LONGLONG (FASTCALL *PFNKSPINCORRELATEDTIME)(PKSPIN Pin, + PLONGLONG SystemTime); + +typedef void (*PFNKSPINRESOLUTION)(PKSPIN Pin,PKSRESOLUTION Resolution); + +typedef NTSTATUS (*PFNKSPININITIALIZEALLOCATOR)(PKSPIN Pin, + PKSALLOCATOR_FRAMING AllocatorFraming, + PVOID *Context); + +typedef void (*PFNKSSTREAMPOINTER)(PKSSTREAM_POINTER StreamPointer); + + +typedef struct KSAUTOMATION_TABLE_ KSAUTOMATION_TABLE,*PKSAUTOMATION_TABLE; + +struct KSAUTOMATION_TABLE_ { + ULONG PropertySetsCount; + ULONG PropertyItemSize; + const KSPROPERTY_SET *PropertySets; + ULONG MethodSetsCount; + ULONG MethodItemSize; + const KSMETHOD_SET *MethodSets; + ULONG EventSetsCount; + ULONG EventItemSize; + const KSEVENT_SET *EventSets; +#ifndef _WIN64 + PVOID Alignment; +#endif +}; + +#define DEFINE_KSAUTOMATION_TABLE(table) \ + const KSAUTOMATION_TABLE table = + +#define DEFINE_KSAUTOMATION_PROPERTIES(table) \ + SIZEOF_ARRAY(table), \ + sizeof(KSPROPERTY_ITEM), \ + table + +#define DEFINE_KSAUTOMATION_METHODS(table) \ + SIZEOF_ARRAY(table), \ + sizeof(KSMETHOD_ITEM), \ + table + +#define DEFINE_KSAUTOMATION_EVENTS(table) \ + SIZEOF_ARRAY(table), \ + sizeof(KSEVENT_ITEM), \ + table + +#define DEFINE_KSAUTOMATION_PROPERTIES_NULL \ + 0, \ + sizeof(KSPROPERTY_ITEM), \ + NULL + +#define DEFINE_KSAUTOMATION_METHODS_NULL \ + 0, \ + sizeof(KSMETHOD_ITEM), \ + NULL + +#define DEFINE_KSAUTOMATION_EVENTS_NULL \ + 0, \ + sizeof(KSEVENT_ITEM), \ + NULL + +#define MIN_DEV_VER_FOR_QI (0x100) + +struct _KSDEVICE_DISPATCH { + PFNKSDEVICECREATE Add; + PFNKSDEVICEPNPSTART Start; + PFNKSDEVICE PostStart; + PFNKSDEVICEIRP QueryStop; + PFNKSDEVICEIRPVOID CancelStop; + PFNKSDEVICEIRPVOID Stop; + PFNKSDEVICEIRP QueryRemove; + PFNKSDEVICEIRPVOID CancelRemove; + PFNKSDEVICEIRPVOID Remove; + PFNKSDEVICEQUERYCAPABILITIES QueryCapabilities; + PFNKSDEVICEIRPVOID SurpriseRemoval; + PFNKSDEVICEQUERYPOWER QueryPower; + PFNKSDEVICESETPOWER SetPower; + PFNKSDEVICEIRP QueryInterface; +}; + +struct _KSFILTER_DISPATCH { + PFNKSFILTERIRP Create; + PFNKSFILTERIRP Close; + PFNKSFILTERPROCESS Process; + PFNKSFILTERVOID Reset; +}; + +struct _KSPIN_DISPATCH { + PFNKSPINIRP Create; + PFNKSPINIRP Close; + PFNKSPIN Process; + PFNKSPINVOID Reset; + PFNKSPINSETDATAFORMAT SetDataFormat; + PFNKSPINSETDEVICESTATE SetDeviceState; + PFNKSPIN Connect; + PFNKSPINVOID Disconnect; + const KSCLOCK_DISPATCH *Clock; + const KSALLOCATOR_DISPATCH *Allocator; +}; + +struct _KSCLOCK_DISPATCH { + PFNKSPINSETTIMER SetTimer; + PFNKSPINCANCELTIMER CancelTimer; + PFNKSPINCORRELATEDTIME CorrelatedTime; + PFNKSPINRESOLUTION Resolution; +}; + +struct _KSALLOCATOR_DISPATCH { + PFNKSPININITIALIZEALLOCATOR InitializeAllocator; + PFNKSDELETEALLOCATOR DeleteAllocator; + PFNKSDEFAULTALLOCATE Allocate; + PFNKSDEFAULTFREE Free; +}; + +#define KSDEVICE_DESCRIPTOR_VERSION (0x100) + +struct _KSDEVICE_DESCRIPTOR { + const KSDEVICE_DISPATCH *Dispatch; + ULONG FilterDescriptorsCount; + const KSFILTER_DESCRIPTOR*const *FilterDescriptors; + ULONG Version; +}; + +struct _KSFILTER_DESCRIPTOR { + const KSFILTER_DISPATCH *Dispatch; + const KSAUTOMATION_TABLE *AutomationTable; + ULONG Version; +#define KSFILTER_DESCRIPTOR_VERSION ((ULONG)-1) + ULONG Flags; +#define KSFILTER_FLAG_DISPATCH_LEVEL_PROCESSING 0x00000001 +#define KSFILTER_FLAG_CRITICAL_PROCESSING 0x00000002 +#define KSFILTER_FLAG_HYPERCRITICAL_PROCESSING 0x00000004 +#define KSFILTER_FLAG_RECEIVE_ZERO_LENGTH_SAMPLES 0x00000008 +#define KSFILTER_FLAG_DENY_USERMODE_ACCESS 0x80000000 + const GUID *ReferenceGuid; + ULONG PinDescriptorsCount; + ULONG PinDescriptorSize; + const KSPIN_DESCRIPTOR_EX *PinDescriptors; + ULONG CategoriesCount; + const GUID *Categories; + ULONG NodeDescriptorsCount; + ULONG NodeDescriptorSize; + const KSNODE_DESCRIPTOR *NodeDescriptors; + ULONG ConnectionsCount; + const KSTOPOLOGY_CONNECTION *Connections; + const KSCOMPONENTID *ComponentId; +}; + +#define DEFINE_KSFILTER_DESCRIPTOR(descriptor) \ + const KSFILTER_DESCRIPTOR descriptor = + +#define DEFINE_KSFILTER_PIN_DESCRIPTORS(table) \ + SIZEOF_ARRAY(table), \ + sizeof(table[0]), \ + table + +#define DEFINE_KSFILTER_CATEGORIES(table) \ + SIZEOF_ARRAY(table), \ + table + +#define DEFINE_KSFILTER_CATEGORY(category) \ + 1, \ + &(category) + +#define DEFINE_KSFILTER_CATEGORIES_NULL \ + 0, \ + NULL + +#define DEFINE_KSFILTER_NODE_DESCRIPTORS(table) \ + SIZEOF_ARRAY(table), \ + sizeof(table[0]), \ + table + +#define DEFINE_KSFILTER_NODE_DESCRIPTORS_NULL \ + 0, \ + sizeof(KSNODE_DESCRIPTOR), \ + NULL + +#define DEFINE_KSFILTER_CONNECTIONS(table) \ + SIZEOF_ARRAY(table), \ + table + +#define DEFINE_KSFILTER_DEFAULT_CONNECTIONS \ + 0, \ + NULL + +#define DEFINE_KSFILTER_DESCRIPTOR_TABLE(table) \ + const KSFILTER_DESCRIPTOR*const table[] = + +struct _KSPIN_DESCRIPTOR_EX { + const KSPIN_DISPATCH *Dispatch; + const KSAUTOMATION_TABLE *AutomationTable; + KSPIN_DESCRIPTOR PinDescriptor; + ULONG Flags; +#define KSPIN_FLAG_DISPATCH_LEVEL_PROCESSING KSFILTER_FLAG_DISPATCH_LEVEL_PROCESSING +#define KSPIN_FLAG_CRITICAL_PROCESSING KSFILTER_FLAG_CRITICAL_PROCESSING +#define KSPIN_FLAG_HYPERCRITICAL_PROCESSING KSFILTER_FLAG_HYPERCRITICAL_PROCESSING +#define KSPIN_FLAG_ASYNCHRONOUS_PROCESSING 0x00000008 +#define KSPIN_FLAG_DO_NOT_INITIATE_PROCESSING 0x00000010 +#define KSPIN_FLAG_INITIATE_PROCESSING_ON_EVERY_ARRIVAL 0x00000020 +#define KSPIN_FLAG_FRAMES_NOT_REQUIRED_FOR_PROCESSING 0x00000040 +#define KSPIN_FLAG_ENFORCE_FIFO 0x00000080 +#define KSPIN_FLAG_GENERATE_MAPPINGS 0x00000100 +#define KSPIN_FLAG_DISTINCT_TRAILING_EDGE 0x00000200 +#define KSPIN_FLAG_PROCESS_IN_RUN_STATE_ONLY 0x00010000 +#define KSPIN_FLAG_SPLITTER 0x00020000 +#define KSPIN_FLAG_USE_STANDARD_TRANSPORT 0x00040000 +#define KSPIN_FLAG_DO_NOT_USE_STANDARD_TRANSPORT 0x00080000 +#define KSPIN_FLAG_FIXED_FORMAT 0x00100000 +#define KSPIN_FLAG_GENERATE_EOS_EVENTS 0x00200000 +#define KSPIN_FLAG_RENDERER (KSPIN_FLAG_PROCESS_IN_RUN_STATE_ONLY|KSPIN_FLAG_GENERATE_EOS_EVENTS) +#define KSPIN_FLAG_IMPLEMENT_CLOCK 0x00400000 +#define KSPIN_FLAG_SOME_FRAMES_REQUIRED_FOR_PROCESSING 0x00800000 +#define KSPIN_FLAG_PROCESS_IF_ANY_IN_RUN_STATE 0x01000000 +#define KSPIN_FLAG_DENY_USERMODE_ACCESS 0x80000000 + ULONG InstancesPossible; + ULONG InstancesNecessary; + const KSALLOCATOR_FRAMING_EX *AllocatorFraming; + PFNKSINTERSECTHANDLEREX IntersectHandler; +}; + +#define DEFINE_KSPIN_DEFAULT_INTERFACES \ + 0, \ + NULL + +#define DEFINE_KSPIN_DEFAULT_MEDIUMS \ + 0, \ + NULL + +struct _KSNODE_DESCRIPTOR { + const KSAUTOMATION_TABLE *AutomationTable; + const GUID *Type; + const GUID *Name; +#ifndef _WIN64 + PVOID Alignment; +#endif +}; + +#ifndef _WIN64 +#define DEFINE_NODE_DESCRIPTOR(automation,type,name) \ + { (automation), (type), (name), NULL } +#else +#define DEFINE_NODE_DESCRIPTOR(automation,type,name) \ + { (automation), (type), (name) } +#endif + +struct _KSDEVICE { + const KSDEVICE_DESCRIPTOR *Descriptor; + KSOBJECT_BAG Bag; + PVOID Context; + PDEVICE_OBJECT FunctionalDeviceObject; + PDEVICE_OBJECT PhysicalDeviceObject; + PDEVICE_OBJECT NextDeviceObject; + BOOLEAN Started; + SYSTEM_POWER_STATE SystemPowerState; + DEVICE_POWER_STATE DevicePowerState; +}; + +struct _KSFILTERFACTORY { + const KSFILTER_DESCRIPTOR *FilterDescriptor; + KSOBJECT_BAG Bag; + PVOID Context; +}; + +struct _KSFILTER { + const KSFILTER_DESCRIPTOR *Descriptor; + KSOBJECT_BAG Bag; + PVOID Context; +}; + +struct _KSPIN { + const KSPIN_DESCRIPTOR_EX *Descriptor; + KSOBJECT_BAG Bag; + PVOID Context; + ULONG Id; + KSPIN_COMMUNICATION Communication; + BOOLEAN ConnectionIsExternal; + KSPIN_INTERFACE ConnectionInterface; + KSPIN_MEDIUM ConnectionMedium; + KSPRIORITY ConnectionPriority; + PKSDATAFORMAT ConnectionFormat; + PKSMULTIPLE_ITEM AttributeList; + ULONG StreamHeaderSize; + KSPIN_DATAFLOW DataFlow; + KSSTATE DeviceState; + KSRESET ResetState; + KSSTATE ClientState; +}; + +struct _KSMAPPING { + PHYSICAL_ADDRESS PhysicalAddress; + ULONG ByteCount; + ULONG Alignment; +}; + +struct _KSSTREAM_POINTER_OFFSET +{ +#if defined(_NTDDK_) + __MINGW_EXTENSION union { + PUCHAR Data; + PKSMAPPING Mappings; + }; +#else + PUCHAR Data; +#endif /* _NTDDK_ */ +#ifndef _WIN64 + PVOID Alignment; +#endif + ULONG Count; + ULONG Remaining; +}; + +struct _KSSTREAM_POINTER +{ + PVOID Context; + PKSPIN Pin; + PKSSTREAM_HEADER StreamHeader; + PKSSTREAM_POINTER_OFFSET Offset; + KSSTREAM_POINTER_OFFSET OffsetIn; + KSSTREAM_POINTER_OFFSET OffsetOut; +}; + +struct _KSPROCESSPIN { + PKSPIN Pin; + PKSSTREAM_POINTER StreamPointer; + PKSPROCESSPIN InPlaceCounterpart; + PKSPROCESSPIN DelegateBranch; + PKSPROCESSPIN CopySource; + PVOID Data; + ULONG BytesAvailable; + ULONG BytesUsed; + ULONG Flags; + BOOLEAN Terminate; +}; + +struct _KSPROCESSPIN_INDEXENTRY { + PKSPROCESSPIN *Pins; + ULONG Count; +}; + +typedef enum { + KsObjectTypeDevice, + KsObjectTypeFilterFactory, + KsObjectTypeFilter, + KsObjectTypePin +} KSOBJECTTYPE; + + +typedef void (*PFNKSFREE)(PVOID Data); + +typedef void (*PFNKSPINFRAMERETURN)(PKSPIN Pin,PVOID Data,ULONG Size,PMDL Mdl, + PVOID Context,NTSTATUS Status); + +typedef void (*PFNKSPINIRPCOMPLETION)(PKSPIN Pin,PIRP Irp); + + +#if defined(_UNKNOWN_H_) || defined(__IUnknown_INTERFACE_DEFINED__) +#ifndef _IKsControl_ +#define _IKsControl_ + +typedef struct IKsControl *PIKSCONTROL; + +#ifndef DEFINE_ABSTRACT_UNKNOWN +#define DEFINE_ABSTRACT_UNKNOWN() \ + STDMETHOD_(NTSTATUS,QueryInterface) (THIS_ \ + REFIID InterfaceId, \ + PVOID *Interface \ + ) PURE; \ + STDMETHOD_(ULONG,AddRef)(THIS) PURE; \ + STDMETHOD_(ULONG,Release)(THIS) PURE; +#endif + +#undef INTERFACE +#define INTERFACE IKsControl +DECLARE_INTERFACE_(IKsControl,IUnknown) +{ + DEFINE_ABSTRACT_UNKNOWN() + STDMETHOD_(NTSTATUS,KsProperty)(THIS_ + PKSPROPERTY Property, + ULONG PropertyLength, + PVOID PropertyData, + ULONG DataLength, + ULONG *BytesReturned + ) PURE; + STDMETHOD_(NTSTATUS,KsMethod) (THIS_ + PKSMETHOD Method, + ULONG MethodLength, + PVOID MethodData, + ULONG DataLength, + ULONG *BytesReturned + ) PURE; + STDMETHOD_(NTSTATUS,KsEvent) (THIS_ + PKSEVENT Event, + ULONG EventLength, + PVOID EventData, + ULONG DataLength, + ULONG *BytesReturned + ) PURE; +}; +typedef struct IKsReferenceClock *PIKSREFERENCECLOCK; + +#undef INTERFACE +#define INTERFACE IKsReferenceClock +DECLARE_INTERFACE_(IKsReferenceClock,IUnknown) +{ + DEFINE_ABSTRACT_UNKNOWN() + STDMETHOD_(LONGLONG,GetTime) (THIS) PURE; + STDMETHOD_(LONGLONG,GetPhysicalTime) (THIS) PURE; + STDMETHOD_(LONGLONG,GetCorrelatedTime)(THIS_ + PLONGLONG SystemTime + ) PURE; + STDMETHOD_(LONGLONG,GetCorrelatedPhysicalTime)(THIS_ + PLONGLONG SystemTime + ) PURE; + STDMETHOD_(NTSTATUS,GetResolution) (THIS_ + PKSRESOLUTION Resolution + ) PURE; + STDMETHOD_(NTSTATUS,GetState) (THIS_ + PKSSTATE State + ) PURE; +}; +#undef INTERFACE + +#define INTERFACE IKsDeviceFunctions +DECLARE_INTERFACE_(IKsDeviceFunctions,IUnknown) +{ + DEFINE_ABSTRACT_UNKNOWN() + STDMETHOD_(NTSTATUS,RegisterAdapterObjectEx) (THIS_ + PADAPTER_OBJECT AdapterObject, + PDEVICE_DESCRIPTION DeviceDescription, + ULONG NumberOfMapRegisters, + ULONG MaxMappingsByteCount, + ULONG MappingTableStride + ) PURE; +}; + +#undef INTERFACE +#define STATIC_IID_IKsControl \ + 0x28F54685L,0x06FD,0x11D2,0xB2,0x7A,0x00,0xA0,0xC9,0x22,0x31,0x96 +DEFINE_GUID(IID_IKsControl, + 0x28F54685L,0x06FD,0x11D2,0xB2,0x7A,0x00,0xA0,0xC9,0x22,0x31,0x96); +#define STATIC_IID_IKsFastClock \ + 0xc9902485,0xc180,0x11d2,0x84,0x73,0xd4,0x23,0x94,0x45,0x9e,0x5e +DEFINE_GUID(IID_IKsFastClock, + 0xc9902485,0xc180,0x11d2,0x84,0x73,0xd4,0x23,0x94,0x45,0x9e,0x5e); +#define STATIC_IID_IKsDeviceFunctions \ + 0xe234f2e2,0xbd69,0x4f8c,0xb3,0xf2,0x7c,0xd7,0x9e,0xd4,0x66,0xbd +DEFINE_GUID(IID_IKsDeviceFunctions, + 0xe234f2e2,0xbd69,0x4f8c,0xb3,0xf2,0x7c,0xd7,0x9e,0xd4,0x66,0xbd); +#endif /* _IKsControl_ */ +#endif /* defined(_UNKNOWN_H_) || defined(__IUnknown_INTERFACE_DEFINED__) */ + +#endif /* _NTDDK_ */ + + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef _KSDDK_ +#define KSDDKAPI +#else +#define KSDDKAPI DECLSPEC_IMPORT +#endif + +#if defined(_NTDDK_) + +KSDDKAPI NTSTATUS NTAPI KsEnableEvent + (PIRP Irp, ULONG EventSetsCount, const KSEVENT_SET *EventSet, + PLIST_ENTRY EventsList, KSEVENTS_LOCKTYPE EventsFlags, + PVOID EventsLock); + +KSDDKAPI NTSTATUS NTAPI KsEnableEventWithAllocator + (PIRP Irp, ULONG EventSetsCount, const KSEVENT_SET *EventSet, + PLIST_ENTRY EventsList, KSEVENTS_LOCKTYPE EventsFlags, + PVOID EventsLock, PFNKSALLOCATOR Allocator, ULONG EventItemSize); + +KSDDKAPI NTSTATUS NTAPI KsDisableEvent + (PIRP Irp, PLIST_ENTRY EventsList, KSEVENTS_LOCKTYPE EventsFlags, + PVOID EventsLock); + +KSDDKAPI VOID NTAPI KsDiscardEvent (PKSEVENT_ENTRY EventEntry); + +KSDDKAPI VOID NTAPI KsFreeEventList + (PFILE_OBJECT FileObject, PLIST_ENTRY EventsList, + KSEVENTS_LOCKTYPE EventsFlags, PVOID EventsLock); + +KSDDKAPI NTSTATUS NTAPI KsGenerateEvent (PKSEVENT_ENTRY EventEntry); + +KSDDKAPI NTSTATUS NTAPI KsGenerateDataEvent + (PKSEVENT_ENTRY EventEntry, ULONG DataSize, PVOID Data); + +KSDDKAPI VOID NTAPI KsGenerateEventList + (GUID *Set, ULONG EventId, PLIST_ENTRY EventsList, + KSEVENTS_LOCKTYPE EventsFlags, PVOID EventsLock); + +KSDDKAPI NTSTATUS NTAPI KsPropertyHandler + (PIRP Irp, ULONG PropertySetsCount, + const KSPROPERTY_SET *PropertySet); + +KSDDKAPI NTSTATUS NTAPI KsPropertyHandlerWithAllocator + (PIRP Irp, ULONG PropertySetsCount, + const KSPROPERTY_SET *PropertySet, PFNKSALLOCATOR Allocator, + ULONG PropertyItemSize); + +KSDDKAPI BOOLEAN NTAPI KsFastPropertyHandler + (PFILE_OBJECT FileObject, PKSPROPERTY Property, + ULONG PropertyLength, PVOID Data, ULONG DataLength, + PIO_STATUS_BLOCK IoStatus, ULONG PropertySetsCount, + const KSPROPERTY_SET *PropertySet); + +KSDDKAPI NTSTATUS NTAPI KsMethodHandler + (PIRP Irp, ULONG MethodSetsCount, + const KSMETHOD_SET *MethodSet); + +KSDDKAPI NTSTATUS NTAPI KsMethodHandlerWithAllocator + (PIRP Irp, ULONG MethodSetsCount, + const KSMETHOD_SET *MethodSet, PFNKSALLOCATOR Allocator, + ULONG MethodItemSize); + +KSDDKAPI BOOLEAN NTAPI KsFastMethodHandler + (PFILE_OBJECT FileObject, PKSMETHOD Method, ULONG MethodLength, + PVOID Data, ULONG DataLength, PIO_STATUS_BLOCK IoStatus, + ULONG MethodSetsCount, const KSMETHOD_SET *MethodSet); + +KSDDKAPI NTSTATUS NTAPI KsCreateDefaultAllocator (PIRP Irp); + +KSDDKAPI NTSTATUS NTAPI KsCreateDefaultAllocatorEx + (PIRP Irp, PVOID InitializeContext, + PFNKSDEFAULTALLOCATE DefaultAllocate, + PFNKSDEFAULTFREE DefaultFree, + PFNKSINITIALIZEALLOCATOR InitializeAllocator, + PFNKSDELETEALLOCATOR DeleteAllocator); + +KSDDKAPI NTSTATUS NTAPI KsCreateAllocator + (HANDLE ConnectionHandle, PKSALLOCATOR_FRAMING AllocatorFraming, + PHANDLE AllocatorHandle); + +KSDDKAPI NTSTATUS NTAPI KsValidateAllocatorCreateRequest + (PIRP Irp, PKSALLOCATOR_FRAMING *AllocatorFraming); + +KSDDKAPI NTSTATUS NTAPI KsValidateAllocatorFramingEx + (PKSALLOCATOR_FRAMING_EX Framing, ULONG BufferSize, + const KSALLOCATOR_FRAMING_EX *PinFraming); + +KSDDKAPI NTSTATUS NTAPI KsAllocateDefaultClock (PKSDEFAULTCLOCK *DefaultClock); + +KSDDKAPI NTSTATUS NTAPI KsAllocateDefaultClockEx + (PKSDEFAULTCLOCK *DefaultClock, PVOID Context, + PFNKSSETTIMER SetTimer, PFNKSCANCELTIMER CancelTimer, + PFNKSCORRELATEDTIME CorrelatedTime, + const KSRESOLUTION *Resolution, ULONG Flags); + +KSDDKAPI VOID NTAPI KsFreeDefaultClock (PKSDEFAULTCLOCK DefaultClock); +KSDDKAPI NTSTATUS NTAPI KsCreateDefaultClock (PIRP Irp, PKSDEFAULTCLOCK DefaultClock); + +KSDDKAPI NTSTATUS NTAPI KsCreateClock + (HANDLE ConnectionHandle, PKSCLOCK_CREATE ClockCreate, + PHANDLE ClockHandle); + +KSDDKAPI NTSTATUS NTAPI KsValidateClockCreateRequest + (PIRP Irp, PKSCLOCK_CREATE *ClockCreate); + +KSDDKAPI KSSTATE NTAPI KsGetDefaultClockState (PKSDEFAULTCLOCK DefaultClock); +KSDDKAPI VOID NTAPI KsSetDefaultClockState(PKSDEFAULTCLOCK DefaultClock, KSSTATE State); +KSDDKAPI LONGLONG NTAPI KsGetDefaultClockTime (PKSDEFAULTCLOCK DefaultClock); +KSDDKAPI VOID NTAPI KsSetDefaultClockTime(PKSDEFAULTCLOCK DefaultClock, LONGLONG Time); + +KSDDKAPI NTSTATUS NTAPI KsCreatePin + (HANDLE FilterHandle, PKSPIN_CONNECT Connect, + ACCESS_MASK DesiredAccess, PHANDLE ConnectionHandle); + +KSDDKAPI NTSTATUS NTAPI KsValidateConnectRequest + (PIRP Irp, ULONG DescriptorsCount, + const KSPIN_DESCRIPTOR *Descriptor, PKSPIN_CONNECT *Connect); + +KSDDKAPI NTSTATUS NTAPI KsPinPropertyHandler + (PIRP Irp, PKSPROPERTY Property, PVOID Data, + ULONG DescriptorsCount, const KSPIN_DESCRIPTOR *Descriptor); + +KSDDKAPI NTSTATUS NTAPI KsPinDataIntersection + (PIRP Irp, PKSP_PIN Pin, PVOID Data, ULONG DescriptorsCount, + const KSPIN_DESCRIPTOR *Descriptor, + PFNKSINTERSECTHANDLER IntersectHandler); + +KSDDKAPI NTSTATUS NTAPI KsPinDataIntersectionEx + (PIRP Irp, PKSP_PIN Pin, PVOID Data, ULONG DescriptorsCount, + const KSPIN_DESCRIPTOR *Descriptor, ULONG DescriptorSize, + PFNKSINTERSECTHANDLEREX IntersectHandler, PVOID HandlerContext); + +KSDDKAPI NTSTATUS NTAPI KsHandleSizedListQuery + (PIRP Irp, ULONG DataItemsCount, ULONG DataItemSize, + const VOID *DataItems); + +#ifndef MAKEINTRESOURCE +#define MAKEINTRESOURCE(r) ((ULONG_PTR) (USHORT) r) +#endif +#ifndef RT_STRING +#define RT_STRING MAKEINTRESOURCE(6) +#define RT_RCDATA MAKEINTRESOURCE(10) +#endif + +KSDDKAPI NTSTATUS NTAPI KsLoadResource + (PVOID ImageBase, POOL_TYPE PoolType, ULONG_PTR ResourceName, + ULONG ResourceType, PVOID *Resource, PULONG ResourceSize); + +KSDDKAPI NTSTATUS NTAPI KsGetImageNameAndResourceId + (HANDLE RegKey, PUNICODE_STRING ImageName, PULONG_PTR ResourceId, + PULONG ValueType); + +KSDDKAPI NTSTATUS NTAPI KsMapModuleName + (PDEVICE_OBJECT PhysicalDeviceObject, PUNICODE_STRING ModuleName, + PUNICODE_STRING ImageName, PULONG_PTR ResourceId, + PULONG ValueType); + +KSDDKAPI NTSTATUS NTAPI KsReferenceBusObject (KSDEVICE_HEADER Header); +KSDDKAPI VOID NTAPI KsDereferenceBusObject (KSDEVICE_HEADER Header); +KSDDKAPI NTSTATUS NTAPI KsDispatchQuerySecurity (PDEVICE_OBJECT DeviceObject, PIRP Irp); +KSDDKAPI NTSTATUS NTAPI KsDispatchSetSecurity (PDEVICE_OBJECT DeviceObject, PIRP Irp); +KSDDKAPI NTSTATUS NTAPI KsDispatchSpecificProperty (PIRP Irp, PFNKSHANDLER Handler); +KSDDKAPI NTSTATUS NTAPI KsDispatchSpecificMethod (PIRP Irp, PFNKSHANDLER Handler); + +KSDDKAPI NTSTATUS NTAPI KsReadFile + (PFILE_OBJECT FileObject, PKEVENT Event, PVOID PortContext, + PIO_STATUS_BLOCK IoStatusBlock, PVOID Buffer, ULONG Length, + ULONG Key, KPROCESSOR_MODE RequestorMode); + +KSDDKAPI NTSTATUS NTAPI KsWriteFile + (PFILE_OBJECT FileObject, PKEVENT Event, PVOID PortContext, + PIO_STATUS_BLOCK IoStatusBlock, PVOID Buffer, ULONG Length, + ULONG Key, KPROCESSOR_MODE RequestorMode); + +KSDDKAPI NTSTATUS NTAPI KsQueryInformationFile + (PFILE_OBJECT FileObject, PVOID FileInformation, ULONG Length, + FILE_INFORMATION_CLASS FileInformationClass); + +KSDDKAPI NTSTATUS NTAPI KsSetInformationFile + (PFILE_OBJECT FileObject, PVOID FileInformation, ULONG Length, + FILE_INFORMATION_CLASS FileInformationClass); + +KSDDKAPI NTSTATUS NTAPI KsStreamIo + (PFILE_OBJECT FileObject, PKEVENT Event, PVOID PortContext, + PIO_COMPLETION_ROUTINE CompletionRoutine, PVOID CompletionContext, + KSCOMPLETION_INVOCATION CompletionInvocationFlags, + PIO_STATUS_BLOCK IoStatusBlock, PVOID StreamHeaders, ULONG Length, + ULONG Flags, KPROCESSOR_MODE RequestorMode); + +KSDDKAPI NTSTATUS NTAPI KsProbeStreamIrp(PIRP Irp, ULONG ProbeFlags, ULONG HeaderSize); +KSDDKAPI NTSTATUS NTAPI KsAllocateExtraData(PIRP Irp, ULONG ExtraSize, PVOID *ExtraBuffer); +KSDDKAPI VOID NTAPI KsNullDriverUnload (PDRIVER_OBJECT DriverObject); + +KSDDKAPI NTSTATUS NTAPI KsSetMajorFunctionHandler + (PDRIVER_OBJECT DriverObject, ULONG MajorFunction); + +KSDDKAPI NTSTATUS NTAPI KsDispatchInvalidDeviceRequest + (PDEVICE_OBJECT DeviceObject, PIRP Irp); + +KSDDKAPI NTSTATUS NTAPI KsDefaultDeviceIoCompletion + (PDEVICE_OBJECT DeviceObject, PIRP Irp); + +KSDDKAPI NTSTATUS NTAPI KsDispatchIrp(PDEVICE_OBJECT DeviceObject, PIRP Irp); + +KSDDKAPI BOOLEAN NTAPI KsDispatchFastIoDeviceControlFailure + (PFILE_OBJECT FileObject, BOOLEAN Wait, PVOID InputBuffer, + ULONG InputBufferLength, PVOID OutputBuffer, + ULONG OutputBufferLength, ULONG IoControlCode, + PIO_STATUS_BLOCK IoStatus, PDEVICE_OBJECT DeviceObject); + +KSDDKAPI BOOLEAN NTAPI KsDispatchFastReadFailure + (PFILE_OBJECT FileObject, PLARGE_INTEGER FileOffset, + ULONG Length, BOOLEAN Wait, ULONG LockKey, PVOID Buffer, + PIO_STATUS_BLOCK IoStatus, PDEVICE_OBJECT DeviceObject); + +#define KsDispatchFastWriteFailure KsDispatchFastReadFailure + +KSDDKAPI VOID NTAPI KsCancelRoutine(PDEVICE_OBJECT DeviceObject, PIRP Irp); +KSDDKAPI VOID NTAPI KsCancelIo(PLIST_ENTRY QueueHead, PKSPIN_LOCK SpinLock); +KSDDKAPI VOID NTAPI KsReleaseIrpOnCancelableQueue(PIRP Irp, PDRIVER_CANCEL DriverCancel); + +KSDDKAPI PIRP NTAPI KsRemoveIrpFromCancelableQueue + (PLIST_ENTRY QueueHead, PKSPIN_LOCK SpinLock, + KSLIST_ENTRY_LOCATION ListLocation, + KSIRP_REMOVAL_OPERATION RemovalOperation); + +KSDDKAPI NTSTATUS NTAPI KsMoveIrpsOnCancelableQueue + (PLIST_ENTRY SourceList, PKSPIN_LOCK SourceLock, + PLIST_ENTRY DestinationList, PKSPIN_LOCK DestinationLock, + KSLIST_ENTRY_LOCATION ListLocation, + PFNKSIRPLISTCALLBACK ListCallback, PVOID Context); + +KSDDKAPI VOID NTAPI KsRemoveSpecificIrpFromCancelableQueue (PIRP Irp); + +KSDDKAPI VOID NTAPI KsAddIrpToCancelableQueue + (PLIST_ENTRY QueueHead, PKSPIN_LOCK SpinLock, PIRP Irp, + KSLIST_ENTRY_LOCATION ListLocation, PDRIVER_CANCEL DriverCancel); + +KSDDKAPI NTSTATUS NTAPI KsAcquireResetValue(PIRP Irp, KSRESET *ResetValue); + +KSDDKAPI NTSTATUS NTAPI KsTopologyPropertyHandler + (PIRP Irp, PKSPROPERTY Property, PVOID Data, + const KSTOPOLOGY *Topology); + +KSDDKAPI VOID NTAPI KsAcquireDeviceSecurityLock(KSDEVICE_HEADER Header, BOOLEAN Exclusive); +KSDDKAPI VOID NTAPI KsReleaseDeviceSecurityLock (KSDEVICE_HEADER Header); +KSDDKAPI NTSTATUS NTAPI KsDefaultDispatchPnp(PDEVICE_OBJECT DeviceObject, PIRP Irp); +KSDDKAPI NTSTATUS NTAPI KsDefaultDispatchPower(PDEVICE_OBJECT DeviceObject, PIRP Irp); +KSDDKAPI NTSTATUS NTAPI KsDefaultForwardIrp(PDEVICE_OBJECT DeviceObject, PIRP Irp); + +KSDDKAPI VOID NTAPI KsSetDevicePnpAndBaseObject + (KSDEVICE_HEADER Header, PDEVICE_OBJECT PnpDeviceObject, + PDEVICE_OBJECT BaseObject); + +KSDDKAPI PDEVICE_OBJECT NTAPI KsQueryDevicePnpObject (KSDEVICE_HEADER Header); +KSDDKAPI ACCESS_MASK NTAPI KsQueryObjectAccessMask (KSOBJECT_HEADER Header); + +KSDDKAPI VOID NTAPI KsRecalculateStackDepth + (KSDEVICE_HEADER Header, BOOLEAN ReuseStackLocation); + +KSDDKAPI VOID NTAPI KsSetTargetState + (KSOBJECT_HEADER Header, KSTARGET_STATE TargetState); + +KSDDKAPI VOID NTAPI KsSetTargetDeviceObject + (KSOBJECT_HEADER Header, PDEVICE_OBJECT TargetDevice); + +KSDDKAPI VOID NTAPI KsSetPowerDispatch + (KSOBJECT_HEADER Header, PFNKSCONTEXT_DISPATCH PowerDispatch, + PVOID PowerContext); + +KSDDKAPI PKSOBJECT_CREATE_ITEM NTAPI KsQueryObjectCreateItem (KSOBJECT_HEADER Header); + +KSDDKAPI NTSTATUS NTAPI KsAllocateDeviceHeader + (KSDEVICE_HEADER *Header, ULONG ItemsCount, + PKSOBJECT_CREATE_ITEM ItemsList); + +KSDDKAPI VOID NTAPI KsFreeDeviceHeader (KSDEVICE_HEADER Header); + +KSDDKAPI NTSTATUS NTAPI KsAllocateObjectHeader + (KSOBJECT_HEADER *Header, ULONG ItemsCount, + PKSOBJECT_CREATE_ITEM ItemsList, PIRP Irp, + const KSDISPATCH_TABLE *Table); + +KSDDKAPI VOID NTAPI KsFreeObjectHeader (KSOBJECT_HEADER Header); + +KSDDKAPI NTSTATUS NTAPI KsAddObjectCreateItemToDeviceHeader + (KSDEVICE_HEADER Header, PDRIVER_DISPATCH Create, PVOID Context, + PWSTR ObjectClass, PSECURITY_DESCRIPTOR SecurityDescriptor); + +KSDDKAPI NTSTATUS NTAPI KsAddObjectCreateItemToObjectHeader + (KSOBJECT_HEADER Header, PDRIVER_DISPATCH Create, PVOID Context, + PWSTR ObjectClass, PSECURITY_DESCRIPTOR SecurityDescriptor); + +KSDDKAPI NTSTATUS NTAPI KsAllocateObjectCreateItem + (KSDEVICE_HEADER Header, PKSOBJECT_CREATE_ITEM CreateItem, + BOOLEAN AllocateEntry, PFNKSITEMFREECALLBACK ItemFreeCallback); + +KSDDKAPI NTSTATUS NTAPI KsFreeObjectCreateItem + (KSDEVICE_HEADER Header, PUNICODE_STRING CreateItem); + +KSDDKAPI NTSTATUS NTAPI KsFreeObjectCreateItemsByContext + (KSDEVICE_HEADER Header, PVOID Context); + +KSDDKAPI NTSTATUS NTAPI KsCreateDefaultSecurity + (PSECURITY_DESCRIPTOR ParentSecurity, + PSECURITY_DESCRIPTOR *DefaultSecurity); + +KSDDKAPI NTSTATUS NTAPI KsForwardIrp + (PIRP Irp, PFILE_OBJECT FileObject, BOOLEAN ReuseStackLocation); + +KSDDKAPI NTSTATUS NTAPI KsForwardAndCatchIrp + (PDEVICE_OBJECT DeviceObject, PIRP Irp, PFILE_OBJECT FileObject, + KSSTACK_USE StackUse); + +KSDDKAPI NTSTATUS NTAPI KsSynchronousIoControlDevice + (PFILE_OBJECT FileObject, KPROCESSOR_MODE RequestorMode, + ULONG IoControl, PVOID InBuffer, ULONG InSize, PVOID OutBuffer, + ULONG OutSize, PULONG BytesReturned); + +KSDDKAPI NTSTATUS NTAPI KsUnserializeObjectPropertiesFromRegistry + (PFILE_OBJECT FileObject, HANDLE ParentKey, + PUNICODE_STRING RegistryPath); + +KSDDKAPI NTSTATUS NTAPI KsCacheMedium + (PUNICODE_STRING SymbolicLink, PKSPIN_MEDIUM Medium, + ULONG PinDirection); + +KSDDKAPI NTSTATUS NTAPI KsRegisterWorker + (WORK_QUEUE_TYPE WorkQueueType, PKSWORKER *Worker); + +KSDDKAPI NTSTATUS NTAPI KsRegisterCountedWorker + (WORK_QUEUE_TYPE WorkQueueType, PWORK_QUEUE_ITEM CountedWorkItem, + PKSWORKER *Worker); + +KSDDKAPI VOID NTAPI KsUnregisterWorker (PKSWORKER Worker); +KSDDKAPI NTSTATUS NTAPI KsQueueWorkItem(PKSWORKER Worker, PWORK_QUEUE_ITEM WorkItem); +KSDDKAPI ULONG NTAPI KsIncrementCountedWorker (PKSWORKER Worker); +KSDDKAPI ULONG NTAPI KsDecrementCountedWorker (PKSWORKER Worker); + +KSDDKAPI NTSTATUS NTAPI KsCreateTopologyNode + (HANDLE ParentHandle, PKSNODE_CREATE NodeCreate, + ACCESS_MASK DesiredAccess, PHANDLE NodeHandle); + +KSDDKAPI NTSTATUS NTAPI KsValidateTopologyNodeCreateRequest + (PIRP Irp, PKSTOPOLOGY Topology, PKSNODE_CREATE *NodeCreate); + +KSDDKAPI NTSTATUS NTAPI KsMergeAutomationTables + (PKSAUTOMATION_TABLE *AutomationTableAB, + PKSAUTOMATION_TABLE AutomationTableA, + PKSAUTOMATION_TABLE AutomationTableB, + KSOBJECT_BAG Bag); + +KSDDKAPI NTSTATUS NTAPI KsInitializeDriver + (PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPathName, + const KSDEVICE_DESCRIPTOR *Descriptor); + +KSDDKAPI NTSTATUS NTAPI KsAddDevice + (PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT PhysicalDeviceObject); + +KSDDKAPI NTSTATUS NTAPI KsCreateDevice + (PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT PhysicalDeviceObject, + const KSDEVICE_DESCRIPTOR *Descriptor, ULONG ExtensionSize, + PKSDEVICE *Device); + +KSDDKAPI NTSTATUS NTAPI KsInitializeDevice + (PDEVICE_OBJECT FunctionalDeviceObject, + PDEVICE_OBJECT PhysicalDeviceObject, + PDEVICE_OBJECT NextDeviceObject, + const KSDEVICE_DESCRIPTOR *Descriptor); + +KSDDKAPI void NTAPI KsTerminateDevice (PDEVICE_OBJECT DeviceObject); +KSDDKAPI PKSDEVICE NTAPI KsGetDeviceForDeviceObject (PDEVICE_OBJECT FunctionalDeviceObject); +KSDDKAPI void NTAPI KsAcquireDevice (PKSDEVICE Device); +KSDDKAPI void NTAPI KsReleaseDevice (PKSDEVICE Device); + +KSDDKAPI void NTAPI KsDeviceRegisterAdapterObject + (PKSDEVICE Device, PADAPTER_OBJECT AdapterObject, + ULONG MaxMappingsByteCount, ULONG MappingTableStride); + +KSDDKAPI ULONG NTAPI KsDeviceGetBusData + (PKSDEVICE Device, ULONG DataType, PVOID Buffer, ULONG Offset, + ULONG Length); + +KSDDKAPI ULONG NTAPI KsDeviceSetBusData + (PKSDEVICE Device, ULONG DataType, PVOID Buffer, ULONG Offset, + ULONG Length); + +KSDDKAPI NTSTATUS NTAPI KsCreateFilterFactory + (PDEVICE_OBJECT DeviceObject, const KSFILTER_DESCRIPTOR *Descriptor, + PWSTR RefString, PSECURITY_DESCRIPTOR SecurityDescriptor, + ULONG CreateItemFlags, PFNKSFILTERFACTORYPOWER SleepCallback, + PFNKSFILTERFACTORYPOWER WakeCallback, + PKSFILTERFACTORY *FilterFactory); + +#define KsDeleteFilterFactory(FilterFactory) \ + KsFreeObjectCreateItemsByContext( *(KSDEVICE_HEADER *)( \ + KsFilterFactoryGetParentDevice(FilterFactory)->FunctionalDeviceObject->DeviceExtension),\ + FilterFactory) + +KSDDKAPI NTSTATUS NTAPI KsFilterFactoryUpdateCacheData + (PKSFILTERFACTORY FilterFactory, + const KSFILTER_DESCRIPTOR *FilterDescriptor); + +KSDDKAPI NTSTATUS NTAPI KsFilterFactoryAddCreateItem + (PKSFILTERFACTORY FilterFactory, PWSTR RefString, + PSECURITY_DESCRIPTOR SecurityDescriptor, ULONG CreateItemFlags); + +KSDDKAPI NTSTATUS NTAPI KsFilterFactorySetDeviceClassesState + (PKSFILTERFACTORY FilterFactory, BOOLEAN NewState); + +KSDDKAPI PUNICODE_STRING NTAPI KsFilterFactoryGetSymbolicLink + (PKSFILTERFACTORY FilterFactory); + +KSDDKAPI void NTAPI KsAddEvent(PVOID Object, PKSEVENT_ENTRY EventEntry); + +void __forceinline KsFilterAddEvent (PKSFILTER Filter, PKSEVENT_ENTRY EventEntry) +{ + KsAddEvent(Filter, EventEntry); +} + +void __forceinline KsPinAddEvent (PKSPIN Pin, PKSEVENT_ENTRY EventEntry) +{ + KsAddEvent(Pin, EventEntry); +} + +KSDDKAPI NTSTATUS NTAPI KsDefaultAddEventHandler + (PIRP Irp, PKSEVENTDATA EventData, PKSEVENT_ENTRY EventEntry); + +KSDDKAPI void NTAPI KsGenerateEvents + (PVOID Object, const GUID *EventSet, ULONG EventId, + ULONG DataSize, PVOID Data, PFNKSGENERATEEVENTCALLBACK CallBack, + PVOID CallBackContext); + +void __forceinline KsFilterGenerateEvents + (PKSFILTER Filter, const GUID *EventSet, ULONG EventId, + ULONG DataSize, PVOID Data, PFNKSGENERATEEVENTCALLBACK CallBack, + PVOID CallBackContext) +{ + KsGenerateEvents(Filter, EventSet, EventId, DataSize, Data, CallBack, + CallBackContext); +} + +void __forceinline KsPinGenerateEvents + (PKSPIN Pin, const GUID *EventSet, ULONG EventId, + ULONG DataSize, PVOID Data, PFNKSGENERATEEVENTCALLBACK CallBack, + PVOID CallBackContext) +{ + KsGenerateEvents(Pin, EventSet, EventId, DataSize, Data, CallBack, + CallBackContext); +} + +typedef enum { + KSSTREAM_POINTER_STATE_UNLOCKED = 0, + KSSTREAM_POINTER_STATE_LOCKED +} KSSTREAM_POINTER_STATE; + +KSDDKAPI NTSTATUS NTAPI KsPinGetAvailableByteCount + (PKSPIN Pin, PLONG InputDataBytes, PLONG OutputBufferBytes); + +KSDDKAPI PKSSTREAM_POINTER NTAPI KsPinGetLeadingEdgeStreamPointer + (PKSPIN Pin, KSSTREAM_POINTER_STATE State); + +KSDDKAPI PKSSTREAM_POINTER NTAPI KsPinGetTrailingEdgeStreamPointer + (PKSPIN Pin, KSSTREAM_POINTER_STATE State); + +KSDDKAPI NTSTATUS NTAPI KsStreamPointerSetStatusCode + (PKSSTREAM_POINTER StreamPointer, NTSTATUS Status); + +KSDDKAPI NTSTATUS NTAPI KsStreamPointerLock (PKSSTREAM_POINTER StreamPointer); +KSDDKAPI void NTAPI KsStreamPointerUnlock(PKSSTREAM_POINTER StreamPointer, BOOLEAN Eject); + +KSDDKAPI void NTAPI KsStreamPointerAdvanceOffsetsAndUnlock + (PKSSTREAM_POINTER StreamPointer, ULONG InUsed, ULONG OutUsed, + BOOLEAN Eject); + +KSDDKAPI void NTAPI KsStreamPointerDelete (PKSSTREAM_POINTER StreamPointer); + +KSDDKAPI NTSTATUS NTAPI KsStreamPointerClone + (PKSSTREAM_POINTER StreamPointer, PFNKSSTREAMPOINTER CancelCallback, + ULONG ContextSize, PKSSTREAM_POINTER *CloneStreamPointer); + +KSDDKAPI NTSTATUS NTAPI KsStreamPointerAdvanceOffsets + (PKSSTREAM_POINTER StreamPointer, ULONG InUsed, ULONG OutUsed, + BOOLEAN Eject); + +KSDDKAPI NTSTATUS NTAPI KsStreamPointerAdvance (PKSSTREAM_POINTER StreamPointer); +KSDDKAPI PMDL NTAPI KsStreamPointerGetMdl (PKSSTREAM_POINTER StreamPointer); + +KSDDKAPI PIRP NTAPI KsStreamPointerGetIrp + (PKSSTREAM_POINTER StreamPointer, PBOOLEAN FirstFrameInIrp, + PBOOLEAN LastFrameInIrp); + +KSDDKAPI void NTAPI KsStreamPointerScheduleTimeout + (PKSSTREAM_POINTER StreamPointer, PFNKSSTREAMPOINTER Callback, + ULONGLONG Interval); + +KSDDKAPI void NTAPI KsStreamPointerCancelTimeout (PKSSTREAM_POINTER StreamPointer); +KSDDKAPI PKSSTREAM_POINTER NTAPI KsPinGetFirstCloneStreamPointer (PKSPIN Pin); + +KSDDKAPI PKSSTREAM_POINTER NTAPI KsStreamPointerGetNextClone + (PKSSTREAM_POINTER StreamPointer); + +KSDDKAPI NTSTATUS NTAPI KsPinHandshake(PKSPIN Pin, PKSHANDSHAKE In, PKSHANDSHAKE Out); +KSDDKAPI void NTAPI KsCompletePendingRequest (PIRP Irp); +KSDDKAPI KSOBJECTTYPE NTAPI KsGetObjectTypeFromIrp (PIRP Irp); +KSDDKAPI PVOID NTAPI KsGetObjectFromFileObject (PFILE_OBJECT FileObject); +KSDDKAPI KSOBJECTTYPE NTAPI KsGetObjectTypeFromFileObject (PFILE_OBJECT FileObject); + +PKSFILTER __forceinline KsGetFilterFromFileObject (PFILE_OBJECT FileObject) +{ + return (PKSFILTER) KsGetObjectFromFileObject(FileObject); +} + +PKSPIN __forceinline KsGetPinFromFileObject (PFILE_OBJECT FileObject) +{ + return (PKSPIN) KsGetObjectFromFileObject(FileObject); +} + +KSDDKAPI PKSGATE NTAPI KsFilterGetAndGate (PKSFILTER Filter); +KSDDKAPI void NTAPI KsFilterAcquireProcessingMutex (PKSFILTER Filter); +KSDDKAPI void NTAPI KsFilterReleaseProcessingMutex (PKSFILTER Filter); +KSDDKAPI void NTAPI KsFilterAttemptProcessing(PKSFILTER Filter, BOOLEAN Asynchronous); +KSDDKAPI PKSGATE NTAPI KsPinGetAndGate(PKSPIN Pin); +KSDDKAPI void NTAPI KsPinAttachAndGate(PKSPIN Pin, PKSGATE AndGate); +KSDDKAPI void NTAPI KsPinAttachOrGate (PKSPIN Pin, PKSGATE OrGate); +KSDDKAPI void NTAPI KsPinAcquireProcessingMutex (PKSPIN Pin); +KSDDKAPI void NTAPI KsPinReleaseProcessingMutex (PKSPIN Pin); +KSDDKAPI BOOLEAN NTAPI KsProcessPinUpdate (PKSPROCESSPIN ProcessPin); + +KSDDKAPI void NTAPI KsPinGetCopyRelationships + (PKSPIN Pin, PKSPIN *CopySource, PKSPIN *DelegateBranch); + +KSDDKAPI void NTAPI KsPinAttemptProcessing(PKSPIN Pin, BOOLEAN Asynchronous); +KSDDKAPI PVOID NTAPI KsGetParent (PVOID Object); + +PKSDEVICE __forceinline KsFilterFactoryGetParentDevice (PKSFILTERFACTORY FilterFactory) +{ + return (PKSDEVICE) KsGetParent((PVOID) FilterFactory); +} + +PKSFILTERFACTORY __forceinline KsFilterGetParentFilterFactory (PKSFILTER Filter) +{ + return (PKSFILTERFACTORY) KsGetParent((PVOID) Filter); +} + +KSDDKAPI PKSFILTER NTAPI KsPinGetParentFilter (PKSPIN Pin); +KSDDKAPI PVOID NTAPI KsGetFirstChild (PVOID Object); + +PKSFILTERFACTORY __forceinline KsDeviceGetFirstChildFilterFactory (PKSDEVICE Device) +{ + return (PKSFILTERFACTORY) KsGetFirstChild((PVOID) Device); +} + +PKSFILTER __forceinline KsFilterFactoryGetFirstChildFilter (PKSFILTERFACTORY FilterFactory) +{ + return (PKSFILTER) KsGetFirstChild((PVOID) FilterFactory); +} + +KSDDKAPI ULONG NTAPI KsFilterGetChildPinCount(PKSFILTER Filter, ULONG PinId); +KSDDKAPI PKSPIN NTAPI KsFilterGetFirstChildPin(PKSFILTER Filter, ULONG PinId); +KSDDKAPI PVOID NTAPI KsGetNextSibling (PVOID Object); +KSDDKAPI PKSPIN NTAPI KsPinGetNextSiblingPin (PKSPIN Pin); + +PKSFILTERFACTORY __forceinline KsFilterFactoryGetNextSiblingFilterFactory + (PKSFILTERFACTORY FilterFactory) +{ + return (PKSFILTERFACTORY) KsGetNextSibling((PVOID) FilterFactory); +} + +PKSFILTER __forceinline KsFilterGetNextSiblingFilter (PKSFILTER Filter) +{ + return (PKSFILTER) KsGetNextSibling((PVOID) Filter); +} + +KSDDKAPI PKSDEVICE NTAPI KsGetDevice (PVOID Object); + +PKSDEVICE __forceinline KsFilterFactoryGetDevice (PKSFILTERFACTORY FilterFactory) +{ + return KsGetDevice((PVOID) FilterFactory); +} + +PKSDEVICE __forceinline KsFilterGetDevice (PKSFILTER Filter) +{ + return KsGetDevice((PVOID) Filter); +} + +PKSDEVICE __forceinline KsPinGetDevice (PKSPIN Pin) +{ + return KsGetDevice((PVOID) Pin); +} + +KSDDKAPI PKSFILTER NTAPI KsGetFilterFromIrp (PIRP Irp); +KSDDKAPI PKSPIN NTAPI KsGetPinFromIrp (PIRP Irp); +KSDDKAPI ULONG NTAPI KsGetNodeIdFromIrp (PIRP Irp); +KSDDKAPI void NTAPI KsAcquireControl (PVOID Object); +KSDDKAPI void NTAPI KsReleaseControl (PVOID Object); + +void __forceinline KsFilterAcquireControl (PKSFILTER Filter) +{ + KsAcquireControl((PVOID) Filter); +} + +void __forceinline KsFilterReleaseControl (PKSFILTER Filter) +{ + KsReleaseControl((PVOID) Filter); +} + +void __forceinline KsPinAcquireControl (PKSPIN Pin) +{ + KsAcquireControl((PVOID) Pin); +} + +void __forceinline KsPinReleaseControl (PKSPIN Pin) +{ + KsReleaseControl((PVOID) Pin); +} + +KSDDKAPI NTSTATUS NTAPI KsAddItemToObjectBag + (KSOBJECT_BAG ObjectBag, PVOID Item, PFNKSFREE Free); + +KSDDKAPI ULONG NTAPI KsRemoveItemFromObjectBag + (KSOBJECT_BAG ObjectBag, PVOID Item, BOOLEAN Free); + +#define KsDiscard(Object,Pointer) \ + KsRemoveItemFromObjectBag((Object)->Bag, (PVOID)(Pointer), TRUE) + +KSDDKAPI NTSTATUS NTAPI KsAllocateObjectBag(PKSDEVICE Device, KSOBJECT_BAG *ObjectBag); +KSDDKAPI void NTAPI KsFreeObjectBag (KSOBJECT_BAG ObjectBag); + +KSDDKAPI NTSTATUS NTAPI KsCopyObjectBagItems + (KSOBJECT_BAG ObjectBagDestination, KSOBJECT_BAG ObjectBagSource); + +KSDDKAPI NTSTATUS NTAPI _KsEdit + (KSOBJECT_BAG ObjectBag, PVOID *PointerToPointerToItem, + ULONG NewSize, ULONG OldSize, ULONG Tag); + +#define KsEdit(Object, PointerToPointer, Tag) \ + _KsEdit((Object)->Bag, (PVOID*)(PointerToPointer), \ + sizeof(**(PointerToPointer)), sizeof(**(PointerToPointer)), (Tag)) + +#define KsEditSized(Object, PointerToPointer, NewSize, OldSize, Tag) \ + _KsEdit((Object)->Bag, (PVOID*)(PointerToPointer), (NewSize), (OldSize), (Tag)) + +KSDDKAPI NTSTATUS NTAPI KsRegisterFilterWithNoKSPins + (PDEVICE_OBJECT DeviceObject, const GUID *InterfaceClassGUID, + ULONG PinCount, WINBOOL *PinDirection, KSPIN_MEDIUM *MediumList, + GUID *CategoryList); + +KSDDKAPI NTSTATUS NTAPI KsFilterCreatePinFactory + (PKSFILTER Filter, const KSPIN_DESCRIPTOR_EX *const PinDescriptor, + PULONG PinID); + +KSDDKAPI NTSTATUS NTAPI KsFilterCreateNode + (PKSFILTER Filter, const KSNODE_DESCRIPTOR *const NodeDescriptor, + PULONG NodeID); + +KSDDKAPI NTSTATUS NTAPI KsFilterAddTopologyConnections + (PKSFILTER Filter, ULONG NewConnectionsCount, + const KSTOPOLOGY_CONNECTION *const NewTopologyConnections); + +KSDDKAPI NTSTATUS NTAPI KsPinGetConnectedPinInterface + (PKSPIN Pin, const GUID *InterfaceId, PVOID *Interface); + +KSDDKAPI PFILE_OBJECT NTAPI KsPinGetConnectedPinFileObject (PKSPIN Pin); +KSDDKAPI PDEVICE_OBJECT NTAPI KsPinGetConnectedPinDeviceObject (PKSPIN Pin); + +KSDDKAPI NTSTATUS NTAPI KsPinGetConnectedFilterInterface + (PKSPIN Pin, const GUID *InterfaceId, PVOID *Interface); + +#if defined(_UNKNOWN_H_) || defined(__IUnknown_INTERFACE_DEFINED__) +KSDDKAPI NTSTATUS NTAPI KsPinGetReferenceClockInterface + (PKSPIN Pin, PIKSREFERENCECLOCK *Interface); +#endif /* defined(_UNKNOWN_H_) || defined(__IUnknown_INTERFACE_DEFINED__) */ + +KSDDKAPI VOID NTAPI KsPinSetPinClockTime(PKSPIN Pin, LONGLONG Time); + +KSDDKAPI NTSTATUS NTAPI KsPinSubmitFrame + (PKSPIN Pin, PVOID Data, ULONG Size, + PKSSTREAM_HEADER StreamHeader, PVOID Context); + +KSDDKAPI NTSTATUS NTAPI KsPinSubmitFrameMdl + (PKSPIN Pin, PMDL Mdl, PKSSTREAM_HEADER StreamHeader, + PVOID Context); + +KSDDKAPI void NTAPI KsPinRegisterFrameReturnCallback + (PKSPIN Pin, PFNKSPINFRAMERETURN FrameReturn); + +KSDDKAPI void NTAPI KsPinRegisterIrpCompletionCallback + (PKSPIN Pin, PFNKSPINIRPCOMPLETION IrpCompletion); + +KSDDKAPI void NTAPI KsPinRegisterHandshakeCallback + (PKSPIN Pin, PFNKSPINHANDSHAKE Handshake); + +KSDDKAPI void NTAPI KsFilterRegisterPowerCallbacks + (PKSFILTER Filter, PFNKSFILTERPOWER Sleep, PFNKSFILTERPOWER Wake); + +KSDDKAPI void NTAPI KsPinRegisterPowerCallbacks + (PKSPIN Pin, PFNKSPINPOWER Sleep, PFNKSPINPOWER Wake); + +#if defined(_UNKNOWN_H_) || defined(__IUnknown_INTERFACE_DEFINED__) +KSDDKAPI PUNKNOWN NTAPI KsRegisterAggregatedClientUnknown + (PVOID Object, PUNKNOWN ClientUnknown); + +KSDDKAPI PUNKNOWN NTAPI KsGetOuterUnknown (PVOID Object); + +PUNKNOWN __forceinline KsDeviceRegisterAggregatedClientUnknown + (PKSDEVICE Device, PUNKNOWN ClientUnknown) +{ + return KsRegisterAggregatedClientUnknown((PVOID)Device, ClientUnknown); +} + +PUNKNOWN __forceinline KsDeviceGetOuterUnknown (PKSDEVICE Device) +{ + return KsGetOuterUnknown((PVOID) Device); +} + +PUNKNOWN __forceinline KsFilterFactoryRegisterAggregatedClientUnknown + (PKSFILTERFACTORY FilterFactory, PUNKNOWN ClientUnknown) +{ + return KsRegisterAggregatedClientUnknown((PVOID)FilterFactory, ClientUnknown); +} + +PUNKNOWN __forceinline KsFilterFactoryGetOuterUnknown (PKSFILTERFACTORY FilterFactory) +{ + return KsGetOuterUnknown((PVOID)FilterFactory); +} + +PUNKNOWN __forceinline KsFilterRegisterAggregatedClientUnknown + (PKSFILTER Filter, PUNKNOWN ClientUnknown) +{ + return KsRegisterAggregatedClientUnknown((PVOID)Filter, ClientUnknown); +} + +PUNKNOWN __forceinline KsFilterGetOuterUnknown (PKSFILTER Filter) +{ + return KsGetOuterUnknown((PVOID)Filter); +} + +PUNKNOWN __forceinline KsPinRegisterAggregatedClientUnknown + (PKSPIN Pin, PUNKNOWN ClientUnknown) +{ + return KsRegisterAggregatedClientUnknown((PVOID)Pin, ClientUnknown); +} + +PUNKNOWN __forceinline KsPinGetOuterUnknown (PKSPIN Pin) +{ + return KsGetOuterUnknown((PVOID)Pin); +} +#endif /* defined(_UNKNOWN_H_) || defined(__IUnknown_INTERFACE_DEFINED__) */ + +#else /* _NTDDK_ */ + +#ifndef KS_NO_CREATE_FUNCTIONS +KSDDKAPI DWORD WINAPI KsCreateAllocator(HANDLE ConnectionHandle,PKSALLOCATOR_FRAMING AllocatorFraming,PHANDLE AllocatorHandle); +KSDDKAPI DWORD NTAPI KsCreateClock(HANDLE ConnectionHandle,PKSCLOCK_CREATE ClockCreate,PHANDLE ClockHandle); +KSDDKAPI DWORD WINAPI KsCreatePin(HANDLE FilterHandle,PKSPIN_CONNECT Connect,ACCESS_MASK DesiredAccess,PHANDLE ConnectionHandle); +KSDDKAPI DWORD WINAPI KsCreateTopologyNode(HANDLE ParentHandle,PKSNODE_CREATE NodeCreate,ACCESS_MASK DesiredAccess,PHANDLE NodeHandle); +#endif + +#endif /* _NTDDK_ */ + +#ifdef __cplusplus +} +#endif + +#define DENY_USERMODE_ACCESS(pIrp,CompleteRequest) \ + if(pIrp->RequestorMode!=KernelMode) { \ + pIrp->IoStatus.Information = 0; \ + pIrp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST; \ + if(CompleteRequest) \ + IoCompleteRequest (pIrp,IO_NO_INCREMENT); \ + return STATUS_INVALID_DEVICE_REQUEST; \ + } + +#endif /* _KS_ */ + diff --git a/extern/portaudio/src/hostapi/wasapi/mingw-include/ksguid.h b/extern/portaudio/src/hostapi/wasapi/mingw-include/ksguid.h new file mode 100644 index 0000000..f0774d0 --- /dev/null +++ b/extern/portaudio/src/hostapi/wasapi/mingw-include/ksguid.h @@ -0,0 +1,28 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER.PD within this package. + */ +#define INITGUID +#include + +#ifndef DECLSPEC_SELECTANY +#define DECLSPEC_SELECTANY __declspec(selectany) +#endif + +#ifdef DEFINE_GUIDEX +#undef DEFINE_GUIDEX +#endif + +#ifdef __cplusplus +#define DEFINE_GUIDEX(name) EXTERN_C const CDECL GUID DECLSPEC_SELECTANY name = { STATICGUIDOF(name) } +#else +#define DEFINE_GUIDEX(name) const CDECL GUID DECLSPEC_SELECTANY name = { STATICGUIDOF(name) } +#endif +#ifndef STATICGUIDOF +#define STATICGUIDOF(guid) STATIC_##guid +#endif + +#ifndef DEFINE_WAVEFORMATEX_GUID +#define DEFINE_WAVEFORMATEX_GUID(x) (USHORT)(x),0x0000,0x0010,0x80,0x00,0x00,0xaa,0x00,0x38,0x9b,0x71 +#endif diff --git a/extern/portaudio/src/hostapi/wasapi/mingw-include/ksmedia.h b/extern/portaudio/src/hostapi/wasapi/mingw-include/ksmedia.h new file mode 100644 index 0000000..f029b01 --- /dev/null +++ b/extern/portaudio/src/hostapi/wasapi/mingw-include/ksmedia.h @@ -0,0 +1,4610 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER.PD within this package. + */ +#if !defined(_KS_) +#warning ks.h must be included before ksmedia.h +#include "ks.h" +#endif + +#if __GNUC__ >= 3 +#pragma GCC system_header +#endif + +#if !defined(_KSMEDIA_) +#define _KSMEDIA_ + +typedef struct { + KSPROPERTY Property; + KSMULTIPLE_ITEM MultipleItem; +} KSMULTIPLE_DATA_PROP,*PKSMULTIPLE_DATA_PROP; + +#define STATIC_KSMEDIUMSETID_MidiBus \ + 0x05908040L,0x3246,0x11D0,0xA5,0xD6,0x28,0xDB,0x04,0xC1,0x00,0x00 +DEFINE_GUIDSTRUCT("05908040-3246-11D0-A5D6-28DB04C10000",KSMEDIUMSETID_MidiBus); +#define KSMEDIUMSETID_MidiBus DEFINE_GUIDNAMED(KSMEDIUMSETID_MidiBus) + +#define STATIC_KSMEDIUMSETID_VPBus \ + 0xA18C15ECL,0xCE43,0x11D0,0xAB,0xE7,0x00,0xA0,0xC9,0x22,0x31,0x96 +DEFINE_GUIDSTRUCT("A18C15EC-CE43-11D0-ABE7-00A0C9223196",KSMEDIUMSETID_VPBus); +#define KSMEDIUMSETID_VPBus DEFINE_GUIDNAMED(KSMEDIUMSETID_VPBus) + +#define STATIC_KSINTERFACESETID_Media \ + 0x3A13EB40L,0x30A7,0x11D0,0xA5,0xD6,0x28,0xDB,0x04,0xC1,0x00,0x00 +DEFINE_GUIDSTRUCT("3A13EB40-30A7-11D0-A5D6-28DB04C10000",KSINTERFACESETID_Media); +#define KSINTERFACESETID_Media DEFINE_GUIDNAMED(KSINTERFACESETID_Media) + +typedef enum { + KSINTERFACE_MEDIA_MUSIC, + KSINTERFACE_MEDIA_WAVE_BUFFERED, + KSINTERFACE_MEDIA_WAVE_QUEUED +} KSINTERFACE_MEDIA; + +#ifndef INIT_USBAUDIO_MID +#define INIT_USBAUDIO_MID(guid,id) \ +{ \ + (guid)->Data1 = 0x4e1cecd2 + (USHORT)(id); \ + (guid)->Data2 = 0x1679; \ + (guid)->Data3 = 0x463b; \ + (guid)->Data4[0] = 0xa7; \ + (guid)->Data4[1] = 0x2f; \ + (guid)->Data4[2] = 0xa5; \ + (guid)->Data4[3] = 0xbf; \ + (guid)->Data4[4] = 0x64; \ + (guid)->Data4[5] = 0xc8; \ + (guid)->Data4[6] = 0x6e; \ + (guid)->Data4[7] = 0xba; \ +} +#define EXTRACT_USBAUDIO_MID(guid) \ + (USHORT)((guid)->Data1 - 0x4e1cecd2) +#define DEFINE_USBAUDIO_MID_GUID(id) \ + 0x4e1cecd2+(USHORT)(id),0x1679,0x463b,0xa7,0x2f,0xa5,0xbf,0x64,0xc8,0x6e,0xba +#define IS_COMPATIBLE_USBAUDIO_MID(guid) \ + (((guid)->Data1 >= 0x4e1cecd2) && \ + ((guid)->Data1 < 0x4e1cecd2 + 0xffff) && \ + ((guid)->Data2 == 0x1679) && \ + ((guid)->Data3 == 0x463b) && \ + ((guid)->Data4[0] == 0xa7) && \ + ((guid)->Data4[1] == 0x2f) && \ + ((guid)->Data4[2] == 0xa5) && \ + ((guid)->Data4[3] == 0xbf) && \ + ((guid)->Data4[4] == 0x64) && \ + ((guid)->Data4[5] == 0xc8) && \ + ((guid)->Data4[6] == 0x6e) && \ + ((guid)->Data4[7] == 0xba) ) +#endif /* INIT_USBAUDIO_MID */ + +#ifndef INIT_USBAUDIO_PID +#define INIT_USBAUDIO_PID(guid,id) \ +{ \ + (guid)->Data1 = 0xabcc5a5e + (USHORT)(id); \ + (guid)->Data2 = 0xc263; \ + (guid)->Data3 = 0x463b; \ + (guid)->Data4[0] = 0xa7; \ + (guid)->Data4[1] = 0x2f; \ + (guid)->Data4[2] = 0xa5; \ + (guid)->Data4[3] = 0xbf; \ + (guid)->Data4[4] = 0x64; \ + (guid)->Data4[5] = 0xc8; \ + (guid)->Data4[6] = 0x6e; \ + (guid)->Data4[7] = 0xba; \ +} +#define EXTRACT_USBAUDIO_PID(guid) \ + (USHORT)((guid)->Data1 - 0xabcc5a5e) +#define DEFINE_USBAUDIO_PID_GUID(id) \ + 0xabcc5a5e+(USHORT)(id),0xc263,0x463b,0xa7,0x2f,0xa5,0xbf,0x64,0xc8,0x6e,0xba +#define IS_COMPATIBLE_USBAUDIO_PID(guid) \ + (((guid)->Data1 >= 0xabcc5a5e) && \ + ((guid)->Data1 < 0xabcc5a5e + 0xffff) && \ + ((guid)->Data2 == 0xc263) && \ + ((guid)->Data3 == 0x463b) && \ + ((guid)->Data4[0] == 0xa7) && \ + ((guid)->Data4[1] == 0x2f) && \ + ((guid)->Data4[2] == 0xa5) && \ + ((guid)->Data4[3] == 0xbf) && \ + ((guid)->Data4[4] == 0x64) && \ + ((guid)->Data4[5] == 0xc8) && \ + ((guid)->Data4[6] == 0x6e) && \ + ((guid)->Data4[7] == 0xba) ) +#endif /* INIT_USBAUDIO_PID */ + +#ifndef INIT_USBAUDIO_PRODUCT_NAME +#define INIT_USBAUDIO_PRODUCT_NAME(guid,vid,pid,strIndex) \ +{ \ + (guid)->Data1 = 0XFC575048 + (USHORT)(vid); \ + (guid)->Data2 = 0x2E08 + (USHORT)(pid); \ + (guid)->Data3 = 0x463B + (USHORT)(strIndex); \ + (guid)->Data4[0] = 0xA7; \ + (guid)->Data4[1] = 0x2F; \ + (guid)->Data4[2] = 0xA5; \ + (guid)->Data4[3] = 0xBF; \ + (guid)->Data4[4] = 0x64; \ + (guid)->Data4[5] = 0xC8; \ + (guid)->Data4[6] = 0x6E; \ + (guid)->Data4[7] = 0xBA; \ +} +#define DEFINE_USBAUDIO_PRODUCT_NAME(vid,pid,strIndex) \ + 0xFC575048+(USHORT)(vid),0x2E08+(USHORT)(pid),0x463B+(USHORT)(strIndex),0xA7,0x2F,0xA5,0xBF,0x64,0xC8,0x6E,0xBA +#endif /* INIT_USBAUDIO_PRODUCT_NAME */ + +#define STATIC_KSCOMPONENTID_USBAUDIO \ + 0x8F1275F0,0x26E9,0x4264,0xBA,0x4D,0x39,0xFF,0xF0,0x1D,0x94,0xAA +DEFINE_GUIDSTRUCT("8F1275F0-26E9-4264-BA4D-39FFF01D94AA",KSCOMPONENTID_USBAUDIO); +#define KSCOMPONENTID_USBAUDIO DEFINE_GUIDNAMED(KSCOMPONENTID_USBAUDIO) + +#define INIT_USB_TERMINAL(guid,id) \ +{ \ + (guid)->Data1 = 0xDFF219E0 + (USHORT)(id); \ + (guid)->Data2 = 0xF70F; \ + (guid)->Data3 = 0x11D0; \ + (guid)->Data4[0] = 0xb9; \ + (guid)->Data4[1] = 0x17; \ + (guid)->Data4[2] = 0x00; \ + (guid)->Data4[3] = 0xa0; \ + (guid)->Data4[4] = 0xc9; \ + (guid)->Data4[5] = 0x22; \ + (guid)->Data4[6] = 0x31; \ + (guid)->Data4[7] = 0x96; \ +} +#define EXTRACT_USB_TERMINAL(guid) \ + (USHORT)((guid)->Data1 - 0xDFF219E0) +#define DEFINE_USB_TERMINAL_GUID(id) \ + 0xDFF219E0+(USHORT)(id),0xF70F,0x11D0,0xB9,0x17,0x00,0xA0,0xC9,0x22,0x31,0x96 + +#define STATIC_KSNODETYPE_MICROPHONE \ + DEFINE_USB_TERMINAL_GUID(0x0201) +DEFINE_GUIDSTRUCT("DFF21BE1-F70F-11D0-B917-00A0C9223196",KSNODETYPE_MICROPHONE); +#define KSNODETYPE_MICROPHONE DEFINE_GUIDNAMED(KSNODETYPE_MICROPHONE) + +#define STATIC_KSNODETYPE_DESKTOP_MICROPHONE \ + DEFINE_USB_TERMINAL_GUID(0x0202) +DEFINE_GUIDSTRUCT("DFF21BE2-F70F-11D0-B917-00A0C9223196",KSNODETYPE_DESKTOP_MICROPHONE); +#define KSNODETYPE_DESKTOP_MICROPHONE DEFINE_GUIDNAMED(KSNODETYPE_DESKTOP_MICROPHONE) + +#define STATIC_KSNODETYPE_PERSONAL_MICROPHONE \ + DEFINE_USB_TERMINAL_GUID(0x0203) +DEFINE_GUIDSTRUCT("DFF21BE3-F70F-11D0-B917-00A0C9223196",KSNODETYPE_PERSONAL_MICROPHONE); +#define KSNODETYPE_PERSONAL_MICROPHONE DEFINE_GUIDNAMED(KSNODETYPE_PERSONAL_MICROPHONE) + +#define STATIC_KSNODETYPE_OMNI_DIRECTIONAL_MICROPHONE \ + DEFINE_USB_TERMINAL_GUID(0x0204) +DEFINE_GUIDSTRUCT("DFF21BE4-F70F-11D0-B917-00A0C9223196",KSNODETYPE_OMNI_DIRECTIONAL_MICROPHONE); +#define KSNODETYPE_OMNI_DIRECTIONAL_MICROPHONE DEFINE_GUIDNAMED(KSNODETYPE_OMNI_DIRECTIONAL_MICROPHONE) + +#define STATIC_KSNODETYPE_MICROPHONE_ARRAY \ + DEFINE_USB_TERMINAL_GUID(0x0205) +DEFINE_GUIDSTRUCT("DFF21BE5-F70F-11D0-B917-00A0C9223196",KSNODETYPE_MICROPHONE_ARRAY); +#define KSNODETYPE_MICROPHONE_ARRAY DEFINE_GUIDNAMED(KSNODETYPE_MICROPHONE_ARRAY) + +#define STATIC_KSNODETYPE_PROCESSING_MICROPHONE_ARRAY \ + DEFINE_USB_TERMINAL_GUID(0x0206) +DEFINE_GUIDSTRUCT("DFF21BE6-F70F-11D0-B917-00A0C9223196",KSNODETYPE_PROCESSING_MICROPHONE_ARRAY); +#define KSNODETYPE_PROCESSING_MICROPHONE_ARRAY DEFINE_GUIDNAMED(KSNODETYPE_PROCESSING_MICROPHONE_ARRAY) + +#define STATIC_KSCATEGORY_MICROPHONE_ARRAY_PROCESSOR \ + 0x830a44f2,0xa32d,0x476b,0xbe,0x97,0x42,0x84,0x56,0x73,0xb3,0x5a +DEFINE_GUIDSTRUCT("830a44f2-a32d-476b-be97-42845673b35a",KSCATEGORY_MICROPHONE_ARRAY_PROCESSOR); +#define KSCATEGORY_MICROPHONE_ARRAY_PROCESSOR DEFINE_GUIDNAMED(KSCATEGORY_MICROPHONE_ARRAY_PROCESSOR) + +#define STATIC_KSNODETYPE_SPEAKER \ + DEFINE_USB_TERMINAL_GUID(0x0301) +DEFINE_GUIDSTRUCT("DFF21CE1-F70F-11D0-B917-00A0C9223196",KSNODETYPE_SPEAKER); +#define KSNODETYPE_SPEAKER DEFINE_GUIDNAMED(KSNODETYPE_SPEAKER) + +#define STATIC_KSNODETYPE_HEADPHONES \ + DEFINE_USB_TERMINAL_GUID(0x0302) +DEFINE_GUIDSTRUCT("DFF21CE2-F70F-11D0-B917-00A0C9223196",KSNODETYPE_HEADPHONES); +#define KSNODETYPE_HEADPHONES DEFINE_GUIDNAMED(KSNODETYPE_HEADPHONES) + +#define STATIC_KSNODETYPE_HEAD_MOUNTED_DISPLAY_AUDIO \ + DEFINE_USB_TERMINAL_GUID(0x0303) +DEFINE_GUIDSTRUCT("DFF21CE3-F70F-11D0-B917-00A0C9223196",KSNODETYPE_HEAD_MOUNTED_DISPLAY_AUDIO); +#define KSNODETYPE_HEAD_MOUNTED_DISPLAY_AUDIO DEFINE_GUIDNAMED(KSNODETYPE_HEAD_MOUNTED_DISPLAY_AUDIO) + +#define STATIC_KSNODETYPE_DESKTOP_SPEAKER \ + DEFINE_USB_TERMINAL_GUID(0x0304) +DEFINE_GUIDSTRUCT("DFF21CE4-F70F-11D0-B917-00A0C9223196",KSNODETYPE_DESKTOP_SPEAKER); +#define KSNODETYPE_DESKTOP_SPEAKER DEFINE_GUIDNAMED(KSNODETYPE_DESKTOP_SPEAKER) + +#define STATIC_KSNODETYPE_ROOM_SPEAKER \ + DEFINE_USB_TERMINAL_GUID(0x0305) +DEFINE_GUIDSTRUCT("DFF21CE5-F70F-11D0-B917-00A0C9223196",KSNODETYPE_ROOM_SPEAKER); +#define KSNODETYPE_ROOM_SPEAKER DEFINE_GUIDNAMED(KSNODETYPE_ROOM_SPEAKER) + +#define STATIC_KSNODETYPE_COMMUNICATION_SPEAKER \ + DEFINE_USB_TERMINAL_GUID(0x0306) +DEFINE_GUIDSTRUCT("DFF21CE6-F70F-11D0-B917-00A0C9223196",KSNODETYPE_COMMUNICATION_SPEAKER); +#define KSNODETYPE_COMMUNICATION_SPEAKER DEFINE_GUIDNAMED(KSNODETYPE_COMMUNICATION_SPEAKER) + +#define STATIC_KSNODETYPE_LOW_FREQUENCY_EFFECTS_SPEAKER \ + DEFINE_USB_TERMINAL_GUID(0x0307) +DEFINE_GUIDSTRUCT("DFF21CE7-F70F-11D0-B917-00A0C9223196",KSNODETYPE_LOW_FREQUENCY_EFFECTS_SPEAKER); +#define KSNODETYPE_LOW_FREQUENCY_EFFECTS_SPEAKER DEFINE_GUIDNAMED(KSNODETYPE_LOW_FREQUENCY_EFFECTS_SPEAKER) + +#define STATIC_KSNODETYPE_HANDSET \ + DEFINE_USB_TERMINAL_GUID(0x0401) +DEFINE_GUIDSTRUCT("DFF21DE1-F70F-11D0-B917-00A0C9223196",KSNODETYPE_HANDSET); +#define KSNODETYPE_HANDSET DEFINE_GUIDNAMED(KSNODETYPE_HANDSET) + +#define STATIC_KSNODETYPE_HEADSET \ + DEFINE_USB_TERMINAL_GUID(0x0402) +DEFINE_GUIDSTRUCT("DFF21DE2-F70F-11D0-B917-00A0C9223196",KSNODETYPE_HEADSET); +#define KSNODETYPE_HEADSET DEFINE_GUIDNAMED(KSNODETYPE_HEADSET) + +#define STATIC_KSNODETYPE_SPEAKERPHONE_NO_ECHO_REDUCTION \ + DEFINE_USB_TERMINAL_GUID(0x0403) +DEFINE_GUIDSTRUCT("DFF21DE3-F70F-11D0-B917-00A0C9223196",KSNODETYPE_SPEAKERPHONE_NO_ECHO_REDUCTION); +#define KSNODETYPE_SPEAKERPHONE_NO_ECHO_REDUCTION DEFINE_GUIDNAMED(KSNODETYPE_SPEAKERPHONE_NO_ECHO_REDUCTION) + +#define STATIC_KSNODETYPE_ECHO_SUPPRESSING_SPEAKERPHONE \ + DEFINE_USB_TERMINAL_GUID(0x0404) +DEFINE_GUIDSTRUCT("DFF21DE4-F70F-11D0-B917-00A0C9223196",KSNODETYPE_ECHO_SUPPRESSING_SPEAKERPHONE); +#define KSNODETYPE_ECHO_SUPPRESSING_SPEAKERPHONE DEFINE_GUIDNAMED(KSNODETYPE_ECHO_SUPPRESSING_SPEAKERPHONE) + +#define STATIC_KSNODETYPE_ECHO_CANCELING_SPEAKERPHONE \ + DEFINE_USB_TERMINAL_GUID(0x0405) +DEFINE_GUIDSTRUCT("DFF21DE5-F70F-11D0-B917-00A0C9223196",KSNODETYPE_ECHO_CANCELING_SPEAKERPHONE); +#define KSNODETYPE_ECHO_CANCELING_SPEAKERPHONE DEFINE_GUIDNAMED(KSNODETYPE_ECHO_CANCELING_SPEAKERPHONE) + +#define STATIC_KSNODETYPE_PHONE_LINE \ + DEFINE_USB_TERMINAL_GUID(0x0501) +DEFINE_GUIDSTRUCT("DFF21EE1-F70F-11D0-B917-00A0C9223196",KSNODETYPE_PHONE_LINE); +#define KSNODETYPE_PHONE_LINE DEFINE_GUIDNAMED(KSNODETYPE_PHONE_LINE) + +#define STATIC_KSNODETYPE_TELEPHONE \ + DEFINE_USB_TERMINAL_GUID(0x0502) +DEFINE_GUIDSTRUCT("DFF21EE2-F70F-11D0-B917-00A0C9223196",KSNODETYPE_TELEPHONE); +#define KSNODETYPE_TELEPHONE DEFINE_GUIDNAMED(KSNODETYPE_TELEPHONE) + +#define STATIC_KSNODETYPE_DOWN_LINE_PHONE \ + DEFINE_USB_TERMINAL_GUID(0x0503) +DEFINE_GUIDSTRUCT("DFF21EE3-F70F-11D0-B917-00A0C9223196",KSNODETYPE_DOWN_LINE_PHONE); +#define KSNODETYPE_DOWN_LINE_PHONE DEFINE_GUIDNAMED(KSNODETYPE_DOWN_LINE_PHONE) + +#define STATIC_KSNODETYPE_ANALOG_CONNECTOR \ + DEFINE_USB_TERMINAL_GUID(0x601) +DEFINE_GUIDSTRUCT("DFF21FE1-F70F-11D0-B917-00A0C9223196",KSNODETYPE_ANALOG_CONNECTOR); +#define KSNODETYPE_ANALOG_CONNECTOR DEFINE_GUIDNAMED(KSNODETYPE_ANALOG_CONNECTOR) + +#define STATIC_KSNODETYPE_DIGITAL_AUDIO_INTERFACE \ + DEFINE_USB_TERMINAL_GUID(0x0602) +DEFINE_GUIDSTRUCT("DFF21FE2-F70F-11D0-B917-00A0C9223196",KSNODETYPE_DIGITAL_AUDIO_INTERFACE); +#define KSNODETYPE_DIGITAL_AUDIO_INTERFACE DEFINE_GUIDNAMED(KSNODETYPE_DIGITAL_AUDIO_INTERFACE) + +#define STATIC_KSNODETYPE_LINE_CONNECTOR \ + DEFINE_USB_TERMINAL_GUID(0x0603) +DEFINE_GUIDSTRUCT("DFF21FE3-F70F-11D0-B917-00A0C9223196",KSNODETYPE_LINE_CONNECTOR); +#define KSNODETYPE_LINE_CONNECTOR DEFINE_GUIDNAMED(KSNODETYPE_LINE_CONNECTOR) + +#define STATIC_KSNODETYPE_LEGACY_AUDIO_CONNECTOR \ + DEFINE_USB_TERMINAL_GUID(0x0604) +DEFINE_GUIDSTRUCT("DFF21FE4-F70F-11D0-B917-00A0C9223196",KSNODETYPE_LEGACY_AUDIO_CONNECTOR); +#define KSNODETYPE_LEGACY_AUDIO_CONNECTOR DEFINE_GUIDNAMED(KSNODETYPE_LEGACY_AUDIO_CONNECTOR) + +#define STATIC_KSNODETYPE_SPDIF_INTERFACE \ + DEFINE_USB_TERMINAL_GUID(0x0605) +DEFINE_GUIDSTRUCT("DFF21FE5-F70F-11D0-B917-00A0C9223196",KSNODETYPE_SPDIF_INTERFACE); +#define KSNODETYPE_SPDIF_INTERFACE DEFINE_GUIDNAMED(KSNODETYPE_SPDIF_INTERFACE) + +#define STATIC_KSNODETYPE_1394_DA_STREAM \ + DEFINE_USB_TERMINAL_GUID(0x0606) +DEFINE_GUIDSTRUCT("DFF21FE6-F70F-11D0-B917-00A0C9223196",KSNODETYPE_1394_DA_STREAM); +#define KSNODETYPE_1394_DA_STREAM DEFINE_GUIDNAMED(KSNODETYPE_1394_DA_STREAM) + +#define STATIC_KSNODETYPE_1394_DV_STREAM_SOUNDTRACK \ + DEFINE_USB_TERMINAL_GUID(0x0607) +DEFINE_GUIDSTRUCT("DFF21FE7-F70F-11D0-B917-00A0C9223196",KSNODETYPE_1394_DV_STREAM_SOUNDTRACK); +#define KSNODETYPE_1394_DV_STREAM_SOUNDTRACK DEFINE_GUIDNAMED(KSNODETYPE_1394_DV_STREAM_SOUNDTRACK) + +#define STATIC_KSNODETYPE_LEVEL_CALIBRATION_NOISE_SOURCE \ + DEFINE_USB_TERMINAL_GUID(0x0701) +DEFINE_GUIDSTRUCT("DFF220E1-F70F-11D0-B917-00A0C9223196",KSNODETYPE_LEVEL_CALIBRATION_NOISE_SOURCE); +#define KSNODETYPE_LEVEL_CALIBRATION_NOISE_SOURCE DEFINE_GUIDNAMED(KSNODETYPE_LEVEL_CALIBRATION_NOISE_SOURCE) + +#define STATIC_KSNODETYPE_EQUALIZATION_NOISE \ + DEFINE_USB_TERMINAL_GUID(0x0702) +DEFINE_GUIDSTRUCT("DFF220E2-F70F-11D0-B917-00A0C9223196",KSNODETYPE_EQUALIZATION_NOISE); +#define KSNODETYPE_EQUALIZATION_NOISE DEFINE_GUIDNAMED(KSNODETYPE_EQUALIZATION_NOISE) + +#define STATIC_KSNODETYPE_CD_PLAYER \ + DEFINE_USB_TERMINAL_GUID(0x0703) +DEFINE_GUIDSTRUCT("DFF220E3-F70F-11D0-B917-00A0C9223196",KSNODETYPE_CD_PLAYER); +#define KSNODETYPE_CD_PLAYER DEFINE_GUIDNAMED(KSNODETYPE_CD_PLAYER) + +#define STATIC_KSNODETYPE_DAT_IO_DIGITAL_AUDIO_TAPE \ + DEFINE_USB_TERMINAL_GUID(0x0704) +DEFINE_GUIDSTRUCT("DFF220E4-F70F-11D0-B917-00A0C9223196",KSNODETYPE_DAT_IO_DIGITAL_AUDIO_TAPE); +#define KSNODETYPE_DAT_IO_DIGITAL_AUDIO_TAPE DEFINE_GUIDNAMED(KSNODETYPE_DAT_IO_DIGITAL_AUDIO_TAPE) + +#define STATIC_KSNODETYPE_DCC_IO_DIGITAL_COMPACT_CASSETTE \ + DEFINE_USB_TERMINAL_GUID(0x0705) +DEFINE_GUIDSTRUCT("DFF220E5-F70F-11D0-B917-00A0C9223196",KSNODETYPE_DCC_IO_DIGITAL_COMPACT_CASSETTE); +#define KSNODETYPE_DCC_IO_DIGITAL_COMPACT_CASSETTE DEFINE_GUIDNAMED(KSNODETYPE_DCC_IO_DIGITAL_COMPACT_CASSETTE) + +#define STATIC_KSNODETYPE_MINIDISK \ + DEFINE_USB_TERMINAL_GUID(0x0706) +DEFINE_GUIDSTRUCT("DFF220E6-F70F-11D0-B917-00A0C9223196",KSNODETYPE_MINIDISK); +#define KSNODETYPE_MINIDISK DEFINE_GUIDNAMED(KSNODETYPE_MINIDISK) + +#define STATIC_KSNODETYPE_ANALOG_TAPE \ + DEFINE_USB_TERMINAL_GUID(0x0707) +DEFINE_GUIDSTRUCT("DFF220E7-F70F-11D0-B917-00A0C9223196",KSNODETYPE_ANALOG_TAPE); +#define KSNODETYPE_ANALOG_TAPE DEFINE_GUIDNAMED(KSNODETYPE_ANALOG_TAPE) + +#define STATIC_KSNODETYPE_PHONOGRAPH \ + DEFINE_USB_TERMINAL_GUID(0x0708) +DEFINE_GUIDSTRUCT("DFF220E8-F70F-11D0-B917-00A0C9223196",KSNODETYPE_PHONOGRAPH); +#define KSNODETYPE_PHONOGRAPH DEFINE_GUIDNAMED(KSNODETYPE_PHONOGRAPH) + +#define STATIC_KSNODETYPE_VCR_AUDIO \ + DEFINE_USB_TERMINAL_GUID(0x0708) +DEFINE_GUIDSTRUCT("DFF220E9-F70F-11D0-B917-00A0C9223196",KSNODETYPE_VCR_AUDIO); +#define KSNODETYPE_VCR_AUDIO DEFINE_GUIDNAMED(KSNODETYPE_VCR_AUDIO) + +#define STATIC_KSNODETYPE_VIDEO_DISC_AUDIO \ + DEFINE_USB_TERMINAL_GUID(0x070A) +DEFINE_GUIDSTRUCT("DFF220EA-F70F-11D0-B917-00A0C9223196",KSNODETYPE_VIDEO_DISC_AUDIO); +#define KSNODETYPE_VIDEO_DISC_AUDIO DEFINE_GUIDNAMED(KSNODETYPE_VIDEO_DISC_AUDIO) + +#define STATIC_KSNODETYPE_DVD_AUDIO \ + DEFINE_USB_TERMINAL_GUID(0x070B) +DEFINE_GUIDSTRUCT("DFF220EB-F70F-11D0-B917-00A0C9223196",KSNODETYPE_DVD_AUDIO); +#define KSNODETYPE_DVD_AUDIO DEFINE_GUIDNAMED(KSNODETYPE_DVD_AUDIO) + +#define STATIC_KSNODETYPE_TV_TUNER_AUDIO \ + DEFINE_USB_TERMINAL_GUID(0x070C) +DEFINE_GUIDSTRUCT("DFF220EC-F70F-11D0-B917-00A0C9223196",KSNODETYPE_TV_TUNER_AUDIO); +#define KSNODETYPE_TV_TUNER_AUDIO DEFINE_GUIDNAMED(KSNODETYPE_TV_TUNER_AUDIO) + +#define STATIC_KSNODETYPE_SATELLITE_RECEIVER_AUDIO \ + DEFINE_USB_TERMINAL_GUID(0x070D) +DEFINE_GUIDSTRUCT("DFF220ED-F70F-11D0-B917-00A0C9223196",KSNODETYPE_SATELLITE_RECEIVER_AUDIO); +#define KSNODETYPE_SATELLITE_RECEIVER_AUDIO DEFINE_GUIDNAMED(KSNODETYPE_SATELLITE_RECEIVER_AUDIO) + +#define STATIC_KSNODETYPE_CABLE_TUNER_AUDIO \ + DEFINE_USB_TERMINAL_GUID(0x070E) +DEFINE_GUIDSTRUCT("DFF220EE-F70F-11D0-B917-00A0C9223196",KSNODETYPE_CABLE_TUNER_AUDIO); +#define KSNODETYPE_CABLE_TUNER_AUDIO DEFINE_GUIDNAMED(KSNODETYPE_CABLE_TUNER_AUDIO) + +#define STATIC_KSNODETYPE_DSS_AUDIO \ + DEFINE_USB_TERMINAL_GUID(0x070F) +DEFINE_GUIDSTRUCT("DFF220EF-F70F-11D0-B917-00A0C9223196",KSNODETYPE_DSS_AUDIO); +#define KSNODETYPE_DSS_AUDIO DEFINE_GUIDNAMED(KSNODETYPE_DSS_AUDIO) + +#define STATIC_KSNODETYPE_RADIO_RECEIVER \ + DEFINE_USB_TERMINAL_GUID(0x0710) +DEFINE_GUIDSTRUCT("DFF220F0-F70F-11D0-B917-00A0C9223196",KSNODETYPE_RADIO_RECEIVER); +#define KSNODETYPE_RADIO_RECEIVER DEFINE_GUIDNAMED(KSNODETYPE_RADIO_RECEIVER) + +#define STATIC_KSNODETYPE_RADIO_TRANSMITTER \ + DEFINE_USB_TERMINAL_GUID(0x0711) +DEFINE_GUIDSTRUCT("DFF220F1-F70F-11D0-B917-00A0C9223196",KSNODETYPE_RADIO_TRANSMITTER); +#define KSNODETYPE_RADIO_TRANSMITTER DEFINE_GUIDNAMED(KSNODETYPE_RADIO_TRANSMITTER) + +#define STATIC_KSNODETYPE_MULTITRACK_RECORDER \ + DEFINE_USB_TERMINAL_GUID(0x0712) +DEFINE_GUIDSTRUCT("DFF220F2-F70F-11D0-B917-00A0C9223196",KSNODETYPE_MULTITRACK_RECORDER); +#define KSNODETYPE_MULTITRACK_RECORDER DEFINE_GUIDNAMED(KSNODETYPE_MULTITRACK_RECORDER) + +#define STATIC_KSNODETYPE_SYNTHESIZER \ + DEFINE_USB_TERMINAL_GUID(0x0713) +DEFINE_GUIDSTRUCT("DFF220F3-F70F-11D0-B917-00A0C9223196",KSNODETYPE_SYNTHESIZER); +#define KSNODETYPE_SYNTHESIZER DEFINE_GUIDNAMED(KSNODETYPE_SYNTHESIZER) + +#define STATIC_KSNODETYPE_SWSYNTH \ + 0x423274A0L,0x8B81,0x11D1,0xA0,0x50,0x00,0x00,0xF8,0x00,0x47,0x88 +DEFINE_GUIDSTRUCT("423274A0-8B81-11D1-A050-0000F8004788",KSNODETYPE_SWSYNTH); +#define KSNODETYPE_SWSYNTH DEFINE_GUIDNAMED(KSNODETYPE_SWSYNTH) + +#define STATIC_KSNODETYPE_SWMIDI \ + 0xCB9BEFA0L,0xA251,0x11D1,0xA0,0x50,0x00,0x00,0xF8,0x00,0x47,0x88 +DEFINE_GUIDSTRUCT("CB9BEFA0-A251-11D1-A050-0000F8004788",KSNODETYPE_SWMIDI); +#define KSNODETYPE_SWMIDI DEFINE_GUIDNAMED(KSNODETYPE_SWMIDI) + +#define STATIC_KSNODETYPE_DRM_DESCRAMBLE \ + 0xFFBB6E3FL,0xCCFE,0x4D84,0x90,0xD9,0x42,0x14,0x18,0xB0,0x3A,0x8E +DEFINE_GUIDSTRUCT("FFBB6E3F-CCFE-4D84-90D9-421418B03A8E",KSNODETYPE_DRM_DESCRAMBLE); +#define KSNODETYPE_DRM_DESCRAMBLE DEFINE_GUIDNAMED(KSNODETYPE_DRM_DESCRAMBLE) + +#define STATIC_KSCATEGORY_AUDIO \ + 0x6994AD04L,0x93EF,0x11D0,0xA3,0xCC,0x00,0xA0,0xC9,0x22,0x31,0x96 +DEFINE_GUIDSTRUCT("6994AD04-93EF-11D0-A3CC-00A0C9223196",KSCATEGORY_AUDIO); +#define KSCATEGORY_AUDIO DEFINE_GUIDNAMED(KSCATEGORY_AUDIO) + +#define STATIC_KSCATEGORY_VIDEO \ + 0x6994AD05L,0x93EF,0x11D0,0xA3,0xCC,0x00,0xA0,0xC9,0x22,0x31,0x96 +DEFINE_GUIDSTRUCT("6994AD05-93EF-11D0-A3CC-00A0C9223196",KSCATEGORY_VIDEO); +#define KSCATEGORY_VIDEO DEFINE_GUIDNAMED(KSCATEGORY_VIDEO) + +/* Added for Vista and later */ +#define STATIC_KSCATEGORY_REALTIME \ + 0xEB115FFCL, 0x10C8, 0x4964, 0x83, 0x1D, 0x6D, 0xCB, 0x02, 0xE6, 0xF2, 0x3F +DEFINE_GUIDSTRUCT("EB115FFC-10C8-4964-831D-6DCB02E6F23F", KSCATEGORY_REALTIME); +#define KSCATEGORY_REALTIME DEFINE_GUIDNAMED(KSCATEGORY_REALTIME) + +#define STATIC_KSCATEGORY_TEXT \ + 0x6994AD06L,0x93EF,0x11D0,0xA3,0xCC,0x00,0xA0,0xC9,0x22,0x31,0x96 +DEFINE_GUIDSTRUCT("6994AD06-93EF-11D0-A3CC-00A0C9223196",KSCATEGORY_TEXT); +#define KSCATEGORY_TEXT DEFINE_GUIDNAMED(KSCATEGORY_TEXT) + +#define STATIC_KSCATEGORY_NETWORK \ + 0x67C9CC3CL,0x69C4,0x11D2,0x87,0x59,0x00,0xA0,0xC9,0x22,0x31,0x96 +DEFINE_GUIDSTRUCT("67C9CC3C-69C4-11D2-8759-00A0C9223196",KSCATEGORY_NETWORK); +#define KSCATEGORY_NETWORK DEFINE_GUIDNAMED(KSCATEGORY_NETWORK) + +#define STATIC_KSCATEGORY_TOPOLOGY \ + 0xDDA54A40L,0x1E4C,0x11D1,0xA0,0x50,0x40,0x57,0x05,0xC1,0x00,0x00 +DEFINE_GUIDSTRUCT("DDA54A40-1E4C-11D1-A050-405705C10000",KSCATEGORY_TOPOLOGY); +#define KSCATEGORY_TOPOLOGY DEFINE_GUIDNAMED(KSCATEGORY_TOPOLOGY) + +#define STATIC_KSCATEGORY_VIRTUAL \ + 0x3503EAC4L,0x1F26,0x11D1,0x8A,0xB0,0x00,0xA0,0xC9,0x22,0x31,0x96 +DEFINE_GUIDSTRUCT("3503EAC4-1F26-11D1-8AB0-00A0C9223196",KSCATEGORY_VIRTUAL); +#define KSCATEGORY_VIRTUAL DEFINE_GUIDNAMED(KSCATEGORY_VIRTUAL) + +#define STATIC_KSCATEGORY_ACOUSTIC_ECHO_CANCEL \ + 0xBF963D80L,0xC559,0x11D0,0x8A,0x2B,0x00,0xA0,0xC9,0x25,0x5A,0xC1 +DEFINE_GUIDSTRUCT("BF963D80-C559-11D0-8A2B-00A0C9255AC1",KSCATEGORY_ACOUSTIC_ECHO_CANCEL); +#define KSCATEGORY_ACOUSTIC_ECHO_CANCEL DEFINE_GUIDNAMED(KSCATEGORY_ACOUSTIC_ECHO_CANCEL) + +#define STATIC_KSCATEGORY_SYSAUDIO \ + 0xA7C7A5B1L,0x5AF3,0x11D1,0x9C,0xED,0x00,0xA0,0x24,0xBF,0x04,0x07 +DEFINE_GUIDSTRUCT("A7C7A5B1-5AF3-11D1-9CED-00A024BF0407",KSCATEGORY_SYSAUDIO); +#define KSCATEGORY_SYSAUDIO DEFINE_GUIDNAMED(KSCATEGORY_SYSAUDIO) + +#define STATIC_KSCATEGORY_WDMAUD \ + 0x3E227E76L,0x690D,0x11D2,0x81,0x61,0x00,0x00,0xF8,0x77,0x5B,0xF1 +DEFINE_GUIDSTRUCT("3E227E76-690D-11D2-8161-0000F8775BF1",KSCATEGORY_WDMAUD); +#define KSCATEGORY_WDMAUD DEFINE_GUIDNAMED(KSCATEGORY_WDMAUD) + +#define STATIC_KSCATEGORY_AUDIO_GFX \ + 0x9BAF9572L,0x340C,0x11D3,0xAB,0xDC,0x00,0xA0,0xC9,0x0A,0xB1,0x6F +DEFINE_GUIDSTRUCT("9BAF9572-340C-11D3-ABDC-00A0C90AB16F",KSCATEGORY_AUDIO_GFX); +#define KSCATEGORY_AUDIO_GFX DEFINE_GUIDNAMED(KSCATEGORY_AUDIO_GFX) + +#define STATIC_KSCATEGORY_AUDIO_SPLITTER \ + 0x9EA331FAL,0xB91B,0x45F8,0x92,0x85,0xBD,0x2B,0xC7,0x7A,0xFC,0xDE +DEFINE_GUIDSTRUCT("9EA331FA-B91B-45F8-9285-BD2BC77AFCDE",KSCATEGORY_AUDIO_SPLITTER); +#define KSCATEGORY_AUDIO_SPLITTER DEFINE_GUIDNAMED(KSCATEGORY_AUDIO_SPLITTER) + +#define STATIC_KSCATEGORY_SYNTHESIZER STATIC_KSNODETYPE_SYNTHESIZER +#define KSCATEGORY_SYNTHESIZER KSNODETYPE_SYNTHESIZER + +#define STATIC_KSCATEGORY_DRM_DESCRAMBLE STATIC_KSNODETYPE_DRM_DESCRAMBLE +#define KSCATEGORY_DRM_DESCRAMBLE KSNODETYPE_DRM_DESCRAMBLE + +#define STATIC_KSCATEGORY_AUDIO_DEVICE \ + 0xFBF6F530L,0x07B9,0x11D2,0xA7,0x1E,0x00,0x00,0xF8,0x00,0x47,0x88 +DEFINE_GUIDSTRUCT("FBF6F530-07B9-11D2-A71E-0000F8004788",KSCATEGORY_AUDIO_DEVICE); +#define KSCATEGORY_AUDIO_DEVICE DEFINE_GUIDNAMED(KSCATEGORY_AUDIO_DEVICE) + +#define STATIC_KSCATEGORY_PREFERRED_WAVEOUT_DEVICE \ + 0xD6C5066EL,0x72C1,0x11D2,0x97,0x55,0x00,0x00,0xF8,0x00,0x47,0x88 +DEFINE_GUIDSTRUCT("D6C5066E-72C1-11D2-9755-0000F8004788",KSCATEGORY_PREFERRED_WAVEOUT_DEVICE); +#define KSCATEGORY_PREFERRED_WAVEOUT_DEVICE DEFINE_GUIDNAMED(KSCATEGORY_PREFERRED_WAVEOUT_DEVICE) + +#define STATIC_KSCATEGORY_PREFERRED_WAVEIN_DEVICE \ + 0xD6C50671L,0x72C1,0x11D2,0x97,0x55,0x00,0x00,0xF8,0x00,0x47,0x88 +DEFINE_GUIDSTRUCT("D6C50671-72C1-11D2-9755-0000F8004788",KSCATEGORY_PREFERRED_WAVEIN_DEVICE); +#define KSCATEGORY_PREFERRED_WAVEIN_DEVICE DEFINE_GUIDNAMED(KSCATEGORY_PREFERRED_WAVEIN_DEVICE) + +#define STATIC_KSCATEGORY_PREFERRED_MIDIOUT_DEVICE \ + 0xD6C50674L,0x72C1,0x11D2,0x97,0x55,0x00,0x00,0xF8,0x00,0x47,0x88 +DEFINE_GUIDSTRUCT("D6C50674-72C1-11D2-9755-0000F8004788",KSCATEGORY_PREFERRED_MIDIOUT_DEVICE); +#define KSCATEGORY_PREFERRED_MIDIOUT_DEVICE DEFINE_GUIDNAMED(KSCATEGORY_PREFERRED_MIDIOUT_DEVICE) + +#define STATIC_KSCATEGORY_WDMAUD_USE_PIN_NAME \ + 0x47A4FA20L,0xA251,0x11D1,0xA0,0x50,0x00,0x00,0xF8,0x00,0x47,0x88 +DEFINE_GUIDSTRUCT("47A4FA20-A251-11D1-A050-0000F8004788",KSCATEGORY_WDMAUD_USE_PIN_NAME); +#define KSCATEGORY_WDMAUD_USE_PIN_NAME DEFINE_GUIDNAMED(KSCATEGORY_WDMAUD_USE_PIN_NAME) + +#define STATIC_KSCATEGORY_ESCALANTE_PLATFORM_DRIVER \ + 0x74f3aea8L,0x9768,0x11d1,0x8e,0x07,0x00,0xa0,0xc9,0x5e,0xc2,0x2e +DEFINE_GUIDSTRUCT("74f3aea8-9768-11d1-8e07-00a0c95ec22e",KSCATEGORY_ESCALANTE_PLATFORM_DRIVER); +#define KSCATEGORY_ESCALANTE_PLATFORM_DRIVER DEFINE_GUIDNAMED(KSCATEGORY_ESCALANTE_PLATFORM_DRIVER) + +#define STATIC_KSDATAFORMAT_TYPE_VIDEO \ + 0x73646976L,0x0000,0x0010,0x80,0x00,0x00,0xaa,0x00,0x38,0x9b,0x71 +DEFINE_GUIDSTRUCT("73646976-0000-0010-8000-00aa00389b71",KSDATAFORMAT_TYPE_VIDEO); +#define KSDATAFORMAT_TYPE_VIDEO DEFINE_GUIDNAMED(KSDATAFORMAT_TYPE_VIDEO) + +#define STATIC_KSDATAFORMAT_TYPE_AUDIO \ + 0x73647561L,0x0000,0x0010,0x80,0x00,0x00,0xaa,0x00,0x38,0x9b,0x71 +DEFINE_GUIDSTRUCT("73647561-0000-0010-8000-00aa00389b71",KSDATAFORMAT_TYPE_AUDIO); +#define KSDATAFORMAT_TYPE_AUDIO DEFINE_GUIDNAMED(KSDATAFORMAT_TYPE_AUDIO) + +#define STATIC_KSDATAFORMAT_TYPE_TEXT \ + 0x73747874L,0x0000,0x0010,0x80,0x00,0x00,0xaa,0x00,0x38,0x9b,0x71 +DEFINE_GUIDSTRUCT("73747874-0000-0010-8000-00aa00389b71",KSDATAFORMAT_TYPE_TEXT); +#define KSDATAFORMAT_TYPE_TEXT DEFINE_GUIDNAMED(KSDATAFORMAT_TYPE_TEXT) + +#if !defined(DEFINE_WAVEFORMATEX_GUID) +#define DEFINE_WAVEFORMATEX_GUID(x) \ + (USHORT)(x),0x0000,0x0010,0x80,0x00,0x00,0xaa,0x00,0x38,0x9b,0x71 +#endif + +#define STATIC_KSDATAFORMAT_SUBTYPE_WAVEFORMATEX \ + 0x00000000L,0x0000,0x0010,0x80,0x00,0x00,0xaa,0x00,0x38,0x9b,0x71 +DEFINE_GUIDSTRUCT("00000000-0000-0010-8000-00aa00389b71",KSDATAFORMAT_SUBTYPE_WAVEFORMATEX); +#define KSDATAFORMAT_SUBTYPE_WAVEFORMATEX DEFINE_GUIDNAMED(KSDATAFORMAT_SUBTYPE_WAVEFORMATEX) + +#define INIT_WAVEFORMATEX_GUID(Guid,x) \ +{ \ + *(Guid) = KSDATAFORMAT_SUBTYPE_WAVEFORMATEX; \ + (Guid)->Data1 = (USHORT)(x); \ +} + +#define EXTRACT_WAVEFORMATEX_ID(Guid) \ + (USHORT)((Guid)->Data1) + +#define IS_VALID_WAVEFORMATEX_GUID(Guid) \ + (!memcmp(((PUSHORT)&KSDATAFORMAT_SUBTYPE_WAVEFORMATEX) + 1, ((PUSHORT)(Guid)) + 1,sizeof(GUID) - sizeof(USHORT))) + +#ifndef INIT_MMREG_MID +#define INIT_MMREG_MID(guid,id) \ +{ \ + (guid)->Data1 = 0xd5a47fa7 + (USHORT)(id); \ + (guid)->Data2 = 0x6d98; \ + (guid)->Data3 = 0x11d1; \ + (guid)->Data4[0] = 0xa2; \ + (guid)->Data4[1] = 0x1a; \ + (guid)->Data4[2] = 0x00; \ + (guid)->Data4[3] = 0xa0; \ + (guid)->Data4[4] = 0xc9; \ + (guid)->Data4[5] = 0x22; \ + (guid)->Data4[6] = 0x31; \ + (guid)->Data4[7] = 0x96; \ +} +#define EXTRACT_MMREG_MID(guid) \ + (USHORT)((guid)->Data1 - 0xd5a47fa7) +#define DEFINE_MMREG_MID_GUID(id) \ + 0xd5a47fa7+(USHORT)(id),0x6d98,0x11d1,0xa2,0x1a,0x00,0xa0,0xc9,0x22,0x31,0x96 + +#define IS_COMPATIBLE_MMREG_MID(guid) \ + (((guid)->Data1 >= 0xd5a47fa7) && \ + ((guid)->Data1 < 0xd5a47fa7 + 0xffff) && \ + ((guid)->Data2 == 0x6d98) && \ + ((guid)->Data3 == 0x11d1) && \ + ((guid)->Data4[0] == 0xa2) && \ + ((guid)->Data4[1] == 0x1a) && \ + ((guid)->Data4[2] == 0x00) && \ + ((guid)->Data4[3] == 0xa0) && \ + ((guid)->Data4[4] == 0xc9) && \ + ((guid)->Data4[5] == 0x22) && \ + ((guid)->Data4[6] == 0x31) && \ + ((guid)->Data4[7] == 0x96) ) +#endif /* INIT_MMREG_MID */ + +#ifndef INIT_MMREG_PID +#define INIT_MMREG_PID(guid,id) \ +{ \ + (guid)->Data1 = 0xe36dc2ac + (USHORT)(id); \ + (guid)->Data2 = 0x6d9a; \ + (guid)->Data3 = 0x11d1; \ + (guid)->Data4[0] = 0xa2; \ + (guid)->Data4[1] = 0x1a; \ + (guid)->Data4[2] = 0x00; \ + (guid)->Data4[3] = 0xa0; \ + (guid)->Data4[4] = 0xc9; \ + (guid)->Data4[5] = 0x22; \ + (guid)->Data4[6] = 0x31; \ + (guid)->Data4[7] = 0x96; \ +} +#define EXTRACT_MMREG_PID(guid) \ + (USHORT)((guid)->Data1 - 0xe36dc2ac) +#define DEFINE_MMREG_PID_GUID(id) \ + 0xe36dc2ac+(USHORT)(id),0x6d9a,0x11d1,0xa2,0x1a,0x00,0xa0,0xc9,0x22,0x31,0x96 + +#define IS_COMPATIBLE_MMREG_PID(guid) \ + (((guid)->Data1 >= 0xe36dc2ac) && \ + ((guid)->Data1 < 0xe36dc2ac + 0xffff) && \ + ((guid)->Data2 == 0x6d9a) && \ + ((guid)->Data3 == 0x11d1) && \ + ((guid)->Data4[0] == 0xa2) && \ + ((guid)->Data4[1] == 0x1a) && \ + ((guid)->Data4[2] == 0x00) && \ + ((guid)->Data4[3] == 0xa0) && \ + ((guid)->Data4[4] == 0xc9) && \ + ((guid)->Data4[5] == 0x22) && \ + ((guid)->Data4[6] == 0x31) && \ + ((guid)->Data4[7] == 0x96) ) +#endif /* INIT_MMREG_PID */ + +#define STATIC_KSDATAFORMAT_SUBTYPE_ANALOG \ + 0x6dba3190L,0x67bd,0x11cf,0xa0,0xf7,0x00,0x20,0xaf,0xd1,0x56,0xe4 +DEFINE_GUIDSTRUCT("6dba3190-67bd-11cf-a0f7-0020afd156e4",KSDATAFORMAT_SUBTYPE_ANALOG); +#define KSDATAFORMAT_SUBTYPE_ANALOG DEFINE_GUIDNAMED(KSDATAFORMAT_SUBTYPE_ANALOG) + +#define STATIC_KSDATAFORMAT_SUBTYPE_PCM \ + DEFINE_WAVEFORMATEX_GUID(WAVE_FORMAT_PCM) +DEFINE_GUIDSTRUCT("00000001-0000-0010-8000-00aa00389b71",KSDATAFORMAT_SUBTYPE_PCM); +#define KSDATAFORMAT_SUBTYPE_PCM DEFINE_GUIDNAMED(KSDATAFORMAT_SUBTYPE_PCM) + +#ifdef _INC_MMREG +#define STATIC_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT \ + DEFINE_WAVEFORMATEX_GUID(WAVE_FORMAT_IEEE_FLOAT) +DEFINE_GUIDSTRUCT("00000003-0000-0010-8000-00aa00389b71",KSDATAFORMAT_SUBTYPE_IEEE_FLOAT); +#define KSDATAFORMAT_SUBTYPE_IEEE_FLOAT DEFINE_GUIDNAMED(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT) + +#define STATIC_KSDATAFORMAT_SUBTYPE_DRM \ + DEFINE_WAVEFORMATEX_GUID(WAVE_FORMAT_DRM) +DEFINE_GUIDSTRUCT("00000009-0000-0010-8000-00aa00389b71",KSDATAFORMAT_SUBTYPE_DRM); +#define KSDATAFORMAT_SUBTYPE_DRM DEFINE_GUIDNAMED(KSDATAFORMAT_SUBTYPE_DRM) + +#define STATIC_KSDATAFORMAT_SUBTYPE_ALAW \ + DEFINE_WAVEFORMATEX_GUID(WAVE_FORMAT_ALAW) +DEFINE_GUIDSTRUCT("00000006-0000-0010-8000-00aa00389b71",KSDATAFORMAT_SUBTYPE_ALAW); +#define KSDATAFORMAT_SUBTYPE_ALAW DEFINE_GUIDNAMED(KSDATAFORMAT_SUBTYPE_ALAW) + +#define STATIC_KSDATAFORMAT_SUBTYPE_MULAW \ + DEFINE_WAVEFORMATEX_GUID(WAVE_FORMAT_MULAW) +DEFINE_GUIDSTRUCT("00000007-0000-0010-8000-00aa00389b71",KSDATAFORMAT_SUBTYPE_MULAW); +#define KSDATAFORMAT_SUBTYPE_MULAW DEFINE_GUIDNAMED(KSDATAFORMAT_SUBTYPE_MULAW) + +#define STATIC_KSDATAFORMAT_SUBTYPE_ADPCM \ + DEFINE_WAVEFORMATEX_GUID(WAVE_FORMAT_ADPCM) +DEFINE_GUIDSTRUCT("00000002-0000-0010-8000-00aa00389b71",KSDATAFORMAT_SUBTYPE_ADPCM); +#define KSDATAFORMAT_SUBTYPE_ADPCM DEFINE_GUIDNAMED(KSDATAFORMAT_SUBTYPE_ADPCM) + +#define STATIC_KSDATAFORMAT_SUBTYPE_MPEG \ + DEFINE_WAVEFORMATEX_GUID(WAVE_FORMAT_MPEG) +DEFINE_GUIDSTRUCT("00000050-0000-0010-8000-00aa00389b71",KSDATAFORMAT_SUBTYPE_MPEG); +#define KSDATAFORMAT_SUBTYPE_MPEG DEFINE_GUIDNAMED(KSDATAFORMAT_SUBTYPE_MPEG) +#endif /* _INC_MMREG */ + +#define STATIC_KSDATAFORMAT_SPECIFIER_VC_ID \ + 0xAD98D184L,0xAAC3,0x11D0,0xA4,0x1C,0x00,0xA0,0xC9,0x22,0x31,0x96 +DEFINE_GUIDSTRUCT("AD98D184-AAC3-11D0-A41C-00A0C9223196",KSDATAFORMAT_SPECIFIER_VC_ID); +#define KSDATAFORMAT_SPECIFIER_VC_ID DEFINE_GUIDNAMED(KSDATAFORMAT_SPECIFIER_VC_ID) + +#define STATIC_KSDATAFORMAT_SPECIFIER_WAVEFORMATEX \ + 0x05589f81L,0xc356,0x11ce,0xbf,0x01,0x00,0xaa,0x00,0x55,0x59,0x5a +DEFINE_GUIDSTRUCT("05589f81-c356-11ce-bf01-00aa0055595a",KSDATAFORMAT_SPECIFIER_WAVEFORMATEX); +#define KSDATAFORMAT_SPECIFIER_WAVEFORMATEX DEFINE_GUIDNAMED(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX) + +#define STATIC_KSDATAFORMAT_SPECIFIER_DSOUND \ + 0x518590a2L,0xa184,0x11d0,0x85,0x22,0x00,0xc0,0x4f,0xd9,0xba,0xf3 +DEFINE_GUIDSTRUCT("518590a2-a184-11d0-8522-00c04fd9baf3",KSDATAFORMAT_SPECIFIER_DSOUND); +#define KSDATAFORMAT_SPECIFIER_DSOUND DEFINE_GUIDNAMED(KSDATAFORMAT_SPECIFIER_DSOUND) + +#if defined(_INC_MMSYSTEM) || defined(_INC_MMREG) +#if !defined(PACK_PRAGMAS_NOT_SUPPORTED) +#include +#endif +typedef struct { + KSDATAFORMAT DataFormat; + WAVEFORMATEX WaveFormatEx; +} KSDATAFORMAT_WAVEFORMATEX,*PKSDATAFORMAT_WAVEFORMATEX; + +#ifndef _WAVEFORMATEXTENSIBLE_ +#define _WAVEFORMATEXTENSIBLE_ +typedef struct { + WAVEFORMATEX Format; + union { + WORD wValidBitsPerSample; + WORD wSamplesPerBlock; + WORD wReserved; + } Samples; + DWORD dwChannelMask; + + GUID SubFormat; +} WAVEFORMATEXTENSIBLE,*PWAVEFORMATEXTENSIBLE; +#endif /* _WAVEFORMATEXTENSIBLE_ */ + +#if !defined(WAVE_FORMAT_EXTENSIBLE) +#define WAVE_FORMAT_EXTENSIBLE 0xFFFE +#endif + +typedef struct { + ULONG Flags; + ULONG Control; + WAVEFORMATEX WaveFormatEx; +} KSDSOUND_BUFFERDESC,*PKSDSOUND_BUFFERDESC; + +typedef struct { + KSDATAFORMAT DataFormat; + KSDSOUND_BUFFERDESC BufferDesc; +} KSDATAFORMAT_DSOUND,*PKSDATAFORMAT_DSOUND; + +#if !defined(PACK_PRAGMAS_NOT_SUPPORTED) +#include +#endif +#endif /* defined(_INC_MMSYSTEM) || defined(_INC_MMREG) */ + +#define KSDSOUND_BUFFER_PRIMARY 0x00000001 +#define KSDSOUND_BUFFER_STATIC 0x00000002 +#define KSDSOUND_BUFFER_LOCHARDWARE 0x00000004 +#define KSDSOUND_BUFFER_LOCSOFTWARE 0x00000008 + +#define KSDSOUND_BUFFER_CTRL_3D 0x00000001 +#define KSDSOUND_BUFFER_CTRL_FREQUENCY 0x00000002 +#define KSDSOUND_BUFFER_CTRL_PAN 0x00000004 +#define KSDSOUND_BUFFER_CTRL_VOLUME 0x00000008 +#define KSDSOUND_BUFFER_CTRL_POSITIONNOTIFY 0x00000010 + +typedef struct { + DWORDLONG PlayOffset; + DWORDLONG WriteOffset; +} KSAUDIO_POSITION,*PKSAUDIO_POSITION; + +typedef struct _DS3DVECTOR { + __MINGW_EXTENSION union { + FLOAT x; + FLOAT dvX; + }; + __MINGW_EXTENSION union { + FLOAT y; + FLOAT dvY; + }; + __MINGW_EXTENSION union { + FLOAT z; + FLOAT dvZ; + }; +} DS3DVECTOR,*PDS3DVECTOR; + +#define STATIC_KSPROPSETID_DirectSound3DListener \ + 0x437b3414L,0xd060,0x11d0,0x85,0x83,0x00,0xc0,0x4f,0xd9,0xba,0xf3 +DEFINE_GUIDSTRUCT("437b3414-d060-11d0-8583-00c04fd9baf3",KSPROPSETID_DirectSound3DListener); +#define KSPROPSETID_DirectSound3DListener DEFINE_GUIDNAMED(KSPROPSETID_DirectSound3DListener) + +typedef enum { + KSPROPERTY_DIRECTSOUND3DLISTENER_ALL, + KSPROPERTY_DIRECTSOUND3DLISTENER_POSITION, + KSPROPERTY_DIRECTSOUND3DLISTENER_VELOCITY, + KSPROPERTY_DIRECTSOUND3DLISTENER_ORIENTATION, + KSPROPERTY_DIRECTSOUND3DLISTENER_DISTANCEFACTOR, + KSPROPERTY_DIRECTSOUND3DLISTENER_ROLLOFFFACTOR, + KSPROPERTY_DIRECTSOUND3DLISTENER_DOPPLERFACTOR, + KSPROPERTY_DIRECTSOUND3DLISTENER_BATCH, + KSPROPERTY_DIRECTSOUND3DLISTENER_ALLOCATION +} KSPROPERTY_DIRECTSOUND3DLISTENER; + +typedef struct { + DS3DVECTOR Position; + DS3DVECTOR Velocity; + DS3DVECTOR OrientFront; + DS3DVECTOR OrientTop; + FLOAT DistanceFactor; + FLOAT RolloffFactor; + FLOAT DopplerFactor; +} KSDS3D_LISTENER_ALL,*PKSDS3D_LISTENER_ALL; + +typedef struct { + DS3DVECTOR Front; + DS3DVECTOR Top; +} KSDS3D_LISTENER_ORIENTATION,*PKSDS3D_LISTENER_ORIENTATION; + +#define STATIC_KSPROPSETID_DirectSound3DBuffer \ + 0x437b3411L,0xd060,0x11d0,0x85,0x83,0x00,0xc0,0x4f,0xd9,0xba,0xf3 +DEFINE_GUIDSTRUCT("437b3411-d060-11d0-8583-00c04fd9baf3",KSPROPSETID_DirectSound3DBuffer); +#define KSPROPSETID_DirectSound3DBuffer DEFINE_GUIDNAMED(KSPROPSETID_DirectSound3DBuffer) + +typedef enum { + KSPROPERTY_DIRECTSOUND3DBUFFER_ALL, + KSPROPERTY_DIRECTSOUND3DBUFFER_POSITION, + KSPROPERTY_DIRECTSOUND3DBUFFER_VELOCITY, + KSPROPERTY_DIRECTSOUND3DBUFFER_CONEANGLES, + KSPROPERTY_DIRECTSOUND3DBUFFER_CONEORIENTATION, + KSPROPERTY_DIRECTSOUND3DBUFFER_CONEOUTSIDEVOLUME, + KSPROPERTY_DIRECTSOUND3DBUFFER_MINDISTANCE, + KSPROPERTY_DIRECTSOUND3DBUFFER_MAXDISTANCE, + KSPROPERTY_DIRECTSOUND3DBUFFER_MODE +} KSPROPERTY_DIRECTSOUND3DBUFFER; + +typedef struct { + DS3DVECTOR Position; + DS3DVECTOR Velocity; + ULONG InsideConeAngle; + ULONG OutsideConeAngle; + DS3DVECTOR ConeOrientation; + LONG ConeOutsideVolume; + FLOAT MinDistance; + FLOAT MaxDistance; + ULONG Mode; +} KSDS3D_BUFFER_ALL,*PKSDS3D_BUFFER_ALL; + +typedef struct { + ULONG InsideConeAngle; + ULONG OutsideConeAngle; +} KSDS3D_BUFFER_CONE_ANGLES,*PKSDS3D_BUFFER_CONE_ANGLES; + +#define KSAUDIO_STEREO_SPEAKER_GEOMETRY_HEADPHONE (-1) +#define KSAUDIO_STEREO_SPEAKER_GEOMETRY_MIN 5 +#define KSAUDIO_STEREO_SPEAKER_GEOMETRY_NARROW 10 +#define KSAUDIO_STEREO_SPEAKER_GEOMETRY_WIDE 20 +#define KSAUDIO_STEREO_SPEAKER_GEOMETRY_MAX 180 + +#define KSDSOUND_3D_MODE_NORMAL 0x00000000 +#define KSDSOUND_3D_MODE_HEADRELATIVE 0x00000001 +#define KSDSOUND_3D_MODE_DISABLE 0x00000002 + +#define KSDSOUND_BUFFER_CTRL_HRTF_3D 0x40000000 + +typedef struct { + ULONG Size; + ULONG Enabled; + WINBOOL SwapChannels; + WINBOOL ZeroAzimuth; + WINBOOL CrossFadeOutput; + ULONG FilterSize; +} KSDS3D_HRTF_PARAMS_MSG,*PKSDS3D_HRTF_PARAMS_MSG; + +typedef enum { + FULL_FILTER, + LIGHT_FILTER, + KSDS3D_FILTER_QUALITY_COUNT +} KSDS3D_HRTF_FILTER_QUALITY; + +typedef struct { + ULONG Size; + KSDS3D_HRTF_FILTER_QUALITY Quality; + FLOAT SampleRate; + ULONG MaxFilterSize; + ULONG FilterTransientMuteLength; + ULONG FilterOverlapBufferLength; + ULONG OutputOverlapBufferLength; + ULONG Reserved; +} KSDS3D_HRTF_INIT_MSG,*PKSDS3D_HRTF_INIT_MSG; + +typedef enum { + FLOAT_COEFF, + SHORT_COEFF, + KSDS3D_COEFF_COUNT +} KSDS3D_HRTF_COEFF_FORMAT; + +typedef enum { + DIRECT_FORM, + CASCADE_FORM, + KSDS3D_FILTER_METHOD_COUNT +} KSDS3D_HRTF_FILTER_METHOD; + +typedef enum { + DS3D_HRTF_VERSION_1 +} KSDS3D_HRTF_FILTER_VERSION; + +typedef struct { + KSDS3D_HRTF_FILTER_METHOD FilterMethod; + KSDS3D_HRTF_COEFF_FORMAT CoeffFormat; + KSDS3D_HRTF_FILTER_VERSION Version; + ULONG Reserved; +} KSDS3D_HRTF_FILTER_FORMAT_MSG,*PKSDS3D_HRTF_FILTER_FORMAT_MSG; + +#define STATIC_KSPROPSETID_Hrtf3d \ + 0xb66decb0L,0xa083,0x11d0,0x85,0x1e,0x00,0xc0,0x4f,0xd9,0xba,0xf3 +DEFINE_GUIDSTRUCT("b66decb0-a083-11d0-851e-00c04fd9baf3",KSPROPSETID_Hrtf3d); +#define KSPROPSETID_Hrtf3d DEFINE_GUIDNAMED(KSPROPSETID_Hrtf3d) + +typedef enum { + KSPROPERTY_HRTF3D_PARAMS = 0, + KSPROPERTY_HRTF3D_INITIALIZE, + KSPROPERTY_HRTF3D_FILTER_FORMAT +} KSPROPERTY_HRTF3D; + +typedef struct { + LONG Channel; + FLOAT VolSmoothScale; + FLOAT TotalDryAttenuation; + FLOAT TotalWetAttenuation; + LONG SmoothFrequency; + LONG Delay; +} KSDS3D_ITD_PARAMS,*PKSDS3D_ITD_PARAMS; + +typedef struct { + ULONG Enabled; + KSDS3D_ITD_PARAMS LeftParams; + KSDS3D_ITD_PARAMS RightParams; + ULONG Reserved; +} KSDS3D_ITD_PARAMS_MSG,*PKSDS3D_ITD_PARAMS_MSG; + +#define STATIC_KSPROPSETID_Itd3d \ + 0x6429f090L,0x9fd9,0x11d0,0xa7,0x5b,0x00,0xa0,0xc9,0x03,0x65,0xe3 +DEFINE_GUIDSTRUCT("6429f090-9fd9-11d0-a75b-00a0c90365e3",KSPROPSETID_Itd3d); +#define KSPROPSETID_Itd3d DEFINE_GUIDNAMED(KSPROPSETID_Itd3d) + +typedef enum { + KSPROPERTY_ITD3D_PARAMS = 0 +} KSPROPERTY_ITD3D; + +typedef struct { + KSDATARANGE DataRange; + ULONG MaximumChannels; + ULONG MinimumBitsPerSample; + ULONG MaximumBitsPerSample; + ULONG MinimumSampleFrequency; + ULONG MaximumSampleFrequency; +} KSDATARANGE_AUDIO,*PKSDATARANGE_AUDIO; + +#define STATIC_KSDATAFORMAT_SUBTYPE_RIFF \ + 0x4995DAEEL,0x9EE6,0x11D0,0xA4,0x0E,0x00,0xA0,0xC9,0x22,0x31,0x96 +DEFINE_GUIDSTRUCT("4995DAEE-9EE6-11D0-A40E-00A0C9223196",KSDATAFORMAT_SUBTYPE_RIFF); +#define KSDATAFORMAT_SUBTYPE_RIFF DEFINE_GUIDNAMED(KSDATAFORMAT_SUBTYPE_RIFF) + +#define STATIC_KSDATAFORMAT_SUBTYPE_RIFFWAVE \ + 0xe436eb8bL,0x524f,0x11ce,0x9f,0x53,0x00,0x20,0xaf,0x0b,0xa7,0x70 +DEFINE_GUIDSTRUCT("e436eb8b-524f-11ce-9f53-0020af0ba770",KSDATAFORMAT_SUBTYPE_RIFFWAVE); +#define KSDATAFORMAT_SUBTYPE_RIFFWAVE DEFINE_GUIDNAMED(KSDATAFORMAT_SUBTYPE_RIFFWAVE) + +#define STATIC_KSPROPSETID_Bibliographic \ + 0x07BA150EL,0xE2B1,0x11D0,0xAC,0x17,0x00,0xA0,0xC9,0x22,0x31,0x96 +DEFINE_GUIDSTRUCT("07BA150E-E2B1-11D0-AC17-00A0C9223196",KSPROPSETID_Bibliographic); +#define KSPROPSETID_Bibliographic DEFINE_GUIDNAMED(KSPROPSETID_Bibliographic) + +typedef enum { + KSPROPERTY_BIBLIOGRAPHIC_LEADER = 'RDL ', + KSPROPERTY_BIBLIOGRAPHIC_LCCN = '010 ', + KSPROPERTY_BIBLIOGRAPHIC_ISBN = '020 ', + KSPROPERTY_BIBLIOGRAPHIC_ISSN = '220 ', + KSPROPERTY_BIBLIOGRAPHIC_CATALOGINGSOURCE = '040 ', + KSPROPERTY_BIBLIOGRAPHIC_MAINPERSONALNAME = '001 ', + KSPROPERTY_BIBLIOGRAPHIC_MAINCORPORATEBODY = '011 ', + KSPROPERTY_BIBLIOGRAPHIC_MAINMEETINGNAME = '111 ', + KSPROPERTY_BIBLIOGRAPHIC_MAINUNIFORMTITLE = '031 ', + KSPROPERTY_BIBLIOGRAPHIC_UNIFORMTITLE = '042 ', + KSPROPERTY_BIBLIOGRAPHIC_TITLESTATEMENT = '542 ', + KSPROPERTY_BIBLIOGRAPHIC_VARYINGFORMTITLE = '642 ', + KSPROPERTY_BIBLIOGRAPHIC_PUBLICATION = '062 ', + KSPROPERTY_BIBLIOGRAPHIC_PHYSICALDESCRIPTION = '003 ', + KSPROPERTY_BIBLIOGRAPHIC_ADDEDENTRYTITLE = '044 ', + KSPROPERTY_BIBLIOGRAPHIC_SERIESSTATEMENT = '094 ', + KSPROPERTY_BIBLIOGRAPHIC_GENERALNOTE = '005 ', + KSPROPERTY_BIBLIOGRAPHIC_BIBLIOGRAPHYNOTE = '405 ', + KSPROPERTY_BIBLIOGRAPHIC_CONTENTSNOTE = '505 ', + KSPROPERTY_BIBLIOGRAPHIC_CREATIONCREDIT = '805 ', + KSPROPERTY_BIBLIOGRAPHIC_CITATION = '015 ', + KSPROPERTY_BIBLIOGRAPHIC_PARTICIPANT = '115 ', + KSPROPERTY_BIBLIOGRAPHIC_SUMMARY = '025 ', + KSPROPERTY_BIBLIOGRAPHIC_TARGETAUDIENCE = '125 ', + KSPROPERTY_BIBLIOGRAPHIC_ADDEDFORMAVAILABLE = '035 ', + KSPROPERTY_BIBLIOGRAPHIC_SYSTEMDETAILS = '835 ', + KSPROPERTY_BIBLIOGRAPHIC_AWARDS = '685 ', + KSPROPERTY_BIBLIOGRAPHIC_ADDEDENTRYPERSONALNAME = '006 ', + KSPROPERTY_BIBLIOGRAPHIC_ADDEDENTRYTOPICALTERM = '056 ', + KSPROPERTY_BIBLIOGRAPHIC_ADDEDENTRYGEOGRAPHIC = '156 ', + KSPROPERTY_BIBLIOGRAPHIC_INDEXTERMGENRE = '556 ', + KSPROPERTY_BIBLIOGRAPHIC_INDEXTERMCURRICULUM = '856 ', + KSPROPERTY_BIBLIOGRAPHIC_ADDEDENTRYUNIFORMTITLE = '037 ', + KSPROPERTY_BIBLIOGRAPHIC_ADDEDENTRYRELATED = '047 ', + KSPROPERTY_BIBLIOGRAPHIC_SERIESSTATEMENTPERSONALNAME = '008 ', + KSPROPERTY_BIBLIOGRAPHIC_SERIESSTATEMENTUNIFORMTITLE = '038 ' +} KSPROPERTY_BIBLIOGRAPHIC; + +#define STATIC_KSPROPSETID_TopologyNode \ + 0x45FFAAA1L,0x6E1B,0x11D0,0xBC,0xF2,0x44,0x45,0x53,0x54,0x00,0x00 +DEFINE_GUIDSTRUCT("45FFAAA1-6E1B-11D0-BCF2-444553540000",KSPROPSETID_TopologyNode); +#define KSPROPSETID_TopologyNode DEFINE_GUIDNAMED(KSPROPSETID_TopologyNode) + +typedef enum { + KSPROPERTY_TOPOLOGYNODE_ENABLE = 1, + KSPROPERTY_TOPOLOGYNODE_RESET +} KSPROPERTY_TOPOLOGYNODE; + +#define STATIC_KSPROPSETID_RtAudio \ + 0xa855a48c,0x2f78,0x4729,0x90,0x51,0x19,0x68,0x74,0x6b,0x9e,0xef +DEFINE_GUIDSTRUCT("A855A48C-2F78-4729-9051-1968746B9EEF",KSPROPSETID_RtAudio); +#define KSPROPSETID_RtAudio DEFINE_GUIDNAMED(KSPROPSETID_RtAudio) + +typedef enum { + KSPROPERTY_RTAUDIO_GETPOSITIONFUNCTION, + /* Added for Vista and later */ + KSPROPERTY_RTAUDIO_BUFFER, + KSPROPERTY_RTAUDIO_HWLATENCY, + KSPROPERTY_RTAUDIO_POSITIONREGISTER, + KSPROPERTY_RTAUDIO_CLOCKREGISTER, + KSPROPERTY_RTAUDIO_BUFFER_WITH_NOTIFICATION, + KSPROPERTY_RTAUDIO_REGISTER_NOTIFICATION_EVENT, + KSPROPERTY_RTAUDIO_UNREGISTER_NOTIFICATION_EVENT +} KSPROPERTY_RTAUDIO; + +#define STATIC_KSPROPSETID_DrmAudioStream \ + 0x2f2c8ddd,0x4198,0x4fac,0xba,0x29,0x61,0xbb,0x5,0xb7,0xde,0x6 +DEFINE_GUIDSTRUCT("2F2C8DDD-4198-4fac-BA29-61BB05B7DE06",KSPROPSETID_DrmAudioStream); +#define KSPROPSETID_DrmAudioStream DEFINE_GUIDNAMED(KSPROPSETID_DrmAudioStream) + +typedef enum { + KSPROPERTY_DRMAUDIOSTREAM_CONTENTID +} KSPROPERTY_DRMAUDIOSTREAM; + +#define STATIC_KSPROPSETID_Audio \ + 0x45FFAAA0L,0x6E1B,0x11D0,0xBC,0xF2,0x44,0x45,0x53,0x54,0x00,0x00 +DEFINE_GUIDSTRUCT("45FFAAA0-6E1B-11D0-BCF2-444553540000",KSPROPSETID_Audio); +#define KSPROPSETID_Audio DEFINE_GUIDNAMED(KSPROPSETID_Audio) + +typedef enum { + KSPROPERTY_AUDIO_LATENCY = 1, + KSPROPERTY_AUDIO_COPY_PROTECTION, + KSPROPERTY_AUDIO_CHANNEL_CONFIG, + KSPROPERTY_AUDIO_VOLUMELEVEL, + KSPROPERTY_AUDIO_POSITION, + KSPROPERTY_AUDIO_DYNAMIC_RANGE, + KSPROPERTY_AUDIO_QUALITY, + KSPROPERTY_AUDIO_SAMPLING_RATE, + KSPROPERTY_AUDIO_DYNAMIC_SAMPLING_RATE, + KSPROPERTY_AUDIO_MIX_LEVEL_TABLE, + KSPROPERTY_AUDIO_MIX_LEVEL_CAPS, + KSPROPERTY_AUDIO_MUX_SOURCE, + KSPROPERTY_AUDIO_MUTE, + KSPROPERTY_AUDIO_BASS, + KSPROPERTY_AUDIO_MID, + KSPROPERTY_AUDIO_TREBLE, + KSPROPERTY_AUDIO_BASS_BOOST, + KSPROPERTY_AUDIO_EQ_LEVEL, + KSPROPERTY_AUDIO_NUM_EQ_BANDS, + KSPROPERTY_AUDIO_EQ_BANDS, + KSPROPERTY_AUDIO_AGC, + KSPROPERTY_AUDIO_DELAY, + KSPROPERTY_AUDIO_LOUDNESS, + KSPROPERTY_AUDIO_WIDE_MODE, + KSPROPERTY_AUDIO_WIDENESS, + KSPROPERTY_AUDIO_REVERB_LEVEL, + KSPROPERTY_AUDIO_CHORUS_LEVEL, + KSPROPERTY_AUDIO_DEV_SPECIFIC, + KSPROPERTY_AUDIO_DEMUX_DEST, + KSPROPERTY_AUDIO_STEREO_ENHANCE, + KSPROPERTY_AUDIO_MANUFACTURE_GUID, + KSPROPERTY_AUDIO_PRODUCT_GUID, + KSPROPERTY_AUDIO_CPU_RESOURCES, + KSPROPERTY_AUDIO_STEREO_SPEAKER_GEOMETRY, + KSPROPERTY_AUDIO_SURROUND_ENCODE, + KSPROPERTY_AUDIO_3D_INTERFACE, + KSPROPERTY_AUDIO_PEAKMETER, + KSPROPERTY_AUDIO_ALGORITHM_INSTANCE, + KSPROPERTY_AUDIO_FILTER_STATE, + KSPROPERTY_AUDIO_PREFERRED_STATUS +} KSPROPERTY_AUDIO; + +#define KSAUDIO_QUALITY_WORST 0x0 +#define KSAUDIO_QUALITY_PC 0x1 +#define KSAUDIO_QUALITY_BASIC 0x2 +#define KSAUDIO_QUALITY_ADVANCED 0x3 + +#define KSAUDIO_CPU_RESOURCES_NOT_HOST_CPU 0x00000000 +#define KSAUDIO_CPU_RESOURCES_HOST_CPU 0x7FFFFFFF + +typedef struct { + WINBOOL fCopyrighted; + WINBOOL fOriginal; +} KSAUDIO_COPY_PROTECTION,*PKSAUDIO_COPY_PROTECTION; + +typedef struct { + LONG ActiveSpeakerPositions; +} KSAUDIO_CHANNEL_CONFIG,*PKSAUDIO_CHANNEL_CONFIG; + +#define SPEAKER_FRONT_LEFT 0x1 +#define SPEAKER_FRONT_RIGHT 0x2 +#define SPEAKER_FRONT_CENTER 0x4 +#define SPEAKER_LOW_FREQUENCY 0x8 +#define SPEAKER_BACK_LEFT 0x10 +#define SPEAKER_BACK_RIGHT 0x20 +#define SPEAKER_FRONT_LEFT_OF_CENTER 0x40 +#define SPEAKER_FRONT_RIGHT_OF_CENTER 0x80 +#define SPEAKER_BACK_CENTER 0x100 +#define SPEAKER_SIDE_LEFT 0x200 +#define SPEAKER_SIDE_RIGHT 0x400 +#define SPEAKER_TOP_CENTER 0x800 +#define SPEAKER_TOP_FRONT_LEFT 0x1000 +#define SPEAKER_TOP_FRONT_CENTER 0x2000 +#define SPEAKER_TOP_FRONT_RIGHT 0x4000 +#define SPEAKER_TOP_BACK_LEFT 0x8000 +#define SPEAKER_TOP_BACK_CENTER 0x10000 +#define SPEAKER_TOP_BACK_RIGHT 0x20000 + +#define SPEAKER_RESERVED 0x7FFC0000 + +#define SPEAKER_ALL 0x80000000 + +#define KSAUDIO_SPEAKER_DIRECTOUT 0 +#define KSAUDIO_SPEAKER_MONO (SPEAKER_FRONT_CENTER) +#define KSAUDIO_SPEAKER_STEREO (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT) +#define KSAUDIO_SPEAKER_QUAD (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | \ + SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT) +#define KSAUDIO_SPEAKER_SURROUND (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | \ + SPEAKER_FRONT_CENTER | SPEAKER_BACK_CENTER) +#define KSAUDIO_SPEAKER_5POINT1 (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | \ + SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY | \ + SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT) +#define KSAUDIO_SPEAKER_7POINT1 (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | \ + SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY | \ + SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT | \ + SPEAKER_FRONT_LEFT_OF_CENTER | SPEAKER_FRONT_RIGHT_OF_CENTER) +#define KSAUDIO_SPEAKER_5POINT1_SURROUND (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | \ + SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY | \ + SPEAKER_SIDE_LEFT | SPEAKER_SIDE_RIGHT) +#define KSAUDIO_SPEAKER_7POINT1_SURROUND (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | \ + SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY | \ + SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT | \ + SPEAKER_SIDE_LEFT | SPEAKER_SIDE_RIGHT) + +#define KSAUDIO_SPEAKER_5POINT1_BACK KSAUDIO_SPEAKER_5POINT1 +#define KSAUDIO_SPEAKER_7POINT1_WIDE KSAUDIO_SPEAKER_7POINT1 + +#define KSAUDIO_SPEAKER_GROUND_FRONT_LEFT SPEAKER_FRONT_LEFT +#define KSAUDIO_SPEAKER_GROUND_FRONT_CENTER SPEAKER_FRONT_CENTER +#define KSAUDIO_SPEAKER_GROUND_FRONT_RIGHT SPEAKER_FRONT_RIGHT +#define KSAUDIO_SPEAKER_GROUND_REAR_LEFT SPEAKER_BACK_LEFT +#define KSAUDIO_SPEAKER_GROUND_REAR_RIGHT SPEAKER_BACK_RIGHT +#define KSAUDIO_SPEAKER_TOP_MIDDLE SPEAKER_TOP_CENTER +#define KSAUDIO_SPEAKER_SUPER_WOOFER SPEAKER_LOW_FREQUENCY + +typedef struct { + ULONG QuietCompression; + ULONG LoudCompression; +} KSAUDIO_DYNAMIC_RANGE,*PKSAUDIO_DYNAMIC_RANGE; + +typedef struct { + WINBOOL Mute; + LONG Level; +} KSAUDIO_MIXLEVEL,*PKSAUDIO_MIXLEVEL; + +typedef struct { + WINBOOL Mute; + LONG Minimum; + LONG Maximum; + LONG Reset; +} KSAUDIO_MIX_CAPS,*PKSAUDIO_MIX_CAPS; + +typedef struct { + ULONG InputChannels; + ULONG OutputChannels; + KSAUDIO_MIX_CAPS Capabilities[1]; +} KSAUDIO_MIXCAP_TABLE,*PKSAUDIO_MIXCAP_TABLE; + +typedef enum { + SE_TECH_NONE, + SE_TECH_ANALOG_DEVICES_PHAT, + SE_TECH_CREATIVE, + SE_TECH_NATIONAL_SEMI, + SE_TECH_YAMAHA_YMERSION, + SE_TECH_BBE, + SE_TECH_CRYSTAL_SEMI, + SE_TECH_QSOUND_QXPANDER, + SE_TECH_SPATIALIZER, + SE_TECH_SRS, + SE_TECH_PLATFORM_TECH, + SE_TECH_AKM, + SE_TECH_AUREAL, + SE_TECH_AZTECH, + SE_TECH_BINAURA, + SE_TECH_ESS_TECH, + SE_TECH_HARMAN_VMAX, + SE_TECH_NVIDEA, + SE_TECH_PHILIPS_INCREDIBLE, + SE_TECH_TEXAS_INST, + SE_TECH_VLSI_TECH +} SE_TECHNIQUE; + +typedef struct { + SE_TECHNIQUE Technique; + ULONG Center; + ULONG Depth; + ULONG Reserved; +} KSAUDIO_STEREO_ENHANCE,*PKSAUDIO_STEREO_ENHANCE; + +typedef enum { + KSPROPERTY_SYSAUDIO_NORMAL_DEFAULT = 0, + KSPROPERTY_SYSAUDIO_PLAYBACK_DEFAULT, + KSPROPERTY_SYSAUDIO_RECORD_DEFAULT, + KSPROPERTY_SYSAUDIO_MIDI_DEFAULT, + KSPROPERTY_SYSAUDIO_MIXER_DEFAULT +} KSPROPERTY_SYSAUDIO_DEFAULT_TYPE; + +typedef struct { + WINBOOL Enable; + KSPROPERTY_SYSAUDIO_DEFAULT_TYPE DeviceType; + ULONG Flags; + ULONG Reserved; +} KSAUDIO_PREFERRED_STATUS,*PKSAUDIO_PREFERRED_STATUS; + +#define STATIC_KSNODETYPE_DAC \ + 0x507AE360L,0xC554,0x11D0,0x8A,0x2B,0x00,0xA0,0xC9,0x25,0x5A,0xC1 +DEFINE_GUIDSTRUCT("507AE360-C554-11D0-8A2B-00A0C9255AC1",KSNODETYPE_DAC); +#define KSNODETYPE_DAC DEFINE_GUIDNAMED(KSNODETYPE_DAC) + +#define STATIC_KSNODETYPE_ADC \ + 0x4D837FE0L,0xC555,0x11D0,0x8A,0x2B,0x00,0xA0,0xC9,0x25,0x5A,0xC1 +DEFINE_GUIDSTRUCT("4D837FE0-C555-11D0-8A2B-00A0C9255AC1",KSNODETYPE_ADC); +#define KSNODETYPE_ADC DEFINE_GUIDNAMED(KSNODETYPE_ADC) + +#define STATIC_KSNODETYPE_SRC \ + 0x9DB7B9E0L,0xC555,0x11D0,0x8A,0x2B,0x00,0xA0,0xC9,0x25,0x5A,0xC1 +DEFINE_GUIDSTRUCT("9DB7B9E0-C555-11D0-8A2B-00A0C9255AC1",KSNODETYPE_SRC); +#define KSNODETYPE_SRC DEFINE_GUIDNAMED(KSNODETYPE_SRC) + +#define STATIC_KSNODETYPE_SUPERMIX \ + 0xE573ADC0L,0xC555,0x11D0,0x8A,0x2B,0x00,0xA0,0xC9,0x25,0x5A,0xC1 +DEFINE_GUIDSTRUCT("E573ADC0-C555-11D0-8A2B-00A0C9255AC1",KSNODETYPE_SUPERMIX); +#define KSNODETYPE_SUPERMIX DEFINE_GUIDNAMED(KSNODETYPE_SUPERMIX) + +#define STATIC_KSNODETYPE_MUX \ + 0x2CEAF780L,0xC556,0x11D0,0x8A,0x2B,0x00,0xA0,0xC9,0x25,0x5A,0xC1 +DEFINE_GUIDSTRUCT("2CEAF780-C556-11D0-8A2B-00A0C9255AC1",KSNODETYPE_MUX); +#define KSNODETYPE_MUX DEFINE_GUIDNAMED(KSNODETYPE_MUX) + +#define STATIC_KSNODETYPE_DEMUX \ + 0xC0EB67D4L,0xE807,0x11D0,0x95,0x8A,0x00,0xC0,0x4F,0xB9,0x25,0xD3 +DEFINE_GUIDSTRUCT("C0EB67D4-E807-11D0-958A-00C04FB925D3",KSNODETYPE_DEMUX); +#define KSNODETYPE_DEMUX DEFINE_GUIDNAMED(KSNODETYPE_DEMUX) + +#define STATIC_KSNODETYPE_SUM \ + 0xDA441A60L,0xC556,0x11D0,0x8A,0x2B,0x00,0xA0,0xC9,0x25,0x5A,0xC1 +DEFINE_GUIDSTRUCT("DA441A60-C556-11D0-8A2B-00A0C9255AC1",KSNODETYPE_SUM); +#define KSNODETYPE_SUM DEFINE_GUIDNAMED(KSNODETYPE_SUM) + +#define STATIC_KSNODETYPE_MUTE \ + 0x02B223C0L,0xC557,0x11D0,0x8A,0x2B,0x00,0xA0,0xC9,0x25,0x5A,0xC1 +DEFINE_GUIDSTRUCT("02B223C0-C557-11D0-8A2B-00A0C9255AC1",KSNODETYPE_MUTE); +#define KSNODETYPE_MUTE DEFINE_GUIDNAMED(KSNODETYPE_MUTE) + +#define STATIC_KSNODETYPE_VOLUME \ + 0x3A5ACC00L,0xC557,0x11D0,0x8A,0x2B,0x00,0xA0,0xC9,0x25,0x5A,0xC1 +DEFINE_GUIDSTRUCT("3A5ACC00-C557-11D0-8A2B-00A0C9255AC1",KSNODETYPE_VOLUME); +#define KSNODETYPE_VOLUME DEFINE_GUIDNAMED(KSNODETYPE_VOLUME) + +#define STATIC_KSNODETYPE_TONE \ + 0x7607E580L,0xC557,0x11D0,0x8A,0x2B,0x00,0xA0,0xC9,0x25,0x5A,0xC1 +DEFINE_GUIDSTRUCT("7607E580-C557-11D0-8A2B-00A0C9255AC1",KSNODETYPE_TONE); +#define KSNODETYPE_TONE DEFINE_GUIDNAMED(KSNODETYPE_TONE) + +#define STATIC_KSNODETYPE_EQUALIZER \ + 0x9D41B4A0L,0xC557,0x11D0,0x8A,0x2B,0x00,0xA0,0xC9,0x25,0x5A,0xC1 +DEFINE_GUIDSTRUCT("9D41B4A0-C557-11D0-8A2B-00A0C9255AC1",KSNODETYPE_EQUALIZER); +#define KSNODETYPE_EQUALIZER DEFINE_GUIDNAMED(KSNODETYPE_EQUALIZER) + +#define STATIC_KSNODETYPE_AGC \ + 0xE88C9BA0L,0xC557,0x11D0,0x8A,0x2B,0x00,0xA0,0xC9,0x25,0x5A,0xC1 +DEFINE_GUIDSTRUCT("E88C9BA0-C557-11D0-8A2B-00A0C9255AC1",KSNODETYPE_AGC); +#define KSNODETYPE_AGC DEFINE_GUIDNAMED(KSNODETYPE_AGC) + +#define STATIC_KSNODETYPE_NOISE_SUPPRESS \ + 0xe07f903f,0x62fd,0x4e60,0x8c,0xdd,0xde,0xa7,0x23,0x66,0x65,0xb5 +DEFINE_GUIDSTRUCT("E07F903F-62FD-4e60-8CDD-DEA7236665B5",KSNODETYPE_NOISE_SUPPRESS); +#define KSNODETYPE_NOISE_SUPPRESS DEFINE_GUIDNAMED(KSNODETYPE_NOISE_SUPPRESS) + +#define STATIC_KSNODETYPE_DELAY \ + 0x144981E0L,0xC558,0x11D0,0x8A,0x2B,0x00,0xA0,0xC9,0x25,0x5A,0xC1 +DEFINE_GUIDSTRUCT("144981E0-C558-11D0-8A2B-00A0C9255AC1",KSNODETYPE_DELAY); +#define KSNODETYPE_DELAY DEFINE_GUIDNAMED(KSNODETYPE_DELAY) + +#define STATIC_KSNODETYPE_LOUDNESS \ + 0x41887440L,0xC558,0x11D0,0x8A,0x2B,0x00,0xA0,0xC9,0x25,0x5A,0xC1 +DEFINE_GUIDSTRUCT("41887440-C558-11D0-8A2B-00A0C9255AC1",KSNODETYPE_LOUDNESS); +#define KSNODETYPE_LOUDNESS DEFINE_GUIDNAMED(KSNODETYPE_LOUDNESS) + +#define STATIC_KSNODETYPE_PROLOGIC_DECODER \ + 0x831C2C80L,0xC558,0x11D0,0x8A,0x2B,0x00,0xA0,0xC9,0x25,0x5A,0xC1 +DEFINE_GUIDSTRUCT("831C2C80-C558-11D0-8A2B-00A0C9255AC1",KSNODETYPE_PROLOGIC_DECODER); +#define KSNODETYPE_PROLOGIC_DECODER DEFINE_GUIDNAMED(KSNODETYPE_PROLOGIC_DECODER) + +#define STATIC_KSNODETYPE_STEREO_WIDE \ + 0xA9E69800L,0xC558,0x11D0,0x8A,0x2B,0x00,0xA0,0xC9,0x25,0x5A,0xC1 +DEFINE_GUIDSTRUCT("A9E69800-C558-11D0-8A2B-00A0C9255AC1",KSNODETYPE_STEREO_WIDE); +#define KSNODETYPE_STEREO_WIDE DEFINE_GUIDNAMED(KSNODETYPE_STEREO_WIDE) + +#define STATIC_KSNODETYPE_STEREO_ENHANCE \ + 0xAF6878ACL,0xE83F,0x11D0,0x95,0x8A,0x00,0xC0,0x4F,0xB9,0x25,0xD3 +DEFINE_GUIDSTRUCT("AF6878AC-E83F-11D0-958A-00C04FB925D3",KSNODETYPE_STEREO_ENHANCE); +#define KSNODETYPE_STEREO_ENHANCE DEFINE_GUIDNAMED(KSNODETYPE_STEREO_ENHANCE) + +#define STATIC_KSNODETYPE_REVERB \ + 0xEF0328E0L,0xC558,0x11D0,0x8A,0x2B,0x00,0xA0,0xC9,0x25,0x5A,0xC1 +DEFINE_GUIDSTRUCT("EF0328E0-C558-11D0-8A2B-00A0C9255AC1",KSNODETYPE_REVERB); +#define KSNODETYPE_REVERB DEFINE_GUIDNAMED(KSNODETYPE_REVERB) + +#define STATIC_KSNODETYPE_CHORUS \ + 0x20173F20L,0xC559,0x11D0,0x8A,0x2B,0x00,0xA0,0xC9,0x25,0x5A,0xC1 +DEFINE_GUIDSTRUCT("20173F20-C559-11D0-8A2B-00A0C9255AC1",KSNODETYPE_CHORUS); +#define KSNODETYPE_CHORUS DEFINE_GUIDNAMED(KSNODETYPE_CHORUS) + +#define STATIC_KSNODETYPE_3D_EFFECTS \ + 0x55515860L,0xC559,0x11D0,0x8A,0x2B,0x00,0xA0,0xC9,0x25,0x5A,0xC1 +DEFINE_GUIDSTRUCT("55515860-C559-11D0-8A2B-00A0C9255AC1",KSNODETYPE_3D_EFFECTS); +#define KSNODETYPE_3D_EFFECTS DEFINE_GUIDNAMED(KSNODETYPE_3D_EFFECTS) + +#define STATIC_KSNODETYPE_ACOUSTIC_ECHO_CANCEL STATIC_KSCATEGORY_ACOUSTIC_ECHO_CANCEL +#define KSNODETYPE_ACOUSTIC_ECHO_CANCEL KSCATEGORY_ACOUSTIC_ECHO_CANCEL + +#define STATIC_KSALGORITHMINSTANCE_SYSTEM_ACOUSTIC_ECHO_CANCEL \ + 0x1c22c56dL,0x9879,0x4f5b,0xa3,0x89,0x27,0x99,0x6d,0xdc,0x28,0x10 +DEFINE_GUIDSTRUCT("1C22C56D-9879-4f5b-A389-27996DDC2810",KSALGORITHMINSTANCE_SYSTEM_ACOUSTIC_ECHO_CANCEL); +#define KSALGORITHMINSTANCE_SYSTEM_ACOUSTIC_ECHO_CANCEL DEFINE_GUIDNAMED(KSALGORITHMINSTANCE_SYSTEM_ACOUSTIC_ECHO_CANCEL) + +#define STATIC_KSALGORITHMINSTANCE_SYSTEM_NOISE_SUPPRESS \ + 0x5ab0882eL,0x7274,0x4516,0x87,0x7d,0x4e,0xee,0x99,0xba,0x4f,0xd0 +DEFINE_GUIDSTRUCT("5AB0882E-7274-4516-877D-4EEE99BA4FD0",KSALGORITHMINSTANCE_SYSTEM_NOISE_SUPPRESS); +#define KSALGORITHMINSTANCE_SYSTEM_NOISE_SUPPRESS DEFINE_GUIDNAMED(KSALGORITHMINSTANCE_SYSTEM_NOISE_SUPPRESS) + +#define STATIC_KSALGORITHMINSTANCE_SYSTEM_AGC \ + 0x950e55b9L,0x877c,0x4c67,0xbe,0x8,0xe4,0x7b,0x56,0x11,0x13,0xa +DEFINE_GUIDSTRUCT("950E55B9-877C-4c67-BE08-E47B5611130A",KSALGORITHMINSTANCE_SYSTEM_AGC); +#define KSALGORITHMINSTANCE_SYSTEM_AGC DEFINE_GUIDNAMED(KSALGORITHMINSTANCE_SYSTEM_AGC) + +#define STATIC_KSALGORITHMINSTANCE_SYSTEM_MICROPHONE_ARRAY_PROCESSOR \ + 0xB6F5A0A0L,0x9E61,0x4F8C,0x91,0xE3,0x76,0xCF,0xF,0x3C,0x47,0x1F +DEFINE_GUIDSTRUCT("B6F5A0A0-9E61-4f8c-91E3-76CF0F3C471F",KSALGORITHMINSTANCE_SYSTEM_MICROPHONE_ARRAY_PROCESSOR); +#define KSALGORITHMINSTANCE_SYSTEM_MICROPHONE_ARRAY_PROCESSOR DEFINE_GUIDNAMED(KSALGORITHMINSTANCE_SYSTEM_MICROPHONE_ARRAY_PROCESSOR) + +#define STATIC_KSNODETYPE_MICROPHONE_ARRAY_PROCESSOR STATIC_KSCATEGORY_MICROPHONE_ARRAY_PROCESSOR +#define KSNODETYPE_MICROPHONE_ARRAY_PROCESSOR KSCATEGORY_MICROPHONE_ARRAY_PROCESSOR + +#define STATIC_KSNODETYPE_DEV_SPECIFIC \ + 0x941C7AC0L,0xC559,0x11D0,0x8A,0x2B,0x00,0xA0,0xC9,0x25,0x5A,0xC1 +DEFINE_GUIDSTRUCT("941C7AC0-C559-11D0-8A2B-00A0C9255AC1",KSNODETYPE_DEV_SPECIFIC); +#define KSNODETYPE_DEV_SPECIFIC DEFINE_GUIDNAMED(KSNODETYPE_DEV_SPECIFIC) + +#define STATIC_KSNODETYPE_PROLOGIC_ENCODER \ + 0x8074C5B2L,0x3C66,0x11D2,0xB4,0x5A,0x30,0x78,0x30,0x2C,0x20,0x30 +DEFINE_GUIDSTRUCT("8074C5B2-3C66-11D2-B45A-3078302C2030",KSNODETYPE_PROLOGIC_ENCODER); +#define KSNODETYPE_PROLOGIC_ENCODER DEFINE_GUIDNAMED(KSNODETYPE_PROLOGIC_ENCODER) +#define KSNODETYPE_SURROUND_ENCODER KSNODETYPE_PROLOGIC_ENCODER + +#define STATIC_KSNODETYPE_PEAKMETER \ + 0xa085651eL,0x5f0d,0x4b36,0xa8,0x69,0xd1,0x95,0xd6,0xab,0x4b,0x9e +DEFINE_GUIDSTRUCT("A085651E-5F0D-4b36-A869-D195D6AB4B9E",KSNODETYPE_PEAKMETER); +#define KSNODETYPE_PEAKMETER DEFINE_GUIDNAMED(KSNODETYPE_PEAKMETER) + +#define STATIC_KSAUDFNAME_BASS \ + 0x185FEDE0L,0x9905,0x11D1,0x95,0xA9,0x00,0xC0,0x4F,0xB9,0x25,0xD3 +DEFINE_GUIDSTRUCT("185FEDE0-9905-11D1-95A9-00C04FB925D3",KSAUDFNAME_BASS); +#define KSAUDFNAME_BASS DEFINE_GUIDNAMED(KSAUDFNAME_BASS) + +#define STATIC_KSAUDFNAME_TREBLE \ + 0x185FEDE1L,0x9905,0x11D1,0x95,0xA9,0x00,0xC0,0x4F,0xB9,0x25,0xD3 +DEFINE_GUIDSTRUCT("185FEDE1-9905-11D1-95A9-00C04FB925D3",KSAUDFNAME_TREBLE); +#define KSAUDFNAME_TREBLE DEFINE_GUIDNAMED(KSAUDFNAME_TREBLE) + +#define STATIC_KSAUDFNAME_3D_STEREO \ + 0x185FEDE2L,0x9905,0x11D1,0x95,0xA9,0x00,0xC0,0x4F,0xB9,0x25,0xD3 +DEFINE_GUIDSTRUCT("185FEDE2-9905-11D1-95A9-00C04FB925D3",KSAUDFNAME_3D_STEREO); +#define KSAUDFNAME_3D_STEREO DEFINE_GUIDNAMED(KSAUDFNAME_3D_STEREO) + +#define STATIC_KSAUDFNAME_MASTER_VOLUME \ + 0x185FEDE3L,0x9905,0x11D1,0x95,0xA9,0x00,0xC0,0x4F,0xB9,0x25,0xD3 +DEFINE_GUIDSTRUCT("185FEDE3-9905-11D1-95A9-00C04FB925D3",KSAUDFNAME_MASTER_VOLUME); +#define KSAUDFNAME_MASTER_VOLUME DEFINE_GUIDNAMED(KSAUDFNAME_MASTER_VOLUME) + +#define STATIC_KSAUDFNAME_MASTER_MUTE \ + 0x185FEDE4L,0x9905,0x11D1,0x95,0xA9,0x00,0xC0,0x4F,0xB9,0x25,0xD3 +DEFINE_GUIDSTRUCT("185FEDE4-9905-11D1-95A9-00C04FB925D3",KSAUDFNAME_MASTER_MUTE); +#define KSAUDFNAME_MASTER_MUTE DEFINE_GUIDNAMED(KSAUDFNAME_MASTER_MUTE) + +#define STATIC_KSAUDFNAME_WAVE_VOLUME \ + 0x185FEDE5L,0x9905,0x11D1,0x95,0xA9,0x00,0xC0,0x4F,0xB9,0x25,0xD3 +DEFINE_GUIDSTRUCT("185FEDE5-9905-11D1-95A9-00C04FB925D3",KSAUDFNAME_WAVE_VOLUME); +#define KSAUDFNAME_WAVE_VOLUME DEFINE_GUIDNAMED(KSAUDFNAME_WAVE_VOLUME) + +#define STATIC_KSAUDFNAME_WAVE_MUTE \ + 0x185FEDE6L,0x9905,0x11D1,0x95,0xA9,0x00,0xC0,0x4F,0xB9,0x25,0xD3 +DEFINE_GUIDSTRUCT("185FEDE6-9905-11D1-95A9-00C04FB925D3",KSAUDFNAME_WAVE_MUTE); +#define KSAUDFNAME_WAVE_MUTE DEFINE_GUIDNAMED(KSAUDFNAME_WAVE_MUTE) + +#define STATIC_KSAUDFNAME_MIDI_VOLUME \ + 0x185FEDE7L,0x9905,0x11D1,0x95,0xA9,0x00,0xC0,0x4F,0xB9,0x25,0xD3 +DEFINE_GUIDSTRUCT("185FEDE7-9905-11D1-95A9-00C04FB925D3",KSAUDFNAME_MIDI_VOLUME); +#define KSAUDFNAME_MIDI_VOLUME DEFINE_GUIDNAMED(KSAUDFNAME_MIDI_VOLUME) + +#define STATIC_KSAUDFNAME_MIDI_MUTE \ + 0x185FEDE8L,0x9905,0x11D1,0x95,0xA9,0x00,0xC0,0x4F,0xB9,0x25,0xD3 +DEFINE_GUIDSTRUCT("185FEDE8-9905-11D1-95A9-00C04FB925D3",KSAUDFNAME_MIDI_MUTE); +#define KSAUDFNAME_MIDI_MUTE DEFINE_GUIDNAMED(KSAUDFNAME_MIDI_MUTE) + +#define STATIC_KSAUDFNAME_CD_VOLUME \ + 0x185FEDE9L,0x9905,0x11D1,0x95,0xA9,0x00,0xC0,0x4F,0xB9,0x25,0xD3 +DEFINE_GUIDSTRUCT("185FEDE9-9905-11D1-95A9-00C04FB925D3",KSAUDFNAME_CD_VOLUME); +#define KSAUDFNAME_CD_VOLUME DEFINE_GUIDNAMED(KSAUDFNAME_CD_VOLUME) + +#define STATIC_KSAUDFNAME_CD_MUTE \ + 0x185FEDEAL,0x9905,0x11D1,0x95,0xA9,0x00,0xC0,0x4F,0xB9,0x25,0xD3 +DEFINE_GUIDSTRUCT("185FEDEA-9905-11D1-95A9-00C04FB925D3",KSAUDFNAME_CD_MUTE); +#define KSAUDFNAME_CD_MUTE DEFINE_GUIDNAMED(KSAUDFNAME_CD_MUTE) + +#define STATIC_KSAUDFNAME_LINE_VOLUME \ + 0x185FEDEBL,0x9905,0x11D1,0x95,0xA9,0x00,0xC0,0x4F,0xB9,0x25,0xD3 +DEFINE_GUIDSTRUCT("185FEDEB-9905-11D1-95A9-00C04FB925D3",KSAUDFNAME_LINE_VOLUME); +#define KSAUDFNAME_LINE_VOLUME DEFINE_GUIDNAMED(KSAUDFNAME_LINE_VOLUME) + +#define STATIC_KSAUDFNAME_LINE_MUTE \ + 0x185FEDECL,0x9905,0x11D1,0x95,0xA9,0x00,0xC0,0x4F,0xB9,0x25,0xD3 +DEFINE_GUIDSTRUCT("185FEDEC-9905-11D1-95A9-00C04FB925D3",KSAUDFNAME_LINE_MUTE); +#define KSAUDFNAME_LINE_MUTE DEFINE_GUIDNAMED(KSAUDFNAME_LINE_MUTE) + +#define STATIC_KSAUDFNAME_MIC_VOLUME \ + 0x185FEDEDL,0x9905,0x11D1,0x95,0xA9,0x00,0xC0,0x4F,0xB9,0x25,0xD3 +DEFINE_GUIDSTRUCT("185FEDED-9905-11D1-95A9-00C04FB925D3",KSAUDFNAME_MIC_VOLUME); +#define KSAUDFNAME_MIC_VOLUME DEFINE_GUIDNAMED(KSAUDFNAME_MIC_VOLUME) + +#define STATIC_KSAUDFNAME_MIC_MUTE \ + 0x185FEDEEL,0x9905,0x11D1,0x95,0xA9,0x00,0xC0,0x4F,0xB9,0x25,0xD3 +DEFINE_GUIDSTRUCT("185FEDEE-9905-11D1-95A9-00C04FB925D3",KSAUDFNAME_MIC_MUTE); +#define KSAUDFNAME_MIC_MUTE DEFINE_GUIDNAMED(KSAUDFNAME_MIC_MUTE) + +#define STATIC_KSAUDFNAME_RECORDING_SOURCE \ + 0x185FEDEFL,0x9905,0x11D1,0x95,0xA9,0x00,0xC0,0x4F,0xB9,0x25,0xD3 +DEFINE_GUIDSTRUCT("185FEDEF-9905-11D1-95A9-00C04FB925D3",KSAUDFNAME_RECORDING_SOURCE); +#define KSAUDFNAME_RECORDING_SOURCE DEFINE_GUIDNAMED(KSAUDFNAME_RECORDING_SOURCE) + +#define STATIC_KSAUDFNAME_PC_SPEAKER_VOLUME \ + 0x185FEDF0L,0x9905,0x11D1,0x95,0xA9,0x00,0xC0,0x4F,0xB9,0x25,0xD3 +DEFINE_GUIDSTRUCT("185FEDF0-9905-11D1-95A9-00C04FB925D3",KSAUDFNAME_PC_SPEAKER_VOLUME); +#define KSAUDFNAME_PC_SPEAKER_VOLUME DEFINE_GUIDNAMED(KSAUDFNAME_PC_SPEAKER_VOLUME) + +#define STATIC_KSAUDFNAME_PC_SPEAKER_MUTE \ + 0x185FEDF1L,0x9905,0x11D1,0x95,0xA9,0x00,0xC0,0x4F,0xB9,0x25,0xD3 +DEFINE_GUIDSTRUCT("185FEDF1-9905-11D1-95A9-00C04FB925D3",KSAUDFNAME_PC_SPEAKER_MUTE); +#define KSAUDFNAME_PC_SPEAKER_MUTE DEFINE_GUIDNAMED(KSAUDFNAME_PC_SPEAKER_MUTE) + +#define STATIC_KSAUDFNAME_MIDI_IN_VOLUME \ + 0x185FEDF2L,0x9905,0x11D1,0x95,0xA9,0x00,0xC0,0x4F,0xB9,0x25,0xD3 +DEFINE_GUIDSTRUCT("185FEDF2-9905-11D1-95A9-00C04FB925D3",KSAUDFNAME_MIDI_IN_VOLUME); +#define KSAUDFNAME_MIDI_IN_VOLUME DEFINE_GUIDNAMED(KSAUDFNAME_MIDI_IN_VOLUME) + +#define STATIC_KSAUDFNAME_CD_IN_VOLUME \ + 0x185FEDF3L,0x9905,0x11D1,0x95,0xA9,0x00,0xC0,0x4F,0xB9,0x25,0xD3 +DEFINE_GUIDSTRUCT("185FEDF3-9905-11D1-95A9-00C04FB925D3",KSAUDFNAME_CD_IN_VOLUME); +#define KSAUDFNAME_CD_IN_VOLUME DEFINE_GUIDNAMED(KSAUDFNAME_CD_IN_VOLUME) + +#define STATIC_KSAUDFNAME_LINE_IN_VOLUME \ + 0x185FEDF4L,0x9905,0x11D1,0x95,0xA9,0x00,0xC0,0x4F,0xB9,0x25,0xD3 +DEFINE_GUIDSTRUCT("185FEDF4-9905-11D1-95A9-00C04FB925D3",KSAUDFNAME_LINE_IN_VOLUME); +#define KSAUDFNAME_LINE_IN_VOLUME DEFINE_GUIDNAMED(KSAUDFNAME_LINE_IN_VOLUME) + +#define STATIC_KSAUDFNAME_MIC_IN_VOLUME \ + 0x185FEDF5L,0x9905,0x11D1,0x95,0xA9,0x00,0xC0,0x4F,0xB9,0x25,0xD3 +DEFINE_GUIDSTRUCT("185FEDF5-9905-11D1-95A9-00C04FB925D3",KSAUDFNAME_MIC_IN_VOLUME); +#define KSAUDFNAME_MIC_IN_VOLUME DEFINE_GUIDNAMED(KSAUDFNAME_MIC_IN_VOLUME) + +#define STATIC_KSAUDFNAME_WAVE_IN_VOLUME \ + 0x185FEDF6L,0x9905,0x11D1,0x95,0xA9,0x00,0xC0,0x4F,0xB9,0x25,0xD3 +DEFINE_GUIDSTRUCT("185FEDF6-9905-11D1-95A9-00C04FB925D3",KSAUDFNAME_WAVE_IN_VOLUME); +#define KSAUDFNAME_WAVE_IN_VOLUME DEFINE_GUIDNAMED(KSAUDFNAME_WAVE_IN_VOLUME) + +#define STATIC_KSAUDFNAME_VOLUME_CONTROL \ + 0x185FEDF7L,0x9905,0x11D1,0x95,0xA9,0x00,0xC0,0x4F,0xB9,0x25,0xD3 +DEFINE_GUIDSTRUCT("185FEDF7-9905-11D1-95A9-00C04FB925D3",KSAUDFNAME_VOLUME_CONTROL); +#define KSAUDFNAME_VOLUME_CONTROL DEFINE_GUIDNAMED(KSAUDFNAME_VOLUME_CONTROL) + +#define STATIC_KSAUDFNAME_MIDI \ + 0x185FEDF8L,0x9905,0x11D1,0x95,0xA9,0x00,0xC0,0x4F,0xB9,0x25,0xD3 +DEFINE_GUIDSTRUCT("185FEDF8-9905-11D1-95A9-00C04FB925D3",KSAUDFNAME_MIDI); +#define KSAUDFNAME_MIDI DEFINE_GUIDNAMED(KSAUDFNAME_MIDI) + +#define STATIC_KSAUDFNAME_LINE_IN \ + 0x185FEDF9L,0x9905,0x11D1,0x95,0xA9,0x00,0xC0,0x4F,0xB9,0x25,0xD3 +DEFINE_GUIDSTRUCT("185FEDF9-9905-11D1-95A9-00C04FB925D3",KSAUDFNAME_LINE_IN); +#define KSAUDFNAME_LINE_IN DEFINE_GUIDNAMED(KSAUDFNAME_LINE_IN) + +#define STATIC_KSAUDFNAME_RECORDING_CONTROL \ + 0x185FEDFAL,0x9905,0x11D1,0x95,0xA9,0x00,0xC0,0x4F,0xB9,0x25,0xD3 +DEFINE_GUIDSTRUCT("185FEDFA-9905-11D1-95A9-00C04FB925D3",KSAUDFNAME_RECORDING_CONTROL); +#define KSAUDFNAME_RECORDING_CONTROL DEFINE_GUIDNAMED(KSAUDFNAME_RECORDING_CONTROL) + +#define STATIC_KSAUDFNAME_CD_AUDIO \ + 0x185FEDFBL,0x9905,0x11D1,0x95,0xA9,0x00,0xC0,0x4F,0xB9,0x25,0xD3 +DEFINE_GUIDSTRUCT("185FEDFB-9905-11D1-95A9-00C04FB925D3",KSAUDFNAME_CD_AUDIO); +#define KSAUDFNAME_CD_AUDIO DEFINE_GUIDNAMED(KSAUDFNAME_CD_AUDIO) + +#define STATIC_KSAUDFNAME_AUX_VOLUME \ + 0x185FEDFCL,0x9905,0x11D1,0x95,0xA9,0x00,0xC0,0x4F,0xB9,0x25,0xD3 +DEFINE_GUIDSTRUCT("185FEDFC-9905-11D1-95A9-00C04FB925D3",KSAUDFNAME_AUX_VOLUME); +#define KSAUDFNAME_AUX_VOLUME DEFINE_GUIDNAMED(KSAUDFNAME_AUX_VOLUME) + +#define STATIC_KSAUDFNAME_AUX_MUTE \ + 0x185FEDFDL,0x9905,0x11D1,0x95,0xA9,0x00,0xC0,0x4F,0xB9,0x25,0xD3 +DEFINE_GUIDSTRUCT("185FEDFD-9905-11D1-95A9-00C04FB925D3",KSAUDFNAME_AUX_MUTE); +#define KSAUDFNAME_AUX_MUTE DEFINE_GUIDNAMED(KSAUDFNAME_AUX_MUTE) + +#define STATIC_KSAUDFNAME_AUX \ + 0x185FEDFEL,0x9905,0x11D1,0x95,0xA9,0x00,0xC0,0x4F,0xB9,0x25,0xD3 +DEFINE_GUIDSTRUCT("185FEDFE-9905-11D1-95A9-00C04FB925D3",KSAUDFNAME_AUX); +#define KSAUDFNAME_AUX DEFINE_GUIDNAMED(KSAUDFNAME_AUX) + +#define STATIC_KSAUDFNAME_PC_SPEAKER \ + 0x185FEDFFL,0x9905,0x11D1,0x95,0xA9,0x00,0xC0,0x4F,0xB9,0x25,0xD3 +DEFINE_GUIDSTRUCT("185FEDFF-9905-11D1-95A9-00C04FB925D3",KSAUDFNAME_PC_SPEAKER); +#define KSAUDFNAME_PC_SPEAKER DEFINE_GUIDNAMED(KSAUDFNAME_PC_SPEAKER) + +#define STATIC_KSAUDFNAME_WAVE_OUT_MIX \ + 0x185FEE00L,0x9905,0x11D1,0x95,0xA9,0x00,0xC0,0x4F,0xB9,0x25,0xD3 +DEFINE_GUIDSTRUCT("185FEE00-9905-11D1-95A9-00C04FB925D3",KSAUDFNAME_WAVE_OUT_MIX); +#define KSAUDFNAME_WAVE_OUT_MIX DEFINE_GUIDNAMED(KSAUDFNAME_WAVE_OUT_MIX) + +#define STATIC_KSAUDFNAME_MONO_OUT \ + 0xf9b41dc3L,0x96e2,0x11d2,0xac,0x4c,0x0,0xc0,0x4f,0x8e,0xfb,0x68 +DEFINE_GUIDSTRUCT("F9B41DC3-96E2-11d2-AC4C-00C04F8EFB68",KSAUDFNAME_MONO_OUT); +#define KSAUDFNAME_MONO_OUT DEFINE_GUIDNAMED(KSAUDFNAME_MONO_OUT) + +#define STATIC_KSAUDFNAME_STEREO_MIX \ + 0xdff077L,0x96e3,0x11d2,0xac,0x4c,0x0,0xc0,0x4f,0x8e,0xfb,0x68 +DEFINE_GUIDSTRUCT("00DFF077-96E3-11d2-AC4C-00C04F8EFB68",KSAUDFNAME_STEREO_MIX); +#define KSAUDFNAME_STEREO_MIX DEFINE_GUIDNAMED(KSAUDFNAME_STEREO_MIX) + +#define STATIC_KSAUDFNAME_MONO_MIX \ + 0xdff078L,0x96e3,0x11d2,0xac,0x4c,0x0,0xc0,0x4f,0x8e,0xfb,0x68 +DEFINE_GUIDSTRUCT("00DFF078-96E3-11d2-AC4C-00C04F8EFB68",KSAUDFNAME_MONO_MIX); +#define KSAUDFNAME_MONO_MIX DEFINE_GUIDNAMED(KSAUDFNAME_MONO_MIX) + +#define STATIC_KSAUDFNAME_MONO_OUT_VOLUME \ + 0x1ad247ebL,0x96e3,0x11d2,0xac,0x4c,0x0,0xc0,0x4f,0x8e,0xfb,0x68 +DEFINE_GUIDSTRUCT("1AD247EB-96E3-11d2-AC4C-00C04F8EFB68",KSAUDFNAME_MONO_OUT_VOLUME); +#define KSAUDFNAME_MONO_OUT_VOLUME DEFINE_GUIDNAMED(KSAUDFNAME_MONO_OUT_VOLUME) + +#define STATIC_KSAUDFNAME_MONO_OUT_MUTE \ + 0x1ad247ecL,0x96e3,0x11d2,0xac,0x4c,0x0,0xc0,0x4f,0x8e,0xfb,0x68 +DEFINE_GUIDSTRUCT("1AD247EC-96E3-11d2-AC4C-00C04F8EFB68",KSAUDFNAME_MONO_OUT_MUTE); +#define KSAUDFNAME_MONO_OUT_MUTE DEFINE_GUIDNAMED(KSAUDFNAME_MONO_OUT_MUTE) + +#define STATIC_KSAUDFNAME_STEREO_MIX_VOLUME \ + 0x1ad247edL,0x96e3,0x11d2,0xac,0x4c,0x0,0xc0,0x4f,0x8e,0xfb,0x68 +DEFINE_GUIDSTRUCT("1AD247ED-96E3-11d2-AC4C-00C04F8EFB68",KSAUDFNAME_STEREO_MIX_VOLUME); +#define KSAUDFNAME_STEREO_MIX_VOLUME DEFINE_GUIDNAMED(KSAUDFNAME_STEREO_MIX_VOLUME) + +#define STATIC_KSAUDFNAME_STEREO_MIX_MUTE \ + 0x22b0eafdL,0x96e3,0x11d2,0xac,0x4c,0x0,0xc0,0x4f,0x8e,0xfb,0x68 +DEFINE_GUIDSTRUCT("22B0EAFD-96E3-11d2-AC4C-00C04F8EFB68",KSAUDFNAME_STEREO_MIX_MUTE); +#define KSAUDFNAME_STEREO_MIX_MUTE DEFINE_GUIDNAMED(KSAUDFNAME_STEREO_MIX_MUTE) + +#define STATIC_KSAUDFNAME_MONO_MIX_VOLUME \ + 0x22b0eafeL,0x96e3,0x11d2,0xac,0x4c,0x0,0xc0,0x4f,0x8e,0xfb,0x68 +DEFINE_GUIDSTRUCT("22B0EAFE-96E3-11d2-AC4C-00C04F8EFB68",KSAUDFNAME_MONO_MIX_VOLUME); +#define KSAUDFNAME_MONO_MIX_VOLUME DEFINE_GUIDNAMED(KSAUDFNAME_MONO_MIX_VOLUME) + +#define STATIC_KSAUDFNAME_MONO_MIX_MUTE \ + 0x2bc31d69L,0x96e3,0x11d2,0xac,0x4c,0x0,0xc0,0x4f,0x8e,0xfb,0x68 +DEFINE_GUIDSTRUCT("2BC31D69-96E3-11d2-AC4C-00C04F8EFB68",KSAUDFNAME_MONO_MIX_MUTE); +#define KSAUDFNAME_MONO_MIX_MUTE DEFINE_GUIDNAMED(KSAUDFNAME_MONO_MIX_MUTE) + +#define STATIC_KSAUDFNAME_MICROPHONE_BOOST \ + 0x2bc31d6aL,0x96e3,0x11d2,0xac,0x4c,0x0,0xc0,0x4f,0x8e,0xfb,0x68 +DEFINE_GUIDSTRUCT("2BC31D6A-96E3-11d2-AC4C-00C04F8EFB68",KSAUDFNAME_MICROPHONE_BOOST); +#define KSAUDFNAME_MICROPHONE_BOOST DEFINE_GUIDNAMED(KSAUDFNAME_MICROPHONE_BOOST) + +#define STATIC_KSAUDFNAME_ALTERNATE_MICROPHONE \ + 0x2bc31d6bL,0x96e3,0x11d2,0xac,0x4c,0x0,0xc0,0x4f,0x8e,0xfb,0x68 +DEFINE_GUIDSTRUCT("2BC31D6B-96E3-11d2-AC4C-00C04F8EFB68",KSAUDFNAME_ALTERNATE_MICROPHONE); +#define KSAUDFNAME_ALTERNATE_MICROPHONE DEFINE_GUIDNAMED(KSAUDFNAME_ALTERNATE_MICROPHONE) + +#define STATIC_KSAUDFNAME_3D_DEPTH \ + 0x63ff5747L,0x991f,0x11d2,0xac,0x4d,0x0,0xc0,0x4f,0x8e,0xfb,0x68 +DEFINE_GUIDSTRUCT("63FF5747-991F-11d2-AC4D-00C04F8EFB68",KSAUDFNAME_3D_DEPTH); +#define KSAUDFNAME_3D_DEPTH DEFINE_GUIDNAMED(KSAUDFNAME_3D_DEPTH) + +#define STATIC_KSAUDFNAME_3D_CENTER \ + 0x9f0670b4L,0x991f,0x11d2,0xac,0x4d,0x0,0xc0,0x4f,0x8e,0xfb,0x68 +DEFINE_GUIDSTRUCT("9F0670B4-991F-11d2-AC4D-00C04F8EFB68",KSAUDFNAME_3D_CENTER); +#define KSAUDFNAME_3D_CENTER DEFINE_GUIDNAMED(KSAUDFNAME_3D_CENTER) + +#define STATIC_KSAUDFNAME_VIDEO_VOLUME \ + 0x9b46e708L,0x992a,0x11d2,0xac,0x4d,0x0,0xc0,0x4f,0x8e,0xfb,0x68 +DEFINE_GUIDSTRUCT("9B46E708-992A-11d2-AC4D-00C04F8EFB68",KSAUDFNAME_VIDEO_VOLUME); +#define KSAUDFNAME_VIDEO_VOLUME DEFINE_GUIDNAMED(KSAUDFNAME_VIDEO_VOLUME) + +#define STATIC_KSAUDFNAME_VIDEO_MUTE \ + 0x9b46e709L,0x992a,0x11d2,0xac,0x4d,0x0,0xc0,0x4f,0x8e,0xfb,0x68 +DEFINE_GUIDSTRUCT("9B46E709-992A-11d2-AC4D-00C04F8EFB68",KSAUDFNAME_VIDEO_MUTE); +#define KSAUDFNAME_VIDEO_MUTE DEFINE_GUIDNAMED(KSAUDFNAME_VIDEO_MUTE) + +#define STATIC_KSAUDFNAME_VIDEO \ + 0x915daec4L,0xa434,0x11d2,0xac,0x52,0x0,0xc0,0x4f,0x8e,0xfb,0x68 +DEFINE_GUIDSTRUCT("915DAEC4-A434-11d2-AC52-00C04F8EFB68",KSAUDFNAME_VIDEO); +#define KSAUDFNAME_VIDEO DEFINE_GUIDNAMED(KSAUDFNAME_VIDEO) + +#define STATIC_KSAUDFNAME_PEAKMETER \ + 0x57e24340L,0xfc5b,0x4612,0xa5,0x62,0x72,0xb1,0x1a,0x29,0xdf,0xae +DEFINE_GUIDSTRUCT("57E24340-FC5B-4612-A562-72B11A29DFAE",KSAUDFNAME_PEAKMETER); +#define KSAUDFNAME_PEAKMETER DEFINE_GUIDNAMED(KSAUDFNAME_PEAKMETER) + +#define KSNODEPIN_STANDARD_IN 1 +#define KSNODEPIN_STANDARD_OUT 0 + +#define KSNODEPIN_SUM_MUX_IN 1 +#define KSNODEPIN_SUM_MUX_OUT 0 + +#define KSNODEPIN_DEMUX_IN 0 +#define KSNODEPIN_DEMUX_OUT 1 + +#define KSNODEPIN_AEC_RENDER_IN 1 +#define KSNODEPIN_AEC_RENDER_OUT 0 +#define KSNODEPIN_AEC_CAPTURE_IN 2 +#define KSNODEPIN_AEC_CAPTURE_OUT 3 + +#define STATIC_KSMETHODSETID_Wavetable \ + 0xDCEF31EBL,0xD907,0x11D0,0x95,0x83,0x00,0xC0,0x4F,0xB9,0x25,0xD3 +DEFINE_GUIDSTRUCT("DCEF31EB-D907-11D0-9583-00C04FB925D3",KSMETHODSETID_Wavetable); +#define KSMETHODSETID_Wavetable DEFINE_GUIDNAMED(KSMETHODSETID_Wavetable) + +typedef enum { + KSMETHOD_WAVETABLE_WAVE_ALLOC, + KSMETHOD_WAVETABLE_WAVE_FREE, + KSMETHOD_WAVETABLE_WAVE_FIND, + KSMETHOD_WAVETABLE_WAVE_WRITE +} KSMETHOD_WAVETABLE; + +typedef struct { + KSIDENTIFIER Identifier; + ULONG Size; + WINBOOL Looped; + ULONG LoopPoint; + WINBOOL InROM; + KSDATAFORMAT Format; +} KSWAVETABLE_WAVE_DESC,*PKSWAVETABLE_WAVE_DESC; + +#define STATIC_KSPROPSETID_Acoustic_Echo_Cancel \ + 0xd7a4af8bL,0x3dc1,0x4902,0x91,0xea,0x8a,0x15,0xc9,0x0e,0x05,0xb2 +DEFINE_GUIDSTRUCT("D7A4AF8B-3DC1-4902-91EA-8A15C90E05B2",KSPROPSETID_Acoustic_Echo_Cancel); +#define KSPROPSETID_Acoustic_Echo_Cancel DEFINE_GUIDNAMED(KSPROPSETID_Acoustic_Echo_Cancel) + +typedef enum { + KSPROPERTY_AEC_NOISE_FILL_ENABLE = 0, + KSPROPERTY_AEC_STATUS, + KSPROPERTY_AEC_MODE +} KSPROPERTY_AEC; + +#define AEC_STATUS_FD_HISTORY_UNINITIALIZED 0x0 +#define AEC_STATUS_FD_HISTORY_CONTINUOUSLY_CONVERGED 0x1 +#define AEC_STATUS_FD_HISTORY_PREVIOUSLY_DIVERGED 0x2 +#define AEC_STATUS_FD_CURRENTLY_CONVERGED 0x8 + +#define AEC_MODE_PASS_THROUGH 0x0 +#define AEC_MODE_HALF_DUPLEX 0x1 +#define AEC_MODE_FULL_DUPLEX 0x2 + +#define STATIC_KSPROPSETID_Wave \ + 0x924e54b0L,0x630f,0x11cf,0xad,0xa7,0x08,0x00,0x3e,0x30,0x49,0x4a +DEFINE_GUIDSTRUCT("924e54b0-630f-11cf-ada7-08003e30494a",KSPROPSETID_Wave); +#define KSPROPSETID_Wave DEFINE_GUIDNAMED(KSPROPSETID_Wave) + +typedef enum { + KSPROPERTY_WAVE_COMPATIBLE_CAPABILITIES, + KSPROPERTY_WAVE_INPUT_CAPABILITIES, + KSPROPERTY_WAVE_OUTPUT_CAPABILITIES, + KSPROPERTY_WAVE_BUFFER, + KSPROPERTY_WAVE_FREQUENCY, + KSPROPERTY_WAVE_VOLUME, + KSPROPERTY_WAVE_PAN +} KSPROPERTY_WAVE; + +typedef struct { + ULONG ulDeviceType; +} KSWAVE_COMPATCAPS,*PKSWAVE_COMPATCAPS; + +#define KSWAVE_COMPATCAPS_INPUT 0x00000000 +#define KSWAVE_COMPATCAPS_OUTPUT 0x00000001 + +typedef struct { + ULONG MaximumChannelsPerConnection; + ULONG MinimumBitsPerSample; + ULONG MaximumBitsPerSample; + ULONG MinimumSampleFrequency; + ULONG MaximumSampleFrequency; + ULONG TotalConnections; + ULONG ActiveConnections; +} KSWAVE_INPUT_CAPABILITIES,*PKSWAVE_INPUT_CAPABILITIES; + +typedef struct { + ULONG MaximumChannelsPerConnection; + ULONG MinimumBitsPerSample; + ULONG MaximumBitsPerSample; + ULONG MinimumSampleFrequency; + ULONG MaximumSampleFrequency; + ULONG TotalConnections; + ULONG StaticConnections; + ULONG StreamingConnections; + ULONG ActiveConnections; + ULONG ActiveStaticConnections; + ULONG ActiveStreamingConnections; + ULONG Total3DConnections; + ULONG Static3DConnections; + ULONG Streaming3DConnections; + ULONG Active3DConnections; + ULONG ActiveStatic3DConnections; + ULONG ActiveStreaming3DConnections; + ULONG TotalSampleMemory; + ULONG FreeSampleMemory; + ULONG LargestFreeContiguousSampleMemory; +} KSWAVE_OUTPUT_CAPABILITIES,*PKSWAVE_OUTPUT_CAPABILITIES; + +typedef struct { + LONG LeftAttenuation; + LONG RightAttenuation; +} KSWAVE_VOLUME,*PKSWAVE_VOLUME; + +#define KSWAVE_BUFFER_ATTRIBUTEF_LOOPING 0x00000001 +#define KSWAVE_BUFFER_ATTRIBUTEF_STATIC 0x00000002 + +typedef struct { + ULONG Attributes; + ULONG BufferSize; + PVOID BufferAddress; +} KSWAVE_BUFFER,*PKSWAVE_BUFFER; + +#define STATIC_KSMUSIC_TECHNOLOGY_PORT \ + 0x86C92E60L,0x62E8,0x11CF,0xA5,0xD6,0x28,0xDB,0x04,0xC1,0x00,0x00 +DEFINE_GUIDSTRUCT("86C92E60-62E8-11CF-A5D6-28DB04C10000",KSMUSIC_TECHNOLOGY_PORT); +#define KSMUSIC_TECHNOLOGY_PORT DEFINE_GUIDNAMED(KSMUSIC_TECHNOLOGY_PORT) + +#define STATIC_KSMUSIC_TECHNOLOGY_SQSYNTH \ + 0x0ECF4380L,0x62E9,0x11CF,0xA5,0xD6,0x28,0xDB,0x04,0xC1,0x00,0x00 +DEFINE_GUIDSTRUCT("0ECF4380-62E9-11CF-A5D6-28DB04C10000",KSMUSIC_TECHNOLOGY_SQSYNTH); +#define KSMUSIC_TECHNOLOGY_SQSYNTH DEFINE_GUIDNAMED(KSMUSIC_TECHNOLOGY_SQSYNTH) + +#define STATIC_KSMUSIC_TECHNOLOGY_FMSYNTH \ + 0x252C5C80L,0x62E9,0x11CF,0xA5,0xD6,0x28,0xDB,0x04,0xC1,0x00,0x00 +DEFINE_GUIDSTRUCT("252C5C80-62E9-11CF-A5D6-28DB04C10000",KSMUSIC_TECHNOLOGY_FMSYNTH); +#define KSMUSIC_TECHNOLOGY_FMSYNTH DEFINE_GUIDNAMED(KSMUSIC_TECHNOLOGY_FMSYNTH) + +#define STATIC_KSMUSIC_TECHNOLOGY_WAVETABLE \ + 0x394EC7C0L,0x62E9,0x11CF,0xA5,0xD6,0x28,0xDB,0x04,0xC1,0x00,0x00 +DEFINE_GUIDSTRUCT("394EC7C0-62E9-11CF-A5D6-28DB04C10000",KSMUSIC_TECHNOLOGY_WAVETABLE); +#define KSMUSIC_TECHNOLOGY_WAVETABLE DEFINE_GUIDNAMED(KSMUSIC_TECHNOLOGY_WAVETABLE) + +#define STATIC_KSMUSIC_TECHNOLOGY_SWSYNTH \ + 0x37407736L,0x3620,0x11D1,0x85,0xD3,0x00,0x00,0xF8,0x75,0x43,0x80 +DEFINE_GUIDSTRUCT("37407736-3620-11D1-85D3-0000F8754380",KSMUSIC_TECHNOLOGY_SWSYNTH); +#define KSMUSIC_TECHNOLOGY_SWSYNTH DEFINE_GUIDNAMED(KSMUSIC_TECHNOLOGY_SWSYNTH) + +#define STATIC_KSPROPSETID_WaveTable \ + 0x8539E660L,0x62E9,0x11CF,0xA5,0xD6,0x28,0xDB,0x04,0xC1,0x00,0x00 +DEFINE_GUIDSTRUCT("8539E660-62E9-11CF-A5D6-28DB04C10000",KSPROPSETID_WaveTable); +#define KSPROPSETID_WaveTable DEFINE_GUIDNAMED(KSPROPSETID_WaveTable) + +typedef enum { + KSPROPERTY_WAVETABLE_LOAD_SAMPLE, + KSPROPERTY_WAVETABLE_UNLOAD_SAMPLE, + KSPROPERTY_WAVETABLE_MEMORY, + KSPROPERTY_WAVETABLE_VERSION +} KSPROPERTY_WAVETABLE; + +typedef struct { + KSDATARANGE DataRange; + GUID Technology; + ULONG Channels; + ULONG Notes; + ULONG ChannelMask; +} KSDATARANGE_MUSIC,*PKSDATARANGE_MUSIC; + +#define STATIC_KSEVENTSETID_Cyclic \ + 0x142C1AC0L,0x072A,0x11D0,0xA5,0xD6,0x28,0xDB,0x04,0xC1,0x00,0x00 +DEFINE_GUIDSTRUCT("142C1AC0-072A-11D0-A5D6-28DB04C10000",KSEVENTSETID_Cyclic); +#define KSEVENTSETID_Cyclic DEFINE_GUIDNAMED(KSEVENTSETID_Cyclic) + +typedef enum { + KSEVENT_CYCLIC_TIME_INTERVAL +} KSEVENT_CYCLIC_TIME; + +#define STATIC_KSPROPSETID_Cyclic \ + 0x3FFEAEA0L,0x2BEE,0x11CF,0xA5,0xD6,0x28,0xDB,0x04,0xC1,0x00,0x00 +DEFINE_GUIDSTRUCT("3FFEAEA0-2BEE-11CF-A5D6-28DB04C10000",KSPROPSETID_Cyclic); +#define KSPROPSETID_Cyclic DEFINE_GUIDNAMED(KSPROPSETID_Cyclic) + +typedef enum { + KSPROPERTY_CYCLIC_POSITION +} KSPROPERTY_CYCLIC; + +#define STATIC_KSEVENTSETID_AudioControlChange \ + 0xE85E9698L,0xFA2F,0x11D1,0x95,0xBD,0x00,0xC0,0x4F,0xB9,0x25,0xD3 +DEFINE_GUIDSTRUCT("E85E9698-FA2F-11D1-95BD-00C04FB925D3",KSEVENTSETID_AudioControlChange); +#define KSEVENTSETID_AudioControlChange DEFINE_GUIDNAMED(KSEVENTSETID_AudioControlChange) + +typedef enum { + KSEVENT_CONTROL_CHANGE +} KSEVENT_AUDIO_CONTROL_CHANGE; + +#define STATIC_KSEVENTSETID_LoopedStreaming \ + 0x4682B940L,0xC6EF,0x11D0,0x96,0xD8,0x00,0xAA,0x00,0x51,0xE5,0x1D +DEFINE_GUIDSTRUCT("4682B940-C6EF-11D0-96D8-00AA0051E51D",KSEVENTSETID_LoopedStreaming); +#define KSEVENTSETID_LoopedStreaming DEFINE_GUIDNAMED(KSEVENTSETID_LoopedStreaming) + +typedef enum { + KSEVENT_LOOPEDSTREAMING_POSITION +} KSEVENT_LOOPEDSTREAMING; + +typedef struct { + KSEVENTDATA KsEventData; + DWORDLONG Position; +} LOOPEDSTREAMING_POSITION_EVENT_DATA,*PLOOPEDSTREAMING_POSITION_EVENT_DATA; + +#define STATIC_KSPROPSETID_Sysaudio \ + 0xCBE3FAA0L,0xCC75,0x11D0,0xB4,0x65,0x00,0x00,0x1A,0x18,0x18,0xE6 +DEFINE_GUIDSTRUCT("CBE3FAA0-CC75-11D0-B465-00001A1818E6",KSPROPSETID_Sysaudio); +#define KSPROPSETID_Sysaudio DEFINE_GUIDNAMED(KSPROPSETID_Sysaudio) + +typedef enum { + KSPROPERTY_SYSAUDIO_DEVICE_COUNT = 1, + KSPROPERTY_SYSAUDIO_DEVICE_FRIENDLY_NAME = 2, + KSPROPERTY_SYSAUDIO_DEVICE_INSTANCE = 3, + KSPROPERTY_SYSAUDIO_DEVICE_INTERFACE_NAME = 4, + KSPROPERTY_SYSAUDIO_SELECT_GRAPH = 5, + KSPROPERTY_SYSAUDIO_CREATE_VIRTUAL_SOURCE = 6, + KSPROPERTY_SYSAUDIO_DEVICE_DEFAULT = 7, + KSPROPERTY_SYSAUDIO_INSTANCE_INFO = 14, + KSPROPERTY_SYSAUDIO_COMPONENT_ID = 16 +} KSPROPERTY_SYSAUDIO; + +typedef struct { + KSPROPERTY Property; + GUID PinCategory; + GUID PinName; +} SYSAUDIO_CREATE_VIRTUAL_SOURCE,*PSYSAUDIO_CREATE_VIRTUAL_SOURCE; + +typedef struct { + KSPROPERTY Property; + ULONG PinId; + ULONG NodeId; + ULONG Flags; + ULONG Reserved; +} SYSAUDIO_SELECT_GRAPH,*PSYSAUDIO_SELECT_GRAPH; + +typedef struct { + KSPROPERTY Property; + ULONG Flags; + ULONG DeviceNumber; +} SYSAUDIO_INSTANCE_INFO,*PSYSAUDIO_INSTANCE_INFO; + +#define SYSAUDIO_FLAGS_DONT_COMBINE_PINS 0x00000001 + +#define STATIC_KSPROPSETID_Sysaudio_Pin \ + 0xA3A53220L,0xC6E4,0x11D0,0xB4,0x65,0x00,0x00,0x1A,0x18,0x18,0xE6 +DEFINE_GUIDSTRUCT("A3A53220-C6E4-11D0-B465-00001A1818E6",KSPROPSETID_Sysaudio_Pin); +#define KSPROPSETID_Sysaudio_Pin DEFINE_GUIDNAMED(KSPROPSETID_Sysaudio_Pin) + +typedef enum { + KSPROPERTY_SYSAUDIO_ATTACH_VIRTUAL_SOURCE = 1 +} KSPROPERTY_SYSAUDIO_PIN; + +typedef struct { + KSPROPERTY Property; + ULONG MixerPinId; + ULONG Reserved; +} SYSAUDIO_ATTACH_VIRTUAL_SOURCE,*PSYSAUDIO_ATTACH_VIRTUAL_SOURCE; + +typedef struct { + KSPROPERTY Property; + ULONG NodeId; + ULONG Reserved; +} KSNODEPROPERTY,*PKSNODEPROPERTY; + +typedef struct { + KSNODEPROPERTY NodeProperty; + LONG Channel; + ULONG Reserved; +} KSNODEPROPERTY_AUDIO_CHANNEL,*PKSNODEPROPERTY_AUDIO_CHANNEL; + +typedef struct { + KSNODEPROPERTY NodeProperty; + ULONG DevSpecificId; + ULONG DeviceInfo; + ULONG Length; +} KSNODEPROPERTY_AUDIO_DEV_SPECIFIC,*PKSNODEPROPERTY_AUDIO_DEV_SPECIFIC; + +typedef struct { + KSNODEPROPERTY NodeProperty; + PVOID ListenerId; +#ifndef _WIN64 + ULONG Reserved; +#endif +} KSNODEPROPERTY_AUDIO_3D_LISTENER,*PKSNODEPROPERTY_AUDIO_3D_LISTENER; + +typedef struct { + KSNODEPROPERTY NodeProperty; + PVOID AppContext; + ULONG Length; +#ifndef _WIN64 + ULONG Reserved; +#endif +} KSNODEPROPERTY_AUDIO_PROPERTY,*PKSNODEPROPERTY_AUDIO_PROPERTY; + +#define STATIC_KSPROPSETID_AudioGfx \ + 0x79a9312eL,0x59ae,0x43b0,0xa3,0x50,0x8b,0x5,0x28,0x4c,0xab,0x24 +DEFINE_GUIDSTRUCT("79A9312E-59AE-43b0-A350-8B05284CAB24",KSPROPSETID_AudioGfx); +#define KSPROPSETID_AudioGfx DEFINE_GUIDNAMED(KSPROPSETID_AudioGfx) + +typedef enum { + KSPROPERTY_AUDIOGFX_RENDERTARGETDEVICEID, + KSPROPERTY_AUDIOGFX_CAPTURETARGETDEVICEID +} KSPROPERTY_AUDIOGFX; + +#define STATIC_KSPROPSETID_Linear \ + 0x5A2FFE80L,0x16B9,0x11D0,0xA5,0xD6,0x28,0xDB,0x04,0xC1,0x00,0x00 +DEFINE_GUIDSTRUCT("5A2FFE80-16B9-11D0-A5D6-28DB04C10000",KSPROPSETID_Linear); +#define KSPROPSETID_Linear DEFINE_GUIDNAMED(KSPROPSETID_Linear) + +typedef enum { + KSPROPERTY_LINEAR_POSITION +} KSPROPERTY_LINEAR; + +#define STATIC_KSDATAFORMAT_TYPE_MUSIC \ + 0xE725D360L,0x62CC,0x11CF,0xA5,0xD6,0x28,0xDB,0x04,0xC1,0x00,0x00 +DEFINE_GUIDSTRUCT("E725D360-62CC-11CF-A5D6-28DB04C10000",KSDATAFORMAT_TYPE_MUSIC); +#define KSDATAFORMAT_TYPE_MUSIC DEFINE_GUIDNAMED(KSDATAFORMAT_TYPE_MUSIC) + +#define STATIC_KSDATAFORMAT_TYPE_MIDI \ + 0x7364696DL,0x0000,0x0010,0x80,0x00,0x00,0xaa,0x00,0x38,0x9b,0x71 +DEFINE_GUIDSTRUCT("7364696D-0000-0010-8000-00aa00389b71",KSDATAFORMAT_TYPE_MIDI); +#define KSDATAFORMAT_TYPE_MIDI DEFINE_GUIDNAMED(KSDATAFORMAT_TYPE_MIDI) + +#define STATIC_KSDATAFORMAT_SUBTYPE_MIDI \ + 0x1D262760L,0xE957,0x11CF,0xA5,0xD6,0x28,0xDB,0x04,0xC1,0x00,0x00 +DEFINE_GUIDSTRUCT("1D262760-E957-11CF-A5D6-28DB04C10000",KSDATAFORMAT_SUBTYPE_MIDI); +#define KSDATAFORMAT_SUBTYPE_MIDI DEFINE_GUIDNAMED(KSDATAFORMAT_SUBTYPE_MIDI) + +#define STATIC_KSDATAFORMAT_SUBTYPE_MIDI_BUS \ + 0x2CA15FA0L,0x6CFE,0x11CF,0xA5,0xD6,0x28,0xDB,0x04,0xC1,0x00,0x00 +DEFINE_GUIDSTRUCT("2CA15FA0-6CFE-11CF-A5D6-28DB04C10000",KSDATAFORMAT_SUBTYPE_MIDI_BUS); +#define KSDATAFORMAT_SUBTYPE_MIDI_BUS DEFINE_GUIDNAMED(KSDATAFORMAT_SUBTYPE_MIDI_BUS) + +#define STATIC_KSDATAFORMAT_SUBTYPE_RIFFMIDI \ + 0x4995DAF0L,0x9EE6,0x11D0,0xA4,0x0E,0x00,0xA0,0xC9,0x22,0x31,0x96 +DEFINE_GUIDSTRUCT("4995DAF0-9EE6-11D0-A40E-00A0C9223196",KSDATAFORMAT_SUBTYPE_RIFFMIDI); +#define KSDATAFORMAT_SUBTYPE_RIFFMIDI DEFINE_GUIDNAMED(KSDATAFORMAT_SUBTYPE_RIFFMIDI) + +typedef struct { + ULONG TimeDeltaMs; + + ULONG ByteCount; +} KSMUSICFORMAT,*PKSMUSICFORMAT; + +#define STATIC_KSDATAFORMAT_TYPE_STANDARD_ELEMENTARY_STREAM \ + 0x36523b11L,0x8ee5,0x11d1,0x8c,0xa3,0x00,0x60,0xb0,0x57,0x66,0x4a +DEFINE_GUIDSTRUCT("36523B11-8EE5-11d1-8CA3-0060B057664A",KSDATAFORMAT_TYPE_STANDARD_ELEMENTARY_STREAM); +#define KSDATAFORMAT_TYPE_STANDARD_ELEMENTARY_STREAM DEFINE_GUIDNAMED(KSDATAFORMAT_TYPE_STANDARD_ELEMENTARY_STREAM) + +#define STATIC_KSDATAFORMAT_TYPE_STANDARD_PES_PACKET \ + 0x36523b12L,0x8ee5,0x11d1,0x8c,0xa3,0x00,0x60,0xb0,0x57,0x66,0x4a +DEFINE_GUIDSTRUCT("36523B12-8EE5-11d1-8CA3-0060B057664A",KSDATAFORMAT_TYPE_STANDARD_PES_PACKET); +#define KSDATAFORMAT_TYPE_STANDARD_PES_PACKET DEFINE_GUIDNAMED(KSDATAFORMAT_TYPE_STANDARD_PES_PACKET) + +#define STATIC_KSDATAFORMAT_TYPE_STANDARD_PACK_HEADER \ + 0x36523b13L,0x8ee5,0x11d1,0x8c,0xa3,0x00,0x60,0xb0,0x57,0x66,0x4a +DEFINE_GUIDSTRUCT("36523B13-8EE5-11d1-8CA3-0060B057664A",KSDATAFORMAT_TYPE_STANDARD_PACK_HEADER); +#define KSDATAFORMAT_TYPE_STANDARD_PACK_HEADER DEFINE_GUIDNAMED(KSDATAFORMAT_TYPE_STANDARD_PACK_HEADER) + +#define STATIC_KSDATAFORMAT_SUBTYPE_STANDARD_MPEG1_VIDEO \ + 0x36523b21L,0x8ee5,0x11d1,0x8c,0xa3,0x00,0x60,0xb0,0x57,0x66,0x4a +DEFINE_GUIDSTRUCT("36523B21-8EE5-11d1-8CA3-0060B057664A",KSDATAFORMAT_SUBTYPE_STANDARD_MPEG1_VIDEO); +#define KSDATAFORMAT_SUBTYPE_STANDARD_MPEG1_VIDEO DEFINE_GUIDNAMED(KSDATAFORMAT_SUBTYPE_STANDARD_MPEG1_VIDEO) + +#define STATIC_KSDATAFORMAT_SUBTYPE_STANDARD_MPEG1_AUDIO \ + 0x36523b22L,0x8ee5,0x11d1,0x8c,0xa3,0x00,0x60,0xb0,0x57,0x66,0x4a +DEFINE_GUIDSTRUCT("36523B22-8EE5-11d1-8CA3-0060B057664A",KSDATAFORMAT_SUBTYPE_STANDARD_MPEG1_AUDIO); +#define KSDATAFORMAT_SUBTYPE_STANDARD_MPEG1_AUDIO DEFINE_GUIDNAMED(KSDATAFORMAT_SUBTYPE_STANDARD_MPEG1_AUDIO) + +#define STATIC_KSDATAFORMAT_SUBTYPE_STANDARD_MPEG2_VIDEO \ + 0x36523b23L,0x8ee5,0x11d1,0x8c,0xa3,0x00,0x60,0xb0,0x57,0x66,0x4a +DEFINE_GUIDSTRUCT("36523B23-8EE5-11d1-8CA3-0060B057664A",KSDATAFORMAT_SUBTYPE_STANDARD_MPEG2_VIDEO); +#define KSDATAFORMAT_SUBTYPE_STANDARD_MPEG2_VIDEO DEFINE_GUIDNAMED(KSDATAFORMAT_SUBTYPE_STANDARD_MPEG2_VIDEO) + +#define STATIC_KSDATAFORMAT_SUBTYPE_STANDARD_MPEG2_AUDIO \ + 0x36523b24L,0x8ee5,0x11d1,0x8c,0xa3,0x00,0x60,0xb0,0x57,0x66,0x4a +DEFINE_GUIDSTRUCT("36523B24-8EE5-11d1-8CA3-0060B057664A",KSDATAFORMAT_SUBTYPE_STANDARD_MPEG2_AUDIO); +#define KSDATAFORMAT_SUBTYPE_STANDARD_MPEG2_AUDIO DEFINE_GUIDNAMED(KSDATAFORMAT_SUBTYPE_STANDARD_MPEG2_AUDIO) + +#define STATIC_KSDATAFORMAT_SUBTYPE_STANDARD_AC3_AUDIO \ + 0x36523b25L,0x8ee5,0x11d1,0x8c,0xa3,0x00,0x60,0xb0,0x57,0x66,0x4a +DEFINE_GUIDSTRUCT("36523B25-8EE5-11d1-8CA3-0060B057664A",KSDATAFORMAT_SUBTYPE_STANDARD_AC3_AUDIO); +#define KSDATAFORMAT_SUBTYPE_STANDARD_AC3_AUDIO DEFINE_GUIDNAMED(KSDATAFORMAT_SUBTYPE_STANDARD_AC3_AUDIO) + +#define STATIC_KSDATAFORMAT_SPECIFIER_DIALECT_MPEG1_VIDEO \ + 0x36523b31L,0x8ee5,0x11d1,0x8c,0xa3,0x00,0x60,0xb0,0x57,0x66,0x4a +DEFINE_GUIDSTRUCT("36523B31-8EE5-11d1-8CA3-0060B057664A",KSDATAFORMAT_SPECIFIER_DIALECT_MPEG1_VIDEO); +#define KSDATAFORMAT_SPECIFIER_DIALECT_MPEG1_VIDEO DEFINE_GUIDNAMED(KSDATAFORMAT_SPECIFIER_DIALECT_MPEG1_VIDEO) + +#define STATIC_KSDATAFORMAT_SPECIFIER_DIALECT_MPEG1_AUDIO \ + 0x36523b32L,0x8ee5,0x11d1,0x8c,0xa3,0x00,0x60,0xb0,0x57,0x66,0x4a +DEFINE_GUIDSTRUCT("36523B32-8EE5-11d1-8CA3-0060B057664A",KSDATAFORMAT_SPECIFIER_DIALECT_MPEG1_AUDIO); +#define KSDATAFORMAT_SPECIFIER_DIALECT_MPEG1_AUDIO DEFINE_GUIDNAMED(KSDATAFORMAT_SPECIFIER_DIALECT_MPEG1_AUDIO) + +#define STATIC_KSDATAFORMAT_SPECIFIER_DIALECT_MPEG2_VIDEO \ + 0x36523b33L,0x8ee5,0x11d1,0x8c,0xa3,0x00,0x60,0xb0,0x57,0x66,0x4a +DEFINE_GUIDSTRUCT("36523B33-8EE5-11d1-8CA3-0060B057664A",KSDATAFORMAT_SPECIFIER_DIALECT_MPEG2_VIDEO); +#define KSDATAFORMAT_SPECIFIER_DIALECT_MPEG2_VIDEO DEFINE_GUIDNAMED(KSDATAFORMAT_SPECIFIER_DIALECT_MPEG2_VIDEO) + +#define STATIC_KSDATAFORMAT_SPECIFIER_DIALECT_MPEG2_AUDIO \ + 0x36523b34L,0x8ee5,0x11d1,0x8c,0xa3,0x00,0x60,0xb0,0x57,0x66,0x4a +DEFINE_GUIDSTRUCT("36523B34-8EE5-11d1-8CA3-0060B057664A",KSDATAFORMAT_SPECIFIER_DIALECT_MPEG2_AUDIO); +#define KSDATAFORMAT_SPECIFIER_DIALECT_MPEG2_AUDIO DEFINE_GUIDNAMED(KSDATAFORMAT_SPECIFIER_DIALECT_MPEG2_AUDIO) + +#define STATIC_KSDATAFORMAT_SPECIFIER_DIALECT_AC3_AUDIO \ + 0x36523b35L,0x8ee5,0x11d1,0x8c,0xa3,0x00,0x60,0xb0,0x57,0x66,0x4a +DEFINE_GUIDSTRUCT("36523B35-8EE5-11d1-8CA3-0060B057664A",KSDATAFORMAT_SPECIFIER_DIALECT_AC3_AUDIO); +#define KSDATAFORMAT_SPECIFIER_DIALECT_AC3_AUDIO DEFINE_GUIDNAMED(KSDATAFORMAT_SPECIFIER_DIALECT_AC3_AUDIO) + +#define STATIC_KSDATAFORMAT_SUBTYPE_DSS_VIDEO \ + 0xa0af4f81L,0xe163,0x11d0,0xba,0xd9,0x00,0x60,0x97,0x44,0x11,0x1a +DEFINE_GUIDSTRUCT("a0af4f81-e163-11d0-bad9-00609744111a",KSDATAFORMAT_SUBTYPE_DSS_VIDEO); +#define KSDATAFORMAT_SUBTYPE_DSS_VIDEO DEFINE_GUIDNAMED(KSDATAFORMAT_SUBTYPE_DSS_VIDEO) + +#define STATIC_KSDATAFORMAT_SUBTYPE_DSS_AUDIO \ + 0xa0af4f82L,0xe163,0x11d0,0xba,0xd9,0x00,0x60,0x97,0x44,0x11,0x1a +DEFINE_GUIDSTRUCT("a0af4f82-e163-11d0-bad9-00609744111a",KSDATAFORMAT_SUBTYPE_DSS_AUDIO); +#define KSDATAFORMAT_SUBTYPE_DSS_AUDIO DEFINE_GUIDNAMED(KSDATAFORMAT_SUBTYPE_DSS_AUDIO) + +#define STATIC_KSDATAFORMAT_SUBTYPE_MPEG1Packet \ + 0xe436eb80,0x524f,0x11ce,0x9f,0x53,0x00,0x20,0xaf,0x0b,0xa7,0x70 +DEFINE_GUIDSTRUCT("e436eb80-524f-11ce-9F53-0020af0ba770",KSDATAFORMAT_SUBTYPE_MPEG1Packet); +#define KSDATAFORMAT_SUBTYPE_MPEG1Packet DEFINE_GUIDNAMED(KSDATAFORMAT_SUBTYPE_MPEG1Packet) + +#define STATIC_KSDATAFORMAT_SUBTYPE_MPEG1Payload \ + 0xe436eb81,0x524f,0x11ce,0x9f,0x53,0x00,0x20,0xaf,0x0b,0xa7,0x70 +DEFINE_GUIDSTRUCT("e436eb81-524f-11ce-9F53-0020af0ba770",KSDATAFORMAT_SUBTYPE_MPEG1Payload); +#define KSDATAFORMAT_SUBTYPE_MPEG1Payload DEFINE_GUIDNAMED(KSDATAFORMAT_SUBTYPE_MPEG1Payload) + +#define STATIC_KSDATAFORMAT_SUBTYPE_MPEG1Video \ + 0xe436eb86,0x524f,0x11ce,0x9f,0x53,0x00,0x20,0xaf,0x0b,0xa7,0x70 +DEFINE_GUIDSTRUCT("e436eb86-524f-11ce-9f53-0020af0ba770",KSDATAFORMAT_SUBTYPE_MPEG1Video); +#define KSDATAFORMAT_SUBTYPE_MPEG1Video DEFINE_GUIDNAMED(KSDATAFORMAT_SUBTYPE_MPEG1Video) + +#define STATIC_KSDATAFORMAT_SPECIFIER_MPEG1_VIDEO \ + 0x05589f82L,0xc356,0x11ce,0xbf,0x01,0x00,0xaa,0x00,0x55,0x59,0x5a +DEFINE_GUIDSTRUCT("05589f82-c356-11ce-bf01-00aa0055595a",KSDATAFORMAT_SPECIFIER_MPEG1_VIDEO); +#define KSDATAFORMAT_SPECIFIER_MPEG1_VIDEO DEFINE_GUIDNAMED(KSDATAFORMAT_SPECIFIER_MPEG1_VIDEO) + +#define STATIC_KSDATAFORMAT_TYPE_MPEG2_PES \ + 0xe06d8020L,0xdb46,0x11cf,0xb4,0xd1,0x00,0x80,0x5f,0x6c,0xbb,0xea +DEFINE_GUIDSTRUCT("e06d8020-db46-11cf-b4d1-00805f6cbbea",KSDATAFORMAT_TYPE_MPEG2_PES); +#define KSDATAFORMAT_TYPE_MPEG2_PES DEFINE_GUIDNAMED(KSDATAFORMAT_TYPE_MPEG2_PES) + +#define STATIC_KSDATAFORMAT_TYPE_MPEG2_PROGRAM \ + 0xe06d8022L,0xdb46,0x11cf,0xb4,0xd1,0x00,0x80,0x5f,0x6c,0xbb,0xea +DEFINE_GUIDSTRUCT("e06d8022-db46-11cf-b4d1-00805f6cbbea",KSDATAFORMAT_TYPE_MPEG2_PROGRAM); +#define KSDATAFORMAT_TYPE_MPEG2_PROGRAM DEFINE_GUIDNAMED(KSDATAFORMAT_TYPE_MPEG2_PROGRAM) + +#define STATIC_KSDATAFORMAT_TYPE_MPEG2_TRANSPORT \ + 0xe06d8023L,0xdb46,0x11cf,0xb4,0xd1,0x00,0x80,0x5f,0x6c,0xbb,0xea +DEFINE_GUIDSTRUCT("e06d8023-db46-11cf-b4d1-00805f6cbbea",KSDATAFORMAT_TYPE_MPEG2_TRANSPORT); +#define KSDATAFORMAT_TYPE_MPEG2_TRANSPORT DEFINE_GUIDNAMED(KSDATAFORMAT_TYPE_MPEG2_TRANSPORT) + +#define STATIC_KSDATAFORMAT_SUBTYPE_MPEG2_VIDEO \ + 0xe06d8026L,0xdb46,0x11cf,0xb4,0xd1,0x00,0x80,0x5f,0x6c,0xbb,0xea +DEFINE_GUIDSTRUCT("e06d8026-db46-11cf-b4d1-00805f6cbbea",KSDATAFORMAT_SUBTYPE_MPEG2_VIDEO); +#define KSDATAFORMAT_SUBTYPE_MPEG2_VIDEO DEFINE_GUIDNAMED(KSDATAFORMAT_SUBTYPE_MPEG2_VIDEO) + +#define STATIC_KSDATAFORMAT_SPECIFIER_MPEG2_VIDEO \ + 0xe06d80e3L,0xdb46,0x11cf,0xb4,0xd1,0x00,0x80,0x5f,0x6c,0xbb,0xea +DEFINE_GUIDSTRUCT("e06d80e3-db46-11cf-b4d1-00805f6cbbea",KSDATAFORMAT_SPECIFIER_MPEG2_VIDEO); +#define KSDATAFORMAT_SPECIFIER_MPEG2_VIDEO DEFINE_GUIDNAMED(KSDATAFORMAT_SPECIFIER_MPEG2_VIDEO) + +#define STATIC_KSPROPSETID_Mpeg2Vid \ + 0xC8E11B60L,0x0CC9,0x11D0,0xBD,0x69,0x00,0x35,0x05,0xC1,0x03,0xA9 +DEFINE_GUIDSTRUCT("C8E11B60-0CC9-11D0-BD69-003505C103A9",KSPROPSETID_Mpeg2Vid); +#define KSPROPSETID_Mpeg2Vid DEFINE_GUIDNAMED(KSPROPSETID_Mpeg2Vid) + +typedef enum { + KSPROPERTY_MPEG2VID_MODES, + KSPROPERTY_MPEG2VID_CUR_MODE, + KSPROPERTY_MPEG2VID_4_3_RECT, + KSPROPERTY_MPEG2VID_16_9_RECT, + KSPROPERTY_MPEG2VID_16_9_PANSCAN +} KSPROPERTY_MPEG2VID; + +#define KSMPEGVIDMODE_PANSCAN 0x0001 +#define KSMPEGVIDMODE_LTRBOX 0x0002 +#define KSMPEGVIDMODE_SCALE 0x0004 + +typedef struct _KSMPEGVID_RECT { + ULONG StartX; + ULONG StartY; + ULONG EndX; + ULONG EndY; +} KSMPEGVID_RECT,*PKSMPEGVID_RECT; + +#define STATIC_KSDATAFORMAT_SUBTYPE_MPEG2_AUDIO \ + 0xe06d802bL,0xdb46,0x11cf,0xb4,0xd1,0x00,0x80,0x5f,0x6c,0xbb,0xea +DEFINE_GUIDSTRUCT("e06d802b-db46-11cf-b4d1-00805f6cbbea",KSDATAFORMAT_SUBTYPE_MPEG2_AUDIO); +#define KSDATAFORMAT_SUBTYPE_MPEG2_AUDIO DEFINE_GUIDNAMED(KSDATAFORMAT_SUBTYPE_MPEG2_AUDIO) + +#define STATIC_KSDATAFORMAT_SPECIFIER_MPEG2_AUDIO \ + 0xe06d80e5L,0xdb46,0x11cf,0xb4,0xd1,0x00,0x80,0x5f,0x6c,0xbb,0xea +DEFINE_GUIDSTRUCT("e06d80e5-db46-11cf-b4d1-00805f6cbbea",KSDATAFORMAT_SPECIFIER_MPEG2_AUDIO); +#define KSDATAFORMAT_SPECIFIER_MPEG2_AUDIO DEFINE_GUIDNAMED(KSDATAFORMAT_SPECIFIER_MPEG2_AUDIO) + +#define STATIC_KSDATAFORMAT_SUBTYPE_LPCM_AUDIO \ + 0xe06d8032L,0xdb46,0x11cf,0xb4,0xd1,0x00,0x80,0x5f,0x6c,0xbb,0xea +DEFINE_GUIDSTRUCT("e06d8032-db46-11cf-b4d1-00805f6cbbea",KSDATAFORMAT_SUBTYPE_LPCM_AUDIO); +#define KSDATAFORMAT_SUBTYPE_LPCM_AUDIO DEFINE_GUIDNAMED(KSDATAFORMAT_SUBTYPE_LPCM_AUDIO) + +#define STATIC_KSDATAFORMAT_SPECIFIER_LPCM_AUDIO \ + 0xe06d80e6L,0xdb46,0x11cf,0xb4,0xd1,0x00,0x80,0x5f,0x6c,0xbb,0xea +DEFINE_GUIDSTRUCT("e06d80e6-db46-11cf-b4d1-00805f6cbbea",KSDATAFORMAT_SPECIFIER_LPCM_AUDIO); +#define KSDATAFORMAT_SPECIFIER_LPCM_AUDIO DEFINE_GUIDNAMED(KSDATAFORMAT_SPECIFIER_LPCM_AUDIO) + +#define STATIC_KSDATAFORMAT_SUBTYPE_AC3_AUDIO \ + 0xe06d802cL,0xdb46,0x11cf,0xb4,0xd1,0x00,0x80,0x5f,0x6c,0xbb,0xea +DEFINE_GUIDSTRUCT("e06d802c-db46-11cf-b4d1-00805f6cbbea",KSDATAFORMAT_SUBTYPE_AC3_AUDIO); +#define KSDATAFORMAT_SUBTYPE_AC3_AUDIO DEFINE_GUIDNAMED(KSDATAFORMAT_SUBTYPE_AC3_AUDIO) + +#define STATIC_KSDATAFORMAT_SPECIFIER_AC3_AUDIO \ + 0xe06d80e4L,0xdb46,0x11cf,0xb4,0xd1,0x00,0x80,0x5f,0x6c,0xbb,0xea +DEFINE_GUIDSTRUCT("e06d80e4-db46-11cf-b4d1-00805f6cbbea",KSDATAFORMAT_SPECIFIER_AC3_AUDIO); +#define KSDATAFORMAT_SPECIFIER_AC3_AUDIO DEFINE_GUIDNAMED(KSDATAFORMAT_SPECIFIER_AC3_AUDIO) + +#define STATIC_KSPROPSETID_AC3 \ + 0xBFABE720L,0x6E1F,0x11D0,0xBC,0xF2,0x44,0x45,0x53,0x54,0x00,0x00 +DEFINE_GUIDSTRUCT("BFABE720-6E1F-11D0-BCF2-444553540000",KSPROPSETID_AC3); +#define KSPROPSETID_AC3 DEFINE_GUIDNAMED(KSPROPSETID_AC3) + +typedef enum { + KSPROPERTY_AC3_ERROR_CONCEALMENT = 1, + KSPROPERTY_AC3_ALTERNATE_AUDIO, + KSPROPERTY_AC3_DOWNMIX, + KSPROPERTY_AC3_BIT_STREAM_MODE, + KSPROPERTY_AC3_DIALOGUE_LEVEL, + KSPROPERTY_AC3_LANGUAGE_CODE, + KSPROPERTY_AC3_ROOM_TYPE +} KSPROPERTY_AC3; + +typedef struct { + WINBOOL fRepeatPreviousBlock; + WINBOOL fErrorInCurrentBlock; +} KSAC3_ERROR_CONCEALMENT,*PKSAC3_ERROR_CONCEALMENT; + +typedef struct { + WINBOOL fStereo; + ULONG DualMode; +} KSAC3_ALTERNATE_AUDIO,*PKSAC3_ALTERNATE_AUDIO; + +#define KSAC3_ALTERNATE_AUDIO_1 1 +#define KSAC3_ALTERNATE_AUDIO_2 2 +#define KSAC3_ALTERNATE_AUDIO_BOTH 3 + +typedef struct { + WINBOOL fDownMix; + WINBOOL fDolbySurround; +} KSAC3_DOWNMIX,*PKSAC3_DOWNMIX; + +typedef struct { + LONG BitStreamMode; +} KSAC3_BIT_STREAM_MODE,*PKSAC3_BIT_STREAM_MODE; + +#define KSAC3_SERVICE_MAIN_AUDIO 0 +#define KSAC3_SERVICE_NO_DIALOG 1 +#define KSAC3_SERVICE_VISUALLY_IMPAIRED 2 +#define KSAC3_SERVICE_HEARING_IMPAIRED 3 +#define KSAC3_SERVICE_DIALOG_ONLY 4 +#define KSAC3_SERVICE_COMMENTARY 5 +#define KSAC3_SERVICE_EMERGENCY_FLASH 6 +#define KSAC3_SERVICE_VOICE_OVER 7 + +typedef struct { + ULONG DialogueLevel; +} KSAC3_DIALOGUE_LEVEL,*PKSAC3_DIALOGUE_LEVEL; + +typedef struct { + WINBOOL fLargeRoom; +} KSAC3_ROOM_TYPE,*PKSAC3_ROOM_TYPE; + +#define STATIC_KSDATAFORMAT_SUBTYPE_DTS_AUDIO \ + 0xe06d8033L,0xdb46,0x11cf,0xb4,0xd1,0x00,0x80,0x5f,0x6c,0xbb,0xea +DEFINE_GUIDSTRUCT("e06d8033-db46-11cf-b4d1-00805f6cbbea",KSDATAFORMAT_SUBTYPE_DTS_AUDIO); +#define KSDATAFORMAT_SUBTYPE_DTS_AUDIO DEFINE_GUIDNAMED(KSDATAFORMAT_SUBTYPE_DTS_AUDIO) + +#define STATIC_KSDATAFORMAT_SUBTYPE_SDDS_AUDIO \ + 0xe06d8034L,0xdb46,0x11cf,0xb4,0xd1,0x00,0x80,0x5f,0x6c,0xbb,0xea +DEFINE_GUIDSTRUCT("e06d8034-db46-11cf-b4d1-00805f6cbbea",KSDATAFORMAT_SUBTYPE_SDDS_AUDIO); +#define KSDATAFORMAT_SUBTYPE_SDDS_AUDIO DEFINE_GUIDNAMED(KSDATAFORMAT_SUBTYPE_SDDS_AUDIO) + +#define STATIC_KSPROPSETID_AudioDecoderOut \ + 0x6ca6e020L,0x43bd,0x11d0,0xbd,0x6a,0x00,0x35,0x05,0xc1,0x03,0xa9 +DEFINE_GUIDSTRUCT("6ca6e020-43bd-11d0-bd6a-003505c103a9",KSPROPSETID_AudioDecoderOut); +#define KSPROPSETID_AudioDecoderOut DEFINE_GUIDNAMED(KSPROPSETID_AudioDecoderOut) + +typedef enum { + KSPROPERTY_AUDDECOUT_MODES, + KSPROPERTY_AUDDECOUT_CUR_MODE +} KSPROPERTY_AUDDECOUT; + +#define KSAUDDECOUTMODE_STEREO_ANALOG 0x0001 +#define KSAUDDECOUTMODE_PCM_51 0x0002 +#define KSAUDDECOUTMODE_SPDIFF 0x0004 + +#define STATIC_KSDATAFORMAT_SUBTYPE_SUBPICTURE \ + 0xe06d802dL,0xdb46,0x11cf,0xb4,0xd1,0x00,0x80,0x5f,0x6c,0xbb,0xea +DEFINE_GUIDSTRUCT("e06d802d-db46-11cf-b4d1-00805f6cbbea",KSDATAFORMAT_SUBTYPE_SUBPICTURE); +#define KSDATAFORMAT_SUBTYPE_SUBPICTURE DEFINE_GUIDNAMED(KSDATAFORMAT_SUBTYPE_SUBPICTURE) + +#define STATIC_KSPROPSETID_DvdSubPic \ + 0xac390460L,0x43af,0x11d0,0xbd,0x6a,0x00,0x35,0x05,0xc1,0x03,0xa9 +DEFINE_GUIDSTRUCT("ac390460-43af-11d0-bd6a-003505c103a9",KSPROPSETID_DvdSubPic); +#define KSPROPSETID_DvdSubPic DEFINE_GUIDNAMED(KSPROPSETID_DvdSubPic) + +typedef enum { + KSPROPERTY_DVDSUBPIC_PALETTE, + KSPROPERTY_DVDSUBPIC_HLI, + KSPROPERTY_DVDSUBPIC_COMPOSIT_ON +} KSPROPERTY_DVDSUBPIC; + +typedef struct _KS_DVD_YCrCb { + UCHAR Reserved; + UCHAR Y; + UCHAR Cr; + UCHAR Cb; +} KS_DVD_YCrCb,*PKS_DVD_YCrCb; + +typedef struct _KS_DVD_YUV { + UCHAR Reserved; + UCHAR Y; + UCHAR V; + UCHAR U; +} KS_DVD_YUV,*PKS_DVD_YUV; + +typedef struct _KSPROPERTY_SPPAL { + KS_DVD_YUV sppal[16]; +} KSPROPERTY_SPPAL,*PKSPROPERTY_SPPAL; + +typedef struct _KS_COLCON { + UCHAR emph1col:4; + UCHAR emph2col:4; + UCHAR backcol:4; + UCHAR patcol:4; + UCHAR emph1con:4; + UCHAR emph2con:4; + UCHAR backcon:4; + UCHAR patcon:4; +} KS_COLCON,*PKS_COLCON; + +typedef struct _KSPROPERTY_SPHLI { + USHORT HLISS; + USHORT Reserved; + ULONG StartPTM; + ULONG EndPTM; + USHORT StartX; + USHORT StartY; + USHORT StopX; + USHORT StopY; + KS_COLCON ColCon; +} KSPROPERTY_SPHLI,*PKSPROPERTY_SPHLI; + +typedef WINBOOL KSPROPERTY_COMPOSIT_ON,*PKSPROPERTY_COMPOSIT_ON; + +#define STATIC_KSPROPSETID_CopyProt \ + 0x0E8A0A40L,0x6AEF,0x11D0,0x9E,0xD0,0x00,0xA0,0x24,0xCA,0x19,0xB3 +DEFINE_GUIDSTRUCT("0E8A0A40-6AEF-11D0-9ED0-00A024CA19B3",KSPROPSETID_CopyProt); +#define KSPROPSETID_CopyProt DEFINE_GUIDNAMED(KSPROPSETID_CopyProt) + +typedef enum { + KSPROPERTY_DVDCOPY_CHLG_KEY = 0x01, + KSPROPERTY_DVDCOPY_DVD_KEY1, + KSPROPERTY_DVDCOPY_DEC_KEY2, + KSPROPERTY_DVDCOPY_TITLE_KEY, + KSPROPERTY_COPY_MACROVISION, + KSPROPERTY_DVDCOPY_REGION, + KSPROPERTY_DVDCOPY_SET_COPY_STATE, + KSPROPERTY_DVDCOPY_DISC_KEY = 0x80 +} KSPROPERTY_COPYPROT; + +typedef struct _KS_DVDCOPY_CHLGKEY { + BYTE ChlgKey[10]; + BYTE Reserved[2]; +} KS_DVDCOPY_CHLGKEY,*PKS_DVDCOPY_CHLGKEY; + +typedef struct _KS_DVDCOPY_BUSKEY { + BYTE BusKey[5]; + BYTE Reserved[1]; +} KS_DVDCOPY_BUSKEY,*PKS_DVDCOPY_BUSKEY; + +typedef struct _KS_DVDCOPY_DISCKEY { + BYTE DiscKey[2048]; +} KS_DVDCOPY_DISCKEY,*PKS_DVDCOPY_DISCKEY; + +typedef struct _KS_DVDCOPY_REGION { + UCHAR Reserved; + UCHAR RegionData; + UCHAR Reserved2[2]; +} KS_DVDCOPY_REGION,*PKS_DVDCOPY_REGION; + +typedef struct _KS_DVDCOPY_TITLEKEY { + ULONG KeyFlags; + ULONG ReservedNT[2]; + UCHAR TitleKey[6]; + UCHAR Reserved[2]; +} KS_DVDCOPY_TITLEKEY,*PKS_DVDCOPY_TITLEKEY; + +typedef struct _KS_COPY_MACROVISION { + ULONG MACROVISIONLevel; +} KS_COPY_MACROVISION,*PKS_COPY_MACROVISION; + +typedef struct _KS_DVDCOPY_SET_COPY_STATE { + ULONG DVDCopyState; +} KS_DVDCOPY_SET_COPY_STATE,*PKS_DVDCOPY_SET_COPY_STATE; + +typedef enum { + KS_DVDCOPYSTATE_INITIALIZE, + KS_DVDCOPYSTATE_INITIALIZE_TITLE, + KS_DVDCOPYSTATE_AUTHENTICATION_NOT_REQUIRED, + KS_DVDCOPYSTATE_AUTHENTICATION_REQUIRED, + KS_DVDCOPYSTATE_DONE +} KS_DVDCOPYSTATE; + +typedef enum { + KS_MACROVISION_DISABLED, + KS_MACROVISION_LEVEL1, + KS_MACROVISION_LEVEL2, + KS_MACROVISION_LEVEL3 +} KS_COPY_MACROVISION_LEVEL,*PKS_COPY_MACROVISION_LEVEL; + +#define KS_DVD_CGMS_RESERVED_MASK 0x00000078 + +#define KS_DVD_CGMS_COPY_PROTECT_MASK 0x00000018 +#define KS_DVD_CGMS_COPY_PERMITTED 0x00000000 +#define KS_DVD_CGMS_COPY_ONCE 0x00000010 +#define KS_DVD_CGMS_NO_COPY 0x00000018 + +#define KS_DVD_COPYRIGHT_MASK 0x00000040 +#define KS_DVD_NOT_COPYRIGHTED 0x00000000 +#define KS_DVD_COPYRIGHTED 0x00000040 + +#define KS_DVD_SECTOR_PROTECT_MASK 0x00000020 +#define KS_DVD_SECTOR_NOT_PROTECTED 0x00000000 +#define KS_DVD_SECTOR_PROTECTED 0x00000020 + +#define STATIC_KSCATEGORY_TVTUNER \ + 0xa799a800L,0xa46d,0x11d0,0xa1,0x8c,0x00,0xa0,0x24,0x01,0xdc,0xd4 +DEFINE_GUIDSTRUCT("a799a800-a46d-11d0-a18c-00a02401dcd4",KSCATEGORY_TVTUNER); +#define KSCATEGORY_TVTUNER DEFINE_GUIDNAMED(KSCATEGORY_TVTUNER) + +#define STATIC_KSCATEGORY_CROSSBAR \ + 0xa799a801L,0xa46d,0x11d0,0xa1,0x8c,0x00,0xa0,0x24,0x01,0xdc,0xd4 +DEFINE_GUIDSTRUCT("a799a801-a46d-11d0-a18c-00a02401dcd4",KSCATEGORY_CROSSBAR); +#define KSCATEGORY_CROSSBAR DEFINE_GUIDNAMED(KSCATEGORY_CROSSBAR) + +#define STATIC_KSCATEGORY_TVAUDIO \ + 0xa799a802L,0xa46d,0x11d0,0xa1,0x8c,0x00,0xa0,0x24,0x01,0xdc,0xd4 +DEFINE_GUIDSTRUCT("a799a802-a46d-11d0-a18c-00a02401dcd4",KSCATEGORY_TVAUDIO); +#define KSCATEGORY_TVAUDIO DEFINE_GUIDNAMED(KSCATEGORY_TVAUDIO) + +#define STATIC_KSCATEGORY_VPMUX \ + 0xa799a803L,0xa46d,0x11d0,0xa1,0x8c,0x00,0xa0,0x24,0x01,0xdc,0xd4 +DEFINE_GUIDSTRUCT("a799a803-a46d-11d0-a18c-00a02401dcd4",KSCATEGORY_VPMUX); +#define KSCATEGORY_VPMUX DEFINE_GUIDNAMED(KSCATEGORY_VPMUX) + +#define STATIC_KSCATEGORY_VBICODEC \ + 0x07dad660L,0x22f1,0x11d1,0xa9,0xf4,0x00,0xc0,0x4f,0xbb,0xde,0x8f +DEFINE_GUIDSTRUCT("07dad660-22f1-11d1-a9f4-00c04fbbde8f",KSCATEGORY_VBICODEC); +#define KSCATEGORY_VBICODEC DEFINE_GUIDNAMED(KSCATEGORY_VBICODEC) + +#define STATIC_KSDATAFORMAT_SUBTYPE_VPVideo \ + 0x5a9b6a40L,0x1a22,0x11d1,0xba,0xd9,0x0,0x60,0x97,0x44,0x11,0x1a +DEFINE_GUIDSTRUCT("5a9b6a40-1a22-11d1-bad9-00609744111a",KSDATAFORMAT_SUBTYPE_VPVideo); +#define KSDATAFORMAT_SUBTYPE_VPVideo DEFINE_GUIDNAMED(KSDATAFORMAT_SUBTYPE_VPVideo) + +#define STATIC_KSDATAFORMAT_SUBTYPE_VPVBI \ + 0x5a9b6a41L,0x1a22,0x11d1,0xba,0xd9,0x0,0x60,0x97,0x44,0x11,0x1a +DEFINE_GUIDSTRUCT("5a9b6a41-1a22-11d1-bad9-00609744111a",KSDATAFORMAT_SUBTYPE_VPVBI); +#define KSDATAFORMAT_SUBTYPE_VPVBI DEFINE_GUIDNAMED(KSDATAFORMAT_SUBTYPE_VPVBI) + +#define STATIC_KSDATAFORMAT_SPECIFIER_VIDEOINFO \ + 0x05589f80L,0xc356,0x11ce,0xbf,0x01,0x00,0xaa,0x00,0x55,0x59,0x5a +DEFINE_GUIDSTRUCT("05589f80-c356-11ce-bf01-00aa0055595a",KSDATAFORMAT_SPECIFIER_VIDEOINFO); +#define KSDATAFORMAT_SPECIFIER_VIDEOINFO DEFINE_GUIDNAMED(KSDATAFORMAT_SPECIFIER_VIDEOINFO) + +#define STATIC_KSDATAFORMAT_SPECIFIER_VIDEOINFO2 \ + 0xf72a76A0L,0xeb0a,0x11d0,0xac,0xe4,0x00,0x00,0xc0,0xcc,0x16,0xba +DEFINE_GUIDSTRUCT("f72a76A0-eb0a-11d0-ace4-0000c0cc16ba",KSDATAFORMAT_SPECIFIER_VIDEOINFO2); +#define KSDATAFORMAT_SPECIFIER_VIDEOINFO2 DEFINE_GUIDNAMED(KSDATAFORMAT_SPECIFIER_VIDEOINFO2) + +#define STATIC_KSDATAFORMAT_TYPE_ANALOGVIDEO \ + 0x0482dde1L,0x7817,0x11cf,0x8a,0x03,0x00,0xaa,0x00,0x6e,0xcb,0x65 +DEFINE_GUIDSTRUCT("0482dde1-7817-11cf-8a03-00aa006ecb65",KSDATAFORMAT_TYPE_ANALOGVIDEO); +#define KSDATAFORMAT_TYPE_ANALOGVIDEO DEFINE_GUIDNAMED(KSDATAFORMAT_TYPE_ANALOGVIDEO) + +#define STATIC_KSDATAFORMAT_SPECIFIER_ANALOGVIDEO \ + 0x0482dde0L,0x7817,0x11cf,0x8a,0x03,0x00,0xaa,0x00,0x6e,0xcb,0x65 +DEFINE_GUIDSTRUCT("0482dde0-7817-11cf-8a03-00aa006ecb65",KSDATAFORMAT_SPECIFIER_ANALOGVIDEO); +#define KSDATAFORMAT_SPECIFIER_ANALOGVIDEO DEFINE_GUIDNAMED(KSDATAFORMAT_SPECIFIER_ANALOGVIDEO) + +#define STATIC_KSDATAFORMAT_TYPE_ANALOGAUDIO \ + 0x0482dee1L,0x7817,0x11cf,0x8a,0x03,0x00,0xaa,0x00,0x6e,0xcb,0x65 +DEFINE_GUIDSTRUCT("0482DEE1-7817-11cf-8a03-00aa006ecb65",KSDATAFORMAT_TYPE_ANALOGAUDIO); +#define KSDATAFORMAT_TYPE_ANALOGAUDIO DEFINE_GUIDNAMED(KSDATAFORMAT_TYPE_ANALOGAUDIO) + +#define STATIC_KSDATAFORMAT_SPECIFIER_VBI \ + 0xf72a76e0L,0xeb0a,0x11d0,0xac,0xe4,0x00,0x00,0xc0,0xcc,0x16,0xba +DEFINE_GUIDSTRUCT("f72a76e0-eb0a-11d0-ace4-0000c0cc16ba",KSDATAFORMAT_SPECIFIER_VBI); +#define KSDATAFORMAT_SPECIFIER_VBI DEFINE_GUIDNAMED(KSDATAFORMAT_SPECIFIER_VBI) + +#define STATIC_KSDATAFORMAT_TYPE_VBI \ + 0xf72a76e1L,0xeb0a,0x11d0,0xac,0xe4,0x00,0x00,0xc0,0xcc,0x16,0xba +DEFINE_GUIDSTRUCT("f72a76e1-eb0a-11d0-ace4-0000c0cc16ba",KSDATAFORMAT_TYPE_VBI); +#define KSDATAFORMAT_TYPE_VBI DEFINE_GUIDNAMED(KSDATAFORMAT_TYPE_VBI) + +#define STATIC_KSDATAFORMAT_SUBTYPE_RAW8 \ + 0xca20d9a0,0x3e3e,0x11d1,0x9b,0xf9,0x0,0xc0,0x4f,0xbb,0xde,0xbf +DEFINE_GUIDSTRUCT("ca20d9a0-3e3e-11d1-9bf9-00c04fbbdebf",KSDATAFORMAT_SUBTYPE_RAW8); +#define KSDATAFORMAT_SUBTYPE_RAW8 DEFINE_GUIDNAMED(KSDATAFORMAT_SUBTYPE_RAW8) + +#define STATIC_KSDATAFORMAT_SUBTYPE_CC \ + 0x33214cc1,0x11f,0x11d2,0xb4,0xb1,0x0,0xa0,0xd1,0x2,0xcf,0xbe +DEFINE_GUIDSTRUCT("33214CC1-011F-11D2-B4B1-00A0D102CFBE",KSDATAFORMAT_SUBTYPE_CC); +#define KSDATAFORMAT_SUBTYPE_CC DEFINE_GUIDNAMED(KSDATAFORMAT_SUBTYPE_CC) + +#define STATIC_KSDATAFORMAT_SUBTYPE_NABTS \ + 0xf72a76e2L,0xeb0a,0x11d0,0xac,0xe4,0x00,0x00,0xc0,0xcc,0x16,0xba +DEFINE_GUIDSTRUCT("f72a76e2-eb0a-11d0-ace4-0000c0cc16ba",KSDATAFORMAT_SUBTYPE_NABTS); +#define KSDATAFORMAT_SUBTYPE_NABTS DEFINE_GUIDNAMED(KSDATAFORMAT_SUBTYPE_NABTS) + +#define STATIC_KSDATAFORMAT_SUBTYPE_TELETEXT \ + 0xf72a76e3L,0xeb0a,0x11d0,0xac,0xe4,0x00,0x00,0xc0,0xcc,0x16,0xba +DEFINE_GUIDSTRUCT("f72a76e3-eb0a-11d0-ace4-0000c0cc16ba",KSDATAFORMAT_SUBTYPE_TELETEXT); +#define KSDATAFORMAT_SUBTYPE_TELETEXT DEFINE_GUIDNAMED(KSDATAFORMAT_SUBTYPE_TELETEXT) + +#define KS_BI_RGB 0L +#define KS_BI_RLE8 1L +#define KS_BI_RLE4 2L +#define KS_BI_BITFIELDS 3L + +typedef struct tagKS_RGBQUAD { + BYTE rgbBlue; + BYTE rgbGreen; + BYTE rgbRed; + BYTE rgbReserved; +} KS_RGBQUAD,*PKS_RGBQUAD; + +#define KS_iPALETTE_COLORS 256 +#define KS_iEGA_COLORS 16 +#define KS_iMASK_COLORS 3 +#define KS_iTRUECOLOR 16 +#define KS_iRED 0 +#define KS_iGREEN 1 +#define KS_iBLUE 2 +#define KS_iPALETTE 8 +#define KS_iMAXBITS 8 +#define KS_SIZE_EGA_PALETTE (KS_iEGA_COLORS *sizeof(KS_RGBQUAD)) +#define KS_SIZE_PALETTE (KS_iPALETTE_COLORS *sizeof(KS_RGBQUAD)) + +typedef struct tagKS_BITMAPINFOHEADER { + DWORD biSize; + LONG biWidth; + LONG biHeight; + WORD biPlanes; + WORD biBitCount; + DWORD biCompression; + DWORD biSizeImage; + LONG biXPelsPerMeter; + LONG biYPelsPerMeter; + DWORD biClrUsed; + DWORD biClrImportant; +} KS_BITMAPINFOHEADER,*PKS_BITMAPINFOHEADER; + +typedef struct tag_KS_TRUECOLORINFO { + DWORD dwBitMasks[KS_iMASK_COLORS]; + KS_RGBQUAD bmiColors[KS_iPALETTE_COLORS]; +} KS_TRUECOLORINFO,*PKS_TRUECOLORINFO; + +#define KS_WIDTHBYTES(bits) ((DWORD)(((bits)+31) & (~31)) / 8) +#define KS_DIBWIDTHBYTES(bi) (DWORD)KS_WIDTHBYTES((DWORD)(bi).biWidth *(DWORD)(bi).biBitCount) +#define KS__DIBSIZE(bi) (KS_DIBWIDTHBYTES(bi) *(DWORD)(bi).biHeight) +#define KS_DIBSIZE(bi) ((bi).biHeight < 0 ? (-1)*(KS__DIBSIZE(bi)) : KS__DIBSIZE(bi)) + +typedef LONGLONG REFERENCE_TIME; + +typedef struct tagKS_VIDEOINFOHEADER { + RECT rcSource; + RECT rcTarget; + DWORD dwBitRate; + DWORD dwBitErrorRate; + REFERENCE_TIME AvgTimePerFrame; + KS_BITMAPINFOHEADER bmiHeader; +} KS_VIDEOINFOHEADER,*PKS_VIDEOINFOHEADER; + +typedef struct tagKS_VIDEOINFO { + RECT rcSource; + RECT rcTarget; + DWORD dwBitRate; + DWORD dwBitErrorRate; + REFERENCE_TIME AvgTimePerFrame; + KS_BITMAPINFOHEADER bmiHeader; + __MINGW_EXTENSION union { + KS_RGBQUAD bmiColors[KS_iPALETTE_COLORS]; + DWORD dwBitMasks[KS_iMASK_COLORS]; + KS_TRUECOLORINFO TrueColorInfo; + }; +} KS_VIDEOINFO,*PKS_VIDEOINFO; + +#define KS_SIZE_MASKS (KS_iMASK_COLORS *sizeof(DWORD)) +#define KS_SIZE_PREHEADER (FIELD_OFFSET(KS_VIDEOINFOHEADER,bmiHeader)) + +#define KS_SIZE_VIDEOHEADER(pbmi) ((pbmi)->bmiHeader.biSize + KS_SIZE_PREHEADER) + +typedef struct tagKS_VBIINFOHEADER { + ULONG StartLine; + ULONG EndLine; + ULONG SamplingFrequency; + ULONG MinLineStartTime; + ULONG MaxLineStartTime; + ULONG ActualLineStartTime; + ULONG ActualLineEndTime; + ULONG VideoStandard; + ULONG SamplesPerLine; + ULONG StrideInBytes; + ULONG BufferSize; +} KS_VBIINFOHEADER,*PKS_VBIINFOHEADER; + +#define KS_VBIDATARATE_NABTS (5727272L) +#define KS_VBIDATARATE_CC (503493L) +#define KS_VBISAMPLINGRATE_4X_NABTS ((long)(4*KS_VBIDATARATE_NABTS)) +#define KS_VBISAMPLINGRATE_47X_NABTS ((long)(27000000)) +#define KS_VBISAMPLINGRATE_5X_NABTS ((long)(5*KS_VBIDATARATE_NABTS)) + +#define KS_47NABTS_SCALER (KS_VBISAMPLINGRATE_47X_NABTS/(double)KS_VBIDATARATE_NABTS) + +typedef struct tagKS_AnalogVideoInfo { + RECT rcSource; + RECT rcTarget; + DWORD dwActiveWidth; + DWORD dwActiveHeight; + REFERENCE_TIME AvgTimePerFrame; +} KS_ANALOGVIDEOINFO,*PKS_ANALOGVIDEOINFO; + +#define KS_TVTUNER_CHANGE_BEGIN_TUNE 0x0001L +#define KS_TVTUNER_CHANGE_END_TUNE 0x0002L + +typedef struct tagKS_TVTUNER_CHANGE_INFO { + DWORD dwFlags; + DWORD dwCountryCode; + DWORD dwAnalogVideoStandard; + DWORD dwChannel; +} KS_TVTUNER_CHANGE_INFO,*PKS_TVTUNER_CHANGE_INFO; + +typedef enum { + KS_MPEG2Level_Low, + KS_MPEG2Level_Main, + KS_MPEG2Level_High1440, + KS_MPEG2Level_High +} KS_MPEG2Level; + +typedef enum { + KS_MPEG2Profile_Simple, + KS_MPEG2Profile_Main, + KS_MPEG2Profile_SNRScalable, + KS_MPEG2Profile_SpatiallyScalable, + KS_MPEG2Profile_High +} KS_MPEG2Profile; + +#define KS_INTERLACE_IsInterlaced 0x00000001 +#define KS_INTERLACE_1FieldPerSample 0x00000002 +#define KS_INTERLACE_Field1First 0x00000004 +#define KS_INTERLACE_UNUSED 0x00000008 +#define KS_INTERLACE_FieldPatternMask 0x00000030 +#define KS_INTERLACE_FieldPatField1Only 0x00000000 +#define KS_INTERLACE_FieldPatField2Only 0x00000010 +#define KS_INTERLACE_FieldPatBothRegular 0x00000020 +#define KS_INTERLACE_FieldPatBothIrregular 0x00000030 +#define KS_INTERLACE_DisplayModeMask 0x000000c0 +#define KS_INTERLACE_DisplayModeBobOnly 0x00000000 +#define KS_INTERLACE_DisplayModeWeaveOnly 0x00000040 +#define KS_INTERLACE_DisplayModeBobOrWeave 0x00000080 + +#define KS_MPEG2_DoPanScan 0x00000001 +#define KS_MPEG2_DVDLine21Field1 0x00000002 +#define KS_MPEG2_DVDLine21Field2 0x00000004 +#define KS_MPEG2_SourceIsLetterboxed 0x00000008 +#define KS_MPEG2_FilmCameraMode 0x00000010 +#define KS_MPEG2_LetterboxAnalogOut 0x00000020 +#define KS_MPEG2_DSS_UserData 0x00000040 +#define KS_MPEG2_DVB_UserData 0x00000080 +#define KS_MPEG2_27MhzTimebase 0x00000100 + +typedef struct tagKS_VIDEOINFOHEADER2 { + RECT rcSource; + RECT rcTarget; + DWORD dwBitRate; + DWORD dwBitErrorRate; + REFERENCE_TIME AvgTimePerFrame; + DWORD dwInterlaceFlags; + DWORD dwCopyProtectFlags; + DWORD dwPictAspectRatioX; + DWORD dwPictAspectRatioY; + DWORD dwReserved1; + DWORD dwReserved2; + KS_BITMAPINFOHEADER bmiHeader; +} KS_VIDEOINFOHEADER2,*PKS_VIDEOINFOHEADER2; + +typedef struct tagKS_MPEG1VIDEOINFO { + KS_VIDEOINFOHEADER hdr; + DWORD dwStartTimeCode; + DWORD cbSequenceHeader; + BYTE bSequenceHeader[1]; +} KS_MPEG1VIDEOINFO,*PKS_MPEG1VIDEOINFO; + +#define KS_MAX_SIZE_MPEG1_SEQUENCE_INFO 140 +#define KS_SIZE_MPEG1VIDEOINFO(pv) (FIELD_OFFSET(KS_MPEG1VIDEOINFO,bSequenceHeader[0]) + (pv)->cbSequenceHeader) +#define KS_MPEG1_SEQUENCE_INFO(pv) ((const BYTE *)(pv)->bSequenceHeader) + +typedef struct tagKS_MPEGVIDEOINFO2 { + KS_VIDEOINFOHEADER2 hdr; + DWORD dwStartTimeCode; + DWORD cbSequenceHeader; + DWORD dwProfile; + DWORD dwLevel; + DWORD dwFlags; + DWORD bSequenceHeader[1]; +} KS_MPEGVIDEOINFO2,*PKS_MPEGVIDEOINFO2; + +#define KS_SIZE_MPEGVIDEOINFO2(pv) (FIELD_OFFSET(KS_MPEGVIDEOINFO2,bSequenceHeader[0]) + (pv)->cbSequenceHeader) +#define KS_MPEG1_SEQUENCE_INFO(pv) ((const BYTE *)(pv)->bSequenceHeader) + +#define KS_MPEGAUDIOINFO_27MhzTimebase 0x00000001 + +typedef struct tagKS_MPEAUDIOINFO { + DWORD dwFlags; + DWORD dwReserved1; + DWORD dwReserved2; + DWORD dwReserved3; +} KS_MPEGAUDIOINFO,*PKS_MPEGAUDIOINFO; + +typedef struct tagKS_DATAFORMAT_VIDEOINFOHEADER { + KSDATAFORMAT DataFormat; + KS_VIDEOINFOHEADER VideoInfoHeader; +} KS_DATAFORMAT_VIDEOINFOHEADER,*PKS_DATAFORMAT_VIDEOINFOHEADER; + +typedef struct tagKS_DATAFORMAT_VIDEOINFOHEADER2 { + KSDATAFORMAT DataFormat; + KS_VIDEOINFOHEADER2 VideoInfoHeader2; +} KS_DATAFORMAT_VIDEOINFOHEADER2,*PKS_DATAFORMAT_VIDEOINFOHEADER2; + +typedef struct tagKS_DATAFORMAT_VIDEOINFO_PALETTE { + KSDATAFORMAT DataFormat; + KS_VIDEOINFO VideoInfo; +} KS_DATAFORMAT_VIDEOINFO_PALETTE,*PKS_DATAFORMAT_VIDEOINFO_PALETTE; + +typedef struct tagKS_DATAFORMAT_VBIINFOHEADER { + KSDATAFORMAT DataFormat; + KS_VBIINFOHEADER VBIInfoHeader; +} KS_DATAFORMAT_VBIINFOHEADER,*PKS_DATAFORMAT_VBIINFOHEADER; + +typedef struct _KS_VIDEO_STREAM_CONFIG_CAPS { + GUID guid; + ULONG VideoStandard; + SIZE InputSize; + SIZE MinCroppingSize; + SIZE MaxCroppingSize; + int CropGranularityX; + int CropGranularityY; + int CropAlignX; + int CropAlignY; + SIZE MinOutputSize; + SIZE MaxOutputSize; + int OutputGranularityX; + int OutputGranularityY; + int StretchTapsX; + int StretchTapsY; + int ShrinkTapsX; + int ShrinkTapsY; + LONGLONG MinFrameInterval; + LONGLONG MaxFrameInterval; + LONG MinBitsPerSecond; + LONG MaxBitsPerSecond; +} KS_VIDEO_STREAM_CONFIG_CAPS,*PKS_VIDEO_STREAM_CONFIG_CAPS; + +typedef struct tagKS_DATARANGE_VIDEO { + KSDATARANGE DataRange; + WINBOOL bFixedSizeSamples; + WINBOOL bTemporalCompression; + DWORD StreamDescriptionFlags; + DWORD MemoryAllocationFlags; + KS_VIDEO_STREAM_CONFIG_CAPS ConfigCaps; + KS_VIDEOINFOHEADER VideoInfoHeader; +} KS_DATARANGE_VIDEO,*PKS_DATARANGE_VIDEO; + +typedef struct tagKS_DATARANGE_VIDEO2 { + KSDATARANGE DataRange; + WINBOOL bFixedSizeSamples; + WINBOOL bTemporalCompression; + DWORD StreamDescriptionFlags; + DWORD MemoryAllocationFlags; + KS_VIDEO_STREAM_CONFIG_CAPS ConfigCaps; + KS_VIDEOINFOHEADER2 VideoInfoHeader; +} KS_DATARANGE_VIDEO2,*PKS_DATARANGE_VIDEO2; + +typedef struct tagKS_DATARANGE_MPEG1_VIDEO { + KSDATARANGE DataRange; + WINBOOL bFixedSizeSamples; + WINBOOL bTemporalCompression; + DWORD StreamDescriptionFlags; + DWORD MemoryAllocationFlags; + KS_VIDEO_STREAM_CONFIG_CAPS ConfigCaps; + KS_MPEG1VIDEOINFO VideoInfoHeader; +} KS_DATARANGE_MPEG1_VIDEO,*PKS_DATARANGE_MPEG1_VIDEO; + +typedef struct tagKS_DATARANGE_MPEG2_VIDEO { + KSDATARANGE DataRange; + WINBOOL bFixedSizeSamples; + WINBOOL bTemporalCompression; + DWORD StreamDescriptionFlags; + DWORD MemoryAllocationFlags; + KS_VIDEO_STREAM_CONFIG_CAPS ConfigCaps; + KS_MPEGVIDEOINFO2 VideoInfoHeader; +} KS_DATARANGE_MPEG2_VIDEO,*PKS_DATARANGE_MPEG2_VIDEO; + +typedef struct tagKS_DATARANGE_VIDEO_PALETTE { + KSDATARANGE DataRange; + WINBOOL bFixedSizeSamples; + WINBOOL bTemporalCompression; + DWORD StreamDescriptionFlags; + DWORD MemoryAllocationFlags; + KS_VIDEO_STREAM_CONFIG_CAPS ConfigCaps; + KS_VIDEOINFO VideoInfo; +} KS_DATARANGE_VIDEO_PALETTE,*PKS_DATARANGE_VIDEO_PALETTE; + +typedef struct tagKS_DATARANGE_VIDEO_VBI { + KSDATARANGE DataRange; + WINBOOL bFixedSizeSamples; + WINBOOL bTemporalCompression; + DWORD StreamDescriptionFlags; + DWORD MemoryAllocationFlags; + KS_VIDEO_STREAM_CONFIG_CAPS ConfigCaps; + KS_VBIINFOHEADER VBIInfoHeader; +} KS_DATARANGE_VIDEO_VBI,*PKS_DATARANGE_VIDEO_VBI; + +typedef struct tagKS_DATARANGE_ANALOGVIDEO { + KSDATARANGE DataRange; + KS_ANALOGVIDEOINFO AnalogVideoInfo; +} KS_DATARANGE_ANALOGVIDEO,*PKS_DATARANGE_ANALOGVIDEO; + +#define KS_VIDEOSTREAM_PREVIEW 0x0001 +#define KS_VIDEOSTREAM_CAPTURE 0x0002 +#define KS_VIDEOSTREAM_VBI 0x0010 +#define KS_VIDEOSTREAM_NABTS 0x0020 +#define KS_VIDEOSTREAM_CC 0x0100 +#define KS_VIDEOSTREAM_EDS 0x0200 +#define KS_VIDEOSTREAM_TELETEXT 0x0400 +#define KS_VIDEOSTREAM_STILL 0x1000 +#define KS_VIDEOSTREAM_IS_VPE 0x8000 + +#define KS_VIDEO_ALLOC_VPE_SYSTEM 0x0001 +#define KS_VIDEO_ALLOC_VPE_DISPLAY 0x0002 +#define KS_VIDEO_ALLOC_VPE_AGP 0x0004 + +#define STATIC_KSPROPSETID_VBICAP_PROPERTIES \ + 0xf162c607,0x7b35,0x496f,0xad,0x7f,0x2d,0xca,0x3b,0x46,0xb7,0x18 +DEFINE_GUIDSTRUCT("F162C607-7B35-496f-AD7F-2DCA3B46B718",KSPROPSETID_VBICAP_PROPERTIES); +#define KSPROPSETID_VBICAP_PROPERTIES DEFINE_GUIDNAMED(KSPROPSETID_VBICAP_PROPERTIES) + +typedef enum { + KSPROPERTY_VBICAP_PROPERTIES_PROTECTION = 0x01 +} KSPROPERTY_VBICAP; + +typedef struct _VBICAP_PROPERTIES_PROTECTION_S { + KSPROPERTY Property; + ULONG StreamIndex; + ULONG Status; +} VBICAP_PROPERTIES_PROTECTION_S,*PVBICAP_PROPERTIES_PROTECTION_S; + +#define KS_VBICAP_PROTECTION_MV_PRESENT 0x0001L +#define KS_VBICAP_PROTECTION_MV_HARDWARE 0x0002L +#define KS_VBICAP_PROTECTION_MV_DETECTED 0x0004L + +#define KS_NABTS_GROUPID_ORIGINAL_CONTENT_BASE 0x800 +#define KS_NABTS_GROUPID_ORIGINAL_CONTENT_ADVERTISER_BASE 0x810 + +#define KS_NABTS_GROUPID_PRODUCTION_COMPANY_CONTENT_BASE 0x820 +#define KS_NABTS_GROUPID_PRODUCTION_COMPANY_ADVERTISER_BASE 0x830 + +#define KS_NABTS_GROUPID_SYNDICATED_SHOW_CONTENT_BASE 0x840 +#define KS_NABTS_GROUPID_SYNDICATED_SHOW_ADVERTISER_BASE 0x850 + +#define KS_NABTS_GROUPID_NETWORK_WIDE_CONTENT_BASE 0x860 +#define KS_NABTS_GROUPID_NETWORK_WIDE_ADVERTISER_BASE 0x870 + +#define KS_NABTS_GROUPID_TELEVISION_STATION_CONTENT_BASE 0x880 +#define KS_NABTS_GROUPID_TELEVISION_STATION_ADVERTISER_BASE 0x890 + +#define KS_NABTS_GROUPID_LOCAL_CABLE_SYSTEM_CONTENT_BASE 0x8A0 +#define KS_NABTS_GROUPID_LOCAL_CABLE_SYSTEM_ADVERTISER_BASE 0x8B0 + +#define KS_NABTS_GROUPID_MICROSOFT_RESERVED_TEST_DATA_BASE 0x8F0 + +#define STATIC_KSDATAFORMAT_TYPE_NABTS \ + 0xe757bca0,0x39ac,0x11d1,0xa9,0xf5,0x0,0xc0,0x4f,0xbb,0xde,0x8f +DEFINE_GUIDSTRUCT("E757BCA0-39AC-11d1-A9F5-00C04FBBDE8F",KSDATAFORMAT_TYPE_NABTS); +#define KSDATAFORMAT_TYPE_NABTS DEFINE_GUIDNAMED(KSDATAFORMAT_TYPE_NABTS) + +#define STATIC_KSDATAFORMAT_SUBTYPE_NABTS_FEC \ + 0xe757bca1,0x39ac,0x11d1,0xa9,0xf5,0x0,0xc0,0x4f,0xbb,0xde,0x8f +DEFINE_GUIDSTRUCT("E757BCA1-39AC-11d1-A9F5-00C04FBBDE8F",KSDATAFORMAT_SUBTYPE_NABTS_FEC); +#define KSDATAFORMAT_SUBTYPE_NABTS_FEC DEFINE_GUIDNAMED(KSDATAFORMAT_SUBTYPE_NABTS_FEC) + +#define MAX_NABTS_VBI_LINES_PER_FIELD 11 +#define NABTS_LINES_PER_BUNDLE 16 +#define NABTS_PAYLOAD_PER_LINE 28 +#define NABTS_BYTES_PER_LINE 36 + +typedef struct _NABTSFEC_BUFFER { + ULONG dataSize; + USHORT groupID; + USHORT Reserved; + UCHAR data[NABTS_LINES_PER_BUNDLE *NABTS_PAYLOAD_PER_LINE]; +} NABTSFEC_BUFFER,*PNABTSFEC_BUFFER; + +#define STATIC_KSPROPSETID_VBICodecFiltering \ + 0xcafeb0caL,0x8715,0x11d0,0xbd,0x6a,0x00,0x35,0xc0,0xed,0xba,0xbe +DEFINE_GUIDSTRUCT("cafeb0ca-8715-11d0-bd6a-0035c0edbabe",KSPROPSETID_VBICodecFiltering); +#define KSPROPSETID_VBICodecFiltering DEFINE_GUIDNAMED(KSPROPSETID_VBICodecFiltering) + +typedef enum { + KSPROPERTY_VBICODECFILTERING_SCANLINES_REQUESTED_BIT_ARRAY = 0x01, + KSPROPERTY_VBICODECFILTERING_SCANLINES_DISCOVERED_BIT_ARRAY, + KSPROPERTY_VBICODECFILTERING_SUBSTREAMS_REQUESTED_BIT_ARRAY, + KSPROPERTY_VBICODECFILTERING_SUBSTREAMS_DISCOVERED_BIT_ARRAY, + KSPROPERTY_VBICODECFILTERING_STATISTICS +} KSPROPERTY_VBICODECFILTERING; + +typedef struct _VBICODECFILTERING_SCANLINES { + DWORD DwordBitArray[32]; +} VBICODECFILTERING_SCANLINES,*PVBICODECFILTERING_SCANLINES; + +typedef struct _VBICODECFILTERING_NABTS_SUBSTREAMS { + DWORD SubstreamMask[128]; +} VBICODECFILTERING_NABTS_SUBSTREAMS,*PVBICODECFILTERING_NABTS_SUBSTREAMS; + +typedef struct _VBICODECFILTERING_CC_SUBSTREAMS { + DWORD SubstreamMask; +} VBICODECFILTERING_CC_SUBSTREAMS,*PVBICODECFILTERING_CC_SUBSTREAMS; + +#define KS_CC_SUBSTREAM_ODD 0x0001L +#define KS_CC_SUBSTREAM_EVEN 0x0002L + +#define KS_CC_SUBSTREAM_FIELD1_MASK 0x00F0L +#define KS_CC_SUBSTREAM_SERVICE_CC1 0x0010L +#define KS_CC_SUBSTREAM_SERVICE_CC2 0x0020L +#define KS_CC_SUBSTREAM_SERVICE_T1 0x0040L +#define KS_CC_SUBSTREAM_SERVICE_T2 0x0080L + +#define KS_CC_SUBSTREAM_FIELD2_MASK 0x1F00L +#define KS_CC_SUBSTREAM_SERVICE_CC3 0x0100L +#define KS_CC_SUBSTREAM_SERVICE_CC4 0x0200L +#define KS_CC_SUBSTREAM_SERVICE_T3 0x0400L +#define KS_CC_SUBSTREAM_SERVICE_T4 0x0800L +#define KS_CC_SUBSTREAM_SERVICE_XDS 0x1000L + +#define CC_MAX_HW_DECODE_LINES 12 +typedef struct _CC_BYTE_PAIR { + BYTE Decoded[2]; + USHORT Reserved; +} CC_BYTE_PAIR,*PCC_BYTE_PAIR; + +typedef struct _CC_HW_FIELD { + VBICODECFILTERING_SCANLINES ScanlinesRequested; + ULONG fieldFlags; + LONGLONG PictureNumber; + CC_BYTE_PAIR Lines[CC_MAX_HW_DECODE_LINES]; +} CC_HW_FIELD,*PCC_HW_FIELD; + +#ifndef PACK_PRAGMAS_NOT_SUPPORTED +#include +#endif +typedef struct _NABTS_BUFFER_LINE { + BYTE Confidence; + BYTE Bytes[NABTS_BYTES_PER_LINE]; +} NABTS_BUFFER_LINE,*PNABTS_BUFFER_LINE; + +#define NABTS_BUFFER_PICTURENUMBER_SUPPORT 1 +typedef struct _NABTS_BUFFER { + VBICODECFILTERING_SCANLINES ScanlinesRequested; + LONGLONG PictureNumber; + NABTS_BUFFER_LINE NabtsLines[MAX_NABTS_VBI_LINES_PER_FIELD]; +} NABTS_BUFFER,*PNABTS_BUFFER; +#ifndef PACK_PRAGMAS_NOT_SUPPORTED +#include +#endif + +#define WST_TVTUNER_CHANGE_BEGIN_TUNE 0x1000L +#define WST_TVTUNER_CHANGE_END_TUNE 0x2000L + +#define MAX_WST_VBI_LINES_PER_FIELD 17 +#define WST_BYTES_PER_LINE 42 + +typedef struct _WST_BUFFER_LINE { + BYTE Confidence; + BYTE Bytes[WST_BYTES_PER_LINE]; +} WST_BUFFER_LINE,*PWST_BUFFER_LINE; + +typedef struct _WST_BUFFER { + VBICODECFILTERING_SCANLINES ScanlinesRequested; + WST_BUFFER_LINE WstLines[MAX_WST_VBI_LINES_PER_FIELD]; +} WST_BUFFER,*PWST_BUFFER; + +typedef struct _VBICODECFILTERING_STATISTICS_COMMON { + DWORD InputSRBsProcessed; + DWORD OutputSRBsProcessed; + DWORD SRBsIgnored; + DWORD InputSRBsMissing; + DWORD OutputSRBsMissing; + DWORD OutputFailures; + DWORD InternalErrors; + DWORD ExternalErrors; + DWORD InputDiscontinuities; + DWORD DSPFailures; + DWORD TvTunerChanges; + DWORD VBIHeaderChanges; + DWORD LineConfidenceAvg; + DWORD BytesOutput; +} VBICODECFILTERING_STATISTICS_COMMON,*PVBICODECFILTERING_STATISTICS_COMMON; + +typedef struct _VBICODECFILTERING_STATISTICS_COMMON_PIN { + DWORD SRBsProcessed; + DWORD SRBsIgnored; + DWORD SRBsMissing; + DWORD InternalErrors; + DWORD ExternalErrors; + DWORD Discontinuities; + DWORD LineConfidenceAvg; + DWORD BytesOutput; +} VBICODECFILTERING_STATISTICS_COMMON_PIN,*PVBICODECFILTERING_STATISTICS_COMMON_PIN; + +typedef struct _VBICODECFILTERING_STATISTICS_NABTS { + VBICODECFILTERING_STATISTICS_COMMON Common; + DWORD FECBundleBadLines; + DWORD FECQueueOverflows; + DWORD FECCorrectedLines; + DWORD FECUncorrectableLines; + DWORD BundlesProcessed; + DWORD BundlesSent2IP; + DWORD FilteredLines; +} VBICODECFILTERING_STATISTICS_NABTS,*PVBICODECFILTERING_STATISTICS_NABTS; + +typedef struct _VBICODECFILTERING_STATISTICS_NABTS_PIN { + VBICODECFILTERING_STATISTICS_COMMON_PIN Common; +} VBICODECFILTERING_STATISTICS_NABTS_PIN,*PVBICODECFILTERING_STATISTICS_NABTS_PIN; + +typedef struct _VBICODECFILTERING_STATISTICS_CC { + VBICODECFILTERING_STATISTICS_COMMON Common; +} VBICODECFILTERING_STATISTICS_CC,*PVBICODECFILTERING_STATISTICS_CC; + +typedef struct _VBICODECFILTERING_STATISTICS_CC_PIN { + VBICODECFILTERING_STATISTICS_COMMON_PIN Common; +} VBICODECFILTERING_STATISTICS_CC_PIN,*PVBICODECFILTERING_STATISTICS_CC_PIN; + +typedef struct _VBICODECFILTERING_STATISTICS_TELETEXT { + VBICODECFILTERING_STATISTICS_COMMON Common; +} VBICODECFILTERING_STATISTICS_TELETEXT,*PVBICODECFILTERING_STATISTICS_TELETEXT; + +typedef struct _VBICODECFILTERING_STATISTICS_TELETEXT_PIN { + VBICODECFILTERING_STATISTICS_COMMON_PIN Common; +} VBICODECFILTERING_STATISTICS_TELETEXT_PIN,*PVBICODECFILTERING_STATISTICS_TELETEXT_PIN; + +typedef struct { + KSPROPERTY Property; + VBICODECFILTERING_SCANLINES Scanlines; +} KSPROPERTY_VBICODECFILTERING_SCANLINES_S,*PKSPROPERTY_VBICODECFILTERING_SCANLINES_S; + +typedef struct { + KSPROPERTY Property; + VBICODECFILTERING_NABTS_SUBSTREAMS Substreams; +} KSPROPERTY_VBICODECFILTERING_NABTS_SUBSTREAMS_S,*PKSPROPERTY_VBICODECFILTERING_NABTS_SUBSTREAMS_S; + +typedef struct { + KSPROPERTY Property; + VBICODECFILTERING_CC_SUBSTREAMS Substreams; +} KSPROPERTY_VBICODECFILTERING_CC_SUBSTREAMS_S,*PKSPROPERTY_VBICODECFILTERING_CC_SUBSTREAMS_S; + +typedef struct { + KSPROPERTY Property; + VBICODECFILTERING_STATISTICS_COMMON Statistics; +} KSPROPERTY_VBICODECFILTERING_STATISTICS_COMMON_S,*PKSPROPERTY_VBICODECFILTERING_STATISTICS_COMMON_S; + +typedef struct { + KSPROPERTY Property; + VBICODECFILTERING_STATISTICS_COMMON_PIN Statistics; +} KSPROPERTY_VBICODECFILTERING_STATISTICS_COMMON_PIN_S,*PKSPROPERTY_VBICODECFILTERING_STATISTICS_COMMON_PIN_S; + +typedef struct { + KSPROPERTY Property; + VBICODECFILTERING_STATISTICS_NABTS Statistics; +} KSPROPERTY_VBICODECFILTERING_STATISTICS_NABTS_S,*PKSPROPERTY_VBICODECFILTERING_STATISTICS_NABTS_S; + +typedef struct { + KSPROPERTY Property; + VBICODECFILTERING_STATISTICS_NABTS_PIN Statistics; +} KSPROPERTY_VBICODECFILTERING_STATISTICS_NABTS_PIN_S,*PKSPROPERTY_VBICODECFILTERING_STATISTICS_NABTS_PIN_S; + +typedef struct { + KSPROPERTY Property; + VBICODECFILTERING_STATISTICS_CC Statistics; +} KSPROPERTY_VBICODECFILTERING_STATISTICS_CC_S,*PKSPROPERTY_VBICODECFILTERING_STATISTICS_CC_S; + +typedef struct { + KSPROPERTY Property; + VBICODECFILTERING_STATISTICS_CC_PIN Statistics; +} KSPROPERTY_VBICODECFILTERING_STATISTICS_CC_PIN_S,*PKSPROPERTY_VBICODECFILTERING_STATISTICS_CC_PIN_S; + +#define STATIC_PINNAME_VIDEO_CAPTURE \ + 0xfb6c4281,0x353,0x11d1,0x90,0x5f,0x0,0x0,0xc0,0xcc,0x16,0xba +#define STATIC_PINNAME_CAPTURE STATIC_PINNAME_VIDEO_CAPTURE +DEFINE_GUIDSTRUCT("FB6C4281-0353-11d1-905F-0000C0CC16BA",PINNAME_VIDEO_CAPTURE); +#define PINNAME_VIDEO_CAPTURE DEFINE_GUIDNAMED(PINNAME_VIDEO_CAPTURE) +#define PINNAME_CAPTURE PINNAME_VIDEO_CAPTURE + +#define STATIC_PINNAME_VIDEO_CC_CAPTURE \ + 0x1aad8061,0x12d,0x11d2,0xb4,0xb1,0x0,0xa0,0xd1,0x2,0xcf,0xbe +#define STATIC_PINNAME_CC_CAPTURE STATIC_PINNAME_VIDEO_CC_CAPTURE +DEFINE_GUIDSTRUCT("1AAD8061-012D-11d2-B4B1-00A0D102CFBE",PINNAME_VIDEO_CC_CAPTURE); +#define PINNAME_VIDEO_CC_CAPTURE DEFINE_GUIDNAMED(PINNAME_VIDEO_CC_CAPTURE) + +#define STATIC_PINNAME_VIDEO_NABTS_CAPTURE \ + 0x29703660,0x498a,0x11d2,0xb4,0xb1,0x0,0xa0,0xd1,0x2,0xcf,0xbe +#define STATIC_PINNAME_NABTS_CAPTURE STATIC_PINNAME_VIDEO_NABTS_CAPTURE +DEFINE_GUIDSTRUCT("29703660-498A-11d2-B4B1-00A0D102CFBE",PINNAME_VIDEO_NABTS_CAPTURE); +#define PINNAME_VIDEO_NABTS_CAPTURE DEFINE_GUIDNAMED(PINNAME_VIDEO_NABTS_CAPTURE) + +#define STATIC_PINNAME_VIDEO_PREVIEW \ + 0xfb6c4282,0x353,0x11d1,0x90,0x5f,0x0,0x0,0xc0,0xcc,0x16,0xba +#define STATIC_PINNAME_PREVIEW STATIC_PINNAME_VIDEO_PREVIEW +DEFINE_GUIDSTRUCT("FB6C4282-0353-11d1-905F-0000C0CC16BA",PINNAME_VIDEO_PREVIEW); +#define PINNAME_VIDEO_PREVIEW DEFINE_GUIDNAMED(PINNAME_VIDEO_PREVIEW) +#define PINNAME_PREVIEW PINNAME_VIDEO_PREVIEW + +#define STATIC_PINNAME_VIDEO_ANALOGVIDEOIN \ + 0xfb6c4283,0x353,0x11d1,0x90,0x5f,0x0,0x0,0xc0,0xcc,0x16,0xba +DEFINE_GUIDSTRUCT("FB6C4283-0353-11d1-905F-0000C0CC16BA",PINNAME_VIDEO_ANALOGVIDEOIN); +#define PINNAME_VIDEO_ANALOGVIDEOIN DEFINE_GUIDNAMED(PINNAME_VIDEO_ANALOGVIDEOIN) + +#define STATIC_PINNAME_VIDEO_VBI \ + 0xfb6c4284,0x353,0x11d1,0x90,0x5f,0x0,0x0,0xc0,0xcc,0x16,0xba +DEFINE_GUIDSTRUCT("FB6C4284-0353-11d1-905F-0000C0CC16BA",PINNAME_VIDEO_VBI); +#define PINNAME_VIDEO_VBI DEFINE_GUIDNAMED(PINNAME_VIDEO_VBI) + +#define STATIC_PINNAME_VIDEO_VIDEOPORT \ + 0xfb6c4285,0x353,0x11d1,0x90,0x5f,0x0,0x0,0xc0,0xcc,0x16,0xba +DEFINE_GUIDSTRUCT("FB6C4285-0353-11d1-905F-0000C0CC16BA",PINNAME_VIDEO_VIDEOPORT); +#define PINNAME_VIDEO_VIDEOPORT DEFINE_GUIDNAMED(PINNAME_VIDEO_VIDEOPORT) + +#define STATIC_PINNAME_VIDEO_NABTS \ + 0xfb6c4286,0x353,0x11d1,0x90,0x5f,0x0,0x0,0xc0,0xcc,0x16,0xba +DEFINE_GUIDSTRUCT("FB6C4286-0353-11d1-905F-0000C0CC16BA",PINNAME_VIDEO_NABTS); +#define PINNAME_VIDEO_NABTS DEFINE_GUIDNAMED(PINNAME_VIDEO_NABTS) + +#define STATIC_PINNAME_VIDEO_EDS \ + 0xfb6c4287,0x353,0x11d1,0x90,0x5f,0x0,0x0,0xc0,0xcc,0x16,0xba +DEFINE_GUIDSTRUCT("FB6C4287-0353-11d1-905F-0000C0CC16BA",PINNAME_VIDEO_EDS); +#define PINNAME_VIDEO_EDS DEFINE_GUIDNAMED(PINNAME_VIDEO_EDS) + +#define STATIC_PINNAME_VIDEO_TELETEXT \ + 0xfb6c4288,0x353,0x11d1,0x90,0x5f,0x0,0x0,0xc0,0xcc,0x16,0xba +DEFINE_GUIDSTRUCT("FB6C4288-0353-11d1-905F-0000C0CC16BA",PINNAME_VIDEO_TELETEXT); +#define PINNAME_VIDEO_TELETEXT DEFINE_GUIDNAMED(PINNAME_VIDEO_TELETEXT) + +#define STATIC_PINNAME_VIDEO_CC \ + 0xfb6c4289,0x353,0x11d1,0x90,0x5f,0x0,0x0,0xc0,0xcc,0x16,0xba +DEFINE_GUIDSTRUCT("FB6C4289-0353-11d1-905F-0000C0CC16BA",PINNAME_VIDEO_CC); +#define PINNAME_VIDEO_CC DEFINE_GUIDNAMED(PINNAME_VIDEO_CC) + +#define STATIC_PINNAME_VIDEO_STILL \ + 0xfb6c428A,0x353,0x11d1,0x90,0x5f,0x0,0x0,0xc0,0xcc,0x16,0xba +DEFINE_GUIDSTRUCT("FB6C428A-0353-11d1-905F-0000C0CC16BA",PINNAME_VIDEO_STILL); +#define PINNAME_VIDEO_STILL DEFINE_GUIDNAMED(PINNAME_VIDEO_STILL) + +#define STATIC_PINNAME_VIDEO_TIMECODE \ + 0xfb6c428B,0x353,0x11d1,0x90,0x5f,0x0,0x0,0xc0,0xcc,0x16,0xba +DEFINE_GUIDSTRUCT("FB6C428B-0353-11d1-905F-0000C0CC16BA",PINNAME_VIDEO_TIMECODE); +#define PINNAME_VIDEO_TIMECODE DEFINE_GUIDNAMED(PINNAME_VIDEO_TIMECODE) + +#define STATIC_PINNAME_VIDEO_VIDEOPORT_VBI \ + 0xfb6c428C,0x353,0x11d1,0x90,0x5f,0x0,0x0,0xc0,0xcc,0x16,0xba +DEFINE_GUIDSTRUCT("FB6C428C-0353-11d1-905F-0000C0CC16BA",PINNAME_VIDEO_VIDEOPORT_VBI); +#define PINNAME_VIDEO_VIDEOPORT_VBI DEFINE_GUIDNAMED(PINNAME_VIDEO_VIDEOPORT_VBI) + +#define KS_VIDEO_FLAG_FRAME 0x0000L +#define KS_VIDEO_FLAG_FIELD1 0x0001L +#define KS_VIDEO_FLAG_FIELD2 0x0002L + +#define KS_VIDEO_FLAG_I_FRAME 0x0000L +#define KS_VIDEO_FLAG_P_FRAME 0x0010L +#define KS_VIDEO_FLAG_B_FRAME 0x0020L + +typedef struct tagKS_FRAME_INFO { + ULONG ExtendedHeaderSize; + DWORD dwFrameFlags; + LONGLONG PictureNumber; + LONGLONG DropCount; + HANDLE hDirectDraw; + HANDLE hSurfaceHandle; + RECT DirectDrawRect; + + DWORD Reserved1; + DWORD Reserved2; + DWORD Reserved3; + DWORD Reserved4; +} KS_FRAME_INFO,*PKS_FRAME_INFO; + +#define KS_VBI_FLAG_FIELD1 0x0001L +#define KS_VBI_FLAG_FIELD2 0x0002L + +#define KS_VBI_FLAG_MV_PRESENT 0x0100L +#define KS_VBI_FLAG_MV_HARDWARE 0x0200L +#define KS_VBI_FLAG_MV_DETECTED 0x0400L + +#define KS_VBI_FLAG_TVTUNER_CHANGE 0x0010L +#define KS_VBI_FLAG_VBIINFOHEADER_CHANGE 0x0020L + +typedef struct tagKS_VBI_FRAME_INFO { + ULONG ExtendedHeaderSize; + DWORD dwFrameFlags; + LONGLONG PictureNumber; + LONGLONG DropCount; + DWORD dwSamplingFrequency; + KS_TVTUNER_CHANGE_INFO TvTunerChangeInfo; + KS_VBIINFOHEADER VBIInfoHeader; +} KS_VBI_FRAME_INFO,*PKS_VBI_FRAME_INFO; + +typedef enum +{ + KS_AnalogVideo_None = 0x00000000, + KS_AnalogVideo_NTSC_M = 0x00000001, + KS_AnalogVideo_NTSC_M_J = 0x00000002, + KS_AnalogVideo_NTSC_433 = 0x00000004, + KS_AnalogVideo_PAL_B = 0x00000010, + KS_AnalogVideo_PAL_D = 0x00000020, + KS_AnalogVideo_PAL_G = 0x00000040, + KS_AnalogVideo_PAL_H = 0x00000080, + KS_AnalogVideo_PAL_I = 0x00000100, + KS_AnalogVideo_PAL_M = 0x00000200, + KS_AnalogVideo_PAL_N = 0x00000400, + KS_AnalogVideo_PAL_60 = 0x00000800, + KS_AnalogVideo_SECAM_B = 0x00001000, + KS_AnalogVideo_SECAM_D = 0x00002000, + KS_AnalogVideo_SECAM_G = 0x00004000, + KS_AnalogVideo_SECAM_H = 0x00008000, + KS_AnalogVideo_SECAM_K = 0x00010000, + KS_AnalogVideo_SECAM_K1 = 0x00020000, + KS_AnalogVideo_SECAM_L = 0x00040000, + KS_AnalogVideo_SECAM_L1 = 0x00080000, + KS_AnalogVideo_PAL_N_COMBO = 0x00100000 +} KS_AnalogVideoStandard; + +#define KS_AnalogVideo_NTSC_Mask 0x00000007 +#define KS_AnalogVideo_PAL_Mask 0x00100FF0 +#define KS_AnalogVideo_SECAM_Mask 0x000FF000 + +#define STATIC_PROPSETID_ALLOCATOR_CONTROL \ + 0x53171960,0x148e,0x11d2,0x99,0x79,0x0,0x0,0xc0,0xcc,0x16,0xba +DEFINE_GUIDSTRUCT("53171960-148E-11d2-9979-0000C0CC16BA",PROPSETID_ALLOCATOR_CONTROL); +#define PROPSETID_ALLOCATOR_CONTROL DEFINE_GUIDNAMED(PROPSETID_ALLOCATOR_CONTROL) + +typedef enum { + KSPROPERTY_ALLOCATOR_CONTROL_HONOR_COUNT, + KSPROPERTY_ALLOCATOR_CONTROL_SURFACE_SIZE, + KSPROPERTY_ALLOCATOR_CONTROL_CAPTURE_CAPS, + KSPROPERTY_ALLOCATOR_CONTROL_CAPTURE_INTERLEAVE +} KSPROPERTY_ALLOCATOR_CONTROL; + +typedef struct { + ULONG CX; + ULONG CY; +} KSPROPERTY_ALLOCATOR_CONTROL_SURFACE_SIZE_S,*PKSPROPERTY_ALLOCATOR_CONTROL_SURFACE_SIZE_S; + +typedef struct { + ULONG InterleavedCapSupported; +} KSPROPERTY_ALLOCATOR_CONTROL_CAPTURE_CAPS_S,*PKSPROPERTY_ALLOCATOR_CONTROL_CAPTURE_CAPS_S; + +typedef struct { + ULONG InterleavedCapPossible; +} KSPROPERTY_ALLOCATOR_CONTROL_CAPTURE_INTERLEAVE_S,*PKSPROPERTY_ALLOCATOR_CONTROL_CAPTURE_INTERLEAVE_S; + +#define STATIC_PROPSETID_VIDCAP_VIDEOPROCAMP \ + 0xC6E13360L,0x30AC,0x11d0,0xa1,0x8c,0x00,0xA0,0xC9,0x11,0x89,0x56 +DEFINE_GUIDSTRUCT("C6E13360-30AC-11d0-A18C-00A0C9118956",PROPSETID_VIDCAP_VIDEOPROCAMP); +#define PROPSETID_VIDCAP_VIDEOPROCAMP DEFINE_GUIDNAMED(PROPSETID_VIDCAP_VIDEOPROCAMP) + +typedef enum { + KSPROPERTY_VIDEOPROCAMP_BRIGHTNESS, + KSPROPERTY_VIDEOPROCAMP_CONTRAST, + KSPROPERTY_VIDEOPROCAMP_HUE, + KSPROPERTY_VIDEOPROCAMP_SATURATION, + KSPROPERTY_VIDEOPROCAMP_SHARPNESS, + KSPROPERTY_VIDEOPROCAMP_GAMMA, + KSPROPERTY_VIDEOPROCAMP_COLORENABLE, + KSPROPERTY_VIDEOPROCAMP_WHITEBALANCE, + KSPROPERTY_VIDEOPROCAMP_BACKLIGHT_COMPENSATION, + KSPROPERTY_VIDEOPROCAMP_GAIN, + KSPROPERTY_VIDEOPROCAMP_DIGITAL_MULTIPLIER, + KSPROPERTY_VIDEOPROCAMP_DIGITAL_MULTIPLIER_LIMIT, + KSPROPERTY_VIDEOPROCAMP_WHITEBALANCE_COMPONENT, + KSPROPERTY_VIDEOPROCAMP_POWERLINE_FREQUENCY +} KSPROPERTY_VIDCAP_VIDEOPROCAMP; + +typedef struct { + KSPROPERTY Property; + LONG Value; + ULONG Flags; + ULONG Capabilities; +} KSPROPERTY_VIDEOPROCAMP_S,*PKSPROPERTY_VIDEOPROCAMP_S; + +typedef struct { + KSP_NODE NodeProperty; + LONG Value; + ULONG Flags; + ULONG Capabilities; +} KSPROPERTY_VIDEOPROCAMP_NODE_S,*PKSPROPERTY_VIDEOPROCAMP_NODE_S; + +typedef struct { + KSPROPERTY Property; + LONG Value1; + ULONG Flags; + ULONG Capabilities; + LONG Value2; +} KSPROPERTY_VIDEOPROCAMP_S2,*PKSPROPERTY_VIDEOPROCAMP_S2; + +typedef struct { + KSP_NODE NodeProperty; + LONG Value1; + ULONG Flags; + ULONG Capabilities; + LONG Value2; +} KSPROPERTY_VIDEOPROCAMP_NODE_S2,*PKSPROPERTY_VIDEOPROCAMP_NODE_S2; + +#define KSPROPERTY_VIDEOPROCAMP_FLAGS_AUTO 0X0001L +#define KSPROPERTY_VIDEOPROCAMP_FLAGS_MANUAL 0X0002L + +#define STATIC_PROPSETID_VIDCAP_SELECTOR \ + 0x1ABDAECA,0x68B6,0x4F83,0x93,0x71,0xB4,0x13,0x90,0x7C,0x7B,0x9F +DEFINE_GUIDSTRUCT("1ABDAECA-68B6-4F83-9371-B413907C7B9F",PROPSETID_VIDCAP_SELECTOR); +#define PROPSETID_VIDCAP_SELECTOR DEFINE_GUIDNAMED(PROPSETID_VIDCAP_SELECTOR) + +typedef enum { + KSPROPERTY_SELECTOR_SOURCE_NODE_ID, + KSPROPERTY_SELECTOR_NUM_SOURCES +} KSPROPERTY_VIDCAP_SELECTOR,*PKSPROPERTY_VIDCAP_SELECTOR; + +typedef struct { + KSPROPERTY Property; + LONG Value; + ULONG Flags; + ULONG Capabilities; +} KSPROPERTY_SELECTOR_S,*PKSPROPERTY_SELECTOR_S; + +typedef struct { + KSP_NODE NodeProperty; + LONG Value; + ULONG Flags; + ULONG Capabilities; +} KSPROPERTY_SELECTOR_NODE_S,*PKSPROPERTY_SELECTOR_NODE_S; + +#define STATIC_PROPSETID_TUNER \ + 0x6a2e0605L,0x28e4,0x11d0,0xa1,0x8c,0x00,0xa0,0xc9,0x11,0x89,0x56 +DEFINE_GUIDSTRUCT("6a2e0605-28e4-11d0-a18c-00a0c9118956",PROPSETID_TUNER); +#define PROPSETID_TUNER DEFINE_GUIDNAMED(PROPSETID_TUNER) + +typedef enum { + KSPROPERTY_TUNER_CAPS, + KSPROPERTY_TUNER_MODE_CAPS, + KSPROPERTY_TUNER_MODE, + KSPROPERTY_TUNER_STANDARD, + KSPROPERTY_TUNER_FREQUENCY, + KSPROPERTY_TUNER_INPUT, + KSPROPERTY_TUNER_STATUS, + KSPROPERTY_TUNER_IF_MEDIUM +} KSPROPERTY_TUNER; + +typedef enum { + KSPROPERTY_TUNER_MODE_TV = 0X0001, + KSPROPERTY_TUNER_MODE_FM_RADIO = 0X0002, + KSPROPERTY_TUNER_MODE_AM_RADIO = 0X0004, + KSPROPERTY_TUNER_MODE_DSS = 0X0008, + KSPROPERTY_TUNER_MODE_ATSC = 0X0010 +} KSPROPERTY_TUNER_MODES; + +typedef enum { + KS_TUNER_TUNING_EXACT = 1, + KS_TUNER_TUNING_FINE, + KS_TUNER_TUNING_COARSE +} KS_TUNER_TUNING_FLAGS; + +typedef enum { + KS_TUNER_STRATEGY_PLL = 0X01, + KS_TUNER_STRATEGY_SIGNAL_STRENGTH = 0X02, + KS_TUNER_STRATEGY_DRIVER_TUNES = 0X04 +} KS_TUNER_STRATEGY; + +typedef struct { + KSPROPERTY Property; + ULONG ModesSupported; + KSPIN_MEDIUM VideoMedium; + KSPIN_MEDIUM TVAudioMedium; + KSPIN_MEDIUM RadioAudioMedium; +} KSPROPERTY_TUNER_CAPS_S,*PKSPROPERTY_TUNER_CAPS_S; + +typedef struct { + KSPROPERTY Property; + KSPIN_MEDIUM IFMedium; +} KSPROPERTY_TUNER_IF_MEDIUM_S,*PKSPROPERTY_TUNER_IF_MEDIUM_S; + +typedef struct { + KSPROPERTY Property; + ULONG Mode; + ULONG StandardsSupported; + ULONG MinFrequency; + ULONG MaxFrequency; + ULONG TuningGranularity; + ULONG NumberOfInputs; + ULONG SettlingTime; + ULONG Strategy; +} KSPROPERTY_TUNER_MODE_CAPS_S,*PKSPROPERTY_TUNER_MODE_CAPS_S; + +typedef struct { + KSPROPERTY Property; + ULONG Mode; +} KSPROPERTY_TUNER_MODE_S,*PKSPROPERTY_TUNER_MODE_S; + +typedef struct { + KSPROPERTY Property; + ULONG Frequency; + ULONG LastFrequency; + ULONG TuningFlags; + ULONG VideoSubChannel; + ULONG AudioSubChannel; + ULONG Channel; + ULONG Country; +} KSPROPERTY_TUNER_FREQUENCY_S,*PKSPROPERTY_TUNER_FREQUENCY_S; + +typedef struct { + KSPROPERTY Property; + ULONG Standard; +} KSPROPERTY_TUNER_STANDARD_S,*PKSPROPERTY_TUNER_STANDARD_S; + +typedef struct { + KSPROPERTY Property; + ULONG InputIndex; +} KSPROPERTY_TUNER_INPUT_S,*PKSPROPERTY_TUNER_INPUT_S; + +typedef struct { + KSPROPERTY Property; + ULONG CurrentFrequency; + ULONG PLLOffset; + ULONG SignalStrength; + ULONG Busy; +} KSPROPERTY_TUNER_STATUS_S,*PKSPROPERTY_TUNER_STATUS_S; + +#define STATIC_EVENTSETID_TUNER \ + 0x6a2e0606L,0x28e4,0x11d0,0xa1,0x8c,0x00,0xa0,0xc9,0x11,0x89,0x56 +DEFINE_GUIDSTRUCT("6a2e0606-28e4-11d0-a18c-00a0c9118956",EVENTSETID_TUNER); +#define EVENTSETID_TUNER DEFINE_GUIDNAMED(EVENTSETID_TUNER) + +typedef enum { + KSEVENT_TUNER_CHANGED +} KSEVENT_TUNER; + +#define STATIC_KSNODETYPE_VIDEO_STREAMING \ + 0xDFF229E1L,0xF70F,0x11D0,0xB9,0x17,0x00,0xA0,0xC9,0x22,0x31,0x96 +DEFINE_GUIDSTRUCT("DFF229E1-F70F-11D0-B917-00A0C9223196",KSNODETYPE_VIDEO_STREAMING); +#define KSNODETYPE_VIDEO_STREAMING DEFINE_GUIDNAMED(KSNODETYPE_VIDEO_STREAMING) + +#define STATIC_KSNODETYPE_VIDEO_INPUT_TERMINAL \ + 0xDFF229E2L,0xF70F,0x11D0,0xB9,0x17,0x00,0xA0,0xC9,0x22,0x31,0x96 +DEFINE_GUIDSTRUCT("DFF229E2-F70F-11D0-B917-00A0C9223196",KSNODETYPE_VIDEO_INPUT_TERMINAL); +#define KSNODETYPE_VIDEO_INPUT_TERMINAL DEFINE_GUIDNAMED(KSNODETYPE_VIDEO_INPUT_TERMINAL) + +#define STATIC_KSNODETYPE_VIDEO_OUTPUT_TERMINAL \ + 0xDFF229E3L,0xF70F,0x11D0,0xB9,0x17,0x00,0xA0,0xC9,0x22,0x31,0x96 +DEFINE_GUIDSTRUCT("DFF229E3-F70F-11D0-B917-00A0C9223196",KSNODETYPE_VIDEO_OUTPUT_TERMINAL); +#define KSNODETYPE_VIDEO_OUTPUT_TERMINAL DEFINE_GUIDNAMED(KSNODETYPE_VIDEO_OUTPUT_TERMINAL) + +#define STATIC_KSNODETYPE_VIDEO_SELECTOR \ + 0xDFF229E4L,0xF70F,0x11D0,0xB9,0x17,0x00,0xA0,0xC9,0x22,0x31,0x96 +DEFINE_GUIDSTRUCT("DFF229E4-F70F-11D0-B917-00A0C9223196",KSNODETYPE_VIDEO_SELECTOR); +#define KSNODETYPE_VIDEO_SELECTOR DEFINE_GUIDNAMED(KSNODETYPE_VIDEO_SELECTOR) + +#define STATIC_KSNODETYPE_VIDEO_PROCESSING \ + 0xDFF229E5L,0xF70F,0x11D0,0xB9,0x17,0x00,0xA0,0xC9,0x22,0x31,0x96 +DEFINE_GUIDSTRUCT("DFF229E5-F70F-11D0-B917-00A0C9223196",KSNODETYPE_VIDEO_PROCESSING); +#define KSNODETYPE_VIDEO_PROCESSING DEFINE_GUIDNAMED(KSNODETYPE_VIDEO_PROCESSING) + +#define STATIC_KSNODETYPE_VIDEO_CAMERA_TERMINAL \ + 0xDFF229E6L,0xF70F,0x11D0,0xB9,0x17,0x00,0xA0,0xC9,0x22,0x31,0x96 +DEFINE_GUIDSTRUCT("DFF229E6-F70F-11D0-B917-00A0C9223196",KSNODETYPE_VIDEO_CAMERA_TERMINAL); +#define KSNODETYPE_VIDEO_CAMERA_TERMINAL DEFINE_GUIDNAMED(KSNODETYPE_VIDEO_CAMERA_TERMINAL) + +#define STATIC_KSNODETYPE_VIDEO_INPUT_MTT \ + 0xDFF229E7L,0xF70F,0x11D0,0xB9,0x17,0x00,0xA0,0xC9,0x22,0x31,0x96 +DEFINE_GUIDSTRUCT("DFF229E7-F70F-11D0-B917-00A0C9223196",KSNODETYPE_VIDEO_INPUT_MTT); +#define KSNODETYPE_VIDEO_INPUT_MTT DEFINE_GUIDNAMED(KSNODETYPE_VIDEO_INPUT_MTT) + +#define STATIC_KSNODETYPE_VIDEO_OUTPUT_MTT \ + 0xDFF229E8L,0xF70F,0x11D0,0xB9,0x17,0x00,0xA0,0xC9,0x22,0x31,0x96 +DEFINE_GUIDSTRUCT("DFF229E8-F70F-11D0-B917-00A0C9223196",KSNODETYPE_VIDEO_OUTPUT_MTT); +#define KSNODETYPE_VIDEO_OUTPUT_MTT DEFINE_GUIDNAMED(KSNODETYPE_VIDEO_OUTPUT_MTT) + +#define STATIC_PROPSETID_VIDCAP_VIDEOENCODER \ + 0x6a2e0610L,0x28e4,0x11d0,0xa1,0x8c,0x00,0xa0,0xc9,0x11,0x89,0x56 +DEFINE_GUIDSTRUCT("6a2e0610-28e4-11d0-a18c-00a0c9118956",PROPSETID_VIDCAP_VIDEOENCODER); +#define PROPSETID_VIDCAP_VIDEOENCODER DEFINE_GUIDNAMED(PROPSETID_VIDCAP_VIDEOENCODER) + +typedef enum { + KSPROPERTY_VIDEOENCODER_CAPS, + KSPROPERTY_VIDEOENCODER_STANDARD, + KSPROPERTY_VIDEOENCODER_COPYPROTECTION, + KSPROPERTY_VIDEOENCODER_CC_ENABLE +} KSPROPERTY_VIDCAP_VIDEOENCODER; + +typedef struct { + KSPROPERTY Property; + LONG Value; + ULONG Flags; + ULONG Capabilities; +} KSPROPERTY_VIDEOENCODER_S,*PKSPROPERTY_VIDEOENCODER_S; + +#define STATIC_PROPSETID_VIDCAP_VIDEODECODER \ + 0xC6E13350L,0x30AC,0x11d0,0xA1,0x8C,0x00,0xA0,0xC9,0x11,0x89,0x56 +DEFINE_GUIDSTRUCT("C6E13350-30AC-11d0-A18C-00A0C9118956",PROPSETID_VIDCAP_VIDEODECODER); +#define PROPSETID_VIDCAP_VIDEODECODER DEFINE_GUIDNAMED(PROPSETID_VIDCAP_VIDEODECODER) + +typedef enum { + KSPROPERTY_VIDEODECODER_CAPS, + KSPROPERTY_VIDEODECODER_STANDARD, + KSPROPERTY_VIDEODECODER_STATUS, + KSPROPERTY_VIDEODECODER_OUTPUT_ENABLE, + KSPROPERTY_VIDEODECODER_VCR_TIMING +} KSPROPERTY_VIDCAP_VIDEODECODER; + +typedef enum { + KS_VIDEODECODER_FLAGS_CAN_DISABLE_OUTPUT = 0X0001, + KS_VIDEODECODER_FLAGS_CAN_USE_VCR_LOCKING = 0X0002, + KS_VIDEODECODER_FLAGS_CAN_INDICATE_LOCKED = 0X0004 +} KS_VIDEODECODER_FLAGS; + +typedef struct { + KSPROPERTY Property; + ULONG StandardsSupported; + ULONG Capabilities; + ULONG SettlingTime; + ULONG HSyncPerVSync; +} KSPROPERTY_VIDEODECODER_CAPS_S,*PKSPROPERTY_VIDEODECODER_CAPS_S; + +typedef struct { + KSPROPERTY Property; + ULONG NumberOfLines; + ULONG SignalLocked; +} KSPROPERTY_VIDEODECODER_STATUS_S,*PKSPROPERTY_VIDEODECODER_STATUS_S; + +typedef struct { + KSPROPERTY Property; + ULONG Value; +} KSPROPERTY_VIDEODECODER_S,*PKSPROPERTY_VIDEODECODER_S; + +#define STATIC_EVENTSETID_VIDEODECODER \ + 0x6a2e0621L,0x28e4,0x11d0,0xa1,0x8c,0x00,0xa0,0xc9,0x11,0x89,0x56 +DEFINE_GUIDSTRUCT("6a2e0621-28e4-11d0-a18c-00a0c9118956",EVENTSETID_VIDEODECODER); +#define EVENTSETID_VIDEODECODER DEFINE_GUIDNAMED(EVENTSETID_VIDEODECODER) + +typedef enum { + KSEVENT_VIDEODECODER_CHANGED +} KSEVENT_VIDEODECODER; + +#define STATIC_PROPSETID_VIDCAP_CAMERACONTROL \ + 0xC6E13370L,0x30AC,0x11d0,0xa1,0x8C,0x00,0xA0,0xC9,0x11,0x89,0x56 +DEFINE_GUIDSTRUCT("C6E13370-30AC-11d0-A18C-00A0C9118956",PROPSETID_VIDCAP_CAMERACONTROL); +#define PROPSETID_VIDCAP_CAMERACONTROL DEFINE_GUIDNAMED(PROPSETID_VIDCAP_CAMERACONTROL) + +typedef enum { + KSPROPERTY_CAMERACONTROL_PAN, + KSPROPERTY_CAMERACONTROL_TILT, + KSPROPERTY_CAMERACONTROL_ROLL, + KSPROPERTY_CAMERACONTROL_ZOOM, + KSPROPERTY_CAMERACONTROL_EXPOSURE, + KSPROPERTY_CAMERACONTROL_IRIS, + KSPROPERTY_CAMERACONTROL_FOCUS, + KSPROPERTY_CAMERACONTROL_SCANMODE, + KSPROPERTY_CAMERACONTROL_PRIVACY, + KSPROPERTY_CAMERACONTROL_PANTILT, + KSPROPERTY_CAMERACONTROL_PAN_RELATIVE, + KSPROPERTY_CAMERACONTROL_TILT_RELATIVE, + KSPROPERTY_CAMERACONTROL_ROLL_RELATIVE, + KSPROPERTY_CAMERACONTROL_ZOOM_RELATIVE, + KSPROPERTY_CAMERACONTROL_EXPOSURE_RELATIVE, + KSPROPERTY_CAMERACONTROL_IRIS_RELATIVE, + KSPROPERTY_CAMERACONTROL_FOCUS_RELATIVE, + KSPROPERTY_CAMERACONTROL_PANTILT_RELATIVE, + KSPROPERTY_CAMERACONTROL_FOCAL_LENGTH +} KSPROPERTY_VIDCAP_CAMERACONTROL; + +typedef struct { + KSPROPERTY Property; + LONG Value; + ULONG Flags; + ULONG Capabilities; +} KSPROPERTY_CAMERACONTROL_S,*PKSPROPERTY_CAMERACONTROL_S; + +typedef struct { + KSP_NODE NodeProperty; + LONG Value; + ULONG Flags; + ULONG Capabilities; +} KSPROPERTY_CAMERACONTROL_NODE_S,PKSPROPERTY_CAMERACONTROL_NODE_S; + +typedef struct { + KSPROPERTY Property; + LONG Value1; + ULONG Flags; + ULONG Capabilities; + LONG Value2; +} KSPROPERTY_CAMERACONTROL_S2,*PKSPROPERTY_CAMERACONTROL_S2; + +typedef struct { + KSP_NODE NodeProperty; + LONG Value1; + ULONG Flags; + ULONG Capabilities; + LONG Value2; +} KSPROPERTY_CAMERACONTROL_NODE_S2,*PKSPROPERTY_CAMERACONTROL_NODE_S2; + +typedef struct { + KSPROPERTY Property; + LONG lOcularFocalLength; + LONG lObjectiveFocalLengthMin; + LONG lObjectiveFocalLengthMax; +} KSPROPERTY_CAMERACONTROL_FOCAL_LENGTH_S,*PKSPROPERTY_CAMERACONTROL_FOCAL_LENGTH_S; + +typedef struct { + KSNODEPROPERTY NodeProperty; + LONG lOcularFocalLength; + LONG lObjectiveFocalLengthMin; + LONG lObjectiveFocalLengthMax; +} KSPROPERTY_CAMERACONTROL_NODE_FOCAL_LENGTH_S,*PKSPROPERTY_CAMERACONTROL_NODE_FOCAL_LENGTH_S; + +#define KSPROPERTY_CAMERACONTROL_FLAGS_AUTO 0X0001L +#define KSPROPERTY_CAMERACONTROL_FLAGS_MANUAL 0X0002L + +#define KSPROPERTY_CAMERACONTROL_FLAGS_ABSOLUTE 0X0000L +#define KSPROPERTY_CAMERACONTROL_FLAGS_RELATIVE 0X0010L + +#ifndef __EDevCtrl__ +#define __EDevCtrl__ + +#define STATIC_PROPSETID_EXT_DEVICE \ + 0xB5730A90L,0x1A2C,0x11cf,0x8c,0x23,0x00,0xAA,0x00,0x6B,0x68,0x14 +DEFINE_GUIDSTRUCT("B5730A90-1A2C-11cf-8C23-00AA006B6814",PROPSETID_EXT_DEVICE); +#define PROPSETID_EXT_DEVICE DEFINE_GUIDNAMED(PROPSETID_EXT_DEVICE) + +typedef enum { + KSPROPERTY_EXTDEVICE_ID, + KSPROPERTY_EXTDEVICE_VERSION, + KSPROPERTY_EXTDEVICE_POWER_STATE, + KSPROPERTY_EXTDEVICE_PORT, + KSPROPERTY_EXTDEVICE_CAPABILITIES +} KSPROPERTY_EXTDEVICE; + +typedef struct tagDEVCAPS{ + LONG CanRecord; + LONG CanRecordStrobe; + LONG HasAudio; + LONG HasVideo; + LONG UsesFiles; + LONG CanSave; + LONG DeviceType; + LONG TCRead; + LONG TCWrite; + LONG CTLRead; + LONG IndexRead; + LONG Preroll; + LONG Postroll; + LONG SyncAcc; + LONG NormRate; + LONG CanPreview; + LONG CanMonitorSrc; + LONG CanTest; + LONG VideoIn; + LONG AudioIn; + LONG Calibrate; + LONG SeekType; + LONG SimulatedHardware; +} DEVCAPS,*PDEVCAPS; + +typedef struct { + KSPROPERTY Property; + union { + DEVCAPS Capabilities; + ULONG DevPort; + ULONG PowerState; + WCHAR pawchString[MAX_PATH]; + DWORD NodeUniqueID[2]; + } u; +} KSPROPERTY_EXTDEVICE_S,*PKSPROPERTY_EXTDEVICE_S; + +#define STATIC_PROPSETID_EXT_TRANSPORT \ + 0xA03CD5F0L,0x3045,0x11cf,0x8c,0x44,0x00,0xAA,0x00,0x6B,0x68,0x14 +DEFINE_GUIDSTRUCT("A03CD5F0-3045-11cf-8C44-00AA006B6814",PROPSETID_EXT_TRANSPORT); +#define PROPSETID_EXT_TRANSPORT DEFINE_GUIDNAMED(PROPSETID_EXT_TRANSPORT) + +typedef enum { + KSPROPERTY_EXTXPORT_CAPABILITIES, + KSPROPERTY_EXTXPORT_INPUT_SIGNAL_MODE, + KSPROPERTY_EXTXPORT_OUTPUT_SIGNAL_MODE, + KSPROPERTY_EXTXPORT_LOAD_MEDIUM, + KSPROPERTY_EXTXPORT_MEDIUM_INFO, + KSPROPERTY_EXTXPORT_STATE, + KSPROPERTY_EXTXPORT_STATE_NOTIFY, + KSPROPERTY_EXTXPORT_TIMECODE_SEARCH, + KSPROPERTY_EXTXPORT_ATN_SEARCH, + KSPROPERTY_EXTXPORT_RTC_SEARCH, + KSPROPERTY_RAW_AVC_CMD +} KSPROPERTY_EXTXPORT; + +typedef struct tagTRANSPORTSTATUS { + LONG Mode; + LONG LastError; + LONG RecordInhibit; + LONG ServoLock; + LONG MediaPresent; + LONG MediaLength; + LONG MediaSize; + LONG MediaTrackCount; + LONG MediaTrackLength; + LONG MediaTrackSide; + LONG MediaType; + LONG LinkMode; + LONG NotifyOn; +} TRANSPORTSTATUS,*PTRANSPORTSTATUS; + +typedef struct tagTRANSPORTBASICPARMS { + LONG TimeFormat; + LONG TimeReference; + LONG Superimpose; + LONG EndStopAction; + LONG RecordFormat; + LONG StepFrames; + LONG SetpField; + LONG Preroll; + LONG RecPreroll; + LONG Postroll; + LONG EditDelay; + LONG PlayTCDelay; + LONG RecTCDelay; + LONG EditField; + LONG FrameServo; + LONG ColorFrameServo; + LONG ServoRef; + LONG WarnGenlock; + LONG SetTracking; + TCHAR VolumeName[40]; + LONG Ballistic[20]; + LONG Speed; + LONG CounterFormat; + LONG TunerChannel; + LONG TunerNumber; + LONG TimerEvent; + LONG TimerStartDay; + LONG TimerStartTime; + LONG TimerStopDay; + LONG TimerStopTime; +} TRANSPORTBASICPARMS,*PTRANSPORTBASICPARMS; + +typedef struct tagTRANSPORTVIDEOPARMS { + LONG OutputMode; + LONG Input; +} TRANSPORTVIDEOPARMS,*PTRANSPORTVIDEOPARMS; + +typedef struct tagTRANSPORTAUDIOPARMS { + LONG EnableOutput; + LONG EnableRecord; + LONG EnableSelsync; + LONG Input; + LONG MonitorSource; +} TRANSPORTAUDIOPARMS,*PTRANSPORTAUDIOPARMS; + +typedef struct { + WINBOOL MediaPresent; + ULONG MediaType; + WINBOOL RecordInhibit; +} MEDIUM_INFO,*PMEDIUM_INFO; + +typedef struct { + ULONG Mode; + ULONG State; +} TRANSPORT_STATE,*PTRANSPORT_STATE; + +typedef struct { + KSPROPERTY Property; + union { + ULONG Capabilities; + ULONG SignalMode; + ULONG LoadMedium; + MEDIUM_INFO MediumInfo; + TRANSPORT_STATE XPrtState; + struct { + BYTE frame; + BYTE second; + BYTE minute; + BYTE hour; + } Timecode; + DWORD dwTimecode; + DWORD dwAbsTrackNumber; + struct { + ULONG PayloadSize; + BYTE Payload[512]; + } RawAVC; + } u; +} KSPROPERTY_EXTXPORT_S,*PKSPROPERTY_EXTXPORT_S; + +typedef struct { + KSP_NODE NodeProperty; + union { + ULONG Capabilities; + ULONG SignalMode; + ULONG LoadMedium; + MEDIUM_INFO MediumInfo; + TRANSPORT_STATE XPrtState; + struct { + BYTE frame; + BYTE second; + BYTE minute; + BYTE hour; + } Timecode; + DWORD dwTimecode; + DWORD dwAbsTrackNumber; + struct { + ULONG PayloadSize; + BYTE Payload[512]; + } RawAVC; + } u; +} KSPROPERTY_EXTXPORT_NODE_S,*PKSPROPERTY_EXTXPORT_NODE_S; + +#define STATIC_PROPSETID_TIMECODE_READER \ + 0x9B496CE1L,0x811B,0x11cf,0x8C,0x77,0x00,0xAA,0x00,0x6B,0x68,0x14 +DEFINE_GUIDSTRUCT("9B496CE1-811B-11cf-8C77-00AA006B6814",PROPSETID_TIMECODE_READER); +#define PROPSETID_TIMECODE_READER DEFINE_GUIDNAMED(PROPSETID_TIMECODE_READER) + +typedef enum { + KSPROPERTY_TIMECODE_READER, + KSPROPERTY_ATN_READER, + KSPROPERTY_RTC_READER +} KSPROPERTY_TIMECODE; + +#ifndef TIMECODE_DEFINED +#define TIMECODE_DEFINED +typedef union _timecode { + struct { + WORD wFrameRate; + WORD wFrameFract; + DWORD dwFrames; + }; + DWORDLONG qw; +} TIMECODE; +typedef TIMECODE *PTIMECODE; + +typedef struct tagTIMECODE_SAMPLE { + LONGLONG qwTick; + TIMECODE timecode; + DWORD dwUser; + DWORD dwFlags; +} TIMECODE_SAMPLE; + +typedef TIMECODE_SAMPLE *PTIMECODE_SAMPLE; +#endif /* TIMECODE_DEFINED */ + +typedef struct { + KSPROPERTY Property; + TIMECODE_SAMPLE TimecodeSamp; +} KSPROPERTY_TIMECODE_S,*PKSPROPERTY_TIMECODE_S; + +typedef struct { + KSP_NODE NodeProperty; + TIMECODE_SAMPLE TimecodeSamp; +} KSPROPERTY_TIMECODE_NODE_S,*PKSPROPERTY_TIMECODE_NODE_S; + +#define STATIC_KSEVENTSETID_EXTDEV_Command \ + 0x109c7988L,0xb3cb,0x11d2,0xb4,0x8e,0x00,0x60,0x97,0xb3,0x39,0x1b +DEFINE_GUIDSTRUCT("109c7988-b3cb-11d2-b48e-006097b3391b",KSEVENTSETID_EXTDEV_Command); +#define KSEVENTSETID_EXTDEV_Command DEFINE_GUIDNAMED(KSEVENTSETID_EXTDEV_Command) + +typedef enum { + KSEVENT_EXTDEV_COMMAND_NOTIFY_INTERIM_READY, + KSEVENT_EXTDEV_COMMAND_CONTROL_INTERIM_READY, + KSEVENT_EXTDEV_COMMAND_BUSRESET, + KSEVENT_EXTDEV_TIMECODE_UPDATE, + KSEVENT_EXTDEV_OPERATION_MODE_UPDATE, + KSEVENT_EXTDEV_TRANSPORT_STATE_UPDATE, + KSEVENT_EXTDEV_NOTIFY_REMOVAL, + KSEVENT_EXTDEV_NOTIFY_MEDIUM_CHANGE +} KSEVENT_DEVCMD; +#endif /* __EDevCtrl__ */ + +#define STATIC_PROPSETID_VIDCAP_CROSSBAR \ + 0x6a2e0640L,0x28e4,0x11d0,0xa1,0x8c,0x00,0xa0,0xc9,0x11,0x89,0x56 +DEFINE_GUIDSTRUCT("6a2e0640-28e4-11d0-a18c-00a0c9118956",PROPSETID_VIDCAP_CROSSBAR); +#define PROPSETID_VIDCAP_CROSSBAR DEFINE_GUIDNAMED(PROPSETID_VIDCAP_CROSSBAR) + +typedef enum { + KSPROPERTY_CROSSBAR_CAPS, + KSPROPERTY_CROSSBAR_PININFO, + KSPROPERTY_CROSSBAR_CAN_ROUTE, + KSPROPERTY_CROSSBAR_ROUTE +} KSPROPERTY_VIDCAP_CROSSBAR; + +typedef struct { + KSPROPERTY Property; + ULONG NumberOfInputs; + ULONG NumberOfOutputs; +} KSPROPERTY_CROSSBAR_CAPS_S,*PKSPROPERTY_CROSSBAR_CAPS_S; + +typedef struct { + KSPROPERTY Property; + KSPIN_DATAFLOW Direction; + ULONG Index; + ULONG PinType; + ULONG RelatedPinIndex; + KSPIN_MEDIUM Medium; +} KSPROPERTY_CROSSBAR_PININFO_S,*PKSPROPERTY_CROSSBAR_PININFO_S; + +typedef struct { + KSPROPERTY Property; + ULONG IndexInputPin; + ULONG IndexOutputPin; + ULONG CanRoute; +} KSPROPERTY_CROSSBAR_ROUTE_S,*PKSPROPERTY_CROSSBAR_ROUTE_S; + +#define STATIC_EVENTSETID_CROSSBAR \ + 0x6a2e0641L,0x28e4,0x11d0,0xa1,0x8c,0x00,0xa0,0xc9,0x11,0x89,0x56 +DEFINE_GUIDSTRUCT("6a2e0641-28e4-11d0-a18c-00a0c9118956",EVENTSETID_CROSSBAR); +#define EVENTSETID_CROSSBAR DEFINE_GUIDNAMED(EVENTSETID_CROSSBAR) + +typedef enum { + KSEVENT_CROSSBAR_CHANGED +} KSEVENT_CROSSBAR; + +typedef enum { + KS_PhysConn_Video_Tuner = 1, + KS_PhysConn_Video_Composite, + KS_PhysConn_Video_SVideo, + KS_PhysConn_Video_RGB, + KS_PhysConn_Video_YRYBY, + KS_PhysConn_Video_SerialDigital, + KS_PhysConn_Video_ParallelDigital, + KS_PhysConn_Video_SCSI, + KS_PhysConn_Video_AUX, + KS_PhysConn_Video_1394, + KS_PhysConn_Video_USB, + KS_PhysConn_Video_VideoDecoder, + KS_PhysConn_Video_VideoEncoder, + KS_PhysConn_Video_SCART, + KS_PhysConn_Audio_Tuner = 4096, + KS_PhysConn_Audio_Line, + KS_PhysConn_Audio_Mic, + KS_PhysConn_Audio_AESDigital, + KS_PhysConn_Audio_SPDIFDigital, + KS_PhysConn_Audio_SCSI, + KS_PhysConn_Audio_AUX, + KS_PhysConn_Audio_1394, + KS_PhysConn_Audio_USB, + KS_PhysConn_Audio_AudioDecoder +} KS_PhysicalConnectorType; + +#define STATIC_PROPSETID_VIDCAP_TVAUDIO \ + 0x6a2e0650L,0x28e4,0x11d0,0xa1,0x8c,0x00,0xa0,0xc9,0x11,0x89,0x56 +DEFINE_GUIDSTRUCT("6a2e0650-28e4-11d0-a18c-00a0c9118956",PROPSETID_VIDCAP_TVAUDIO); +#define PROPSETID_VIDCAP_TVAUDIO DEFINE_GUIDNAMED(PROPSETID_VIDCAP_TVAUDIO) + +typedef enum { + KSPROPERTY_TVAUDIO_CAPS, + KSPROPERTY_TVAUDIO_MODE, + KSPROPERTY_TVAUDIO_CURRENTLY_AVAILABLE_MODES +} KSPROPERTY_VIDCAP_TVAUDIO; + +#define KS_TVAUDIO_MODE_MONO 0x0001 +#define KS_TVAUDIO_MODE_STEREO 0x0002 +#define KS_TVAUDIO_MODE_LANG_A 0x0010 +#define KS_TVAUDIO_MODE_LANG_B 0x0020 +#define KS_TVAUDIO_MODE_LANG_C 0x0040 + +typedef struct { + KSPROPERTY Property; + ULONG Capabilities; + KSPIN_MEDIUM InputMedium; + KSPIN_MEDIUM OutputMedium; +} KSPROPERTY_TVAUDIO_CAPS_S,*PKSPROPERTY_TVAUDIO_CAPS_S; + +typedef struct { + KSPROPERTY Property; + ULONG Mode; +} KSPROPERTY_TVAUDIO_S,*PKSPROPERTY_TVAUDIO_S; + +#define STATIC_KSEVENTSETID_VIDCAP_TVAUDIO \ + 0x6a2e0651L,0x28e4,0x11d0,0xa1,0x8c,0x00,0xa0,0xc9,0x11,0x89,0x56 +DEFINE_GUIDSTRUCT("6a2e0651-28e4-11d0-a18c-00a0c9118956",KSEVENTSETID_VIDCAP_TVAUDIO); +#define KSEVENTSETID_VIDCAP_TVAUDIO DEFINE_GUIDNAMED(KSEVENTSETID_VIDCAP_TVAUDIO) + +typedef enum { + KSEVENT_TVAUDIO_CHANGED +} KSEVENT_TVAUDIO; + +#define STATIC_PROPSETID_VIDCAP_VIDEOCOMPRESSION \ + 0xC6E13343L,0x30AC,0x11d0,0xA1,0x8C,0x00,0xA0,0xC9,0x11,0x89,0x56 +DEFINE_GUIDSTRUCT("C6E13343-30AC-11d0-A18C-00A0C9118956",PROPSETID_VIDCAP_VIDEOCOMPRESSION); +#define PROPSETID_VIDCAP_VIDEOCOMPRESSION DEFINE_GUIDNAMED(PROPSETID_VIDCAP_VIDEOCOMPRESSION) + +typedef enum { + KSPROPERTY_VIDEOCOMPRESSION_GETINFO, + KSPROPERTY_VIDEOCOMPRESSION_KEYFRAME_RATE, + KSPROPERTY_VIDEOCOMPRESSION_PFRAMES_PER_KEYFRAME, + KSPROPERTY_VIDEOCOMPRESSION_QUALITY, + KSPROPERTY_VIDEOCOMPRESSION_OVERRIDE_KEYFRAME, + KSPROPERTY_VIDEOCOMPRESSION_OVERRIDE_FRAME_SIZE, + KSPROPERTY_VIDEOCOMPRESSION_WINDOWSIZE +} KSPROPERTY_VIDCAP_VIDEOCOMPRESSION; + +typedef enum { + KS_CompressionCaps_CanQuality = 1, + KS_CompressionCaps_CanCrunch = 2, + KS_CompressionCaps_CanKeyFrame = 4, + KS_CompressionCaps_CanBFrame = 8, + KS_CompressionCaps_CanWindow = 0x10 +} KS_CompressionCaps; + +typedef enum { + KS_StreamingHint_FrameInterval = 0x0100, + KS_StreamingHint_KeyFrameRate = 0x0200, + KS_StreamingHint_PFrameRate = 0x0400, + KS_StreamingHint_CompQuality = 0x0800, + KS_StreamingHint_CompWindowSize = 0x1000 +} KS_VideoStreamingHints; + +typedef struct { + KSPROPERTY Property; + ULONG StreamIndex; + LONG DefaultKeyFrameRate; + LONG DefaultPFrameRate; + LONG DefaultQuality; + LONG NumberOfQualitySettings; + LONG Capabilities; +} KSPROPERTY_VIDEOCOMPRESSION_GETINFO_S,*PKSPROPERTY_VIDEOCOMPRESSION_GETINFO_S; + +typedef struct { + KSPROPERTY Property; + ULONG StreamIndex; + LONG Value; +} KSPROPERTY_VIDEOCOMPRESSION_S,*PKSPROPERTY_VIDEOCOMPRESSION_S; + +typedef struct { + KSPROPERTY Property; + ULONG StreamIndex; + LONG Value; + ULONG Flags; +} KSPROPERTY_VIDEOCOMPRESSION_S1,*PKSPROPERTY_VIDEOCOMPRESSION_S1; + +#define STATIC_KSDATAFORMAT_SUBTYPE_OVERLAY \ + 0xe436eb7fL,0x524f,0x11ce,0x9f,0x53,0x00,0x20,0xaf,0x0b,0xa7,0x70 +DEFINE_GUIDSTRUCT("e436eb7f-524f-11ce-9f53-0020af0ba770",KSDATAFORMAT_SUBTYPE_OVERLAY); +#define KSDATAFORMAT_SUBTYPE_OVERLAY DEFINE_GUIDNAMED(KSDATAFORMAT_SUBTYPE_OVERLAY) + +#define STATIC_KSPROPSETID_OverlayUpdate \ + 0x490EA5CFL,0x7681,0x11D1,0xA2,0x1C,0x00,0xA0,0xC9,0x22,0x31,0x96 +DEFINE_GUIDSTRUCT("490EA5CF-7681-11D1-A21C-00A0C9223196",KSPROPSETID_OverlayUpdate); +#define KSPROPSETID_OverlayUpdate DEFINE_GUIDNAMED(KSPROPSETID_OverlayUpdate) + +typedef enum { + KSPROPERTY_OVERLAYUPDATE_INTERESTS, + KSPROPERTY_OVERLAYUPDATE_CLIPLIST = 0x1, + KSPROPERTY_OVERLAYUPDATE_PALETTE = 0x2, + KSPROPERTY_OVERLAYUPDATE_COLORKEY = 0x4, + KSPROPERTY_OVERLAYUPDATE_VIDEOPOSITION = 0x8, + KSPROPERTY_OVERLAYUPDATE_DISPLAYCHANGE = 0x10, + KSPROPERTY_OVERLAYUPDATE_COLORREF = 0x10000000 +} KSPROPERTY_OVERLAYUPDATE; + +typedef struct { + ULONG PelsWidth; + ULONG PelsHeight; + ULONG BitsPerPel; + WCHAR DeviceID[1]; +} KSDISPLAYCHANGE,*PKSDISPLAYCHANGE; + +#define DEFINE_KSPROPERTY_ITEM_OVERLAYUPDATE_INTERESTS(Handler) \ + DEFINE_KSPROPERTY_ITEM( \ + KSPROPERTY_OVERLAYUPDATE_INTERESTS, \ + (Handler), \ + sizeof(KSPROPERTY), \ + sizeof(ULONG), \ + NULL, NULL, 0, NULL, NULL, 0) + +#define DEFINE_KSPROPERTY_ITEM_OVERLAYUPDATE_PALETTE(Handler) \ + DEFINE_KSPROPERTY_ITEM( \ + KSPROPERTY_OVERLAYUPDATE_PALETTE, \ + NULL, \ + sizeof(KSPROPERTY), \ + 0, \ + (Handler), \ + NULL, 0, NULL, NULL, 0) + +#define DEFINE_KSPROPERTY_ITEM_OVERLAYUPDATE_COLORKEY(Handler) \ + DEFINE_KSPROPERTY_ITEM( \ + KSPROPERTY_OVERLAYUPDATE_COLORKEY, \ + NULL, \ + sizeof(KSPROPERTY), \ + sizeof(COLORKEY), \ + (Handler), \ + NULL, 0, NULL, NULL, 0) + +#define DEFINE_KSPROPERTY_ITEM_OVERLAYUPDATE_CLIPLIST(Handler) \ + DEFINE_KSPROPERTY_ITEM( \ + KSPROPERTY_OVERLAYUPDATE_CLIPLIST, \ + NULL, \ + sizeof(KSPROPERTY), \ + 2 *sizeof(RECT) + sizeof(RGNDATAHEADER),\ + (Handler), \ + NULL, 0, NULL, NULL, 0) + +#define DEFINE_KSPROPERTY_ITEM_OVERLAYUPDATE_VIDEOPOSITION(Handler) \ + DEFINE_KSPROPERTY_ITEM( \ + KSPROPERTY_OVERLAYUPDATE_VIDEOPOSITION, \ + NULL, \ + sizeof(KSPROPERTY), \ + 2 *sizeof(RECT), \ + (Handler), \ + NULL, 0, NULL, NULL, 0) + +#define DEFINE_KSPROPERTY_ITEM_OVERLAYUPDATE_DISPLAYCHANGE(Handler) \ + DEFINE_KSPROPERTY_ITEM( \ + KSPROPERTY_OVERLAYUPDATE_DISPLAYCHANGE, \ + NULL, \ + sizeof(KSPROPERTY), \ + sizeof(KSDISPLAYCHANGE), \ + (Handler), \ + NULL, 0, NULL, NULL, 0) + +#define DEFINE_KSPROPERTY_ITEM_OVERLAYUPDATE_COLORREF(Handler) \ + DEFINE_KSPROPERTY_ITEM( \ + KSPROPERTY_OVERLAYUPDATE_COLORREF, \ + (Handler), \ + sizeof(KSPROPERTY), \ + sizeof(COLORREF), \ + NULL, \ + NULL, 0, NULL, NULL, 0) + +#define STATIC_PROPSETID_VIDCAP_VIDEOCONTROL \ + 0x6a2e0670L,0x28e4,0x11d0,0xa1,0x8c,0x00,0xa0,0xc9,0x11,0x89,0x56 +DEFINE_GUIDSTRUCT("6a2e0670-28e4-11d0-a18c-00a0c9118956",PROPSETID_VIDCAP_VIDEOCONTROL); +#define PROPSETID_VIDCAP_VIDEOCONTROL DEFINE_GUIDNAMED(PROPSETID_VIDCAP_VIDEOCONTROL) + +typedef enum { + KSPROPERTY_VIDEOCONTROL_CAPS, + KSPROPERTY_VIDEOCONTROL_ACTUAL_FRAME_RATE, + KSPROPERTY_VIDEOCONTROL_FRAME_RATES, + KSPROPERTY_VIDEOCONTROL_MODE +} KSPROPERTY_VIDCAP_VIDEOCONTROL; + +typedef enum { + KS_VideoControlFlag_FlipHorizontal = 0x0001, + KS_VideoControlFlag_FlipVertical = 0x0002, + KS_Obsolete_VideoControlFlag_ExternalTriggerEnable = 0x0010, + KS_Obsolete_VideoControlFlag_Trigger = 0x0020, + KS_VideoControlFlag_ExternalTriggerEnable = 0x0004, + KS_VideoControlFlag_Trigger = 0x0008 +} KS_VideoControlFlags; + +typedef struct { + KSPROPERTY Property; + ULONG StreamIndex; + ULONG VideoControlCaps; +} KSPROPERTY_VIDEOCONTROL_CAPS_S,*PKSPROPERTY_VIDEOCONTROL_CAPS_S; + +typedef struct { + KSPROPERTY Property; + ULONG StreamIndex; + LONG Mode; +} KSPROPERTY_VIDEOCONTROL_MODE_S,*PKSPROPERTY_VIDEOCONTROL_MODE_S; + +typedef struct { + KSPROPERTY Property; + ULONG StreamIndex; + ULONG RangeIndex; + SIZE Dimensions; + LONGLONG CurrentActualFrameRate; + LONGLONG CurrentMaxAvailableFrameRate; +} KSPROPERTY_VIDEOCONTROL_ACTUAL_FRAME_RATE_S,*PKSPROPERTY_VIDEOCONTROL_ACTUAL_FRAME_RATE_S; + +typedef struct { + KSPROPERTY Property; + ULONG StreamIndex; + ULONG RangeIndex; + SIZE Dimensions; +} KSPROPERTY_VIDEOCONTROL_FRAME_RATES_S,*PKSPROPERTY_VIDEOCONTROL_FRAME_RATES_S; + +#define STATIC_PROPSETID_VIDCAP_DROPPEDFRAMES \ + 0xC6E13344L,0x30AC,0x11d0,0xa1,0x8c,0x00,0xa0,0xc9,0x11,0x89,0x56 +DEFINE_GUIDSTRUCT("C6E13344-30AC-11d0-A18C-00A0C9118956",PROPSETID_VIDCAP_DROPPEDFRAMES); +#define PROPSETID_VIDCAP_DROPPEDFRAMES DEFINE_GUIDNAMED(PROPSETID_VIDCAP_DROPPEDFRAMES) + +typedef enum { + KSPROPERTY_DROPPEDFRAMES_CURRENT +} KSPROPERTY_VIDCAP_DROPPEDFRAMES; + +typedef struct { + KSPROPERTY Property; + LONGLONG PictureNumber; + LONGLONG DropCount; + ULONG AverageFrameSize; +} KSPROPERTY_DROPPEDFRAMES_CURRENT_S,*PKSPROPERTY_DROPPEDFRAMES_CURRENT_S; + +#define STATIC_KSPROPSETID_VPConfig \ + 0xbc29a660L,0x30e3,0x11d0,0x9e,0x69,0x00,0xc0,0x4f,0xd7,0xc1,0x5b +DEFINE_GUIDSTRUCT("bc29a660-30e3-11d0-9e69-00c04fd7c15b",KSPROPSETID_VPConfig); +#define KSPROPSETID_VPConfig DEFINE_GUIDNAMED(KSPROPSETID_VPConfig) + +#define STATIC_KSPROPSETID_VPVBIConfig \ + 0xec529b00L,0x1a1f,0x11d1,0xba,0xd9,0x0,0x60,0x97,0x44,0x11,0x1a +DEFINE_GUIDSTRUCT("ec529b00-1a1f-11d1-bad9-00609744111a",KSPROPSETID_VPVBIConfig); +#define KSPROPSETID_VPVBIConfig DEFINE_GUIDNAMED(KSPROPSETID_VPVBIConfig) + +typedef enum { + KSPROPERTY_VPCONFIG_NUMCONNECTINFO, + KSPROPERTY_VPCONFIG_GETCONNECTINFO, + KSPROPERTY_VPCONFIG_SETCONNECTINFO, + KSPROPERTY_VPCONFIG_VPDATAINFO, + KSPROPERTY_VPCONFIG_MAXPIXELRATE, + KSPROPERTY_VPCONFIG_INFORMVPINPUT, + KSPROPERTY_VPCONFIG_NUMVIDEOFORMAT, + KSPROPERTY_VPCONFIG_GETVIDEOFORMAT, + KSPROPERTY_VPCONFIG_SETVIDEOFORMAT, + KSPROPERTY_VPCONFIG_INVERTPOLARITY, + KSPROPERTY_VPCONFIG_DECIMATIONCAPABILITY, + KSPROPERTY_VPCONFIG_SCALEFACTOR, + KSPROPERTY_VPCONFIG_DDRAWHANDLE, + KSPROPERTY_VPCONFIG_VIDEOPORTID, + KSPROPERTY_VPCONFIG_DDRAWSURFACEHANDLE, + KSPROPERTY_VPCONFIG_SURFACEPARAMS +} KSPROPERTY_VPCONFIG; + +#define STATIC_CLSID_KsIBasicAudioInterfaceHandler \ + 0xb9f8ac3e,0x0f71,0x11d2,0xb7,0x2c,0x00,0xc0,0x4f,0xb6,0xbd,0x3d +DEFINE_GUIDSTRUCT("b9f8ac3e-0f71-11d2-b72c-00c04fb6bd3d",CLSID_KsIBasicAudioInterfaceHandler); +#define CLSID_KsIBasicAudioInterfaceHandler DEFINE_GUIDNAMED(CLSID_KsIBasicAudioInterfaceHandler) + +#ifdef __IVPType__ +typedef struct { + AMVPSIZE Size; + DWORD MaxPixelsPerSecond; + DWORD Reserved; +} KSVPMAXPIXELRATE,*PKSVPMAXPIXELRATE; + +typedef struct { + KSPROPERTY Property; + AMVPSIZE Size; +} KSVPSIZE_PROP,*PKSVPSIZE_PROP; + +typedef struct { + DWORD dwPitch; + DWORD dwXOrigin; + DWORD dwYOrigin; +} KSVPSURFACEPARAMS,*PKSVPSURFACEPARAMS; +#else /* __IVPType__ */ + +#ifndef __DDRAW_INCLUDED__ +#define DDPF_FOURCC 0x00000004l + +typedef struct _DDPIXELFORMAT +{ + DWORD dwSize; + DWORD dwFlags; + DWORD dwFourCC; + __MINGW_EXTENSION union + { + DWORD dwRGBBitCount; + DWORD dwYUVBitCount; + DWORD dwZBufferBitDepth; + DWORD dwAlphaBitDepth; + }; + __MINGW_EXTENSION union + { + DWORD dwRBitMask; + DWORD dwYBitMask; + }; + __MINGW_EXTENSION union + { + DWORD dwGBitMask; + DWORD dwUBitMask; + }; + __MINGW_EXTENSION union + { + DWORD dwBBitMask; + DWORD dwVBitMask; + }; + __MINGW_EXTENSION union + { + DWORD dwRGBAlphaBitMask; + DWORD dwYUVAlphaBitMask; + DWORD dwRGBZBitMask; + DWORD dwYUVZBitMask; + }; +} DDPIXELFORMAT,*LPDDPIXELFORMAT; +#endif /* __DDRAW_INCLUDED__ */ + +#ifndef __DVP_INCLUDED__ +typedef struct _DDVIDEOPORTCONNECT { + DWORD dwSize; + DWORD dwPortWidth; + GUID guidTypeID; + DWORD dwFlags; + ULONG_PTR dwReserved1; +} DDVIDEOPORTCONNECT,*LPDDVIDEOPORTCONNECT; + +#define DDVPTYPE_E_HREFH_VREFH \ + 0x54F39980L,0xDA60,0x11CF,0x9B,0x06,0x00,0xA0,0xC9,0x03,0xA3,0xB8 + +#define DDVPTYPE_E_HREFL_VREFL \ + 0xE09C77E0L,0xDA60,0x11CF,0x9B,0x06,0x00,0xA0,0xC9,0x03,0xA3,0xB8 +#endif /* __DVP_INCLUDED__ */ + +typedef enum +{ + KS_PixAspectRatio_NTSC4x3, + KS_PixAspectRatio_NTSC16x9, + KS_PixAspectRatio_PAL4x3, + KS_PixAspectRatio_PAL16x9 +} KS_AMPixAspectRatio; + +typedef enum +{ + KS_AMVP_DO_NOT_CARE, + KS_AMVP_BEST_BANDWIDTH, + KS_AMVP_INPUT_SAME_AS_OUTPUT +} KS_AMVP_SELECTFORMATBY; + +typedef enum +{ + KS_AMVP_MODE_WEAVE, + KS_AMVP_MODE_BOBINTERLEAVED, + KS_AMVP_MODE_BOBNONINTERLEAVED, + KS_AMVP_MODE_SKIPEVEN, + KS_AMVP_MODE_SKIPODD +} KS_AMVP_MODE; + +typedef struct tagKS_AMVPDIMINFO +{ + DWORD dwFieldWidth; + DWORD dwFieldHeight; + DWORD dwVBIWidth; + DWORD dwVBIHeight; + RECT rcValidRegion; +} KS_AMVPDIMINFO,*PKS_AMVPDIMINFO; + +typedef struct tagKS_AMVPDATAINFO +{ + DWORD dwSize; + DWORD dwMicrosecondsPerField; + KS_AMVPDIMINFO amvpDimInfo; + DWORD dwPictAspectRatioX; + DWORD dwPictAspectRatioY; + WINBOOL bEnableDoubleClock; + WINBOOL bEnableVACT; + WINBOOL bDataIsInterlaced; + LONG lHalfLinesOdd; + WINBOOL bFieldPolarityInverted; + DWORD dwNumLinesInVREF; + LONG lHalfLinesEven; + DWORD dwReserved1; +} KS_AMVPDATAINFO,*PKS_AMVPDATAINFO; + +typedef struct tagKS_AMVPSIZE +{ + DWORD dwWidth; + DWORD dwHeight; +} KS_AMVPSIZE,*PKS_AMVPSIZE; + +typedef struct { + KS_AMVPSIZE Size; + DWORD MaxPixelsPerSecond; + DWORD Reserved; +} KSVPMAXPIXELRATE,*PKSVPMAXPIXELRATE; + +typedef struct { + KSPROPERTY Property; + KS_AMVPSIZE Size; +} KSVPSIZE_PROP,*PKSVPSIZE_PROP; + +typedef struct { + DWORD dwPitch; + DWORD dwXOrigin; + DWORD dwYOrigin; +} KSVPSURFACEPARAMS,*PKSVPSURFACEPARAMS; +#endif /* __IVPType__ */ + +#define STATIC_KSEVENTSETID_VPNotify \ + 0x20c5598eL,0xd3c8,0x11d0,0x8d,0xfc,0x00,0xc0,0x4f,0xd7,0xc0,0x8b +DEFINE_GUIDSTRUCT("20c5598e-d3c8-11d0-8dfc-00c04fd7c08b",KSEVENTSETID_VPNotify); +#define KSEVENTSETID_VPNotify DEFINE_GUIDNAMED(KSEVENTSETID_VPNotify) + +typedef enum { + KSEVENT_VPNOTIFY_FORMATCHANGE +} KSEVENT_VPNOTIFY; + +#define STATIC_KSEVENTSETID_VIDCAPTOSTI \ + 0xdb47de20,0xf628,0x11d1,0xba,0x41,0x0,0xa0,0xc9,0xd,0x2b,0x5 +DEFINE_GUIDSTRUCT("DB47DE20-F628-11d1-BA41-00A0C90D2B05",KSEVENTSETID_VIDCAPTOSTI); +#define KSEVENTSETID_VIDCAPNotify DEFINE_GUIDNAMED(KSEVENTSETID_VIDCAPTOSTI) + +typedef enum { + KSEVENT_VIDCAPTOSTI_EXT_TRIGGER, + KSEVENT_VIDCAP_AUTO_UPDATE, + KSEVENT_VIDCAP_SEARCH +} KSEVENT_VIDCAPTOSTI; + +typedef enum { + KSPROPERTY_EXTENSION_UNIT_INFO, + KSPROPERTY_EXTENSION_UNIT_CONTROL, + KSPROPERTY_EXTENSION_UNIT_PASS_THROUGH = 0xffff +} KSPROPERTY_EXTENSION_UNIT,*PKSPROPERTY_EXTENSION_UNIT; + +#define STATIC_KSEVENTSETID_VPVBINotify \ + 0xec529b01L,0x1a1f,0x11d1,0xba,0xd9,0x0,0x60,0x97,0x44,0x11,0x1a +DEFINE_GUIDSTRUCT("ec529b01-1a1f-11d1-bad9-00609744111a",KSEVENTSETID_VPVBINotify); +#define KSEVENTSETID_VPVBINotify DEFINE_GUIDNAMED(KSEVENTSETID_VPVBINotify) + +typedef enum { + KSEVENT_VPVBINOTIFY_FORMATCHANGE +} KSEVENT_VPVBINOTIFY; + +#define STATIC_KSDATAFORMAT_TYPE_AUXLine21Data \ + 0x670aea80L,0x3a82,0x11d0,0xb7,0x9b,0x00,0xaa,0x00,0x37,0x67,0xa7 +DEFINE_GUIDSTRUCT("670aea80-3a82-11d0-b79b-00aa003767a7",KSDATAFORMAT_TYPE_AUXLine21Data); +#define KSDATAFORMAT_TYPE_AUXLine21Data DEFINE_GUIDNAMED(KSDATAFORMAT_TYPE_AUXLine21Data) + +#define STATIC_KSDATAFORMAT_SUBTYPE_Line21_BytePair \ + 0x6e8d4a22L,0x310c,0x11d0,0xb7,0x9a,0x00,0xaa,0x00,0x37,0x67,0xa7 +DEFINE_GUIDSTRUCT("6e8d4a22-310c-11d0-b79a-00aa003767a7",KSDATAFORMAT_SUBTYPE_Line21_BytePair); +#define KSDATAFORMAT_SUBTYPE_Line21_BytePair DEFINE_GUIDNAMED(KSDATAFORMAT_SUBTYPE_Line21_BytePair) + +#define STATIC_KSDATAFORMAT_SUBTYPE_Line21_GOPPacket \ + 0x6e8d4a23L,0x310c,0x11d0,0xb7,0x9a,0x00,0xaa,0x00,0x37,0x67,0xa7 +DEFINE_GUIDSTRUCT("6e8d4a23-310c-11d0-b79a-00aa003767a7",KSDATAFORMAT_SUBTYPE_Line21_GOPPacket); +#define KSDATAFORMAT_SUBTYPE_Line21_GOPPacket DEFINE_GUIDNAMED(KSDATAFORMAT_SUBTYPE_Line21_GOPPacket) + +typedef struct _KSGOP_USERDATA { + ULONG sc; + ULONG reserved1; + BYTE cFields; + CHAR l21Data[3]; +} KSGOP_USERDATA,*PKSGOP_USERDATA; + +#define STATIC_KSDATAFORMAT_TYPE_DVD_ENCRYPTED_PACK \ + 0xed0b916a,0x044d,0x11d1,0xaa,0x78,0x00,0xc0,0x4f,0xc3,0x1d,0x60 +DEFINE_GUIDSTRUCT("ed0b916a-044d-11d1-aa78-00c04fc31d60",KSDATAFORMAT_TYPE_DVD_ENCRYPTED_PACK); +#define KSDATAFORMAT_TYPE_DVD_ENCRYPTED_PACK DEFINE_GUIDNAMED(KSDATAFORMAT_TYPE_DVD_ENCRYPTED_PACK) + +#define KS_AM_UseNewCSSKey 0x1 + +#define STATIC_KSPROPSETID_TSRateChange \ + 0xa503c5c0,0x1d1d,0x11d1,0xad,0x80,0x44,0x45,0x53,0x54,0x0,0x0 +DEFINE_GUIDSTRUCT("A503C5C0-1D1D-11D1-AD80-444553540000",KSPROPSETID_TSRateChange); +#define KSPROPSETID_TSRateChange DEFINE_GUIDNAMED(KSPROPSETID_TSRateChange) + +typedef enum { + KS_AM_RATE_SimpleRateChange = 1, + KS_AM_RATE_ExactRateChange = 2, + KS_AM_RATE_MaxFullDataRate = 3, + KS_AM_RATE_Step = 4 +} KS_AM_PROPERTY_TS_RATE_CHANGE; + +typedef struct { + REFERENCE_TIME StartTime; + LONG Rate; +} KS_AM_SimpleRateChange,*PKS_AM_SimpleRateChange; + +typedef struct { + REFERENCE_TIME OutputZeroTime; + LONG Rate; +} KS_AM_ExactRateChange,*PKS_AM_ExactRateChange; + +typedef LONG KS_AM_MaxFullDataRate; +typedef DWORD KS_AM_Step; + +#define STATIC_KSCATEGORY_ENCODER \ + 0x19689bf6,0xc384,0x48fd,0xad,0x51,0x90,0xe5,0x8c,0x79,0xf7,0xb +DEFINE_GUIDSTRUCT("19689BF6-C384-48fd-AD51-90E58C79F70B",KSCATEGORY_ENCODER); +#define KSCATEGORY_ENCODER DEFINE_GUIDNAMED(KSCATEGORY_ENCODER) + +#define STATIC_KSCATEGORY_MULTIPLEXER \ + 0x7a5de1d3,0x1a1,0x452c,0xb4,0x81,0x4f,0xa2,0xb9,0x62,0x71,0xe8 +DEFINE_GUIDSTRUCT("7A5DE1D3-01A1-452c-B481-4FA2B96271E8",KSCATEGORY_MULTIPLEXER); +#define KSCATEGORY_MULTIPLEXER DEFINE_GUIDNAMED(KSCATEGORY_MULTIPLEXER) + +#ifndef __ENCODER_API_GUIDS__ +#define __ENCODER_API_GUIDS__ + +#define STATIC_ENCAPIPARAM_BITRATE \ + 0x49cc4c43,0xca83,0x4ad4,0xa9,0xaf,0xf3,0x69,0x6a,0xf6,0x66,0xdf +DEFINE_GUIDSTRUCT("49CC4C43-CA83-4ad4-A9AF-F3696AF666DF",ENCAPIPARAM_BITRATE); +#define ENCAPIPARAM_BITRATE DEFINE_GUIDNAMED(ENCAPIPARAM_BITRATE) + +#define STATIC_ENCAPIPARAM_PEAK_BITRATE \ + 0x703f16a9,0x3d48,0x44a1,0xb0,0x77,0x1,0x8d,0xff,0x91,0x5d,0x19 +DEFINE_GUIDSTRUCT("703F16A9-3D48-44a1-B077-018DFF915D19",ENCAPIPARAM_PEAK_BITRATE); +#define ENCAPIPARAM_PEAK_BITRATE DEFINE_GUIDNAMED(ENCAPIPARAM_PEAK_BITRATE) + +#define STATIC_ENCAPIPARAM_BITRATE_MODE \ + 0xee5fb25c,0xc713,0x40d1,0x9d,0x58,0xc0,0xd7,0x24,0x1e,0x25,0xf +DEFINE_GUIDSTRUCT("EE5FB25C-C713-40d1-9D58-C0D7241E250F",ENCAPIPARAM_BITRATE_MODE); +#define ENCAPIPARAM_BITRATE_MODE DEFINE_GUIDNAMED(ENCAPIPARAM_BITRATE_MODE) + +#define STATIC_CODECAPI_CHANGELISTS \ + 0x62b12acf,0xf6b0,0x47d9,0x94,0x56,0x96,0xf2,0x2c,0x4e,0x0b,0x9d +DEFINE_GUIDSTRUCT("62B12ACF-F6B0-47D9-9456-96F22C4E0B9D",CODECAPI_CHANGELISTS); +#define CODECAPI_CHANGELISTS DEFINE_GUIDNAMED(CODECAPI_CHANGELISTS) + +#define STATIC_CODECAPI_VIDEO_ENCODER \ + 0x7112e8e1,0x3d03,0x47ef,0x8e,0x60,0x03,0xf1,0xcf,0x53,0x73,0x01 +DEFINE_GUIDSTRUCT("7112E8E1-3D03-47EF-8E60-03F1CF537301",CODECAPI_VIDEO_ENCODER); +#define CODECAPI_VIDEO_ENCODER DEFINE_GUIDNAMED(CODECAPI_VIDEO_ENCODER) + +#define STATIC_CODECAPI_AUDIO_ENCODER \ + 0xb9d19a3e,0xf897,0x429c,0xbc,0x46,0x81,0x38,0xb7,0x27,0x2b,0x2d +DEFINE_GUIDSTRUCT("B9D19A3E-F897-429C-BC46-8138B7272B2D",CODECAPI_AUDIO_ENCODER); +#define CODECAPI_AUDIO_ENCODER DEFINE_GUIDNAMED(CODECAPI_AUDIO_ENCODER) + +#define STATIC_CODECAPI_SETALLDEFAULTS \ + 0x6c5e6a7c,0xacf8,0x4f55,0xa9,0x99,0x1a,0x62,0x81,0x09,0x05,0x1b +DEFINE_GUIDSTRUCT("6C5E6A7C-ACF8-4F55-A999-1A628109051B",CODECAPI_SETALLDEFAULTS); +#define CODECAPI_SETALLDEFAULTS DEFINE_GUIDNAMED(CODECAPI_SETALLDEFAULTS) + +#define STATIC_CODECAPI_ALLSETTINGS \ + 0x6a577e92,0x83e1,0x4113,0xad,0xc2,0x4f,0xce,0xc3,0x2f,0x83,0xa1 +DEFINE_GUIDSTRUCT("6A577E92-83E1-4113-ADC2-4FCEC32F83A1",CODECAPI_ALLSETTINGS); +#define CODECAPI_ALLSETTINGS DEFINE_GUIDNAMED(CODECAPI_ALLSETTINGS) + +#define STATIC_CODECAPI_SUPPORTSEVENTS \ + 0x0581af97,0x7693,0x4dbd,0x9d,0xca,0x3f,0x9e,0xbd,0x65,0x85,0xa1 +DEFINE_GUIDSTRUCT("0581AF97-7693-4DBD-9DCA-3F9EBD6585A1",CODECAPI_SUPPORTSEVENTS); +#define CODECAPI_SUPPORTSEVENTS DEFINE_GUIDNAMED(CODECAPI_SUPPORTSEVENTS) + +#define STATIC_CODECAPI_CURRENTCHANGELIST \ + 0x1cb14e83,0x7d72,0x4657,0x83,0xfd,0x47,0xa2,0xc5,0xb9,0xd1,0x3d +DEFINE_GUIDSTRUCT("1CB14E83-7D72-4657-83FD-47A2C5B9D13D",CODECAPI_CURRENTCHANGELIST); +#define CODECAPI_CURRENTCHANGELIST DEFINE_GUIDNAMED(CODECAPI_CURRENTCHANGELIST) +#endif /* __ENCODER_API_GUIDS__ */ + +#ifndef __ENCODER_API_DEFINES__ +#define __ENCODER_API_DEFINES__ +typedef enum { + ConstantBitRate = 0, + VariableBitRateAverage, + VariableBitRatePeak +} VIDEOENCODER_BITRATE_MODE; +#endif /* __ENCODER_API_DEFINES__ */ + +#define STATIC_KSPROPSETID_Jack\ + 0x4509f757, 0x2d46, 0x4637, 0x8e, 0x62, 0xce, 0x7d, 0xb9, 0x44, 0xf5, 0x7b +DEFINE_GUIDSTRUCT("4509F757-2D46-4637-8E62-CE7DB944F57B", KSPROPSETID_Jack); +#define KSPROPSETID_Jack DEFINE_GUIDNAMED(KSPROPSETID_Jack) + +typedef enum { + KSPROPERTY_JACK_DESCRIPTION = 1, + KSPROPERTY_JACK_DESCRIPTION2, + KSPROPERTY_JACK_SINK_INFO +} KSPROPERTY_JACK; + +typedef enum +{ + eConnTypeUnknown, + eConnType3Point5mm, + eConnTypeQuarter, + eConnTypeAtapiInternal, + eConnTypeRCA, + eConnTypeOptical, + eConnTypeOtherDigital, + eConnTypeOtherAnalog, + eConnTypeMultichannelAnalogDIN, + eConnTypeXlrProfessional, + eConnTypeRJ11Modem, + eConnTypeCombination +} EPcxConnectionType; + +typedef enum +{ + eGeoLocRear = 0x1, + eGeoLocFront, + eGeoLocLeft, + eGeoLocRight, + eGeoLocTop, + eGeoLocBottom, + eGeoLocRearPanel, + eGeoLocRiser, + eGeoLocInsideMobileLid, + eGeoLocDrivebay, + eGeoLocHDMI, + eGeoLocOutsideMobileLid, + eGeoLocATAPI, + eGeoLocReserved5, + eGeoLocReserved6, + EPcxGeoLocation_enum_count +} EPcxGeoLocation; + +typedef enum +{ + eGenLocPrimaryBox = 0, + eGenLocInternal, + eGenLocSeparate, + eGenLocOther, + EPcxGenLocation_enum_count +} EPcxGenLocation; + +typedef enum +{ + ePortConnJack = 0, + ePortConnIntegratedDevice, + ePortConnBothIntegratedAndJack, + ePortConnUnknown +} EPxcPortConnection; + +typedef struct +{ + DWORD ChannelMapping; + COLORREF Color; + EPcxConnectionType ConnectionType; + EPcxGeoLocation GeoLocation; + EPcxGenLocation GenLocation; + EPxcPortConnection PortConnection; + BOOL IsConnected; +} KSJACK_DESCRIPTION, *PKSJACK_DESCRIPTION; + +typedef enum +{ + KSJACK_SINK_CONNECTIONTYPE_HDMI = 0, + KSJACK_SINK_CONNECTIONTYPE_DISPLAYPORT, +} KSJACK_SINK_CONNECTIONTYPE; + +#define MAX_SINK_DESCRIPTION_NAME_LENGTH 32 +typedef struct _tagKSJACK_SINK_INFORMATION +{ + KSJACK_SINK_CONNECTIONTYPE ConnType; + WORD ManufacturerId; + WORD ProductId; + WORD AudioLatency; + BOOL HDCPCapable; + BOOL AICapable; + UCHAR SinkDescriptionLength; + WCHAR SinkDescription[MAX_SINK_DESCRIPTION_NAME_LENGTH]; + LUID PortId; +} KSJACK_SINK_INFORMATION, *PKSJACK_SINK_INFORMATION; + +#define JACKDESC2_PRESENCE_DETECT_CAPABILITY 0x00000001 +#define JACKDESC2_DYNAMIC_FORMAT_CHANGE_CAPABILITY 0x00000002 + +typedef struct _tagKSJACK_DESCRIPTION2 +{ + DWORD DeviceStateInfo; + DWORD JackCapabilities; +} KSJACK_DESCRIPTION2, *PKSJACK_DESCRIPTION2; + +/* Additional structs for Windows Vista and later */ +typedef struct _tagKSRTAUDIO_BUFFER_PROPERTY { + KSPROPERTY Property; + PVOID BaseAddress; + ULONG RequestedBufferSize; +} KSRTAUDIO_BUFFER_PROPERTY, *PKSRTAUDIO_BUFFER_PROPERTY; + +typedef struct _tagKSRTAUDIO_BUFFER_PROPERTY_WITH_NOTIFICATION { + KSPROPERTY Property; + PVOID BaseAddress; + ULONG RequestedBufferSize; + ULONG NotificationCount; +} KSRTAUDIO_BUFFER_PROPERTY_WITH_NOTIFICATION, *PKSRTAUDIO_BUFFER_PROPERTY_WITH_NOTIFICATION; + +typedef struct _tagKSRTAUDIO_BUFFER { + PVOID BufferAddress; + ULONG ActualBufferSize; + BOOL CallMemoryBarrier; +} KSRTAUDIO_BUFFER, *PKSRTAUDIO_BUFFER; + +typedef struct _tagKSRTAUDIO_HWLATENCY { + ULONG FifoSize; + ULONG ChipsetDelay; + ULONG CodecDelay; +} KSRTAUDIO_HWLATENCY, *PKSRTAUDIO_HWLATENCY; + +typedef struct _tagKSRTAUDIO_HWREGISTER_PROPERTY { + KSPROPERTY Property; + PVOID BaseAddress; +} KSRTAUDIO_HWREGISTER_PROPERTY, *PKSRTAUDIO_HWREGISTER_PROPERTY; + +typedef struct _tagKSRTAUDIO_HWREGISTER { + PVOID Register; + ULONG Width; + ULONGLONG Numerator; + ULONGLONG Denominator; + ULONG Accuracy; +} KSRTAUDIO_HWREGISTER, *PKSRTAUDIO_HWREGISTER; + +typedef struct _tagKSRTAUDIO_NOTIFICATION_EVENT_PROPERTY { + KSPROPERTY Property; + HANDLE NotificationEvent; +} KSRTAUDIO_NOTIFICATION_EVENT_PROPERTY, *PKSRTAUDIO_NOTIFICATION_EVENT_PROPERTY; + + +#endif /* _KSMEDIA_ */ + diff --git a/extern/portaudio/src/hostapi/wasapi/mingw-include/ksproxy.h b/extern/portaudio/src/hostapi/wasapi/mingw-include/ksproxy.h new file mode 100644 index 0000000..e6e049d --- /dev/null +++ b/extern/portaudio/src/hostapi/wasapi/mingw-include/ksproxy.h @@ -0,0 +1,639 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER.PD within this package. + */ +#ifndef __KSPROXY__ +#define __KSPROXY__ + +#ifdef __cplusplus +extern "C" { +#endif + +#undef KSDDKAPI +#ifdef _KSDDK_ +#define KSDDKAPI +#else +#define KSDDKAPI DECLSPEC_IMPORT +#endif + +#define STATIC_IID_IKsObject \ + 0x423c13a2L,0x2070,0x11d0,0x9e,0xf7,0x00,0xaa,0x00,0xa2,0x16,0xa1 + +#define STATIC_IID_IKsPinEx \ + 0x7bb38260L,0xd19c,0x11d2,0xb3,0x8a,0x00,0xa0,0xc9,0x5e,0xc2,0x2e + +#define STATIC_IID_IKsPin \ + 0xb61178d1L,0xa2d9,0x11cf,0x9e,0x53,0x00,0xaa,0x00,0xa2,0x16,0xa1 + +#define STATIC_IID_IKsPinPipe \ + 0xe539cd90L,0xa8b4,0x11d1,0x81,0x89,0x00,0xa0,0xc9,0x06,0x28,0x02 + +#define STATIC_IID_IKsDataTypeHandler \ + 0x5ffbaa02L,0x49a3,0x11d0,0x9f,0x36,0x00,0xaa,0x00,0xa2,0x16,0xa1 + +#define STATIC_IID_IKsDataTypeCompletion \ + 0x827D1A0EL,0x0F73,0x11D2,0xB2,0x7A,0x00,0xA0,0xC9,0x22,0x31,0x96 + +#define STATIC_IID_IKsInterfaceHandler \ + 0xD3ABC7E0L,0x9A61,0x11D0,0xA4,0x0D,0x00,0xA0,0xC9,0x22,0x31,0x96 + +#define STATIC_IID_IKsClockPropertySet \ + 0x5C5CBD84L,0xE755,0x11D0,0xAC,0x18,0x00,0xA0,0xC9,0x22,0x31,0x96 + +#define STATIC_IID_IKsAllocator \ + 0x8da64899L,0xc0d9,0x11d0,0x84,0x13,0x00,0x00,0xf8,0x22,0xfe,0x8a + +#define STATIC_IID_IKsAllocatorEx \ + 0x091bb63aL,0x603f,0x11d1,0xb0,0x67,0x00,0xa0,0xc9,0x06,0x28,0x02 + +#ifndef STATIC_IID_IKsPropertySet +#define STATIC_IID_IKsPropertySet \ + 0x31EFAC30L,0x515C,0x11d0,0xA9,0xAA,0x00,0xAA,0x00,0x61,0xBE,0x93 +#endif + +#define STATIC_IID_IKsTopology \ + 0x28F54683L,0x06FD,0x11D2,0xB2,0x7A,0x00,0xA0,0xC9,0x22,0x31,0x96 + +#ifndef STATIC_IID_IKsControl +#define STATIC_IID_IKsControl \ + 0x28F54685L,0x06FD,0x11D2,0xB2,0x7A,0x00,0xA0,0xC9,0x22,0x31,0x96 +#endif + +#define STATIC_IID_IKsAggregateControl \ + 0x7F40EAC0L,0x3947,0x11D2,0x87,0x4E,0x00,0xA0,0xC9,0x22,0x31,0x96 + +#define STATIC_CLSID_Proxy \ + 0x17CCA71BL,0xECD7,0x11D0,0xB9,0x08,0x00,0xA0,0xC9,0x22,0x31,0x96 + +#ifdef _KS_ + +DEFINE_GUIDEX(IID_IKsObject); + +DEFINE_GUIDEX(IID_IKsPin); + +DEFINE_GUIDEX(IID_IKsPinEx); + +DEFINE_GUIDEX(IID_IKsPinPipe); + +DEFINE_GUIDEX(IID_IKsDataTypeHandler); + +DEFINE_GUIDEX(IID_IKsDataTypeCompletion); + +DEFINE_GUIDEX(IID_IKsInterfaceHandler); + +DEFINE_GUIDEX(IID_IKsClockPropertySet); + +DEFINE_GUIDEX(IID_IKsAllocator); + +DEFINE_GUIDEX(IID_IKsAllocatorEx); + +#define IID_IKsQualityForwarder KSCATEGORY_QUALITY +#define STATIC_IID_IKsQualityForwarder STATIC_KSCATEGORY_QUALITY + +typedef enum { + KsAllocatorMode_User, + KsAllocatorMode_Kernel +} KSALLOCATORMODE; + +typedef enum { + FramingProp_Uninitialized, + FramingProp_None, + FramingProp_Old, + FramingProp_Ex +} FRAMING_PROP; + +typedef FRAMING_PROP *PFRAMING_PROP; + +typedef enum { + Framing_Cache_Update, + Framing_Cache_ReadLast, + Framing_Cache_ReadOrig, + Framing_Cache_Write +} FRAMING_CACHE_OPS; + +typedef struct { + LONGLONG MinTotalNominator; + LONGLONG MaxTotalNominator; + LONGLONG TotalDenominator; +} OPTIMAL_WEIGHT_TOTALS; + +typedef struct IPin IPin; +typedef struct IKsPin IKsPin; +typedef struct IKsAllocator IKsAllocator; +typedef struct IKsAllocatorEx IKsAllocatorEx; + +#define AllocatorStrategy_DontCare 0 +#define AllocatorStrategy_MinimizeNumberOfFrames 0x00000001 +#define AllocatorStrategy_MinimizeFrameSize 0x00000002 +#define AllocatorStrategy_MinimizeNumberOfAllocators 0x00000004 +#define AllocatorStrategy_MaximizeSpeed 0x00000008 + +#define PipeFactor_None 0 +#define PipeFactor_UserModeUpstream 0x00000001 +#define PipeFactor_UserModeDownstream 0x00000002 +#define PipeFactor_MemoryTypes 0x00000004 +#define PipeFactor_Flags 0x00000008 +#define PipeFactor_PhysicalRanges 0x00000010 +#define PipeFactor_OptimalRanges 0x00000020 +#define PipeFactor_FixedCompression 0x00000040 +#define PipeFactor_UnknownCompression 0x00000080 + +#define PipeFactor_Buffers 0x00000100 +#define PipeFactor_Align 0x00000200 +#define PipeFactor_PhysicalEnd 0x00000400 +#define PipeFactor_LogicalEnd 0x00000800 + +typedef enum { + PipeState_DontCare, + PipeState_RangeNotFixed, + PipeState_RangeFixed, + PipeState_CompressionUnknown, + PipeState_Finalized +} PIPE_STATE; + +typedef struct _PIPE_DIMENSIONS { + KS_COMPRESSION AllocatorPin; + KS_COMPRESSION MaxExpansionPin; + KS_COMPRESSION EndPin; +} PIPE_DIMENSIONS,*PPIPE_DIMENSIONS; + +typedef enum { + Pipe_Allocator_None, + Pipe_Allocator_FirstPin, + Pipe_Allocator_LastPin, + Pipe_Allocator_MiddlePin +} PIPE_ALLOCATOR_PLACE; + +typedef PIPE_ALLOCATOR_PLACE *PPIPE_ALLOCATOR_PLACE; + +typedef enum { + KS_MemoryTypeDontCare = 0, + KS_MemoryTypeKernelPaged, + KS_MemoryTypeKernelNonPaged, + KS_MemoryTypeDeviceHostMapped, + KS_MemoryTypeDeviceSpecific, + KS_MemoryTypeUser, + KS_MemoryTypeAnyHost +} KS_LogicalMemoryType; + +typedef KS_LogicalMemoryType *PKS_LogicalMemoryType; + +typedef struct _PIPE_TERMINATION { + ULONG Flags; + ULONG OutsideFactors; + ULONG Weigth; + KS_FRAMING_RANGE PhysicalRange; + KS_FRAMING_RANGE_WEIGHTED OptimalRange; + KS_COMPRESSION Compression; +} PIPE_TERMINATION; + +typedef struct _ALLOCATOR_PROPERTIES_EX +{ + long cBuffers; + long cbBuffer; + long cbAlign; + long cbPrefix; + + GUID MemoryType; + GUID BusType; + PIPE_STATE State; + PIPE_TERMINATION Input; + PIPE_TERMINATION Output; + ULONG Strategy; + ULONG Flags; + ULONG Weight; + KS_LogicalMemoryType LogicalMemoryType; + PIPE_ALLOCATOR_PLACE AllocatorPlace; + PIPE_DIMENSIONS Dimensions; + KS_FRAMING_RANGE PhysicalRange; + IKsAllocatorEx *PrevSegment; + ULONG CountNextSegments; + IKsAllocatorEx **NextSegments; + ULONG InsideFactors; + ULONG NumberPins; +} ALLOCATOR_PROPERTIES_EX; + +typedef ALLOCATOR_PROPERTIES_EX *PALLOCATOR_PROPERTIES_EX; + +#ifdef __STREAMS__ + +struct IKsClockPropertySet; +#undef INTERFACE +#define INTERFACE IKsClockPropertySet +DECLARE_INTERFACE_(IKsClockPropertySet,IUnknown) +{ + STDMETHOD(KsGetTime) (THIS_ + LONGLONG *Time + ) PURE; + STDMETHOD(KsSetTime) (THIS_ + LONGLONG Time + ) PURE; + STDMETHOD(KsGetPhysicalTime) (THIS_ + LONGLONG *Time + ) PURE; + STDMETHOD(KsSetPhysicalTime) (THIS_ + LONGLONG Time + ) PURE; + STDMETHOD(KsGetCorrelatedTime) (THIS_ + KSCORRELATED_TIME *CorrelatedTime + ) PURE; + STDMETHOD(KsSetCorrelatedTime) (THIS_ + KSCORRELATED_TIME *CorrelatedTime + ) PURE; + STDMETHOD(KsGetCorrelatedPhysicalTime)(THIS_ + KSCORRELATED_TIME *CorrelatedTime + ) PURE; + STDMETHOD(KsSetCorrelatedPhysicalTime)(THIS_ + KSCORRELATED_TIME *CorrelatedTime + ) PURE; + STDMETHOD(KsGetResolution) (THIS_ + KSRESOLUTION *Resolution + ) PURE; + STDMETHOD(KsGetState) (THIS_ + KSSTATE *State + ) PURE; +}; + +struct IKsAllocator; +#undef INTERFACE +#define INTERFACE IKsAllocator +DECLARE_INTERFACE_(IKsAllocator,IUnknown) +{ + STDMETHOD_(HANDLE,KsGetAllocatorHandle)(THIS) PURE; + STDMETHOD_(KSALLOCATORMODE,KsGetAllocatorMode)(THIS) PURE; + STDMETHOD(KsGetAllocatorStatus) (THIS_ + PKSSTREAMALLOCATOR_STATUS AllocatorStatus + ) PURE; + STDMETHOD_(VOID,KsSetAllocatorMode) (THIS_ + KSALLOCATORMODE Mode + ) PURE; +}; + +struct IKsAllocatorEx; +#undef INTERFACE +#define INTERFACE IKsAllocatorEx +DECLARE_INTERFACE_(IKsAllocatorEx,IKsAllocator) +{ + STDMETHOD_(PALLOCATOR_PROPERTIES_EX,KsGetProperties)(THIS) PURE; + STDMETHOD_(VOID,KsSetProperties) (THIS_ + PALLOCATOR_PROPERTIES_EX + ) PURE; + STDMETHOD_(VOID,KsSetAllocatorHandle) (THIS_ + HANDLE AllocatorHandle + ) PURE; + STDMETHOD_(HANDLE,KsCreateAllocatorAndGetHandle)(THIS_ + IKsPin *KsPin + ) PURE; +}; + +typedef enum { + KsPeekOperation_PeekOnly, + KsPeekOperation_AddRef +} KSPEEKOPERATION; + +typedef struct _KSSTREAM_SEGMENT *PKSSTREAM_SEGMENT; +struct IKsPin; + +#undef INTERFACE +#define INTERFACE IKsPin +DECLARE_INTERFACE_(IKsPin,IUnknown) +{ + STDMETHOD(KsQueryMediums) (THIS_ + PKSMULTIPLE_ITEM *MediumList + ) PURE; + STDMETHOD(KsQueryInterfaces) (THIS_ + PKSMULTIPLE_ITEM *InterfaceList + ) PURE; + STDMETHOD(KsCreateSinkPinHandle) (THIS_ + KSPIN_INTERFACE& Interface, + KSPIN_MEDIUM& Medium + ) PURE; + STDMETHOD(KsGetCurrentCommunication) (THIS_ + KSPIN_COMMUNICATION *Communication, + KSPIN_INTERFACE *Interface, + KSPIN_MEDIUM *Medium + ) PURE; + STDMETHOD(KsPropagateAcquire) (THIS) PURE; + STDMETHOD(KsDeliver) (THIS_ + IMediaSample *Sample, + ULONG Flags + ) PURE; + STDMETHOD(KsMediaSamplesCompleted) (THIS_ + PKSSTREAM_SEGMENT StreamSegment + ) PURE; + STDMETHOD_(IMemAllocator *,KsPeekAllocator)(THIS_ + KSPEEKOPERATION Operation + ) PURE; + STDMETHOD(KsReceiveAllocator) (THIS_ + IMemAllocator *MemAllocator + ) PURE; + STDMETHOD(KsRenegotiateAllocator) (THIS) PURE; + STDMETHOD_(LONG,KsIncrementPendingIoCount)(THIS) PURE; + STDMETHOD_(LONG,KsDecrementPendingIoCount)(THIS) PURE; + STDMETHOD(KsQualityNotify) (THIS_ + ULONG Proportion, + REFERENCE_TIME TimeDelta + ) PURE; +}; + +struct IKsPinEx; +#undef INTERFACE +#define INTERFACE IKsPinEx +DECLARE_INTERFACE_(IKsPinEx,IKsPin) +{ + STDMETHOD_(VOID,KsNotifyError) (THIS_ + IMediaSample *Sample, + HRESULT hr + ) PURE; +}; + +struct IKsPinPipe; +#undef INTERFACE +#define INTERFACE IKsPinPipe +DECLARE_INTERFACE_(IKsPinPipe,IUnknown) +{ + STDMETHOD(KsGetPinFramingCache) (THIS_ + PKSALLOCATOR_FRAMING_EX *FramingEx, + PFRAMING_PROP FramingProp, + FRAMING_CACHE_OPS Option + ) PURE; + STDMETHOD(KsSetPinFramingCache) (THIS_ + PKSALLOCATOR_FRAMING_EX FramingEx, + PFRAMING_PROP FramingProp, + FRAMING_CACHE_OPS Option + ) PURE; + STDMETHOD_(IPin*,KsGetConnectedPin) (THIS) PURE; + STDMETHOD_(IKsAllocatorEx*,KsGetPipe) (THIS_ + KSPEEKOPERATION Operation + ) PURE; + STDMETHOD(KsSetPipe) (THIS_ + IKsAllocatorEx *KsAllocator + ) PURE; + STDMETHOD_(ULONG,KsGetPipeAllocatorFlag)(THIS) PURE; + STDMETHOD(KsSetPipeAllocatorFlag) (THIS_ + ULONG Flag + ) PURE; + STDMETHOD_(GUID,KsGetPinBusCache) (THIS) PURE; + STDMETHOD(KsSetPinBusCache) (THIS_ + GUID Bus + ) PURE; + STDMETHOD_(PWCHAR,KsGetPinName) (THIS) PURE; + STDMETHOD_(PWCHAR,KsGetFilterName) (THIS) PURE; +}; + +struct IKsPinFactory; +#undef INTERFACE +#define INTERFACE IKsPinFactory +DECLARE_INTERFACE_(IKsPinFactory,IUnknown) +{ + STDMETHOD(KsPinFactory) (THIS_ + ULONG *PinFactory + ) PURE; +}; + +typedef enum { + KsIoOperation_Write, + KsIoOperation_Read +} KSIOOPERATION; + +struct IKsDataTypeHandler; +#undef INTERFACE +#define INTERFACE IKsDataTypeHandler +DECLARE_INTERFACE_(IKsDataTypeHandler,IUnknown) +{ + STDMETHOD(KsCompleteIoOperation) (THIS_ + IMediaSample *Sample, + PVOID StreamHeader, + KSIOOPERATION IoOperation, + WINBOOL Cancelled + ) PURE; + STDMETHOD(KsIsMediaTypeInRanges) (THIS_ + PVOID DataRanges + ) PURE; + STDMETHOD(KsPrepareIoOperation) (THIS_ + IMediaSample *Sample, + PVOID StreamHeader, + KSIOOPERATION IoOperation + ) PURE; + STDMETHOD(KsQueryExtendedSize) (THIS_ + ULONG *ExtendedSize + ) PURE; + STDMETHOD(KsSetMediaType) (THIS_ + const AM_MEDIA_TYPE *AmMediaType + ) PURE; +}; + +struct IKsDataTypeCompletion; +#undef INTERFACE +#define INTERFACE IKsDataTypeCompletion +DECLARE_INTERFACE_(IKsDataTypeCompletion,IUnknown) +{ + STDMETHOD(KsCompleteMediaType) (THIS_ + HANDLE FilterHandle, + ULONG PinFactoryId, + AM_MEDIA_TYPE *AmMediaType + ) PURE; +}; + +struct IKsInterfaceHandler; +#undef INTERFACE +#define INTERFACE IKsInterfaceHandler +DECLARE_INTERFACE_(IKsInterfaceHandler,IUnknown) +{ + STDMETHOD(KsSetPin) (THIS_ + IKsPin *KsPin + ) PURE; + STDMETHOD(KsProcessMediaSamples) (THIS_ + IKsDataTypeHandler *KsDataTypeHandler, + IMediaSample **SampleList, + PLONG SampleCount, + KSIOOPERATION IoOperation, + PKSSTREAM_SEGMENT *StreamSegment + ) PURE; + STDMETHOD(KsCompleteIo) (THIS_ + PKSSTREAM_SEGMENT StreamSegment + ) PURE; +}; + +typedef struct _KSSTREAM_SEGMENT { + IKsInterfaceHandler *KsInterfaceHandler; + IKsDataTypeHandler *KsDataTypeHandler; + KSIOOPERATION IoOperation; + HANDLE CompletionEvent; +} KSSTREAM_SEGMENT; + +struct IKsObject; +#undef INTERFACE +#define INTERFACE IKsObject +DECLARE_INTERFACE_(IKsObject,IUnknown) +{ + STDMETHOD_(HANDLE,KsGetObjectHandle) (THIS) PURE; +}; + +struct IKsQualityForwarder; +#undef INTERFACE +#define INTERFACE IKsQualityForwarder +DECLARE_INTERFACE_(IKsQualityForwarder,IKsObject) +{ + STDMETHOD_(VOID,KsFlushClient) (THIS_ + IKsPin *Pin + ) PURE; +}; + +struct IKsNotifyEvent; +#undef INTERFACE +#define INTERFACE IKsNotifyEvent +DECLARE_INTERFACE_(IKsNotifyEvent,IUnknown) +{ + STDMETHOD(KsNotifyEvent) (THIS_ + ULONG Event, + ULONG_PTR lParam1, + ULONG_PTR lParam2 + ) PURE; +}; + +KSDDKAPI HRESULT WINAPI KsResolveRequiredAttributes(PKSDATARANGE DataRange,PKSMULTIPLE_ITEM Attributes); +KSDDKAPI HRESULT WINAPI KsOpenDefaultDevice(REFGUID Category,ACCESS_MASK Access,PHANDLE DeviceHandle); +KSDDKAPI HRESULT WINAPI KsSynchronousDeviceControl(HANDLE Handle,ULONG IoControl,PVOID InBuffer,ULONG InLength,PVOID OutBuffer,ULONG OutLength,PULONG BytesReturned); +KSDDKAPI HRESULT WINAPI KsGetMultiplePinFactoryItems(HANDLE FilterHandle,ULONG PinFactoryId,ULONG PropertyId,PVOID *Items); +KSDDKAPI HRESULT WINAPI KsGetMediaTypeCount(HANDLE FilterHandle,ULONG PinFactoryId,ULONG *MediaTypeCount); +KSDDKAPI HRESULT WINAPI KsGetMediaType(int Position,AM_MEDIA_TYPE *AmMediaType,HANDLE FilterHandle,ULONG PinFactoryId); +#endif /* __STREAMS__ */ + +#ifndef _IKsPropertySet_ +DEFINE_GUIDEX(IID_IKsPropertySet); +#endif + +#ifndef _IKsControl_ +DEFINE_GUIDEX(IID_IKsControl); +#endif + +DEFINE_GUIDEX(IID_IKsAggregateControl); +#ifndef _IKsTopology_ +DEFINE_GUIDEX(IID_IKsTopology); +#endif +DEFINE_GUIDSTRUCT("17CCA71B-ECD7-11D0-B908-00A0C9223196",CLSID_Proxy); +#define CLSID_Proxy DEFINE_GUIDNAMED(CLSID_Proxy) + +#else /* _KS_ */ + +#ifndef _IKsPropertySet_ +DEFINE_GUID(IID_IKsPropertySet,STATIC_IID_IKsPropertySet); +#endif + +DEFINE_GUID(CLSID_Proxy,STATIC_CLSID_Proxy); + +#endif /* _KS_ */ + +#ifndef _IKsPropertySet_ +#define _IKsPropertySet_ +#define KSPROPERTY_SUPPORT_GET 1 +#define KSPROPERTY_SUPPORT_SET 2 + +#ifdef DECLARE_INTERFACE_ +struct IKsPropertySet; +#undef INTERFACE +#define INTERFACE IKsPropertySet +DECLARE_INTERFACE_(IKsPropertySet,IUnknown) +{ + STDMETHOD(Set) (THIS_ + REFGUID PropSet, + ULONG Id, + LPVOID InstanceData, + ULONG InstanceLength, + LPVOID PropertyData, + ULONG DataLength + ) PURE; + STDMETHOD(Get) (THIS_ + REFGUID PropSet, + ULONG Id, + LPVOID InstanceData, + ULONG InstanceLength, + LPVOID PropertyData, + ULONG DataLength, + ULONG *BytesReturned + ) PURE; + STDMETHOD(QuerySupported) (THIS_ + REFGUID PropSet, + ULONG Id, + ULONG *TypeSupport + ) PURE; +}; +#endif /* DECLARE_INTERFACE_ */ +#endif /* _IKsPropertySet_ */ + +#ifndef _IKsControl_ +#define _IKsControl_ +#ifdef DECLARE_INTERFACE_ +struct IKsControl; +#undef INTERFACE +#define INTERFACE IKsControl +DECLARE_INTERFACE_(IKsControl,IUnknown) +{ + STDMETHOD(KsProperty) (THIS_ + PKSPROPERTY Property, + ULONG PropertyLength, + LPVOID PropertyData, + ULONG DataLength, + ULONG *BytesReturned + ) PURE; + STDMETHOD(KsMethod) (THIS_ + PKSMETHOD Method, + ULONG MethodLength, + LPVOID MethodData, + ULONG DataLength, + ULONG *BytesReturned + ) PURE; + STDMETHOD(KsEvent) (THIS_ + PKSEVENT Event, + ULONG EventLength, + LPVOID EventData, + ULONG DataLength, + ULONG *BytesReturned + ) PURE; +}; +#endif /* DECLARE_INTERFACE_ */ +#endif /* _IKsControl_ */ + +#ifdef DECLARE_INTERFACE_ +struct IKsAggregateControl; +#undef INTERFACE +#define INTERFACE IKsAggregateControl +DECLARE_INTERFACE_(IKsAggregateControl,IUnknown) +{ + STDMETHOD(KsAddAggregate) (THIS_ + REFGUID AggregateClass + ) PURE; + STDMETHOD(KsRemoveAggregate) (THIS_ + REFGUID AggregateClass + ) PURE; +}; +#endif /* DECLARE_INTERFACE_ */ + +#ifndef _IKsTopology_ +#define _IKsTopology_ +#ifdef DECLARE_INTERFACE_ +struct IKsTopology; +#undef INTERFACE +#define INTERFACE IKsTopology +DECLARE_INTERFACE_(IKsTopology,IUnknown) +{ + STDMETHOD(CreateNodeInstance) (THIS_ + ULONG NodeId, + ULONG Flags, + ACCESS_MASK DesiredAccess, + IUnknown *UnkOuter, + REFGUID InterfaceId, + LPVOID *Interface + ) PURE; +}; +#endif /* DECLARE_INTERFACE_ */ +#endif /* _IKsTopology_ */ + +#ifdef __cplusplus +} +#endif + +#endif /* __KSPROXY__ */ + diff --git a/extern/portaudio/src/hostapi/wasapi/mingw-include/ksuuids.h b/extern/portaudio/src/hostapi/wasapi/mingw-include/ksuuids.h new file mode 100644 index 0000000..7d0efff --- /dev/null +++ b/extern/portaudio/src/hostapi/wasapi/mingw-include/ksuuids.h @@ -0,0 +1,159 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the w64 mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER.PD within this package. + */ + +OUR_GUID_ENTRY(MEDIATYPE_MPEG2_PACK, + 0x36523B13,0x8EE5,0x11d1,0x8C,0xA3,0x00,0x60,0xB0,0x57,0x66,0x4A) + +OUR_GUID_ENTRY(MEDIATYPE_MPEG2_PES, + 0xe06d8020,0xdb46,0x11cf,0xb4,0xd1,0x00,0x80,0x5f,0x6c,0xbb,0xea) + +OUR_GUID_ENTRY(MEDIATYPE_MPEG2_SECTIONS, + 0x455f176c,0x4b06,0x47ce,0x9a,0xef,0x8c,0xae,0xf7,0x3d,0xf7,0xb5) + +OUR_GUID_ENTRY(MEDIASUBTYPE_ATSC_SI, + 0xb3c7397c,0xd303,0x414d,0xb3,0x3c,0x4e,0xd2,0xc9,0xd2,0x97,0x33) + +OUR_GUID_ENTRY(MEDIASUBTYPE_DVB_SI, + 0xe9dd31a3,0x221d,0x4adb,0x85,0x32,0x9a,0xf3,0x9,0xc1,0xa4,0x8) + +OUR_GUID_ENTRY(MEDIASUBTYPE_MPEG2DATA, + 0xc892e55b,0x252d,0x42b5,0xa3,0x16,0xd9,0x97,0xe7,0xa5,0xd9,0x95) + +OUR_GUID_ENTRY(MEDIASUBTYPE_MPEG2_VIDEO, + 0xe06d8026,0xdb46,0x11cf,0xb4,0xd1,0x00,0x80,0x5f,0x6c,0xbb,0xea) + +OUR_GUID_ENTRY(FORMAT_MPEG2_VIDEO, + 0xe06d80e3,0xdb46,0x11cf,0xb4,0xd1,0x00,0x80,0x5f,0x6c,0xbb,0xea) + +OUR_GUID_ENTRY(FORMAT_VIDEOINFO2, + 0xf72a76A0L,0xeb0a,0x11d0,0xac,0xe4,0x0,0x0,0xc0,0xcc,0x16,0xba) + +OUR_GUID_ENTRY(MEDIASUBTYPE_MPEG2_PROGRAM, + 0xe06d8022,0xdb46,0x11cf,0xb4,0xd1,0x00,0x80,0x05f,0x6c,0xbb,0xea) + +OUR_GUID_ENTRY(MEDIASUBTYPE_MPEG2_TRANSPORT, + 0xe06d8023,0xdb46,0x11cf,0xb4,0xd1,0x00,0x80,0x05f,0x6c,0xbb,0xea) + +OUR_GUID_ENTRY(MEDIASUBTYPE_MPEG2_TRANSPORT_STRIDE, + 0x138aa9a4,0x1ee2,0x4c5b,0x98,0x8e,0x19,0xab,0xfd,0xbc,0x8a,0x11) + +OUR_GUID_ENTRY(MEDIASUBTYPE_MPEG2_AUDIO, + 0xe06d802b,0xdb46,0x11cf,0xb4,0xd1,0x00,0x80,0x05f,0x6c,0xbb,0xea) + +OUR_GUID_ENTRY(MEDIASUBTYPE_DOLBY_AC3, + 0xe06d802c,0xdb46,0x11cf,0xb4,0xd1,0x00,0x80,0x05f,0x6c,0xbb,0xea) + +OUR_GUID_ENTRY(MEDIASUBTYPE_DVD_SUBPICTURE, + 0xe06d802d,0xdb46,0x11cf,0xb4,0xd1,0x00,0x80,0x05f,0x6c,0xbb,0xea) + +OUR_GUID_ENTRY(MEDIASUBTYPE_DVD_LPCM_AUDIO, + 0xe06d8032,0xdb46,0x11cf,0xb4,0xd1,0x00,0x80,0x05f,0x6c,0xbb,0xea) + +OUR_GUID_ENTRY(MEDIASUBTYPE_DTS, + 0xe06d8033,0xdb46,0x11cf,0xb4,0xd1,0x00,0x80,0x05f,0x6c,0xbb,0xea) + +OUR_GUID_ENTRY(MEDIASUBTYPE_SDDS, + 0xe06d8034,0xdb46,0x11cf,0xb4,0xd1,0x00,0x80,0x05f,0x6c,0xbb,0xea) + +OUR_GUID_ENTRY(MEDIATYPE_DVD_ENCRYPTED_PACK, + 0xed0b916a,0x044d,0x11d1,0xaa,0x78,0x00,0xc0,0x04f,0xc3,0x1d,0x60) + +OUR_GUID_ENTRY(MEDIATYPE_DVD_NAVIGATION, + 0xe06d802e,0xdb46,0x11cf,0xb4,0xd1,0x00,0x80,0x05f,0x6c,0xbb,0xea) + +OUR_GUID_ENTRY(MEDIASUBTYPE_DVD_NAVIGATION_PCI, + 0xe06d802f,0xdb46,0x11cf,0xb4,0xd1,0x00,0x80,0x05f,0x6c,0xbb,0xea) + +OUR_GUID_ENTRY(MEDIASUBTYPE_DVD_NAVIGATION_DSI, + 0xe06d8030,0xdb46,0x11cf,0xb4,0xd1,0x00,0x80,0x05f,0x6c,0xbb,0xea) + +OUR_GUID_ENTRY(MEDIASUBTYPE_DVD_NAVIGATION_PROVIDER, + 0xe06d8031,0xdb46,0x11cf,0xb4,0xd1,0x00,0x80,0x05f,0x6c,0xbb,0xea) + +OUR_GUID_ENTRY(FORMAT_MPEG2Video, + 0xe06d80e3,0xdb46,0x11cf,0xb4,0xd1,0x00,0x80,0x05f,0x6c,0xbb,0xea) + +OUR_GUID_ENTRY(FORMAT_DolbyAC3, + 0xe06d80e4,0xdb46,0x11cf,0xb4,0xd1,0x00,0x80,0x05f,0x6c,0xbb,0xea) + +OUR_GUID_ENTRY(FORMAT_MPEG2Audio, + 0xe06d80e5,0xdb46,0x11cf,0xb4,0xd1,0x00,0x80,0x05f,0x6c,0xbb,0xea) + +OUR_GUID_ENTRY(FORMAT_DVD_LPCMAudio, + 0xe06d80e6,0xdb46,0x11cf,0xb4,0xd1,0x00,0x80,0x05f,0x6c,0xbb,0xea) + +OUR_GUID_ENTRY(AM_KSPROPSETID_AC3, + 0xBFABE720,0x6E1F,0x11D0,0xBC,0xF2,0x44,0x45,0x53,0x54,0x00,0x00) + +OUR_GUID_ENTRY(AM_KSPROPSETID_DvdSubPic, + 0xac390460,0x43af,0x11d0,0xbd,0x6a,0x00,0x35,0x05,0xc1,0x03,0xa9) + +OUR_GUID_ENTRY(AM_KSPROPSETID_CopyProt, + 0x0E8A0A40,0x6AEF,0x11D0,0x9E,0xD0,0x00,0xA0,0x24,0xCA,0x19,0xB3) + +OUR_GUID_ENTRY(AM_KSPROPSETID_TSRateChange, + 0xa503c5c0,0x1d1d,0x11d1,0xad,0x80,0x44,0x45,0x53,0x54,0x0,0x0) + +OUR_GUID_ENTRY(AM_KSPROPSETID_DVD_RateChange, + 0x3577eb09,0x9582,0x477f,0xb2,0x9c,0xb0,0xc4,0x52,0xa4,0xff,0x9a) + +OUR_GUID_ENTRY(AM_KSPROPSETID_DvdKaraoke, + 0xae4720ae,0xaa71,0x42d8,0xb8,0x2a,0xff,0xfd,0xf5,0x8b,0x76,0xfd) + +OUR_GUID_ENTRY(AM_KSPROPSETID_FrameStep, + 0xc830acbd,0xab07,0x492f,0x88,0x52,0x45,0xb6,0x98,0x7c,0x29,0x79) + +OUR_GUID_ENTRY(AM_KSCATEGORY_CAPTURE, + 0x65E8773DL,0x8F56,0x11D0,0xA3,0xB9,0x00,0xA0,0xC9,0x22,0x31,0x96) + +OUR_GUID_ENTRY(AM_KSCATEGORY_RENDER, + 0x65E8773EL,0x8F56,0x11D0,0xA3,0xB9,0x00,0xA0,0xC9,0x22,0x31,0x96) + +OUR_GUID_ENTRY(AM_KSCATEGORY_DATACOMPRESSOR, + 0x1E84C900L,0x7E70,0x11D0,0xA5,0xD6,0x28,0xDB,0x04,0xC1,0x00,0x00) + +OUR_GUID_ENTRY(AM_KSCATEGORY_AUDIO, + 0x6994AD04L,0x93EF,0x11D0,0xA3,0xCC,0x00,0xA0,0xC9,0x22,0x31,0x96) + +OUR_GUID_ENTRY(AM_KSCATEGORY_VIDEO, + 0x6994AD05L,0x93EF,0x11D0,0xA3,0xCC,0x00,0xA0,0xC9,0x22,0x31,0x96) + +OUR_GUID_ENTRY(AM_KSCATEGORY_TVTUNER, + 0xa799a800L,0xa46d,0x11d0,0xa1,0x8c,0x00,0xa0,0x24,0x01,0xdc,0xd4) + +OUR_GUID_ENTRY(AM_KSCATEGORY_CROSSBAR, + 0xa799a801L,0xa46d,0x11d0,0xa1,0x8c,0x00,0xa0,0x24,0x01,0xdc,0xd4) + +OUR_GUID_ENTRY(AM_KSCATEGORY_TVAUDIO, + 0xa799a802L,0xa46d,0x11d0,0xa1,0x8c,0x00,0xa0,0x24,0x01,0xdc,0xd4) + +OUR_GUID_ENTRY(AM_KSCATEGORY_VBICODEC, + 0x07dad660L,0x22f1,0x11d1,0xa9,0xf4,0x00,0xc0,0x4f,0xbb,0xde,0x8f) + +OUR_GUID_ENTRY(AM_KSCATEGORY_VBICODEC_MI, + 0x9c24a977,0x951,0x451a,0x80,0x6,0xe,0x49,0xbd,0x28,0xcd,0x5f) + +OUR_GUID_ENTRY(AM_KSCATEGORY_SPLITTER, + 0x0A4252A0L,0x7E70,0x11D0,0xA5,0xD6,0x28,0xDB,0x04,0xC1,0x00,0x00) + +OUR_GUID_ENTRY(IID_IKsInterfaceHandler, + 0xD3ABC7E0L,0x9A61,0x11D0,0xA4,0x0D,0x00,0xA0,0xC9,0x22,0x31,0x96) + +OUR_GUID_ENTRY(IID_IKsDataTypeHandler, + 0x5FFBAA02L,0x49A3,0x11D0,0x9F,0x36,0x00,0xAA,0x00,0xA2,0x16,0xA1) + +OUR_GUID_ENTRY(IID_IKsPin, + 0xb61178d1L,0xa2d9,0x11cf,0x9e,0x53,0x00,0xaa,0x00,0xa2,0x16,0xa1) + +OUR_GUID_ENTRY(IID_IKsControl, + 0x28F54685L,0x06FD,0x11D2,0xB2,0x7A,0x00,0xA0,0xC9,0x22,0x31,0x96) + +OUR_GUID_ENTRY(IID_IKsPinFactory, + 0xCD5EBE6BL,0x8B6E,0x11D1,0x8A,0xE0,0x00,0xA0,0xC9,0x22,0x31,0x96) + +OUR_GUID_ENTRY(AM_INTERFACESETID_Standard, + 0x1A8766A0L,0x62CE,0x11CF,0xA5,0xD6,0x28,0xDB,0x04,0xC1,0x00,0x00) + diff --git a/extern/portaudio/src/hostapi/wasapi/mingw-include/mmdeviceapi.h b/extern/portaudio/src/hostapi/wasapi/mingw-include/mmdeviceapi.h new file mode 100644 index 0000000..a75e475 --- /dev/null +++ b/extern/portaudio/src/hostapi/wasapi/mingw-include/mmdeviceapi.h @@ -0,0 +1,929 @@ + + +/* this ALWAYS GENERATED file contains the definitions for the interfaces */ + + + /* File created by MIDL compiler version 7.00.0499 */ +/* Compiler settings for mmdeviceapi.idl: + Oicf, W1, Zp8, env=Win32 (32b run) + protocol : dce , ms_ext, c_ext, robust + error checks: allocation ref bounds_check enum stub_data + VC __declspec() decoration level: + __declspec(uuid()), __declspec(selectany), __declspec(novtable) + DECLSPEC_UUID(), MIDL_INTERFACE() +*/ +//@@MIDL_FILE_HEADING( ) + +#pragma warning( disable: 4049 ) /* more than 64k source lines */ + + +/* verify that the version is high enough to compile this file*/ +#ifndef __REQUIRED_RPCNDR_H_VERSION__ +#define __REQUIRED_RPCNDR_H_VERSION__ 500 +#endif + +/* verify that the version is high enough to compile this file*/ +#ifndef __REQUIRED_RPCSAL_H_VERSION__ +#define __REQUIRED_RPCSAL_H_VERSION__ 100 +#endif + +#include "rpc.h" +#include "rpcndr.h" + +#ifndef __RPCNDR_H_VERSION__ +#error this stub requires an updated version of +#endif // __RPCNDR_H_VERSION__ + +#ifndef COM_NO_WINDOWS_H +#include "windows.h" +#include "ole2.h" +#endif /*COM_NO_WINDOWS_H*/ + +#ifndef __mmdeviceapi_h__ +#define __mmdeviceapi_h__ + +#if __GNUC__ >=3 +#pragma GCC system_header +#endif + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +/* Forward Declarations */ + +#ifndef __IMMNotificationClient_FWD_DEFINED__ +#define __IMMNotificationClient_FWD_DEFINED__ +typedef interface IMMNotificationClient IMMNotificationClient; +#endif /* __IMMNotificationClient_FWD_DEFINED__ */ + + +#ifndef __IMMDevice_FWD_DEFINED__ +#define __IMMDevice_FWD_DEFINED__ +typedef interface IMMDevice IMMDevice; +#endif /* __IMMDevice_FWD_DEFINED__ */ + + +#ifndef __IMMDeviceCollection_FWD_DEFINED__ +#define __IMMDeviceCollection_FWD_DEFINED__ +typedef interface IMMDeviceCollection IMMDeviceCollection; +#endif /* __IMMDeviceCollection_FWD_DEFINED__ */ + + +#ifndef __IMMEndpoint_FWD_DEFINED__ +#define __IMMEndpoint_FWD_DEFINED__ +typedef interface IMMEndpoint IMMEndpoint; +#endif /* __IMMEndpoint_FWD_DEFINED__ */ + + +#ifndef __IMMDeviceEnumerator_FWD_DEFINED__ +#define __IMMDeviceEnumerator_FWD_DEFINED__ +typedef interface IMMDeviceEnumerator IMMDeviceEnumerator; +#endif /* __IMMDeviceEnumerator_FWD_DEFINED__ */ + + +#ifndef __IMMDeviceActivator_FWD_DEFINED__ +#define __IMMDeviceActivator_FWD_DEFINED__ +typedef interface IMMDeviceActivator IMMDeviceActivator; +#endif /* __IMMDeviceActivator_FWD_DEFINED__ */ + + +#ifndef __MMDeviceEnumerator_FWD_DEFINED__ +#define __MMDeviceEnumerator_FWD_DEFINED__ + +#ifdef __cplusplus +typedef class MMDeviceEnumerator MMDeviceEnumerator; +#else +typedef struct MMDeviceEnumerator MMDeviceEnumerator; +#endif /* __cplusplus */ + +#endif /* __MMDeviceEnumerator_FWD_DEFINED__ */ + + +/* header files for imported files */ +#include "unknwn.h" +#include "propsys.h" + +#ifdef __cplusplus +extern "C"{ +#endif + + +/* interface __MIDL_itf_mmdeviceapi_0000_0000 */ +/* [local] */ + +#define E_NOTFOUND HRESULT_FROM_WIN32(ERROR_NOT_FOUND) +#define E_UNSUPPORTED_TYPE HRESULT_FROM_WIN32(ERROR_UNSUPPORTED_TYPE) +#define DEVICE_STATE_ACTIVE 0x00000001 +#define DEVICE_STATE_DISABLED 0x00000002 +#define DEVICE_STATE_NOTPRESENT 0x00000004 +#define DEVICE_STATE_UNPLUGGED 0x00000008 +#define DEVICE_STATEMASK_ALL 0x0000000f +#ifdef DEFINE_PROPERTYKEY +#undef DEFINE_PROPERTYKEY +#endif +#ifdef INITGUID +#define DEFINE_PROPERTYKEY(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8, pid) EXTERN_C const PROPERTYKEY name = { { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } }, pid } +#else +#define DEFINE_PROPERTYKEY(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8, pid) EXTERN_C const PROPERTYKEY name +#endif // INITGUID +DEFINE_PROPERTYKEY(PKEY_AudioEndpoint_FormFactor, 0x1da5d803, 0xd492, 0x4edd, 0x8c, 0x23, 0xe0, 0xc0, 0xff, 0xee, 0x7f, 0x0e, 0); +DEFINE_PROPERTYKEY(PKEY_AudioEndpoint_ControlPanelPageProvider, 0x1da5d803, 0xd492, 0x4edd, 0x8c, 0x23, 0xe0, 0xc0, 0xff, 0xee, 0x7f, 0x0e, 1); +DEFINE_PROPERTYKEY(PKEY_AudioEndpoint_Association, 0x1da5d803, 0xd492, 0x4edd, 0x8c, 0x23, 0xe0, 0xc0, 0xff, 0xee, 0x7f, 0x0e, 2); +DEFINE_PROPERTYKEY(PKEY_AudioEndpoint_PhysicalSpeakers, 0x1da5d803, 0xd492, 0x4edd, 0x8c, 0x23, 0xe0, 0xc0, 0xff, 0xee, 0x7f, 0x0e, 3); +DEFINE_PROPERTYKEY(PKEY_AudioEndpoint_GUID, 0x1da5d803, 0xd492, 0x4edd, 0x8c, 0x23, 0xe0, 0xc0, 0xff, 0xee, 0x7f, 0x0e, 4); +DEFINE_PROPERTYKEY(PKEY_AudioEndpoint_Disable_SysFx, 0x1da5d803, 0xd492, 0x4edd, 0x8c, 0x23, 0xe0, 0xc0, 0xff, 0xee, 0x7f, 0x0e, 5); +#define ENDPOINT_SYSFX_ENABLED 0x00000000 // System Effects are enabled. +#define ENDPOINT_SYSFX_DISABLED 0x00000001 // System Effects are disabled. +DEFINE_PROPERTYKEY(PKEY_AudioEndpoint_FullRangeSpeakers, 0x1da5d803, 0xd492, 0x4edd, 0x8c, 0x23, 0xe0, 0xc0, 0xff, 0xee, 0x7f, 0x0e, 6); +DEFINE_PROPERTYKEY(PKEY_AudioEngine_DeviceFormat, 0xf19f064d, 0x82c, 0x4e27, 0xbc, 0x73, 0x68, 0x82, 0xa1, 0xbb, 0x8e, 0x4c, 0); +typedef struct tagDIRECTX_AUDIO_ACTIVATION_PARAMS + { + DWORD cbDirectXAudioActivationParams; + GUID guidAudioSession; + DWORD dwAudioStreamFlags; + } DIRECTX_AUDIO_ACTIVATION_PARAMS; + +typedef struct tagDIRECTX_AUDIO_ACTIVATION_PARAMS *PDIRECTX_AUDIO_ACTIVATION_PARAMS; + +typedef /* [public][public][public][public][public] */ +enum __MIDL___MIDL_itf_mmdeviceapi_0000_0000_0001 + { eRender = 0, + eCapture = ( eRender + 1 ) , + eAll = ( eCapture + 1 ) , + EDataFlow_enum_count = ( eAll + 1 ) + } EDataFlow; + +typedef /* [public][public][public] */ +enum __MIDL___MIDL_itf_mmdeviceapi_0000_0000_0002 + { eConsole = 0, + eMultimedia = ( eConsole + 1 ) , + eCommunications = ( eMultimedia + 1 ) , + ERole_enum_count = ( eCommunications + 1 ) + } ERole; + +typedef /* [public] */ +enum __MIDL___MIDL_itf_mmdeviceapi_0000_0000_0003 + { RemoteNetworkDevice = 0, + Speakers = ( RemoteNetworkDevice + 1 ) , + LineLevel = ( Speakers + 1 ) , + Headphones = ( LineLevel + 1 ) , + Microphone = ( Headphones + 1 ) , + Headset = ( Microphone + 1 ) , + Handset = ( Headset + 1 ) , + UnknownDigitalPassthrough = ( Handset + 1 ) , + SPDIF = ( UnknownDigitalPassthrough + 1 ) , + HDMI = ( SPDIF + 1 ) , + UnknownFormFactor = ( HDMI + 1 ) + } EndpointFormFactor; + + + +extern RPC_IF_HANDLE __MIDL_itf_mmdeviceapi_0000_0000_v0_0_c_ifspec; +extern RPC_IF_HANDLE __MIDL_itf_mmdeviceapi_0000_0000_v0_0_s_ifspec; + +#ifndef __IMMNotificationClient_INTERFACE_DEFINED__ +#define __IMMNotificationClient_INTERFACE_DEFINED__ + +/* interface IMMNotificationClient */ +/* [unique][helpstring][nonextensible][uuid][local][object] */ + + +EXTERN_C const IID IID_IMMNotificationClient; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("7991EEC9-7E89-4D85-8390-6C703CEC60C0") + IMMNotificationClient : public IUnknown + { + public: + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE OnDeviceStateChanged( + /* [in] */ + __in LPCWSTR pwstrDeviceId, + /* [in] */ + __in DWORD dwNewState) = 0; + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE OnDeviceAdded( + /* [in] */ + __in LPCWSTR pwstrDeviceId) = 0; + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE OnDeviceRemoved( + /* [in] */ + __in LPCWSTR pwstrDeviceId) = 0; + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE OnDefaultDeviceChanged( + /* [in] */ + __in EDataFlow flow, + /* [in] */ + __in ERole role, + /* [in] */ + __in LPCWSTR pwstrDefaultDeviceId) = 0; + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE OnPropertyValueChanged( + /* [in] */ + __in LPCWSTR pwstrDeviceId, + /* [in] */ + __in const PROPERTYKEY key) = 0; + + }; + +#else /* C style interface */ + + typedef struct IMMNotificationClientVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IMMNotificationClient * This, + /* [in] */ REFIID riid, + /* [iid_is][out] */ + __RPC__deref_out void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IMMNotificationClient * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IMMNotificationClient * This); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *OnDeviceStateChanged )( + IMMNotificationClient * This, + /* [in] */ + __in LPCWSTR pwstrDeviceId, + /* [in] */ + __in DWORD dwNewState); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *OnDeviceAdded )( + IMMNotificationClient * This, + /* [in] */ + __in LPCWSTR pwstrDeviceId); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *OnDeviceRemoved )( + IMMNotificationClient * This, + /* [in] */ + __in LPCWSTR pwstrDeviceId); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *OnDefaultDeviceChanged )( + IMMNotificationClient * This, + /* [in] */ + __in EDataFlow flow, + /* [in] */ + __in ERole role, + /* [in] */ + __in LPCWSTR pwstrDefaultDeviceId); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *OnPropertyValueChanged )( + IMMNotificationClient * This, + /* [in] */ + __in LPCWSTR pwstrDeviceId, + /* [in] */ + __in const PROPERTYKEY key); + + END_INTERFACE + } IMMNotificationClientVtbl; + + interface IMMNotificationClient + { + CONST_VTBL struct IMMNotificationClientVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IMMNotificationClient_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IMMNotificationClient_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IMMNotificationClient_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IMMNotificationClient_OnDeviceStateChanged(This,pwstrDeviceId,dwNewState) \ + ( (This)->lpVtbl -> OnDeviceStateChanged(This,pwstrDeviceId,dwNewState) ) + +#define IMMNotificationClient_OnDeviceAdded(This,pwstrDeviceId) \ + ( (This)->lpVtbl -> OnDeviceAdded(This,pwstrDeviceId) ) + +#define IMMNotificationClient_OnDeviceRemoved(This,pwstrDeviceId) \ + ( (This)->lpVtbl -> OnDeviceRemoved(This,pwstrDeviceId) ) + +#define IMMNotificationClient_OnDefaultDeviceChanged(This,flow,role,pwstrDefaultDeviceId) \ + ( (This)->lpVtbl -> OnDefaultDeviceChanged(This,flow,role,pwstrDefaultDeviceId) ) + +#define IMMNotificationClient_OnPropertyValueChanged(This,pwstrDeviceId,key) \ + ( (This)->lpVtbl -> OnPropertyValueChanged(This,pwstrDeviceId,key) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IMMNotificationClient_INTERFACE_DEFINED__ */ + + +#ifndef __IMMDevice_INTERFACE_DEFINED__ +#define __IMMDevice_INTERFACE_DEFINED__ + +/* interface IMMDevice */ +/* [unique][helpstring][nonextensible][uuid][local][object] */ + + +EXTERN_C const IID IID_IMMDevice; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("D666063F-1587-4E43-81F1-B948E807363F") + IMMDevice : public IUnknown + { + public: + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE Activate( + /* [in] */ + __in REFIID iid, + /* [in] */ + __in DWORD dwClsCtx, + /* [unique][in] */ + __in_opt PROPVARIANT *pActivationParams, + /* [iid_is][out] */ + __out void **ppInterface) = 0; + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE OpenPropertyStore( + /* [in] */ + __in DWORD stgmAccess, + /* [out] */ + __out IPropertyStore **ppProperties) = 0; + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE GetId( + /* [out] */ + __deref_out LPWSTR *ppstrId) = 0; + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE GetState( + /* [out] */ + __out DWORD *pdwState) = 0; + + }; + +#else /* C style interface */ + + typedef struct IMMDeviceVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IMMDevice * This, + /* [in] */ REFIID riid, + /* [iid_is][out] */ + __RPC__deref_out void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IMMDevice * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IMMDevice * This); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *Activate )( + IMMDevice * This, + /* [in] */ + __in REFIID iid, + /* [in] */ + __in DWORD dwClsCtx, + /* [unique][in] */ + __in_opt PROPVARIANT *pActivationParams, + /* [iid_is][out] */ + __out void **ppInterface); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *OpenPropertyStore )( + IMMDevice * This, + /* [in] */ + __in DWORD stgmAccess, + /* [out] */ + __out IPropertyStore **ppProperties); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *GetId )( + IMMDevice * This, + /* [out] */ + __deref_out LPWSTR *ppstrId); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *GetState )( + IMMDevice * This, + /* [out] */ + __out DWORD *pdwState); + + END_INTERFACE + } IMMDeviceVtbl; + + interface IMMDevice + { + CONST_VTBL struct IMMDeviceVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IMMDevice_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IMMDevice_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IMMDevice_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IMMDevice_Activate(This,iid,dwClsCtx,pActivationParams,ppInterface) \ + ( (This)->lpVtbl -> Activate(This,iid,dwClsCtx,pActivationParams,ppInterface) ) + +#define IMMDevice_OpenPropertyStore(This,stgmAccess,ppProperties) \ + ( (This)->lpVtbl -> OpenPropertyStore(This,stgmAccess,ppProperties) ) + +#define IMMDevice_GetId(This,ppstrId) \ + ( (This)->lpVtbl -> GetId(This,ppstrId) ) + +#define IMMDevice_GetState(This,pdwState) \ + ( (This)->lpVtbl -> GetState(This,pdwState) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IMMDevice_INTERFACE_DEFINED__ */ + + +#ifndef __IMMDeviceCollection_INTERFACE_DEFINED__ +#define __IMMDeviceCollection_INTERFACE_DEFINED__ + +/* interface IMMDeviceCollection */ +/* [unique][helpstring][nonextensible][uuid][local][object] */ + + +EXTERN_C const IID IID_IMMDeviceCollection; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("0BD7A1BE-7A1A-44DB-8397-CC5392387B5E") + IMMDeviceCollection : public IUnknown + { + public: + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE GetCount( + /* [out] */ + __out UINT *pcDevices) = 0; + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE Item( + /* [in] */ + __in UINT nDevice, + /* [out] */ + __out IMMDevice **ppDevice) = 0; + + }; + +#else /* C style interface */ + + typedef struct IMMDeviceCollectionVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IMMDeviceCollection * This, + /* [in] */ REFIID riid, + /* [iid_is][out] */ + __RPC__deref_out void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IMMDeviceCollection * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IMMDeviceCollection * This); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *GetCount )( + IMMDeviceCollection * This, + /* [out] */ + __out UINT *pcDevices); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *Item )( + IMMDeviceCollection * This, + /* [in] */ + __in UINT nDevice, + /* [out] */ + __out IMMDevice **ppDevice); + + END_INTERFACE + } IMMDeviceCollectionVtbl; + + interface IMMDeviceCollection + { + CONST_VTBL struct IMMDeviceCollectionVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IMMDeviceCollection_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IMMDeviceCollection_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IMMDeviceCollection_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IMMDeviceCollection_GetCount(This,pcDevices) \ + ( (This)->lpVtbl -> GetCount(This,pcDevices) ) + +#define IMMDeviceCollection_Item(This,nDevice,ppDevice) \ + ( (This)->lpVtbl -> Item(This,nDevice,ppDevice) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IMMDeviceCollection_INTERFACE_DEFINED__ */ + + +#ifndef __IMMEndpoint_INTERFACE_DEFINED__ +#define __IMMEndpoint_INTERFACE_DEFINED__ + +/* interface IMMEndpoint */ +/* [unique][helpstring][nonextensible][uuid][local][object] */ + + +EXTERN_C const IID IID_IMMEndpoint; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("1BE09788-6894-4089-8586-9A2A6C265AC5") + IMMEndpoint : public IUnknown + { + public: + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE GetDataFlow( + /* [out] */ + __out EDataFlow *pDataFlow) = 0; + + }; + +#else /* C style interface */ + + typedef struct IMMEndpointVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IMMEndpoint * This, + /* [in] */ REFIID riid, + /* [iid_is][out] */ + __RPC__deref_out void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IMMEndpoint * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IMMEndpoint * This); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *GetDataFlow )( + IMMEndpoint * This, + /* [out] */ + __out EDataFlow *pDataFlow); + + END_INTERFACE + } IMMEndpointVtbl; + + interface IMMEndpoint + { + CONST_VTBL struct IMMEndpointVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IMMEndpoint_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IMMEndpoint_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IMMEndpoint_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IMMEndpoint_GetDataFlow(This,pDataFlow) \ + ( (This)->lpVtbl -> GetDataFlow(This,pDataFlow) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IMMEndpoint_INTERFACE_DEFINED__ */ + + +#ifndef __IMMDeviceEnumerator_INTERFACE_DEFINED__ +#define __IMMDeviceEnumerator_INTERFACE_DEFINED__ + +/* interface IMMDeviceEnumerator */ +/* [unique][helpstring][nonextensible][uuid][local][object] */ + + +EXTERN_C const IID IID_IMMDeviceEnumerator; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("A95664D2-9614-4F35-A746-DE8DB63617E6") + IMMDeviceEnumerator : public IUnknown + { + public: + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE EnumAudioEndpoints( + /* [in] */ + __in EDataFlow dataFlow, + /* [in] */ + __in DWORD dwStateMask, + /* [out] */ + __out IMMDeviceCollection **ppDevices) = 0; + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE GetDefaultAudioEndpoint( + /* [in] */ + __in EDataFlow dataFlow, + /* [in] */ + __in ERole role, + /* [out] */ + __out IMMDevice **ppEndpoint) = 0; + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE GetDevice( + /* */ + __in LPCWSTR pwstrId, + /* [out] */ + __out IMMDevice **ppDevice) = 0; + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE RegisterEndpointNotificationCallback( + /* [in] */ + __in IMMNotificationClient *pClient) = 0; + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE UnregisterEndpointNotificationCallback( + /* [in] */ + __in IMMNotificationClient *pClient) = 0; + + }; + +#else /* C style interface */ + + typedef struct IMMDeviceEnumeratorVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IMMDeviceEnumerator * This, + /* [in] */ REFIID riid, + /* [iid_is][out] */ + __RPC__deref_out void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IMMDeviceEnumerator * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IMMDeviceEnumerator * This); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *EnumAudioEndpoints )( + IMMDeviceEnumerator * This, + /* [in] */ + __in EDataFlow dataFlow, + /* [in] */ + __in DWORD dwStateMask, + /* [out] */ + __out IMMDeviceCollection **ppDevices); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *GetDefaultAudioEndpoint )( + IMMDeviceEnumerator * This, + /* [in] */ + __in EDataFlow dataFlow, + /* [in] */ + __in ERole role, + /* [out] */ + __out IMMDevice **ppEndpoint); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *GetDevice )( + IMMDeviceEnumerator * This, + /* */ + __in LPCWSTR pwstrId, + /* [out] */ + __out IMMDevice **ppDevice); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *RegisterEndpointNotificationCallback )( + IMMDeviceEnumerator * This, + /* [in] */ + __in IMMNotificationClient *pClient); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *UnregisterEndpointNotificationCallback )( + IMMDeviceEnumerator * This, + /* [in] */ + __in IMMNotificationClient *pClient); + + END_INTERFACE + } IMMDeviceEnumeratorVtbl; + + interface IMMDeviceEnumerator + { + CONST_VTBL struct IMMDeviceEnumeratorVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IMMDeviceEnumerator_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IMMDeviceEnumerator_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IMMDeviceEnumerator_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IMMDeviceEnumerator_EnumAudioEndpoints(This,dataFlow,dwStateMask,ppDevices) \ + ( (This)->lpVtbl -> EnumAudioEndpoints(This,dataFlow,dwStateMask,ppDevices) ) + +#define IMMDeviceEnumerator_GetDefaultAudioEndpoint(This,dataFlow,role,ppEndpoint) \ + ( (This)->lpVtbl -> GetDefaultAudioEndpoint(This,dataFlow,role,ppEndpoint) ) + +#define IMMDeviceEnumerator_GetDevice(This,pwstrId,ppDevice) \ + ( (This)->lpVtbl -> GetDevice(This,pwstrId,ppDevice) ) + +#define IMMDeviceEnumerator_RegisterEndpointNotificationCallback(This,pClient) \ + ( (This)->lpVtbl -> RegisterEndpointNotificationCallback(This,pClient) ) + +#define IMMDeviceEnumerator_UnregisterEndpointNotificationCallback(This,pClient) \ + ( (This)->lpVtbl -> UnregisterEndpointNotificationCallback(This,pClient) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IMMDeviceEnumerator_INTERFACE_DEFINED__ */ + + +#ifndef __IMMDeviceActivator_INTERFACE_DEFINED__ +#define __IMMDeviceActivator_INTERFACE_DEFINED__ + +/* interface IMMDeviceActivator */ +/* [unique][helpstring][nonextensible][uuid][local][object] */ + + +EXTERN_C const IID IID_IMMDeviceActivator; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("3B0D0EA4-D0A9-4B0E-935B-09516746FAC0") + IMMDeviceActivator : public IUnknown + { + public: + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE Activate( + /* [in] */ + __in REFIID iid, + /* [in] */ + __in IMMDevice *pDevice, + /* [in] */ + __in_opt PROPVARIANT *pActivationParams, + /* [iid_is][out] */ + __out void **ppInterface) = 0; + + }; + +#else /* C style interface */ + + typedef struct IMMDeviceActivatorVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IMMDeviceActivator * This, + /* [in] */ REFIID riid, + /* [iid_is][out] */ + __RPC__deref_out void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IMMDeviceActivator * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IMMDeviceActivator * This); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *Activate )( + IMMDeviceActivator * This, + /* [in] */ + __in REFIID iid, + /* [in] */ + __in IMMDevice *pDevice, + /* [in] */ + __in_opt PROPVARIANT *pActivationParams, + /* [iid_is][out] */ + __out void **ppInterface); + + END_INTERFACE + } IMMDeviceActivatorVtbl; + + interface IMMDeviceActivator + { + CONST_VTBL struct IMMDeviceActivatorVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IMMDeviceActivator_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IMMDeviceActivator_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IMMDeviceActivator_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IMMDeviceActivator_Activate(This,iid,pDevice,pActivationParams,ppInterface) \ + ( (This)->lpVtbl -> Activate(This,iid,pDevice,pActivationParams,ppInterface) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IMMDeviceActivator_INTERFACE_DEFINED__ */ + + +/* interface __MIDL_itf_mmdeviceapi_0000_0006 */ +/* [local] */ + +typedef /* [public] */ struct __MIDL___MIDL_itf_mmdeviceapi_0000_0006_0001 + { + LPARAM AddPageParam; + IMMDevice *pEndpoint; + IMMDevice *pPnpInterface; + IMMDevice *pPnpDevnode; + } AudioExtensionParams; + + + +extern RPC_IF_HANDLE __MIDL_itf_mmdeviceapi_0000_0006_v0_0_c_ifspec; +extern RPC_IF_HANDLE __MIDL_itf_mmdeviceapi_0000_0006_v0_0_s_ifspec; + + +#ifndef __MMDeviceAPILib_LIBRARY_DEFINED__ +#define __MMDeviceAPILib_LIBRARY_DEFINED__ + +/* library MMDeviceAPILib */ +/* [helpstring][version][uuid] */ + + +EXTERN_C const IID LIBID_MMDeviceAPILib; + +EXTERN_C const CLSID CLSID_MMDeviceEnumerator; + +#ifdef __cplusplus + +class DECLSPEC_UUID("BCDE0395-E52F-467C-8E3D-C4579291692E") +MMDeviceEnumerator; +#endif +#endif /* __MMDeviceAPILib_LIBRARY_DEFINED__ */ + +/* Additional Prototypes for ALL interfaces */ + +/* end of Additional Prototypes */ + +#ifdef __cplusplus +} +#endif + +#endif + + + diff --git a/extern/portaudio/src/hostapi/wasapi/mingw-include/propkeydef.h b/extern/portaudio/src/hostapi/wasapi/mingw-include/propkeydef.h new file mode 100644 index 0000000..a361044 --- /dev/null +++ b/extern/portaudio/src/hostapi/wasapi/mingw-include/propkeydef.h @@ -0,0 +1,26 @@ +#ifndef PID_FIRST_USABLE +#define PID_FIRST_USABLE 2 +#endif + +#ifndef REFPROPERTYKEY +#ifdef __cplusplus +#define REFPROPERTYKEY const PROPERTYKEY & +#else // !__cplusplus +#define REFPROPERTYKEY const PROPERTYKEY * __MIDL_CONST +#endif // __cplusplus +#endif //REFPROPERTYKEY + +#ifdef DEFINE_PROPERTYKEY +#undef DEFINE_PROPERTYKEY +#endif + +#ifdef INITGUID +#define DEFINE_PROPERTYKEY(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8, pid) EXTERN_C const PROPERTYKEY DECLSPEC_SELECTANY name = { { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } }, pid } +#else +#define DEFINE_PROPERTYKEY(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8, pid) EXTERN_C const PROPERTYKEY name +#endif // INITGUID + +#ifndef IsEqualPropertyKey +#define IsEqualPropertyKey(a, b) (((a).pid == (b).pid) && IsEqualIID((a).fmtid, (b).fmtid) ) +#endif // IsEqualPropertyKey + diff --git a/extern/portaudio/src/hostapi/wasapi/mingw-include/propsys.h b/extern/portaudio/src/hostapi/wasapi/mingw-include/propsys.h new file mode 100644 index 0000000..5ed5608 --- /dev/null +++ b/extern/portaudio/src/hostapi/wasapi/mingw-include/propsys.h @@ -0,0 +1,3605 @@ + + +/* this ALWAYS GENERATED file contains the definitions for the interfaces */ + + + /* File created by MIDL compiler version 7.00.0499 */ +/* Compiler settings for propsys.idl: + Oicf, W1, Zp8, env=Win32 (32b run) + protocol : dce , ms_ext, c_ext, robust + error checks: allocation ref bounds_check enum stub_data + VC __declspec() decoration level: + __declspec(uuid()), __declspec(selectany), __declspec(novtable) + DECLSPEC_UUID(), MIDL_INTERFACE() +*/ +//@@MIDL_FILE_HEADING( ) + +#pragma warning( disable: 4049 ) /* more than 64k source lines */ + + +/* verify that the version is high enough to compile this file*/ +#ifndef __REQUIRED_RPCNDR_H_VERSION__ +#define __REQUIRED_RPCNDR_H_VERSION__ 475 +#endif + +/* verify that the version is high enough to compile this file*/ +#ifndef __REQUIRED_RPCSAL_H_VERSION__ +#define __REQUIRED_RPCSAL_H_VERSION__ 100 +#endif + +#include "rpc.h" +#include "rpcndr.h" + +#ifndef __RPCNDR_H_VERSION__ +#error this stub requires an updated version of +#endif // __RPCNDR_H_VERSION__ + +#ifndef COM_NO_WINDOWS_H +#include "windows.h" +#include "ole2.h" +#endif /*COM_NO_WINDOWS_H*/ + +#ifndef __propsys_h__ +#define __propsys_h__ + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +/* Forward Declarations */ + +#ifndef __IInitializeWithFile_FWD_DEFINED__ +#define __IInitializeWithFile_FWD_DEFINED__ +typedef interface IInitializeWithFile IInitializeWithFile; +#endif /* __IInitializeWithFile_FWD_DEFINED__ */ + + +#ifndef __IInitializeWithStream_FWD_DEFINED__ +#define __IInitializeWithStream_FWD_DEFINED__ +typedef interface IInitializeWithStream IInitializeWithStream; +#endif /* __IInitializeWithStream_FWD_DEFINED__ */ + + +#ifndef __IPropertyStore_FWD_DEFINED__ +#define __IPropertyStore_FWD_DEFINED__ +typedef interface IPropertyStore IPropertyStore; +#endif /* __IPropertyStore_FWD_DEFINED__ */ + + +#ifndef __INamedPropertyStore_FWD_DEFINED__ +#define __INamedPropertyStore_FWD_DEFINED__ +typedef interface INamedPropertyStore INamedPropertyStore; +#endif /* __INamedPropertyStore_FWD_DEFINED__ */ + + +#ifndef __IObjectWithPropertyKey_FWD_DEFINED__ +#define __IObjectWithPropertyKey_FWD_DEFINED__ +typedef interface IObjectWithPropertyKey IObjectWithPropertyKey; +#endif /* __IObjectWithPropertyKey_FWD_DEFINED__ */ + + +#ifndef __IPropertyChange_FWD_DEFINED__ +#define __IPropertyChange_FWD_DEFINED__ +typedef interface IPropertyChange IPropertyChange; +#endif /* __IPropertyChange_FWD_DEFINED__ */ + + +#ifndef __IPropertyChangeArray_FWD_DEFINED__ +#define __IPropertyChangeArray_FWD_DEFINED__ +typedef interface IPropertyChangeArray IPropertyChangeArray; +#endif /* __IPropertyChangeArray_FWD_DEFINED__ */ + + +#ifndef __IPropertyStoreCapabilities_FWD_DEFINED__ +#define __IPropertyStoreCapabilities_FWD_DEFINED__ +typedef interface IPropertyStoreCapabilities IPropertyStoreCapabilities; +#endif /* __IPropertyStoreCapabilities_FWD_DEFINED__ */ + + +#ifndef __IPropertyStoreCache_FWD_DEFINED__ +#define __IPropertyStoreCache_FWD_DEFINED__ +typedef interface IPropertyStoreCache IPropertyStoreCache; +#endif /* __IPropertyStoreCache_FWD_DEFINED__ */ + + +#ifndef __IPropertyEnumType_FWD_DEFINED__ +#define __IPropertyEnumType_FWD_DEFINED__ +typedef interface IPropertyEnumType IPropertyEnumType; +#endif /* __IPropertyEnumType_FWD_DEFINED__ */ + + +#ifndef __IPropertyEnumTypeList_FWD_DEFINED__ +#define __IPropertyEnumTypeList_FWD_DEFINED__ +typedef interface IPropertyEnumTypeList IPropertyEnumTypeList; +#endif /* __IPropertyEnumTypeList_FWD_DEFINED__ */ + + +#ifndef __IPropertyDescription_FWD_DEFINED__ +#define __IPropertyDescription_FWD_DEFINED__ +typedef interface IPropertyDescription IPropertyDescription; +#endif /* __IPropertyDescription_FWD_DEFINED__ */ + + +#ifndef __IPropertyDescriptionAliasInfo_FWD_DEFINED__ +#define __IPropertyDescriptionAliasInfo_FWD_DEFINED__ +typedef interface IPropertyDescriptionAliasInfo IPropertyDescriptionAliasInfo; +#endif /* __IPropertyDescriptionAliasInfo_FWD_DEFINED__ */ + + +#ifndef __IPropertyDescriptionSearchInfo_FWD_DEFINED__ +#define __IPropertyDescriptionSearchInfo_FWD_DEFINED__ +typedef interface IPropertyDescriptionSearchInfo IPropertyDescriptionSearchInfo; +#endif /* __IPropertyDescriptionSearchInfo_FWD_DEFINED__ */ + + +#ifndef __IPropertySystem_FWD_DEFINED__ +#define __IPropertySystem_FWD_DEFINED__ +typedef interface IPropertySystem IPropertySystem; +#endif /* __IPropertySystem_FWD_DEFINED__ */ + + +#ifndef __IPropertyDescriptionList_FWD_DEFINED__ +#define __IPropertyDescriptionList_FWD_DEFINED__ +typedef interface IPropertyDescriptionList IPropertyDescriptionList; +#endif /* __IPropertyDescriptionList_FWD_DEFINED__ */ + + +#ifndef __IPropertyStoreFactory_FWD_DEFINED__ +#define __IPropertyStoreFactory_FWD_DEFINED__ +typedef interface IPropertyStoreFactory IPropertyStoreFactory; +#endif /* __IPropertyStoreFactory_FWD_DEFINED__ */ + + +#ifndef __IDelayedPropertyStoreFactory_FWD_DEFINED__ +#define __IDelayedPropertyStoreFactory_FWD_DEFINED__ +typedef interface IDelayedPropertyStoreFactory IDelayedPropertyStoreFactory; +#endif /* __IDelayedPropertyStoreFactory_FWD_DEFINED__ */ + + +#ifndef __IPersistSerializedPropStorage_FWD_DEFINED__ +#define __IPersistSerializedPropStorage_FWD_DEFINED__ +typedef interface IPersistSerializedPropStorage IPersistSerializedPropStorage; +#endif /* __IPersistSerializedPropStorage_FWD_DEFINED__ */ + + +#ifndef __IPropertySystemChangeNotify_FWD_DEFINED__ +#define __IPropertySystemChangeNotify_FWD_DEFINED__ +typedef interface IPropertySystemChangeNotify IPropertySystemChangeNotify; +#endif /* __IPropertySystemChangeNotify_FWD_DEFINED__ */ + + +#ifndef __ICreateObject_FWD_DEFINED__ +#define __ICreateObject_FWD_DEFINED__ +typedef interface ICreateObject ICreateObject; +#endif /* __ICreateObject_FWD_DEFINED__ */ + + +#ifndef __InMemoryPropertyStore_FWD_DEFINED__ +#define __InMemoryPropertyStore_FWD_DEFINED__ + +#ifdef __cplusplus +typedef class InMemoryPropertyStore InMemoryPropertyStore; +#else +typedef struct InMemoryPropertyStore InMemoryPropertyStore; +#endif /* __cplusplus */ + +#endif /* __InMemoryPropertyStore_FWD_DEFINED__ */ + + +#ifndef __PropertySystem_FWD_DEFINED__ +#define __PropertySystem_FWD_DEFINED__ + +#ifdef __cplusplus +typedef class PropertySystem PropertySystem; +#else +typedef struct PropertySystem PropertySystem; +#endif /* __cplusplus */ + +#endif /* __PropertySystem_FWD_DEFINED__ */ + + +/* header files for imported files */ +#include "objidl.h" +#include "oleidl.h" +#include "ocidl.h" +#include "shtypes.h" +#include "structuredquery.h" + +#ifdef __cplusplus +extern "C"{ +#endif + + +/* interface __MIDL_itf_propsys_0000_0000 */ +/* [local] */ + +#ifndef PSSTDAPI +#if defined(_PROPSYS_) +#define PSSTDAPI STDAPI +#define PSSTDAPI_(type) STDAPI_(type) +#else +#define PSSTDAPI EXTERN_C DECLSPEC_IMPORT HRESULT STDAPICALLTYPE +#define PSSTDAPI_(type) EXTERN_C DECLSPEC_IMPORT type STDAPICALLTYPE +#endif +#endif // PSSTDAPI +#if 0 +typedef PROPERTYKEY *REFPROPERTYKEY; + +#endif // 0 +#include + + +extern RPC_IF_HANDLE __MIDL_itf_propsys_0000_0000_v0_0_c_ifspec; +extern RPC_IF_HANDLE __MIDL_itf_propsys_0000_0000_v0_0_s_ifspec; + +#ifndef __IInitializeWithFile_INTERFACE_DEFINED__ +#define __IInitializeWithFile_INTERFACE_DEFINED__ + +/* interface IInitializeWithFile */ +/* [unique][object][uuid] */ + + +EXTERN_C const IID IID_IInitializeWithFile; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("b7d14566-0509-4cce-a71f-0a554233bd9b") + IInitializeWithFile : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE Initialize( + /* [string][in] */ __RPC__in LPCWSTR pszFilePath, + /* [in] */ DWORD grfMode) = 0; + + }; + +#else /* C style interface */ + + typedef struct IInitializeWithFileVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IInitializeWithFile * This, + /* [in] */ __RPC__in REFIID riid, + /* [iid_is][out] */ + __RPC__deref_out void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IInitializeWithFile * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IInitializeWithFile * This); + + HRESULT ( STDMETHODCALLTYPE *Initialize )( + IInitializeWithFile * This, + /* [string][in] */ __RPC__in LPCWSTR pszFilePath, + /* [in] */ DWORD grfMode); + + END_INTERFACE + } IInitializeWithFileVtbl; + + interface IInitializeWithFile + { + CONST_VTBL struct IInitializeWithFileVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IInitializeWithFile_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IInitializeWithFile_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IInitializeWithFile_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IInitializeWithFile_Initialize(This,pszFilePath,grfMode) \ + ( (This)->lpVtbl -> Initialize(This,pszFilePath,grfMode) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IInitializeWithFile_INTERFACE_DEFINED__ */ + + +#ifndef __IInitializeWithStream_INTERFACE_DEFINED__ +#define __IInitializeWithStream_INTERFACE_DEFINED__ + +/* interface IInitializeWithStream */ +/* [unique][object][uuid] */ + + +EXTERN_C const IID IID_IInitializeWithStream; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("b824b49d-22ac-4161-ac8a-9916e8fa3f7f") + IInitializeWithStream : public IUnknown + { + public: + virtual /* [local] */ HRESULT STDMETHODCALLTYPE Initialize( + /* [in] */ IStream *pstream, + /* [in] */ DWORD grfMode) = 0; + + }; + +#else /* C style interface */ + + typedef struct IInitializeWithStreamVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IInitializeWithStream * This, + /* [in] */ __RPC__in REFIID riid, + /* [iid_is][out] */ + __RPC__deref_out void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IInitializeWithStream * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IInitializeWithStream * This); + + /* [local] */ HRESULT ( STDMETHODCALLTYPE *Initialize )( + IInitializeWithStream * This, + /* [in] */ IStream *pstream, + /* [in] */ DWORD grfMode); + + END_INTERFACE + } IInitializeWithStreamVtbl; + + interface IInitializeWithStream + { + CONST_VTBL struct IInitializeWithStreamVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IInitializeWithStream_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IInitializeWithStream_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IInitializeWithStream_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IInitializeWithStream_Initialize(This,pstream,grfMode) \ + ( (This)->lpVtbl -> Initialize(This,pstream,grfMode) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + +/* [call_as] */ HRESULT STDMETHODCALLTYPE IInitializeWithStream_RemoteInitialize_Proxy( + IInitializeWithStream * This, + /* [in] */ __RPC__in_opt IStream *pstream, + /* [in] */ DWORD grfMode); + + +void __RPC_STUB IInitializeWithStream_RemoteInitialize_Stub( + IRpcStubBuffer *This, + IRpcChannelBuffer *_pRpcChannelBuffer, + PRPC_MESSAGE _pRpcMessage, + DWORD *_pdwStubPhase); + + + +#endif /* __IInitializeWithStream_INTERFACE_DEFINED__ */ + + +#ifndef __IPropertyStore_INTERFACE_DEFINED__ +#define __IPropertyStore_INTERFACE_DEFINED__ + +/* interface IPropertyStore */ +/* [unique][object][helpstring][uuid] */ + + +EXTERN_C const IID IID_IPropertyStore; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("886d8eeb-8cf2-4446-8d02-cdba1dbdcf99") + IPropertyStore : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE GetCount( + /* [out] */ __RPC__out DWORD *cProps) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetAt( + /* [in] */ DWORD iProp, + /* [out] */ __RPC__out PROPERTYKEY *pkey) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetValue( + /* [in] */ __RPC__in REFPROPERTYKEY key, + /* [out] */ __RPC__out PROPVARIANT *pv) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetValue( + /* [in] */ __RPC__in REFPROPERTYKEY key, + /* [in] */ __RPC__in REFPROPVARIANT propvar) = 0; + + virtual HRESULT STDMETHODCALLTYPE Commit( void) = 0; + + }; + +#else /* C style interface */ + + typedef struct IPropertyStoreVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IPropertyStore * This, + /* [in] */ __RPC__in REFIID riid, + /* [iid_is][out] */ + __RPC__deref_out void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IPropertyStore * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IPropertyStore * This); + + HRESULT ( STDMETHODCALLTYPE *GetCount )( + IPropertyStore * This, + /* [out] */ __RPC__out DWORD *cProps); + + HRESULT ( STDMETHODCALLTYPE *GetAt )( + IPropertyStore * This, + /* [in] */ DWORD iProp, + /* [out] */ __RPC__out PROPERTYKEY *pkey); + + HRESULT ( STDMETHODCALLTYPE *GetValue )( + IPropertyStore * This, + /* [in] */ __RPC__in REFPROPERTYKEY key, + /* [out] */ __RPC__out PROPVARIANT *pv); + + HRESULT ( STDMETHODCALLTYPE *SetValue )( + IPropertyStore * This, + /* [in] */ __RPC__in REFPROPERTYKEY key, + /* [in] */ __RPC__in REFPROPVARIANT propvar); + + HRESULT ( STDMETHODCALLTYPE *Commit )( + IPropertyStore * This); + + END_INTERFACE + } IPropertyStoreVtbl; + + interface IPropertyStore + { + CONST_VTBL struct IPropertyStoreVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IPropertyStore_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IPropertyStore_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IPropertyStore_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IPropertyStore_GetCount(This,cProps) \ + ( (This)->lpVtbl -> GetCount(This,cProps) ) + +#define IPropertyStore_GetAt(This,iProp,pkey) \ + ( (This)->lpVtbl -> GetAt(This,iProp,pkey) ) + +#define IPropertyStore_GetValue(This,key,pv) \ + ( (This)->lpVtbl -> GetValue(This,key,pv) ) + +#define IPropertyStore_SetValue(This,key,propvar) \ + ( (This)->lpVtbl -> SetValue(This,key,propvar) ) + +#define IPropertyStore_Commit(This) \ + ( (This)->lpVtbl -> Commit(This) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IPropertyStore_INTERFACE_DEFINED__ */ + + +/* interface __MIDL_itf_propsys_0000_0003 */ +/* [local] */ + +typedef /* [unique] */ __RPC_unique_pointer IPropertyStore *LPPROPERTYSTORE; + + + +extern RPC_IF_HANDLE __MIDL_itf_propsys_0000_0003_v0_0_c_ifspec; +extern RPC_IF_HANDLE __MIDL_itf_propsys_0000_0003_v0_0_s_ifspec; + +#ifndef __INamedPropertyStore_INTERFACE_DEFINED__ +#define __INamedPropertyStore_INTERFACE_DEFINED__ + +/* interface INamedPropertyStore */ +/* [unique][object][uuid] */ + + +EXTERN_C const IID IID_INamedPropertyStore; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("71604b0f-97b0-4764-8577-2f13e98a1422") + INamedPropertyStore : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE GetNamedValue( + /* [string][in] */ __RPC__in LPCWSTR pszName, + /* [out] */ __RPC__out PROPVARIANT *ppropvar) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetNamedValue( + /* [string][in] */ __RPC__in LPCWSTR pszName, + /* [in] */ __RPC__in REFPROPVARIANT propvar) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetNameCount( + /* [out] */ __RPC__out DWORD *pdwCount) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetNameAt( + /* [in] */ DWORD iProp, + /* [out] */ __RPC__deref_out_opt BSTR *pbstrName) = 0; + + }; + +#else /* C style interface */ + + typedef struct INamedPropertyStoreVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + INamedPropertyStore * This, + /* [in] */ __RPC__in REFIID riid, + /* [iid_is][out] */ + __RPC__deref_out void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + INamedPropertyStore * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + INamedPropertyStore * This); + + HRESULT ( STDMETHODCALLTYPE *GetNamedValue )( + INamedPropertyStore * This, + /* [string][in] */ __RPC__in LPCWSTR pszName, + /* [out] */ __RPC__out PROPVARIANT *ppropvar); + + HRESULT ( STDMETHODCALLTYPE *SetNamedValue )( + INamedPropertyStore * This, + /* [string][in] */ __RPC__in LPCWSTR pszName, + /* [in] */ __RPC__in REFPROPVARIANT propvar); + + HRESULT ( STDMETHODCALLTYPE *GetNameCount )( + INamedPropertyStore * This, + /* [out] */ __RPC__out DWORD *pdwCount); + + HRESULT ( STDMETHODCALLTYPE *GetNameAt )( + INamedPropertyStore * This, + /* [in] */ DWORD iProp, + /* [out] */ __RPC__deref_out_opt BSTR *pbstrName); + + END_INTERFACE + } INamedPropertyStoreVtbl; + + interface INamedPropertyStore + { + CONST_VTBL struct INamedPropertyStoreVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define INamedPropertyStore_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define INamedPropertyStore_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define INamedPropertyStore_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define INamedPropertyStore_GetNamedValue(This,pszName,ppropvar) \ + ( (This)->lpVtbl -> GetNamedValue(This,pszName,ppropvar) ) + +#define INamedPropertyStore_SetNamedValue(This,pszName,propvar) \ + ( (This)->lpVtbl -> SetNamedValue(This,pszName,propvar) ) + +#define INamedPropertyStore_GetNameCount(This,pdwCount) \ + ( (This)->lpVtbl -> GetNameCount(This,pdwCount) ) + +#define INamedPropertyStore_GetNameAt(This,iProp,pbstrName) \ + ( (This)->lpVtbl -> GetNameAt(This,iProp,pbstrName) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __INamedPropertyStore_INTERFACE_DEFINED__ */ + + +/* interface __MIDL_itf_propsys_0000_0004 */ +/* [local] */ + +/* [v1_enum] */ +enum tagGETPROPERTYSTOREFLAGS + { GPS_DEFAULT = 0, + GPS_HANDLERPROPERTIESONLY = 0x1, + GPS_READWRITE = 0x2, + GPS_TEMPORARY = 0x4, + GPS_FASTPROPERTIESONLY = 0x8, + GPS_OPENSLOWITEM = 0x10, + GPS_DELAYCREATION = 0x20, + GPS_BESTEFFORT = 0x40, + GPS_MASK_VALID = 0x7f + } ; +typedef int GETPROPERTYSTOREFLAGS; + + + +extern RPC_IF_HANDLE __MIDL_itf_propsys_0000_0004_v0_0_c_ifspec; +extern RPC_IF_HANDLE __MIDL_itf_propsys_0000_0004_v0_0_s_ifspec; + +#ifndef __IObjectWithPropertyKey_INTERFACE_DEFINED__ +#define __IObjectWithPropertyKey_INTERFACE_DEFINED__ + +/* interface IObjectWithPropertyKey */ +/* [uuid][object] */ + + +EXTERN_C const IID IID_IObjectWithPropertyKey; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("fc0ca0a7-c316-4fd2-9031-3e628e6d4f23") + IObjectWithPropertyKey : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE SetPropertyKey( + /* [in] */ __RPC__in REFPROPERTYKEY key) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetPropertyKey( + /* [out] */ __RPC__out PROPERTYKEY *pkey) = 0; + + }; + +#else /* C style interface */ + + typedef struct IObjectWithPropertyKeyVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IObjectWithPropertyKey * This, + /* [in] */ __RPC__in REFIID riid, + /* [iid_is][out] */ + __RPC__deref_out void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IObjectWithPropertyKey * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IObjectWithPropertyKey * This); + + HRESULT ( STDMETHODCALLTYPE *SetPropertyKey )( + IObjectWithPropertyKey * This, + /* [in] */ __RPC__in REFPROPERTYKEY key); + + HRESULT ( STDMETHODCALLTYPE *GetPropertyKey )( + IObjectWithPropertyKey * This, + /* [out] */ __RPC__out PROPERTYKEY *pkey); + + END_INTERFACE + } IObjectWithPropertyKeyVtbl; + + interface IObjectWithPropertyKey + { + CONST_VTBL struct IObjectWithPropertyKeyVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IObjectWithPropertyKey_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IObjectWithPropertyKey_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IObjectWithPropertyKey_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IObjectWithPropertyKey_SetPropertyKey(This,key) \ + ( (This)->lpVtbl -> SetPropertyKey(This,key) ) + +#define IObjectWithPropertyKey_GetPropertyKey(This,pkey) \ + ( (This)->lpVtbl -> GetPropertyKey(This,pkey) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IObjectWithPropertyKey_INTERFACE_DEFINED__ */ + + +/* interface __MIDL_itf_propsys_0000_0005 */ +/* [local] */ + +typedef /* [v1_enum] */ +enum tagPKA_FLAGS + { PKA_SET = 0, + PKA_APPEND = ( PKA_SET + 1 ) , + PKA_DELETE = ( PKA_APPEND + 1 ) + } PKA_FLAGS; + + + +extern RPC_IF_HANDLE __MIDL_itf_propsys_0000_0005_v0_0_c_ifspec; +extern RPC_IF_HANDLE __MIDL_itf_propsys_0000_0005_v0_0_s_ifspec; + +#ifndef __IPropertyChange_INTERFACE_DEFINED__ +#define __IPropertyChange_INTERFACE_DEFINED__ + +/* interface IPropertyChange */ +/* [unique][object][uuid] */ + + +EXTERN_C const IID IID_IPropertyChange; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("f917bc8a-1bba-4478-a245-1bde03eb9431") + IPropertyChange : public IObjectWithPropertyKey + { + public: + virtual HRESULT STDMETHODCALLTYPE ApplyToPropVariant( + /* [in] */ __RPC__in REFPROPVARIANT propvarIn, + /* [out] */ __RPC__out PROPVARIANT *ppropvarOut) = 0; + + }; + +#else /* C style interface */ + + typedef struct IPropertyChangeVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IPropertyChange * This, + /* [in] */ __RPC__in REFIID riid, + /* [iid_is][out] */ + __RPC__deref_out void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IPropertyChange * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IPropertyChange * This); + + HRESULT ( STDMETHODCALLTYPE *SetPropertyKey )( + IPropertyChange * This, + /* [in] */ __RPC__in REFPROPERTYKEY key); + + HRESULT ( STDMETHODCALLTYPE *GetPropertyKey )( + IPropertyChange * This, + /* [out] */ __RPC__out PROPERTYKEY *pkey); + + HRESULT ( STDMETHODCALLTYPE *ApplyToPropVariant )( + IPropertyChange * This, + /* [in] */ __RPC__in REFPROPVARIANT propvarIn, + /* [out] */ __RPC__out PROPVARIANT *ppropvarOut); + + END_INTERFACE + } IPropertyChangeVtbl; + + interface IPropertyChange + { + CONST_VTBL struct IPropertyChangeVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IPropertyChange_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IPropertyChange_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IPropertyChange_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IPropertyChange_SetPropertyKey(This,key) \ + ( (This)->lpVtbl -> SetPropertyKey(This,key) ) + +#define IPropertyChange_GetPropertyKey(This,pkey) \ + ( (This)->lpVtbl -> GetPropertyKey(This,pkey) ) + + +#define IPropertyChange_ApplyToPropVariant(This,propvarIn,ppropvarOut) \ + ( (This)->lpVtbl -> ApplyToPropVariant(This,propvarIn,ppropvarOut) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IPropertyChange_INTERFACE_DEFINED__ */ + + +#ifndef __IPropertyChangeArray_INTERFACE_DEFINED__ +#define __IPropertyChangeArray_INTERFACE_DEFINED__ + +/* interface IPropertyChangeArray */ +/* [unique][object][uuid] */ + + +EXTERN_C const IID IID_IPropertyChangeArray; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("380f5cad-1b5e-42f2-805d-637fd392d31e") + IPropertyChangeArray : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE GetCount( + /* [out] */ __RPC__out UINT *pcOperations) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetAt( + /* [in] */ UINT iIndex, + /* [in] */ __RPC__in REFIID riid, + /* [iid_is][out] */ __RPC__deref_out_opt void **ppv) = 0; + + virtual HRESULT STDMETHODCALLTYPE InsertAt( + /* [in] */ UINT iIndex, + /* [in] */ __RPC__in_opt IPropertyChange *ppropChange) = 0; + + virtual HRESULT STDMETHODCALLTYPE Append( + /* [in] */ __RPC__in_opt IPropertyChange *ppropChange) = 0; + + virtual HRESULT STDMETHODCALLTYPE AppendOrReplace( + /* [in] */ __RPC__in_opt IPropertyChange *ppropChange) = 0; + + virtual HRESULT STDMETHODCALLTYPE RemoveAt( + /* [in] */ UINT iIndex) = 0; + + virtual HRESULT STDMETHODCALLTYPE IsKeyInArray( + /* [in] */ __RPC__in REFPROPERTYKEY key) = 0; + + }; + +#else /* C style interface */ + + typedef struct IPropertyChangeArrayVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IPropertyChangeArray * This, + /* [in] */ __RPC__in REFIID riid, + /* [iid_is][out] */ + __RPC__deref_out void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IPropertyChangeArray * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IPropertyChangeArray * This); + + HRESULT ( STDMETHODCALLTYPE *GetCount )( + IPropertyChangeArray * This, + /* [out] */ __RPC__out UINT *pcOperations); + + HRESULT ( STDMETHODCALLTYPE *GetAt )( + IPropertyChangeArray * This, + /* [in] */ UINT iIndex, + /* [in] */ __RPC__in REFIID riid, + /* [iid_is][out] */ __RPC__deref_out_opt void **ppv); + + HRESULT ( STDMETHODCALLTYPE *InsertAt )( + IPropertyChangeArray * This, + /* [in] */ UINT iIndex, + /* [in] */ __RPC__in_opt IPropertyChange *ppropChange); + + HRESULT ( STDMETHODCALLTYPE *Append )( + IPropertyChangeArray * This, + /* [in] */ __RPC__in_opt IPropertyChange *ppropChange); + + HRESULT ( STDMETHODCALLTYPE *AppendOrReplace )( + IPropertyChangeArray * This, + /* [in] */ __RPC__in_opt IPropertyChange *ppropChange); + + HRESULT ( STDMETHODCALLTYPE *RemoveAt )( + IPropertyChangeArray * This, + /* [in] */ UINT iIndex); + + HRESULT ( STDMETHODCALLTYPE *IsKeyInArray )( + IPropertyChangeArray * This, + /* [in] */ __RPC__in REFPROPERTYKEY key); + + END_INTERFACE + } IPropertyChangeArrayVtbl; + + interface IPropertyChangeArray + { + CONST_VTBL struct IPropertyChangeArrayVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IPropertyChangeArray_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IPropertyChangeArray_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IPropertyChangeArray_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IPropertyChangeArray_GetCount(This,pcOperations) \ + ( (This)->lpVtbl -> GetCount(This,pcOperations) ) + +#define IPropertyChangeArray_GetAt(This,iIndex,riid,ppv) \ + ( (This)->lpVtbl -> GetAt(This,iIndex,riid,ppv) ) + +#define IPropertyChangeArray_InsertAt(This,iIndex,ppropChange) \ + ( (This)->lpVtbl -> InsertAt(This,iIndex,ppropChange) ) + +#define IPropertyChangeArray_Append(This,ppropChange) \ + ( (This)->lpVtbl -> Append(This,ppropChange) ) + +#define IPropertyChangeArray_AppendOrReplace(This,ppropChange) \ + ( (This)->lpVtbl -> AppendOrReplace(This,ppropChange) ) + +#define IPropertyChangeArray_RemoveAt(This,iIndex) \ + ( (This)->lpVtbl -> RemoveAt(This,iIndex) ) + +#define IPropertyChangeArray_IsKeyInArray(This,key) \ + ( (This)->lpVtbl -> IsKeyInArray(This,key) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IPropertyChangeArray_INTERFACE_DEFINED__ */ + + +#ifndef __IPropertyStoreCapabilities_INTERFACE_DEFINED__ +#define __IPropertyStoreCapabilities_INTERFACE_DEFINED__ + +/* interface IPropertyStoreCapabilities */ +/* [unique][object][uuid] */ + + +EXTERN_C const IID IID_IPropertyStoreCapabilities; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("c8e2d566-186e-4d49-bf41-6909ead56acc") + IPropertyStoreCapabilities : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE IsPropertyWritable( + /* [in] */ __RPC__in REFPROPERTYKEY key) = 0; + + }; + +#else /* C style interface */ + + typedef struct IPropertyStoreCapabilitiesVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IPropertyStoreCapabilities * This, + /* [in] */ __RPC__in REFIID riid, + /* [iid_is][out] */ + __RPC__deref_out void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IPropertyStoreCapabilities * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IPropertyStoreCapabilities * This); + + HRESULT ( STDMETHODCALLTYPE *IsPropertyWritable )( + IPropertyStoreCapabilities * This, + /* [in] */ __RPC__in REFPROPERTYKEY key); + + END_INTERFACE + } IPropertyStoreCapabilitiesVtbl; + + interface IPropertyStoreCapabilities + { + CONST_VTBL struct IPropertyStoreCapabilitiesVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IPropertyStoreCapabilities_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IPropertyStoreCapabilities_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IPropertyStoreCapabilities_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IPropertyStoreCapabilities_IsPropertyWritable(This,key) \ + ( (This)->lpVtbl -> IsPropertyWritable(This,key) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IPropertyStoreCapabilities_INTERFACE_DEFINED__ */ + + +#ifndef __IPropertyStoreCache_INTERFACE_DEFINED__ +#define __IPropertyStoreCache_INTERFACE_DEFINED__ + +/* interface IPropertyStoreCache */ +/* [unique][object][uuid] */ + +typedef /* [v1_enum] */ +enum _PSC_STATE + { PSC_NORMAL = 0, + PSC_NOTINSOURCE = 1, + PSC_DIRTY = 2, + PSC_READONLY = 3 + } PSC_STATE; + + +EXTERN_C const IID IID_IPropertyStoreCache; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("3017056d-9a91-4e90-937d-746c72abbf4f") + IPropertyStoreCache : public IPropertyStore + { + public: + virtual HRESULT STDMETHODCALLTYPE GetState( + /* [in] */ __RPC__in REFPROPERTYKEY key, + /* [out] */ __RPC__out PSC_STATE *pstate) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetValueAndState( + /* [in] */ __RPC__in REFPROPERTYKEY key, + /* [out] */ __RPC__out PROPVARIANT *ppropvar, + /* [out] */ __RPC__out PSC_STATE *pstate) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetState( + /* [in] */ __RPC__in REFPROPERTYKEY key, + /* [in] */ PSC_STATE state) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetValueAndState( + /* [in] */ __RPC__in REFPROPERTYKEY key, + /* [unique][in] */ __RPC__in_opt const PROPVARIANT *ppropvar, + /* [in] */ PSC_STATE state) = 0; + + }; + +#else /* C style interface */ + + typedef struct IPropertyStoreCacheVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IPropertyStoreCache * This, + /* [in] */ __RPC__in REFIID riid, + /* [iid_is][out] */ + __RPC__deref_out void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IPropertyStoreCache * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IPropertyStoreCache * This); + + HRESULT ( STDMETHODCALLTYPE *GetCount )( + IPropertyStoreCache * This, + /* [out] */ __RPC__out DWORD *cProps); + + HRESULT ( STDMETHODCALLTYPE *GetAt )( + IPropertyStoreCache * This, + /* [in] */ DWORD iProp, + /* [out] */ __RPC__out PROPERTYKEY *pkey); + + HRESULT ( STDMETHODCALLTYPE *GetValue )( + IPropertyStoreCache * This, + /* [in] */ __RPC__in REFPROPERTYKEY key, + /* [out] */ __RPC__out PROPVARIANT *pv); + + HRESULT ( STDMETHODCALLTYPE *SetValue )( + IPropertyStoreCache * This, + /* [in] */ __RPC__in REFPROPERTYKEY key, + /* [in] */ __RPC__in REFPROPVARIANT propvar); + + HRESULT ( STDMETHODCALLTYPE *Commit )( + IPropertyStoreCache * This); + + HRESULT ( STDMETHODCALLTYPE *GetState )( + IPropertyStoreCache * This, + /* [in] */ __RPC__in REFPROPERTYKEY key, + /* [out] */ __RPC__out PSC_STATE *pstate); + + HRESULT ( STDMETHODCALLTYPE *GetValueAndState )( + IPropertyStoreCache * This, + /* [in] */ __RPC__in REFPROPERTYKEY key, + /* [out] */ __RPC__out PROPVARIANT *ppropvar, + /* [out] */ __RPC__out PSC_STATE *pstate); + + HRESULT ( STDMETHODCALLTYPE *SetState )( + IPropertyStoreCache * This, + /* [in] */ __RPC__in REFPROPERTYKEY key, + /* [in] */ PSC_STATE state); + + HRESULT ( STDMETHODCALLTYPE *SetValueAndState )( + IPropertyStoreCache * This, + /* [in] */ __RPC__in REFPROPERTYKEY key, + /* [unique][in] */ __RPC__in_opt const PROPVARIANT *ppropvar, + /* [in] */ PSC_STATE state); + + END_INTERFACE + } IPropertyStoreCacheVtbl; + + interface IPropertyStoreCache + { + CONST_VTBL struct IPropertyStoreCacheVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IPropertyStoreCache_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IPropertyStoreCache_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IPropertyStoreCache_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IPropertyStoreCache_GetCount(This,cProps) \ + ( (This)->lpVtbl -> GetCount(This,cProps) ) + +#define IPropertyStoreCache_GetAt(This,iProp,pkey) \ + ( (This)->lpVtbl -> GetAt(This,iProp,pkey) ) + +#define IPropertyStoreCache_GetValue(This,key,pv) \ + ( (This)->lpVtbl -> GetValue(This,key,pv) ) + +#define IPropertyStoreCache_SetValue(This,key,propvar) \ + ( (This)->lpVtbl -> SetValue(This,key,propvar) ) + +#define IPropertyStoreCache_Commit(This) \ + ( (This)->lpVtbl -> Commit(This) ) + + +#define IPropertyStoreCache_GetState(This,key,pstate) \ + ( (This)->lpVtbl -> GetState(This,key,pstate) ) + +#define IPropertyStoreCache_GetValueAndState(This,key,ppropvar,pstate) \ + ( (This)->lpVtbl -> GetValueAndState(This,key,ppropvar,pstate) ) + +#define IPropertyStoreCache_SetState(This,key,state) \ + ( (This)->lpVtbl -> SetState(This,key,state) ) + +#define IPropertyStoreCache_SetValueAndState(This,key,ppropvar,state) \ + ( (This)->lpVtbl -> SetValueAndState(This,key,ppropvar,state) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IPropertyStoreCache_INTERFACE_DEFINED__ */ + + +#ifndef __IPropertyEnumType_INTERFACE_DEFINED__ +#define __IPropertyEnumType_INTERFACE_DEFINED__ + +/* interface IPropertyEnumType */ +/* [unique][object][uuid] */ + +/* [v1_enum] */ +enum tagPROPENUMTYPE + { PET_DISCRETEVALUE = 0, + PET_RANGEDVALUE = 1, + PET_DEFAULTVALUE = 2, + PET_ENDRANGE = 3 + } ; +typedef enum tagPROPENUMTYPE PROPENUMTYPE; + + +EXTERN_C const IID IID_IPropertyEnumType; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("11e1fbf9-2d56-4a6b-8db3-7cd193a471f2") + IPropertyEnumType : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE GetEnumType( + /* [out] */ __RPC__out PROPENUMTYPE *penumtype) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetValue( + /* [out] */ __RPC__out PROPVARIANT *ppropvar) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetRangeMinValue( + /* [out] */ __RPC__out PROPVARIANT *ppropvarMin) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetRangeSetValue( + /* [out] */ __RPC__out PROPVARIANT *ppropvarSet) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetDisplayText( + /* [out] */ __RPC__deref_out_opt LPWSTR *ppszDisplay) = 0; + + }; + +#else /* C style interface */ + + typedef struct IPropertyEnumTypeVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IPropertyEnumType * This, + /* [in] */ __RPC__in REFIID riid, + /* [iid_is][out] */ + __RPC__deref_out void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IPropertyEnumType * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IPropertyEnumType * This); + + HRESULT ( STDMETHODCALLTYPE *GetEnumType )( + IPropertyEnumType * This, + /* [out] */ __RPC__out PROPENUMTYPE *penumtype); + + HRESULT ( STDMETHODCALLTYPE *GetValue )( + IPropertyEnumType * This, + /* [out] */ __RPC__out PROPVARIANT *ppropvar); + + HRESULT ( STDMETHODCALLTYPE *GetRangeMinValue )( + IPropertyEnumType * This, + /* [out] */ __RPC__out PROPVARIANT *ppropvarMin); + + HRESULT ( STDMETHODCALLTYPE *GetRangeSetValue )( + IPropertyEnumType * This, + /* [out] */ __RPC__out PROPVARIANT *ppropvarSet); + + HRESULT ( STDMETHODCALLTYPE *GetDisplayText )( + IPropertyEnumType * This, + /* [out] */ __RPC__deref_out_opt LPWSTR *ppszDisplay); + + END_INTERFACE + } IPropertyEnumTypeVtbl; + + interface IPropertyEnumType + { + CONST_VTBL struct IPropertyEnumTypeVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IPropertyEnumType_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IPropertyEnumType_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IPropertyEnumType_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IPropertyEnumType_GetEnumType(This,penumtype) \ + ( (This)->lpVtbl -> GetEnumType(This,penumtype) ) + +#define IPropertyEnumType_GetValue(This,ppropvar) \ + ( (This)->lpVtbl -> GetValue(This,ppropvar) ) + +#define IPropertyEnumType_GetRangeMinValue(This,ppropvarMin) \ + ( (This)->lpVtbl -> GetRangeMinValue(This,ppropvarMin) ) + +#define IPropertyEnumType_GetRangeSetValue(This,ppropvarSet) \ + ( (This)->lpVtbl -> GetRangeSetValue(This,ppropvarSet) ) + +#define IPropertyEnumType_GetDisplayText(This,ppszDisplay) \ + ( (This)->lpVtbl -> GetDisplayText(This,ppszDisplay) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IPropertyEnumType_INTERFACE_DEFINED__ */ + + +#ifndef __IPropertyEnumTypeList_INTERFACE_DEFINED__ +#define __IPropertyEnumTypeList_INTERFACE_DEFINED__ + +/* interface IPropertyEnumTypeList */ +/* [unique][object][uuid] */ + + +EXTERN_C const IID IID_IPropertyEnumTypeList; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("a99400f4-3d84-4557-94ba-1242fb2cc9a6") + IPropertyEnumTypeList : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE GetCount( + /* [out] */ __RPC__out UINT *pctypes) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetAt( + /* [in] */ UINT itype, + /* [in] */ __RPC__in REFIID riid, + /* [iid_is][out] */ __RPC__deref_out_opt void **ppv) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetConditionAt( + /* [in] */ UINT nIndex, + /* [in] */ __RPC__in REFIID riid, + /* [iid_is][out] */ __RPC__deref_out_opt void **ppv) = 0; + + virtual HRESULT STDMETHODCALLTYPE FindMatchingIndex( + /* [in] */ __RPC__in REFPROPVARIANT propvarCmp, + /* [out] */ __RPC__out UINT *pnIndex) = 0; + + }; + +#else /* C style interface */ + + typedef struct IPropertyEnumTypeListVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IPropertyEnumTypeList * This, + /* [in] */ __RPC__in REFIID riid, + /* [iid_is][out] */ + __RPC__deref_out void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IPropertyEnumTypeList * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IPropertyEnumTypeList * This); + + HRESULT ( STDMETHODCALLTYPE *GetCount )( + IPropertyEnumTypeList * This, + /* [out] */ __RPC__out UINT *pctypes); + + HRESULT ( STDMETHODCALLTYPE *GetAt )( + IPropertyEnumTypeList * This, + /* [in] */ UINT itype, + /* [in] */ __RPC__in REFIID riid, + /* [iid_is][out] */ __RPC__deref_out_opt void **ppv); + + HRESULT ( STDMETHODCALLTYPE *GetConditionAt )( + IPropertyEnumTypeList * This, + /* [in] */ UINT nIndex, + /* [in] */ __RPC__in REFIID riid, + /* [iid_is][out] */ __RPC__deref_out_opt void **ppv); + + HRESULT ( STDMETHODCALLTYPE *FindMatchingIndex )( + IPropertyEnumTypeList * This, + /* [in] */ __RPC__in REFPROPVARIANT propvarCmp, + /* [out] */ __RPC__out UINT *pnIndex); + + END_INTERFACE + } IPropertyEnumTypeListVtbl; + + interface IPropertyEnumTypeList + { + CONST_VTBL struct IPropertyEnumTypeListVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IPropertyEnumTypeList_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IPropertyEnumTypeList_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IPropertyEnumTypeList_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IPropertyEnumTypeList_GetCount(This,pctypes) \ + ( (This)->lpVtbl -> GetCount(This,pctypes) ) + +#define IPropertyEnumTypeList_GetAt(This,itype,riid,ppv) \ + ( (This)->lpVtbl -> GetAt(This,itype,riid,ppv) ) + +#define IPropertyEnumTypeList_GetConditionAt(This,nIndex,riid,ppv) \ + ( (This)->lpVtbl -> GetConditionAt(This,nIndex,riid,ppv) ) + +#define IPropertyEnumTypeList_FindMatchingIndex(This,propvarCmp,pnIndex) \ + ( (This)->lpVtbl -> FindMatchingIndex(This,propvarCmp,pnIndex) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IPropertyEnumTypeList_INTERFACE_DEFINED__ */ + + +#ifndef __IPropertyDescription_INTERFACE_DEFINED__ +#define __IPropertyDescription_INTERFACE_DEFINED__ + +/* interface IPropertyDescription */ +/* [unique][object][uuid] */ + +/* [v1_enum] */ +enum tagPROPDESC_TYPE_FLAGS + { PDTF_DEFAULT = 0, + PDTF_MULTIPLEVALUES = 0x1, + PDTF_ISINNATE = 0x2, + PDTF_ISGROUP = 0x4, + PDTF_CANGROUPBY = 0x8, + PDTF_CANSTACKBY = 0x10, + PDTF_ISTREEPROPERTY = 0x20, + PDTF_INCLUDEINFULLTEXTQUERY = 0x40, + PDTF_ISVIEWABLE = 0x80, + PDTF_ISQUERYABLE = 0x100, + PDTF_ISSYSTEMPROPERTY = 0x80000000, + PDTF_MASK_ALL = 0x800001ff + } ; +typedef int PROPDESC_TYPE_FLAGS; + +/* [v1_enum] */ +enum tagPROPDESC_VIEW_FLAGS + { PDVF_DEFAULT = 0, + PDVF_CENTERALIGN = 0x1, + PDVF_RIGHTALIGN = 0x2, + PDVF_BEGINNEWGROUP = 0x4, + PDVF_FILLAREA = 0x8, + PDVF_SORTDESCENDING = 0x10, + PDVF_SHOWONLYIFPRESENT = 0x20, + PDVF_SHOWBYDEFAULT = 0x40, + PDVF_SHOWINPRIMARYLIST = 0x80, + PDVF_SHOWINSECONDARYLIST = 0x100, + PDVF_HIDELABEL = 0x200, + PDVF_HIDDEN = 0x800, + PDVF_CANWRAP = 0x1000, + PDVF_MASK_ALL = 0x1bff + } ; +typedef int PROPDESC_VIEW_FLAGS; + +/* [v1_enum] */ +enum tagPROPDESC_DISPLAYTYPE + { PDDT_STRING = 0, + PDDT_NUMBER = 1, + PDDT_BOOLEAN = 2, + PDDT_DATETIME = 3, + PDDT_ENUMERATED = 4 + } ; +typedef enum tagPROPDESC_DISPLAYTYPE PROPDESC_DISPLAYTYPE; + +/* [v1_enum] */ +enum tagPROPDESC_GROUPING_RANGE + { PDGR_DISCRETE = 0, + PDGR_ALPHANUMERIC = 1, + PDGR_SIZE = 2, + PDGR_DYNAMIC = 3, + PDGR_DATE = 4, + PDGR_PERCENT = 5, + PDGR_ENUMERATED = 6 + } ; +typedef enum tagPROPDESC_GROUPING_RANGE PROPDESC_GROUPING_RANGE; + +/* [v1_enum] */ +enum tagPROPDESC_FORMAT_FLAGS + { PDFF_DEFAULT = 0, + PDFF_PREFIXNAME = 0x1, + PDFF_FILENAME = 0x2, + PDFF_ALWAYSKB = 0x4, + PDFF_RESERVED_RIGHTTOLEFT = 0x8, + PDFF_SHORTTIME = 0x10, + PDFF_LONGTIME = 0x20, + PDFF_HIDETIME = 0x40, + PDFF_SHORTDATE = 0x80, + PDFF_LONGDATE = 0x100, + PDFF_HIDEDATE = 0x200, + PDFF_RELATIVEDATE = 0x400, + PDFF_USEEDITINVITATION = 0x800, + PDFF_READONLY = 0x1000, + PDFF_NOAUTOREADINGORDER = 0x2000 + } ; +typedef int PROPDESC_FORMAT_FLAGS; + +/* [v1_enum] */ +enum tagPROPDESC_SORTDESCRIPTION + { PDSD_GENERAL = 0, + PDSD_A_Z = 1, + PDSD_LOWEST_HIGHEST = 2, + PDSD_SMALLEST_BIGGEST = 3, + PDSD_OLDEST_NEWEST = 4 + } ; +typedef enum tagPROPDESC_SORTDESCRIPTION PROPDESC_SORTDESCRIPTION; + +/* [v1_enum] */ +enum tagPROPDESC_RELATIVEDESCRIPTION_TYPE + { PDRDT_GENERAL = 0, + PDRDT_DATE = 1, + PDRDT_SIZE = 2, + PDRDT_COUNT = 3, + PDRDT_REVISION = 4, + PDRDT_LENGTH = 5, + PDRDT_DURATION = 6, + PDRDT_SPEED = 7, + PDRDT_RATE = 8, + PDRDT_RATING = 9, + PDRDT_PRIORITY = 10 + } ; +typedef enum tagPROPDESC_RELATIVEDESCRIPTION_TYPE PROPDESC_RELATIVEDESCRIPTION_TYPE; + +/* [v1_enum] */ +enum tagPROPDESC_AGGREGATION_TYPE + { PDAT_DEFAULT = 0, + PDAT_FIRST = 1, + PDAT_SUM = 2, + PDAT_AVERAGE = 3, + PDAT_DATERANGE = 4, + PDAT_UNION = 5, + PDAT_MAX = 6, + PDAT_MIN = 7 + } ; +typedef enum tagPROPDESC_AGGREGATION_TYPE PROPDESC_AGGREGATION_TYPE; + +/* [v1_enum] */ +enum tagPROPDESC_CONDITION_TYPE + { PDCOT_NONE = 0, + PDCOT_STRING = 1, + PDCOT_SIZE = 2, + PDCOT_DATETIME = 3, + PDCOT_BOOLEAN = 4, + PDCOT_NUMBER = 5 + } ; +typedef enum tagPROPDESC_CONDITION_TYPE PROPDESC_CONDITION_TYPE; + + +EXTERN_C const IID IID_IPropertyDescription; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("6f79d558-3e96-4549-a1d1-7d75d2288814") + IPropertyDescription : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE GetPropertyKey( + /* [out] */ __RPC__out PROPERTYKEY *pkey) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetCanonicalName( + /* [string][out] */ __RPC__deref_out_opt_string LPWSTR *ppszName) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetPropertyType( + /* [out] */ __RPC__out VARTYPE *pvartype) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetDisplayName( + /* [string][out] */ __RPC__deref_out_opt_string LPWSTR *ppszName) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetEditInvitation( + /* [string][out] */ __RPC__deref_out_opt_string LPWSTR *ppszInvite) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetTypeFlags( + /* [in] */ PROPDESC_TYPE_FLAGS mask, + /* [out] */ __RPC__out PROPDESC_TYPE_FLAGS *ppdtFlags) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetViewFlags( + /* [out] */ __RPC__out PROPDESC_VIEW_FLAGS *ppdvFlags) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetDefaultColumnWidth( + /* [out] */ __RPC__out UINT *pcxChars) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetDisplayType( + /* [out] */ __RPC__out PROPDESC_DISPLAYTYPE *pdisplaytype) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetColumnState( + /* [out] */ __RPC__out SHCOLSTATEF *pcsFlags) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetGroupingRange( + /* [out] */ __RPC__out PROPDESC_GROUPING_RANGE *pgr) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetRelativeDescriptionType( + /* [out] */ __RPC__out PROPDESC_RELATIVEDESCRIPTION_TYPE *prdt) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetRelativeDescription( + /* [in] */ __RPC__in REFPROPVARIANT propvar1, + /* [in] */ __RPC__in REFPROPVARIANT propvar2, + /* [string][out] */ __RPC__deref_out_opt_string LPWSTR *ppszDesc1, + /* [string][out] */ __RPC__deref_out_opt_string LPWSTR *ppszDesc2) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetSortDescription( + /* [out] */ __RPC__out PROPDESC_SORTDESCRIPTION *psd) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetSortDescriptionLabel( + /* [in] */ BOOL fDescending, + /* [string][out] */ __RPC__deref_out_opt_string LPWSTR *ppszDescription) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetAggregationType( + /* [out] */ __RPC__out PROPDESC_AGGREGATION_TYPE *paggtype) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetConditionType( + /* [out] */ __RPC__out PROPDESC_CONDITION_TYPE *pcontype, + /* [out] */ __RPC__out CONDITION_OPERATION *popDefault) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetEnumTypeList( + /* [in] */ __RPC__in REFIID riid, + /* [iid_is][out] */ __RPC__deref_out_opt void **ppv) = 0; + + virtual /* [local] */ HRESULT STDMETHODCALLTYPE CoerceToCanonicalValue( + /* [out][in] */ PROPVARIANT *ppropvar) = 0; + + virtual HRESULT STDMETHODCALLTYPE FormatForDisplay( + /* [in] */ __RPC__in REFPROPVARIANT propvar, + /* [in] */ PROPDESC_FORMAT_FLAGS pdfFlags, + /* [string][out] */ __RPC__deref_out_opt_string LPWSTR *ppszDisplay) = 0; + + virtual HRESULT STDMETHODCALLTYPE IsValueCanonical( + /* [in] */ __RPC__in REFPROPVARIANT propvar) = 0; + + }; + +#else /* C style interface */ + + typedef struct IPropertyDescriptionVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IPropertyDescription * This, + /* [in] */ __RPC__in REFIID riid, + /* [iid_is][out] */ + __RPC__deref_out void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IPropertyDescription * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IPropertyDescription * This); + + HRESULT ( STDMETHODCALLTYPE *GetPropertyKey )( + IPropertyDescription * This, + /* [out] */ __RPC__out PROPERTYKEY *pkey); + + HRESULT ( STDMETHODCALLTYPE *GetCanonicalName )( + IPropertyDescription * This, + /* [string][out] */ __RPC__deref_out_opt_string LPWSTR *ppszName); + + HRESULT ( STDMETHODCALLTYPE *GetPropertyType )( + IPropertyDescription * This, + /* [out] */ __RPC__out VARTYPE *pvartype); + + HRESULT ( STDMETHODCALLTYPE *GetDisplayName )( + IPropertyDescription * This, + /* [string][out] */ __RPC__deref_out_opt_string LPWSTR *ppszName); + + HRESULT ( STDMETHODCALLTYPE *GetEditInvitation )( + IPropertyDescription * This, + /* [string][out] */ __RPC__deref_out_opt_string LPWSTR *ppszInvite); + + HRESULT ( STDMETHODCALLTYPE *GetTypeFlags )( + IPropertyDescription * This, + /* [in] */ PROPDESC_TYPE_FLAGS mask, + /* [out] */ __RPC__out PROPDESC_TYPE_FLAGS *ppdtFlags); + + HRESULT ( STDMETHODCALLTYPE *GetViewFlags )( + IPropertyDescription * This, + /* [out] */ __RPC__out PROPDESC_VIEW_FLAGS *ppdvFlags); + + HRESULT ( STDMETHODCALLTYPE *GetDefaultColumnWidth )( + IPropertyDescription * This, + /* [out] */ __RPC__out UINT *pcxChars); + + HRESULT ( STDMETHODCALLTYPE *GetDisplayType )( + IPropertyDescription * This, + /* [out] */ __RPC__out PROPDESC_DISPLAYTYPE *pdisplaytype); + + HRESULT ( STDMETHODCALLTYPE *GetColumnState )( + IPropertyDescription * This, + /* [out] */ __RPC__out SHCOLSTATEF *pcsFlags); + + HRESULT ( STDMETHODCALLTYPE *GetGroupingRange )( + IPropertyDescription * This, + /* [out] */ __RPC__out PROPDESC_GROUPING_RANGE *pgr); + + HRESULT ( STDMETHODCALLTYPE *GetRelativeDescriptionType )( + IPropertyDescription * This, + /* [out] */ __RPC__out PROPDESC_RELATIVEDESCRIPTION_TYPE *prdt); + + HRESULT ( STDMETHODCALLTYPE *GetRelativeDescription )( + IPropertyDescription * This, + /* [in] */ __RPC__in REFPROPVARIANT propvar1, + /* [in] */ __RPC__in REFPROPVARIANT propvar2, + /* [string][out] */ __RPC__deref_out_opt_string LPWSTR *ppszDesc1, + /* [string][out] */ __RPC__deref_out_opt_string LPWSTR *ppszDesc2); + + HRESULT ( STDMETHODCALLTYPE *GetSortDescription )( + IPropertyDescription * This, + /* [out] */ __RPC__out PROPDESC_SORTDESCRIPTION *psd); + + HRESULT ( STDMETHODCALLTYPE *GetSortDescriptionLabel )( + IPropertyDescription * This, + /* [in] */ BOOL fDescending, + /* [string][out] */ __RPC__deref_out_opt_string LPWSTR *ppszDescription); + + HRESULT ( STDMETHODCALLTYPE *GetAggregationType )( + IPropertyDescription * This, + /* [out] */ __RPC__out PROPDESC_AGGREGATION_TYPE *paggtype); + + HRESULT ( STDMETHODCALLTYPE *GetConditionType )( + IPropertyDescription * This, + /* [out] */ __RPC__out PROPDESC_CONDITION_TYPE *pcontype, + /* [out] */ __RPC__out CONDITION_OPERATION *popDefault); + + HRESULT ( STDMETHODCALLTYPE *GetEnumTypeList )( + IPropertyDescription * This, + /* [in] */ __RPC__in REFIID riid, + /* [iid_is][out] */ __RPC__deref_out_opt void **ppv); + + /* [local] */ HRESULT ( STDMETHODCALLTYPE *CoerceToCanonicalValue )( + IPropertyDescription * This, + /* [out][in] */ PROPVARIANT *ppropvar); + + HRESULT ( STDMETHODCALLTYPE *FormatForDisplay )( + IPropertyDescription * This, + /* [in] */ __RPC__in REFPROPVARIANT propvar, + /* [in] */ PROPDESC_FORMAT_FLAGS pdfFlags, + /* [string][out] */ __RPC__deref_out_opt_string LPWSTR *ppszDisplay); + + HRESULT ( STDMETHODCALLTYPE *IsValueCanonical )( + IPropertyDescription * This, + /* [in] */ __RPC__in REFPROPVARIANT propvar); + + END_INTERFACE + } IPropertyDescriptionVtbl; + + interface IPropertyDescription + { + CONST_VTBL struct IPropertyDescriptionVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IPropertyDescription_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IPropertyDescription_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IPropertyDescription_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IPropertyDescription_GetPropertyKey(This,pkey) \ + ( (This)->lpVtbl -> GetPropertyKey(This,pkey) ) + +#define IPropertyDescription_GetCanonicalName(This,ppszName) \ + ( (This)->lpVtbl -> GetCanonicalName(This,ppszName) ) + +#define IPropertyDescription_GetPropertyType(This,pvartype) \ + ( (This)->lpVtbl -> GetPropertyType(This,pvartype) ) + +#define IPropertyDescription_GetDisplayName(This,ppszName) \ + ( (This)->lpVtbl -> GetDisplayName(This,ppszName) ) + +#define IPropertyDescription_GetEditInvitation(This,ppszInvite) \ + ( (This)->lpVtbl -> GetEditInvitation(This,ppszInvite) ) + +#define IPropertyDescription_GetTypeFlags(This,mask,ppdtFlags) \ + ( (This)->lpVtbl -> GetTypeFlags(This,mask,ppdtFlags) ) + +#define IPropertyDescription_GetViewFlags(This,ppdvFlags) \ + ( (This)->lpVtbl -> GetViewFlags(This,ppdvFlags) ) + +#define IPropertyDescription_GetDefaultColumnWidth(This,pcxChars) \ + ( (This)->lpVtbl -> GetDefaultColumnWidth(This,pcxChars) ) + +#define IPropertyDescription_GetDisplayType(This,pdisplaytype) \ + ( (This)->lpVtbl -> GetDisplayType(This,pdisplaytype) ) + +#define IPropertyDescription_GetColumnState(This,pcsFlags) \ + ( (This)->lpVtbl -> GetColumnState(This,pcsFlags) ) + +#define IPropertyDescription_GetGroupingRange(This,pgr) \ + ( (This)->lpVtbl -> GetGroupingRange(This,pgr) ) + +#define IPropertyDescription_GetRelativeDescriptionType(This,prdt) \ + ( (This)->lpVtbl -> GetRelativeDescriptionType(This,prdt) ) + +#define IPropertyDescription_GetRelativeDescription(This,propvar1,propvar2,ppszDesc1,ppszDesc2) \ + ( (This)->lpVtbl -> GetRelativeDescription(This,propvar1,propvar2,ppszDesc1,ppszDesc2) ) + +#define IPropertyDescription_GetSortDescription(This,psd) \ + ( (This)->lpVtbl -> GetSortDescription(This,psd) ) + +#define IPropertyDescription_GetSortDescriptionLabel(This,fDescending,ppszDescription) \ + ( (This)->lpVtbl -> GetSortDescriptionLabel(This,fDescending,ppszDescription) ) + +#define IPropertyDescription_GetAggregationType(This,paggtype) \ + ( (This)->lpVtbl -> GetAggregationType(This,paggtype) ) + +#define IPropertyDescription_GetConditionType(This,pcontype,popDefault) \ + ( (This)->lpVtbl -> GetConditionType(This,pcontype,popDefault) ) + +#define IPropertyDescription_GetEnumTypeList(This,riid,ppv) \ + ( (This)->lpVtbl -> GetEnumTypeList(This,riid,ppv) ) + +#define IPropertyDescription_CoerceToCanonicalValue(This,ppropvar) \ + ( (This)->lpVtbl -> CoerceToCanonicalValue(This,ppropvar) ) + +#define IPropertyDescription_FormatForDisplay(This,propvar,pdfFlags,ppszDisplay) \ + ( (This)->lpVtbl -> FormatForDisplay(This,propvar,pdfFlags,ppszDisplay) ) + +#define IPropertyDescription_IsValueCanonical(This,propvar) \ + ( (This)->lpVtbl -> IsValueCanonical(This,propvar) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + +/* [call_as] */ HRESULT STDMETHODCALLTYPE IPropertyDescription_RemoteCoerceToCanonicalValue_Proxy( + IPropertyDescription * This, + /* [in] */ __RPC__in REFPROPVARIANT propvar, + /* [out] */ __RPC__out PROPVARIANT *ppropvar); + + +void __RPC_STUB IPropertyDescription_RemoteCoerceToCanonicalValue_Stub( + IRpcStubBuffer *This, + IRpcChannelBuffer *_pRpcChannelBuffer, + PRPC_MESSAGE _pRpcMessage, + DWORD *_pdwStubPhase); + + + +#endif /* __IPropertyDescription_INTERFACE_DEFINED__ */ + + +#ifndef __IPropertyDescriptionAliasInfo_INTERFACE_DEFINED__ +#define __IPropertyDescriptionAliasInfo_INTERFACE_DEFINED__ + +/* interface IPropertyDescriptionAliasInfo */ +/* [unique][object][uuid] */ + + +EXTERN_C const IID IID_IPropertyDescriptionAliasInfo; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("f67104fc-2af9-46fd-b32d-243c1404f3d1") + IPropertyDescriptionAliasInfo : public IPropertyDescription + { + public: + virtual HRESULT STDMETHODCALLTYPE GetSortByAlias( + /* [in] */ __RPC__in REFIID riid, + /* [iid_is][out] */ __RPC__deref_out_opt void **ppv) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetAdditionalSortByAliases( + /* [in] */ __RPC__in REFIID riid, + /* [iid_is][out] */ __RPC__deref_out_opt void **ppv) = 0; + + }; + +#else /* C style interface */ + + typedef struct IPropertyDescriptionAliasInfoVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IPropertyDescriptionAliasInfo * This, + /* [in] */ __RPC__in REFIID riid, + /* [iid_is][out] */ + __RPC__deref_out void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IPropertyDescriptionAliasInfo * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IPropertyDescriptionAliasInfo * This); + + HRESULT ( STDMETHODCALLTYPE *GetPropertyKey )( + IPropertyDescriptionAliasInfo * This, + /* [out] */ __RPC__out PROPERTYKEY *pkey); + + HRESULT ( STDMETHODCALLTYPE *GetCanonicalName )( + IPropertyDescriptionAliasInfo * This, + /* [string][out] */ __RPC__deref_out_opt_string LPWSTR *ppszName); + + HRESULT ( STDMETHODCALLTYPE *GetPropertyType )( + IPropertyDescriptionAliasInfo * This, + /* [out] */ __RPC__out VARTYPE *pvartype); + + HRESULT ( STDMETHODCALLTYPE *GetDisplayName )( + IPropertyDescriptionAliasInfo * This, + /* [string][out] */ __RPC__deref_out_opt_string LPWSTR *ppszName); + + HRESULT ( STDMETHODCALLTYPE *GetEditInvitation )( + IPropertyDescriptionAliasInfo * This, + /* [string][out] */ __RPC__deref_out_opt_string LPWSTR *ppszInvite); + + HRESULT ( STDMETHODCALLTYPE *GetTypeFlags )( + IPropertyDescriptionAliasInfo * This, + /* [in] */ PROPDESC_TYPE_FLAGS mask, + /* [out] */ __RPC__out PROPDESC_TYPE_FLAGS *ppdtFlags); + + HRESULT ( STDMETHODCALLTYPE *GetViewFlags )( + IPropertyDescriptionAliasInfo * This, + /* [out] */ __RPC__out PROPDESC_VIEW_FLAGS *ppdvFlags); + + HRESULT ( STDMETHODCALLTYPE *GetDefaultColumnWidth )( + IPropertyDescriptionAliasInfo * This, + /* [out] */ __RPC__out UINT *pcxChars); + + HRESULT ( STDMETHODCALLTYPE *GetDisplayType )( + IPropertyDescriptionAliasInfo * This, + /* [out] */ __RPC__out PROPDESC_DISPLAYTYPE *pdisplaytype); + + HRESULT ( STDMETHODCALLTYPE *GetColumnState )( + IPropertyDescriptionAliasInfo * This, + /* [out] */ __RPC__out SHCOLSTATEF *pcsFlags); + + HRESULT ( STDMETHODCALLTYPE *GetGroupingRange )( + IPropertyDescriptionAliasInfo * This, + /* [out] */ __RPC__out PROPDESC_GROUPING_RANGE *pgr); + + HRESULT ( STDMETHODCALLTYPE *GetRelativeDescriptionType )( + IPropertyDescriptionAliasInfo * This, + /* [out] */ __RPC__out PROPDESC_RELATIVEDESCRIPTION_TYPE *prdt); + + HRESULT ( STDMETHODCALLTYPE *GetRelativeDescription )( + IPropertyDescriptionAliasInfo * This, + /* [in] */ __RPC__in REFPROPVARIANT propvar1, + /* [in] */ __RPC__in REFPROPVARIANT propvar2, + /* [string][out] */ __RPC__deref_out_opt_string LPWSTR *ppszDesc1, + /* [string][out] */ __RPC__deref_out_opt_string LPWSTR *ppszDesc2); + + HRESULT ( STDMETHODCALLTYPE *GetSortDescription )( + IPropertyDescriptionAliasInfo * This, + /* [out] */ __RPC__out PROPDESC_SORTDESCRIPTION *psd); + + HRESULT ( STDMETHODCALLTYPE *GetSortDescriptionLabel )( + IPropertyDescriptionAliasInfo * This, + /* [in] */ BOOL fDescending, + /* [string][out] */ __RPC__deref_out_opt_string LPWSTR *ppszDescription); + + HRESULT ( STDMETHODCALLTYPE *GetAggregationType )( + IPropertyDescriptionAliasInfo * This, + /* [out] */ __RPC__out PROPDESC_AGGREGATION_TYPE *paggtype); + + HRESULT ( STDMETHODCALLTYPE *GetConditionType )( + IPropertyDescriptionAliasInfo * This, + /* [out] */ __RPC__out PROPDESC_CONDITION_TYPE *pcontype, + /* [out] */ __RPC__out CONDITION_OPERATION *popDefault); + + HRESULT ( STDMETHODCALLTYPE *GetEnumTypeList )( + IPropertyDescriptionAliasInfo * This, + /* [in] */ __RPC__in REFIID riid, + /* [iid_is][out] */ __RPC__deref_out_opt void **ppv); + + /* [local] */ HRESULT ( STDMETHODCALLTYPE *CoerceToCanonicalValue )( + IPropertyDescriptionAliasInfo * This, + /* [out][in] */ PROPVARIANT *ppropvar); + + HRESULT ( STDMETHODCALLTYPE *FormatForDisplay )( + IPropertyDescriptionAliasInfo * This, + /* [in] */ __RPC__in REFPROPVARIANT propvar, + /* [in] */ PROPDESC_FORMAT_FLAGS pdfFlags, + /* [string][out] */ __RPC__deref_out_opt_string LPWSTR *ppszDisplay); + + HRESULT ( STDMETHODCALLTYPE *IsValueCanonical )( + IPropertyDescriptionAliasInfo * This, + /* [in] */ __RPC__in REFPROPVARIANT propvar); + + HRESULT ( STDMETHODCALLTYPE *GetSortByAlias )( + IPropertyDescriptionAliasInfo * This, + /* [in] */ __RPC__in REFIID riid, + /* [iid_is][out] */ __RPC__deref_out_opt void **ppv); + + HRESULT ( STDMETHODCALLTYPE *GetAdditionalSortByAliases )( + IPropertyDescriptionAliasInfo * This, + /* [in] */ __RPC__in REFIID riid, + /* [iid_is][out] */ __RPC__deref_out_opt void **ppv); + + END_INTERFACE + } IPropertyDescriptionAliasInfoVtbl; + + interface IPropertyDescriptionAliasInfo + { + CONST_VTBL struct IPropertyDescriptionAliasInfoVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IPropertyDescriptionAliasInfo_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IPropertyDescriptionAliasInfo_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IPropertyDescriptionAliasInfo_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IPropertyDescriptionAliasInfo_GetPropertyKey(This,pkey) \ + ( (This)->lpVtbl -> GetPropertyKey(This,pkey) ) + +#define IPropertyDescriptionAliasInfo_GetCanonicalName(This,ppszName) \ + ( (This)->lpVtbl -> GetCanonicalName(This,ppszName) ) + +#define IPropertyDescriptionAliasInfo_GetPropertyType(This,pvartype) \ + ( (This)->lpVtbl -> GetPropertyType(This,pvartype) ) + +#define IPropertyDescriptionAliasInfo_GetDisplayName(This,ppszName) \ + ( (This)->lpVtbl -> GetDisplayName(This,ppszName) ) + +#define IPropertyDescriptionAliasInfo_GetEditInvitation(This,ppszInvite) \ + ( (This)->lpVtbl -> GetEditInvitation(This,ppszInvite) ) + +#define IPropertyDescriptionAliasInfo_GetTypeFlags(This,mask,ppdtFlags) \ + ( (This)->lpVtbl -> GetTypeFlags(This,mask,ppdtFlags) ) + +#define IPropertyDescriptionAliasInfo_GetViewFlags(This,ppdvFlags) \ + ( (This)->lpVtbl -> GetViewFlags(This,ppdvFlags) ) + +#define IPropertyDescriptionAliasInfo_GetDefaultColumnWidth(This,pcxChars) \ + ( (This)->lpVtbl -> GetDefaultColumnWidth(This,pcxChars) ) + +#define IPropertyDescriptionAliasInfo_GetDisplayType(This,pdisplaytype) \ + ( (This)->lpVtbl -> GetDisplayType(This,pdisplaytype) ) + +#define IPropertyDescriptionAliasInfo_GetColumnState(This,pcsFlags) \ + ( (This)->lpVtbl -> GetColumnState(This,pcsFlags) ) + +#define IPropertyDescriptionAliasInfo_GetGroupingRange(This,pgr) \ + ( (This)->lpVtbl -> GetGroupingRange(This,pgr) ) + +#define IPropertyDescriptionAliasInfo_GetRelativeDescriptionType(This,prdt) \ + ( (This)->lpVtbl -> GetRelativeDescriptionType(This,prdt) ) + +#define IPropertyDescriptionAliasInfo_GetRelativeDescription(This,propvar1,propvar2,ppszDesc1,ppszDesc2) \ + ( (This)->lpVtbl -> GetRelativeDescription(This,propvar1,propvar2,ppszDesc1,ppszDesc2) ) + +#define IPropertyDescriptionAliasInfo_GetSortDescription(This,psd) \ + ( (This)->lpVtbl -> GetSortDescription(This,psd) ) + +#define IPropertyDescriptionAliasInfo_GetSortDescriptionLabel(This,fDescending,ppszDescription) \ + ( (This)->lpVtbl -> GetSortDescriptionLabel(This,fDescending,ppszDescription) ) + +#define IPropertyDescriptionAliasInfo_GetAggregationType(This,paggtype) \ + ( (This)->lpVtbl -> GetAggregationType(This,paggtype) ) + +#define IPropertyDescriptionAliasInfo_GetConditionType(This,pcontype,popDefault) \ + ( (This)->lpVtbl -> GetConditionType(This,pcontype,popDefault) ) + +#define IPropertyDescriptionAliasInfo_GetEnumTypeList(This,riid,ppv) \ + ( (This)->lpVtbl -> GetEnumTypeList(This,riid,ppv) ) + +#define IPropertyDescriptionAliasInfo_CoerceToCanonicalValue(This,ppropvar) \ + ( (This)->lpVtbl -> CoerceToCanonicalValue(This,ppropvar) ) + +#define IPropertyDescriptionAliasInfo_FormatForDisplay(This,propvar,pdfFlags,ppszDisplay) \ + ( (This)->lpVtbl -> FormatForDisplay(This,propvar,pdfFlags,ppszDisplay) ) + +#define IPropertyDescriptionAliasInfo_IsValueCanonical(This,propvar) \ + ( (This)->lpVtbl -> IsValueCanonical(This,propvar) ) + + +#define IPropertyDescriptionAliasInfo_GetSortByAlias(This,riid,ppv) \ + ( (This)->lpVtbl -> GetSortByAlias(This,riid,ppv) ) + +#define IPropertyDescriptionAliasInfo_GetAdditionalSortByAliases(This,riid,ppv) \ + ( (This)->lpVtbl -> GetAdditionalSortByAliases(This,riid,ppv) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IPropertyDescriptionAliasInfo_INTERFACE_DEFINED__ */ + + +#ifndef __IPropertyDescriptionSearchInfo_INTERFACE_DEFINED__ +#define __IPropertyDescriptionSearchInfo_INTERFACE_DEFINED__ + +/* interface IPropertyDescriptionSearchInfo */ +/* [unique][object][uuid] */ + +/* [v1_enum] */ +enum tagPROPDESC_SEARCHINFO_FLAGS + { PDSIF_DEFAULT = 0, + PDSIF_ININVERTEDINDEX = 0x1, + PDSIF_ISCOLUMN = 0x2, + PDSIF_ISCOLUMNSPARSE = 0x4 + } ; +typedef int PROPDESC_SEARCHINFO_FLAGS; + +typedef /* [v1_enum] */ +enum tagPROPDESC_COLUMNINDEX_TYPE + { PDCIT_NONE = 0, + PDCIT_ONDISK = 1, + PDCIT_INMEMORY = 2 + } PROPDESC_COLUMNINDEX_TYPE; + + +EXTERN_C const IID IID_IPropertyDescriptionSearchInfo; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("078f91bd-29a2-440f-924e-46a291524520") + IPropertyDescriptionSearchInfo : public IPropertyDescription + { + public: + virtual HRESULT STDMETHODCALLTYPE GetSearchInfoFlags( + /* [out] */ __RPC__out PROPDESC_SEARCHINFO_FLAGS *ppdsiFlags) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetColumnIndexType( + /* [out] */ __RPC__out PROPDESC_COLUMNINDEX_TYPE *ppdciType) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetProjectionString( + /* [out] */ __RPC__deref_out_opt LPWSTR *ppszProjection) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetMaxSize( + /* [out] */ __RPC__out UINT *pcbMaxSize) = 0; + + }; + +#else /* C style interface */ + + typedef struct IPropertyDescriptionSearchInfoVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IPropertyDescriptionSearchInfo * This, + /* [in] */ __RPC__in REFIID riid, + /* [iid_is][out] */ + __RPC__deref_out void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IPropertyDescriptionSearchInfo * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IPropertyDescriptionSearchInfo * This); + + HRESULT ( STDMETHODCALLTYPE *GetPropertyKey )( + IPropertyDescriptionSearchInfo * This, + /* [out] */ __RPC__out PROPERTYKEY *pkey); + + HRESULT ( STDMETHODCALLTYPE *GetCanonicalName )( + IPropertyDescriptionSearchInfo * This, + /* [string][out] */ __RPC__deref_out_opt_string LPWSTR *ppszName); + + HRESULT ( STDMETHODCALLTYPE *GetPropertyType )( + IPropertyDescriptionSearchInfo * This, + /* [out] */ __RPC__out VARTYPE *pvartype); + + HRESULT ( STDMETHODCALLTYPE *GetDisplayName )( + IPropertyDescriptionSearchInfo * This, + /* [string][out] */ __RPC__deref_out_opt_string LPWSTR *ppszName); + + HRESULT ( STDMETHODCALLTYPE *GetEditInvitation )( + IPropertyDescriptionSearchInfo * This, + /* [string][out] */ __RPC__deref_out_opt_string LPWSTR *ppszInvite); + + HRESULT ( STDMETHODCALLTYPE *GetTypeFlags )( + IPropertyDescriptionSearchInfo * This, + /* [in] */ PROPDESC_TYPE_FLAGS mask, + /* [out] */ __RPC__out PROPDESC_TYPE_FLAGS *ppdtFlags); + + HRESULT ( STDMETHODCALLTYPE *GetViewFlags )( + IPropertyDescriptionSearchInfo * This, + /* [out] */ __RPC__out PROPDESC_VIEW_FLAGS *ppdvFlags); + + HRESULT ( STDMETHODCALLTYPE *GetDefaultColumnWidth )( + IPropertyDescriptionSearchInfo * This, + /* [out] */ __RPC__out UINT *pcxChars); + + HRESULT ( STDMETHODCALLTYPE *GetDisplayType )( + IPropertyDescriptionSearchInfo * This, + /* [out] */ __RPC__out PROPDESC_DISPLAYTYPE *pdisplaytype); + + HRESULT ( STDMETHODCALLTYPE *GetColumnState )( + IPropertyDescriptionSearchInfo * This, + /* [out] */ __RPC__out SHCOLSTATEF *pcsFlags); + + HRESULT ( STDMETHODCALLTYPE *GetGroupingRange )( + IPropertyDescriptionSearchInfo * This, + /* [out] */ __RPC__out PROPDESC_GROUPING_RANGE *pgr); + + HRESULT ( STDMETHODCALLTYPE *GetRelativeDescriptionType )( + IPropertyDescriptionSearchInfo * This, + /* [out] */ __RPC__out PROPDESC_RELATIVEDESCRIPTION_TYPE *prdt); + + HRESULT ( STDMETHODCALLTYPE *GetRelativeDescription )( + IPropertyDescriptionSearchInfo * This, + /* [in] */ __RPC__in REFPROPVARIANT propvar1, + /* [in] */ __RPC__in REFPROPVARIANT propvar2, + /* [string][out] */ __RPC__deref_out_opt_string LPWSTR *ppszDesc1, + /* [string][out] */ __RPC__deref_out_opt_string LPWSTR *ppszDesc2); + + HRESULT ( STDMETHODCALLTYPE *GetSortDescription )( + IPropertyDescriptionSearchInfo * This, + /* [out] */ __RPC__out PROPDESC_SORTDESCRIPTION *psd); + + HRESULT ( STDMETHODCALLTYPE *GetSortDescriptionLabel )( + IPropertyDescriptionSearchInfo * This, + /* [in] */ BOOL fDescending, + /* [string][out] */ __RPC__deref_out_opt_string LPWSTR *ppszDescription); + + HRESULT ( STDMETHODCALLTYPE *GetAggregationType )( + IPropertyDescriptionSearchInfo * This, + /* [out] */ __RPC__out PROPDESC_AGGREGATION_TYPE *paggtype); + + HRESULT ( STDMETHODCALLTYPE *GetConditionType )( + IPropertyDescriptionSearchInfo * This, + /* [out] */ __RPC__out PROPDESC_CONDITION_TYPE *pcontype, + /* [out] */ __RPC__out CONDITION_OPERATION *popDefault); + + HRESULT ( STDMETHODCALLTYPE *GetEnumTypeList )( + IPropertyDescriptionSearchInfo * This, + /* [in] */ __RPC__in REFIID riid, + /* [iid_is][out] */ __RPC__deref_out_opt void **ppv); + + /* [local] */ HRESULT ( STDMETHODCALLTYPE *CoerceToCanonicalValue )( + IPropertyDescriptionSearchInfo * This, + /* [out][in] */ PROPVARIANT *ppropvar); + + HRESULT ( STDMETHODCALLTYPE *FormatForDisplay )( + IPropertyDescriptionSearchInfo * This, + /* [in] */ __RPC__in REFPROPVARIANT propvar, + /* [in] */ PROPDESC_FORMAT_FLAGS pdfFlags, + /* [string][out] */ __RPC__deref_out_opt_string LPWSTR *ppszDisplay); + + HRESULT ( STDMETHODCALLTYPE *IsValueCanonical )( + IPropertyDescriptionSearchInfo * This, + /* [in] */ __RPC__in REFPROPVARIANT propvar); + + HRESULT ( STDMETHODCALLTYPE *GetSearchInfoFlags )( + IPropertyDescriptionSearchInfo * This, + /* [out] */ __RPC__out PROPDESC_SEARCHINFO_FLAGS *ppdsiFlags); + + HRESULT ( STDMETHODCALLTYPE *GetColumnIndexType )( + IPropertyDescriptionSearchInfo * This, + /* [out] */ __RPC__out PROPDESC_COLUMNINDEX_TYPE *ppdciType); + + HRESULT ( STDMETHODCALLTYPE *GetProjectionString )( + IPropertyDescriptionSearchInfo * This, + /* [out] */ __RPC__deref_out_opt LPWSTR *ppszProjection); + + HRESULT ( STDMETHODCALLTYPE *GetMaxSize )( + IPropertyDescriptionSearchInfo * This, + /* [out] */ __RPC__out UINT *pcbMaxSize); + + END_INTERFACE + } IPropertyDescriptionSearchInfoVtbl; + + interface IPropertyDescriptionSearchInfo + { + CONST_VTBL struct IPropertyDescriptionSearchInfoVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IPropertyDescriptionSearchInfo_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IPropertyDescriptionSearchInfo_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IPropertyDescriptionSearchInfo_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IPropertyDescriptionSearchInfo_GetPropertyKey(This,pkey) \ + ( (This)->lpVtbl -> GetPropertyKey(This,pkey) ) + +#define IPropertyDescriptionSearchInfo_GetCanonicalName(This,ppszName) \ + ( (This)->lpVtbl -> GetCanonicalName(This,ppszName) ) + +#define IPropertyDescriptionSearchInfo_GetPropertyType(This,pvartype) \ + ( (This)->lpVtbl -> GetPropertyType(This,pvartype) ) + +#define IPropertyDescriptionSearchInfo_GetDisplayName(This,ppszName) \ + ( (This)->lpVtbl -> GetDisplayName(This,ppszName) ) + +#define IPropertyDescriptionSearchInfo_GetEditInvitation(This,ppszInvite) \ + ( (This)->lpVtbl -> GetEditInvitation(This,ppszInvite) ) + +#define IPropertyDescriptionSearchInfo_GetTypeFlags(This,mask,ppdtFlags) \ + ( (This)->lpVtbl -> GetTypeFlags(This,mask,ppdtFlags) ) + +#define IPropertyDescriptionSearchInfo_GetViewFlags(This,ppdvFlags) \ + ( (This)->lpVtbl -> GetViewFlags(This,ppdvFlags) ) + +#define IPropertyDescriptionSearchInfo_GetDefaultColumnWidth(This,pcxChars) \ + ( (This)->lpVtbl -> GetDefaultColumnWidth(This,pcxChars) ) + +#define IPropertyDescriptionSearchInfo_GetDisplayType(This,pdisplaytype) \ + ( (This)->lpVtbl -> GetDisplayType(This,pdisplaytype) ) + +#define IPropertyDescriptionSearchInfo_GetColumnState(This,pcsFlags) \ + ( (This)->lpVtbl -> GetColumnState(This,pcsFlags) ) + +#define IPropertyDescriptionSearchInfo_GetGroupingRange(This,pgr) \ + ( (This)->lpVtbl -> GetGroupingRange(This,pgr) ) + +#define IPropertyDescriptionSearchInfo_GetRelativeDescriptionType(This,prdt) \ + ( (This)->lpVtbl -> GetRelativeDescriptionType(This,prdt) ) + +#define IPropertyDescriptionSearchInfo_GetRelativeDescription(This,propvar1,propvar2,ppszDesc1,ppszDesc2) \ + ( (This)->lpVtbl -> GetRelativeDescription(This,propvar1,propvar2,ppszDesc1,ppszDesc2) ) + +#define IPropertyDescriptionSearchInfo_GetSortDescription(This,psd) \ + ( (This)->lpVtbl -> GetSortDescription(This,psd) ) + +#define IPropertyDescriptionSearchInfo_GetSortDescriptionLabel(This,fDescending,ppszDescription) \ + ( (This)->lpVtbl -> GetSortDescriptionLabel(This,fDescending,ppszDescription) ) + +#define IPropertyDescriptionSearchInfo_GetAggregationType(This,paggtype) \ + ( (This)->lpVtbl -> GetAggregationType(This,paggtype) ) + +#define IPropertyDescriptionSearchInfo_GetConditionType(This,pcontype,popDefault) \ + ( (This)->lpVtbl -> GetConditionType(This,pcontype,popDefault) ) + +#define IPropertyDescriptionSearchInfo_GetEnumTypeList(This,riid,ppv) \ + ( (This)->lpVtbl -> GetEnumTypeList(This,riid,ppv) ) + +#define IPropertyDescriptionSearchInfo_CoerceToCanonicalValue(This,ppropvar) \ + ( (This)->lpVtbl -> CoerceToCanonicalValue(This,ppropvar) ) + +#define IPropertyDescriptionSearchInfo_FormatForDisplay(This,propvar,pdfFlags,ppszDisplay) \ + ( (This)->lpVtbl -> FormatForDisplay(This,propvar,pdfFlags,ppszDisplay) ) + +#define IPropertyDescriptionSearchInfo_IsValueCanonical(This,propvar) \ + ( (This)->lpVtbl -> IsValueCanonical(This,propvar) ) + + +#define IPropertyDescriptionSearchInfo_GetSearchInfoFlags(This,ppdsiFlags) \ + ( (This)->lpVtbl -> GetSearchInfoFlags(This,ppdsiFlags) ) + +#define IPropertyDescriptionSearchInfo_GetColumnIndexType(This,ppdciType) \ + ( (This)->lpVtbl -> GetColumnIndexType(This,ppdciType) ) + +#define IPropertyDescriptionSearchInfo_GetProjectionString(This,ppszProjection) \ + ( (This)->lpVtbl -> GetProjectionString(This,ppszProjection) ) + +#define IPropertyDescriptionSearchInfo_GetMaxSize(This,pcbMaxSize) \ + ( (This)->lpVtbl -> GetMaxSize(This,pcbMaxSize) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IPropertyDescriptionSearchInfo_INTERFACE_DEFINED__ */ + + +/* interface __MIDL_itf_propsys_0000_0014 */ +/* [local] */ + +/* [v1_enum] */ +enum tagPROPDESC_ENUMFILTER + { PDEF_ALL = 0, + PDEF_SYSTEM = 1, + PDEF_NONSYSTEM = 2, + PDEF_VIEWABLE = 3, + PDEF_QUERYABLE = 4, + PDEF_INFULLTEXTQUERY = 5, + PDEF_COLUMN = 6 + } ; +typedef enum tagPROPDESC_ENUMFILTER PROPDESC_ENUMFILTER; + + + +extern RPC_IF_HANDLE __MIDL_itf_propsys_0000_0014_v0_0_c_ifspec; +extern RPC_IF_HANDLE __MIDL_itf_propsys_0000_0014_v0_0_s_ifspec; + +#ifndef __IPropertySystem_INTERFACE_DEFINED__ +#define __IPropertySystem_INTERFACE_DEFINED__ + +/* interface IPropertySystem */ +/* [unique][object][uuid] */ + + +EXTERN_C const IID IID_IPropertySystem; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("ca724e8a-c3e6-442b-88a4-6fb0db8035a3") + IPropertySystem : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE GetPropertyDescription( + /* [in] */ __RPC__in REFPROPERTYKEY propkey, + /* [in] */ __RPC__in REFIID riid, + /* [iid_is][out] */ __RPC__deref_out_opt void **ppv) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetPropertyDescriptionByName( + /* [string][in] */ __RPC__in LPCWSTR pszCanonicalName, + /* [in] */ __RPC__in REFIID riid, + /* [iid_is][out] */ __RPC__deref_out_opt void **ppv) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetPropertyDescriptionListFromString( + /* [string][in] */ __RPC__in LPCWSTR pszPropList, + /* [in] */ __RPC__in REFIID riid, + /* [iid_is][out] */ __RPC__deref_out_opt void **ppv) = 0; + + virtual HRESULT STDMETHODCALLTYPE EnumeratePropertyDescriptions( + /* [in] */ PROPDESC_ENUMFILTER filterOn, + /* [in] */ __RPC__in REFIID riid, + /* [iid_is][out] */ __RPC__deref_out_opt void **ppv) = 0; + + virtual HRESULT STDMETHODCALLTYPE FormatForDisplay( + /* [in] */ __RPC__in REFPROPERTYKEY key, + /* [in] */ __RPC__in REFPROPVARIANT propvar, + /* [in] */ PROPDESC_FORMAT_FLAGS pdff, + /* [size_is][string][out] */ __RPC__out_ecount_full_string(cchText) LPWSTR pszText, + /* [in] */ DWORD cchText) = 0; + + virtual HRESULT STDMETHODCALLTYPE FormatForDisplayAlloc( + /* [in] */ __RPC__in REFPROPERTYKEY key, + /* [in] */ __RPC__in REFPROPVARIANT propvar, + /* [in] */ PROPDESC_FORMAT_FLAGS pdff, + /* [string][out] */ __RPC__deref_out_opt_string LPWSTR *ppszDisplay) = 0; + + virtual HRESULT STDMETHODCALLTYPE RegisterPropertySchema( + /* [string][in] */ __RPC__in LPCWSTR pszPath) = 0; + + virtual HRESULT STDMETHODCALLTYPE UnregisterPropertySchema( + /* [string][in] */ __RPC__in LPCWSTR pszPath) = 0; + + virtual HRESULT STDMETHODCALLTYPE RefreshPropertySchema( void) = 0; + + }; + +#else /* C style interface */ + + typedef struct IPropertySystemVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IPropertySystem * This, + /* [in] */ __RPC__in REFIID riid, + /* [iid_is][out] */ + __RPC__deref_out void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IPropertySystem * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IPropertySystem * This); + + HRESULT ( STDMETHODCALLTYPE *GetPropertyDescription )( + IPropertySystem * This, + /* [in] */ __RPC__in REFPROPERTYKEY propkey, + /* [in] */ __RPC__in REFIID riid, + /* [iid_is][out] */ __RPC__deref_out_opt void **ppv); + + HRESULT ( STDMETHODCALLTYPE *GetPropertyDescriptionByName )( + IPropertySystem * This, + /* [string][in] */ __RPC__in LPCWSTR pszCanonicalName, + /* [in] */ __RPC__in REFIID riid, + /* [iid_is][out] */ __RPC__deref_out_opt void **ppv); + + HRESULT ( STDMETHODCALLTYPE *GetPropertyDescriptionListFromString )( + IPropertySystem * This, + /* [string][in] */ __RPC__in LPCWSTR pszPropList, + /* [in] */ __RPC__in REFIID riid, + /* [iid_is][out] */ __RPC__deref_out_opt void **ppv); + + HRESULT ( STDMETHODCALLTYPE *EnumeratePropertyDescriptions )( + IPropertySystem * This, + /* [in] */ PROPDESC_ENUMFILTER filterOn, + /* [in] */ __RPC__in REFIID riid, + /* [iid_is][out] */ __RPC__deref_out_opt void **ppv); + + HRESULT ( STDMETHODCALLTYPE *FormatForDisplay )( + IPropertySystem * This, + /* [in] */ __RPC__in REFPROPERTYKEY key, + /* [in] */ __RPC__in REFPROPVARIANT propvar, + /* [in] */ PROPDESC_FORMAT_FLAGS pdff, + /* [size_is][string][out] */ __RPC__out_ecount_full_string(cchText) LPWSTR pszText, + /* [in] */ DWORD cchText); + + HRESULT ( STDMETHODCALLTYPE *FormatForDisplayAlloc )( + IPropertySystem * This, + /* [in] */ __RPC__in REFPROPERTYKEY key, + /* [in] */ __RPC__in REFPROPVARIANT propvar, + /* [in] */ PROPDESC_FORMAT_FLAGS pdff, + /* [string][out] */ __RPC__deref_out_opt_string LPWSTR *ppszDisplay); + + HRESULT ( STDMETHODCALLTYPE *RegisterPropertySchema )( + IPropertySystem * This, + /* [string][in] */ __RPC__in LPCWSTR pszPath); + + HRESULT ( STDMETHODCALLTYPE *UnregisterPropertySchema )( + IPropertySystem * This, + /* [string][in] */ __RPC__in LPCWSTR pszPath); + + HRESULT ( STDMETHODCALLTYPE *RefreshPropertySchema )( + IPropertySystem * This); + + END_INTERFACE + } IPropertySystemVtbl; + + interface IPropertySystem + { + CONST_VTBL struct IPropertySystemVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IPropertySystem_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IPropertySystem_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IPropertySystem_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IPropertySystem_GetPropertyDescription(This,propkey,riid,ppv) \ + ( (This)->lpVtbl -> GetPropertyDescription(This,propkey,riid,ppv) ) + +#define IPropertySystem_GetPropertyDescriptionByName(This,pszCanonicalName,riid,ppv) \ + ( (This)->lpVtbl -> GetPropertyDescriptionByName(This,pszCanonicalName,riid,ppv) ) + +#define IPropertySystem_GetPropertyDescriptionListFromString(This,pszPropList,riid,ppv) \ + ( (This)->lpVtbl -> GetPropertyDescriptionListFromString(This,pszPropList,riid,ppv) ) + +#define IPropertySystem_EnumeratePropertyDescriptions(This,filterOn,riid,ppv) \ + ( (This)->lpVtbl -> EnumeratePropertyDescriptions(This,filterOn,riid,ppv) ) + +#define IPropertySystem_FormatForDisplay(This,key,propvar,pdff,pszText,cchText) \ + ( (This)->lpVtbl -> FormatForDisplay(This,key,propvar,pdff,pszText,cchText) ) + +#define IPropertySystem_FormatForDisplayAlloc(This,key,propvar,pdff,ppszDisplay) \ + ( (This)->lpVtbl -> FormatForDisplayAlloc(This,key,propvar,pdff,ppszDisplay) ) + +#define IPropertySystem_RegisterPropertySchema(This,pszPath) \ + ( (This)->lpVtbl -> RegisterPropertySchema(This,pszPath) ) + +#define IPropertySystem_UnregisterPropertySchema(This,pszPath) \ + ( (This)->lpVtbl -> UnregisterPropertySchema(This,pszPath) ) + +#define IPropertySystem_RefreshPropertySchema(This) \ + ( (This)->lpVtbl -> RefreshPropertySchema(This) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IPropertySystem_INTERFACE_DEFINED__ */ + + +#ifndef __IPropertyDescriptionList_INTERFACE_DEFINED__ +#define __IPropertyDescriptionList_INTERFACE_DEFINED__ + +/* interface IPropertyDescriptionList */ +/* [unique][object][uuid] */ + + +EXTERN_C const IID IID_IPropertyDescriptionList; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("1f9fc1d0-c39b-4b26-817f-011967d3440e") + IPropertyDescriptionList : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE GetCount( + /* [out] */ __RPC__out UINT *pcElem) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetAt( + /* [in] */ UINT iElem, + /* [in] */ __RPC__in REFIID riid, + /* [iid_is][out] */ __RPC__deref_out_opt void **ppv) = 0; + + }; + +#else /* C style interface */ + + typedef struct IPropertyDescriptionListVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IPropertyDescriptionList * This, + /* [in] */ __RPC__in REFIID riid, + /* [iid_is][out] */ + __RPC__deref_out void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IPropertyDescriptionList * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IPropertyDescriptionList * This); + + HRESULT ( STDMETHODCALLTYPE *GetCount )( + IPropertyDescriptionList * This, + /* [out] */ __RPC__out UINT *pcElem); + + HRESULT ( STDMETHODCALLTYPE *GetAt )( + IPropertyDescriptionList * This, + /* [in] */ UINT iElem, + /* [in] */ __RPC__in REFIID riid, + /* [iid_is][out] */ __RPC__deref_out_opt void **ppv); + + END_INTERFACE + } IPropertyDescriptionListVtbl; + + interface IPropertyDescriptionList + { + CONST_VTBL struct IPropertyDescriptionListVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IPropertyDescriptionList_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IPropertyDescriptionList_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IPropertyDescriptionList_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IPropertyDescriptionList_GetCount(This,pcElem) \ + ( (This)->lpVtbl -> GetCount(This,pcElem) ) + +#define IPropertyDescriptionList_GetAt(This,iElem,riid,ppv) \ + ( (This)->lpVtbl -> GetAt(This,iElem,riid,ppv) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IPropertyDescriptionList_INTERFACE_DEFINED__ */ + + +#ifndef __IPropertyStoreFactory_INTERFACE_DEFINED__ +#define __IPropertyStoreFactory_INTERFACE_DEFINED__ + +/* interface IPropertyStoreFactory */ +/* [unique][object][uuid] */ + + +EXTERN_C const IID IID_IPropertyStoreFactory; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("bc110b6d-57e8-4148-a9c6-91015ab2f3a5") + IPropertyStoreFactory : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE GetPropertyStore( + /* [in] */ GETPROPERTYSTOREFLAGS flags, + /* [unique][in] */ __RPC__in_opt IUnknown *pUnkFactory, + /* [in] */ __RPC__in REFIID riid, + /* [iid_is][out] */ __RPC__deref_out_opt void **ppv) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetPropertyStoreForKeys( + /* [unique][in] */ __RPC__in_opt const PROPERTYKEY *rgKeys, + /* [in] */ UINT cKeys, + /* [in] */ GETPROPERTYSTOREFLAGS flags, + /* [in] */ __RPC__in REFIID riid, + /* [iid_is][out] */ __RPC__deref_out_opt void **ppv) = 0; + + }; + +#else /* C style interface */ + + typedef struct IPropertyStoreFactoryVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IPropertyStoreFactory * This, + /* [in] */ __RPC__in REFIID riid, + /* [iid_is][out] */ + __RPC__deref_out void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IPropertyStoreFactory * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IPropertyStoreFactory * This); + + HRESULT ( STDMETHODCALLTYPE *GetPropertyStore )( + IPropertyStoreFactory * This, + /* [in] */ GETPROPERTYSTOREFLAGS flags, + /* [unique][in] */ __RPC__in_opt IUnknown *pUnkFactory, + /* [in] */ __RPC__in REFIID riid, + /* [iid_is][out] */ __RPC__deref_out_opt void **ppv); + + HRESULT ( STDMETHODCALLTYPE *GetPropertyStoreForKeys )( + IPropertyStoreFactory * This, + /* [unique][in] */ __RPC__in_opt const PROPERTYKEY *rgKeys, + /* [in] */ UINT cKeys, + /* [in] */ GETPROPERTYSTOREFLAGS flags, + /* [in] */ __RPC__in REFIID riid, + /* [iid_is][out] */ __RPC__deref_out_opt void **ppv); + + END_INTERFACE + } IPropertyStoreFactoryVtbl; + + interface IPropertyStoreFactory + { + CONST_VTBL struct IPropertyStoreFactoryVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IPropertyStoreFactory_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IPropertyStoreFactory_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IPropertyStoreFactory_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IPropertyStoreFactory_GetPropertyStore(This,flags,pUnkFactory,riid,ppv) \ + ( (This)->lpVtbl -> GetPropertyStore(This,flags,pUnkFactory,riid,ppv) ) + +#define IPropertyStoreFactory_GetPropertyStoreForKeys(This,rgKeys,cKeys,flags,riid,ppv) \ + ( (This)->lpVtbl -> GetPropertyStoreForKeys(This,rgKeys,cKeys,flags,riid,ppv) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IPropertyStoreFactory_INTERFACE_DEFINED__ */ + + +#ifndef __IDelayedPropertyStoreFactory_INTERFACE_DEFINED__ +#define __IDelayedPropertyStoreFactory_INTERFACE_DEFINED__ + +/* interface IDelayedPropertyStoreFactory */ +/* [unique][object][uuid] */ + + +EXTERN_C const IID IID_IDelayedPropertyStoreFactory; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("40d4577f-e237-4bdb-bd69-58f089431b6a") + IDelayedPropertyStoreFactory : public IPropertyStoreFactory + { + public: + virtual HRESULT STDMETHODCALLTYPE GetDelayedPropertyStore( + /* [in] */ GETPROPERTYSTOREFLAGS flags, + /* [in] */ DWORD dwStoreId, + /* [in] */ __RPC__in REFIID riid, + /* [iid_is][out] */ __RPC__deref_out_opt void **ppv) = 0; + + }; + +#else /* C style interface */ + + typedef struct IDelayedPropertyStoreFactoryVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IDelayedPropertyStoreFactory * This, + /* [in] */ __RPC__in REFIID riid, + /* [iid_is][out] */ + __RPC__deref_out void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IDelayedPropertyStoreFactory * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IDelayedPropertyStoreFactory * This); + + HRESULT ( STDMETHODCALLTYPE *GetPropertyStore )( + IDelayedPropertyStoreFactory * This, + /* [in] */ GETPROPERTYSTOREFLAGS flags, + /* [unique][in] */ __RPC__in_opt IUnknown *pUnkFactory, + /* [in] */ __RPC__in REFIID riid, + /* [iid_is][out] */ __RPC__deref_out_opt void **ppv); + + HRESULT ( STDMETHODCALLTYPE *GetPropertyStoreForKeys )( + IDelayedPropertyStoreFactory * This, + /* [unique][in] */ __RPC__in_opt const PROPERTYKEY *rgKeys, + /* [in] */ UINT cKeys, + /* [in] */ GETPROPERTYSTOREFLAGS flags, + /* [in] */ __RPC__in REFIID riid, + /* [iid_is][out] */ __RPC__deref_out_opt void **ppv); + + HRESULT ( STDMETHODCALLTYPE *GetDelayedPropertyStore )( + IDelayedPropertyStoreFactory * This, + /* [in] */ GETPROPERTYSTOREFLAGS flags, + /* [in] */ DWORD dwStoreId, + /* [in] */ __RPC__in REFIID riid, + /* [iid_is][out] */ __RPC__deref_out_opt void **ppv); + + END_INTERFACE + } IDelayedPropertyStoreFactoryVtbl; + + interface IDelayedPropertyStoreFactory + { + CONST_VTBL struct IDelayedPropertyStoreFactoryVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IDelayedPropertyStoreFactory_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IDelayedPropertyStoreFactory_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IDelayedPropertyStoreFactory_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IDelayedPropertyStoreFactory_GetPropertyStore(This,flags,pUnkFactory,riid,ppv) \ + ( (This)->lpVtbl -> GetPropertyStore(This,flags,pUnkFactory,riid,ppv) ) + +#define IDelayedPropertyStoreFactory_GetPropertyStoreForKeys(This,rgKeys,cKeys,flags,riid,ppv) \ + ( (This)->lpVtbl -> GetPropertyStoreForKeys(This,rgKeys,cKeys,flags,riid,ppv) ) + + +#define IDelayedPropertyStoreFactory_GetDelayedPropertyStore(This,flags,dwStoreId,riid,ppv) \ + ( (This)->lpVtbl -> GetDelayedPropertyStore(This,flags,dwStoreId,riid,ppv) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IDelayedPropertyStoreFactory_INTERFACE_DEFINED__ */ + + +/* interface __MIDL_itf_propsys_0000_0018 */ +/* [local] */ + +/* [v1_enum] */ +enum tagPERSIST_SPROPSTORE_FLAGS + { FPSPS_READONLY = 0x1 + } ; +typedef int PERSIST_SPROPSTORE_FLAGS; + +typedef struct tagSERIALIZEDPROPSTORAGE SERIALIZEDPROPSTORAGE; + +typedef SERIALIZEDPROPSTORAGE __unaligned *PUSERIALIZEDPROPSTORAGE; + +typedef const SERIALIZEDPROPSTORAGE __unaligned *PCUSERIALIZEDPROPSTORAGE; + + + +extern RPC_IF_HANDLE __MIDL_itf_propsys_0000_0018_v0_0_c_ifspec; +extern RPC_IF_HANDLE __MIDL_itf_propsys_0000_0018_v0_0_s_ifspec; + +#ifndef __IPersistSerializedPropStorage_INTERFACE_DEFINED__ +#define __IPersistSerializedPropStorage_INTERFACE_DEFINED__ + +/* interface IPersistSerializedPropStorage */ +/* [object][local][unique][uuid] */ + + +EXTERN_C const IID IID_IPersistSerializedPropStorage; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("e318ad57-0aa0-450f-aca5-6fab7103d917") + IPersistSerializedPropStorage : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE SetFlags( + /* [in] */ PERSIST_SPROPSTORE_FLAGS flags) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetPropertyStorage( + /* [in] */ + __in_bcount(cb) PCUSERIALIZEDPROPSTORAGE psps, + /* [in] */ + __in DWORD cb) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetPropertyStorage( + /* [out] */ + __deref_out_bcount(*pcb) SERIALIZEDPROPSTORAGE **ppsps, + /* [out] */ + __out DWORD *pcb) = 0; + + }; + +#else /* C style interface */ + + typedef struct IPersistSerializedPropStorageVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IPersistSerializedPropStorage * This, + /* [in] */ REFIID riid, + /* [iid_is][out] */ + __RPC__deref_out void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IPersistSerializedPropStorage * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IPersistSerializedPropStorage * This); + + HRESULT ( STDMETHODCALLTYPE *SetFlags )( + IPersistSerializedPropStorage * This, + /* [in] */ PERSIST_SPROPSTORE_FLAGS flags); + + HRESULT ( STDMETHODCALLTYPE *SetPropertyStorage )( + IPersistSerializedPropStorage * This, + /* [in] */ + __in_bcount(cb) PCUSERIALIZEDPROPSTORAGE psps, + /* [in] */ + __in DWORD cb); + + HRESULT ( STDMETHODCALLTYPE *GetPropertyStorage )( + IPersistSerializedPropStorage * This, + /* [out] */ + __deref_out_bcount(*pcb) SERIALIZEDPROPSTORAGE **ppsps, + /* [out] */ + __out DWORD *pcb); + + END_INTERFACE + } IPersistSerializedPropStorageVtbl; + + interface IPersistSerializedPropStorage + { + CONST_VTBL struct IPersistSerializedPropStorageVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IPersistSerializedPropStorage_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IPersistSerializedPropStorage_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IPersistSerializedPropStorage_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IPersistSerializedPropStorage_SetFlags(This,flags) \ + ( (This)->lpVtbl -> SetFlags(This,flags) ) + +#define IPersistSerializedPropStorage_SetPropertyStorage(This,psps,cb) \ + ( (This)->lpVtbl -> SetPropertyStorage(This,psps,cb) ) + +#define IPersistSerializedPropStorage_GetPropertyStorage(This,ppsps,pcb) \ + ( (This)->lpVtbl -> GetPropertyStorage(This,ppsps,pcb) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IPersistSerializedPropStorage_INTERFACE_DEFINED__ */ + + +#ifndef __IPropertySystemChangeNotify_INTERFACE_DEFINED__ +#define __IPropertySystemChangeNotify_INTERFACE_DEFINED__ + +/* interface IPropertySystemChangeNotify */ +/* [unique][object][uuid] */ + + +EXTERN_C const IID IID_IPropertySystemChangeNotify; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("fa955fd9-38be-4879-a6ce-824cf52d609f") + IPropertySystemChangeNotify : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE SchemaRefreshed( void) = 0; + + }; + +#else /* C style interface */ + + typedef struct IPropertySystemChangeNotifyVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IPropertySystemChangeNotify * This, + /* [in] */ __RPC__in REFIID riid, + /* [iid_is][out] */ + __RPC__deref_out void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IPropertySystemChangeNotify * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IPropertySystemChangeNotify * This); + + HRESULT ( STDMETHODCALLTYPE *SchemaRefreshed )( + IPropertySystemChangeNotify * This); + + END_INTERFACE + } IPropertySystemChangeNotifyVtbl; + + interface IPropertySystemChangeNotify + { + CONST_VTBL struct IPropertySystemChangeNotifyVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IPropertySystemChangeNotify_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IPropertySystemChangeNotify_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IPropertySystemChangeNotify_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IPropertySystemChangeNotify_SchemaRefreshed(This) \ + ( (This)->lpVtbl -> SchemaRefreshed(This) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IPropertySystemChangeNotify_INTERFACE_DEFINED__ */ + + +#ifndef __ICreateObject_INTERFACE_DEFINED__ +#define __ICreateObject_INTERFACE_DEFINED__ + +/* interface ICreateObject */ +/* [object][unique][uuid] */ + + +EXTERN_C const IID IID_ICreateObject; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("75121952-e0d0-43e5-9380-1d80483acf72") + ICreateObject : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE CreateObject( + /* [in] */ __RPC__in REFCLSID clsid, + /* [unique][in] */ __RPC__in_opt IUnknown *pUnkOuter, + /* [in] */ __RPC__in REFIID riid, + /* [iid_is][out] */ __RPC__deref_out_opt void **ppv) = 0; + + }; + +#else /* C style interface */ + + typedef struct ICreateObjectVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ICreateObject * This, + /* [in] */ __RPC__in REFIID riid, + /* [iid_is][out] */ + __RPC__deref_out void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ICreateObject * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ICreateObject * This); + + HRESULT ( STDMETHODCALLTYPE *CreateObject )( + ICreateObject * This, + /* [in] */ __RPC__in REFCLSID clsid, + /* [unique][in] */ __RPC__in_opt IUnknown *pUnkOuter, + /* [in] */ __RPC__in REFIID riid, + /* [iid_is][out] */ __RPC__deref_out_opt void **ppv); + + END_INTERFACE + } ICreateObjectVtbl; + + interface ICreateObject + { + CONST_VTBL struct ICreateObjectVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ICreateObject_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ICreateObject_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ICreateObject_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ICreateObject_CreateObject(This,clsid,pUnkOuter,riid,ppv) \ + ( (This)->lpVtbl -> CreateObject(This,clsid,pUnkOuter,riid,ppv) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ICreateObject_INTERFACE_DEFINED__ */ + + +/* interface __MIDL_itf_propsys_0000_0021 */ +/* [local] */ + +// Format a property value for display purposes +PSSTDAPI PSFormatForDisplay( + __in REFPROPERTYKEY propkey, + __in REFPROPVARIANT propvar, + __in PROPDESC_FORMAT_FLAGS pdfFlags, + __out_ecount(cchText) LPWSTR pwszText, + __in DWORD cchText); + +PSSTDAPI PSFormatForDisplayAlloc( + __in REFPROPERTYKEY key, + __in REFPROPVARIANT propvar, + __in PROPDESC_FORMAT_FLAGS pdff, + __deref_out PWSTR *ppszDisplay); + +PSSTDAPI PSFormatPropertyValue( + __in IPropertyStore *pps, + __in IPropertyDescription *ppd, + __in PROPDESC_FORMAT_FLAGS pdff, + __deref_out LPWSTR *ppszDisplay); + + +#define PKEY_PIDSTR_MAX 10 // will take care of any long integer value +#define GUIDSTRING_MAX (1 + 8 + 1 + 4 + 1 + 4 + 1 + 4 + 1 + 12 + 1 + 1) // "{12345678-1234-1234-1234-123456789012}" +#define PKEYSTR_MAX (GUIDSTRING_MAX + 1 + PKEY_PIDSTR_MAX) + +// Convert a PROPERTYKEY to and from a PWSTR +PSSTDAPI PSStringFromPropertyKey( + __in REFPROPERTYKEY pkey, + __out_ecount(cch) LPWSTR psz, + __in UINT cch); + +PSSTDAPI PSPropertyKeyFromString( + __in LPCWSTR pszString, + __out PROPERTYKEY *pkey); + + +// Creates an in-memory property store +// Returns an IPropertyStore, IPersistSerializedPropStorage, and related interfaces interface +PSSTDAPI PSCreateMemoryPropertyStore( + __in REFIID riid, + __deref_out void **ppv); + + +// Create a read-only, delay-bind multiplexing property store +// Returns an IPropertyStore interface or related interfaces +PSSTDAPI PSCreateDelayedMultiplexPropertyStore( + __in GETPROPERTYSTOREFLAGS flags, + __in IDelayedPropertyStoreFactory *pdpsf, + __in_ecount(cStores) const DWORD *rgStoreIds, + __in DWORD cStores, + __in REFIID riid, + __deref_out void **ppv); + + +// Create a read-only property store from one or more sources (which each must support either IPropertyStore or IPropertySetStorage) +// Returns an IPropertyStore interface or related interfaces +PSSTDAPI PSCreateMultiplexPropertyStore( + __in_ecount(cStores) IUnknown **prgpunkStores, + __in DWORD cStores, + __in REFIID riid, + __deref_out void **ppv); + + +// Create a container for IPropertyChanges +// Returns an IPropertyChangeArray interface +PSSTDAPI PSCreatePropertyChangeArray( + __in_ecount_opt(cChanges) const PROPERTYKEY *rgpropkey, + __in_ecount_opt(cChanges) const PKA_FLAGS *rgflags, + __in_ecount_opt(cChanges) const PROPVARIANT *rgpropvar, + __in UINT cChanges, + __in REFIID riid, + __deref_out void **ppv); + + +// Create a simple property change +// Returns an IPropertyChange interface +PSSTDAPI PSCreateSimplePropertyChange( + __in PKA_FLAGS flags, + __in REFPROPERTYKEY key, + __in REFPROPVARIANT propvar, + __in REFIID riid, + __deref_out void **ppv); + + +// Get a property description +// Returns an IPropertyDescription interface +PSSTDAPI PSGetPropertyDescription( + __in REFPROPERTYKEY propkey, + __in REFIID riid, + __deref_out void **ppv); + +PSSTDAPI PSGetPropertyDescriptionByName( + __in LPCWSTR pszCanonicalName, + __in REFIID riid, + __deref_out void **ppv); + + +// Lookup a per-machine registered file property handler +PSSTDAPI PSLookupPropertyHandlerCLSID( + __in PCWSTR pszFilePath, + __out CLSID *pclsid); +// Get a property handler, on Vista or downlevel to XP +// punkItem is a shell item created with an SHCreateItemXXX API +// Returns an IPropertyStore +PSSTDAPI PSGetItemPropertyHandler( + __in IUnknown *punkItem, + __in BOOL fReadWrite, + __in REFIID riid, + __deref_out void **ppv); + + +// Get a property handler, on Vista or downlevel to XP +// punkItem is a shell item created with an SHCreateItemXXX API +// punkCreateObject supports ICreateObject +// Returns an IPropertyStore +PSSTDAPI PSGetItemPropertyHandlerWithCreateObject( + __in IUnknown *punkItem, + __in BOOL fReadWrite, + __in IUnknown *punkCreateObject, + __in REFIID riid, + __deref_out void **ppv); + + +// Get or set a property value from a store +PSSTDAPI PSGetPropertyValue( + __in IPropertyStore *pps, + __in IPropertyDescription *ppd, + __out PROPVARIANT *ppropvar); + +PSSTDAPI PSSetPropertyValue( + __in IPropertyStore *pps, + __in IPropertyDescription *ppd, + __in REFPROPVARIANT propvar); + + +// Interact with the set of property descriptions +PSSTDAPI PSRegisterPropertySchema( + __in PCWSTR pszPath); + +PSSTDAPI PSUnregisterPropertySchema( + __in PCWSTR pszPath); + +PSSTDAPI PSRefreshPropertySchema(); + +// Returns either: IPropertyDescriptionList or IEnumUnknown interfaces +PSSTDAPI PSEnumeratePropertyDescriptions( + __in PROPDESC_ENUMFILTER filterOn, + __in REFIID riid, + __deref_out void **ppv); + + +// Convert between a PROPERTYKEY and its canonical name +PSSTDAPI PSGetPropertyKeyFromName( + __in PCWSTR pszName, + __out PROPERTYKEY *ppropkey); + +PSSTDAPI PSGetNameFromPropertyKey( + __in REFPROPERTYKEY propkey, + __deref_out PWSTR *ppszCanonicalName); + + +// Coerce and canonicalize a property value +PSSTDAPI PSCoerceToCanonicalValue( + __in REFPROPERTYKEY key, + __inout PROPVARIANT *ppropvar); + + +// Convert a 'prop:' string into a list of property descriptions +// Returns an IPropertyDescriptionList interface +PSSTDAPI PSGetPropertyDescriptionListFromString( + __in LPCWSTR pszPropList, + __in REFIID riid, + __deref_out void **ppv); + + +// Wrap an IPropertySetStorage interface in an IPropertyStore interface +// Returns an IPropertyStore or related interface +PSSTDAPI PSCreatePropertyStoreFromPropertySetStorage( + __in IPropertySetStorage *ppss, + DWORD grfMode, + REFIID riid, + __deref_out void **ppv); + + +// punkSource must support IPropertyStore or IPropertySetStorage +// On success, the returned ppv is guaranteed to support IPropertyStore. +// If punkSource already supports IPropertyStore, no wrapper is created. +PSSTDAPI PSCreatePropertyStoreFromObject( + __in IUnknown *punk, + __in DWORD grfMode, + __in REFIID riid, + __deref_out void **ppv); + + +// punkSource must support IPropertyStore +// riid may be IPropertyStore, IPropertySetStorage, IPropertyStoreCapabilities, or IObjectProvider +PSSTDAPI PSCreateAdapterFromPropertyStore( + __in IPropertyStore *pps, + __in REFIID riid, + __deref_out void **ppv); + + +// Talk to the property system using an interface +// Returns an IPropertySystem interface +PSSTDAPI PSGetPropertySystem( + __in REFIID riid, + __deref_out void **ppv); + + +// Obtain a value from serialized property storage +PSSTDAPI PSGetPropertyFromPropertyStorage( + __in_bcount(cb) PCUSERIALIZEDPROPSTORAGE psps, + __in DWORD cb, + __in REFPROPERTYKEY rpkey, + __out PROPVARIANT *ppropvar); + + +// Obtain a named value from serialized property storage +PSSTDAPI PSGetNamedPropertyFromPropertyStorage( + __in_bcount(cb) PCUSERIALIZEDPROPSTORAGE psps, + __in DWORD cb, + __in LPCWSTR pszName, + __out PROPVARIANT *ppropvar); + + + + +extern RPC_IF_HANDLE __MIDL_itf_propsys_0000_0021_v0_0_c_ifspec; +extern RPC_IF_HANDLE __MIDL_itf_propsys_0000_0021_v0_0_s_ifspec; + + +#ifndef __PropSysObjects_LIBRARY_DEFINED__ +#define __PropSysObjects_LIBRARY_DEFINED__ + +/* library PropSysObjects */ +/* [version][lcid][uuid] */ + + +EXTERN_C const IID LIBID_PropSysObjects; + +EXTERN_C const CLSID CLSID_InMemoryPropertyStore; + +#ifdef __cplusplus + +class DECLSPEC_UUID("9a02e012-6303-4e1e-b9a1-630f802592c5") +InMemoryPropertyStore; +#endif + +EXTERN_C const CLSID CLSID_PropertySystem; + +#ifdef __cplusplus + +class DECLSPEC_UUID("b8967f85-58ae-4f46-9fb2-5d7904798f4b") +PropertySystem; +#endif +#endif /* __PropSysObjects_LIBRARY_DEFINED__ */ + +/* Additional Prototypes for ALL interfaces */ + +unsigned long __RPC_USER BSTR_UserSize( unsigned long *, unsigned long , BSTR * ); +unsigned char * __RPC_USER BSTR_UserMarshal( unsigned long *, unsigned char *, BSTR * ); +unsigned char * __RPC_USER BSTR_UserUnmarshal(unsigned long *, unsigned char *, BSTR * ); +void __RPC_USER BSTR_UserFree( unsigned long *, BSTR * ); + +unsigned long __RPC_USER LPSAFEARRAY_UserSize( unsigned long *, unsigned long , LPSAFEARRAY * ); +unsigned char * __RPC_USER LPSAFEARRAY_UserMarshal( unsigned long *, unsigned char *, LPSAFEARRAY * ); +unsigned char * __RPC_USER LPSAFEARRAY_UserUnmarshal(unsigned long *, unsigned char *, LPSAFEARRAY * ); +void __RPC_USER LPSAFEARRAY_UserFree( unsigned long *, LPSAFEARRAY * ); + +unsigned long __RPC_USER BSTR_UserSize64( unsigned long *, unsigned long , BSTR * ); +unsigned char * __RPC_USER BSTR_UserMarshal64( unsigned long *, unsigned char *, BSTR * ); +unsigned char * __RPC_USER BSTR_UserUnmarshal64(unsigned long *, unsigned char *, BSTR * ); +void __RPC_USER BSTR_UserFree64( unsigned long *, BSTR * ); + +unsigned long __RPC_USER LPSAFEARRAY_UserSize64( unsigned long *, unsigned long , LPSAFEARRAY * ); +unsigned char * __RPC_USER LPSAFEARRAY_UserMarshal64( unsigned long *, unsigned char *, LPSAFEARRAY * ); +unsigned char * __RPC_USER LPSAFEARRAY_UserUnmarshal64(unsigned long *, unsigned char *, LPSAFEARRAY * ); +void __RPC_USER LPSAFEARRAY_UserFree64( unsigned long *, LPSAFEARRAY * ); + +/* [local] */ HRESULT STDMETHODCALLTYPE IInitializeWithStream_Initialize_Proxy( + IInitializeWithStream * This, + /* [in] */ IStream *pstream, + /* [in] */ DWORD grfMode); + + +/* [call_as] */ HRESULT STDMETHODCALLTYPE IInitializeWithStream_Initialize_Stub( + IInitializeWithStream * This, + /* [in] */ __RPC__in_opt IStream *pstream, + /* [in] */ DWORD grfMode); + +/* [local] */ HRESULT STDMETHODCALLTYPE IPropertyDescription_CoerceToCanonicalValue_Proxy( + IPropertyDescription * This, + /* [out][in] */ PROPVARIANT *ppropvar); + + +/* [call_as] */ HRESULT STDMETHODCALLTYPE IPropertyDescription_CoerceToCanonicalValue_Stub( + IPropertyDescription * This, + /* [in] */ __RPC__in REFPROPVARIANT propvar, + /* [out] */ __RPC__out PROPVARIANT *ppropvar); + + + +/* end of Additional Prototypes */ + +#ifdef __cplusplus +} +#endif + +#endif + + + diff --git a/extern/portaudio/src/hostapi/wasapi/mingw-include/rpcsal.h b/extern/portaudio/src/hostapi/wasapi/mingw-include/rpcsal.h new file mode 100644 index 0000000..ba9836a --- /dev/null +++ b/extern/portaudio/src/hostapi/wasapi/mingw-include/rpcsal.h @@ -0,0 +1,113 @@ +#pragma once + +#if __GNUC__ >=3 +#pragma GCC system_header +#endif + +#define RPC_range(min,max) + +#define __RPC__in +#define __RPC__in_string +#define __RPC__in_opt_string +#define __RPC__deref_opt_in_opt +#define __RPC__opt_in_opt_string +#define __RPC__in_ecount(size) +#define __RPC__in_ecount_full(size) +#define __RPC__in_ecount_full_string(size) +#define __RPC__in_ecount_part(size, length) +#define __RPC__in_ecount_full_opt(size) +#define __RPC__in_ecount_full_opt_string(size) +#define __RPC__inout_ecount_full_opt_string(size) +#define __RPC__in_ecount_part_opt(size, length) + +#define __RPC__deref_in +#define __RPC__deref_in_string +#define __RPC__deref_opt_in +#define __RPC__deref_in_opt +#define __RPC__deref_in_ecount(size) +#define __RPC__deref_in_ecount_part(size, length) +#define __RPC__deref_in_ecount_full(size) +#define __RPC__deref_in_ecount_full_opt(size) +#define __RPC__deref_in_ecount_full_string(size) +#define __RPC__deref_in_ecount_full_opt_string(size) +#define __RPC__deref_in_ecount_opt(size) +#define __RPC__deref_in_ecount_opt_string(size) +#define __RPC__deref_in_ecount_part_opt(size, length) + +// [out] +#define __RPC__out +#define __RPC__out_ecount(size) +#define __RPC__out_ecount_part(size, length) +#define __RPC__out_ecount_full(size) +#define __RPC__out_ecount_full_string(size) + +// [in,out] +#define __RPC__inout +#define __RPC__inout_string +#define __RPC__opt_inout +#define __RPC__inout_ecount(size) +#define __RPC__inout_ecount_part(size, length) +#define __RPC__inout_ecount_full(size) +#define __RPC__inout_ecount_full_string(size) + +// [in,unique] +#define __RPC__in_opt +#define __RPC__in_ecount_opt(size) + + +// [in,out,unique] +#define __RPC__inout_opt +#define __RPC__inout_ecount_opt(size) +#define __RPC__inout_ecount_part_opt(size, length) +#define __RPC__inout_ecount_full_opt(size) +#define __RPC__inout_ecount_full_string(size) + +// [out] ** +#define __RPC__deref_out +#define __RPC__deref_out_string +#define __RPC__deref_out_opt +#define __RPC__deref_out_opt_string +#define __RPC__deref_out_ecount(size) +#define __RPC__deref_out_ecount_part(size, length) +#define __RPC__deref_out_ecount_full(size) +#define __RPC__deref_out_ecount_full_string(size) + + +// [in,out] **, second pointer decoration. +#define __RPC__deref_inout +#define __RPC__deref_inout_string +#define __RPC__deref_inout_opt +#define __RPC__deref_inout_opt_string +#define __RPC__deref_inout_ecount_full(size) +#define __RPC__deref_inout_ecount_full_string(size) +#define __RPC__deref_inout_ecount_opt(size) +#define __RPC__deref_inout_ecount_part_opt(size, length) +#define __RPC__deref_inout_ecount_full_opt(size) +#define __RPC__deref_inout_ecount_full_opt_string(size) + +// #define __RPC_out_opt out_opt is not allowed in rpc + +// [in,out,unique] +#define __RPC__deref_opt_inout +#define __RPC__deref_opt_inout_string +#define __RPC__deref_opt_inout_ecount(size) +#define __RPC__deref_opt_inout_ecount_part(size, length) +#define __RPC__deref_opt_inout_ecount_full(size) +#define __RPC__deref_opt_inout_ecount_full_string(size) + +#define __RPC__deref_out_ecount_opt(size) +#define __RPC__deref_out_ecount_part_opt(size, length) +#define __RPC__deref_out_ecount_full_opt(size) +#define __RPC__deref_out_ecount_full_opt_string(size) + +#define __RPC__deref_opt_inout_opt +#define __RPC__deref_opt_inout_opt_string +#define __RPC__deref_opt_inout_ecount_opt(size) +#define __RPC__deref_opt_inout_ecount_part_opt(size, length) +#define __RPC__deref_opt_inout_ecount_full_opt(size) +#define __RPC__deref_opt_inout_ecount_full_opt_string(size) + +#define __RPC_full_pointer +#define __RPC_unique_pointer +#define __RPC_ref_pointer +#define __RPC_string diff --git a/extern/portaudio/src/hostapi/wasapi/mingw-include/sal.h b/extern/portaudio/src/hostapi/wasapi/mingw-include/sal.h new file mode 100644 index 0000000..3f99ab9 --- /dev/null +++ b/extern/portaudio/src/hostapi/wasapi/mingw-include/sal.h @@ -0,0 +1,252 @@ +#pragma once + +#if __GNUC__ >=3 +#pragma GCC system_header +#endif + +/*#define __null*/ // << Conflicts with GCC internal type __null +#define __notnull +#define __maybenull +#define __readonly +#define __notreadonly +#define __maybereadonly +#define __valid +#define __notvalid +#define __maybevalid +#define __readableTo(extent) +#define __elem_readableTo(size) +#define __byte_readableTo(size) +#define __writableTo(size) +#define __elem_writableTo(size) +#define __byte_writableTo(size) +#define __deref +#define __pre +#define __post +#define __precond(expr) +#define __postcond(expr) +#define __exceptthat +#define __execeptthat +#define __inner_success(expr) +#define __inner_checkReturn +#define __inner_typefix(ctype) +#define __inner_override +#define __inner_callback +#define __inner_blocksOn(resource) +#define __inner_fallthrough_dec +#define __inner_fallthrough +#define __refparam +#define __inner_control_entrypoint(category) +#define __inner_data_entrypoint(category) + +#define __ecount(size) +#define __bcount(size) +#define __in +#define __in_ecount(size) +#define __in_bcount(size) +#define __in_z +#define __in_ecount_z(size) +#define __in_bcount_z(size) +#define __in_nz +#define __in_ecount_nz(size) +#define __in_bcount_nz(size) +#define __out +#define __out_ecount(size) +#define __out_bcount(size) +#define __out_ecount_part(size,length) +#define __out_bcount_part(size,length) +#define __out_ecount_full(size) +#define __out_bcount_full(size) +#define __out_z +#define __out_z_opt +#define __out_ecount_z(size) +#define __out_bcount_z(size) +#define __out_ecount_part_z(size,length) +#define __out_bcount_part_z(size,length) +#define __out_ecount_full_z(size) +#define __out_bcount_full_z(size) +#define __out_nz +#define __out_nz_opt +#define __out_ecount_nz(size) +#define __out_bcount_nz(size) +#define __inout +#define __inout_ecount(size) +#define __inout_bcount(size) +#define __inout_ecount_part(size,length) +#define __inout_bcount_part(size,length) +#define __inout_ecount_full(size) +#define __inout_bcount_full(size) +#define __inout_z +#define __inout_ecount_z(size) +#define __inout_bcount_z(size) +#define __inout_nz +#define __inout_ecount_nz(size) +#define __inout_bcount_nz(size) +#define __ecount_opt(size) +#define __bcount_opt(size) +#define __in_opt +#define __in_ecount_opt(size) +#define __in_bcount_opt(size) +#define __in_z_opt +#define __in_ecount_z_opt(size) +#define __in_bcount_z_opt(size) +#define __in_nz_opt +#define __in_ecount_nz_opt(size) +#define __in_bcount_nz_opt(size) +#define __out_opt +#define __out_ecount_opt(size) +#define __out_bcount_opt(size) +#define __out_ecount_part_opt(size,length) +#define __out_bcount_part_opt(size,length) +#define __out_ecount_full_opt(size) +#define __out_bcount_full_opt(size) +#define __out_ecount_z_opt(size) +#define __out_bcount_z_opt(size) +#define __out_ecount_part_z_opt(size,length) +#define __out_bcount_part_z_opt(size,length) +#define __out_ecount_full_z_opt(size) +#define __out_bcount_full_z_opt(size) +#define __out_ecount_nz_opt(size) +#define __out_bcount_nz_opt(size) +#define __inout_opt +#define __inout_ecount_opt(size) +#define __inout_bcount_opt(size) +#define __inout_ecount_part_opt(size,length) +#define __inout_bcount_part_opt(size,length) +#define __inout_ecount_full_opt(size) +#define __inout_bcount_full_opt(size) +#define __inout_z_opt +#define __inout_ecount_z_opt(size) +#define __inout_ecount_z_opt(size) +#define __inout_bcount_z_opt(size) +#define __inout_nz_opt +#define __inout_ecount_nz_opt(size) +#define __inout_bcount_nz_opt(size) +#define __deref_ecount(size) +#define __deref_bcount(size) +#define __deref_out +#define __deref_out_ecount(size) +#define __deref_out_bcount(size) +#define __deref_out_ecount_part(size,length) +#define __deref_out_bcount_part(size,length) +#define __deref_out_ecount_full(size) +#define __deref_out_bcount_full(size) +#define __deref_out_z +#define __deref_out_ecount_z(size) +#define __deref_out_bcount_z(size) +#define __deref_out_nz +#define __deref_out_ecount_nz(size) +#define __deref_out_bcount_nz(size) +#define __deref_inout +#define __deref_inout_z +#define __deref_inout_ecount(size) +#define __deref_inout_bcount(size) +#define __deref_inout_ecount_part(size,length) +#define __deref_inout_bcount_part(size,length) +#define __deref_inout_ecount_full(size) +#define __deref_inout_bcount_full(size) +#define __deref_inout_z +#define __deref_inout_ecount_z(size) +#define __deref_inout_bcount_z(size) +#define __deref_inout_nz +#define __deref_inout_ecount_nz(size) +#define __deref_inout_bcount_nz(size) +#define __deref_ecount_opt(size) +#define __deref_bcount_opt(size) +#define __deref_out_opt +#define __deref_out_ecount_opt(size) +#define __deref_out_bcount_opt(size) +#define __deref_out_ecount_part_opt(size,length) +#define __deref_out_bcount_part_opt(size,length) +#define __deref_out_ecount_full_opt(size) +#define __deref_out_bcount_full_opt(size) +#define __deref_out_z_opt +#define __deref_out_ecount_z_opt(size) +#define __deref_out_bcount_z_opt(size) +#define __deref_out_nz_opt +#define __deref_out_ecount_nz_opt(size) +#define __deref_out_bcount_nz_opt(size) +#define __deref_inout_opt +#define __deref_inout_ecount_opt(size) +#define __deref_inout_bcount_opt(size) +#define __deref_inout_ecount_part_opt(size,length) +#define __deref_inout_bcount_part_opt(size,length) +#define __deref_inout_ecount_full_opt(size) +#define __deref_inout_bcount_full_opt(size) +#define __deref_inout_z_opt +#define __deref_inout_ecount_z_opt(size) +#define __deref_inout_bcount_z_opt(size) +#define __deref_inout_nz_opt +#define __deref_inout_ecount_nz_opt(size) +#define __deref_inout_bcount_nz_opt(size) +#define __deref_opt_ecount(size) +#define __deref_opt_bcount(size) +#define __deref_opt_out +#define __deref_opt_out_z +#define __deref_opt_out_ecount(size) +#define __deref_opt_out_bcount(size) +#define __deref_opt_out_ecount_part(size,length) +#define __deref_opt_out_bcount_part(size,length) +#define __deref_opt_out_ecount_full(size) +#define __deref_opt_out_bcount_full(size) +#define __deref_opt_inout +#define __deref_opt_inout_ecount(size) +#define __deref_opt_inout_bcount(size) +#define __deref_opt_inout_ecount_part(size,length) +#define __deref_opt_inout_bcount_part(size,length) +#define __deref_opt_inout_ecount_full(size) +#define __deref_opt_inout_bcount_full(size) +#define __deref_opt_inout_z +#define __deref_opt_inout_ecount_z(size) +#define __deref_opt_inout_bcount_z(size) +#define __deref_opt_inout_nz +#define __deref_opt_inout_ecount_nz(size) +#define __deref_opt_inout_bcount_nz(size) +#define __deref_opt_ecount_opt(size) +#define __deref_opt_bcount_opt(size) +#define __deref_opt_out_opt +#define __deref_opt_out_ecount_opt(size) +#define __deref_opt_out_bcount_opt(size) +#define __deref_opt_out_ecount_part_opt(size,length) +#define __deref_opt_out_bcount_part_opt(size,length) +#define __deref_opt_out_ecount_full_opt(size) +#define __deref_opt_out_bcount_full_opt(size) +#define __deref_opt_out_z_opt +#define __deref_opt_out_ecount_z_opt(size) +#define __deref_opt_out_bcount_z_opt(size) +#define __deref_opt_out_nz_opt +#define __deref_opt_out_ecount_nz_opt(size) +#define __deref_opt_out_bcount_nz_opt(size) +#define __deref_opt_inout_opt +#define __deref_opt_inout_ecount_opt(size) +#define __deref_opt_inout_bcount_opt(size) +#define __deref_opt_inout_ecount_part_opt(size,length) +#define __deref_opt_inout_bcount_part_opt(size,length) +#define __deref_opt_inout_ecount_full_opt(size) +#define __deref_opt_inout_bcount_full_opt(size) +#define __deref_opt_inout_z_opt +#define __deref_opt_inout_ecount_z_opt(size) +#define __deref_opt_inout_bcount_z_opt(size) +#define __deref_opt_inout_nz_opt +#define __deref_opt_inout_ecount_nz_opt(size) +#define __deref_opt_inout_bcount_nz_opt(size) + +#define __success(expr) +#define __nullterminated +#define __nullnullterminated +#define __reserved +#define __checkReturn +#define __typefix(ctype) +#define __override +#define __callback +#define __format_string +#define __blocksOn(resource) +#define __control_entrypoint(category) +#define __data_entrypoint(category) + +#ifndef __fallthrough + #define __fallthrough __inner_fallthrough +#endif + +#ifndef __analysis_assume + #define __analysis_assume(expr) +#endif diff --git a/extern/portaudio/src/hostapi/wasapi/mingw-include/structuredquery.h b/extern/portaudio/src/hostapi/wasapi/mingw-include/structuredquery.h new file mode 100644 index 0000000..bca20a9 --- /dev/null +++ b/extern/portaudio/src/hostapi/wasapi/mingw-include/structuredquery.h @@ -0,0 +1,2478 @@ + + +/* this ALWAYS GENERATED file contains the definitions for the interfaces */ + + + /* File created by MIDL compiler version 7.00.0499 */ +/* Compiler settings for structuredquery.idl: + Oicf, W1, Zp8, env=Win32 (32b run) + protocol : dce , ms_ext, c_ext, robust + error checks: allocation ref bounds_check enum stub_data + VC __declspec() decoration level: + __declspec(uuid()), __declspec(selectany), __declspec(novtable) + DECLSPEC_UUID(), MIDL_INTERFACE() +*/ +//@@MIDL_FILE_HEADING( ) + +#pragma warning( disable: 4049 ) /* more than 64k source lines */ + + +/* verify that the version is high enough to compile this file*/ +#ifndef __REQUIRED_RPCNDR_H_VERSION__ +#define __REQUIRED_RPCNDR_H_VERSION__ 475 +#endif + +/* verify that the version is high enough to compile this file*/ +#ifndef __REQUIRED_RPCSAL_H_VERSION__ +#define __REQUIRED_RPCSAL_H_VERSION__ 100 +#endif + +#include "rpc.h" +#include "rpcndr.h" + +#ifndef __RPCNDR_H_VERSION__ +#error this stub requires an updated version of +#endif // __RPCNDR_H_VERSION__ + +#ifndef COM_NO_WINDOWS_H +#include "windows.h" +#include "ole2.h" +#endif /*COM_NO_WINDOWS_H*/ + +#ifndef __structuredquery_h__ +#define __structuredquery_h__ + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +/* Forward Declarations */ + +#ifndef __IQueryParser_FWD_DEFINED__ +#define __IQueryParser_FWD_DEFINED__ +typedef interface IQueryParser IQueryParser; +#endif /* __IQueryParser_FWD_DEFINED__ */ + + +#ifndef __IConditionFactory_FWD_DEFINED__ +#define __IConditionFactory_FWD_DEFINED__ +typedef interface IConditionFactory IConditionFactory; +#endif /* __IConditionFactory_FWD_DEFINED__ */ + + +#ifndef __IQuerySolution_FWD_DEFINED__ +#define __IQuerySolution_FWD_DEFINED__ +typedef interface IQuerySolution IQuerySolution; +#endif /* __IQuerySolution_FWD_DEFINED__ */ + + +#ifndef __ICondition_FWD_DEFINED__ +#define __ICondition_FWD_DEFINED__ +typedef interface ICondition ICondition; +#endif /* __ICondition_FWD_DEFINED__ */ + + +#ifndef __IConditionGenerator_FWD_DEFINED__ +#define __IConditionGenerator_FWD_DEFINED__ +typedef interface IConditionGenerator IConditionGenerator; +#endif /* __IConditionGenerator_FWD_DEFINED__ */ + + +#ifndef __IRichChunk_FWD_DEFINED__ +#define __IRichChunk_FWD_DEFINED__ +typedef interface IRichChunk IRichChunk; +#endif /* __IRichChunk_FWD_DEFINED__ */ + + +#ifndef __IInterval_FWD_DEFINED__ +#define __IInterval_FWD_DEFINED__ +typedef interface IInterval IInterval; +#endif /* __IInterval_FWD_DEFINED__ */ + + +#ifndef __IMetaData_FWD_DEFINED__ +#define __IMetaData_FWD_DEFINED__ +typedef interface IMetaData IMetaData; +#endif /* __IMetaData_FWD_DEFINED__ */ + + +#ifndef __IEntity_FWD_DEFINED__ +#define __IEntity_FWD_DEFINED__ +typedef interface IEntity IEntity; +#endif /* __IEntity_FWD_DEFINED__ */ + + +#ifndef __IRelationship_FWD_DEFINED__ +#define __IRelationship_FWD_DEFINED__ +typedef interface IRelationship IRelationship; +#endif /* __IRelationship_FWD_DEFINED__ */ + + +#ifndef __INamedEntity_FWD_DEFINED__ +#define __INamedEntity_FWD_DEFINED__ +typedef interface INamedEntity INamedEntity; +#endif /* __INamedEntity_FWD_DEFINED__ */ + + +#ifndef __ISchemaProvider_FWD_DEFINED__ +#define __ISchemaProvider_FWD_DEFINED__ +typedef interface ISchemaProvider ISchemaProvider; +#endif /* __ISchemaProvider_FWD_DEFINED__ */ + + +#ifndef __ITokenCollection_FWD_DEFINED__ +#define __ITokenCollection_FWD_DEFINED__ +typedef interface ITokenCollection ITokenCollection; +#endif /* __ITokenCollection_FWD_DEFINED__ */ + + +#ifndef __INamedEntityCollector_FWD_DEFINED__ +#define __INamedEntityCollector_FWD_DEFINED__ +typedef interface INamedEntityCollector INamedEntityCollector; +#endif /* __INamedEntityCollector_FWD_DEFINED__ */ + + +#ifndef __ISchemaLocalizerSupport_FWD_DEFINED__ +#define __ISchemaLocalizerSupport_FWD_DEFINED__ +typedef interface ISchemaLocalizerSupport ISchemaLocalizerSupport; +#endif /* __ISchemaLocalizerSupport_FWD_DEFINED__ */ + + +#ifndef __IQueryParserManager_FWD_DEFINED__ +#define __IQueryParserManager_FWD_DEFINED__ +typedef interface IQueryParserManager IQueryParserManager; +#endif /* __IQueryParserManager_FWD_DEFINED__ */ + + +#ifndef __QueryParser_FWD_DEFINED__ +#define __QueryParser_FWD_DEFINED__ + +#ifdef __cplusplus +typedef class QueryParser QueryParser; +#else +typedef struct QueryParser QueryParser; +#endif /* __cplusplus */ + +#endif /* __QueryParser_FWD_DEFINED__ */ + + +#ifndef __NegationCondition_FWD_DEFINED__ +#define __NegationCondition_FWD_DEFINED__ + +#ifdef __cplusplus +typedef class NegationCondition NegationCondition; +#else +typedef struct NegationCondition NegationCondition; +#endif /* __cplusplus */ + +#endif /* __NegationCondition_FWD_DEFINED__ */ + + +#ifndef __CompoundCondition_FWD_DEFINED__ +#define __CompoundCondition_FWD_DEFINED__ + +#ifdef __cplusplus +typedef class CompoundCondition CompoundCondition; +#else +typedef struct CompoundCondition CompoundCondition; +#endif /* __cplusplus */ + +#endif /* __CompoundCondition_FWD_DEFINED__ */ + + +#ifndef __LeafCondition_FWD_DEFINED__ +#define __LeafCondition_FWD_DEFINED__ + +#ifdef __cplusplus +typedef class LeafCondition LeafCondition; +#else +typedef struct LeafCondition LeafCondition; +#endif /* __cplusplus */ + +#endif /* __LeafCondition_FWD_DEFINED__ */ + + +#ifndef __ConditionFactory_FWD_DEFINED__ +#define __ConditionFactory_FWD_DEFINED__ + +#ifdef __cplusplus +typedef class ConditionFactory ConditionFactory; +#else +typedef struct ConditionFactory ConditionFactory; +#endif /* __cplusplus */ + +#endif /* __ConditionFactory_FWD_DEFINED__ */ + + +#ifndef __Interval_FWD_DEFINED__ +#define __Interval_FWD_DEFINED__ + +#ifdef __cplusplus +typedef class Interval Interval; +#else +typedef struct Interval Interval; +#endif /* __cplusplus */ + +#endif /* __Interval_FWD_DEFINED__ */ + + +#ifndef __QueryParserManager_FWD_DEFINED__ +#define __QueryParserManager_FWD_DEFINED__ + +#ifdef __cplusplus +typedef class QueryParserManager QueryParserManager; +#else +typedef struct QueryParserManager QueryParserManager; +#endif /* __cplusplus */ + +#endif /* __QueryParserManager_FWD_DEFINED__ */ + + +/* header files for imported files */ +#include "oaidl.h" +#include "ocidl.h" +#include "propidl.h" + +#ifdef __cplusplus +extern "C"{ +#endif + + +/* interface __MIDL_itf_structuredquery_0000_0000 */ +/* [local] */ + + + + + + + + + + + +typedef /* [v1_enum] */ +enum tagCONDITION_TYPE + { CT_AND_CONDITION = 0, + CT_OR_CONDITION = ( CT_AND_CONDITION + 1 ) , + CT_NOT_CONDITION = ( CT_OR_CONDITION + 1 ) , + CT_LEAF_CONDITION = ( CT_NOT_CONDITION + 1 ) + } CONDITION_TYPE; + +typedef /* [v1_enum] */ +enum tagCONDITION_OPERATION + { COP_IMPLICIT = 0, + COP_EQUAL = ( COP_IMPLICIT + 1 ) , + COP_NOTEQUAL = ( COP_EQUAL + 1 ) , + COP_LESSTHAN = ( COP_NOTEQUAL + 1 ) , + COP_GREATERTHAN = ( COP_LESSTHAN + 1 ) , + COP_LESSTHANOREQUAL = ( COP_GREATERTHAN + 1 ) , + COP_GREATERTHANOREQUAL = ( COP_LESSTHANOREQUAL + 1 ) , + COP_VALUE_STARTSWITH = ( COP_GREATERTHANOREQUAL + 1 ) , + COP_VALUE_ENDSWITH = ( COP_VALUE_STARTSWITH + 1 ) , + COP_VALUE_CONTAINS = ( COP_VALUE_ENDSWITH + 1 ) , + COP_VALUE_NOTCONTAINS = ( COP_VALUE_CONTAINS + 1 ) , + COP_DOSWILDCARDS = ( COP_VALUE_NOTCONTAINS + 1 ) , + COP_WORD_EQUAL = ( COP_DOSWILDCARDS + 1 ) , + COP_WORD_STARTSWITH = ( COP_WORD_EQUAL + 1 ) , + COP_APPLICATION_SPECIFIC = ( COP_WORD_STARTSWITH + 1 ) + } CONDITION_OPERATION; + +typedef /* [v1_enum] */ +enum tagSTRUCTURED_QUERY_SINGLE_OPTION + { SQSO_SCHEMA = 0, + SQSO_LOCALE_WORD_BREAKING = ( SQSO_SCHEMA + 1 ) , + SQSO_WORD_BREAKER = ( SQSO_LOCALE_WORD_BREAKING + 1 ) , + SQSO_NATURAL_SYNTAX = ( SQSO_WORD_BREAKER + 1 ) , + SQSO_AUTOMATIC_WILDCARD = ( SQSO_NATURAL_SYNTAX + 1 ) , + SQSO_TRACE_LEVEL = ( SQSO_AUTOMATIC_WILDCARD + 1 ) , + SQSO_LANGUAGE_KEYWORDS = ( SQSO_TRACE_LEVEL + 1 ) + } STRUCTURED_QUERY_SINGLE_OPTION; + +typedef /* [v1_enum] */ +enum tagSTRUCTURED_QUERY_MULTIOPTION + { SQMO_VIRTUAL_PROPERTY = 0, + SQMO_DEFAULT_PROPERTY = ( SQMO_VIRTUAL_PROPERTY + 1 ) , + SQMO_GENERATOR_FOR_TYPE = ( SQMO_DEFAULT_PROPERTY + 1 ) + } STRUCTURED_QUERY_MULTIOPTION; + +typedef /* [v1_enum] */ +enum tagSTRUCTURED_QUERY_PARSE_ERROR + { SQPE_NONE = 0, + SQPE_EXTRA_OPENING_PARENTHESIS = ( SQPE_NONE + 1 ) , + SQPE_EXTRA_CLOSING_PARENTHESIS = ( SQPE_EXTRA_OPENING_PARENTHESIS + 1 ) , + SQPE_IGNORED_MODIFIER = ( SQPE_EXTRA_CLOSING_PARENTHESIS + 1 ) , + SQPE_IGNORED_CONNECTOR = ( SQPE_IGNORED_MODIFIER + 1 ) , + SQPE_IGNORED_KEYWORD = ( SQPE_IGNORED_CONNECTOR + 1 ) , + SQPE_UNHANDLED = ( SQPE_IGNORED_KEYWORD + 1 ) + } STRUCTURED_QUERY_PARSE_ERROR; + +/* [v1_enum] */ +enum tagSTRUCTURED_QUERY_RESOLVE_OPTION + { SQRO_DONT_RESOLVE_DATETIME = 0x1, + SQRO_ALWAYS_ONE_INTERVAL = 0x2, + SQRO_DONT_SIMPLIFY_CONDITION_TREES = 0x4, + SQRO_DONT_MAP_RELATIONS = 0x8, + SQRO_DONT_RESOLVE_RANGES = 0x10, + SQRO_DONT_REMOVE_UNRESTRICTED_KEYWORDS = 0x20, + SQRO_DONT_SPLIT_WORDS = 0x40, + SQRO_IGNORE_PHRASE_ORDER = 0x80 + } ; +typedef int STRUCTURED_QUERY_RESOLVE_OPTION; + +typedef /* [v1_enum] */ +enum tagINTERVAL_LIMIT_KIND + { ILK_EXPLICIT_INCLUDED = 0, + ILK_EXPLICIT_EXCLUDED = ( ILK_EXPLICIT_INCLUDED + 1 ) , + ILK_NEGATIVE_INFINITY = ( ILK_EXPLICIT_EXCLUDED + 1 ) , + ILK_POSITIVE_INFINITY = ( ILK_NEGATIVE_INFINITY + 1 ) + } INTERVAL_LIMIT_KIND; + +typedef /* [v1_enum] */ +enum tagQUERY_PARSER_MANAGER_OPTION + { QPMO_SCHEMA_BINARY_NAME = 0, + QPMO_PRELOCALIZED_SCHEMA_BINARY_PATH = ( QPMO_SCHEMA_BINARY_NAME + 1 ) , + QPMO_UNLOCALIZED_SCHEMA_BINARY_PATH = ( QPMO_PRELOCALIZED_SCHEMA_BINARY_PATH + 1 ) , + QPMO_LOCALIZED_SCHEMA_BINARY_PATH = ( QPMO_UNLOCALIZED_SCHEMA_BINARY_PATH + 1 ) , + QPMO_APPEND_LCID_TO_LOCALIZED_PATH = ( QPMO_LOCALIZED_SCHEMA_BINARY_PATH + 1 ) , + QPMO_LOCALIZER_SUPPORT = ( QPMO_APPEND_LCID_TO_LOCALIZED_PATH + 1 ) + } QUERY_PARSER_MANAGER_OPTION; + + + +extern RPC_IF_HANDLE __MIDL_itf_structuredquery_0000_0000_v0_0_c_ifspec; +extern RPC_IF_HANDLE __MIDL_itf_structuredquery_0000_0000_v0_0_s_ifspec; + +#ifndef __IQueryParser_INTERFACE_DEFINED__ +#define __IQueryParser_INTERFACE_DEFINED__ + +/* interface IQueryParser */ +/* [unique][uuid][object] */ + + +EXTERN_C const IID IID_IQueryParser; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("2EBDEE67-3505-43f8-9946-EA44ABC8E5B0") + IQueryParser : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE Parse( + /* [in] */ __RPC__in LPCWSTR pszInputString, + /* [in] */ __RPC__in_opt IEnumUnknown *pCustomProperties, + /* [retval][out] */ __RPC__deref_out_opt IQuerySolution **ppSolution) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetOption( + /* [in] */ STRUCTURED_QUERY_SINGLE_OPTION option, + /* [in] */ __RPC__in const PROPVARIANT *pOptionValue) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetOption( + /* [in] */ STRUCTURED_QUERY_SINGLE_OPTION option, + /* [retval][out] */ __RPC__out PROPVARIANT *pOptionValue) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetMultiOption( + /* [in] */ STRUCTURED_QUERY_MULTIOPTION option, + /* [in] */ __RPC__in LPCWSTR pszOptionKey, + /* [in] */ __RPC__in const PROPVARIANT *pOptionValue) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetSchemaProvider( + /* [retval][out] */ __RPC__deref_out_opt ISchemaProvider **ppSchemaProvider) = 0; + + virtual HRESULT STDMETHODCALLTYPE RestateToString( + /* [in] */ __RPC__in_opt ICondition *pCondition, + /* [in] */ BOOL fUseEnglish, + /* [out] */ __RPC__deref_out_opt LPWSTR *ppszQueryString) = 0; + + virtual HRESULT STDMETHODCALLTYPE ParsePropertyValue( + /* [in] */ __RPC__in LPCWSTR pszPropertyName, + /* [in] */ __RPC__in LPCWSTR pszInputString, + /* [retval][out] */ __RPC__deref_out_opt IQuerySolution **ppSolution) = 0; + + virtual HRESULT STDMETHODCALLTYPE RestatePropertyValueToString( + /* [in] */ __RPC__in_opt ICondition *pCondition, + /* [in] */ BOOL fUseEnglish, + /* [out] */ __RPC__deref_out_opt LPWSTR *ppszPropertyName, + /* [out] */ __RPC__deref_out_opt LPWSTR *ppszQueryString) = 0; + + }; + +#else /* C style interface */ + + typedef struct IQueryParserVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IQueryParser * This, + /* [in] */ __RPC__in REFIID riid, + /* [iid_is][out] */ + __RPC__deref_out void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IQueryParser * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IQueryParser * This); + + HRESULT ( STDMETHODCALLTYPE *Parse )( + IQueryParser * This, + /* [in] */ __RPC__in LPCWSTR pszInputString, + /* [in] */ __RPC__in_opt IEnumUnknown *pCustomProperties, + /* [retval][out] */ __RPC__deref_out_opt IQuerySolution **ppSolution); + + HRESULT ( STDMETHODCALLTYPE *SetOption )( + IQueryParser * This, + /* [in] */ STRUCTURED_QUERY_SINGLE_OPTION option, + /* [in] */ __RPC__in const PROPVARIANT *pOptionValue); + + HRESULT ( STDMETHODCALLTYPE *GetOption )( + IQueryParser * This, + /* [in] */ STRUCTURED_QUERY_SINGLE_OPTION option, + /* [retval][out] */ __RPC__out PROPVARIANT *pOptionValue); + + HRESULT ( STDMETHODCALLTYPE *SetMultiOption )( + IQueryParser * This, + /* [in] */ STRUCTURED_QUERY_MULTIOPTION option, + /* [in] */ __RPC__in LPCWSTR pszOptionKey, + /* [in] */ __RPC__in const PROPVARIANT *pOptionValue); + + HRESULT ( STDMETHODCALLTYPE *GetSchemaProvider )( + IQueryParser * This, + /* [retval][out] */ __RPC__deref_out_opt ISchemaProvider **ppSchemaProvider); + + HRESULT ( STDMETHODCALLTYPE *RestateToString )( + IQueryParser * This, + /* [in] */ __RPC__in_opt ICondition *pCondition, + /* [in] */ BOOL fUseEnglish, + /* [out] */ __RPC__deref_out_opt LPWSTR *ppszQueryString); + + HRESULT ( STDMETHODCALLTYPE *ParsePropertyValue )( + IQueryParser * This, + /* [in] */ __RPC__in LPCWSTR pszPropertyName, + /* [in] */ __RPC__in LPCWSTR pszInputString, + /* [retval][out] */ __RPC__deref_out_opt IQuerySolution **ppSolution); + + HRESULT ( STDMETHODCALLTYPE *RestatePropertyValueToString )( + IQueryParser * This, + /* [in] */ __RPC__in_opt ICondition *pCondition, + /* [in] */ BOOL fUseEnglish, + /* [out] */ __RPC__deref_out_opt LPWSTR *ppszPropertyName, + /* [out] */ __RPC__deref_out_opt LPWSTR *ppszQueryString); + + END_INTERFACE + } IQueryParserVtbl; + + interface IQueryParser + { + CONST_VTBL struct IQueryParserVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IQueryParser_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IQueryParser_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IQueryParser_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IQueryParser_Parse(This,pszInputString,pCustomProperties,ppSolution) \ + ( (This)->lpVtbl -> Parse(This,pszInputString,pCustomProperties,ppSolution) ) + +#define IQueryParser_SetOption(This,option,pOptionValue) \ + ( (This)->lpVtbl -> SetOption(This,option,pOptionValue) ) + +#define IQueryParser_GetOption(This,option,pOptionValue) \ + ( (This)->lpVtbl -> GetOption(This,option,pOptionValue) ) + +#define IQueryParser_SetMultiOption(This,option,pszOptionKey,pOptionValue) \ + ( (This)->lpVtbl -> SetMultiOption(This,option,pszOptionKey,pOptionValue) ) + +#define IQueryParser_GetSchemaProvider(This,ppSchemaProvider) \ + ( (This)->lpVtbl -> GetSchemaProvider(This,ppSchemaProvider) ) + +#define IQueryParser_RestateToString(This,pCondition,fUseEnglish,ppszQueryString) \ + ( (This)->lpVtbl -> RestateToString(This,pCondition,fUseEnglish,ppszQueryString) ) + +#define IQueryParser_ParsePropertyValue(This,pszPropertyName,pszInputString,ppSolution) \ + ( (This)->lpVtbl -> ParsePropertyValue(This,pszPropertyName,pszInputString,ppSolution) ) + +#define IQueryParser_RestatePropertyValueToString(This,pCondition,fUseEnglish,ppszPropertyName,ppszQueryString) \ + ( (This)->lpVtbl -> RestatePropertyValueToString(This,pCondition,fUseEnglish,ppszPropertyName,ppszQueryString) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IQueryParser_INTERFACE_DEFINED__ */ + + +#ifndef __IConditionFactory_INTERFACE_DEFINED__ +#define __IConditionFactory_INTERFACE_DEFINED__ + +/* interface IConditionFactory */ +/* [unique][uuid][object] */ + + +EXTERN_C const IID IID_IConditionFactory; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("A5EFE073-B16F-474f-9F3E-9F8B497A3E08") + IConditionFactory : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE MakeNot( + /* [in] */ __RPC__in_opt ICondition *pSubCondition, + /* [in] */ BOOL simplify, + /* [retval][out] */ __RPC__deref_out_opt ICondition **ppResultQuery) = 0; + + virtual HRESULT STDMETHODCALLTYPE MakeAndOr( + /* [in] */ CONDITION_TYPE nodeType, + /* [in] */ __RPC__in_opt IEnumUnknown *pSubConditions, + /* [in] */ BOOL simplify, + /* [retval][out] */ __RPC__deref_out_opt ICondition **ppResultQuery) = 0; + + virtual HRESULT STDMETHODCALLTYPE MakeLeaf( + /* [unique][in] */ __RPC__in_opt LPCWSTR pszPropertyName, + /* [in] */ CONDITION_OPERATION op, + /* [unique][in] */ __RPC__in_opt LPCWSTR pszValueType, + /* [in] */ __RPC__in const PROPVARIANT *pValue, + /* [in] */ __RPC__in_opt IRichChunk *pPropertyNameTerm, + /* [in] */ __RPC__in_opt IRichChunk *pOperationTerm, + /* [in] */ __RPC__in_opt IRichChunk *pValueTerm, + /* [in] */ BOOL expand, + /* [retval][out] */ __RPC__deref_out_opt ICondition **ppResultQuery) = 0; + + virtual /* [local] */ HRESULT STDMETHODCALLTYPE Resolve( + /* [in] */ + __in ICondition *pConditionTree, + /* [in] */ + __in STRUCTURED_QUERY_RESOLVE_OPTION sqro, + /* [ref][in] */ + __in_opt const SYSTEMTIME *pstReferenceTime, + /* [retval][out] */ + __out ICondition **ppResolvedConditionTree) = 0; + + }; + +#else /* C style interface */ + + typedef struct IConditionFactoryVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IConditionFactory * This, + /* [in] */ __RPC__in REFIID riid, + /* [iid_is][out] */ + __RPC__deref_out void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IConditionFactory * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IConditionFactory * This); + + HRESULT ( STDMETHODCALLTYPE *MakeNot )( + IConditionFactory * This, + /* [in] */ __RPC__in_opt ICondition *pSubCondition, + /* [in] */ BOOL simplify, + /* [retval][out] */ __RPC__deref_out_opt ICondition **ppResultQuery); + + HRESULT ( STDMETHODCALLTYPE *MakeAndOr )( + IConditionFactory * This, + /* [in] */ CONDITION_TYPE nodeType, + /* [in] */ __RPC__in_opt IEnumUnknown *pSubConditions, + /* [in] */ BOOL simplify, + /* [retval][out] */ __RPC__deref_out_opt ICondition **ppResultQuery); + + HRESULT ( STDMETHODCALLTYPE *MakeLeaf )( + IConditionFactory * This, + /* [unique][in] */ __RPC__in_opt LPCWSTR pszPropertyName, + /* [in] */ CONDITION_OPERATION op, + /* [unique][in] */ __RPC__in_opt LPCWSTR pszValueType, + /* [in] */ __RPC__in const PROPVARIANT *pValue, + /* [in] */ __RPC__in_opt IRichChunk *pPropertyNameTerm, + /* [in] */ __RPC__in_opt IRichChunk *pOperationTerm, + /* [in] */ __RPC__in_opt IRichChunk *pValueTerm, + /* [in] */ BOOL expand, + /* [retval][out] */ __RPC__deref_out_opt ICondition **ppResultQuery); + + /* [local] */ HRESULT ( STDMETHODCALLTYPE *Resolve )( + IConditionFactory * This, + /* [in] */ + __in ICondition *pConditionTree, + /* [in] */ + __in STRUCTURED_QUERY_RESOLVE_OPTION sqro, + /* [ref][in] */ + __in_opt const SYSTEMTIME *pstReferenceTime, + /* [retval][out] */ + __out ICondition **ppResolvedConditionTree); + + END_INTERFACE + } IConditionFactoryVtbl; + + interface IConditionFactory + { + CONST_VTBL struct IConditionFactoryVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IConditionFactory_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IConditionFactory_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IConditionFactory_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IConditionFactory_MakeNot(This,pSubCondition,simplify,ppResultQuery) \ + ( (This)->lpVtbl -> MakeNot(This,pSubCondition,simplify,ppResultQuery) ) + +#define IConditionFactory_MakeAndOr(This,nodeType,pSubConditions,simplify,ppResultQuery) \ + ( (This)->lpVtbl -> MakeAndOr(This,nodeType,pSubConditions,simplify,ppResultQuery) ) + +#define IConditionFactory_MakeLeaf(This,pszPropertyName,op,pszValueType,pValue,pPropertyNameTerm,pOperationTerm,pValueTerm,expand,ppResultQuery) \ + ( (This)->lpVtbl -> MakeLeaf(This,pszPropertyName,op,pszValueType,pValue,pPropertyNameTerm,pOperationTerm,pValueTerm,expand,ppResultQuery) ) + +#define IConditionFactory_Resolve(This,pConditionTree,sqro,pstReferenceTime,ppResolvedConditionTree) \ + ( (This)->lpVtbl -> Resolve(This,pConditionTree,sqro,pstReferenceTime,ppResolvedConditionTree) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IConditionFactory_INTERFACE_DEFINED__ */ + + +#ifndef __IQuerySolution_INTERFACE_DEFINED__ +#define __IQuerySolution_INTERFACE_DEFINED__ + +/* interface IQuerySolution */ +/* [unique][uuid][object] */ + + +EXTERN_C const IID IID_IQuerySolution; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("D6EBC66B-8921-4193-AFDD-A1789FB7FF57") + IQuerySolution : public IConditionFactory + { + public: + virtual /* [local] */ HRESULT STDMETHODCALLTYPE GetQuery( + /* [out] */ + __out_opt ICondition **ppQueryNode, + /* [out] */ + __out_opt IEntity **ppMainType) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetErrors( + /* [in] */ __RPC__in REFIID riid, + /* [iid_is][retval][out] */ __RPC__deref_out_opt void **ppParseErrors) = 0; + + virtual /* [local] */ HRESULT STDMETHODCALLTYPE GetLexicalData( + /* [out] */ + __deref_opt_out LPWSTR *ppszInputString, + /* [out] */ + __out_opt ITokenCollection **ppTokens, + /* [out] */ + __out_opt LCID *pLocale, + /* [out] */ + __out_opt IUnknown **ppWordBreaker) = 0; + + }; + +#else /* C style interface */ + + typedef struct IQuerySolutionVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IQuerySolution * This, + /* [in] */ __RPC__in REFIID riid, + /* [iid_is][out] */ + __RPC__deref_out void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IQuerySolution * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IQuerySolution * This); + + HRESULT ( STDMETHODCALLTYPE *MakeNot )( + IQuerySolution * This, + /* [in] */ __RPC__in_opt ICondition *pSubCondition, + /* [in] */ BOOL simplify, + /* [retval][out] */ __RPC__deref_out_opt ICondition **ppResultQuery); + + HRESULT ( STDMETHODCALLTYPE *MakeAndOr )( + IQuerySolution * This, + /* [in] */ CONDITION_TYPE nodeType, + /* [in] */ __RPC__in_opt IEnumUnknown *pSubConditions, + /* [in] */ BOOL simplify, + /* [retval][out] */ __RPC__deref_out_opt ICondition **ppResultQuery); + + HRESULT ( STDMETHODCALLTYPE *MakeLeaf )( + IQuerySolution * This, + /* [unique][in] */ __RPC__in_opt LPCWSTR pszPropertyName, + /* [in] */ CONDITION_OPERATION op, + /* [unique][in] */ __RPC__in_opt LPCWSTR pszValueType, + /* [in] */ __RPC__in const PROPVARIANT *pValue, + /* [in] */ __RPC__in_opt IRichChunk *pPropertyNameTerm, + /* [in] */ __RPC__in_opt IRichChunk *pOperationTerm, + /* [in] */ __RPC__in_opt IRichChunk *pValueTerm, + /* [in] */ BOOL expand, + /* [retval][out] */ __RPC__deref_out_opt ICondition **ppResultQuery); + + /* [local] */ HRESULT ( STDMETHODCALLTYPE *Resolve )( + IQuerySolution * This, + /* [in] */ + __in ICondition *pConditionTree, + /* [in] */ + __in STRUCTURED_QUERY_RESOLVE_OPTION sqro, + /* [ref][in] */ + __in_opt const SYSTEMTIME *pstReferenceTime, + /* [retval][out] */ + __out ICondition **ppResolvedConditionTree); + + /* [local] */ HRESULT ( STDMETHODCALLTYPE *GetQuery )( + IQuerySolution * This, + /* [out] */ + __out_opt ICondition **ppQueryNode, + /* [out] */ + __out_opt IEntity **ppMainType); + + HRESULT ( STDMETHODCALLTYPE *GetErrors )( + IQuerySolution * This, + /* [in] */ __RPC__in REFIID riid, + /* [iid_is][retval][out] */ __RPC__deref_out_opt void **ppParseErrors); + + /* [local] */ HRESULT ( STDMETHODCALLTYPE *GetLexicalData )( + IQuerySolution * This, + /* [out] */ + __deref_opt_out LPWSTR *ppszInputString, + /* [out] */ + __out_opt ITokenCollection **ppTokens, + /* [out] */ + __out_opt LCID *pLocale, + /* [out] */ + __out_opt IUnknown **ppWordBreaker); + + END_INTERFACE + } IQuerySolutionVtbl; + + interface IQuerySolution + { + CONST_VTBL struct IQuerySolutionVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IQuerySolution_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IQuerySolution_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IQuerySolution_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IQuerySolution_MakeNot(This,pSubCondition,simplify,ppResultQuery) \ + ( (This)->lpVtbl -> MakeNot(This,pSubCondition,simplify,ppResultQuery) ) + +#define IQuerySolution_MakeAndOr(This,nodeType,pSubConditions,simplify,ppResultQuery) \ + ( (This)->lpVtbl -> MakeAndOr(This,nodeType,pSubConditions,simplify,ppResultQuery) ) + +#define IQuerySolution_MakeLeaf(This,pszPropertyName,op,pszValueType,pValue,pPropertyNameTerm,pOperationTerm,pValueTerm,expand,ppResultQuery) \ + ( (This)->lpVtbl -> MakeLeaf(This,pszPropertyName,op,pszValueType,pValue,pPropertyNameTerm,pOperationTerm,pValueTerm,expand,ppResultQuery) ) + +#define IQuerySolution_Resolve(This,pConditionTree,sqro,pstReferenceTime,ppResolvedConditionTree) \ + ( (This)->lpVtbl -> Resolve(This,pConditionTree,sqro,pstReferenceTime,ppResolvedConditionTree) ) + + +#define IQuerySolution_GetQuery(This,ppQueryNode,ppMainType) \ + ( (This)->lpVtbl -> GetQuery(This,ppQueryNode,ppMainType) ) + +#define IQuerySolution_GetErrors(This,riid,ppParseErrors) \ + ( (This)->lpVtbl -> GetErrors(This,riid,ppParseErrors) ) + +#define IQuerySolution_GetLexicalData(This,ppszInputString,ppTokens,pLocale,ppWordBreaker) \ + ( (This)->lpVtbl -> GetLexicalData(This,ppszInputString,ppTokens,pLocale,ppWordBreaker) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IQuerySolution_INTERFACE_DEFINED__ */ + + +#ifndef __ICondition_INTERFACE_DEFINED__ +#define __ICondition_INTERFACE_DEFINED__ + +/* interface ICondition */ +/* [unique][uuid][object] */ + + +EXTERN_C const IID IID_ICondition; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("0FC988D4-C935-4b97-A973-46282EA175C8") + ICondition : public IPersistStream + { + public: + virtual HRESULT STDMETHODCALLTYPE GetConditionType( + /* [retval][out] */ __RPC__out CONDITION_TYPE *pNodeType) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetSubConditions( + /* [in] */ __RPC__in REFIID riid, + /* [iid_is][retval][out] */ __RPC__deref_out_opt void **ppv) = 0; + + virtual /* [local] */ HRESULT STDMETHODCALLTYPE GetComparisonInfo( + /* [out] */ + __deref_opt_out LPWSTR *ppszPropertyName, + /* [out] */ + __out_opt CONDITION_OPERATION *pOperation, + /* [out] */ + __out_opt PROPVARIANT *pValue) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetValueType( + /* [retval][out] */ __RPC__deref_out_opt LPWSTR *ppszValueTypeName) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetValueNormalization( + /* [retval][out] */ __RPC__deref_out_opt LPWSTR *ppszNormalization) = 0; + + virtual /* [local] */ HRESULT STDMETHODCALLTYPE GetInputTerms( + /* [out] */ + __out_opt IRichChunk **ppPropertyTerm, + /* [out] */ + __out_opt IRichChunk **ppOperationTerm, + /* [out] */ + __out_opt IRichChunk **ppValueTerm) = 0; + + virtual HRESULT STDMETHODCALLTYPE Clone( + /* [retval][out] */ __RPC__deref_out_opt ICondition **ppc) = 0; + + }; + +#else /* C style interface */ + + typedef struct IConditionVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ICondition * This, + /* [in] */ __RPC__in REFIID riid, + /* [iid_is][out] */ + __RPC__deref_out void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ICondition * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ICondition * This); + + HRESULT ( STDMETHODCALLTYPE *GetClassID )( + ICondition * This, + /* [out] */ __RPC__out CLSID *pClassID); + + HRESULT ( STDMETHODCALLTYPE *IsDirty )( + ICondition * This); + + HRESULT ( STDMETHODCALLTYPE *Load )( + ICondition * This, + /* [unique][in] */ __RPC__in_opt IStream *pStm); + + HRESULT ( STDMETHODCALLTYPE *Save )( + ICondition * This, + /* [unique][in] */ __RPC__in_opt IStream *pStm, + /* [in] */ BOOL fClearDirty); + + HRESULT ( STDMETHODCALLTYPE *GetSizeMax )( + ICondition * This, + /* [out] */ __RPC__out ULARGE_INTEGER *pcbSize); + + HRESULT ( STDMETHODCALLTYPE *GetConditionType )( + ICondition * This, + /* [retval][out] */ __RPC__out CONDITION_TYPE *pNodeType); + + HRESULT ( STDMETHODCALLTYPE *GetSubConditions )( + ICondition * This, + /* [in] */ __RPC__in REFIID riid, + /* [iid_is][retval][out] */ __RPC__deref_out_opt void **ppv); + + /* [local] */ HRESULT ( STDMETHODCALLTYPE *GetComparisonInfo )( + ICondition * This, + /* [out] */ + __deref_opt_out LPWSTR *ppszPropertyName, + /* [out] */ + __out_opt CONDITION_OPERATION *pOperation, + /* [out] */ + __out_opt PROPVARIANT *pValue); + + HRESULT ( STDMETHODCALLTYPE *GetValueType )( + ICondition * This, + /* [retval][out] */ __RPC__deref_out_opt LPWSTR *ppszValueTypeName); + + HRESULT ( STDMETHODCALLTYPE *GetValueNormalization )( + ICondition * This, + /* [retval][out] */ __RPC__deref_out_opt LPWSTR *ppszNormalization); + + /* [local] */ HRESULT ( STDMETHODCALLTYPE *GetInputTerms )( + ICondition * This, + /* [out] */ + __out_opt IRichChunk **ppPropertyTerm, + /* [out] */ + __out_opt IRichChunk **ppOperationTerm, + /* [out] */ + __out_opt IRichChunk **ppValueTerm); + + HRESULT ( STDMETHODCALLTYPE *Clone )( + ICondition * This, + /* [retval][out] */ __RPC__deref_out_opt ICondition **ppc); + + END_INTERFACE + } IConditionVtbl; + + interface ICondition + { + CONST_VTBL struct IConditionVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ICondition_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ICondition_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ICondition_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ICondition_GetClassID(This,pClassID) \ + ( (This)->lpVtbl -> GetClassID(This,pClassID) ) + + +#define ICondition_IsDirty(This) \ + ( (This)->lpVtbl -> IsDirty(This) ) + +#define ICondition_Load(This,pStm) \ + ( (This)->lpVtbl -> Load(This,pStm) ) + +#define ICondition_Save(This,pStm,fClearDirty) \ + ( (This)->lpVtbl -> Save(This,pStm,fClearDirty) ) + +#define ICondition_GetSizeMax(This,pcbSize) \ + ( (This)->lpVtbl -> GetSizeMax(This,pcbSize) ) + + +#define ICondition_GetConditionType(This,pNodeType) \ + ( (This)->lpVtbl -> GetConditionType(This,pNodeType) ) + +#define ICondition_GetSubConditions(This,riid,ppv) \ + ( (This)->lpVtbl -> GetSubConditions(This,riid,ppv) ) + +#define ICondition_GetComparisonInfo(This,ppszPropertyName,pOperation,pValue) \ + ( (This)->lpVtbl -> GetComparisonInfo(This,ppszPropertyName,pOperation,pValue) ) + +#define ICondition_GetValueType(This,ppszValueTypeName) \ + ( (This)->lpVtbl -> GetValueType(This,ppszValueTypeName) ) + +#define ICondition_GetValueNormalization(This,ppszNormalization) \ + ( (This)->lpVtbl -> GetValueNormalization(This,ppszNormalization) ) + +#define ICondition_GetInputTerms(This,ppPropertyTerm,ppOperationTerm,ppValueTerm) \ + ( (This)->lpVtbl -> GetInputTerms(This,ppPropertyTerm,ppOperationTerm,ppValueTerm) ) + +#define ICondition_Clone(This,ppc) \ + ( (This)->lpVtbl -> Clone(This,ppc) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ICondition_INTERFACE_DEFINED__ */ + + +#ifndef __IConditionGenerator_INTERFACE_DEFINED__ +#define __IConditionGenerator_INTERFACE_DEFINED__ + +/* interface IConditionGenerator */ +/* [unique][uuid][object] */ + + +EXTERN_C const IID IID_IConditionGenerator; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("92D2CC58-4386-45a3-B98C-7E0CE64A4117") + IConditionGenerator : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE Initialize( + /* [in] */ __RPC__in_opt ISchemaProvider *pSchemaProvider) = 0; + + virtual HRESULT STDMETHODCALLTYPE RecognizeNamedEntities( + /* [in] */ __RPC__in LPCWSTR pszInputString, + /* [in] */ LCID lcid, + /* [in] */ __RPC__in_opt ITokenCollection *pTokenCollection, + /* [out][in] */ __RPC__inout_opt INamedEntityCollector *pNamedEntities) = 0; + + virtual HRESULT STDMETHODCALLTYPE GenerateForLeaf( + /* [in] */ __RPC__in_opt IConditionFactory *pConditionFactory, + /* [unique][in] */ __RPC__in_opt LPCWSTR pszPropertyName, + /* [in] */ CONDITION_OPERATION op, + /* [unique][in] */ __RPC__in_opt LPCWSTR pszValueType, + /* [in] */ __RPC__in LPCWSTR pszValue, + /* [unique][in] */ __RPC__in_opt LPCWSTR pszValue2, + /* [in] */ __RPC__in_opt IRichChunk *pPropertyNameTerm, + /* [in] */ __RPC__in_opt IRichChunk *pOperationTerm, + /* [in] */ __RPC__in_opt IRichChunk *pValueTerm, + /* [in] */ BOOL automaticWildcard, + /* [out] */ __RPC__out BOOL *pNoStringQuery, + /* [retval][out] */ __RPC__deref_out_opt ICondition **ppQueryExpression) = 0; + + virtual /* [local] */ HRESULT STDMETHODCALLTYPE DefaultPhrase( + /* [unique][in] */ LPCWSTR pszValueType, + /* [in] */ const PROPVARIANT *ppropvar, + /* [in] */ BOOL fUseEnglish, + /* [retval][out] */ + __deref_opt_out LPWSTR *ppszPhrase) = 0; + + }; + +#else /* C style interface */ + + typedef struct IConditionGeneratorVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IConditionGenerator * This, + /* [in] */ __RPC__in REFIID riid, + /* [iid_is][out] */ + __RPC__deref_out void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IConditionGenerator * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IConditionGenerator * This); + + HRESULT ( STDMETHODCALLTYPE *Initialize )( + IConditionGenerator * This, + /* [in] */ __RPC__in_opt ISchemaProvider *pSchemaProvider); + + HRESULT ( STDMETHODCALLTYPE *RecognizeNamedEntities )( + IConditionGenerator * This, + /* [in] */ __RPC__in LPCWSTR pszInputString, + /* [in] */ LCID lcid, + /* [in] */ __RPC__in_opt ITokenCollection *pTokenCollection, + /* [out][in] */ __RPC__inout_opt INamedEntityCollector *pNamedEntities); + + HRESULT ( STDMETHODCALLTYPE *GenerateForLeaf )( + IConditionGenerator * This, + /* [in] */ __RPC__in_opt IConditionFactory *pConditionFactory, + /* [unique][in] */ __RPC__in_opt LPCWSTR pszPropertyName, + /* [in] */ CONDITION_OPERATION op, + /* [unique][in] */ __RPC__in_opt LPCWSTR pszValueType, + /* [in] */ __RPC__in LPCWSTR pszValue, + /* [unique][in] */ __RPC__in_opt LPCWSTR pszValue2, + /* [in] */ __RPC__in_opt IRichChunk *pPropertyNameTerm, + /* [in] */ __RPC__in_opt IRichChunk *pOperationTerm, + /* [in] */ __RPC__in_opt IRichChunk *pValueTerm, + /* [in] */ BOOL automaticWildcard, + /* [out] */ __RPC__out BOOL *pNoStringQuery, + /* [retval][out] */ __RPC__deref_out_opt ICondition **ppQueryExpression); + + /* [local] */ HRESULT ( STDMETHODCALLTYPE *DefaultPhrase )( + IConditionGenerator * This, + /* [unique][in] */ LPCWSTR pszValueType, + /* [in] */ const PROPVARIANT *ppropvar, + /* [in] */ BOOL fUseEnglish, + /* [retval][out] */ + __deref_opt_out LPWSTR *ppszPhrase); + + END_INTERFACE + } IConditionGeneratorVtbl; + + interface IConditionGenerator + { + CONST_VTBL struct IConditionGeneratorVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IConditionGenerator_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IConditionGenerator_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IConditionGenerator_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IConditionGenerator_Initialize(This,pSchemaProvider) \ + ( (This)->lpVtbl -> Initialize(This,pSchemaProvider) ) + +#define IConditionGenerator_RecognizeNamedEntities(This,pszInputString,lcid,pTokenCollection,pNamedEntities) \ + ( (This)->lpVtbl -> RecognizeNamedEntities(This,pszInputString,lcid,pTokenCollection,pNamedEntities) ) + +#define IConditionGenerator_GenerateForLeaf(This,pConditionFactory,pszPropertyName,op,pszValueType,pszValue,pszValue2,pPropertyNameTerm,pOperationTerm,pValueTerm,automaticWildcard,pNoStringQuery,ppQueryExpression) \ + ( (This)->lpVtbl -> GenerateForLeaf(This,pConditionFactory,pszPropertyName,op,pszValueType,pszValue,pszValue2,pPropertyNameTerm,pOperationTerm,pValueTerm,automaticWildcard,pNoStringQuery,ppQueryExpression) ) + +#define IConditionGenerator_DefaultPhrase(This,pszValueType,ppropvar,fUseEnglish,ppszPhrase) \ + ( (This)->lpVtbl -> DefaultPhrase(This,pszValueType,ppropvar,fUseEnglish,ppszPhrase) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IConditionGenerator_INTERFACE_DEFINED__ */ + + +#ifndef __IRichChunk_INTERFACE_DEFINED__ +#define __IRichChunk_INTERFACE_DEFINED__ + +/* interface IRichChunk */ +/* [unique][uuid][object] */ + + +EXTERN_C const IID IID_IRichChunk; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("4FDEF69C-DBC9-454e-9910-B34F3C64B510") + IRichChunk : public IUnknown + { + public: + virtual /* [local] */ HRESULT STDMETHODCALLTYPE GetData( + /* [out] */ + __out_opt ULONG *pFirstPos, + /* [out] */ + __out_opt ULONG *pLength, + /* [out] */ + __deref_opt_out LPWSTR *ppsz, + /* [out] */ + __out_opt PROPVARIANT *pValue) = 0; + + }; + +#else /* C style interface */ + + typedef struct IRichChunkVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IRichChunk * This, + /* [in] */ __RPC__in REFIID riid, + /* [iid_is][out] */ + __RPC__deref_out void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IRichChunk * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IRichChunk * This); + + /* [local] */ HRESULT ( STDMETHODCALLTYPE *GetData )( + IRichChunk * This, + /* [out] */ + __out_opt ULONG *pFirstPos, + /* [out] */ + __out_opt ULONG *pLength, + /* [out] */ + __deref_opt_out LPWSTR *ppsz, + /* [out] */ + __out_opt PROPVARIANT *pValue); + + END_INTERFACE + } IRichChunkVtbl; + + interface IRichChunk + { + CONST_VTBL struct IRichChunkVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IRichChunk_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IRichChunk_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IRichChunk_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IRichChunk_GetData(This,pFirstPos,pLength,ppsz,pValue) \ + ( (This)->lpVtbl -> GetData(This,pFirstPos,pLength,ppsz,pValue) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IRichChunk_INTERFACE_DEFINED__ */ + + +#ifndef __IInterval_INTERFACE_DEFINED__ +#define __IInterval_INTERFACE_DEFINED__ + +/* interface IInterval */ +/* [unique][uuid][object] */ + + +EXTERN_C const IID IID_IInterval; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("6BF0A714-3C18-430b-8B5D-83B1C234D3DB") + IInterval : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE GetLimits( + /* [out] */ __RPC__out INTERVAL_LIMIT_KIND *pilkLower, + /* [out] */ __RPC__out PROPVARIANT *ppropvarLower, + /* [out] */ __RPC__out INTERVAL_LIMIT_KIND *pilkUpper, + /* [out] */ __RPC__out PROPVARIANT *ppropvarUpper) = 0; + + }; + +#else /* C style interface */ + + typedef struct IIntervalVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IInterval * This, + /* [in] */ __RPC__in REFIID riid, + /* [iid_is][out] */ + __RPC__deref_out void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IInterval * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IInterval * This); + + HRESULT ( STDMETHODCALLTYPE *GetLimits )( + IInterval * This, + /* [out] */ __RPC__out INTERVAL_LIMIT_KIND *pilkLower, + /* [out] */ __RPC__out PROPVARIANT *ppropvarLower, + /* [out] */ __RPC__out INTERVAL_LIMIT_KIND *pilkUpper, + /* [out] */ __RPC__out PROPVARIANT *ppropvarUpper); + + END_INTERFACE + } IIntervalVtbl; + + interface IInterval + { + CONST_VTBL struct IIntervalVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IInterval_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IInterval_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IInterval_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IInterval_GetLimits(This,pilkLower,ppropvarLower,pilkUpper,ppropvarUpper) \ + ( (This)->lpVtbl -> GetLimits(This,pilkLower,ppropvarLower,pilkUpper,ppropvarUpper) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IInterval_INTERFACE_DEFINED__ */ + + +#ifndef __IMetaData_INTERFACE_DEFINED__ +#define __IMetaData_INTERFACE_DEFINED__ + +/* interface IMetaData */ +/* [unique][uuid][object][helpstring] */ + + +EXTERN_C const IID IID_IMetaData; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("780102B0-C43B-4876-BC7B-5E9BA5C88794") + IMetaData : public IUnknown + { + public: + virtual /* [local] */ HRESULT STDMETHODCALLTYPE GetData( + /* [out] */ + __deref_opt_out LPWSTR *ppszKey, + /* [out] */ + __deref_opt_out LPWSTR *ppszValue) = 0; + + }; + +#else /* C style interface */ + + typedef struct IMetaDataVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IMetaData * This, + /* [in] */ __RPC__in REFIID riid, + /* [iid_is][out] */ + __RPC__deref_out void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IMetaData * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IMetaData * This); + + /* [local] */ HRESULT ( STDMETHODCALLTYPE *GetData )( + IMetaData * This, + /* [out] */ + __deref_opt_out LPWSTR *ppszKey, + /* [out] */ + __deref_opt_out LPWSTR *ppszValue); + + END_INTERFACE + } IMetaDataVtbl; + + interface IMetaData + { + CONST_VTBL struct IMetaDataVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IMetaData_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IMetaData_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IMetaData_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IMetaData_GetData(This,ppszKey,ppszValue) \ + ( (This)->lpVtbl -> GetData(This,ppszKey,ppszValue) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IMetaData_INTERFACE_DEFINED__ */ + + +/* interface __MIDL_itf_structuredquery_0000_0008 */ +/* [local] */ + + + + +extern RPC_IF_HANDLE __MIDL_itf_structuredquery_0000_0008_v0_0_c_ifspec; +extern RPC_IF_HANDLE __MIDL_itf_structuredquery_0000_0008_v0_0_s_ifspec; + +#ifndef __IEntity_INTERFACE_DEFINED__ +#define __IEntity_INTERFACE_DEFINED__ + +/* interface IEntity */ +/* [unique][object][uuid][helpstring] */ + + +EXTERN_C const IID IID_IEntity; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("24264891-E80B-4fd3-B7CE-4FF2FAE8931F") + IEntity : public IUnknown + { + public: + virtual /* [local] */ HRESULT STDMETHODCALLTYPE Name( + /* [retval][out] */ + __deref_opt_out LPWSTR *ppszName) = 0; + + virtual HRESULT STDMETHODCALLTYPE Base( + /* [retval][out] */ __RPC__deref_out_opt IEntity **pBaseEntity) = 0; + + virtual HRESULT STDMETHODCALLTYPE Relationships( + /* [in] */ __RPC__in REFIID riid, + /* [iid_is][retval][out] */ __RPC__deref_out_opt void **pRelationships) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetRelationship( + /* [in] */ __RPC__in LPCWSTR pszRelationName, + /* [retval][out] */ __RPC__deref_out_opt IRelationship **pRelationship) = 0; + + virtual HRESULT STDMETHODCALLTYPE MetaData( + /* [in] */ __RPC__in REFIID riid, + /* [iid_is][retval][out] */ __RPC__deref_out_opt void **pMetaData) = 0; + + virtual HRESULT STDMETHODCALLTYPE NamedEntities( + /* [in] */ __RPC__in REFIID riid, + /* [iid_is][retval][out] */ __RPC__deref_out_opt void **pNamedEntities) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetNamedEntity( + /* [in] */ __RPC__in LPCWSTR pszValue, + /* [retval][out] */ __RPC__deref_out_opt INamedEntity **ppNamedEntity) = 0; + + virtual /* [local] */ HRESULT STDMETHODCALLTYPE DefaultPhrase( + /* [retval][out] */ + __deref_opt_out LPWSTR *ppszPhrase) = 0; + + }; + +#else /* C style interface */ + + typedef struct IEntityVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IEntity * This, + /* [in] */ __RPC__in REFIID riid, + /* [iid_is][out] */ + __RPC__deref_out void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IEntity * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IEntity * This); + + /* [local] */ HRESULT ( STDMETHODCALLTYPE *Name )( + IEntity * This, + /* [retval][out] */ + __deref_opt_out LPWSTR *ppszName); + + HRESULT ( STDMETHODCALLTYPE *Base )( + IEntity * This, + /* [retval][out] */ __RPC__deref_out_opt IEntity **pBaseEntity); + + HRESULT ( STDMETHODCALLTYPE *Relationships )( + IEntity * This, + /* [in] */ __RPC__in REFIID riid, + /* [iid_is][retval][out] */ __RPC__deref_out_opt void **pRelationships); + + HRESULT ( STDMETHODCALLTYPE *GetRelationship )( + IEntity * This, + /* [in] */ __RPC__in LPCWSTR pszRelationName, + /* [retval][out] */ __RPC__deref_out_opt IRelationship **pRelationship); + + HRESULT ( STDMETHODCALLTYPE *MetaData )( + IEntity * This, + /* [in] */ __RPC__in REFIID riid, + /* [iid_is][retval][out] */ __RPC__deref_out_opt void **pMetaData); + + HRESULT ( STDMETHODCALLTYPE *NamedEntities )( + IEntity * This, + /* [in] */ __RPC__in REFIID riid, + /* [iid_is][retval][out] */ __RPC__deref_out_opt void **pNamedEntities); + + HRESULT ( STDMETHODCALLTYPE *GetNamedEntity )( + IEntity * This, + /* [in] */ __RPC__in LPCWSTR pszValue, + /* [retval][out] */ __RPC__deref_out_opt INamedEntity **ppNamedEntity); + + /* [local] */ HRESULT ( STDMETHODCALLTYPE *DefaultPhrase )( + IEntity * This, + /* [retval][out] */ + __deref_opt_out LPWSTR *ppszPhrase); + + END_INTERFACE + } IEntityVtbl; + + interface IEntity + { + CONST_VTBL struct IEntityVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IEntity_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IEntity_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IEntity_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IEntity_Name(This,ppszName) \ + ( (This)->lpVtbl -> Name(This,ppszName) ) + +#define IEntity_Base(This,pBaseEntity) \ + ( (This)->lpVtbl -> Base(This,pBaseEntity) ) + +#define IEntity_Relationships(This,riid,pRelationships) \ + ( (This)->lpVtbl -> Relationships(This,riid,pRelationships) ) + +#define IEntity_GetRelationship(This,pszRelationName,pRelationship) \ + ( (This)->lpVtbl -> GetRelationship(This,pszRelationName,pRelationship) ) + +#define IEntity_MetaData(This,riid,pMetaData) \ + ( (This)->lpVtbl -> MetaData(This,riid,pMetaData) ) + +#define IEntity_NamedEntities(This,riid,pNamedEntities) \ + ( (This)->lpVtbl -> NamedEntities(This,riid,pNamedEntities) ) + +#define IEntity_GetNamedEntity(This,pszValue,ppNamedEntity) \ + ( (This)->lpVtbl -> GetNamedEntity(This,pszValue,ppNamedEntity) ) + +#define IEntity_DefaultPhrase(This,ppszPhrase) \ + ( (This)->lpVtbl -> DefaultPhrase(This,ppszPhrase) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IEntity_INTERFACE_DEFINED__ */ + + +#ifndef __IRelationship_INTERFACE_DEFINED__ +#define __IRelationship_INTERFACE_DEFINED__ + +/* interface IRelationship */ +/* [unique][object][uuid][helpstring] */ + + +EXTERN_C const IID IID_IRelationship; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("2769280B-5108-498c-9C7F-A51239B63147") + IRelationship : public IUnknown + { + public: + virtual /* [local] */ HRESULT STDMETHODCALLTYPE Name( + /* [retval][out] */ + __deref_opt_out LPWSTR *ppszName) = 0; + + virtual HRESULT STDMETHODCALLTYPE IsReal( + /* [retval][out] */ __RPC__out BOOL *pIsReal) = 0; + + virtual HRESULT STDMETHODCALLTYPE Destination( + /* [retval][out] */ __RPC__deref_out_opt IEntity **pDestinationEntity) = 0; + + virtual HRESULT STDMETHODCALLTYPE MetaData( + /* [in] */ __RPC__in REFIID riid, + /* [iid_is][retval][out] */ __RPC__deref_out_opt void **pMetaData) = 0; + + virtual /* [local] */ HRESULT STDMETHODCALLTYPE DefaultPhrase( + /* [retval][out] */ + __deref_opt_out LPWSTR *ppszPhrase) = 0; + + }; + +#else /* C style interface */ + + typedef struct IRelationshipVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IRelationship * This, + /* [in] */ __RPC__in REFIID riid, + /* [iid_is][out] */ + __RPC__deref_out void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IRelationship * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IRelationship * This); + + /* [local] */ HRESULT ( STDMETHODCALLTYPE *Name )( + IRelationship * This, + /* [retval][out] */ + __deref_opt_out LPWSTR *ppszName); + + HRESULT ( STDMETHODCALLTYPE *IsReal )( + IRelationship * This, + /* [retval][out] */ __RPC__out BOOL *pIsReal); + + HRESULT ( STDMETHODCALLTYPE *Destination )( + IRelationship * This, + /* [retval][out] */ __RPC__deref_out_opt IEntity **pDestinationEntity); + + HRESULT ( STDMETHODCALLTYPE *MetaData )( + IRelationship * This, + /* [in] */ __RPC__in REFIID riid, + /* [iid_is][retval][out] */ __RPC__deref_out_opt void **pMetaData); + + /* [local] */ HRESULT ( STDMETHODCALLTYPE *DefaultPhrase )( + IRelationship * This, + /* [retval][out] */ + __deref_opt_out LPWSTR *ppszPhrase); + + END_INTERFACE + } IRelationshipVtbl; + + interface IRelationship + { + CONST_VTBL struct IRelationshipVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IRelationship_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IRelationship_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IRelationship_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IRelationship_Name(This,ppszName) \ + ( (This)->lpVtbl -> Name(This,ppszName) ) + +#define IRelationship_IsReal(This,pIsReal) \ + ( (This)->lpVtbl -> IsReal(This,pIsReal) ) + +#define IRelationship_Destination(This,pDestinationEntity) \ + ( (This)->lpVtbl -> Destination(This,pDestinationEntity) ) + +#define IRelationship_MetaData(This,riid,pMetaData) \ + ( (This)->lpVtbl -> MetaData(This,riid,pMetaData) ) + +#define IRelationship_DefaultPhrase(This,ppszPhrase) \ + ( (This)->lpVtbl -> DefaultPhrase(This,ppszPhrase) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IRelationship_INTERFACE_DEFINED__ */ + + +#ifndef __INamedEntity_INTERFACE_DEFINED__ +#define __INamedEntity_INTERFACE_DEFINED__ + +/* interface INamedEntity */ +/* [unique][uuid][object][helpstring] */ + + +EXTERN_C const IID IID_INamedEntity; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("ABDBD0B1-7D54-49fb-AB5C-BFF4130004CD") + INamedEntity : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE GetValue( + /* [retval][out] */ __RPC__deref_out_opt LPWSTR *ppszValue) = 0; + + virtual /* [local] */ HRESULT STDMETHODCALLTYPE DefaultPhrase( + /* [retval][out] */ + __deref_opt_out LPWSTR *ppszPhrase) = 0; + + }; + +#else /* C style interface */ + + typedef struct INamedEntityVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + INamedEntity * This, + /* [in] */ __RPC__in REFIID riid, + /* [iid_is][out] */ + __RPC__deref_out void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + INamedEntity * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + INamedEntity * This); + + HRESULT ( STDMETHODCALLTYPE *GetValue )( + INamedEntity * This, + /* [retval][out] */ __RPC__deref_out_opt LPWSTR *ppszValue); + + /* [local] */ HRESULT ( STDMETHODCALLTYPE *DefaultPhrase )( + INamedEntity * This, + /* [retval][out] */ + __deref_opt_out LPWSTR *ppszPhrase); + + END_INTERFACE + } INamedEntityVtbl; + + interface INamedEntity + { + CONST_VTBL struct INamedEntityVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define INamedEntity_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define INamedEntity_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define INamedEntity_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define INamedEntity_GetValue(This,ppszValue) \ + ( (This)->lpVtbl -> GetValue(This,ppszValue) ) + +#define INamedEntity_DefaultPhrase(This,ppszPhrase) \ + ( (This)->lpVtbl -> DefaultPhrase(This,ppszPhrase) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __INamedEntity_INTERFACE_DEFINED__ */ + + +#ifndef __ISchemaProvider_INTERFACE_DEFINED__ +#define __ISchemaProvider_INTERFACE_DEFINED__ + +/* interface ISchemaProvider */ +/* [unique][object][uuid][helpstring] */ + + +EXTERN_C const IID IID_ISchemaProvider; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("8CF89BCB-394C-49b2-AE28-A59DD4ED7F68") + ISchemaProvider : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE Entities( + /* [in] */ __RPC__in REFIID riid, + /* [iid_is][retval][out] */ __RPC__deref_out_opt void **pEntities) = 0; + + virtual HRESULT STDMETHODCALLTYPE RootEntity( + /* [retval][out] */ __RPC__deref_out_opt IEntity **pRootEntity) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetEntity( + /* [in] */ __RPC__in LPCWSTR pszEntityName, + /* [retval][out] */ __RPC__deref_out_opt IEntity **pEntity) = 0; + + virtual HRESULT STDMETHODCALLTYPE MetaData( + /* [in] */ __RPC__in REFIID riid, + /* [iid_is][retval][out] */ __RPC__deref_out_opt void **pMetaData) = 0; + + virtual HRESULT STDMETHODCALLTYPE Localize( + /* [in] */ LCID lcid, + /* [in] */ __RPC__in_opt ISchemaLocalizerSupport *pSchemaLocalizerSupport) = 0; + + virtual HRESULT STDMETHODCALLTYPE SaveBinary( + /* [in] */ __RPC__in LPCWSTR pszSchemaBinaryPath) = 0; + + virtual HRESULT STDMETHODCALLTYPE LookupAuthoredNamedEntity( + /* [in] */ __RPC__in_opt IEntity *pEntity, + /* [in] */ __RPC__in LPCWSTR pszInputString, + /* [in] */ __RPC__in_opt ITokenCollection *pTokenCollection, + /* [in] */ ULONG cTokensBegin, + /* [out] */ __RPC__out ULONG *pcTokensLength, + /* [out] */ __RPC__deref_out_opt LPWSTR *ppszValue) = 0; + + }; + +#else /* C style interface */ + + typedef struct ISchemaProviderVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ISchemaProvider * This, + /* [in] */ __RPC__in REFIID riid, + /* [iid_is][out] */ + __RPC__deref_out void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ISchemaProvider * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ISchemaProvider * This); + + HRESULT ( STDMETHODCALLTYPE *Entities )( + ISchemaProvider * This, + /* [in] */ __RPC__in REFIID riid, + /* [iid_is][retval][out] */ __RPC__deref_out_opt void **pEntities); + + HRESULT ( STDMETHODCALLTYPE *RootEntity )( + ISchemaProvider * This, + /* [retval][out] */ __RPC__deref_out_opt IEntity **pRootEntity); + + HRESULT ( STDMETHODCALLTYPE *GetEntity )( + ISchemaProvider * This, + /* [in] */ __RPC__in LPCWSTR pszEntityName, + /* [retval][out] */ __RPC__deref_out_opt IEntity **pEntity); + + HRESULT ( STDMETHODCALLTYPE *MetaData )( + ISchemaProvider * This, + /* [in] */ __RPC__in REFIID riid, + /* [iid_is][retval][out] */ __RPC__deref_out_opt void **pMetaData); + + HRESULT ( STDMETHODCALLTYPE *Localize )( + ISchemaProvider * This, + /* [in] */ LCID lcid, + /* [in] */ __RPC__in_opt ISchemaLocalizerSupport *pSchemaLocalizerSupport); + + HRESULT ( STDMETHODCALLTYPE *SaveBinary )( + ISchemaProvider * This, + /* [in] */ __RPC__in LPCWSTR pszSchemaBinaryPath); + + HRESULT ( STDMETHODCALLTYPE *LookupAuthoredNamedEntity )( + ISchemaProvider * This, + /* [in] */ __RPC__in_opt IEntity *pEntity, + /* [in] */ __RPC__in LPCWSTR pszInputString, + /* [in] */ __RPC__in_opt ITokenCollection *pTokenCollection, + /* [in] */ ULONG cTokensBegin, + /* [out] */ __RPC__out ULONG *pcTokensLength, + /* [out] */ __RPC__deref_out_opt LPWSTR *ppszValue); + + END_INTERFACE + } ISchemaProviderVtbl; + + interface ISchemaProvider + { + CONST_VTBL struct ISchemaProviderVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ISchemaProvider_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ISchemaProvider_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ISchemaProvider_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ISchemaProvider_Entities(This,riid,pEntities) \ + ( (This)->lpVtbl -> Entities(This,riid,pEntities) ) + +#define ISchemaProvider_RootEntity(This,pRootEntity) \ + ( (This)->lpVtbl -> RootEntity(This,pRootEntity) ) + +#define ISchemaProvider_GetEntity(This,pszEntityName,pEntity) \ + ( (This)->lpVtbl -> GetEntity(This,pszEntityName,pEntity) ) + +#define ISchemaProvider_MetaData(This,riid,pMetaData) \ + ( (This)->lpVtbl -> MetaData(This,riid,pMetaData) ) + +#define ISchemaProvider_Localize(This,lcid,pSchemaLocalizerSupport) \ + ( (This)->lpVtbl -> Localize(This,lcid,pSchemaLocalizerSupport) ) + +#define ISchemaProvider_SaveBinary(This,pszSchemaBinaryPath) \ + ( (This)->lpVtbl -> SaveBinary(This,pszSchemaBinaryPath) ) + +#define ISchemaProvider_LookupAuthoredNamedEntity(This,pEntity,pszInputString,pTokenCollection,cTokensBegin,pcTokensLength,ppszValue) \ + ( (This)->lpVtbl -> LookupAuthoredNamedEntity(This,pEntity,pszInputString,pTokenCollection,cTokensBegin,pcTokensLength,ppszValue) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ISchemaProvider_INTERFACE_DEFINED__ */ + + +#ifndef __ITokenCollection_INTERFACE_DEFINED__ +#define __ITokenCollection_INTERFACE_DEFINED__ + +/* interface ITokenCollection */ +/* [unique][object][uuid][helpstring] */ + + +EXTERN_C const IID IID_ITokenCollection; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("22D8B4F2-F577-4adb-A335-C2AE88416FAB") + ITokenCollection : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE NumberOfTokens( + __RPC__in ULONG *pCount) = 0; + + virtual /* [local] */ HRESULT STDMETHODCALLTYPE GetToken( + /* [in] */ ULONG i, + /* [out] */ + __out_opt ULONG *pBegin, + /* [out] */ + __out_opt ULONG *pLength, + /* [out] */ + __deref_opt_out LPWSTR *ppsz) = 0; + + }; + +#else /* C style interface */ + + typedef struct ITokenCollectionVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ITokenCollection * This, + /* [in] */ __RPC__in REFIID riid, + /* [iid_is][out] */ + __RPC__deref_out void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ITokenCollection * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ITokenCollection * This); + + HRESULT ( STDMETHODCALLTYPE *NumberOfTokens )( + ITokenCollection * This, + __RPC__in ULONG *pCount); + + /* [local] */ HRESULT ( STDMETHODCALLTYPE *GetToken )( + ITokenCollection * This, + /* [in] */ ULONG i, + /* [out] */ + __out_opt ULONG *pBegin, + /* [out] */ + __out_opt ULONG *pLength, + /* [out] */ + __deref_opt_out LPWSTR *ppsz); + + END_INTERFACE + } ITokenCollectionVtbl; + + interface ITokenCollection + { + CONST_VTBL struct ITokenCollectionVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ITokenCollection_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ITokenCollection_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ITokenCollection_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ITokenCollection_NumberOfTokens(This,pCount) \ + ( (This)->lpVtbl -> NumberOfTokens(This,pCount) ) + +#define ITokenCollection_GetToken(This,i,pBegin,pLength,ppsz) \ + ( (This)->lpVtbl -> GetToken(This,i,pBegin,pLength,ppsz) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ITokenCollection_INTERFACE_DEFINED__ */ + + +/* interface __MIDL_itf_structuredquery_0000_0013 */ +/* [local] */ + +typedef /* [public][public][v1_enum] */ +enum __MIDL___MIDL_itf_structuredquery_0000_0013_0001 + { NEC_LOW = 0, + NEC_MEDIUM = ( NEC_LOW + 1 ) , + NEC_HIGH = ( NEC_MEDIUM + 1 ) + } NAMED_ENTITY_CERTAINTY; + + + +extern RPC_IF_HANDLE __MIDL_itf_structuredquery_0000_0013_v0_0_c_ifspec; +extern RPC_IF_HANDLE __MIDL_itf_structuredquery_0000_0013_v0_0_s_ifspec; + +#ifndef __INamedEntityCollector_INTERFACE_DEFINED__ +#define __INamedEntityCollector_INTERFACE_DEFINED__ + +/* interface INamedEntityCollector */ +/* [unique][object][uuid][helpstring] */ + + +EXTERN_C const IID IID_INamedEntityCollector; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("AF2440F6-8AFC-47d0-9A7F-396A0ACFB43D") + INamedEntityCollector : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE Add( + /* [in] */ ULONG beginSpan, + /* [in] */ ULONG endSpan, + /* [in] */ ULONG beginActual, + /* [in] */ ULONG endActual, + /* [in] */ __RPC__in_opt IEntity *pType, + /* [in] */ __RPC__in LPCWSTR pszValue, + /* [in] */ NAMED_ENTITY_CERTAINTY certainty) = 0; + + }; + +#else /* C style interface */ + + typedef struct INamedEntityCollectorVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + INamedEntityCollector * This, + /* [in] */ __RPC__in REFIID riid, + /* [iid_is][out] */ + __RPC__deref_out void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + INamedEntityCollector * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + INamedEntityCollector * This); + + HRESULT ( STDMETHODCALLTYPE *Add )( + INamedEntityCollector * This, + /* [in] */ ULONG beginSpan, + /* [in] */ ULONG endSpan, + /* [in] */ ULONG beginActual, + /* [in] */ ULONG endActual, + /* [in] */ __RPC__in_opt IEntity *pType, + /* [in] */ __RPC__in LPCWSTR pszValue, + /* [in] */ NAMED_ENTITY_CERTAINTY certainty); + + END_INTERFACE + } INamedEntityCollectorVtbl; + + interface INamedEntityCollector + { + CONST_VTBL struct INamedEntityCollectorVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define INamedEntityCollector_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define INamedEntityCollector_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define INamedEntityCollector_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define INamedEntityCollector_Add(This,beginSpan,endSpan,beginActual,endActual,pType,pszValue,certainty) \ + ( (This)->lpVtbl -> Add(This,beginSpan,endSpan,beginActual,endActual,pType,pszValue,certainty) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __INamedEntityCollector_INTERFACE_DEFINED__ */ + + +#ifndef __ISchemaLocalizerSupport_INTERFACE_DEFINED__ +#define __ISchemaLocalizerSupport_INTERFACE_DEFINED__ + +/* interface ISchemaLocalizerSupport */ +/* [unique][object][uuid] */ + + +EXTERN_C const IID IID_ISchemaLocalizerSupport; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("CA3FDCA2-BFBE-4eed-90D7-0CAEF0A1BDA1") + ISchemaLocalizerSupport : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE Localize( + /* [in] */ __RPC__in LPCWSTR pszGlobalString, + /* [retval][out] */ __RPC__deref_out_opt LPWSTR *ppszLocalString) = 0; + + }; + +#else /* C style interface */ + + typedef struct ISchemaLocalizerSupportVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + ISchemaLocalizerSupport * This, + /* [in] */ __RPC__in REFIID riid, + /* [iid_is][out] */ + __RPC__deref_out void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + ISchemaLocalizerSupport * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + ISchemaLocalizerSupport * This); + + HRESULT ( STDMETHODCALLTYPE *Localize )( + ISchemaLocalizerSupport * This, + /* [in] */ __RPC__in LPCWSTR pszGlobalString, + /* [retval][out] */ __RPC__deref_out_opt LPWSTR *ppszLocalString); + + END_INTERFACE + } ISchemaLocalizerSupportVtbl; + + interface ISchemaLocalizerSupport + { + CONST_VTBL struct ISchemaLocalizerSupportVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define ISchemaLocalizerSupport_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define ISchemaLocalizerSupport_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define ISchemaLocalizerSupport_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define ISchemaLocalizerSupport_Localize(This,pszGlobalString,ppszLocalString) \ + ( (This)->lpVtbl -> Localize(This,pszGlobalString,ppszLocalString) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __ISchemaLocalizerSupport_INTERFACE_DEFINED__ */ + + +#ifndef __IQueryParserManager_INTERFACE_DEFINED__ +#define __IQueryParserManager_INTERFACE_DEFINED__ + +/* interface IQueryParserManager */ +/* [unique][object][uuid] */ + + +EXTERN_C const IID IID_IQueryParserManager; + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("A879E3C4-AF77-44fb-8F37-EBD1487CF920") + IQueryParserManager : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE CreateLoadedParser( + /* [in] */ __RPC__in LPCWSTR pszCatalog, + /* [in] */ LANGID langidForKeywords, + /* [in] */ __RPC__in REFIID riid, + /* [iid_is][retval][out] */ __RPC__deref_out_opt void **ppQueryParser) = 0; + + virtual HRESULT STDMETHODCALLTYPE InitializeOptions( + /* [in] */ BOOL fUnderstandNQS, + /* [in] */ BOOL fAutoWildCard, + /* [in] */ __RPC__in_opt IQueryParser *pQueryParser) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetOption( + /* [in] */ QUERY_PARSER_MANAGER_OPTION option, + /* [in] */ __RPC__in const PROPVARIANT *pOptionValue) = 0; + + }; + +#else /* C style interface */ + + typedef struct IQueryParserManagerVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE *QueryInterface )( + IQueryParserManager * This, + /* [in] */ __RPC__in REFIID riid, + /* [iid_is][out] */ + __RPC__deref_out void **ppvObject); + + ULONG ( STDMETHODCALLTYPE *AddRef )( + IQueryParserManager * This); + + ULONG ( STDMETHODCALLTYPE *Release )( + IQueryParserManager * This); + + HRESULT ( STDMETHODCALLTYPE *CreateLoadedParser )( + IQueryParserManager * This, + /* [in] */ __RPC__in LPCWSTR pszCatalog, + /* [in] */ LANGID langidForKeywords, + /* [in] */ __RPC__in REFIID riid, + /* [iid_is][retval][out] */ __RPC__deref_out_opt void **ppQueryParser); + + HRESULT ( STDMETHODCALLTYPE *InitializeOptions )( + IQueryParserManager * This, + /* [in] */ BOOL fUnderstandNQS, + /* [in] */ BOOL fAutoWildCard, + /* [in] */ __RPC__in_opt IQueryParser *pQueryParser); + + HRESULT ( STDMETHODCALLTYPE *SetOption )( + IQueryParserManager * This, + /* [in] */ QUERY_PARSER_MANAGER_OPTION option, + /* [in] */ __RPC__in const PROPVARIANT *pOptionValue); + + END_INTERFACE + } IQueryParserManagerVtbl; + + interface IQueryParserManager + { + CONST_VTBL struct IQueryParserManagerVtbl *lpVtbl; + }; + + + +#ifdef COBJMACROS + + +#define IQueryParserManager_QueryInterface(This,riid,ppvObject) \ + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) + +#define IQueryParserManager_AddRef(This) \ + ( (This)->lpVtbl -> AddRef(This) ) + +#define IQueryParserManager_Release(This) \ + ( (This)->lpVtbl -> Release(This) ) + + +#define IQueryParserManager_CreateLoadedParser(This,pszCatalog,langidForKeywords,riid,ppQueryParser) \ + ( (This)->lpVtbl -> CreateLoadedParser(This,pszCatalog,langidForKeywords,riid,ppQueryParser) ) + +#define IQueryParserManager_InitializeOptions(This,fUnderstandNQS,fAutoWildCard,pQueryParser) \ + ( (This)->lpVtbl -> InitializeOptions(This,fUnderstandNQS,fAutoWildCard,pQueryParser) ) + +#define IQueryParserManager_SetOption(This,option,pOptionValue) \ + ( (This)->lpVtbl -> SetOption(This,option,pOptionValue) ) + +#endif /* COBJMACROS */ + + +#endif /* C style interface */ + + + + +#endif /* __IQueryParserManager_INTERFACE_DEFINED__ */ + + + +#ifndef __StructuredQuery1_LIBRARY_DEFINED__ +#define __StructuredQuery1_LIBRARY_DEFINED__ + +/* library StructuredQuery1 */ +/* [version][uuid] */ + + +EXTERN_C const IID LIBID_StructuredQuery1; + +EXTERN_C const CLSID CLSID_QueryParser; + +#ifdef __cplusplus + +class DECLSPEC_UUID("B72F8FD8-0FAB-4dd9-BDBF-245A6CE1485B") +QueryParser; +#endif + +EXTERN_C const CLSID CLSID_NegationCondition; + +#ifdef __cplusplus + +class DECLSPEC_UUID("8DE9C74C-605A-4acd-BEE3-2B222AA2D23D") +NegationCondition; +#endif + +EXTERN_C const CLSID CLSID_CompoundCondition; + +#ifdef __cplusplus + +class DECLSPEC_UUID("116F8D13-101E-4fa5-84D4-FF8279381935") +CompoundCondition; +#endif + +EXTERN_C const CLSID CLSID_LeafCondition; + +#ifdef __cplusplus + +class DECLSPEC_UUID("52F15C89-5A17-48e1-BBCD-46A3F89C7CC2") +LeafCondition; +#endif + +EXTERN_C const CLSID CLSID_ConditionFactory; + +#ifdef __cplusplus + +class DECLSPEC_UUID("E03E85B0-7BE3-4000-BA98-6C13DE9FA486") +ConditionFactory; +#endif + +EXTERN_C const CLSID CLSID_Interval; + +#ifdef __cplusplus + +class DECLSPEC_UUID("D957171F-4BF9-4de2-BCD5-C70A7CA55836") +Interval; +#endif + +EXTERN_C const CLSID CLSID_QueryParserManager; + +#ifdef __cplusplus + +class DECLSPEC_UUID("5088B39A-29B4-4d9d-8245-4EE289222F66") +QueryParserManager; +#endif +#endif /* __StructuredQuery1_LIBRARY_DEFINED__ */ + +/* Additional Prototypes for ALL interfaces */ + +unsigned long __RPC_USER BSTR_UserSize( unsigned long *, unsigned long , BSTR * ); +unsigned char * __RPC_USER BSTR_UserMarshal( unsigned long *, unsigned char *, BSTR * ); +unsigned char * __RPC_USER BSTR_UserUnmarshal(unsigned long *, unsigned char *, BSTR * ); +void __RPC_USER BSTR_UserFree( unsigned long *, BSTR * ); + +unsigned long __RPC_USER LPSAFEARRAY_UserSize( unsigned long *, unsigned long , LPSAFEARRAY * ); +unsigned char * __RPC_USER LPSAFEARRAY_UserMarshal( unsigned long *, unsigned char *, LPSAFEARRAY * ); +unsigned char * __RPC_USER LPSAFEARRAY_UserUnmarshal(unsigned long *, unsigned char *, LPSAFEARRAY * ); +void __RPC_USER LPSAFEARRAY_UserFree( unsigned long *, LPSAFEARRAY * ); + +/* end of Additional Prototypes */ + +#ifdef __cplusplus +} +#endif + +#endif + + + diff --git a/extern/portaudio/src/hostapi/wasapi/pa_win_wasapi.c b/extern/portaudio/src/hostapi/wasapi/pa_win_wasapi.c new file mode 100644 index 0000000..f4b3186 --- /dev/null +++ b/extern/portaudio/src/hostapi/wasapi/pa_win_wasapi.c @@ -0,0 +1,6300 @@ +/* + * Portable Audio I/O Library WASAPI implementation + * Copyright (c) 2006-2010 David Viens + * Copyright (c) 2010-2019 Dmitry Kostjuchenko + * + * Based on the Open Source API proposed by Ross Bencina + * Copyright (c) 1999-2019 Ross Bencina, Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +/** @file + @ingroup hostapi_src + @brief WASAPI implementation of support for a host API. + @note pa_wasapi currently requires minimum VC 2005, and the latest Vista SDK +*/ + +#include +#include +#include +#include + +// Max device count (if defined) causes max constant device count in the device list that +// enables PaWasapi_UpdateDeviceList() API and makes it possible to update WASAPI list dynamically +#ifndef PA_WASAPI_MAX_CONST_DEVICE_COUNT + #define PA_WASAPI_MAX_CONST_DEVICE_COUNT 0 // Force basic behavior by defining 0 if not defined by user +#endif + +// Fallback from Event to the Polling method in case if latency is higher than 21.33ms, as it allows to use +// 100% of CPU inside the PA's callback. +// Note: Some USB DAC drivers are buggy when Polling method is forced in Exclusive mode, audio output becomes +// unstable with a lot of interruptions, therefore this define is optional. The default behavior is to +// not change the Event mode to Polling and use the mode which user provided. +//#define PA_WASAPI_FORCE_POLL_IF_LARGE_BUFFER + +// WinRT +#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP) + #define PA_WINRT + #define INITGUID +#endif + +// WASAPI +// using adjustments for MinGW build from @mgeier/MXE +// https://github.com/mxe/mxe/commit/f4bbc45682f021948bdaefd9fd476e2a04c4740f +#include // must be before other Wasapi headers +#if defined(_MSC_VER) && (_MSC_VER >= 1400) || defined(__MINGW64_VERSION_MAJOR) + #include + #define COBJMACROS + #include + #include + #define INITGUID // Avoid additional linkage of static libs, excessive code will be optimized out by the compiler +#ifndef _MSC_VER + #include +#endif + #include + #include + #include // Used to get IKsJackDescription interface + #undef INITGUID +#endif +#ifndef __MWERKS__ + #include + #include +#endif + +#include "pa_util.h" +#include "pa_allocation.h" +#include "pa_hostapi.h" +#include "pa_stream.h" +#include "pa_cpuload.h" +#include "pa_process.h" +#include "pa_win_wasapi.h" +#include "pa_debugprint.h" +#include "pa_ringbuffer.h" +#include "pa_win_coinitialize.h" + +#if !defined(NTDDI_VERSION) + + #undef WINVER + #undef _WIN32_WINNT + #define WINVER 0x0600 // VISTA + #define _WIN32_WINNT WINVER + + #ifndef _AVRT_ //<< fix MinGW dummy compile by defining missing type: AVRT_PRIORITY + typedef enum _AVRT_PRIORITY + { + AVRT_PRIORITY_LOW = -1, + AVRT_PRIORITY_NORMAL, + AVRT_PRIORITY_HIGH, + AVRT_PRIORITY_CRITICAL + } AVRT_PRIORITY, *PAVRT_PRIORITY; + #endif + + #include // << for IID/CLSID + #include + #include + + #ifndef __LPCGUID_DEFINED__ + #define __LPCGUID_DEFINED__ + typedef const GUID *LPCGUID; + #endif + + #ifndef PROPERTYKEY_DEFINED + #define PROPERTYKEY_DEFINED + typedef struct _tagpropertykey + { + GUID fmtid; + DWORD pid; + } PROPERTYKEY; + #endif + + #ifdef __midl_proxy + #define __MIDL_CONST + #else + #define __MIDL_CONST const + #endif + + #ifdef WIN64 + #include + typedef LONG NTSTATUS; + #define FASTCALL + #include + #include + #else + typedef struct _BYTE_BLOB + { + unsigned long clSize; + unsigned char abData[ 1 ]; + } BYTE_BLOB; + typedef /* [unique] */ __RPC_unique_pointer BYTE_BLOB *UP_BYTE_BLOB; + typedef LONGLONG REFERENCE_TIME; + #define NONAMELESSUNION + #endif + + #ifndef WAVE_FORMAT_IEEE_FLOAT + #define WAVE_FORMAT_IEEE_FLOAT 0x0003 // 32-bit floating-point + #endif + + #ifndef __MINGW_EXTENSION + #if defined(__GNUC__) || defined(__GNUG__) + #define __MINGW_EXTENSION __extension__ + #else + #define __MINGW_EXTENSION + #endif + #endif + + #include + #include + #define COBJMACROS + #define INITGUID // Avoid additional linkage of static libs, excessive code will be optimized out by the compiler + #include + #include + #include + #include + #include // Used to get IKsJackDescription interface + #undef INITGUID + +#endif // NTDDI_VERSION + +// Missing declarations for WinRT +#ifdef PA_WINRT + + #define DEVICE_STATE_ACTIVE 0x00000001 + + typedef enum _EDataFlow + { + eRender = 0, + eCapture = ( eRender + 1 ) , + eAll = ( eCapture + 1 ) , + EDataFlow_enum_count = ( eAll + 1 ) + } + EDataFlow; + + typedef enum _EndpointFormFactor + { + RemoteNetworkDevice = 0, + Speakers = ( RemoteNetworkDevice + 1 ) , + LineLevel = ( Speakers + 1 ) , + Headphones = ( LineLevel + 1 ) , + Microphone = ( Headphones + 1 ) , + Headset = ( Microphone + 1 ) , + Handset = ( Headset + 1 ) , + UnknownDigitalPassthrough = ( Handset + 1 ) , + SPDIF = ( UnknownDigitalPassthrough + 1 ) , + HDMI = ( SPDIF + 1 ) , + UnknownFormFactor = ( HDMI + 1 ) + } + EndpointFormFactor; + +#endif + +#ifndef GUID_SECT + #define GUID_SECT +#endif + +#define __DEFINE_GUID(n,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) static const GUID n GUID_SECT = {l,w1,w2,{b1,b2,b3,b4,b5,b6,b7,b8}} +#define __DEFINE_IID(n,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) static const IID n GUID_SECT = {l,w1,w2,{b1,b2,b3,b4,b5,b6,b7,b8}} +#define __DEFINE_CLSID(n,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) static const CLSID n GUID_SECT = {l,w1,w2,{b1,b2,b3,b4,b5,b6,b7,b8}} +#define PA_DEFINE_CLSID(className, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \ + __DEFINE_CLSID(pa_CLSID_##className, 0x##l, 0x##w1, 0x##w2, 0x##b1, 0x##b2, 0x##b3, 0x##b4, 0x##b5, 0x##b6, 0x##b7, 0x##b8) +#define PA_DEFINE_IID(interfaceName, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \ + __DEFINE_IID(pa_IID_##interfaceName, 0x##l, 0x##w1, 0x##w2, 0x##b1, 0x##b2, 0x##b3, 0x##b4, 0x##b5, 0x##b6, 0x##b7, 0x##b8) + +// "1CB9AD4C-DBFA-4c32-B178-C2F568A703B2" +PA_DEFINE_IID(IAudioClient, 1cb9ad4c, dbfa, 4c32, b1, 78, c2, f5, 68, a7, 03, b2); +// "726778CD-F60A-4EDA-82DE-E47610CD78AA" +PA_DEFINE_IID(IAudioClient2, 726778cd, f60a, 4eda, 82, de, e4, 76, 10, cd, 78, aa); +// "7ED4EE07-8E67-4CD4-8C1A-2B7A5987AD42" +PA_DEFINE_IID(IAudioClient3, 7ed4ee07, 8e67, 4cd4, 8c, 1a, 2b, 7a, 59, 87, ad, 42); +// "1BE09788-6894-4089-8586-9A2A6C265AC5" +PA_DEFINE_IID(IMMEndpoint, 1be09788, 6894, 4089, 85, 86, 9a, 2a, 6c, 26, 5a, c5); +// "A95664D2-9614-4F35-A746-DE8DB63617E6" +PA_DEFINE_IID(IMMDeviceEnumerator, a95664d2, 9614, 4f35, a7, 46, de, 8d, b6, 36, 17, e6); +// "BCDE0395-E52F-467C-8E3D-C4579291692E" +PA_DEFINE_CLSID(IMMDeviceEnumerator,bcde0395, e52f, 467c, 8e, 3d, c4, 57, 92, 91, 69, 2e); +// "F294ACFC-3146-4483-A7BF-ADDCA7C260E2" +PA_DEFINE_IID(IAudioRenderClient, f294acfc, 3146, 4483, a7, bf, ad, dc, a7, c2, 60, e2); +// "C8ADBD64-E71E-48a0-A4DE-185C395CD317" +PA_DEFINE_IID(IAudioCaptureClient, c8adbd64, e71e, 48a0, a4, de, 18, 5c, 39, 5c, d3, 17); +// *2A07407E-6497-4A18-9787-32F79BD0D98F* Or this?? +PA_DEFINE_IID(IDeviceTopology, 2A07407E, 6497, 4A18, 97, 87, 32, f7, 9b, d0, d9, 8f); +// *AE2DE0E4-5BCA-4F2D-AA46-5D13F8FDB3A9* +PA_DEFINE_IID(IPart, AE2DE0E4, 5BCA, 4F2D, aa, 46, 5d, 13, f8, fd, b3, a9); +// *4509F757-2D46-4637-8E62-CE7DB944F57B* +PA_DEFINE_IID(IKsJackDescription, 4509F757, 2D46, 4637, 8e, 62, ce, 7d, b9, 44, f5, 7b); + +// Media formats: +__DEFINE_GUID(pa_KSDATAFORMAT_SUBTYPE_PCM, 0x00000001, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 ); +__DEFINE_GUID(pa_KSDATAFORMAT_SUBTYPE_ADPCM, 0x00000002, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 ); +__DEFINE_GUID(pa_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, 0x00000003, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 ); + +#ifdef __IAudioClient2_INTERFACE_DEFINED__ +typedef enum _pa_AUDCLNT_STREAMOPTIONS { + pa_AUDCLNT_STREAMOPTIONS_NONE = 0x00, + pa_AUDCLNT_STREAMOPTIONS_RAW = 0x01, + pa_AUDCLNT_STREAMOPTIONS_MATCH_FORMAT = 0x02 +} pa_AUDCLNT_STREAMOPTIONS; +typedef struct _pa_AudioClientProperties { + UINT32 cbSize; + BOOL bIsOffload; + AUDIO_STREAM_CATEGORY eCategory; + pa_AUDCLNT_STREAMOPTIONS Options; +} pa_AudioClientProperties; +#define PA_AUDIOCLIENTPROPERTIES_SIZE_CATEGORY (sizeof(pa_AudioClientProperties) - sizeof(pa_AUDCLNT_STREAMOPTIONS)) +#define PA_AUDIOCLIENTPROPERTIES_SIZE_OPTIONS sizeof(pa_AudioClientProperties) +#endif // __IAudioClient2_INTERFACE_DEFINED__ + +/* use CreateThread for CYGWIN/Windows Mobile, _beginthreadex for all others */ +#if !defined(__CYGWIN__) && !defined(_WIN32_WCE) + #define CREATE_THREAD(PROC) (HANDLE)_beginthreadex( NULL, 0, (PROC), stream, 0, &stream->dwThreadId ) + #define PA_THREAD_FUNC static unsigned WINAPI + #define PA_THREAD_ID unsigned +#else + #define CREATE_THREAD(PROC) CreateThread( NULL, 0, (PROC), stream, 0, &stream->dwThreadId ) + #define PA_THREAD_FUNC static DWORD WINAPI + #define PA_THREAD_ID DWORD +#endif + +// Thread function forward decl. +PA_THREAD_FUNC ProcThreadEvent(void *param); +PA_THREAD_FUNC ProcThreadPoll(void *param); + +// Error codes (availabe since Windows 7) +#ifndef AUDCLNT_E_BUFFER_ERROR + #define AUDCLNT_E_BUFFER_ERROR AUDCLNT_ERR(0x018) +#endif +#ifndef AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED + #define AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED AUDCLNT_ERR(0x019) +#endif +#ifndef AUDCLNT_E_INVALID_DEVICE_PERIOD + #define AUDCLNT_E_INVALID_DEVICE_PERIOD AUDCLNT_ERR(0x020) +#endif + +// Stream flags (availabe since Windows 7) +#ifndef AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY + #define AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY 0x08000000 +#endif +#ifndef AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM + #define AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM 0x80000000 +#endif + +#define MAX_STR_LEN 512 + +#ifdef PA_WINRT + #define PA_WASAPI_DEVICE_ID_LEN 4096 +#endif + +enum { S_INPUT = 0, S_OUTPUT = 1, S_COUNT = 2, S_FULLDUPLEX = 0 }; + +// Number of packets which compose single contignous buffer. With trial and error it was calculated +// that WASAPI Input sub-system uses 6 packets per whole buffer. Please provide more information +// or corrections if available. +enum { WASAPI_PACKETS_PER_INPUT_BUFFER = 6 }; + +#define STATIC_ARRAY_SIZE(array) (sizeof(array)/sizeof(array[0])) + +#define PRINT(x) PA_DEBUG(x); + +#define PA_SKELETON_SET_LAST_HOST_ERROR( errorCode, errorText ) \ + PaUtil_SetLastHostErrorInfo( paWASAPI, errorCode, errorText ) + +#define PA_WASAPI__IS_FULLDUPLEX(STREAM) ((STREAM)->in.clientProc && (STREAM)->out.clientProc) + +#ifndef IF_FAILED_JUMP +#define IF_FAILED_JUMP(hr, label) if(FAILED(hr)) goto label; +#endif + +#ifndef IF_FAILED_INTERNAL_ERROR_JUMP +#define IF_FAILED_INTERNAL_ERROR_JUMP(hr, error, label) if(FAILED(hr)) { error = paInternalError; goto label; } +#endif + +#define SAFE_CLOSE(h) if ((h) != NULL) { CloseHandle((h)); (h) = NULL; } +#define SAFE_RELEASE(punk) if ((punk) != NULL) { (punk)->lpVtbl->Release((punk)); (punk) = NULL; } + +// Mixer function +typedef void (*MixMonoToStereoF) (void *__to, const void *__from, UINT32 count); + +// AVRT is the new "multimedia schedulling stuff" +#ifndef PA_WINRT +typedef BOOL (WINAPI *FAvRtCreateThreadOrderingGroup) (PHANDLE,PLARGE_INTEGER,GUID*,PLARGE_INTEGER); +typedef BOOL (WINAPI *FAvRtDeleteThreadOrderingGroup) (HANDLE); +typedef BOOL (WINAPI *FAvRtWaitOnThreadOrderingGroup) (HANDLE); +typedef HANDLE (WINAPI *FAvSetMmThreadCharacteristics) (LPCSTR,LPDWORD); +typedef BOOL (WINAPI *FAvRevertMmThreadCharacteristics)(HANDLE); +typedef BOOL (WINAPI *FAvSetMmThreadPriority) (HANDLE,AVRT_PRIORITY); +static HMODULE hDInputDLL = 0; +FAvRtCreateThreadOrderingGroup pAvRtCreateThreadOrderingGroup = NULL; +FAvRtDeleteThreadOrderingGroup pAvRtDeleteThreadOrderingGroup = NULL; +FAvRtWaitOnThreadOrderingGroup pAvRtWaitOnThreadOrderingGroup = NULL; +FAvSetMmThreadCharacteristics pAvSetMmThreadCharacteristics = NULL; +FAvRevertMmThreadCharacteristics pAvRevertMmThreadCharacteristics = NULL; +FAvSetMmThreadPriority pAvSetMmThreadPriority = NULL; +#endif + +#define _GetProc(fun, type, name) { \ + fun = (type) GetProcAddress(hDInputDLL,name); \ + if (fun == NULL) { \ + PRINT(("GetProcAddr failed for %s" ,name)); \ + return FALSE; \ + } \ + } \ + +// ------------------------------------------------------------------------------------------ +/* prototypes for functions declared in this file */ +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ +PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index ); +#ifdef __cplusplus +} +#endif /* __cplusplus */ +// dummy entry point for other compilers and sdks +// currently built using RC1 SDK (5600) +//#if _MSC_VER < 1400 +//PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex ) +//{ + //return paNoError; +//} +//#else + +// ------------------------------------------------------------------------------------------ +static void Terminate( struct PaUtilHostApiRepresentation *hostApi ); +static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi, + const PaStreamParameters *inputParameters, + const PaStreamParameters *outputParameters, + double sampleRate ); +static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, + PaStream** s, + const PaStreamParameters *inputParameters, + const PaStreamParameters *outputParameters, + double sampleRate, + unsigned long framesPerBuffer, + PaStreamFlags streamFlags, + PaStreamCallback *streamCallback, + void *userData ); +static PaError CloseStream( PaStream* stream ); +static PaError StartStream( PaStream *stream ); +static PaError StopStream( PaStream *stream ); +static PaError AbortStream( PaStream *stream ); +static PaError IsStreamStopped( PaStream *s ); +static PaError IsStreamActive( PaStream *stream ); +static PaTime GetStreamTime( PaStream *stream ); +static double GetStreamCpuLoad( PaStream* stream ); +static PaError ReadStream( PaStream* stream, void *buffer, unsigned long frames ); +static PaError WriteStream( PaStream* stream, const void *buffer, unsigned long frames ); +static signed long GetStreamReadAvailable( PaStream* stream ); +static signed long GetStreamWriteAvailable( PaStream* stream ); + +// ------------------------------------------------------------------------------------------ +/* + These are fields that can be gathered from IDevice and IAudioDevice PRIOR to Initialize, and + done in first pass i assume that neither of these will cause the Driver to "load", but again, + who knows how they implement their stuff + */ +typedef struct PaWasapiDeviceInfo +{ + // Device +#ifndef PA_WINRT + IMMDevice *device; +#endif + + // from GetId + WCHAR szDeviceID[MAX_STR_LEN]; + + // from GetState + DWORD state; + + // Fields filled from IAudioDevice (_prior_ to Initialize) + // from GetDevicePeriod( + REFERENCE_TIME DefaultDevicePeriod; + REFERENCE_TIME MinimumDevicePeriod; + + // Default format (setup through Control Panel by user) + WAVEFORMATEXTENSIBLE DefaultFormat; + + // Mix format (internal format used by WASAPI audio engine) + WAVEFORMATEXTENSIBLE MixFormat; + + // Fields filled from IMMEndpoint'sGetDataFlow + EDataFlow flow; + + // Formfactor + EndpointFormFactor formFactor; +} +PaWasapiDeviceInfo; + +// ------------------------------------------------------------------------------------------ +/* PaWasapiHostApiRepresentation - host api datastructure specific to this implementation */ +typedef struct +{ + PaUtilHostApiRepresentation inheritedHostApiRep; + PaUtilStreamInterface callbackStreamInterface; + PaUtilStreamInterface blockingStreamInterface; + + PaUtilAllocationGroup *allocations; + + /* implementation specific data goes here */ + + PaWinUtilComInitializationResult comInitializationResult; + + // this is the REAL number of devices, whether they are usefull to PA or not! + UINT32 deviceCount; + + WCHAR defaultRenderer[MAX_STR_LEN]; + WCHAR defaultCapturer[MAX_STR_LEN]; + + PaWasapiDeviceInfo *devInfo; + + // is TRUE when WOW64 Vista/7 Workaround is needed + BOOL useWOW64Workaround; +} +PaWasapiHostApiRepresentation; + +// ------------------------------------------------------------------------------------------ +/* PaWasapiAudioClientParams - audio client parameters */ +typedef struct PaWasapiAudioClientParams +{ + PaWasapiDeviceInfo *device_info; + PaStreamParameters stream_params; + PaWasapiStreamInfo wasapi_params; + UINT32 frames_per_buffer; + double sample_rate; + BOOL blocking; + BOOL full_duplex; + BOOL wow64_workaround; +} +PaWasapiAudioClientParams; + +// ------------------------------------------------------------------------------------------ +/* PaWasapiStream - a stream data structure specifically for this implementation */ +typedef struct PaWasapiSubStream +{ + IAudioClient *clientParent; +#ifndef PA_WINRT + IStream *clientStream; +#endif + IAudioClient *clientProc; + + WAVEFORMATEXTENSIBLE wavex; + UINT32 bufferSize; + REFERENCE_TIME deviceLatency; + REFERENCE_TIME period; + double latencySeconds; + UINT32 framesPerHostCallback; + AUDCLNT_SHAREMODE shareMode; + UINT32 streamFlags; // AUDCLNT_STREAMFLAGS_EVENTCALLBACK, ... + UINT32 flags; + PaWasapiAudioClientParams params; //!< parameters + + // Buffers + UINT32 buffers; //!< number of buffers used (from host side) + UINT32 framesPerBuffer; //!< number of frames per 1 buffer + BOOL userBufferAndHostMatch; + + // Used for Mono >> Stereo workaround, if driver does not support it + // (in Exclusive mode WASAPI usually refuses to operate with Mono (1-ch) + void *monoBuffer; //!< pointer to buffer + UINT32 monoBufferSize; //!< buffer size in bytes + MixMonoToStereoF monoMixer; //!< pointer to mixer function + + PaUtilRingBuffer *tailBuffer; //!< buffer with trailing sample for blocking mode operations (only for Input) + void *tailBufferMemory; //!< tail buffer memory region +} +PaWasapiSubStream; + +// ------------------------------------------------------------------------------------------ +/* PaWasapiHostProcessor - redirects processing data */ +typedef struct PaWasapiHostProcessor +{ + PaWasapiHostProcessorCallback processor; + void *userData; +} +PaWasapiHostProcessor; + +// ------------------------------------------------------------------------------------------ +typedef struct PaWasapiStream +{ + /* IMPLEMENT ME: rename this */ + PaUtilStreamRepresentation streamRepresentation; + PaUtilCpuLoadMeasurer cpuLoadMeasurer; + PaUtilBufferProcessor bufferProcessor; + + // input + PaWasapiSubStream in; + IAudioCaptureClient *captureClientParent; +#ifndef PA_WINRT + IStream *captureClientStream; +#endif + IAudioCaptureClient *captureClient; + IAudioEndpointVolume *inVol; + + // output + PaWasapiSubStream out; + IAudioRenderClient *renderClientParent; +#ifndef PA_WINRT + IStream *renderClientStream; +#endif + IAudioRenderClient *renderClient; + IAudioEndpointVolume *outVol; + + // event handles for event-driven processing mode + HANDLE event[S_COUNT]; + + // buffer mode + PaUtilHostBufferSizeMode bufferMode; + + // must be volatile to avoid race condition on user query while + // thread is being started + volatile BOOL running; + + PA_THREAD_ID dwThreadId; + HANDLE hThread; + HANDLE hCloseRequest; + HANDLE hThreadStart; //!< signalled by thread on start + HANDLE hThreadExit; //!< signalled by thread on exit + HANDLE hBlockingOpStreamRD; + HANDLE hBlockingOpStreamWR; + + // Host callback Output overrider + PaWasapiHostProcessor hostProcessOverrideOutput; + + // Host callback Input overrider + PaWasapiHostProcessor hostProcessOverrideInput; + + // Defines blocking/callback interface used + BOOL bBlocking; + + // Av Task (MM thread management) + HANDLE hAvTask; + + // Thread priority level + PaWasapiThreadPriority nThreadPriority; + + // State handler + PaWasapiStreamStateCallback fnStateHandler; + void *pStateHandlerUserData; +} +PaWasapiStream; + +// COM marshaling +static HRESULT MarshalSubStreamComPointers(PaWasapiSubStream *substream); +static HRESULT MarshalStreamComPointers(PaWasapiStream *stream); +static HRESULT UnmarshalSubStreamComPointers(PaWasapiSubStream *substream); +static HRESULT UnmarshalStreamComPointers(PaWasapiStream *stream); +static void ReleaseUnmarshaledSubComPointers(PaWasapiSubStream *substream); +static void ReleaseUnmarshaledComPointers(PaWasapiStream *stream); + +// Local methods +static void _StreamOnStop(PaWasapiStream *stream); +static void _StreamFinish(PaWasapiStream *stream); +static void _StreamCleanup(PaWasapiStream *stream); +static HRESULT _PollGetOutputFramesAvailable(PaWasapiStream *stream, UINT32 *available); +static HRESULT _PollGetInputFramesAvailable(PaWasapiStream *stream, UINT32 *available); +static void *PaWasapi_ReallocateMemory(void *prev, size_t size); +static void PaWasapi_FreeMemory(void *ptr); +static PaSampleFormat WaveToPaFormat(const WAVEFORMATEXTENSIBLE *fmtext); + +// Local statics +#ifdef PA_WINRT +static OLECHAR g_DefaultRenderId[PA_WASAPI_DEVICE_ID_LEN] = { 0 }; +static OLECHAR g_DefaultCaptureId[PA_WASAPI_DEVICE_ID_LEN] = { 0 }; +#endif + +// ------------------------------------------------------------------------------------------ +#define LogHostError(HRES) __LogHostError(HRES, __FUNCTION__, __FILE__, __LINE__) +static HRESULT __LogHostError(HRESULT res, const char *func, const char *file, int line) +{ + const char *text = NULL; + switch (res) + { + case S_OK: return res; + case E_POINTER :text ="E_POINTER"; break; + case E_INVALIDARG :text ="E_INVALIDARG"; break; + + case AUDCLNT_E_NOT_INITIALIZED :text ="AUDCLNT_E_NOT_INITIALIZED"; break; + case AUDCLNT_E_ALREADY_INITIALIZED :text ="AUDCLNT_E_ALREADY_INITIALIZED"; break; + case AUDCLNT_E_WRONG_ENDPOINT_TYPE :text ="AUDCLNT_E_WRONG_ENDPOINT_TYPE"; break; + case AUDCLNT_E_DEVICE_INVALIDATED :text ="AUDCLNT_E_DEVICE_INVALIDATED"; break; + case AUDCLNT_E_NOT_STOPPED :text ="AUDCLNT_E_NOT_STOPPED"; break; + case AUDCLNT_E_BUFFER_TOO_LARGE :text ="AUDCLNT_E_BUFFER_TOO_LARGE"; break; + case AUDCLNT_E_OUT_OF_ORDER :text ="AUDCLNT_E_OUT_OF_ORDER"; break; + case AUDCLNT_E_UNSUPPORTED_FORMAT :text ="AUDCLNT_E_UNSUPPORTED_FORMAT"; break; + case AUDCLNT_E_INVALID_SIZE :text ="AUDCLNT_E_INVALID_SIZE"; break; + case AUDCLNT_E_DEVICE_IN_USE :text ="AUDCLNT_E_DEVICE_IN_USE"; break; + case AUDCLNT_E_BUFFER_OPERATION_PENDING :text ="AUDCLNT_E_BUFFER_OPERATION_PENDING"; break; + case AUDCLNT_E_THREAD_NOT_REGISTERED :text ="AUDCLNT_E_THREAD_NOT_REGISTERED"; break; + case AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED :text ="AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED"; break; + case AUDCLNT_E_ENDPOINT_CREATE_FAILED :text ="AUDCLNT_E_ENDPOINT_CREATE_FAILED"; break; + case AUDCLNT_E_SERVICE_NOT_RUNNING :text ="AUDCLNT_E_SERVICE_NOT_RUNNING"; break; + case AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED :text ="AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED"; break; + case AUDCLNT_E_EXCLUSIVE_MODE_ONLY :text ="AUDCLNT_E_EXCLUSIVE_MODE_ONLY"; break; + case AUDCLNT_E_BUFDURATION_PERIOD_NOT_EQUAL :text ="AUDCLNT_E_BUFDURATION_PERIOD_NOT_EQUAL"; break; + case AUDCLNT_E_EVENTHANDLE_NOT_SET :text ="AUDCLNT_E_EVENTHANDLE_NOT_SET"; break; + case AUDCLNT_E_INCORRECT_BUFFER_SIZE :text ="AUDCLNT_E_INCORRECT_BUFFER_SIZE"; break; + case AUDCLNT_E_BUFFER_SIZE_ERROR :text ="AUDCLNT_E_BUFFER_SIZE_ERROR"; break; + case AUDCLNT_E_CPUUSAGE_EXCEEDED :text ="AUDCLNT_E_CPUUSAGE_EXCEEDED"; break; + case AUDCLNT_E_BUFFER_ERROR :text ="AUDCLNT_E_BUFFER_ERROR"; break; + case AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED :text ="AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED"; break; + case AUDCLNT_E_INVALID_DEVICE_PERIOD :text ="AUDCLNT_E_INVALID_DEVICE_PERIOD"; break; + +#ifdef AUDCLNT_E_INVALID_STREAM_FLAG + case AUDCLNT_E_INVALID_STREAM_FLAG :text ="AUDCLNT_E_INVALID_STREAM_FLAG"; break; +#endif +#ifdef AUDCLNT_E_ENDPOINT_OFFLOAD_NOT_CAPABLE + case AUDCLNT_E_ENDPOINT_OFFLOAD_NOT_CAPABLE :text ="AUDCLNT_E_ENDPOINT_OFFLOAD_NOT_CAPABLE"; break; +#endif +#ifdef AUDCLNT_E_OUT_OF_OFFLOAD_RESOURCES + case AUDCLNT_E_OUT_OF_OFFLOAD_RESOURCES :text ="AUDCLNT_E_OUT_OF_OFFLOAD_RESOURCES"; break; +#endif +#ifdef AUDCLNT_E_OFFLOAD_MODE_ONLY + case AUDCLNT_E_OFFLOAD_MODE_ONLY :text ="AUDCLNT_E_OFFLOAD_MODE_ONLY"; break; +#endif +#ifdef AUDCLNT_E_NONOFFLOAD_MODE_ONLY + case AUDCLNT_E_NONOFFLOAD_MODE_ONLY :text ="AUDCLNT_E_NONOFFLOAD_MODE_ONLY"; break; +#endif +#ifdef AUDCLNT_E_RESOURCES_INVALIDATED + case AUDCLNT_E_RESOURCES_INVALIDATED :text ="AUDCLNT_E_RESOURCES_INVALIDATED"; break; +#endif +#ifdef AUDCLNT_E_RAW_MODE_UNSUPPORTED + case AUDCLNT_E_RAW_MODE_UNSUPPORTED :text ="AUDCLNT_E_RAW_MODE_UNSUPPORTED"; break; +#endif +#ifdef AUDCLNT_E_ENGINE_PERIODICITY_LOCKED + case AUDCLNT_E_ENGINE_PERIODICITY_LOCKED :text ="AUDCLNT_E_ENGINE_PERIODICITY_LOCKED"; break; +#endif +#ifdef AUDCLNT_E_ENGINE_FORMAT_LOCKED + case AUDCLNT_E_ENGINE_FORMAT_LOCKED :text ="AUDCLNT_E_ENGINE_FORMAT_LOCKED"; break; +#endif + + case AUDCLNT_S_BUFFER_EMPTY :text ="AUDCLNT_S_BUFFER_EMPTY"; break; + case AUDCLNT_S_THREAD_ALREADY_REGISTERED :text ="AUDCLNT_S_THREAD_ALREADY_REGISTERED"; break; + case AUDCLNT_S_POSITION_STALLED :text ="AUDCLNT_S_POSITION_STALLED"; break; + + // other windows common errors: + case CO_E_NOTINITIALIZED :text ="CO_E_NOTINITIALIZED: you must call CoInitialize() before Pa_OpenStream()"; break; + + default: + text = "UNKNOWN ERROR"; + } + PRINT(("WASAPI ERROR HRESULT: 0x%X : %s\n [FUNCTION: %s FILE: %s {LINE: %d}]\n", res, text, func, file, line)); +#ifndef PA_ENABLE_DEBUG_OUTPUT + (void)func; (void)file; (void)line; +#endif + PA_SKELETON_SET_LAST_HOST_ERROR(res, text); + return res; +} + +// ------------------------------------------------------------------------------------------ +#define LogPaError(PAERR) __LogPaError(PAERR, __FUNCTION__, __FILE__, __LINE__) +static PaError __LogPaError(PaError err, const char *func, const char *file, int line) +{ + if (err == paNoError) + return err; + + PRINT(("WASAPI ERROR PAERROR: %i : %s\n [FUNCTION: %s FILE: %s {LINE: %d}]\n", err, Pa_GetErrorText(err), func, file, line)); +#ifndef PA_ENABLE_DEBUG_OUTPUT + (void)func; (void)file; (void)line; +#endif + return err; +} + +// ------------------------------------------------------------------------------------------ +/*! \class ThreadSleepScheduler + Allows to emulate thread sleep of less than 1 millisecond under Windows. Scheduler + calculates number of times the thread must run untill next sleep of 1 millisecond. + It does not make thread sleeping for real number of microseconds but rather controls + how many of imaginary microseconds the thread task can allow thread to sleep. +*/ +typedef struct ThreadIdleScheduler +{ + UINT32 m_idle_microseconds; //!< number of microseconds to sleep + UINT32 m_next_sleep; //!< next sleep round + UINT32 m_i; //!< current round iterator position + UINT32 m_resolution; //!< resolution in number of milliseconds +} +ThreadIdleScheduler; +//! Setup scheduler. +static void ThreadIdleScheduler_Setup(ThreadIdleScheduler *sched, UINT32 resolution, UINT32 microseconds) +{ + assert(microseconds != 0); + assert(resolution != 0); + assert((resolution * 1000) >= microseconds); + + memset(sched, 0, sizeof(*sched)); + + sched->m_idle_microseconds = microseconds; + sched->m_resolution = resolution; + sched->m_next_sleep = (resolution * 1000) / microseconds; +} +//! Iterate and check if can sleep. +static UINT32 ThreadIdleScheduler_NextSleep(ThreadIdleScheduler *sched) +{ + // advance and check if thread can sleep + if (++ sched->m_i == sched->m_next_sleep) + { + sched->m_i = 0; + return sched->m_resolution; + } + return 0; +} + +// ------------------------------------------------------------------------------------------ +/*static double nano100ToMillis(REFERENCE_TIME ref) +{ + // 1 nano = 0.000000001 seconds + //100 nano = 0.0000001 seconds + //100 nano = 0.0001 milliseconds + return ((double)ref)*0.0001; +}*/ + +// ------------------------------------------------------------------------------------------ +static double nano100ToSeconds(REFERENCE_TIME ref) +{ + // 1 nano = 0.000000001 seconds + //100 nano = 0.0000001 seconds + //100 nano = 0.0001 milliseconds + return ((double)ref)*0.0000001; +} + +// ------------------------------------------------------------------------------------------ +/*static REFERENCE_TIME MillisTonano100(double ref) +{ + // 1 nano = 0.000000001 seconds + //100 nano = 0.0000001 seconds + //100 nano = 0.0001 milliseconds + return (REFERENCE_TIME)(ref/0.0001); +}*/ + +// ------------------------------------------------------------------------------------------ +static REFERENCE_TIME SecondsTonano100(double ref) +{ + // 1 nano = 0.000000001 seconds + //100 nano = 0.0000001 seconds + //100 nano = 0.0001 milliseconds + return (REFERENCE_TIME)(ref/0.0000001); +} + +// ------------------------------------------------------------------------------------------ +// Makes Hns period from frames and sample rate +static REFERENCE_TIME MakeHnsPeriod(UINT32 nFrames, DWORD nSamplesPerSec) +{ + return (REFERENCE_TIME)((10000.0 * 1000 / nSamplesPerSec * nFrames) + 0.5); +} + +// ------------------------------------------------------------------------------------------ +// Converts PaSampleFormat to bits per sample value +// Note: paCustomFormat stands for 8.24 format (24-bits inside 32-bit containers) +static WORD PaSampleFormatToBitsPerSample(PaSampleFormat format_id) +{ + switch (format_id & ~paNonInterleaved) + { + case paFloat32: + case paInt32: return 32; + case paCustomFormat: + case paInt24: return 24; + case paInt16: return 16; + case paInt8: + case paUInt8: return 8; + } + return 0; +} + +// ------------------------------------------------------------------------------------------ +// Convert PaSampleFormat to valid sample format for I/O, e.g. if paCustomFormat is specified +// it will be converted to paInt32, other formats pass through +// Note: paCustomFormat stands for 8.24 format (24-bits inside 32-bit containers) +static PaSampleFormat GetSampleFormatForIO(PaSampleFormat format_id) +{ + return ((format_id & ~paNonInterleaved) == paCustomFormat ? + (paInt32 | (format_id & paNonInterleaved ? paNonInterleaved : 0)) : format_id); +} + +// ------------------------------------------------------------------------------------------ +// Converts Hns period into number of frames +static UINT32 MakeFramesFromHns(REFERENCE_TIME hnsPeriod, UINT32 nSamplesPerSec) +{ + UINT32 nFrames = (UINT32)( // frames = + 1.0 * hnsPeriod * // hns * + nSamplesPerSec / // (frames / s) / + 1000 / // (ms / s) / + 10000 // (hns / s) / + + 0.5 // rounding + ); + return nFrames; +} + +// Aligning function type +typedef UINT32 (*ALIGN_FUNC) (UINT32 v, UINT32 align); + +// ------------------------------------------------------------------------------------------ +// Aligns 'v' backwards +static UINT32 ALIGN_BWD(UINT32 v, UINT32 align) +{ + return ((v - (align ? v % align : 0))); +} + +// ------------------------------------------------------------------------------------------ +// Aligns 'v' forward +static UINT32 ALIGN_FWD(UINT32 v, UINT32 align) +{ + UINT32 remainder = (align ? (v % align) : 0); + if (remainder == 0) + return v; + return v + (align - remainder); +} + +// ------------------------------------------------------------------------------------------ +// Get next value power of 2 +static UINT32 ALIGN_NEXT_POW2(UINT32 v) +{ + UINT32 v2 = 1; + while (v > (v2 <<= 1)) { } + v = v2; + return v; +} + +// ------------------------------------------------------------------------------------------ +// Aligns WASAPI buffer to 128 byte packet boundary. HD Audio will fail to play if buffer +// is misaligned. This problem was solved in Windows 7 were AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED +// is thrown although we must align for Vista anyway. +static UINT32 AlignFramesPerBuffer(UINT32 nFrames, UINT32 nSamplesPerSec, UINT32 nBlockAlign, + ALIGN_FUNC pAlignFunc) +{ +#define HDA_PACKET_SIZE (128) + + long frame_bytes = nFrames * nBlockAlign; + long packets; + (void)nSamplesPerSec; + + // align to packet size + frame_bytes = pAlignFunc(frame_bytes, HDA_PACKET_SIZE); // use ALIGN_FWD if bigger but safer period is more desired + + // atlest 1 frame must be available + if (frame_bytes < HDA_PACKET_SIZE) + frame_bytes = HDA_PACKET_SIZE; + + nFrames = frame_bytes / nBlockAlign; + packets = frame_bytes / HDA_PACKET_SIZE; + + frame_bytes = packets * HDA_PACKET_SIZE; + nFrames = frame_bytes / nBlockAlign; + + return nFrames; + +#undef HDA_PACKET_SIZE +} + +// ------------------------------------------------------------------------------------------ +static UINT32 GetFramesSleepTime(REFERENCE_TIME nFrames, REFERENCE_TIME nSamplesPerSec) +{ + REFERENCE_TIME nDuration; + if (nSamplesPerSec == 0) + return 0; + +#define REFTIMES_PER_SEC 10000000LL +#define REFTIMES_PER_MILLISEC 10000LL + + // Calculate the actual duration of the allocated buffer. + nDuration = (REFTIMES_PER_SEC * nFrames) / nSamplesPerSec; + return (UINT32)(nDuration / REFTIMES_PER_MILLISEC); + +#undef REFTIMES_PER_SEC +#undef REFTIMES_PER_MILLISEC +} + +// ------------------------------------------------------------------------------------------ +static UINT32 GetFramesSleepTimeMicroseconds(REFERENCE_TIME nFrames, REFERENCE_TIME nSamplesPerSec) +{ + REFERENCE_TIME nDuration; + if (nSamplesPerSec == 0) + return 0; + +#define REFTIMES_PER_SEC 10000000LL +#define REFTIMES_PER_MILLISEC 10000LL + + // Calculate the actual duration of the allocated buffer. + nDuration = (REFTIMES_PER_SEC * nFrames) / nSamplesPerSec; + return (UINT32)(nDuration / 10); + +#undef REFTIMES_PER_SEC +#undef REFTIMES_PER_MILLISEC +} + +// ------------------------------------------------------------------------------------------ +#ifndef PA_WINRT +static BOOL SetupAVRT() +{ + hDInputDLL = LoadLibraryA("avrt.dll"); + if (hDInputDLL == NULL) + return FALSE; + + _GetProc(pAvRtCreateThreadOrderingGroup, FAvRtCreateThreadOrderingGroup, "AvRtCreateThreadOrderingGroup"); + _GetProc(pAvRtDeleteThreadOrderingGroup, FAvRtDeleteThreadOrderingGroup, "AvRtDeleteThreadOrderingGroup"); + _GetProc(pAvRtWaitOnThreadOrderingGroup, FAvRtWaitOnThreadOrderingGroup, "AvRtWaitOnThreadOrderingGroup"); + _GetProc(pAvSetMmThreadCharacteristics, FAvSetMmThreadCharacteristics, "AvSetMmThreadCharacteristicsA"); + _GetProc(pAvRevertMmThreadCharacteristics,FAvRevertMmThreadCharacteristics,"AvRevertMmThreadCharacteristics"); + _GetProc(pAvSetMmThreadPriority, FAvSetMmThreadPriority, "AvSetMmThreadPriority"); + + return pAvRtCreateThreadOrderingGroup && + pAvRtDeleteThreadOrderingGroup && + pAvRtWaitOnThreadOrderingGroup && + pAvSetMmThreadCharacteristics && + pAvRevertMmThreadCharacteristics && + pAvSetMmThreadPriority; +} +#endif + +// ------------------------------------------------------------------------------------------ +static void CloseAVRT() +{ +#ifndef PA_WINRT + if (hDInputDLL != NULL) + FreeLibrary(hDInputDLL); + hDInputDLL = NULL; +#endif +} + +// ------------------------------------------------------------------------------------------ +static BOOL IsWow64() +{ +#ifndef PA_WINRT + + // http://msdn.microsoft.com/en-us/library/ms684139(VS.85).aspx + + typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL); + LPFN_ISWOW64PROCESS fnIsWow64Process; + + BOOL bIsWow64 = FALSE; + + // IsWow64Process is not available on all supported versions of Windows. + // Use GetModuleHandle to get a handle to the DLL that contains the function + // and GetProcAddress to get a pointer to the function if available. + + fnIsWow64Process = (LPFN_ISWOW64PROCESS) GetProcAddress( + GetModuleHandleA("kernel32"), "IsWow64Process"); + + if (fnIsWow64Process == NULL) + return FALSE; + + if (!fnIsWow64Process(GetCurrentProcess(), &bIsWow64)) + return FALSE; + + return bIsWow64; + +#else + + return FALSE; + +#endif +} + +// ------------------------------------------------------------------------------------------ +typedef enum EWindowsVersion +{ + WINDOWS_UNKNOWN = 0, + WINDOWS_VISTA_SERVER2008, + WINDOWS_7_SERVER2008R2, + WINDOWS_8_SERVER2012, + WINDOWS_8_1_SERVER2012R2, + WINDOWS_10_SERVER2016, + WINDOWS_FUTURE +} +EWindowsVersion; +// Alternative way for checking Windows version (allows to check version on Windows 8.1 and up) +#ifndef PA_WINRT +static BOOL IsWindowsVersionOrGreater(WORD wMajorVersion, WORD wMinorVersion, WORD wServicePackMajor) +{ + typedef ULONGLONG (NTAPI *LPFN_VERSETCONDITIONMASK)(ULONGLONG ConditionMask, DWORD TypeMask, BYTE Condition); + typedef BOOL (WINAPI *LPFN_VERIFYVERSIONINFO)(LPOSVERSIONINFOEXA lpVersionInformation, DWORD dwTypeMask, DWORDLONG dwlConditionMask); + + LPFN_VERSETCONDITIONMASK fnVerSetConditionMask; + LPFN_VERIFYVERSIONINFO fnVerifyVersionInfo; + OSVERSIONINFOEXA osvi = { sizeof(osvi), 0, 0, 0, 0, {0}, 0, 0 }; + DWORDLONG dwlConditionMask; + + fnVerSetConditionMask = (LPFN_VERSETCONDITIONMASK)GetProcAddress(GetModuleHandleA("kernel32"), "VerSetConditionMask"); + fnVerifyVersionInfo = (LPFN_VERIFYVERSIONINFO)GetProcAddress(GetModuleHandleA("kernel32"), "VerifyVersionInfoA"); + + if ((fnVerSetConditionMask == NULL) || (fnVerifyVersionInfo == NULL)) + return FALSE; + + dwlConditionMask = fnVerSetConditionMask( + fnVerSetConditionMask( + fnVerSetConditionMask( + 0, VER_MAJORVERSION, VER_GREATER_EQUAL), + VER_MINORVERSION, VER_GREATER_EQUAL), + VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL); + + osvi.dwMajorVersion = wMajorVersion; + osvi.dwMinorVersion = wMinorVersion; + osvi.wServicePackMajor = wServicePackMajor; + + return (fnVerifyVersionInfo(&osvi, VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR, dwlConditionMask) != FALSE); +} +#endif +// Get Windows version +static EWindowsVersion GetWindowsVersion() +{ +#ifndef PA_WINRT + static EWindowsVersion version = WINDOWS_UNKNOWN; + + if (version == WINDOWS_UNKNOWN) + { + DWORD dwMajorVersion = 0xFFFFFFFFU, dwMinorVersion = 0, dwBuild = 0; + + // RTL_OSVERSIONINFOW equals OSVERSIONINFOW but it is missing inb MinGW winnt.h header, + // thus use OSVERSIONINFOW for greater portability + typedef NTSTATUS (WINAPI *LPFN_RTLGETVERSION)(POSVERSIONINFOW lpVersionInformation); + LPFN_RTLGETVERSION fnRtlGetVersion; + + #define NTSTATUS_SUCCESS ((NTSTATUS)0x00000000L) + + // RtlGetVersion must be able to provide true Windows version (Windows 10 may be reported as Windows 8 + // by GetVersion API) + if ((fnRtlGetVersion = (LPFN_RTLGETVERSION)GetProcAddress(GetModuleHandleA("ntdll"), "RtlGetVersion")) != NULL) + { + OSVERSIONINFOW ver = { sizeof(OSVERSIONINFOW), 0, 0, 0, 0, {0} }; + + PRINT(("WASAPI: getting Windows version with RtlGetVersion()\n")); + + if (fnRtlGetVersion(&ver) == NTSTATUS_SUCCESS) + { + dwMajorVersion = ver.dwMajorVersion; + dwMinorVersion = ver.dwMinorVersion; + dwBuild = ver.dwBuildNumber; + } + } + + #undef NTSTATUS_SUCCESS + + // fallback to GetVersion if RtlGetVersion is missing + if (dwMajorVersion == 0xFFFFFFFFU) + { + typedef DWORD (WINAPI *LPFN_GETVERSION)(VOID); + LPFN_GETVERSION fnGetVersion; + + if ((fnGetVersion = (LPFN_GETVERSION)GetProcAddress(GetModuleHandleA("kernel32"), "GetVersion")) != NULL) + { + DWORD dwVersion; + + PRINT(("WASAPI: getting Windows version with GetVersion()\n")); + + dwVersion = fnGetVersion(); + + dwMajorVersion = (DWORD)(LOBYTE(LOWORD(dwVersion))); + dwMinorVersion = (DWORD)(HIBYTE(LOWORD(dwVersion))); + + if (dwVersion < 0x80000000) + dwBuild = (DWORD)(HIWORD(dwVersion)); + } + } + + if (dwMajorVersion != 0xFFFFFFFFU) + { + switch (dwMajorVersion) + { + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + break; // skip lower + case 6: + switch (dwMinorVersion) + { + case 0: version = WINDOWS_VISTA_SERVER2008; break; + case 1: version = WINDOWS_7_SERVER2008R2; break; + case 2: version = WINDOWS_8_SERVER2012; break; + case 3: version = WINDOWS_8_1_SERVER2012R2; break; + default: version = WINDOWS_FUTURE; break; + } + break; + case 10: + switch (dwMinorVersion) + { + case 0: version = WINDOWS_10_SERVER2016; break; + default: version = WINDOWS_FUTURE; break; + } + break; + default: + version = WINDOWS_FUTURE; + break; + } + } + // fallback to VerifyVersionInfo if RtlGetVersion and GetVersion are missing + else + { + PRINT(("WASAPI: getting Windows version with VerifyVersionInfo()\n")); + + if (IsWindowsVersionOrGreater(10, 0, 0)) + version = WINDOWS_10_SERVER2016; + else + if (IsWindowsVersionOrGreater(6, 3, 0)) + version = WINDOWS_8_1_SERVER2012R2; + else + if (IsWindowsVersionOrGreater(6, 2, 0)) + version = WINDOWS_8_SERVER2012; + else + if (IsWindowsVersionOrGreater(6, 1, 0)) + version = WINDOWS_7_SERVER2008R2; + else + if (IsWindowsVersionOrGreater(6, 0, 0)) + version = WINDOWS_VISTA_SERVER2008; + else + version = WINDOWS_FUTURE; + } + + PRINT(("WASAPI: Windows version = %d\n", version)); + } + + return version; +#else + #if (_WIN32_WINNT >= _WIN32_WINNT_WIN10) + return WINDOWS_10_SERVER2016; + #else + return WINDOWS_8_SERVER2012; + #endif +#endif +} + +// ------------------------------------------------------------------------------------------ +static BOOL UseWOW64Workaround() +{ + // note: WOW64 bug is common to Windows Vista x64, thus we fall back to safe Poll-driven + // method. Windows 7 x64 seems has WOW64 bug fixed. + + return (IsWow64() && (GetWindowsVersion() == WINDOWS_VISTA_SERVER2008)); +} + +// ------------------------------------------------------------------------------------------ +static UINT32 GetAudioClientVersion() +{ + if (GetWindowsVersion() >= WINDOWS_10_SERVER2016) + return 3; + else + if (GetWindowsVersion() >= WINDOWS_8_SERVER2012) + return 2; + + return 1; +} + +// ------------------------------------------------------------------------------------------ +static const IID *GetAudioClientIID() +{ + static const IID *cli_iid = NULL; + if (cli_iid == NULL) + { + UINT32 cli_version = GetAudioClientVersion(); + switch (cli_version) + { + case 3: cli_iid = &pa_IID_IAudioClient3; break; + case 2: cli_iid = &pa_IID_IAudioClient2; break; + default: cli_iid = &pa_IID_IAudioClient; break; + } + + PRINT(("WASAPI: IAudioClient version = %d\n", cli_version)); + } + + return cli_iid; +} + +// ------------------------------------------------------------------------------------------ +typedef enum EMixDirection +{ + MIX_DIR__1TO2, //!< mix one channel to L and R + MIX_DIR__2TO1, //!< mix L and R channels to one channel + MIX_DIR__2TO1_L //!< mix only L channel (of total 2 channels) to one channel +} +EMixDirection; + +// ------------------------------------------------------------------------------------------ +#define _WASAPI_MONO_TO_STEREO_MIXER_1_TO_2(TYPE)\ + TYPE * __restrict to = (TYPE *)__to;\ + const TYPE * __restrict from = (const TYPE *)__from;\ + const TYPE * __restrict end = from + count;\ + while (from != end)\ + {\ + to[0] = to[1] = *from ++;\ + to += 2;\ + } + +// ------------------------------------------------------------------------------------------ +#define _WASAPI_MONO_TO_STEREO_MIXER_2_TO_1_FLT32(TYPE)\ + TYPE * __restrict to = (TYPE *)__to;\ + const TYPE * __restrict from = (const TYPE *)__from;\ + const TYPE * __restrict end = to + count;\ + while (to != end)\ + {\ + *to ++ = (TYPE)((float)(from[0] + from[1]) * 0.5f);\ + from += 2;\ + } + +// ------------------------------------------------------------------------------------------ +#define _WASAPI_MONO_TO_STEREO_MIXER_2_TO_1_INT32(TYPE)\ + TYPE * __restrict to = (TYPE *)__to;\ + const TYPE * __restrict from = (const TYPE *)__from;\ + const TYPE * __restrict end = to + count;\ + while (to != end)\ + {\ + *to ++ = (TYPE)(((INT32)from[0] + (INT32)from[1]) >> 1);\ + from += 2;\ + } + +// ------------------------------------------------------------------------------------------ +#define _WASAPI_MONO_TO_STEREO_MIXER_2_TO_1_INT64(TYPE)\ + TYPE * __restrict to = (TYPE *)__to;\ + const TYPE * __restrict from = (const TYPE *)__from;\ + const TYPE * __restrict end = to + count;\ + while (to != end)\ + {\ + *to ++ = (TYPE)(((INT64)from[0] + (INT64)from[1]) >> 1);\ + from += 2;\ + } + +// ------------------------------------------------------------------------------------------ +#define _WASAPI_MONO_TO_STEREO_MIXER_2_TO_1_L(TYPE)\ + TYPE * __restrict to = (TYPE *)__to;\ + const TYPE * __restrict from = (const TYPE *)__from;\ + const TYPE * __restrict end = to + count;\ + while (to != end)\ + {\ + *to ++ = from[0];\ + from += 2;\ + } + +// ------------------------------------------------------------------------------------------ +static void _MixMonoToStereo_1TO2_8(void *__to, const void *__from, UINT32 count) { _WASAPI_MONO_TO_STEREO_MIXER_1_TO_2(BYTE); } +static void _MixMonoToStereo_1TO2_16(void *__to, const void *__from, UINT32 count) { _WASAPI_MONO_TO_STEREO_MIXER_1_TO_2(short); } +static void _MixMonoToStereo_1TO2_8_24(void *__to, const void *__from, UINT32 count) { _WASAPI_MONO_TO_STEREO_MIXER_1_TO_2(int); /* !!! int24 data is contained in 32-bit containers*/ } +static void _MixMonoToStereo_1TO2_32(void *__to, const void *__from, UINT32 count) { _WASAPI_MONO_TO_STEREO_MIXER_1_TO_2(int); } +static void _MixMonoToStereo_1TO2_32f(void *__to, const void *__from, UINT32 count) { _WASAPI_MONO_TO_STEREO_MIXER_1_TO_2(float); } +static void _MixMonoToStereo_1TO2_24(void *__to, const void *__from, UINT32 count) +{ + const UCHAR * __restrict from = (const UCHAR *)__from; + UCHAR * __restrict to = (UCHAR *)__to; + const UCHAR * __restrict end = to + (count * (2 * 3)); + + while (to != end) + { + to[0] = to[3] = from[0]; + to[1] = to[4] = from[1]; + to[2] = to[5] = from[2]; + + from += 3; + to += (2 * 3); + } +} + +// ------------------------------------------------------------------------------------------ +static void _MixMonoToStereo_2TO1_8(void *__to, const void *__from, UINT32 count) { _WASAPI_MONO_TO_STEREO_MIXER_2_TO_1_INT32(BYTE); } +static void _MixMonoToStereo_2TO1_16(void *__to, const void *__from, UINT32 count) { _WASAPI_MONO_TO_STEREO_MIXER_2_TO_1_INT32(short); } +static void _MixMonoToStereo_2TO1_8_24(void *__to, const void *__from, UINT32 count) { _WASAPI_MONO_TO_STEREO_MIXER_2_TO_1_INT32(int); /* !!! int24 data is contained in 32-bit containers*/ } +static void _MixMonoToStereo_2TO1_32(void *__to, const void *__from, UINT32 count) { _WASAPI_MONO_TO_STEREO_MIXER_2_TO_1_INT64(int); } +static void _MixMonoToStereo_2TO1_32f(void *__to, const void *__from, UINT32 count) { _WASAPI_MONO_TO_STEREO_MIXER_2_TO_1_FLT32(float); } +static void _MixMonoToStereo_2TO1_24(void *__to, const void *__from, UINT32 count) +{ + const UCHAR * __restrict from = (const UCHAR *)__from; + UCHAR * __restrict to = (UCHAR *)__to; + const UCHAR * __restrict end = to + (count * 3); + PaInt32 tempL, tempR, tempM; + + while (to != end) + { + tempL = (((PaInt32)from[0]) << 8); + tempL = tempL | (((PaInt32)from[1]) << 16); + tempL = tempL | (((PaInt32)from[2]) << 24); + + tempR = (((PaInt32)from[3]) << 8); + tempR = tempR | (((PaInt32)from[4]) << 16); + tempR = tempR | (((PaInt32)from[5]) << 24); + + tempM = (tempL + tempR) >> 1; + + to[0] = (UCHAR)(tempM >> 8); + to[1] = (UCHAR)(tempM >> 16); + to[2] = (UCHAR)(tempM >> 24); + + from += (2 * 3); + to += 3; + } +} + +// ------------------------------------------------------------------------------------------ +static void _MixMonoToStereo_2TO1_8_L(void *__to, const void *__from, UINT32 count) { _WASAPI_MONO_TO_STEREO_MIXER_2_TO_1_L(BYTE); } +static void _MixMonoToStereo_2TO1_16_L(void *__to, const void *__from, UINT32 count) { _WASAPI_MONO_TO_STEREO_MIXER_2_TO_1_L(short); } +static void _MixMonoToStereo_2TO1_8_24_L(void *__to, const void *__from, UINT32 count) { _WASAPI_MONO_TO_STEREO_MIXER_2_TO_1_L(int); /* !!! int24 data is contained in 32-bit containers*/ } +static void _MixMonoToStereo_2TO1_32_L(void *__to, const void *__from, UINT32 count) { _WASAPI_MONO_TO_STEREO_MIXER_2_TO_1_L(int); } +static void _MixMonoToStereo_2TO1_32f_L(void *__to, const void *__from, UINT32 count) { _WASAPI_MONO_TO_STEREO_MIXER_2_TO_1_L(float); } +static void _MixMonoToStereo_2TO1_24_L(void *__to, const void *__from, UINT32 count) +{ + const UCHAR * __restrict from = (const UCHAR *)__from; + UCHAR * __restrict to = (UCHAR *)__to; + const UCHAR * __restrict end = to + (count * 3); + + while (to != end) + { + to[0] = from[0]; + to[1] = from[1]; + to[2] = from[2]; + + from += (2 * 3); + to += 3; + } +} + +// ------------------------------------------------------------------------------------------ +static MixMonoToStereoF GetMonoToStereoMixer(const WAVEFORMATEXTENSIBLE *fmtext, EMixDirection dir) +{ + PaSampleFormat format = WaveToPaFormat(fmtext); + + switch (dir) + { + case MIX_DIR__1TO2: + switch (format & ~paNonInterleaved) + { + case paUInt8: return _MixMonoToStereo_1TO2_8; + case paInt16: return _MixMonoToStereo_1TO2_16; + case paInt24: return (fmtext->Format.wBitsPerSample == 32 ? _MixMonoToStereo_1TO2_8_24 : _MixMonoToStereo_1TO2_24); + case paInt32: return _MixMonoToStereo_1TO2_32; + case paFloat32: return _MixMonoToStereo_1TO2_32f; + } + break; + + case MIX_DIR__2TO1: + switch (format & ~paNonInterleaved) + { + case paUInt8: return _MixMonoToStereo_2TO1_8; + case paInt16: return _MixMonoToStereo_2TO1_16; + case paInt24: return (fmtext->Format.wBitsPerSample == 32 ? _MixMonoToStereo_2TO1_8_24 : _MixMonoToStereo_2TO1_24); + case paInt32: return _MixMonoToStereo_2TO1_32; + case paFloat32: return _MixMonoToStereo_2TO1_32f; + } + break; + + case MIX_DIR__2TO1_L: + switch (format & ~paNonInterleaved) + { + case paUInt8: return _MixMonoToStereo_2TO1_8_L; + case paInt16: return _MixMonoToStereo_2TO1_16_L; + case paInt24: return (fmtext->Format.wBitsPerSample == 32 ? _MixMonoToStereo_2TO1_8_24_L : _MixMonoToStereo_2TO1_24_L); + case paInt32: return _MixMonoToStereo_2TO1_32_L; + case paFloat32: return _MixMonoToStereo_2TO1_32f_L; + } + break; + } + + return NULL; +} + +// ------------------------------------------------------------------------------------------ +#ifdef PA_WINRT +typedef struct PaActivateAudioInterfaceCompletionHandler +{ + IActivateAudioInterfaceCompletionHandler parent; + volatile LONG refs; + volatile LONG done; + struct + { + const IID *iid; + void **obj; + } + in; + struct + { + HRESULT hr; + } + out; +} +PaActivateAudioInterfaceCompletionHandler; + +static HRESULT (STDMETHODCALLTYPE PaActivateAudioInterfaceCompletionHandler_QueryInterface)( + IActivateAudioInterfaceCompletionHandler *This, REFIID riid, void **ppvObject) +{ + PaActivateAudioInterfaceCompletionHandler *handler = (PaActivateAudioInterfaceCompletionHandler *)This; + + // From MSDN: + // "The IAgileObject interface is a marker interface that indicates that an object + // is free threaded and can be called from any apartment." + if (IsEqualIID(riid, &IID_IUnknown) || + IsEqualIID(riid, &IID_IAgileObject)) + { + IActivateAudioInterfaceCompletionHandler_AddRef((IActivateAudioInterfaceCompletionHandler *)handler); + (*ppvObject) = handler; + return S_OK; + } + + return E_NOINTERFACE; +} + +static ULONG (STDMETHODCALLTYPE PaActivateAudioInterfaceCompletionHandler_AddRef)( + IActivateAudioInterfaceCompletionHandler *This) +{ + PaActivateAudioInterfaceCompletionHandler *handler = (PaActivateAudioInterfaceCompletionHandler *)This; + + return InterlockedIncrement(&handler->refs); +} + +static ULONG (STDMETHODCALLTYPE PaActivateAudioInterfaceCompletionHandler_Release)( + IActivateAudioInterfaceCompletionHandler *This) +{ + PaActivateAudioInterfaceCompletionHandler *handler = (PaActivateAudioInterfaceCompletionHandler *)This; + ULONG refs; + + if ((refs = InterlockedDecrement(&handler->refs)) == 0) + { + PaUtil_FreeMemory(handler->parent.lpVtbl); + PaUtil_FreeMemory(handler); + } + + return refs; +} + +static HRESULT (STDMETHODCALLTYPE PaActivateAudioInterfaceCompletionHandler_ActivateCompleted)( + IActivateAudioInterfaceCompletionHandler *This, IActivateAudioInterfaceAsyncOperation *activateOperation) +{ + PaActivateAudioInterfaceCompletionHandler *handler = (PaActivateAudioInterfaceCompletionHandler *)This; + + HRESULT hr = S_OK; + HRESULT hrActivateResult = S_OK; + IUnknown *punkAudioInterface = NULL; + + // Check for a successful activation result + hr = IActivateAudioInterfaceAsyncOperation_GetActivateResult(activateOperation, &hrActivateResult, &punkAudioInterface); + if (SUCCEEDED(hr) && SUCCEEDED(hrActivateResult)) + { + // Get pointer to the requested audio interface + IUnknown_QueryInterface(punkAudioInterface, handler->in.iid, handler->in.obj); + if ((*handler->in.obj) == NULL) + hrActivateResult = E_FAIL; + } + SAFE_RELEASE(punkAudioInterface); + + if (SUCCEEDED(hr)) + handler->out.hr = hrActivateResult; + else + handler->out.hr = hr; + + // Got client object, stop busy waiting in ActivateAudioInterface + InterlockedExchange(&handler->done, TRUE); + + return hr; +} + +static IActivateAudioInterfaceCompletionHandler *CreateActivateAudioInterfaceCompletionHandler(const IID *iid, void **obj) +{ + PaActivateAudioInterfaceCompletionHandler *handler = PaUtil_AllocateMemory(sizeof(PaActivateAudioInterfaceCompletionHandler)); + ZeroMemory(handler, sizeof(*handler)); + handler->parent.lpVtbl = PaUtil_AllocateMemory(sizeof(*handler->parent.lpVtbl)); + handler->parent.lpVtbl->QueryInterface = &PaActivateAudioInterfaceCompletionHandler_QueryInterface; + handler->parent.lpVtbl->AddRef = &PaActivateAudioInterfaceCompletionHandler_AddRef; + handler->parent.lpVtbl->Release = &PaActivateAudioInterfaceCompletionHandler_Release; + handler->parent.lpVtbl->ActivateCompleted = &PaActivateAudioInterfaceCompletionHandler_ActivateCompleted; + handler->refs = 1; + handler->in.iid = iid; + handler->in.obj = obj; + return (IActivateAudioInterfaceCompletionHandler *)handler; +} +#endif + +// ------------------------------------------------------------------------------------------ +#ifdef PA_WINRT +static HRESULT ActivateAudioInterface_WINRT(EDataFlow flow, const IID *iid, void **obj) +{ +#define PA_WASAPI_DEVICE_PATH_LEN 64 + + PaError result = paNoError; + HRESULT hr = S_OK; + IActivateAudioInterfaceAsyncOperation *asyncOp = NULL; + IActivateAudioInterfaceCompletionHandler *handler = CreateActivateAudioInterfaceCompletionHandler(iid, obj); + PaActivateAudioInterfaceCompletionHandler *handlerImpl = (PaActivateAudioInterfaceCompletionHandler *)handler; + OLECHAR tmp[PA_WASAPI_DEVICE_PATH_LEN] = { 0 }; + OLECHAR *devicePath = tmp; + + // Get device path in form L"{DEVICE_GUID}" + switch (flow) + { + case eRender: + if (g_DefaultRenderId[0] != 0) + devicePath = g_DefaultRenderId; + else + StringFromGUID2(&DEVINTERFACE_AUDIO_RENDER, devicePath, PA_WASAPI_DEVICE_PATH_LEN - 1); + break; + case eCapture: + if (g_DefaultCaptureId[0] != 0) + devicePath = g_DefaultCaptureId; + else + StringFromGUID2(&DEVINTERFACE_AUDIO_CAPTURE, devicePath, PA_WASAPI_DEVICE_PATH_LEN - 1); + break; + default: + return S_FALSE; + } + + // Async operation will call back to IActivateAudioInterfaceCompletionHandler::ActivateCompleted + // which must be an agile interface implementation + hr = ActivateAudioInterfaceAsync(devicePath, iid, NULL, handler, &asyncOp); + IF_FAILED_INTERNAL_ERROR_JUMP(hr, result, error); + + // Wait in busy loop for async operation to complete + // Use Interlocked API here to ensure that ->done variable is read every time through the loop + while (SUCCEEDED(hr) && !InterlockedOr(&handlerImpl->done, 0)) + { + Sleep(1); + } + + hr = handlerImpl->out.hr; + +error: + + SAFE_RELEASE(asyncOp); + SAFE_RELEASE(handler); + + return hr; + +#undef PA_WASAPI_DEVICE_PATH_LEN +} +#endif + +// ------------------------------------------------------------------------------------------ +static HRESULT ActivateAudioInterface(const PaWasapiDeviceInfo *deviceInfo, const PaWasapiStreamInfo *streamInfo, + IAudioClient **client) +{ + HRESULT hr; + +#ifndef PA_WINRT + if (FAILED(hr = IMMDevice_Activate(deviceInfo->device, GetAudioClientIID(), CLSCTX_ALL, NULL, (void **)client))) + return hr; +#else + if (FAILED(hr = ActivateAudioInterface_WINRT(deviceInfo->flow, GetAudioClientIID(), (void **)client))) + return hr; +#endif + + // Set audio client options (applicable only to IAudioClient2+): options may affect the audio format + // support by IAudioClient implementation and therefore we should set them before GetClosestFormat() + // in order to correctly match the requested format +#ifdef __IAudioClient2_INTERFACE_DEFINED__ + if ((streamInfo != NULL) && (GetAudioClientVersion() >= 2)) + { + pa_AudioClientProperties audioProps = { 0 }; + audioProps.cbSize = sizeof(pa_AudioClientProperties); + audioProps.bIsOffload = FALSE; + audioProps.eCategory = (AUDIO_STREAM_CATEGORY)streamInfo->streamCategory; + switch (streamInfo->streamOption) + { + case eStreamOptionRaw: + if (GetWindowsVersion() >= WINDOWS_8_1_SERVER2012R2) + audioProps.Options = pa_AUDCLNT_STREAMOPTIONS_RAW; + break; + case eStreamOptionMatchFormat: + if (GetWindowsVersion() >= WINDOWS_10_SERVER2016) + audioProps.Options = pa_AUDCLNT_STREAMOPTIONS_MATCH_FORMAT; + break; + } + + if (FAILED(hr = IAudioClient2_SetClientProperties((IAudioClient2 *)(*client), (AudioClientProperties *)&audioProps))) + { + PRINT(("WASAPI: IAudioClient2_SetClientProperties(IsOffload = %d, Category = %d, Options = %d) failed\n", audioProps.bIsOffload, audioProps.eCategory, audioProps.Options)); + LogHostError(hr); + } + else + { + PRINT(("WASAPI: IAudioClient2 set properties: IsOffload = %d, Category = %d, Options = %d\n", audioProps.bIsOffload, audioProps.eCategory, audioProps.Options)); + } + } +#endif + + return S_OK; +} + +// ------------------------------------------------------------------------------------------ +#ifdef PA_WINRT +// Windows 10 SDK 10.0.15063.0 has SignalObjectAndWait defined again (unlike in 10.0.14393.0 and lower) +#if !defined(WDK_NTDDI_VERSION) || (WDK_NTDDI_VERSION < NTDDI_WIN10_RS2) +static DWORD SignalObjectAndWait(HANDLE hObjectToSignal, HANDLE hObjectToWaitOn, DWORD dwMilliseconds, BOOL bAlertable) +{ + SetEvent(hObjectToSignal); + return WaitForSingleObjectEx(hObjectToWaitOn, dwMilliseconds, bAlertable); +} +#endif +#endif + +// ------------------------------------------------------------------------------------------ +static void NotifyStateChanged(PaWasapiStream *stream, UINT32 flags, HRESULT hr) +{ + if (stream->fnStateHandler == NULL) + return; + + if (FAILED(hr)) + flags |= paWasapiStreamStateError; + + stream->fnStateHandler((PaStream *)stream, flags, hr, stream->pStateHandlerUserData); +} + +// ------------------------------------------------------------------------------------------ +static PaError CreateDeviceList(PaWasapiHostApiRepresentation *paWasapi, PaHostApiIndex hostApiIndex) +{ + PaUtilHostApiRepresentation *hostApi = (PaUtilHostApiRepresentation *)paWasapi; + PaError result = paNoError; + PaDeviceInfo *deviceInfoArray; + HRESULT hr = S_OK; + UINT i; +#ifndef PA_WINRT + IMMDeviceCollection* pEndPoints = NULL; + IMMDeviceEnumerator *pEnumerator = NULL; +#endif + IAudioClient *tmpClient; + + // Make sure device list empty + if ((paWasapi->deviceCount != 0) || (hostApi->info.deviceCount != 0)) + return paInternalError; + +#ifndef PA_WINRT + hr = CoCreateInstance(&pa_CLSID_IMMDeviceEnumerator, NULL, CLSCTX_INPROC_SERVER, + &pa_IID_IMMDeviceEnumerator, (void **)&pEnumerator); + + // We need to set the result to a value otherwise we will return paNoError + // [IF_FAILED_JUMP(hResult, error);] + IF_FAILED_INTERNAL_ERROR_JUMP(hr, result, error); + + // getting default device ids in the eMultimedia "role" + { + { + IMMDevice *defaultRenderer = NULL; + hr = IMMDeviceEnumerator_GetDefaultAudioEndpoint(pEnumerator, eRender, eMultimedia, &defaultRenderer); + if (hr != S_OK) + { + if (hr != E_NOTFOUND) { + // We need to set the result to a value otherwise we will return paNoError + // [IF_FAILED_JUMP(hResult, error);] + IF_FAILED_INTERNAL_ERROR_JUMP(hr, result, error); + } + } + else + { + WCHAR *pszDeviceId = NULL; + hr = IMMDevice_GetId(defaultRenderer, &pszDeviceId); + // We need to set the result to a value otherwise we will return paNoError + // [IF_FAILED_JUMP(hResult, error);] + IF_FAILED_INTERNAL_ERROR_JUMP(hr, result, error); + wcsncpy(paWasapi->defaultRenderer, pszDeviceId, MAX_STR_LEN-1); + CoTaskMemFree(pszDeviceId); + IMMDevice_Release(defaultRenderer); + } + } + + { + IMMDevice *defaultCapturer = NULL; + hr = IMMDeviceEnumerator_GetDefaultAudioEndpoint(pEnumerator, eCapture, eMultimedia, &defaultCapturer); + if (hr != S_OK) + { + if (hr != E_NOTFOUND) { + // We need to set the result to a value otherwise we will return paNoError + // [IF_FAILED_JUMP(hResult, error);] + IF_FAILED_INTERNAL_ERROR_JUMP(hr, result, error); + } + } + else + { + WCHAR *pszDeviceId = NULL; + hr = IMMDevice_GetId(defaultCapturer, &pszDeviceId); + // We need to set the result to a value otherwise we will return paNoError + // [IF_FAILED_JUMP(hResult, error);] + IF_FAILED_INTERNAL_ERROR_JUMP(hr, result, error); + wcsncpy(paWasapi->defaultCapturer, pszDeviceId, MAX_STR_LEN-1); + CoTaskMemFree(pszDeviceId); + IMMDevice_Release(defaultCapturer); + } + } + } + + hr = IMMDeviceEnumerator_EnumAudioEndpoints(pEnumerator, eAll, DEVICE_STATE_ACTIVE, &pEndPoints); + // We need to set the result to a value otherwise we will return paNoError + // [IF_FAILED_JUMP(hResult, error);] + IF_FAILED_INTERNAL_ERROR_JUMP(hr, result, error); + + hr = IMMDeviceCollection_GetCount(pEndPoints, &paWasapi->deviceCount); + // We need to set the result to a value otherwise we will return paNoError + // [IF_FAILED_JUMP(hResult, error);] + IF_FAILED_INTERNAL_ERROR_JUMP(hr, result, error); + +#else + // Determine number of available devices by activating AudioClient for render and capture data flows + if (SUCCEEDED(ActivateAudioInterface_WINRT(eRender, GetAudioClientIID(), &tmpClient))) + { + paWasapi->deviceCount++; + SAFE_RELEASE(tmpClient); + } + if (SUCCEEDED(ActivateAudioInterface_WINRT(eCapture, GetAudioClientIID(), &tmpClient))) + { + paWasapi->deviceCount++; + SAFE_RELEASE(tmpClient); + } +#endif + + paWasapi->devInfo = (PaWasapiDeviceInfo *)PaUtil_GroupAllocateMemory( + paWasapi->allocations, sizeof(PaWasapiDeviceInfo) * paWasapi->deviceCount); + if (paWasapi->devInfo == NULL) + { + result = paInsufficientMemory; + goto error; + } + memset(paWasapi->devInfo, 0, sizeof(PaWasapiDeviceInfo) * paWasapi->deviceCount); + + if (paWasapi->deviceCount > 0) + { + UINT32 deviceCount = paWasapi->deviceCount; + #if defined(PA_WASAPI_MAX_CONST_DEVICE_COUNT) && (PA_WASAPI_MAX_CONST_DEVICE_COUNT > 0) + if (deviceCount < PA_WASAPI_MAX_CONST_DEVICE_COUNT) + deviceCount = PA_WASAPI_MAX_CONST_DEVICE_COUNT; + #endif + + hostApi->deviceInfos = (PaDeviceInfo **)PaUtil_GroupAllocateMemory( + paWasapi->allocations, sizeof(PaDeviceInfo *) * deviceCount); + if (hostApi->deviceInfos == NULL) + { + result = paInsufficientMemory; + goto error; + } + + /* allocate all device info structs in a contiguous block */ + deviceInfoArray = (PaDeviceInfo *)PaUtil_GroupAllocateMemory( + paWasapi->allocations, sizeof(PaDeviceInfo) * deviceCount); + if (deviceInfoArray == NULL) + { + result = paInsufficientMemory; + goto error; + } + memset(deviceInfoArray, 0, sizeof(PaDeviceInfo) * deviceCount); + + for (i = 0; i < paWasapi->deviceCount; ++i) + { + PaDeviceInfo *deviceInfo = &deviceInfoArray[i]; + deviceInfo->structVersion = 2; + deviceInfo->hostApi = hostApiIndex; + + PA_DEBUG(("WASAPI: device idx: %02d\n", i)); + PA_DEBUG(("WASAPI: ---------------\n")); + + #ifndef PA_WINRT + hr = IMMDeviceCollection_Item(pEndPoints, i, &paWasapi->devInfo[i].device); + // We need to set the result to a value otherwise we will return paNoError + // [IF_FAILED_JUMP(hResult, error);] + IF_FAILED_INTERNAL_ERROR_JUMP(hr, result, error); + + // getting ID + { + WCHAR *pszDeviceId = NULL; + hr = IMMDevice_GetId(paWasapi->devInfo[i].device, &pszDeviceId); + // We need to set the result to a value otherwise we will return paNoError + // [IF_FAILED_JUMP(hr, error);] + IF_FAILED_INTERNAL_ERROR_JUMP(hr, result, error); + wcsncpy(paWasapi->devInfo[i].szDeviceID, pszDeviceId, MAX_STR_LEN-1); + CoTaskMemFree(pszDeviceId); + + if (lstrcmpW(paWasapi->devInfo[i].szDeviceID, paWasapi->defaultCapturer) == 0) + {// we found the default input! + hostApi->info.defaultInputDevice = hostApi->info.deviceCount; + } + if (lstrcmpW(paWasapi->devInfo[i].szDeviceID, paWasapi->defaultRenderer) == 0) + {// we found the default output! + hostApi->info.defaultOutputDevice = hostApi->info.deviceCount; + } + } + + hr = IMMDevice_GetState(paWasapi->devInfo[i].device, &paWasapi->devInfo[i].state); + // We need to set the result to a value otherwise we will return paNoError + // [IF_FAILED_JUMP(hResult, error);] + IF_FAILED_INTERNAL_ERROR_JUMP(hr, result, error); + + if (paWasapi->devInfo[i].state != DEVICE_STATE_ACTIVE) + { + PRINT(("WASAPI device: %d is not currently available (state:%d)\n", i, paWasapi->devInfo[i].state)); + } + + { + IPropertyStore *pProperty; + hr = IMMDevice_OpenPropertyStore(paWasapi->devInfo[i].device, STGM_READ, &pProperty); + // We need to set the result to a value otherwise we will return paNoError + // [IF_FAILED_JUMP(hResult, error);] + IF_FAILED_INTERNAL_ERROR_JUMP(hr, result, error); + + // "Friendly" Name + { + PROPVARIANT value; + PropVariantInit(&value); + hr = IPropertyStore_GetValue(pProperty, &PKEY_Device_FriendlyName, &value); + // We need to set the result to a value otherwise we will return paNoError + // [IF_FAILED_JUMP(hResult, error);] + IF_FAILED_INTERNAL_ERROR_JUMP(hr, result, error); + if ((deviceInfo->name = (char *)PaUtil_GroupAllocateMemory(paWasapi->allocations, MAX_STR_LEN + 1)) == NULL) + { + result = paInsufficientMemory; + goto error; + } + if (value.pwszVal) + WideCharToMultiByte(CP_UTF8, 0, value.pwszVal, (int)wcslen(value.pwszVal), (char *)deviceInfo->name, MAX_STR_LEN - 1, 0, 0); + else + _snprintf((char *)deviceInfo->name, MAX_STR_LEN - 1, "baddev%d", i); + PropVariantClear(&value); + PA_DEBUG(("WASAPI:%d| name[%s]\n", i, deviceInfo->name)); + } + + // Default format + { + PROPVARIANT value; + PropVariantInit(&value); + hr = IPropertyStore_GetValue(pProperty, &PKEY_AudioEngine_DeviceFormat, &value); + // We need to set the result to a value otherwise we will return paNoError + // [IF_FAILED_JUMP(hResult, error);] + IF_FAILED_INTERNAL_ERROR_JUMP(hr, result, error); + memcpy(&paWasapi->devInfo[i].DefaultFormat, value.blob.pBlobData, min(sizeof(paWasapi->devInfo[i].DefaultFormat), value.blob.cbSize)); + // cleanup + PropVariantClear(&value); + } + + // Formfactor + { + PROPVARIANT value; + PropVariantInit(&value); + hr = IPropertyStore_GetValue(pProperty, &PKEY_AudioEndpoint_FormFactor, &value); + // We need to set the result to a value otherwise we will return paNoError + // [IF_FAILED_JUMP(hResult, error);] + IF_FAILED_INTERNAL_ERROR_JUMP(hr, result, error); + // set + #if defined(DUMMYUNIONNAME) && defined(NONAMELESSUNION) + // avoid breaking strict-aliasing rules in such line: (EndpointFormFactor)(*((UINT *)(((WORD *)&value.wReserved3)+1))); + UINT v; + memcpy(&v, (((WORD *)&value.wReserved3)+1), sizeof(v)); + paWasapi->devInfo[i].formFactor = (EndpointFormFactor)v; + #else + paWasapi->devInfo[i].formFactor = (EndpointFormFactor)value.uintVal; + #endif + PA_DEBUG(("WASAPI:%d| form-factor[%d]\n", i, paWasapi->devInfo[i].formFactor)); + // cleanup + PropVariantClear(&value); + } + + SAFE_RELEASE(pProperty); + } + + // Endpoint data + { + IMMEndpoint *endpoint = NULL; + hr = IMMDevice_QueryInterface(paWasapi->devInfo[i].device, &pa_IID_IMMEndpoint, (void **)&endpoint); + if (SUCCEEDED(hr)) + { + hr = IMMEndpoint_GetDataFlow(endpoint, &paWasapi->devInfo[i].flow); + SAFE_RELEASE(endpoint); + } + } + #endif + + // Getting a temporary IAudioClient for more fields + // we make sure NOT to call Initialize yet! + { + #ifdef PA_WINRT + // Set flow as ActivateAudioInterface depends on it and selects corresponding + // direction for the Audio Client + paWasapi->devInfo[i].flow = (i == 0 ? eRender : eCapture); + #endif + + // Create temp Audio Client instance to query additional details + hr = ActivateAudioInterface(&paWasapi->devInfo[i], NULL, &tmpClient); + // We need to set the result to a value otherwise we will return paNoError + // [IF_FAILED_JUMP(hResult, error);] + IF_FAILED_INTERNAL_ERROR_JUMP(hr, result, error); + + // Get latency + hr = IAudioClient_GetDevicePeriod(tmpClient, + &paWasapi->devInfo[i].DefaultDevicePeriod, + &paWasapi->devInfo[i].MinimumDevicePeriod); + if (FAILED(hr)) + { + PA_DEBUG(("WASAPI:%d| failed getting min/default periods by IAudioClient::GetDevicePeriod() with error[%08X], will use 30000/100000 hns\n", i, (UINT32)hr)); + + // assign WASAPI common values + paWasapi->devInfo[i].DefaultDevicePeriod = 100000; + paWasapi->devInfo[i].MinimumDevicePeriod = 30000; + + // ignore error, let continue further without failing with paInternalError + hr = S_OK; + } + + // Get mix format + { + WAVEFORMATEX *mixFormat; + + hr = IAudioClient_GetMixFormat(tmpClient, &mixFormat); + if (SUCCEEDED(hr)) + { + memcpy(&paWasapi->devInfo[i].MixFormat, mixFormat, min(sizeof(paWasapi->devInfo[i].MixFormat), (sizeof(*mixFormat) + mixFormat->cbSize))); + CoTaskMemFree(mixFormat); + } + } + + // Register WINRT device + #ifdef PA_WINRT + if (SUCCEEDED(hr)) + { + // Default device + if (i == 0) + hostApi->info.defaultOutputDevice = hostApi->info.deviceCount; + else + hostApi->info.defaultInputDevice = hostApi->info.deviceCount; + + // State + paWasapi->devInfo[i].state = DEVICE_STATE_ACTIVE; + + // Default format is always a mix format + paWasapi->devInfo[i].DefaultFormat = paWasapi->devInfo[i].MixFormat; + + // Form-factor + paWasapi->devInfo[i].formFactor = UnknownFormFactor; + + // Name + if ((deviceInfo->name = (char *)PaUtil_GroupAllocateMemory(paWasapi->allocations, MAX_STR_LEN + 1)) == NULL) + { + SAFE_RELEASE(tmpClient); + result = paInsufficientMemory; + goto error; + } + _snprintf((char *)deviceInfo->name, MAX_STR_LEN - 1, "WASAPI_%s:%d", (i == 0 ? "Output" : "Input"), i); + PA_DEBUG(("WASAPI:%d| name[%s]\n", i, deviceInfo->name)); + } + #endif + + // Release tmp client + SAFE_RELEASE(tmpClient); + + if (hr != S_OK) + { + //davidv: this happened with my hardware, previously for that same device in DirectSound: + //Digital Output (Realtek AC'97 Audio)'s GUID: {0x38f2cf50,0x7b4c,0x4740,0x86,0xeb,0xd4,0x38,0x66,0xd8,0xc8, 0x9f} + //so something must be _really_ wrong with this device, TODO handle this better. We kind of need GetMixFormat + LogHostError(hr); + // We need to set the result to a value otherwise we will return paNoError + result = paInternalError; + goto error; + } + } + + // we can now fill in portaudio device data + deviceInfo->maxInputChannels = 0; + deviceInfo->maxOutputChannels = 0; + deviceInfo->defaultSampleRate = paWasapi->devInfo[i].MixFormat.Format.nSamplesPerSec; + switch (paWasapi->devInfo[i].flow) + { + case eRender: { + deviceInfo->maxOutputChannels = paWasapi->devInfo[i].MixFormat.Format.nChannels; + deviceInfo->defaultHighOutputLatency = nano100ToSeconds(paWasapi->devInfo[i].DefaultDevicePeriod); + deviceInfo->defaultLowOutputLatency = nano100ToSeconds(paWasapi->devInfo[i].MinimumDevicePeriod); + PA_DEBUG(("WASAPI:%d| def.SR[%d] max.CH[%d] latency{hi[%f] lo[%f]}\n", i, (UINT32)deviceInfo->defaultSampleRate, + deviceInfo->maxOutputChannels, (float)deviceInfo->defaultHighOutputLatency, (float)deviceInfo->defaultLowOutputLatency)); + break;} + case eCapture: { + deviceInfo->maxInputChannels = paWasapi->devInfo[i].MixFormat.Format.nChannels; + deviceInfo->defaultHighInputLatency = nano100ToSeconds(paWasapi->devInfo[i].DefaultDevicePeriod); + deviceInfo->defaultLowInputLatency = nano100ToSeconds(paWasapi->devInfo[i].MinimumDevicePeriod); + PA_DEBUG(("WASAPI:%d| def.SR[%d] max.CH[%d] latency{hi[%f] lo[%f]}\n", i, (UINT32)deviceInfo->defaultSampleRate, + deviceInfo->maxInputChannels, (float)deviceInfo->defaultHighInputLatency, (float)deviceInfo->defaultLowInputLatency)); + break; } + default: + PRINT(("WASAPI:%d| bad Data Flow!\n", i)); + // We need to set the result to a value otherwise we will return paNoError + result = paInternalError; + //continue; // do not skip from list, allow to initialize + break; + } + + hostApi->deviceInfos[i] = deviceInfo; + ++hostApi->info.deviceCount; + } + + #if defined(PA_WASAPI_MAX_CONST_DEVICE_COUNT) && (PA_WASAPI_MAX_CONST_DEVICE_COUNT > 0) + if (hostApi->info.deviceCount < PA_WASAPI_MAX_CONST_DEVICE_COUNT) + { + for (i = hostApi->info.deviceCount; i < PA_WASAPI_MAX_CONST_DEVICE_COUNT; ++i) + { + PaDeviceInfo *deviceInfo = &deviceInfoArray[i]; + deviceInfo->structVersion = 2; + deviceInfo->hostApi = hostApiIndex; + + if ((deviceInfo->name = (char *)PaUtil_GroupAllocateMemory(paWasapi->allocations, 1)) == NULL) + { + result = paInsufficientMemory; + goto error; + } + ((char *)deviceInfo->name)[0] = 0; + + hostApi->deviceInfos[i] = deviceInfo; + ++hostApi->info.deviceCount; + } + } + #endif + } + +#ifndef PA_WINRT + SAFE_RELEASE(pEndPoints); + SAFE_RELEASE(pEnumerator); +#endif + + PRINT(("WASAPI: device list created ok\n")); + + return paNoError; + +error: + + PRINT(("WASAPI: failed %s error[%d|%s]\n", __FUNCTION__, result, Pa_GetErrorText(result))); + +#ifndef PA_WINRT + SAFE_RELEASE(pEndPoints); + SAFE_RELEASE(pEnumerator); +#endif + + // Safety if error was not set so that we do not think initialize was a success + if (result == paNoError) + result = paInternalError; + + return result; +} + +// ------------------------------------------------------------------------------------------ +PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex ) +{ + PaError result; + PaWasapiHostApiRepresentation *paWasapi; + +#ifndef PA_WINRT + if (!SetupAVRT()) + { + PRINT(("WASAPI: No AVRT! (not VISTA?)\n")); + return paNoError; + } +#endif + + paWasapi = (PaWasapiHostApiRepresentation *)PaUtil_AllocateMemory(sizeof(PaWasapiHostApiRepresentation)); + if (paWasapi == NULL) + { + result = paInsufficientMemory; + goto error; + } + memset(paWasapi, 0, sizeof(PaWasapiHostApiRepresentation)); /* ensure all fields are zeroed. especially paWasapi->allocations */ + + // Initialize COM subsystem + result = PaWinUtil_CoInitialize(paWASAPI, &paWasapi->comInitializationResult); + if (result != paNoError) + goto error; + + // Create memory group + paWasapi->allocations = PaUtil_CreateAllocationGroup(); + if (paWasapi->allocations == NULL) + { + result = paInsufficientMemory; + goto error; + } + + // Fill basic interface info + *hostApi = &paWasapi->inheritedHostApiRep; + (*hostApi)->info.structVersion = 1; + (*hostApi)->info.type = paWASAPI; + (*hostApi)->info.name = "Windows WASAPI"; + (*hostApi)->info.deviceCount = 0; + (*hostApi)->info.defaultInputDevice = paNoDevice; + (*hostApi)->info.defaultOutputDevice = paNoDevice; + (*hostApi)->Terminate = Terminate; + (*hostApi)->OpenStream = OpenStream; + (*hostApi)->IsFormatSupported = IsFormatSupported; + + // Fill the device list + if ((result = CreateDeviceList(paWasapi, hostApiIndex)) != paNoError) + goto error; + + // Detect if platform workaround is required + paWasapi->useWOW64Workaround = UseWOW64Workaround(); + + PaUtil_InitializeStreamInterface( &paWasapi->callbackStreamInterface, CloseStream, StartStream, + StopStream, AbortStream, IsStreamStopped, IsStreamActive, + GetStreamTime, GetStreamCpuLoad, + PaUtil_DummyRead, PaUtil_DummyWrite, + PaUtil_DummyGetReadAvailable, PaUtil_DummyGetWriteAvailable ); + + PaUtil_InitializeStreamInterface( &paWasapi->blockingStreamInterface, CloseStream, StartStream, + StopStream, AbortStream, IsStreamStopped, IsStreamActive, + GetStreamTime, PaUtil_DummyGetCpuLoad, + ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable ); + + PRINT(("WASAPI: initialized ok\n")); + + return paNoError; + +error: + + PRINT(("WASAPI: failed %s error[%d|%s]\n", __FUNCTION__, result, Pa_GetErrorText(result))); + + Terminate((PaUtilHostApiRepresentation *)paWasapi); + + return result; +} + +// ------------------------------------------------------------------------------------------ +static void ReleaseWasapiDeviceInfoList( PaWasapiHostApiRepresentation *paWasapi ) +{ + UINT32 i; + + // Release device info bound objects + for (i = 0; i < paWasapi->deviceCount; ++i) + { + #ifndef PA_WINRT + SAFE_RELEASE(paWasapi->devInfo[i].device); + #endif + } + + // Free device info + if (paWasapi->allocations != NULL) + PaUtil_GroupFreeMemory(paWasapi->allocations, paWasapi->devInfo); + + // Be ready for a device list reinitialization and if its creation is failed pointers must not be dangling + paWasapi->devInfo = NULL; + paWasapi->deviceCount = 0; +} + +// ------------------------------------------------------------------------------------------ +static void Terminate( PaUtilHostApiRepresentation *hostApi ) +{ + PaWasapiHostApiRepresentation *paWasapi = (PaWasapiHostApiRepresentation*)hostApi; + if (paWasapi == NULL) + return; + + // Release device list + ReleaseWasapiDeviceInfoList(paWasapi); + + // Free allocations and memory group itself + if (paWasapi->allocations != NULL) + { + PaUtil_FreeAllAllocations(paWasapi->allocations); + PaUtil_DestroyAllocationGroup(paWasapi->allocations); + } + + // Release COM subsystem + PaWinUtil_CoUninitialize(paWASAPI, &paWasapi->comInitializationResult); + + // Free API representation + PaUtil_FreeMemory(paWasapi); + + // Close AVRT + CloseAVRT(); +} + +// ------------------------------------------------------------------------------------------ +static PaWasapiHostApiRepresentation *_GetHostApi(PaError *ret) +{ + PaError error; + PaUtilHostApiRepresentation *pApi; + + if ((error = PaUtil_GetHostApiRepresentation(&pApi, paWASAPI)) != paNoError) + { + if (ret != NULL) + (*ret) = error; + + return NULL; + } + + return (PaWasapiHostApiRepresentation *)pApi; +} + +// ------------------------------------------------------------------------------------------ +static PaError UpdateDeviceList() +{ + int i; + PaError ret; + PaWasapiHostApiRepresentation *paWasapi; + PaUtilHostApiRepresentation *hostApi; + + // Get API + hostApi = (PaUtilHostApiRepresentation *)(paWasapi = _GetHostApi(&ret)); + if (paWasapi == NULL) + return paNotInitialized; + + // Make sure initialized properly + if (paWasapi->allocations == NULL) + return paNotInitialized; + + // Release WASAPI internal device info list + ReleaseWasapiDeviceInfoList(paWasapi); + + // Release external device info list + if (hostApi->deviceInfos != NULL) + { + for (i = 0; i < hostApi->info.deviceCount; ++i) + { + PaUtil_GroupFreeMemory(paWasapi->allocations, (void *)hostApi->deviceInfos[i]->name); + } + PaUtil_GroupFreeMemory(paWasapi->allocations, hostApi->deviceInfos[0]); + PaUtil_GroupFreeMemory(paWasapi->allocations, hostApi->deviceInfos); + + // Be ready for a device list reinitialization and if its creation is failed pointers must not be dangling + hostApi->deviceInfos = NULL; + hostApi->info.deviceCount = 0; + hostApi->info.defaultInputDevice = paNoDevice; + hostApi->info.defaultOutputDevice = paNoDevice; + } + + // Fill possibly updated device list + if ((ret = CreateDeviceList(paWasapi, Pa_HostApiTypeIdToHostApiIndex(paWASAPI))) != paNoError) + return ret; + + return paNoError; +} + +// ------------------------------------------------------------------------------------------ +#if defined(PA_WASAPI_MAX_CONST_DEVICE_COUNT) && (PA_WASAPI_MAX_CONST_DEVICE_COUNT > 0) +PaError PaWasapi_UpdateDeviceList() +{ + return UpdateDeviceList(); +} +#endif + +// ------------------------------------------------------------------------------------------ +int PaWasapi_GetDeviceCurrentFormat( PaStream *pStream, void *pFormat, unsigned int formatSize, int bOutput ) +{ + UINT32 size; + WAVEFORMATEXTENSIBLE *format; + + PaWasapiStream *stream = (PaWasapiStream *)pStream; + if (stream == NULL) + return paBadStreamPtr; + + format = (bOutput == TRUE ? &stream->out.wavex : &stream->in.wavex); + + size = min(formatSize, (UINT32)sizeof(*format)); + memcpy(pFormat, format, size); + + return size; +} + +// ------------------------------------------------------------------------------------------ +int PaWasapi_GetDeviceDefaultFormat( void *pFormat, unsigned int formatSize, PaDeviceIndex device ) +{ + PaError ret; + PaWasapiHostApiRepresentation *paWasapi; + UINT32 size; + PaDeviceIndex index; + + if (pFormat == NULL) + return paBadBufferPtr; + if (formatSize <= 0) + return paBufferTooSmall; + + // Get API + paWasapi = _GetHostApi(&ret); + if (paWasapi == NULL) + return ret; + + // Get device index + ret = PaUtil_DeviceIndexToHostApiDeviceIndex(&index, device, &paWasapi->inheritedHostApiRep); + if (ret != paNoError) + return ret; + + // Validate index + if ((UINT32)index >= paWasapi->deviceCount) + return paInvalidDevice; + + size = min(formatSize, (UINT32)sizeof(paWasapi->devInfo[ index ].DefaultFormat)); + memcpy(pFormat, &paWasapi->devInfo[ index ].DefaultFormat, size); + + return size; +} + +// ------------------------------------------------------------------------------------------ +int PaWasapi_GetDeviceMixFormat( void *pFormat, unsigned int formatSize, PaDeviceIndex device ) +{ + PaError ret; + PaWasapiHostApiRepresentation *paWasapi; + UINT32 size; + PaDeviceIndex index; + + if (pFormat == NULL) + return paBadBufferPtr; + if (formatSize <= 0) + return paBufferTooSmall; + + // Get API + paWasapi = _GetHostApi(&ret); + if (paWasapi == NULL) + return ret; + + // Get device index + ret = PaUtil_DeviceIndexToHostApiDeviceIndex(&index, device, &paWasapi->inheritedHostApiRep); + if (ret != paNoError) + return ret; + + // Validate index + if ((UINT32)index >= paWasapi->deviceCount) + return paInvalidDevice; + + size = min(formatSize, (UINT32)sizeof(paWasapi->devInfo[ index ].MixFormat)); + memcpy(pFormat, &paWasapi->devInfo[ index ].MixFormat, size); + + return size; +} + +// ------------------------------------------------------------------------------------------ +int PaWasapi_GetDeviceRole( PaDeviceIndex device ) +{ + PaError ret; + PaDeviceIndex index; + + // Get API + PaWasapiHostApiRepresentation *paWasapi = _GetHostApi(&ret); + if (paWasapi == NULL) + return paNotInitialized; + + // Get device index + ret = PaUtil_DeviceIndexToHostApiDeviceIndex(&index, device, &paWasapi->inheritedHostApiRep); + if (ret != paNoError) + return ret; + + // Validate index + if ((UINT32)index >= paWasapi->deviceCount) + return paInvalidDevice; + + return paWasapi->devInfo[ index ].formFactor; +} + +// ------------------------------------------------------------------------------------------ +PaError PaWasapi_GetFramesPerHostBuffer( PaStream *pStream, unsigned int *pInput, unsigned int *pOutput ) +{ + PaWasapiStream *stream = (PaWasapiStream *)pStream; + if (stream == NULL) + return paBadStreamPtr; + + if (pInput != NULL) + (*pInput) = stream->in.framesPerHostCallback; + + if (pOutput != NULL) + (*pOutput) = stream->out.framesPerHostCallback; + + return paNoError; +} + +// ------------------------------------------------------------------------------------------ +static void LogWAVEFORMATEXTENSIBLE(const WAVEFORMATEXTENSIBLE *in) +{ + const WAVEFORMATEX *old = (WAVEFORMATEX *)in; + switch (old->wFormatTag) + { + case WAVE_FORMAT_EXTENSIBLE: { + + PRINT(("wFormatTag =WAVE_FORMAT_EXTENSIBLE\n")); + + if (IsEqualGUID(&in->SubFormat, &pa_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)) + { + PRINT(("SubFormat =KSDATAFORMAT_SUBTYPE_IEEE_FLOAT\n")); + } + else + if (IsEqualGUID(&in->SubFormat, &pa_KSDATAFORMAT_SUBTYPE_PCM)) + { + PRINT(("SubFormat =KSDATAFORMAT_SUBTYPE_PCM\n")); + } + else + { + PRINT(("SubFormat =CUSTOM GUID{%d:%d:%d:%d%d%d%d%d%d%d%d}\n", + in->SubFormat.Data1, + in->SubFormat.Data2, + in->SubFormat.Data3, + (int)in->SubFormat.Data4[0], + (int)in->SubFormat.Data4[1], + (int)in->SubFormat.Data4[2], + (int)in->SubFormat.Data4[3], + (int)in->SubFormat.Data4[4], + (int)in->SubFormat.Data4[5], + (int)in->SubFormat.Data4[6], + (int)in->SubFormat.Data4[7])); + } + PRINT(("Samples.wValidBitsPerSample =%d\n", in->Samples.wValidBitsPerSample)); + PRINT(("dwChannelMask =0x%X\n",in->dwChannelMask)); + + break; } + + case WAVE_FORMAT_PCM: PRINT(("wFormatTag =WAVE_FORMAT_PCM\n")); break; + case WAVE_FORMAT_IEEE_FLOAT: PRINT(("wFormatTag =WAVE_FORMAT_IEEE_FLOAT\n")); break; + default: + PRINT(("wFormatTag =UNKNOWN(%d)\n",old->wFormatTag)); break; + } + + PRINT(("nChannels =%d\n",old->nChannels)); + PRINT(("nSamplesPerSec =%d\n",old->nSamplesPerSec)); + PRINT(("nAvgBytesPerSec=%d\n",old->nAvgBytesPerSec)); + PRINT(("nBlockAlign =%d\n",old->nBlockAlign)); + PRINT(("wBitsPerSample =%d\n",old->wBitsPerSample)); + PRINT(("cbSize =%d\n",old->cbSize)); +} + +// ------------------------------------------------------------------------------------------ +PaSampleFormat WaveToPaFormat(const WAVEFORMATEXTENSIBLE *fmtext) +{ + const WAVEFORMATEX *fmt = (WAVEFORMATEX *)fmtext; + + switch (fmt->wFormatTag) + { + case WAVE_FORMAT_EXTENSIBLE: { + if (IsEqualGUID(&fmtext->SubFormat, &pa_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)) + { + if (fmtext->Samples.wValidBitsPerSample == 32) + return paFloat32; + } + else + if (IsEqualGUID(&fmtext->SubFormat, &pa_KSDATAFORMAT_SUBTYPE_PCM)) + { + switch (fmt->wBitsPerSample) + { + case 32: return paInt32; + case 24: return paInt24; + case 16: return paInt16; + case 8: return paUInt8; + } + } + break; } + + case WAVE_FORMAT_IEEE_FLOAT: + return paFloat32; + + case WAVE_FORMAT_PCM: { + switch (fmt->wBitsPerSample) + { + case 32: return paInt32; + case 24: return paInt24; + case 16: return paInt16; + case 8: return paUInt8; + } + break; } + } + + return paCustomFormat; +} + +// ------------------------------------------------------------------------------------------ +static PaError MakeWaveFormatFromParams(WAVEFORMATEXTENSIBLE *wavex, const PaStreamParameters *params, + double sampleRate, BOOL packedOnly) +{ + WORD bitsPerSample; + WAVEFORMATEX *old; + DWORD channelMask = 0; + BOOL useExtensible = (params->channelCount > 2); // format is always forced for >2 channels format + PaWasapiStreamInfo *streamInfo = (PaWasapiStreamInfo *)params->hostApiSpecificStreamInfo; + + // Convert PaSampleFormat to valid data bits + if ((bitsPerSample = PaSampleFormatToBitsPerSample(params->sampleFormat)) == 0) + return paSampleFormatNotSupported; + + // Use user assigned channel mask + if ((streamInfo != NULL) && (streamInfo->flags & paWinWasapiUseChannelMask)) + { + channelMask = streamInfo->channelMask; + useExtensible = TRUE; + } + + memset(wavex, 0, sizeof(*wavex)); + + old = (WAVEFORMATEX *)wavex; + old->nChannels = (WORD)params->channelCount; + old->nSamplesPerSec = (DWORD)sampleRate; + old->wBitsPerSample = bitsPerSample; + + // according to MSDN for WAVEFORMATEX structure for WAVE_FORMAT_PCM: + // "If wFormatTag is WAVE_FORMAT_PCM, then wBitsPerSample should be equal to 8 or 16." + if ((bitsPerSample != 8) && (bitsPerSample != 16)) + { + // Normally 20 or 24 bits must go in 32 bit containers (ints) but in Exclusive mode some devices require + // packed version of the format, e.g. for example 24-bit in 3-bytes + old->wBitsPerSample = (packedOnly ? bitsPerSample : 32); + useExtensible = TRUE; + } + + // WAVEFORMATEX + if (!useExtensible) + { + old->wFormatTag = WAVE_FORMAT_PCM; + } + // WAVEFORMATEXTENSIBLE + else + { + old->wFormatTag = WAVE_FORMAT_EXTENSIBLE; + old->cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX); + + if ((params->sampleFormat & ~paNonInterleaved) == paFloat32) + wavex->SubFormat = pa_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; + else + wavex->SubFormat = pa_KSDATAFORMAT_SUBTYPE_PCM; + + wavex->Samples.wValidBitsPerSample = bitsPerSample; + + // Set channel mask + if (channelMask != 0) + { + wavex->dwChannelMask = channelMask; + } + else + { + switch (params->channelCount) + { + case 1: wavex->dwChannelMask = PAWIN_SPEAKER_MONO; break; + case 2: wavex->dwChannelMask = PAWIN_SPEAKER_STEREO; break; + case 3: wavex->dwChannelMask = PAWIN_SPEAKER_STEREO|SPEAKER_LOW_FREQUENCY; break; + case 4: wavex->dwChannelMask = PAWIN_SPEAKER_QUAD; break; + case 5: wavex->dwChannelMask = PAWIN_SPEAKER_QUAD|SPEAKER_LOW_FREQUENCY; break; +#ifdef PAWIN_SPEAKER_5POINT1_SURROUND + case 6: wavex->dwChannelMask = PAWIN_SPEAKER_5POINT1_SURROUND; break; +#else + case 6: wavex->dwChannelMask = PAWIN_SPEAKER_5POINT1; break; +#endif +#ifdef PAWIN_SPEAKER_5POINT1_SURROUND + case 7: wavex->dwChannelMask = PAWIN_SPEAKER_5POINT1_SURROUND|SPEAKER_BACK_CENTER; break; +#else + case 7: wavex->dwChannelMask = PAWIN_SPEAKER_5POINT1|SPEAKER_BACK_CENTER; break; +#endif +#ifdef PAWIN_SPEAKER_7POINT1_SURROUND + case 8: wavex->dwChannelMask = PAWIN_SPEAKER_7POINT1_SURROUND; break; +#else + case 8: wavex->dwChannelMask = PAWIN_SPEAKER_7POINT1; break; +#endif + + default: wavex->dwChannelMask = 0; + } + } + } + + old->nBlockAlign = old->nChannels * (old->wBitsPerSample / 8); + old->nAvgBytesPerSec = old->nSamplesPerSec * old->nBlockAlign; + + return paNoError; +} + +// ------------------------------------------------------------------------------------------ +static HRESULT GetAlternativeSampleFormatExclusive(IAudioClient *client, double sampleRate, + const PaStreamParameters *params, WAVEFORMATEXTENSIBLE *outWavex, BOOL packedSampleFormatOnly) +{ + HRESULT hr = !S_OK; + AUDCLNT_SHAREMODE shareMode = AUDCLNT_SHAREMODE_EXCLUSIVE; + WAVEFORMATEXTENSIBLE testFormat; + PaStreamParameters testParams; + int i; + static const PaSampleFormat bestToWorst[] = { paInt32, paInt24, paFloat32, paInt16 }; + + // Try combination Stereo (2 channels) and then we will use our custom mono-stereo mixer + if (params->channelCount == 1) + { + testParams = (*params); + testParams.channelCount = 2; + + if (MakeWaveFormatFromParams(&testFormat, &testParams, sampleRate, packedSampleFormatOnly) == paNoError) + { + if ((hr = IAudioClient_IsFormatSupported(client, shareMode, &testFormat.Format, NULL)) == S_OK) + { + (*outWavex) = testFormat; + return hr; + } + } + + // Try selecting suitable sample type + for (i = 0; i < STATIC_ARRAY_SIZE(bestToWorst); ++i) + { + testParams.sampleFormat = bestToWorst[i]; + + if (MakeWaveFormatFromParams(&testFormat, &testParams, sampleRate, packedSampleFormatOnly) == paNoError) + { + if ((hr = IAudioClient_IsFormatSupported(client, shareMode, &testFormat.Format, NULL)) == S_OK) + { + (*outWavex) = testFormat; + return hr; + } + } + } + } + + // Try selecting suitable sample type + testParams = (*params); + for (i = 0; i < STATIC_ARRAY_SIZE(bestToWorst); ++i) + { + testParams.sampleFormat = bestToWorst[i]; + + if (MakeWaveFormatFromParams(&testFormat, &testParams, sampleRate, packedSampleFormatOnly) == paNoError) + { + if ((hr = IAudioClient_IsFormatSupported(client, shareMode, &testFormat.Format, NULL)) == S_OK) + { + (*outWavex) = testFormat; + return hr; + } + } + } + + return hr; +} + +// ------------------------------------------------------------------------------------------ +static PaError GetClosestFormat(IAudioClient *client, double sampleRate, const PaStreamParameters *_params, + AUDCLNT_SHAREMODE shareMode, WAVEFORMATEXTENSIBLE *outWavex, BOOL output) +{ + PaWasapiStreamInfo *streamInfo = (PaWasapiStreamInfo *)_params->hostApiSpecificStreamInfo; + WAVEFORMATEX *sharedClosestMatch = NULL; + HRESULT hr = !S_OK; + PaStreamParameters params = (*_params); + const BOOL explicitFormat = (streamInfo != NULL) && ((streamInfo->flags & paWinWasapiExplicitSampleFormat) == paWinWasapiExplicitSampleFormat); + (void)output; + + /* It was not noticed that 24-bit Input producing no output while device accepts this format. + To fix this issue let's ask for 32-bits and let PA converters convert host 32-bit data + to 24-bit for user-space. The bug concerns Vista, if Windows 7 supports 24-bits for Input + please report to PortAudio developers to exclude Windows 7. + */ + /*if ((params.sampleFormat == paInt24) && (output == FALSE)) + params.sampleFormat = paFloat32;*/ // <<< The silence was due to missing Int32_To_Int24_Dither implementation + + // Try standard approach, e.g. if data is > 16 bits it will be packed into 32-bit containers + MakeWaveFormatFromParams(outWavex, ¶ms, sampleRate, FALSE); + + // If built-in PCM converter requested then shared mode format will always succeed + if ((GetWindowsVersion() >= WINDOWS_7_SERVER2008R2) && + (shareMode == AUDCLNT_SHAREMODE_SHARED) && + ((streamInfo != NULL) && (streamInfo->flags & paWinWasapiAutoConvert))) + return paFormatIsSupported; + + hr = IAudioClient_IsFormatSupported(client, shareMode, &outWavex->Format, (shareMode == AUDCLNT_SHAREMODE_SHARED ? &sharedClosestMatch : NULL)); + + // Exclusive mode can require packed format for some devices + if ((hr != S_OK) && (shareMode == AUDCLNT_SHAREMODE_EXCLUSIVE)) + { + // Enforce packed only format, e.g. data bits will not be packed into 32-bit containers in any case + MakeWaveFormatFromParams(outWavex, ¶ms, sampleRate, TRUE); + hr = IAudioClient_IsFormatSupported(client, shareMode, &outWavex->Format, NULL); + } + + if (hr == S_OK) + { + return paFormatIsSupported; + } + else + if (sharedClosestMatch != NULL) + { + WORD bitsPerSample; + + if (sharedClosestMatch->wFormatTag == WAVE_FORMAT_EXTENSIBLE) + memcpy(outWavex, sharedClosestMatch, sizeof(WAVEFORMATEXTENSIBLE)); + else + memcpy(outWavex, sharedClosestMatch, sizeof(WAVEFORMATEX)); + + CoTaskMemFree(sharedClosestMatch); + sharedClosestMatch = NULL; + + // Validate SampleRate + if ((DWORD)sampleRate != outWavex->Format.nSamplesPerSec) + return paInvalidSampleRate; + + // Validate Channel count + if ((WORD)params.channelCount != outWavex->Format.nChannels) + { + // If mono, then driver does not support 1 channel, we use internal workaround + // of tiny software mixing functionality, e.g. we provide to user buffer 1 channel + // but then mix into 2 for device buffer + if ((params.channelCount == 1) && (outWavex->Format.nChannels == 2)) + return paFormatIsSupported; + else + return paInvalidChannelCount; + } + + // Validate Sample format + if ((bitsPerSample = PaSampleFormatToBitsPerSample(params.sampleFormat)) == 0) + return paSampleFormatNotSupported; + + // Accepted format + return paFormatIsSupported; + } + else + if ((shareMode == AUDCLNT_SHAREMODE_EXCLUSIVE) && !explicitFormat) + { + // Try standard approach, e.g. if data is > 16 bits it will be packed into 32-bit containers + if ((hr = GetAlternativeSampleFormatExclusive(client, sampleRate, ¶ms, outWavex, FALSE)) == S_OK) + return paFormatIsSupported; + + // Enforce packed only format, e.g. data bits will not be packed into 32-bit containers in any case + if ((hr = GetAlternativeSampleFormatExclusive(client, sampleRate, ¶ms, outWavex, TRUE)) == S_OK) + return paFormatIsSupported; + + // Log failure + LogHostError(hr); + } + else + { + // Exclusive mode and requested strict format, WASAPI did not accept this sample format + LogHostError(hr); + } + + return paInvalidSampleRate; +} + +// ------------------------------------------------------------------------------------------ +static PaError IsStreamParamsValid(struct PaUtilHostApiRepresentation *hostApi, + const PaStreamParameters *inputParameters, + const PaStreamParameters *outputParameters, + double sampleRate) +{ + if (hostApi == NULL) + return paHostApiNotFound; + if ((UINT32)sampleRate == 0) + return paInvalidSampleRate; + + if (inputParameters != NULL) + { + /* all standard sample formats are supported by the buffer adapter, + this implementation doesn't support any custom sample formats */ + // Note: paCustomFormat is now 8.24 (24-bits in 32-bit containers) + //if (inputParameters->sampleFormat & paCustomFormat) + // return paSampleFormatNotSupported; + + /* unless alternate device specification is supported, reject the use of + paUseHostApiSpecificDeviceSpecification */ + if (inputParameters->device == paUseHostApiSpecificDeviceSpecification) + return paInvalidDevice; + + /* check that input device can support inputChannelCount */ + if (inputParameters->channelCount > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels) + return paInvalidChannelCount; + + /* validate inputStreamInfo */ + if (inputParameters->hostApiSpecificStreamInfo) + { + PaWasapiStreamInfo *inputStreamInfo = (PaWasapiStreamInfo *)inputParameters->hostApiSpecificStreamInfo; + if ((inputStreamInfo->size != sizeof(PaWasapiStreamInfo)) || + (inputStreamInfo->version != 1) || + (inputStreamInfo->hostApiType != paWASAPI)) + { + return paIncompatibleHostApiSpecificStreamInfo; + } + } + + return paNoError; + } + + if (outputParameters != NULL) + { + /* all standard sample formats are supported by the buffer adapter, + this implementation doesn't support any custom sample formats */ + // Note: paCustomFormat is now 8.24 (24-bits in 32-bit containers) + //if (outputParameters->sampleFormat & paCustomFormat) + // return paSampleFormatNotSupported; + + /* unless alternate device specification is supported, reject the use of + paUseHostApiSpecificDeviceSpecification */ + if (outputParameters->device == paUseHostApiSpecificDeviceSpecification) + return paInvalidDevice; + + /* check that output device can support outputChannelCount */ + if (outputParameters->channelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels) + return paInvalidChannelCount; + + /* validate outputStreamInfo */ + if(outputParameters->hostApiSpecificStreamInfo) + { + PaWasapiStreamInfo *outputStreamInfo = (PaWasapiStreamInfo *)outputParameters->hostApiSpecificStreamInfo; + if ((outputStreamInfo->size != sizeof(PaWasapiStreamInfo)) || + (outputStreamInfo->version != 1) || + (outputStreamInfo->hostApiType != paWASAPI)) + { + return paIncompatibleHostApiSpecificStreamInfo; + } + } + + return paNoError; + } + + return (inputParameters || outputParameters ? paNoError : paInternalError); +} + +// ------------------------------------------------------------------------------------------ +static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi, + const PaStreamParameters *inputParameters, + const PaStreamParameters *outputParameters, + double sampleRate ) +{ + IAudioClient *tmpClient = NULL; + PaWasapiHostApiRepresentation *paWasapi = (PaWasapiHostApiRepresentation*)hostApi; + PaWasapiStreamInfo *inputStreamInfo = NULL, *outputStreamInfo = NULL; + + // Validate PaStreamParameters + PaError error; + if ((error = IsStreamParamsValid(hostApi, inputParameters, outputParameters, sampleRate)) != paNoError) + return error; + + if (inputParameters != NULL) + { + WAVEFORMATEXTENSIBLE wavex; + HRESULT hr; + PaError answer; + AUDCLNT_SHAREMODE shareMode = AUDCLNT_SHAREMODE_SHARED; + inputStreamInfo = (PaWasapiStreamInfo *)inputParameters->hostApiSpecificStreamInfo; + + if (inputStreamInfo && (inputStreamInfo->flags & paWinWasapiExclusive)) + shareMode = AUDCLNT_SHAREMODE_EXCLUSIVE; + + hr = ActivateAudioInterface(&paWasapi->devInfo[inputParameters->device], inputStreamInfo, &tmpClient); + if (hr != S_OK) + { + LogHostError(hr); + return paInvalidDevice; + } + + answer = GetClosestFormat(tmpClient, sampleRate, inputParameters, shareMode, &wavex, FALSE); + SAFE_RELEASE(tmpClient); + + if (answer != paFormatIsSupported) + return answer; + } + + if (outputParameters != NULL) + { + HRESULT hr; + WAVEFORMATEXTENSIBLE wavex; + PaError answer; + AUDCLNT_SHAREMODE shareMode = AUDCLNT_SHAREMODE_SHARED; + outputStreamInfo = (PaWasapiStreamInfo *)outputParameters->hostApiSpecificStreamInfo; + + if (outputStreamInfo && (outputStreamInfo->flags & paWinWasapiExclusive)) + shareMode = AUDCLNT_SHAREMODE_EXCLUSIVE; + + hr = ActivateAudioInterface(&paWasapi->devInfo[outputParameters->device], outputStreamInfo, &tmpClient); + if (hr != S_OK) + { + LogHostError(hr); + return paInvalidDevice; + } + + answer = GetClosestFormat(tmpClient, sampleRate, outputParameters, shareMode, &wavex, TRUE); + SAFE_RELEASE(tmpClient); + + if (answer != paFormatIsSupported) + return answer; + } + + return paFormatIsSupported; +} + +// ------------------------------------------------------------------------------------------ +static PaUint32 _GetFramesPerHostBuffer(PaUint32 userFramesPerBuffer, PaTime suggestedLatency, double sampleRate, PaUint32 TimerJitterMs) +{ + PaUint32 frames = userFramesPerBuffer + max( userFramesPerBuffer, (PaUint32)(suggestedLatency * sampleRate) ); + frames += (PaUint32)((sampleRate * 0.001) * TimerJitterMs); + return frames; +} + +// ------------------------------------------------------------------------------------------ +static void _RecalculateBuffersCount(PaWasapiSubStream *sub, UINT32 userFramesPerBuffer, UINT32 framesPerLatency, BOOL fullDuplex) +{ + // Count buffers (must be at least 1) + sub->buffers = (userFramesPerBuffer ? framesPerLatency / userFramesPerBuffer : 0); + if (sub->buffers == 0) + sub->buffers = 1; + + // Determine amount of buffers used: + // - Full-duplex mode will lead to period difference, thus only 1. + // - Input mode, only 1, as WASAPI allows extraction of only 1 packet. + // - For Shared mode we use double buffering. + if ((sub->shareMode == AUDCLNT_SHAREMODE_EXCLUSIVE) || fullDuplex) + { + // Exclusive mode does not allow >1 buffers be used for Event interface, e.g. GetBuffer + // call must acquire max buffer size and it all must be processed. + if (sub->streamFlags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK) + sub->userBufferAndHostMatch = 1; + + // Use paUtilBoundedHostBufferSize because exclusive mode will starve and produce + // bad quality of audio + sub->buffers = 1; + } +} + +// ------------------------------------------------------------------------------------------ +static void _CalculateAlignedPeriod(PaWasapiSubStream *pSub, UINT32 *nFramesPerLatency, ALIGN_FUNC pAlignFunc) +{ + // Align frames to HD Audio packet size of 128 bytes for Exclusive mode only. + // Not aligning on Windows Vista will cause Event timeout, although Windows 7 will + // return AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED error to realign buffer. Aligning is necessary + // for Exclusive mode only! when audio data is feeded directly to hardware. + if (pSub->shareMode == AUDCLNT_SHAREMODE_EXCLUSIVE) + { + (*nFramesPerLatency) = AlignFramesPerBuffer((*nFramesPerLatency), + pSub->wavex.Format.nSamplesPerSec, pSub->wavex.Format.nBlockAlign, pAlignFunc); + } + + // Calculate period + pSub->period = MakeHnsPeriod((*nFramesPerLatency), pSub->wavex.Format.nSamplesPerSec); +} + +// ------------------------------------------------------------------------------------------ +static void _CalculatePeriodicity(PaWasapiSubStream *pSub, BOOL output, REFERENCE_TIME *periodicity) +{ + // Note: according Microsoft docs for IAudioClient::Initialize we can set periodicity of the buffer + // only for Exclusive mode. By setting periodicity almost equal to the user buffer frames we can + // achieve high quality (less glitchy) low-latency audio. + if (pSub->shareMode == AUDCLNT_SHAREMODE_EXCLUSIVE) + { + const PaWasapiDeviceInfo *pInfo = pSub->params.device_info; + + // By default periodicity equals to the full buffer (legacy PA WASAPI's behavior) + (*periodicity) = pSub->period; + + // Try make buffer ready for I/O once we request the buffer readiness for it. Only Polling mode + // because for Event mode buffer size and periodicity must be equal according Microsoft + // documentation for IAudioClient::Initialize. + // + // TO-DO: try spread to capture and full-duplex cases (not tested and therefore disabled) + // + if (((pSub->streamFlags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK) == 0) && + (output && !pSub->params.full_duplex)) + { + UINT32 alignedFrames; + REFERENCE_TIME userPeriodicity; + + // Align frames backwards, so device will likely make buffer read ready when we are ready + // to read it (our sheduling will wait for amount of millisoconds of frames_per_buffer) + alignedFrames = AlignFramesPerBuffer(pSub->params.frames_per_buffer, + pSub->wavex.Format.nSamplesPerSec, pSub->wavex.Format.nBlockAlign, ALIGN_BWD); + + userPeriodicity = MakeHnsPeriod(alignedFrames, pSub->wavex.Format.nSamplesPerSec); + + // Must not be larger than buffer size + if (userPeriodicity > pSub->period) + userPeriodicity = pSub->period; + + // Must not be smaller than minimum supported by the device + if (userPeriodicity < pInfo->MinimumDevicePeriod) + userPeriodicity = pInfo->MinimumDevicePeriod; + + (*periodicity) = userPeriodicity; + } + } + else + (*periodicity) = 0; +} + +// ------------------------------------------------------------------------------------------ +static HRESULT CreateAudioClient(PaWasapiStream *pStream, PaWasapiSubStream *pSub, BOOL output, PaError *pa_error) +{ + PaError error; + HRESULT hr; + const PaWasapiDeviceInfo *pInfo = pSub->params.device_info; + const PaStreamParameters *params = &pSub->params.stream_params; + const double sampleRate = pSub->params.sample_rate; + const BOOL fullDuplex = pSub->params.full_duplex; + const UINT32 userFramesPerBuffer = pSub->params.frames_per_buffer; + UINT32 framesPerLatency = userFramesPerBuffer; + IAudioClient *audioClient = NULL; + REFERENCE_TIME eventPeriodicity = 0; + + // Assume default failure due to some reason + (*pa_error) = paInvalidDevice; + + // Validate parameters + if (!pSub || !pInfo || !params) + { + (*pa_error) = paBadStreamPtr; + return E_POINTER; + } + if ((UINT32)sampleRate == 0) + { + (*pa_error) = paInvalidSampleRate; + return E_INVALIDARG; + } + + // Get the audio client + if (FAILED(hr = ActivateAudioInterface(pInfo, &pSub->params.wasapi_params, &audioClient))) + { + (*pa_error) = paInsufficientMemory; + LogHostError(hr); + goto done; + } + + // Get closest format + if ((error = GetClosestFormat(audioClient, sampleRate, params, pSub->shareMode, &pSub->wavex, output)) != paFormatIsSupported) + { + (*pa_error) = error; + LogHostError(hr = AUDCLNT_E_UNSUPPORTED_FORMAT); + goto done; // fail, format not supported + } + + // Check for Mono <<>> Stereo workaround + if ((params->channelCount == 1) && (pSub->wavex.Format.nChannels == 2)) + { + // select mixer + pSub->monoMixer = GetMonoToStereoMixer(&pSub->wavex, (pInfo->flow == eRender ? MIX_DIR__1TO2 : MIX_DIR__2TO1_L)); + if (pSub->monoMixer == NULL) + { + (*pa_error) = paInvalidChannelCount; + LogHostError(hr = AUDCLNT_E_UNSUPPORTED_FORMAT); + goto done; // fail, no mixer for format + } + } + + // Calculate host buffer size + if ((pSub->shareMode != AUDCLNT_SHAREMODE_EXCLUSIVE) && + (!pSub->streamFlags || ((pSub->streamFlags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK) == 0))) + { + framesPerLatency = _GetFramesPerHostBuffer(userFramesPerBuffer, + params->suggestedLatency, pSub->wavex.Format.nSamplesPerSec, 0/*, + (pSub->streamFlags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK ? 0 : 1)*/); + } + else + { + #ifdef PA_WASAPI_FORCE_POLL_IF_LARGE_BUFFER + REFERENCE_TIME overall; + #endif + + // Work 1:1 with user buffer (only polling allows to use >1) + framesPerLatency += MakeFramesFromHns(SecondsTonano100(params->suggestedLatency), pSub->wavex.Format.nSamplesPerSec); + + // Force Polling if overall latency is >= 21.33ms as it allows to use 100% CPU in a callback, + // or user specified latency parameter. + #ifdef PA_WASAPI_FORCE_POLL_IF_LARGE_BUFFER + overall = MakeHnsPeriod(framesPerLatency, pSub->wavex.Format.nSamplesPerSec); + if (overall >= (106667 * 2)/*21.33ms*/) + { + framesPerLatency = _GetFramesPerHostBuffer(userFramesPerBuffer, + params->suggestedLatency, pSub->wavex.Format.nSamplesPerSec, 0/*, + (streamFlags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK ? 0 : 1)*/); + + // Use Polling interface + pSub->streamFlags &= ~AUDCLNT_STREAMFLAGS_EVENTCALLBACK; + PRINT(("WASAPI: CreateAudioClient: forcing POLL mode\n")); + } + #endif + } + + // For full-duplex output resize buffer to be the same as for input + if (output && fullDuplex) + framesPerLatency = pStream->in.framesPerHostCallback; + + // Avoid 0 frames + if (framesPerLatency == 0) + framesPerLatency = MakeFramesFromHns(pInfo->DefaultDevicePeriod, pSub->wavex.Format.nSamplesPerSec); + + // Exclusive Input stream renders data in 6 packets, we must set then the size of + // single packet, total buffer size, e.g. required latency will be PacketSize * 6 + if (!output && (pSub->shareMode == AUDCLNT_SHAREMODE_EXCLUSIVE)) + { + // Do it only for Polling mode + if ((pSub->streamFlags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK) == 0) + framesPerLatency /= WASAPI_PACKETS_PER_INPUT_BUFFER; + } + + // Calculate aligned period + _CalculateAlignedPeriod(pSub, &framesPerLatency, ALIGN_BWD); + + /*! Enforce min/max period for device in Shared mode to avoid bad audio quality. + Avoid doing so for Exclusive mode as alignment will suffer. + */ + if (pSub->shareMode == AUDCLNT_SHAREMODE_SHARED) + { + if (pSub->period < pInfo->DefaultDevicePeriod) + { + pSub->period = pInfo->DefaultDevicePeriod; + + // Recalculate aligned period + framesPerLatency = MakeFramesFromHns(pSub->period, pSub->wavex.Format.nSamplesPerSec); + _CalculateAlignedPeriod(pSub, &framesPerLatency, ALIGN_BWD); + } + } + else + { + if (pSub->period < pInfo->MinimumDevicePeriod) + { + pSub->period = pInfo->MinimumDevicePeriod; + + // Recalculate aligned period + framesPerLatency = MakeFramesFromHns(pSub->period, pSub->wavex.Format.nSamplesPerSec); + _CalculateAlignedPeriod(pSub, &framesPerLatency, ALIGN_FWD); + } + } + + /*! Windows 7 does not allow to set latency lower than minimal device period and will + return error: AUDCLNT_E_INVALID_DEVICE_PERIOD. Under Vista we enforce the same behavior + manually for unified behavior on all platforms. + */ + { + /*! AUDCLNT_E_BUFFER_SIZE_ERROR: Applies to Windows 7 and later. + Indicates that the buffer duration value requested by an exclusive-mode client is + out of range. The requested duration value for pull mode must not be greater than + 500 milliseconds; for push mode the duration value must not be greater than 2 seconds. + */ + if (pSub->shareMode == AUDCLNT_SHAREMODE_EXCLUSIVE) + { + static const REFERENCE_TIME MAX_BUFFER_EVENT_DURATION = 500 * 10000; + static const REFERENCE_TIME MAX_BUFFER_POLL_DURATION = 2000 * 10000; + + // Pull mode, max 500ms + if (pSub->streamFlags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK) + { + if (pSub->period > MAX_BUFFER_EVENT_DURATION) + { + pSub->period = MAX_BUFFER_EVENT_DURATION; + + // Recalculate aligned period + framesPerLatency = MakeFramesFromHns(pSub->period, pSub->wavex.Format.nSamplesPerSec); + _CalculateAlignedPeriod(pSub, &framesPerLatency, ALIGN_BWD); + } + } + // Push mode, max 2000ms + else + { + if (pSub->period > MAX_BUFFER_POLL_DURATION) + { + pSub->period = MAX_BUFFER_POLL_DURATION; + + // Recalculate aligned period + framesPerLatency = MakeFramesFromHns(pSub->period, pSub->wavex.Format.nSamplesPerSec); + _CalculateAlignedPeriod(pSub, &framesPerLatency, ALIGN_BWD); + } + } + } + } + + // Set device scheduling period (always 0 in Shared mode according Microsoft docs) + _CalculatePeriodicity(pSub, output, &eventPeriodicity); + + // Open the stream and associate it with an audio session + hr = IAudioClient_Initialize(audioClient, + pSub->shareMode, + pSub->streamFlags, + pSub->period, + eventPeriodicity, + &pSub->wavex.Format, + NULL); + + // [Output only] Check if buffer size is the one we requested in Exclusive mode, for UAC1 USB DACs WASAPI + // can allocate internal buffer equal to 8 times of pSub->period that has to be corrected in order to match + // the requested latency + if (output && SUCCEEDED(hr) && (pSub->shareMode == AUDCLNT_SHAREMODE_EXCLUSIVE)) + { + UINT32 maxBufferFrames; + + if (FAILED(hr = IAudioClient_GetBufferSize(audioClient, &maxBufferFrames))) + { + (*pa_error) = paInvalidDevice; + LogHostError(hr); + goto done; + } + + // For Exclusive mode for UAC1 devices maxBufferFrames may be framesPerLatency * 8 but check any difference + // to be able to guarantee the latency user requested and also resulted framesPerLatency may be bigger than + // 2 seconds that will cause audio client not operational (GetCurrentPadding() will return always 0) + if (maxBufferFrames >= (framesPerLatency * 2)) + { + UINT32 ratio = maxBufferFrames / framesPerLatency; + + PRINT(("WASAPI: CreateAudioClient: detected %d times larger buffer than requested, correct to match user latency\n", ratio)); + + // Get new aligned frames lowered by calculated ratio + framesPerLatency = MakeFramesFromHns(pSub->period / ratio, pSub->wavex.Format.nSamplesPerSec); + _CalculateAlignedPeriod(pSub, &framesPerLatency, ALIGN_BWD); + + // Make sure we are not below the minimum period + if (pSub->period < pInfo->MinimumDevicePeriod) + pSub->period = pInfo->MinimumDevicePeriod; + + // Release previous client + SAFE_RELEASE(audioClient); + + // Create a new audio client + if (FAILED(hr = ActivateAudioInterface(pInfo, &pSub->params.wasapi_params, &audioClient))) + { + (*pa_error) = paInsufficientMemory; + LogHostError(hr); + goto done; + } + + // Set device scheduling period (always 0 in Shared mode according Microsoft docs) + _CalculatePeriodicity(pSub, output, &eventPeriodicity); + + // Open the stream and associate it with an audio session + hr = IAudioClient_Initialize(audioClient, + pSub->shareMode, + pSub->streamFlags, + pSub->period, + eventPeriodicity, + &pSub->wavex.Format, + NULL); + } + } + + /*! WASAPI is tricky on large device buffer, sometimes 2000ms can be allocated sometimes + less. There is no known guaranteed level thus we make subsequent tries by decreasing + buffer by 100ms per try. + */ + while ((hr == E_OUTOFMEMORY) && (pSub->period > (100 * 10000))) + { + PRINT(("WASAPI: CreateAudioClient: decreasing buffer size to %d milliseconds\n", (pSub->period / 10000))); + + // Decrease by 100ms and try again + pSub->period -= (100 * 10000); + + // Recalculate aligned period + framesPerLatency = MakeFramesFromHns(pSub->period, pSub->wavex.Format.nSamplesPerSec); + _CalculateAlignedPeriod(pSub, &framesPerLatency, ALIGN_BWD); + + // Release the previous allocations + SAFE_RELEASE(audioClient); + + // Create a new audio client + if (FAILED(hr = ActivateAudioInterface(pInfo, &pSub->params.wasapi_params, &audioClient))) + { + (*pa_error) = paInsufficientMemory; + LogHostError(hr); + goto done; + } + + // Set device scheduling period (always 0 in Shared mode according Microsoft docs) + _CalculatePeriodicity(pSub, output, &eventPeriodicity); + + // Open the stream and associate it with an audio session + hr = IAudioClient_Initialize(audioClient, + pSub->shareMode, + pSub->streamFlags, + pSub->period, + eventPeriodicity, + &pSub->wavex.Format, + NULL); + } + + /*! WASAPI buffer size or alignment failure. Fallback to using default size and alignment. + */ + if ((hr == AUDCLNT_E_BUFFER_SIZE_ERROR) || (hr == AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED)) + { + // Use default + pSub->period = pInfo->DefaultDevicePeriod; + + PRINT(("WASAPI: CreateAudioClient: correcting buffer size/alignment to device default\n")); + + // Release the previous allocations + SAFE_RELEASE(audioClient); + + // Create a new audio client + if (FAILED(hr = ActivateAudioInterface(pInfo, &pSub->params.wasapi_params, &audioClient))) + { + (*pa_error) = paInsufficientMemory; + LogHostError(hr); + goto done; + } + + // Set device scheduling period (always 0 in Shared mode according Microsoft docs) + _CalculatePeriodicity(pSub, output, &eventPeriodicity); + + // Open the stream and associate it with an audio session + hr = IAudioClient_Initialize(audioClient, + pSub->shareMode, + pSub->streamFlags, + pSub->period, + eventPeriodicity, + &pSub->wavex.Format, + NULL); + } + + // Error has no workaround, fail completely + if (FAILED(hr)) + { + (*pa_error) = paInvalidDevice; + LogHostError(hr); + goto done; + } + + // Set client + pSub->clientParent = audioClient; + IAudioClient_AddRef(pSub->clientParent); + + // Recalculate buffers count + _RecalculateBuffersCount(pSub, userFramesPerBuffer, MakeFramesFromHns(pSub->period, pSub->wavex.Format.nSamplesPerSec), + fullDuplex); + + // No error, client is succesfully created + (*pa_error) = paNoError; + +done: + + // Clean up + SAFE_RELEASE(audioClient); + return hr; +} + +// ------------------------------------------------------------------------------------------ +static PaError ActivateAudioClientOutput(PaWasapiStream *stream) +{ + HRESULT hr; + PaError result; + UINT32 maxBufferSize; + PaTime bufferLatency; + const UINT32 framesPerBuffer = stream->out.params.frames_per_buffer; + + // Create Audio client + if (FAILED(hr = CreateAudioClient(stream, &stream->out, TRUE, &result))) + { + LogPaError(result); + goto error; + } + LogWAVEFORMATEXTENSIBLE(&stream->out.wavex); + + // Activate volume + stream->outVol = NULL; + /*hr = info->device->Activate( + __uuidof(IAudioEndpointVolume), CLSCTX_INPROC_SERVER, NULL, + (void**)&stream->outVol); + if (hr != S_OK) + return paInvalidDevice;*/ + + // Get max possible buffer size to check if it is not less than that we request + if (FAILED(hr = IAudioClient_GetBufferSize(stream->out.clientParent, &maxBufferSize))) + { + LogHostError(hr); + LogPaError(result = paInvalidDevice); + goto error; + } + + // Correct buffer to max size if it maxed out result of GetBufferSize + stream->out.bufferSize = maxBufferSize; + + // Get interface latency (actually uneeded as we calculate latency from the size of maxBufferSize) + if (FAILED(hr = IAudioClient_GetStreamLatency(stream->out.clientParent, &stream->out.deviceLatency))) + { + LogHostError(hr); + LogPaError(result = paInvalidDevice); + goto error; + } + //stream->out.latencySeconds = nano100ToSeconds(stream->out.deviceLatency); + + // Number of frames that are required at each period + stream->out.framesPerHostCallback = maxBufferSize; + + // Calculate frames per single buffer, if buffers > 1 then always framesPerBuffer + stream->out.framesPerBuffer = + (stream->out.userBufferAndHostMatch ? stream->out.framesPerHostCallback : framesPerBuffer); + + // Calculate buffer latency + bufferLatency = (PaTime)maxBufferSize / stream->out.wavex.Format.nSamplesPerSec; + + // Append buffer latency to interface latency in shared mode (see GetStreamLatency notes) + stream->out.latencySeconds = bufferLatency; + + PRINT(("WASAPI::OpenStream(output): framesPerUser[ %d ] framesPerHost[ %d ] latency[ %.02fms ] exclusive[ %s ] wow64_fix[ %s ] mode[ %s ]\n", (UINT32)framesPerBuffer, (UINT32)stream->out.framesPerHostCallback, (float)(stream->out.latencySeconds*1000.0f), (stream->out.shareMode == AUDCLNT_SHAREMODE_EXCLUSIVE ? "YES" : "NO"), (stream->out.params.wow64_workaround ? "YES" : "NO"), (stream->out.streamFlags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK ? "EVENT" : "POLL"))); + + return paNoError; + +error: + + return result; +} + +// ------------------------------------------------------------------------------------------ +static PaError ActivateAudioClientInput(PaWasapiStream *stream) +{ + HRESULT hr; + PaError result; + UINT32 maxBufferSize; + PaTime bufferLatency; + const UINT32 framesPerBuffer = stream->in.params.frames_per_buffer; + + // Create Audio client + if (FAILED(hr = CreateAudioClient(stream, &stream->in, FALSE, &result))) + { + LogPaError(result); + goto error; + } + LogWAVEFORMATEXTENSIBLE(&stream->in.wavex); + + // Create volume mgr + stream->inVol = NULL; + /*hr = info->device->Activate( + __uuidof(IAudioEndpointVolume), CLSCTX_INPROC_SERVER, NULL, + (void**)&stream->inVol); + if (hr != S_OK) + return paInvalidDevice;*/ + + // Get max possible buffer size to check if it is not less than that we request + if (FAILED(hr = IAudioClient_GetBufferSize(stream->in.clientParent, &maxBufferSize))) + { + LogHostError(hr); + LogPaError(result = paInvalidDevice); + goto error; + } + + // Correct buffer to max size if it maxed out result of GetBufferSize + stream->in.bufferSize = maxBufferSize; + + // Get interface latency (actually uneeded as we calculate latency from the size + // of maxBufferSize). + if (FAILED(hr = IAudioClient_GetStreamLatency(stream->in.clientParent, &stream->in.deviceLatency))) + { + LogHostError(hr); + LogPaError(result = paInvalidDevice); + goto error; + } + //stream->in.latencySeconds = nano100ToSeconds(stream->in.deviceLatency); + + // Number of frames that are required at each period + stream->in.framesPerHostCallback = maxBufferSize; + + // Calculate frames per single buffer, if buffers > 1 then always framesPerBuffer + stream->in.framesPerBuffer = + (stream->in.userBufferAndHostMatch ? stream->in.framesPerHostCallback : framesPerBuffer); + + // Calculate buffer latency + bufferLatency = (PaTime)maxBufferSize / stream->in.wavex.Format.nSamplesPerSec; + + // Append buffer latency to interface latency in shared mode (see GetStreamLatency notes) + stream->in.latencySeconds = bufferLatency; + + PRINT(("WASAPI::OpenStream(input): framesPerUser[ %d ] framesPerHost[ %d ] latency[ %.02fms ] exclusive[ %s ] wow64_fix[ %s ] mode[ %s ]\n", (UINT32)framesPerBuffer, (UINT32)stream->in.framesPerHostCallback, (float)(stream->in.latencySeconds*1000.0f), (stream->in.shareMode == AUDCLNT_SHAREMODE_EXCLUSIVE ? "YES" : "NO"), (stream->in.params.wow64_workaround ? "YES" : "NO"), (stream->in.streamFlags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK ? "EVENT" : "POLL"))); + + return paNoError; + +error: + + return result; +} + +// ------------------------------------------------------------------------------------------ +static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, + PaStream** s, + const PaStreamParameters *inputParameters, + const PaStreamParameters *outputParameters, + double sampleRate, + unsigned long framesPerBuffer, + PaStreamFlags streamFlags, + PaStreamCallback *streamCallback, + void *userData ) +{ + PaError result = paNoError; + HRESULT hr; + PaWasapiHostApiRepresentation *paWasapi = (PaWasapiHostApiRepresentation*)hostApi; + PaWasapiStream *stream = NULL; + int inputChannelCount, outputChannelCount; + PaSampleFormat inputSampleFormat, outputSampleFormat; + PaSampleFormat hostInputSampleFormat, hostOutputSampleFormat; + PaWasapiStreamInfo *inputStreamInfo = NULL, *outputStreamInfo = NULL; + PaWasapiDeviceInfo *info = NULL; + ULONG framesPerHostCallback; + PaUtilHostBufferSizeMode bufferMode; + const BOOL fullDuplex = ((inputParameters != NULL) && (outputParameters != NULL)); + BOOL useInputBufferProcessor = (inputParameters != NULL), useOutputBufferProcessor = (outputParameters != NULL); + + // validate PaStreamParameters + if ((result = IsStreamParamsValid(hostApi, inputParameters, outputParameters, sampleRate)) != paNoError) + return LogPaError(result); + + // Validate platform specific flags + if ((streamFlags & paPlatformSpecificFlags) != 0) + { + LogPaError(result = paInvalidFlag); /* unexpected platform specific flag */ + goto error; + } + + // Allocate memory for PaWasapiStream + if ((stream = (PaWasapiStream *)PaUtil_AllocateMemory(sizeof(PaWasapiStream))) == NULL) + { + LogPaError(result = paInsufficientMemory); + goto error; + } + + // Default thread priority is Audio: for exclusive mode we will use Pro Audio. + stream->nThreadPriority = eThreadPriorityAudio; + + // Set default number of frames: paFramesPerBufferUnspecified + if (framesPerBuffer == paFramesPerBufferUnspecified) + { + UINT32 framesPerBufferIn = 0, framesPerBufferOut = 0; + if (inputParameters != NULL) + { + info = &paWasapi->devInfo[inputParameters->device]; + framesPerBufferIn = MakeFramesFromHns(info->DefaultDevicePeriod, (UINT32)sampleRate); + } + if (outputParameters != NULL) + { + info = &paWasapi->devInfo[outputParameters->device]; + framesPerBufferOut = MakeFramesFromHns(info->DefaultDevicePeriod, (UINT32)sampleRate); + } + // choosing maximum default size + framesPerBuffer = max(framesPerBufferIn, framesPerBufferOut); + } + if (framesPerBuffer == 0) + framesPerBuffer = ((UINT32)sampleRate / 100) * 2; + + // Try create device: Input + if (inputParameters != NULL) + { + inputChannelCount = inputParameters->channelCount; + inputSampleFormat = GetSampleFormatForIO(inputParameters->sampleFormat); + info = &paWasapi->devInfo[inputParameters->device]; + + // default Shared Mode + stream->in.shareMode = AUDCLNT_SHAREMODE_SHARED; + + // PaWasapiStreamInfo + if (inputParameters->hostApiSpecificStreamInfo != NULL) + { + memcpy(&stream->in.params.wasapi_params, inputParameters->hostApiSpecificStreamInfo, min(sizeof(stream->in.params.wasapi_params), ((PaWasapiStreamInfo *)inputParameters->hostApiSpecificStreamInfo)->size)); + stream->in.params.wasapi_params.size = sizeof(stream->in.params.wasapi_params); + + stream->in.params.stream_params.hostApiSpecificStreamInfo = &stream->in.params.wasapi_params; + inputStreamInfo = &stream->in.params.wasapi_params; + + stream->in.flags = inputStreamInfo->flags; + + // Exclusive Mode + if (inputStreamInfo->flags & paWinWasapiExclusive) + { + // Boost thread priority + stream->nThreadPriority = eThreadPriorityProAudio; + // Make Exclusive + stream->in.shareMode = AUDCLNT_SHAREMODE_EXCLUSIVE; + } + + // explicit thread priority level + if (inputStreamInfo->flags & paWinWasapiThreadPriority) + { + if ((inputStreamInfo->threadPriority > eThreadPriorityNone) && + (inputStreamInfo->threadPriority <= eThreadPriorityWindowManager)) + stream->nThreadPriority = inputStreamInfo->threadPriority; + } + + // redirect processing to custom user callback, ignore PA buffer processor + useInputBufferProcessor = !(inputStreamInfo->flags & paWinWasapiRedirectHostProcessor); + } + + // Choose processing mode + stream->in.streamFlags = (stream->in.shareMode == AUDCLNT_SHAREMODE_EXCLUSIVE ? AUDCLNT_STREAMFLAGS_EVENTCALLBACK : 0); + if (paWasapi->useWOW64Workaround) + stream->in.streamFlags = 0; // polling interface + else + if (streamCallback == NULL) + stream->in.streamFlags = 0; // polling interface + else + if ((inputStreamInfo != NULL) && (inputStreamInfo->flags & paWinWasapiPolling)) + stream->in.streamFlags = 0; // polling interface + else + if (fullDuplex) + stream->in.streamFlags = 0; // polling interface is implemented for full-duplex mode also + + // Use built-in PCM converter (channel count and sample rate) if requested + if ((GetWindowsVersion() >= WINDOWS_7_SERVER2008R2) && + (stream->in.shareMode == AUDCLNT_SHAREMODE_SHARED) && + ((inputStreamInfo != NULL) && (inputStreamInfo->flags & paWinWasapiAutoConvert))) + stream->in.streamFlags |= (AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM | AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY); + + // Fill parameters for Audio Client creation + stream->in.params.device_info = info; + stream->in.params.stream_params = (*inputParameters); + stream->in.params.frames_per_buffer = framesPerBuffer; + stream->in.params.sample_rate = sampleRate; + stream->in.params.blocking = (streamCallback == NULL); + stream->in.params.full_duplex = fullDuplex; + stream->in.params.wow64_workaround = paWasapi->useWOW64Workaround; + + // Create and activate audio client + if (FAILED(hr = ActivateAudioClientInput(stream))) + { + LogPaError(result = paInvalidDevice); + goto error; + } + + // Get closest format + hostInputSampleFormat = PaUtil_SelectClosestAvailableFormat(WaveToPaFormat(&stream->in.wavex), inputSampleFormat); + + // Set user-side custom host processor + if ((inputStreamInfo != NULL) && + (inputStreamInfo->flags & paWinWasapiRedirectHostProcessor)) + { + stream->hostProcessOverrideInput.processor = inputStreamInfo->hostProcessorInput; + stream->hostProcessOverrideInput.userData = userData; + } + + // Only get IAudioCaptureClient input once here instead of getting it at multiple places based on the use + if (FAILED(hr = IAudioClient_GetService(stream->in.clientParent, &pa_IID_IAudioCaptureClient, (void **)&stream->captureClientParent))) + { + LogHostError(hr); + LogPaError(result = paUnanticipatedHostError); + goto error; + } + + // Create ring buffer for blocking mode (It is needed because we fetch Input packets, not frames, + // and thus we have to save partial packet if such remains unread) + if (stream->in.params.blocking == TRUE) + { + UINT32 bufferFrames = ALIGN_NEXT_POW2((stream->in.framesPerHostCallback / WASAPI_PACKETS_PER_INPUT_BUFFER) * 2); + UINT32 frameSize = stream->in.wavex.Format.nBlockAlign; + + // buffer + if ((stream->in.tailBuffer = PaUtil_AllocateMemory(sizeof(PaUtilRingBuffer))) == NULL) + { + LogPaError(result = paInsufficientMemory); + goto error; + } + memset(stream->in.tailBuffer, 0, sizeof(PaUtilRingBuffer)); + + // buffer memory region + stream->in.tailBufferMemory = PaUtil_AllocateMemory(frameSize * bufferFrames); + if (stream->in.tailBufferMemory == NULL) + { + LogPaError(result = paInsufficientMemory); + goto error; + } + + // initialize + if (PaUtil_InitializeRingBuffer(stream->in.tailBuffer, frameSize, bufferFrames, stream->in.tailBufferMemory) != 0) + { + LogPaError(result = paInternalError); + goto error; + } + } + } + else + { + inputChannelCount = 0; + inputSampleFormat = hostInputSampleFormat = paInt16; /* Surpress 'uninitialised var' warnings. */ + } + + // Try create device: Output + if (outputParameters != NULL) + { + outputChannelCount = outputParameters->channelCount; + outputSampleFormat = GetSampleFormatForIO(outputParameters->sampleFormat); + info = &paWasapi->devInfo[outputParameters->device]; + + // default Shared Mode + stream->out.shareMode = AUDCLNT_SHAREMODE_SHARED; + + // set PaWasapiStreamInfo + if (outputParameters->hostApiSpecificStreamInfo != NULL) + { + memcpy(&stream->out.params.wasapi_params, outputParameters->hostApiSpecificStreamInfo, min(sizeof(stream->out.params.wasapi_params), ((PaWasapiStreamInfo *)outputParameters->hostApiSpecificStreamInfo)->size)); + stream->out.params.wasapi_params.size = sizeof(stream->out.params.wasapi_params); + + stream->out.params.stream_params.hostApiSpecificStreamInfo = &stream->out.params.wasapi_params; + outputStreamInfo = &stream->out.params.wasapi_params; + + stream->out.flags = outputStreamInfo->flags; + + // Exclusive Mode + if (outputStreamInfo->flags & paWinWasapiExclusive) + { + // Boost thread priority + stream->nThreadPriority = eThreadPriorityProAudio; + // Make Exclusive + stream->out.shareMode = AUDCLNT_SHAREMODE_EXCLUSIVE; + } + + // explicit thread priority level + if (outputStreamInfo->flags & paWinWasapiThreadPriority) + { + if ((outputStreamInfo->threadPriority > eThreadPriorityNone) && + (outputStreamInfo->threadPriority <= eThreadPriorityWindowManager)) + stream->nThreadPriority = outputStreamInfo->threadPriority; + } + + // redirect processing to custom user callback, ignore PA buffer processor + useOutputBufferProcessor = !(outputStreamInfo->flags & paWinWasapiRedirectHostProcessor); + } + + // Choose processing mode + stream->out.streamFlags = (stream->out.shareMode == AUDCLNT_SHAREMODE_EXCLUSIVE ? AUDCLNT_STREAMFLAGS_EVENTCALLBACK : 0); + if (paWasapi->useWOW64Workaround) + stream->out.streamFlags = 0; // polling interface + else + if (streamCallback == NULL) + stream->out.streamFlags = 0; // polling interface + else + if ((outputStreamInfo != NULL) && (outputStreamInfo->flags & paWinWasapiPolling)) + stream->out.streamFlags = 0; // polling interface + else + if (fullDuplex) + stream->out.streamFlags = 0; // polling interface is implemented for full-duplex mode also + + // Use built-in PCM converter (channel count and sample rate) if requested + if ((GetWindowsVersion() >= WINDOWS_7_SERVER2008R2) && + (stream->out.shareMode == AUDCLNT_SHAREMODE_SHARED) && + ((outputStreamInfo != NULL) && (outputStreamInfo->flags & paWinWasapiAutoConvert))) + stream->out.streamFlags |= (AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM | AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY); + + // Fill parameters for Audio Client creation + stream->out.params.device_info = info; + stream->out.params.stream_params = (*outputParameters); + stream->out.params.frames_per_buffer = framesPerBuffer; + stream->out.params.sample_rate = sampleRate; + stream->out.params.blocking = (streamCallback == NULL); + stream->out.params.full_duplex = fullDuplex; + stream->out.params.wow64_workaround = paWasapi->useWOW64Workaround; + + // Create and activate audio client + if (FAILED(hr = ActivateAudioClientOutput(stream))) + { + LogPaError(result = paInvalidDevice); + goto error; + } + + // Get closest format + hostOutputSampleFormat = PaUtil_SelectClosestAvailableFormat(WaveToPaFormat(&stream->out.wavex), outputSampleFormat); + + // Set user-side custom host processor + if ((outputStreamInfo != NULL) && + (outputStreamInfo->flags & paWinWasapiRedirectHostProcessor)) + { + stream->hostProcessOverrideOutput.processor = outputStreamInfo->hostProcessorOutput; + stream->hostProcessOverrideOutput.userData = userData; + } + + // Only get IAudioCaptureClient output once here instead of getting it at multiple places based on the use + if (FAILED(hr = IAudioClient_GetService(stream->out.clientParent, &pa_IID_IAudioRenderClient, (void **)&stream->renderClientParent))) + { + LogHostError(hr); + LogPaError(result = paUnanticipatedHostError); + goto error; + } + } + else + { + outputChannelCount = 0; + outputSampleFormat = hostOutputSampleFormat = paInt16; /* Surpress 'uninitialized var' warnings. */ + } + + // log full-duplex + if (fullDuplex) + PRINT(("WASAPI::OpenStream: full-duplex mode\n")); + + // paWinWasapiPolling must be on/or not on both streams + if ((inputParameters != NULL) && (outputParameters != NULL)) + { + if ((inputStreamInfo != NULL) && (outputStreamInfo != NULL)) + { + if (((inputStreamInfo->flags & paWinWasapiPolling) && + !(outputStreamInfo->flags & paWinWasapiPolling)) + || + (!(inputStreamInfo->flags & paWinWasapiPolling) && + (outputStreamInfo->flags & paWinWasapiPolling))) + { + LogPaError(result = paInvalidFlag); + goto error; + } + } + } + + // Initialize stream representation + if (streamCallback) + { + stream->bBlocking = FALSE; + PaUtil_InitializeStreamRepresentation(&stream->streamRepresentation, + &paWasapi->callbackStreamInterface, + streamCallback, userData); + } + else + { + stream->bBlocking = TRUE; + PaUtil_InitializeStreamRepresentation(&stream->streamRepresentation, + &paWasapi->blockingStreamInterface, + streamCallback, userData); + } + + // Initialize CPU measurer + PaUtil_InitializeCpuLoadMeasurer(&stream->cpuLoadMeasurer, sampleRate); + + if (outputParameters && inputParameters) + { + // serious problem #1 - No, Not a problem, especially concerning Exclusive mode. + // Input device in exclusive mode somehow is getting large buffer always, thus we + // adjust Output latency to reflect it, thus period will differ but playback will be + // normal. + /*if (stream->in.period != stream->out.period) + { + PRINT(("WASAPI: OpenStream: period discrepancy\n")); + LogPaError(result = paBadIODeviceCombination); + goto error; + }*/ + + // serious problem #2 - No, Not a problem, as framesPerHostCallback take into account + // sample size while it is not a problem for PA full-duplex, we must care of + // preriod only! + /*if (stream->out.framesPerHostCallback != stream->in.framesPerHostCallback) + { + PRINT(("WASAPI: OpenStream: framesPerHostCallback discrepancy\n")); + goto error; + }*/ + } + + // Calculate frames per host for processor + framesPerHostCallback = (outputParameters ? stream->out.framesPerBuffer : stream->in.framesPerBuffer); + + // Choose correct mode of buffer processing: + // Exclusive/Shared non paWinWasapiPolling mode: paUtilFixedHostBufferSize - always fixed + // Exclusive/Shared paWinWasapiPolling mode: paUtilBoundedHostBufferSize - may vary for Exclusive or Full-duplex + bufferMode = paUtilFixedHostBufferSize; + if (inputParameters) // !!! WASAPI IAudioCaptureClient::GetBuffer extracts not number of frames but 1 packet, thus we always must adapt + bufferMode = paUtilBoundedHostBufferSize; + else + if (outputParameters) + { + if ((stream->out.buffers == 1) && + (!stream->out.streamFlags || ((stream->out.streamFlags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK) == 0))) + bufferMode = paUtilBoundedHostBufferSize; + } + stream->bufferMode = bufferMode; + + // Initialize buffer processor + if (useInputBufferProcessor || useOutputBufferProcessor) + { + result = PaUtil_InitializeBufferProcessor( + &stream->bufferProcessor, + inputChannelCount, + inputSampleFormat, + hostInputSampleFormat, + outputChannelCount, + outputSampleFormat, + hostOutputSampleFormat, + sampleRate, + streamFlags, + framesPerBuffer, + framesPerHostCallback, + bufferMode, + streamCallback, + userData); + if (result != paNoError) + { + LogPaError(result); + goto error; + } + } + + // Set Input latency + stream->streamRepresentation.streamInfo.inputLatency = + (useInputBufferProcessor ? PaUtil_GetBufferProcessorInputLatencyFrames(&stream->bufferProcessor) / sampleRate : 0) + + (inputParameters != NULL ? stream->in.latencySeconds : 0); + + // Set Output latency + stream->streamRepresentation.streamInfo.outputLatency = + (useOutputBufferProcessor ? PaUtil_GetBufferProcessorOutputLatencyFrames(&stream->bufferProcessor) / sampleRate : 0) + + (outputParameters != NULL ? stream->out.latencySeconds : 0); + + // Set SR + stream->streamRepresentation.streamInfo.sampleRate = sampleRate; + + (*s) = (PaStream *)stream; + return result; + +error: + + if (stream != NULL) + CloseStream(stream); + + return result; +} + +// ------------------------------------------------------------------------------------------ +static PaError CloseStream( PaStream* s ) +{ + PaError result = paNoError; + PaWasapiStream *stream = (PaWasapiStream*)s; + + // abort active stream + if (IsStreamActive(s)) + { + result = AbortStream(s); + } + + SAFE_RELEASE(stream->captureClientParent); + SAFE_RELEASE(stream->renderClientParent); + SAFE_RELEASE(stream->out.clientParent); + SAFE_RELEASE(stream->in.clientParent); + SAFE_RELEASE(stream->inVol); + SAFE_RELEASE(stream->outVol); + + CloseHandle(stream->event[S_INPUT]); + CloseHandle(stream->event[S_OUTPUT]); + + _StreamCleanup(stream); + + PaWasapi_FreeMemory(stream->in.monoBuffer); + PaWasapi_FreeMemory(stream->out.monoBuffer); + + PaUtil_FreeMemory(stream->in.tailBuffer); + PaUtil_FreeMemory(stream->in.tailBufferMemory); + + PaUtil_FreeMemory(stream->out.tailBuffer); + PaUtil_FreeMemory(stream->out.tailBufferMemory); + + PaUtil_TerminateBufferProcessor(&stream->bufferProcessor); + PaUtil_TerminateStreamRepresentation(&stream->streamRepresentation); + PaUtil_FreeMemory(stream); + + return result; +} + +// ------------------------------------------------------------------------------------------ +HRESULT UnmarshalSubStreamComPointers(PaWasapiSubStream *substream) +{ +#ifndef PA_WINRT + HRESULT hResult = S_OK; + HRESULT hFirstBadResult = S_OK; + substream->clientProc = NULL; + + // IAudioClient + hResult = CoGetInterfaceAndReleaseStream(substream->clientStream, GetAudioClientIID(), (LPVOID*)&substream->clientProc); + substream->clientStream = NULL; + if (hResult != S_OK) + { + hFirstBadResult = (hFirstBadResult == S_OK) ? hResult : hFirstBadResult; + } + + return hFirstBadResult; + +#else + (void)substream; + return S_OK; +#endif +} + +// ------------------------------------------------------------------------------------------ +HRESULT UnmarshalStreamComPointers(PaWasapiStream *stream) +{ +#ifndef PA_WINRT + HRESULT hResult = S_OK; + HRESULT hFirstBadResult = S_OK; + stream->captureClient = NULL; + stream->renderClient = NULL; + stream->in.clientProc = NULL; + stream->out.clientProc = NULL; + + if (NULL != stream->in.clientParent) + { + // SubStream pointers + hResult = UnmarshalSubStreamComPointers(&stream->in); + if (hResult != S_OK) + { + hFirstBadResult = (hFirstBadResult == S_OK) ? hResult : hFirstBadResult; + } + + // IAudioCaptureClient + hResult = CoGetInterfaceAndReleaseStream(stream->captureClientStream, &pa_IID_IAudioCaptureClient, (LPVOID*)&stream->captureClient); + stream->captureClientStream = NULL; + if (hResult != S_OK) + { + hFirstBadResult = (hFirstBadResult == S_OK) ? hResult : hFirstBadResult; + } + } + + if (NULL != stream->out.clientParent) + { + // SubStream pointers + hResult = UnmarshalSubStreamComPointers(&stream->out); + if (hResult != S_OK) + { + hFirstBadResult = (hFirstBadResult == S_OK) ? hResult : hFirstBadResult; + } + + // IAudioRenderClient + hResult = CoGetInterfaceAndReleaseStream(stream->renderClientStream, &pa_IID_IAudioRenderClient, (LPVOID*)&stream->renderClient); + stream->renderClientStream = NULL; + if (hResult != S_OK) + { + hFirstBadResult = (hFirstBadResult == S_OK) ? hResult : hFirstBadResult; + } + } + + return hFirstBadResult; +#else + if (stream->in.clientParent != NULL) + { + stream->in.clientProc = stream->in.clientParent; + IAudioClient_AddRef(stream->in.clientParent); + } + + if (stream->out.clientParent != NULL) + { + stream->out.clientProc = stream->out.clientParent; + IAudioClient_AddRef(stream->out.clientParent); + } + + if (stream->renderClientParent != NULL) + { + stream->renderClient = stream->renderClientParent; + IAudioRenderClient_AddRef(stream->renderClientParent); + } + + if (stream->captureClientParent != NULL) + { + stream->captureClient = stream->captureClientParent; + IAudioCaptureClient_AddRef(stream->captureClientParent); + } + + return S_OK; +#endif +} + +// ----------------------------------------------------------------------------------------- +void ReleaseUnmarshaledSubComPointers(PaWasapiSubStream *substream) +{ + SAFE_RELEASE(substream->clientProc); +} + +// ----------------------------------------------------------------------------------------- +void ReleaseUnmarshaledComPointers(PaWasapiStream *stream) +{ + // Release AudioClient services first + SAFE_RELEASE(stream->captureClient); + SAFE_RELEASE(stream->renderClient); + + // Release AudioClients + ReleaseUnmarshaledSubComPointers(&stream->in); + ReleaseUnmarshaledSubComPointers(&stream->out); +} + +// ------------------------------------------------------------------------------------------ +HRESULT MarshalSubStreamComPointers(PaWasapiSubStream *substream) +{ +#ifndef PA_WINRT + HRESULT hResult; + substream->clientStream = NULL; + + // IAudioClient + hResult = CoMarshalInterThreadInterfaceInStream(GetAudioClientIID(), (LPUNKNOWN)substream->clientParent, &substream->clientStream); + if (hResult != S_OK) + goto marshal_sub_error; + + return hResult; + + // If marshaling error occurred, make sure to release everything. +marshal_sub_error: + + UnmarshalSubStreamComPointers(substream); + ReleaseUnmarshaledSubComPointers(substream); + return hResult; +#else + (void)substream; + return S_OK; +#endif +} + +// ------------------------------------------------------------------------------------------ +HRESULT MarshalStreamComPointers(PaWasapiStream *stream) +{ +#ifndef PA_WINRT + HRESULT hResult = S_OK; + stream->captureClientStream = NULL; + stream->in.clientStream = NULL; + stream->renderClientStream = NULL; + stream->out.clientStream = NULL; + + if (NULL != stream->in.clientParent) + { + // SubStream pointers + hResult = MarshalSubStreamComPointers(&stream->in); + if (hResult != S_OK) + goto marshal_error; + + // IAudioCaptureClient + hResult = CoMarshalInterThreadInterfaceInStream(&pa_IID_IAudioCaptureClient, (LPUNKNOWN)stream->captureClientParent, &stream->captureClientStream); + if (hResult != S_OK) + goto marshal_error; + } + + if (NULL != stream->out.clientParent) + { + // SubStream pointers + hResult = MarshalSubStreamComPointers(&stream->out); + if (hResult != S_OK) + goto marshal_error; + + // IAudioRenderClient + hResult = CoMarshalInterThreadInterfaceInStream(&pa_IID_IAudioRenderClient, (LPUNKNOWN)stream->renderClientParent, &stream->renderClientStream); + if (hResult != S_OK) + goto marshal_error; + } + + return hResult; + + // If marshaling error occurred, make sure to release everything. +marshal_error: + + UnmarshalStreamComPointers(stream); + ReleaseUnmarshaledComPointers(stream); + return hResult; +#else + (void)stream; + return S_OK; +#endif +} + +// ------------------------------------------------------------------------------------------ +static PaError StartStream( PaStream *s ) +{ + HRESULT hr; + PaWasapiStream *stream = (PaWasapiStream*)s; + PaError result = paNoError; + + // check if stream is active already + if (IsStreamActive(s)) + return paStreamIsNotStopped; + + PaUtil_ResetBufferProcessor(&stream->bufferProcessor); + + // Cleanup handles (may be necessary if stream was stopped by itself due to error) + _StreamCleanup(stream); + + // Create close event + if ((stream->hCloseRequest = CreateEvent(NULL, TRUE, FALSE, NULL)) == NULL) + { + result = paInsufficientMemory; + goto start_error; + } + + // Create thread + if (!stream->bBlocking) + { + // Create thread events + stream->hThreadStart = CreateEvent(NULL, TRUE, FALSE, NULL); + stream->hThreadExit = CreateEvent(NULL, TRUE, FALSE, NULL); + if ((stream->hThreadStart == NULL) || (stream->hThreadExit == NULL)) + { + result = paInsufficientMemory; + goto start_error; + } + + // Marshal WASAPI interface pointers for safe use in thread created below. + if ((hr = MarshalStreamComPointers(stream)) != S_OK) + { + PRINT(("Failed marshaling stream COM pointers.")); + result = paUnanticipatedHostError; + goto nonblocking_start_error; + } + + if ((stream->in.clientParent && (stream->in.streamFlags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK)) || + (stream->out.clientParent && (stream->out.streamFlags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK))) + { + if ((stream->hThread = CREATE_THREAD(ProcThreadEvent)) == NULL) + { + PRINT(("Failed creating thread: ProcThreadEvent.")); + result = paUnanticipatedHostError; + goto nonblocking_start_error; + } + } + else + { + if ((stream->hThread = CREATE_THREAD(ProcThreadPoll)) == NULL) + { + PRINT(("Failed creating thread: ProcThreadPoll.")); + result = paUnanticipatedHostError; + goto nonblocking_start_error; + } + } + + // Wait for thread to start + if (WaitForSingleObject(stream->hThreadStart, 60*1000) == WAIT_TIMEOUT) + { + PRINT(("Failed starting thread: timeout.")); + result = paUnanticipatedHostError; + goto nonblocking_start_error; + } + } + else + { + // Create blocking operation events (non-signaled event means - blocking operation is pending) + if (stream->out.clientParent != NULL) + { + if ((stream->hBlockingOpStreamWR = CreateEvent(NULL, TRUE, TRUE, NULL)) == NULL) + { + result = paInsufficientMemory; + goto start_error; + } + } + if (stream->in.clientParent != NULL) + { + if ((stream->hBlockingOpStreamRD = CreateEvent(NULL, TRUE, TRUE, NULL)) == NULL) + { + result = paInsufficientMemory; + goto start_error; + } + } + + // Initialize event & start INPUT stream + if (stream->in.clientParent != NULL) + { + if ((hr = IAudioClient_Start(stream->in.clientParent)) != S_OK) + { + LogHostError(hr); + result = paUnanticipatedHostError; + goto start_error; + } + } + + // Initialize event & start OUTPUT stream + if (stream->out.clientParent != NULL) + { + // Start + if ((hr = IAudioClient_Start(stream->out.clientParent)) != S_OK) + { + LogHostError(hr); + result = paUnanticipatedHostError; + goto start_error; + } + } + + // Set parent to working pointers to use shared functions. + stream->captureClient = stream->captureClientParent; + stream->renderClient = stream->renderClientParent; + stream->in.clientProc = stream->in.clientParent; + stream->out.clientProc = stream->out.clientParent; + + // Signal: stream running. + stream->running = TRUE; + } + + return result; + +nonblocking_start_error: + + // Set hThreadExit event to prevent blocking during cleanup + SetEvent(stream->hThreadExit); + UnmarshalStreamComPointers(stream); + ReleaseUnmarshaledComPointers(stream); + +start_error: + + StopStream(s); + return result; +} + +// ------------------------------------------------------------------------------------------ +void _StreamFinish(PaWasapiStream *stream) +{ + // Issue command to thread to stop processing and wait for thread exit + if (!stream->bBlocking) + { + SignalObjectAndWait(stream->hCloseRequest, stream->hThreadExit, INFINITE, FALSE); + } + else + // Blocking mode does not own thread + { + // Signal close event and wait for each of 2 blocking operations to complete + if (stream->out.clientParent) + SignalObjectAndWait(stream->hCloseRequest, stream->hBlockingOpStreamWR, INFINITE, TRUE); + if (stream->out.clientParent) + SignalObjectAndWait(stream->hCloseRequest, stream->hBlockingOpStreamRD, INFINITE, TRUE); + + // Process stop + _StreamOnStop(stream); + } + + // Cleanup handles + _StreamCleanup(stream); + + stream->running = FALSE; +} + +// ------------------------------------------------------------------------------------------ +void _StreamCleanup(PaWasapiStream *stream) +{ + // Close thread handles to allow restart + SAFE_CLOSE(stream->hThread); + SAFE_CLOSE(stream->hThreadStart); + SAFE_CLOSE(stream->hThreadExit); + SAFE_CLOSE(stream->hCloseRequest); + SAFE_CLOSE(stream->hBlockingOpStreamRD); + SAFE_CLOSE(stream->hBlockingOpStreamWR); +} + +// ------------------------------------------------------------------------------------------ +static PaError StopStream( PaStream *s ) +{ + // Finish stream + _StreamFinish((PaWasapiStream *)s); + return paNoError; +} + +// ------------------------------------------------------------------------------------------ +static PaError AbortStream( PaStream *s ) +{ + // Finish stream + _StreamFinish((PaWasapiStream *)s); + return paNoError; +} + +// ------------------------------------------------------------------------------------------ +static PaError IsStreamStopped( PaStream *s ) +{ + return !((PaWasapiStream *)s)->running; +} + +// ------------------------------------------------------------------------------------------ +static PaError IsStreamActive( PaStream *s ) +{ + return ((PaWasapiStream *)s)->running; +} + +// ------------------------------------------------------------------------------------------ +static PaTime GetStreamTime( PaStream *s ) +{ + PaWasapiStream *stream = (PaWasapiStream*)s; + + /* suppress unused variable warnings */ + (void) stream; + + return PaUtil_GetTime(); +} + +// ------------------------------------------------------------------------------------------ +static double GetStreamCpuLoad( PaStream* s ) +{ + return PaUtil_GetCpuLoad(&((PaWasapiStream *)s)->cpuLoadMeasurer); +} + +// ------------------------------------------------------------------------------------------ +static PaError ReadStream( PaStream* s, void *_buffer, unsigned long frames ) +{ + PaWasapiStream *stream = (PaWasapiStream*)s; + + HRESULT hr = S_OK; + BYTE *user_buffer = (BYTE *)_buffer; + BYTE *wasapi_buffer = NULL; + DWORD flags = 0; + UINT32 i, available, sleep = 0; + unsigned long processed; + ThreadIdleScheduler sched; + + // validate + if (!stream->running) + return paStreamIsStopped; + if (stream->captureClient == NULL) + return paBadStreamPtr; + + // Notify blocking op has begun + ResetEvent(stream->hBlockingOpStreamRD); + + // Use thread scheduling for 500 microseconds (emulated) when wait time for frames is less than + // 1 milliseconds, emulation helps to normalize CPU consumption and avoids too busy waiting + ThreadIdleScheduler_Setup(&sched, 1, 250/* microseconds */); + + // Make a local copy of the user buffer pointer(s), this is necessary + // because PaUtil_CopyOutput() advances these pointers every time it is called + if (!stream->bufferProcessor.userInputIsInterleaved) + { + user_buffer = (BYTE *)alloca(sizeof(BYTE *) * stream->bufferProcessor.inputChannelCount); + if (user_buffer == NULL) + return paInsufficientMemory; + + for (i = 0; i < stream->bufferProcessor.inputChannelCount; ++i) + ((BYTE **)user_buffer)[i] = ((BYTE **)_buffer)[i]; + } + + // Findout if there are tail frames, flush them all before reading hardware + if ((available = PaUtil_GetRingBufferReadAvailable(stream->in.tailBuffer)) != 0) + { + ring_buffer_size_t buf1_size = 0, buf2_size = 0, read, desired; + void *buf1 = NULL, *buf2 = NULL; + + // Limit desired to amount of requested frames + desired = available; + if ((UINT32)desired > frames) + desired = frames; + + // Get pointers to read regions + read = PaUtil_GetRingBufferReadRegions(stream->in.tailBuffer, desired, &buf1, &buf1_size, &buf2, &buf2_size); + + if (buf1 != NULL) + { + // Register available frames to processor + PaUtil_SetInputFrameCount(&stream->bufferProcessor, buf1_size); + + // Register host buffer pointer to processor + PaUtil_SetInterleavedInputChannels(&stream->bufferProcessor, 0, buf1, stream->bufferProcessor.inputChannelCount); + + // Copy user data to host buffer (with conversion if applicable) + processed = PaUtil_CopyInput(&stream->bufferProcessor, (void **)&user_buffer, buf1_size); + frames -= processed; + } + + if (buf2 != NULL) + { + // Register available frames to processor + PaUtil_SetInputFrameCount(&stream->bufferProcessor, buf2_size); + + // Register host buffer pointer to processor + PaUtil_SetInterleavedInputChannels(&stream->bufferProcessor, 0, buf2, stream->bufferProcessor.inputChannelCount); + + // Copy user data to host buffer (with conversion if applicable) + processed = PaUtil_CopyInput(&stream->bufferProcessor, (void **)&user_buffer, buf2_size); + frames -= processed; + } + + // Advance + PaUtil_AdvanceRingBufferReadIndex(stream->in.tailBuffer, read); + } + + // Read hardware + while (frames != 0) + { + // Check if blocking call must be interrupted + if (WaitForSingleObject(stream->hCloseRequest, sleep) != WAIT_TIMEOUT) + break; + + // Get available frames (must be finding out available frames before call to IAudioCaptureClient_GetBuffer + // othervise audio glitches will occur inExclusive mode as it seems that WASAPI has some scheduling/ + // processing problems when such busy polling with IAudioCaptureClient_GetBuffer occurs) + if ((hr = _PollGetInputFramesAvailable(stream, &available)) != S_OK) + { + LogHostError(hr); + return paUnanticipatedHostError; + } + + // Wait for more frames to become available + if (available == 0) + { + // Exclusive mode may require latency of 1 millisecond, thus we shall sleep + // around 500 microseconds (emulated) to collect packets in time + if (stream->in.shareMode != AUDCLNT_SHAREMODE_EXCLUSIVE) + { + UINT32 sleep_frames = (frames < stream->in.framesPerHostCallback ? frames : stream->in.framesPerHostCallback); + + sleep = GetFramesSleepTime(sleep_frames, stream->in.wavex.Format.nSamplesPerSec); + sleep /= 4; // wait only for 1/4 of the buffer + + // WASAPI input provides packets, thus expiring packet will result in bad audio + // limit waiting time to 2 seconds (will always work for smallest buffer in Shared) + if (sleep > 2) + sleep = 2; + + // Avoid busy waiting, schedule next 1 millesecond wait + if (sleep == 0) + sleep = ThreadIdleScheduler_NextSleep(&sched); + } + else + { + if ((sleep = ThreadIdleScheduler_NextSleep(&sched)) != 0) + { + Sleep(sleep); + sleep = 0; + } + } + + continue; + } + + // Get the available data in the shared buffer. + if ((hr = IAudioCaptureClient_GetBuffer(stream->captureClient, &wasapi_buffer, &available, &flags, NULL, NULL)) != S_OK) + { + // Buffer size is too small, waiting + if (hr != AUDCLNT_S_BUFFER_EMPTY) + { + LogHostError(hr); + goto end; + } + + continue; + } + + // Register available frames to processor + PaUtil_SetInputFrameCount(&stream->bufferProcessor, available); + + // Register host buffer pointer to processor + PaUtil_SetInterleavedInputChannels(&stream->bufferProcessor, 0, wasapi_buffer, stream->bufferProcessor.inputChannelCount); + + // Copy user data to host buffer (with conversion if applicable) + processed = PaUtil_CopyInput(&stream->bufferProcessor, (void **)&user_buffer, frames); + frames -= processed; + + // Save tail into buffer + if ((frames == 0) && (available > processed)) + { + UINT32 bytes_processed = processed * stream->in.wavex.Format.nBlockAlign; + UINT32 frames_to_save = available - processed; + + PaUtil_WriteRingBuffer(stream->in.tailBuffer, wasapi_buffer + bytes_processed, frames_to_save); + } + + // Release host buffer + if ((hr = IAudioCaptureClient_ReleaseBuffer(stream->captureClient, available)) != S_OK) + { + LogHostError(hr); + goto end; + } + } + +end: + + // Notify blocking op has ended + SetEvent(stream->hBlockingOpStreamRD); + + return (hr != S_OK ? paUnanticipatedHostError : paNoError); +} + +// ------------------------------------------------------------------------------------------ +static PaError WriteStream( PaStream* s, const void *_buffer, unsigned long frames ) +{ + PaWasapiStream *stream = (PaWasapiStream*)s; + + //UINT32 frames; + const BYTE *user_buffer = (const BYTE *)_buffer; + BYTE *wasapi_buffer; + HRESULT hr = S_OK; + UINT32 i, available, sleep = 0; + unsigned long processed; + ThreadIdleScheduler sched; + + // validate + if (!stream->running) + return paStreamIsStopped; + if (stream->renderClient == NULL) + return paBadStreamPtr; + + // Notify blocking op has begun + ResetEvent(stream->hBlockingOpStreamWR); + + // Use thread scheduling for 500 microseconds (emulated) when wait time for frames is less than + // 1 milliseconds, emulation helps to normalize CPU consumption and avoids too busy waiting + ThreadIdleScheduler_Setup(&sched, 1, 500/* microseconds */); + + // Make a local copy of the user buffer pointer(s), this is necessary + // because PaUtil_CopyOutput() advances these pointers every time it is called + if (!stream->bufferProcessor.userOutputIsInterleaved) + { + user_buffer = (const BYTE *)alloca(sizeof(const BYTE *) * stream->bufferProcessor.outputChannelCount); + if (user_buffer == NULL) + return paInsufficientMemory; + + for (i = 0; i < stream->bufferProcessor.outputChannelCount; ++i) + ((const BYTE **)user_buffer)[i] = ((const BYTE **)_buffer)[i]; + } + + // Blocking (potentially, untill 'frames' are consumed) loop + while (frames != 0) + { + // Check if blocking call must be interrupted + if (WaitForSingleObject(stream->hCloseRequest, sleep) != WAIT_TIMEOUT) + break; + + // Get frames available + if ((hr = _PollGetOutputFramesAvailable(stream, &available)) != S_OK) + { + LogHostError(hr); + goto end; + } + + // Wait for more frames to become available + if (available == 0) + { + UINT32 sleep_frames = (frames < stream->out.framesPerHostCallback ? frames : stream->out.framesPerHostCallback); + + sleep = GetFramesSleepTime(sleep_frames, stream->out.wavex.Format.nSamplesPerSec); + sleep /= 2; // wait only for half of the buffer + + // Avoid busy waiting, schedule next 1 millesecond wait + if (sleep == 0) + sleep = ThreadIdleScheduler_NextSleep(&sched); + + continue; + } + + // Keep in 'frames' range + if (available > frames) + available = frames; + + // Get pointer to host buffer + if ((hr = IAudioRenderClient_GetBuffer(stream->renderClient, available, &wasapi_buffer)) != S_OK) + { + // Buffer size is too big, waiting + if (hr == AUDCLNT_E_BUFFER_TOO_LARGE) + continue; + + LogHostError(hr); + goto end; + } + + // Keep waiting again (on Vista it was noticed that WASAPI could SOMETIMES return NULL pointer + // to buffer without returning AUDCLNT_E_BUFFER_TOO_LARGE instead) + if (wasapi_buffer == NULL) + continue; + + // Register available frames to processor + PaUtil_SetOutputFrameCount(&stream->bufferProcessor, available); + + // Register host buffer pointer to processor + PaUtil_SetInterleavedOutputChannels(&stream->bufferProcessor, 0, wasapi_buffer, stream->bufferProcessor.outputChannelCount); + + // Copy user data to host buffer (with conversion if applicable), this call will advance + // pointer 'user_buffer' to consumed portion of data + processed = PaUtil_CopyOutput(&stream->bufferProcessor, (const void **)&user_buffer, frames); + frames -= processed; + + // Release host buffer + if ((hr = IAudioRenderClient_ReleaseBuffer(stream->renderClient, available, 0)) != S_OK) + { + LogHostError(hr); + goto end; + } + } + +end: + + // Notify blocking op has ended + SetEvent(stream->hBlockingOpStreamWR); + + return (hr != S_OK ? paUnanticipatedHostError : paNoError); +} + +unsigned long PaUtil_GetOutputFrameCount( PaUtilBufferProcessor* bp ) +{ + return bp->hostOutputFrameCount[0]; +} + +// ------------------------------------------------------------------------------------------ +static signed long GetStreamReadAvailable( PaStream* s ) +{ + PaWasapiStream *stream = (PaWasapiStream*)s; + + HRESULT hr; + UINT32 available = 0; + + // validate + if (!stream->running) + return paStreamIsStopped; + if (stream->captureClient == NULL) + return paBadStreamPtr; + + // available in hardware buffer + if ((hr = _PollGetInputFramesAvailable(stream, &available)) != S_OK) + { + LogHostError(hr); + return paUnanticipatedHostError; + } + + // available in software tail buffer + available += PaUtil_GetRingBufferReadAvailable(stream->in.tailBuffer); + + return available; +} + +// ------------------------------------------------------------------------------------------ +static signed long GetStreamWriteAvailable( PaStream* s ) +{ + PaWasapiStream *stream = (PaWasapiStream*)s; + HRESULT hr; + UINT32 available = 0; + + // validate + if (!stream->running) + return paStreamIsStopped; + if (stream->renderClient == NULL) + return paBadStreamPtr; + + if ((hr = _PollGetOutputFramesAvailable(stream, &available)) != S_OK) + { + LogHostError(hr); + return paUnanticipatedHostError; + } + + return (signed long)available; +} + + +// ------------------------------------------------------------------------------------------ +static void WaspiHostProcessingLoop( void *inputBuffer, long inputFrames, + void *outputBuffer, long outputFrames, + void *userData ) +{ + PaWasapiStream *stream = (PaWasapiStream*)userData; + PaStreamCallbackTimeInfo timeInfo = {0,0,0}; + PaStreamCallbackFlags flags = 0; + int callbackResult; + unsigned long framesProcessed; + HRESULT hr; + UINT32 pending; + + PaUtil_BeginCpuLoadMeasurement( &stream->cpuLoadMeasurer ); + + /* + Pa_GetStreamTime: + - generate timing information + - handle buffer slips + */ + timeInfo.currentTime = PaUtil_GetTime(); + // Query input latency + if (stream->in.clientProc != NULL) + { + PaTime pending_time; + if ((hr = IAudioClient_GetCurrentPadding(stream->in.clientProc, &pending)) == S_OK) + pending_time = (PaTime)pending / (PaTime)stream->in.wavex.Format.nSamplesPerSec; + else + pending_time = (PaTime)stream->in.latencySeconds; + + timeInfo.inputBufferAdcTime = timeInfo.currentTime + pending_time; + } + // Query output current latency + if (stream->out.clientProc != NULL) + { + PaTime pending_time; + if ((hr = IAudioClient_GetCurrentPadding(stream->out.clientProc, &pending)) == S_OK) + pending_time = (PaTime)pending / (PaTime)stream->out.wavex.Format.nSamplesPerSec; + else + pending_time = (PaTime)stream->out.latencySeconds; + + timeInfo.outputBufferDacTime = timeInfo.currentTime + pending_time; + } + + /* + If you need to byte swap or shift inputBuffer to convert it into a + portaudio format, do it here. + */ + + PaUtil_BeginBufferProcessing( &stream->bufferProcessor, &timeInfo, flags ); + + /* + depending on whether the host buffers are interleaved, non-interleaved + or a mixture, you will want to call PaUtil_SetInterleaved*Channels(), + PaUtil_SetNonInterleaved*Channel() or PaUtil_Set*Channel() here. + */ + + if (stream->bufferProcessor.inputChannelCount > 0) + { + PaUtil_SetInputFrameCount( &stream->bufferProcessor, inputFrames ); + PaUtil_SetInterleavedInputChannels( &stream->bufferProcessor, + 0, /* first channel of inputBuffer is channel 0 */ + inputBuffer, + 0 ); /* 0 - use inputChannelCount passed to init buffer processor */ + } + + if (stream->bufferProcessor.outputChannelCount > 0) + { + PaUtil_SetOutputFrameCount( &stream->bufferProcessor, outputFrames); + PaUtil_SetInterleavedOutputChannels( &stream->bufferProcessor, + 0, /* first channel of outputBuffer is channel 0 */ + outputBuffer, + 0 ); /* 0 - use outputChannelCount passed to init buffer processor */ + } + + /* you must pass a valid value of callback result to PaUtil_EndBufferProcessing() + in general you would pass paContinue for normal operation, and + paComplete to drain the buffer processor's internal output buffer. + You can check whether the buffer processor's output buffer is empty + using PaUtil_IsBufferProcessorOuputEmpty( bufferProcessor ) + */ + callbackResult = paContinue; + framesProcessed = PaUtil_EndBufferProcessing( &stream->bufferProcessor, &callbackResult ); + + /* + If you need to byte swap or shift outputBuffer to convert it to + host format, do it here. + */ + + PaUtil_EndCpuLoadMeasurement( &stream->cpuLoadMeasurer, framesProcessed ); + + if (callbackResult == paContinue) + { + /* nothing special to do */ + } + else + if (callbackResult == paAbort) + { + // stop stream + SetEvent(stream->hCloseRequest); + } + else + { + // stop stream + SetEvent(stream->hCloseRequest); + } +} + +// ------------------------------------------------------------------------------------------ +#ifndef PA_WINRT +static PaError MMCSS_activate(PaWasapiThreadPriority nPriorityClass, HANDLE *ret) +{ + static const char *mmcs_name[] = + { + NULL, + "Audio", + "Capture", + "Distribution", + "Games", + "Playback", + "Pro Audio", + "Window Manager" + }; + + DWORD task_idx = 0; + HANDLE hTask; + + if ((UINT32)nPriorityClass >= STATIC_ARRAY_SIZE(mmcs_name)) + return paUnanticipatedHostError; + + if ((hTask = pAvSetMmThreadCharacteristics(mmcs_name[nPriorityClass], &task_idx)) == NULL) + { + PRINT(("WASAPI: AvSetMmThreadCharacteristics failed: error[%d]\n", GetLastError())); + return paUnanticipatedHostError; + } + + /*BOOL priority_ok = pAvSetMmThreadPriority(hTask, AVRT_PRIORITY_NORMAL); + if (priority_ok == FALSE) + { + PRINT(("WASAPI: AvSetMmThreadPriority failed!\n")); + }*/ + + // debug + { + int cur_priority = GetThreadPriority(GetCurrentThread()); + DWORD cur_priority_class = GetPriorityClass(GetCurrentProcess()); + PRINT(("WASAPI: thread[ priority-0x%X class-0x%X ]\n", cur_priority, cur_priority_class)); + } + + (*ret) = hTask; + return paNoError; +} +#endif + +// ------------------------------------------------------------------------------------------ +#ifndef PA_WINRT +static void MMCSS_deactivate(HANDLE hTask) +{ + if (pAvRevertMmThreadCharacteristics(hTask) == FALSE) + { + PRINT(("WASAPI: AvRevertMmThreadCharacteristics failed!\n")); + } +} +#endif + +// ------------------------------------------------------------------------------------------ +PaError PaWasapi_ThreadPriorityBoost(void **pTask, PaWasapiThreadPriority priorityClass) +{ + HANDLE task; + PaError ret; + + if (pTask == NULL) + return paUnanticipatedHostError; + +#ifndef PA_WINRT + if ((ret = MMCSS_activate(priorityClass, &task)) != paNoError) + return ret; +#else + switch (priorityClass) + { + case eThreadPriorityAudio: + case eThreadPriorityProAudio: { + + // Save previous thread priority + intptr_t priority_prev = GetThreadPriority(GetCurrentThread()); + + // Try set new thread priority + if (SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST) == FALSE) + return paUnanticipatedHostError; + + // Memorize prev priority (pretend to be non NULL pointer by adding 0x80000000 mask) + task = (HANDLE)(priority_prev | 0x80000000); + + ret = paNoError; + + break; } + + default: + return paUnanticipatedHostError; + } +#endif + + (*pTask) = task; + return ret; +} + +// ------------------------------------------------------------------------------------------ +PaError PaWasapi_ThreadPriorityRevert(void *pTask) +{ + if (pTask == NULL) + return paUnanticipatedHostError; + +#ifndef PA_WINRT + MMCSS_deactivate((HANDLE)pTask); +#else + // Revert previous priority by removing 0x80000000 mask + if (SetThreadPriority(GetCurrentThread(), (int)((intptr_t)pTask & ~0x80000000)) == FALSE) + return paUnanticipatedHostError; +#endif + + return paNoError; +} + +// ------------------------------------------------------------------------------------------ +// Described at: +// http://msdn.microsoft.com/en-us/library/dd371387(v=VS.85).aspx + +PaError PaWasapi_GetJackCount(PaDeviceIndex device, int *pJackCount) +{ +#ifndef PA_WINRT + PaError ret; + HRESULT hr = S_OK; + PaDeviceIndex index; + IDeviceTopology *pDeviceTopology = NULL; + IConnector *pConnFrom = NULL; + IConnector *pConnTo = NULL; + IPart *pPart = NULL; + IKsJackDescription *pJackDesc = NULL; + UINT jackCount = 0; + + PaWasapiHostApiRepresentation *paWasapi = _GetHostApi(&ret); + if (paWasapi == NULL) + return paNotInitialized; + + if (pJackCount == NULL) + return paUnanticipatedHostError; + + // Get device index + ret = PaUtil_DeviceIndexToHostApiDeviceIndex(&index, device, &paWasapi->inheritedHostApiRep); + if (ret != paNoError) + return ret; + + // Validate index + if ((UINT32)index >= paWasapi->deviceCount) + return paInvalidDevice; + + // Get the endpoint device's IDeviceTopology interface + hr = IMMDevice_Activate(paWasapi->devInfo[index].device, &pa_IID_IDeviceTopology, + CLSCTX_INPROC_SERVER, NULL, (void**)&pDeviceTopology); + IF_FAILED_JUMP(hr, error); + + // The device topology for an endpoint device always contains just one connector (connector number 0) + hr = IDeviceTopology_GetConnector(pDeviceTopology, 0, &pConnFrom); + IF_FAILED_JUMP(hr, error); + + // Step across the connection to the jack on the adapter + hr = IConnector_GetConnectedTo(pConnFrom, &pConnTo); + if (HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == hr) + { + // The adapter device is not currently active + hr = E_NOINTERFACE; + } + IF_FAILED_JUMP(hr, error); + + // Get the connector's IPart interface + hr = IConnector_QueryInterface(pConnTo, &pa_IID_IPart, (void**)&pPart); + IF_FAILED_JUMP(hr, error); + + // Activate the connector's IKsJackDescription interface + hr = IPart_Activate(pPart, CLSCTX_INPROC_SERVER, &pa_IID_IKsJackDescription, (void**)&pJackDesc); + IF_FAILED_JUMP(hr, error); + + // Return jack count for this device + hr = IKsJackDescription_GetJackCount(pJackDesc, &jackCount); + IF_FAILED_JUMP(hr, error); + + // Set. + (*pJackCount) = jackCount; + + // Ok. + ret = paNoError; + +error: + + SAFE_RELEASE(pDeviceTopology); + SAFE_RELEASE(pConnFrom); + SAFE_RELEASE(pConnTo); + SAFE_RELEASE(pPart); + SAFE_RELEASE(pJackDesc); + + LogHostError(hr); + return paNoError; +#else + (void)device; + (void)pJackCount; + return paUnanticipatedHostError; +#endif +} + +// ------------------------------------------------------------------------------------------ +#ifndef PA_WINRT +static PaWasapiJackConnectionType _ConvertJackConnectionTypeWASAPIToPA(int connType) +{ + switch (connType) + { + case eConnTypeUnknown: return eJackConnTypeUnknown; +#ifdef _KS_ + case eConnType3Point5mm: return eJackConnType3Point5mm; +#else + case eConnTypeEighth: return eJackConnType3Point5mm; +#endif + case eConnTypeQuarter: return eJackConnTypeQuarter; + case eConnTypeAtapiInternal: return eJackConnTypeAtapiInternal; + case eConnTypeRCA: return eJackConnTypeRCA; + case eConnTypeOptical: return eJackConnTypeOptical; + case eConnTypeOtherDigital: return eJackConnTypeOtherDigital; + case eConnTypeOtherAnalog: return eJackConnTypeOtherAnalog; + case eConnTypeMultichannelAnalogDIN: return eJackConnTypeMultichannelAnalogDIN; + case eConnTypeXlrProfessional: return eJackConnTypeXlrProfessional; + case eConnTypeRJ11Modem: return eJackConnTypeRJ11Modem; + case eConnTypeCombination: return eJackConnTypeCombination; + } + return eJackConnTypeUnknown; +} +#endif + +// ------------------------------------------------------------------------------------------ +#ifndef PA_WINRT +static PaWasapiJackGeoLocation _ConvertJackGeoLocationWASAPIToPA(int geoLoc) +{ + switch (geoLoc) + { + case eGeoLocRear: return eJackGeoLocRear; + case eGeoLocFront: return eJackGeoLocFront; + case eGeoLocLeft: return eJackGeoLocLeft; + case eGeoLocRight: return eJackGeoLocRight; + case eGeoLocTop: return eJackGeoLocTop; + case eGeoLocBottom: return eJackGeoLocBottom; +#ifdef _KS_ + case eGeoLocRearPanel: return eJackGeoLocRearPanel; +#else + case eGeoLocRearOPanel: return eJackGeoLocRearPanel; +#endif + case eGeoLocRiser: return eJackGeoLocRiser; + case eGeoLocInsideMobileLid: return eJackGeoLocInsideMobileLid; + case eGeoLocDrivebay: return eJackGeoLocDrivebay; + case eGeoLocHDMI: return eJackGeoLocHDMI; + case eGeoLocOutsideMobileLid: return eJackGeoLocOutsideMobileLid; + case eGeoLocATAPI: return eJackGeoLocATAPI; + } + return eJackGeoLocUnk; +} +#endif + +// ------------------------------------------------------------------------------------------ +#ifndef PA_WINRT +static PaWasapiJackGenLocation _ConvertJackGenLocationWASAPIToPA(int genLoc) +{ + switch (genLoc) + { + case eGenLocPrimaryBox: return eJackGenLocPrimaryBox; + case eGenLocInternal: return eJackGenLocInternal; +#ifdef _KS_ + case eGenLocSeparate: return eJackGenLocSeparate; +#else + case eGenLocSeperate: return eJackGenLocSeparate; +#endif + case eGenLocOther: return eJackGenLocOther; + } + return eJackGenLocPrimaryBox; +} +#endif + +// ------------------------------------------------------------------------------------------ +#ifndef PA_WINRT +static PaWasapiJackPortConnection _ConvertJackPortConnectionWASAPIToPA(int portConn) +{ + switch (portConn) + { + case ePortConnJack: return eJackPortConnJack; + case ePortConnIntegratedDevice: return eJackPortConnIntegratedDevice; + case ePortConnBothIntegratedAndJack:return eJackPortConnBothIntegratedAndJack; + case ePortConnUnknown: return eJackPortConnUnknown; + } + return eJackPortConnJack; +} +#endif + +// ------------------------------------------------------------------------------------------ +// Described at: +// http://msdn.microsoft.com/en-us/library/dd371387(v=VS.85).aspx + +PaError PaWasapi_GetJackDescription(PaDeviceIndex device, int jackIndex, PaWasapiJackDescription *pJackDescription) +{ +#ifndef PA_WINRT + PaError ret; + HRESULT hr = S_OK; + PaDeviceIndex index; + IDeviceTopology *pDeviceTopology = NULL; + IConnector *pConnFrom = NULL; + IConnector *pConnTo = NULL; + IPart *pPart = NULL; + IKsJackDescription *pJackDesc = NULL; + KSJACK_DESCRIPTION jack = { 0 }; + + PaWasapiHostApiRepresentation *paWasapi = _GetHostApi(&ret); + if (paWasapi == NULL) + return paNotInitialized; + + // Get device index + ret = PaUtil_DeviceIndexToHostApiDeviceIndex(&index, device, &paWasapi->inheritedHostApiRep); + if (ret != paNoError) + return ret; + + // Validate index + if ((UINT32)index >= paWasapi->deviceCount) + return paInvalidDevice; + + // Get the endpoint device's IDeviceTopology interface + hr = IMMDevice_Activate(paWasapi->devInfo[index].device, &pa_IID_IDeviceTopology, + CLSCTX_INPROC_SERVER, NULL, (void**)&pDeviceTopology); + IF_FAILED_JUMP(hr, error); + + // The device topology for an endpoint device always contains just one connector (connector number 0) + hr = IDeviceTopology_GetConnector(pDeviceTopology, 0, &pConnFrom); + IF_FAILED_JUMP(hr, error); + + // Step across the connection to the jack on the adapter + hr = IConnector_GetConnectedTo(pConnFrom, &pConnTo); + if (HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == hr) + { + // The adapter device is not currently active + hr = E_NOINTERFACE; + } + IF_FAILED_JUMP(hr, error); + + // Get the connector's IPart interface + hr = IConnector_QueryInterface(pConnTo, &pa_IID_IPart, (void**)&pPart); + IF_FAILED_JUMP(hr, error); + + // Activate the connector's IKsJackDescription interface + hr = IPart_Activate(pPart, CLSCTX_INPROC_SERVER, &pa_IID_IKsJackDescription, (void**)&pJackDesc); + IF_FAILED_JUMP(hr, error); + + // Test to return jack description struct for index 0 + hr = IKsJackDescription_GetJackDescription(pJackDesc, jackIndex, &jack); + IF_FAILED_JUMP(hr, error); + + // Convert WASAPI values to PA format + pJackDescription->channelMapping = jack.ChannelMapping; + pJackDescription->color = jack.Color; + pJackDescription->connectionType = _ConvertJackConnectionTypeWASAPIToPA(jack.ConnectionType); + pJackDescription->genLocation = _ConvertJackGenLocationWASAPIToPA(jack.GenLocation); + pJackDescription->geoLocation = _ConvertJackGeoLocationWASAPIToPA(jack.GeoLocation); + pJackDescription->isConnected = jack.IsConnected; + pJackDescription->portConnection = _ConvertJackPortConnectionWASAPIToPA(jack.PortConnection); + + // Ok + ret = paNoError; + +error: + + SAFE_RELEASE(pDeviceTopology); + SAFE_RELEASE(pConnFrom); + SAFE_RELEASE(pConnTo); + SAFE_RELEASE(pPart); + SAFE_RELEASE(pJackDesc); + + LogHostError(hr); + return ret; + +#else + (void)device; + (void)jackIndex; + (void)pJackDescription; + return paUnanticipatedHostError; +#endif +} + +// ------------------------------------------------------------------------------------------ +PaError PaWasapi_GetAudioClient(PaStream *pStream, void **pAudioClient, int bOutput) +{ + PaWasapiStream *stream = (PaWasapiStream *)pStream; + if (stream == NULL) + return paBadStreamPtr; + + if (pAudioClient == NULL) + return paUnanticipatedHostError; + + (*pAudioClient) = (bOutput == TRUE ? stream->out.clientParent : stream->in.clientParent); + + return paNoError; +} + +// ------------------------------------------------------------------------------------------ +PaError PaWasapi_SetDefaultInterfaceId( unsigned short *pId, int bOutput ) +{ +#ifdef PA_WINRT + int i; + + // Validate Id length + if (pId != NULL) + { + for (i = 0; pId[i] != 0; ++i) + { + if (i >= PA_WASAPI_DEVICE_ID_LEN) + return paBufferTooBig; + } + } + + // Set Id (or reset to all 0 if NULL is provided) + if (bOutput) + { + memset(g_DefaultRenderId, 0, sizeof(g_DefaultRenderId)); + if (pId != NULL) + { + for (i = 0; (pId[i] != 0) && (i < STATIC_ARRAY_SIZE(g_DefaultRenderId)); ++i) + g_DefaultRenderId[i] = pId[i]; + } + } + else + { + memset(g_DefaultCaptureId, 0, sizeof(g_DefaultCaptureId)); + if (pId != NULL) + { + for (i = 0; (pId[i] != 0) && (i < STATIC_ARRAY_SIZE(g_DefaultCaptureId)); ++i) + g_DefaultCaptureId[i] = pId[i]; + } + } + + return paNoError; + +#else + return paIncompatibleStreamHostApi; +#endif +} + +// ------------------------------------------------------------------------------------------ +PaError PaWasapi_SetStreamStateHandler( PaStream *pStream, PaWasapiStreamStateCallback fnStateHandler, void *pUserData ) +{ + PaWasapiStream *stream = (PaWasapiStream *)pStream; + if (stream == NULL) + return paBadStreamPtr; + + stream->fnStateHandler = fnStateHandler; + stream->pStateHandlerUserData = pUserData; + + return paNoError; +} + +// ------------------------------------------------------------------------------------------ +HRESULT _PollGetOutputFramesAvailable(PaWasapiStream *stream, UINT32 *available) +{ + HRESULT hr; + UINT32 frames = stream->out.framesPerHostCallback, + padding = 0; + + (*available) = 0; + + // get read position + if ((hr = IAudioClient_GetCurrentPadding(stream->out.clientProc, &padding)) != S_OK) + return LogHostError(hr); + + // get available + frames -= padding; + + // set + (*available) = frames; + return hr; +} + +// ------------------------------------------------------------------------------------------ +HRESULT _PollGetInputFramesAvailable(PaWasapiStream *stream, UINT32 *available) +{ + HRESULT hr; + + (*available) = 0; + + // GetCurrentPadding() has opposite meaning to Output stream + if ((hr = IAudioClient_GetCurrentPadding(stream->in.clientProc, available)) != S_OK) + return LogHostError(hr); + + return hr; +} + +// ------------------------------------------------------------------------------------------ +static HRESULT ProcessOutputBuffer(PaWasapiStream *stream, PaWasapiHostProcessor *processor, UINT32 frames) +{ + HRESULT hr; + BYTE *data = NULL; + + // Get buffer + if ((hr = IAudioRenderClient_GetBuffer(stream->renderClient, frames, &data)) != S_OK) + { + // Both modes, Shared and Exclusive, can fail with AUDCLNT_E_BUFFER_TOO_LARGE error + #if 0 + if (stream->out.shareMode == AUDCLNT_SHAREMODE_SHARED) + { + // Using GetCurrentPadding to overcome AUDCLNT_E_BUFFER_TOO_LARGE in + // shared mode results in no sound in Event-driven mode (MSDN does not + // document this, or is it WASAPI bug?), thus we better + // try to acquire buffer next time when GetBuffer allows to do so. + #if 0 + // Get Read position + UINT32 padding = 0; + hr = IAudioClient_GetCurrentPadding(stream->out.clientProc, &padding); + if (hr != S_OK) + return LogHostError(hr); + + // Get frames to write + frames -= padding; + if (frames == 0) + return S_OK; + + if ((hr = IAudioRenderClient_GetBuffer(stream->renderClient, frames, &data)) != S_OK) + return LogHostError(hr); + #else + if (hr == AUDCLNT_E_BUFFER_TOO_LARGE) + return S_OK; // be silent in shared mode, try again next time + #endif + } + else + return LogHostError(hr); + #else + if (hr == AUDCLNT_E_BUFFER_TOO_LARGE) + return S_OK; // try again next time + + return LogHostError(hr); + #endif + } + + // Process data + if (stream->out.monoMixer != NULL) + { + // expand buffer + UINT32 mono_frames_size = frames * (stream->out.wavex.Format.wBitsPerSample / 8); + if (mono_frames_size > stream->out.monoBufferSize) + { + stream->out.monoBuffer = PaWasapi_ReallocateMemory(stream->out.monoBuffer, (stream->out.monoBufferSize = mono_frames_size)); + if (stream->out.monoBuffer == NULL) + { + hr = E_OUTOFMEMORY; + LogHostError(hr); + return hr; + } + } + + // process + processor[S_OUTPUT].processor(NULL, 0, (BYTE *)stream->out.monoBuffer, frames, processor[S_OUTPUT].userData); + + // mix 1 to 2 channels + stream->out.monoMixer(data, stream->out.monoBuffer, frames); + } + else + { + processor[S_OUTPUT].processor(NULL, 0, data, frames, processor[S_OUTPUT].userData); + } + + // Release buffer + if ((hr = IAudioRenderClient_ReleaseBuffer(stream->renderClient, frames, 0)) != S_OK) + LogHostError(hr); + + return hr; +} + +// ------------------------------------------------------------------------------------------ +static HRESULT ProcessInputBuffer(PaWasapiStream *stream, PaWasapiHostProcessor *processor) +{ + HRESULT hr = S_OK; + UINT32 frames; + BYTE *data = NULL; + DWORD flags = 0; + + for (;;) + { + // Check if blocking call must be interrupted + if (WaitForSingleObject(stream->hCloseRequest, 0) != WAIT_TIMEOUT) + break; + + // Findout if any frames available + frames = 0; + if ((hr = _PollGetInputFramesAvailable(stream, &frames)) != S_OK) + return hr; + + // Empty/consumed buffer + if (frames == 0) + break; + + // Get the available data in the shared buffer. + if ((hr = IAudioCaptureClient_GetBuffer(stream->captureClient, &data, &frames, &flags, NULL, NULL)) != S_OK) + { + if (hr == AUDCLNT_S_BUFFER_EMPTY) + { + hr = S_OK; + break; // Empty/consumed buffer + } + + return LogHostError(hr); + break; + } + + // Detect silence + // if (flags & AUDCLNT_BUFFERFLAGS_SILENT) + // data = NULL; + + // Process data + if (stream->in.monoMixer != NULL) + { + // expand buffer + UINT32 mono_frames_size = frames * (stream->in.wavex.Format.wBitsPerSample / 8); + if (mono_frames_size > stream->in.monoBufferSize) + { + stream->in.monoBuffer = PaWasapi_ReallocateMemory(stream->in.monoBuffer, (stream->in.monoBufferSize = mono_frames_size)); + if (stream->in.monoBuffer == NULL) + { + hr = E_OUTOFMEMORY; + LogHostError(hr); + return hr; + } + } + + // mix 1 to 2 channels + stream->in.monoMixer(stream->in.monoBuffer, data, frames); + + // process + processor[S_INPUT].processor((BYTE *)stream->in.monoBuffer, frames, NULL, 0, processor[S_INPUT].userData); + } + else + { + processor[S_INPUT].processor(data, frames, NULL, 0, processor[S_INPUT].userData); + } + + // Release buffer + if ((hr = IAudioCaptureClient_ReleaseBuffer(stream->captureClient, frames)) != S_OK) + return LogHostError(hr); + + //break; + } + + return hr; +} + +// ------------------------------------------------------------------------------------------ +void _StreamOnStop(PaWasapiStream *stream) +{ + // Stop INPUT/OUTPUT clients + if (!stream->bBlocking) + { + if (stream->in.clientProc != NULL) + IAudioClient_Stop(stream->in.clientProc); + if (stream->out.clientProc != NULL) + IAudioClient_Stop(stream->out.clientProc); + } + else + { + if (stream->in.clientParent != NULL) + IAudioClient_Stop(stream->in.clientParent); + if (stream->out.clientParent != NULL) + IAudioClient_Stop(stream->out.clientParent); + } + + // Restore thread priority + if (stream->hAvTask != NULL) + { + PaWasapi_ThreadPriorityRevert(stream->hAvTask); + stream->hAvTask = NULL; + } + + // Notify + if (stream->streamRepresentation.streamFinishedCallback != NULL) + stream->streamRepresentation.streamFinishedCallback(stream->streamRepresentation.userData); +} + +// ------------------------------------------------------------------------------------------ +PA_THREAD_FUNC ProcThreadEvent(void *param) +{ + PaWasapiHostProcessor processor[S_COUNT]; + HRESULT hr; + DWORD dwResult; + PaWasapiStream *stream = (PaWasapiStream *)param; + PaWasapiHostProcessor defaultProcessor; + BOOL set_event[S_COUNT] = { FALSE, FALSE }; + BOOL bWaitAllEvents = FALSE; + BOOL bThreadComInitialized = FALSE; + + // Notify: state + NotifyStateChanged(stream, paWasapiStreamStateThreadPrepare, ERROR_SUCCESS); + + /* + If COM is already initialized CoInitialize will either return + FALSE, or RPC_E_CHANGED_MODE if it was initialized in a different + threading mode. In either case we shouldn't consider it an error + but we need to be careful to not call CoUninitialize() if + RPC_E_CHANGED_MODE was returned. + */ + hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); + if (FAILED(hr) && (hr != RPC_E_CHANGED_MODE)) + { + PRINT(("WASAPI: failed ProcThreadEvent CoInitialize")); + return (UINT32)paUnanticipatedHostError; + } + if (hr != RPC_E_CHANGED_MODE) + bThreadComInitialized = TRUE; + + // Unmarshal stream pointers for safe COM operation + hr = UnmarshalStreamComPointers(stream); + if (hr != S_OK) { + PRINT(("Error unmarshaling stream COM pointers. HRESULT: %i\n", hr)); + goto thread_end; + } + + // Waiting on all events in case of Full-Duplex/Exclusive mode. + if ((stream->in.clientProc != NULL) && (stream->out.clientProc != NULL)) + { + bWaitAllEvents = (stream->in.shareMode == AUDCLNT_SHAREMODE_EXCLUSIVE) && + (stream->out.shareMode == AUDCLNT_SHAREMODE_EXCLUSIVE); + } + + // Setup data processors + defaultProcessor.processor = WaspiHostProcessingLoop; + defaultProcessor.userData = stream; + processor[S_INPUT] = (stream->hostProcessOverrideInput.processor != NULL ? stream->hostProcessOverrideInput : defaultProcessor); + processor[S_OUTPUT] = (stream->hostProcessOverrideOutput.processor != NULL ? stream->hostProcessOverrideOutput : defaultProcessor); + + // Boost thread priority + PaWasapi_ThreadPriorityBoost((void **)&stream->hAvTask, stream->nThreadPriority); + + // Create events + if (stream->event[S_OUTPUT] == NULL) + { + stream->event[S_OUTPUT] = CreateEvent(NULL, FALSE, FALSE, NULL); + set_event[S_OUTPUT] = TRUE; + } + if (stream->event[S_INPUT] == NULL) + { + stream->event[S_INPUT] = CreateEvent(NULL, FALSE, FALSE, NULL); + set_event[S_INPUT] = TRUE; + } + if ((stream->event[S_OUTPUT] == NULL) || (stream->event[S_INPUT] == NULL)) + { + PRINT(("WASAPI Thread: failed creating Input/Output event handle\n")); + goto thread_error; + } + + // Initialize event & start INPUT stream + if (stream->in.clientProc) + { + // Create & set handle + if (set_event[S_INPUT]) + { + if ((hr = IAudioClient_SetEventHandle(stream->in.clientProc, stream->event[S_INPUT])) != S_OK) + { + LogHostError(hr); + goto thread_error; + } + } + + // Start + if ((hr = IAudioClient_Start(stream->in.clientProc)) != S_OK) + { + LogHostError(hr); + goto thread_error; + } + } + + // Initialize event & start OUTPUT stream + if (stream->out.clientProc) + { + // Create & set handle + if (set_event[S_OUTPUT]) + { + if ((hr = IAudioClient_SetEventHandle(stream->out.clientProc, stream->event[S_OUTPUT])) != S_OK) + { + LogHostError(hr); + goto thread_error; + } + } + + // Preload buffer before start + if ((hr = ProcessOutputBuffer(stream, processor, stream->out.framesPerBuffer)) != S_OK) + { + LogHostError(hr); + goto thread_error; + } + + // Start + if ((hr = IAudioClient_Start(stream->out.clientProc)) != S_OK) + { + LogHostError(hr); + goto thread_error; + } + + } + + // Signal: stream running + stream->running = TRUE; + + // Notify: thread started + SetEvent(stream->hThreadStart); + + // Notify: state + NotifyStateChanged(stream, paWasapiStreamStateThreadStart, ERROR_SUCCESS); + + // Processing Loop + for (;;) + { + // 10 sec timeout (on timeout stream will auto-stop when processed by WAIT_TIMEOUT case) + dwResult = WaitForMultipleObjects(S_COUNT, stream->event, bWaitAllEvents, 10*1000); + + // Check for close event (after wait for buffers to avoid any calls to user + // callback when hCloseRequest was set) + if (WaitForSingleObject(stream->hCloseRequest, 0) != WAIT_TIMEOUT) + break; + + // Process S_INPUT/S_OUTPUT + switch (dwResult) + { + case WAIT_TIMEOUT: { + PRINT(("WASAPI Thread: WAIT_TIMEOUT - probably bad audio driver or Vista x64 bug: use paWinWasapiPolling instead\n")); + goto thread_end; + break; } + + // Input stream + case WAIT_OBJECT_0 + S_INPUT: { + + if (stream->captureClient == NULL) + break; + + if ((hr = ProcessInputBuffer(stream, processor)) != S_OK) + { + LogHostError(hr); + goto thread_error; + } + + break; } + + // Output stream + case WAIT_OBJECT_0 + S_OUTPUT: { + + if (stream->renderClient == NULL) + break; + + if ((hr = ProcessOutputBuffer(stream, processor, stream->out.framesPerBuffer)) != S_OK) + { + LogHostError(hr); + goto thread_error; + } + + break; } + } + } + +thread_end: + + // Process stop + _StreamOnStop(stream); + + // Release unmarshaled COM pointers + ReleaseUnmarshaledComPointers(stream); + + // Cleanup COM for this thread + if (bThreadComInitialized == TRUE) + CoUninitialize(); + + // Notify: not running + stream->running = FALSE; + + // Notify: thread exited + SetEvent(stream->hThreadExit); + + // Notify: state + NotifyStateChanged(stream, paWasapiStreamStateThreadStop, hr); + + return 0; + +thread_error: + + // Prevent deadlocking in Pa_StreamStart + SetEvent(stream->hThreadStart); + + // Exit + goto thread_end; +} + +// ------------------------------------------------------------------------------------------ +PA_THREAD_FUNC ProcThreadPoll(void *param) +{ + PaWasapiHostProcessor processor[S_COUNT]; + HRESULT hr; + PaWasapiStream *stream = (PaWasapiStream *)param; + PaWasapiHostProcessor defaultProcessor; + INT32 i; + ThreadIdleScheduler scheduler; + + // Calculate the actual duration of the allocated buffer. + DWORD sleep_ms = 0; + DWORD sleep_ms_in; + DWORD sleep_ms_out; + + BOOL bThreadComInitialized = FALSE; + + // Notify: state + NotifyStateChanged(stream, paWasapiStreamStateThreadPrepare, ERROR_SUCCESS); + + /* + If COM is already initialized CoInitialize will either return + FALSE, or RPC_E_CHANGED_MODE if it was initialized in a different + threading mode. In either case we shouldn't consider it an error + but we need to be careful to not call CoUninitialize() if + RPC_E_CHANGED_MODE was returned. + */ + hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); + if (FAILED(hr) && (hr != RPC_E_CHANGED_MODE)) + { + PRINT(("WASAPI: failed ProcThreadPoll CoInitialize")); + return (UINT32)paUnanticipatedHostError; + } + if (hr != RPC_E_CHANGED_MODE) + bThreadComInitialized = TRUE; + + // Unmarshal stream pointers for safe COM operation + hr = UnmarshalStreamComPointers(stream); + if (hr != S_OK) + { + PRINT(("Error unmarshaling stream COM pointers. HRESULT: %i\n", hr)); + return 0; + } + + // Calculate timeout for next polling attempt. + sleep_ms_in = GetFramesSleepTime(stream->in.framesPerHostCallback / WASAPI_PACKETS_PER_INPUT_BUFFER, stream->in.wavex.Format.nSamplesPerSec); + sleep_ms_out = GetFramesSleepTime(stream->out.framesPerBuffer, stream->out.wavex.Format.nSamplesPerSec); + + // WASAPI Input packets tend to expire very easily, let's limit sleep time to 2 milliseconds + // for all cases. Please propose better solution if any. + if (sleep_ms_in > 2) + sleep_ms_in = 2; + + // Adjust polling time for non-paUtilFixedHostBufferSize. Input stream is not adjustable as it is being + // polled according its packet length. + if (stream->bufferMode != paUtilFixedHostBufferSize) + { + //sleep_ms_in = GetFramesSleepTime((stream->bufferProcessor.framesPerUserBuffer ? stream->bufferProcessor.framesPerUserBuffer : stream->in.params.frames_per_buffer), stream->in.wavex.Format.nSamplesPerSec); + sleep_ms_out = GetFramesSleepTime((stream->bufferProcessor.framesPerUserBuffer ? stream->bufferProcessor.framesPerUserBuffer : stream->out.params.frames_per_buffer), stream->out.wavex.Format.nSamplesPerSec); + } + + // Choose smallest + if ((sleep_ms_in != 0) && (sleep_ms_out != 0)) + sleep_ms = min(sleep_ms_in, sleep_ms_out); + else + sleep_ms = (sleep_ms_in ? sleep_ms_in : sleep_ms_out); + + // Make sure not 0, othervise use ThreadIdleScheduler + if (sleep_ms == 0) + { + sleep_ms_in = GetFramesSleepTimeMicroseconds(stream->in.framesPerHostCallback / WASAPI_PACKETS_PER_INPUT_BUFFER, stream->in.wavex.Format.nSamplesPerSec); + sleep_ms_out = GetFramesSleepTimeMicroseconds((stream->bufferProcessor.framesPerUserBuffer ? stream->bufferProcessor.framesPerUserBuffer : stream->out.params.frames_per_buffer), stream->out.wavex.Format.nSamplesPerSec); + + // Choose smallest + if ((sleep_ms_in != 0) && (sleep_ms_out != 0)) + sleep_ms = min(sleep_ms_in, sleep_ms_out); + else + sleep_ms = (sleep_ms_in ? sleep_ms_in : sleep_ms_out); + + // Setup thread sleep scheduler + ThreadIdleScheduler_Setup(&scheduler, 1, sleep_ms/* microseconds here */); + sleep_ms = 0; + } + + // Setup data processors + defaultProcessor.processor = WaspiHostProcessingLoop; + defaultProcessor.userData = stream; + processor[S_INPUT] = (stream->hostProcessOverrideInput.processor != NULL ? stream->hostProcessOverrideInput : defaultProcessor); + processor[S_OUTPUT] = (stream->hostProcessOverrideOutput.processor != NULL ? stream->hostProcessOverrideOutput : defaultProcessor); + + // Boost thread priority + PaWasapi_ThreadPriorityBoost((void **)&stream->hAvTask, stream->nThreadPriority); + + // Initialize event & start INPUT stream + if (stream->in.clientProc) + { + if ((hr = IAudioClient_Start(stream->in.clientProc)) != S_OK) + { + LogHostError(hr); + goto thread_error; + } + } + + // Initialize event & start OUTPUT stream + if (stream->out.clientProc) + { + // Preload buffer (obligatory, othervise ->Start() will fail), avoid processing + // when in full-duplex mode as it requires input processing as well + if (!PA_WASAPI__IS_FULLDUPLEX(stream)) + { + UINT32 frames = 0; + if ((hr = _PollGetOutputFramesAvailable(stream, &frames)) == S_OK) + { + if (stream->bufferMode == paUtilFixedHostBufferSize) + { + if (frames >= stream->out.framesPerBuffer) + { + frames = stream->out.framesPerBuffer; + + if ((hr = ProcessOutputBuffer(stream, processor, frames)) != S_OK) + { + LogHostError(hr); // not fatal, just log + } + } + } + else + { + // Some devices may not start (will get stuck with 0 ready frames) if data not prefetched + if (frames == 0) + frames = stream->out.framesPerBuffer; + + // USB DACs report large buffer in Exclusive mode and if it is filled fully will stuck in + // non playing state, e.g. IAudioClient_GetCurrentPadding() will start reporting max buffer size + // constantly, thus preload data size equal to the user buffer to allow process going + if ((stream->out.shareMode == AUDCLNT_SHAREMODE_EXCLUSIVE) && (frames >= (stream->out.framesPerBuffer * 2))) + frames -= stream->out.framesPerBuffer; + + if ((hr = ProcessOutputBuffer(stream, processor, frames)) != S_OK) + { + LogHostError(hr); // not fatal, just log + } + } + } + else + { + LogHostError(hr); // not fatal, just log + } + } + + // Start + if ((hr = IAudioClient_Start(stream->out.clientProc)) != S_OK) + { + LogHostError(hr); + goto thread_error; + } + } + + // Signal: stream running + stream->running = TRUE; + + // Notify: thread started + SetEvent(stream->hThreadStart); + + // Notify: state + NotifyStateChanged(stream, paWasapiStreamStateThreadStart, ERROR_SUCCESS); + + if (!PA_WASAPI__IS_FULLDUPLEX(stream)) + { + UINT32 next_sleep = sleep_ms; + + // Processing Loop + while (WaitForSingleObject(stream->hCloseRequest, next_sleep) == WAIT_TIMEOUT) + { + // Get next sleep time + if (sleep_ms == 0) + next_sleep = ThreadIdleScheduler_NextSleep(&scheduler); + + for (i = 0; i < S_COUNT; ++i) + { + // Process S_INPUT/S_OUTPUT + switch (i) + { + // Input stream + case S_INPUT: { + + if (stream->captureClient == NULL) + break; + + if ((hr = ProcessInputBuffer(stream, processor)) != S_OK) + { + LogHostError(hr); + goto thread_error; + } + + break; } + + // Output stream + case S_OUTPUT: { + + UINT32 frames; + if (stream->renderClient == NULL) + break; + + // Get available frames + if ((hr = _PollGetOutputFramesAvailable(stream, &frames)) != S_OK) + { + LogHostError(hr); + goto thread_error; + } + + // Output data to the user callback + if (stream->bufferMode == paUtilFixedHostBufferSize) + { + while (frames >= stream->out.framesPerBuffer) + { + if ((hr = ProcessOutputBuffer(stream, processor, stream->out.framesPerBuffer)) != S_OK) + { + LogHostError(hr); + goto thread_error; + } + + frames -= stream->out.framesPerBuffer; + } + } + else + if (frames != 0) + { + if ((hr = ProcessOutputBuffer(stream, processor, frames)) != S_OK) + { + LogHostError(hr); + goto thread_error; + } + } + + break; } + } + } + } + } + else + { +#if 0 + // Processing Loop + while (WaitForSingleObject(stream->hCloseRequest, 1) == WAIT_TIMEOUT) + { + UINT32 i_frames = 0, i_processed = 0; + BYTE *i_data = NULL, *o_data = NULL, *o_data_host = NULL; + DWORD i_flags = 0; + UINT32 o_frames = 0; + + // get host input buffer + if ((hr = IAudioCaptureClient_GetBuffer(stream->captureClient, &i_data, &i_frames, &i_flags, NULL, NULL)) != S_OK) + { + if (hr == AUDCLNT_S_BUFFER_EMPTY) + continue; // no data in capture buffer + + LogHostError(hr); + break; + } + + // get available frames + if ((hr = _PollGetOutputFramesAvailable(stream, &o_frames)) != S_OK) + { + // release input buffer + IAudioCaptureClient_ReleaseBuffer(stream->captureClient, 0); + + LogHostError(hr); + break; + } + + // process equal ammount of frames + if (o_frames >= i_frames) + { + // process input ammount of frames + UINT32 o_processed = i_frames; + + // get host output buffer + if ((hr = IAudioRenderClient_GetBuffer(stream->procRCClient, o_processed, &o_data)) == S_OK) + { + // processed amount of i_frames + i_processed = i_frames; + o_data_host = o_data; + + // convert output mono + if (stream->out.monoMixer) + { + UINT32 mono_frames_size = o_processed * (stream->out.wavex.Format.wBitsPerSample / 8); + // expand buffer + if (mono_frames_size > stream->out.monoBufferSize) + { + stream->out.monoBuffer = PaWasapi_ReallocateMemory(stream->out.monoBuffer, (stream->out.monoBufferSize = mono_frames_size)); + if (stream->out.monoBuffer == NULL) + { + // release input buffer + IAudioCaptureClient_ReleaseBuffer(stream->captureClient, 0); + // release output buffer + IAudioRenderClient_ReleaseBuffer(stream->renderClient, 0, 0); + + LogPaError(paInsufficientMemory); + break; + } + } + + // replace buffer pointer + o_data = (BYTE *)stream->out.monoBuffer; + } + + // convert input mono + if (stream->in.monoMixer) + { + UINT32 mono_frames_size = i_processed * (stream->in.wavex.Format.wBitsPerSample / 8); + // expand buffer + if (mono_frames_size > stream->in.monoBufferSize) + { + stream->in.monoBuffer = PaWasapi_ReallocateMemory(stream->in.monoBuffer, (stream->in.monoBufferSize = mono_frames_size)); + if (stream->in.monoBuffer == NULL) + { + // release input buffer + IAudioCaptureClient_ReleaseBuffer(stream->captureClient, 0); + // release output buffer + IAudioRenderClient_ReleaseBuffer(stream->renderClient, 0, 0); + + LogPaError(paInsufficientMemory); + break; + } + } + + // mix 2 to 1 input channels + stream->in.monoMixer(stream->in.monoBuffer, i_data, i_processed); + + // replace buffer pointer + i_data = (BYTE *)stream->in.monoBuffer; + } + + // process + processor[S_FULLDUPLEX].processor(i_data, i_processed, o_data, o_processed, processor[S_FULLDUPLEX].userData); + + // mix 1 to 2 output channels + if (stream->out.monoBuffer) + stream->out.monoMixer(o_data_host, stream->out.monoBuffer, o_processed); + + // release host output buffer + if ((hr = IAudioRenderClient_ReleaseBuffer(stream->renderClient, o_processed, 0)) != S_OK) + LogHostError(hr); + } + else + { + if (stream->out.shareMode != AUDCLNT_SHAREMODE_SHARED) + LogHostError(hr); // be silent in shared mode, try again next time + } + } + + // release host input buffer + if ((hr = IAudioCaptureClient_ReleaseBuffer(stream->captureClient, i_processed)) != S_OK) + { + LogHostError(hr); + break; + } + } +#else + // Processing Loop + UINT32 next_sleep = sleep_ms; + while (WaitForSingleObject(stream->hCloseRequest, next_sleep) == WAIT_TIMEOUT) + { + UINT32 i_frames = 0, i_processed = 0; + BYTE *i_data = NULL, *o_data = NULL, *o_data_host = NULL; + DWORD i_flags = 0; + UINT32 o_frames = 0; + + // Get next sleep time + if (sleep_ms == 0) + { + next_sleep = ThreadIdleScheduler_NextSleep(&scheduler); + } + + // get available frames + if ((hr = _PollGetOutputFramesAvailable(stream, &o_frames)) != S_OK) + { + LogHostError(hr); + break; + } + + while (o_frames != 0) + { + // get host input buffer + if ((hr = IAudioCaptureClient_GetBuffer(stream->captureClient, &i_data, &i_frames, &i_flags, NULL, NULL)) != S_OK) + { + if (hr == AUDCLNT_S_BUFFER_EMPTY) + break; // no data in capture buffer + + LogHostError(hr); + break; + } + + // process equal ammount of frames + if (o_frames >= i_frames) + { + // process input ammount of frames + UINT32 o_processed = i_frames; + + // get host output buffer + if ((hr = IAudioRenderClient_GetBuffer(stream->renderClient, o_processed, &o_data)) == S_OK) + { + // processed amount of i_frames + i_processed = i_frames; + o_data_host = o_data; + + // convert output mono + if (stream->out.monoMixer) + { + UINT32 mono_frames_size = o_processed * (stream->out.wavex.Format.wBitsPerSample / 8); + // expand buffer + if (mono_frames_size > stream->out.monoBufferSize) + { + stream->out.monoBuffer = PaWasapi_ReallocateMemory(stream->out.monoBuffer, (stream->out.monoBufferSize = mono_frames_size)); + if (stream->out.monoBuffer == NULL) + { + // release input buffer + IAudioCaptureClient_ReleaseBuffer(stream->captureClient, 0); + // release output buffer + IAudioRenderClient_ReleaseBuffer(stream->renderClient, 0, 0); + + LogPaError(paInsufficientMemory); + goto thread_error; + } + } + + // replace buffer pointer + o_data = (BYTE *)stream->out.monoBuffer; + } + + // convert input mono + if (stream->in.monoMixer) + { + UINT32 mono_frames_size = i_processed * (stream->in.wavex.Format.wBitsPerSample / 8); + // expand buffer + if (mono_frames_size > stream->in.monoBufferSize) + { + stream->in.monoBuffer = PaWasapi_ReallocateMemory(stream->in.monoBuffer, (stream->in.monoBufferSize = mono_frames_size)); + if (stream->in.monoBuffer == NULL) + { + // release input buffer + IAudioCaptureClient_ReleaseBuffer(stream->captureClient, 0); + // release output buffer + IAudioRenderClient_ReleaseBuffer(stream->renderClient, 0, 0); + + LogPaError(paInsufficientMemory); + goto thread_error; + } + } + + // mix 2 to 1 input channels + stream->in.monoMixer(stream->in.monoBuffer, i_data, i_processed); + + // replace buffer pointer + i_data = (BYTE *)stream->in.monoBuffer; + } + + // process + processor[S_FULLDUPLEX].processor(i_data, i_processed, o_data, o_processed, processor[S_FULLDUPLEX].userData); + + // mix 1 to 2 output channels + if (stream->out.monoBuffer) + stream->out.monoMixer(o_data_host, stream->out.monoBuffer, o_processed); + + // release host output buffer + if ((hr = IAudioRenderClient_ReleaseBuffer(stream->renderClient, o_processed, 0)) != S_OK) + LogHostError(hr); + + o_frames -= o_processed; + } + else + { + if (stream->out.shareMode != AUDCLNT_SHAREMODE_SHARED) + LogHostError(hr); // be silent in shared mode, try again next time + } + } + else + { + i_processed = 0; + goto fd_release_buffer_in; + } + +fd_release_buffer_in: + + // release host input buffer + if ((hr = IAudioCaptureClient_ReleaseBuffer(stream->captureClient, i_processed)) != S_OK) + { + LogHostError(hr); + break; + } + + // break processing, input hasn't been accumulated yet + if (i_processed == 0) + break; + } + } +#endif + } + +thread_end: + + // Process stop + _StreamOnStop(stream); + + // Release unmarshaled COM pointers + ReleaseUnmarshaledComPointers(stream); + + // Cleanup COM for this thread + if (bThreadComInitialized == TRUE) + CoUninitialize(); + + // Notify: not running + stream->running = FALSE; + + // Notify: thread exited + SetEvent(stream->hThreadExit); + + // Notify: state + NotifyStateChanged(stream, paWasapiStreamStateThreadStop, hr); + + return 0; + +thread_error: + + // Prevent deadlocking in Pa_StreamStart + SetEvent(stream->hThreadStart); + + // Exit + goto thread_end; +} + +// ------------------------------------------------------------------------------------------ +void *PaWasapi_ReallocateMemory(void *prev, size_t size) +{ + void *ret = realloc(prev, size); + if (ret == NULL) + { + PaWasapi_FreeMemory(prev); + return NULL; + } + return ret; +} + +// ------------------------------------------------------------------------------------------ +void PaWasapi_FreeMemory(void *ptr) +{ + free(ptr); +} + +//#endif //VC 2005 + + + + +#if 0 + if(bFirst) { + float masteur; + hr = stream->outVol->GetMasterVolumeLevelScalar(&masteur); + if (hr != S_OK) + LogHostError(hr); + float chan1, chan2; + hr = stream->outVol->GetChannelVolumeLevelScalar(0, &chan1); + if (hr != S_OK) + LogHostError(hr); + hr = stream->outVol->GetChannelVolumeLevelScalar(1, &chan2); + if (hr != S_OK) + LogHostError(hr); + + BOOL bMute; + hr = stream->outVol->GetMute(&bMute); + if (hr != S_OK) + LogHostError(hr); + + stream->outVol->SetMasterVolumeLevelScalar(0.5, NULL); + stream->outVol->SetChannelVolumeLevelScalar(0, 0.5, NULL); + stream->outVol->SetChannelVolumeLevelScalar(1, 0.5, NULL); + stream->outVol->SetMute(FALSE, NULL); + bFirst = FALSE; + } +#endif diff --git a/extern/portaudio/src/hostapi/wasapi/readme.txt b/extern/portaudio/src/hostapi/wasapi/readme.txt new file mode 100644 index 0000000..0cfa0fa --- /dev/null +++ b/extern/portaudio/src/hostapi/wasapi/readme.txt @@ -0,0 +1,22 @@ +************** +* WASAPI API * +************** + +------------------------------------------- +Microsoft Visual Studio 2005 SP1 and higher +------------------------------------------- +No specific action is required to compile WASAPI API under Visual Studio. +You are only required to install min. Windows Vista SDK (v6.0A) prior +the compilation. To compile with WASAPI specific functionality for Windows 8 +and higher the min. Windows 8 SDK is required. + +---------------------------------------- +MinGW (GCC 32/64-bit) +---------------------------------------- +To compile with MinGW you are required to include 'mingw-include' directory +which contains necessary files with WASAPI API. These files are modified +for the compatibility with MinGW compiler. These files are taken from +the Windows Vista SDK (v6.0A). MinGW compilation is tested and proved to be +fully working. +MinGW (32-bit) tested min. version: gcc version 4.4.0 (GCC) +MinGW64 (64-bit) tested min. version: gcc version 4.4.4 20100226 (prerelease) (GCC) \ No newline at end of file diff --git a/extern/portaudio/src/hostapi/wdmks/pa_win_wdmks.c b/extern/portaudio/src/hostapi/wdmks/pa_win_wdmks.c new file mode 100644 index 0000000..70a48d8 --- /dev/null +++ b/extern/portaudio/src/hostapi/wdmks/pa_win_wdmks.c @@ -0,0 +1,6791 @@ +/* +* $Id$ +* PortAudio Windows WDM-KS interface +* +* Author: Andrew Baldwin, Robert Bielik (WaveRT) +* Based on the Open Source API proposed by Ross Bencina +* Copyright (c) 1999-2004 Andrew Baldwin, Ross Bencina, Phil Burk +* +* Permission is hereby granted, free of charge, to any person obtaining +* a copy of this software and associated documentation files +* (the "Software"), to deal in the Software without restriction, +* including without limitation the rights to use, copy, modify, merge, +* publish, distribute, sublicense, and/or sell copies of the Software, +* and to permit persons to whom the Software is furnished to do so, +* subject to the following conditions: +* +* The above copyright notice and this permission notice shall be +* included in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR +* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +/* +* The text above constitutes the entire PortAudio license; however, +* the PortAudio community also makes the following non-binding requests: +* +* Any person wishing to distribute modifications to the Software is +* requested to send the modifications to the original developer so that +* they can be incorporated into the canonical version. It is also +* requested that these non-binding requests be included along with the +* license above. +*/ + +/** @file +@ingroup hostapi_src +@brief Portaudio WDM-KS host API. + +@note This is the implementation of the Portaudio host API using the +Windows WDM/Kernel Streaming API in order to enable very low latency +playback and recording on all modern Windows platforms (e.g. 2K, XP, Vista, Win7) +Note: This API accesses the device drivers below the usual KMIXER +component which is normally used to enable multi-client mixing and +format conversion. That means that it will lock out all other users +of a device for the duration of active stream using those devices +*/ + +#include + +#if (defined(_WIN32) && (defined(_MSC_VER) && (_MSC_VER >= 1200))) /* MSC version 6 and above */ +#pragma comment( lib, "setupapi.lib" ) +#endif + +/* Debugging/tracing support */ + +#define PA_LOGE_ +#define PA_LOGL_ + +#ifdef __GNUC__ +#include +#define _WIN32_WINNT 0x0501 +#define WINVER 0x0501 +#endif + +#include /* strlen() */ +#include +#include /* iswspace() */ + +#include "pa_util.h" +#include "pa_allocation.h" +#include "pa_hostapi.h" +#include "pa_stream.h" +#include "pa_cpuload.h" +#include "pa_process.h" +#include "portaudio.h" +#include "pa_debugprint.h" +#include "pa_memorybarrier.h" +#include "pa_ringbuffer.h" +#include "pa_trace.h" +#include "pa_win_waveformat.h" + +#include "pa_win_wdmks.h" + +#ifndef DRV_QUERYDEVICEINTERFACE +#define DRV_QUERYDEVICEINTERFACE (DRV_RESERVED + 12) +#endif +#ifndef DRV_QUERYDEVICEINTERFACESIZE +#define DRV_QUERYDEVICEINTERFACESIZE (DRV_RESERVED + 13) +#endif + +#include +#ifndef __GNUC__ /* Fix for ticket #257: MinGW-w64: Inclusion of triggers multiple redefinition errors. */ +#include +#endif +#include + +#include + +#ifdef _MSC_VER +#define snprintf _snprintf +#define vsnprintf _vsnprintf +#endif + +/* The PA_HP_TRACE macro is used in RT parts, so it can be switched off without affecting +the rest of the debug tracing */ +#if 1 +#define PA_HP_TRACE(x) PaUtil_AddHighSpeedLogMessage x ; +#else +#define PA_HP_TRACE(x) +#endif + +/* A define that selects whether the resulting pin names are chosen from pin category +instead of the available pin names, who sometimes can be quite cheesy, like "Volume control". +Default is to use the pin category. +*/ +#ifndef PA_WDMKS_USE_CATEGORY_FOR_PIN_NAMES +#define PA_WDMKS_USE_CATEGORY_FOR_PIN_NAMES 1 +#endif + +#ifdef __GNUC__ +#undef PA_LOGE_ +#define PA_LOGE_ PA_DEBUG(("%s {\n",__FUNCTION__)) +#undef PA_LOGL_ +#define PA_LOGL_ PA_DEBUG(("} %s\n",__FUNCTION__)) +/* These defines are set in order to allow the WIndows DirectX +* headers to compile with a GCC compiler such as MinGW +* NOTE: The headers may generate a few warning in GCC, but +* they should compile */ +#define _INC_MMSYSTEM +#define _INC_MMREG +#define _NTRTL_ /* Turn off default definition of DEFINE_GUIDEX */ +#define DEFINE_GUID_THUNK(name,guid) DEFINE_GUID(name,guid) +#define DEFINE_GUIDEX(n) DEFINE_GUID_THUNK( n, STATIC_##n ) +#if !defined( DEFINE_WAVEFORMATEX_GUID ) +#define DEFINE_WAVEFORMATEX_GUID(x) (USHORT)(x), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 +#endif +#define WAVE_FORMAT_ADPCM 0x0002 +#define WAVE_FORMAT_IEEE_FLOAT 0x0003 +#define WAVE_FORMAT_ALAW 0x0006 +#define WAVE_FORMAT_MULAW 0x0007 +#define WAVE_FORMAT_MPEG 0x0050 +#define WAVE_FORMAT_DRM 0x0009 +#define DYNAMIC_GUID_THUNK(l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) {l,w1,w2,{b1,b2,b3,b4,b5,b6,b7,b8}} +#define DYNAMIC_GUID(data) DYNAMIC_GUID_THUNK(data) +#endif + +/* use CreateThread for CYGWIN/Windows Mobile, _beginthreadex for all others */ +#if !defined(__CYGWIN__) && !defined(_WIN32_WCE) +#define CREATE_THREAD_FUNCTION (HANDLE)_beginthreadex +#define PA_THREAD_FUNC static unsigned WINAPI +#else +#define CREATE_THREAD_FUNCTION CreateThread +#define PA_THREAD_FUNC static DWORD WINAPI +#endif + +#ifdef _MSC_VER +#define NOMMIDS +#define DYNAMIC_GUID(data) {data} +#define _NTRTL_ /* Turn off default definition of DEFINE_GUIDEX */ +#undef DEFINE_GUID +#define DEFINE_GUID(n,data) EXTERN_C const GUID n = {data} +#define DEFINE_GUID_THUNK(n,data) DEFINE_GUID(n,data) +#define DEFINE_GUIDEX(n) DEFINE_GUID_THUNK(n, STATIC_##n) +#endif + +#include + +#ifndef EXTERN_C +#define EXTERN_C extern +#endif + +#if defined(__GNUC__) + +/* For MinGW we reference mingw-include files supplied with WASAPI */ +#define WINBOOL BOOL + +#include "../wasapi/mingw-include/ks.h" +#include "../wasapi/mingw-include/ksmedia.h" + +#else + +#include +#include + +/* Note that Windows SDK V6.0A or later is needed for WaveRT specific structs to be present in + ksmedia.h. Also make sure that the SDK include path is before other include paths (that may contain + an "old" ksmedia.h), so the proper ksmedia.h is used */ +#include + +#endif + +#include +#include + +/* These next definitions allow the use of the KSUSER DLL */ +typedef /*KSDDKAPI*/ DWORD WINAPI KSCREATEPIN(HANDLE, PKSPIN_CONNECT, ACCESS_MASK, PHANDLE); +extern HMODULE DllKsUser; +extern KSCREATEPIN* FunctionKsCreatePin; + +/* These definitions allows the use of AVRT.DLL on Vista and later OSs */ +typedef enum _PA_AVRT_PRIORITY +{ + PA_AVRT_PRIORITY_LOW = -1, + PA_AVRT_PRIORITY_NORMAL, + PA_AVRT_PRIORITY_HIGH, + PA_AVRT_PRIORITY_CRITICAL +} PA_AVRT_PRIORITY, *PPA_AVRT_PRIORITY; + +typedef struct +{ + HINSTANCE hInstance; + + HANDLE (WINAPI *AvSetMmThreadCharacteristics) (LPCSTR, LPDWORD); + BOOL (WINAPI *AvRevertMmThreadCharacteristics) (HANDLE); + BOOL (WINAPI *AvSetMmThreadPriority) (HANDLE, PA_AVRT_PRIORITY); +} PaWinWDMKSAvRtEntryPoints; + +static PaWinWDMKSAvRtEntryPoints paWinWDMKSAvRtEntryPoints = {0}; + +/* An unspecified channel count (-1) is not treated correctly, so we replace it with +* an arbitrarily large number */ +#define MAXIMUM_NUMBER_OF_CHANNELS 256 + +/* Forward definition to break circular type reference between pin and filter */ +struct __PaWinWdmFilter; +typedef struct __PaWinWdmFilter PaWinWdmFilter; + +struct __PaWinWdmPin; +typedef struct __PaWinWdmPin PaWinWdmPin; + +struct __PaWinWdmStream; +typedef struct __PaWinWdmStream PaWinWdmStream; + +/* Function prototype for getting audio position */ +typedef PaError (*FunctionGetPinAudioPosition)(PaWinWdmPin*, unsigned long*); + +/* Function prototype for memory barrier */ +typedef void (*FunctionMemoryBarrier)(void); + +struct __PaProcessThreadInfo; +typedef struct __PaProcessThreadInfo PaProcessThreadInfo; + +typedef PaError (*FunctionPinHandler)(PaProcessThreadInfo* pInfo, unsigned eventIndex); + +typedef enum __PaStreamStartEnum +{ + StreamStart_kOk, + StreamStart_kFailed, + StreamStart_kCnt +} PaStreamStartEnum; + +/* Multiplexed input structure. +* Very often several physical inputs are multiplexed through a MUX node (represented in the topology filter) */ +typedef struct __PaWinWdmMuxedInput +{ + wchar_t friendlyName[MAX_PATH]; + ULONG muxPinId; + ULONG muxNodeId; + ULONG endpointPinId; +} PaWinWdmMuxedInput; + +/* The Pin structure +* A pin is an input or output node, e.g. for audio flow */ +struct __PaWinWdmPin +{ + HANDLE handle; + PaWinWdmMuxedInput** inputs; + unsigned inputCount; + wchar_t friendlyName[MAX_PATH]; + + PaWinWdmFilter* parentFilter; + PaWDMKSSubType pinKsSubType; + unsigned long pinId; + unsigned long endpointPinId; /* For output pins */ + KSPIN_CONNECT* pinConnect; + unsigned long pinConnectSize; + KSDATAFORMAT_WAVEFORMATEX* ksDataFormatWfx; + KSPIN_COMMUNICATION communication; + KSDATARANGE* dataRanges; + KSMULTIPLE_ITEM* dataRangesItem; + KSPIN_DATAFLOW dataFlow; + KSPIN_CINSTANCES instances; + unsigned long frameSize; + int maxChannels; + unsigned long formats; + int defaultSampleRate; + ULONG *positionRegister; /* WaveRT */ + ULONG hwLatency; /* WaveRT */ + FunctionMemoryBarrier fnMemBarrier; /* WaveRT */ + FunctionGetPinAudioPosition fnAudioPosition; /* WaveRT */ + FunctionPinHandler fnEventHandler; + FunctionPinHandler fnSubmitHandler; +}; + +/* The Filter structure +* A filter has a number of pins and a "friendly name" */ +struct __PaWinWdmFilter +{ + HANDLE handle; + PaWinWDMKSDeviceInfo devInfo; /* This will hold information that is exposed in PaDeviceInfo */ + + DWORD deviceNode; + int pinCount; + PaWinWdmPin** pins; + PaWinWdmFilter* topologyFilter; + wchar_t friendlyName[MAX_PATH]; + int validPinCount; + int usageCount; + KSMULTIPLE_ITEM* connections; + KSMULTIPLE_ITEM* nodes; + int filterRefCount; +}; + + +typedef struct __PaWinWdmDeviceInfo +{ + PaDeviceInfo inheritedDeviceInfo; + char compositeName[MAX_PATH]; /* Composite name consists of pin name + device name in utf8 */ + PaWinWdmFilter* filter; + unsigned long pin; + int muxPosition; /* Used only for input devices */ + int endpointPinId; +} +PaWinWdmDeviceInfo; + +/* PaWinWdmHostApiRepresentation - host api datastructure specific to this implementation */ +typedef struct __PaWinWdmHostApiRepresentation +{ + PaUtilHostApiRepresentation inheritedHostApiRep; + PaUtilStreamInterface callbackStreamInterface; + PaUtilStreamInterface blockingStreamInterface; + + PaUtilAllocationGroup* allocations; + int deviceCount; +} +PaWinWdmHostApiRepresentation; + +typedef struct __DATAPACKET +{ + KSSTREAM_HEADER Header; + OVERLAPPED Signal; +} DATAPACKET; + +typedef struct __PaIOPacket +{ + DATAPACKET* packet; + unsigned startByte; + unsigned lengthBytes; +} PaIOPacket; + +typedef struct __PaWinWdmIOInfo +{ + PaWinWdmPin* pPin; + char* hostBuffer; + unsigned hostBufferSize; + unsigned framesPerBuffer; + unsigned bytesPerFrame; + unsigned bytesPerSample; + unsigned noOfPackets; /* Only used in WaveCyclic */ + HANDLE *events; /* noOfPackets handles (WaveCyclic) 1 (WaveRT) */ + DATAPACKET *packets; /* noOfPackets packets (WaveCyclic) 2 (WaveRT) */ + /* WaveRT polled mode */ + unsigned lastPosition; + unsigned pollCntr; +} PaWinWdmIOInfo; + +/* PaWinWdmStream - a stream data structure specifically for this implementation */ +struct __PaWinWdmStream +{ + PaUtilStreamRepresentation streamRepresentation; + PaWDMKSSpecificStreamInfo hostApiStreamInfo; /* This holds info that is exposed through PaStreamInfo */ + PaUtilCpuLoadMeasurer cpuLoadMeasurer; + PaUtilBufferProcessor bufferProcessor; + +#if PA_TRACE_REALTIME_EVENTS + LogHandle hLog; +#endif + + PaUtilAllocationGroup* allocGroup; + PaWinWdmIOInfo capture; + PaWinWdmIOInfo render; + int streamStarted; + int streamActive; + int streamStop; + int streamAbort; + int oldProcessPriority; + HANDLE streamThread; + HANDLE eventAbort; + HANDLE eventStreamStart[StreamStart_kCnt]; /* 0 = OK, 1 = Failed */ + PaError threadResult; + PaStreamFlags streamFlags; + + /* Capture ring buffer */ + PaUtilRingBuffer ringBuffer; + char* ringBufferData; + + /* These values handle the case where the user wants to use fewer + * channels than the device has */ + int userInputChannels; + int deviceInputChannels; + int userOutputChannels; + int deviceOutputChannels; +}; + +/* Gather all processing variables in a struct */ +struct __PaProcessThreadInfo +{ + PaWinWdmStream *stream; + PaStreamCallbackTimeInfo ti; + PaStreamCallbackFlags underover; + int cbResult; + volatile int pending; + volatile int priming; + volatile int pinsStarted; + unsigned long timeout; + unsigned captureHead; + unsigned captureTail; + unsigned renderHead; + unsigned renderTail; + PaIOPacket capturePackets[4]; + PaIOPacket renderPackets[4]; +}; + +/* Used for transferring device infos during scanning / rescanning */ +typedef struct __PaWinWDMScanDeviceInfosResults +{ + PaDeviceInfo **deviceInfos; + PaDeviceIndex defaultInputDevice; + PaDeviceIndex defaultOutputDevice; +} PaWinWDMScanDeviceInfosResults; + +static const unsigned cPacketsArrayMask = 3; + +HMODULE DllKsUser = NULL; +KSCREATEPIN* FunctionKsCreatePin = NULL; + +/* prototypes for functions declared in this file */ + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + PaError PaWinWdm_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index ); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +/* Low level I/O functions */ +static PaError WdmSyncIoctl(HANDLE handle, + unsigned long ioctlNumber, + void* inBuffer, + unsigned long inBufferCount, + void* outBuffer, + unsigned long outBufferCount, + unsigned long* bytesReturned); + +static PaError WdmGetPropertySimple(HANDLE handle, + const GUID* const guidPropertySet, + unsigned long property, + void* value, + unsigned long valueCount); + +static PaError WdmSetPropertySimple(HANDLE handle, + const GUID* const guidPropertySet, + unsigned long property, + void* value, + unsigned long valueCount, + void* instance, + unsigned long instanceCount); + +static PaError WdmGetPinPropertySimple(HANDLE handle, + unsigned long pinId, + const GUID* const guidPropertySet, + unsigned long property, + void* value, + unsigned long valueCount, + unsigned long* byteCount); + +static PaError WdmGetPinPropertyMulti(HANDLE handle, + unsigned long pinId, + const GUID* const guidPropertySet, + unsigned long property, + KSMULTIPLE_ITEM** ksMultipleItem); + +static PaError WdmGetPropertyMulti(HANDLE handle, + const GUID* const guidPropertySet, + unsigned long property, + KSMULTIPLE_ITEM** ksMultipleItem); + +static PaError WdmSetMuxNodeProperty(HANDLE handle, + ULONG nodeId, + ULONG pinId); + + +/** Pin management functions */ +static PaWinWdmPin* PinNew(PaWinWdmFilter* parentFilter, unsigned long pinId, PaError* error); +static void PinFree(PaWinWdmPin* pin); +static void PinClose(PaWinWdmPin* pin); +static PaError PinInstantiate(PaWinWdmPin* pin); +/*static PaError PinGetState(PaWinWdmPin* pin, KSSTATE* state); NOT USED */ +static PaError PinSetState(PaWinWdmPin* pin, KSSTATE state); +static PaError PinSetFormat(PaWinWdmPin* pin, const WAVEFORMATEX* format); +static PaError PinIsFormatSupported(PaWinWdmPin* pin, const WAVEFORMATEX* format); +/* WaveRT support */ +static PaError PinQueryNotificationSupport(PaWinWdmPin* pPin, BOOL* pbResult); +static PaError PinGetBuffer(PaWinWdmPin* pPin, void** pBuffer, DWORD* pRequestedBufSize, BOOL* pbCallMemBarrier); +static PaError PinRegisterPositionRegister(PaWinWdmPin* pPin); +static PaError PinRegisterNotificationHandle(PaWinWdmPin* pPin, HANDLE handle); +static PaError PinUnregisterNotificationHandle(PaWinWdmPin* pPin, HANDLE handle); +static PaError PinGetHwLatency(PaWinWdmPin* pPin, ULONG* pFifoSize, ULONG* pChipsetDelay, ULONG* pCodecDelay); +static PaError PinGetAudioPositionMemoryMapped(PaWinWdmPin* pPin, ULONG* pPosition); +static PaError PinGetAudioPositionViaIOCTLRead(PaWinWdmPin* pPin, ULONG* pPosition); +static PaError PinGetAudioPositionViaIOCTLWrite(PaWinWdmPin* pPin, ULONG* pPosition); + +/* Filter management functions */ +static PaWinWdmFilter* FilterNew(PaWDMKSType type, DWORD devNode, const wchar_t* filterName, const wchar_t* friendlyName, PaError* error); +static PaError FilterInitializePins(PaWinWdmFilter* filter); +static void FilterFree(PaWinWdmFilter* filter); +static void FilterAddRef(PaWinWdmFilter* filter); +static PaWinWdmPin* FilterCreatePin( + PaWinWdmFilter* filter, + int pinId, + const WAVEFORMATEX* wfex, + PaError* error); +static PaError FilterUse(PaWinWdmFilter* filter); +static void FilterRelease(PaWinWdmFilter* filter); + +/* Hot plug functions */ +static BOOL IsDeviceTheSame(const PaWinWdmDeviceInfo* pDev1, + const PaWinWdmDeviceInfo* pDev2); + +/* Interface functions */ +static void Terminate( struct PaUtilHostApiRepresentation *hostApi ); +static PaError IsFormatSupported( +struct PaUtilHostApiRepresentation *hostApi, + const PaStreamParameters *inputParameters, + const PaStreamParameters *outputParameters, + double sampleRate ); + +static PaError ScanDeviceInfos( struct PaUtilHostApiRepresentation *hostApi, PaHostApiIndex index, void **newDeviceInfos, int *newDeviceCount ); +static PaError CommitDeviceInfos( struct PaUtilHostApiRepresentation *hostApi, PaHostApiIndex index, void *deviceInfos, int deviceCount ); +static PaError DisposeDeviceInfos( struct PaUtilHostApiRepresentation *hostApi, void *deviceInfos, int deviceCount ); + +static PaError OpenStream( +struct PaUtilHostApiRepresentation *hostApi, + PaStream** s, + const PaStreamParameters *inputParameters, + const PaStreamParameters *outputParameters, + double sampleRate, + unsigned long framesPerBuffer, + PaStreamFlags streamFlags, + PaStreamCallback *streamCallback, + void *userData ); +static PaError CloseStream( PaStream* stream ); +static PaError StartStream( PaStream *stream ); +static PaError StopStream( PaStream *stream ); +static PaError AbortStream( PaStream *stream ); +static PaError IsStreamStopped( PaStream *s ); +static PaError IsStreamActive( PaStream *stream ); +static PaTime GetStreamTime( PaStream *stream ); +static double GetStreamCpuLoad( PaStream* stream ); +static PaError ReadStream( + PaStream* stream, + void *buffer, + unsigned long frames ); +static PaError WriteStream( + PaStream* stream, + const void *buffer, + unsigned long frames ); +static signed long GetStreamReadAvailable( PaStream* stream ); +static signed long GetStreamWriteAvailable( PaStream* stream ); + +/* Utility functions */ +static unsigned long GetWfexSize(const WAVEFORMATEX* wfex); +static PaWinWdmFilter** BuildFilterList(int* filterCount, int* noOfPaDevices, PaError* result); +static BOOL PinWrite(HANDLE h, DATAPACKET* p); +static BOOL PinRead(HANDLE h, DATAPACKET* p); +static void DuplicateFirstChannelInt16(void* buffer, int channels, int samples); +static void DuplicateFirstChannelInt24(void* buffer, int channels, int samples); +PA_THREAD_FUNC ProcessingThread(void*); + +/* Pin handler functions */ +static PaError PaPinCaptureEventHandler_WaveCyclic(PaProcessThreadInfo* pInfo, unsigned eventIndex); +static PaError PaPinCaptureSubmitHandler_WaveCyclic(PaProcessThreadInfo* pInfo, unsigned eventIndex); + +static PaError PaPinRenderEventHandler_WaveCyclic(PaProcessThreadInfo* pInfo, unsigned eventIndex); +static PaError PaPinRenderSubmitHandler_WaveCyclic(PaProcessThreadInfo* pInfo, unsigned eventIndex); + +static PaError PaPinCaptureEventHandler_WaveRTEvent(PaProcessThreadInfo* pInfo, unsigned eventIndex); +static PaError PaPinCaptureEventHandler_WaveRTPolled(PaProcessThreadInfo* pInfo, unsigned eventIndex); +static PaError PaPinCaptureSubmitHandler_WaveRTEvent(PaProcessThreadInfo* pInfo, unsigned eventIndex); +static PaError PaPinCaptureSubmitHandler_WaveRTPolled(PaProcessThreadInfo* pInfo, unsigned eventIndex); + +static PaError PaPinRenderEventHandler_WaveRTEvent(PaProcessThreadInfo* pInfo, unsigned eventIndex); +static PaError PaPinRenderEventHandler_WaveRTPolled(PaProcessThreadInfo* pInfo, unsigned eventIndex); +static PaError PaPinRenderSubmitHandler_WaveRTEvent(PaProcessThreadInfo* pInfo, unsigned eventIndex); +static PaError PaPinRenderSubmitHandler_WaveRTPolled(PaProcessThreadInfo* pInfo, unsigned eventIndex); + +/* Function bodies */ + +#if defined(_DEBUG) && defined(PA_ENABLE_DEBUG_OUTPUT) +#define PA_WDMKS_SET_TREF +static PaTime tRef = 0; + +static void PaWinWdmDebugPrintf(const char* fmt, ...) +{ + va_list list; + char buffer[1024]; + PaTime t = PaUtil_GetTime() - tRef; + va_start(list, fmt); + _vsnprintf(buffer, 1023, fmt, list); + va_end(list); + PaUtil_DebugPrint("%6.3lf: %s", t, buffer); +} + +#ifdef PA_DEBUG +#undef PA_DEBUG +#define PA_DEBUG(x) PaWinWdmDebugPrintf x ; +#endif +#endif + +static BOOL IsDeviceTheSame(const PaWinWdmDeviceInfo* pDev1, + const PaWinWdmDeviceInfo* pDev2) +{ + if (pDev1 == NULL || pDev2 == NULL) + return FALSE; + + if (pDev1 == pDev2) + return TRUE; + + if (strcmp(pDev1->compositeName, pDev2->compositeName) == 0) + return TRUE; + + return FALSE; +} + +static BOOL IsEarlierThanVista() +{ +/* +NOTE: GetVersionEx() is deprecated as of Windows 8.1 and can not be used to reliably detect +versions of Windows higher than Windows 8 (due to manifest requirements for reporting higher versions). +Microsoft recommends switching to VerifyVersionInfo (available on Win 2k and later), however GetVersionEx +is is faster, for now we just disable the deprecation warning. +See: https://msdn.microsoft.com/en-us/library/windows/desktop/ms724451(v=vs.85).aspx +See: http://www.codeproject.com/Articles/678606/Part-Overcoming-Windows-s-deprecation-of-GetVe +*/ +#pragma warning (disable : 4996) /* use of GetVersionEx */ + + OSVERSIONINFO osvi; + osvi.dwOSVersionInfoSize = sizeof(osvi); + if (GetVersionEx(&osvi) && osvi.dwMajorVersion<6) + { + return TRUE; + } + return FALSE; + +#pragma warning (default : 4996) +} + + + +static void MemoryBarrierDummy(void) +{ + /* Do nothing */ +} + +static void MemoryBarrierRead(void) +{ + PaUtil_ReadMemoryBarrier(); +} + +static void MemoryBarrierWrite(void) +{ + PaUtil_WriteMemoryBarrier(); +} + +static unsigned long GetWfexSize(const WAVEFORMATEX* wfex) +{ + if( wfex->wFormatTag == WAVE_FORMAT_PCM ) + { + return sizeof( WAVEFORMATEX ); + } + else + { + return (sizeof( WAVEFORMATEX ) + wfex->cbSize); + } +} + +static void PaWinWDM_SetLastErrorInfo(long errCode, const char* fmt, ...) +{ + va_list list; + char buffer[1024]; + va_start(list, fmt); + _vsnprintf(buffer, 1023, fmt, list); + va_end(list); + PaUtil_SetLastHostErrorInfo(paWDMKS, errCode, buffer); +} + +/* +Low level pin/filter access functions +*/ +static PaError WdmSyncIoctl( + HANDLE handle, + unsigned long ioctlNumber, + void* inBuffer, + unsigned long inBufferCount, + void* outBuffer, + unsigned long outBufferCount, + unsigned long* bytesReturned) +{ + PaError result = paNoError; + unsigned long dummyBytesReturned = 0; + BOOL bRes; + + if( !bytesReturned ) + { + /* Use a dummy as the caller hasn't supplied one */ + bytesReturned = &dummyBytesReturned; + } + + bRes = DeviceIoControl(handle, ioctlNumber, inBuffer, inBufferCount, outBuffer, outBufferCount, bytesReturned, NULL); + if (!bRes) + { + unsigned long error = GetLastError(); + if ( !(((error == ERROR_INSUFFICIENT_BUFFER ) || ( error == ERROR_MORE_DATA )) && + ( ioctlNumber == IOCTL_KS_PROPERTY ) && + ( outBufferCount == 0 ) ) ) + { + KSPROPERTY* ksProperty = (KSPROPERTY*)inBuffer; + + PaWinWDM_SetLastErrorInfo(result, "WdmSyncIoctl: DeviceIoControl GLE = 0x%08X (prop_set = {%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}, prop_id = %u)", + error, + ksProperty->Set.Data1, ksProperty->Set.Data2, ksProperty->Set.Data3, + ksProperty->Set.Data4[0], ksProperty->Set.Data4[1], + ksProperty->Set.Data4[2], ksProperty->Set.Data4[3], + ksProperty->Set.Data4[4], ksProperty->Set.Data4[5], + ksProperty->Set.Data4[6], ksProperty->Set.Data4[7], + ksProperty->Id + ); + result = paUnanticipatedHostError; + } + } + return result; +} + +static PaError WdmGetPropertySimple(HANDLE handle, + const GUID* const guidPropertySet, + unsigned long property, + void* value, + unsigned long valueCount) +{ + PaError result; + KSPROPERTY ksProperty; + + ksProperty.Set = *guidPropertySet; + ksProperty.Id = property; + ksProperty.Flags = KSPROPERTY_TYPE_GET; + + result = WdmSyncIoctl( + handle, + IOCTL_KS_PROPERTY, + &ksProperty, + sizeof(KSPROPERTY), + value, + valueCount, + NULL); + + return result; +} + +static PaError WdmSetPropertySimple( + HANDLE handle, + const GUID* const guidPropertySet, + unsigned long property, + void* value, + unsigned long valueCount, + void* instance, + unsigned long instanceCount) +{ + PaError result; + KSPROPERTY* ksProperty; + unsigned long propertyCount = 0; + + propertyCount = sizeof(KSPROPERTY) + instanceCount; + ksProperty = (KSPROPERTY*)_alloca( propertyCount ); + if( !ksProperty ) + { + return paInsufficientMemory; + } + + ksProperty->Set = *guidPropertySet; + ksProperty->Id = property; + ksProperty->Flags = KSPROPERTY_TYPE_SET; + + if( instance ) + { + memcpy((void*)((char*)ksProperty + sizeof(KSPROPERTY)), instance, instanceCount); + } + + result = WdmSyncIoctl( + handle, + IOCTL_KS_PROPERTY, + ksProperty, + propertyCount, + value, + valueCount, + NULL); + + return result; +} + +static PaError WdmGetPinPropertySimple( + HANDLE handle, + unsigned long pinId, + const GUID* const guidPropertySet, + unsigned long property, + void* value, + unsigned long valueCount, + unsigned long *byteCount) +{ + PaError result; + + KSP_PIN ksPProp; + ksPProp.Property.Set = *guidPropertySet; + ksPProp.Property.Id = property; + ksPProp.Property.Flags = KSPROPERTY_TYPE_GET; + ksPProp.PinId = pinId; + ksPProp.Reserved = 0; + + result = WdmSyncIoctl( + handle, + IOCTL_KS_PROPERTY, + &ksPProp, + sizeof(KSP_PIN), + value, + valueCount, + byteCount); + + return result; +} + +static PaError WdmGetPinPropertyMulti( + HANDLE handle, + unsigned long pinId, + const GUID* const guidPropertySet, + unsigned long property, + KSMULTIPLE_ITEM** ksMultipleItem) +{ + PaError result; + unsigned long multipleItemSize = 0; + KSP_PIN ksPProp; + + ksPProp.Property.Set = *guidPropertySet; + ksPProp.Property.Id = property; + ksPProp.Property.Flags = KSPROPERTY_TYPE_GET; + ksPProp.PinId = pinId; + ksPProp.Reserved = 0; + + result = WdmSyncIoctl( + handle, + IOCTL_KS_PROPERTY, + &ksPProp.Property, + sizeof(KSP_PIN), + NULL, + 0, + &multipleItemSize); + if( result != paNoError ) + { + return result; + } + + *ksMultipleItem = (KSMULTIPLE_ITEM*)PaUtil_AllocateMemory( multipleItemSize ); + if( !*ksMultipleItem ) + { + return paInsufficientMemory; + } + + result = WdmSyncIoctl( + handle, + IOCTL_KS_PROPERTY, + &ksPProp, + sizeof(KSP_PIN), + (void*)*ksMultipleItem, + multipleItemSize, + NULL); + + if( result != paNoError ) + { + PaUtil_FreeMemory( ksMultipleItem ); + } + + return result; +} + +static PaError WdmGetPropertyMulti(HANDLE handle, + const GUID* const guidPropertySet, + unsigned long property, + KSMULTIPLE_ITEM** ksMultipleItem) +{ + PaError result; + unsigned long multipleItemSize = 0; + KSPROPERTY ksProp; + + ksProp.Set = *guidPropertySet; + ksProp.Id = property; + ksProp.Flags = KSPROPERTY_TYPE_GET; + + result = WdmSyncIoctl( + handle, + IOCTL_KS_PROPERTY, + &ksProp, + sizeof(KSPROPERTY), + NULL, + 0, + &multipleItemSize); + if( result != paNoError ) + { + return result; + } + + *ksMultipleItem = (KSMULTIPLE_ITEM*)PaUtil_AllocateMemory( multipleItemSize ); + if( !*ksMultipleItem ) + { + return paInsufficientMemory; + } + + result = WdmSyncIoctl( + handle, + IOCTL_KS_PROPERTY, + &ksProp, + sizeof(KSPROPERTY), + (void*)*ksMultipleItem, + multipleItemSize, + NULL); + + if( result != paNoError ) + { + PaUtil_FreeMemory( ksMultipleItem ); + } + + return result; +} + +static PaError WdmSetMuxNodeProperty(HANDLE handle, + ULONG nodeId, + ULONG pinId) +{ + PaError result = paNoError; + KSNODEPROPERTY prop; + prop.Property.Set = KSPROPSETID_Audio; + prop.Property.Id = KSPROPERTY_AUDIO_MUX_SOURCE; + prop.Property.Flags = KSPROPERTY_TYPE_SET | KSPROPERTY_TYPE_TOPOLOGY; + prop.NodeId = nodeId; + prop.Reserved = 0; + + result = WdmSyncIoctl(handle, IOCTL_KS_PROPERTY, &prop, sizeof(KSNODEPROPERTY), &pinId, sizeof(ULONG), NULL); + + return result; +} + +/* Used when traversing topology for outputs */ +static const KSTOPOLOGY_CONNECTION* GetConnectionTo(const KSTOPOLOGY_CONNECTION* pFrom, PaWinWdmFilter* filter, int muxIdx) +{ + unsigned i; + const KSTOPOLOGY_CONNECTION* retval = NULL; + const KSTOPOLOGY_CONNECTION* connections = (const KSTOPOLOGY_CONNECTION*)(filter->connections + 1); + (void)muxIdx; + PA_DEBUG(("GetConnectionTo: Checking %u connections... (pFrom = %p)", filter->connections->Count, pFrom)); + for (i = 0; i < filter->connections->Count; ++i) + { + const KSTOPOLOGY_CONNECTION* pConn = connections + i; + if (pConn == pFrom) + continue; + + if (pConn->FromNode == pFrom->ToNode) + { + retval = pConn; + break; + } + } + PA_DEBUG(("GetConnectionTo: Returning %p\n", retval)); + return retval; +} + +/* Used when traversing topology for inputs */ +static const KSTOPOLOGY_CONNECTION* GetConnectionFrom(const KSTOPOLOGY_CONNECTION* pTo, PaWinWdmFilter* filter, int muxIdx) +{ + unsigned i; + const KSTOPOLOGY_CONNECTION* retval = NULL; + const KSTOPOLOGY_CONNECTION* connections = (const KSTOPOLOGY_CONNECTION*)(filter->connections + 1); + int muxCntr = 0; + PA_DEBUG(("GetConnectionFrom: Checking %u connections... (pTo = %p)\n", filter->connections->Count, pTo)); + for (i = 0; i < filter->connections->Count; ++i) + { + const KSTOPOLOGY_CONNECTION* pConn = connections + i; + if (pConn == pTo) + continue; + + if (pConn->ToNode == pTo->FromNode) + { + if (muxIdx >= 0) + { + if (muxCntr < muxIdx) + { + ++muxCntr; + continue; + } + } + retval = pConn; + break; + } + } + PA_DEBUG(("GetConnectionFrom: Returning %p\n", retval)); + return retval; +} + +static ULONG GetNumberOfConnectionsTo(const KSTOPOLOGY_CONNECTION* pTo, PaWinWdmFilter* filter) +{ + ULONG retval = 0; + unsigned i; + const KSTOPOLOGY_CONNECTION* connections = (const KSTOPOLOGY_CONNECTION*)(filter->connections + 1); + PA_DEBUG(("GetNumberOfConnectionsTo: Checking %u connections...\n", filter->connections->Count)); + for (i = 0; i < filter->connections->Count; ++i) + { + const KSTOPOLOGY_CONNECTION* pConn = connections + i; + if (pConn->ToNode == pTo->FromNode && + (pTo->FromNode != KSFILTER_NODE || pConn->ToNodePin == pTo->FromNodePin)) + { + ++retval; + } + } + PA_DEBUG(("GetNumberOfConnectionsTo: Returning %d\n", retval)); + return retval; +} + +typedef const KSTOPOLOGY_CONNECTION *(*TFnGetConnection)(const KSTOPOLOGY_CONNECTION*, PaWinWdmFilter*, int); + +static const KSTOPOLOGY_CONNECTION* FindStartConnectionFrom(ULONG startPin, PaWinWdmFilter* filter) +{ + unsigned i; + const KSTOPOLOGY_CONNECTION* connections = (const KSTOPOLOGY_CONNECTION*)(filter->connections + 1); + PA_DEBUG(("FindStartConnectionFrom: Startpin %u, Checking %u connections...\n", startPin, filter->connections->Count)); + for (i = 0; i < filter->connections->Count; ++i) + { + const KSTOPOLOGY_CONNECTION* pConn = connections + i; + if (pConn->ToNode == KSFILTER_NODE && pConn->ToNodePin == startPin) + { + PA_DEBUG(("FindStartConnectionFrom: returning %p\n", pConn)); + return pConn; + } + } + + PA_DEBUG(("FindStartConnectionFrom: returning NULL\n")); + assert(FALSE); + return 0; +} + +static const KSTOPOLOGY_CONNECTION* FindStartConnectionTo(ULONG startPin, PaWinWdmFilter* filter) +{ + unsigned i; + const KSTOPOLOGY_CONNECTION* connections = (const KSTOPOLOGY_CONNECTION*)(filter->connections + 1); + PA_DEBUG(("FindStartConnectionTo: Startpin %u, Checking %u connections...\n", startPin, filter->connections->Count)); + for (i = 0; i < filter->connections->Count; ++i) + { + const KSTOPOLOGY_CONNECTION* pConn = connections + i; + if (pConn->FromNode == KSFILTER_NODE && pConn->FromNodePin == startPin) + { + PA_DEBUG(("FindStartConnectionTo: returning %p\n", pConn)); + return pConn; + } + } + + PA_DEBUG(("FindStartConnectionTo: returning NULL\n")); + assert(FALSE); + return 0; +} + +static ULONG GetConnectedPin(ULONG startPin, BOOL forward, PaWinWdmFilter* filter, int muxPosition, ULONG *muxInputPinId, ULONG *muxNodeId) +{ + int limit=1000; + const KSTOPOLOGY_CONNECTION *conn = NULL; + TFnGetConnection fnGetConnection = forward ? GetConnectionTo : GetConnectionFrom ; + PA_LOGE_; + while (1) + { + limit--; + if (limit == 0) { + PA_DEBUG(("GetConnectedPin: LOOP LIMIT REACHED\n")); + break; + } + + if (conn == NULL) + { + conn = forward ? FindStartConnectionTo(startPin, filter) : FindStartConnectionFrom(startPin, filter); + } + else + { + conn = fnGetConnection(conn, filter, -1); + } + + /* Handling case of erroneous connection list */ + if (conn == NULL) + { + break; + } + + if (forward ? conn->ToNode == KSFILTER_NODE : conn->FromNode == KSFILTER_NODE) + { + return forward ? conn->ToNodePin : conn->FromNodePin; + } + else + { + PA_DEBUG(("GetConnectedPin: count=%d, forward=%d, muxPosition=%d\n", filter->nodes->Count, forward, muxPosition)); + if (filter->nodes->Count > 0 && !forward && muxPosition >= 0) + { + const GUID* nodes = (const GUID*)(filter->nodes + 1); + if (IsEqualGUID(&nodes[conn->FromNode], &KSNODETYPE_MUX)) + { + ULONG nConn = GetNumberOfConnectionsTo(conn, filter); + conn = fnGetConnection(conn, filter, muxPosition); + if (conn == NULL) + { + break; + } + if (muxInputPinId != 0) + { + *muxInputPinId = conn->ToNodePin; + } + if (muxNodeId != 0) + { + *muxNodeId = conn->ToNode; + } + } + } + } + } + PA_LOGL_; + return KSFILTER_NODE; +} + +static void DumpConnectionsAndNodes(PaWinWdmFilter* filter) +{ + unsigned i; + const KSTOPOLOGY_CONNECTION* connections = (const KSTOPOLOGY_CONNECTION*)(filter->connections + 1); + const GUID* nodes = (const GUID*)(filter->nodes + 1); + + PA_LOGE_; + PA_DEBUG(("DumpConnectionsAndNodes: connections=%d, nodes=%d\n", filter->connections->Count, filter->nodes->Count)); + + for (i=0; i < filter->connections->Count; ++i) + { + const KSTOPOLOGY_CONNECTION* pConn = connections + i; + PA_DEBUG((" Connection: %u - FromNode=%u,FromPin=%u -> ToNode=%u,ToPin=%u\n", + i, + pConn->FromNode, pConn->FromNodePin, + pConn->ToNode, pConn->ToNodePin + )); + } + + for (i=0; i < filter->nodes->Count; ++i) + { + const GUID* pConn = nodes + i; + PA_DEBUG((" Node: %d - {%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}\n", + i, + pConn->Data1, pConn->Data2, pConn->Data3, + pConn->Data4[0], pConn->Data4[1], + pConn->Data4[2], pConn->Data4[3], + pConn->Data4[4], pConn->Data4[5], + pConn->Data4[6], pConn->Data4[7] + )); + } + PA_LOGL_; + +} + +typedef struct __PaUsbTerminalGUIDToName +{ + USHORT usbGUID; + wchar_t name[64]; +} PaUsbTerminalGUIDToName; + +static const PaUsbTerminalGUIDToName kNames[] = +{ + /* Types copied from: http://msdn.microsoft.com/en-us/library/ff537742(v=vs.85).aspx */ + /* Input terminal types */ + { 0x0201, L"Microphone" }, + { 0x0202, L"Desktop Microphone" }, + { 0x0203, L"Personal Microphone" }, + { 0x0204, L"Omni Directional Microphone" }, + { 0x0205, L"Microphone Array" }, + { 0x0206, L"Processing Microphone Array" }, + /* Output terminal types */ + { 0x0301, L"Speakers" }, + { 0x0302, L"Headphones" }, + { 0x0303, L"Head Mounted Display Audio" }, + { 0x0304, L"Desktop Speaker" }, + { 0x0305, L"Room Speaker" }, + { 0x0306, L"Communication Speaker" }, + { 0x0307, L"LFE Speakers" }, + /* External terminal types */ + { 0x0601, L"Analog" }, + { 0x0602, L"Digital" }, + { 0x0603, L"Line" }, + { 0x0604, L"Audio" }, + { 0x0605, L"SPDIF" }, +}; + +static const unsigned kNamesCnt = sizeof(kNames)/sizeof(PaUsbTerminalGUIDToName); + +static int PaUsbTerminalGUIDToNameCmp(const void* lhs, const void* rhs) +{ + const PaUsbTerminalGUIDToName* pL = (const PaUsbTerminalGUIDToName*)lhs; + const PaUsbTerminalGUIDToName* pR = (const PaUsbTerminalGUIDToName*)rhs; + return ((int)(pL->usbGUID) - (int)(pR->usbGUID)); +} + +static PaError GetNameFromCategory(const GUID* pGUID, BOOL input, wchar_t* name, unsigned length) +{ + PaError result = paUnanticipatedHostError; + USHORT usbTerminalGUID = (USHORT)(pGUID->Data1 - 0xDFF219E0); + + PA_LOGE_; + if (input && usbTerminalGUID >= 0x301 && usbTerminalGUID < 0x400) + { + /* Output terminal name for an input !? Set it to Line! */ + usbTerminalGUID = 0x603; + } + if (!input && usbTerminalGUID >= 0x201 && usbTerminalGUID < 0x300) + { + /* Input terminal name for an output !? Set it to Line! */ + usbTerminalGUID = 0x603; + } + if (usbTerminalGUID >= 0x201 && usbTerminalGUID < 0x713) + { + PaUsbTerminalGUIDToName s = { usbTerminalGUID }; + const PaUsbTerminalGUIDToName* ptr = bsearch( + &s, + kNames, + kNamesCnt, + sizeof(PaUsbTerminalGUIDToName), + PaUsbTerminalGUIDToNameCmp + ); + if (ptr != 0) + { + PA_DEBUG(("GetNameFromCategory: USB GUID %04X -> '%S'\n", usbTerminalGUID, ptr->name)); + + if (name != NULL && length > 0) + { + int n = _snwprintf(name, length, L"%s", ptr->name); + if (usbTerminalGUID >= 0x601 && usbTerminalGUID < 0x700) + { + _snwprintf(name + n, length - n, L" %s", (input ? L"In":L"Out")); + } + } + result = paNoError; + } + } + else + { + PaWinWDM_SetLastErrorInfo(result, "GetNameFromCategory: usbTerminalGUID = %04X ", usbTerminalGUID); + } + PA_LOGL_; + return result; +} + +static BOOL IsFrequencyWithinRange(const KSDATARANGE_AUDIO* range, int frequency) +{ + if (frequency < (int)range->MinimumSampleFrequency) + return FALSE; + if (frequency > (int)range->MaximumSampleFrequency) + return FALSE; + return TRUE; +} + +static BOOL IsBitsWithinRange(const KSDATARANGE_AUDIO* range, int noOfBits) +{ + if (noOfBits < (int)range->MinimumBitsPerSample) + return FALSE; + if (noOfBits > (int)range->MaximumBitsPerSample) + return FALSE; + return TRUE; +} + +/* Note: Somewhat different order compared to WMME implementation, as we want to focus on fidelity first */ +static const int defaultSampleRateSearchOrder[] = +{ 44100, 48000, 88200, 96000, 192000, 32000, 24000, 22050, 16000, 12000, 11025, 9600, 8000 }; +static const int defaultSampleRateSearchOrderCount = sizeof(defaultSampleRateSearchOrder)/sizeof(defaultSampleRateSearchOrder[0]); + +static int DefaultSampleFrequencyIndex(const KSDATARANGE_AUDIO* range) +{ + int i; + + for(i=0; i < defaultSampleRateSearchOrderCount; ++i) + { + int currentFrequency = defaultSampleRateSearchOrder[i]; + + if (IsFrequencyWithinRange(range, currentFrequency)) + { + return i; + } + } + + return -1; +} + +/* +Create a new pin object belonging to a filter +The pin object holds all the configuration information about the pin +before it is opened, and then the handle of the pin after is opened +*/ +static PaWinWdmPin* PinNew(PaWinWdmFilter* parentFilter, unsigned long pinId, PaError* error) +{ + PaWinWdmPin* pin; + PaError result; + unsigned long i; + KSMULTIPLE_ITEM* item = NULL; + KSIDENTIFIER* identifier; + KSDATARANGE* dataRange; + const ULONG streamingId = (parentFilter->devInfo.streamingType == Type_kWaveRT) ? KSINTERFACE_STANDARD_LOOPED_STREAMING : KSINTERFACE_STANDARD_STREAMING; + int defaultSampleRateIndex = defaultSampleRateSearchOrderCount; + + PA_LOGE_; + PA_DEBUG(("PinNew: Creating pin %d:\n",pinId)); + + /* Allocate the new PIN object */ + pin = (PaWinWdmPin*)PaUtil_AllocateMemory( sizeof(PaWinWdmPin) ); + if( !pin ) + { + result = paInsufficientMemory; + goto error; + } + + /* Zero the pin object */ + /* memset( (void*)pin, 0, sizeof(PaWinWdmPin) ); */ + + pin->parentFilter = parentFilter; + pin->pinId = pinId; + + /* Allocate a connect structure */ + pin->pinConnectSize = sizeof(KSPIN_CONNECT) + sizeof(KSDATAFORMAT_WAVEFORMATEX); + pin->pinConnect = (KSPIN_CONNECT*)PaUtil_AllocateMemory( pin->pinConnectSize ); + if( !pin->pinConnect ) + { + result = paInsufficientMemory; + goto error; + } + + /* Configure the connect structure with default values */ + pin->pinConnect->Interface.Set = KSINTERFACESETID_Standard; + pin->pinConnect->Interface.Id = streamingId; + pin->pinConnect->Interface.Flags = 0; + pin->pinConnect->Medium.Set = KSMEDIUMSETID_Standard; + pin->pinConnect->Medium.Id = KSMEDIUM_TYPE_ANYINSTANCE; + pin->pinConnect->Medium.Flags = 0; + pin->pinConnect->PinId = pinId; + pin->pinConnect->PinToHandle = NULL; + pin->pinConnect->Priority.PriorityClass = KSPRIORITY_NORMAL; + pin->pinConnect->Priority.PrioritySubClass = 1; + pin->ksDataFormatWfx = (KSDATAFORMAT_WAVEFORMATEX*)(pin->pinConnect + 1); + pin->ksDataFormatWfx->DataFormat.FormatSize = sizeof(KSDATAFORMAT_WAVEFORMATEX); + pin->ksDataFormatWfx->DataFormat.Flags = 0; + pin->ksDataFormatWfx->DataFormat.Reserved = 0; + pin->ksDataFormatWfx->DataFormat.MajorFormat = KSDATAFORMAT_TYPE_AUDIO; + pin->ksDataFormatWfx->DataFormat.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; + pin->ksDataFormatWfx->DataFormat.Specifier = KSDATAFORMAT_SPECIFIER_WAVEFORMATEX; + + pin->frameSize = 0; /* Unknown until we instantiate pin */ + + /* Get the COMMUNICATION property */ + result = WdmGetPinPropertySimple( + parentFilter->handle, + pinId, + &KSPROPSETID_Pin, + KSPROPERTY_PIN_COMMUNICATION, + &pin->communication, + sizeof(KSPIN_COMMUNICATION), + NULL); + if( result != paNoError ) + goto error; + + if( /*(pin->communication != KSPIN_COMMUNICATION_SOURCE) &&*/ + (pin->communication != KSPIN_COMMUNICATION_SINK) && + (pin->communication != KSPIN_COMMUNICATION_BOTH) ) + { + PA_DEBUG(("PinNew: Not source/sink\n")); + result = paInvalidDevice; + goto error; + } + + /* Get dataflow information */ + result = WdmGetPinPropertySimple( + parentFilter->handle, + pinId, + &KSPROPSETID_Pin, + KSPROPERTY_PIN_DATAFLOW, + &pin->dataFlow, + sizeof(KSPIN_DATAFLOW), + NULL); + + if( result != paNoError ) + goto error; + + /* Get the INTERFACE property list */ + result = WdmGetPinPropertyMulti( + parentFilter->handle, + pinId, + &KSPROPSETID_Pin, + KSPROPERTY_PIN_INTERFACES, + &item); + + if( result != paNoError ) + goto error; + + identifier = (KSIDENTIFIER*)(item+1); + + /* Check that at least one interface is STANDARD_STREAMING */ + result = paUnanticipatedHostError; + for( i = 0; i < item->Count; i++ ) + { + if( IsEqualGUID(&identifier[i].Set, &KSINTERFACESETID_Standard) && ( identifier[i].Id == streamingId ) ) + { + result = paNoError; + break; + } + } + + if( result != paNoError ) + { + PA_DEBUG(("PinNew: No %s streaming\n", streamingId==KSINTERFACE_STANDARD_LOOPED_STREAMING?"looped":"standard")); + goto error; + } + + /* Don't need interfaces any more */ + PaUtil_FreeMemory( item ); + item = NULL; + + /* Get the MEDIUM properties list */ + result = WdmGetPinPropertyMulti( + parentFilter->handle, + pinId, + &KSPROPSETID_Pin, + KSPROPERTY_PIN_MEDIUMS, + &item); + + if( result != paNoError ) + goto error; + + identifier = (KSIDENTIFIER*)(item+1); /* Not actually necessary... */ + + /* Check that at least one medium is STANDARD_DEVIO */ + result = paUnanticipatedHostError; + for( i = 0; i < item->Count; i++ ) + { + if( IsEqualGUID(&identifier[i].Set, &KSMEDIUMSETID_Standard) && ( identifier[i].Id == KSMEDIUM_STANDARD_DEVIO ) ) + { + result = paNoError; + break; + } + } + + if( result != paNoError ) + { + PA_DEBUG(("No standard devio\n")); + goto error; + } + /* Don't need mediums any more */ + PaUtil_FreeMemory( item ); + item = NULL; + + /* Get DATARANGES */ + result = WdmGetPinPropertyMulti( + parentFilter->handle, + pinId, + &KSPROPSETID_Pin, + KSPROPERTY_PIN_DATARANGES, + &pin->dataRangesItem); + + if( result != paNoError ) + goto error; + + pin->dataRanges = (KSDATARANGE*)(pin->dataRangesItem +1); + + /* Check that at least one datarange supports audio */ + result = paUnanticipatedHostError; + dataRange = pin->dataRanges; + pin->maxChannels = 0; + pin->defaultSampleRate = 0; + pin->formats = 0; + PA_DEBUG(("PinNew: Checking %u no of dataranges...\n", pin->dataRangesItem->Count)); + for( i = 0; i < pin->dataRangesItem->Count; i++) + { + PA_DEBUG(("PinNew: DR major format %x\n",*(unsigned long*)(&(dataRange->MajorFormat)))); + /* Check that subformat is WAVEFORMATEX, PCM or WILDCARD */ + if( IS_VALID_WAVEFORMATEX_GUID(&dataRange->SubFormat) || + IsEqualGUID(&dataRange->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM) || + IsEqualGUID(&dataRange->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT) || + IsEqualGUID(&dataRange->SubFormat, &KSDATAFORMAT_SUBTYPE_WILDCARD) || + IsEqualGUID(&dataRange->MajorFormat, &KSDATAFORMAT_TYPE_AUDIO) ) + { + int defaultIndex; + result = paNoError; + /* Record the maximum possible channels with this pin */ + if( ((KSDATARANGE_AUDIO*)dataRange)->MaximumChannels == (ULONG) -1 ) + { + pin->maxChannels = MAXIMUM_NUMBER_OF_CHANNELS; + } + else if( (int) ((KSDATARANGE_AUDIO*)dataRange)->MaximumChannels > pin->maxChannels ) + { + pin->maxChannels = (int) ((KSDATARANGE_AUDIO*)dataRange)->MaximumChannels; + } + PA_DEBUG(("PinNew: MaxChannel: %d\n",pin->maxChannels)); + + /* Record the formats (bit depths) that are supported */ + if( IsBitsWithinRange((KSDATARANGE_AUDIO*)dataRange, 8) ) + { + pin->formats |= paInt8; + PA_DEBUG(("PinNew: Format PCM 8 bit supported\n")); + } + if( IsBitsWithinRange((KSDATARANGE_AUDIO*)dataRange, 16) ) + { + pin->formats |= paInt16; + PA_DEBUG(("PinNew: Format PCM 16 bit supported\n")); + } + if( IsBitsWithinRange((KSDATARANGE_AUDIO*)dataRange, 24) ) + { + pin->formats |= paInt24; + PA_DEBUG(("PinNew: Format PCM 24 bit supported\n")); + } + if( IsBitsWithinRange((KSDATARANGE_AUDIO*)dataRange, 32) ) + { + if (IsEqualGUID(&dataRange->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)) + { + pin->formats |= paFloat32; + PA_DEBUG(("PinNew: Format IEEE float 32 bit supported\n")); + } + else + { + pin->formats |= paInt32; + PA_DEBUG(("PinNew: Format PCM 32 bit supported\n")); + } + } + + defaultIndex = DefaultSampleFrequencyIndex((KSDATARANGE_AUDIO*)dataRange); + if (defaultIndex >= 0 && defaultIndex < defaultSampleRateIndex) + { + defaultSampleRateIndex = defaultIndex; + } + } + dataRange = (KSDATARANGE*)( ((char*)dataRange) + dataRange->FormatSize); + } + + if( result != paNoError ) + goto error; + + /* If none of the frequencies searched for are present, there's something seriously wrong */ + if (defaultSampleRateIndex == defaultSampleRateSearchOrderCount) + { + PA_DEBUG(("PinNew: No default sample rate found, skipping pin!\n")); + PaWinWDM_SetLastErrorInfo(paUnanticipatedHostError, "PinNew: No default sample rate found"); + result = paUnanticipatedHostError; + goto error; + } + + /* Set the default sample rate */ + pin->defaultSampleRate = defaultSampleRateSearchOrder[defaultSampleRateIndex]; + PA_DEBUG(("PinNew: Default sample rate = %d Hz\n", pin->defaultSampleRate)); + + /* Get instance information */ + result = WdmGetPinPropertySimple( + parentFilter->handle, + pinId, + &KSPROPSETID_Pin, + KSPROPERTY_PIN_CINSTANCES, + &pin->instances, + sizeof(KSPIN_CINSTANCES), + NULL); + + if( result != paNoError ) + goto error; + + /* If WaveRT, check if pin supports notification mode */ + if (parentFilter->devInfo.streamingType == Type_kWaveRT) + { + BOOL bSupportsNotification = FALSE; + if (PinQueryNotificationSupport(pin, &bSupportsNotification) == paNoError) + { + pin->pinKsSubType = bSupportsNotification ? SubType_kNotification : SubType_kPolled; + } + } + + /* Query pin name (which means we need to traverse to non IRP pin, via physical connection to topology filter pin, through + its nodes to the endpoint pin, and get that ones name... phew...) */ + PA_DEBUG(("PinNew: Finding topology pin...\n")); + + { + ULONG topoPinId = GetConnectedPin(pinId, (pin->dataFlow == KSPIN_DATAFLOW_IN), parentFilter, -1, NULL, NULL); + const wchar_t kInputName[] = L"Input"; + const wchar_t kOutputName[] = L"Output"; + + if (topoPinId != KSFILTER_NODE) + { + /* Get physical connection for topo pin */ + unsigned long cbBytes = 0; + PA_DEBUG(("PinNew: Getting physical connection...\n")); + result = WdmGetPinPropertySimple(parentFilter->handle, + topoPinId, + &KSPROPSETID_Pin, + KSPROPERTY_PIN_PHYSICALCONNECTION, + 0, + 0, + &cbBytes + ); + + if (result != paNoError) + { + /* No physical connection -> there is no topology filter! So we get the name of the pin! */ + PA_DEBUG(("PinNew: No physical connection! Getting the pin name\n")); + result = WdmGetPinPropertySimple(parentFilter->handle, + topoPinId, + &KSPROPSETID_Pin, + KSPROPERTY_PIN_NAME, + pin->friendlyName, + MAX_PATH, + NULL); + if (result != paNoError) + { + GUID category = {0}; + + /* Get pin category information */ + result = WdmGetPinPropertySimple(parentFilter->handle, + topoPinId, + &KSPROPSETID_Pin, + KSPROPERTY_PIN_CATEGORY, + &category, + sizeof(GUID), + NULL); + + if (result == paNoError) + { + result = GetNameFromCategory(&category, (pin->dataFlow == KSPIN_DATAFLOW_OUT), pin->friendlyName, MAX_PATH); + } + } + + /* Make sure pin gets a name here... */ + if (wcslen(pin->friendlyName) == 0) + { + wcscpy(pin->friendlyName, (pin->dataFlow == KSPIN_DATAFLOW_IN) ? kOutputName : kInputName); +#ifdef UNICODE + PA_DEBUG(("PinNew: Setting pin friendly name to '%s'\n", pin->friendlyName)); +#else + PA_DEBUG(("PinNew: Setting pin friendly name to '%S'\n", pin->friendlyName)); +#endif + } + + /* This is then == the endpoint pin */ + pin->endpointPinId = (pin->dataFlow == KSPIN_DATAFLOW_IN) ? pinId : topoPinId; + } + else + { + KSPIN_PHYSICALCONNECTION* pc = (KSPIN_PHYSICALCONNECTION*)PaUtil_AllocateMemory(cbBytes + 2); + ULONG pcPin; + wchar_t symbLinkName[MAX_PATH]; + PA_DEBUG(("PinNew: Physical connection found!\n")); + if (pc == NULL) + { + result = paInsufficientMemory; + goto error; + } + result = WdmGetPinPropertySimple(parentFilter->handle, + topoPinId, + &KSPROPSETID_Pin, + KSPROPERTY_PIN_PHYSICALCONNECTION, + pc, + cbBytes, + NULL + ); + + pcPin = pc->Pin; + wcsncpy(symbLinkName, pc->SymbolicLinkName, MAX_PATH); + PaUtil_FreeMemory( pc ); + + if (result != paNoError) + { + /* Shouldn't happen, but fail if it does */ + PA_DEBUG(("PinNew: failed to retrieve physical connection!\n")); + goto error; + } + + if (symbLinkName[1] == TEXT('?')) + { + symbLinkName[1] = TEXT('\\'); + } + + if (pin->parentFilter->topologyFilter == NULL) + { + PA_DEBUG(("PinNew: Creating topology filter '%S'\n", symbLinkName)); + + pin->parentFilter->topologyFilter = FilterNew(Type_kNotUsed, 0, symbLinkName, L"", &result); + if (pin->parentFilter->topologyFilter == NULL) + { + PA_DEBUG(("PinNew: Failed creating topology filter\n")); + result = paUnanticipatedHostError; + PaWinWDM_SetLastErrorInfo(result, "Failed to create topology filter '%S'", symbLinkName); + goto error; + } + + /* Copy info so we have it in device info */ + wcsncpy(pin->parentFilter->devInfo.topologyPath, symbLinkName, MAX_PATH); + } + else + { + /* Must be the same */ + assert(wcscmp(symbLinkName, pin->parentFilter->topologyFilter->devInfo.filterPath) == 0); + } + + PA_DEBUG(("PinNew: Opening topology filter...")); + + result = FilterUse(pin->parentFilter->topologyFilter); + if (result == paNoError) + { + unsigned long endpointPinId; + + if (pin->dataFlow == KSPIN_DATAFLOW_IN) + { + /* The "endpointPinId" is what WASAPI looks at for pin names */ + GUID category = {0}; + + PA_DEBUG(("PinNew: Checking for output endpoint pin id...\n")); + + endpointPinId = GetConnectedPin(pcPin, TRUE, pin->parentFilter->topologyFilter, -1, NULL, NULL); + + if (endpointPinId == KSFILTER_NODE) + { + result = paUnanticipatedHostError; + PaWinWDM_SetLastErrorInfo(result, "Failed to get endpoint pin ID on topology filter!"); + goto error; + } + + PA_DEBUG(("PinNew: Found endpoint pin id %u\n", endpointPinId)); + + /* Get pin category information */ + result = WdmGetPinPropertySimple(pin->parentFilter->topologyFilter->handle, + endpointPinId, + &KSPROPSETID_Pin, + KSPROPERTY_PIN_CATEGORY, + &category, + sizeof(GUID), + NULL); + + if (result == paNoError) + { +#if !PA_WDMKS_USE_CATEGORY_FOR_PIN_NAMES + wchar_t pinName[MAX_PATH]; + + PA_DEBUG(("PinNew: Getting pin name property...")); + + /* Ok, try pin name also, and favor that if available */ + result = WdmGetPinPropertySimple(pin->parentFilter->topologyFilter->handle, + endpointPinId, + &KSPROPSETID_Pin, + KSPROPERTY_PIN_NAME, + pinName, + MAX_PATH, + NULL); + + if (result == paNoError && wcslen(pinName)>0) + { + wcsncpy(pin->friendlyName, pinName, MAX_PATH); + } + else +#endif + { + result = GetNameFromCategory(&category, (pin->dataFlow == KSPIN_DATAFLOW_OUT), pin->friendlyName, MAX_PATH); + } + } + + /* Make sure we get a name for the pin */ + if (wcslen(pin->friendlyName) == 0) + { + wcscpy(pin->friendlyName, kOutputName); + } +#ifdef UNICODE + PA_DEBUG(("PinNew: Pin name '%s'\n", pin->friendlyName)); +#else + PA_DEBUG(("PinNew: Pin name '%S'\n", pin->friendlyName)); +#endif + + /* Set endpoint pin ID (this is the topology INPUT pin, since portmixer will always traverse the + filter in audio streaming direction, see http://msdn.microsoft.com/en-us/library/windows/hardware/ff536331(v=vs.85).aspx + for more information) + */ + pin->endpointPinId = pcPin; + } + else + { + unsigned muxCount = 0; + int muxPos = 0; + /* Max 64 multiplexer inputs... sanity check :) */ + for (i = 0; i < 64; ++i) + { + ULONG muxNodeIdTest = (unsigned)-1; + PA_DEBUG(("PinNew: Checking for input endpoint pin id (%d)...\n", i)); + + endpointPinId = GetConnectedPin(pcPin, + FALSE, + pin->parentFilter->topologyFilter, + (int)i, + NULL, + &muxNodeIdTest); + + if (endpointPinId == KSFILTER_NODE) + { + /* We're done */ + PA_DEBUG(("PinNew: Done with inputs.\n", endpointPinId)); + break; + } + else + { + /* The "endpointPinId" is what WASAPI looks at for pin names */ + GUID category = {0}; + + PA_DEBUG(("PinNew: Found endpoint pin id %u\n", endpointPinId)); + + /* Get pin category information */ + result = WdmGetPinPropertySimple(pin->parentFilter->topologyFilter->handle, + endpointPinId, + &KSPROPSETID_Pin, + KSPROPERTY_PIN_CATEGORY, + &category, + sizeof(GUID), + NULL); + + if (result == paNoError) + { + if (muxNodeIdTest == (unsigned)-1) + { + /* Ok, try pin name, and favor that if available */ + result = WdmGetPinPropertySimple(pin->parentFilter->topologyFilter->handle, + endpointPinId, + &KSPROPSETID_Pin, + KSPROPERTY_PIN_NAME, + pin->friendlyName, + MAX_PATH, + NULL); + + if (result != paNoError) + { + result = GetNameFromCategory(&category, TRUE, pin->friendlyName, MAX_PATH); + } + break; + } + else + { + result = GetNameFromCategory(&category, TRUE, NULL, 0); + + if (result == paNoError) + { + ++muxCount; + } + } + } + else + { + PA_DEBUG(("PinNew: Failed to get pin category")); + } + } + } + + if (muxCount == 0) + { + pin->endpointPinId = endpointPinId; + /* Make sure we get a name for the pin */ + if (wcslen(pin->friendlyName) == 0) + { + wcscpy(pin->friendlyName, kInputName); + } +#ifdef UNICODE + PA_DEBUG(("PinNew: Input friendly name '%s'\n", pin->friendlyName)); +#else + PA_DEBUG(("PinNew: Input friendly name '%S'\n", pin->friendlyName)); +#endif + } + else // muxCount > 0 + { + PA_DEBUG(("PinNew: Setting up %u inputs\n", muxCount)); + + /* Now we redo the operation once known how many multiplexer positions there are */ + pin->inputs = (PaWinWdmMuxedInput**)PaUtil_AllocateMemory(muxCount * sizeof(PaWinWdmMuxedInput*)); + if (pin->inputs == NULL) + { + FilterRelease(pin->parentFilter->topologyFilter); + result = paInsufficientMemory; + goto error; + } + pin->inputCount = muxCount; + + for (i = 0; i < muxCount; ++muxPos) + { + PA_DEBUG(("PinNew: Setting up input %u...\n", i)); + + if (pin->inputs[i] == NULL) + { + pin->inputs[i] = (PaWinWdmMuxedInput*)PaUtil_AllocateMemory(sizeof(PaWinWdmMuxedInput)); + if (pin->inputs[i] == NULL) + { + FilterRelease(pin->parentFilter->topologyFilter); + result = paInsufficientMemory; + goto error; + } + } + + endpointPinId = GetConnectedPin(pcPin, + FALSE, + pin->parentFilter->topologyFilter, + muxPos, + &pin->inputs[i]->muxPinId, + &pin->inputs[i]->muxNodeId); + + if (endpointPinId != KSFILTER_NODE) + { + /* The "endpointPinId" is what WASAPI looks at for pin names */ + GUID category = {0}; + + /* Set input endpoint ID */ + pin->inputs[i]->endpointPinId = endpointPinId; + + /* Get pin category information */ + result = WdmGetPinPropertySimple(pin->parentFilter->topologyFilter->handle, + endpointPinId, + &KSPROPSETID_Pin, + KSPROPERTY_PIN_CATEGORY, + &category, + sizeof(GUID), + NULL); + + if (result == paNoError) + { + /* Try pin name first, and if that is not defined, use category instead */ + result = WdmGetPinPropertySimple(pin->parentFilter->topologyFilter->handle, + endpointPinId, + &KSPROPSETID_Pin, + KSPROPERTY_PIN_NAME, + pin->inputs[i]->friendlyName, + MAX_PATH, + NULL); + + if (result != paNoError) + { + result = GetNameFromCategory(&category, TRUE, pin->inputs[i]->friendlyName, MAX_PATH); + if (result != paNoError) + { + /* Only specify name, let name hash in ScanDeviceInfos fix postfix enumerators */ + wcscpy(pin->inputs[i]->friendlyName, kInputName); + } + } +#ifdef UNICODE + PA_DEBUG(("PinNew: Input (%u) friendly name '%s'\n", i, pin->inputs[i]->friendlyName)); +#else + PA_DEBUG(("PinNew: Input (%u) friendly name '%S'\n", i, pin->inputs[i]->friendlyName)); +#endif + ++i; + } + } + else + { + /* Should never come here! */ + assert(FALSE); + } + } + } + } + } + } + } + else + { + PA_DEBUG(("PinNew: No topology pin id found. Bad...\n")); + /* No TOPO pin id ??? This is bad. Ok, so we just say it is an input or output... */ + wcscpy(pin->friendlyName, (pin->dataFlow == KSPIN_DATAFLOW_IN) ? kOutputName : kInputName); + } + } + + /* Release topology filter if it has been used */ + if (pin->parentFilter->topologyFilter && pin->parentFilter->topologyFilter->handle != NULL) + { + PA_DEBUG(("PinNew: Releasing topology filter...\n")); + FilterRelease(pin->parentFilter->topologyFilter); + } + + /* Success */ + *error = paNoError; + PA_DEBUG(("Pin created successfully\n")); + PA_LOGL_; + return pin; + +error: + PA_DEBUG(("PinNew: Error %d\n", result)); + /* + Error cleanup + */ + + if (pin->parentFilter->topologyFilter && pin->parentFilter->topologyFilter->handle != NULL) + { + FilterRelease(pin->parentFilter->topologyFilter); + } + + PaUtil_FreeMemory( item ); + PinFree(pin); + + *error = result; + PA_LOGL_; + return NULL; +} + +/* +Safely free all resources associated with the pin +*/ +static void PinFree(PaWinWdmPin* pin) +{ + unsigned i; + PA_LOGE_; + if( pin ) + { + PinClose(pin); + if( pin->pinConnect ) + { + PaUtil_FreeMemory( pin->pinConnect ); + } + if( pin->dataRangesItem ) + { + PaUtil_FreeMemory( pin->dataRangesItem ); + } + if( pin->inputs ) + { + for (i = 0; i < pin->inputCount; ++i) + { + PaUtil_FreeMemory( pin->inputs[i] ); + } + PaUtil_FreeMemory( pin->inputs ); + } + PaUtil_FreeMemory( pin ); + } + PA_LOGL_; +} + +/* +If the pin handle is open, close it +*/ +static void PinClose(PaWinWdmPin* pin) +{ + PA_LOGE_; + if( pin == NULL ) + { + PA_DEBUG(("Closing NULL pin!")); + PA_LOGL_; + return; + } + if( pin->handle != NULL ) + { + PinSetState( pin, KSSTATE_PAUSE ); + PinSetState( pin, KSSTATE_STOP ); + CloseHandle( pin->handle ); + pin->handle = NULL; + FilterRelease(pin->parentFilter); + } + PA_LOGL_; +} + +/* +Set the state of this (instantiated) pin +*/ +static PaError PinSetState(PaWinWdmPin* pin, KSSTATE state) +{ + PaError result = paNoError; + KSPROPERTY prop; + + PA_LOGE_; + prop.Set = KSPROPSETID_Connection; + prop.Id = KSPROPERTY_CONNECTION_STATE; + prop.Flags = KSPROPERTY_TYPE_SET; + + if( pin == NULL ) + return paInternalError; + if( pin->handle == NULL ) + return paInternalError; + + result = WdmSyncIoctl(pin->handle, IOCTL_KS_PROPERTY, &prop, sizeof(KSPROPERTY), &state, sizeof(KSSTATE), NULL); + + PA_LOGL_; + return result; +} + +static PaError PinInstantiate(PaWinWdmPin* pin) +{ + PaError result; + unsigned long createResult; + KSALLOCATOR_FRAMING ksaf; + KSALLOCATOR_FRAMING_EX ksafex; + + PA_LOGE_; + + if( pin == NULL ) + return paInternalError; + if(!pin->pinConnect) + return paInternalError; + + FilterUse(pin->parentFilter); + + createResult = FunctionKsCreatePin( + pin->parentFilter->handle, + pin->pinConnect, + GENERIC_WRITE | GENERIC_READ, + &pin->handle + ); + + PA_DEBUG(("Pin create result = 0x%08x\n",createResult)); + if( createResult != ERROR_SUCCESS ) + { + FilterRelease(pin->parentFilter); + pin->handle = NULL; + switch (createResult) + { + case ERROR_INVALID_PARAMETER: + /* First case when pin actually don't support the format */ + return paSampleFormatNotSupported; + case ERROR_BAD_COMMAND: + /* Case when pin is occupied (by another application) */ + return paDeviceUnavailable; + default: + /* All other cases */ + return paInvalidDevice; + } + } + + if (pin->parentFilter->devInfo.streamingType == Type_kWaveCyclic) + { + /* Framing size query only valid for WaveCyclic devices */ + result = WdmGetPropertySimple( + pin->handle, + &KSPROPSETID_Connection, + KSPROPERTY_CONNECTION_ALLOCATORFRAMING, + &ksaf, + sizeof(ksaf)); + + if( result != paNoError ) + { + result = WdmGetPropertySimple( + pin->handle, + &KSPROPSETID_Connection, + KSPROPERTY_CONNECTION_ALLOCATORFRAMING_EX, + &ksafex, + sizeof(ksafex)); + if( result == paNoError ) + { + pin->frameSize = ksafex.FramingItem[0].FramingRange.Range.MinFrameSize; + } + } + else + { + pin->frameSize = ksaf.FrameSize; + } + } + + PA_LOGL_; + + return paNoError; +} + +static PaError PinSetFormat(PaWinWdmPin* pin, const WAVEFORMATEX* format) +{ + unsigned long size; + void* newConnect; + + PA_LOGE_; + + if( pin == NULL ) + return paInternalError; + if( format == NULL ) + return paInternalError; + + size = GetWfexSize(format) + sizeof(KSPIN_CONNECT) + sizeof(KSDATAFORMAT_WAVEFORMATEX) - sizeof(WAVEFORMATEX); + + if( pin->pinConnectSize != size ) + { + newConnect = PaUtil_AllocateMemory( size ); + if( newConnect == NULL ) + return paInsufficientMemory; + memcpy( newConnect, (void*)pin->pinConnect, min(pin->pinConnectSize,size) ); + PaUtil_FreeMemory( pin->pinConnect ); + pin->pinConnect = (KSPIN_CONNECT*)newConnect; + pin->pinConnectSize = size; + pin->ksDataFormatWfx = (KSDATAFORMAT_WAVEFORMATEX*)((KSPIN_CONNECT*)newConnect + 1); + pin->ksDataFormatWfx->DataFormat.FormatSize = size - sizeof(KSPIN_CONNECT); + } + + memcpy( (void*)&(pin->ksDataFormatWfx->WaveFormatEx), format, GetWfexSize(format) ); + pin->ksDataFormatWfx->DataFormat.SampleSize = (unsigned short)(format->nChannels * (format->wBitsPerSample / 8)); + + PA_LOGL_; + + return paNoError; +} + +static PaError PinIsFormatSupported(PaWinWdmPin* pin, const WAVEFORMATEX* format) +{ + KSDATARANGE_AUDIO* dataRange; + unsigned long count; + GUID guid = DYNAMIC_GUID( DEFINE_WAVEFORMATEX_GUID(format->wFormatTag) ); + PaError result = paInvalidDevice; + const WAVEFORMATEXTENSIBLE* pFormatExt = (format->wFormatTag == WAVE_FORMAT_EXTENSIBLE) ? (const WAVEFORMATEXTENSIBLE*)format : 0; + + PA_LOGE_; + + if( pFormatExt != 0 ) + { + guid = pFormatExt->SubFormat; + } + dataRange = (KSDATARANGE_AUDIO*)pin->dataRanges; + for(count = 0; + countdataRangesItem->Count; + count++, + dataRange = (KSDATARANGE_AUDIO*)( ((char*)dataRange) + dataRange->DataRange.FormatSize)) /* Need to update dataRange here, due to 'continue' !! */ + { + /* Check major format*/ + if (!(IsEqualGUID(&(dataRange->DataRange.MajorFormat), &KSDATAFORMAT_TYPE_AUDIO) || + IsEqualGUID(&(dataRange->DataRange.MajorFormat), &KSDATAFORMAT_TYPE_WILDCARD))) + { + continue; + } + + /* This is an audio or wildcard datarange... */ + if (! (IsEqualGUID(&(dataRange->DataRange.SubFormat), &KSDATAFORMAT_SUBTYPE_WILDCARD) || + IsEqualGUID(&(dataRange->DataRange.SubFormat), &KSDATAFORMAT_SUBTYPE_PCM) || + IsEqualGUID(&(dataRange->DataRange.SubFormat), &guid) )) + { + continue; + } + + /* Check specifier... */ + if (! (IsEqualGUID(&(dataRange->DataRange.Specifier), &KSDATAFORMAT_SPECIFIER_WILDCARD) || + IsEqualGUID(&(dataRange->DataRange.Specifier), &KSDATAFORMAT_SPECIFIER_WAVEFORMATEX)) ) + { + continue; + } + + PA_DEBUG(("Pin:%x, DataRange:%d\n",(void*)pin,count)); + PA_DEBUG(("\tFormatSize:%d, SampleSize:%d\n",dataRange->DataRange.FormatSize,dataRange->DataRange.SampleSize)); + PA_DEBUG(("\tMaxChannels:%d\n",dataRange->MaximumChannels)); + PA_DEBUG(("\tBits:%d-%d\n",dataRange->MinimumBitsPerSample,dataRange->MaximumBitsPerSample)); + PA_DEBUG(("\tSampleRate:%d-%d\n",dataRange->MinimumSampleFrequency,dataRange->MaximumSampleFrequency)); + + if( dataRange->MaximumChannels != (ULONG)-1 && + dataRange->MaximumChannels < format->nChannels ) + { + result = paInvalidChannelCount; + continue; + } + + if (pFormatExt != 0) + { + if (!IsBitsWithinRange(dataRange, pFormatExt->Samples.wValidBitsPerSample)) + { + result = paSampleFormatNotSupported; + continue; + } + } + else + { + if (!IsBitsWithinRange(dataRange, format->wBitsPerSample)) + { + result = paSampleFormatNotSupported; + continue; + } + } + + if (!IsFrequencyWithinRange(dataRange, format->nSamplesPerSec)) + { + result = paInvalidSampleRate; + continue; + } + + /* Success! */ + result = paNoError; + break; + } + + PA_LOGL_; + return result; +} + +static PaError PinQueryNotificationSupport(PaWinWdmPin* pPin, BOOL* pbResult) +{ + PaError result = paNoError; + KSPROPERTY propIn; + + PA_LOGE_; + + propIn.Set = KSPROPSETID_RtAudio; + propIn.Id = 8; /* = KSPROPERTY_RTAUDIO_QUERY_NOTIFICATION_SUPPORT */ + propIn.Flags = KSPROPERTY_TYPE_GET; + + result = WdmSyncIoctl(pPin->handle, IOCTL_KS_PROPERTY, + &propIn, + sizeof(KSPROPERTY), + pbResult, + sizeof(BOOL), + NULL); + + if (result != paNoError) + { + PA_DEBUG(("Failed PinQueryNotificationSupport\n")); + } + + PA_LOGL_; + return result; +} + +static PaError PinGetBufferWithNotification(PaWinWdmPin* pPin, void** pBuffer, DWORD* pRequestedBufSize, BOOL* pbCallMemBarrier) +{ + PaError result = paNoError; + KSRTAUDIO_BUFFER_PROPERTY_WITH_NOTIFICATION propIn; + KSRTAUDIO_BUFFER propOut; + + PA_LOGE_; + + propIn.BaseAddress = 0; + propIn.NotificationCount = 2; + propIn.RequestedBufferSize = *pRequestedBufSize; + propIn.Property.Set = KSPROPSETID_RtAudio; + propIn.Property.Id = KSPROPERTY_RTAUDIO_BUFFER_WITH_NOTIFICATION; + propIn.Property.Flags = KSPROPERTY_TYPE_GET; + + result = WdmSyncIoctl(pPin->handle, IOCTL_KS_PROPERTY, + &propIn, + sizeof(KSRTAUDIO_BUFFER_PROPERTY_WITH_NOTIFICATION), + &propOut, + sizeof(KSRTAUDIO_BUFFER), + NULL); + + if (result == paNoError) + { + *pBuffer = propOut.BufferAddress; + *pRequestedBufSize = propOut.ActualBufferSize; + *pbCallMemBarrier = propOut.CallMemoryBarrier; + } + else + { + PA_DEBUG(("Failed to get buffer with notification\n")); + } + + PA_LOGL_; + return result; +} + +static PaError PinGetBufferWithoutNotification(PaWinWdmPin* pPin, void** pBuffer, DWORD* pRequestedBufSize, BOOL* pbCallMemBarrier) +{ + PaError result = paNoError; + KSRTAUDIO_BUFFER_PROPERTY propIn; + KSRTAUDIO_BUFFER propOut; + + PA_LOGE_; + + propIn.BaseAddress = NULL; + propIn.RequestedBufferSize = *pRequestedBufSize; + propIn.Property.Set = KSPROPSETID_RtAudio; + propIn.Property.Id = KSPROPERTY_RTAUDIO_BUFFER; + propIn.Property.Flags = KSPROPERTY_TYPE_GET; + + result = WdmSyncIoctl(pPin->handle, IOCTL_KS_PROPERTY, + &propIn, + sizeof(KSRTAUDIO_BUFFER_PROPERTY), + &propOut, + sizeof(KSRTAUDIO_BUFFER), + NULL); + + if (result == paNoError) + { + *pBuffer = propOut.BufferAddress; + *pRequestedBufSize = propOut.ActualBufferSize; + *pbCallMemBarrier = propOut.CallMemoryBarrier; + } + else + { + PA_DEBUG(("Failed to get buffer without notification\n")); + } + + PA_LOGL_; + return result; +} + +/* greatest common divisor - PGCD in French */ +static unsigned long PaWinWDMGCD( unsigned long a, unsigned long b ) +{ + return (b==0) ? a : PaWinWDMGCD( b, a%b); +} + + +/* This function will handle getting the cyclic buffer from a WaveRT driver. Certain WaveRT drivers needs to have +requested buffer size on multiples of 128 bytes: + +*/ +static PaError PinGetBuffer(PaWinWdmPin* pPin, void** pBuffer, DWORD* pRequestedBufSize, BOOL* pbCallMemBarrier) +{ + PaError result = paNoError; + int limit = 1000; + PA_LOGE_; + + while (1) + { + limit--; + if (limit == 0) { + PA_DEBUG(("PinGetBuffer: LOOP LIMIT REACHED\n")); + break; + } + + if (pPin->pinKsSubType != SubType_kPolled) + { + /* In case of unknown (or notification), we try both modes */ + result = PinGetBufferWithNotification(pPin, pBuffer, pRequestedBufSize, pbCallMemBarrier); + if (result == paNoError) + { + PA_DEBUG(("PinGetBuffer: SubType_kNotification\n")); + pPin->pinKsSubType = SubType_kNotification; + break; + } + } + + result = PinGetBufferWithoutNotification(pPin, pBuffer, pRequestedBufSize, pbCallMemBarrier); + if (result == paNoError) + { + PA_DEBUG(("PinGetBuffer: SubType_kPolled\n")); + pPin->pinKsSubType = SubType_kPolled; + break; + } + + /* Check if requested size is on a 128 byte boundary */ + if (((*pRequestedBufSize) % 128UL) == 0) + { + PA_DEBUG(("Buffer size on 128 byte boundary, still fails :(\n")); + /* Ok, can't do much more */ + break; + } + else + { + /* Compute LCM so we know which sizes are on a 128 byte boundary */ + const unsigned gcd = PaWinWDMGCD(128UL, pPin->ksDataFormatWfx->WaveFormatEx.nBlockAlign); + const unsigned lcm = (128UL * pPin->ksDataFormatWfx->WaveFormatEx.nBlockAlign) / gcd; + DWORD dwOldSize = *pRequestedBufSize; + + /* Align size to (next larger) LCM byte boundary, and then we try again. Note that LCM is not necessarily a + power of 2. */ + *pRequestedBufSize = ((*pRequestedBufSize + lcm - 1) / lcm) * lcm; + + PA_DEBUG(("Adjusting buffer size from %u to %u bytes (128 byte boundary, LCM=%u)\n", dwOldSize, *pRequestedBufSize, lcm)); + } + } + + PA_LOGL_; + + return result; +} + +static PaError PinRegisterPositionRegister(PaWinWdmPin* pPin) +{ + PaError result = paNoError; + KSRTAUDIO_HWREGISTER_PROPERTY propIn; + KSRTAUDIO_HWREGISTER propOut; + + PA_LOGE_; + + propIn.BaseAddress = NULL; + propIn.Property.Set = KSPROPSETID_RtAudio; + propIn.Property.Id = KSPROPERTY_RTAUDIO_POSITIONREGISTER; + propIn.Property.Flags = KSPROPERTY_TYPE_SET; + + result = WdmSyncIoctl(pPin->handle, IOCTL_KS_PROPERTY, + &propIn, + sizeof(KSRTAUDIO_HWREGISTER_PROPERTY), + &propOut, + sizeof(KSRTAUDIO_HWREGISTER), + NULL); + + if (result == paNoError) + { + pPin->positionRegister = (ULONG*)propOut.Register; + } + else + { + PA_DEBUG(("Failed to register position register\n")); + } + + PA_LOGL_; + + return result; +} + +static PaError PinRegisterNotificationHandle(PaWinWdmPin* pPin, HANDLE handle) +{ + PaError result = paNoError; + KSRTAUDIO_NOTIFICATION_EVENT_PROPERTY prop; + + PA_LOGE_; + + prop.NotificationEvent = handle; + prop.Property.Set = KSPROPSETID_RtAudio; + prop.Property.Id = KSPROPERTY_RTAUDIO_REGISTER_NOTIFICATION_EVENT; + prop.Property.Flags = KSPROPERTY_TYPE_SET; + + result = WdmSyncIoctl(pPin->handle, + IOCTL_KS_PROPERTY, + &prop, + sizeof(KSRTAUDIO_NOTIFICATION_EVENT_PROPERTY), + &prop, + sizeof(KSRTAUDIO_NOTIFICATION_EVENT_PROPERTY), + NULL); + + if (result != paNoError) { + PA_DEBUG(("Failed to register notification handle 0x%08X\n", handle)); + } + + PA_LOGL_; + + return result; +} + +static PaError PinUnregisterNotificationHandle(PaWinWdmPin* pPin, HANDLE handle) +{ + PaError result = paNoError; + KSRTAUDIO_NOTIFICATION_EVENT_PROPERTY prop; + + PA_LOGE_; + + if (handle != NULL) + { + prop.NotificationEvent = handle; + prop.Property.Set = KSPROPSETID_RtAudio; + prop.Property.Id = KSPROPERTY_RTAUDIO_UNREGISTER_NOTIFICATION_EVENT; + prop.Property.Flags = KSPROPERTY_TYPE_SET; + + result = WdmSyncIoctl(pPin->handle, + IOCTL_KS_PROPERTY, + &prop, + sizeof(KSRTAUDIO_NOTIFICATION_EVENT_PROPERTY), + &prop, + sizeof(KSRTAUDIO_NOTIFICATION_EVENT_PROPERTY), + NULL); + + if (result != paNoError) { + PA_DEBUG(("Failed to unregister notification handle 0x%08X\n", handle)); + } + } + PA_LOGL_; + + return result; +} + +static PaError PinGetHwLatency(PaWinWdmPin* pPin, ULONG* pFifoSize, ULONG* pChipsetDelay, ULONG* pCodecDelay) +{ + PaError result = paNoError; + KSPROPERTY propIn; + KSRTAUDIO_HWLATENCY propOut; + + PA_LOGE_; + + propIn.Set = KSPROPSETID_RtAudio; + propIn.Id = KSPROPERTY_RTAUDIO_HWLATENCY; + propIn.Flags = KSPROPERTY_TYPE_GET; + + result = WdmSyncIoctl(pPin->handle, IOCTL_KS_PROPERTY, + &propIn, + sizeof(KSPROPERTY), + &propOut, + sizeof(KSRTAUDIO_HWLATENCY), + NULL); + + if (result == paNoError) + { + *pFifoSize = propOut.FifoSize; + *pChipsetDelay = propOut.ChipsetDelay; + *pCodecDelay = propOut.CodecDelay; + } + else + { + PA_DEBUG(("Failed to retrieve hardware FIFO size!\n")); + } + + PA_LOGL_; + + return result; +} + +/* This one is used for WaveRT */ +static PaError PinGetAudioPositionMemoryMapped(PaWinWdmPin* pPin, ULONG* pPosition) +{ + *pPosition = (*pPin->positionRegister); + return paNoError; +} + +/* This one also, but in case the driver hasn't implemented memory mapped access to the position register */ +static PaError PinGetAudioPositionViaIOCTLRead(PaWinWdmPin* pPin, ULONG* pPosition) +{ + PaError result = paNoError; + KSPROPERTY propIn; + KSAUDIO_POSITION propOut; + + PA_LOGE_; + + propIn.Set = KSPROPSETID_Audio; + propIn.Id = KSPROPERTY_AUDIO_POSITION; + propIn.Flags = KSPROPERTY_TYPE_GET; + + result = WdmSyncIoctl(pPin->handle, + IOCTL_KS_PROPERTY, + &propIn, sizeof(KSPROPERTY), + &propOut, sizeof(KSAUDIO_POSITION), + NULL); + + if (result == paNoError) + { + *pPosition = (ULONG)(propOut.PlayOffset); + } + else + { + PA_DEBUG(("Failed to get audio play position!\n")); + } + + PA_LOGL_; + + return result; + +} + +/* This one also, but in case the driver hasn't implemented memory mapped access to the position register */ +static PaError PinGetAudioPositionViaIOCTLWrite(PaWinWdmPin* pPin, ULONG* pPosition) +{ + PaError result = paNoError; + KSPROPERTY propIn; + KSAUDIO_POSITION propOut; + + PA_LOGE_; + + propIn.Set = KSPROPSETID_Audio; + propIn.Id = KSPROPERTY_AUDIO_POSITION; + propIn.Flags = KSPROPERTY_TYPE_GET; + + result = WdmSyncIoctl(pPin->handle, + IOCTL_KS_PROPERTY, + &propIn, sizeof(KSPROPERTY), + &propOut, sizeof(KSAUDIO_POSITION), + NULL); + + if (result == paNoError) + { + *pPosition = (ULONG)(propOut.WriteOffset); + } + else + { + PA_DEBUG(("Failed to get audio write position!\n")); + } + + PA_LOGL_; + + return result; + +} + +/***********************************************************************************************/ + +/** +* Create a new filter object. +*/ +static PaWinWdmFilter* FilterNew( PaWDMKSType type, DWORD devNode, const wchar_t* filterName, const wchar_t* friendlyName, PaError* error ) +{ + PaWinWdmFilter* filter = 0; + PaError result; + + /* Allocate the new filter object */ + filter = (PaWinWdmFilter*)PaUtil_AllocateMemory( sizeof(PaWinWdmFilter) ); + if( !filter ) + { + result = paInsufficientMemory; + goto error; + } + + PA_DEBUG(("FilterNew: Creating filter '%S'\n", friendlyName)); + + /* Set type flag */ + filter->devInfo.streamingType = type; + + /* Store device node */ + filter->deviceNode = devNode; + + /* Zero the filter object - done by AllocateMemory */ + /* memset( (void*)filter, 0, sizeof(PaWinWdmFilter) ); */ + + /* Copy the filter name */ + wcsncpy(filter->devInfo.filterPath, filterName, MAX_PATH); + + /* Copy the friendly name */ + wcsncpy(filter->friendlyName, friendlyName, MAX_PATH); + + PA_DEBUG(("FilterNew: Opening filter...\n", friendlyName)); + + /* Open the filter handle */ + result = FilterUse(filter); + if( result != paNoError ) + { + goto error; + } + + /* Get pin count */ + result = WdmGetPinPropertySimple + ( + filter->handle, + 0, + &KSPROPSETID_Pin, + KSPROPERTY_PIN_CTYPES, + &filter->pinCount, + sizeof(filter->pinCount), + NULL); + + if( result != paNoError) + { + goto error; + } + + /* Get connections & nodes for filter */ + result = WdmGetPropertyMulti( + filter->handle, + &KSPROPSETID_Topology, + KSPROPERTY_TOPOLOGY_CONNECTIONS, + &filter->connections); + + if( result != paNoError) + { + goto error; + } + + result = WdmGetPropertyMulti( + filter->handle, + &KSPROPSETID_Topology, + KSPROPERTY_TOPOLOGY_NODES, + &filter->nodes); + + if( result != paNoError) + { + goto error; + } + + /* For debugging purposes */ + DumpConnectionsAndNodes(filter); + + /* Get product GUID (it might not be supported) */ + { + KSCOMPONENTID compId; + if (WdmGetPropertySimple(filter->handle, &KSPROPSETID_General, KSPROPERTY_GENERAL_COMPONENTID, &compId, sizeof(KSCOMPONENTID)) == paNoError) + { + filter->devInfo.deviceProductGuid = compId.Product; + } + } + + /* This section is not executed for topology filters */ + if (type != Type_kNotUsed) + { + /* Initialize the pins */ + result = FilterInitializePins(filter); + + if( result != paNoError) + { + goto error; + } + } + + /* Close the filter handle for now + * It will be opened later when needed */ + FilterRelease(filter); + + *error = paNoError; + return filter; + +error: + PA_DEBUG(("FilterNew: Error %d\n", result)); + /* + Error cleanup + */ + FilterFree(filter); + + *error = result; + return NULL; +} + +/** +* Add reference to filter +*/ +static void FilterAddRef( PaWinWdmFilter* filter ) +{ + if (filter != 0) + { + filter->filterRefCount++; + } +} + + +/** +* Initialize the pins of the filter. This is separated from FilterNew because this might fail if there is another +* process using the pin(s). +*/ +PaError FilterInitializePins( PaWinWdmFilter* filter ) +{ + PaError result = paNoError; + int pinId; + + if (filter->devInfo.streamingType == Type_kNotUsed) + return paNoError; + + if (filter->pins != NULL) + return paNoError; + + /* Allocate pointer array to hold the pins */ + filter->pins = (PaWinWdmPin**)PaUtil_AllocateMemory( sizeof(PaWinWdmPin*) * filter->pinCount ); + if( !filter->pins ) + { + result = paInsufficientMemory; + goto error; + } + + /* Create all the pins we can */ + for(pinId = 0; pinId < filter->pinCount; pinId++) + { + /* Create the pin with this Id */ + PaWinWdmPin* newPin; + newPin = PinNew(filter, pinId, &result); + if( result == paInsufficientMemory ) + goto error; + if( newPin != NULL ) + { + filter->pins[pinId] = newPin; + ++filter->validPinCount; + } + } + + if (filter->validPinCount == 0) + { + result = paDeviceUnavailable; + goto error; + } + + return paNoError; + +error: + + if (filter->pins) + { + for (pinId = 0; pinId < filter->pinCount; ++pinId) + { + if (filter->pins[pinId]) + { + PinFree(filter->pins[pinId]); + filter->pins[pinId] = 0; + } + } + PaUtil_FreeMemory( filter->pins ); + filter->pins = 0; + } + + return result; +} + + +/** +* Free a previously created filter +*/ +static void FilterFree(PaWinWdmFilter* filter) +{ + PA_LOGL_; + if( filter ) + { + if (--filter->filterRefCount > 0) + { + /* Ok, a stream has a ref count to this filter */ + return; + } + + if ( filter->topologyFilter ) + { + FilterFree(filter->topologyFilter); + filter->topologyFilter = 0; + } + if ( filter->pins ) + { + int pinId; + for( pinId = 0; pinId < filter->pinCount; pinId++ ) + PinFree(filter->pins[pinId]); + PaUtil_FreeMemory( filter->pins ); + filter->pins = 0; + } + if( filter->connections ) + { + PaUtil_FreeMemory(filter->connections); + filter->connections = 0; + } + if( filter->nodes ) + { + PaUtil_FreeMemory(filter->nodes); + filter->nodes = 0; + } + if( filter->handle ) + CloseHandle( filter->handle ); + PaUtil_FreeMemory( filter ); + } + PA_LOGE_; +} + +/** +* Reopen the filter handle if necessary so it can be used +**/ +static PaError FilterUse(PaWinWdmFilter* filter) +{ + assert( filter ); + + PA_LOGE_; + if( filter->handle == NULL ) + { + /* Open the filter */ + filter->handle = CreateFileW( + filter->devInfo.filterPath, + GENERIC_READ | GENERIC_WRITE, + 0, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, + NULL); + + if( filter->handle == NULL ) + { + return paDeviceUnavailable; + } + } + filter->usageCount++; + PA_LOGL_; + return paNoError; +} + +/** +* Release the filter handle if nobody is using it +**/ +static void FilterRelease(PaWinWdmFilter* filter) +{ + assert( filter ); + assert( filter->usageCount > 0 ); + + PA_LOGE_; + /* Check first topology filter, if used */ + if (filter->topologyFilter != NULL && filter->topologyFilter->handle != NULL) + { + FilterRelease(filter->topologyFilter); + } + + filter->usageCount--; + if( filter->usageCount == 0 ) + { + if( filter->handle != NULL ) + { + CloseHandle( filter->handle ); + filter->handle = NULL; + } + } + PA_LOGL_; +} + +/** +* Create a render or playback pin using the supplied format +**/ +static PaWinWdmPin* FilterCreatePin(PaWinWdmFilter* filter, + int pinId, + const WAVEFORMATEX* wfex, + PaError* error) +{ + PaError result = paNoError; + PaWinWdmPin* pin = NULL; + assert( filter ); + assert( pinId < filter->pinCount ); + pin = filter->pins[pinId]; + assert( pin ); + result = PinSetFormat(pin,wfex); + if( result == paNoError ) + { + result = PinInstantiate(pin); + } + *error = result; + return result == paNoError ? pin : 0; +} + +static const wchar_t kUsbPrefix[] = L"\\\\?\\USB"; + +static BOOL IsUSBDevice(const wchar_t* devicePath) +{ + /* Alex Lessard pointed out that different devices might present the device path with + lower case letters. */ + return (_wcsnicmp(devicePath, kUsbPrefix, sizeof(kUsbPrefix)/sizeof(kUsbPrefix[0]) ) == 0); +} + +/* This should make it more language tolerant, I hope... */ +static const wchar_t kUsbNamePrefix[] = L"USB Audio"; + +static BOOL IsNameUSBAudioDevice(const wchar_t* friendlyName) +{ + return (_wcsnicmp(friendlyName, kUsbNamePrefix, sizeof(kUsbNamePrefix)/sizeof(kUsbNamePrefix[0])) == 0); +} + +typedef enum _tag_EAlias +{ + Alias_kRender = (1<<0), + Alias_kCapture = (1<<1), + Alias_kRealtime = (1<<2), +} EAlias; + +/* Trim whitespace from string */ +static void TrimString(wchar_t* str, size_t length) +{ + wchar_t* s = str; + wchar_t* e = 0; + + /* Find start of string */ + while (iswspace(*s)) ++s; + e=s+min(length,wcslen(s))-1; + + /* Find end of string */ + while(e>s && iswspace(*e)) --e; + ++e; + + length = e - s; + memmove(str, s, length * sizeof(wchar_t)); + str[length] = 0; +} + +/** +* Build the list of available filters +* Use the SetupDi API to enumerate all devices in the KSCATEGORY_AUDIO which +* have a KSCATEGORY_RENDER or KSCATEGORY_CAPTURE alias. For each of these +* devices initialise a PaWinWdmFilter structure by calling our NewFilter() +* function. We enumerate devices twice, once to count how many there are, +* and once to initialize the PaWinWdmFilter structures. +* +* Vista and later: Also check KSCATEGORY_REALTIME for WaveRT devices. +*/ +//PaError BuildFilterList( PaWinWdmHostApiRepresentation* wdmHostApi, int* noOfPaDevices ) +PaWinWdmFilter** BuildFilterList( int* pFilterCount, int* pNoOfPaDevices, PaError* pResult ) +{ + PaWinWdmFilter** ppFilters = NULL; + HDEVINFO handle = NULL; + int device; + int invalidDevices; + int slot; + SP_DEVICE_INTERFACE_DATA interfaceData; + SP_DEVICE_INTERFACE_DATA aliasData; + SP_DEVINFO_DATA devInfoData; + int noError; + const int sizeInterface = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA) + (MAX_PATH * sizeof(WCHAR)); + unsigned char interfaceDetailsArray[sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA) + (MAX_PATH * sizeof(WCHAR))]; + SP_DEVICE_INTERFACE_DETAIL_DATA_W* devInterfaceDetails = (SP_DEVICE_INTERFACE_DETAIL_DATA_W*)interfaceDetailsArray; + const GUID* category = (const GUID*)&KSCATEGORY_AUDIO; + const GUID* alias_render = (const GUID*)&KSCATEGORY_RENDER; + const GUID* alias_capture = (const GUID*)&KSCATEGORY_CAPTURE; + const GUID* category_realtime = (const GUID*)&KSCATEGORY_REALTIME; + DWORD aliasFlags; + PaWDMKSType streamingType; + int filterCount = 0; + int noOfPaDevices = 0; + + PA_LOGE_; + + assert(pFilterCount != NULL); + assert(pNoOfPaDevices != NULL); + assert(pResult != NULL); + + devInterfaceDetails->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W); + *pFilterCount = 0; + *pNoOfPaDevices = 0; + + /* Open a handle to search for devices (filters) */ + handle = SetupDiGetClassDevs(category,NULL,NULL,DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); + if( handle == INVALID_HANDLE_VALUE ) + { + *pResult = paUnanticipatedHostError; + return NULL; + } + PA_DEBUG(("Setup called\n")); + + /* First let's count the number of devices so we can allocate a list */ + invalidDevices = 0; + for( device = 0;;device++ ) + { + interfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); + interfaceData.Reserved = 0; + aliasData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); + aliasData.Reserved = 0; + noError = SetupDiEnumDeviceInterfaces(handle,NULL,category,device,&interfaceData); + PA_DEBUG(("Enum called\n")); + if( !noError ) + break; /* No more devices */ + + /* Check this one has the render or capture alias */ + aliasFlags = 0; + noError = SetupDiGetDeviceInterfaceAlias(handle,&interfaceData,alias_render,&aliasData); + PA_DEBUG(("noError = %d\n",noError)); + if(noError) + { + if(aliasData.Flags && (!(aliasData.Flags & SPINT_REMOVED))) + { + PA_DEBUG(("Device %d has render alias\n",device)); + aliasFlags |= Alias_kRender; /* Has render alias */ + } + else + { + PA_DEBUG(("Device %d has no render alias\n",device)); + } + } + noError = SetupDiGetDeviceInterfaceAlias(handle,&interfaceData,alias_capture,&aliasData); + if(noError) + { + if(aliasData.Flags && (!(aliasData.Flags & SPINT_REMOVED))) + { + PA_DEBUG(("Device %d has capture alias\n",device)); + aliasFlags |= Alias_kCapture; /* Has capture alias */ + } + else + { + PA_DEBUG(("Device %d has no capture alias\n",device)); + } + } + if(!aliasFlags) + invalidDevices++; /* This was not a valid capture or render audio device */ + } + /* Remember how many there are */ + filterCount = device-invalidDevices; + + PA_DEBUG(("Interfaces found: %d\n",device-invalidDevices)); + + /* Now allocate the list of pointers to devices */ + ppFilters = (PaWinWdmFilter**)PaUtil_AllocateMemory( sizeof(PaWinWdmFilter*) * filterCount); + if( ppFilters == 0 ) + { + if(handle != NULL) + SetupDiDestroyDeviceInfoList(handle); + *pResult = paInsufficientMemory; + return NULL; + } + + /* Now create filter objects for each interface found */ + slot = 0; + for( device = 0;;device++ ) + { + interfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); + interfaceData.Reserved = 0; + aliasData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); + aliasData.Reserved = 0; + devInfoData.cbSize = sizeof(SP_DEVINFO_DATA); + devInfoData.Reserved = 0; + streamingType = Type_kWaveCyclic; + + noError = SetupDiEnumDeviceInterfaces(handle,NULL,category,device,&interfaceData); + if( !noError ) + break; /* No more devices */ + + /* Check this one has the render or capture alias */ + aliasFlags = 0; + noError = SetupDiGetDeviceInterfaceAlias(handle,&interfaceData,alias_render,&aliasData); + if(noError) + { + if(aliasData.Flags && (!(aliasData.Flags & SPINT_REMOVED))) + { + PA_DEBUG(("Device %d has render alias\n",device)); + aliasFlags |= Alias_kRender; /* Has render alias */ + } + } + noError = SetupDiGetDeviceInterfaceAlias(handle,&interfaceData,alias_capture,&aliasData); + if(noError) + { + if(aliasData.Flags && (!(aliasData.Flags & SPINT_REMOVED))) + { + PA_DEBUG(("Device %d has capture alias\n",device)); + aliasFlags |= Alias_kCapture; /* Has capture alias */ + } + } + if(!aliasFlags) + { + continue; /* This was not a valid capture or render audio device */ + } + else + { + /* Check if filter is WaveRT, if not it is a WaveCyclic */ + noError = SetupDiGetDeviceInterfaceAlias(handle,&interfaceData,category_realtime,&aliasData); + if (noError) + { + PA_DEBUG(("Device %d has realtime alias\n",device)); + aliasFlags |= Alias_kRealtime; + streamingType = Type_kWaveRT; + } + } + + noError = SetupDiGetDeviceInterfaceDetailW(handle,&interfaceData,devInterfaceDetails,sizeInterface,NULL,&devInfoData); + if( noError ) + { + DWORD type; + WCHAR friendlyName[MAX_PATH] = {0}; + DWORD sizeFriendlyName; + PaWinWdmFilter* newFilter = 0; + + PaError result = paNoError; + /* Try to get the "friendly name" for this interface */ + sizeFriendlyName = sizeof(friendlyName); + + if (IsEarlierThanVista() && IsUSBDevice(devInterfaceDetails->DevicePath)) + { + /* XP and USB audio device needs to look elsewhere, otherwise it'll only be a "USB Audio Device". Not + very literate. */ + if (!SetupDiGetDeviceRegistryPropertyW(handle, + &devInfoData, + SPDRP_LOCATION_INFORMATION, + &type, + (BYTE*)friendlyName, + sizeof(friendlyName), + NULL)) + { + friendlyName[0] = 0; + } + } + + if (friendlyName[0] == 0 || IsNameUSBAudioDevice(friendlyName)) + { + /* Fix contributed by Ben Allison + * Removed KEY_SET_VALUE from flags on following call + * as its causes failure when running without admin rights + * and it was not required */ + HKEY hkey=SetupDiOpenDeviceInterfaceRegKey(handle,&interfaceData,0,KEY_QUERY_VALUE); + if(hkey!=INVALID_HANDLE_VALUE) + { + noError = RegQueryValueExW(hkey,L"FriendlyName",0,&type,(BYTE*)friendlyName,&sizeFriendlyName); + if( noError == ERROR_SUCCESS ) + { + PA_DEBUG(("Interface %d, Name: %s\n",device,friendlyName)); + RegCloseKey(hkey); + } + else + { + friendlyName[0] = 0; + } + } + } + + TrimString(friendlyName, sizeFriendlyName); + + newFilter = FilterNew(streamingType, + devInfoData.DevInst, + devInterfaceDetails->DevicePath, + friendlyName, + &result); + + if( result == paNoError ) + { + int pin; + unsigned filterIOs = 0; + + /* Increment number of "devices" */ + for (pin = 0; pin < newFilter->pinCount; ++pin) + { + PaWinWdmPin* pPin = newFilter->pins[pin]; + if (pPin == NULL) + continue; + + filterIOs += max(1, pPin->inputCount); + } + + noOfPaDevices += filterIOs; + + PA_DEBUG(("Filter (%s) created with %d valid pins (total I/Os: %u)\n", ((newFilter->devInfo.streamingType==Type_kWaveRT)?"WaveRT":"WaveCyclic"), newFilter->validPinCount, filterIOs)); + + assert(slot < filterCount); + + ppFilters[slot] = newFilter; + + slot++; + } + else + { + PA_DEBUG(("Filter NOT created\n")); + /* As there are now less filters than we initially thought + * we must reduce the count by one */ + filterCount--; + } + } + } + + /* Clean up */ + if(handle != NULL) + SetupDiDestroyDeviceInfoList(handle); + + *pFilterCount = filterCount; + *pNoOfPaDevices = noOfPaDevices; + + return ppFilters; +} + +typedef struct PaNameHashIndex +{ + unsigned index; + unsigned count; + ULONG hash; + struct PaNameHashIndex *next; +} PaNameHashIndex; + +typedef struct PaNameHashObject +{ + PaNameHashIndex* list; + PaUtilAllocationGroup* allocGroup; +} PaNameHashObject; + +static ULONG GetNameHash(const wchar_t* str, const BOOL input) +{ + /* This is to make sure that a name that exists as both input & output won't get the same hash value */ + const ULONG fnv_prime = (input ? 0x811C9DD7 : 0x811FEB0B); + ULONG hash = 0; + for(; *str != 0; str++) + { + hash *= fnv_prime; + hash ^= (*str); + } + assert(hash != 0); + return hash; +} + +static PaError CreateHashEntry(PaNameHashObject* obj, const wchar_t* name, const BOOL input) +{ + ULONG hash = GetNameHash(name, input); + PaNameHashIndex * pLast = NULL; + PaNameHashIndex * p = obj->list; + while (p != 0) + { + if (p->hash == hash) + { + break; + } + pLast = p; + p = p->next; + } + if (p == NULL) + { + p = (PaNameHashIndex*)PaUtil_GroupAllocateMemory(obj->allocGroup, sizeof(PaNameHashIndex)); + if (p == NULL) + { + return paInsufficientMemory; + } + p->hash = hash; + p->count = 1; + if (pLast != 0) + { + assert(pLast->next == 0); + pLast->next = p; + } + if (obj->list == 0) + { + obj->list = p; + } + } + else + { + ++p->count; + } + return paNoError; +} + +static PaError InitNameHashObject(PaNameHashObject* obj, PaWinWdmFilter* pFilter) +{ + int i; + + obj->allocGroup = PaUtil_CreateAllocationGroup(); + if (obj->allocGroup == NULL) + { + return paInsufficientMemory; + } + + for (i = 0; i < pFilter->pinCount; ++i) + { + unsigned m; + PaWinWdmPin* pin = pFilter->pins[i]; + + if (pin == NULL) + continue; + + for (m = 0; m < max(1, pin->inputCount); ++m) + { + const BOOL isInput = (pin->dataFlow == KSPIN_DATAFLOW_OUT); + const wchar_t* name = (pin->inputs == NULL) ? pin->friendlyName : pin->inputs[m]->friendlyName; + + PaError result = CreateHashEntry(obj, name, isInput); + + if (result != paNoError) + { + return result; + } + } + } + return paNoError; +} + +static void DeinitNameHashObject(PaNameHashObject* obj) +{ + assert(obj != 0); + PaUtil_FreeAllAllocations(obj->allocGroup); + PaUtil_DestroyAllocationGroup(obj->allocGroup); + memset(obj, 0, sizeof(PaNameHashObject)); +} + +static unsigned GetNameIndex(PaNameHashObject* obj, const wchar_t* name, const BOOL input) +{ + ULONG hash = GetNameHash(name, input); + PaNameHashIndex* p = obj->list; + while (p != NULL) + { + if (p->hash == hash) + { + if (p->count > 1) + { + return (++p->index); + } + else + { + return 0; + } + } + + p = p->next; + } + // Should never get here!! + assert(FALSE); + return 0; +} + +static PaError ScanDeviceInfos( struct PaUtilHostApiRepresentation *hostApi, PaHostApiIndex hostApiIndex, void **scanResults, int *newDeviceCount ) +{ + PaWinWdmHostApiRepresentation *wdmHostApi = (PaWinWdmHostApiRepresentation*)hostApi; + PaError result = paNoError; + PaWinWdmFilter** ppFilters = 0; + PaWinWDMScanDeviceInfosResults *outArgument = 0; + int filterCount = 0; + int totalDeviceCount = 0; + int idxDevice = 0; + DWORD defaultInDevPathSize = 0; + DWORD defaultOutDevPathSize = 0; + wchar_t* defaultInDevPath = 0; + wchar_t* defaultOutDevPath = 0; + + ppFilters = BuildFilterList( &filterCount, &totalDeviceCount, &result ); + if( result != paNoError ) + { + goto error; + } + + // Get hold of default device paths for capture & playback + if( waveInMessage(0, DRV_QUERYDEVICEINTERFACESIZE, (DWORD_PTR)&defaultInDevPathSize, 0 ) == MMSYSERR_NOERROR ) + { + defaultInDevPath = (wchar_t *)PaUtil_AllocateMemory((defaultInDevPathSize + 1) * sizeof(wchar_t)); + waveInMessage(0, DRV_QUERYDEVICEINTERFACE, (DWORD_PTR)defaultInDevPath, defaultInDevPathSize); + } + if( waveOutMessage(0, DRV_QUERYDEVICEINTERFACESIZE, (DWORD_PTR)&defaultOutDevPathSize, 0 ) == MMSYSERR_NOERROR ) + { + defaultOutDevPath = (wchar_t *)PaUtil_AllocateMemory((defaultOutDevPathSize + 1) * sizeof(wchar_t)); + waveOutMessage(0, DRV_QUERYDEVICEINTERFACE, (DWORD_PTR)defaultOutDevPath, defaultOutDevPathSize); + } + + if( totalDeviceCount > 0 ) + { + PaWinWdmDeviceInfo *deviceInfoArray = 0; + int idxFilter; + int i; + unsigned devIsDefaultIn = 0, devIsDefaultOut = 0; + + /* Allocate the out param for all the info we need */ + outArgument = (PaWinWDMScanDeviceInfosResults *) PaUtil_GroupAllocateMemory( + wdmHostApi->allocations, sizeof(PaWinWDMScanDeviceInfosResults) ); + if( !outArgument ) + { + result = paInsufficientMemory; + goto error; + } + + outArgument->defaultInputDevice = paNoDevice; + outArgument->defaultOutputDevice = paNoDevice; + + outArgument->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory( + wdmHostApi->allocations, sizeof(PaDeviceInfo*) * totalDeviceCount ); + if( !outArgument->deviceInfos ) + { + result = paInsufficientMemory; + goto error; + } + + /* allocate all device info structs in a contiguous block */ + deviceInfoArray = (PaWinWdmDeviceInfo*)PaUtil_GroupAllocateMemory( + wdmHostApi->allocations, sizeof(PaWinWdmDeviceInfo) * totalDeviceCount ); + if( !deviceInfoArray ) + { + result = paInsufficientMemory; + goto error; + } + + /* Make sure all items in array */ + for( i = 0 ; i < totalDeviceCount; ++i ) + { + PaDeviceInfo *deviceInfo = &deviceInfoArray[i].inheritedDeviceInfo; + deviceInfo->structVersion = 2; + deviceInfo->hostApi = hostApiIndex; + deviceInfo->name = 0; + outArgument->deviceInfos[ i ] = deviceInfo; + } + + idxDevice = 0; + for (idxFilter = 0; idxFilter < filterCount; ++idxFilter) + { + PaNameHashObject nameHash = {0}; + PaWinWdmFilter* pFilter = ppFilters[idxFilter]; + if( pFilter == NULL ) + continue; + + if (InitNameHashObject(&nameHash, pFilter) != paNoError) + { + DeinitNameHashObject(&nameHash); + continue; + } + + devIsDefaultIn = (defaultInDevPath && (_wcsicmp(pFilter->devInfo.filterPath, defaultInDevPath) == 0)); + devIsDefaultOut = (defaultOutDevPath && (_wcsicmp(pFilter->devInfo.filterPath, defaultOutDevPath) == 0)); + + for (i = 0; i < pFilter->pinCount; ++i) + { + unsigned m; + ULONG nameIndex = 0; + ULONG nameIndexHash = 0; + PaWinWdmPin* pin = pFilter->pins[i]; + + if (pin == NULL) + continue; + + for (m = 0; m < max(1, pin->inputCount); ++m) + { + PaWinWdmDeviceInfo *wdmDeviceInfo = (PaWinWdmDeviceInfo *)outArgument->deviceInfos[idxDevice]; + PaDeviceInfo *deviceInfo = &wdmDeviceInfo->inheritedDeviceInfo; + wchar_t localCompositeName[MAX_PATH]; + unsigned nameIndex = 0; + const BOOL isInput = (pin->dataFlow == KSPIN_DATAFLOW_OUT); + + wdmDeviceInfo->filter = pFilter; + + deviceInfo->structVersion = 2; + deviceInfo->hostApi = hostApiIndex; + deviceInfo->name = wdmDeviceInfo->compositeName; + /* deviceInfo->hostApiSpecificDeviceInfo = &pFilter->devInfo; */ + + wdmDeviceInfo->pin = pin->pinId; + + /* Get the name of the "device" */ + if (pin->inputs == NULL) + { + wcsncpy(localCompositeName, pin->friendlyName, MAX_PATH); + wdmDeviceInfo->muxPosition = -1; + wdmDeviceInfo->endpointPinId = pin->endpointPinId; + } + else + { + PaWinWdmMuxedInput* input = pin->inputs[m]; + wcsncpy(localCompositeName, input->friendlyName, MAX_PATH); + wdmDeviceInfo->muxPosition = (int)m; + wdmDeviceInfo->endpointPinId = input->endpointPinId; + } + + { + /* Get base length */ + size_t n = wcslen(localCompositeName); + + /* Check if there are more entries with same name (which might very well be the case), if there + are, the name will be postfixed with an index. */ + nameIndex = GetNameIndex(&nameHash, localCompositeName, isInput); + if (nameIndex > 0) + { + /* This name has multiple instances, so we post fix with a number */ + n += _snwprintf(localCompositeName + n, MAX_PATH - n, L" %u", nameIndex); + } + /* Postfix with filter name */ + _snwprintf(localCompositeName + n, MAX_PATH - n, L" (%s)", pFilter->friendlyName); + } + + /* Convert wide char string to utf-8 */ + WideCharToMultiByte(CP_UTF8, 0, localCompositeName, -1, wdmDeviceInfo->compositeName, MAX_PATH, NULL, NULL); + + /* NB! WDM/KS has no concept of a full-duplex device, each pin is either an input or an output */ + if (isInput) + { + /* INPUT ! */ + deviceInfo->maxInputChannels = pin->maxChannels; + deviceInfo->maxOutputChannels = 0; + + /* RoBi NB: Due to the fact that input audio endpoints in Vista (& later OSs) can be the same device, but with + different input mux settings, there might be a discrepancy between the default input device chosen, and + that which will be used by Portaudio. Not much to do about that unfortunately. + */ + if ((defaultInDevPath == 0 || devIsDefaultIn) && + outArgument->defaultInputDevice == paNoDevice) + { + outArgument->defaultInputDevice = idxDevice; + } + } + else + { + /* OUTPUT ! */ + deviceInfo->maxInputChannels = 0; + deviceInfo->maxOutputChannels = pin->maxChannels; + + if ((defaultOutDevPath == 0 || devIsDefaultOut) && + outArgument->defaultOutputDevice == paNoDevice) + { + outArgument->defaultOutputDevice = idxDevice; + } + } + + /* These low values are not very useful because + * a) The lowest latency we end up with can depend on many factors such + * as the device buffer sizes/granularities, sample rate, channels and format + * b) We cannot know the device buffer sizes until we try to open/use it at + * a particular setting + * So: we give 512x48000Hz frames as the default low input latency + **/ + switch (pFilter->devInfo.streamingType) + { + case Type_kWaveCyclic: + if (IsEarlierThanVista()) + { + /* XP doesn't tolerate low latency, unless the Process Priority Class is set to REALTIME_PRIORITY_CLASS + through SetPriorityClass, then 10 ms is quite feasible. However, one should then bear in mind that ALL of + the process is running in REALTIME_PRIORITY_CLASS, which might not be appropriate for an application with + a GUI . In this case it is advisable to separate the audio engine in another process and use IPC to communicate + with it. */ + deviceInfo->defaultLowInputLatency = 0.02; + deviceInfo->defaultLowOutputLatency = 0.02; + } + else + { + /* This is a conservative estimate. Most WaveCyclic drivers will limit the available latency, but f.i. my Edirol + PCR-A30 can reach 3 ms latency easily... */ + deviceInfo->defaultLowInputLatency = 0.01; + deviceInfo->defaultLowOutputLatency = 0.01; + } + deviceInfo->defaultHighInputLatency = (4096.0/48000.0); + deviceInfo->defaultHighOutputLatency = (4096.0/48000.0); + deviceInfo->defaultSampleRate = (double)(pin->defaultSampleRate); + break; + case Type_kWaveRT: + /* This is also a conservative estimate, based on WaveRT polled mode. In polled mode, the latency will be dictated + by the buffer size given by the driver. */ + deviceInfo->defaultLowInputLatency = 0.01; + deviceInfo->defaultLowOutputLatency = 0.01; + deviceInfo->defaultHighInputLatency = 0.04; + deviceInfo->defaultHighOutputLatency = 0.04; + deviceInfo->defaultSampleRate = (double)(pin->defaultSampleRate); + break; + default: + assert(0); + break; + } + + /* Add reference to filter */ + FilterAddRef(wdmDeviceInfo->filter); + + assert(idxDevice < totalDeviceCount); + ++idxDevice; + } + } + + /* If no one has add ref'd the filter, drop it */ + if (pFilter->filterRefCount == 0) + { + FilterFree(pFilter); + } + + /* Deinitialize name hash object */ + DeinitNameHashObject(&nameHash); + } + } + + *scanResults = outArgument; + *newDeviceCount = idxDevice; + return result; + +error: + result = DisposeDeviceInfos(hostApi, outArgument, totalDeviceCount); + + return result; +} + +static PaError CommitDeviceInfos( struct PaUtilHostApiRepresentation *hostApi, PaHostApiIndex index, void *scanResults, int deviceCount ) +{ + PaWinWdmHostApiRepresentation *wdmHostApi = (PaWinWdmHostApiRepresentation*)hostApi; + + hostApi->info.deviceCount = 0; + hostApi->info.defaultInputDevice = paNoDevice; + hostApi->info.defaultOutputDevice = paNoDevice; + + /* Free any old memory which might be in the device info */ + if( hostApi->deviceInfos ) + { + PaWinWDMScanDeviceInfosResults* localScanResults = (PaWinWDMScanDeviceInfosResults*)PaUtil_GroupAllocateMemory( + wdmHostApi->allocations, sizeof(PaWinWDMScanDeviceInfosResults)); + localScanResults->deviceInfos = hostApi->deviceInfos; + + DisposeDeviceInfos(hostApi, &localScanResults, hostApi->info.deviceCount); + + hostApi->deviceInfos = NULL; + } + + if( scanResults != NULL ) + { + PaWinWDMScanDeviceInfosResults *scanDeviceInfosResults = ( PaWinWDMScanDeviceInfosResults * ) scanResults; + + if( deviceCount > 0 ) + { + /* use the array allocated in ScanDeviceInfos() as our deviceInfos */ + hostApi->deviceInfos = scanDeviceInfosResults->deviceInfos; + + hostApi->info.defaultInputDevice = scanDeviceInfosResults->defaultInputDevice; + hostApi->info.defaultOutputDevice = scanDeviceInfosResults->defaultOutputDevice; + + hostApi->info.deviceCount = deviceCount; + } + + PaUtil_GroupFreeMemory( wdmHostApi->allocations, scanDeviceInfosResults ); + } + + return paNoError; + +} + +static PaError DisposeDeviceInfos( struct PaUtilHostApiRepresentation *hostApi, void *scanResults, int deviceCount ) +{ + PaWinWdmHostApiRepresentation *winDsHostApi = (PaWinWdmHostApiRepresentation*)hostApi; + + if( scanResults != NULL ) + { + PaWinWDMScanDeviceInfosResults *scanDeviceInfosResults = ( PaWinWDMScanDeviceInfosResults * ) scanResults; + + if( scanDeviceInfosResults->deviceInfos ) + { + int i; + for (i = 0; i < deviceCount; ++i) + { + PaWinWdmDeviceInfo* pDevice = (PaWinWdmDeviceInfo*)scanDeviceInfosResults->deviceInfos[i]; + if (pDevice->filter != 0) + { + FilterFree(pDevice->filter); + } + } + + PaUtil_GroupFreeMemory( winDsHostApi->allocations, scanDeviceInfosResults->deviceInfos[0] ); /* all device info structs are allocated in a block so we can destroy them here */ + PaUtil_GroupFreeMemory( winDsHostApi->allocations, scanDeviceInfosResults->deviceInfos ); + } + + PaUtil_GroupFreeMemory( winDsHostApi->allocations, scanDeviceInfosResults ); + } + + return paNoError; + +} + +PaError PaWinWdm_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex ) +{ + PaError result = paNoError; + int deviceCount = 0; + void *scanResults = 0; + PaWinWdmHostApiRepresentation *wdmHostApi = NULL; + + PA_LOGE_; + +#ifdef PA_WDMKS_SET_TREF + tRef = PaUtil_GetTime(); +#endif + + /* + Attempt to load the KSUSER.DLL without which we cannot create pins + We will unload this on termination + */ + if(DllKsUser == NULL) + { + DllKsUser = LoadLibrary(TEXT("ksuser.dll")); + if(DllKsUser == NULL) + goto error; + } + FunctionKsCreatePin = (KSCREATEPIN*)GetProcAddress(DllKsUser, "KsCreatePin"); + if(FunctionKsCreatePin == NULL) + goto error; + + /* Attempt to load AVRT.DLL, if we can't, then we'll just use time critical prio instead... */ + if(paWinWDMKSAvRtEntryPoints.hInstance == NULL) + { + paWinWDMKSAvRtEntryPoints.hInstance = LoadLibrary(TEXT("avrt.dll")); + if (paWinWDMKSAvRtEntryPoints.hInstance != NULL) + { + paWinWDMKSAvRtEntryPoints.AvSetMmThreadCharacteristics = + (HANDLE(WINAPI*)(LPCSTR,LPDWORD))GetProcAddress(paWinWDMKSAvRtEntryPoints.hInstance,"AvSetMmThreadCharacteristicsA"); + paWinWDMKSAvRtEntryPoints.AvRevertMmThreadCharacteristics = + (BOOL(WINAPI*)(HANDLE))GetProcAddress(paWinWDMKSAvRtEntryPoints.hInstance, "AvRevertMmThreadCharacteristics"); + paWinWDMKSAvRtEntryPoints.AvSetMmThreadPriority = + (BOOL(WINAPI*)(HANDLE,PA_AVRT_PRIORITY))GetProcAddress(paWinWDMKSAvRtEntryPoints.hInstance, "AvSetMmThreadPriority"); + } + } + + wdmHostApi = (PaWinWdmHostApiRepresentation*)PaUtil_AllocateMemory( sizeof(PaWinWdmHostApiRepresentation) ); + if( !wdmHostApi ) + { + result = paInsufficientMemory; + goto error; + } + + wdmHostApi->allocations = PaUtil_CreateAllocationGroup(); + if( !wdmHostApi->allocations ) + { + result = paInsufficientMemory; + goto error; + } + + *hostApi = &wdmHostApi->inheritedHostApiRep; + (*hostApi)->info.structVersion = 1; + (*hostApi)->info.type = paWDMKS; + (*hostApi)->info.name = "Windows WDM-KS"; + + /* these are all updated by CommitDeviceInfos() */ + (*hostApi)->info.deviceCount = 0; + (*hostApi)->info.defaultInputDevice = paNoDevice; + (*hostApi)->info.defaultOutputDevice = paNoDevice; + (*hostApi)->deviceInfos = 0; + + result = ScanDeviceInfos(&wdmHostApi->inheritedHostApiRep, hostApiIndex, &scanResults, &deviceCount); + if (result != paNoError) + { + goto error; + } + + CommitDeviceInfos(&wdmHostApi->inheritedHostApiRep, hostApiIndex, scanResults, deviceCount); + + (*hostApi)->Terminate = Terminate; + (*hostApi)->OpenStream = OpenStream; + (*hostApi)->IsFormatSupported = IsFormatSupported; + /* In preparation for hotplug + (*hostApi)->ScanDeviceInfos = ScanDeviceInfos; + (*hostApi)->CommitDeviceInfos = CommitDeviceInfos; + (*hostApi)->DisposeDeviceInfos = DisposeDeviceInfos; + */ + PaUtil_InitializeStreamInterface( &wdmHostApi->callbackStreamInterface, CloseStream, StartStream, + StopStream, AbortStream, IsStreamStopped, IsStreamActive, + GetStreamTime, GetStreamCpuLoad, + PaUtil_DummyRead, PaUtil_DummyWrite, + PaUtil_DummyGetReadAvailable, PaUtil_DummyGetWriteAvailable ); + + PaUtil_InitializeStreamInterface( &wdmHostApi->blockingStreamInterface, CloseStream, StartStream, + StopStream, AbortStream, IsStreamStopped, IsStreamActive, + GetStreamTime, PaUtil_DummyGetCpuLoad, + ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable ); + + PA_LOGL_; + return result; + +error: + Terminate( (PaUtilHostApiRepresentation*)wdmHostApi ); + + PA_LOGL_; + return result; +} + + +static void Terminate( struct PaUtilHostApiRepresentation *hostApi ) +{ + PaWinWdmHostApiRepresentation *wdmHostApi = (PaWinWdmHostApiRepresentation*)hostApi; + PA_LOGE_; + + /* Do not unload the libraries */ + if( DllKsUser != NULL ) + { + FreeLibrary( DllKsUser ); + DllKsUser = NULL; + } + + if( paWinWDMKSAvRtEntryPoints.hInstance != NULL ) + { + FreeLibrary( paWinWDMKSAvRtEntryPoints.hInstance ); + paWinWDMKSAvRtEntryPoints.hInstance = NULL; + } + + if( wdmHostApi) + { + PaWinWDMScanDeviceInfosResults* localScanResults = (PaWinWDMScanDeviceInfosResults*)PaUtil_GroupAllocateMemory( + wdmHostApi->allocations, sizeof(PaWinWDMScanDeviceInfosResults)); + localScanResults->deviceInfos = hostApi->deviceInfos; + DisposeDeviceInfos(hostApi, localScanResults, hostApi->info.deviceCount); + + if( wdmHostApi->allocations ) + { + PaUtil_FreeAllAllocations( wdmHostApi->allocations ); + PaUtil_DestroyAllocationGroup( wdmHostApi->allocations ); + } + PaUtil_FreeMemory( wdmHostApi ); + } + PA_LOGL_; +} + +static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi, + const PaStreamParameters *inputParameters, + const PaStreamParameters *outputParameters, + double sampleRate ) +{ + int inputChannelCount, outputChannelCount; + PaSampleFormat inputSampleFormat, outputSampleFormat; + PaWinWdmHostApiRepresentation *wdmHostApi = (PaWinWdmHostApiRepresentation*)hostApi; + PaWinWdmFilter* pFilter; + int result = paFormatIsSupported; + WAVEFORMATEXTENSIBLE wfx; + PaWinWaveFormatChannelMask channelMask; + + PA_LOGE_; + + if( inputParameters ) + { + PaWinWdmDeviceInfo* pDeviceInfo = (PaWinWdmDeviceInfo*)wdmHostApi->inheritedHostApiRep.deviceInfos[inputParameters->device]; + PaWinWdmPin* pin; + unsigned fmt; + unsigned long testFormat = 0; + unsigned validBits = 0; + + inputChannelCount = inputParameters->channelCount; + inputSampleFormat = inputParameters->sampleFormat; + + /* all standard sample formats are supported by the buffer adapter, + this implementation doesn't support any custom sample formats */ + if( inputSampleFormat & paCustomFormat ) + { + PaWinWDM_SetLastErrorInfo(paSampleFormatNotSupported, "IsFormatSupported: Custom input format not supported"); + return paSampleFormatNotSupported; + } + + /* unless alternate device specification is supported, reject the use of + paUseHostApiSpecificDeviceSpecification */ + + if( inputParameters->device == paUseHostApiSpecificDeviceSpecification ) + { + PaWinWDM_SetLastErrorInfo(paInvalidDevice, "IsFormatSupported: paUseHostApiSpecificDeviceSpecification not supported"); + return paInvalidDevice; + } + + /* check that input device can support inputChannelCount */ + if( inputChannelCount > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels ) + { + PaWinWDM_SetLastErrorInfo(paInvalidChannelCount, "IsFormatSupported: Invalid input channel count"); + return paInvalidChannelCount; + } + + /* validate inputStreamInfo */ + if( inputParameters->hostApiSpecificStreamInfo ) + { + PaWinWDM_SetLastErrorInfo(paIncompatibleHostApiSpecificStreamInfo, "Host API stream info not supported"); + return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */ + } + + pFilter = pDeviceInfo->filter; + pin = pFilter->pins[pDeviceInfo->pin]; + + /* Find out the testing format */ + for (fmt = paFloat32; fmt <= paUInt8; fmt <<= 1) + { + if ((fmt & pin->formats) != 0) + { + /* Found a matching format! */ + testFormat = fmt; + break; + } + } + if (testFormat == 0) + { + PaWinWDM_SetLastErrorInfo(result, "IsFormatSupported(capture) failed: no testformat found!"); + return paUnanticipatedHostError; + } + + /* Due to special considerations, WaveRT devices with paInt24 should be tested with paInt32 and + valid bits = 24 (instead of 24 bit samples) */ + if (pFilter->devInfo.streamingType == Type_kWaveRT && testFormat == paInt24) + { + PA_DEBUG(("IsFormatSupported (capture): WaveRT overriding testFormat paInt24 with paInt32 (24 valid bits)")); + testFormat = paInt32; + validBits = 24; + } + + /* Check that the input format is supported */ + channelMask = PaWin_DefaultChannelMask(inputChannelCount); + PaWin_InitializeWaveFormatExtensible((PaWinWaveFormat*)&wfx, + inputChannelCount, + testFormat, + PaWin_SampleFormatToLinearWaveFormatTag(testFormat), + sampleRate, + channelMask ); + if (validBits != 0) + { + wfx.Samples.wValidBitsPerSample = validBits; + } + + result = PinIsFormatSupported(pin, (const WAVEFORMATEX*)&wfx); + if( result != paNoError ) + { + /* Try a WAVE_FORMAT_PCM instead */ + PaWin_InitializeWaveFormatEx((PaWinWaveFormat*)&wfx, + inputChannelCount, + testFormat, + PaWin_SampleFormatToLinearWaveFormatTag(testFormat), + sampleRate); + + if (validBits != 0) + { + wfx.Samples.wValidBitsPerSample = validBits; + } + + result = PinIsFormatSupported(pin, (const WAVEFORMATEX*)&wfx); + if( result != paNoError ) + { + PaWinWDM_SetLastErrorInfo(result, "IsFormatSupported(capture) failed: sr=%u,ch=%u,bits=%u", wfx.Format.nSamplesPerSec, wfx.Format.nChannels, wfx.Format.wBitsPerSample); + return result; + } + } + } + else + { + inputChannelCount = 0; + } + + if( outputParameters ) + { + PaWinWdmDeviceInfo* pDeviceInfo = (PaWinWdmDeviceInfo*)wdmHostApi->inheritedHostApiRep.deviceInfos[outputParameters->device]; + PaWinWdmPin* pin; + unsigned fmt; + unsigned long testFormat = 0; + unsigned validBits = 0; + + outputChannelCount = outputParameters->channelCount; + outputSampleFormat = outputParameters->sampleFormat; + + /* all standard sample formats are supported by the buffer adapter, + this implementation doesn't support any custom sample formats */ + if( outputSampleFormat & paCustomFormat ) + { + PaWinWDM_SetLastErrorInfo(paSampleFormatNotSupported, "IsFormatSupported: Custom output format not supported"); + return paSampleFormatNotSupported; + } + + /* unless alternate device specification is supported, reject the use of + paUseHostApiSpecificDeviceSpecification */ + + if( outputParameters->device == paUseHostApiSpecificDeviceSpecification ) + { + PaWinWDM_SetLastErrorInfo(paInvalidDevice, "IsFormatSupported: paUseHostApiSpecificDeviceSpecification not supported"); + return paInvalidDevice; + } + + /* check that output device can support outputChannelCount */ + if( outputChannelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels ) + { + PaWinWDM_SetLastErrorInfo(paInvalidChannelCount, "Invalid output channel count"); + return paInvalidChannelCount; + } + + /* validate outputStreamInfo */ + if( outputParameters->hostApiSpecificStreamInfo ) + { + PaWinWDM_SetLastErrorInfo(paIncompatibleHostApiSpecificStreamInfo, "Host API stream info not supported"); + return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */ + } + + pFilter = pDeviceInfo->filter; + pin = pFilter->pins[pDeviceInfo->pin]; + + /* Find out the testing format */ + for (fmt = paFloat32; fmt <= paUInt8; fmt <<= 1) + { + if ((fmt & pin->formats) != 0) + { + /* Found a matching format! */ + testFormat = fmt; + break; + } + } + if (testFormat == 0) + { + PaWinWDM_SetLastErrorInfo(result, "IsFormatSupported(render) failed: no testformat found!"); + return paUnanticipatedHostError; + } + + /* Due to special considerations, WaveRT devices with paInt24 should be tested with paInt32 and + valid bits = 24 (instead of 24 bit samples) */ + if (pFilter->devInfo.streamingType == Type_kWaveRT && testFormat == paInt24) + { + PA_DEBUG(("IsFormatSupported (render): WaveRT overriding testFormat paInt24 with paInt32 (24 valid bits)")); + testFormat = paInt32; + validBits = 24; + } + + /* Check that the output format is supported */ + channelMask = PaWin_DefaultChannelMask(outputChannelCount); + PaWin_InitializeWaveFormatExtensible((PaWinWaveFormat*)&wfx, + outputChannelCount, + testFormat, + PaWin_SampleFormatToLinearWaveFormatTag(testFormat), + sampleRate, + channelMask ); + + if (validBits != 0) + { + wfx.Samples.wValidBitsPerSample = validBits; + } + + result = PinIsFormatSupported(pin, (const WAVEFORMATEX*)&wfx); + if( result != paNoError ) + { + /* Try a WAVE_FORMAT_PCM instead */ + PaWin_InitializeWaveFormatEx((PaWinWaveFormat*)&wfx, + outputChannelCount, + testFormat, + PaWin_SampleFormatToLinearWaveFormatTag(testFormat), + sampleRate); + + if (validBits != 0) + { + wfx.Samples.wValidBitsPerSample = validBits; + } + + result = PinIsFormatSupported(pin, (const WAVEFORMATEX*)&wfx); + if( result != paNoError ) + { + PaWinWDM_SetLastErrorInfo(result, "IsFormatSupported(render) failed: %u,%u,%u", wfx.Format.nSamplesPerSec, wfx.Format.nChannels, wfx.Format.wBitsPerSample); + return result; + } + } + + } + else + { + outputChannelCount = 0; + } + + /* + IMPLEMENT ME: + + - if a full duplex stream is requested, check that the combination + of input and output parameters is supported if necessary + + - check that the device supports sampleRate + + Because the buffer adapter handles conversion between all standard + sample formats, the following checks are only required if paCustomFormat + is implemented, or under some other unusual conditions. + + - check that input device can support inputSampleFormat, or that + we have the capability to convert from inputSampleFormat to + a native format + + - check that output device can support outputSampleFormat, or that + we have the capability to convert from outputSampleFormat to + a native format + */ + if((inputChannelCount == 0)&&(outputChannelCount == 0)) + { + PaWinWDM_SetLastErrorInfo(paSampleFormatNotSupported, "No input or output channels defined"); + result = paSampleFormatNotSupported; /* Not right error */ + } + + PA_LOGL_; + return result; +} + +static void ResetStreamEvents(PaWinWdmStream* stream) +{ + unsigned i; + ResetEvent(stream->eventAbort); + ResetEvent(stream->eventStreamStart[StreamStart_kOk]); + ResetEvent(stream->eventStreamStart[StreamStart_kFailed]); + + for (i=0; icapture.noOfPackets; ++i) + { + if (stream->capture.events && stream->capture.events[i]) + { + ResetEvent(stream->capture.events[i]); + } + } + + for (i=0; irender.noOfPackets; ++i) + { + if (stream->render.events && stream->render.events[i]) + { + ResetEvent(stream->render.events[i]); + } + } +} + +static void CloseStreamEvents(PaWinWdmStream* stream) +{ + unsigned i; + PaWinWdmIOInfo* ios[2] = { &stream->capture, &stream->render }; + + if (stream->eventAbort) + { + CloseHandle(stream->eventAbort); + stream->eventAbort = 0; + } + if (stream->eventStreamStart[StreamStart_kOk]) + { + CloseHandle(stream->eventStreamStart[StreamStart_kOk]); + } + if (stream->eventStreamStart[StreamStart_kFailed]) + { + CloseHandle(stream->eventStreamStart[StreamStart_kFailed]); + } + + for (i = 0; i < 2; ++i) + { + unsigned j; + /* Unregister notification handles for WaveRT */ + if (ios[i]->pPin && ios[i]->pPin->parentFilter->devInfo.streamingType == Type_kWaveRT && + ios[i]->pPin->pinKsSubType == SubType_kNotification && + ios[i]->events != 0) + { + PinUnregisterNotificationHandle(ios[i]->pPin, ios[i]->events[0]); + } + + for (j=0; j < ios[i]->noOfPackets; ++j) + { + if (ios[i]->events && ios[i]->events[j]) + { + CloseHandle(ios[i]->events[j]); + ios[i]->events[j] = 0; + } + } + } +} + +static unsigned NextPowerOf2(unsigned val) +{ + val--; + val = (val >> 1) | val; + val = (val >> 2) | val; + val = (val >> 4) | val; + val = (val >> 8) | val; + val = (val >> 16) | val; + return ++val; +} + +static PaError ValidateSpecificStreamParameters( + const PaStreamParameters *streamParameters, + const PaWinWDMKSInfo *streamInfo, + unsigned isInput) +{ + if( streamInfo ) + { + if( streamInfo->size != sizeof( PaWinWDMKSInfo ) + || streamInfo->version != 1 ) + { + PA_DEBUG(("Stream parameters: size or version not correct")); + return paIncompatibleHostApiSpecificStreamInfo; + } + + if (!!(streamInfo->flags & ~(paWinWDMKSOverrideFramesize | paWinWDMKSUseGivenChannelMask))) + { + PA_DEBUG(("Stream parameters: non supported flags set")); + return paIncompatibleHostApiSpecificStreamInfo; + } + + if (streamInfo->noOfPackets != 0 && + (streamInfo->noOfPackets < 2 || streamInfo->noOfPackets > 8)) + { + PA_DEBUG(("Stream parameters: noOfPackets %u out of range [2,8]", streamInfo->noOfPackets)); + return paIncompatibleHostApiSpecificStreamInfo; + } + + if (streamInfo->flags & paWinWDMKSUseGivenChannelMask) + { + if (isInput) + { + PA_DEBUG(("Stream parameters: Channels mask setting not supported for input stream")); + return paIncompatibleHostApiSpecificStreamInfo; + } + + if (streamInfo->channelMask & PAWIN_SPEAKER_RESERVED) + { + PA_DEBUG(("Stream parameters: Given channels mask 0x%08X not supported", streamInfo->channelMask)); + return paIncompatibleHostApiSpecificStreamInfo; + } + } + + } + + return paNoError; +} + + + + +/* see pa_hostapi.h for a list of validity guarantees made about OpenStream parameters */ + +static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, + PaStream** s, + const PaStreamParameters *inputParameters, + const PaStreamParameters *outputParameters, + double sampleRate, + unsigned long framesPerUserBuffer, + PaStreamFlags streamFlags, + PaStreamCallback *streamCallback, + void *userData ) +{ + PaError result = paNoError; + PaWinWdmHostApiRepresentation *wdmHostApi = (PaWinWdmHostApiRepresentation*)hostApi; + PaWinWdmStream *stream = 0; + /* unsigned long framesPerHostBuffer; these may not be equivalent for all implementations */ + PaSampleFormat inputSampleFormat, outputSampleFormat; + PaSampleFormat hostInputSampleFormat, hostOutputSampleFormat; + int userInputChannels,userOutputChannels; + WAVEFORMATEXTENSIBLE wfx; + + PA_LOGE_; + PA_DEBUG(("OpenStream:sampleRate = %f\n",sampleRate)); + PA_DEBUG(("OpenStream:framesPerBuffer = %lu\n",framesPerUserBuffer)); + + if( inputParameters ) + { + userInputChannels = inputParameters->channelCount; + inputSampleFormat = inputParameters->sampleFormat; + + /* unless alternate device specification is supported, reject the use of + paUseHostApiSpecificDeviceSpecification */ + + if( inputParameters->device == paUseHostApiSpecificDeviceSpecification ) + { + PaWinWDM_SetLastErrorInfo(paInvalidDevice, "paUseHostApiSpecificDeviceSpecification(in) not supported"); + return paInvalidDevice; + } + + /* check that input device can support stream->userInputChannels */ + if( userInputChannels > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels ) + { + PaWinWDM_SetLastErrorInfo(paInvalidChannelCount, "Invalid input channel count"); + return paInvalidChannelCount; + } + + /* validate inputStreamInfo */ + result = ValidateSpecificStreamParameters(inputParameters, inputParameters->hostApiSpecificStreamInfo, 1 ); + if(result != paNoError) + { + PaWinWDM_SetLastErrorInfo(result, "Host API stream info not supported (in)"); + return result; /* this implementation doesn't use custom stream info */ + } + } + else + { + userInputChannels = 0; + inputSampleFormat = hostInputSampleFormat = paInt16; /* Supress 'uninitialised var' warnings. */ + } + + if( outputParameters ) + { + userOutputChannels = outputParameters->channelCount; + outputSampleFormat = outputParameters->sampleFormat; + + /* unless alternate device specification is supported, reject the use of + paUseHostApiSpecificDeviceSpecification */ + + if( outputParameters->device == paUseHostApiSpecificDeviceSpecification ) + { + PaWinWDM_SetLastErrorInfo(paInvalidDevice, "paUseHostApiSpecificDeviceSpecification(out) not supported"); + return paInvalidDevice; + } + + /* check that output device can support stream->userInputChannels */ + if( userOutputChannels > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels ) + { + PaWinWDM_SetLastErrorInfo(paInvalidChannelCount, "Invalid output channel count"); + return paInvalidChannelCount; + } + + /* validate outputStreamInfo */ + result = ValidateSpecificStreamParameters( outputParameters, outputParameters->hostApiSpecificStreamInfo, 0 ); + if (result != paNoError) + { + PaWinWDM_SetLastErrorInfo(result, "Host API stream info not supported (out)"); + return result; /* this implementation doesn't use custom stream info */ + } + } + else + { + userOutputChannels = 0; + outputSampleFormat = hostOutputSampleFormat = paInt16; /* Supress 'uninitialized var' warnings. */ + } + + /* validate platform specific flags */ + if( (streamFlags & paPlatformSpecificFlags) != 0 ) + { + PaWinWDM_SetLastErrorInfo(paInvalidFlag, "Invalid flag supplied"); + return paInvalidFlag; /* unexpected platform specific flag */ + } + + stream = (PaWinWdmStream*)PaUtil_AllocateMemory( sizeof(PaWinWdmStream) ); + if( !stream ) + { + result = paInsufficientMemory; + goto error; + } + + /* Create allocation group */ + stream->allocGroup = PaUtil_CreateAllocationGroup(); + if( !stream->allocGroup ) + { + result = paInsufficientMemory; + goto error; + } + + /* Zero the stream object */ + /* memset((void*)stream,0,sizeof(PaWinWdmStream)); */ + + if( streamCallback ) + { + PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation, + &wdmHostApi->callbackStreamInterface, streamCallback, userData ); + } + else + { + /* PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation, + &wdmHostApi->blockingStreamInterface, streamCallback, userData ); */ + + /* We don't support the blocking API yet */ + PA_DEBUG(("Blocking API not supported yet!\n")); + PaWinWDM_SetLastErrorInfo(paUnanticipatedHostError, "Blocking API not supported yet"); + result = paUnanticipatedHostError; + goto error; + } + + PaUtil_InitializeCpuLoadMeasurer( &stream->cpuLoadMeasurer, sampleRate ); + + /* Instantiate the input pin if necessary */ + if(userInputChannels > 0) + { + PaWinWdmFilter* pFilter; + PaWinWdmDeviceInfo* pDeviceInfo; + PaWinWdmPin* pPin; + unsigned validBitsPerSample = 0; + PaWinWaveFormatChannelMask channelMask = PaWin_DefaultChannelMask( userInputChannels ); + + result = paSampleFormatNotSupported; + pDeviceInfo = (PaWinWdmDeviceInfo*)wdmHostApi->inheritedHostApiRep.deviceInfos[inputParameters->device]; + pFilter = pDeviceInfo->filter; + pPin = pFilter->pins[pDeviceInfo->pin]; + + stream->userInputChannels = userInputChannels; + + hostInputSampleFormat = PaUtil_SelectClosestAvailableFormat( pPin->formats, inputSampleFormat ); + if (hostInputSampleFormat == paSampleFormatNotSupported) + { + result = paUnanticipatedHostError; + PaWinWDM_SetLastErrorInfo(result, "PU_SCAF(%X,%X) failed (input)", pPin->formats, inputSampleFormat); + goto error; + } + else if (pFilter->devInfo.streamingType == Type_kWaveRT && hostInputSampleFormat == paInt24) + { + /* For WaveRT, we choose 32 bit format instead of paInt24, since we MIGHT need to align buffer on a + 128 byte boundary (see PinGetBuffer) */ + hostInputSampleFormat = paInt32; + /* But we'll tell the driver that it's 24 bit in 32 bit container */ + validBitsPerSample = 24; + } + + while (hostInputSampleFormat <= paUInt8) + { + unsigned channelsToProbe = stream->userInputChannels; + /* Some or all KS devices can only handle the exact number of channels + * they specify. But PortAudio clients expect to be able to + * at least specify mono I/O on a multi-channel device + * If this is the case, then we will do the channel mapping internally + * The following loop tests this case + **/ + while (1) + { + PaWin_InitializeWaveFormatExtensible((PaWinWaveFormat*)&wfx, + channelsToProbe, + hostInputSampleFormat, + PaWin_SampleFormatToLinearWaveFormatTag(hostInputSampleFormat), + sampleRate, + channelMask ); + stream->capture.bytesPerFrame = wfx.Format.nBlockAlign; + if (validBitsPerSample != 0) + { + wfx.Samples.wValidBitsPerSample = validBitsPerSample; + } + stream->capture.pPin = FilterCreatePin(pFilter, pPin->pinId, (WAVEFORMATEX*)&wfx, &result); + stream->deviceInputChannels = channelsToProbe; + + if( result != paNoError && result != paDeviceUnavailable ) + { + /* Try a WAVE_FORMAT_PCM instead */ + PaWin_InitializeWaveFormatEx((PaWinWaveFormat*)&wfx, + channelsToProbe, + hostInputSampleFormat, + PaWin_SampleFormatToLinearWaveFormatTag(hostInputSampleFormat), + sampleRate); + if (validBitsPerSample != 0) + { + wfx.Samples.wValidBitsPerSample = validBitsPerSample; + } + stream->capture.pPin = FilterCreatePin(pFilter, pPin->pinId, (const WAVEFORMATEX*)&wfx, &result); + } + + if (result == paDeviceUnavailable) goto occupied; + + if (result == paNoError) + { + /* We're done */ + break; + } + + if (channelsToProbe < (unsigned)pPin->maxChannels) + { + /* Go to next multiple of 2 */ + channelsToProbe = min((((channelsToProbe>>1)+1)<<1), (unsigned)pPin->maxChannels); + continue; + } + + break; + } + + if (result == paNoError) + { + /* We're done */ + break; + } + + /* Go to next format in line with lower resolution */ + hostInputSampleFormat <<= 1; + } + + if(stream->capture.pPin == NULL) + { + PaWinWDM_SetLastErrorInfo(result, "Failed to create capture pin: sr=%u,ch=%u,bits=%u,align=%u", + wfx.Format.nSamplesPerSec, wfx.Format.nChannels, wfx.Format.wBitsPerSample, wfx.Format.nBlockAlign); + goto error; + } + + /* Select correct mux input on MUX node of topology filter */ + if (pDeviceInfo->muxPosition >= 0) + { + assert(pPin->parentFilter->topologyFilter != NULL); + + result = FilterUse(pPin->parentFilter->topologyFilter); + if (result != paNoError) + { + PaWinWDM_SetLastErrorInfo(result, "Failed to open topology filter"); + goto error; + } + + result = WdmSetMuxNodeProperty(pPin->parentFilter->topologyFilter->handle, + pPin->inputs[pDeviceInfo->muxPosition]->muxNodeId, + pPin->inputs[pDeviceInfo->muxPosition]->muxPinId); + + FilterRelease(pPin->parentFilter->topologyFilter); + + if(result != paNoError) + { + PaWinWDM_SetLastErrorInfo(result, "Failed to set topology mux node"); + goto error; + } + } + + stream->capture.bytesPerSample = stream->capture.bytesPerFrame / stream->deviceInputChannels; + stream->capture.pPin->frameSize /= stream->capture.bytesPerFrame; + PA_DEBUG(("Capture pin frames: %d\n",stream->capture.pPin->frameSize)); + } + else + { + stream->capture.pPin = NULL; + stream->capture.bytesPerFrame = 0; + } + + /* Instantiate the output pin if necessary */ + if(userOutputChannels > 0) + { + PaWinWdmFilter* pFilter; + PaWinWdmDeviceInfo* pDeviceInfo; + PaWinWdmPin* pPin; + PaWinWDMKSInfo* pInfo = (PaWinWDMKSInfo*)(outputParameters->hostApiSpecificStreamInfo); + unsigned validBitsPerSample = 0; + PaWinWaveFormatChannelMask channelMask = PaWin_DefaultChannelMask( userOutputChannels ); + if (pInfo && (pInfo->flags & paWinWDMKSUseGivenChannelMask)) + { + PA_DEBUG(("Using channelMask 0x%08X instead of default 0x%08X\n", + pInfo->channelMask, + channelMask)); + channelMask = pInfo->channelMask; + } + + result = paSampleFormatNotSupported; + pDeviceInfo = (PaWinWdmDeviceInfo*)wdmHostApi->inheritedHostApiRep.deviceInfos[outputParameters->device]; + pFilter = pDeviceInfo->filter; + pPin = pFilter->pins[pDeviceInfo->pin]; + + stream->userOutputChannels = userOutputChannels; + + hostOutputSampleFormat = PaUtil_SelectClosestAvailableFormat( pPin->formats, outputSampleFormat ); + if (hostOutputSampleFormat == paSampleFormatNotSupported) + { + result = paUnanticipatedHostError; + PaWinWDM_SetLastErrorInfo(result, "PU_SCAF(%X,%X) failed (output)", pPin->formats, hostOutputSampleFormat); + goto error; + } + else if (pFilter->devInfo.streamingType == Type_kWaveRT && hostOutputSampleFormat == paInt24) + { + /* For WaveRT, we choose 32 bit format instead of paInt24, since we MIGHT need to align buffer on a + 128 byte boundary (see PinGetBuffer) */ + hostOutputSampleFormat = paInt32; + /* But we'll tell the driver that it's 24 bit in 32 bit container */ + validBitsPerSample = 24; + } + + while (hostOutputSampleFormat <= paUInt8) + { + unsigned channelsToProbe = stream->userOutputChannels; + /* Some or all KS devices can only handle the exact number of channels + * they specify. But PortAudio clients expect to be able to + * at least specify mono I/O on a multi-channel device + * If this is the case, then we will do the channel mapping internally + * The following loop tests this case + **/ + while (1) + { + PaWin_InitializeWaveFormatExtensible((PaWinWaveFormat*)&wfx, + channelsToProbe, + hostOutputSampleFormat, + PaWin_SampleFormatToLinearWaveFormatTag(hostOutputSampleFormat), + sampleRate, + channelMask ); + stream->render.bytesPerFrame = wfx.Format.nBlockAlign; + if (validBitsPerSample != 0) + { + wfx.Samples.wValidBitsPerSample = validBitsPerSample; + } + stream->render.pPin = FilterCreatePin(pFilter, pPin->pinId, (WAVEFORMATEX*)&wfx, &result); + stream->deviceOutputChannels = channelsToProbe; + + if( result != paNoError && result != paDeviceUnavailable ) + { + PaWin_InitializeWaveFormatEx((PaWinWaveFormat*)&wfx, + channelsToProbe, + hostOutputSampleFormat, + PaWin_SampleFormatToLinearWaveFormatTag(hostOutputSampleFormat), + sampleRate); + if (validBitsPerSample != 0) + { + wfx.Samples.wValidBitsPerSample = validBitsPerSample; + } + stream->render.pPin = FilterCreatePin(pFilter, pPin->pinId, (const WAVEFORMATEX*)&wfx, &result); + } + + if (result == paDeviceUnavailable) goto occupied; + + if (result == paNoError) + { + /* We're done */ + break; + } + + if (channelsToProbe < (unsigned)pPin->maxChannels) + { + /* Go to next multiple of 2 */ + channelsToProbe = min((((channelsToProbe>>1)+1)<<1), (unsigned)pPin->maxChannels); + continue; + } + + break; + }; + + if (result == paNoError) + { + /* We're done */ + break; + } + + /* Go to next format in line with lower resolution */ + hostOutputSampleFormat <<= 1; + } + + if(stream->render.pPin == NULL) + { + PaWinWDM_SetLastErrorInfo(result, "Failed to create render pin: sr=%u,ch=%u,bits=%u,align=%u", + wfx.Format.nSamplesPerSec, wfx.Format.nChannels, wfx.Format.wBitsPerSample, wfx.Format.nBlockAlign); + goto error; + } + + stream->render.bytesPerSample = stream->render.bytesPerFrame / stream->deviceOutputChannels; + stream->render.pPin->frameSize /= stream->render.bytesPerFrame; + PA_DEBUG(("Render pin frames: %d\n",stream->render.pPin->frameSize)); + } + else + { + stream->render.pPin = NULL; + stream->render.bytesPerFrame = 0; + } + + /* Calculate the framesPerHostXxxxBuffer size based upon the suggested latency values */ + /* Record the buffer length */ + if(inputParameters) + { + /* Calculate the frames from the user's value - add a bit to round up */ + stream->capture.framesPerBuffer = (unsigned long)((inputParameters->suggestedLatency*sampleRate)+0.0001); + if(stream->capture.framesPerBuffer > (unsigned long)sampleRate) + { /* Upper limit is 1 second */ + stream->capture.framesPerBuffer = (unsigned long)sampleRate; + } + else if(stream->capture.framesPerBuffer < stream->capture.pPin->frameSize) + { + stream->capture.framesPerBuffer = stream->capture.pPin->frameSize; + } + PA_DEBUG(("Input frames chosen:%ld\n",stream->capture.framesPerBuffer)); + + /* Setup number of packets to use */ + stream->capture.noOfPackets = 2; + + if (inputParameters->hostApiSpecificStreamInfo) + { + PaWinWDMKSInfo* pInfo = (PaWinWDMKSInfo*)inputParameters->hostApiSpecificStreamInfo; + + if (stream->capture.pPin->parentFilter->devInfo.streamingType == Type_kWaveCyclic && + pInfo->noOfPackets != 0) + { + stream->capture.noOfPackets = pInfo->noOfPackets; + } + } + } + + if(outputParameters) + { + /* Calculate the frames from the user's value - add a bit to round up */ + stream->render.framesPerBuffer = (unsigned long)((outputParameters->suggestedLatency*sampleRate)+0.0001); + if(stream->render.framesPerBuffer > (unsigned long)sampleRate) + { /* Upper limit is 1 second */ + stream->render.framesPerBuffer = (unsigned long)sampleRate; + } + else if(stream->render.framesPerBuffer < stream->render.pPin->frameSize) + { + stream->render.framesPerBuffer = stream->render.pPin->frameSize; + } + PA_DEBUG(("Output frames chosen:%ld\n",stream->render.framesPerBuffer)); + + /* Setup number of packets to use */ + stream->render.noOfPackets = 2; + + if (outputParameters->hostApiSpecificStreamInfo) + { + PaWinWDMKSInfo* pInfo = (PaWinWDMKSInfo*)outputParameters->hostApiSpecificStreamInfo; + + if (stream->render.pPin->parentFilter->devInfo.streamingType == Type_kWaveCyclic && + pInfo->noOfPackets != 0) + { + stream->render.noOfPackets = pInfo->noOfPackets; + } + } + } + + /* Host buffer size is bound to the largest of the input and output frame sizes */ + result = PaUtil_InitializeBufferProcessor( &stream->bufferProcessor, + stream->userInputChannels, inputSampleFormat, hostInputSampleFormat, + stream->userOutputChannels, outputSampleFormat, hostOutputSampleFormat, + sampleRate, streamFlags, framesPerUserBuffer, + max(stream->capture.framesPerBuffer, stream->render.framesPerBuffer), + paUtilBoundedHostBufferSize, + streamCallback, userData ); + if( result != paNoError ) + { + PaWinWDM_SetLastErrorInfo(result, "PaUtil_InitializeBufferProcessor failed: ich=%u, isf=%u, hisf=%u, och=%u, osf=%u, hosf=%u, sr=%lf, flags=0x%X, fpub=%u, fphb=%u", + stream->userInputChannels, inputSampleFormat, hostInputSampleFormat, + stream->userOutputChannels, outputSampleFormat, hostOutputSampleFormat, + sampleRate, streamFlags, framesPerUserBuffer, + max(stream->capture.framesPerBuffer, stream->render.framesPerBuffer)); + goto error; + } + + /* Allocate/get all the buffers for host I/O */ + if (stream->userInputChannels > 0) + { + stream->streamRepresentation.streamInfo.inputLatency = stream->capture.framesPerBuffer / sampleRate; + + switch (stream->capture.pPin->parentFilter->devInfo.streamingType) + { + case Type_kWaveCyclic: + { + unsigned size = stream->capture.noOfPackets * stream->capture.framesPerBuffer * stream->capture.bytesPerFrame; + /* Allocate input host buffer */ + stream->capture.hostBuffer = (char*)PaUtil_GroupAllocateMemory(stream->allocGroup, size); + PA_DEBUG(("Input buffer allocated (size = %u)\n", size)); + if( !stream->capture.hostBuffer ) + { + PA_DEBUG(("Cannot allocate host input buffer!\n")); + PaWinWDM_SetLastErrorInfo(paInsufficientMemory, "Failed to allocate input buffer"); + result = paInsufficientMemory; + goto error; + } + stream->capture.hostBufferSize = size; + PA_DEBUG(("Input buffer start = %p (size=%u)\n",stream->capture.hostBuffer, stream->capture.hostBufferSize)); + stream->capture.pPin->fnEventHandler = PaPinCaptureEventHandler_WaveCyclic; + stream->capture.pPin->fnSubmitHandler = PaPinCaptureSubmitHandler_WaveCyclic; + } + break; + case Type_kWaveRT: + { + const DWORD dwTotalSize = 2 * stream->capture.framesPerBuffer * stream->capture.bytesPerFrame; + DWORD dwRequestedSize = dwTotalSize; + BOOL bCallMemoryBarrier = FALSE; + ULONG hwFifoLatency = 0; + ULONG dummy; + result = PinGetBuffer(stream->capture.pPin, (void**)&stream->capture.hostBuffer, &dwRequestedSize, &bCallMemoryBarrier); + if (!result) + { + PA_DEBUG(("Input buffer start = %p, size = %u\n", stream->capture.hostBuffer, dwRequestedSize)); + if (dwRequestedSize != dwTotalSize) + { + PA_DEBUG(("Buffer length changed by driver from %u to %u !\n", dwTotalSize, dwRequestedSize)); + /* Recalculate to what the driver has given us */ + stream->capture.framesPerBuffer = dwRequestedSize / (2 * stream->capture.bytesPerFrame); + } + stream->capture.hostBufferSize = dwRequestedSize; + + if (stream->capture.pPin->pinKsSubType == SubType_kPolled) + { + stream->capture.pPin->fnEventHandler = PaPinCaptureEventHandler_WaveRTPolled; + stream->capture.pPin->fnSubmitHandler = PaPinCaptureSubmitHandler_WaveRTPolled; + } + else + { + stream->capture.pPin->fnEventHandler = PaPinCaptureEventHandler_WaveRTEvent; + stream->capture.pPin->fnSubmitHandler = PaPinCaptureSubmitHandler_WaveRTEvent; + } + + stream->capture.pPin->fnMemBarrier = bCallMemoryBarrier ? MemoryBarrierRead : MemoryBarrierDummy; + } + else + { + PA_DEBUG(("Failed to get input buffer (WaveRT)\n")); + PaWinWDM_SetLastErrorInfo(paUnanticipatedHostError, "Failed to get input buffer (WaveRT)"); + result = paUnanticipatedHostError; + goto error; + } + + /* Get latency */ + result = PinGetHwLatency(stream->capture.pPin, &hwFifoLatency, &dummy, &dummy); + if (result == paNoError) + { + stream->capture.pPin->hwLatency = hwFifoLatency; + + /* Add HW latency into total input latency */ + stream->streamRepresentation.streamInfo.inputLatency += ((hwFifoLatency / stream->capture.bytesPerFrame) / sampleRate); + } + else + { + PA_DEBUG(("Failed to get size of FIFO hardware buffer (is set to zero)\n")); + stream->capture.pPin->hwLatency = 0; + } + } + break; + default: + /* Undefined wave type!! */ + assert(0); + result = paInternalError; + PaWinWDM_SetLastErrorInfo(result, "Wave type %u ??", stream->capture.pPin->parentFilter->devInfo.streamingType); + goto error; + } + } + else + { + stream->capture.hostBuffer = 0; + } + + if (stream->userOutputChannels > 0) + { + stream->streamRepresentation.streamInfo.outputLatency = stream->render.framesPerBuffer / sampleRate; + + switch (stream->render.pPin->parentFilter->devInfo.streamingType) + { + case Type_kWaveCyclic: + { + unsigned size = stream->render.noOfPackets * stream->render.framesPerBuffer * stream->render.bytesPerFrame; + /* Allocate output device buffer */ + stream->render.hostBuffer = (char*)PaUtil_GroupAllocateMemory(stream->allocGroup, size); + PA_DEBUG(("Output buffer allocated (size = %u)\n", size)); + if( !stream->render.hostBuffer ) + { + PA_DEBUG(("Cannot allocate host output buffer!\n")); + PaWinWDM_SetLastErrorInfo(paInsufficientMemory, "Failed to allocate output buffer"); + result = paInsufficientMemory; + goto error; + } + stream->render.hostBufferSize = size; + PA_DEBUG(("Output buffer start = %p (size=%u)\n",stream->render.hostBuffer, stream->render.hostBufferSize)); + + stream->render.pPin->fnEventHandler = PaPinRenderEventHandler_WaveCyclic; + stream->render.pPin->fnSubmitHandler = PaPinRenderSubmitHandler_WaveCyclic; + } + break; + case Type_kWaveRT: + { + const DWORD dwTotalSize = 2 * stream->render.framesPerBuffer * stream->render.bytesPerFrame; + DWORD dwRequestedSize = dwTotalSize; + BOOL bCallMemoryBarrier = FALSE; + ULONG hwFifoLatency = 0; + ULONG dummy; + result = PinGetBuffer(stream->render.pPin, (void**)&stream->render.hostBuffer, &dwRequestedSize, &bCallMemoryBarrier); + if (!result) + { + PA_DEBUG(("Output buffer start = %p, size = %u, membarrier = %u\n", stream->render.hostBuffer, dwRequestedSize, bCallMemoryBarrier)); + if (dwRequestedSize != dwTotalSize) + { + PA_DEBUG(("Buffer length changed by driver from %u to %u !\n", dwTotalSize, dwRequestedSize)); + /* Recalculate to what the driver has given us */ + stream->render.framesPerBuffer = dwRequestedSize / (2 * stream->render.bytesPerFrame); + } + stream->render.hostBufferSize = dwRequestedSize; + + if (stream->render.pPin->pinKsSubType == SubType_kPolled) + { + stream->render.pPin->fnEventHandler = PaPinRenderEventHandler_WaveRTPolled; + stream->render.pPin->fnSubmitHandler = PaPinRenderSubmitHandler_WaveRTPolled; + } + else + { + stream->render.pPin->fnEventHandler = PaPinRenderEventHandler_WaveRTEvent; + stream->render.pPin->fnSubmitHandler = PaPinRenderSubmitHandler_WaveRTEvent; + } + + stream->render.pPin->fnMemBarrier = bCallMemoryBarrier ? MemoryBarrierWrite : MemoryBarrierDummy; + } + else + { + PA_DEBUG(("Failed to get output buffer (with notification)\n")); + PaWinWDM_SetLastErrorInfo(paUnanticipatedHostError, "Failed to get output buffer (with notification)"); + result = paUnanticipatedHostError; + goto error; + } + + /* Get latency */ + result = PinGetHwLatency(stream->render.pPin, &hwFifoLatency, &dummy, &dummy); + if (result == paNoError) + { + stream->render.pPin->hwLatency = hwFifoLatency; + + /* Add HW latency into total output latency */ + stream->streamRepresentation.streamInfo.outputLatency += ((hwFifoLatency / stream->render.bytesPerFrame) / sampleRate); + } + else + { + PA_DEBUG(("Failed to get size of FIFO hardware buffer (is set to zero)\n")); + stream->render.pPin->hwLatency = 0; + } + } + break; + default: + /* Undefined wave type!! */ + assert(0); + result = paInternalError; + PaWinWDM_SetLastErrorInfo(result, "Wave type %u ??", stream->capture.pPin->parentFilter->devInfo.streamingType); + goto error; + } + } + else + { + stream->render.hostBuffer = 0; + } + + stream->streamRepresentation.streamInfo.sampleRate = sampleRate; + + PA_DEBUG(("BytesPerInputFrame = %d\n",stream->capture.bytesPerFrame)); + PA_DEBUG(("BytesPerOutputFrame = %d\n",stream->render.bytesPerFrame)); + + /* memset(stream->hostBuffer,0,size); */ + + /* Abort */ + stream->eventAbort = CreateEvent(NULL, TRUE, FALSE, NULL); + if (stream->eventAbort == 0) + { + result = paInsufficientMemory; + goto error; + } + stream->eventStreamStart[0] = CreateEvent(NULL, TRUE, FALSE, NULL); + if (stream->eventStreamStart[0] == 0) + { + result = paInsufficientMemory; + goto error; + } + stream->eventStreamStart[1] = CreateEvent(NULL, TRUE, FALSE, NULL); + if (stream->eventStreamStart[1] == 0) + { + result = paInsufficientMemory; + goto error; + } + + if(stream->userInputChannels > 0) + { + const unsigned bufferSizeInBytes = stream->capture.framesPerBuffer * stream->capture.bytesPerFrame; + const unsigned ringBufferFrameSize = NextPowerOf2( 1024 + 2 * max(stream->capture.framesPerBuffer, stream->render.framesPerBuffer) ); + + stream->capture.events = (HANDLE*)PaUtil_GroupAllocateMemory(stream->allocGroup, stream->capture.noOfPackets * sizeof(HANDLE)); + if (stream->capture.events == NULL) + { + result = paInsufficientMemory; + goto error; + } + + stream->capture.packets = (DATAPACKET*)PaUtil_GroupAllocateMemory(stream->allocGroup, stream->capture.noOfPackets * sizeof(DATAPACKET)); + if (stream->capture.packets == NULL) + { + result = paInsufficientMemory; + goto error; + } + + switch(stream->capture.pPin->parentFilter->devInfo.streamingType) + { + case Type_kWaveCyclic: + { + /* WaveCyclic case */ + unsigned i; + for (i = 0; i < stream->capture.noOfPackets; ++i) + { + /* Set up the packets */ + DATAPACKET *p = stream->capture.packets + i; + + /* Record event */ + stream->capture.events[i] = CreateEvent(NULL, TRUE, FALSE, NULL); + + p->Signal.hEvent = stream->capture.events[i]; + p->Header.Data = stream->capture.hostBuffer + (i*bufferSizeInBytes); + p->Header.FrameExtent = bufferSizeInBytes; + p->Header.DataUsed = 0; + p->Header.Size = sizeof(p->Header); + p->Header.PresentationTime.Numerator = 1; + p->Header.PresentationTime.Denominator = 1; + } + } + break; + case Type_kWaveRT: + { + /* Set up the "packets" */ + DATAPACKET *p = stream->capture.packets + 0; + + /* Record event: WaveRT has a single event for 2 notification per buffer */ + stream->capture.events[0] = CreateEvent(NULL, FALSE, FALSE, NULL); + + p->Header.Data = stream->capture.hostBuffer; + p->Header.FrameExtent = bufferSizeInBytes; + p->Header.DataUsed = 0; + p->Header.Size = sizeof(p->Header); + p->Header.PresentationTime.Numerator = 1; + p->Header.PresentationTime.Denominator = 1; + + ++p; + p->Header.Data = stream->capture.hostBuffer + bufferSizeInBytes; + p->Header.FrameExtent = bufferSizeInBytes; + p->Header.DataUsed = 0; + p->Header.Size = sizeof(p->Header); + p->Header.PresentationTime.Numerator = 1; + p->Header.PresentationTime.Denominator = 1; + + if (stream->capture.pPin->pinKsSubType == SubType_kNotification) + { + result = PinRegisterNotificationHandle(stream->capture.pPin, stream->capture.events[0]); + + if (result != paNoError) + { + PA_DEBUG(("Failed to register capture notification handle\n")); + PaWinWDM_SetLastErrorInfo(paUnanticipatedHostError, "Failed to register capture notification handle"); + result = paUnanticipatedHostError; + goto error; + } + } + + result = PinRegisterPositionRegister(stream->capture.pPin); + + if (result != paNoError) + { + unsigned long pos = 0xdeadc0de; + PA_DEBUG(("Failed to register capture position register, using PinGetAudioPositionViaIOCTLWrite\n")); + stream->capture.pPin->fnAudioPosition = PinGetAudioPositionViaIOCTLWrite; + /* Test position function */ + result = (stream->capture.pPin->fnAudioPosition)(stream->capture.pPin, &pos); + if (result != paNoError || pos != 0x0) + { + PA_DEBUG(("Failed to read capture position register (IOCTL)\n")); + PaWinWDM_SetLastErrorInfo(paUnanticipatedHostError, "Failed to read capture position register (IOCTL)"); + result = paUnanticipatedHostError; + goto error; + } + } + else + { + stream->capture.pPin->fnAudioPosition = PinGetAudioPositionMemoryMapped; + } + } + break; + default: + /* Undefined wave type!! */ + assert(0); + result = paInternalError; + PaWinWDM_SetLastErrorInfo(result, "Wave type %u ??", stream->capture.pPin->parentFilter->devInfo.streamingType); + goto error; + } + + /* Setup the input ring buffer here */ + stream->ringBufferData = (char*)PaUtil_GroupAllocateMemory(stream->allocGroup, ringBufferFrameSize * stream->capture.bytesPerFrame); + if (stream->ringBufferData == NULL) + { + result = paInsufficientMemory; + goto error; + } + PaUtil_InitializeRingBuffer(&stream->ringBuffer, stream->capture.bytesPerFrame, ringBufferFrameSize, stream->ringBufferData); + } + if(stream->userOutputChannels > 0) + { + const unsigned bufferSizeInBytes = stream->render.framesPerBuffer * stream->render.bytesPerFrame; + + stream->render.events = (HANDLE*)PaUtil_GroupAllocateMemory(stream->allocGroup, stream->render.noOfPackets * sizeof(HANDLE)); + if (stream->render.events == NULL) + { + result = paInsufficientMemory; + goto error; + } + + stream->render.packets = (DATAPACKET*)PaUtil_GroupAllocateMemory(stream->allocGroup, stream->render.noOfPackets * sizeof(DATAPACKET)); + if (stream->render.packets == NULL) + { + result = paInsufficientMemory; + goto error; + } + + switch(stream->render.pPin->parentFilter->devInfo.streamingType) + { + case Type_kWaveCyclic: + { + /* WaveCyclic case */ + unsigned i; + for (i = 0; i < stream->render.noOfPackets; ++i) + { + /* Set up the packets */ + DATAPACKET *p = stream->render.packets + i; + + /* Playback event */ + stream->render.events[i] = CreateEvent(NULL, TRUE, FALSE, NULL); + + /* In this case, we just use the packets as ptr to the device buffer */ + p->Signal.hEvent = stream->render.events[i]; + p->Header.Data = stream->render.hostBuffer + (i*bufferSizeInBytes); + p->Header.FrameExtent = bufferSizeInBytes; + p->Header.DataUsed = bufferSizeInBytes; + p->Header.Size = sizeof(p->Header); + p->Header.PresentationTime.Numerator = 1; + p->Header.PresentationTime.Denominator = 1; + } + } + break; + case Type_kWaveRT: + { + /* WaveRT case */ + + /* Set up the "packets" */ + DATAPACKET *p = stream->render.packets; + + /* The only playback event */ + stream->render.events[0] = CreateEvent(NULL, FALSE, FALSE, NULL); + + /* In this case, we just use the packets as ptr to the device buffer */ + p->Header.Data = stream->render.hostBuffer; + p->Header.FrameExtent = stream->render.framesPerBuffer*stream->render.bytesPerFrame; + p->Header.DataUsed = stream->render.framesPerBuffer*stream->render.bytesPerFrame; + p->Header.Size = sizeof(p->Header); + p->Header.PresentationTime.Numerator = 1; + p->Header.PresentationTime.Denominator = 1; + + ++p; + p->Header.Data = stream->render.hostBuffer + stream->render.framesPerBuffer*stream->render.bytesPerFrame; + p->Header.FrameExtent = stream->render.framesPerBuffer*stream->render.bytesPerFrame; + p->Header.DataUsed = stream->render.framesPerBuffer*stream->render.bytesPerFrame; + p->Header.Size = sizeof(p->Header); + p->Header.PresentationTime.Numerator = 1; + p->Header.PresentationTime.Denominator = 1; + + if (stream->render.pPin->pinKsSubType == SubType_kNotification) + { + result = PinRegisterNotificationHandle(stream->render.pPin, stream->render.events[0]); + + if (result != paNoError) + { + PA_DEBUG(("Failed to register rendering notification handle\n")); + PaWinWDM_SetLastErrorInfo(paUnanticipatedHostError, "Failed to register rendering notification handle"); + result = paUnanticipatedHostError; + goto error; + } + } + + result = PinRegisterPositionRegister(stream->render.pPin); + + if (result != paNoError) + { + unsigned long pos = 0xdeadc0de; + PA_DEBUG(("Failed to register rendering position register, using PinGetAudioPositionViaIOCTLRead\n")); + stream->render.pPin->fnAudioPosition = PinGetAudioPositionViaIOCTLRead; + /* Test position function */ + result = (stream->render.pPin->fnAudioPosition)(stream->render.pPin, &pos); + if (result != paNoError || pos != 0x0) + { + PA_DEBUG(("Failed to read render position register (IOCTL)\n")); + PaWinWDM_SetLastErrorInfo(paUnanticipatedHostError, "Failed to read render position register (IOCTL)"); + result = paUnanticipatedHostError; + goto error; + } + } + else + { + stream->render.pPin->fnAudioPosition = PinGetAudioPositionMemoryMapped; + } + } + break; + default: + /* Undefined wave type!! */ + assert(0); + result = paInternalError; + PaWinWDM_SetLastErrorInfo(result, "Wave type %u ??", stream->capture.pPin->parentFilter->devInfo.streamingType); + goto error; + } + } + + stream->streamStarted = 0; + stream->streamActive = 0; + stream->streamStop = 0; + stream->streamAbort = 0; + stream->streamFlags = streamFlags; + stream->oldProcessPriority = REALTIME_PRIORITY_CLASS; + + /* Increase ref count on filters in use, so that a CommitDeviceInfos won't delete them */ + if (stream->capture.pPin != 0) + { + FilterAddRef(stream->capture.pPin->parentFilter); + } + if (stream->render.pPin != 0) + { + FilterAddRef(stream->render.pPin->parentFilter); + } + + /* Ok, now update our host API specific stream info */ + if (stream->userInputChannels) + { + PaWinWdmDeviceInfo *pDeviceInfo = (PaWinWdmDeviceInfo*)wdmHostApi->inheritedHostApiRep.deviceInfos[inputParameters->device]; + + stream->hostApiStreamInfo.input.device = Pa_HostApiDeviceIndexToDeviceIndex(Pa_HostApiTypeIdToHostApiIndex(paWDMKS), inputParameters->device); + stream->hostApiStreamInfo.input.channels = stream->deviceInputChannels; + stream->hostApiStreamInfo.input.muxNodeId = -1; + if (stream->capture.pPin->inputs) + { + stream->hostApiStreamInfo.input.muxNodeId = stream->capture.pPin->inputs[pDeviceInfo->muxPosition]->muxNodeId; + } + stream->hostApiStreamInfo.input.endpointPinId = pDeviceInfo->endpointPinId; + stream->hostApiStreamInfo.input.framesPerHostBuffer = stream->capture.framesPerBuffer; + stream->hostApiStreamInfo.input.streamingSubType = stream->capture.pPin->pinKsSubType; + } + else + { + stream->hostApiStreamInfo.input.device = paNoDevice; + } + if (stream->userOutputChannels) + { + stream->hostApiStreamInfo.output.device = Pa_HostApiDeviceIndexToDeviceIndex(Pa_HostApiTypeIdToHostApiIndex(paWDMKS), outputParameters->device); + stream->hostApiStreamInfo.output.channels = stream->deviceOutputChannels; + stream->hostApiStreamInfo.output.framesPerHostBuffer = stream->render.framesPerBuffer; + stream->hostApiStreamInfo.output.endpointPinId = stream->render.pPin->endpointPinId; + stream->hostApiStreamInfo.output.streamingSubType = stream->render.pPin->pinKsSubType; + } + else + { + stream->hostApiStreamInfo.output.device = paNoDevice; + } + /*stream->streamRepresentation.streamInfo.hostApiTypeId = paWDMKS; + stream->streamRepresentation.streamInfo.hostApiSpecificStreamInfo = &stream->hostApiStreamInfo;*/ + stream->streamRepresentation.streamInfo.structVersion = 2; + + *s = (PaStream*)stream; + + PA_LOGL_; + return result; + +occupied: + /* Ok, someone else is hogging the pin, bail out */ + assert (result == paDeviceUnavailable); + PaWinWDM_SetLastErrorInfo(result, "Device is occupied"); + +error: + PaUtil_TerminateBufferProcessor( &stream->bufferProcessor ); + + CloseStreamEvents(stream); + + if (stream->allocGroup) + { + PaUtil_FreeAllAllocations(stream->allocGroup); + PaUtil_DestroyAllocationGroup(stream->allocGroup); + stream->allocGroup = 0; + } + + if(stream->render.pPin) + PinClose(stream->render.pPin); + if(stream->capture.pPin) + PinClose(stream->capture.pPin); + + PaUtil_FreeMemory( stream ); + + PA_LOGL_; + return result; +} + +/* +When CloseStream() is called, the multi-api layer ensures that +the stream has already been stopped or aborted. +*/ +static PaError CloseStream( PaStream* s ) +{ + PaError result = paNoError; + PaWinWdmStream *stream = (PaWinWdmStream*)s; + + PA_LOGE_; + + assert(!stream->streamStarted); + assert(!stream->streamActive); + + PaUtil_TerminateBufferProcessor( &stream->bufferProcessor ); + PaUtil_TerminateStreamRepresentation( &stream->streamRepresentation ); + + CloseStreamEvents(stream); + + if (stream->allocGroup) + { + PaUtil_FreeAllAllocations(stream->allocGroup); + PaUtil_DestroyAllocationGroup(stream->allocGroup); + stream->allocGroup = 0; + } + + if(stream->render.pPin) + { + PinClose(stream->render.pPin); + } + if(stream->capture.pPin) + { + PinClose(stream->capture.pPin); + } + + if (stream->render.pPin) + { + FilterFree(stream->render.pPin->parentFilter); + } + if (stream->capture.pPin) + { + FilterFree(stream->capture.pPin->parentFilter); + } + + PaUtil_FreeMemory( stream ); + + PA_LOGL_; + return result; +} + +/* +Write the supplied packet to the pin +Asynchronous +Should return paNoError on success +*/ +static PaError PinWrite(HANDLE h, DATAPACKET* p) +{ + PaError result = paNoError; + unsigned long cbReturned = 0; + BOOL fRes = DeviceIoControl(h, + IOCTL_KS_WRITE_STREAM, + NULL, + 0, + &p->Header, + p->Header.Size, + &cbReturned, + &p->Signal); + if (!fRes) + { + unsigned long error = GetLastError(); + if (error != ERROR_IO_PENDING) + { + result = paInternalError; + } + } + return result; +} + +/* +Read to the supplied packet from the pin +Asynchronous +Should return paNoError on success +*/ +static PaError PinRead(HANDLE h, DATAPACKET* p) +{ + PaError result = paNoError; + unsigned long cbReturned = 0; + BOOL fRes = DeviceIoControl(h, + IOCTL_KS_READ_STREAM, + NULL, + 0, + &p->Header, + p->Header.Size, + &cbReturned, + &p->Signal); + if (!fRes) + { + unsigned long error = GetLastError(); + if (error != ERROR_IO_PENDING) + { + result = paInternalError; + } + } + return result; +} + +/* +Copy the first interleaved channel of 16 bit data to the other channels +*/ +static void DuplicateFirstChannelInt16(void* buffer, int channels, int samples) +{ + unsigned short* data = (unsigned short*)buffer; + int channel; + unsigned short sourceSample; + while( samples-- ) + { + sourceSample = *data++; + channel = channels-1; + while( channel-- ) + { + *data++ = sourceSample; + } + } +} + +/* +Copy the first interleaved channel of 24 bit data to the other channels +*/ +static void DuplicateFirstChannelInt24(void* buffer, int channels, int samples) +{ + unsigned char* data = (unsigned char*)buffer; + int channel; + unsigned char sourceSample[3]; + while( samples-- ) + { + sourceSample[0] = data[0]; + sourceSample[1] = data[1]; + sourceSample[2] = data[2]; + data += 3; + channel = channels-1; + while( channel-- ) + { + data[0] = sourceSample[0]; + data[1] = sourceSample[1]; + data[2] = sourceSample[2]; + data += 3; + } + } +} + +/* +Copy the first interleaved channel of 32 bit data to the other channels +*/ +static void DuplicateFirstChannelInt32(void* buffer, int channels, int samples) +{ + unsigned long* data = (unsigned long*)buffer; + int channel; + unsigned long sourceSample; + while( samples-- ) + { + sourceSample = *data++; + channel = channels-1; + while( channel-- ) + { + *data++ = sourceSample; + } + } +} + +/* +Increase the priority of the calling thread to RT +*/ +static HANDLE BumpThreadPriority() +{ + HANDLE hThread = GetCurrentThread(); + DWORD dwTask = 0; + HANDLE hAVRT = NULL; + + /* If we have access to AVRT.DLL (Vista and later), use it */ + if (paWinWDMKSAvRtEntryPoints.AvSetMmThreadCharacteristics != NULL) + { + hAVRT = paWinWDMKSAvRtEntryPoints.AvSetMmThreadCharacteristics("Pro Audio", &dwTask); + if (hAVRT != NULL && hAVRT != INVALID_HANDLE_VALUE) + { + BOOL bret = paWinWDMKSAvRtEntryPoints.AvSetMmThreadPriority(hAVRT, PA_AVRT_PRIORITY_CRITICAL); + if (!bret) + { + PA_DEBUG(("Set mm thread prio to critical failed!\n")); + } + else + { + return hAVRT; + } + } + else + { + PA_DEBUG(("Set mm thread characteristic to 'Pro Audio' failed, reverting to SetThreadPriority\n")); + } + } + + /* For XP and earlier, or if AvSetMmThreadCharacteristics fails (MMCSS disabled ?) */ + if (timeBeginPeriod(1) != TIMERR_NOERROR) { + PA_DEBUG(("timeBeginPeriod(1) failed!\n")); + } + + if (!SetThreadPriority(hThread, THREAD_PRIORITY_TIME_CRITICAL)) { + PA_DEBUG(("SetThreadPriority failed!\n")); + } + + return hAVRT; +} + +/* +Decrease the priority of the calling thread to normal +*/ +static void DropThreadPriority(HANDLE hAVRT) +{ + HANDLE hThread = GetCurrentThread(); + + if (hAVRT != NULL) + { + paWinWDMKSAvRtEntryPoints.AvSetMmThreadPriority(hAVRT, PA_AVRT_PRIORITY_NORMAL); + paWinWDMKSAvRtEntryPoints.AvRevertMmThreadCharacteristics(hAVRT); + return; + } + + SetThreadPriority(hThread, THREAD_PRIORITY_NORMAL); + timeEndPeriod(1); +} + +static PaError PreparePinForStart(PaWinWdmPin* pin) +{ + PaError result; + result = PinSetState(pin, KSSTATE_ACQUIRE); + if (result != paNoError) + { + goto error; + } + result = PinSetState(pin, KSSTATE_PAUSE); + if (result != paNoError) + { + goto error; + } + return result; + +error: + PinSetState(pin, KSSTATE_STOP); + return result; +} + +static PaError PreparePinsForStart(PaProcessThreadInfo* pInfo) +{ + PaError result = paNoError; + /* Submit buffers */ + if (pInfo->stream->capture.pPin) + { + if ((result = PreparePinForStart(pInfo->stream->capture.pPin)) != paNoError) + { + goto error; + } + + if (pInfo->stream->capture.pPin->parentFilter->devInfo.streamingType == Type_kWaveCyclic) + { + unsigned i; + for(i=0; i < pInfo->stream->capture.noOfPackets; ++i) + { + if ((result = PinRead(pInfo->stream->capture.pPin->handle, pInfo->stream->capture.packets + i)) != paNoError) + { + goto error; + } + ++pInfo->pending; + } + } + else + { + pInfo->pending = 2; + } + } + + if(pInfo->stream->render.pPin) + { + if ((result = PreparePinForStart(pInfo->stream->render.pPin)) != paNoError) + { + goto error; + } + + pInfo->priming += pInfo->stream->render.noOfPackets; + ++pInfo->pending; + SetEvent(pInfo->stream->render.events[0]); + if (pInfo->stream->render.pPin->parentFilter->devInfo.streamingType == Type_kWaveCyclic) + { + unsigned i; + for(i=1; i < pInfo->stream->render.noOfPackets; ++i) + { + SetEvent(pInfo->stream->render.events[i]); + ++pInfo->pending; + } + } + } + +error: + PA_DEBUG(("PreparePinsForStart = %d\n", result)); + return result; +} + +static PaError StartPin(PaWinWdmPin* pin) +{ + return PinSetState(pin, KSSTATE_RUN); +} + +static PaError StartPins(PaProcessThreadInfo* pInfo) +{ + PaError result = paNoError; + /* Start the pins as synced as possible */ + if (pInfo->stream->capture.pPin) + { + result = StartPin(pInfo->stream->capture.pPin); + } + if(pInfo->stream->render.pPin) + { + result = StartPin(pInfo->stream->render.pPin); + } + PA_DEBUG(("StartPins = %d\n", result)); + return result; +} + + +static PaError StopPin(PaWinWdmPin* pin) +{ + PinSetState(pin, KSSTATE_PAUSE); + PinSetState(pin, KSSTATE_STOP); + return paNoError; +} + + +static PaError StopPins(PaProcessThreadInfo* pInfo) +{ + PaError result = paNoError; + if(pInfo->stream->render.pPin) + { + StopPin(pInfo->stream->render.pPin); + } + if(pInfo->stream->capture.pPin) + { + StopPin(pInfo->stream->capture.pPin); + } + return result; +} + +typedef void (*TSetInputFrameCount)(PaUtilBufferProcessor*, unsigned long); +typedef void (*TSetInputChannel)(PaUtilBufferProcessor*, unsigned int, void *, unsigned int); +static const TSetInputFrameCount fnSetInputFrameCount[2] = { PaUtil_SetInputFrameCount, PaUtil_Set2ndInputFrameCount }; +static const TSetInputChannel fnSetInputChannel[2] = { PaUtil_SetInputChannel, PaUtil_Set2ndInputChannel }; + +static PaError PaDoProcessing(PaProcessThreadInfo* pInfo) +{ + PaError result = paNoError; + int i, framesProcessed = 0, doChannelCopy = 0; + ring_buffer_size_t inputFramesAvailable = PaUtil_GetRingBufferReadAvailable(&pInfo->stream->ringBuffer); + + /* Do necessary buffer processing (which will invoke user callback if necessary) */ + if (pInfo->cbResult == paContinue && + (pInfo->renderHead != pInfo->renderTail || inputFramesAvailable)) + { + unsigned processFullDuplex = pInfo->stream->capture.pPin && pInfo->stream->render.pPin && (!pInfo->priming); + + PA_HP_TRACE((pInfo->stream->hLog, "DoProcessing: InputFrames=%u", inputFramesAvailable)); + + PaUtil_BeginCpuLoadMeasurement( &pInfo->stream->cpuLoadMeasurer ); + + pInfo->ti.currentTime = PaUtil_GetTime(); + + PaUtil_BeginBufferProcessing(&pInfo->stream->bufferProcessor, &pInfo->ti, pInfo->underover); + pInfo->underover = 0; /* Reset the (under|over)flow status */ + + if (pInfo->renderTail != pInfo->renderHead) + { + DATAPACKET* packet = pInfo->renderPackets[pInfo->renderTail & cPacketsArrayMask].packet; + + assert(packet != 0); + assert(packet->Header.Data != 0); + + PaUtil_SetOutputFrameCount(&pInfo->stream->bufferProcessor, pInfo->stream->render.framesPerBuffer); + + for(i=0;istream->userOutputChannels;i++) + { + /* Only write the user output channels. Leave the rest blank */ + PaUtil_SetOutputChannel(&pInfo->stream->bufferProcessor, + i, + ((unsigned char*)(packet->Header.Data))+(i*pInfo->stream->render.bytesPerSample), + pInfo->stream->deviceOutputChannels); + } + + /* We will do a copy to the other channels after the data has been written */ + doChannelCopy = ( pInfo->stream->userOutputChannels == 1 ); + } + + if (inputFramesAvailable && (!pInfo->stream->userOutputChannels || inputFramesAvailable >= (int)pInfo->stream->render.framesPerBuffer)) + { + unsigned wrapCntr = 0; + void* data[2] = {0}; + ring_buffer_size_t size[2] = {0}; + + /* If full-duplex, we just extract output buffer number of frames */ + if (pInfo->stream->userOutputChannels) + { + inputFramesAvailable = min(inputFramesAvailable, (int)pInfo->stream->render.framesPerBuffer); + } + + inputFramesAvailable = PaUtil_GetRingBufferReadRegions(&pInfo->stream->ringBuffer, + inputFramesAvailable, + &data[0], + &size[0], + &data[1], + &size[1]); + + for (wrapCntr = 0; wrapCntr < 2; ++wrapCntr) + { + if (size[wrapCntr] == 0) + break; + + fnSetInputFrameCount[wrapCntr](&pInfo->stream->bufferProcessor, size[wrapCntr]); + for(i=0;istream->userInputChannels;i++) + { + /* Only read as many channels as the user wants */ + fnSetInputChannel[wrapCntr](&pInfo->stream->bufferProcessor, + i, + ((unsigned char*)(data[wrapCntr]))+(i*pInfo->stream->capture.bytesPerSample), + pInfo->stream->deviceInputChannels); + } + } + } + else + { + /* We haven't consumed anything from the ring buffer... */ + inputFramesAvailable = 0; + /* If we have full-duplex, this is at startup, so mark no-input! */ + if (pInfo->stream->userOutputChannels>0 && pInfo->stream->userInputChannels>0) + { + PA_HP_TRACE((pInfo->stream->hLog, "Input startup, marking no input.")); + PaUtil_SetNoInput(&pInfo->stream->bufferProcessor); + } + } + + if (processFullDuplex) /* full duplex */ + { + /* Only call the EndBufferProcessing function when the total input frames == total output frames */ + const unsigned long totalInputFrameCount = pInfo->stream->bufferProcessor.hostInputFrameCount[0] + pInfo->stream->bufferProcessor.hostInputFrameCount[1]; + const unsigned long totalOutputFrameCount = pInfo->stream->bufferProcessor.hostOutputFrameCount[0] + pInfo->stream->bufferProcessor.hostOutputFrameCount[1]; + + if(totalInputFrameCount == totalOutputFrameCount && totalOutputFrameCount != 0) + { + framesProcessed = PaUtil_EndBufferProcessing(&pInfo->stream->bufferProcessor, &pInfo->cbResult); + } + else + { + framesProcessed = 0; + } + } + else + { + framesProcessed = PaUtil_EndBufferProcessing(&pInfo->stream->bufferProcessor, &pInfo->cbResult); + } + + PA_HP_TRACE((pInfo->stream->hLog, "Frames processed: %u %s", framesProcessed, (pInfo->priming ? "(priming)":""))); + + if( doChannelCopy ) + { + DATAPACKET* packet = pInfo->renderPackets[pInfo->renderTail & cPacketsArrayMask].packet; + /* Copy the first output channel to the other channels */ + switch (pInfo->stream->render.bytesPerSample) + { + case 2: + DuplicateFirstChannelInt16(packet->Header.Data, pInfo->stream->deviceOutputChannels, pInfo->stream->render.framesPerBuffer); + break; + case 3: + DuplicateFirstChannelInt24(packet->Header.Data, pInfo->stream->deviceOutputChannels, pInfo->stream->render.framesPerBuffer); + break; + case 4: + DuplicateFirstChannelInt32(packet->Header.Data, pInfo->stream->deviceOutputChannels, pInfo->stream->render.framesPerBuffer); + break; + default: + assert(0); /* Unsupported format! */ + break; + } + } + PaUtil_EndCpuLoadMeasurement( &pInfo->stream->cpuLoadMeasurer, framesProcessed ); + + if (inputFramesAvailable) + { + PaUtil_AdvanceRingBufferReadIndex(&pInfo->stream->ringBuffer, inputFramesAvailable); + } + + if (pInfo->renderTail != pInfo->renderHead) + { + if (!pInfo->stream->streamStop) + { + result = pInfo->stream->render.pPin->fnSubmitHandler(pInfo, pInfo->renderTail); + if (result != paNoError) + { + PA_HP_TRACE((pInfo->stream->hLog, "Capture submit handler failed with result %d", result)); + return result; + } + } + pInfo->renderTail++; + if (!pInfo->pinsStarted && pInfo->priming == 0) + { + /* We start the pins here to allow "prime time" */ + if ((result = StartPins(pInfo)) == paNoError) + { + PA_HP_TRACE((pInfo->stream->hLog, "Starting pins!")); + pInfo->pinsStarted = 1; + } + } + } + } + + return result; +} + +static VOID CALLBACK TimerAPCWaveRTPolledMode( + LPVOID lpArgToCompletionRoutine, + DWORD dwTimerLowValue, + DWORD dwTimerHighValue) +{ + HANDLE* pHandles = (HANDLE*)lpArgToCompletionRoutine; + if (pHandles[0]) SetEvent(pHandles[0]); + if (pHandles[1]) SetEvent(pHandles[1]); +} + +static DWORD GetCurrentTimeInMillisecs() +{ + return timeGetTime(); +} + +PA_THREAD_FUNC ProcessingThread(void* pParam) +{ + PaError result = paNoError; + HANDLE hAVRT = NULL; + HANDLE hTimer = NULL; + HANDLE *handleArray = NULL; + HANDLE timerEventHandles[2] = {0}; + unsigned noOfHandles = 0; + unsigned captureEvents = 0; + unsigned renderEvents = 0; + unsigned timerPeriod = 0; + DWORD timeStamp[2] = {0}; + + PaProcessThreadInfo info; + memset(&info, 0, sizeof(PaProcessThreadInfo)); + info.stream = (PaWinWdmStream*)pParam; + + info.stream->threadResult = paNoError; + + PA_LOGE_; + + info.ti.inputBufferAdcTime = 0.0; + info.ti.currentTime = 0.0; + info.ti.outputBufferDacTime = 0.0; + + PA_DEBUG(("In buffer len: %.3f ms\n",(2000*info.stream->capture.framesPerBuffer) / info.stream->streamRepresentation.streamInfo.sampleRate)); + PA_DEBUG(("Out buffer len: %.3f ms\n",(2000*info.stream->render.framesPerBuffer) / info.stream->streamRepresentation.streamInfo.sampleRate)); + info.timeout = (DWORD)max( + (2000*info.stream->render.framesPerBuffer/info.stream->streamRepresentation.streamInfo.sampleRate + 0.5), + (2000*info.stream->capture.framesPerBuffer/info.stream->streamRepresentation.streamInfo.sampleRate + 0.5)); + info.timeout = max(info.timeout*8, 100); + timerPeriod = info.timeout; + PA_DEBUG(("Timeout = %ld ms\n",info.timeout)); + + /* Allocate handle array */ + handleArray = (HANDLE*)PaUtil_AllocateMemory((info.stream->capture.noOfPackets + info.stream->render.noOfPackets + 1) * sizeof(HANDLE)); + + /* Setup handle array for WFMO */ + if (info.stream->capture.pPin != 0) + { + handleArray[noOfHandles++] = info.stream->capture.events[0]; + if (info.stream->capture.pPin->parentFilter->devInfo.streamingType == Type_kWaveCyclic) + { + unsigned i; + for(i=1; i < info.stream->capture.noOfPackets; ++i) + { + handleArray[noOfHandles++] = info.stream->capture.events[i]; + } + } + captureEvents = noOfHandles; + renderEvents = noOfHandles; + } + + if (info.stream->render.pPin != 0) + { + handleArray[noOfHandles++] = info.stream->render.events[0]; + if (info.stream->render.pPin->parentFilter->devInfo.streamingType == Type_kWaveCyclic) + { + unsigned i; + for(i=1; i < info.stream->render.noOfPackets; ++i) + { + handleArray[noOfHandles++] = info.stream->render.events[i]; + } + } + renderEvents = noOfHandles; + } + handleArray[noOfHandles++] = info.stream->eventAbort; + assert(noOfHandles <= (info.stream->capture.noOfPackets + info.stream->render.noOfPackets + 1)); + + /* Prepare render and capture pins */ + if ((result = PreparePinsForStart(&info)) != paNoError) + { + PA_DEBUG(("Failed to prepare device(s)!\n")); + goto error; + } + + /* Init high speed logger */ + if (PaUtil_InitializeHighSpeedLog(&info.stream->hLog, 1000000) != paNoError) + { + PA_DEBUG(("Failed to init high speed logger!\n")); + goto error; + } + + /* Heighten priority here */ + hAVRT = BumpThreadPriority(); + + /* If input only, we start the pins immediately */ + if (info.stream->render.pPin == 0) + { + if ((result = StartPins(&info)) != paNoError) + { + PA_DEBUG(("Failed to start device(s)!\n")); + goto error; + } + info.pinsStarted = 1; + } + + /* Handle WaveRT polled mode */ + { + const unsigned fs = (unsigned)info.stream->streamRepresentation.streamInfo.sampleRate; + if (info.stream->capture.pPin != 0 && info.stream->capture.pPin->pinKsSubType == SubType_kPolled) + { + timerEventHandles[0] = info.stream->capture.events[0]; + timerPeriod = min(timerPeriod, (1000*info.stream->capture.framesPerBuffer)/fs); + } + + if (info.stream->render.pPin != 0 && info.stream->render.pPin->pinKsSubType == SubType_kPolled) + { + timerEventHandles[1] = info.stream->render.events[0]; + timerPeriod = min(timerPeriod, (1000*info.stream->render.framesPerBuffer)/fs); + } + + if (timerEventHandles[0] || timerEventHandles[1]) + { + LARGE_INTEGER dueTime = {0}; + + timerPeriod=max(timerPeriod/5,1); + PA_DEBUG(("Timer event handles=0x%04X,0x%04X period=%u ms", timerEventHandles[0], timerEventHandles[1], timerPeriod)); + hTimer = CreateWaitableTimer(0, FALSE, NULL); + if (hTimer == NULL) + { + result = paUnanticipatedHostError; + goto error; + } + /* invoke first timeout immediately */ + if (!SetWaitableTimer(hTimer, &dueTime, timerPeriod, TimerAPCWaveRTPolledMode, timerEventHandles, FALSE)) + { + result = paUnanticipatedHostError; + goto error; + } + PA_DEBUG(("Waitable timer started, period = %u ms\n", timerPeriod)); + } + } + + /* Mark stream as active */ + info.stream->streamActive = 1; + info.stream->threadResult = paNoError; + + /* Up and running... */ + SetEvent(info.stream->eventStreamStart[StreamStart_kOk]); + + /* Take timestamp here */ + timeStamp[0] = timeStamp[1] = GetCurrentTimeInMillisecs(); + + while(!info.stream->streamAbort) + { + unsigned doProcessing = 1; + unsigned wait = WaitForMultipleObjects(noOfHandles, handleArray, FALSE, 0); + unsigned eventSignalled = wait - WAIT_OBJECT_0; + DWORD dwCurrentTime = 0; + + if (wait == WAIT_FAILED) + { + PA_DEBUG(("Wait failed = %ld! \n",wait)); + break; + } + if (wait == WAIT_TIMEOUT) + { + wait = WaitForMultipleObjectsEx(noOfHandles, handleArray, FALSE, 50, TRUE); + eventSignalled = wait - WAIT_OBJECT_0; + } + else + { + if (eventSignalled < captureEvents) + { + if (PaUtil_GetRingBufferWriteAvailable(&info.stream->ringBuffer) == 0) + { + PA_HP_TRACE((info.stream->hLog, "!!!!! Input overflow !!!!!")); + info.underover |= paInputOverflow; + } + } + else if (eventSignalled < renderEvents) + { + if (!info.priming && info.renderHead - info.renderTail > 1) + { + PA_HP_TRACE((info.stream->hLog, "!!!!! Output underflow !!!!!")); + info.underover |= paOutputUnderflow; + } + } + } + + /* Get event time */ + dwCurrentTime = GetCurrentTimeInMillisecs(); + + /* Since we can mix capture/render devices between WaveCyclic, WaveRT polled and WaveRT notification (3x3 combinations), + we can't rely on the timeout of WFMO to check for device timeouts, we need to keep tally. */ + if (info.stream->capture.pPin && (dwCurrentTime - timeStamp[0]) >= info.timeout) + { + PA_DEBUG(("Timeout for capture device (%u ms)!", info.timeout, (dwCurrentTime - timeStamp[0]))); + result = paTimedOut; + break; + } + if (info.stream->render.pPin && (dwCurrentTime - timeStamp[1]) >= info.timeout) + { + PA_DEBUG(("Timeout for render device (%u ms)!", info.timeout, (dwCurrentTime - timeStamp[1]))); + result = paTimedOut; + break; + } + + if (wait == WAIT_IO_COMPLETION) + { + /* Waitable timer has fired! */ + PA_HP_TRACE((info.stream->hLog, "WAIT_IO_COMPLETION")); + continue; + } + + if (wait == WAIT_TIMEOUT) + { + continue; + } + else + { + if (eventSignalled < captureEvents) + { + if (info.stream->capture.pPin->fnEventHandler(&info, eventSignalled) == paNoError) + { + timeStamp[0] = dwCurrentTime; + + /* Since we use the ring buffer, we can submit the buffers directly */ + if (!info.stream->streamStop) + { + result = info.stream->capture.pPin->fnSubmitHandler(&info, info.captureTail); + if (result != paNoError) + { + PA_HP_TRACE((info.stream->hLog, "Capture submit handler failed with result %d", result)); + break; + } + } + ++info.captureTail; + /* If full-duplex, let _only_ render event trigger processing. We still need the stream stop + handling working, so let that be processed anyways... */ + if (info.stream->userOutputChannels > 0) + { + doProcessing = 0; + } + } + } + else if (eventSignalled < renderEvents) + { + timeStamp[1] = dwCurrentTime; + eventSignalled -= captureEvents; + info.stream->render.pPin->fnEventHandler(&info, eventSignalled); + } + else + { + assert(info.stream->streamAbort); + PA_HP_TRACE((info.stream->hLog, "Stream abort!")); + continue; + } + } + + /* Handle processing */ + if (doProcessing) + { + result = PaDoProcessing(&info); + if (result != paNoError) + { + PA_HP_TRACE((info.stream->hLog, "PaDoProcessing failed!")); + break; + } + } + + if(info.stream->streamStop && info.cbResult != paComplete) + { + PA_HP_TRACE((info.stream->hLog, "Stream stop! pending=%d",info.pending)); + info.cbResult = paComplete; /* Stop, but play remaining buffers */ + } + + if(info.pending<=0) + { + PA_HP_TRACE((info.stream->hLog, "pending==0 finished...")); + break; + } + if((!info.stream->render.pPin)&&(info.cbResult!=paContinue)) + { + PA_HP_TRACE((info.stream->hLog, "record only cbResult=%d...",info.cbResult)); + break; + } + } + + PA_DEBUG(("Finished processing loop\n")); + + info.stream->threadResult = result; + goto bailout; + +error: + PA_DEBUG(("Error starting processing thread\n")); + /* Set the "error" event together with result */ + info.stream->threadResult = result; + SetEvent(info.stream->eventStreamStart[StreamStart_kFailed]); + +bailout: + if (hTimer) + { + PA_DEBUG(("Waitable timer stopped\n", timerPeriod)); + CancelWaitableTimer(hTimer); + CloseHandle(hTimer); + hTimer = 0; + } + + if (info.pinsStarted) + { + StopPins(&info); + } + + /* Lower prio here */ + DropThreadPriority(hAVRT); + + if (handleArray != NULL) + { + PaUtil_FreeMemory(handleArray); + } + +#if PA_TRACE_REALTIME_EVENTS + if (info.stream->hLog) + { + PA_DEBUG(("Dumping highspeed trace...\n")); + PaUtil_DumpHighSpeedLog(info.stream->hLog, "hp_trace.log"); + PaUtil_DiscardHighSpeedLog(info.stream->hLog); + info.stream->hLog = 0; + } +#endif + info.stream->streamActive = 0; + + if((!info.stream->streamStop)&&(!info.stream->streamAbort)) + { + /* Invoke the user stream finished callback */ + /* Only do it from here if not being stopped/aborted by user */ + if( info.stream->streamRepresentation.streamFinishedCallback != 0 ) + info.stream->streamRepresentation.streamFinishedCallback( info.stream->streamRepresentation.userData ); + } + info.stream->streamStop = 0; + info.stream->streamAbort = 0; + + PA_LOGL_; + return 0; +} + + +static PaError StartStream( PaStream *s ) +{ + PaError result = paNoError; + PaWinWdmStream *stream = (PaWinWdmStream*)s; + + PA_LOGE_; + + if (stream->streamThread != NULL) + { + return paStreamIsNotStopped; + } + + stream->streamStop = 0; + stream->streamAbort = 0; + + ResetStreamEvents(stream); + + PaUtil_ResetBufferProcessor( &stream->bufferProcessor ); + + stream->oldProcessPriority = GetPriorityClass(GetCurrentProcess()); + /* Uncomment the following line to enable dynamic boosting of the process + * priority to real time for best low latency support + * Disabled by default because RT processes can easily block the OS */ + /*ret = SetPriorityClass(GetCurrentProcess(),REALTIME_PRIORITY_CLASS); + PA_DEBUG(("Class ret = %d;",ret));*/ + + stream->streamThread = CREATE_THREAD_FUNCTION (NULL, 0, ProcessingThread, stream, CREATE_SUSPENDED, NULL); + if(stream->streamThread == NULL) + { + result = paInsufficientMemory; + goto end; + } + ResumeThread(stream->streamThread); + + switch (WaitForMultipleObjects(2, stream->eventStreamStart, FALSE, 5000)) + { + case WAIT_OBJECT_0 + StreamStart_kOk: + PA_DEBUG(("Processing thread started!\n")); + result = paNoError; + /* streamActive is set in processing thread */ + stream->streamStarted = 1; + break; + case WAIT_OBJECT_0 + StreamStart_kFailed: + PA_DEBUG(("Processing thread start failed! (result=%d)\n", stream->threadResult)); + result = stream->threadResult; + /* Wait for the stream to really exit */ + WaitForSingleObject(stream->streamThread, 200); + CloseHandle(stream->streamThread); + stream->streamThread = 0; + break; + case WAIT_TIMEOUT: + default: + result = paTimedOut; + PaWinWDM_SetLastErrorInfo(result, "Failed to start processing thread (timeout)!"); + break; + } + +end: + PA_LOGL_; + return result; +} + + +static PaError StopStream( PaStream *s ) +{ + PaError result = paNoError; + PaWinWdmStream *stream = (PaWinWdmStream*)s; + BOOL doCb = FALSE; + + PA_LOGE_; + + if(stream->streamActive) + { + DWORD dwExitCode; + doCb = TRUE; + stream->streamStop = 1; + if (GetExitCodeThread(stream->streamThread, &dwExitCode) && dwExitCode == STILL_ACTIVE) + { + if (WaitForSingleObject(stream->streamThread, INFINITE) != WAIT_OBJECT_0) + { + PA_DEBUG(("StopStream: stream thread terminated\n")); + TerminateThread(stream->streamThread, -1); + result = paTimedOut; + } + } + else + { + PA_DEBUG(("StopStream: GECT says not active, but streamActive is not false ??")); + result = paUnanticipatedHostError; + PaWinWDM_SetLastErrorInfo(result, "StopStream: GECT says not active, but streamActive = %d", stream->streamActive); + } + } + else + { + if (stream->threadResult != paNoError) + { + PA_DEBUG(("StopStream: Stream not active (%d)\n", stream->threadResult)); + result = stream->threadResult; + stream->threadResult = paNoError; + } + } + + if (stream->streamThread != NULL) + { + CloseHandle(stream->streamThread); + stream->streamThread = 0; + } + stream->streamStarted = 0; + stream->streamActive = 0; + + if(doCb) + { + /* Do user callback now after all state has been reset */ + /* This means it should be safe for the called function */ + /* to invoke e.g. StartStream */ + if( stream->streamRepresentation.streamFinishedCallback != 0 ) + stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData ); + } + + PA_LOGL_; + return result; +} + +static PaError AbortStream( PaStream *s ) +{ + PaError result = paNoError; + PaWinWdmStream *stream = (PaWinWdmStream*)s; + int doCb = 0; + + PA_LOGE_; + + if(stream->streamActive) + { + doCb = 1; + stream->streamAbort = 1; + SetEvent(stream->eventAbort); /* Signal immediately */ + if (WaitForSingleObject(stream->streamThread, 10000) != WAIT_OBJECT_0) + { + TerminateThread(stream->streamThread, -1); + result = paTimedOut; + + PA_DEBUG(("AbortStream: stream thread terminated\n")); + } + assert(!stream->streamActive); + } + CloseHandle(stream->streamThread); + stream->streamThread = NULL; + stream->streamStarted = 0; + + if(doCb) + { + /* Do user callback now after all state has been reset */ + /* This means it should be safe for the called function */ + /* to invoke e.g. StartStream */ + if( stream->streamRepresentation.streamFinishedCallback != 0 ) + stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData ); + } + + stream->streamActive = 0; + stream->streamStarted = 0; + + PA_LOGL_; + return result; +} + + +static PaError IsStreamStopped( PaStream *s ) +{ + PaWinWdmStream *stream = (PaWinWdmStream*)s; + int result = 0; + + PA_LOGE_; + + if(!stream->streamStarted) + result = 1; + + PA_LOGL_; + return result; +} + + +static PaError IsStreamActive( PaStream *s ) +{ + PaWinWdmStream *stream = (PaWinWdmStream*)s; + int result = 0; + + PA_LOGE_; + + if(stream->streamActive) + result = 1; + + PA_LOGL_; + return result; +} + + +static PaTime GetStreamTime( PaStream* s ) +{ + PA_LOGE_; + PA_LOGL_; + (void)s; + return PaUtil_GetTime(); +} + + +static double GetStreamCpuLoad( PaStream* s ) +{ + PaWinWdmStream *stream = (PaWinWdmStream*)s; + double result; + PA_LOGE_; + result = PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer ); + PA_LOGL_; + return result; +} + + +/* +As separate stream interfaces are used for blocking and callback +streams, the following functions can be guaranteed to only be called +for blocking streams. +*/ + +static PaError ReadStream( PaStream* s, + void *buffer, + unsigned long frames ) +{ + PaWinWdmStream *stream = (PaWinWdmStream*)s; + + PA_LOGE_; + + /* suppress unused variable warnings */ + (void) buffer; + (void) frames; + (void) stream; + + /* IMPLEMENT ME, see portaudio.h for required behavior*/ + PA_LOGL_; + return paInternalError; +} + + +static PaError WriteStream( PaStream* s, + const void *buffer, + unsigned long frames ) +{ + PaWinWdmStream *stream = (PaWinWdmStream*)s; + + PA_LOGE_; + + /* suppress unused variable warnings */ + (void) buffer; + (void) frames; + (void) stream; + + /* IMPLEMENT ME, see portaudio.h for required behavior*/ + PA_LOGL_; + return paInternalError; +} + + +static signed long GetStreamReadAvailable( PaStream* s ) +{ + PaWinWdmStream *stream = (PaWinWdmStream*)s; + + PA_LOGE_; + + /* suppress unused variable warnings */ + (void) stream; + + /* IMPLEMENT ME, see portaudio.h for required behavior*/ + PA_LOGL_; + return 0; +} + + +static signed long GetStreamWriteAvailable( PaStream* s ) +{ + PaWinWdmStream *stream = (PaWinWdmStream*)s; + + PA_LOGE_; + /* suppress unused variable warnings */ + (void) stream; + + /* IMPLEMENT ME, see portaudio.h for required behavior*/ + PA_LOGL_; + return 0; +} + +/***************************************************************************************/ +/* Event and submit handlers for WaveCyclic */ +/***************************************************************************************/ + +static PaError PaPinCaptureEventHandler_WaveCyclic(PaProcessThreadInfo* pInfo, unsigned eventIndex) +{ + PaError result = paNoError; + ring_buffer_size_t frameCount; + DATAPACKET* packet = pInfo->stream->capture.packets + eventIndex; + + assert( eventIndex < pInfo->stream->capture.noOfPackets ); + + if (packet->Header.DataUsed == 0) + { + PA_HP_TRACE((pInfo->stream->hLog, ">>> Capture bogus event (no data): idx=%u", eventIndex)); + + /* Bogus event, reset! This is to handle the behavior of this USB mic: http://shop.xtz.se/measurement-system/microphone-to-dirac-live-room-correction-suite + on startup of streaming, where it erroneously sets the event without the corresponding buffer being filled (DataUsed == 0) */ + ResetEvent(packet->Signal.hEvent); + + result = -1; /* Only need this to be NOT paNoError */ + } + else + { + pInfo->capturePackets[pInfo->captureHead & cPacketsArrayMask].packet = packet; + + frameCount = PaUtil_WriteRingBuffer(&pInfo->stream->ringBuffer, packet->Header.Data, pInfo->stream->capture.framesPerBuffer); + + PA_HP_TRACE((pInfo->stream->hLog, ">>> Capture event: idx=%u (frames=%u)", eventIndex, frameCount)); + ++pInfo->captureHead; + } + + --pInfo->pending; /* This needs to be done in either case */ + return result; +} + +static PaError PaPinCaptureSubmitHandler_WaveCyclic(PaProcessThreadInfo* pInfo, unsigned eventIndex) +{ + PaError result = paNoError; + DATAPACKET* packet = pInfo->capturePackets[pInfo->captureTail & cPacketsArrayMask].packet; + pInfo->capturePackets[pInfo->captureTail & cPacketsArrayMask].packet = 0; + assert(packet != 0); + PA_HP_TRACE((pInfo->stream->hLog, "Capture submit: %u", eventIndex)); + packet->Header.DataUsed = 0; /* Reset for reuse */ + ResetEvent(packet->Signal.hEvent); + result = PinRead(pInfo->stream->capture.pPin->handle, packet); + ++pInfo->pending; + return result; +} + +static PaError PaPinRenderEventHandler_WaveCyclic(PaProcessThreadInfo* pInfo, unsigned eventIndex) +{ + assert( eventIndex < pInfo->stream->render.noOfPackets ); + + pInfo->renderPackets[pInfo->renderHead & cPacketsArrayMask].packet = pInfo->stream->render.packets + eventIndex; + PA_HP_TRACE((pInfo->stream->hLog, "<<< Render event : idx=%u head=%u", eventIndex, pInfo->renderHead)); + ++pInfo->renderHead; + --pInfo->pending; + return paNoError; +} + +static PaError PaPinRenderSubmitHandler_WaveCyclic(PaProcessThreadInfo* pInfo, unsigned eventIndex) +{ + PaError result = paNoError; + DATAPACKET* packet = pInfo->renderPackets[pInfo->renderTail & cPacketsArrayMask].packet; + pInfo->renderPackets[pInfo->renderTail & cPacketsArrayMask].packet = 0; + assert(packet != 0); + + PA_HP_TRACE((pInfo->stream->hLog, "Render submit : %u idx=%u", pInfo->renderTail, (unsigned)(packet - pInfo->stream->render.packets))); + ResetEvent(packet->Signal.hEvent); + result = PinWrite(pInfo->stream->render.pPin->handle, packet); + /* Reset event, just in case we have an analogous situation to capture (see PaPinCaptureSubmitHandler_WaveCyclic) */ + ++pInfo->pending; + if (pInfo->priming) + { + --pInfo->priming; + } + return result; +} + +/***************************************************************************************/ +/* Event and submit handlers for WaveRT */ +/***************************************************************************************/ + +static PaError PaPinCaptureEventHandler_WaveRTEvent(PaProcessThreadInfo* pInfo, unsigned eventIndex) +{ + unsigned long pos; + unsigned realInBuf; + unsigned frameCount; + PaWinWdmIOInfo* pCapture = &pInfo->stream->capture; + const unsigned halfInputBuffer = pCapture->hostBufferSize >> 1; + PaWinWdmPin* pin = pCapture->pPin; + DATAPACKET* packet = 0; + + /* Get hold of current ADC position */ + pin->fnAudioPosition(pin, &pos); + /* Wrap it (robi: why not use hw latency compensation here ?? because pos then gets _way_ off from + where it should be, i.e. at beginning or half buffer position. Why? No idea.) */ + + pos %= pCapture->hostBufferSize; + /* Then realInBuf will point to "other" half of double buffer */ + realInBuf = pos < halfInputBuffer ? 1U : 0U; + + packet = pInfo->stream->capture.packets + realInBuf; + + /* Call barrier (or dummy) */ + pin->fnMemBarrier(); + + /* Put it in queue */ + frameCount = PaUtil_WriteRingBuffer(&pInfo->stream->ringBuffer, packet->Header.Data, pCapture->framesPerBuffer); + + pInfo->capturePackets[pInfo->captureHead & cPacketsArrayMask].packet = packet; + + PA_HP_TRACE((pInfo->stream->hLog, "Capture event (WaveRT): idx=%u head=%u (pos = %4.1lf%%, frames=%u)", realInBuf, pInfo->captureHead, (pos * 100.0 / pCapture->hostBufferSize), frameCount)); + + ++pInfo->captureHead; + --pInfo->pending; + + return paNoError; +} + +static PaError PaPinCaptureEventHandler_WaveRTPolled(PaProcessThreadInfo* pInfo, unsigned eventIndex) +{ + unsigned long pos; + unsigned bytesToRead; + PaWinWdmIOInfo* pCapture = &pInfo->stream->capture; + const unsigned halfInputBuffer = pCapture->hostBufferSize>>1; + PaWinWdmPin* pin = pInfo->stream->capture.pPin; + + /* Get hold of current ADC position */ + pin->fnAudioPosition(pin, &pos); + /* Wrap it (robi: why not use hw latency compensation here ?? because pos then gets _way_ off from + where it should be, i.e. at beginning or half buffer position. Why? No idea.) */ + /* Compensate for HW FIFO to get to last read buffer position */ + pos += pin->hwLatency; + pos %= pCapture->hostBufferSize; + /* Need to align position on frame boundary */ + pos &= ~(pCapture->bytesPerFrame - 1); + + /* Call barrier (or dummy) */ + pin->fnMemBarrier(); + + /* Put it in "queue" */ + bytesToRead = (pCapture->hostBufferSize + pos - pCapture->lastPosition) % pCapture->hostBufferSize; + if (bytesToRead > 0) + { + unsigned frameCount = PaUtil_WriteRingBuffer(&pInfo->stream->ringBuffer, + pCapture->hostBuffer + pCapture->lastPosition, + bytesToRead / pCapture->bytesPerFrame); + + pCapture->lastPosition = (pCapture->lastPosition + frameCount * pCapture->bytesPerFrame) % pCapture->hostBufferSize; + + PA_HP_TRACE((pInfo->stream->hLog, "Capture event (WaveRTPolled): pos = %4.1lf%%, framesRead=%u", (pos * 100.0 / pCapture->hostBufferSize), frameCount)); + ++pInfo->captureHead; + --pInfo->pending; + } + return paNoError; +} + +static PaError PaPinCaptureSubmitHandler_WaveRTEvent(PaProcessThreadInfo* pInfo, unsigned eventIndex) +{ + pInfo->capturePackets[pInfo->captureTail & cPacketsArrayMask].packet = 0; + ++pInfo->pending; + return paNoError; +} + +static PaError PaPinCaptureSubmitHandler_WaveRTPolled(PaProcessThreadInfo* pInfo, unsigned eventIndex) +{ + pInfo->capturePackets[pInfo->captureTail & cPacketsArrayMask].packet = 0; + ++pInfo->pending; + return paNoError; +} + +static PaError PaPinRenderEventHandler_WaveRTEvent(PaProcessThreadInfo* pInfo, unsigned eventIndex) +{ + unsigned long pos; + unsigned realOutBuf; + PaWinWdmIOInfo* pRender = &pInfo->stream->render; + const unsigned halfOutputBuffer = pRender->hostBufferSize >> 1; + PaWinWdmPin* pin = pInfo->stream->render.pPin; + PaIOPacket* ioPacket = &pInfo->renderPackets[pInfo->renderHead & cPacketsArrayMask]; + + /* Get hold of current DAC position */ + pin->fnAudioPosition(pin, &pos); + /* Compensate for HW FIFO to get to last read buffer position */ + pos += pin->hwLatency; + /* Wrap it */ + pos %= pRender->hostBufferSize; + /* And align it, not sure its really needed though */ + pos &= ~(pRender->bytesPerFrame - 1); + /* Then realOutBuf will point to "other" half of double buffer */ + realOutBuf = pos < halfOutputBuffer ? 1U : 0U; + + if (pInfo->priming) + { + realOutBuf = pInfo->renderHead & 0x1; + } + ioPacket->packet = pInfo->stream->render.packets + realOutBuf; + ioPacket->startByte = realOutBuf * halfOutputBuffer; + ioPacket->lengthBytes = halfOutputBuffer; + + PA_HP_TRACE((pInfo->stream->hLog, "Render event (WaveRT) : idx=%u head=%u (pos = %4.1lf%%)", realOutBuf, pInfo->renderHead, (pos * 100.0 / pRender->hostBufferSize) )); + + ++pInfo->renderHead; + --pInfo->pending; + return paNoError; +} + +static PaError PaPinRenderEventHandler_WaveRTPolled(PaProcessThreadInfo* pInfo, unsigned eventIndex) +{ + unsigned long pos; + unsigned realOutBuf; + unsigned bytesToWrite; + + PaWinWdmIOInfo* pRender = &pInfo->stream->render; + const unsigned halfOutputBuffer = pRender->hostBufferSize >> 1; + PaWinWdmPin* pin = pInfo->stream->render.pPin; + PaIOPacket* ioPacket = &pInfo->renderPackets[pInfo->renderHead & cPacketsArrayMask]; + + /* Get hold of current DAC position */ + pin->fnAudioPosition(pin, &pos); + /* Compensate for HW FIFO to get to last read buffer position */ + pos += pin->hwLatency; + /* Wrap it */ + pos %= pRender->hostBufferSize; + /* And align it, not sure its really needed though */ + pos &= ~(pRender->bytesPerFrame - 1); + + if (pInfo->priming) + { + realOutBuf = pInfo->renderHead & 0x1; + ioPacket->packet = pInfo->stream->render.packets + realOutBuf; + ioPacket->startByte = realOutBuf * halfOutputBuffer; + ioPacket->lengthBytes = halfOutputBuffer; + ++pInfo->renderHead; + --pInfo->pending; + } + else + { + bytesToWrite = (pRender->hostBufferSize + pos - pRender->lastPosition) % pRender->hostBufferSize; + ++pRender->pollCntr; + if (bytesToWrite >= halfOutputBuffer) + { + realOutBuf = (pos < halfOutputBuffer) ? 1U : 0U; + ioPacket->packet = pInfo->stream->render.packets + realOutBuf; + pRender->lastPosition = realOutBuf ? 0U : halfOutputBuffer; + ioPacket->startByte = realOutBuf * halfOutputBuffer; + ioPacket->lengthBytes = halfOutputBuffer; + ++pInfo->renderHead; + --pInfo->pending; + PA_HP_TRACE((pInfo->stream->hLog, "Render event (WaveRTPolled) : idx=%u head=%u (pos = %4.1lf%%, cnt=%u)", realOutBuf, pInfo->renderHead, (pos * 100.0 / pRender->hostBufferSize), pRender->pollCntr)); + pRender->pollCntr = 0; + } + } + return paNoError; +} + +static PaError PaPinRenderSubmitHandler_WaveRTEvent(PaProcessThreadInfo* pInfo, unsigned eventIndex) +{ + PaWinWdmPin* pin = pInfo->stream->render.pPin; + pInfo->renderPackets[pInfo->renderTail & cPacketsArrayMask].packet = 0; + /* Call barrier (if needed) */ + pin->fnMemBarrier(); + PA_HP_TRACE((pInfo->stream->hLog, "Render submit (WaveRT) : submit=%u", pInfo->renderTail)); + ++pInfo->pending; + if (pInfo->priming) + { + --pInfo->priming; + if (pInfo->priming) + { + PA_HP_TRACE((pInfo->stream->hLog, "Setting WaveRT event for priming (2)")); + SetEvent(pInfo->stream->render.events[0]); + } + } + return paNoError; +} + +static PaError PaPinRenderSubmitHandler_WaveRTPolled(PaProcessThreadInfo* pInfo, unsigned eventIndex) +{ + PaWinWdmPin* pin = pInfo->stream->render.pPin; + pInfo->renderPackets[pInfo->renderTail & cPacketsArrayMask].packet = 0; + /* Call barrier (if needed) */ + pin->fnMemBarrier(); + PA_HP_TRACE((pInfo->stream->hLog, "Render submit (WaveRTPolled) : submit=%u", pInfo->renderTail)); + ++pInfo->pending; + if (pInfo->priming) + { + --pInfo->priming; + if (pInfo->priming) + { + PA_HP_TRACE((pInfo->stream->hLog, "Setting WaveRT event for priming (2)")); + SetEvent(pInfo->stream->render.events[0]); + } + } + return paNoError; +} diff --git a/extern/portaudio/src/hostapi/wdmks/readme.txt b/extern/portaudio/src/hostapi/wdmks/readme.txt new file mode 100644 index 0000000..c4c349c --- /dev/null +++ b/extern/portaudio/src/hostapi/wdmks/readme.txt @@ -0,0 +1,85 @@ +Notes about WDM-KS host API +--------------------------- + +Status history +-------------- +16th January 2011: +Added support for WaveRT device API (Vista and later) for even lesser +latency support. + +10th November 2005: +Made following changes: + * OpenStream: Try all PaSampleFormats internally if the the chosen + format is not supported natively. This fixed several problems + with soundcards that did not take kindly to using 24-bit 3-byte formats. + * OpenStream: Make the minimum framesPerHostIBuffer (and framesPerHostOBuffer) + the default frameSize for the playback/recording pin. + * ProcessingThread: Added a switch to only call PaUtil_EndBufferProcessing + if the total input frames equals the total output frames + +5th September 2004: +This is the first public version of the code. It should be considered +an alpha release with zero guarantee not to crash on any particular +system. So far it has only been tested in the author's development +environment, which means a Win2k/SP2 PIII laptop with integrated +SoundMAX driver and USB Tascam US-428 compiled with both MinGW +(GCC 3.3) and MSVC++6 using the MS DirectX 9 SDK. +It has been most widely tested with the MinGW build, with most of the +test programs (particularly paqa_devs and paqa_errs) passing. +There are some notable failures: patest_out_underflow and both of the +blocking I/O tests (as blocking I/O is not implemented). +At this point the code needs to be tested with a much wider variety +of configurations and feedback provided from testers regarding +both working and failing cases. + +What is the WDM-KS host API? +---------------------------- +PortAudio for Windows currently has 3 functional host implementations. +MME uses the oldest Windows audio API which does not offer good +play/record latency. +DirectX improves this, but still imposes a penalty +of 10s of milliseconds due to the system mixing of streams from +multiple applications. +ASIO offers very good latency, but requires special drivers which are +not always available for cheaper audio hardware. Also, when ASIO +drivers are available, they are not always so robust because they +bypass all of the standardised Windows device driver architecture +and hit the hardware their own way. +Alternatively there are a couple of free (but closed source) ASIO +implementations which connect to the lower level Windows +"Kernel Streaming" API, but again these require special installation +by the user, and can be limited in functionality or difficult to use. + +This is where the PortAudio "WDM-KS" host implementation comes in. +It directly connects PortAudio to the same Kernel Streaming API which +those ASIO bridges use. This avoids the mixing penatly of DirectX, +giving at least as good latency as any ASIO driver, but it has the +advantage of working with ANY Windows audio hardware which is available +through the normal MME/DirectX routes without the user requiring +any additional device drivers to be installed, and allowing all +device selection to be done through the normal PortAudio API. + +Note that in general you should only be using this host API if your +application has a real requirement for very low latency audio (<20ms), +either because you are generating sounds in real-time based upon +user input, or you a processing recorded audio in real time. + +The only thing to be aware of is that using the KS interface will +block that device from being used by the rest of system through +the higher level APIs, or conversely, if the system is using +a device, the KS API will not be able to use it. MS recommend that +you should keep the device open only when your application has focus. +In PortAudio terms, this means having a stream Open on a WDMKS device. + +Usage +----- +To add the WDMKS backend to your program which is already using +PortAudio, you must define PA_USE_WDMKS=1 in your build file, +and include the pa_win_wdmks\pa_win_wdmks.c into your build. +The file should compile in both C and C++. +You will need a DirectX SDK installed on your system for the +ks.h and ksmedia.h header files. +You will need to link to the system "setupapi" library. +Note that if you use MinGW, you will get more warnings from +the DX header files when using GCC(C), and still a few warnings +with G++(CPP). diff --git a/extern/portaudio/src/hostapi/wmme/pa_win_wmme.c b/extern/portaudio/src/hostapi/wmme/pa_win_wmme.c new file mode 100644 index 0000000..422c867 --- /dev/null +++ b/extern/portaudio/src/hostapi/wmme/pa_win_wmme.c @@ -0,0 +1,4055 @@ +/* + * $Id$ + * pa_win_wmme.c + * Implementation of PortAudio for Windows MultiMedia Extensions (WMME) + * + * PortAudio Portable Real-Time Audio Library + * Latest Version at: http://www.portaudio.com + * + * Authors: Ross Bencina and Phil Burk + * Copyright (c) 1999-2000 Ross Bencina and Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +/* Modification History: + PLB = Phil Burk + JM = Julien Maillard + RDB = Ross Bencina + PLB20010402 - sDevicePtrs now allocates based on sizeof(pointer) + PLB20010413 - check for excessive numbers of channels + PLB20010422 - apply Mike Berry's changes for CodeWarrior on PC + including conditional inclusion of memory.h, + and explicit typecasting on memory allocation + PLB20010802 - use GlobalAlloc for sDevicesPtr instead of PaHost_AllocFastMemory + PLB20010816 - pass process instead of thread to SetPriorityClass() + PLB20010927 - use number of frames instead of real-time for CPULoad calculation. + JM20020118 - prevent hung thread when buffers underflow. + PLB20020321 - detect Win XP versus NT, 9x; fix DBUG typo; removed init of CurrentCount + RDB20020411 - various renaming cleanups, factored streamData alloc and cpu usage init + RDB20020417 - stopped counting WAVE_MAPPER when there were no real devices + refactoring, renaming and fixed a few edge case bugs + RDB20020531 - converted to V19 framework + ** NOTE maintanance history is now stored in CVS ** +*/ + +/** @file + @ingroup hostapi_src + + @brief Win32 host API implementation for the Windows MultiMedia Extensions (WMME) audio API. +*/ + +/* + How it works: + + For both callback and blocking read/write streams we open the MME devices + in CALLBACK_EVENT mode. In this mode, MME signals an Event object whenever + it has finished with a buffer (either filled it for input, or played it + for output). Where necessary, we block waiting for Event objects using + WaitMultipleObjects(). + + When implementing a PA callback stream, we set up a high priority thread + which waits on the MME buffer Events and drains/fills the buffers when + they are ready. + + When implementing a PA blocking read/write stream, we simply wait on these + Events (when necessary) inside the ReadStream() and WriteStream() functions. +*/ + +#include +#include +#include +#include +#include +#include +#ifndef UNDER_CE +#include +#endif +#include +/* PLB20010422 - "memory.h" doesn't work on CodeWarrior for PC. Thanks Mike Berry for the mod. */ +#ifndef __MWERKS__ +#include +#include +#endif /* __MWERKS__ */ + +#include "portaudio.h" +#include "pa_trace.h" +#include "pa_util.h" +#include "pa_allocation.h" +#include "pa_hostapi.h" +#include "pa_stream.h" +#include "pa_cpuload.h" +#include "pa_process.h" +#include "pa_debugprint.h" + +#include "pa_win_wmme.h" +#include "pa_win_waveformat.h" + +#ifdef PAWIN_USE_WDMKS_DEVICE_INFO +#include "pa_win_wdmks_utils.h" +#ifndef DRV_QUERYDEVICEINTERFACE +#define DRV_QUERYDEVICEINTERFACE (DRV_RESERVED + 12) +#endif +#ifndef DRV_QUERYDEVICEINTERFACESIZE +#define DRV_QUERYDEVICEINTERFACESIZE (DRV_RESERVED + 13) +#endif +#endif /* PAWIN_USE_WDMKS_DEVICE_INFO */ + +/* use CreateThread for CYGWIN, _beginthreadex for all others */ +#if !defined(__CYGWIN__) && !defined(_WIN32_WCE) +#define CREATE_THREAD (HANDLE)_beginthreadex( 0, 0, ProcessingThreadProc, stream, 0, &stream->processingThreadId ) +#define PA_THREAD_FUNC static unsigned WINAPI +#define PA_THREAD_ID unsigned +#else +#define CREATE_THREAD CreateThread( 0, 0, ProcessingThreadProc, stream, 0, &stream->processingThreadId ) +#define PA_THREAD_FUNC static DWORD WINAPI +#define PA_THREAD_ID DWORD +#endif +#if (defined(_WIN32_WCE)) +#pragma comment(lib, "Coredll.lib") +#elif (defined(WIN32) && (defined(_MSC_VER) && (_MSC_VER >= 1200))) /* MSC version 6 and above */ +#pragma comment(lib, "winmm.lib") +#endif + +/* + provided in newer platform sdks + */ +#ifndef DWORD_PTR + #if defined(_WIN64) + #define DWORD_PTR unsigned __int64 + #else + #define DWORD_PTR unsigned long + #endif +#endif + +/************************************************* Constants ********/ + +#define PA_MME_USE_HIGH_DEFAULT_LATENCY_ (0) /* For debugging glitches. */ + +#if PA_MME_USE_HIGH_DEFAULT_LATENCY_ + #define PA_MME_WIN_9X_DEFAULT_LATENCY_ (0.4) + #define PA_MME_MIN_HOST_OUTPUT_BUFFER_COUNT_ (4) + #define PA_MME_MIN_HOST_INPUT_BUFFER_COUNT_FULL_DUPLEX_ (4) + #define PA_MME_MIN_HOST_INPUT_BUFFER_COUNT_HALF_DUPLEX_ (4) + #define PA_MME_HOST_BUFFER_GRANULARITY_FRAMES_WHEN_UNSPECIFIED_ (16) + #define PA_MME_MAX_HOST_BUFFER_SECS_ (0.3) /* Do not exceed unless user buffer exceeds */ + #define PA_MME_MAX_HOST_BUFFER_BYTES_ (32 * 1024) /* Has precedence over PA_MME_MAX_HOST_BUFFER_SECS_, some drivers are known to crash with buffer sizes > 32k */ +#else + #define PA_MME_WIN_9X_DEFAULT_LATENCY_ (0.2) + #define PA_MME_MIN_HOST_OUTPUT_BUFFER_COUNT_ (2) + #define PA_MME_MIN_HOST_INPUT_BUFFER_COUNT_FULL_DUPLEX_ (3) /* always use at least 3 input buffers for full duplex */ + #define PA_MME_MIN_HOST_INPUT_BUFFER_COUNT_HALF_DUPLEX_ (2) + #define PA_MME_HOST_BUFFER_GRANULARITY_FRAMES_WHEN_UNSPECIFIED_ (16) + #define PA_MME_MAX_HOST_BUFFER_SECS_ (0.1) /* Do not exceed unless user buffer exceeds */ + #define PA_MME_MAX_HOST_BUFFER_BYTES_ (32 * 1024) /* Has precedence over PA_MME_MAX_HOST_BUFFER_SECS_, some drivers are known to crash with buffer sizes > 32k */ +#endif + +/* Use higher latency for NT because it is even worse at real-time + operation than Win9x. +*/ +#define PA_MME_WIN_NT_DEFAULT_LATENCY_ (0.4) + +/* Default low latency for WDM based systems. This is based on a rough + survey of workable latency settings using patest_wmme_find_best_latency_params.c. + See pdf attached to ticket 185 for a graph of the survey results: + http://www.portaudio.com/trac/ticket/185 + + Workable latencies varied between 40ms and ~80ms on different systems (different + combinations of hardware, 32 and 64 bit, WinXP, Vista and Win7. We didn't + get enough Vista results to know if Vista has systemically worse latency. + For now we choose a safe value across all Windows versions here. +*/ +#define PA_MME_WIN_WDM_DEFAULT_LATENCY_ (0.090) + + +/* When client suggestedLatency could result in many host buffers, we aim to have around 8, + based off Windows documentation that suggests that the kmixer uses 8 buffers. This choice + is somewhat arbitrary here, since we havn't observed significant stability degredation + with using either more, or less buffers. +*/ +#define PA_MME_TARGET_HOST_BUFFER_COUNT_ 8 + +#define PA_MME_MIN_TIMEOUT_MSEC_ (1000) + +static const char constInputMapperSuffix_[] = " - Input"; +static const char constOutputMapperSuffix_[] = " - Output"; + +/********************************************************************/ + +/* Copy null-terminated TCHAR string to explicit char string using UTF8 encoding */ +static char *CopyTCharStringToUtf8CString(char *destination, size_t destLengthBytes, const TCHAR *source) +{ +#if !defined(_UNICODE) && !defined(UNICODE) + return strcpy(destination, source); +#else + /* The cbMultiByte parameter ["destLengthBytes" below] is: + """ + Size, in bytes, of the buffer indicated by lpMultiByteStr ["destination" below]. + If this parameter is set to 0, the function returns the required buffer + size for lpMultiByteStr and makes no use of the output parameter itself. + """ + Source: WideCharToMultiByte at MSDN: + http://msdn.microsoft.com/en-us/library/windows/desktop/dd374130(v=vs.85).aspx + */ + int intDestLengthBytes; /* cbMultiByte */ + /* intDestLengthBytes is an int, destLengthBytes is a size_t. Ensure that we don't overflow + intDestLengthBytes by only using at most INT_MAX bytes of destination buffer. + */ + if (destLengthBytes < INT_MAX) + { +#pragma warning (disable : 4267) /* "conversion from 'size_t' to 'int', possible loss of data" */ + intDestLengthBytes = (int)destLengthBytes; /* destLengthBytes is guaranteed < INT_MAX here */ +#pragma warning (default : 4267) + } + else + { + intDestLengthBytes = INT_MAX; + } + + if (WideCharToMultiByte(CP_UTF8, 0, source, -1, destination, /*cbMultiByte=*/intDestLengthBytes, NULL, NULL) == 0) + return NULL; + return destination; +#endif +} + +/* returns required length (in bytes) of destination buffer when + converting TCHAR string to UTF8 bytes, not including the terminating null. */ +static size_t TCharStringLen(const TCHAR *str) +{ +#if !defined(_UNICODE) && !defined(UNICODE) + return strlen(str); +#else + return WideCharToMultiByte(CP_UTF8, 0, str, -1, NULL, 0, NULL, NULL); +#endif +} + +/********************************************************************/ + +typedef struct PaWinMmeStream PaWinMmeStream; /* forward declaration */ + +/* prototypes for functions declared in this file */ + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +PaError PaWinMme_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index ); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +static void Terminate( struct PaUtilHostApiRepresentation *hostApi ); +static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, + PaStream** stream, + const PaStreamParameters *inputParameters, + const PaStreamParameters *outputParameters, + double sampleRate, + unsigned long framesPerBuffer, + PaStreamFlags streamFlags, + PaStreamCallback *streamCallback, + void *userData ); +static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi, + const PaStreamParameters *inputParameters, + const PaStreamParameters *outputParameters, + double sampleRate ); +static PaError CloseStream( PaStream* stream ); +static PaError StartStream( PaStream *stream ); +static PaError StopStream( PaStream *stream ); +static PaError AbortStream( PaStream *stream ); +static PaError IsStreamStopped( PaStream *s ); +static PaError IsStreamActive( PaStream *stream ); +static PaTime GetStreamTime( PaStream *stream ); +static double GetStreamCpuLoad( PaStream* stream ); +static PaError ReadStream( PaStream* stream, void *buffer, unsigned long frames ); +static PaError WriteStream( PaStream* stream, const void *buffer, unsigned long frames ); +static signed long GetStreamReadAvailable( PaStream* stream ); +static signed long GetStreamWriteAvailable( PaStream* stream ); + + +/* macros for setting last host error information */ + +#ifdef UNICODE + +#define PA_MME_SET_LAST_WAVEIN_ERROR( mmresult ) \ + { \ + wchar_t mmeErrorTextWide[ MAXERRORLENGTH ]; \ + char mmeErrorText[ MAXERRORLENGTH ]; \ + waveInGetErrorText( mmresult, mmeErrorTextWide, MAXERRORLENGTH ); \ + WideCharToMultiByte( CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR,\ + mmeErrorTextWide, -1, mmeErrorText, MAXERRORLENGTH, NULL, NULL ); \ + PaUtil_SetLastHostErrorInfo( paMME, mmresult, mmeErrorText ); \ + } + +#define PA_MME_SET_LAST_WAVEOUT_ERROR( mmresult ) \ + { \ + wchar_t mmeErrorTextWide[ MAXERRORLENGTH ]; \ + char mmeErrorText[ MAXERRORLENGTH ]; \ + waveOutGetErrorText( mmresult, mmeErrorTextWide, MAXERRORLENGTH ); \ + WideCharToMultiByte( CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR,\ + mmeErrorTextWide, -1, mmeErrorText, MAXERRORLENGTH, NULL, NULL ); \ + PaUtil_SetLastHostErrorInfo( paMME, mmresult, mmeErrorText ); \ + } + +#else /* !UNICODE */ + +#define PA_MME_SET_LAST_WAVEIN_ERROR( mmresult ) \ + { \ + char mmeErrorText[ MAXERRORLENGTH ]; \ + waveInGetErrorText( mmresult, mmeErrorText, MAXERRORLENGTH ); \ + PaUtil_SetLastHostErrorInfo( paMME, mmresult, mmeErrorText ); \ + } + +#define PA_MME_SET_LAST_WAVEOUT_ERROR( mmresult ) \ + { \ + char mmeErrorText[ MAXERRORLENGTH ]; \ + waveOutGetErrorText( mmresult, mmeErrorText, MAXERRORLENGTH ); \ + PaUtil_SetLastHostErrorInfo( paMME, mmresult, mmeErrorText ); \ + } + +#endif /* UNICODE */ + + +static void PaMme_SetLastSystemError( DWORD errorCode ) +{ + char *lpMsgBuf; + FormatMessage( + FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, + NULL, + errorCode, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPTSTR) &lpMsgBuf, + 0, + NULL + ); + PaUtil_SetLastHostErrorInfo( paMME, errorCode, lpMsgBuf ); + LocalFree( lpMsgBuf ); +} + +#define PA_MME_SET_LAST_SYSTEM_ERROR( errorCode ) \ + PaMme_SetLastSystemError( errorCode ) + + +/* PaError returning wrappers for some commonly used win32 functions + note that we allow passing a null ptr to have no effect. +*/ + +static PaError CreateEventWithPaError( HANDLE *handle, + LPSECURITY_ATTRIBUTES lpEventAttributes, + BOOL bManualReset, + BOOL bInitialState, + LPCTSTR lpName ) +{ + PaError result = paNoError; + + *handle = NULL; + + *handle = CreateEvent( lpEventAttributes, bManualReset, bInitialState, lpName ); + if( *handle == NULL ) + { + result = paUnanticipatedHostError; + PA_MME_SET_LAST_SYSTEM_ERROR( GetLastError() ); + } + + return result; +} + + +static PaError ResetEventWithPaError( HANDLE handle ) +{ + PaError result = paNoError; + + if( handle ) + { + if( ResetEvent( handle ) == 0 ) + { + result = paUnanticipatedHostError; + PA_MME_SET_LAST_SYSTEM_ERROR( GetLastError() ); + } + } + + return result; +} + + +static PaError CloseHandleWithPaError( HANDLE handle ) +{ + PaError result = paNoError; + + if( handle ) + { + if( CloseHandle( handle ) == 0 ) + { + result = paUnanticipatedHostError; + PA_MME_SET_LAST_SYSTEM_ERROR( GetLastError() ); + } + } + + return result; +} + + +/* PaWinMmeHostApiRepresentation - host api datastructure specific to this implementation */ + +typedef struct +{ + PaUtilHostApiRepresentation inheritedHostApiRep; + PaUtilStreamInterface callbackStreamInterface; + PaUtilStreamInterface blockingStreamInterface; + + PaUtilAllocationGroup *allocations; + + int inputDeviceCount, outputDeviceCount; + + /** winMmeDeviceIds is an array of WinMme device ids. + fields in the range [0, inputDeviceCount) are input device ids, + and [inputDeviceCount, inputDeviceCount + outputDeviceCount) are output + device ids. + */ + UINT *winMmeDeviceIds; +} +PaWinMmeHostApiRepresentation; + + +typedef struct +{ + PaDeviceInfo inheritedDeviceInfo; + DWORD dwFormats; /**<< standard formats bitmask from the WAVEINCAPS and WAVEOUTCAPS structures */ + char deviceInputChannelCountIsKnown; /**<< if the system returns 0xFFFF then we don't really know the number of supported channels (1=>known, 0=>unknown)*/ + char deviceOutputChannelCountIsKnown; /**<< if the system returns 0xFFFF then we don't really know the number of supported channels (1=>known, 0=>unknown)*/ +} +PaWinMmeDeviceInfo; + + +/************************************************************************* + * Returns recommended device ID. + * On the PC, the recommended device can be specified by the user by + * setting an environment variable. For example, to use device #1. + * + * set PA_RECOMMENDED_OUTPUT_DEVICE=1 + * + * The user should first determine the available device ID by using + * the supplied application "pa_devs". + */ +#define PA_ENV_BUF_SIZE_ (32) +#define PA_REC_IN_DEV_ENV_NAME_ ("PA_RECOMMENDED_INPUT_DEVICE") +#define PA_REC_OUT_DEV_ENV_NAME_ ("PA_RECOMMENDED_OUTPUT_DEVICE") +static PaDeviceIndex GetEnvDefaultDeviceID( char *envName ) +{ + PaDeviceIndex recommendedIndex = paNoDevice; + DWORD hresult; + char envbuf[PA_ENV_BUF_SIZE_]; + +#ifndef WIN32_PLATFORM_PSPC /* no GetEnvironmentVariable on PocketPC */ + + /* Let user determine default device by setting environment variable. */ + hresult = GetEnvironmentVariableA( envName, envbuf, PA_ENV_BUF_SIZE_ ); + if( (hresult > 0) && (hresult < PA_ENV_BUF_SIZE_) ) + { + recommendedIndex = atoi( envbuf ); + } +#endif + + return recommendedIndex; +} + + +static void InitializeDefaultDeviceIdsFromEnv( PaWinMmeHostApiRepresentation *hostApi ) +{ + PaDeviceIndex device; + + /* input */ + device = GetEnvDefaultDeviceID( PA_REC_IN_DEV_ENV_NAME_ ); + if( device != paNoDevice && + ( device >= 0 && device < hostApi->inheritedHostApiRep.info.deviceCount ) && + hostApi->inheritedHostApiRep.deviceInfos[ device ]->maxInputChannels > 0 ) + { + hostApi->inheritedHostApiRep.info.defaultInputDevice = device; + } + + /* output */ + device = GetEnvDefaultDeviceID( PA_REC_OUT_DEV_ENV_NAME_ ); + if( device != paNoDevice && + ( device >= 0 && device < hostApi->inheritedHostApiRep.info.deviceCount ) && + hostApi->inheritedHostApiRep.deviceInfos[ device ]->maxOutputChannels > 0 ) + { + hostApi->inheritedHostApiRep.info.defaultOutputDevice = device; + } +} + + +/** Convert external PA ID to a windows multimedia device ID +*/ +static UINT LocalDeviceIndexToWinMmeDeviceId( PaWinMmeHostApiRepresentation *hostApi, PaDeviceIndex device ) +{ + assert( device >= 0 && device < hostApi->inputDeviceCount + hostApi->outputDeviceCount ); + + return hostApi->winMmeDeviceIds[ device ]; +} + + +static int SampleFormatAndWinWmmeSpecificFlagsToLinearWaveFormatTag( PaSampleFormat sampleFormat, unsigned long winMmeSpecificFlags ) +{ + int waveFormatTag = 0; + + if( winMmeSpecificFlags & paWinMmeWaveFormatDolbyAc3Spdif ) + waveFormatTag = PAWIN_WAVE_FORMAT_DOLBY_AC3_SPDIF; + else if( winMmeSpecificFlags & paWinMmeWaveFormatWmaSpdif ) + waveFormatTag = PAWIN_WAVE_FORMAT_WMA_SPDIF; + else + waveFormatTag = PaWin_SampleFormatToLinearWaveFormatTag( sampleFormat ); + + return waveFormatTag; +} + + +static PaError QueryInputWaveFormatEx( int deviceId, WAVEFORMATEX *waveFormatEx ) +{ + MMRESULT mmresult; + + switch( mmresult = waveInOpen( NULL, deviceId, waveFormatEx, 0, 0, WAVE_FORMAT_QUERY ) ) + { + case MMSYSERR_NOERROR: + return paNoError; + case MMSYSERR_ALLOCATED: /* Specified resource is already allocated. */ + return paDeviceUnavailable; + case MMSYSERR_NODRIVER: /* No device driver is present. */ + return paDeviceUnavailable; + case MMSYSERR_NOMEM: /* Unable to allocate or lock memory. */ + return paInsufficientMemory; + case WAVERR_BADFORMAT: /* Attempted to open with an unsupported waveform-audio format. */ + return paSampleFormatNotSupported; + + case MMSYSERR_BADDEVICEID: /* Specified device identifier is out of range. */ + /* falls through */ + default: + PA_MME_SET_LAST_WAVEIN_ERROR( mmresult ); + return paUnanticipatedHostError; + } +} + + +static PaError QueryOutputWaveFormatEx( int deviceId, WAVEFORMATEX *waveFormatEx ) +{ + MMRESULT mmresult; + + switch( mmresult = waveOutOpen( NULL, deviceId, waveFormatEx, 0, 0, WAVE_FORMAT_QUERY ) ) + { + case MMSYSERR_NOERROR: + return paNoError; + case MMSYSERR_ALLOCATED: /* Specified resource is already allocated. */ + return paDeviceUnavailable; + case MMSYSERR_NODRIVER: /* No device driver is present. */ + return paDeviceUnavailable; + case MMSYSERR_NOMEM: /* Unable to allocate or lock memory. */ + return paInsufficientMemory; + case WAVERR_BADFORMAT: /* Attempted to open with an unsupported waveform-audio format. */ + return paSampleFormatNotSupported; + + case MMSYSERR_BADDEVICEID: /* Specified device identifier is out of range. */ + /* falls through */ + default: + PA_MME_SET_LAST_WAVEOUT_ERROR( mmresult ); + return paUnanticipatedHostError; + } +} + + +static PaError QueryFormatSupported( PaDeviceInfo *deviceInfo, + PaError (*waveFormatExQueryFunction)(int, WAVEFORMATEX*), + int winMmeDeviceId, int channels, double sampleRate, unsigned long winMmeSpecificFlags ) +{ + PaWinMmeDeviceInfo *winMmeDeviceInfo = (PaWinMmeDeviceInfo*)deviceInfo; + PaWinWaveFormat waveFormat; + PaSampleFormat sampleFormat; + int waveFormatTag; + + /* @todo at the moment we only query with 16 bit sample format and directout speaker config*/ + + sampleFormat = paInt16; + waveFormatTag = SampleFormatAndWinWmmeSpecificFlagsToLinearWaveFormatTag( sampleFormat, winMmeSpecificFlags ); + + if( waveFormatTag == PaWin_SampleFormatToLinearWaveFormatTag( paInt16 ) ){ + + /* attempt bypass querying the device for linear formats */ + + if( sampleRate == 11025.0 + && ( (channels == 1 && (winMmeDeviceInfo->dwFormats & WAVE_FORMAT_1M16)) + || (channels == 2 && (winMmeDeviceInfo->dwFormats & WAVE_FORMAT_1S16)) ) ){ + + return paNoError; + } + + if( sampleRate == 22050.0 + && ( (channels == 1 && (winMmeDeviceInfo->dwFormats & WAVE_FORMAT_2M16)) + || (channels == 2 && (winMmeDeviceInfo->dwFormats & WAVE_FORMAT_2S16)) ) ){ + + return paNoError; + } + + if( sampleRate == 44100.0 + && ( (channels == 1 && (winMmeDeviceInfo->dwFormats & WAVE_FORMAT_4M16)) + || (channels == 2 && (winMmeDeviceInfo->dwFormats & WAVE_FORMAT_4S16)) ) ){ + + return paNoError; + } + } + + + /* first, attempt to query the device using WAVEFORMATEXTENSIBLE, + if this fails we fall back to WAVEFORMATEX */ + + PaWin_InitializeWaveFormatExtensible( &waveFormat, channels, sampleFormat, waveFormatTag, + sampleRate, PAWIN_SPEAKER_DIRECTOUT ); + + if( waveFormatExQueryFunction( winMmeDeviceId, (WAVEFORMATEX*)&waveFormat ) == paNoError ) + return paNoError; + + PaWin_InitializeWaveFormatEx( &waveFormat, channels, sampleFormat, waveFormatTag, sampleRate ); + + return waveFormatExQueryFunction( winMmeDeviceId, (WAVEFORMATEX*)&waveFormat ); +} + + +#define PA_DEFAULTSAMPLERATESEARCHORDER_COUNT_ (13) /* must match array length below */ +static double defaultSampleRateSearchOrder_[] = + { 44100.0, 48000.0, 32000.0, 24000.0, 22050.0, 88200.0, 96000.0, 192000.0, + 16000.0, 12000.0, 11025.0, 9600.0, 8000.0 }; + +static void DetectDefaultSampleRate( PaWinMmeDeviceInfo *winMmeDeviceInfo, int winMmeDeviceId, + PaError (*waveFormatExQueryFunction)(int, WAVEFORMATEX*), int maxChannels ) +{ + PaDeviceInfo *deviceInfo = &winMmeDeviceInfo->inheritedDeviceInfo; + int i; + + deviceInfo->defaultSampleRate = 0.; + + for( i=0; i < PA_DEFAULTSAMPLERATESEARCHORDER_COUNT_; ++i ) + { + double sampleRate = defaultSampleRateSearchOrder_[ i ]; + PaError paerror = QueryFormatSupported( deviceInfo, waveFormatExQueryFunction, winMmeDeviceId, maxChannels, sampleRate, 0 ); + if( paerror == paNoError ) + { + deviceInfo->defaultSampleRate = sampleRate; + break; + } + } +} + + +#ifdef PAWIN_USE_WDMKS_DEVICE_INFO +static int QueryWaveInKSFilterMaxChannels( int waveInDeviceId, int *maxChannels ) +{ + void *devicePath; + DWORD devicePathSize; + int result = 0; + + if( waveInMessage((HWAVEIN)waveInDeviceId, DRV_QUERYDEVICEINTERFACESIZE, + (DWORD_PTR)&devicePathSize, 0 ) != MMSYSERR_NOERROR ) + return 0; + + devicePath = PaUtil_AllocateMemory( devicePathSize ); + if( !devicePath ) + return 0; + + /* apparently DRV_QUERYDEVICEINTERFACE returns a unicode interface path, although this is undocumented */ + if( waveInMessage((HWAVEIN)waveInDeviceId, DRV_QUERYDEVICEINTERFACE, + (DWORD_PTR)devicePath, devicePathSize ) == MMSYSERR_NOERROR ) + { + int count = PaWin_WDMKS_QueryFilterMaximumChannelCount( devicePath, /* isInput= */ 1 ); + if( count > 0 ) + { + *maxChannels = count; + result = 1; + } + } + + PaUtil_FreeMemory( devicePath ); + + return result; +} +#endif /* PAWIN_USE_WDMKS_DEVICE_INFO */ + + +static PaError InitializeInputDeviceInfo( PaWinMmeHostApiRepresentation *winMmeHostApi, + PaWinMmeDeviceInfo *winMmeDeviceInfo, UINT winMmeInputDeviceId, int *success ) +{ + PaError result = paNoError; + char *deviceName; /* non-const ptr */ + MMRESULT mmresult; + WAVEINCAPS wic; + PaDeviceInfo *deviceInfo = &winMmeDeviceInfo->inheritedDeviceInfo; + size_t len; + + *success = 0; + + mmresult = waveInGetDevCaps( winMmeInputDeviceId, &wic, sizeof( WAVEINCAPS ) ); + if( mmresult == MMSYSERR_NOMEM ) + { + result = paInsufficientMemory; + goto error; + } + else if( mmresult != MMSYSERR_NOERROR ) + { + /* instead of returning paUnanticipatedHostError we return + paNoError, but leave success set as 0. This allows + Pa_Initialize to just ignore this device, without failing + the entire initialisation process. + */ + return paNoError; + } + + /* NOTE: the WAVEOUTCAPS.szPname is a null-terminated array of 32 characters, + so we are limited to displaying only the first 31 characters of the device name. */ + if( winMmeInputDeviceId == WAVE_MAPPER ) + { + len = TCharStringLen( wic.szPname ) + 1 + sizeof(constInputMapperSuffix_); + /* Append I/O suffix to WAVE_MAPPER device. */ + deviceName = (char*)PaUtil_GroupAllocateMemory( + winMmeHostApi->allocations, + (long)len ); + if( !deviceName ) + { + result = paInsufficientMemory; + goto error; + } + CopyTCharStringToUtf8CString( deviceName, len, wic.szPname ); + strcat( deviceName, constInputMapperSuffix_ ); + } + else + { + len = TCharStringLen( wic.szPname ) + 1; + deviceName = (char*)PaUtil_GroupAllocateMemory( + winMmeHostApi->allocations, + (long)len ); + if( !deviceName ) + { + result = paInsufficientMemory; + goto error; + } + CopyTCharStringToUtf8CString( deviceName, len, wic.szPname ); + } + deviceInfo->name = deviceName; + + if( wic.wChannels == 0xFFFF || wic.wChannels < 1 || wic.wChannels > 255 ){ + /* For Windows versions using WDM (possibly Windows 98 ME and later) + * the kernel mixer sits between the application and the driver. As a result, + * wave*GetDevCaps often kernel mixer channel counts, which are unlimited. + * When this happens we assume the device is stereo and set a flag + * so that other channel counts can be tried with OpenStream -- i.e. when + * device*ChannelCountIsKnown is false, OpenStream will try whatever + * channel count you supply. + * see also InitializeOutputDeviceInfo() below. + */ + + PA_DEBUG(("Pa_GetDeviceInfo: Num input channels reported as %d! Changed to 2.\n", wic.wChannels )); + deviceInfo->maxInputChannels = 2; + winMmeDeviceInfo->deviceInputChannelCountIsKnown = 0; + }else{ + deviceInfo->maxInputChannels = wic.wChannels; + winMmeDeviceInfo->deviceInputChannelCountIsKnown = 1; + } + +#ifdef PAWIN_USE_WDMKS_DEVICE_INFO + winMmeDeviceInfo->deviceInputChannelCountIsKnown = + QueryWaveInKSFilterMaxChannels( winMmeInputDeviceId, &deviceInfo->maxInputChannels ); +#endif /* PAWIN_USE_WDMKS_DEVICE_INFO */ + + winMmeDeviceInfo->dwFormats = wic.dwFormats; + + DetectDefaultSampleRate( winMmeDeviceInfo, winMmeInputDeviceId, + QueryInputWaveFormatEx, deviceInfo->maxInputChannels ); + + *success = 1; + +error: + return result; +} + + +#ifdef PAWIN_USE_WDMKS_DEVICE_INFO +static int QueryWaveOutKSFilterMaxChannels( int waveOutDeviceId, int *maxChannels ) +{ + void *devicePath; + DWORD devicePathSize; + int result = 0; + + if( waveOutMessage((HWAVEOUT)waveOutDeviceId, DRV_QUERYDEVICEINTERFACESIZE, + (DWORD_PTR)&devicePathSize, 0 ) != MMSYSERR_NOERROR ) + return 0; + + devicePath = PaUtil_AllocateMemory( devicePathSize ); + if( !devicePath ) + return 0; + + /* apparently DRV_QUERYDEVICEINTERFACE returns a unicode interface path, although this is undocumented */ + if( waveOutMessage((HWAVEOUT)waveOutDeviceId, DRV_QUERYDEVICEINTERFACE, + (DWORD_PTR)devicePath, devicePathSize ) == MMSYSERR_NOERROR ) + { + int count = PaWin_WDMKS_QueryFilterMaximumChannelCount( devicePath, /* isInput= */ 0 ); + if( count > 0 ) + { + *maxChannels = count; + result = 1; + } + } + + PaUtil_FreeMemory( devicePath ); + + return result; +} +#endif /* PAWIN_USE_WDMKS_DEVICE_INFO */ + + +static PaError InitializeOutputDeviceInfo( PaWinMmeHostApiRepresentation *winMmeHostApi, + PaWinMmeDeviceInfo *winMmeDeviceInfo, UINT winMmeOutputDeviceId, int *success ) +{ + PaError result = paNoError; + char *deviceName; /* non-const ptr */ + MMRESULT mmresult; + WAVEOUTCAPS woc; + PaDeviceInfo *deviceInfo = &winMmeDeviceInfo->inheritedDeviceInfo; + size_t len; +#ifdef PAWIN_USE_WDMKS_DEVICE_INFO + int wdmksDeviceOutputChannelCountIsKnown; +#endif + + *success = 0; + + mmresult = waveOutGetDevCaps( winMmeOutputDeviceId, &woc, sizeof( WAVEOUTCAPS ) ); + if( mmresult == MMSYSERR_NOMEM ) + { + result = paInsufficientMemory; + goto error; + } + else if( mmresult != MMSYSERR_NOERROR ) + { + /* instead of returning paUnanticipatedHostError we return + paNoError, but leave success set as 0. This allows + Pa_Initialize to just ignore this device, without failing + the entire initialisation process. + */ + return paNoError; + } + + /* NOTE: the WAVEOUTCAPS.szPname is a null-terminated array of 32 characters, + so we are limited to displaying only the first 31 characters of the device name. */ + if( winMmeOutputDeviceId == WAVE_MAPPER ) + { + /* Append I/O suffix to WAVE_MAPPER device. */ + len = TCharStringLen( woc.szPname ) + 1 + sizeof(constOutputMapperSuffix_); + deviceName = (char*)PaUtil_GroupAllocateMemory( + winMmeHostApi->allocations, + (long)len ); + if( !deviceName ) + { + result = paInsufficientMemory; + goto error; + } + CopyTCharStringToUtf8CString( deviceName, len, woc.szPname ); + strcat( deviceName, constOutputMapperSuffix_ ); + } + else + { + len = TCharStringLen( woc.szPname ) + 1; + deviceName = (char*)PaUtil_GroupAllocateMemory( + winMmeHostApi->allocations, + (long)len ); + if( !deviceName ) + { + result = paInsufficientMemory; + goto error; + } + CopyTCharStringToUtf8CString( deviceName, len, woc.szPname ); + } + deviceInfo->name = deviceName; + + if( woc.wChannels == 0xFFFF || woc.wChannels < 1 || woc.wChannels > 255 ){ + /* For Windows versions using WDM (possibly Windows 98 ME and later) + * the kernel mixer sits between the application and the driver. As a result, + * wave*GetDevCaps often kernel mixer channel counts, which are unlimited. + * When this happens we assume the device is stereo and set a flag + * so that other channel counts can be tried with OpenStream -- i.e. when + * device*ChannelCountIsKnown is false, OpenStream will try whatever + * channel count you supply. + * see also InitializeInputDeviceInfo() above. + */ + + PA_DEBUG(("Pa_GetDeviceInfo: Num output channels reported as %d! Changed to 2.\n", woc.wChannels )); + deviceInfo->maxOutputChannels = 2; + winMmeDeviceInfo->deviceOutputChannelCountIsKnown = 0; + }else{ + deviceInfo->maxOutputChannels = woc.wChannels; + winMmeDeviceInfo->deviceOutputChannelCountIsKnown = 1; + } + +#ifdef PAWIN_USE_WDMKS_DEVICE_INFO + wdmksDeviceOutputChannelCountIsKnown = QueryWaveOutKSFilterMaxChannels( + winMmeOutputDeviceId, &deviceInfo->maxOutputChannels ); + if( wdmksDeviceOutputChannelCountIsKnown && !winMmeDeviceInfo->deviceOutputChannelCountIsKnown ) + winMmeDeviceInfo->deviceOutputChannelCountIsKnown = 1; +#endif /* PAWIN_USE_WDMKS_DEVICE_INFO */ + + winMmeDeviceInfo->dwFormats = woc.dwFormats; + + DetectDefaultSampleRate( winMmeDeviceInfo, winMmeOutputDeviceId, + QueryOutputWaveFormatEx, deviceInfo->maxOutputChannels ); + + *success = 1; + +error: + return result; +} + + +static void GetDefaultLatencies( PaTime *defaultLowLatency, PaTime *defaultHighLatency ) +{ +/* +NOTE: GetVersionEx() is deprecated as of Windows 8.1 and can not be used to reliably detect +versions of Windows higher than Windows 8 (due to manifest requirements for reporting higher versions). +Microsoft recommends switching to VerifyVersionInfo (available on Win 2k and later), however GetVersionEx +is is faster, for now we just disable the deprecation warning. +See: https://msdn.microsoft.com/en-us/library/windows/desktop/ms724451(v=vs.85).aspx +See: http://www.codeproject.com/Articles/678606/Part-Overcoming-Windows-s-deprecation-of-GetVe +*/ +#pragma warning (disable : 4996) /* use of GetVersionEx */ + + OSVERSIONINFO osvi; + osvi.dwOSVersionInfoSize = sizeof( osvi ); + GetVersionEx( &osvi ); + + /* Check for NT */ + if( (osvi.dwMajorVersion == 4) && (osvi.dwPlatformId == 2) ) + { + *defaultLowLatency = PA_MME_WIN_NT_DEFAULT_LATENCY_; + } + else if(osvi.dwMajorVersion >= 5) + { + *defaultLowLatency = PA_MME_WIN_WDM_DEFAULT_LATENCY_; + } + else + { + *defaultLowLatency = PA_MME_WIN_9X_DEFAULT_LATENCY_; + } + + *defaultHighLatency = *defaultLowLatency * 2; + +#pragma warning (default : 4996) +} + + +PaError PaWinMme_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex ) +{ + PaError result = paNoError; + int i; + PaWinMmeHostApiRepresentation *winMmeHostApi; + int inputDeviceCount, outputDeviceCount, maximumPossibleDeviceCount; + PaWinMmeDeviceInfo *deviceInfoArray; + int deviceInfoInitializationSucceeded; + PaTime defaultLowLatency, defaultHighLatency; + DWORD waveInPreferredDevice, waveOutPreferredDevice; + DWORD preferredDeviceStatusFlags; + + winMmeHostApi = (PaWinMmeHostApiRepresentation*)PaUtil_AllocateMemory( sizeof(PaWinMmeHostApiRepresentation) ); + if( !winMmeHostApi ) + { + result = paInsufficientMemory; + goto error; + } + + winMmeHostApi->allocations = PaUtil_CreateAllocationGroup(); + if( !winMmeHostApi->allocations ) + { + result = paInsufficientMemory; + goto error; + } + + *hostApi = &winMmeHostApi->inheritedHostApiRep; + (*hostApi)->info.structVersion = 1; + (*hostApi)->info.type = paMME; + (*hostApi)->info.name = "MME"; + + + /* initialise device counts and default devices under the assumption that + there are no devices. These values are incremented below if and when + devices are successfully initialized. + */ + (*hostApi)->info.deviceCount = 0; + (*hostApi)->info.defaultInputDevice = paNoDevice; + (*hostApi)->info.defaultOutputDevice = paNoDevice; + winMmeHostApi->inputDeviceCount = 0; + winMmeHostApi->outputDeviceCount = 0; + +#if !defined(DRVM_MAPPER_PREFERRED_GET) +/* DRVM_MAPPER_PREFERRED_GET is defined in mmddk.h but we avoid a dependency on the DDK by defining it here */ +#define DRVM_MAPPER_PREFERRED_GET (0x2000+21) +#endif + + /* the following calls assume that if wave*Message fails the preferred device parameter won't be modified */ + preferredDeviceStatusFlags = 0; + waveInPreferredDevice = -1; + waveInMessage( (HWAVEIN)WAVE_MAPPER, DRVM_MAPPER_PREFERRED_GET, (DWORD_PTR)&waveInPreferredDevice, (DWORD_PTR)&preferredDeviceStatusFlags ); + + preferredDeviceStatusFlags = 0; + waveOutPreferredDevice = -1; + waveOutMessage( (HWAVEOUT)WAVE_MAPPER, DRVM_MAPPER_PREFERRED_GET, (DWORD_PTR)&waveOutPreferredDevice, (DWORD_PTR)&preferredDeviceStatusFlags ); + + maximumPossibleDeviceCount = 0; + + inputDeviceCount = waveInGetNumDevs(); + if( inputDeviceCount > 0 ) + maximumPossibleDeviceCount += inputDeviceCount + 1; /* assume there is a WAVE_MAPPER */ + + outputDeviceCount = waveOutGetNumDevs(); + if( outputDeviceCount > 0 ) + maximumPossibleDeviceCount += outputDeviceCount + 1; /* assume there is a WAVE_MAPPER */ + + + if( maximumPossibleDeviceCount > 0 ){ + + (*hostApi)->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory( + winMmeHostApi->allocations, sizeof(PaDeviceInfo*) * maximumPossibleDeviceCount ); + if( !(*hostApi)->deviceInfos ) + { + result = paInsufficientMemory; + goto error; + } + + /* allocate all device info structs in a contiguous block */ + deviceInfoArray = (PaWinMmeDeviceInfo*)PaUtil_GroupAllocateMemory( + winMmeHostApi->allocations, sizeof(PaWinMmeDeviceInfo) * maximumPossibleDeviceCount ); + if( !deviceInfoArray ) + { + result = paInsufficientMemory; + goto error; + } + + winMmeHostApi->winMmeDeviceIds = (UINT*)PaUtil_GroupAllocateMemory( + winMmeHostApi->allocations, sizeof(int) * maximumPossibleDeviceCount ); + if( !winMmeHostApi->winMmeDeviceIds ) + { + result = paInsufficientMemory; + goto error; + } + + GetDefaultLatencies( &defaultLowLatency, &defaultHighLatency ); + + if( inputDeviceCount > 0 ){ + /* -1 is the WAVE_MAPPER */ + for( i = -1; i < inputDeviceCount; ++i ){ + UINT winMmeDeviceId = (UINT)((i==-1) ? WAVE_MAPPER : i); + PaWinMmeDeviceInfo *wmmeDeviceInfo = &deviceInfoArray[ (*hostApi)->info.deviceCount ]; + PaDeviceInfo *deviceInfo = &wmmeDeviceInfo->inheritedDeviceInfo; + deviceInfo->structVersion = 2; + deviceInfo->hostApi = hostApiIndex; + + deviceInfo->maxInputChannels = 0; + wmmeDeviceInfo->deviceInputChannelCountIsKnown = 1; + deviceInfo->maxOutputChannels = 0; + wmmeDeviceInfo->deviceOutputChannelCountIsKnown = 1; + + deviceInfo->defaultLowInputLatency = defaultLowLatency; + deviceInfo->defaultLowOutputLatency = defaultLowLatency; + deviceInfo->defaultHighInputLatency = defaultHighLatency; + deviceInfo->defaultHighOutputLatency = defaultHighLatency; + + result = InitializeInputDeviceInfo( winMmeHostApi, wmmeDeviceInfo, + winMmeDeviceId, &deviceInfoInitializationSucceeded ); + if( result != paNoError ) + goto error; + + if( deviceInfoInitializationSucceeded ){ + if( (*hostApi)->info.defaultInputDevice == paNoDevice ){ + /* if there is currently no default device, use the first one available */ + (*hostApi)->info.defaultInputDevice = (*hostApi)->info.deviceCount; + + }else if( winMmeDeviceId == waveInPreferredDevice ){ + /* set the default device to the system preferred device */ + (*hostApi)->info.defaultInputDevice = (*hostApi)->info.deviceCount; + } + + winMmeHostApi->winMmeDeviceIds[ (*hostApi)->info.deviceCount ] = winMmeDeviceId; + (*hostApi)->deviceInfos[ (*hostApi)->info.deviceCount ] = deviceInfo; + + winMmeHostApi->inputDeviceCount++; + (*hostApi)->info.deviceCount++; + } + } + } + + if( outputDeviceCount > 0 ){ + /* -1 is the WAVE_MAPPER */ + for( i = -1; i < outputDeviceCount; ++i ){ + UINT winMmeDeviceId = (UINT)((i==-1) ? WAVE_MAPPER : i); + PaWinMmeDeviceInfo *wmmeDeviceInfo = &deviceInfoArray[ (*hostApi)->info.deviceCount ]; + PaDeviceInfo *deviceInfo = &wmmeDeviceInfo->inheritedDeviceInfo; + deviceInfo->structVersion = 2; + deviceInfo->hostApi = hostApiIndex; + + deviceInfo->maxInputChannels = 0; + wmmeDeviceInfo->deviceInputChannelCountIsKnown = 1; + deviceInfo->maxOutputChannels = 0; + wmmeDeviceInfo->deviceOutputChannelCountIsKnown = 1; + + deviceInfo->defaultLowInputLatency = defaultLowLatency; + deviceInfo->defaultLowOutputLatency = defaultLowLatency; + deviceInfo->defaultHighInputLatency = defaultHighLatency; + deviceInfo->defaultHighOutputLatency = defaultHighLatency; + + result = InitializeOutputDeviceInfo( winMmeHostApi, wmmeDeviceInfo, + winMmeDeviceId, &deviceInfoInitializationSucceeded ); + if( result != paNoError ) + goto error; + + if( deviceInfoInitializationSucceeded ){ + if( (*hostApi)->info.defaultOutputDevice == paNoDevice ){ + /* if there is currently no default device, use the first one available */ + (*hostApi)->info.defaultOutputDevice = (*hostApi)->info.deviceCount; + + }else if( winMmeDeviceId == waveOutPreferredDevice ){ + /* set the default device to the system preferred device */ + (*hostApi)->info.defaultOutputDevice = (*hostApi)->info.deviceCount; + } + + winMmeHostApi->winMmeDeviceIds[ (*hostApi)->info.deviceCount ] = winMmeDeviceId; + (*hostApi)->deviceInfos[ (*hostApi)->info.deviceCount ] = deviceInfo; + + winMmeHostApi->outputDeviceCount++; + (*hostApi)->info.deviceCount++; + } + } + } + } + + InitializeDefaultDeviceIdsFromEnv( winMmeHostApi ); + + (*hostApi)->Terminate = Terminate; + (*hostApi)->OpenStream = OpenStream; + (*hostApi)->IsFormatSupported = IsFormatSupported; + + PaUtil_InitializeStreamInterface( &winMmeHostApi->callbackStreamInterface, CloseStream, StartStream, + StopStream, AbortStream, IsStreamStopped, IsStreamActive, + GetStreamTime, GetStreamCpuLoad, + PaUtil_DummyRead, PaUtil_DummyWrite, + PaUtil_DummyGetReadAvailable, PaUtil_DummyGetWriteAvailable ); + + PaUtil_InitializeStreamInterface( &winMmeHostApi->blockingStreamInterface, CloseStream, StartStream, + StopStream, AbortStream, IsStreamStopped, IsStreamActive, + GetStreamTime, PaUtil_DummyGetCpuLoad, + ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable ); + + return result; + +error: + if( winMmeHostApi ) + { + if( winMmeHostApi->allocations ) + { + PaUtil_FreeAllAllocations( winMmeHostApi->allocations ); + PaUtil_DestroyAllocationGroup( winMmeHostApi->allocations ); + } + + PaUtil_FreeMemory( winMmeHostApi ); + } + + return result; +} + + +static void Terminate( struct PaUtilHostApiRepresentation *hostApi ) +{ + PaWinMmeHostApiRepresentation *winMmeHostApi = (PaWinMmeHostApiRepresentation*)hostApi; + + if( winMmeHostApi->allocations ) + { + PaUtil_FreeAllAllocations( winMmeHostApi->allocations ); + PaUtil_DestroyAllocationGroup( winMmeHostApi->allocations ); + } + + PaUtil_FreeMemory( winMmeHostApi ); +} + + +static PaError IsInputChannelCountSupported( PaWinMmeDeviceInfo* deviceInfo, int channelCount ) +{ + PaError result = paNoError; + + if( channelCount > 0 + && deviceInfo->deviceInputChannelCountIsKnown + && channelCount > deviceInfo->inheritedDeviceInfo.maxInputChannels ){ + + result = paInvalidChannelCount; + } + + return result; +} + +static PaError IsOutputChannelCountSupported( PaWinMmeDeviceInfo* deviceInfo, int channelCount ) +{ + PaError result = paNoError; + + if( channelCount > 0 + && deviceInfo->deviceOutputChannelCountIsKnown + && channelCount > deviceInfo->inheritedDeviceInfo.maxOutputChannels ){ + + result = paInvalidChannelCount; + } + + return result; +} + +static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi, + const PaStreamParameters *inputParameters, + const PaStreamParameters *outputParameters, + double sampleRate ) +{ + PaWinMmeHostApiRepresentation *winMmeHostApi = (PaWinMmeHostApiRepresentation*)hostApi; + PaDeviceInfo *inputDeviceInfo, *outputDeviceInfo; + int inputChannelCount, outputChannelCount; + int inputMultipleDeviceChannelCount, outputMultipleDeviceChannelCount; + PaSampleFormat inputSampleFormat, outputSampleFormat; + PaWinMmeStreamInfo *inputStreamInfo, *outputStreamInfo; + UINT winMmeInputDeviceId, winMmeOutputDeviceId; + unsigned int i; + PaError paerror; + + /* The calls to QueryFormatSupported below are intended to detect invalid + sample rates. If we assume that the channel count and format are OK, + then the only thing that could fail is the sample rate. This isn't + strictly true, but I can't think of a better way to test that the + sample rate is valid. + */ + + if( inputParameters ) + { + inputChannelCount = inputParameters->channelCount; + inputSampleFormat = inputParameters->sampleFormat; + inputStreamInfo = inputParameters->hostApiSpecificStreamInfo; + + /* all standard sample formats are supported by the buffer adapter, + this implementation doesn't support any custom sample formats */ + if( inputSampleFormat & paCustomFormat ) + return paSampleFormatNotSupported; + + if( inputParameters->device == paUseHostApiSpecificDeviceSpecification + && inputStreamInfo && (inputStreamInfo->flags & paWinMmeUseMultipleDevices) ) + { + inputMultipleDeviceChannelCount = 0; + for( i=0; i< inputStreamInfo->deviceCount; ++i ) + { + inputMultipleDeviceChannelCount += inputStreamInfo->devices[i].channelCount; + + inputDeviceInfo = hostApi->deviceInfos[ inputStreamInfo->devices[i].device ]; + + /* check that input device can support inputChannelCount */ + if( inputStreamInfo->devices[i].channelCount < 1 ) + return paInvalidChannelCount; + + paerror = IsInputChannelCountSupported( (PaWinMmeDeviceInfo*)inputDeviceInfo, + inputStreamInfo->devices[i].channelCount ); + if( paerror != paNoError ) + return paerror; + + /* test for valid sample rate, see comment above */ + winMmeInputDeviceId = LocalDeviceIndexToWinMmeDeviceId( winMmeHostApi, inputStreamInfo->devices[i].device ); + paerror = QueryFormatSupported( inputDeviceInfo, QueryInputWaveFormatEx, + winMmeInputDeviceId, inputStreamInfo->devices[i].channelCount, sampleRate, + ((inputStreamInfo) ? inputStreamInfo->flags : 0) ); + if( paerror != paNoError ) + return paInvalidSampleRate; + } + + if( inputMultipleDeviceChannelCount != inputChannelCount ) + return paIncompatibleHostApiSpecificStreamInfo; + } + else + { + if( inputStreamInfo && (inputStreamInfo->flags & paWinMmeUseMultipleDevices) ) + return paIncompatibleHostApiSpecificStreamInfo; /* paUseHostApiSpecificDeviceSpecification was not supplied as the input device */ + + inputDeviceInfo = hostApi->deviceInfos[ inputParameters->device ]; + + /* check that input device can support inputChannelCount */ + paerror = IsInputChannelCountSupported( (PaWinMmeDeviceInfo*)inputDeviceInfo, inputChannelCount ); + if( paerror != paNoError ) + return paerror; + + /* test for valid sample rate, see comment above */ + winMmeInputDeviceId = LocalDeviceIndexToWinMmeDeviceId( winMmeHostApi, inputParameters->device ); + paerror = QueryFormatSupported( inputDeviceInfo, QueryInputWaveFormatEx, + winMmeInputDeviceId, inputChannelCount, sampleRate, + ((inputStreamInfo) ? inputStreamInfo->flags : 0) ); + if( paerror != paNoError ) + return paInvalidSampleRate; + } + } + + if( outputParameters ) + { + outputChannelCount = outputParameters->channelCount; + outputSampleFormat = outputParameters->sampleFormat; + outputStreamInfo = outputParameters->hostApiSpecificStreamInfo; + + /* all standard sample formats are supported by the buffer adapter, + this implementation doesn't support any custom sample formats */ + if( outputSampleFormat & paCustomFormat ) + return paSampleFormatNotSupported; + + if( outputParameters->device == paUseHostApiSpecificDeviceSpecification + && outputStreamInfo && (outputStreamInfo->flags & paWinMmeUseMultipleDevices) ) + { + outputMultipleDeviceChannelCount = 0; + for( i=0; i< outputStreamInfo->deviceCount; ++i ) + { + outputMultipleDeviceChannelCount += outputStreamInfo->devices[i].channelCount; + + outputDeviceInfo = hostApi->deviceInfos[ outputStreamInfo->devices[i].device ]; + + /* check that output device can support outputChannelCount */ + if( outputStreamInfo->devices[i].channelCount < 1 ) + return paInvalidChannelCount; + + paerror = IsOutputChannelCountSupported( (PaWinMmeDeviceInfo*)outputDeviceInfo, + outputStreamInfo->devices[i].channelCount ); + if( paerror != paNoError ) + return paerror; + + /* test for valid sample rate, see comment above */ + winMmeOutputDeviceId = LocalDeviceIndexToWinMmeDeviceId( winMmeHostApi, outputStreamInfo->devices[i].device ); + paerror = QueryFormatSupported( outputDeviceInfo, QueryOutputWaveFormatEx, + winMmeOutputDeviceId, outputStreamInfo->devices[i].channelCount, sampleRate, + ((outputStreamInfo) ? outputStreamInfo->flags : 0) ); + if( paerror != paNoError ) + return paInvalidSampleRate; + } + + if( outputMultipleDeviceChannelCount != outputChannelCount ) + return paIncompatibleHostApiSpecificStreamInfo; + } + else + { + if( outputStreamInfo && (outputStreamInfo->flags & paWinMmeUseMultipleDevices) ) + return paIncompatibleHostApiSpecificStreamInfo; /* paUseHostApiSpecificDeviceSpecification was not supplied as the output device */ + + outputDeviceInfo = hostApi->deviceInfos[ outputParameters->device ]; + + /* check that output device can support outputChannelCount */ + paerror = IsOutputChannelCountSupported( (PaWinMmeDeviceInfo*)outputDeviceInfo, outputChannelCount ); + if( paerror != paNoError ) + return paerror; + + /* test for valid sample rate, see comment above */ + winMmeOutputDeviceId = LocalDeviceIndexToWinMmeDeviceId( winMmeHostApi, outputParameters->device ); + paerror = QueryFormatSupported( outputDeviceInfo, QueryOutputWaveFormatEx, + winMmeOutputDeviceId, outputChannelCount, sampleRate, + ((outputStreamInfo) ? outputStreamInfo->flags : 0) ); + if( paerror != paNoError ) + return paInvalidSampleRate; + } + } + + /* + - if a full duplex stream is requested, check that the combination + of input and output parameters is supported + + - check that the device supports sampleRate + + for mme all we can do is test that the input and output devices + support the requested sample rate and number of channels. we + cannot test for full duplex compatibility. + */ + + return paFormatIsSupported; +} + + +static unsigned long ComputeHostBufferCountForFixedBufferSizeFrames( + unsigned long suggestedLatencyFrames, + unsigned long hostBufferSizeFrames, + unsigned long minimumBufferCount ) +{ + /* Calculate the number of buffers of length hostFramesPerBuffer + that fit in suggestedLatencyFrames, rounding up to the next integer. + + The value (hostBufferSizeFrames - 1) below is to ensure the buffer count is rounded up. + */ + unsigned long resultBufferCount = ((suggestedLatencyFrames + (hostBufferSizeFrames - 1)) / hostBufferSizeFrames); + + /* We always need one extra buffer for processing while the rest are queued/playing. + i.e. latency is framesPerBuffer * (bufferCount - 1) + */ + resultBufferCount += 1; + + if( resultBufferCount < minimumBufferCount ) /* clamp to minimum buffer count */ + resultBufferCount = minimumBufferCount; + + return resultBufferCount; +} + + +static unsigned long ComputeHostBufferSizeGivenHardUpperLimit( + unsigned long userFramesPerBuffer, + unsigned long absoluteMaximumBufferSizeFrames ) +{ + static unsigned long primes_[] = { 2, 3, 5, 7, 11, 13, 17, 19, 23, + 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 0 }; /* zero terminated */ + + unsigned long result = userFramesPerBuffer; + int i; + + assert( absoluteMaximumBufferSizeFrames > 67 ); /* assume maximum is large and we're only factoring by small primes */ + + /* search for the largest integer factor of userFramesPerBuffer less + than or equal to absoluteMaximumBufferSizeFrames */ + + /* repeatedly divide by smallest prime factors until a buffer size + smaller than absoluteMaximumBufferSizeFrames is found */ + while( result > absoluteMaximumBufferSizeFrames ){ + + /* search for the smallest prime factor of result */ + for( i=0; primes_[i] != 0; ++i ) + { + unsigned long p = primes_[i]; + unsigned long divided = result / p; + if( divided*p == result ) + { + result = divided; + break; /* continue with outer while loop */ + } + } + if( primes_[i] == 0 ) + { /* loop failed to find a prime factor, return an approximate result */ + unsigned long d = (userFramesPerBuffer + (absoluteMaximumBufferSizeFrames-1)) + / absoluteMaximumBufferSizeFrames; + return userFramesPerBuffer / d; + } + } + + return result; +} + + +static PaError SelectHostBufferSizeFramesAndHostBufferCount( + unsigned long suggestedLatencyFrames, + unsigned long userFramesPerBuffer, + unsigned long minimumBufferCount, + unsigned long preferredMaximumBufferSizeFrames, /* try not to exceed this. for example, don't exceed when coalescing buffers */ + unsigned long absoluteMaximumBufferSizeFrames, /* never exceed this, a hard limit */ + unsigned long *hostBufferSizeFrames, + unsigned long *hostBufferCount ) +{ + unsigned long effectiveUserFramesPerBuffer; + unsigned long numberOfUserBuffersPerHostBuffer; + + + if( userFramesPerBuffer == paFramesPerBufferUnspecified ){ + + effectiveUserFramesPerBuffer = PA_MME_HOST_BUFFER_GRANULARITY_FRAMES_WHEN_UNSPECIFIED_; + + }else{ + + if( userFramesPerBuffer > absoluteMaximumBufferSizeFrames ){ + + /* user has requested a user buffer that's larger than absoluteMaximumBufferSizeFrames. + try to choose a buffer size that is equal or smaller than absoluteMaximumBufferSizeFrames + but is also an integer factor of userFramesPerBuffer, so as to distribute computation evenly. + the buffer processor will handle the block adaption between host and user buffer sizes. + see http://www.portaudio.com/trac/ticket/189 for discussion. + */ + + effectiveUserFramesPerBuffer = ComputeHostBufferSizeGivenHardUpperLimit( userFramesPerBuffer, absoluteMaximumBufferSizeFrames ); + assert( effectiveUserFramesPerBuffer <= absoluteMaximumBufferSizeFrames ); + + /* try to ensure that duration of host buffering is at least as + large as duration of user buffer. */ + if( suggestedLatencyFrames < userFramesPerBuffer ) + suggestedLatencyFrames = userFramesPerBuffer; + + }else{ + + effectiveUserFramesPerBuffer = userFramesPerBuffer; + } + } + + /* compute a host buffer count based on suggestedLatencyFrames and our granularity */ + + *hostBufferSizeFrames = effectiveUserFramesPerBuffer; + + *hostBufferCount = ComputeHostBufferCountForFixedBufferSizeFrames( + suggestedLatencyFrames, *hostBufferSizeFrames, minimumBufferCount ); + + if( *hostBufferSizeFrames >= userFramesPerBuffer ) + { + /* + If there are too many host buffers we would like to coalesce + them by packing an integer number of user buffers into each host buffer. + We try to coalesce such that hostBufferCount will lie between + PA_MME_TARGET_HOST_BUFFER_COUNT_ and (PA_MME_TARGET_HOST_BUFFER_COUNT_*2)-1. + We limit coalescing to avoid exceeding either absoluteMaximumBufferSizeFrames and + preferredMaximumBufferSizeFrames. + + First, compute a coalescing factor: the number of user buffers per host buffer. + The goal is to achieve PA_MME_TARGET_HOST_BUFFER_COUNT_ total buffer count. + Since our latency is computed based on (*hostBufferCount - 1) we compute a + coalescing factor based on (*hostBufferCount - 1) and (PA_MME_TARGET_HOST_BUFFER_COUNT_-1). + + The + (PA_MME_TARGET_HOST_BUFFER_COUNT_-2) term below is intended to round up. + */ + numberOfUserBuffersPerHostBuffer = ((*hostBufferCount - 1) + (PA_MME_TARGET_HOST_BUFFER_COUNT_-2)) / (PA_MME_TARGET_HOST_BUFFER_COUNT_ - 1); + + if( numberOfUserBuffersPerHostBuffer > 1 ) + { + unsigned long maxCoalescedBufferSizeFrames = (absoluteMaximumBufferSizeFrames < preferredMaximumBufferSizeFrames) /* minimum of our limits */ + ? absoluteMaximumBufferSizeFrames + : preferredMaximumBufferSizeFrames; + + unsigned long maxUserBuffersPerHostBuffer = maxCoalescedBufferSizeFrames / effectiveUserFramesPerBuffer; /* don't coalesce more than this */ + + if( numberOfUserBuffersPerHostBuffer > maxUserBuffersPerHostBuffer ) + numberOfUserBuffersPerHostBuffer = maxUserBuffersPerHostBuffer; + + *hostBufferSizeFrames = effectiveUserFramesPerBuffer * numberOfUserBuffersPerHostBuffer; + + /* recompute hostBufferCount to approximate suggestedLatencyFrames now that hostBufferSizeFrames is larger */ + *hostBufferCount = ComputeHostBufferCountForFixedBufferSizeFrames( + suggestedLatencyFrames, *hostBufferSizeFrames, minimumBufferCount ); + } + } + + return paNoError; +} + + +static PaError CalculateMaxHostSampleFrameSizeBytes( + int channelCount, + PaSampleFormat hostSampleFormat, + const PaWinMmeStreamInfo *streamInfo, + int *hostSampleFrameSizeBytes ) +{ + unsigned int i; + /* PA WMME streams may aggregate multiple WMME devices. When the stream addresses + more than one device in a single direction, maxDeviceChannelCount is the maximum + number of channels used by a single device. + */ + int maxDeviceChannelCount = channelCount; + int hostSampleSizeBytes = Pa_GetSampleSize( hostSampleFormat ); + if( hostSampleSizeBytes < 0 ) + { + return hostSampleSizeBytes; /* the value of hostSampleSize here is an error code, not a sample size */ + } + + if( streamInfo && ( streamInfo->flags & paWinMmeUseMultipleDevices ) ) + { + maxDeviceChannelCount = streamInfo->devices[0].channelCount; + for( i=1; i< streamInfo->deviceCount; ++i ) + { + if( streamInfo->devices[i].channelCount > maxDeviceChannelCount ) + maxDeviceChannelCount = streamInfo->devices[i].channelCount; + } + } + + *hostSampleFrameSizeBytes = hostSampleSizeBytes * maxDeviceChannelCount; + + return paNoError; +} + + +/* CalculateBufferSettings() fills the framesPerHostInputBuffer, hostInputBufferCount, + framesPerHostOutputBuffer and hostOutputBufferCount parameters based on the values + of the other parameters. +*/ + +static PaError CalculateBufferSettings( + unsigned long *hostFramesPerInputBuffer, unsigned long *hostInputBufferCount, + unsigned long *hostFramesPerOutputBuffer, unsigned long *hostOutputBufferCount, + int inputChannelCount, PaSampleFormat hostInputSampleFormat, + PaTime suggestedInputLatency, const PaWinMmeStreamInfo *inputStreamInfo, + int outputChannelCount, PaSampleFormat hostOutputSampleFormat, + PaTime suggestedOutputLatency, const PaWinMmeStreamInfo *outputStreamInfo, + double sampleRate, unsigned long userFramesPerBuffer ) +{ + PaError result = paNoError; + + if( inputChannelCount > 0 ) /* stream has input */ + { + int hostInputFrameSizeBytes; + result = CalculateMaxHostSampleFrameSizeBytes( + inputChannelCount, hostInputSampleFormat, inputStreamInfo, &hostInputFrameSizeBytes ); + if( result != paNoError ) + goto error; + + if( inputStreamInfo + && ( inputStreamInfo->flags & paWinMmeUseLowLevelLatencyParameters ) ) + { + /* input - using low level latency parameters if provided */ + + if( inputStreamInfo->bufferCount <= 0 + || inputStreamInfo->framesPerBuffer <= 0 ) + { + result = paIncompatibleHostApiSpecificStreamInfo; + goto error; + } + + *hostFramesPerInputBuffer = inputStreamInfo->framesPerBuffer; + *hostInputBufferCount = inputStreamInfo->bufferCount; + } + else + { + /* input - not using low level latency parameters, so compute + hostFramesPerInputBuffer and hostInputBufferCount + based on userFramesPerBuffer and suggestedInputLatency. */ + + unsigned long minimumBufferCount = (outputChannelCount > 0) + ? PA_MME_MIN_HOST_INPUT_BUFFER_COUNT_FULL_DUPLEX_ + : PA_MME_MIN_HOST_INPUT_BUFFER_COUNT_HALF_DUPLEX_; + + result = SelectHostBufferSizeFramesAndHostBufferCount( + (unsigned long)(suggestedInputLatency * sampleRate), /* (truncate) */ + userFramesPerBuffer, + minimumBufferCount, + (unsigned long)(PA_MME_MAX_HOST_BUFFER_SECS_ * sampleRate), /* in frames. preferred maximum */ + (PA_MME_MAX_HOST_BUFFER_BYTES_ / hostInputFrameSizeBytes), /* in frames. a hard limit. note truncation due to + division is intentional here to limit max bytes */ + hostFramesPerInputBuffer, + hostInputBufferCount ); + if( result != paNoError ) + goto error; + } + } + else + { + *hostFramesPerInputBuffer = 0; + *hostInputBufferCount = 0; + } + + if( outputChannelCount > 0 ) /* stream has output */ + { + if( outputStreamInfo + && ( outputStreamInfo->flags & paWinMmeUseLowLevelLatencyParameters ) ) + { + /* output - using low level latency parameters */ + + if( outputStreamInfo->bufferCount <= 0 + || outputStreamInfo->framesPerBuffer <= 0 ) + { + result = paIncompatibleHostApiSpecificStreamInfo; + goto error; + } + + *hostFramesPerOutputBuffer = outputStreamInfo->framesPerBuffer; + *hostOutputBufferCount = outputStreamInfo->bufferCount; + + if( inputChannelCount > 0 ) /* full duplex */ + { + /* harmonize hostFramesPerInputBuffer and hostFramesPerOutputBuffer */ + + if( *hostFramesPerInputBuffer != *hostFramesPerOutputBuffer ) + { + if( inputStreamInfo + && ( inputStreamInfo->flags & paWinMmeUseLowLevelLatencyParameters ) ) + { + /* a custom StreamInfo was used for specifying both input + and output buffer sizes. We require that the larger buffer size + must be a multiple of the smaller buffer size */ + + if( *hostFramesPerInputBuffer < *hostFramesPerOutputBuffer ) + { + if( *hostFramesPerOutputBuffer % *hostFramesPerInputBuffer != 0 ) + { + result = paIncompatibleHostApiSpecificStreamInfo; + goto error; + } + } + else + { + assert( *hostFramesPerInputBuffer > *hostFramesPerOutputBuffer ); + if( *hostFramesPerInputBuffer % *hostFramesPerOutputBuffer != 0 ) + { + result = paIncompatibleHostApiSpecificStreamInfo; + goto error; + } + } + } + else + { + /* a custom StreamInfo was not used for specifying the input buffer size, + so use the output buffer size, and approximately the suggested input latency. */ + + *hostFramesPerInputBuffer = *hostFramesPerOutputBuffer; + + *hostInputBufferCount = ComputeHostBufferCountForFixedBufferSizeFrames( + (unsigned long)(suggestedInputLatency * sampleRate), + *hostFramesPerInputBuffer, + PA_MME_MIN_HOST_INPUT_BUFFER_COUNT_FULL_DUPLEX_ ); + } + } + } + } + else + { + /* output - no low level latency parameters, so compute hostFramesPerOutputBuffer and hostOutputBufferCount + based on userFramesPerBuffer and suggestedOutputLatency. */ + + int hostOutputFrameSizeBytes; + result = CalculateMaxHostSampleFrameSizeBytes( + outputChannelCount, hostOutputSampleFormat, outputStreamInfo, &hostOutputFrameSizeBytes ); + if( result != paNoError ) + goto error; + + /* compute the output buffer size and count */ + + result = SelectHostBufferSizeFramesAndHostBufferCount( + (unsigned long)(suggestedOutputLatency * sampleRate), /* (truncate) */ + userFramesPerBuffer, + PA_MME_MIN_HOST_OUTPUT_BUFFER_COUNT_, + (unsigned long)(PA_MME_MAX_HOST_BUFFER_SECS_ * sampleRate), /* in frames. preferred maximum */ + (PA_MME_MAX_HOST_BUFFER_BYTES_ / hostOutputFrameSizeBytes), /* in frames. a hard limit. note truncation due to + division is intentional here to limit max bytes */ + hostFramesPerOutputBuffer, + hostOutputBufferCount ); + if( result != paNoError ) + goto error; + + if( inputChannelCount > 0 ) /* full duplex */ + { + /* harmonize hostFramesPerInputBuffer and hostFramesPerOutputBuffer */ + + /* ensure that both input and output buffer sizes are the same. + if they don't match at this stage, choose the smallest one + and use that for input and output and recompute the corresponding + buffer count accordingly. + */ + + if( *hostFramesPerOutputBuffer != *hostFramesPerInputBuffer ) + { + if( hostFramesPerInputBuffer < hostFramesPerOutputBuffer ) + { + *hostFramesPerOutputBuffer = *hostFramesPerInputBuffer; + + *hostOutputBufferCount = ComputeHostBufferCountForFixedBufferSizeFrames( + (unsigned long)(suggestedOutputLatency * sampleRate), + *hostOutputBufferCount, + PA_MME_MIN_HOST_OUTPUT_BUFFER_COUNT_ ); + } + else + { + *hostFramesPerInputBuffer = *hostFramesPerOutputBuffer; + + *hostInputBufferCount = ComputeHostBufferCountForFixedBufferSizeFrames( + (unsigned long)(suggestedInputLatency * sampleRate), + *hostFramesPerInputBuffer, + PA_MME_MIN_HOST_INPUT_BUFFER_COUNT_FULL_DUPLEX_ ); + } + } + } + } + } + else + { + *hostFramesPerOutputBuffer = 0; + *hostOutputBufferCount = 0; + } + +error: + return result; +} + + +typedef struct +{ + HANDLE bufferEvent; + void *waveHandles; + unsigned int deviceCount; + /* unsigned int channelCount; */ + WAVEHDR **waveHeaders; /* waveHeaders[device][buffer] */ + unsigned int bufferCount; + unsigned int currentBufferIndex; + unsigned int framesPerBuffer; + unsigned int framesUsedInCurrentBuffer; +}PaWinMmeSingleDirectionHandlesAndBuffers; + +/* prototypes for functions operating on PaWinMmeSingleDirectionHandlesAndBuffers */ + +static void InitializeSingleDirectionHandlesAndBuffers( PaWinMmeSingleDirectionHandlesAndBuffers *handlesAndBuffers ); +static PaError InitializeWaveHandles( PaWinMmeHostApiRepresentation *winMmeHostApi, + PaWinMmeSingleDirectionHandlesAndBuffers *handlesAndBuffers, + unsigned long winMmeSpecificFlags, + unsigned long bytesPerHostSample, + double sampleRate, PaWinMmeDeviceAndChannelCount *devices, + unsigned int deviceCount, PaWinWaveFormatChannelMask channelMask, int isInput ); +static PaError TerminateWaveHandles( PaWinMmeSingleDirectionHandlesAndBuffers *handlesAndBuffers, int isInput, int currentlyProcessingAnError ); +static PaError InitializeWaveHeaders( PaWinMmeSingleDirectionHandlesAndBuffers *handlesAndBuffers, + unsigned long hostBufferCount, + PaSampleFormat hostSampleFormat, + unsigned long framesPerHostBuffer, + PaWinMmeDeviceAndChannelCount *devices, + int isInput ); +static void TerminateWaveHeaders( PaWinMmeSingleDirectionHandlesAndBuffers *handlesAndBuffers, int isInput ); + + +static void InitializeSingleDirectionHandlesAndBuffers( PaWinMmeSingleDirectionHandlesAndBuffers *handlesAndBuffers ) +{ + handlesAndBuffers->bufferEvent = 0; + handlesAndBuffers->waveHandles = 0; + handlesAndBuffers->deviceCount = 0; + handlesAndBuffers->waveHeaders = 0; + handlesAndBuffers->bufferCount = 0; +} + +static PaError InitializeWaveHandles( PaWinMmeHostApiRepresentation *winMmeHostApi, + PaWinMmeSingleDirectionHandlesAndBuffers *handlesAndBuffers, + unsigned long winMmeSpecificFlags, + unsigned long bytesPerHostSample, + double sampleRate, PaWinMmeDeviceAndChannelCount *devices, + unsigned int deviceCount, PaWinWaveFormatChannelMask channelMask, int isInput ) +{ + PaError result; + MMRESULT mmresult; + signed int i, j; + PaSampleFormat sampleFormat; + int waveFormatTag; + + /* for error cleanup we expect that InitializeSingleDirectionHandlesAndBuffers() + has already been called to zero some fields */ + + result = CreateEventWithPaError( &handlesAndBuffers->bufferEvent, NULL, FALSE, FALSE, NULL ); + if( result != paNoError ) goto error; + + if( isInput ) + handlesAndBuffers->waveHandles = (void*)PaUtil_AllocateMemory( sizeof(HWAVEIN) * deviceCount ); + else + handlesAndBuffers->waveHandles = (void*)PaUtil_AllocateMemory( sizeof(HWAVEOUT) * deviceCount ); + if( !handlesAndBuffers->waveHandles ) + { + result = paInsufficientMemory; + goto error; + } + + handlesAndBuffers->deviceCount = deviceCount; + + for( i = 0; i < (signed int)deviceCount; ++i ) + { + if( isInput ) + ((HWAVEIN*)handlesAndBuffers->waveHandles)[i] = 0; + else + ((HWAVEOUT*)handlesAndBuffers->waveHandles)[i] = 0; + } + + /* @todo at the moment we only use 16 bit sample format */ + sampleFormat = paInt16; + waveFormatTag = SampleFormatAndWinWmmeSpecificFlagsToLinearWaveFormatTag( sampleFormat, winMmeSpecificFlags ); + + for( i = 0; i < (signed int)deviceCount; ++i ) + { + PaWinWaveFormat waveFormat; + UINT winMmeDeviceId = LocalDeviceIndexToWinMmeDeviceId( winMmeHostApi, devices[i].device ); + + /* @todo: consider providing a flag or #define to not try waveformat extensible + this could just initialize j to 1 the first time round. */ + + for( j = 0; j < 2; ++j ) + { + switch(j){ + case 0: + /* first, attempt to open the device using WAVEFORMATEXTENSIBLE, + if this fails we fall back to WAVEFORMATEX */ + + PaWin_InitializeWaveFormatExtensible( &waveFormat, devices[i].channelCount, + sampleFormat, waveFormatTag, sampleRate, channelMask ); + break; + + case 1: + /* retry with WAVEFORMATEX */ + + PaWin_InitializeWaveFormatEx( &waveFormat, devices[i].channelCount, + sampleFormat, waveFormatTag, sampleRate ); + break; + } + + /* REVIEW: consider not firing an event for input when a full duplex + stream is being used. this would probably depend on the + neverDropInput flag. */ + + if( isInput ) + { + mmresult = waveInOpen( &((HWAVEIN*)handlesAndBuffers->waveHandles)[i], winMmeDeviceId, + (WAVEFORMATEX*)&waveFormat, + (DWORD_PTR)handlesAndBuffers->bufferEvent, (DWORD_PTR)0, CALLBACK_EVENT ); + } + else + { + mmresult = waveOutOpen( &((HWAVEOUT*)handlesAndBuffers->waveHandles)[i], winMmeDeviceId, + (WAVEFORMATEX*)&waveFormat, + (DWORD_PTR)handlesAndBuffers->bufferEvent, (DWORD_PTR)0, CALLBACK_EVENT ); + } + + if( mmresult == MMSYSERR_NOERROR ) + { + break; /* success */ + } + else if( j == 0 ) + { + continue; /* try again with WAVEFORMATEX */ + } + else + { + switch( mmresult ) + { + case MMSYSERR_ALLOCATED: /* Specified resource is already allocated. */ + result = paDeviceUnavailable; + break; + case MMSYSERR_NODRIVER: /* No device driver is present. */ + result = paDeviceUnavailable; + break; + case MMSYSERR_NOMEM: /* Unable to allocate or lock memory. */ + result = paInsufficientMemory; + break; + + case MMSYSERR_BADDEVICEID: /* Specified device identifier is out of range. */ + /* falls through */ + + case WAVERR_BADFORMAT: /* Attempted to open with an unsupported waveform-audio format. */ + /* This can also occur if we try to open the device with an unsupported + * number of channels. This is attempted when device*ChannelCountIsKnown is + * set to 0. + */ + /* falls through */ + default: + result = paUnanticipatedHostError; + if( isInput ) + { + PA_MME_SET_LAST_WAVEIN_ERROR( mmresult ); + } + else + { + PA_MME_SET_LAST_WAVEOUT_ERROR( mmresult ); + } + } + goto error; + } + } + } + + return result; + +error: + TerminateWaveHandles( handlesAndBuffers, isInput, 1 /* currentlyProcessingAnError */ ); + + return result; +} + + +static PaError TerminateWaveHandles( PaWinMmeSingleDirectionHandlesAndBuffers *handlesAndBuffers, int isInput, int currentlyProcessingAnError ) +{ + PaError result = paNoError; + MMRESULT mmresult; + signed int i; + + if( handlesAndBuffers->waveHandles ) + { + for( i = handlesAndBuffers->deviceCount-1; i >= 0; --i ) + { + if( isInput ) + { + if( ((HWAVEIN*)handlesAndBuffers->waveHandles)[i] ) + mmresult = waveInClose( ((HWAVEIN*)handlesAndBuffers->waveHandles)[i] ); + else + mmresult = MMSYSERR_NOERROR; + } + else + { + if( ((HWAVEOUT*)handlesAndBuffers->waveHandles)[i] ) + mmresult = waveOutClose( ((HWAVEOUT*)handlesAndBuffers->waveHandles)[i] ); + else + mmresult = MMSYSERR_NOERROR; + } + + if( mmresult != MMSYSERR_NOERROR && + !currentlyProcessingAnError ) /* don't update the error state if we're already processing an error */ + { + result = paUnanticipatedHostError; + if( isInput ) + { + PA_MME_SET_LAST_WAVEIN_ERROR( mmresult ); + } + else + { + PA_MME_SET_LAST_WAVEOUT_ERROR( mmresult ); + } + /* note that we don't break here, we try to continue closing devices */ + } + } + + PaUtil_FreeMemory( handlesAndBuffers->waveHandles ); + handlesAndBuffers->waveHandles = 0; + } + + if( handlesAndBuffers->bufferEvent ) + { + result = CloseHandleWithPaError( handlesAndBuffers->bufferEvent ); + handlesAndBuffers->bufferEvent = 0; + } + + return result; +} + + +static PaError InitializeWaveHeaders( PaWinMmeSingleDirectionHandlesAndBuffers *handlesAndBuffers, + unsigned long hostBufferCount, + PaSampleFormat hostSampleFormat, + unsigned long framesPerHostBuffer, + PaWinMmeDeviceAndChannelCount *devices, + int isInput ) +{ + PaError result = paNoError; + MMRESULT mmresult; + WAVEHDR *deviceWaveHeaders; + signed int i, j; + + /* for error cleanup we expect that InitializeSingleDirectionHandlesAndBuffers() + has already been called to zero some fields */ + + + /* allocate an array of pointers to arrays of wave headers, one array of + wave headers per device */ + handlesAndBuffers->waveHeaders = (WAVEHDR**)PaUtil_AllocateMemory( sizeof(WAVEHDR*) * handlesAndBuffers->deviceCount ); + if( !handlesAndBuffers->waveHeaders ) + { + result = paInsufficientMemory; + goto error; + } + + for( i = 0; i < (signed int)handlesAndBuffers->deviceCount; ++i ) + handlesAndBuffers->waveHeaders[i] = 0; + + handlesAndBuffers->bufferCount = hostBufferCount; + + for( i = 0; i < (signed int)handlesAndBuffers->deviceCount; ++i ) + { + int bufferBytes = Pa_GetSampleSize( hostSampleFormat ) * + framesPerHostBuffer * devices[i].channelCount; + if( bufferBytes < 0 ) + { + result = paInternalError; + goto error; + } + + /* Allocate an array of wave headers for device i */ + deviceWaveHeaders = (WAVEHDR *) PaUtil_AllocateMemory( sizeof(WAVEHDR)*hostBufferCount ); + if( !deviceWaveHeaders ) + { + result = paInsufficientMemory; + goto error; + } + + for( j=0; j < (signed int)hostBufferCount; ++j ) + deviceWaveHeaders[j].lpData = 0; + + handlesAndBuffers->waveHeaders[i] = deviceWaveHeaders; + + /* Allocate a buffer for each wave header */ + for( j=0; j < (signed int)hostBufferCount; ++j ) + { + deviceWaveHeaders[j].lpData = (char *)PaUtil_AllocateMemory( bufferBytes ); + if( !deviceWaveHeaders[j].lpData ) + { + result = paInsufficientMemory; + goto error; + } + deviceWaveHeaders[j].dwBufferLength = bufferBytes; + deviceWaveHeaders[j].dwUser = 0xFFFFFFFF; /* indicates that *PrepareHeader() has not yet been called, for error clean up code */ + + if( isInput ) + { + mmresult = waveInPrepareHeader( ((HWAVEIN*)handlesAndBuffers->waveHandles)[i], &deviceWaveHeaders[j], sizeof(WAVEHDR) ); + if( mmresult != MMSYSERR_NOERROR ) + { + result = paUnanticipatedHostError; + PA_MME_SET_LAST_WAVEIN_ERROR( mmresult ); + goto error; + } + } + else /* output */ + { + mmresult = waveOutPrepareHeader( ((HWAVEOUT*)handlesAndBuffers->waveHandles)[i], &deviceWaveHeaders[j], sizeof(WAVEHDR) ); + if( mmresult != MMSYSERR_NOERROR ) + { + result = paUnanticipatedHostError; + PA_MME_SET_LAST_WAVEIN_ERROR( mmresult ); + goto error; + } + } + deviceWaveHeaders[j].dwUser = devices[i].channelCount; + } + } + + return result; + +error: + TerminateWaveHeaders( handlesAndBuffers, isInput ); + + return result; +} + + +static void TerminateWaveHeaders( PaWinMmeSingleDirectionHandlesAndBuffers *handlesAndBuffers, int isInput ) +{ + signed int i, j; + WAVEHDR *deviceWaveHeaders; + + if( handlesAndBuffers->waveHeaders ) + { + for( i = handlesAndBuffers->deviceCount-1; i >= 0 ; --i ) + { + deviceWaveHeaders = handlesAndBuffers->waveHeaders[i]; /* wave headers for device i */ + if( deviceWaveHeaders ) + { + for( j = handlesAndBuffers->bufferCount-1; j >= 0; --j ) + { + if( deviceWaveHeaders[j].lpData ) + { + if( deviceWaveHeaders[j].dwUser != 0xFFFFFFFF ) + { + if( isInput ) + waveInUnprepareHeader( ((HWAVEIN*)handlesAndBuffers->waveHandles)[i], &deviceWaveHeaders[j], sizeof(WAVEHDR) ); + else + waveOutUnprepareHeader( ((HWAVEOUT*)handlesAndBuffers->waveHandles)[i], &deviceWaveHeaders[j], sizeof(WAVEHDR) ); + } + + PaUtil_FreeMemory( deviceWaveHeaders[j].lpData ); + } + } + + PaUtil_FreeMemory( deviceWaveHeaders ); + } + } + + PaUtil_FreeMemory( handlesAndBuffers->waveHeaders ); + handlesAndBuffers->waveHeaders = 0; + } +} + + + +/* PaWinMmeStream - a stream data structure specifically for this implementation */ +/* note that struct PaWinMmeStream is typedeffed to PaWinMmeStream above. */ +struct PaWinMmeStream +{ + PaUtilStreamRepresentation streamRepresentation; + PaUtilCpuLoadMeasurer cpuLoadMeasurer; + PaUtilBufferProcessor bufferProcessor; + + int primeStreamUsingCallback; + + PaWinMmeSingleDirectionHandlesAndBuffers input; + PaWinMmeSingleDirectionHandlesAndBuffers output; + + /* Processing thread management -------------- */ + HANDLE abortEvent; + HANDLE processingThread; + PA_THREAD_ID processingThreadId; + + char throttleProcessingThreadOnOverload; /* 0 -> don't throtte, non-0 -> throttle */ + int processingThreadPriority; + int highThreadPriority; + int throttledThreadPriority; + unsigned long throttledSleepMsecs; + + int isStopped; + volatile int isActive; + volatile int stopProcessing; /* stop thread once existing buffers have been returned */ + volatile int abortProcessing; /* stop thread immediately */ + + DWORD allBuffersDurationMs; /* used to calculate timeouts */ +}; + +/* updates deviceCount if PaWinMmeUseMultipleDevices is used */ + +static PaError ValidateWinMmeSpecificStreamInfo( + const PaStreamParameters *streamParameters, + const PaWinMmeStreamInfo *streamInfo, + unsigned long *winMmeSpecificFlags, + char *throttleProcessingThreadOnOverload, + unsigned long *deviceCount ) +{ + if( streamInfo ) + { + if( streamInfo->size != sizeof( PaWinMmeStreamInfo ) + || streamInfo->version != 1 ) + { + return paIncompatibleHostApiSpecificStreamInfo; + } + + *winMmeSpecificFlags = streamInfo->flags; + + if( streamInfo->flags & paWinMmeDontThrottleOverloadedProcessingThread ) + *throttleProcessingThreadOnOverload = 0; + + if( streamInfo->flags & paWinMmeUseMultipleDevices ) + { + if( streamParameters->device != paUseHostApiSpecificDeviceSpecification ) + return paInvalidDevice; + + *deviceCount = streamInfo->deviceCount; + } + } + + return paNoError; +} + +static PaError RetrieveDevicesFromStreamParameters( + struct PaUtilHostApiRepresentation *hostApi, + const PaStreamParameters *streamParameters, + const PaWinMmeStreamInfo *streamInfo, + PaWinMmeDeviceAndChannelCount *devices, + unsigned long deviceCount ) +{ + PaError result = paNoError; + unsigned int i; + int totalChannelCount; + PaDeviceIndex hostApiDevice; + + if( streamInfo && streamInfo->flags & paWinMmeUseMultipleDevices ) + { + totalChannelCount = 0; + for( i=0; i < deviceCount; ++i ) + { + /* validate that the device number is within range */ + result = PaUtil_DeviceIndexToHostApiDeviceIndex( &hostApiDevice, + streamInfo->devices[i].device, hostApi ); + if( result != paNoError ) + return result; + + devices[i].device = hostApiDevice; + devices[i].channelCount = streamInfo->devices[i].channelCount; + + totalChannelCount += devices[i].channelCount; + } + + if( totalChannelCount != streamParameters->channelCount ) + { + /* channelCount must match total channels specified by multiple devices */ + return paInvalidChannelCount; /* REVIEW use of this error code */ + } + } + else + { + devices[0].device = streamParameters->device; + devices[0].channelCount = streamParameters->channelCount; + } + + return result; +} + +static PaError ValidateInputChannelCounts( + struct PaUtilHostApiRepresentation *hostApi, + PaWinMmeDeviceAndChannelCount *devices, + unsigned long deviceCount ) +{ + unsigned int i; + PaWinMmeDeviceInfo *inputDeviceInfo; + PaError paerror; + + for( i=0; i < deviceCount; ++i ) + { + if( devices[i].channelCount < 1 ) + return paInvalidChannelCount; + + inputDeviceInfo = + (PaWinMmeDeviceInfo*)hostApi->deviceInfos[ devices[i].device ]; + + paerror = IsInputChannelCountSupported( inputDeviceInfo, devices[i].channelCount ); + if( paerror != paNoError ) + return paerror; + } + + return paNoError; +} + +static PaError ValidateOutputChannelCounts( + struct PaUtilHostApiRepresentation *hostApi, + PaWinMmeDeviceAndChannelCount *devices, + unsigned long deviceCount ) +{ + unsigned int i; + PaWinMmeDeviceInfo *outputDeviceInfo; + PaError paerror; + + for( i=0; i < deviceCount; ++i ) + { + if( devices[i].channelCount < 1 ) + return paInvalidChannelCount; + + outputDeviceInfo = + (PaWinMmeDeviceInfo*)hostApi->deviceInfos[ devices[i].device ]; + + paerror = IsOutputChannelCountSupported( outputDeviceInfo, devices[i].channelCount ); + if( paerror != paNoError ) + return paerror; + } + + return paNoError; +} + + +/* the following macros are intended to improve the readability of the following code */ +#define PA_IS_INPUT_STREAM_( stream ) ( stream ->input.waveHandles ) +#define PA_IS_OUTPUT_STREAM_( stream ) ( stream ->output.waveHandles ) +#define PA_IS_FULL_DUPLEX_STREAM_( stream ) ( stream ->input.waveHandles && stream ->output.waveHandles ) +#define PA_IS_HALF_DUPLEX_STREAM_( stream ) ( !(stream ->input.waveHandles && stream ->output.waveHandles) ) + +static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, + PaStream** s, + const PaStreamParameters *inputParameters, + const PaStreamParameters *outputParameters, + double sampleRate, + unsigned long framesPerBuffer, + PaStreamFlags streamFlags, + PaStreamCallback *streamCallback, + void *userData ) +{ + PaError result; + PaWinMmeHostApiRepresentation *winMmeHostApi = (PaWinMmeHostApiRepresentation*)hostApi; + PaWinMmeStream *stream = 0; + int bufferProcessorIsInitialized = 0; + int streamRepresentationIsInitialized = 0; + PaSampleFormat hostInputSampleFormat, hostOutputSampleFormat; + int inputChannelCount, outputChannelCount; + PaSampleFormat inputSampleFormat, outputSampleFormat; + double suggestedInputLatency, suggestedOutputLatency; + PaWinMmeStreamInfo *inputStreamInfo, *outputStreamInfo; + PaWinWaveFormatChannelMask inputChannelMask, outputChannelMask; + unsigned long framesPerHostInputBuffer; + unsigned long hostInputBufferCount; + unsigned long framesPerHostOutputBuffer; + unsigned long hostOutputBufferCount; + unsigned long framesPerBufferProcessorCall; + PaWinMmeDeviceAndChannelCount *inputDevices = 0; /* contains all devices and channel counts as local host api ids, even when PaWinMmeUseMultipleDevices is not used */ + unsigned long winMmeSpecificInputFlags = 0; + unsigned long inputDeviceCount = 0; + PaWinMmeDeviceAndChannelCount *outputDevices = 0; + unsigned long winMmeSpecificOutputFlags = 0; + unsigned long outputDeviceCount = 0; /* contains all devices and channel counts as local host api ids, even when PaWinMmeUseMultipleDevices is not used */ + char throttleProcessingThreadOnOverload = 1; + + + if( inputParameters ) + { + inputChannelCount = inputParameters->channelCount; + inputSampleFormat = inputParameters->sampleFormat; + suggestedInputLatency = inputParameters->suggestedLatency; + + inputDeviceCount = 1; + + /* validate input hostApiSpecificStreamInfo */ + inputStreamInfo = (PaWinMmeStreamInfo*)inputParameters->hostApiSpecificStreamInfo; + result = ValidateWinMmeSpecificStreamInfo( inputParameters, inputStreamInfo, + &winMmeSpecificInputFlags, + &throttleProcessingThreadOnOverload, + &inputDeviceCount ); + if( result != paNoError ) return result; + + inputDevices = (PaWinMmeDeviceAndChannelCount*)alloca( sizeof(PaWinMmeDeviceAndChannelCount) * inputDeviceCount ); + if( !inputDevices ) return paInsufficientMemory; + + result = RetrieveDevicesFromStreamParameters( hostApi, inputParameters, inputStreamInfo, inputDevices, inputDeviceCount ); + if( result != paNoError ) return result; + + result = ValidateInputChannelCounts( hostApi, inputDevices, inputDeviceCount ); + if( result != paNoError ) return result; + + hostInputSampleFormat = + PaUtil_SelectClosestAvailableFormat( paInt16 /* native formats */, inputSampleFormat ); + + if( inputDeviceCount != 1 ){ + /* always use direct speakers when using multi-device multichannel mode */ + inputChannelMask = PAWIN_SPEAKER_DIRECTOUT; + } + else + { + if( inputStreamInfo && inputStreamInfo->flags & paWinMmeUseChannelMask ) + inputChannelMask = inputStreamInfo->channelMask; + else + inputChannelMask = PaWin_DefaultChannelMask( inputDevices[0].channelCount ); + } + } + else + { + inputChannelCount = 0; + inputSampleFormat = 0; + suggestedInputLatency = 0.; + inputStreamInfo = 0; + hostInputSampleFormat = 0; + } + + + if( outputParameters ) + { + outputChannelCount = outputParameters->channelCount; + outputSampleFormat = outputParameters->sampleFormat; + suggestedOutputLatency = outputParameters->suggestedLatency; + + outputDeviceCount = 1; + + /* validate output hostApiSpecificStreamInfo */ + outputStreamInfo = (PaWinMmeStreamInfo*)outputParameters->hostApiSpecificStreamInfo; + result = ValidateWinMmeSpecificStreamInfo( outputParameters, outputStreamInfo, + &winMmeSpecificOutputFlags, + &throttleProcessingThreadOnOverload, + &outputDeviceCount ); + if( result != paNoError ) return result; + + outputDevices = (PaWinMmeDeviceAndChannelCount*)alloca( sizeof(PaWinMmeDeviceAndChannelCount) * outputDeviceCount ); + if( !outputDevices ) return paInsufficientMemory; + + result = RetrieveDevicesFromStreamParameters( hostApi, outputParameters, outputStreamInfo, outputDevices, outputDeviceCount ); + if( result != paNoError ) return result; + + result = ValidateOutputChannelCounts( hostApi, outputDevices, outputDeviceCount ); + if( result != paNoError ) return result; + + hostOutputSampleFormat = + PaUtil_SelectClosestAvailableFormat( paInt16 /* native formats */, outputSampleFormat ); + + if( outputDeviceCount != 1 ){ + /* always use direct speakers when using multi-device multichannel mode */ + outputChannelMask = PAWIN_SPEAKER_DIRECTOUT; + } + else + { + if( outputStreamInfo && outputStreamInfo->flags & paWinMmeUseChannelMask ) + outputChannelMask = outputStreamInfo->channelMask; + else + outputChannelMask = PaWin_DefaultChannelMask( outputDevices[0].channelCount ); + } + } + else + { + outputChannelCount = 0; + outputSampleFormat = 0; + outputStreamInfo = 0; + hostOutputSampleFormat = 0; + suggestedOutputLatency = 0.; + } + + + /* + IMPLEMENT ME: + - alter sampleRate to a close allowable rate if possible / necessary + */ + + + /* validate platform specific flags */ + if( (streamFlags & paPlatformSpecificFlags) != 0 ) + return paInvalidFlag; /* unexpected platform specific flag */ + + + /* always disable clipping and dithering if we are outputting a raw spdif stream */ + if( (winMmeSpecificOutputFlags & paWinMmeWaveFormatDolbyAc3Spdif) + || (winMmeSpecificOutputFlags & paWinMmeWaveFormatWmaSpdif) ){ + + streamFlags = streamFlags | paClipOff | paDitherOff; + } + + + result = CalculateBufferSettings( &framesPerHostInputBuffer, &hostInputBufferCount, + &framesPerHostOutputBuffer, &hostOutputBufferCount, + inputChannelCount, hostInputSampleFormat, suggestedInputLatency, inputStreamInfo, + outputChannelCount, hostOutputSampleFormat, suggestedOutputLatency, outputStreamInfo, + sampleRate, framesPerBuffer ); + if( result != paNoError ) goto error; + + + stream = (PaWinMmeStream*)PaUtil_AllocateMemory( sizeof(PaWinMmeStream) ); + if( !stream ) + { + result = paInsufficientMemory; + goto error; + } + + InitializeSingleDirectionHandlesAndBuffers( &stream->input ); + InitializeSingleDirectionHandlesAndBuffers( &stream->output ); + + stream->abortEvent = 0; + stream->processingThread = 0; + + stream->throttleProcessingThreadOnOverload = throttleProcessingThreadOnOverload; + + PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation, + ( (streamCallback) + ? &winMmeHostApi->callbackStreamInterface + : &winMmeHostApi->blockingStreamInterface ), + streamCallback, userData ); + streamRepresentationIsInitialized = 1; + + PaUtil_InitializeCpuLoadMeasurer( &stream->cpuLoadMeasurer, sampleRate ); + + + if( inputParameters && outputParameters ) /* full duplex */ + { + if( framesPerHostInputBuffer < framesPerHostOutputBuffer ) + { + assert( (framesPerHostOutputBuffer % framesPerHostInputBuffer) == 0 ); /* CalculateBufferSettings() should guarantee this condition */ + + framesPerBufferProcessorCall = framesPerHostInputBuffer; + } + else + { + assert( (framesPerHostInputBuffer % framesPerHostOutputBuffer) == 0 ); /* CalculateBufferSettings() should guarantee this condition */ + + framesPerBufferProcessorCall = framesPerHostOutputBuffer; + } + } + else if( inputParameters ) + { + framesPerBufferProcessorCall = framesPerHostInputBuffer; + } + else if( outputParameters ) + { + framesPerBufferProcessorCall = framesPerHostOutputBuffer; + } + + stream->input.framesPerBuffer = framesPerHostInputBuffer; + stream->output.framesPerBuffer = framesPerHostOutputBuffer; + + result = PaUtil_InitializeBufferProcessor( &stream->bufferProcessor, + inputChannelCount, inputSampleFormat, hostInputSampleFormat, + outputChannelCount, outputSampleFormat, hostOutputSampleFormat, + sampleRate, streamFlags, framesPerBuffer, + framesPerBufferProcessorCall, paUtilFixedHostBufferSize, + streamCallback, userData ); + if( result != paNoError ) goto error; + + bufferProcessorIsInitialized = 1; + + /* stream info input latency is the minimum buffering latency (unlike suggested and default which are *maximums*) */ + stream->streamRepresentation.streamInfo.inputLatency = + (double)(PaUtil_GetBufferProcessorInputLatencyFrames(&stream->bufferProcessor) + + framesPerHostInputBuffer) / sampleRate; + stream->streamRepresentation.streamInfo.outputLatency = + (double)(PaUtil_GetBufferProcessorOutputLatencyFrames(&stream->bufferProcessor) + + (framesPerHostOutputBuffer * (hostOutputBufferCount-1))) / sampleRate; + stream->streamRepresentation.streamInfo.sampleRate = sampleRate; + + stream->primeStreamUsingCallback = ( (streamFlags&paPrimeOutputBuffersUsingStreamCallback) && streamCallback ) ? 1 : 0; + + /* time to sleep when throttling due to >100% cpu usage. + -a quater of a buffer's duration */ + stream->throttledSleepMsecs = + (unsigned long)(stream->bufferProcessor.framesPerHostBuffer * + stream->bufferProcessor.samplePeriod * .25 * 1000); + + stream->isStopped = 1; + stream->isActive = 0; + + + /* for maximum compatibility with multi-device multichannel drivers, + we first open all devices, then we prepare all buffers, finally + we start all devices ( in StartStream() ). teardown in reverse order. + */ + + if( inputParameters ) + { + result = InitializeWaveHandles( winMmeHostApi, &stream->input, + winMmeSpecificInputFlags, + stream->bufferProcessor.bytesPerHostInputSample, sampleRate, + inputDevices, inputDeviceCount, inputChannelMask, 1 /* isInput */ ); + if( result != paNoError ) goto error; + } + + if( outputParameters ) + { + result = InitializeWaveHandles( winMmeHostApi, &stream->output, + winMmeSpecificOutputFlags, + stream->bufferProcessor.bytesPerHostOutputSample, sampleRate, + outputDevices, outputDeviceCount, outputChannelMask, 0 /* isInput */ ); + if( result != paNoError ) goto error; + } + + if( inputParameters ) + { + result = InitializeWaveHeaders( &stream->input, hostInputBufferCount, + hostInputSampleFormat, framesPerHostInputBuffer, inputDevices, 1 /* isInput */ ); + if( result != paNoError ) goto error; + } + + if( outputParameters ) + { + result = InitializeWaveHeaders( &stream->output, hostOutputBufferCount, + hostOutputSampleFormat, framesPerHostOutputBuffer, outputDevices, 0 /* not isInput */ ); + if( result != paNoError ) goto error; + + stream->allBuffersDurationMs = (DWORD) (1000.0 * (framesPerHostOutputBuffer * stream->output.bufferCount) / sampleRate); + } + else + { + stream->allBuffersDurationMs = (DWORD) (1000.0 * (framesPerHostInputBuffer * stream->input.bufferCount) / sampleRate); + } + + + if( streamCallback ) + { + /* abort event is only needed for callback streams */ + result = CreateEventWithPaError( &stream->abortEvent, NULL, TRUE, FALSE, NULL ); + if( result != paNoError ) goto error; + } + + *s = (PaStream*)stream; + + return result; + +error: + + if( stream ) + { + if( stream->abortEvent ) + CloseHandle( stream->abortEvent ); + + TerminateWaveHeaders( &stream->output, 0 /* not isInput */ ); + TerminateWaveHeaders( &stream->input, 1 /* isInput */ ); + + TerminateWaveHandles( &stream->output, 0 /* not isInput */, 1 /* currentlyProcessingAnError */ ); + TerminateWaveHandles( &stream->input, 1 /* isInput */, 1 /* currentlyProcessingAnError */ ); + + if( bufferProcessorIsInitialized ) + PaUtil_TerminateBufferProcessor( &stream->bufferProcessor ); + + if( streamRepresentationIsInitialized ) + PaUtil_TerminateStreamRepresentation( &stream->streamRepresentation ); + + PaUtil_FreeMemory( stream ); + } + + return result; +} + + +/* return non-zero if all current buffers are done */ +static int BuffersAreDone( WAVEHDR **waveHeaders, unsigned int deviceCount, int bufferIndex ) +{ + unsigned int i; + + for( i=0; i < deviceCount; ++i ) + { + if( !(waveHeaders[i][ bufferIndex ].dwFlags & WHDR_DONE) ) + { + return 0; + } + } + + return 1; +} + +static int CurrentInputBuffersAreDone( PaWinMmeStream *stream ) +{ + return BuffersAreDone( stream->input.waveHeaders, stream->input.deviceCount, stream->input.currentBufferIndex ); +} + +static int CurrentOutputBuffersAreDone( PaWinMmeStream *stream ) +{ + return BuffersAreDone( stream->output.waveHeaders, stream->output.deviceCount, stream->output.currentBufferIndex ); +} + + +/* return non-zero if any buffers are queued */ +static int NoBuffersAreQueued( PaWinMmeSingleDirectionHandlesAndBuffers *handlesAndBuffers ) +{ + unsigned int i, j; + + if( handlesAndBuffers->waveHandles ) + { + for( i=0; i < handlesAndBuffers->bufferCount; ++i ) + { + for( j=0; j < handlesAndBuffers->deviceCount; ++j ) + { + if( !( handlesAndBuffers->waveHeaders[ j ][ i ].dwFlags & WHDR_DONE) ) + { + return 0; + } + } + } + } + + return 1; +} + + +#define PA_CIRCULAR_INCREMENT_( current, max )\ + ( (((current) + 1) >= (max)) ? (0) : (current+1) ) + +#define PA_CIRCULAR_DECREMENT_( current, max )\ + ( ((current) == 0) ? ((max)-1) : (current-1) ) + + +static signed long GetAvailableFrames( PaWinMmeSingleDirectionHandlesAndBuffers *handlesAndBuffers ) +{ + signed long result = 0; + unsigned int i; + + if( BuffersAreDone( handlesAndBuffers->waveHeaders, handlesAndBuffers->deviceCount, handlesAndBuffers->currentBufferIndex ) ) + { + /* we could calculate the following in O(1) if we kept track of the + last done buffer */ + result = handlesAndBuffers->framesPerBuffer - handlesAndBuffers->framesUsedInCurrentBuffer; + + i = PA_CIRCULAR_INCREMENT_( handlesAndBuffers->currentBufferIndex, handlesAndBuffers->bufferCount ); + while( i != handlesAndBuffers->currentBufferIndex ) + { + if( BuffersAreDone( handlesAndBuffers->waveHeaders, handlesAndBuffers->deviceCount, i ) ) + { + result += handlesAndBuffers->framesPerBuffer; + i = PA_CIRCULAR_INCREMENT_( i, handlesAndBuffers->bufferCount ); + } + else + break; + } + } + + return result; +} + + +static PaError AdvanceToNextInputBuffer( PaWinMmeStream *stream ) +{ + PaError result = paNoError; + MMRESULT mmresult; + unsigned int i; + + for( i=0; i < stream->input.deviceCount; ++i ) + { + stream->input.waveHeaders[i][ stream->input.currentBufferIndex ].dwFlags &= ~WHDR_DONE; + mmresult = waveInAddBuffer( ((HWAVEIN*)stream->input.waveHandles)[i], + &stream->input.waveHeaders[i][ stream->input.currentBufferIndex ], + sizeof(WAVEHDR) ); + if( mmresult != MMSYSERR_NOERROR ) + { + result = paUnanticipatedHostError; + PA_MME_SET_LAST_WAVEIN_ERROR( mmresult ); + } + } + + stream->input.currentBufferIndex = + PA_CIRCULAR_INCREMENT_( stream->input.currentBufferIndex, stream->input.bufferCount ); + + stream->input.framesUsedInCurrentBuffer = 0; + + return result; +} + + +static PaError AdvanceToNextOutputBuffer( PaWinMmeStream *stream ) +{ + PaError result = paNoError; + MMRESULT mmresult; + unsigned int i; + + for( i=0; i < stream->output.deviceCount; ++i ) + { + mmresult = waveOutWrite( ((HWAVEOUT*)stream->output.waveHandles)[i], + &stream->output.waveHeaders[i][ stream->output.currentBufferIndex ], + sizeof(WAVEHDR) ); + if( mmresult != MMSYSERR_NOERROR ) + { + result = paUnanticipatedHostError; + PA_MME_SET_LAST_WAVEOUT_ERROR( mmresult ); + } + } + + stream->output.currentBufferIndex = + PA_CIRCULAR_INCREMENT_( stream->output.currentBufferIndex, stream->output.bufferCount ); + + stream->output.framesUsedInCurrentBuffer = 0; + + return result; +} + + +/* requeue all but the most recent input with the driver. Used for catching + up after a total input buffer underrun */ +static PaError CatchUpInputBuffers( PaWinMmeStream *stream ) +{ + PaError result = paNoError; + unsigned int i; + + for( i=0; i < stream->input.bufferCount - 1; ++i ) + { + result = AdvanceToNextInputBuffer( stream ); + if( result != paNoError ) + break; + } + + return result; +} + + +/* take the most recent output and duplicate it to all other output buffers + and requeue them. Used for catching up after a total output buffer underrun. +*/ +static PaError CatchUpOutputBuffers( PaWinMmeStream *stream ) +{ + PaError result = paNoError; + unsigned int i, j; + unsigned int previousBufferIndex = + PA_CIRCULAR_DECREMENT_( stream->output.currentBufferIndex, stream->output.bufferCount ); + + for( i=0; i < stream->output.bufferCount - 1; ++i ) + { + for( j=0; j < stream->output.deviceCount; ++j ) + { + if( stream->output.waveHeaders[j][ stream->output.currentBufferIndex ].lpData + != stream->output.waveHeaders[j][ previousBufferIndex ].lpData ) + { + CopyMemory( stream->output.waveHeaders[j][ stream->output.currentBufferIndex ].lpData, + stream->output.waveHeaders[j][ previousBufferIndex ].lpData, + stream->output.waveHeaders[j][ stream->output.currentBufferIndex ].dwBufferLength ); + } + } + + result = AdvanceToNextOutputBuffer( stream ); + if( result != paNoError ) + break; + } + + return result; +} + + +PA_THREAD_FUNC ProcessingThreadProc( void *pArg ) +{ + PaWinMmeStream *stream = (PaWinMmeStream *)pArg; + HANDLE events[3]; + int eventCount = 0; + DWORD result = paNoError; + DWORD waitResult; + DWORD timeout = (unsigned long)(stream->allBuffersDurationMs * 0.5); + int hostBuffersAvailable; + signed int hostInputBufferIndex, hostOutputBufferIndex; + PaStreamCallbackFlags statusFlags; + int callbackResult; + int done = 0; + unsigned int channel, i; + unsigned long framesProcessed; + + /* prepare event array for call to WaitForMultipleObjects() */ + if( stream->input.bufferEvent ) + events[eventCount++] = stream->input.bufferEvent; + if( stream->output.bufferEvent ) + events[eventCount++] = stream->output.bufferEvent; + events[eventCount++] = stream->abortEvent; + + statusFlags = 0; /** @todo support paInputUnderflow, paOutputOverflow and paNeverDropInput */ + + /* loop until something causes us to stop */ + do{ + /* wait for MME to signal that a buffer is available, or for + the PA abort event to be signaled. + + When this indicates that one or more buffers are available + NoBuffersAreQueued() and Current*BuffersAreDone are used below to + poll for additional done buffers. NoBuffersAreQueued() will fail + to identify an underrun/overflow if the driver doesn't mark all done + buffers prior to signalling the event. Some drivers do this + (eg RME Digi96, and others don't eg VIA PC 97 input). This isn't a + huge problem, it just means that we won't always be able to detect + underflow/overflow. + */ + waitResult = WaitForMultipleObjects( eventCount, events, FALSE /* wait all = FALSE */, timeout ); + if( waitResult == WAIT_FAILED ) + { + result = paUnanticipatedHostError; + /** @todo FIXME/REVIEW: can't return host error info from an asyncronous thread. see http://www.portaudio.com/trac/ticket/143 */ + done = 1; + } + else if( waitResult == WAIT_TIMEOUT ) + { + /* if a timeout is encountered, continue */ + } + + if( stream->abortProcessing ) + { + /* Pa_AbortStream() has been called, stop processing immediately */ + done = 1; + } + else if( stream->stopProcessing ) + { + /* Pa_StopStream() has been called or the user callback returned + non-zero, processing will continue until all output buffers + are marked as done. The stream will stop immediately if it + is input-only. + */ + + if( PA_IS_OUTPUT_STREAM_(stream) ) + { + if( NoBuffersAreQueued( &stream->output ) ) + done = 1; /* Will cause thread to return. */ + } + else + { + /* input only stream */ + done = 1; /* Will cause thread to return. */ + } + } + else + { + hostBuffersAvailable = 1; + + /* process all available host buffers */ + do + { + hostInputBufferIndex = -1; + hostOutputBufferIndex = -1; + + if( PA_IS_INPUT_STREAM_(stream) ) + { + if( CurrentInputBuffersAreDone( stream ) ) + { + if( NoBuffersAreQueued( &stream->input ) ) + { + /** @todo + if all of the other buffers are also ready then + we discard all but the most recent. This is an + input buffer overflow. FIXME: these buffers should + be passed to the callback in a paNeverDropInput + stream. http://www.portaudio.com/trac/ticket/142 + + note that it is also possible for an input overflow + to happen while the callback is processing a buffer. + that is handled further down. + */ + result = CatchUpInputBuffers( stream ); + if( result != paNoError ) + done = 1; + + statusFlags |= paInputOverflow; + } + + hostInputBufferIndex = stream->input.currentBufferIndex; + } + } + + if( PA_IS_OUTPUT_STREAM_(stream) ) + { + if( CurrentOutputBuffersAreDone( stream ) ) + { + /* ok, we have an output buffer */ + + if( NoBuffersAreQueued( &stream->output ) ) + { + /* + if all of the other buffers are also ready, catch up by copying + the most recently generated buffer into all but one of the output + buffers. + + note that this catch up code only handles the case where all + buffers have been played out due to this thread not having + woken up at all. a more common case occurs when this thread + is woken up, processes one buffer, but takes too long, and as + a result all the other buffers have become un-queued. that + case is handled further down. + */ + + result = CatchUpOutputBuffers( stream ); + if( result != paNoError ) + done = 1; + + statusFlags |= paOutputUnderflow; + } + + hostOutputBufferIndex = stream->output.currentBufferIndex; + } + } + + + if( (PA_IS_FULL_DUPLEX_STREAM_(stream) && hostInputBufferIndex != -1 && hostOutputBufferIndex != -1) || + (PA_IS_HALF_DUPLEX_STREAM_(stream) && ( hostInputBufferIndex != -1 || hostOutputBufferIndex != -1 ) ) ) + { + PaStreamCallbackTimeInfo timeInfo = {0,0,0}; /** @todo implement inputBufferAdcTime */ + + + if( PA_IS_OUTPUT_STREAM_(stream) ) + { + /* set timeInfo.currentTime and calculate timeInfo.outputBufferDacTime + from the current wave out position */ + MMTIME mmtime; + double timeBeforeGetPosition, timeAfterGetPosition; + double time; + long framesInBufferRing; + long writePosition; + long playbackPosition; + HWAVEOUT firstWaveOutDevice = ((HWAVEOUT*)stream->output.waveHandles)[0]; + + mmtime.wType = TIME_SAMPLES; + timeBeforeGetPosition = PaUtil_GetTime(); + waveOutGetPosition( firstWaveOutDevice, &mmtime, sizeof(MMTIME) ); + timeAfterGetPosition = PaUtil_GetTime(); + + timeInfo.currentTime = timeAfterGetPosition; + + /* approximate time at which wave out position was measured + as half way between timeBeforeGetPosition and timeAfterGetPosition */ + time = timeBeforeGetPosition + (timeAfterGetPosition - timeBeforeGetPosition) * .5; + + framesInBufferRing = stream->output.bufferCount * stream->bufferProcessor.framesPerHostBuffer; + playbackPosition = mmtime.u.sample % framesInBufferRing; + + writePosition = stream->output.currentBufferIndex * stream->bufferProcessor.framesPerHostBuffer + + stream->output.framesUsedInCurrentBuffer; + + if( playbackPosition >= writePosition ){ + timeInfo.outputBufferDacTime = + time + ((double)( writePosition + (framesInBufferRing - playbackPosition) ) * stream->bufferProcessor.samplePeriod ); + }else{ + timeInfo.outputBufferDacTime = + time + ((double)( writePosition - playbackPosition ) * stream->bufferProcessor.samplePeriod ); + } + } + + + PaUtil_BeginCpuLoadMeasurement( &stream->cpuLoadMeasurer ); + + PaUtil_BeginBufferProcessing( &stream->bufferProcessor, &timeInfo, statusFlags ); + + /* reset status flags once they have been passed to the buffer processor */ + statusFlags = 0; + + if( PA_IS_INPUT_STREAM_(stream) ) + { + PaUtil_SetInputFrameCount( &stream->bufferProcessor, 0 /* default to host buffer size */ ); + + channel = 0; + for( i=0; iinput.deviceCount; ++i ) + { + /* we have stored the number of channels in the buffer in dwUser */ + int channelCount = (int)stream->input.waveHeaders[i][ hostInputBufferIndex ].dwUser; + + PaUtil_SetInterleavedInputChannels( &stream->bufferProcessor, channel, + stream->input.waveHeaders[i][ hostInputBufferIndex ].lpData + + stream->input.framesUsedInCurrentBuffer * channelCount * + stream->bufferProcessor.bytesPerHostInputSample, + channelCount ); + + + channel += channelCount; + } + } + + if( PA_IS_OUTPUT_STREAM_(stream) ) + { + PaUtil_SetOutputFrameCount( &stream->bufferProcessor, 0 /* default to host buffer size */ ); + + channel = 0; + for( i=0; ioutput.deviceCount; ++i ) + { + /* we have stored the number of channels in the buffer in dwUser */ + int channelCount = (int)stream->output.waveHeaders[i][ hostOutputBufferIndex ].dwUser; + + PaUtil_SetInterleavedOutputChannels( &stream->bufferProcessor, channel, + stream->output.waveHeaders[i][ hostOutputBufferIndex ].lpData + + stream->output.framesUsedInCurrentBuffer * channelCount * + stream->bufferProcessor.bytesPerHostOutputSample, + channelCount ); + + channel += channelCount; + } + } + + callbackResult = paContinue; + framesProcessed = PaUtil_EndBufferProcessing( &stream->bufferProcessor, &callbackResult ); + + stream->input.framesUsedInCurrentBuffer += framesProcessed; + stream->output.framesUsedInCurrentBuffer += framesProcessed; + + PaUtil_EndCpuLoadMeasurement( &stream->cpuLoadMeasurer, framesProcessed ); + + if( callbackResult == paContinue ) + { + /* nothing special to do */ + } + else if( callbackResult == paAbort ) + { + stream->abortProcessing = 1; + done = 1; + /** @todo FIXME: should probably reset the output device immediately once the callback returns paAbort + see: http://www.portaudio.com/trac/ticket/141 + */ + result = paNoError; + } + else + { + /* User callback has asked us to stop with paComplete or other non-zero value */ + stream->stopProcessing = 1; /* stop once currently queued audio has finished */ + result = paNoError; + } + + + if( PA_IS_INPUT_STREAM_(stream) + && stream->stopProcessing == 0 && stream->abortProcessing == 0 + && stream->input.framesUsedInCurrentBuffer == stream->input.framesPerBuffer ) + { + if( NoBuffersAreQueued( &stream->input ) ) + { + /** @todo need to handle PaNeverDropInput here where necessary */ + result = CatchUpInputBuffers( stream ); + if( result != paNoError ) + done = 1; + + statusFlags |= paInputOverflow; + } + + result = AdvanceToNextInputBuffer( stream ); + if( result != paNoError ) + done = 1; + } + + + if( PA_IS_OUTPUT_STREAM_(stream) && !stream->abortProcessing ) + { + if( stream->stopProcessing && + stream->output.framesUsedInCurrentBuffer < stream->output.framesPerBuffer ) + { + /* zero remaining samples in output output buffer and flush */ + + stream->output.framesUsedInCurrentBuffer += PaUtil_ZeroOutput( &stream->bufferProcessor, + stream->output.framesPerBuffer - stream->output.framesUsedInCurrentBuffer ); + + /* we send the entire buffer to the output devices, but we could + just send a partial buffer, rather than zeroing the unused + samples. + */ + } + + if( stream->output.framesUsedInCurrentBuffer == stream->output.framesPerBuffer ) + { + /* check for underflow before enquing the just-generated buffer, + but recover from underflow after enquing it. This ensures + that the most recent audio segment is repeated */ + int outputUnderflow = NoBuffersAreQueued( &stream->output ); + + result = AdvanceToNextOutputBuffer( stream ); + if( result != paNoError ) + done = 1; + + if( outputUnderflow && !done && !stream->stopProcessing ) + { + /* Recover from underflow in the case where the + underflow occured while processing the buffer + we just finished */ + + result = CatchUpOutputBuffers( stream ); + if( result != paNoError ) + done = 1; + + statusFlags |= paOutputUnderflow; + } + } + } + + if( stream->throttleProcessingThreadOnOverload != 0 ) + { + if( stream->stopProcessing || stream->abortProcessing ) + { + if( stream->processingThreadPriority != stream->highThreadPriority ) + { + SetThreadPriority( stream->processingThread, stream->highThreadPriority ); + stream->processingThreadPriority = stream->highThreadPriority; + } + } + else if( PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer ) > 1. ) + { + if( stream->processingThreadPriority != stream->throttledThreadPriority ) + { + SetThreadPriority( stream->processingThread, stream->throttledThreadPriority ); + stream->processingThreadPriority = stream->throttledThreadPriority; + } + + /* sleep to give other processes a go */ + Sleep( stream->throttledSleepMsecs ); + } + else + { + if( stream->processingThreadPriority != stream->highThreadPriority ) + { + SetThreadPriority( stream->processingThread, stream->highThreadPriority ); + stream->processingThreadPriority = stream->highThreadPriority; + } + } + } + } + else + { + hostBuffersAvailable = 0; + } + } + while( hostBuffersAvailable && + stream->stopProcessing == 0 && + stream->abortProcessing == 0 && + !done ); + } + } + while( !done ); + + stream->isActive = 0; + + if( stream->streamRepresentation.streamFinishedCallback != 0 ) + stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData ); + + PaUtil_ResetCpuLoadMeasurer( &stream->cpuLoadMeasurer ); + + return result; +} + + +/* + When CloseStream() is called, the multi-api layer ensures that + the stream has already been stopped or aborted. +*/ +static PaError CloseStream( PaStream* s ) +{ + PaError result; + PaWinMmeStream *stream = (PaWinMmeStream*)s; + + result = CloseHandleWithPaError( stream->abortEvent ); + if( result != paNoError ) goto error; + + TerminateWaveHeaders( &stream->output, 0 /* not isInput */ ); + TerminateWaveHeaders( &stream->input, 1 /* isInput */ ); + + TerminateWaveHandles( &stream->output, 0 /* not isInput */, 0 /* not currentlyProcessingAnError */ ); + TerminateWaveHandles( &stream->input, 1 /* isInput */, 0 /* not currentlyProcessingAnError */ ); + + PaUtil_TerminateBufferProcessor( &stream->bufferProcessor ); + PaUtil_TerminateStreamRepresentation( &stream->streamRepresentation ); + PaUtil_FreeMemory( stream ); + +error: + /** @todo REVIEW: what is the best way to clean up a stream if an error is detected? */ + return result; +} + + +static PaError StartStream( PaStream *s ) +{ + PaError result; + PaWinMmeStream *stream = (PaWinMmeStream*)s; + MMRESULT mmresult; + unsigned int i, j; + int callbackResult; + unsigned int channel; + unsigned long framesProcessed; + PaStreamCallbackTimeInfo timeInfo = {0,0,0}; /** @todo implement this for stream priming */ + + PaUtil_ResetBufferProcessor( &stream->bufferProcessor ); + + if( PA_IS_INPUT_STREAM_(stream) ) + { + for( i=0; iinput.bufferCount; ++i ) + { + for( j=0; jinput.deviceCount; ++j ) + { + stream->input.waveHeaders[j][i].dwFlags &= ~WHDR_DONE; + mmresult = waveInAddBuffer( ((HWAVEIN*)stream->input.waveHandles)[j], &stream->input.waveHeaders[j][i], sizeof(WAVEHDR) ); + if( mmresult != MMSYSERR_NOERROR ) + { + result = paUnanticipatedHostError; + PA_MME_SET_LAST_WAVEIN_ERROR( mmresult ); + goto error; + } + } + } + stream->input.currentBufferIndex = 0; + stream->input.framesUsedInCurrentBuffer = 0; + } + + if( PA_IS_OUTPUT_STREAM_(stream) ) + { + for( i=0; ioutput.deviceCount; ++i ) + { + if( (mmresult = waveOutPause( ((HWAVEOUT*)stream->output.waveHandles)[i] )) != MMSYSERR_NOERROR ) + { + result = paUnanticipatedHostError; + PA_MME_SET_LAST_WAVEOUT_ERROR( mmresult ); + goto error; + } + } + + for( i=0; ioutput.bufferCount; ++i ) + { + if( stream->primeStreamUsingCallback ) + { + + stream->output.framesUsedInCurrentBuffer = 0; + do{ + + PaUtil_BeginBufferProcessing( &stream->bufferProcessor, + &timeInfo, + paPrimingOutput | ((stream->input.bufferCount > 0 ) ? paInputUnderflow : 0)); + + if( stream->input.bufferCount > 0 ) + PaUtil_SetNoInput( &stream->bufferProcessor ); + + PaUtil_SetOutputFrameCount( &stream->bufferProcessor, 0 /* default to host buffer size */ ); + + channel = 0; + for( j=0; joutput.deviceCount; ++j ) + { + /* we have stored the number of channels in the buffer in dwUser */ + int channelCount = (int)stream->output.waveHeaders[j][i].dwUser; + + PaUtil_SetInterleavedOutputChannels( &stream->bufferProcessor, channel, + stream->output.waveHeaders[j][i].lpData + + stream->output.framesUsedInCurrentBuffer * channelCount * + stream->bufferProcessor.bytesPerHostOutputSample, + channelCount ); + + /* we have stored the number of channels in the buffer in dwUser */ + channel += channelCount; + } + + callbackResult = paContinue; + framesProcessed = PaUtil_EndBufferProcessing( &stream->bufferProcessor, &callbackResult ); + stream->output.framesUsedInCurrentBuffer += framesProcessed; + + if( callbackResult != paContinue ) + { + /** @todo fix this, what do we do if callback result is non-zero during stream + priming? + + for complete: play out primed waveHeaders as usual + for abort: clean up immediately. + */ + } + + }while( stream->output.framesUsedInCurrentBuffer != stream->output.framesPerBuffer ); + + } + else + { + for( j=0; joutput.deviceCount; ++j ) + { + ZeroMemory( stream->output.waveHeaders[j][i].lpData, stream->output.waveHeaders[j][i].dwBufferLength ); + } + } + + /* we queue all channels of a single buffer frame (accross all + devices, because some multidevice multichannel drivers work + better this way */ + for( j=0; joutput.deviceCount; ++j ) + { + mmresult = waveOutWrite( ((HWAVEOUT*)stream->output.waveHandles)[j], &stream->output.waveHeaders[j][i], sizeof(WAVEHDR) ); + if( mmresult != MMSYSERR_NOERROR ) + { + result = paUnanticipatedHostError; + PA_MME_SET_LAST_WAVEOUT_ERROR( mmresult ); + goto error; + } + } + } + stream->output.currentBufferIndex = 0; + stream->output.framesUsedInCurrentBuffer = 0; + } + + + stream->isStopped = 0; + stream->isActive = 1; + stream->stopProcessing = 0; + stream->abortProcessing = 0; + + result = ResetEventWithPaError( stream->input.bufferEvent ); + if( result != paNoError ) goto error; + + result = ResetEventWithPaError( stream->output.bufferEvent ); + if( result != paNoError ) goto error; + + + if( stream->streamRepresentation.streamCallback ) + { + /* callback stream */ + + result = ResetEventWithPaError( stream->abortEvent ); + if( result != paNoError ) goto error; + + /* Create thread that waits for audio buffers to be ready for processing. */ + stream->processingThread = CREATE_THREAD; + if( !stream->processingThread ) + { + result = paUnanticipatedHostError; + PA_MME_SET_LAST_SYSTEM_ERROR( GetLastError() ); + goto error; + } + + /** @todo could have mme specific stream parameters to allow the user + to set the callback thread priorities */ + stream->highThreadPriority = THREAD_PRIORITY_TIME_CRITICAL; + stream->throttledThreadPriority = THREAD_PRIORITY_NORMAL; + + if( !SetThreadPriority( stream->processingThread, stream->highThreadPriority ) ) + { + result = paUnanticipatedHostError; + PA_MME_SET_LAST_SYSTEM_ERROR( GetLastError() ); + goto error; + } + stream->processingThreadPriority = stream->highThreadPriority; + } + else + { + /* blocking read/write stream */ + + } + + if( PA_IS_INPUT_STREAM_(stream) ) + { + for( i=0; i < stream->input.deviceCount; ++i ) + { + mmresult = waveInStart( ((HWAVEIN*)stream->input.waveHandles)[i] ); + PA_DEBUG(("Pa_StartStream: waveInStart returned = 0x%X.\n", mmresult)); + if( mmresult != MMSYSERR_NOERROR ) + { + result = paUnanticipatedHostError; + PA_MME_SET_LAST_WAVEIN_ERROR( mmresult ); + goto error; + } + } + } + + if( PA_IS_OUTPUT_STREAM_(stream) ) + { + for( i=0; i < stream->output.deviceCount; ++i ) + { + if( (mmresult = waveOutRestart( ((HWAVEOUT*)stream->output.waveHandles)[i] )) != MMSYSERR_NOERROR ) + { + result = paUnanticipatedHostError; + PA_MME_SET_LAST_WAVEOUT_ERROR( mmresult ); + goto error; + } + } + } + + return result; + +error: + /** @todo FIXME: implement recovery as best we can + This should involve rolling back to a state as-if this function had never been called + */ + return result; +} + + +static PaError StopStream( PaStream *s ) +{ + PaError result = paNoError; + PaWinMmeStream *stream = (PaWinMmeStream*)s; + int timeout; + DWORD waitResult; + MMRESULT mmresult; + signed int hostOutputBufferIndex; + unsigned int channel, waitCount, i; + + /** @todo + REVIEW: the error checking in this function needs review. the basic + idea is to return from this function in a known state - for example + there is no point avoiding calling waveInReset just because + the thread times out. + */ + + if( stream->processingThread ) + { + /* callback stream */ + + /* Tell processing thread to stop generating more data and to let current data play out. */ + stream->stopProcessing = 1; + + /* Calculate timeOut longer than longest time it could take to return all buffers. */ + timeout = (int)(stream->allBuffersDurationMs * 1.5); + if( timeout < PA_MME_MIN_TIMEOUT_MSEC_ ) + timeout = PA_MME_MIN_TIMEOUT_MSEC_; + + PA_DEBUG(("WinMME StopStream: waiting for background thread.\n")); + + waitResult = WaitForSingleObject( stream->processingThread, timeout ); + if( waitResult == WAIT_TIMEOUT ) + { + /* try to abort */ + stream->abortProcessing = 1; + SetEvent( stream->abortEvent ); + waitResult = WaitForSingleObject( stream->processingThread, timeout ); + if( waitResult == WAIT_TIMEOUT ) + { + PA_DEBUG(("WinMME StopStream: timed out while waiting for background thread to finish.\n")); + result = paTimedOut; + } + } + + CloseHandle( stream->processingThread ); + stream->processingThread = NULL; + } + else + { + /* blocking read / write stream */ + + if( PA_IS_OUTPUT_STREAM_(stream) ) + { + if( stream->output.framesUsedInCurrentBuffer > 0 ) + { + /* there are still unqueued frames in the current buffer, so flush them */ + + hostOutputBufferIndex = stream->output.currentBufferIndex; + + PaUtil_SetOutputFrameCount( &stream->bufferProcessor, + stream->output.framesPerBuffer - stream->output.framesUsedInCurrentBuffer ); + + channel = 0; + for( i=0; ioutput.deviceCount; ++i ) + { + /* we have stored the number of channels in the buffer in dwUser */ + int channelCount = (int)stream->output.waveHeaders[i][ hostOutputBufferIndex ].dwUser; + + PaUtil_SetInterleavedOutputChannels( &stream->bufferProcessor, channel, + stream->output.waveHeaders[i][ hostOutputBufferIndex ].lpData + + stream->output.framesUsedInCurrentBuffer * channelCount * + stream->bufferProcessor.bytesPerHostOutputSample, + channelCount ); + + channel += channelCount; + } + + PaUtil_ZeroOutput( &stream->bufferProcessor, + stream->output.framesPerBuffer - stream->output.framesUsedInCurrentBuffer ); + + /* we send the entire buffer to the output devices, but we could + just send a partial buffer, rather than zeroing the unused + samples. + */ + AdvanceToNextOutputBuffer( stream ); + } + + + timeout = (stream->allBuffersDurationMs / stream->output.bufferCount) + 1; + if( timeout < PA_MME_MIN_TIMEOUT_MSEC_ ) + timeout = PA_MME_MIN_TIMEOUT_MSEC_; + + waitCount = 0; + while( !NoBuffersAreQueued( &stream->output ) && waitCount <= stream->output.bufferCount ) + { + /* wait for MME to signal that a buffer is available */ + waitResult = WaitForSingleObject( stream->output.bufferEvent, timeout ); + if( waitResult == WAIT_FAILED ) + { + break; + } + else if( waitResult == WAIT_TIMEOUT ) + { + /* keep waiting */ + } + + ++waitCount; + } + } + } + + if( PA_IS_OUTPUT_STREAM_(stream) ) + { + for( i =0; i < stream->output.deviceCount; ++i ) + { + mmresult = waveOutReset( ((HWAVEOUT*)stream->output.waveHandles)[i] ); + if( mmresult != MMSYSERR_NOERROR ) + { + result = paUnanticipatedHostError; + PA_MME_SET_LAST_WAVEOUT_ERROR( mmresult ); + } + } + } + + if( PA_IS_INPUT_STREAM_(stream) ) + { + for( i=0; i < stream->input.deviceCount; ++i ) + { + mmresult = waveInReset( ((HWAVEIN*)stream->input.waveHandles)[i] ); + if( mmresult != MMSYSERR_NOERROR ) + { + result = paUnanticipatedHostError; + PA_MME_SET_LAST_WAVEIN_ERROR( mmresult ); + } + } + } + + stream->isStopped = 1; + stream->isActive = 0; + + return result; +} + + +static PaError AbortStream( PaStream *s ) +{ + PaError result = paNoError; + PaWinMmeStream *stream = (PaWinMmeStream*)s; + int timeout; + DWORD waitResult; + MMRESULT mmresult; + unsigned int i; + + /** @todo + REVIEW: the error checking in this function needs review. the basic + idea is to return from this function in a known state - for example + there is no point avoiding calling waveInReset just because + the thread times out. + */ + + if( stream->processingThread ) + { + /* callback stream */ + + /* Tell processing thread to abort immediately */ + stream->abortProcessing = 1; + SetEvent( stream->abortEvent ); + } + + + if( PA_IS_OUTPUT_STREAM_(stream) ) + { + for( i =0; i < stream->output.deviceCount; ++i ) + { + mmresult = waveOutReset( ((HWAVEOUT*)stream->output.waveHandles)[i] ); + if( mmresult != MMSYSERR_NOERROR ) + { + PA_MME_SET_LAST_WAVEOUT_ERROR( mmresult ); + return paUnanticipatedHostError; + } + } + } + + if( PA_IS_INPUT_STREAM_(stream) ) + { + for( i=0; i < stream->input.deviceCount; ++i ) + { + mmresult = waveInReset( ((HWAVEIN*)stream->input.waveHandles)[i] ); + if( mmresult != MMSYSERR_NOERROR ) + { + PA_MME_SET_LAST_WAVEIN_ERROR( mmresult ); + return paUnanticipatedHostError; + } + } + } + + + if( stream->processingThread ) + { + /* callback stream */ + + PA_DEBUG(("WinMME AbortStream: waiting for background thread.\n")); + + /* Calculate timeOut longer than longest time it could take to return all buffers. */ + timeout = (int)(stream->allBuffersDurationMs * 1.5); + if( timeout < PA_MME_MIN_TIMEOUT_MSEC_ ) + timeout = PA_MME_MIN_TIMEOUT_MSEC_; + + waitResult = WaitForSingleObject( stream->processingThread, timeout ); + if( waitResult == WAIT_TIMEOUT ) + { + PA_DEBUG(("WinMME AbortStream: timed out while waiting for background thread to finish.\n")); + return paTimedOut; + } + + CloseHandle( stream->processingThread ); + stream->processingThread = NULL; + } + + stream->isStopped = 1; + stream->isActive = 0; + + return result; +} + + +static PaError IsStreamStopped( PaStream *s ) +{ + PaWinMmeStream *stream = (PaWinMmeStream*)s; + + return stream->isStopped; +} + + +static PaError IsStreamActive( PaStream *s ) +{ + PaWinMmeStream *stream = (PaWinMmeStream*)s; + + return stream->isActive; +} + + +static PaTime GetStreamTime( PaStream *s ) +{ + (void) s; /* unused parameter */ + + return PaUtil_GetTime(); +} + + +static double GetStreamCpuLoad( PaStream* s ) +{ + PaWinMmeStream *stream = (PaWinMmeStream*)s; + + return PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer ); +} + + +/* + As separate stream interfaces are used for blocking and callback + streams, the following functions can be guaranteed to only be called + for blocking streams. +*/ + +static PaError ReadStream( PaStream* s, + void *buffer, + unsigned long frames ) +{ + PaError result = paNoError; + PaWinMmeStream *stream = (PaWinMmeStream*)s; + void *userBuffer; + unsigned long framesRead = 0; + unsigned long framesProcessed; + signed int hostInputBufferIndex; + DWORD waitResult; + DWORD timeout = (unsigned long)(stream->allBuffersDurationMs * 0.5); + unsigned int channel, i; + + if( PA_IS_INPUT_STREAM_(stream) ) + { + /* make a local copy of the user buffer pointer(s). this is necessary + because PaUtil_CopyInput() advances these pointers every time + it is called. + */ + if( stream->bufferProcessor.userInputIsInterleaved ) + { + userBuffer = buffer; + } + else + { + userBuffer = (void*)alloca( sizeof(void*) * stream->bufferProcessor.inputChannelCount ); + if( !userBuffer ) + return paInsufficientMemory; + for( i = 0; ibufferProcessor.inputChannelCount; ++i ) + ((void**)userBuffer)[i] = ((void**)buffer)[i]; + } + + do{ + if( CurrentInputBuffersAreDone( stream ) ) + { + if( NoBuffersAreQueued( &stream->input ) ) + { + /** @todo REVIEW: consider what to do if the input overflows. + do we requeue all of the buffers? should we be running + a thread to make sure they are always queued? + see: http://www.portaudio.com/trac/ticket/117 + */ + + result = paInputOverflowed; + } + + hostInputBufferIndex = stream->input.currentBufferIndex; + + PaUtil_SetInputFrameCount( &stream->bufferProcessor, + stream->input.framesPerBuffer - stream->input.framesUsedInCurrentBuffer ); + + channel = 0; + for( i=0; iinput.deviceCount; ++i ) + { + /* we have stored the number of channels in the buffer in dwUser */ + int channelCount = (int)stream->input.waveHeaders[i][ hostInputBufferIndex ].dwUser; + + PaUtil_SetInterleavedInputChannels( &stream->bufferProcessor, channel, + stream->input.waveHeaders[i][ hostInputBufferIndex ].lpData + + stream->input.framesUsedInCurrentBuffer * channelCount * + stream->bufferProcessor.bytesPerHostInputSample, + channelCount ); + + channel += channelCount; + } + + framesProcessed = PaUtil_CopyInput( &stream->bufferProcessor, &userBuffer, frames - framesRead ); + + stream->input.framesUsedInCurrentBuffer += framesProcessed; + if( stream->input.framesUsedInCurrentBuffer == stream->input.framesPerBuffer ) + { + result = AdvanceToNextInputBuffer( stream ); + if( result != paNoError ) + break; + } + + framesRead += framesProcessed; + + }else{ + /* wait for MME to signal that a buffer is available */ + waitResult = WaitForSingleObject( stream->input.bufferEvent, timeout ); + if( waitResult == WAIT_FAILED ) + { + result = paUnanticipatedHostError; + break; + } + else if( waitResult == WAIT_TIMEOUT ) + { + /* if a timeout is encountered, continue, + perhaps we should give up eventually + */ + } + } + }while( framesRead < frames ); + } + else + { + result = paCanNotReadFromAnOutputOnlyStream; + } + + return result; +} + + +static PaError WriteStream( PaStream* s, + const void *buffer, + unsigned long frames ) +{ + PaError result = paNoError; + PaWinMmeStream *stream = (PaWinMmeStream*)s; + const void *userBuffer; + unsigned long framesWritten = 0; + unsigned long framesProcessed; + signed int hostOutputBufferIndex; + DWORD waitResult; + DWORD timeout = (unsigned long)(stream->allBuffersDurationMs * 0.5); + unsigned int channel, i; + + + if( PA_IS_OUTPUT_STREAM_(stream) ) + { + /* make a local copy of the user buffer pointer(s). this is necessary + because PaUtil_CopyOutput() advances these pointers every time + it is called. + */ + if( stream->bufferProcessor.userOutputIsInterleaved ) + { + userBuffer = buffer; + } + else + { + userBuffer = (const void*)alloca( sizeof(void*) * stream->bufferProcessor.outputChannelCount ); + if( !userBuffer ) + return paInsufficientMemory; + for( i = 0; ibufferProcessor.outputChannelCount; ++i ) + ((const void**)userBuffer)[i] = ((const void**)buffer)[i]; + } + + do{ + if( CurrentOutputBuffersAreDone( stream ) ) + { + if( NoBuffersAreQueued( &stream->output ) ) + { + /** @todo REVIEW: consider what to do if the output + underflows. do we requeue all the existing buffers with + zeros? should we run a separate thread to keep the buffers + enqueued at all times? + see: http://www.portaudio.com/trac/ticket/117 + */ + + result = paOutputUnderflowed; + } + + hostOutputBufferIndex = stream->output.currentBufferIndex; + + PaUtil_SetOutputFrameCount( &stream->bufferProcessor, + stream->output.framesPerBuffer - stream->output.framesUsedInCurrentBuffer ); + + channel = 0; + for( i=0; ioutput.deviceCount; ++i ) + { + /* we have stored the number of channels in the buffer in dwUser */ + int channelCount = (int)stream->output.waveHeaders[i][ hostOutputBufferIndex ].dwUser; + + PaUtil_SetInterleavedOutputChannels( &stream->bufferProcessor, channel, + stream->output.waveHeaders[i][ hostOutputBufferIndex ].lpData + + stream->output.framesUsedInCurrentBuffer * channelCount * + stream->bufferProcessor.bytesPerHostOutputSample, + channelCount ); + + channel += channelCount; + } + + framesProcessed = PaUtil_CopyOutput( &stream->bufferProcessor, &userBuffer, frames - framesWritten ); + + stream->output.framesUsedInCurrentBuffer += framesProcessed; + if( stream->output.framesUsedInCurrentBuffer == stream->output.framesPerBuffer ) + { + result = AdvanceToNextOutputBuffer( stream ); + if( result != paNoError ) + break; + } + + framesWritten += framesProcessed; + } + else + { + /* wait for MME to signal that a buffer is available */ + waitResult = WaitForSingleObject( stream->output.bufferEvent, timeout ); + if( waitResult == WAIT_FAILED ) + { + result = paUnanticipatedHostError; + break; + } + else if( waitResult == WAIT_TIMEOUT ) + { + /* if a timeout is encountered, continue, + perhaps we should give up eventually + */ + } + } + }while( framesWritten < frames ); + } + else + { + result = paCanNotWriteToAnInputOnlyStream; + } + + return result; +} + + +static signed long GetStreamReadAvailable( PaStream* s ) +{ + PaWinMmeStream *stream = (PaWinMmeStream*)s; + + if( PA_IS_INPUT_STREAM_(stream) ) + return GetAvailableFrames( &stream->input ); + else + return paCanNotReadFromAnOutputOnlyStream; +} + + +static signed long GetStreamWriteAvailable( PaStream* s ) +{ + PaWinMmeStream *stream = (PaWinMmeStream*)s; + + if( PA_IS_OUTPUT_STREAM_(stream) ) + return GetAvailableFrames( &stream->output ); + else + return paCanNotWriteToAnInputOnlyStream; +} + + +/* NOTE: the following functions are MME-stream specific, and are called directly + by client code. We need to check for many more error conditions here because + we don't have the benefit of pa_front.c's parameter checking. +*/ + +static PaError GetWinMMEStreamPointer( PaWinMmeStream **stream, PaStream *s ) +{ + PaError result; + PaUtilHostApiRepresentation *hostApi; + PaWinMmeHostApiRepresentation *winMmeHostApi; + + result = PaUtil_ValidateStreamPointer( s ); + if( result != paNoError ) + return result; + + result = PaUtil_GetHostApiRepresentation( &hostApi, paMME ); + if( result != paNoError ) + return result; + + winMmeHostApi = (PaWinMmeHostApiRepresentation*)hostApi; + + /* note, the following would be easier if there was a generic way of testing + that a stream belongs to a specific host API */ + + if( PA_STREAM_REP( s )->streamInterface == &winMmeHostApi->callbackStreamInterface + || PA_STREAM_REP( s )->streamInterface == &winMmeHostApi->blockingStreamInterface ) + { + /* s is a WinMME stream */ + *stream = (PaWinMmeStream *)s; + return paNoError; + } + else + { + return paIncompatibleStreamHostApi; + } +} + + +int PaWinMME_GetStreamInputHandleCount( PaStream* s ) +{ + PaWinMmeStream *stream; + PaError result = GetWinMMEStreamPointer( &stream, s ); + + if( result == paNoError ) + return (PA_IS_INPUT_STREAM_(stream)) ? stream->input.deviceCount : 0; + else + return result; +} + + +HWAVEIN PaWinMME_GetStreamInputHandle( PaStream* s, int handleIndex ) +{ + PaWinMmeStream *stream; + PaError result = GetWinMMEStreamPointer( &stream, s ); + + if( result == paNoError + && PA_IS_INPUT_STREAM_(stream) + && handleIndex >= 0 + && (unsigned int)handleIndex < stream->input.deviceCount ) + return ((HWAVEIN*)stream->input.waveHandles)[handleIndex]; + else + return 0; +} + + +int PaWinMME_GetStreamOutputHandleCount( PaStream* s) +{ + PaWinMmeStream *stream; + PaError result = GetWinMMEStreamPointer( &stream, s ); + + if( result == paNoError ) + return (PA_IS_OUTPUT_STREAM_(stream)) ? stream->output.deviceCount : 0; + else + return result; +} + + +HWAVEOUT PaWinMME_GetStreamOutputHandle( PaStream* s, int handleIndex ) +{ + PaWinMmeStream *stream; + PaError result = GetWinMMEStreamPointer( &stream, s ); + + if( result == paNoError + && PA_IS_OUTPUT_STREAM_(stream) + && handleIndex >= 0 + && (unsigned int)handleIndex < stream->output.deviceCount ) + return ((HWAVEOUT*)stream->output.waveHandles)[handleIndex]; + else + return 0; +} diff --git a/extern/portaudio/src/os/unix/pa_unix_hostapis.c b/extern/portaudio/src/os/unix/pa_unix_hostapis.c new file mode 100644 index 0000000..a9b4a05 --- /dev/null +++ b/extern/portaudio/src/os/unix/pa_unix_hostapis.c @@ -0,0 +1,103 @@ +/* + * $Id$ + * Portable Audio I/O Library UNIX initialization table + * + * Based on the Open Source API proposed by Ross Bencina + * Copyright (c) 1999-2002 Ross Bencina, Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +/** @file + @ingroup unix_src +*/ + +#include "pa_hostapi.h" + +PaError PaJack_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index ); +PaError PaAlsa_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index ); +PaError PaOSS_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index ); +/* Added for IRIX, Pieter, oct 2, 2003: */ +PaError PaSGI_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index ); +/* Linux AudioScience HPI */ +PaError PaAsiHpi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index ); +PaError PaMacCore_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index ); +PaError PaSkeleton_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index ); + +/** Note that on Linux, ALSA is placed before OSS so that the former is preferred over the latter. + */ + +PaUtilHostApiInitializer *paHostApiInitializers[] = + { +#ifdef __linux__ + +#if PA_USE_ALSA + PaAlsa_Initialize, +#endif + +#if PA_USE_OSS + PaOSS_Initialize, +#endif + +#else /* __linux__ */ + +#if PA_USE_OSS + PaOSS_Initialize, +#endif + +#if PA_USE_ALSA + PaAlsa_Initialize, +#endif + +#endif /* __linux__ */ + +#if PA_USE_JACK + PaJack_Initialize, +#endif + /* Added for IRIX, Pieter, oct 2, 2003: */ +#if PA_USE_SGI + PaSGI_Initialize, +#endif + +#if PA_USE_ASIHPI + PaAsiHpi_Initialize, +#endif + +#if PA_USE_COREAUDIO + PaMacCore_Initialize, +#endif + +#if PA_USE_SKELETON + PaSkeleton_Initialize, +#endif + + 0 /* NULL terminated array */ + }; diff --git a/extern/portaudio/src/os/unix/pa_unix_util.c b/extern/portaudio/src/os/unix/pa_unix_util.c new file mode 100644 index 0000000..17664ea --- /dev/null +++ b/extern/portaudio/src/os/unix/pa_unix_util.c @@ -0,0 +1,710 @@ +/* + * $Id$ + * Portable Audio I/O Library + * UNIX platform-specific support functions + * + * Based on the Open Source API proposed by Ross Bencina + * Copyright (c) 1999-2000 Ross Bencina + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +/** @file + @ingroup unix_src +*/ + +#include +#include +#include +#include +#include +#include +#include /* For memset */ +#include +#include + +#if defined(__APPLE__) && !defined(HAVE_MACH_ABSOLUTE_TIME) +#define HAVE_MACH_ABSOLUTE_TIME +#endif +#ifdef HAVE_MACH_ABSOLUTE_TIME +#include +#endif + +#include "pa_util.h" +#include "pa_unix_util.h" +#include "pa_debugprint.h" + +/* + Track memory allocations to avoid leaks. + */ + +#if PA_TRACK_MEMORY +static int numAllocations_ = 0; +#endif + + +void *PaUtil_AllocateMemory( long size ) +{ + void *result = malloc( size ); + +#if PA_TRACK_MEMORY + if( result != NULL ) numAllocations_ += 1; +#endif + return result; +} + + +void PaUtil_FreeMemory( void *block ) +{ + if( block != NULL ) + { + free( block ); +#if PA_TRACK_MEMORY + numAllocations_ -= 1; +#endif + + } +} + + +int PaUtil_CountCurrentlyAllocatedBlocks( void ) +{ +#if PA_TRACK_MEMORY + return numAllocations_; +#else + return 0; +#endif +} + + +void Pa_Sleep( long msec ) +{ +#ifdef HAVE_NANOSLEEP + struct timespec req = {0}, rem = {0}; + PaTime time = msec / 1.e3; + req.tv_sec = (time_t)time; + assert(time - req.tv_sec < 1.0); + req.tv_nsec = (long)((time - req.tv_sec) * 1.e9); + nanosleep(&req, &rem); + /* XXX: Try sleeping the remaining time (contained in rem) if interrupted by a signal? */ +#else + while( msec > 999 ) /* For OpenBSD and IRIX, argument */ + { /* to usleep must be < 1000000. */ + usleep( 999000 ); + msec -= 999; + } + usleep( msec * 1000 ); +#endif +} + +#ifdef HAVE_MACH_ABSOLUTE_TIME +/* + Discussion on the CoreAudio mailing list suggests that calling + gettimeofday (or anything else in the BSD layer) is not real-time + safe, so we use mach_absolute_time on OSX. This implementation is + based on these two links: + + Technical Q&A QA1398 - Mach Absolute Time Units + http://developer.apple.com/mac/library/qa/qa2004/qa1398.html + + Tutorial: Performance and Time. + http://www.macresearch.org/tutorial_performance_and_time +*/ + +/* Scaler to convert the result of mach_absolute_time to seconds */ +static double machSecondsConversionScaler_ = 0.0; +#endif + +void PaUtil_InitializeClock( void ) +{ +#ifdef HAVE_MACH_ABSOLUTE_TIME + mach_timebase_info_data_t info; + kern_return_t err = mach_timebase_info( &info ); + if( err == 0 ) + machSecondsConversionScaler_ = 1e-9 * (double) info.numer / (double) info.denom; +#endif +} + + +PaTime PaUtil_GetTime( void ) +{ +#ifdef HAVE_MACH_ABSOLUTE_TIME + return mach_absolute_time() * machSecondsConversionScaler_; +#elif defined(HAVE_CLOCK_GETTIME) + struct timespec tp; + clock_gettime(CLOCK_REALTIME, &tp); + return (PaTime)(tp.tv_sec + tp.tv_nsec * 1e-9); +#else + struct timeval tv; + gettimeofday( &tv, NULL ); + return (PaTime) tv.tv_usec * 1e-6 + tv.tv_sec; +#endif +} + +PaError PaUtil_InitializeThreading( PaUtilThreading *threading ) +{ + (void) paUtilErr_; + return paNoError; +} + +void PaUtil_TerminateThreading( PaUtilThreading *threading ) +{ +} + +PaError PaUtil_StartThreading( PaUtilThreading *threading, void *(*threadRoutine)(void *), void *data ) +{ + pthread_create( &threading->callbackThread, NULL, threadRoutine, data ); + return paNoError; +} + +PaError PaUtil_CancelThreading( PaUtilThreading *threading, int wait, PaError *exitResult ) +{ + PaError result = paNoError; + void *pret; + + if( exitResult ) + *exitResult = paNoError; + + /* If pthread_cancel is not supported (Android platform) whole this function can lead to indefinite waiting if + working thread (callbackThread) has'n received any stop signals from outside, please keep + this in mind when considering using PaUtil_CancelThreading + */ +#ifdef PTHREAD_CANCELED + /* Only kill the thread if it isn't in the process of stopping (flushing adaptation buffers) */ + if( !wait ) + pthread_cancel( threading->callbackThread ); /* XXX: Safe to call this if the thread has exited on its own? */ +#endif + pthread_join( threading->callbackThread, &pret ); + +#ifdef PTHREAD_CANCELED + if( pret && PTHREAD_CANCELED != pret ) +#else + /* !wait means the thread may have been canceled */ + if( pret && wait ) +#endif + { + if( exitResult ) + *exitResult = *(PaError *) pret; + free( pret ); + } + + return result; +} + +/* Threading */ +/* paUnixMainThread + * We have to be a bit careful with defining this global variable, + * as explained below. */ +#ifdef __APPLE__ +/* apple/gcc has a "problem" with global vars and dynamic libs. + Initializing it seems to fix the problem. + Described a bit in this thread: + http://gcc.gnu.org/ml/gcc/2005-06/msg00179.html +*/ +pthread_t paUnixMainThread = 0; +#else +/*pthreads are opaque. We don't know that asigning it an int value + always makes sense, so we don't initialize it unless we have to.*/ +pthread_t paUnixMainThread = 0; +#endif + +PaError PaUnixThreading_Initialize() +{ + paUnixMainThread = pthread_self(); + return paNoError; +} + +static PaError BoostPriority( PaUnixThread* self ) +{ + PaError result = paNoError; + struct sched_param spm = { 0 }; + /* Priority should only matter between contending FIFO threads? */ + spm.sched_priority = 1; + + assert( self ); + + if( pthread_setschedparam( self->thread, SCHED_FIFO, &spm ) != 0 ) + { + PA_UNLESS( errno == EPERM, paInternalError ); /* Lack permission to raise priority */ + PA_DEBUG(( "Failed bumping priority\n" )); + result = 0; + } + else + { + result = 1; /* Success */ + } +error: + return result; +} + +PaError PaUnixThread_New( PaUnixThread* self, void* (*threadFunc)( void* ), void* threadArg, PaTime waitForChild, + int rtSched ) +{ + PaError result = paNoError; + pthread_attr_t attr; + int started = 0; + + memset( self, 0, sizeof (PaUnixThread) ); + PaUnixMutex_Initialize( &self->mtx ); + PA_ASSERT_CALL( pthread_cond_init( &self->cond, NULL ), 0 ); + + self->parentWaiting = 0 != waitForChild; + + /* Spawn thread */ + +/* Temporarily disabled since we should test during configuration for presence of required mman.h header */ +#if 0 +#if defined _POSIX_MEMLOCK && (_POSIX_MEMLOCK != -1) + if( rtSched ) + { + if( mlockall( MCL_CURRENT | MCL_FUTURE ) < 0 ) + { + int savedErrno = errno; /* In case errno gets overwritten */ + assert( savedErrno != EINVAL ); /* Most likely a programmer error */ + PA_UNLESS( (savedErrno == EPERM), paInternalError ); + PA_DEBUG(( "%s: Failed locking memory\n", __FUNCTION__ )); + } + else + PA_DEBUG(( "%s: Successfully locked memory\n", __FUNCTION__ )); + } +#endif +#endif + + PA_UNLESS( !pthread_attr_init( &attr ), paInternalError ); + /* Priority relative to other processes */ + PA_UNLESS( !pthread_attr_setscope( &attr, PTHREAD_SCOPE_SYSTEM ), paInternalError ); + + PA_UNLESS( !pthread_create( &self->thread, &attr, threadFunc, threadArg ), paInternalError ); + started = 1; + + if( rtSched ) + { +#if 0 + if( self->useWatchdog ) + { + int err; + struct sched_param wdSpm = { 0 }; + /* Launch watchdog, watchdog sets callback thread priority */ + int prio = PA_MIN( self->rtPrio + 4, sched_get_priority_max( SCHED_FIFO ) ); + wdSpm.sched_priority = prio; + + PA_UNLESS( !pthread_attr_init( &attr ), paInternalError ); + PA_UNLESS( !pthread_attr_setinheritsched( &attr, PTHREAD_EXPLICIT_SCHED ), paInternalError ); + PA_UNLESS( !pthread_attr_setscope( &attr, PTHREAD_SCOPE_SYSTEM ), paInternalError ); + PA_UNLESS( !pthread_attr_setschedpolicy( &attr, SCHED_FIFO ), paInternalError ); + PA_UNLESS( !pthread_attr_setschedparam( &attr, &wdSpm ), paInternalError ); + if( (err = pthread_create( &self->watchdogThread, &attr, &WatchdogFunc, self )) ) + { + PA_UNLESS( err == EPERM, paInternalError ); + /* Permission error, go on without realtime privileges */ + PA_DEBUG(( "Failed bumping priority\n" )); + } + else + { + int policy; + self->watchdogRunning = 1; + PA_ENSURE_SYSTEM( pthread_getschedparam( self->watchdogThread, &policy, &wdSpm ), 0 ); + /* Check if priority is right, policy could potentially differ from SCHED_FIFO (but that's alright) */ + if( wdSpm.sched_priority != prio ) + { + PA_DEBUG(( "Watchdog priority not set correctly (%d)\n", wdSpm.sched_priority )); + PA_ENSURE( paInternalError ); + } + } + } + else +#endif + PA_ENSURE( BoostPriority( self ) ); + + { + int policy; + struct sched_param spm; + pthread_getschedparam(self->thread, &policy, &spm); + } + } + + if( self->parentWaiting ) + { + PaTime till; + struct timespec ts; + int res = 0; + PaTime now; + + PA_ENSURE( PaUnixMutex_Lock( &self->mtx ) ); + + /* Wait for stream to be started */ + now = PaUtil_GetTime(); + till = now + waitForChild; + + while( self->parentWaiting && !res ) + { + if( waitForChild > 0 ) + { + ts.tv_sec = (time_t) floor( till ); + ts.tv_nsec = (long) ((till - floor( till )) * 1e9); + res = pthread_cond_timedwait( &self->cond, &self->mtx.mtx, &ts ); + } + else + { + res = pthread_cond_wait( &self->cond, &self->mtx.mtx ); + } + } + + PA_ENSURE( PaUnixMutex_Unlock( &self->mtx ) ); + + PA_UNLESS( !res || ETIMEDOUT == res, paInternalError ); + PA_DEBUG(( "%s: Waited for %g seconds for stream to start\n", __FUNCTION__, PaUtil_GetTime() - now )); + if( ETIMEDOUT == res ) + { + PA_ENSURE( paTimedOut ); + } + } + +end: + return result; +error: + if( started ) + { + PaUnixThread_Terminate( self, 0, NULL ); + } + + goto end; +} + +PaError PaUnixThread_Terminate( PaUnixThread* self, int wait, PaError* exitResult ) +{ + PaError result = paNoError; + void* pret; + + if( exitResult ) + { + *exitResult = paNoError; + } +#if 0 + if( watchdogExitResult ) + *watchdogExitResult = paNoError; + + if( th->watchdogRunning ) + { + pthread_cancel( th->watchdogThread ); + PA_ENSURE_SYSTEM( pthread_join( th->watchdogThread, &pret ), 0 ); + + if( pret && pret != PTHREAD_CANCELED ) + { + if( watchdogExitResult ) + *watchdogExitResult = *(PaError *) pret; + free( pret ); + } + } +#endif + + /* Only kill the thread if it isn't in the process of stopping (flushing adaptation buffers) */ + /* TODO: Make join time out */ + self->stopRequested = wait; + if( !wait ) + { + PA_DEBUG(( "%s: Canceling thread %d\n", __FUNCTION__, self->thread )); + /* XXX: Safe to call this if the thread has exited on its own? */ +#ifdef PTHREAD_CANCELED + pthread_cancel( self->thread ); +#endif + } + PA_DEBUG(( "%s: Joining thread %d\n", __FUNCTION__, self->thread )); + PA_ENSURE_SYSTEM( pthread_join( self->thread, &pret ), 0 ); + +#ifdef PTHREAD_CANCELED + if( pret && PTHREAD_CANCELED != pret ) +#else + /* !wait means the thread may have been canceled */ + if( pret && wait ) +#endif + { + if( exitResult ) + { + *exitResult = *(PaError*)pret; + } + free( pret ); + } + +error: + PA_ASSERT_CALL( PaUnixMutex_Terminate( &self->mtx ), paNoError ); + PA_ASSERT_CALL( pthread_cond_destroy( &self->cond ), 0 ); + + return result; +} + +PaError PaUnixThread_PrepareNotify( PaUnixThread* self ) +{ + PaError result = paNoError; + PA_UNLESS( self->parentWaiting, paInternalError ); + + PA_ENSURE( PaUnixMutex_Lock( &self->mtx ) ); + self->locked = 1; + +error: + return result; +} + +PaError PaUnixThread_NotifyParent( PaUnixThread* self ) +{ + PaError result = paNoError; + PA_UNLESS( self->parentWaiting, paInternalError ); + + if( !self->locked ) + { + PA_ENSURE( PaUnixMutex_Lock( &self->mtx ) ); + self->locked = 1; + } + self->parentWaiting = 0; + pthread_cond_signal( &self->cond ); + PA_ENSURE( PaUnixMutex_Unlock( &self->mtx ) ); + self->locked = 0; + +error: + return result; +} + +int PaUnixThread_StopRequested( PaUnixThread* self ) +{ + return self->stopRequested; +} + +PaError PaUnixMutex_Initialize( PaUnixMutex* self ) +{ + PaError result = paNoError; + PA_ASSERT_CALL( pthread_mutex_init( &self->mtx, NULL ), 0 ); + return result; +} + +PaError PaUnixMutex_Terminate( PaUnixMutex* self ) +{ + PaError result = paNoError; + PA_ASSERT_CALL( pthread_mutex_destroy( &self->mtx ), 0 ); + return result; +} + +/** Lock mutex. + * + * We're disabling thread cancellation while the thread is holding a lock, so mutexes are + * properly unlocked at termination time. + */ +PaError PaUnixMutex_Lock( PaUnixMutex* self ) +{ + PaError result = paNoError; + +#ifdef PTHREAD_CANCEL + int oldState; + PA_ENSURE_SYSTEM( pthread_setcancelstate( PTHREAD_CANCEL_DISABLE, &oldState ), 0 ); +#endif + PA_ENSURE_SYSTEM( pthread_mutex_lock( &self->mtx ), 0 ); + +error: + return result; +} + +/** Unlock mutex. + * + * Thread cancellation is enabled again after the mutex is properly unlocked. + */ +PaError PaUnixMutex_Unlock( PaUnixMutex* self ) +{ + PaError result = paNoError; + + PA_ENSURE_SYSTEM( pthread_mutex_unlock( &self->mtx ), 0 ); +#ifdef PTHREAD_CANCEL + int oldState; + PA_ENSURE_SYSTEM( pthread_setcancelstate( PTHREAD_CANCEL_ENABLE, &oldState ), 0 ); +#endif + +error: + return result; +} + + +#if 0 +static void OnWatchdogExit( void *userData ) +{ + PaAlsaThreading *th = (PaAlsaThreading *) userData; + struct sched_param spm = { 0 }; + assert( th ); + + PA_ASSERT_CALL( pthread_setschedparam( th->callbackThread, SCHED_OTHER, &spm ), 0 ); /* Lower before exiting */ + PA_DEBUG(( "Watchdog exiting\n" )); +} + +static void *WatchdogFunc( void *userData ) +{ + PaError result = paNoError, *pres = NULL; + int err; + PaAlsaThreading *th = (PaAlsaThreading *) userData; + unsigned intervalMsec = 500; + const PaTime maxSeconds = 3.; /* Max seconds between callbacks */ + PaTime timeThen = PaUtil_GetTime(), timeNow, timeElapsed, cpuTimeThen, cpuTimeNow, cpuTimeElapsed; + double cpuLoad, avgCpuLoad = 0.; + int throttled = 0; + + assert( th ); + + /* Execute OnWatchdogExit when exiting */ + pthread_cleanup_push( &OnWatchdogExit, th ); + + /* Boost priority of callback thread */ + PA_ENSURE( result = BoostPriority( th ) ); + if( !result ) + { + /* Boost failed, might as well exit */ + pthread_exit( NULL ); + } + + cpuTimeThen = th->callbackCpuTime; + { + int policy; + struct sched_param spm = { 0 }; + pthread_getschedparam( pthread_self(), &policy, &spm ); + PA_DEBUG(( "%s: Watchdog priority is %d\n", __FUNCTION__, spm.sched_priority )); + } + + while( 1 ) + { + double lowpassCoeff = 0.9, lowpassCoeff1 = 0.99999 - lowpassCoeff; + + /* Test before and after in case whatever underlying sleep call isn't interrupted by pthread_cancel */ + pthread_testcancel(); + Pa_Sleep( intervalMsec ); + pthread_testcancel(); + + if( PaUtil_GetTime() - th->callbackTime > maxSeconds ) + { + PA_DEBUG(( "Watchdog: Terminating callback thread\n" )); + /* Tell thread to terminate */ + err = pthread_kill( th->callbackThread, SIGKILL ); + pthread_exit( NULL ); + } + + PA_DEBUG(( "%s: PortAudio reports CPU load: %g\n", __FUNCTION__, PaUtil_GetCpuLoad( th->cpuLoadMeasurer ) )); + + /* Check if we should throttle, or unthrottle :P */ + cpuTimeNow = th->callbackCpuTime; + cpuTimeElapsed = cpuTimeNow - cpuTimeThen; + cpuTimeThen = cpuTimeNow; + + timeNow = PaUtil_GetTime(); + timeElapsed = timeNow - timeThen; + timeThen = timeNow; + cpuLoad = cpuTimeElapsed / timeElapsed; + avgCpuLoad = avgCpuLoad * lowpassCoeff + cpuLoad * lowpassCoeff1; + /* + if( throttled ) + PA_DEBUG(( "Watchdog: CPU load: %g, %g\n", avgCpuLoad, cpuTimeElapsed )); + */ + if( PaUtil_GetCpuLoad( th->cpuLoadMeasurer ) > .925 ) + { + static int policy; + static struct sched_param spm = { 0 }; + static const struct sched_param defaultSpm = { 0 }; + PA_DEBUG(( "%s: Throttling audio thread, priority %d\n", __FUNCTION__, spm.sched_priority )); + + pthread_getschedparam( th->callbackThread, &policy, &spm ); + if( !pthread_setschedparam( th->callbackThread, SCHED_OTHER, &defaultSpm ) ) + { + throttled = 1; + } + else + PA_DEBUG(( "Watchdog: Couldn't lower priority of audio thread: %s\n", strerror( errno ) )); + + /* Give other processes a go, before raising priority again */ + PA_DEBUG(( "%s: Watchdog sleeping for %lu msecs before unthrottling\n", __FUNCTION__, th->throttledSleepTime )); + Pa_Sleep( th->throttledSleepTime ); + + /* Reset callback priority */ + if( pthread_setschedparam( th->callbackThread, SCHED_FIFO, &spm ) != 0 ) + { + PA_DEBUG(( "%s: Couldn't raise priority of audio thread: %s\n", __FUNCTION__, strerror( errno ) )); + } + + if( PaUtil_GetCpuLoad( th->cpuLoadMeasurer ) >= .99 ) + intervalMsec = 50; + else + intervalMsec = 100; + + /* + lowpassCoeff = .97; + lowpassCoeff1 = .99999 - lowpassCoeff; + */ + } + else if( throttled && avgCpuLoad < .8 ) + { + intervalMsec = 500; + throttled = 0; + + /* + lowpassCoeff = .9; + lowpassCoeff1 = .99999 - lowpassCoeff; + */ + } + } + + pthread_cleanup_pop( 1 ); /* Execute cleanup on exit */ + +error: + /* Shouldn't get here in the normal case */ + + /* Pass on error code */ + pres = malloc( sizeof (PaError) ); + *pres = result; + + pthread_exit( pres ); +} + +static void CallbackUpdate( PaAlsaThreading *th ) +{ + th->callbackTime = PaUtil_GetTime(); + th->callbackCpuTime = PaUtil_GetCpuLoad( th->cpuLoadMeasurer ); +} + +/* +static void *CanaryFunc( void *userData ) +{ + const unsigned intervalMsec = 1000; + PaUtilThreading *th = (PaUtilThreading *) userData; + + while( 1 ) + { + th->canaryTime = PaUtil_GetTime(); + + pthread_testcancel(); + Pa_Sleep( intervalMsec ); + } + + pthread_exit( NULL ); +} +*/ +#endif diff --git a/extern/portaudio/src/os/unix/pa_unix_util.h b/extern/portaudio/src/os/unix/pa_unix_util.h new file mode 100644 index 0000000..d73c99c --- /dev/null +++ b/extern/portaudio/src/os/unix/pa_unix_util.h @@ -0,0 +1,224 @@ +/* + * $Id$ + * Portable Audio I/O Library + * UNIX platform-specific support functions + * + * Based on the Open Source API proposed by Ross Bencina + * Copyright (c) 1999-2000 Ross Bencina + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +/** @file + @ingroup unix_src +*/ + +#ifndef PA_UNIX_UTIL_H +#define PA_UNIX_UTIL_H + +#include "pa_cpuload.h" +#include +#include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +#define PA_MIN(x,y) ( (x) < (y) ? (x) : (y) ) +#define PA_MAX(x,y) ( (x) > (y) ? (x) : (y) ) + +/* Utilize GCC branch prediction for error tests */ +#if defined __GNUC__ && __GNUC__ >= 3 +#define UNLIKELY(expr) __builtin_expect( (expr), 0 ) +#else +#define UNLIKELY(expr) (expr) +#endif + +#define STRINGIZE_HELPER(expr) #expr +#define STRINGIZE(expr) STRINGIZE_HELPER(expr) + +#define PA_UNLESS(expr, code) \ + do { \ + if( UNLIKELY( (expr) == 0 ) ) \ + { \ + PaUtil_DebugPrint(( "Expression '" #expr "' failed in '" __FILE__ "', line: " STRINGIZE( __LINE__ ) "\n" )); \ + result = (code); \ + goto error; \ + } \ + } while (0); + +static PaError paUtilErr_; /* Used with PA_ENSURE */ + +/* Check PaError */ +#define PA_ENSURE(expr) \ + do { \ + if( UNLIKELY( (paUtilErr_ = (expr)) < paNoError ) ) \ + { \ + PaUtil_DebugPrint(( "Expression '" #expr "' failed in '" __FILE__ "', line: " STRINGIZE( __LINE__ ) "\n" )); \ + result = paUtilErr_; \ + goto error; \ + } \ + } while (0); + +#define PA_ASSERT_CALL(expr, success) \ + paUtilErr_ = (expr); \ + assert( success == paUtilErr_ ); + +#define PA_ENSURE_SYSTEM(expr, success) \ + do { \ + if( UNLIKELY( (paUtilErr_ = (expr)) != success ) ) \ + { \ + /* PaUtil_SetLastHostErrorInfo should only be used in the main thread */ \ + if( pthread_equal(pthread_self(), paUnixMainThread) ) \ + { \ + PaUtil_SetLastHostErrorInfo( paALSA, paUtilErr_, strerror( paUtilErr_ ) ); \ + } \ + PaUtil_DebugPrint( "Expression '" #expr "' failed in '" __FILE__ "', line: " STRINGIZE( __LINE__ ) "\n" ); \ + result = paUnanticipatedHostError; \ + goto error; \ + } \ + } while( 0 ); + +typedef struct { + pthread_t callbackThread; +} PaUtilThreading; + +PaError PaUtil_InitializeThreading( PaUtilThreading *threading ); +void PaUtil_TerminateThreading( PaUtilThreading *threading ); +PaError PaUtil_StartThreading( PaUtilThreading *threading, void *(*threadRoutine)(void *), void *data ); +PaError PaUtil_CancelThreading( PaUtilThreading *threading, int wait, PaError *exitResult ); + +/* State accessed by utility functions */ + +/* +void PaUnix_SetRealtimeScheduling( int rt ); + +void PaUtil_InitializeThreading( PaUtilThreading *th, PaUtilCpuLoadMeasurer *clm ); + +PaError PaUtil_CreateCallbackThread( PaUtilThreading *th, void *(*CallbackThreadFunc)( void * ), PaStream *s ); + +PaError PaUtil_KillCallbackThread( PaUtilThreading *th, PaError *exitResult ); + +void PaUtil_CallbackUpdate( PaUtilThreading *th ); +*/ + +extern pthread_t paUnixMainThread; + +typedef struct +{ + pthread_mutex_t mtx; +} PaUnixMutex; + +PaError PaUnixMutex_Initialize( PaUnixMutex* self ); +PaError PaUnixMutex_Terminate( PaUnixMutex* self ); +PaError PaUnixMutex_Lock( PaUnixMutex* self ); +PaError PaUnixMutex_Unlock( PaUnixMutex* self ); + +typedef struct +{ + pthread_t thread; + int parentWaiting; + int stopRequested; + int locked; + PaUnixMutex mtx; + pthread_cond_t cond; + volatile sig_atomic_t stopRequest; +} PaUnixThread; + +/** Initialize global threading state. + */ +PaError PaUnixThreading_Initialize(); + +/** Perish, passing on eventual error code. + * + * A thin wrapper around pthread_exit, will automatically pass on any error code to the joining thread. + * If the result indicates an error, i.e. it is not equal to paNoError, this function will automatically + * allocate a pointer so the error is passed on with pthread_exit. If the result indicates that all is + * well however, only a NULL pointer will be handed to pthread_exit. Thus, the joining thread should + * check whether a non-NULL result pointer is obtained from pthread_join and make sure to free it. + * @param result: The error code to pass on to the joining thread. + */ +#define PaUnixThreading_EXIT(result) \ + do { \ + PaError* pres = NULL; \ + if( paNoError != (result) ) \ + { \ + pres = malloc( sizeof (PaError) ); \ + *pres = (result); \ + } \ + pthread_exit( pres ); \ + } while (0); + +/** Spawn a thread. + * + * Intended for spawning the callback thread from the main thread. This function can even block (for a certain + * time or indefinitely) untill notified by the callback thread (using PaUnixThread_NotifyParent), which can be + * useful in order to make sure that callback has commenced before returning from Pa_StartStream. + * @param threadFunc: The function to be executed in the child thread. + * @param waitForChild: If not 0, wait for child thread to call PaUnixThread_NotifyParent. Less than 0 means + * wait for ever, greater than 0 wait for the specified time. + * @param rtSched: Enable realtime scheduling? + * @return: If timed out waiting on child, paTimedOut. + */ +PaError PaUnixThread_New( PaUnixThread* self, void* (*threadFunc)( void* ), void* threadArg, PaTime waitForChild, + int rtSched ); + +/** Terminate thread. + * + * @param wait: If true, request that background thread stop and wait untill it does, else cancel it. + * @param exitResult: If non-null this will upon return contain the exit status of the thread. + */ +PaError PaUnixThread_Terminate( PaUnixThread* self, int wait, PaError* exitResult ); + +/** Prepare to notify waiting parent thread. + * + * An internal lock must be held before the parent is notified in PaUnixThread_NotifyParent, call this to + * acquire it beforehand. + * @return: If parent is not waiting, paInternalError. + */ +PaError PaUnixThread_PrepareNotify( PaUnixThread* self ); + +/** Notify waiting parent thread. + * + * @return: If parent timed out waiting, paTimedOut. If parent was never waiting, paInternalError. + */ +PaError PaUnixThread_NotifyParent( PaUnixThread* self ); + +/** Has the parent thread requested this thread to stop? + */ +int PaUnixThread_StopRequested( PaUnixThread* self ); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif diff --git a/extern/portaudio/src/os/win/pa_win_coinitialize.c b/extern/portaudio/src/os/win/pa_win_coinitialize.c new file mode 100644 index 0000000..c4c6dde --- /dev/null +++ b/extern/portaudio/src/os/win/pa_win_coinitialize.c @@ -0,0 +1,148 @@ +/* + * Microsoft COM initialization routines + * Copyright (c) 1999-2011 Ross Bencina, Dmitry Kostjuchenko + * + * Based on the Open Source API proposed by Ross Bencina + * Copyright (c) 1999-2011 Ross Bencina, Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +/** @file + @ingroup win_src + + @brief Microsoft COM initialization routines. +*/ + +#include +#include + +#include "portaudio.h" +#include "pa_util.h" +#include "pa_debugprint.h" + +#include "pa_win_coinitialize.h" + + +#if (defined(WIN32) && (defined(_MSC_VER) && (_MSC_VER >= 1200))) && !defined(_WIN32_WCE) && !(defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP)) /* MSC version 6 and above */ +#pragma comment( lib, "ole32.lib" ) +#endif + + +/* use some special bit patterns here to try to guard against uninitialized memory errors */ +#define PAWINUTIL_COM_INITIALIZED (0xb38f) +#define PAWINUTIL_COM_NOT_INITIALIZED (0xf1cd) + + +PaError PaWinUtil_CoInitialize( PaHostApiTypeId hostApiType, PaWinUtilComInitializationResult *comInitializationResult ) +{ + HRESULT hr; + + comInitializationResult->state = PAWINUTIL_COM_NOT_INITIALIZED; + + /* + If COM is already initialized CoInitialize will either return + FALSE, or RPC_E_CHANGED_MODE if it was initialised in a different + threading mode. In either case we shouldn't consider it an error + but we need to be careful to not call CoUninitialize() if + RPC_E_CHANGED_MODE was returned. + */ + +#if !defined(WINAPI_FAMILY) || (WINAPI_FAMILY != WINAPI_FAMILY_APP) + hr = CoInitialize(0); /* use legacy-safe equivalent to CoInitializeEx(NULL, COINIT_APARTMENTTHREADED) */ +#else + hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); +#endif + if( FAILED(hr) && hr != RPC_E_CHANGED_MODE ) + { + PA_DEBUG(("CoInitialize(0) failed. hr=%d\n", hr)); + + if( hr == E_OUTOFMEMORY ) + return paInsufficientMemory; + + { + char *lpMsgBuf; + FormatMessage( + FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, + NULL, + hr, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPTSTR) &lpMsgBuf, + 0, + NULL + ); + PaUtil_SetLastHostErrorInfo( hostApiType, hr, lpMsgBuf ); + LocalFree( lpMsgBuf ); + } + + return paUnanticipatedHostError; + } + + if( hr != RPC_E_CHANGED_MODE ) + { + comInitializationResult->state = PAWINUTIL_COM_INITIALIZED; + + /* + Memorize calling thread id and report warning on Uninitialize if + calling thread is different as CoInitialize must match CoUninitialize + in the same thread. + */ + comInitializationResult->initializingThreadId = GetCurrentThreadId(); + } + + return paNoError; +} + + +void PaWinUtil_CoUninitialize( PaHostApiTypeId hostApiType, PaWinUtilComInitializationResult *comInitializationResult ) +{ + if( comInitializationResult->state != PAWINUTIL_COM_NOT_INITIALIZED + && comInitializationResult->state != PAWINUTIL_COM_INITIALIZED ){ + + PA_DEBUG(("ERROR: PaWinUtil_CoUninitialize called without calling PaWinUtil_CoInitialize\n")); + } + + if( comInitializationResult->state == PAWINUTIL_COM_INITIALIZED ) + { + DWORD currentThreadId = GetCurrentThreadId(); + if( comInitializationResult->initializingThreadId != currentThreadId ) + { + PA_DEBUG(("ERROR: failed PaWinUtil_CoUninitialize calling thread[%d] does not match initializing thread[%d]\n", + currentThreadId, comInitializationResult->initializingThreadId)); + } + else + { + CoUninitialize(); + + comInitializationResult->state = PAWINUTIL_COM_NOT_INITIALIZED; + } + } +} \ No newline at end of file diff --git a/extern/portaudio/src/os/win/pa_win_coinitialize.h b/extern/portaudio/src/os/win/pa_win_coinitialize.h new file mode 100644 index 0000000..687ab83 --- /dev/null +++ b/extern/portaudio/src/os/win/pa_win_coinitialize.h @@ -0,0 +1,94 @@ +/* + * Microsoft COM initialization routines + * Copyright (c) 1999-2011 Ross Bencina, Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +/** @file + @ingroup win_src + + @brief Microsoft COM initialization routines. +*/ + +#ifndef PA_WIN_COINITIALIZE_H +#define PA_WIN_COINITIALIZE_H + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + +/** + @brief Data type used to hold the result of an attempt to initialize COM + using PaWinUtil_CoInitialize. Must be retained between a call to + PaWinUtil_CoInitialize and a matching call to PaWinUtil_CoUninitialize. +*/ +typedef struct PaWinUtilComInitializationResult{ + int state; + int initializingThreadId; +} PaWinUtilComInitializationResult; + + +/** + @brief Initialize Microsoft COM subsystem on the current thread. + + @param hostApiType the host API type id of the caller. Used for error reporting. + + @param comInitializationResult An output parameter. The value pointed to by + this parameter stores information required by PaWinUtil_CoUninitialize + to correctly uninitialize COM. The value should be retained and later + passed to PaWinUtil_CoUninitialize. + + If PaWinUtil_CoInitialize returns paNoError, the caller must later call + PaWinUtil_CoUninitialize once. +*/ +PaError PaWinUtil_CoInitialize( PaHostApiTypeId hostApiType, PaWinUtilComInitializationResult *comInitializationResult ); + + +/** + @brief Uninitialize the Microsoft COM subsystem on the current thread using + the result of a previous call to PaWinUtil_CoInitialize. Must be called on the same + thread as PaWinUtil_CoInitialize. + + @param hostApiType the host API type id of the caller. Used for error reporting. + + @param comInitializationResult An input parameter. A pointer to a value previously + initialized by a call to PaWinUtil_CoInitialize. +*/ +void PaWinUtil_CoUninitialize( PaHostApiTypeId hostApiType, PaWinUtilComInitializationResult *comInitializationResult ); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* PA_WIN_COINITIALIZE_H */ diff --git a/extern/portaudio/src/os/win/pa_win_hostapis.c b/extern/portaudio/src/os/win/pa_win_hostapis.c new file mode 100644 index 0000000..9c9927a --- /dev/null +++ b/extern/portaudio/src/os/win/pa_win_hostapis.c @@ -0,0 +1,102 @@ +/* + * $Id$ + * Portable Audio I/O Library Windows initialization table + * + * Based on the Open Source API proposed by Ross Bencina + * Copyright (c) 1999-2008 Ross Bencina, Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +/** @file + @ingroup win_src + + @brief Win32 host API initialization function table. +*/ + +/* This is needed to make this source file depend on CMake option changes + and at the same time make it transparent for clients not using CMake. +*/ +#ifdef PORTAUDIO_CMAKE_GENERATED +#include "options_cmake.h" +#endif + +#include "pa_hostapi.h" + + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +PaError PaSkeleton_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index ); +PaError PaWinMme_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index ); +PaError PaWinDs_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index ); +PaError PaAsio_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index ); +PaError PaWinWdm_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index ); +PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index ); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +PaUtilHostApiInitializer *paHostApiInitializers[] = + { + +#if PA_USE_WMME + PaWinMme_Initialize, +#endif + +#if PA_USE_DS + PaWinDs_Initialize, +#endif + +#if PA_USE_ASIO + PaAsio_Initialize, +#endif + +#if PA_USE_WASAPI + PaWasapi_Initialize, +#endif + +#if PA_USE_WDMKS + PaWinWdm_Initialize, +#endif + +#if PA_USE_SKELETON + PaSkeleton_Initialize, /* just for testing. last in list so it isn't marked as default. */ +#endif + + 0 /* NULL terminated array */ + }; + + diff --git a/extern/portaudio/src/os/win/pa_win_util.c b/extern/portaudio/src/os/win/pa_win_util.c new file mode 100644 index 0000000..1cd3525 --- /dev/null +++ b/extern/portaudio/src/os/win/pa_win_util.c @@ -0,0 +1,160 @@ +/* + * $Id$ + * Portable Audio I/O Library + * Win32 platform-specific support functions + * + * Based on the Open Source API proposed by Ross Bencina + * Copyright (c) 1999-2008 Ross Bencina + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +/** @file + @ingroup win_src + + @brief Win32 implementation of platform-specific PaUtil support functions. +*/ + +#include + +#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP) + #include /* for _ftime_s() */ +#else + #include /* for timeGetTime() */ + #if (defined(WIN32) && (defined(_MSC_VER) && (_MSC_VER >= 1200))) && !defined(_WIN32_WCE) /* MSC version 6 and above */ + #pragma comment( lib, "winmm.lib" ) + #endif +#endif + +#include "pa_util.h" + +/* + Track memory allocations to avoid leaks. + */ + +#if PA_TRACK_MEMORY +static int numAllocations_ = 0; +#endif + + +void *PaUtil_AllocateMemory( long size ) +{ + void *result = GlobalAlloc( GPTR, size ); + +#if PA_TRACK_MEMORY + if( result != NULL ) numAllocations_ += 1; +#endif + return result; +} + + +void PaUtil_FreeMemory( void *block ) +{ + if( block != NULL ) + { + GlobalFree( block ); +#if PA_TRACK_MEMORY + numAllocations_ -= 1; +#endif + + } +} + + +int PaUtil_CountCurrentlyAllocatedBlocks( void ) +{ +#if PA_TRACK_MEMORY + return numAllocations_; +#else + return 0; +#endif +} + + +void Pa_Sleep( long msec ) +{ + Sleep( msec ); +} + +static int usePerformanceCounter_; +static double secondsPerTick_; + +void PaUtil_InitializeClock( void ) +{ + LARGE_INTEGER ticksPerSecond; + + if( QueryPerformanceFrequency( &ticksPerSecond ) != 0 ) + { + usePerformanceCounter_ = 1; + secondsPerTick_ = 1.0 / (double)ticksPerSecond.QuadPart; + } + else + { + usePerformanceCounter_ = 0; + } +} + + +double PaUtil_GetTime( void ) +{ + LARGE_INTEGER time; + + if( usePerformanceCounter_ ) + { + /* + Note: QueryPerformanceCounter has a known issue where it can skip forward + by a few seconds (!) due to a hardware bug on some PCI-ISA bridge hardware. + This is documented here: + http://support.microsoft.com/default.aspx?scid=KB;EN-US;Q274323& + + The work-arounds are not very paletable and involve querying GetTickCount + at every time step. + + Using rdtsc is not a good option on multi-core systems. + + For now we just use QueryPerformanceCounter(). It's good, most of the time. + */ + QueryPerformanceCounter( &time ); + return time.QuadPart * secondsPerTick_; + } + else + { +#ifndef UNDER_CE + #if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP) + return GetTickCount64() * .001; + #else + return timeGetTime() * .001; + #endif +#else + return GetTickCount() * .001; +#endif + } +} diff --git a/extern/portaudio/src/os/win/pa_win_waveformat.c b/extern/portaudio/src/os/win/pa_win_waveformat.c new file mode 100644 index 0000000..bd5addd --- /dev/null +++ b/extern/portaudio/src/os/win/pa_win_waveformat.c @@ -0,0 +1,162 @@ +/* + * PortAudio Portable Real-Time Audio Library + * Windows WAVEFORMAT* data structure utilities + * portaudio.h should be included before this file. + * + * Copyright (c) 2007 Ross Bencina + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +#include +#include +#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP) + #include /* for WAVEFORMATEX */ +#endif + +#include "portaudio.h" +#include "pa_win_waveformat.h" + + +#if !defined(WAVE_FORMAT_EXTENSIBLE) +#define WAVE_FORMAT_EXTENSIBLE 0xFFFE +#endif + + +static GUID pawin_ksDataFormatSubtypeGuidBase = + { (USHORT)(WAVE_FORMAT_PCM), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 }; + + +int PaWin_SampleFormatToLinearWaveFormatTag( PaSampleFormat sampleFormat ) +{ + if( sampleFormat == paFloat32 ) + return PAWIN_WAVE_FORMAT_IEEE_FLOAT; + + return PAWIN_WAVE_FORMAT_PCM; +} + + +void PaWin_InitializeWaveFormatEx( PaWinWaveFormat *waveFormat, + int numChannels, PaSampleFormat sampleFormat, int waveFormatTag, double sampleRate ) +{ + WAVEFORMATEX *waveFormatEx = (WAVEFORMATEX*)waveFormat; + int bytesPerSample = Pa_GetSampleSize(sampleFormat); + unsigned long bytesPerFrame = numChannels * bytesPerSample; + + waveFormatEx->wFormatTag = waveFormatTag; + waveFormatEx->nChannels = (WORD)numChannels; + waveFormatEx->nSamplesPerSec = (DWORD)sampleRate; + waveFormatEx->nAvgBytesPerSec = waveFormatEx->nSamplesPerSec * bytesPerFrame; + waveFormatEx->nBlockAlign = (WORD)bytesPerFrame; + waveFormatEx->wBitsPerSample = bytesPerSample * 8; + waveFormatEx->cbSize = 0; +} + + +void PaWin_InitializeWaveFormatExtensible( PaWinWaveFormat *waveFormat, + int numChannels, PaSampleFormat sampleFormat, int waveFormatTag, double sampleRate, + PaWinWaveFormatChannelMask channelMask ) +{ + WAVEFORMATEX *waveFormatEx = (WAVEFORMATEX*)waveFormat; + int bytesPerSample = Pa_GetSampleSize(sampleFormat); + unsigned long bytesPerFrame = numChannels * bytesPerSample; + GUID guid; + + waveFormatEx->wFormatTag = WAVE_FORMAT_EXTENSIBLE; + waveFormatEx->nChannels = (WORD)numChannels; + waveFormatEx->nSamplesPerSec = (DWORD)sampleRate; + waveFormatEx->nAvgBytesPerSec = waveFormatEx->nSamplesPerSec * bytesPerFrame; + waveFormatEx->nBlockAlign = (WORD)bytesPerFrame; + waveFormatEx->wBitsPerSample = bytesPerSample * 8; + waveFormatEx->cbSize = 22; + + *((WORD*)&waveFormat->fields[PAWIN_INDEXOF_WVALIDBITSPERSAMPLE]) = + waveFormatEx->wBitsPerSample; + + *((DWORD*)&waveFormat->fields[PAWIN_INDEXOF_DWCHANNELMASK]) = channelMask; + + guid = pawin_ksDataFormatSubtypeGuidBase; + guid.Data1 = (USHORT)waveFormatTag; + *((GUID*)&waveFormat->fields[PAWIN_INDEXOF_SUBFORMAT]) = guid; +} + +PaWinWaveFormatChannelMask PaWin_DefaultChannelMask( int numChannels ) +{ + switch( numChannels ){ + case 1: + return PAWIN_SPEAKER_MONO; + case 2: + return PAWIN_SPEAKER_STEREO; + case 3: + return PAWIN_SPEAKER_FRONT_LEFT | PAWIN_SPEAKER_FRONT_CENTER | PAWIN_SPEAKER_FRONT_RIGHT; + case 4: + return PAWIN_SPEAKER_QUAD; + case 5: + return PAWIN_SPEAKER_QUAD | PAWIN_SPEAKER_FRONT_CENTER; + case 6: + /* The meaning of the PAWIN_SPEAKER_5POINT1 flag has changed over time: + http://msdn2.microsoft.com/en-us/library/aa474707.aspx + We use PAWIN_SPEAKER_5POINT1 (not PAWIN_SPEAKER_5POINT1_SURROUND) + because on some cards (eg Audigy) PAWIN_SPEAKER_5POINT1_SURROUND + results in a virtual mixdown placing the rear output in the + front _and_ rear speakers. + */ + return PAWIN_SPEAKER_5POINT1; + /* case 7: */ + case 8: + /* RoBi: PAWIN_SPEAKER_7POINT1_SURROUND fits normal surround sound setups better than PAWIN_SPEAKER_7POINT1, f.i. NVidia HDMI Audio + output is silent on channels 5&6 with NVidia drivers, and channel 7&8 with Micrsoft HD Audio driver using PAWIN_SPEAKER_7POINT1. + With PAWIN_SPEAKER_7POINT1_SURROUND both setups work OK. */ + return PAWIN_SPEAKER_7POINT1_SURROUND; + } + + /* Apparently some Audigy drivers will output silence + if the direct-out constant (0) is used. So this is not ideal. + + RoBi 2012-12-19: Also, NVidia driver seem to output garbage instead. Again not very ideal. + */ + return PAWIN_SPEAKER_DIRECTOUT; + + /* Note that Alec Rogers proposed the following as an alternate method to + generate the default channel mask, however it doesn't seem to be an improvement + over the above, since some drivers will matrix outputs mapping to non-present + speakers accross multiple physical speakers. + + if(nChannels==1) { + pwfFormat->dwChannelMask = SPEAKER_FRONT_CENTER; + } + else { + pwfFormat->dwChannelMask = 0; + for(i=0; idwChannelMask = (pwfFormat->dwChannelMask << 1) | 0x1; + } + */ +} diff --git a/extern/portaudio/src/os/win/pa_win_wdmks_utils.c b/extern/portaudio/src/os/win/pa_win_wdmks_utils.c new file mode 100644 index 0000000..4bd067a --- /dev/null +++ b/extern/portaudio/src/os/win/pa_win_wdmks_utils.c @@ -0,0 +1,309 @@ +/* + * PortAudio Portable Real-Time Audio Library + * Windows WDM KS utilities + * + * Copyright (c) 1999 - 2007 Andrew Baldwin, Ross Bencina + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +#include +#include +#ifndef WAVE_FORMAT_IEEE_FLOAT + #define WAVE_FORMAT_IEEE_FLOAT 0x0003 // MinGW32 does not define this +#endif +#ifndef _WAVEFORMATEXTENSIBLE_ + #define _WAVEFORMATEXTENSIBLE_ // MinGW32 does not define this +#endif +#ifndef _INC_MMREG + #define _INC_MMREG // for STATIC_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT +#endif +#include // MinGW32 does not define this automatically + +#if defined(__GNUC__) + +#include "../../hostapi/wasapi/mingw-include/ks.h" +#include "../../hostapi/wasapi/mingw-include/ksmedia.h" + +#else + +#include +#include + +#endif + +#include // just for some development printfs + +#include "portaudio.h" +#include "pa_util.h" +#include "pa_win_wdmks_utils.h" + + +/* PortAudio-local instances of GUIDs previously sourced from ksguid.lib */ + +/* GUID KSDATAFORMAT_TYPE_AUDIO */ +static const GUID pa_KSDATAFORMAT_TYPE_AUDIO = { STATIC_KSDATAFORMAT_TYPE_AUDIO }; + +/* GUID KSDATAFORMAT_SUBTYPE_IEEE_FLOAT */ +static const GUID pa_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT = { STATIC_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT }; + +/* GUID KSDATAFORMAT_SUBTYPE_PCM */ +static const GUID pa_KSDATAFORMAT_SUBTYPE_PCM = { STATIC_KSDATAFORMAT_SUBTYPE_PCM }; + +/* GUID KSDATAFORMAT_SUBTYPE_WAVEFORMATEX */ +static const GUID pa_KSDATAFORMAT_SUBTYPE_WAVEFORMATEX = { STATIC_KSDATAFORMAT_SUBTYPE_WAVEFORMATEX }; + +/* GUID KSMEDIUMSETID_Standard */ +static const GUID pa_KSMEDIUMSETID_Standard = { STATIC_KSMEDIUMSETID_Standard }; + +/* GUID KSINTERFACESETID_Standard */ +static const GUID pa_KSINTERFACESETID_Standard = { STATIC_KSINTERFACESETID_Standard }; + +/* GUID KSPROPSETID_Pin */ +static const GUID pa_KSPROPSETID_Pin = { STATIC_KSPROPSETID_Pin }; + +#define pa_IS_VALID_WAVEFORMATEX_GUID(Guid)\ + (!memcmp(((PUSHORT)&pa_KSDATAFORMAT_SUBTYPE_WAVEFORMATEX) + 1, ((PUSHORT)(Guid)) + 1, sizeof(GUID) - sizeof(USHORT))) + + +static PaError WdmGetPinPropertySimple( + HANDLE handle, + unsigned long pinId, + unsigned long property, + void* value, + unsigned long valueSize ) +{ + DWORD bytesReturned; + KSP_PIN ksPProp; + ksPProp.Property.Set = pa_KSPROPSETID_Pin; + ksPProp.Property.Id = property; + ksPProp.Property.Flags = KSPROPERTY_TYPE_GET; + ksPProp.PinId = pinId; + ksPProp.Reserved = 0; + + if( DeviceIoControl( handle, IOCTL_KS_PROPERTY, &ksPProp, sizeof(KSP_PIN), + value, valueSize, &bytesReturned, NULL ) == 0 || bytesReturned != valueSize ) + { + return paUnanticipatedHostError; + } + else + { + return paNoError; + } +} + + +static PaError WdmGetPinPropertyMulti( + HANDLE handle, + unsigned long pinId, + unsigned long property, + KSMULTIPLE_ITEM** ksMultipleItem) +{ + unsigned long multipleItemSize = 0; + KSP_PIN ksPProp; + DWORD bytesReturned; + + *ksMultipleItem = 0; + + ksPProp.Property.Set = pa_KSPROPSETID_Pin; + ksPProp.Property.Id = property; + ksPProp.Property.Flags = KSPROPERTY_TYPE_GET; + ksPProp.PinId = pinId; + ksPProp.Reserved = 0; + + if( DeviceIoControl( handle, IOCTL_KS_PROPERTY, &ksPProp.Property, + sizeof(KSP_PIN), NULL, 0, &multipleItemSize, NULL ) == 0 && GetLastError() != ERROR_MORE_DATA ) + { + return paUnanticipatedHostError; + } + + *ksMultipleItem = (KSMULTIPLE_ITEM*)PaUtil_AllocateMemory( multipleItemSize ); + if( !*ksMultipleItem ) + { + return paInsufficientMemory; + } + + if( DeviceIoControl( handle, IOCTL_KS_PROPERTY, &ksPProp, sizeof(KSP_PIN), + (void*)*ksMultipleItem, multipleItemSize, &bytesReturned, NULL ) == 0 || bytesReturned != multipleItemSize ) + { + PaUtil_FreeMemory( ksMultipleItem ); + return paUnanticipatedHostError; + } + + return paNoError; +} + + +static int GetKSFilterPinCount( HANDLE deviceHandle ) +{ + DWORD result; + + if( WdmGetPinPropertySimple( deviceHandle, 0, KSPROPERTY_PIN_CTYPES, &result, sizeof(result) ) == paNoError ){ + return result; + }else{ + return 0; + } +} + + +static KSPIN_COMMUNICATION GetKSFilterPinPropertyCommunication( HANDLE deviceHandle, int pinId ) +{ + KSPIN_COMMUNICATION result; + + if( WdmGetPinPropertySimple( deviceHandle, pinId, KSPROPERTY_PIN_COMMUNICATION, &result, sizeof(result) ) == paNoError ){ + return result; + }else{ + return KSPIN_COMMUNICATION_NONE; + } +} + + +static KSPIN_DATAFLOW GetKSFilterPinPropertyDataflow( HANDLE deviceHandle, int pinId ) +{ + KSPIN_DATAFLOW result; + + if( WdmGetPinPropertySimple( deviceHandle, pinId, KSPROPERTY_PIN_DATAFLOW, &result, sizeof(result) ) == paNoError ){ + return result; + }else{ + return (KSPIN_DATAFLOW)0; + } +} + + +static int KSFilterPinPropertyIdentifiersInclude( + HANDLE deviceHandle, int pinId, unsigned long property, const GUID *identifierSet, unsigned long identifierId ) +{ + KSMULTIPLE_ITEM* item = NULL; + KSIDENTIFIER* identifier; + int i; + int result = 0; + + if( WdmGetPinPropertyMulti( deviceHandle, pinId, property, &item) != paNoError ) + return 0; + + identifier = (KSIDENTIFIER*)(item+1); + + for( i = 0; i < (int)item->Count; i++ ) + { + if( !memcmp( (void*)&identifier[i].Set, (void*)identifierSet, sizeof( GUID ) ) && + ( identifier[i].Id == identifierId ) ) + { + result = 1; + break; + } + } + + PaUtil_FreeMemory( item ); + + return result; +} + + +/* return the maximum channel count supported by any pin on the device. + if isInput is non-zero we query input pins, otherwise output pins. +*/ +int PaWin_WDMKS_QueryFilterMaximumChannelCount( void *wcharDevicePath, int isInput ) +{ + HANDLE deviceHandle; + ULONG i; + int pinCount, pinId; + int result = 0; + KSPIN_DATAFLOW requiredDataflowDirection = (isInput ? KSPIN_DATAFLOW_OUT : KSPIN_DATAFLOW_IN ); + + if( !wcharDevicePath ) + return 0; + + deviceHandle = CreateFileW( (LPCWSTR)wcharDevicePath, FILE_SHARE_READ|FILE_SHARE_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL ); + if( deviceHandle == INVALID_HANDLE_VALUE ) + return 0; + + pinCount = GetKSFilterPinCount( deviceHandle ); + for( pinId = 0; pinId < pinCount; ++pinId ) + { + KSPIN_COMMUNICATION communication = GetKSFilterPinPropertyCommunication( deviceHandle, pinId ); + KSPIN_DATAFLOW dataflow = GetKSFilterPinPropertyDataflow( deviceHandle, pinId ); + if( ( dataflow == requiredDataflowDirection ) && + (( communication == KSPIN_COMMUNICATION_SINK) || + ( communication == KSPIN_COMMUNICATION_BOTH)) + && ( KSFilterPinPropertyIdentifiersInclude( deviceHandle, pinId, + KSPROPERTY_PIN_INTERFACES, &pa_KSINTERFACESETID_Standard, KSINTERFACE_STANDARD_STREAMING ) + || KSFilterPinPropertyIdentifiersInclude( deviceHandle, pinId, + KSPROPERTY_PIN_INTERFACES, &pa_KSINTERFACESETID_Standard, KSINTERFACE_STANDARD_LOOPED_STREAMING ) ) + && KSFilterPinPropertyIdentifiersInclude( deviceHandle, pinId, + KSPROPERTY_PIN_MEDIUMS, &pa_KSMEDIUMSETID_Standard, KSMEDIUM_STANDARD_DEVIO ) ) + { + KSMULTIPLE_ITEM* item = NULL; + if( WdmGetPinPropertyMulti( deviceHandle, pinId, KSPROPERTY_PIN_DATARANGES, &item ) == paNoError ) + { + KSDATARANGE *dataRange = (KSDATARANGE*)(item+1); + + for( i=0; i < item->Count; ++i ){ + + if( pa_IS_VALID_WAVEFORMATEX_GUID(&dataRange->SubFormat) + || memcmp( (void*)&dataRange->SubFormat, (void*)&pa_KSDATAFORMAT_SUBTYPE_PCM, sizeof(GUID) ) == 0 + || memcmp( (void*)&dataRange->SubFormat, (void*)&pa_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, sizeof(GUID) ) == 0 + || ( ( memcmp( (void*)&dataRange->MajorFormat, (void*)&pa_KSDATAFORMAT_TYPE_AUDIO, sizeof(GUID) ) == 0 ) + && ( memcmp( (void*)&dataRange->SubFormat, (void*)&KSDATAFORMAT_SUBTYPE_WILDCARD, sizeof(GUID) ) == 0 ) ) ) + { + KSDATARANGE_AUDIO *dataRangeAudio = (KSDATARANGE_AUDIO*)dataRange; + + /* + printf( ">>> %d %d %d %d %S\n", isInput, dataflow, communication, dataRangeAudio->MaximumChannels, devicePath ); + + if( memcmp((void*)&dataRange->Specifier, (void*)&KSDATAFORMAT_SPECIFIER_WAVEFORMATEX, sizeof(GUID) ) == 0 ) + printf( "\tspecifier: KSDATAFORMAT_SPECIFIER_WAVEFORMATEX\n" ); + else if( memcmp((void*)&dataRange->Specifier, (void*)&KSDATAFORMAT_SPECIFIER_DSOUND, sizeof(GUID) ) == 0 ) + printf( "\tspecifier: KSDATAFORMAT_SPECIFIER_DSOUND\n" ); + else if( memcmp((void*)&dataRange->Specifier, (void*)&KSDATAFORMAT_SPECIFIER_WILDCARD, sizeof(GUID) ) == 0 ) + printf( "\tspecifier: KSDATAFORMAT_SPECIFIER_WILDCARD\n" ); + else + printf( "\tspecifier: ?\n" ); + */ + + /* + We assume that very high values for MaximumChannels are not useful and indicate + that the driver isn't prepared to tell us the real number of channels which it supports. + */ + if( dataRangeAudio->MaximumChannels < 0xFFFFUL && (int)dataRangeAudio->MaximumChannels > result ) + result = (int)dataRangeAudio->MaximumChannels; + } + + dataRange = (KSDATARANGE*)( ((char*)dataRange) + dataRange->FormatSize); + } + + PaUtil_FreeMemory( item ); + } + } + } + + CloseHandle( deviceHandle ); + return result; +} diff --git a/extern/portaudio/src/os/win/pa_win_wdmks_utils.h b/extern/portaudio/src/os/win/pa_win_wdmks_utils.h new file mode 100644 index 0000000..b8e923a --- /dev/null +++ b/extern/portaudio/src/os/win/pa_win_wdmks_utils.h @@ -0,0 +1,65 @@ +#ifndef PA_WIN_WDMKS_UTILS_H +#define PA_WIN_WDMKS_UTILS_H + +/* + * PortAudio Portable Real-Time Audio Library + * Windows WDM KS utilities + * + * Copyright (c) 1999 - 2007 Ross Bencina, Andrew Baldwin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +/** @file + @brief Utilities for working with the Windows WDM KS API +*/ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Query for the maximum number of channels supported by any pin of the + specified device. Returns 0 if the query fails for any reason. + + @param wcharDevicePath A system level PnP interface path, supplied as a WCHAR unicode string. + Declard as void* to avoid introducing a dependency on wchar_t here. + + @param isInput A flag specifying whether to query for input (non-zero) or output (zero) channels. +*/ +int PaWin_WDMKS_QueryFilterMaximumChannelCount( void *wcharDevicePath, int isInput ); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* PA_WIN_WDMKS_UTILS_H */ \ No newline at end of file diff --git a/extern/portaudio/src/os/win/pa_x86_plain_converters.c b/extern/portaudio/src/os/win/pa_x86_plain_converters.c new file mode 100644 index 0000000..ae43d28 --- /dev/null +++ b/extern/portaudio/src/os/win/pa_x86_plain_converters.c @@ -0,0 +1,1218 @@ +/* + * Plain Intel IA32 assembly implementations of PortAudio sample converter functions. + * Copyright (c) 1999-2002 Ross Bencina, Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +/** @file + @ingroup win_src +*/ + +#include "pa_x86_plain_converters.h" + +#include "pa_converters.h" +#include "pa_dither.h" + +/* + the main reason these versions are faster than the equivalent C versions + is that float -> int casting is expensive in C on x86 because the rounding + mode needs to be changed for every cast. these versions only set + the rounding mode once outside the loop. + + small additional speed gains are made by the way that clamping is + implemented. + +TODO: + o- inline dither code + o- implement Dither only (no-clip) versions + o- implement int8 and uint8 versions + o- test thouroughly + + o- the packed 24 bit functions could benefit from unrolling and avoiding + byte and word sized register access. +*/ + +/* -------------------------------------------------------------------------- */ + +/* +#define PA_CLIP_( val, min, max )\ + { val = ((val) < (min)) ? (min) : (((val) > (max)) ? (max) : (val)); } +*/ + +/* + the following notes were used to determine whether a floating point + value should be saturated (ie >1 or <-1) by loading it into an integer + register. these should be rewritten so that they make sense. + + an ieee floating point value + + 1.xxxxxxxxxxxxxxxxxxxx? + + + is less than or equal to 1 and greater than or equal to -1 either: + + if the mantissa is 0 and the unbiased exponent is 0 + + OR + + if the unbiased exponent < 0 + + this translates to: + + if the mantissa is 0 and the biased exponent is 7F + + or + + if the biased exponent is less than 7F + + + therefore the value is greater than 1 or less than -1 if + + the mantissa is not 0 and the biased exponent is 7F + + or + + if the biased exponent is greater than 7F + + + in other words, if we mask out the sign bit, the value is + greater than 1 or less than -1 if its integer representation is greater than: + + 0 01111111 0000 0000 0000 0000 0000 000 + + 0011 1111 1000 0000 0000 0000 0000 0000 => 0x3F800000 +*/ + +#if defined(_WIN64) || defined(_WIN32_WCE) + +/* + -EMT64/AMD64 uses different asm + -VC2005 doesnt allow _WIN64 with inline assembly either! + */ +void PaUtil_InitializeX86PlainConverters( void ) +{ +} + +#else + +/* -------------------------------------------------------------------------- */ + +static const short fpuControlWord_ = 0x033F; /*round to nearest, 64 bit precision, all exceptions masked*/ +static const double int32Scaler_ = 0x7FFFFFFF; +static const double ditheredInt32Scaler_ = 0x7FFFFFFE; +static const double int24Scaler_ = 0x7FFFFF; +static const double ditheredInt24Scaler_ = 0x7FFFFE; +static const double int16Scaler_ = 0x7FFF; +static const double ditheredInt16Scaler_ = 0x7FFE; + +#define PA_DITHER_BITS_ (15) +/* Multiply by PA_FLOAT_DITHER_SCALE_ to get a float between -2.0 and +1.99999 */ +#define PA_FLOAT_DITHER_SCALE_ (1.0F / ((1< source ptr + // eax -> source byte stride + // edi -> destination ptr + // ebx -> destination byte stride + // ecx -> source end ptr + // edx -> temp + + mov esi, sourceBuffer + + mov edx, 4 // sizeof float32 and int32 + mov eax, sourceStride + imul eax, edx + + mov ecx, count + imul ecx, eax + add ecx, esi + + mov edi, destinationBuffer + + mov ebx, destinationStride + imul ebx, edx + + fwait + fstcw savedFpuControlWord + fldcw fpuControlWord_ + + fld int32Scaler_ // stack: (int)0x7FFFFFFF + + Float32_To_Int32_loop: + + // load unscaled value into st(0) + fld dword ptr [esi] // stack: value, (int)0x7FFFFFFF + add esi, eax // increment source ptr + //lea esi, [esi+eax] + fmul st(0), st(1) // st(0) *= st(1), stack: value*0x7FFFFFFF, (int)0x7FFFFFFF + /* + note: we could store to a temporary qword here which would cause + wraparound distortion instead of int indefinite 0x10. that would + be more work, and given that not enabling clipping is only advisable + when you know that your signal isn't going to clip it isn't worth it. + */ + fistp dword ptr [edi] // pop st(0) into dest, stack: (int)0x7FFFFFFF + + add edi, ebx // increment destination ptr + //lea edi, [edi+ebx] + + cmp esi, ecx // has src ptr reached end? + jne Float32_To_Int32_loop + + ffree st(0) + fincstp + + fwait + fnclex + fldcw savedFpuControlWord + } +} + +/* -------------------------------------------------------------------------- */ + +static void Float32_To_Int32_Clip( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, PaUtilTriangularDitherGenerator *ditherGenerator ) +{ +/* + float *src = (float*)sourceBuffer; + signed long *dest = (signed long*)destinationBuffer; + (void) ditherGenerator; // unused parameter + + while( count-- ) + { + // REVIEW + double scaled = *src * 0x7FFFFFFF; + PA_CLIP_( scaled, -2147483648., 2147483647. ); + *dest = (signed long) scaled; + + src += sourceStride; + dest += destinationStride; + } +*/ + + short savedFpuControlWord; + + (void) ditherGenerator; /* unused parameter */ + + __asm{ + // esi -> source ptr + // eax -> source byte stride + // edi -> destination ptr + // ebx -> destination byte stride + // ecx -> source end ptr + // edx -> temp + + mov esi, sourceBuffer + + mov edx, 4 // sizeof float32 and int32 + mov eax, sourceStride + imul eax, edx + + mov ecx, count + imul ecx, eax + add ecx, esi + + mov edi, destinationBuffer + + mov ebx, destinationStride + imul ebx, edx + + fwait + fstcw savedFpuControlWord + fldcw fpuControlWord_ + + fld int32Scaler_ // stack: (int)0x7FFFFFFF + + Float32_To_Int32_Clip_loop: + + mov edx, dword ptr [esi] // load floating point value into integer register + + and edx, 0x7FFFFFFF // mask off sign + cmp edx, 0x3F800000 // greater than 1.0 or less than -1.0 + + jg Float32_To_Int32_Clip_clamp + + // load unscaled value into st(0) + fld dword ptr [esi] // stack: value, (int)0x7FFFFFFF + add esi, eax // increment source ptr + //lea esi, [esi+eax] + fmul st(0), st(1) // st(0) *= st(1), stack: value*0x7FFFFFFF, (int)0x7FFFFFFF + fistp dword ptr [edi] // pop st(0) into dest, stack: (int)0x7FFFFFFF + jmp Float32_To_Int32_Clip_stored + + Float32_To_Int32_Clip_clamp: + mov edx, dword ptr [esi] // load floating point value into integer register + shr edx, 31 // move sign bit into bit 0 + add esi, eax // increment source ptr + //lea esi, [esi+eax] + add edx, 0x7FFFFFFF // convert to maximum range integers + mov dword ptr [edi], edx + + Float32_To_Int32_Clip_stored: + + //add edi, ebx // increment destination ptr + lea edi, [edi+ebx] + + cmp esi, ecx // has src ptr reached end? + jne Float32_To_Int32_Clip_loop + + ffree st(0) + fincstp + + fwait + fnclex + fldcw savedFpuControlWord + } +} + +/* -------------------------------------------------------------------------- */ + +static void Float32_To_Int32_DitherClip( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + /* + float *src = (float*)sourceBuffer; + signed long *dest = (signed long*)destinationBuffer; + + while( count-- ) + { + // REVIEW + double dither = PaUtil_GenerateFloatTriangularDither( ditherGenerator ); + // use smaller scaler to prevent overflow when we add the dither + double dithered = ((double)*src * (2147483646.0)) + dither; + PA_CLIP_( dithered, -2147483648., 2147483647. ); + *dest = (signed long) dithered; + + + src += sourceStride; + dest += destinationStride; + } + */ + + short savedFpuControlWord; + + // spill storage: + signed long sourceByteStride; + signed long highpassedDither; + + // dither state: + unsigned long ditherPrevious = ditherGenerator->previous; + unsigned long ditherRandSeed1 = ditherGenerator->randSeed1; + unsigned long ditherRandSeed2 = ditherGenerator->randSeed2; + + __asm{ + // esi -> source ptr + // eax -> source byte stride + // edi -> destination ptr + // ebx -> destination byte stride + // ecx -> source end ptr + // edx -> temp + + mov esi, sourceBuffer + + mov edx, 4 // sizeof float32 and int32 + mov eax, sourceStride + imul eax, edx + + mov ecx, count + imul ecx, eax + add ecx, esi + + mov edi, destinationBuffer + + mov ebx, destinationStride + imul ebx, edx + + fwait + fstcw savedFpuControlWord + fldcw fpuControlWord_ + + fld ditheredInt32Scaler_ // stack: int scaler + + Float32_To_Int32_DitherClip_loop: + + mov edx, dword ptr [esi] // load floating point value into integer register + + and edx, 0x7FFFFFFF // mask off sign + cmp edx, 0x3F800000 // greater than 1.0 or less than -1.0 + + jg Float32_To_Int32_DitherClip_clamp + + // load unscaled value into st(0) + fld dword ptr [esi] // stack: value, int scaler + add esi, eax // increment source ptr + //lea esi, [esi+eax] + fmul st(0), st(1) // st(0) *= st(1), stack: value*(int scaler), int scaler + + /* + // call PaUtil_GenerateFloatTriangularDither with C calling convention + mov sourceByteStride, eax // save eax + mov sourceEnd, ecx // save ecx + push ditherGenerator // pass ditherGenerator parameter on stack + call PaUtil_GenerateFloatTriangularDither // stack: dither, value*(int scaler), int scaler + pop edx // clear parameter off stack + mov ecx, sourceEnd // restore ecx + mov eax, sourceByteStride // restore eax + */ + + // generate dither + mov sourceByteStride, eax // save eax + mov edx, 196314165 + mov eax, ditherRandSeed1 + mul edx // eax:edx = eax * 196314165 + //add eax, 907633515 + lea eax, [eax+907633515] + mov ditherRandSeed1, eax + mov edx, 196314165 + mov eax, ditherRandSeed2 + mul edx // eax:edx = eax * 196314165 + //add eax, 907633515 + lea eax, [eax+907633515] + mov edx, ditherRandSeed1 + shr edx, PA_DITHER_SHIFT_ + mov ditherRandSeed2, eax + shr eax, PA_DITHER_SHIFT_ + //add eax, edx // eax -> current + lea eax, [eax+edx] + mov edx, ditherPrevious + neg edx + lea edx, [eax+edx] // highpass = current - previous + mov highpassedDither, edx + mov ditherPrevious, eax // previous = current + mov eax, sourceByteStride // restore eax + fild highpassedDither + fmul const_float_dither_scale_ + // end generate dither, dither signal in st(0) + + faddp st(1), st(0) // stack: dither + value*(int scaler), int scaler + fistp dword ptr [edi] // pop st(0) into dest, stack: int scaler + jmp Float32_To_Int32_DitherClip_stored + + Float32_To_Int32_DitherClip_clamp: + mov edx, dword ptr [esi] // load floating point value into integer register + shr edx, 31 // move sign bit into bit 0 + add esi, eax // increment source ptr + //lea esi, [esi+eax] + add edx, 0x7FFFFFFF // convert to maximum range integers + mov dword ptr [edi], edx + + Float32_To_Int32_DitherClip_stored: + + //add edi, ebx // increment destination ptr + lea edi, [edi+ebx] + + cmp esi, ecx // has src ptr reached end? + jne Float32_To_Int32_DitherClip_loop + + ffree st(0) + fincstp + + fwait + fnclex + fldcw savedFpuControlWord + } + + ditherGenerator->previous = ditherPrevious; + ditherGenerator->randSeed1 = ditherRandSeed1; + ditherGenerator->randSeed2 = ditherRandSeed2; +} + +/* -------------------------------------------------------------------------- */ + +static void Float32_To_Int24( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, PaUtilTriangularDitherGenerator *ditherGenerator ) +{ +/* + float *src = (float*)sourceBuffer; + unsigned char *dest = (unsigned char*)destinationBuffer; + signed long temp; + + (void) ditherGenerator; // unused parameter + + while( count-- ) + { + // convert to 32 bit and drop the low 8 bits + double scaled = *src * 0x7FFFFFFF; + temp = (signed long) scaled; + + dest[0] = (unsigned char)(temp >> 8); + dest[1] = (unsigned char)(temp >> 16); + dest[2] = (unsigned char)(temp >> 24); + + src += sourceStride; + dest += destinationStride * 3; + } +*/ + + short savedFpuControlWord; + + signed long tempInt32; + + (void) ditherGenerator; /* unused parameter */ + + __asm{ + // esi -> source ptr + // eax -> source byte stride + // edi -> destination ptr + // ebx -> destination byte stride + // ecx -> source end ptr + // edx -> temp + + mov esi, sourceBuffer + + mov edx, 4 // sizeof float32 + mov eax, sourceStride + imul eax, edx + + mov ecx, count + imul ecx, eax + add ecx, esi + + mov edi, destinationBuffer + + mov edx, 3 // sizeof int24 + mov ebx, destinationStride + imul ebx, edx + + fwait + fstcw savedFpuControlWord + fldcw fpuControlWord_ + + fld int24Scaler_ // stack: (int)0x7FFFFF + + Float32_To_Int24_loop: + + // load unscaled value into st(0) + fld dword ptr [esi] // stack: value, (int)0x7FFFFF + add esi, eax // increment source ptr + //lea esi, [esi+eax] + fmul st(0), st(1) // st(0) *= st(1), stack: value*0x7FFFFF, (int)0x7FFFFF + fistp tempInt32 // pop st(0) into tempInt32, stack: (int)0x7FFFFF + mov edx, tempInt32 + + mov byte ptr [edi], DL + shr edx, 8 + //mov byte ptr [edi+1], DL + //mov byte ptr [edi+2], DH + mov word ptr [edi+1], DX + + //add edi, ebx // increment destination ptr + lea edi, [edi+ebx] + + cmp esi, ecx // has src ptr reached end? + jne Float32_To_Int24_loop + + ffree st(0) + fincstp + + fwait + fnclex + fldcw savedFpuControlWord + } +} + +/* -------------------------------------------------------------------------- */ + +static void Float32_To_Int24_Clip( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, PaUtilTriangularDitherGenerator *ditherGenerator ) +{ +/* + float *src = (float*)sourceBuffer; + unsigned char *dest = (unsigned char*)destinationBuffer; + signed long temp; + + (void) ditherGenerator; // unused parameter + + while( count-- ) + { + // convert to 32 bit and drop the low 8 bits + double scaled = *src * 0x7FFFFFFF; + PA_CLIP_( scaled, -2147483648., 2147483647. ); + temp = (signed long) scaled; + + dest[0] = (unsigned char)(temp >> 8); + dest[1] = (unsigned char)(temp >> 16); + dest[2] = (unsigned char)(temp >> 24); + + src += sourceStride; + dest += destinationStride * 3; + } +*/ + + short savedFpuControlWord; + + signed long tempInt32; + + (void) ditherGenerator; /* unused parameter */ + + __asm{ + // esi -> source ptr + // eax -> source byte stride + // edi -> destination ptr + // ebx -> destination byte stride + // ecx -> source end ptr + // edx -> temp + + mov esi, sourceBuffer + + mov edx, 4 // sizeof float32 + mov eax, sourceStride + imul eax, edx + + mov ecx, count + imul ecx, eax + add ecx, esi + + mov edi, destinationBuffer + + mov edx, 3 // sizeof int24 + mov ebx, destinationStride + imul ebx, edx + + fwait + fstcw savedFpuControlWord + fldcw fpuControlWord_ + + fld int24Scaler_ // stack: (int)0x7FFFFF + + Float32_To_Int24_Clip_loop: + + mov edx, dword ptr [esi] // load floating point value into integer register + + and edx, 0x7FFFFFFF // mask off sign + cmp edx, 0x3F800000 // greater than 1.0 or less than -1.0 + + jg Float32_To_Int24_Clip_clamp + + // load unscaled value into st(0) + fld dword ptr [esi] // stack: value, (int)0x7FFFFF + add esi, eax // increment source ptr + //lea esi, [esi+eax] + fmul st(0), st(1) // st(0) *= st(1), stack: value*0x7FFFFF, (int)0x7FFFFF + fistp tempInt32 // pop st(0) into tempInt32, stack: (int)0x7FFFFF + mov edx, tempInt32 + jmp Float32_To_Int24_Clip_store + + Float32_To_Int24_Clip_clamp: + mov edx, dword ptr [esi] // load floating point value into integer register + shr edx, 31 // move sign bit into bit 0 + add esi, eax // increment source ptr + //lea esi, [esi+eax] + add edx, 0x7FFFFF // convert to maximum range integers + + Float32_To_Int24_Clip_store: + + mov byte ptr [edi], DL + shr edx, 8 + //mov byte ptr [edi+1], DL + //mov byte ptr [edi+2], DH + mov word ptr [edi+1], DX + + //add edi, ebx // increment destination ptr + lea edi, [edi+ebx] + + cmp esi, ecx // has src ptr reached end? + jne Float32_To_Int24_Clip_loop + + ffree st(0) + fincstp + + fwait + fnclex + fldcw savedFpuControlWord + } +} + +/* -------------------------------------------------------------------------- */ + +static void Float32_To_Int24_DitherClip( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, PaUtilTriangularDitherGenerator *ditherGenerator ) +{ +/* + float *src = (float*)sourceBuffer; + unsigned char *dest = (unsigned char*)destinationBuffer; + signed long temp; + + while( count-- ) + { + // convert to 32 bit and drop the low 8 bits + + // FIXME: the dither amplitude here appears to be too small by 8 bits + double dither = PaUtil_GenerateFloatTriangularDither( ditherGenerator ); + // use smaller scaler to prevent overflow when we add the dither + double dithered = ((double)*src * (2147483646.0)) + dither; + PA_CLIP_( dithered, -2147483648., 2147483647. ); + + temp = (signed long) dithered; + + dest[0] = (unsigned char)(temp >> 8); + dest[1] = (unsigned char)(temp >> 16); + dest[2] = (unsigned char)(temp >> 24); + + src += sourceStride; + dest += destinationStride * 3; + } +*/ + + short savedFpuControlWord; + + // spill storage: + signed long sourceByteStride; + signed long highpassedDither; + + // dither state: + unsigned long ditherPrevious = ditherGenerator->previous; + unsigned long ditherRandSeed1 = ditherGenerator->randSeed1; + unsigned long ditherRandSeed2 = ditherGenerator->randSeed2; + + signed long tempInt32; + + __asm{ + // esi -> source ptr + // eax -> source byte stride + // edi -> destination ptr + // ebx -> destination byte stride + // ecx -> source end ptr + // edx -> temp + + mov esi, sourceBuffer + + mov edx, 4 // sizeof float32 + mov eax, sourceStride + imul eax, edx + + mov ecx, count + imul ecx, eax + add ecx, esi + + mov edi, destinationBuffer + + mov edx, 3 // sizeof int24 + mov ebx, destinationStride + imul ebx, edx + + fwait + fstcw savedFpuControlWord + fldcw fpuControlWord_ + + fld ditheredInt24Scaler_ // stack: int scaler + + Float32_To_Int24_DitherClip_loop: + + mov edx, dword ptr [esi] // load floating point value into integer register + + and edx, 0x7FFFFFFF // mask off sign + cmp edx, 0x3F800000 // greater than 1.0 or less than -1.0 + + jg Float32_To_Int24_DitherClip_clamp + + // load unscaled value into st(0) + fld dword ptr [esi] // stack: value, int scaler + add esi, eax // increment source ptr + //lea esi, [esi+eax] + fmul st(0), st(1) // st(0) *= st(1), stack: value*(int scaler), int scaler + + /* + // call PaUtil_GenerateFloatTriangularDither with C calling convention + mov sourceByteStride, eax // save eax + mov sourceEnd, ecx // save ecx + push ditherGenerator // pass ditherGenerator parameter on stack + call PaUtil_GenerateFloatTriangularDither // stack: dither, value*(int scaler), int scaler + pop edx // clear parameter off stack + mov ecx, sourceEnd // restore ecx + mov eax, sourceByteStride // restore eax + */ + + // generate dither + mov sourceByteStride, eax // save eax + mov edx, 196314165 + mov eax, ditherRandSeed1 + mul edx // eax:edx = eax * 196314165 + //add eax, 907633515 + lea eax, [eax+907633515] + mov ditherRandSeed1, eax + mov edx, 196314165 + mov eax, ditherRandSeed2 + mul edx // eax:edx = eax * 196314165 + //add eax, 907633515 + lea eax, [eax+907633515] + mov edx, ditherRandSeed1 + shr edx, PA_DITHER_SHIFT_ + mov ditherRandSeed2, eax + shr eax, PA_DITHER_SHIFT_ + //add eax, edx // eax -> current + lea eax, [eax+edx] + mov edx, ditherPrevious + neg edx + lea edx, [eax+edx] // highpass = current - previous + mov highpassedDither, edx + mov ditherPrevious, eax // previous = current + mov eax, sourceByteStride // restore eax + fild highpassedDither + fmul const_float_dither_scale_ + // end generate dither, dither signal in st(0) + + faddp st(1), st(0) // stack: dither * value*(int scaler), int scaler + fistp tempInt32 // pop st(0) into tempInt32, stack: int scaler + mov edx, tempInt32 + jmp Float32_To_Int24_DitherClip_store + + Float32_To_Int24_DitherClip_clamp: + mov edx, dword ptr [esi] // load floating point value into integer register + shr edx, 31 // move sign bit into bit 0 + add esi, eax // increment source ptr + //lea esi, [esi+eax] + add edx, 0x7FFFFF // convert to maximum range integers + + Float32_To_Int24_DitherClip_store: + + mov byte ptr [edi], DL + shr edx, 8 + //mov byte ptr [edi+1], DL + //mov byte ptr [edi+2], DH + mov word ptr [edi+1], DX + + //add edi, ebx // increment destination ptr + lea edi, [edi+ebx] + + cmp esi, ecx // has src ptr reached end? + jne Float32_To_Int24_DitherClip_loop + + ffree st(0) + fincstp + + fwait + fnclex + fldcw savedFpuControlWord + } + + ditherGenerator->previous = ditherPrevious; + ditherGenerator->randSeed1 = ditherRandSeed1; + ditherGenerator->randSeed2 = ditherRandSeed2; +} + +/* -------------------------------------------------------------------------- */ + +static void Float32_To_Int16( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, PaUtilTriangularDitherGenerator *ditherGenerator ) +{ +/* + float *src = (float*)sourceBuffer; + signed short *dest = (signed short*)destinationBuffer; + (void)ditherGenerator; // unused parameter + + while( count-- ) + { + + short samp = (short) (*src * (32767.0f)); + *dest = samp; + + src += sourceStride; + dest += destinationStride; + } +*/ + + short savedFpuControlWord; + + (void) ditherGenerator; /* unused parameter */ + + __asm{ + // esi -> source ptr + // eax -> source byte stride + // edi -> destination ptr + // ebx -> destination byte stride + // ecx -> source end ptr + // edx -> temp + + mov esi, sourceBuffer + + mov edx, 4 // sizeof float32 + mov eax, sourceStride + imul eax, edx // source byte stride + + mov ecx, count + imul ecx, eax + add ecx, esi // source end ptr = count * source byte stride + source ptr + + mov edi, destinationBuffer + + mov edx, 2 // sizeof int16 + mov ebx, destinationStride + imul ebx, edx // destination byte stride + + fwait + fstcw savedFpuControlWord + fldcw fpuControlWord_ + + fld int16Scaler_ // stack: (int)0x7FFF + + Float32_To_Int16_loop: + + // load unscaled value into st(0) + fld dword ptr [esi] // stack: value, (int)0x7FFF + add esi, eax // increment source ptr + //lea esi, [esi+eax] + fmul st(0), st(1) // st(0) *= st(1), stack: value*0x7FFF, (int)0x7FFF + fistp word ptr [edi] // store scaled int into dest, stack: (int)0x7FFF + + add edi, ebx // increment destination ptr + //lea edi, [edi+ebx] + + cmp esi, ecx // has src ptr reached end? + jne Float32_To_Int16_loop + + ffree st(0) + fincstp + + fwait + fnclex + fldcw savedFpuControlWord + } +} + +/* -------------------------------------------------------------------------- */ + +static void Float32_To_Int16_Clip( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, PaUtilTriangularDitherGenerator *ditherGenerator ) +{ +/* + float *src = (float*)sourceBuffer; + signed short *dest = (signed short*)destinationBuffer; + (void)ditherGenerator; // unused parameter + + while( count-- ) + { + long samp = (signed long) (*src * (32767.0f)); + PA_CLIP_( samp, -0x8000, 0x7FFF ); + *dest = (signed short) samp; + + src += sourceStride; + dest += destinationStride; + } +*/ + + short savedFpuControlWord; + + (void) ditherGenerator; /* unused parameter */ + + __asm{ + // esi -> source ptr + // eax -> source byte stride + // edi -> destination ptr + // ebx -> destination byte stride + // ecx -> source end ptr + // edx -> temp + + mov esi, sourceBuffer + + mov edx, 4 // sizeof float32 + mov eax, sourceStride + imul eax, edx // source byte stride + + mov ecx, count + imul ecx, eax + add ecx, esi // source end ptr = count * source byte stride + source ptr + + mov edi, destinationBuffer + + mov edx, 2 // sizeof int16 + mov ebx, destinationStride + imul ebx, edx // destination byte stride + + fwait + fstcw savedFpuControlWord + fldcw fpuControlWord_ + + fld int16Scaler_ // stack: (int)0x7FFF + + Float32_To_Int16_Clip_loop: + + mov edx, dword ptr [esi] // load floating point value into integer register + + and edx, 0x7FFFFFFF // mask off sign + cmp edx, 0x3F800000 // greater than 1.0 or less than -1.0 + + jg Float32_To_Int16_Clip_clamp + + // load unscaled value into st(0) + fld dword ptr [esi] // stack: value, (int)0x7FFF + add esi, eax // increment source ptr + //lea esi, [esi+eax] + fmul st(0), st(1) // st(0) *= st(1), stack: value*0x7FFF, (int)0x7FFF + fistp word ptr [edi] // store scaled int into dest, stack: (int)0x7FFF + jmp Float32_To_Int16_Clip_stored + + Float32_To_Int16_Clip_clamp: + mov edx, dword ptr [esi] // load floating point value into integer register + shr edx, 31 // move sign bit into bit 0 + add esi, eax // increment source ptr + //lea esi, [esi+eax] + add dx, 0x7FFF // convert to maximum range integers + mov word ptr [edi], dx // store clamped into into dest + + Float32_To_Int16_Clip_stored: + + add edi, ebx // increment destination ptr + //lea edi, [edi+ebx] + + cmp esi, ecx // has src ptr reached end? + jne Float32_To_Int16_Clip_loop + + ffree st(0) + fincstp + + fwait + fnclex + fldcw savedFpuControlWord + } +} + +/* -------------------------------------------------------------------------- */ + +static void Float32_To_Int16_DitherClip( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, PaUtilTriangularDitherGenerator *ditherGenerator ) +{ +/* + float *src = (float*)sourceBuffer; + signed short *dest = (signed short*)destinationBuffer; + (void)ditherGenerator; // unused parameter + + while( count-- ) + { + + float dither = PaUtil_GenerateFloatTriangularDither( ditherGenerator ); + // use smaller scaler to prevent overflow when we add the dither + float dithered = (*src * (32766.0f)) + dither; + signed long samp = (signed long) dithered; + PA_CLIP_( samp, -0x8000, 0x7FFF ); + *dest = (signed short) samp; + + src += sourceStride; + dest += destinationStride; + } +*/ + + short savedFpuControlWord; + + // spill storage: + signed long sourceByteStride; + signed long highpassedDither; + + // dither state: + unsigned long ditherPrevious = ditherGenerator->previous; + unsigned long ditherRandSeed1 = ditherGenerator->randSeed1; + unsigned long ditherRandSeed2 = ditherGenerator->randSeed2; + + __asm{ + // esi -> source ptr + // eax -> source byte stride + // edi -> destination ptr + // ebx -> destination byte stride + // ecx -> source end ptr + // edx -> temp + + mov esi, sourceBuffer + + mov edx, 4 // sizeof float32 + mov eax, sourceStride + imul eax, edx // source byte stride + + mov ecx, count + imul ecx, eax + add ecx, esi // source end ptr = count * source byte stride + source ptr + + mov edi, destinationBuffer + + mov edx, 2 // sizeof int16 + mov ebx, destinationStride + imul ebx, edx // destination byte stride + + fwait + fstcw savedFpuControlWord + fldcw fpuControlWord_ + + fld ditheredInt16Scaler_ // stack: int scaler + + Float32_To_Int16_DitherClip_loop: + + mov edx, dword ptr [esi] // load floating point value into integer register + + and edx, 0x7FFFFFFF // mask off sign + cmp edx, 0x3F800000 // greater than 1.0 or less than -1.0 + + jg Float32_To_Int16_DitherClip_clamp + + // load unscaled value into st(0) + fld dword ptr [esi] // stack: value, int scaler + add esi, eax // increment source ptr + //lea esi, [esi+eax] + fmul st(0), st(1) // st(0) *= st(1), stack: value*(int scaler), int scaler + + /* + // call PaUtil_GenerateFloatTriangularDither with C calling convention + mov sourceByteStride, eax // save eax + mov sourceEnd, ecx // save ecx + push ditherGenerator // pass ditherGenerator parameter on stack + call PaUtil_GenerateFloatTriangularDither // stack: dither, value*(int scaler), int scaler + pop edx // clear parameter off stack + mov ecx, sourceEnd // restore ecx + mov eax, sourceByteStride // restore eax + */ + + // generate dither + mov sourceByteStride, eax // save eax + mov edx, 196314165 + mov eax, ditherRandSeed1 + mul edx // eax:edx = eax * 196314165 + //add eax, 907633515 + lea eax, [eax+907633515] + mov ditherRandSeed1, eax + mov edx, 196314165 + mov eax, ditherRandSeed2 + mul edx // eax:edx = eax * 196314165 + //add eax, 907633515 + lea eax, [eax+907633515] + mov edx, ditherRandSeed1 + shr edx, PA_DITHER_SHIFT_ + mov ditherRandSeed2, eax + shr eax, PA_DITHER_SHIFT_ + //add eax, edx // eax -> current + lea eax, [eax+edx] // current = randSeed1>>x + randSeed2>>x + mov edx, ditherPrevious + neg edx + lea edx, [eax+edx] // highpass = current - previous + mov highpassedDither, edx + mov ditherPrevious, eax // previous = current + mov eax, sourceByteStride // restore eax + fild highpassedDither + fmul const_float_dither_scale_ + // end generate dither, dither signal in st(0) + + faddp st(1), st(0) // stack: dither * value*(int scaler), int scaler + fistp word ptr [edi] // store scaled int into dest, stack: int scaler + jmp Float32_To_Int16_DitherClip_stored + + Float32_To_Int16_DitherClip_clamp: + mov edx, dword ptr [esi] // load floating point value into integer register + shr edx, 31 // move sign bit into bit 0 + add esi, eax // increment source ptr + //lea esi, [esi+eax] + add dx, 0x7FFF // convert to maximum range integers + mov word ptr [edi], dx // store clamped into into dest + + Float32_To_Int16_DitherClip_stored: + + add edi, ebx // increment destination ptr + //lea edi, [edi+ebx] + + cmp esi, ecx // has src ptr reached end? + jne Float32_To_Int16_DitherClip_loop + + ffree st(0) + fincstp + + fwait + fnclex + fldcw savedFpuControlWord + } + + ditherGenerator->previous = ditherPrevious; + ditherGenerator->randSeed1 = ditherRandSeed1; + ditherGenerator->randSeed2 = ditherRandSeed2; +} + +/* -------------------------------------------------------------------------- */ + +void PaUtil_InitializeX86PlainConverters( void ) +{ + paConverters.Float32_To_Int32 = Float32_To_Int32; + paConverters.Float32_To_Int32_Clip = Float32_To_Int32_Clip; + paConverters.Float32_To_Int32_DitherClip = Float32_To_Int32_DitherClip; + + paConverters.Float32_To_Int24 = Float32_To_Int24; + paConverters.Float32_To_Int24_Clip = Float32_To_Int24_Clip; + paConverters.Float32_To_Int24_DitherClip = Float32_To_Int24_DitherClip; + + paConverters.Float32_To_Int16 = Float32_To_Int16; + paConverters.Float32_To_Int16_Clip = Float32_To_Int16_Clip; + paConverters.Float32_To_Int16_DitherClip = Float32_To_Int16_DitherClip; +} + +#endif + +/* -------------------------------------------------------------------------- */ diff --git a/extern/portaudio/src/os/win/pa_x86_plain_converters.h b/extern/portaudio/src/os/win/pa_x86_plain_converters.h new file mode 100644 index 0000000..1623115 --- /dev/null +++ b/extern/portaudio/src/os/win/pa_x86_plain_converters.h @@ -0,0 +1,60 @@ +/* + * Plain Intel IA32 assembly implementations of PortAudio sample converter functions. + * Copyright (c) 1999-2002 Ross Bencina, Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +/** @file + @ingroup win_src +*/ + +#ifndef PA_X86_PLAIN_CONVERTERS_H +#define PA_X86_PLAIN_CONVERTERS_H + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + +/** + @brief Install optimized converter functions suitable for all IA32 processors + + It is recommended to call PaUtil_InitializeX86PlainConverters prior to calling Pa_Initialize +*/ +void PaUtil_InitializeX86PlainConverters( void ); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* PA_X86_PLAIN_CONVERTERS_H */ diff --git a/extern/portaudio/test/CMakeLists.txt b/extern/portaudio/test/CMakeLists.txt new file mode 100644 index 0000000..973568f --- /dev/null +++ b/extern/portaudio/test/CMakeLists.txt @@ -0,0 +1,13 @@ +# Test projects +# Use the macro to add test projects + +MACRO(ADD_TEST appl_name) + ADD_EXECUTABLE(${appl_name} "${appl_name}.c") + TARGET_LINK_LIBRARIES(${appl_name} portaudio_static) + SET_TARGET_PROPERTIES(${appl_name} + PROPERTIES + FOLDER "Test" + ) +ENDMACRO(ADD_TEST) + +ADD_TEST(patest_longsine) diff --git a/extern/portaudio/test/README.txt b/extern/portaudio/test/README.txt new file mode 100644 index 0000000..7cce15e --- /dev/null +++ b/extern/portaudio/test/README.txt @@ -0,0 +1,52 @@ +TODO - This should be moved into a doxydoc page. + +For more information on the TestPlan please visit: + + http://www.portaudio.com/trac/wiki/TestPlan + +This directory contains various programs to test PortAudio. The files +named patest_* are tests. + +All following tests are up to date with the V19 API. They should all compile +(without any warnings on GCC 3.3). Note that this does not necessarily mean that +the tests pass, just that they compile. + + x- paqa_devs.c + x- paqa_errs.c (needs reviewing) + x- patest1.c + x- patest_buffer.c + x- patest_callbackstop.c + x- patest_clip.c (last test fails, dither doesn't currently force clip in V19) + x- patest_dither.c + x- patest_hang.c + x- patest_latency.c + x- patest_leftright.c + x- patest_longsine.c + x- patest_many.c + x- patest_maxsines.c + x- patest_mono.c + x- patest_multi_sine.c + x- patest_pink.c + x- patest_prime.c + x- patest_read_record.c + x- patest_record.c + x- patest_ringmix.c + x- patest_saw.c + x- patest_sine.c + x- patest_sine8.c + x- patest_sine_formats.c + x- patest_sine_time.c + x- patest_start_stop.c + x- patest_stop.c + x- patest_sync.c + x- patest_toomanysines.c + x- patest_two_rates.c + x- patest_underflow.c + x- patest_wire.c + x- patest_write_sine.c + x- pa_devs.c + x- pa_fuzz.c + x- pa_minlat.c + +Note that Phil Burk deleted the debug_* tests on 2/26/11. They were just hacked +versions of old V18 tests. If we need to debug then we can just hack a working V19 test. diff --git a/extern/portaudio/test/pa_minlat.c b/extern/portaudio/test/pa_minlat.c new file mode 100644 index 0000000..0106cf3 --- /dev/null +++ b/extern/portaudio/test/pa_minlat.c @@ -0,0 +1,205 @@ +/** @file pa_minlat.c + @ingroup test_src + @brief Experiment with different numbers of buffers to determine the + minimum latency for a computer. + @author Phil Burk http://www.softsynth.com +*/ +/* + * $Id$ + * + * This program uses the PortAudio Portable Audio Library. + * For more information see: http://www.portaudio.com + * Copyright (c) 1999-2000 Ross Bencina and Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +#include +#include +#include +#include +#include "portaudio.h" + +#ifndef M_PI +#define M_PI (3.14159265) +#endif +#define TWOPI (M_PI * 2.0) + +#define DEFAULT_BUFFER_SIZE (32) + +typedef struct +{ + double left_phase; + double right_phase; +} +paTestData; + +/* Very simple synthesis routine to generate two sine waves. */ +static int paminlatCallback( const void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + const PaStreamCallbackTimeInfo* timeInfo, + PaStreamCallbackFlags statusFlags, + void *userData ) +{ + paTestData *data = (paTestData*)userData; + float *out = (float*)outputBuffer; + unsigned int i; + double left_phaseInc = 0.02; + double right_phaseInc = 0.06; + + double left_phase = data->left_phase; + double right_phase = data->right_phase; + + for( i=0; i TWOPI ) left_phase -= TWOPI; + *out++ = (float) sin( left_phase ); + + right_phase += right_phaseInc; + if( right_phase > TWOPI ) right_phase -= TWOPI; + *out++ = (float) sin( right_phase ); + } + + data->left_phase = left_phase; + data->right_phase = right_phase; + return 0; +} + +int main( int argc, char **argv ); +int main( int argc, char **argv ) +{ + PaStreamParameters outputParameters; + PaStream *stream; + PaError err; + paTestData data; + int go; + int outLatency = 0; + int minLatency = DEFAULT_BUFFER_SIZE * 2; + int framesPerBuffer; + double sampleRate = 44100.0; + char str[256]; + char *line; + + printf("pa_minlat - Determine minimum latency for your computer.\n"); + printf(" usage: pa_minlat {userBufferSize}\n"); + printf(" for example: pa_minlat 64\n"); + printf("Adjust your stereo until you hear a smooth tone in each speaker.\n"); + printf("Then try to find the smallest number of frames that still sounds smooth.\n"); + printf("Note that the sound will stop momentarily when you change the number of buffers.\n"); + + /* Get bufferSize from command line. */ + framesPerBuffer = ( argc > 1 ) ? atol( argv[1] ) : DEFAULT_BUFFER_SIZE; + printf("Frames per buffer = %d\n", framesPerBuffer ); + + data.left_phase = data.right_phase = 0.0; + + err = Pa_Initialize(); + if( err != paNoError ) goto error; + + outLatency = sampleRate * 200.0 / 1000.0; /* 200 msec. */ + + /* Try different numBuffers in a loop. */ + go = 1; + while( go ) + { + outputParameters.device = Pa_GetDefaultOutputDevice(); /* Default output device. */ + outputParameters.channelCount = 2; /* Stereo output */ + outputParameters.sampleFormat = paFloat32; /* 32 bit floating point output. */ + outputParameters.suggestedLatency = (double)outLatency / sampleRate; /* In seconds. */ + outputParameters.hostApiSpecificStreamInfo = NULL; + + printf("Latency = %d frames = %6.1f msec.\n", outLatency, outputParameters.suggestedLatency * 1000.0 ); + + err = Pa_OpenStream( + &stream, + NULL, /* no input */ + &outputParameters, + sampleRate, + framesPerBuffer, + paClipOff, /* we won't output out of range samples so don't bother clipping them */ + paminlatCallback, + &data ); + if( err != paNoError ) goto error; + if( stream == NULL ) goto error; + + /* Start audio. */ + err = Pa_StartStream( stream ); + if( err != paNoError ) goto error; + + /* Ask user for a new nlatency. */ + printf("\nMove windows around to see if the sound glitches.\n"); + printf("Latency now %d, enter new number of frames, or 'q' to quit: ", outLatency ); + line = fgets( str, 256, stdin ); + if( line == NULL ) + { + go = 0; + } + else + { + { + /* Get rid of newline */ + size_t l = strlen( str ) - 1; + if( str[ l ] == '\n') + str[ l ] = '\0'; + } + + + if( str[0] == 'q' ) go = 0; + else + { + outLatency = atol( str ); + if( outLatency < minLatency ) + { + printf( "Latency below minimum of %d! Set to minimum!!!\n", minLatency ); + outLatency = minLatency; + } + } + + } + /* Stop sound until ENTER hit. */ + err = Pa_StopStream( stream ); + if( err != paNoError ) goto error; + err = Pa_CloseStream( stream ); + if( err != paNoError ) goto error; + } + printf("A good setting for latency would be somewhat higher than\n"); + printf("the minimum latency that worked.\n"); + printf("PortAudio: Test finished.\n"); + Pa_Terminate(); + return 0; +error: + Pa_Terminate(); + fprintf( stderr, "An error occured while using the portaudio stream\n" ); + fprintf( stderr, "Error number: %d\n", err ); + fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); + return 1; +} diff --git a/extern/portaudio/test/patest1.c b/extern/portaudio/test/patest1.c new file mode 100644 index 0000000..a0fae47 --- /dev/null +++ b/extern/portaudio/test/patest1.c @@ -0,0 +1,208 @@ +/** @file patest1.c + @ingroup test_src + @brief Ring modulate the audio input with a sine wave for 20 seconds. + @author Ross Bencina +*/ +/* + * $Id$ + * + * This program uses the PortAudio Portable Audio Library. + * For more information see: http://www.portaudio.com + * Copyright (c) 1999-2000 Ross Bencina and Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +#include +#include +#include "portaudio.h" + +#ifndef M_PI +#define M_PI (3.14159265) +#endif + +#define SAMPLE_RATE (44100) + +typedef struct +{ + float sine[100]; + int phase; + int sampsToGo; +} +patest1data; + +static int patest1Callback( const void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + const PaStreamCallbackTimeInfo* timeInfo, + PaStreamCallbackFlags statusFlags, + void *userData ) +{ + patest1data *data = (patest1data*)userData; + float *in = (float*)inputBuffer; + float *out = (float*)outputBuffer; + int framesToCalc = framesPerBuffer; + unsigned long i = 0; + int finished; + + if( data->sampsToGo < framesPerBuffer ) + { + framesToCalc = data->sampsToGo; + finished = paComplete; + } + else + { + finished = paContinue; + } + + for( ; isine[data->phase]; /* left */ + *out++ = *in++ * data->sine[data->phase++]; /* right */ + if( data->phase >= 100 ) + data->phase = 0; + } + + data->sampsToGo -= framesToCalc; + + /* zero remainder of final buffer if not already done */ + for( ; idefaultLowInputLatency; + inputParameters.hostApiSpecificStreamInfo = NULL; + + outputParameters.device = Pa_GetDefaultOutputDevice(); /* default output device */ + if (outputParameters.device == paNoDevice) { + fprintf(stderr,"Error: No default output device.\n"); + goto done; + } + outputParameters.channelCount = 2; /* stereo output */ + outputParameters.sampleFormat = paFloat32; /* 32 bit floating point output */ + outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultLowOutputLatency; + outputParameters.hostApiSpecificStreamInfo = NULL; + + err = Pa_OpenStream( + &stream, + &inputParameters, + &outputParameters, + (double)SAMPLE_RATE, /* Samplerate in Hertz. */ + 512, /* Small buffers */ + paClipOff, /* We won't output out of range samples so don't bother clipping them. */ + patest1Callback, + &data ); + if( err != paNoError ) goto done; + + err = Pa_StartStream( stream ); + if( err != paNoError ) goto done; + + printf( "Press any key to end.\n" ); fflush(stdout); + + getc( stdin ); /* wait for input before exiting */ + + err = Pa_AbortStream( stream ); + if( err != paNoError ) goto done; + + printf( "Waiting for stream to complete...\n" ); + + /* sleep until playback has finished */ + while( ( err = Pa_IsStreamActive( stream ) ) == 1 ) Pa_Sleep(1000); + if( err < 0 ) goto done; + + err = Pa_CloseStream( stream ); + if( err != paNoError ) goto done; + +done: + Pa_Terminate(); + + if( err != paNoError ) + { + fprintf( stderr, "An error occured while using portaudio\n" ); + if( err == paUnanticipatedHostError ) + { + fprintf( stderr, " unanticipated host error.\n"); + herr = Pa_GetLastHostErrorInfo(); + if (herr) + { + fprintf( stderr, " Error number: %ld\n", herr->errorCode ); + if (herr->errorText) + fprintf( stderr, " Error text: %s\n", herr->errorText ); + } + else + fprintf( stderr, " Pa_GetLastHostErrorInfo() failed!\n" ); + } + else + { + fprintf( stderr, " Error number: %d\n", err ); + fprintf( stderr, " Error text: %s\n", Pa_GetErrorText( err ) ); + } + + err = 1; /* Always return 0 or 1, but no other return codes. */ + } + + printf( "bye\n" ); + + return err; +} diff --git a/extern/portaudio/test/patest_buffer.c b/extern/portaudio/test/patest_buffer.c new file mode 100644 index 0000000..830b3ac --- /dev/null +++ b/extern/portaudio/test/patest_buffer.c @@ -0,0 +1,206 @@ +/** @file patest_buffer.c + @ingroup test_src + @brief Test opening streams with different buffer sizes. + @author Phil Burk http://www.softsynth.com +*/ +/* + * $Id$ + * + * This program uses the PortAudio Portable Audio Library. + * For more information see: http://www.portaudio.com + * Copyright (c) 1999-2000 Ross Bencina and Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +#include +#include +#include +#include "portaudio.h" +#define NUM_SECONDS (3) +#define SAMPLE_RATE (44100) +#ifndef M_PI +#define M_PI (3.14159265) +#endif +#define TABLE_SIZE (200) + +#define BUFFER_TABLE 14 +long buffer_table[] = {paFramesPerBufferUnspecified,16,32,64,128,200,256,500,512,600,723,1000,1024,2345}; + +typedef struct +{ + short sine[TABLE_SIZE]; + int left_phase; + int right_phase; + unsigned int sampsToGo; +} +paTestData; +PaError TestOnce( int buffersize, PaDeviceIndex ); + +/* This routine will be called by the PortAudio engine when audio is needed. +** It may called at interrupt level on some machines so don't do anything +** that could mess up the system like calling malloc() or free(). +*/ +static int patest1Callback( const void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + const PaStreamCallbackTimeInfo* timeInfo, + PaStreamCallbackFlags statusFlags, + void *userData ) +{ + paTestData *data = (paTestData*)userData; + short *out = (short*)outputBuffer; + unsigned int i; + int finished = 0; + (void) inputBuffer; /* Prevent "unused variable" warnings. */ + + if( data->sampsToGo < framesPerBuffer ) + { + /* final buffer... */ + + for( i=0; isampsToGo; i++ ) + { + *out++ = data->sine[data->left_phase]; /* left */ + *out++ = data->sine[data->right_phase]; /* right */ + data->left_phase += 1; + if( data->left_phase >= TABLE_SIZE ) data->left_phase -= TABLE_SIZE; + data->right_phase += 3; /* higher pitch so we can distinguish left and right. */ + if( data->right_phase >= TABLE_SIZE ) data->right_phase -= TABLE_SIZE; + } + /* zero remainder of final buffer */ + for( ; isine[data->left_phase]; /* left */ + *out++ = data->sine[data->right_phase]; /* right */ + data->left_phase += 1; + if( data->left_phase >= TABLE_SIZE ) data->left_phase -= TABLE_SIZE; + data->right_phase += 3; /* higher pitch so we can distinguish left and right. */ + if( data->right_phase >= TABLE_SIZE ) data->right_phase -= TABLE_SIZE; + } + data->sampsToGo -= framesPerBuffer; + } + return finished; +} + +/*******************************************************************/ +int main(int argc, char **args); +int main(int argc, char **args) +{ + int i; + int device = -1; + PaError err; + printf("Test opening streams with different buffer sizes\n"); + if( argc > 1 ) { + device=atoi( args[1] ); + printf("Using device number %d.\n\n", device ); + } else { + printf("Using default device.\n\n" ); + } + + for (i = 0 ; i < BUFFER_TABLE; i++) + { + printf("Buffer size %ld\n", buffer_table[i]); + err = TestOnce(buffer_table[i], device); + if( err < 0 ) return 0; + + } + return 0; +} + + +PaError TestOnce( int buffersize, PaDeviceIndex device ) +{ + PaStreamParameters outputParameters; + PaStream *stream; + PaError err; + paTestData data; + int i; + int totalSamps; + /* initialise sinusoidal wavetable */ + for( i=0; idefaultLowOutputLatency; + outputParameters.hostApiSpecificStreamInfo = NULL; + err = Pa_OpenStream( + &stream, + NULL, /* no input */ + &outputParameters, + SAMPLE_RATE, + buffersize, /* frames per buffer */ + (paClipOff | paDitherOff), + patest1Callback, + &data ); + if( err != paNoError ) goto error; + + err = Pa_StartStream( stream ); + if( err != paNoError ) goto error; + printf("Waiting for sound to finish.\n"); + Pa_Sleep(1000*NUM_SECONDS); + err = Pa_CloseStream( stream ); + if( err != paNoError ) goto error; + Pa_Terminate(); + return paNoError; +error: + Pa_Terminate(); + fprintf( stderr, "An error occured while using the portaudio stream\n" ); + fprintf( stderr, "Error number: %d\n", err ); + fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); + fprintf( stderr, "Host Error message: %s\n", Pa_GetLastHostErrorInfo()->errorText ); + return err; +} diff --git a/extern/portaudio/test/patest_callbackstop.c b/extern/portaudio/test/patest_callbackstop.c new file mode 100644 index 0000000..bd6e829 --- /dev/null +++ b/extern/portaudio/test/patest_callbackstop.c @@ -0,0 +1,252 @@ +/** @file patest_callbackstop.c + @ingroup test_src + @brief Test the paComplete callback result code. + @author Ross Bencina +*/ +/* + * $Id$ + * + * This program uses the PortAudio Portable Audio Library. + * For more information see: http://www.portaudio.com/ + * Copyright (c) 1999-2000 Ross Bencina and Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +#include +#include +#include "portaudio.h" + +#define NUM_SECONDS (5) +#define NUM_LOOPS (4) +#define SAMPLE_RATE (44100) +#define FRAMES_PER_BUFFER (67) + +#ifndef M_PI +#define M_PI (3.14159265) +#endif + +#define TABLE_SIZE (200) +typedef struct +{ + float sine[TABLE_SIZE]; + int phase; + unsigned long generatedFramesCount; + volatile int callbackReturnedPaComplete; + volatile int callbackInvokedAfterReturningPaComplete; + char message[100]; +} +TestData; + +/* + This routine will be called by the PortAudio stream when audio is needed. + It may be called at interrupt level on some machines so don't do anything + that could mess up the system like calling malloc() or free(). +*/ +static int TestCallback( const void *input, void *output, + unsigned long frameCount, + const PaStreamCallbackTimeInfo* timeInfo, + PaStreamCallbackFlags statusFlags, + void *userData ) +{ + TestData *data = (TestData*)userData; + float *out = (float*)output; + unsigned long i; + float x; + + (void) input; /* Prevent unused variable warnings. */ + (void) timeInfo; + (void) statusFlags; + + + if( data->callbackReturnedPaComplete ) + data->callbackInvokedAfterReturningPaComplete = 1; + + for( i=0; isine[ data->phase++ ]; + if( data->phase >= TABLE_SIZE ) + data->phase -= TABLE_SIZE; + + *out++ = x; /* left */ + *out++ = x; /* right */ + } + + data->generatedFramesCount += frameCount; + if( data->generatedFramesCount >= (NUM_SECONDS * SAMPLE_RATE) ) + { + data->callbackReturnedPaComplete = 1; + return paComplete; + } + else + { + return paContinue; + } +} + +/* + * This routine is called by portaudio when playback is done. + */ +static void StreamFinished( void* userData ) +{ + TestData *data = (TestData *) userData; + printf( "Stream Completed: %s\n", data->message ); +} + + +/*----------------------------------------------------------------------------*/ +int main(void); +int main(void) +{ + PaStreamParameters outputParameters; + PaStream *stream; + PaError err; + TestData data; + int i, j; + + + printf( "PortAudio Test: output sine wave. SR = %d, BufSize = %d\n", + SAMPLE_RATE, FRAMES_PER_BUFFER ); + + /* initialise sinusoidal wavetable */ + for( i=0; idefaultLowOutputLatency; + outputParameters.hostApiSpecificStreamInfo = NULL; + + err = Pa_OpenStream( + &stream, + NULL, /* no input */ + &outputParameters, + SAMPLE_RATE, + FRAMES_PER_BUFFER, + paClipOff, /* output will be in-range, so no need to clip */ + TestCallback, + &data ); + if( err != paNoError ) goto error; + + sprintf( data.message, "Loop: XX" ); + err = Pa_SetStreamFinishedCallback( stream, &StreamFinished ); + if( err != paNoError ) goto error; + + printf("Repeating test %d times.\n", NUM_LOOPS ); + + for( i=0; i < NUM_LOOPS; ++i ) + { + data.phase = 0; + data.generatedFramesCount = 0; + data.callbackReturnedPaComplete = 0; + data.callbackInvokedAfterReturningPaComplete = 0; + sprintf( data.message, "Loop: %d", i ); + + err = Pa_StartStream( stream ); + if( err != paNoError ) goto error; + + printf("Play for %d seconds.\n", NUM_SECONDS ); + + /* wait for the callback to complete generating NUM_SECONDS of tone */ + + do + { + Pa_Sleep( 500 ); + } + while( !data.callbackReturnedPaComplete ); + + printf( "Callback returned paComplete.\n" ); + printf( "Waiting for buffers to finish playing...\n" ); + + /* wait for stream to become inactive, + or for a timeout of approximately NUM_SECONDS + */ + + j = 0; + while( (err = Pa_IsStreamActive( stream )) == 1 && j < NUM_SECONDS * 2 ) + { + printf(".\n" ); + Pa_Sleep( 500 ); + ++j; + } + + if( err < 0 ) + { + goto error; + } + else if( err == 1 ) + { + printf( "TEST FAILED: Timed out waiting for buffers to finish playing.\n" ); + } + else + { + printf("Buffers finished.\n" ); + } + + if( data.callbackInvokedAfterReturningPaComplete ) + { + printf( "TEST FAILED: Callback was invoked after returning paComplete.\n" ); + } + + + err = Pa_StopStream( stream ); + if( err != paNoError ) goto error; + + printf( "sleeping for 1 second...\n" ); + Pa_Sleep( 1000 ); + } + + err = Pa_CloseStream( stream ); + if( err != paNoError ) goto error; + + Pa_Terminate(); + printf("Test finished.\n"); + + return err; +error: + Pa_Terminate(); + fprintf( stderr, "An error occured while using the portaudio stream\n" ); + fprintf( stderr, "Error number: %d\n", err ); + fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); + return err; +} diff --git a/extern/portaudio/test/patest_clip.c b/extern/portaudio/test/patest_clip.c new file mode 100644 index 0000000..e86d0ac --- /dev/null +++ b/extern/portaudio/test/patest_clip.c @@ -0,0 +1,190 @@ +/** @file patest_clip.c + @ingroup test_src + @brief Play a sine wave for several seconds at an amplitude + that would require clipping. + + @author Phil Burk http://www.softsynth.com +*/ +/* + * $Id$ + * + * This program uses the PortAudio Portable Audio Library. + * For more information see: http://www.portaudio.com + * Copyright (c) 1999-2000 Ross Bencina and Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +#include +#include +#include "portaudio.h" + +#define NUM_SECONDS (4) +#define SAMPLE_RATE (44100) +#ifndef M_PI +#define M_PI (3.14159265) +#endif +#define TABLE_SIZE (200) + +typedef struct paTestData +{ + float sine[TABLE_SIZE]; + float amplitude; + int left_phase; + int right_phase; +} +paTestData; + +PaError PlaySine( paTestData *data, unsigned long flags, float amplitude ); + +/* This routine will be called by the PortAudio engine when audio is needed. +** It may called at interrupt level on some machines so don't do anything +** that could mess up the system like calling malloc() or free(). +*/ +static int sineCallback( const void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + const PaStreamCallbackTimeInfo* timeInfo, + PaStreamCallbackFlags statusFlags, + void *userData ) +{ + paTestData *data = (paTestData*)userData; + float *out = (float*)outputBuffer; + float amplitude = data->amplitude; + unsigned int i; + (void) inputBuffer; /* Prevent "unused variable" warnings. */ + (void) timeInfo; + (void) statusFlags; + + for( i=0; isine[data->left_phase]; /* left */ + *out++ = amplitude * data->sine[data->right_phase]; /* right */ + data->left_phase += 1; + if( data->left_phase >= TABLE_SIZE ) data->left_phase -= TABLE_SIZE; + data->right_phase += 3; /* higher pitch so we can distinguish left and right. */ + if( data->right_phase >= TABLE_SIZE ) data->right_phase -= TABLE_SIZE; + } + return 0; +} +/*******************************************************************/ +int main(void); +int main(void) +{ + PaError err; + paTestData data; + int i; + + printf("PortAudio Test: output sine wave with and without clipping.\n"); + /* initialise sinusoidal wavetable */ + for( i=0; ileft_phase = data->right_phase = 0; + data->amplitude = amplitude; + + err = Pa_Initialize(); + if( err != paNoError ) goto error; + + outputParameters.device = Pa_GetDefaultOutputDevice(); /* default output device */ + if (outputParameters.device == paNoDevice) { + fprintf(stderr,"Error: No default output device.\n"); + goto error; + } + outputParameters.channelCount = 2; /* stereo output */ + outputParameters.sampleFormat = paFloat32; /* 32 bit floating point output */ + outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultLowOutputLatency; + outputParameters.hostApiSpecificStreamInfo = NULL; + + err = Pa_OpenStream( + &stream, + NULL, /* no input */ + &outputParameters, + SAMPLE_RATE, + 1024, + flags, + sineCallback, + data ); + if( err != paNoError ) goto error; + + err = Pa_StartStream( stream ); + if( err != paNoError ) goto error; + + Pa_Sleep( NUM_SECONDS * 1000 ); + printf("CPULoad = %8.6f\n", Pa_GetStreamCpuLoad( stream ) ); + + err = Pa_CloseStream( stream ); + if( err != paNoError ) goto error; + + Pa_Terminate(); + return paNoError; +error: + return err; +} diff --git a/extern/portaudio/test/patest_converters.c b/extern/portaudio/test/patest_converters.c new file mode 100644 index 0000000..1474a71 --- /dev/null +++ b/extern/portaudio/test/patest_converters.c @@ -0,0 +1,395 @@ +/** @file patest_converters.c + @ingroup test_src + @brief Tests the converter functions in pa_converters.c + @author Ross Bencina + + Link with pa_dither.c and pa_converters.c + + see http://www.portaudio.com/trac/wiki/V19ConvertersStatus for a discussion of this. +*/ +/* + * $Id: $ + * + * This program uses the PortAudio Portable Audio Library. + * For more information see: http://www.portaudio.com/ + * Copyright (c) 1999-2008 Ross Bencina and Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ +#include +#include +#include +#include + +#include "portaudio.h" +#include "pa_converters.h" +#include "pa_dither.h" +#include "pa_types.h" +#include "pa_endianness.h" + +#ifndef M_PI +#define M_PI (3.14159265) +#endif + +#define MAX_PER_CHANNEL_FRAME_COUNT (2048) +#define MAX_CHANNEL_COUNT (8) + + +#define SAMPLE_FORMAT_COUNT (6) + +static PaSampleFormat sampleFormats_[ SAMPLE_FORMAT_COUNT ] = + { paFloat32, paInt32, paInt24, paInt16, paInt8, paUInt8 }; /* all standard PA sample formats */ + +static const char* sampleFormatNames_[SAMPLE_FORMAT_COUNT] = + { "paFloat32", "paInt32", "paInt24", "paInt16", "paInt8", "paUInt8" }; + + +static const char* abbreviatedSampleFormatNames_[SAMPLE_FORMAT_COUNT] = + { "f32", "i32", "i24", "i16", " i8", "ui8" }; + + +PaError My_Pa_GetSampleSize( PaSampleFormat format ); + +/* + available flags are paClipOff and paDitherOff + clipping is usually applied for float -> int conversions + dither is usually applied for all downconversions (ie anything but 8bit->8bit conversions +*/ + +static int CanClip( PaSampleFormat sourceFormat, PaSampleFormat destinationFormat ) +{ + if( sourceFormat == paFloat32 && destinationFormat != sourceFormat ) + return 1; + else + return 0; +} + +static int CanDither( PaSampleFormat sourceFormat, PaSampleFormat destinationFormat ) +{ + if( sourceFormat < destinationFormat && sourceFormat != paInt8 ) + return 1; + else + return 0; +} + +static void GenerateOneCycleSineReference( double *out, int frameCount, int strideFrames ) +{ + int i; + for( i=0; i < frameCount; ++i ){ + *out = sin( ((double)i/(double)frameCount) * 2. * M_PI ); + out += strideFrames; + } +} + + +static void GenerateOneCycleSine( PaSampleFormat format, void *buffer, int frameCount, int strideFrames ) +{ + switch( format ){ + + case paFloat32: + { + int i; + float *out = (float*)buffer; + for( i=0; i < frameCount; ++i ){ + *out = (float).9 * sin( ((double)i/(double)frameCount) * 2. * M_PI ); + out += strideFrames; + } + } + break; + case paInt32: + { + int i; + PaInt32 *out = (PaInt32*)buffer; + for( i=0; i < frameCount; ++i ){ + *out = (PaInt32)(.9 * sin( ((double)i/(double)frameCount) * 2. * M_PI ) * 0x7FFFFFFF); + out += strideFrames; + } + } + break; + case paInt24: + { + int i; + unsigned char *out = (unsigned char*)buffer; + for( i=0; i < frameCount; ++i ){ + signed long temp = (PaInt32)(.9 * sin( ((double)i/(double)frameCount) * 2. * M_PI ) * 0x7FFFFFFF); + + #if defined(PA_LITTLE_ENDIAN) + out[0] = (unsigned char)(temp >> 8) & 0xFF; + out[1] = (unsigned char)(temp >> 16) & 0xFF; + out[2] = (unsigned char)(temp >> 24) & 0xFF; + #elif defined(PA_BIG_ENDIAN) + out[0] = (unsigned char)(temp >> 24) & 0xFF; + out[1] = (unsigned char)(temp >> 16) & 0xFF; + out[2] = (unsigned char)(temp >> 8) & 0xFF; + #endif + out += 3; + } + } + break; + case paInt16: + { + int i; + PaInt16 *out = (PaInt16*)buffer; + for( i=0; i < frameCount; ++i ){ + *out = (PaInt16)(.9 * sin( ((double)i/(double)frameCount) * 2. * M_PI ) * 0x7FFF ); + out += strideFrames; + } + } + break; + case paInt8: + { + int i; + signed char *out = (signed char*)buffer; + for( i=0; i < frameCount; ++i ){ + *out = (signed char)(.9 * sin( ((double)i/(double)frameCount) * 2. * M_PI ) * 0x7F ); + out += strideFrames; + } + } + break; + case paUInt8: + { + int i; + unsigned char *out = (unsigned char*)buffer; + for( i=0; i < frameCount; ++i ){ + *out = (unsigned char)( .5 * (1. + (.9 * sin( ((double)i/(double)frameCount) * 2. * M_PI ))) * 0xFF ); + out += strideFrames; + } + } + break; + } +} + +int TestNonZeroPresent( void *buffer, int size ) +{ + char *p = (char*)buffer; + int i; + + for( i=0; i < size; ++i ){ + + if( *p != 0 ) + return 1; + ++p; + } + + return 0; +} + +float MaximumAbsDifference( float* sourceBuffer, float* referenceBuffer, int count ) +{ + float result = 0; + float difference; + while( count-- ){ + difference = fabs( *sourceBuffer++ - *referenceBuffer++ ); + if( difference > result ) + result = difference; + } + + return result; +} + +int main( const char **argv, int argc ) +{ + PaUtilTriangularDitherGenerator ditherState; + PaUtilConverter *converter; + void *destinationBuffer, *sourceBuffer; + double *referenceBuffer; + int sourceFormatIndex, destinationFormatIndex; + PaSampleFormat sourceFormat, destinationFormat; + PaStreamFlags flags; + int passFailMatrix[SAMPLE_FORMAT_COUNT][SAMPLE_FORMAT_COUNT]; // [source][destination] + float noiseAmplitudeMatrix[SAMPLE_FORMAT_COUNT][SAMPLE_FORMAT_COUNT]; // [source][destination] + float amp; + +#define FLAG_COMBINATION_COUNT (4) + PaStreamFlags flagCombinations[FLAG_COMBINATION_COUNT] = { paNoFlag, paClipOff, paDitherOff, paClipOff | paDitherOff }; + const char *flagCombinationNames[FLAG_COMBINATION_COUNT] = { "paNoFlag", "paClipOff", "paDitherOff", "paClipOff | paDitherOff" }; + int flagCombinationIndex; + + PaUtil_InitializeTriangularDitherState( &ditherState ); + + /* allocate more than enough space, we use sizeof(float) but we need to fit any 32 bit datum */ + + destinationBuffer = (void*)malloc( MAX_PER_CHANNEL_FRAME_COUNT * MAX_CHANNEL_COUNT * sizeof(float) ); + sourceBuffer = (void*)malloc( MAX_PER_CHANNEL_FRAME_COUNT * MAX_CHANNEL_COUNT * sizeof(float) ); + referenceBuffer = (void*)malloc( MAX_PER_CHANNEL_FRAME_COUNT * MAX_CHANNEL_COUNT * sizeof(float) ); + + + /* the first round of tests simply iterates through the buffer combinations testing + that putting something in gives something out */ + + printf( "= Sine wave in, something out =\n" ); + + printf( "\n" ); + + GenerateOneCycleSine( paFloat32, referenceBuffer, MAX_PER_CHANNEL_FRAME_COUNT, 1 ); + + for( flagCombinationIndex = 0; flagCombinationIndex < FLAG_COMBINATION_COUNT; ++flagCombinationIndex ){ + flags = flagCombinations[flagCombinationIndex]; + + printf( "\n" ); + printf( "== flags = %s ==\n", flagCombinationNames[flagCombinationIndex] ); + + for( sourceFormatIndex = 0; sourceFormatIndex < SAMPLE_FORMAT_COUNT; ++sourceFormatIndex ){ + for( destinationFormatIndex = 0; destinationFormatIndex < SAMPLE_FORMAT_COUNT; ++destinationFormatIndex ){ + sourceFormat = sampleFormats_[sourceFormatIndex]; + destinationFormat = sampleFormats_[destinationFormatIndex]; + //printf( "%s -> %s ", sampleFormatNames_[ sourceFormatIndex ], sampleFormatNames_[ destinationFormatIndex ] ); + + converter = PaUtil_SelectConverter( sourceFormat, destinationFormat, flags ); + + /* source is a sinewave */ + GenerateOneCycleSine( sourceFormat, sourceBuffer, MAX_PER_CHANNEL_FRAME_COUNT, 1 ); + + /* zero destination */ + memset( destinationBuffer, 0, MAX_PER_CHANNEL_FRAME_COUNT * My_Pa_GetSampleSize( destinationFormat ) ); + + (*converter)( destinationBuffer, 1, sourceBuffer, 1, MAX_PER_CHANNEL_FRAME_COUNT, &ditherState ); + + /* + Other ways we could test this would be: + - pass a constant, check for a constant (wouldn't work with dither) + - pass alternating +/-, check for the same... + */ + if( TestNonZeroPresent( destinationBuffer, MAX_PER_CHANNEL_FRAME_COUNT * My_Pa_GetSampleSize( destinationFormat ) ) ){ + //printf( "PASSED\n" ); + passFailMatrix[sourceFormatIndex][destinationFormatIndex] = 1; + }else{ + //printf( "FAILED\n" ); + passFailMatrix[sourceFormatIndex][destinationFormatIndex] = 0; + } + + + /* try to measure the noise floor (comparing output signal to a float32 sine wave) */ + + if( passFailMatrix[sourceFormatIndex][destinationFormatIndex] ){ + + /* convert destination back to paFloat32 into source */ + converter = PaUtil_SelectConverter( destinationFormat, paFloat32, paNoFlag ); + + memset( sourceBuffer, 0, MAX_PER_CHANNEL_FRAME_COUNT * My_Pa_GetSampleSize( paFloat32 ) ); + (*converter)( sourceBuffer, 1, destinationBuffer, 1, MAX_PER_CHANNEL_FRAME_COUNT, &ditherState ); + + if( TestNonZeroPresent( sourceBuffer, MAX_PER_CHANNEL_FRAME_COUNT * My_Pa_GetSampleSize( paFloat32 ) ) ){ + + noiseAmplitudeMatrix[sourceFormatIndex][destinationFormatIndex] = MaximumAbsDifference( (float*)sourceBuffer, (float*)referenceBuffer, MAX_PER_CHANNEL_FRAME_COUNT ); + + }else{ + /* can't test noise floor because there is no conversion from dest format to float available */ + noiseAmplitudeMatrix[sourceFormatIndex][destinationFormatIndex] = -1; // mark as failed + } + }else{ + noiseAmplitudeMatrix[sourceFormatIndex][destinationFormatIndex] = -1; // mark as failed + } + } + } + + printf( "\n" ); + printf( "=== Output contains non-zero data ===\n" ); + printf( "Key: . - pass, X - fail\n" ); + printf( "{{{\n" ); // trac preformated text tag + printf( "in| out: " ); + for( destinationFormatIndex = 0; destinationFormatIndex < SAMPLE_FORMAT_COUNT; ++destinationFormatIndex ){ + printf( " %s ", abbreviatedSampleFormatNames_[destinationFormatIndex] ); + } + printf( "\n" ); + + for( sourceFormatIndex = 0; sourceFormatIndex < SAMPLE_FORMAT_COUNT; ++sourceFormatIndex ){ + printf( "%s ", abbreviatedSampleFormatNames_[sourceFormatIndex] ); + for( destinationFormatIndex = 0; destinationFormatIndex < SAMPLE_FORMAT_COUNT; ++destinationFormatIndex ){ + printf( " %s ", (passFailMatrix[sourceFormatIndex][destinationFormatIndex])? " ." : " X" ); + } + printf( "\n" ); + } + printf( "}}}\n" ); // trac preformated text tag + + printf( "\n" ); + printf( "=== Combined dynamic range (src->dest->float32) ===\n" ); + printf( "Key: Noise amplitude in dBfs, X - fail (either above failed or dest->float32 failed)\n" ); + printf( "{{{\n" ); // trac preformated text tag + printf( "in| out: " ); + for( destinationFormatIndex = 0; destinationFormatIndex < SAMPLE_FORMAT_COUNT; ++destinationFormatIndex ){ + printf( " %s ", abbreviatedSampleFormatNames_[destinationFormatIndex] ); + } + printf( "\n" ); + + for( sourceFormatIndex = 0; sourceFormatIndex < SAMPLE_FORMAT_COUNT; ++sourceFormatIndex ){ + printf( " %s ", abbreviatedSampleFormatNames_[sourceFormatIndex] ); + for( destinationFormatIndex = 0; destinationFormatIndex < SAMPLE_FORMAT_COUNT; ++destinationFormatIndex ){ + amp = noiseAmplitudeMatrix[sourceFormatIndex][destinationFormatIndex]; + if( amp < 0. ) + printf( " X " ); + else + printf( " % 6.1f ", 20.*log10(amp) ); + } + printf( "\n" ); + } + printf( "}}}\n" ); // trac preformated text tag + } + + + free( destinationBuffer ); + free( sourceBuffer ); + free( referenceBuffer ); +} + +// copied here for now otherwise we need to include the world just for this function. +PaError My_Pa_GetSampleSize( PaSampleFormat format ) +{ + int result; + + switch( format & ~paNonInterleaved ) + { + + case paUInt8: + case paInt8: + result = 1; + break; + + case paInt16: + result = 2; + break; + + case paInt24: + result = 3; + break; + + case paFloat32: + case paInt32: + result = 4; + break; + + default: + result = paSampleFormatNotSupported; + break; + } + + return (PaError) result; +} diff --git a/extern/portaudio/test/patest_dither.c b/extern/portaudio/test/patest_dither.c new file mode 100644 index 0000000..e694c8b --- /dev/null +++ b/extern/portaudio/test/patest_dither.c @@ -0,0 +1,190 @@ +/** @file patest_dither.c + @ingroup test_src + @brief Attempt to hear difference between dithered and non-dithered signal. + + This only has an effect if the native format is 16 bit. + + @author Phil Burk http://www.softsynth.com +*/ +/* + * $Id$ + * + * This program uses the PortAudio Portable Audio Library. + * For more information see: http://www.portaudio.com + * Copyright (c) 1999-2000 Ross Bencina and Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +#include +#include + +#include "portaudio.h" + +#define NUM_SECONDS (5) +#define SAMPLE_RATE (44100) +#ifndef M_PI +#define M_PI (3.14159265) +#endif +#define TABLE_SIZE (200) + +typedef struct paTestData +{ + float sine[TABLE_SIZE]; + float amplitude; + int left_phase; + int right_phase; +} +paTestData; + +/* This routine will be called by the PortAudio engine when audio is needed. +** It may called at interrupt level on some machines so don't do anything +** that could mess up the system like calling malloc() or free(). +*/ +static int sineCallback( const void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + const PaStreamCallbackTimeInfo *timeInfo, + PaStreamCallbackFlags statusFlags, void *userData ) +{ + paTestData *data = (paTestData*)userData; + float *out = (float*)outputBuffer; + float amplitude = data->amplitude; + unsigned int i; + (void) inputBuffer; + + for( i=0; isine[data->left_phase]; /* left */ + *out++ = amplitude * data->sine[data->right_phase]; /* right */ + data->left_phase += 1; + if( data->left_phase >= TABLE_SIZE ) data->left_phase -= TABLE_SIZE; + data->right_phase += 3; /* higher pitch so we can distinguish left and right. */ + if( data->right_phase >= TABLE_SIZE ) data->right_phase -= TABLE_SIZE; + } + return 0; +} + +/*****************************************************************************/ +/* + V18 version did not call Pa_Terminate() if Pa_Initialize() failed. + This V19 version ALWAYS calls Pa_Terminate(). PS. +*/ +PaError PlaySine( paTestData *data, PaStreamFlags flags, float amplitude ); +PaError PlaySine( paTestData *data, PaStreamFlags flags, float amplitude ) +{ + PaStream* stream; + PaStreamParameters outputParameters; + PaError err; + + data->left_phase = data->right_phase = 0; + data->amplitude = amplitude; + + err = Pa_Initialize(); + if (err != paNoError) + goto done; + + outputParameters.device = Pa_GetDefaultOutputDevice(); /* default output device */ + if (outputParameters.device == paNoDevice) { + fprintf(stderr,"Error: No default output device.\n"); + goto done; + } + outputParameters.channelCount = 2; /* stereo output */ + outputParameters.hostApiSpecificStreamInfo = NULL; + outputParameters.sampleFormat = paFloat32; /* 32 bit floating point output. */ + /* When you change this, also */ + /* adapt the callback routine! */ + outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device ) + ->defaultLowOutputLatency; /* Low latency. */ + err = Pa_OpenStream( &stream, + NULL, /* No input. */ + &outputParameters, + SAMPLE_RATE, + 1024, /* frames per buffer */ + flags, + sineCallback, + (void*)data ); + if (err != paNoError) + goto done; + + err = Pa_StartStream( stream ); + if (err != paNoError) + goto done; + + Pa_Sleep( NUM_SECONDS * 1000 ); + printf("CPULoad = %8.6f\n", Pa_GetStreamCpuLoad(stream)); + + err = Pa_CloseStream( stream ); +done: + Pa_Sleep( 250 ); /* Just a small silence. */ + Pa_Terminate(); + return err; +} + + +/*******************************************************************/ +int main(void); +int main(void) +{ + PaError err; + paTestData DATA; + int i; + float amplitude = 4.0 / (1<<15); + + printf("PortAudio Test: output EXTREMELY QUIET sine wave with and without dithering.\n"); + /* initialise sinusoidal wavetable */ + for( i=0; i +#include +#include + +#define _WIN32_WINNT 0x0501 /* for GetNativeSystemInfo */ +#include +//#include /* required when using pa_win_wmme.h */ + +#include /* for _getch */ + + +#include "portaudio.h" +#include "pa_win_ds.h" + + +#define DEFAULT_SAMPLE_RATE (44100.) + +#ifndef M_PI +#define M_PI (3.14159265) +#endif + +#define TABLE_SIZE (2048) + +#define CHANNEL_COUNT (2) + + +/*******************************************************************/ +/* functions to query and print Windows version information */ + +typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL); + +LPFN_ISWOW64PROCESS fnIsWow64Process; + +static BOOL IsWow64() +{ + BOOL bIsWow64 = FALSE; + + //IsWow64Process is not available on all supported versions of Windows. + //Use GetModuleHandle to get a handle to the DLL that contains the function + //and GetProcAddress to get a pointer to the function if available. + + fnIsWow64Process = (LPFN_ISWOW64PROCESS) GetProcAddress( + GetModuleHandle(TEXT("kernel32")),"IsWow64Process" ); + + if(NULL != fnIsWow64Process) + { + if (!fnIsWow64Process(GetCurrentProcess(),&bIsWow64)) + { + //handle error + } + } + return bIsWow64; +} + +static void printWindowsVersionInfo( FILE *fp ) +{ + OSVERSIONINFOEX osVersionInfoEx; + SYSTEM_INFO systemInfo; + const char *osName = "Unknown"; + const char *osProductType = ""; + const char *processorArchitecture = "Unknown"; + + memset( &osVersionInfoEx, 0, sizeof(OSVERSIONINFOEX) ); + osVersionInfoEx.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); + GetVersionEx( &osVersionInfoEx ); + + + if( osVersionInfoEx.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS ){ + switch( osVersionInfoEx.dwMinorVersion ){ + case 0: osName = "Windows 95"; break; + case 10: osName = "Windows 98"; break; // could also be 98SE (I've seen code discriminate based + // on osInfo.Version.Revision.ToString() == "2222A") + case 90: osName = "Windows Me"; break; + } + }else if( osVersionInfoEx.dwPlatformId == VER_PLATFORM_WIN32_NT ){ + switch( osVersionInfoEx.dwMajorVersion ){ + case 3: osName = "Windows NT 3.51"; break; + case 4: osName = "Windows NT 4.0"; break; + case 5: switch( osVersionInfoEx.dwMinorVersion ){ + case 0: osName = "Windows 2000"; break; + case 1: osName = "Windows XP"; break; + case 2: + if( osVersionInfoEx.wSuiteMask & 0x00008000 /*VER_SUITE_WH_SERVER*/ ){ + osName = "Windows Home Server"; + }else{ + if( osVersionInfoEx.wProductType == VER_NT_WORKSTATION ){ + osName = "Windows XP Professional x64 Edition (?)"; + }else{ + if( GetSystemMetrics(/*SM_SERVERR2*/89) == 0 ) + osName = "Windows Server 2003"; + else + osName = "Windows Server 2003 R2"; + } + }break; + }break; + case 6:switch( osVersionInfoEx.dwMinorVersion ){ + case 0: + if( osVersionInfoEx.wProductType == VER_NT_WORKSTATION ) + osName = "Windows Vista"; + else + osName = "Windows Server 2008"; + break; + case 1: + if( osVersionInfoEx.wProductType == VER_NT_WORKSTATION ) + osName = "Windows 7"; + else + osName = "Windows Server 2008 R2"; + break; + }break; + } + } + + if(osVersionInfoEx.dwMajorVersion == 4) + { + if(osVersionInfoEx.wProductType == VER_NT_WORKSTATION) + osProductType = "Workstation"; + else if(osVersionInfoEx.wProductType == VER_NT_SERVER) + osProductType = "Server"; + } + else if(osVersionInfoEx.dwMajorVersion == 5) + { + if(osVersionInfoEx.wProductType == VER_NT_WORKSTATION) + { + if((osVersionInfoEx.wSuiteMask & VER_SUITE_PERSONAL) == VER_SUITE_PERSONAL) + osProductType = "Home Edition"; // Windows XP Home Edition + else + osProductType = "Professional"; // Windows XP / Windows 2000 Professional + } + else if(osVersionInfoEx.wProductType == VER_NT_SERVER) + { + if(osVersionInfoEx.dwMinorVersion == 0) + { + if((osVersionInfoEx.wSuiteMask & VER_SUITE_DATACENTER) == VER_SUITE_DATACENTER) + osProductType = "Datacenter Server"; // Windows 2000 Datacenter Server + else if((osVersionInfoEx.wSuiteMask & VER_SUITE_ENTERPRISE) == VER_SUITE_ENTERPRISE) + osProductType = "Advanced Server"; // Windows 2000 Advanced Server + else + osProductType = "Server"; // Windows 2000 Server + } + } + else + { + if((osVersionInfoEx.wSuiteMask & VER_SUITE_DATACENTER) == VER_SUITE_DATACENTER) + osProductType = "Datacenter Edition"; // Windows Server 2003 Datacenter Edition + else if((osVersionInfoEx.wSuiteMask & VER_SUITE_ENTERPRISE) == VER_SUITE_ENTERPRISE) + osProductType = "Enterprise Edition"; // Windows Server 2003 Enterprise Edition + else if((osVersionInfoEx.wSuiteMask & VER_SUITE_BLADE) == VER_SUITE_BLADE) + osProductType = "Web Edition"; // Windows Server 2003 Web Edition + else + osProductType = "Standard Edition"; // Windows Server 2003 Standard Edition + } + } + + memset( &systemInfo, 0, sizeof(SYSTEM_INFO) ); + GetNativeSystemInfo( &systemInfo ); + + if( systemInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL ) + processorArchitecture = "x86"; + else if( systemInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64 ) + processorArchitecture = "x64"; + else if( systemInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_IA64 ) + processorArchitecture = "Itanium"; + + + fprintf( fp, "OS name and edition: %s %s\n", osName, osProductType ); + fprintf( fp, "OS version: %d.%d.%d %S\n", + osVersionInfoEx.dwMajorVersion, osVersionInfoEx.dwMinorVersion, + osVersionInfoEx.dwBuildNumber, osVersionInfoEx.szCSDVersion ); + fprintf( fp, "Processor architecture: %s\n", processorArchitecture ); + fprintf( fp, "WoW64 process: %s\n", IsWow64() ? "Yes" : "No" ); +} + +static void printTimeAndDate( FILE *fp ) +{ + struct tm *local; + time_t t; + + t = time(NULL); + local = localtime(&t); + fprintf(fp, "Local time and date: %s", asctime(local)); + local = gmtime(&t); + fprintf(fp, "UTC time and date: %s", asctime(local)); +} + +/*******************************************************************/ + +typedef struct +{ + float sine[TABLE_SIZE]; + double phase; + double phaseIncrement; + volatile int fadeIn; + volatile int fadeOut; + double amp; +} +paTestData; + +static paTestData data; + +/* This routine will be called by the PortAudio engine when audio is needed. +** It may called at interrupt level on some machines so don't do anything +** that could mess up the system like calling malloc() or free(). +*/ +static int patestCallback( const void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + const PaStreamCallbackTimeInfo* timeInfo, + PaStreamCallbackFlags statusFlags, + void *userData ) +{ + paTestData *data = (paTestData*)userData; + float *out = (float*)outputBuffer; + unsigned long i,j; + + (void) timeInfo; /* Prevent unused variable warnings. */ + (void) statusFlags; + (void) inputBuffer; + + for( i=0; isine[(int)data->phase]; + data->phase += data->phaseIncrement; + if( data->phase >= TABLE_SIZE ){ + data->phase -= TABLE_SIZE; + } + + x *= data->amp; + if( data->fadeIn ){ + data->amp += .001; + if( data->amp >= 1. ) + data->fadeIn = 0; + }else if( data->fadeOut ){ + if( data->amp > 0 ) + data->amp -= .001; + } + + for( j = 0; j < CHANNEL_COUNT; ++j ){ + *out++ = x; + } + } + + if( data->amp > 0 ) + return paContinue; + else + return paComplete; +} + + +#define YES 1 +#define NO 0 + + +static int playUntilKeyPress( int deviceIndex, float sampleRate, + int framesPerUserBuffer, int framesPerDSoundBuffer ) +{ + PaStreamParameters outputParameters; + PaWinDirectSoundStreamInfo directSoundStreamInfo; + PaStream *stream; + PaError err; + int c; + + outputParameters.device = deviceIndex; + outputParameters.channelCount = CHANNEL_COUNT; + outputParameters.sampleFormat = paFloat32; /* 32 bit floating point processing */ + outputParameters.suggestedLatency = 0; /*Pa_GetDeviceInfo( outputParameters.device )->defaultLowOutputLatency;*/ + outputParameters.hostApiSpecificStreamInfo = NULL; + + directSoundStreamInfo.size = sizeof(PaWinDirectSoundStreamInfo); + directSoundStreamInfo.hostApiType = paDirectSound; + directSoundStreamInfo.version = 2; + directSoundStreamInfo.flags = paWinDirectSoundUseLowLevelLatencyParameters; + directSoundStreamInfo.framesPerBuffer = framesPerDSoundBuffer; + outputParameters.hostApiSpecificStreamInfo = &directSoundStreamInfo; + + err = Pa_OpenStream( + &stream, + NULL, /* no input */ + &outputParameters, + sampleRate, + framesPerUserBuffer, + paClipOff | paPrimeOutputBuffersUsingStreamCallback, /* we won't output out of range samples so don't bother clipping them */ + patestCallback, + &data ); + if( err != paNoError ) goto error; + + data.amp = 0; + data.fadeIn = 1; + data.fadeOut = 0; + data.phase = 0; + data.phaseIncrement = 15 + ((rand()%100) / 10); // randomise pitch + + err = Pa_StartStream( stream ); + if( err != paNoError ) goto error; + + + do{ + printf( "Trying buffer size %d.\nIf it sounds smooth (without clicks or glitches) press 'y', if it sounds bad press 'n' ('q' to quit)\n", framesPerDSoundBuffer ); + c = tolower(_getch()); + if( c == 'q' ){ + Pa_Terminate(); + exit(0); + } + }while( c != 'y' && c != 'n' ); + + data.fadeOut = 1; + while( Pa_IsStreamActive(stream) == 1 ) + Pa_Sleep( 100 ); + + err = Pa_StopStream( stream ); + if( err != paNoError ) goto error; + + err = Pa_CloseStream( stream ); + if( err != paNoError ) goto error; + + return (c == 'y') ? YES : NO; + +error: + return err; +} + +/*******************************************************************/ +static void usage( int dsoundHostApiIndex ) +{ + int i; + + fprintf( stderr, "PortAudio DirectSound output latency user guided test\n" ); + fprintf( stderr, "Usage: x.exe dsound-device-index [sampleRate]\n" ); + fprintf( stderr, "Invalid device index. Use one of these:\n" ); + for( i=0; i < Pa_GetDeviceCount(); ++i ){ + + if( Pa_GetDeviceInfo(i)->hostApi == dsoundHostApiIndex && Pa_GetDeviceInfo(i)->maxOutputChannels > 0 ) + fprintf( stderr, "%d (%s)\n", i, Pa_GetDeviceInfo(i)->name ); + } + Pa_Terminate(); + exit(-1); +} + +/* + ideas: + o- could be testing with 80% CPU load + o- could test with different channel counts +*/ + +int main(int argc, char* argv[]) +{ + PaError err; + int i; + int deviceIndex; + int dsoundBufferSize, smallestWorkingBufferSize; + int smallestWorkingBufferingLatencyFrames; + int min, max, mid; + int testResult; + FILE *resultsFp; + int dsoundHostApiIndex; + const PaHostApiInfo *dsoundHostApiInfo; + double sampleRate = DEFAULT_SAMPLE_RATE; + + err = Pa_Initialize(); + if( err != paNoError ) goto error; + + dsoundHostApiIndex = Pa_HostApiTypeIdToHostApiIndex( paDirectSound ); + dsoundHostApiInfo = Pa_GetHostApiInfo( dsoundHostApiIndex ); + + if( argc > 3 ) + usage(dsoundHostApiIndex); + + deviceIndex = dsoundHostApiInfo->defaultOutputDevice; + if( argc >= 2 ){ + deviceIndex = -1; + if( sscanf( argv[1], "%d", &deviceIndex ) != 1 ) + usage(dsoundHostApiInfo); + if( deviceIndex < 0 || deviceIndex >= Pa_GetDeviceCount() || Pa_GetDeviceInfo(deviceIndex)->hostApi != dsoundHostApiIndex ){ + usage(dsoundHostApiInfo); + } + } + + printf( "Using device id %d (%s)\n", deviceIndex, Pa_GetDeviceInfo(deviceIndex)->name ); + + if( argc >= 3 ){ + if( sscanf( argv[2], "%lf", &sampleRate ) != 1 ) + usage(dsoundHostApiIndex); + } + + printf( "Testing with sample rate %f.\n", (float)sampleRate ); + + + + /* initialise sinusoidal wavetable */ + for( i=0; iname ); + fflush( resultsFp ); + + fprintf( resultsFp, "Sample rate: %f\n", (float)sampleRate ); + fprintf( resultsFp, "Smallest working buffer size (frames), Smallest working buffering latency (frames), Smallest working buffering latency (Seconds)\n" ); + + + /* + Binary search after Niklaus Wirth + from http://en.wikipedia.org/wiki/Binary_search_algorithm#The_algorithm + */ + min = 1; + max = (int)(sampleRate * .3); /* we assume that this size works 300ms */ + smallestWorkingBufferSize = 0; + + do{ + mid = min + ((max - min) / 2); + + dsoundBufferSize = mid; + testResult = playUntilKeyPress( deviceIndex, sampleRate, 0, dsoundBufferSize ); + + if( testResult == YES ){ + max = mid - 1; + smallestWorkingBufferSize = dsoundBufferSize; + }else{ + min = mid + 1; + } + + }while( (min <= max) && (testResult == YES || testResult == NO) ); + + smallestWorkingBufferingLatencyFrames = smallestWorkingBufferSize; /* not strictly true, but we're using an unspecified callback size, so kind of */ + + printf( "Smallest working buffer size is: %d\n", smallestWorkingBufferSize ); + printf( "Corresponding to buffering latency of %d frames, or %f seconds.\n", smallestWorkingBufferingLatencyFrames, smallestWorkingBufferingLatencyFrames / sampleRate ); + + fprintf( resultsFp, "%d, %d, %f\n", smallestWorkingBufferSize, smallestWorkingBufferingLatencyFrames, smallestWorkingBufferingLatencyFrames / sampleRate ); + fflush( resultsFp ); + + + /* power of 2 test. iterate to the smallest power of two that works */ + + smallestWorkingBufferSize = 0; + dsoundBufferSize = 64; + + do{ + testResult = playUntilKeyPress( deviceIndex, sampleRate, 0, dsoundBufferSize ); + + if( testResult == YES ){ + smallestWorkingBufferSize = dsoundBufferSize; + }else{ + dsoundBufferSize *= 2; + } + + }while( (dsoundBufferSize <= (int)(sampleRate * .3)) && testResult == NO ); + + smallestWorkingBufferingLatencyFrames = smallestWorkingBufferSize; /* not strictly true, but we're using an unspecified callback size, so kind of */ + + fprintf( resultsFp, "%d, %d, %f\n", smallestWorkingBufferSize, smallestWorkingBufferingLatencyFrames, smallestWorkingBufferingLatencyFrames / sampleRate ); + fflush( resultsFp ); + + + fprintf( resultsFp, "###\n" ); + fclose( resultsFp ); + + Pa_Terminate(); + printf("Test finished.\n"); + + return err; +error: + Pa_Terminate(); + fprintf( stderr, "An error occurred while using the PortAudio stream\n" ); + fprintf( stderr, "Error number: %d\n", err ); + fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); + return err; +} + diff --git a/extern/portaudio/test/patest_dsound_low_level_latency_params.c b/extern/portaudio/test/patest_dsound_low_level_latency_params.c new file mode 100644 index 0000000..a1e7c7e --- /dev/null +++ b/extern/portaudio/test/patest_dsound_low_level_latency_params.c @@ -0,0 +1,187 @@ +/* + * $Id: $ + * Portable Audio I/O Library + * Windows DirectSound low level buffer parameters test + * + * Copyright (c) 2011 Ross Bencina + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +#include +#include + +#include "portaudio.h" +#include "pa_win_ds.h" + +#define NUM_SECONDS (6) +#define SAMPLE_RATE (44100) + +#define DSOUND_FRAMES_PER_HOST_BUFFER (256*2) //(440*10) + +#define FRAMES_PER_BUFFER 256 + +#ifndef M_PI +#define M_PI (3.14159265) +#endif + +#define TABLE_SIZE (2048) + +#define CHANNEL_COUNT (2) + + +typedef struct +{ + float sine[TABLE_SIZE]; + double phase; +} +paTestData; + +/* This routine will be called by the PortAudio engine when audio is needed. +** It may called at interrupt level on some machines so don't do anything +** that could mess up the system like calling malloc() or free(). +*/ +static int patestCallback( const void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + const PaStreamCallbackTimeInfo* timeInfo, + PaStreamCallbackFlags statusFlags, + void *userData ) +{ + paTestData *data = (paTestData*)userData; + float *out = (float*)outputBuffer; + unsigned long i,j; + + (void) timeInfo; /* Prevent unused variable warnings. */ + (void) statusFlags; + (void) inputBuffer; + + for( i=0; isine[(int)data->phase]; + data->phase += 20; + if( data->phase >= TABLE_SIZE ){ + data->phase -= TABLE_SIZE; + } + + for( j = 0; j < CHANNEL_COUNT; ++j ){ + *out++ = x; + } + } + + return paContinue; +} + +/*******************************************************************/ +int main(int argc, char* argv[]) +{ + PaStreamParameters outputParameters; + PaWinDirectSoundStreamInfo dsoundStreamInfo; + PaStream *stream; + PaError err; + paTestData data; + int i; + int deviceIndex; + + printf("PortAudio Test: output a sine blip on each channel. SR = %d, BufSize = %d, Chans = %d\n", SAMPLE_RATE, FRAMES_PER_BUFFER, CHANNEL_COUNT); + + err = Pa_Initialize(); + if( err != paNoError ) goto error; + + deviceIndex = Pa_GetHostApiInfo( Pa_HostApiTypeIdToHostApiIndex( paDirectSound ) )->defaultOutputDevice; + if( argc == 2 ){ + sscanf( argv[1], "%d", &deviceIndex ); + } + + printf( "using device id %d (%s)\n", deviceIndex, Pa_GetDeviceInfo(deviceIndex)->name ); + + /* initialise sinusoidal wavetable */ + for( i=0; idefaultLowOutputLatency;*/ + outputParameters.hostApiSpecificStreamInfo = NULL; + + dsoundStreamInfo.size = sizeof(PaWinDirectSoundStreamInfo); + dsoundStreamInfo.hostApiType = paDirectSound; + dsoundStreamInfo.version = 2; + dsoundStreamInfo.flags = paWinDirectSoundUseLowLevelLatencyParameters; + dsoundStreamInfo.framesPerBuffer = DSOUND_FRAMES_PER_HOST_BUFFER; + outputParameters.hostApiSpecificStreamInfo = &dsoundStreamInfo; + + + if( Pa_IsFormatSupported( 0, &outputParameters, SAMPLE_RATE ) == paFormatIsSupported ){ + printf( "Pa_IsFormatSupported reports device will support %d channels.\n", CHANNEL_COUNT ); + }else{ + printf( "Pa_IsFormatSupported reports device will not support %d channels.\n", CHANNEL_COUNT ); + } + + err = Pa_OpenStream( + &stream, + NULL, /* no input */ + &outputParameters, + SAMPLE_RATE, + FRAMES_PER_BUFFER, + paClipOff, /* we won't output out of range samples so don't bother clipping them */ + patestCallback, + &data ); + if( err != paNoError ) goto error; + + err = Pa_StartStream( stream ); + if( err != paNoError ) goto error; + + printf("Play for %d seconds.\n", NUM_SECONDS ); + Pa_Sleep( NUM_SECONDS * 1000 ); + + err = Pa_StopStream( stream ); + if( err != paNoError ) goto error; + + err = Pa_CloseStream( stream ); + if( err != paNoError ) goto error; + + Pa_Terminate(); + printf("Test finished.\n"); + + return err; +error: + Pa_Terminate(); + fprintf( stderr, "An error occured while using the portaudio stream\n" ); + fprintf( stderr, "Error number: %d\n", err ); + fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); + return err; +} + diff --git a/extern/portaudio/test/patest_dsound_surround.c b/extern/portaudio/test/patest_dsound_surround.c new file mode 100644 index 0000000..3ffd151 --- /dev/null +++ b/extern/portaudio/test/patest_dsound_surround.c @@ -0,0 +1,205 @@ +/* + * $Id: $ + * Portable Audio I/O Library + * Windows DirectSound surround sound output test + * + * Copyright (c) 2007 Ross Bencina + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +#include +#include + +#include /* required when using pa_win_wmme.h */ +#include /* required when using pa_win_wmme.h */ + +#include "portaudio.h" +#include "pa_win_ds.h" + +#define NUM_SECONDS (12) +#define SAMPLE_RATE (44100) +#define FRAMES_PER_BUFFER (64) + +#ifndef M_PI +#define M_PI (3.14159265) +#endif + +#define TABLE_SIZE (100) + +#define CHANNEL_COUNT (6) + + + +typedef struct +{ + float sine[TABLE_SIZE]; + int phase; + int currentChannel; + int cycleCount; +} +paTestData; + +/* This routine will be called by the PortAudio engine when audio is needed. +** It may called at interrupt level on some machines so don't do anything +** that could mess up the system like calling malloc() or free(). +*/ +static int patestCallback( const void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + const PaStreamCallbackTimeInfo* timeInfo, + PaStreamCallbackFlags statusFlags, + void *userData ) +{ + paTestData *data = (paTestData*)userData; + float *out = (float*)outputBuffer; + unsigned long i,j; + + (void) timeInfo; /* Prevent unused variable warnings. */ + (void) statusFlags; + (void) inputBuffer; + + for( i=0; icurrentChannel && data->cycleCount < 4410 ){ + *out++ = data->sine[data->phase]; + data->phase += 1 + j; // play each channel at a different pitch so they can be distinguished + if( data->phase >= TABLE_SIZE ){ + data->phase -= TABLE_SIZE; + } + }else{ + *out++ = 0; + } + } + + data->cycleCount++; + if( data->cycleCount > 44100 ){ + data->cycleCount = 0; + + ++data->currentChannel; + if( data->currentChannel >= CHANNEL_COUNT ) + data->currentChannel -= CHANNEL_COUNT; + } + } + + return paContinue; +} + +/*******************************************************************/ +int main(int argc, char* argv[]) +{ + PaStreamParameters outputParameters; + PaWinDirectSoundStreamInfo directSoundStreamInfo; + PaStream *stream; + PaError err; + paTestData data; + int i; + int deviceIndex; + + printf("PortAudio Test: output a sine blip on each channel. SR = %d, BufSize = %d, Chans = %d\n", SAMPLE_RATE, FRAMES_PER_BUFFER, CHANNEL_COUNT); + + err = Pa_Initialize(); + if( err != paNoError ) goto error; + + deviceIndex = Pa_GetHostApiInfo( Pa_HostApiTypeIdToHostApiIndex( paDirectSound ) )->defaultOutputDevice; + if( argc == 2 ){ + sscanf( argv[1], "%d", &deviceIndex ); + } + + printf( "using device id %d (%s)\n", deviceIndex, Pa_GetDeviceInfo(deviceIndex)->name ); + + /* initialise sinusoidal wavetable */ + for( i=0; idefaultLowOutputLatency; + outputParameters.hostApiSpecificStreamInfo = NULL; + + /* it's not strictly necessary to provide a channelMask for surround sound + output. But if you want to be sure which channel mask PortAudio will use + then you should supply one */ + directSoundStreamInfo.size = sizeof(PaWinDirectSoundStreamInfo); + directSoundStreamInfo.hostApiType = paDirectSound; + directSoundStreamInfo.version = 1; + directSoundStreamInfo.flags = paWinDirectSoundUseChannelMask; + directSoundStreamInfo.channelMask = PAWIN_SPEAKER_5POINT1; /* request 5.1 output format */ + outputParameters.hostApiSpecificStreamInfo = &directSoundStreamInfo; + + if( Pa_IsFormatSupported( 0, &outputParameters, SAMPLE_RATE ) == paFormatIsSupported ){ + printf( "Pa_IsFormatSupported reports device will support %d channels.\n", CHANNEL_COUNT ); + }else{ + printf( "Pa_IsFormatSupported reports device will not support %d channels.\n", CHANNEL_COUNT ); + } + + err = Pa_OpenStream( + &stream, + NULL, /* no input */ + &outputParameters, + SAMPLE_RATE, + FRAMES_PER_BUFFER, + paClipOff, /* we won't output out of range samples so don't bother clipping them */ + patestCallback, + &data ); + if( err != paNoError ) goto error; + + err = Pa_StartStream( stream ); + if( err != paNoError ) goto error; + + printf("Play for %d seconds.\n", NUM_SECONDS ); + Pa_Sleep( NUM_SECONDS * 1000 ); + + err = Pa_StopStream( stream ); + if( err != paNoError ) goto error; + + err = Pa_CloseStream( stream ); + if( err != paNoError ) goto error; + + Pa_Terminate(); + printf("Test finished.\n"); + + return err; +error: + Pa_Terminate(); + fprintf( stderr, "An error occured while using the portaudio stream\n" ); + fprintf( stderr, "Error number: %d\n", err ); + fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); + return err; +} + diff --git a/extern/portaudio/test/patest_hang.c b/extern/portaudio/test/patest_hang.c new file mode 100644 index 0000000..6bda629 --- /dev/null +++ b/extern/portaudio/test/patest_hang.c @@ -0,0 +1,164 @@ +/** @file patest_hang.c + @ingroup test_src + @brief Play a sine then hang audio callback to test watchdog. + @author Ross Bencina + @author Phil Burk +*/ +/* + * $Id$ + * + * This program uses the PortAudio Portable Audio Library. + * For more information see: http://www.portaudio.com + * Copyright (c) 1999-2000 Ross Bencina and Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +#include +#include + +#include "portaudio.h" + +#define SAMPLE_RATE (44100) +#define FRAMES_PER_BUFFER (1024) +#ifndef M_PI +#define M_PI (3.14159265) +#endif +#define TWOPI (M_PI * 2.0) + +typedef struct paTestData +{ + int sleepFor; + double phase; +} +paTestData; + +/* This routine will be called by the PortAudio engine when audio is needed. +** It may called at interrupt level on some machines so don't do anything +** that could mess up the system like calling malloc() or free(). +*/ +static int patestCallback( const void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + const PaStreamCallbackTimeInfo* timeInfo, + PaStreamCallbackFlags statusFlags, + void *userData ) +{ + paTestData *data = (paTestData*)userData; + float *out = (float*)outputBuffer; + unsigned long i; + int finished = 0; + double phaseInc = 0.02; + double phase = data->phase; + + (void) inputBuffer; /* Prevent unused argument warning. */ + + for( i=0; i TWOPI ) phase -= TWOPI; + /* This is not a very efficient way to calc sines. */ + *out++ = (float) sin( phase ); /* mono */ + } + + if( data->sleepFor > 0 ) + { + Pa_Sleep( data->sleepFor ); + } + + data->phase = phase; + return finished; +} + +/*******************************************************************/ +int main(void); +int main(void) +{ + PaStream* stream; + PaStreamParameters outputParameters; + PaError err; + int i; + paTestData data = {0}; + + printf("PortAudio Test: output sine wave. SR = %d, BufSize = %d\n", + SAMPLE_RATE, FRAMES_PER_BUFFER ); + + err = Pa_Initialize(); + if( err != paNoError ) goto error; + + outputParameters.device = Pa_GetDefaultOutputDevice(); /* Default output device. */ + if (outputParameters.device == paNoDevice) { + fprintf(stderr,"Error: No default output device.\n"); + goto error; + } + outputParameters.channelCount = 1; /* Mono output. */ + outputParameters.sampleFormat = paFloat32; /* 32 bit floating point. */ + outputParameters.hostApiSpecificStreamInfo = NULL; + outputParameters.suggestedLatency = Pa_GetDeviceInfo(outputParameters.device) + ->defaultLowOutputLatency; + err = Pa_OpenStream(&stream, + NULL, /* No input. */ + &outputParameters, + SAMPLE_RATE, + FRAMES_PER_BUFFER, + paClipOff, /* No out of range samples. */ + patestCallback, + &data); + if (err != paNoError) goto error; + + err = Pa_StartStream( stream ); + if( err != paNoError ) goto error; + + /* Gradually increase sleep time. */ + /* Was: for( i=0; i<10000; i+= 1000 ) */ + for(i=0; i <= 1000; i += 100) + { + printf("Sleep for %d milliseconds in audio callback.\n", i ); + data.sleepFor = i; + Pa_Sleep( ((i<1000) ? 1000 : i) ); + } + + printf("Suffer for 10 seconds.\n"); + Pa_Sleep( 10000 ); + + err = Pa_StopStream( stream ); + if( err != paNoError ) goto error; + err = Pa_CloseStream( stream ); + if( err != paNoError ) goto error; + Pa_Terminate(); + printf("Test finished.\n"); + return err; +error: + Pa_Terminate(); + fprintf( stderr, "An error occured while using the portaudio stream\n" ); + fprintf( stderr, "Error number: %d\n", err ); + fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); + return err; +} diff --git a/extern/portaudio/test/patest_in_overflow.c b/extern/portaudio/test/patest_in_overflow.c new file mode 100644 index 0000000..1f2a837 --- /dev/null +++ b/extern/portaudio/test/patest_in_overflow.c @@ -0,0 +1,236 @@ +/** @file patest_in_overflow.c + @ingroup test_src + @brief Count input overflows (using paInputOverflow flag) under + overloaded and normal conditions. + This test uses the same method to overload the stream as does + patest_out_underflow.c -- it generates sine waves until the cpu load + exceeds a certain level. However this test is only concerned with + input and so doesn't ouput any sound. + + @author Ross Bencina + @author Phil Burk +*/ +/* + * $Id$ + * + * This program uses the PortAudio Portable Audio Library. + * For more information see: http://www.portaudio.com + * Copyright (c) 1999-2004 Ross Bencina and Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +#include +#include +#include "portaudio.h" + +#define MAX_SINES (500) +#define MAX_LOAD (1.2) +#define SAMPLE_RATE (44100) +#define FRAMES_PER_BUFFER (512) +#ifndef M_PI +#define M_PI (3.14159265) +#endif +#define TWOPI (M_PI * 2.0) + +typedef struct paTestData +{ + int sineCount; + double phases[MAX_SINES]; + int countOverflows; + int inputOverflowCount; +} +paTestData; + +/* This routine will be called by the PortAudio engine when audio is needed. +** It may called at interrupt level on some machines so don't do anything +** that could mess up the system like calling malloc() or free(). +*/ +static int patestCallback( const void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + const PaStreamCallbackTimeInfo* timeInfo, + PaStreamCallbackFlags statusFlags, + void *userData ) +{ + paTestData *data = (paTestData*)userData; + float out; /* variable to hold dummy output */ + unsigned long i; + int j; + int finished = paContinue; + (void) timeInfo; /* Prevent unused variable warning. */ + (void) inputBuffer; /* Prevent unused variable warning. */ + (void) outputBuffer; /* Prevent unused variable warning. */ + + if( data->countOverflows && (statusFlags & paInputOverflow) ) + data->inputOverflowCount++; + + for( i=0; isineCount; j++ ) + { + /* Advance phase of next oscillator. */ + phase = data->phases[j]; + phase += phaseInc; + if( phase > TWOPI ) phase -= TWOPI; + + phaseInc *= 1.02; + if( phaseInc > 0.5 ) phaseInc *= 0.5; + + /* This is not a very efficient way to calc sines. */ + output += (float) sin( phase ); + data->phases[j] = phase; + } + /* this is an input-only stream so we don't actually use the output */ + out = (float) (output / data->sineCount); + (void) out; /* suppress unused variable warning*/ + } + + return finished; +} + +/*******************************************************************/ +int main(void); +int main(void) +{ + PaStreamParameters inputParameters; + PaStream *stream; + PaError err; + int safeSineCount, stressedSineCount; + int safeOverflowCount, stressedOverflowCount; + paTestData data = {0}; + double load; + + + printf("PortAudio Test: input only, no sound output. Load callback by performing calculations, count input overflows. SR = %d, BufSize = %d. MAX_LOAD = %f\n", + SAMPLE_RATE, FRAMES_PER_BUFFER, (float)MAX_LOAD ); + + err = Pa_Initialize(); + if( err != paNoError ) goto error; + + inputParameters.device = Pa_GetDefaultInputDevice(); /* default input device */ + if (inputParameters.device == paNoDevice) { + fprintf(stderr,"Error: No default input device.\n"); + goto error; + } + inputParameters.channelCount = 1; /* mono output */ + inputParameters.sampleFormat = paFloat32; /* 32 bit floating point output */ + inputParameters.suggestedLatency = Pa_GetDeviceInfo( inputParameters.device )->defaultLowInputLatency; + inputParameters.hostApiSpecificStreamInfo = NULL; + + err = Pa_OpenStream( + &stream, + &inputParameters, + NULL, /* no output */ + SAMPLE_RATE, + FRAMES_PER_BUFFER, + paClipOff, /* we won't output out of range samples so don't bother clipping them */ + patestCallback, + &data ); + if( err != paNoError ) goto error; + err = Pa_StartStream( stream ); + if( err != paNoError ) goto error; + + printf("Establishing load conditions...\n" ); + + /* Determine number of sines required to get to 50% */ + do + { + data.sineCount++; + Pa_Sleep( 100 ); + + load = Pa_GetStreamCpuLoad( stream ); + printf("sineCount = %d, CPU load = %f\n", data.sineCount, load ); + } + while( load < 0.5 && data.sineCount < (MAX_SINES-1)); + + safeSineCount = data.sineCount; + + /* Calculate target stress value then ramp up to that level*/ + stressedSineCount = (int) (2.0 * data.sineCount * MAX_LOAD ); + if( stressedSineCount > MAX_SINES ) + stressedSineCount = MAX_SINES; + for( ; data.sineCount < stressedSineCount; data.sineCount++ ) + { + Pa_Sleep( 100 ); + load = Pa_GetStreamCpuLoad( stream ); + printf("STRESSING: sineCount = %d, CPU load = %f\n", data.sineCount, load ); + } + + printf("Counting overflows for 5 seconds.\n"); + data.countOverflows = 1; + Pa_Sleep( 5000 ); + + stressedOverflowCount = data.inputOverflowCount; + + data.countOverflows = 0; + data.sineCount = safeSineCount; + + printf("Resuming safe load...\n"); + Pa_Sleep( 1500 ); + data.inputOverflowCount = 0; + Pa_Sleep( 1500 ); + load = Pa_GetStreamCpuLoad( stream ); + printf("sineCount = %d, CPU load = %f\n", data.sineCount, load ); + + printf("Counting overflows for 5 seconds.\n"); + data.countOverflows = 1; + Pa_Sleep( 5000 ); + + safeOverflowCount = data.inputOverflowCount; + + printf("Stop stream.\n"); + err = Pa_StopStream( stream ); + if( err != paNoError ) goto error; + + err = Pa_CloseStream( stream ); + if( err != paNoError ) goto error; + + Pa_Terminate(); + + if( stressedOverflowCount == 0 ) + printf("Test failed, no input overflows detected under stress.\n"); + else if( safeOverflowCount != 0 ) + printf("Test failed, %d unexpected overflows detected under safe load.\n", safeOverflowCount); + else + printf("Test passed, %d expected input overflows detected under stress, 0 unexpected overflows detected under safe load.\n", stressedOverflowCount ); + + return err; +error: + Pa_Terminate(); + fprintf( stderr, "An error occured while using the portaudio stream\n" ); + fprintf( stderr, "Error number: %d\n", err ); + fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); + return err; +} diff --git a/extern/portaudio/test/patest_jack_wasapi.c b/extern/portaudio/test/patest_jack_wasapi.c new file mode 100644 index 0000000..f01297a --- /dev/null +++ b/extern/portaudio/test/patest_jack_wasapi.c @@ -0,0 +1,343 @@ +/** @file pa_test_jack_wasapi.c + @ingroup test_src + @brief Print out jack information for WASAPI endpoints + @author Reid Bishop +*/ +/* + * $Id: pa_test_jack_wasapi.c 1368 2008-03-01 00:38:27Z rbishop $ + * + * This program uses the PortAudio Portable Audio Library. + * For more information see: http://www.portaudio.com/ + * Copyright (c) 1999-2010 Ross Bencina and Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ +#include +#include "portaudio.h" +#include "pa_win_wasapi.h" + + +/* +* Helper function to determine if a given enum is present in mask variable +* +*/ +static int IsInMask(int val, int val2) +{ + return ((val & val2) == val2); +} + +/* +* This routine enumerates through the ChannelMapping for the IJackDescription +*/ + +static void EnumIJackChannels(int channelMapping) +{ + printf("Channel Mapping: "); + if(channelMapping == PAWIN_SPEAKER_DIRECTOUT) + { + printf("DIRECTOUT\n"); + return; + } + if(IsInMask(channelMapping, PAWIN_SPEAKER_FRONT_LEFT)) + printf("FRONT_LEFT, "); + if(IsInMask(channelMapping, PAWIN_SPEAKER_FRONT_RIGHT)) + printf("FRONT_RIGHT, "); + if(IsInMask(channelMapping, PAWIN_SPEAKER_FRONT_CENTER)) + printf("FRONT_CENTER, "); + if(IsInMask(channelMapping, PAWIN_SPEAKER_LOW_FREQUENCY)) + printf("LOW_FREQUENCY, "); + if(IsInMask(channelMapping, PAWIN_SPEAKER_BACK_LEFT)) + printf("BACK_LEFT, "); + if(IsInMask(channelMapping,PAWIN_SPEAKER_BACK_RIGHT)) + printf("BACK_RIGHT, "); + if(IsInMask(channelMapping, PAWIN_SPEAKER_FRONT_LEFT_OF_CENTER)) + printf("FRONT_LEFT_OF_CENTER, "); + if(IsInMask(channelMapping, PAWIN_SPEAKER_FRONT_RIGHT_OF_CENTER)) + printf("FRONT_RIGHT_OF_CENTER, "); + if(IsInMask(channelMapping, PAWIN_SPEAKER_BACK_CENTER)) + printf("BACK_CENTER, "); + if(IsInMask(channelMapping,PAWIN_SPEAKER_SIDE_LEFT)) + printf("SIDE_LEFT, "); + if(IsInMask(channelMapping,PAWIN_SPEAKER_SIDE_RIGHT)) + printf("SIDE_RIGHT, "); + if(IsInMask(channelMapping, PAWIN_SPEAKER_TOP_CENTER)) + printf("TOP_CENTER, "); + if(IsInMask(channelMapping, PAWIN_SPEAKER_TOP_FRONT_LEFT)) + printf("TOP_FRONT_LEFT, "); + if(IsInMask(channelMapping, PAWIN_SPEAKER_TOP_FRONT_CENTER)) + printf("TOP_FRONT_CENTER, "); + if(IsInMask(channelMapping, PAWIN_SPEAKER_TOP_FRONT_RIGHT)) + printf("TOP_FRONT_RIGHT, "); + if(IsInMask(channelMapping, PAWIN_SPEAKER_TOP_BACK_LEFT)) + printf("TOP_BACK_LEFT, "); + if(IsInMask(channelMapping, PAWIN_SPEAKER_TOP_BACK_CENTER)) + printf("TOP_BACK_CENTER, "); + if(IsInMask(channelMapping, PAWIN_SPEAKER_TOP_BACK_RIGHT)) + printf("TOP_BACK_RIGHT, "); + + printf("\n"); +} + +/* +* This routine enumerates through the Jack Connection Types enums for IJackDescription +*/ +static void EnumIJackConnectionType(int cType) +{ + printf("Connection Type: "); + switch(cType) + { + case eJackConnTypeUnknown: + printf("eJackConnTypeUnknown"); + break; + case eJackConnType3Point5mm: + printf("eJackConnType3Point5mm"); + break; + case eJackConnTypeQuarter: + printf("eJackConnTypeQuarter"); + break; + case eJackConnTypeAtapiInternal: + printf("eJackConnTypeAtapiInternal"); + break; + case eJackConnTypeRCA: + printf("eJackConnTypeRCA"); + break; + case eJackConnTypeOptical: + printf("eJackConnTypeOptical"); + break; + case eJackConnTypeOtherDigital: + printf("eJackConnTypeOtherDigital"); + break; + case eJackConnTypeOtherAnalog: + printf("eJackConnTypeOtherAnalog"); + break; + case eJackConnTypeMultichannelAnalogDIN: + printf("eJackConnTypeMultichannelAnalogDIN"); + break; + case eJackConnTypeXlrProfessional: + printf("eJackConnTypeXlrProfessional"); + break; + case eJackConnTypeRJ11Modem: + printf("eJackConnTypeRJ11Modem"); + break; + case eJackConnTypeCombination: + printf("eJackConnTypeCombination"); + break; + } + printf("\n"); +} + +/* +* This routine enumerates through the GeoLocation enums for the IJackDescription +*/ +static void EnumIJackGeoLocation(int iVal) +{ + printf("Geometric Location: "); + switch(iVal) + { + case eJackGeoLocRear: + printf("eJackGeoLocRear"); + break; + case eJackGeoLocFront: + printf("eJackGeoLocFront"); + break; + case eJackGeoLocLeft: + printf("eJackGeoLocLeft"); + break; + case eJackGeoLocRight: + printf("eJackGeoLocRight"); + break; + case eJackGeoLocTop: + printf("eJackGeoLocTop"); + break; + case eJackGeoLocBottom: + printf("eJackGeoLocBottom"); + break; + case eJackGeoLocRearPanel: + printf("eJackGeoLocRearPanel"); + break; + case eJackGeoLocRiser: + printf("eJackGeoLocRiser"); + break; + case eJackGeoLocInsideMobileLid: + printf("eJackGeoLocInsideMobileLid"); + break; + case eJackGeoLocDrivebay: + printf("eJackGeoLocDrivebay"); + break; + case eJackGeoLocHDMI: + printf("eJackGeoLocHDMI"); + break; + case eJackGeoLocOutsideMobileLid: + printf("eJackGeoLocOutsideMobileLid"); + break; + case eJackGeoLocATAPI: + printf("eJackGeoLocATAPI"); + break; + } + printf("\n"); +} + +/* +* This routine enumerates through the GenLocation enums for the IJackDescription +*/ +static void EnumIJackGenLocation(int iVal) +{ + printf("General Location: "); + switch(iVal) + { + case eJackGenLocPrimaryBox: + printf("eJackGenLocPrimaryBox"); + break; + case eJackGenLocInternal: + printf("eJackGenLocInternal"); + break; + case eJackGenLocSeparate: + printf("eJackGenLocSeparate"); + break; + case eJackGenLocOther: + printf("eJackGenLocOther"); + break; + } + printf("\n"); +} + +/* +* This routine enumerates through the PortConnection enums for the IJackDescription +*/ +static void EnumIJackPortConnection(int iVal) +{ + printf("Port Type: "); + switch(iVal) + { + case eJackPortConnJack: + printf("eJackPortConnJack"); + break; + case eJackPortConnIntegratedDevice: + printf("eJackPortConnIntegratedDevice"); + break; + case eJackPortConnBothIntegratedAndJack: + printf("eJackPortConnBothIntegratedAndJack"); + break; + case eJackPortConnUnknown: + printf("eJackPortConnUnknown"); + break; + } + printf("\n"); +} + +/* +* This routine retrieves and parses the KSJACK_DESCRIPTION structure for +* the provided device ID. +*/ +static PaError GetJackInformation(int deviceId) +{ + PaError err; + int i; + int jackCount = 0; + PaWasapiJackDescription jackDesc; + + err = PaWasapi_GetJackCount(deviceId, &jackCount); + if( err != paNoError ) return err; + + fprintf( stderr,"Number of Jacks: %d \n", jackCount ); + + for( i = 0; ihostApi == Pa_HostApiTypeIdToHostApiIndex(paWASAPI) ) + { + if( device->maxOutputChannels == 0 ) + { + isInput = 1; + } + printf("------------------------------------------\n"); + printf("Device: %s",device->name); + if(isInput) + printf(" (Input) %d Channels\n",device->maxInputChannels); + else + printf(" (Output) %d Channels\n",device->maxOutputChannels); + // Try to see if this WASAPI device can provide Jack information + err = GetJackInformation(i); + if( err != paNoError ) goto error; + } + } + Pa_Terminate(); + printf("Test finished.\n"); + return err; + +error: + Pa_Terminate(); + fprintf( stderr, "An error occured while using the portaudio stream\n" ); + fprintf( stderr, "Error number: %d\n", err ); + fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); + return err; +} diff --git a/extern/portaudio/test/patest_latency.c b/extern/portaudio/test/patest_latency.c new file mode 100644 index 0000000..bbc6fe6 --- /dev/null +++ b/extern/portaudio/test/patest_latency.c @@ -0,0 +1,193 @@ +/** @file + @ingroup test_src + @brief Hear the latency caused by big buffers. + Play a sine wave and change frequency based on letter input. + @author Phil Burk , and Darren Gibbs +*/ +/* + * $Id$ + * + * This program uses the PortAudio Portable Audio Library. + * For more information see: http://www.portaudio.com + * Copyright (c) 1999-2000 Ross Bencina and Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +#include +#include +#include "portaudio.h" + +#define OUTPUT_DEVICE (Pa_GetDefaultOutputDevice()) +#define SAMPLE_RATE (44100) +#define FRAMES_PER_BUFFER (64) + +#define MIN_FREQ (100.0f) +#define CalcPhaseIncrement(freq) ((freq)/SAMPLE_RATE) +#ifndef M_PI +#define M_PI (3.14159265) +#endif +#define TABLE_SIZE (400) + +typedef struct +{ + float sine[TABLE_SIZE + 1]; /* add one for guard point for interpolation */ + float phase_increment; + float left_phase; + float right_phase; +} +paTestData; + +float LookupSine( paTestData *data, float phase ); +/* Convert phase between and 1.0 to sine value + * using linear interpolation. + */ +float LookupSine( paTestData *data, float phase ) +{ + float fIndex = phase*TABLE_SIZE; + int index = (int) fIndex; + float fract = fIndex - index; + float lo = data->sine[index]; + float hi = data->sine[index+1]; + float val = lo + fract*(hi-lo); + return val; +} + +/* This routine will be called by the PortAudio engine when audio is needed. +** It may called at interrupt level on some machines so don't do anything +** that could mess up the system like calling malloc() or free(). +*/ +static int patestCallback( const void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + const PaStreamCallbackTimeInfo* timeInfo, + PaStreamCallbackFlags statusFlags, + void *userData ) +{ + paTestData *data = (paTestData*)userData; + float *out = (float*)outputBuffer; + int i; + + (void) inputBuffer; /* Prevent unused variable warning. */ + + for( i=0; ileft_phase); /* left */ + *out++ = LookupSine(data, data->right_phase); /* right */ + data->left_phase += data->phase_increment; + if( data->left_phase >= 1.0f ) data->left_phase -= 1.0f; + data->right_phase += (data->phase_increment * 1.5f); /* fifth above */ + if( data->right_phase >= 1.0f ) data->right_phase -= 1.0f; + } + return 0; +} + +/*******************************************************************/ +int main(void); +int main(void) +{ + PaStream *stream; + PaStreamParameters outputParameters; + PaError err; + paTestData data; + int i; + int done = 0; + + printf("PortAudio Test: enter letter then hit ENTER.\n" ); + /* initialise sinusoidal wavetable */ + for( i=0; idefaultLowOutputLatency; + outputParameters.hostApiSpecificStreamInfo = NULL; + + printf("Requested output latency = %.4f seconds.\n", outputParameters.suggestedLatency ); + printf("%d frames per buffer.\n.", FRAMES_PER_BUFFER ); + + err = Pa_OpenStream( + &stream, + NULL, /* no input */ + &outputParameters, + SAMPLE_RATE, + FRAMES_PER_BUFFER, + paClipOff|paDitherOff, /* we won't output out of range samples so don't bother clipping them */ + patestCallback, + &data ); + if( err != paNoError ) goto error; + + err = Pa_StartStream( stream ); + if( err != paNoError ) goto error; + printf("Play ASCII keyboard. Hit 'q' to stop. (Use RETURN key on Mac)\n"); + fflush(stdout); + while ( !done ) + { + float freq; + int index; + char c; + do + { + c = getchar(); + } + while( c < ' '); /* Strip white space and control chars. */ + + if( c == 'q' ) done = 1; + index = c % 26; + freq = MIN_FREQ + (index * 40.0); + data.phase_increment = CalcPhaseIncrement(freq); + } + printf("Call Pa_StopStream()\n"); + err = Pa_StopStream( stream ); + if( err != paNoError ) goto error; + Pa_Terminate(); + printf("Test finished.\n"); + return err; +error: + Pa_Terminate(); + fprintf( stderr, "An error occured while using the portaudio stream\n" ); + fprintf( stderr, "Error number: %d\n", err ); + fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); + return err; +} diff --git a/extern/portaudio/test/patest_leftright.c b/extern/portaudio/test/patest_leftright.c new file mode 100644 index 0000000..33ccf12 --- /dev/null +++ b/extern/portaudio/test/patest_leftright.c @@ -0,0 +1,185 @@ +/** @file patest_leftright.c + @ingroup test_src + @brief Play different tone sine waves that + alternate between left and right channel. + + The low tone should be on the left channel. + + @author Ross Bencina + @author Phil Burk +*/ +/* + * $Id$ + * + * This program uses the PortAudio Portable Audio Library. + * For more information see: http://www.portaudio.com + * Copyright (c) 1999-2000 Ross Bencina and Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +#include +#include +#include "portaudio.h" + +#define NUM_SECONDS (8) +#define SAMPLE_RATE (44100) +#define FRAMES_PER_BUFFER (512) +#ifndef M_PI +#define M_PI (3.14159265) +#endif +#define TABLE_SIZE (200) +#define BALANCE_DELTA (0.001) + +typedef struct +{ + float sine[TABLE_SIZE]; + int left_phase; + int right_phase; + float targetBalance; // 0.0 = left, 1.0 = right + float currentBalance; +} paTestData; + +/* This routine will be called by the PortAudio engine when audio is needed. +** It may called at interrupt level on some machines so don't do anything +** that could mess up the system like calling malloc() or free(). +*/ +static int patestCallback( const void *inputBuffer, + void *outputBuffer, + unsigned long framesPerBuffer, + const PaStreamCallbackTimeInfo* timeInfo, + PaStreamCallbackFlags statusFlags, + void *userData ) +{ + paTestData *data = (paTestData*)userData; + float *out = (float*)outputBuffer; + unsigned long i; + int finished = 0; + /* Prevent unused variable warnings. */ + (void) inputBuffer; + + for( i=0; icurrentBalance < data->targetBalance ) + { + data->currentBalance += BALANCE_DELTA; + } + else if( data->currentBalance > data->targetBalance ) + { + data->currentBalance -= BALANCE_DELTA; + } + // Apply left/right balance. + *out++ = data->sine[data->left_phase] * (1.0f - data->currentBalance); /* left */ + *out++ = data->sine[data->right_phase] * data->currentBalance; /* right */ + + data->left_phase += 1; + if( data->left_phase >= TABLE_SIZE ) data->left_phase -= TABLE_SIZE; + data->right_phase += 3; /* higher pitch so we can distinguish left and right. */ + if( data->right_phase >= TABLE_SIZE ) data->right_phase -= TABLE_SIZE; + } + + return finished; +} + +/*******************************************************************/ +int main(void); +int main(void) +{ + PaStream *stream; + PaStreamParameters outputParameters; + PaError err; + paTestData data; + int i; + printf("Play different tone sine waves that alternate between left and right channel.\n"); + printf("The low tone should be on the left channel.\n"); + + /* initialise sinusoidal wavetable */ + for( i=0; idefaultLowOutputLatency; + outputParameters.hostApiSpecificStreamInfo = NULL; + + err = Pa_OpenStream( &stream, + NULL, /* No input. */ + &outputParameters, /* As above. */ + SAMPLE_RATE, + FRAMES_PER_BUFFER, + paClipOff, /* we won't output out of range samples so don't bother clipping them */ + patestCallback, + &data ); + if( err != paNoError ) goto error; + + err = Pa_StartStream( stream ); + if( err != paNoError ) goto error; + + printf("Play for several seconds.\n"); + for( i=0; i<4; i++ ) + { + printf("Hear low sound on left side.\n"); + data.targetBalance = 0.01; + Pa_Sleep( 1000 ); + + printf("Hear high sound on right side.\n"); + data.targetBalance = 0.99; + Pa_Sleep( 1000 ); + } + + err = Pa_StopStream( stream ); + if( err != paNoError ) goto error; + err = Pa_CloseStream( stream ); + if( err != paNoError ) goto error; + Pa_Terminate(); + printf("Test finished.\n"); + return err; +error: + Pa_Terminate(); + fprintf( stderr, "An error occured while using the portaudio stream\n" ); + fprintf( stderr, "Error number: %d\n", err ); + fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); + return err; +} diff --git a/extern/portaudio/test/patest_longsine.c b/extern/portaudio/test/patest_longsine.c new file mode 100644 index 0000000..3eba0ce --- /dev/null +++ b/extern/portaudio/test/patest_longsine.c @@ -0,0 +1,151 @@ +/** @file patest_longsine.c + @ingroup test_src + @brief Play a sine wave until ENTER hit. + @author Phil Burk http://www.softsynth.com +*/ +/* + * $Id$ + * + * This program uses the PortAudio Portable Audio Library. + * For more information see: http://www.portaudio.com + * Copyright (c) 1999-2000 Ross Bencina and Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +#include +#include + +#include "portaudio.h" + +#define SAMPLE_RATE (44100) + +#ifndef M_PI +#define M_PI (3.14159265) +#endif + +#define TABLE_SIZE (200) +typedef struct +{ + float sine[TABLE_SIZE]; + int left_phase; + int right_phase; +} +paTestData; + +/* This routine will be called by the PortAudio engine when audio is needed. +** It may called at interrupt level on some machines so don't do anything +** that could mess up the system like calling malloc() or free(). +*/ +static int patestCallback(const void* inputBuffer, + void* outputBuffer, + unsigned long framesPerBuffer, + const PaStreamCallbackTimeInfo* timeInfo, + PaStreamCallbackFlags statusFlags, + void* userData) +{ + paTestData *data = (paTestData*)userData; + float *out = (float*)outputBuffer; + unsigned int i; + (void) inputBuffer; /* Prevent unused argument warning. */ + for( i=0; isine[data->left_phase]; /* left */ + *out++ = data->sine[data->right_phase]; /* right */ + data->left_phase += 1; + if( data->left_phase >= TABLE_SIZE ) data->left_phase -= TABLE_SIZE; + data->right_phase += 3; /* higher pitch so we can distinguish left and right. */ + if( data->right_phase >= TABLE_SIZE ) data->right_phase -= TABLE_SIZE; + } + return 0; +} + +/*******************************************************************/ +int main(void); +int main(void) +{ + PaStreamParameters outputParameters; + PaStream *stream; + PaError err; + paTestData data; + int i; + printf("PortAudio Test: output sine wave.\n"); + + /* initialise sinusoidal wavetable */ + for( i=0; idefaultLowOutputLatency; + outputParameters.hostApiSpecificStreamInfo = NULL; + + err = Pa_OpenStream( &stream, + NULL, /* No input. */ + &outputParameters, /* As above. */ + SAMPLE_RATE, + 256, /* Frames per buffer. */ + paClipOff, /* No out of range samples expected. */ + patestCallback, + &data ); + if( err != paNoError ) goto error; + + err = Pa_StartStream( stream ); + if( err != paNoError ) goto error; + + printf("Hit ENTER to stop program.\n"); + getchar(); + + err = Pa_CloseStream( stream ); + if( err != paNoError ) goto error; + Pa_Terminate(); + + printf("Test finished.\n"); + return err; + +error: + Pa_Terminate(); + fprintf( stderr, "An error occured while using the portaudio stream\n" ); + fprintf( stderr, "Error number: %d\n", err ); + fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); + return err; +} diff --git a/extern/portaudio/test/patest_many.c b/extern/portaudio/test/patest_many.c new file mode 100644 index 0000000..083fdb4 --- /dev/null +++ b/extern/portaudio/test/patest_many.c @@ -0,0 +1,210 @@ +/** @file patest_many.c + @ingroup test_src + @brief Start and stop the PortAudio Driver multiple times. + @author Phil Burk http://www.softsynth.com +*/ +/* + * $Id$ + * + * This program uses the PortAudio Portable Audio Library. + * For more information see: http://www.portaudio.com + * Copyright (c) 1999-2000 Ross Bencina and Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +#include +#include +#include +#include "portaudio.h" +#define NUM_SECONDS (1) +#define SAMPLE_RATE (44100) +#ifndef M_PI +#define M_PI (3.14159265) +#endif +#define TABLE_SIZE (200) +typedef struct +{ + short sine[TABLE_SIZE]; + int left_phase; + int right_phase; + unsigned int sampsToGo; +} +paTestData; +PaError TestOnce( void ); +static int patest1Callback( const void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + const PaStreamCallbackTimeInfo* timeInfo, + PaStreamCallbackFlags statusFlags, + void *userData ); + +/* This routine will be called by the PortAudio engine when audio is needed. +** It may called at interrupt level on some machines so don't do anything +** that could mess up the system like calling malloc() or free(). +*/ +static int patest1Callback( const void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + const PaStreamCallbackTimeInfo* timeInfo, + PaStreamCallbackFlags statusFlags, + void *userData ) +{ + paTestData *data = (paTestData*)userData; + short *out = (short*)outputBuffer; + unsigned int i; + int finished = 0; + (void) inputBuffer; /* Prevent "unused variable" warnings. */ + + if( data->sampsToGo < framesPerBuffer ) + { + /* final buffer... */ + + for( i=0; isampsToGo; i++ ) + { + *out++ = data->sine[data->left_phase]; /* left */ + *out++ = data->sine[data->right_phase]; /* right */ + data->left_phase += 1; + if( data->left_phase >= TABLE_SIZE ) data->left_phase -= TABLE_SIZE; + data->right_phase += 3; /* higher pitch so we can distinguish left and right. */ + if( data->right_phase >= TABLE_SIZE ) data->right_phase -= TABLE_SIZE; + } + /* zero remainder of final buffer */ + for( ; isine[data->left_phase]; /* left */ + *out++ = data->sine[data->right_phase]; /* right */ + data->left_phase += 1; + if( data->left_phase >= TABLE_SIZE ) data->left_phase -= TABLE_SIZE; + data->right_phase += 3; /* higher pitch so we can distinguish left and right. */ + if( data->right_phase >= TABLE_SIZE ) data->right_phase -= TABLE_SIZE; + } + data->sampsToGo -= framesPerBuffer; + } + return finished; +} +/*******************************************************************/ +#ifdef MACINTOSH +int main(void); +int main(void) +{ + int i; + PaError err; + int numLoops = 10; + printf("Loop %d times.\n", numLoops ); + for( i=0; i 1 ) + { + numLoops = atoi(argv[1]); + } + for( i=0; idefaultLowOutputLatency; + outputParameters.hostApiSpecificStreamInfo = NULL; + err = Pa_OpenStream( + &stream, + NULL, /* no input */ + &outputParameters, + SAMPLE_RATE, + 1024, /* frames per buffer */ + paClipOff, /* we won't output out of range samples so don't bother clipping them */ + patest1Callback, + &data ); + if( err != paNoError ) goto error; + + err = Pa_StartStream( stream ); + if( err != paNoError ) goto error; + printf("Waiting for sound to finish.\n"); + Pa_Sleep(1000); + err = Pa_CloseStream( stream ); + if( err != paNoError ) goto error; + Pa_Terminate(); + return paNoError; +error: + Pa_Terminate(); + fprintf( stderr, "An error occured while using the portaudio stream\n" ); + fprintf( stderr, "Error number: %d\n", err ); + fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); + return err; +} diff --git a/extern/portaudio/test/patest_maxsines.c b/extern/portaudio/test/patest_maxsines.c new file mode 100644 index 0000000..49db8d2 --- /dev/null +++ b/extern/portaudio/test/patest_maxsines.c @@ -0,0 +1,216 @@ +/** @file patest_maxsines.c + @ingroup test_src + @brief How many sine waves can we calculate and play in less than 80% CPU Load. + @author Ross Bencina + @author Phil Burk +*/ +/* + * $Id$ + * + * This program uses the PortAudio Portable Audio Library. + * For more information see: http://www.portaudio.com + * Copyright (c) 1999-2000 Ross Bencina and Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +#include +#include +#include "portaudio.h" + +#define MAX_SINES (2000) +#define MAX_USAGE (0.5) +#define SAMPLE_RATE (44100) +#define FREQ_TO_PHASE_INC(freq) (freq/(float)SAMPLE_RATE) + +#define MIN_PHASE_INC FREQ_TO_PHASE_INC(200.0f) +#define MAX_PHASE_INC (MIN_PHASE_INC * (1 << 5)) + +#define FRAMES_PER_BUFFER (512) +#ifndef M_PI +#define M_PI (3.14159265) +#endif +#define TWOPI (M_PI * 2.0) + +#define TABLE_SIZE (1024) + +typedef struct paTestData +{ + int numSines; + float sine[TABLE_SIZE + 1]; /* add one for guard point for interpolation */ + float phases[MAX_SINES]; +} +paTestData; + +/* Convert phase between 0.0 and 1.0 to sine value + * using linear interpolation. + */ +float LookupSine( paTestData *data, float phase ); +float LookupSine( paTestData *data, float phase ) +{ + float fIndex = phase*TABLE_SIZE; + int index = (int) fIndex; + float fract = fIndex - index; + float lo = data->sine[index]; + float hi = data->sine[index+1]; + float val = lo + fract*(hi-lo); + return val; +} + +/* This routine will be called by the PortAudio engine when audio is needed. +** It may called at interrupt level on some machines so don't do anything +** that could mess up the system like calling malloc() or free(). +*/ +static int patestCallback(const void* inputBuffer, + void* outputBuffer, + unsigned long framesPerBuffer, + const PaStreamCallbackTimeInfo* timeInfo, + PaStreamCallbackFlags statusFlags, + void* userData ) +{ + paTestData *data = (paTestData*)userData; + float *out = (float*)outputBuffer; + float outSample; + float scaler; + int numForScale; + unsigned long i; + int j; + int finished = 0; + (void) inputBuffer; /* Prevent unused argument warning. */ + + /* Determine amplitude scaling factor */ + numForScale = data->numSines; + if( numForScale < 8 ) numForScale = 8; /* prevent pops at beginning */ + scaler = 1.0f / numForScale; + + for( i=0; inumSines; j++ ) + { + /* Advance phase of next oscillator. */ + phase = data->phases[j]; + phase += phaseInc; + if( phase >= 1.0 ) phase -= 1.0; + + output += LookupSine(data, phase); + data->phases[j] = phase; + + phaseInc *= 1.02f; + if( phaseInc > MAX_PHASE_INC ) phaseInc = MIN_PHASE_INC; + } + + outSample = (float) (output * scaler); + *out++ = outSample; /* Left */ + *out++ = outSample; /* Right */ + } + return finished; +} + +/*******************************************************************/ +int main(void); +int main(void) +{ + int i; + PaStream* stream; + PaStreamParameters outputParameters; + PaError err; + paTestData data = {0}; + double load; + + printf("PortAudio Test: output sine wave. SR = %d, BufSize = %d\n", SAMPLE_RATE, FRAMES_PER_BUFFER); + + /* initialise sinusoidal wavetable */ + for( i=0; idefaultHighOutputLatency; + err = Pa_OpenStream(&stream, + NULL, /* no input */ + &outputParameters, + SAMPLE_RATE, + FRAMES_PER_BUFFER, + paClipOff, /* No out of range samples should occur. */ + patestCallback, + &data); + if( err != paNoError ) + goto error; + + err = Pa_StartStream( stream ); + if( err != paNoError ) + goto error; + + /* Play an increasing number of sine waves until we hit MAX_USAGE */ + do { + data.numSines += 10; + Pa_Sleep(200); + load = Pa_GetStreamCpuLoad(stream); + printf("numSines = %d, CPU load = %f\n", data.numSines, load ); + fflush(stdout); + } while((load < MAX_USAGE) && (data.numSines < MAX_SINES)); + + Pa_Sleep(2000); /* Stay for 2 seconds at max CPU. */ + + err = Pa_StopStream( stream ); + if( err != paNoError ) + goto error; + + err = Pa_CloseStream( stream ); + if( err != paNoError ) + goto error; + + Pa_Terminate(); + printf("Test finished.\n"); + return err; +error: + Pa_Terminate(); + fprintf( stderr, "An error occured while using the portaudio stream\n" ); + fprintf( stderr, "Error number: %d\n", err ); + fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); + return err; +} diff --git a/extern/portaudio/test/patest_mono.c b/extern/portaudio/test/patest_mono.c new file mode 100644 index 0000000..40c9d64 --- /dev/null +++ b/extern/portaudio/test/patest_mono.c @@ -0,0 +1,156 @@ +/** @file patest_mono.c + @ingroup test_src + @brief Play a monophonic sine wave using the Portable Audio api for several seconds. + @author Phil Burk http://www.softsynth.com +*/ +/* + * $Id$ + * + * Authors: + * Ross Bencina + * Phil Burk + * + * This program uses the PortAudio Portable Audio Library. + * For more information see: http://www.portaudio.com + * Copyright (c) 1999-2000 Ross Bencina and Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +#include +#include +#include "portaudio.h" + +#define NUM_SECONDS (10) +#define SAMPLE_RATE (44100) +#define AMPLITUDE (0.8) +#define FRAMES_PER_BUFFER (64) +#define OUTPUT_DEVICE Pa_GetDefaultOutputDevice() + +#ifndef M_PI +#define M_PI (3.14159265) +#endif + +#define TABLE_SIZE (200) +typedef struct +{ + float sine[TABLE_SIZE]; + int phase; +} +paTestData; + +/* This routine will be called by the PortAudio engine when audio is needed. +** It may called at interrupt level on some machines so don't do anything +** that could mess up the system like calling malloc() or free(). +*/ +static int patestCallback( const void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + const PaStreamCallbackTimeInfo* timeInfo, + PaStreamCallbackFlags statusFlags, + void *userData ) +{ + paTestData *data = (paTestData*)userData; + float *out = (float*)outputBuffer; + unsigned long i; + int finished = 0; + /* avoid unused variable warnings */ + (void) inputBuffer; + (void) timeInfo; + (void) statusFlags; + for( i=0; isine[data->phase]; /* left */ + data->phase += 1; + if( data->phase >= TABLE_SIZE ) data->phase -= TABLE_SIZE; + } + return finished; +} + +/*******************************************************************/ +int main(void); +int main(void) +{ + PaStreamParameters outputParameters; + PaStream *stream; + PaError err; + paTestData data; + int i; + printf("PortAudio Test: output MONO sine wave. SR = %d, BufSize = %d\n", SAMPLE_RATE, FRAMES_PER_BUFFER); + /* initialise sinusoidal wavetable */ + for( i=0; idefaultLowOutputLatency; + outputParameters.hostApiSpecificStreamInfo = NULL; + + err = Pa_OpenStream( + &stream, + NULL, /* no input */ + &outputParameters, + SAMPLE_RATE, + FRAMES_PER_BUFFER, + paClipOff, /* we won't output out of range samples so don't bother clipping them */ + patestCallback, + &data ); + if( err != paNoError ) goto error; + + err = Pa_StartStream( stream ); + if( err != paNoError ) goto error; + + printf("Play for %d seconds.\n", NUM_SECONDS ); fflush(stdout); + Pa_Sleep( NUM_SECONDS * 1000 ); + + err = Pa_StopStream( stream ); + if( err != paNoError ) goto error; + + err = Pa_CloseStream( stream ); + if( err != paNoError ) goto error; + + Pa_Terminate(); + printf("Test finished.\n"); + return err; +error: + Pa_Terminate(); + fprintf( stderr, "An error occured while using the portaudio stream\n" ); + fprintf( stderr, "Error number: %d\n", err ); + fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); + return err; +} + diff --git a/extern/portaudio/test/patest_multi_sine.c b/extern/portaudio/test/patest_multi_sine.c new file mode 100644 index 0000000..2b11bfc --- /dev/null +++ b/extern/portaudio/test/patest_multi_sine.c @@ -0,0 +1,205 @@ +/** @file patest_multi_sine.c + @ingroup test_src + @brief Play a different sine wave on each channel. + @author Phil Burk http://www.softsynth.com +*/ +/* + * $Id$ + * + * This program uses the PortAudio Portable Audio Library. + * For more information see: http://www.portaudio.com + * Copyright (c) 1999-2000 Ross Bencina and Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +#include +#include + +#include "portaudio.h" + +#define SAMPLE_RATE (44100) +#define FRAMES_PER_BUFFER (128) +#define FREQ_INCR (300.0 / SAMPLE_RATE) +#define MAX_CHANNELS (64) + +#ifndef M_PI +#define M_PI (3.14159265) +#endif + +typedef struct +{ + short interleaved; /* Nonzero for interleaved / zero for non-interleaved. */ + int numChannels; /* Actually used. */ + double phases[MAX_CHANNELS]; /* Each channel gets its' own frequency. */ +} +paTestData; + +/* This routine will be called by the PortAudio engine when audio is needed. +** It may called at interrupt level on some machines so don't do anything +** that could mess up the system like calling malloc() or free(). +*/ +static int patestCallback(const void* inputBuffer, + void* outputBuffer, + unsigned long framesPerBuffer, + const PaStreamCallbackTimeInfo* timeInfo, + PaStreamCallbackFlags statusFlags, + void* userData) +{ + int frameIndex, channelIndex; + float** outputs = (float**)outputBuffer; + paTestData* data = (paTestData*)userData; + + (void) inputBuffer; /* Prevent unused arg warning. */ + if (data->interleaved) + { + float *out = (float*)outputBuffer; /* interleaved version */ + for( frameIndex=0; frameIndex<(int)framesPerBuffer; frameIndex++ ) + { + for( channelIndex=0; channelIndexnumChannels; channelIndex++ ) + { + /* Output sine wave on every channel. */ + *out++ = (float) sin(data->phases[channelIndex]); + + /* Play each channel at a higher frequency. */ + data->phases[channelIndex] += FREQ_INCR * (4 + channelIndex); + if( data->phases[channelIndex] >= (2.0 * M_PI) ) data->phases[channelIndex] -= (2.0 * M_PI); + } + } + } + else + { + for( frameIndex=0; frameIndex<(int)framesPerBuffer; frameIndex++ ) + { + for( channelIndex=0; channelIndexnumChannels; channelIndex++ ) + { + /* Output sine wave on every channel. */ + outputs[channelIndex][frameIndex] = (float) sin(data->phases[channelIndex]); + + /* Play each channel at a higher frequency. */ + data->phases[channelIndex] += FREQ_INCR * (4 + channelIndex); + if( data->phases[channelIndex] >= (2.0 * M_PI) ) data->phases[channelIndex] -= (2.0 * M_PI); + } + } + } + return 0; +} + +/*******************************************************************/ +int test(short interleaved) +{ + PaStream* stream; + PaStreamParameters outputParameters; + PaError err; + const PaDeviceInfo* pdi; + paTestData data; + short n; + + outputParameters.device = Pa_GetDefaultOutputDevice(); /* Default output device, max channels. */ + if (outputParameters.device == paNoDevice) { + fprintf(stderr,"Error: No default output device.\n"); + return paInvalidDevice; + } + pdi = Pa_GetDeviceInfo(outputParameters.device); + outputParameters.channelCount = pdi->maxOutputChannels; + if (outputParameters.channelCount > MAX_CHANNELS) + outputParameters.channelCount = MAX_CHANNELS; + outputParameters.sampleFormat = paFloat32; /* 32 bit floating point output */ + outputParameters.suggestedLatency = pdi->defaultLowOutputLatency; + outputParameters.hostApiSpecificStreamInfo = NULL; + + data.interleaved = interleaved; + data.numChannels = outputParameters.channelCount; + for (n = 0; n < data.numChannels; n++) + data.phases[n] = 0.0; /* Phases wrap and maybe don't need initialisation. */ + printf("%d ", data.numChannels); + if (interleaved) + printf("interleaved "); + else + { + printf(" non-interleaved "); + outputParameters.sampleFormat |= paNonInterleaved; + } + printf("channels.\n"); + + err = Pa_OpenStream(&stream, + NULL, /* No input. */ + &outputParameters, + SAMPLE_RATE, /* Sample rate. */ + FRAMES_PER_BUFFER, /* Frames per buffer. */ + paClipOff, /* Samples never out of range, no clipping. */ + patestCallback, + &data); + if (err == paNoError) + { + err = Pa_StartStream(stream); + if (err == paNoError) + { + printf("Hit ENTER to stop this test.\n"); + getchar(); + err = Pa_StopStream(stream); + } + Pa_CloseStream( stream ); + } + return err; +} + + +/*******************************************************************/ +int main(void) +{ + PaError err; + + printf("PortAudio Test: output sine wave on each channel.\n" ); + + err = Pa_Initialize(); + if (err != paNoError) + goto done; + + err = test(1); /* 1 means interleaved. */ + if (err != paNoError) + goto done; + + err = test(0); /* 0 means not interleaved. */ + if (err != paNoError) + goto done; + + printf("Test finished.\n"); +done: + if (err) + { + fprintf(stderr, "An error occured while using the portaudio stream\n"); + fprintf(stderr, "Error number: %d\n", err ); + fprintf(stderr, "Error message: %s\n", Pa_GetErrorText(err)); + } + Pa_Terminate(); + return 0; +} diff --git a/extern/portaudio/test/patest_out_underflow.c b/extern/portaudio/test/patest_out_underflow.c new file mode 100644 index 0000000..dee90f8 --- /dev/null +++ b/extern/portaudio/test/patest_out_underflow.c @@ -0,0 +1,251 @@ +/** @file patest_out_underflow.c + @ingroup test_src + @brief Count output underflows (using paOutputUnderflow flag) + under overloaded and normal conditions. + @author Ross Bencina + @author Phil Burk +*/ +/* + * $Id$ + * + * This program uses the PortAudio Portable Audio Library. + * For more information see: http://www.portaudio.com + * Copyright (c) 1999-2004 Ross Bencina and Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +#include +#include +#include "portaudio.h" + +#define MAX_SINES (1000) +#define MAX_LOAD (1.2) +#define SAMPLE_RATE (44100) +#define FRAMES_PER_BUFFER (512) +#ifndef M_PI +#define M_PI (3.14159265) +#endif +#define TWOPI (M_PI * 2.0) + +typedef struct paTestData +{ + int sineCount; + double phases[MAX_SINES]; + int countUnderflows; + int outputUnderflowCount; +} +paTestData; + +/* This routine will be called by the PortAudio engine when audio is needed. +** It may called at interrupt level on some machines so don't do anything +** that could mess up the system like calling malloc() or free(). +*/ +static int patestCallback( const void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + const PaStreamCallbackTimeInfo* timeInfo, + PaStreamCallbackFlags statusFlags, + void *userData ) +{ + paTestData *data = (paTestData*)userData; + float *out = (float*)outputBuffer; + unsigned long i; + int j; + int finished = paContinue; + (void) timeInfo; /* Prevent unused variable warning. */ + (void) inputBuffer; /* Prevent unused variable warning. */ + + + if( data->countUnderflows && (statusFlags & paOutputUnderflow) ) + { + data->outputUnderflowCount++; + } + for( i=0; isineCount; j++ ) + { + /* Advance phase of next oscillator. */ + phase = data->phases[j]; + phase += phaseInc; + if( phase > TWOPI ) phase -= TWOPI; + + phaseInc *= 1.02; + if( phaseInc > 0.5 ) phaseInc *= 0.5; + + /* This is not a very efficient way to calc sines. */ + output += (float) sin( phase ); + data->phases[j] = phase; + } + *out++ = (float) (output / data->sineCount); + } + + return finished; +} + +/*******************************************************************/ +int main(void); +int main(void) +{ + PaStreamParameters outputParameters; + PaStream *stream; + PaError err; + int safeSineCount, stressedSineCount; + int sineCount; + int safeUnderflowCount, stressedUnderflowCount; + paTestData data = {0}; + double load; + double suggestedLatency; + + + printf("PortAudio Test: output sine waves, count underflows. SR = %d, BufSize = %d. MAX_LOAD = %f\n", + SAMPLE_RATE, FRAMES_PER_BUFFER, (float)MAX_LOAD ); + + err = Pa_Initialize(); + if( err != paNoError ) goto error; + + outputParameters.device = Pa_GetDefaultOutputDevice(); /* default output device */ + if (outputParameters.device == paNoDevice) { + fprintf(stderr,"Error: No default output device.\n"); + goto error; + } + outputParameters.channelCount = 1; /* mono output */ + outputParameters.sampleFormat = paFloat32; /* 32 bit floating point output */ + suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultLowOutputLatency; + outputParameters.suggestedLatency = suggestedLatency; + outputParameters.hostApiSpecificStreamInfo = NULL; + + err = Pa_OpenStream( + &stream, + NULL, /* no input */ + &outputParameters, + SAMPLE_RATE, + FRAMES_PER_BUFFER, + paClipOff, /* we won't output out of range samples so don't bother clipping them */ + patestCallback, + &data ); + if( err != paNoError ) goto error; + err = Pa_StartStream( stream ); + if( err != paNoError ) goto error; + + printf("Establishing load conditions...\n" ); + + /* Determine number of sines required to get to 50% */ + do + { + Pa_Sleep( 100 ); + + load = Pa_GetStreamCpuLoad( stream ); + printf("sineCount = %d, CPU load = %f\n", data.sineCount, load ); + + if( load < 0.3 ) + { + data.sineCount += 10; + } + else if( load < 0.4 ) + { + data.sineCount += 2; + } + else + { + data.sineCount += 1; + } + } + while( load < 0.5 && data.sineCount < (MAX_SINES-1)); + + safeSineCount = data.sineCount; + + /* Calculate target stress value then ramp up to that level*/ + stressedSineCount = (int) (2.0 * data.sineCount * MAX_LOAD ); + if( stressedSineCount > MAX_SINES ) + stressedSineCount = MAX_SINES; + sineCount = data.sineCount; + for( ; sineCount < stressedSineCount; sineCount+=4 ) + { + data.sineCount = sineCount; + Pa_Sleep( 100 ); + load = Pa_GetStreamCpuLoad( stream ); + printf("STRESSING: sineCount = %d, CPU load = %f\n", sineCount, load ); + } + + printf("Counting underflows for 2 seconds.\n"); + data.countUnderflows = 1; + Pa_Sleep( 2000 ); + + stressedUnderflowCount = data.outputUnderflowCount; + + data.countUnderflows = 0; + data.sineCount = safeSineCount; + + printf("Resuming safe load...\n"); + Pa_Sleep( 1500 ); + data.outputUnderflowCount = 0; + Pa_Sleep( 1500 ); + load = Pa_GetStreamCpuLoad( stream ); + printf("sineCount = %d, CPU load = %f\n", data.sineCount, load ); + + printf("Counting underflows for 5 seconds.\n"); + data.countUnderflows = 1; + Pa_Sleep( 5000 ); + + safeUnderflowCount = data.outputUnderflowCount; + + printf("Stop stream.\n"); + err = Pa_StopStream( stream ); + if( err != paNoError ) goto error; + + err = Pa_CloseStream( stream ); + if( err != paNoError ) goto error; + + Pa_Terminate(); + + printf("suggestedLatency = %f\n", suggestedLatency); + + // Report pass or fail + if( stressedUnderflowCount == 0 ) + printf("Test FAILED, no output underflows detected under stress.\n"); + else + printf("Test %s, %d expected output underflows detected under stress, " + "%d unexpected underflows detected under safe load.\n", + (safeUnderflowCount == 0) ? "PASSED" : "FAILED", + stressedUnderflowCount, safeUnderflowCount ); + + return err; +error: + Pa_Terminate(); + fprintf( stderr, "An error occured while using the portaudio stream\n" ); + fprintf( stderr, "Error number: %d\n", err ); + fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); + return err; +} diff --git a/extern/portaudio/test/patest_prime.c b/extern/portaudio/test/patest_prime.c new file mode 100644 index 0000000..045757e --- /dev/null +++ b/extern/portaudio/test/patest_prime.c @@ -0,0 +1,234 @@ +/** @file patest_prime.c + @ingroup test_src + @brief Test stream priming mode. + @author Ross Bencina http://www.audiomulch.com/~rossb +*/ + +/* + * $Id$ + * + * This program uses the PortAudio Portable Audio Library. + * For more information see: http://www.portaudio.com + * Copyright (c) 1999-2000 Ross Bencina and Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +#include +#include +#include "portaudio.h" +#include "pa_util.h" + +#define NUM_BEEPS (3) +#define SAMPLE_RATE (44100) +#define SAMPLE_PERIOD (1.0/44100.0) +#define FRAMES_PER_BUFFER (256) +#define BEEP_DURATION (400) +#define IDLE_DURATION (SAMPLE_RATE*2) /* 2 seconds */ +#define SLEEP_MSEC (50) + +#define STATE_BKG_IDLE (0) +#define STATE_BKG_BEEPING (1) + +typedef struct +{ + float leftPhase; + float rightPhase; + int state; + int beepCountdown; + int idleCountdown; +} +paTestData; + +static void InitializeTestData( paTestData *testData ) +{ + testData->leftPhase = 0; + testData->rightPhase = 0; + testData->state = STATE_BKG_BEEPING; + testData->beepCountdown = BEEP_DURATION; + testData->idleCountdown = IDLE_DURATION; +} + +/* This routine will be called by the PortAudio engine when audio is needed. +** It may called at interrupt level on some machines so don't do anything +** that could mess up the system like calling malloc() or free(). +*/ +static int patestCallback( const void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + const PaStreamCallbackTimeInfo *timeInfo, + PaStreamCallbackFlags statusFlags, void *userData ) +{ + /* Cast data passed through stream to our structure. */ + paTestData *data = (paTestData*)userData; + float *out = (float*)outputBuffer; + unsigned int i; + int result = paContinue; + + /* supress unused parameter warnings */ + (void) inputBuffer; + (void) timeInfo; + (void) statusFlags; + + for( i=0; istate ) + { + case STATE_BKG_IDLE: + *out++ = 0.0; /* left */ + *out++ = 0.0; /* right */ + --data->idleCountdown; + + if( data->idleCountdown <= 0 ) result = paComplete; + break; + + case STATE_BKG_BEEPING: + if( data->beepCountdown <= 0 ) + { + data->state = STATE_BKG_IDLE; + *out++ = 0.0; /* left */ + *out++ = 0.0; /* right */ + } + else + { + /* Play sawtooth wave. */ + *out++ = data->leftPhase; /* left */ + *out++ = data->rightPhase; /* right */ + /* Generate simple sawtooth phaser that ranges between -1.0 and 1.0. */ + data->leftPhase += 0.01f; + /* When signal reaches top, drop back down. */ + if( data->leftPhase >= 1.0f ) data->leftPhase -= 2.0f; + /* higher pitch so we can distinguish left and right. */ + data->rightPhase += 0.03f; + if( data->rightPhase >= 1.0f ) data->rightPhase -= 2.0f; + } + --data->beepCountdown; + break; + } + } + + return result; +} + +/*******************************************************************/ +static PaError DoTest( int flags ) +{ + PaStream *stream; + PaError err = paNoError; + paTestData data; + PaStreamParameters outputParameters; + + InitializeTestData( &data ); + + outputParameters.device = Pa_GetDefaultOutputDevice(); + if (outputParameters.device == paNoDevice) { + fprintf(stderr,"Error: No default output device.\n"); + goto error; + } + outputParameters.channelCount = 2; + outputParameters.hostApiSpecificStreamInfo = NULL; + outputParameters.sampleFormat = paFloat32; + outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultHighOutputLatency; + + /* Open an audio I/O stream. */ + err = Pa_OpenStream( + &stream, + NULL, /* no input */ + &outputParameters, + SAMPLE_RATE, + FRAMES_PER_BUFFER, /* frames per buffer */ + paClipOff | flags, /* we won't output out of range samples so don't bother clipping them */ + patestCallback, + &data ); + if( err != paNoError ) goto error; + + + err = Pa_StartStream( stream ); + if( err != paNoError ) goto error; + + printf("hear \"BEEP\"\n" ); + fflush(stdout); + + while( ( err = Pa_IsStreamActive( stream ) ) == 1 ) Pa_Sleep(SLEEP_MSEC); + if( err < 0 ) goto error; + + err = Pa_StopStream( stream ); + if( err != paNoError ) goto error; + + err = Pa_CloseStream( stream ); + if( err != paNoError ) goto error; + + return err; +error: + return err; +} + +/*******************************************************************/ +int main(void); +int main(void) +{ + PaError err = paNoError; + int i; + + /* Initialize library before making any other calls. */ + err = Pa_Initialize(); + if( err != paNoError ) goto error; + + printf("PortAudio Test: Testing stream playback with no priming.\n"); + printf("PortAudio Test: you should see BEEP before you hear it.\n"); + printf("BEEP %d times.\n", NUM_BEEPS ); + + for( i=0; i< NUM_BEEPS; ++i ) + { + err = DoTest( 0 ); + if( err != paNoError ) + goto error; + } + + printf("PortAudio Test: Testing stream playback with priming.\n"); + printf("PortAudio Test: you should see BEEP around the same time you hear it.\n"); + for( i=0; i< NUM_BEEPS; ++i ) + { + err = DoTest( paPrimeOutputBuffersUsingStreamCallback ); + if( err != paNoError ) + goto error; + } + + printf("Test finished.\n"); + + Pa_Terminate(); + return err; +error: + Pa_Terminate(); + fprintf( stderr, "An error occured while using the portaudio stream\n" ); + fprintf( stderr, "Error number: %d\n", err ); + fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); + return err; +} diff --git a/extern/portaudio/test/patest_read_record.c b/extern/portaudio/test/patest_read_record.c new file mode 100644 index 0000000..e8e5561 --- /dev/null +++ b/extern/portaudio/test/patest_read_record.c @@ -0,0 +1,244 @@ +/** @file patest_read_record.c + @ingroup test_src + @brief Record input into an array; Save array to a file; Playback recorded + data. Implemented using the blocking API (Pa_ReadStream(), Pa_WriteStream() ) + @author Phil Burk http://www.softsynth.com + @author Ross Bencina rossb@audiomulch.com +*/ +/* + * $Id$ + * + * This program uses the PortAudio Portable Audio Library. + * For more information see: http://www.portaudio.com + * Copyright (c) 1999-2000 Ross Bencina and Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +#include +#include +#include "portaudio.h" + +/* #define SAMPLE_RATE (17932) // Test failure to open with this value. */ +#define SAMPLE_RATE (44100) +#define FRAMES_PER_BUFFER (1024) +#define NUM_SECONDS (5) +#define NUM_CHANNELS (2) +/* #define DITHER_FLAG (paDitherOff) */ +#define DITHER_FLAG (0) /**/ + +/* Select sample format. */ +#if 1 +#define PA_SAMPLE_TYPE paFloat32 +typedef float SAMPLE; +#define SAMPLE_SILENCE (0.0f) +#define PRINTF_S_FORMAT "%.8f" +#elif 1 +#define PA_SAMPLE_TYPE paInt16 +typedef short SAMPLE; +#define SAMPLE_SILENCE (0) +#define PRINTF_S_FORMAT "%d" +#elif 0 +#define PA_SAMPLE_TYPE paInt8 +typedef char SAMPLE; +#define SAMPLE_SILENCE (0) +#define PRINTF_S_FORMAT "%d" +#else +#define PA_SAMPLE_TYPE paUInt8 +typedef unsigned char SAMPLE; +#define SAMPLE_SILENCE (128) +#define PRINTF_S_FORMAT "%d" +#endif + + +/*******************************************************************/ +int main(void); +int main(void) +{ + PaStreamParameters inputParameters, outputParameters; + PaStream *stream; + PaError err; + SAMPLE *recordedSamples; + int i; + int totalFrames; + int numSamples; + int numBytes; + SAMPLE max, average, val; + + + printf("patest_read_record.c\n"); fflush(stdout); + + totalFrames = NUM_SECONDS * SAMPLE_RATE; /* Record for a few seconds. */ + numSamples = totalFrames * NUM_CHANNELS; + + numBytes = numSamples * sizeof(SAMPLE); + recordedSamples = (SAMPLE *) malloc( numBytes ); + if( recordedSamples == NULL ) + { + printf("Could not allocate record array.\n"); + exit(1); + } + for( i=0; idefaultLowInputLatency; + inputParameters.hostApiSpecificStreamInfo = NULL; + + /* Record some audio. -------------------------------------------- */ + err = Pa_OpenStream( + &stream, + &inputParameters, + NULL, /* &outputParameters, */ + SAMPLE_RATE, + FRAMES_PER_BUFFER, + paClipOff, /* we won't output out of range samples so don't bother clipping them */ + NULL, /* no callback, use blocking API */ + NULL ); /* no callback, so no callback userData */ + if( err != paNoError ) goto error; + + err = Pa_StartStream( stream ); + if( err != paNoError ) goto error; + printf("Now recording!!\n"); fflush(stdout); + + err = Pa_ReadStream( stream, recordedSamples, totalFrames ); + if( err != paNoError ) goto error; + + err = Pa_CloseStream( stream ); + if( err != paNoError ) goto error; + + /* Measure maximum peak amplitude. */ + max = 0; + average = 0; + for( i=0; i max ) + { + max = val; + } + average += val; + } + + average = average / numSamples; + + printf("Sample max amplitude = "PRINTF_S_FORMAT"\n", max ); + printf("Sample average = "PRINTF_S_FORMAT"\n", average ); +/* Was as below. Better choose at compile time because this + keeps generating compiler-warnings: + if( PA_SAMPLE_TYPE == paFloat32 ) + { + printf("sample max amplitude = %f\n", max ); + printf("sample average = %f\n", average ); + } + else + { + printf("sample max amplitude = %d\n", max ); + printf("sample average = %d\n", average ); + } +*/ + /* Write recorded data to a file. */ +#if 0 + { + FILE *fid; + fid = fopen("recorded.raw", "wb"); + if( fid == NULL ) + { + printf("Could not open file."); + } + else + { + fwrite( recordedSamples, NUM_CHANNELS * sizeof(SAMPLE), totalFrames, fid ); + fclose( fid ); + printf("Wrote data to 'recorded.raw'\n"); + } + } +#endif + + /* Playback recorded data. -------------------------------------------- */ + + outputParameters.device = Pa_GetDefaultOutputDevice(); /* default output device */ + if (outputParameters.device == paNoDevice) { + fprintf(stderr,"Error: No default output device.\n"); + goto error; + } + outputParameters.channelCount = NUM_CHANNELS; + outputParameters.sampleFormat = PA_SAMPLE_TYPE; + outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultLowOutputLatency; + outputParameters.hostApiSpecificStreamInfo = NULL; + + printf("Begin playback.\n"); fflush(stdout); + err = Pa_OpenStream( + &stream, + NULL, /* no input */ + &outputParameters, + SAMPLE_RATE, + FRAMES_PER_BUFFER, + paClipOff, /* we won't output out of range samples so don't bother clipping them */ + NULL, /* no callback, use blocking API */ + NULL ); /* no callback, so no callback userData */ + if( err != paNoError ) goto error; + + if( stream ) + { + err = Pa_StartStream( stream ); + if( err != paNoError ) goto error; + printf("Waiting for playback to finish.\n"); fflush(stdout); + + err = Pa_WriteStream( stream, recordedSamples, totalFrames ); + if( err != paNoError ) goto error; + + err = Pa_CloseStream( stream ); + if( err != paNoError ) goto error; + printf("Done.\n"); fflush(stdout); + } + free( recordedSamples ); + + Pa_Terminate(); + return 0; + +error: + Pa_Terminate(); + fprintf( stderr, "An error occured while using the portaudio stream\n" ); + fprintf( stderr, "Error number: %d\n", err ); + fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); + return -1; +} + diff --git a/extern/portaudio/test/patest_ringmix.c b/extern/portaudio/test/patest_ringmix.c new file mode 100644 index 0000000..2b365fb --- /dev/null +++ b/extern/portaudio/test/patest_ringmix.c @@ -0,0 +1,86 @@ +/** @file patest_ringmix.c + @ingroup test_src + @brief Ring modulate inputs to left output, mix inputs to right output. +*/ +/* + * $Id$ + * + * This program uses the PortAudio Portable Audio Library. + * For more information see: http://www.portaudio.com + * Copyright (c) 1999-2000 Ross Bencina and Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + + +#include "stdio.h" +#include "portaudio.h" +/* This will be called asynchronously by the PortAudio engine. */ +static int myCallback( const void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + const PaStreamCallbackTimeInfo* timeInfo, + PaStreamCallbackFlags statusFlags, + void *userData ) +{ + const float *in = (const float *) inputBuffer; + float *out = (float *) outputBuffer; + float leftInput, rightInput; + unsigned int i; + + /* Read input buffer, process data, and fill output buffer. */ + for( i=0; i +*/ +/* + * $Id$ + * + * This program uses the PortAudio Portable Audio Library. + * For more information see: http://www.portaudio.com + * Copyright (c) 1999-2000 Ross Bencina and Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +#include +#include +#include "portaudio.h" + +#define NUM_SECONDS (8) +#define SAMPLE_RATE (44100) +#define TABLE_SIZE (200) +#define TEST_UNSIGNED (0) + +#if TEST_UNSIGNED +#define TEST_FORMAT paUInt8 +typedef unsigned char sample_t; +#define SILENCE ((sample_t)0x80) +#else +#define TEST_FORMAT paInt8 +typedef char sample_t; +#define SILENCE ((sample_t)0x00) +#endif + +#ifndef M_PI +#define M_PI (3.14159265) +#endif + +typedef struct +{ + sample_t sine[TABLE_SIZE]; + int left_phase; + int right_phase; + unsigned int framesToGo; +} +paTestData; + +/* This routine will be called by the PortAudio engine when audio is needed. +** It may called at interrupt level on some machines so don't do anything +** that could mess up the system like calling malloc() or free(). +*/ +static int patestCallback( const void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + const PaStreamCallbackTimeInfo* timeInfo, + PaStreamCallbackFlags statusFlags, + void *userData ) +{ + paTestData *data = (paTestData*)userData; + sample_t *out = (sample_t*)outputBuffer; + int i; + int framesToCalc; + int finished = 0; + (void) inputBuffer; /* Prevent unused variable warnings. */ + + if( data->framesToGo < framesPerBuffer ) + { + framesToCalc = data->framesToGo; + data->framesToGo = 0; + finished = 1; + } + else + { + framesToCalc = framesPerBuffer; + data->framesToGo -= framesPerBuffer; + } + + for( i=0; isine[data->left_phase]; /* left */ + *out++ = data->sine[data->right_phase]; /* right */ + data->left_phase += 1; + if( data->left_phase >= TABLE_SIZE ) data->left_phase -= TABLE_SIZE; + data->right_phase += 3; /* higher pitch so we can distinguish left and right. */ + if( data->right_phase >= TABLE_SIZE ) data->right_phase -= TABLE_SIZE; + } + /* zero remainder of final buffer */ + for( ; i<(int)framesPerBuffer; i++ ) + { + *out++ = SILENCE; /* left */ + *out++ = SILENCE; /* right */ + } + return finished; +} + +/*******************************************************************/ +int main(void); +int main(void) +{ + PaStreamParameters outputParameters; + PaStream* stream; + PaError err; + paTestData data; + PaTime streamOpened; + int i, totalSamps; + +#if TEST_UNSIGNED + printf("PortAudio Test: output UNsigned 8 bit sine wave.\n"); +#else + printf("PortAudio Test: output signed 8 bit sine wave.\n"); +#endif + /* initialise sinusoidal wavetable */ + for( i=0; idefaultLowOutputLatency; + outputParameters.hostApiSpecificStreamInfo = NULL; + err = Pa_OpenStream( &stream, + NULL, /* No input. */ + &outputParameters, + SAMPLE_RATE, + 256, /* Frames per buffer. */ + paClipOff, /* We won't output out of range samples so don't bother clipping them. */ + patestCallback, + &data ); + if( err != paNoError ) + goto error; + + streamOpened = Pa_GetStreamTime( stream ); /* Time in seconds when stream was opened (approx). */ + + err = Pa_StartStream( stream ); + if( err != paNoError ) + goto error; + + /* Watch until sound is halfway finished. */ + /* (Was ( Pa_StreamTime( stream ) < (totalSamps/2) ) in V18. */ + while( (Pa_GetStreamTime( stream ) - streamOpened) < (PaTime)NUM_SECONDS / 2.0 ) + Pa_Sleep(10); + + /* Stop sound. */ + printf("Stopping Stream.\n"); + err = Pa_StopStream( stream ); + if( err != paNoError ) + goto error; + + printf("Pause for 2 seconds.\n"); + Pa_Sleep( 2000 ); + + printf("Starting again.\n"); + err = Pa_StartStream( stream ); + if( err != paNoError ) + goto error; + + printf("Waiting for sound to finish.\n"); + + while( ( err = Pa_IsStreamActive( stream ) ) == 1 ) + Pa_Sleep(100); + if( err < 0 ) + goto error; + + err = Pa_CloseStream( stream ); + if( err != paNoError ) + goto error; + + Pa_Terminate(); + printf("Test finished.\n"); + return err; +error: + Pa_Terminate(); + fprintf( stderr, "An error occured while using the portaudio stream\n" ); + fprintf( stderr, "Error number: %d\n", err ); + fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); + return err; +} diff --git a/extern/portaudio/test/patest_sine_channelmaps.c b/extern/portaudio/test/patest_sine_channelmaps.c new file mode 100644 index 0000000..3d0d4c0 --- /dev/null +++ b/extern/portaudio/test/patest_sine_channelmaps.c @@ -0,0 +1,190 @@ +/* + * patest_sine_channelmaps.c + * + * This program uses the PortAudio Portable Audio Library. + * For more information see: http://www.portaudio.com/ + * Copyright (c) 1999-2000 Ross Bencina and Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +/** @file patest_sine_channelmaps.c + @ingroup test_src + @brief Plays sine waves using sme simple channel maps. + Designed for use with CoreAudio, but should made to work with other APIs + @author Bjorn Roche + @author Ross Bencina + @author Phil Burk +*/ + +#include +#include +#include "portaudio.h" + +#ifdef __APPLE__ +#include "pa_mac_core.h" +#endif + +#define NUM_SECONDS (5) +#define SAMPLE_RATE (44100) +#define FRAMES_PER_BUFFER (64) + +#ifndef M_PI +#define M_PI (3.14159265) +#endif + +#define TABLE_SIZE (200) +typedef struct +{ + float sine[TABLE_SIZE]; + int left_phase; + int right_phase; +} +paTestData; + +/* This routine will be called by the PortAudio engine when audio is needed. +** It may called at interrupt level on some machines so don't do anything +** that could mess up the system like calling malloc() or free(). +*/ +static int patestCallback( const void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + const PaStreamCallbackTimeInfo* timeInfo, + PaStreamCallbackFlags statusFlags, + void *userData ) +{ + paTestData *data = (paTestData*)userData; + float *out = (float*)outputBuffer; + unsigned long i; + + (void) timeInfo; /* Prevent unused variable warnings. */ + (void) statusFlags; + (void) inputBuffer; + + for( i=0; isine[data->left_phase]; /* left */ + *out++ = data->sine[data->right_phase]; /* right */ + data->left_phase += 1; + if( data->left_phase >= TABLE_SIZE ) data->left_phase -= TABLE_SIZE; + data->right_phase += 3; /* higher pitch so we can distinguish left and right. */ + if( data->right_phase >= TABLE_SIZE ) data->right_phase -= TABLE_SIZE; + } + + return paContinue; +} + +/*******************************************************************/ +int main(void); +int main(void) +{ + PaStreamParameters outputParameters; + PaStream *stream; + PaError err; + paTestData data; +#ifdef __APPLE__ + PaMacCoreStreamInfo macInfo; + const SInt32 channelMap[4] = { -1, -1, 0, 1 }; +#endif + int i; + + + printf("PortAudio Test: output sine wave. SR = %d, BufSize = %d\n", SAMPLE_RATE, FRAMES_PER_BUFFER); + printf("Output will be mapped to channels 2 and 3 instead of 0 and 1.\n"); + + /* initialise sinusoidal wavetable */ + for( i=0; idefaultLowOutputLatency; +#ifdef __APPLE__ + outputParameters.hostApiSpecificStreamInfo = &macInfo; +#else + outputParameters.hostApiSpecificStreamInfo = NULL; +#endif + + err = Pa_OpenStream( + &stream, + NULL, /* no input */ + &outputParameters, + SAMPLE_RATE, + FRAMES_PER_BUFFER, + paClipOff, /* we won't output out of range samples so don't bother clipping them */ + patestCallback, + &data ); + if( err != paNoError ) goto error; + + err = Pa_StartStream( stream ); + if( err != paNoError ) goto error; + + printf("Play for %d seconds.\n", NUM_SECONDS ); + Pa_Sleep( NUM_SECONDS * 1000 ); + + err = Pa_StopStream( stream ); + if( err != paNoError ) goto error; + + err = Pa_CloseStream( stream ); + if( err != paNoError ) goto error; + + Pa_Terminate(); + printf("Test finished.\n"); + + return err; +error: + Pa_Terminate(); + fprintf( stderr, "An error occured while using the portaudio stream\n" ); + fprintf( stderr, "Error number: %d\n", err ); + fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); + return err; +} diff --git a/extern/portaudio/test/patest_sine_formats.c b/extern/portaudio/test/patest_sine_formats.c new file mode 100644 index 0000000..5d01155 --- /dev/null +++ b/extern/portaudio/test/patest_sine_formats.c @@ -0,0 +1,203 @@ +/** @file patest_sine_formats.c + @ingroup test_src + @brief Play a sine wave for several seconds. Test various data formats. + @author Phil Burk +*/ +/* + * $Id$ + * + * This program uses the PortAudio Portable Audio Library. + * For more information see: http://www.portaudio.com + * Copyright (c) 1999-2000 Ross Bencina and Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ +#include +#include +#include "portaudio.h" + +#define NUM_SECONDS (10) +#define SAMPLE_RATE (44100) +#define FRAMES_PER_BUFFER (512) +#define LEFT_FREQ (SAMPLE_RATE/256.0) /* So we hit 1.0 */ +#define RIGHT_FREQ (500.0) +#define AMPLITUDE (1.0) + +/* Select ONE format for testing. */ +#define TEST_UINT8 (0) +#define TEST_INT8 (0) +#define TEST_INT16 (1) +#define TEST_FLOAT32 (0) + +#if TEST_UINT8 +#define TEST_FORMAT paUInt8 +typedef unsigned char SAMPLE_t; +#define SAMPLE_ZERO (0x80) +#define DOUBLE_TO_SAMPLE(x) (SAMPLE_ZERO + (SAMPLE_t)(127.0 * (x))) +#define FORMAT_NAME "Unsigned 8 Bit" + +#elif TEST_INT8 +#define TEST_FORMAT paInt8 +typedef char SAMPLE_t; +#define SAMPLE_ZERO (0) +#define DOUBLE_TO_SAMPLE(x) (SAMPLE_ZERO + (SAMPLE_t)(127.0 * (x))) +#define FORMAT_NAME "Signed 8 Bit" + +#elif TEST_INT16 +#define TEST_FORMAT paInt16 +typedef short SAMPLE_t; +#define SAMPLE_ZERO (0) +#define DOUBLE_TO_SAMPLE(x) (SAMPLE_ZERO + (SAMPLE_t)(32767 * (x))) +#define FORMAT_NAME "Signed 16 Bit" + +#elif TEST_FLOAT32 +#define TEST_FORMAT paFloat32 +typedef float SAMPLE_t; +#define SAMPLE_ZERO (0.0) +#define DOUBLE_TO_SAMPLE(x) ((SAMPLE_t)(x)) +#define FORMAT_NAME "Float 32 Bit" +#endif + +#ifndef M_PI +#define M_PI (3.14159265) +#endif + + +typedef struct +{ + double left_phase; + double right_phase; + unsigned int framesToGo; +} +paTestData; +/* This routine will be called by the PortAudio engine when audio is needed. +** It may called at interrupt level on some machines so don't do anything +** that could mess up the system like calling malloc() or free(). +*/ +static int patestCallback( const void *inputBuffer, + void *outputBuffer, + unsigned long framesPerBuffer, + const PaStreamCallbackTimeInfo* timeInfo, + PaStreamCallbackFlags statusFlags, + void *userData ) +{ + paTestData *data = (paTestData*)userData; + SAMPLE_t *out = (SAMPLE_t *)outputBuffer; + int i; + int framesToCalc; + int finished = 0; + (void) inputBuffer; /* Prevent unused variable warnings. */ + + if( data->framesToGo < framesPerBuffer ) + { + framesToCalc = data->framesToGo; + data->framesToGo = 0; + finished = 1; + } + else + { + framesToCalc = framesPerBuffer; + data->framesToGo -= framesPerBuffer; + } + + for( i=0; ileft_phase += (LEFT_FREQ / SAMPLE_RATE); + if( data->left_phase > 1.0) data->left_phase -= 1.0; + *out++ = DOUBLE_TO_SAMPLE( AMPLITUDE * sin( (data->left_phase * M_PI * 2. ))); + + data->right_phase += (RIGHT_FREQ / SAMPLE_RATE); + if( data->right_phase > 1.0) data->right_phase -= 1.0; + *out++ = DOUBLE_TO_SAMPLE( AMPLITUDE * sin( (data->right_phase * M_PI * 2. ))); + } + /* zero remainder of final buffer */ + for( ; i<(int)framesPerBuffer; i++ ) + { + *out++ = SAMPLE_ZERO; /* left */ + *out++ = SAMPLE_ZERO; /* right */ + } + return finished; +} +/*******************************************************************/ +int main(void); +int main(void) +{ + PaStream *stream; + PaStreamParameters outputParameters; + PaError err; + paTestData data; + int totalSamps; + + printf("PortAudio Test: output " FORMAT_NAME "\n"); + + data.left_phase = data.right_phase = 0.0; + data.framesToGo = totalSamps = NUM_SECONDS * SAMPLE_RATE; /* Play for a few seconds. */ + err = Pa_Initialize(); + if( err != paNoError ) goto error; + + + outputParameters.device = Pa_GetDefaultOutputDevice(); /* Default output device. */ + outputParameters.channelCount = 2; /* Stereo output */ + outputParameters.sampleFormat = TEST_FORMAT; /* Selected above. */ + outputParameters.suggestedLatency = Pa_GetDeviceInfo(outputParameters.device)->defaultLowOutputLatency; + outputParameters.hostApiSpecificStreamInfo = NULL; + err = Pa_OpenStream( &stream, + NULL, /* No input. */ + &outputParameters, /* As above. */ + SAMPLE_RATE, + FRAMES_PER_BUFFER, + paClipOff, /* we won't output out of range samples so don't bother clipping them */ + patestCallback, + &data ); + if( err != paNoError ) goto error; + + err = Pa_StartStream( stream ); + if( err != paNoError ) goto error; + + printf("Waiting %d seconds for sound to finish.\n", NUM_SECONDS ); + + while( ( err = Pa_IsStreamActive( stream ) ) == 1 ) Pa_Sleep(100); + if( err < 0 ) goto error; + + err = Pa_CloseStream( stream ); + if( err != paNoError ) goto error; + Pa_Terminate(); + + printf("PortAudio Test Finished: " FORMAT_NAME "\n"); + + return err; +error: + Pa_Terminate(); + fprintf( stderr, "An error occured while using the portaudio stream\n" ); + fprintf( stderr, "Error number: %d\n", err ); + fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); + return err; +} diff --git a/extern/portaudio/test/patest_sine_srate.c b/extern/portaudio/test/patest_sine_srate.c new file mode 100644 index 0000000..106a972 --- /dev/null +++ b/extern/portaudio/test/patest_sine_srate.c @@ -0,0 +1,182 @@ +/* + * $Id: patest_sine.c 1097 2006-08-26 08:27:53Z rossb $ + * + * This program uses the PortAudio Portable Audio Library. + * For more information see: http://www.portaudio.com/ + * Copyright (c) 1999-2000 Ross Bencina and Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +/** @file patest_sine_srate_mac.c + @ingroup test_src + @brief Plays sine waves at 44100 and 48000, + and forces the hardware to change if this is a mac. + Designed for use with CoreAudio. + @author Bjorn Roche + @author Ross Bencina + @author Phil Burk +*/ + +#include +#include +#include "portaudio.h" + +#ifdef __APPLE__ +#include "pa_mac_core.h" +#endif + +#define NUM_SECONDS (5) +#define SAMPLE_RATE1 (44100) +#define SAMPLE_RATE2 (48000) +#define FRAMES_PER_BUFFER (64) + +#ifndef M_PI +#define M_PI (3.14159265) +#endif + +#define TABLE_SIZE (200) +typedef struct +{ + float sine[TABLE_SIZE]; + int left_phase; + int right_phase; +} +paTestData; + +/* This routine will be called by the PortAudio engine when audio is needed. +** It may called at interrupt level on some machines so don't do anything +** that could mess up the system like calling malloc() or free(). +*/ +static int patestCallback( const void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + const PaStreamCallbackTimeInfo* timeInfo, + PaStreamCallbackFlags statusFlags, + void *userData ) +{ + paTestData *data = (paTestData*)userData; + float *out = (float*)outputBuffer; + unsigned long i; + + (void) timeInfo; /* Prevent unused variable warnings. */ + (void) statusFlags; + (void) inputBuffer; + + for( i=0; isine[data->left_phase]; /* left */ + *out++ = data->sine[data->right_phase]; /* right */ + data->left_phase += 1; + if( data->left_phase >= TABLE_SIZE ) data->left_phase -= TABLE_SIZE; + data->right_phase += 3; /* higher pitch so we can distinguish left and right. */ + if( data->right_phase >= TABLE_SIZE ) data->right_phase -= TABLE_SIZE; + } + + return paContinue; +} + +/*******************************************************************/ +int main(void); +int main(void) +{ + PaStreamParameters outputParameters; + PaStream *stream; + PaError err; + paTestData data; +#ifdef __APPLE__ + PaMacCoreStreamInfo macInfo; +#endif + int i; + + /* initialise sinusoidal wavetable */ + for( i=0; idefaultLowOutputLatency; + /** setup host specific info */ +#ifdef __APPLE__ + PaMacCore_SetupStreamInfo( &macInfo, paMacCorePro ); + outputParameters.hostApiSpecificStreamInfo = &macInfo; +#else + printf( "Hardware SR changing not being tested on this platform.\n" ); + outputParameters.hostApiSpecificStreamInfo = NULL; +#endif + err = Pa_OpenStream( + &stream, + NULL, /* no input */ + &outputParameters, + sr, + FRAMES_PER_BUFFER, + paClipOff, /* we won't output out of range samples so don't bother clipping them */ + patestCallback, + &data ); + if( err != paNoError ) goto error; + + err = Pa_StartStream( stream ); + if( err != paNoError ) goto error; + + printf("Play for %d seconds.\n", NUM_SECONDS ); + Pa_Sleep( NUM_SECONDS * 1000 ); + + err = Pa_StopStream( stream ); + if( err != paNoError ) goto error; + + err = Pa_CloseStream( stream ); + if( err != paNoError ) goto error; + } + + Pa_Terminate(); + printf("Test finished.\n"); + + return err; +error: + Pa_Terminate(); + fprintf( stderr, "An error occured while using the portaudio stream\n" ); + fprintf( stderr, "Error number: %d\n", err ); + fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); + return err; +} diff --git a/extern/portaudio/test/patest_sine_time.c b/extern/portaudio/test/patest_sine_time.c new file mode 100644 index 0000000..0d6a1da --- /dev/null +++ b/extern/portaudio/test/patest_sine_time.c @@ -0,0 +1,219 @@ +/** @file patest_sine_time.c + @ingroup test_src + @brief Play a sine wave for several seconds, pausing in the middle. + Uses the Pa_GetStreamTime() call. + @author Ross Bencina + @author Phil Burk +*/ +/* + * $Id$ + * + * This program uses the PortAudio Portable Audio Library. + * For more information see: http://www.portaudio.com + * Copyright (c) 1999-2000 Ross Bencina and Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ +#include +#include + +#include "portaudio.h" +#include "pa_util.h" + +#define NUM_SECONDS (8) +#define SAMPLE_RATE (44100) +#define FRAMES_PER_BUFFER (64) + +#ifndef M_PI +#define M_PI (3.14159265) +#endif +#define TWOPI (M_PI * 2.0) + +#define TABLE_SIZE (200) + +typedef struct +{ + double left_phase; + double right_phase; + volatile PaTime outTime; +} +paTestData; + +/* This routine will be called by the PortAudio engine when audio is needed. +** It may called at interrupt level on some machines so don't do anything +** that could mess up the system like calling malloc() or free(). +*/ +static int patestCallback( const void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + const PaStreamCallbackTimeInfo* timeInfo, + PaStreamCallbackFlags statusFlags, + void *userData ) +{ + paTestData *data = (paTestData*)userData; + float *out = (float*)outputBuffer; + unsigned int i; + + double left_phaseInc = 0.02; + double right_phaseInc = 0.06; + + double left_phase = data->left_phase; + double right_phase = data->right_phase; + + (void) statusFlags; /* Prevent unused variable warnings. */ + (void) inputBuffer; + + data->outTime = timeInfo->outputBufferDacTime; + + for( i=0; i TWOPI ) left_phase -= TWOPI; + *out++ = (float) sin( left_phase ); + + right_phase += right_phaseInc; + if( right_phase > TWOPI ) right_phase -= TWOPI; + *out++ = (float) sin( right_phase ); + } + + data->left_phase = left_phase; + data->right_phase = right_phase; + + return paContinue; +} + +/*******************************************************************/ +static void ReportStreamTime( PaStream *stream, paTestData *data ); +static void ReportStreamTime( PaStream *stream, paTestData *data ) +{ + PaTime streamTime, latency, outTime; + + streamTime = Pa_GetStreamTime( stream ); + outTime = data->outTime; + if( outTime < 0.0 ) + { + printf("Stream time = %8.1f\n", streamTime ); + } + else + { + latency = outTime - streamTime; + printf("Stream time = %8.4f, outTime = %8.4f, latency = %8.4f\n", + streamTime, outTime, latency ); + } + fflush(stdout); +} + +/*******************************************************************/ +int main(void); +int main(void) +{ + PaStreamParameters outputParameters; + PaStream *stream; + PaError err; + paTestData data; + PaTime startTime; + + printf("PortAudio Test: output sine wave. SR = %d, BufSize = %d\n", SAMPLE_RATE, FRAMES_PER_BUFFER); + + data.left_phase = data.right_phase = 0; + + err = Pa_Initialize(); + if( err != paNoError ) goto error; + + outputParameters.device = Pa_GetDefaultOutputDevice(); /* default output device */ + if (outputParameters.device == paNoDevice) { + fprintf(stderr,"Error: No default output device.\n"); + goto error; + } + outputParameters.channelCount = 2; /* stereo output */ + outputParameters.sampleFormat = paFloat32; /* 32 bit floating point output */ + outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultLowOutputLatency; + outputParameters.hostApiSpecificStreamInfo = NULL; + + err = Pa_OpenStream( + &stream, + NULL, /* no input */ + &outputParameters, + SAMPLE_RATE, + FRAMES_PER_BUFFER, + paClipOff, /* we won't output out of range samples so don't bother clipping them */ + patestCallback, + &data ); + if( err != paNoError ) goto error; + + /* Watch until sound is halfway finished. */ + printf("Play for %d seconds.\n", NUM_SECONDS/2 ); fflush(stdout); + + data.outTime = -1.0; /* mark time for callback as undefined */ + err = Pa_StartStream( stream ); + if( err != paNoError ) goto error; + + startTime = Pa_GetStreamTime( stream ); + + do + { + ReportStreamTime( stream, &data ); + Pa_Sleep(100); + } while( (Pa_GetStreamTime( stream ) - startTime) < (NUM_SECONDS/2) ); + + /* Stop sound for 2 seconds. */ + err = Pa_StopStream( stream ); + if( err != paNoError ) goto error; + + printf("Pause for 2 seconds.\n"); fflush(stdout); + Pa_Sleep( 2000 ); + + data.outTime = -1.0; /* mark time for callback as undefined */ + err = Pa_StartStream( stream ); + if( err != paNoError ) goto error; + + startTime = Pa_GetStreamTime( stream ); + + printf("Play until sound is finished.\n"); fflush(stdout); + do + { + ReportStreamTime( stream, &data ); + Pa_Sleep(100); + } while( (Pa_GetStreamTime( stream ) - startTime) < (NUM_SECONDS/2) ); + + err = Pa_CloseStream( stream ); + if( err != paNoError ) goto error; + + Pa_Terminate(); + printf("Test finished.\n"); + return err; + +error: + Pa_Terminate(); + fprintf( stderr, "An error occured while using the portaudio stream\n" ); + fprintf( stderr, "Error number: %d\n", err ); + fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); + return err; +} diff --git a/extern/portaudio/test/patest_start_stop.c b/extern/portaudio/test/patest_start_stop.c new file mode 100644 index 0000000..cf82b67 --- /dev/null +++ b/extern/portaudio/test/patest_start_stop.c @@ -0,0 +1,174 @@ +/** @file patest_start_stop.c + @ingroup test_src + @brief Play a sine wave for several seconds. Start and stop the stream multiple times. + + @author Ross Bencina + @author Phil Burk +*/ +/* + * $Id$ + * + * This program uses the PortAudio Portable Audio Library. + * For more information see: http://www.portaudio.com/ + * Copyright (c) 1999-2000 Ross Bencina and Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ +#include +#include +#include "portaudio.h" + +#define OUTPUT_DEVICE Pa_GetDefaultOutputDevice() /* default output device */ + +#define NUM_SECONDS (3) +#define NUM_LOOPS (4) +#define SAMPLE_RATE (44100) +#define FRAMES_PER_BUFFER (400) + +#ifndef M_PI +#define M_PI (3.14159265) +#endif + +#define TABLE_SIZE (200) +typedef struct +{ + float sine[TABLE_SIZE]; + int left_phase; + int right_phase; +} +paTestData; + +/* This routine will be called by the PortAudio engine when audio is needed. +** It may called at interrupt level on some machines so don't do anything +** that could mess up the system like calling malloc() or free(). +*/ +static int patestCallback( const void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + const PaStreamCallbackTimeInfo* timeInfo, + PaStreamCallbackFlags statusFlags, + void *userData ) +{ + paTestData *data = (paTestData*)userData; + float *out = (float*)outputBuffer; + unsigned long i; + + (void) timeInfo; /* Prevent unused variable warnings. */ + (void) statusFlags; + (void) inputBuffer; + + for( i=0; isine[data->left_phase]; /* left */ + *out++ = data->sine[data->right_phase]; /* right */ + data->left_phase += 1; + if( data->left_phase >= TABLE_SIZE ) data->left_phase -= TABLE_SIZE; + data->right_phase += 3; /* higher pitch so we can distinguish left and right. */ + if( data->right_phase >= TABLE_SIZE ) data->right_phase -= TABLE_SIZE; + } + + return paContinue; +} + +/*******************************************************************/ +int main(void); +int main(void) +{ + PaStreamParameters outputParameters; + PaStream *stream; + PaError err; + paTestData data; + int i; + + + printf("PortAudio Test: output sine wave. SR = %d, BufSize = %d\n", SAMPLE_RATE, FRAMES_PER_BUFFER); + + /* initialise sinusoidal wavetable */ + for( i=0; idefaultLowOutputLatency; + outputParameters.hostApiSpecificStreamInfo = NULL; + + err = Pa_OpenStream( + &stream, + NULL, /* no input */ + &outputParameters, + SAMPLE_RATE, + FRAMES_PER_BUFFER, + paClipOff, /* we won't output out of range samples so don't bother clipping them */ + patestCallback, + &data ); + if( err != paNoError ) goto error; + + for( i=0; i +*/ +/* + * $Id$ + * + * This program uses the PortAudio Portable Audio Library. + * For more information see: http://www.portaudio.com + * Copyright (c) 1999-2000 Ross Bencina and Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ +#include +#include +#include "portaudio.h" + +#define OUTPUT_DEVICE (Pa_GetDefaultOutputDevice()) +#define SLEEP_DUR (200) +#define SAMPLE_RATE (44100) +#define FRAMES_PER_BUFFER (256) +#define LATENCY_SECONDS (3.f) +#define FRAMES_PER_NOTE (SAMPLE_RATE/2) +#define MAX_REPEATS (2) +#define FUNDAMENTAL (400.0f / SAMPLE_RATE) +#define NOTE_0 (FUNDAMENTAL * 1.0f / 1.0f) +#define NOTE_1 (FUNDAMENTAL * 5.0f / 4.0f) +#define NOTE_2 (FUNDAMENTAL * 4.0f / 3.0f) +#define NOTE_3 (FUNDAMENTAL * 3.0f / 2.0f) +#define NOTE_4 (FUNDAMENTAL * 2.0f / 1.0f) +#define MODE_FINISH (0) +#define MODE_STOP (1) +#define MODE_ABORT (2) +#ifndef M_PI +#define M_PI (3.14159265) +#endif +#define TABLE_SIZE (400) + +typedef struct +{ + float waveform[TABLE_SIZE + 1]; /* Add one for guard point for interpolation. */ + float phase_increment; + float phase; + float *tune; + int notesPerTune; + int frameCounter; + int noteCounter; + int repeatCounter; + PaTime outTime; + int stopMode; + int done; +} +paTestData; + +/************* Prototypes *****************************/ +int TestStopMode( paTestData *data ); +float LookupWaveform( paTestData *data, float phase ); + +/****************************************************** + * Convert phase between 0.0 and 1.0 to waveform value + * using linear interpolation. + */ +float LookupWaveform( paTestData *data, float phase ) +{ + float fIndex = phase*TABLE_SIZE; + int index = (int) fIndex; + float fract = fIndex - index; + float lo = data->waveform[index]; + float hi = data->waveform[index+1]; + float val = lo + fract*(hi-lo); + return val; +} + +/* This routine will be called by the PortAudio engine when audio is needed. +** It may called at interrupt level on some machines so don't do anything +** that could mess up the system like calling malloc() or free(). +*/ +static int patestCallback( const void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + const PaStreamCallbackTimeInfo* timeInfo, + PaStreamCallbackFlags statusFlags, + void *userData ) +{ + paTestData *data = (paTestData*)userData; + float *out = (float*)outputBuffer; + float value; + unsigned int i = 0; + int finished = paContinue; + + (void) inputBuffer; /* Prevent unused variable warnings. */ + (void) timeInfo; + (void) statusFlags; + + + /* data->outTime = outTime; */ + + if( !data->done ) + { + for( i=0; iframeCounter >= FRAMES_PER_NOTE ) + { + data->noteCounter += 1; + data->frameCounter = 0; + /* Are we done with this tune? */ + if( data->noteCounter >= data->notesPerTune ) + { + data->noteCounter = 0; + data->repeatCounter += 1; + /* Are we totally done? */ + if( data->repeatCounter >= MAX_REPEATS ) + { + data->done = 1; + if( data->stopMode == MODE_FINISH ) + { + finished = paComplete; + break; + } + } + } + data->phase_increment = data->tune[data->noteCounter]; + } + value = LookupWaveform(data, data->phase); + *out++ = value; /* left */ + *out++ = value; /* right */ + data->phase += data->phase_increment; + if( data->phase >= 1.0f ) data->phase -= 1.0f; + + data->frameCounter += 1; + } + } + /* zero remainder of final buffer */ + for( ; idone = 0; + data->phase = 0.0; + data->frameCounter = 0; + data->noteCounter = 0; + data->repeatCounter = 0; + data->phase_increment = data->tune[data->noteCounter]; + + err = Pa_Initialize(); + if( err != paNoError ) goto error; + + outputParameters.device = OUTPUT_DEVICE; + if (outputParameters.device == paNoDevice) { + fprintf(stderr,"Error: No default output device.\n"); + goto error; + } + outputParameters.channelCount = 2; /* stereo output */ + outputParameters.sampleFormat = paFloat32; /* 32 bit floating point output */ + outputParameters.suggestedLatency = LATENCY_SECONDS; + outputParameters.hostApiSpecificStreamInfo = NULL; + + err = Pa_OpenStream( + &stream, + NULL, /* no input */ + &outputParameters, + SAMPLE_RATE, + FRAMES_PER_BUFFER, /* frames per buffer */ + paClipOff, /* we won't output out of range samples so don't bother clipping them */ + patestCallback, + data ); + if( err != paNoError ) goto error; + + err = Pa_StartStream( stream ); + if( err != paNoError ) goto error; + + if( data->stopMode == MODE_FINISH ) + { + while( ( err = Pa_IsStreamActive( stream ) ) == 1 ) + { + /*printf("outTime = %g, note# = %d, repeat# = %d\n", data->outTime, + data->noteCounter, data->repeatCounter ); + fflush(stdout); */ + Pa_Sleep( SLEEP_DUR ); + } + if( err < 0 ) goto error; + } + else + { + while( data->repeatCounter < MAX_REPEATS ) + { + /*printf("outTime = %g, note# = %d, repeat# = %d\n", data->outTime, + data->noteCounter, data->repeatCounter ); + fflush(stdout); */ + Pa_Sleep( SLEEP_DUR ); + } + } + + if( data->stopMode == MODE_ABORT ) + { + printf("Call Pa_AbortStream()\n"); + err = Pa_AbortStream( stream ); + } + else + { + printf("Call Pa_StopStream()\n"); + err = Pa_StopStream( stream ); + } + if( err != paNoError ) goto error; + + printf("Call Pa_CloseStream()\n"); fflush(stdout); + err = Pa_CloseStream( stream ); + if( err != paNoError ) goto error; + + Pa_Terminate(); + printf("Test finished.\n"); + + return err; + +error: + Pa_Terminate(); + fprintf( stderr, "An error occured while using the portaudio stream\n" ); + fprintf( stderr, "Error number: %d\n", err ); + fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); + return err; +} diff --git a/extern/portaudio/test/patest_stop_playout.c b/extern/portaudio/test/patest_stop_playout.c new file mode 100644 index 0000000..9a451eb --- /dev/null +++ b/extern/portaudio/test/patest_stop_playout.c @@ -0,0 +1,478 @@ +/** @file patest_stop_playout.c + @ingroup test_src + @brief Test whether all queued samples are played when Pa_StopStream() + is used with a callback or read/write stream, or when the callback + returns paComplete. + @author Ross Bencina +*/ +/* + * $Id$ + * + * This program uses the PortAudio Portable Audio Library. + * For more information see: http://www.portaudio.com/ + * Copyright (c) 1999-2004 Ross Bencina and Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ +#include +#include +#include "portaudio.h" + +#define SAMPLE_RATE (44100) +#define FRAMES_PER_BUFFER (1024) + +#define TONE_SECONDS (1) /* long tone */ +#define TONE_FADE_SECONDS (.04) /* fades at start and end of long tone */ +#define GAP_SECONDS (.25) /* gap between long tone and blip */ +#define BLIP_SECONDS (.035) /* short blip */ + +#define NUM_REPEATS (3) + +#ifndef M_PI +#define M_PI (3.14159265) +#endif + +#define TABLE_SIZE (2048) +typedef struct +{ + float sine[TABLE_SIZE+1]; + + int repeatCount; + + double phase; + double lowIncrement, highIncrement; + + int gap1Length, toneLength, toneFadesLength, gap2Length, blipLength; + int gap1Countdown, toneCountdown, gap2Countdown, blipCountdown; +} +TestData; + + +static void RetriggerTestSignalGenerator( TestData *data ) +{ + data->phase = 0.; + data->gap1Countdown = data->gap1Length; + data->toneCountdown = data->toneLength; + data->gap2Countdown = data->gap2Length; + data->blipCountdown = data->blipLength; +} + + +static void ResetTestSignalGenerator( TestData *data ) +{ + data->repeatCount = 0; + RetriggerTestSignalGenerator( data ); +} + + +static void InitTestSignalGenerator( TestData *data ) +{ + int signalLengthModBufferLength, i; + + /* initialise sinusoidal wavetable */ + for( i=0; isine[i] = (float) sin( ((double)i/(double)TABLE_SIZE) * M_PI * 2. ); + } + data->sine[TABLE_SIZE] = data->sine[0]; /* guard point for linear interpolation */ + + + + data->lowIncrement = (330. / SAMPLE_RATE) * TABLE_SIZE; + data->highIncrement = (1760. / SAMPLE_RATE) * TABLE_SIZE; + + data->gap1Length = GAP_SECONDS * SAMPLE_RATE; + data->toneLength = TONE_SECONDS * SAMPLE_RATE; + data->toneFadesLength = TONE_FADE_SECONDS * SAMPLE_RATE; + data->gap2Length = GAP_SECONDS * SAMPLE_RATE; + data->blipLength = BLIP_SECONDS * SAMPLE_RATE; + + /* adjust signal length to be a multiple of the buffer length */ + signalLengthModBufferLength = (data->gap1Length + data->toneLength + data->gap2Length + data->blipLength) % FRAMES_PER_BUFFER; + if( signalLengthModBufferLength > 0 ) + data->toneLength += signalLengthModBufferLength; + + ResetTestSignalGenerator( data ); +} + + +#define MIN( a, b ) (((a)<(b))?(a):(b)) + +static void GenerateTestSignal( TestData *data, float *stereo, int frameCount ) +{ + int framesGenerated = 0; + float output; + long index; + float fraction; + int count, i; + + while( framesGenerated < frameCount && data->repeatCount < NUM_REPEATS ) + { + if( framesGenerated < frameCount && data->gap1Countdown > 0 ){ + count = MIN( frameCount - framesGenerated, data->gap1Countdown ); + for( i=0; i < count; ++i ) + { + *stereo++ = 0.f; + *stereo++ = 0.f; + } + + data->gap1Countdown -= count; + framesGenerated += count; + } + + if( framesGenerated < frameCount && data->toneCountdown > 0 ){ + count = MIN( frameCount - framesGenerated, data->toneCountdown ); + for( i=0; i < count; ++i ) + { + /* tone with data->lowIncrement phase increment */ + index = (long)data->phase; + fraction = data->phase - index; + output = data->sine[ index ] + (data->sine[ index + 1 ] - data->sine[ index ]) * fraction; + + data->phase += data->lowIncrement; + while( data->phase >= TABLE_SIZE ) + data->phase -= TABLE_SIZE; + + /* apply fade to ends */ + + if( data->toneCountdown < data->toneFadesLength ) + { + /* cosine-bell fade out at end */ + output *= (-cos(((float)data->toneCountdown / (float)data->toneFadesLength) * M_PI) + 1.) * .5; + } + else if( data->toneCountdown > data->toneLength - data->toneFadesLength ) + { + /* cosine-bell fade in at start */ + output *= (cos(((float)(data->toneCountdown - (data->toneLength - data->toneFadesLength)) / (float)data->toneFadesLength) * M_PI) + 1.) * .5; + } + + output *= .5; /* play tone half as loud as blip */ + + *stereo++ = output; + *stereo++ = output; + + data->toneCountdown--; + } + + framesGenerated += count; + } + + if( framesGenerated < frameCount && data->gap2Countdown > 0 ){ + count = MIN( frameCount - framesGenerated, data->gap2Countdown ); + for( i=0; i < count; ++i ) + { + *stereo++ = 0.f; + *stereo++ = 0.f; + } + + data->gap2Countdown -= count; + framesGenerated += count; + } + + if( framesGenerated < frameCount && data->blipCountdown > 0 ){ + count = MIN( frameCount - framesGenerated, data->blipCountdown ); + for( i=0; i < count; ++i ) + { + /* tone with data->highIncrement phase increment */ + index = (long)data->phase; + fraction = data->phase - index; + output = data->sine[ index ] + (data->sine[ index + 1 ] - data->sine[ index ]) * fraction; + + data->phase += data->highIncrement; + while( data->phase >= TABLE_SIZE ) + data->phase -= TABLE_SIZE; + + /* cosine-bell envelope over whole blip */ + output *= (-cos( ((float)data->blipCountdown / (float)data->blipLength) * 2. * M_PI) + 1.) * .5; + + *stereo++ = output; + *stereo++ = output; + + data->blipCountdown--; + } + + framesGenerated += count; + } + + + if( data->blipCountdown == 0 ) + { + RetriggerTestSignalGenerator( data ); + data->repeatCount++; + } + } + + if( framesGenerated < frameCount ) + { + count = frameCount - framesGenerated; + for( i=0; i < count; ++i ) + { + *stereo++ = 0.f; + *stereo++ = 0.f; + } + } +} + + +static int IsTestSignalFinished( TestData *data ) +{ + if( data->repeatCount >= NUM_REPEATS ) + return 1; + else + return 0; +} + + +static int TestCallback1( const void *inputBuffer, void *outputBuffer, + unsigned long frameCount, + const PaStreamCallbackTimeInfo* timeInfo, + PaStreamCallbackFlags statusFlags, + void *userData ) +{ + (void) inputBuffer; /* Prevent unused variable warnings. */ + (void) timeInfo; + (void) statusFlags; + + GenerateTestSignal( (TestData*)userData, (float*)outputBuffer, frameCount ); + + if( IsTestSignalFinished( (TestData*)userData ) ) + return paComplete; + else + return paContinue; +} + + +volatile int testCallback2Finished = 0; + +static int TestCallback2( const void *inputBuffer, void *outputBuffer, + unsigned long frameCount, + const PaStreamCallbackTimeInfo* timeInfo, + PaStreamCallbackFlags statusFlags, + void *userData ) +{ + (void) inputBuffer; /* Prevent unused variable warnings. */ + (void) timeInfo; + (void) statusFlags; + + GenerateTestSignal( (TestData*)userData, (float*)outputBuffer, frameCount ); + + if( IsTestSignalFinished( (TestData*)userData ) ) + testCallback2Finished = 1; + + return paContinue; +} + +/*******************************************************************/ +int main(void); +int main(void) +{ + PaStreamParameters outputParameters; + PaStream *stream; + PaError err; + TestData data; + float writeBuffer[ FRAMES_PER_BUFFER * 2 ]; + + printf("PortAudio Test: check that stopping stream plays out all queued samples. SR = %d, BufSize = %d\n", SAMPLE_RATE, FRAMES_PER_BUFFER); + + InitTestSignalGenerator( &data ); + + err = Pa_Initialize(); + if( err != paNoError ) goto error; + + outputParameters.device = Pa_GetDefaultOutputDevice(); /* default output device */ + outputParameters.channelCount = 2; /* stereo output */ + outputParameters.sampleFormat = paFloat32; /* 32 bit floating point output */ + outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultHighOutputLatency; + outputParameters.hostApiSpecificStreamInfo = NULL; + +/* test paComplete ---------------------------------------------------------- */ + + ResetTestSignalGenerator( &data ); + + err = Pa_OpenStream( + &stream, + NULL, /* no input */ + &outputParameters, + SAMPLE_RATE, + FRAMES_PER_BUFFER, + paClipOff, /* we won't output out of range samples so don't bother clipping them */ + TestCallback1, + &data ); + if( err != paNoError ) goto error; + + err = Pa_StartStream( stream ); + if( err != paNoError ) goto error; + + printf("\nPlaying 'tone-blip' %d times using callback, stops by returning paComplete from callback.\n", NUM_REPEATS ); + printf("If final blip is not intact, callback+paComplete implementation may be faulty.\n\n" ); + + while( (err = Pa_IsStreamActive( stream )) == 1 ) + Pa_Sleep( 2 ); + + if( err != 0 ) goto error; + + err = Pa_StopStream( stream ); + if( err != paNoError ) goto error; + + err = Pa_CloseStream( stream ); + if( err != paNoError ) goto error; + + Pa_Sleep( 500 ); + + +/* test paComplete ---------------------------------------------------------- */ + + ResetTestSignalGenerator( &data ); + + err = Pa_OpenStream( + &stream, + NULL, /* no input */ + &outputParameters, + SAMPLE_RATE, + FRAMES_PER_BUFFER, + paClipOff, /* we won't output out of range samples so don't bother clipping them */ + TestCallback1, + &data ); + if( err != paNoError ) goto error; + + err = Pa_StartStream( stream ); + if( err != paNoError ) goto error; + + printf("\nPlaying 'tone-blip' %d times using callback, stops by returning paComplete from callback.\n", NUM_REPEATS ); + printf("If final blip is not intact or is followed by garbage, callback+paComplete implementation may be faulty.\n\n" ); + + while( (err = Pa_IsStreamActive( stream )) == 1 ) + Pa_Sleep( 5 ); + + printf("Waiting 5 seconds after paComplete before stopping the stream. Tests that buffers are flushed correctly.\n"); + Pa_Sleep( 5000 ); + + if( err != 0 ) goto error; + + err = Pa_StopStream( stream ); + if( err != paNoError ) goto error; + + err = Pa_CloseStream( stream ); + if( err != paNoError ) goto error; + + Pa_Sleep( 500 ); + + +/* test Pa_StopStream() with callback --------------------------------------- */ + + ResetTestSignalGenerator( &data ); + + testCallback2Finished = 0; + + err = Pa_OpenStream( + &stream, + NULL, /* no input */ + &outputParameters, + SAMPLE_RATE, + FRAMES_PER_BUFFER, + paClipOff, /* we won't output out of range samples so don't bother clipping them */ + TestCallback2, + &data ); + if( err != paNoError ) goto error; + + err = Pa_StartStream( stream ); + if( err != paNoError ) goto error; + + + printf("\nPlaying 'tone-blip' %d times using callback, stops by calling Pa_StopStream.\n", NUM_REPEATS ); + printf("If final blip is not intact, callback+Pa_StopStream implementation may be faulty.\n\n" ); + + /* note that polling a volatile flag is not a good way to synchronise with + the callback, but it's the best we can do portably. */ + while( !testCallback2Finished ) + Pa_Sleep( 2 ); + + Pa_Sleep( 500 ); + + err = Pa_StopStream( stream ); + if( err != paNoError ) goto error; + + + err = Pa_CloseStream( stream ); + if( err != paNoError ) goto error; + + Pa_Sleep( 500 ); + +/* test Pa_StopStream() with Pa_WriteStream --------------------------------- */ + + ResetTestSignalGenerator( &data ); + + err = Pa_OpenStream( + &stream, + NULL, /* no input */ + &outputParameters, + SAMPLE_RATE, + FRAMES_PER_BUFFER, + paClipOff, /* we won't output out of range samples so don't bother clipping them */ + NULL, /* no callback, use blocking API */ + NULL ); /* no callback, so no callback userData */ + if( err != paNoError ) goto error; + + err = Pa_StartStream( stream ); + if( err != paNoError ) goto error; + + + printf("\nPlaying 'tone-blip' %d times using Pa_WriteStream, stops by calling Pa_StopStream.\n", NUM_REPEATS ); + printf("If final blip is not intact, Pa_WriteStream+Pa_StopStream implementation may be faulty.\n\n" ); + + do{ + GenerateTestSignal( &data, writeBuffer, FRAMES_PER_BUFFER ); + err = Pa_WriteStream( stream, writeBuffer, FRAMES_PER_BUFFER ); + if( err != paNoError ) goto error; + + }while( !IsTestSignalFinished( &data ) ); + + err = Pa_StopStream( stream ); + if( err != paNoError ) goto error; + + + err = Pa_CloseStream( stream ); + if( err != paNoError ) goto error; + +/* -------------------------------------------------------------------------- */ + + Pa_Terminate(); + printf("Test finished.\n"); + + return err; + +error: + Pa_Terminate(); + fprintf( stderr, "An error occured while using the portaudio stream\n" ); + fprintf( stderr, "Error number: %d\n", err ); + fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); + return err; +} diff --git a/extern/portaudio/test/patest_suggested_vs_streaminfo_latency.c b/extern/portaudio/test/patest_suggested_vs_streaminfo_latency.c new file mode 100644 index 0000000..0b7f21d --- /dev/null +++ b/extern/portaudio/test/patest_suggested_vs_streaminfo_latency.c @@ -0,0 +1,269 @@ +/** @file patest_suggested_vs_streaminfo_latency.c + @ingroup test_src + @brief Print suggested vs. PaStreamInfo reported actual latency + @author Ross Bencina + + Opens streams with a sequence of suggested latency values + from 0 to 2 seconds in .5ms intervals and gathers the resulting actual + latency values. Output a csv file and graph suggested vs. actual. Run + with framesPerBuffer unspecified, powers of 2 and multiples of 50 and + prime number buffer sizes. +*/ +/* + * $Id: patest_sine.c 1368 2008-03-01 00:38:27Z rossb $ + * + * This program uses the PortAudio Portable Audio Library. + * For more information see: http://www.portaudio.com/ + * Copyright (c) 1999-2000 Ross Bencina and Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ +#include +#include +#include +#include +#include "portaudio.h" + +#define SAMPLE_RATE (44100) +#define FRAMES_PER_BUFFER 2//(128) +#define NUM_CHANNELS (2) + +#define SUGGESTED_LATENCY_START_SECONDS (0.0) +#define SUGGESTED_LATENCY_END_SECONDS (2.0) +#define SUGGESTED_LATENCY_INCREMENT_SECONDS (0.0005) /* half a millisecond increments */ + + +/* dummy callback. does nothing. never gets called */ +static int patestCallback( const void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + const PaStreamCallbackTimeInfo* timeInfo, + PaStreamCallbackFlags statusFlags, + void *userData ) +{ + return paContinue; +} + +/*******************************************************************/ +static void usage() +{ + int i; + const PaDeviceInfo *deviceInfo; + const char *channelString; + + fprintf( stderr, "PortAudio suggested (requested) vs. resulting (reported) stream latency test\n" ); + fprintf( stderr, "Usage: x.exe input-device-index output-device-index sample-rate frames-per-buffer\n" ); + fprintf( stderr, "Use -1 for default device index, or use one of these:\n" ); + for( i=0; i < Pa_GetDeviceCount(); ++i ){ + deviceInfo = Pa_GetDeviceInfo(i); + if( deviceInfo->maxInputChannels > 0 && deviceInfo->maxOutputChannels > 0 ) + channelString = "full-duplex"; + else if( deviceInfo->maxInputChannels > 0 ) + channelString = "input only"; + else + channelString = "output only"; + + fprintf( stderr, "%d (%s, %s, %s)\n", i, deviceInfo->name, Pa_GetHostApiInfo(deviceInfo->hostApi)->name, channelString ); + } + Pa_Terminate(); + exit(-1); +} + +int main( int argc, const char* argv[] ); +int main( int argc, const char* argv[] ) +{ + PaStreamParameters inputParameters, outputParameters; + PaStream *stream; + PaError err; + PaTime suggestedLatency; + const PaStreamInfo *streamInfo; + const PaDeviceInfo *deviceInfo; + float sampleRate = SAMPLE_RATE; + int framesPerBuffer = FRAMES_PER_BUFFER; + err = Pa_Initialize(); + if( err != paNoError ) goto error; + + if( argc > 1 && strcmp(argv[1],"-h") == 0 ) + usage(); + + if( argc > 3 ){ + sampleRate = atoi(argv[3]); + } + + if( argc > 4 ){ + framesPerBuffer = atoi(argv[4]); + } + + printf("# sample rate=%f, frames per buffer=%d\n", (float)sampleRate, framesPerBuffer ); + + inputParameters.device = -1; + if( argc > 1 ) + inputParameters.device = atoi(argv[1]); + if( inputParameters.device == -1 ){ + inputParameters.device = Pa_GetDefaultInputDevice(); + if (inputParameters.device == paNoDevice) { + fprintf(stderr,"Error: No default input device available.\n"); + goto error; + } + }else{ + deviceInfo = Pa_GetDeviceInfo(inputParameters.device); + if( !deviceInfo ){ + fprintf(stderr,"Error: Invalid input device index.\n"); + usage(); + } + if( deviceInfo->maxInputChannels == 0 ){ + fprintf(stderr,"Error: Specified input device has no input channels (an output only device?).\n"); + usage(); + } + } + + inputParameters.channelCount = NUM_CHANNELS; + inputParameters.sampleFormat = paFloat32; /* 32 bit floating point output */ + inputParameters.hostApiSpecificStreamInfo = NULL; + + deviceInfo = Pa_GetDeviceInfo(inputParameters.device); + printf( "# using input device id %d (%s, %s)\n", inputParameters.device, deviceInfo->name, Pa_GetHostApiInfo(deviceInfo->hostApi)->name ); + + + outputParameters.device = -1; + if( argc > 2 ) + outputParameters.device = atoi(argv[2]); + if( outputParameters.device == -1 ){ + outputParameters.device = Pa_GetDefaultOutputDevice(); + if (outputParameters.device == paNoDevice) { + fprintf(stderr,"Error: No default output device available.\n"); + goto error; + } + }else{ + deviceInfo = Pa_GetDeviceInfo(outputParameters.device); + if( !deviceInfo ){ + fprintf(stderr,"Error: Invalid output device index.\n"); + usage(); + } + if( deviceInfo->maxOutputChannels == 0 ){ + fprintf(stderr,"Error: Specified output device has no output channels (an input only device?).\n"); + usage(); + } + } + + outputParameters.channelCount = NUM_CHANNELS; + outputParameters.sampleFormat = paFloat32; /* 32 bit floating point output */ + outputParameters.hostApiSpecificStreamInfo = NULL; + + deviceInfo = Pa_GetDeviceInfo(outputParameters.device); + printf( "# using output device id %d (%s, %s)\n", outputParameters.device, deviceInfo->name, Pa_GetHostApiInfo(deviceInfo->hostApi)->name ); + + + printf( "# suggested latency, half duplex PaStreamInfo::outputLatency, half duplex PaStreamInfo::inputLatency, full duplex PaStreamInfo::outputLatency, full duplex PaStreamInfo::inputLatency\n" ); + suggestedLatency = SUGGESTED_LATENCY_START_SECONDS; + while( suggestedLatency <= SUGGESTED_LATENCY_END_SECONDS ){ + + outputParameters.suggestedLatency = suggestedLatency; + inputParameters.suggestedLatency = suggestedLatency; + + printf( "%f, ", suggestedLatency ); + + /* ------------------------------ output ------------------------------ */ + + err = Pa_OpenStream( + &stream, + NULL, /* no input */ + &outputParameters, + sampleRate, + framesPerBuffer, + paClipOff, /* we won't output out of range samples so don't bother clipping them */ + patestCallback, + 0 ); + if( err != paNoError ) goto error; + + streamInfo = Pa_GetStreamInfo( stream ); + + printf( "%f,", streamInfo->outputLatency ); + + err = Pa_CloseStream( stream ); + if( err != paNoError ) goto error; + + /* ------------------------------ input ------------------------------ */ + + err = Pa_OpenStream( + &stream, + &inputParameters, + NULL, /* no output */ + sampleRate, + framesPerBuffer, + paClipOff, /* we won't output out of range samples so don't bother clipping them */ + patestCallback, + 0 ); + if( err != paNoError ) goto error; + + streamInfo = Pa_GetStreamInfo( stream ); + + printf( "%f,", streamInfo->inputLatency ); + + err = Pa_CloseStream( stream ); + if( err != paNoError ) goto error; + + /* ------------------------------ full duplex ------------------------------ */ + + err = Pa_OpenStream( + &stream, + &inputParameters, + &outputParameters, + sampleRate, + framesPerBuffer, + paClipOff, /* we won't output out of range samples so don't bother clipping them */ + patestCallback, + 0 ); + if( err != paNoError ) goto error; + + streamInfo = Pa_GetStreamInfo( stream ); + + printf( "%f,%f", streamInfo->outputLatency, streamInfo->inputLatency ); + + err = Pa_CloseStream( stream ); + if( err != paNoError ) goto error; + + /* ------------------------------------------------------------ */ + + printf( "\n" ); + suggestedLatency += SUGGESTED_LATENCY_INCREMENT_SECONDS; + } + + Pa_Terminate(); + printf("# Test finished.\n"); + + return err; +error: + Pa_Terminate(); + fprintf( stderr, "An error occured while using the portaudio stream\n" ); + fprintf( stderr, "Error number: %d\n", err ); + fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); + return err; +} diff --git a/extern/portaudio/test/patest_suggested_vs_streaminfo_latency.py b/extern/portaudio/test/patest_suggested_vs_streaminfo_latency.py new file mode 100644 index 0000000..46c7434 --- /dev/null +++ b/extern/portaudio/test/patest_suggested_vs_streaminfo_latency.py @@ -0,0 +1,150 @@ +#!/usr/bin/env python +""" + +Run and graph the results of patest_suggested_vs_streaminfo_latency.c + +Requires matplotlib for plotting: http://matplotlib.sourceforge.net/ + +""" +import os +from pylab import * +import numpy +from matplotlib.backends.backend_pdf import PdfPages + +testExeName = "PATest.exe" # rename to whatever the compiled patest_suggested_vs_streaminfo_latency.c binary is +dataFileName = "patest_suggested_vs_streaminfo_latency.csv" # code below calls the exe to generate this file + +inputDeviceIndex = -1 # -1 means default +outputDeviceIndex = -1 # -1 means default +sampleRate = 44100 +pdfFilenameSuffix = "_wmme" + +pdfFile = PdfPages("patest_suggested_vs_streaminfo_latency_" + str(sampleRate) + pdfFilenameSuffix +".pdf") #output this pdf file + + +def loadCsvData( dataFileName ): + params= "" + inputDevice = "" + outputDevice = "" + + startLines = file(dataFileName).readlines(1024) + for line in startLines: + if "output device" in line: + outputDevice = line.strip(" \t\n\r#") + if "input device" in line: + inputDevice = line.strip(" \t\n\r#") + params = startLines[0].strip(" \t\n\r#") + + data = numpy.loadtxt(dataFileName, delimiter=",", skiprows=4).transpose() + + class R(object): pass + result = R() + result.params = params + for s in params.split(','): + if "sample rate" in s: + result.sampleRate = s + + result.inputDevice = inputDevice + result.outputDevice = outputDevice + result.suggestedLatency = data[0] + result.halfDuplexOutputLatency = data[1] + result.halfDuplexInputLatency = data[2] + result.fullDuplexOutputLatency = data[3] + result.fullDuplexInputLatency = data[4] + return result; + + +def setFigureTitleAndAxisLabels( framesPerBufferString ): + title("PortAudio suggested (requested) vs. resulting (reported) stream latency\n" + framesPerBufferString) + ylabel("PaStreamInfo::{input,output}Latency (s)") + xlabel("Pa_OpenStream suggestedLatency (s)") + grid(True) + legend(loc="upper left") + +def setDisplayRangeSeconds( maxSeconds ): + xlim(0, maxSeconds) + ylim(0, maxSeconds) + + +# run the test with different frames per buffer values: + +compositeTestFramesPerBufferValues = [0] +# powers of two +for i in range (1,11): + compositeTestFramesPerBufferValues.append( pow(2,i) ) + +# multiples of 50 +for i in range (1,20): + compositeTestFramesPerBufferValues.append( i * 50 ) + +# 10ms buffer sizes +compositeTestFramesPerBufferValues.append( 441 ) +compositeTestFramesPerBufferValues.append( 882 ) + +# large primes +#compositeTestFramesPerBufferValues.append( 39209 ) +#compositeTestFramesPerBufferValues.append( 37537 ) +#compositeTestFramesPerBufferValues.append( 26437 ) + +individualPlotFramesPerBufferValues = [0,64,128,256,512] #output separate plots for these + +isFirst = True + +for framesPerBuffer in compositeTestFramesPerBufferValues: + commandString = testExeName + " " + str(inputDeviceIndex) + " " + str(outputDeviceIndex) + " " + str(sampleRate) + " " + str(framesPerBuffer) + ' > ' + dataFileName + print commandString + os.system(commandString) + + d = loadCsvData(dataFileName) + + if isFirst: + figure(1) # title sheet + gcf().text(0.1, 0.0, + "patest_suggested_vs_streaminfo_latency\n%s\n%s\n%s\n"%(d.inputDevice,d.outputDevice,d.sampleRate)) + pdfFile.savefig() + + + figure(2) # composite plot, includes all compositeTestFramesPerBufferValues + + if isFirst: + plot( d.suggestedLatency, d.suggestedLatency, label="Suggested latency" ) + + plot( d.suggestedLatency, d.halfDuplexOutputLatency ) + plot( d.suggestedLatency, d.halfDuplexInputLatency ) + plot( d.suggestedLatency, d.fullDuplexOutputLatency ) + plot( d.suggestedLatency, d.fullDuplexInputLatency ) + + if framesPerBuffer in individualPlotFramesPerBufferValues: # individual plots + figure( 3 + individualPlotFramesPerBufferValues.index(framesPerBuffer) ) + + plot( d.suggestedLatency, d.suggestedLatency, label="Suggested latency" ) + plot( d.suggestedLatency, d.halfDuplexOutputLatency, label="Half-duplex output latency" ) + plot( d.suggestedLatency, d.halfDuplexInputLatency, label="Half-duplex input latency" ) + plot( d.suggestedLatency, d.fullDuplexOutputLatency, label="Full-duplex output latency" ) + plot( d.suggestedLatency, d.fullDuplexInputLatency, label="Full-duplex input latency" ) + + if framesPerBuffer == 0: + framesPerBufferText = "paFramesPerBufferUnspecified" + else: + framesPerBufferText = str(framesPerBuffer) + setFigureTitleAndAxisLabels( "user frames per buffer: "+str(framesPerBufferText) ) + setDisplayRangeSeconds(2.2) + pdfFile.savefig() + setDisplayRangeSeconds(0.1) + setFigureTitleAndAxisLabels( "user frames per buffer: "+str(framesPerBufferText)+" (detail)" ) + pdfFile.savefig() + + isFirst = False + +figure(2) +setFigureTitleAndAxisLabels( "composite of frames per buffer values:\n"+str(compositeTestFramesPerBufferValues) ) +setDisplayRangeSeconds(2.2) +pdfFile.savefig() +setDisplayRangeSeconds(0.1) +setFigureTitleAndAxisLabels( "composite of frames per buffer values:\n"+str(compositeTestFramesPerBufferValues)+" (detail)" ) +pdfFile.savefig() + +pdfFile.close() + +#uncomment this to display interactively, otherwise we just output a pdf +#show() diff --git a/extern/portaudio/test/patest_sync.c b/extern/portaudio/test/patest_sync.c new file mode 100644 index 0000000..a064be1 --- /dev/null +++ b/extern/portaudio/test/patest_sync.c @@ -0,0 +1,271 @@ +/** @file patest_sync.c + @ingroup test_src + @brief Test time stamping and synchronization of audio and video. + + A high latency is used so we can hear the difference in time. + Random durations are used so we know we are hearing the right beep + and not the one before or after. + + Sequence of events: + -# Foreground requests a beep. + -# Background randomly schedules a beep. + -# Foreground waits for the beep to be heard based on PaUtil_GetTime(). + -# Foreground outputs video (printf) in sync with audio. + -# Repeat. + + @author Phil Burk http://www.softsynth.com +*/ +/* + * $Id$ + * + * This program uses the PortAudio Portable Audio Library. + * For more information see: http://www.portaudio.com + * Copyright (c) 1999-2000 Ross Bencina and Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +#include +#include +#include "portaudio.h" +#include "pa_util.h" +#define NUM_BEEPS (6) +#define SAMPLE_RATE (44100) +#define SAMPLE_PERIOD (1.0/44100.0) +#define FRAMES_PER_BUFFER (256) +#define BEEP_DURATION (400) +#define LATENCY_MSEC (2000) +#define SLEEP_MSEC (10) +#define TIMEOUT_MSEC (15000) + +#define STATE_BKG_IDLE (0) +#define STATE_BKG_PENDING (1) +#define STATE_BKG_BEEPING (2) +typedef struct +{ + float left_phase; + float right_phase; + int state; + volatile int requestBeep; /* Set by foreground, cleared by background. */ + PaTime beepTime; + int beepCount; + double latency; /* For debugging. */ +} +paTestData; + +static unsigned long GenerateRandomNumber( void ); +/************************************************************/ +/* Calculate pseudo-random 32 bit number based on linear congruential method. */ +static unsigned long GenerateRandomNumber( void ) +{ + static unsigned long randSeed = 99887766; /* Change this for different random sequences. */ + randSeed = (randSeed * 196314165) + 907633515; + return randSeed; +} + +/* This routine will be called by the PortAudio engine when audio is needed. +** It may called at interrupt level on some machines so don't do anything +** that could mess up the system like calling malloc() or free(). +*/ +static int patestCallback( const void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + const PaStreamCallbackTimeInfo *timeInfo, + PaStreamCallbackFlags statusFlags, void *userData ) +{ + /* Cast data passed through stream to our structure. */ + paTestData *data = (paTestData*)userData; + float *out = (float*)outputBuffer; + unsigned int i; + (void) inputBuffer; + + data->latency = timeInfo->outputBufferDacTime - timeInfo->currentTime; + + for( i=0; istate ) + { + case STATE_BKG_IDLE: + /* Schedule beep at some random time in the future. */ + if( data->requestBeep ) + { + int random = GenerateRandomNumber() >> 14; + data->beepTime = timeInfo->outputBufferDacTime + (( (double)(random + SAMPLE_RATE)) * SAMPLE_PERIOD ); + data->state = STATE_BKG_PENDING; + } + *out++ = 0.0; /* left */ + *out++ = 0.0; /* right */ + break; + + case STATE_BKG_PENDING: + if( (timeInfo->outputBufferDacTime + (i*SAMPLE_PERIOD)) >= data->beepTime ) + { + data->state = STATE_BKG_BEEPING; + data->beepCount = BEEP_DURATION; + data->left_phase = data->right_phase = 0.0; + } + *out++ = 0.0; /* left */ + *out++ = 0.0; /* right */ + break; + + case STATE_BKG_BEEPING: + if( data->beepCount <= 0 ) + { + data->state = STATE_BKG_IDLE; + data->requestBeep = 0; + *out++ = 0.0; /* left */ + *out++ = 0.0; /* right */ + } + else + { + /* Play sawtooth wave. */ + *out++ = data->left_phase; /* left */ + *out++ = data->right_phase; /* right */ + /* Generate simple sawtooth phaser that ranges between -1.0 and 1.0. */ + data->left_phase += 0.01f; + /* When signal reaches top, drop back down. */ + if( data->left_phase >= 1.0f ) data->left_phase -= 2.0f; + /* higher pitch so we can distinguish left and right. */ + data->right_phase += 0.03f; + if( data->right_phase >= 1.0f ) data->right_phase -= 2.0f; + } + data->beepCount -= 1; + break; + + default: + data->state = STATE_BKG_IDLE; + break; + } + } + return 0; +} +/*******************************************************************/ +int main(void); +int main(void) +{ + PaStream *stream; + PaError err; + paTestData DATA; + int i, timeout; + PaTime previousTime; + PaStreamParameters outputParameters; + printf("PortAudio Test: you should see BEEP at the same time you hear it.\n"); + printf("Wait for a few seconds random delay between BEEPs.\n"); + printf("BEEP %d times.\n", NUM_BEEPS ); + /* Initialize our DATA for use by callback. */ + DATA.left_phase = DATA.right_phase = 0.0; + DATA.state = STATE_BKG_IDLE; + DATA.requestBeep = 0; + /* Initialize library before making any other calls. */ + err = Pa_Initialize(); + if( err != paNoError ) goto error; + + outputParameters.device = Pa_GetDefaultOutputDevice(); + if (outputParameters.device == paNoDevice) { + fprintf(stderr,"Error: No default output device.\n"); + goto error; + } + outputParameters.channelCount = 2; + outputParameters.hostApiSpecificStreamInfo = NULL; + outputParameters.sampleFormat = paFloat32; + outputParameters.suggestedLatency = (double)LATENCY_MSEC / 1000; + + /* Open an audio I/O stream. */ + err = Pa_OpenStream( + &stream, + NULL, /* no input */ + &outputParameters, + SAMPLE_RATE, + FRAMES_PER_BUFFER, /* frames per buffer */ + paClipOff, /* we won't output out of range samples so don't bother clipping them */ + patestCallback, + &DATA ); + if( err != paNoError ) goto error; + + err = Pa_StartStream( stream ); + if( err != paNoError ) goto error; + + printf("started\n"); + fflush(stdout); + + previousTime = Pa_GetStreamTime( stream ); + for( i=0; i 0 ) ) Pa_Sleep(SLEEP_MSEC); + if( timeout <= 0 ) + { + fprintf( stderr, "Timed out waiting for background to acknowledge request.\n" ); + goto error; + } + printf("calc beep for %9.3f, latency = %6.3f\n", DATA.beepTime, DATA.latency ); + fflush(stdout); + + /* Wait for scheduled beep time. */ + timeout = TIMEOUT_MSEC + (10000/SLEEP_MSEC); + while( (Pa_GetStreamTime( stream ) < DATA.beepTime) && (timeout-- > 0 ) ) + { + Pa_Sleep(SLEEP_MSEC); + } + if( timeout <= 0 ) + { + fprintf( stderr, "Timed out waiting for time. Now = %9.3f, Beep for %9.3f.\n", + PaUtil_GetTime(), DATA.beepTime ); + goto error; + } + + /* Beep should be sounding now so print synchronized BEEP. */ + printf("hear \"BEEP\" at %9.3f, delta = %9.3f\n", + Pa_GetStreamTime( stream ), (DATA.beepTime - previousTime) ); + fflush(stdout); + + previousTime = DATA.beepTime; + } + + err = Pa_StopStream( stream ); + if( err != paNoError ) goto error; + + err = Pa_CloseStream( stream ); + if( err != paNoError ) goto error; + + Pa_Terminate(); + printf("Test finished.\n"); + return err; +error: + Pa_Terminate(); + fprintf( stderr, "An error occured while using the portaudio stream\n" ); + fprintf( stderr, "Error number: %d\n", err ); + fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); + return err; +} diff --git a/extern/portaudio/test/patest_timing.c b/extern/portaudio/test/patest_timing.c new file mode 100644 index 0000000..ed8a11a --- /dev/null +++ b/extern/portaudio/test/patest_timing.c @@ -0,0 +1,173 @@ +/** @file patest_timing.c + @ingroup test_src + @brief Play a sine wave for several seconds, and spits out a ton of timing info while it's at it. Based on patest_sine.c + @author Bjorn Roche + @author Ross Bencina + @author Phil Burk +*/ +/* + * $Id: patest_timing.c 578 2003-09-02 04:17:38Z rossbencina $ + * + * This program uses the PortAudio Portable Audio Library. + * For more information see: http://www.portaudio.com/ + * Copyright (c) 1999-2000 Ross Bencina and Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +#include +#include +#include "portaudio.h" + +#define NUM_SECONDS (5) +#define SAMPLE_RATE (44100) +#define FRAMES_PER_BUFFER (64) + +#ifndef M_PI +#define M_PI (3.14159265) +#endif + +#define TABLE_SIZE (200) +typedef struct +{ + PaStream *stream; + PaTime start; + float sine[TABLE_SIZE]; + int left_phase; + int right_phase; +} +paTestData; + +/* This routine will be called by the PortAudio engine when audio is needed. +** It may called at interrupt level on some machines so don't do anything +** that could mess up the system like calling malloc() or free(). +*/ +static int patestCallback( const void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + const PaStreamCallbackTimeInfo* timeInfo, + PaStreamCallbackFlags statusFlags, + void *userData ) +{ + paTestData *data = (paTestData*)userData; + float *out = (float*)outputBuffer; + unsigned long i; + + (void) timeInfo; /* Prevent unused variable warnings. */ + (void) statusFlags; + (void) inputBuffer; + + printf( "Timing info given to callback: Adc: %g, Current: %g, Dac: %g\n", + timeInfo->inputBufferAdcTime, + timeInfo->currentTime, + timeInfo->outputBufferDacTime ); + + printf( "getStreamTime() returns: %g\n", Pa_GetStreamTime(data->stream) - data->start ); + + for( i=0; isine[data->left_phase]; /* left */ + *out++ = data->sine[data->right_phase]; /* right */ + data->left_phase += 1; + if( data->left_phase >= TABLE_SIZE ) data->left_phase -= TABLE_SIZE; + data->right_phase += 3; /* higher pitch so we can distinguish left and right. */ + if( data->right_phase >= TABLE_SIZE ) data->right_phase -= TABLE_SIZE; + } + + return paContinue; +} + +/*******************************************************************/ +int main(void); +int main(void) +{ + PaStreamParameters outputParameters; + PaStream *stream; + PaError err; + paTestData data; + int i; + + + printf("PortAudio Test: output sine wave. SR = %d, BufSize = %d\n", SAMPLE_RATE, FRAMES_PER_BUFFER); + + /* initialise sinusoidal wavetable */ + for( i=0; idefaultLowOutputLatency; + outputParameters.hostApiSpecificStreamInfo = NULL; + + err = Pa_OpenStream( + &stream, + NULL, /* no input */ + &outputParameters, + SAMPLE_RATE, + FRAMES_PER_BUFFER, + paClipOff, /* we won't output out of range samples so don't bother clipping them */ + patestCallback, + &data ); + data.stream = stream; + data.start = Pa_GetStreamTime(stream); + if( err != paNoError ) goto error; + + err = Pa_StartStream( stream ); + data.start = Pa_GetStreamTime(stream); + if( err != paNoError ) goto error; + + printf("Play for %d seconds.\n", NUM_SECONDS ); + Pa_Sleep( NUM_SECONDS * 1000 ); + + err = Pa_StopStream( stream ); + if( err != paNoError ) goto error; + + err = Pa_CloseStream( stream ); + if( err != paNoError ) goto error; + + Pa_Terminate(); + printf("Test finished.\n"); + printf("The tone should have been heard for about 5 seconds and all the timing info above should report that about 5 seconds elapsed (except Adc, which is undefined since there was no input device opened).\n"); + + return err; +error: + Pa_Terminate(); + fprintf( stderr, "An error occured while using the portaudio stream\n" ); + fprintf( stderr, "Error number: %d\n", err ); + fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); + return err; +} diff --git a/extern/portaudio/test/patest_toomanysines.c b/extern/portaudio/test/patest_toomanysines.c new file mode 100644 index 0000000..4722f5e --- /dev/null +++ b/extern/portaudio/test/patest_toomanysines.c @@ -0,0 +1,200 @@ +/** @file patest_toomanysines.c + @ingroup test_src + @brief Play more sine waves than we can handle in real time as a stress test. + @todo This may not be needed now that we have "patest_out_overflow.c". + @author Ross Bencina + @author Phil Burk +*/ +/* + * $Id$ + * + * This program uses the PortAudio Portable Audio Library. + * For more information see: http://www.portaudio.com + * Copyright (c) 1999-2000 Ross Bencina and Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +#include +#include +#include "portaudio.h" + +#define MAX_SINES (1000) +#define MAX_LOAD (1.2) +#define SAMPLE_RATE (44100) +#define FRAMES_PER_BUFFER (512) +#ifndef M_PI +#define M_PI (3.14159265) +#endif +#define TWOPI (M_PI * 2.0) + +typedef struct paTestData +{ + int numSines; + double phases[MAX_SINES]; +} +paTestData; + +/* This routine will be called by the PortAudio engine when audio is needed. +** It may called at interrupt level on some machines so don't do anything +** that could mess up the system like calling malloc() or free(). +*/ +static int patestCallback( const void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + const PaStreamCallbackTimeInfo* timeInfo, + PaStreamCallbackFlags statusFlags, + void *userData ) +{ + paTestData *data = (paTestData*)userData; + float *out = (float*)outputBuffer; + unsigned long i; + int j; + int finished = 0; + (void) inputBuffer; /* Prevent unused variable warning. */ + + for( i=0; inumSines; j++ ) + { + /* Advance phase of next oscillator. */ + phase = data->phases[j]; + phase += phaseInc; + if( phase > TWOPI ) phase -= TWOPI; + + phaseInc *= 1.02; + if( phaseInc > 0.5 ) phaseInc *= 0.5; + + /* This is not a very efficient way to calc sines. */ + output += (float) sin( phase ); + data->phases[j] = phase; + } + *out++ = (float) (output / data->numSines); + } + return finished; +} + +/*******************************************************************/ +int main(void); +int main(void) +{ + PaStreamParameters outputParameters; + PaStream *stream; + PaError err; + int numStress; + paTestData data = {0}; + double load; + + printf("PortAudio Test: output sine wave. SR = %d, BufSize = %d. MAX_LOAD = %f\n", + SAMPLE_RATE, FRAMES_PER_BUFFER, MAX_LOAD ); + + err = Pa_Initialize(); + if( err != paNoError ) goto error; + + outputParameters.device = Pa_GetDefaultOutputDevice(); /* default output device */ + if (outputParameters.device == paNoDevice) { + fprintf(stderr,"Error: No default output device.\n"); + goto error; + } + outputParameters.channelCount = 1; /* mono output */ + outputParameters.sampleFormat = paFloat32; /* 32 bit floating point output */ + outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultLowOutputLatency; + outputParameters.hostApiSpecificStreamInfo = NULL; + + err = Pa_OpenStream( + &stream, + NULL, /* no input */ + &outputParameters, + SAMPLE_RATE, + FRAMES_PER_BUFFER, + paClipOff, /* we won't output out of range samples so don't bother clipping them */ + patestCallback, + &data ); + if( err != paNoError ) goto error; + err = Pa_StartStream( stream ); + if( err != paNoError ) goto error; + + /* Determine number of sines required to get to 50% */ + do + { Pa_Sleep( 100 ); + + load = Pa_GetStreamCpuLoad( stream ); + printf("numSines = %d, CPU load = %f\n", data.numSines, load ); + + if( load < 0.3 ) + { + data.numSines += 10; + } + else if( load < 0.4 ) + { + data.numSines += 2; + } + else + { + data.numSines += 1; + } + + } + while( load < 0.5 ); + + /* Calculate target stress value then ramp up to that level*/ + numStress = (int) (2.0 * data.numSines * MAX_LOAD ); + if( numStress > MAX_SINES ) + numStress = MAX_SINES; + for( ; data.numSines < numStress; data.numSines+=2 ) + { + Pa_Sleep( 200 ); + load = Pa_GetStreamCpuLoad( stream ); + printf("STRESSING: numSines = %d, CPU load = %f\n", data.numSines, load ); + } + + printf("Suffer for 5 seconds.\n"); + Pa_Sleep( 5000 ); + + printf("Stop stream.\n"); + err = Pa_StopStream( stream ); + if( err != paNoError ) goto error; + + err = Pa_CloseStream( stream ); + if( err != paNoError ) goto error; + + Pa_Terminate(); + printf("Test finished.\n"); + return err; +error: + Pa_Terminate(); + fprintf( stderr, "An error occured while using the portaudio stream\n" ); + fprintf( stderr, "Error number: %d\n", err ); + fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); + return err; +} diff --git a/extern/portaudio/test/patest_two_rates.c b/extern/portaudio/test/patest_two_rates.c new file mode 100644 index 0000000..5a2b178 --- /dev/null +++ b/extern/portaudio/test/patest_two_rates.c @@ -0,0 +1,178 @@ +/** @file patest_two_rates.c + @ingroup test_src + @brief Play two streams at different rates to make sure they don't interfere. + @author Phil Burk +*/ +/* + * $Id$ + * + * Author: Phil Burk http://www.softsynth.com + * + * This program uses the PortAudio Portable Audio Library. + * For more information see: http://www.portaudio.com + * Copyright (c) 1999-2000 Ross Bencina and Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +#include +#include +#include "portaudio.h" + +#define OUTPUT_DEVICE (Pa_GetDefaultOutputDeviceID()) +#define SAMPLE_RATE_1 (44100) +#define SAMPLE_RATE_2 (48000) +#define FRAMES_PER_BUFFER (256) +#define FREQ_INCR (0.1) + +#ifndef M_PI +#define M_PI (3.14159265) +#endif + +typedef struct +{ + double phase; + int numFrames; +} paTestData; + +/* This routine will be called by the PortAudio engine when audio is needed. + ** It may called at interrupt level on some machines so don't do anything + ** that could mess up the system like calling malloc() or free(). + */ +static int patestCallback( const void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + const PaStreamCallbackTimeInfo* timeInfo, + PaStreamCallbackFlags statusFlags, + void *userData ) +{ + paTestData *data = (paTestData*)userData; + float *out = (float*)outputBuffer; + int frameIndex; + (void) timeInfo; /* Prevent unused variable warnings. */ + (void) inputBuffer; + + for( frameIndex=0; frameIndex<(int)framesPerBuffer; frameIndex++ ) + { + /* Generate sine wave. */ + float value = (float) 0.3 * sin(data->phase); + /* Stereo - two channels. */ + *out++ = value; + *out++ = value; + + data->phase += FREQ_INCR; + if( data->phase >= (2.0 * M_PI) ) data->phase -= (2.0 * M_PI); + } + data->numFrames += 1; + return 0; +} + +/*******************************************************************/ +int main(void); +int main(void) +{ + PaError err; + PaStreamParameters outputParameters; + PaStream *stream1; + PaStream *stream2; + paTestData data1 = {0}; + paTestData data2 = {0}; + printf("PortAudio Test: two rates.\n" ); + + err = Pa_Initialize(); + if( err != paNoError ) goto error; + + outputParameters.device = Pa_GetDefaultOutputDevice(); /* default output device */ + if (outputParameters.device == paNoDevice) { + fprintf(stderr,"Error: No default output device.\n"); + goto error; + } + outputParameters.channelCount = 2; /* stereo output */ + outputParameters.sampleFormat = paFloat32; /* 32 bit floating point output */ + outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultLowOutputLatency; + outputParameters.hostApiSpecificStreamInfo = NULL; + + /* Start first stream. **********************/ + err = Pa_OpenStream( + &stream1, + NULL, /* no input */ + &outputParameters, + SAMPLE_RATE_1, + FRAMES_PER_BUFFER, + paClipOff, /* we won't output out of range samples so don't bother clipping them */ + patestCallback, + &data1 ); + if( err != paNoError ) goto error; + + err = Pa_StartStream( stream1 ); + if( err != paNoError ) goto error; + + Pa_Sleep( 3 * 1000 ); + + /* Start second stream. **********************/ + err = Pa_OpenStream( + &stream2, + NULL, /* no input */ + &outputParameters, + SAMPLE_RATE_2, + FRAMES_PER_BUFFER, + paClipOff, /* we won't output out of range samples so don't bother clipping them */ + patestCallback, + &data2 ); + if( err != paNoError ) goto error; + + err = Pa_StartStream( stream2 ); + if( err != paNoError ) goto error; + + Pa_Sleep( 3 * 1000 ); + + err = Pa_StopStream( stream2 ); + if( err != paNoError ) goto error; + + Pa_Sleep( 3 * 1000 ); + + err = Pa_StopStream( stream1 ); + if( err != paNoError ) goto error; + + Pa_CloseStream( stream2 ); + Pa_CloseStream( stream1 ); + + Pa_Terminate(); + + printf("NumFrames = %d on stream1, %d on stream2.\n", data1.numFrames, data2.numFrames ); + printf("Test finished.\n"); + return err; +error: + Pa_Terminate(); + fprintf( stderr, "An error occured while using the portaudio stream\n" ); + fprintf( stderr, "Error number: %d\n", err ); + fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); + return err; +} diff --git a/extern/portaudio/test/patest_underflow.c b/extern/portaudio/test/patest_underflow.c new file mode 100644 index 0000000..e1726a6 --- /dev/null +++ b/extern/portaudio/test/patest_underflow.c @@ -0,0 +1,162 @@ +/** @file patest_underflow.c + @ingroup test_src + @brief Simulate an output buffer underflow condition. + Tests whether the stream can be stopped when underflowing buffers. + @author Ross Bencina + @author Phil Burk +*/ +/* + * $Id$ + * + * This program uses the PortAudio Portable Audio Library. + * For more information see: http://www.portaudio.com + * Copyright (c) 1999-2000 Ross Bencina and Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +#include +#include +#include "portaudio.h" + +#define NUM_SECONDS (20) +#define SAMPLE_RATE (44100) +#define FRAMES_PER_BUFFER (2048) +#define MSEC_PER_BUFFER ( (FRAMES_PER_BUFFER * 1000) / SAMPLE_RATE ) + +#ifndef M_PI +#define M_PI (3.14159265) +#endif + +#define TABLE_SIZE (200) +typedef struct +{ + float sine[TABLE_SIZE]; + int left_phase; + int right_phase; + int sleepTime; +} +paTestData; + +/* This routine will be called by the PortAudio engine when audio is needed. +** It may called at interrupt level on some machines so don't do anything +** that could mess up the system like calling malloc() or free(). +*/ +static int patestCallback( const void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + const PaStreamCallbackTimeInfo* timeInfo, + PaStreamCallbackFlags statusFlags, + void *userData ) +{ + paTestData *data = (paTestData*)userData; + float *out = (float*)outputBuffer; + unsigned long i; + int finished = 0; + (void) inputBuffer; /* Prevent unused variable warnings. */ + for( i=0; isine[data->left_phase]; /* left */ + *out++ = data->sine[data->right_phase]; /* right */ + data->left_phase += 1; + if( data->left_phase >= TABLE_SIZE ) data->left_phase -= TABLE_SIZE; + data->right_phase += 3; /* higher pitch so we can distinguish left and right. */ + if( data->right_phase >= TABLE_SIZE ) data->right_phase -= TABLE_SIZE; + } + + /* Cause underflow to occur. */ + if( data->sleepTime > 0 ) Pa_Sleep( data->sleepTime ); + data->sleepTime += 1; + + return finished; +} + +/*******************************************************************/ +int main(void); +int main(void) +{ + PaStreamParameters outputParameters; + PaStream *stream; + PaError err; + paTestData data; + int i; + printf("PortAudio Test: output sine wave. SR = %d, BufSize = %d\n", SAMPLE_RATE, FRAMES_PER_BUFFER); + /* initialise sinusoidal wavetable */ + for( i=0; idefaultLowOutputLatency; + outputParameters.hostApiSpecificStreamInfo = NULL; + err = Pa_OpenStream( + &stream, + NULL, /* no input */ + &outputParameters, + SAMPLE_RATE, + FRAMES_PER_BUFFER, + paClipOff, /* we won't output out of range samples so don't bother clipping them */ + patestCallback, + &data ); + if( err != paNoError ) goto error; + err = Pa_StartStream( stream ); + if( err != paNoError ) goto error; + + while( data.sleepTime < (2 * MSEC_PER_BUFFER) ) + { + printf("SleepTime = %d\n", data.sleepTime ); + Pa_Sleep( data.sleepTime ); + } + + printf("Try to stop stream.\n"); + err = Pa_StopStream( stream ); + if( err != paNoError ) goto error; + err = Pa_CloseStream( stream ); + if( err != paNoError ) goto error; + Pa_Terminate(); + printf("Test finished.\n"); + return err; +error: + Pa_Terminate(); + fprintf( stderr, "An error occured while using the portaudio stream\n" ); + fprintf( stderr, "Error number: %d\n", err ); + fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); + return err; +} diff --git a/extern/portaudio/test/patest_unplug.c b/extern/portaudio/test/patest_unplug.c new file mode 100644 index 0000000..ba55b7d --- /dev/null +++ b/extern/portaudio/test/patest_unplug.c @@ -0,0 +1,243 @@ +/** @file patest_unplug.c + @ingroup test_src + @brief Debug a crash involving unplugging a USB device. + @author Phil Burk http://www.softsynth.com +*/ +/* + * $Id$ + * + * This program uses the PortAudio Portable Audio Library. + * For more information see: http://www.portaudio.com + * Copyright (c) 1999-2000 Ross Bencina and Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +#include +#include +#include +#include +#include "portaudio.h" + +#define NUM_SECONDS (8) +#define SAMPLE_RATE (44100) +#ifndef M_PI +#define M_PI (3.14159265) +#endif +#define TABLE_SIZE (200) +#define FRAMES_PER_BUFFER (64) +#define MAX_CHANNELS (8) + +typedef struct +{ + short sine[TABLE_SIZE]; + int32_t phases[MAX_CHANNELS]; + int32_t numChannels; + int32_t sampsToGo; +} +paTestData; + + +static int inputCallback( const void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + const PaStreamCallbackTimeInfo* timeInfo, + PaStreamCallbackFlags statusFlags, + void *userData ) +{ + paTestData *data = (paTestData*)userData; + int finished = 0; + (void) inputBuffer; /* Prevent "unused variable" warnings. */ + (void) outputBuffer; /* Prevent "unused variable" warnings. */ + + data->sampsToGo -= framesPerBuffer; + if (data->sampsToGo <= 0) + { + data->sampsToGo = 0; + finished = 1; + } + return finished; +} + +static int outputCallback( const void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + const PaStreamCallbackTimeInfo* timeInfo, + PaStreamCallbackFlags statusFlags, + void *userData ) +{ + paTestData *data = (paTestData*)userData; + short *out = (short*)outputBuffer; + unsigned int i; + int finished = 0; + (void) inputBuffer; /* Prevent "unused variable" warnings. */ + + for( i=0; inumChannels; channelIndex++) + { + int phase = data->phases[channelIndex]; + *out++ = data->sine[phase]; + phase += channelIndex + 2; + if( phase >= TABLE_SIZE ) phase -= TABLE_SIZE; + data->phases[channelIndex] = phase; + } + } + return finished; +} + +/*******************************************************************/ +int main(int argc, char **args); +int main(int argc, char **args) +{ + PaStreamParameters inputParameters; + PaStreamParameters outputParameters; + PaStream *inputStream; + PaStream *outputStream; + const PaDeviceInfo *deviceInfo; + PaError err; + paTestData data; + int i; + int totalSamps; + int inputDevice = -1; + int outputDevice = -1; + + printf("Test unplugging a USB device.\n"); + + if( argc > 1 ) { + inputDevice = outputDevice = atoi( args[1] ); + printf("Using device number %d.\n\n", inputDevice ); + } else { + printf("Using default device.\n\n" ); + } + + memset(&data, 0, sizeof(data)); + + /* initialise sinusoidal wavetable */ + for( i=0; idefaultLowInputLatency; + inputParameters.hostApiSpecificStreamInfo = NULL; + err = Pa_OpenStream( + &inputStream, + &inputParameters, + NULL, + SAMPLE_RATE, + FRAMES_PER_BUFFER, + 0, + inputCallback, + &data ); + if( err != paNoError ) goto error; + + outputParameters.channelCount = 2; + outputParameters.sampleFormat = paInt16; + deviceInfo = Pa_GetDeviceInfo( outputParameters.device ); + if( deviceInfo == NULL ) + { + fprintf( stderr, "No matching output device.\n" ); + goto error; + } + outputParameters.suggestedLatency = deviceInfo->defaultLowOutputLatency; + outputParameters.hostApiSpecificStreamInfo = NULL; + err = Pa_OpenStream( + &outputStream, + NULL, + &outputParameters, + SAMPLE_RATE, + FRAMES_PER_BUFFER, + (paClipOff | paDitherOff), + outputCallback, + &data ); + if( err != paNoError ) goto error; + + err = Pa_StartStream( inputStream ); + if( err != paNoError ) goto error; + err = Pa_StartStream( outputStream ); + if( err != paNoError ) goto error; + + printf("When you hear sound, unplug the USB device.\n"); + do + { + Pa_Sleep(500); + printf("Frames remaining = %d\n", data.sampsToGo); + printf("Pa_IsStreamActive(inputStream) = %d\n", Pa_IsStreamActive(inputStream)); + printf("Pa_IsStreamActive(outputStream) = %d\n", Pa_IsStreamActive(outputStream)); + } while( Pa_IsStreamActive(inputStream) && Pa_IsStreamActive(outputStream) ); + + err = Pa_CloseStream( inputStream ); + if( err != paNoError ) goto error; + err = Pa_CloseStream( outputStream ); + if( err != paNoError ) goto error; + Pa_Terminate(); + return paNoError; +error: + Pa_Terminate(); + fprintf( stderr, "An error occured while using the portaudio stream\n" ); + fprintf( stderr, "Error number: %d\n", err ); + fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); + fprintf( stderr, "Host Error message: %s\n", Pa_GetLastHostErrorInfo()->errorText ); + return err; +} diff --git a/extern/portaudio/test/patest_wire.c b/extern/portaudio/test/patest_wire.c new file mode 100644 index 0000000..ba3477b --- /dev/null +++ b/extern/portaudio/test/patest_wire.c @@ -0,0 +1,331 @@ +/** @file patest_wire.c + @ingroup test_src + @brief Pass input directly to output. + + Note that some HW devices, for example many ISA audio cards + on PCs, do NOT support full duplex! For a PC, you normally need + a PCI based audio card such as the SBLive. + + @author Phil Burk http://www.softsynth.com + + While adapting to V19-API, I excluded configs with framesPerCallback=0 + because of an assert in file pa_common/pa_process.c. Pieter, Oct 9, 2003. + +*/ +/* + * $Id$ + * + * This program uses the PortAudio Portable Audio Library. + * For more information see: http://www.portaudio.com + * Copyright (c) 1999-2000 Ross Bencina and Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +#include +#include +#include "portaudio.h" + +#define SAMPLE_RATE (44100) + +typedef struct WireConfig_s +{ + int isInputInterleaved; + int isOutputInterleaved; + int numInputChannels; + int numOutputChannels; + int framesPerCallback; + /* count status flags */ + int numInputUnderflows; + int numInputOverflows; + int numOutputUnderflows; + int numOutputOverflows; + int numPrimingOutputs; + int numCallbacks; +} WireConfig_t; + +#define USE_FLOAT_INPUT (1) +#define USE_FLOAT_OUTPUT (1) + +/* Latencies set to defaults. */ + +#if USE_FLOAT_INPUT + #define INPUT_FORMAT paFloat32 + typedef float INPUT_SAMPLE; +#else + #define INPUT_FORMAT paInt16 + typedef short INPUT_SAMPLE; +#endif + +#if USE_FLOAT_OUTPUT + #define OUTPUT_FORMAT paFloat32 + typedef float OUTPUT_SAMPLE; +#else + #define OUTPUT_FORMAT paInt16 + typedef short OUTPUT_SAMPLE; +#endif + +double gInOutScaler = 1.0; +#define CONVERT_IN_TO_OUT(in) ((OUTPUT_SAMPLE) ((in) * gInOutScaler)) + +#define INPUT_DEVICE (Pa_GetDefaultInputDevice()) +#define OUTPUT_DEVICE (Pa_GetDefaultOutputDevice()) + +static PaError TestConfiguration( WireConfig_t *config ); + +static int wireCallback( const void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + const PaStreamCallbackTimeInfo* timeInfo, + PaStreamCallbackFlags statusFlags, + void *userData ); + +/* This routine will be called by the PortAudio engine when audio is needed. +** It may be called at interrupt level on some machines so don't do anything +** that could mess up the system like calling malloc() or free(). +*/ + +static int wireCallback( const void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + const PaStreamCallbackTimeInfo* timeInfo, + PaStreamCallbackFlags statusFlags, + void *userData ) +{ + INPUT_SAMPLE *in; + OUTPUT_SAMPLE *out; + int inStride; + int outStride; + int inDone = 0; + int outDone = 0; + WireConfig_t *config = (WireConfig_t *) userData; + unsigned int i; + int inChannel, outChannel; + + /* This may get called with NULL inputBuffer during initial setup. */ + if( inputBuffer == NULL) return 0; + + /* Count flags */ + if( (statusFlags & paInputUnderflow) != 0 ) config->numInputUnderflows += 1; + if( (statusFlags & paInputOverflow) != 0 ) config->numInputOverflows += 1; + if( (statusFlags & paOutputUnderflow) != 0 ) config->numOutputUnderflows += 1; + if( (statusFlags & paOutputOverflow) != 0 ) config->numOutputOverflows += 1; + if( (statusFlags & paPrimingOutput) != 0 ) config->numPrimingOutputs += 1; + config->numCallbacks += 1; + + inChannel=0, outChannel=0; + while( !(inDone && outDone) ) + { + if( config->isInputInterleaved ) + { + in = ((INPUT_SAMPLE*)inputBuffer) + inChannel; + inStride = config->numInputChannels; + } + else + { + in = ((INPUT_SAMPLE**)inputBuffer)[inChannel]; + inStride = 1; + } + + if( config->isOutputInterleaved ) + { + out = ((OUTPUT_SAMPLE*)outputBuffer) + outChannel; + outStride = config->numOutputChannels; + } + else + { + out = ((OUTPUT_SAMPLE**)outputBuffer)[outChannel]; + outStride = 1; + } + + for( i=0; inumInputChannels - 1)) inChannel++; + else inDone = 1; + if(outChannel < (config->numOutputChannels - 1)) outChannel++; + else outDone = 1; + } + return 0; +} + +/*******************************************************************/ +int main(void); +int main(void) +{ + PaError err = paNoError; + WireConfig_t CONFIG; + WireConfig_t *config = &CONFIG; + int configIndex = 0;; + + err = Pa_Initialize(); + if( err != paNoError ) goto error; + + printf("Please connect audio signal to input and listen for it on output!\n"); + printf("input format = %lu\n", INPUT_FORMAT ); + printf("output format = %lu\n", OUTPUT_FORMAT ); + printf("input device ID = %d\n", INPUT_DEVICE ); + printf("output device ID = %d\n", OUTPUT_DEVICE ); + + if( INPUT_FORMAT == OUTPUT_FORMAT ) + { + gInOutScaler = 1.0; + } + else if( (INPUT_FORMAT == paInt16) && (OUTPUT_FORMAT == paFloat32) ) + { + gInOutScaler = 1.0/32768.0; + } + else if( (INPUT_FORMAT == paFloat32) && (OUTPUT_FORMAT == paInt16) ) + { + gInOutScaler = 32768.0; + } + + for( config->isInputInterleaved = 0; config->isInputInterleaved < 2; config->isInputInterleaved++ ) + { + for( config->isOutputInterleaved = 0; config->isOutputInterleaved < 2; config->isOutputInterleaved++ ) + { + for( config->numInputChannels = 1; config->numInputChannels < 3; config->numInputChannels++ ) + { + for( config->numOutputChannels = 1; config->numOutputChannels < 3; config->numOutputChannels++ ) + { + /* If framesPerCallback = 0, assertion fails in file pa_common/pa_process.c, line 1413: EX. */ + for( config->framesPerCallback = 64; config->framesPerCallback < 129; config->framesPerCallback += 64 ) + { + printf("-----------------------------------------------\n" ); + printf("Configuration #%d\n", configIndex++ ); + err = TestConfiguration( config ); + /* Give user a chance to bail out. */ + if( err == 1 ) + { + err = paNoError; + goto done; + } + else if( err != paNoError ) goto error; + } + } + } + } + } + +done: + Pa_Terminate(); + printf("Full duplex sound test complete.\n"); fflush(stdout); + printf("Hit ENTER to quit.\n"); fflush(stdout); + getchar(); + return 0; + +error: + Pa_Terminate(); + fprintf( stderr, "An error occured while using the portaudio stream\n" ); + fprintf( stderr, "Error number: %d\n", err ); + fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); + printf("Hit ENTER to quit.\n"); fflush(stdout); + getchar(); + return -1; +} + +static PaError TestConfiguration( WireConfig_t *config ) +{ + int c; + PaError err = paNoError; + PaStream *stream; + PaStreamParameters inputParameters, outputParameters; + + printf("input %sinterleaved!\n", (config->isInputInterleaved ? " " : "NOT ") ); + printf("output %sinterleaved!\n", (config->isOutputInterleaved ? " " : "NOT ") ); + printf("input channels = %d\n", config->numInputChannels ); + printf("output channels = %d\n", config->numOutputChannels ); + printf("framesPerCallback = %d\n", config->framesPerCallback ); + + inputParameters.device = INPUT_DEVICE; /* default input device */ + if (inputParameters.device == paNoDevice) { + fprintf(stderr,"Error: No default input device.\n"); + goto error; + } + inputParameters.channelCount = config->numInputChannels; + inputParameters.sampleFormat = INPUT_FORMAT | (config->isInputInterleaved ? 0 : paNonInterleaved); + inputParameters.suggestedLatency = Pa_GetDeviceInfo( inputParameters.device )->defaultLowInputLatency; + inputParameters.hostApiSpecificStreamInfo = NULL; + + outputParameters.device = OUTPUT_DEVICE; /* default output device */ + if (outputParameters.device == paNoDevice) { + fprintf(stderr,"Error: No default output device.\n"); + goto error; + } + outputParameters.channelCount = config->numOutputChannels; + outputParameters.sampleFormat = OUTPUT_FORMAT | (config->isOutputInterleaved ? 0 : paNonInterleaved); + outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultLowOutputLatency; + outputParameters.hostApiSpecificStreamInfo = NULL; + + config->numInputUnderflows = 0; + config->numInputOverflows = 0; + config->numOutputUnderflows = 0; + config->numOutputOverflows = 0; + config->numPrimingOutputs = 0; + config->numCallbacks = 0; + + err = Pa_OpenStream( + &stream, + &inputParameters, + &outputParameters, + SAMPLE_RATE, + config->framesPerCallback, /* frames per buffer */ + paClipOff, /* we won't output out of range samples so don't bother clipping them */ + wireCallback, + config ); + if( err != paNoError ) goto error; + + err = Pa_StartStream( stream ); + if( err != paNoError ) goto error; + + printf("Now recording and playing. - Hit ENTER for next configuration, or 'q' to quit.\n"); fflush(stdout); + c = getchar(); + + printf("Closing stream.\n"); + err = Pa_CloseStream( stream ); + if( err != paNoError ) goto error; + +#define CHECK_FLAG_COUNT(member) \ + if( config->member > 0 ) printf("FLAGS SET: " #member " = %d\n", config->member ); + CHECK_FLAG_COUNT( numInputUnderflows ); + CHECK_FLAG_COUNT( numInputOverflows ); + CHECK_FLAG_COUNT( numOutputUnderflows ); + CHECK_FLAG_COUNT( numOutputOverflows ); + CHECK_FLAG_COUNT( numPrimingOutputs ); + printf("number of callbacks = %d\n", config->numCallbacks ); + + if( c == 'q' ) return 1; + +error: + return err; +} diff --git a/extern/portaudio/test/patest_wmme_find_best_latency_params.c b/extern/portaudio/test/patest_wmme_find_best_latency_params.c new file mode 100644 index 0000000..618b97e --- /dev/null +++ b/extern/portaudio/test/patest_wmme_find_best_latency_params.c @@ -0,0 +1,518 @@ +/* + * $Id: $ + * Portable Audio I/O Library + * Windows MME low level buffer user guided parameters search + * + * Copyright (c) 2010 Ross Bencina + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +#include +#include +#include + +#define _WIN32_WINNT 0x0501 /* for GetNativeSystemInfo */ +#include /* required when using pa_win_wmme.h */ +#include /* required when using pa_win_wmme.h */ + +#include /* for _getch */ + + +#include "portaudio.h" +#include "pa_win_wmme.h" + + +#define DEFAULT_SAMPLE_RATE (44100.) + +#ifndef M_PI +#define M_PI (3.14159265) +#endif + +#define TABLE_SIZE (2048) + +#define CHANNEL_COUNT (2) + + +/* seach parameters. we test all buffer counts in this range */ +#define MIN_WMME_BUFFER_COUNT (2) +#define MAX_WMME_BUFFER_COUNT (12) + + +/*******************************************************************/ +/* functions to query and print Windows version information */ + +typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL); + +LPFN_ISWOW64PROCESS fnIsWow64Process; + +static BOOL IsWow64() +{ + BOOL bIsWow64 = FALSE; + + //IsWow64Process is not available on all supported versions of Windows. + //Use GetModuleHandle to get a handle to the DLL that contains the function + //and GetProcAddress to get a pointer to the function if available. + + fnIsWow64Process = (LPFN_ISWOW64PROCESS) GetProcAddress( + GetModuleHandle(TEXT("kernel32")),"IsWow64Process" ); + + if(NULL != fnIsWow64Process) + { + if (!fnIsWow64Process(GetCurrentProcess(),&bIsWow64)) + { + //handle error + } + } + return bIsWow64; +} + +static void printWindowsVersionInfo( FILE *fp ) +{ + OSVERSIONINFOEX osVersionInfoEx; + SYSTEM_INFO systemInfo; + const char *osName = "Unknown"; + const char *osProductType = ""; + const char *processorArchitecture = "Unknown"; + + memset( &osVersionInfoEx, 0, sizeof(OSVERSIONINFOEX) ); + osVersionInfoEx.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); + GetVersionEx( &osVersionInfoEx ); + + + if( osVersionInfoEx.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS ){ + switch( osVersionInfoEx.dwMinorVersion ){ + case 0: osName = "Windows 95"; break; + case 10: osName = "Windows 98"; break; // could also be 98SE (I've seen code discriminate based + // on osInfo.Version.Revision.ToString() == "2222A") + case 90: osName = "Windows Me"; break; + } + }else if( osVersionInfoEx.dwPlatformId == VER_PLATFORM_WIN32_NT ){ + switch( osVersionInfoEx.dwMajorVersion ){ + case 3: osName = "Windows NT 3.51"; break; + case 4: osName = "Windows NT 4.0"; break; + case 5: switch( osVersionInfoEx.dwMinorVersion ){ + case 0: osName = "Windows 2000"; break; + case 1: osName = "Windows XP"; break; + case 2: + if( osVersionInfoEx.wSuiteMask & 0x00008000 /*VER_SUITE_WH_SERVER*/ ){ + osName = "Windows Home Server"; + }else{ + if( osVersionInfoEx.wProductType == VER_NT_WORKSTATION ){ + osName = "Windows XP Professional x64 Edition (?)"; + }else{ + if( GetSystemMetrics(/*SM_SERVERR2*/89) == 0 ) + osName = "Windows Server 2003"; + else + osName = "Windows Server 2003 R2"; + } + }break; + }break; + case 6:switch( osVersionInfoEx.dwMinorVersion ){ + case 0: + if( osVersionInfoEx.wProductType == VER_NT_WORKSTATION ) + osName = "Windows Vista"; + else + osName = "Windows Server 2008"; + break; + case 1: + if( osVersionInfoEx.wProductType == VER_NT_WORKSTATION ) + osName = "Windows 7"; + else + osName = "Windows Server 2008 R2"; + break; + }break; + } + } + + if(osVersionInfoEx.dwMajorVersion == 4) + { + if(osVersionInfoEx.wProductType == VER_NT_WORKSTATION) + osProductType = "Workstation"; + else if(osVersionInfoEx.wProductType == VER_NT_SERVER) + osProductType = "Server"; + } + else if(osVersionInfoEx.dwMajorVersion == 5) + { + if(osVersionInfoEx.wProductType == VER_NT_WORKSTATION) + { + if((osVersionInfoEx.wSuiteMask & VER_SUITE_PERSONAL) == VER_SUITE_PERSONAL) + osProductType = "Home Edition"; // Windows XP Home Edition + else + osProductType = "Professional"; // Windows XP / Windows 2000 Professional + } + else if(osVersionInfoEx.wProductType == VER_NT_SERVER) + { + if(osVersionInfoEx.dwMinorVersion == 0) + { + if((osVersionInfoEx.wSuiteMask & VER_SUITE_DATACENTER) == VER_SUITE_DATACENTER) + osProductType = "Datacenter Server"; // Windows 2000 Datacenter Server + else if((osVersionInfoEx.wSuiteMask & VER_SUITE_ENTERPRISE) == VER_SUITE_ENTERPRISE) + osProductType = "Advanced Server"; // Windows 2000 Advanced Server + else + osProductType = "Server"; // Windows 2000 Server + } + } + else + { + if((osVersionInfoEx.wSuiteMask & VER_SUITE_DATACENTER) == VER_SUITE_DATACENTER) + osProductType = "Datacenter Edition"; // Windows Server 2003 Datacenter Edition + else if((osVersionInfoEx.wSuiteMask & VER_SUITE_ENTERPRISE) == VER_SUITE_ENTERPRISE) + osProductType = "Enterprise Edition"; // Windows Server 2003 Enterprise Edition + else if((osVersionInfoEx.wSuiteMask & VER_SUITE_BLADE) == VER_SUITE_BLADE) + osProductType = "Web Edition"; // Windows Server 2003 Web Edition + else + osProductType = "Standard Edition"; // Windows Server 2003 Standard Edition + } + } + + memset( &systemInfo, 0, sizeof(SYSTEM_INFO) ); + GetNativeSystemInfo( &systemInfo ); + + if( systemInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL ) + processorArchitecture = "x86"; + else if( systemInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64 ) + processorArchitecture = "x64"; + else if( systemInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_IA64 ) + processorArchitecture = "Itanium"; + + + fprintf( fp, "OS name and edition: %s %s\n", osName, osProductType ); + fprintf( fp, "OS version: %d.%d.%d %S\n", + osVersionInfoEx.dwMajorVersion, osVersionInfoEx.dwMinorVersion, + osVersionInfoEx.dwBuildNumber, osVersionInfoEx.szCSDVersion ); + fprintf( fp, "Processor architecture: %s\n", processorArchitecture ); + fprintf( fp, "WoW64 process: %s\n", IsWow64() ? "Yes" : "No" ); +} + +static void printTimeAndDate( FILE *fp ) +{ + struct tm *local; + time_t t; + + t = time(NULL); + local = localtime(&t); + fprintf(fp, "Local time and date: %s", asctime(local)); + local = gmtime(&t); + fprintf(fp, "UTC time and date: %s", asctime(local)); +} + +/*******************************************************************/ + +typedef struct +{ + float sine[TABLE_SIZE]; + double phase; + double phaseIncrement; + volatile int fadeIn; + volatile int fadeOut; + double amp; +} +paTestData; + +static paTestData data; + +/* This routine will be called by the PortAudio engine when audio is needed. +** It may called at interrupt level on some machines so don't do anything +** that could mess up the system like calling malloc() or free(). +*/ +static int patestCallback( const void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + const PaStreamCallbackTimeInfo* timeInfo, + PaStreamCallbackFlags statusFlags, + void *userData ) +{ + paTestData *data = (paTestData*)userData; + float *out = (float*)outputBuffer; + unsigned long i,j; + + (void) timeInfo; /* Prevent unused variable warnings. */ + (void) statusFlags; + (void) inputBuffer; + + for( i=0; isine[(int)data->phase]; + data->phase += data->phaseIncrement; + if( data->phase >= TABLE_SIZE ){ + data->phase -= TABLE_SIZE; + } + + x *= data->amp; + if( data->fadeIn ){ + data->amp += .001; + if( data->amp >= 1. ) + data->fadeIn = 0; + }else if( data->fadeOut ){ + if( data->amp > 0 ) + data->amp -= .001; + } + + for( j = 0; j < CHANNEL_COUNT; ++j ){ + *out++ = x; + } + } + + if( data->amp > 0 ) + return paContinue; + else + return paComplete; +} + + +#define YES 1 +#define NO 0 + + +static int playUntilKeyPress( int deviceIndex, float sampleRate, + int framesPerUserBuffer, int framesPerWmmeBuffer, int wmmeBufferCount ) +{ + PaStreamParameters outputParameters; + PaWinMmeStreamInfo wmmeStreamInfo; + PaStream *stream; + PaError err; + int c; + + outputParameters.device = deviceIndex; + outputParameters.channelCount = CHANNEL_COUNT; + outputParameters.sampleFormat = paFloat32; /* 32 bit floating point processing */ + outputParameters.suggestedLatency = 0; /*Pa_GetDeviceInfo( outputParameters.device )->defaultLowOutputLatency;*/ + outputParameters.hostApiSpecificStreamInfo = NULL; + + wmmeStreamInfo.size = sizeof(PaWinMmeStreamInfo); + wmmeStreamInfo.hostApiType = paMME; + wmmeStreamInfo.version = 1; + wmmeStreamInfo.flags = paWinMmeUseLowLevelLatencyParameters | paWinMmeDontThrottleOverloadedProcessingThread; + wmmeStreamInfo.framesPerBuffer = framesPerWmmeBuffer; + wmmeStreamInfo.bufferCount = wmmeBufferCount; + outputParameters.hostApiSpecificStreamInfo = &wmmeStreamInfo; + + err = Pa_OpenStream( + &stream, + NULL, /* no input */ + &outputParameters, + sampleRate, + framesPerUserBuffer, + paClipOff | paPrimeOutputBuffersUsingStreamCallback, /* we won't output out of range samples so don't bother clipping them */ + patestCallback, + &data ); + if( err != paNoError ) goto error; + + data.amp = 0; + data.fadeIn = 1; + data.fadeOut = 0; + data.phase = 0; + data.phaseIncrement = 15 + ((rand()%100) / 10); // randomise pitch + + err = Pa_StartStream( stream ); + if( err != paNoError ) goto error; + + + do{ + printf( "Trying buffer size %d.\nIf it sounds smooth (without clicks or glitches) press 'y', if it sounds bad press 'n' ('q' to quit)\n", framesPerWmmeBuffer ); + c = tolower(_getch()); + if( c == 'q' ){ + Pa_Terminate(); + exit(0); + } + }while( c != 'y' && c != 'n' ); + + data.fadeOut = 1; + while( Pa_IsStreamActive(stream) == 1 ) + Pa_Sleep( 100 ); + + err = Pa_StopStream( stream ); + if( err != paNoError ) goto error; + + err = Pa_CloseStream( stream ); + if( err != paNoError ) goto error; + + return (c == 'y') ? YES : NO; + +error: + return err; +} + +/*******************************************************************/ +static void usage( int wmmeHostApiIndex ) +{ + int i; + + fprintf( stderr, "PortAudio WMME output latency user guided test\n" ); + fprintf( stderr, "Usage: x.exe mme-device-index [sampleRate [min-buffer-count max-buffer-count]]\n" ); + fprintf( stderr, "Invalid device index. Use one of these:\n" ); + for( i=0; i < Pa_GetDeviceCount(); ++i ){ + + if( Pa_GetDeviceInfo(i)->hostApi == wmmeHostApiIndex && Pa_GetDeviceInfo(i)->maxOutputChannels > 0 ) + fprintf( stderr, "%d (%s)\n", i, Pa_GetDeviceInfo(i)->name ); + } + Pa_Terminate(); + exit(-1); +} + +/* + ideas: + o- could be testing with 80% CPU load + o- could test with different channel counts +*/ + +int main(int argc, char* argv[]) +{ + PaError err; + int i; + int deviceIndex; + int wmmeBufferCount, wmmeBufferSize, smallestWorkingBufferSize; + int smallestWorkingBufferingLatencyFrames; + int min, max, mid; + int testResult; + FILE *resultsFp; + int wmmeHostApiIndex; + const PaHostApiInfo *wmmeHostApiInfo; + double sampleRate = DEFAULT_SAMPLE_RATE; + int wmmeMinBufferCount = MIN_WMME_BUFFER_COUNT; + int wmmeMaxBufferCount = MAX_WMME_BUFFER_COUNT; + + err = Pa_Initialize(); + if( err != paNoError ) goto error; + + wmmeHostApiIndex = Pa_HostApiTypeIdToHostApiIndex( paMME ); + wmmeHostApiInfo = Pa_GetHostApiInfo( wmmeHostApiIndex ); + + if( argc > 5 ) + usage(wmmeHostApiIndex); + + deviceIndex = wmmeHostApiInfo->defaultOutputDevice; + if( argc >= 2 ){ + deviceIndex = -1; + if( sscanf( argv[1], "%d", &deviceIndex ) != 1 ) + usage(wmmeHostApiIndex); + if( deviceIndex < 0 || deviceIndex >= Pa_GetDeviceCount() || Pa_GetDeviceInfo(deviceIndex)->hostApi != wmmeHostApiIndex ){ + usage(wmmeHostApiIndex); + } + } + + printf( "Using device id %d (%s)\n", deviceIndex, Pa_GetDeviceInfo(deviceIndex)->name ); + + if( argc >= 3 ){ + if( sscanf( argv[2], "%lf", &sampleRate ) != 1 ) + usage(wmmeHostApiIndex); + } + + printf( "Testing with sample rate %f.\n", (float)sampleRate ); + + if( argc == 4 ){ + if( sscanf( argv[3], "%d", &wmmeMinBufferCount ) != 1 ) + usage(wmmeHostApiIndex); + wmmeMaxBufferCount = wmmeMinBufferCount; + } + + if( argc == 5 ){ + if( sscanf( argv[3], "%d", &wmmeMinBufferCount ) != 1 ) + usage(wmmeHostApiIndex); + if( sscanf( argv[4], "%d", &wmmeMaxBufferCount ) != 1 ) + usage(wmmeHostApiIndex); + } + + printf( "Testing buffer counts from %d to %d\n", wmmeMinBufferCount, wmmeMaxBufferCount ); + + + /* initialise sinusoidal wavetable */ + for( i=0; iname ); + fflush( resultsFp ); + + fprintf( resultsFp, "Sample rate: %f\n", (float)sampleRate ); + fprintf( resultsFp, "Buffer count, Smallest working buffer size (frames), Smallest working buffering latency (frames), Smallest working buffering latency (Seconds)\n" ); + + for( wmmeBufferCount = wmmeMinBufferCount; wmmeBufferCount <= wmmeMaxBufferCount; ++wmmeBufferCount ){ + + printf( "Test %d of %d\n", (wmmeBufferCount - wmmeMinBufferCount) + 1, (wmmeMaxBufferCount-wmmeMinBufferCount) + 1 ); + printf( "Testing with %d buffers...\n", wmmeBufferCount ); + + /* + Binary search after Niklaus Wirth + from http://en.wikipedia.org/wiki/Binary_search_algorithm#The_algorithm + */ + min = 1; + max = (int)((sampleRate * .3) / (wmmeBufferCount-1)); //8192; /* we assume that this size works 300ms */ + smallestWorkingBufferSize = 0; + + do{ + mid = min + ((max - min) / 2); + + wmmeBufferSize = mid; + testResult = playUntilKeyPress( deviceIndex, sampleRate, wmmeBufferSize, wmmeBufferSize, wmmeBufferCount ); + + if( testResult == YES ){ + max = mid - 1; + smallestWorkingBufferSize = wmmeBufferSize; + }else{ + min = mid + 1; + } + + }while( (min <= max) && (testResult == YES || testResult == NO) ); + + smallestWorkingBufferingLatencyFrames = smallestWorkingBufferSize * (wmmeBufferCount - 1); + + printf( "Smallest working buffer size for %d buffers is: %d\n", wmmeBufferCount, smallestWorkingBufferSize ); + printf( "Corresponding to buffering latency of %d frames, or %f seconds.\n", smallestWorkingBufferingLatencyFrames, smallestWorkingBufferingLatencyFrames / sampleRate ); + + fprintf( resultsFp, "%d, %d, %d, %f\n", wmmeBufferCount, smallestWorkingBufferSize, smallestWorkingBufferingLatencyFrames, smallestWorkingBufferingLatencyFrames / sampleRate ); + fflush( resultsFp ); + } + + fprintf( resultsFp, "###\n" ); + fclose( resultsFp ); + + Pa_Terminate(); + printf("Test finished.\n"); + + return err; +error: + Pa_Terminate(); + fprintf( stderr, "An error occured while using the portaudio stream\n" ); + fprintf( stderr, "Error number: %d\n", err ); + fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); + return err; +} + diff --git a/extern/portaudio/test/patest_wmme_low_level_latency_params.c b/extern/portaudio/test/patest_wmme_low_level_latency_params.c new file mode 100644 index 0000000..a28c88b --- /dev/null +++ b/extern/portaudio/test/patest_wmme_low_level_latency_params.c @@ -0,0 +1,192 @@ +/* + * $Id: $ + * Portable Audio I/O Library + * Windows MME low level buffer parameters test + * + * Copyright (c) 2007 Ross Bencina + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +#include +#include + +#include /* required when using pa_win_wmme.h */ +#include /* required when using pa_win_wmme.h */ + +#include "portaudio.h" +#include "pa_win_wmme.h" + +#define NUM_SECONDS (6) +#define SAMPLE_RATE (44100) + +#define WMME_FRAMES_PER_BUFFER (440) +#define WMME_BUFFER_COUNT (6) + +#define FRAMES_PER_BUFFER WMME_FRAMES_PER_BUFFER /* hardwire portaudio callback buffer size to WMME buffer size for this test */ + +#ifndef M_PI +#define M_PI (3.14159265) +#endif + +#define TABLE_SIZE (2048) + +#define CHANNEL_COUNT (2) + + +typedef struct +{ + float sine[TABLE_SIZE]; + double phase; +} +paTestData; + +/* This routine will be called by the PortAudio engine when audio is needed. +** It may called at interrupt level on some machines so don't do anything +** that could mess up the system like calling malloc() or free(). +*/ +static int patestCallback( const void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + const PaStreamCallbackTimeInfo* timeInfo, + PaStreamCallbackFlags statusFlags, + void *userData ) +{ + paTestData *data = (paTestData*)userData; + float *out = (float*)outputBuffer; + unsigned long i,j; + + (void) timeInfo; /* Prevent unused variable warnings. */ + (void) statusFlags; + (void) inputBuffer; + + for( i=0; isine[(int)data->phase]; + data->phase += 20; + if( data->phase >= TABLE_SIZE ){ + data->phase -= TABLE_SIZE; + } + + for( j = 0; j < CHANNEL_COUNT; ++j ){ + *out++ = x; + } + } + + return paContinue; +} + +/*******************************************************************/ +int main(int argc, char* argv[]) +{ + PaStreamParameters outputParameters; + PaWinMmeStreamInfo wmmeStreamInfo; + PaStream *stream; + PaError err; + paTestData data; + int i; + int deviceIndex; + + printf("PortAudio Test: output a sine blip on each channel. SR = %d, BufSize = %d, Chans = %d\n", SAMPLE_RATE, FRAMES_PER_BUFFER, CHANNEL_COUNT); + + err = Pa_Initialize(); + if( err != paNoError ) goto error; + + deviceIndex = Pa_GetHostApiInfo( Pa_HostApiTypeIdToHostApiIndex( paMME ) )->defaultOutputDevice; + if( argc == 2 ){ + sscanf( argv[1], "%d", &deviceIndex ); + } + + printf( "using device id %d (%s)\n", deviceIndex, Pa_GetDeviceInfo(deviceIndex)->name ); + + /* initialise sinusoidal wavetable */ + for( i=0; idefaultLowOutputLatency;*/ + outputParameters.hostApiSpecificStreamInfo = NULL; + + wmmeStreamInfo.size = sizeof(PaWinMmeStreamInfo); + wmmeStreamInfo.hostApiType = paMME; + wmmeStreamInfo.version = 1; + wmmeStreamInfo.flags = paWinMmeUseLowLevelLatencyParameters | paWinMmeDontThrottleOverloadedProcessingThread; + wmmeStreamInfo.framesPerBuffer = WMME_FRAMES_PER_BUFFER; + wmmeStreamInfo.bufferCount = WMME_BUFFER_COUNT; + outputParameters.hostApiSpecificStreamInfo = &wmmeStreamInfo; + + + if( Pa_IsFormatSupported( 0, &outputParameters, SAMPLE_RATE ) == paFormatIsSupported ){ + printf( "Pa_IsFormatSupported reports device will support %d channels.\n", CHANNEL_COUNT ); + }else{ + printf( "Pa_IsFormatSupported reports device will not support %d channels.\n", CHANNEL_COUNT ); + } + + err = Pa_OpenStream( + &stream, + NULL, /* no input */ + &outputParameters, + SAMPLE_RATE, + FRAMES_PER_BUFFER, + paClipOff, /* we won't output out of range samples so don't bother clipping them */ + patestCallback, + &data ); + if( err != paNoError ) goto error; + + err = Pa_StartStream( stream ); + if( err != paNoError ) goto error; + + printf("Play for %d seconds.\n", NUM_SECONDS ); + Pa_Sleep( NUM_SECONDS * 1000 ); + + err = Pa_StopStream( stream ); + if( err != paNoError ) goto error; + + err = Pa_CloseStream( stream ); + if( err != paNoError ) goto error; + + Pa_Terminate(); + printf("Test finished.\n"); + + return err; +error: + Pa_Terminate(); + fprintf( stderr, "An error occured while using the portaudio stream\n" ); + fprintf( stderr, "Error number: %d\n", err ); + fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); + return err; +} + diff --git a/extern/portaudio/test/patest_write_stop.c b/extern/portaudio/test/patest_write_stop.c new file mode 100644 index 0000000..243e774 --- /dev/null +++ b/extern/portaudio/test/patest_write_stop.c @@ -0,0 +1,165 @@ +/** @file patest_write_stop.c + @brief Play a few seconds of silence followed by a few cycles of a sine wave. Tests to make sure that pa_StopStream() completes playback in blocking I/O + @author Bjorn Roche of XO Audio (www.xoaudio.com) + @author Ross Bencina + @author Phil Burk +*/ +/* + * $Id$ + * + * This program uses the PortAudio Portable Audio Library. + * For more information see: http://www.portaudio.com/ + * Copyright (c) 1999-2000 Ross Bencina and Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +#include +#include +#include "portaudio.h" + +#define NUM_SECONDS (5) +#define SAMPLE_RATE (44100) +#define FRAMES_PER_BUFFER (1024) + +#ifndef M_PI +#define M_PI (3.14159265) +#endif + +#define TABLE_SIZE (200) + + +int main(void); +int main(void) +{ + PaStreamParameters outputParameters; + PaStream *stream; + PaError err; + float buffer[FRAMES_PER_BUFFER][2]; /* stereo output buffer */ + float sine[TABLE_SIZE]; /* sine wavetable */ + int left_phase = 0; + int right_phase = 0; + int left_inc = 1; + int right_inc = 3; /* higher pitch so we can distinguish left and right. */ + int i, j; + int bufferCount; + const int framesBy2 = FRAMES_PER_BUFFER >> 1; + const float framesBy2f = (float) framesBy2 ; + + + printf( "PortAudio Test: output silence, followed by one buffer of a ramped sine wave. SR = %d, BufSize = %d\n", + SAMPLE_RATE, FRAMES_PER_BUFFER); + + /* initialise sinusoidal wavetable */ + for( i=0; idefaultHighOutputLatency * 5; + outputParameters.hostApiSpecificStreamInfo = NULL; + + /* open the stream */ + err = Pa_OpenStream( + &stream, + NULL, /* no input */ + &outputParameters, + SAMPLE_RATE, + FRAMES_PER_BUFFER, + paClipOff, /* we won't output out of range samples so don't bother clipping them */ + NULL, /* no callback, use blocking API */ + NULL ); /* no callback, so no callback userData */ + if( err != paNoError ) goto error; + + /* start the stream */ + err = Pa_StartStream( stream ); + if( err != paNoError ) goto error; + + printf("Playing %d seconds of silence followed by one buffer of a ramped sinusoid.\n", NUM_SECONDS ); + + bufferCount = ((NUM_SECONDS * SAMPLE_RATE) / FRAMES_PER_BUFFER); + + /* clear buffer */ + for( j=0; j < FRAMES_PER_BUFFER; j++ ) + { + buffer[j][0] = 0; /* left */ + buffer[j][1] = 0; /* right */ + } + /* play the silent buffer a bunch o' times */ + for( i=0; i < bufferCount; i++ ) + { + err = Pa_WriteStream( stream, buffer, FRAMES_PER_BUFFER ); + if( err != paNoError ) goto error; + } + /* play a non-silent buffer once */ + for( j=0; j < FRAMES_PER_BUFFER; j++ ) + { + float ramp = 1; + if( j < framesBy2 ) + ramp = j / framesBy2f; + else + ramp = (FRAMES_PER_BUFFER - j) / framesBy2f ; + + buffer[j][0] = sine[left_phase] * ramp; /* left */ + buffer[j][1] = sine[right_phase] * ramp; /* right */ + left_phase += left_inc; + if( left_phase >= TABLE_SIZE ) left_phase -= TABLE_SIZE; + right_phase += right_inc; + if( right_phase >= TABLE_SIZE ) right_phase -= TABLE_SIZE; + } + err = Pa_WriteStream( stream, buffer, FRAMES_PER_BUFFER ); + if( err != paNoError ) goto error; + + /* stop stream, close, and terminate */ + err = Pa_StopStream( stream ); + if( err != paNoError ) goto error; + + err = Pa_CloseStream( stream ); + if( err != paNoError ) goto error; + + Pa_Terminate(); + printf("Test finished.\n"); + + return err; +error: + Pa_Terminate(); + fprintf( stderr, "An error occured while using the portaudio stream\n" ); + fprintf( stderr, "Error number: %d\n", err ); + fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); + return err; +} diff --git a/extern/portaudio/test/patest_write_stop_hang_illegal.c b/extern/portaudio/test/patest_write_stop_hang_illegal.c new file mode 100644 index 0000000..ed93425 --- /dev/null +++ b/extern/portaudio/test/patest_write_stop_hang_illegal.c @@ -0,0 +1,168 @@ +/** @file patest_write_stop_threads.c + @brief Call Pa_StopStream() from another thread to see if PortAudio hangs. + @author Bjorn Roche of XO Audio (www.xoaudio.com) + @author Ross Bencina + @author Phil Burk +*/ +/* + * $Id$ + * + * This program uses the PortAudio Portable Audio Library. + * For more information see: http://www.portaudio.com/ + * Copyright (c) 1999-2000 Ross Bencina and Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +#include +#include +#include +#include +/* pthread may only be available on Mac and Linux. */ +#include +#include "portaudio.h" + +#define SAMPLE_RATE (44100) +#define FRAMES_PER_BUFFER (2048) + +static float s_buffer[FRAMES_PER_BUFFER][2]; /* stereo output buffer */ + +/** + * WARNING: PortAudio is NOT thread safe. DO NOT call PortAudio + * from multiple threads without synchronization. This test uses + * PA in an ILLEGAL WAY in order to try to flush out potential hang bugs. + * The test calls Pa_WriteStream() and Pa_StopStream() simultaneously + * from separate threads in order to try to cause Pa_StopStream() to hang. + * In the main thread we write to the stream in a loop. + * Then try stopping PA from another thread to see if it hangs. + * + * @note: Do not expect this test to pass. The test is only here + * as a debugging aid for hang bugs. Since this test uses PA in an + * illegal way, it may fail for reasons that are not PA bugs. + */ + +/* Wait for awhile then abort the stream. */ +void *stop_thread_proc(void *arg) +{ + PaStream *stream = (PaStream *)arg; + PaTime time; + for (int i = 0; i < 20; i++) + { + /* ILLEGAL unsynchronised call to PA, see comment above */ + time = Pa_GetStreamTime( stream ); + printf("Stream time = %f\n", time); + fflush(stdout); + usleep(100 * 1000); + } + printf("Call Pa_StopStream()\n"); + fflush(stdout); + /* ILLEGAL unsynchronised call to PA, see comment above */ + PaError err = Pa_StopStream( stream ); + printf("Pa_StopStream() returned %d\n", err); + fflush(stdout); + + return stream; +} + +int main(void); +int main(void) +{ + PaStreamParameters outputParameters; + PaStream *stream; + PaError err; + int result; + pthread_t thread; + + printf( "PortAudio Test: output silence and stop from another thread. SR = %d, BufSize = %d\n", + SAMPLE_RATE, FRAMES_PER_BUFFER); + + err = Pa_Initialize(); + if( err != paNoError ) goto error; + + outputParameters.device = Pa_GetDefaultOutputDevice(); /* default output device */ + outputParameters.channelCount = 2; /* stereo output */ + outputParameters.sampleFormat = paFloat32; /* 32 bit floating point output */ + outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultHighOutputLatency * 5; + outputParameters.hostApiSpecificStreamInfo = NULL; + + /* open the stream */ + err = Pa_OpenStream( + &stream, + NULL, /* no input */ + &outputParameters, + SAMPLE_RATE, + FRAMES_PER_BUFFER, + paClipOff, /* we won't output out of range samples so don't bother clipping them */ + NULL, /* no callback, use blocking API */ + NULL ); /* no callback, so no callback userData */ + if( err != paNoError ) goto error; + + result = pthread_create(&thread, NULL /* attributes */, stop_thread_proc, stream); + + /* start the stream */ + err = Pa_StartStream( stream ); + if( err != paNoError ) goto error; + + /* clear buffer */ + memset( s_buffer, 0, sizeof(s_buffer) ); + + /* play the silent buffer many times */ + while( Pa_IsStreamActive(stream) > 0 ) + { + err = Pa_WriteStream( stream, s_buffer, FRAMES_PER_BUFFER ); + printf("Pa_WriteStream returns %d = %s\n", err, Pa_GetErrorText( err )); + if( err != paNoError ) + { + err = paNoError; + break; + }; + } + + printf("Try to join the thread that called Pa_StopStream().\n"); + result = pthread_join( thread, NULL ); + printf("pthread_join returned %d\n", result); + + /* close, and terminate */ + printf("Call Pa_CloseStream\n"); + err = Pa_CloseStream( stream ); + if( err != paNoError ) goto error; + + Pa_Terminate(); + printf("Test finished.\n"); + + return err; +error: + Pa_Terminate(); + fprintf( stderr, "An error occured while using the portaudio stream\n" ); + fprintf( stderr, "Error number: %d\n", err ); + fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); + return err; +} diff --git a/extern/portaudio/testcvs/changeme.txt b/extern/portaudio/testcvs/changeme.txt new file mode 100644 index 0000000..48904b7 --- /dev/null +++ b/extern/portaudio/testcvs/changeme.txt @@ -0,0 +1,21 @@ +This is just a dopy little file used to test the source code repository. +Feel free to trash this file. +Minor change. +Another tweak. +philburk tweak +stephane test +Phil changed this again on 2/21/02. Yawn... +Bjorn test3! +Phil tried to change this on 5/13/08 +Now we are using SVN instead of CVS. PB 2/10/10 +Test from builder-pc + +make a change using SVN on Ubuntu +tweak +testing + +PLB changing it to see if SVN broken +Testing from Ubuntu with SVN on Assembla. + +5/2/2016 - Now using Git! + diff --git a/extern/portaudio/testcvs/file1.txt b/extern/portaudio/testcvs/file1.txt new file mode 100644 index 0000000..a900ec6 --- /dev/null +++ b/extern/portaudio/testcvs/file1.txt @@ -0,0 +1,9 @@ +This is used to test the SVN versioning system. + + $Revision$ + $Author$ + $Date$ + $Id$ + +After propset svn:keywords + diff --git a/extern/portaudio/testcvs/file2.txt b/extern/portaudio/testcvs/file2.txt new file mode 100644 index 0000000..a900ec6 --- /dev/null +++ b/extern/portaudio/testcvs/file2.txt @@ -0,0 +1,9 @@ +This is used to test the SVN versioning system. + + $Revision$ + $Author$ + $Date$ + $Id$ + +After propset svn:keywords + diff --git a/extern/portaudio/update_gitrevision.sh b/extern/portaudio/update_gitrevision.sh new file mode 100755 index 0000000..80d4f3b --- /dev/null +++ b/extern/portaudio/update_gitrevision.sh @@ -0,0 +1,17 @@ +#!/bin/bash +# +# Write the Git commit SHA to an include file. +# This should be run before compiling code on Linux or Macintosh. +# +revision_filename=src/common/pa_gitrevision.h + +# Run git first to make sure it is installed before corrupting the +# include file. +git rev-parse HEAD + +# Update the include file with the current Git revision. +echo -n "#define PA_GIT_REVISION " > ${revision_filename} +git rev-parse HEAD >> ${revision_filename} + +echo ${revision_filename} now contains +cat ${revision_filename} diff --git a/extern/smaa/CMakeLists.txt b/extern/smaa/CMakeLists.txt new file mode 100644 index 0000000..40ebd91 --- /dev/null +++ b/extern/smaa/CMakeLists.txt @@ -0,0 +1,4 @@ +add_library(SMAA INTERFACE) +target_include_directories(SMAA INTERFACE include) + +add_library(SMAA::SMAA ALIAS SMAA) diff --git a/extern/smaa/include/AreaTex.h b/extern/smaa/include/AreaTex.h new file mode 100644 index 0000000..bdbef8b --- /dev/null +++ b/extern/smaa/include/AreaTex.h @@ -0,0 +1,14980 @@ +/** + * Copyright (C) 2013 Jorge Jimenez (jorge@iryoku.com) + * Copyright (C) 2013 Jose I. Echevarria (joseignacioechevarria@gmail.com) + * Copyright (C) 2013 Belen Masia (bmasia@unizar.es) + * Copyright (C) 2013 Fernando Navarro (fernandn@microsoft.com) + * Copyright (C) 2013 Diego Gutierrez (diegog@unizar.es) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to + * do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. As clarification, there + * is no requirement that the copyright notice and permission be included in + * binary distributions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + + +#ifndef AREATEX_H +#define AREATEX_H + +#define AREATEX_WIDTH 160 +#define AREATEX_HEIGHT 560 +#define AREATEX_PITCH (AREATEX_WIDTH * 2) +#define AREATEX_SIZE (AREATEX_HEIGHT * AREATEX_PITCH) + +/** + * Stored in R8G8 format. Load it in the following format: + * - DX9: D3DFMT_A8L8 + * - DX10: DXGI_FORMAT_R8G8_UNORM + */ +static const unsigned char areaTexBytes[] = { +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x40, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x44, 0x7b, 0x41, 0x5d, +0x42, 0x54, 0x41, 0x4f, 0x42, 0x4b, 0x42, 0x49, 0x42, 0x48, 0x41, 0x47, +0x42, 0x46, 0x42, 0x45, 0x42, 0x45, 0x42, 0x44, 0x42, 0x44, 0x42, 0x44, +0x42, 0x43, 0x41, 0x43, 0x42, 0x43, 0x42, 0x43, 0x42, 0x43, 0x42, 0x43, +0x04, 0x7f, 0x22, 0x3d, 0x2b, 0x3d, 0x30, 0x3d, 0x33, 0x3d, 0x35, 0x3d, +0x37, 0x3d, 0x38, 0x3d, 0x39, 0x3d, 0x39, 0x3d, 0x3a, 0x3d, 0x3a, 0x3d, +0x3b, 0x3d, 0x3b, 0x3d, 0x3b, 0x3d, 0x3c, 0x3d, 0x3c, 0x3d, 0x3c, 0x3d, +0x3c, 0x3d, 0x3c, 0x3d, 0x40, 0x7f, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x0a, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x62, 0x20, 0x4d, 0x2a, 0x48, 0x30, 0x44, 0x33, +0x44, 0x35, 0x44, 0x36, 0x43, 0x37, 0x42, 0x38, 0x43, 0x39, 0x42, 0x39, +0x42, 0x3a, 0x42, 0x3a, 0x42, 0x3b, 0x42, 0x3b, 0x42, 0x3b, 0x41, 0x3b, +0x42, 0x3c, 0x42, 0x3c, 0x42, 0x3c, 0x42, 0x3c, 0x00, 0x5d, 0x0c, 0x49, +0x16, 0x43, 0x1d, 0x41, 0x22, 0x40, 0x26, 0x3f, 0x29, 0x3f, 0x2c, 0x3f, +0x2e, 0x3e, 0x2f, 0x3e, 0x31, 0x3e, 0x32, 0x3e, 0x33, 0x3e, 0x33, 0x3e, +0x34, 0x3e, 0x35, 0x3e, 0x35, 0x3e, 0x36, 0x3e, 0x37, 0x3e, 0x37, 0x3e, +0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x66, 0x00, 0x3f, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x66, 0x00, 0x3f, 0x00, 0x03, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x6d, 0x0b, 0x57, 0x16, 0x4f, 0x1d, 0x4a, 0x22, 0x48, 0x26, 0x47, 0x29, +0x46, 0x2b, 0x44, 0x2d, 0x44, 0x2f, 0x44, 0x30, 0x44, 0x31, 0x44, 0x32, +0x43, 0x33, 0x43, 0x34, 0x43, 0x34, 0x42, 0x35, 0x43, 0x36, 0x42, 0x36, +0x42, 0x37, 0x42, 0x37, 0x00, 0x68, 0x06, 0x54, 0x0d, 0x4b, 0x14, 0x47, +0x19, 0x44, 0x1d, 0x43, 0x20, 0x41, 0x23, 0x41, 0x26, 0x40, 0x27, 0x40, +0x29, 0x3f, 0x2b, 0x3f, 0x2c, 0x3f, 0x2d, 0x3f, 0x2e, 0x3f, 0x2f, 0x3f, +0x30, 0x3f, 0x30, 0x3e, 0x31, 0x3e, 0x32, 0x3e, 0x41, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x72, 0x00, 0x5c, +0x00, 0x2d, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x72, 0x00, 0x5c, 0x00, 0x2d, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x72, 0x06, 0x5f, 0x0d, +0x56, 0x14, 0x4f, 0x19, 0x4d, 0x1d, 0x4a, 0x20, 0x49, 0x23, 0x47, 0x25, +0x46, 0x27, 0x46, 0x29, 0x45, 0x2a, 0x45, 0x2c, 0x44, 0x2d, 0x44, 0x2e, +0x44, 0x2f, 0x43, 0x30, 0x44, 0x30, 0x44, 0x31, 0x43, 0x32, 0x43, 0x33, +0x00, 0x6d, 0x04, 0x5b, 0x09, 0x51, 0x0e, 0x4c, 0x13, 0x48, 0x17, 0x46, +0x1a, 0x44, 0x1d, 0x43, 0x1f, 0x42, 0x22, 0x42, 0x24, 0x41, 0x25, 0x41, +0x27, 0x40, 0x28, 0x40, 0x29, 0x40, 0x2a, 0x3f, 0x2b, 0x3f, 0x2c, 0x3f, +0x2d, 0x3f, 0x2e, 0x3f, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x6a, 0x00, 0x48, 0x00, 0x22, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x6a, 0x00, +0x48, 0x00, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x75, 0x03, 0x64, 0x09, 0x5a, 0x0e, 0x54, 0x13, +0x51, 0x17, 0x4e, 0x1a, 0x4c, 0x1d, 0x49, 0x1f, 0x49, 0x22, 0x48, 0x23, +0x47, 0x25, 0x46, 0x26, 0x46, 0x28, 0x45, 0x29, 0x45, 0x2a, 0x44, 0x2b, +0x44, 0x2c, 0x44, 0x2d, 0x44, 0x2e, 0x44, 0x2e, 0x00, 0x70, 0x02, 0x60, +0x07, 0x56, 0x0b, 0x50, 0x0f, 0x4c, 0x12, 0x49, 0x16, 0x47, 0x18, 0x46, +0x1b, 0x45, 0x1d, 0x44, 0x1f, 0x43, 0x21, 0x42, 0x22, 0x42, 0x24, 0x41, +0x25, 0x41, 0x26, 0x40, 0x27, 0x40, 0x28, 0x40, 0x29, 0x40, 0x2a, 0x3f, +0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x7a, 0x00, 0x71, 0x00, 0x59, 0x00, 0x3a, 0x00, 0x1b, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x7a, 0x00, 0x71, 0x00, 0x59, 0x00, 0x3a, 0x00, +0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x77, 0x02, 0x68, 0x06, 0x5f, 0x0b, 0x58, 0x0f, 0x54, 0x12, 0x51, 0x15, +0x4f, 0x18, 0x4c, 0x1b, 0x4b, 0x1d, 0x4a, 0x1f, 0x49, 0x21, 0x48, 0x22, +0x48, 0x23, 0x47, 0x25, 0x46, 0x26, 0x45, 0x27, 0x45, 0x28, 0x45, 0x29, +0x45, 0x2a, 0x44, 0x2b, 0x00, 0x72, 0x02, 0x64, 0x05, 0x5b, 0x08, 0x54, +0x0c, 0x50, 0x0f, 0x4d, 0x12, 0x4a, 0x14, 0x48, 0x17, 0x47, 0x19, 0x46, +0x1b, 0x45, 0x1d, 0x44, 0x1f, 0x44, 0x20, 0x42, 0x21, 0x42, 0x22, 0x42, +0x24, 0x41, 0x25, 0x41, 0x26, 0x41, 0x27, 0x40, 0x41, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x75, +0x00, 0x63, 0x00, 0x4a, 0x00, 0x30, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x7c, 0x00, 0x75, 0x00, 0x63, 0x00, 0x4a, 0x00, 0x30, 0x00, 0x16, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x78, 0x02, 0x6b, 0x05, +0x62, 0x08, 0x5b, 0x0c, 0x57, 0x0f, 0x54, 0x12, 0x51, 0x14, 0x4e, 0x17, +0x4d, 0x19, 0x4c, 0x1b, 0x4b, 0x1d, 0x4a, 0x1e, 0x49, 0x20, 0x48, 0x21, +0x48, 0x22, 0x46, 0x24, 0x46, 0x25, 0x46, 0x26, 0x46, 0x27, 0x45, 0x27, +0x00, 0x74, 0x01, 0x66, 0x04, 0x5e, 0x07, 0x57, 0x0a, 0x53, 0x0d, 0x4f, +0x10, 0x4d, 0x12, 0x4b, 0x14, 0x49, 0x16, 0x48, 0x18, 0x46, 0x1a, 0x45, +0x1b, 0x45, 0x1d, 0x44, 0x1e, 0x44, 0x20, 0x43, 0x21, 0x42, 0x22, 0x42, +0x23, 0x42, 0x24, 0x41, 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x78, 0x00, 0x6a, 0x00, 0x56, +0x00, 0x3f, 0x00, 0x28, 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x78, 0x00, +0x6a, 0x00, 0x56, 0x00, 0x3f, 0x00, 0x28, 0x00, 0x13, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x79, 0x01, 0x6d, 0x04, 0x65, 0x07, 0x5e, 0x0a, +0x5a, 0x0d, 0x56, 0x0f, 0x54, 0x12, 0x51, 0x14, 0x4f, 0x16, 0x4e, 0x18, +0x4c, 0x1a, 0x4b, 0x1b, 0x4b, 0x1d, 0x4a, 0x1e, 0x49, 0x1f, 0x48, 0x21, +0x48, 0x22, 0x48, 0x23, 0x47, 0x23, 0x46, 0x25, 0x00, 0x75, 0x01, 0x69, +0x03, 0x61, 0x06, 0x5a, 0x08, 0x56, 0x0b, 0x52, 0x0d, 0x4f, 0x10, 0x4d, +0x12, 0x4b, 0x14, 0x4a, 0x16, 0x48, 0x17, 0x47, 0x19, 0x46, 0x1a, 0x45, +0x1c, 0x45, 0x1d, 0x44, 0x1e, 0x44, 0x1f, 0x44, 0x20, 0x43, 0x21, 0x42, +0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x7d, 0x00, 0x79, 0x00, 0x6e, 0x00, 0x5e, 0x00, 0x4b, 0x00, 0x37, +0x00, 0x23, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x7d, 0x00, 0x79, 0x00, 0x6e, 0x00, 0x5e, 0x00, +0x4b, 0x00, 0x37, 0x00, 0x23, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x7a, 0x01, 0x6f, 0x03, 0x67, 0x06, 0x60, 0x08, 0x5d, 0x0b, 0x59, 0x0d, +0x56, 0x10, 0x53, 0x11, 0x51, 0x14, 0x50, 0x15, 0x4e, 0x17, 0x4d, 0x19, +0x4c, 0x1a, 0x4b, 0x1b, 0x4b, 0x1d, 0x48, 0x1e, 0x49, 0x1f, 0x49, 0x20, +0x48, 0x21, 0x48, 0x22, 0x00, 0x76, 0x01, 0x6b, 0x03, 0x63, 0x05, 0x5d, +0x07, 0x58, 0x09, 0x54, 0x0c, 0x52, 0x0e, 0x4f, 0x10, 0x4d, 0x11, 0x4c, +0x13, 0x4a, 0x15, 0x49, 0x17, 0x48, 0x18, 0x47, 0x19, 0x46, 0x1b, 0x45, +0x1c, 0x45, 0x1d, 0x44, 0x1e, 0x44, 0x1f, 0x44, 0x41, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7d, 0x00, 0x7a, +0x00, 0x72, 0x00, 0x64, 0x00, 0x54, 0x00, 0x42, 0x00, 0x30, 0x00, 0x1f, +0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x7d, 0x00, 0x7a, 0x00, 0x72, 0x00, 0x64, 0x00, 0x54, 0x00, 0x42, 0x00, +0x30, 0x00, 0x1f, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x7b, 0x01, 0x71, 0x02, +0x69, 0x05, 0x63, 0x07, 0x5f, 0x09, 0x5b, 0x0c, 0x58, 0x0e, 0x55, 0x10, +0x53, 0x11, 0x52, 0x13, 0x50, 0x15, 0x4e, 0x16, 0x4e, 0x18, 0x4c, 0x19, +0x4c, 0x1a, 0x4a, 0x1c, 0x4b, 0x1d, 0x49, 0x1e, 0x49, 0x1f, 0x49, 0x20, +0x00, 0x77, 0x00, 0x6c, 0x02, 0x65, 0x04, 0x5f, 0x06, 0x5a, 0x08, 0x57, +0x0a, 0x54, 0x0c, 0x51, 0x0e, 0x4f, 0x10, 0x4d, 0x11, 0x4c, 0x13, 0x4a, +0x15, 0x49, 0x16, 0x48, 0x18, 0x48, 0x18, 0x46, 0x1a, 0x46, 0x1b, 0x45, +0x1c, 0x45, 0x1d, 0x45, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7b, 0x00, 0x74, 0x00, 0x69, +0x00, 0x5b, 0x00, 0x4b, 0x00, 0x3b, 0x00, 0x2b, 0x00, 0x1b, 0x00, 0x0d, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7b, 0x00, +0x74, 0x00, 0x69, 0x00, 0x5b, 0x00, 0x4b, 0x00, 0x3b, 0x00, 0x2b, 0x00, +0x1b, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x7b, 0x00, 0x72, 0x02, 0x6b, 0x04, 0x64, 0x06, +0x61, 0x08, 0x5d, 0x0a, 0x5a, 0x0c, 0x56, 0x0e, 0x55, 0x10, 0x53, 0x11, +0x52, 0x13, 0x50, 0x15, 0x4f, 0x16, 0x4e, 0x17, 0x4d, 0x18, 0x4b, 0x1a, +0x4b, 0x1a, 0x4b, 0x1c, 0x4b, 0x1d, 0x49, 0x1d, 0x00, 0x77, 0x00, 0x6e, +0x02, 0x66, 0x04, 0x61, 0x05, 0x5c, 0x07, 0x59, 0x09, 0x56, 0x0b, 0x53, +0x0d, 0x51, 0x0f, 0x4f, 0x10, 0x4e, 0x11, 0x4c, 0x13, 0x4b, 0x14, 0x4a, +0x15, 0x48, 0x17, 0x48, 0x18, 0x47, 0x19, 0x46, 0x1b, 0x46, 0x1b, 0x45, +0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x7e, 0x00, 0x7c, 0x00, 0x76, 0x00, 0x6d, 0x00, 0x61, 0x00, 0x53, +0x00, 0x44, 0x00, 0x35, 0x00, 0x27, 0x00, 0x19, 0x00, 0x0c, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7c, 0x00, 0x76, 0x00, 0x6d, 0x00, +0x61, 0x00, 0x53, 0x00, 0x44, 0x00, 0x35, 0x00, 0x27, 0x00, 0x19, 0x00, +0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x7c, 0x00, 0x73, 0x02, 0x6c, 0x03, 0x66, 0x05, 0x63, 0x07, 0x5e, 0x09, +0x5c, 0x0b, 0x58, 0x0c, 0x57, 0x0e, 0x55, 0x10, 0x53, 0x11, 0x52, 0x13, +0x50, 0x14, 0x4f, 0x15, 0x4e, 0x17, 0x4c, 0x18, 0x4c, 0x19, 0x4c, 0x1a, +0x4b, 0x1a, 0x4b, 0x1c, 0x00, 0x77, 0x00, 0x6f, 0x02, 0x68, 0x03, 0x63, +0x05, 0x5e, 0x06, 0x5a, 0x08, 0x57, 0x0a, 0x55, 0x0b, 0x53, 0x0d, 0x50, +0x0f, 0x4f, 0x10, 0x4e, 0x11, 0x4c, 0x13, 0x4b, 0x14, 0x4a, 0x15, 0x49, +0x16, 0x48, 0x18, 0x48, 0x18, 0x46, 0x19, 0x46, 0x41, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7c, +0x00, 0x77, 0x00, 0x6f, 0x00, 0x65, 0x00, 0x59, 0x00, 0x4c, 0x00, 0x3e, +0x00, 0x30, 0x00, 0x23, 0x00, 0x16, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x7e, 0x00, 0x7c, 0x00, 0x77, 0x00, 0x6f, 0x00, 0x65, 0x00, 0x59, 0x00, +0x4c, 0x00, 0x3e, 0x00, 0x30, 0x00, 0x23, 0x00, 0x16, 0x00, 0x0b, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x7c, 0x00, 0x74, 0x02, +0x6e, 0x03, 0x68, 0x05, 0x64, 0x06, 0x60, 0x08, 0x5d, 0x0a, 0x5a, 0x0b, +0x58, 0x0d, 0x56, 0x0e, 0x55, 0x10, 0x53, 0x11, 0x52, 0x13, 0x50, 0x14, +0x50, 0x15, 0x4d, 0x16, 0x4e, 0x18, 0x4c, 0x18, 0x4c, 0x19, 0x4c, 0x1a, +0x00, 0x78, 0x00, 0x70, 0x01, 0x69, 0x03, 0x64, 0x04, 0x60, 0x06, 0x5c, +0x07, 0x59, 0x09, 0x56, 0x0b, 0x54, 0x0c, 0x52, 0x0d, 0x50, 0x0f, 0x4f, +0x10, 0x4e, 0x11, 0x4c, 0x13, 0x4b, 0x13, 0x4a, 0x15, 0x4a, 0x15, 0x48, +0x17, 0x48, 0x18, 0x47, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7d, 0x00, 0x78, 0x00, 0x71, +0x00, 0x68, 0x00, 0x5e, 0x00, 0x52, 0x00, 0x45, 0x00, 0x39, 0x00, 0x2c, +0x00, 0x20, 0x00, 0x15, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7d, 0x00, +0x78, 0x00, 0x71, 0x00, 0x68, 0x00, 0x5e, 0x00, 0x52, 0x00, 0x45, 0x00, +0x39, 0x00, 0x2c, 0x00, 0x20, 0x00, 0x15, 0x00, 0x0a, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x7d, 0x00, 0x75, 0x01, 0x6f, 0x02, 0x69, 0x04, +0x65, 0x06, 0x62, 0x07, 0x5f, 0x09, 0x5b, 0x0b, 0x5a, 0x0c, 0x58, 0x0d, +0x56, 0x0e, 0x55, 0x10, 0x53, 0x11, 0x52, 0x13, 0x50, 0x13, 0x4f, 0x15, +0x4e, 0x15, 0x4e, 0x17, 0x4d, 0x18, 0x4c, 0x18, 0x00, 0x78, 0x00, 0x71, +0x01, 0x6a, 0x03, 0x66, 0x04, 0x61, 0x05, 0x5d, 0x06, 0x5a, 0x08, 0x58, +0x09, 0x55, 0x0b, 0x53, 0x0d, 0x52, 0x0e, 0x50, 0x0f, 0x4e, 0x10, 0x4e, +0x11, 0x4c, 0x13, 0x4c, 0x13, 0x4a, 0x15, 0x4a, 0x15, 0x49, 0x16, 0x48, +0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x7e, 0x00, 0x7d, 0x00, 0x79, 0x00, 0x73, 0x00, 0x6b, 0x00, 0x62, +0x00, 0x57, 0x00, 0x4c, 0x00, 0x40, 0x00, 0x34, 0x00, 0x29, 0x00, 0x1e, +0x00, 0x13, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7d, 0x00, 0x79, 0x00, 0x73, 0x00, +0x6b, 0x00, 0x62, 0x00, 0x57, 0x00, 0x4c, 0x00, 0x40, 0x00, 0x34, 0x00, +0x29, 0x00, 0x1e, 0x00, 0x13, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x7d, 0x00, 0x76, 0x01, 0x70, 0x02, 0x6a, 0x03, 0x67, 0x05, 0x63, 0x06, +0x60, 0x08, 0x5d, 0x09, 0x5b, 0x0b, 0x59, 0x0c, 0x57, 0x0d, 0x55, 0x0e, +0x55, 0x10, 0x53, 0x11, 0x52, 0x13, 0x4f, 0x13, 0x50, 0x15, 0x4f, 0x15, +0x4e, 0x16, 0x4e, 0x18, 0x00, 0x79, 0x00, 0x71, 0x01, 0x6c, 0x02, 0x66, +0x04, 0x62, 0x05, 0x5f, 0x06, 0x5c, 0x07, 0x59, 0x09, 0x57, 0x0a, 0x55, +0x0b, 0x53, 0x0d, 0x51, 0x0e, 0x50, 0x0f, 0x4e, 0x11, 0x4e, 0x11, 0x4c, +0x13, 0x4c, 0x13, 0x4b, 0x14, 0x4a, 0x15, 0x4a, 0x41, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7d, +0x00, 0x7a, 0x00, 0x75, 0x00, 0x6e, 0x00, 0x65, 0x00, 0x5b, 0x00, 0x51, +0x00, 0x46, 0x00, 0x3b, 0x00, 0x30, 0x00, 0x26, 0x00, 0x1b, 0x00, 0x12, +0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x7e, 0x00, 0x7d, 0x00, 0x7a, 0x00, 0x75, 0x00, 0x6e, 0x00, 0x65, 0x00, +0x5b, 0x00, 0x51, 0x00, 0x46, 0x00, 0x3b, 0x00, 0x30, 0x00, 0x26, 0x00, +0x1b, 0x00, 0x12, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x7d, 0x00, 0x76, 0x01, +0x71, 0x02, 0x6c, 0x03, 0x68, 0x05, 0x64, 0x06, 0x61, 0x07, 0x5e, 0x09, +0x5c, 0x0a, 0x5a, 0x0b, 0x59, 0x0c, 0x57, 0x0e, 0x55, 0x0e, 0x55, 0x11, +0x52, 0x11, 0x51, 0x12, 0x51, 0x13, 0x50, 0x14, 0x4f, 0x15, 0x4e, 0x15, +0x00, 0x79, 0x00, 0x72, 0x01, 0x6d, 0x02, 0x68, 0x03, 0x63, 0x04, 0x60, +0x06, 0x5d, 0x07, 0x5b, 0x08, 0x58, 0x09, 0x56, 0x0b, 0x54, 0x0c, 0x53, +0x0d, 0x51, 0x0e, 0x50, 0x0f, 0x4e, 0x11, 0x4e, 0x11, 0x4c, 0x12, 0x4c, +0x13, 0x4b, 0x14, 0x4a, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x00, 0x1f, 0x00, 0x3f, +0x00, 0x66, 0x00, 0x72, 0x00, 0x78, 0x00, 0x7a, 0x00, 0x7c, 0x00, 0x7c, +0x00, 0x7d, 0x00, 0x7d, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x7e, +0x00, 0x7e, 0x00, 0x7e, 0x00, 0x7d, 0x00, 0x58, 0x00, 0x70, 0x00, 0x77, +0x00, 0x79, 0x00, 0x7b, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7d, 0x00, 0x7d, +0x00, 0x7e, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x7e, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x1f, 0x00, 0x3f, +0x00, 0x66, 0x00, 0x72, 0x00, 0x78, 0x00, 0x7a, 0x00, 0x7c, 0x00, 0x7c, +0x00, 0x7d, 0x00, 0x7d, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x7e, +0x00, 0x7e, 0x00, 0x7e, 0x1f, 0x1f, 0x00, 0x3f, 0x00, 0x66, 0x00, 0x72, +0x00, 0x78, 0x00, 0x7a, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7d, 0x00, 0x7d, +0x00, 0x7e, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x7e, +0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x7d, 0x00, 0x77, 0x01, 0x72, 0x02, 0x6d, 0x03, +0x69, 0x04, 0x66, 0x06, 0x63, 0x07, 0x5f, 0x08, 0x5e, 0x09, 0x5c, 0x0b, +0x5a, 0x0c, 0x58, 0x0c, 0x57, 0x0e, 0x55, 0x0f, 0x54, 0x11, 0x51, 0x11, +0x52, 0x12, 0x51, 0x13, 0x50, 0x14, 0x50, 0x15, 0x00, 0x79, 0x00, 0x73, +0x01, 0x6d, 0x02, 0x69, 0x03, 0x65, 0x04, 0x61, 0x05, 0x5e, 0x06, 0x5c, +0x07, 0x59, 0x09, 0x57, 0x0a, 0x55, 0x0b, 0x54, 0x0d, 0x53, 0x0d, 0x51, +0x0f, 0x50, 0x0f, 0x4e, 0x11, 0x4e, 0x11, 0x4c, 0x12, 0x4c, 0x13, 0x4b, +0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x3f, 0x00, 0x5c, +0x00, 0x6a, 0x00, 0x71, 0x00, 0x75, 0x00, 0x78, 0x00, 0x79, 0x00, 0x7a, +0x00, 0x7b, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7d, 0x00, 0x7d, 0x00, 0x7d, +0x00, 0x58, 0x00, 0x44, 0x00, 0x55, 0x00, 0x67, 0x00, 0x6e, 0x00, 0x72, +0x00, 0x75, 0x00, 0x78, 0x00, 0x79, 0x00, 0x7a, 0x00, 0x7b, 0x00, 0x7c, +0x00, 0x7c, 0x00, 0x7d, 0x00, 0x7d, 0x00, 0x7d, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x0a, 0x0a, 0x00, 0x3f, 0x00, 0x5c, +0x00, 0x6a, 0x00, 0x71, 0x00, 0x75, 0x00, 0x78, 0x00, 0x79, 0x00, 0x7a, +0x00, 0x7b, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7d, 0x00, 0x7d, 0x00, 0x7d, +0x3f, 0x00, 0x0a, 0x0a, 0x00, 0x3f, 0x00, 0x5c, 0x00, 0x6a, 0x00, 0x71, +0x00, 0x75, 0x00, 0x78, 0x00, 0x79, 0x00, 0x7a, 0x00, 0x7b, 0x00, 0x7c, +0x00, 0x7c, 0x00, 0x7d, 0x00, 0x7d, 0x00, 0x7d, 0x41, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x7d, 0x00, 0x78, 0x01, 0x72, 0x02, 0x6e, 0x02, 0x6a, 0x03, 0x67, 0x05, +0x64, 0x06, 0x60, 0x07, 0x5f, 0x09, 0x5c, 0x0a, 0x5b, 0x0b, 0x5a, 0x0c, +0x57, 0x0c, 0x56, 0x0e, 0x55, 0x0f, 0x53, 0x11, 0x52, 0x11, 0x52, 0x12, +0x51, 0x13, 0x50, 0x13, 0x00, 0x79, 0x00, 0x73, 0x01, 0x6e, 0x02, 0x69, +0x03, 0x66, 0x04, 0x62, 0x05, 0x5f, 0x06, 0x5d, 0x07, 0x5b, 0x08, 0x58, +0x09, 0x56, 0x0b, 0x55, 0x0b, 0x53, 0x0d, 0x52, 0x0d, 0x50, 0x0f, 0x50, +0x0f, 0x4e, 0x11, 0x4e, 0x11, 0x4d, 0x12, 0x4c, 0x41, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x2d, 0x00, 0x48, 0x00, 0x59, +0x00, 0x63, 0x00, 0x6a, 0x00, 0x6e, 0x00, 0x72, 0x00, 0x74, 0x00, 0x76, +0x00, 0x77, 0x00, 0x78, 0x00, 0x79, 0x00, 0x7a, 0x00, 0x70, 0x00, 0x55, +0x00, 0x20, 0x00, 0x3e, 0x00, 0x50, 0x00, 0x5a, 0x00, 0x63, 0x00, 0x6a, +0x00, 0x6e, 0x00, 0x72, 0x00, 0x74, 0x00, 0x76, 0x00, 0x77, 0x00, 0x78, +0x00, 0x79, 0x00, 0x7a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x66, 0x00, 0x3f, 0x00, 0x03, 0x03, 0x00, 0x2d, 0x00, 0x48, 0x00, 0x59, +0x00, 0x63, 0x00, 0x6a, 0x00, 0x6e, 0x00, 0x72, 0x00, 0x74, 0x00, 0x76, +0x00, 0x77, 0x00, 0x78, 0x00, 0x79, 0x00, 0x7a, 0x66, 0x00, 0x3f, 0x00, +0x03, 0x03, 0x00, 0x2d, 0x00, 0x48, 0x00, 0x59, 0x00, 0x63, 0x00, 0x6a, +0x00, 0x6e, 0x00, 0x72, 0x00, 0x74, 0x00, 0x76, 0x00, 0x77, 0x00, 0x78, +0x00, 0x79, 0x00, 0x7a, 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x7e, 0x00, 0x78, 0x01, +0x73, 0x02, 0x6e, 0x02, 0x6b, 0x03, 0x68, 0x05, 0x65, 0x06, 0x61, 0x07, +0x5f, 0x07, 0x5e, 0x09, 0x5c, 0x0b, 0x5a, 0x0b, 0x59, 0x0c, 0x57, 0x0d, +0x56, 0x0e, 0x54, 0x0f, 0x54, 0x11, 0x52, 0x11, 0x52, 0x12, 0x51, 0x13, +0x00, 0x79, 0x00, 0x74, 0x00, 0x6f, 0x02, 0x6a, 0x03, 0x66, 0x04, 0x63, +0x05, 0x60, 0x05, 0x5e, 0x06, 0x5b, 0x07, 0x59, 0x09, 0x58, 0x09, 0x55, +0x0b, 0x55, 0x0c, 0x53, 0x0d, 0x52, 0x0d, 0x50, 0x0f, 0x50, 0x0f, 0x4e, +0x11, 0x4e, 0x11, 0x4d, 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x01, 0x00, 0x22, 0x00, 0x3a, 0x00, 0x4a, 0x00, 0x56, +0x00, 0x5e, 0x00, 0x64, 0x00, 0x69, 0x00, 0x6d, 0x00, 0x6f, 0x00, 0x71, +0x00, 0x73, 0x00, 0x75, 0x00, 0x77, 0x00, 0x67, 0x00, 0x3e, 0x00, 0x0d, +0x00, 0x28, 0x00, 0x3a, 0x00, 0x4a, 0x00, 0x56, 0x00, 0x5e, 0x00, 0x64, +0x00, 0x69, 0x00, 0x6d, 0x00, 0x6f, 0x00, 0x71, 0x00, 0x73, 0x00, 0x75, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x72, 0x00, 0x5c, 0x00, +0x2d, 0x00, 0x01, 0x01, 0x00, 0x22, 0x00, 0x3a, 0x00, 0x4a, 0x00, 0x56, +0x00, 0x5e, 0x00, 0x64, 0x00, 0x69, 0x00, 0x6d, 0x00, 0x6f, 0x00, 0x71, +0x00, 0x73, 0x00, 0x75, 0x72, 0x00, 0x5c, 0x00, 0x2d, 0x00, 0x01, 0x01, +0x00, 0x22, 0x00, 0x3a, 0x00, 0x4a, 0x00, 0x56, 0x00, 0x5e, 0x00, 0x64, +0x00, 0x69, 0x00, 0x6d, 0x00, 0x6f, 0x00, 0x71, 0x00, 0x73, 0x00, 0x75, +0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x7e, 0x00, 0x78, 0x00, 0x74, 0x01, 0x6f, 0x02, +0x6c, 0x03, 0x68, 0x04, 0x65, 0x05, 0x62, 0x06, 0x61, 0x07, 0x5f, 0x09, +0x5c, 0x09, 0x5b, 0x0b, 0x5a, 0x0b, 0x58, 0x0c, 0x57, 0x0d, 0x55, 0x0e, +0x55, 0x0f, 0x54, 0x11, 0x52, 0x11, 0x52, 0x12, 0x00, 0x79, 0x00, 0x74, +0x00, 0x70, 0x01, 0x6b, 0x02, 0x67, 0x03, 0x64, 0x04, 0x61, 0x05, 0x5f, +0x06, 0x5d, 0x07, 0x5b, 0x08, 0x58, 0x09, 0x57, 0x0a, 0x55, 0x0b, 0x54, +0x0c, 0x53, 0x0d, 0x51, 0x0e, 0x50, 0x0f, 0x50, 0x0f, 0x4e, 0x11, 0x4e, +0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x1b, 0x00, 0x30, 0x00, 0x3f, 0x00, 0x4b, 0x00, 0x54, +0x00, 0x5b, 0x00, 0x61, 0x00, 0x65, 0x00, 0x68, 0x00, 0x6b, 0x00, 0x6e, +0x00, 0x79, 0x00, 0x6e, 0x00, 0x50, 0x00, 0x28, 0x00, 0x01, 0x00, 0x1b, +0x00, 0x30, 0x00, 0x3f, 0x00, 0x4b, 0x00, 0x54, 0x00, 0x5b, 0x00, 0x61, +0x00, 0x65, 0x00, 0x68, 0x00, 0x6b, 0x00, 0x6e, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x6a, 0x00, 0x48, 0x00, 0x22, 0x00, +0x00, 0x00, 0x00, 0x1b, 0x00, 0x30, 0x00, 0x3f, 0x00, 0x4b, 0x00, 0x54, +0x00, 0x5b, 0x00, 0x61, 0x00, 0x65, 0x00, 0x68, 0x00, 0x6b, 0x00, 0x6e, +0x78, 0x00, 0x6a, 0x00, 0x48, 0x00, 0x22, 0x00, 0x00, 0x00, 0x00, 0x1b, +0x00, 0x30, 0x00, 0x3f, 0x00, 0x4b, 0x00, 0x54, 0x00, 0x5b, 0x00, 0x61, +0x00, 0x65, 0x00, 0x68, 0x00, 0x6b, 0x00, 0x6e, 0x21, 0x5d, 0x0c, 0x68, +0x06, 0x6d, 0x04, 0x71, 0x02, 0x72, 0x02, 0x74, 0x01, 0x75, 0x01, 0x76, +0x01, 0x77, 0x00, 0x77, 0x00, 0x77, 0x00, 0x78, 0x00, 0x78, 0x00, 0x79, +0x00, 0x79, 0x00, 0x79, 0x00, 0x79, 0x00, 0x79, 0x00, 0x79, 0x00, 0x7a, +0x42, 0x40, 0x17, 0x55, 0x0c, 0x60, 0x08, 0x66, 0x05, 0x6a, 0x04, 0x6d, +0x03, 0x6f, 0x02, 0x71, 0x02, 0x73, 0x01, 0x73, 0x01, 0x74, 0x01, 0x75, +0x01, 0x76, 0x01, 0x77, 0x00, 0x77, 0x00, 0x77, 0x00, 0x78, 0x00, 0x78, +0x00, 0x78, 0x00, 0x78, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, +0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, +0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, +0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x21, 0x5d, 0x0c, 0x68, +0x06, 0x6d, 0x04, 0x71, 0x02, 0x72, 0x02, 0x74, 0x01, 0x75, 0x01, 0x76, +0x01, 0x77, 0x00, 0x77, 0x00, 0x77, 0x00, 0x78, 0x00, 0x78, 0x00, 0x79, +0x00, 0x79, 0x00, 0x79, 0x00, 0x79, 0x00, 0x79, 0x00, 0x79, 0x00, 0x7a, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x16, 0x00, 0x28, 0x00, 0x37, 0x00, 0x42, 0x00, 0x4b, 0x00, 0x53, +0x00, 0x59, 0x00, 0x5e, 0x00, 0x62, 0x00, 0x65, 0x00, 0x7b, 0x00, 0x72, +0x00, 0x5a, 0x00, 0x3a, 0x00, 0x1b, 0x00, 0x01, 0x00, 0x16, 0x00, 0x28, +0x00, 0x37, 0x00, 0x42, 0x00, 0x4b, 0x00, 0x53, 0x00, 0x59, 0x00, 0x5e, +0x00, 0x62, 0x00, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x7a, 0x00, 0x71, 0x00, 0x59, 0x00, 0x3a, 0x00, 0x1b, 0x00, 0x00, 0x00, +0x00, 0x16, 0x00, 0x28, 0x00, 0x37, 0x00, 0x42, 0x00, 0x4b, 0x00, 0x53, +0x00, 0x59, 0x00, 0x5e, 0x00, 0x62, 0x00, 0x65, 0x7a, 0x00, 0x71, 0x00, +0x59, 0x00, 0x3a, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x28, +0x00, 0x37, 0x00, 0x42, 0x00, 0x4b, 0x00, 0x53, 0x00, 0x59, 0x00, 0x5e, +0x00, 0x62, 0x00, 0x65, 0x2b, 0x49, 0x16, 0x53, 0x0d, 0x5b, 0x09, 0x60, +0x07, 0x64, 0x05, 0x67, 0x04, 0x69, 0x03, 0x6b, 0x03, 0x6c, 0x02, 0x6e, +0x02, 0x6f, 0x02, 0x70, 0x01, 0x71, 0x01, 0x71, 0x01, 0x72, 0x01, 0x73, +0x01, 0x73, 0x01, 0x74, 0x00, 0x74, 0x00, 0x75, 0x57, 0x16, 0x2d, 0x2c, +0x1b, 0x3b, 0x12, 0x45, 0x0d, 0x4d, 0x0b, 0x53, 0x08, 0x57, 0x07, 0x5b, +0x05, 0x5e, 0x05, 0x61, 0x04, 0x63, 0x04, 0x65, 0x03, 0x67, 0x02, 0x68, +0x02, 0x69, 0x02, 0x6b, 0x02, 0x6c, 0x01, 0x6d, 0x01, 0x6e, 0x01, 0x6f, +0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, +0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, +0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, +0x00, 0x7b, 0x00, 0x7b, 0x2b, 0x49, 0x16, 0x53, 0x0d, 0x5b, 0x09, 0x60, +0x07, 0x64, 0x05, 0x67, 0x04, 0x69, 0x03, 0x6b, 0x03, 0x6c, 0x02, 0x6e, +0x02, 0x6f, 0x02, 0x70, 0x01, 0x71, 0x01, 0x71, 0x01, 0x72, 0x01, 0x73, +0x01, 0x73, 0x01, 0x74, 0x00, 0x74, 0x00, 0x75, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, +0x00, 0x23, 0x00, 0x30, 0x00, 0x3b, 0x00, 0x44, 0x00, 0x4c, 0x00, 0x52, +0x00, 0x57, 0x00, 0x5b, 0x00, 0x7c, 0x00, 0x75, 0x00, 0x63, 0x00, 0x4a, +0x00, 0x30, 0x00, 0x16, 0x00, 0x00, 0x00, 0x13, 0x00, 0x23, 0x00, 0x30, +0x00, 0x3b, 0x00, 0x44, 0x00, 0x4c, 0x00, 0x52, 0x00, 0x57, 0x00, 0x5b, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x75, 0x00, +0x63, 0x00, 0x4a, 0x00, 0x30, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x13, +0x00, 0x23, 0x00, 0x30, 0x00, 0x3b, 0x00, 0x44, 0x00, 0x4c, 0x00, 0x52, +0x00, 0x57, 0x00, 0x5b, 0x7c, 0x00, 0x75, 0x00, 0x63, 0x00, 0x4a, 0x00, +0x30, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x23, 0x00, 0x30, +0x00, 0x3b, 0x00, 0x44, 0x00, 0x4c, 0x00, 0x52, 0x00, 0x57, 0x00, 0x5b, +0x31, 0x43, 0x1d, 0x4b, 0x14, 0x51, 0x0e, 0x56, 0x0b, 0x5b, 0x08, 0x5e, +0x07, 0x61, 0x06, 0x63, 0x05, 0x65, 0x04, 0x67, 0x04, 0x68, 0x03, 0x69, +0x03, 0x6a, 0x03, 0x6c, 0x02, 0x6d, 0x02, 0x6d, 0x02, 0x6e, 0x02, 0x6f, +0x02, 0x70, 0x01, 0x70, 0x61, 0x0c, 0x3b, 0x1b, 0x28, 0x28, 0x1d, 0x32, +0x16, 0x3a, 0x11, 0x41, 0x0e, 0x47, 0x0c, 0x4b, 0x0a, 0x4f, 0x09, 0x53, +0x07, 0x55, 0x06, 0x58, 0x05, 0x5a, 0x05, 0x5c, 0x05, 0x5e, 0x04, 0x60, +0x04, 0x61, 0x04, 0x63, 0x03, 0x64, 0x02, 0x66, 0x00, 0x7b, 0x00, 0x7b, +0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, +0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, +0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, +0x31, 0x43, 0x1d, 0x4b, 0x14, 0x51, 0x0e, 0x56, 0x0b, 0x5b, 0x08, 0x5e, +0x07, 0x61, 0x06, 0x63, 0x05, 0x65, 0x04, 0x67, 0x04, 0x68, 0x03, 0x69, +0x03, 0x6a, 0x03, 0x6c, 0x02, 0x6d, 0x02, 0x6d, 0x02, 0x6e, 0x02, 0x6f, +0x02, 0x70, 0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x1f, +0x00, 0x2b, 0x00, 0x35, 0x00, 0x3e, 0x00, 0x45, 0x00, 0x4c, 0x00, 0x51, +0x00, 0x7c, 0x00, 0x78, 0x00, 0x6a, 0x00, 0x56, 0x00, 0x3f, 0x00, 0x28, +0x00, 0x13, 0x00, 0x00, 0x00, 0x10, 0x00, 0x1f, 0x00, 0x2b, 0x00, 0x35, +0x00, 0x3e, 0x00, 0x45, 0x00, 0x4c, 0x00, 0x51, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x78, 0x00, 0x6a, 0x00, 0x56, 0x00, +0x3f, 0x00, 0x28, 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x1f, +0x00, 0x2b, 0x00, 0x35, 0x00, 0x3e, 0x00, 0x45, 0x00, 0x4c, 0x00, 0x51, +0x7c, 0x00, 0x78, 0x00, 0x6a, 0x00, 0x56, 0x00, 0x3f, 0x00, 0x28, 0x00, +0x13, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x1f, 0x00, 0x2b, 0x00, 0x35, +0x00, 0x3e, 0x00, 0x45, 0x00, 0x4c, 0x00, 0x51, 0x33, 0x41, 0x22, 0x46, +0x19, 0x4c, 0x13, 0x50, 0x0f, 0x54, 0x0c, 0x57, 0x0a, 0x5a, 0x08, 0x5d, +0x07, 0x5f, 0x06, 0x61, 0x05, 0x63, 0x05, 0x64, 0x04, 0x66, 0x04, 0x66, +0x04, 0x68, 0x03, 0x69, 0x03, 0x69, 0x03, 0x6a, 0x03, 0x6b, 0x02, 0x6c, +0x67, 0x07, 0x45, 0x12, 0x32, 0x1d, 0x26, 0x26, 0x1e, 0x2e, 0x18, 0x34, +0x14, 0x3a, 0x11, 0x3f, 0x0f, 0x44, 0x0c, 0x47, 0x0b, 0x4b, 0x0a, 0x4d, +0x09, 0x51, 0x07, 0x52, 0x07, 0x55, 0x06, 0x57, 0x05, 0x58, 0x05, 0x5a, +0x05, 0x5c, 0x04, 0x5d, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, +0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, +0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, +0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x33, 0x41, 0x22, 0x46, +0x19, 0x4c, 0x13, 0x50, 0x0f, 0x54, 0x0c, 0x57, 0x0a, 0x5a, 0x08, 0x5d, +0x07, 0x5f, 0x06, 0x61, 0x05, 0x63, 0x05, 0x64, 0x04, 0x66, 0x04, 0x66, +0x04, 0x68, 0x03, 0x69, 0x03, 0x69, 0x03, 0x6a, 0x03, 0x6b, 0x02, 0x6c, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x1b, 0x00, 0x27, +0x00, 0x30, 0x00, 0x39, 0x00, 0x40, 0x00, 0x46, 0x00, 0x7d, 0x00, 0x79, +0x00, 0x6e, 0x00, 0x5e, 0x00, 0x4b, 0x00, 0x37, 0x00, 0x23, 0x00, 0x10, +0x00, 0x00, 0x00, 0x0e, 0x00, 0x1b, 0x00, 0x27, 0x00, 0x30, 0x00, 0x39, +0x00, 0x40, 0x00, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x7d, 0x00, 0x79, 0x00, 0x6e, 0x00, 0x5e, 0x00, 0x4b, 0x00, 0x37, 0x00, +0x23, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x1b, 0x00, 0x27, +0x00, 0x30, 0x00, 0x39, 0x00, 0x40, 0x00, 0x46, 0x7d, 0x00, 0x79, 0x00, +0x6e, 0x00, 0x5e, 0x00, 0x4b, 0x00, 0x37, 0x00, 0x23, 0x00, 0x10, 0x00, +0x00, 0x00, 0x00, 0x0e, 0x00, 0x1b, 0x00, 0x27, 0x00, 0x30, 0x00, 0x39, +0x00, 0x40, 0x00, 0x46, 0x35, 0x40, 0x27, 0x44, 0x1d, 0x48, 0x17, 0x4c, +0x12, 0x50, 0x0f, 0x53, 0x0d, 0x56, 0x0b, 0x58, 0x09, 0x5a, 0x08, 0x5c, +0x07, 0x5e, 0x06, 0x60, 0x06, 0x61, 0x05, 0x62, 0x05, 0x63, 0x04, 0x65, +0x04, 0x66, 0x04, 0x66, 0x04, 0x67, 0x03, 0x68, 0x6b, 0x05, 0x4d, 0x0d, +0x3b, 0x16, 0x2e, 0x1e, 0x25, 0x25, 0x1f, 0x2b, 0x1a, 0x31, 0x16, 0x36, +0x13, 0x3a, 0x10, 0x3e, 0x0f, 0x42, 0x0d, 0x45, 0x0c, 0x47, 0x0a, 0x4a, +0x0a, 0x4c, 0x09, 0x4f, 0x07, 0x51, 0x07, 0x52, 0x07, 0x54, 0x06, 0x56, +0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, +0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, +0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, +0x00, 0x7b, 0x00, 0x7b, 0x35, 0x40, 0x27, 0x44, 0x1d, 0x48, 0x17, 0x4c, +0x12, 0x50, 0x0f, 0x53, 0x0d, 0x56, 0x0b, 0x58, 0x09, 0x5a, 0x08, 0x5c, +0x07, 0x5e, 0x06, 0x60, 0x06, 0x61, 0x05, 0x62, 0x05, 0x63, 0x04, 0x65, +0x04, 0x66, 0x04, 0x66, 0x04, 0x67, 0x03, 0x68, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x19, 0x00, 0x23, 0x00, 0x2c, +0x00, 0x34, 0x00, 0x3b, 0x00, 0x7d, 0x00, 0x7a, 0x00, 0x72, 0x00, 0x64, +0x00, 0x54, 0x00, 0x42, 0x00, 0x30, 0x00, 0x1f, 0x00, 0x0e, 0x00, 0x00, +0x00, 0x0d, 0x00, 0x19, 0x00, 0x23, 0x00, 0x2c, 0x00, 0x34, 0x00, 0x3b, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7d, 0x00, 0x7a, 0x00, +0x72, 0x00, 0x64, 0x00, 0x54, 0x00, 0x42, 0x00, 0x30, 0x00, 0x1f, 0x00, +0x0e, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x19, 0x00, 0x23, 0x00, 0x2c, +0x00, 0x34, 0x00, 0x3b, 0x7d, 0x00, 0x7a, 0x00, 0x72, 0x00, 0x64, 0x00, +0x54, 0x00, 0x42, 0x00, 0x30, 0x00, 0x1f, 0x00, 0x0e, 0x00, 0x00, 0x00, +0x00, 0x0d, 0x00, 0x19, 0x00, 0x23, 0x00, 0x2c, 0x00, 0x34, 0x00, 0x3b, +0x37, 0x3f, 0x29, 0x43, 0x21, 0x46, 0x1a, 0x49, 0x16, 0x4d, 0x12, 0x50, +0x10, 0x52, 0x0d, 0x54, 0x0c, 0x57, 0x0a, 0x59, 0x09, 0x5a, 0x08, 0x5c, +0x07, 0x5d, 0x06, 0x5f, 0x06, 0x60, 0x06, 0x61, 0x05, 0x62, 0x05, 0x63, +0x04, 0x64, 0x04, 0x65, 0x6e, 0x04, 0x53, 0x0a, 0x41, 0x11, 0x34, 0x18, +0x2b, 0x1f, 0x24, 0x24, 0x1f, 0x29, 0x1b, 0x2e, 0x17, 0x33, 0x15, 0x37, +0x12, 0x3a, 0x10, 0x3d, 0x0f, 0x40, 0x0d, 0x43, 0x0c, 0x45, 0x0c, 0x48, +0x0a, 0x4a, 0x0a, 0x4c, 0x09, 0x4e, 0x07, 0x4f, 0x00, 0x7b, 0x00, 0x7b, +0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, +0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, +0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, +0x37, 0x3f, 0x29, 0x43, 0x21, 0x46, 0x1a, 0x49, 0x16, 0x4d, 0x12, 0x50, +0x10, 0x52, 0x0d, 0x54, 0x0c, 0x57, 0x0a, 0x59, 0x09, 0x5a, 0x08, 0x5c, +0x07, 0x5d, 0x06, 0x5f, 0x06, 0x60, 0x06, 0x61, 0x05, 0x62, 0x05, 0x63, +0x04, 0x64, 0x04, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x0c, 0x00, 0x16, 0x00, 0x20, 0x00, 0x29, 0x00, 0x30, +0x00, 0x7e, 0x00, 0x7b, 0x00, 0x74, 0x00, 0x69, 0x00, 0x5b, 0x00, 0x4b, +0x00, 0x3b, 0x00, 0x2b, 0x00, 0x1b, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0c, +0x00, 0x16, 0x00, 0x20, 0x00, 0x29, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7b, 0x00, 0x74, 0x00, 0x69, 0x00, +0x5b, 0x00, 0x4b, 0x00, 0x3b, 0x00, 0x2b, 0x00, 0x1b, 0x00, 0x0d, 0x00, +0x00, 0x00, 0x00, 0x0c, 0x00, 0x16, 0x00, 0x20, 0x00, 0x29, 0x00, 0x30, +0x7e, 0x00, 0x7b, 0x00, 0x74, 0x00, 0x69, 0x00, 0x5b, 0x00, 0x4b, 0x00, +0x3b, 0x00, 0x2b, 0x00, 0x1b, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x0c, +0x00, 0x16, 0x00, 0x20, 0x00, 0x29, 0x00, 0x30, 0x38, 0x3f, 0x2c, 0x41, +0x23, 0x44, 0x1d, 0x47, 0x19, 0x4a, 0x14, 0x4d, 0x12, 0x4f, 0x10, 0x52, +0x0e, 0x54, 0x0c, 0x56, 0x0b, 0x57, 0x0a, 0x59, 0x09, 0x5a, 0x08, 0x5c, +0x07, 0x5d, 0x07, 0x5e, 0x06, 0x5f, 0x06, 0x61, 0x05, 0x61, 0x05, 0x62, +0x70, 0x03, 0x58, 0x08, 0x47, 0x0e, 0x3a, 0x14, 0x31, 0x1a, 0x29, 0x1f, +0x24, 0x24, 0x20, 0x28, 0x1c, 0x2d, 0x19, 0x31, 0x16, 0x34, 0x14, 0x37, +0x12, 0x3a, 0x10, 0x3d, 0x0f, 0x3f, 0x0e, 0x42, 0x0c, 0x44, 0x0c, 0x46, +0x0b, 0x47, 0x0a, 0x4a, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, +0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, +0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, +0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x38, 0x3f, 0x2c, 0x41, +0x23, 0x44, 0x1d, 0x47, 0x19, 0x4a, 0x14, 0x4d, 0x12, 0x4f, 0x10, 0x52, +0x0e, 0x54, 0x0c, 0x56, 0x0b, 0x57, 0x0a, 0x59, 0x09, 0x5a, 0x08, 0x5c, +0x07, 0x5d, 0x07, 0x5e, 0x06, 0x5f, 0x06, 0x61, 0x05, 0x61, 0x05, 0x62, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x0b, 0x00, 0x15, 0x00, 0x1e, 0x00, 0x26, 0x00, 0x7e, 0x00, 0x7c, +0x00, 0x76, 0x00, 0x6d, 0x00, 0x61, 0x00, 0x53, 0x00, 0x44, 0x00, 0x35, +0x00, 0x27, 0x00, 0x19, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x15, +0x00, 0x1e, 0x00, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x7e, 0x00, 0x7c, 0x00, 0x76, 0x00, 0x6d, 0x00, 0x61, 0x00, 0x53, 0x00, +0x44, 0x00, 0x35, 0x00, 0x27, 0x00, 0x19, 0x00, 0x0c, 0x00, 0x00, 0x00, +0x00, 0x0b, 0x00, 0x15, 0x00, 0x1e, 0x00, 0x26, 0x7e, 0x00, 0x7c, 0x00, +0x76, 0x00, 0x6d, 0x00, 0x61, 0x00, 0x53, 0x00, 0x44, 0x00, 0x35, 0x00, +0x27, 0x00, 0x19, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x15, +0x00, 0x1e, 0x00, 0x26, 0x39, 0x3f, 0x2e, 0x41, 0x26, 0x43, 0x20, 0x46, +0x1b, 0x48, 0x17, 0x4b, 0x14, 0x4d, 0x12, 0x4f, 0x10, 0x51, 0x0e, 0x53, +0x0d, 0x55, 0x0b, 0x56, 0x0b, 0x58, 0x09, 0x59, 0x09, 0x5b, 0x08, 0x5b, +0x07, 0x5d, 0x07, 0x5e, 0x06, 0x5f, 0x06, 0x60, 0x71, 0x02, 0x5b, 0x07, +0x4c, 0x0c, 0x3f, 0x11, 0x36, 0x16, 0x2e, 0x1b, 0x29, 0x20, 0x24, 0x23, +0x20, 0x28, 0x1d, 0x2b, 0x19, 0x2f, 0x17, 0x32, 0x16, 0x35, 0x12, 0x37, +0x12, 0x3a, 0x10, 0x3c, 0x0f, 0x3f, 0x0e, 0x41, 0x0c, 0x42, 0x0c, 0x45, +0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, +0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, +0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, +0x00, 0x7b, 0x00, 0x7b, 0x39, 0x3f, 0x2e, 0x41, 0x26, 0x43, 0x20, 0x46, +0x1b, 0x48, 0x17, 0x4b, 0x14, 0x4d, 0x12, 0x4f, 0x10, 0x51, 0x0e, 0x53, +0x0d, 0x55, 0x0b, 0x56, 0x0b, 0x58, 0x09, 0x59, 0x09, 0x5b, 0x08, 0x5b, +0x07, 0x5d, 0x07, 0x5e, 0x06, 0x5f, 0x06, 0x60, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, +0x00, 0x13, 0x00, 0x1b, 0x00, 0x7e, 0x00, 0x7c, 0x00, 0x77, 0x00, 0x6f, +0x00, 0x65, 0x00, 0x59, 0x00, 0x4c, 0x00, 0x3e, 0x00, 0x30, 0x00, 0x23, +0x00, 0x16, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x13, 0x00, 0x1b, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7c, 0x00, +0x77, 0x00, 0x6f, 0x00, 0x65, 0x00, 0x59, 0x00, 0x4c, 0x00, 0x3e, 0x00, +0x30, 0x00, 0x23, 0x00, 0x16, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x0a, +0x00, 0x13, 0x00, 0x1b, 0x7e, 0x00, 0x7c, 0x00, 0x77, 0x00, 0x6f, 0x00, +0x65, 0x00, 0x59, 0x00, 0x4c, 0x00, 0x3e, 0x00, 0x30, 0x00, 0x23, 0x00, +0x16, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x13, 0x00, 0x1b, +0x39, 0x3e, 0x2f, 0x40, 0x28, 0x42, 0x22, 0x45, 0x1d, 0x47, 0x19, 0x49, +0x16, 0x4b, 0x14, 0x4d, 0x11, 0x4f, 0x10, 0x51, 0x0f, 0x53, 0x0d, 0x54, +0x0c, 0x55, 0x0b, 0x57, 0x0a, 0x58, 0x09, 0x59, 0x09, 0x5b, 0x08, 0x5b, +0x07, 0x5c, 0x07, 0x5e, 0x73, 0x02, 0x5e, 0x05, 0x4f, 0x0a, 0x44, 0x0f, +0x3a, 0x13, 0x33, 0x18, 0x2d, 0x1c, 0x27, 0x20, 0x23, 0x23, 0x20, 0x27, +0x1d, 0x2a, 0x1a, 0x2d, 0x18, 0x30, 0x16, 0x33, 0x14, 0x35, 0x12, 0x38, +0x12, 0x3a, 0x10, 0x3c, 0x0f, 0x3e, 0x0f, 0x41, 0x00, 0x7b, 0x00, 0x7b, +0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, +0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, +0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, +0x39, 0x3e, 0x2f, 0x40, 0x28, 0x42, 0x22, 0x45, 0x1d, 0x47, 0x19, 0x49, +0x16, 0x4b, 0x14, 0x4d, 0x11, 0x4f, 0x10, 0x51, 0x0f, 0x53, 0x0d, 0x54, +0x0c, 0x55, 0x0b, 0x57, 0x0a, 0x58, 0x09, 0x59, 0x09, 0x5b, 0x08, 0x5b, +0x07, 0x5c, 0x07, 0x5e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x12, +0x00, 0x7e, 0x00, 0x7d, 0x00, 0x78, 0x00, 0x71, 0x00, 0x68, 0x00, 0x5e, +0x00, 0x52, 0x00, 0x45, 0x00, 0x39, 0x00, 0x2c, 0x00, 0x20, 0x00, 0x15, +0x00, 0x0a, 0x00, 0x00, 0x00, 0x09, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7d, 0x00, 0x78, 0x00, 0x71, 0x00, +0x68, 0x00, 0x5e, 0x00, 0x52, 0x00, 0x45, 0x00, 0x39, 0x00, 0x2c, 0x00, +0x20, 0x00, 0x15, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x12, +0x7e, 0x00, 0x7d, 0x00, 0x78, 0x00, 0x71, 0x00, 0x68, 0x00, 0x5e, 0x00, +0x52, 0x00, 0x45, 0x00, 0x39, 0x00, 0x2c, 0x00, 0x20, 0x00, 0x15, 0x00, +0x0a, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x12, 0x3a, 0x3e, 0x31, 0x40, +0x29, 0x42, 0x23, 0x44, 0x1f, 0x46, 0x1b, 0x48, 0x18, 0x4a, 0x15, 0x4c, +0x13, 0x4d, 0x11, 0x4f, 0x10, 0x50, 0x0f, 0x52, 0x0d, 0x53, 0x0d, 0x55, +0x0b, 0x56, 0x0b, 0x57, 0x0a, 0x58, 0x09, 0x59, 0x09, 0x5b, 0x08, 0x5b, +0x74, 0x01, 0x62, 0x05, 0x53, 0x08, 0x47, 0x0c, 0x3e, 0x11, 0x37, 0x15, +0x31, 0x19, 0x2b, 0x1d, 0x27, 0x20, 0x23, 0x23, 0x20, 0x26, 0x1d, 0x2a, +0x1b, 0x2c, 0x19, 0x2f, 0x16, 0x31, 0x16, 0x34, 0x13, 0x35, 0x12, 0x38, +0x12, 0x3b, 0x0f, 0x3b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, +0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, +0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, +0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x3a, 0x3e, 0x31, 0x40, +0x29, 0x42, 0x23, 0x44, 0x1f, 0x46, 0x1b, 0x48, 0x18, 0x4a, 0x15, 0x4c, +0x13, 0x4d, 0x11, 0x4f, 0x10, 0x50, 0x0f, 0x52, 0x0d, 0x53, 0x0d, 0x55, +0x0b, 0x56, 0x0b, 0x57, 0x0a, 0x58, 0x09, 0x59, 0x09, 0x5b, 0x08, 0x5b, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x7e, 0x00, 0x7d, +0x00, 0x79, 0x00, 0x73, 0x00, 0x6b, 0x00, 0x62, 0x00, 0x57, 0x00, 0x4c, +0x00, 0x40, 0x00, 0x34, 0x00, 0x29, 0x00, 0x1e, 0x00, 0x13, 0x00, 0x09, +0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x7e, 0x00, 0x7d, 0x00, 0x79, 0x00, 0x73, 0x00, 0x6b, 0x00, 0x62, 0x00, +0x57, 0x00, 0x4c, 0x00, 0x40, 0x00, 0x34, 0x00, 0x29, 0x00, 0x1e, 0x00, +0x13, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x08, 0x7e, 0x00, 0x7d, 0x00, +0x79, 0x00, 0x73, 0x00, 0x6b, 0x00, 0x62, 0x00, 0x57, 0x00, 0x4c, 0x00, +0x40, 0x00, 0x34, 0x00, 0x29, 0x00, 0x1e, 0x00, 0x13, 0x00, 0x09, 0x00, +0x00, 0x00, 0x00, 0x08, 0x3a, 0x3e, 0x32, 0x3f, 0x2b, 0x41, 0x25, 0x43, +0x21, 0x45, 0x1d, 0x46, 0x1a, 0x48, 0x17, 0x4a, 0x15, 0x4c, 0x13, 0x4e, +0x11, 0x4f, 0x10, 0x50, 0x0f, 0x52, 0x0e, 0x53, 0x0d, 0x54, 0x0c, 0x55, +0x0b, 0x56, 0x0b, 0x58, 0x09, 0x58, 0x09, 0x59, 0x75, 0x01, 0x64, 0x04, +0x56, 0x07, 0x4b, 0x0b, 0x42, 0x0f, 0x3a, 0x12, 0x34, 0x16, 0x2f, 0x19, +0x2a, 0x1d, 0x26, 0x20, 0x23, 0x23, 0x21, 0x26, 0x1d, 0x29, 0x1b, 0x2b, +0x19, 0x2e, 0x18, 0x30, 0x16, 0x32, 0x15, 0x35, 0x12, 0x35, 0x12, 0x38, +0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, +0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, +0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, +0x00, 0x7b, 0x00, 0x7b, 0x3a, 0x3e, 0x32, 0x3f, 0x2b, 0x41, 0x25, 0x43, +0x21, 0x45, 0x1d, 0x46, 0x1a, 0x48, 0x17, 0x4a, 0x15, 0x4c, 0x13, 0x4e, +0x11, 0x4f, 0x10, 0x50, 0x0f, 0x52, 0x0e, 0x53, 0x0d, 0x54, 0x0c, 0x55, +0x0b, 0x56, 0x0b, 0x58, 0x09, 0x58, 0x09, 0x59, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7d, 0x00, 0x7a, 0x00, 0x75, +0x00, 0x6e, 0x00, 0x65, 0x00, 0x5b, 0x00, 0x51, 0x00, 0x46, 0x00, 0x3b, +0x00, 0x30, 0x00, 0x26, 0x00, 0x1b, 0x00, 0x12, 0x00, 0x08, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7d, 0x00, +0x7a, 0x00, 0x75, 0x00, 0x6e, 0x00, 0x65, 0x00, 0x5b, 0x00, 0x51, 0x00, +0x46, 0x00, 0x3b, 0x00, 0x30, 0x00, 0x26, 0x00, 0x1b, 0x00, 0x12, 0x00, +0x08, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7d, 0x00, 0x7a, 0x00, 0x75, 0x00, +0x6e, 0x00, 0x65, 0x00, 0x5b, 0x00, 0x51, 0x00, 0x46, 0x00, 0x3b, 0x00, +0x30, 0x00, 0x26, 0x00, 0x1b, 0x00, 0x12, 0x00, 0x08, 0x00, 0x00, 0x00, +0x3b, 0x3e, 0x33, 0x3f, 0x2c, 0x41, 0x27, 0x42, 0x22, 0x44, 0x1f, 0x45, +0x1c, 0x47, 0x19, 0x49, 0x17, 0x4a, 0x15, 0x4c, 0x13, 0x4e, 0x11, 0x4f, +0x10, 0x50, 0x0f, 0x51, 0x0e, 0x53, 0x0d, 0x54, 0x0c, 0x55, 0x0b, 0x55, +0x0b, 0x57, 0x0a, 0x58, 0x76, 0x01, 0x66, 0x04, 0x58, 0x06, 0x4d, 0x0a, +0x45, 0x0d, 0x3e, 0x10, 0x37, 0x14, 0x32, 0x17, 0x2d, 0x1a, 0x2a, 0x1d, +0x26, 0x21, 0x22, 0x22, 0x21, 0x26, 0x1d, 0x28, 0x1c, 0x2b, 0x19, 0x2c, +0x19, 0x30, 0x16, 0x30, 0x16, 0x33, 0x14, 0x35, 0x00, 0x7b, 0x00, 0x7b, +0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, +0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, +0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, +0x3b, 0x3e, 0x33, 0x3f, 0x2c, 0x41, 0x27, 0x42, 0x22, 0x44, 0x1f, 0x45, +0x1c, 0x47, 0x19, 0x49, 0x17, 0x4a, 0x15, 0x4c, 0x13, 0x4e, 0x11, 0x4f, +0x10, 0x50, 0x0f, 0x51, 0x0e, 0x53, 0x0d, 0x54, 0x0c, 0x55, 0x0b, 0x55, +0x0b, 0x57, 0x0a, 0x58, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x3e, 0x33, 0x3f, +0x2d, 0x40, 0x28, 0x42, 0x24, 0x44, 0x20, 0x45, 0x1d, 0x46, 0x1a, 0x48, +0x18, 0x49, 0x16, 0x4b, 0x14, 0x4c, 0x13, 0x4e, 0x11, 0x4e, 0x10, 0x50, +0x0f, 0x51, 0x0f, 0x53, 0x0d, 0x53, 0x0d, 0x55, 0x0b, 0x55, 0x0b, 0x56, +0x77, 0x01, 0x67, 0x03, 0x5a, 0x05, 0x51, 0x09, 0x48, 0x0c, 0x40, 0x0f, +0x3a, 0x12, 0x35, 0x16, 0x30, 0x18, 0x2c, 0x1b, 0x29, 0x1d, 0x26, 0x21, +0x22, 0x22, 0x21, 0x26, 0x1d, 0x27, 0x1d, 0x2b, 0x1a, 0x2b, 0x19, 0x2e, +0x17, 0x30, 0x16, 0x31, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, +0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, +0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, +0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x3b, 0x3e, 0x33, 0x3f, +0x2d, 0x40, 0x28, 0x42, 0x24, 0x44, 0x20, 0x45, 0x1d, 0x46, 0x1a, 0x48, +0x18, 0x49, 0x16, 0x4b, 0x14, 0x4c, 0x13, 0x4e, 0x11, 0x4e, 0x10, 0x50, +0x0f, 0x51, 0x0f, 0x53, 0x0d, 0x53, 0x0d, 0x55, 0x0b, 0x55, 0x0b, 0x56, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x3b, 0x3e, 0x34, 0x3f, 0x2e, 0x40, 0x29, 0x41, +0x25, 0x43, 0x21, 0x44, 0x1e, 0x45, 0x1c, 0x47, 0x19, 0x48, 0x18, 0x4a, +0x15, 0x4b, 0x14, 0x4c, 0x13, 0x4e, 0x11, 0x4e, 0x11, 0x50, 0x0f, 0x50, +0x0f, 0x52, 0x0d, 0x53, 0x0d, 0x54, 0x0c, 0x55, 0x77, 0x01, 0x68, 0x02, +0x5d, 0x05, 0x52, 0x07, 0x4a, 0x0a, 0x43, 0x0d, 0x3d, 0x10, 0x38, 0x12, +0x33, 0x16, 0x2f, 0x19, 0x2b, 0x1b, 0x28, 0x1d, 0x26, 0x21, 0x22, 0x22, +0x21, 0x26, 0x1e, 0x26, 0x1d, 0x2a, 0x1a, 0x2b, 0x19, 0x2d, 0x18, 0x30, +0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, +0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, +0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, +0x00, 0x7b, 0x00, 0x7b, 0x3b, 0x3e, 0x34, 0x3f, 0x2e, 0x40, 0x29, 0x41, +0x25, 0x43, 0x21, 0x44, 0x1e, 0x45, 0x1c, 0x47, 0x19, 0x48, 0x18, 0x4a, +0x15, 0x4b, 0x14, 0x4c, 0x13, 0x4e, 0x11, 0x4e, 0x11, 0x50, 0x0f, 0x50, +0x0f, 0x52, 0x0d, 0x53, 0x0d, 0x54, 0x0c, 0x55, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x3c, 0x3e, 0x35, 0x3f, 0x2f, 0x40, 0x2a, 0x41, 0x26, 0x42, 0x22, 0x44, +0x20, 0x45, 0x1d, 0x46, 0x1b, 0x48, 0x18, 0x48, 0x17, 0x4a, 0x15, 0x4b, +0x13, 0x4c, 0x13, 0x4e, 0x11, 0x4e, 0x11, 0x50, 0x0f, 0x50, 0x0f, 0x52, +0x0d, 0x53, 0x0d, 0x53, 0x77, 0x00, 0x6a, 0x02, 0x5e, 0x04, 0x55, 0x07, +0x4c, 0x0a, 0x45, 0x0c, 0x40, 0x0f, 0x3a, 0x12, 0x35, 0x14, 0x31, 0x16, +0x2e, 0x19, 0x2b, 0x1c, 0x27, 0x1d, 0x26, 0x22, 0x21, 0x22, 0x21, 0x25, +0x1e, 0x26, 0x1d, 0x29, 0x1b, 0x2b, 0x19, 0x2b, 0x00, 0x7b, 0x00, 0x7b, +0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, +0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, +0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, +0x3c, 0x3e, 0x35, 0x3f, 0x2f, 0x40, 0x2a, 0x41, 0x26, 0x42, 0x22, 0x44, +0x20, 0x45, 0x1d, 0x46, 0x1b, 0x48, 0x18, 0x48, 0x17, 0x4a, 0x15, 0x4b, +0x13, 0x4c, 0x13, 0x4e, 0x11, 0x4e, 0x11, 0x50, 0x0f, 0x50, 0x0f, 0x52, +0x0d, 0x53, 0x0d, 0x53, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x3e, 0x35, 0x3f, +0x30, 0x3f, 0x2b, 0x40, 0x27, 0x42, 0x24, 0x43, 0x21, 0x44, 0x1e, 0x45, +0x1c, 0x46, 0x1a, 0x48, 0x18, 0x49, 0x16, 0x4a, 0x15, 0x4c, 0x13, 0x4c, +0x13, 0x4e, 0x11, 0x4e, 0x11, 0x50, 0x0f, 0x50, 0x0f, 0x51, 0x0e, 0x53, +0x78, 0x00, 0x6b, 0x02, 0x60, 0x04, 0x57, 0x06, 0x4f, 0x09, 0x48, 0x0c, +0x42, 0x0e, 0x3c, 0x10, 0x38, 0x12, 0x34, 0x16, 0x30, 0x18, 0x2d, 0x19, +0x2b, 0x1d, 0x26, 0x1e, 0x25, 0x22, 0x21, 0x22, 0x21, 0x25, 0x1e, 0x26, +0x1d, 0x28, 0x1c, 0x2b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, +0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, +0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, +0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x3c, 0x3e, 0x35, 0x3f, +0x30, 0x3f, 0x2b, 0x40, 0x27, 0x42, 0x24, 0x43, 0x21, 0x44, 0x1e, 0x45, +0x1c, 0x46, 0x1a, 0x48, 0x18, 0x49, 0x16, 0x4a, 0x15, 0x4c, 0x13, 0x4c, +0x13, 0x4e, 0x11, 0x4e, 0x11, 0x50, 0x0f, 0x50, 0x0f, 0x51, 0x0e, 0x53, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x3c, 0x3e, 0x36, 0x3f, 0x30, 0x3f, 0x2c, 0x40, +0x28, 0x41, 0x25, 0x42, 0x22, 0x44, 0x1f, 0x45, 0x1d, 0x46, 0x1b, 0x47, +0x19, 0x48, 0x18, 0x4a, 0x15, 0x4a, 0x15, 0x4c, 0x13, 0x4c, 0x13, 0x4e, +0x11, 0x4e, 0x11, 0x50, 0x0f, 0x50, 0x0f, 0x51, 0x78, 0x00, 0x6d, 0x02, +0x61, 0x04, 0x58, 0x05, 0x51, 0x07, 0x4a, 0x0a, 0x44, 0x0c, 0x3f, 0x0f, +0x3a, 0x12, 0x35, 0x14, 0x32, 0x16, 0x30, 0x19, 0x2b, 0x19, 0x2a, 0x1d, +0x26, 0x1e, 0x25, 0x22, 0x21, 0x22, 0x21, 0x25, 0x1e, 0x26, 0x1d, 0x27, +0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, +0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, +0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, +0x00, 0x7b, 0x00, 0x7b, 0x3c, 0x3e, 0x36, 0x3f, 0x30, 0x3f, 0x2c, 0x40, +0x28, 0x41, 0x25, 0x42, 0x22, 0x44, 0x1f, 0x45, 0x1d, 0x46, 0x1b, 0x47, +0x19, 0x48, 0x18, 0x4a, 0x15, 0x4a, 0x15, 0x4c, 0x13, 0x4c, 0x13, 0x4e, +0x11, 0x4e, 0x11, 0x50, 0x0f, 0x50, 0x0f, 0x51, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x3c, 0x3e, 0x37, 0x3e, 0x31, 0x3f, 0x2d, 0x40, 0x29, 0x41, 0x26, 0x42, +0x23, 0x44, 0x20, 0x45, 0x1e, 0x45, 0x1c, 0x46, 0x1a, 0x48, 0x18, 0x48, +0x17, 0x4a, 0x15, 0x4a, 0x14, 0x4c, 0x13, 0x4c, 0x12, 0x4e, 0x11, 0x4e, +0x11, 0x50, 0x0f, 0x50, 0x78, 0x00, 0x6d, 0x02, 0x63, 0x04, 0x5a, 0x05, +0x53, 0x07, 0x4c, 0x0a, 0x46, 0x0c, 0x41, 0x0f, 0x3c, 0x0f, 0x38, 0x12, +0x35, 0x16, 0x30, 0x16, 0x2e, 0x19, 0x2b, 0x1a, 0x29, 0x1d, 0x26, 0x1e, +0x25, 0x22, 0x21, 0x22, 0x21, 0x25, 0x1f, 0x26, 0x00, 0x7b, 0x00, 0x7b, +0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, +0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, +0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, +0x3c, 0x3e, 0x37, 0x3e, 0x31, 0x3f, 0x2d, 0x40, 0x29, 0x41, 0x26, 0x42, +0x23, 0x44, 0x20, 0x45, 0x1e, 0x45, 0x1c, 0x46, 0x1a, 0x48, 0x18, 0x48, +0x17, 0x4a, 0x15, 0x4a, 0x14, 0x4c, 0x13, 0x4c, 0x12, 0x4e, 0x11, 0x4e, +0x11, 0x50, 0x0f, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x3e, 0x37, 0x3e, +0x32, 0x3f, 0x2e, 0x40, 0x2a, 0x41, 0x27, 0x42, 0x24, 0x43, 0x21, 0x44, +0x1f, 0x45, 0x1d, 0x46, 0x1b, 0x47, 0x1a, 0x48, 0x18, 0x49, 0x16, 0x4a, +0x15, 0x4b, 0x14, 0x4c, 0x13, 0x4d, 0x12, 0x4e, 0x11, 0x4e, 0x11, 0x50, +0x78, 0x00, 0x6e, 0x01, 0x65, 0x03, 0x5c, 0x05, 0x54, 0x07, 0x4e, 0x09, +0x48, 0x0b, 0x43, 0x0c, 0x3e, 0x0f, 0x3b, 0x12, 0x36, 0x12, 0x33, 0x16, +0x30, 0x17, 0x2d, 0x19, 0x2b, 0x1b, 0x28, 0x1d, 0x26, 0x1e, 0x25, 0x22, +0x21, 0x22, 0x21, 0x24, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, +0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, +0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, +0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x3c, 0x3e, 0x37, 0x3e, +0x32, 0x3f, 0x2e, 0x40, 0x2a, 0x41, 0x27, 0x42, 0x24, 0x43, 0x21, 0x44, +0x1f, 0x45, 0x1d, 0x46, 0x1b, 0x47, 0x1a, 0x48, 0x18, 0x49, 0x16, 0x4a, +0x15, 0x4b, 0x14, 0x4c, 0x13, 0x4d, 0x12, 0x4e, 0x11, 0x4e, 0x11, 0x50, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x3c, 0x3e, 0x37, 0x3e, 0x33, 0x3f, 0x2e, 0x3f, +0x2b, 0x40, 0x28, 0x41, 0x25, 0x42, 0x22, 0x44, 0x20, 0x45, 0x1e, 0x45, +0x1c, 0x46, 0x1b, 0x48, 0x19, 0x48, 0x18, 0x4a, 0x16, 0x4a, 0x15, 0x4b, +0x13, 0x4c, 0x13, 0x4d, 0x12, 0x4e, 0x11, 0x4e, 0x79, 0x00, 0x6f, 0x01, +0x66, 0x02, 0x5d, 0x04, 0x56, 0x06, 0x4f, 0x07, 0x4a, 0x0a, 0x45, 0x0c, +0x41, 0x0f, 0x3b, 0x0f, 0x38, 0x12, 0x35, 0x14, 0x31, 0x16, 0x30, 0x18, +0x2b, 0x19, 0x2b, 0x1c, 0x27, 0x1d, 0x26, 0x1f, 0x24, 0x22, 0x21, 0x22, +0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, +0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, +0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7b, +0x00, 0x7b, 0x00, 0x7b, 0x3c, 0x3e, 0x37, 0x3e, 0x33, 0x3f, 0x2e, 0x3f, +0x2b, 0x40, 0x28, 0x41, 0x25, 0x42, 0x22, 0x44, 0x20, 0x45, 0x1e, 0x45, +0x1c, 0x46, 0x1b, 0x48, 0x19, 0x48, 0x18, 0x4a, 0x16, 0x4a, 0x15, 0x4b, +0x13, 0x4c, 0x13, 0x4d, 0x12, 0x4e, 0x11, 0x4e, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x62, 0x00, 0x6c, 0x00, 0x72, 0x00, 0x74, 0x00, 0x77, 0x00, 0x79, 0x00, +0x79, 0x00, 0x7a, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7c, 0x00, 0x7c, 0x00, +0x7d, 0x00, 0x7d, 0x00, 0x7d, 0x00, 0x7c, 0x00, 0x7e, 0x00, 0x7e, 0x00, +0x7e, 0x00, 0x7e, 0x00, 0x81, 0x00, 0x82, 0x00, 0x83, 0x00, 0x81, 0x00, +0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x82, 0x00, 0x83, 0x00, 0x83, 0x00, +0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x81, 0x00, +0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x08, 0x00, 0x44, 0x00, +0x56, 0x00, 0x61, 0x00, 0x67, 0x00, 0x6b, 0x00, 0x6e, 0x00, 0x70, 0x00, +0x71, 0x00, 0x73, 0x00, 0x74, 0x00, 0x75, 0x00, 0x76, 0x00, 0x76, 0x00, +0x77, 0x00, 0x77, 0x00, 0x77, 0x00, 0x78, 0x00, 0x78, 0x00, 0x78, 0x00, +0x44, 0x00, 0x63, 0x00, 0x6c, 0x00, 0x71, 0x00, 0x75, 0x00, 0x77, 0x00, +0x79, 0x00, 0x79, 0x00, 0x7a, 0x00, 0x7b, 0x00, 0x7b, 0x00, 0x7c, 0x00, +0x7c, 0x00, 0x7d, 0x00, 0x7d, 0x00, 0x7c, 0x00, 0x7d, 0x00, 0x7e, 0x00, +0x7e, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4c, 0x0b, 0x57, 0x06, +0x5f, 0x03, 0x63, 0x02, 0x68, 0x02, 0x6b, 0x01, 0x6d, 0x01, 0x6e, 0x01, +0x71, 0x00, 0x72, 0x00, 0x73, 0x00, 0x74, 0x00, 0x75, 0x00, 0x76, 0x00, +0x76, 0x00, 0x76, 0x00, 0x78, 0x00, 0x78, 0x00, 0x78, 0x00, 0x79, 0x00, +0x82, 0x00, 0x82, 0x00, 0x83, 0x00, 0x81, 0x00, 0x83, 0x00, 0x83, 0x00, +0x83, 0x00, 0x82, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, +0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x81, 0x00, 0x83, 0x00, 0x83, 0x00, +0x83, 0x00, 0x83, 0x00, 0x00, 0x40, 0x17, 0x17, 0x2c, 0x0c, 0x3b, 0x07, +0x45, 0x05, 0x4d, 0x04, 0x53, 0x03, 0x57, 0x02, 0x5c, 0x02, 0x5e, 0x01, +0x61, 0x01, 0x63, 0x01, 0x66, 0x01, 0x67, 0x01, 0x68, 0x00, 0x69, 0x00, +0x6b, 0x00, 0x6c, 0x00, 0x6d, 0x00, 0x6e, 0x00, 0x41, 0x20, 0x4d, 0x0b, +0x58, 0x06, 0x5e, 0x03, 0x64, 0x02, 0x68, 0x02, 0x6b, 0x01, 0x6c, 0x01, +0x6f, 0x01, 0x71, 0x00, 0x72, 0x00, 0x73, 0x00, 0x74, 0x00, 0x75, 0x00, +0x76, 0x00, 0x75, 0x00, 0x77, 0x00, 0x78, 0x00, 0x78, 0x00, 0x78, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x47, 0x15, 0x4f, 0x0d, 0x56, 0x09, 0x59, 0x06, +0x5f, 0x05, 0x62, 0x04, 0x65, 0x03, 0x67, 0x02, 0x69, 0x02, 0x6b, 0x02, +0x6c, 0x02, 0x6e, 0x01, 0x6f, 0x01, 0x70, 0x01, 0x71, 0x01, 0x70, 0x01, +0x72, 0x00, 0x73, 0x00, 0x74, 0x00, 0x74, 0x00, 0x83, 0x00, 0x82, 0x00, +0x83, 0x00, 0x81, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x82, 0x00, +0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, +0x83, 0x00, 0x81, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, +0x00, 0x55, 0x0c, 0x2c, 0x1b, 0x1b, 0x27, 0x12, 0x32, 0x0d, 0x3a, 0x0b, +0x41, 0x08, 0x47, 0x07, 0x4c, 0x05, 0x4f, 0x05, 0x53, 0x04, 0x56, 0x04, +0x58, 0x03, 0x5a, 0x02, 0x5d, 0x02, 0x5e, 0x02, 0x60, 0x02, 0x61, 0x01, +0x63, 0x01, 0x64, 0x01, 0x41, 0x2a, 0x47, 0x16, 0x4f, 0x0d, 0x54, 0x09, +0x5b, 0x06, 0x5f, 0x05, 0x62, 0x04, 0x64, 0x03, 0x67, 0x02, 0x69, 0x02, +0x6b, 0x02, 0x6c, 0x02, 0x6e, 0x01, 0x6f, 0x01, 0x70, 0x01, 0x70, 0x01, +0x71, 0x01, 0x72, 0x00, 0x73, 0x00, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x45, 0x1d, 0x4a, 0x14, 0x50, 0x0e, 0x54, 0x0b, 0x59, 0x08, 0x5c, 0x07, +0x5f, 0x06, 0x60, 0x05, 0x64, 0x04, 0x65, 0x03, 0x67, 0x03, 0x68, 0x02, +0x6a, 0x02, 0x6b, 0x02, 0x6c, 0x02, 0x6c, 0x02, 0x6e, 0x02, 0x6f, 0x01, +0x70, 0x01, 0x70, 0x01, 0x83, 0x00, 0x82, 0x00, 0x83, 0x00, 0x81, 0x00, +0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x82, 0x00, 0x83, 0x00, 0x83, 0x00, +0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x81, 0x00, +0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x00, 0x60, 0x08, 0x3b, +0x12, 0x28, 0x1d, 0x1d, 0x26, 0x16, 0x2e, 0x11, 0x34, 0x0e, 0x3a, 0x0c, +0x3f, 0x0a, 0x44, 0x08, 0x47, 0x07, 0x4b, 0x06, 0x4d, 0x05, 0x51, 0x05, +0x52, 0x04, 0x55, 0x04, 0x57, 0x04, 0x58, 0x04, 0x5a, 0x03, 0x5c, 0x02, +0x42, 0x30, 0x45, 0x1d, 0x4b, 0x14, 0x4f, 0x0e, 0x55, 0x0b, 0x59, 0x08, +0x5c, 0x07, 0x5e, 0x06, 0x61, 0x05, 0x64, 0x04, 0x65, 0x03, 0x67, 0x03, +0x68, 0x02, 0x6a, 0x02, 0x6b, 0x02, 0x6b, 0x02, 0x6d, 0x02, 0x6e, 0x02, +0x6f, 0x01, 0x70, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x22, 0x48, 0x19, +0x4d, 0x13, 0x50, 0x0f, 0x54, 0x0c, 0x57, 0x0a, 0x5a, 0x08, 0x5c, 0x07, +0x5f, 0x06, 0x61, 0x05, 0x63, 0x05, 0x64, 0x04, 0x65, 0x03, 0x67, 0x03, +0x68, 0x03, 0x68, 0x02, 0x6a, 0x02, 0x6b, 0x02, 0x6c, 0x02, 0x6d, 0x02, +0x83, 0x00, 0x82, 0x00, 0x83, 0x00, 0x81, 0x00, 0x83, 0x00, 0x83, 0x00, +0x83, 0x00, 0x82, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, +0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x81, 0x00, 0x83, 0x00, 0x83, 0x00, +0x83, 0x00, 0x83, 0x00, 0x00, 0x66, 0x05, 0x45, 0x0d, 0x32, 0x16, 0x26, +0x1e, 0x1e, 0x25, 0x18, 0x2b, 0x14, 0x31, 0x11, 0x36, 0x0f, 0x3a, 0x0c, +0x3e, 0x0b, 0x42, 0x0a, 0x45, 0x09, 0x47, 0x07, 0x4a, 0x07, 0x4c, 0x06, +0x4f, 0x05, 0x51, 0x05, 0x52, 0x05, 0x54, 0x04, 0x41, 0x33, 0x44, 0x22, +0x48, 0x19, 0x4c, 0x13, 0x51, 0x0f, 0x54, 0x0c, 0x57, 0x0a, 0x59, 0x08, +0x5d, 0x07, 0x5f, 0x06, 0x61, 0x05, 0x63, 0x05, 0x64, 0x04, 0x65, 0x03, +0x67, 0x03, 0x67, 0x03, 0x69, 0x02, 0x6a, 0x02, 0x6b, 0x02, 0x6c, 0x02, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x43, 0x26, 0x47, 0x1d, 0x4a, 0x17, 0x4d, 0x12, +0x51, 0x0f, 0x54, 0x0d, 0x56, 0x0b, 0x58, 0x09, 0x5b, 0x08, 0x5d, 0x07, +0x5f, 0x06, 0x60, 0x06, 0x62, 0x05, 0x63, 0x05, 0x64, 0x04, 0x65, 0x03, +0x67, 0x03, 0x67, 0x03, 0x68, 0x03, 0x69, 0x02, 0x83, 0x00, 0x83, 0x00, +0x83, 0x00, 0x81, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x82, 0x00, +0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, +0x83, 0x00, 0x81, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, +0x00, 0x6a, 0x04, 0x4d, 0x0b, 0x3a, 0x11, 0x2e, 0x18, 0x25, 0x1f, 0x1f, +0x24, 0x1a, 0x29, 0x16, 0x2e, 0x13, 0x33, 0x11, 0x37, 0x0f, 0x3a, 0x0d, +0x3d, 0x0c, 0x40, 0x0a, 0x43, 0x0a, 0x45, 0x09, 0x48, 0x07, 0x4a, 0x07, +0x4c, 0x07, 0x4e, 0x06, 0x41, 0x35, 0x43, 0x26, 0x47, 0x1d, 0x49, 0x17, +0x4e, 0x12, 0x51, 0x0f, 0x54, 0x0d, 0x55, 0x0b, 0x59, 0x09, 0x5b, 0x08, +0x5d, 0x07, 0x5f, 0x06, 0x60, 0x06, 0x62, 0x05, 0x63, 0x05, 0x63, 0x04, +0x65, 0x03, 0x67, 0x03, 0x67, 0x03, 0x68, 0x03, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x43, 0x29, 0x45, 0x20, 0x49, 0x1a, 0x4b, 0x15, 0x4f, 0x12, 0x51, 0x0f, +0x54, 0x0d, 0x55, 0x0b, 0x58, 0x0a, 0x5a, 0x09, 0x5b, 0x08, 0x5d, 0x07, +0x5f, 0x06, 0x60, 0x06, 0x61, 0x05, 0x62, 0x05, 0x64, 0x05, 0x65, 0x04, +0x65, 0x03, 0x66, 0x03, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x81, 0x00, +0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x82, 0x00, 0x83, 0x00, 0x83, 0x00, +0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x81, 0x00, +0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x00, 0x6d, 0x03, 0x52, +0x08, 0x41, 0x0e, 0x34, 0x14, 0x2b, 0x1a, 0x24, 0x1f, 0x1f, 0x24, 0x1b, +0x28, 0x17, 0x2d, 0x15, 0x31, 0x12, 0x34, 0x10, 0x37, 0x0f, 0x3a, 0x0d, +0x3d, 0x0c, 0x40, 0x0b, 0x42, 0x0a, 0x44, 0x0a, 0x46, 0x09, 0x47, 0x07, +0x41, 0x36, 0x43, 0x29, 0x46, 0x20, 0x48, 0x1a, 0x4c, 0x15, 0x4f, 0x12, +0x51, 0x0f, 0x53, 0x0d, 0x56, 0x0b, 0x58, 0x0a, 0x5a, 0x09, 0x5b, 0x08, +0x5d, 0x07, 0x5f, 0x06, 0x60, 0x06, 0x60, 0x05, 0x62, 0x05, 0x64, 0x05, +0x65, 0x04, 0x65, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0x2b, 0x45, 0x23, +0x48, 0x1d, 0x49, 0x18, 0x4d, 0x14, 0x4f, 0x12, 0x51, 0x10, 0x53, 0x0e, +0x55, 0x0c, 0x57, 0x0b, 0x59, 0x0a, 0x5a, 0x09, 0x5c, 0x08, 0x5d, 0x07, +0x5f, 0x07, 0x5f, 0x06, 0x61, 0x06, 0x62, 0x05, 0x63, 0x05, 0x64, 0x05, +0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x81, 0x00, 0x83, 0x00, 0x83, 0x00, +0x83, 0x00, 0x82, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, +0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x81, 0x00, 0x83, 0x00, 0x83, 0x00, +0x83, 0x00, 0x83, 0x00, 0x00, 0x6f, 0x02, 0x57, 0x07, 0x47, 0x0c, 0x3a, +0x11, 0x31, 0x16, 0x29, 0x1b, 0x24, 0x20, 0x20, 0x23, 0x1c, 0x28, 0x19, +0x2b, 0x16, 0x2f, 0x14, 0x32, 0x12, 0x35, 0x10, 0x38, 0x0f, 0x3a, 0x0e, +0x3c, 0x0c, 0x3f, 0x0c, 0x41, 0x0b, 0x42, 0x0a, 0x41, 0x37, 0x43, 0x2b, +0x45, 0x23, 0x47, 0x1d, 0x4a, 0x18, 0x4d, 0x14, 0x4f, 0x12, 0x51, 0x10, +0x53, 0x0e, 0x55, 0x0c, 0x57, 0x0b, 0x59, 0x0a, 0x5a, 0x09, 0x5c, 0x08, +0x5d, 0x07, 0x5e, 0x07, 0x60, 0x06, 0x61, 0x06, 0x62, 0x05, 0x63, 0x05, +0x1f, 0x00, 0x3f, 0x00, 0x66, 0x00, 0x72, 0x00, 0x78, 0x00, 0x7a, 0x00, +0x7c, 0x00, 0x7c, 0x00, 0x7d, 0x00, 0x7d, 0x00, 0x7e, 0x00, 0x7e, 0x00, +0x7e, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x1f, 0x1f, 0x3f, 0x00, +0x66, 0x00, 0x72, 0x00, 0x78, 0x00, 0x7a, 0x00, 0x7c, 0x00, 0x7c, 0x00, +0x7d, 0x00, 0x7d, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x7e, 0x00, +0x7e, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x7d, 0x00, 0x58, 0x00, 0x70, 0x00, 0x77, 0x00, 0x79, 0x00, 0x7b, 0x00, +0x7c, 0x00, 0x7c, 0x00, 0x7d, 0x00, 0x7d, 0x00, 0x7e, 0x00, 0x7e, 0x00, +0x7e, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x1f, 0x1f, 0x3f, 0x00, +0x66, 0x00, 0x72, 0x00, 0x78, 0x00, 0x7a, 0x00, 0x7c, 0x00, 0x7c, 0x00, +0x7d, 0x00, 0x7d, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x7e, 0x00, +0x7e, 0x00, 0x7e, 0x00, 0x43, 0x2d, 0x44, 0x25, 0x46, 0x1f, 0x48, 0x1b, +0x4b, 0x17, 0x4d, 0x14, 0x50, 0x12, 0x51, 0x10, 0x53, 0x0e, 0x55, 0x0c, +0x57, 0x0b, 0x58, 0x0b, 0x5a, 0x09, 0x5b, 0x09, 0x5c, 0x08, 0x5c, 0x07, +0x5f, 0x07, 0x60, 0x06, 0x61, 0x06, 0x62, 0x06, 0x83, 0x00, 0x83, 0x00, +0x83, 0x00, 0x81, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x82, 0x00, +0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, +0x83, 0x00, 0x81, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, +0x00, 0x71, 0x02, 0x5b, 0x05, 0x4b, 0x0a, 0x3f, 0x0f, 0x36, 0x13, 0x2e, +0x18, 0x29, 0x1c, 0x23, 0x20, 0x20, 0x23, 0x1d, 0x27, 0x19, 0x2a, 0x17, +0x2d, 0x16, 0x30, 0x12, 0x33, 0x12, 0x35, 0x10, 0x38, 0x0f, 0x3b, 0x0e, +0x3c, 0x0c, 0x3e, 0x0c, 0x41, 0x38, 0x43, 0x2d, 0x44, 0x25, 0x45, 0x1f, +0x49, 0x1b, 0x4b, 0x17, 0x4d, 0x14, 0x4f, 0x11, 0x51, 0x10, 0x53, 0x0e, +0x55, 0x0c, 0x57, 0x0b, 0x58, 0x0b, 0x5a, 0x09, 0x5b, 0x09, 0x5b, 0x08, +0x5e, 0x07, 0x5f, 0x07, 0x60, 0x06, 0x61, 0x06, 0x00, 0x00, 0x0a, 0x00, +0x3f, 0x00, 0x5c, 0x00, 0x6a, 0x00, 0x71, 0x00, 0x75, 0x00, 0x78, 0x00, +0x79, 0x00, 0x7a, 0x00, 0x7b, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7d, 0x00, +0x7d, 0x00, 0x7d, 0x00, 0x00, 0x3f, 0x0a, 0x0a, 0x3f, 0x00, 0x5c, 0x00, +0x6a, 0x00, 0x71, 0x00, 0x75, 0x00, 0x78, 0x00, 0x79, 0x00, 0x7a, 0x00, +0x7b, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7d, 0x00, 0x7d, 0x00, 0x7d, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0x00, 0x44, 0x00, +0x55, 0x00, 0x67, 0x00, 0x6e, 0x00, 0x72, 0x00, 0x75, 0x00, 0x78, 0x00, +0x79, 0x00, 0x7a, 0x00, 0x7b, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7d, 0x00, +0x7d, 0x00, 0x7d, 0x00, 0x00, 0x3f, 0x0a, 0x0a, 0x3f, 0x00, 0x5c, 0x00, +0x6a, 0x00, 0x71, 0x00, 0x75, 0x00, 0x78, 0x00, 0x79, 0x00, 0x7a, 0x00, +0x7b, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7d, 0x00, 0x7d, 0x00, 0x7d, 0x00, +0x42, 0x2f, 0x44, 0x27, 0x46, 0x22, 0x47, 0x1d, 0x4a, 0x19, 0x4c, 0x16, +0x4e, 0x13, 0x4f, 0x11, 0x52, 0x10, 0x53, 0x0e, 0x55, 0x0d, 0x56, 0x0c, +0x58, 0x0b, 0x59, 0x0a, 0x5a, 0x09, 0x5b, 0x09, 0x5c, 0x07, 0x5e, 0x07, +0x5f, 0x07, 0x5f, 0x06, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x82, 0x00, +0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x82, 0x00, 0x83, 0x00, 0x83, 0x00, +0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x81, 0x00, +0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x00, 0x73, 0x01, 0x5e, +0x05, 0x4f, 0x08, 0x44, 0x0c, 0x3a, 0x10, 0x33, 0x15, 0x2d, 0x19, 0x28, +0x1d, 0x23, 0x20, 0x20, 0x23, 0x1d, 0x26, 0x1a, 0x2a, 0x18, 0x2c, 0x16, +0x2f, 0x14, 0x31, 0x12, 0x34, 0x12, 0x35, 0x0f, 0x38, 0x0f, 0x3b, 0x0f, +0x41, 0x39, 0x42, 0x2f, 0x44, 0x27, 0x45, 0x22, 0x48, 0x1d, 0x4a, 0x19, +0x4c, 0x16, 0x4d, 0x14, 0x50, 0x11, 0x52, 0x10, 0x53, 0x0e, 0x55, 0x0d, +0x56, 0x0c, 0x58, 0x0b, 0x59, 0x0a, 0x59, 0x09, 0x5c, 0x09, 0x5c, 0x07, +0x5e, 0x07, 0x5f, 0x07, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x2d, 0x00, +0x48, 0x00, 0x59, 0x00, 0x63, 0x00, 0x6a, 0x00, 0x6e, 0x00, 0x72, 0x00, +0x74, 0x00, 0x76, 0x00, 0x77, 0x00, 0x78, 0x00, 0x79, 0x00, 0x7a, 0x00, +0x00, 0x66, 0x00, 0x3f, 0x03, 0x03, 0x2d, 0x00, 0x48, 0x00, 0x59, 0x00, +0x63, 0x00, 0x6a, 0x00, 0x6e, 0x00, 0x72, 0x00, 0x74, 0x00, 0x76, 0x00, +0x77, 0x00, 0x78, 0x00, 0x79, 0x00, 0x7a, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x55, 0x00, 0x20, 0x00, 0x3e, 0x00, +0x50, 0x00, 0x5a, 0x00, 0x63, 0x00, 0x6a, 0x00, 0x6e, 0x00, 0x72, 0x00, +0x74, 0x00, 0x76, 0x00, 0x77, 0x00, 0x78, 0x00, 0x79, 0x00, 0x7a, 0x00, +0x00, 0x66, 0x00, 0x3f, 0x03, 0x03, 0x2d, 0x00, 0x48, 0x00, 0x59, 0x00, +0x63, 0x00, 0x6a, 0x00, 0x6e, 0x00, 0x72, 0x00, 0x74, 0x00, 0x76, 0x00, +0x77, 0x00, 0x78, 0x00, 0x79, 0x00, 0x7a, 0x00, 0x42, 0x30, 0x44, 0x29, +0x45, 0x23, 0x46, 0x1f, 0x49, 0x1b, 0x4b, 0x18, 0x4c, 0x15, 0x4d, 0x13, +0x50, 0x11, 0x52, 0x10, 0x53, 0x0e, 0x55, 0x0d, 0x56, 0x0c, 0x57, 0x0b, +0x59, 0x0b, 0x59, 0x09, 0x5b, 0x09, 0x5c, 0x09, 0x5c, 0x07, 0x5e, 0x07, +0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x82, 0x00, 0x83, 0x00, 0x83, 0x00, +0x83, 0x00, 0x82, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, +0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x81, 0x00, 0x83, 0x00, 0x83, 0x00, +0x83, 0x00, 0x83, 0x00, 0x00, 0x73, 0x01, 0x61, 0x04, 0x52, 0x07, 0x47, +0x0b, 0x3e, 0x0f, 0x37, 0x12, 0x31, 0x16, 0x2b, 0x19, 0x27, 0x1d, 0x23, +0x20, 0x20, 0x23, 0x1d, 0x26, 0x1b, 0x29, 0x19, 0x2b, 0x16, 0x2e, 0x16, +0x30, 0x13, 0x32, 0x12, 0x35, 0x12, 0x36, 0x0f, 0x41, 0x39, 0x42, 0x30, +0x44, 0x29, 0x44, 0x23, 0x47, 0x1f, 0x49, 0x1b, 0x4b, 0x18, 0x4c, 0x15, +0x4e, 0x13, 0x50, 0x11, 0x52, 0x10, 0x53, 0x0e, 0x55, 0x0d, 0x56, 0x0c, +0x57, 0x0b, 0x57, 0x0b, 0x5a, 0x09, 0x5b, 0x09, 0x5c, 0x09, 0x5c, 0x07, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x22, 0x00, 0x3a, 0x00, +0x4a, 0x00, 0x56, 0x00, 0x5e, 0x00, 0x64, 0x00, 0x69, 0x00, 0x6d, 0x00, +0x6f, 0x00, 0x71, 0x00, 0x73, 0x00, 0x75, 0x00, 0x00, 0x72, 0x00, 0x5c, +0x00, 0x2d, 0x01, 0x01, 0x22, 0x00, 0x3a, 0x00, 0x4a, 0x00, 0x56, 0x00, +0x5e, 0x00, 0x64, 0x00, 0x69, 0x00, 0x6d, 0x00, 0x6f, 0x00, 0x71, 0x00, +0x73, 0x00, 0x75, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x77, 0x00, 0x67, 0x00, 0x3e, 0x00, 0x0d, 0x00, 0x28, 0x00, 0x3a, 0x00, +0x4a, 0x00, 0x56, 0x00, 0x5e, 0x00, 0x64, 0x00, 0x69, 0x00, 0x6d, 0x00, +0x6f, 0x00, 0x71, 0x00, 0x73, 0x00, 0x75, 0x00, 0x00, 0x72, 0x00, 0x5c, +0x00, 0x2d, 0x01, 0x01, 0x22, 0x00, 0x3a, 0x00, 0x4a, 0x00, 0x56, 0x00, +0x5e, 0x00, 0x64, 0x00, 0x69, 0x00, 0x6d, 0x00, 0x6f, 0x00, 0x71, 0x00, +0x73, 0x00, 0x75, 0x00, 0x42, 0x32, 0x44, 0x2a, 0x45, 0x25, 0x46, 0x21, +0x48, 0x1d, 0x4a, 0x1a, 0x4b, 0x17, 0x4c, 0x15, 0x4e, 0x13, 0x50, 0x11, +0x52, 0x10, 0x53, 0x0e, 0x55, 0x0d, 0x55, 0x0c, 0x57, 0x0c, 0x57, 0x0b, +0x5a, 0x0a, 0x5a, 0x09, 0x5b, 0x09, 0x5c, 0x09, 0x83, 0x00, 0x83, 0x00, +0x83, 0x00, 0x82, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x82, 0x00, +0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, +0x83, 0x00, 0x81, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, +0x00, 0x74, 0x01, 0x64, 0x04, 0x55, 0x06, 0x4a, 0x0a, 0x42, 0x0d, 0x3a, +0x10, 0x34, 0x14, 0x2f, 0x17, 0x2a, 0x1a, 0x26, 0x1d, 0x23, 0x21, 0x21, +0x22, 0x1d, 0x26, 0x1b, 0x28, 0x19, 0x2b, 0x18, 0x2c, 0x16, 0x30, 0x15, +0x30, 0x12, 0x33, 0x12, 0x41, 0x3a, 0x42, 0x32, 0x44, 0x2a, 0x44, 0x25, +0x46, 0x21, 0x48, 0x1d, 0x4a, 0x1a, 0x4b, 0x17, 0x4d, 0x15, 0x4e, 0x13, +0x50, 0x11, 0x52, 0x10, 0x53, 0x0e, 0x55, 0x0d, 0x55, 0x0c, 0x56, 0x0c, +0x58, 0x0b, 0x5a, 0x0a, 0x5a, 0x09, 0x5b, 0x09, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x30, 0x00, 0x3f, 0x00, +0x4b, 0x00, 0x54, 0x00, 0x5b, 0x00, 0x61, 0x00, 0x65, 0x00, 0x68, 0x00, +0x6b, 0x00, 0x6e, 0x00, 0x00, 0x78, 0x00, 0x6a, 0x00, 0x48, 0x00, 0x22, +0x00, 0x00, 0x1b, 0x00, 0x30, 0x00, 0x3f, 0x00, 0x4b, 0x00, 0x54, 0x00, +0x5b, 0x00, 0x61, 0x00, 0x65, 0x00, 0x68, 0x00, 0x6b, 0x00, 0x6e, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79, 0x00, 0x6e, 0x00, +0x50, 0x00, 0x28, 0x00, 0x01, 0x00, 0x1b, 0x00, 0x30, 0x00, 0x3f, 0x00, +0x4b, 0x00, 0x54, 0x00, 0x5b, 0x00, 0x61, 0x00, 0x65, 0x00, 0x68, 0x00, +0x6b, 0x00, 0x6e, 0x00, 0x00, 0x78, 0x00, 0x6a, 0x00, 0x48, 0x00, 0x22, +0x00, 0x00, 0x1b, 0x00, 0x30, 0x00, 0x3f, 0x00, 0x4b, 0x00, 0x54, 0x00, +0x5b, 0x00, 0x61, 0x00, 0x65, 0x00, 0x68, 0x00, 0x6b, 0x00, 0x6e, 0x00, +0x42, 0x32, 0x43, 0x2c, 0x44, 0x26, 0x45, 0x22, 0x48, 0x1f, 0x49, 0x1b, +0x4b, 0x19, 0x4c, 0x16, 0x4e, 0x15, 0x4f, 0x13, 0x50, 0x11, 0x52, 0x10, +0x53, 0x0e, 0x55, 0x0e, 0x55, 0x0c, 0x56, 0x0c, 0x57, 0x0b, 0x59, 0x0b, +0x5a, 0x0a, 0x5a, 0x09, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x82, 0x00, +0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x82, 0x00, 0x83, 0x00, 0x83, 0x00, +0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x81, 0x00, +0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x00, 0x75, 0x01, 0x65, +0x03, 0x58, 0x05, 0x4d, 0x09, 0x45, 0x0c, 0x3e, 0x0f, 0x37, 0x12, 0x32, +0x16, 0x2d, 0x18, 0x2a, 0x1b, 0x26, 0x1d, 0x22, 0x21, 0x21, 0x22, 0x1d, +0x26, 0x1c, 0x27, 0x19, 0x2b, 0x19, 0x2b, 0x16, 0x2e, 0x16, 0x30, 0x14, +0x41, 0x3a, 0x42, 0x32, 0x43, 0x2c, 0x44, 0x26, 0x46, 0x22, 0x48, 0x1f, +0x49, 0x1b, 0x4a, 0x19, 0x4c, 0x16, 0x4e, 0x15, 0x4f, 0x13, 0x50, 0x11, +0x52, 0x10, 0x53, 0x0e, 0x55, 0x0e, 0x54, 0x0c, 0x57, 0x0c, 0x57, 0x0b, +0x59, 0x0b, 0x5a, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x28, 0x00, 0x37, 0x00, 0x42, 0x00, +0x4b, 0x00, 0x53, 0x00, 0x59, 0x00, 0x5e, 0x00, 0x62, 0x00, 0x65, 0x00, +0x00, 0x7a, 0x00, 0x71, 0x00, 0x59, 0x00, 0x3a, 0x00, 0x1b, 0x00, 0x00, +0x16, 0x00, 0x28, 0x00, 0x37, 0x00, 0x42, 0x00, 0x4b, 0x00, 0x53, 0x00, +0x59, 0x00, 0x5e, 0x00, 0x62, 0x00, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x7b, 0x00, 0x72, 0x00, 0x5a, 0x00, 0x3a, 0x00, +0x1b, 0x00, 0x01, 0x00, 0x16, 0x00, 0x28, 0x00, 0x37, 0x00, 0x42, 0x00, +0x4b, 0x00, 0x53, 0x00, 0x59, 0x00, 0x5e, 0x00, 0x62, 0x00, 0x65, 0x00, +0x00, 0x7a, 0x00, 0x71, 0x00, 0x59, 0x00, 0x3a, 0x00, 0x1b, 0x00, 0x00, +0x16, 0x00, 0x28, 0x00, 0x37, 0x00, 0x42, 0x00, 0x4b, 0x00, 0x53, 0x00, +0x59, 0x00, 0x5e, 0x00, 0x62, 0x00, 0x65, 0x00, 0x42, 0x33, 0x43, 0x2d, +0x44, 0x28, 0x45, 0x23, 0x47, 0x20, 0x48, 0x1d, 0x4a, 0x1a, 0x4a, 0x18, +0x4c, 0x16, 0x4e, 0x14, 0x4f, 0x13, 0x50, 0x11, 0x52, 0x10, 0x53, 0x0e, +0x55, 0x0e, 0x54, 0x0d, 0x57, 0x0c, 0x57, 0x0b, 0x58, 0x0b, 0x5a, 0x0b, +0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x82, 0x00, 0x83, 0x00, 0x83, 0x00, +0x83, 0x00, 0x82, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, +0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x81, 0x00, 0x83, 0x00, 0x83, 0x00, +0x83, 0x00, 0x83, 0x00, 0x00, 0x76, 0x01, 0x67, 0x02, 0x5a, 0x05, 0x50, +0x07, 0x47, 0x0a, 0x40, 0x0d, 0x3a, 0x10, 0x35, 0x12, 0x30, 0x16, 0x2c, +0x19, 0x29, 0x1b, 0x26, 0x1d, 0x22, 0x21, 0x21, 0x22, 0x1d, 0x26, 0x1d, +0x26, 0x1a, 0x2a, 0x19, 0x2b, 0x17, 0x2d, 0x16, 0x41, 0x3b, 0x42, 0x33, +0x43, 0x2d, 0x44, 0x28, 0x45, 0x23, 0x47, 0x20, 0x48, 0x1d, 0x49, 0x1a, +0x4b, 0x18, 0x4c, 0x16, 0x4e, 0x14, 0x4f, 0x13, 0x50, 0x11, 0x52, 0x10, +0x53, 0x0e, 0x54, 0x0e, 0x55, 0x0d, 0x57, 0x0c, 0x57, 0x0b, 0x58, 0x0b, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x13, 0x00, 0x23, 0x00, 0x30, 0x00, 0x3b, 0x00, 0x44, 0x00, +0x4c, 0x00, 0x52, 0x00, 0x57, 0x00, 0x5b, 0x00, 0x00, 0x7c, 0x00, 0x75, +0x00, 0x63, 0x00, 0x4a, 0x00, 0x30, 0x00, 0x16, 0x00, 0x00, 0x13, 0x00, +0x23, 0x00, 0x30, 0x00, 0x3b, 0x00, 0x44, 0x00, 0x4c, 0x00, 0x52, 0x00, +0x57, 0x00, 0x5b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x7c, 0x00, 0x75, 0x00, 0x63, 0x00, 0x4a, 0x00, 0x30, 0x00, 0x16, 0x00, +0x00, 0x00, 0x13, 0x00, 0x23, 0x00, 0x30, 0x00, 0x3b, 0x00, 0x44, 0x00, +0x4c, 0x00, 0x52, 0x00, 0x57, 0x00, 0x5b, 0x00, 0x00, 0x7c, 0x00, 0x75, +0x00, 0x63, 0x00, 0x4a, 0x00, 0x30, 0x00, 0x16, 0x00, 0x00, 0x13, 0x00, +0x23, 0x00, 0x30, 0x00, 0x3b, 0x00, 0x44, 0x00, 0x4c, 0x00, 0x52, 0x00, +0x57, 0x00, 0x5b, 0x00, 0x42, 0x34, 0x43, 0x2e, 0x44, 0x29, 0x45, 0x25, +0x46, 0x21, 0x48, 0x1e, 0x49, 0x1b, 0x4a, 0x19, 0x4c, 0x17, 0x4d, 0x15, +0x4e, 0x14, 0x50, 0x13, 0x50, 0x11, 0x52, 0x11, 0x52, 0x0f, 0x53, 0x0e, +0x55, 0x0d, 0x56, 0x0c, 0x57, 0x0c, 0x57, 0x0b, 0x83, 0x00, 0x83, 0x00, +0x83, 0x00, 0x82, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x82, 0x00, +0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, +0x83, 0x00, 0x81, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, +0x00, 0x77, 0x00, 0x68, 0x02, 0x5c, 0x05, 0x52, 0x07, 0x4a, 0x0a, 0x43, +0x0c, 0x3d, 0x0f, 0x37, 0x12, 0x33, 0x14, 0x2f, 0x16, 0x2b, 0x19, 0x28, +0x1c, 0x26, 0x1d, 0x22, 0x21, 0x22, 0x21, 0x1e, 0x25, 0x1d, 0x26, 0x1a, +0x29, 0x19, 0x2b, 0x18, 0x41, 0x3b, 0x42, 0x34, 0x43, 0x2e, 0x44, 0x29, +0x45, 0x25, 0x46, 0x21, 0x48, 0x1e, 0x48, 0x1b, 0x4b, 0x19, 0x4c, 0x17, +0x4d, 0x15, 0x4e, 0x14, 0x50, 0x13, 0x50, 0x11, 0x52, 0x11, 0x51, 0x0f, +0x54, 0x0e, 0x55, 0x0d, 0x56, 0x0c, 0x57, 0x0c, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x10, 0x00, 0x1f, 0x00, 0x2b, 0x00, 0x35, 0x00, 0x3e, 0x00, 0x45, 0x00, +0x4c, 0x00, 0x51, 0x00, 0x00, 0x7c, 0x00, 0x78, 0x00, 0x6a, 0x00, 0x56, +0x00, 0x3f, 0x00, 0x28, 0x00, 0x13, 0x00, 0x00, 0x10, 0x00, 0x1f, 0x00, +0x2b, 0x00, 0x35, 0x00, 0x3e, 0x00, 0x45, 0x00, 0x4c, 0x00, 0x51, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x78, 0x00, +0x6a, 0x00, 0x56, 0x00, 0x3f, 0x00, 0x28, 0x00, 0x13, 0x00, 0x00, 0x00, +0x10, 0x00, 0x1f, 0x00, 0x2b, 0x00, 0x35, 0x00, 0x3e, 0x00, 0x45, 0x00, +0x4c, 0x00, 0x51, 0x00, 0x00, 0x7c, 0x00, 0x78, 0x00, 0x6a, 0x00, 0x56, +0x00, 0x3f, 0x00, 0x28, 0x00, 0x13, 0x00, 0x00, 0x10, 0x00, 0x1f, 0x00, +0x2b, 0x00, 0x35, 0x00, 0x3e, 0x00, 0x45, 0x00, 0x4c, 0x00, 0x51, 0x00, +0x42, 0x34, 0x43, 0x2f, 0x44, 0x2a, 0x44, 0x26, 0x46, 0x22, 0x47, 0x1f, +0x48, 0x1d, 0x49, 0x1a, 0x4b, 0x18, 0x4c, 0x17, 0x4e, 0x15, 0x4e, 0x13, +0x50, 0x13, 0x50, 0x11, 0x52, 0x11, 0x51, 0x0f, 0x54, 0x0e, 0x55, 0x0d, +0x56, 0x0c, 0x57, 0x0c, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x82, 0x00, +0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x82, 0x00, 0x83, 0x00, 0x83, 0x00, +0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x81, 0x00, +0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x00, 0x77, 0x00, 0x69, +0x02, 0x5e, 0x04, 0x55, 0x06, 0x4c, 0x09, 0x45, 0x0c, 0x3f, 0x0e, 0x3a, +0x10, 0x35, 0x12, 0x31, 0x16, 0x2e, 0x18, 0x2b, 0x19, 0x27, 0x1d, 0x26, +0x1e, 0x22, 0x21, 0x22, 0x21, 0x1e, 0x25, 0x1d, 0x26, 0x1b, 0x28, 0x19, +0x41, 0x3b, 0x42, 0x34, 0x43, 0x2f, 0x43, 0x2a, 0x45, 0x26, 0x46, 0x22, +0x47, 0x1f, 0x48, 0x1d, 0x4a, 0x1a, 0x4b, 0x18, 0x4c, 0x17, 0x4e, 0x15, +0x4e, 0x13, 0x50, 0x13, 0x50, 0x11, 0x51, 0x11, 0x52, 0x0f, 0x54, 0x0e, +0x55, 0x0d, 0x56, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, +0x1b, 0x00, 0x27, 0x00, 0x30, 0x00, 0x39, 0x00, 0x40, 0x00, 0x46, 0x00, +0x00, 0x7d, 0x00, 0x79, 0x00, 0x6e, 0x00, 0x5e, 0x00, 0x4b, 0x00, 0x37, +0x00, 0x23, 0x00, 0x10, 0x00, 0x00, 0x0e, 0x00, 0x1b, 0x00, 0x27, 0x00, +0x30, 0x00, 0x39, 0x00, 0x40, 0x00, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x7d, 0x00, 0x79, 0x00, 0x6e, 0x00, 0x5e, 0x00, +0x4b, 0x00, 0x37, 0x00, 0x23, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0e, 0x00, +0x1b, 0x00, 0x27, 0x00, 0x30, 0x00, 0x39, 0x00, 0x40, 0x00, 0x46, 0x00, +0x00, 0x7d, 0x00, 0x79, 0x00, 0x6e, 0x00, 0x5e, 0x00, 0x4b, 0x00, 0x37, +0x00, 0x23, 0x00, 0x10, 0x00, 0x00, 0x0e, 0x00, 0x1b, 0x00, 0x27, 0x00, +0x30, 0x00, 0x39, 0x00, 0x40, 0x00, 0x46, 0x00, 0x42, 0x35, 0x43, 0x30, +0x44, 0x2b, 0x44, 0x27, 0x45, 0x24, 0x46, 0x21, 0x48, 0x1e, 0x48, 0x1c, +0x4b, 0x1a, 0x4b, 0x18, 0x4c, 0x16, 0x4e, 0x15, 0x4e, 0x13, 0x50, 0x12, +0x50, 0x11, 0x51, 0x11, 0x52, 0x0f, 0x54, 0x0e, 0x55, 0x0e, 0x55, 0x0c, +0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, +0x83, 0x00, 0x82, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, +0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x81, 0x00, 0x83, 0x00, 0x83, 0x00, +0x83, 0x00, 0x83, 0x00, 0x00, 0x77, 0x00, 0x6b, 0x02, 0x60, 0x04, 0x57, +0x05, 0x4f, 0x07, 0x48, 0x0a, 0x42, 0x0c, 0x3c, 0x0f, 0x38, 0x12, 0x34, +0x14, 0x30, 0x16, 0x2c, 0x19, 0x2b, 0x19, 0x26, 0x1d, 0x25, 0x1e, 0x22, +0x21, 0x22, 0x21, 0x1e, 0x25, 0x1d, 0x26, 0x1c, 0x41, 0x3b, 0x42, 0x35, +0x43, 0x30, 0x43, 0x2b, 0x44, 0x27, 0x45, 0x24, 0x46, 0x21, 0x47, 0x1e, +0x49, 0x1c, 0x4b, 0x1a, 0x4b, 0x18, 0x4c, 0x16, 0x4e, 0x15, 0x4e, 0x13, +0x50, 0x12, 0x50, 0x11, 0x52, 0x11, 0x52, 0x0f, 0x54, 0x0e, 0x55, 0x0e, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x19, 0x00, +0x23, 0x00, 0x2c, 0x00, 0x34, 0x00, 0x3b, 0x00, 0x00, 0x7d, 0x00, 0x7a, +0x00, 0x72, 0x00, 0x64, 0x00, 0x54, 0x00, 0x42, 0x00, 0x30, 0x00, 0x1f, +0x00, 0x0e, 0x00, 0x00, 0x0d, 0x00, 0x19, 0x00, 0x23, 0x00, 0x2c, 0x00, +0x34, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x7d, 0x00, 0x7a, 0x00, 0x72, 0x00, 0x64, 0x00, 0x54, 0x00, 0x42, 0x00, +0x30, 0x00, 0x1f, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x19, 0x00, +0x23, 0x00, 0x2c, 0x00, 0x34, 0x00, 0x3b, 0x00, 0x00, 0x7d, 0x00, 0x7a, +0x00, 0x72, 0x00, 0x64, 0x00, 0x54, 0x00, 0x42, 0x00, 0x30, 0x00, 0x1f, +0x00, 0x0e, 0x00, 0x00, 0x0d, 0x00, 0x19, 0x00, 0x23, 0x00, 0x2c, 0x00, +0x34, 0x00, 0x3b, 0x00, 0x42, 0x36, 0x43, 0x30, 0x44, 0x2c, 0x44, 0x28, +0x45, 0x25, 0x46, 0x22, 0x48, 0x1f, 0x48, 0x1d, 0x49, 0x1a, 0x4b, 0x19, +0x4c, 0x18, 0x4d, 0x15, 0x4e, 0x15, 0x4f, 0x13, 0x50, 0x12, 0x50, 0x11, +0x52, 0x11, 0x52, 0x0f, 0x54, 0x0e, 0x55, 0x0e, 0x83, 0x00, 0x83, 0x00, +0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x82, 0x00, +0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, +0x83, 0x00, 0x81, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, +0x00, 0x77, 0x00, 0x6c, 0x02, 0x61, 0x04, 0x58, 0x05, 0x51, 0x07, 0x4a, +0x0a, 0x44, 0x0c, 0x3f, 0x0f, 0x3a, 0x10, 0x35, 0x12, 0x32, 0x16, 0x30, +0x16, 0x2b, 0x19, 0x2a, 0x1a, 0x26, 0x1d, 0x25, 0x1e, 0x22, 0x21, 0x22, +0x21, 0x1e, 0x25, 0x1d, 0x41, 0x3b, 0x42, 0x36, 0x43, 0x30, 0x43, 0x2c, +0x44, 0x28, 0x45, 0x25, 0x46, 0x22, 0x47, 0x1f, 0x49, 0x1d, 0x49, 0x1a, +0x4b, 0x19, 0x4c, 0x18, 0x4d, 0x15, 0x4e, 0x15, 0x4f, 0x13, 0x4f, 0x12, +0x51, 0x11, 0x52, 0x11, 0x52, 0x0f, 0x54, 0x0e, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x16, 0x00, 0x20, 0x00, +0x29, 0x00, 0x30, 0x00, 0x00, 0x7e, 0x00, 0x7b, 0x00, 0x74, 0x00, 0x69, +0x00, 0x5b, 0x00, 0x4b, 0x00, 0x3b, 0x00, 0x2b, 0x00, 0x1b, 0x00, 0x0d, +0x00, 0x00, 0x0c, 0x00, 0x16, 0x00, 0x20, 0x00, 0x29, 0x00, 0x30, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7b, 0x00, +0x74, 0x00, 0x69, 0x00, 0x5b, 0x00, 0x4b, 0x00, 0x3b, 0x00, 0x2b, 0x00, +0x1b, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x16, 0x00, 0x20, 0x00, +0x29, 0x00, 0x30, 0x00, 0x00, 0x7e, 0x00, 0x7b, 0x00, 0x74, 0x00, 0x69, +0x00, 0x5b, 0x00, 0x4b, 0x00, 0x3b, 0x00, 0x2b, 0x00, 0x1b, 0x00, 0x0d, +0x00, 0x00, 0x0c, 0x00, 0x16, 0x00, 0x20, 0x00, 0x29, 0x00, 0x30, 0x00, +0x42, 0x36, 0x42, 0x31, 0x43, 0x2d, 0x44, 0x29, 0x45, 0x26, 0x46, 0x23, +0x47, 0x20, 0x47, 0x1e, 0x49, 0x1c, 0x4b, 0x1a, 0x4b, 0x18, 0x4c, 0x17, +0x4d, 0x15, 0x4e, 0x14, 0x4f, 0x13, 0x4f, 0x12, 0x51, 0x11, 0x52, 0x11, +0x52, 0x0f, 0x54, 0x0e, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x82, 0x00, +0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x82, 0x00, 0x83, 0x00, 0x83, 0x00, +0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x81, 0x00, +0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x00, 0x78, 0x00, 0x6d, +0x01, 0x62, 0x03, 0x5a, 0x05, 0x52, 0x07, 0x4c, 0x09, 0x46, 0x0b, 0x41, +0x0c, 0x3c, 0x0f, 0x38, 0x12, 0x35, 0x12, 0x30, 0x16, 0x2e, 0x17, 0x2b, +0x19, 0x29, 0x1b, 0x26, 0x1d, 0x25, 0x1e, 0x22, 0x21, 0x22, 0x21, 0x1f, +0x41, 0x3c, 0x42, 0x36, 0x42, 0x31, 0x43, 0x2d, 0x44, 0x29, 0x45, 0x26, +0x46, 0x23, 0x46, 0x20, 0x48, 0x1e, 0x49, 0x1c, 0x4b, 0x1a, 0x4b, 0x18, +0x4c, 0x17, 0x4d, 0x15, 0x4e, 0x14, 0x4e, 0x13, 0x50, 0x12, 0x51, 0x11, +0x52, 0x11, 0x52, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x15, 0x00, 0x1e, 0x00, 0x26, 0x00, +0x00, 0x7e, 0x00, 0x7c, 0x00, 0x76, 0x00, 0x6d, 0x00, 0x61, 0x00, 0x53, +0x00, 0x44, 0x00, 0x35, 0x00, 0x27, 0x00, 0x19, 0x00, 0x0c, 0x00, 0x00, +0x0b, 0x00, 0x15, 0x00, 0x1e, 0x00, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7c, 0x00, 0x76, 0x00, 0x6d, 0x00, +0x61, 0x00, 0x53, 0x00, 0x44, 0x00, 0x35, 0x00, 0x27, 0x00, 0x19, 0x00, +0x0c, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x15, 0x00, 0x1e, 0x00, 0x26, 0x00, +0x00, 0x7e, 0x00, 0x7c, 0x00, 0x76, 0x00, 0x6d, 0x00, 0x61, 0x00, 0x53, +0x00, 0x44, 0x00, 0x35, 0x00, 0x27, 0x00, 0x19, 0x00, 0x0c, 0x00, 0x00, +0x0b, 0x00, 0x15, 0x00, 0x1e, 0x00, 0x26, 0x00, 0x42, 0x37, 0x42, 0x32, +0x43, 0x2d, 0x44, 0x2a, 0x45, 0x27, 0x45, 0x23, 0x46, 0x21, 0x47, 0x1f, +0x49, 0x1d, 0x49, 0x1a, 0x4b, 0x19, 0x4c, 0x18, 0x4c, 0x16, 0x4e, 0x15, +0x4e, 0x14, 0x4f, 0x13, 0x50, 0x12, 0x51, 0x11, 0x52, 0x11, 0x52, 0x0f, +0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, +0x83, 0x00, 0x82, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x83, 0x00, +0x83, 0x00, 0x83, 0x00, 0x83, 0x00, 0x81, 0x00, 0x83, 0x00, 0x83, 0x00, +0x83, 0x00, 0x83, 0x00, 0x00, 0x78, 0x00, 0x6e, 0x01, 0x64, 0x02, 0x5b, +0x04, 0x54, 0x06, 0x4e, 0x07, 0x47, 0x0a, 0x42, 0x0c, 0x3e, 0x0f, 0x3b, +0x0f, 0x35, 0x12, 0x33, 0x14, 0x30, 0x16, 0x2d, 0x19, 0x2b, 0x19, 0x28, +0x1c, 0x26, 0x1d, 0x25, 0x1f, 0x22, 0x21, 0x22, 0x41, 0x3c, 0x42, 0x37, +0x42, 0x32, 0x43, 0x2d, 0x44, 0x2a, 0x45, 0x27, 0x45, 0x23, 0x46, 0x21, +0x48, 0x1f, 0x49, 0x1d, 0x49, 0x1a, 0x4b, 0x19, 0x4c, 0x18, 0x4c, 0x16, +0x4e, 0x15, 0x4d, 0x14, 0x50, 0x13, 0x50, 0x12, 0x51, 0x11, 0x52, 0x11, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x0a, 0x00, 0x13, 0x00, 0x1b, 0x00, 0x00, 0x7e, 0x00, 0x7c, +0x00, 0x77, 0x00, 0x6f, 0x00, 0x65, 0x00, 0x59, 0x00, 0x4c, 0x00, 0x3e, +0x00, 0x30, 0x00, 0x23, 0x00, 0x16, 0x00, 0x0b, 0x00, 0x00, 0x0a, 0x00, +0x13, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x7e, 0x00, 0x7c, 0x00, 0x77, 0x00, 0x6f, 0x00, 0x65, 0x00, 0x59, 0x00, +0x4c, 0x00, 0x3e, 0x00, 0x30, 0x00, 0x23, 0x00, 0x16, 0x00, 0x0b, 0x00, +0x00, 0x00, 0x0a, 0x00, 0x13, 0x00, 0x1b, 0x00, 0x00, 0x7e, 0x00, 0x7c, +0x00, 0x77, 0x00, 0x6f, 0x00, 0x65, 0x00, 0x59, 0x00, 0x4c, 0x00, 0x3e, +0x00, 0x30, 0x00, 0x23, 0x00, 0x16, 0x00, 0x0b, 0x00, 0x00, 0x0a, 0x00, +0x13, 0x00, 0x1b, 0x00, 0x40, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x61, 0x20, 0x4d, 0x2a, +0x48, 0x30, 0x44, 0x33, 0x44, 0x35, 0x44, 0x36, 0x43, 0x37, 0x42, 0x38, +0x43, 0x39, 0x42, 0x39, 0x42, 0x3a, 0x42, 0x3a, 0x42, 0x3b, 0x42, 0x3b, +0x42, 0x3b, 0x41, 0x3b, 0x42, 0x3c, 0x42, 0x3c, 0x42, 0x3c, 0x42, 0x3c, +0x04, 0x3d, 0x22, 0x3d, 0x2b, 0x3d, 0x30, 0x3d, 0x33, 0x3d, 0x35, 0x3d, +0x37, 0x3d, 0x38, 0x3d, 0x39, 0x3d, 0x39, 0x3d, 0x3a, 0x3d, 0x3a, 0x3d, +0x3b, 0x3d, 0x3b, 0x3d, 0x3b, 0x3d, 0x3c, 0x3d, 0x3c, 0x3d, 0x3c, 0x3d, +0x3c, 0x3d, 0x3c, 0x3d, 0x40, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x09, 0x00, 0x12, 0x00, 0x00, 0x7e, 0x00, 0x7d, 0x00, 0x78, 0x00, 0x71, +0x00, 0x68, 0x00, 0x5e, 0x00, 0x52, 0x00, 0x45, 0x00, 0x39, 0x00, 0x2c, +0x00, 0x20, 0x00, 0x15, 0x00, 0x0a, 0x00, 0x00, 0x09, 0x00, 0x12, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7d, 0x00, +0x78, 0x00, 0x71, 0x00, 0x68, 0x00, 0x5e, 0x00, 0x52, 0x00, 0x45, 0x00, +0x39, 0x00, 0x2c, 0x00, 0x20, 0x00, 0x15, 0x00, 0x0a, 0x00, 0x00, 0x00, +0x09, 0x00, 0x12, 0x00, 0x00, 0x7e, 0x00, 0x7d, 0x00, 0x78, 0x00, 0x71, +0x00, 0x68, 0x00, 0x5e, 0x00, 0x52, 0x00, 0x45, 0x00, 0x39, 0x00, 0x2c, +0x00, 0x20, 0x00, 0x15, 0x00, 0x0a, 0x00, 0x00, 0x09, 0x00, 0x12, 0x00, +0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x6c, 0x0b, 0x57, 0x16, 0x4f, 0x1d, 0x4a, 0x22, +0x48, 0x26, 0x47, 0x29, 0x46, 0x2b, 0x44, 0x2d, 0x44, 0x2f, 0x44, 0x30, +0x44, 0x31, 0x44, 0x32, 0x43, 0x33, 0x43, 0x34, 0x43, 0x34, 0x42, 0x35, +0x43, 0x36, 0x42, 0x36, 0x42, 0x37, 0x42, 0x37, 0x00, 0x5d, 0x0c, 0x49, +0x16, 0x43, 0x1d, 0x41, 0x22, 0x40, 0x26, 0x3f, 0x29, 0x3f, 0x2c, 0x3f, +0x2e, 0x3e, 0x2f, 0x3e, 0x31, 0x3e, 0x32, 0x3e, 0x33, 0x3e, 0x33, 0x3e, +0x34, 0x3e, 0x35, 0x3e, 0x35, 0x3e, 0x36, 0x3e, 0x37, 0x3e, 0x37, 0x3e, +0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, +0x00, 0x7e, 0x00, 0x7d, 0x00, 0x79, 0x00, 0x73, 0x00, 0x6b, 0x00, 0x62, +0x00, 0x57, 0x00, 0x4c, 0x00, 0x40, 0x00, 0x34, 0x00, 0x29, 0x00, 0x1e, +0x00, 0x13, 0x00, 0x09, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7d, 0x00, 0x79, 0x00, 0x73, 0x00, +0x6b, 0x00, 0x62, 0x00, 0x57, 0x00, 0x4c, 0x00, 0x40, 0x00, 0x34, 0x00, +0x29, 0x00, 0x1e, 0x00, 0x13, 0x00, 0x09, 0x00, 0x00, 0x00, 0x08, 0x00, +0x00, 0x7e, 0x00, 0x7d, 0x00, 0x79, 0x00, 0x73, 0x00, 0x6b, 0x00, 0x62, +0x00, 0x57, 0x00, 0x4c, 0x00, 0x40, 0x00, 0x34, 0x00, 0x29, 0x00, 0x1e, +0x00, 0x13, 0x00, 0x09, 0x00, 0x00, 0x08, 0x00, 0x41, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x72, 0x06, 0x5f, 0x0d, 0x56, 0x14, 0x4f, 0x19, 0x4d, 0x1d, 0x4a, 0x20, +0x49, 0x23, 0x47, 0x25, 0x46, 0x27, 0x46, 0x29, 0x45, 0x2a, 0x45, 0x2c, +0x44, 0x2d, 0x44, 0x2e, 0x44, 0x2f, 0x43, 0x30, 0x44, 0x30, 0x44, 0x31, +0x43, 0x32, 0x43, 0x33, 0x00, 0x68, 0x06, 0x54, 0x0d, 0x4b, 0x14, 0x47, +0x19, 0x44, 0x1d, 0x43, 0x20, 0x41, 0x23, 0x41, 0x26, 0x40, 0x27, 0x40, +0x29, 0x3f, 0x2b, 0x3f, 0x2c, 0x3f, 0x2d, 0x3f, 0x2e, 0x3f, 0x2f, 0x3f, +0x30, 0x3f, 0x30, 0x3e, 0x31, 0x3e, 0x32, 0x3e, 0x41, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7d, +0x00, 0x7a, 0x00, 0x75, 0x00, 0x6e, 0x00, 0x65, 0x00, 0x5b, 0x00, 0x51, +0x00, 0x46, 0x00, 0x3b, 0x00, 0x30, 0x00, 0x26, 0x00, 0x1b, 0x00, 0x12, +0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x7e, 0x00, 0x7d, 0x00, 0x7a, 0x00, 0x75, 0x00, 0x6e, 0x00, 0x65, 0x00, +0x5b, 0x00, 0x51, 0x00, 0x46, 0x00, 0x3b, 0x00, 0x30, 0x00, 0x26, 0x00, +0x1b, 0x00, 0x12, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7d, +0x00, 0x7a, 0x00, 0x75, 0x00, 0x6e, 0x00, 0x65, 0x00, 0x5b, 0x00, 0x51, +0x00, 0x46, 0x00, 0x3b, 0x00, 0x30, 0x00, 0x26, 0x00, 0x1b, 0x00, 0x12, +0x00, 0x08, 0x00, 0x00, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x75, 0x03, 0x64, 0x09, +0x5a, 0x0e, 0x54, 0x13, 0x51, 0x17, 0x4e, 0x1a, 0x4c, 0x1d, 0x49, 0x1f, +0x49, 0x22, 0x48, 0x23, 0x47, 0x25, 0x46, 0x26, 0x46, 0x28, 0x45, 0x29, +0x45, 0x2a, 0x44, 0x2b, 0x44, 0x2c, 0x44, 0x2d, 0x44, 0x2e, 0x44, 0x2e, +0x00, 0x6d, 0x04, 0x5b, 0x09, 0x51, 0x0e, 0x4c, 0x13, 0x48, 0x17, 0x46, +0x1a, 0x44, 0x1d, 0x43, 0x1f, 0x42, 0x22, 0x42, 0x24, 0x41, 0x25, 0x41, +0x27, 0x40, 0x28, 0x40, 0x29, 0x40, 0x2a, 0x3f, 0x2b, 0x3f, 0x2c, 0x3f, +0x2d, 0x3f, 0x2e, 0x3f, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x1f, 0x1f, 0x3f, 0x00, 0x66, 0x00, 0x72, 0x00, +0x78, 0x00, 0x7a, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7d, 0x00, 0x7d, 0x00, +0x7e, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x7e, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x1f, 0x00, 0x3f, +0x00, 0x66, 0x00, 0x72, 0x00, 0x78, 0x00, 0x7a, 0x00, 0x7c, 0x00, 0x7c, +0x00, 0x7d, 0x00, 0x7d, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x7e, +0x00, 0x7e, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x77, 0x02, 0x68, 0x06, 0x5f, 0x0b, 0x58, 0x0f, +0x54, 0x12, 0x51, 0x15, 0x4f, 0x18, 0x4c, 0x1b, 0x4b, 0x1d, 0x4a, 0x1f, +0x49, 0x21, 0x48, 0x22, 0x48, 0x23, 0x47, 0x25, 0x46, 0x26, 0x45, 0x27, +0x45, 0x28, 0x45, 0x29, 0x45, 0x2a, 0x44, 0x2b, 0x00, 0x70, 0x02, 0x60, +0x07, 0x56, 0x0b, 0x50, 0x0f, 0x4c, 0x12, 0x49, 0x16, 0x47, 0x18, 0x46, +0x1b, 0x45, 0x1d, 0x44, 0x1f, 0x43, 0x21, 0x42, 0x22, 0x42, 0x24, 0x41, +0x25, 0x41, 0x26, 0x40, 0x27, 0x40, 0x28, 0x40, 0x29, 0x40, 0x2a, 0x3f, +0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x3f, 0x0a, 0x0a, 0x3f, 0x00, 0x5c, 0x00, 0x6a, 0x00, 0x71, 0x00, +0x75, 0x00, 0x78, 0x00, 0x79, 0x00, 0x7a, 0x00, 0x7b, 0x00, 0x7c, 0x00, +0x7c, 0x00, 0x7d, 0x00, 0x7d, 0x00, 0x7d, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x0a, 0x0a, 0x00, 0x3f, 0x00, 0x5c, +0x00, 0x6a, 0x00, 0x71, 0x00, 0x75, 0x00, 0x78, 0x00, 0x79, 0x00, 0x7a, +0x00, 0x7b, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7d, 0x00, 0x7d, 0x00, 0x7d, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x78, 0x02, 0x6b, 0x05, 0x62, 0x08, 0x5b, 0x0c, 0x57, 0x0f, 0x54, 0x12, +0x51, 0x14, 0x4e, 0x17, 0x4d, 0x19, 0x4c, 0x1b, 0x4b, 0x1d, 0x4a, 0x1e, +0x49, 0x20, 0x48, 0x21, 0x48, 0x22, 0x46, 0x24, 0x46, 0x25, 0x46, 0x26, +0x46, 0x27, 0x45, 0x27, 0x00, 0x72, 0x02, 0x64, 0x05, 0x5b, 0x08, 0x54, +0x0c, 0x50, 0x0f, 0x4d, 0x12, 0x4a, 0x14, 0x48, 0x17, 0x47, 0x19, 0x46, +0x1b, 0x45, 0x1d, 0x44, 0x1f, 0x44, 0x20, 0x42, 0x21, 0x42, 0x22, 0x42, +0x24, 0x41, 0x25, 0x41, 0x26, 0x41, 0x27, 0x40, 0x41, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x00, 0x3f, +0x03, 0x03, 0x2d, 0x00, 0x48, 0x00, 0x59, 0x00, 0x63, 0x00, 0x6a, 0x00, +0x6e, 0x00, 0x72, 0x00, 0x74, 0x00, 0x76, 0x00, 0x77, 0x00, 0x78, 0x00, +0x79, 0x00, 0x7a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x66, 0x00, 0x3f, 0x00, 0x03, 0x03, 0x00, 0x2d, 0x00, 0x48, 0x00, 0x59, +0x00, 0x63, 0x00, 0x6a, 0x00, 0x6e, 0x00, 0x72, 0x00, 0x74, 0x00, 0x76, +0x00, 0x77, 0x00, 0x78, 0x00, 0x79, 0x00, 0x7a, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x79, 0x01, 0x6d, 0x04, +0x65, 0x07, 0x5e, 0x0a, 0x5a, 0x0d, 0x56, 0x0f, 0x54, 0x12, 0x51, 0x14, +0x4f, 0x16, 0x4e, 0x18, 0x4c, 0x1a, 0x4b, 0x1b, 0x4b, 0x1d, 0x4a, 0x1e, +0x49, 0x1f, 0x48, 0x21, 0x48, 0x22, 0x48, 0x23, 0x47, 0x23, 0x46, 0x25, +0x00, 0x74, 0x01, 0x66, 0x04, 0x5e, 0x07, 0x57, 0x0a, 0x53, 0x0d, 0x4f, +0x10, 0x4d, 0x12, 0x4b, 0x14, 0x49, 0x16, 0x48, 0x18, 0x46, 0x1a, 0x45, +0x1b, 0x45, 0x1d, 0x44, 0x1e, 0x44, 0x20, 0x43, 0x21, 0x42, 0x22, 0x42, +0x23, 0x42, 0x24, 0x41, 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x72, 0x00, 0x5c, 0x00, 0x2d, 0x01, 0x01, +0x22, 0x00, 0x3a, 0x00, 0x4a, 0x00, 0x56, 0x00, 0x5e, 0x00, 0x64, 0x00, +0x69, 0x00, 0x6d, 0x00, 0x6f, 0x00, 0x71, 0x00, 0x73, 0x00, 0x75, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x72, 0x00, 0x5c, 0x00, +0x2d, 0x00, 0x01, 0x01, 0x00, 0x22, 0x00, 0x3a, 0x00, 0x4a, 0x00, 0x56, +0x00, 0x5e, 0x00, 0x64, 0x00, 0x69, 0x00, 0x6d, 0x00, 0x6f, 0x00, 0x71, +0x00, 0x73, 0x00, 0x75, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x7a, 0x01, 0x6f, 0x03, 0x67, 0x06, 0x60, 0x08, +0x5d, 0x0b, 0x59, 0x0d, 0x56, 0x10, 0x53, 0x11, 0x51, 0x14, 0x50, 0x15, +0x4e, 0x17, 0x4d, 0x19, 0x4c, 0x1a, 0x4b, 0x1b, 0x4b, 0x1d, 0x48, 0x1e, +0x49, 0x1f, 0x49, 0x20, 0x48, 0x21, 0x48, 0x22, 0x00, 0x75, 0x01, 0x69, +0x03, 0x61, 0x06, 0x5a, 0x08, 0x56, 0x0b, 0x52, 0x0d, 0x4f, 0x10, 0x4d, +0x12, 0x4b, 0x14, 0x4a, 0x16, 0x48, 0x17, 0x47, 0x19, 0x46, 0x1a, 0x45, +0x1c, 0x45, 0x1d, 0x44, 0x1e, 0x44, 0x1f, 0x44, 0x20, 0x43, 0x21, 0x42, +0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x78, 0x00, 0x6a, 0x00, 0x48, 0x00, 0x22, 0x00, 0x00, 0x1b, 0x00, +0x30, 0x00, 0x3f, 0x00, 0x4b, 0x00, 0x54, 0x00, 0x5b, 0x00, 0x61, 0x00, +0x65, 0x00, 0x68, 0x00, 0x6b, 0x00, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x6a, 0x00, 0x48, 0x00, 0x22, 0x00, +0x00, 0x00, 0x00, 0x1b, 0x00, 0x30, 0x00, 0x3f, 0x00, 0x4b, 0x00, 0x54, +0x00, 0x5b, 0x00, 0x61, 0x00, 0x65, 0x00, 0x68, 0x00, 0x6b, 0x00, 0x6e, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x7b, 0x01, 0x71, 0x02, 0x69, 0x05, 0x62, 0x07, 0x5f, 0x09, 0x5b, 0x0c, +0x58, 0x0e, 0x55, 0x10, 0x53, 0x11, 0x52, 0x13, 0x50, 0x15, 0x4e, 0x16, +0x4e, 0x18, 0x4c, 0x19, 0x4c, 0x1a, 0x4a, 0x1c, 0x4b, 0x1d, 0x49, 0x1e, +0x49, 0x1f, 0x49, 0x20, 0x00, 0x76, 0x01, 0x6b, 0x03, 0x63, 0x05, 0x5d, +0x07, 0x58, 0x09, 0x54, 0x0c, 0x52, 0x0e, 0x4f, 0x10, 0x4d, 0x11, 0x4c, +0x13, 0x4a, 0x15, 0x49, 0x17, 0x48, 0x18, 0x47, 0x19, 0x46, 0x1b, 0x45, +0x1c, 0x45, 0x1d, 0x44, 0x1e, 0x44, 0x1f, 0x44, 0x41, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7a, 0x00, 0x71, +0x00, 0x59, 0x00, 0x3a, 0x00, 0x1b, 0x00, 0x00, 0x16, 0x00, 0x28, 0x00, +0x37, 0x00, 0x42, 0x00, 0x4b, 0x00, 0x53, 0x00, 0x59, 0x00, 0x5e, 0x00, +0x62, 0x00, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x7a, 0x00, 0x71, 0x00, 0x59, 0x00, 0x3a, 0x00, 0x1b, 0x00, 0x00, 0x00, +0x00, 0x16, 0x00, 0x28, 0x00, 0x37, 0x00, 0x42, 0x00, 0x4b, 0x00, 0x53, +0x00, 0x59, 0x00, 0x5e, 0x00, 0x62, 0x00, 0x65, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x7b, 0x00, 0x72, 0x02, +0x6b, 0x04, 0x64, 0x06, 0x61, 0x08, 0x5d, 0x0a, 0x5a, 0x0c, 0x56, 0x0e, +0x55, 0x10, 0x53, 0x11, 0x52, 0x13, 0x50, 0x15, 0x4f, 0x16, 0x4e, 0x17, +0x4d, 0x18, 0x4b, 0x1a, 0x4b, 0x1a, 0x4b, 0x1c, 0x4b, 0x1d, 0x49, 0x1d, +0x00, 0x77, 0x00, 0x6c, 0x02, 0x65, 0x04, 0x5f, 0x06, 0x5a, 0x08, 0x57, +0x0a, 0x54, 0x0c, 0x51, 0x0e, 0x4f, 0x10, 0x4d, 0x11, 0x4c, 0x13, 0x4a, +0x15, 0x49, 0x16, 0x48, 0x18, 0x48, 0x18, 0x46, 0x1a, 0x46, 0x1b, 0x45, +0x1c, 0x45, 0x1d, 0x45, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x75, 0x00, 0x63, 0x00, 0x4a, +0x00, 0x30, 0x00, 0x16, 0x00, 0x00, 0x13, 0x00, 0x23, 0x00, 0x30, 0x00, +0x3b, 0x00, 0x44, 0x00, 0x4c, 0x00, 0x52, 0x00, 0x57, 0x00, 0x5b, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x75, 0x00, +0x63, 0x00, 0x4a, 0x00, 0x30, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x13, +0x00, 0x23, 0x00, 0x30, 0x00, 0x3b, 0x00, 0x44, 0x00, 0x4c, 0x00, 0x52, +0x00, 0x57, 0x00, 0x5b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x7c, 0x00, 0x73, 0x02, 0x6c, 0x03, 0x66, 0x05, +0x63, 0x07, 0x5e, 0x09, 0x5c, 0x0b, 0x58, 0x0c, 0x57, 0x0e, 0x55, 0x10, +0x53, 0x11, 0x52, 0x13, 0x50, 0x14, 0x4f, 0x15, 0x4e, 0x17, 0x4c, 0x18, +0x4c, 0x19, 0x4c, 0x1a, 0x4b, 0x1a, 0x4b, 0x1c, 0x00, 0x77, 0x00, 0x6e, +0x02, 0x66, 0x04, 0x61, 0x05, 0x5c, 0x07, 0x59, 0x09, 0x56, 0x0b, 0x53, +0x0d, 0x51, 0x0f, 0x4f, 0x10, 0x4e, 0x11, 0x4c, 0x13, 0x4b, 0x14, 0x4a, +0x15, 0x48, 0x17, 0x48, 0x18, 0x47, 0x19, 0x46, 0x1b, 0x46, 0x1b, 0x45, +0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x7c, 0x00, 0x78, 0x00, 0x6a, 0x00, 0x56, 0x00, 0x3f, 0x00, 0x28, +0x00, 0x13, 0x00, 0x00, 0x10, 0x00, 0x1f, 0x00, 0x2b, 0x00, 0x35, 0x00, +0x3e, 0x00, 0x45, 0x00, 0x4c, 0x00, 0x51, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x78, 0x00, 0x6a, 0x00, 0x56, 0x00, +0x3f, 0x00, 0x28, 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x1f, +0x00, 0x2b, 0x00, 0x35, 0x00, 0x3e, 0x00, 0x45, 0x00, 0x4c, 0x00, 0x51, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x7c, 0x00, 0x74, 0x02, 0x6e, 0x03, 0x68, 0x05, 0x64, 0x06, 0x60, 0x08, +0x5d, 0x0a, 0x5a, 0x0b, 0x58, 0x0d, 0x56, 0x0e, 0x55, 0x10, 0x53, 0x11, +0x52, 0x13, 0x50, 0x14, 0x50, 0x15, 0x4d, 0x16, 0x4e, 0x18, 0x4c, 0x18, +0x4c, 0x19, 0x4c, 0x1a, 0x00, 0x77, 0x00, 0x6f, 0x02, 0x68, 0x03, 0x63, +0x05, 0x5e, 0x06, 0x5a, 0x08, 0x57, 0x0a, 0x55, 0x0b, 0x53, 0x0d, 0x50, +0x0f, 0x4f, 0x10, 0x4e, 0x11, 0x4c, 0x13, 0x4b, 0x14, 0x4a, 0x15, 0x49, +0x16, 0x48, 0x18, 0x48, 0x18, 0x46, 0x19, 0x46, 0x41, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7d, 0x00, 0x79, +0x00, 0x6e, 0x00, 0x5e, 0x00, 0x4b, 0x00, 0x37, 0x00, 0x23, 0x00, 0x10, +0x00, 0x00, 0x0e, 0x00, 0x1b, 0x00, 0x27, 0x00, 0x30, 0x00, 0x39, 0x00, +0x40, 0x00, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x7d, 0x00, 0x79, 0x00, 0x6e, 0x00, 0x5e, 0x00, 0x4b, 0x00, 0x37, 0x00, +0x23, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x1b, 0x00, 0x27, +0x00, 0x30, 0x00, 0x39, 0x00, 0x40, 0x00, 0x46, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x7d, 0x00, 0x75, 0x01, +0x6f, 0x02, 0x69, 0x04, 0x65, 0x06, 0x62, 0x07, 0x5f, 0x09, 0x5b, 0x0b, +0x5a, 0x0c, 0x58, 0x0d, 0x56, 0x0e, 0x55, 0x10, 0x53, 0x11, 0x52, 0x13, +0x50, 0x13, 0x4f, 0x15, 0x4e, 0x15, 0x4e, 0x17, 0x4d, 0x18, 0x4c, 0x18, +0x00, 0x78, 0x00, 0x70, 0x01, 0x69, 0x03, 0x64, 0x04, 0x60, 0x06, 0x5c, +0x07, 0x59, 0x09, 0x56, 0x0b, 0x54, 0x0c, 0x52, 0x0d, 0x50, 0x0f, 0x4f, +0x10, 0x4e, 0x11, 0x4c, 0x13, 0x4b, 0x13, 0x4a, 0x15, 0x4a, 0x15, 0x48, +0x17, 0x48, 0x18, 0x47, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x7d, 0x00, 0x7a, 0x00, 0x72, 0x00, 0x64, +0x00, 0x54, 0x00, 0x42, 0x00, 0x30, 0x00, 0x1f, 0x00, 0x0e, 0x00, 0x00, +0x0d, 0x00, 0x19, 0x00, 0x23, 0x00, 0x2c, 0x00, 0x34, 0x00, 0x3b, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7d, 0x00, 0x7a, 0x00, +0x72, 0x00, 0x64, 0x00, 0x54, 0x00, 0x42, 0x00, 0x30, 0x00, 0x1f, 0x00, +0x0e, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x19, 0x00, 0x23, 0x00, 0x2c, +0x00, 0x34, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x7d, 0x00, 0x76, 0x01, 0x70, 0x02, 0x6a, 0x03, +0x67, 0x05, 0x63, 0x06, 0x60, 0x08, 0x5d, 0x09, 0x5b, 0x0b, 0x59, 0x0c, +0x57, 0x0d, 0x55, 0x0e, 0x55, 0x10, 0x53, 0x11, 0x52, 0x13, 0x4f, 0x13, +0x50, 0x15, 0x4f, 0x15, 0x4e, 0x16, 0x4e, 0x18, 0x00, 0x78, 0x00, 0x71, +0x01, 0x6a, 0x03, 0x66, 0x04, 0x61, 0x05, 0x5d, 0x06, 0x5a, 0x08, 0x58, +0x09, 0x55, 0x0b, 0x53, 0x0d, 0x52, 0x0e, 0x50, 0x0f, 0x4e, 0x10, 0x4e, +0x11, 0x4c, 0x13, 0x4c, 0x13, 0x4a, 0x15, 0x4a, 0x15, 0x49, 0x16, 0x48, +0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x7e, 0x00, 0x7b, 0x00, 0x74, 0x00, 0x69, 0x00, 0x5b, 0x00, 0x4b, +0x00, 0x3b, 0x00, 0x2b, 0x00, 0x1b, 0x00, 0x0d, 0x00, 0x00, 0x0c, 0x00, +0x16, 0x00, 0x20, 0x00, 0x29, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7b, 0x00, 0x74, 0x00, 0x69, 0x00, +0x5b, 0x00, 0x4b, 0x00, 0x3b, 0x00, 0x2b, 0x00, 0x1b, 0x00, 0x0d, 0x00, +0x00, 0x00, 0x00, 0x0c, 0x00, 0x16, 0x00, 0x20, 0x00, 0x29, 0x00, 0x30, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x7d, 0x00, 0x76, 0x01, 0x71, 0x02, 0x6c, 0x03, 0x68, 0x05, 0x64, 0x06, +0x61, 0x07, 0x5e, 0x09, 0x5c, 0x0a, 0x5a, 0x0b, 0x59, 0x0c, 0x57, 0x0e, +0x55, 0x0e, 0x55, 0x11, 0x52, 0x11, 0x51, 0x12, 0x51, 0x13, 0x50, 0x14, +0x4f, 0x15, 0x4e, 0x15, 0x00, 0x79, 0x00, 0x71, 0x01, 0x6c, 0x02, 0x66, +0x04, 0x62, 0x05, 0x5f, 0x06, 0x5c, 0x07, 0x59, 0x09, 0x57, 0x0a, 0x55, +0x0b, 0x53, 0x0d, 0x51, 0x0e, 0x50, 0x0f, 0x4e, 0x11, 0x4e, 0x11, 0x4c, +0x13, 0x4c, 0x13, 0x4b, 0x14, 0x4a, 0x15, 0x4a, 0x41, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7c, +0x00, 0x76, 0x00, 0x6d, 0x00, 0x61, 0x00, 0x53, 0x00, 0x44, 0x00, 0x35, +0x00, 0x27, 0x00, 0x19, 0x00, 0x0c, 0x00, 0x00, 0x0b, 0x00, 0x15, 0x00, +0x1e, 0x00, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x7e, 0x00, 0x7c, 0x00, 0x76, 0x00, 0x6d, 0x00, 0x61, 0x00, 0x53, 0x00, +0x44, 0x00, 0x35, 0x00, 0x27, 0x00, 0x19, 0x00, 0x0c, 0x00, 0x00, 0x00, +0x00, 0x0b, 0x00, 0x15, 0x00, 0x1e, 0x00, 0x26, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x7d, 0x00, 0x77, 0x01, +0x72, 0x02, 0x6d, 0x03, 0x69, 0x04, 0x66, 0x06, 0x63, 0x07, 0x5f, 0x08, +0x5e, 0x09, 0x5c, 0x0b, 0x5a, 0x0c, 0x58, 0x0c, 0x57, 0x0e, 0x55, 0x0f, +0x54, 0x11, 0x51, 0x11, 0x52, 0x12, 0x51, 0x13, 0x50, 0x14, 0x50, 0x15, +0x00, 0x79, 0x00, 0x72, 0x01, 0x6d, 0x02, 0x68, 0x03, 0x63, 0x04, 0x60, +0x06, 0x5d, 0x07, 0x5b, 0x08, 0x58, 0x09, 0x56, 0x0b, 0x54, 0x0c, 0x53, +0x0d, 0x51, 0x0e, 0x50, 0x0f, 0x4e, 0x11, 0x4e, 0x11, 0x4c, 0x12, 0x4c, +0x13, 0x4b, 0x14, 0x4a, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7c, 0x00, 0x77, 0x00, 0x6f, +0x00, 0x65, 0x00, 0x59, 0x00, 0x4c, 0x00, 0x3e, 0x00, 0x30, 0x00, 0x23, +0x00, 0x16, 0x00, 0x0b, 0x00, 0x00, 0x0a, 0x00, 0x13, 0x00, 0x1b, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7c, 0x00, +0x77, 0x00, 0x6f, 0x00, 0x65, 0x00, 0x59, 0x00, 0x4c, 0x00, 0x3e, 0x00, +0x30, 0x00, 0x23, 0x00, 0x16, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x0a, +0x00, 0x13, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x7d, 0x00, 0x78, 0x01, 0x72, 0x02, 0x6e, 0x02, +0x6a, 0x03, 0x67, 0x05, 0x64, 0x06, 0x60, 0x07, 0x5f, 0x09, 0x5c, 0x0a, +0x5b, 0x0b, 0x5a, 0x0c, 0x57, 0x0c, 0x56, 0x0e, 0x55, 0x0f, 0x53, 0x11, +0x52, 0x11, 0x52, 0x12, 0x51, 0x13, 0x50, 0x13, 0x00, 0x79, 0x00, 0x73, +0x01, 0x6d, 0x02, 0x69, 0x03, 0x65, 0x04, 0x61, 0x05, 0x5e, 0x06, 0x5c, +0x07, 0x59, 0x09, 0x57, 0x0a, 0x55, 0x0b, 0x54, 0x0d, 0x53, 0x0d, 0x51, +0x0f, 0x50, 0x0f, 0x4e, 0x11, 0x4e, 0x11, 0x4c, 0x12, 0x4c, 0x13, 0x4b, +0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x7e, 0x00, 0x7d, 0x00, 0x78, 0x00, 0x71, 0x00, 0x68, 0x00, 0x5e, +0x00, 0x52, 0x00, 0x45, 0x00, 0x39, 0x00, 0x2c, 0x00, 0x20, 0x00, 0x15, +0x00, 0x0a, 0x00, 0x00, 0x09, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7d, 0x00, 0x78, 0x00, 0x71, 0x00, +0x68, 0x00, 0x5e, 0x00, 0x52, 0x00, 0x45, 0x00, 0x39, 0x00, 0x2c, 0x00, +0x20, 0x00, 0x15, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x12, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x7e, 0x00, 0x78, 0x01, 0x73, 0x02, 0x6e, 0x02, 0x6b, 0x03, 0x68, 0x05, +0x65, 0x06, 0x62, 0x07, 0x5f, 0x07, 0x5e, 0x09, 0x5c, 0x0b, 0x5a, 0x0b, +0x59, 0x0c, 0x57, 0x0d, 0x56, 0x0e, 0x54, 0x0f, 0x54, 0x11, 0x52, 0x11, +0x52, 0x12, 0x51, 0x13, 0x00, 0x79, 0x00, 0x73, 0x01, 0x6e, 0x02, 0x69, +0x03, 0x66, 0x04, 0x62, 0x05, 0x5f, 0x06, 0x5d, 0x07, 0x5b, 0x08, 0x58, +0x09, 0x56, 0x0b, 0x55, 0x0b, 0x53, 0x0d, 0x52, 0x0d, 0x50, 0x0f, 0x50, +0x0f, 0x4e, 0x11, 0x4e, 0x11, 0x4d, 0x12, 0x4c, 0x41, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7d, +0x00, 0x79, 0x00, 0x73, 0x00, 0x6b, 0x00, 0x62, 0x00, 0x57, 0x00, 0x4c, +0x00, 0x40, 0x00, 0x34, 0x00, 0x29, 0x00, 0x1e, 0x00, 0x13, 0x00, 0x09, +0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x7e, 0x00, 0x7d, 0x00, 0x79, 0x00, 0x73, 0x00, 0x6b, 0x00, 0x62, 0x00, +0x57, 0x00, 0x4c, 0x00, 0x40, 0x00, 0x34, 0x00, 0x29, 0x00, 0x1e, 0x00, +0x13, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x7e, 0x00, 0x78, 0x00, +0x74, 0x01, 0x6f, 0x02, 0x6c, 0x03, 0x68, 0x04, 0x65, 0x05, 0x62, 0x06, +0x61, 0x07, 0x5f, 0x09, 0x5c, 0x09, 0x5b, 0x0b, 0x5a, 0x0b, 0x58, 0x0c, +0x57, 0x0d, 0x55, 0x0e, 0x55, 0x0f, 0x54, 0x11, 0x52, 0x11, 0x52, 0x12, +0x00, 0x79, 0x00, 0x74, 0x00, 0x6f, 0x02, 0x6a, 0x03, 0x66, 0x04, 0x63, +0x05, 0x60, 0x05, 0x5e, 0x06, 0x5b, 0x07, 0x59, 0x09, 0x58, 0x09, 0x55, +0x0b, 0x55, 0x0c, 0x53, 0x0d, 0x52, 0x0d, 0x50, 0x0f, 0x50, 0x0f, 0x4e, +0x11, 0x4e, 0x11, 0x4d, 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7d, 0x00, 0x7a, 0x00, 0x75, +0x00, 0x6e, 0x00, 0x65, 0x00, 0x5b, 0x00, 0x51, 0x00, 0x46, 0x00, 0x3b, +0x00, 0x30, 0x00, 0x26, 0x00, 0x1b, 0x00, 0x12, 0x00, 0x08, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x7d, 0x00, +0x7a, 0x00, 0x75, 0x00, 0x6e, 0x00, 0x65, 0x00, 0x5b, 0x00, 0x51, 0x00, +0x46, 0x00, 0x3b, 0x00, 0x30, 0x00, 0x26, 0x00, 0x1b, 0x00, 0x12, 0x00, +0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x7e, 0x00, 0x79, 0x00, 0x74, 0x01, 0x70, 0x02, +0x6c, 0x03, 0x69, 0x03, 0x66, 0x05, 0x63, 0x06, 0x62, 0x07, 0x5f, 0x07, +0x5e, 0x09, 0x5c, 0x0a, 0x5a, 0x0b, 0x5a, 0x0c, 0x57, 0x0c, 0x56, 0x0e, +0x55, 0x0e, 0x55, 0x0f, 0x54, 0x11, 0x52, 0x11, 0x00, 0x79, 0x00, 0x74, +0x00, 0x70, 0x01, 0x6b, 0x02, 0x67, 0x03, 0x64, 0x04, 0x61, 0x05, 0x5f, +0x06, 0x5d, 0x07, 0x5b, 0x08, 0x58, 0x09, 0x57, 0x0a, 0x55, 0x0b, 0x54, +0x0c, 0x53, 0x0d, 0x51, 0x0e, 0x50, 0x0f, 0x50, 0x0f, 0x4e, 0x11, 0x4e, +0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x66, 0x7f, 0x4d, 0x68, 0x49, 0x5c, 0x47, 0x55, 0x45, 0x51, 0x45, 0x4e, +0x44, 0x4c, 0x43, 0x4a, 0x43, 0x49, 0x43, 0x48, 0x43, 0x47, 0x42, 0x47, +0x42, 0x46, 0x42, 0x46, 0x42, 0x45, 0x42, 0x45, 0x42, 0x45, 0x42, 0x44, +0x42, 0x44, 0x42, 0x44, 0x57, 0x7f, 0x2e, 0x58, 0x34, 0x4d, 0x37, 0x49, +0x39, 0x47, 0x3a, 0x45, 0x3b, 0x44, 0x3b, 0x44, 0x3c, 0x43, 0x3c, 0x43, +0x3c, 0x43, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x41, +0x3d, 0x41, 0x3d, 0x41, 0x3d, 0x41, 0x3d, 0x41, 0x99, 0x7f, 0x4d, 0x58, +0x49, 0x4d, 0x47, 0x49, 0x45, 0x47, 0x45, 0x45, 0x44, 0x44, 0x43, 0x44, +0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, +0x42, 0x41, 0x42, 0x41, 0x42, 0x41, 0x42, 0x41, 0x42, 0x41, 0x42, 0x41, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x05, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x5f, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0xa5, 0x16, 0x74, 0x23, +0x62, 0x29, 0x59, 0x2d, 0x53, 0x30, 0x50, 0x32, 0x4e, 0x34, 0x4c, 0x35, +0x4a, 0x36, 0x49, 0x37, 0x48, 0x38, 0x48, 0x38, 0x47, 0x39, 0x46, 0x39, +0x46, 0x39, 0x46, 0x3a, 0x45, 0x3a, 0x45, 0x3a, 0x45, 0x3a, 0x44, 0x3b, +0x23, 0x2f, 0x25, 0x35, 0x2a, 0x37, 0x2e, 0x39, 0x31, 0x3a, 0x33, 0x3b, +0x34, 0x3b, 0x35, 0x3c, 0x37, 0x3c, 0x37, 0x3c, 0x38, 0x3d, 0x38, 0x3d, +0x39, 0x3d, 0x39, 0x3d, 0x39, 0x3d, 0x3a, 0x3d, 0x3a, 0x3d, 0x3a, 0x3d, +0x3b, 0x3d, 0x3b, 0x3d, 0x77, 0x27, 0x5f, 0x31, 0x56, 0x35, 0x52, 0x38, +0x4f, 0x39, 0x4c, 0x3a, 0x4b, 0x3b, 0x49, 0x3b, 0x48, 0x3c, 0x48, 0x3c, +0x47, 0x3c, 0x47, 0x3c, 0x46, 0x3d, 0x46, 0x3d, 0x45, 0x3d, 0x45, 0x3d, +0x45, 0x3d, 0x44, 0x3d, 0x44, 0x3d, 0x44, 0x3d, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x00, 0x1f, 0x00, 0x01, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0x00, 0x5f, 0x00, +0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0xbb, 0x01, 0x91, 0x09, 0x78, 0x11, 0x6b, 0x17, +0x62, 0x1c, 0x5c, 0x20, 0x58, 0x23, 0x55, 0x25, 0x52, 0x28, 0x51, 0x2a, +0x4f, 0x2b, 0x4e, 0x2c, 0x4d, 0x2e, 0x4c, 0x2f, 0x4b, 0x30, 0x4a, 0x31, +0x49, 0x31, 0x49, 0x32, 0x48, 0x33, 0x47, 0x33, 0x22, 0x25, 0x23, 0x2a, +0x26, 0x2e, 0x2a, 0x31, 0x2c, 0x33, 0x2e, 0x34, 0x30, 0x36, 0x31, 0x37, +0x32, 0x37, 0x33, 0x38, 0x34, 0x38, 0x35, 0x39, 0x36, 0x39, 0x36, 0x3a, +0x37, 0x3a, 0x37, 0x3a, 0x38, 0x3a, 0x38, 0x3b, 0x39, 0x3b, 0x39, 0x3b, +0x7a, 0x1a, 0x68, 0x24, 0x5f, 0x2a, 0x5a, 0x2e, 0x55, 0x31, 0x53, 0x33, +0x51, 0x34, 0x4f, 0x35, 0x4d, 0x36, 0x4c, 0x37, 0x4b, 0x38, 0x4b, 0x38, +0x4a, 0x39, 0x49, 0x39, 0x49, 0x39, 0x48, 0x3a, 0x47, 0x3a, 0x47, 0x3a, +0x46, 0x3b, 0x46, 0x3b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x39, 0x00, 0x2e, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0xac, 0x00, 0x8b, 0x00, 0x44, 0x00, 0x02, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0xc6, 0x00, 0xa3, 0x02, 0x8a, 0x07, 0x7a, 0x0c, 0x6f, 0x11, 0x68, 0x15, +0x62, 0x18, 0x5e, 0x1b, 0x5b, 0x1d, 0x58, 0x20, 0x56, 0x22, 0x54, 0x23, +0x53, 0x25, 0x51, 0x26, 0x50, 0x28, 0x4e, 0x29, 0x4d, 0x2a, 0x4d, 0x2b, +0x4d, 0x2c, 0x4c, 0x2c, 0x22, 0x23, 0x22, 0x27, 0x25, 0x2a, 0x27, 0x2c, +0x2a, 0x2e, 0x2b, 0x30, 0x2d, 0x32, 0x2e, 0x33, 0x30, 0x34, 0x31, 0x34, +0x32, 0x35, 0x33, 0x36, 0x33, 0x36, 0x34, 0x37, 0x34, 0x37, 0x35, 0x38, +0x36, 0x38, 0x36, 0x39, 0x36, 0x39, 0x36, 0x39, 0x7b, 0x16, 0x6d, 0x1f, +0x65, 0x24, 0x5f, 0x28, 0x5b, 0x2b, 0x58, 0x2d, 0x55, 0x2f, 0x54, 0x31, +0x52, 0x32, 0x50, 0x33, 0x4f, 0x34, 0x4e, 0x35, 0x4d, 0x35, 0x4c, 0x36, +0x4b, 0x36, 0x4a, 0x37, 0x4a, 0x38, 0x4a, 0x38, 0x4a, 0x39, 0x49, 0x39, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x35, +0x00, 0x24, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0xb3, 0x00, 0x9f, 0x00, 0x6d, 0x00, 0x33, 0x00, 0x01, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0xcc, 0x00, 0xaf, 0x00, +0x98, 0x03, 0x87, 0x06, 0x7b, 0x0a, 0x73, 0x0e, 0x6c, 0x11, 0x67, 0x13, +0x63, 0x16, 0x5f, 0x18, 0x5c, 0x1a, 0x5a, 0x1c, 0x58, 0x1e, 0x56, 0x20, +0x55, 0x21, 0x54, 0x22, 0x52, 0x24, 0x51, 0x25, 0x50, 0x26, 0x4f, 0x27, +0x22, 0x22, 0x22, 0x25, 0x24, 0x27, 0x26, 0x2a, 0x28, 0x2b, 0x29, 0x2d, +0x2b, 0x2f, 0x2c, 0x30, 0x2d, 0x31, 0x2f, 0x32, 0x30, 0x33, 0x30, 0x33, +0x31, 0x34, 0x32, 0x35, 0x33, 0x35, 0x33, 0x36, 0x33, 0x36, 0x34, 0x36, +0x35, 0x36, 0x35, 0x37, 0x7c, 0x15, 0x71, 0x1b, 0x68, 0x20, 0x63, 0x24, +0x5f, 0x27, 0x5c, 0x29, 0x59, 0x2c, 0x57, 0x2d, 0x55, 0x2f, 0x54, 0x30, +0x53, 0x31, 0x51, 0x32, 0x50, 0x32, 0x4f, 0x33, 0x4f, 0x34, 0x4e, 0x35, +0x4d, 0x35, 0x4c, 0x35, 0x4b, 0x35, 0x4a, 0x36, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x38, 0x00, 0x2c, 0x00, 0x1d, +0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb7, 0x00, 0xaa, 0x00, +0x85, 0x00, 0x57, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0xcf, 0x00, 0xb7, 0x00, 0xa2, 0x00, 0x92, 0x03, +0x85, 0x06, 0x7c, 0x09, 0x75, 0x0b, 0x6f, 0x0e, 0x6a, 0x11, 0x66, 0x13, +0x63, 0x15, 0x5f, 0x17, 0x5e, 0x19, 0x5c, 0x1a, 0x5a, 0x1c, 0x57, 0x1d, +0x56, 0x1f, 0x55, 0x1f, 0x55, 0x21, 0x54, 0x22, 0x22, 0x22, 0x22, 0x24, +0x23, 0x26, 0x25, 0x28, 0x26, 0x29, 0x28, 0x2b, 0x29, 0x2c, 0x2b, 0x2d, +0x2c, 0x2f, 0x2d, 0x30, 0x2d, 0x30, 0x2f, 0x31, 0x30, 0x32, 0x30, 0x33, +0x30, 0x33, 0x32, 0x33, 0x32, 0x34, 0x33, 0x35, 0x33, 0x36, 0x33, 0x36, +0x7c, 0x14, 0x73, 0x19, 0x6c, 0x1e, 0x67, 0x22, 0x63, 0x24, 0x5f, 0x26, +0x5c, 0x28, 0x5a, 0x2a, 0x58, 0x2c, 0x57, 0x2d, 0x55, 0x2e, 0x53, 0x2f, +0x53, 0x30, 0x52, 0x31, 0x51, 0x31, 0x4f, 0x32, 0x4f, 0x33, 0x4f, 0x33, +0x4f, 0x34, 0x4e, 0x35, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x3e, 0x00, 0x3a, 0x00, 0x31, 0x00, 0x25, 0x00, 0x18, 0x00, 0x0b, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0xba, 0x00, 0xb0, 0x00, 0x95, 0x00, 0x70, 0x00, +0x48, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0xd2, 0x00, 0xbd, 0x00, 0xaa, 0x00, 0x9b, 0x01, 0x8e, 0x03, 0x84, 0x05, +0x7c, 0x08, 0x76, 0x0a, 0x71, 0x0c, 0x6c, 0x0f, 0x69, 0x11, 0x66, 0x12, +0x63, 0x14, 0x60, 0x16, 0x5e, 0x17, 0x5d, 0x19, 0x5b, 0x1a, 0x59, 0x1b, +0x57, 0x1c, 0x56, 0x1e, 0x22, 0x22, 0x22, 0x23, 0x23, 0x25, 0x24, 0x27, +0x25, 0x28, 0x27, 0x29, 0x28, 0x2b, 0x29, 0x2c, 0x2b, 0x2d, 0x2b, 0x2d, +0x2d, 0x2f, 0x2d, 0x30, 0x2d, 0x30, 0x2f, 0x30, 0x30, 0x32, 0x30, 0x33, +0x30, 0x33, 0x31, 0x33, 0x32, 0x33, 0x33, 0x33, 0x7d, 0x13, 0x75, 0x18, +0x6e, 0x1c, 0x69, 0x1f, 0x65, 0x22, 0x62, 0x24, 0x60, 0x26, 0x5c, 0x28, +0x5b, 0x29, 0x59, 0x2a, 0x57, 0x2c, 0x57, 0x2d, 0x55, 0x2e, 0x53, 0x2e, +0x53, 0x2f, 0x53, 0x31, 0x51, 0x31, 0x50, 0x31, 0x4f, 0x31, 0x4f, 0x32, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x3c, +0x00, 0x35, 0x00, 0x2b, 0x00, 0x1f, 0x00, 0x14, 0x00, 0x09, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0xbb, 0x00, 0xb3, 0x00, 0x9f, 0x00, 0x81, 0x00, 0x5f, 0x00, 0x3d, 0x00, +0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0xd3, 0x00, 0xc2, 0x00, +0xb1, 0x00, 0xa2, 0x00, 0x96, 0x02, 0x8c, 0x03, 0x83, 0x05, 0x7d, 0x07, +0x77, 0x09, 0x73, 0x0b, 0x6f, 0x0d, 0x6a, 0x0f, 0x68, 0x11, 0x66, 0x12, +0x63, 0x14, 0x60, 0x15, 0x5f, 0x16, 0x5e, 0x18, 0x5c, 0x19, 0x5a, 0x1a, +0x22, 0x22, 0x22, 0x23, 0x23, 0x24, 0x24, 0x25, 0x25, 0x27, 0x26, 0x29, +0x27, 0x29, 0x28, 0x2b, 0x29, 0x2b, 0x2b, 0x2d, 0x2b, 0x2d, 0x2c, 0x2e, +0x2d, 0x2f, 0x2d, 0x30, 0x2e, 0x30, 0x2f, 0x30, 0x30, 0x31, 0x30, 0x32, +0x30, 0x33, 0x30, 0x33, 0x7d, 0x13, 0x76, 0x17, 0x70, 0x1b, 0x6b, 0x1e, +0x68, 0x20, 0x65, 0x22, 0x61, 0x24, 0x60, 0x26, 0x5d, 0x27, 0x5c, 0x29, +0x5a, 0x2a, 0x58, 0x2b, 0x57, 0x2c, 0x57, 0x2d, 0x55, 0x2e, 0x53, 0x2e, +0x53, 0x2f, 0x53, 0x30, 0x53, 0x31, 0x51, 0x31, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x3c, 0x00, 0x37, 0x00, 0x2f, +0x00, 0x25, 0x00, 0x1b, 0x00, 0x11, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbc, 0x00, 0xb6, 0x00, +0xa6, 0x00, 0x8e, 0x00, 0x71, 0x00, 0x52, 0x00, 0x35, 0x00, 0x19, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0xd4, 0x00, 0xc5, 0x00, 0xb6, 0x00, 0xa8, 0x00, +0x9c, 0x00, 0x92, 0x02, 0x8a, 0x03, 0x82, 0x05, 0x7d, 0x07, 0x78, 0x09, +0x74, 0x0a, 0x71, 0x0c, 0x6c, 0x0e, 0x69, 0x0f, 0x68, 0x11, 0x65, 0x12, +0x63, 0x13, 0x60, 0x14, 0x5f, 0x16, 0x5e, 0x17, 0x21, 0x22, 0x22, 0x23, +0x22, 0x24, 0x23, 0x25, 0x24, 0x26, 0x25, 0x27, 0x27, 0x28, 0x27, 0x29, +0x28, 0x2b, 0x29, 0x2b, 0x2b, 0x2c, 0x2b, 0x2d, 0x2b, 0x2d, 0x2d, 0x2e, +0x2d, 0x2f, 0x2d, 0x30, 0x2e, 0x30, 0x2f, 0x30, 0x30, 0x30, 0x30, 0x31, +0x7d, 0x12, 0x77, 0x16, 0x71, 0x19, 0x6d, 0x1c, 0x69, 0x1f, 0x66, 0x20, +0x64, 0x23, 0x61, 0x24, 0x60, 0x26, 0x5d, 0x27, 0x5c, 0x28, 0x5b, 0x2a, +0x58, 0x2a, 0x57, 0x2b, 0x57, 0x2c, 0x56, 0x2e, 0x54, 0x2e, 0x53, 0x2e, +0x53, 0x2e, 0x53, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x3e, 0x00, 0x3d, 0x00, 0x39, 0x00, 0x32, 0x00, 0x2a, 0x00, 0x21, +0x00, 0x18, 0x00, 0x0f, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0xbc, 0x00, 0xb8, 0x00, 0xab, 0x00, 0x97, 0x00, +0x7e, 0x00, 0x64, 0x00, 0x48, 0x00, 0x2e, 0x00, 0x16, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0xd5, 0x00, 0xc7, 0x00, 0xba, 0x00, 0xad, 0x00, 0xa2, 0x00, 0x98, 0x01, +0x8f, 0x02, 0x88, 0x03, 0x82, 0x05, 0x7e, 0x07, 0x78, 0x08, 0x74, 0x0a, +0x72, 0x0b, 0x6e, 0x0c, 0x6b, 0x0e, 0x69, 0x0f, 0x67, 0x11, 0x65, 0x12, +0x63, 0x13, 0x60, 0x14, 0x21, 0x22, 0x22, 0x22, 0x22, 0x23, 0x23, 0x24, +0x24, 0x25, 0x25, 0x27, 0x26, 0x27, 0x27, 0x28, 0x27, 0x29, 0x28, 0x2b, +0x29, 0x2b, 0x2b, 0x2b, 0x2b, 0x2d, 0x2a, 0x2d, 0x2c, 0x2d, 0x2d, 0x2e, +0x2d, 0x2f, 0x2d, 0x30, 0x2e, 0x30, 0x2f, 0x30, 0x7d, 0x12, 0x77, 0x15, +0x72, 0x18, 0x6e, 0x1b, 0x6b, 0x1d, 0x68, 0x20, 0x65, 0x21, 0x64, 0x23, +0x60, 0x24, 0x60, 0x26, 0x5d, 0x27, 0x5c, 0x27, 0x5c, 0x29, 0x59, 0x2a, +0x57, 0x2a, 0x57, 0x2b, 0x57, 0x2c, 0x56, 0x2e, 0x54, 0x2e, 0x53, 0x2e, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x3d, +0x00, 0x3a, 0x00, 0x34, 0x00, 0x2d, 0x00, 0x25, 0x00, 0x1d, 0x00, 0x15, +0x00, 0x0d, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0xbd, 0x00, 0xb9, 0x00, 0xae, 0x00, 0x9e, 0x00, 0x89, 0x00, 0x71, 0x00, +0x59, 0x00, 0x41, 0x00, 0x29, 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0xd6, 0x00, 0xc9, 0x00, +0xbd, 0x00, 0xb2, 0x00, 0xa7, 0x00, 0x9d, 0x00, 0x95, 0x01, 0x8e, 0x02, +0x87, 0x03, 0x82, 0x05, 0x7e, 0x06, 0x79, 0x08, 0x75, 0x09, 0x73, 0x0b, +0x70, 0x0c, 0x6c, 0x0d, 0x6a, 0x0e, 0x68, 0x0f, 0x67, 0x11, 0x65, 0x12, +0x21, 0x22, 0x22, 0x22, 0x22, 0x23, 0x23, 0x24, 0x24, 0x25, 0x24, 0x26, +0x25, 0x27, 0x27, 0x28, 0x27, 0x28, 0x28, 0x29, 0x28, 0x2b, 0x28, 0x2b, +0x2a, 0x2b, 0x2b, 0x2c, 0x2a, 0x2d, 0x2b, 0x2d, 0x2d, 0x2d, 0x2d, 0x2e, +0x2d, 0x2f, 0x2d, 0x30, 0x7d, 0x12, 0x78, 0x15, 0x73, 0x18, 0x70, 0x1a, +0x6d, 0x1d, 0x69, 0x1e, 0x67, 0x20, 0x65, 0x21, 0x63, 0x23, 0x60, 0x24, +0x60, 0x26, 0x5d, 0x27, 0x5c, 0x27, 0x5c, 0x28, 0x5a, 0x2a, 0x58, 0x2a, +0x57, 0x2a, 0x57, 0x2b, 0x57, 0x2c, 0x56, 0x2e, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x3e, 0x00, 0x3b, 0x00, 0x36, +0x00, 0x30, 0x00, 0x29, 0x00, 0x22, 0x00, 0x1a, 0x00, 0x13, 0x00, 0x0c, +0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbd, 0x00, 0xba, 0x00, +0xb1, 0x00, 0xa3, 0x00, 0x91, 0x00, 0x7c, 0x00, 0x66, 0x00, 0x50, 0x00, +0x3a, 0x00, 0x25, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0xd7, 0x00, 0xcb, 0x00, 0xc0, 0x00, 0xb5, 0x00, +0xab, 0x00, 0xa2, 0x00, 0x9a, 0x00, 0x92, 0x02, 0x8d, 0x02, 0x87, 0x03, +0x81, 0x05, 0x7e, 0x06, 0x79, 0x07, 0x76, 0x09, 0x74, 0x0a, 0x71, 0x0b, +0x6e, 0x0c, 0x6b, 0x0d, 0x6a, 0x0e, 0x68, 0x10, 0x21, 0x22, 0x22, 0x22, +0x22, 0x23, 0x23, 0x24, 0x23, 0x25, 0x24, 0x25, 0x25, 0x27, 0x25, 0x27, +0x27, 0x28, 0x27, 0x28, 0x28, 0x29, 0x28, 0x2b, 0x28, 0x2b, 0x2a, 0x2b, +0x2b, 0x2c, 0x2b, 0x2d, 0x2b, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2e, +0x7e, 0x12, 0x79, 0x15, 0x75, 0x17, 0x71, 0x1a, 0x6d, 0x1b, 0x6a, 0x1d, +0x69, 0x1f, 0x65, 0x20, 0x65, 0x22, 0x62, 0x23, 0x60, 0x23, 0x60, 0x25, +0x5d, 0x27, 0x5c, 0x27, 0x5c, 0x28, 0x5c, 0x29, 0x59, 0x2a, 0x57, 0x2a, +0x57, 0x2a, 0x57, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x3f, 0x00, 0x3e, 0x00, 0x3b, 0x00, 0x37, 0x00, 0x32, 0x00, 0x2c, +0x00, 0x26, 0x00, 0x1f, 0x00, 0x18, 0x00, 0x11, 0x00, 0x0b, 0x00, 0x05, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0xbd, 0x00, 0xbb, 0x00, 0xb3, 0x00, 0xa7, 0x00, +0x98, 0x00, 0x85, 0x00, 0x72, 0x00, 0x5d, 0x00, 0x49, 0x00, 0x35, 0x00, +0x22, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0xd7, 0x00, 0xcc, 0x00, 0xc2, 0x00, 0xb9, 0x00, 0xae, 0x00, 0xa6, 0x00, +0x9e, 0x00, 0x97, 0x01, 0x90, 0x02, 0x8b, 0x02, 0x85, 0x04, 0x81, 0x05, +0x7e, 0x06, 0x7a, 0x07, 0x76, 0x08, 0x74, 0x09, 0x72, 0x0b, 0x6f, 0x0c, +0x6c, 0x0c, 0x6a, 0x0e, 0x21, 0x22, 0x22, 0x22, 0x22, 0x23, 0x23, 0x24, +0x23, 0x24, 0x24, 0x25, 0x25, 0x25, 0x25, 0x27, 0x26, 0x27, 0x27, 0x28, +0x26, 0x28, 0x28, 0x28, 0x28, 0x2a, 0x28, 0x2b, 0x2a, 0x2b, 0x2b, 0x2b, +0x2b, 0x2d, 0x2b, 0x2d, 0x2c, 0x2d, 0x2d, 0x2d, 0x7e, 0x12, 0x79, 0x15, +0x75, 0x17, 0x72, 0x19, 0x6e, 0x1a, 0x6c, 0x1d, 0x69, 0x1d, 0x68, 0x20, +0x65, 0x20, 0x65, 0x22, 0x61, 0x23, 0x60, 0x23, 0x60, 0x25, 0x5e, 0x27, +0x5c, 0x27, 0x5c, 0x27, 0x5c, 0x29, 0x5a, 0x2a, 0x58, 0x2a, 0x57, 0x2a, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x3e, +0x00, 0x3c, 0x00, 0x38, 0x00, 0x34, 0x00, 0x2f, 0x00, 0x29, 0x00, 0x22, +0x00, 0x1c, 0x00, 0x16, 0x00, 0x10, 0x00, 0x0a, 0x00, 0x05, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0xbe, 0x00, 0xbb, 0x00, 0xb5, 0x00, 0xaa, 0x00, 0x9d, 0x00, 0x8d, 0x00, +0x7b, 0x00, 0x68, 0x00, 0x55, 0x00, 0x43, 0x00, 0x30, 0x00, 0x1f, 0x00, +0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0xd8, 0x00, 0xce, 0x00, +0xc5, 0x00, 0xbb, 0x00, 0xb2, 0x00, 0xaa, 0x00, 0xa1, 0x00, 0x9b, 0x00, +0x94, 0x01, 0x8f, 0x02, 0x8a, 0x03, 0x84, 0x04, 0x81, 0x05, 0x7e, 0x06, +0x7b, 0x07, 0x77, 0x08, 0x75, 0x09, 0x73, 0x0a, 0x71, 0x0b, 0x6e, 0x0c, +0x21, 0x22, 0x22, 0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x24, 0x24, 0x25, +0x24, 0x25, 0x25, 0x26, 0x25, 0x27, 0x27, 0x27, 0x27, 0x28, 0x27, 0x28, +0x28, 0x28, 0x28, 0x2a, 0x28, 0x2b, 0x2a, 0x2b, 0x2b, 0x2b, 0x2b, 0x2c, +0x2b, 0x2d, 0x2b, 0x2d, 0x7e, 0x12, 0x7a, 0x14, 0x76, 0x16, 0x72, 0x18, +0x6f, 0x1a, 0x6d, 0x1b, 0x6a, 0x1d, 0x69, 0x1e, 0x66, 0x20, 0x65, 0x20, +0x64, 0x23, 0x61, 0x23, 0x60, 0x23, 0x60, 0x25, 0x5e, 0x27, 0x5c, 0x27, +0x5c, 0x27, 0x5c, 0x28, 0x5b, 0x2a, 0x59, 0x2a, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x3e, 0x00, 0x3c, 0x00, 0x39, +0x00, 0x35, 0x00, 0x31, 0x00, 0x2b, 0x00, 0x26, 0x00, 0x20, 0x00, 0x1a, +0x00, 0x14, 0x00, 0x0f, 0x00, 0x09, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x00, 0xbc, 0x00, +0xb6, 0x00, 0xad, 0x00, 0xa1, 0x00, 0x93, 0x00, 0x83, 0x00, 0x72, 0x00, +0x60, 0x00, 0x4f, 0x00, 0x3d, 0x00, 0x2d, 0x00, 0x1d, 0x00, 0x0e, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0xd8, 0x00, 0xcf, 0x00, 0xc6, 0x00, 0xbd, 0x00, +0xb5, 0x00, 0xad, 0x00, 0xa6, 0x00, 0x9e, 0x00, 0x99, 0x00, 0x92, 0x01, +0x8e, 0x02, 0x89, 0x03, 0x84, 0x04, 0x81, 0x05, 0x7e, 0x06, 0x7b, 0x07, +0x77, 0x07, 0x75, 0x09, 0x73, 0x09, 0x72, 0x0b, 0x21, 0x22, 0x22, 0x22, +0x22, 0x22, 0x22, 0x23, 0x23, 0x24, 0x24, 0x24, 0x24, 0x25, 0x25, 0x25, +0x25, 0x27, 0x25, 0x27, 0x27, 0x27, 0x27, 0x28, 0x27, 0x28, 0x28, 0x28, +0x28, 0x2a, 0x28, 0x2b, 0x2a, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2d, +0x7e, 0x12, 0x7a, 0x14, 0x76, 0x15, 0x72, 0x18, 0x71, 0x1a, 0x6d, 0x1a, +0x6c, 0x1d, 0x69, 0x1d, 0x68, 0x1f, 0x65, 0x20, 0x65, 0x21, 0x64, 0x23, +0x60, 0x23, 0x60, 0x23, 0x60, 0x25, 0x5e, 0x27, 0x5c, 0x27, 0x5c, 0x27, +0x5c, 0x27, 0x5c, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x3f, 0x00, 0x3e, 0x00, 0x3d, 0x00, 0x3a, 0x00, 0x37, 0x00, 0x32, +0x00, 0x2d, 0x00, 0x28, 0x00, 0x23, 0x00, 0x1d, 0x00, 0x18, 0x00, 0x13, +0x00, 0x0d, 0x00, 0x09, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0xbe, 0x00, 0xbc, 0x00, 0xb7, 0x00, 0xaf, 0x00, +0xa5, 0x00, 0x98, 0x00, 0x89, 0x00, 0x7a, 0x00, 0x6a, 0x00, 0x59, 0x00, +0x49, 0x00, 0x39, 0x00, 0x29, 0x00, 0x1b, 0x00, 0x0d, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0xd8, 0x00, 0xd0, 0x00, 0xc7, 0x00, 0xbf, 0x00, 0xb8, 0x00, 0xaf, 0x00, +0xa9, 0x00, 0xa1, 0x00, 0x9c, 0x00, 0x96, 0x01, 0x90, 0x02, 0x8d, 0x02, +0x88, 0x03, 0x84, 0x04, 0x81, 0x05, 0x7f, 0x06, 0x7b, 0x07, 0x77, 0x07, +0x76, 0x09, 0x74, 0x09, 0x21, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x23, +0x23, 0x24, 0x23, 0x24, 0x24, 0x25, 0x24, 0x25, 0x25, 0x26, 0x25, 0x27, +0x26, 0x27, 0x27, 0x27, 0x26, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x2a, +0x28, 0x2b, 0x2a, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x7e, 0x11, 0x7a, 0x13, +0x76, 0x15, 0x74, 0x18, 0x72, 0x19, 0x6e, 0x1a, 0x6d, 0x1c, 0x69, 0x1d, +0x69, 0x1e, 0x67, 0x20, 0x65, 0x20, 0x65, 0x21, 0x63, 0x23, 0x60, 0x23, +0x60, 0x23, 0x60, 0x25, 0x5e, 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x5c, 0x27, +0x00, 0x0f, 0x00, 0x1f, 0x00, 0x33, 0x00, 0x39, 0x00, 0x3c, 0x00, 0x3d, +0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3f, 0x00, 0x3f, +0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x58, 0x00, 0x3d, +0x00, 0x4c, 0x00, 0x4c, 0x00, 0x48, 0x00, 0x42, 0x00, 0x3e, 0x00, 0x3e, +0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3f, +0x00, 0x3f, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x3b, 0x0b, 0x07, 0x17, 0x00, 0x2c, 0x00, 0x36, 0x00, 0x3a, 0x00, 0x3c, +0x00, 0x3d, 0x00, 0x3d, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3e, +0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3f, 0x47, 0x07, 0x0f, 0x0f, +0x00, 0x26, 0x00, 0x33, 0x00, 0x38, 0x00, 0x3a, 0x00, 0x3c, 0x00, 0x3d, +0x00, 0x3d, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3f, +0x00, 0x3f, 0x00, 0x3f, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0xd9, 0x00, 0xd1, 0x00, +0xc9, 0x00, 0xc1, 0x00, 0xba, 0x00, 0xb2, 0x00, 0xac, 0x00, 0xa5, 0x00, +0x9e, 0x00, 0x9a, 0x00, 0x93, 0x01, 0x8f, 0x02, 0x8c, 0x02, 0x88, 0x03, +0x83, 0x04, 0x81, 0x05, 0x7f, 0x06, 0x7b, 0x06, 0x78, 0x07, 0x76, 0x08, +0x21, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x23, 0x23, 0x23, 0x23, 0x24, +0x24, 0x24, 0x24, 0x25, 0x25, 0x25, 0x25, 0x27, 0x25, 0x27, 0x27, 0x27, +0x27, 0x28, 0x27, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x2a, 0x28, 0x2b, +0x2a, 0x2b, 0x2b, 0x2b, 0x7e, 0x11, 0x7b, 0x13, 0x77, 0x15, 0x75, 0x17, +0x72, 0x18, 0x6f, 0x1a, 0x6d, 0x1a, 0x6c, 0x1d, 0x69, 0x1d, 0x69, 0x1f, +0x65, 0x20, 0x65, 0x20, 0x65, 0x22, 0x62, 0x23, 0x60, 0x23, 0x60, 0x23, +0x60, 0x25, 0x5f, 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x00, 0x00, 0x00, 0x05, +0x00, 0x1f, 0x00, 0x2e, 0x00, 0x35, 0x00, 0x38, 0x00, 0x3a, 0x00, 0x3c, +0x00, 0x3c, 0x00, 0x3d, 0x00, 0x3d, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3e, +0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3d, 0x00, 0x30, 0x00, 0x39, 0x00, 0x42, +0x00, 0x41, 0x00, 0x3d, 0x00, 0x3a, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3d, +0x00, 0x3d, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3e, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6f, 0x00, 0x27, 0x02, +0x02, 0x12, 0x00, 0x25, 0x00, 0x2f, 0x00, 0x35, 0x00, 0x38, 0x00, 0x3a, +0x00, 0x3b, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3d, 0x00, 0x3d, 0x00, 0x3e, +0x00, 0x3e, 0x00, 0x3e, 0x7f, 0x00, 0x3f, 0x00, 0x05, 0x05, 0x00, 0x1c, +0x00, 0x2a, 0x00, 0x31, 0x00, 0x35, 0x00, 0x38, 0x00, 0x39, 0x00, 0x3b, +0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3d, 0x00, 0x3d, 0x00, 0x3d, 0x00, 0x3e, +0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0xd9, 0x00, 0xd2, 0x00, 0xca, 0x00, 0xc3, 0x00, +0xbb, 0x00, 0xb5, 0x00, 0xae, 0x00, 0xa8, 0x00, 0xa1, 0x00, 0x9d, 0x00, +0x98, 0x00, 0x92, 0x01, 0x8e, 0x02, 0x8b, 0x02, 0x87, 0x03, 0x83, 0x04, +0x81, 0x05, 0x7f, 0x06, 0x7c, 0x06, 0x78, 0x07, 0x21, 0x22, 0x22, 0x22, +0x22, 0x22, 0x22, 0x23, 0x23, 0x23, 0x23, 0x24, 0x24, 0x24, 0x24, 0x25, +0x24, 0x25, 0x25, 0x25, 0x25, 0x27, 0x26, 0x27, 0x27, 0x27, 0x27, 0x28, +0x27, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x2a, 0x28, 0x2b, 0x29, 0x2b, +0x7e, 0x11, 0x7b, 0x13, 0x77, 0x15, 0x76, 0x17, 0x72, 0x18, 0x71, 0x1a, +0x6d, 0x1a, 0x6d, 0x1c, 0x69, 0x1d, 0x69, 0x1d, 0x68, 0x20, 0x65, 0x20, +0x65, 0x20, 0x65, 0x22, 0x61, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x25, +0x5f, 0x27, 0x5c, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x16, +0x00, 0x24, 0x00, 0x2c, 0x00, 0x31, 0x00, 0x35, 0x00, 0x37, 0x00, 0x39, +0x00, 0x3a, 0x00, 0x3b, 0x00, 0x3b, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3d, +0x00, 0x4c, 0x00, 0x39, 0x00, 0x16, 0x00, 0x28, 0x00, 0x2f, 0x00, 0x2e, +0x00, 0x31, 0x00, 0x35, 0x00, 0x37, 0x00, 0x39, 0x00, 0x3a, 0x00, 0x3b, +0x00, 0x3b, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3d, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x9f, 0x00, 0x6f, 0x00, 0x22, 0x00, 0x09, 0x0b, +0x00, 0x16, 0x00, 0x23, 0x00, 0x2a, 0x00, 0x2f, 0x00, 0x33, 0x00, 0x35, +0x00, 0x37, 0x00, 0x38, 0x00, 0x39, 0x00, 0x3a, 0x00, 0x3b, 0x00, 0x3c, +0xa5, 0x00, 0x7f, 0x00, 0x3f, 0x00, 0x12, 0x00, 0x00, 0x09, 0x00, 0x19, +0x00, 0x23, 0x00, 0x2a, 0x00, 0x2f, 0x00, 0x32, 0x00, 0x34, 0x00, 0x36, +0x00, 0x38, 0x00, 0x39, 0x00, 0x3a, 0x00, 0x3a, 0x41, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0xd9, 0x00, 0xd2, 0x00, 0xca, 0x00, 0xc5, 0x00, 0xbd, 0x00, 0xb7, 0x00, +0xb0, 0x00, 0xab, 0x00, 0xa4, 0x00, 0x9f, 0x00, 0x9b, 0x00, 0x95, 0x01, +0x91, 0x01, 0x8e, 0x02, 0x8a, 0x02, 0x86, 0x03, 0x83, 0x04, 0x81, 0x05, +0x7f, 0x06, 0x7c, 0x06, 0x21, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x23, +0x22, 0x23, 0x23, 0x24, 0x23, 0x24, 0x24, 0x24, 0x24, 0x25, 0x25, 0x25, +0x25, 0x26, 0x25, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x28, 0x27, 0x28, +0x28, 0x28, 0x28, 0x28, 0x28, 0x2a, 0x28, 0x2b, 0x7f, 0x11, 0x7b, 0x13, +0x77, 0x15, 0x76, 0x16, 0x72, 0x18, 0x72, 0x19, 0x6d, 0x1a, 0x6d, 0x1b, +0x6b, 0x1d, 0x69, 0x1d, 0x69, 0x1e, 0x66, 0x20, 0x65, 0x20, 0x65, 0x20, +0x64, 0x22, 0x61, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x24, 0x5f, 0x26, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x1d, +0x00, 0x25, 0x00, 0x2b, 0x00, 0x2f, 0x00, 0x32, 0x00, 0x34, 0x00, 0x36, +0x00, 0x37, 0x00, 0x38, 0x00, 0x39, 0x00, 0x3a, 0x00, 0x4c, 0x00, 0x42, +0x00, 0x28, 0x00, 0x09, 0x00, 0x16, 0x00, 0x1d, 0x00, 0x25, 0x00, 0x2b, +0x00, 0x2f, 0x00, 0x32, 0x00, 0x34, 0x00, 0x36, 0x00, 0x37, 0x00, 0x38, +0x00, 0x39, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0xaf, 0x00, 0x93, 0x00, 0x58, 0x00, 0x21, 0x00, 0x0e, 0x08, 0x02, 0x0e, +0x00, 0x18, 0x00, 0x20, 0x00, 0x27, 0x00, 0x2b, 0x00, 0x2f, 0x00, 0x31, +0x00, 0x33, 0x00, 0x35, 0x00, 0x36, 0x00, 0x38, 0xb2, 0x00, 0x9c, 0x00, +0x6d, 0x00, 0x3f, 0x00, 0x1d, 0x00, 0x05, 0x00, 0x00, 0x0b, 0x00, 0x16, +0x00, 0x1f, 0x00, 0x25, 0x00, 0x29, 0x00, 0x2d, 0x00, 0x30, 0x00, 0x32, +0x00, 0x33, 0x00, 0x35, 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0xda, 0x00, 0xd2, 0x00, +0xcb, 0x00, 0xc6, 0x00, 0xbe, 0x00, 0xb9, 0x00, 0xb2, 0x00, 0xac, 0x00, +0xa8, 0x00, 0xa1, 0x00, 0x9d, 0x00, 0x99, 0x00, 0x93, 0x01, 0x90, 0x02, +0x8d, 0x02, 0x89, 0x02, 0x85, 0x03, 0x83, 0x04, 0x81, 0x05, 0x7f, 0x06, +0x21, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x23, 0x23, 0x23, +0x23, 0x24, 0x24, 0x24, 0x24, 0x25, 0x24, 0x25, 0x25, 0x25, 0x25, 0x27, +0x25, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x29, 0x27, 0x28, 0x28, 0x28, +0x28, 0x28, 0x28, 0x29, 0x7f, 0x11, 0x7b, 0x13, 0x78, 0x15, 0x76, 0x15, +0x73, 0x18, 0x72, 0x18, 0x6f, 0x1a, 0x6d, 0x1a, 0x6d, 0x1c, 0x69, 0x1d, +0x69, 0x1d, 0x69, 0x1f, 0x65, 0x20, 0x65, 0x20, 0x65, 0x21, 0x64, 0x23, +0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x24, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x18, 0x00, 0x1f, +0x00, 0x25, 0x00, 0x2a, 0x00, 0x2d, 0x00, 0x30, 0x00, 0x32, 0x00, 0x34, +0x00, 0x35, 0x00, 0x37, 0x00, 0x48, 0x00, 0x41, 0x00, 0x2f, 0x00, 0x16, +0x00, 0x00, 0x00, 0x0d, 0x00, 0x18, 0x00, 0x1f, 0x00, 0x25, 0x00, 0x2a, +0x00, 0x2d, 0x00, 0x30, 0x00, 0x32, 0x00, 0x34, 0x00, 0x35, 0x00, 0x37, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb5, 0x00, 0xa4, 0x00, +0x7a, 0x00, 0x4a, 0x00, 0x20, 0x00, 0x12, 0x06, 0x07, 0x0c, 0x00, 0x10, +0x00, 0x18, 0x00, 0x1f, 0x00, 0x24, 0x00, 0x28, 0x00, 0x2c, 0x00, 0x2e, +0x00, 0x30, 0x00, 0x32, 0xb7, 0x00, 0xaa, 0x00, 0x88, 0x00, 0x62, 0x00, +0x3f, 0x00, 0x24, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x14, +0x00, 0x1b, 0x00, 0x21, 0x00, 0x25, 0x00, 0x29, 0x00, 0x2b, 0x00, 0x2e, +0x33, 0x22, 0x28, 0x22, 0x25, 0x22, 0x24, 0x22, 0x23, 0x22, 0x23, 0x22, +0x22, 0x22, 0x22, 0x21, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x21, +0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x22, 0x22, 0x21, 0x22, 0x21, +0x22, 0x21, 0x22, 0x21, 0x9d, 0x05, 0x6b, 0x0d, 0x51, 0x12, 0x45, 0x15, +0x3d, 0x17, 0x38, 0x18, 0x35, 0x1a, 0x32, 0x1b, 0x30, 0x1b, 0x2f, 0x1c, +0x2d, 0x1c, 0x2d, 0x1c, 0x2c, 0x1d, 0x2b, 0x1d, 0x2a, 0x1e, 0x2a, 0x1e, +0x29, 0x1e, 0x29, 0x1e, 0x28, 0x1e, 0x28, 0x1e, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x5f, 0x13, 0x46, 0x17, 0x39, 0x1a, 0x33, 0x1b, 0x2f, 0x1c, 0x2d, 0x1d, +0x2b, 0x1e, 0x2a, 0x1e, 0x29, 0x1e, 0x28, 0x1f, 0x27, 0x1f, 0x27, 0x1f, +0x27, 0x1f, 0x26, 0x1f, 0x26, 0x20, 0x26, 0x20, 0x25, 0x20, 0x25, 0x20, +0x25, 0x20, 0x25, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x14, 0x00, 0x1b, 0x00, 0x21, +0x00, 0x25, 0x00, 0x29, 0x00, 0x2c, 0x00, 0x2f, 0x00, 0x31, 0x00, 0x32, +0x00, 0x42, 0x00, 0x3d, 0x00, 0x2e, 0x00, 0x1d, 0x00, 0x0d, 0x00, 0x00, +0x00, 0x0b, 0x00, 0x14, 0x00, 0x1b, 0x00, 0x21, 0x00, 0x25, 0x00, 0x29, +0x00, 0x2c, 0x00, 0x2f, 0x00, 0x31, 0x00, 0x32, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0xb9, 0x00, 0xad, 0x00, 0x8f, 0x00, 0x68, 0x00, +0x42, 0x00, 0x20, 0x00, 0x14, 0x05, 0x0b, 0x0a, 0x04, 0x0d, 0x00, 0x12, +0x00, 0x19, 0x00, 0x1e, 0x00, 0x23, 0x00, 0x26, 0x00, 0x29, 0x00, 0x2c, +0xba, 0x00, 0xb1, 0x00, 0x99, 0x00, 0x7a, 0x00, 0x5b, 0x00, 0x3f, 0x00, +0x29, 0x00, 0x16, 0x00, 0x08, 0x00, 0x00, 0x02, 0x00, 0x0c, 0x00, 0x13, +0x00, 0x19, 0x00, 0x1e, 0x00, 0x22, 0x00, 0x25, 0x37, 0x28, 0x2d, 0x25, +0x28, 0x23, 0x26, 0x23, 0x25, 0x23, 0x24, 0x22, 0x24, 0x22, 0x23, 0x22, +0x23, 0x22, 0x23, 0x22, 0x23, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, +0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, +0xbc, 0x00, 0x8e, 0x01, 0x73, 0x04, 0x60, 0x08, 0x55, 0x0b, 0x4c, 0x0d, +0x47, 0x0f, 0x42, 0x11, 0x3e, 0x12, 0x3b, 0x13, 0x39, 0x14, 0x37, 0x15, +0x36, 0x16, 0x34, 0x16, 0x33, 0x17, 0x32, 0x18, 0x31, 0x18, 0x30, 0x19, +0x2f, 0x19, 0x2f, 0x19, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x6f, 0x11, 0x58, 0x11, +0x4a, 0x13, 0x41, 0x15, 0x3b, 0x16, 0x37, 0x17, 0x34, 0x18, 0x32, 0x19, +0x30, 0x1a, 0x2e, 0x1a, 0x2d, 0x1b, 0x2c, 0x1b, 0x2c, 0x1c, 0x2b, 0x1c, +0x2a, 0x1c, 0x2a, 0x1d, 0x29, 0x1d, 0x29, 0x1d, 0x28, 0x1d, 0x28, 0x1d, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x09, 0x00, 0x11, 0x00, 0x18, 0x00, 0x1d, 0x00, 0x22, +0x00, 0x26, 0x00, 0x29, 0x00, 0x2b, 0x00, 0x2d, 0x00, 0x3e, 0x00, 0x3a, +0x00, 0x31, 0x00, 0x25, 0x00, 0x18, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x09, +0x00, 0x11, 0x00, 0x18, 0x00, 0x1d, 0x00, 0x22, 0x00, 0x26, 0x00, 0x29, +0x00, 0x2b, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0xba, 0x00, 0xb2, 0x00, 0x9c, 0x00, 0x7d, 0x00, 0x5c, 0x00, 0x3c, 0x00, +0x20, 0x00, 0x16, 0x04, 0x0e, 0x08, 0x07, 0x0c, 0x02, 0x0e, 0x00, 0x13, +0x00, 0x19, 0x00, 0x1d, 0x00, 0x21, 0x00, 0x25, 0xbb, 0x00, 0xb5, 0x00, +0xa3, 0x00, 0x8a, 0x00, 0x6f, 0x00, 0x56, 0x00, 0x3f, 0x00, 0x2c, 0x00, +0x1c, 0x00, 0x0f, 0x00, 0x04, 0x00, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x12, +0x00, 0x17, 0x00, 0x1c, 0x38, 0x2c, 0x30, 0x28, 0x2b, 0x26, 0x29, 0x25, +0x27, 0x24, 0x26, 0x24, 0x25, 0x23, 0x24, 0x23, 0x24, 0x23, 0x24, 0x22, +0x23, 0x22, 0x23, 0x22, 0x23, 0x22, 0x23, 0x22, 0x23, 0x22, 0x23, 0x22, +0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0xc6, 0x00, 0xa4, 0x00, +0x89, 0x00, 0x77, 0x02, 0x67, 0x04, 0x5e, 0x06, 0x55, 0x08, 0x50, 0x0a, +0x4b, 0x0c, 0x47, 0x0d, 0x44, 0x0e, 0x41, 0x0f, 0x3e, 0x10, 0x3d, 0x11, +0x3b, 0x12, 0x39, 0x12, 0x38, 0x13, 0x37, 0x14, 0x35, 0x15, 0x35, 0x16, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x74, 0x11, 0x63, 0x11, 0x55, 0x11, 0x4c, 0x12, +0x44, 0x13, 0x40, 0x14, 0x3b, 0x15, 0x39, 0x16, 0x36, 0x17, 0x34, 0x17, +0x33, 0x18, 0x31, 0x18, 0x30, 0x19, 0x2f, 0x19, 0x2e, 0x1a, 0x2d, 0x1a, +0x2d, 0x1a, 0x2c, 0x1b, 0x2b, 0x1b, 0x2b, 0x1c, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x08, 0x00, 0x0f, 0x00, 0x15, 0x00, 0x1a, 0x00, 0x1f, 0x00, 0x22, +0x00, 0x26, 0x00, 0x28, 0x00, 0x3e, 0x00, 0x3c, 0x00, 0x35, 0x00, 0x2b, +0x00, 0x1f, 0x00, 0x14, 0x00, 0x09, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0f, +0x00, 0x15, 0x00, 0x1a, 0x00, 0x1f, 0x00, 0x22, 0x00, 0x26, 0x00, 0x28, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbc, 0x00, 0xb5, 0x00, +0xa4, 0x00, 0x8b, 0x00, 0x6f, 0x00, 0x52, 0x00, 0x37, 0x00, 0x20, 0x00, +0x17, 0x04, 0x10, 0x07, 0x0a, 0x0a, 0x05, 0x0d, 0x00, 0x0f, 0x00, 0x14, +0x00, 0x19, 0x00, 0x1d, 0xbc, 0x00, 0xb7, 0x00, 0xaa, 0x00, 0x96, 0x00, +0x7f, 0x00, 0x68, 0x00, 0x53, 0x00, 0x3f, 0x00, 0x2e, 0x00, 0x20, 0x00, +0x14, 0x00, 0x0a, 0x00, 0x01, 0x00, 0x00, 0x06, 0x00, 0x0c, 0x00, 0x11, +0x3a, 0x2f, 0x32, 0x2b, 0x2e, 0x28, 0x2b, 0x27, 0x28, 0x25, 0x27, 0x25, +0x27, 0x24, 0x25, 0x24, 0x25, 0x24, 0x24, 0x23, 0x24, 0x23, 0x24, 0x23, +0x24, 0x23, 0x23, 0x23, 0x23, 0x22, 0x23, 0x22, 0x23, 0x22, 0x23, 0x22, +0x23, 0x22, 0x23, 0x22, 0xcd, 0x00, 0xb0, 0x00, 0x9a, 0x00, 0x87, 0x00, +0x78, 0x01, 0x6c, 0x03, 0x64, 0x04, 0x5c, 0x05, 0x57, 0x07, 0x51, 0x09, +0x4e, 0x0a, 0x4a, 0x0b, 0x48, 0x0c, 0x45, 0x0c, 0x43, 0x0e, 0x40, 0x0f, +0x3f, 0x0f, 0x3d, 0x0f, 0x3c, 0x11, 0x3b, 0x12, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x77, 0x11, 0x69, 0x11, 0x5e, 0x11, 0x54, 0x11, 0x4d, 0x11, 0x47, 0x12, +0x43, 0x13, 0x3f, 0x13, 0x3c, 0x14, 0x39, 0x15, 0x38, 0x16, 0x36, 0x16, +0x35, 0x17, 0x33, 0x17, 0x32, 0x18, 0x31, 0x18, 0x30, 0x18, 0x2f, 0x18, +0x2f, 0x19, 0x2e, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, +0x00, 0x0d, 0x00, 0x13, 0x00, 0x18, 0x00, 0x1c, 0x00, 0x20, 0x00, 0x23, +0x00, 0x3e, 0x00, 0x3c, 0x00, 0x37, 0x00, 0x2f, 0x00, 0x25, 0x00, 0x1b, +0x00, 0x11, 0x00, 0x08, 0x00, 0x00, 0x00, 0x07, 0x00, 0x0d, 0x00, 0x13, +0x00, 0x18, 0x00, 0x1c, 0x00, 0x20, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0xbc, 0x00, 0xb8, 0x00, 0xaa, 0x00, 0x96, 0x00, +0x7e, 0x00, 0x64, 0x00, 0x4c, 0x00, 0x34, 0x00, 0x20, 0x00, 0x18, 0x03, +0x11, 0x06, 0x0c, 0x09, 0x07, 0x0c, 0x03, 0x0e, 0x00, 0x10, 0x00, 0x15, +0xbd, 0x00, 0xb9, 0x00, 0xae, 0x00, 0x9e, 0x00, 0x8b, 0x00, 0x77, 0x00, +0x63, 0x00, 0x50, 0x00, 0x3f, 0x00, 0x30, 0x00, 0x23, 0x00, 0x18, 0x00, +0x0e, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x07, 0x3b, 0x32, 0x34, 0x2d, +0x2f, 0x2a, 0x2c, 0x28, 0x2a, 0x27, 0x29, 0x26, 0x27, 0x25, 0x27, 0x25, +0x26, 0x24, 0x25, 0x24, 0x25, 0x24, 0x25, 0x24, 0x24, 0x23, 0x24, 0x23, +0x24, 0x23, 0x24, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x22, +0xcf, 0x00, 0xb9, 0x00, 0xa4, 0x00, 0x94, 0x00, 0x85, 0x00, 0x7a, 0x01, +0x70, 0x02, 0x68, 0x03, 0x61, 0x04, 0x5c, 0x05, 0x57, 0x07, 0x53, 0x07, +0x50, 0x09, 0x4c, 0x0a, 0x4a, 0x0a, 0x48, 0x0c, 0x45, 0x0c, 0x44, 0x0c, +0x42, 0x0d, 0x41, 0x0f, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x78, 0x11, 0x6d, 0x11, +0x63, 0x11, 0x5b, 0x11, 0x53, 0x11, 0x4e, 0x11, 0x49, 0x12, 0x45, 0x12, +0x41, 0x13, 0x3f, 0x13, 0x3c, 0x14, 0x3a, 0x14, 0x39, 0x15, 0x37, 0x16, +0x36, 0x16, 0x35, 0x17, 0x33, 0x17, 0x33, 0x17, 0x32, 0x17, 0x31, 0x18, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x0c, +0x00, 0x11, 0x00, 0x16, 0x00, 0x1a, 0x00, 0x1d, 0x00, 0x3e, 0x00, 0x3d, +0x00, 0x39, 0x00, 0x32, 0x00, 0x2a, 0x00, 0x21, 0x00, 0x18, 0x00, 0x0f, +0x00, 0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x0c, 0x00, 0x11, 0x00, 0x16, +0x00, 0x1a, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0xbd, 0x00, 0xb9, 0x00, 0xae, 0x00, 0x9d, 0x00, 0x89, 0x00, 0x73, 0x00, +0x5c, 0x00, 0x46, 0x00, 0x32, 0x00, 0x20, 0x00, 0x19, 0x03, 0x13, 0x06, +0x0e, 0x08, 0x09, 0x0b, 0x05, 0x0d, 0x01, 0x0e, 0xbd, 0x00, 0xba, 0x00, +0xb1, 0x00, 0xa4, 0x00, 0x94, 0x00, 0x82, 0x00, 0x70, 0x00, 0x5e, 0x00, +0x4e, 0x00, 0x3f, 0x00, 0x32, 0x00, 0x26, 0x00, 0x1c, 0x00, 0x13, 0x00, +0x0b, 0x00, 0x03, 0x00, 0x3c, 0x34, 0x35, 0x2f, 0x31, 0x2c, 0x2e, 0x2a, +0x2c, 0x28, 0x2a, 0x27, 0x28, 0x27, 0x28, 0x26, 0x27, 0x25, 0x27, 0x25, +0x25, 0x24, 0x25, 0x24, 0x25, 0x24, 0x25, 0x24, 0x24, 0x24, 0x24, 0x23, +0x24, 0x23, 0x24, 0x23, 0x24, 0x23, 0x23, 0x23, 0xd2, 0x00, 0xbe, 0x00, +0xad, 0x00, 0x9d, 0x00, 0x90, 0x00, 0x84, 0x00, 0x7a, 0x00, 0x72, 0x01, +0x6b, 0x02, 0x65, 0x04, 0x60, 0x04, 0x5b, 0x05, 0x58, 0x06, 0x54, 0x07, +0x51, 0x07, 0x4f, 0x09, 0x4c, 0x0a, 0x4a, 0x0a, 0x48, 0x0b, 0x46, 0x0c, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x7a, 0x11, 0x70, 0x11, 0x67, 0x11, 0x5f, 0x11, +0x59, 0x11, 0x53, 0x11, 0x4e, 0x11, 0x4a, 0x11, 0x46, 0x12, 0x43, 0x13, +0x41, 0x13, 0x3e, 0x13, 0x3d, 0x14, 0x3b, 0x14, 0x39, 0x14, 0x38, 0x15, +0x37, 0x16, 0x36, 0x16, 0x35, 0x16, 0x34, 0x17, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x0b, 0x00, 0x10, +0x00, 0x14, 0x00, 0x18, 0x00, 0x3f, 0x00, 0x3d, 0x00, 0x3a, 0x00, 0x34, +0x00, 0x2d, 0x00, 0x25, 0x00, 0x1d, 0x00, 0x15, 0x00, 0x0d, 0x00, 0x06, +0x00, 0x00, 0x00, 0x06, 0x00, 0x0b, 0x00, 0x10, 0x00, 0x14, 0x00, 0x18, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbd, 0x00, 0xba, 0x00, +0xb1, 0x00, 0xa3, 0x00, 0x92, 0x00, 0x7e, 0x00, 0x6a, 0x00, 0x56, 0x00, +0x42, 0x00, 0x30, 0x00, 0x1f, 0x00, 0x19, 0x03, 0x14, 0x05, 0x0f, 0x08, +0x0b, 0x0a, 0x07, 0x0c, 0xbd, 0x00, 0xbb, 0x00, 0xb4, 0x00, 0xa9, 0x00, +0x9b, 0x00, 0x8b, 0x00, 0x7b, 0x00, 0x6b, 0x00, 0x5b, 0x00, 0x4d, 0x00, +0x3f, 0x00, 0x33, 0x00, 0x28, 0x00, 0x1f, 0x00, 0x16, 0x00, 0x0e, 0x00, +0x3c, 0x35, 0x36, 0x31, 0x32, 0x2e, 0x2f, 0x2b, 0x2d, 0x2a, 0x2b, 0x28, +0x2a, 0x28, 0x28, 0x27, 0x28, 0x27, 0x27, 0x25, 0x27, 0x25, 0x26, 0x25, +0x25, 0x25, 0x25, 0x24, 0x25, 0x24, 0x25, 0x24, 0x24, 0x24, 0x24, 0x24, +0x24, 0x23, 0x24, 0x23, 0xd3, 0x00, 0xc2, 0x00, 0xb2, 0x00, 0xa4, 0x00, +0x98, 0x00, 0x8d, 0x00, 0x83, 0x00, 0x7b, 0x00, 0x73, 0x01, 0x6e, 0x02, +0x67, 0x02, 0x63, 0x04, 0x5f, 0x04, 0x5b, 0x05, 0x58, 0x05, 0x55, 0x07, +0x52, 0x07, 0x50, 0x07, 0x4e, 0x09, 0x4c, 0x0a, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x7a, 0x11, 0x72, 0x11, 0x6a, 0x11, 0x63, 0x11, 0x5d, 0x11, 0x57, 0x11, +0x52, 0x11, 0x4e, 0x11, 0x4a, 0x11, 0x48, 0x12, 0x44, 0x12, 0x42, 0x13, +0x40, 0x13, 0x3e, 0x13, 0x3d, 0x13, 0x3b, 0x14, 0x3a, 0x14, 0x39, 0x14, +0x38, 0x15, 0x37, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x0a, 0x00, 0x0f, 0x00, 0x13, +0x00, 0x3f, 0x00, 0x3e, 0x00, 0x3b, 0x00, 0x36, 0x00, 0x30, 0x00, 0x29, +0x00, 0x22, 0x00, 0x1a, 0x00, 0x13, 0x00, 0x0c, 0x00, 0x06, 0x00, 0x00, +0x00, 0x05, 0x00, 0x0a, 0x00, 0x0f, 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0xbd, 0x00, 0xbb, 0x00, 0xb3, 0x00, 0xa8, 0x00, +0x99, 0x00, 0x87, 0x00, 0x75, 0x00, 0x62, 0x00, 0x50, 0x00, 0x3f, 0x00, +0x2e, 0x00, 0x1f, 0x00, 0x1a, 0x02, 0x15, 0x05, 0x10, 0x07, 0x0c, 0x09, +0xbe, 0x00, 0xbc, 0x00, 0xb6, 0x00, 0xac, 0x00, 0xa0, 0x00, 0x93, 0x00, +0x84, 0x00, 0x75, 0x00, 0x66, 0x00, 0x58, 0x00, 0x4b, 0x00, 0x3f, 0x00, +0x34, 0x00, 0x2a, 0x00, 0x21, 0x00, 0x19, 0x00, 0x3c, 0x36, 0x37, 0x32, +0x33, 0x2f, 0x30, 0x2d, 0x2e, 0x2b, 0x2d, 0x2a, 0x2b, 0x28, 0x2a, 0x28, +0x28, 0x27, 0x28, 0x27, 0x27, 0x26, 0x27, 0x25, 0x27, 0x25, 0x26, 0x25, +0x25, 0x25, 0x25, 0x24, 0x25, 0x24, 0x25, 0x24, 0x24, 0x24, 0x24, 0x24, +0xd5, 0x00, 0xc5, 0x00, 0xb7, 0x00, 0xaa, 0x00, 0x9f, 0x00, 0x95, 0x00, +0x8b, 0x00, 0x83, 0x00, 0x7c, 0x00, 0x75, 0x01, 0x6f, 0x01, 0x69, 0x02, +0x66, 0x02, 0x61, 0x04, 0x5e, 0x04, 0x5a, 0x05, 0x58, 0x05, 0x55, 0x06, +0x53, 0x07, 0x51, 0x07, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x7b, 0x11, 0x73, 0x11, +0x6c, 0x11, 0x66, 0x11, 0x60, 0x11, 0x5b, 0x11, 0x56, 0x11, 0x52, 0x11, +0x4f, 0x11, 0x4b, 0x11, 0x48, 0x11, 0x45, 0x12, 0x44, 0x12, 0x41, 0x13, +0x40, 0x13, 0x3e, 0x13, 0x3d, 0x13, 0x3b, 0x14, 0x3a, 0x14, 0x39, 0x14, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x05, 0x00, 0x09, 0x00, 0x0d, 0x00, 0x3f, 0x00, 0x3e, +0x00, 0x3b, 0x00, 0x37, 0x00, 0x32, 0x00, 0x2c, 0x00, 0x26, 0x00, 0x1f, +0x00, 0x18, 0x00, 0x11, 0x00, 0x0b, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, +0x00, 0x09, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0xbe, 0x00, 0xbb, 0x00, 0xb5, 0x00, 0xab, 0x00, 0x9e, 0x00, 0x8f, 0x00, +0x7e, 0x00, 0x6d, 0x00, 0x5c, 0x00, 0x4c, 0x00, 0x3c, 0x00, 0x2d, 0x00, +0x1f, 0x00, 0x1a, 0x02, 0x16, 0x04, 0x11, 0x06, 0xbe, 0x00, 0xbc, 0x00, +0xb7, 0x00, 0xaf, 0x00, 0xa5, 0x00, 0x99, 0x00, 0x8b, 0x00, 0x7e, 0x00, +0x70, 0x00, 0x63, 0x00, 0x56, 0x00, 0x4a, 0x00, 0x3f, 0x00, 0x35, 0x00, +0x2c, 0x00, 0x23, 0x00, 0x3c, 0x37, 0x38, 0x33, 0x34, 0x30, 0x31, 0x2e, +0x2f, 0x2c, 0x2d, 0x2a, 0x2c, 0x2a, 0x2b, 0x28, 0x2a, 0x28, 0x28, 0x27, +0x28, 0x27, 0x27, 0x27, 0x27, 0x26, 0x27, 0x25, 0x27, 0x25, 0x25, 0x25, +0x25, 0x25, 0x25, 0x24, 0x25, 0x24, 0x25, 0x24, 0xd5, 0x00, 0xc8, 0x00, +0xbb, 0x00, 0xaf, 0x00, 0xa5, 0x00, 0x9b, 0x00, 0x92, 0x00, 0x8a, 0x00, +0x82, 0x00, 0x7c, 0x00, 0x76, 0x00, 0x70, 0x01, 0x6c, 0x02, 0x67, 0x02, +0x64, 0x03, 0x60, 0x04, 0x5d, 0x04, 0x5b, 0x05, 0x58, 0x05, 0x55, 0x05, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x7b, 0x11, 0x75, 0x11, 0x6e, 0x11, 0x68, 0x11, +0x63, 0x11, 0x5e, 0x11, 0x5a, 0x11, 0x56, 0x11, 0x52, 0x11, 0x4f, 0x11, +0x4c, 0x11, 0x49, 0x11, 0x47, 0x12, 0x44, 0x12, 0x43, 0x12, 0x41, 0x13, +0x3f, 0x13, 0x3e, 0x13, 0x3d, 0x13, 0x3b, 0x13, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x04, 0x00, 0x09, 0x00, 0x3f, 0x00, 0x3e, 0x00, 0x3c, 0x00, 0x38, +0x00, 0x34, 0x00, 0x2f, 0x00, 0x29, 0x00, 0x22, 0x00, 0x1c, 0x00, 0x16, +0x00, 0x10, 0x00, 0x0a, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x09, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x00, 0xbc, 0x00, +0xb7, 0x00, 0xae, 0x00, 0xa2, 0x00, 0x95, 0x00, 0x86, 0x00, 0x77, 0x00, +0x67, 0x00, 0x57, 0x00, 0x48, 0x00, 0x3a, 0x00, 0x2c, 0x00, 0x1f, 0x00, +0x1b, 0x02, 0x16, 0x04, 0xbe, 0x00, 0xbd, 0x00, 0xb8, 0x00, 0xb1, 0x00, +0xa8, 0x00, 0x9d, 0x00, 0x92, 0x00, 0x85, 0x00, 0x78, 0x00, 0x6c, 0x00, +0x60, 0x00, 0x54, 0x00, 0x49, 0x00, 0x3f, 0x00, 0x36, 0x00, 0x2d, 0x00, +0x3d, 0x38, 0x38, 0x34, 0x35, 0x31, 0x33, 0x2f, 0x30, 0x2d, 0x2e, 0x2c, +0x2d, 0x2b, 0x2b, 0x2a, 0x2b, 0x28, 0x2a, 0x28, 0x28, 0x27, 0x28, 0x27, +0x28, 0x27, 0x27, 0x27, 0x27, 0x25, 0x27, 0x25, 0x26, 0x25, 0x25, 0x25, +0x25, 0x25, 0x25, 0x24, 0xd6, 0x00, 0xca, 0x00, 0xbe, 0x00, 0xb3, 0x00, +0xaa, 0x00, 0xa0, 0x00, 0x98, 0x00, 0x90, 0x00, 0x88, 0x00, 0x82, 0x00, +0x7d, 0x00, 0x77, 0x00, 0x71, 0x01, 0x6d, 0x01, 0x69, 0x02, 0x66, 0x02, +0x63, 0x04, 0x60, 0x04, 0x5d, 0x04, 0x5b, 0x05, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x7c, 0x11, 0x76, 0x11, 0x70, 0x11, 0x6a, 0x11, 0x66, 0x11, 0x61, 0x11, +0x5d, 0x11, 0x59, 0x11, 0x55, 0x11, 0x52, 0x11, 0x4f, 0x11, 0x4c, 0x11, +0x49, 0x11, 0x47, 0x11, 0x45, 0x12, 0x44, 0x12, 0x42, 0x13, 0x41, 0x13, +0x3f, 0x13, 0x3e, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, +0x00, 0x3f, 0x00, 0x3e, 0x00, 0x3c, 0x00, 0x39, 0x00, 0x35, 0x00, 0x31, +0x00, 0x2b, 0x00, 0x26, 0x00, 0x20, 0x00, 0x1a, 0x00, 0x14, 0x00, 0x0f, +0x00, 0x09, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0xbe, 0x00, 0xbc, 0x00, 0xb8, 0x00, 0xb0, 0x00, +0xa6, 0x00, 0x9a, 0x00, 0x8d, 0x00, 0x7f, 0x00, 0x70, 0x00, 0x61, 0x00, +0x53, 0x00, 0x45, 0x00, 0x38, 0x00, 0x2b, 0x00, 0x1f, 0x00, 0x1b, 0x02, +0xbe, 0x00, 0xbd, 0x00, 0xb9, 0x00, 0xb3, 0x00, 0xab, 0x00, 0xa1, 0x00, +0x97, 0x00, 0x8b, 0x00, 0x80, 0x00, 0x74, 0x00, 0x68, 0x00, 0x5d, 0x00, +0x53, 0x00, 0x49, 0x00, 0x3f, 0x00, 0x36, 0x00, 0x3d, 0x38, 0x39, 0x35, +0x36, 0x32, 0x33, 0x30, 0x31, 0x2e, 0x30, 0x2d, 0x2d, 0x2b, 0x2d, 0x2b, +0x2b, 0x2a, 0x2b, 0x28, 0x2a, 0x28, 0x28, 0x28, 0x28, 0x26, 0x28, 0x27, +0x27, 0x27, 0x27, 0x26, 0x27, 0x25, 0x27, 0x25, 0x26, 0x25, 0x25, 0x25, +0xd6, 0x00, 0xcc, 0x00, 0xc0, 0x00, 0xb7, 0x00, 0xad, 0x00, 0xa5, 0x00, +0x9d, 0x00, 0x96, 0x00, 0x8f, 0x00, 0x88, 0x00, 0x81, 0x00, 0x7d, 0x00, +0x77, 0x00, 0x73, 0x01, 0x6f, 0x01, 0x6b, 0x02, 0x67, 0x02, 0x64, 0x02, +0x62, 0x04, 0x5f, 0x04, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x7c, 0x11, 0x77, 0x11, +0x71, 0x11, 0x6c, 0x11, 0x67, 0x11, 0x63, 0x11, 0x5f, 0x11, 0x5c, 0x11, +0x58, 0x11, 0x55, 0x11, 0x51, 0x11, 0x4f, 0x11, 0x4c, 0x11, 0x4a, 0x11, +0x48, 0x11, 0x46, 0x12, 0x44, 0x12, 0x43, 0x12, 0x42, 0x13, 0x40, 0x13, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x3e, +0x00, 0x3d, 0x00, 0x3a, 0x00, 0x37, 0x00, 0x32, 0x00, 0x2d, 0x00, 0x28, +0x00, 0x23, 0x00, 0x1d, 0x00, 0x18, 0x00, 0x13, 0x00, 0x0d, 0x00, 0x09, +0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0xbe, 0x00, 0xbd, 0x00, 0xb9, 0x00, 0xb2, 0x00, 0xa9, 0x00, 0x9e, 0x00, +0x92, 0x00, 0x85, 0x00, 0x78, 0x00, 0x6a, 0x00, 0x5c, 0x00, 0x4f, 0x00, +0x42, 0x00, 0x36, 0x00, 0x2a, 0x00, 0x1f, 0x00, 0xbe, 0x00, 0xbd, 0x00, +0xba, 0x00, 0xb4, 0x00, 0xad, 0x00, 0xa5, 0x00, 0x9b, 0x00, 0x91, 0x00, +0x86, 0x00, 0x7b, 0x00, 0x70, 0x00, 0x65, 0x00, 0x5b, 0x00, 0x51, 0x00, +0x48, 0x00, 0x3f, 0x00, 0x3d, 0x39, 0x39, 0x36, 0x36, 0x33, 0x33, 0x30, +0x32, 0x2f, 0x30, 0x2d, 0x2e, 0x2d, 0x2d, 0x2a, 0x2c, 0x2b, 0x2b, 0x29, +0x2b, 0x28, 0x29, 0x28, 0x28, 0x28, 0x28, 0x26, 0x28, 0x27, 0x27, 0x27, +0x27, 0x27, 0x27, 0x26, 0x27, 0x25, 0x27, 0x25, 0xd7, 0x00, 0xcc, 0x00, +0xc3, 0x00, 0xba, 0x00, 0xb1, 0x00, 0xa8, 0x00, 0xa0, 0x00, 0x99, 0x00, +0x93, 0x00, 0x8d, 0x00, 0x87, 0x00, 0x81, 0x00, 0x7d, 0x00, 0x78, 0x00, +0x74, 0x00, 0x70, 0x01, 0x6c, 0x01, 0x69, 0x02, 0x66, 0x02, 0x63, 0x02, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x7c, 0x11, 0x77, 0x11, 0x72, 0x11, 0x6e, 0x11, +0x69, 0x11, 0x65, 0x11, 0x61, 0x11, 0x5d, 0x11, 0x5a, 0x11, 0x57, 0x11, +0x54, 0x11, 0x51, 0x11, 0x4f, 0x11, 0x4d, 0x11, 0x4b, 0x11, 0x49, 0x11, +0x47, 0x11, 0x45, 0x12, 0x44, 0x12, 0x42, 0x12, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x3d, 0x39, 0x39, 0x36, 0x36, 0x33, 0x34, 0x32, 0x33, 0x30, 0x30, 0x2e, +0x30, 0x2d, 0x2d, 0x2c, 0x2d, 0x2b, 0x2b, 0x2b, 0x2b, 0x29, 0x2b, 0x28, +0x29, 0x28, 0x28, 0x28, 0x28, 0x27, 0x29, 0x27, 0x27, 0x27, 0x27, 0x27, +0x27, 0x27, 0x27, 0x25, 0xd7, 0x00, 0xce, 0x00, 0xc5, 0x00, 0xbc, 0x00, +0xb4, 0x00, 0xac, 0x00, 0xa5, 0x00, 0x9e, 0x00, 0x97, 0x00, 0x91, 0x00, +0x8c, 0x00, 0x87, 0x00, 0x81, 0x00, 0x7d, 0x00, 0x78, 0x00, 0x75, 0x00, +0x71, 0x01, 0x6d, 0x01, 0x6b, 0x02, 0x68, 0x02, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x7c, 0x11, 0x78, 0x11, 0x73, 0x11, 0x6f, 0x11, 0x6b, 0x11, 0x67, 0x11, +0x63, 0x11, 0x60, 0x11, 0x5c, 0x11, 0x59, 0x11, 0x57, 0x11, 0x54, 0x11, +0x51, 0x11, 0x4f, 0x11, 0x4d, 0x11, 0x4b, 0x11, 0x49, 0x11, 0x47, 0x11, +0x46, 0x12, 0x45, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3d, 0x39, 0x3a, 0x36, +0x37, 0x34, 0x35, 0x33, 0x33, 0x30, 0x31, 0x30, 0x30, 0x2d, 0x2e, 0x2d, +0x2d, 0x2b, 0x2d, 0x2b, 0x2b, 0x2b, 0x2b, 0x29, 0x2b, 0x28, 0x29, 0x28, +0x28, 0x28, 0x28, 0x27, 0x28, 0x27, 0x28, 0x27, 0x27, 0x27, 0x27, 0x27, +0xd8, 0x00, 0xcf, 0x00, 0xc6, 0x00, 0xbe, 0x00, 0xb6, 0x00, 0xaf, 0x00, +0xa8, 0x00, 0xa1, 0x00, 0x9c, 0x00, 0x96, 0x00, 0x90, 0x00, 0x8a, 0x00, +0x86, 0x00, 0x81, 0x00, 0x7d, 0x00, 0x79, 0x00, 0x75, 0x00, 0x72, 0x01, +0x6f, 0x01, 0x6b, 0x01, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x7d, 0x11, 0x78, 0x11, +0x74, 0x11, 0x70, 0x11, 0x6c, 0x11, 0x68, 0x11, 0x65, 0x11, 0x61, 0x11, +0x5f, 0x11, 0x5c, 0x11, 0x59, 0x11, 0x56, 0x11, 0x54, 0x11, 0x51, 0x11, +0x4f, 0x11, 0x4d, 0x11, 0x4b, 0x11, 0x4a, 0x11, 0x48, 0x11, 0x46, 0x11, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x3d, 0x3a, 0x3a, 0x37, 0x38, 0x35, 0x36, 0x33, +0x33, 0x31, 0x32, 0x30, 0x30, 0x2e, 0x30, 0x2d, 0x2d, 0x2d, 0x2d, 0x2b, +0x2c, 0x2b, 0x2b, 0x2b, 0x2b, 0x29, 0x2b, 0x28, 0x29, 0x28, 0x28, 0x28, +0x28, 0x27, 0x28, 0x26, 0x28, 0x27, 0x27, 0x27, 0xd8, 0x00, 0xd0, 0x00, +0xc8, 0x00, 0xc0, 0x00, 0xb9, 0x00, 0xb2, 0x00, 0xab, 0x00, 0xa5, 0x00, +0x9f, 0x00, 0x99, 0x00, 0x94, 0x00, 0x8f, 0x00, 0x8a, 0x00, 0x86, 0x00, +0x81, 0x00, 0x7d, 0x00, 0x79, 0x00, 0x76, 0x00, 0x73, 0x00, 0x70, 0x01, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x7d, 0x11, 0x79, 0x11, 0x75, 0x11, 0x71, 0x11, +0x6d, 0x11, 0x6a, 0x11, 0x66, 0x11, 0x63, 0x11, 0x60, 0x11, 0x5d, 0x11, +0x5b, 0x11, 0x58, 0x11, 0x56, 0x11, 0x54, 0x11, 0x51, 0x11, 0x4f, 0x11, +0x4d, 0x11, 0x4c, 0x11, 0x4a, 0x11, 0x49, 0x11, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x3d, 0x3a, 0x3a, 0x37, 0x38, 0x36, 0x36, 0x33, 0x33, 0x32, 0x33, 0x30, +0x30, 0x30, 0x30, 0x2d, 0x2f, 0x2d, 0x2d, 0x2c, 0x2d, 0x2b, 0x2c, 0x2b, +0x2b, 0x2b, 0x2b, 0x29, 0x2b, 0x28, 0x29, 0x28, 0x28, 0x28, 0x28, 0x28, +0x28, 0x27, 0x29, 0x27, 0xd9, 0x00, 0xd1, 0x00, 0xc9, 0x00, 0xc2, 0x00, +0xbb, 0x00, 0xb4, 0x00, 0xae, 0x00, 0xa8, 0x00, 0xa2, 0x00, 0x9c, 0x00, +0x97, 0x00, 0x92, 0x00, 0x8e, 0x00, 0x89, 0x00, 0x85, 0x00, 0x81, 0x00, +0x7d, 0x00, 0x7a, 0x00, 0x76, 0x00, 0x73, 0x00, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x7d, 0x11, 0x79, 0x11, 0x75, 0x11, 0x72, 0x11, 0x6e, 0x11, 0x6b, 0x11, +0x68, 0x11, 0x65, 0x11, 0x62, 0x11, 0x5f, 0x11, 0x5c, 0x11, 0x5a, 0x11, +0x58, 0x11, 0x55, 0x11, 0x53, 0x11, 0x51, 0x11, 0x4f, 0x11, 0x4e, 0x11, +0x4c, 0x11, 0x4a, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3d, 0x3a, 0x3b, 0x38, +0x39, 0x36, 0x36, 0x33, 0x34, 0x33, 0x33, 0x30, 0x32, 0x30, 0x30, 0x2e, +0x30, 0x2d, 0x2d, 0x2d, 0x2d, 0x2c, 0x2d, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, +0x2b, 0x29, 0x2b, 0x28, 0x29, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x27, +0xd9, 0x00, 0xd1, 0x00, 0xca, 0x00, 0xc3, 0x00, 0xbc, 0x00, 0xb6, 0x00, +0xb0, 0x00, 0xaa, 0x00, 0xa5, 0x00, 0xa0, 0x00, 0x9a, 0x00, 0x96, 0x00, +0x91, 0x00, 0x8d, 0x00, 0x89, 0x00, 0x84, 0x00, 0x81, 0x00, 0x7d, 0x00, +0x7a, 0x00, 0x77, 0x00, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x7d, 0x11, 0x79, 0x11, +0x76, 0x11, 0x72, 0x11, 0x6f, 0x11, 0x6c, 0x11, 0x69, 0x11, 0x66, 0x11, +0x63, 0x11, 0x61, 0x11, 0x5e, 0x11, 0x5c, 0x11, 0x59, 0x11, 0x57, 0x11, +0x55, 0x11, 0x53, 0x11, 0x51, 0x11, 0x4f, 0x11, 0x4e, 0x11, 0x4c, 0x11, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x3d, 0x3a, 0x3b, 0x39, 0x39, 0x36, 0x36, 0x34, +0x35, 0x33, 0x33, 0x31, 0x33, 0x30, 0x30, 0x30, 0x30, 0x2d, 0x2f, 0x2d, +0x2d, 0x2d, 0x2d, 0x2b, 0x2d, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x29, +0x2b, 0x28, 0x29, 0x28, 0x28, 0x28, 0x28, 0x28, 0xd9, 0x00, 0xd2, 0x00, +0xcb, 0x00, 0xc4, 0x00, 0xbe, 0x00, 0xb8, 0x00, 0xb2, 0x00, 0xad, 0x00, +0xa8, 0x00, 0xa2, 0x00, 0x9d, 0x00, 0x99, 0x00, 0x94, 0x00, 0x90, 0x00, +0x8b, 0x00, 0x88, 0x00, 0x84, 0x00, 0x81, 0x00, 0x7d, 0x00, 0x7b, 0x00, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x7d, 0x11, 0x7a, 0x11, 0x76, 0x11, 0x73, 0x11, +0x70, 0x11, 0x6d, 0x11, 0x6a, 0x11, 0x67, 0x11, 0x65, 0x11, 0x62, 0x11, +0x5f, 0x11, 0x5d, 0x11, 0x5b, 0x11, 0x59, 0x11, 0x56, 0x11, 0x55, 0x11, +0x53, 0x11, 0x51, 0x11, 0x4f, 0x11, 0x4e, 0x11, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x3d, 0x3b, 0x3b, 0x39, 0x3a, 0x36, 0x36, 0x35, 0x36, 0x33, 0x33, 0x32, +0x33, 0x30, 0x31, 0x30, 0x30, 0x2f, 0x30, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, +0x2d, 0x2b, 0x2c, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x28, 0x2b, 0x28, +0x28, 0x28, 0x28, 0x28, 0xd9, 0x00, 0xd3, 0x00, 0xcc, 0x00, 0xc6, 0x00, +0xc0, 0x00, 0xba, 0x00, 0xb4, 0x00, 0xaf, 0x00, 0xaa, 0x00, 0xa5, 0x00, +0xa0, 0x00, 0x9b, 0x00, 0x97, 0x00, 0x93, 0x00, 0x8f, 0x00, 0x8b, 0x00, +0x88, 0x00, 0x83, 0x00, 0x81, 0x00, 0x7d, 0x00, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x7d, 0x11, 0x7a, 0x11, 0x77, 0x11, 0x74, 0x11, 0x71, 0x11, 0x6e, 0x11, +0x6b, 0x11, 0x68, 0x11, 0x66, 0x11, 0x63, 0x11, 0x61, 0x11, 0x5e, 0x11, +0x5c, 0x11, 0x5a, 0x11, 0x58, 0x11, 0x56, 0x11, 0x55, 0x11, 0x52, 0x11, +0x51, 0x11, 0x4f, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3d, 0x3b, 0x3b, 0x39, +0x39, 0x36, 0x37, 0x36, 0x36, 0x33, 0x34, 0x33, 0x33, 0x31, 0x32, 0x30, +0x30, 0x30, 0x30, 0x2d, 0x2f, 0x2d, 0x2d, 0x2d, 0x2d, 0x2c, 0x2d, 0x2b, +0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2a, 0x2b, 0x28, 0x2a, 0x28, 0x28, 0x28, +0xd9, 0x00, 0xd3, 0x00, 0xcd, 0x00, 0xc7, 0x00, 0xc1, 0x00, 0xbc, 0x00, +0xb7, 0x00, 0xb0, 0x00, 0xac, 0x00, 0xa7, 0x00, 0xa2, 0x00, 0x9e, 0x00, +0x9a, 0x00, 0x95, 0x00, 0x93, 0x00, 0x8e, 0x00, 0x8b, 0x00, 0x87, 0x00, +0x83, 0x00, 0x81, 0x00, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x7d, 0x11, 0x7a, 0x11, +0x77, 0x11, 0x74, 0x11, 0x71, 0x11, 0x6f, 0x11, 0x6c, 0x11, 0x69, 0x11, +0x67, 0x11, 0x64, 0x11, 0x62, 0x11, 0x60, 0x11, 0x5e, 0x11, 0x5b, 0x11, +0x5a, 0x11, 0x58, 0x11, 0x56, 0x11, 0x54, 0x11, 0x52, 0x11, 0x51, 0x11, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x98, 0x00, 0xb8, 0x00, 0xc5, 0x00, 0xcb, 0x00, +0xcf, 0x00, 0xd1, 0x00, 0xd3, 0x00, 0xd4, 0x00, 0xd5, 0x00, 0xd6, 0x00, +0xd6, 0x00, 0xd7, 0x00, 0xd8, 0x00, 0xd8, 0x00, 0xd8, 0x00, 0xd9, 0x00, +0xd9, 0x00, 0xd9, 0x00, 0xd9, 0x00, 0xda, 0x00, 0xdd, 0x00, 0xdd, 0x00, +0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, +0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, +0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, +0x44, 0x00, 0x9d, 0x00, 0xbc, 0x00, 0xc6, 0x00, 0xcd, 0x00, 0xcf, 0x00, +0xd2, 0x00, 0xd3, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0xd6, 0x00, 0xd6, 0x00, +0xd7, 0x00, 0xd7, 0x00, 0xd8, 0x00, 0xd8, 0x00, 0xd9, 0x00, 0xd9, 0x00, +0xd9, 0x00, 0xd9, 0x00, 0x90, 0x00, 0xbd, 0x00, 0xcc, 0x00, 0xd1, 0x00, +0xd5, 0x00, 0xd6, 0x00, 0xd7, 0x00, 0xd8, 0x00, 0xd9, 0x00, 0xd9, 0x00, +0xd9, 0x00, 0xd9, 0x00, 0xda, 0x00, 0xda, 0x00, 0xda, 0x00, 0xda, 0x00, +0xdb, 0x00, 0xdb, 0x00, 0xdb, 0x00, 0xdb, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x68, 0x01, 0x8b, 0x00, 0xa0, 0x00, 0xad, 0x00, 0xb6, 0x00, 0xbc, 0x00, +0xc1, 0x00, 0xc4, 0x00, 0xc7, 0x00, 0xc9, 0x00, 0xcb, 0x00, 0xcc, 0x00, +0xcd, 0x00, 0xcf, 0x00, 0xd0, 0x00, 0xd1, 0x00, 0xd2, 0x00, 0xd2, 0x00, +0xd2, 0x00, 0xd3, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, +0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, +0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, +0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0x25, 0x05, 0x6b, 0x00, +0x8e, 0x00, 0xa4, 0x00, 0xb0, 0x00, 0xb9, 0x00, 0xbe, 0x00, 0xc2, 0x00, +0xc5, 0x00, 0xc8, 0x00, 0xca, 0x00, 0xcc, 0x00, 0xcc, 0x00, 0xce, 0x00, +0xcf, 0x00, 0xd0, 0x00, 0xd1, 0x00, 0xd1, 0x00, 0xd2, 0x00, 0xd3, 0x00, +0x81, 0x02, 0xa4, 0x00, 0xb5, 0x00, 0xc0, 0x00, 0xc6, 0x00, 0xcb, 0x00, +0xcd, 0x00, 0xcf, 0x00, 0xd1, 0x00, 0xd2, 0x00, 0xd3, 0x00, 0xd4, 0x00, +0xd4, 0x00, 0xd5, 0x00, 0xd6, 0x00, 0xd6, 0x00, 0xd7, 0x00, 0xd7, 0x00, +0xd7, 0x00, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x56, 0x09, 0x72, 0x02, +0x87, 0x00, 0x96, 0x00, 0xa0, 0x00, 0xa9, 0x00, 0xb0, 0x00, 0xb5, 0x00, +0xb9, 0x00, 0xbd, 0x00, 0xbf, 0x00, 0xc2, 0x00, 0xc4, 0x00, 0xc6, 0x00, +0xc7, 0x00, 0xc9, 0x00, 0xca, 0x00, 0xca, 0x00, 0xcb, 0x00, 0xcc, 0x00, +0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, +0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, +0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, +0xdd, 0x00, 0xdd, 0x00, 0x23, 0x0d, 0x51, 0x01, 0x73, 0x00, 0x89, 0x00, +0x9a, 0x00, 0xa4, 0x00, 0xad, 0x00, 0xb2, 0x00, 0xb7, 0x00, 0xbb, 0x00, +0xbe, 0x00, 0xc0, 0x00, 0xc3, 0x00, 0xc5, 0x00, 0xc6, 0x00, 0xc8, 0x00, +0xc9, 0x00, 0xca, 0x00, 0xcb, 0x00, 0xcc, 0x00, 0x80, 0x06, 0x97, 0x00, +0xa8, 0x00, 0xb3, 0x00, 0xbb, 0x00, 0xc0, 0x00, 0xc5, 0x00, 0xc7, 0x00, +0xca, 0x00, 0xcc, 0x00, 0xcd, 0x00, 0xce, 0x00, 0xd0, 0x00, 0xd1, 0x00, +0xd1, 0x00, 0xd2, 0x00, 0xd3, 0x00, 0xd3, 0x00, 0xd4, 0x00, 0xd4, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x4f, 0x11, 0x65, 0x07, 0x76, 0x03, 0x84, 0x01, +0x8f, 0x00, 0x99, 0x00, 0xa1, 0x00, 0xa7, 0x00, 0xad, 0x00, 0xb1, 0x00, +0xb4, 0x00, 0xb8, 0x00, 0xbb, 0x00, 0xbd, 0x00, 0xbe, 0x00, 0xc0, 0x00, +0xc2, 0x00, 0xc4, 0x00, 0xc6, 0x00, 0xc7, 0x00, 0xdd, 0x00, 0xdd, 0x00, +0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, +0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, +0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, +0x22, 0x12, 0x45, 0x04, 0x60, 0x00, 0x77, 0x00, 0x87, 0x00, 0x94, 0x00, +0x9d, 0x00, 0xa4, 0x00, 0xaa, 0x00, 0xaf, 0x00, 0xb3, 0x00, 0xb7, 0x00, +0xba, 0x00, 0xbc, 0x00, 0xbe, 0x00, 0xc0, 0x00, 0xc2, 0x00, 0xc3, 0x00, +0xc4, 0x00, 0xc6, 0x00, 0x7f, 0x09, 0x91, 0x02, 0x9e, 0x00, 0xaa, 0x00, +0xb2, 0x00, 0xb8, 0x00, 0xbd, 0x00, 0xc0, 0x00, 0xc3, 0x00, 0xc6, 0x00, +0xc8, 0x00, 0xca, 0x00, 0xcb, 0x00, 0xcc, 0x00, 0xcd, 0x00, 0xce, 0x00, +0xcf, 0x00, 0xd0, 0x00, 0xd0, 0x00, 0xd1, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x4b, 0x17, 0x5d, 0x0c, 0x6c, 0x06, 0x78, 0x03, 0x83, 0x01, 0x8c, 0x00, +0x94, 0x00, 0x9b, 0x00, 0xa1, 0x00, 0xa6, 0x00, 0xaa, 0x00, 0xae, 0x00, +0xb1, 0x00, 0xb4, 0x00, 0xb7, 0x00, 0xba, 0x00, 0xbb, 0x00, 0xbd, 0x00, +0xbe, 0x00, 0xbf, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, +0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, +0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, +0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0x22, 0x15, 0x3d, 0x08, +0x55, 0x02, 0x67, 0x00, 0x78, 0x00, 0x85, 0x00, 0x90, 0x00, 0x98, 0x00, +0x9f, 0x00, 0xa5, 0x00, 0xaa, 0x00, 0xad, 0x00, 0xb1, 0x00, 0xb4, 0x00, +0xb6, 0x00, 0xb9, 0x00, 0xbb, 0x00, 0xbc, 0x00, 0xbe, 0x00, 0xc0, 0x00, +0x7f, 0x0a, 0x8d, 0x04, 0x99, 0x01, 0xa2, 0x00, 0xaa, 0x00, 0xb1, 0x00, +0xb6, 0x00, 0xba, 0x00, 0xbe, 0x00, 0xc1, 0x00, 0xc3, 0x00, 0xc5, 0x00, +0xc7, 0x00, 0xc8, 0x00, 0xc9, 0x00, 0xcb, 0x00, 0xcc, 0x00, 0xcc, 0x00, +0xcd, 0x00, 0xce, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x49, 0x1c, 0x57, 0x11, +0x64, 0x0a, 0x70, 0x06, 0x79, 0x03, 0x82, 0x02, 0x8a, 0x00, 0x91, 0x00, +0x97, 0x00, 0x9c, 0x00, 0xa1, 0x00, 0xa5, 0x00, 0xa9, 0x00, 0xad, 0x00, +0xaf, 0x00, 0xb1, 0x00, 0xb4, 0x00, 0xb6, 0x00, 0xb9, 0x00, 0xba, 0x00, +0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, +0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, +0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, +0xdd, 0x00, 0xdd, 0x00, 0x21, 0x17, 0x38, 0x0b, 0x4c, 0x04, 0x5e, 0x01, +0x6c, 0x00, 0x7a, 0x00, 0x84, 0x00, 0x8d, 0x00, 0x95, 0x00, 0x9b, 0x00, +0xa0, 0x00, 0xa5, 0x00, 0xa8, 0x00, 0xac, 0x00, 0xaf, 0x00, 0xb2, 0x00, +0xb4, 0x00, 0xb6, 0x00, 0xb8, 0x00, 0xba, 0x00, 0x7f, 0x0b, 0x8a, 0x05, +0x94, 0x02, 0x9d, 0x00, 0xa4, 0x00, 0xab, 0x00, 0xb0, 0x00, 0xb5, 0x00, +0xb9, 0x00, 0xbc, 0x00, 0xbe, 0x00, 0xc1, 0x00, 0xc2, 0x00, 0xc4, 0x00, +0xc6, 0x00, 0xc7, 0x00, 0xc8, 0x00, 0xc9, 0x00, 0xca, 0x00, 0xcb, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x47, 0x20, 0x54, 0x15, 0x5f, 0x0e, 0x69, 0x09, +0x72, 0x05, 0x7a, 0x03, 0x82, 0x02, 0x88, 0x01, 0x8f, 0x00, 0x94, 0x00, +0x99, 0x00, 0x9e, 0x00, 0xa1, 0x00, 0xa4, 0x00, 0xa8, 0x00, 0xac, 0x00, +0xae, 0x00, 0xb0, 0x00, 0xb1, 0x00, 0xb4, 0x00, 0xdd, 0x00, 0xdd, 0x00, +0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, +0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, +0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, +0x22, 0x18, 0x35, 0x0d, 0x47, 0x06, 0x55, 0x03, 0x64, 0x01, 0x70, 0x00, +0x7a, 0x00, 0x83, 0x00, 0x8b, 0x00, 0x92, 0x00, 0x98, 0x00, 0x9d, 0x00, +0xa0, 0x00, 0xa5, 0x00, 0xa8, 0x00, 0xab, 0x00, 0xae, 0x00, 0xb0, 0x00, +0xb2, 0x00, 0xb4, 0x00, 0x7f, 0x0c, 0x89, 0x06, 0x92, 0x03, 0x99, 0x01, +0xa0, 0x00, 0xa6, 0x00, 0xab, 0x00, 0xb0, 0x00, 0xb4, 0x00, 0xb7, 0x00, +0xba, 0x00, 0xbd, 0x00, 0xbe, 0x00, 0xc1, 0x00, 0xc2, 0x00, 0xc4, 0x00, +0xc5, 0x00, 0xc6, 0x00, 0xc7, 0x00, 0xc8, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x46, 0x23, 0x50, 0x18, 0x5b, 0x11, 0x64, 0x0b, 0x6c, 0x08, 0x74, 0x05, +0x7b, 0x03, 0x82, 0x02, 0x87, 0x01, 0x8c, 0x00, 0x91, 0x00, 0x95, 0x00, +0x9a, 0x00, 0x9e, 0x00, 0xa1, 0x00, 0xa4, 0x00, 0xa7, 0x00, 0xab, 0x00, +0xac, 0x00, 0xaf, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, +0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, +0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, +0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0x21, 0x1a, 0x32, 0x0f, +0x42, 0x08, 0x50, 0x04, 0x5c, 0x02, 0x68, 0x00, 0x72, 0x00, 0x7b, 0x00, +0x83, 0x00, 0x8a, 0x00, 0x90, 0x00, 0x96, 0x00, 0x99, 0x00, 0x9e, 0x00, +0xa1, 0x00, 0xa5, 0x00, 0xa8, 0x00, 0xaa, 0x00, 0xad, 0x00, 0xaf, 0x00, +0x7f, 0x0d, 0x88, 0x07, 0x8f, 0x04, 0x96, 0x02, 0x9c, 0x01, 0xa2, 0x00, +0xa7, 0x00, 0xac, 0x00, 0xb0, 0x00, 0xb3, 0x00, 0xb6, 0x00, 0xb9, 0x00, +0xbb, 0x00, 0xbd, 0x00, 0xbf, 0x00, 0xc1, 0x00, 0xc2, 0x00, 0xc3, 0x00, +0xc5, 0x00, 0xc6, 0x00, 0x2f, 0x00, 0x5f, 0x00, 0x99, 0x00, 0xac, 0x00, +0xb3, 0x00, 0xb7, 0x00, 0xba, 0x00, 0xbb, 0x00, 0xbc, 0x00, 0xbc, 0x00, +0xbd, 0x00, 0xbd, 0x00, 0xbd, 0x00, 0xbe, 0x00, 0xbe, 0x00, 0xbe, 0x00, +0x3b, 0x0b, 0x6f, 0x00, 0x9f, 0x00, 0xaf, 0x00, 0xb5, 0x00, 0xb9, 0x00, +0xba, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbd, 0x00, 0xbd, 0x00, 0xbd, 0x00, +0xbe, 0x00, 0xbe, 0x00, 0xbe, 0x00, 0xbe, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x9a, 0x00, 0x6d, 0x00, 0x8d, 0x00, 0x9b, 0x00, +0xa6, 0x00, 0xb2, 0x00, 0xba, 0x00, 0xbb, 0x00, 0xbc, 0x00, 0xbc, 0x00, +0xbd, 0x00, 0xbd, 0x00, 0xbd, 0x00, 0xbe, 0x00, 0xbe, 0x00, 0xbe, 0x00, +0x47, 0x07, 0x7f, 0x00, 0xa5, 0x00, 0xb2, 0x00, 0xb7, 0x00, 0xba, 0x00, +0xbb, 0x00, 0xbc, 0x00, 0xbd, 0x00, 0xbd, 0x00, 0xbd, 0x00, 0xbe, 0x00, +0xbe, 0x00, 0xbe, 0x00, 0xbe, 0x00, 0xbe, 0x00, 0x45, 0x25, 0x4e, 0x1b, +0x57, 0x13, 0x60, 0x0e, 0x68, 0x0a, 0x6f, 0x07, 0x76, 0x05, 0x7b, 0x03, +0x82, 0x02, 0x86, 0x02, 0x8b, 0x01, 0x90, 0x00, 0x93, 0x00, 0x97, 0x00, +0x9b, 0x00, 0x9e, 0x00, 0xa1, 0x00, 0xa3, 0x00, 0xa6, 0x00, 0xaa, 0x00, +0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, +0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, +0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, +0xdd, 0x00, 0xdd, 0x00, 0x22, 0x1b, 0x30, 0x11, 0x3e, 0x0a, 0x4b, 0x05, +0x57, 0x03, 0x61, 0x01, 0x6b, 0x00, 0x73, 0x00, 0x7c, 0x00, 0x82, 0x00, +0x88, 0x00, 0x8f, 0x00, 0x93, 0x00, 0x97, 0x00, 0x9c, 0x00, 0x9f, 0x00, +0xa2, 0x00, 0xa5, 0x00, 0xa8, 0x00, 0xaa, 0x00, 0x7f, 0x0d, 0x86, 0x08, +0x8d, 0x05, 0x94, 0x02, 0x9a, 0x01, 0x9f, 0x00, 0xa4, 0x00, 0xa8, 0x00, +0xac, 0x00, 0xaf, 0x00, 0xb2, 0x00, 0xb6, 0x00, 0xb8, 0x00, 0xba, 0x00, +0xbc, 0x00, 0xbe, 0x00, 0xbf, 0x00, 0xc1, 0x00, 0xc2, 0x00, 0xc3, 0x00, +0x00, 0x00, 0x0f, 0x00, 0x5f, 0x00, 0x8b, 0x00, 0x9f, 0x00, 0xaa, 0x00, +0xb0, 0x00, 0xb3, 0x00, 0xb6, 0x00, 0xb8, 0x00, 0xb9, 0x00, 0xba, 0x00, +0xbb, 0x00, 0xbb, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0x07, 0x17, 0x27, 0x02, +0x6f, 0x00, 0x93, 0x00, 0xa4, 0x00, 0xad, 0x00, 0xb2, 0x00, 0xb5, 0x00, +0xb8, 0x00, 0xb9, 0x00, 0xba, 0x00, 0xbb, 0x00, 0xbb, 0x00, 0xbc, 0x00, +0xbc, 0x00, 0xbd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x6d, 0x00, 0x54, 0x00, 0x6b, 0x00, 0x87, 0x00, 0x98, 0x00, 0xa6, 0x00, +0xb0, 0x00, 0xb3, 0x00, 0xb6, 0x00, 0xb8, 0x00, 0xb9, 0x00, 0xba, 0x00, +0xbb, 0x00, 0xbb, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0x0f, 0x0f, 0x3f, 0x00, +0x7f, 0x00, 0x9c, 0x00, 0xaa, 0x00, 0xb1, 0x00, 0xb5, 0x00, 0xb7, 0x00, +0xb9, 0x00, 0xba, 0x00, 0xbb, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbd, 0x00, +0xbd, 0x00, 0xbd, 0x00, 0x45, 0x28, 0x4d, 0x1d, 0x55, 0x16, 0x5d, 0x11, +0x64, 0x0c, 0x6b, 0x09, 0x71, 0x07, 0x77, 0x05, 0x7b, 0x03, 0x81, 0x02, +0x85, 0x02, 0x8a, 0x01, 0x8e, 0x00, 0x92, 0x00, 0x95, 0x00, 0x98, 0x00, +0x9d, 0x00, 0x9f, 0x00, 0xa1, 0x00, 0xa3, 0x00, 0xdd, 0x00, 0xdd, 0x00, +0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, +0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, +0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, +0x21, 0x1b, 0x2f, 0x12, 0x3b, 0x0c, 0x47, 0x07, 0x51, 0x04, 0x5c, 0x02, +0x65, 0x01, 0x6e, 0x00, 0x75, 0x00, 0x7c, 0x00, 0x82, 0x00, 0x88, 0x00, +0x8d, 0x00, 0x91, 0x00, 0x96, 0x00, 0x99, 0x00, 0x9c, 0x00, 0xa0, 0x00, +0xa2, 0x00, 0xa5, 0x00, 0x7f, 0x0d, 0x86, 0x09, 0x8c, 0x06, 0x92, 0x03, +0x97, 0x02, 0x9c, 0x01, 0xa1, 0x00, 0xa5, 0x00, 0xa9, 0x00, 0xac, 0x00, +0xaf, 0x00, 0xb2, 0x00, 0xb5, 0x00, 0xb7, 0x00, 0xb9, 0x00, 0xbb, 0x00, +0xbc, 0x00, 0xbe, 0x00, 0xbf, 0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, +0x05, 0x00, 0x44, 0x00, 0x6d, 0x00, 0x85, 0x00, 0x95, 0x00, 0x9f, 0x00, +0xa6, 0x00, 0xab, 0x00, 0xae, 0x00, 0xb1, 0x00, 0xb3, 0x00, 0xb5, 0x00, +0xb6, 0x00, 0xb7, 0x00, 0x00, 0x2c, 0x02, 0x12, 0x22, 0x00, 0x58, 0x00, +0x7a, 0x00, 0x8f, 0x00, 0x9c, 0x00, 0xa4, 0x00, 0xaa, 0x00, 0xae, 0x00, +0xb1, 0x00, 0xb3, 0x00, 0xb5, 0x00, 0xb7, 0x00, 0xb8, 0x00, 0xb9, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8d, 0x00, 0x6b, 0x00, +0x28, 0x00, 0x52, 0x00, 0x70, 0x00, 0x85, 0x00, 0x95, 0x00, 0x9f, 0x00, +0xa6, 0x00, 0xab, 0x00, 0xae, 0x00, 0xb1, 0x00, 0xb3, 0x00, 0xb5, 0x00, +0xb6, 0x00, 0xb7, 0x00, 0x00, 0x26, 0x05, 0x05, 0x3f, 0x00, 0x6d, 0x00, +0x88, 0x00, 0x99, 0x00, 0xa3, 0x00, 0xaa, 0x00, 0xae, 0x00, 0xb1, 0x00, +0xb4, 0x00, 0xb6, 0x00, 0xb7, 0x00, 0xb8, 0x00, 0xb9, 0x00, 0xba, 0x00, +0x44, 0x2a, 0x4b, 0x20, 0x53, 0x18, 0x5a, 0x13, 0x61, 0x0f, 0x67, 0x0b, +0x6d, 0x09, 0x73, 0x07, 0x77, 0x05, 0x7c, 0x03, 0x81, 0x02, 0x85, 0x02, +0x88, 0x01, 0x8d, 0x01, 0x90, 0x00, 0x93, 0x00, 0x96, 0x00, 0x9a, 0x00, +0x9d, 0x00, 0x9f, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, +0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, +0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, +0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0x22, 0x1c, 0x2d, 0x13, +0x39, 0x0d, 0x44, 0x09, 0x4e, 0x05, 0x57, 0x04, 0x60, 0x02, 0x67, 0x01, +0x6f, 0x00, 0x76, 0x00, 0x7d, 0x00, 0x81, 0x00, 0x87, 0x00, 0x8c, 0x00, +0x90, 0x00, 0x94, 0x00, 0x97, 0x00, 0x9a, 0x00, 0x9d, 0x00, 0xa0, 0x00, +0x7f, 0x0e, 0x85, 0x09, 0x8b, 0x06, 0x90, 0x04, 0x95, 0x02, 0x9a, 0x02, +0x9e, 0x01, 0xa2, 0x00, 0xa6, 0x00, 0xa9, 0x00, 0xad, 0x00, 0xaf, 0x00, +0xb2, 0x00, 0xb4, 0x00, 0xb6, 0x00, 0xb8, 0x00, 0xba, 0x00, 0xbb, 0x00, +0xbd, 0x00, 0xbe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, +0x33, 0x00, 0x57, 0x00, 0x70, 0x00, 0x81, 0x00, 0x8e, 0x00, 0x97, 0x00, +0x9e, 0x00, 0xa3, 0x00, 0xa7, 0x00, 0xaa, 0x00, 0xad, 0x00, 0xaf, 0x00, +0x00, 0x36, 0x00, 0x25, 0x09, 0x0b, 0x21, 0x00, 0x4a, 0x00, 0x68, 0x00, +0x7d, 0x00, 0x8b, 0x00, 0x96, 0x00, 0x9d, 0x00, 0xa3, 0x00, 0xa8, 0x00, +0xab, 0x00, 0xae, 0x00, 0xb0, 0x00, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x9b, 0x00, 0x87, 0x00, 0x52, 0x00, 0x11, 0x00, +0x39, 0x00, 0x57, 0x00, 0x70, 0x00, 0x81, 0x00, 0x8e, 0x00, 0x97, 0x00, +0x9e, 0x00, 0xa3, 0x00, 0xa7, 0x00, 0xaa, 0x00, 0xad, 0x00, 0xaf, 0x00, +0x00, 0x33, 0x00, 0x1c, 0x12, 0x00, 0x3f, 0x00, 0x62, 0x00, 0x7a, 0x00, +0x8a, 0x00, 0x96, 0x00, 0x9e, 0x00, 0xa4, 0x00, 0xa9, 0x00, 0xac, 0x00, +0xaf, 0x00, 0xb1, 0x00, 0xb3, 0x00, 0xb4, 0x00, 0x43, 0x2b, 0x4a, 0x22, +0x51, 0x1a, 0x57, 0x15, 0x5e, 0x11, 0x63, 0x0d, 0x69, 0x0a, 0x6e, 0x08, +0x74, 0x06, 0x78, 0x05, 0x7c, 0x04, 0x81, 0x03, 0x84, 0x02, 0x87, 0x02, +0x8c, 0x01, 0x8f, 0x00, 0x92, 0x00, 0x94, 0x00, 0x97, 0x00, 0x9b, 0x00, +0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, +0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, +0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, +0xdd, 0x00, 0xdd, 0x00, 0x21, 0x1c, 0x2d, 0x14, 0x37, 0x0e, 0x41, 0x0a, +0x4a, 0x07, 0x53, 0x04, 0x5b, 0x02, 0x63, 0x01, 0x69, 0x00, 0x70, 0x00, +0x77, 0x00, 0x7d, 0x00, 0x81, 0x00, 0x87, 0x00, 0x8a, 0x00, 0x8f, 0x00, +0x92, 0x00, 0x96, 0x00, 0x99, 0x00, 0x9b, 0x00, 0x7f, 0x0e, 0x85, 0x0a, +0x8a, 0x07, 0x8f, 0x05, 0x93, 0x03, 0x98, 0x02, 0x9c, 0x01, 0xa0, 0x00, +0xa3, 0x00, 0xa6, 0x00, 0xaa, 0x00, 0xad, 0x00, 0xaf, 0x00, 0xb2, 0x00, +0xb3, 0x00, 0xb6, 0x00, 0xb7, 0x00, 0xb9, 0x00, 0xbb, 0x00, 0xbc, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x28, 0x00, +0x48, 0x00, 0x5f, 0x00, 0x71, 0x00, 0x7e, 0x00, 0x89, 0x00, 0x91, 0x00, +0x98, 0x00, 0x9d, 0x00, 0xa1, 0x00, 0xa5, 0x00, 0x00, 0x3a, 0x00, 0x2f, +0x00, 0x16, 0x0e, 0x08, 0x20, 0x00, 0x42, 0x00, 0x5c, 0x00, 0x6f, 0x00, +0x7e, 0x00, 0x89, 0x00, 0x92, 0x00, 0x99, 0x00, 0x9e, 0x00, 0xa2, 0x00, +0xa6, 0x00, 0xa9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0xa6, 0x00, 0x98, 0x00, 0x70, 0x00, 0x39, 0x00, 0x02, 0x00, 0x28, 0x00, +0x48, 0x00, 0x5f, 0x00, 0x71, 0x00, 0x7e, 0x00, 0x89, 0x00, 0x91, 0x00, +0x98, 0x00, 0x9d, 0x00, 0xa1, 0x00, 0xa5, 0x00, 0x00, 0x38, 0x00, 0x2a, +0x00, 0x09, 0x1d, 0x00, 0x3f, 0x00, 0x5b, 0x00, 0x6f, 0x00, 0x7f, 0x00, +0x8b, 0x00, 0x94, 0x00, 0x9b, 0x00, 0xa0, 0x00, 0xa5, 0x00, 0xa8, 0x00, +0xab, 0x00, 0xad, 0x00, 0x43, 0x2c, 0x49, 0x23, 0x50, 0x1c, 0x56, 0x17, +0x5b, 0x12, 0x61, 0x0f, 0x66, 0x0c, 0x6b, 0x0a, 0x6f, 0x08, 0x75, 0x06, +0x78, 0x05, 0x7c, 0x04, 0x81, 0x03, 0x84, 0x02, 0x87, 0x02, 0x8b, 0x01, +0x8e, 0x01, 0x91, 0x00, 0x93, 0x00, 0x95, 0x00, 0xdd, 0x00, 0xdd, 0x00, +0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, +0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, +0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, +0x22, 0x1c, 0x2c, 0x15, 0x36, 0x0f, 0x3e, 0x0b, 0x48, 0x07, 0x50, 0x05, +0x58, 0x04, 0x5f, 0x02, 0x66, 0x01, 0x6c, 0x00, 0x71, 0x00, 0x77, 0x00, +0x7d, 0x00, 0x81, 0x00, 0x86, 0x00, 0x8a, 0x00, 0x8e, 0x00, 0x91, 0x00, +0x94, 0x00, 0x97, 0x00, 0x7f, 0x0e, 0x84, 0x0a, 0x89, 0x07, 0x8d, 0x05, +0x92, 0x03, 0x96, 0x02, 0x9a, 0x02, 0x9e, 0x01, 0xa1, 0x00, 0xa4, 0x00, +0xa7, 0x00, 0xaa, 0x00, 0xad, 0x00, 0xaf, 0x00, 0xb1, 0x00, 0xb3, 0x00, +0xb5, 0x00, 0xb7, 0x00, 0xb8, 0x00, 0xba, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x00, 0x3d, 0x00, +0x52, 0x00, 0x64, 0x00, 0x71, 0x00, 0x7c, 0x00, 0x85, 0x00, 0x8d, 0x00, +0x93, 0x00, 0x98, 0x00, 0x00, 0x3c, 0x00, 0x35, 0x00, 0x23, 0x02, 0x0e, +0x12, 0x06, 0x20, 0x00, 0x3c, 0x00, 0x52, 0x00, 0x64, 0x00, 0x73, 0x00, +0x7e, 0x00, 0x87, 0x00, 0x8f, 0x00, 0x95, 0x00, 0x9a, 0x00, 0x9e, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb2, 0x00, 0xa6, 0x00, +0x85, 0x00, 0x57, 0x00, 0x28, 0x00, 0x01, 0x00, 0x21, 0x00, 0x3d, 0x00, +0x52, 0x00, 0x64, 0x00, 0x71, 0x00, 0x7c, 0x00, 0x85, 0x00, 0x8d, 0x00, +0x93, 0x00, 0x98, 0x00, 0x00, 0x3a, 0x00, 0x31, 0x00, 0x19, 0x05, 0x00, +0x24, 0x00, 0x3f, 0x00, 0x56, 0x00, 0x68, 0x00, 0x77, 0x00, 0x82, 0x00, +0x8b, 0x00, 0x93, 0x00, 0x99, 0x00, 0x9d, 0x00, 0xa1, 0x00, 0xa5, 0x00, +0x43, 0x2e, 0x48, 0x25, 0x4e, 0x1e, 0x54, 0x19, 0x59, 0x14, 0x5f, 0x11, +0x63, 0x0e, 0x69, 0x0b, 0x6c, 0x09, 0x71, 0x07, 0x76, 0x06, 0x78, 0x05, +0x7c, 0x04, 0x81, 0x03, 0x84, 0x02, 0x86, 0x02, 0x8a, 0x01, 0x8e, 0x01, +0x90, 0x00, 0x92, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, +0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, +0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, +0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0x21, 0x1d, 0x2b, 0x16, +0x34, 0x10, 0x3d, 0x0c, 0x45, 0x09, 0x4c, 0x06, 0x54, 0x04, 0x5b, 0x02, +0x61, 0x02, 0x67, 0x01, 0x6d, 0x00, 0x73, 0x00, 0x78, 0x00, 0x7d, 0x00, +0x81, 0x00, 0x86, 0x00, 0x89, 0x00, 0x8d, 0x00, 0x90, 0x00, 0x93, 0x00, +0x7f, 0x0e, 0x84, 0x0b, 0x88, 0x08, 0x8d, 0x06, 0x91, 0x04, 0x94, 0x03, +0x98, 0x02, 0x9c, 0x01, 0x9f, 0x01, 0xa2, 0x00, 0xa5, 0x00, 0xa8, 0x00, +0xaa, 0x00, 0xad, 0x00, 0xaf, 0x00, 0xb1, 0x00, 0xb3, 0x00, 0xb5, 0x00, +0xb6, 0x00, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x35, 0x00, 0x48, 0x00, +0x59, 0x00, 0x66, 0x00, 0x72, 0x00, 0x7b, 0x00, 0x83, 0x00, 0x89, 0x00, +0x00, 0x3d, 0x00, 0x38, 0x00, 0x2a, 0x00, 0x18, 0x07, 0x0c, 0x14, 0x05, +0x20, 0x00, 0x37, 0x00, 0x4c, 0x00, 0x5c, 0x00, 0x6a, 0x00, 0x75, 0x00, +0x7e, 0x00, 0x86, 0x00, 0x8d, 0x00, 0x92, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0xba, 0x00, 0xb0, 0x00, 0x95, 0x00, 0x70, 0x00, +0x48, 0x00, 0x21, 0x00, 0x01, 0x00, 0x1c, 0x00, 0x35, 0x00, 0x48, 0x00, +0x59, 0x00, 0x66, 0x00, 0x72, 0x00, 0x7b, 0x00, 0x83, 0x00, 0x89, 0x00, +0x00, 0x3c, 0x00, 0x35, 0x00, 0x23, 0x00, 0x0b, 0x0f, 0x00, 0x29, 0x00, +0x3f, 0x00, 0x53, 0x00, 0x63, 0x00, 0x70, 0x00, 0x7b, 0x00, 0x84, 0x00, +0x8b, 0x00, 0x92, 0x00, 0x97, 0x00, 0x9b, 0x00, 0x42, 0x2f, 0x48, 0x26, +0x4d, 0x20, 0x52, 0x1a, 0x58, 0x16, 0x5c, 0x12, 0x61, 0x0f, 0x66, 0x0c, +0x6b, 0x0b, 0x6d, 0x09, 0x73, 0x07, 0x76, 0x06, 0x79, 0x05, 0x7d, 0x04, +0x81, 0x03, 0x83, 0x02, 0x86, 0x02, 0x89, 0x02, 0x8d, 0x01, 0x8f, 0x01, +0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, +0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, +0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, +0xdd, 0x00, 0xdd, 0x00, 0x22, 0x1d, 0x2a, 0x16, 0x33, 0x11, 0x3b, 0x0c, +0x43, 0x0a, 0x4a, 0x07, 0x51, 0x05, 0x58, 0x04, 0x5e, 0x02, 0x64, 0x01, +0x69, 0x01, 0x6f, 0x00, 0x74, 0x00, 0x78, 0x00, 0x7d, 0x00, 0x81, 0x00, +0x85, 0x00, 0x89, 0x00, 0x8b, 0x00, 0x8f, 0x00, 0x7f, 0x0e, 0x83, 0x0b, +0x88, 0x08, 0x8c, 0x06, 0x90, 0x05, 0x93, 0x03, 0x97, 0x02, 0x9a, 0x02, +0x9d, 0x01, 0xa0, 0x00, 0xa3, 0x00, 0xa6, 0x00, 0xa8, 0x00, 0xaa, 0x00, +0xad, 0x00, 0xaf, 0x00, 0xb1, 0x00, 0xb3, 0x00, 0xb4, 0x00, 0xb6, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x19, 0x00, 0x2e, 0x00, 0x41, 0x00, 0x50, 0x00, +0x5d, 0x00, 0x68, 0x00, 0x72, 0x00, 0x7a, 0x00, 0x00, 0x3d, 0x00, 0x3a, +0x00, 0x2f, 0x00, 0x20, 0x00, 0x10, 0x0b, 0x0a, 0x16, 0x04, 0x20, 0x00, +0x34, 0x00, 0x46, 0x00, 0x56, 0x00, 0x62, 0x00, 0x6d, 0x00, 0x77, 0x00, +0x7f, 0x00, 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0xbb, 0x00, 0xb3, 0x00, 0x9f, 0x00, 0x81, 0x00, 0x5f, 0x00, 0x3d, 0x00, +0x1c, 0x00, 0x00, 0x00, 0x19, 0x00, 0x2e, 0x00, 0x41, 0x00, 0x50, 0x00, +0x5d, 0x00, 0x68, 0x00, 0x72, 0x00, 0x7a, 0x00, 0x00, 0x3d, 0x00, 0x38, +0x00, 0x2a, 0x00, 0x16, 0x00, 0x00, 0x16, 0x00, 0x2c, 0x00, 0x3f, 0x00, +0x50, 0x00, 0x5e, 0x00, 0x6b, 0x00, 0x75, 0x00, 0x7e, 0x00, 0x85, 0x00, +0x8b, 0x00, 0x91, 0x00, 0x42, 0x30, 0x47, 0x28, 0x4c, 0x21, 0x51, 0x1c, +0x56, 0x17, 0x5a, 0x14, 0x60, 0x11, 0x63, 0x0e, 0x68, 0x0c, 0x6c, 0x0a, +0x6f, 0x08, 0x74, 0x07, 0x77, 0x06, 0x79, 0x05, 0x7d, 0x04, 0x81, 0x03, +0x83, 0x02, 0x85, 0x02, 0x88, 0x02, 0x8c, 0x01, 0xdd, 0x00, 0xdd, 0x00, +0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, +0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, +0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, +0x21, 0x1e, 0x2a, 0x17, 0x32, 0x12, 0x39, 0x0e, 0x40, 0x0a, 0x48, 0x07, +0x4f, 0x05, 0x55, 0x04, 0x5a, 0x03, 0x60, 0x02, 0x66, 0x01, 0x6b, 0x00, +0x70, 0x00, 0x75, 0x00, 0x79, 0x00, 0x7d, 0x00, 0x81, 0x00, 0x84, 0x00, +0x88, 0x00, 0x8b, 0x00, 0x7f, 0x0f, 0x83, 0x0b, 0x87, 0x09, 0x8b, 0x07, +0x8e, 0x05, 0x92, 0x03, 0x96, 0x02, 0x99, 0x02, 0x9b, 0x01, 0x9e, 0x01, +0xa1, 0x00, 0xa4, 0x00, 0xa6, 0x00, 0xa9, 0x00, 0xab, 0x00, 0xad, 0x00, +0xaf, 0x00, 0xb0, 0x00, 0xb2, 0x00, 0xb4, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x16, 0x00, 0x29, 0x00, 0x3a, 0x00, 0x49, 0x00, 0x55, 0x00, +0x60, 0x00, 0x6a, 0x00, 0x00, 0x3e, 0x00, 0x3b, 0x00, 0x33, 0x00, 0x27, +0x00, 0x18, 0x04, 0x0d, 0x0e, 0x08, 0x17, 0x04, 0x20, 0x00, 0x32, 0x00, +0x42, 0x00, 0x50, 0x00, 0x5c, 0x00, 0x67, 0x00, 0x70, 0x00, 0x78, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbc, 0x00, 0xb6, 0x00, +0xa6, 0x00, 0x8e, 0x00, 0x71, 0x00, 0x52, 0x00, 0x35, 0x00, 0x19, 0x00, +0x00, 0x00, 0x16, 0x00, 0x29, 0x00, 0x3a, 0x00, 0x49, 0x00, 0x55, 0x00, +0x60, 0x00, 0x6a, 0x00, 0x00, 0x3d, 0x00, 0x39, 0x00, 0x2f, 0x00, 0x1f, +0x00, 0x0b, 0x08, 0x00, 0x1c, 0x00, 0x2e, 0x00, 0x3f, 0x00, 0x4e, 0x00, +0x5b, 0x00, 0x66, 0x00, 0x70, 0x00, 0x78, 0x00, 0x80, 0x00, 0x86, 0x00, +0x42, 0x31, 0x47, 0x29, 0x4b, 0x22, 0x50, 0x1d, 0x55, 0x19, 0x58, 0x15, +0x5e, 0x12, 0x61, 0x0f, 0x65, 0x0d, 0x6a, 0x0b, 0x6c, 0x09, 0x70, 0x08, +0x75, 0x07, 0x77, 0x06, 0x79, 0x05, 0x7d, 0x04, 0x81, 0x03, 0x83, 0x02, +0x85, 0x02, 0x87, 0x02, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, +0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, +0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, +0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0x21, 0x1e, 0x29, 0x18, +0x31, 0x12, 0x38, 0x0f, 0x3f, 0x0c, 0x45, 0x09, 0x4c, 0x07, 0x52, 0x05, +0x58, 0x04, 0x5d, 0x02, 0x63, 0x02, 0x67, 0x01, 0x6c, 0x00, 0x71, 0x00, +0x75, 0x00, 0x79, 0x00, 0x7d, 0x00, 0x81, 0x00, 0x84, 0x00, 0x88, 0x00, +0x7f, 0x0f, 0x83, 0x0c, 0x87, 0x09, 0x8a, 0x07, 0x8e, 0x06, 0x91, 0x04, +0x94, 0x03, 0x97, 0x02, 0x9a, 0x02, 0x9d, 0x01, 0xa0, 0x01, 0xa2, 0x00, +0xa4, 0x00, 0xa7, 0x00, 0xa9, 0x00, 0xab, 0x00, 0xad, 0x00, 0xaf, 0x00, +0xb0, 0x00, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x13, 0x00, 0x25, 0x00, 0x35, 0x00, 0x43, 0x00, 0x4f, 0x00, 0x59, 0x00, +0x00, 0x3e, 0x00, 0x3c, 0x00, 0x35, 0x00, 0x2b, 0x00, 0x1f, 0x00, 0x12, +0x07, 0x0c, 0x10, 0x07, 0x18, 0x03, 0x20, 0x00, 0x30, 0x00, 0x3f, 0x00, +0x4c, 0x00, 0x57, 0x00, 0x61, 0x00, 0x6a, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0xbc, 0x00, 0xb8, 0x00, 0xab, 0x00, 0x97, 0x00, +0x7e, 0x00, 0x64, 0x00, 0x48, 0x00, 0x2e, 0x00, 0x16, 0x00, 0x00, 0x00, +0x13, 0x00, 0x25, 0x00, 0x35, 0x00, 0x43, 0x00, 0x4f, 0x00, 0x59, 0x00, +0x00, 0x3e, 0x00, 0x3b, 0x00, 0x32, 0x00, 0x25, 0x00, 0x14, 0x00, 0x02, +0x0f, 0x00, 0x20, 0x00, 0x30, 0x00, 0x3f, 0x00, 0x4d, 0x00, 0x58, 0x00, +0x63, 0x00, 0x6c, 0x00, 0x74, 0x00, 0x7b, 0x00, 0x42, 0x31, 0x46, 0x2a, +0x4a, 0x24, 0x4f, 0x1f, 0x53, 0x1a, 0x58, 0x16, 0x5c, 0x13, 0x60, 0x11, +0x63, 0x0e, 0x67, 0x0c, 0x6b, 0x0b, 0x6d, 0x09, 0x72, 0x07, 0x75, 0x07, +0x77, 0x06, 0x79, 0x05, 0x7e, 0x04, 0x81, 0x03, 0x83, 0x02, 0x85, 0x02, +0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, +0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, +0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, +0xdd, 0x00, 0xdd, 0x00, 0x21, 0x1e, 0x29, 0x18, 0x30, 0x13, 0x37, 0x0f, +0x3d, 0x0c, 0x44, 0x0a, 0x4a, 0x07, 0x50, 0x05, 0x55, 0x04, 0x5b, 0x04, +0x60, 0x02, 0x64, 0x01, 0x69, 0x01, 0x6d, 0x00, 0x72, 0x00, 0x76, 0x00, +0x7a, 0x00, 0x7d, 0x00, 0x81, 0x00, 0x83, 0x00, 0x7f, 0x0f, 0x83, 0x0c, +0x86, 0x09, 0x8a, 0x07, 0x8d, 0x06, 0x90, 0x05, 0x93, 0x03, 0x96, 0x02, +0x99, 0x02, 0x9c, 0x02, 0x9e, 0x01, 0xa0, 0x00, 0xa3, 0x00, 0xa5, 0x00, +0xa7, 0x00, 0xa9, 0x00, 0xab, 0x00, 0xad, 0x00, 0xaf, 0x00, 0xb0, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, +0x22, 0x00, 0x30, 0x00, 0x3d, 0x00, 0x49, 0x00, 0x00, 0x3e, 0x00, 0x3c, +0x00, 0x37, 0x00, 0x2f, 0x00, 0x24, 0x00, 0x19, 0x02, 0x0e, 0x0a, 0x0a, +0x11, 0x06, 0x19, 0x03, 0x1f, 0x00, 0x2e, 0x00, 0x3c, 0x00, 0x48, 0x00, +0x53, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0xbd, 0x00, 0xb9, 0x00, 0xae, 0x00, 0x9e, 0x00, 0x89, 0x00, 0x71, 0x00, +0x59, 0x00, 0x41, 0x00, 0x29, 0x00, 0x13, 0x00, 0x00, 0x00, 0x12, 0x00, +0x22, 0x00, 0x30, 0x00, 0x3d, 0x00, 0x49, 0x00, 0x00, 0x3e, 0x00, 0x3c, +0x00, 0x34, 0x00, 0x29, 0x00, 0x1b, 0x00, 0x0c, 0x04, 0x00, 0x14, 0x00, +0x23, 0x00, 0x32, 0x00, 0x3f, 0x00, 0x4b, 0x00, 0x56, 0x00, 0x60, 0x00, +0x68, 0x00, 0x70, 0x00, 0x42, 0x32, 0x46, 0x2b, 0x49, 0x25, 0x4f, 0x1f, +0x52, 0x1b, 0x57, 0x18, 0x59, 0x14, 0x5f, 0x12, 0x62, 0x0f, 0x65, 0x0d, +0x6a, 0x0c, 0x6c, 0x0a, 0x6e, 0x09, 0x73, 0x07, 0x76, 0x06, 0x78, 0x06, +0x7a, 0x05, 0x7e, 0x04, 0x81, 0x03, 0x83, 0x02, 0xdd, 0x00, 0xdd, 0x00, +0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, +0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, +0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, +0x21, 0x1e, 0x28, 0x19, 0x2f, 0x14, 0x35, 0x0f, 0x3c, 0x0c, 0x42, 0x0a, +0x48, 0x07, 0x4e, 0x06, 0x53, 0x05, 0x58, 0x04, 0x5d, 0x02, 0x62, 0x02, +0x66, 0x01, 0x6b, 0x01, 0x6f, 0x00, 0x73, 0x00, 0x76, 0x00, 0x7a, 0x00, +0x7d, 0x00, 0x81, 0x00, 0x7f, 0x0f, 0x82, 0x0c, 0x86, 0x0a, 0x89, 0x07, +0x8c, 0x06, 0x8f, 0x05, 0x92, 0x03, 0x95, 0x03, 0x98, 0x02, 0x9a, 0x02, +0x9d, 0x01, 0x9f, 0x01, 0xa1, 0x00, 0xa4, 0x00, 0xa6, 0x00, 0xa8, 0x00, +0xa9, 0x00, 0xab, 0x00, 0xad, 0x00, 0xaf, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x1f, 0x00, +0x2d, 0x00, 0x39, 0x00, 0x00, 0x3e, 0x00, 0x3d, 0x00, 0x38, 0x00, 0x31, +0x00, 0x28, 0x00, 0x1e, 0x00, 0x13, 0x05, 0x0d, 0x0c, 0x09, 0x13, 0x06, +0x19, 0x03, 0x1f, 0x00, 0x2d, 0x00, 0x3a, 0x00, 0x45, 0x00, 0x4f, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbd, 0x00, 0xba, 0x00, +0xb1, 0x00, 0xa3, 0x00, 0x91, 0x00, 0x7c, 0x00, 0x66, 0x00, 0x50, 0x00, +0x3a, 0x00, 0x25, 0x00, 0x12, 0x00, 0x00, 0x00, 0x10, 0x00, 0x1f, 0x00, +0x2d, 0x00, 0x39, 0x00, 0x00, 0x3e, 0x00, 0x3c, 0x00, 0x36, 0x00, 0x2d, +0x00, 0x21, 0x00, 0x13, 0x00, 0x04, 0x0a, 0x00, 0x18, 0x00, 0x26, 0x00, +0x33, 0x00, 0x3f, 0x00, 0x4a, 0x00, 0x54, 0x00, 0x5d, 0x00, 0x65, 0x00, +0x42, 0x33, 0x45, 0x2c, 0x48, 0x26, 0x4e, 0x21, 0x50, 0x1c, 0x56, 0x19, +0x58, 0x16, 0x5c, 0x13, 0x60, 0x11, 0x62, 0x0e, 0x67, 0x0c, 0x6a, 0x0b, +0x6d, 0x0a, 0x70, 0x09, 0x74, 0x07, 0x76, 0x06, 0x78, 0x06, 0x7a, 0x05, +0x7e, 0x04, 0x81, 0x03, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, +0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, +0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, +0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0x21, 0x1e, 0x28, 0x19, +0x2f, 0x15, 0x35, 0x11, 0x3b, 0x0d, 0x41, 0x0b, 0x46, 0x09, 0x4c, 0x07, +0x51, 0x05, 0x55, 0x04, 0x5b, 0x04, 0x5f, 0x02, 0x63, 0x02, 0x68, 0x01, +0x6b, 0x00, 0x70, 0x00, 0x73, 0x00, 0x77, 0x00, 0x7b, 0x00, 0x7d, 0x00, +0x7f, 0x0f, 0x82, 0x0c, 0x86, 0x0a, 0x89, 0x08, 0x8c, 0x06, 0x8f, 0x05, +0x91, 0x04, 0x94, 0x03, 0x97, 0x02, 0x99, 0x02, 0x9c, 0x02, 0x9e, 0x01, +0xa0, 0x01, 0xa2, 0x00, 0xa4, 0x00, 0xa6, 0x00, 0xa8, 0x00, 0xaa, 0x00, +0xac, 0x00, 0xad, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x1d, 0x00, 0x29, 0x00, +0x00, 0x3f, 0x00, 0x3d, 0x00, 0x39, 0x00, 0x33, 0x00, 0x2c, 0x00, 0x23, +0x00, 0x19, 0x00, 0x0f, 0x07, 0x0c, 0x0e, 0x08, 0x14, 0x05, 0x1a, 0x02, +0x1f, 0x00, 0x2c, 0x00, 0x38, 0x00, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0xbd, 0x00, 0xbb, 0x00, 0xb3, 0x00, 0xa7, 0x00, +0x98, 0x00, 0x85, 0x00, 0x72, 0x00, 0x5d, 0x00, 0x49, 0x00, 0x35, 0x00, +0x22, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x1d, 0x00, 0x29, 0x00, +0x00, 0x3e, 0x00, 0x3d, 0x00, 0x38, 0x00, 0x30, 0x00, 0x25, 0x00, 0x19, +0x00, 0x0c, 0x01, 0x00, 0x0e, 0x00, 0x1c, 0x00, 0x28, 0x00, 0x34, 0x00, +0x3f, 0x00, 0x49, 0x00, 0x53, 0x00, 0x5b, 0x00, 0x5d, 0x1a, 0x6d, 0x16, +0x72, 0x15, 0x75, 0x14, 0x77, 0x13, 0x78, 0x13, 0x79, 0x13, 0x7a, 0x12, +0x7a, 0x12, 0x7b, 0x12, 0x7b, 0x12, 0x7b, 0x12, 0x7c, 0x12, 0x7c, 0x11, +0x7c, 0x11, 0x7c, 0x11, 0x7c, 0x11, 0x7c, 0x11, 0x7c, 0x11, 0x7d, 0x11, +0xbd, 0x02, 0xa4, 0x06, 0x97, 0x09, 0x91, 0x0a, 0x8d, 0x0b, 0x8a, 0x0c, +0x89, 0x0d, 0x88, 0x0d, 0x86, 0x0d, 0x86, 0x0e, 0x85, 0x0e, 0x85, 0x0e, +0x84, 0x0e, 0x84, 0x0e, 0x83, 0x0f, 0x83, 0x0f, 0x83, 0x0f, 0x83, 0x0f, +0x82, 0x0f, 0x82, 0x0f, 0x33, 0x11, 0x5f, 0x11, 0x6f, 0x11, 0x74, 0x11, +0x77, 0x11, 0x78, 0x11, 0x7a, 0x11, 0x7a, 0x11, 0x7b, 0x11, 0x7b, 0x11, +0x7c, 0x11, 0x7c, 0x11, 0x7c, 0x11, 0x7c, 0x11, 0x7d, 0x11, 0x7d, 0x11, +0x7d, 0x11, 0x7d, 0x11, 0x7d, 0x11, 0x7d, 0x11, 0x7f, 0x11, 0x7f, 0x11, +0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, +0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, +0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x1b, 0x00, 0x00, 0x3f, 0x00, 0x3e, +0x00, 0x3a, 0x00, 0x35, 0x00, 0x2e, 0x00, 0x26, 0x00, 0x1d, 0x00, 0x14, +0x03, 0x0e, 0x09, 0x0b, 0x0f, 0x08, 0x15, 0x05, 0x1a, 0x02, 0x1f, 0x00, +0x2b, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0xbe, 0x00, 0xbb, 0x00, 0xb5, 0x00, 0xaa, 0x00, 0x9d, 0x00, 0x8d, 0x00, +0x7b, 0x00, 0x68, 0x00, 0x55, 0x00, 0x43, 0x00, 0x30, 0x00, 0x1f, 0x00, +0x0f, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x1b, 0x00, 0x00, 0x3f, 0x00, 0x3d, +0x00, 0x39, 0x00, 0x32, 0x00, 0x29, 0x00, 0x1e, 0x00, 0x12, 0x00, 0x06, +0x06, 0x00, 0x13, 0x00, 0x1f, 0x00, 0x2a, 0x00, 0x35, 0x00, 0x3f, 0x00, +0x49, 0x00, 0x51, 0x00, 0x50, 0x24, 0x5f, 0x1f, 0x66, 0x1b, 0x6b, 0x19, +0x6e, 0x18, 0x70, 0x17, 0x73, 0x16, 0x73, 0x15, 0x75, 0x15, 0x76, 0x15, +0x76, 0x15, 0x77, 0x14, 0x77, 0x14, 0x78, 0x13, 0x78, 0x13, 0x79, 0x13, +0x79, 0x13, 0x7a, 0x13, 0x7a, 0x13, 0x7b, 0x13, 0xcc, 0x00, 0xb5, 0x00, +0xa8, 0x02, 0x9e, 0x04, 0x99, 0x05, 0x94, 0x06, 0x92, 0x07, 0x8f, 0x08, +0x8d, 0x09, 0x8c, 0x09, 0x8b, 0x0a, 0x8a, 0x0a, 0x89, 0x0b, 0x88, 0x0b, +0x88, 0x0b, 0x87, 0x0c, 0x87, 0x0c, 0x86, 0x0c, 0x86, 0x0c, 0x86, 0x0c, +0x23, 0x13, 0x46, 0x11, 0x58, 0x11, 0x63, 0x11, 0x69, 0x11, 0x6d, 0x11, +0x70, 0x11, 0x72, 0x11, 0x73, 0x11, 0x75, 0x11, 0x76, 0x11, 0x77, 0x11, +0x77, 0x11, 0x78, 0x11, 0x78, 0x11, 0x79, 0x11, 0x79, 0x11, 0x79, 0x11, +0x7a, 0x11, 0x7a, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, +0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, +0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, +0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x0d, 0x00, 0x00, 0x3f, 0x00, 0x3e, 0x00, 0x3b, 0x00, 0x36, +0x00, 0x30, 0x00, 0x29, 0x00, 0x21, 0x00, 0x19, 0x00, 0x10, 0x05, 0x0d, +0x0b, 0x0a, 0x10, 0x07, 0x16, 0x04, 0x1b, 0x02, 0x1f, 0x00, 0x2a, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x00, 0xbc, 0x00, +0xb6, 0x00, 0xad, 0x00, 0xa1, 0x00, 0x93, 0x00, 0x83, 0x00, 0x72, 0x00, +0x60, 0x00, 0x4f, 0x00, 0x3d, 0x00, 0x2d, 0x00, 0x1d, 0x00, 0x0e, 0x00, +0x00, 0x00, 0x0d, 0x00, 0x00, 0x3f, 0x00, 0x3d, 0x00, 0x3a, 0x00, 0x33, +0x00, 0x2b, 0x00, 0x22, 0x00, 0x17, 0x00, 0x0c, 0x00, 0x00, 0x0b, 0x00, +0x16, 0x00, 0x21, 0x00, 0x2c, 0x00, 0x36, 0x00, 0x3f, 0x00, 0x48, 0x00, +0x4a, 0x2a, 0x57, 0x24, 0x5f, 0x20, 0x64, 0x1e, 0x68, 0x1c, 0x6a, 0x1b, +0x6d, 0x19, 0x6e, 0x18, 0x70, 0x18, 0x72, 0x17, 0x72, 0x17, 0x73, 0x16, +0x74, 0x15, 0x75, 0x15, 0x76, 0x15, 0x76, 0x15, 0x76, 0x15, 0x76, 0x15, +0x76, 0x15, 0x77, 0x14, 0xd1, 0x00, 0xc0, 0x00, 0xb3, 0x00, 0xaa, 0x01, +0xa2, 0x02, 0x9d, 0x03, 0x99, 0x04, 0x96, 0x05, 0x94, 0x06, 0x92, 0x06, +0x90, 0x07, 0x8f, 0x07, 0x8d, 0x08, 0x8d, 0x08, 0x8c, 0x09, 0x8b, 0x09, +0x8a, 0x09, 0x8a, 0x0a, 0x89, 0x0a, 0x89, 0x0b, 0x22, 0x17, 0x39, 0x11, +0x4a, 0x11, 0x55, 0x11, 0x5e, 0x11, 0x63, 0x11, 0x67, 0x11, 0x6a, 0x11, +0x6c, 0x11, 0x6e, 0x11, 0x70, 0x11, 0x71, 0x11, 0x72, 0x11, 0x73, 0x11, +0x74, 0x11, 0x75, 0x11, 0x75, 0x11, 0x76, 0x11, 0x76, 0x11, 0x77, 0x11, +0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, +0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, +0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, +0x7f, 0x11, 0x7f, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x3f, 0x00, 0x3e, 0x00, 0x3c, 0x00, 0x38, 0x00, 0x32, 0x00, 0x2c, +0x00, 0x25, 0x00, 0x1d, 0x00, 0x15, 0x01, 0x0e, 0x07, 0x0c, 0x0c, 0x09, +0x11, 0x06, 0x16, 0x04, 0x1b, 0x02, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0xbe, 0x00, 0xbc, 0x00, 0xb7, 0x00, 0xaf, 0x00, +0xa5, 0x00, 0x98, 0x00, 0x89, 0x00, 0x7a, 0x00, 0x6a, 0x00, 0x59, 0x00, +0x49, 0x00, 0x39, 0x00, 0x29, 0x00, 0x1b, 0x00, 0x0d, 0x00, 0x00, 0x00, +0x00, 0x3f, 0x00, 0x3e, 0x00, 0x3a, 0x00, 0x35, 0x00, 0x2e, 0x00, 0x25, +0x00, 0x1c, 0x00, 0x11, 0x00, 0x07, 0x03, 0x00, 0x0e, 0x00, 0x19, 0x00, +0x23, 0x00, 0x2d, 0x00, 0x36, 0x00, 0x3f, 0x00, 0x48, 0x2e, 0x53, 0x28, +0x5a, 0x24, 0x5f, 0x22, 0x63, 0x1f, 0x66, 0x1e, 0x69, 0x1c, 0x6a, 0x1b, +0x6c, 0x1a, 0x6d, 0x1a, 0x6e, 0x19, 0x70, 0x18, 0x71, 0x18, 0x72, 0x18, +0x72, 0x17, 0x72, 0x17, 0x73, 0x16, 0x74, 0x15, 0x75, 0x15, 0x76, 0x15, +0xd5, 0x00, 0xc6, 0x00, 0xbb, 0x00, 0xb2, 0x00, 0xaa, 0x00, 0xa4, 0x01, +0xa0, 0x02, 0x9c, 0x02, 0x9a, 0x03, 0x97, 0x04, 0x95, 0x05, 0x93, 0x05, +0x92, 0x06, 0x91, 0x06, 0x90, 0x07, 0x8e, 0x07, 0x8e, 0x07, 0x8d, 0x07, +0x8c, 0x08, 0x8c, 0x09, 0x22, 0x1a, 0x33, 0x13, 0x41, 0x11, 0x4c, 0x11, +0x54, 0x11, 0x5b, 0x11, 0x5f, 0x11, 0x63, 0x11, 0x66, 0x11, 0x68, 0x11, +0x6a, 0x11, 0x6c, 0x11, 0x6e, 0x11, 0x6f, 0x11, 0x70, 0x11, 0x71, 0x11, +0x72, 0x11, 0x72, 0x11, 0x73, 0x11, 0x74, 0x11, 0x7f, 0x11, 0x7f, 0x11, +0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, +0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, +0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x07, 0x7f, 0x00, +0xa5, 0x00, 0xb2, 0x00, 0xb7, 0x00, 0xba, 0x00, 0xbb, 0x00, 0xbc, 0x00, +0xbd, 0x00, 0xbd, 0x00, 0xbd, 0x00, 0xbe, 0x00, 0xbe, 0x00, 0xbe, 0x00, +0xbe, 0x00, 0xbe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x47, 0x07, 0x0f, 0x0f, 0x00, 0x26, 0x00, 0x33, 0x00, 0x38, 0x00, 0x3a, +0x00, 0x3c, 0x00, 0x3d, 0x00, 0x3d, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3e, +0x00, 0x3e, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x46, 0x31, 0x50, 0x2b, 0x56, 0x27, 0x5b, 0x24, +0x5f, 0x22, 0x62, 0x20, 0x65, 0x1f, 0x67, 0x1d, 0x69, 0x1d, 0x6a, 0x1b, +0x6c, 0x1a, 0x6d, 0x1a, 0x6d, 0x1a, 0x6e, 0x19, 0x6f, 0x18, 0x71, 0x18, +0x72, 0x18, 0x72, 0x18, 0x72, 0x18, 0x72, 0x17, 0xd6, 0x00, 0xcb, 0x00, +0xc0, 0x00, 0xb8, 0x00, 0xb1, 0x00, 0xab, 0x00, 0xa6, 0x01, 0xa2, 0x01, +0x9f, 0x02, 0x9c, 0x02, 0x9a, 0x03, 0x98, 0x03, 0x96, 0x04, 0x94, 0x05, +0x93, 0x05, 0x92, 0x06, 0x91, 0x06, 0x90, 0x06, 0x8f, 0x06, 0x8f, 0x07, +0x22, 0x1b, 0x2f, 0x15, 0x3b, 0x12, 0x44, 0x11, 0x4d, 0x11, 0x53, 0x11, +0x59, 0x11, 0x5d, 0x11, 0x60, 0x11, 0x63, 0x11, 0x66, 0x11, 0x67, 0x11, +0x69, 0x11, 0x6b, 0x11, 0x6c, 0x11, 0x6d, 0x11, 0x6e, 0x11, 0x6f, 0x11, +0x70, 0x11, 0x71, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, +0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, +0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, +0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x0f, 0x0f, 0x3f, 0x00, 0x7f, 0x00, 0x9c, 0x00, +0xaa, 0x00, 0xb1, 0x00, 0xb5, 0x00, 0xb7, 0x00, 0xb9, 0x00, 0xba, 0x00, +0xbb, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbd, 0x00, 0xbd, 0x00, 0xbd, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x3f, 0x00, +0x05, 0x05, 0x00, 0x1c, 0x00, 0x2a, 0x00, 0x31, 0x00, 0x35, 0x00, 0x38, +0x00, 0x39, 0x00, 0x3b, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3d, 0x00, 0x3d, +0x00, 0x3d, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x45, 0x33, 0x4d, 0x2e, 0x53, 0x29, 0x58, 0x26, 0x5c, 0x24, 0x5f, 0x22, +0x61, 0x21, 0x65, 0x20, 0x65, 0x1e, 0x68, 0x1d, 0x69, 0x1d, 0x6a, 0x1b, +0x6b, 0x1a, 0x6d, 0x1a, 0x6d, 0x1a, 0x6d, 0x1a, 0x6e, 0x19, 0x6f, 0x18, +0x71, 0x18, 0x72, 0x18, 0xd7, 0x00, 0xcd, 0x00, 0xc5, 0x00, 0xbd, 0x00, +0xb6, 0x00, 0xb0, 0x00, 0xab, 0x00, 0xa7, 0x00, 0xa4, 0x01, 0xa1, 0x02, +0x9e, 0x02, 0x9c, 0x02, 0x9a, 0x03, 0x98, 0x03, 0x97, 0x03, 0x96, 0x04, +0x94, 0x05, 0x93, 0x05, 0x92, 0x05, 0x91, 0x06, 0x21, 0x1c, 0x2d, 0x16, +0x37, 0x13, 0x40, 0x11, 0x47, 0x11, 0x4e, 0x11, 0x53, 0x11, 0x57, 0x11, +0x5b, 0x11, 0x5e, 0x11, 0x61, 0x11, 0x63, 0x11, 0x65, 0x11, 0x67, 0x11, +0x68, 0x11, 0x6a, 0x11, 0x6b, 0x11, 0x6c, 0x11, 0x6d, 0x11, 0x6e, 0x11, +0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, +0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, +0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, +0x7f, 0x11, 0x7f, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x26, 0x05, 0x05, 0x3f, 0x00, 0x6d, 0x00, 0x88, 0x00, 0x99, 0x00, +0xa3, 0x00, 0xaa, 0x00, 0xae, 0x00, 0xb1, 0x00, 0xb4, 0x00, 0xb6, 0x00, +0xb7, 0x00, 0xb8, 0x00, 0xb9, 0x00, 0xba, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0xa5, 0x00, 0x7f, 0x00, 0x3f, 0x00, 0x12, 0x00, +0x00, 0x09, 0x00, 0x19, 0x00, 0x23, 0x00, 0x2a, 0x00, 0x2f, 0x00, 0x32, +0x00, 0x34, 0x00, 0x36, 0x00, 0x38, 0x00, 0x39, 0x00, 0x3a, 0x00, 0x3a, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x34, 0x4c, 0x2f, +0x51, 0x2c, 0x56, 0x28, 0x5a, 0x26, 0x5c, 0x24, 0x60, 0x23, 0x61, 0x21, +0x64, 0x20, 0x65, 0x1f, 0x66, 0x1d, 0x69, 0x1d, 0x69, 0x1d, 0x69, 0x1c, +0x6b, 0x1a, 0x6d, 0x1a, 0x6d, 0x1a, 0x6d, 0x1a, 0x6d, 0x1a, 0x6e, 0x19, +0xd8, 0x00, 0xcf, 0x00, 0xc7, 0x00, 0xc0, 0x00, 0xba, 0x00, 0xb5, 0x00, +0xb0, 0x00, 0xac, 0x00, 0xa8, 0x00, 0xa5, 0x01, 0xa2, 0x01, 0xa0, 0x02, +0x9e, 0x02, 0x9c, 0x02, 0x9a, 0x02, 0x99, 0x03, 0x97, 0x03, 0x96, 0x03, +0x95, 0x04, 0x94, 0x05, 0x22, 0x1d, 0x2b, 0x17, 0x34, 0x14, 0x3b, 0x12, +0x43, 0x11, 0x49, 0x11, 0x4e, 0x11, 0x52, 0x11, 0x56, 0x11, 0x5a, 0x11, +0x5d, 0x11, 0x5f, 0x11, 0x61, 0x11, 0x63, 0x11, 0x65, 0x11, 0x66, 0x11, +0x68, 0x11, 0x69, 0x11, 0x6a, 0x11, 0x6b, 0x11, 0x7f, 0x11, 0x7f, 0x11, +0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, +0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, +0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x00, 0x1c, +0x12, 0x00, 0x3f, 0x00, 0x62, 0x00, 0x7a, 0x00, 0x8a, 0x00, 0x96, 0x00, +0x9e, 0x00, 0xa4, 0x00, 0xa9, 0x00, 0xac, 0x00, 0xaf, 0x00, 0xb1, 0x00, +0xb3, 0x00, 0xb4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0xb2, 0x00, 0x9c, 0x00, 0x6d, 0x00, 0x3f, 0x00, 0x1d, 0x00, 0x05, 0x00, +0x00, 0x0b, 0x00, 0x16, 0x00, 0x1f, 0x00, 0x25, 0x00, 0x29, 0x00, 0x2d, +0x00, 0x30, 0x00, 0x32, 0x00, 0x33, 0x00, 0x35, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x44, 0x36, 0x4a, 0x31, 0x50, 0x2d, 0x54, 0x2a, +0x57, 0x28, 0x5b, 0x26, 0x5c, 0x24, 0x60, 0x23, 0x61, 0x21, 0x63, 0x20, +0x65, 0x20, 0x65, 0x1e, 0x67, 0x1d, 0x69, 0x1d, 0x69, 0x1d, 0x69, 0x1c, +0x6a, 0x1b, 0x6d, 0x1a, 0x6d, 0x1a, 0x6d, 0x1a, 0xd9, 0x00, 0xd1, 0x00, +0xca, 0x00, 0xc3, 0x00, 0xbe, 0x00, 0xb9, 0x00, 0xb4, 0x00, 0xb0, 0x00, +0xac, 0x00, 0xa9, 0x00, 0xa6, 0x00, 0xa3, 0x01, 0xa1, 0x01, 0x9f, 0x02, +0x9d, 0x02, 0x9b, 0x02, 0x9a, 0x02, 0x99, 0x03, 0x98, 0x03, 0x97, 0x03, +0x21, 0x1e, 0x2a, 0x18, 0x32, 0x15, 0x39, 0x13, 0x3f, 0x12, 0x45, 0x11, +0x4a, 0x11, 0x4e, 0x11, 0x52, 0x11, 0x56, 0x11, 0x59, 0x11, 0x5c, 0x11, +0x5d, 0x11, 0x60, 0x11, 0x61, 0x11, 0x63, 0x11, 0x65, 0x11, 0x66, 0x11, +0x67, 0x11, 0x68, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, +0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, +0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, +0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x2a, 0x00, 0x09, 0x1d, 0x00, +0x3f, 0x00, 0x5b, 0x00, 0x6f, 0x00, 0x7f, 0x00, 0x8b, 0x00, 0x94, 0x00, +0x9b, 0x00, 0xa0, 0x00, 0xa5, 0x00, 0xa8, 0x00, 0xab, 0x00, 0xad, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb7, 0x00, 0xaa, 0x00, +0x88, 0x00, 0x62, 0x00, 0x3f, 0x00, 0x24, 0x00, 0x0f, 0x00, 0x00, 0x00, +0x00, 0x0b, 0x00, 0x14, 0x00, 0x1b, 0x00, 0x21, 0x00, 0x25, 0x00, 0x29, +0x00, 0x2b, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x43, 0x36, 0x49, 0x32, 0x4e, 0x2f, 0x52, 0x2c, 0x56, 0x29, 0x58, 0x27, +0x5b, 0x26, 0x5d, 0x24, 0x60, 0x23, 0x60, 0x22, 0x62, 0x20, 0x65, 0x20, +0x65, 0x1f, 0x66, 0x1e, 0x68, 0x1d, 0x69, 0x1d, 0x69, 0x1d, 0x69, 0x1c, +0x6a, 0x1b, 0x6c, 0x1a, 0xd9, 0x00, 0xd2, 0x00, 0xcc, 0x00, 0xc6, 0x00, +0xc1, 0x00, 0xbc, 0x00, 0xb7, 0x00, 0xb3, 0x00, 0xaf, 0x00, 0xac, 0x00, +0xa9, 0x00, 0xa6, 0x00, 0xa4, 0x01, 0xa2, 0x01, 0xa0, 0x01, 0x9e, 0x02, +0x9d, 0x02, 0x9c, 0x02, 0x9a, 0x02, 0x99, 0x02, 0x22, 0x1e, 0x29, 0x19, +0x30, 0x16, 0x36, 0x13, 0x3c, 0x12, 0x41, 0x11, 0x46, 0x11, 0x4a, 0x11, +0x4f, 0x11, 0x52, 0x11, 0x55, 0x11, 0x58, 0x11, 0x5a, 0x11, 0x5c, 0x11, +0x5f, 0x11, 0x60, 0x11, 0x62, 0x11, 0x63, 0x11, 0x65, 0x11, 0x66, 0x11, +0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, +0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, +0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, +0x7f, 0x11, 0x7f, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x3a, 0x00, 0x31, 0x00, 0x19, 0x05, 0x00, 0x24, 0x00, 0x3f, 0x00, +0x56, 0x00, 0x68, 0x00, 0x77, 0x00, 0x82, 0x00, 0x8b, 0x00, 0x93, 0x00, +0x99, 0x00, 0x9d, 0x00, 0xa1, 0x00, 0xa5, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0xba, 0x00, 0xb1, 0x00, 0x99, 0x00, 0x7a, 0x00, +0x5b, 0x00, 0x3f, 0x00, 0x29, 0x00, 0x16, 0x00, 0x08, 0x00, 0x00, 0x02, +0x00, 0x0c, 0x00, 0x13, 0x00, 0x19, 0x00, 0x1e, 0x00, 0x22, 0x00, 0x25, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0x37, 0x48, 0x33, +0x4d, 0x30, 0x51, 0x2d, 0x54, 0x2a, 0x57, 0x29, 0x59, 0x27, 0x5c, 0x26, +0x5d, 0x24, 0x60, 0x23, 0x60, 0x22, 0x62, 0x20, 0x65, 0x20, 0x65, 0x20, +0x65, 0x1f, 0x66, 0x1d, 0x69, 0x1d, 0x69, 0x1d, 0x69, 0x1d, 0x69, 0x1d, +0xd9, 0x00, 0xd3, 0x00, 0xcd, 0x00, 0xc8, 0x00, 0xc3, 0x00, 0xbe, 0x00, +0xba, 0x00, 0xb6, 0x00, 0xb2, 0x00, 0xaf, 0x00, 0xad, 0x00, 0xaa, 0x00, +0xa7, 0x00, 0xa5, 0x00, 0xa3, 0x01, 0xa1, 0x01, 0xa0, 0x02, 0x9e, 0x02, +0x9d, 0x02, 0x9c, 0x02, 0x21, 0x1e, 0x28, 0x1a, 0x2e, 0x17, 0x34, 0x14, +0x39, 0x13, 0x3f, 0x12, 0x43, 0x11, 0x48, 0x11, 0x4b, 0x11, 0x4f, 0x11, +0x52, 0x11, 0x55, 0x11, 0x57, 0x11, 0x59, 0x11, 0x5c, 0x11, 0x5d, 0x11, +0x5f, 0x11, 0x61, 0x11, 0x62, 0x11, 0x63, 0x11, 0x7f, 0x11, 0x7f, 0x11, +0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, +0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, +0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x35, +0x00, 0x23, 0x00, 0x0b, 0x0f, 0x00, 0x29, 0x00, 0x3f, 0x00, 0x53, 0x00, +0x63, 0x00, 0x70, 0x00, 0x7b, 0x00, 0x84, 0x00, 0x8b, 0x00, 0x92, 0x00, +0x97, 0x00, 0x9b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0xbb, 0x00, 0xb5, 0x00, 0xa3, 0x00, 0x8a, 0x00, 0x6f, 0x00, 0x56, 0x00, +0x3f, 0x00, 0x2c, 0x00, 0x1c, 0x00, 0x0f, 0x00, 0x04, 0x00, 0x00, 0x04, +0x00, 0x0c, 0x00, 0x12, 0x00, 0x17, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x43, 0x38, 0x48, 0x34, 0x4c, 0x31, 0x4f, 0x2e, +0x53, 0x2c, 0x56, 0x2a, 0x57, 0x28, 0x5a, 0x27, 0x5c, 0x26, 0x5d, 0x23, +0x60, 0x23, 0x60, 0x23, 0x61, 0x21, 0x64, 0x20, 0x65, 0x20, 0x65, 0x20, +0x65, 0x1e, 0x67, 0x1d, 0x69, 0x1d, 0x69, 0x1d, 0xd9, 0x00, 0xd4, 0x00, +0xce, 0x00, 0xca, 0x00, 0xc5, 0x00, 0xc1, 0x00, 0xbd, 0x00, 0xb9, 0x00, +0xb6, 0x00, 0xb2, 0x00, 0xaf, 0x00, 0xad, 0x00, 0xaa, 0x00, 0xa8, 0x00, +0xa6, 0x00, 0xa4, 0x01, 0xa2, 0x01, 0xa0, 0x01, 0x9f, 0x02, 0x9e, 0x02, +0x22, 0x1f, 0x27, 0x1a, 0x2d, 0x17, 0x33, 0x15, 0x38, 0x13, 0x3c, 0x13, +0x41, 0x12, 0x44, 0x11, 0x48, 0x11, 0x4c, 0x11, 0x4f, 0x11, 0x51, 0x11, +0x54, 0x11, 0x57, 0x11, 0x59, 0x11, 0x5b, 0x11, 0x5c, 0x11, 0x5e, 0x11, +0x5f, 0x11, 0x61, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, +0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, +0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, +0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x38, 0x00, 0x2a, 0x00, 0x16, +0x00, 0x00, 0x16, 0x00, 0x2c, 0x00, 0x3f, 0x00, 0x50, 0x00, 0x5e, 0x00, +0x6b, 0x00, 0x75, 0x00, 0x7e, 0x00, 0x85, 0x00, 0x8b, 0x00, 0x91, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbc, 0x00, 0xb7, 0x00, +0xaa, 0x00, 0x96, 0x00, 0x7f, 0x00, 0x68, 0x00, 0x53, 0x00, 0x3f, 0x00, +0x2e, 0x00, 0x20, 0x00, 0x14, 0x00, 0x0a, 0x00, 0x01, 0x00, 0x00, 0x06, +0x00, 0x0c, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x43, 0x38, 0x47, 0x35, 0x4b, 0x32, 0x4e, 0x2f, 0x52, 0x2d, 0x53, 0x2b, +0x57, 0x2a, 0x58, 0x27, 0x5b, 0x27, 0x5c, 0x25, 0x5d, 0x23, 0x60, 0x23, +0x60, 0x23, 0x61, 0x21, 0x64, 0x20, 0x65, 0x20, 0x65, 0x20, 0x65, 0x1f, +0x66, 0x1e, 0x68, 0x1d, 0xda, 0x00, 0xd4, 0x00, 0xd0, 0x00, 0xcb, 0x00, +0xc7, 0x00, 0xc2, 0x00, 0xbe, 0x00, 0xbb, 0x00, 0xb8, 0x00, 0xb5, 0x00, +0xb2, 0x00, 0xaf, 0x00, 0xad, 0x00, 0xaa, 0x00, 0xa8, 0x00, 0xa6, 0x00, +0xa4, 0x00, 0xa3, 0x01, 0xa1, 0x01, 0xa0, 0x01, 0x21, 0x1f, 0x27, 0x1b, +0x2c, 0x18, 0x31, 0x16, 0x36, 0x14, 0x3a, 0x13, 0x3e, 0x12, 0x42, 0x11, +0x45, 0x11, 0x49, 0x11, 0x4c, 0x11, 0x4f, 0x11, 0x51, 0x11, 0x54, 0x11, +0x56, 0x11, 0x58, 0x11, 0x5a, 0x11, 0x5c, 0x11, 0x5d, 0x11, 0x5e, 0x11, +0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, +0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, +0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, +0x7f, 0x11, 0x7f, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x3d, 0x00, 0x39, 0x00, 0x2f, 0x00, 0x1f, 0x00, 0x0b, 0x08, 0x00, +0x1c, 0x00, 0x2e, 0x00, 0x3f, 0x00, 0x4e, 0x00, 0x5b, 0x00, 0x66, 0x00, +0x70, 0x00, 0x78, 0x00, 0x80, 0x00, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0xbd, 0x00, 0xb9, 0x00, 0xae, 0x00, 0x9e, 0x00, +0x8b, 0x00, 0x77, 0x00, 0x63, 0x00, 0x50, 0x00, 0x3f, 0x00, 0x30, 0x00, +0x23, 0x00, 0x18, 0x00, 0x0e, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x07, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x39, 0x46, 0x35, +0x4a, 0x32, 0x4e, 0x30, 0x50, 0x2e, 0x53, 0x2c, 0x55, 0x2a, 0x57, 0x29, +0x58, 0x27, 0x5c, 0x27, 0x5c, 0x25, 0x5d, 0x23, 0x60, 0x23, 0x60, 0x23, +0x60, 0x22, 0x63, 0x20, 0x65, 0x20, 0x65, 0x20, 0x65, 0x20, 0x65, 0x1f, +0xda, 0x00, 0xd5, 0x00, 0xd1, 0x00, 0xcc, 0x00, 0xc8, 0x00, 0xc4, 0x00, +0xc1, 0x00, 0xbd, 0x00, 0xba, 0x00, 0xb7, 0x00, 0xb4, 0x00, 0xb2, 0x00, +0xaf, 0x00, 0xad, 0x00, 0xaa, 0x00, 0xa9, 0x00, 0xa7, 0x00, 0xa5, 0x00, +0xa4, 0x01, 0xa2, 0x01, 0x22, 0x1f, 0x27, 0x1b, 0x2c, 0x18, 0x30, 0x16, +0x35, 0x14, 0x39, 0x13, 0x3d, 0x13, 0x40, 0x12, 0x44, 0x11, 0x47, 0x11, +0x49, 0x11, 0x4c, 0x11, 0x4f, 0x11, 0x51, 0x11, 0x54, 0x11, 0x56, 0x11, +0x58, 0x11, 0x59, 0x11, 0x5b, 0x11, 0x5c, 0x11, 0x7f, 0x11, 0x7f, 0x11, +0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, +0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, +0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x3b, +0x00, 0x32, 0x00, 0x25, 0x00, 0x14, 0x00, 0x02, 0x0f, 0x00, 0x20, 0x00, +0x30, 0x00, 0x3f, 0x00, 0x4d, 0x00, 0x58, 0x00, 0x63, 0x00, 0x6c, 0x00, +0x74, 0x00, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0xbd, 0x00, 0xba, 0x00, 0xb1, 0x00, 0xa4, 0x00, 0x94, 0x00, 0x82, 0x00, +0x70, 0x00, 0x5e, 0x00, 0x4e, 0x00, 0x3f, 0x00, 0x32, 0x00, 0x26, 0x00, +0x1c, 0x00, 0x13, 0x00, 0x0b, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x42, 0x39, 0x46, 0x36, 0x4a, 0x33, 0x4d, 0x31, +0x4f, 0x2e, 0x52, 0x2d, 0x53, 0x2b, 0x57, 0x2a, 0x57, 0x28, 0x5a, 0x27, +0x5c, 0x27, 0x5c, 0x25, 0x5e, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x22, +0x62, 0x20, 0x65, 0x20, 0x65, 0x20, 0x65, 0x20, 0xda, 0x00, 0xd6, 0x00, +0xd1, 0x00, 0xcd, 0x00, 0xc9, 0x00, 0xc6, 0x00, 0xc2, 0x00, 0xbf, 0x00, +0xbc, 0x00, 0xb9, 0x00, 0xb6, 0x00, 0xb3, 0x00, 0xb1, 0x00, 0xaf, 0x00, +0xad, 0x00, 0xab, 0x00, 0xa9, 0x00, 0xa7, 0x00, 0xa6, 0x00, 0xa4, 0x00, +0x21, 0x1f, 0x26, 0x1c, 0x2b, 0x19, 0x2f, 0x17, 0x33, 0x15, 0x37, 0x14, +0x3b, 0x13, 0x3e, 0x12, 0x41, 0x12, 0x44, 0x11, 0x47, 0x11, 0x4a, 0x11, +0x4d, 0x11, 0x4f, 0x11, 0x51, 0x11, 0x54, 0x11, 0x55, 0x11, 0x57, 0x11, +0x59, 0x11, 0x5a, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, +0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, +0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, +0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x3c, 0x00, 0x34, 0x00, 0x29, +0x00, 0x1b, 0x00, 0x0c, 0x04, 0x00, 0x14, 0x00, 0x23, 0x00, 0x32, 0x00, +0x3f, 0x00, 0x4b, 0x00, 0x56, 0x00, 0x60, 0x00, 0x68, 0x00, 0x70, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbd, 0x00, 0xbb, 0x00, +0xb4, 0x00, 0xa9, 0x00, 0x9b, 0x00, 0x8b, 0x00, 0x7b, 0x00, 0x6b, 0x00, +0x5b, 0x00, 0x4d, 0x00, 0x3f, 0x00, 0x33, 0x00, 0x28, 0x00, 0x1f, 0x00, +0x16, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x42, 0x39, 0x45, 0x36, 0x49, 0x34, 0x4c, 0x31, 0x4f, 0x30, 0x51, 0x2e, +0x53, 0x2c, 0x55, 0x2a, 0x57, 0x2a, 0x57, 0x28, 0x5b, 0x27, 0x5c, 0x27, +0x5c, 0x25, 0x5e, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x22, 0x61, 0x21, +0x64, 0x20, 0x65, 0x20, 0xda, 0x00, 0xd6, 0x00, 0xd2, 0x00, 0xce, 0x00, +0xcb, 0x00, 0xc7, 0x00, 0xc4, 0x00, 0xc1, 0x00, 0xbe, 0x00, 0xbb, 0x00, +0xb8, 0x00, 0xb6, 0x00, 0xb3, 0x00, 0xb1, 0x00, 0xaf, 0x00, 0xad, 0x00, +0xab, 0x00, 0xa9, 0x00, 0xa8, 0x00, 0xa6, 0x00, 0x22, 0x1f, 0x26, 0x1c, +0x2a, 0x19, 0x2e, 0x17, 0x32, 0x16, 0x36, 0x14, 0x39, 0x13, 0x3d, 0x13, +0x40, 0x12, 0x43, 0x11, 0x45, 0x11, 0x48, 0x11, 0x4b, 0x11, 0x4d, 0x11, +0x4f, 0x11, 0x51, 0x11, 0x53, 0x11, 0x55, 0x11, 0x56, 0x11, 0x58, 0x11, +0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, +0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, +0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, +0x7f, 0x11, 0x7f, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x3e, 0x00, 0x3c, 0x00, 0x36, 0x00, 0x2d, 0x00, 0x21, 0x00, 0x13, +0x00, 0x04, 0x0a, 0x00, 0x18, 0x00, 0x26, 0x00, 0x33, 0x00, 0x3f, 0x00, +0x4a, 0x00, 0x54, 0x00, 0x5d, 0x00, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0xbe, 0x00, 0xbc, 0x00, 0xb6, 0x00, 0xac, 0x00, +0xa0, 0x00, 0x93, 0x00, 0x84, 0x00, 0x75, 0x00, 0x66, 0x00, 0x58, 0x00, +0x4b, 0x00, 0x3f, 0x00, 0x34, 0x00, 0x2a, 0x00, 0x21, 0x00, 0x19, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x3a, 0x45, 0x37, +0x48, 0x35, 0x4a, 0x32, 0x4e, 0x31, 0x50, 0x2e, 0x53, 0x2e, 0x53, 0x2b, +0x57, 0x2a, 0x57, 0x29, 0x58, 0x27, 0x5b, 0x27, 0x5c, 0x27, 0x5c, 0x25, +0x5e, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x61, 0x21, 0x64, 0x20, +0xdb, 0x00, 0xd7, 0x00, 0xd3, 0x00, 0xcf, 0x00, 0xcc, 0x00, 0xc8, 0x00, +0xc5, 0x00, 0xc2, 0x00, 0xbf, 0x00, 0xbc, 0x00, 0xba, 0x00, 0xb7, 0x00, +0xb5, 0x00, 0xb3, 0x00, 0xb1, 0x00, 0xaf, 0x00, 0xad, 0x00, 0xab, 0x00, +0xa9, 0x00, 0xa8, 0x00, 0x21, 0x20, 0x26, 0x1c, 0x2a, 0x1a, 0x2d, 0x18, +0x31, 0x16, 0x35, 0x14, 0x38, 0x13, 0x3b, 0x13, 0x3e, 0x12, 0x41, 0x12, +0x44, 0x11, 0x46, 0x11, 0x49, 0x11, 0x4b, 0x11, 0x4d, 0x11, 0x4f, 0x11, +0x51, 0x11, 0x53, 0x11, 0x55, 0x11, 0x56, 0x11, 0x7f, 0x11, 0x7f, 0x11, +0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, +0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, +0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x3d, +0x00, 0x38, 0x00, 0x30, 0x00, 0x25, 0x00, 0x19, 0x00, 0x0c, 0x01, 0x00, +0x0e, 0x00, 0x1c, 0x00, 0x28, 0x00, 0x34, 0x00, 0x3f, 0x00, 0x49, 0x00, +0x53, 0x00, 0x5b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0xbe, 0x00, 0xbc, 0x00, 0xb7, 0x00, 0xaf, 0x00, 0xa5, 0x00, 0x99, 0x00, +0x8b, 0x00, 0x7e, 0x00, 0x70, 0x00, 0x63, 0x00, 0x56, 0x00, 0x4a, 0x00, +0x3f, 0x00, 0x35, 0x00, 0x2c, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x42, 0x3a, 0x45, 0x37, 0x48, 0x35, 0x4a, 0x33, +0x4d, 0x31, 0x4f, 0x2f, 0x52, 0x2e, 0x53, 0x2c, 0x55, 0x2a, 0x57, 0x2a, +0x57, 0x29, 0x59, 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x5c, 0x25, 0x5f, 0x23, +0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x22, 0xdb, 0x00, 0xd7, 0x00, +0xd3, 0x00, 0xd0, 0x00, 0xcc, 0x00, 0xc9, 0x00, 0xc6, 0x00, 0xc3, 0x00, +0xc1, 0x00, 0xbe, 0x00, 0xbb, 0x00, 0xb9, 0x00, 0xb7, 0x00, 0xb5, 0x00, +0xb3, 0x00, 0xb0, 0x00, 0xaf, 0x00, 0xad, 0x00, 0xab, 0x00, 0xaa, 0x00, +0x21, 0x20, 0x25, 0x1d, 0x29, 0x1a, 0x2d, 0x18, 0x30, 0x17, 0x33, 0x15, +0x37, 0x14, 0x3a, 0x13, 0x3d, 0x13, 0x3f, 0x12, 0x42, 0x12, 0x44, 0x11, +0x47, 0x11, 0x49, 0x11, 0x4b, 0x11, 0x4d, 0x11, 0x4f, 0x11, 0x51, 0x11, +0x53, 0x11, 0x55, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, +0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, +0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, +0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x3d, 0x00, 0x39, 0x00, 0x32, +0x00, 0x29, 0x00, 0x1e, 0x00, 0x12, 0x00, 0x06, 0x06, 0x00, 0x13, 0x00, +0x1f, 0x00, 0x2a, 0x00, 0x35, 0x00, 0x3f, 0x00, 0x49, 0x00, 0x51, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x00, 0xbd, 0x00, +0xb8, 0x00, 0xb1, 0x00, 0xa8, 0x00, 0x9d, 0x00, 0x92, 0x00, 0x85, 0x00, +0x78, 0x00, 0x6c, 0x00, 0x60, 0x00, 0x54, 0x00, 0x49, 0x00, 0x3f, 0x00, +0x36, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x42, 0x3a, 0x45, 0x38, 0x47, 0x35, 0x4a, 0x33, 0x4d, 0x31, 0x4f, 0x30, +0x51, 0x2e, 0x53, 0x2e, 0x53, 0x2b, 0x56, 0x2a, 0x57, 0x2a, 0x57, 0x28, +0x5a, 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x5c, 0x25, 0x5f, 0x23, 0x60, 0x23, +0x60, 0x23, 0x60, 0x23, 0xdb, 0x00, 0xd7, 0x00, 0xd4, 0x00, 0xd0, 0x00, +0xcd, 0x00, 0xca, 0x00, 0xc7, 0x00, 0xc5, 0x00, 0xc2, 0x00, 0xbf, 0x00, +0xbd, 0x00, 0xbb, 0x00, 0xb8, 0x00, 0xb6, 0x00, 0xb4, 0x00, 0xb2, 0x00, +0xb0, 0x00, 0xaf, 0x00, 0xad, 0x00, 0xac, 0x00, 0x21, 0x20, 0x25, 0x1d, +0x29, 0x1a, 0x2c, 0x18, 0x2f, 0x17, 0x33, 0x16, 0x36, 0x14, 0x39, 0x13, +0x3b, 0x13, 0x3e, 0x13, 0x41, 0x12, 0x43, 0x11, 0x45, 0x11, 0x47, 0x11, +0x4a, 0x11, 0x4c, 0x11, 0x4e, 0x11, 0x4f, 0x11, 0x51, 0x11, 0x52, 0x11, +0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, +0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, +0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, +0x7f, 0x11, 0x7f, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x3f, 0x00, 0x3d, 0x00, 0x3a, 0x00, 0x33, 0x00, 0x2b, 0x00, 0x22, +0x00, 0x17, 0x00, 0x0c, 0x00, 0x00, 0x0b, 0x00, 0x16, 0x00, 0x21, 0x00, +0x2c, 0x00, 0x36, 0x00, 0x3f, 0x00, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0xbe, 0x00, 0xbd, 0x00, 0xb9, 0x00, 0xb3, 0x00, +0xab, 0x00, 0xa1, 0x00, 0x97, 0x00, 0x8b, 0x00, 0x80, 0x00, 0x74, 0x00, +0x68, 0x00, 0x5d, 0x00, 0x53, 0x00, 0x49, 0x00, 0x3f, 0x00, 0x36, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x3b, 0x44, 0x39, +0x46, 0x35, 0x4a, 0x34, 0x4c, 0x31, 0x4f, 0x31, 0x4f, 0x2e, 0x53, 0x2e, +0x53, 0x2c, 0x55, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x58, 0x27, 0x5b, 0x27, +0x5c, 0x27, 0x5c, 0x27, 0x5c, 0x24, 0x5f, 0x23, 0x60, 0x23, 0x60, 0x23, +0xdb, 0x00, 0xd8, 0x00, 0xd4, 0x00, 0xd1, 0x00, 0xce, 0x00, 0xcb, 0x00, +0xc8, 0x00, 0xc6, 0x00, 0xc3, 0x00, 0xc1, 0x00, 0xbe, 0x00, 0xbc, 0x00, +0xba, 0x00, 0xb8, 0x00, 0xb6, 0x00, 0xb4, 0x00, 0xb2, 0x00, 0xb0, 0x00, +0xaf, 0x00, 0xad, 0x00, 0x21, 0x20, 0x25, 0x1d, 0x28, 0x1b, 0x2b, 0x18, +0x2f, 0x17, 0x32, 0x16, 0x35, 0x14, 0x38, 0x14, 0x3a, 0x13, 0x3d, 0x13, +0x3f, 0x12, 0x42, 0x12, 0x44, 0x11, 0x46, 0x11, 0x48, 0x11, 0x4a, 0x11, +0x4c, 0x11, 0x4e, 0x11, 0x4f, 0x11, 0x51, 0x11, 0x7f, 0x11, 0x7f, 0x11, +0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, +0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, +0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x3e, +0x00, 0x3a, 0x00, 0x35, 0x00, 0x2e, 0x00, 0x25, 0x00, 0x1c, 0x00, 0x11, +0x00, 0x07, 0x03, 0x00, 0x0e, 0x00, 0x19, 0x00, 0x23, 0x00, 0x2d, 0x00, +0x36, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0xbe, 0x00, 0xbd, 0x00, 0xba, 0x00, 0xb4, 0x00, 0xad, 0x00, 0xa5, 0x00, +0x9b, 0x00, 0x91, 0x00, 0x86, 0x00, 0x7b, 0x00, 0x70, 0x00, 0x65, 0x00, +0x5b, 0x00, 0x51, 0x00, 0x48, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x42, 0x3b, 0x44, 0x39, 0x46, 0x36, 0x4a, 0x35, +0x4a, 0x32, 0x4e, 0x31, 0x4f, 0x2f, 0x51, 0x2e, 0x53, 0x2e, 0x53, 0x2b, +0x56, 0x2a, 0x57, 0x2a, 0x57, 0x29, 0x59, 0x27, 0x5c, 0x27, 0x5c, 0x27, +0x5c, 0x26, 0x5c, 0x24, 0x5f, 0x23, 0x60, 0x23, 0xdb, 0x00, 0xd8, 0x00, +0xd5, 0x00, 0xd2, 0x00, 0xcf, 0x00, 0xcc, 0x00, 0xca, 0x00, 0xc6, 0x00, +0xc4, 0x00, 0xc2, 0x00, 0xbf, 0x00, 0xbd, 0x00, 0xbb, 0x00, 0xb9, 0x00, +0xb8, 0x00, 0xb5, 0x00, 0xb4, 0x00, 0xb2, 0x00, 0xb0, 0x00, 0xaf, 0x00, +0x21, 0x20, 0x25, 0x1d, 0x28, 0x1b, 0x2b, 0x19, 0x2e, 0x17, 0x31, 0x16, +0x34, 0x15, 0x37, 0x14, 0x39, 0x13, 0x3b, 0x13, 0x3e, 0x13, 0x40, 0x12, +0x42, 0x12, 0x45, 0x11, 0x46, 0x11, 0x49, 0x11, 0x4a, 0x11, 0x4c, 0x11, +0x4e, 0x11, 0x4f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, +0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, +0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, +0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x7f, 0x11, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x40, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x27, 0x68, 0x32, 0x51, 0x36, 0x4a, 0x38, 0x47, +0x3a, 0x46, 0x3a, 0x45, 0x3b, 0x44, 0x3c, 0x43, 0x3c, 0x43, 0x3c, 0x43, +0x3c, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x41, +0x3d, 0x41, 0x3d, 0x41, 0x3d, 0x41, 0x3d, 0x41, 0x41, 0x0e, 0x16, 0x27, +0x23, 0x31, 0x2a, 0x35, 0x2e, 0x38, 0x31, 0x39, 0x33, 0x3a, 0x34, 0x3b, +0x35, 0x3b, 0x36, 0x3c, 0x37, 0x3c, 0x38, 0x3c, 0x38, 0x3c, 0x39, 0x3d, +0x39, 0x3d, 0x3a, 0x3d, 0x3a, 0x3d, 0x3a, 0x3d, 0x3a, 0x3d, 0x3b, 0x3d, +0x68, 0x00, 0x32, 0x27, 0x36, 0x31, 0x38, 0x35, 0x3a, 0x38, 0x3a, 0x39, +0x3b, 0x3a, 0x3c, 0x3b, 0x3c, 0x3b, 0x3c, 0x3c, 0x3c, 0x3c, 0x3d, 0x3c, +0x3d, 0x3c, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, +0x3d, 0x3d, 0x3d, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x5f, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x22, 0x32, 0x28, 0x36, 0x2c, 0x38, 0x2f, 0x3a, 0x32, 0x3a, 0x34, 0x3b, +0x35, 0x3c, 0x36, 0x3c, 0x37, 0x3c, 0x37, 0x3c, 0x38, 0x3d, 0x39, 0x3d, +0x39, 0x3d, 0x39, 0x3d, 0x3a, 0x3d, 0x3a, 0x3d, 0x3a, 0x3d, 0x3a, 0x3d, +0x3b, 0x3d, 0x3b, 0x3d, 0x00, 0x97, 0x01, 0x67, 0x09, 0x56, 0x11, 0x4f, +0x17, 0x4b, 0x1c, 0x49, 0x20, 0x47, 0x23, 0x46, 0x25, 0x45, 0x28, 0x44, +0x2a, 0x44, 0x2b, 0x43, 0x2c, 0x43, 0x2e, 0x43, 0x2f, 0x42, 0x30, 0x42, +0x31, 0x42, 0x31, 0x42, 0x32, 0x42, 0x33, 0x42, 0x1a, 0x5c, 0x25, 0x4f, +0x2a, 0x4a, 0x2e, 0x48, 0x31, 0x46, 0x33, 0x45, 0x34, 0x44, 0x36, 0x44, +0x37, 0x43, 0x37, 0x43, 0x38, 0x43, 0x38, 0x42, 0x39, 0x42, 0x39, 0x42, +0x39, 0x41, 0x3a, 0x41, 0x3a, 0x41, 0x3a, 0x41, 0x3b, 0x41, 0x3b, 0x41, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0x00, 0x5f, +0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x33, 0x00, 0x1f, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x22, 0x28, 0x25, 0x2d, +0x28, 0x30, 0x2b, 0x32, 0x2e, 0x34, 0x2f, 0x35, 0x31, 0x36, 0x32, 0x37, +0x33, 0x38, 0x34, 0x38, 0x35, 0x39, 0x36, 0x39, 0x36, 0x39, 0x36, 0x3a, +0x37, 0x3a, 0x37, 0x3a, 0x38, 0x3b, 0x38, 0x3b, 0x39, 0x3b, 0x39, 0x3b, +0x00, 0xb7, 0x00, 0x8b, 0x02, 0x72, 0x07, 0x65, 0x0c, 0x5c, 0x11, 0x57, +0x15, 0x53, 0x18, 0x50, 0x1b, 0x4e, 0x1d, 0x4d, 0x20, 0x4b, 0x22, 0x4a, +0x23, 0x49, 0x25, 0x48, 0x26, 0x48, 0x28, 0x47, 0x29, 0x47, 0x2a, 0x46, +0x2b, 0x46, 0x2c, 0x45, 0x16, 0x6d, 0x1f, 0x5f, 0x24, 0x57, 0x28, 0x53, +0x2b, 0x50, 0x2d, 0x4d, 0x2f, 0x4c, 0x31, 0x4a, 0x32, 0x49, 0x33, 0x48, +0x34, 0x48, 0x35, 0x47, 0x35, 0x46, 0x36, 0x46, 0x36, 0x45, 0x37, 0x45, +0x38, 0x45, 0x38, 0x45, 0x39, 0x44, 0x39, 0x44, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0xac, 0x00, 0x8b, 0x00, 0x44, 0x00, 0x02, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x39, 0x00, 0x2e, 0x00, +0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x22, 0x25, 0x23, 0x28, 0x26, 0x2b, 0x28, 0x2e, +0x2a, 0x2f, 0x2c, 0x31, 0x2e, 0x32, 0x2f, 0x33, 0x30, 0x34, 0x31, 0x35, +0x32, 0x36, 0x33, 0x36, 0x33, 0x36, 0x34, 0x37, 0x35, 0x38, 0x36, 0x38, +0x36, 0x39, 0x36, 0x39, 0x36, 0x39, 0x36, 0x39, 0x00, 0xc5, 0x00, 0xa0, +0x00, 0x87, 0x03, 0x76, 0x06, 0x6b, 0x0a, 0x64, 0x0e, 0x5f, 0x11, 0x5b, +0x13, 0x57, 0x16, 0x55, 0x18, 0x53, 0x1a, 0x51, 0x1c, 0x50, 0x1e, 0x4e, +0x20, 0x4d, 0x21, 0x4c, 0x22, 0x4b, 0x24, 0x4a, 0x25, 0x49, 0x26, 0x48, +0x15, 0x72, 0x1b, 0x66, 0x20, 0x5f, 0x24, 0x5a, 0x27, 0x56, 0x29, 0x53, +0x2c, 0x51, 0x2d, 0x50, 0x2f, 0x4e, 0x30, 0x4d, 0x31, 0x4c, 0x32, 0x4b, +0x32, 0x4a, 0x33, 0x49, 0x34, 0x49, 0x35, 0x48, 0x35, 0x48, 0x35, 0x47, +0x35, 0x46, 0x36, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0xb3, 0x00, 0x9f, 0x00, 0x6d, 0x00, 0x33, 0x00, 0x01, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x35, 0x00, 0x24, 0x00, 0x11, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x22, 0x24, 0x23, 0x26, 0x25, 0x29, 0x27, 0x2b, 0x28, 0x2c, 0x2a, 0x2e, +0x2c, 0x2f, 0x2d, 0x30, 0x2e, 0x31, 0x2f, 0x32, 0x30, 0x33, 0x30, 0x33, +0x32, 0x34, 0x33, 0x35, 0x33, 0x36, 0x33, 0x36, 0x33, 0x36, 0x34, 0x36, +0x35, 0x36, 0x36, 0x37, 0x00, 0xcb, 0x00, 0xad, 0x00, 0x96, 0x01, 0x84, +0x03, 0x78, 0x06, 0x70, 0x09, 0x69, 0x0b, 0x64, 0x0e, 0x60, 0x10, 0x5d, +0x13, 0x59, 0x15, 0x57, 0x17, 0x56, 0x19, 0x54, 0x1a, 0x52, 0x1c, 0x51, +0x1d, 0x50, 0x1f, 0x4f, 0x1f, 0x4f, 0x21, 0x4e, 0x14, 0x75, 0x19, 0x6b, +0x1e, 0x64, 0x22, 0x5f, 0x24, 0x5b, 0x27, 0x58, 0x29, 0x56, 0x2a, 0x54, +0x2c, 0x52, 0x2d, 0x51, 0x2e, 0x4f, 0x2f, 0x4e, 0x30, 0x4e, 0x31, 0x4d, +0x31, 0x4c, 0x32, 0x4a, 0x33, 0x4a, 0x33, 0x4a, 0x34, 0x4a, 0x35, 0x4a, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb7, 0x00, 0xaa, +0x00, 0x85, 0x00, 0x57, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x3d, 0x00, 0x38, 0x00, 0x2c, 0x00, 0x1d, 0x00, 0x0d, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x22, 0x23, 0x23, 0x25, +0x24, 0x27, 0x25, 0x28, 0x27, 0x2a, 0x28, 0x2c, 0x2a, 0x2d, 0x2b, 0x2e, +0x2c, 0x2f, 0x2d, 0x30, 0x2e, 0x31, 0x2f, 0x32, 0x30, 0x32, 0x30, 0x33, +0x31, 0x33, 0x32, 0x33, 0x33, 0x34, 0x33, 0x35, 0x33, 0x36, 0x33, 0x36, +0x00, 0xcf, 0x00, 0xb6, 0x00, 0xa0, 0x00, 0x8f, 0x01, 0x83, 0x03, 0x79, +0x05, 0x72, 0x08, 0x6c, 0x0a, 0x68, 0x0c, 0x64, 0x0f, 0x61, 0x10, 0x5e, +0x12, 0x5b, 0x14, 0x59, 0x16, 0x58, 0x17, 0x56, 0x19, 0x55, 0x1a, 0x53, +0x1b, 0x52, 0x1c, 0x50, 0x13, 0x77, 0x18, 0x6e, 0x1c, 0x68, 0x1f, 0x63, +0x22, 0x5f, 0x24, 0x5c, 0x26, 0x59, 0x28, 0x57, 0x29, 0x56, 0x2a, 0x54, +0x2c, 0x53, 0x2d, 0x52, 0x2e, 0x50, 0x2e, 0x4f, 0x2f, 0x4f, 0x31, 0x4e, +0x31, 0x4d, 0x31, 0x4d, 0x31, 0x4c, 0x32, 0x4a, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0xba, 0x00, 0xb0, 0x00, 0x95, 0x00, 0x70, +0x00, 0x48, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x3a, 0x00, +0x31, 0x00, 0x25, 0x00, 0x18, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x22, 0x23, 0x22, 0x24, 0x24, 0x26, 0x25, 0x27, +0x26, 0x29, 0x27, 0x2a, 0x28, 0x2b, 0x2a, 0x2d, 0x2a, 0x2d, 0x2c, 0x2e, +0x2d, 0x30, 0x2d, 0x30, 0x2e, 0x30, 0x30, 0x31, 0x30, 0x32, 0x30, 0x33, +0x30, 0x33, 0x31, 0x33, 0x32, 0x33, 0x33, 0x34, 0x00, 0xd1, 0x00, 0xbc, +0x00, 0xa9, 0x00, 0x99, 0x00, 0x8c, 0x02, 0x82, 0x03, 0x7a, 0x05, 0x74, +0x07, 0x6f, 0x09, 0x6b, 0x0b, 0x67, 0x0d, 0x63, 0x0f, 0x61, 0x10, 0x5f, +0x12, 0x5c, 0x14, 0x5a, 0x15, 0x58, 0x16, 0x58, 0x18, 0x57, 0x19, 0x56, +0x13, 0x78, 0x17, 0x70, 0x1b, 0x6a, 0x1e, 0x66, 0x20, 0x62, 0x22, 0x5f, +0x24, 0x5c, 0x26, 0x5b, 0x27, 0x58, 0x29, 0x57, 0x2a, 0x56, 0x2b, 0x53, +0x2c, 0x53, 0x2d, 0x52, 0x2e, 0x51, 0x2e, 0x50, 0x2f, 0x4f, 0x30, 0x4f, +0x31, 0x4f, 0x31, 0x4e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0xbb, 0x00, 0xb3, 0x00, 0x9f, 0x00, 0x81, 0x00, 0x5f, 0x00, 0x3d, +0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x3c, 0x00, 0x35, 0x00, 0x2b, 0x00, +0x1f, 0x00, 0x14, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x22, 0x22, 0x22, 0x24, 0x23, 0x25, 0x24, 0x27, 0x25, 0x27, 0x27, 0x28, +0x28, 0x2a, 0x28, 0x2b, 0x2a, 0x2c, 0x2b, 0x2d, 0x2b, 0x2d, 0x2d, 0x2e, +0x2d, 0x30, 0x2d, 0x30, 0x2e, 0x30, 0x30, 0x30, 0x30, 0x31, 0x30, 0x33, +0x30, 0x33, 0x31, 0x33, 0x00, 0xd3, 0x00, 0xc1, 0x00, 0xaf, 0x00, 0xa1, +0x00, 0x94, 0x00, 0x8a, 0x02, 0x82, 0x03, 0x7b, 0x05, 0x76, 0x07, 0x71, +0x09, 0x6d, 0x0a, 0x69, 0x0c, 0x66, 0x0e, 0x63, 0x0f, 0x61, 0x10, 0x60, +0x12, 0x5d, 0x13, 0x5c, 0x14, 0x59, 0x16, 0x58, 0x13, 0x79, 0x16, 0x72, +0x19, 0x6d, 0x1c, 0x69, 0x1f, 0x65, 0x20, 0x61, 0x23, 0x60, 0x24, 0x5c, +0x26, 0x5b, 0x27, 0x59, 0x28, 0x57, 0x2a, 0x57, 0x2a, 0x55, 0x2b, 0x53, +0x2c, 0x53, 0x2e, 0x53, 0x2e, 0x52, 0x2e, 0x51, 0x2e, 0x4f, 0x2f, 0x4f, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbc, 0x00, 0xb6, +0x00, 0xa6, 0x00, 0x8e, 0x00, 0x71, 0x00, 0x52, 0x00, 0x35, 0x00, 0x19, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x3e, 0x00, 0x3c, 0x00, 0x37, 0x00, 0x2f, 0x00, 0x25, 0x00, 0x1b, 0x00, +0x11, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x22, 0x22, 0x22, 0x23, +0x23, 0x24, 0x24, 0x25, 0x25, 0x27, 0x26, 0x28, 0x26, 0x28, 0x28, 0x2a, +0x28, 0x2b, 0x2a, 0x2b, 0x2b, 0x2d, 0x2a, 0x2d, 0x2c, 0x2d, 0x2d, 0x2e, +0x2d, 0x30, 0x2d, 0x30, 0x2e, 0x30, 0x30, 0x30, 0x30, 0x31, 0x30, 0x32, +0x00, 0xd4, 0x00, 0xc4, 0x00, 0xb5, 0x00, 0xa7, 0x00, 0x9b, 0x00, 0x91, +0x01, 0x88, 0x02, 0x82, 0x03, 0x7b, 0x05, 0x77, 0x07, 0x73, 0x08, 0x6e, +0x0a, 0x6b, 0x0b, 0x69, 0x0c, 0x66, 0x0e, 0x63, 0x0f, 0x61, 0x10, 0x60, +0x12, 0x5f, 0x13, 0x5c, 0x12, 0x79, 0x15, 0x73, 0x18, 0x6e, 0x1b, 0x6a, +0x1d, 0x67, 0x20, 0x65, 0x21, 0x61, 0x23, 0x60, 0x24, 0x5d, 0x26, 0x5c, +0x27, 0x5a, 0x27, 0x58, 0x29, 0x57, 0x2a, 0x57, 0x2a, 0x55, 0x2b, 0x53, +0x2c, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x51, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0xbc, 0x00, 0xb8, 0x00, 0xab, 0x00, 0x97, +0x00, 0x7e, 0x00, 0x64, 0x00, 0x48, 0x00, 0x2e, 0x00, 0x16, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x3d, 0x00, +0x39, 0x00, 0x32, 0x00, 0x2a, 0x00, 0x21, 0x00, 0x18, 0x00, 0x0f, 0x00, +0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x22, 0x22, 0x22, 0x23, 0x23, 0x24, 0x24, 0x25, +0x24, 0x26, 0x25, 0x27, 0x27, 0x28, 0x27, 0x28, 0x28, 0x2a, 0x28, 0x2b, +0x2a, 0x2b, 0x2b, 0x2c, 0x2b, 0x2d, 0x2b, 0x2d, 0x2d, 0x2d, 0x2d, 0x2f, +0x2d, 0x30, 0x2d, 0x30, 0x2f, 0x30, 0x30, 0x30, 0x00, 0xd5, 0x00, 0xc7, +0x00, 0xb9, 0x00, 0xad, 0x00, 0xa1, 0x00, 0x97, 0x00, 0x8f, 0x01, 0x87, +0x02, 0x82, 0x03, 0x7b, 0x05, 0x77, 0x06, 0x74, 0x08, 0x6f, 0x09, 0x6c, +0x0b, 0x6b, 0x0c, 0x68, 0x0d, 0x65, 0x0e, 0x63, 0x0f, 0x62, 0x10, 0x60, +0x12, 0x7a, 0x15, 0x75, 0x18, 0x70, 0x1a, 0x6c, 0x1d, 0x69, 0x1e, 0x65, +0x20, 0x64, 0x21, 0x61, 0x23, 0x60, 0x24, 0x5d, 0x26, 0x5c, 0x27, 0x5b, +0x27, 0x58, 0x28, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x55, 0x2b, 0x53, +0x2c, 0x53, 0x2e, 0x53, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0xbd, 0x00, 0xb9, 0x00, 0xae, 0x00, 0x9e, 0x00, 0x89, 0x00, 0x71, +0x00, 0x59, 0x00, 0x41, 0x00, 0x29, 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x3d, 0x00, 0x3a, 0x00, 0x34, 0x00, +0x2d, 0x00, 0x25, 0x00, 0x1d, 0x00, 0x15, 0x00, 0x0d, 0x00, 0x06, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x21, 0x22, 0x22, 0x23, 0x23, 0x24, 0x23, 0x24, 0x24, 0x25, 0x25, 0x27, +0x25, 0x27, 0x27, 0x28, 0x27, 0x28, 0x28, 0x2a, 0x28, 0x2b, 0x29, 0x2b, +0x2b, 0x2b, 0x2b, 0x2d, 0x2b, 0x2d, 0x2c, 0x2d, 0x2d, 0x2d, 0x2d, 0x2f, +0x2d, 0x30, 0x2d, 0x30, 0x00, 0xd6, 0x00, 0xc9, 0x00, 0xbc, 0x00, 0xb1, +0x00, 0xa6, 0x00, 0x9c, 0x00, 0x94, 0x00, 0x8c, 0x02, 0x86, 0x02, 0x81, +0x03, 0x7c, 0x05, 0x78, 0x06, 0x75, 0x07, 0x71, 0x09, 0x6d, 0x0a, 0x6c, +0x0b, 0x6a, 0x0c, 0x67, 0x0d, 0x65, 0x0e, 0x62, 0x12, 0x7b, 0x15, 0x76, +0x18, 0x72, 0x1a, 0x6d, 0x1b, 0x6a, 0x1d, 0x68, 0x1f, 0x65, 0x20, 0x63, +0x22, 0x60, 0x23, 0x60, 0x23, 0x5d, 0x25, 0x5c, 0x27, 0x5c, 0x27, 0x5a, +0x28, 0x57, 0x29, 0x57, 0x2a, 0x57, 0x2a, 0x56, 0x2a, 0x55, 0x2b, 0x53, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbd, 0x00, 0xba, +0x00, 0xb1, 0x00, 0xa3, 0x00, 0x91, 0x00, 0x7c, 0x00, 0x66, 0x00, 0x50, +0x00, 0x3a, 0x00, 0x25, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x3f, 0x00, 0x3e, 0x00, 0x3b, 0x00, 0x36, 0x00, 0x30, 0x00, 0x29, 0x00, +0x22, 0x00, 0x1a, 0x00, 0x13, 0x00, 0x0c, 0x00, 0x06, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x21, 0x22, 0x22, 0x23, +0x22, 0x23, 0x23, 0x24, 0x24, 0x25, 0x24, 0x25, 0x25, 0x27, 0x26, 0x27, +0x27, 0x28, 0x27, 0x28, 0x28, 0x2a, 0x28, 0x2b, 0x29, 0x2b, 0x2b, 0x2b, +0x2b, 0x2c, 0x2b, 0x2d, 0x2c, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2f, +0x00, 0xd6, 0x00, 0xcb, 0x00, 0xbf, 0x00, 0xb4, 0x00, 0xab, 0x00, 0xa1, +0x00, 0x99, 0x00, 0x91, 0x01, 0x8b, 0x02, 0x85, 0x02, 0x81, 0x04, 0x7c, +0x05, 0x78, 0x06, 0x76, 0x07, 0x73, 0x08, 0x6f, 0x09, 0x6c, 0x0b, 0x6b, +0x0c, 0x6a, 0x0c, 0x67, 0x12, 0x7b, 0x15, 0x76, 0x17, 0x72, 0x19, 0x6e, +0x1a, 0x6c, 0x1d, 0x69, 0x1d, 0x66, 0x20, 0x65, 0x20, 0x62, 0x22, 0x60, +0x23, 0x60, 0x23, 0x5d, 0x25, 0x5c, 0x27, 0x5c, 0x27, 0x5b, 0x27, 0x58, +0x29, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x56, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0xbd, 0x00, 0xbb, 0x00, 0xb3, 0x00, 0xa7, +0x00, 0x98, 0x00, 0x85, 0x00, 0x72, 0x00, 0x5d, 0x00, 0x49, 0x00, 0x35, +0x00, 0x22, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x3e, 0x00, +0x3b, 0x00, 0x37, 0x00, 0x32, 0x00, 0x2c, 0x00, 0x26, 0x00, 0x1f, 0x00, +0x18, 0x00, 0x11, 0x00, 0x0b, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x22, 0x22, 0x22, 0x22, 0x22, 0x23, 0x23, 0x24, +0x24, 0x25, 0x24, 0x25, 0x25, 0x26, 0x25, 0x27, 0x27, 0x27, 0x27, 0x28, +0x28, 0x28, 0x28, 0x29, 0x28, 0x2b, 0x29, 0x2b, 0x2b, 0x2b, 0x2b, 0x2c, +0x2b, 0x2d, 0x2b, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x00, 0xd7, 0x00, 0xcc, +0x00, 0xc2, 0x00, 0xb8, 0x00, 0xae, 0x00, 0xa5, 0x00, 0x9e, 0x00, 0x95, +0x00, 0x90, 0x01, 0x8a, 0x02, 0x85, 0x03, 0x81, 0x04, 0x7c, 0x05, 0x78, +0x06, 0x76, 0x07, 0x74, 0x08, 0x70, 0x09, 0x6d, 0x0a, 0x6c, 0x0b, 0x6a, +0x12, 0x7b, 0x14, 0x77, 0x16, 0x73, 0x18, 0x70, 0x1a, 0x6d, 0x1c, 0x6a, +0x1d, 0x69, 0x1e, 0x65, 0x20, 0x65, 0x20, 0x62, 0x23, 0x60, 0x23, 0x60, +0x23, 0x5d, 0x25, 0x5c, 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x59, 0x28, 0x57, +0x2a, 0x57, 0x2a, 0x57, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0xbe, 0x00, 0xbb, 0x00, 0xb5, 0x00, 0xaa, 0x00, 0x9d, 0x00, 0x8d, +0x00, 0x7b, 0x00, 0x68, 0x00, 0x55, 0x00, 0x43, 0x00, 0x30, 0x00, 0x1f, +0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x3e, 0x00, 0x3c, 0x00, 0x38, 0x00, +0x34, 0x00, 0x2f, 0x00, 0x29, 0x00, 0x22, 0x00, 0x1c, 0x00, 0x16, 0x00, +0x10, 0x00, 0x0a, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x22, 0x22, 0x22, 0x22, 0x22, 0x23, 0x23, 0x24, 0x23, 0x24, 0x24, 0x25, +0x25, 0x25, 0x25, 0x27, 0x26, 0x27, 0x27, 0x28, 0x26, 0x28, 0x28, 0x28, +0x28, 0x29, 0x28, 0x2b, 0x29, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2d, +0x2b, 0x2d, 0x2c, 0x2d, 0x00, 0xd7, 0x00, 0xcd, 0x00, 0xc4, 0x00, 0xbb, +0x00, 0xb1, 0x00, 0xa9, 0x00, 0xa1, 0x00, 0x9a, 0x00, 0x93, 0x00, 0x8e, +0x01, 0x88, 0x02, 0x84, 0x03, 0x81, 0x04, 0x7c, 0x05, 0x79, 0x06, 0x77, +0x07, 0x75, 0x07, 0x72, 0x09, 0x6e, 0x09, 0x6d, 0x12, 0x7b, 0x14, 0x77, +0x15, 0x73, 0x18, 0x71, 0x1a, 0x6d, 0x1a, 0x6b, 0x1d, 0x69, 0x1d, 0x67, +0x1f, 0x65, 0x20, 0x65, 0x21, 0x61, 0x23, 0x60, 0x23, 0x60, 0x23, 0x5e, +0x25, 0x5c, 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x5a, 0x27, 0x58, 0x29, 0x57, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x00, 0xbc, +0x00, 0xb6, 0x00, 0xad, 0x00, 0xa1, 0x00, 0x93, 0x00, 0x83, 0x00, 0x72, +0x00, 0x60, 0x00, 0x4f, 0x00, 0x3d, 0x00, 0x2d, 0x00, 0x1d, 0x00, 0x0e, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x3f, 0x00, 0x3e, 0x00, 0x3c, 0x00, 0x39, 0x00, 0x35, 0x00, 0x31, 0x00, +0x2b, 0x00, 0x26, 0x00, 0x20, 0x00, 0x1a, 0x00, 0x14, 0x00, 0x0f, 0x00, +0x09, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x22, 0x22, 0x22, 0x22, +0x22, 0x23, 0x23, 0x23, 0x23, 0x24, 0x24, 0x25, 0x24, 0x25, 0x25, 0x26, +0x25, 0x27, 0x27, 0x27, 0x27, 0x28, 0x26, 0x28, 0x28, 0x28, 0x28, 0x29, +0x28, 0x2b, 0x29, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2c, 0x2b, 0x2d, +0x00, 0xd8, 0x00, 0xcf, 0x00, 0xc6, 0x00, 0xbd, 0x00, 0xb4, 0x00, 0xad, +0x00, 0xa4, 0x00, 0x9e, 0x00, 0x97, 0x00, 0x92, 0x01, 0x8d, 0x02, 0x88, +0x02, 0x84, 0x03, 0x81, 0x04, 0x7d, 0x05, 0x79, 0x06, 0x77, 0x07, 0x75, +0x07, 0x73, 0x09, 0x70, 0x12, 0x7c, 0x13, 0x78, 0x15, 0x75, 0x18, 0x72, +0x19, 0x6e, 0x1a, 0x6d, 0x1c, 0x69, 0x1d, 0x69, 0x1e, 0x66, 0x20, 0x65, +0x20, 0x64, 0x21, 0x61, 0x23, 0x60, 0x23, 0x60, 0x23, 0x5e, 0x25, 0x5c, +0x27, 0x5c, 0x27, 0x5c, 0x27, 0x5b, 0x27, 0x59, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x00, 0xbc, 0x00, 0xb7, 0x00, 0xaf, +0x00, 0xa5, 0x00, 0x98, 0x00, 0x89, 0x00, 0x7a, 0x00, 0x6a, 0x00, 0x59, +0x00, 0x49, 0x00, 0x39, 0x00, 0x29, 0x00, 0x1b, 0x00, 0x0d, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x3e, 0x00, +0x3d, 0x00, 0x3a, 0x00, 0x37, 0x00, 0x32, 0x00, 0x2d, 0x00, 0x28, 0x00, +0x23, 0x00, 0x1d, 0x00, 0x18, 0x00, 0x13, 0x00, 0x0d, 0x00, 0x09, 0x00, +0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x22, 0x22, 0x22, 0x22, 0x22, 0x23, 0x22, 0x23, +0x23, 0x24, 0x24, 0x24, 0x24, 0x25, 0x25, 0x25, 0x25, 0x27, 0x25, 0x27, +0x27, 0x27, 0x27, 0x28, 0x27, 0x28, 0x28, 0x28, 0x28, 0x29, 0x28, 0x2b, +0x29, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x00, 0xd8, 0x00, 0xd0, +0x00, 0xc7, 0x00, 0xbe, 0x00, 0xb7, 0x00, 0xaf, 0x00, 0xa8, 0x00, 0xa1, +0x00, 0x9b, 0x00, 0x95, 0x00, 0x90, 0x01, 0x8c, 0x02, 0x87, 0x02, 0x84, +0x03, 0x81, 0x04, 0x7d, 0x05, 0x79, 0x06, 0x77, 0x06, 0x76, 0x07, 0x74, +0x11, 0x7c, 0x13, 0x78, 0x15, 0x76, 0x17, 0x72, 0x18, 0x6f, 0x1a, 0x6d, +0x1b, 0x6a, 0x1d, 0x69, 0x1d, 0x68, 0x1f, 0x65, 0x20, 0x65, 0x20, 0x64, +0x22, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x5e, 0x25, 0x5c, 0x27, 0x5c, +0x27, 0x5c, 0x27, 0x5c, 0x00, 0x2f, 0x00, 0x5f, 0x00, 0x99, 0x00, 0xac, +0x00, 0xb3, 0x00, 0xb7, 0x00, 0xba, 0x00, 0xbb, 0x00, 0xbc, 0x00, 0xbc, +0x00, 0xbd, 0x00, 0xbd, 0x00, 0xbd, 0x00, 0xbe, 0x00, 0xbe, 0x00, 0xbe, +0x00, 0x9a, 0x00, 0x6d, 0x00, 0x8d, 0x00, 0x9b, 0x00, 0xa6, 0x00, 0xb2, +0x00, 0xba, 0x00, 0xbb, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbd, 0x00, 0xbd, +0x00, 0xbd, 0x00, 0xbe, 0x00, 0xbe, 0x00, 0xbe, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x0b, 0x3b, 0x00, 0x6f, 0x00, 0x9f, 0x00, 0xaf, +0x00, 0xb5, 0x00, 0xb9, 0x00, 0xba, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbd, +0x00, 0xbd, 0x00, 0xbd, 0x00, 0xbe, 0x00, 0xbe, 0x00, 0xbe, 0x00, 0xbe, +0x07, 0x47, 0x00, 0x7f, 0x00, 0xa5, 0x00, 0xb2, 0x00, 0xb7, 0x00, 0xba, +0x00, 0xbb, 0x00, 0xbc, 0x00, 0xbd, 0x00, 0xbd, 0x00, 0xbd, 0x00, 0xbe, +0x00, 0xbe, 0x00, 0xbe, 0x00, 0xbe, 0x00, 0xbe, 0x41, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x23, 0x23, 0x24, 0x23, 0x24, +0x24, 0x25, 0x24, 0x25, 0x25, 0x25, 0x25, 0x27, 0x26, 0x27, 0x27, 0x27, +0x27, 0x29, 0x27, 0x28, 0x28, 0x28, 0x28, 0x29, 0x28, 0x2b, 0x29, 0x2b, +0x2b, 0x2b, 0x2b, 0x2b, 0x00, 0xd8, 0x00, 0xd1, 0x00, 0xc9, 0x00, 0xc0, +0x00, 0xba, 0x00, 0xb1, 0x00, 0xac, 0x00, 0xa4, 0x00, 0x9e, 0x00, 0x98, +0x00, 0x93, 0x00, 0x8f, 0x01, 0x8b, 0x02, 0x86, 0x02, 0x83, 0x03, 0x81, +0x04, 0x7d, 0x05, 0x79, 0x06, 0x78, 0x06, 0x76, 0x11, 0x7c, 0x13, 0x79, +0x15, 0x76, 0x17, 0x72, 0x18, 0x71, 0x1a, 0x6d, 0x1a, 0x6d, 0x1c, 0x69, +0x1d, 0x69, 0x1d, 0x66, 0x20, 0x65, 0x20, 0x65, 0x20, 0x63, 0x22, 0x60, +0x23, 0x60, 0x23, 0x60, 0x23, 0x5f, 0x25, 0x5c, 0x27, 0x5c, 0x27, 0x5c, +0x00, 0x00, 0x00, 0x0f, 0x00, 0x5f, 0x00, 0x8b, 0x00, 0x9f, 0x00, 0xaa, +0x00, 0xb0, 0x00, 0xb3, 0x00, 0xb6, 0x00, 0xb8, 0x00, 0xb9, 0x00, 0xba, +0x00, 0xbb, 0x00, 0xbb, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0x6d, 0x00, 0x54, +0x00, 0x6b, 0x00, 0x87, 0x00, 0x98, 0x00, 0xa6, 0x00, 0xb0, 0x00, 0xb3, +0x00, 0xb6, 0x00, 0xb8, 0x00, 0xb9, 0x00, 0xba, 0x00, 0xbb, 0x00, 0xbb, +0x00, 0xbc, 0x00, 0xbc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x17, 0x07, 0x02, 0x27, 0x00, 0x6f, 0x00, 0x93, 0x00, 0xa4, 0x00, 0xad, +0x00, 0xb2, 0x00, 0xb5, 0x00, 0xb8, 0x00, 0xb9, 0x00, 0xba, 0x00, 0xbb, +0x00, 0xbb, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbd, 0x0f, 0x0f, 0x00, 0x3f, +0x00, 0x7f, 0x00, 0x9c, 0x00, 0xaa, 0x00, 0xb1, 0x00, 0xb5, 0x00, 0xb7, +0x00, 0xb9, 0x00, 0xba, 0x00, 0xbb, 0x00, 0xbc, 0x00, 0xbc, 0x00, 0xbd, +0x00, 0xbd, 0x00, 0xbd, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x22, 0x22, 0x22, 0x22, +0x22, 0x22, 0x22, 0x23, 0x23, 0x23, 0x23, 0x24, 0x24, 0x24, 0x24, 0x25, +0x25, 0x25, 0x25, 0x26, 0x25, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x28, +0x27, 0x28, 0x28, 0x28, 0x28, 0x29, 0x28, 0x2b, 0x28, 0x2b, 0x2a, 0x2b, +0x00, 0xd9, 0x00, 0xd2, 0x00, 0xc9, 0x00, 0xc2, 0x00, 0xbb, 0x00, 0xb4, +0x00, 0xae, 0x00, 0xa7, 0x00, 0xa1, 0x00, 0x9d, 0x00, 0x96, 0x00, 0x92, +0x01, 0x8e, 0x01, 0x89, 0x02, 0x86, 0x02, 0x83, 0x03, 0x81, 0x04, 0x7e, +0x05, 0x7a, 0x06, 0x78, 0x11, 0x7c, 0x13, 0x79, 0x15, 0x76, 0x16, 0x73, +0x18, 0x72, 0x19, 0x6e, 0x1a, 0x6d, 0x1b, 0x6a, 0x1d, 0x69, 0x1d, 0x69, +0x1e, 0x65, 0x20, 0x65, 0x20, 0x65, 0x20, 0x62, 0x22, 0x60, 0x23, 0x60, +0x23, 0x60, 0x23, 0x5f, 0x24, 0x5c, 0x26, 0x5c, 0x00, 0x00, 0x00, 0x00, +0x00, 0x05, 0x00, 0x44, 0x00, 0x6d, 0x00, 0x85, 0x00, 0x95, 0x00, 0x9f, +0x00, 0xa6, 0x00, 0xab, 0x00, 0xae, 0x00, 0xb1, 0x00, 0xb3, 0x00, 0xb5, +0x00, 0xb6, 0x00, 0xb7, 0x00, 0x8d, 0x00, 0x6b, 0x00, 0x28, 0x00, 0x52, +0x00, 0x70, 0x00, 0x85, 0x00, 0x95, 0x00, 0x9f, 0x00, 0xa6, 0x00, 0xab, +0x00, 0xae, 0x00, 0xb1, 0x00, 0xb3, 0x00, 0xb5, 0x00, 0xb6, 0x00, 0xb7, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x12, 0x02, +0x00, 0x22, 0x00, 0x58, 0x00, 0x7a, 0x00, 0x8f, 0x00, 0x9c, 0x00, 0xa4, +0x00, 0xaa, 0x00, 0xae, 0x00, 0xb1, 0x00, 0xb3, 0x00, 0xb5, 0x00, 0xb7, +0x00, 0xb8, 0x00, 0xb9, 0x26, 0x00, 0x05, 0x05, 0x00, 0x3f, 0x00, 0x6d, +0x00, 0x88, 0x00, 0x99, 0x00, 0xa3, 0x00, 0xaa, 0x00, 0xae, 0x00, 0xb1, +0x00, 0xb4, 0x00, 0xb6, 0x00, 0xb7, 0x00, 0xb8, 0x00, 0xb9, 0x00, 0xba, +0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x23, +0x23, 0x23, 0x23, 0x24, 0x24, 0x24, 0x24, 0x25, 0x24, 0x25, 0x25, 0x25, +0x25, 0x27, 0x26, 0x27, 0x27, 0x27, 0x27, 0x28, 0x27, 0x28, 0x28, 0x28, +0x28, 0x28, 0x28, 0x29, 0x28, 0x2b, 0x28, 0x2b, 0x00, 0xd9, 0x00, 0xd2, +0x00, 0xca, 0x00, 0xc4, 0x00, 0xbd, 0x00, 0xb6, 0x00, 0xb0, 0x00, 0xaa, +0x00, 0xa3, 0x00, 0x9f, 0x00, 0x9a, 0x00, 0x94, 0x00, 0x91, 0x01, 0x8e, +0x02, 0x89, 0x02, 0x85, 0x02, 0x83, 0x03, 0x81, 0x04, 0x7e, 0x05, 0x7a, +0x11, 0x7c, 0x13, 0x7a, 0x15, 0x76, 0x15, 0x74, 0x18, 0x72, 0x18, 0x6f, +0x1a, 0x6d, 0x1a, 0x6c, 0x1c, 0x69, 0x1d, 0x69, 0x1d, 0x67, 0x1f, 0x65, +0x20, 0x65, 0x20, 0x65, 0x21, 0x61, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, +0x23, 0x5f, 0x24, 0x5c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, +0x00, 0x33, 0x00, 0x57, 0x00, 0x70, 0x00, 0x81, 0x00, 0x8e, 0x00, 0x97, +0x00, 0x9e, 0x00, 0xa3, 0x00, 0xa7, 0x00, 0xaa, 0x00, 0xad, 0x00, 0xaf, +0x00, 0x9b, 0x00, 0x87, 0x00, 0x52, 0x00, 0x11, 0x00, 0x39, 0x00, 0x57, +0x00, 0x70, 0x00, 0x81, 0x00, 0x8e, 0x00, 0x97, 0x00, 0x9e, 0x00, 0xa3, +0x00, 0xa7, 0x00, 0xaa, 0x00, 0xad, 0x00, 0xaf, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x36, 0x00, 0x25, 0x00, 0x0b, 0x09, 0x00, 0x21, +0x00, 0x4a, 0x00, 0x68, 0x00, 0x7d, 0x00, 0x8b, 0x00, 0x96, 0x00, 0x9d, +0x00, 0xa3, 0x00, 0xa8, 0x00, 0xab, 0x00, 0xae, 0x00, 0xb0, 0x00, 0xb2, +0x33, 0x00, 0x1c, 0x00, 0x00, 0x12, 0x00, 0x3f, 0x00, 0x62, 0x00, 0x7a, +0x00, 0x8a, 0x00, 0x96, 0x00, 0x9e, 0x00, 0xa4, 0x00, 0xa9, 0x00, 0xac, +0x00, 0xaf, 0x00, 0xb1, 0x00, 0xb3, 0x00, 0xb4, 0x41, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x21, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x23, 0x23, 0x23, 0x23, 0x24, +0x23, 0x24, 0x24, 0x24, 0x24, 0x25, 0x25, 0x25, 0x25, 0x26, 0x25, 0x27, +0x27, 0x27, 0x27, 0x27, 0x27, 0x28, 0x27, 0x28, 0x28, 0x28, 0x28, 0x28, +0x28, 0x28, 0x28, 0x2a, 0x00, 0xd9, 0x00, 0xd2, 0x00, 0xcb, 0x00, 0xc6, +0x00, 0xbe, 0x00, 0xb9, 0x00, 0xb1, 0x00, 0xac, 0x00, 0xa6, 0x00, 0xa1, +0x00, 0x9d, 0x00, 0x97, 0x00, 0x93, 0x00, 0x90, 0x01, 0x8d, 0x02, 0x88, +0x02, 0x85, 0x02, 0x83, 0x03, 0x81, 0x04, 0x7e, 0x11, 0x7c, 0x13, 0x7a, +0x15, 0x76, 0x15, 0x75, 0x18, 0x72, 0x18, 0x71, 0x1a, 0x6d, 0x1a, 0x6d, +0x1b, 0x6a, 0x1d, 0x69, 0x1d, 0x69, 0x1e, 0x66, 0x20, 0x65, 0x20, 0x65, +0x20, 0x64, 0x21, 0x61, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x5f, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x28, +0x00, 0x48, 0x00, 0x5f, 0x00, 0x71, 0x00, 0x7e, 0x00, 0x89, 0x00, 0x91, +0x00, 0x98, 0x00, 0x9d, 0x00, 0xa1, 0x00, 0xa5, 0x00, 0xa6, 0x00, 0x98, +0x00, 0x70, 0x00, 0x39, 0x00, 0x02, 0x00, 0x28, 0x00, 0x48, 0x00, 0x5f, +0x00, 0x71, 0x00, 0x7e, 0x00, 0x89, 0x00, 0x91, 0x00, 0x98, 0x00, 0x9d, +0x00, 0xa1, 0x00, 0xa5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x3a, 0x00, 0x2f, 0x00, 0x16, 0x00, 0x08, 0x0e, 0x00, 0x20, 0x00, 0x42, +0x00, 0x5c, 0x00, 0x6f, 0x00, 0x7e, 0x00, 0x89, 0x00, 0x92, 0x00, 0x99, +0x00, 0x9e, 0x00, 0xa2, 0x00, 0xa6, 0x00, 0xa9, 0x38, 0x00, 0x2a, 0x00, +0x09, 0x00, 0x00, 0x1d, 0x00, 0x3f, 0x00, 0x5b, 0x00, 0x6f, 0x00, 0x7f, +0x00, 0x8b, 0x00, 0x94, 0x00, 0x9b, 0x00, 0xa0, 0x00, 0xa5, 0x00, 0xa8, +0x00, 0xab, 0x00, 0xad, 0x16, 0xa4, 0x01, 0xbb, 0x00, 0xc6, 0x00, 0xcc, +0x00, 0xcf, 0x00, 0xd1, 0x00, 0xd3, 0x00, 0xd4, 0x00, 0xd5, 0x00, 0xd6, +0x00, 0xd7, 0x00, 0xd7, 0x00, 0xd8, 0x00, 0xd8, 0x00, 0xd8, 0x00, 0xd9, +0x00, 0xd9, 0x00, 0xd9, 0x00, 0xd9, 0x00, 0xda, 0x05, 0x9d, 0x00, 0xbc, +0x00, 0xc6, 0x00, 0xcd, 0x00, 0xcf, 0x00, 0xd2, 0x00, 0xd3, 0x00, 0xd5, +0x00, 0xd5, 0x00, 0xd6, 0x00, 0xd6, 0x00, 0xd7, 0x00, 0xd7, 0x00, 0xd8, +0x00, 0xd8, 0x00, 0xd9, 0x00, 0xd9, 0x00, 0xd9, 0x00, 0xd9, 0x00, 0xd9, +0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, +0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, +0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, +0x00, 0xdd, 0x00, 0xdd, 0x02, 0xbd, 0x00, 0xcc, 0x00, 0xd1, 0x00, 0xd5, +0x00, 0xd6, 0x00, 0xd7, 0x00, 0xd8, 0x00, 0xd9, 0x00, 0xd9, 0x00, 0xd9, +0x00, 0xd9, 0x00, 0xda, 0x00, 0xda, 0x00, 0xda, 0x00, 0xda, 0x00, 0xdb, +0x00, 0xdb, 0x00, 0xdb, 0x00, 0xdb, 0x00, 0xdb, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x00, 0x3d, +0x00, 0x52, 0x00, 0x64, 0x00, 0x71, 0x00, 0x7c, 0x00, 0x85, 0x00, 0x8d, +0x00, 0x93, 0x00, 0x98, 0x00, 0xb2, 0x00, 0xa6, 0x00, 0x85, 0x00, 0x57, +0x00, 0x28, 0x00, 0x01, 0x00, 0x21, 0x00, 0x3d, 0x00, 0x52, 0x00, 0x64, +0x00, 0x71, 0x00, 0x7c, 0x00, 0x85, 0x00, 0x8d, 0x00, 0x93, 0x00, 0x98, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x35, 0x00, +0x23, 0x00, 0x0e, 0x02, 0x06, 0x12, 0x00, 0x20, 0x00, 0x3c, 0x00, 0x52, +0x00, 0x64, 0x00, 0x73, 0x00, 0x7e, 0x00, 0x87, 0x00, 0x8f, 0x00, 0x95, +0x00, 0x9a, 0x00, 0x9e, 0x3a, 0x00, 0x31, 0x00, 0x19, 0x00, 0x00, 0x05, +0x00, 0x24, 0x00, 0x3f, 0x00, 0x56, 0x00, 0x68, 0x00, 0x77, 0x00, 0x82, +0x00, 0x8b, 0x00, 0x93, 0x00, 0x99, 0x00, 0x9d, 0x00, 0xa1, 0x00, 0xa5, +0x23, 0x74, 0x09, 0x91, 0x02, 0xa3, 0x00, 0xaf, 0x00, 0xb7, 0x00, 0xbd, +0x00, 0xc2, 0x00, 0xc5, 0x00, 0xc7, 0x00, 0xc9, 0x00, 0xcb, 0x00, 0xcc, +0x00, 0xce, 0x00, 0xcf, 0x00, 0xd0, 0x00, 0xd1, 0x00, 0xd2, 0x00, 0xd2, +0x00, 0xd2, 0x00, 0xd3, 0x0d, 0x6b, 0x01, 0x8e, 0x00, 0xa4, 0x00, 0xb0, +0x00, 0xb9, 0x00, 0xbe, 0x00, 0xc2, 0x00, 0xc5, 0x00, 0xc8, 0x00, 0xca, +0x00, 0xcc, 0x00, 0xcc, 0x00, 0xce, 0x00, 0xcf, 0x00, 0xd0, 0x00, 0xd1, +0x00, 0xd1, 0x00, 0xd2, 0x00, 0xd3, 0x00, 0xd3, 0x00, 0xdd, 0x00, 0xdd, +0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, +0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, +0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, +0x06, 0xa4, 0x00, 0xb5, 0x00, 0xc0, 0x00, 0xc6, 0x00, 0xcb, 0x00, 0xcd, +0x00, 0xcf, 0x00, 0xd1, 0x00, 0xd2, 0x00, 0xd3, 0x00, 0xd4, 0x00, 0xd4, +0x00, 0xd5, 0x00, 0xd6, 0x00, 0xd6, 0x00, 0xd7, 0x00, 0xd7, 0x00, 0xd7, +0x00, 0xd8, 0x00, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x35, 0x00, 0x48, +0x00, 0x59, 0x00, 0x66, 0x00, 0x72, 0x00, 0x7b, 0x00, 0x83, 0x00, 0x89, +0x00, 0xba, 0x00, 0xb0, 0x00, 0x95, 0x00, 0x70, 0x00, 0x48, 0x00, 0x21, +0x00, 0x01, 0x00, 0x1c, 0x00, 0x35, 0x00, 0x48, 0x00, 0x59, 0x00, 0x66, +0x00, 0x72, 0x00, 0x7b, 0x00, 0x83, 0x00, 0x89, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x38, 0x00, 0x2a, 0x00, 0x18, 0x00, +0x0c, 0x07, 0x05, 0x14, 0x00, 0x20, 0x00, 0x37, 0x00, 0x4c, 0x00, 0x5c, +0x00, 0x6a, 0x00, 0x75, 0x00, 0x7e, 0x00, 0x86, 0x00, 0x8d, 0x00, 0x92, +0x3c, 0x00, 0x35, 0x00, 0x23, 0x00, 0x0b, 0x00, 0x00, 0x0f, 0x00, 0x29, +0x00, 0x3f, 0x00, 0x53, 0x00, 0x63, 0x00, 0x70, 0x00, 0x7b, 0x00, 0x84, +0x00, 0x8b, 0x00, 0x92, 0x00, 0x97, 0x00, 0x9b, 0x2a, 0x61, 0x11, 0x78, +0x07, 0x8a, 0x03, 0x98, 0x01, 0xa2, 0x00, 0xaa, 0x00, 0xb1, 0x00, 0xb6, +0x00, 0xba, 0x00, 0xbd, 0x00, 0xc0, 0x00, 0xc2, 0x00, 0xc5, 0x00, 0xc6, +0x00, 0xc7, 0x00, 0xc9, 0x00, 0xc9, 0x00, 0xca, 0x00, 0xcb, 0x00, 0xcc, +0x12, 0x51, 0x04, 0x73, 0x00, 0x89, 0x00, 0x9a, 0x00, 0xa4, 0x00, 0xad, +0x00, 0xb2, 0x00, 0xb7, 0x00, 0xbb, 0x00, 0xbe, 0x00, 0xc0, 0x00, 0xc3, +0x00, 0xc5, 0x00, 0xc6, 0x00, 0xc8, 0x00, 0xc9, 0x00, 0xca, 0x00, 0xcb, +0x00, 0xcc, 0x00, 0xcd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, +0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, +0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, +0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x09, 0x97, 0x02, 0xa8, +0x00, 0xb3, 0x00, 0xbb, 0x00, 0xc0, 0x00, 0xc5, 0x00, 0xc7, 0x00, 0xca, +0x00, 0xcc, 0x00, 0xcd, 0x00, 0xce, 0x00, 0xd0, 0x00, 0xd1, 0x00, 0xd1, +0x00, 0xd2, 0x00, 0xd3, 0x00, 0xd3, 0x00, 0xd4, 0x00, 0xd4, 0x00, 0xd5, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x00, 0x2e, 0x00, 0x41, 0x00, 0x50, +0x00, 0x5d, 0x00, 0x68, 0x00, 0x72, 0x00, 0x7a, 0x00, 0xbb, 0x00, 0xb3, +0x00, 0x9f, 0x00, 0x81, 0x00, 0x5f, 0x00, 0x3d, 0x00, 0x1c, 0x00, 0x00, +0x00, 0x19, 0x00, 0x2e, 0x00, 0x41, 0x00, 0x50, 0x00, 0x5d, 0x00, 0x68, +0x00, 0x72, 0x00, 0x7a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x3d, 0x00, 0x3a, 0x00, 0x2f, 0x00, 0x20, 0x00, 0x10, 0x00, 0x0a, 0x0b, +0x04, 0x16, 0x00, 0x20, 0x00, 0x34, 0x00, 0x46, 0x00, 0x56, 0x00, 0x62, +0x00, 0x6d, 0x00, 0x77, 0x00, 0x7f, 0x00, 0x85, 0x3d, 0x00, 0x38, 0x00, +0x2a, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x2c, 0x00, 0x3f, +0x00, 0x50, 0x00, 0x5e, 0x00, 0x6b, 0x00, 0x75, 0x00, 0x7e, 0x00, 0x85, +0x00, 0x8b, 0x00, 0x91, 0x2e, 0x59, 0x17, 0x6b, 0x0c, 0x7a, 0x06, 0x87, +0x03, 0x92, 0x01, 0x9b, 0x00, 0xa2, 0x00, 0xa8, 0x00, 0xad, 0x00, 0xb1, +0x00, 0xb5, 0x00, 0xb9, 0x00, 0xbb, 0x00, 0xbd, 0x00, 0xbe, 0x00, 0xc1, +0x00, 0xc3, 0x00, 0xc4, 0x00, 0xc6, 0x00, 0xc7, 0x15, 0x45, 0x08, 0x60, +0x02, 0x77, 0x00, 0x87, 0x00, 0x94, 0x00, 0x9d, 0x00, 0xa4, 0x00, 0xaa, +0x00, 0xaf, 0x00, 0xb3, 0x00, 0xb7, 0x00, 0xba, 0x00, 0xbc, 0x00, 0xbe, +0x00, 0xc0, 0x00, 0xc2, 0x00, 0xc3, 0x00, 0xc4, 0x00, 0xc6, 0x00, 0xc7, +0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, +0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, +0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, +0x00, 0xdd, 0x00, 0xdd, 0x0a, 0x91, 0x04, 0x9e, 0x01, 0xaa, 0x00, 0xb2, +0x00, 0xb8, 0x00, 0xbd, 0x00, 0xc0, 0x00, 0xc3, 0x00, 0xc6, 0x00, 0xc8, +0x00, 0xca, 0x00, 0xcb, 0x00, 0xcc, 0x00, 0xcd, 0x00, 0xce, 0x00, 0xcf, +0x00, 0xd0, 0x00, 0xd0, 0x00, 0xd1, 0x00, 0xd2, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x16, 0x00, 0x29, 0x00, 0x3a, 0x00, 0x49, 0x00, 0x55, +0x00, 0x60, 0x00, 0x6a, 0x00, 0xbc, 0x00, 0xb6, 0x00, 0xa6, 0x00, 0x8e, +0x00, 0x71, 0x00, 0x52, 0x00, 0x35, 0x00, 0x19, 0x00, 0x00, 0x00, 0x16, +0x00, 0x29, 0x00, 0x3a, 0x00, 0x49, 0x00, 0x55, 0x00, 0x60, 0x00, 0x6a, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x3b, 0x00, +0x33, 0x00, 0x27, 0x00, 0x18, 0x00, 0x0d, 0x04, 0x08, 0x0e, 0x04, 0x17, +0x00, 0x20, 0x00, 0x32, 0x00, 0x42, 0x00, 0x50, 0x00, 0x5c, 0x00, 0x67, +0x00, 0x70, 0x00, 0x78, 0x3d, 0x00, 0x39, 0x00, 0x2f, 0x00, 0x1f, 0x00, +0x0b, 0x00, 0x00, 0x08, 0x00, 0x1c, 0x00, 0x2e, 0x00, 0x3f, 0x00, 0x4e, +0x00, 0x5b, 0x00, 0x66, 0x00, 0x70, 0x00, 0x78, 0x00, 0x80, 0x00, 0x86, +0x31, 0x53, 0x1c, 0x62, 0x11, 0x70, 0x0a, 0x7b, 0x06, 0x85, 0x03, 0x8e, +0x02, 0x96, 0x00, 0x9c, 0x00, 0xa2, 0x00, 0xa7, 0x00, 0xab, 0x00, 0xae, +0x00, 0xb2, 0x00, 0xb5, 0x00, 0xb8, 0x00, 0xba, 0x00, 0xbb, 0x00, 0xbd, +0x00, 0xbe, 0x00, 0xbf, 0x17, 0x3d, 0x0b, 0x55, 0x04, 0x67, 0x01, 0x78, +0x00, 0x85, 0x00, 0x90, 0x00, 0x98, 0x00, 0x9f, 0x00, 0xa5, 0x00, 0xaa, +0x00, 0xad, 0x00, 0xb1, 0x00, 0xb4, 0x00, 0xb6, 0x00, 0xb9, 0x00, 0xbb, +0x00, 0xbc, 0x00, 0xbe, 0x00, 0xc0, 0x00, 0xc1, 0x00, 0xdd, 0x00, 0xdd, +0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, +0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, +0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, +0x0b, 0x8d, 0x05, 0x99, 0x02, 0xa2, 0x00, 0xaa, 0x00, 0xb1, 0x00, 0xb6, +0x00, 0xba, 0x00, 0xbe, 0x00, 0xc1, 0x00, 0xc3, 0x00, 0xc5, 0x00, 0xc7, +0x00, 0xc8, 0x00, 0xc9, 0x00, 0xcb, 0x00, 0xcc, 0x00, 0xcc, 0x00, 0xcd, +0x00, 0xce, 0x00, 0xcf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x13, 0x00, 0x25, 0x00, 0x35, 0x00, 0x43, 0x00, 0x4f, 0x00, 0x59, +0x00, 0xbc, 0x00, 0xb8, 0x00, 0xab, 0x00, 0x97, 0x00, 0x7e, 0x00, 0x64, +0x00, 0x48, 0x00, 0x2e, 0x00, 0x16, 0x00, 0x00, 0x00, 0x13, 0x00, 0x25, +0x00, 0x35, 0x00, 0x43, 0x00, 0x4f, 0x00, 0x59, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x3c, 0x00, 0x35, 0x00, 0x2b, 0x00, +0x1f, 0x00, 0x12, 0x00, 0x0c, 0x07, 0x07, 0x10, 0x03, 0x18, 0x00, 0x20, +0x00, 0x30, 0x00, 0x3f, 0x00, 0x4c, 0x00, 0x57, 0x00, 0x61, 0x00, 0x6a, +0x3e, 0x00, 0x3b, 0x00, 0x32, 0x00, 0x25, 0x00, 0x14, 0x00, 0x02, 0x00, +0x00, 0x0f, 0x00, 0x20, 0x00, 0x30, 0x00, 0x3f, 0x00, 0x4d, 0x00, 0x58, +0x00, 0x63, 0x00, 0x6c, 0x00, 0x74, 0x00, 0x7b, 0x33, 0x50, 0x20, 0x5c, +0x15, 0x68, 0x0e, 0x72, 0x09, 0x7c, 0x05, 0x84, 0x03, 0x8c, 0x02, 0x92, +0x01, 0x98, 0x00, 0x9d, 0x00, 0xa1, 0x00, 0xa6, 0x00, 0xaa, 0x00, 0xad, +0x00, 0xaf, 0x00, 0xb2, 0x00, 0xb5, 0x00, 0xb7, 0x00, 0xb9, 0x00, 0xba, +0x18, 0x38, 0x0d, 0x4c, 0x06, 0x5e, 0x03, 0x6c, 0x01, 0x7a, 0x00, 0x84, +0x00, 0x8d, 0x00, 0x95, 0x00, 0x9b, 0x00, 0xa0, 0x00, 0xa5, 0x00, 0xa8, +0x00, 0xac, 0x00, 0xaf, 0x00, 0xb2, 0x00, 0xb4, 0x00, 0xb6, 0x00, 0xb8, +0x00, 0xba, 0x00, 0xbc, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, +0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, +0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, +0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x0c, 0x8a, 0x06, 0x94, +0x03, 0x9d, 0x01, 0xa4, 0x00, 0xab, 0x00, 0xb0, 0x00, 0xb5, 0x00, 0xb9, +0x00, 0xbc, 0x00, 0xbe, 0x00, 0xc1, 0x00, 0xc2, 0x00, 0xc4, 0x00, 0xc6, +0x00, 0xc7, 0x00, 0xc8, 0x00, 0xc9, 0x00, 0xca, 0x00, 0xcb, 0x00, 0xcc, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, +0x00, 0x22, 0x00, 0x30, 0x00, 0x3d, 0x00, 0x49, 0x00, 0xbd, 0x00, 0xb9, +0x00, 0xae, 0x00, 0x9e, 0x00, 0x89, 0x00, 0x71, 0x00, 0x59, 0x00, 0x41, +0x00, 0x29, 0x00, 0x13, 0x00, 0x00, 0x00, 0x12, 0x00, 0x22, 0x00, 0x30, +0x00, 0x3d, 0x00, 0x49, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x3e, 0x00, 0x3c, 0x00, 0x37, 0x00, 0x2f, 0x00, 0x24, 0x00, 0x19, 0x00, +0x0e, 0x02, 0x0a, 0x0a, 0x06, 0x11, 0x03, 0x19, 0x00, 0x1f, 0x00, 0x2e, +0x00, 0x3c, 0x00, 0x48, 0x00, 0x53, 0x00, 0x5c, 0x3e, 0x00, 0x3c, 0x00, +0x34, 0x00, 0x29, 0x00, 0x1b, 0x00, 0x0c, 0x00, 0x00, 0x04, 0x00, 0x14, +0x00, 0x23, 0x00, 0x32, 0x00, 0x3f, 0x00, 0x4b, 0x00, 0x56, 0x00, 0x60, +0x00, 0x68, 0x00, 0x70, 0x34, 0x4e, 0x23, 0x58, 0x18, 0x62, 0x10, 0x6c, +0x0b, 0x75, 0x08, 0x7c, 0x05, 0x83, 0x03, 0x8a, 0x02, 0x8f, 0x01, 0x95, +0x00, 0x9a, 0x00, 0x9e, 0x00, 0xa1, 0x00, 0xa5, 0x00, 0xa9, 0x00, 0xac, +0x00, 0xae, 0x00, 0xb0, 0x00, 0xb2, 0x00, 0xb5, 0x1a, 0x35, 0x0f, 0x47, +0x08, 0x55, 0x04, 0x64, 0x02, 0x70, 0x00, 0x7a, 0x00, 0x83, 0x00, 0x8b, +0x00, 0x92, 0x00, 0x98, 0x00, 0x9d, 0x00, 0xa0, 0x00, 0xa5, 0x00, 0xa8, +0x00, 0xab, 0x00, 0xae, 0x00, 0xb0, 0x00, 0xb2, 0x00, 0xb4, 0x00, 0xb7, +0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, +0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, +0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, +0x00, 0xdd, 0x00, 0xdd, 0x0d, 0x89, 0x07, 0x92, 0x04, 0x99, 0x02, 0xa0, +0x01, 0xa6, 0x00, 0xab, 0x00, 0xb0, 0x00, 0xb4, 0x00, 0xb7, 0x00, 0xba, +0x00, 0xbd, 0x00, 0xbe, 0x00, 0xc1, 0x00, 0xc2, 0x00, 0xc4, 0x00, 0xc5, +0x00, 0xc6, 0x00, 0xc7, 0x00, 0xc8, 0x00, 0xca, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x1f, +0x00, 0x2d, 0x00, 0x39, 0x00, 0xbd, 0x00, 0xba, 0x00, 0xb1, 0x00, 0xa3, +0x00, 0x91, 0x00, 0x7c, 0x00, 0x66, 0x00, 0x50, 0x00, 0x3a, 0x00, 0x25, +0x00, 0x12, 0x00, 0x00, 0x00, 0x10, 0x00, 0x1f, 0x00, 0x2d, 0x00, 0x39, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x3d, 0x00, +0x38, 0x00, 0x31, 0x00, 0x28, 0x00, 0x1e, 0x00, 0x13, 0x00, 0x0d, 0x05, +0x09, 0x0c, 0x06, 0x13, 0x03, 0x19, 0x00, 0x1f, 0x00, 0x2d, 0x00, 0x3a, +0x00, 0x45, 0x00, 0x4f, 0x3e, 0x00, 0x3c, 0x00, 0x36, 0x00, 0x2d, 0x00, +0x21, 0x00, 0x13, 0x00, 0x04, 0x00, 0x00, 0x0a, 0x00, 0x18, 0x00, 0x26, +0x00, 0x33, 0x00, 0x3f, 0x00, 0x4a, 0x00, 0x54, 0x00, 0x5d, 0x00, 0x65, +0x35, 0x4c, 0x26, 0x55, 0x1b, 0x5e, 0x13, 0x67, 0x0e, 0x6f, 0x0a, 0x76, +0x07, 0x7d, 0x05, 0x82, 0x03, 0x88, 0x02, 0x8e, 0x02, 0x92, 0x01, 0x97, +0x00, 0x9b, 0x00, 0x9e, 0x00, 0xa1, 0x00, 0xa5, 0x00, 0xa8, 0x00, 0xab, +0x00, 0xac, 0x00, 0xaf, 0x1b, 0x33, 0x10, 0x42, 0x0a, 0x50, 0x05, 0x5c, +0x03, 0x68, 0x01, 0x72, 0x00, 0x7b, 0x00, 0x83, 0x00, 0x8a, 0x00, 0x90, +0x00, 0x96, 0x00, 0x99, 0x00, 0x9e, 0x00, 0xa1, 0x00, 0xa5, 0x00, 0xa8, +0x00, 0xaa, 0x00, 0xad, 0x00, 0xaf, 0x00, 0xb0, 0x00, 0xdd, 0x00, 0xdd, +0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, +0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, +0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, +0x0d, 0x88, 0x08, 0x8f, 0x05, 0x96, 0x02, 0x9c, 0x01, 0xa2, 0x00, 0xa7, +0x00, 0xac, 0x00, 0xb0, 0x00, 0xb3, 0x00, 0xb6, 0x00, 0xb9, 0x00, 0xbb, +0x00, 0xbd, 0x00, 0xbf, 0x00, 0xc1, 0x00, 0xc2, 0x00, 0xc3, 0x00, 0xc5, +0x00, 0xc6, 0x00, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x1d, 0x00, 0x29, +0x00, 0xbd, 0x00, 0xbb, 0x00, 0xb3, 0x00, 0xa7, 0x00, 0x98, 0x00, 0x85, +0x00, 0x72, 0x00, 0x5d, 0x00, 0x49, 0x00, 0x35, 0x00, 0x22, 0x00, 0x10, +0x00, 0x00, 0x00, 0x0f, 0x00, 0x1d, 0x00, 0x29, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x3d, 0x00, 0x39, 0x00, 0x33, 0x00, +0x2c, 0x00, 0x23, 0x00, 0x19, 0x00, 0x0f, 0x00, 0x0c, 0x07, 0x08, 0x0e, +0x05, 0x14, 0x02, 0x1a, 0x00, 0x1f, 0x00, 0x2c, 0x00, 0x38, 0x00, 0x42, +0x3e, 0x00, 0x3d, 0x00, 0x38, 0x00, 0x30, 0x00, 0x25, 0x00, 0x19, 0x00, +0x0c, 0x00, 0x00, 0x01, 0x00, 0x0e, 0x00, 0x1c, 0x00, 0x28, 0x00, 0x34, +0x00, 0x3f, 0x00, 0x49, 0x00, 0x53, 0x00, 0x5b, 0x36, 0x4a, 0x28, 0x52, +0x1d, 0x5b, 0x16, 0x63, 0x10, 0x6a, 0x0c, 0x71, 0x09, 0x77, 0x07, 0x7d, +0x05, 0x82, 0x03, 0x87, 0x02, 0x8c, 0x02, 0x90, 0x01, 0x94, 0x00, 0x99, +0x00, 0x9c, 0x00, 0x9e, 0x00, 0xa1, 0x00, 0xa4, 0x00, 0xa7, 0x00, 0xaa, +0x1b, 0x30, 0x12, 0x3e, 0x0c, 0x4b, 0x07, 0x57, 0x04, 0x61, 0x02, 0x6b, +0x01, 0x73, 0x00, 0x7c, 0x00, 0x82, 0x00, 0x88, 0x00, 0x8f, 0x00, 0x93, +0x00, 0x97, 0x00, 0x9c, 0x00, 0x9f, 0x00, 0xa2, 0x00, 0xa5, 0x00, 0xa8, +0x00, 0xaa, 0x00, 0xac, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, +0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, +0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, +0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x0d, 0x86, 0x09, 0x8d, +0x06, 0x94, 0x03, 0x9a, 0x02, 0x9f, 0x01, 0xa4, 0x00, 0xa8, 0x00, 0xac, +0x00, 0xaf, 0x00, 0xb2, 0x00, 0xb6, 0x00, 0xb8, 0x00, 0xba, 0x00, 0xbc, +0x00, 0xbe, 0x00, 0xbf, 0x00, 0xc1, 0x00, 0xc2, 0x00, 0xc3, 0x00, 0xc4, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x1b, 0x00, 0xbe, 0x00, 0xbb, +0x00, 0xb5, 0x00, 0xaa, 0x00, 0x9d, 0x00, 0x8d, 0x00, 0x7b, 0x00, 0x68, +0x00, 0x55, 0x00, 0x43, 0x00, 0x30, 0x00, 0x1f, 0x00, 0x0f, 0x00, 0x00, +0x00, 0x0e, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x3f, 0x00, 0x3e, 0x00, 0x3a, 0x00, 0x35, 0x00, 0x2e, 0x00, 0x26, 0x00, +0x1d, 0x00, 0x14, 0x00, 0x0e, 0x03, 0x0b, 0x09, 0x08, 0x0f, 0x05, 0x15, +0x02, 0x1a, 0x00, 0x1f, 0x00, 0x2b, 0x00, 0x36, 0x3f, 0x00, 0x3d, 0x00, +0x39, 0x00, 0x32, 0x00, 0x29, 0x00, 0x1e, 0x00, 0x12, 0x00, 0x06, 0x00, +0x00, 0x06, 0x00, 0x13, 0x00, 0x1f, 0x00, 0x2a, 0x00, 0x35, 0x00, 0x3f, +0x00, 0x49, 0x00, 0x51, 0x37, 0x49, 0x2a, 0x51, 0x20, 0x58, 0x18, 0x5f, +0x13, 0x66, 0x0f, 0x6c, 0x0b, 0x73, 0x09, 0x78, 0x07, 0x7e, 0x05, 0x82, +0x03, 0x86, 0x02, 0x8b, 0x02, 0x8f, 0x01, 0x92, 0x01, 0x96, 0x00, 0x9a, +0x00, 0x9d, 0x00, 0x9f, 0x00, 0xa1, 0x00, 0xa4, 0x1c, 0x2f, 0x13, 0x3b, +0x0d, 0x47, 0x09, 0x51, 0x05, 0x5c, 0x04, 0x65, 0x02, 0x6e, 0x01, 0x75, +0x00, 0x7c, 0x00, 0x82, 0x00, 0x88, 0x00, 0x8d, 0x00, 0x91, 0x00, 0x96, +0x00, 0x99, 0x00, 0x9c, 0x00, 0xa0, 0x00, 0xa2, 0x00, 0xa5, 0x00, 0xa7, +0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, +0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, +0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, +0x00, 0xdd, 0x00, 0xdd, 0x0e, 0x86, 0x09, 0x8c, 0x06, 0x92, 0x04, 0x97, +0x02, 0x9c, 0x02, 0xa1, 0x01, 0xa5, 0x00, 0xa9, 0x00, 0xac, 0x00, 0xaf, +0x00, 0xb2, 0x00, 0xb5, 0x00, 0xb7, 0x00, 0xb9, 0x00, 0xbb, 0x00, 0xbc, +0x00, 0xbe, 0x00, 0xbf, 0x00, 0xc1, 0x00, 0xc2, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x0d, 0x00, 0xbe, 0x00, 0xbc, 0x00, 0xb6, 0x00, 0xad, +0x00, 0xa1, 0x00, 0x93, 0x00, 0x83, 0x00, 0x72, 0x00, 0x60, 0x00, 0x4f, +0x00, 0x3d, 0x00, 0x2d, 0x00, 0x1d, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x0d, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x3e, 0x00, +0x3b, 0x00, 0x36, 0x00, 0x30, 0x00, 0x29, 0x00, 0x21, 0x00, 0x19, 0x00, +0x10, 0x00, 0x0d, 0x05, 0x0a, 0x0b, 0x07, 0x10, 0x04, 0x16, 0x02, 0x1b, +0x00, 0x1f, 0x00, 0x2a, 0x3f, 0x00, 0x3d, 0x00, 0x3a, 0x00, 0x33, 0x00, +0x2b, 0x00, 0x22, 0x00, 0x17, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x0b, +0x00, 0x16, 0x00, 0x21, 0x00, 0x2c, 0x00, 0x36, 0x00, 0x3f, 0x00, 0x48, +0x38, 0x48, 0x2b, 0x4f, 0x22, 0x56, 0x1a, 0x5c, 0x15, 0x63, 0x11, 0x69, +0x0d, 0x6e, 0x0a, 0x74, 0x08, 0x78, 0x06, 0x7e, 0x05, 0x81, 0x04, 0x85, +0x03, 0x8a, 0x02, 0x8e, 0x02, 0x90, 0x01, 0x93, 0x00, 0x98, 0x00, 0x9b, +0x00, 0x9d, 0x00, 0x9f, 0x1c, 0x2d, 0x14, 0x39, 0x0e, 0x44, 0x0a, 0x4e, +0x07, 0x57, 0x04, 0x60, 0x02, 0x67, 0x01, 0x6f, 0x00, 0x76, 0x00, 0x7d, +0x00, 0x81, 0x00, 0x87, 0x00, 0x8c, 0x00, 0x90, 0x00, 0x94, 0x00, 0x97, +0x00, 0x9a, 0x00, 0x9d, 0x00, 0xa0, 0x00, 0xa2, 0x00, 0xdd, 0x00, 0xdd, +0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, +0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, +0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, +0x0e, 0x85, 0x0a, 0x8b, 0x07, 0x90, 0x05, 0x95, 0x03, 0x9a, 0x02, 0x9e, +0x01, 0xa2, 0x00, 0xa6, 0x00, 0xa9, 0x00, 0xad, 0x00, 0xaf, 0x00, 0xb2, +0x00, 0xb4, 0x00, 0xb6, 0x00, 0xb8, 0x00, 0xba, 0x00, 0xbb, 0x00, 0xbd, +0x00, 0xbe, 0x00, 0xbf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0xbe, 0x00, 0xbc, 0x00, 0xb7, 0x00, 0xaf, 0x00, 0xa5, 0x00, 0x98, +0x00, 0x89, 0x00, 0x7a, 0x00, 0x6a, 0x00, 0x59, 0x00, 0x49, 0x00, 0x39, +0x00, 0x29, 0x00, 0x1b, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x3e, 0x00, 0x3c, 0x00, 0x38, 0x00, +0x32, 0x00, 0x2c, 0x00, 0x25, 0x00, 0x1d, 0x00, 0x15, 0x00, 0x0e, 0x01, +0x0c, 0x07, 0x09, 0x0c, 0x06, 0x11, 0x04, 0x16, 0x02, 0x1b, 0x00, 0x1f, +0x3f, 0x00, 0x3e, 0x00, 0x3a, 0x00, 0x35, 0x00, 0x2e, 0x00, 0x25, 0x00, +0x1c, 0x00, 0x11, 0x00, 0x07, 0x00, 0x00, 0x03, 0x00, 0x0e, 0x00, 0x19, +0x00, 0x23, 0x00, 0x2d, 0x00, 0x36, 0x00, 0x3f, 0x38, 0x48, 0x2d, 0x4e, +0x23, 0x54, 0x1c, 0x5a, 0x17, 0x5f, 0x12, 0x66, 0x0f, 0x6a, 0x0c, 0x71, +0x0a, 0x74, 0x08, 0x79, 0x06, 0x7e, 0x05, 0x81, 0x04, 0x84, 0x03, 0x89, +0x02, 0x8d, 0x02, 0x8f, 0x01, 0x92, 0x01, 0x95, 0x00, 0x99, 0x00, 0x9b, +0x1c, 0x2d, 0x15, 0x37, 0x0f, 0x41, 0x0b, 0x4a, 0x07, 0x53, 0x05, 0x5b, +0x04, 0x63, 0x02, 0x69, 0x01, 0x70, 0x00, 0x77, 0x00, 0x7d, 0x00, 0x81, +0x00, 0x87, 0x00, 0x8a, 0x00, 0x8f, 0x00, 0x92, 0x00, 0x96, 0x00, 0x99, +0x00, 0x9b, 0x00, 0x9e, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, +0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, +0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, +0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x0e, 0x85, 0x0a, 0x8a, +0x07, 0x8f, 0x05, 0x93, 0x03, 0x98, 0x02, 0x9c, 0x02, 0xa0, 0x01, 0xa3, +0x00, 0xa6, 0x00, 0xaa, 0x00, 0xad, 0x00, 0xaf, 0x00, 0xb2, 0x00, 0xb3, +0x00, 0xb6, 0x00, 0xb7, 0x00, 0xb9, 0x00, 0xbb, 0x00, 0xbc, 0x00, 0xbd, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x39, 0x47, 0x2e, 0x4d, 0x25, 0x53, 0x1e, 0x58, +0x19, 0x5e, 0x14, 0x63, 0x11, 0x68, 0x0e, 0x6c, 0x0b, 0x72, 0x09, 0x75, +0x07, 0x79, 0x06, 0x7e, 0x05, 0x81, 0x04, 0x84, 0x03, 0x88, 0x02, 0x8c, +0x02, 0x8e, 0x01, 0x91, 0x01, 0x93, 0x00, 0x97, 0x1d, 0x2c, 0x16, 0x36, +0x10, 0x3e, 0x0c, 0x48, 0x09, 0x50, 0x06, 0x58, 0x04, 0x5f, 0x02, 0x66, +0x02, 0x6c, 0x01, 0x71, 0x00, 0x77, 0x00, 0x7d, 0x00, 0x81, 0x00, 0x86, +0x00, 0x8a, 0x00, 0x8e, 0x00, 0x91, 0x00, 0x94, 0x00, 0x97, 0x00, 0x9a, +0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, +0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, +0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, +0x00, 0xdd, 0x00, 0xdd, 0x0e, 0x84, 0x0b, 0x89, 0x08, 0x8d, 0x06, 0x92, +0x04, 0x96, 0x03, 0x9a, 0x02, 0x9e, 0x01, 0xa1, 0x01, 0xa4, 0x00, 0xa7, +0x00, 0xaa, 0x00, 0xad, 0x00, 0xaf, 0x00, 0xb1, 0x00, 0xb3, 0x00, 0xb5, +0x00, 0xb7, 0x00, 0xb8, 0x00, 0xba, 0x00, 0xbb, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x39, 0x46, 0x2f, 0x4c, 0x26, 0x51, 0x20, 0x56, 0x1a, 0x5c, 0x16, 0x60, +0x12, 0x66, 0x0f, 0x69, 0x0c, 0x6e, 0x0b, 0x73, 0x09, 0x76, 0x07, 0x7a, +0x06, 0x7e, 0x05, 0x81, 0x04, 0x84, 0x03, 0x88, 0x02, 0x8b, 0x02, 0x8e, +0x02, 0x90, 0x01, 0x92, 0x1d, 0x2b, 0x16, 0x34, 0x11, 0x3d, 0x0c, 0x45, +0x0a, 0x4c, 0x07, 0x54, 0x05, 0x5b, 0x04, 0x61, 0x02, 0x67, 0x01, 0x6d, +0x01, 0x73, 0x00, 0x78, 0x00, 0x7d, 0x00, 0x81, 0x00, 0x86, 0x00, 0x89, +0x00, 0x8d, 0x00, 0x90, 0x00, 0x93, 0x00, 0x95, 0x00, 0xdd, 0x00, 0xdd, +0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, +0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, +0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, +0x0e, 0x84, 0x0b, 0x88, 0x08, 0x8d, 0x06, 0x91, 0x05, 0x94, 0x03, 0x98, +0x02, 0x9c, 0x02, 0x9f, 0x01, 0xa2, 0x00, 0xa5, 0x00, 0xa8, 0x00, 0xaa, +0x00, 0xad, 0x00, 0xaf, 0x00, 0xb1, 0x00, 0xb3, 0x00, 0xb5, 0x00, 0xb6, +0x00, 0xb8, 0x00, 0xb9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x39, 0x46, 0x30, 0x4b, +0x28, 0x50, 0x21, 0x55, 0x1c, 0x59, 0x17, 0x5e, 0x14, 0x63, 0x10, 0x68, +0x0e, 0x6b, 0x0c, 0x70, 0x0a, 0x74, 0x08, 0x76, 0x07, 0x7b, 0x06, 0x7e, +0x05, 0x81, 0x04, 0x83, 0x03, 0x87, 0x02, 0x8a, 0x02, 0x8d, 0x02, 0x8f, +0x1e, 0x2a, 0x17, 0x33, 0x12, 0x3b, 0x0e, 0x43, 0x0a, 0x4a, 0x07, 0x51, +0x05, 0x58, 0x04, 0x5e, 0x03, 0x64, 0x02, 0x69, 0x01, 0x6f, 0x00, 0x74, +0x00, 0x78, 0x00, 0x7d, 0x00, 0x81, 0x00, 0x85, 0x00, 0x89, 0x00, 0x8b, +0x00, 0x8f, 0x00, 0x93, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, +0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, +0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, +0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x0f, 0x83, 0x0b, 0x88, +0x09, 0x8c, 0x07, 0x90, 0x05, 0x93, 0x03, 0x97, 0x02, 0x9a, 0x02, 0x9d, +0x01, 0xa0, 0x01, 0xa3, 0x00, 0xa6, 0x00, 0xa8, 0x00, 0xaa, 0x00, 0xad, +0x00, 0xaf, 0x00, 0xb1, 0x00, 0xb3, 0x00, 0xb4, 0x00, 0xb6, 0x00, 0xb8, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x3a, 0x46, 0x31, 0x4a, 0x29, 0x4e, 0x22, 0x54, +0x1d, 0x57, 0x19, 0x5d, 0x15, 0x60, 0x12, 0x65, 0x0f, 0x69, 0x0d, 0x6c, +0x0b, 0x71, 0x09, 0x74, 0x08, 0x77, 0x07, 0x7b, 0x06, 0x7f, 0x05, 0x81, +0x04, 0x83, 0x03, 0x86, 0x02, 0x8a, 0x02, 0x8c, 0x1e, 0x2a, 0x18, 0x32, +0x12, 0x39, 0x0f, 0x40, 0x0c, 0x48, 0x09, 0x4f, 0x07, 0x55, 0x05, 0x5a, +0x04, 0x60, 0x02, 0x66, 0x02, 0x6b, 0x01, 0x70, 0x00, 0x75, 0x00, 0x79, +0x00, 0x7d, 0x00, 0x81, 0x00, 0x84, 0x00, 0x88, 0x00, 0x8b, 0x00, 0x8e, +0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, +0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, +0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, +0x00, 0xdd, 0x00, 0xdd, 0x0f, 0x83, 0x0c, 0x87, 0x09, 0x8b, 0x07, 0x8e, +0x06, 0x92, 0x04, 0x96, 0x03, 0x99, 0x02, 0x9b, 0x02, 0x9e, 0x01, 0xa1, +0x01, 0xa4, 0x00, 0xa6, 0x00, 0xa9, 0x00, 0xab, 0x00, 0xad, 0x00, 0xaf, +0x00, 0xb0, 0x00, 0xb2, 0x00, 0xb4, 0x00, 0xb5, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x3a, 0x45, 0x31, 0x49, 0x2a, 0x4d, 0x24, 0x52, 0x1f, 0x56, 0x1a, 0x5b, +0x16, 0x5f, 0x13, 0x63, 0x10, 0x67, 0x0e, 0x6a, 0x0c, 0x6e, 0x0b, 0x72, +0x09, 0x75, 0x07, 0x77, 0x07, 0x7b, 0x06, 0x7f, 0x05, 0x81, 0x04, 0x83, +0x03, 0x85, 0x02, 0x89, 0x1e, 0x29, 0x18, 0x31, 0x13, 0x38, 0x0f, 0x3f, +0x0c, 0x45, 0x0a, 0x4c, 0x07, 0x52, 0x05, 0x58, 0x04, 0x5d, 0x04, 0x63, +0x02, 0x67, 0x01, 0x6c, 0x01, 0x71, 0x00, 0x75, 0x00, 0x79, 0x00, 0x7d, +0x00, 0x81, 0x00, 0x84, 0x00, 0x88, 0x00, 0x8b, 0x00, 0xdd, 0x00, 0xdd, +0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, +0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, +0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, +0x0f, 0x83, 0x0c, 0x87, 0x09, 0x8a, 0x07, 0x8e, 0x06, 0x91, 0x05, 0x94, +0x03, 0x97, 0x02, 0x9a, 0x02, 0x9d, 0x02, 0xa0, 0x01, 0xa2, 0x00, 0xa4, +0x00, 0xa7, 0x00, 0xa9, 0x00, 0xab, 0x00, 0xad, 0x00, 0xaf, 0x00, 0xb0, +0x00, 0xb2, 0x00, 0xb4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3a, 0x45, 0x32, 0x48, +0x2b, 0x4d, 0x25, 0x51, 0x20, 0x55, 0x1b, 0x59, 0x18, 0x5e, 0x14, 0x60, +0x12, 0x65, 0x0f, 0x68, 0x0d, 0x6b, 0x0c, 0x6f, 0x0a, 0x73, 0x09, 0x75, +0x07, 0x77, 0x06, 0x7b, 0x06, 0x7f, 0x05, 0x81, 0x04, 0x83, 0x03, 0x85, +0x1e, 0x29, 0x19, 0x30, 0x14, 0x37, 0x0f, 0x3d, 0x0c, 0x44, 0x0a, 0x4a, +0x07, 0x50, 0x06, 0x55, 0x05, 0x5b, 0x04, 0x60, 0x02, 0x64, 0x02, 0x69, +0x01, 0x6d, 0x01, 0x72, 0x00, 0x76, 0x00, 0x7a, 0x00, 0x7d, 0x00, 0x81, +0x00, 0x83, 0x00, 0x87, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, +0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, +0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, +0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x0f, 0x83, 0x0c, 0x86, +0x0a, 0x8a, 0x07, 0x8d, 0x06, 0x90, 0x05, 0x93, 0x03, 0x96, 0x03, 0x99, +0x02, 0x9c, 0x02, 0x9e, 0x01, 0xa0, 0x01, 0xa3, 0x00, 0xa5, 0x00, 0xa7, +0x00, 0xa9, 0x00, 0xab, 0x00, 0xad, 0x00, 0xaf, 0x00, 0xb0, 0x00, 0xb2, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x3b, 0x45, 0x33, 0x48, 0x2c, 0x4d, 0x26, 0x4f, +0x21, 0x55, 0x1c, 0x57, 0x19, 0x5c, 0x16, 0x5f, 0x13, 0x63, 0x10, 0x67, +0x0e, 0x6a, 0x0c, 0x6c, 0x0b, 0x71, 0x0a, 0x73, 0x09, 0x76, 0x07, 0x78, +0x06, 0x7c, 0x06, 0x7f, 0x05, 0x81, 0x04, 0x83, 0x1e, 0x28, 0x19, 0x2f, +0x15, 0x35, 0x10, 0x3c, 0x0d, 0x42, 0x0b, 0x48, 0x09, 0x4e, 0x07, 0x53, +0x05, 0x58, 0x04, 0x5d, 0x04, 0x62, 0x02, 0x66, 0x02, 0x6b, 0x01, 0x6f, +0x00, 0x73, 0x00, 0x76, 0x00, 0x7a, 0x00, 0x7d, 0x00, 0x81, 0x00, 0x83, +0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, +0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, +0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, +0x00, 0xdd, 0x00, 0xdd, 0x0f, 0x82, 0x0c, 0x86, 0x0a, 0x89, 0x08, 0x8c, +0x06, 0x8f, 0x05, 0x92, 0x04, 0x95, 0x03, 0x98, 0x02, 0x9a, 0x02, 0x9d, +0x02, 0x9f, 0x01, 0xa1, 0x01, 0xa4, 0x00, 0xa6, 0x00, 0xa8, 0x00, 0xa9, +0x00, 0xab, 0x00, 0xad, 0x00, 0xaf, 0x00, 0xb0, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x3b, 0x44, 0x33, 0x47, 0x2c, 0x4c, 0x27, 0x4f, 0x22, 0x54, 0x1e, 0x56, +0x1a, 0x5a, 0x17, 0x5e, 0x14, 0x60, 0x12, 0x65, 0x10, 0x68, 0x0e, 0x6a, +0x0c, 0x6e, 0x0b, 0x72, 0x09, 0x74, 0x08, 0x76, 0x07, 0x78, 0x06, 0x7c, +0x06, 0x7f, 0x05, 0x81, 0x1e, 0x28, 0x19, 0x2f, 0x16, 0x35, 0x12, 0x3b, +0x0f, 0x41, 0x0c, 0x46, 0x0a, 0x4c, 0x07, 0x51, 0x05, 0x55, 0x05, 0x5b, +0x04, 0x5f, 0x02, 0x63, 0x02, 0x68, 0x01, 0x6b, 0x01, 0x70, 0x00, 0x73, +0x00, 0x77, 0x00, 0x7b, 0x00, 0x7d, 0x00, 0x81, 0x00, 0xdd, 0x00, 0xdd, +0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, +0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, +0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, +0x0f, 0x82, 0x0c, 0x86, 0x0b, 0x89, 0x09, 0x8c, 0x07, 0x8f, 0x06, 0x91, +0x05, 0x94, 0x03, 0x97, 0x02, 0x99, 0x02, 0x9c, 0x02, 0x9e, 0x01, 0xa0, +0x01, 0xa2, 0x00, 0xa4, 0x00, 0xa6, 0x00, 0xa8, 0x00, 0xaa, 0x00, 0xac, +0x00, 0xad, 0x00, 0xaf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2f, 0x23, 0x25, 0x22, +0x23, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, +0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x21, 0x22, 0x22, 0x22, +0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x00, 0x44, 0x05, 0x25, 0x0d, 0x23, 0x12, 0x22, +0x15, 0x22, 0x17, 0x22, 0x18, 0x22, 0x1a, 0x22, 0x1b, 0x22, 0x1b, 0x22, +0x1c, 0x22, 0x1c, 0x22, 0x1c, 0x22, 0x1d, 0x22, 0x1d, 0x22, 0x1e, 0x22, +0x1e, 0x22, 0x1e, 0x22, 0x1e, 0x22, 0x1e, 0x22, 0x10, 0x33, 0x13, 0x23, +0x17, 0x22, 0x1a, 0x22, 0x1b, 0x22, 0x1c, 0x22, 0x1d, 0x22, 0x1e, 0x22, +0x1e, 0x22, 0x1e, 0x22, 0x1f, 0x22, 0x1f, 0x22, 0x1f, 0x22, 0x1f, 0x22, +0x1f, 0x22, 0x20, 0x22, 0x20, 0x22, 0x20, 0x22, 0x20, 0x22, 0x20, 0x22, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x35, 0x25, 0x2b, 0x23, 0x27, 0x22, 0x25, 0x22, +0x24, 0x22, 0x23, 0x22, 0x23, 0x22, 0x23, 0x22, 0x22, 0x22, 0x22, 0x22, +0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, +0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x00, 0x9d, 0x00, 0x6b, 0x01, 0x51, 0x04, 0x45, 0x08, 0x3d, 0x0b, 0x38, +0x0d, 0x35, 0x0f, 0x33, 0x10, 0x30, 0x12, 0x2f, 0x13, 0x2d, 0x14, 0x2d, +0x15, 0x2c, 0x16, 0x2b, 0x16, 0x2a, 0x17, 0x2a, 0x18, 0x29, 0x18, 0x29, +0x19, 0x28, 0x19, 0x28, 0x10, 0x5f, 0x10, 0x46, 0x11, 0x39, 0x13, 0x33, +0x15, 0x2f, 0x16, 0x2d, 0x17, 0x2b, 0x18, 0x2a, 0x19, 0x29, 0x1a, 0x28, +0x1a, 0x27, 0x1b, 0x27, 0x1b, 0x27, 0x1c, 0x26, 0x1c, 0x26, 0x1c, 0x26, +0x1d, 0x25, 0x1d, 0x25, 0x1d, 0x25, 0x1d, 0x25, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x38, 0x2a, 0x2e, 0x26, 0x2a, 0x25, 0x27, 0x24, 0x26, 0x23, 0x25, 0x23, +0x24, 0x23, 0x24, 0x22, 0x23, 0x22, 0x23, 0x22, 0x23, 0x22, 0x23, 0x22, +0x23, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, +0x22, 0x22, 0x22, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x00, 0xbc, 0x00, 0x8e, +0x00, 0x73, 0x00, 0x60, 0x02, 0x55, 0x04, 0x4c, 0x06, 0x47, 0x08, 0x42, +0x0a, 0x3e, 0x0c, 0x3b, 0x0d, 0x39, 0x0e, 0x37, 0x0f, 0x36, 0x10, 0x34, +0x11, 0x33, 0x12, 0x32, 0x12, 0x31, 0x13, 0x30, 0x14, 0x2f, 0x15, 0x2f, +0x10, 0x6f, 0x10, 0x58, 0x10, 0x4a, 0x11, 0x41, 0x12, 0x3b, 0x13, 0x37, +0x14, 0x34, 0x15, 0x32, 0x16, 0x30, 0x17, 0x2e, 0x17, 0x2d, 0x18, 0x2c, +0x18, 0x2c, 0x19, 0x2b, 0x19, 0x2a, 0x1a, 0x2a, 0x1a, 0x29, 0x1a, 0x29, +0x1b, 0x28, 0x1b, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x39, 0x2e, 0x31, 0x29, +0x2c, 0x27, 0x2a, 0x26, 0x28, 0x25, 0x27, 0x24, 0x25, 0x24, 0x25, 0x23, +0x24, 0x23, 0x24, 0x23, 0x24, 0x23, 0x24, 0x23, 0x23, 0x22, 0x23, 0x22, +0x23, 0x22, 0x23, 0x22, 0x23, 0x22, 0x23, 0x22, 0x22, 0x22, 0x22, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x00, 0xc6, 0x00, 0xa4, 0x00, 0x89, 0x00, 0x77, +0x00, 0x67, 0x01, 0x5e, 0x03, 0x55, 0x04, 0x50, 0x05, 0x4b, 0x07, 0x47, +0x09, 0x44, 0x0a, 0x41, 0x0b, 0x3e, 0x0c, 0x3d, 0x0c, 0x3b, 0x0e, 0x39, +0x0f, 0x38, 0x0f, 0x37, 0x0f, 0x35, 0x10, 0x35, 0x10, 0x74, 0x10, 0x63, +0x10, 0x55, 0x10, 0x4c, 0x11, 0x44, 0x11, 0x40, 0x12, 0x3b, 0x13, 0x39, +0x13, 0x36, 0x14, 0x34, 0x15, 0x33, 0x16, 0x31, 0x16, 0x30, 0x17, 0x2f, +0x17, 0x2e, 0x18, 0x2d, 0x18, 0x2d, 0x18, 0x2c, 0x18, 0x2b, 0x19, 0x2b, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x3a, 0x31, 0x33, 0x2c, 0x2f, 0x29, 0x2b, 0x28, +0x29, 0x26, 0x28, 0x25, 0x27, 0x25, 0x26, 0x24, 0x25, 0x24, 0x25, 0x24, +0x25, 0x23, 0x24, 0x23, 0x24, 0x23, 0x24, 0x23, 0x24, 0x23, 0x23, 0x23, +0x23, 0x23, 0x23, 0x22, 0x23, 0x22, 0x23, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x00, 0xcd, 0x00, 0xb0, 0x00, 0x9a, 0x00, 0x87, 0x00, 0x78, 0x00, 0x6c, +0x01, 0x64, 0x02, 0x5c, 0x03, 0x57, 0x04, 0x51, 0x05, 0x4e, 0x07, 0x4a, +0x07, 0x48, 0x09, 0x45, 0x0a, 0x43, 0x0a, 0x40, 0x0c, 0x3f, 0x0c, 0x3d, +0x0c, 0x3c, 0x0d, 0x3b, 0x10, 0x77, 0x10, 0x69, 0x10, 0x5e, 0x10, 0x54, +0x10, 0x4d, 0x11, 0x47, 0x11, 0x43, 0x12, 0x3f, 0x12, 0x3c, 0x13, 0x39, +0x13, 0x38, 0x14, 0x36, 0x14, 0x35, 0x15, 0x33, 0x16, 0x32, 0x16, 0x31, +0x17, 0x30, 0x17, 0x2f, 0x17, 0x2f, 0x17, 0x2e, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x3b, 0x33, 0x34, 0x2e, 0x30, 0x2b, 0x2d, 0x29, 0x2b, 0x28, 0x29, 0x27, +0x29, 0x26, 0x27, 0x25, 0x27, 0x25, 0x26, 0x24, 0x25, 0x24, 0x25, 0x24, +0x25, 0x24, 0x24, 0x24, 0x24, 0x23, 0x24, 0x23, 0x24, 0x23, 0x24, 0x23, +0x23, 0x23, 0x23, 0x23, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x00, 0xcf, 0x00, 0xb9, +0x00, 0xa4, 0x00, 0x94, 0x00, 0x85, 0x00, 0x7a, 0x00, 0x70, 0x00, 0x68, +0x01, 0x61, 0x02, 0x5c, 0x04, 0x57, 0x04, 0x53, 0x05, 0x50, 0x06, 0x4c, +0x07, 0x4a, 0x07, 0x48, 0x09, 0x45, 0x0a, 0x44, 0x0a, 0x42, 0x0b, 0x41, +0x10, 0x78, 0x10, 0x6d, 0x10, 0x63, 0x10, 0x5b, 0x10, 0x53, 0x10, 0x4e, +0x11, 0x49, 0x11, 0x45, 0x11, 0x41, 0x12, 0x3f, 0x13, 0x3c, 0x13, 0x3a, +0x13, 0x39, 0x14, 0x37, 0x14, 0x36, 0x14, 0x35, 0x15, 0x33, 0x16, 0x33, +0x16, 0x32, 0x16, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x34, 0x36, 0x30, +0x32, 0x2d, 0x2f, 0x2b, 0x2d, 0x29, 0x2b, 0x28, 0x29, 0x27, 0x28, 0x27, +0x27, 0x26, 0x27, 0x25, 0x27, 0x25, 0x25, 0x25, 0x25, 0x24, 0x25, 0x24, +0x25, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x23, 0x24, 0x23, 0x24, 0x23, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x00, 0xd2, 0x00, 0xbe, 0x00, 0xad, 0x00, 0x9d, +0x00, 0x90, 0x00, 0x84, 0x00, 0x7a, 0x00, 0x72, 0x00, 0x6b, 0x01, 0x65, +0x02, 0x60, 0x02, 0x5b, 0x04, 0x58, 0x04, 0x54, 0x05, 0x51, 0x05, 0x4f, +0x07, 0x4c, 0x07, 0x4a, 0x07, 0x48, 0x09, 0x46, 0x10, 0x7a, 0x10, 0x70, +0x10, 0x67, 0x10, 0x5f, 0x10, 0x59, 0x10, 0x53, 0x10, 0x4e, 0x11, 0x4a, +0x11, 0x46, 0x11, 0x43, 0x12, 0x41, 0x12, 0x3e, 0x13, 0x3d, 0x13, 0x3b, +0x13, 0x39, 0x13, 0x38, 0x14, 0x37, 0x14, 0x36, 0x14, 0x35, 0x15, 0x34, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x3c, 0x35, 0x37, 0x31, 0x33, 0x2e, 0x30, 0x2c, +0x2d, 0x2a, 0x2c, 0x29, 0x2b, 0x28, 0x29, 0x27, 0x28, 0x27, 0x28, 0x27, +0x27, 0x25, 0x27, 0x25, 0x26, 0x25, 0x25, 0x25, 0x25, 0x24, 0x25, 0x24, +0x25, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x00, 0xd3, 0x00, 0xc2, 0x00, 0xb2, 0x00, 0xa4, 0x00, 0x98, 0x00, 0x8d, +0x00, 0x83, 0x00, 0x7b, 0x00, 0x73, 0x00, 0x6e, 0x01, 0x67, 0x01, 0x63, +0x02, 0x5f, 0x02, 0x5b, 0x04, 0x58, 0x04, 0x55, 0x05, 0x52, 0x05, 0x50, +0x06, 0x4e, 0x07, 0x4c, 0x10, 0x7a, 0x10, 0x72, 0x10, 0x6a, 0x10, 0x63, +0x10, 0x5d, 0x10, 0x57, 0x10, 0x52, 0x10, 0x4e, 0x11, 0x4a, 0x11, 0x48, +0x11, 0x44, 0x11, 0x42, 0x12, 0x40, 0x12, 0x3e, 0x13, 0x3d, 0x13, 0x3b, +0x13, 0x3a, 0x13, 0x39, 0x14, 0x38, 0x14, 0x37, 0x0f, 0x00, 0x1f, 0x00, +0x33, 0x00, 0x39, 0x00, 0x3c, 0x00, 0x3d, 0x00, 0x3e, 0x00, 0x3e, 0x00, +0x3e, 0x00, 0x3e, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3f, 0x00, +0x3f, 0x00, 0x3f, 0x00, 0x0b, 0x3b, 0x17, 0x07, 0x2c, 0x00, 0x36, 0x00, +0x3a, 0x00, 0x3c, 0x00, 0x3d, 0x00, 0x3d, 0x00, 0x3e, 0x00, 0x3e, 0x00, +0x3e, 0x00, 0x3e, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3f, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0x00, 0x3d, 0x00, +0x4c, 0x00, 0x4c, 0x00, 0x48, 0x00, 0x42, 0x00, 0x3e, 0x00, 0x3e, 0x00, +0x3e, 0x00, 0x3e, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3f, 0x00, +0x3f, 0x00, 0x3f, 0x00, 0x07, 0x47, 0x0f, 0x0f, 0x26, 0x00, 0x33, 0x00, +0x38, 0x00, 0x3a, 0x00, 0x3c, 0x00, 0x3d, 0x00, 0x3d, 0x00, 0x3e, 0x00, +0x3e, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3f, 0x00, +0x3c, 0x37, 0x37, 0x32, 0x34, 0x30, 0x31, 0x2d, 0x2f, 0x2c, 0x2d, 0x2b, +0x2b, 0x29, 0x2b, 0x28, 0x29, 0x27, 0x28, 0x27, 0x28, 0x27, 0x27, 0x26, +0x27, 0x25, 0x27, 0x25, 0x26, 0x25, 0x25, 0x25, 0x25, 0x24, 0x25, 0x24, +0x25, 0x24, 0x24, 0x24, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x00, 0xd5, 0x00, 0xc5, +0x00, 0xb7, 0x00, 0xaa, 0x00, 0x9f, 0x00, 0x95, 0x00, 0x8b, 0x00, 0x83, +0x00, 0x7c, 0x00, 0x75, 0x00, 0x6f, 0x00, 0x69, 0x01, 0x66, 0x02, 0x61, +0x02, 0x5e, 0x03, 0x5a, 0x04, 0x58, 0x04, 0x55, 0x05, 0x53, 0x05, 0x51, +0x10, 0x7b, 0x10, 0x73, 0x10, 0x6c, 0x10, 0x66, 0x10, 0x60, 0x10, 0x5b, +0x10, 0x56, 0x10, 0x52, 0x10, 0x4f, 0x11, 0x4b, 0x11, 0x48, 0x11, 0x45, +0x11, 0x44, 0x12, 0x41, 0x12, 0x40, 0x12, 0x3e, 0x13, 0x3d, 0x13, 0x3b, +0x13, 0x3a, 0x13, 0x39, 0x00, 0x00, 0x05, 0x00, 0x1f, 0x00, 0x2e, 0x00, +0x35, 0x00, 0x38, 0x00, 0x3a, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3d, 0x00, +0x3d, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3e, 0x00, +0x00, 0x6f, 0x02, 0x27, 0x12, 0x02, 0x25, 0x00, 0x2f, 0x00, 0x35, 0x00, +0x38, 0x00, 0x3a, 0x00, 0x3b, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3d, 0x00, +0x3d, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x30, 0x00, 0x39, 0x00, 0x42, 0x00, +0x41, 0x00, 0x3d, 0x00, 0x3a, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3d, 0x00, +0x3d, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3e, 0x00, +0x00, 0x7f, 0x00, 0x3f, 0x05, 0x05, 0x1c, 0x00, 0x2a, 0x00, 0x31, 0x00, +0x35, 0x00, 0x38, 0x00, 0x39, 0x00, 0x3b, 0x00, 0x3c, 0x00, 0x3c, 0x00, +0x3d, 0x00, 0x3d, 0x00, 0x3d, 0x00, 0x3e, 0x00, 0x3c, 0x37, 0x38, 0x33, +0x34, 0x31, 0x32, 0x2f, 0x30, 0x2d, 0x2d, 0x2b, 0x2d, 0x2b, 0x2b, 0x29, +0x2b, 0x28, 0x29, 0x28, 0x28, 0x27, 0x28, 0x27, 0x27, 0x27, 0x27, 0x25, +0x27, 0x25, 0x27, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x24, 0x25, 0x24, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x00, 0xd5, 0x00, 0xc8, 0x00, 0xbb, 0x00, 0xaf, +0x00, 0xa5, 0x00, 0x9b, 0x00, 0x92, 0x00, 0x8a, 0x00, 0x82, 0x00, 0x7c, +0x00, 0x76, 0x00, 0x70, 0x00, 0x6c, 0x01, 0x67, 0x01, 0x64, 0x02, 0x60, +0x02, 0x5d, 0x04, 0x5b, 0x04, 0x58, 0x04, 0x55, 0x10, 0x7b, 0x10, 0x75, +0x10, 0x6e, 0x10, 0x68, 0x10, 0x63, 0x10, 0x5e, 0x10, 0x5a, 0x10, 0x56, +0x10, 0x52, 0x10, 0x4f, 0x11, 0x4c, 0x11, 0x49, 0x11, 0x47, 0x11, 0x44, +0x11, 0x43, 0x12, 0x41, 0x12, 0x3f, 0x13, 0x3e, 0x13, 0x3d, 0x13, 0x3b, +0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x16, 0x00, 0x24, 0x00, 0x2c, 0x00, +0x31, 0x00, 0x35, 0x00, 0x37, 0x00, 0x39, 0x00, 0x3a, 0x00, 0x3b, 0x00, +0x3b, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3d, 0x00, 0x00, 0x9f, 0x00, 0x6f, +0x00, 0x22, 0x0b, 0x09, 0x16, 0x00, 0x23, 0x00, 0x2a, 0x00, 0x2f, 0x00, +0x33, 0x00, 0x35, 0x00, 0x37, 0x00, 0x38, 0x00, 0x39, 0x00, 0x3a, 0x00, +0x3b, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x4c, 0x00, 0x39, 0x00, 0x16, 0x00, 0x28, 0x00, 0x2f, 0x00, 0x2e, 0x00, +0x31, 0x00, 0x35, 0x00, 0x37, 0x00, 0x39, 0x00, 0x3a, 0x00, 0x3b, 0x00, +0x3b, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3d, 0x00, 0x00, 0xa5, 0x00, 0x7f, +0x00, 0x3f, 0x00, 0x12, 0x09, 0x00, 0x19, 0x00, 0x23, 0x00, 0x2a, 0x00, +0x2f, 0x00, 0x32, 0x00, 0x34, 0x00, 0x36, 0x00, 0x38, 0x00, 0x39, 0x00, +0x3a, 0x00, 0x3a, 0x00, 0x3d, 0x38, 0x39, 0x34, 0x35, 0x32, 0x33, 0x30, +0x30, 0x2d, 0x2f, 0x2d, 0x2d, 0x2b, 0x2c, 0x2b, 0x2b, 0x29, 0x2b, 0x28, +0x29, 0x28, 0x28, 0x26, 0x28, 0x27, 0x27, 0x27, 0x27, 0x26, 0x27, 0x25, +0x27, 0x25, 0x26, 0x25, 0x25, 0x25, 0x25, 0x25, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x00, 0xd6, 0x00, 0xca, 0x00, 0xbe, 0x00, 0xb3, 0x00, 0xaa, 0x00, 0xa0, +0x00, 0x98, 0x00, 0x90, 0x00, 0x88, 0x00, 0x82, 0x00, 0x7d, 0x00, 0x77, +0x00, 0x71, 0x00, 0x6d, 0x01, 0x69, 0x01, 0x66, 0x02, 0x63, 0x02, 0x60, +0x02, 0x5d, 0x04, 0x5b, 0x10, 0x7c, 0x10, 0x76, 0x10, 0x70, 0x10, 0x6a, +0x10, 0x65, 0x10, 0x61, 0x10, 0x5d, 0x10, 0x59, 0x10, 0x55, 0x10, 0x52, +0x10, 0x4f, 0x11, 0x4c, 0x11, 0x49, 0x11, 0x47, 0x11, 0x45, 0x11, 0x44, +0x12, 0x42, 0x12, 0x41, 0x12, 0x3f, 0x13, 0x3e, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x1d, 0x00, 0x25, 0x00, 0x2b, 0x00, +0x2f, 0x00, 0x32, 0x00, 0x34, 0x00, 0x36, 0x00, 0x37, 0x00, 0x38, 0x00, +0x39, 0x00, 0x3a, 0x00, 0x00, 0xaf, 0x00, 0x93, 0x00, 0x58, 0x00, 0x21, +0x08, 0x0e, 0x0e, 0x02, 0x18, 0x00, 0x20, 0x00, 0x27, 0x00, 0x2b, 0x00, +0x2f, 0x00, 0x31, 0x00, 0x33, 0x00, 0x35, 0x00, 0x36, 0x00, 0x38, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x42, 0x00, +0x28, 0x00, 0x09, 0x00, 0x16, 0x00, 0x1d, 0x00, 0x25, 0x00, 0x2b, 0x00, +0x2f, 0x00, 0x32, 0x00, 0x34, 0x00, 0x36, 0x00, 0x37, 0x00, 0x38, 0x00, +0x39, 0x00, 0x3a, 0x00, 0x00, 0xb2, 0x00, 0x9c, 0x00, 0x6d, 0x00, 0x3f, +0x00, 0x1d, 0x00, 0x05, 0x0b, 0x00, 0x16, 0x00, 0x1f, 0x00, 0x25, 0x00, +0x29, 0x00, 0x2d, 0x00, 0x30, 0x00, 0x32, 0x00, 0x33, 0x00, 0x35, 0x00, +0x3d, 0x38, 0x39, 0x35, 0x36, 0x33, 0x33, 0x30, 0x31, 0x2f, 0x30, 0x2d, +0x2e, 0x2c, 0x2d, 0x2b, 0x2b, 0x2b, 0x2b, 0x28, 0x2b, 0x28, 0x28, 0x28, +0x28, 0x27, 0x28, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x26, 0x27, 0x25, +0x27, 0x25, 0x25, 0x25, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x00, 0xd6, 0x00, 0xcc, +0x00, 0xc0, 0x00, 0xb7, 0x00, 0xad, 0x00, 0xa5, 0x00, 0x9d, 0x00, 0x96, +0x00, 0x8f, 0x00, 0x88, 0x00, 0x81, 0x00, 0x7d, 0x00, 0x77, 0x00, 0x73, +0x00, 0x6f, 0x00, 0x6b, 0x01, 0x67, 0x01, 0x64, 0x02, 0x62, 0x02, 0x5f, +0x10, 0x7c, 0x10, 0x77, 0x10, 0x71, 0x10, 0x6c, 0x10, 0x67, 0x10, 0x63, +0x10, 0x5f, 0x10, 0x5c, 0x10, 0x58, 0x10, 0x55, 0x10, 0x51, 0x10, 0x4f, +0x11, 0x4c, 0x11, 0x4a, 0x11, 0x48, 0x11, 0x46, 0x11, 0x44, 0x11, 0x43, +0x12, 0x42, 0x12, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x0d, 0x00, 0x18, 0x00, 0x1f, 0x00, 0x25, 0x00, 0x2a, 0x00, +0x2d, 0x00, 0x30, 0x00, 0x32, 0x00, 0x34, 0x00, 0x35, 0x00, 0x37, 0x00, +0x00, 0xb5, 0x00, 0xa4, 0x00, 0x7a, 0x00, 0x4a, 0x00, 0x20, 0x06, 0x12, +0x0c, 0x07, 0x10, 0x00, 0x18, 0x00, 0x1f, 0x00, 0x24, 0x00, 0x28, 0x00, +0x2c, 0x00, 0x2e, 0x00, 0x30, 0x00, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x41, 0x00, 0x2f, 0x00, 0x16, 0x00, +0x00, 0x00, 0x0d, 0x00, 0x18, 0x00, 0x1f, 0x00, 0x25, 0x00, 0x2a, 0x00, +0x2d, 0x00, 0x30, 0x00, 0x32, 0x00, 0x34, 0x00, 0x35, 0x00, 0x37, 0x00, +0x00, 0xb7, 0x00, 0xaa, 0x00, 0x88, 0x00, 0x62, 0x00, 0x3f, 0x00, 0x24, +0x00, 0x0f, 0x00, 0x00, 0x0b, 0x00, 0x14, 0x00, 0x1b, 0x00, 0x21, 0x00, +0x25, 0x00, 0x29, 0x00, 0x2b, 0x00, 0x2e, 0x00, 0x3d, 0x39, 0x3a, 0x36, +0x36, 0x33, 0x34, 0x31, 0x32, 0x30, 0x30, 0x2d, 0x2f, 0x2d, 0x2d, 0x2b, +0x2d, 0x2b, 0x2b, 0x2a, 0x2b, 0x28, 0x2a, 0x28, 0x28, 0x28, 0x28, 0x27, +0x28, 0x26, 0x28, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x25, 0x27, 0x25, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x00, 0xd7, 0x00, 0xcc, 0x00, 0xc3, 0x00, 0xba, +0x00, 0xb1, 0x00, 0xa8, 0x00, 0xa0, 0x00, 0x99, 0x00, 0x93, 0x00, 0x8d, +0x00, 0x87, 0x00, 0x81, 0x00, 0x7d, 0x00, 0x78, 0x00, 0x74, 0x00, 0x70, +0x00, 0x6c, 0x01, 0x69, 0x01, 0x66, 0x02, 0x63, 0x10, 0x7c, 0x10, 0x77, +0x10, 0x72, 0x10, 0x6e, 0x10, 0x69, 0x10, 0x65, 0x10, 0x61, 0x10, 0x5d, +0x10, 0x5a, 0x10, 0x57, 0x10, 0x54, 0x10, 0x51, 0x10, 0x4f, 0x11, 0x4d, +0x11, 0x4b, 0x11, 0x49, 0x11, 0x47, 0x11, 0x45, 0x11, 0x44, 0x12, 0x42, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x0b, 0x00, 0x14, 0x00, 0x1b, 0x00, 0x21, 0x00, 0x25, 0x00, 0x29, 0x00, +0x2c, 0x00, 0x2f, 0x00, 0x31, 0x00, 0x32, 0x00, 0x00, 0xb9, 0x00, 0xad, +0x00, 0x8f, 0x00, 0x68, 0x00, 0x42, 0x00, 0x20, 0x05, 0x14, 0x0a, 0x0b, +0x0d, 0x04, 0x12, 0x00, 0x19, 0x00, 0x1e, 0x00, 0x23, 0x00, 0x26, 0x00, +0x29, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x42, 0x00, 0x3d, 0x00, 0x2e, 0x00, 0x1d, 0x00, 0x0d, 0x00, 0x00, 0x00, +0x0b, 0x00, 0x14, 0x00, 0x1b, 0x00, 0x21, 0x00, 0x25, 0x00, 0x29, 0x00, +0x2c, 0x00, 0x2f, 0x00, 0x31, 0x00, 0x32, 0x00, 0x00, 0xba, 0x00, 0xb1, +0x00, 0x99, 0x00, 0x7a, 0x00, 0x5b, 0x00, 0x3f, 0x00, 0x29, 0x00, 0x16, +0x00, 0x08, 0x02, 0x00, 0x0c, 0x00, 0x13, 0x00, 0x19, 0x00, 0x1e, 0x00, +0x22, 0x00, 0x25, 0x00, 0x3d, 0x39, 0x3a, 0x36, 0x37, 0x34, 0x35, 0x32, +0x33, 0x30, 0x31, 0x2f, 0x30, 0x2d, 0x2e, 0x2d, 0x2d, 0x2a, 0x2c, 0x2b, +0x2b, 0x2a, 0x2b, 0x28, 0x2a, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x27, +0x28, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x26, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x00, 0xd7, 0x00, 0xce, 0x00, 0xc5, 0x00, 0xbc, 0x00, 0xb4, 0x00, 0xac, +0x00, 0xa5, 0x00, 0x9e, 0x00, 0x97, 0x00, 0x91, 0x00, 0x8c, 0x00, 0x87, +0x00, 0x81, 0x00, 0x7d, 0x00, 0x78, 0x00, 0x75, 0x00, 0x71, 0x00, 0x6d, +0x01, 0x6b, 0x01, 0x68, 0x10, 0x7c, 0x10, 0x78, 0x10, 0x73, 0x10, 0x6f, +0x10, 0x6b, 0x10, 0x67, 0x10, 0x63, 0x10, 0x60, 0x10, 0x5c, 0x10, 0x59, +0x10, 0x57, 0x10, 0x54, 0x10, 0x51, 0x10, 0x4f, 0x11, 0x4d, 0x11, 0x4b, +0x11, 0x49, 0x11, 0x47, 0x11, 0x46, 0x11, 0x45, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, +0x11, 0x00, 0x18, 0x00, 0x1d, 0x00, 0x22, 0x00, 0x26, 0x00, 0x29, 0x00, +0x2b, 0x00, 0x2d, 0x00, 0x00, 0xba, 0x00, 0xb2, 0x00, 0x9c, 0x00, 0x7d, +0x00, 0x5c, 0x00, 0x3c, 0x00, 0x20, 0x04, 0x16, 0x08, 0x0e, 0x0c, 0x07, +0x0e, 0x02, 0x13, 0x00, 0x19, 0x00, 0x1d, 0x00, 0x21, 0x00, 0x25, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x3a, 0x00, +0x31, 0x00, 0x25, 0x00, 0x18, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x09, 0x00, +0x11, 0x00, 0x18, 0x00, 0x1d, 0x00, 0x22, 0x00, 0x26, 0x00, 0x29, 0x00, +0x2b, 0x00, 0x2d, 0x00, 0x00, 0xbb, 0x00, 0xb5, 0x00, 0xa3, 0x00, 0x8a, +0x00, 0x6f, 0x00, 0x56, 0x00, 0x3f, 0x00, 0x2c, 0x00, 0x1c, 0x00, 0x0f, +0x00, 0x04, 0x04, 0x00, 0x0c, 0x00, 0x12, 0x00, 0x17, 0x00, 0x1c, 0x00, +0x3d, 0x39, 0x3a, 0x36, 0x37, 0x34, 0x35, 0x33, 0x33, 0x30, 0x32, 0x30, +0x30, 0x2e, 0x2f, 0x2d, 0x2d, 0x2c, 0x2d, 0x2a, 0x2c, 0x2b, 0x2b, 0x2a, +0x2b, 0x28, 0x2a, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x26, 0x28, 0x27, +0x27, 0x27, 0x27, 0x27, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x00, 0xd8, 0x00, 0xcf, +0x00, 0xc6, 0x00, 0xbe, 0x00, 0xb6, 0x00, 0xaf, 0x00, 0xa8, 0x00, 0xa1, +0x00, 0x9c, 0x00, 0x96, 0x00, 0x90, 0x00, 0x8a, 0x00, 0x86, 0x00, 0x81, +0x00, 0x7d, 0x00, 0x79, 0x00, 0x75, 0x00, 0x72, 0x00, 0x6f, 0x00, 0x6b, +0x10, 0x7d, 0x10, 0x78, 0x10, 0x74, 0x10, 0x70, 0x10, 0x6c, 0x10, 0x68, +0x10, 0x65, 0x10, 0x61, 0x10, 0x5f, 0x10, 0x5c, 0x10, 0x59, 0x10, 0x56, +0x10, 0x54, 0x10, 0x51, 0x10, 0x4f, 0x11, 0x4d, 0x11, 0x4b, 0x11, 0x4a, +0x11, 0x48, 0x11, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0f, 0x00, +0x15, 0x00, 0x1a, 0x00, 0x1f, 0x00, 0x22, 0x00, 0x26, 0x00, 0x28, 0x00, +0x00, 0xbc, 0x00, 0xb5, 0x00, 0xa4, 0x00, 0x8b, 0x00, 0x6f, 0x00, 0x52, +0x00, 0x37, 0x00, 0x20, 0x04, 0x17, 0x07, 0x10, 0x0a, 0x0a, 0x0d, 0x05, +0x0f, 0x00, 0x14, 0x00, 0x19, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x3c, 0x00, 0x35, 0x00, 0x2b, 0x00, +0x1f, 0x00, 0x14, 0x00, 0x09, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0f, 0x00, +0x15, 0x00, 0x1a, 0x00, 0x1f, 0x00, 0x22, 0x00, 0x26, 0x00, 0x28, 0x00, +0x00, 0xbc, 0x00, 0xb7, 0x00, 0xaa, 0x00, 0x96, 0x00, 0x7f, 0x00, 0x68, +0x00, 0x53, 0x00, 0x3f, 0x00, 0x2e, 0x00, 0x20, 0x00, 0x14, 0x00, 0x0a, +0x00, 0x01, 0x06, 0x00, 0x0c, 0x00, 0x11, 0x00, 0x3d, 0x3a, 0x3a, 0x37, +0x38, 0x35, 0x36, 0x33, 0x33, 0x32, 0x33, 0x30, 0x30, 0x2f, 0x30, 0x2d, +0x2e, 0x2d, 0x2d, 0x2b, 0x2d, 0x2b, 0x2b, 0x2b, 0x2b, 0x2a, 0x2b, 0x28, +0x2a, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x27, 0x29, 0x27, 0x27, 0x27, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x00, 0xd8, 0x00, 0xd0, 0x00, 0xc8, 0x00, 0xc0, +0x00, 0xb9, 0x00, 0xb2, 0x00, 0xab, 0x00, 0xa5, 0x00, 0x9f, 0x00, 0x99, +0x00, 0x94, 0x00, 0x8f, 0x00, 0x8a, 0x00, 0x86, 0x00, 0x81, 0x00, 0x7d, +0x00, 0x79, 0x00, 0x76, 0x00, 0x73, 0x00, 0x70, 0x10, 0x7d, 0x10, 0x79, +0x10, 0x75, 0x10, 0x71, 0x10, 0x6d, 0x10, 0x6a, 0x10, 0x66, 0x10, 0x63, +0x10, 0x60, 0x10, 0x5d, 0x10, 0x5b, 0x10, 0x58, 0x10, 0x56, 0x10, 0x54, +0x10, 0x51, 0x10, 0x4f, 0x11, 0x4d, 0x11, 0x4c, 0x11, 0x4a, 0x11, 0x49, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x0d, 0x00, 0x13, 0x00, +0x18, 0x00, 0x1c, 0x00, 0x20, 0x00, 0x23, 0x00, 0x00, 0xbc, 0x00, 0xb8, +0x00, 0xaa, 0x00, 0x96, 0x00, 0x7e, 0x00, 0x64, 0x00, 0x4c, 0x00, 0x34, +0x00, 0x20, 0x03, 0x18, 0x06, 0x11, 0x09, 0x0c, 0x0c, 0x07, 0x0e, 0x03, +0x10, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x3e, 0x00, 0x3c, 0x00, 0x37, 0x00, 0x2f, 0x00, 0x25, 0x00, 0x1b, 0x00, +0x11, 0x00, 0x08, 0x00, 0x00, 0x00, 0x07, 0x00, 0x0d, 0x00, 0x13, 0x00, +0x18, 0x00, 0x1c, 0x00, 0x20, 0x00, 0x23, 0x00, 0x00, 0xbd, 0x00, 0xb9, +0x00, 0xae, 0x00, 0x9e, 0x00, 0x8b, 0x00, 0x77, 0x00, 0x63, 0x00, 0x50, +0x00, 0x3f, 0x00, 0x30, 0x00, 0x23, 0x00, 0x18, 0x00, 0x0e, 0x00, 0x06, +0x00, 0x00, 0x07, 0x00, 0x3d, 0x3a, 0x3a, 0x38, 0x38, 0x36, 0x36, 0x33, +0x34, 0x33, 0x33, 0x30, 0x31, 0x30, 0x30, 0x2e, 0x2f, 0x2d, 0x2d, 0x2d, +0x2d, 0x2b, 0x2d, 0x2b, 0x2b, 0x2b, 0x2b, 0x2a, 0x2b, 0x28, 0x2a, 0x28, +0x28, 0x28, 0x28, 0x28, 0x28, 0x27, 0x28, 0x27, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x00, 0xd9, 0x00, 0xd1, 0x00, 0xc9, 0x00, 0xc2, 0x00, 0xbb, 0x00, 0xb4, +0x00, 0xae, 0x00, 0xa8, 0x00, 0xa2, 0x00, 0x9c, 0x00, 0x97, 0x00, 0x92, +0x00, 0x8e, 0x00, 0x89, 0x00, 0x85, 0x00, 0x81, 0x00, 0x7d, 0x00, 0x7a, +0x00, 0x76, 0x00, 0x73, 0x10, 0x7d, 0x10, 0x79, 0x10, 0x75, 0x10, 0x72, +0x10, 0x6e, 0x10, 0x6b, 0x10, 0x68, 0x10, 0x65, 0x10, 0x62, 0x10, 0x5f, +0x10, 0x5c, 0x10, 0x5a, 0x10, 0x58, 0x10, 0x55, 0x10, 0x53, 0x10, 0x51, +0x10, 0x4f, 0x11, 0x4e, 0x11, 0x4c, 0x11, 0x4a, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x0c, 0x00, 0x11, 0x00, 0x16, 0x00, +0x1a, 0x00, 0x1d, 0x00, 0x00, 0xbd, 0x00, 0xb9, 0x00, 0xae, 0x00, 0x9d, +0x00, 0x89, 0x00, 0x73, 0x00, 0x5c, 0x00, 0x46, 0x00, 0x32, 0x00, 0x20, +0x03, 0x19, 0x06, 0x13, 0x08, 0x0e, 0x0b, 0x09, 0x0d, 0x05, 0x0e, 0x01, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x3d, 0x00, +0x39, 0x00, 0x32, 0x00, 0x2a, 0x00, 0x21, 0x00, 0x18, 0x00, 0x0f, 0x00, +0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x0c, 0x00, 0x11, 0x00, 0x16, 0x00, +0x1a, 0x00, 0x1d, 0x00, 0x00, 0xbd, 0x00, 0xba, 0x00, 0xb1, 0x00, 0xa4, +0x00, 0x94, 0x00, 0x82, 0x00, 0x70, 0x00, 0x5e, 0x00, 0x4e, 0x00, 0x3f, +0x00, 0x32, 0x00, 0x26, 0x00, 0x1c, 0x00, 0x13, 0x00, 0x0b, 0x00, 0x03, +0x3d, 0x3a, 0x3b, 0x38, 0x39, 0x36, 0x36, 0x34, 0x35, 0x33, 0x33, 0x31, +0x32, 0x30, 0x30, 0x2f, 0x30, 0x2d, 0x2e, 0x2d, 0x2d, 0x2c, 0x2d, 0x2a, +0x2c, 0x2b, 0x2b, 0x2b, 0x2b, 0x2a, 0x2b, 0x28, 0x2a, 0x28, 0x28, 0x28, +0x28, 0x28, 0x28, 0x28, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x00, 0xd9, 0x00, 0xd1, +0x00, 0xca, 0x00, 0xc3, 0x00, 0xbc, 0x00, 0xb6, 0x00, 0xb0, 0x00, 0xaa, +0x00, 0xa5, 0x00, 0xa0, 0x00, 0x9a, 0x00, 0x96, 0x00, 0x91, 0x00, 0x8d, +0x00, 0x89, 0x00, 0x84, 0x00, 0x81, 0x00, 0x7d, 0x00, 0x7a, 0x00, 0x77, +0x10, 0x7d, 0x10, 0x79, 0x10, 0x76, 0x10, 0x72, 0x10, 0x6f, 0x10, 0x6c, +0x10, 0x69, 0x10, 0x66, 0x10, 0x63, 0x10, 0x61, 0x10, 0x5e, 0x10, 0x5c, +0x10, 0x59, 0x10, 0x57, 0x10, 0x55, 0x10, 0x53, 0x10, 0x51, 0x10, 0x4f, +0x11, 0x4e, 0x11, 0x4c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x06, 0x00, 0x0b, 0x00, 0x10, 0x00, 0x14, 0x00, 0x18, 0x00, +0x00, 0xbd, 0x00, 0xba, 0x00, 0xb1, 0x00, 0xa3, 0x00, 0x92, 0x00, 0x7e, +0x00, 0x6a, 0x00, 0x56, 0x00, 0x42, 0x00, 0x30, 0x00, 0x1f, 0x03, 0x19, +0x05, 0x14, 0x08, 0x0f, 0x0a, 0x0b, 0x0c, 0x07, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x3d, 0x00, 0x3a, 0x00, 0x34, 0x00, +0x2d, 0x00, 0x25, 0x00, 0x1d, 0x00, 0x15, 0x00, 0x0d, 0x00, 0x06, 0x00, +0x00, 0x00, 0x06, 0x00, 0x0b, 0x00, 0x10, 0x00, 0x14, 0x00, 0x18, 0x00, +0x00, 0xbd, 0x00, 0xbb, 0x00, 0xb4, 0x00, 0xa9, 0x00, 0x9b, 0x00, 0x8b, +0x00, 0x7b, 0x00, 0x6b, 0x00, 0x5b, 0x00, 0x4d, 0x00, 0x3f, 0x00, 0x33, +0x00, 0x28, 0x00, 0x1f, 0x00, 0x16, 0x00, 0x0e, 0x3d, 0x3b, 0x3b, 0x39, +0x3a, 0x36, 0x36, 0x35, 0x36, 0x33, 0x33, 0x32, 0x33, 0x30, 0x30, 0x30, +0x30, 0x2e, 0x2f, 0x2d, 0x2d, 0x2d, 0x2d, 0x2c, 0x2d, 0x2b, 0x2b, 0x2b, +0x2b, 0x2b, 0x2b, 0x2a, 0x2b, 0x28, 0x2a, 0x28, 0x28, 0x28, 0x28, 0x28, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x00, 0xd9, 0x00, 0xd2, 0x00, 0xcb, 0x00, 0xc4, +0x00, 0xbe, 0x00, 0xb8, 0x00, 0xb2, 0x00, 0xad, 0x00, 0xa8, 0x00, 0xa2, +0x00, 0x9d, 0x00, 0x99, 0x00, 0x94, 0x00, 0x90, 0x00, 0x8b, 0x00, 0x88, +0x00, 0x84, 0x00, 0x81, 0x00, 0x7d, 0x00, 0x7b, 0x10, 0x7d, 0x10, 0x7a, +0x10, 0x76, 0x10, 0x73, 0x10, 0x70, 0x10, 0x6d, 0x10, 0x6a, 0x10, 0x67, +0x10, 0x65, 0x10, 0x62, 0x10, 0x5f, 0x10, 0x5d, 0x10, 0x5b, 0x10, 0x59, +0x10, 0x56, 0x10, 0x55, 0x10, 0x53, 0x10, 0x51, 0x10, 0x4f, 0x11, 0x4e, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x05, 0x00, 0x0a, 0x00, 0x0f, 0x00, 0x13, 0x00, 0x00, 0xbd, 0x00, 0xbb, +0x00, 0xb3, 0x00, 0xa8, 0x00, 0x99, 0x00, 0x87, 0x00, 0x75, 0x00, 0x62, +0x00, 0x50, 0x00, 0x3f, 0x00, 0x2e, 0x00, 0x1f, 0x02, 0x1a, 0x05, 0x15, +0x07, 0x10, 0x09, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x3f, 0x00, 0x3e, 0x00, 0x3b, 0x00, 0x36, 0x00, 0x30, 0x00, 0x29, 0x00, +0x22, 0x00, 0x1a, 0x00, 0x13, 0x00, 0x0c, 0x00, 0x06, 0x00, 0x00, 0x00, +0x05, 0x00, 0x0a, 0x00, 0x0f, 0x00, 0x13, 0x00, 0x00, 0xbe, 0x00, 0xbc, +0x00, 0xb6, 0x00, 0xac, 0x00, 0xa0, 0x00, 0x93, 0x00, 0x84, 0x00, 0x75, +0x00, 0x66, 0x00, 0x58, 0x00, 0x4b, 0x00, 0x3f, 0x00, 0x34, 0x00, 0x2a, +0x00, 0x21, 0x00, 0x19, 0x3d, 0x3b, 0x3b, 0x39, 0x39, 0x36, 0x37, 0x35, +0x36, 0x33, 0x33, 0x33, 0x33, 0x30, 0x31, 0x30, 0x30, 0x2f, 0x30, 0x2d, +0x2e, 0x2d, 0x2d, 0x2d, 0x2d, 0x2b, 0x2d, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, +0x2b, 0x29, 0x2b, 0x28, 0x29, 0x28, 0x28, 0x28, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x22, +0x00, 0xd9, 0x00, 0xd3, 0x00, 0xcc, 0x00, 0xc6, 0x00, 0xc0, 0x00, 0xba, +0x00, 0xb4, 0x00, 0xaf, 0x00, 0xaa, 0x00, 0xa5, 0x00, 0xa0, 0x00, 0x9b, +0x00, 0x97, 0x00, 0x93, 0x00, 0x8f, 0x00, 0x8b, 0x00, 0x88, 0x00, 0x83, +0x00, 0x81, 0x00, 0x7d, 0x10, 0x7d, 0x10, 0x7a, 0x10, 0x77, 0x10, 0x74, +0x10, 0x71, 0x10, 0x6e, 0x10, 0x6b, 0x10, 0x68, 0x10, 0x65, 0x10, 0x63, +0x10, 0x61, 0x10, 0x5e, 0x10, 0x5c, 0x10, 0x5a, 0x10, 0x58, 0x10, 0x56, +0x10, 0x55, 0x10, 0x52, 0x10, 0x51, 0x10, 0x4f, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, +0x09, 0x00, 0x0d, 0x00, 0x00, 0xbe, 0x00, 0xbb, 0x00, 0xb5, 0x00, 0xab, +0x00, 0x9e, 0x00, 0x8f, 0x00, 0x7e, 0x00, 0x6d, 0x00, 0x5c, 0x00, 0x4c, +0x00, 0x3c, 0x00, 0x2d, 0x00, 0x1f, 0x02, 0x1a, 0x04, 0x16, 0x06, 0x11, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x3e, 0x00, +0x3b, 0x00, 0x37, 0x00, 0x32, 0x00, 0x2c, 0x00, 0x26, 0x00, 0x1f, 0x00, +0x18, 0x00, 0x11, 0x00, 0x0b, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, +0x09, 0x00, 0x0d, 0x00, 0x00, 0xbe, 0x00, 0xbc, 0x00, 0xb7, 0x00, 0xaf, +0x00, 0xa5, 0x00, 0x99, 0x00, 0x8b, 0x00, 0x7e, 0x00, 0x70, 0x00, 0x63, +0x00, 0x56, 0x00, 0x4a, 0x00, 0x3f, 0x00, 0x35, 0x00, 0x2c, 0x00, 0x23, +0x27, 0x76, 0x1a, 0x79, 0x16, 0x7b, 0x15, 0x7c, 0x14, 0x7c, 0x13, 0x7d, +0x13, 0x7d, 0x13, 0x7d, 0x12, 0x7d, 0x12, 0x7d, 0x12, 0x7e, 0x12, 0x7e, +0x12, 0x7e, 0x12, 0x7e, 0x12, 0x7e, 0x11, 0x7e, 0x11, 0x7e, 0x11, 0x7e, +0x11, 0x7f, 0x11, 0x7f, 0x13, 0x5f, 0x10, 0x6f, 0x10, 0x74, 0x10, 0x77, +0x10, 0x78, 0x10, 0x7a, 0x10, 0x7a, 0x10, 0x7b, 0x10, 0x7b, 0x10, 0x7c, +0x10, 0x7c, 0x10, 0x7c, 0x10, 0x7c, 0x10, 0x7d, 0x10, 0x7d, 0x10, 0x7d, +0x10, 0x7d, 0x10, 0x7d, 0x10, 0x7d, 0x10, 0x7d, 0x00, 0x90, 0x02, 0x81, +0x06, 0x80, 0x09, 0x7f, 0x0a, 0x7f, 0x0b, 0x7f, 0x0c, 0x7f, 0x0d, 0x7f, +0x0d, 0x7f, 0x0d, 0x7f, 0x0e, 0x7f, 0x0e, 0x7f, 0x0e, 0x7f, 0x0e, 0x7f, +0x0e, 0x7f, 0x0f, 0x7f, 0x0f, 0x7f, 0x0f, 0x7f, 0x0f, 0x7f, 0x0f, 0x7f, +0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, +0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, +0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, +0x10, 0x7f, 0x10, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x09, 0x00, +0x00, 0xbe, 0x00, 0xbc, 0x00, 0xb7, 0x00, 0xae, 0x00, 0xa2, 0x00, 0x95, +0x00, 0x86, 0x00, 0x77, 0x00, 0x67, 0x00, 0x57, 0x00, 0x48, 0x00, 0x3a, +0x00, 0x2c, 0x00, 0x1f, 0x02, 0x1b, 0x04, 0x16, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x3e, 0x00, 0x3c, 0x00, 0x38, 0x00, +0x34, 0x00, 0x2f, 0x00, 0x29, 0x00, 0x22, 0x00, 0x1c, 0x00, 0x16, 0x00, +0x10, 0x00, 0x0a, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x09, 0x00, +0x00, 0xbe, 0x00, 0xbd, 0x00, 0xb8, 0x00, 0xb1, 0x00, 0xa8, 0x00, 0x9d, +0x00, 0x92, 0x00, 0x85, 0x00, 0x78, 0x00, 0x6c, 0x00, 0x60, 0x00, 0x54, +0x00, 0x49, 0x00, 0x3f, 0x00, 0x36, 0x00, 0x2d, 0x32, 0x5f, 0x25, 0x68, +0x1f, 0x6d, 0x1c, 0x71, 0x19, 0x72, 0x18, 0x74, 0x17, 0x76, 0x16, 0x77, +0x16, 0x77, 0x15, 0x78, 0x15, 0x79, 0x15, 0x79, 0x14, 0x7a, 0x14, 0x7a, +0x13, 0x7a, 0x13, 0x7b, 0x13, 0x7b, 0x13, 0x7b, 0x13, 0x7b, 0x13, 0x7b, +0x17, 0x46, 0x11, 0x58, 0x10, 0x63, 0x10, 0x69, 0x10, 0x6d, 0x10, 0x70, +0x10, 0x72, 0x10, 0x73, 0x10, 0x75, 0x10, 0x76, 0x10, 0x77, 0x10, 0x77, +0x10, 0x78, 0x10, 0x78, 0x10, 0x79, 0x10, 0x79, 0x10, 0x79, 0x10, 0x7a, +0x10, 0x7a, 0x10, 0x7a, 0x00, 0xbd, 0x00, 0xa4, 0x00, 0x97, 0x02, 0x91, +0x04, 0x8d, 0x05, 0x8a, 0x06, 0x89, 0x07, 0x88, 0x08, 0x86, 0x09, 0x86, +0x09, 0x85, 0x0a, 0x85, 0x0a, 0x84, 0x0b, 0x84, 0x0b, 0x83, 0x0b, 0x83, +0x0c, 0x83, 0x0c, 0x83, 0x0c, 0x82, 0x0c, 0x82, 0x10, 0x7f, 0x10, 0x7f, +0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, +0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, +0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0xbe, 0x00, 0xbc, +0x00, 0xb8, 0x00, 0xb0, 0x00, 0xa6, 0x00, 0x9a, 0x00, 0x8d, 0x00, 0x7f, +0x00, 0x70, 0x00, 0x61, 0x00, 0x53, 0x00, 0x45, 0x00, 0x38, 0x00, 0x2b, +0x00, 0x1f, 0x02, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x3f, 0x00, 0x3e, 0x00, 0x3c, 0x00, 0x39, 0x00, 0x35, 0x00, 0x31, 0x00, +0x2b, 0x00, 0x26, 0x00, 0x20, 0x00, 0x1a, 0x00, 0x14, 0x00, 0x0f, 0x00, +0x09, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0xbe, 0x00, 0xbd, +0x00, 0xb9, 0x00, 0xb3, 0x00, 0xab, 0x00, 0xa1, 0x00, 0x97, 0x00, 0x8b, +0x00, 0x80, 0x00, 0x74, 0x00, 0x68, 0x00, 0x5d, 0x00, 0x53, 0x00, 0x49, +0x00, 0x3f, 0x00, 0x36, 0x36, 0x56, 0x2a, 0x5f, 0x24, 0x65, 0x20, 0x68, +0x1e, 0x6c, 0x1c, 0x6e, 0x1b, 0x70, 0x19, 0x71, 0x18, 0x72, 0x18, 0x73, +0x18, 0x75, 0x17, 0x75, 0x16, 0x76, 0x15, 0x76, 0x15, 0x76, 0x15, 0x77, +0x15, 0x77, 0x15, 0x77, 0x15, 0x78, 0x15, 0x79, 0x1a, 0x39, 0x13, 0x4a, +0x11, 0x55, 0x10, 0x5e, 0x10, 0x63, 0x10, 0x67, 0x10, 0x6a, 0x10, 0x6c, +0x10, 0x6e, 0x10, 0x70, 0x10, 0x71, 0x10, 0x72, 0x10, 0x73, 0x10, 0x74, +0x10, 0x75, 0x10, 0x75, 0x10, 0x76, 0x10, 0x76, 0x10, 0x77, 0x10, 0x77, +0x00, 0xcc, 0x00, 0xb5, 0x00, 0xa8, 0x00, 0x9e, 0x01, 0x99, 0x02, 0x94, +0x03, 0x92, 0x04, 0x8f, 0x05, 0x8d, 0x06, 0x8c, 0x06, 0x8b, 0x07, 0x8a, +0x07, 0x89, 0x08, 0x88, 0x08, 0x88, 0x09, 0x87, 0x09, 0x87, 0x09, 0x86, +0x0a, 0x86, 0x0a, 0x86, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, +0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, +0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, +0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x00, 0xbd, 0x00, 0xb9, 0x00, 0xb2, +0x00, 0xa9, 0x00, 0x9e, 0x00, 0x92, 0x00, 0x85, 0x00, 0x78, 0x00, 0x6a, +0x00, 0x5c, 0x00, 0x4f, 0x00, 0x42, 0x00, 0x36, 0x00, 0x2a, 0x00, 0x1f, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x3e, 0x00, +0x3d, 0x00, 0x3a, 0x00, 0x37, 0x00, 0x32, 0x00, 0x2d, 0x00, 0x28, 0x00, +0x23, 0x00, 0x1d, 0x00, 0x18, 0x00, 0x13, 0x00, 0x0d, 0x00, 0x09, 0x00, +0x04, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x00, 0xbd, 0x00, 0xba, 0x00, 0xb4, +0x00, 0xad, 0x00, 0xa5, 0x00, 0x9b, 0x00, 0x91, 0x00, 0x86, 0x00, 0x7b, +0x00, 0x70, 0x00, 0x65, 0x00, 0x5b, 0x00, 0x51, 0x00, 0x48, 0x00, 0x3f, +0x38, 0x52, 0x2e, 0x59, 0x28, 0x5f, 0x24, 0x63, 0x22, 0x67, 0x1f, 0x69, +0x1e, 0x6b, 0x1c, 0x6d, 0x1b, 0x6e, 0x1a, 0x70, 0x1a, 0x71, 0x19, 0x72, +0x18, 0x72, 0x18, 0x72, 0x18, 0x73, 0x17, 0x75, 0x17, 0x76, 0x16, 0x76, +0x15, 0x76, 0x15, 0x76, 0x1b, 0x33, 0x15, 0x41, 0x12, 0x4c, 0x11, 0x54, +0x10, 0x5b, 0x10, 0x5f, 0x10, 0x63, 0x10, 0x66, 0x10, 0x68, 0x10, 0x6a, +0x10, 0x6c, 0x10, 0x6e, 0x10, 0x6f, 0x10, 0x70, 0x10, 0x71, 0x10, 0x72, +0x10, 0x72, 0x10, 0x73, 0x10, 0x74, 0x10, 0x74, 0x00, 0xd1, 0x00, 0xc0, +0x00, 0xb3, 0x00, 0xaa, 0x00, 0xa2, 0x00, 0x9d, 0x01, 0x99, 0x02, 0x96, +0x02, 0x94, 0x03, 0x92, 0x04, 0x90, 0x05, 0x8f, 0x05, 0x8d, 0x06, 0x8d, +0x06, 0x8c, 0x07, 0x8b, 0x07, 0x8a, 0x07, 0x8a, 0x07, 0x89, 0x08, 0x89, +0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, +0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, +0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, +0x10, 0x7f, 0x10, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x07, 0x47, 0x0f, 0x0f, 0x26, 0x00, 0x33, 0x00, 0x38, 0x00, 0x3a, 0x00, +0x3c, 0x00, 0x3d, 0x00, 0x3d, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3e, 0x00, +0x3e, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x07, 0x47, 0x00, 0x7f, 0x00, 0xa5, 0x00, 0xb2, +0x00, 0xb7, 0x00, 0xba, 0x00, 0xbb, 0x00, 0xbc, 0x00, 0xbd, 0x00, 0xbd, +0x00, 0xbd, 0x00, 0xbe, 0x00, 0xbe, 0x00, 0xbe, 0x00, 0xbe, 0x00, 0xbe, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x39, 0x4f, 0x31, 0x55, +0x2b, 0x5b, 0x27, 0x5f, 0x24, 0x63, 0x22, 0x65, 0x20, 0x68, 0x1f, 0x69, +0x1d, 0x6b, 0x1d, 0x6d, 0x1b, 0x6d, 0x1a, 0x6e, 0x1a, 0x6f, 0x1a, 0x71, +0x19, 0x72, 0x18, 0x72, 0x18, 0x72, 0x18, 0x72, 0x18, 0x73, 0x18, 0x74, +0x1c, 0x2f, 0x16, 0x3b, 0x13, 0x44, 0x11, 0x4d, 0x11, 0x53, 0x10, 0x59, +0x10, 0x5d, 0x10, 0x60, 0x10, 0x63, 0x10, 0x65, 0x10, 0x67, 0x10, 0x69, +0x10, 0x6b, 0x10, 0x6c, 0x10, 0x6d, 0x10, 0x6e, 0x10, 0x6f, 0x10, 0x70, +0x10, 0x71, 0x10, 0x71, 0x00, 0xd5, 0x00, 0xc6, 0x00, 0xbb, 0x00, 0xb2, +0x00, 0xaa, 0x00, 0xa4, 0x00, 0xa0, 0x01, 0x9c, 0x01, 0x9a, 0x02, 0x97, +0x02, 0x95, 0x03, 0x93, 0x03, 0x92, 0x04, 0x91, 0x05, 0x90, 0x05, 0x8e, +0x06, 0x8e, 0x06, 0x8d, 0x06, 0x8c, 0x06, 0x8c, 0x10, 0x7f, 0x10, 0x7f, +0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, +0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, +0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x3f, +0x05, 0x05, 0x1c, 0x00, 0x2a, 0x00, 0x31, 0x00, 0x35, 0x00, 0x38, 0x00, +0x39, 0x00, 0x3b, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3d, 0x00, 0x3d, 0x00, +0x3d, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x0f, 0x0f, 0x00, 0x3f, 0x00, 0x7f, 0x00, 0x9c, 0x00, 0xaa, 0x00, 0xb1, +0x00, 0xb5, 0x00, 0xb7, 0x00, 0xb9, 0x00, 0xba, 0x00, 0xbb, 0x00, 0xbc, +0x00, 0xbc, 0x00, 0xbd, 0x00, 0xbd, 0x00, 0xbd, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x3a, 0x4c, 0x33, 0x53, 0x2e, 0x58, 0x29, 0x5c, +0x27, 0x5f, 0x24, 0x62, 0x22, 0x64, 0x20, 0x66, 0x20, 0x68, 0x1e, 0x69, +0x1d, 0x6a, 0x1d, 0x6c, 0x1c, 0x6d, 0x1a, 0x6d, 0x1a, 0x6e, 0x1a, 0x6f, +0x1a, 0x71, 0x19, 0x72, 0x18, 0x72, 0x18, 0x72, 0x1d, 0x2d, 0x17, 0x37, +0x14, 0x40, 0x12, 0x47, 0x11, 0x4e, 0x11, 0x53, 0x10, 0x57, 0x10, 0x5b, +0x10, 0x5e, 0x10, 0x61, 0x10, 0x63, 0x10, 0x65, 0x10, 0x67, 0x10, 0x68, +0x10, 0x6a, 0x10, 0x6b, 0x10, 0x6c, 0x10, 0x6d, 0x10, 0x6e, 0x10, 0x6f, +0x00, 0xd6, 0x00, 0xcb, 0x00, 0xc0, 0x00, 0xb8, 0x00, 0xb1, 0x00, 0xab, +0x00, 0xa6, 0x00, 0xa2, 0x00, 0x9f, 0x01, 0x9c, 0x02, 0x9a, 0x02, 0x98, +0x02, 0x96, 0x03, 0x94, 0x03, 0x93, 0x03, 0x92, 0x04, 0x91, 0x05, 0x90, +0x05, 0x8f, 0x05, 0x8f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, +0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, +0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, +0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0xa5, 0x00, 0x7f, 0x00, 0x3f, 0x00, 0x12, +0x09, 0x00, 0x19, 0x00, 0x23, 0x00, 0x2a, 0x00, 0x2f, 0x00, 0x32, 0x00, +0x34, 0x00, 0x36, 0x00, 0x38, 0x00, 0x39, 0x00, 0x3a, 0x00, 0x3a, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x26, 0x00, 0x05, 0x05, +0x00, 0x3f, 0x00, 0x6d, 0x00, 0x88, 0x00, 0x99, 0x00, 0xa3, 0x00, 0xaa, +0x00, 0xae, 0x00, 0xb1, 0x00, 0xb4, 0x00, 0xb6, 0x00, 0xb7, 0x00, 0xb8, +0x00, 0xb9, 0x00, 0xba, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x3b, 0x4b, 0x34, 0x51, 0x2f, 0x55, 0x2c, 0x59, 0x29, 0x5c, 0x26, 0x60, +0x24, 0x61, 0x23, 0x64, 0x21, 0x65, 0x20, 0x67, 0x1f, 0x69, 0x1d, 0x69, +0x1d, 0x6a, 0x1d, 0x6c, 0x1c, 0x6d, 0x1b, 0x6d, 0x1a, 0x6d, 0x1a, 0x6d, +0x1a, 0x6f, 0x1a, 0x71, 0x1e, 0x2b, 0x18, 0x34, 0x15, 0x3b, 0x13, 0x43, +0x12, 0x49, 0x11, 0x4e, 0x11, 0x52, 0x10, 0x56, 0x10, 0x5a, 0x10, 0x5d, +0x10, 0x5f, 0x10, 0x61, 0x10, 0x63, 0x10, 0x65, 0x10, 0x66, 0x10, 0x68, +0x10, 0x69, 0x10, 0x6a, 0x10, 0x6b, 0x10, 0x6c, 0x00, 0xd7, 0x00, 0xcd, +0x00, 0xc5, 0x00, 0xbd, 0x00, 0xb6, 0x00, 0xb0, 0x00, 0xab, 0x00, 0xa7, +0x00, 0xa4, 0x00, 0xa1, 0x01, 0x9e, 0x01, 0x9c, 0x02, 0x9a, 0x02, 0x98, +0x02, 0x97, 0x02, 0x96, 0x03, 0x94, 0x03, 0x93, 0x03, 0x92, 0x04, 0x91, +0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, +0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, +0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, +0x10, 0x7f, 0x10, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0xb2, 0x00, 0x9c, 0x00, 0x6d, 0x00, 0x3f, 0x00, 0x1d, 0x00, 0x05, +0x0b, 0x00, 0x16, 0x00, 0x1f, 0x00, 0x25, 0x00, 0x29, 0x00, 0x2d, 0x00, +0x30, 0x00, 0x32, 0x00, 0x33, 0x00, 0x35, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x33, 0x00, 0x1c, 0x00, 0x00, 0x12, 0x00, 0x3f, +0x00, 0x62, 0x00, 0x7a, 0x00, 0x8a, 0x00, 0x96, 0x00, 0x9e, 0x00, 0xa4, +0x00, 0xa9, 0x00, 0xac, 0x00, 0xaf, 0x00, 0xb1, 0x00, 0xb3, 0x00, 0xb4, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x49, 0x36, 0x4f, +0x31, 0x54, 0x2d, 0x57, 0x2a, 0x5a, 0x28, 0x5c, 0x26, 0x60, 0x24, 0x61, +0x23, 0x64, 0x21, 0x65, 0x20, 0x65, 0x20, 0x68, 0x1e, 0x69, 0x1d, 0x69, +0x1d, 0x69, 0x1d, 0x6b, 0x1c, 0x6d, 0x1b, 0x6d, 0x1a, 0x6d, 0x1a, 0x6d, +0x1e, 0x2a, 0x19, 0x32, 0x16, 0x39, 0x13, 0x3f, 0x12, 0x45, 0x11, 0x4a, +0x11, 0x4e, 0x11, 0x52, 0x10, 0x56, 0x10, 0x59, 0x10, 0x5c, 0x10, 0x5d, +0x10, 0x60, 0x10, 0x61, 0x10, 0x63, 0x10, 0x65, 0x10, 0x66, 0x10, 0x67, +0x10, 0x68, 0x10, 0x69, 0x00, 0xd8, 0x00, 0xcf, 0x00, 0xc7, 0x00, 0xc0, +0x00, 0xba, 0x00, 0xb5, 0x00, 0xb0, 0x00, 0xac, 0x00, 0xa8, 0x00, 0xa5, +0x00, 0xa2, 0x00, 0xa0, 0x01, 0x9e, 0x01, 0x9c, 0x02, 0x9a, 0x02, 0x99, +0x02, 0x97, 0x02, 0x96, 0x03, 0x95, 0x03, 0x94, 0x10, 0x7f, 0x10, 0x7f, +0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, +0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, +0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb7, 0x00, 0xaa, +0x00, 0x88, 0x00, 0x62, 0x00, 0x3f, 0x00, 0x24, 0x00, 0x0f, 0x00, 0x00, +0x0b, 0x00, 0x14, 0x00, 0x1b, 0x00, 0x21, 0x00, 0x25, 0x00, 0x29, 0x00, +0x2b, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x38, 0x00, 0x2a, 0x00, 0x09, 0x00, 0x00, 0x1d, 0x00, 0x3f, 0x00, 0x5b, +0x00, 0x6f, 0x00, 0x7f, 0x00, 0x8b, 0x00, 0x94, 0x00, 0x9b, 0x00, 0xa0, +0x00, 0xa5, 0x00, 0xa8, 0x00, 0xab, 0x00, 0xad, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x3c, 0x48, 0x37, 0x4d, 0x32, 0x51, 0x2f, 0x55, +0x2c, 0x58, 0x29, 0x5b, 0x27, 0x5d, 0x26, 0x60, 0x24, 0x60, 0x23, 0x63, +0x22, 0x65, 0x20, 0x65, 0x20, 0x66, 0x1f, 0x68, 0x1e, 0x69, 0x1d, 0x69, +0x1d, 0x69, 0x1d, 0x6b, 0x1c, 0x6d, 0x1b, 0x6d, 0x1e, 0x29, 0x1a, 0x30, +0x17, 0x36, 0x14, 0x3c, 0x13, 0x41, 0x12, 0x46, 0x11, 0x4a, 0x11, 0x4f, +0x11, 0x52, 0x10, 0x55, 0x10, 0x58, 0x10, 0x5a, 0x10, 0x5c, 0x10, 0x5f, +0x10, 0x60, 0x10, 0x62, 0x10, 0x63, 0x10, 0x65, 0x10, 0x65, 0x10, 0x67, +0x00, 0xd9, 0x00, 0xd1, 0x00, 0xca, 0x00, 0xc3, 0x00, 0xbe, 0x00, 0xb9, +0x00, 0xb4, 0x00, 0xb0, 0x00, 0xac, 0x00, 0xa9, 0x00, 0xa6, 0x00, 0xa3, +0x00, 0xa1, 0x01, 0x9f, 0x01, 0x9d, 0x01, 0x9b, 0x02, 0x9a, 0x02, 0x99, +0x02, 0x98, 0x02, 0x97, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, +0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, +0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, +0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0xba, 0x00, 0xb1, 0x00, 0x99, 0x00, 0x7a, +0x00, 0x5b, 0x00, 0x3f, 0x00, 0x29, 0x00, 0x16, 0x00, 0x08, 0x02, 0x00, +0x0c, 0x00, 0x13, 0x00, 0x19, 0x00, 0x1e, 0x00, 0x22, 0x00, 0x25, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x31, 0x00, +0x19, 0x00, 0x00, 0x05, 0x00, 0x24, 0x00, 0x3f, 0x00, 0x56, 0x00, 0x68, +0x00, 0x77, 0x00, 0x82, 0x00, 0x8b, 0x00, 0x93, 0x00, 0x99, 0x00, 0x9d, +0x00, 0xa1, 0x00, 0xa5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x3c, 0x48, 0x37, 0x4c, 0x33, 0x50, 0x30, 0x54, 0x2d, 0x57, 0x2a, 0x59, +0x29, 0x5c, 0x27, 0x5d, 0x26, 0x60, 0x24, 0x60, 0x23, 0x62, 0x22, 0x65, +0x20, 0x65, 0x20, 0x65, 0x20, 0x67, 0x1f, 0x69, 0x1d, 0x69, 0x1d, 0x69, +0x1d, 0x69, 0x1d, 0x6a, 0x1f, 0x28, 0x1a, 0x2e, 0x17, 0x34, 0x15, 0x39, +0x13, 0x3f, 0x13, 0x43, 0x12, 0x48, 0x11, 0x4b, 0x11, 0x4f, 0x11, 0x52, +0x10, 0x55, 0x10, 0x57, 0x10, 0x59, 0x10, 0x5c, 0x10, 0x5d, 0x10, 0x5f, +0x10, 0x61, 0x10, 0x62, 0x10, 0x63, 0x10, 0x64, 0x00, 0xd9, 0x00, 0xd2, +0x00, 0xcc, 0x00, 0xc6, 0x00, 0xc1, 0x00, 0xbc, 0x00, 0xb7, 0x00, 0xb3, +0x00, 0xaf, 0x00, 0xac, 0x00, 0xa9, 0x00, 0xa6, 0x00, 0xa4, 0x00, 0xa2, +0x00, 0xa0, 0x01, 0x9e, 0x01, 0x9d, 0x02, 0x9c, 0x02, 0x9a, 0x02, 0x99, +0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, +0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, +0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, +0x10, 0x7f, 0x10, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0xbb, 0x00, 0xb5, 0x00, 0xa3, 0x00, 0x8a, 0x00, 0x6f, 0x00, 0x56, +0x00, 0x3f, 0x00, 0x2c, 0x00, 0x1c, 0x00, 0x0f, 0x00, 0x04, 0x04, 0x00, +0x0c, 0x00, 0x12, 0x00, 0x17, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x35, 0x00, 0x23, 0x00, 0x0b, 0x00, +0x00, 0x0f, 0x00, 0x29, 0x00, 0x3f, 0x00, 0x53, 0x00, 0x63, 0x00, 0x70, +0x00, 0x7b, 0x00, 0x84, 0x00, 0x8b, 0x00, 0x92, 0x00, 0x97, 0x00, 0x9b, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x47, 0x38, 0x4b, +0x34, 0x4f, 0x31, 0x53, 0x2e, 0x55, 0x2c, 0x57, 0x2a, 0x5a, 0x28, 0x5c, +0x27, 0x5d, 0x26, 0x60, 0x23, 0x60, 0x23, 0x61, 0x23, 0x64, 0x21, 0x65, +0x20, 0x65, 0x20, 0x65, 0x20, 0x68, 0x1e, 0x69, 0x1d, 0x69, 0x1d, 0x69, +0x1f, 0x27, 0x1b, 0x2d, 0x18, 0x33, 0x16, 0x38, 0x14, 0x3c, 0x13, 0x41, +0x12, 0x44, 0x11, 0x48, 0x11, 0x4c, 0x11, 0x4f, 0x11, 0x51, 0x10, 0x54, +0x10, 0x57, 0x10, 0x59, 0x10, 0x5b, 0x10, 0x5c, 0x10, 0x5e, 0x10, 0x5f, +0x10, 0x61, 0x10, 0x62, 0x00, 0xd9, 0x00, 0xd3, 0x00, 0xcd, 0x00, 0xc8, +0x00, 0xc3, 0x00, 0xbe, 0x00, 0xba, 0x00, 0xb6, 0x00, 0xb2, 0x00, 0xaf, +0x00, 0xad, 0x00, 0xaa, 0x00, 0xa7, 0x00, 0xa5, 0x00, 0xa3, 0x00, 0xa1, +0x01, 0xa0, 0x01, 0x9e, 0x01, 0x9d, 0x02, 0x9c, 0x10, 0x7f, 0x10, 0x7f, +0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, +0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, +0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbc, 0x00, 0xb7, +0x00, 0xaa, 0x00, 0x96, 0x00, 0x7f, 0x00, 0x68, 0x00, 0x53, 0x00, 0x3f, +0x00, 0x2e, 0x00, 0x20, 0x00, 0x14, 0x00, 0x0a, 0x00, 0x01, 0x06, 0x00, +0x0c, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x3d, 0x00, 0x38, 0x00, 0x2a, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x16, +0x00, 0x2c, 0x00, 0x3f, 0x00, 0x50, 0x00, 0x5e, 0x00, 0x6b, 0x00, 0x75, +0x00, 0x7e, 0x00, 0x85, 0x00, 0x8b, 0x00, 0x91, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x3d, 0x47, 0x38, 0x4b, 0x35, 0x4e, 0x32, 0x51, +0x2f, 0x53, 0x2d, 0x57, 0x2b, 0x58, 0x2a, 0x5b, 0x27, 0x5c, 0x27, 0x5d, +0x25, 0x60, 0x23, 0x60, 0x23, 0x61, 0x23, 0x64, 0x21, 0x65, 0x20, 0x65, +0x20, 0x65, 0x20, 0x66, 0x1f, 0x69, 0x1e, 0x69, 0x1f, 0x27, 0x1b, 0x2c, +0x18, 0x31, 0x16, 0x36, 0x14, 0x3a, 0x13, 0x3e, 0x13, 0x42, 0x12, 0x45, +0x11, 0x49, 0x11, 0x4c, 0x11, 0x4f, 0x11, 0x51, 0x10, 0x54, 0x10, 0x56, +0x10, 0x58, 0x10, 0x5a, 0x10, 0x5c, 0x10, 0x5d, 0x10, 0x5e, 0x10, 0x60, +0x00, 0xd9, 0x00, 0xd4, 0x00, 0xce, 0x00, 0xca, 0x00, 0xc5, 0x00, 0xc1, +0x00, 0xbd, 0x00, 0xb9, 0x00, 0xb6, 0x00, 0xb2, 0x00, 0xaf, 0x00, 0xad, +0x00, 0xaa, 0x00, 0xa8, 0x00, 0xa6, 0x00, 0xa4, 0x00, 0xa2, 0x00, 0xa0, +0x01, 0x9f, 0x01, 0x9e, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, +0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, +0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, +0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0xbd, 0x00, 0xb9, 0x00, 0xae, 0x00, 0x9e, +0x00, 0x8b, 0x00, 0x77, 0x00, 0x63, 0x00, 0x50, 0x00, 0x3f, 0x00, 0x30, +0x00, 0x23, 0x00, 0x18, 0x00, 0x0e, 0x00, 0x06, 0x00, 0x00, 0x07, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x39, 0x00, +0x2f, 0x00, 0x1f, 0x00, 0x0b, 0x00, 0x00, 0x08, 0x00, 0x1c, 0x00, 0x2e, +0x00, 0x3f, 0x00, 0x4e, 0x00, 0x5b, 0x00, 0x66, 0x00, 0x70, 0x00, 0x78, +0x00, 0x80, 0x00, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x3d, 0x46, 0x39, 0x4a, 0x35, 0x4d, 0x32, 0x50, 0x30, 0x53, 0x2e, 0x55, +0x2c, 0x57, 0x2a, 0x58, 0x29, 0x5c, 0x27, 0x5c, 0x27, 0x5d, 0x25, 0x60, +0x23, 0x60, 0x23, 0x60, 0x23, 0x63, 0x22, 0x65, 0x20, 0x65, 0x20, 0x65, +0x20, 0x65, 0x20, 0x67, 0x1f, 0x27, 0x1c, 0x2c, 0x19, 0x30, 0x17, 0x35, +0x15, 0x39, 0x14, 0x3d, 0x13, 0x40, 0x12, 0x44, 0x12, 0x47, 0x11, 0x49, +0x11, 0x4c, 0x11, 0x4f, 0x11, 0x51, 0x10, 0x54, 0x10, 0x56, 0x10, 0x58, +0x10, 0x59, 0x10, 0x5b, 0x10, 0x5c, 0x10, 0x5e, 0x00, 0xda, 0x00, 0xd4, +0x00, 0xd0, 0x00, 0xcb, 0x00, 0xc7, 0x00, 0xc2, 0x00, 0xbe, 0x00, 0xbb, +0x00, 0xb8, 0x00, 0xb5, 0x00, 0xb2, 0x00, 0xaf, 0x00, 0xad, 0x00, 0xaa, +0x00, 0xa8, 0x00, 0xa6, 0x00, 0xa4, 0x00, 0xa3, 0x00, 0xa1, 0x01, 0xa0, +0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, +0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, +0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, +0x10, 0x7f, 0x10, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0xbd, 0x00, 0xba, 0x00, 0xb1, 0x00, 0xa4, 0x00, 0x94, 0x00, 0x82, +0x00, 0x70, 0x00, 0x5e, 0x00, 0x4e, 0x00, 0x3f, 0x00, 0x32, 0x00, 0x26, +0x00, 0x1c, 0x00, 0x13, 0x00, 0x0b, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x3b, 0x00, 0x32, 0x00, 0x25, 0x00, +0x14, 0x00, 0x02, 0x00, 0x00, 0x0f, 0x00, 0x20, 0x00, 0x30, 0x00, 0x3f, +0x00, 0x4d, 0x00, 0x58, 0x00, 0x63, 0x00, 0x6c, 0x00, 0x74, 0x00, 0x7b, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3d, 0x46, 0x39, 0x49, +0x36, 0x4c, 0x33, 0x4f, 0x31, 0x52, 0x2e, 0x53, 0x2d, 0x57, 0x2b, 0x57, +0x2a, 0x59, 0x28, 0x5c, 0x27, 0x5c, 0x27, 0x5e, 0x25, 0x60, 0x23, 0x60, +0x23, 0x60, 0x23, 0x62, 0x22, 0x65, 0x20, 0x65, 0x20, 0x65, 0x20, 0x65, +0x1f, 0x26, 0x1c, 0x2b, 0x19, 0x2f, 0x17, 0x33, 0x16, 0x37, 0x14, 0x3b, +0x13, 0x3e, 0x13, 0x41, 0x12, 0x44, 0x11, 0x47, 0x11, 0x4a, 0x11, 0x4d, +0x11, 0x4f, 0x11, 0x51, 0x10, 0x54, 0x10, 0x55, 0x10, 0x57, 0x10, 0x59, +0x10, 0x5a, 0x10, 0x5b, 0x00, 0xda, 0x00, 0xd5, 0x00, 0xd1, 0x00, 0xcc, +0x00, 0xc8, 0x00, 0xc4, 0x00, 0xc1, 0x00, 0xbd, 0x00, 0xba, 0x00, 0xb7, +0x00, 0xb4, 0x00, 0xb2, 0x00, 0xaf, 0x00, 0xad, 0x00, 0xaa, 0x00, 0xa9, +0x00, 0xa7, 0x00, 0xa5, 0x00, 0xa4, 0x00, 0xa2, 0x10, 0x7f, 0x10, 0x7f, +0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, +0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, +0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbd, 0x00, 0xbb, +0x00, 0xb4, 0x00, 0xa9, 0x00, 0x9b, 0x00, 0x8b, 0x00, 0x7b, 0x00, 0x6b, +0x00, 0x5b, 0x00, 0x4d, 0x00, 0x3f, 0x00, 0x33, 0x00, 0x28, 0x00, 0x1f, +0x00, 0x16, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x3e, 0x00, 0x3c, 0x00, 0x34, 0x00, 0x29, 0x00, 0x1b, 0x00, 0x0c, 0x00, +0x00, 0x04, 0x00, 0x14, 0x00, 0x23, 0x00, 0x32, 0x00, 0x3f, 0x00, 0x4b, +0x00, 0x56, 0x00, 0x60, 0x00, 0x68, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x3d, 0x45, 0x39, 0x48, 0x36, 0x4b, 0x34, 0x4f, +0x31, 0x50, 0x30, 0x53, 0x2e, 0x55, 0x2c, 0x57, 0x2a, 0x57, 0x2a, 0x5a, +0x28, 0x5c, 0x27, 0x5c, 0x27, 0x5e, 0x25, 0x60, 0x23, 0x60, 0x23, 0x60, +0x23, 0x61, 0x22, 0x64, 0x21, 0x65, 0x20, 0x65, 0x20, 0x26, 0x1c, 0x2a, +0x1a, 0x2e, 0x18, 0x32, 0x16, 0x36, 0x14, 0x39, 0x13, 0x3d, 0x13, 0x40, +0x12, 0x43, 0x12, 0x45, 0x11, 0x48, 0x11, 0x4b, 0x11, 0x4d, 0x11, 0x4f, +0x11, 0x51, 0x10, 0x53, 0x10, 0x55, 0x10, 0x56, 0x10, 0x58, 0x10, 0x5a, +0x00, 0xda, 0x00, 0xd6, 0x00, 0xd1, 0x00, 0xcd, 0x00, 0xc9, 0x00, 0xc6, +0x00, 0xc2, 0x00, 0xbf, 0x00, 0xbc, 0x00, 0xb9, 0x00, 0xb6, 0x00, 0xb3, +0x00, 0xb1, 0x00, 0xaf, 0x00, 0xad, 0x00, 0xab, 0x00, 0xa9, 0x00, 0xa7, +0x00, 0xa6, 0x00, 0xa4, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, +0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, +0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, +0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x00, 0xbc, 0x00, 0xb6, 0x00, 0xac, +0x00, 0xa0, 0x00, 0x93, 0x00, 0x84, 0x00, 0x75, 0x00, 0x66, 0x00, 0x58, +0x00, 0x4b, 0x00, 0x3f, 0x00, 0x34, 0x00, 0x2a, 0x00, 0x21, 0x00, 0x19, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x3c, 0x00, +0x36, 0x00, 0x2d, 0x00, 0x21, 0x00, 0x13, 0x00, 0x04, 0x00, 0x00, 0x0a, +0x00, 0x18, 0x00, 0x26, 0x00, 0x33, 0x00, 0x3f, 0x00, 0x4a, 0x00, 0x54, +0x00, 0x5d, 0x00, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x3d, 0x45, 0x3a, 0x48, 0x37, 0x4a, 0x35, 0x4e, 0x32, 0x4f, 0x31, 0x53, +0x2e, 0x53, 0x2e, 0x56, 0x2b, 0x57, 0x2a, 0x58, 0x29, 0x5b, 0x27, 0x5c, +0x27, 0x5c, 0x27, 0x5e, 0x25, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x61, +0x23, 0x64, 0x21, 0x65, 0x20, 0x26, 0x1d, 0x2a, 0x1a, 0x2d, 0x18, 0x31, +0x17, 0x35, 0x15, 0x38, 0x14, 0x3b, 0x13, 0x3e, 0x13, 0x41, 0x12, 0x44, +0x12, 0x46, 0x11, 0x49, 0x11, 0x4b, 0x11, 0x4d, 0x11, 0x4f, 0x11, 0x51, +0x10, 0x53, 0x10, 0x55, 0x10, 0x56, 0x10, 0x58, 0x00, 0xda, 0x00, 0xd6, +0x00, 0xd2, 0x00, 0xce, 0x00, 0xcb, 0x00, 0xc7, 0x00, 0xc4, 0x00, 0xc1, +0x00, 0xbe, 0x00, 0xbb, 0x00, 0xb8, 0x00, 0xb6, 0x00, 0xb3, 0x00, 0xb1, +0x00, 0xaf, 0x00, 0xad, 0x00, 0xab, 0x00, 0xa9, 0x00, 0xa8, 0x00, 0xa6, +0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, +0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, +0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, +0x10, 0x7f, 0x10, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0xbe, 0x00, 0xbc, 0x00, 0xb7, 0x00, 0xaf, 0x00, 0xa5, 0x00, 0x99, +0x00, 0x8b, 0x00, 0x7e, 0x00, 0x70, 0x00, 0x63, 0x00, 0x56, 0x00, 0x4a, +0x00, 0x3f, 0x00, 0x35, 0x00, 0x2c, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x3d, 0x00, 0x38, 0x00, 0x30, 0x00, +0x25, 0x00, 0x19, 0x00, 0x0c, 0x00, 0x00, 0x01, 0x00, 0x0e, 0x00, 0x1c, +0x00, 0x28, 0x00, 0x34, 0x00, 0x3f, 0x00, 0x49, 0x00, 0x53, 0x00, 0x5b, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3d, 0x45, 0x3a, 0x47, +0x38, 0x4a, 0x35, 0x4d, 0x33, 0x4f, 0x31, 0x51, 0x2f, 0x53, 0x2e, 0x54, +0x2c, 0x57, 0x2a, 0x57, 0x2a, 0x59, 0x29, 0x5c, 0x27, 0x5c, 0x27, 0x5c, +0x27, 0x5e, 0x25, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x63, +0x20, 0x25, 0x1d, 0x29, 0x1a, 0x2d, 0x18, 0x30, 0x17, 0x33, 0x16, 0x37, +0x14, 0x3a, 0x13, 0x3d, 0x13, 0x3f, 0x13, 0x42, 0x12, 0x44, 0x11, 0x47, +0x11, 0x49, 0x11, 0x4b, 0x11, 0x4d, 0x11, 0x4f, 0x11, 0x51, 0x10, 0x53, +0x10, 0x55, 0x10, 0x56, 0x00, 0xdb, 0x00, 0xd7, 0x00, 0xd3, 0x00, 0xcf, +0x00, 0xcc, 0x00, 0xc8, 0x00, 0xc5, 0x00, 0xc2, 0x00, 0xbf, 0x00, 0xbc, +0x00, 0xba, 0x00, 0xb7, 0x00, 0xb5, 0x00, 0xb3, 0x00, 0xb1, 0x00, 0xaf, +0x00, 0xad, 0x00, 0xab, 0x00, 0xa9, 0x00, 0xa8, 0x10, 0x7f, 0x10, 0x7f, +0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, +0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, +0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x00, 0xbd, +0x00, 0xb8, 0x00, 0xb1, 0x00, 0xa8, 0x00, 0x9d, 0x00, 0x92, 0x00, 0x85, +0x00, 0x78, 0x00, 0x6c, 0x00, 0x60, 0x00, 0x54, 0x00, 0x49, 0x00, 0x3f, +0x00, 0x36, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x3f, 0x00, 0x3d, 0x00, 0x39, 0x00, 0x32, 0x00, 0x29, 0x00, 0x1e, 0x00, +0x12, 0x00, 0x06, 0x00, 0x00, 0x06, 0x00, 0x13, 0x00, 0x1f, 0x00, 0x2a, +0x00, 0x35, 0x00, 0x3f, 0x00, 0x49, 0x00, 0x51, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x3d, 0x44, 0x3a, 0x47, 0x38, 0x4a, 0x35, 0x4c, +0x33, 0x4f, 0x31, 0x50, 0x30, 0x53, 0x2e, 0x53, 0x2e, 0x56, 0x2b, 0x57, +0x2a, 0x57, 0x2a, 0x5a, 0x28, 0x5c, 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x5f, +0x25, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x20, 0x25, 0x1d, 0x29, +0x1b, 0x2c, 0x18, 0x2f, 0x17, 0x33, 0x16, 0x36, 0x14, 0x39, 0x14, 0x3b, +0x13, 0x3e, 0x13, 0x41, 0x12, 0x43, 0x12, 0x45, 0x11, 0x47, 0x11, 0x4a, +0x11, 0x4c, 0x11, 0x4e, 0x11, 0x4f, 0x11, 0x51, 0x10, 0x52, 0x10, 0x54, +0x00, 0xdb, 0x00, 0xd7, 0x00, 0xd3, 0x00, 0xd0, 0x00, 0xcc, 0x00, 0xc9, +0x00, 0xc6, 0x00, 0xc3, 0x00, 0xc1, 0x00, 0xbe, 0x00, 0xbb, 0x00, 0xb9, +0x00, 0xb7, 0x00, 0xb5, 0x00, 0xb3, 0x00, 0xb0, 0x00, 0xaf, 0x00, 0xad, +0x00, 0xab, 0x00, 0xaa, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, +0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, +0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, +0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x00, 0xbd, 0x00, 0xb9, 0x00, 0xb3, +0x00, 0xab, 0x00, 0xa1, 0x00, 0x97, 0x00, 0x8b, 0x00, 0x80, 0x00, 0x74, +0x00, 0x68, 0x00, 0x5d, 0x00, 0x53, 0x00, 0x49, 0x00, 0x3f, 0x00, 0x36, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x3d, 0x00, +0x3a, 0x00, 0x33, 0x00, 0x2b, 0x00, 0x22, 0x00, 0x17, 0x00, 0x0c, 0x00, +0x00, 0x00, 0x00, 0x0b, 0x00, 0x16, 0x00, 0x21, 0x00, 0x2c, 0x00, 0x36, +0x00, 0x3f, 0x00, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x3d, 0x44, 0x3b, 0x46, 0x39, 0x4a, 0x35, 0x4b, 0x34, 0x4f, 0x31, 0x4f, +0x31, 0x53, 0x2e, 0x53, 0x2e, 0x54, 0x2c, 0x57, 0x2a, 0x57, 0x2a, 0x58, +0x2a, 0x5b, 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x5f, 0x24, 0x60, +0x23, 0x60, 0x23, 0x60, 0x20, 0x25, 0x1d, 0x28, 0x1b, 0x2b, 0x19, 0x2f, +0x17, 0x32, 0x16, 0x35, 0x15, 0x38, 0x14, 0x3a, 0x13, 0x3d, 0x13, 0x3f, +0x13, 0x42, 0x12, 0x44, 0x12, 0x46, 0x11, 0x48, 0x11, 0x4a, 0x11, 0x4c, +0x11, 0x4e, 0x11, 0x4f, 0x11, 0x51, 0x10, 0x52, 0x00, 0xdb, 0x00, 0xd7, +0x00, 0xd4, 0x00, 0xd0, 0x00, 0xcd, 0x00, 0xca, 0x00, 0xc7, 0x00, 0xc5, +0x00, 0xc2, 0x00, 0xbf, 0x00, 0xbd, 0x00, 0xbb, 0x00, 0xb8, 0x00, 0xb6, +0x00, 0xb4, 0x00, 0xb2, 0x00, 0xb0, 0x00, 0xaf, 0x00, 0xad, 0x00, 0xac, +0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, +0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, +0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, +0x10, 0x7f, 0x10, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0xbe, 0x00, 0xbd, 0x00, 0xba, 0x00, 0xb4, 0x00, 0xad, 0x00, 0xa5, +0x00, 0x9b, 0x00, 0x91, 0x00, 0x86, 0x00, 0x7b, 0x00, 0x70, 0x00, 0x65, +0x00, 0x5b, 0x00, 0x51, 0x00, 0x48, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x3e, 0x00, 0x3a, 0x00, 0x35, 0x00, +0x2e, 0x00, 0x25, 0x00, 0x1c, 0x00, 0x11, 0x00, 0x07, 0x00, 0x00, 0x03, +0x00, 0x0e, 0x00, 0x19, 0x00, 0x23, 0x00, 0x2d, 0x00, 0x36, 0x00, 0x3f, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3d, 0x44, 0x3b, 0x46, +0x39, 0x49, 0x36, 0x4a, 0x35, 0x4e, 0x32, 0x4f, 0x31, 0x51, 0x2f, 0x53, +0x2e, 0x53, 0x2e, 0x56, 0x2b, 0x57, 0x2a, 0x57, 0x2a, 0x58, 0x29, 0x5c, +0x27, 0x5c, 0x27, 0x5c, 0x27, 0x5c, 0x26, 0x5f, 0x24, 0x60, 0x23, 0x60, +0x20, 0x25, 0x1d, 0x28, 0x1c, 0x2b, 0x1a, 0x2e, 0x18, 0x31, 0x17, 0x34, +0x16, 0x37, 0x14, 0x39, 0x13, 0x3b, 0x13, 0x3e, 0x13, 0x40, 0x12, 0x42, +0x12, 0x45, 0x11, 0x46, 0x11, 0x49, 0x11, 0x4a, 0x11, 0x4c, 0x11, 0x4e, +0x11, 0x4f, 0x11, 0x51, 0x00, 0xdb, 0x00, 0xd8, 0x00, 0xd4, 0x00, 0xd1, +0x00, 0xce, 0x00, 0xcb, 0x00, 0xc8, 0x00, 0xc6, 0x00, 0xc3, 0x00, 0xc1, +0x00, 0xbe, 0x00, 0xbc, 0x00, 0xba, 0x00, 0xb8, 0x00, 0xb6, 0x00, 0xb4, +0x00, 0xb2, 0x00, 0xb0, 0x00, 0xaf, 0x00, 0xad, 0x10, 0x7f, 0x10, 0x7f, +0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, +0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, +0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, 0x10, 0x7f, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x40, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x56, 0x7f, 0x47, 0x63, +0x44, 0x57, 0x43, 0x52, 0x43, 0x4e, 0x42, 0x4c, 0x42, 0x4a, 0x42, 0x49, +0x42, 0x48, 0x42, 0x47, 0x42, 0x46, 0x42, 0x45, 0x42, 0x45, 0x42, 0x45, +0x42, 0x44, 0x42, 0x44, 0x42, 0x44, 0x42, 0x43, 0x42, 0x43, 0x42, 0x43, +0x4c, 0x7f, 0x27, 0x4d, 0x2f, 0x46, 0x33, 0x44, 0x36, 0x43, 0x37, 0x43, +0x39, 0x42, 0x3a, 0x41, 0x3a, 0x41, 0x3b, 0x41, 0x3b, 0x41, 0x3b, 0x41, +0x3c, 0x41, 0x3c, 0x41, 0x3c, 0x41, 0x3c, 0x41, 0x3c, 0x41, 0x3d, 0x41, +0x3d, 0x41, 0x3d, 0x41, 0x8e, 0x7f, 0x47, 0x4d, 0x44, 0x46, 0x43, 0x44, +0x43, 0x43, 0x42, 0x43, 0x42, 0x42, 0x42, 0x41, 0x42, 0x41, 0x42, 0x41, +0x42, 0x41, 0x42, 0x41, 0x42, 0x41, 0x42, 0x41, 0x42, 0x41, 0x42, 0x41, +0x42, 0x41, 0x42, 0x41, 0x42, 0x41, 0x42, 0x41, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x0d, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x85, 0x1b, 0x60, 0x27, 0x54, 0x2d, 0x4e, 0x30, +0x4b, 0x33, 0x49, 0x34, 0x47, 0x35, 0x46, 0x37, 0x45, 0x38, 0x45, 0x38, +0x44, 0x39, 0x43, 0x39, 0x43, 0x3a, 0x42, 0x3a, 0x42, 0x3a, 0x42, 0x3b, +0x42, 0x3b, 0x42, 0x3b, 0x42, 0x3b, 0x42, 0x3b, 0x09, 0x43, 0x16, 0x3f, +0x1f, 0x3e, 0x25, 0x3e, 0x29, 0x3e, 0x2c, 0x3e, 0x2f, 0x3e, 0x30, 0x3e, +0x32, 0x3e, 0x33, 0x3e, 0x34, 0x3e, 0x35, 0x3e, 0x36, 0x3e, 0x36, 0x3e, +0x37, 0x3e, 0x37, 0x3e, 0x38, 0x3e, 0x38, 0x3e, 0x38, 0x3e, 0x39, 0x3e, +0x59, 0x31, 0x4f, 0x38, 0x4b, 0x3a, 0x48, 0x3b, 0x47, 0x3c, 0x46, 0x3c, +0x45, 0x3d, 0x45, 0x3d, 0x44, 0x3d, 0x43, 0x3d, 0x43, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x4c, 0x00, 0x2f, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x4f, 0x00, 0x04, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x96, 0x05, 0x74, 0x0f, 0x63, 0x17, 0x5a, 0x1d, 0x54, 0x21, 0x51, 0x24, +0x4e, 0x27, 0x4c, 0x29, 0x4a, 0x2b, 0x49, 0x2d, 0x49, 0x2e, 0x48, 0x2f, +0x48, 0x31, 0x47, 0x31, 0x46, 0x32, 0x46, 0x33, 0x44, 0x33, 0x44, 0x34, +0x43, 0x34, 0x43, 0x35, 0x09, 0x43, 0x11, 0x3e, 0x18, 0x3c, 0x1d, 0x3c, +0x22, 0x3c, 0x25, 0x3c, 0x27, 0x3c, 0x2a, 0x3c, 0x2c, 0x3d, 0x2d, 0x3d, +0x2f, 0x3d, 0x30, 0x3e, 0x31, 0x3e, 0x31, 0x3e, 0x32, 0x3e, 0x33, 0x3e, +0x33, 0x3e, 0x34, 0x3e, 0x35, 0x3e, 0x35, 0x3e, 0x5b, 0x2a, 0x53, 0x31, +0x4f, 0x34, 0x4c, 0x36, 0x4b, 0x38, 0x4a, 0x39, 0x48, 0x39, 0x47, 0x3a, +0x46, 0x3b, 0x46, 0x3b, 0x46, 0x3c, 0x46, 0x3c, 0x46, 0x3d, 0x45, 0x3d, +0x44, 0x3d, 0x44, 0x3d, 0x43, 0x3d, 0x43, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x56, 0x00, 0x45, +0x00, 0x22, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x8f, 0x00, 0x73, 0x00, 0x38, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x9e, 0x01, 0x81, 0x06, +0x6f, 0x0d, 0x64, 0x12, 0x5d, 0x16, 0x58, 0x1a, 0x54, 0x1d, 0x53, 0x20, +0x50, 0x22, 0x4e, 0x24, 0x4c, 0x26, 0x4b, 0x27, 0x4a, 0x29, 0x49, 0x2a, +0x49, 0x2b, 0x49, 0x2c, 0x48, 0x2d, 0x48, 0x2e, 0x48, 0x2f, 0x47, 0x2f, +0x09, 0x44, 0x0f, 0x3e, 0x14, 0x3c, 0x19, 0x3c, 0x1d, 0x3b, 0x20, 0x3b, +0x23, 0x3b, 0x25, 0x3c, 0x27, 0x3c, 0x28, 0x3c, 0x2a, 0x3b, 0x2c, 0x3b, +0x2c, 0x3b, 0x2d, 0x3b, 0x2f, 0x3c, 0x2f, 0x3c, 0x30, 0x3d, 0x31, 0x3e, +0x32, 0x3e, 0x32, 0x3e, 0x5c, 0x28, 0x56, 0x2d, 0x52, 0x31, 0x4f, 0x33, +0x4e, 0x35, 0x4b, 0x36, 0x4a, 0x37, 0x4a, 0x38, 0x49, 0x39, 0x47, 0x39, +0x46, 0x39, 0x46, 0x39, 0x46, 0x39, 0x46, 0x3a, 0x46, 0x3a, 0x46, 0x3b, +0x46, 0x3c, 0x46, 0x3c, 0x46, 0x3d, 0x45, 0x3d, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x59, 0x00, 0x4f, 0x00, 0x36, 0x00, 0x19, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x96, 0x00, 0x84, 0x00, +0x5b, 0x00, 0x2a, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0xa4, 0x00, 0x8a, 0x03, 0x78, 0x07, 0x6d, 0x0c, +0x65, 0x10, 0x60, 0x13, 0x5b, 0x16, 0x57, 0x19, 0x55, 0x1b, 0x53, 0x1e, +0x52, 0x1f, 0x4f, 0x22, 0x4d, 0x23, 0x4c, 0x24, 0x4b, 0x25, 0x4b, 0x27, +0x4a, 0x28, 0x49, 0x29, 0x49, 0x29, 0x49, 0x2b, 0x09, 0x45, 0x0d, 0x40, +0x11, 0x3d, 0x16, 0x3c, 0x19, 0x3b, 0x1d, 0x3b, 0x1f, 0x3b, 0x21, 0x3a, +0x23, 0x3b, 0x25, 0x3b, 0x26, 0x3c, 0x28, 0x3c, 0x29, 0x3c, 0x2a, 0x3b, +0x2b, 0x3b, 0x2c, 0x3b, 0x2d, 0x3b, 0x2e, 0x3b, 0x2e, 0x3b, 0x2f, 0x3b, +0x5d, 0x27, 0x57, 0x2c, 0x54, 0x2f, 0x52, 0x31, 0x4f, 0x32, 0x4e, 0x34, +0x4c, 0x35, 0x4a, 0x35, 0x4a, 0x36, 0x4a, 0x37, 0x4a, 0x38, 0x48, 0x39, +0x47, 0x39, 0x46, 0x39, 0x46, 0x39, 0x46, 0x39, 0x46, 0x39, 0x46, 0x39, +0x46, 0x39, 0x46, 0x3a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x5b, 0x00, 0x55, 0x00, 0x42, 0x00, 0x2b, 0x00, 0x14, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x99, 0x00, 0x8d, 0x00, 0x6f, 0x00, 0x48, 0x00, +0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0xa7, 0x00, 0x91, 0x01, 0x80, 0x04, 0x75, 0x08, 0x6c, 0x0b, 0x65, 0x0e, +0x61, 0x11, 0x5d, 0x14, 0x59, 0x16, 0x56, 0x19, 0x55, 0x1a, 0x54, 0x1c, +0x53, 0x1e, 0x51, 0x1f, 0x4f, 0x21, 0x4d, 0x22, 0x4c, 0x23, 0x4b, 0x24, +0x4b, 0x25, 0x4b, 0x26, 0x09, 0x45, 0x0d, 0x41, 0x10, 0x3e, 0x14, 0x3d, +0x17, 0x3c, 0x1a, 0x3b, 0x1c, 0x3b, 0x1e, 0x3b, 0x20, 0x3b, 0x22, 0x3a, +0x23, 0x3a, 0x25, 0x3b, 0x26, 0x3c, 0x28, 0x3c, 0x28, 0x3c, 0x29, 0x3c, +0x2a, 0x3c, 0x2b, 0x3b, 0x2c, 0x3b, 0x2d, 0x3b, 0x5d, 0x26, 0x59, 0x2a, +0x56, 0x2d, 0x53, 0x2f, 0x51, 0x31, 0x4f, 0x32, 0x4f, 0x33, 0x4d, 0x35, +0x4b, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x37, 0x4a, 0x38, 0x49, 0x39, +0x48, 0x39, 0x47, 0x39, 0x46, 0x39, 0x46, 0x39, 0x46, 0x39, 0x46, 0x39, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5d, 0x00, 0x58, +0x00, 0x4a, 0x00, 0x38, 0x00, 0x24, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x9b, 0x00, 0x92, 0x00, 0x7c, 0x00, 0x5d, 0x00, 0x3c, 0x00, 0x1c, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0xa9, 0x00, 0x96, 0x00, +0x86, 0x02, 0x7a, 0x05, 0x72, 0x08, 0x6b, 0x0b, 0x65, 0x0e, 0x62, 0x10, +0x5f, 0x12, 0x5b, 0x14, 0x58, 0x16, 0x56, 0x18, 0x55, 0x1a, 0x54, 0x1b, +0x53, 0x1d, 0x52, 0x1e, 0x50, 0x1f, 0x4f, 0x20, 0x4d, 0x21, 0x4c, 0x22, +0x09, 0x46, 0x0c, 0x41, 0x0f, 0x3f, 0x12, 0x3d, 0x15, 0x3c, 0x17, 0x3c, +0x1a, 0x3b, 0x1c, 0x3a, 0x1e, 0x3b, 0x1f, 0x3b, 0x21, 0x3a, 0x22, 0x3a, +0x24, 0x3a, 0x25, 0x3a, 0x26, 0x3b, 0x27, 0x3c, 0x28, 0x3c, 0x29, 0x3c, +0x2a, 0x3c, 0x2a, 0x3c, 0x5e, 0x26, 0x5a, 0x29, 0x57, 0x2c, 0x53, 0x2e, +0x53, 0x30, 0x50, 0x31, 0x4f, 0x31, 0x4f, 0x33, 0x4e, 0x34, 0x4c, 0x35, +0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x36, 0x4a, 0x37, 0x4a, 0x38, +0x48, 0x39, 0x47, 0x39, 0x46, 0x39, 0x46, 0x39, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x5d, 0x00, 0x59, 0x00, 0x4f, 0x00, 0x40, +0x00, 0x2f, 0x00, 0x1e, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9c, 0x00, 0x95, 0x00, +0x84, 0x00, 0x6c, 0x00, 0x4f, 0x00, 0x32, 0x00, 0x18, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0xab, 0x00, 0x9a, 0x00, 0x8b, 0x01, 0x7f, 0x03, +0x77, 0x06, 0x71, 0x08, 0x6a, 0x0b, 0x66, 0x0d, 0x63, 0x0f, 0x60, 0x11, +0x5d, 0x13, 0x59, 0x14, 0x57, 0x16, 0x56, 0x18, 0x55, 0x19, 0x54, 0x1b, +0x53, 0x1c, 0x53, 0x1d, 0x51, 0x1e, 0x50, 0x1f, 0x0a, 0x46, 0x0c, 0x42, +0x0e, 0x3f, 0x11, 0x3f, 0x13, 0x3c, 0x16, 0x3c, 0x18, 0x3c, 0x1a, 0x3b, +0x1c, 0x3a, 0x1e, 0x3b, 0x1f, 0x3b, 0x20, 0x3b, 0x21, 0x3a, 0x23, 0x3a, +0x24, 0x3a, 0x25, 0x39, 0x26, 0x3a, 0x27, 0x3c, 0x27, 0x3c, 0x28, 0x3c, +0x5e, 0x26, 0x5a, 0x29, 0x57, 0x2b, 0x55, 0x2d, 0x53, 0x2e, 0x53, 0x30, +0x50, 0x31, 0x4f, 0x31, 0x4f, 0x32, 0x4f, 0x34, 0x4d, 0x35, 0x4b, 0x35, +0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x36, 0x4a, 0x38, +0x4a, 0x39, 0x48, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x5e, 0x00, 0x5b, 0x00, 0x53, 0x00, 0x47, 0x00, 0x38, 0x00, 0x29, +0x00, 0x1a, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x9c, 0x00, 0x98, 0x00, 0x8a, 0x00, 0x76, 0x00, +0x5e, 0x00, 0x45, 0x00, 0x2c, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0xac, 0x00, 0x9d, 0x00, 0x8f, 0x01, 0x85, 0x02, 0x7b, 0x04, 0x75, 0x06, +0x6f, 0x08, 0x69, 0x0b, 0x66, 0x0d, 0x63, 0x0e, 0x61, 0x10, 0x5e, 0x12, +0x5b, 0x13, 0x58, 0x15, 0x57, 0x16, 0x56, 0x18, 0x55, 0x19, 0x55, 0x1a, +0x54, 0x1b, 0x53, 0x1c, 0x0a, 0x47, 0x0b, 0x42, 0x0e, 0x40, 0x10, 0x3f, +0x12, 0x3d, 0x15, 0x3c, 0x17, 0x3c, 0x18, 0x3c, 0x1a, 0x3b, 0x1c, 0x3a, +0x1d, 0x3b, 0x1f, 0x3b, 0x20, 0x3b, 0x21, 0x3b, 0x22, 0x3a, 0x23, 0x3a, +0x24, 0x3a, 0x25, 0x39, 0x26, 0x3a, 0x27, 0x3b, 0x5e, 0x26, 0x5b, 0x28, +0x57, 0x2a, 0x57, 0x2c, 0x53, 0x2e, 0x53, 0x2e, 0x52, 0x30, 0x4f, 0x31, +0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x33, 0x4e, 0x35, 0x4b, 0x35, 0x4a, 0x35, +0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x36, 0x4a, 0x37, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x5c, +0x00, 0x55, 0x00, 0x4b, 0x00, 0x3f, 0x00, 0x32, 0x00, 0x24, 0x00, 0x17, +0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x9d, 0x00, 0x99, 0x00, 0x8e, 0x00, 0x7e, 0x00, 0x69, 0x00, 0x53, 0x00, +0x3c, 0x00, 0x26, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0xad, 0x00, 0xa0, 0x00, +0x92, 0x00, 0x89, 0x02, 0x7f, 0x03, 0x78, 0x05, 0x73, 0x07, 0x6e, 0x09, +0x69, 0x0b, 0x66, 0x0c, 0x64, 0x0e, 0x62, 0x0f, 0x60, 0x11, 0x5c, 0x12, +0x59, 0x14, 0x58, 0x15, 0x57, 0x16, 0x56, 0x18, 0x55, 0x18, 0x55, 0x1a, +0x0a, 0x47, 0x0b, 0x43, 0x0d, 0x41, 0x0f, 0x3f, 0x11, 0x3f, 0x13, 0x3c, +0x15, 0x3b, 0x17, 0x3c, 0x18, 0x3c, 0x1a, 0x3b, 0x1c, 0x3a, 0x1d, 0x3a, +0x1f, 0x3b, 0x1f, 0x3b, 0x21, 0x3b, 0x21, 0x3b, 0x22, 0x3a, 0x24, 0x3a, +0x24, 0x3a, 0x24, 0x39, 0x5e, 0x26, 0x5c, 0x27, 0x58, 0x2a, 0x57, 0x2b, +0x55, 0x2e, 0x53, 0x2e, 0x53, 0x2f, 0x52, 0x31, 0x4f, 0x31, 0x4f, 0x31, +0x4f, 0x31, 0x4f, 0x32, 0x4e, 0x34, 0x4c, 0x35, 0x4a, 0x35, 0x4a, 0x35, +0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x5c, 0x00, 0x57, 0x00, 0x4f, +0x00, 0x44, 0x00, 0x38, 0x00, 0x2c, 0x00, 0x20, 0x00, 0x14, 0x00, 0x09, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9d, 0x00, 0x9a, 0x00, +0x91, 0x00, 0x83, 0x00, 0x72, 0x00, 0x5e, 0x00, 0x4a, 0x00, 0x36, 0x00, +0x22, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0xae, 0x00, 0xa2, 0x00, 0x95, 0x00, 0x8b, 0x01, +0x83, 0x02, 0x7b, 0x04, 0x76, 0x05, 0x73, 0x07, 0x6e, 0x09, 0x69, 0x0a, +0x66, 0x0c, 0x64, 0x0d, 0x62, 0x0f, 0x61, 0x10, 0x5e, 0x11, 0x5b, 0x13, +0x58, 0x14, 0x58, 0x15, 0x56, 0x16, 0x56, 0x18, 0x0a, 0x47, 0x0b, 0x43, +0x0d, 0x42, 0x0f, 0x3f, 0x11, 0x3f, 0x12, 0x3e, 0x14, 0x3c, 0x16, 0x3c, +0x17, 0x3c, 0x19, 0x3c, 0x1a, 0x3b, 0x1c, 0x3a, 0x1d, 0x39, 0x1f, 0x3b, +0x1f, 0x3b, 0x20, 0x3b, 0x21, 0x3b, 0x21, 0x3a, 0x22, 0x3a, 0x24, 0x3a, +0x5e, 0x26, 0x5c, 0x27, 0x59, 0x2a, 0x57, 0x2a, 0x56, 0x2c, 0x53, 0x2e, +0x53, 0x2e, 0x53, 0x2f, 0x51, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, +0x4f, 0x32, 0x4f, 0x33, 0x4d, 0x35, 0x4b, 0x35, 0x4a, 0x35, 0x4a, 0x35, +0x4a, 0x35, 0x4a, 0x35, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x5e, 0x00, 0x5d, 0x00, 0x58, 0x00, 0x51, 0x00, 0x48, 0x00, 0x3e, +0x00, 0x33, 0x00, 0x28, 0x00, 0x1d, 0x00, 0x12, 0x00, 0x09, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x9b, 0x00, 0x93, 0x00, 0x88, 0x00, +0x79, 0x00, 0x68, 0x00, 0x55, 0x00, 0x43, 0x00, 0x30, 0x00, 0x1f, 0x00, +0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0xaf, 0x00, 0xa3, 0x00, 0x98, 0x00, 0x8e, 0x00, 0x87, 0x02, 0x7f, 0x03, +0x79, 0x04, 0x75, 0x06, 0x71, 0x07, 0x6c, 0x09, 0x68, 0x0a, 0x66, 0x0c, +0x64, 0x0d, 0x63, 0x0e, 0x61, 0x10, 0x5f, 0x11, 0x5c, 0x12, 0x59, 0x13, +0x58, 0x14, 0x58, 0x15, 0x0a, 0x47, 0x0b, 0x43, 0x0d, 0x42, 0x0e, 0x40, +0x10, 0x3e, 0x11, 0x3f, 0x13, 0x3c, 0x15, 0x3b, 0x17, 0x3c, 0x17, 0x3c, +0x19, 0x3c, 0x1a, 0x3b, 0x1c, 0x3b, 0x1c, 0x39, 0x1e, 0x3a, 0x1f, 0x3b, +0x1f, 0x3b, 0x21, 0x3b, 0x21, 0x3b, 0x22, 0x3a, 0x5e, 0x25, 0x5c, 0x27, +0x5a, 0x29, 0x57, 0x2a, 0x57, 0x2b, 0x54, 0x2e, 0x53, 0x2e, 0x53, 0x2e, +0x53, 0x2f, 0x50, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, +0x4f, 0x33, 0x4e, 0x34, 0x4c, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x5d, +0x00, 0x59, 0x00, 0x53, 0x00, 0x4c, 0x00, 0x42, 0x00, 0x39, 0x00, 0x2e, +0x00, 0x24, 0x00, 0x1a, 0x00, 0x11, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x9e, 0x00, 0x9c, 0x00, 0x95, 0x00, 0x8b, 0x00, 0x7e, 0x00, 0x6f, 0x00, +0x5f, 0x00, 0x4e, 0x00, 0x3d, 0x00, 0x2c, 0x00, 0x1c, 0x00, 0x0d, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0xaf, 0x00, 0xa5, 0x00, +0x9a, 0x00, 0x90, 0x00, 0x8a, 0x01, 0x83, 0x02, 0x7c, 0x03, 0x77, 0x05, +0x74, 0x06, 0x70, 0x07, 0x6c, 0x09, 0x68, 0x0a, 0x66, 0x0b, 0x64, 0x0c, +0x63, 0x0e, 0x61, 0x0f, 0x60, 0x11, 0x5d, 0x11, 0x5b, 0x13, 0x59, 0x13, +0x0a, 0x47, 0x0a, 0x44, 0x0d, 0x42, 0x0e, 0x41, 0x0f, 0x3e, 0x11, 0x3f, +0x13, 0x3e, 0x14, 0x3c, 0x15, 0x3a, 0x17, 0x3c, 0x17, 0x3c, 0x19, 0x3c, +0x1a, 0x3b, 0x1c, 0x3b, 0x1c, 0x39, 0x1e, 0x3a, 0x1f, 0x3b, 0x1f, 0x3b, +0x20, 0x3b, 0x21, 0x3b, 0x5e, 0x25, 0x5c, 0x27, 0x5a, 0x29, 0x57, 0x2a, +0x57, 0x2a, 0x56, 0x2d, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x30, +0x50, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x32, +0x4f, 0x33, 0x4d, 0x35, 0x4b, 0x35, 0x4a, 0x35, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x5d, 0x00, 0x5a, 0x00, 0x55, +0x00, 0x4e, 0x00, 0x46, 0x00, 0x3d, 0x00, 0x34, 0x00, 0x2a, 0x00, 0x21, +0x00, 0x18, 0x00, 0x0f, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x9c, 0x00, +0x97, 0x00, 0x8e, 0x00, 0x83, 0x00, 0x75, 0x00, 0x66, 0x00, 0x57, 0x00, +0x47, 0x00, 0x37, 0x00, 0x28, 0x00, 0x1a, 0x00, 0x0c, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0xb0, 0x00, 0xa6, 0x00, 0x9d, 0x00, 0x92, 0x00, +0x8c, 0x01, 0x86, 0x02, 0x7e, 0x02, 0x7a, 0x04, 0x76, 0x05, 0x73, 0x06, +0x70, 0x07, 0x6b, 0x09, 0x68, 0x0a, 0x66, 0x0b, 0x65, 0x0c, 0x63, 0x0e, +0x62, 0x0e, 0x61, 0x10, 0x5e, 0x11, 0x5c, 0x12, 0x0a, 0x47, 0x0a, 0x44, +0x0c, 0x42, 0x0d, 0x41, 0x0f, 0x3f, 0x11, 0x3f, 0x11, 0x3f, 0x13, 0x3d, +0x15, 0x3c, 0x16, 0x3b, 0x17, 0x3c, 0x18, 0x3c, 0x19, 0x3c, 0x1a, 0x3b, +0x1c, 0x3b, 0x1c, 0x39, 0x1e, 0x39, 0x1f, 0x3b, 0x1f, 0x3b, 0x1f, 0x3b, +0x5f, 0x25, 0x5c, 0x27, 0x5b, 0x28, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2b, +0x54, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x52, 0x30, 0x4f, 0x31, +0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x33, +0x4e, 0x34, 0x4c, 0x35, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x5f, 0x00, 0x5e, 0x00, 0x5b, 0x00, 0x56, 0x00, 0x50, 0x00, 0x49, +0x00, 0x41, 0x00, 0x39, 0x00, 0x30, 0x00, 0x27, 0x00, 0x1e, 0x00, 0x16, +0x00, 0x0e, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x9c, 0x00, 0x98, 0x00, 0x90, 0x00, +0x86, 0x00, 0x7a, 0x00, 0x6d, 0x00, 0x5f, 0x00, 0x50, 0x00, 0x41, 0x00, +0x33, 0x00, 0x25, 0x00, 0x18, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0xb0, 0x00, 0xa7, 0x00, 0x9f, 0x00, 0x95, 0x00, 0x8e, 0x00, 0x88, 0x01, +0x82, 0x02, 0x7c, 0x03, 0x78, 0x05, 0x75, 0x06, 0x72, 0x07, 0x6f, 0x08, +0x6a, 0x09, 0x68, 0x0a, 0x66, 0x0b, 0x65, 0x0c, 0x63, 0x0d, 0x62, 0x0e, +0x61, 0x0f, 0x60, 0x11, 0x0a, 0x47, 0x0a, 0x45, 0x0c, 0x42, 0x0d, 0x42, +0x0e, 0x40, 0x10, 0x3d, 0x11, 0x3f, 0x13, 0x3e, 0x14, 0x3c, 0x15, 0x3b, +0x17, 0x3b, 0x17, 0x3c, 0x18, 0x3c, 0x19, 0x3c, 0x1a, 0x3b, 0x1c, 0x3b, +0x1c, 0x3a, 0x1d, 0x39, 0x1f, 0x3a, 0x1f, 0x3b, 0x5f, 0x25, 0x5c, 0x27, +0x5c, 0x27, 0x58, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x56, 0x2d, 0x53, 0x2e, +0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x52, 0x31, 0x4f, 0x31, 0x4f, 0x31, +0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x32, 0x4f, 0x34, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x5e, +0x00, 0x5b, 0x00, 0x57, 0x00, 0x52, 0x00, 0x4c, 0x00, 0x44, 0x00, 0x3d, +0x00, 0x35, 0x00, 0x2c, 0x00, 0x24, 0x00, 0x1c, 0x00, 0x14, 0x00, 0x0d, +0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x9e, 0x00, 0x9d, 0x00, 0x99, 0x00, 0x92, 0x00, 0x89, 0x00, 0x7e, 0x00, +0x72, 0x00, 0x66, 0x00, 0x58, 0x00, 0x4a, 0x00, 0x3d, 0x00, 0x2f, 0x00, +0x22, 0x00, 0x16, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0xb1, 0x00, 0xa7, 0x00, +0xa0, 0x00, 0x97, 0x00, 0x90, 0x00, 0x8a, 0x01, 0x85, 0x02, 0x7e, 0x02, +0x7a, 0x03, 0x77, 0x05, 0x74, 0x06, 0x72, 0x07, 0x6e, 0x08, 0x6a, 0x09, +0x68, 0x0a, 0x66, 0x0b, 0x65, 0x0c, 0x63, 0x0d, 0x63, 0x0e, 0x61, 0x0f, +0x0a, 0x47, 0x0a, 0x45, 0x0b, 0x42, 0x0d, 0x42, 0x0e, 0x40, 0x0f, 0x3e, +0x11, 0x3f, 0x12, 0x3f, 0x13, 0x3d, 0x15, 0x3c, 0x15, 0x3a, 0x17, 0x3c, +0x17, 0x3c, 0x19, 0x3c, 0x19, 0x3c, 0x1a, 0x3b, 0x1c, 0x3b, 0x1c, 0x3a, +0x1d, 0x39, 0x1f, 0x39, 0x5f, 0x25, 0x5c, 0x27, 0x5c, 0x27, 0x59, 0x2a, +0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2c, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, +0x53, 0x2e, 0x53, 0x2f, 0x51, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, +0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x00, 0x17, 0x00, 0x2f, +0x00, 0x4c, 0x00, 0x56, 0x00, 0x59, 0x00, 0x5b, 0x00, 0x5d, 0x00, 0x5d, +0x00, 0x5e, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x5f, +0x00, 0x5f, 0x00, 0x5f, 0x00, 0x6c, 0x00, 0x4c, 0x00, 0x5f, 0x00, 0x62, +0x00, 0x62, 0x00, 0x5f, 0x00, 0x5d, 0x00, 0x5d, 0x00, 0x5e, 0x00, 0x5e, +0x00, 0x5e, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x5f, 0x00, 0x5f, 0x00, 0x5f, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x14, 0x01, 0x29, +0x00, 0x49, 0x00, 0x54, 0x00, 0x59, 0x00, 0x5b, 0x00, 0x5c, 0x00, 0x5d, +0x00, 0x5d, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x5e, +0x00, 0x5f, 0x00, 0x5f, 0x31, 0x11, 0x03, 0x23, 0x00, 0x46, 0x00, 0x52, +0x00, 0x58, 0x00, 0x5a, 0x00, 0x5c, 0x00, 0x5d, 0x00, 0x5d, 0x00, 0x5e, +0x00, 0x5e, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x5f, +0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0xb1, 0x00, 0xa8, 0x00, 0xa1, 0x00, 0x99, 0x00, +0x91, 0x00, 0x8c, 0x00, 0x88, 0x01, 0x82, 0x02, 0x7c, 0x03, 0x79, 0x04, +0x76, 0x05, 0x74, 0x06, 0x71, 0x07, 0x6d, 0x08, 0x6a, 0x09, 0x68, 0x0a, +0x66, 0x0b, 0x65, 0x0c, 0x64, 0x0c, 0x63, 0x0e, 0x0a, 0x47, 0x0a, 0x45, +0x0b, 0x42, 0x0d, 0x42, 0x0e, 0x41, 0x0f, 0x3f, 0x11, 0x3e, 0x11, 0x3f, +0x13, 0x3e, 0x13, 0x3c, 0x15, 0x3c, 0x16, 0x3a, 0x17, 0x3c, 0x17, 0x3c, +0x19, 0x3c, 0x19, 0x3c, 0x1a, 0x3b, 0x1c, 0x3b, 0x1c, 0x3a, 0x1d, 0x39, +0x5f, 0x25, 0x5c, 0x27, 0x5c, 0x27, 0x5a, 0x29, 0x57, 0x2a, 0x57, 0x2a, +0x57, 0x2a, 0x55, 0x2d, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, +0x53, 0x2f, 0x51, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, +0x4f, 0x31, 0x4f, 0x31, 0x00, 0x00, 0x00, 0x07, 0x00, 0x2f, 0x00, 0x45, +0x00, 0x4f, 0x00, 0x55, 0x00, 0x58, 0x00, 0x59, 0x00, 0x5b, 0x00, 0x5c, +0x00, 0x5c, 0x00, 0x5d, 0x00, 0x5d, 0x00, 0x5d, 0x00, 0x5e, 0x00, 0x5e, +0x00, 0x4c, 0x00, 0x3b, 0x00, 0x48, 0x00, 0x55, 0x00, 0x58, 0x00, 0x57, +0x00, 0x58, 0x00, 0x59, 0x00, 0x5b, 0x00, 0x5c, 0x00, 0x5c, 0x00, 0x5d, +0x00, 0x5d, 0x00, 0x5d, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x57, 0x00, 0x16, 0x04, 0x00, 0x27, 0x00, 0x41, +0x00, 0x4d, 0x00, 0x53, 0x00, 0x56, 0x00, 0x59, 0x00, 0x5a, 0x00, 0x5b, +0x00, 0x5c, 0x00, 0x5c, 0x00, 0x5d, 0x00, 0x5d, 0x00, 0x5d, 0x00, 0x5e, +0x5f, 0x00, 0x20, 0x00, 0x00, 0x1f, 0x00, 0x3c, 0x00, 0x4a, 0x00, 0x51, +0x00, 0x55, 0x00, 0x58, 0x00, 0x59, 0x00, 0x5b, 0x00, 0x5b, 0x00, 0x5c, +0x00, 0x5d, 0x00, 0x5d, 0x00, 0x5d, 0x00, 0x5d, 0x41, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0xb1, 0x00, 0xa9, 0x00, 0xa2, 0x00, 0x9b, 0x00, 0x93, 0x00, 0x8e, 0x00, +0x89, 0x01, 0x84, 0x02, 0x7e, 0x02, 0x7a, 0x03, 0x78, 0x05, 0x75, 0x05, +0x73, 0x06, 0x71, 0x07, 0x6c, 0x08, 0x69, 0x09, 0x68, 0x0a, 0x66, 0x0b, +0x65, 0x0c, 0x64, 0x0c, 0x0a, 0x47, 0x0a, 0x46, 0x0b, 0x43, 0x0d, 0x42, +0x0e, 0x42, 0x0f, 0x40, 0x10, 0x3d, 0x11, 0x3f, 0x12, 0x3f, 0x13, 0x3d, +0x15, 0x3c, 0x15, 0x3b, 0x17, 0x3a, 0x17, 0x3c, 0x17, 0x3c, 0x19, 0x3c, +0x19, 0x3c, 0x1a, 0x3b, 0x1c, 0x3b, 0x1c, 0x3b, 0x5f, 0x25, 0x5c, 0x27, +0x5c, 0x27, 0x5b, 0x28, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2c, +0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x30, +0x50, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, +0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x22, 0x00, 0x36, 0x00, 0x42, +0x00, 0x4a, 0x00, 0x4f, 0x00, 0x53, 0x00, 0x55, 0x00, 0x57, 0x00, 0x58, +0x00, 0x59, 0x00, 0x5a, 0x00, 0x5b, 0x00, 0x5b, 0x00, 0x5f, 0x00, 0x48, +0x00, 0x1b, 0x00, 0x34, 0x00, 0x40, 0x00, 0x44, 0x00, 0x4a, 0x00, 0x4f, +0x00, 0x53, 0x00, 0x55, 0x00, 0x57, 0x00, 0x58, 0x00, 0x59, 0x00, 0x5a, +0x00, 0x5b, 0x00, 0x5b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x82, 0x00, 0x57, 0x00, 0x12, 0x01, 0x00, 0x17, 0x00, 0x2f, 0x00, 0x3e, +0x00, 0x47, 0x00, 0x4d, 0x00, 0x51, 0x00, 0x53, 0x00, 0x56, 0x00, 0x57, +0x00, 0x58, 0x00, 0x59, 0x00, 0x5a, 0x00, 0x5b, 0x85, 0x00, 0x5f, 0x00, +0x1f, 0x00, 0x00, 0x0d, 0x00, 0x28, 0x00, 0x39, 0x00, 0x43, 0x00, 0x4a, +0x00, 0x4e, 0x00, 0x52, 0x00, 0x54, 0x00, 0x56, 0x00, 0x57, 0x00, 0x59, +0x00, 0x59, 0x00, 0x5a, 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0xb2, 0x00, 0xa9, 0x00, +0xa3, 0x00, 0x9d, 0x00, 0x94, 0x00, 0x8f, 0x00, 0x8b, 0x01, 0x87, 0x02, +0x81, 0x02, 0x7c, 0x03, 0x79, 0x03, 0x77, 0x05, 0x75, 0x06, 0x72, 0x06, +0x70, 0x07, 0x6c, 0x08, 0x69, 0x09, 0x68, 0x0a, 0x66, 0x0b, 0x65, 0x0c, +0x0a, 0x47, 0x0a, 0x46, 0x0b, 0x43, 0x0d, 0x42, 0x0d, 0x42, 0x0e, 0x40, +0x0f, 0x3e, 0x11, 0x3e, 0x11, 0x3f, 0x13, 0x3f, 0x13, 0x3c, 0x15, 0x3c, +0x15, 0x3a, 0x17, 0x3b, 0x17, 0x3c, 0x18, 0x3c, 0x19, 0x3c, 0x19, 0x3c, +0x1a, 0x3b, 0x1c, 0x3b, 0x5f, 0x24, 0x5c, 0x27, 0x5c, 0x27, 0x5b, 0x28, +0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2b, 0x55, 0x2e, 0x53, 0x2e, +0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x52, 0x30, 0x50, 0x31, +0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x01, 0x00, 0x19, 0x00, 0x2b, 0x00, 0x38, 0x00, 0x40, +0x00, 0x47, 0x00, 0x4b, 0x00, 0x4f, 0x00, 0x51, 0x00, 0x53, 0x00, 0x55, +0x00, 0x56, 0x00, 0x57, 0x00, 0x62, 0x00, 0x55, 0x00, 0x34, 0x00, 0x0b, +0x00, 0x1f, 0x00, 0x2b, 0x00, 0x38, 0x00, 0x40, 0x00, 0x47, 0x00, 0x4b, +0x00, 0x4f, 0x00, 0x51, 0x00, 0x53, 0x00, 0x55, 0x00, 0x56, 0x00, 0x57, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x91, 0x00, 0x78, 0x00, +0x43, 0x00, 0x10, 0x00, 0x00, 0x0e, 0x00, 0x23, 0x00, 0x31, 0x00, 0x3b, +0x00, 0x42, 0x00, 0x48, 0x00, 0x4c, 0x00, 0x4f, 0x00, 0x51, 0x00, 0x53, +0x00, 0x55, 0x00, 0x56, 0x92, 0x00, 0x7c, 0x00, 0x4d, 0x00, 0x1f, 0x00, +0x00, 0x02, 0x00, 0x1a, 0x00, 0x2a, 0x00, 0x36, 0x00, 0x3e, 0x00, 0x45, +0x00, 0x49, 0x00, 0x4d, 0x00, 0x4f, 0x00, 0x52, 0x00, 0x53, 0x00, 0x55, +0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0xb2, 0x00, 0xaa, 0x00, 0xa4, 0x00, 0x9e, 0x00, +0x96, 0x00, 0x90, 0x00, 0x8c, 0x00, 0x88, 0x01, 0x84, 0x02, 0x7e, 0x02, +0x7b, 0x03, 0x78, 0x04, 0x76, 0x05, 0x74, 0x06, 0x72, 0x07, 0x6f, 0x07, +0x6b, 0x09, 0x69, 0x09, 0x68, 0x0a, 0x66, 0x0b, 0x0a, 0x47, 0x0a, 0x46, +0x0b, 0x44, 0x0d, 0x42, 0x0d, 0x42, 0x0e, 0x40, 0x0f, 0x3f, 0x10, 0x3d, +0x11, 0x3f, 0x12, 0x3f, 0x13, 0x3e, 0x14, 0x3c, 0x15, 0x3c, 0x16, 0x3a, +0x17, 0x3b, 0x17, 0x3c, 0x18, 0x3c, 0x19, 0x3c, 0x19, 0x3c, 0x1a, 0x3b, +0x5f, 0x24, 0x5c, 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x58, 0x2a, 0x57, 0x2a, +0x57, 0x2a, 0x57, 0x2a, 0x56, 0x2c, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, +0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x52, 0x30, 0x4f, 0x31, 0x4f, 0x31, +0x4f, 0x31, 0x4f, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x14, 0x00, 0x24, 0x00, 0x2f, 0x00, 0x38, 0x00, 0x3f, +0x00, 0x44, 0x00, 0x48, 0x00, 0x4c, 0x00, 0x4e, 0x00, 0x50, 0x00, 0x52, +0x00, 0x62, 0x00, 0x58, 0x00, 0x40, 0x00, 0x1f, 0x00, 0x01, 0x00, 0x14, +0x00, 0x24, 0x00, 0x2f, 0x00, 0x38, 0x00, 0x3f, 0x00, 0x44, 0x00, 0x48, +0x00, 0x4c, 0x00, 0x4e, 0x00, 0x50, 0x00, 0x52, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x96, 0x00, 0x87, 0x00, 0x61, 0x00, 0x36, 0x00, +0x10, 0x00, 0x02, 0x0a, 0x00, 0x1a, 0x00, 0x27, 0x00, 0x32, 0x00, 0x3a, +0x00, 0x40, 0x00, 0x44, 0x00, 0x48, 0x00, 0x4b, 0x00, 0x4e, 0x00, 0x50, +0x97, 0x00, 0x8a, 0x00, 0x68, 0x00, 0x42, 0x00, 0x1f, 0x00, 0x04, 0x00, +0x00, 0x10, 0x00, 0x1f, 0x00, 0x2b, 0x00, 0x34, 0x00, 0x3b, 0x00, 0x41, +0x00, 0x45, 0x00, 0x49, 0x00, 0x4b, 0x00, 0x4e, 0x28, 0x3c, 0x16, 0x41, +0x11, 0x43, 0x0f, 0x44, 0x0e, 0x45, 0x0d, 0x46, 0x0c, 0x46, 0x0c, 0x46, +0x0b, 0x47, 0x0b, 0x47, 0x0b, 0x47, 0x0b, 0x47, 0x0a, 0x47, 0x0a, 0x47, +0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, +0x6e, 0x1c, 0x3a, 0x29, 0x27, 0x31, 0x1e, 0x36, 0x19, 0x3a, 0x17, 0x3b, +0x14, 0x3d, 0x13, 0x3f, 0x11, 0x40, 0x11, 0x40, 0x10, 0x41, 0x0f, 0x42, +0x0f, 0x43, 0x0f, 0x43, 0x0e, 0x43, 0x0e, 0x44, 0x0d, 0x44, 0x0d, 0x44, +0x0c, 0x44, 0x0c, 0x44, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, +0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, +0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, +0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x3c, 0x32, 0x22, 0x38, +0x18, 0x3c, 0x14, 0x3f, 0x11, 0x40, 0x10, 0x41, 0x0f, 0x42, 0x0e, 0x43, +0x0e, 0x44, 0x0d, 0x44, 0x0d, 0x44, 0x0c, 0x44, 0x0c, 0x45, 0x0c, 0x45, +0x0c, 0x45, 0x0c, 0x45, 0x0b, 0x45, 0x0b, 0x45, 0x0b, 0x46, 0x0b, 0x46, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x10, 0x00, 0x1e, 0x00, 0x29, 0x00, 0x32, 0x00, 0x38, 0x00, 0x3e, +0x00, 0x42, 0x00, 0x46, 0x00, 0x49, 0x00, 0x4c, 0x00, 0x5f, 0x00, 0x57, +0x00, 0x44, 0x00, 0x2b, 0x00, 0x14, 0x00, 0x00, 0x00, 0x10, 0x00, 0x1e, +0x00, 0x29, 0x00, 0x32, 0x00, 0x38, 0x00, 0x3e, 0x00, 0x42, 0x00, 0x46, +0x00, 0x49, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x99, 0x00, 0x8f, 0x00, 0x74, 0x00, 0x51, 0x00, 0x2e, 0x00, 0x10, 0x00, +0x04, 0x08, 0x00, 0x13, 0x00, 0x20, 0x00, 0x2a, 0x00, 0x32, 0x00, 0x38, +0x00, 0x3e, 0x00, 0x42, 0x00, 0x45, 0x00, 0x48, 0x9a, 0x00, 0x91, 0x00, +0x79, 0x00, 0x5a, 0x00, 0x3b, 0x00, 0x1f, 0x00, 0x09, 0x00, 0x00, 0x08, +0x00, 0x17, 0x00, 0x22, 0x00, 0x2c, 0x00, 0x33, 0x00, 0x39, 0x00, 0x3e, +0x00, 0x42, 0x00, 0x45, 0x30, 0x38, 0x20, 0x3a, 0x18, 0x3d, 0x14, 0x3e, +0x12, 0x40, 0x10, 0x41, 0x0f, 0x42, 0x0e, 0x42, 0x0e, 0x42, 0x0d, 0x43, +0x0d, 0x43, 0x0d, 0x44, 0x0d, 0x44, 0x0c, 0x45, 0x0c, 0x45, 0x0b, 0x45, +0x0b, 0x46, 0x0b, 0x46, 0x0b, 0x46, 0x0b, 0x47, 0x8a, 0x03, 0x59, 0x0f, +0x40, 0x18, 0x32, 0x1f, 0x2a, 0x24, 0x24, 0x28, 0x20, 0x2c, 0x1c, 0x2f, +0x1b, 0x31, 0x18, 0x33, 0x17, 0x34, 0x16, 0x36, 0x15, 0x37, 0x14, 0x38, +0x13, 0x39, 0x12, 0x3a, 0x12, 0x3a, 0x12, 0x3b, 0x11, 0x3c, 0x10, 0x3c, +0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, +0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, +0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, +0x0a, 0x47, 0x0a, 0x47, 0x4a, 0x25, 0x31, 0x2b, 0x25, 0x30, 0x1e, 0x33, +0x1a, 0x36, 0x17, 0x38, 0x15, 0x39, 0x13, 0x3b, 0x12, 0x3c, 0x11, 0x3d, +0x10, 0x3e, 0x10, 0x3f, 0x0f, 0x3f, 0x0f, 0x40, 0x0e, 0x40, 0x0e, 0x40, +0x0e, 0x41, 0x0e, 0x41, 0x0d, 0x42, 0x0d, 0x42, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, +0x00, 0x1a, 0x00, 0x24, 0x00, 0x2c, 0x00, 0x33, 0x00, 0x39, 0x00, 0x3d, +0x00, 0x41, 0x00, 0x44, 0x00, 0x5d, 0x00, 0x58, 0x00, 0x4a, 0x00, 0x38, +0x00, 0x24, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x1a, 0x00, 0x24, +0x00, 0x2c, 0x00, 0x33, 0x00, 0x39, 0x00, 0x3d, 0x00, 0x41, 0x00, 0x44, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9b, 0x00, 0x94, 0x00, +0x7f, 0x00, 0x64, 0x00, 0x46, 0x00, 0x29, 0x00, 0x10, 0x00, 0x06, 0x07, +0x00, 0x0e, 0x00, 0x1a, 0x00, 0x24, 0x00, 0x2c, 0x00, 0x32, 0x00, 0x38, +0x00, 0x3c, 0x00, 0x40, 0x9b, 0x00, 0x95, 0x00, 0x83, 0x00, 0x6a, 0x00, +0x4f, 0x00, 0x36, 0x00, 0x1f, 0x00, 0x0c, 0x00, 0x00, 0x03, 0x00, 0x10, +0x00, 0x1b, 0x00, 0x24, 0x00, 0x2c, 0x00, 0x32, 0x00, 0x37, 0x00, 0x3c, +0x34, 0x38, 0x25, 0x39, 0x1e, 0x3b, 0x19, 0x3c, 0x16, 0x3d, 0x14, 0x3d, +0x13, 0x3f, 0x11, 0x40, 0x10, 0x41, 0x0f, 0x41, 0x0f, 0x42, 0x0e, 0x42, +0x0e, 0x42, 0x0d, 0x42, 0x0d, 0x42, 0x0d, 0x42, 0x0d, 0x43, 0x0d, 0x43, +0x0d, 0x44, 0x0d, 0x44, 0x97, 0x00, 0x6c, 0x06, 0x52, 0x0d, 0x43, 0x12, +0x38, 0x18, 0x30, 0x1c, 0x2a, 0x20, 0x27, 0x23, 0x23, 0x26, 0x20, 0x28, +0x1e, 0x2a, 0x1c, 0x2c, 0x1b, 0x2e, 0x19, 0x2f, 0x18, 0x31, 0x17, 0x32, +0x16, 0x33, 0x16, 0x34, 0x16, 0x35, 0x15, 0x35, 0x0a, 0x47, 0x0a, 0x47, +0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, +0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, +0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, +0x50, 0x24, 0x3b, 0x27, 0x2e, 0x2a, 0x26, 0x2d, 0x21, 0x2f, 0x1d, 0x32, +0x1a, 0x33, 0x18, 0x35, 0x16, 0x36, 0x15, 0x38, 0x14, 0x39, 0x13, 0x3a, +0x12, 0x3a, 0x11, 0x3b, 0x11, 0x3c, 0x11, 0x3c, 0x10, 0x3d, 0x10, 0x3e, +0x10, 0x3e, 0x0f, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x17, +0x00, 0x20, 0x00, 0x28, 0x00, 0x2e, 0x00, 0x34, 0x00, 0x39, 0x00, 0x3d, +0x00, 0x5d, 0x00, 0x59, 0x00, 0x4f, 0x00, 0x40, 0x00, 0x2f, 0x00, 0x1e, +0x00, 0x0e, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x17, 0x00, 0x20, 0x00, 0x28, +0x00, 0x2e, 0x00, 0x34, 0x00, 0x39, 0x00, 0x3d, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x9c, 0x00, 0x96, 0x00, 0x87, 0x00, 0x71, 0x00, +0x57, 0x00, 0x3d, 0x00, 0x25, 0x00, 0x10, 0x00, 0x07, 0x06, 0x00, 0x0b, +0x00, 0x15, 0x00, 0x1f, 0x00, 0x26, 0x00, 0x2d, 0x00, 0x32, 0x00, 0x37, +0x9c, 0x00, 0x97, 0x00, 0x8a, 0x00, 0x76, 0x00, 0x5f, 0x00, 0x48, 0x00, +0x33, 0x00, 0x1f, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x15, +0x00, 0x1e, 0x00, 0x25, 0x00, 0x2c, 0x00, 0x31, 0x36, 0x39, 0x2a, 0x39, +0x22, 0x39, 0x1d, 0x3a, 0x1a, 0x3b, 0x17, 0x3d, 0x15, 0x3d, 0x13, 0x3d, +0x13, 0x3e, 0x12, 0x3f, 0x11, 0x40, 0x10, 0x41, 0x0f, 0x41, 0x0f, 0x42, +0x0e, 0x41, 0x0e, 0x42, 0x0e, 0x42, 0x0e, 0x41, 0x0e, 0x42, 0x0d, 0x42, +0x9e, 0x00, 0x79, 0x02, 0x61, 0x07, 0x50, 0x0b, 0x44, 0x10, 0x3b, 0x14, +0x34, 0x18, 0x2f, 0x1b, 0x2b, 0x1e, 0x28, 0x20, 0x25, 0x23, 0x23, 0x25, +0x21, 0x27, 0x1f, 0x28, 0x1d, 0x2a, 0x1c, 0x2b, 0x1b, 0x2c, 0x19, 0x2e, +0x19, 0x2f, 0x19, 0x30, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, +0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, +0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, +0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x54, 0x23, 0x42, 0x25, +0x35, 0x27, 0x2d, 0x29, 0x27, 0x2c, 0x22, 0x2e, 0x1f, 0x2f, 0x1c, 0x31, +0x1a, 0x33, 0x19, 0x34, 0x17, 0x35, 0x16, 0x36, 0x15, 0x37, 0x14, 0x38, +0x13, 0x38, 0x13, 0x39, 0x12, 0x3a, 0x11, 0x3a, 0x11, 0x3b, 0x11, 0x3c, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x14, 0x00, 0x1d, +0x00, 0x24, 0x00, 0x2a, 0x00, 0x30, 0x00, 0x35, 0x00, 0x5e, 0x00, 0x5b, +0x00, 0x53, 0x00, 0x47, 0x00, 0x38, 0x00, 0x29, 0x00, 0x1a, 0x00, 0x0c, +0x00, 0x00, 0x00, 0x0b, 0x00, 0x14, 0x00, 0x1d, 0x00, 0x24, 0x00, 0x2a, +0x00, 0x30, 0x00, 0x35, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x9d, 0x00, 0x98, 0x00, 0x8c, 0x00, 0x7a, 0x00, 0x64, 0x00, 0x4e, 0x00, +0x37, 0x00, 0x22, 0x00, 0x10, 0x00, 0x08, 0x05, 0x02, 0x0a, 0x00, 0x12, +0x00, 0x1a, 0x00, 0x22, 0x00, 0x28, 0x00, 0x2d, 0x9d, 0x00, 0x99, 0x00, +0x8e, 0x00, 0x7e, 0x00, 0x6b, 0x00, 0x57, 0x00, 0x43, 0x00, 0x30, 0x00, +0x1f, 0x00, 0x11, 0x00, 0x04, 0x00, 0x00, 0x07, 0x00, 0x10, 0x00, 0x19, +0x00, 0x20, 0x00, 0x26, 0x38, 0x39, 0x2d, 0x39, 0x25, 0x39, 0x20, 0x3a, +0x1d, 0x3b, 0x1a, 0x3b, 0x18, 0x3c, 0x16, 0x3d, 0x14, 0x3d, 0x13, 0x3d, +0x13, 0x3d, 0x12, 0x3e, 0x11, 0x3f, 0x11, 0x40, 0x10, 0x40, 0x0f, 0x41, +0x0f, 0x42, 0x0f, 0x42, 0x0e, 0x42, 0x0e, 0x42, 0xa2, 0x00, 0x84, 0x00, +0x6c, 0x04, 0x5a, 0x07, 0x4e, 0x0b, 0x45, 0x0f, 0x3e, 0x12, 0x38, 0x15, +0x32, 0x18, 0x2f, 0x1a, 0x2c, 0x1d, 0x29, 0x1f, 0x26, 0x21, 0x24, 0x22, +0x22, 0x24, 0x21, 0x26, 0x1f, 0x27, 0x1e, 0x28, 0x1d, 0x2a, 0x1c, 0x2b, +0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, +0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, +0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, +0x0a, 0x47, 0x0a, 0x47, 0x56, 0x23, 0x47, 0x24, 0x3b, 0x25, 0x32, 0x27, +0x2c, 0x29, 0x27, 0x2b, 0x24, 0x2d, 0x21, 0x2e, 0x1e, 0x30, 0x1c, 0x31, +0x1b, 0x32, 0x19, 0x33, 0x18, 0x34, 0x17, 0x35, 0x16, 0x36, 0x15, 0x37, +0x14, 0x37, 0x14, 0x38, 0x13, 0x38, 0x13, 0x39, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x12, 0x00, 0x1a, 0x00, 0x21, +0x00, 0x27, 0x00, 0x2c, 0x00, 0x5e, 0x00, 0x5c, 0x00, 0x55, 0x00, 0x4b, +0x00, 0x3f, 0x00, 0x32, 0x00, 0x24, 0x00, 0x17, 0x00, 0x0b, 0x00, 0x00, +0x00, 0x09, 0x00, 0x12, 0x00, 0x1a, 0x00, 0x21, 0x00, 0x27, 0x00, 0x2c, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9d, 0x00, 0x9a, 0x00, +0x90, 0x00, 0x81, 0x00, 0x6f, 0x00, 0x5b, 0x00, 0x46, 0x00, 0x32, 0x00, +0x20, 0x00, 0x10, 0x00, 0x09, 0x04, 0x03, 0x09, 0x00, 0x0f, 0x00, 0x17, +0x00, 0x1e, 0x00, 0x24, 0x9d, 0x00, 0x9a, 0x00, 0x92, 0x00, 0x84, 0x00, +0x74, 0x00, 0x62, 0x00, 0x50, 0x00, 0x3f, 0x00, 0x2e, 0x00, 0x1f, 0x00, +0x12, 0x00, 0x06, 0x00, 0x00, 0x03, 0x00, 0x0c, 0x00, 0x14, 0x00, 0x1b, +0x39, 0x3a, 0x2f, 0x39, 0x28, 0x39, 0x23, 0x39, 0x20, 0x3a, 0x1c, 0x3b, +0x1a, 0x3a, 0x18, 0x3b, 0x17, 0x3c, 0x15, 0x3e, 0x14, 0x3e, 0x13, 0x3d, +0x13, 0x3d, 0x12, 0x3d, 0x11, 0x3e, 0x11, 0x3f, 0x11, 0x40, 0x10, 0x40, +0x0f, 0x40, 0x0f, 0x41, 0xa6, 0x00, 0x8b, 0x00, 0x75, 0x02, 0x63, 0x05, +0x57, 0x07, 0x4d, 0x0b, 0x45, 0x0e, 0x3e, 0x11, 0x39, 0x13, 0x35, 0x16, +0x32, 0x18, 0x2e, 0x1a, 0x2c, 0x1c, 0x29, 0x1d, 0x27, 0x1f, 0x26, 0x22, +0x24, 0x22, 0x21, 0x23, 0x21, 0x25, 0x20, 0x26, 0x0a, 0x47, 0x0a, 0x47, +0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, +0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, +0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, +0x58, 0x23, 0x4a, 0x23, 0x3f, 0x24, 0x36, 0x26, 0x30, 0x27, 0x2b, 0x29, +0x27, 0x2a, 0x24, 0x2c, 0x22, 0x2d, 0x20, 0x2e, 0x1e, 0x30, 0x1c, 0x30, +0x1b, 0x32, 0x1a, 0x32, 0x18, 0x33, 0x18, 0x34, 0x17, 0x34, 0x16, 0x35, +0x16, 0x36, 0x15, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x09, 0x00, 0x11, 0x00, 0x18, 0x00, 0x1e, 0x00, 0x24, +0x00, 0x5e, 0x00, 0x5c, 0x00, 0x57, 0x00, 0x4f, 0x00, 0x44, 0x00, 0x38, +0x00, 0x2c, 0x00, 0x20, 0x00, 0x14, 0x00, 0x09, 0x00, 0x00, 0x00, 0x09, +0x00, 0x11, 0x00, 0x18, 0x00, 0x1e, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x9d, 0x00, 0x9b, 0x00, 0x93, 0x00, 0x86, 0x00, +0x76, 0x00, 0x65, 0x00, 0x52, 0x00, 0x40, 0x00, 0x2f, 0x00, 0x1e, 0x00, +0x10, 0x00, 0x09, 0x04, 0x04, 0x08, 0x00, 0x0c, 0x00, 0x14, 0x00, 0x1a, +0x9e, 0x00, 0x9b, 0x00, 0x94, 0x00, 0x89, 0x00, 0x7b, 0x00, 0x6b, 0x00, +0x5b, 0x00, 0x4b, 0x00, 0x3b, 0x00, 0x2d, 0x00, 0x1f, 0x00, 0x13, 0x00, +0x08, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x11, 0x3a, 0x3a, 0x31, 0x3a, +0x2a, 0x39, 0x25, 0x3a, 0x22, 0x39, 0x1e, 0x3b, 0x1c, 0x3b, 0x1a, 0x3a, +0x19, 0x3a, 0x17, 0x3c, 0x16, 0x3c, 0x15, 0x3e, 0x14, 0x3e, 0x13, 0x3d, +0x13, 0x3d, 0x12, 0x3d, 0x11, 0x3d, 0x11, 0x3e, 0x11, 0x3f, 0x10, 0x40, +0xa8, 0x00, 0x90, 0x00, 0x7c, 0x01, 0x6b, 0x02, 0x5f, 0x05, 0x55, 0x07, +0x4c, 0x0a, 0x45, 0x0d, 0x40, 0x0f, 0x3c, 0x12, 0x37, 0x14, 0x34, 0x16, +0x31, 0x18, 0x2e, 0x19, 0x2b, 0x1b, 0x2a, 0x1d, 0x28, 0x1e, 0x26, 0x20, +0x25, 0x22, 0x23, 0x22, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, +0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, +0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, +0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x59, 0x23, 0x4d, 0x23, +0x43, 0x24, 0x3b, 0x25, 0x34, 0x26, 0x2f, 0x27, 0x2b, 0x29, 0x28, 0x2a, +0x25, 0x2b, 0x23, 0x2d, 0x21, 0x2e, 0x1f, 0x2e, 0x1d, 0x30, 0x1c, 0x30, +0x1b, 0x31, 0x1a, 0x32, 0x19, 0x32, 0x18, 0x33, 0x17, 0x34, 0x16, 0x34, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x08, 0x00, 0x0f, 0x00, 0x16, 0x00, 0x1c, 0x00, 0x5e, 0x00, 0x5d, +0x00, 0x58, 0x00, 0x51, 0x00, 0x48, 0x00, 0x3e, 0x00, 0x33, 0x00, 0x28, +0x00, 0x1d, 0x00, 0x12, 0x00, 0x09, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0f, +0x00, 0x16, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x9e, 0x00, 0x9b, 0x00, 0x95, 0x00, 0x8a, 0x00, 0x7d, 0x00, 0x6d, 0x00, +0x5d, 0x00, 0x4c, 0x00, 0x3b, 0x00, 0x2c, 0x00, 0x1d, 0x00, 0x10, 0x00, +0x0a, 0x04, 0x05, 0x07, 0x00, 0x0b, 0x00, 0x11, 0x9e, 0x00, 0x9c, 0x00, +0x96, 0x00, 0x8c, 0x00, 0x80, 0x00, 0x73, 0x00, 0x64, 0x00, 0x55, 0x00, +0x46, 0x00, 0x38, 0x00, 0x2b, 0x00, 0x1f, 0x00, 0x14, 0x00, 0x0a, 0x00, +0x01, 0x00, 0x00, 0x06, 0x3a, 0x3b, 0x32, 0x3a, 0x2c, 0x39, 0x27, 0x3a, +0x23, 0x39, 0x21, 0x39, 0x1e, 0x3b, 0x1c, 0x3c, 0x1a, 0x3a, 0x19, 0x3a, +0x17, 0x3b, 0x17, 0x3c, 0x15, 0x3d, 0x15, 0x3e, 0x14, 0x3e, 0x13, 0x3d, +0x13, 0x3d, 0x13, 0x3d, 0x11, 0x3d, 0x11, 0x3e, 0xaa, 0x00, 0x94, 0x00, +0x82, 0x00, 0x72, 0x01, 0x65, 0x04, 0x5b, 0x05, 0x53, 0x07, 0x4b, 0x0a, +0x45, 0x0c, 0x41, 0x0f, 0x3d, 0x11, 0x39, 0x12, 0x36, 0x15, 0x33, 0x16, +0x30, 0x18, 0x2e, 0x19, 0x2b, 0x1a, 0x2b, 0x1d, 0x29, 0x1d, 0x26, 0x1e, +0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, +0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, +0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, +0x0a, 0x47, 0x0a, 0x47, 0x5a, 0x23, 0x4f, 0x23, 0x46, 0x24, 0x3e, 0x24, +0x37, 0x25, 0x32, 0x26, 0x2e, 0x27, 0x2b, 0x28, 0x28, 0x2a, 0x25, 0x2b, +0x23, 0x2c, 0x21, 0x2d, 0x20, 0x2e, 0x1e, 0x2e, 0x1d, 0x30, 0x1c, 0x30, +0x1b, 0x31, 0x1a, 0x32, 0x19, 0x32, 0x18, 0x33, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, +0x00, 0x0e, 0x00, 0x14, 0x00, 0x5e, 0x00, 0x5d, 0x00, 0x59, 0x00, 0x53, +0x00, 0x4c, 0x00, 0x42, 0x00, 0x39, 0x00, 0x2e, 0x00, 0x24, 0x00, 0x1a, +0x00, 0x11, 0x00, 0x08, 0x00, 0x00, 0x00, 0x07, 0x00, 0x0e, 0x00, 0x14, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x9c, 0x00, +0x96, 0x00, 0x8d, 0x00, 0x81, 0x00, 0x74, 0x00, 0x65, 0x00, 0x56, 0x00, +0x46, 0x00, 0x37, 0x00, 0x29, 0x00, 0x1c, 0x00, 0x10, 0x00, 0x0a, 0x03, +0x06, 0x07, 0x01, 0x0a, 0x9e, 0x00, 0x9c, 0x00, 0x97, 0x00, 0x8f, 0x00, +0x85, 0x00, 0x79, 0x00, 0x6b, 0x00, 0x5e, 0x00, 0x50, 0x00, 0x43, 0x00, +0x36, 0x00, 0x2a, 0x00, 0x1f, 0x00, 0x15, 0x00, 0x0c, 0x00, 0x03, 0x00, +0x3b, 0x3b, 0x33, 0x3b, 0x2d, 0x39, 0x29, 0x39, 0x25, 0x3a, 0x22, 0x39, +0x20, 0x39, 0x1e, 0x3b, 0x1c, 0x3c, 0x1a, 0x3a, 0x19, 0x3a, 0x18, 0x3a, +0x17, 0x3c, 0x16, 0x3c, 0x15, 0x3d, 0x15, 0x3e, 0x13, 0x3f, 0x13, 0x3d, +0x13, 0x3d, 0x13, 0x3d, 0xaa, 0x00, 0x98, 0x00, 0x87, 0x00, 0x78, 0x01, +0x6b, 0x02, 0x61, 0x04, 0x58, 0x06, 0x51, 0x08, 0x4b, 0x0a, 0x46, 0x0c, +0x42, 0x0e, 0x3e, 0x0f, 0x3a, 0x12, 0x37, 0x12, 0x35, 0x16, 0x32, 0x16, +0x30, 0x18, 0x2e, 0x19, 0x2b, 0x1a, 0x2b, 0x1c, 0x0a, 0x47, 0x0a, 0x47, +0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, +0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, +0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, +0x5a, 0x23, 0x51, 0x23, 0x48, 0x23, 0x41, 0x24, 0x3a, 0x25, 0x35, 0x25, +0x31, 0x26, 0x2e, 0x27, 0x2a, 0x28, 0x28, 0x2a, 0x26, 0x2b, 0x24, 0x2b, +0x22, 0x2d, 0x21, 0x2d, 0x1f, 0x2e, 0x1e, 0x2e, 0x1d, 0x30, 0x1c, 0x30, +0x1b, 0x30, 0x1a, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x0d, +0x00, 0x5f, 0x00, 0x5d, 0x00, 0x5a, 0x00, 0x55, 0x00, 0x4e, 0x00, 0x46, +0x00, 0x3d, 0x00, 0x34, 0x00, 0x2a, 0x00, 0x21, 0x00, 0x18, 0x00, 0x0f, +0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x9c, 0x00, 0x97, 0x00, 0x90, 0x00, +0x85, 0x00, 0x79, 0x00, 0x6c, 0x00, 0x5e, 0x00, 0x50, 0x00, 0x42, 0x00, +0x34, 0x00, 0x27, 0x00, 0x1b, 0x00, 0x0f, 0x00, 0x0b, 0x03, 0x06, 0x06, +0x9e, 0x00, 0x9d, 0x00, 0x98, 0x00, 0x91, 0x00, 0x88, 0x00, 0x7e, 0x00, +0x72, 0x00, 0x65, 0x00, 0x59, 0x00, 0x4c, 0x00, 0x40, 0x00, 0x34, 0x00, +0x2a, 0x00, 0x1f, 0x00, 0x16, 0x00, 0x0d, 0x00, 0x3b, 0x3c, 0x34, 0x3a, +0x2f, 0x3a, 0x2a, 0x39, 0x26, 0x3a, 0x23, 0x3a, 0x21, 0x39, 0x1f, 0x3a, +0x1d, 0x3b, 0x1c, 0x3c, 0x1a, 0x3b, 0x19, 0x3a, 0x18, 0x3a, 0x17, 0x3b, +0x17, 0x3c, 0x15, 0x3c, 0x15, 0x3d, 0x15, 0x3f, 0x13, 0x3f, 0x13, 0x3e, +0xac, 0x00, 0x9b, 0x00, 0x8b, 0x00, 0x7c, 0x00, 0x71, 0x01, 0x67, 0x03, +0x5e, 0x05, 0x57, 0x07, 0x51, 0x08, 0x4b, 0x0a, 0x46, 0x0c, 0x42, 0x0d, +0x3f, 0x0f, 0x3b, 0x11, 0x39, 0x12, 0x35, 0x14, 0x34, 0x16, 0x31, 0x16, +0x30, 0x18, 0x2e, 0x19, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, +0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, +0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, +0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x5b, 0x23, 0x52, 0x23, +0x4a, 0x23, 0x43, 0x24, 0x3d, 0x24, 0x38, 0x25, 0x34, 0x26, 0x30, 0x27, +0x2d, 0x27, 0x2a, 0x28, 0x28, 0x2a, 0x26, 0x2a, 0x24, 0x2b, 0x22, 0x2c, +0x21, 0x2d, 0x20, 0x2d, 0x1f, 0x2e, 0x1d, 0x2e, 0x1d, 0x30, 0x1c, 0x30, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x5f, 0x00, 0x5e, +0x00, 0x5b, 0x00, 0x56, 0x00, 0x50, 0x00, 0x49, 0x00, 0x41, 0x00, 0x39, +0x00, 0x30, 0x00, 0x27, 0x00, 0x1e, 0x00, 0x16, 0x00, 0x0e, 0x00, 0x07, +0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x9e, 0x00, 0x9d, 0x00, 0x98, 0x00, 0x92, 0x00, 0x89, 0x00, 0x7e, 0x00, +0x72, 0x00, 0x65, 0x00, 0x58, 0x00, 0x4b, 0x00, 0x3e, 0x00, 0x31, 0x00, +0x25, 0x00, 0x1a, 0x00, 0x0f, 0x00, 0x0b, 0x03, 0x9e, 0x00, 0x9d, 0x00, +0x99, 0x00, 0x93, 0x00, 0x8b, 0x00, 0x82, 0x00, 0x77, 0x00, 0x6c, 0x00, +0x60, 0x00, 0x54, 0x00, 0x49, 0x00, 0x3d, 0x00, 0x33, 0x00, 0x29, 0x00, +0x1f, 0x00, 0x17, 0x00, 0x3b, 0x3c, 0x35, 0x3a, 0x30, 0x3b, 0x2c, 0x39, +0x28, 0x3a, 0x25, 0x3b, 0x22, 0x39, 0x21, 0x39, 0x1f, 0x3a, 0x1d, 0x3b, +0x1c, 0x3c, 0x1a, 0x3b, 0x19, 0x3a, 0x19, 0x3a, 0x17, 0x3a, 0x17, 0x3c, +0x16, 0x3c, 0x15, 0x3c, 0x15, 0x3e, 0x14, 0x3f, 0xad, 0x00, 0x9d, 0x00, +0x8e, 0x00, 0x81, 0x00, 0x76, 0x01, 0x6b, 0x02, 0x63, 0x04, 0x5c, 0x05, +0x56, 0x07, 0x50, 0x08, 0x4b, 0x0a, 0x47, 0x0c, 0x43, 0x0c, 0x40, 0x0f, +0x3c, 0x0f, 0x3a, 0x12, 0x37, 0x12, 0x35, 0x14, 0x33, 0x16, 0x30, 0x16, +0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, +0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, +0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, +0x0a, 0x47, 0x0a, 0x47, 0x5b, 0x23, 0x53, 0x23, 0x4c, 0x23, 0x45, 0x23, +0x40, 0x24, 0x3b, 0x25, 0x36, 0x25, 0x33, 0x26, 0x30, 0x27, 0x2d, 0x28, +0x2a, 0x28, 0x28, 0x2a, 0x26, 0x2a, 0x25, 0x2b, 0x23, 0x2b, 0x22, 0x2d, +0x20, 0x2d, 0x20, 0x2e, 0x1e, 0x2e, 0x1d, 0x2e, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x5e, 0x00, 0x5b, 0x00, 0x57, +0x00, 0x52, 0x00, 0x4c, 0x00, 0x44, 0x00, 0x3d, 0x00, 0x35, 0x00, 0x2c, +0x00, 0x24, 0x00, 0x1c, 0x00, 0x14, 0x00, 0x0d, 0x00, 0x06, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x9d, 0x00, +0x99, 0x00, 0x93, 0x00, 0x8b, 0x00, 0x82, 0x00, 0x77, 0x00, 0x6b, 0x00, +0x5f, 0x00, 0x53, 0x00, 0x46, 0x00, 0x3a, 0x00, 0x2f, 0x00, 0x24, 0x00, +0x19, 0x00, 0x0f, 0x00, 0x9e, 0x00, 0x9d, 0x00, 0x9a, 0x00, 0x95, 0x00, +0x8d, 0x00, 0x85, 0x00, 0x7b, 0x00, 0x71, 0x00, 0x66, 0x00, 0x5b, 0x00, +0x50, 0x00, 0x46, 0x00, 0x3b, 0x00, 0x31, 0x00, 0x28, 0x00, 0x1f, 0x00, +0x3c, 0x3d, 0x36, 0x3a, 0x31, 0x3b, 0x2c, 0x3a, 0x29, 0x39, 0x26, 0x3a, +0x24, 0x3b, 0x21, 0x39, 0x20, 0x39, 0x1f, 0x3a, 0x1d, 0x3b, 0x1c, 0x3c, +0x1a, 0x3c, 0x19, 0x3a, 0x19, 0x3a, 0x17, 0x3a, 0x17, 0x3b, 0x17, 0x3c, +0x15, 0x3c, 0x15, 0x3c, 0xad, 0x00, 0x9f, 0x00, 0x91, 0x00, 0x85, 0x00, +0x79, 0x00, 0x6f, 0x01, 0x67, 0x02, 0x60, 0x04, 0x59, 0x05, 0x54, 0x07, +0x4f, 0x08, 0x4b, 0x0a, 0x47, 0x0c, 0x43, 0x0c, 0x41, 0x0f, 0x3d, 0x0f, +0x3b, 0x11, 0x38, 0x12, 0x35, 0x12, 0x35, 0x15, 0x0a, 0x47, 0x0a, 0x47, +0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, +0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, +0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, +0x5b, 0x23, 0x54, 0x23, 0x4e, 0x23, 0x47, 0x23, 0x42, 0x24, 0x3c, 0x24, +0x38, 0x25, 0x35, 0x25, 0x32, 0x26, 0x2f, 0x27, 0x2d, 0x28, 0x2a, 0x28, +0x28, 0x2a, 0x26, 0x2a, 0x25, 0x2b, 0x23, 0x2b, 0x22, 0x2c, 0x21, 0x2d, +0x20, 0x2d, 0x20, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x3d, 0x36, 0x3a, +0x32, 0x3b, 0x2d, 0x3b, 0x2b, 0x39, 0x28, 0x3a, 0x25, 0x3a, 0x23, 0x3a, +0x21, 0x39, 0x1f, 0x39, 0x1f, 0x3b, 0x1c, 0x3b, 0x1c, 0x3c, 0x1a, 0x3c, +0x19, 0x3a, 0x19, 0x3a, 0x18, 0x3a, 0x17, 0x3a, 0x17, 0x3c, 0x16, 0x3c, +0xad, 0x00, 0xa0, 0x00, 0x94, 0x00, 0x88, 0x00, 0x7e, 0x00, 0x74, 0x01, +0x6c, 0x02, 0x65, 0x03, 0x5e, 0x04, 0x58, 0x05, 0x53, 0x07, 0x4f, 0x08, +0x4b, 0x0a, 0x47, 0x0b, 0x44, 0x0c, 0x41, 0x0e, 0x3e, 0x0f, 0x3b, 0x0f, +0x3a, 0x12, 0x37, 0x12, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, +0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, +0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, +0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x5c, 0x23, 0x55, 0x23, +0x4f, 0x23, 0x49, 0x23, 0x44, 0x24, 0x3f, 0x24, 0x3b, 0x25, 0x37, 0x25, +0x34, 0x26, 0x31, 0x26, 0x2e, 0x27, 0x2c, 0x28, 0x2a, 0x28, 0x28, 0x29, +0x27, 0x2a, 0x25, 0x2b, 0x24, 0x2b, 0x22, 0x2b, 0x22, 0x2d, 0x20, 0x2d, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x3c, 0x3e, 0x37, 0x3b, 0x33, 0x3b, 0x2f, 0x3b, +0x2b, 0x39, 0x29, 0x39, 0x26, 0x3a, 0x24, 0x3b, 0x22, 0x3a, 0x21, 0x39, +0x1f, 0x39, 0x1e, 0x3b, 0x1c, 0x3b, 0x1c, 0x3c, 0x1a, 0x3c, 0x19, 0x3b, +0x19, 0x3a, 0x18, 0x3a, 0x17, 0x3a, 0x17, 0x3b, 0xae, 0x00, 0xa2, 0x00, +0x97, 0x00, 0x8b, 0x00, 0x80, 0x00, 0x77, 0x00, 0x6f, 0x01, 0x67, 0x02, +0x61, 0x04, 0x5c, 0x05, 0x57, 0x05, 0x52, 0x07, 0x4e, 0x08, 0x4b, 0x0a, +0x47, 0x0b, 0x44, 0x0c, 0x41, 0x0d, 0x3f, 0x0f, 0x3c, 0x0f, 0x3b, 0x11, +0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, +0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, +0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, +0x0a, 0x47, 0x0a, 0x47, 0x5c, 0x23, 0x56, 0x23, 0x50, 0x23, 0x4a, 0x23, +0x45, 0x23, 0x40, 0x24, 0x3c, 0x24, 0x39, 0x25, 0x35, 0x25, 0x33, 0x26, +0x30, 0x26, 0x2e, 0x27, 0x2c, 0x28, 0x2a, 0x28, 0x28, 0x29, 0x27, 0x2a, +0x25, 0x2a, 0x24, 0x2b, 0x23, 0x2b, 0x22, 0x2c, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x3c, 0x3e, 0x37, 0x3b, 0x33, 0x3a, 0x2f, 0x3b, 0x2c, 0x3a, 0x2a, 0x39, +0x27, 0x3a, 0x25, 0x3a, 0x23, 0x3b, 0x21, 0x39, 0x20, 0x39, 0x1f, 0x39, +0x1e, 0x3b, 0x1c, 0x3b, 0x1c, 0x3c, 0x1a, 0x3c, 0x19, 0x3b, 0x19, 0x3a, +0x19, 0x3a, 0x17, 0x3a, 0xaf, 0x00, 0xa3, 0x00, 0x98, 0x00, 0x8e, 0x00, +0x84, 0x00, 0x7a, 0x00, 0x72, 0x01, 0x6c, 0x02, 0x65, 0x02, 0x5f, 0x04, +0x5a, 0x05, 0x56, 0x05, 0x52, 0x07, 0x4e, 0x09, 0x4a, 0x0a, 0x47, 0x0b, +0x45, 0x0c, 0x41, 0x0c, 0x40, 0x0f, 0x3d, 0x0f, 0x0a, 0x47, 0x0a, 0x47, +0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, +0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, +0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, +0x5c, 0x23, 0x56, 0x23, 0x51, 0x23, 0x4c, 0x23, 0x47, 0x23, 0x42, 0x24, +0x3e, 0x24, 0x3b, 0x25, 0x37, 0x25, 0x34, 0x25, 0x32, 0x26, 0x30, 0x26, +0x2e, 0x27, 0x2c, 0x28, 0x2a, 0x28, 0x28, 0x29, 0x27, 0x2a, 0x25, 0x2a, +0x25, 0x2b, 0x23, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x3e, 0x38, 0x3c, +0x34, 0x3a, 0x30, 0x3b, 0x2d, 0x3b, 0x2a, 0x39, 0x28, 0x39, 0x26, 0x3a, +0x24, 0x3b, 0x22, 0x3b, 0x21, 0x39, 0x20, 0x39, 0x1f, 0x39, 0x1e, 0x3b, +0x1c, 0x3b, 0x1c, 0x3c, 0x1a, 0x3c, 0x19, 0x3b, 0x19, 0x3a, 0x19, 0x3a, +0xaf, 0x00, 0xa5, 0x00, 0x99, 0x00, 0x90, 0x00, 0x87, 0x00, 0x7e, 0x00, +0x76, 0x00, 0x6f, 0x01, 0x68, 0x02, 0x62, 0x04, 0x5e, 0x04, 0x59, 0x05, +0x55, 0x06, 0x51, 0x07, 0x4e, 0x09, 0x4a, 0x0a, 0x47, 0x0a, 0x45, 0x0c, +0x41, 0x0c, 0x41, 0x0f, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, +0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, +0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, +0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x5c, 0x23, 0x57, 0x23, +0x52, 0x23, 0x4d, 0x23, 0x48, 0x23, 0x44, 0x23, 0x40, 0x24, 0x3c, 0x24, +0x39, 0x25, 0x36, 0x25, 0x34, 0x25, 0x31, 0x26, 0x2f, 0x27, 0x2d, 0x27, +0x2c, 0x28, 0x2a, 0x28, 0x28, 0x29, 0x27, 0x2a, 0x25, 0x2a, 0x25, 0x2b, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x3d, 0x3e, 0x38, 0x3c, 0x34, 0x3a, 0x31, 0x3b, +0x2e, 0x3c, 0x2b, 0x39, 0x29, 0x39, 0x27, 0x3a, 0x25, 0x3a, 0x24, 0x3b, +0x21, 0x3a, 0x21, 0x39, 0x1f, 0x39, 0x1f, 0x3a, 0x1d, 0x3b, 0x1c, 0x3b, +0x1c, 0x3c, 0x1a, 0x3c, 0x19, 0x3c, 0x19, 0x3a, 0xaf, 0x00, 0xa6, 0x00, +0x9b, 0x00, 0x91, 0x00, 0x88, 0x00, 0x80, 0x00, 0x78, 0x00, 0x71, 0x01, +0x6b, 0x02, 0x66, 0x02, 0x61, 0x04, 0x5c, 0x04, 0x58, 0x05, 0x55, 0x07, +0x50, 0x07, 0x4e, 0x09, 0x4a, 0x0a, 0x47, 0x0a, 0x45, 0x0c, 0x42, 0x0c, +0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, +0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, +0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, +0x0a, 0x47, 0x0a, 0x47, 0x5c, 0x23, 0x58, 0x23, 0x53, 0x23, 0x4d, 0x23, +0x49, 0x23, 0x45, 0x23, 0x41, 0x24, 0x3d, 0x24, 0x3b, 0x24, 0x38, 0x25, +0x35, 0x25, 0x33, 0x26, 0x31, 0x26, 0x2f, 0x27, 0x2d, 0x27, 0x2c, 0x28, +0x2a, 0x28, 0x28, 0x28, 0x28, 0x2a, 0x26, 0x2a, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x3d, 0x3e, 0x38, 0x3d, 0x35, 0x3a, 0x32, 0x3b, 0x2e, 0x3b, 0x2c, 0x3a, +0x2a, 0x39, 0x27, 0x39, 0x26, 0x3a, 0x24, 0x3a, 0x23, 0x3b, 0x21, 0x39, +0x21, 0x39, 0x1f, 0x39, 0x1f, 0x3a, 0x1d, 0x3b, 0x1c, 0x3b, 0x1c, 0x3c, +0x1a, 0x3c, 0x19, 0x3c, 0xb0, 0x00, 0xa6, 0x00, 0x9d, 0x00, 0x93, 0x00, +0x8b, 0x00, 0x83, 0x00, 0x7c, 0x00, 0x75, 0x00, 0x6e, 0x01, 0x69, 0x02, +0x63, 0x03, 0x5f, 0x04, 0x5b, 0x05, 0x56, 0x05, 0x54, 0x07, 0x4f, 0x07, +0x4e, 0x09, 0x4a, 0x0a, 0x47, 0x0a, 0x46, 0x0c, 0x0a, 0x47, 0x0a, 0x47, +0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, +0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, +0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, +0x5d, 0x23, 0x58, 0x23, 0x53, 0x23, 0x4f, 0x23, 0x4a, 0x23, 0x46, 0x23, +0x43, 0x24, 0x3f, 0x24, 0x3c, 0x24, 0x39, 0x25, 0x36, 0x25, 0x34, 0x25, +0x33, 0x26, 0x30, 0x26, 0x2f, 0x27, 0x2d, 0x27, 0x2c, 0x28, 0x2a, 0x28, +0x28, 0x28, 0x28, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3d, 0x3e, 0x39, 0x3e, +0x35, 0x3a, 0x32, 0x3a, 0x2f, 0x3b, 0x2d, 0x3c, 0x2a, 0x39, 0x28, 0x39, +0x27, 0x3a, 0x24, 0x3a, 0x24, 0x3b, 0x22, 0x3b, 0x21, 0x39, 0x20, 0x39, +0x1f, 0x39, 0x1f, 0x3a, 0x1d, 0x3b, 0x1c, 0x3b, 0x1c, 0x3c, 0x1a, 0x3c, +0xb0, 0x00, 0xa7, 0x00, 0x9e, 0x00, 0x96, 0x00, 0x8d, 0x00, 0x86, 0x00, +0x7e, 0x00, 0x77, 0x00, 0x71, 0x01, 0x6b, 0x01, 0x66, 0x02, 0x62, 0x04, +0x5d, 0x04, 0x5a, 0x05, 0x55, 0x05, 0x53, 0x07, 0x4f, 0x07, 0x4e, 0x09, +0x4a, 0x0a, 0x47, 0x0a, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, +0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, +0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, +0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x5d, 0x23, 0x58, 0x23, +0x54, 0x23, 0x50, 0x23, 0x4c, 0x23, 0x48, 0x23, 0x44, 0x23, 0x40, 0x24, +0x3d, 0x24, 0x3a, 0x24, 0x38, 0x25, 0x36, 0x25, 0x33, 0x25, 0x32, 0x26, +0x2f, 0x26, 0x2f, 0x27, 0x2c, 0x27, 0x2c, 0x28, 0x2a, 0x28, 0x28, 0x28, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x3d, 0x3e, 0x39, 0x3e, 0x35, 0x3b, 0x32, 0x3a, +0x30, 0x3b, 0x2e, 0x3c, 0x2b, 0x3a, 0x2a, 0x39, 0x27, 0x39, 0x26, 0x3a, +0x24, 0x3a, 0x23, 0x3b, 0x21, 0x3a, 0x21, 0x39, 0x1f, 0x39, 0x1f, 0x39, +0x1e, 0x3b, 0x1c, 0x3b, 0x1c, 0x3b, 0x1c, 0x3c, 0xb1, 0x00, 0xa7, 0x00, +0x9f, 0x00, 0x97, 0x00, 0x8f, 0x00, 0x87, 0x00, 0x80, 0x00, 0x79, 0x00, +0x73, 0x00, 0x6e, 0x01, 0x69, 0x02, 0x64, 0x02, 0x60, 0x04, 0x5c, 0x04, +0x59, 0x05, 0x55, 0x05, 0x53, 0x07, 0x4e, 0x07, 0x4e, 0x09, 0x4a, 0x0a, +0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, +0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, +0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, +0x0a, 0x47, 0x0a, 0x47, 0x5d, 0x23, 0x58, 0x23, 0x54, 0x23, 0x50, 0x23, +0x4c, 0x23, 0x48, 0x23, 0x45, 0x23, 0x42, 0x24, 0x3f, 0x24, 0x3c, 0x24, +0x39, 0x25, 0x37, 0x25, 0x35, 0x25, 0x33, 0x25, 0x31, 0x26, 0x2f, 0x26, +0x2e, 0x27, 0x2c, 0x27, 0x2c, 0x28, 0x2a, 0x28, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x7f, 0x00, 0x94, 0x00, 0x9e, 0x00, 0xa3, 0x00, 0xa7, 0x00, 0xa9, 0x00, +0xab, 0x00, 0xac, 0x00, 0xad, 0x00, 0xae, 0x00, 0xae, 0x00, 0xaf, 0x00, +0xaf, 0x00, 0xb0, 0x00, 0xb0, 0x00, 0xb1, 0x00, 0xb1, 0x00, 0xb1, 0x00, +0xb2, 0x00, 0xb2, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, +0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, +0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, +0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0x21, 0x00, 0x6e, 0x00, +0x8a, 0x00, 0x97, 0x00, 0x9e, 0x00, 0xa2, 0x00, 0xa6, 0x00, 0xa8, 0x00, +0xaa, 0x00, 0xaa, 0x00, 0xac, 0x00, 0xad, 0x00, 0xad, 0x00, 0xad, 0x00, +0xae, 0x00, 0xaf, 0x00, 0xaf, 0x00, 0xaf, 0x00, 0xb0, 0x00, 0xb0, 0x00, +0x6c, 0x00, 0x92, 0x00, 0xa1, 0x00, 0xa7, 0x00, 0xaa, 0x00, 0xac, 0x00, +0xae, 0x00, 0xaf, 0x00, 0xb0, 0x00, 0xb1, 0x00, 0xb1, 0x00, 0xb2, 0x00, +0xb2, 0x00, 0xb2, 0x00, 0xb3, 0x00, 0xb3, 0x00, 0xb3, 0x00, 0xb3, 0x00, +0xb3, 0x00, 0xb4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x59, 0x04, 0x70, 0x01, +0x7f, 0x00, 0x88, 0x00, 0x90, 0x00, 0x95, 0x00, 0x99, 0x00, 0x9c, 0x00, +0x9f, 0x00, 0xa2, 0x00, 0xa3, 0x00, 0xa5, 0x00, 0xa6, 0x00, 0xa7, 0x00, +0xa7, 0x00, 0xa8, 0x00, 0xa9, 0x00, 0xa9, 0x00, 0xaa, 0x00, 0xaa, 0x00, +0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, +0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, +0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, +0xb7, 0x00, 0xb7, 0x00, 0x0a, 0x1c, 0x3a, 0x03, 0x59, 0x00, 0x6c, 0x00, +0x79, 0x00, 0x84, 0x00, 0x8b, 0x00, 0x90, 0x00, 0x94, 0x00, 0x98, 0x00, +0x9b, 0x00, 0x9d, 0x00, 0x9f, 0x00, 0xa0, 0x00, 0xa2, 0x00, 0xa3, 0x00, +0xa5, 0x00, 0xa6, 0x00, 0xa6, 0x00, 0xa7, 0x00, 0x60, 0x0e, 0x79, 0x01, +0x88, 0x00, 0x92, 0x00, 0x98, 0x00, 0x9d, 0x00, 0xa1, 0x00, 0xa3, 0x00, +0xa5, 0x00, 0xa8, 0x00, 0xa9, 0x00, 0xaa, 0x00, 0xab, 0x00, 0xac, 0x00, +0xac, 0x00, 0xad, 0x00, 0xae, 0x00, 0xae, 0x00, 0xae, 0x00, 0xaf, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x4e, 0x0f, 0x60, 0x07, 0x6d, 0x03, 0x77, 0x01, +0x7f, 0x00, 0x85, 0x00, 0x8b, 0x00, 0x8f, 0x00, 0x92, 0x00, 0x94, 0x00, +0x97, 0x00, 0x9a, 0x00, 0x9c, 0x00, 0x9e, 0x00, 0xa0, 0x00, 0xa1, 0x00, +0xa2, 0x00, 0xa3, 0x00, 0xa4, 0x00, 0xa4, 0x00, 0xb7, 0x00, 0xb7, 0x00, +0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, +0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, +0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, +0x0a, 0x29, 0x27, 0x0f, 0x40, 0x06, 0x52, 0x02, 0x61, 0x00, 0x6c, 0x00, +0x75, 0x00, 0x7c, 0x00, 0x82, 0x00, 0x87, 0x00, 0x8b, 0x00, 0x8e, 0x00, +0x91, 0x00, 0x94, 0x00, 0x97, 0x00, 0x98, 0x00, 0x99, 0x00, 0x9b, 0x00, +0x9d, 0x00, 0x9e, 0x00, 0x60, 0x14, 0x6f, 0x07, 0x7b, 0x03, 0x84, 0x01, +0x8c, 0x00, 0x91, 0x00, 0x96, 0x00, 0x99, 0x00, 0x9d, 0x00, 0x9f, 0x00, +0xa1, 0x00, 0xa2, 0x00, 0xa4, 0x00, 0xa5, 0x00, 0xa7, 0x00, 0xa7, 0x00, +0xa8, 0x00, 0xa9, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x49, 0x17, 0x56, 0x0d, 0x62, 0x07, 0x6b, 0x04, 0x73, 0x02, 0x79, 0x01, +0x7e, 0x01, 0x83, 0x00, 0x88, 0x00, 0x8b, 0x00, 0x8e, 0x00, 0x90, 0x00, +0x92, 0x00, 0x94, 0x00, 0x96, 0x00, 0x98, 0x00, 0x9a, 0x00, 0x9c, 0x00, +0x9e, 0x00, 0x9f, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, +0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, +0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, +0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0x09, 0x31, 0x1e, 0x18, +0x32, 0x0d, 0x43, 0x07, 0x50, 0x04, 0x5a, 0x02, 0x63, 0x01, 0x6b, 0x00, +0x72, 0x00, 0x78, 0x00, 0x7c, 0x00, 0x81, 0x00, 0x85, 0x00, 0x88, 0x00, +0x8b, 0x00, 0x8e, 0x00, 0x90, 0x00, 0x91, 0x00, 0x93, 0x00, 0x96, 0x00, +0x60, 0x18, 0x6b, 0x0c, 0x74, 0x06, 0x7d, 0x03, 0x83, 0x02, 0x89, 0x01, +0x8d, 0x00, 0x91, 0x00, 0x95, 0x00, 0x98, 0x00, 0x9a, 0x00, 0x9c, 0x00, +0x9e, 0x00, 0x9f, 0x00, 0xa1, 0x00, 0xa3, 0x00, 0xa3, 0x00, 0xa4, 0x00, +0xa5, 0x00, 0xa6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x1d, 0x51, 0x12, +0x5b, 0x0c, 0x63, 0x08, 0x6a, 0x05, 0x70, 0x03, 0x77, 0x02, 0x7b, 0x02, +0x7e, 0x01, 0x82, 0x00, 0x86, 0x00, 0x8a, 0x00, 0x8c, 0x00, 0x8e, 0x00, +0x90, 0x00, 0x91, 0x00, 0x93, 0x00, 0x94, 0x00, 0x95, 0x00, 0x97, 0x00, +0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, +0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, +0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, +0xb7, 0x00, 0xb7, 0x00, 0x09, 0x36, 0x19, 0x1f, 0x2a, 0x12, 0x38, 0x0b, +0x44, 0x07, 0x4e, 0x05, 0x57, 0x02, 0x5f, 0x01, 0x65, 0x01, 0x6b, 0x00, +0x71, 0x00, 0x76, 0x00, 0x79, 0x00, 0x7e, 0x00, 0x80, 0x00, 0x84, 0x00, +0x87, 0x00, 0x88, 0x00, 0x8b, 0x00, 0x8d, 0x00, 0x60, 0x1b, 0x68, 0x0f, +0x70, 0x09, 0x77, 0x05, 0x7d, 0x03, 0x82, 0x02, 0x87, 0x01, 0x8b, 0x00, +0x8e, 0x00, 0x91, 0x00, 0x94, 0x00, 0x96, 0x00, 0x98, 0x00, 0x9a, 0x00, +0x9b, 0x00, 0x9d, 0x00, 0x9f, 0x00, 0xa0, 0x00, 0xa1, 0x00, 0xa2, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x45, 0x21, 0x4e, 0x16, 0x56, 0x10, 0x5d, 0x0b, +0x65, 0x08, 0x69, 0x06, 0x6f, 0x04, 0x74, 0x03, 0x78, 0x02, 0x7b, 0x02, +0x7e, 0x01, 0x81, 0x01, 0x85, 0x00, 0x88, 0x00, 0x8a, 0x00, 0x8c, 0x00, +0x8e, 0x00, 0x8f, 0x00, 0x90, 0x00, 0x92, 0x00, 0xb7, 0x00, 0xb7, 0x00, +0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, +0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, +0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, +0x09, 0x3a, 0x17, 0x24, 0x24, 0x18, 0x30, 0x10, 0x3b, 0x0b, 0x45, 0x07, +0x4d, 0x05, 0x55, 0x04, 0x5b, 0x02, 0x61, 0x01, 0x67, 0x01, 0x6b, 0x00, +0x6f, 0x00, 0x74, 0x00, 0x77, 0x00, 0x7a, 0x00, 0x7e, 0x00, 0x80, 0x00, +0x83, 0x00, 0x86, 0x00, 0x60, 0x1d, 0x67, 0x12, 0x6d, 0x0c, 0x73, 0x08, +0x79, 0x05, 0x7e, 0x03, 0x82, 0x02, 0x86, 0x02, 0x89, 0x01, 0x8c, 0x00, +0x8f, 0x00, 0x91, 0x00, 0x93, 0x00, 0x96, 0x00, 0x97, 0x00, 0x99, 0x00, +0x9a, 0x00, 0x9b, 0x00, 0x9d, 0x00, 0x9e, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x44, 0x24, 0x4c, 0x1a, 0x53, 0x13, 0x59, 0x0e, 0x5f, 0x0b, 0x65, 0x08, +0x69, 0x06, 0x6d, 0x05, 0x73, 0x04, 0x76, 0x03, 0x79, 0x02, 0x7c, 0x02, +0x7e, 0x01, 0x81, 0x01, 0x84, 0x00, 0x87, 0x00, 0x89, 0x00, 0x8b, 0x00, +0x8c, 0x00, 0x8d, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, +0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, +0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, +0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0x09, 0x3b, 0x14, 0x28, +0x20, 0x1c, 0x2a, 0x14, 0x34, 0x0f, 0x3e, 0x0b, 0x45, 0x07, 0x4c, 0x05, +0x53, 0x04, 0x58, 0x03, 0x5e, 0x02, 0x63, 0x01, 0x67, 0x01, 0x6c, 0x00, +0x6f, 0x00, 0x72, 0x00, 0x76, 0x00, 0x78, 0x00, 0x7c, 0x00, 0x7e, 0x00, +0x60, 0x1d, 0x66, 0x14, 0x6b, 0x0e, 0x71, 0x0a, 0x76, 0x07, 0x7a, 0x05, +0x7e, 0x03, 0x81, 0x02, 0x85, 0x02, 0x88, 0x01, 0x8b, 0x01, 0x8d, 0x00, +0x8f, 0x00, 0x91, 0x00, 0x93, 0x00, 0x95, 0x00, 0x96, 0x00, 0x98, 0x00, +0x99, 0x00, 0x9a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0x27, 0x4a, 0x1d, +0x4f, 0x16, 0x57, 0x11, 0x5b, 0x0e, 0x61, 0x0b, 0x66, 0x08, 0x69, 0x07, +0x6d, 0x05, 0x71, 0x04, 0x75, 0x03, 0x77, 0x02, 0x7a, 0x02, 0x7c, 0x02, +0x7e, 0x01, 0x80, 0x01, 0x83, 0x01, 0x86, 0x00, 0x88, 0x00, 0x89, 0x00, +0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, +0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, +0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, +0xb7, 0x00, 0xb7, 0x00, 0x09, 0x3d, 0x13, 0x2c, 0x1c, 0x20, 0x27, 0x18, +0x2f, 0x12, 0x38, 0x0e, 0x3e, 0x0a, 0x45, 0x07, 0x4b, 0x06, 0x51, 0x05, +0x57, 0x04, 0x5c, 0x02, 0x60, 0x02, 0x65, 0x01, 0x67, 0x01, 0x6c, 0x00, +0x6f, 0x00, 0x71, 0x00, 0x75, 0x00, 0x77, 0x00, 0x60, 0x1e, 0x65, 0x16, +0x6a, 0x10, 0x6f, 0x0c, 0x73, 0x09, 0x77, 0x07, 0x7b, 0x05, 0x7e, 0x03, +0x81, 0x03, 0x84, 0x02, 0x87, 0x02, 0x89, 0x01, 0x8b, 0x01, 0x8e, 0x00, +0x8f, 0x00, 0x91, 0x00, 0x93, 0x00, 0x94, 0x00, 0x96, 0x00, 0x97, 0x00, +0x27, 0x00, 0x4f, 0x00, 0x7f, 0x00, 0x8f, 0x00, 0x96, 0x00, 0x99, 0x00, +0x9b, 0x00, 0x9c, 0x00, 0x9c, 0x00, 0x9d, 0x00, 0x9d, 0x00, 0x9e, 0x00, +0x9e, 0x00, 0x9e, 0x00, 0x9e, 0x00, 0x9e, 0x00, 0x2c, 0x14, 0x57, 0x00, +0x82, 0x00, 0x91, 0x00, 0x96, 0x00, 0x99, 0x00, 0x9b, 0x00, 0x9c, 0x00, +0x9d, 0x00, 0x9d, 0x00, 0x9d, 0x00, 0x9e, 0x00, 0x9e, 0x00, 0x9e, 0x00, +0x9e, 0x00, 0x9e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x8c, 0x00, 0x63, 0x00, 0x7f, 0x00, 0x89, 0x00, 0x90, 0x00, 0x96, 0x00, +0x9b, 0x00, 0x9c, 0x00, 0x9c, 0x00, 0x9d, 0x00, 0x9d, 0x00, 0x9e, 0x00, +0x9e, 0x00, 0x9e, 0x00, 0x9e, 0x00, 0x9e, 0x00, 0x31, 0x11, 0x5f, 0x00, +0x85, 0x00, 0x92, 0x00, 0x97, 0x00, 0x9a, 0x00, 0x9b, 0x00, 0x9c, 0x00, +0x9d, 0x00, 0x9d, 0x00, 0x9e, 0x00, 0x9e, 0x00, 0x9e, 0x00, 0x9e, 0x00, +0x9e, 0x00, 0x9e, 0x00, 0x43, 0x29, 0x48, 0x20, 0x4d, 0x19, 0x54, 0x14, +0x58, 0x10, 0x5c, 0x0d, 0x62, 0x0b, 0x66, 0x09, 0x69, 0x07, 0x6c, 0x06, +0x70, 0x05, 0x74, 0x04, 0x76, 0x03, 0x78, 0x02, 0x7a, 0x02, 0x7c, 0x02, +0x7e, 0x02, 0x80, 0x01, 0x82, 0x01, 0x85, 0x00, 0xb7, 0x00, 0xb7, 0x00, +0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, +0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, +0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, +0x09, 0x3f, 0x11, 0x2f, 0x1b, 0x23, 0x23, 0x1b, 0x2b, 0x15, 0x32, 0x11, +0x39, 0x0d, 0x40, 0x0a, 0x45, 0x08, 0x4b, 0x07, 0x51, 0x05, 0x56, 0x04, +0x59, 0x03, 0x5e, 0x02, 0x61, 0x02, 0x65, 0x01, 0x68, 0x01, 0x6b, 0x00, +0x6e, 0x00, 0x71, 0x00, 0x60, 0x1f, 0x64, 0x17, 0x69, 0x11, 0x6d, 0x0d, +0x71, 0x0a, 0x75, 0x08, 0x78, 0x06, 0x7b, 0x05, 0x7e, 0x04, 0x81, 0x03, +0x84, 0x02, 0x86, 0x02, 0x88, 0x01, 0x8a, 0x01, 0x8c, 0x01, 0x8e, 0x00, +0x8f, 0x00, 0x91, 0x00, 0x93, 0x00, 0x94, 0x00, 0x00, 0x00, 0x0d, 0x00, +0x4f, 0x00, 0x73, 0x00, 0x84, 0x00, 0x8d, 0x00, 0x92, 0x00, 0x95, 0x00, +0x98, 0x00, 0x99, 0x00, 0x9a, 0x00, 0x9b, 0x00, 0x9c, 0x00, 0x9c, 0x00, +0x9c, 0x00, 0x9d, 0x00, 0x01, 0x29, 0x16, 0x04, 0x57, 0x00, 0x78, 0x00, +0x87, 0x00, 0x8f, 0x00, 0x94, 0x00, 0x96, 0x00, 0x98, 0x00, 0x9a, 0x00, +0x9b, 0x00, 0x9b, 0x00, 0x9c, 0x00, 0x9c, 0x00, 0x9d, 0x00, 0x9d, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x00, 0x4d, 0x00, +0x60, 0x00, 0x77, 0x00, 0x83, 0x00, 0x8c, 0x00, 0x92, 0x00, 0x95, 0x00, +0x98, 0x00, 0x99, 0x00, 0x9a, 0x00, 0x9b, 0x00, 0x9c, 0x00, 0x9c, 0x00, +0x9c, 0x00, 0x9d, 0x00, 0x03, 0x23, 0x20, 0x00, 0x5f, 0x00, 0x7c, 0x00, +0x8a, 0x00, 0x91, 0x00, 0x95, 0x00, 0x97, 0x00, 0x99, 0x00, 0x9a, 0x00, +0x9b, 0x00, 0x9c, 0x00, 0x9c, 0x00, 0x9d, 0x00, 0x9d, 0x00, 0x9d, 0x00, +0x43, 0x2b, 0x47, 0x22, 0x4c, 0x1b, 0x51, 0x16, 0x56, 0x12, 0x59, 0x0f, +0x5e, 0x0d, 0x63, 0x0b, 0x66, 0x09, 0x69, 0x07, 0x6b, 0x06, 0x6f, 0x05, +0x73, 0x05, 0x75, 0x03, 0x77, 0x03, 0x79, 0x02, 0x7a, 0x02, 0x7c, 0x02, +0x7e, 0x02, 0x7f, 0x01, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, +0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, +0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, +0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0x09, 0x40, 0x11, 0x31, +0x18, 0x26, 0x20, 0x1e, 0x28, 0x18, 0x2f, 0x13, 0x35, 0x0f, 0x3c, 0x0c, +0x41, 0x0a, 0x46, 0x08, 0x4b, 0x07, 0x50, 0x05, 0x54, 0x04, 0x58, 0x04, +0x5c, 0x02, 0x5f, 0x02, 0x62, 0x02, 0x66, 0x01, 0x69, 0x01, 0x6b, 0x00, +0x60, 0x20, 0x64, 0x18, 0x68, 0x13, 0x6b, 0x0f, 0x6f, 0x0c, 0x73, 0x09, +0x76, 0x07, 0x79, 0x06, 0x7c, 0x05, 0x7e, 0x04, 0x81, 0x03, 0x83, 0x02, +0x85, 0x02, 0x88, 0x02, 0x89, 0x01, 0x8b, 0x01, 0x8d, 0x01, 0x8e, 0x00, +0x90, 0x00, 0x91, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x38, 0x00, +0x5b, 0x00, 0x6f, 0x00, 0x7c, 0x00, 0x84, 0x00, 0x8a, 0x00, 0x8e, 0x00, +0x91, 0x00, 0x93, 0x00, 0x95, 0x00, 0x97, 0x00, 0x98, 0x00, 0x99, 0x00, +0x00, 0x49, 0x00, 0x27, 0x12, 0x01, 0x43, 0x00, 0x61, 0x00, 0x74, 0x00, +0x7f, 0x00, 0x87, 0x00, 0x8c, 0x00, 0x90, 0x00, 0x93, 0x00, 0x95, 0x00, +0x96, 0x00, 0x97, 0x00, 0x98, 0x00, 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x60, 0x00, 0x24, 0x00, 0x48, 0x00, +0x60, 0x00, 0x70, 0x00, 0x7c, 0x00, 0x84, 0x00, 0x8a, 0x00, 0x8e, 0x00, +0x91, 0x00, 0x93, 0x00, 0x95, 0x00, 0x97, 0x00, 0x98, 0x00, 0x99, 0x00, +0x00, 0x46, 0x00, 0x1f, 0x1f, 0x00, 0x4d, 0x00, 0x68, 0x00, 0x79, 0x00, +0x83, 0x00, 0x8a, 0x00, 0x8e, 0x00, 0x92, 0x00, 0x94, 0x00, 0x96, 0x00, +0x97, 0x00, 0x98, 0x00, 0x99, 0x00, 0x9a, 0x00, 0x43, 0x2d, 0x46, 0x24, +0x4b, 0x1e, 0x4f, 0x19, 0x55, 0x14, 0x58, 0x11, 0x5b, 0x0e, 0x5f, 0x0c, +0x64, 0x0a, 0x66, 0x09, 0x68, 0x07, 0x6a, 0x06, 0x6e, 0x06, 0x72, 0x05, +0x74, 0x04, 0x76, 0x03, 0x78, 0x03, 0x79, 0x02, 0x7b, 0x02, 0x7c, 0x02, +0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, +0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, +0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, +0xb7, 0x00, 0xb7, 0x00, 0x09, 0x40, 0x10, 0x33, 0x17, 0x28, 0x1e, 0x20, +0x25, 0x1a, 0x2c, 0x16, 0x32, 0x12, 0x37, 0x0f, 0x3d, 0x0c, 0x42, 0x0a, +0x46, 0x08, 0x4b, 0x07, 0x4f, 0x05, 0x53, 0x05, 0x57, 0x04, 0x5a, 0x04, +0x5e, 0x02, 0x61, 0x02, 0x63, 0x01, 0x66, 0x01, 0x60, 0x20, 0x63, 0x19, +0x67, 0x14, 0x6a, 0x10, 0x6e, 0x0d, 0x71, 0x0b, 0x74, 0x09, 0x77, 0x07, +0x7a, 0x06, 0x7c, 0x05, 0x7f, 0x04, 0x81, 0x03, 0x83, 0x02, 0x85, 0x02, +0x87, 0x02, 0x88, 0x02, 0x8a, 0x01, 0x8c, 0x01, 0x8d, 0x00, 0x8e, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x2a, 0x00, 0x48, 0x00, +0x5d, 0x00, 0x6c, 0x00, 0x76, 0x00, 0x7e, 0x00, 0x83, 0x00, 0x88, 0x00, +0x8b, 0x00, 0x8e, 0x00, 0x90, 0x00, 0x92, 0x00, 0x00, 0x54, 0x00, 0x41, +0x00, 0x17, 0x10, 0x00, 0x36, 0x00, 0x51, 0x00, 0x64, 0x00, 0x71, 0x00, +0x7a, 0x00, 0x81, 0x00, 0x86, 0x00, 0x8a, 0x00, 0x8d, 0x00, 0x90, 0x00, +0x92, 0x00, 0x93, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x89, 0x00, 0x77, 0x00, 0x48, 0x00, 0x0f, 0x00, 0x30, 0x00, 0x48, 0x00, +0x5d, 0x00, 0x6c, 0x00, 0x76, 0x00, 0x7e, 0x00, 0x83, 0x00, 0x88, 0x00, +0x8b, 0x00, 0x8e, 0x00, 0x90, 0x00, 0x92, 0x00, 0x00, 0x52, 0x00, 0x3c, +0x00, 0x0d, 0x1f, 0x00, 0x42, 0x00, 0x5a, 0x00, 0x6a, 0x00, 0x76, 0x00, +0x7e, 0x00, 0x84, 0x00, 0x89, 0x00, 0x8c, 0x00, 0x8f, 0x00, 0x91, 0x00, +0x93, 0x00, 0x95, 0x00, 0x42, 0x2e, 0x45, 0x26, 0x4b, 0x1f, 0x4d, 0x1a, +0x52, 0x16, 0x56, 0x13, 0x59, 0x10, 0x5c, 0x0e, 0x61, 0x0c, 0x64, 0x0a, +0x66, 0x09, 0x68, 0x07, 0x6a, 0x07, 0x6d, 0x06, 0x71, 0x05, 0x74, 0x05, +0x75, 0x03, 0x77, 0x03, 0x78, 0x02, 0x7a, 0x02, 0xb7, 0x00, 0xb7, 0x00, +0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, +0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, +0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, +0x09, 0x41, 0x0f, 0x34, 0x16, 0x2a, 0x1c, 0x23, 0x23, 0x1d, 0x29, 0x18, +0x2e, 0x14, 0x34, 0x11, 0x39, 0x0e, 0x3e, 0x0c, 0x42, 0x0a, 0x47, 0x08, +0x4b, 0x07, 0x4f, 0x05, 0x52, 0x05, 0x56, 0x04, 0x59, 0x04, 0x5c, 0x03, +0x5f, 0x02, 0x62, 0x02, 0x60, 0x20, 0x63, 0x1a, 0x66, 0x15, 0x6a, 0x11, +0x6d, 0x0e, 0x70, 0x0c, 0x73, 0x0a, 0x75, 0x08, 0x78, 0x07, 0x7a, 0x06, +0x7d, 0x05, 0x7f, 0x04, 0x81, 0x03, 0x83, 0x02, 0x85, 0x02, 0x86, 0x02, +0x88, 0x02, 0x89, 0x01, 0x8b, 0x01, 0x8c, 0x01, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x22, 0x00, 0x3c, 0x00, 0x4f, 0x00, +0x5e, 0x00, 0x69, 0x00, 0x72, 0x00, 0x79, 0x00, 0x7e, 0x00, 0x83, 0x00, +0x86, 0x00, 0x89, 0x00, 0x00, 0x59, 0x00, 0x4d, 0x00, 0x2f, 0x00, 0x0e, +0x10, 0x00, 0x2e, 0x00, 0x46, 0x00, 0x57, 0x00, 0x64, 0x00, 0x6f, 0x00, +0x76, 0x00, 0x7d, 0x00, 0x81, 0x00, 0x85, 0x00, 0x89, 0x00, 0x8b, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x00, 0x83, 0x00, +0x60, 0x00, 0x30, 0x00, 0x02, 0x00, 0x22, 0x00, 0x3c, 0x00, 0x4f, 0x00, +0x5e, 0x00, 0x69, 0x00, 0x72, 0x00, 0x79, 0x00, 0x7e, 0x00, 0x83, 0x00, +0x86, 0x00, 0x89, 0x00, 0x00, 0x58, 0x00, 0x4a, 0x00, 0x28, 0x00, 0x02, +0x1f, 0x00, 0x3b, 0x00, 0x4f, 0x00, 0x5f, 0x00, 0x6b, 0x00, 0x74, 0x00, +0x7b, 0x00, 0x80, 0x00, 0x85, 0x00, 0x88, 0x00, 0x8b, 0x00, 0x8d, 0x00, +0x42, 0x2f, 0x44, 0x27, 0x4a, 0x22, 0x4c, 0x1c, 0x50, 0x18, 0x55, 0x14, +0x57, 0x12, 0x5a, 0x0f, 0x5d, 0x0d, 0x62, 0x0c, 0x64, 0x0a, 0x66, 0x09, +0x68, 0x08, 0x6a, 0x07, 0x6c, 0x06, 0x70, 0x05, 0x73, 0x05, 0x75, 0x04, +0x76, 0x03, 0x78, 0x03, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, +0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, +0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, +0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0x09, 0x42, 0x0f, 0x36, +0x15, 0x2c, 0x1b, 0x25, 0x21, 0x1f, 0x26, 0x1a, 0x2c, 0x16, 0x31, 0x12, +0x36, 0x0f, 0x3a, 0x0d, 0x3f, 0x0c, 0x43, 0x0a, 0x47, 0x08, 0x4b, 0x07, +0x4e, 0x05, 0x52, 0x05, 0x55, 0x04, 0x58, 0x04, 0x5b, 0x04, 0x5d, 0x02, +0x60, 0x21, 0x63, 0x1b, 0x66, 0x16, 0x69, 0x12, 0x6c, 0x0f, 0x6e, 0x0d, +0x71, 0x0b, 0x74, 0x09, 0x76, 0x07, 0x79, 0x06, 0x7b, 0x06, 0x7d, 0x05, +0x7f, 0x04, 0x81, 0x03, 0x82, 0x02, 0x84, 0x02, 0x86, 0x02, 0x87, 0x02, +0x89, 0x02, 0x8a, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x33, 0x00, 0x45, 0x00, 0x53, 0x00, +0x5e, 0x00, 0x68, 0x00, 0x6f, 0x00, 0x75, 0x00, 0x7a, 0x00, 0x7e, 0x00, +0x00, 0x5b, 0x00, 0x53, 0x00, 0x3e, 0x00, 0x23, 0x02, 0x0a, 0x10, 0x00, +0x29, 0x00, 0x3d, 0x00, 0x4e, 0x00, 0x5b, 0x00, 0x65, 0x00, 0x6d, 0x00, +0x74, 0x00, 0x79, 0x00, 0x7e, 0x00, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x96, 0x00, 0x8c, 0x00, 0x70, 0x00, 0x48, 0x00, +0x22, 0x00, 0x01, 0x00, 0x1c, 0x00, 0x33, 0x00, 0x45, 0x00, 0x53, 0x00, +0x5e, 0x00, 0x68, 0x00, 0x6f, 0x00, 0x75, 0x00, 0x7a, 0x00, 0x7e, 0x00, +0x00, 0x5a, 0x00, 0x51, 0x00, 0x39, 0x00, 0x1a, 0x04, 0x00, 0x1f, 0x00, +0x36, 0x00, 0x48, 0x00, 0x57, 0x00, 0x62, 0x00, 0x6b, 0x00, 0x73, 0x00, +0x79, 0x00, 0x7e, 0x00, 0x82, 0x00, 0x85, 0x00, 0x42, 0x31, 0x44, 0x29, +0x49, 0x23, 0x4c, 0x1e, 0x4e, 0x1a, 0x53, 0x16, 0x56, 0x13, 0x58, 0x11, +0x5a, 0x0f, 0x5f, 0x0d, 0x63, 0x0b, 0x64, 0x0a, 0x66, 0x09, 0x68, 0x08, +0x6a, 0x07, 0x6b, 0x06, 0x6f, 0x06, 0x72, 0x05, 0x74, 0x05, 0x75, 0x03, +0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, +0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, +0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, +0xb7, 0x00, 0xb7, 0x00, 0x09, 0x43, 0x0f, 0x37, 0x14, 0x2e, 0x19, 0x27, +0x1f, 0x21, 0x24, 0x1c, 0x29, 0x18, 0x2e, 0x15, 0x33, 0x12, 0x37, 0x0f, +0x3b, 0x0c, 0x40, 0x0c, 0x43, 0x0a, 0x47, 0x08, 0x4b, 0x07, 0x4e, 0x06, +0x51, 0x05, 0x55, 0x05, 0x56, 0x04, 0x5a, 0x04, 0x60, 0x21, 0x63, 0x1b, +0x65, 0x17, 0x68, 0x13, 0x6b, 0x10, 0x6e, 0x0e, 0x70, 0x0c, 0x73, 0x0a, +0x75, 0x09, 0x77, 0x07, 0x79, 0x06, 0x7b, 0x06, 0x7d, 0x05, 0x7f, 0x04, +0x81, 0x03, 0x82, 0x03, 0x84, 0x02, 0x86, 0x02, 0x87, 0x02, 0x88, 0x02, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x18, 0x00, 0x2c, 0x00, 0x3c, 0x00, 0x4a, 0x00, 0x55, 0x00, +0x5f, 0x00, 0x66, 0x00, 0x6d, 0x00, 0x72, 0x00, 0x00, 0x5c, 0x00, 0x56, +0x00, 0x47, 0x00, 0x31, 0x00, 0x1a, 0x04, 0x08, 0x10, 0x00, 0x25, 0x00, +0x37, 0x00, 0x46, 0x00, 0x52, 0x00, 0x5d, 0x00, 0x65, 0x00, 0x6c, 0x00, +0x72, 0x00, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x9b, 0x00, 0x92, 0x00, 0x7c, 0x00, 0x5d, 0x00, 0x3c, 0x00, 0x1c, 0x00, +0x01, 0x00, 0x18, 0x00, 0x2c, 0x00, 0x3c, 0x00, 0x4a, 0x00, 0x55, 0x00, +0x5f, 0x00, 0x66, 0x00, 0x6d, 0x00, 0x72, 0x00, 0x00, 0x5c, 0x00, 0x55, +0x00, 0x43, 0x00, 0x2a, 0x00, 0x10, 0x09, 0x00, 0x1f, 0x00, 0x33, 0x00, +0x43, 0x00, 0x50, 0x00, 0x5b, 0x00, 0x64, 0x00, 0x6b, 0x00, 0x72, 0x00, +0x77, 0x00, 0x7b, 0x00, 0x42, 0x31, 0x44, 0x2a, 0x48, 0x24, 0x4b, 0x1f, +0x4d, 0x1b, 0x51, 0x18, 0x55, 0x15, 0x57, 0x12, 0x59, 0x10, 0x5b, 0x0e, +0x5f, 0x0c, 0x63, 0x0b, 0x65, 0x0a, 0x66, 0x09, 0x68, 0x08, 0x6a, 0x07, +0x6b, 0x06, 0x6e, 0x06, 0x71, 0x05, 0x73, 0x05, 0xb7, 0x00, 0xb7, 0x00, +0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, +0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, +0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, +0x0a, 0x43, 0x0e, 0x38, 0x13, 0x2f, 0x18, 0x28, 0x1d, 0x22, 0x22, 0x1d, +0x27, 0x19, 0x2b, 0x16, 0x30, 0x12, 0x35, 0x11, 0x39, 0x0f, 0x3c, 0x0c, +0x41, 0x0b, 0x44, 0x0a, 0x47, 0x09, 0x4a, 0x07, 0x4e, 0x07, 0x50, 0x05, +0x54, 0x05, 0x55, 0x04, 0x60, 0x21, 0x63, 0x1c, 0x65, 0x17, 0x68, 0x14, +0x6a, 0x11, 0x6c, 0x0e, 0x6f, 0x0c, 0x71, 0x0b, 0x73, 0x09, 0x76, 0x08, +0x78, 0x07, 0x79, 0x06, 0x7c, 0x05, 0x7d, 0x05, 0x7f, 0x04, 0x81, 0x03, +0x82, 0x03, 0x84, 0x02, 0x85, 0x02, 0x86, 0x02, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x14, 0x00, 0x26, 0x00, 0x36, 0x00, 0x43, 0x00, 0x4e, 0x00, 0x57, 0x00, +0x5f, 0x00, 0x66, 0x00, 0x00, 0x5d, 0x00, 0x59, 0x00, 0x4d, 0x00, 0x3b, +0x00, 0x27, 0x00, 0x13, 0x06, 0x07, 0x10, 0x00, 0x22, 0x00, 0x32, 0x00, +0x40, 0x00, 0x4c, 0x00, 0x56, 0x00, 0x5e, 0x00, 0x65, 0x00, 0x6b, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9c, 0x00, 0x95, 0x00, +0x84, 0x00, 0x6c, 0x00, 0x4f, 0x00, 0x32, 0x00, 0x18, 0x00, 0x00, 0x00, +0x14, 0x00, 0x26, 0x00, 0x36, 0x00, 0x43, 0x00, 0x4e, 0x00, 0x57, 0x00, +0x5f, 0x00, 0x66, 0x00, 0x00, 0x5d, 0x00, 0x58, 0x00, 0x4a, 0x00, 0x36, +0x00, 0x1f, 0x00, 0x08, 0x0c, 0x00, 0x1f, 0x00, 0x30, 0x00, 0x3f, 0x00, +0x4b, 0x00, 0x55, 0x00, 0x5e, 0x00, 0x65, 0x00, 0x6c, 0x00, 0x71, 0x00, +0x42, 0x32, 0x44, 0x2b, 0x47, 0x25, 0x4b, 0x21, 0x4c, 0x1d, 0x4f, 0x19, +0x54, 0x16, 0x56, 0x14, 0x58, 0x11, 0x5a, 0x10, 0x5d, 0x0e, 0x61, 0x0c, +0x63, 0x0b, 0x65, 0x0a, 0x66, 0x09, 0x68, 0x08, 0x69, 0x07, 0x6b, 0x07, +0x6d, 0x06, 0x71, 0x05, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, +0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, +0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, +0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0x0a, 0x43, 0x0e, 0x39, +0x12, 0x31, 0x17, 0x2a, 0x1c, 0x24, 0x21, 0x1f, 0x26, 0x1b, 0x2a, 0x18, +0x2e, 0x16, 0x32, 0x12, 0x35, 0x0f, 0x3a, 0x0f, 0x3d, 0x0c, 0x41, 0x0b, +0x44, 0x0a, 0x47, 0x09, 0x4a, 0x07, 0x4e, 0x07, 0x4f, 0x05, 0x53, 0x05, +0x60, 0x21, 0x62, 0x1c, 0x65, 0x18, 0x67, 0x15, 0x6a, 0x12, 0x6c, 0x0f, +0x6e, 0x0d, 0x71, 0x0c, 0x73, 0x0b, 0x74, 0x09, 0x76, 0x07, 0x79, 0x07, +0x7a, 0x06, 0x7c, 0x05, 0x7d, 0x05, 0x7f, 0x04, 0x81, 0x03, 0x82, 0x03, +0x83, 0x02, 0x85, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, +0x22, 0x00, 0x30, 0x00, 0x3d, 0x00, 0x47, 0x00, 0x50, 0x00, 0x58, 0x00, +0x00, 0x5d, 0x00, 0x5a, 0x00, 0x51, 0x00, 0x42, 0x00, 0x32, 0x00, 0x20, +0x00, 0x0e, 0x07, 0x06, 0x10, 0x00, 0x20, 0x00, 0x2f, 0x00, 0x3b, 0x00, +0x46, 0x00, 0x50, 0x00, 0x58, 0x00, 0x5f, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x9c, 0x00, 0x98, 0x00, 0x8a, 0x00, 0x76, 0x00, +0x5e, 0x00, 0x45, 0x00, 0x2c, 0x00, 0x14, 0x00, 0x00, 0x00, 0x12, 0x00, +0x22, 0x00, 0x30, 0x00, 0x3d, 0x00, 0x47, 0x00, 0x50, 0x00, 0x58, 0x00, +0x00, 0x5d, 0x00, 0x59, 0x00, 0x4e, 0x00, 0x3e, 0x00, 0x2b, 0x00, 0x17, +0x00, 0x03, 0x0f, 0x00, 0x1f, 0x00, 0x2e, 0x00, 0x3b, 0x00, 0x46, 0x00, +0x50, 0x00, 0x59, 0x00, 0x60, 0x00, 0x66, 0x00, 0x42, 0x33, 0x43, 0x2c, +0x46, 0x27, 0x4a, 0x22, 0x4c, 0x1e, 0x4d, 0x1b, 0x52, 0x18, 0x55, 0x15, +0x57, 0x13, 0x58, 0x11, 0x5a, 0x0f, 0x5e, 0x0e, 0x62, 0x0c, 0x63, 0x0b, +0x65, 0x0a, 0x66, 0x09, 0x68, 0x08, 0x69, 0x07, 0x6b, 0x07, 0x6c, 0x06, +0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, +0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, +0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, +0xb7, 0x00, 0xb7, 0x00, 0x0a, 0x44, 0x0d, 0x3a, 0x12, 0x32, 0x16, 0x2b, +0x1b, 0x26, 0x1f, 0x22, 0x24, 0x1d, 0x28, 0x19, 0x2b, 0x16, 0x30, 0x14, +0x34, 0x12, 0x37, 0x0f, 0x3b, 0x0e, 0x3e, 0x0c, 0x41, 0x0b, 0x45, 0x0a, +0x47, 0x09, 0x4a, 0x07, 0x4e, 0x07, 0x4f, 0x05, 0x60, 0x22, 0x62, 0x1d, +0x65, 0x19, 0x66, 0x15, 0x69, 0x13, 0x6b, 0x11, 0x6d, 0x0e, 0x6f, 0x0c, +0x71, 0x0b, 0x73, 0x0a, 0x76, 0x09, 0x77, 0x07, 0x79, 0x07, 0x7a, 0x06, +0x7c, 0x05, 0x7e, 0x05, 0x7f, 0x04, 0x80, 0x03, 0x82, 0x03, 0x83, 0x02, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x1f, 0x00, +0x2c, 0x00, 0x37, 0x00, 0x41, 0x00, 0x4a, 0x00, 0x00, 0x5e, 0x00, 0x5b, +0x00, 0x53, 0x00, 0x48, 0x00, 0x3a, 0x00, 0x2a, 0x00, 0x1a, 0x00, 0x0b, +0x08, 0x05, 0x10, 0x00, 0x1e, 0x00, 0x2c, 0x00, 0x37, 0x00, 0x42, 0x00, +0x4b, 0x00, 0x53, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x9d, 0x00, 0x99, 0x00, 0x8e, 0x00, 0x7e, 0x00, 0x69, 0x00, 0x53, 0x00, +0x3c, 0x00, 0x26, 0x00, 0x12, 0x00, 0x00, 0x00, 0x10, 0x00, 0x1f, 0x00, +0x2c, 0x00, 0x37, 0x00, 0x41, 0x00, 0x4a, 0x00, 0x00, 0x5e, 0x00, 0x5b, +0x00, 0x52, 0x00, 0x45, 0x00, 0x34, 0x00, 0x22, 0x00, 0x10, 0x00, 0x00, +0x11, 0x00, 0x1f, 0x00, 0x2d, 0x00, 0x38, 0x00, 0x43, 0x00, 0x4c, 0x00, +0x54, 0x00, 0x5b, 0x00, 0x42, 0x33, 0x43, 0x2d, 0x45, 0x28, 0x49, 0x23, +0x4b, 0x1f, 0x4d, 0x1c, 0x50, 0x19, 0x55, 0x16, 0x56, 0x14, 0x58, 0x12, +0x59, 0x11, 0x5b, 0x0e, 0x5f, 0x0d, 0x62, 0x0c, 0x63, 0x0b, 0x65, 0x0a, +0x66, 0x09, 0x68, 0x09, 0x69, 0x07, 0x6b, 0x07, 0xb7, 0x00, 0xb7, 0x00, +0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, +0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, +0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, +0x0a, 0x44, 0x0d, 0x3a, 0x12, 0x33, 0x16, 0x2c, 0x19, 0x27, 0x1e, 0x22, +0x21, 0x1e, 0x26, 0x1a, 0x2b, 0x18, 0x2e, 0x16, 0x31, 0x12, 0x35, 0x11, +0x38, 0x0f, 0x3b, 0x0d, 0x3f, 0x0c, 0x41, 0x0a, 0x45, 0x0a, 0x47, 0x09, +0x4a, 0x07, 0x4e, 0x07, 0x60, 0x22, 0x62, 0x1d, 0x64, 0x19, 0x66, 0x16, +0x68, 0x13, 0x6a, 0x11, 0x6c, 0x0f, 0x6e, 0x0d, 0x71, 0x0c, 0x73, 0x0b, +0x74, 0x09, 0x76, 0x08, 0x78, 0x07, 0x79, 0x06, 0x7b, 0x06, 0x7c, 0x05, +0x7e, 0x05, 0x7f, 0x04, 0x80, 0x03, 0x82, 0x03, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x1c, 0x00, 0x28, 0x00, +0x33, 0x00, 0x3d, 0x00, 0x00, 0x5e, 0x00, 0x5c, 0x00, 0x56, 0x00, 0x4c, +0x00, 0x40, 0x00, 0x32, 0x00, 0x24, 0x00, 0x15, 0x02, 0x0a, 0x09, 0x04, +0x10, 0x00, 0x1d, 0x00, 0x29, 0x00, 0x34, 0x00, 0x3e, 0x00, 0x46, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9d, 0x00, 0x9a, 0x00, +0x91, 0x00, 0x83, 0x00, 0x72, 0x00, 0x5e, 0x00, 0x4a, 0x00, 0x36, 0x00, +0x22, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x1c, 0x00, 0x28, 0x00, +0x33, 0x00, 0x3d, 0x00, 0x00, 0x5e, 0x00, 0x5b, 0x00, 0x54, 0x00, 0x49, +0x00, 0x3b, 0x00, 0x2c, 0x00, 0x1b, 0x00, 0x0b, 0x04, 0x00, 0x12, 0x00, +0x1f, 0x00, 0x2b, 0x00, 0x36, 0x00, 0x40, 0x00, 0x49, 0x00, 0x50, 0x00, +0x42, 0x34, 0x43, 0x2e, 0x44, 0x29, 0x49, 0x24, 0x4b, 0x20, 0x4c, 0x1d, +0x4e, 0x1a, 0x53, 0x18, 0x55, 0x15, 0x56, 0x13, 0x58, 0x11, 0x5a, 0x10, +0x5c, 0x0e, 0x60, 0x0d, 0x63, 0x0c, 0x64, 0x0b, 0x65, 0x0a, 0x66, 0x09, +0x68, 0x09, 0x69, 0x07, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, +0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, +0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, +0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0x0a, 0x44, 0x0c, 0x3b, +0x11, 0x34, 0x16, 0x2e, 0x19, 0x28, 0x1d, 0x23, 0x21, 0x20, 0x25, 0x1d, +0x29, 0x19, 0x2b, 0x16, 0x30, 0x14, 0x33, 0x12, 0x35, 0x0f, 0x3a, 0x0f, +0x3c, 0x0c, 0x40, 0x0c, 0x41, 0x0a, 0x45, 0x0a, 0x47, 0x09, 0x4a, 0x07, +0x60, 0x22, 0x62, 0x1d, 0x64, 0x1a, 0x66, 0x17, 0x68, 0x14, 0x6a, 0x11, +0x6c, 0x10, 0x6e, 0x0e, 0x70, 0x0c, 0x71, 0x0b, 0x73, 0x0a, 0x75, 0x09, +0x76, 0x07, 0x78, 0x07, 0x79, 0x06, 0x7b, 0x06, 0x7c, 0x05, 0x7e, 0x05, +0x7f, 0x04, 0x80, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x1a, 0x00, 0x25, 0x00, 0x2f, 0x00, +0x00, 0x5e, 0x00, 0x5c, 0x00, 0x57, 0x00, 0x4f, 0x00, 0x44, 0x00, 0x38, +0x00, 0x2c, 0x00, 0x1f, 0x00, 0x12, 0x03, 0x09, 0x09, 0x04, 0x10, 0x00, +0x1c, 0x00, 0x27, 0x00, 0x31, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x9b, 0x00, 0x93, 0x00, 0x88, 0x00, +0x79, 0x00, 0x68, 0x00, 0x55, 0x00, 0x43, 0x00, 0x30, 0x00, 0x1f, 0x00, +0x0f, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x1a, 0x00, 0x25, 0x00, 0x2f, 0x00, +0x00, 0x5e, 0x00, 0x5c, 0x00, 0x56, 0x00, 0x4d, 0x00, 0x41, 0x00, 0x33, +0x00, 0x24, 0x00, 0x15, 0x00, 0x07, 0x06, 0x00, 0x13, 0x00, 0x1f, 0x00, +0x2a, 0x00, 0x34, 0x00, 0x3d, 0x00, 0x46, 0x00, 0x42, 0x34, 0x43, 0x2f, +0x44, 0x29, 0x49, 0x25, 0x4b, 0x21, 0x4c, 0x1e, 0x4d, 0x1b, 0x51, 0x18, +0x55, 0x16, 0x56, 0x14, 0x58, 0x13, 0x59, 0x11, 0x5a, 0x0f, 0x5d, 0x0e, +0x61, 0x0c, 0x63, 0x0c, 0x64, 0x0b, 0x65, 0x0a, 0x66, 0x09, 0x68, 0x09, +0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, +0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, +0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, +0xb7, 0x00, 0xb7, 0x00, 0x0a, 0x44, 0x0c, 0x3c, 0x10, 0x35, 0x15, 0x2f, +0x19, 0x2a, 0x1c, 0x25, 0x20, 0x22, 0x23, 0x1d, 0x26, 0x1a, 0x2b, 0x18, +0x2e, 0x16, 0x30, 0x12, 0x35, 0x12, 0x37, 0x0f, 0x3b, 0x0f, 0x3d, 0x0c, +0x41, 0x0c, 0x42, 0x0a, 0x46, 0x0a, 0x47, 0x09, 0x60, 0x22, 0x62, 0x1e, +0x64, 0x1a, 0x66, 0x17, 0x68, 0x15, 0x6a, 0x12, 0x6b, 0x11, 0x6d, 0x0e, +0x6e, 0x0d, 0x71, 0x0c, 0x72, 0x0b, 0x74, 0x09, 0x76, 0x09, 0x77, 0x07, +0x79, 0x07, 0x7a, 0x06, 0x7c, 0x06, 0x7c, 0x05, 0x7e, 0x05, 0x7f, 0x04, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x0c, 0x00, 0x18, 0x00, 0x22, 0x00, 0x00, 0x5e, 0x00, 0x5d, +0x00, 0x58, 0x00, 0x51, 0x00, 0x48, 0x00, 0x3e, 0x00, 0x32, 0x00, 0x26, +0x00, 0x1a, 0x00, 0x0f, 0x04, 0x08, 0x0a, 0x04, 0x10, 0x00, 0x1b, 0x00, +0x25, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x9e, 0x00, 0x9c, 0x00, 0x95, 0x00, 0x8b, 0x00, 0x7e, 0x00, 0x6f, 0x00, +0x5f, 0x00, 0x4e, 0x00, 0x3d, 0x00, 0x2c, 0x00, 0x1c, 0x00, 0x0d, 0x00, +0x00, 0x00, 0x0c, 0x00, 0x18, 0x00, 0x22, 0x00, 0x00, 0x5e, 0x00, 0x5d, +0x00, 0x57, 0x00, 0x4f, 0x00, 0x45, 0x00, 0x39, 0x00, 0x2c, 0x00, 0x1e, +0x00, 0x10, 0x00, 0x03, 0x08, 0x00, 0x14, 0x00, 0x1f, 0x00, 0x2a, 0x00, +0x33, 0x00, 0x3b, 0x00, 0x4f, 0x2a, 0x56, 0x28, 0x59, 0x27, 0x5a, 0x26, +0x5c, 0x26, 0x5c, 0x26, 0x5c, 0x26, 0x5d, 0x26, 0x5d, 0x26, 0x5d, 0x25, +0x5d, 0x25, 0x5d, 0x25, 0x5d, 0x25, 0x5d, 0x25, 0x5e, 0x25, 0x5e, 0x25, +0x5e, 0x24, 0x5e, 0x24, 0x5e, 0x24, 0x5e, 0x24, 0x92, 0x0e, 0x79, 0x14, +0x6f, 0x18, 0x6b, 0x1b, 0x68, 0x1d, 0x67, 0x1d, 0x66, 0x1e, 0x65, 0x1f, +0x64, 0x20, 0x64, 0x20, 0x63, 0x20, 0x63, 0x21, 0x63, 0x21, 0x63, 0x21, +0x63, 0x21, 0x62, 0x22, 0x62, 0x22, 0x62, 0x22, 0x62, 0x22, 0x62, 0x22, +0x16, 0x23, 0x3c, 0x23, 0x4a, 0x23, 0x50, 0x23, 0x54, 0x23, 0x56, 0x23, +0x58, 0x23, 0x59, 0x23, 0x5a, 0x23, 0x5a, 0x23, 0x5b, 0x23, 0x5b, 0x23, +0x5b, 0x23, 0x5c, 0x23, 0x5c, 0x23, 0x5c, 0x23, 0x5c, 0x23, 0x5c, 0x23, +0x5d, 0x23, 0x5d, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, +0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, +0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, +0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x0b, 0x00, 0x16, 0x00, 0x00, 0x5e, 0x00, 0x5d, 0x00, 0x59, 0x00, 0x53, +0x00, 0x4b, 0x00, 0x42, 0x00, 0x38, 0x00, 0x2d, 0x00, 0x22, 0x00, 0x17, +0x00, 0x0c, 0x05, 0x07, 0x0a, 0x03, 0x0f, 0x00, 0x1a, 0x00, 0x24, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x9c, 0x00, +0x97, 0x00, 0x8e, 0x00, 0x83, 0x00, 0x75, 0x00, 0x66, 0x00, 0x57, 0x00, +0x47, 0x00, 0x37, 0x00, 0x28, 0x00, 0x1a, 0x00, 0x0c, 0x00, 0x00, 0x00, +0x0b, 0x00, 0x16, 0x00, 0x00, 0x5e, 0x00, 0x5d, 0x00, 0x59, 0x00, 0x52, +0x00, 0x49, 0x00, 0x3e, 0x00, 0x32, 0x00, 0x25, 0x00, 0x19, 0x00, 0x0c, +0x00, 0x00, 0x0a, 0x00, 0x15, 0x00, 0x1f, 0x00, 0x29, 0x00, 0x31, 0x00, +0x48, 0x31, 0x4f, 0x2e, 0x53, 0x2c, 0x55, 0x2a, 0x57, 0x29, 0x58, 0x29, +0x59, 0x28, 0x59, 0x27, 0x5a, 0x27, 0x5b, 0x27, 0x5c, 0x27, 0x5c, 0x27, +0x5c, 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x5c, 0x27, +0x5c, 0x27, 0x5c, 0x27, 0xa1, 0x01, 0x88, 0x07, 0x7b, 0x0c, 0x74, 0x0f, +0x70, 0x12, 0x6d, 0x14, 0x6b, 0x16, 0x6a, 0x17, 0x69, 0x18, 0x68, 0x19, +0x67, 0x1a, 0x66, 0x1b, 0x66, 0x1b, 0x65, 0x1c, 0x65, 0x1c, 0x65, 0x1d, +0x65, 0x1d, 0x64, 0x1d, 0x64, 0x1e, 0x64, 0x1e, 0x0a, 0x32, 0x22, 0x25, +0x31, 0x24, 0x3b, 0x23, 0x42, 0x23, 0x47, 0x23, 0x4a, 0x23, 0x4d, 0x23, +0x4f, 0x23, 0x51, 0x23, 0x52, 0x23, 0x53, 0x23, 0x54, 0x23, 0x55, 0x23, +0x56, 0x23, 0x56, 0x23, 0x57, 0x23, 0x58, 0x23, 0x58, 0x23, 0x58, 0x23, +0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, +0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, +0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, +0x60, 0x23, 0x60, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, +0x00, 0x5f, 0x00, 0x5d, 0x00, 0x5a, 0x00, 0x55, 0x00, 0x4e, 0x00, 0x45, +0x00, 0x3c, 0x00, 0x32, 0x00, 0x28, 0x00, 0x1e, 0x00, 0x14, 0x00, 0x0b, +0x06, 0x07, 0x0b, 0x03, 0x0f, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x9c, 0x00, 0x98, 0x00, 0x90, 0x00, +0x86, 0x00, 0x7a, 0x00, 0x6d, 0x00, 0x5f, 0x00, 0x50, 0x00, 0x41, 0x00, +0x33, 0x00, 0x25, 0x00, 0x18, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0a, 0x00, +0x00, 0x5e, 0x00, 0x5d, 0x00, 0x59, 0x00, 0x53, 0x00, 0x4b, 0x00, 0x42, +0x00, 0x37, 0x00, 0x2c, 0x00, 0x20, 0x00, 0x14, 0x00, 0x09, 0x01, 0x00, +0x0c, 0x00, 0x16, 0x00, 0x1f, 0x00, 0x28, 0x00, 0x45, 0x34, 0x4b, 0x31, +0x4f, 0x2f, 0x52, 0x2d, 0x54, 0x2c, 0x55, 0x2b, 0x57, 0x2a, 0x57, 0x2a, +0x57, 0x2a, 0x57, 0x29, 0x58, 0x29, 0x59, 0x28, 0x59, 0x27, 0x5a, 0x27, +0x5c, 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x5c, 0x27, +0xa7, 0x00, 0x92, 0x03, 0x84, 0x06, 0x7d, 0x09, 0x77, 0x0c, 0x73, 0x0e, +0x71, 0x10, 0x6f, 0x11, 0x6d, 0x13, 0x6b, 0x14, 0x6a, 0x15, 0x6a, 0x16, +0x69, 0x17, 0x68, 0x17, 0x68, 0x18, 0x67, 0x19, 0x66, 0x19, 0x66, 0x1a, +0x66, 0x1a, 0x66, 0x1a, 0x0a, 0x38, 0x18, 0x2b, 0x25, 0x27, 0x2e, 0x25, +0x35, 0x24, 0x3b, 0x23, 0x3f, 0x23, 0x43, 0x23, 0x46, 0x23, 0x48, 0x23, +0x4a, 0x23, 0x4c, 0x23, 0x4e, 0x23, 0x4f, 0x23, 0x50, 0x23, 0x51, 0x23, +0x52, 0x23, 0x53, 0x23, 0x53, 0x23, 0x54, 0x23, 0x60, 0x23, 0x60, 0x23, +0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, +0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, +0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x5e, +0x00, 0x5b, 0x00, 0x56, 0x00, 0x50, 0x00, 0x48, 0x00, 0x40, 0x00, 0x37, +0x00, 0x2d, 0x00, 0x24, 0x00, 0x1a, 0x00, 0x11, 0x01, 0x0a, 0x06, 0x06, +0x0b, 0x03, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x9e, 0x00, 0x9d, 0x00, 0x99, 0x00, 0x92, 0x00, 0x89, 0x00, 0x7e, 0x00, +0x72, 0x00, 0x66, 0x00, 0x58, 0x00, 0x4a, 0x00, 0x3d, 0x00, 0x2f, 0x00, +0x22, 0x00, 0x16, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x5d, +0x00, 0x5a, 0x00, 0x55, 0x00, 0x4e, 0x00, 0x45, 0x00, 0x3c, 0x00, 0x31, +0x00, 0x26, 0x00, 0x1b, 0x00, 0x11, 0x00, 0x06, 0x03, 0x00, 0x0d, 0x00, +0x17, 0x00, 0x1f, 0x00, 0x44, 0x36, 0x49, 0x33, 0x4d, 0x31, 0x4f, 0x2f, +0x51, 0x2e, 0x53, 0x2d, 0x53, 0x2c, 0x55, 0x2b, 0x56, 0x2a, 0x57, 0x2a, +0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x29, 0x58, 0x29, +0x59, 0x28, 0x5a, 0x27, 0x5b, 0x27, 0x5c, 0x27, 0xaa, 0x00, 0x98, 0x01, +0x8c, 0x03, 0x83, 0x05, 0x7d, 0x08, 0x79, 0x0a, 0x76, 0x0c, 0x73, 0x0d, +0x71, 0x0f, 0x6f, 0x10, 0x6e, 0x11, 0x6d, 0x12, 0x6c, 0x13, 0x6b, 0x14, +0x6a, 0x15, 0x6a, 0x15, 0x69, 0x16, 0x68, 0x17, 0x68, 0x17, 0x68, 0x18, +0x0a, 0x3c, 0x14, 0x30, 0x1e, 0x2a, 0x26, 0x27, 0x2d, 0x25, 0x32, 0x24, +0x36, 0x24, 0x3b, 0x24, 0x3e, 0x23, 0x41, 0x23, 0x43, 0x23, 0x45, 0x23, +0x47, 0x23, 0x49, 0x23, 0x4a, 0x23, 0x4c, 0x23, 0x4d, 0x23, 0x4d, 0x23, +0x4f, 0x23, 0x50, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, +0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, +0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, +0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x31, 0x11, 0x5f, 0x00, 0x85, 0x00, 0x92, 0x00, +0x97, 0x00, 0x9a, 0x00, 0x9b, 0x00, 0x9c, 0x00, 0x9d, 0x00, 0x9d, 0x00, +0x9e, 0x00, 0x9e, 0x00, 0x9e, 0x00, 0x9e, 0x00, 0x9e, 0x00, 0x9e, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x31, 0x11, 0x03, 0x23, +0x00, 0x46, 0x00, 0x52, 0x00, 0x58, 0x00, 0x5a, 0x00, 0x5c, 0x00, 0x5d, +0x00, 0x5d, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x5e, +0x00, 0x5e, 0x00, 0x5f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x43, 0x38, 0x48, 0x35, 0x4b, 0x32, 0x4e, 0x31, 0x4f, 0x30, 0x50, 0x2e, +0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2c, 0x54, 0x2b, 0x56, 0x2a, 0x57, 0x2a, +0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, +0x57, 0x2a, 0x58, 0x29, 0xac, 0x00, 0x9d, 0x00, 0x91, 0x02, 0x89, 0x03, +0x82, 0x05, 0x7e, 0x07, 0x7a, 0x09, 0x77, 0x0a, 0x75, 0x0c, 0x73, 0x0d, +0x71, 0x0e, 0x70, 0x0f, 0x6e, 0x10, 0x6e, 0x11, 0x6c, 0x12, 0x6c, 0x13, +0x6b, 0x13, 0x6a, 0x14, 0x6a, 0x15, 0x6a, 0x15, 0x09, 0x3f, 0x11, 0x33, +0x1a, 0x2d, 0x21, 0x29, 0x27, 0x27, 0x2c, 0x26, 0x30, 0x25, 0x34, 0x24, +0x37, 0x24, 0x3a, 0x24, 0x3d, 0x23, 0x40, 0x23, 0x42, 0x23, 0x44, 0x23, +0x45, 0x23, 0x47, 0x23, 0x48, 0x23, 0x49, 0x23, 0x4a, 0x23, 0x4c, 0x23, +0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, +0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, +0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, +0x60, 0x23, 0x60, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x03, 0x23, 0x20, 0x00, 0x5f, 0x00, 0x7c, 0x00, 0x8a, 0x00, 0x91, 0x00, +0x95, 0x00, 0x97, 0x00, 0x99, 0x00, 0x9a, 0x00, 0x9b, 0x00, 0x9c, 0x00, +0x9c, 0x00, 0x9d, 0x00, 0x9d, 0x00, 0x9d, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x20, 0x00, 0x00, 0x1f, 0x00, 0x3c, +0x00, 0x4a, 0x00, 0x51, 0x00, 0x55, 0x00, 0x58, 0x00, 0x59, 0x00, 0x5b, +0x00, 0x5b, 0x00, 0x5c, 0x00, 0x5d, 0x00, 0x5d, 0x00, 0x5d, 0x00, 0x5d, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0x39, 0x46, 0x36, +0x4a, 0x34, 0x4b, 0x32, 0x4e, 0x31, 0x4f, 0x30, 0x50, 0x2e, 0x53, 0x2e, +0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2d, 0x54, 0x2b, 0x55, 0x2a, 0x57, 0x2a, +0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, +0xae, 0x00, 0xa1, 0x00, 0x96, 0x01, 0x8d, 0x02, 0x87, 0x03, 0x82, 0x05, +0x7e, 0x07, 0x7b, 0x08, 0x78, 0x09, 0x76, 0x0b, 0x74, 0x0c, 0x73, 0x0d, +0x71, 0x0e, 0x70, 0x0e, 0x6f, 0x0f, 0x6e, 0x11, 0x6d, 0x11, 0x6c, 0x11, +0x6c, 0x12, 0x6b, 0x13, 0x09, 0x40, 0x10, 0x36, 0x17, 0x2f, 0x1d, 0x2c, +0x22, 0x29, 0x27, 0x27, 0x2b, 0x26, 0x2f, 0x25, 0x32, 0x25, 0x35, 0x24, +0x38, 0x24, 0x3b, 0x24, 0x3c, 0x24, 0x3f, 0x23, 0x40, 0x23, 0x42, 0x23, +0x44, 0x23, 0x45, 0x23, 0x46, 0x23, 0x48, 0x23, 0x60, 0x23, 0x60, 0x23, +0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, +0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, +0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x00, 0x1f, +0x1f, 0x00, 0x4d, 0x00, 0x68, 0x00, 0x79, 0x00, 0x83, 0x00, 0x8a, 0x00, +0x8e, 0x00, 0x92, 0x00, 0x94, 0x00, 0x96, 0x00, 0x97, 0x00, 0x98, 0x00, +0x99, 0x00, 0x9a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x85, 0x00, 0x5f, 0x00, 0x1f, 0x00, 0x00, 0x0d, 0x00, 0x28, 0x00, 0x39, +0x00, 0x43, 0x00, 0x4a, 0x00, 0x4e, 0x00, 0x52, 0x00, 0x54, 0x00, 0x56, +0x00, 0x57, 0x00, 0x59, 0x00, 0x59, 0x00, 0x5a, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x42, 0x39, 0x45, 0x37, 0x48, 0x35, 0x4a, 0x33, +0x4c, 0x31, 0x4f, 0x31, 0x4f, 0x30, 0x50, 0x2e, 0x52, 0x2e, 0x53, 0x2e, +0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2d, 0x54, 0x2c, 0x55, 0x2a, 0x57, 0x2a, +0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0xaf, 0x00, 0xa3, 0x00, +0x99, 0x00, 0x91, 0x01, 0x8b, 0x02, 0x86, 0x03, 0x81, 0x05, 0x7e, 0x06, +0x7b, 0x07, 0x79, 0x09, 0x77, 0x0a, 0x75, 0x0b, 0x74, 0x0c, 0x73, 0x0c, +0x71, 0x0d, 0x71, 0x0e, 0x6f, 0x0f, 0x6e, 0x10, 0x6e, 0x11, 0x6d, 0x11, +0x09, 0x41, 0x0f, 0x38, 0x15, 0x32, 0x1a, 0x2e, 0x1f, 0x2b, 0x24, 0x29, +0x27, 0x27, 0x2b, 0x26, 0x2e, 0x25, 0x31, 0x25, 0x34, 0x25, 0x36, 0x24, +0x38, 0x24, 0x3b, 0x24, 0x3c, 0x24, 0x3e, 0x23, 0x40, 0x23, 0x41, 0x23, +0x43, 0x23, 0x44, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, +0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, +0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, +0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x52, 0x00, 0x3c, 0x00, 0x0d, 0x1f, 0x00, +0x42, 0x00, 0x5a, 0x00, 0x6a, 0x00, 0x76, 0x00, 0x7e, 0x00, 0x84, 0x00, +0x89, 0x00, 0x8c, 0x00, 0x8f, 0x00, 0x91, 0x00, 0x93, 0x00, 0x95, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x92, 0x00, 0x7c, 0x00, +0x4d, 0x00, 0x1f, 0x00, 0x00, 0x02, 0x00, 0x1a, 0x00, 0x2a, 0x00, 0x36, +0x00, 0x3e, 0x00, 0x45, 0x00, 0x49, 0x00, 0x4d, 0x00, 0x4f, 0x00, 0x52, +0x00, 0x53, 0x00, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x42, 0x3a, 0x45, 0x38, 0x47, 0x35, 0x4a, 0x35, 0x4a, 0x33, 0x4d, 0x31, +0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x2f, 0x52, 0x2e, 0x53, 0x2e, 0x53, 0x2e, +0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2d, 0x53, 0x2c, 0x55, 0x2b, 0x57, 0x2a, +0x57, 0x2a, 0x57, 0x2a, 0xb0, 0x00, 0xa5, 0x00, 0x9d, 0x00, 0x95, 0x00, +0x8e, 0x02, 0x89, 0x02, 0x85, 0x03, 0x81, 0x05, 0x7e, 0x06, 0x7c, 0x07, +0x7a, 0x08, 0x78, 0x09, 0x76, 0x0a, 0x75, 0x0b, 0x73, 0x0c, 0x73, 0x0c, +0x71, 0x0d, 0x71, 0x0e, 0x70, 0x0e, 0x6e, 0x0f, 0x09, 0x42, 0x0e, 0x39, +0x13, 0x33, 0x18, 0x2f, 0x1c, 0x2d, 0x21, 0x2a, 0x24, 0x29, 0x28, 0x27, +0x2b, 0x26, 0x2e, 0x26, 0x30, 0x25, 0x33, 0x25, 0x35, 0x25, 0x37, 0x24, +0x39, 0x24, 0x3b, 0x24, 0x3c, 0x24, 0x3d, 0x24, 0x3f, 0x23, 0x40, 0x23, +0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, +0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, +0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, +0x60, 0x23, 0x60, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x58, 0x00, 0x4a, 0x00, 0x28, 0x00, 0x02, 0x1f, 0x00, 0x3b, 0x00, +0x4f, 0x00, 0x5f, 0x00, 0x6b, 0x00, 0x74, 0x00, 0x7b, 0x00, 0x80, 0x00, +0x85, 0x00, 0x88, 0x00, 0x8b, 0x00, 0x8d, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x97, 0x00, 0x8a, 0x00, 0x68, 0x00, 0x42, 0x00, +0x1f, 0x00, 0x04, 0x00, 0x00, 0x10, 0x00, 0x1f, 0x00, 0x2b, 0x00, 0x34, +0x00, 0x3b, 0x00, 0x41, 0x00, 0x45, 0x00, 0x49, 0x00, 0x4b, 0x00, 0x4e, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x3b, 0x44, 0x39, +0x46, 0x36, 0x49, 0x35, 0x4a, 0x34, 0x4b, 0x32, 0x4e, 0x31, 0x4f, 0x31, +0x4f, 0x31, 0x4f, 0x2f, 0x51, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, +0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2c, 0x54, 0x2b, 0x56, 0x2a, +0xb1, 0x00, 0xa8, 0x00, 0x9f, 0x00, 0x98, 0x00, 0x91, 0x01, 0x8c, 0x02, +0x88, 0x03, 0x84, 0x04, 0x81, 0x05, 0x7e, 0x06, 0x7c, 0x07, 0x7a, 0x07, +0x79, 0x09, 0x77, 0x09, 0x76, 0x0b, 0x74, 0x0b, 0x73, 0x0c, 0x73, 0x0c, +0x71, 0x0d, 0x71, 0x0e, 0x09, 0x43, 0x0e, 0x3b, 0x12, 0x35, 0x16, 0x31, +0x1a, 0x2e, 0x1e, 0x2c, 0x22, 0x2a, 0x25, 0x28, 0x28, 0x27, 0x2a, 0x27, +0x2d, 0x26, 0x30, 0x25, 0x32, 0x25, 0x34, 0x25, 0x35, 0x25, 0x37, 0x24, +0x39, 0x24, 0x3b, 0x24, 0x3c, 0x24, 0x3d, 0x24, 0x60, 0x23, 0x60, 0x23, +0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, +0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, +0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5a, 0x00, 0x51, +0x00, 0x39, 0x00, 0x1a, 0x04, 0x00, 0x1f, 0x00, 0x36, 0x00, 0x48, 0x00, +0x57, 0x00, 0x62, 0x00, 0x6b, 0x00, 0x73, 0x00, 0x79, 0x00, 0x7e, 0x00, +0x82, 0x00, 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x9a, 0x00, 0x91, 0x00, 0x79, 0x00, 0x5a, 0x00, 0x3b, 0x00, 0x1f, 0x00, +0x09, 0x00, 0x00, 0x08, 0x00, 0x17, 0x00, 0x22, 0x00, 0x2c, 0x00, 0x33, +0x00, 0x39, 0x00, 0x3e, 0x00, 0x42, 0x00, 0x45, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x42, 0x3b, 0x44, 0x39, 0x46, 0x37, 0x48, 0x35, +0x4a, 0x35, 0x4a, 0x34, 0x4c, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, +0x4f, 0x30, 0x50, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, +0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2d, 0xb1, 0x00, 0xa9, 0x00, +0xa1, 0x00, 0x9a, 0x00, 0x94, 0x00, 0x8f, 0x01, 0x8b, 0x02, 0x87, 0x03, +0x84, 0x04, 0x81, 0x05, 0x7f, 0x06, 0x7d, 0x06, 0x7b, 0x07, 0x79, 0x08, +0x78, 0x09, 0x76, 0x0a, 0x76, 0x0b, 0x74, 0x0b, 0x73, 0x0c, 0x72, 0x0c, +0x09, 0x44, 0x0d, 0x3c, 0x11, 0x36, 0x15, 0x33, 0x19, 0x30, 0x1c, 0x2d, +0x20, 0x2b, 0x23, 0x2a, 0x25, 0x28, 0x28, 0x27, 0x2a, 0x27, 0x2d, 0x26, +0x2f, 0x26, 0x31, 0x25, 0x33, 0x25, 0x34, 0x25, 0x36, 0x24, 0x38, 0x24, +0x39, 0x24, 0x3a, 0x24, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, +0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, +0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, +0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x55, 0x00, 0x43, 0x00, 0x2a, +0x00, 0x10, 0x09, 0x00, 0x1f, 0x00, 0x33, 0x00, 0x43, 0x00, 0x50, 0x00, +0x5b, 0x00, 0x64, 0x00, 0x6b, 0x00, 0x72, 0x00, 0x77, 0x00, 0x7b, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9b, 0x00, 0x95, 0x00, +0x83, 0x00, 0x6a, 0x00, 0x4f, 0x00, 0x36, 0x00, 0x1f, 0x00, 0x0c, 0x00, +0x00, 0x03, 0x00, 0x10, 0x00, 0x1b, 0x00, 0x24, 0x00, 0x2c, 0x00, 0x32, +0x00, 0x37, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x42, 0x3c, 0x43, 0x39, 0x46, 0x38, 0x46, 0x35, 0x4a, 0x35, 0x4a, 0x35, +0x4a, 0x33, 0x4d, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x30, +0x50, 0x2e, 0x52, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, +0x53, 0x2e, 0x53, 0x2e, 0xb2, 0x00, 0xaa, 0x00, 0xa2, 0x00, 0x9c, 0x00, +0x96, 0x00, 0x91, 0x01, 0x8d, 0x02, 0x89, 0x02, 0x86, 0x03, 0x83, 0x04, +0x81, 0x05, 0x7f, 0x06, 0x7d, 0x06, 0x7b, 0x07, 0x79, 0x07, 0x79, 0x09, +0x77, 0x09, 0x76, 0x0a, 0x75, 0x0b, 0x74, 0x0b, 0x0a, 0x44, 0x0d, 0x3d, +0x10, 0x38, 0x14, 0x34, 0x17, 0x31, 0x1b, 0x2e, 0x1e, 0x2d, 0x21, 0x2b, +0x23, 0x2a, 0x26, 0x28, 0x28, 0x28, 0x2a, 0x27, 0x2d, 0x26, 0x2e, 0x26, +0x30, 0x25, 0x32, 0x25, 0x34, 0x25, 0x35, 0x25, 0x36, 0x24, 0x38, 0x24, +0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, +0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, +0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, +0x60, 0x23, 0x60, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x5d, 0x00, 0x58, 0x00, 0x4a, 0x00, 0x36, 0x00, 0x1f, 0x00, 0x08, +0x0c, 0x00, 0x1f, 0x00, 0x30, 0x00, 0x3f, 0x00, 0x4b, 0x00, 0x55, 0x00, +0x5e, 0x00, 0x65, 0x00, 0x6c, 0x00, 0x71, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x9c, 0x00, 0x97, 0x00, 0x8a, 0x00, 0x76, 0x00, +0x5f, 0x00, 0x48, 0x00, 0x33, 0x00, 0x1f, 0x00, 0x0f, 0x00, 0x00, 0x00, +0x00, 0x0b, 0x00, 0x15, 0x00, 0x1e, 0x00, 0x25, 0x00, 0x2c, 0x00, 0x31, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x3c, 0x43, 0x39, +0x46, 0x39, 0x46, 0x37, 0x49, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4b, 0x32, +0x4e, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x2f, +0x52, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, +0xb2, 0x00, 0xab, 0x00, 0xa4, 0x00, 0x9e, 0x00, 0x98, 0x00, 0x93, 0x00, +0x8f, 0x01, 0x8b, 0x02, 0x88, 0x02, 0x85, 0x03, 0x83, 0x04, 0x81, 0x05, +0x7f, 0x06, 0x7d, 0x06, 0x7c, 0x07, 0x7a, 0x07, 0x79, 0x08, 0x78, 0x09, +0x76, 0x09, 0x76, 0x0a, 0x0a, 0x44, 0x0c, 0x3e, 0x10, 0x39, 0x13, 0x35, +0x16, 0x32, 0x19, 0x30, 0x1c, 0x2e, 0x1f, 0x2c, 0x21, 0x2b, 0x24, 0x2a, +0x26, 0x28, 0x28, 0x28, 0x2a, 0x27, 0x2c, 0x26, 0x2e, 0x26, 0x30, 0x25, +0x31, 0x25, 0x33, 0x25, 0x34, 0x25, 0x36, 0x25, 0x60, 0x23, 0x60, 0x23, +0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, +0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, +0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5d, 0x00, 0x59, +0x00, 0x4e, 0x00, 0x3e, 0x00, 0x2b, 0x00, 0x17, 0x00, 0x03, 0x0f, 0x00, +0x1f, 0x00, 0x2e, 0x00, 0x3b, 0x00, 0x46, 0x00, 0x50, 0x00, 0x59, 0x00, +0x60, 0x00, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x9d, 0x00, 0x99, 0x00, 0x8e, 0x00, 0x7e, 0x00, 0x6b, 0x00, 0x57, 0x00, +0x43, 0x00, 0x30, 0x00, 0x1f, 0x00, 0x11, 0x00, 0x04, 0x00, 0x00, 0x07, +0x00, 0x10, 0x00, 0x19, 0x00, 0x20, 0x00, 0x26, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x42, 0x3d, 0x42, 0x39, 0x46, 0x39, 0x46, 0x38, +0x47, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x34, 0x4b, 0x32, 0x4e, 0x31, +0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x2f, 0x51, 0x2e, +0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0xb2, 0x00, 0xac, 0x00, +0xa5, 0x00, 0x9f, 0x00, 0x9a, 0x00, 0x96, 0x00, 0x91, 0x01, 0x8e, 0x01, +0x8a, 0x02, 0x88, 0x02, 0x85, 0x03, 0x83, 0x04, 0x81, 0x05, 0x7f, 0x05, +0x7d, 0x06, 0x7c, 0x07, 0x7a, 0x07, 0x79, 0x07, 0x78, 0x09, 0x77, 0x09, +0x0a, 0x44, 0x0c, 0x3f, 0x0f, 0x3a, 0x12, 0x36, 0x15, 0x33, 0x18, 0x30, +0x1b, 0x2e, 0x1d, 0x2d, 0x20, 0x2b, 0x22, 0x2a, 0x24, 0x2a, 0x26, 0x28, +0x28, 0x28, 0x2a, 0x27, 0x2c, 0x26, 0x2e, 0x26, 0x2f, 0x26, 0x31, 0x25, +0x33, 0x25, 0x33, 0x25, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, +0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, +0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, +0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x5b, 0x00, 0x52, 0x00, 0x45, +0x00, 0x34, 0x00, 0x22, 0x00, 0x10, 0x00, 0x00, 0x11, 0x00, 0x1f, 0x00, +0x2d, 0x00, 0x38, 0x00, 0x43, 0x00, 0x4c, 0x00, 0x54, 0x00, 0x5b, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9d, 0x00, 0x9a, 0x00, +0x92, 0x00, 0x84, 0x00, 0x74, 0x00, 0x62, 0x00, 0x50, 0x00, 0x3f, 0x00, +0x2e, 0x00, 0x1f, 0x00, 0x12, 0x00, 0x06, 0x00, 0x00, 0x03, 0x00, 0x0c, +0x00, 0x14, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x42, 0x3d, 0x42, 0x3a, 0x45, 0x39, 0x46, 0x39, 0x46, 0x36, 0x49, 0x35, +0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x33, 0x4d, 0x31, 0x4f, 0x31, 0x4f, 0x31, +0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x30, 0x50, 0x2e, 0x53, 0x2e, +0x53, 0x2e, 0x53, 0x2e, 0xb3, 0x00, 0xac, 0x00, 0xa7, 0x00, 0xa1, 0x00, +0x9b, 0x00, 0x97, 0x00, 0x93, 0x00, 0x8f, 0x01, 0x8c, 0x02, 0x89, 0x02, +0x87, 0x02, 0x85, 0x03, 0x82, 0x04, 0x81, 0x05, 0x7f, 0x05, 0x7d, 0x06, +0x7c, 0x06, 0x7b, 0x07, 0x79, 0x07, 0x79, 0x08, 0x0a, 0x45, 0x0c, 0x3f, +0x0f, 0x3a, 0x11, 0x37, 0x14, 0x34, 0x17, 0x32, 0x1a, 0x30, 0x1c, 0x2e, +0x1e, 0x2d, 0x21, 0x2b, 0x22, 0x2a, 0x25, 0x2a, 0x26, 0x28, 0x28, 0x28, +0x2a, 0x27, 0x2c, 0x27, 0x2d, 0x26, 0x2f, 0x26, 0x30, 0x25, 0x32, 0x25, +0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, +0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, +0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, +0x60, 0x23, 0x60, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x5e, 0x00, 0x5b, 0x00, 0x54, 0x00, 0x49, 0x00, 0x3b, 0x00, 0x2c, +0x00, 0x1b, 0x00, 0x0b, 0x04, 0x00, 0x12, 0x00, 0x1f, 0x00, 0x2b, 0x00, +0x36, 0x00, 0x40, 0x00, 0x49, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x9b, 0x00, 0x94, 0x00, 0x89, 0x00, +0x7b, 0x00, 0x6b, 0x00, 0x5b, 0x00, 0x4b, 0x00, 0x3b, 0x00, 0x2d, 0x00, +0x1f, 0x00, 0x13, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x11, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x3d, 0x42, 0x3a, +0x44, 0x39, 0x46, 0x39, 0x46, 0x37, 0x48, 0x35, 0x4a, 0x35, 0x4a, 0x35, +0x4a, 0x35, 0x4a, 0x33, 0x4d, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, +0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x30, 0x50, 0x2e, 0x53, 0x2e, 0x53, 0x2e, +0xb3, 0x00, 0xad, 0x00, 0xa7, 0x00, 0xa3, 0x00, 0x9d, 0x00, 0x99, 0x00, +0x95, 0x00, 0x91, 0x01, 0x8e, 0x01, 0x8b, 0x02, 0x88, 0x02, 0x86, 0x02, +0x84, 0x03, 0x82, 0x04, 0x81, 0x05, 0x7f, 0x05, 0x7e, 0x06, 0x7c, 0x06, +0x7b, 0x07, 0x7a, 0x07, 0x0a, 0x45, 0x0c, 0x40, 0x0e, 0x3b, 0x11, 0x38, +0x13, 0x35, 0x16, 0x32, 0x18, 0x30, 0x1b, 0x2e, 0x1d, 0x2d, 0x1f, 0x2c, +0x21, 0x2b, 0x23, 0x2a, 0x25, 0x29, 0x27, 0x28, 0x28, 0x28, 0x2a, 0x27, +0x2c, 0x27, 0x2d, 0x26, 0x2f, 0x26, 0x2f, 0x25, 0x60, 0x23, 0x60, 0x23, +0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, +0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, +0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x5c, +0x00, 0x56, 0x00, 0x4d, 0x00, 0x41, 0x00, 0x33, 0x00, 0x24, 0x00, 0x15, +0x00, 0x07, 0x06, 0x00, 0x13, 0x00, 0x1f, 0x00, 0x2a, 0x00, 0x34, 0x00, +0x3d, 0x00, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x9e, 0x00, 0x9c, 0x00, 0x96, 0x00, 0x8c, 0x00, 0x80, 0x00, 0x73, 0x00, +0x64, 0x00, 0x55, 0x00, 0x46, 0x00, 0x38, 0x00, 0x2b, 0x00, 0x1f, 0x00, +0x14, 0x00, 0x0a, 0x00, 0x01, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x42, 0x3d, 0x42, 0x3b, 0x44, 0x39, 0x46, 0x39, +0x46, 0x38, 0x47, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x34, +0x4b, 0x32, 0x4e, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, +0x4f, 0x31, 0x4f, 0x30, 0x50, 0x2f, 0x52, 0x2e, 0xb3, 0x00, 0xae, 0x00, +0xa8, 0x00, 0xa3, 0x00, 0x9f, 0x00, 0x9a, 0x00, 0x96, 0x00, 0x93, 0x00, +0x8f, 0x01, 0x8d, 0x02, 0x8a, 0x02, 0x88, 0x02, 0x86, 0x03, 0x84, 0x03, +0x82, 0x04, 0x81, 0x05, 0x7f, 0x05, 0x7e, 0x06, 0x7c, 0x06, 0x7c, 0x07, +0x0a, 0x45, 0x0c, 0x40, 0x0e, 0x3c, 0x11, 0x38, 0x13, 0x36, 0x15, 0x33, +0x18, 0x31, 0x1a, 0x30, 0x1c, 0x2e, 0x1e, 0x2d, 0x20, 0x2b, 0x22, 0x2b, +0x23, 0x2a, 0x25, 0x29, 0x27, 0x28, 0x28, 0x28, 0x2a, 0x27, 0x2c, 0x27, +0x2d, 0x26, 0x2f, 0x26, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, +0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, +0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, +0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x5d, 0x00, 0x57, 0x00, 0x4f, +0x00, 0x45, 0x00, 0x39, 0x00, 0x2c, 0x00, 0x1e, 0x00, 0x10, 0x00, 0x03, +0x08, 0x00, 0x14, 0x00, 0x1f, 0x00, 0x2a, 0x00, 0x33, 0x00, 0x3b, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x9c, 0x00, +0x97, 0x00, 0x8f, 0x00, 0x85, 0x00, 0x79, 0x00, 0x6b, 0x00, 0x5e, 0x00, +0x50, 0x00, 0x43, 0x00, 0x36, 0x00, 0x2a, 0x00, 0x1f, 0x00, 0x15, 0x00, +0x0c, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x42, 0x3d, 0x42, 0x3c, 0x43, 0x39, 0x46, 0x39, 0x46, 0x39, 0x46, 0x36, +0x49, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x33, 0x4c, 0x31, +0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, +0x4f, 0x31, 0x4f, 0x2f, 0xb3, 0x00, 0xae, 0x00, 0xa9, 0x00, 0xa4, 0x00, +0xa0, 0x00, 0x9b, 0x00, 0x98, 0x00, 0x94, 0x00, 0x91, 0x01, 0x8e, 0x01, +0x8c, 0x02, 0x89, 0x02, 0x87, 0x02, 0x86, 0x03, 0x84, 0x03, 0x82, 0x04, +0x80, 0x05, 0x7f, 0x05, 0x7e, 0x06, 0x7c, 0x06, 0x0a, 0x45, 0x0b, 0x40, +0x0e, 0x3c, 0x10, 0x39, 0x12, 0x37, 0x14, 0x34, 0x17, 0x32, 0x19, 0x30, +0x1b, 0x2e, 0x1d, 0x2d, 0x1f, 0x2d, 0x20, 0x2b, 0x22, 0x2b, 0x24, 0x2a, +0x25, 0x29, 0x27, 0x28, 0x28, 0x28, 0x2a, 0x27, 0x2c, 0x27, 0x2c, 0x26, +0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, +0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, +0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, +0x60, 0x23, 0x60, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x5e, 0x00, 0x5d, 0x00, 0x59, 0x00, 0x52, 0x00, 0x49, 0x00, 0x3e, +0x00, 0x32, 0x00, 0x25, 0x00, 0x19, 0x00, 0x0c, 0x00, 0x00, 0x0a, 0x00, +0x15, 0x00, 0x1f, 0x00, 0x29, 0x00, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x9d, 0x00, 0x98, 0x00, 0x91, 0x00, +0x88, 0x00, 0x7e, 0x00, 0x72, 0x00, 0x65, 0x00, 0x59, 0x00, 0x4c, 0x00, +0x40, 0x00, 0x34, 0x00, 0x2a, 0x00, 0x1f, 0x00, 0x16, 0x00, 0x0d, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x3d, 0x42, 0x3c, +0x43, 0x39, 0x46, 0x39, 0x46, 0x39, 0x46, 0x37, 0x48, 0x35, 0x4a, 0x35, +0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x33, 0x4d, 0x31, 0x4f, 0x31, +0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, +0xb3, 0x00, 0xae, 0x00, 0xaa, 0x00, 0xa5, 0x00, 0xa1, 0x00, 0x9d, 0x00, +0x99, 0x00, 0x96, 0x00, 0x93, 0x00, 0x90, 0x01, 0x8d, 0x01, 0x8b, 0x02, +0x89, 0x02, 0x87, 0x02, 0x85, 0x03, 0x83, 0x03, 0x82, 0x04, 0x80, 0x05, +0x7f, 0x05, 0x7e, 0x06, 0x0a, 0x45, 0x0b, 0x41, 0x0e, 0x3d, 0x10, 0x3a, +0x11, 0x37, 0x14, 0x34, 0x16, 0x32, 0x18, 0x31, 0x1a, 0x30, 0x1c, 0x2e, +0x1d, 0x2d, 0x20, 0x2c, 0x21, 0x2b, 0x22, 0x2a, 0x24, 0x2a, 0x25, 0x29, +0x27, 0x28, 0x28, 0x28, 0x2a, 0x27, 0x2c, 0x27, 0x60, 0x23, 0x60, 0x23, +0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, +0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, +0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x5d, +0x00, 0x59, 0x00, 0x53, 0x00, 0x4b, 0x00, 0x42, 0x00, 0x37, 0x00, 0x2c, +0x00, 0x20, 0x00, 0x14, 0x00, 0x09, 0x01, 0x00, 0x0c, 0x00, 0x16, 0x00, +0x1f, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x9e, 0x00, 0x9d, 0x00, 0x99, 0x00, 0x93, 0x00, 0x8b, 0x00, 0x82, 0x00, +0x77, 0x00, 0x6c, 0x00, 0x60, 0x00, 0x54, 0x00, 0x49, 0x00, 0x3d, 0x00, +0x33, 0x00, 0x29, 0x00, 0x1f, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x39, 0x46, 0x39, +0x46, 0x39, 0x46, 0x39, 0x46, 0x36, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, +0x4a, 0x35, 0x4a, 0x34, 0x4b, 0x32, 0x4e, 0x31, 0x4f, 0x31, 0x4f, 0x31, +0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0xb4, 0x00, 0xaf, 0x00, +0xaa, 0x00, 0xa6, 0x00, 0xa2, 0x00, 0x9e, 0x00, 0x9a, 0x00, 0x97, 0x00, +0x94, 0x00, 0x91, 0x00, 0x8e, 0x01, 0x8c, 0x02, 0x8a, 0x02, 0x88, 0x02, +0x86, 0x02, 0x85, 0x03, 0x83, 0x03, 0x82, 0x04, 0x80, 0x05, 0x7f, 0x05, +0x0a, 0x45, 0x0b, 0x41, 0x0d, 0x3e, 0x10, 0x3a, 0x11, 0x38, 0x13, 0x35, +0x16, 0x33, 0x17, 0x32, 0x19, 0x30, 0x1b, 0x2e, 0x1d, 0x2e, 0x1e, 0x2d, +0x20, 0x2b, 0x22, 0x2b, 0x23, 0x2a, 0x25, 0x2a, 0x25, 0x28, 0x28, 0x28, +0x28, 0x28, 0x2a, 0x27, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, +0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, +0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, +0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x5d, 0x00, 0x5a, 0x00, 0x55, +0x00, 0x4e, 0x00, 0x45, 0x00, 0x3c, 0x00, 0x31, 0x00, 0x26, 0x00, 0x1b, +0x00, 0x11, 0x00, 0x06, 0x03, 0x00, 0x0d, 0x00, 0x17, 0x00, 0x1f, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x9d, 0x00, +0x9a, 0x00, 0x95, 0x00, 0x8d, 0x00, 0x85, 0x00, 0x7b, 0x00, 0x71, 0x00, +0x66, 0x00, 0x5b, 0x00, 0x50, 0x00, 0x46, 0x00, 0x3b, 0x00, 0x31, 0x00, +0x28, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3a, 0x45, 0x39, 0x46, 0x39, 0x46, 0x39, +0x46, 0x37, 0x49, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, +0x4a, 0x34, 0x4c, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, +0x4f, 0x31, 0x4f, 0x31, 0xb4, 0x00, 0xaf, 0x00, 0xab, 0x00, 0xa7, 0x00, +0xa3, 0x00, 0x9f, 0x00, 0x9b, 0x00, 0x98, 0x00, 0x95, 0x00, 0x92, 0x00, +0x90, 0x01, 0x8d, 0x01, 0x8b, 0x02, 0x89, 0x02, 0x88, 0x02, 0x86, 0x02, +0x85, 0x03, 0x82, 0x03, 0x82, 0x04, 0x80, 0x05, 0x0a, 0x46, 0x0b, 0x42, +0x0d, 0x3e, 0x0f, 0x3b, 0x11, 0x38, 0x13, 0x36, 0x15, 0x34, 0x16, 0x32, +0x18, 0x30, 0x1a, 0x30, 0x1c, 0x2e, 0x1d, 0x2d, 0x20, 0x2d, 0x20, 0x2b, +0x22, 0x2b, 0x23, 0x2a, 0x25, 0x2a, 0x26, 0x28, 0x28, 0x28, 0x28, 0x28, +0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, +0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, +0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, +0x60, 0x23, 0x60, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x32, 0x74, 0x38, 0x57, 0x3a, 0x4f, 0x3c, 0x4b, 0x3c, 0x49, 0x3d, 0x47, +0x3d, 0x46, 0x3d, 0x45, 0x3d, 0x45, 0x3d, 0x44, 0x3d, 0x43, 0x3d, 0x43, +0x3d, 0x43, 0x3d, 0x43, 0x3d, 0x43, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, +0x3d, 0x42, 0x3d, 0x42, 0x41, 0x09, 0x1b, 0x31, 0x27, 0x38, 0x2d, 0x3a, +0x31, 0x3b, 0x33, 0x3c, 0x35, 0x3c, 0x36, 0x3d, 0x37, 0x3d, 0x38, 0x3d, +0x38, 0x3d, 0x39, 0x3d, 0x3a, 0x3d, 0x3a, 0x3d, 0x3a, 0x3d, 0x3a, 0x3d, +0x3b, 0x3d, 0x3b, 0x3d, 0x3b, 0x3d, 0x3c, 0x3d, 0x73, 0x00, 0x38, 0x31, +0x3a, 0x38, 0x3c, 0x3a, 0x3c, 0x3b, 0x3d, 0x3c, 0x3d, 0x3c, 0x3d, 0x3d, +0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, +0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x0d, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x2f, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x3d, 0x28, 0x38, 0x30, +0x38, 0x34, 0x39, 0x36, 0x39, 0x38, 0x3a, 0x39, 0x3a, 0x39, 0x3b, 0x3a, +0x3b, 0x3b, 0x3c, 0x3b, 0x3c, 0x3b, 0x3d, 0x3c, 0x3d, 0x3c, 0x3e, 0x3c, +0x3e, 0x3c, 0x3e, 0x3c, 0x3e, 0x3c, 0x3e, 0x3d, 0x3e, 0x3d, 0x3e, 0x3d, +0x00, 0x7e, 0x05, 0x58, 0x0f, 0x4e, 0x17, 0x49, 0x1d, 0x47, 0x21, 0x45, +0x24, 0x44, 0x27, 0x43, 0x29, 0x43, 0x2b, 0x43, 0x2d, 0x43, 0x2e, 0x42, +0x2f, 0x42, 0x31, 0x42, 0x31, 0x42, 0x32, 0x42, 0x33, 0x42, 0x33, 0x42, +0x34, 0x42, 0x34, 0x42, 0x2b, 0x4e, 0x31, 0x47, 0x34, 0x45, 0x36, 0x44, +0x38, 0x43, 0x39, 0x42, 0x39, 0x42, 0x3a, 0x41, 0x3b, 0x41, 0x3b, 0x41, +0x3c, 0x41, 0x3c, 0x41, 0x3d, 0x41, 0x3d, 0x41, 0x3d, 0x41, 0x3d, 0x41, +0x3d, 0x41, 0x3d, 0x41, 0x3d, 0x41, 0x3d, 0x41, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x4f, 0x00, 0x04, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x2f, 0x00, +0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x41, 0x16, 0x3a, 0x20, 0x39, 0x25, 0x39, 0x29, +0x39, 0x2d, 0x39, 0x2f, 0x3a, 0x31, 0x3a, 0x32, 0x3b, 0x33, 0x3a, 0x34, +0x3a, 0x35, 0x3a, 0x36, 0x3a, 0x36, 0x3b, 0x37, 0x3b, 0x37, 0x3c, 0x38, +0x3c, 0x38, 0x3d, 0x38, 0x3e, 0x39, 0x3e, 0x39, 0x00, 0x93, 0x01, 0x70, +0x06, 0x60, 0x0d, 0x56, 0x12, 0x52, 0x16, 0x4e, 0x1a, 0x4c, 0x1d, 0x4a, +0x20, 0x48, 0x22, 0x47, 0x24, 0x46, 0x26, 0x45, 0x27, 0x44, 0x29, 0x44, +0x2a, 0x44, 0x2b, 0x44, 0x2c, 0x43, 0x2d, 0x43, 0x2e, 0x43, 0x2f, 0x43, +0x28, 0x56, 0x2e, 0x4f, 0x31, 0x4b, 0x33, 0x49, 0x35, 0x48, 0x36, 0x46, +0x37, 0x45, 0x38, 0x45, 0x39, 0x44, 0x39, 0x44, 0x39, 0x43, 0x39, 0x43, +0x39, 0x42, 0x3a, 0x42, 0x3a, 0x42, 0x3b, 0x42, 0x3c, 0x42, 0x3c, 0x42, +0x3d, 0x42, 0x3d, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x8f, 0x00, 0x73, 0x00, 0x38, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x56, 0x00, 0x45, 0x00, 0x22, 0x00, 0x01, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x43, 0x11, 0x3d, 0x18, 0x3b, 0x1e, 0x3a, 0x22, 0x39, 0x25, 0x39, 0x28, +0x39, 0x2a, 0x39, 0x2c, 0x39, 0x2d, 0x3a, 0x2f, 0x3b, 0x30, 0x3b, 0x31, +0x3b, 0x32, 0x3b, 0x33, 0x3a, 0x33, 0x3a, 0x34, 0x3a, 0x34, 0x3a, 0x35, +0x3a, 0x35, 0x3b, 0x35, 0x00, 0x9d, 0x00, 0x7f, 0x03, 0x6d, 0x07, 0x62, +0x0c, 0x5b, 0x10, 0x56, 0x13, 0x52, 0x16, 0x50, 0x19, 0x4d, 0x1c, 0x4c, +0x1e, 0x4b, 0x1f, 0x4b, 0x22, 0x4a, 0x23, 0x49, 0x24, 0x48, 0x25, 0x47, +0x27, 0x46, 0x28, 0x45, 0x29, 0x44, 0x29, 0x44, 0x27, 0x59, 0x2c, 0x53, +0x2f, 0x4f, 0x31, 0x4d, 0x32, 0x4b, 0x34, 0x4a, 0x35, 0x48, 0x35, 0x47, +0x36, 0x46, 0x37, 0x46, 0x38, 0x46, 0x39, 0x46, 0x39, 0x46, 0x39, 0x45, +0x39, 0x44, 0x39, 0x44, 0x39, 0x43, 0x39, 0x43, 0x39, 0x42, 0x3a, 0x42, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x96, 0x00, 0x84, +0x00, 0x5b, 0x00, 0x2a, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x59, 0x00, 0x4f, 0x00, 0x36, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x44, 0x0f, 0x3e, 0x14, +0x3c, 0x19, 0x3a, 0x1d, 0x3a, 0x20, 0x39, 0x23, 0x3a, 0x25, 0x3a, 0x27, +0x39, 0x29, 0x39, 0x2a, 0x39, 0x2c, 0x3a, 0x2c, 0x3b, 0x2d, 0x3b, 0x2f, +0x3b, 0x2f, 0x3b, 0x30, 0x3b, 0x31, 0x3b, 0x32, 0x3a, 0x32, 0x3a, 0x33, +0x00, 0xa3, 0x00, 0x88, 0x01, 0x77, 0x04, 0x6b, 0x08, 0x63, 0x0b, 0x5d, +0x0e, 0x59, 0x11, 0x57, 0x14, 0x54, 0x16, 0x51, 0x19, 0x4f, 0x1a, 0x4d, +0x1c, 0x4c, 0x1e, 0x4c, 0x1f, 0x4b, 0x21, 0x4b, 0x22, 0x4a, 0x23, 0x49, +0x24, 0x49, 0x25, 0x49, 0x27, 0x5a, 0x2a, 0x55, 0x2d, 0x52, 0x2f, 0x4f, +0x31, 0x4e, 0x32, 0x4b, 0x33, 0x4a, 0x35, 0x4a, 0x35, 0x49, 0x35, 0x48, +0x35, 0x46, 0x37, 0x46, 0x38, 0x46, 0x39, 0x46, 0x39, 0x46, 0x39, 0x46, +0x39, 0x46, 0x39, 0x46, 0x39, 0x46, 0x39, 0x45, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0x00, 0x8d, 0x00, 0x6f, 0x00, 0x48, +0x00, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5b, 0x00, 0x55, 0x00, +0x42, 0x00, 0x2b, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x45, 0x0e, 0x40, 0x12, 0x3d, 0x16, 0x3b, 0x1a, +0x3b, 0x1d, 0x3a, 0x20, 0x39, 0x22, 0x39, 0x23, 0x3a, 0x25, 0x3a, 0x26, +0x3a, 0x28, 0x39, 0x29, 0x39, 0x2a, 0x39, 0x2b, 0x3a, 0x2c, 0x3b, 0x2d, +0x3c, 0x2e, 0x3b, 0x2e, 0x3b, 0x2f, 0x3b, 0x30, 0x00, 0xa7, 0x00, 0x90, +0x00, 0x7e, 0x02, 0x73, 0x05, 0x6a, 0x08, 0x65, 0x0b, 0x5f, 0x0d, 0x5b, +0x10, 0x58, 0x12, 0x56, 0x14, 0x55, 0x16, 0x52, 0x18, 0x50, 0x1a, 0x4e, +0x1b, 0x4d, 0x1d, 0x4c, 0x1e, 0x4c, 0x1f, 0x4b, 0x20, 0x4b, 0x21, 0x4b, +0x26, 0x5b, 0x2a, 0x57, 0x2c, 0x54, 0x2e, 0x51, 0x30, 0x4f, 0x31, 0x4e, +0x31, 0x4c, 0x33, 0x4a, 0x34, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x49, +0x35, 0x47, 0x36, 0x46, 0x37, 0x46, 0x38, 0x46, 0x39, 0x46, 0x39, 0x46, +0x39, 0x46, 0x39, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x9b, 0x00, 0x92, 0x00, 0x7c, 0x00, 0x5d, 0x00, 0x3c, 0x00, 0x1c, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x5d, 0x00, 0x58, 0x00, 0x4a, 0x00, 0x38, 0x00, +0x24, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x46, 0x0d, 0x41, 0x11, 0x3d, 0x14, 0x3d, 0x17, 0x3b, 0x1a, 0x3b, 0x1c, +0x3b, 0x1e, 0x39, 0x21, 0x39, 0x22, 0x3a, 0x23, 0x3a, 0x25, 0x3a, 0x26, +0x3a, 0x28, 0x39, 0x29, 0x39, 0x2a, 0x39, 0x2a, 0x39, 0x2b, 0x3b, 0x2c, +0x3c, 0x2d, 0x3c, 0x2e, 0x00, 0xa9, 0x00, 0x95, 0x00, 0x85, 0x01, 0x79, +0x03, 0x70, 0x06, 0x69, 0x08, 0x65, 0x0b, 0x61, 0x0d, 0x5c, 0x0f, 0x59, +0x11, 0x58, 0x13, 0x56, 0x14, 0x55, 0x16, 0x53, 0x18, 0x51, 0x19, 0x4f, +0x1b, 0x4d, 0x1c, 0x4d, 0x1d, 0x4c, 0x1e, 0x4c, 0x26, 0x5c, 0x29, 0x58, +0x2b, 0x55, 0x2d, 0x53, 0x2e, 0x50, 0x30, 0x4f, 0x31, 0x4f, 0x31, 0x4d, +0x32, 0x4b, 0x34, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x49, +0x35, 0x48, 0x35, 0x47, 0x36, 0x46, 0x38, 0x46, 0x39, 0x46, 0x39, 0x46, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9c, 0x00, 0x95, +0x00, 0x84, 0x00, 0x6c, 0x00, 0x4f, 0x00, 0x32, 0x00, 0x18, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x5d, 0x00, 0x59, 0x00, 0x4f, 0x00, 0x40, 0x00, 0x2f, 0x00, 0x1e, 0x00, +0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x46, 0x0c, 0x42, 0x0f, +0x3f, 0x13, 0x3d, 0x15, 0x3c, 0x18, 0x3a, 0x1a, 0x3b, 0x1c, 0x3b, 0x1e, +0x39, 0x20, 0x39, 0x21, 0x39, 0x22, 0x3b, 0x24, 0x3a, 0x25, 0x3a, 0x26, +0x3a, 0x27, 0x39, 0x28, 0x39, 0x29, 0x39, 0x2a, 0x39, 0x2a, 0x3a, 0x2b, +0x00, 0xab, 0x00, 0x99, 0x00, 0x8b, 0x01, 0x7e, 0x02, 0x77, 0x04, 0x6f, +0x06, 0x69, 0x08, 0x66, 0x0b, 0x62, 0x0d, 0x5e, 0x0e, 0x5b, 0x10, 0x59, +0x12, 0x57, 0x13, 0x56, 0x15, 0x55, 0x16, 0x54, 0x18, 0x52, 0x19, 0x50, +0x1a, 0x4e, 0x1b, 0x4d, 0x26, 0x5c, 0x28, 0x59, 0x2a, 0x57, 0x2c, 0x53, +0x2e, 0x53, 0x2e, 0x50, 0x30, 0x4f, 0x31, 0x4f, 0x31, 0x4e, 0x31, 0x4c, +0x33, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, +0x35, 0x49, 0x35, 0x48, 0x36, 0x46, 0x37, 0x46, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x9c, 0x00, 0x98, 0x00, 0x8a, 0x00, 0x76, +0x00, 0x5e, 0x00, 0x45, 0x00, 0x2c, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x5b, 0x00, +0x53, 0x00, 0x47, 0x00, 0x38, 0x00, 0x29, 0x00, 0x1a, 0x00, 0x0c, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x46, 0x0c, 0x42, 0x0e, 0x40, 0x11, 0x3d, 0x13, +0x3d, 0x16, 0x3b, 0x18, 0x3b, 0x1a, 0x3c, 0x1c, 0x3b, 0x1e, 0x3a, 0x1f, +0x39, 0x21, 0x39, 0x21, 0x3a, 0x23, 0x3b, 0x24, 0x3a, 0x25, 0x3a, 0x26, +0x3a, 0x27, 0x39, 0x27, 0x39, 0x28, 0x39, 0x2a, 0x00, 0xac, 0x00, 0x9c, +0x00, 0x8f, 0x00, 0x83, 0x02, 0x7b, 0x03, 0x74, 0x05, 0x6d, 0x07, 0x69, +0x09, 0x66, 0x0b, 0x63, 0x0c, 0x5f, 0x0e, 0x5c, 0x0f, 0x5a, 0x11, 0x58, +0x12, 0x57, 0x14, 0x56, 0x15, 0x55, 0x16, 0x55, 0x18, 0x53, 0x18, 0x51, +0x26, 0x5d, 0x27, 0x59, 0x2a, 0x57, 0x2b, 0x55, 0x2e, 0x53, 0x2e, 0x53, +0x2f, 0x50, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4d, 0x32, 0x4b, +0x34, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, +0x35, 0x4a, 0x35, 0x49, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x9d, 0x00, 0x99, 0x00, 0x8e, 0x00, 0x7e, 0x00, 0x69, 0x00, 0x53, +0x00, 0x3c, 0x00, 0x26, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x5c, 0x00, 0x55, 0x00, 0x4b, 0x00, +0x3f, 0x00, 0x32, 0x00, 0x24, 0x00, 0x17, 0x00, 0x0b, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x47, 0x0b, 0x42, 0x0d, 0x41, 0x10, 0x3e, 0x13, 0x3d, 0x15, 0x3c, 0x17, +0x3a, 0x19, 0x3b, 0x1a, 0x3c, 0x1c, 0x3b, 0x1d, 0x3a, 0x1f, 0x39, 0x20, +0x39, 0x21, 0x3a, 0x22, 0x3b, 0x23, 0x3b, 0x24, 0x3a, 0x25, 0x3a, 0x26, +0x3a, 0x27, 0x39, 0x27, 0x00, 0xad, 0x00, 0x9f, 0x00, 0x92, 0x00, 0x88, +0x01, 0x7e, 0x02, 0x78, 0x04, 0x72, 0x05, 0x6d, 0x07, 0x69, 0x09, 0x66, +0x0a, 0x64, 0x0c, 0x61, 0x0d, 0x5d, 0x0f, 0x5a, 0x10, 0x59, 0x11, 0x58, +0x13, 0x57, 0x14, 0x56, 0x15, 0x55, 0x16, 0x55, 0x26, 0x5d, 0x27, 0x5a, +0x2a, 0x57, 0x2a, 0x56, 0x2c, 0x53, 0x2e, 0x53, 0x2e, 0x52, 0x2f, 0x4f, +0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4e, 0x32, 0x4b, 0x33, 0x4a, +0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9d, 0x00, 0x9a, +0x00, 0x91, 0x00, 0x83, 0x00, 0x72, 0x00, 0x5e, 0x00, 0x4a, 0x00, 0x36, +0x00, 0x22, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x5e, 0x00, 0x5c, 0x00, 0x57, 0x00, 0x4f, 0x00, 0x44, 0x00, 0x38, 0x00, +0x2c, 0x00, 0x20, 0x00, 0x14, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x47, 0x0b, 0x43, 0x0d, +0x41, 0x0f, 0x3f, 0x12, 0x3d, 0x13, 0x3e, 0x15, 0x3c, 0x17, 0x3a, 0x19, +0x3a, 0x1a, 0x3c, 0x1c, 0x3b, 0x1d, 0x3a, 0x1f, 0x39, 0x1f, 0x39, 0x21, +0x39, 0x21, 0x3b, 0x22, 0x3b, 0x24, 0x3a, 0x24, 0x3a, 0x24, 0x3a, 0x26, +0x00, 0xae, 0x00, 0xa2, 0x00, 0x94, 0x00, 0x8b, 0x00, 0x82, 0x02, 0x7b, +0x03, 0x76, 0x05, 0x71, 0x06, 0x6c, 0x07, 0x69, 0x09, 0x66, 0x0a, 0x64, +0x0c, 0x62, 0x0d, 0x5f, 0x0e, 0x5b, 0x10, 0x5a, 0x10, 0x58, 0x12, 0x58, +0x13, 0x56, 0x14, 0x56, 0x25, 0x5d, 0x27, 0x5b, 0x29, 0x57, 0x2a, 0x57, +0x2b, 0x54, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x52, 0x2f, 0x4f, 0x31, 0x4f, +0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4e, 0x31, 0x4d, 0x33, 0x4a, 0x34, 0x4a, +0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x9b, 0x00, 0x93, 0x00, 0x88, +0x00, 0x79, 0x00, 0x68, 0x00, 0x55, 0x00, 0x43, 0x00, 0x30, 0x00, 0x1f, +0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x5d, 0x00, +0x58, 0x00, 0x51, 0x00, 0x48, 0x00, 0x3e, 0x00, 0x33, 0x00, 0x28, 0x00, +0x1d, 0x00, 0x12, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x47, 0x0b, 0x43, 0x0d, 0x42, 0x0f, 0x40, 0x11, +0x3d, 0x13, 0x3e, 0x14, 0x3c, 0x16, 0x3b, 0x17, 0x3a, 0x19, 0x3b, 0x1a, +0x3c, 0x1c, 0x3b, 0x1d, 0x3b, 0x1f, 0x39, 0x1f, 0x39, 0x20, 0x39, 0x21, +0x3a, 0x21, 0x3b, 0x22, 0x3b, 0x24, 0x3a, 0x24, 0x00, 0xae, 0x00, 0xa3, +0x00, 0x97, 0x00, 0x8e, 0x00, 0x86, 0x01, 0x7e, 0x02, 0x79, 0x03, 0x75, +0x05, 0x70, 0x06, 0x6b, 0x07, 0x68, 0x09, 0x66, 0x0a, 0x64, 0x0b, 0x63, +0x0c, 0x5f, 0x0e, 0x5d, 0x0f, 0x5a, 0x10, 0x59, 0x11, 0x58, 0x13, 0x58, +0x25, 0x5d, 0x27, 0x5c, 0x29, 0x58, 0x2a, 0x57, 0x2a, 0x56, 0x2d, 0x53, +0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x51, 0x30, 0x4f, 0x31, 0x4f, 0x31, 0x4f, +0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4d, 0x32, 0x4b, 0x33, 0x4a, 0x35, 0x4a, +0x35, 0x4a, 0x35, 0x4a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x9e, 0x00, 0x9c, 0x00, 0x95, 0x00, 0x8b, 0x00, 0x7e, 0x00, 0x6f, +0x00, 0x5f, 0x00, 0x4e, 0x00, 0x3d, 0x00, 0x2c, 0x00, 0x1c, 0x00, 0x0d, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x5d, 0x00, 0x59, 0x00, 0x53, 0x00, +0x4c, 0x00, 0x42, 0x00, 0x39, 0x00, 0x2e, 0x00, 0x24, 0x00, 0x1a, 0x00, +0x11, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x47, 0x0b, 0x44, 0x0d, 0x42, 0x0e, 0x41, 0x10, 0x3e, 0x12, 0x3d, 0x13, +0x3e, 0x15, 0x3c, 0x17, 0x3a, 0x18, 0x3b, 0x19, 0x3b, 0x1a, 0x3c, 0x1c, +0x3b, 0x1c, 0x3b, 0x1e, 0x39, 0x1f, 0x39, 0x20, 0x39, 0x21, 0x39, 0x21, +0x3b, 0x22, 0x3b, 0x23, 0x00, 0xaf, 0x00, 0xa5, 0x00, 0x99, 0x00, 0x90, +0x00, 0x8a, 0x01, 0x81, 0x02, 0x7c, 0x02, 0x77, 0x04, 0x74, 0x05, 0x6f, +0x06, 0x6a, 0x07, 0x68, 0x09, 0x66, 0x0a, 0x64, 0x0b, 0x63, 0x0c, 0x61, +0x0e, 0x5e, 0x0e, 0x5b, 0x10, 0x5a, 0x10, 0x59, 0x25, 0x5d, 0x27, 0x5c, +0x28, 0x59, 0x2a, 0x57, 0x2a, 0x57, 0x2b, 0x54, 0x2e, 0x53, 0x2e, 0x53, +0x2e, 0x53, 0x2e, 0x50, 0x30, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, +0x31, 0x4f, 0x31, 0x4e, 0x31, 0x4c, 0x33, 0x4a, 0x34, 0x4a, 0x35, 0x4a, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x9c, +0x00, 0x97, 0x00, 0x8e, 0x00, 0x83, 0x00, 0x75, 0x00, 0x66, 0x00, 0x57, +0x00, 0x47, 0x00, 0x37, 0x00, 0x28, 0x00, 0x1a, 0x00, 0x0c, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x5f, 0x00, 0x5d, 0x00, 0x5a, 0x00, 0x55, 0x00, 0x4e, 0x00, 0x46, 0x00, +0x3d, 0x00, 0x34, 0x00, 0x2a, 0x00, 0x21, 0x00, 0x18, 0x00, 0x0f, 0x00, +0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x47, 0x0a, 0x44, 0x0d, +0x42, 0x0e, 0x41, 0x0f, 0x3f, 0x11, 0x3d, 0x13, 0x3e, 0x14, 0x3d, 0x15, +0x3c, 0x17, 0x3a, 0x18, 0x3a, 0x19, 0x3c, 0x1a, 0x3c, 0x1c, 0x3b, 0x1c, +0x3b, 0x1e, 0x39, 0x1f, 0x39, 0x1f, 0x39, 0x21, 0x39, 0x21, 0x3a, 0x21, +0x00, 0xaf, 0x00, 0xa6, 0x00, 0x9c, 0x00, 0x92, 0x00, 0x8c, 0x00, 0x85, +0x01, 0x7e, 0x02, 0x7a, 0x03, 0x76, 0x05, 0x73, 0x06, 0x6e, 0x07, 0x6a, +0x08, 0x68, 0x09, 0x66, 0x0a, 0x65, 0x0b, 0x63, 0x0c, 0x62, 0x0d, 0x5f, +0x0e, 0x5c, 0x0f, 0x5a, 0x25, 0x5d, 0x27, 0x5c, 0x27, 0x59, 0x2a, 0x57, +0x2a, 0x57, 0x2a, 0x55, 0x2d, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, +0x2e, 0x50, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, +0x31, 0x4f, 0x31, 0x4d, 0x32, 0x4b, 0x34, 0x4a, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x9c, 0x00, 0x98, 0x00, 0x90, +0x00, 0x86, 0x00, 0x7a, 0x00, 0x6d, 0x00, 0x5f, 0x00, 0x50, 0x00, 0x41, +0x00, 0x33, 0x00, 0x25, 0x00, 0x18, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x5e, 0x00, +0x5b, 0x00, 0x56, 0x00, 0x50, 0x00, 0x49, 0x00, 0x41, 0x00, 0x39, 0x00, +0x30, 0x00, 0x27, 0x00, 0x1e, 0x00, 0x16, 0x00, 0x0e, 0x00, 0x07, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x47, 0x0a, 0x45, 0x0c, 0x42, 0x0d, 0x42, 0x0f, +0x40, 0x11, 0x3d, 0x12, 0x3d, 0x13, 0x3e, 0x15, 0x3c, 0x16, 0x3b, 0x17, +0x3a, 0x19, 0x3a, 0x19, 0x3c, 0x1a, 0x3c, 0x1c, 0x3b, 0x1c, 0x3b, 0x1e, +0x3a, 0x1f, 0x39, 0x1f, 0x39, 0x20, 0x39, 0x21, 0x00, 0xb0, 0x00, 0xa7, +0x00, 0x9e, 0x00, 0x94, 0x00, 0x8e, 0x00, 0x88, 0x01, 0x81, 0x02, 0x7c, +0x02, 0x78, 0x03, 0x75, 0x05, 0x72, 0x06, 0x6d, 0x07, 0x6a, 0x08, 0x68, +0x09, 0x66, 0x0a, 0x65, 0x0b, 0x63, 0x0c, 0x62, 0x0d, 0x60, 0x0e, 0x5d, +0x25, 0x5d, 0x27, 0x5c, 0x27, 0x5a, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57, +0x2c, 0x54, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x52, 0x2f, 0x4f, +0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, +0x31, 0x4e, 0x31, 0x4c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x9e, 0x00, 0x9d, 0x00, 0x99, 0x00, 0x92, 0x00, 0x89, 0x00, 0x7e, +0x00, 0x72, 0x00, 0x66, 0x00, 0x58, 0x00, 0x4a, 0x00, 0x3d, 0x00, 0x2f, +0x00, 0x22, 0x00, 0x16, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x5e, 0x00, 0x5b, 0x00, 0x57, 0x00, +0x52, 0x00, 0x4c, 0x00, 0x44, 0x00, 0x3d, 0x00, 0x35, 0x00, 0x2c, 0x00, +0x24, 0x00, 0x1c, 0x00, 0x14, 0x00, 0x0d, 0x00, 0x06, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x47, 0x0a, 0x45, 0x0c, 0x42, 0x0d, 0x42, 0x0e, 0x40, 0x10, 0x3e, 0x11, +0x3d, 0x13, 0x3e, 0x14, 0x3d, 0x15, 0x3c, 0x17, 0x3a, 0x17, 0x3a, 0x19, +0x3b, 0x19, 0x3c, 0x1a, 0x3c, 0x1c, 0x3b, 0x1c, 0x3b, 0x1d, 0x3a, 0x1f, +0x39, 0x1f, 0x39, 0x1f, 0x00, 0xb0, 0x00, 0xa7, 0x00, 0xa0, 0x00, 0x96, +0x00, 0x90, 0x00, 0x8a, 0x00, 0x84, 0x01, 0x7e, 0x02, 0x7a, 0x03, 0x77, +0x04, 0x74, 0x05, 0x71, 0x06, 0x6c, 0x07, 0x6a, 0x08, 0x68, 0x09, 0x66, +0x0a, 0x65, 0x0b, 0x63, 0x0c, 0x63, 0x0c, 0x61, 0x25, 0x5e, 0x27, 0x5c, +0x27, 0x5c, 0x29, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x55, 0x2d, 0x53, +0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x52, 0x2f, 0x4f, 0x31, 0x4f, +0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, +0x00, 0x27, 0x00, 0x4f, 0x00, 0x7f, 0x00, 0x8f, 0x00, 0x96, 0x00, 0x99, +0x00, 0x9b, 0x00, 0x9c, 0x00, 0x9c, 0x00, 0x9d, 0x00, 0x9d, 0x00, 0x9e, +0x00, 0x9e, 0x00, 0x9e, 0x00, 0x9e, 0x00, 0x9e, 0x00, 0x8c, 0x00, 0x63, +0x00, 0x7f, 0x00, 0x89, 0x00, 0x90, 0x00, 0x96, 0x00, 0x9b, 0x00, 0x9c, +0x00, 0x9c, 0x00, 0x9d, 0x00, 0x9d, 0x00, 0x9e, 0x00, 0x9e, 0x00, 0x9e, +0x00, 0x9e, 0x00, 0x9e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x14, 0x2c, 0x00, 0x57, 0x00, 0x82, 0x00, 0x91, 0x00, 0x96, 0x00, 0x99, +0x00, 0x9b, 0x00, 0x9c, 0x00, 0x9d, 0x00, 0x9d, 0x00, 0x9d, 0x00, 0x9e, +0x00, 0x9e, 0x00, 0x9e, 0x00, 0x9e, 0x00, 0x9e, 0x11, 0x31, 0x00, 0x5f, +0x00, 0x85, 0x00, 0x92, 0x00, 0x97, 0x00, 0x9a, 0x00, 0x9b, 0x00, 0x9c, +0x00, 0x9d, 0x00, 0x9d, 0x00, 0x9e, 0x00, 0x9e, 0x00, 0x9e, 0x00, 0x9e, +0x00, 0x9e, 0x00, 0x9e, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x47, 0x0a, 0x45, 0x0b, +0x42, 0x0d, 0x42, 0x0e, 0x41, 0x0f, 0x3f, 0x11, 0x3d, 0x12, 0x3d, 0x13, +0x3e, 0x15, 0x3c, 0x15, 0x3c, 0x17, 0x3a, 0x17, 0x3a, 0x19, 0x3b, 0x19, +0x3c, 0x1a, 0x3c, 0x1c, 0x3b, 0x1c, 0x3b, 0x1d, 0x3a, 0x1f, 0x39, 0x1f, +0x00, 0xb1, 0x00, 0xa8, 0x00, 0xa1, 0x00, 0x98, 0x00, 0x91, 0x00, 0x8c, +0x00, 0x87, 0x01, 0x80, 0x02, 0x7c, 0x02, 0x79, 0x03, 0x76, 0x05, 0x74, +0x05, 0x70, 0x06, 0x6b, 0x07, 0x6a, 0x08, 0x68, 0x09, 0x66, 0x0a, 0x65, +0x0b, 0x64, 0x0c, 0x63, 0x25, 0x5e, 0x27, 0x5c, 0x27, 0x5c, 0x29, 0x58, +0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2c, 0x53, 0x2e, 0x53, 0x2e, 0x53, +0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x51, 0x30, 0x4f, 0x31, 0x4f, 0x31, 0x4f, +0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x00, 0x00, 0x00, 0x0d, +0x00, 0x4f, 0x00, 0x73, 0x00, 0x84, 0x00, 0x8d, 0x00, 0x92, 0x00, 0x95, +0x00, 0x98, 0x00, 0x99, 0x00, 0x9a, 0x00, 0x9b, 0x00, 0x9c, 0x00, 0x9c, +0x00, 0x9c, 0x00, 0x9d, 0x00, 0x63, 0x00, 0x4d, 0x00, 0x60, 0x00, 0x77, +0x00, 0x83, 0x00, 0x8c, 0x00, 0x92, 0x00, 0x95, 0x00, 0x98, 0x00, 0x99, +0x00, 0x9a, 0x00, 0x9b, 0x00, 0x9c, 0x00, 0x9c, 0x00, 0x9c, 0x00, 0x9d, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x29, 0x01, 0x04, 0x16, +0x00, 0x57, 0x00, 0x78, 0x00, 0x87, 0x00, 0x8f, 0x00, 0x94, 0x00, 0x96, +0x00, 0x98, 0x00, 0x9a, 0x00, 0x9b, 0x00, 0x9b, 0x00, 0x9c, 0x00, 0x9c, +0x00, 0x9d, 0x00, 0x9d, 0x23, 0x03, 0x00, 0x20, 0x00, 0x5f, 0x00, 0x7c, +0x00, 0x8a, 0x00, 0x91, 0x00, 0x95, 0x00, 0x97, 0x00, 0x99, 0x00, 0x9a, +0x00, 0x9b, 0x00, 0x9c, 0x00, 0x9c, 0x00, 0x9d, 0x00, 0x9d, 0x00, 0x9d, +0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x47, 0x0a, 0x46, 0x0b, 0x43, 0x0d, 0x41, 0x0e, +0x42, 0x0f, 0x40, 0x11, 0x3d, 0x11, 0x3d, 0x13, 0x3f, 0x13, 0x3d, 0x15, +0x3c, 0x16, 0x3b, 0x17, 0x3a, 0x18, 0x3a, 0x19, 0x3b, 0x19, 0x3c, 0x1a, +0x3c, 0x1c, 0x3b, 0x1c, 0x3b, 0x1d, 0x3b, 0x1e, 0x00, 0xb1, 0x00, 0xa9, +0x00, 0xa2, 0x00, 0x9a, 0x00, 0x93, 0x00, 0x8d, 0x00, 0x89, 0x01, 0x83, +0x02, 0x7e, 0x02, 0x7a, 0x03, 0x78, 0x03, 0x75, 0x05, 0x73, 0x06, 0x6f, +0x06, 0x6b, 0x07, 0x69, 0x08, 0x68, 0x09, 0x66, 0x0a, 0x66, 0x0b, 0x64, +0x24, 0x5e, 0x27, 0x5c, 0x27, 0x5c, 0x28, 0x59, 0x2a, 0x57, 0x2a, 0x57, +0x2a, 0x57, 0x2b, 0x55, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, +0x2e, 0x53, 0x2e, 0x50, 0x30, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, +0x31, 0x4f, 0x31, 0x4f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x38, +0x00, 0x5b, 0x00, 0x6f, 0x00, 0x7c, 0x00, 0x84, 0x00, 0x8a, 0x00, 0x8e, +0x00, 0x91, 0x00, 0x93, 0x00, 0x95, 0x00, 0x97, 0x00, 0x98, 0x00, 0x99, +0x00, 0x7f, 0x00, 0x60, 0x00, 0x24, 0x00, 0x48, 0x00, 0x60, 0x00, 0x70, +0x00, 0x7c, 0x00, 0x84, 0x00, 0x8a, 0x00, 0x8e, 0x00, 0x91, 0x00, 0x93, +0x00, 0x95, 0x00, 0x97, 0x00, 0x98, 0x00, 0x99, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x49, 0x00, 0x27, 0x00, 0x01, 0x12, 0x00, 0x43, +0x00, 0x61, 0x00, 0x74, 0x00, 0x7f, 0x00, 0x87, 0x00, 0x8c, 0x00, 0x90, +0x00, 0x93, 0x00, 0x95, 0x00, 0x96, 0x00, 0x97, 0x00, 0x98, 0x00, 0x99, +0x46, 0x00, 0x1f, 0x00, 0x00, 0x1f, 0x00, 0x4d, 0x00, 0x68, 0x00, 0x79, +0x00, 0x83, 0x00, 0x8a, 0x00, 0x8e, 0x00, 0x92, 0x00, 0x94, 0x00, 0x96, +0x00, 0x97, 0x00, 0x98, 0x00, 0x99, 0x00, 0x9a, 0x41, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x47, 0x0a, 0x46, 0x0b, 0x43, 0x0d, 0x41, 0x0e, 0x42, 0x0f, 0x40, 0x10, +0x3e, 0x11, 0x3d, 0x13, 0x3d, 0x13, 0x3f, 0x15, 0x3c, 0x15, 0x3c, 0x17, +0x3a, 0x17, 0x3a, 0x18, 0x3b, 0x19, 0x3b, 0x19, 0x3c, 0x1a, 0x3c, 0x1c, +0x3b, 0x1c, 0x3b, 0x1c, 0x00, 0xb1, 0x00, 0xa9, 0x00, 0xa3, 0x00, 0x9c, +0x00, 0x94, 0x00, 0x8f, 0x00, 0x8b, 0x00, 0x86, 0x01, 0x80, 0x02, 0x7c, +0x02, 0x79, 0x03, 0x77, 0x04, 0x75, 0x05, 0x72, 0x06, 0x6e, 0x07, 0x6b, +0x07, 0x69, 0x09, 0x68, 0x09, 0x66, 0x0a, 0x66, 0x24, 0x5e, 0x27, 0x5c, +0x27, 0x5c, 0x27, 0x5a, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57, +0x2c, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, +0x2e, 0x50, 0x30, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x2a, 0x00, 0x48, +0x00, 0x5d, 0x00, 0x6c, 0x00, 0x76, 0x00, 0x7e, 0x00, 0x83, 0x00, 0x88, +0x00, 0x8b, 0x00, 0x8e, 0x00, 0x90, 0x00, 0x92, 0x00, 0x89, 0x00, 0x77, +0x00, 0x48, 0x00, 0x0f, 0x00, 0x30, 0x00, 0x48, 0x00, 0x5d, 0x00, 0x6c, +0x00, 0x76, 0x00, 0x7e, 0x00, 0x83, 0x00, 0x88, 0x00, 0x8b, 0x00, 0x8e, +0x00, 0x90, 0x00, 0x92, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x54, 0x00, 0x41, 0x00, 0x17, 0x00, 0x00, 0x10, 0x00, 0x36, 0x00, 0x51, +0x00, 0x64, 0x00, 0x71, 0x00, 0x7a, 0x00, 0x81, 0x00, 0x86, 0x00, 0x8a, +0x00, 0x8d, 0x00, 0x90, 0x00, 0x92, 0x00, 0x93, 0x52, 0x00, 0x3c, 0x00, +0x0d, 0x00, 0x00, 0x1f, 0x00, 0x42, 0x00, 0x5a, 0x00, 0x6a, 0x00, 0x76, +0x00, 0x7e, 0x00, 0x84, 0x00, 0x89, 0x00, 0x8c, 0x00, 0x8f, 0x00, 0x91, +0x00, 0x93, 0x00, 0x95, 0x41, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, 0x42, 0x3d, 0x42, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x41, 0x3d, +0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x47, 0x0a, 0x46, 0x0b, +0x44, 0x0d, 0x42, 0x0d, 0x42, 0x0e, 0x40, 0x0f, 0x40, 0x11, 0x3d, 0x11, +0x3d, 0x13, 0x3f, 0x13, 0x3e, 0x15, 0x3c, 0x15, 0x3c, 0x17, 0x3a, 0x17, +0x3a, 0x18, 0x3b, 0x19, 0x3c, 0x19, 0x3c, 0x1a, 0x3c, 0x1c, 0x3b, 0x1c, +0x00, 0xb2, 0x00, 0xaa, 0x00, 0xa4, 0x00, 0x9e, 0x00, 0x95, 0x00, 0x90, +0x00, 0x8c, 0x00, 0x88, 0x01, 0x82, 0x02, 0x7e, 0x02, 0x7b, 0x02, 0x78, +0x03, 0x76, 0x05, 0x74, 0x05, 0x71, 0x06, 0x6d, 0x07, 0x6b, 0x07, 0x69, +0x09, 0x68, 0x09, 0x66, 0x24, 0x5e, 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x5b, +0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2b, 0x54, 0x2e, 0x53, +0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x52, 0x2f, 0x50, +0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x22, 0x00, 0x3c, 0x00, 0x4f, +0x00, 0x5e, 0x00, 0x69, 0x00, 0x72, 0x00, 0x79, 0x00, 0x7e, 0x00, 0x83, +0x00, 0x86, 0x00, 0x89, 0x00, 0x90, 0x00, 0x83, 0x00, 0x60, 0x00, 0x30, +0x00, 0x02, 0x00, 0x22, 0x00, 0x3c, 0x00, 0x4f, 0x00, 0x5e, 0x00, 0x69, +0x00, 0x72, 0x00, 0x79, 0x00, 0x7e, 0x00, 0x83, 0x00, 0x86, 0x00, 0x89, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x59, 0x00, 0x4d, 0x00, +0x2f, 0x00, 0x0e, 0x00, 0x00, 0x10, 0x00, 0x2e, 0x00, 0x46, 0x00, 0x57, +0x00, 0x64, 0x00, 0x6f, 0x00, 0x76, 0x00, 0x7d, 0x00, 0x81, 0x00, 0x85, +0x00, 0x89, 0x00, 0x8b, 0x58, 0x00, 0x4a, 0x00, 0x28, 0x00, 0x02, 0x00, +0x00, 0x1f, 0x00, 0x3b, 0x00, 0x4f, 0x00, 0x5f, 0x00, 0x6b, 0x00, 0x74, +0x00, 0x7b, 0x00, 0x80, 0x00, 0x85, 0x00, 0x88, 0x00, 0x8b, 0x00, 0x8d, +0x1b, 0x85, 0x05, 0x96, 0x01, 0x9e, 0x00, 0xa4, 0x00, 0xa7, 0x00, 0xa9, +0x00, 0xab, 0x00, 0xac, 0x00, 0xad, 0x00, 0xae, 0x00, 0xaf, 0x00, 0xaf, +0x00, 0xb0, 0x00, 0xb0, 0x00, 0xb1, 0x00, 0xb1, 0x00, 0xb1, 0x00, 0xb2, +0x00, 0xb2, 0x00, 0xb2, 0x1c, 0x6e, 0x03, 0x8a, 0x00, 0x97, 0x00, 0x9e, +0x00, 0xa2, 0x00, 0xa6, 0x00, 0xa8, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xac, +0x00, 0xad, 0x00, 0xad, 0x00, 0xad, 0x00, 0xae, 0x00, 0xaf, 0x00, 0xaf, +0x00, 0xaf, 0x00, 0xb0, 0x00, 0xb0, 0x00, 0xb1, 0x00, 0xb7, 0x00, 0xb7, +0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, +0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, +0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, +0x0e, 0x92, 0x01, 0xa1, 0x00, 0xa7, 0x00, 0xaa, 0x00, 0xac, 0x00, 0xae, +0x00, 0xaf, 0x00, 0xb0, 0x00, 0xb1, 0x00, 0xb1, 0x00, 0xb2, 0x00, 0xb2, +0x00, 0xb2, 0x00, 0xb3, 0x00, 0xb3, 0x00, 0xb3, 0x00, 0xb3, 0x00, 0xb3, +0x00, 0xb4, 0x00, 0xb4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x33, 0x00, 0x45, 0x00, 0x53, +0x00, 0x5e, 0x00, 0x68, 0x00, 0x6f, 0x00, 0x75, 0x00, 0x7a, 0x00, 0x7e, +0x00, 0x96, 0x00, 0x8c, 0x00, 0x70, 0x00, 0x48, 0x00, 0x22, 0x00, 0x01, +0x00, 0x1c, 0x00, 0x33, 0x00, 0x45, 0x00, 0x53, 0x00, 0x5e, 0x00, 0x68, +0x00, 0x6f, 0x00, 0x75, 0x00, 0x7a, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x5b, 0x00, 0x53, 0x00, 0x3e, 0x00, 0x23, 0x00, +0x0a, 0x02, 0x00, 0x10, 0x00, 0x29, 0x00, 0x3d, 0x00, 0x4e, 0x00, 0x5b, +0x00, 0x65, 0x00, 0x6d, 0x00, 0x74, 0x00, 0x79, 0x00, 0x7e, 0x00, 0x82, +0x5a, 0x00, 0x51, 0x00, 0x39, 0x00, 0x1a, 0x00, 0x00, 0x04, 0x00, 0x1f, +0x00, 0x36, 0x00, 0x48, 0x00, 0x57, 0x00, 0x62, 0x00, 0x6b, 0x00, 0x73, +0x00, 0x79, 0x00, 0x7e, 0x00, 0x82, 0x00, 0x85, 0x27, 0x60, 0x0f, 0x73, +0x07, 0x81, 0x03, 0x8a, 0x01, 0x91, 0x00, 0x95, 0x00, 0x99, 0x00, 0x9d, +0x00, 0xa0, 0x00, 0xa2, 0x00, 0xa3, 0x00, 0xa5, 0x00, 0xa6, 0x00, 0xa7, +0x00, 0xa7, 0x00, 0xa8, 0x00, 0xa9, 0x00, 0xa9, 0x00, 0xaa, 0x00, 0xaa, +0x29, 0x3a, 0x0f, 0x59, 0x06, 0x6c, 0x02, 0x79, 0x00, 0x84, 0x00, 0x8b, +0x00, 0x90, 0x00, 0x94, 0x00, 0x98, 0x00, 0x9b, 0x00, 0x9d, 0x00, 0x9f, +0x00, 0xa0, 0x00, 0xa2, 0x00, 0xa3, 0x00, 0xa5, 0x00, 0xa6, 0x00, 0xa6, +0x00, 0xa7, 0x00, 0xa7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, +0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, +0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, +0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x14, 0x79, 0x07, 0x88, +0x03, 0x92, 0x01, 0x98, 0x00, 0x9d, 0x00, 0xa1, 0x00, 0xa3, 0x00, 0xa5, +0x00, 0xa8, 0x00, 0xa9, 0x00, 0xaa, 0x00, 0xab, 0x00, 0xac, 0x00, 0xac, +0x00, 0xad, 0x00, 0xae, 0x00, 0xae, 0x00, 0xae, 0x00, 0xaf, 0x00, 0xaf, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x18, 0x00, 0x2c, 0x00, 0x3c, 0x00, 0x4a, 0x00, 0x55, +0x00, 0x5f, 0x00, 0x66, 0x00, 0x6d, 0x00, 0x72, 0x00, 0x9b, 0x00, 0x92, +0x00, 0x7c, 0x00, 0x5d, 0x00, 0x3c, 0x00, 0x1c, 0x00, 0x01, 0x00, 0x18, +0x00, 0x2c, 0x00, 0x3c, 0x00, 0x4a, 0x00, 0x55, 0x00, 0x5f, 0x00, 0x66, +0x00, 0x6d, 0x00, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x5c, 0x00, 0x56, 0x00, 0x47, 0x00, 0x31, 0x00, 0x1a, 0x00, 0x08, 0x04, +0x00, 0x10, 0x00, 0x25, 0x00, 0x37, 0x00, 0x46, 0x00, 0x52, 0x00, 0x5d, +0x00, 0x65, 0x00, 0x6c, 0x00, 0x72, 0x00, 0x77, 0x5c, 0x00, 0x55, 0x00, +0x43, 0x00, 0x2a, 0x00, 0x10, 0x00, 0x00, 0x09, 0x00, 0x1f, 0x00, 0x33, +0x00, 0x43, 0x00, 0x50, 0x00, 0x5b, 0x00, 0x64, 0x00, 0x6b, 0x00, 0x72, +0x00, 0x77, 0x00, 0x7b, 0x2d, 0x54, 0x17, 0x63, 0x0d, 0x6f, 0x07, 0x78, +0x04, 0x80, 0x02, 0x86, 0x01, 0x8b, 0x01, 0x8f, 0x00, 0x92, 0x00, 0x95, +0x00, 0x98, 0x00, 0x9a, 0x00, 0x9d, 0x00, 0x9f, 0x00, 0xa0, 0x00, 0xa1, +0x00, 0xa2, 0x00, 0xa3, 0x00, 0xa4, 0x00, 0xa4, 0x31, 0x27, 0x18, 0x40, +0x0d, 0x52, 0x07, 0x61, 0x04, 0x6c, 0x02, 0x75, 0x01, 0x7c, 0x00, 0x82, +0x00, 0x87, 0x00, 0x8b, 0x00, 0x8e, 0x00, 0x91, 0x00, 0x94, 0x00, 0x97, +0x00, 0x98, 0x00, 0x99, 0x00, 0x9b, 0x00, 0x9d, 0x00, 0x9e, 0x00, 0x9f, +0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, +0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, +0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, +0x00, 0xb7, 0x00, 0xb7, 0x18, 0x6f, 0x0c, 0x7b, 0x06, 0x84, 0x03, 0x8c, +0x02, 0x91, 0x01, 0x96, 0x00, 0x99, 0x00, 0x9d, 0x00, 0x9f, 0x00, 0xa1, +0x00, 0xa2, 0x00, 0xa4, 0x00, 0xa5, 0x00, 0xa7, 0x00, 0xa7, 0x00, 0xa8, +0x00, 0xa9, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xab, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x14, 0x00, 0x26, 0x00, 0x36, 0x00, 0x43, 0x00, 0x4e, 0x00, 0x57, +0x00, 0x5f, 0x00, 0x66, 0x00, 0x9c, 0x00, 0x95, 0x00, 0x84, 0x00, 0x6c, +0x00, 0x4f, 0x00, 0x32, 0x00, 0x18, 0x00, 0x00, 0x00, 0x14, 0x00, 0x26, +0x00, 0x36, 0x00, 0x43, 0x00, 0x4e, 0x00, 0x57, 0x00, 0x5f, 0x00, 0x66, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5d, 0x00, 0x59, 0x00, +0x4d, 0x00, 0x3b, 0x00, 0x27, 0x00, 0x13, 0x00, 0x07, 0x06, 0x00, 0x10, +0x00, 0x22, 0x00, 0x32, 0x00, 0x40, 0x00, 0x4c, 0x00, 0x56, 0x00, 0x5e, +0x00, 0x65, 0x00, 0x6b, 0x5d, 0x00, 0x58, 0x00, 0x4a, 0x00, 0x36, 0x00, +0x1f, 0x00, 0x08, 0x00, 0x00, 0x0c, 0x00, 0x1f, 0x00, 0x30, 0x00, 0x3f, +0x00, 0x4b, 0x00, 0x55, 0x00, 0x5e, 0x00, 0x65, 0x00, 0x6c, 0x00, 0x71, +0x30, 0x4e, 0x1d, 0x5a, 0x12, 0x64, 0x0c, 0x6d, 0x08, 0x75, 0x05, 0x7a, +0x03, 0x7f, 0x02, 0x85, 0x02, 0x89, 0x01, 0x8b, 0x00, 0x8e, 0x00, 0x90, +0x00, 0x92, 0x00, 0x94, 0x00, 0x97, 0x00, 0x99, 0x00, 0x9b, 0x00, 0x9c, +0x00, 0x9e, 0x00, 0x9f, 0x36, 0x1e, 0x1f, 0x32, 0x12, 0x43, 0x0b, 0x50, +0x07, 0x5a, 0x05, 0x63, 0x02, 0x6b, 0x01, 0x72, 0x01, 0x78, 0x00, 0x7c, +0x00, 0x81, 0x00, 0x85, 0x00, 0x88, 0x00, 0x8b, 0x00, 0x8e, 0x00, 0x90, +0x00, 0x91, 0x00, 0x93, 0x00, 0x96, 0x00, 0x97, 0x00, 0xb7, 0x00, 0xb7, +0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, +0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, +0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, +0x1b, 0x6b, 0x0f, 0x74, 0x09, 0x7d, 0x05, 0x83, 0x03, 0x89, 0x02, 0x8d, +0x01, 0x91, 0x00, 0x95, 0x00, 0x98, 0x00, 0x9a, 0x00, 0x9c, 0x00, 0x9e, +0x00, 0x9f, 0x00, 0xa1, 0x00, 0xa3, 0x00, 0xa3, 0x00, 0xa4, 0x00, 0xa5, +0x00, 0xa6, 0x00, 0xa7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, +0x00, 0x22, 0x00, 0x30, 0x00, 0x3d, 0x00, 0x47, 0x00, 0x50, 0x00, 0x58, +0x00, 0x9c, 0x00, 0x98, 0x00, 0x8a, 0x00, 0x76, 0x00, 0x5e, 0x00, 0x45, +0x00, 0x2c, 0x00, 0x14, 0x00, 0x00, 0x00, 0x12, 0x00, 0x22, 0x00, 0x30, +0x00, 0x3d, 0x00, 0x47, 0x00, 0x50, 0x00, 0x58, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x5d, 0x00, 0x5a, 0x00, 0x51, 0x00, 0x42, 0x00, +0x32, 0x00, 0x20, 0x00, 0x0e, 0x00, 0x06, 0x07, 0x00, 0x10, 0x00, 0x20, +0x00, 0x2f, 0x00, 0x3b, 0x00, 0x46, 0x00, 0x50, 0x00, 0x58, 0x00, 0x5f, +0x5d, 0x00, 0x59, 0x00, 0x4e, 0x00, 0x3e, 0x00, 0x2b, 0x00, 0x17, 0x00, +0x03, 0x00, 0x00, 0x0f, 0x00, 0x1f, 0x00, 0x2e, 0x00, 0x3b, 0x00, 0x46, +0x00, 0x50, 0x00, 0x59, 0x00, 0x60, 0x00, 0x66, 0x33, 0x4b, 0x21, 0x54, +0x16, 0x5d, 0x10, 0x65, 0x0b, 0x6c, 0x08, 0x72, 0x06, 0x77, 0x04, 0x7b, +0x03, 0x7f, 0x02, 0x83, 0x02, 0x87, 0x01, 0x8a, 0x01, 0x8c, 0x00, 0x8e, +0x00, 0x90, 0x00, 0x91, 0x00, 0x93, 0x00, 0x94, 0x00, 0x95, 0x00, 0x98, +0x3a, 0x19, 0x24, 0x2a, 0x18, 0x38, 0x10, 0x44, 0x0b, 0x4e, 0x07, 0x57, +0x05, 0x5f, 0x04, 0x65, 0x02, 0x6b, 0x01, 0x71, 0x01, 0x76, 0x00, 0x79, +0x00, 0x7e, 0x00, 0x80, 0x00, 0x84, 0x00, 0x87, 0x00, 0x88, 0x00, 0x8b, +0x00, 0x8d, 0x00, 0x8f, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, +0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, +0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, +0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x1d, 0x68, 0x12, 0x70, +0x0c, 0x77, 0x08, 0x7d, 0x05, 0x82, 0x03, 0x87, 0x02, 0x8b, 0x02, 0x8e, +0x01, 0x91, 0x00, 0x94, 0x00, 0x96, 0x00, 0x98, 0x00, 0x9a, 0x00, 0x9b, +0x00, 0x9d, 0x00, 0x9f, 0x00, 0xa0, 0x00, 0xa1, 0x00, 0xa2, 0x00, 0xa3, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x1f, +0x00, 0x2c, 0x00, 0x37, 0x00, 0x41, 0x00, 0x4a, 0x00, 0x9d, 0x00, 0x99, +0x00, 0x8e, 0x00, 0x7e, 0x00, 0x69, 0x00, 0x53, 0x00, 0x3c, 0x00, 0x26, +0x00, 0x12, 0x00, 0x00, 0x00, 0x10, 0x00, 0x1f, 0x00, 0x2c, 0x00, 0x37, +0x00, 0x41, 0x00, 0x4a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x5e, 0x00, 0x5b, 0x00, 0x53, 0x00, 0x48, 0x00, 0x3a, 0x00, 0x2a, 0x00, +0x1a, 0x00, 0x0b, 0x00, 0x05, 0x08, 0x00, 0x10, 0x00, 0x1e, 0x00, 0x2c, +0x00, 0x37, 0x00, 0x42, 0x00, 0x4b, 0x00, 0x53, 0x5e, 0x00, 0x5b, 0x00, +0x52, 0x00, 0x45, 0x00, 0x34, 0x00, 0x22, 0x00, 0x10, 0x00, 0x00, 0x00, +0x00, 0x11, 0x00, 0x1f, 0x00, 0x2d, 0x00, 0x38, 0x00, 0x43, 0x00, 0x4c, +0x00, 0x54, 0x00, 0x5b, 0x34, 0x49, 0x25, 0x51, 0x1a, 0x58, 0x13, 0x60, +0x0e, 0x65, 0x0b, 0x6b, 0x08, 0x71, 0x06, 0x75, 0x05, 0x78, 0x04, 0x7b, +0x03, 0x7f, 0x02, 0x83, 0x02, 0x86, 0x01, 0x88, 0x01, 0x8a, 0x00, 0x8c, +0x00, 0x8d, 0x00, 0x8f, 0x00, 0x90, 0x00, 0x92, 0x3b, 0x17, 0x28, 0x24, +0x1c, 0x30, 0x14, 0x3b, 0x0f, 0x45, 0x0b, 0x4d, 0x07, 0x55, 0x05, 0x5b, +0x04, 0x61, 0x03, 0x67, 0x02, 0x6b, 0x01, 0x6f, 0x01, 0x74, 0x00, 0x77, +0x00, 0x7a, 0x00, 0x7e, 0x00, 0x80, 0x00, 0x83, 0x00, 0x86, 0x00, 0x87, +0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, +0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, +0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, +0x00, 0xb7, 0x00, 0xb7, 0x1d, 0x67, 0x14, 0x6d, 0x0e, 0x73, 0x0a, 0x79, +0x07, 0x7e, 0x05, 0x82, 0x03, 0x86, 0x02, 0x89, 0x02, 0x8c, 0x01, 0x8f, +0x01, 0x91, 0x00, 0x93, 0x00, 0x96, 0x00, 0x97, 0x00, 0x99, 0x00, 0x9a, +0x00, 0x9b, 0x00, 0x9d, 0x00, 0x9e, 0x00, 0x9f, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x1c, 0x00, 0x28, +0x00, 0x33, 0x00, 0x3d, 0x00, 0x9d, 0x00, 0x9a, 0x00, 0x91, 0x00, 0x83, +0x00, 0x72, 0x00, 0x5e, 0x00, 0x4a, 0x00, 0x36, 0x00, 0x22, 0x00, 0x10, +0x00, 0x00, 0x00, 0x0f, 0x00, 0x1c, 0x00, 0x28, 0x00, 0x33, 0x00, 0x3d, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x5c, 0x00, +0x56, 0x00, 0x4c, 0x00, 0x40, 0x00, 0x32, 0x00, 0x24, 0x00, 0x15, 0x00, +0x0a, 0x02, 0x04, 0x09, 0x00, 0x10, 0x00, 0x1d, 0x00, 0x29, 0x00, 0x34, +0x00, 0x3e, 0x00, 0x46, 0x5e, 0x00, 0x5b, 0x00, 0x54, 0x00, 0x49, 0x00, +0x3b, 0x00, 0x2c, 0x00, 0x1b, 0x00, 0x0b, 0x00, 0x00, 0x04, 0x00, 0x12, +0x00, 0x1f, 0x00, 0x2b, 0x00, 0x36, 0x00, 0x40, 0x00, 0x49, 0x00, 0x50, +0x36, 0x47, 0x27, 0x4e, 0x1d, 0x54, 0x16, 0x5b, 0x11, 0x61, 0x0e, 0x65, +0x0b, 0x6a, 0x08, 0x6f, 0x07, 0x73, 0x05, 0x76, 0x05, 0x79, 0x03, 0x7c, +0x02, 0x7e, 0x02, 0x82, 0x02, 0x85, 0x01, 0x88, 0x01, 0x89, 0x01, 0x8b, +0x00, 0x8c, 0x00, 0x8d, 0x3d, 0x14, 0x2c, 0x20, 0x20, 0x2a, 0x18, 0x34, +0x12, 0x3e, 0x0e, 0x45, 0x0a, 0x4c, 0x07, 0x53, 0x06, 0x58, 0x05, 0x5e, +0x04, 0x63, 0x02, 0x67, 0x02, 0x6c, 0x01, 0x6f, 0x01, 0x72, 0x00, 0x76, +0x00, 0x78, 0x00, 0x7c, 0x00, 0x7e, 0x00, 0x80, 0x00, 0xb7, 0x00, 0xb7, +0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, +0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, +0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, +0x1e, 0x66, 0x16, 0x6b, 0x10, 0x71, 0x0c, 0x76, 0x09, 0x7a, 0x07, 0x7e, +0x05, 0x81, 0x03, 0x85, 0x03, 0x88, 0x02, 0x8b, 0x02, 0x8d, 0x01, 0x8f, +0x01, 0x91, 0x00, 0x93, 0x00, 0x95, 0x00, 0x96, 0x00, 0x98, 0x00, 0x99, +0x00, 0x9a, 0x00, 0x9b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x1a, 0x00, 0x25, 0x00, 0x2f, +0x00, 0x9e, 0x00, 0x9b, 0x00, 0x93, 0x00, 0x88, 0x00, 0x79, 0x00, 0x68, +0x00, 0x55, 0x00, 0x43, 0x00, 0x30, 0x00, 0x1f, 0x00, 0x0f, 0x00, 0x00, +0x00, 0x0d, 0x00, 0x1a, 0x00, 0x25, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x5c, 0x00, 0x57, 0x00, 0x4f, 0x00, +0x44, 0x00, 0x38, 0x00, 0x2c, 0x00, 0x1f, 0x00, 0x12, 0x00, 0x09, 0x03, +0x04, 0x09, 0x00, 0x10, 0x00, 0x1c, 0x00, 0x27, 0x00, 0x31, 0x00, 0x3a, +0x5e, 0x00, 0x5c, 0x00, 0x56, 0x00, 0x4d, 0x00, 0x41, 0x00, 0x33, 0x00, +0x24, 0x00, 0x15, 0x00, 0x07, 0x00, 0x00, 0x06, 0x00, 0x13, 0x00, 0x1f, +0x00, 0x2a, 0x00, 0x34, 0x00, 0x3d, 0x00, 0x46, 0x37, 0x46, 0x29, 0x4c, +0x20, 0x52, 0x19, 0x57, 0x14, 0x5d, 0x10, 0x62, 0x0d, 0x66, 0x0b, 0x69, +0x09, 0x6e, 0x07, 0x73, 0x06, 0x75, 0x05, 0x77, 0x04, 0x7a, 0x03, 0x7c, +0x02, 0x7e, 0x02, 0x82, 0x02, 0x84, 0x02, 0x87, 0x01, 0x88, 0x01, 0x89, +0x3f, 0x13, 0x2f, 0x1c, 0x23, 0x27, 0x1b, 0x2f, 0x15, 0x38, 0x10, 0x3e, +0x0d, 0x45, 0x0a, 0x4b, 0x08, 0x51, 0x07, 0x57, 0x05, 0x5c, 0x04, 0x60, +0x03, 0x65, 0x02, 0x67, 0x02, 0x6c, 0x01, 0x6f, 0x01, 0x71, 0x00, 0x75, +0x00, 0x77, 0x00, 0x79, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, +0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, +0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, +0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x1f, 0x65, 0x17, 0x6a, +0x11, 0x6f, 0x0d, 0x73, 0x0a, 0x77, 0x08, 0x7b, 0x06, 0x7e, 0x05, 0x81, +0x04, 0x84, 0x03, 0x87, 0x02, 0x89, 0x02, 0x8b, 0x01, 0x8e, 0x01, 0x8f, +0x01, 0x91, 0x00, 0x93, 0x00, 0x94, 0x00, 0x96, 0x00, 0x97, 0x00, 0x98, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x0c, 0x00, 0x18, 0x00, 0x22, 0x00, 0x9e, 0x00, 0x9c, +0x00, 0x95, 0x00, 0x8b, 0x00, 0x7e, 0x00, 0x6f, 0x00, 0x5f, 0x00, 0x4e, +0x00, 0x3d, 0x00, 0x2c, 0x00, 0x1c, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0c, +0x00, 0x18, 0x00, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x5e, 0x00, 0x5d, 0x00, 0x58, 0x00, 0x51, 0x00, 0x48, 0x00, 0x3e, 0x00, +0x32, 0x00, 0x26, 0x00, 0x1a, 0x00, 0x0f, 0x00, 0x08, 0x04, 0x04, 0x0a, +0x00, 0x10, 0x00, 0x1b, 0x00, 0x25, 0x00, 0x2f, 0x5e, 0x00, 0x5d, 0x00, +0x57, 0x00, 0x4f, 0x00, 0x45, 0x00, 0x39, 0x00, 0x2c, 0x00, 0x1e, 0x00, +0x10, 0x00, 0x03, 0x00, 0x00, 0x08, 0x00, 0x14, 0x00, 0x1f, 0x00, 0x2a, +0x00, 0x33, 0x00, 0x3b, 0x38, 0x45, 0x2b, 0x4a, 0x22, 0x50, 0x1c, 0x55, +0x16, 0x59, 0x12, 0x5f, 0x0f, 0x63, 0x0d, 0x66, 0x0b, 0x69, 0x09, 0x6e, +0x07, 0x71, 0x06, 0x74, 0x05, 0x76, 0x05, 0x78, 0x03, 0x7a, 0x03, 0x7c, +0x02, 0x7e, 0x02, 0x81, 0x02, 0x84, 0x02, 0x86, 0x40, 0x11, 0x31, 0x1b, +0x26, 0x23, 0x1e, 0x2b, 0x18, 0x33, 0x13, 0x39, 0x0f, 0x40, 0x0c, 0x45, +0x0a, 0x4b, 0x08, 0x51, 0x07, 0x56, 0x05, 0x59, 0x04, 0x5e, 0x04, 0x61, +0x02, 0x65, 0x02, 0x68, 0x02, 0x6b, 0x01, 0x6e, 0x01, 0x71, 0x00, 0x73, +0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, +0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, +0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, +0x00, 0xb7, 0x00, 0xb7, 0x20, 0x64, 0x18, 0x69, 0x13, 0x6d, 0x0f, 0x71, +0x0c, 0x75, 0x09, 0x78, 0x07, 0x7b, 0x06, 0x7e, 0x05, 0x81, 0x04, 0x84, +0x03, 0x86, 0x02, 0x88, 0x02, 0x8a, 0x02, 0x8c, 0x01, 0x8e, 0x01, 0x8f, +0x01, 0x91, 0x00, 0x93, 0x00, 0x94, 0x00, 0x95, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x0b, 0x00, 0x16, 0x00, 0x9e, 0x00, 0x9c, 0x00, 0x97, 0x00, 0x8e, +0x00, 0x83, 0x00, 0x75, 0x00, 0x66, 0x00, 0x57, 0x00, 0x47, 0x00, 0x37, +0x00, 0x28, 0x00, 0x1a, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x16, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x5d, 0x00, +0x59, 0x00, 0x53, 0x00, 0x4b, 0x00, 0x42, 0x00, 0x38, 0x00, 0x2d, 0x00, +0x22, 0x00, 0x17, 0x00, 0x0c, 0x00, 0x07, 0x05, 0x03, 0x0a, 0x00, 0x0f, +0x00, 0x1a, 0x00, 0x24, 0x5e, 0x00, 0x5d, 0x00, 0x59, 0x00, 0x52, 0x00, +0x49, 0x00, 0x3e, 0x00, 0x32, 0x00, 0x25, 0x00, 0x19, 0x00, 0x0c, 0x00, +0x00, 0x00, 0x00, 0x0a, 0x00, 0x15, 0x00, 0x1f, 0x00, 0x29, 0x00, 0x31, +0x38, 0x45, 0x2d, 0x49, 0x24, 0x4e, 0x1e, 0x53, 0x19, 0x56, 0x14, 0x5b, +0x11, 0x60, 0x0e, 0x63, 0x0c, 0x66, 0x0a, 0x69, 0x09, 0x6c, 0x07, 0x70, +0x06, 0x73, 0x06, 0x75, 0x05, 0x77, 0x04, 0x79, 0x03, 0x7a, 0x03, 0x7c, +0x02, 0x7e, 0x02, 0x80, 0x40, 0x11, 0x32, 0x18, 0x28, 0x20, 0x20, 0x28, +0x1a, 0x2f, 0x16, 0x35, 0x12, 0x3c, 0x0f, 0x41, 0x0c, 0x46, 0x0a, 0x4b, +0x08, 0x50, 0x07, 0x54, 0x05, 0x58, 0x05, 0x5c, 0x04, 0x5f, 0x04, 0x62, +0x02, 0x66, 0x02, 0x69, 0x01, 0x6b, 0x01, 0x6e, 0x00, 0xb7, 0x00, 0xb7, +0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, +0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, +0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, +0x20, 0x64, 0x19, 0x68, 0x14, 0x6b, 0x10, 0x6f, 0x0d, 0x73, 0x0b, 0x76, +0x09, 0x79, 0x07, 0x7c, 0x06, 0x7e, 0x05, 0x81, 0x04, 0x83, 0x03, 0x85, +0x02, 0x88, 0x02, 0x89, 0x02, 0x8b, 0x02, 0x8d, 0x01, 0x8e, 0x01, 0x90, +0x00, 0x91, 0x00, 0x92, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, +0x00, 0x9e, 0x00, 0x9c, 0x00, 0x98, 0x00, 0x90, 0x00, 0x86, 0x00, 0x7a, +0x00, 0x6d, 0x00, 0x5f, 0x00, 0x50, 0x00, 0x41, 0x00, 0x33, 0x00, 0x25, +0x00, 0x18, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x5d, 0x00, 0x5a, 0x00, 0x55, 0x00, +0x4e, 0x00, 0x45, 0x00, 0x3c, 0x00, 0x32, 0x00, 0x28, 0x00, 0x1e, 0x00, +0x14, 0x00, 0x0b, 0x00, 0x07, 0x06, 0x03, 0x0b, 0x00, 0x0f, 0x00, 0x19, +0x5e, 0x00, 0x5d, 0x00, 0x59, 0x00, 0x53, 0x00, 0x4b, 0x00, 0x42, 0x00, +0x37, 0x00, 0x2c, 0x00, 0x20, 0x00, 0x14, 0x00, 0x09, 0x00, 0x00, 0x01, +0x00, 0x0c, 0x00, 0x16, 0x00, 0x1f, 0x00, 0x28, 0x39, 0x44, 0x2e, 0x49, +0x26, 0x4c, 0x1f, 0x52, 0x1a, 0x55, 0x16, 0x58, 0x13, 0x5d, 0x10, 0x61, +0x0e, 0x64, 0x0c, 0x66, 0x0a, 0x68, 0x09, 0x6c, 0x07, 0x70, 0x07, 0x72, +0x06, 0x74, 0x05, 0x76, 0x05, 0x78, 0x03, 0x79, 0x03, 0x7b, 0x02, 0x7c, +0x41, 0x10, 0x34, 0x17, 0x2a, 0x1e, 0x23, 0x25, 0x1d, 0x2c, 0x18, 0x32, +0x14, 0x37, 0x10, 0x3d, 0x0e, 0x42, 0x0c, 0x46, 0x0a, 0x4b, 0x08, 0x4f, +0x07, 0x53, 0x05, 0x57, 0x05, 0x5a, 0x04, 0x5e, 0x04, 0x61, 0x03, 0x63, +0x02, 0x66, 0x02, 0x69, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, +0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, +0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, +0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x20, 0x63, 0x1a, 0x67, +0x15, 0x6a, 0x11, 0x6e, 0x0e, 0x71, 0x0c, 0x74, 0x0a, 0x77, 0x08, 0x7a, +0x07, 0x7c, 0x06, 0x7f, 0x05, 0x81, 0x04, 0x83, 0x03, 0x85, 0x02, 0x87, +0x02, 0x88, 0x02, 0x8a, 0x02, 0x8c, 0x01, 0x8d, 0x01, 0x8e, 0x01, 0x90, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x9d, +0x00, 0x99, 0x00, 0x92, 0x00, 0x89, 0x00, 0x7e, 0x00, 0x72, 0x00, 0x66, +0x00, 0x58, 0x00, 0x4a, 0x00, 0x3d, 0x00, 0x2f, 0x00, 0x22, 0x00, 0x16, +0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x5f, 0x00, 0x5e, 0x00, 0x5b, 0x00, 0x56, 0x00, 0x50, 0x00, 0x48, 0x00, +0x40, 0x00, 0x37, 0x00, 0x2d, 0x00, 0x24, 0x00, 0x1a, 0x00, 0x11, 0x00, +0x0a, 0x01, 0x06, 0x06, 0x03, 0x0b, 0x00, 0x0f, 0x5f, 0x00, 0x5d, 0x00, +0x5a, 0x00, 0x55, 0x00, 0x4e, 0x00, 0x45, 0x00, 0x3c, 0x00, 0x31, 0x00, +0x26, 0x00, 0x1b, 0x00, 0x11, 0x00, 0x06, 0x00, 0x00, 0x03, 0x00, 0x0d, +0x00, 0x17, 0x00, 0x1f, 0x39, 0x43, 0x2f, 0x48, 0x27, 0x4b, 0x22, 0x4f, +0x1c, 0x54, 0x18, 0x56, 0x14, 0x59, 0x12, 0x5e, 0x0f, 0x62, 0x0d, 0x64, +0x0c, 0x66, 0x0a, 0x68, 0x09, 0x6b, 0x08, 0x6f, 0x07, 0x72, 0x06, 0x74, +0x05, 0x75, 0x05, 0x77, 0x04, 0x78, 0x03, 0x7a, 0x42, 0x0f, 0x36, 0x16, +0x2c, 0x1c, 0x25, 0x23, 0x1f, 0x29, 0x1a, 0x2e, 0x16, 0x34, 0x12, 0x39, +0x0f, 0x3e, 0x0d, 0x42, 0x0c, 0x47, 0x0a, 0x4b, 0x08, 0x4f, 0x07, 0x52, +0x05, 0x56, 0x05, 0x59, 0x04, 0x5c, 0x04, 0x5f, 0x04, 0x62, 0x02, 0x64, +0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, +0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, +0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, +0x00, 0xb7, 0x00, 0xb7, 0x21, 0x63, 0x1b, 0x66, 0x16, 0x6a, 0x12, 0x6d, +0x0f, 0x70, 0x0d, 0x73, 0x0b, 0x75, 0x09, 0x78, 0x07, 0x7a, 0x06, 0x7d, +0x06, 0x7f, 0x05, 0x81, 0x04, 0x83, 0x03, 0x85, 0x02, 0x86, 0x02, 0x88, +0x02, 0x89, 0x02, 0x8b, 0x02, 0x8c, 0x01, 0x8d, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x3a, 0x43, 0x31, 0x48, 0x29, 0x4a, 0x23, 0x4d, 0x1e, 0x53, 0x1a, 0x55, +0x16, 0x57, 0x13, 0x5b, 0x11, 0x60, 0x0f, 0x62, 0x0d, 0x64, 0x0b, 0x66, +0x0a, 0x68, 0x09, 0x6a, 0x08, 0x6e, 0x07, 0x71, 0x06, 0x73, 0x06, 0x75, +0x05, 0x76, 0x05, 0x78, 0x43, 0x0f, 0x37, 0x15, 0x2e, 0x1b, 0x27, 0x21, +0x21, 0x26, 0x1c, 0x2c, 0x18, 0x31, 0x15, 0x36, 0x12, 0x3a, 0x0f, 0x3f, +0x0c, 0x43, 0x0c, 0x47, 0x0a, 0x4b, 0x08, 0x4e, 0x07, 0x52, 0x06, 0x55, +0x05, 0x58, 0x05, 0x5b, 0x04, 0x5d, 0x04, 0x60, 0x00, 0xb7, 0x00, 0xb7, +0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, +0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, +0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, +0x21, 0x63, 0x1b, 0x66, 0x17, 0x69, 0x13, 0x6c, 0x10, 0x6e, 0x0e, 0x71, +0x0c, 0x74, 0x0a, 0x76, 0x09, 0x79, 0x07, 0x7b, 0x06, 0x7d, 0x06, 0x7f, +0x05, 0x81, 0x04, 0x82, 0x03, 0x84, 0x03, 0x86, 0x02, 0x87, 0x02, 0x89, +0x02, 0x8a, 0x02, 0x8b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3a, 0x42, 0x31, 0x47, +0x2a, 0x49, 0x24, 0x4c, 0x1f, 0x51, 0x1b, 0x54, 0x18, 0x56, 0x15, 0x58, +0x12, 0x5c, 0x10, 0x61, 0x0e, 0x63, 0x0c, 0x64, 0x0b, 0x66, 0x0a, 0x68, +0x09, 0x6a, 0x08, 0x6d, 0x07, 0x71, 0x06, 0x72, 0x06, 0x74, 0x05, 0x75, +0x43, 0x0f, 0x38, 0x14, 0x2f, 0x19, 0x28, 0x1f, 0x22, 0x24, 0x1d, 0x29, +0x19, 0x2e, 0x16, 0x33, 0x12, 0x37, 0x11, 0x3b, 0x0f, 0x40, 0x0c, 0x43, +0x0b, 0x47, 0x0a, 0x4b, 0x09, 0x4e, 0x07, 0x51, 0x07, 0x55, 0x05, 0x56, +0x05, 0x5a, 0x04, 0x5c, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, +0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, +0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, +0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x21, 0x63, 0x1c, 0x65, +0x17, 0x68, 0x14, 0x6b, 0x11, 0x6e, 0x0e, 0x70, 0x0c, 0x73, 0x0b, 0x75, +0x09, 0x77, 0x08, 0x79, 0x07, 0x7b, 0x06, 0x7d, 0x05, 0x7f, 0x05, 0x81, +0x04, 0x82, 0x03, 0x84, 0x03, 0x86, 0x02, 0x87, 0x02, 0x88, 0x02, 0x89, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x3a, 0x42, 0x32, 0x46, 0x2b, 0x49, 0x25, 0x4b, +0x21, 0x4f, 0x1d, 0x53, 0x19, 0x55, 0x16, 0x57, 0x14, 0x59, 0x11, 0x5e, +0x10, 0x61, 0x0e, 0x63, 0x0c, 0x65, 0x0b, 0x66, 0x0a, 0x68, 0x09, 0x6a, +0x08, 0x6c, 0x07, 0x70, 0x07, 0x72, 0x06, 0x73, 0x43, 0x0e, 0x39, 0x13, +0x31, 0x18, 0x2a, 0x1d, 0x24, 0x22, 0x1f, 0x27, 0x1b, 0x2b, 0x18, 0x30, +0x16, 0x35, 0x12, 0x39, 0x0f, 0x3c, 0x0f, 0x41, 0x0c, 0x44, 0x0b, 0x47, +0x0a, 0x4a, 0x09, 0x4e, 0x07, 0x50, 0x07, 0x54, 0x05, 0x55, 0x05, 0x59, +0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, +0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, +0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, +0x00, 0xb7, 0x00, 0xb7, 0x21, 0x63, 0x1c, 0x65, 0x18, 0x68, 0x15, 0x6a, +0x12, 0x6c, 0x0f, 0x6f, 0x0d, 0x71, 0x0c, 0x73, 0x0b, 0x76, 0x09, 0x78, +0x07, 0x79, 0x07, 0x7c, 0x06, 0x7d, 0x05, 0x7f, 0x05, 0x81, 0x04, 0x82, +0x03, 0x84, 0x03, 0x85, 0x02, 0x86, 0x02, 0x88, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x3b, 0x42, 0x33, 0x45, 0x2c, 0x49, 0x27, 0x4b, 0x22, 0x4d, 0x1e, 0x52, +0x1b, 0x54, 0x18, 0x56, 0x15, 0x58, 0x13, 0x5b, 0x10, 0x5f, 0x0f, 0x61, +0x0e, 0x63, 0x0c, 0x65, 0x0b, 0x66, 0x0a, 0x68, 0x09, 0x69, 0x08, 0x6c, +0x07, 0x6f, 0x07, 0x72, 0x44, 0x0e, 0x3a, 0x12, 0x32, 0x17, 0x2b, 0x1c, +0x26, 0x21, 0x21, 0x26, 0x1d, 0x2a, 0x19, 0x2e, 0x16, 0x32, 0x14, 0x35, +0x12, 0x3a, 0x0f, 0x3d, 0x0e, 0x41, 0x0c, 0x44, 0x0b, 0x47, 0x0a, 0x4a, +0x09, 0x4e, 0x07, 0x4f, 0x07, 0x53, 0x05, 0x55, 0x00, 0xb7, 0x00, 0xb7, +0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, +0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, +0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, +0x22, 0x62, 0x1d, 0x65, 0x19, 0x67, 0x15, 0x6a, 0x13, 0x6c, 0x10, 0x6e, +0x0e, 0x71, 0x0c, 0x73, 0x0b, 0x74, 0x0a, 0x76, 0x09, 0x79, 0x07, 0x7a, +0x07, 0x7c, 0x06, 0x7d, 0x05, 0x7f, 0x05, 0x81, 0x04, 0x82, 0x03, 0x83, +0x03, 0x85, 0x02, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x42, 0x33, 0x44, +0x2d, 0x48, 0x28, 0x4a, 0x23, 0x4c, 0x1f, 0x50, 0x1c, 0x53, 0x19, 0x55, +0x16, 0x57, 0x14, 0x58, 0x12, 0x5c, 0x10, 0x60, 0x0e, 0x62, 0x0d, 0x63, +0x0c, 0x65, 0x0b, 0x66, 0x0a, 0x68, 0x09, 0x69, 0x09, 0x6b, 0x07, 0x6e, +0x44, 0x0d, 0x3a, 0x12, 0x33, 0x16, 0x2c, 0x1b, 0x27, 0x1f, 0x21, 0x24, +0x1e, 0x28, 0x1a, 0x2b, 0x18, 0x30, 0x16, 0x34, 0x12, 0x37, 0x11, 0x3b, +0x0f, 0x3e, 0x0d, 0x41, 0x0c, 0x45, 0x0a, 0x47, 0x0a, 0x4a, 0x09, 0x4e, +0x07, 0x4f, 0x07, 0x53, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, +0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, +0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, +0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x22, 0x62, 0x1d, 0x65, +0x19, 0x66, 0x16, 0x69, 0x13, 0x6b, 0x10, 0x6d, 0x0f, 0x6f, 0x0d, 0x71, +0x0c, 0x73, 0x0b, 0x76, 0x09, 0x77, 0x08, 0x79, 0x07, 0x7a, 0x06, 0x7c, +0x06, 0x7e, 0x05, 0x7f, 0x05, 0x80, 0x04, 0x82, 0x03, 0x83, 0x03, 0x85, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x3b, 0x42, 0x34, 0x44, 0x2e, 0x48, 0x29, 0x49, +0x24, 0x4b, 0x20, 0x4f, 0x1d, 0x53, 0x1a, 0x55, 0x18, 0x56, 0x15, 0x58, +0x13, 0x59, 0x11, 0x5d, 0x10, 0x61, 0x0e, 0x62, 0x0d, 0x63, 0x0c, 0x65, +0x0b, 0x66, 0x0a, 0x68, 0x09, 0x69, 0x09, 0x6b, 0x44, 0x0d, 0x3b, 0x12, +0x34, 0x16, 0x2e, 0x19, 0x28, 0x1e, 0x23, 0x22, 0x20, 0x26, 0x1d, 0x2b, +0x19, 0x2e, 0x16, 0x31, 0x14, 0x35, 0x12, 0x38, 0x0f, 0x3b, 0x0f, 0x3f, +0x0c, 0x41, 0x0c, 0x45, 0x0a, 0x47, 0x0a, 0x4a, 0x09, 0x4e, 0x07, 0x4e, +0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, +0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, +0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, +0x00, 0xb7, 0x00, 0xb7, 0x22, 0x62, 0x1d, 0x64, 0x1a, 0x66, 0x17, 0x68, +0x14, 0x6a, 0x11, 0x6c, 0x10, 0x6e, 0x0e, 0x71, 0x0c, 0x73, 0x0b, 0x74, +0x0a, 0x76, 0x09, 0x78, 0x07, 0x79, 0x07, 0x7b, 0x06, 0x7c, 0x06, 0x7e, +0x05, 0x7f, 0x05, 0x80, 0x04, 0x82, 0x03, 0x82, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x3b, 0x42, 0x34, 0x43, 0x2f, 0x48, 0x29, 0x49, 0x25, 0x4b, 0x21, 0x4d, +0x1e, 0x51, 0x1b, 0x54, 0x18, 0x55, 0x16, 0x56, 0x14, 0x58, 0x13, 0x5b, +0x10, 0x5e, 0x0f, 0x61, 0x0e, 0x63, 0x0c, 0x64, 0x0c, 0x66, 0x0b, 0x66, +0x0a, 0x68, 0x09, 0x69, 0x44, 0x0c, 0x3c, 0x11, 0x35, 0x16, 0x2f, 0x19, +0x2a, 0x1d, 0x25, 0x22, 0x21, 0x25, 0x1d, 0x29, 0x1a, 0x2b, 0x18, 0x30, +0x16, 0x33, 0x12, 0x35, 0x12, 0x3a, 0x0f, 0x3c, 0x0f, 0x40, 0x0c, 0x41, +0x0c, 0x45, 0x0a, 0x47, 0x0a, 0x4a, 0x09, 0x4e, 0x00, 0xb7, 0x00, 0xb7, +0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, +0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, +0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, +0x22, 0x62, 0x1e, 0x64, 0x1a, 0x66, 0x17, 0x68, 0x15, 0x6a, 0x12, 0x6c, +0x10, 0x6e, 0x0e, 0x70, 0x0d, 0x71, 0x0c, 0x73, 0x0b, 0x75, 0x09, 0x76, +0x09, 0x78, 0x07, 0x79, 0x07, 0x7b, 0x06, 0x7c, 0x06, 0x7e, 0x05, 0x7f, +0x05, 0x80, 0x04, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x42, 0x35, 0x43, +0x2f, 0x47, 0x2b, 0x49, 0x26, 0x4b, 0x22, 0x4c, 0x1f, 0x4f, 0x1c, 0x53, +0x1a, 0x55, 0x18, 0x56, 0x15, 0x58, 0x13, 0x59, 0x12, 0x5c, 0x10, 0x60, +0x0f, 0x61, 0x0e, 0x63, 0x0c, 0x64, 0x0c, 0x66, 0x0b, 0x66, 0x0a, 0x68, +0x44, 0x0c, 0x3c, 0x10, 0x35, 0x15, 0x30, 0x19, 0x2b, 0x1c, 0x26, 0x20, +0x21, 0x23, 0x1e, 0x26, 0x1c, 0x2b, 0x19, 0x2e, 0x16, 0x30, 0x15, 0x35, +0x12, 0x37, 0x11, 0x3b, 0x0f, 0x3d, 0x0f, 0x41, 0x0c, 0x42, 0x0c, 0x46, +0x0a, 0x47, 0x0a, 0x4a, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, +0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, +0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, +0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x00, 0xb7, 0x22, 0x62, 0x1e, 0x64, +0x1a, 0x66, 0x18, 0x68, 0x15, 0x6a, 0x13, 0x6b, 0x10, 0x6d, 0x0f, 0x6e, +0x0e, 0x71, 0x0c, 0x72, 0x0b, 0x74, 0x0a, 0x76, 0x09, 0x77, 0x08, 0x79, +0x07, 0x7a, 0x07, 0x7c, 0x06, 0x7c, 0x06, 0x7e, 0x05, 0x7f, 0x05, 0x80, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x44, 0x09, 0x43, 0x09, 0x44, 0x09, 0x45, 0x09, +0x45, 0x09, 0x46, 0x09, 0x46, 0x09, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, +0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, +0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, +0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, +0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, +0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, +0x00, 0x22, 0x1c, 0x0a, 0x29, 0x0a, 0x31, 0x09, 0x36, 0x09, 0x3a, 0x09, +0x3b, 0x09, 0x3d, 0x09, 0x3f, 0x09, 0x40, 0x09, 0x40, 0x09, 0x41, 0x09, +0x42, 0x09, 0x43, 0x09, 0x43, 0x0a, 0x43, 0x0a, 0x44, 0x0a, 0x44, 0x0a, +0x44, 0x0a, 0x44, 0x0a, 0x23, 0x16, 0x32, 0x0a, 0x38, 0x0a, 0x3c, 0x0a, +0x3f, 0x09, 0x40, 0x09, 0x41, 0x09, 0x42, 0x09, 0x43, 0x09, 0x44, 0x09, +0x44, 0x0a, 0x44, 0x0a, 0x44, 0x0a, 0x45, 0x0a, 0x45, 0x0a, 0x45, 0x0a, +0x45, 0x0a, 0x45, 0x0a, 0x45, 0x0a, 0x46, 0x0a, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x3f, 0x16, 0x3e, 0x11, 0x3f, 0x0f, 0x40, 0x0d, 0x41, 0x0d, 0x41, 0x0c, +0x42, 0x0c, 0x43, 0x0b, 0x43, 0x0b, 0x43, 0x0b, 0x43, 0x0b, 0x44, 0x0a, +0x44, 0x0a, 0x45, 0x0a, 0x45, 0x0a, 0x45, 0x0a, 0x46, 0x0a, 0x46, 0x0a, +0x46, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, +0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, +0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, +0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x00, 0x6e, 0x03, 0x3a, +0x0f, 0x27, 0x18, 0x1e, 0x1f, 0x19, 0x24, 0x17, 0x28, 0x14, 0x2c, 0x13, +0x2f, 0x11, 0x31, 0x11, 0x32, 0x10, 0x34, 0x0f, 0x36, 0x0f, 0x37, 0x0f, +0x38, 0x0e, 0x39, 0x0e, 0x3a, 0x0d, 0x3a, 0x0d, 0x3b, 0x0c, 0x3c, 0x0c, +0x23, 0x3c, 0x25, 0x22, 0x2b, 0x18, 0x30, 0x14, 0x33, 0x11, 0x36, 0x10, +0x38, 0x0f, 0x39, 0x0e, 0x3b, 0x0e, 0x3c, 0x0d, 0x3d, 0x0d, 0x3e, 0x0c, +0x3f, 0x0c, 0x3f, 0x0c, 0x40, 0x0c, 0x40, 0x0c, 0x40, 0x0b, 0x41, 0x0b, +0x41, 0x0b, 0x42, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x1f, 0x3c, 0x18, +0x3c, 0x14, 0x3d, 0x11, 0x3e, 0x11, 0x3f, 0x0f, 0x3f, 0x0e, 0x40, 0x0e, +0x41, 0x0d, 0x42, 0x0d, 0x42, 0x0d, 0x42, 0x0d, 0x42, 0x0c, 0x42, 0x0c, +0x42, 0x0b, 0x42, 0x0b, 0x43, 0x0b, 0x43, 0x0b, 0x44, 0x0b, 0x44, 0x0b, +0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, +0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, +0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, +0x47, 0x0a, 0x47, 0x0a, 0x00, 0x8a, 0x00, 0x59, 0x06, 0x40, 0x0d, 0x32, +0x12, 0x2a, 0x18, 0x24, 0x1c, 0x20, 0x20, 0x1c, 0x23, 0x1b, 0x26, 0x18, +0x28, 0x17, 0x2a, 0x16, 0x2c, 0x15, 0x2e, 0x14, 0x2f, 0x13, 0x31, 0x12, +0x32, 0x12, 0x33, 0x12, 0x34, 0x11, 0x35, 0x10, 0x23, 0x4a, 0x24, 0x31, +0x27, 0x25, 0x2a, 0x1e, 0x2d, 0x1a, 0x2f, 0x17, 0x32, 0x15, 0x33, 0x13, +0x35, 0x12, 0x36, 0x11, 0x38, 0x10, 0x39, 0x10, 0x3a, 0x0f, 0x3a, 0x0f, +0x3b, 0x0e, 0x3c, 0x0e, 0x3c, 0x0e, 0x3d, 0x0e, 0x3e, 0x0d, 0x3e, 0x0d, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x3e, 0x25, 0x3c, 0x1d, 0x3c, 0x19, 0x3c, 0x16, +0x3d, 0x14, 0x3d, 0x12, 0x3f, 0x11, 0x3f, 0x10, 0x3f, 0x0f, 0x3f, 0x0f, +0x40, 0x0e, 0x41, 0x0e, 0x41, 0x0d, 0x42, 0x0d, 0x42, 0x0d, 0x42, 0x0d, +0x42, 0x0d, 0x42, 0x0d, 0x42, 0x0d, 0x42, 0x0c, 0x47, 0x0a, 0x47, 0x0a, +0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, +0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, +0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, +0x00, 0x97, 0x00, 0x6c, 0x02, 0x52, 0x07, 0x43, 0x0b, 0x38, 0x10, 0x30, +0x14, 0x2a, 0x18, 0x27, 0x1b, 0x23, 0x1e, 0x20, 0x20, 0x1e, 0x23, 0x1c, +0x25, 0x1b, 0x27, 0x19, 0x28, 0x18, 0x2a, 0x17, 0x2b, 0x16, 0x2c, 0x16, +0x2e, 0x16, 0x2f, 0x15, 0x23, 0x50, 0x23, 0x3b, 0x25, 0x2e, 0x27, 0x26, +0x29, 0x21, 0x2c, 0x1d, 0x2e, 0x1a, 0x2f, 0x18, 0x31, 0x16, 0x33, 0x15, +0x34, 0x14, 0x35, 0x13, 0x36, 0x12, 0x37, 0x11, 0x38, 0x11, 0x38, 0x11, +0x39, 0x10, 0x3a, 0x10, 0x3a, 0x10, 0x3b, 0x0f, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x3e, 0x29, 0x3c, 0x22, 0x3b, 0x1d, 0x3b, 0x19, 0x3c, 0x17, 0x3c, 0x15, +0x3c, 0x13, 0x3d, 0x12, 0x3f, 0x11, 0x3f, 0x11, 0x3e, 0x10, 0x3e, 0x0f, +0x3f, 0x0f, 0x40, 0x0e, 0x40, 0x0e, 0x41, 0x0e, 0x42, 0x0e, 0x42, 0x0d, +0x42, 0x0d, 0x42, 0x0d, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, +0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, +0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, +0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x00, 0x9e, 0x00, 0x79, +0x00, 0x61, 0x04, 0x50, 0x07, 0x44, 0x0b, 0x3b, 0x0f, 0x34, 0x12, 0x2f, +0x15, 0x2b, 0x18, 0x28, 0x1a, 0x25, 0x1d, 0x23, 0x1f, 0x21, 0x21, 0x1f, +0x22, 0x1d, 0x24, 0x1c, 0x26, 0x1b, 0x27, 0x19, 0x28, 0x19, 0x2a, 0x19, +0x23, 0x54, 0x23, 0x42, 0x24, 0x35, 0x25, 0x2d, 0x27, 0x27, 0x29, 0x22, +0x2b, 0x1f, 0x2d, 0x1c, 0x2e, 0x1a, 0x30, 0x19, 0x31, 0x17, 0x32, 0x16, +0x33, 0x15, 0x34, 0x14, 0x35, 0x13, 0x36, 0x13, 0x37, 0x12, 0x37, 0x11, +0x38, 0x11, 0x38, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x2c, 0x3c, 0x25, +0x3b, 0x20, 0x3b, 0x1d, 0x3b, 0x1a, 0x3c, 0x17, 0x3c, 0x16, 0x3c, 0x14, +0x3c, 0x13, 0x3e, 0x12, 0x3f, 0x11, 0x3f, 0x11, 0x3f, 0x11, 0x3d, 0x10, +0x3e, 0x0f, 0x3f, 0x0f, 0x40, 0x0f, 0x40, 0x0e, 0x40, 0x0e, 0x41, 0x0e, +0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, +0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, +0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, +0x47, 0x0a, 0x47, 0x0a, 0x00, 0xa2, 0x00, 0x84, 0x00, 0x6c, 0x02, 0x5a, +0x05, 0x4e, 0x07, 0x45, 0x0b, 0x3e, 0x0e, 0x38, 0x10, 0x33, 0x13, 0x2f, +0x16, 0x2c, 0x18, 0x29, 0x1a, 0x26, 0x1c, 0x24, 0x1d, 0x22, 0x1f, 0x21, +0x21, 0x1f, 0x21, 0x1e, 0x23, 0x1d, 0x25, 0x1c, 0x23, 0x56, 0x23, 0x47, +0x23, 0x3b, 0x24, 0x32, 0x26, 0x2c, 0x27, 0x27, 0x29, 0x24, 0x2a, 0x21, +0x2c, 0x1e, 0x2d, 0x1c, 0x2e, 0x1b, 0x30, 0x19, 0x30, 0x18, 0x32, 0x17, +0x32, 0x16, 0x33, 0x15, 0x34, 0x14, 0x34, 0x14, 0x35, 0x13, 0x36, 0x13, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x3e, 0x2e, 0x3c, 0x27, 0x3b, 0x23, 0x3b, 0x1f, +0x3b, 0x1c, 0x3b, 0x1a, 0x3c, 0x18, 0x3c, 0x17, 0x3b, 0x15, 0x3c, 0x14, +0x3c, 0x13, 0x3e, 0x13, 0x3f, 0x11, 0x3f, 0x11, 0x3f, 0x11, 0x3e, 0x11, +0x3d, 0x10, 0x3e, 0x0f, 0x3f, 0x0f, 0x40, 0x0f, 0x47, 0x0a, 0x47, 0x0a, +0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, +0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, +0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, +0x00, 0xa6, 0x00, 0x8b, 0x00, 0x75, 0x01, 0x63, 0x02, 0x57, 0x05, 0x4d, +0x07, 0x45, 0x0a, 0x3e, 0x0d, 0x39, 0x0f, 0x35, 0x12, 0x32, 0x14, 0x2e, +0x16, 0x2c, 0x18, 0x29, 0x19, 0x27, 0x1b, 0x26, 0x1d, 0x24, 0x1e, 0x22, +0x20, 0x22, 0x21, 0x20, 0x23, 0x58, 0x23, 0x4a, 0x23, 0x3f, 0x24, 0x36, +0x25, 0x30, 0x26, 0x2b, 0x27, 0x27, 0x29, 0x24, 0x2a, 0x22, 0x2b, 0x20, +0x2d, 0x1e, 0x2e, 0x1c, 0x2e, 0x1b, 0x30, 0x1a, 0x30, 0x18, 0x31, 0x18, +0x32, 0x17, 0x32, 0x16, 0x33, 0x16, 0x34, 0x15, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x3e, 0x30, 0x3c, 0x2a, 0x3c, 0x25, 0x3a, 0x21, 0x3b, 0x1e, 0x3a, 0x1c, +0x3b, 0x1a, 0x3c, 0x18, 0x3c, 0x17, 0x3c, 0x16, 0x3b, 0x15, 0x3c, 0x14, +0x3d, 0x13, 0x3e, 0x13, 0x3f, 0x12, 0x3f, 0x11, 0x3f, 0x11, 0x3e, 0x11, +0x3d, 0x10, 0x3e, 0x0f, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, +0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, +0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, +0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x00, 0xa8, 0x00, 0x90, +0x00, 0x7c, 0x00, 0x6b, 0x01, 0x5f, 0x04, 0x55, 0x05, 0x4c, 0x07, 0x45, +0x0a, 0x40, 0x0c, 0x3c, 0x0f, 0x37, 0x10, 0x34, 0x12, 0x31, 0x15, 0x2e, +0x16, 0x2b, 0x18, 0x2a, 0x19, 0x28, 0x1a, 0x26, 0x1d, 0x25, 0x1d, 0x23, +0x23, 0x59, 0x23, 0x4d, 0x23, 0x43, 0x24, 0x3b, 0x24, 0x34, 0x25, 0x2f, +0x26, 0x2b, 0x27, 0x28, 0x28, 0x25, 0x2a, 0x23, 0x2b, 0x21, 0x2c, 0x1f, +0x2d, 0x1d, 0x2e, 0x1c, 0x2e, 0x1b, 0x30, 0x1a, 0x30, 0x19, 0x31, 0x18, +0x32, 0x17, 0x32, 0x16, 0x17, 0x00, 0x2f, 0x00, 0x4c, 0x00, 0x56, 0x00, +0x59, 0x00, 0x5b, 0x00, 0x5d, 0x00, 0x5d, 0x00, 0x5e, 0x00, 0x5e, 0x00, +0x5e, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x5f, 0x00, 0x5f, 0x00, 0x5f, 0x00, +0x14, 0x2c, 0x29, 0x01, 0x49, 0x00, 0x54, 0x00, 0x59, 0x00, 0x5b, 0x00, +0x5c, 0x00, 0x5d, 0x00, 0x5d, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x5e, 0x00, +0x5e, 0x00, 0x5e, 0x00, 0x5f, 0x00, 0x5f, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x4c, 0x00, 0x5f, 0x00, 0x62, 0x00, +0x62, 0x00, 0x5f, 0x00, 0x5d, 0x00, 0x5d, 0x00, 0x5e, 0x00, 0x5e, 0x00, +0x5e, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x5f, 0x00, 0x5f, 0x00, 0x5f, 0x00, +0x11, 0x31, 0x23, 0x03, 0x46, 0x00, 0x52, 0x00, 0x58, 0x00, 0x5a, 0x00, +0x5c, 0x00, 0x5d, 0x00, 0x5d, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x5e, 0x00, +0x5e, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x5f, 0x00, 0x3e, 0x32, 0x3d, 0x2c, +0x3c, 0x26, 0x3b, 0x23, 0x3b, 0x20, 0x3b, 0x1e, 0x3a, 0x1c, 0x3b, 0x1a, +0x3c, 0x18, 0x3c, 0x17, 0x3c, 0x17, 0x3a, 0x15, 0x3c, 0x15, 0x3c, 0x14, +0x3d, 0x13, 0x3e, 0x13, 0x3f, 0x12, 0x3f, 0x11, 0x3f, 0x11, 0x3e, 0x11, +0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, +0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, +0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, +0x47, 0x0a, 0x47, 0x0a, 0x00, 0xaa, 0x00, 0x94, 0x00, 0x82, 0x00, 0x72, +0x01, 0x65, 0x02, 0x5b, 0x04, 0x53, 0x06, 0x4b, 0x08, 0x45, 0x0a, 0x41, +0x0c, 0x3d, 0x0e, 0x39, 0x0f, 0x36, 0x12, 0x33, 0x12, 0x30, 0x16, 0x2e, +0x16, 0x2b, 0x18, 0x2b, 0x19, 0x29, 0x1a, 0x26, 0x23, 0x5a, 0x23, 0x4f, +0x23, 0x46, 0x23, 0x3e, 0x24, 0x37, 0x25, 0x32, 0x25, 0x2e, 0x26, 0x2b, +0x27, 0x28, 0x28, 0x25, 0x2a, 0x23, 0x2b, 0x21, 0x2b, 0x20, 0x2d, 0x1e, +0x2d, 0x1d, 0x2e, 0x1c, 0x2e, 0x1b, 0x30, 0x1a, 0x30, 0x19, 0x30, 0x18, +0x00, 0x00, 0x07, 0x00, 0x2f, 0x00, 0x45, 0x00, 0x4f, 0x00, 0x55, 0x00, +0x58, 0x00, 0x59, 0x00, 0x5b, 0x00, 0x5c, 0x00, 0x5c, 0x00, 0x5d, 0x00, +0x5d, 0x00, 0x5d, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x00, 0x57, 0x04, 0x16, +0x27, 0x00, 0x41, 0x00, 0x4d, 0x00, 0x53, 0x00, 0x56, 0x00, 0x59, 0x00, +0x5a, 0x00, 0x5b, 0x00, 0x5c, 0x00, 0x5c, 0x00, 0x5d, 0x00, 0x5d, 0x00, +0x5d, 0x00, 0x5e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x4c, 0x00, 0x3b, 0x00, 0x48, 0x00, 0x55, 0x00, 0x58, 0x00, 0x57, 0x00, +0x58, 0x00, 0x59, 0x00, 0x5b, 0x00, 0x5c, 0x00, 0x5c, 0x00, 0x5d, 0x00, +0x5d, 0x00, 0x5d, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x00, 0x5f, 0x00, 0x20, +0x1f, 0x00, 0x3c, 0x00, 0x4a, 0x00, 0x51, 0x00, 0x55, 0x00, 0x58, 0x00, +0x59, 0x00, 0x5b, 0x00, 0x5b, 0x00, 0x5c, 0x00, 0x5d, 0x00, 0x5d, 0x00, +0x5d, 0x00, 0x5d, 0x00, 0x3e, 0x33, 0x3d, 0x2d, 0x3c, 0x28, 0x3b, 0x25, +0x3a, 0x22, 0x3b, 0x1f, 0x3b, 0x1e, 0x3a, 0x1c, 0x3b, 0x1a, 0x3c, 0x19, +0x3c, 0x17, 0x3c, 0x17, 0x3b, 0x16, 0x3b, 0x15, 0x3c, 0x15, 0x3c, 0x13, +0x3d, 0x13, 0x3f, 0x13, 0x3f, 0x12, 0x3f, 0x11, 0x47, 0x0a, 0x47, 0x0a, +0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, +0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, +0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, +0x00, 0xaa, 0x00, 0x98, 0x00, 0x87, 0x00, 0x78, 0x00, 0x6b, 0x01, 0x61, +0x03, 0x58, 0x05, 0x51, 0x07, 0x4b, 0x08, 0x46, 0x0a, 0x42, 0x0c, 0x3e, +0x0d, 0x3a, 0x0f, 0x37, 0x11, 0x35, 0x12, 0x32, 0x14, 0x30, 0x16, 0x2e, +0x16, 0x2b, 0x18, 0x2b, 0x23, 0x5a, 0x23, 0x51, 0x23, 0x48, 0x23, 0x41, +0x24, 0x3a, 0x24, 0x35, 0x25, 0x31, 0x26, 0x2e, 0x27, 0x2a, 0x27, 0x28, +0x28, 0x26, 0x2a, 0x24, 0x2a, 0x22, 0x2b, 0x21, 0x2c, 0x1f, 0x2d, 0x1e, +0x2d, 0x1d, 0x2e, 0x1c, 0x2e, 0x1b, 0x30, 0x1a, 0x00, 0x00, 0x00, 0x00, +0x02, 0x00, 0x22, 0x00, 0x36, 0x00, 0x42, 0x00, 0x4a, 0x00, 0x4f, 0x00, +0x53, 0x00, 0x55, 0x00, 0x57, 0x00, 0x58, 0x00, 0x59, 0x00, 0x5a, 0x00, +0x5b, 0x00, 0x5b, 0x00, 0x00, 0x82, 0x00, 0x57, 0x01, 0x12, 0x17, 0x00, +0x2f, 0x00, 0x3e, 0x00, 0x47, 0x00, 0x4d, 0x00, 0x51, 0x00, 0x53, 0x00, +0x56, 0x00, 0x57, 0x00, 0x58, 0x00, 0x59, 0x00, 0x5a, 0x00, 0x5b, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x48, 0x00, +0x1b, 0x00, 0x34, 0x00, 0x40, 0x00, 0x44, 0x00, 0x4a, 0x00, 0x4f, 0x00, +0x53, 0x00, 0x55, 0x00, 0x57, 0x00, 0x58, 0x00, 0x59, 0x00, 0x5a, 0x00, +0x5b, 0x00, 0x5b, 0x00, 0x00, 0x85, 0x00, 0x5f, 0x00, 0x1f, 0x0d, 0x00, +0x28, 0x00, 0x39, 0x00, 0x43, 0x00, 0x4a, 0x00, 0x4e, 0x00, 0x52, 0x00, +0x54, 0x00, 0x56, 0x00, 0x57, 0x00, 0x59, 0x00, 0x59, 0x00, 0x5a, 0x00, +0x3e, 0x34, 0x3d, 0x2f, 0x3b, 0x2a, 0x3c, 0x26, 0x3a, 0x23, 0x3b, 0x21, +0x3b, 0x1f, 0x3b, 0x1d, 0x3a, 0x1c, 0x3b, 0x1a, 0x3c, 0x19, 0x3c, 0x17, +0x3c, 0x17, 0x3b, 0x17, 0x3a, 0x15, 0x3c, 0x15, 0x3c, 0x15, 0x3c, 0x13, +0x3e, 0x13, 0x3f, 0x13, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, +0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, +0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, +0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x00, 0xac, 0x00, 0x9b, +0x00, 0x8b, 0x00, 0x7c, 0x00, 0x71, 0x01, 0x67, 0x02, 0x5e, 0x04, 0x57, +0x05, 0x51, 0x07, 0x4b, 0x08, 0x46, 0x0a, 0x42, 0x0c, 0x3f, 0x0c, 0x3b, +0x0f, 0x39, 0x0f, 0x35, 0x12, 0x34, 0x12, 0x31, 0x14, 0x30, 0x16, 0x2e, +0x23, 0x5b, 0x23, 0x52, 0x23, 0x4a, 0x23, 0x43, 0x23, 0x3d, 0x24, 0x38, +0x25, 0x34, 0x25, 0x30, 0x26, 0x2d, 0x27, 0x2a, 0x28, 0x28, 0x28, 0x26, +0x2a, 0x24, 0x2a, 0x22, 0x2b, 0x21, 0x2b, 0x20, 0x2d, 0x1f, 0x2d, 0x1d, +0x2e, 0x1d, 0x2e, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, +0x19, 0x00, 0x2b, 0x00, 0x38, 0x00, 0x40, 0x00, 0x47, 0x00, 0x4b, 0x00, +0x4f, 0x00, 0x51, 0x00, 0x53, 0x00, 0x55, 0x00, 0x56, 0x00, 0x57, 0x00, +0x00, 0x91, 0x00, 0x78, 0x00, 0x43, 0x00, 0x10, 0x0e, 0x00, 0x23, 0x00, +0x31, 0x00, 0x3b, 0x00, 0x42, 0x00, 0x48, 0x00, 0x4c, 0x00, 0x4f, 0x00, +0x51, 0x00, 0x53, 0x00, 0x55, 0x00, 0x56, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x62, 0x00, 0x55, 0x00, 0x34, 0x00, 0x0b, 0x00, +0x1f, 0x00, 0x2b, 0x00, 0x38, 0x00, 0x40, 0x00, 0x47, 0x00, 0x4b, 0x00, +0x4f, 0x00, 0x51, 0x00, 0x53, 0x00, 0x55, 0x00, 0x56, 0x00, 0x57, 0x00, +0x00, 0x92, 0x00, 0x7c, 0x00, 0x4d, 0x00, 0x1f, 0x02, 0x00, 0x1a, 0x00, +0x2a, 0x00, 0x36, 0x00, 0x3e, 0x00, 0x45, 0x00, 0x49, 0x00, 0x4d, 0x00, +0x4f, 0x00, 0x52, 0x00, 0x53, 0x00, 0x55, 0x00, 0x3e, 0x35, 0x3e, 0x30, +0x3b, 0x2c, 0x3c, 0x28, 0x3b, 0x25, 0x3a, 0x22, 0x3b, 0x20, 0x3b, 0x1f, +0x3a, 0x1d, 0x3a, 0x1c, 0x3b, 0x1a, 0x3c, 0x19, 0x3c, 0x18, 0x3c, 0x17, +0x3c, 0x17, 0x3a, 0x16, 0x3b, 0x15, 0x3c, 0x15, 0x3c, 0x14, 0x3c, 0x13, +0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, +0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, +0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, +0x47, 0x0a, 0x47, 0x0a, 0x00, 0xad, 0x00, 0x9d, 0x00, 0x8e, 0x00, 0x81, +0x00, 0x76, 0x00, 0x6b, 0x01, 0x63, 0x02, 0x5c, 0x04, 0x56, 0x05, 0x50, +0x07, 0x4b, 0x08, 0x47, 0x0a, 0x43, 0x0c, 0x40, 0x0c, 0x3c, 0x0f, 0x3a, +0x0f, 0x37, 0x11, 0x35, 0x12, 0x33, 0x12, 0x30, 0x23, 0x5b, 0x23, 0x53, +0x23, 0x4c, 0x23, 0x45, 0x23, 0x40, 0x24, 0x3b, 0x24, 0x36, 0x25, 0x33, +0x25, 0x30, 0x26, 0x2d, 0x27, 0x2a, 0x28, 0x28, 0x28, 0x26, 0x2a, 0x25, +0x2a, 0x23, 0x2b, 0x22, 0x2b, 0x20, 0x2c, 0x20, 0x2d, 0x1e, 0x2d, 0x1d, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, +0x24, 0x00, 0x2f, 0x00, 0x38, 0x00, 0x3f, 0x00, 0x44, 0x00, 0x48, 0x00, +0x4c, 0x00, 0x4e, 0x00, 0x50, 0x00, 0x52, 0x00, 0x00, 0x96, 0x00, 0x87, +0x00, 0x61, 0x00, 0x36, 0x00, 0x10, 0x0a, 0x02, 0x1a, 0x00, 0x27, 0x00, +0x32, 0x00, 0x3a, 0x00, 0x40, 0x00, 0x44, 0x00, 0x48, 0x00, 0x4b, 0x00, +0x4e, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x62, 0x00, 0x58, 0x00, 0x40, 0x00, 0x1f, 0x00, 0x01, 0x00, 0x14, 0x00, +0x24, 0x00, 0x2f, 0x00, 0x38, 0x00, 0x3f, 0x00, 0x44, 0x00, 0x48, 0x00, +0x4c, 0x00, 0x4e, 0x00, 0x50, 0x00, 0x52, 0x00, 0x00, 0x97, 0x00, 0x8a, +0x00, 0x68, 0x00, 0x42, 0x00, 0x1f, 0x00, 0x04, 0x10, 0x00, 0x1f, 0x00, +0x2b, 0x00, 0x34, 0x00, 0x3b, 0x00, 0x41, 0x00, 0x45, 0x00, 0x49, 0x00, +0x4b, 0x00, 0x4e, 0x00, 0x3e, 0x36, 0x3e, 0x31, 0x3b, 0x2c, 0x3c, 0x29, +0x3c, 0x26, 0x3a, 0x24, 0x3a, 0x21, 0x3b, 0x20, 0x3b, 0x1f, 0x39, 0x1d, +0x3b, 0x1c, 0x3b, 0x1a, 0x3c, 0x19, 0x3c, 0x18, 0x3c, 0x17, 0x3c, 0x17, +0x3a, 0x17, 0x3a, 0x15, 0x3c, 0x15, 0x3c, 0x15, 0x47, 0x0a, 0x47, 0x0a, +0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, +0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, +0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, +0x00, 0xad, 0x00, 0x9f, 0x00, 0x91, 0x00, 0x85, 0x00, 0x79, 0x00, 0x6f, +0x01, 0x67, 0x02, 0x60, 0x03, 0x59, 0x04, 0x54, 0x05, 0x4f, 0x07, 0x4b, +0x08, 0x47, 0x0a, 0x43, 0x0b, 0x41, 0x0c, 0x3d, 0x0e, 0x3b, 0x0f, 0x38, +0x0f, 0x35, 0x12, 0x35, 0x23, 0x5b, 0x23, 0x54, 0x23, 0x4e, 0x23, 0x47, +0x23, 0x42, 0x24, 0x3c, 0x24, 0x38, 0x25, 0x35, 0x25, 0x32, 0x26, 0x2f, +0x26, 0x2d, 0x27, 0x2a, 0x28, 0x28, 0x28, 0x26, 0x29, 0x25, 0x2a, 0x23, +0x2b, 0x22, 0x2b, 0x21, 0x2b, 0x20, 0x2d, 0x20, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x1e, 0x00, +0x29, 0x00, 0x32, 0x00, 0x38, 0x00, 0x3e, 0x00, 0x42, 0x00, 0x46, 0x00, +0x49, 0x00, 0x4c, 0x00, 0x00, 0x99, 0x00, 0x8f, 0x00, 0x74, 0x00, 0x51, +0x00, 0x2e, 0x00, 0x10, 0x08, 0x04, 0x13, 0x00, 0x20, 0x00, 0x2a, 0x00, +0x32, 0x00, 0x38, 0x00, 0x3e, 0x00, 0x42, 0x00, 0x45, 0x00, 0x48, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x57, 0x00, +0x44, 0x00, 0x2b, 0x00, 0x14, 0x00, 0x00, 0x00, 0x10, 0x00, 0x1e, 0x00, +0x29, 0x00, 0x32, 0x00, 0x38, 0x00, 0x3e, 0x00, 0x42, 0x00, 0x46, 0x00, +0x49, 0x00, 0x4c, 0x00, 0x00, 0x9a, 0x00, 0x91, 0x00, 0x79, 0x00, 0x5a, +0x00, 0x3b, 0x00, 0x1f, 0x00, 0x09, 0x08, 0x00, 0x17, 0x00, 0x22, 0x00, +0x2c, 0x00, 0x33, 0x00, 0x39, 0x00, 0x3e, 0x00, 0x42, 0x00, 0x45, 0x00, +0x3e, 0x36, 0x3e, 0x31, 0x3b, 0x2d, 0x3b, 0x2a, 0x3c, 0x27, 0x3a, 0x25, +0x3a, 0x23, 0x3b, 0x21, 0x3b, 0x1f, 0x3b, 0x1f, 0x39, 0x1c, 0x3b, 0x1c, +0x3b, 0x1a, 0x3c, 0x19, 0x3c, 0x19, 0x3c, 0x17, 0x3c, 0x17, 0x3b, 0x17, +0x3a, 0x16, 0x3b, 0x15, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, +0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, +0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, +0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x00, 0xad, 0x00, 0xa0, +0x00, 0x94, 0x00, 0x88, 0x00, 0x7e, 0x00, 0x74, 0x00, 0x6c, 0x01, 0x65, +0x02, 0x5e, 0x04, 0x58, 0x05, 0x53, 0x05, 0x4f, 0x07, 0x4b, 0x08, 0x47, +0x0a, 0x44, 0x0b, 0x41, 0x0c, 0x3e, 0x0d, 0x3b, 0x0f, 0x3a, 0x0f, 0x37, +0x23, 0x5c, 0x23, 0x55, 0x23, 0x4f, 0x23, 0x49, 0x23, 0x44, 0x23, 0x3f, +0x24, 0x3b, 0x24, 0x37, 0x25, 0x34, 0x25, 0x31, 0x26, 0x2e, 0x26, 0x2c, +0x27, 0x2a, 0x28, 0x28, 0x28, 0x27, 0x29, 0x25, 0x2a, 0x24, 0x2a, 0x22, +0x2b, 0x22, 0x2b, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x1a, 0x00, 0x24, 0x00, +0x2c, 0x00, 0x33, 0x00, 0x39, 0x00, 0x3d, 0x00, 0x41, 0x00, 0x44, 0x00, +0x00, 0x9b, 0x00, 0x94, 0x00, 0x7f, 0x00, 0x64, 0x00, 0x46, 0x00, 0x29, +0x00, 0x10, 0x07, 0x06, 0x0e, 0x00, 0x1a, 0x00, 0x24, 0x00, 0x2c, 0x00, +0x32, 0x00, 0x38, 0x00, 0x3c, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x5d, 0x00, 0x58, 0x00, 0x4a, 0x00, 0x38, 0x00, +0x24, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x1a, 0x00, 0x24, 0x00, +0x2c, 0x00, 0x33, 0x00, 0x39, 0x00, 0x3d, 0x00, 0x41, 0x00, 0x44, 0x00, +0x00, 0x9b, 0x00, 0x95, 0x00, 0x83, 0x00, 0x6a, 0x00, 0x4f, 0x00, 0x36, +0x00, 0x1f, 0x00, 0x0c, 0x03, 0x00, 0x10, 0x00, 0x1b, 0x00, 0x24, 0x00, +0x2c, 0x00, 0x32, 0x00, 0x37, 0x00, 0x3c, 0x00, 0x3e, 0x37, 0x3e, 0x32, +0x3c, 0x2f, 0x3b, 0x2b, 0x3c, 0x28, 0x3b, 0x26, 0x3a, 0x24, 0x3a, 0x22, +0x3b, 0x21, 0x3b, 0x1f, 0x3a, 0x1e, 0x39, 0x1c, 0x3b, 0x1c, 0x3b, 0x1a, +0x3c, 0x19, 0x3c, 0x19, 0x3c, 0x17, 0x3c, 0x17, 0x3b, 0x17, 0x3a, 0x17, +0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, +0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, +0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, +0x47, 0x0a, 0x47, 0x0a, 0x00, 0xae, 0x00, 0xa2, 0x00, 0x97, 0x00, 0x8b, +0x00, 0x80, 0x00, 0x77, 0x00, 0x6f, 0x01, 0x67, 0x02, 0x61, 0x02, 0x5c, +0x04, 0x57, 0x05, 0x52, 0x05, 0x4e, 0x07, 0x4b, 0x09, 0x47, 0x0a, 0x44, +0x0b, 0x41, 0x0c, 0x3f, 0x0c, 0x3c, 0x0f, 0x3b, 0x23, 0x5c, 0x23, 0x56, +0x23, 0x50, 0x23, 0x4a, 0x23, 0x45, 0x23, 0x40, 0x24, 0x3c, 0x24, 0x39, +0x25, 0x35, 0x25, 0x33, 0x25, 0x30, 0x26, 0x2e, 0x26, 0x2c, 0x27, 0x2a, +0x28, 0x28, 0x28, 0x27, 0x29, 0x25, 0x2a, 0x24, 0x2a, 0x23, 0x2b, 0x22, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x17, 0x00, 0x20, 0x00, 0x28, 0x00, +0x2e, 0x00, 0x34, 0x00, 0x39, 0x00, 0x3d, 0x00, 0x00, 0x9c, 0x00, 0x96, +0x00, 0x87, 0x00, 0x71, 0x00, 0x57, 0x00, 0x3d, 0x00, 0x25, 0x00, 0x10, +0x06, 0x07, 0x0b, 0x00, 0x15, 0x00, 0x1f, 0x00, 0x26, 0x00, 0x2d, 0x00, +0x32, 0x00, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x5d, 0x00, 0x59, 0x00, 0x4f, 0x00, 0x40, 0x00, 0x2f, 0x00, 0x1e, 0x00, +0x0e, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x17, 0x00, 0x20, 0x00, 0x28, 0x00, +0x2e, 0x00, 0x34, 0x00, 0x39, 0x00, 0x3d, 0x00, 0x00, 0x9c, 0x00, 0x97, +0x00, 0x8a, 0x00, 0x76, 0x00, 0x5f, 0x00, 0x48, 0x00, 0x33, 0x00, 0x1f, +0x00, 0x0f, 0x00, 0x00, 0x0b, 0x00, 0x15, 0x00, 0x1e, 0x00, 0x25, 0x00, +0x2c, 0x00, 0x31, 0x00, 0x3e, 0x37, 0x3e, 0x33, 0x3c, 0x2f, 0x3b, 0x2c, +0x3c, 0x29, 0x3c, 0x27, 0x39, 0x25, 0x3a, 0x23, 0x3b, 0x21, 0x3b, 0x20, +0x3b, 0x1f, 0x3a, 0x1e, 0x39, 0x1c, 0x3b, 0x1c, 0x3b, 0x1a, 0x3c, 0x19, +0x3c, 0x19, 0x3c, 0x18, 0x3c, 0x17, 0x3b, 0x17, 0x47, 0x0a, 0x47, 0x0a, +0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, +0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, +0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, +0x00, 0xaf, 0x00, 0xa3, 0x00, 0x98, 0x00, 0x8e, 0x00, 0x84, 0x00, 0x7a, +0x00, 0x72, 0x00, 0x6c, 0x01, 0x65, 0x02, 0x5f, 0x04, 0x5a, 0x04, 0x56, +0x05, 0x52, 0x06, 0x4e, 0x07, 0x4a, 0x09, 0x47, 0x0a, 0x45, 0x0a, 0x41, +0x0c, 0x40, 0x0c, 0x3d, 0x23, 0x5c, 0x23, 0x56, 0x23, 0x51, 0x23, 0x4c, +0x23, 0x47, 0x23, 0x42, 0x23, 0x3e, 0x24, 0x3b, 0x24, 0x37, 0x25, 0x34, +0x25, 0x32, 0x25, 0x30, 0x26, 0x2e, 0x27, 0x2c, 0x27, 0x2a, 0x28, 0x28, +0x28, 0x27, 0x29, 0x25, 0x2a, 0x25, 0x2a, 0x23, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x0b, 0x00, 0x14, 0x00, 0x1d, 0x00, 0x24, 0x00, 0x2a, 0x00, +0x30, 0x00, 0x35, 0x00, 0x00, 0x9d, 0x00, 0x98, 0x00, 0x8c, 0x00, 0x7a, +0x00, 0x64, 0x00, 0x4e, 0x00, 0x37, 0x00, 0x22, 0x00, 0x10, 0x05, 0x08, +0x0a, 0x02, 0x12, 0x00, 0x1a, 0x00, 0x22, 0x00, 0x28, 0x00, 0x2d, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x5b, 0x00, +0x53, 0x00, 0x47, 0x00, 0x38, 0x00, 0x29, 0x00, 0x1a, 0x00, 0x0c, 0x00, +0x00, 0x00, 0x0b, 0x00, 0x14, 0x00, 0x1d, 0x00, 0x24, 0x00, 0x2a, 0x00, +0x30, 0x00, 0x35, 0x00, 0x00, 0x9d, 0x00, 0x99, 0x00, 0x8e, 0x00, 0x7e, +0x00, 0x6b, 0x00, 0x57, 0x00, 0x43, 0x00, 0x30, 0x00, 0x1f, 0x00, 0x11, +0x00, 0x04, 0x07, 0x00, 0x10, 0x00, 0x19, 0x00, 0x20, 0x00, 0x26, 0x00, +0x3e, 0x38, 0x3e, 0x33, 0x3d, 0x30, 0x3b, 0x2d, 0x3c, 0x2a, 0x3c, 0x27, +0x3a, 0x26, 0x3a, 0x24, 0x3a, 0x22, 0x3b, 0x21, 0x3b, 0x1f, 0x3b, 0x1f, +0x39, 0x1e, 0x3a, 0x1c, 0x3b, 0x1c, 0x3b, 0x1a, 0x3c, 0x19, 0x3c, 0x19, +0x3c, 0x18, 0x3c, 0x17, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, +0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, +0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, +0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x00, 0xaf, 0x00, 0xa5, +0x00, 0x99, 0x00, 0x90, 0x00, 0x87, 0x00, 0x7e, 0x00, 0x76, 0x00, 0x6f, +0x01, 0x68, 0x02, 0x62, 0x02, 0x5e, 0x04, 0x59, 0x04, 0x55, 0x05, 0x51, +0x07, 0x4e, 0x07, 0x4a, 0x09, 0x47, 0x0a, 0x45, 0x0a, 0x41, 0x0c, 0x41, +0x23, 0x5c, 0x23, 0x57, 0x23, 0x52, 0x23, 0x4d, 0x23, 0x48, 0x23, 0x44, +0x23, 0x40, 0x24, 0x3c, 0x24, 0x39, 0x24, 0x36, 0x25, 0x34, 0x25, 0x31, +0x26, 0x2f, 0x26, 0x2d, 0x27, 0x2c, 0x27, 0x2a, 0x28, 0x28, 0x28, 0x27, +0x28, 0x25, 0x2a, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x09, 0x00, 0x12, 0x00, 0x1a, 0x00, 0x21, 0x00, 0x27, 0x00, 0x2c, 0x00, +0x00, 0x9d, 0x00, 0x9a, 0x00, 0x90, 0x00, 0x81, 0x00, 0x6f, 0x00, 0x5b, +0x00, 0x46, 0x00, 0x32, 0x00, 0x20, 0x00, 0x10, 0x04, 0x09, 0x09, 0x03, +0x0f, 0x00, 0x17, 0x00, 0x1e, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x5c, 0x00, 0x55, 0x00, 0x4b, 0x00, +0x3f, 0x00, 0x32, 0x00, 0x24, 0x00, 0x17, 0x00, 0x0b, 0x00, 0x00, 0x00, +0x09, 0x00, 0x12, 0x00, 0x1a, 0x00, 0x21, 0x00, 0x27, 0x00, 0x2c, 0x00, +0x00, 0x9d, 0x00, 0x9a, 0x00, 0x92, 0x00, 0x84, 0x00, 0x74, 0x00, 0x62, +0x00, 0x50, 0x00, 0x3f, 0x00, 0x2e, 0x00, 0x1f, 0x00, 0x12, 0x00, 0x06, +0x03, 0x00, 0x0c, 0x00, 0x14, 0x00, 0x1b, 0x00, 0x3e, 0x38, 0x3e, 0x34, +0x3e, 0x31, 0x3b, 0x2e, 0x3b, 0x2b, 0x3c, 0x29, 0x3c, 0x27, 0x39, 0x25, +0x3a, 0x24, 0x3a, 0x21, 0x3b, 0x21, 0x3b, 0x1f, 0x3b, 0x1f, 0x39, 0x1d, +0x3a, 0x1c, 0x3b, 0x1c, 0x3b, 0x1a, 0x3c, 0x19, 0x3c, 0x19, 0x3c, 0x19, +0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, +0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, +0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, +0x47, 0x0a, 0x47, 0x0a, 0x00, 0xaf, 0x00, 0xa6, 0x00, 0x9b, 0x00, 0x91, +0x00, 0x88, 0x00, 0x80, 0x00, 0x78, 0x00, 0x71, 0x00, 0x6b, 0x01, 0x66, +0x02, 0x61, 0x03, 0x5c, 0x04, 0x58, 0x05, 0x55, 0x05, 0x50, 0x07, 0x4e, +0x07, 0x4a, 0x09, 0x47, 0x0a, 0x45, 0x0a, 0x42, 0x23, 0x5c, 0x23, 0x58, +0x23, 0x53, 0x23, 0x4d, 0x23, 0x49, 0x23, 0x45, 0x23, 0x41, 0x24, 0x3d, +0x24, 0x3b, 0x24, 0x38, 0x25, 0x35, 0x25, 0x33, 0x25, 0x31, 0x26, 0x2f, +0x26, 0x2d, 0x27, 0x2c, 0x27, 0x2a, 0x28, 0x28, 0x28, 0x28, 0x28, 0x26, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, +0x11, 0x00, 0x18, 0x00, 0x1e, 0x00, 0x24, 0x00, 0x00, 0x9d, 0x00, 0x9b, +0x00, 0x93, 0x00, 0x86, 0x00, 0x76, 0x00, 0x65, 0x00, 0x52, 0x00, 0x40, +0x00, 0x2f, 0x00, 0x1e, 0x00, 0x10, 0x04, 0x09, 0x08, 0x04, 0x0c, 0x00, +0x14, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x5e, 0x00, 0x5c, 0x00, 0x57, 0x00, 0x4f, 0x00, 0x44, 0x00, 0x38, 0x00, +0x2c, 0x00, 0x20, 0x00, 0x14, 0x00, 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, +0x11, 0x00, 0x18, 0x00, 0x1e, 0x00, 0x24, 0x00, 0x00, 0x9e, 0x00, 0x9b, +0x00, 0x94, 0x00, 0x89, 0x00, 0x7b, 0x00, 0x6b, 0x00, 0x5b, 0x00, 0x4b, +0x00, 0x3b, 0x00, 0x2d, 0x00, 0x1f, 0x00, 0x13, 0x00, 0x08, 0x00, 0x00, +0x09, 0x00, 0x11, 0x00, 0x3e, 0x38, 0x3e, 0x35, 0x3e, 0x32, 0x3b, 0x2e, +0x3b, 0x2c, 0x3c, 0x2a, 0x3c, 0x27, 0x3a, 0x26, 0x3a, 0x24, 0x3a, 0x23, +0x3b, 0x21, 0x3b, 0x20, 0x3b, 0x1f, 0x3a, 0x1f, 0x39, 0x1d, 0x3a, 0x1c, +0x3b, 0x1c, 0x3b, 0x1a, 0x3c, 0x19, 0x3c, 0x19, 0x47, 0x0a, 0x47, 0x0a, +0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, +0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, +0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, +0x00, 0xb0, 0x00, 0xa6, 0x00, 0x9d, 0x00, 0x93, 0x00, 0x8b, 0x00, 0x83, +0x00, 0x7c, 0x00, 0x75, 0x00, 0x6e, 0x01, 0x69, 0x01, 0x63, 0x02, 0x5f, +0x04, 0x5b, 0x04, 0x56, 0x05, 0x54, 0x05, 0x4f, 0x07, 0x4e, 0x07, 0x4a, +0x09, 0x47, 0x0a, 0x46, 0x23, 0x5d, 0x23, 0x58, 0x23, 0x53, 0x23, 0x4f, +0x23, 0x4a, 0x23, 0x46, 0x23, 0x43, 0x23, 0x3f, 0x24, 0x3c, 0x24, 0x39, +0x24, 0x36, 0x25, 0x34, 0x25, 0x32, 0x25, 0x30, 0x26, 0x2f, 0x26, 0x2d, +0x27, 0x2c, 0x27, 0x2a, 0x28, 0x28, 0x28, 0x28, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0f, 0x00, +0x16, 0x00, 0x1c, 0x00, 0x00, 0x9e, 0x00, 0x9b, 0x00, 0x95, 0x00, 0x8a, +0x00, 0x7d, 0x00, 0x6d, 0x00, 0x5d, 0x00, 0x4c, 0x00, 0x3b, 0x00, 0x2c, +0x00, 0x1d, 0x00, 0x10, 0x04, 0x0a, 0x07, 0x05, 0x0b, 0x00, 0x11, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x5d, 0x00, +0x58, 0x00, 0x51, 0x00, 0x48, 0x00, 0x3e, 0x00, 0x33, 0x00, 0x28, 0x00, +0x1d, 0x00, 0x12, 0x00, 0x09, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0f, 0x00, +0x16, 0x00, 0x1c, 0x00, 0x00, 0x9e, 0x00, 0x9c, 0x00, 0x96, 0x00, 0x8c, +0x00, 0x80, 0x00, 0x73, 0x00, 0x64, 0x00, 0x55, 0x00, 0x46, 0x00, 0x38, +0x00, 0x2b, 0x00, 0x1f, 0x00, 0x14, 0x00, 0x0a, 0x00, 0x01, 0x06, 0x00, +0x3e, 0x39, 0x3e, 0x35, 0x3e, 0x32, 0x3b, 0x2f, 0x3b, 0x2d, 0x3c, 0x2a, +0x3c, 0x28, 0x3b, 0x27, 0x39, 0x24, 0x3a, 0x24, 0x3a, 0x22, 0x3b, 0x21, +0x3b, 0x1f, 0x3b, 0x1f, 0x39, 0x1f, 0x39, 0x1d, 0x3b, 0x1c, 0x3b, 0x1c, +0x3b, 0x1a, 0x3c, 0x19, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, +0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, +0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, +0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x47, 0x0a, 0x00, 0xb0, 0x00, 0xa7, +0x00, 0x9e, 0x00, 0x96, 0x00, 0x8d, 0x00, 0x86, 0x00, 0x7e, 0x00, 0x77, +0x00, 0x71, 0x00, 0x6b, 0x01, 0x66, 0x02, 0x62, 0x02, 0x5d, 0x04, 0x5a, +0x04, 0x55, 0x05, 0x53, 0x05, 0x4f, 0x07, 0x4e, 0x07, 0x4a, 0x09, 0x47, +0x23, 0x5d, 0x23, 0x58, 0x23, 0x54, 0x23, 0x50, 0x23, 0x4c, 0x23, 0x48, +0x23, 0x44, 0x23, 0x40, 0x24, 0x3d, 0x24, 0x3a, 0x24, 0x38, 0x25, 0x36, +0x25, 0x33, 0x25, 0x32, 0x25, 0x2f, 0x26, 0x2f, 0x26, 0x2c, 0x27, 0x2c, +0x27, 0x2a, 0x28, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x0e, 0x00, 0x14, 0x00, +0x00, 0x9e, 0x00, 0x9c, 0x00, 0x96, 0x00, 0x8d, 0x00, 0x81, 0x00, 0x74, +0x00, 0x65, 0x00, 0x56, 0x00, 0x46, 0x00, 0x37, 0x00, 0x29, 0x00, 0x1c, +0x00, 0x10, 0x03, 0x0a, 0x07, 0x06, 0x0a, 0x01, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x5d, 0x00, 0x59, 0x00, 0x53, 0x00, +0x4c, 0x00, 0x42, 0x00, 0x39, 0x00, 0x2e, 0x00, 0x24, 0x00, 0x1a, 0x00, +0x11, 0x00, 0x08, 0x00, 0x00, 0x00, 0x07, 0x00, 0x0e, 0x00, 0x14, 0x00, +0x00, 0x9e, 0x00, 0x9c, 0x00, 0x97, 0x00, 0x8f, 0x00, 0x85, 0x00, 0x79, +0x00, 0x6b, 0x00, 0x5e, 0x00, 0x50, 0x00, 0x43, 0x00, 0x36, 0x00, 0x2a, +0x00, 0x1f, 0x00, 0x15, 0x00, 0x0c, 0x00, 0x03, 0x32, 0x59, 0x2a, 0x5b, +0x28, 0x5c, 0x27, 0x5d, 0x27, 0x5d, 0x26, 0x5e, 0x26, 0x5e, 0x26, 0x5e, +0x26, 0x5e, 0x26, 0x5e, 0x25, 0x5e, 0x25, 0x5e, 0x25, 0x5f, 0x25, 0x5f, +0x25, 0x5f, 0x25, 0x5f, 0x25, 0x5f, 0x24, 0x5f, 0x24, 0x5f, 0x24, 0x60, +0x32, 0x3c, 0x25, 0x4a, 0x24, 0x50, 0x23, 0x54, 0x23, 0x56, 0x23, 0x58, +0x23, 0x59, 0x23, 0x5a, 0x23, 0x5a, 0x23, 0x5b, 0x23, 0x5b, 0x23, 0x5b, +0x23, 0x5c, 0x23, 0x5c, 0x23, 0x5c, 0x23, 0x5c, 0x23, 0x5c, 0x23, 0x5d, +0x23, 0x5d, 0x23, 0x5d, 0x00, 0x6c, 0x0e, 0x60, 0x14, 0x60, 0x18, 0x60, +0x1b, 0x60, 0x1d, 0x60, 0x1d, 0x60, 0x1e, 0x60, 0x1f, 0x60, 0x20, 0x60, +0x20, 0x60, 0x20, 0x60, 0x21, 0x60, 0x21, 0x60, 0x21, 0x60, 0x21, 0x60, +0x22, 0x60, 0x22, 0x60, 0x22, 0x60, 0x22, 0x60, 0x23, 0x60, 0x23, 0x60, +0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, +0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, +0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x0d, 0x00, 0x00, 0x9e, 0x00, 0x9c, +0x00, 0x97, 0x00, 0x90, 0x00, 0x85, 0x00, 0x79, 0x00, 0x6c, 0x00, 0x5e, +0x00, 0x50, 0x00, 0x42, 0x00, 0x34, 0x00, 0x27, 0x00, 0x1b, 0x00, 0x0f, +0x03, 0x0b, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x5f, 0x00, 0x5d, 0x00, 0x5a, 0x00, 0x55, 0x00, 0x4e, 0x00, 0x46, 0x00, +0x3d, 0x00, 0x34, 0x00, 0x2a, 0x00, 0x21, 0x00, 0x18, 0x00, 0x0f, 0x00, +0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x0d, 0x00, 0x00, 0x9e, 0x00, 0x9d, +0x00, 0x98, 0x00, 0x91, 0x00, 0x88, 0x00, 0x7e, 0x00, 0x72, 0x00, 0x65, +0x00, 0x59, 0x00, 0x4c, 0x00, 0x40, 0x00, 0x34, 0x00, 0x2a, 0x00, 0x1f, +0x00, 0x16, 0x00, 0x0d, 0x38, 0x4f, 0x31, 0x53, 0x2e, 0x56, 0x2c, 0x57, +0x2a, 0x59, 0x29, 0x5a, 0x29, 0x5a, 0x28, 0x5b, 0x27, 0x5c, 0x27, 0x5c, +0x27, 0x5c, 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x5c, +0x27, 0x5c, 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x5c, 0x38, 0x22, 0x2b, 0x31, +0x27, 0x3b, 0x25, 0x42, 0x24, 0x47, 0x23, 0x4a, 0x23, 0x4d, 0x23, 0x4f, +0x23, 0x51, 0x23, 0x52, 0x23, 0x53, 0x23, 0x54, 0x23, 0x55, 0x23, 0x56, +0x23, 0x56, 0x23, 0x57, 0x23, 0x58, 0x23, 0x58, 0x23, 0x58, 0x23, 0x58, +0x00, 0x92, 0x01, 0x79, 0x07, 0x6f, 0x0c, 0x6b, 0x0f, 0x68, 0x12, 0x67, +0x14, 0x66, 0x16, 0x65, 0x17, 0x64, 0x18, 0x64, 0x19, 0x63, 0x1a, 0x63, +0x1b, 0x63, 0x1b, 0x63, 0x1c, 0x63, 0x1c, 0x62, 0x1d, 0x62, 0x1d, 0x62, +0x1d, 0x62, 0x1e, 0x62, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, +0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, +0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, +0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x06, 0x00, 0x00, 0x9e, 0x00, 0x9d, 0x00, 0x98, 0x00, 0x92, +0x00, 0x89, 0x00, 0x7e, 0x00, 0x72, 0x00, 0x65, 0x00, 0x58, 0x00, 0x4b, +0x00, 0x3e, 0x00, 0x31, 0x00, 0x25, 0x00, 0x1a, 0x00, 0x0f, 0x03, 0x0b, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x5e, 0x00, +0x5b, 0x00, 0x56, 0x00, 0x50, 0x00, 0x49, 0x00, 0x41, 0x00, 0x39, 0x00, +0x30, 0x00, 0x27, 0x00, 0x1e, 0x00, 0x16, 0x00, 0x0e, 0x00, 0x07, 0x00, +0x00, 0x00, 0x06, 0x00, 0x00, 0x9e, 0x00, 0x9d, 0x00, 0x99, 0x00, 0x93, +0x00, 0x8b, 0x00, 0x82, 0x00, 0x77, 0x00, 0x6c, 0x00, 0x60, 0x00, 0x54, +0x00, 0x49, 0x00, 0x3d, 0x00, 0x33, 0x00, 0x29, 0x00, 0x1f, 0x00, 0x17, +0x3a, 0x4b, 0x34, 0x4f, 0x31, 0x52, 0x2f, 0x54, 0x2d, 0x56, 0x2c, 0x57, +0x2b, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x59, 0x29, 0x5a, 0x29, 0x5a, +0x28, 0x5b, 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x5c, 0x27, 0x5c, +0x27, 0x5c, 0x27, 0x5c, 0x3c, 0x18, 0x30, 0x25, 0x2a, 0x2e, 0x27, 0x35, +0x25, 0x3b, 0x24, 0x3f, 0x24, 0x43, 0x24, 0x46, 0x23, 0x48, 0x23, 0x4a, +0x23, 0x4c, 0x23, 0x4e, 0x23, 0x4f, 0x23, 0x50, 0x23, 0x51, 0x23, 0x52, +0x23, 0x53, 0x23, 0x53, 0x23, 0x54, 0x23, 0x54, 0x00, 0xa1, 0x00, 0x88, +0x03, 0x7b, 0x06, 0x74, 0x09, 0x70, 0x0c, 0x6d, 0x0e, 0x6b, 0x10, 0x6a, +0x11, 0x69, 0x13, 0x68, 0x14, 0x67, 0x15, 0x66, 0x16, 0x66, 0x17, 0x65, +0x17, 0x65, 0x18, 0x65, 0x19, 0x65, 0x19, 0x64, 0x1a, 0x64, 0x1a, 0x64, +0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, +0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, +0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, +0x23, 0x60, 0x23, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x9e, 0x00, 0x9d, 0x00, 0x99, 0x00, 0x93, 0x00, 0x8b, 0x00, 0x82, +0x00, 0x77, 0x00, 0x6b, 0x00, 0x5f, 0x00, 0x53, 0x00, 0x46, 0x00, 0x3a, +0x00, 0x2f, 0x00, 0x24, 0x00, 0x19, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x5e, 0x00, 0x5b, 0x00, 0x57, 0x00, +0x52, 0x00, 0x4c, 0x00, 0x44, 0x00, 0x3d, 0x00, 0x35, 0x00, 0x2c, 0x00, +0x24, 0x00, 0x1c, 0x00, 0x14, 0x00, 0x0d, 0x00, 0x06, 0x00, 0x00, 0x00, +0x00, 0x9e, 0x00, 0x9d, 0x00, 0x9a, 0x00, 0x95, 0x00, 0x8d, 0x00, 0x85, +0x00, 0x7b, 0x00, 0x71, 0x00, 0x66, 0x00, 0x5b, 0x00, 0x50, 0x00, 0x46, +0x00, 0x3b, 0x00, 0x31, 0x00, 0x28, 0x00, 0x1f, 0x3b, 0x48, 0x36, 0x4c, +0x33, 0x4f, 0x31, 0x52, 0x2f, 0x53, 0x2e, 0x53, 0x2d, 0x55, 0x2c, 0x57, +0x2b, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x58, +0x2a, 0x59, 0x29, 0x5a, 0x29, 0x5b, 0x28, 0x5b, 0x27, 0x5c, 0x27, 0x5c, +0x3f, 0x14, 0x33, 0x1e, 0x2d, 0x26, 0x29, 0x2d, 0x27, 0x32, 0x26, 0x36, +0x25, 0x3b, 0x24, 0x3e, 0x24, 0x41, 0x24, 0x43, 0x23, 0x45, 0x23, 0x47, +0x23, 0x49, 0x23, 0x4a, 0x23, 0x4c, 0x23, 0x4d, 0x23, 0x4d, 0x23, 0x4f, +0x23, 0x50, 0x23, 0x50, 0x00, 0xa7, 0x00, 0x92, 0x01, 0x84, 0x03, 0x7d, +0x05, 0x77, 0x08, 0x73, 0x0a, 0x71, 0x0c, 0x6f, 0x0d, 0x6d, 0x0f, 0x6b, +0x10, 0x6a, 0x11, 0x6a, 0x12, 0x69, 0x13, 0x68, 0x14, 0x68, 0x15, 0x67, +0x15, 0x66, 0x16, 0x66, 0x17, 0x66, 0x17, 0x66, 0x23, 0x60, 0x23, 0x60, +0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, +0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, +0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x31, 0x23, 0x03, +0x46, 0x00, 0x52, 0x00, 0x58, 0x00, 0x5a, 0x00, 0x5c, 0x00, 0x5d, 0x00, +0x5d, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x5e, 0x00, 0x5e, 0x00, +0x5e, 0x00, 0x5f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x11, 0x31, 0x00, 0x5f, 0x00, 0x85, 0x00, 0x92, 0x00, 0x97, 0x00, 0x9a, +0x00, 0x9b, 0x00, 0x9c, 0x00, 0x9d, 0x00, 0x9d, 0x00, 0x9e, 0x00, 0x9e, +0x00, 0x9e, 0x00, 0x9e, 0x00, 0x9e, 0x00, 0x9e, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x3c, 0x47, 0x38, 0x4b, 0x35, 0x4e, 0x32, 0x4f, +0x31, 0x51, 0x30, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x55, 0x2c, 0x56, +0x2b, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57, +0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x58, 0x2a, 0x59, 0x40, 0x11, 0x36, 0x1a, +0x2f, 0x21, 0x2c, 0x27, 0x29, 0x2c, 0x27, 0x30, 0x26, 0x34, 0x25, 0x37, +0x25, 0x3a, 0x24, 0x3d, 0x24, 0x40, 0x24, 0x42, 0x24, 0x44, 0x23, 0x45, +0x23, 0x47, 0x23, 0x48, 0x23, 0x49, 0x23, 0x4a, 0x23, 0x4c, 0x23, 0x4c, +0x00, 0xaa, 0x00, 0x98, 0x00, 0x8c, 0x02, 0x83, 0x03, 0x7d, 0x05, 0x79, +0x07, 0x76, 0x09, 0x73, 0x0a, 0x71, 0x0c, 0x6f, 0x0d, 0x6e, 0x0e, 0x6d, +0x0f, 0x6c, 0x10, 0x6b, 0x11, 0x6a, 0x12, 0x6a, 0x13, 0x69, 0x13, 0x68, +0x14, 0x68, 0x15, 0x68, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, +0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, +0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, +0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x20, 0x1f, 0x00, 0x3c, 0x00, +0x4a, 0x00, 0x51, 0x00, 0x55, 0x00, 0x58, 0x00, 0x59, 0x00, 0x5b, 0x00, +0x5b, 0x00, 0x5c, 0x00, 0x5d, 0x00, 0x5d, 0x00, 0x5d, 0x00, 0x5d, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x03, 0x00, 0x20, +0x00, 0x5f, 0x00, 0x7c, 0x00, 0x8a, 0x00, 0x91, 0x00, 0x95, 0x00, 0x97, +0x00, 0x99, 0x00, 0x9a, 0x00, 0x9b, 0x00, 0x9c, 0x00, 0x9c, 0x00, 0x9d, +0x00, 0x9d, 0x00, 0x9d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x3d, 0x46, 0x39, 0x4a, 0x36, 0x4b, 0x34, 0x4e, 0x32, 0x4f, 0x31, 0x50, +0x30, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x54, 0x2d, 0x56, +0x2b, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57, +0x2a, 0x57, 0x2a, 0x57, 0x41, 0x10, 0x38, 0x17, 0x32, 0x1d, 0x2e, 0x22, +0x2b, 0x27, 0x29, 0x2b, 0x27, 0x2f, 0x26, 0x32, 0x25, 0x35, 0x25, 0x38, +0x25, 0x3b, 0x24, 0x3c, 0x24, 0x3f, 0x24, 0x40, 0x24, 0x42, 0x23, 0x44, +0x23, 0x45, 0x23, 0x46, 0x23, 0x48, 0x23, 0x48, 0x00, 0xac, 0x00, 0x9d, +0x00, 0x91, 0x01, 0x89, 0x02, 0x82, 0x03, 0x7e, 0x05, 0x7a, 0x07, 0x77, +0x08, 0x75, 0x09, 0x73, 0x0b, 0x71, 0x0c, 0x70, 0x0d, 0x6e, 0x0e, 0x6e, +0x0e, 0x6c, 0x0f, 0x6c, 0x10, 0x6b, 0x10, 0x6a, 0x11, 0x6a, 0x12, 0x6a, +0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, +0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, +0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, +0x23, 0x60, 0x23, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x85, 0x00, 0x5f, 0x00, 0x1f, 0x0d, 0x00, 0x28, 0x00, 0x39, 0x00, +0x43, 0x00, 0x4a, 0x00, 0x4e, 0x00, 0x52, 0x00, 0x54, 0x00, 0x56, 0x00, +0x57, 0x00, 0x59, 0x00, 0x59, 0x00, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x46, 0x00, 0x1f, 0x00, 0x00, 0x1f, 0x00, 0x4d, +0x00, 0x68, 0x00, 0x79, 0x00, 0x83, 0x00, 0x8a, 0x00, 0x8e, 0x00, 0x92, +0x00, 0x94, 0x00, 0x96, 0x00, 0x97, 0x00, 0x98, 0x00, 0x99, 0x00, 0x9a, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3d, 0x45, 0x39, 0x48, +0x37, 0x4a, 0x35, 0x4c, 0x33, 0x4f, 0x31, 0x4f, 0x31, 0x50, 0x30, 0x52, +0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x54, 0x2d, 0x56, +0x2c, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x2a, 0x57, +0x42, 0x0f, 0x39, 0x15, 0x33, 0x1a, 0x2f, 0x1f, 0x2d, 0x24, 0x2a, 0x27, +0x29, 0x2b, 0x27, 0x2e, 0x26, 0x31, 0x26, 0x34, 0x25, 0x36, 0x25, 0x38, +0x25, 0x3b, 0x24, 0x3c, 0x24, 0x3e, 0x24, 0x40, 0x24, 0x41, 0x24, 0x43, +0x23, 0x44, 0x23, 0x45, 0x00, 0xae, 0x00, 0xa1, 0x00, 0x96, 0x00, 0x8d, +0x01, 0x87, 0x02, 0x82, 0x03, 0x7e, 0x05, 0x7b, 0x06, 0x78, 0x07, 0x76, +0x09, 0x74, 0x0a, 0x73, 0x0b, 0x71, 0x0c, 0x70, 0x0c, 0x6f, 0x0d, 0x6e, +0x0e, 0x6d, 0x0f, 0x6c, 0x10, 0x6c, 0x10, 0x6b, 0x23, 0x60, 0x23, 0x60, +0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, +0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, +0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x92, 0x00, 0x7c, +0x00, 0x4d, 0x00, 0x1f, 0x02, 0x00, 0x1a, 0x00, 0x2a, 0x00, 0x36, 0x00, +0x3e, 0x00, 0x45, 0x00, 0x49, 0x00, 0x4d, 0x00, 0x4f, 0x00, 0x52, 0x00, +0x53, 0x00, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x52, 0x00, 0x3c, 0x00, 0x0d, 0x00, 0x00, 0x1f, 0x00, 0x42, 0x00, 0x5a, +0x00, 0x6a, 0x00, 0x76, 0x00, 0x7e, 0x00, 0x84, 0x00, 0x89, 0x00, 0x8c, +0x00, 0x8f, 0x00, 0x91, 0x00, 0x93, 0x00, 0x95, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x3d, 0x45, 0x3a, 0x47, 0x38, 0x4a, 0x35, 0x4a, +0x35, 0x4d, 0x33, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x52, 0x2f, 0x53, +0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2d, 0x55, +0x2c, 0x57, 0x2b, 0x57, 0x2a, 0x57, 0x2a, 0x57, 0x43, 0x0e, 0x3b, 0x13, +0x35, 0x18, 0x31, 0x1c, 0x2e, 0x21, 0x2c, 0x24, 0x2a, 0x28, 0x28, 0x2b, +0x27, 0x2e, 0x27, 0x30, 0x26, 0x33, 0x25, 0x35, 0x25, 0x37, 0x25, 0x39, +0x25, 0x3b, 0x24, 0x3c, 0x24, 0x3d, 0x24, 0x3f, 0x24, 0x40, 0x24, 0x42, +0x00, 0xaf, 0x00, 0xa3, 0x00, 0x99, 0x00, 0x91, 0x00, 0x8b, 0x02, 0x86, +0x02, 0x81, 0x03, 0x7e, 0x05, 0x7b, 0x06, 0x79, 0x07, 0x77, 0x08, 0x75, +0x09, 0x74, 0x0a, 0x73, 0x0b, 0x71, 0x0c, 0x71, 0x0c, 0x6f, 0x0d, 0x6e, +0x0e, 0x6e, 0x0e, 0x6d, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, +0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, +0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, +0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x97, 0x00, 0x8a, 0x00, 0x68, 0x00, 0x42, +0x00, 0x1f, 0x00, 0x04, 0x10, 0x00, 0x1f, 0x00, 0x2b, 0x00, 0x34, 0x00, +0x3b, 0x00, 0x41, 0x00, 0x45, 0x00, 0x49, 0x00, 0x4b, 0x00, 0x4e, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0x00, 0x4a, 0x00, +0x28, 0x00, 0x02, 0x00, 0x00, 0x1f, 0x00, 0x3b, 0x00, 0x4f, 0x00, 0x5f, +0x00, 0x6b, 0x00, 0x74, 0x00, 0x7b, 0x00, 0x80, 0x00, 0x85, 0x00, 0x88, +0x00, 0x8b, 0x00, 0x8d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x3d, 0x44, 0x3b, 0x46, 0x39, 0x49, 0x36, 0x4a, 0x35, 0x4b, 0x34, 0x4e, +0x32, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x51, 0x2f, 0x53, 0x2e, 0x53, +0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x55, +0x2c, 0x56, 0x2b, 0x57, 0x44, 0x0e, 0x3c, 0x12, 0x36, 0x16, 0x33, 0x1a, +0x30, 0x1e, 0x2d, 0x22, 0x2b, 0x25, 0x2a, 0x28, 0x28, 0x2a, 0x27, 0x2d, +0x27, 0x30, 0x26, 0x32, 0x26, 0x34, 0x25, 0x35, 0x25, 0x37, 0x25, 0x39, +0x24, 0x3b, 0x24, 0x3c, 0x24, 0x3d, 0x24, 0x3f, 0x00, 0xb0, 0x00, 0xa5, +0x00, 0x9d, 0x00, 0x95, 0x00, 0x8e, 0x01, 0x89, 0x02, 0x85, 0x03, 0x81, +0x04, 0x7e, 0x05, 0x7c, 0x06, 0x7a, 0x07, 0x78, 0x07, 0x76, 0x09, 0x75, +0x09, 0x73, 0x0b, 0x73, 0x0b, 0x71, 0x0c, 0x71, 0x0c, 0x70, 0x0d, 0x6e, +0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, +0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, +0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, +0x23, 0x60, 0x23, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x9a, 0x00, 0x91, 0x00, 0x79, 0x00, 0x5a, 0x00, 0x3b, 0x00, 0x1f, +0x00, 0x09, 0x08, 0x00, 0x17, 0x00, 0x22, 0x00, 0x2c, 0x00, 0x33, 0x00, +0x39, 0x00, 0x3e, 0x00, 0x42, 0x00, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x5a, 0x00, 0x51, 0x00, 0x39, 0x00, 0x1a, 0x00, +0x00, 0x04, 0x00, 0x1f, 0x00, 0x36, 0x00, 0x48, 0x00, 0x57, 0x00, 0x62, +0x00, 0x6b, 0x00, 0x73, 0x00, 0x79, 0x00, 0x7e, 0x00, 0x82, 0x00, 0x85, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3d, 0x44, 0x3b, 0x46, +0x39, 0x48, 0x37, 0x4a, 0x35, 0x4a, 0x35, 0x4c, 0x34, 0x4f, 0x31, 0x4f, +0x31, 0x4f, 0x31, 0x4f, 0x31, 0x50, 0x30, 0x53, 0x2e, 0x53, 0x2e, 0x53, +0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x55, +0x44, 0x0d, 0x3d, 0x11, 0x38, 0x15, 0x34, 0x19, 0x31, 0x1c, 0x2e, 0x20, +0x2d, 0x23, 0x2b, 0x25, 0x2a, 0x28, 0x28, 0x2a, 0x28, 0x2d, 0x27, 0x2f, +0x26, 0x31, 0x26, 0x33, 0x25, 0x34, 0x25, 0x36, 0x25, 0x38, 0x25, 0x39, +0x24, 0x3a, 0x24, 0x3c, 0x00, 0xb1, 0x00, 0xa8, 0x00, 0x9f, 0x00, 0x98, +0x00, 0x91, 0x00, 0x8c, 0x01, 0x88, 0x02, 0x84, 0x03, 0x81, 0x04, 0x7e, +0x05, 0x7c, 0x06, 0x7a, 0x06, 0x79, 0x07, 0x77, 0x08, 0x76, 0x09, 0x74, +0x0a, 0x73, 0x0b, 0x73, 0x0b, 0x71, 0x0c, 0x71, 0x23, 0x60, 0x23, 0x60, +0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, +0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, +0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9b, 0x00, 0x95, +0x00, 0x83, 0x00, 0x6a, 0x00, 0x4f, 0x00, 0x36, 0x00, 0x1f, 0x00, 0x0c, +0x03, 0x00, 0x10, 0x00, 0x1b, 0x00, 0x24, 0x00, 0x2c, 0x00, 0x32, 0x00, +0x37, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x5c, 0x00, 0x55, 0x00, 0x43, 0x00, 0x2a, 0x00, 0x10, 0x00, 0x00, 0x09, +0x00, 0x1f, 0x00, 0x33, 0x00, 0x43, 0x00, 0x50, 0x00, 0x5b, 0x00, 0x64, +0x00, 0x6b, 0x00, 0x72, 0x00, 0x77, 0x00, 0x7b, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x3d, 0x43, 0x3c, 0x46, 0x39, 0x46, 0x39, 0x4a, +0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4d, 0x33, 0x4f, 0x31, 0x4f, 0x31, 0x4f, +0x31, 0x4f, 0x31, 0x50, 0x30, 0x52, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, +0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x44, 0x0d, 0x3e, 0x10, +0x39, 0x14, 0x35, 0x17, 0x32, 0x1b, 0x30, 0x1e, 0x2e, 0x21, 0x2c, 0x23, +0x2b, 0x26, 0x2a, 0x28, 0x28, 0x2a, 0x28, 0x2d, 0x27, 0x2e, 0x26, 0x30, +0x26, 0x32, 0x25, 0x34, 0x25, 0x35, 0x25, 0x36, 0x25, 0x38, 0x25, 0x39, +0x00, 0xb1, 0x00, 0xa9, 0x00, 0xa1, 0x00, 0x9a, 0x00, 0x94, 0x00, 0x8f, +0x01, 0x8b, 0x02, 0x87, 0x02, 0x84, 0x03, 0x81, 0x04, 0x7f, 0x05, 0x7d, +0x06, 0x7b, 0x06, 0x79, 0x07, 0x78, 0x07, 0x76, 0x09, 0x76, 0x09, 0x74, +0x0a, 0x73, 0x0b, 0x72, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, +0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, +0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, +0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x9c, 0x00, 0x97, 0x00, 0x8a, 0x00, 0x76, +0x00, 0x5f, 0x00, 0x48, 0x00, 0x33, 0x00, 0x1f, 0x00, 0x0f, 0x00, 0x00, +0x0b, 0x00, 0x15, 0x00, 0x1e, 0x00, 0x25, 0x00, 0x2c, 0x00, 0x31, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5d, 0x00, 0x58, 0x00, +0x4a, 0x00, 0x36, 0x00, 0x1f, 0x00, 0x08, 0x00, 0x00, 0x0c, 0x00, 0x1f, +0x00, 0x30, 0x00, 0x3f, 0x00, 0x4b, 0x00, 0x55, 0x00, 0x5e, 0x00, 0x65, +0x00, 0x6c, 0x00, 0x71, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x3d, 0x42, 0x3c, 0x46, 0x39, 0x46, 0x39, 0x48, 0x37, 0x4a, 0x35, 0x4a, +0x35, 0x4b, 0x35, 0x4e, 0x32, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, +0x31, 0x4f, 0x31, 0x52, 0x2f, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, +0x2e, 0x53, 0x2e, 0x53, 0x44, 0x0c, 0x3f, 0x10, 0x3a, 0x13, 0x36, 0x16, +0x33, 0x19, 0x30, 0x1c, 0x2e, 0x1f, 0x2d, 0x21, 0x2b, 0x24, 0x2a, 0x26, +0x2a, 0x28, 0x28, 0x2a, 0x28, 0x2c, 0x27, 0x2e, 0x26, 0x30, 0x26, 0x31, +0x26, 0x33, 0x25, 0x34, 0x25, 0x36, 0x25, 0x37, 0x00, 0xb2, 0x00, 0xaa, +0x00, 0xa2, 0x00, 0x9c, 0x00, 0x96, 0x00, 0x91, 0x00, 0x8d, 0x01, 0x89, +0x02, 0x86, 0x02, 0x83, 0x03, 0x81, 0x04, 0x7f, 0x05, 0x7d, 0x06, 0x7b, +0x06, 0x79, 0x07, 0x79, 0x07, 0x77, 0x08, 0x76, 0x09, 0x75, 0x09, 0x74, +0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, +0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, +0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, +0x23, 0x60, 0x23, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x9d, 0x00, 0x99, 0x00, 0x8e, 0x00, 0x7e, 0x00, 0x6b, 0x00, 0x57, +0x00, 0x43, 0x00, 0x30, 0x00, 0x1f, 0x00, 0x11, 0x00, 0x04, 0x07, 0x00, +0x10, 0x00, 0x19, 0x00, 0x20, 0x00, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x5d, 0x00, 0x59, 0x00, 0x4e, 0x00, 0x3e, 0x00, +0x2b, 0x00, 0x17, 0x00, 0x03, 0x00, 0x00, 0x0f, 0x00, 0x1f, 0x00, 0x2e, +0x00, 0x3b, 0x00, 0x46, 0x00, 0x50, 0x00, 0x59, 0x00, 0x60, 0x00, 0x66, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3d, 0x42, 0x3d, 0x46, +0x39, 0x46, 0x39, 0x47, 0x38, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4b, +0x34, 0x4e, 0x32, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, +0x31, 0x51, 0x2f, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, +0x45, 0x0c, 0x3f, 0x0f, 0x3a, 0x12, 0x37, 0x15, 0x34, 0x18, 0x32, 0x1b, +0x30, 0x1d, 0x2e, 0x20, 0x2d, 0x22, 0x2b, 0x24, 0x2a, 0x26, 0x2a, 0x28, +0x28, 0x2a, 0x28, 0x2c, 0x27, 0x2e, 0x27, 0x2f, 0x26, 0x31, 0x26, 0x32, +0x25, 0x33, 0x25, 0x35, 0x00, 0xb2, 0x00, 0xab, 0x00, 0xa4, 0x00, 0x9e, +0x00, 0x98, 0x00, 0x93, 0x00, 0x8f, 0x01, 0x8b, 0x01, 0x88, 0x02, 0x85, +0x02, 0x83, 0x03, 0x81, 0x04, 0x7f, 0x05, 0x7d, 0x05, 0x7c, 0x06, 0x7a, +0x07, 0x79, 0x07, 0x78, 0x07, 0x76, 0x09, 0x76, 0x23, 0x60, 0x23, 0x60, +0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, +0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, +0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9d, 0x00, 0x9a, +0x00, 0x92, 0x00, 0x84, 0x00, 0x74, 0x00, 0x62, 0x00, 0x50, 0x00, 0x3f, +0x00, 0x2e, 0x00, 0x1f, 0x00, 0x12, 0x00, 0x06, 0x03, 0x00, 0x0c, 0x00, +0x14, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x5e, 0x00, 0x5b, 0x00, 0x52, 0x00, 0x45, 0x00, 0x34, 0x00, 0x22, 0x00, +0x10, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x1f, 0x00, 0x2d, 0x00, 0x38, +0x00, 0x43, 0x00, 0x4c, 0x00, 0x54, 0x00, 0x5b, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x3d, 0x42, 0x3d, 0x45, 0x3a, 0x46, 0x39, 0x46, +0x39, 0x49, 0x36, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4c, 0x33, 0x4f, +0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x51, +0x30, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x2e, 0x53, 0x45, 0x0c, 0x40, 0x0f, +0x3b, 0x11, 0x38, 0x14, 0x35, 0x17, 0x32, 0x1a, 0x30, 0x1c, 0x2e, 0x1e, +0x2d, 0x21, 0x2c, 0x22, 0x2b, 0x25, 0x2a, 0x26, 0x29, 0x28, 0x28, 0x2a, +0x28, 0x2c, 0x27, 0x2d, 0x27, 0x2f, 0x26, 0x30, 0x26, 0x32, 0x25, 0x33, +0x00, 0xb2, 0x00, 0xac, 0x00, 0xa5, 0x00, 0x9f, 0x00, 0x9a, 0x00, 0x96, +0x00, 0x91, 0x00, 0x8e, 0x01, 0x8a, 0x02, 0x88, 0x02, 0x85, 0x02, 0x83, +0x03, 0x81, 0x04, 0x7f, 0x05, 0x7d, 0x05, 0x7c, 0x06, 0x7a, 0x06, 0x79, +0x07, 0x78, 0x07, 0x77, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, +0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, +0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, +0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x9b, 0x00, 0x94, 0x00, 0x89, +0x00, 0x7b, 0x00, 0x6b, 0x00, 0x5b, 0x00, 0x4b, 0x00, 0x3b, 0x00, 0x2d, +0x00, 0x1f, 0x00, 0x13, 0x00, 0x08, 0x00, 0x00, 0x09, 0x00, 0x11, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x5b, 0x00, +0x54, 0x00, 0x49, 0x00, 0x3b, 0x00, 0x2c, 0x00, 0x1b, 0x00, 0x0b, 0x00, +0x00, 0x04, 0x00, 0x12, 0x00, 0x1f, 0x00, 0x2b, 0x00, 0x36, 0x00, 0x40, +0x00, 0x49, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x3d, 0x42, 0x3d, 0x44, 0x3a, 0x46, 0x39, 0x46, 0x39, 0x48, 0x37, 0x4a, +0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4d, 0x33, 0x4f, 0x31, 0x4f, +0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x50, 0x30, 0x53, +0x2e, 0x53, 0x2e, 0x53, 0x45, 0x0c, 0x40, 0x0e, 0x3c, 0x11, 0x38, 0x13, +0x36, 0x16, 0x33, 0x18, 0x31, 0x1b, 0x30, 0x1d, 0x2e, 0x1f, 0x2d, 0x21, +0x2b, 0x23, 0x2b, 0x25, 0x2a, 0x27, 0x29, 0x28, 0x28, 0x2a, 0x28, 0x2c, +0x27, 0x2d, 0x27, 0x2f, 0x26, 0x2f, 0x26, 0x31, 0x00, 0xb3, 0x00, 0xac, +0x00, 0xa7, 0x00, 0xa1, 0x00, 0x9b, 0x00, 0x97, 0x00, 0x93, 0x00, 0x8f, +0x01, 0x8c, 0x01, 0x89, 0x02, 0x87, 0x02, 0x85, 0x02, 0x82, 0x03, 0x81, +0x04, 0x7f, 0x05, 0x7d, 0x05, 0x7c, 0x06, 0x7b, 0x06, 0x79, 0x07, 0x79, +0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, +0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, +0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, +0x23, 0x60, 0x23, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x9e, 0x00, 0x9c, 0x00, 0x96, 0x00, 0x8c, 0x00, 0x80, 0x00, 0x73, +0x00, 0x64, 0x00, 0x55, 0x00, 0x46, 0x00, 0x38, 0x00, 0x2b, 0x00, 0x1f, +0x00, 0x14, 0x00, 0x0a, 0x00, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x5c, 0x00, 0x56, 0x00, 0x4d, 0x00, +0x41, 0x00, 0x33, 0x00, 0x24, 0x00, 0x15, 0x00, 0x07, 0x00, 0x00, 0x06, +0x00, 0x13, 0x00, 0x1f, 0x00, 0x2a, 0x00, 0x34, 0x00, 0x3d, 0x00, 0x46, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3d, 0x42, 0x3d, 0x44, +0x3b, 0x46, 0x39, 0x46, 0x39, 0x47, 0x38, 0x4a, 0x35, 0x4a, 0x35, 0x4a, +0x35, 0x4a, 0x35, 0x4b, 0x34, 0x4e, 0x32, 0x4f, 0x31, 0x4f, 0x31, 0x4f, +0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x50, 0x30, 0x52, 0x2f, 0x53, +0x45, 0x0c, 0x40, 0x0e, 0x3c, 0x11, 0x39, 0x13, 0x37, 0x15, 0x34, 0x18, +0x32, 0x1a, 0x30, 0x1c, 0x2e, 0x1e, 0x2d, 0x20, 0x2d, 0x22, 0x2b, 0x23, +0x2b, 0x25, 0x2a, 0x27, 0x29, 0x28, 0x28, 0x2a, 0x28, 0x2c, 0x27, 0x2d, +0x27, 0x2f, 0x26, 0x2f, 0x00, 0xb3, 0x00, 0xad, 0x00, 0xa7, 0x00, 0xa3, +0x00, 0x9d, 0x00, 0x99, 0x00, 0x95, 0x00, 0x91, 0x00, 0x8e, 0x01, 0x8b, +0x02, 0x88, 0x02, 0x86, 0x02, 0x84, 0x03, 0x82, 0x03, 0x81, 0x04, 0x7f, +0x05, 0x7e, 0x05, 0x7c, 0x06, 0x7b, 0x06, 0x7a, 0x23, 0x60, 0x23, 0x60, +0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, +0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, +0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x9c, +0x00, 0x97, 0x00, 0x8f, 0x00, 0x85, 0x00, 0x79, 0x00, 0x6b, 0x00, 0x5e, +0x00, 0x50, 0x00, 0x43, 0x00, 0x36, 0x00, 0x2a, 0x00, 0x1f, 0x00, 0x15, +0x00, 0x0c, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x5e, 0x00, 0x5d, 0x00, 0x57, 0x00, 0x4f, 0x00, 0x45, 0x00, 0x39, 0x00, +0x2c, 0x00, 0x1e, 0x00, 0x10, 0x00, 0x03, 0x00, 0x00, 0x08, 0x00, 0x14, +0x00, 0x1f, 0x00, 0x2a, 0x00, 0x33, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x3d, 0x42, 0x3d, 0x43, 0x3c, 0x46, 0x39, 0x46, +0x39, 0x46, 0x39, 0x49, 0x36, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, +0x35, 0x4c, 0x33, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, +0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x52, 0x45, 0x0b, 0x41, 0x0e, +0x3d, 0x10, 0x3a, 0x12, 0x37, 0x14, 0x34, 0x17, 0x32, 0x19, 0x31, 0x1b, +0x30, 0x1d, 0x2e, 0x1f, 0x2d, 0x20, 0x2c, 0x22, 0x2b, 0x24, 0x2a, 0x25, +0x2a, 0x27, 0x29, 0x28, 0x28, 0x2a, 0x28, 0x2c, 0x27, 0x2c, 0x27, 0x2e, +0x00, 0xb3, 0x00, 0xae, 0x00, 0xa8, 0x00, 0xa3, 0x00, 0x9f, 0x00, 0x9a, +0x00, 0x96, 0x00, 0x93, 0x00, 0x8f, 0x01, 0x8d, 0x01, 0x8a, 0x02, 0x88, +0x02, 0x86, 0x02, 0x84, 0x03, 0x82, 0x03, 0x81, 0x04, 0x7f, 0x05, 0x7e, +0x05, 0x7c, 0x06, 0x7c, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, +0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, +0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, +0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x9d, 0x00, 0x98, 0x00, 0x91, +0x00, 0x88, 0x00, 0x7e, 0x00, 0x72, 0x00, 0x65, 0x00, 0x59, 0x00, 0x4c, +0x00, 0x40, 0x00, 0x34, 0x00, 0x2a, 0x00, 0x1f, 0x00, 0x16, 0x00, 0x0d, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x5d, 0x00, +0x59, 0x00, 0x52, 0x00, 0x49, 0x00, 0x3e, 0x00, 0x32, 0x00, 0x25, 0x00, +0x19, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x15, 0x00, 0x1f, +0x00, 0x29, 0x00, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x3d, 0x42, 0x3d, 0x43, 0x3c, 0x46, 0x39, 0x46, 0x39, 0x46, 0x39, 0x47, +0x38, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4d, +0x33, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, +0x31, 0x4f, 0x31, 0x4f, 0x45, 0x0b, 0x41, 0x0e, 0x3e, 0x10, 0x3a, 0x11, +0x38, 0x14, 0x35, 0x16, 0x33, 0x18, 0x32, 0x1a, 0x30, 0x1c, 0x2e, 0x1d, +0x2e, 0x20, 0x2d, 0x21, 0x2b, 0x22, 0x2b, 0x24, 0x2a, 0x25, 0x2a, 0x27, +0x28, 0x28, 0x28, 0x2a, 0x28, 0x2c, 0x27, 0x2c, 0x00, 0xb3, 0x00, 0xae, +0x00, 0xa9, 0x00, 0xa4, 0x00, 0xa0, 0x00, 0x9b, 0x00, 0x98, 0x00, 0x94, +0x00, 0x91, 0x00, 0x8e, 0x01, 0x8c, 0x01, 0x89, 0x02, 0x87, 0x02, 0x86, +0x02, 0x84, 0x03, 0x82, 0x03, 0x80, 0x04, 0x7f, 0x05, 0x7e, 0x05, 0x7c, +0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, +0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, +0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, +0x23, 0x60, 0x23, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x9e, 0x00, 0x9d, 0x00, 0x99, 0x00, 0x93, 0x00, 0x8b, 0x00, 0x82, +0x00, 0x77, 0x00, 0x6c, 0x00, 0x60, 0x00, 0x54, 0x00, 0x49, 0x00, 0x3d, +0x00, 0x33, 0x00, 0x29, 0x00, 0x1f, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x5d, 0x00, 0x59, 0x00, 0x53, 0x00, +0x4b, 0x00, 0x42, 0x00, 0x37, 0x00, 0x2c, 0x00, 0x20, 0x00, 0x14, 0x00, +0x09, 0x00, 0x00, 0x01, 0x00, 0x0c, 0x00, 0x16, 0x00, 0x1f, 0x00, 0x28, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3d, 0x42, 0x3d, 0x42, +0x3d, 0x46, 0x39, 0x46, 0x39, 0x46, 0x39, 0x46, 0x39, 0x4a, 0x36, 0x4a, +0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4b, 0x34, 0x4e, 0x32, 0x4f, +0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, +0x46, 0x0b, 0x42, 0x0d, 0x3e, 0x10, 0x3b, 0x11, 0x38, 0x13, 0x36, 0x16, +0x34, 0x17, 0x32, 0x19, 0x30, 0x1b, 0x30, 0x1d, 0x2e, 0x1e, 0x2d, 0x20, +0x2d, 0x22, 0x2b, 0x23, 0x2b, 0x25, 0x2a, 0x25, 0x2a, 0x28, 0x28, 0x28, +0x28, 0x2a, 0x28, 0x2c, 0x00, 0xb3, 0x00, 0xae, 0x00, 0xaa, 0x00, 0xa5, +0x00, 0xa1, 0x00, 0x9d, 0x00, 0x99, 0x00, 0x96, 0x00, 0x93, 0x00, 0x90, +0x00, 0x8d, 0x01, 0x8b, 0x02, 0x89, 0x02, 0x87, 0x02, 0x85, 0x02, 0x83, +0x03, 0x82, 0x03, 0x80, 0x04, 0x7f, 0x05, 0x7e, 0x23, 0x60, 0x23, 0x60, +0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, +0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, +0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x9d, +0x00, 0x9a, 0x00, 0x95, 0x00, 0x8d, 0x00, 0x85, 0x00, 0x7b, 0x00, 0x71, +0x00, 0x66, 0x00, 0x5b, 0x00, 0x50, 0x00, 0x46, 0x00, 0x3b, 0x00, 0x31, +0x00, 0x28, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x5f, 0x00, 0x5d, 0x00, 0x5a, 0x00, 0x55, 0x00, 0x4e, 0x00, 0x45, 0x00, +0x3c, 0x00, 0x31, 0x00, 0x26, 0x00, 0x1b, 0x00, 0x11, 0x00, 0x06, 0x00, +0x00, 0x03, 0x00, 0x0d, 0x00, 0x17, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x3d, 0x42, 0x3d, 0x42, 0x3d, 0x45, 0x3a, 0x46, +0x39, 0x46, 0x39, 0x46, 0x39, 0x48, 0x37, 0x4a, 0x35, 0x4a, 0x35, 0x4a, +0x35, 0x4a, 0x35, 0x4a, 0x35, 0x4c, 0x34, 0x4f, 0x31, 0x4f, 0x31, 0x4f, +0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x31, 0x4f, 0x46, 0x0b, 0x42, 0x0d, +0x3e, 0x0f, 0x3c, 0x11, 0x39, 0x13, 0x37, 0x15, 0x34, 0x16, 0x33, 0x18, +0x32, 0x1a, 0x30, 0x1c, 0x2e, 0x1d, 0x2e, 0x20, 0x2d, 0x20, 0x2c, 0x22, +0x2b, 0x23, 0x2b, 0x25, 0x2a, 0x26, 0x2a, 0x28, 0x28, 0x28, 0x28, 0x2a, +0x00, 0xb4, 0x00, 0xaf, 0x00, 0xaa, 0x00, 0xa6, 0x00, 0xa2, 0x00, 0x9e, +0x00, 0x9a, 0x00, 0x97, 0x00, 0x94, 0x00, 0x91, 0x00, 0x8e, 0x01, 0x8c, +0x01, 0x8a, 0x02, 0x88, 0x02, 0x86, 0x02, 0x85, 0x02, 0x83, 0x03, 0x82, +0x03, 0x80, 0x04, 0x7f, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, +0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, +0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, +0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x23, 0x60, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x0f, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x6f, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x00, 0x0f, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0xb2, 0x00, 0x6f, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x17, 0x00, 0x0b, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x00, 0xa2, 0x00, +0x4f, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x1e, 0x00, 0x1a, 0x00, 0x12, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0xd2, 0x00, 0xb9, 0x00, 0x7f, 0x00, 0x3c, 0x00, +0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x1c, +0x00, 0x16, 0x00, 0x0e, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0xd6, 0x00, 0xc6, 0x00, 0x9c, 0x00, 0x66, 0x00, 0x2f, 0x00, 0x01, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1d, 0x00, 0x18, 0x00, 0x12, +0x00, 0x0c, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd9, 0x00, 0xcd, 0x00, +0xae, 0x00, 0x82, 0x00, 0x54, 0x00, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x1f, 0x00, 0x1e, 0x00, 0x1a, 0x00, 0x15, 0x00, 0x0f, 0x00, 0x0a, +0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0xda, 0x00, 0xd2, 0x00, 0xb9, 0x00, 0x97, 0x00, +0x6f, 0x00, 0x47, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1e, +0x00, 0x1b, 0x00, 0x17, 0x00, 0x12, 0x00, 0x0d, 0x00, 0x08, 0x00, 0x04, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0xdb, 0x00, 0xd4, 0x00, 0xc2, 0x00, 0xa5, 0x00, 0x84, 0x00, 0x60, 0x00, +0x3d, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1e, 0x00, 0x1c, 0x00, 0x19, +0x00, 0x15, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x07, 0x00, 0x03, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x00, 0xd7, 0x00, +0xc7, 0x00, 0xb0, 0x00, 0x93, 0x00, 0x74, 0x00, 0x55, 0x00, 0x36, 0x00, +0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x1f, 0x00, 0x1e, 0x00, 0x1d, 0x00, 0x1a, 0x00, 0x16, 0x00, 0x12, +0x00, 0x0e, 0x00, 0x0a, 0x00, 0x06, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0xdc, 0x00, 0xd8, 0x00, 0xcc, 0x00, 0xb8, 0x00, +0xa0, 0x00, 0x84, 0x00, 0x68, 0x00, 0x4b, 0x00, 0x30, 0x00, 0x17, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1f, +0x00, 0x1d, 0x00, 0x1b, 0x00, 0x18, 0x00, 0x14, 0x00, 0x11, 0x00, 0x0d, +0x00, 0x09, 0x00, 0x06, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0xdd, 0x00, 0xd9, 0x00, 0xcf, 0x00, 0xbe, 0x00, 0xa9, 0x00, 0x91, 0x00, +0x78, 0x00, 0x5d, 0x00, 0x44, 0x00, 0x2b, 0x00, 0x15, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1d, 0x00, 0x1b, +0x00, 0x19, 0x00, 0x16, 0x00, 0x13, 0x00, 0x0f, 0x00, 0x0c, 0x00, 0x08, +0x00, 0x05, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdd, 0x00, 0xda, 0x00, +0xd1, 0x00, 0xc3, 0x00, 0xb1, 0x00, 0x9c, 0x00, 0x85, 0x00, 0x6d, 0x00, +0x55, 0x00, 0x3e, 0x00, 0x28, 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1e, 0x00, 0x1c, 0x00, 0x1a, 0x00, 0x17, +0x00, 0x14, 0x00, 0x11, 0x00, 0x0e, 0x00, 0x0b, 0x00, 0x08, 0x00, 0x05, +0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0xdd, 0x00, 0xdb, 0x00, 0xd3, 0x00, 0xc7, 0x00, +0xb7, 0x00, 0xa4, 0x00, 0x90, 0x00, 0x7a, 0x00, 0x64, 0x00, 0x4e, 0x00, +0x39, 0x00, 0x24, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1f, +0x00, 0x1e, 0x00, 0x1c, 0x00, 0x1a, 0x00, 0x18, 0x00, 0x15, 0x00, 0x13, +0x00, 0x10, 0x00, 0x0d, 0x00, 0x0a, 0x00, 0x07, 0x00, 0x04, 0x00, 0x02, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0xdd, 0x00, 0xdb, 0x00, 0xd5, 0x00, 0xca, 0x00, 0xbc, 0x00, 0xab, 0x00, +0x99, 0x00, 0x85, 0x00, 0x70, 0x00, 0x5c, 0x00, 0x48, 0x00, 0x34, 0x00, +0x22, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1e, 0x00, 0x1d, +0x00, 0x1b, 0x00, 0x19, 0x00, 0x16, 0x00, 0x14, 0x00, 0x11, 0x00, 0x0e, +0x00, 0x0c, 0x00, 0x09, 0x00, 0x06, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xde, 0x00, 0xdc, 0x00, +0xd6, 0x00, 0xcd, 0x00, 0xc0, 0x00, 0xb1, 0x00, 0xa0, 0x00, 0x8e, 0x00, +0x7b, 0x00, 0x68, 0x00, 0x55, 0x00, 0x42, 0x00, 0x30, 0x00, 0x1f, 0x00, +0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x0f, 0x00, 0x19, 0x00, 0x1c, +0x00, 0x1e, 0x00, 0x1e, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, +0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, +0x00, 0x3e, 0x00, 0x2b, 0x00, 0x34, 0x00, 0x32, 0x00, 0x2c, 0x00, 0x24, +0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, +0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x4c, 0x04, 0x11, 0x09, 0x01, 0x11, 0x00, 0x17, +0x00, 0x1b, 0x00, 0x1c, 0x00, 0x1d, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x1e, +0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, +0x61, 0x01, 0x23, 0x03, 0x03, 0x09, 0x00, 0x13, 0x00, 0x18, 0x00, 0x1a, +0x00, 0x1c, 0x00, 0x1d, 0x00, 0x1d, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x1e, +0x00, 0x1e, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x02, 0x00, 0x0f, 0x00, 0x17, 0x00, 0x1a, 0x00, 0x1c, +0x00, 0x1d, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x1f, +0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x2b, 0x00, 0x21, +0x00, 0x27, 0x00, 0x2b, 0x00, 0x28, 0x00, 0x21, 0x00, 0x1d, 0x00, 0x1e, +0x00, 0x1e, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, +0x00, 0x1f, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x87, 0x00, 0x39, 0x01, 0x0f, 0x07, 0x02, 0x0c, 0x00, 0x12, 0x00, 0x17, +0x00, 0x19, 0x00, 0x1b, 0x00, 0x1c, 0x00, 0x1c, 0x00, 0x1d, 0x00, 0x1d, +0x00, 0x1e, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x1e, 0x9f, 0x00, 0x5f, 0x00, +0x1f, 0x00, 0x04, 0x01, 0x00, 0x0a, 0x00, 0x11, 0x00, 0x15, 0x00, 0x18, +0x00, 0x1a, 0x00, 0x1b, 0x00, 0x1c, 0x00, 0x1c, 0x00, 0x1d, 0x00, 0x1d, +0x00, 0x1d, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x0b, 0x00, 0x12, 0x00, 0x16, 0x00, 0x18, 0x00, 0x1a, +0x00, 0x1b, 0x00, 0x1c, 0x00, 0x1d, 0x00, 0x1d, 0x00, 0x1d, 0x00, 0x1e, +0x00, 0x1e, 0x00, 0x1e, 0x00, 0x34, 0x00, 0x27, 0x00, 0x0f, 0x00, 0x1a, +0x00, 0x1c, 0x00, 0x18, 0x00, 0x18, 0x00, 0x1a, 0x00, 0x1b, 0x00, 0x1c, +0x00, 0x1d, 0x00, 0x1d, 0x00, 0x1d, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x1e, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbc, 0x00, 0x87, 0x00, +0x32, 0x00, 0x19, 0x05, 0x0b, 0x09, 0x03, 0x0b, 0x00, 0x0e, 0x00, 0x12, +0x00, 0x15, 0x00, 0x17, 0x00, 0x19, 0x00, 0x1a, 0x00, 0x1b, 0x00, 0x1b, +0x00, 0x1c, 0x00, 0x1c, 0xc5, 0x00, 0x9f, 0x00, 0x5f, 0x00, 0x32, 0x00, +0x16, 0x00, 0x06, 0x00, 0x00, 0x03, 0x00, 0x0a, 0x00, 0x0f, 0x00, 0x12, +0x00, 0x14, 0x00, 0x16, 0x00, 0x18, 0x00, 0x19, 0x00, 0x1a, 0x00, 0x1a, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x08, 0x00, 0x0e, 0x00, 0x12, 0x00, 0x15, 0x00, 0x17, 0x00, 0x19, +0x00, 0x1a, 0x00, 0x1b, 0x00, 0x1b, 0x00, 0x1c, 0x00, 0x1c, 0x00, 0x1d, +0x00, 0x32, 0x00, 0x2b, 0x00, 0x1a, 0x00, 0x06, 0x00, 0x0d, 0x00, 0x0e, +0x00, 0x12, 0x00, 0x15, 0x00, 0x17, 0x00, 0x19, 0x00, 0x1a, 0x00, 0x1b, +0x00, 0x1b, 0x00, 0x1c, 0x00, 0x1c, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0xcd, 0x00, 0xaf, 0x00, 0x6e, 0x00, 0x31, 0x00, +0x1e, 0x04, 0x12, 0x07, 0x0a, 0x09, 0x04, 0x0a, 0x00, 0x0b, 0x00, 0x0f, +0x00, 0x12, 0x00, 0x14, 0x00, 0x16, 0x00, 0x17, 0x00, 0x18, 0x00, 0x19, +0xd2, 0x00, 0xbc, 0x00, 0x8d, 0x00, 0x5f, 0x00, 0x3d, 0x00, 0x25, 0x00, +0x14, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x09, 0x00, 0x0d, +0x00, 0x10, 0x00, 0x12, 0x00, 0x14, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, +0x00, 0x0c, 0x00, 0x0f, 0x00, 0x12, 0x00, 0x15, 0x00, 0x16, 0x00, 0x18, +0x00, 0x19, 0x00, 0x1a, 0x00, 0x1a, 0x00, 0x1b, 0x00, 0x2c, 0x00, 0x28, +0x00, 0x1c, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x06, 0x00, 0x0c, 0x00, 0x0f, +0x00, 0x12, 0x00, 0x15, 0x00, 0x16, 0x00, 0x18, 0x00, 0x19, 0x00, 0x1a, +0x00, 0x1a, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0xd4, 0x00, 0xc1, 0x00, 0x93, 0x00, 0x5f, 0x00, 0x30, 0x00, 0x22, 0x03, +0x17, 0x06, 0x0f, 0x07, 0x0a, 0x09, 0x05, 0x0a, 0x02, 0x0b, 0x00, 0x0c, +0x00, 0x0f, 0x00, 0x11, 0x00, 0x13, 0x00, 0x15, 0xd7, 0x00, 0xc9, 0x00, +0xa8, 0x00, 0x81, 0x00, 0x5f, 0x00, 0x44, 0x00, 0x2f, 0x00, 0x1f, 0x00, +0x14, 0x00, 0x0b, 0x00, 0x04, 0x00, 0x00, 0x01, 0x00, 0x05, 0x00, 0x09, +0x00, 0x0c, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x0a, +0x00, 0x0d, 0x00, 0x10, 0x00, 0x12, 0x00, 0x14, 0x00, 0x16, 0x00, 0x17, +0x00, 0x18, 0x00, 0x19, 0x00, 0x24, 0x00, 0x21, 0x00, 0x18, 0x00, 0x0e, +0x00, 0x06, 0x00, 0x00, 0x00, 0x05, 0x00, 0x0a, 0x00, 0x0d, 0x00, 0x10, +0x00, 0x12, 0x00, 0x14, 0x00, 0x16, 0x00, 0x17, 0x00, 0x18, 0x00, 0x19, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x00, 0xcb, 0x00, +0xaa, 0x00, 0x7f, 0x00, 0x55, 0x00, 0x30, 0x00, 0x24, 0x02, 0x1b, 0x05, +0x14, 0x06, 0x0e, 0x08, 0x09, 0x09, 0x06, 0x0a, 0x03, 0x0b, 0x00, 0x0b, +0x00, 0x0d, 0x00, 0x0f, 0xda, 0x00, 0xd0, 0x00, 0xb8, 0x00, 0x99, 0x00, +0x7a, 0x00, 0x5f, 0x00, 0x49, 0x00, 0x36, 0x00, 0x28, 0x00, 0x1c, 0x00, +0x13, 0x00, 0x0c, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x02, 0x00, 0x05, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0c, +0x00, 0x0e, 0x00, 0x11, 0x00, 0x13, 0x00, 0x14, 0x00, 0x15, 0x00, 0x16, +0x00, 0x1f, 0x00, 0x1d, 0x00, 0x18, 0x00, 0x12, 0x00, 0x0c, 0x00, 0x05, +0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x0e, 0x00, 0x11, +0x00, 0x13, 0x00, 0x14, 0x00, 0x15, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0xda, 0x00, 0xd1, 0x00, 0xb8, 0x00, 0x96, 0x00, +0x71, 0x00, 0x4e, 0x00, 0x30, 0x00, 0x26, 0x02, 0x1e, 0x04, 0x17, 0x06, +0x12, 0x07, 0x0d, 0x08, 0x09, 0x09, 0x06, 0x0a, 0x04, 0x0a, 0x01, 0x0b, +0xdb, 0x00, 0xd5, 0x00, 0xc3, 0x00, 0xaa, 0x00, 0x8f, 0x00, 0x76, 0x00, +0x5f, 0x00, 0x4c, 0x00, 0x3c, 0x00, 0x2f, 0x00, 0x24, 0x00, 0x1b, 0x00, +0x13, 0x00, 0x0d, 0x00, 0x08, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x07, 0x00, 0x0a, 0x00, 0x0d, +0x00, 0x0f, 0x00, 0x11, 0x00, 0x13, 0x00, 0x14, 0x00, 0x1f, 0x00, 0x1e, +0x00, 0x1a, 0x00, 0x15, 0x00, 0x0f, 0x00, 0x0a, 0x00, 0x04, 0x00, 0x00, +0x00, 0x04, 0x00, 0x07, 0x00, 0x0a, 0x00, 0x0d, 0x00, 0x0f, 0x00, 0x11, +0x00, 0x13, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0xdb, 0x00, 0xd4, 0x00, 0xc1, 0x00, 0xa6, 0x00, 0x87, 0x00, 0x67, 0x00, +0x4a, 0x00, 0x30, 0x00, 0x27, 0x02, 0x20, 0x03, 0x1a, 0x05, 0x14, 0x06, +0x10, 0x07, 0x0c, 0x08, 0x09, 0x09, 0x07, 0x0a, 0xdc, 0x00, 0xd7, 0x00, +0xc9, 0x00, 0xb6, 0x00, 0x9f, 0x00, 0x88, 0x00, 0x72, 0x00, 0x5f, 0x00, +0x4e, 0x00, 0x40, 0x00, 0x34, 0x00, 0x29, 0x00, 0x21, 0x00, 0x19, 0x00, +0x13, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x03, 0x00, 0x06, 0x00, 0x09, 0x00, 0x0c, 0x00, 0x0e, +0x00, 0x10, 0x00, 0x11, 0x00, 0x1f, 0x00, 0x1e, 0x00, 0x1b, 0x00, 0x17, +0x00, 0x12, 0x00, 0x0d, 0x00, 0x08, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, +0x00, 0x06, 0x00, 0x09, 0x00, 0x0c, 0x00, 0x0e, 0x00, 0x10, 0x00, 0x11, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x00, 0xd7, 0x00, +0xc8, 0x00, 0xb2, 0x00, 0x97, 0x00, 0x7b, 0x00, 0x60, 0x00, 0x46, 0x00, +0x30, 0x00, 0x28, 0x01, 0x21, 0x03, 0x1c, 0x04, 0x17, 0x06, 0x13, 0x07, +0x0f, 0x08, 0x0c, 0x08, 0xdd, 0x00, 0xd9, 0x00, 0xce, 0x00, 0xbe, 0x00, +0xab, 0x00, 0x96, 0x00, 0x82, 0x00, 0x70, 0x00, 0x5f, 0x00, 0x50, 0x00, +0x43, 0x00, 0x38, 0x00, 0x2e, 0x00, 0x26, 0x00, 0x1f, 0x00, 0x18, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x03, 0x00, 0x06, 0x00, 0x08, 0x00, 0x0b, 0x00, 0x0d, 0x00, 0x0e, +0x00, 0x1f, 0x00, 0x1e, 0x00, 0x1c, 0x00, 0x19, 0x00, 0x15, 0x00, 0x10, +0x00, 0x0c, 0x00, 0x07, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x06, +0x00, 0x08, 0x00, 0x0b, 0x00, 0x0d, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0xdc, 0x00, 0xd8, 0x00, 0xcc, 0x00, 0xba, 0x00, +0xa4, 0x00, 0x8b, 0x00, 0x72, 0x00, 0x5a, 0x00, 0x44, 0x00, 0x2f, 0x00, +0x29, 0x01, 0x23, 0x03, 0x1e, 0x04, 0x19, 0x05, 0x15, 0x06, 0x11, 0x07, +0xdd, 0x00, 0xda, 0x00, 0xd1, 0x00, 0xc4, 0x00, 0xb4, 0x00, 0xa2, 0x00, +0x90, 0x00, 0x7e, 0x00, 0x6e, 0x00, 0x5f, 0x00, 0x52, 0x00, 0x46, 0x00, +0x3c, 0x00, 0x32, 0x00, 0x2a, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, +0x00, 0x05, 0x00, 0x08, 0x00, 0x0a, 0x00, 0x0c, 0x00, 0x1f, 0x00, 0x1e, +0x00, 0x1d, 0x00, 0x1a, 0x00, 0x16, 0x00, 0x12, 0x00, 0x0e, 0x00, 0x0a, +0x00, 0x06, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x05, 0x00, 0x08, +0x00, 0x0a, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0xdd, 0x00, 0xd9, 0x00, 0xd0, 0x00, 0xc0, 0x00, 0xad, 0x00, 0x98, 0x00, +0x81, 0x00, 0x6b, 0x00, 0x56, 0x00, 0x42, 0x00, 0x2f, 0x00, 0x29, 0x01, +0x24, 0x02, 0x1f, 0x04, 0x1b, 0x05, 0x17, 0x06, 0xdd, 0x00, 0xdb, 0x00, +0xd4, 0x00, 0xc9, 0x00, 0xbb, 0x00, 0xab, 0x00, 0x9b, 0x00, 0x8a, 0x00, +0x7b, 0x00, 0x6c, 0x00, 0x5f, 0x00, 0x53, 0x00, 0x48, 0x00, 0x3f, 0x00, +0x36, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x05, +0x00, 0x07, 0x00, 0x09, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1d, 0x00, 0x1b, +0x00, 0x18, 0x00, 0x14, 0x00, 0x11, 0x00, 0x0d, 0x00, 0x09, 0x00, 0x06, +0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x05, 0x00, 0x07, 0x00, 0x09, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdd, 0x00, 0xda, 0x00, +0xd2, 0x00, 0xc5, 0x00, 0xb5, 0x00, 0xa2, 0x00, 0x8e, 0x00, 0x79, 0x00, +0x65, 0x00, 0x52, 0x00, 0x40, 0x00, 0x2f, 0x00, 0x2a, 0x01, 0x25, 0x02, +0x20, 0x03, 0x1c, 0x04, 0xde, 0x00, 0xdc, 0x00, 0xd6, 0x00, 0xcc, 0x00, +0xc0, 0x00, 0xb2, 0x00, 0xa4, 0x00, 0x95, 0x00, 0x86, 0x00, 0x78, 0x00, +0x6b, 0x00, 0x5f, 0x00, 0x54, 0x00, 0x4a, 0x00, 0x41, 0x00, 0x39, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x04, 0x00, 0x06, +0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1d, 0x00, 0x1b, 0x00, 0x19, 0x00, 0x16, +0x00, 0x13, 0x00, 0x0f, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x05, 0x00, 0x02, +0x00, 0x00, 0x00, 0x02, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0xdd, 0x00, 0xdb, 0x00, 0xd4, 0x00, 0xc9, 0x00, +0xbb, 0x00, 0xaa, 0x00, 0x98, 0x00, 0x85, 0x00, 0x72, 0x00, 0x60, 0x00, +0x4f, 0x00, 0x3e, 0x00, 0x2f, 0x00, 0x2a, 0x01, 0x26, 0x02, 0x21, 0x03, +0xde, 0x00, 0xdc, 0x00, 0xd7, 0x00, 0xcf, 0x00, 0xc4, 0x00, 0xb8, 0x00, +0xab, 0x00, 0x9e, 0x00, 0x90, 0x00, 0x83, 0x00, 0x76, 0x00, 0x6a, 0x00, +0x5f, 0x00, 0x55, 0x00, 0x4c, 0x00, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x04, 0x00, 0x1f, 0x00, 0x1f, +0x00, 0x1e, 0x00, 0x1c, 0x00, 0x1a, 0x00, 0x17, 0x00, 0x14, 0x00, 0x11, +0x00, 0x0e, 0x00, 0x0b, 0x00, 0x08, 0x00, 0x05, 0x00, 0x02, 0x00, 0x00, +0x00, 0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0xde, 0x00, 0xdc, 0x00, 0xd6, 0x00, 0xcc, 0x00, 0xc0, 0x00, 0xb1, 0x00, +0xa0, 0x00, 0x8f, 0x00, 0x7e, 0x00, 0x6d, 0x00, 0x5c, 0x00, 0x4c, 0x00, +0x3d, 0x00, 0x2f, 0x00, 0x2b, 0x01, 0x26, 0x02, 0xde, 0x00, 0xdc, 0x00, +0xd8, 0x00, 0xd1, 0x00, 0xc8, 0x00, 0xbd, 0x00, 0xb1, 0x00, 0xa5, 0x00, +0x98, 0x00, 0x8c, 0x00, 0x80, 0x00, 0x74, 0x00, 0x69, 0x00, 0x5f, 0x00, +0x56, 0x00, 0x4d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x02, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1e, 0x00, 0x1c, +0x00, 0x1a, 0x00, 0x18, 0x00, 0x15, 0x00, 0x13, 0x00, 0x10, 0x00, 0x0d, +0x00, 0x0a, 0x00, 0x07, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xde, 0x00, 0xdc, 0x00, +0xd7, 0x00, 0xce, 0x00, 0xc3, 0x00, 0xb6, 0x00, 0xa8, 0x00, 0x98, 0x00, +0x88, 0x00, 0x78, 0x00, 0x68, 0x00, 0x59, 0x00, 0x4a, 0x00, 0x3c, 0x00, +0x2f, 0x00, 0x2b, 0x01, 0xde, 0x00, 0xdd, 0x00, 0xd9, 0x00, 0xd3, 0x00, +0xcb, 0x00, 0xc1, 0x00, 0xb7, 0x00, 0xab, 0x00, 0xa0, 0x00, 0x94, 0x00, +0x88, 0x00, 0x7d, 0x00, 0x73, 0x00, 0x69, 0x00, 0x5f, 0x00, 0x56, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1e, 0x00, 0x1d, 0x00, 0x1b, 0x00, 0x19, +0x00, 0x16, 0x00, 0x14, 0x00, 0x11, 0x00, 0x0e, 0x00, 0x0c, 0x00, 0x09, +0x00, 0x06, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0xde, 0x00, 0xdc, 0x00, 0xd8, 0x00, 0xd0, 0x00, +0xc7, 0x00, 0xbb, 0x00, 0xae, 0x00, 0xa0, 0x00, 0x91, 0x00, 0x82, 0x00, +0x73, 0x00, 0x64, 0x00, 0x56, 0x00, 0x48, 0x00, 0x3b, 0x00, 0x2f, 0x00, +0xde, 0x00, 0xdd, 0x00, 0xda, 0x00, 0xd4, 0x00, 0xcd, 0x00, 0xc5, 0x00, +0xbb, 0x00, 0xb1, 0x00, 0xa6, 0x00, 0x9b, 0x00, 0x90, 0x00, 0x85, 0x00, +0x7b, 0x00, 0x71, 0x00, 0x68, 0x00, 0x5f, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x37, 0x00, 0x6f, 0x00, +0xb2, 0x00, 0xc8, 0x00, 0xd2, 0x00, 0xd6, 0x00, 0xd9, 0x00, 0xda, 0x00, +0xdb, 0x00, 0xdc, 0x00, 0xdc, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, +0xdd, 0x00, 0xde, 0x00, 0x4c, 0x04, 0x87, 0x00, 0xbc, 0x00, 0xcd, 0x00, +0xd4, 0x00, 0xd8, 0x00, 0xda, 0x00, 0xdb, 0x00, 0xdc, 0x00, 0xdc, 0x00, +0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xde, 0x00, 0xde, 0x00, 0xde, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa6, 0x00, 0x76, 0x00, +0x9b, 0x00, 0xac, 0x00, 0xbc, 0x00, 0xcd, 0x00, 0xd9, 0x00, 0xda, 0x00, +0xdb, 0x00, 0xdc, 0x00, 0xdc, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, +0xdd, 0x00, 0xde, 0x00, 0x61, 0x01, 0x9f, 0x00, 0xc5, 0x00, 0xd2, 0x00, +0xd7, 0x00, 0xda, 0x00, 0xdb, 0x00, 0xdc, 0x00, 0xdd, 0x00, 0xdd, 0x00, +0xdd, 0x00, 0xde, 0x00, 0xde, 0x00, 0xde, 0x00, 0xde, 0x00, 0xde, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x6f, 0x00, 0xa2, 0x00, +0xb9, 0x00, 0xc6, 0x00, 0xcd, 0x00, 0xd2, 0x00, 0xd4, 0x00, 0xd7, 0x00, +0xd8, 0x00, 0xd9, 0x00, 0xda, 0x00, 0xdb, 0x00, 0xdb, 0x00, 0xdc, 0x00, +0x11, 0x09, 0x39, 0x01, 0x87, 0x00, 0xaf, 0x00, 0xc1, 0x00, 0xcb, 0x00, +0xd1, 0x00, 0xd4, 0x00, 0xd7, 0x00, 0xd8, 0x00, 0xd9, 0x00, 0xda, 0x00, +0xdb, 0x00, 0xdc, 0x00, 0xdc, 0x00, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x76, 0x00, 0x5b, 0x00, 0x75, 0x00, 0x96, 0x00, +0xab, 0x00, 0xc0, 0x00, 0xcd, 0x00, 0xd2, 0x00, 0xd4, 0x00, 0xd7, 0x00, +0xd8, 0x00, 0xd9, 0x00, 0xda, 0x00, 0xdb, 0x00, 0xdb, 0x00, 0xdc, 0x00, +0x23, 0x03, 0x5f, 0x00, 0x9f, 0x00, 0xbc, 0x00, 0xc9, 0x00, 0xd0, 0x00, +0xd5, 0x00, 0xd7, 0x00, 0xd9, 0x00, 0xda, 0x00, 0xdb, 0x00, 0xdc, 0x00, +0xdc, 0x00, 0xdc, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x4f, 0x00, 0x7f, 0x00, 0x9c, 0x00, +0xae, 0x00, 0xb9, 0x00, 0xc2, 0x00, 0xc7, 0x00, 0xcc, 0x00, 0xcf, 0x00, +0xd1, 0x00, 0xd3, 0x00, 0xd5, 0x00, 0xd6, 0x00, 0x01, 0x11, 0x0f, 0x07, +0x32, 0x00, 0x6e, 0x00, 0x93, 0x00, 0xaa, 0x00, 0xb8, 0x00, 0xc1, 0x00, +0xc8, 0x00, 0xcc, 0x00, 0xd0, 0x00, 0xd2, 0x00, 0xd4, 0x00, 0xd6, 0x00, +0xd7, 0x00, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x9b, 0x00, 0x75, 0x00, 0x2b, 0x00, 0x5b, 0x00, 0x7f, 0x00, 0x9b, 0x00, +0xae, 0x00, 0xb9, 0x00, 0xc2, 0x00, 0xc7, 0x00, 0xcc, 0x00, 0xcf, 0x00, +0xd1, 0x00, 0xd3, 0x00, 0xd5, 0x00, 0xd6, 0x00, 0x03, 0x09, 0x1f, 0x00, +0x5f, 0x00, 0x8d, 0x00, 0xa8, 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xc9, 0x00, +0xce, 0x00, 0xd1, 0x00, 0xd4, 0x00, 0xd6, 0x00, 0xd7, 0x00, 0xd8, 0x00, +0xd9, 0x00, 0xda, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x02, 0x00, 0x3c, 0x00, 0x66, 0x00, 0x82, 0x00, 0x97, 0x00, +0xa5, 0x00, 0xb0, 0x00, 0xb8, 0x00, 0xbe, 0x00, 0xc3, 0x00, 0xc7, 0x00, +0xca, 0x00, 0xcd, 0x00, 0x00, 0x17, 0x02, 0x0c, 0x19, 0x05, 0x31, 0x00, +0x5f, 0x00, 0x7f, 0x00, 0x96, 0x00, 0xa6, 0x00, 0xb2, 0x00, 0xba, 0x00, +0xc0, 0x00, 0xc5, 0x00, 0xc9, 0x00, 0xcc, 0x00, 0xce, 0x00, 0xd0, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xac, 0x00, 0x96, 0x00, +0x5b, 0x00, 0x13, 0x00, 0x41, 0x00, 0x66, 0x00, 0x82, 0x00, 0x97, 0x00, +0xa5, 0x00, 0xb0, 0x00, 0xb8, 0x00, 0xbe, 0x00, 0xc3, 0x00, 0xc7, 0x00, +0xca, 0x00, 0xcd, 0x00, 0x00, 0x13, 0x04, 0x01, 0x32, 0x00, 0x5f, 0x00, +0x81, 0x00, 0x99, 0x00, 0xaa, 0x00, 0xb6, 0x00, 0xbe, 0x00, 0xc4, 0x00, +0xc9, 0x00, 0xcc, 0x00, 0xcf, 0x00, 0xd1, 0x00, 0xd3, 0x00, 0xd4, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x01, 0x00, 0x2f, 0x00, 0x54, 0x00, 0x6f, 0x00, 0x84, 0x00, 0x93, 0x00, +0xa0, 0x00, 0xa9, 0x00, 0xb1, 0x00, 0xb7, 0x00, 0xbc, 0x00, 0xc0, 0x00, +0x00, 0x1b, 0x00, 0x12, 0x0b, 0x09, 0x1e, 0x04, 0x30, 0x00, 0x55, 0x00, +0x71, 0x00, 0x87, 0x00, 0x97, 0x00, 0xa4, 0x00, 0xad, 0x00, 0xb5, 0x00, +0xbb, 0x00, 0xc0, 0x00, 0xc3, 0x00, 0xc7, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0xbc, 0x00, 0xab, 0x00, 0x7f, 0x00, 0x41, 0x00, +0x03, 0x00, 0x2f, 0x00, 0x54, 0x00, 0x6f, 0x00, 0x84, 0x00, 0x93, 0x00, +0xa0, 0x00, 0xa9, 0x00, 0xb1, 0x00, 0xb7, 0x00, 0xbc, 0x00, 0xc0, 0x00, +0x00, 0x18, 0x00, 0x0a, 0x16, 0x00, 0x3d, 0x00, 0x5f, 0x00, 0x7a, 0x00, +0x8f, 0x00, 0x9f, 0x00, 0xab, 0x00, 0xb4, 0x00, 0xbb, 0x00, 0xc0, 0x00, +0xc4, 0x00, 0xc8, 0x00, 0xcb, 0x00, 0xcd, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, +0x27, 0x00, 0x47, 0x00, 0x60, 0x00, 0x74, 0x00, 0x84, 0x00, 0x91, 0x00, +0x9c, 0x00, 0xa4, 0x00, 0xab, 0x00, 0xb1, 0x00, 0x00, 0x1c, 0x00, 0x17, +0x03, 0x0b, 0x12, 0x07, 0x22, 0x03, 0x30, 0x00, 0x4e, 0x00, 0x67, 0x00, +0x7b, 0x00, 0x8b, 0x00, 0x98, 0x00, 0xa2, 0x00, 0xaa, 0x00, 0xb1, 0x00, +0xb6, 0x00, 0xbb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0xcd, 0x00, 0xc0, 0x00, 0x9b, 0x00, 0x66, 0x00, 0x2f, 0x00, 0x02, 0x00, +0x27, 0x00, 0x47, 0x00, 0x60, 0x00, 0x74, 0x00, 0x84, 0x00, 0x91, 0x00, +0x9c, 0x00, 0xa4, 0x00, 0xab, 0x00, 0xb1, 0x00, 0x00, 0x1a, 0x00, 0x11, +0x06, 0x00, 0x25, 0x00, 0x44, 0x00, 0x5f, 0x00, 0x76, 0x00, 0x88, 0x00, +0x96, 0x00, 0xa2, 0x00, 0xab, 0x00, 0xb2, 0x00, 0xb8, 0x00, 0xbd, 0x00, +0xc1, 0x00, 0xc5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x00, +0x3d, 0x00, 0x55, 0x00, 0x68, 0x00, 0x78, 0x00, 0x85, 0x00, 0x90, 0x00, +0x99, 0x00, 0xa0, 0x00, 0x00, 0x1d, 0x00, 0x19, 0x00, 0x0e, 0x0a, 0x09, +0x17, 0x06, 0x24, 0x02, 0x30, 0x00, 0x4a, 0x00, 0x60, 0x00, 0x72, 0x00, +0x81, 0x00, 0x8e, 0x00, 0x98, 0x00, 0xa0, 0x00, 0xa8, 0x00, 0xae, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd9, 0x00, 0xcd, 0x00, +0xae, 0x00, 0x82, 0x00, 0x54, 0x00, 0x27, 0x00, 0x01, 0x00, 0x21, 0x00, +0x3d, 0x00, 0x55, 0x00, 0x68, 0x00, 0x78, 0x00, 0x85, 0x00, 0x90, 0x00, +0x99, 0x00, 0xa0, 0x00, 0x00, 0x1c, 0x00, 0x15, 0x00, 0x03, 0x14, 0x00, +0x2f, 0x00, 0x49, 0x00, 0x5f, 0x00, 0x72, 0x00, 0x82, 0x00, 0x90, 0x00, +0x9b, 0x00, 0xa4, 0x00, 0xab, 0x00, 0xb1, 0x00, 0xb7, 0x00, 0xbb, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x36, 0x00, +0x4b, 0x00, 0x5d, 0x00, 0x6d, 0x00, 0x7a, 0x00, 0x85, 0x00, 0x8e, 0x00, +0x00, 0x1e, 0x00, 0x1b, 0x00, 0x12, 0x04, 0x0a, 0x0f, 0x07, 0x1b, 0x05, +0x26, 0x02, 0x30, 0x00, 0x46, 0x00, 0x5a, 0x00, 0x6b, 0x00, 0x79, 0x00, +0x85, 0x00, 0x8f, 0x00, 0x98, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0xda, 0x00, 0xd2, 0x00, 0xb9, 0x00, 0x97, 0x00, +0x6f, 0x00, 0x47, 0x00, 0x21, 0x00, 0x01, 0x00, 0x1d, 0x00, 0x36, 0x00, +0x4b, 0x00, 0x5d, 0x00, 0x6d, 0x00, 0x7a, 0x00, 0x85, 0x00, 0x8e, 0x00, +0x00, 0x1d, 0x00, 0x18, 0x00, 0x0a, 0x09, 0x00, 0x1f, 0x00, 0x36, 0x00, +0x4c, 0x00, 0x5f, 0x00, 0x70, 0x00, 0x7e, 0x00, 0x8a, 0x00, 0x95, 0x00, +0x9e, 0x00, 0xa5, 0x00, 0xab, 0x00, 0xb1, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x00, 0x30, 0x00, 0x44, 0x00, +0x55, 0x00, 0x64, 0x00, 0x70, 0x00, 0x7b, 0x00, 0x00, 0x1e, 0x00, 0x1c, +0x00, 0x15, 0x00, 0x0b, 0x0a, 0x09, 0x14, 0x06, 0x1e, 0x04, 0x27, 0x02, +0x30, 0x00, 0x44, 0x00, 0x56, 0x00, 0x65, 0x00, 0x72, 0x00, 0x7e, 0x00, +0x88, 0x00, 0x91, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0xdb, 0x00, 0xd4, 0x00, 0xc2, 0x00, 0xa5, 0x00, 0x84, 0x00, 0x60, 0x00, +0x3d, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x19, 0x00, 0x30, 0x00, 0x44, 0x00, +0x55, 0x00, 0x64, 0x00, 0x70, 0x00, 0x7b, 0x00, 0x00, 0x1d, 0x00, 0x1a, +0x00, 0x0f, 0x00, 0x00, 0x14, 0x00, 0x28, 0x00, 0x3c, 0x00, 0x4e, 0x00, +0x5f, 0x00, 0x6e, 0x00, 0x7b, 0x00, 0x86, 0x00, 0x90, 0x00, 0x98, 0x00, +0xa0, 0x00, 0xa6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x2b, 0x00, 0x3e, 0x00, 0x4e, 0x00, +0x5c, 0x00, 0x68, 0x00, 0x00, 0x1e, 0x00, 0x1c, 0x00, 0x17, 0x00, 0x0f, +0x05, 0x0a, 0x0e, 0x08, 0x17, 0x06, 0x20, 0x03, 0x28, 0x01, 0x2f, 0x00, +0x42, 0x00, 0x52, 0x00, 0x60, 0x00, 0x6d, 0x00, 0x78, 0x00, 0x82, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x00, 0xd7, 0x00, +0xc7, 0x00, 0xb0, 0x00, 0x93, 0x00, 0x74, 0x00, 0x55, 0x00, 0x36, 0x00, +0x19, 0x00, 0x00, 0x00, 0x17, 0x00, 0x2b, 0x00, 0x3e, 0x00, 0x4e, 0x00, +0x5c, 0x00, 0x68, 0x00, 0x00, 0x1e, 0x00, 0x1b, 0x00, 0x12, 0x00, 0x05, +0x0b, 0x00, 0x1c, 0x00, 0x2f, 0x00, 0x40, 0x00, 0x50, 0x00, 0x5f, 0x00, +0x6c, 0x00, 0x78, 0x00, 0x83, 0x00, 0x8c, 0x00, 0x94, 0x00, 0x9b, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x15, 0x00, 0x28, 0x00, 0x39, 0x00, 0x48, 0x00, 0x55, 0x00, +0x00, 0x1f, 0x00, 0x1d, 0x00, 0x19, 0x00, 0x12, 0x02, 0x0b, 0x09, 0x09, +0x12, 0x07, 0x1a, 0x05, 0x21, 0x03, 0x29, 0x01, 0x2f, 0x00, 0x40, 0x00, +0x4f, 0x00, 0x5c, 0x00, 0x68, 0x00, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0xdc, 0x00, 0xd8, 0x00, 0xcc, 0x00, 0xb8, 0x00, +0xa0, 0x00, 0x84, 0x00, 0x68, 0x00, 0x4b, 0x00, 0x30, 0x00, 0x17, 0x00, +0x00, 0x00, 0x15, 0x00, 0x28, 0x00, 0x39, 0x00, 0x48, 0x00, 0x55, 0x00, +0x00, 0x1e, 0x00, 0x1c, 0x00, 0x14, 0x00, 0x09, 0x04, 0x00, 0x13, 0x00, +0x24, 0x00, 0x34, 0x00, 0x43, 0x00, 0x52, 0x00, 0x5f, 0x00, 0x6b, 0x00, +0x76, 0x00, 0x80, 0x00, 0x88, 0x00, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x13, 0x00, 0x24, 0x00, 0x34, 0x00, 0x42, 0x00, 0x00, 0x1f, 0x00, 0x1d, +0x00, 0x1a, 0x00, 0x14, 0x00, 0x0c, 0x06, 0x0a, 0x0d, 0x08, 0x14, 0x06, +0x1c, 0x04, 0x23, 0x03, 0x29, 0x01, 0x2f, 0x00, 0x3e, 0x00, 0x4c, 0x00, +0x59, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0xdd, 0x00, 0xd9, 0x00, 0xcf, 0x00, 0xbe, 0x00, 0xa9, 0x00, 0x91, 0x00, +0x78, 0x00, 0x5d, 0x00, 0x44, 0x00, 0x2b, 0x00, 0x15, 0x00, 0x00, 0x00, +0x13, 0x00, 0x24, 0x00, 0x34, 0x00, 0x42, 0x00, 0x00, 0x1e, 0x00, 0x1c, +0x00, 0x16, 0x00, 0x0d, 0x00, 0x01, 0x0c, 0x00, 0x1b, 0x00, 0x29, 0x00, +0x38, 0x00, 0x46, 0x00, 0x53, 0x00, 0x5f, 0x00, 0x6a, 0x00, 0x74, 0x00, +0x7d, 0x00, 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, +0x22, 0x00, 0x30, 0x00, 0x00, 0x1f, 0x00, 0x1e, 0x00, 0x1b, 0x00, 0x16, +0x00, 0x0f, 0x03, 0x0b, 0x09, 0x09, 0x10, 0x07, 0x17, 0x06, 0x1e, 0x04, +0x24, 0x02, 0x2a, 0x01, 0x2f, 0x00, 0x3d, 0x00, 0x4a, 0x00, 0x56, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdd, 0x00, 0xda, 0x00, +0xd1, 0x00, 0xc3, 0x00, 0xb1, 0x00, 0x9c, 0x00, 0x85, 0x00, 0x6d, 0x00, +0x55, 0x00, 0x3e, 0x00, 0x28, 0x00, 0x13, 0x00, 0x00, 0x00, 0x11, 0x00, +0x22, 0x00, 0x30, 0x00, 0x00, 0x1e, 0x00, 0x1d, 0x00, 0x18, 0x00, 0x10, +0x00, 0x05, 0x06, 0x00, 0x13, 0x00, 0x21, 0x00, 0x2e, 0x00, 0x3c, 0x00, +0x48, 0x00, 0x54, 0x00, 0x5f, 0x00, 0x69, 0x00, 0x73, 0x00, 0x7b, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x1f, 0x00, +0x00, 0x1f, 0x00, 0x1e, 0x00, 0x1b, 0x00, 0x17, 0x00, 0x11, 0x00, 0x0b, +0x06, 0x0a, 0x0c, 0x08, 0x13, 0x07, 0x19, 0x05, 0x1f, 0x04, 0x25, 0x02, +0x2a, 0x01, 0x2f, 0x00, 0x3c, 0x00, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0xdd, 0x00, 0xdb, 0x00, 0xd3, 0x00, 0xc7, 0x00, +0xb7, 0x00, 0xa4, 0x00, 0x90, 0x00, 0x7a, 0x00, 0x64, 0x00, 0x4e, 0x00, +0x39, 0x00, 0x24, 0x00, 0x11, 0x00, 0x00, 0x00, 0x10, 0x00, 0x1f, 0x00, +0x00, 0x1f, 0x00, 0x1d, 0x00, 0x19, 0x00, 0x12, 0x00, 0x09, 0x01, 0x00, +0x0d, 0x00, 0x19, 0x00, 0x26, 0x00, 0x32, 0x00, 0x3f, 0x00, 0x4a, 0x00, +0x55, 0x00, 0x5f, 0x00, 0x69, 0x00, 0x71, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x1f, 0x00, 0x1e, +0x00, 0x1c, 0x00, 0x18, 0x00, 0x13, 0x00, 0x0d, 0x04, 0x0a, 0x09, 0x09, +0x0f, 0x08, 0x15, 0x06, 0x1b, 0x05, 0x20, 0x03, 0x26, 0x02, 0x2b, 0x01, +0x2f, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0xdd, 0x00, 0xdb, 0x00, 0xd5, 0x00, 0xca, 0x00, 0xbc, 0x00, 0xab, 0x00, +0x99, 0x00, 0x85, 0x00, 0x70, 0x00, 0x5c, 0x00, 0x48, 0x00, 0x34, 0x00, +0x22, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x1f, 0x00, 0x1d, +0x00, 0x1a, 0x00, 0x14, 0x00, 0x0c, 0x00, 0x02, 0x08, 0x00, 0x13, 0x00, +0x1f, 0x00, 0x2a, 0x00, 0x36, 0x00, 0x41, 0x00, 0x4c, 0x00, 0x56, 0x00, +0x5f, 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1e, 0x00, 0x1c, 0x00, 0x19, +0x00, 0x15, 0x00, 0x0f, 0x01, 0x0b, 0x07, 0x0a, 0x0c, 0x08, 0x11, 0x07, +0x17, 0x06, 0x1c, 0x04, 0x21, 0x03, 0x26, 0x02, 0x2b, 0x01, 0x2f, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xde, 0x00, 0xdc, 0x00, +0xd6, 0x00, 0xcd, 0x00, 0xc0, 0x00, 0xb1, 0x00, 0xa0, 0x00, 0x8e, 0x00, +0x7b, 0x00, 0x68, 0x00, 0x55, 0x00, 0x42, 0x00, 0x30, 0x00, 0x1f, 0x00, +0x0f, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1e, 0x00, 0x1a, 0x00, 0x15, +0x00, 0x0e, 0x00, 0x05, 0x03, 0x00, 0x0e, 0x00, 0x18, 0x00, 0x23, 0x00, +0x2e, 0x00, 0x39, 0x00, 0x43, 0x00, 0x4d, 0x00, 0x56, 0x00, 0x5f, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x61, 0x01, 0x9f, 0x00, 0xc5, 0x00, 0xd2, 0x00, 0xd7, 0x00, 0xda, 0x00, +0xdb, 0x00, 0xdc, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xde, 0x00, +0xde, 0x00, 0xde, 0x00, 0xde, 0x00, 0xde, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x61, 0x01, 0x23, 0x03, 0x03, 0x09, 0x00, 0x13, +0x00, 0x18, 0x00, 0x1a, 0x00, 0x1c, 0x00, 0x1d, 0x00, 0x1d, 0x00, 0x1e, +0x00, 0x1e, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x03, 0x5f, 0x00, +0x9f, 0x00, 0xbc, 0x00, 0xc9, 0x00, 0xd0, 0x00, 0xd5, 0x00, 0xd7, 0x00, +0xd9, 0x00, 0xda, 0x00, 0xdb, 0x00, 0xdc, 0x00, 0xdc, 0x00, 0xdc, 0x00, +0xdd, 0x00, 0xdd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x9f, 0x00, 0x5f, 0x00, 0x1f, 0x00, 0x04, 0x01, 0x00, 0x0a, 0x00, 0x11, +0x00, 0x15, 0x00, 0x18, 0x00, 0x1a, 0x00, 0x1b, 0x00, 0x1c, 0x00, 0x1c, +0x00, 0x1d, 0x00, 0x1d, 0x00, 0x1d, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x03, 0x09, 0x1f, 0x00, 0x5f, 0x00, 0x8d, 0x00, +0xa8, 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xc9, 0x00, 0xce, 0x00, 0xd1, 0x00, +0xd4, 0x00, 0xd6, 0x00, 0xd7, 0x00, 0xd8, 0x00, 0xd9, 0x00, 0xda, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc5, 0x00, 0x9f, 0x00, +0x5f, 0x00, 0x32, 0x00, 0x16, 0x00, 0x06, 0x00, 0x00, 0x03, 0x00, 0x0a, +0x00, 0x0f, 0x00, 0x12, 0x00, 0x14, 0x00, 0x16, 0x00, 0x18, 0x00, 0x19, +0x00, 0x1a, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x13, 0x04, 0x01, 0x32, 0x00, 0x5f, 0x00, 0x81, 0x00, 0x99, 0x00, +0xaa, 0x00, 0xb6, 0x00, 0xbe, 0x00, 0xc4, 0x00, 0xc9, 0x00, 0xcc, 0x00, +0xcf, 0x00, 0xd1, 0x00, 0xd3, 0x00, 0xd4, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0xd2, 0x00, 0xbc, 0x00, 0x8d, 0x00, 0x5f, 0x00, +0x3d, 0x00, 0x25, 0x00, 0x14, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x05, +0x00, 0x09, 0x00, 0x0d, 0x00, 0x10, 0x00, 0x12, 0x00, 0x14, 0x00, 0x15, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x0a, +0x16, 0x00, 0x3d, 0x00, 0x5f, 0x00, 0x7a, 0x00, 0x8f, 0x00, 0x9f, 0x00, +0xab, 0x00, 0xb4, 0x00, 0xbb, 0x00, 0xc0, 0x00, 0xc4, 0x00, 0xc8, 0x00, +0xcb, 0x00, 0xcd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0xd7, 0x00, 0xc9, 0x00, 0xa8, 0x00, 0x81, 0x00, 0x5f, 0x00, 0x44, 0x00, +0x2f, 0x00, 0x1f, 0x00, 0x14, 0x00, 0x0b, 0x00, 0x04, 0x00, 0x00, 0x01, +0x00, 0x05, 0x00, 0x09, 0x00, 0x0c, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x11, 0x06, 0x00, 0x25, 0x00, +0x44, 0x00, 0x5f, 0x00, 0x76, 0x00, 0x88, 0x00, 0x96, 0x00, 0xa2, 0x00, +0xab, 0x00, 0xb2, 0x00, 0xb8, 0x00, 0xbd, 0x00, 0xc1, 0x00, 0xc5, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xda, 0x00, 0xd0, 0x00, +0xb8, 0x00, 0x99, 0x00, 0x7a, 0x00, 0x5f, 0x00, 0x49, 0x00, 0x36, 0x00, +0x28, 0x00, 0x1c, 0x00, 0x13, 0x00, 0x0c, 0x00, 0x06, 0x00, 0x01, 0x00, +0x00, 0x02, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x1c, 0x00, 0x15, 0x00, 0x03, 0x14, 0x00, 0x2f, 0x00, 0x49, 0x00, +0x5f, 0x00, 0x72, 0x00, 0x82, 0x00, 0x90, 0x00, 0x9b, 0x00, 0xa4, 0x00, +0xab, 0x00, 0xb1, 0x00, 0xb7, 0x00, 0xbb, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0xdb, 0x00, 0xd5, 0x00, 0xc3, 0x00, 0xaa, 0x00, +0x8f, 0x00, 0x76, 0x00, 0x5f, 0x00, 0x4c, 0x00, 0x3c, 0x00, 0x2f, 0x00, +0x24, 0x00, 0x1b, 0x00, 0x13, 0x00, 0x0d, 0x00, 0x08, 0x00, 0x03, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x18, +0x00, 0x0a, 0x09, 0x00, 0x1f, 0x00, 0x36, 0x00, 0x4c, 0x00, 0x5f, 0x00, +0x70, 0x00, 0x7e, 0x00, 0x8a, 0x00, 0x95, 0x00, 0x9e, 0x00, 0xa5, 0x00, +0xab, 0x00, 0xb1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0xdc, 0x00, 0xd7, 0x00, 0xc9, 0x00, 0xb6, 0x00, 0x9f, 0x00, 0x88, 0x00, +0x72, 0x00, 0x5f, 0x00, 0x4e, 0x00, 0x40, 0x00, 0x34, 0x00, 0x29, 0x00, +0x21, 0x00, 0x19, 0x00, 0x13, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x1a, 0x00, 0x0f, 0x00, 0x00, +0x14, 0x00, 0x28, 0x00, 0x3c, 0x00, 0x4e, 0x00, 0x5f, 0x00, 0x6e, 0x00, +0x7b, 0x00, 0x86, 0x00, 0x90, 0x00, 0x98, 0x00, 0xa0, 0x00, 0xa6, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdd, 0x00, 0xd9, 0x00, +0xce, 0x00, 0xbe, 0x00, 0xab, 0x00, 0x96, 0x00, 0x82, 0x00, 0x70, 0x00, +0x5f, 0x00, 0x50, 0x00, 0x43, 0x00, 0x38, 0x00, 0x2e, 0x00, 0x26, 0x00, +0x1f, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x1e, 0x00, 0x1b, 0x00, 0x12, 0x00, 0x05, 0x0b, 0x00, 0x1c, 0x00, +0x2f, 0x00, 0x40, 0x00, 0x50, 0x00, 0x5f, 0x00, 0x6c, 0x00, 0x78, 0x00, +0x83, 0x00, 0x8c, 0x00, 0x94, 0x00, 0x9b, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0xdd, 0x00, 0xda, 0x00, 0xd1, 0x00, 0xc4, 0x00, +0xb4, 0x00, 0xa2, 0x00, 0x90, 0x00, 0x7e, 0x00, 0x6e, 0x00, 0x5f, 0x00, +0x52, 0x00, 0x46, 0x00, 0x3c, 0x00, 0x32, 0x00, 0x2a, 0x00, 0x23, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x1c, +0x00, 0x14, 0x00, 0x09, 0x04, 0x00, 0x13, 0x00, 0x24, 0x00, 0x34, 0x00, +0x43, 0x00, 0x52, 0x00, 0x5f, 0x00, 0x6b, 0x00, 0x76, 0x00, 0x80, 0x00, +0x88, 0x00, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0xdd, 0x00, 0xdb, 0x00, 0xd4, 0x00, 0xc9, 0x00, 0xbb, 0x00, 0xab, 0x00, +0x9b, 0x00, 0x8a, 0x00, 0x7b, 0x00, 0x6c, 0x00, 0x5f, 0x00, 0x53, 0x00, +0x48, 0x00, 0x3f, 0x00, 0x36, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x1c, 0x00, 0x16, 0x00, 0x0d, +0x00, 0x01, 0x0c, 0x00, 0x1b, 0x00, 0x29, 0x00, 0x38, 0x00, 0x46, 0x00, +0x53, 0x00, 0x5f, 0x00, 0x6a, 0x00, 0x74, 0x00, 0x7d, 0x00, 0x85, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xde, 0x00, 0xdc, 0x00, +0xd6, 0x00, 0xcc, 0x00, 0xc0, 0x00, 0xb2, 0x00, 0xa4, 0x00, 0x95, 0x00, +0x86, 0x00, 0x78, 0x00, 0x6b, 0x00, 0x5f, 0x00, 0x54, 0x00, 0x4a, 0x00, +0x41, 0x00, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x1e, 0x00, 0x1d, 0x00, 0x18, 0x00, 0x10, 0x00, 0x05, 0x06, 0x00, +0x13, 0x00, 0x21, 0x00, 0x2e, 0x00, 0x3c, 0x00, 0x48, 0x00, 0x54, 0x00, +0x5f, 0x00, 0x69, 0x00, 0x73, 0x00, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0xde, 0x00, 0xdc, 0x00, 0xd7, 0x00, 0xcf, 0x00, +0xc4, 0x00, 0xb8, 0x00, 0xab, 0x00, 0x9e, 0x00, 0x90, 0x00, 0x83, 0x00, +0x76, 0x00, 0x6a, 0x00, 0x5f, 0x00, 0x55, 0x00, 0x4c, 0x00, 0x43, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1d, +0x00, 0x19, 0x00, 0x12, 0x00, 0x09, 0x01, 0x00, 0x0d, 0x00, 0x19, 0x00, +0x26, 0x00, 0x32, 0x00, 0x3f, 0x00, 0x4a, 0x00, 0x55, 0x00, 0x5f, 0x00, +0x69, 0x00, 0x71, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0xde, 0x00, 0xdc, 0x00, 0xd8, 0x00, 0xd1, 0x00, 0xc8, 0x00, 0xbd, 0x00, +0xb1, 0x00, 0xa5, 0x00, 0x98, 0x00, 0x8c, 0x00, 0x80, 0x00, 0x74, 0x00, +0x69, 0x00, 0x5f, 0x00, 0x56, 0x00, 0x4d, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1d, 0x00, 0x1a, 0x00, 0x14, +0x00, 0x0c, 0x00, 0x02, 0x08, 0x00, 0x13, 0x00, 0x1f, 0x00, 0x2a, 0x00, +0x36, 0x00, 0x41, 0x00, 0x4c, 0x00, 0x56, 0x00, 0x5f, 0x00, 0x68, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xde, 0x00, 0xdd, 0x00, +0xd9, 0x00, 0xd3, 0x00, 0xcb, 0x00, 0xc1, 0x00, 0xb7, 0x00, 0xab, 0x00, +0xa0, 0x00, 0x94, 0x00, 0x88, 0x00, 0x7d, 0x00, 0x73, 0x00, 0x69, 0x00, +0x5f, 0x00, 0x56, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x1f, 0x00, 0x1e, 0x00, 0x1a, 0x00, 0x15, 0x00, 0x0e, 0x00, 0x05, +0x03, 0x00, 0x0e, 0x00, 0x18, 0x00, 0x23, 0x00, 0x2e, 0x00, 0x39, 0x00, +0x43, 0x00, 0x4d, 0x00, 0x56, 0x00, 0x5f, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0xde, 0x00, 0xdd, 0x00, 0xda, 0x00, 0xd4, 0x00, +0xcd, 0x00, 0xc5, 0x00, 0xbb, 0x00, 0xb1, 0x00, 0xa6, 0x00, 0x9b, 0x00, +0x90, 0x00, 0x85, 0x00, 0x7b, 0x00, 0x71, 0x00, 0x68, 0x00, 0x5f, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x6f, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x02, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0xb2, 0x00, 0x6f, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x19, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x00, 0xa2, +0x00, 0x4f, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x1c, 0x00, 0x17, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0xd2, 0x00, 0xb9, 0x00, 0x7f, 0x00, 0x3c, +0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x1a, 0x00, +0x12, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0xd6, 0x00, 0xc6, 0x00, 0x9c, 0x00, 0x66, 0x00, 0x2f, 0x00, 0x01, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x1c, 0x00, 0x16, 0x00, 0x0e, 0x00, +0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd9, 0x00, 0xcd, +0x00, 0xae, 0x00, 0x82, 0x00, 0x54, 0x00, 0x27, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x1f, 0x00, 0x1d, 0x00, 0x18, 0x00, 0x12, 0x00, 0x0c, 0x00, 0x05, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0xda, 0x00, 0xd2, 0x00, 0xb9, 0x00, 0x97, +0x00, 0x6f, 0x00, 0x47, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1e, 0x00, +0x1a, 0x00, 0x15, 0x00, 0x0f, 0x00, 0x0a, 0x00, 0x04, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0xdb, 0x00, 0xd4, 0x00, 0xc2, 0x00, 0xa5, 0x00, 0x84, 0x00, 0x60, +0x00, 0x3d, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1e, 0x00, 0x1b, 0x00, 0x17, 0x00, +0x12, 0x00, 0x0d, 0x00, 0x08, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x00, 0xd7, +0x00, 0xc7, 0x00, 0xb0, 0x00, 0x93, 0x00, 0x74, 0x00, 0x55, 0x00, 0x36, +0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x1f, 0x00, 0x1e, 0x00, 0x1c, 0x00, 0x19, 0x00, 0x15, 0x00, 0x10, 0x00, +0x0c, 0x00, 0x07, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x00, 0xd8, 0x00, 0xcc, 0x00, 0xb8, +0x00, 0xa0, 0x00, 0x84, 0x00, 0x68, 0x00, 0x4b, 0x00, 0x30, 0x00, 0x17, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1e, 0x00, +0x1d, 0x00, 0x1a, 0x00, 0x16, 0x00, 0x12, 0x00, 0x0e, 0x00, 0x0a, 0x00, +0x06, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0xdd, 0x00, 0xd9, 0x00, 0xcf, 0x00, 0xbe, 0x00, 0xa9, 0x00, 0x91, +0x00, 0x78, 0x00, 0x5d, 0x00, 0x44, 0x00, 0x2b, 0x00, 0x15, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1d, 0x00, 0x1b, 0x00, +0x18, 0x00, 0x14, 0x00, 0x11, 0x00, 0x0d, 0x00, 0x09, 0x00, 0x06, 0x00, +0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdd, 0x00, 0xda, +0x00, 0xd1, 0x00, 0xc3, 0x00, 0xb1, 0x00, 0x9c, 0x00, 0x85, 0x00, 0x6d, +0x00, 0x55, 0x00, 0x3e, 0x00, 0x28, 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x1f, 0x00, 0x1f, 0x00, 0x1d, 0x00, 0x1b, 0x00, 0x19, 0x00, 0x16, 0x00, +0x13, 0x00, 0x0f, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x05, 0x00, 0x02, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0xdd, 0x00, 0xdb, 0x00, 0xd3, 0x00, 0xc7, +0x00, 0xb7, 0x00, 0xa4, 0x00, 0x90, 0x00, 0x7a, 0x00, 0x64, 0x00, 0x4e, +0x00, 0x39, 0x00, 0x24, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1f, 0x00, +0x1e, 0x00, 0x1c, 0x00, 0x1a, 0x00, 0x17, 0x00, 0x14, 0x00, 0x11, 0x00, +0x0e, 0x00, 0x0b, 0x00, 0x08, 0x00, 0x05, 0x00, 0x02, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0xdd, 0x00, 0xdb, 0x00, 0xd5, 0x00, 0xca, 0x00, 0xbc, 0x00, 0xab, +0x00, 0x99, 0x00, 0x85, 0x00, 0x70, 0x00, 0x5c, 0x00, 0x48, 0x00, 0x34, +0x00, 0x22, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1e, 0x00, 0x1c, 0x00, +0x1a, 0x00, 0x18, 0x00, 0x15, 0x00, 0x13, 0x00, 0x10, 0x00, 0x0d, 0x00, +0x0a, 0x00, 0x07, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xde, 0x00, 0xdc, +0x00, 0xd6, 0x00, 0xcd, 0x00, 0xc0, 0x00, 0xb1, 0x00, 0xa0, 0x00, 0x8e, +0x00, 0x7b, 0x00, 0x68, 0x00, 0x55, 0x00, 0x42, 0x00, 0x30, 0x00, 0x1f, +0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x1f, 0x00, 0x1f, 0x00, 0x1e, 0x00, 0x1d, 0x00, 0x1b, 0x00, 0x19, 0x00, +0x16, 0x00, 0x14, 0x00, 0x11, 0x00, 0x0e, 0x00, 0x0c, 0x00, 0x09, 0x00, +0x06, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x37, 0x00, 0x6f, +0x00, 0xb2, 0x00, 0xc8, 0x00, 0xd2, 0x00, 0xd6, 0x00, 0xd9, 0x00, 0xda, +0x00, 0xdb, 0x00, 0xdc, 0x00, 0xdc, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, +0x00, 0xdd, 0x00, 0xde, 0x00, 0xa6, 0x00, 0x76, 0x00, 0x9b, 0x00, 0xac, +0x00, 0xbc, 0x00, 0xcd, 0x00, 0xd9, 0x00, 0xda, 0x00, 0xdb, 0x00, 0xdc, +0x00, 0xdc, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xde, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x4c, 0x00, 0x87, +0x00, 0xbc, 0x00, 0xcd, 0x00, 0xd4, 0x00, 0xd8, 0x00, 0xda, 0x00, 0xdb, +0x00, 0xdc, 0x00, 0xdc, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xde, +0x00, 0xde, 0x00, 0xde, 0x01, 0x61, 0x00, 0x9f, 0x00, 0xc5, 0x00, 0xd2, +0x00, 0xd7, 0x00, 0xda, 0x00, 0xdb, 0x00, 0xdc, 0x00, 0xdd, 0x00, 0xdd, +0x00, 0xdd, 0x00, 0xde, 0x00, 0xde, 0x00, 0xde, 0x00, 0xde, 0x00, 0xde, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x6f, 0x00, 0xa2, +0x00, 0xb9, 0x00, 0xc6, 0x00, 0xcd, 0x00, 0xd2, 0x00, 0xd4, 0x00, 0xd7, +0x00, 0xd8, 0x00, 0xd9, 0x00, 0xda, 0x00, 0xdb, 0x00, 0xdb, 0x00, 0xdc, +0x00, 0x76, 0x00, 0x5b, 0x00, 0x75, 0x00, 0x96, 0x00, 0xab, 0x00, 0xc0, +0x00, 0xcd, 0x00, 0xd2, 0x00, 0xd4, 0x00, 0xd7, 0x00, 0xd8, 0x00, 0xd9, +0x00, 0xda, 0x00, 0xdb, 0x00, 0xdb, 0x00, 0xdc, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x09, 0x11, 0x01, 0x39, 0x00, 0x87, 0x00, 0xaf, +0x00, 0xc1, 0x00, 0xcb, 0x00, 0xd1, 0x00, 0xd4, 0x00, 0xd7, 0x00, 0xd8, +0x00, 0xd9, 0x00, 0xda, 0x00, 0xdb, 0x00, 0xdc, 0x00, 0xdc, 0x00, 0xdc, +0x03, 0x23, 0x00, 0x5f, 0x00, 0x9f, 0x00, 0xbc, 0x00, 0xc9, 0x00, 0xd0, +0x00, 0xd5, 0x00, 0xd7, 0x00, 0xd9, 0x00, 0xda, 0x00, 0xdb, 0x00, 0xdc, +0x00, 0xdc, 0x00, 0xdc, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x4f, 0x00, 0x7f, 0x00, 0x9c, +0x00, 0xae, 0x00, 0xb9, 0x00, 0xc2, 0x00, 0xc7, 0x00, 0xcc, 0x00, 0xcf, +0x00, 0xd1, 0x00, 0xd3, 0x00, 0xd5, 0x00, 0xd6, 0x00, 0x9b, 0x00, 0x75, +0x00, 0x2b, 0x00, 0x5b, 0x00, 0x7f, 0x00, 0x9b, 0x00, 0xae, 0x00, 0xb9, +0x00, 0xc2, 0x00, 0xc7, 0x00, 0xcc, 0x00, 0xcf, 0x00, 0xd1, 0x00, 0xd3, +0x00, 0xd5, 0x00, 0xd6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x11, 0x01, 0x07, 0x0f, 0x00, 0x32, 0x00, 0x6e, 0x00, 0x93, 0x00, 0xaa, +0x00, 0xb8, 0x00, 0xc1, 0x00, 0xc8, 0x00, 0xcc, 0x00, 0xd0, 0x00, 0xd2, +0x00, 0xd4, 0x00, 0xd6, 0x00, 0xd7, 0x00, 0xd8, 0x09, 0x03, 0x00, 0x1f, +0x00, 0x5f, 0x00, 0x8d, 0x00, 0xa8, 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xc9, +0x00, 0xce, 0x00, 0xd1, 0x00, 0xd4, 0x00, 0xd6, 0x00, 0xd7, 0x00, 0xd8, +0x00, 0xd9, 0x00, 0xda, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x02, 0x00, 0x3c, 0x00, 0x66, 0x00, 0x82, 0x00, 0x97, +0x00, 0xa5, 0x00, 0xb0, 0x00, 0xb8, 0x00, 0xbe, 0x00, 0xc3, 0x00, 0xc7, +0x00, 0xca, 0x00, 0xcd, 0x00, 0xac, 0x00, 0x96, 0x00, 0x5b, 0x00, 0x13, +0x00, 0x41, 0x00, 0x66, 0x00, 0x82, 0x00, 0x97, 0x00, 0xa5, 0x00, 0xb0, +0x00, 0xb8, 0x00, 0xbe, 0x00, 0xc3, 0x00, 0xc7, 0x00, 0xca, 0x00, 0xcd, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x0c, 0x02, +0x05, 0x19, 0x00, 0x31, 0x00, 0x5f, 0x00, 0x7f, 0x00, 0x96, 0x00, 0xa6, +0x00, 0xb2, 0x00, 0xba, 0x00, 0xc0, 0x00, 0xc5, 0x00, 0xc9, 0x00, 0xcc, +0x00, 0xce, 0x00, 0xd0, 0x13, 0x00, 0x01, 0x04, 0x00, 0x32, 0x00, 0x5f, +0x00, 0x81, 0x00, 0x99, 0x00, 0xaa, 0x00, 0xb6, 0x00, 0xbe, 0x00, 0xc4, +0x00, 0xc9, 0x00, 0xcc, 0x00, 0xcf, 0x00, 0xd1, 0x00, 0xd3, 0x00, 0xd4, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x01, 0x00, 0x2f, 0x00, 0x54, 0x00, 0x6f, 0x00, 0x84, 0x00, 0x93, +0x00, 0xa0, 0x00, 0xa9, 0x00, 0xb1, 0x00, 0xb7, 0x00, 0xbc, 0x00, 0xc0, +0x00, 0xbc, 0x00, 0xab, 0x00, 0x7f, 0x00, 0x41, 0x00, 0x03, 0x00, 0x2f, +0x00, 0x54, 0x00, 0x6f, 0x00, 0x84, 0x00, 0x93, 0x00, 0xa0, 0x00, 0xa9, +0x00, 0xb1, 0x00, 0xb7, 0x00, 0xbc, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x12, 0x00, 0x09, 0x0b, 0x04, 0x1e, +0x00, 0x30, 0x00, 0x55, 0x00, 0x71, 0x00, 0x87, 0x00, 0x97, 0x00, 0xa4, +0x00, 0xad, 0x00, 0xb5, 0x00, 0xbb, 0x00, 0xc0, 0x00, 0xc3, 0x00, 0xc7, +0x18, 0x00, 0x0a, 0x00, 0x00, 0x16, 0x00, 0x3d, 0x00, 0x5f, 0x00, 0x7a, +0x00, 0x8f, 0x00, 0x9f, 0x00, 0xab, 0x00, 0xb4, 0x00, 0xbb, 0x00, 0xc0, +0x00, 0xc4, 0x00, 0xc8, 0x00, 0xcb, 0x00, 0xcd, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +0x00, 0x27, 0x00, 0x47, 0x00, 0x60, 0x00, 0x74, 0x00, 0x84, 0x00, 0x91, +0x00, 0x9c, 0x00, 0xa4, 0x00, 0xab, 0x00, 0xb1, 0x00, 0xcd, 0x00, 0xc0, +0x00, 0x9b, 0x00, 0x66, 0x00, 0x2f, 0x00, 0x02, 0x00, 0x27, 0x00, 0x47, +0x00, 0x60, 0x00, 0x74, 0x00, 0x84, 0x00, 0x91, 0x00, 0x9c, 0x00, 0xa4, +0x00, 0xab, 0x00, 0xb1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x1c, 0x00, 0x17, 0x00, 0x0b, 0x03, 0x07, 0x12, 0x03, 0x22, 0x00, 0x30, +0x00, 0x4e, 0x00, 0x67, 0x00, 0x7b, 0x00, 0x8b, 0x00, 0x98, 0x00, 0xa2, +0x00, 0xaa, 0x00, 0xb1, 0x00, 0xb6, 0x00, 0xbb, 0x1a, 0x00, 0x11, 0x00, +0x00, 0x06, 0x00, 0x25, 0x00, 0x44, 0x00, 0x5f, 0x00, 0x76, 0x00, 0x88, +0x00, 0x96, 0x00, 0xa2, 0x00, 0xab, 0x00, 0xb2, 0x00, 0xb8, 0x00, 0xbd, +0x00, 0xc1, 0x00, 0xc5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, +0x00, 0x3d, 0x00, 0x55, 0x00, 0x68, 0x00, 0x78, 0x00, 0x85, 0x00, 0x90, +0x00, 0x99, 0x00, 0xa0, 0x00, 0xd9, 0x00, 0xcd, 0x00, 0xae, 0x00, 0x82, +0x00, 0x54, 0x00, 0x27, 0x00, 0x01, 0x00, 0x21, 0x00, 0x3d, 0x00, 0x55, +0x00, 0x68, 0x00, 0x78, 0x00, 0x85, 0x00, 0x90, 0x00, 0x99, 0x00, 0xa0, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x19, 0x00, +0x0e, 0x00, 0x09, 0x0a, 0x06, 0x17, 0x02, 0x24, 0x00, 0x30, 0x00, 0x4a, +0x00, 0x60, 0x00, 0x72, 0x00, 0x81, 0x00, 0x8e, 0x00, 0x98, 0x00, 0xa0, +0x00, 0xa8, 0x00, 0xae, 0x1c, 0x00, 0x15, 0x00, 0x03, 0x00, 0x00, 0x14, +0x00, 0x2f, 0x00, 0x49, 0x00, 0x5f, 0x00, 0x72, 0x00, 0x82, 0x00, 0x90, +0x00, 0x9b, 0x00, 0xa4, 0x00, 0xab, 0x00, 0xb1, 0x00, 0xb7, 0x00, 0xbb, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x36, +0x00, 0x4b, 0x00, 0x5d, 0x00, 0x6d, 0x00, 0x7a, 0x00, 0x85, 0x00, 0x8e, +0x00, 0xda, 0x00, 0xd2, 0x00, 0xb9, 0x00, 0x97, 0x00, 0x6f, 0x00, 0x47, +0x00, 0x21, 0x00, 0x01, 0x00, 0x1d, 0x00, 0x36, 0x00, 0x4b, 0x00, 0x5d, +0x00, 0x6d, 0x00, 0x7a, 0x00, 0x85, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x1b, 0x00, 0x12, 0x00, 0x0a, 0x04, +0x07, 0x0f, 0x05, 0x1b, 0x02, 0x26, 0x00, 0x30, 0x00, 0x46, 0x00, 0x5a, +0x00, 0x6b, 0x00, 0x79, 0x00, 0x85, 0x00, 0x8f, 0x00, 0x98, 0x00, 0xa0, +0x1d, 0x00, 0x18, 0x00, 0x0a, 0x00, 0x00, 0x09, 0x00, 0x1f, 0x00, 0x36, +0x00, 0x4c, 0x00, 0x5f, 0x00, 0x70, 0x00, 0x7e, 0x00, 0x8a, 0x00, 0x95, +0x00, 0x9e, 0x00, 0xa5, 0x00, 0xab, 0x00, 0xb1, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x00, 0x30, 0x00, 0x44, +0x00, 0x55, 0x00, 0x64, 0x00, 0x70, 0x00, 0x7b, 0x00, 0xdb, 0x00, 0xd4, +0x00, 0xc2, 0x00, 0xa5, 0x00, 0x84, 0x00, 0x60, 0x00, 0x3d, 0x00, 0x1d, +0x00, 0x00, 0x00, 0x19, 0x00, 0x30, 0x00, 0x44, 0x00, 0x55, 0x00, 0x64, +0x00, 0x70, 0x00, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x1e, 0x00, 0x1c, 0x00, 0x15, 0x00, 0x0b, 0x00, 0x09, 0x0a, 0x06, 0x14, +0x04, 0x1e, 0x02, 0x27, 0x00, 0x30, 0x00, 0x44, 0x00, 0x56, 0x00, 0x65, +0x00, 0x72, 0x00, 0x7e, 0x00, 0x88, 0x00, 0x91, 0x1d, 0x00, 0x1a, 0x00, +0x0f, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x28, 0x00, 0x3c, 0x00, 0x4e, +0x00, 0x5f, 0x00, 0x6e, 0x00, 0x7b, 0x00, 0x86, 0x00, 0x90, 0x00, 0x98, +0x00, 0xa0, 0x00, 0xa6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x2b, 0x00, 0x3e, 0x00, 0x4e, +0x00, 0x5c, 0x00, 0x68, 0x00, 0xdc, 0x00, 0xd7, 0x00, 0xc7, 0x00, 0xb0, +0x00, 0x93, 0x00, 0x74, 0x00, 0x55, 0x00, 0x36, 0x00, 0x19, 0x00, 0x00, +0x00, 0x17, 0x00, 0x2b, 0x00, 0x3e, 0x00, 0x4e, 0x00, 0x5c, 0x00, 0x68, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x1c, 0x00, +0x17, 0x00, 0x0f, 0x00, 0x0a, 0x05, 0x08, 0x0e, 0x06, 0x17, 0x03, 0x20, +0x01, 0x28, 0x00, 0x2f, 0x00, 0x42, 0x00, 0x52, 0x00, 0x60, 0x00, 0x6d, +0x00, 0x78, 0x00, 0x82, 0x1e, 0x00, 0x1b, 0x00, 0x12, 0x00, 0x05, 0x00, +0x00, 0x0b, 0x00, 0x1c, 0x00, 0x2f, 0x00, 0x40, 0x00, 0x50, 0x00, 0x5f, +0x00, 0x6c, 0x00, 0x78, 0x00, 0x83, 0x00, 0x8c, 0x00, 0x94, 0x00, 0x9b, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x15, 0x00, 0x28, 0x00, 0x39, 0x00, 0x48, 0x00, 0x55, +0x00, 0xdc, 0x00, 0xd8, 0x00, 0xcc, 0x00, 0xb8, 0x00, 0xa0, 0x00, 0x84, +0x00, 0x68, 0x00, 0x4b, 0x00, 0x30, 0x00, 0x17, 0x00, 0x00, 0x00, 0x15, +0x00, 0x28, 0x00, 0x39, 0x00, 0x48, 0x00, 0x55, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1d, 0x00, 0x19, 0x00, 0x12, 0x00, +0x0b, 0x02, 0x09, 0x09, 0x07, 0x12, 0x05, 0x1a, 0x03, 0x21, 0x01, 0x29, +0x00, 0x2f, 0x00, 0x40, 0x00, 0x4f, 0x00, 0x5c, 0x00, 0x68, 0x00, 0x73, +0x1e, 0x00, 0x1c, 0x00, 0x14, 0x00, 0x09, 0x00, 0x00, 0x04, 0x00, 0x13, +0x00, 0x24, 0x00, 0x34, 0x00, 0x43, 0x00, 0x52, 0x00, 0x5f, 0x00, 0x6b, +0x00, 0x76, 0x00, 0x80, 0x00, 0x88, 0x00, 0x90, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x13, 0x00, 0x24, 0x00, 0x34, 0x00, 0x42, 0x00, 0xdd, 0x00, 0xd9, +0x00, 0xcf, 0x00, 0xbe, 0x00, 0xa9, 0x00, 0x91, 0x00, 0x78, 0x00, 0x5d, +0x00, 0x44, 0x00, 0x2b, 0x00, 0x15, 0x00, 0x00, 0x00, 0x13, 0x00, 0x24, +0x00, 0x34, 0x00, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x1f, 0x00, 0x1d, 0x00, 0x1a, 0x00, 0x14, 0x00, 0x0c, 0x00, 0x0a, 0x06, +0x08, 0x0d, 0x06, 0x14, 0x04, 0x1c, 0x03, 0x23, 0x01, 0x29, 0x00, 0x2f, +0x00, 0x3e, 0x00, 0x4c, 0x00, 0x59, 0x00, 0x64, 0x1e, 0x00, 0x1c, 0x00, +0x16, 0x00, 0x0d, 0x00, 0x01, 0x00, 0x00, 0x0c, 0x00, 0x1b, 0x00, 0x29, +0x00, 0x38, 0x00, 0x46, 0x00, 0x53, 0x00, 0x5f, 0x00, 0x6a, 0x00, 0x74, +0x00, 0x7d, 0x00, 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, +0x00, 0x22, 0x00, 0x30, 0x00, 0xdd, 0x00, 0xda, 0x00, 0xd1, 0x00, 0xc3, +0x00, 0xb1, 0x00, 0x9c, 0x00, 0x85, 0x00, 0x6d, 0x00, 0x55, 0x00, 0x3e, +0x00, 0x28, 0x00, 0x13, 0x00, 0x00, 0x00, 0x11, 0x00, 0x22, 0x00, 0x30, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1e, 0x00, +0x1b, 0x00, 0x16, 0x00, 0x0f, 0x00, 0x0b, 0x03, 0x09, 0x09, 0x07, 0x10, +0x06, 0x17, 0x04, 0x1e, 0x02, 0x24, 0x01, 0x2a, 0x00, 0x2f, 0x00, 0x3d, +0x00, 0x4a, 0x00, 0x56, 0x1e, 0x00, 0x1d, 0x00, 0x18, 0x00, 0x10, 0x00, +0x05, 0x00, 0x00, 0x06, 0x00, 0x13, 0x00, 0x21, 0x00, 0x2e, 0x00, 0x3c, +0x00, 0x48, 0x00, 0x54, 0x00, 0x5f, 0x00, 0x69, 0x00, 0x73, 0x00, 0x7b, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x1f, +0x00, 0xdd, 0x00, 0xdb, 0x00, 0xd3, 0x00, 0xc7, 0x00, 0xb7, 0x00, 0xa4, +0x00, 0x90, 0x00, 0x7a, 0x00, 0x64, 0x00, 0x4e, 0x00, 0x39, 0x00, 0x24, +0x00, 0x11, 0x00, 0x00, 0x00, 0x10, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1e, 0x00, 0x1b, 0x00, 0x17, 0x00, +0x11, 0x00, 0x0b, 0x00, 0x0a, 0x06, 0x08, 0x0c, 0x07, 0x13, 0x05, 0x19, +0x04, 0x1f, 0x02, 0x25, 0x01, 0x2a, 0x00, 0x2f, 0x00, 0x3c, 0x00, 0x48, +0x1f, 0x00, 0x1d, 0x00, 0x19, 0x00, 0x12, 0x00, 0x09, 0x00, 0x00, 0x01, +0x00, 0x0d, 0x00, 0x19, 0x00, 0x26, 0x00, 0x32, 0x00, 0x3f, 0x00, 0x4a, +0x00, 0x55, 0x00, 0x5f, 0x00, 0x69, 0x00, 0x71, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0xdd, 0x00, 0xdb, +0x00, 0xd5, 0x00, 0xca, 0x00, 0xbc, 0x00, 0xab, 0x00, 0x99, 0x00, 0x85, +0x00, 0x70, 0x00, 0x5c, 0x00, 0x48, 0x00, 0x34, 0x00, 0x22, 0x00, 0x10, +0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x1f, 0x00, 0x1e, 0x00, 0x1c, 0x00, 0x18, 0x00, 0x13, 0x00, 0x0d, 0x00, +0x0a, 0x04, 0x09, 0x09, 0x08, 0x0f, 0x06, 0x15, 0x05, 0x1b, 0x03, 0x20, +0x02, 0x26, 0x01, 0x2b, 0x00, 0x2f, 0x00, 0x3b, 0x1f, 0x00, 0x1d, 0x00, +0x1a, 0x00, 0x14, 0x00, 0x0c, 0x00, 0x02, 0x00, 0x00, 0x08, 0x00, 0x13, +0x00, 0x1f, 0x00, 0x2a, 0x00, 0x36, 0x00, 0x41, 0x00, 0x4c, 0x00, 0x56, +0x00, 0x5f, 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0xde, 0x00, 0xdc, 0x00, 0xd6, 0x00, 0xcd, +0x00, 0xc0, 0x00, 0xb1, 0x00, 0xa0, 0x00, 0x8e, 0x00, 0x7b, 0x00, 0x68, +0x00, 0x55, 0x00, 0x42, 0x00, 0x30, 0x00, 0x1f, 0x00, 0x0f, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1e, 0x00, +0x1c, 0x00, 0x19, 0x00, 0x15, 0x00, 0x0f, 0x00, 0x0b, 0x01, 0x0a, 0x07, +0x08, 0x0c, 0x07, 0x11, 0x06, 0x17, 0x04, 0x1c, 0x03, 0x21, 0x02, 0x26, +0x01, 0x2b, 0x00, 0x2f, 0x1f, 0x00, 0x1e, 0x00, 0x1a, 0x00, 0x15, 0x00, +0x0e, 0x00, 0x05, 0x00, 0x00, 0x03, 0x00, 0x0e, 0x00, 0x18, 0x00, 0x23, +0x00, 0x2e, 0x00, 0x39, 0x00, 0x43, 0x00, 0x4d, 0x00, 0x56, 0x00, 0x5f, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x07, 0x00, 0x0f, 0x00, 0x19, 0x00, 0x1c, 0x00, 0x1e, 0x00, 0x1e, 0x00, +0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, +0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x04, 0x4c, 0x09, 0x11, +0x11, 0x01, 0x17, 0x00, 0x1b, 0x00, 0x1c, 0x00, 0x1d, 0x00, 0x1e, 0x00, +0x1e, 0x00, 0x1e, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, +0x1f, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x3e, 0x00, 0x2b, 0x00, 0x34, 0x00, 0x32, 0x00, 0x2c, 0x00, 0x24, 0x00, +0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, +0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x01, 0x61, 0x03, 0x23, +0x09, 0x03, 0x13, 0x00, 0x18, 0x00, 0x1a, 0x00, 0x1c, 0x00, 0x1d, 0x00, +0x1d, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x1f, 0x00, +0x1f, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, +0x0f, 0x00, 0x17, 0x00, 0x1a, 0x00, 0x1c, 0x00, 0x1d, 0x00, 0x1e, 0x00, +0x1e, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, +0x1f, 0x00, 0x1f, 0x00, 0x00, 0x87, 0x01, 0x39, 0x07, 0x0f, 0x0c, 0x02, +0x12, 0x00, 0x17, 0x00, 0x19, 0x00, 0x1b, 0x00, 0x1c, 0x00, 0x1c, 0x00, +0x1d, 0x00, 0x1d, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x1e, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x21, 0x00, +0x27, 0x00, 0x2b, 0x00, 0x28, 0x00, 0x21, 0x00, 0x1d, 0x00, 0x1e, 0x00, +0x1e, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, +0x1f, 0x00, 0x1f, 0x00, 0x00, 0x9f, 0x00, 0x5f, 0x00, 0x1f, 0x01, 0x04, +0x0a, 0x00, 0x11, 0x00, 0x15, 0x00, 0x18, 0x00, 0x1a, 0x00, 0x1b, 0x00, +0x1c, 0x00, 0x1c, 0x00, 0x1d, 0x00, 0x1d, 0x00, 0x1d, 0x00, 0x1e, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, +0x12, 0x00, 0x16, 0x00, 0x18, 0x00, 0x1a, 0x00, 0x1b, 0x00, 0x1c, 0x00, +0x1d, 0x00, 0x1d, 0x00, 0x1d, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x1e, 0x00, +0x00, 0xbc, 0x00, 0x87, 0x00, 0x32, 0x05, 0x19, 0x09, 0x0b, 0x0b, 0x03, +0x0e, 0x00, 0x12, 0x00, 0x15, 0x00, 0x17, 0x00, 0x19, 0x00, 0x1a, 0x00, +0x1b, 0x00, 0x1b, 0x00, 0x1c, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x27, 0x00, 0x0f, 0x00, 0x1a, 0x00, +0x1c, 0x00, 0x18, 0x00, 0x18, 0x00, 0x1a, 0x00, 0x1b, 0x00, 0x1c, 0x00, +0x1d, 0x00, 0x1d, 0x00, 0x1d, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x1e, 0x00, +0x00, 0xc5, 0x00, 0x9f, 0x00, 0x5f, 0x00, 0x32, 0x00, 0x16, 0x00, 0x06, +0x03, 0x00, 0x0a, 0x00, 0x0f, 0x00, 0x12, 0x00, 0x14, 0x00, 0x16, 0x00, +0x18, 0x00, 0x19, 0x00, 0x1a, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0e, 0x00, +0x12, 0x00, 0x15, 0x00, 0x17, 0x00, 0x19, 0x00, 0x1a, 0x00, 0x1b, 0x00, +0x1b, 0x00, 0x1c, 0x00, 0x1c, 0x00, 0x1d, 0x00, 0x00, 0xcd, 0x00, 0xaf, +0x00, 0x6e, 0x00, 0x31, 0x04, 0x1e, 0x07, 0x12, 0x09, 0x0a, 0x0a, 0x04, +0x0b, 0x00, 0x0f, 0x00, 0x12, 0x00, 0x14, 0x00, 0x16, 0x00, 0x17, 0x00, +0x18, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x32, 0x00, 0x2b, 0x00, 0x1a, 0x00, 0x06, 0x00, 0x0d, 0x00, 0x0e, 0x00, +0x12, 0x00, 0x15, 0x00, 0x17, 0x00, 0x19, 0x00, 0x1a, 0x00, 0x1b, 0x00, +0x1b, 0x00, 0x1c, 0x00, 0x1c, 0x00, 0x1d, 0x00, 0x00, 0xd2, 0x00, 0xbc, +0x00, 0x8d, 0x00, 0x5f, 0x00, 0x3d, 0x00, 0x25, 0x00, 0x14, 0x00, 0x09, +0x00, 0x00, 0x05, 0x00, 0x09, 0x00, 0x0d, 0x00, 0x10, 0x00, 0x12, 0x00, +0x14, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x0c, 0x00, 0x0f, 0x00, +0x12, 0x00, 0x15, 0x00, 0x16, 0x00, 0x18, 0x00, 0x19, 0x00, 0x1a, 0x00, +0x1a, 0x00, 0x1b, 0x00, 0x00, 0xd4, 0x00, 0xc1, 0x00, 0x93, 0x00, 0x5f, +0x00, 0x30, 0x03, 0x22, 0x06, 0x17, 0x07, 0x0f, 0x09, 0x0a, 0x0a, 0x05, +0x0b, 0x02, 0x0c, 0x00, 0x0f, 0x00, 0x11, 0x00, 0x13, 0x00, 0x15, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x28, 0x00, +0x1c, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x06, 0x00, 0x0c, 0x00, 0x0f, 0x00, +0x12, 0x00, 0x15, 0x00, 0x16, 0x00, 0x18, 0x00, 0x19, 0x00, 0x1a, 0x00, +0x1a, 0x00, 0x1b, 0x00, 0x00, 0xd7, 0x00, 0xc9, 0x00, 0xa8, 0x00, 0x81, +0x00, 0x5f, 0x00, 0x44, 0x00, 0x2f, 0x00, 0x1f, 0x00, 0x14, 0x00, 0x0b, +0x00, 0x04, 0x01, 0x00, 0x05, 0x00, 0x09, 0x00, 0x0c, 0x00, 0x0e, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x0a, 0x00, 0x0d, 0x00, 0x10, 0x00, +0x12, 0x00, 0x14, 0x00, 0x16, 0x00, 0x17, 0x00, 0x18, 0x00, 0x19, 0x00, +0x00, 0xd8, 0x00, 0xcb, 0x00, 0xaa, 0x00, 0x7f, 0x00, 0x55, 0x00, 0x30, +0x02, 0x24, 0x05, 0x1b, 0x06, 0x14, 0x08, 0x0e, 0x09, 0x09, 0x0a, 0x06, +0x0b, 0x03, 0x0b, 0x00, 0x0d, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x24, 0x00, 0x21, 0x00, 0x18, 0x00, 0x0e, 0x00, +0x06, 0x00, 0x00, 0x00, 0x05, 0x00, 0x0a, 0x00, 0x0d, 0x00, 0x10, 0x00, +0x12, 0x00, 0x14, 0x00, 0x16, 0x00, 0x17, 0x00, 0x18, 0x00, 0x19, 0x00, +0x00, 0xda, 0x00, 0xd0, 0x00, 0xb8, 0x00, 0x99, 0x00, 0x7a, 0x00, 0x5f, +0x00, 0x49, 0x00, 0x36, 0x00, 0x28, 0x00, 0x1c, 0x00, 0x13, 0x00, 0x0c, +0x00, 0x06, 0x00, 0x01, 0x02, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x0e, 0x00, 0x11, 0x00, +0x13, 0x00, 0x14, 0x00, 0x15, 0x00, 0x16, 0x00, 0x00, 0xda, 0x00, 0xd1, +0x00, 0xb8, 0x00, 0x96, 0x00, 0x71, 0x00, 0x4e, 0x00, 0x30, 0x02, 0x26, +0x04, 0x1e, 0x06, 0x17, 0x07, 0x12, 0x08, 0x0d, 0x09, 0x09, 0x0a, 0x06, +0x0a, 0x04, 0x0b, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x1f, 0x00, 0x1d, 0x00, 0x18, 0x00, 0x12, 0x00, 0x0c, 0x00, 0x05, 0x00, +0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x0e, 0x00, 0x11, 0x00, +0x13, 0x00, 0x14, 0x00, 0x15, 0x00, 0x16, 0x00, 0x00, 0xdb, 0x00, 0xd5, +0x00, 0xc3, 0x00, 0xaa, 0x00, 0x8f, 0x00, 0x76, 0x00, 0x5f, 0x00, 0x4c, +0x00, 0x3c, 0x00, 0x2f, 0x00, 0x24, 0x00, 0x1b, 0x00, 0x13, 0x00, 0x0d, +0x00, 0x08, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x04, 0x00, 0x07, 0x00, 0x0a, 0x00, 0x0d, 0x00, 0x0f, 0x00, 0x11, 0x00, +0x13, 0x00, 0x14, 0x00, 0x00, 0xdb, 0x00, 0xd4, 0x00, 0xc1, 0x00, 0xa6, +0x00, 0x87, 0x00, 0x67, 0x00, 0x4a, 0x00, 0x30, 0x02, 0x27, 0x03, 0x20, +0x05, 0x1a, 0x06, 0x14, 0x07, 0x10, 0x08, 0x0c, 0x09, 0x09, 0x0a, 0x07, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1e, 0x00, +0x1a, 0x00, 0x15, 0x00, 0x0f, 0x00, 0x0a, 0x00, 0x04, 0x00, 0x00, 0x00, +0x04, 0x00, 0x07, 0x00, 0x0a, 0x00, 0x0d, 0x00, 0x0f, 0x00, 0x11, 0x00, +0x13, 0x00, 0x14, 0x00, 0x00, 0xdc, 0x00, 0xd7, 0x00, 0xc9, 0x00, 0xb6, +0x00, 0x9f, 0x00, 0x88, 0x00, 0x72, 0x00, 0x5f, 0x00, 0x4e, 0x00, 0x40, +0x00, 0x34, 0x00, 0x29, 0x00, 0x21, 0x00, 0x19, 0x00, 0x13, 0x00, 0x0e, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, +0x06, 0x00, 0x09, 0x00, 0x0c, 0x00, 0x0e, 0x00, 0x10, 0x00, 0x11, 0x00, +0x00, 0xdc, 0x00, 0xd7, 0x00, 0xc8, 0x00, 0xb2, 0x00, 0x97, 0x00, 0x7b, +0x00, 0x60, 0x00, 0x46, 0x00, 0x30, 0x01, 0x28, 0x03, 0x21, 0x04, 0x1c, +0x06, 0x17, 0x07, 0x13, 0x08, 0x0f, 0x08, 0x0c, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1e, 0x00, 0x1b, 0x00, 0x17, 0x00, +0x12, 0x00, 0x0d, 0x00, 0x08, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, +0x06, 0x00, 0x09, 0x00, 0x0c, 0x00, 0x0e, 0x00, 0x10, 0x00, 0x11, 0x00, +0x00, 0xdd, 0x00, 0xd9, 0x00, 0xce, 0x00, 0xbe, 0x00, 0xab, 0x00, 0x96, +0x00, 0x82, 0x00, 0x70, 0x00, 0x5f, 0x00, 0x50, 0x00, 0x43, 0x00, 0x38, +0x00, 0x2e, 0x00, 0x26, 0x00, 0x1f, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x06, 0x00, +0x08, 0x00, 0x0b, 0x00, 0x0d, 0x00, 0x0e, 0x00, 0x00, 0xdc, 0x00, 0xd8, +0x00, 0xcc, 0x00, 0xba, 0x00, 0xa4, 0x00, 0x8b, 0x00, 0x72, 0x00, 0x5a, +0x00, 0x44, 0x00, 0x2f, 0x01, 0x29, 0x03, 0x23, 0x04, 0x1e, 0x05, 0x19, +0x06, 0x15, 0x07, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x1f, 0x00, 0x1e, 0x00, 0x1c, 0x00, 0x19, 0x00, 0x15, 0x00, 0x10, 0x00, +0x0c, 0x00, 0x07, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x06, 0x00, +0x08, 0x00, 0x0b, 0x00, 0x0d, 0x00, 0x0e, 0x00, 0x00, 0xdd, 0x00, 0xda, +0x00, 0xd1, 0x00, 0xc4, 0x00, 0xb4, 0x00, 0xa2, 0x00, 0x90, 0x00, 0x7e, +0x00, 0x6e, 0x00, 0x5f, 0x00, 0x52, 0x00, 0x46, 0x00, 0x3c, 0x00, 0x32, +0x00, 0x2a, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x05, 0x00, 0x08, 0x00, +0x0a, 0x00, 0x0c, 0x00, 0x00, 0xdd, 0x00, 0xd9, 0x00, 0xd0, 0x00, 0xc0, +0x00, 0xad, 0x00, 0x98, 0x00, 0x81, 0x00, 0x6b, 0x00, 0x56, 0x00, 0x42, +0x00, 0x2f, 0x01, 0x29, 0x02, 0x24, 0x04, 0x1f, 0x05, 0x1b, 0x06, 0x17, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1e, 0x00, +0x1d, 0x00, 0x1a, 0x00, 0x16, 0x00, 0x12, 0x00, 0x0e, 0x00, 0x0a, 0x00, +0x06, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x05, 0x00, 0x08, 0x00, +0x0a, 0x00, 0x0c, 0x00, 0x00, 0xdd, 0x00, 0xdb, 0x00, 0xd4, 0x00, 0xc9, +0x00, 0xbb, 0x00, 0xab, 0x00, 0x9b, 0x00, 0x8a, 0x00, 0x7b, 0x00, 0x6c, +0x00, 0x5f, 0x00, 0x53, 0x00, 0x48, 0x00, 0x3f, 0x00, 0x36, 0x00, 0x2e, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x05, 0x00, 0x07, 0x00, 0x09, 0x00, +0x00, 0xdd, 0x00, 0xda, 0x00, 0xd2, 0x00, 0xc5, 0x00, 0xb5, 0x00, 0xa2, +0x00, 0x8e, 0x00, 0x79, 0x00, 0x65, 0x00, 0x52, 0x00, 0x40, 0x00, 0x2f, +0x01, 0x2a, 0x02, 0x25, 0x03, 0x20, 0x04, 0x1c, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1d, 0x00, 0x1b, 0x00, +0x18, 0x00, 0x14, 0x00, 0x11, 0x00, 0x0d, 0x00, 0x09, 0x00, 0x06, 0x00, +0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x05, 0x00, 0x07, 0x00, 0x09, 0x00, +0x00, 0xde, 0x00, 0xdc, 0x00, 0xd6, 0x00, 0xcc, 0x00, 0xc0, 0x00, 0xb2, +0x00, 0xa4, 0x00, 0x95, 0x00, 0x86, 0x00, 0x78, 0x00, 0x6b, 0x00, 0x5f, +0x00, 0x54, 0x00, 0x4a, 0x00, 0x41, 0x00, 0x39, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x02, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0xdd, 0x00, 0xdb, +0x00, 0xd4, 0x00, 0xc9, 0x00, 0xbb, 0x00, 0xaa, 0x00, 0x98, 0x00, 0x85, +0x00, 0x72, 0x00, 0x60, 0x00, 0x4f, 0x00, 0x3e, 0x00, 0x2f, 0x01, 0x2a, +0x02, 0x26, 0x03, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x1f, 0x00, 0x1f, 0x00, 0x1d, 0x00, 0x1b, 0x00, 0x19, 0x00, 0x16, 0x00, +0x13, 0x00, 0x0f, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x05, 0x00, 0x02, 0x00, +0x00, 0x00, 0x02, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0xde, 0x00, 0xdc, +0x00, 0xd7, 0x00, 0xcf, 0x00, 0xc4, 0x00, 0xb8, 0x00, 0xab, 0x00, 0x9e, +0x00, 0x90, 0x00, 0x83, 0x00, 0x76, 0x00, 0x6a, 0x00, 0x5f, 0x00, 0x55, +0x00, 0x4c, 0x00, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x02, 0x00, 0x04, 0x00, 0x00, 0xde, 0x00, 0xdc, 0x00, 0xd6, 0x00, 0xcc, +0x00, 0xc0, 0x00, 0xb1, 0x00, 0xa0, 0x00, 0x8f, 0x00, 0x7e, 0x00, 0x6d, +0x00, 0x5c, 0x00, 0x4c, 0x00, 0x3d, 0x00, 0x2f, 0x01, 0x2b, 0x02, 0x26, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1f, 0x00, +0x1e, 0x00, 0x1c, 0x00, 0x1a, 0x00, 0x17, 0x00, 0x14, 0x00, 0x11, 0x00, +0x0e, 0x00, 0x0b, 0x00, 0x08, 0x00, 0x05, 0x00, 0x02, 0x00, 0x00, 0x00, +0x02, 0x00, 0x04, 0x00, 0x00, 0xde, 0x00, 0xdc, 0x00, 0xd8, 0x00, 0xd1, +0x00, 0xc8, 0x00, 0xbd, 0x00, 0xb1, 0x00, 0xa5, 0x00, 0x98, 0x00, 0x8c, +0x00, 0x80, 0x00, 0x74, 0x00, 0x69, 0x00, 0x5f, 0x00, 0x56, 0x00, 0x4d, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, +0x00, 0xde, 0x00, 0xdc, 0x00, 0xd7, 0x00, 0xce, 0x00, 0xc3, 0x00, 0xb6, +0x00, 0xa8, 0x00, 0x98, 0x00, 0x88, 0x00, 0x78, 0x00, 0x68, 0x00, 0x59, +0x00, 0x4a, 0x00, 0x3c, 0x00, 0x2f, 0x01, 0x2b, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1e, 0x00, 0x1c, 0x00, +0x1a, 0x00, 0x18, 0x00, 0x15, 0x00, 0x13, 0x00, 0x10, 0x00, 0x0d, 0x00, +0x0a, 0x00, 0x07, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, +0x00, 0xde, 0x00, 0xdd, 0x00, 0xd9, 0x00, 0xd3, 0x00, 0xcb, 0x00, 0xc1, +0x00, 0xb7, 0x00, 0xab, 0x00, 0xa0, 0x00, 0x94, 0x00, 0x88, 0x00, 0x7d, +0x00, 0x73, 0x00, 0x69, 0x00, 0x5f, 0x00, 0x56, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xde, 0x00, 0xdc, +0x00, 0xd8, 0x00, 0xd0, 0x00, 0xc7, 0x00, 0xbb, 0x00, 0xae, 0x00, 0xa0, +0x00, 0x91, 0x00, 0x82, 0x00, 0x73, 0x00, 0x64, 0x00, 0x56, 0x00, 0x48, +0x00, 0x3b, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x1f, 0x00, 0x1f, 0x00, 0x1e, 0x00, 0x1d, 0x00, 0x1b, 0x00, 0x19, 0x00, +0x16, 0x00, 0x14, 0x00, 0x11, 0x00, 0x0e, 0x00, 0x0c, 0x00, 0x09, 0x00, +0x06, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0xde, 0x00, 0xdd, +0x00, 0xda, 0x00, 0xd4, 0x00, 0xcd, 0x00, 0xc5, 0x00, 0xbb, 0x00, 0xb1, +0x00, 0xa6, 0x00, 0x9b, 0x00, 0x90, 0x00, 0x85, 0x00, 0x7b, 0x00, 0x71, +0x00, 0x68, 0x00, 0x5f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x01, 0x61, 0x03, 0x23, 0x09, 0x03, 0x13, 0x00, +0x18, 0x00, 0x1a, 0x00, 0x1c, 0x00, 0x1d, 0x00, 0x1d, 0x00, 0x1e, 0x00, +0x1e, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x1f, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x61, 0x00, 0x9f, +0x00, 0xc5, 0x00, 0xd2, 0x00, 0xd7, 0x00, 0xda, 0x00, 0xdb, 0x00, 0xdc, +0x00, 0xdd, 0x00, 0xdd, 0x00, 0xdd, 0x00, 0xde, 0x00, 0xde, 0x00, 0xde, +0x00, 0xde, 0x00, 0xde, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x9f, 0x00, 0x5f, 0x00, 0x1f, 0x01, 0x04, 0x0a, 0x00, 0x11, 0x00, +0x15, 0x00, 0x18, 0x00, 0x1a, 0x00, 0x1b, 0x00, 0x1c, 0x00, 0x1c, 0x00, +0x1d, 0x00, 0x1d, 0x00, 0x1d, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x03, 0x23, 0x00, 0x5f, 0x00, 0x9f, 0x00, 0xbc, +0x00, 0xc9, 0x00, 0xd0, 0x00, 0xd5, 0x00, 0xd7, 0x00, 0xd9, 0x00, 0xda, +0x00, 0xdb, 0x00, 0xdc, 0x00, 0xdc, 0x00, 0xdc, 0x00, 0xdd, 0x00, 0xdd, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc5, 0x00, 0x9f, +0x00, 0x5f, 0x00, 0x32, 0x00, 0x16, 0x00, 0x06, 0x03, 0x00, 0x0a, 0x00, +0x0f, 0x00, 0x12, 0x00, 0x14, 0x00, 0x16, 0x00, 0x18, 0x00, 0x19, 0x00, +0x1a, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x09, 0x03, 0x00, 0x1f, 0x00, 0x5f, 0x00, 0x8d, 0x00, 0xa8, 0x00, 0xb8, +0x00, 0xc3, 0x00, 0xc9, 0x00, 0xce, 0x00, 0xd1, 0x00, 0xd4, 0x00, 0xd6, +0x00, 0xd7, 0x00, 0xd8, 0x00, 0xd9, 0x00, 0xda, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0xd2, 0x00, 0xbc, 0x00, 0x8d, 0x00, 0x5f, +0x00, 0x3d, 0x00, 0x25, 0x00, 0x14, 0x00, 0x09, 0x00, 0x00, 0x05, 0x00, +0x09, 0x00, 0x0d, 0x00, 0x10, 0x00, 0x12, 0x00, 0x14, 0x00, 0x15, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x01, 0x04, +0x00, 0x32, 0x00, 0x5f, 0x00, 0x81, 0x00, 0x99, 0x00, 0xaa, 0x00, 0xb6, +0x00, 0xbe, 0x00, 0xc4, 0x00, 0xc9, 0x00, 0xcc, 0x00, 0xcf, 0x00, 0xd1, +0x00, 0xd3, 0x00, 0xd4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0xd7, 0x00, 0xc9, 0x00, 0xa8, 0x00, 0x81, 0x00, 0x5f, 0x00, 0x44, +0x00, 0x2f, 0x00, 0x1f, 0x00, 0x14, 0x00, 0x0b, 0x00, 0x04, 0x01, 0x00, +0x05, 0x00, 0x09, 0x00, 0x0c, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x0a, 0x00, 0x00, 0x16, 0x00, 0x3d, +0x00, 0x5f, 0x00, 0x7a, 0x00, 0x8f, 0x00, 0x9f, 0x00, 0xab, 0x00, 0xb4, +0x00, 0xbb, 0x00, 0xc0, 0x00, 0xc4, 0x00, 0xc8, 0x00, 0xcb, 0x00, 0xcd, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xda, 0x00, 0xd0, +0x00, 0xb8, 0x00, 0x99, 0x00, 0x7a, 0x00, 0x5f, 0x00, 0x49, 0x00, 0x36, +0x00, 0x28, 0x00, 0x1c, 0x00, 0x13, 0x00, 0x0c, 0x00, 0x06, 0x00, 0x01, +0x02, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x1a, 0x00, 0x11, 0x00, 0x00, 0x06, 0x00, 0x25, 0x00, 0x44, 0x00, 0x5f, +0x00, 0x76, 0x00, 0x88, 0x00, 0x96, 0x00, 0xa2, 0x00, 0xab, 0x00, 0xb2, +0x00, 0xb8, 0x00, 0xbd, 0x00, 0xc1, 0x00, 0xc5, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0xdb, 0x00, 0xd5, 0x00, 0xc3, 0x00, 0xaa, +0x00, 0x8f, 0x00, 0x76, 0x00, 0x5f, 0x00, 0x4c, 0x00, 0x3c, 0x00, 0x2f, +0x00, 0x24, 0x00, 0x1b, 0x00, 0x13, 0x00, 0x0d, 0x00, 0x08, 0x00, 0x03, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x15, 0x00, +0x03, 0x00, 0x00, 0x14, 0x00, 0x2f, 0x00, 0x49, 0x00, 0x5f, 0x00, 0x72, +0x00, 0x82, 0x00, 0x90, 0x00, 0x9b, 0x00, 0xa4, 0x00, 0xab, 0x00, 0xb1, +0x00, 0xb7, 0x00, 0xbb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0xdc, 0x00, 0xd7, 0x00, 0xc9, 0x00, 0xb6, 0x00, 0x9f, 0x00, 0x88, +0x00, 0x72, 0x00, 0x5f, 0x00, 0x4e, 0x00, 0x40, 0x00, 0x34, 0x00, 0x29, +0x00, 0x21, 0x00, 0x19, 0x00, 0x13, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x18, 0x00, 0x0a, 0x00, 0x00, 0x09, +0x00, 0x1f, 0x00, 0x36, 0x00, 0x4c, 0x00, 0x5f, 0x00, 0x70, 0x00, 0x7e, +0x00, 0x8a, 0x00, 0x95, 0x00, 0x9e, 0x00, 0xa5, 0x00, 0xab, 0x00, 0xb1, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdd, 0x00, 0xd9, +0x00, 0xce, 0x00, 0xbe, 0x00, 0xab, 0x00, 0x96, 0x00, 0x82, 0x00, 0x70, +0x00, 0x5f, 0x00, 0x50, 0x00, 0x43, 0x00, 0x38, 0x00, 0x2e, 0x00, 0x26, +0x00, 0x1f, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x1d, 0x00, 0x1a, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x28, +0x00, 0x3c, 0x00, 0x4e, 0x00, 0x5f, 0x00, 0x6e, 0x00, 0x7b, 0x00, 0x86, +0x00, 0x90, 0x00, 0x98, 0x00, 0xa0, 0x00, 0xa6, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0xdd, 0x00, 0xda, 0x00, 0xd1, 0x00, 0xc4, +0x00, 0xb4, 0x00, 0xa2, 0x00, 0x90, 0x00, 0x7e, 0x00, 0x6e, 0x00, 0x5f, +0x00, 0x52, 0x00, 0x46, 0x00, 0x3c, 0x00, 0x32, 0x00, 0x2a, 0x00, 0x23, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x1b, 0x00, +0x12, 0x00, 0x05, 0x00, 0x00, 0x0b, 0x00, 0x1c, 0x00, 0x2f, 0x00, 0x40, +0x00, 0x50, 0x00, 0x5f, 0x00, 0x6c, 0x00, 0x78, 0x00, 0x83, 0x00, 0x8c, +0x00, 0x94, 0x00, 0x9b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0xdd, 0x00, 0xdb, 0x00, 0xd4, 0x00, 0xc9, 0x00, 0xbb, 0x00, 0xab, +0x00, 0x9b, 0x00, 0x8a, 0x00, 0x7b, 0x00, 0x6c, 0x00, 0x5f, 0x00, 0x53, +0x00, 0x48, 0x00, 0x3f, 0x00, 0x36, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x1c, 0x00, 0x14, 0x00, 0x09, 0x00, +0x00, 0x04, 0x00, 0x13, 0x00, 0x24, 0x00, 0x34, 0x00, 0x43, 0x00, 0x52, +0x00, 0x5f, 0x00, 0x6b, 0x00, 0x76, 0x00, 0x80, 0x00, 0x88, 0x00, 0x90, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xde, 0x00, 0xdc, +0x00, 0xd6, 0x00, 0xcc, 0x00, 0xc0, 0x00, 0xb2, 0x00, 0xa4, 0x00, 0x95, +0x00, 0x86, 0x00, 0x78, 0x00, 0x6b, 0x00, 0x5f, 0x00, 0x54, 0x00, 0x4a, +0x00, 0x41, 0x00, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x1e, 0x00, 0x1c, 0x00, 0x16, 0x00, 0x0d, 0x00, 0x01, 0x00, 0x00, 0x0c, +0x00, 0x1b, 0x00, 0x29, 0x00, 0x38, 0x00, 0x46, 0x00, 0x53, 0x00, 0x5f, +0x00, 0x6a, 0x00, 0x74, 0x00, 0x7d, 0x00, 0x85, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0xde, 0x00, 0xdc, 0x00, 0xd7, 0x00, 0xcf, +0x00, 0xc4, 0x00, 0xb8, 0x00, 0xab, 0x00, 0x9e, 0x00, 0x90, 0x00, 0x83, +0x00, 0x76, 0x00, 0x6a, 0x00, 0x5f, 0x00, 0x55, 0x00, 0x4c, 0x00, 0x43, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x1d, 0x00, +0x18, 0x00, 0x10, 0x00, 0x05, 0x00, 0x00, 0x06, 0x00, 0x13, 0x00, 0x21, +0x00, 0x2e, 0x00, 0x3c, 0x00, 0x48, 0x00, 0x54, 0x00, 0x5f, 0x00, 0x69, +0x00, 0x73, 0x00, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0xde, 0x00, 0xdc, 0x00, 0xd8, 0x00, 0xd1, 0x00, 0xc8, 0x00, 0xbd, +0x00, 0xb1, 0x00, 0xa5, 0x00, 0x98, 0x00, 0x8c, 0x00, 0x80, 0x00, 0x74, +0x00, 0x69, 0x00, 0x5f, 0x00, 0x56, 0x00, 0x4d, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1d, 0x00, 0x19, 0x00, 0x12, 0x00, +0x09, 0x00, 0x00, 0x01, 0x00, 0x0d, 0x00, 0x19, 0x00, 0x26, 0x00, 0x32, +0x00, 0x3f, 0x00, 0x4a, 0x00, 0x55, 0x00, 0x5f, 0x00, 0x69, 0x00, 0x71, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xde, 0x00, 0xdd, +0x00, 0xd9, 0x00, 0xd3, 0x00, 0xcb, 0x00, 0xc1, 0x00, 0xb7, 0x00, 0xab, +0x00, 0xa0, 0x00, 0x94, 0x00, 0x88, 0x00, 0x7d, 0x00, 0x73, 0x00, 0x69, +0x00, 0x5f, 0x00, 0x56, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x1f, 0x00, 0x1d, 0x00, 0x1a, 0x00, 0x14, 0x00, 0x0c, 0x00, 0x02, 0x00, +0x00, 0x08, 0x00, 0x13, 0x00, 0x1f, 0x00, 0x2a, 0x00, 0x36, 0x00, 0x41, +0x00, 0x4c, 0x00, 0x56, 0x00, 0x5f, 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0xde, 0x00, 0xdd, 0x00, 0xda, 0x00, 0xd4, +0x00, 0xcd, 0x00, 0xc5, 0x00, 0xbb, 0x00, 0xb1, 0x00, 0xa6, 0x00, 0x9b, +0x00, 0x90, 0x00, 0x85, 0x00, 0x7b, 0x00, 0x71, 0x00, 0x68, 0x00, 0x5f, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x1e, 0x00, +0x1a, 0x00, 0x15, 0x00, 0x0e, 0x00, 0x05, 0x00, 0x00, 0x03, 0x00, 0x0e, +0x00, 0x18, 0x00, 0x23, 0x00, 0x2e, 0x00, 0x39, 0x00, 0x43, 0x00, 0x4d, +0x00, 0x56, 0x00, 0x5f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00 +}; + +#endif diff --git a/extern/smaa/include/SearchTex.h b/extern/smaa/include/SearchTex.h new file mode 100644 index 0000000..56e8516 --- /dev/null +++ b/extern/smaa/include/SearchTex.h @@ -0,0 +1,132 @@ +/** + * Copyright (C) 2013 Jorge Jimenez (jorge@iryoku.com) + * Copyright (C) 2013 Jose I. Echevarria (joseignacioechevarria@gmail.com) + * Copyright (C) 2013 Belen Masia (bmasia@unizar.es) + * Copyright (C) 2013 Fernando Navarro (fernandn@microsoft.com) + * Copyright (C) 2013 Diego Gutierrez (diegog@unizar.es) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to + * do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. As clarification, there + * is no requirement that the copyright notice and permission be included in + * binary distributions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + + +#ifndef SEARCHTEX_H +#define SEARCHTEX_H + +#define SEARCHTEX_WIDTH 64 +#define SEARCHTEX_HEIGHT 16 +#define SEARCHTEX_PITCH SEARCHTEX_WIDTH +#define SEARCHTEX_SIZE (SEARCHTEX_HEIGHT * SEARCHTEX_PITCH) + +/** + * Stored in R8 format. Load it in the following format: + * - DX9: D3DFMT_L8 + * - DX10: DXGI_FORMAT_R8_UNORM + */ +static const unsigned char searchTexBytes[] = { + 0xfe, 0xfe, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0xfe, 0xfe, 0x00, 0x7f, 0x7f, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x00, + 0x7f, 0x7f, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x7f, 0x7f, 0xfe, 0x7f, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0xfe, + 0xfe, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x7f, 0x7f, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x7f, + 0x7f, 0xfe, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xfe, 0xfe, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0xfe, 0xfe, 0x00, 0x7f, 0x7f, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x00, + 0x7f, 0x7f, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x7f, 0x7f, 0xfe, 0x7f, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0xfe, + 0xfe, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x7f, 0x7f, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x7f, + 0x7f, 0xfe, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x7f, + 0x7f, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x7f, 0x7f, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x7f, + 0x7f, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x7f, + 0x7f, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x7f, 0x7f, 0x00, 0x00, + 0x7f, 0x7f, 0x00, 0x7f, 0x7f, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x7f, + 0x7f, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x7f, 0x7f, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x7f, + 0x7f, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x7f, + 0x7f, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x7f, 0x7f, 0x00, 0x00, + 0x7f, 0x7f, 0x00, 0x7f, 0x7f, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, +}; + +#endif diff --git a/extern/sol/CMakeLists.txt b/extern/sol/CMakeLists.txt new file mode 100755 index 0000000..2848cf0 --- /dev/null +++ b/extern/sol/CMakeLists.txt @@ -0,0 +1,15 @@ +if(TARGET liblua_static) + set(LUA_LIBRARY liblua_static) + set(LUA_INCLUDE_DIR ${CMAKE_BINARY_DIR}/_deps/lua-build/include) +else() + find_package(LuaJIT REQUIRED) +endif() + +add_library(sol INTERFACE) +target_include_directories(sol SYSTEM INTERFACE include ${LUA_INCLUDE_DIR}) +target_link_libraries(sol INTERFACE ${LUA_LIBRARY}) +target_compile_definitions(sol INTERFACE SOL_ALL_SAFETIES_ON SOL_EXCEPTIONS_SAFE_PROPAGATION) + +if(ENABLE_IOS OR ENABLE_TVOS) +target_compile_definitions(sol INTERFACE LUA_USE_APPLE) +endif() \ No newline at end of file diff --git a/extern/sol/include/sol.hpp b/extern/sol/include/sol.hpp new file mode 100644 index 0000000..de97281 --- /dev/null +++ b/extern/sol/include/sol.hpp @@ -0,0 +1,25838 @@ +// The MIT License (MIT) + +// Copyright (c) 2013-2020 Rapptz, ThePhD and contributors + +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +// This file was generated with a script. +// Generated 2020-05-22 13:37:38.805887 UTC +// This header was generated with sol v3.2.0 (revision d9c034d) +// https://github.com/ThePhD/sol2 + +#ifndef SOL_SINGLE_INCLUDE_HPP +#define SOL_SINGLE_INCLUDE_HPP + +// beginning of sol/sol.hpp + +#ifndef SOL_HPP +#define SOL_HPP + +#if defined(UE_BUILD_DEBUG) || defined(UE_BUILD_DEVELOPMENT) || defined(UE_BUILD_TEST) || defined(UE_BUILD_SHIPPING) || defined(UE_SERVER) +#define SOL_INSIDE_UNREAL +#ifdef check +#pragma push_macro("check") +#undef check +#endif +#endif // Unreal Engine 4 Bullshit + +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wshadow" +#pragma GCC diagnostic ignored "-Wconversion" +#if __GNUC__ > 6 +#pragma GCC diagnostic ignored "-Wnoexcept-type" +#endif +#elif defined(__clang__) +#elif defined _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4505) // unreferenced local function has been removed GEE THANKS +#endif // clang++ vs. g++ vs. VC++ + +// beginning of sol/forward.hpp + +#ifndef SOL_FORWARD_HPP +#define SOL_FORWARD_HPP + +// beginning of sol/feature_test.hpp + +#if (defined(__cplusplus) && __cplusplus >= 201703L) \ + || (defined(_MSC_VER) && _MSC_VER > 1900 && ((defined(_HAS_CXX17) && _HAS_CXX17 == 1) || (defined(_MSVC_LANG) && (_MSVC_LANG > 201402L)))) +#endif // C++17 features check + +#if defined(__cpp_noexcept_function_type) || ((defined(_MSC_VER) && _MSC_VER > 1911) && (defined(_MSVC_LANG) && ((_MSVC_LANG >= 201403L)))) +#ifndef SOL_NOEXCEPT_FUNCTION_TYPE +#define SOL_NOEXCEPT_FUNCTION_TYPE 1 +#endif // noexcept is part of a function's type +#endif // compiler-specific checks +#if defined(__clang__) && defined(__APPLE__) +#if defined(__has_include) +#if __has_include() +#define SOL_STD_VARIANT 1 +#endif // has include nonsense +#endif // __has_include +#else +#define SOL_STD_VARIANT 1 +#endif // Clang screws up variant + +// beginning of sol/config.hpp + +#ifdef _MSC_VER +#if defined(_DEBUG) && !defined(NDEBUG) +#ifndef SOL_IN_DEBUG_DETECTED +#define SOL_IN_DEBUG_DETECTED 1 +#endif +#endif // VC++ Debug macros + +#if !defined(_CPPUNWIND) +#if !defined(SOL_NO_EXCEPTIONS) +#define SOL_NO_EXCEPTIONS 1 +#endif +#endif // Automatic Exceptions + +#if !defined(_CPPRTTI) +#if !defined(SOL_NO_RTTI) +#define SOL_NO_RTTI 1 +#endif +#endif // Automatic RTTI +#elif defined(__GNUC__) || defined(__clang__) + +#if !defined(NDEBUG) && !defined(__OPTIMIZE__) +#if !defined(SOL_IN_DEBUG_DETECTED) +#define SOL_IN_DEBUG_DETECTED 1 +#endif +#endif // Not Debug && g++ optimizer flag + +#if !defined(__EXCEPTIONS) +#if !defined(SOL_NO_EXCEPTIONS) +#define SOL_NO_EXCEPTIONS 1 +#endif +#endif // No Exceptions + +#if !defined(__GXX_RTTI) +#if !defined(SOL_NO_RTTI) +#define SOL_NO_RTTI 1 +#endif +#endif // No RTTI + +#endif // vc++ || clang++/g++ + +#if defined(SOL_CHECK_ARGUMENTS) && SOL_CHECK_ARGUMENTS != 0 +#if defined(SOL_ALL_SAFETIES_ON) +#define SOL_ALL_SAFETIES_ON 1 +#endif // turn all the safeties on +#endif // Compatibility Define for Safety + +#if defined(SOL_ALL_SAFETIES_ON) && SOL_ALL_SAFETIES_ON != 0 + +#if !defined(SOL_SAFE_GETTER) +#define SOL_SAFE_GETTER 1 +#endif + +#if !defined(SOL_SAFE_USERTYPE) +#define SOL_SAFE_USERTYPE 1 +#endif + +#if !defined(SOL_SAFE_REFERENCES) +#define SOL_SAFE_REFERENCES 1 +#endif + +#if !defined(SOL_SAFE_FUNCTION) +#define SOL_SAFE_FUNCTION 1 +#endif + +#if !defined(SOL_SAFE_FUNCTION_CALLS) +#define SOL_SAFE_FUNCTION_CALLS 1 +#endif + +#if !defined(SOL_SAFE_PROXIES) +#define SOL_SAFE_PROXIES 1 +#endif + +#if !defined(SOL_SAFE_NUMERICS) +#define SOL_SAFE_NUMERICS 1 +#endif + +#if !defined(SOL_NO_CHECK_NUMBER_PRECISION) +#define SOL_NO_CHECK_NUMBER_PRECISION 0 +#endif + +#if !defined(SOL_SAFE_STACK_CHECK) +#define SOL_SAFE_STACK_CHECK 1 +#endif + +#endif // Turn on Safety for all if top-level macro is defined + +#if defined(SOL_IN_DEBUG_DETECTED) && SOL_IN_DEBUG_DETECTED != 0 + +#if !defined(SOL_SAFE_REFERENCES) +#define SOL_SAFE_REFERENCES 1 +#endif + +#if !defined(SOL_SAFE_USERTYPE) +#define SOL_SAFE_USERTYPE 1 +#endif + +#if !defined(SOL_SAFE_FUNCTION_CALLS) +#define SOL_SAFE_FUNCTION_CALLS 1 +#endif + +#if !defined(SOL_PRINT_ERRORS) +#define SOL_PRINT_ERRORS 1 +#endif + +#if !defined(SOL_SAFE_STACK_CHECK) +#define SOL_SAFE_STACK_CHECK 1 +#endif + +#endif // DEBUG: Turn on all debug safety features for VC++ / g++ / clang++ and similar + +#if !defined(SOL_PRINT_ERRORS) +#define SOL_PRINT_ERRORS 0 +#endif + +#if !defined(SOL_DEFAULT_PASS_ON_ERROR) +#define SOL_DEFAULT_PASS_ON_ERROR 0 +#endif + +#if !defined(SOL_ENABLE_INTEROP) +#define SOL_ENABLE_INTEROP 0 +#endif + +#if defined(__MAC_OS_X_VERSION_MAX_ALLOWED) || defined(__OBJC__) || defined(nil) +#if !defined(SOL_NO_NIL) +#define SOL_NO_NIL 1 +#endif +#endif // avoiding nil defines / keywords + +#ifndef SOL_STACK_STRING_OPTIMIZATION_SIZE +#define SOL_STACK_STRING_OPTIMIZATION_SIZE 1024 +#endif // Optimized conversion routines using a KB or so off the stack + +#if !defined(SOL_SAFE_STACK_CHECK) +#define SOL_SAFE_STACK_CHECK 0 +#endif // use luaL_checkstack to check stack overflow / overrun + +#if !defined(SOL_AUTOMAGICAL_TYPES_BY_DEFAULT) +#define SOL_AUTOMAGICAL_TYPES_BY_DEFAULT 1 +#endif // make is_automagical on/off by default + +// end of sol/config.hpp + +// beginning of sol/config_setup.hpp + +// end of sol/config_setup.hpp + +// end of sol/feature_test.hpp + +#include +#include +#include + +#if defined(SOL_USING_CXX_LUA) && SOL_USING_CXX_LUA +struct lua_State; +#else +extern "C" { +struct lua_State; +} +#endif // C++ Mangling for Lua vs. Not + +namespace sol { + + enum class type; + + class stateless_reference; + template + class basic_reference; + using reference = basic_reference; + using main_reference = basic_reference; + class stateless_stack_reference; + class stack_reference; + + template + class basic_bytecode; + + struct lua_value; + + struct proxy_base_tag; + template + struct proxy_base; + template + struct table_proxy; + + template + class basic_table_core; + template + using table_core = basic_table_core; + template + using main_table_core = basic_table_core; + template + using stack_table_core = basic_table_core; + template + using basic_table = basic_table_core; + using table = table_core; + using global_table = table_core; + using main_table = main_table_core; + using main_global_table = main_table_core; + using stack_table = stack_table_core; + using stack_global_table = stack_table_core; + + template + struct basic_lua_table; + using lua_table = basic_lua_table; + using stack_lua_table = basic_lua_table; + + template + class basic_usertype; + template + using usertype = basic_usertype; + template + using stack_usertype = basic_usertype; + + template + class basic_metatable; + using metatable = basic_metatable; + using stack_metatable = basic_metatable; + + template + struct basic_environment; + using environment = basic_environment; + using main_environment = basic_environment; + using stack_environment = basic_environment; + + template + class basic_function; + template + class basic_protected_function; + using unsafe_function = basic_function; + using safe_function = basic_protected_function; + using main_unsafe_function = basic_function; + using main_safe_function = basic_protected_function; + using stack_unsafe_function = basic_function; + using stack_safe_function = basic_protected_function; + using stack_aligned_unsafe_function = basic_function; + using stack_aligned_safe_function = basic_protected_function; + using protected_function = safe_function; + using main_protected_function = main_safe_function; + using stack_protected_function = stack_safe_function; + using stack_aligned_protected_function = stack_aligned_safe_function; +#if defined(SOL_SAFE_FUNCTION) && SOL_SAFE_FUNCTION + using function = protected_function; + using main_function = main_protected_function; + using stack_function = stack_protected_function; + using stack_aligned_function = stack_aligned_safe_function; +#else + using function = unsafe_function; + using main_function = main_unsafe_function; + using stack_function = stack_unsafe_function; + using stack_aligned_function = stack_aligned_unsafe_function; +#endif + using stack_aligned_stack_handler_function = basic_protected_function; + + struct unsafe_function_result; + struct protected_function_result; + using safe_function_result = protected_function_result; +#if defined(SOL_SAFE_FUNCTION) && SOL_SAFE_FUNCTION + using function_result = safe_function_result; +#else + using function_result = unsafe_function_result; +#endif + + template + class basic_object_base; + template + class basic_object; + template + class basic_userdata; + template + class basic_lightuserdata; + template + class basic_coroutine; + template + class basic_thread; + + using object = basic_object; + using userdata = basic_userdata; + using lightuserdata = basic_lightuserdata; + using thread = basic_thread; + using coroutine = basic_coroutine; + using main_object = basic_object; + using main_userdata = basic_userdata; + using main_lightuserdata = basic_lightuserdata; + using main_coroutine = basic_coroutine; + using stack_object = basic_object; + using stack_userdata = basic_userdata; + using stack_lightuserdata = basic_lightuserdata; + using stack_thread = basic_thread; + using stack_coroutine = basic_coroutine; + + struct stack_proxy_base; + struct stack_proxy; + struct variadic_args; + struct variadic_results; + struct stack_count; + struct this_state; + struct this_main_state; + struct this_environment; + + class state_view; + class state; + + template + struct as_table_t; + template + struct as_container_t; + template + struct nested; + template + struct light; + template + struct user; + template + struct as_args_t; + template + struct protect_t; + template + struct policy_wrapper; + + template + struct usertype_traits; + template + struct unique_usertype_traits; + + template + struct types { + typedef std::make_index_sequence indices; + static constexpr std::size_t size() { + return sizeof...(Args); + } + }; + + template + struct derive : std::false_type { + typedef types<> type; + }; + + template + struct base : std::false_type { + typedef types<> type; + }; + + template + struct weak_derive { + static bool value; + }; + + template + bool weak_derive::value = false; + + namespace stack { + struct record; + } + +#if !defined(SOL_USE_BOOST) || (SOL_USE_BOOST == 0) + template + class optional; + + template + class optional; +#endif + + using check_handler_type = int(lua_State*, int, type, type, const char*); + +} // namespace sol + +#define SOL_BASE_CLASSES(T, ...) \ + namespace sol { \ + template <> \ + struct base : std::true_type { \ + typedef ::sol::types<__VA_ARGS__> type; \ + }; \ + } \ + void a_sol3_detail_function_decl_please_no_collide() +#define SOL_DERIVED_CLASSES(T, ...) \ + namespace sol { \ + template <> \ + struct derive : std::true_type { \ + typedef ::sol::types<__VA_ARGS__> type; \ + }; \ + } \ + void a_sol3_detail_function_decl_please_no_collide() + +#endif // SOL_FORWARD_HPP +// end of sol/forward.hpp + +// beginning of sol/forward_detail.hpp + +#ifndef SOL_FORWARD_DETAIL_HPP +#define SOL_FORWARD_DETAIL_HPP + +// beginning of sol/traits.hpp + +// beginning of sol/tuple.hpp + +// beginning of sol/base_traits.hpp + +namespace sol { + namespace detail { + struct unchecked_t {}; + const unchecked_t unchecked = unchecked_t{}; + } // namespace detail + + namespace meta { + using sfinae_yes_t = std::true_type; + using sfinae_no_t = std::false_type; + + template + using void_t = void; + + template + using unqualified = std::remove_cv>; + + template + using unqualified_t = typename unqualified::type; + + namespace meta_detail { + template + struct unqualified_non_alias : unqualified {}; + + template